[
  {
    "path": ".gitattributes",
    "content": "src/clientversion.cpp export-subst\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--- Remove sections that do not apply -->\n\nThis issue tracker is only for technical issues related to Gulden.\n\nGeneral support questions and/or support requests and are best directed to our slack.\n\nPlease ensure you are running the latest version of the software before reporting issues.\n\n### Describe the issue\n\n### Can you reliably reproduce the issue?\n#### If so, please list the steps to reproduce below:\n1.\n2.\n3.\n\n### Expected behaviour\nTell us what should happen\n\n### Actual behaviour\nTell us what happens instead\n\n### Screenshots.\nIf the issue is related to the GUI, screenshots can be added to this issue via drag & drop.\n\n### What version of Gulden are you using?\nList the version number/commit ID, and if it is an official binary, self compiled or a distribution package such as PPA.\n\n### Machine specs:\n- OS:\n- CPU:\n- RAM:\n- Disk size:\n- Disk Type (HD/SDD):\n\n### Any extra information that might be useful in the debugging process.\nThis is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred.\n"
  },
  {
    "path": ".gitignore",
    "content": "*.tar.gz\n\n*.exe\n\n# autoreconf\nMakefile.in\naclocal.m4\nautom4te.cache/\nbuild-aux/config.guess\nbuild-aux/config.sub\nbuild-aux/depcomp\nbuild-aux/install-sh\nbuild-aux/ltmain.sh\nbuild-aux/m4/libtool.m4\nbuild-aux/m4/lt~obsolete.m4\nbuild-aux/m4/ltoptions.m4\nbuild-aux/m4/ltsugar.m4\nbuild-aux/m4/ltversion.m4\nbuild-aux/missing\nbuild-aux/compile\nbuild-aux/test-driver\nconfig.log\nconfig.status\nconfigure\nlibtool\nsrc/config/gulden-config.h\nsrc/config/gulden-config.h.in\nsrc/config/stamp-h1\nshare/setup.nsi\nshare/qt/Info.plist\n\nsrc/univalue/gen\n\nsrc/qt/*.moc\nsrc/qt/_Gulden/*.moc\nsrc/qt/moc_*.cpp\nsrc/qt/_Gulden/moc_*.cpp\nsrc/qt/forms/ui_*.h\nsrc/qt/_Gulden/forms/ui_*.h\nsrc/qt/qfonticon/moc_*.cpp\nsrc/qt/test/moc*.cpp\n\n.deps\n.dirstamp\n.libs\n.*.swp\n*.*~*\n*.bak\n*.rej\n*.orig\n*.pyc\n*.o\n*.o-*\n*.patch\n*.a\n*.pb.cc\n*.pb.h\n\n*.log\n*.trs\n*.dmg\n\n*.json.h\n*.raw.h\n\n#libtool object files\n*.lo\n*.la\n\n# Compilation and Qt preprocessor part\n*.qm\nMakefile\nMakefile.am.user\nGulden-tx\nGulden-cli\nGuldenD\n/src/qt/Gulden\n\n# Unit-tests\nMakefile.test\ntest_Gulden\ntest_gulden\n\n# Resources cpp\nqrc_*.cpp\n\n# Mac specific\n.DS_Store\nbuild\n\n#lcov\n*.gcno\n*.gcda\n/*.info\ntest_bitcoin.coverage/\ntotal.coverage/\ncoverage_percent.txt\n\n#build tests\nlinux-coverage-build\nlinux-build\nwin32-build\ntest/config.ini\ntest/cache/*\n\n!src/leveldb*/Makefile\n\n/doc/doxygen/\n\nlibguldenconsensus.pc\ncontrib/devtools/split-debug.sh\ncontrib/gitian-descriptors/*.yml\n\n#Auto generated npm files\nsrc/frontend/electron/dist\n\n#Private local config file for developer tools\nprivate.conf\n\n#Generated by translation system, not actually used by build\nsrc/qt/guldenstrings.cpp\n\nsrc/test/test_gulden_fuzzy\n\ndebug\ndebug2\nrelease\nmassif\nprofile\nreleasewithdebug\nfoo\nfoo2\n*.po\n\n# In tree build files take form of /build/<build-type> and/or /build_<build-type>\n/build*\n\n# In tree files auto generated and/or downloaded for the Android build\n/developer-tools/android-ndk-gulden/\n/djinni/\n\nxcuserdata\n\n# Android Studio/IntelliJ IDE\n.idea\n"
  },
  {
    "path": ".gitmodules",
    "content": ""
  },
  {
    "path": ".mailmap",
    "content": "Willem de Jonge\t<willem@isnapp.nl>\tWillem de Jonge\t<willem@isnapp.nl>\n<malcolm@gulden.com>\t<mmacleod@webmail.co.za>\n<malcolm@gulden.com>\t<malcolm@Malcolms-MacBook-Pro.local>\nMalcolm MacLeod <malcolm@gulden.com>\tMalcolm\t<malcolm@gulden.com>\nMalcolm MacLeod <malcolm@gulden.com>    Malcolm James MacLeod <malcolm@gulden.com>\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: minimal\ndist: trusty\nsudo: required\ncache:\n  ccache: true\n  directories:\n  - depends/built\n  - depends/sdk-sources\n  - $HOME/.ccache\n\nenv:\n  global:\n    - MAKEJOBS=-j3\n    - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID\n    - CCACHE_SIZE=500M\n    - CCACHE_TEMPDIR=/tmp/.ccache-temp\n    - CCACHE_COMPRESS=1\n    - CCACHE_DIR=$HOME/.ccache\n    - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out\n    - WINEDEBUG=fixme-all\n    - DOCKER_PACKAGES=\"build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache\"\nmatrix:\n  include:\n    - os: linux\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - g++-7\n      env: MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7\" HOST=x86_64-unknown-linux-gnu PACKAGES=\"libqrencode-dev libminiupnpc-dev libqwt-qt5-dev libqwt-headers python3-zmq libqt5webkit5-dev qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev\" DEP_OPTS=\"NO_QT=1 NO_UPNP=1 ALLOW_HOST_PACKAGES=1\" RUN_TESTS=false GOAL=\"install\" GULDEN_CONFIG='--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=\"-DBYPASS_TEST_REWRITES\"'\n#    - os: linux\n#      addons:\n#        apt:\n#          sources:\n#            - ubuntu-toolchain-r-test\n#          packages:\n#            - g++-7\n#      env: MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7\" HOST=x86_64-unknown-linux-gnu PACKAGES=\"libqrencode-dev libminiupnpc-dev python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev\" DEP_OPTS=\"NO_QT=1 NO_WALLET=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1\" RUN_TESTS=true GOAL=\"install\" GULDEN_CONFIG='--enable-zmq --disable-wallet --with-gui=no --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=\"-DBYPASS_TEST_REWRITES\"'\n    - os: linux\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - g++-7\n      env: MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7\" HOST=x86_64-unknown-linux-gnu PACKAGES=\"libqrencode-dev libminiupnpc-dev python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev\" DEP_OPTS=\"NO_QT=1 NO_UPNP=1 ALLOW_HOST_PACKAGES=1\" RUN_TESTS=true GOAL=\"install\" GULDEN_CONFIG='--enable-zmq --disable-wallet --with-gui=no --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=\"-DBYPASS_TEST_REWRITES\"'\n    #Tests only make dist\n    - os: linux\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - g++-7\n      env: MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7\" HOST=x86_64-unknown-linux-gnu PACKAGES=\"libqrencode-dev libminiupnpc-dev libqwt-qt5-dev libqwt-headers python3-zmq libqt5webkit5-dev qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev\" DEP_OPTS=\"NO_QT=1 NO_UPNP=1 ALLOW_HOST_PACKAGES=1\" DIST_ONLY=true GOAL=\"install\" GULDEN_CONFIG='--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=\"-DBYPASS_TEST_REWRITES\"'\n\nbefore_install:\n    - eval \"${MATRIX_EVAL}\"\n    - export PATH=$(echo $PATH | tr ':' \"\\n\" | sed '/\\/opt\\/python/d' | tr \"\\n\" \":\" | sed \"s|::|:|g\")\ninstall:\n    - env | grep -E '^(CCACHE_|WINEDEBUG|DISPLAY|BOOST_TEST_RANDOM|CONFIG_SHELL|TRAVIS)' | tee /tmp/env\n    - DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$TRAVIS_BUILD_DIR,dst=$TRAVIS_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $TRAVIS_BUILD_DIR --env-file /tmp/env ubuntu:18.04)\n    - DOCKER_EXEC () { docker exec $DOCKER_ID bash -c \"cd $PWD && $*\"; }\n    - if [ -n \"$DPKG_ADD_ARCH\" ]; then DOCKER_EXEC dpkg --add-architecture \"$DPKG_ADD_ARCH\" ; fi\n    - travis_retry DOCKER_EXEC apt-get update\n    - travis_retry DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES\nbefore_script:\n    - if [ -z \"$NO_DEPENDS\" ]; then DOCKER_EXEC CONFIG_SHELL= make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS; fi\n    # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI\n    - if [ \"$NEED_XVFB\" = 1 ]; then DOCKER_EXEC /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi\nscript:\n    - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1`\n    - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST\n    - GULDEN_CONFIG_ALL=\"--enable-werror --disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib\"\n    - if [ -z \"$NO_DEPENDS\" ]; then DOCKER_EXEC ccache --max-size=$CCACHE_SIZE; fi\n    - test -n \"$CONFIG_SHELL\" && DOCKER_EXEC \"$CONFIG_SHELL\" -c \"./autogen.sh\" || DOCKER_EXEC ./autogen.sh\n    - mkdir build && cd build\n    - DOCKER_EXEC \"echo 'prefix=/usr' | tee /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'exec_prefix=/usr' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'libdir=/usr/lib64' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'includedir=/usr/include/qwt' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'Name:Qwt' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'Description:Qt Widgets for Technical Applications' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'Version:6.1.3' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'Libs:-lqwt-qt5' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC \"echo 'Cflags:-I/usr/include/qwt' | tee -a /usr/share/pkgconfig/Qt5Qwt.pc\"\n    - DOCKER_EXEC ../configure --cache-file=config.cache $GULDEN_CONFIG_ALL $GULDEN_CONFIG || ( cat config.log && false)\n    - if [ \"DIST_ONLY\" = \"true\" ]; then DOCKER_EXEC make dist; fi\n    - if [ \"DIST_ONLY\" != \"true\" ]; then DOCKER_EXEC make $MAKEJOBS; fi\n#    - if [ \"$RUN_TESTS\" = \"true\" ]; then travis_wait 60 DOCKER_EXEC ./src/test/test_gulden; fi\nafter_script:\n    - echo $TRAVIS_COMMIT_RANGE\n    - echo $TRAVIS_COMMIT_LOG\n\nnotifications:\n  slack:\n    secure: iNEHGC+a1uC0bGNKDH85XuSwk18Jyqb8t02dosNcZd46L1eZyUrcL/AoQBVw/r8Ay+dOUcTY6arjKrkobPjvXGpamrJo0ejI6vZlfe8t1nR+P7feYLDhYeJQ4yb6ZV7uKzOP+ZocoEoTKttsHkoWKGGNuNzHcPcjhzLkYmY3MHfGmIQDVcU6DAGGTw6SQB1FkMbOWpgpqXndidEpX6N8pdZ3gCG3EFLKI/xQAVlyvzEmQOc4uP4vLMVhCQVc03MgnQIm5DpbsPdMMp4h24ysstTIFk6zO8qwjqzeePr4bRWTYRdaVxIHvd269bo7rCMn7p+Apc+xHnDIaCHJbzrI7HN8iJ4Pe9W4MTOR/GUNesfQhnrkWndSYRfObTzpfZHOgdv+K9dQ+A+kn3CUEQfLXFtwtmafgpVzQ0PeU3mLqXJt1zzYVoxCSqyO/dpye9Ezr5cPged29a35lL80ChIywlL83EkbcXpctoA9AHu4M44h1gTCG5oleulsuQjEPnNZYdEKuY2uAmB0dszzbgu1R+BBVmnBQSW0LT1AwJGD/30SihQZhY+vXrJOBBTrQl6mrA7iX5kAe2o5kGCkVuKj/o8P9ia5LF88PsWibYm4cB+wt07DxVK/rjZDw/yi0+G59D6HrF0B2i8Jg7yJOQ2JyC3Au/1d+17tHmxqAdp6xPE=\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing to Munt\n============================\n\nWant to contribute to Munt? There are many ways you can contribute, see below.\n\nOpening issues\n--------------------\n\nOpen an issue to report bugs or to propose new features. \nNote please first check for existing issues before reporting new ones; and ideally check with the slack support channels that your issue is legitimate.\n\nContributing code\n---------------------------\nCode contributions are always welcome, simply submit a pull request for it to be reviewed. For larger changes first check with the developers and Munt community whether the changes are ones that fit the vision of the project and are not already being worked on by someone else, to avoid dissapointment and/or wasting your time.\n\nKeep your pull requests as clean as possible, don't mix multiple issues into one request, don't make unnecesssary formatting or name changes that make the patch larger than it needs to be, these can rather be split into multiple requests.\n\nView [the developer guidelines](./doc/developer_guidelines.md) for basic code style standards and suggestions.\n\nTesting\n---------------------------\n\nRead here about our [testnet](./technical_documentation/accelerated_testnet.md) which includes a testbed for merchant integration and join the community on slack for further communication/assistance.\n\n\nLocalisation/Translation\n-----------------------\n\nImprovements/additions to the localisations are always welcome, however please don't modify the .ts files directly - the correct place to participate in translation is our translation portal translate.munt.org\nDiscussion around translation can be had in the #translate channel on our slack.\n"
  },
  {
    "path": "COPYING",
    "content": "For licensing of all original portions of the code coming from the Munt project, please review the license in this file or in COPYING_munt which is an unmodified copy of the GNU Lesser General Public License v3\nFor licensing of all original unmodified portions of code coming from upstream, please review COPYING_upstream which is an unmodified copy of the upstream license.\nFor licensing of all portions of the code in specific subdirectories, please review the COPYING or LICENSE file for the sub directory in question: src/secp256k1/COPYING; src/LRUCache/COPYING; src/crypto/ctaes/COPYING; src/univalue/COPYING; src/leveldb/LICENSE.\n\nIn all cases review also the licensing comments in the files themselves which superceed the above when present. All code in this repository falls under the above licenses unless specifically stated otherwise in the file.\nAll modifications to all files, irrespective of the original licensing of the file form part of the work of the Munt project and are subject to the GNU Lesser General Public License v3, please review the text below or in COPYING_munt which is an unmodified copy of the GNU Lesser General Public License v3.\n\n\n-----------------------------------------------------\n\nGNU LESSER GENERAL PUBLIC LICENSE\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n\nThis version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.\n0. Additional Definitions.\n\nAs used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License.\n\n“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.\n\nAn “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.\n\nA “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”.\n\nThe “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.\n\nThe “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.\n1. Exception to Section 3 of the GNU GPL.\n\nYou may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.\n2. Conveying Modified Versions.\n\nIf you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:\n\n    a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or\n    b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.\n\n3. Object Code Incorporating Material from Library Header Files.\n\nThe object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:\n\n    a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the object code with a copy of the GNU GPL and this license document.\n\n4. Combined Works.\n\nYou may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:\n\n    a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the Combined Work with a copy of the GNU GPL and this license document.\n    c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.\n    d) Do one of the following:\n        0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.\n        1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.\n    e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)\n\n5. Combined Libraries.\n\nYou may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:\n\n    a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.\n    b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\n\n6. Revised Versions of the GNU Lesser General Public License.\n\nThe Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.\n\nIf the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.\n"
  },
  {
    "path": "COPYING_munt",
    "content": "GNU LESSER GENERAL PUBLIC LICENSE\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n\nThis version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.\n0. Additional Definitions.\n\nAs used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License.\n\n“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.\n\nAn “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.\n\nA “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”.\n\nThe “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.\n\nThe “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.\n1. Exception to Section 3 of the GNU GPL.\n\nYou may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.\n2. Conveying Modified Versions.\n\nIf you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:\n\n    a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or\n    b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.\n\n3. Object Code Incorporating Material from Library Header Files.\n\nThe object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:\n\n    a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the object code with a copy of the GNU GPL and this license document.\n\n4. Combined Works.\n\nYou may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:\n\n    a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the Combined Work with a copy of the GNU GPL and this license document.\n    c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.\n    d) Do one of the following:\n        0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.\n        1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.\n    e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)\n\n5. Combined Libraries.\n\nYou may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:\n\n    a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.\n    b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\n\n6. Revised Versions of the GNU Lesser General Public License.\n\nThe Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.\n\nIf the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.\n"
  },
  {
    "path": "COPYING_upstream",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2009-2017 The Bitcoin Core developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "INSTALL.md",
    "content": "Windows\n================\nDownload and install the latest .exe setup file from [releases](https://github.com/muntorg/munt-official/releases)\n\nLinux\n================\nDesktop users - Download and install the latest .AppImage from [releases](https://github.com/muntorg/munt-official/releases)\nServer/Embeddeded - Download and decompress the latest binaries for your architecture from [releases](https://github.com/muntorg/munt-official/releases)\n\nmacOS\n================\nDownload and install the latest .dmg file from [releases](https://github.com/muntorg/munt-official/releases)\n\nBuilding\n================\n\nSee [build instructions](./doc/building.md) for instructions on building Munt.\n"
  },
  {
    "path": "Makefile.am",
    "content": "# Copyright (c) 2013-2016 The Bitcoin developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# File contains modifications by: The Centure developers\n# All modifications:\n# Copyright (c) 2016-2022 The Centure developers\n# Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n# Distributed under the GNU Lesser General Public License v3, see the accompanying\n# file COPYING\n\nACLOCAL_AMFLAGS = -I build-aux/m4\nSUBDIRS = src\n.PHONY: deploy FORCE\n\nGZIP_ENV=\"-9n\"\nexport PYTHONPATH\n\nDAEMON_BIN=$(top_builddir)/src/$(_DAEMON_NAME)$(EXEEXT)\nCLI_BIN=$(top_builddir)/src/$(_CLI_NAME)$(EXEEXT)\nWIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)\n\nempty :=\nspace := $(empty) $(empty)\n\nOSX_APP=Munt.app\nOSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME))\nOSX_DMG = $(OSX_VOLNAME).dmg\nOSX_BACKGROUND_SVG=background.svg\nOSX_BACKGROUND_IMAGE=background.tiff\nOSX_BACKGROUND_IMAGE_DPIS=36 72\nOSX_DSSTORE_GEN=DS_Store\nOSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist\nOSX_INSTALLER_ICONS=$(top_srcdir)/src/frontend/electron/build/icon.icns\n\nDIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)\nDIST_CONTRIB = $(top_srcdir)/contrib/Munt-cli.bash-completion \\\n\t       $(top_srcdir)/contrib/Munt-tx.bash-completion \\\n\t       $(top_srcdir)/contrib/Munt-daemon.bash-completion \\\n\t       $(top_srcdir)/contrib/init \n\nBIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \\\n           $(top_srcdir)/contrib/devtools/security-check.py\n\nWINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/icon.ico \\\n  $(top_srcdir)/share/pixmaps/nsis-header.bmp \\\n  $(top_srcdir)/share/pixmaps/nsis-wizard.bmp\n\nOSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \\\n  $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_SVG) \\\n  $(top_srcdir)/contrib/macdeploy/$(OSX_DSSTORE_GEN) \\\n  $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \\\n  $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh\n\nCOVERAGE_INFO = baseline_filtered_combined.info baseline.info \\\n  leveldb_baseline.info test_filtered.info total_coverage.info \\\n  baseline_filtered.info functional_test.info functional_test_filtered.info \\\n  leveldb_baseline_filtered.info test_coverage.info test.info\n\ndist-hook:\n\t-$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf -\n\nstrip: all-recursive\n\t$(MKDIR_P) $(top_builddir)/release\n\tSTRIPPROG=\"$(STRIP)\" $(INSTALL_STRIP_PROGRAM) $(DAEMON_BIN) $(top_builddir)/release\n\tSTRIPPROG=\"$(STRIP)\" $(INSTALL_STRIP_PROGRAM) $(CLI_BIN) $(top_builddir)/release\n\n\n$(WIN_INSTALLER): all-recursive\n\t@test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \\\n\t  echo error: could not build $@\n\t@echo built $@\n\n$(OSX_APP)/Contents/PkgInfo:\n\t$(MKDIR_P) $(@D)\n\t@echo \"APPL????\" > $@\n\n$(OSX_APP)/Contents/Resources/empty.lproj:\n\t$(MKDIR_P) $(@D)\n\t@touch $@ \n\n$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST)\n\t$(MKDIR_P) $(@D)\n\t$(INSTALL_DATA) $< $@\n\n$(OSX_APP)/Contents/Resources/Munt.icns: $(OSX_INSTALLER_ICONS)\n\t$(MKDIR_P) $(@D)\n\t$(INSTALL_DATA) $< $@\n\n$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings:\n\t$(MKDIR_P) $(@D)\n\techo '{\tCFBundleDisplayName = \"$(PACKAGE_NAME)\"; CFBundleName = \"$(PACKAGE_NAME)\"; }' > $@\n\nOSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \\\n  $(OSX_APP)/Contents/Resources/Munt.icns $(OSX_APP)/Contents/Info.plist \\\n  $(OSX_APP)/Contents/MacOS/Munt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings\n\nosx_volname:\n\techo $(OSX_VOLNAME) >$@\n\nif BUILD_DARWIN\n$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE)\n\t$(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME)\n\n$(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG)\n\tsed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < \"$<\" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@\n$(OSX_BACKGROUND_IMAGE)@2x.png: contrib/macdeploy/$(OSX_BACKGROUND_SVG)\n\tsed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < \"$<\" | $(RSVG_CONVERT) -f png -d 72 -p 72 -o $@\n$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE).png $(OSX_BACKGROUND_IMAGE)@2x.png\n\ttiffutil -cathidpicheck $^ -out $@\n\ndeploydir: $(OSX_DMG)\nelse\nAPP_DIST_DIR=$(top_builddir)/dist\nAPP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/.VolumeIcon.icns  $(APP_DIST_DIR)/Applications\n\n$(APP_DIST_DIR)/Applications:\n\t@rm -f $@\n\t@cd $(@D); $(LN_S) /Applications $(@F)\n\n$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Munt\n\n$(OSX_DMG): $(APP_DIST_EXTRAS)\n\t$(GENISOIMAGE) -no-cache-inodes -D -l -probe -V \"$(OSX_VOLNAME)\" -no-pad -r -dir-mode 0755 -apple -o $@ dist\n\ndpi%.$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_SVG)\n\tsed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < \"$<\" | $(RSVG_CONVERT) -f png -d $* -p $* | $(IMAGEMAGICK_CONVERT) - $@\nOSX_BACKGROUND_IMAGE_DPIFILES := $(foreach dpi,$(OSX_BACKGROUND_IMAGE_DPIS),dpi$(dpi).$(OSX_BACKGROUND_IMAGE))\n$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIFILES)\n\t$(MKDIR_P) $(@D)\n\t$(TIFFCP) -c none $(OSX_BACKGROUND_IMAGE_DPIFILES) $@\n\n$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/$(OSX_DSSTORE_GEN)\n$(APP_DIST_DIR)/.VolumeIcon.icns: $(top_srcdir)/src/qt/res/icons/Munt.icns\n\t$(INSTALL) $< $@\n\n\n\ndeploydir: $(APP_DIST_EXTRAS)\nendif\n\nif TARGET_DARWIN\nappbundle: $(OSX_APP_BUILT)\ndeploy: $(OSX_DMG)\nendif\nif TARGET_WINDOWS\ndeploy: $(WIN_INSTALLER)\nendif\n\n$(DAEMON_BIN): FORCE\n\t$(MAKE) -C src $(@F)\n\n$(CLI_BIN): FORCE\n\t$(MAKE) -C src $(@F)\n\nif USE_LCOV\n\nbaseline.info:\n\t$(LCOV) -c -i -d $(abs_builddir)/src -o $@\n\nbaseline_filtered.info: baseline.info\n\t$(LCOV) -r $< \"/usr/include/*\" -o $@\n\nleveldb_baseline.info: baseline_filtered.info\n\t$(LCOV) -c -i -d $(abs_builddir)/src/leveldb -b $(abs_builddir)/src/leveldb -o $@\n\nleveldb_baseline_filtered.info: leveldb_baseline.info\n\t$(LCOV) -r $< \"/usr/include/*\" -o $@\n\nbaseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info\n\t$(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@\n\ntest.info: baseline_filtered_combined.info\n\t$(MAKE) -C src/ check\n\t$(LCOV) -c -d $(abs_builddir)/src -t test -o $@\n\t$(LCOV) -z -d $(abs_builddir)/src\n\t$(LCOV) -z -d $(abs_builddir)/src/leveldb\n\ntest_filtered.info: test.info\n\t$(LCOV) -r $< \"/usr/include/*\" -o $@\n\nfunctional_test.info: test_filtered.info\n\t-@TIMEOUT=15 python test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)\n\t$(LCOV) -c -d $(abs_builddir)/src --t functional-tests -o $@\n\t$(LCOV) -z -d $(abs_builddir)/src\n\t$(LCOV) -z -d $(abs_builddir)/src/leveldb\n\nfunctional_test_filtered.info: functional_test.info\n\t$(LCOV) -r $< \"/usr/include/*\" -o $@\n\ntest_coverage.info: baseline_filtered_combined.info test_filtered.info\n\t$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_filtered.info -o $@\n\ntotal_coverage.info: baseline_filtered_combined.info test_filtered.info functional_test_filtered.info\n\t$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) \"\\%\" | $(AWK) '{ print substr($$3,2,50) \"/\" $$5 }' > coverage_percent.txt\n\ntest.coverage/.dirstamp:  test_coverage.info\n\t$(GENHTML) -s $< -o $(@D)\n\t@touch $@\n\ntotal.coverage/.dirstamp: total_coverage.info\n\t$(GENHTML) -s $< -o $(@D)\n\t@touch $@\n\ncov: test.coverage/.dirstamp total.coverage/.dirstamp\n\nendif\n\ndist_noinst_SCRIPTS = autogen.sh\n\nEXTRA_DIST = $(top_srcdir)/share/genbuild.sh test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) COPYING COPYING_munt COPYING_upstream\n\nEXTRA_DIST += \\\n    test/util/util-test.py \\\n    test/util/data/util-test.json \\\n    test/util/data/blanktxv1.hex \\\n    test/util/data/blanktxv1.json \\\n    test/util/data/blanktxv2.hex \\\n    test/util/data/blanktxv2.json \\\n    test/util/data/tt-delin1-out.hex \\\n    test/util/data/tt-delin1-out.json \\\n    test/util/data/tt-delout1-out.hex \\\n    test/util/data/tt-delout1-out.json \\\n    test/util/data/tt-locktime317000-out.hex \\\n    test/util/data/tt-locktime317000-out.json \\\n    test/util/data/tx394b54bb.hex \\\n    test/util/data/txcreate1.hex \\\n    test/util/data/txcreate1.json \\\n    test/util/data/txcreate2.hex \\\n    test/util/data/txcreate2.json \\\n    test/util/data/txcreatedata1.hex \\\n    test/util/data/txcreatedata1.json \\\n    test/util/data/txcreatedata2.hex \\\n    test/util/data/txcreatedata2.json \\\n    test/util/data/txcreatedata_seq0.hex \\\n    test/util/data/txcreatedata_seq0.json \\\n    test/util/data/txcreatedata_seq1.hex \\\n    test/util/data/txcreatedata_seq1.json \\\n    test/util/data/txcreatemultisig1.hex \\\n    test/util/data/txcreatemultisig1.json \\\n    test/util/data/txcreatemultisig2.hex \\\n    test/util/data/txcreatemultisig2.json \\\n    test/util/data/txcreatemultisig3.hex \\\n    test/util/data/txcreatemultisig3.json \\\n    test/util/data/txcreatemultisig4.hex \\\n    test/util/data/txcreatemultisig4.json \\\n    test/util/data/txcreateoutpubkey1.hex \\\n    test/util/data/txcreateoutpubkey1.json \\\n    test/util/data/txcreateoutpubkey2.hex \\\n    test/util/data/txcreateoutpubkey2.json \\\n    test/util/data/txcreateoutpubkey3.hex \\\n    test/util/data/txcreateoutpubkey3.json \\\n    test/util/data/txcreatescript1.hex \\\n    test/util/data/txcreatescript1.json \\\n    test/util/data/txcreatescript2.hex \\\n    test/util/data/txcreatescript2.json \\\n    test/util/data/txcreatescript3.hex \\\n    test/util/data/txcreatescript3.json \\\n    test/util/data/txcreatescript4.hex \\\n    test/util/data/txcreatescript4.json \\\n    test/util/data/txcreatesignv1.hex \\\n    test/util/data/txcreatesignv1.json \\\n    test/util/data/txcreatesignv2.hex \\\n    src/data/chainparams_mainnet_static_checkpoint_data.cpp \\\n    src/data/static_diff_data.cpp\n\n\nCLEANFILES = $(OSX_DMG) $(WIN_INSTALLER)\n\n.INTERMEDIATE: $(COVERAGE_INFO)\n\nDISTCHECK_CONFIGURE_FLAGS = --enable-man\n\nclean-local:\n\trm -rf coverage_percent.txt test.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP)\n\trm -rf test/functional/__pycache__\n"
  },
  {
    "path": "README.md",
    "content": "<table cellspacing=\"0\" cellpadding=\"0\" color=\"grey\" border=\"1px\">\n  <tr border=0>\n    <td border=\"0px\" width=\"80%\" rowspan=\"7\">\n      <a href=\"https://www.munt.org\">\n        <img height=260px align=\"left\" src=\"https://munt.org/img/design/munt-000000.svg\" alt=\"Munt\"/>\n      </a>\n      <p>Munt is a witness-secured decentralized network for payments, digital assets, finance and more<br/>\n      Munt takes the basic blockchain concept and improves on the areas where it has shortcomings in order to make a product that is more suitable for every day use.</p>\n      <p>The project is driven at the core by a focus on key concepts of <i>usability</i> and <i>quality</i>.</p><p>Join the Munt project today and help build the future!</p>\n    </td>\n    <td width=\"20%\" border=0>\n      <a href=\"#\">\n        <img height=\"20px\" src=\"https://travis-ci.org/muntorg/munt-official.svg?branch=master\" alt=\"ci build status\"/>\n      </a>\n    </td>\n  </tr>\n  <tr border=0>\n    <td>\n      <a href=\"https://github.com/muntorg/munt-official/issues\">\n        <img  height=\"20px\" src=\"https://img.shields.io/github/issues/muntorg/munt-official.svg?color=blue\" alt=\"open issues\"/>\n    </td>\n  </tr>\n  <tr border=0>\n    <td>\n      <a href=\"https://github.com/muntorg/munt-official/issues?q=is%3Aissue+is%3Aclosed\">\n        <img  height=\"20px\" src=\"https://img.shields.io/github/issues-closed/muntorg/munt-official.svg?color=blue\" alt=\"closed issues\"/>\n      </a>\n    </td>\n  </tr>\n  <tr border=0>\n    <td border=0>\n      <a href=\"https://github.com/muntorg/munt-official/releases\">\n        <img height=\"20px\" src=\"https://img.shields.io/github/downloads/muntorg/munt-official/total.svg?color=blue\" alt=\"total downloads\"/>\n      </a>\n    </td>\n  </tr>\n  <tr border=0>\n    <td>\n      <a href=\"https://github.com/munt/munt-official/commits/master\">\n        <img height=\"20px\" src=\"https://img.shields.io/github/commit-activity/y/muntorg/munt-official.svg\" alt=\"commits 1y\"/>\n      </a>\n    </td>\n  </tr>\n  <tr>\n    <td>\n      <a href=\"https://github.com/muntorg/munt-official/compare/master@%7B12month%7D...develop\">\n        <img height=\"20px\" src=\"https://img.shields.io/badge/dev%20branch-develop-blue.svg\" alt=\"active_branch\"/>\n      </a>\n    </td>\n  </tr>\n</table>\n\n\n\n### License\nAll code, binaries and other assets in this repository are subject to [The GNU Lesser General Public License v3](https://github.com/muntorg/munt-official/blob/master/COPYING_munt) except where explicitely stated otherwise.\n\n### Branches\n`master` branch tracks the current public release; is generally updated only for each release (with accompanying tag) and very occasionally for minor documentation or other commits. If all you want is to build/track the current version of the sofrware than use the `master` branch.\n\n`develop` branch tracks current major development branch\nThis is where most development that will go into the next major release is always taking place (feature branches are merged into here) and is linked in the table at the top of this README as the `dev branch`. For development changes you will generally want to work on this branch.\n\n\nMajor features are worked on in temporary feature branches until they can be merged back into one of the development branches. \nThe currently most active branch, where most development that will go into the next major release is taking place is linked in the table at the top of this README as the `dev branch` and may be updated as development mandates seperate branches, for development changes you will generally want to work on this branch.\n\nOld versions that are still maintained get their own version branch e.g. there might be `2.4_development` even if we are already on `3.x` development series\n\n\n### Contributing\nIf you are thinking about contributing toward the development of Munt in some capacity whether small or large, code or translating; Please read [this guide](./CONTRIBUTING.md) first for information on how to do so.\n\n### Technical documentation\n* [PoW² whitepaper](.//technical_documentation/PoW2.pdf); [PoW² activation](./technical_documentation/PoW2_activation.md)\n* [Transaction format](./technical_documentation/transaction_format.md)\n* [Account system](./technical_documentation/account_system.md)\n* [Accelerated testnet](./technical_documentation/accelerated_testnet.md)\n* [Official testnet](./technical_documentation/accelerated_testnet.md#official-testnet)\n\n\n### Community\n\nConnect with the community through one or more of the following:\n\n[Website](https://munt.org) ◾ [Slack](https://munt.org/join) ◾ [Twitter](https://twitter.com/munt_org) ◾ [Facebook](http://facebook.com/gulden) ◾ [Meetup](https://www.meetup.com/gulden) ◾ [Reddit](https://www.reddit.com/r/munt) ◾ [IRC](https://web.libera.chat/?channels=Muntorg)\n\n\n### Downloading\n\nThe latest binaries and installers can be found [here](https://github.com/muntorg/munt-official/releases) for all platforms, including raspbian.\n\n### Building\n[Binaries](https://github.com/munt/munt-official/releases) for both the UI as well as the daemon and command line interface for multiple architectures.\n\nFor those who really need too or are technically inclined it is of course possible to build the software yourself. Please read the [build instructions](./doc/building.md) before attempting to build the software and/or seeking support.\n\n### Additional technical information\n\n\n|Technical specifications|Main network|[Testnet](./technical_documentation/accelerated_testnet.md#official-testnet)|\n|:-----------|:---------|:---------|\n|Consensus algorithm:|PoW² SIGMA/Witness|PoW² SIGMA/Witness|\n|Recommended transaction confirmations:|2|2|\n|Block reward SIGMA:|75 (10|65) MUNT|1000 MUNT|\n|Block reward witness:|15 MUNT|20 MUNT|\n|Block interval target:|150 seconds (2.5 minutes)|Configurable|\n|Difficulty adjustment period:|Every block|Every block|\n|Difficulty adjustment algorithm:|Delta|Delta|\n|Total coins to be minted over time:|750M|-|\n|P2P Port|9231|9923|\n|RPC Port|9232|9924|\n|P2P Network Header|fcfef7e0|Look in debug.log|\n|Address version byte|38 (G)|65 (T)|\n|P2SH version byte|98 (g)|127 (t)|\n|BIP44 coin type|87 0x80000057|87 0x80000057|\n|**Infrastructure**|**Main network**|**[Testnet](./technical_documentation/accelerated_testnet.md#official-testnet)**|\n|Official block explorer|https://explorer.munt.org/|-|\n|Community block explorer|https://muntbook.org/|-|\n|Community block explorer|https://munt.chainviewer.org/|-|\n|DNS Seed 1|seed.gulden.com|-|\n|DNS Seed 2|amsterdam.gulden.com|-|\n|DNS Seed 3|rotterdam.gulden.network|-|\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2013-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nset -e\nsrcdir=\"$(dirname $0)\"\ncd \"$srcdir\"\nif [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE=\"`which glibtoolize 2>/dev/null`\"; then\n  LIBTOOLIZE=\"${GLIBTOOLIZE}\"\n  export LIBTOOLIZE\nfi\nwhich autoreconf >/dev/null || \\\n  (echo \"configuration failed, please install autoconf first\" && exit 1)\nautoreconf --install --force --warnings=all\n"
  },
  {
    "path": "changelog.txt",
    "content": "3.0.5\n\nFinal release by Centure developers\nRelicensed under the GNU Lesser General Public License v3\nGeneral maintenance, version bump of most electron/vue/node libraries, update of checkpoints and other data etc.\nUI        - Transaction export functionality\nUI        - Add a basic about dialog displaying licensing information\n\n\n\n\n3.0.4\n\nMaintenence release, no major changes.\n\n\n\n3.0.2\n\nCORE      - Fix a crash that was triggering on windows builds\n\n\n\n\n3.0.1\n\nSoftware rebrands to Munt name.\nThis build represents our final switch from Qt to Electron for UI builds, Qt is completely removed from the codebase, users who require Qt specific functionality should remain on 2.5.0 until the 3.x series matures and gains more features\n\nUI        - New electron based UI\nCORE      - Switch to guix for macOS builds as well; all official builds now done on guix\nCORE      - Update various library dependencies to latest versions\nNET       - Bump MIN_PEER_PROTO_VERSION to 70020; This will disconnect from network all peers not on 2.5.0 or above\nUI        - Native M1/arm64 builds for macOS\n\n\n\n\n2.5.0\n\nIntroduce reward changes\n    \nAt block 1'619'997 chain forks and per block dev reward is removed, with a once off dev payment of 100'000'000 NLG paid into address GSTG9pQ6yRdGurmjUDGwm8FyYc272vP13b\n    \nTo keep the eventual supply at exactly 700'000'000 other small changes are then made:\n    * First halving is brought forward to block 2'074'989\n    * We slightly alter the rounding of each halving step to give cleaner numbers\n    * We continue halving for more rounds all the way down to 0.00000001 reward\n    * Final reward amount continues until block 433'009'989 with the 12.2709 NLG for this period being slowly paid out over a very very long period\n\nHalving schedule as follows (every four years):\n    5 mining,          7.5 witness\n    2 mining,          4 witness\n    1 mining,          2 witness\n    0.5 mining,        1 witness\n    0.2 mining,        0.5 witness\n    0.1 mining,        0.2 witness\n    0.05 mining,       0.1 witness\n    0.02 mining,       0.05 witness\n    0.01 mining,       0.02 witness\n    0.005 mining,      0.01 witness\n    0.002 mining,      0.005 witness\n    0.001 mining,      0.002 witness\n    0.0005 mining,     0.001 witness\n    0.0002 mining,     0.0005 witness\n    0.0001 mining,     0.0002 witness\n    0.00005 mining,    0.0001 witness\n    0.00002 mining,    0.00005 witness\n    0.00001 mining,    0.00002 witness\n    0.000005 mining,   0.00001 witness\n    0.000002 mining,   0.000005 witness\n    0.000001 mining,   0.000002 witness\n    0.0000005 mining,  0.000001 witness\n    0.0000002 mining,  0.0000005 witness\n    0.0000001 mining,  0.0000002 witness\n    0.00000005 mining, 0.0000001 witness\n    0.00000002 mining, 0.00000005 witness\n    0.00000001 mining, 0.00000002 witness (Stays here until completion - block 433'009'989)\n\n\n\n\n2.4.11\n\nThis build aims to be the final 2.4.x series release after issues were found that prevented 2.4.8 from being so.\nAs such it will likely represent the final Qt UI release with 2.5 series of builds replacing Qt with the electron UI.\n\nCORE      - Implement several important fixes to the fast path of the \"index based\" portion of the coin cache, these issues would  have resulted in nodes temporarily falling out of sync (until restarted) in some instances had the fast path been turned on however it has been off until now\nCORE      - Turn on the fast path for \"index based\" portion of the coin caches, this should drastically improve node performance in some instances\nCORE      - Introduce optimised sha256 implementations to take advantage of available CPU features (SSE4, neon etc.) when available/possible\nCORE      - Various performance improvements, removal of lock contention in some instances \nCORE      - Various improvements to mutexes to make it easier to spot issues as well as for better performance\nCORE      - Improved debug logging in various places throghout the program\nCORE      - Update linux builds to GCC 11\nCORE      - Update macOS builds to clang 14 (sdk 12)\nCORE      - Update android builds to clang 12 (ndk r23b)\nCORE      - Update windows builds to GCC 10\nCORE      - Switch to guix instead of gitian for official builds (all except macOS which will switch also for subsequent releases)\nCORE      - With all compilers updated we are now able to target C++20\nCORE      - Update libraries (boost 1.77.0; zmq 4.3.4; univalue 1.0.4; leveldb 1.22+)\nCORE      - Flush chainstate more frequently to prevent nodes having to resync if they terminate uncleanly after a full sync etc.\nLITE      - Fix issue that was preventing lite wallet from functioning on testnet\nLITE      - Fix a crash on macOS at program exit\nLITE      - Fix/improve behaviour of loading/synchronisation screen and make it smoother\nLITE      - Native M1/arm64 builds macOS\nRPC       - Add a 'loaded' paramater to results of 'getmempoolinfo' command\nRPC       - Improve/fix 'fundrawtransaction' command that failed in some instances\nRPC       - Improve/fix help text for several commands\nQA        - Introduction of more unit and functional tests\n\nDozens of other stability, code quality, build system, testing etc. related fixes and improvements.\n\n\n\n\n2.4.8\n\nFinal maintanence release ahead of upcoming 2.5 series of builds; 2.5 will fully activate witness sync and drop the deprecated Qt UI in favour of the electron one (Edit: This ended up not being the case)\n\n\n\n\n2.4.7\n\nCORE      - Fix an issue that would cause witness loop to terminate under some error conditions\nCORE      - Remove behaviour that would cause a complete resync under some error conditions, only do this on mobile/spv wallets and favour a plain assert on regular wallets instead\nRPC       - Improve output for `validateaddress` command when used on witness addresses\nMISC      - Various minor logging improvements to help with stability and user support\n\n\n\n\n2.4.6\n\nCORE      - Introduce a discount on relay fees for transactions that contain mining/witness rewards\n\n\n\n\n2.4.5\n\nCORE      - Chain stability fix for rare issue experienced by some peers\n\n\n\n\n2.4.4\n\nUI        - Fix witness earning estimates for recent reward changes\nCORE      - Improve regression in coin cache performance\n\n\n\n\n2.4.3\n\nCONSENSUS - Fix an issue with fresh syncs stalling, regression was introduced in 2.4.1 release\nCONSENSUS - Fix a rare issue with index based utxo getting corrupted (memory only, disk data remained valid)\nCORE      - Fix an issue that was causing unnecessarily frequent flushing to disk; this should bring large performance improvements for machines with slow disks\nCORE      - CORE: Major load time performance increase on large wallets, especially on machines with slower disks\nCORE      - Introduce some code that makes it easier for users that missed the fork to update with any manual intervention\nCORE      - Introduce some performance improvements to the code\nCORE      - Various regtest/testing improvements and general codebase cleanup\n\n\n\n\n2.4.1\n\nRPC       - Add arena setup time to \"gethashps\" output\nRPC       - New command \"getlinkedaccount\" as counterpart for existing \"importlinkedaccount\" command\nCORE      - Fix a DoS attack that can be utilised against miners\n\n\n\n\n2.4.0\n\nCONSENSUS - Implement proposed reward reductions and halving, as decided by community and GAB\n            Reward changes to take place at block 1'400'000\n            Halvings every 842'500 blocks, this is roughly four years assuming stable block times (a tiny fraction over in order to make things work out smoothly)\n            Very minor truncation based rounding applied when halving in order to keep numbers clean and end on a clean supply amount\n            Final supply of 700'000'000 with last reward mined on block 17'727'500\nCORE      - Implement a new/simplified way of tracking the witness specific portion of the UTXO set, this improves code simplicity as well as efficiency in a variety of ways\nCORE      - Implement methods/functionality to track/encode witness set \"deltas\" (changes) between blocks\nCONSENSUS - Store the witness set delta as part of each header, this allows for a very efficient syncing method which we are calling \"witness sync\"\nCONSENSUS - Enable spending of addresses with uncompressed keys again\nCONSENSUS - Allow renewal of multiple parts of the same witness account in a single transaction instead of requiring a renewal for each part\nCORE/UI   - Introduce a separate mining parameter for number of threads to use for \"arena setup\" when mining so that this can be set independently of \"mining threads\"\nCORE      - Fix a sync issue that would sometimes cause new installs to get stuck when syncing the first few blocks \nCORE      - Apply some optimisations to ConnectBlock calls that should improve performance quite substantially on some machines\nRPC       - \"setgenerate\" gains an extra parameter for the above, all miners should be aware of this as previous setgenerate syntax may fail\nRPC       - New command \"setwitnessrewardaddress\"\nRPC       - New command \"restoreaccount\"\nRPC       - Improve behaviour of \"deleteaccount\" to permanently remove/purge accounts from the wallet if they are readonly accounts; as opposed to the regular behaviour of just hiding accounts that applies to other account types\nRPC       - Fix return value of \"enablenetwork\" command\nRPC       - Add \"selected_shavite_implementation\", \"selected_echo_implementation\" and \"selected_argon_implementation\" to \"getmininginfo\" output\nUI        - Show \"elapsed\" time to current date for witness accounts\nZMQ       - Add a new ZMQ channel \"zmqpubwallettx\"\n\nAnd a variety of other small performance, stability and code quality enhancements, general maintenence etc. many of which are backported from the Florin project.\n\n\n\n\n2.3.12\n\nCORE    - Mining/Witness stability fix; Fix an issue that was causing periodic freezing of some mining/witnessing nodes\n\n\n\n\n2.3.11\n\nReduce eventual supply to a total of 750'000'000 coins as first step in implementing the supply reduction that has been requested by community/GAB; The intention is for the rewards to also change (as requested) however this will take place in a later release after a bit more time has been allowed for technical consideration of the implications.\n\nMISC    - Minor performance improvements to witnessing\nRPC     - New RPC command \"submitheader\"\nRPC     - Fix an issue where \"rotatewitnessaddress\" would fail if used on account that has never performed any witness actions\nRPC     - Introduce \"forcesigseg\" command (Only useful for development)\nRPC     - Add command \"repairwalletfromutxo\"\nRPC     - New command \"decodeblock\"\nRPC     - New \"defrag\" command, this can be used to recombine lots of small \"dust\" outputs into one single output again\nRPC     - New command \"invalidateunwitnessedblocksatheight\"\n\nThis build contains quite a large variety of misc. bug fixes, code improvements and stability fixes, quite a few backported from Novo development.\n\n\n\n\n2.3.10\n\nMISC    - New URI handlers \"guldenlite:\" and \"guldenpro:\" for specific targeting of lite/pro apps; \"gulden:\" URI handler still remains and will be used to target whichever app is installed\nUI      - Add in-app sell functionality (as companion to recent buy functionality); In collaboration with Blockhut\n\n\n\n\n2.3.9\n\nRPC     - Add 'selected_witness_index' info to 'getwitnessoutput' command\nDebug   - Introduce split debug uploads for all linux/windows builds and add documentation on how to utilise it\nBench   - Add some additional benchmark info to \"bench_sigma\" tool\n\n\n\n\n2.3.0.8\n\nFix a regression in SPV wallets causing sync issues on some devices\n\n\n\n\n2.3.0.7\n\nMinor maintenence release, introduce new buy behaviour into desktop wallets\n\n\n\n\n2.3.0.6\n\nLITE/UI - New/Improved buy functionality\nRPC     - Introduce range based 'getwitnessinfo' ability for explorers and similar\n\n\n\n\n2.3.0.5\n\nInitial release of new \"lite\" wallet; an SPV based desktop wallet with trimmed down feature set for those who want something fast but with less features than the core wallet\nRPC     - Fix '*' behaviour in listaccounts command\nRPC     - Give 'decodescript' the ability to decode old phase3 transactions\n\n\n\n\n2.3.0.4\n\nCORE    - Fix a crash in SIGMA verification code that could be triggered in some (relatively rare) instances\nRPC     - Hide various \"hidden\" developer RPC commands from the autocomplete\nRPC     - Introduce a new command \"repairwitnessaddress\" that can be used to repair a wallet if the witness key for a witness address is not available while wallet is locked (which is required for witnessing)\nRPC     - Extend \"validateaddress\" command to give more information for witness addresses\nCORE    - Minor improvement when renewing witness accounts; check for and repair any instances of missing witness key when doing a renewal\n\n\n\n\n2.3.0.2\n\nRPC     - Implement new command \"removeallorphans\"\nRPC     - Introduce a new command \"checkwalletagainstutxo\"\nNET     - Increase minimum peer protocol version to ban old peers\nCORE    - Checkpoint server deactivation has kicked in, so take away check and permanently disable auto checkpoints instead\n\n\n\n\n2.3.0.1\n\nMaintenance release, update to new code signing certificates.\n\n\n\n\n2.3.0.0\n\nCORE    - Set checkpoint server deactivation for 1602774915 (Thursday, 15-Oct-20 15:15:15 UTC)\n          Checkpointing is now no longer required with witnessing now fully implemented and stable as per the original whitepaper specification\nNET     - Disallow all peers below protocol version 70018 after timestamp server deactivates\nRPC     - Correction to return value of 'enablenetwork' command\n\n\n\n\n2.2.0.14\n\nCORE    - Implement a change that improves mining efficiency for update miners\nCORE    - Increment protocol version and ban older peer versions, this will lead to some bandwidth savings for nodes and make the network more efficient\n\n\n\n\n2.2.0.12\n\nCORE    - Undo accidental increase in mining subsidy [Activate at block: 1228004]\nUI      - Fix a minor regression in witness funding dialog\n\n\n\n\n2.2.0.11\n\nUI      - Fix up display of various phase3 related accounts/transactions for older wallets.\n\n\n\n\n2.2.0.10\n\nCORE    - Change dev subsidy reward to 80 NLG per block, as decided by GAB [Activate at block: 1226652 (Estimate 09/07/2020 @ 2:30pm (UTC+2)]\nCORE    - Activate changes to the Delta difficulty adjustment algorithm, which should see slightly smoother block times [Activates at timestamp: 1599494400 09/07/2020 @ 6:00pm (UTC+2)]\nCORE    - Fix a bug that was preventing witnesses from taking advantage of the ability to add transactions to the block they witness\n          This should lead to smoother transaction verification (lower average time until first confirm) and also allow witnesses to earn a small amount extra through transaction rewards\nCMDFLAG - Implement blockmaxsize flag for witness block creation as well, previously was only for mining block creation\nRPC     - Introduce some special case code to 'move' command to assist a small amount of 'legacy' phase3 witness accounts that otherwise experience difficulty being emptied when lock expires\nRPC     - Fix balance display for 'getaccountbalances'\nRPC     - Add rescan paramater to 'importwitnesskeys'\nRPC     - Remove 'getwitnessinfo' support for all blocks prior to phase5\nUI      - Improve estimated earnings calculation in UI\nCORE    - Fix a bug where in rare instances a \"null\" transaction could potentially be added to the wallet and make the wallet falsely appear corrupted on reload. There is no known release version of the code that could trigger this, however we protect against any future mistakes that might allow it to be sure\nCORE    - Remove various phase3 related parts of the codebase, these removals improve application performance and simplify the codebase\nCORE    - Remove old official testnet and start a new improved testnet in its place\nCORE    - Introduce \"genesis witness\" concept for testnet, that allows accelerated testnets to start with witnessing/phase5 already active from block 0\nCORE    - Introduce various unity/node.js/electron related changes to the codebase, that will allow for electron UI to be adopted in future. Electron UI already in relatively advanced stages but needs further work before merge\n\nNB! (Only relevant for old phase3 accounts, does not apply to phase4 accounts)\nWith the removal of special purpose phase3 code this release introduces some potential oddities to transaction lists for accounts that locked/unlocked funds to a phase 3 witness, instead of showing as a lock/unlock these actions will show as sending/receiving external funds.\nWitness generation actions of old phase 3 accounts will still show correctly.\nThis will be cleaned up as part of the ongoing work on a new UI, and will show correctly again in future.\n\n\n\n\n2.2.0.7\n\nNET     - Improve networking performance\nNET     - Remove support for old protocol versions that are no longer supported\nRPC     - Fix a crash in gettxoutsetinfo; Improve gettxoutsetinfo behaviour for new transaction output types\nRPC     - Fix GetNetworkHashPS calculation; It was incorrectly including witness 'work' in the mining calculation and returning an overly high number as a result\nRPC     - Introduce 'pow_time' and 'witness_time' fields to all block based RPC commands that include 'time' in the output; Change 'time' to display the most accurate time always (witness time if available, otherwise pow time)\nMINING  - Prevent mining of orphan blocks while wallet is still syncing on startup\nUI      - Fix a balance display issue some wallets were experiencing\nCORE    - Fix a rare crash that was being triggered in some nodes\nCORE    - Various performance improvements from removal of parts of the phase3 backwards support\n\n\n\n\n2.2.0.6\n\nUI      - Fix a UI freeze that was occuring on 'finished' witness accounts\nRPC     - Fix a crash in 'signrawtransaction' when signing new transaction types (of non script type)\nRPC     - Improve 'dumpblockgaps' command to output data for both witness and PoW timestamps; previous behaviour considered PoW timestamps only\nRPC     - Backport/add 'uptime' command from upstream\nRPC     - Backport/add 'getblockstats' command from upstream\nRPC     - Update second paramater of 'estimatesmartfee' from bool to string to match changes in upstream\nRPC     - Add output of witness/spending pubkeyhash when calling validateaddress on a witness address\nCORE    - Fix an issue some wallets were having with signing extend/optimise transactions\nCORE    - Remove various parts of the old phase3 codebase, this should bring performance improvements\n\n\n\n\n2.2.0.5\n\nUI      - Fix UI behaviour for upgrading expired witness accounts\nUI      - Improve UI behaviour for displaying 'extend' button for witness accounts \nUI      - Add/Fix \"Ctrl+L\" shortcut to clear debug console text\nRPC     - Make 'renewwitnessaccount' command work also for upgrading witness accounts\nCORE    - Restore 'first' mining address for those miners whose address was changed to a new one by buils containing the issue that was fixed in 2.2.0.3 release\nCORE    - Improve mining behaviour for v2 transactions, insert an extra nonce, this is unlikely to matter at current mining speeds in any way but is better for correctness anyway. (Only really relevant in fringe cases like mining with -limitdeltadiffdrop=0)\n\n\n\n\n2.2.0.4\n\nUI      - Fix display of witness locktime end date\nUI      - Improve phase4 witness renewal so that multi-part witness accounts can renew all parts in one go\nUI      - Fix display of witness earnings graph for expired accounts\nUI      - Fix witness renewal for phase3; A regression broke it in some instances\nCORE    - Fix an issue with txdb 'corrupting' its index based outpoints; also repair already corrupted databases in place\nCORE    - Increase the size of the maximum allowed fee on the network to 2 NLG\n\n\n\n\n2.2.0.3\n\nUI      - Fix issue where a witness account that had o nly partially been emptied could not be fully emptied\nUI      - Fix a bug in witness overview when transaction was still pending first confirmation after funding\nUI      - Fix some issues where transactions spending money out of witness accounts were not displaying the right amount in transaction list\nUI      - Fix an issue with witness graph display strangely\nCORE    - Fix an issue where mining address would change if doing a restore on top of an existing block chain\nCORE    - Temporarily lower default memory usage on pis for first batch of 2.2 pi upgrades; we will raise these limits again in future\n\n\n\n\n2.2.0.2\n\nUI      - Minor fixes to witness dialog\nCORE    - Minor stability fixes\n\n\n\n\n2.2.0.1\n\nUI      - Minor cosmetic fixes\nCORE    - Minor stability fixes\n\n\n\n\n2.2.0.0\n\nThis release incorporates several major feature branches, which combined involve over years of major development effort.\nHighlights include:\n * The final phase of our PoW² rollout, which brings new functionality to witness addresses/accounts\n * Our new 'v2' transaction format\n * Unity; A single unified codebase backend that is shared between desktop and mobile wallets\n\nPoW² phase4:\nCORE    - Ability to compound witness earnings becomes active\nCORE    - Delta difficulty adjustments now uses the more accurate witness time instead of the mining time, which should improve block timings and reduce  hash rate swings\nUI      - Easily toggle compounding on/off for a witness account\nUI      - Extend the locktime and/or quantity of a witness account via UI\nUI      - New optimise button which can be used on large witness accounts (>1% network weight) to divide/combine into smaller/larger parts for better earnings\nUI      - Improved dialog for funding witness accounts; Also automatically optimizes large witness accounts (>1% network weight) into multiple parts when creating if appropriate\nRPC     - Various Phase4 RPC commands become active:\n            Add funds to a witness account and/or extend the lock period - extendwitnessaccount \"funding_account\" \"witness_account\" \"amount\" \"time\" \n            Add funds to a witness address and/or extend the lock period - extendwitnessaddress \"funding_account\" \"witness_address\" \"amount\" \"time\" \n            Split a witness account into multiple witness addresses; Lock period is not changed this exists for the benefit of users whose weight is too large for the network - splitwitnessaccount \"funding_account\" \"witness_account\" \"amounts\" \n            Merge multiple identical witness addresses into a single one; Only works on identical accounts i.e. ones that have previously been split - mergewitnessaccount \"funding_account\" \"witness_account\"\n            Change the witness key on an account where the key may have been compromised or as a periodic precaution - rotatewitnessaccount \"funding_account\" \"witness_account\" \n            Change the witness key on an address where the key may have been compromised or as a periodic precaution  - rotatewitnessaddress \"funding_account\" \"witness_address\" \n            Set a witness account to compound all or part of the earnings it receives - setwitnesscompound \"witness_account\" \"amount\"\n            Check the compounding settings for a witness account - getwitnesscompound \"witness_account\"\n            Set an address or script other than the default for witness reward payout - setwitnessrewardscript \"witness_account\" \"destination\" force_pubkey\n            Get the current address or script that has been set for witness reward payout - getwitnessrewardscript \"witness_account\" \n            Set the compounding template for a witness account; Can be used to managed advanced configurations of how the reward should be paid out - setwitnessrewardtemplate \"witness_account\" [[\"destination1\" (,\"amount\") (,\"percentage%\") (,\"remainder\") (,\"compound_overflow\")], [\"destination2\" ...], ...]\n            Get the compounding template for a witness account - getwitnessrewardtemplate \"witness_account\" \n\n\nv2 transaction format (SegSig):\nCORE    - New compact transaction format, with a \"only pay for what you use\" philosophy. Extensible transaction output/input types and flags for easier future extendability in various directions. Uses various built in methods like compact amount representation to ensure transactions are as small as possible while being efficient to process.\nCORE    - Transaction functionality like RBF using proper built in flags instead of magic values\nCORE    - Three new initial transaction types (extensible to more)\n            * Script - Bitcoin compatible 'script' format as in v1 transaction format, for more complex types of transactions that require this functionality \n            * StandardKeyHash - A compact and concise format for regular day to day transactions without the extra unnecessary processing overhead of a scripting language\n            * PoW2WitnessOutput - A compact and concise format for witness transactions; Replaces the sub-optimal requirement of placing all the witnessing information in; More compact, faster to process and leads to a cleaner code base\nCORE    - Compact transaction signatures used throghout for smaller transaction size\nCORE    - Introduce 'index based outpoints' to new transaction format; allowing for reduction of transaction size in many cases.\nCORE    - Remove unncessary requirement of 'OP_0' from multisig transaction signatures (Legacy bitcoin bug)\nCORE    - Transaction signatures are seperate from the transaction script; Similar to SegWit, but done in a more efficient way that doesn't have to worry about backwards compatibility\nCORE    - Remove sources of transaction malleability; Similar to SegWit, but done in a more efficient way that doesn't have to worry about backwards compatibility \n\n\nOther:\nCORE    - Extend recovery phrase with (optional) birth number\nUI      - Option to hide status bar when synchronized (default enabled). Disable to always show status indicators.\nRPC     - Implement new 'importlinkedaccount' command.\nRPC     - Add an optional purge option to 'deleteseed' command.\nRPC     - Add 'initialblockdownload', 'automatic_pruning' and 'prune_target_size' fields to 'getblockchaininfo' results\nRPC     - Add 'fail_count' and 'action_nonce' data to 'getwitnessinfo' command.\nAnd numerous more smaller changes and bug fixes, for a comprehensive list view the commit history on our github repository.\n\n\n\n\n2.1.0.24\n\nCORE    - Lower default memory usage on devices with <1gb memory.\nCORE    - Update to V2 nocks API for IBAN transactions.\nCORE    - Several minor mining improvements\nUI      - Display arena setup time in mining UI\nRPC     - Improve 'resetdatadirpartial' and 'resetdatadirfull' functionality.\n\n\n\n\n2.1.0.22\n\nUI      - Performance improvement when syncing with a wallet that has a witness account and lots of transactions\nUI      - Introduce a way to show/hide orphan transactions in account transaction list\nUI      - Transaction list export functionality, and button for account transaction list export\nUI      - Add a context menu item to remove all orphan transactions for an account\nUI      - New 'recipient' input field and related functionality for IBAN payments\nCORE    - Fix an issue with reporting of peer IPv6 addresses\nCORE    - Fix an issue with dual IPv6/IPv4 binds\nCORE    - Fix an issue when binding multiple listening sockets\n\n\n\n\n2.1.0.20\n\nUI      - Various minor UI fixes.\nCORE    - Minor enhancements to SIGMA mining performance.\nCORE    - Fix some periodic crashes and minor stability issues with SIGMA mining.\nCMDFLAG - New config flag \"sigmaalgo\" which can be used to bypass automatic algorithm detection. (Valid options currently are: ref, avx512f, avx2, avx, sse4.2, ssse3, avx512faes, avx2aes, avxaes, sse4.2aes, ssse3aes)\n\n\n\n\n2.1.0.19\n\nUI      - Introduce an 'open datadir' button to debug info window\nUI      - Fix a small bug with sending funds from mining account\nCORE    - Fix various minor race conditions in code\nCORE    - Minor improvements to default settings for low memory machines\nRPC     - New support specific RPC commands to aid support staff in assisting users: resetdatadirpartial, resetdatadirfull, getcheckpoint, getlastblocks, resetconfig, resetconfig_pi_lowmem, resetconfig_pi_medmem\nRPC     - Improve responsiveness of 'setgenerate' and 'getgenerate' commands\nRPC     - Update output of getblock and other commands to include pre/post nonce \n\n\n\n\n2.1.0.18\n\nMISC    - Introduce small new feature to help update users who got stuck on a fork\nUI      - Automatically lower the mining memory limits on 32 bit systems that can't handle 4GB of process memory\nUI      - Various minor improvements to mining UI\nCORE    - Fix an issue with autodetection of mining accounts when recovering from phrase\nCORE    - Improve the way total network hashrate is estimated (RPC: getnetworkhashps)\nRPC     - New RPC command 'getminingrewardaddress'\nRPC     - Improve the way human difficulty is displayed for SIGMA so that its more human friendly (not fractional)\n\n\n\n\n2.1.0.17\n\nMISC    - Update checkpoints\nCORE    - Improve upgrade procedure for any users who failed to upgrade for previous releases in time and were temporarily stuck on a fork.\nUI      - Minor improvements to information display in mining dialog.\n\n\n\n\n2.1.0.16\n\nCORE    - Temporarily reduce witness reward back to 20, due to unexpected complications with adjusting witness rewards during phase3. Reward will be restored to 30 at a future date after further discussion on how to proceed.\n\n\n\n\n2.1.0.15\n\nCORE    - Adjust minimum PoW limit; as with delta hashrate is much slower than regular PoW algorithms.\n\n\n\n\n\n2.1.0.14\n\nCORE    - Reduce mainnet proof of work limit to be lower as SIGMA works at a much lower difficulty, and is causing blocks to take very long to solve.\n\n\n\n\n2.1.0.12\n\nUI      - Introduce new basic user interface for mining\nUI      - Fix a bug on windows where closing the debug dialog with main app hidden could cause the entire app to close\nCORE    - Introduce new 'mining' account type\nRPC     - New command 'createminingaccount'\nRPC     - New command 'setminingrewardaddress'\nRPC     - Modify 'setgenerate' behaviour to work with mining accounts when present, a regular account can still be used by explicitely passing an account name when calling 'setgenerate'\nCMDFLAG - New flag '-genmemlimit' to go with existing '-gen' and '-genproclimit'\n\n\n\n\n2.1.0.11\n\nThis release introduces the new SIGMA PoW algorithm, a 'CPU friendly' algorithm designed to better suit Guldens needs than the previous algorithm scrypt that was used before.\nCORE    - Introduce new utility 'bench_sigma' for testing/benchmarking SIGMA outside of the Gulden app itself.\nCORE    - Fix DOS vulnerability (crash) in witness bundle input checking\nCORE    - Introduce SIGMA as the new PoW algorithm in testnet builds.\nCORE    - Minor improve to Delta difficulty adjustment algorithm to work better with SIGMA\nCORE    - Introduce new/modified reward schedule for development funding and slight increase in witness rewards (as per GAB decision)\nRPC     - Modify 'setgenerate' command to take a memory paramater for SIGMA\nRPC     - Improve output of 'getnetworkhashps' command\nRPC     - Drop support for 'getblocktemplate' - it is not required for CPU mining and we can simplify the codebase without it.\n\n\n\n\n2.1.0.7\n\nRPC     - Fix a bug in InvalidateBlock behaviour when called on a block that isn't currently in the main chain.\nCORE    - Minor improvement to mining behaviour when an absent witness is present.\nUI      - Fix a windows only issue with non-ASCII wallet paths. (Introduced by bdb upgrade)\n\n\n\n\n2.1.0.6\n\nMISC    - Update checkpoints.\nCORE    - Introduce an improvement to checkpoint server mechanism to temporarily help stabalise chain against mining instability. Mechanism will be removed once phase4 and/or SIGMA are active and is just a temporary measure.\n\n\n\n\n2.1.0.5\n\nCORE    - Fix a rare issue where witnessing devices would fail to witness due to not completing a proper rescan after importing a witness address.\nCORE    - Improve transaction propagation speed by pushing mempool to new connections\nCORE    - Introduce builds of the UI client for all architectures (\"arm\" and \"aarch64\" previously did not have)\nCORE    - Introduce \"riscv64\" to the list of officially supported architectures.\nCORE    - Introduce AppImage installers for \"arm\" and \"aarch64\"\nRPC     - New command \"getaccountaddress\" to get current receiving address (as would be displayed in UI) for an account.\nMISC    - Update to newer version of Qt which should improve various minor UI aspects.\n\n\n\n\n2.1.0.4\n\nMISC    - Minor maintenance release, update checkpoints and other minor changes\nCORE    - Introduce some code to automatically detect and clear the failed verification status of blocks in certain situations where it is safe to do so. This will make it easier for users who fail to update before a fork to update after the fork without having to issue any manual commands.\nCORE    - Add some additional logging of error conditions to the witness loop.\nCORE    - Fix a potential race condition in networking code, that may have been the cause of very rare intermittent network related crashes. Detected on android as part of \"unity\" project.\nUI      - Fix a display issue with \"local currency\" mouse-over tooltips.\nUI      - Fix a small display update issue when switching between witness and normal accounts in some instances.\nUI      - Clean up the language selection list in options dialog.\nZMQ     - Fix a bug in the NotifyStalledWitness ZMQ code.\n\n\n\n\n2.1.0.3\n\nUI      - Modify witness QR for better interoperability with external apps.\nUI      - Remove embedded webkit for buy page in favour of simply launching buy page in an external browser.\nRPC     - Minor RPC fixes.\n\n\n\n\n2.1.0.1\n\nUI      - Implement an address tab for witness accounts, for easier access of the current active witness account address and for better integration with third party monitoring apps.\n\n\n\n\n2.1.0.0\n\nCORE    - Implement a few consensus level changes for witnessing, these are minor improvements but are better to make now before phase 4 activation for the sake of future code cleanliness.\n        These changes will, these changes will activate at block 881000 (Estimated around 17-18th January 2019) all 2.0.x users should attempt to update before then, all 1.6.x users can remain on 1.6.x - contact developers for assistance if in doubt.\nUI      - Minor UI fixes\n\n\n\n\n2.0.0.17\nRPC     - Introduce new debug command verifywitnessaddress\nUI      - Update styling and graphics\n\n\n\n\n2.0.0.15\nUI      - Fix font issues with macOS mojave\n\n\n\n\n2.0.0.14\nCORE    - Fix for upstream critical vulnerability CVE-2018-17144\n\n\n\n\n2.0.0.12\nUI      - Improve visual look of the \"all\" button in the send coins dialog.\nUI      - Fix a problem with increasing memory consumption over time that was affecting some users.\nUI      - Fix an issue where emptying an \"unlocked\" witness account first required restarting the wallet.\nUI      - Fix an issue where an \"unlocked\" witness account would show incorrect statistical information.\nCORE    - Reduce memory footprint and improve performance of witness validation.\n\n\n\n\n2.0.0.11\nUI      - Display full converted balance in upper left for forex (Euro or other currency) display instead of only available balance; Add a tooltip to break down the different amounts when hovered over.\nUI      - Fix an issue where the transaction list would sometimes show confusing more recent timestamps when importing a witness-only key or recovering from phrase.\nRPC     - New command \"getaddress\" as a way to easily get Gulden address(es) from a pubkey or script.\nRPC     - New command \"emptymempool\" to temporarily empty the mempool of all transactions, useful for debugging as well as a last resort tool if mining pools ever find themselves in a situation where mempool is somehow misbehaving.\nRPC     - Fix a crash when calling 'validateaddress' with no wallet.\nCORE    - Fix a \"CreateBlock\" issue that was triggering in rare circumstances and affecting \"getblocktemplate\" RPC calls by miners when it did.\nCORE    - Fix a crash that can occur during rescan when using zapwallettxes.\nCORE    - Enable witness renewal and emptying of witness accounts whose lock period has expired - from block 797000 onwards.\nCMDFLAG - New command line flag \"-disablenet\" to start with networking disabled, useful in some debugging scenarios.\nCMDFLAG - New command line flag \"-zmqpubstalledwitness=<address>\" to turn on zmq monitoring for stalled witnesses.\nZMQ     - Add new message \"stalledwitness\" which can be used by services to monitor for slow and absent witnesses - enabled via CMDFLAG \"zmqpubstalledwitness\"\n\n\n\n\n2.0.0.10\nRPC     - Make \"getrescanprogress\" command more responsive.\nUI      - Fix an issue with \"orphaned\" witness earnings incorrectly showing as part of account balance.\nUI      - Add a user alert message if number of witnesses on the network drops below 100 as a precaution to help keep the number of witnesses high.\nUI      - Fix a bug with wallet rescan progress display.\nUI      - Another fix to prevent \"Failed to calculate witness info for candidate block\" dialog from showing in situations where it isn't really harmful.\nUI      - Fix an issue some users were having with unlocking wallet.\nUI      - Fix an issue where the receive coins dialog would, when creating a new account, in certain instances temporarily show the address for a different account.\nUI      - Allow emptying of non-witness funds if normal funds are somehow sent to a witness account address.\nUI      - Fix a small glitch where empty wallet balance would occasionally display as -0.00\nUI      - Fix a transaction view issue where \"locked from\" transactions were occasionally displayed as \"received from\" instead.\nRPC     - Fix a small issue with one of the weights being output incorrectly in `getwitnessinfo` command.\nRPC     - Add some additional PoW² related output to 'getblock' and 'getheader' calls.\nRPC     - Fix an occasional/intermittent issue where getblocktemplate would fail when called by mining pools\nCMDFLAG - Default \"minimallogging\" flag to on for arm and aarch64 architectures.\nCORE    - Fix a block relay issue that combined with other factors was occasionally leading to temporary chain stalls.\n\n\n\n\n2.0.0.9\nCORE    - Major witness validation performance improvement and memory usage reduction due to partial chain cloning\nCORE    - Move some invalid block logic earlier in the block check process, this should help address some issues users have been experiencing as well as further stabalise the network.\nCORE    - Simplify phase2/phase3 checks now that we know the final blocks where they activated; This will help performance in various ways and simplifies the code.\nCORE    - Some minor performance improvements\nUI      - Fix an underlying issue that was causing a \"scary\" looking message dialog to occasionally pop up and bother some users.\nUI      - Fix an issue with witness earnings graph display for units other than \"blocks\"\nUI      - Fix an occasional/random UI lockup when password dialog shows from backup page.\nCMDFLAG - Add a new flag `limitdeltadiffdrop=n` for mining pools, larger mining pools should set this to 0. Medium pools 1-6, very small pools can leave it off.\nCMDFLAG - Add new \"minimallogging\" flag for the benefit of users with limited disk space e.g. pi users\n\n\n\n\n2.0.0.7\nCORE    - Fix a crash for users who run with -disablewallet\n\n\n\n\n2.0.0.6\nCORE    - Stability fix for a minor crash issue some users might otherwise experience in phase 3.\nUI      - Some very minor localisation and UI cleanups\nUI      - Fix a balance display issue\nWALLET  - Implement detection for an issue with incorrect HD index counter incrementing that may have affected some users in past versions of the software. Users who are affected are in no immediate danger but should be warned to rectify the issue regardless.\nNET     - No longer advertise or establish outgoing connections to outdated (1.6.x) peers but allow incoming connections from them.\n\n\n\n\n\n2.0.0.4\nUI      - Fix a (phase 3 only) issue where the transaction list sometimes displaying unnecessary duplicate \"rejected\" earning messages for every valid earning message.\nRPC     - Add two commands disablewitnessing/enablewitnessing - useful for various testing scenarios and some other fringe use cases.\nNET     - Fix an annoying instability issue (crash) in the networking code that is triggered by the checkpoint system in some scenarios.\n\n\n\n\n2.0.0.2\nUI      - Implement an improved \"new account\" page; which makes witnessing more visible as well as better displays and advertizes various other capabilities of our wallets.\nUI      - Resolve a minor issue where old Legacy accounts were incorrectly hidden by UI in some circumstances, due to an old already fixed issue that was in some older 1.6.x wallets.\nCMDFLAG - Add a new command line flag \"-resyncforblockindexupgrade\" for the benefit of some devices that may be having trouble upgrading.\nCMDFLAG - Add a new command line flag \"-reverseheaders\" to allow control over whether to use reverse headers or not.\nCORE    - Various code quality improvements; travis now running with '-Werror -Wall -Wextra' for first time.\n\n\n\n2.0.0.1\nRPC     - Fix a small issue with rescan progress percentage\nCORE    - Fix an issue with locked wallets and account indexes that was triggering assertions in some cases.\nUI      - Fix a possible minor crash that some users may have been encountering during upgrade.\nUI      - Fix an issue with GuldenD and repeated unlock requests, limit to a single unlock request.\n\n\n\n\n2.0.0\nThis release incorporates three new major feature branches, which combined involve over a year of intense development effort:\n* PoW² - See https://github.com/Gulden/gulden-official/raw/master/technical_documentation/Gulden_PoW2.pdf for technical information\nHighlights include: Ability to lock funds for a period of time and earn rewards while securing the network. Drastically enhanced network security.\n\nUI      - New \"witness overview\" dialog with info and statistics on witness accounts, complete with a graph showing current and predicted earnings.\nUI      - New \"witness fund\" dialog, with estimate to help pick the right weight when funding an account.\nCORE    - New blockchain consensus rules for a PoW² driven blockchain with determistic witnessing.\nCORE    - New address type for two key witness accounts\nCORE    - New account types for witnessing, including special behaviour (hardening) of the witness key chain so that witness keys can be shared without compromising wallet security.\nCORE    - New witness-only account types for linked witnessing between main wallet and a backup witness device.\nCORE    - Automatic witnessing of incoming blocks in exchange for rewards\nRPC     - New commands:\n        View a statistical/informational snapshot of the witness system for any block in the blockchain - getwitnessinfo \"block_specifier\" verbose mine_only\n        Create a new witness account - createwitnessaccount \"name\"\n        Lock funds into a witness account - fundwitnessaccount \"funding_account\" \"witness_account\" \"amount\" \"time\" \"force_multiple\"\n        Add funds to a witness account and/or extend the lock period - extendwitnessaccount \"funding_account\" \"witness_account\" \"amount\" \"time\" \n        Add funds to a witness address and/or extend the lock period - extendwitnessaddress \"funding_account\" \"witness_address\" \"amount\" \"time\" \n        Export a URL for creation of a linked \"witness-only\" account - getwitnessaccountkeys \"witness_account\" \n        Import a \"witness-only\" account from a URL that has previously been exported - importwitnesskeys \"account_name\" \"encoded_key_url\" \"create_account\"\n        Split a witness account into multiple witness addresses; Lock period is not changed this exists for the benefit of users whose weight is too large for the network - splitwitnessaccount \"funding_account\" \"witness_account\" \"amounts\"\n        Merge multiple identical witness addresses into a single one; Only works on identical accounts i.e. ones that have previously been split - mergewitnessaccount \"funding_account\" \"witness_account\"\n        Renew a witness account that has expired due to failiure to witness - renewwitnessaccount \"witness_account\" \n        Change the witness key on an account where the key may have been compromised or as a periodic precaution - rotatewitnessaccount \"funding_account\" \"witness_account\"\n        Change the witness key on an account where the key may have been compromised or as a periodic precaution  - rotatewitnessaddress \"funding_account\" \"witness_address\"\n        Set a witness account to compound all or part of the earnings it receives (phase 4 only) - setwitnesscompound \"witness_account\" \"amount\"\n        Check the compounding settings for a witness account - getwitnesscompound \"witness_account\"\n        Set an address or script other than the default for witness reward payout - setwitnessrewardscript \"witness_account\" \"address_or_script\" force_pubkey \n        Get the current address or script that has been set for witness reward payout - getwitnessrewardscript \"witness_account\" \nRPC     - GetBlockTemplate support for mining in conjunction with phase 3 witnessing.\n\n* SegSig - A new transaction format. See https://github.com/Gulden/gulden-official/blob/master/technical_documentation/transaction_format.md for technical information.\nHighlights include: Solving of malleability issues; More compact transactions (over 50% in some cases) leading to increased network capacity for peak transaction periods; New transaction types (for PoW²); Extensible transaction types for future development.\n\nCORE    - Implement fixes for transaction malleability\nCORE    - Implement new more compact transaction format\nCORE    - Implement two new transaction types \"StandardKeyHash\" and \"PoW2_Witness\"\nCORE    - Implement version scheme allowing easy future creation of additional compact special purpose transactions\nCORE    - Witness based version bit activation, for better control of future updates. Feature activation can now be controlled by \"miner voting\", \"witness voting\" or a combination at developer discretion.\n\n* Sonic - The sonic project involves multiple changes to the p2p networking stack within Gulden.\nHighlights include: A switch to boost::asio for the networking stack to replace the old select() based networking code; Multiple improvements to the initial chain synchronisation process, including reverse header synchronisation, making it drastically faster; Removal of limitations to how many peers a server can handle, which helps solve scalability/congestion issues on the network in peak usage periods.\n\n* Non exhaustive list of additional general changes.\nUI      - Gulden desktop client gains an automatic update check to alert users of updates. Update check is cryptographically secured to ensure that it cannot be tampered with.\nUI      - Improved handling of wallet alerts/warnings through a new warning dialog.\nUI      - New \"all\" button on send coin screen to send all funds.\nUI      - Major reworking of send coin screen including improved Nocks integration and many other bug fixes.\nUI      - Improve handling of small window sizes; hide some window elements on smaller windows when necessary.\nUI      - Add localisation for the loading/splash screen when wallet first opens.\nCORE    - Improved handling of \"private key\" imports.\nCORE    - Major performance improvements for wallets with lots of transactions.\nCORE    - Major performance improvements for wallets with lots of accounts.\nCORE    - Performance improvements when creating new accounts.\nCORE    - Numerous other performance improvements throughout the wallet.\nCORE    - Major reworking of application life cycle management (open/close); so that it is faster and more consistent across applications. This forms the first step of our future \"Unity\" project, and fixes various crash at exit bugs and possible sources of wallet corruption.\nCMDFLAG - Add a -windowtitle command flag, primarily intended to be used to assist with testing so that multiple program instances can be easily distinguished.\nCMDFLAG - Add a new -disableui flag to start with just a RPC console (and wallet); Useful for some types of debugging.\nRPC     - New command 'getaccountbalances' return a list of individual balances for all accounts.\nRPC     - New command 'listunspentforaccount' as account specific counterpart for listunspent.\nRPC     - New command 'rescan' to trigger a wallet rescan (Same as Tools>rescan via UI).\nRPC     - New command 'getrescanprogress' to view the progress percentageof an ongoing wallet rescan.\nRPC     - New command 'getimmaturebalance' as conterpart to 'getunconfirmedbalance'\nRPC     - Add account capability to 'sendmany' command.\nRPC     - Modify 'listaccounts' command to take an optional second paramater to filter on account state. Add a new \"state\" field to the output and clarify better the difference between \"type\" and \"HD_type\"\nAnd many more changes and bug fixes, for a comprehensive list view the commit history on our github repository.\n\n\n\n\n1.6.4.8\nMinor maintenence release.\nUI      - Introduce a new informational widget and other minor UI improvements that make it move obvious to users that the wallet is not yet available during initial sync.\nUI      - Add a new menu item for setting the currency.\nUI      - Fix a crash in the send dialog on machines with no network connection.\nUI      - Remove bitcoin payment option from send screen\nCORE    - Update checkpoints, static difficulties, static seeds and other static information to help assist new users with better syncing experience.\n\n\n\n\n1.6.4.7\nMinor testnet related release.\n\n\n\n\n1.6.4.6\nRPC     - Fix an issue introduced in 1.6.4.3 which can cause users running with \"-disablewallet\" to experience RPC freezes when calling certain RPC commands.\n\n\n\n\n1.6.4.5\nUI      - Fix \"run on boot\" links that were broken by testnet changes and other minor \"run on boot\" corrections.\n\n\n\n\n1.6.4.1\nMinor bugfix release.\nUI      - Some small translation changes\nRPC     - Add an HDIndex flag to 'listaccounts' RPC output, useful for debugging HD wallet issues.\nCORE    - Speed up address allocation when -keypool is set to a larger than default size.\n\n\n\n\n1.6.4\nCMDFLAG - Add new command line flag '-coinbasesignature' to make it easy to add coinbase signatures to generated blocks (predominantly meant for testnet)\nCMDFLAG - Add new command line flag '-accountpool' to increase the default account look ahead size. (Needed in some cases to find accounts on rescan when large account gaps are present)\nUI      - Add a special warning if the users wallet.dat is readonly (instead of displaying a generic/scary 'corrupted wallet' message)\nUI      - Improvements to send dialog, improve handling when user tries to send amounts equal too or larger than available balance.\nUI      - New menu item for importing private keys.\nUI      - New menu item to allow users to easily rescan without having to use command line flags or mess around in RPC console.\nUI      - Improve the way rescan (and other actions that require progress) display in the program.\nUI      - Fix a bug where transaction screen would sometimes show transactions for all accounts instead of just the active one.\nRPC     - Modify createaccount command so that it can also create legacy accounts.\nRPC     - New commands for read only (watch) HD accounts. getreadonlyaccount, importreadonlyaccount.\nRPC     - New command for read only (watch) HD seeds, getreadonlyseed.\nRPC     - New 'deleteaccount' command\nRPC     - Modify 'move' command so that it can handle `-1` as input for the amount field, passing '-1' will calculate the available balance in the account for the confirmation level passed and transfer all of it.\nRPC     - Merge a bug fix from user 'mezrin' for 'dumpwallet' command.\nRPC     - Fix a bug in command 'gettransaction' where transaction would not show if 'rpconlylistsecuredtransactions' flag was set to false.\nCORE/RPC/UI - Support for read only (watch) HD accounts.\nCORE/RPC/UI - Support for read only (watch) HD seeds.\nCORE    - Assorted other minor bug fixes.\n\n\n\n\n1.6.3\nRPC     - Fix incorrect getaddressesbyaccount output.\nCORE    - Fix a possible crash in the checkpoint system.\n\n\n\n\n1.6.2\nRPC     - Bring back command that was removed in 1.6.0, adapted to the new account system - getaccount \"Guldenaddress\"\nRPC     - Bring back command that was removed in 1.6.0, adapted to the new account system - getaddressesbyaccount \"account\"\n\n\n\n\n1.6.1\nMinor bugfix release.\n\n\n\n\n1.6.0\nUI      - New user interface with drastic improvements over the old user interface.\nUI      - Ticker/Exchange rate integration into app.\nUI      - In wallet support for buying coins with euro via nocks.\nUI/RPC/CORE - New 'account based' wallet internals.\nUI      - New in wallet buy support for bitcoin and IBAN via nocks API.\nUI/RPC/CORE - Full support for BIP33 and BIP44 HD wallet standards with mnemonics.\nUI/CORE - Implement support for synchronised mobile accounts.\nCORE    - Update to upstream bitcoin 0.13 codebase providing numerous bug fixes and improvements.\nCORE    - Improve the checkpointing code, fix a checkpoint corruption issue that some users were experiencing.\nRPC     - Change 'rpconlylistsecuredtransactions' to be on by default.\n\n\n\n\n1.5.5\nCORE    - Introduce a checkpoint system to protect against 50% attacks.\nUI      - Update the UI so that only checkpointed transactions are marked as 'final'\nRPC     - Update several commands so that exchanges can make use of the checkpoint system to be double spend proof.\n\n\n\n\n1.5.4\nMinor bugfix release.\n\n\n\n\n1.5.3\nMinor bugfix release.\n\n\n\n\n1.5.2\nMinor bugfix release.\nCORE    - Updated to new seed nodes.\nUI      - Fixed an issue with some external URIs not working on OSX machines.\nCORE    - Add the KGW fix to all platforms.\n\n\n\n\n1.5.1\nUI      - Rebrand to Gulden, updated UI.\nCORE    - Implement a fix for KGW difficulty algorithm on 32 bit systems - linux only.\n\n\n\n\n1.5.0\nCORE    - New updated codebase based on bitcoin 0.10/0.11\nCORE    - Impement a new difficulty adjustment algorithm named DELTA.\n"
  },
  {
    "path": "configure.ac",
    "content": "AC_PREREQ([2.69])\ndefine(_CLIENT_VERSION_MAJOR,       3)\ndefine(_CLIENT_VERSION_MINOR,       0)\ndefine(_CLIENT_VERSION_REVISION, 0)\ndefine(_CLIENT_VERSION_BUILD,       7)\ndefine(_CLIENT_VERSION_IS_RELEASE, false)\ndefine(_COPYRIGHT_YEAR, 2022)\ndefine(_COPYRIGHT_HOLDERS,[The %s developers])\ndefine(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Centure]])\nAC_INIT([Munt],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@munt.org],[Munt])\nAC_CONFIG_SRCDIR([src/init.cpp])\nAC_CONFIG_HEADERS([src/config/build-config.h])\nAC_CONFIG_AUX_DIR([build-aux])\nAC_CONFIG_MACRO_DIR([build-aux/m4])\n\nm4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal([PKG_PROG_PKG_CONFIG macro not found. Please install pkg-config and re-run autogen.sh])])\nPKG_PROG_PKG_CONFIG\nif test \"$PKG_CONFIG\" = \"\"; then\n  AC_MSG_ERROR([pkg-config not found])\nfi\n\nm4_define([_DAEMON_NAME], [Munt-daemon])\nm4_define([_CLI_NAME], [Munt-cli])\nm4_define([_GUI_NAME], [Munt])\nm4_define([_TX_NAME], [Munt-tx])\n[_DAEMON_NAME]=_DAEMON_NAME\n[_CLI_NAME]=_CLI_NAME\n[_GUI_NAME]=_GUI_NAME\n[_TX_NAME]=_TX_NAME\nAC_DEFINE(DAEMON_NAME, \"_DAEMON_NAME\", [Command name of the deamon binary])\nAC_DEFINE(CLI_NAME, \"_CLI_NAME\", [Command name of the cli binary])\nAC_DEFINE(GUI_NAME, \"_GUI_NAME\", [Command name of the gui binary])\nAC_DEFINE(TX_NAME, \"_TX_NAME\", [Command name of the tx binary])\n\n\ndnl Unless the user specified ARFLAGS, force it to be cr\nAC_ARG_VAR([ARFLAGS], [Flags for the archiver, defaults to <cr> if not set])\nif test \"${ARFLAGS+set}\" != \"set\"; then\n  ARFLAGS=\"cr\"\nfi\n\nAC_CANONICAL_HOST\n\nAH_TOP([#ifndef BUILD_CONFIG_H])\nAH_TOP([#define BUILD_CONFIG_H])\nAH_BOTTOM([#endif //BUILD_CONFIG_H])\n\ndnl faketime breaks configure and is only needed for make. Disable it here.\nunset FAKETIME\n\ndnl Automake init set-up and checks\nAM_INIT_AUTOMAKE([1.13 no-define subdir-objects foreign])\n\ndnl faketime messes with timestamps and causes configure to be re-run.\ndnl --disable-maintainer-mode can be used to bypass this.\nAM_MAINTAINER_MODE([enable])\n\ndnl make the compilation flags quiet unless V=1 is used\nAM_SILENT_RULES([yes])\n\ndnl Compiler checks (here before libtool).\nif test \"${CXXFLAGS+set}\" = \"set\"; then\n  CXXFLAGS_overridden=yes\nelse\n  CXXFLAGS_overridden=no\nfi\nAC_PROG_CXX\n\ndnl By default, libtool for mingw refuses to link static libs into a dll for\ndnl fear of mixing pic/non-pic objects, and import/export complications. Since\ndnl we have those under control, re-enable that functionality.\ncase $host in\n  *mingw*)\n     lt_cv_deplibs_check_method=\"pass_all\"\n  ;;\nesac\n\nAC_ARG_WITH([seccomp],\n  [AS_HELP_STRING([--with-seccomp],\n  [enable experimental syscall sandbox feature (-sandbox), default is yes if seccomp-bpf is detected under Linux x86_64])],\n  [seccomp_found=$withval],\n  [seccomp_found=auto])\n\ndnl Require C++17 compiler (no GNU extensions)\nAX_CXX_COMPILE_STDCXX([17], [noext], [mandatory], [nodefault])\ndnl Check if -latomic is required for <std::atomic>\nCHECK_ATOMIC\n\ndnl Check for compiler (not cpu/runtime) intrinsic support.\nINTRINSIC_FLAG_CHECK\n\ndnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures\ndnl that we get the same -std flags for both.\nm4_ifdef([AC_PROG_OBJCXX],[\nif test \"${OBJCXX+set}\" = \"\"; then\n  OBJCXX=\"${CXX}\"\nfi\nAC_PROG_OBJCXX\n])\n\ndnl Since libtool 1.5.2 (released 2004-01-25), on Linux libtool no longer\ndnl sets RPATH for any directories in the dynamic linker search path.\ndnl See more: https://wiki.debian.org/RpathIssue\nLT_PREREQ([1.5.2])\ndnl Libtool init checks.\nLT_INIT([pic-only win32-dll])\nLIBTOOL=\"$LIBTOOL --preserve-dup-deps\"\n\ndnl Check/return PATH for base programs.\nAC_PATH_TOOL([AR], [ar])\nAC_PATH_TOOL([RANLIB], [ranlib])\nAC_PATH_TOOL([STRIP], [strip])\nAC_PATH_TOOL([GCOV], [gcov])\nAC_PATH_PROG([LCOV], [lcov])\ndnl Python 3.5 is specified in .python-version and should be used if available, see doc/dependencies.md\nAC_PATH_PROGS([PYTHON], [python3.5 python3.6 python3.7 python3.8 python3 python])\nAC_PATH_PROG([GENHTML], [genhtml])\nAC_PATH_PROG([GIT], [git])\nAC_PATH_PROG([CCACHE], [ccache])\nAC_PATH_PROG([XGETTEXT], [xgettext])\nAC_PATH_PROG([HEXDUMP], [hexdump])\nAC_PATH_TOOL(READELF, readelf)\nAC_PATH_TOOL(CPPFILT, c++filt)\nAC_PATH_TOOL([OBJCOPY], [objcopy])\nAC_PATH_PROG(DJINNI_RUN, djinni-run,, $prefix/bin)\n\nAC_ARG_VAR([PYTHONPATH], [Augments the default search path for python module files])\n\n# Enable wallet\nAC_ARG_ENABLE([wallet],\n  [AS_HELP_STRING([--disable-wallet],\n  [disable wallet (enabled by default)])],\n  [enable_wallet=$enableval],\n  [enable_wallet=yes])\n\nAC_ARG_WITH([bdb],\n  [AS_HELP_STRING([--without-bdb],\n  [disable bdb wallet support (default is enabled if wallet is enabled)])],\n  [use_bdb=$withval],\n  [use_bdb=auto])\n\nAC_ARG_WITH([miniupnpc],\n  [AS_HELP_STRING([--with-miniupnpc],\n  [enable UPNP (default is yes if libminiupnpc is found)])],\n  [use_upnp=$withval],\n  [use_upnp=auto])\n\nAC_ARG_ENABLE([upnp-default],\n  [AS_HELP_STRING([--enable-upnp-default],\n  [if UPNP is enabled, turn it on at startup (default is no)])],\n  [use_upnp_default=$enableval],\n  [use_upnp_default=no])\n\nAC_ARG_ENABLE(tests,\n    AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]),\n    [use_tests=$enableval],\n    [use_tests=yes])\n\nAC_ARG_ENABLE(gui-tests,\n    AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]),\n    [use_gui_tests=$enableval],\n    [use_gui_tests=$use_tests])\n\nAC_ARG_WITH([rapidcheck],\n  [AS_HELP_STRING([--with-rapidcheck],\n  [enable RapidCheck property based tests (default is yes if librapidcheck is found)])],\n  [use_rapidcheck=$withval],\n  [use_rapidcheck=auto])\n\nAC_ARG_ENABLE(bench,\n    AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]),\n    [use_bench=$enableval],\n    [use_bench=yes])\n\nAC_ARG_ENABLE([extended-functional-tests],\n    AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]),\n    [use_extended_functional_tests=$enableval],\n    [use_extended_functional_tests=no])\n\nAC_ARG_WITH([qrencode],\n  [AS_HELP_STRING([--with-qrencode],\n  [enable QR code support (default is yes if qt is enabled and libqrencode is found)])],\n  [use_qr=$withval],\n  [use_qr=auto])\n\nAC_ARG_ENABLE([hardening],\n  [AS_HELP_STRING([--disable-hardening],\n  [do not attempt to harden the resulting executables (default is to harden when possible)])],\n  [use_hardening=$enableval],\n  [use_hardening=auto])\n\nAC_ARG_ENABLE([reduce-exports],\n  [AS_HELP_STRING([--enable-reduce-exports],\n  [attempt to reduce exported symbols in the resulting executables (default is no)])],\n  [use_reduce_exports=$enableval],\n  [use_reduce_exports=no])\n\nAC_ARG_ENABLE([ccache],\n  [AS_HELP_STRING([--disable-ccache],\n  [do not use ccache for building (default is to use if found)])],\n  [use_ccache=$enableval],\n  [use_ccache=auto])\n\ndnl Suppress warnings from external headers (e.g. Boost, Qt).\ndnl May be useful if warnings from external headers clutter the build output\ndnl too much, so that it becomes difficult to spot Core warnings\ndnl or if they cause a build failure with --enable-werror.\nAC_ARG_ENABLE([suppress-external-warnings],\n  [AS_HELP_STRING([--enable-suppress-external-warnings],\n                  [Suppress warnings from external headers (default is no)])],\n  [suppress_external_warnings=$enableval],\n  [suppress_external_warnings=no])\n\nAC_ARG_ENABLE([lcov],\n  [AS_HELP_STRING([--enable-lcov],\n  [enable lcov testing (default is no)])],\n  [use_lcov=yes],\n  [use_lcov=no])\n\nAC_ARG_ENABLE([zmq],\n  [AS_HELP_STRING([--disable-zmq],\n  [disable ZMQ notifications])],\n  [use_zmq=$enableval],\n  [use_zmq=yes])\n\nAC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], [])\n\nAC_ARG_ENABLE(man,\n    [AS_HELP_STRING([--disable-man],\n                    [do not install man pages (default is to install)])],,\n    enable_man=yes)\nAM_CONDITIONAL([ENABLE_MAN], [test \"$enable_man\" != \"no\"])\n\ndnl Enable debug\nAC_ARG_ENABLE([debug],\n    [AS_HELP_STRING([--enable-debug],\n                    [use compiler flags and macros suited for debugging (default is no)])],\n    [enable_debug=$enableval],\n    [enable_debug=no])\n\ndnl Enable different -fsanitize options\nAC_ARG_WITH([sanitizers],\n    [AS_HELP_STRING([--with-sanitizers],\n                    [comma separated list of extra sanitizers to build with (default is none enabled)])],\n    [use_sanitizers=$withval])\n\ndnl Enable gprof profiling\nAC_ARG_ENABLE([gprof],\n    [AS_HELP_STRING([--enable-gprof],\n                    [use gprof profiling compiler flags (default is no)])],\n    [enable_gprof=$enableval],\n    [enable_gprof=no])\n\ndnl Turn warnings into errors\nAC_ARG_ENABLE([werror],\n    [AS_HELP_STRING([--enable-werror],\n                    [Treat compiler warnings as errors (default is no)])],\n    [enable_werror=$enableval],\n    [enable_werror=no])\n\n# Strong warnings\nAC_ARG_ENABLE([strong-warnings],\n    [AS_HELP_STRING([--disable-strong-warnings],\n                    [Use compiler flags to generate extra warnings (default is yes)])],\n    [strong_warnings=$enableval],\n    [strong_warnings=yes])\n\nAC_LANG_PUSH([C++])\nAX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR=\"-Werror\"],[CXXFLAG_WERROR=\"\"])\n\nif test \"x$enable_debug\" = xyes; then\n    CPPFLAGS=\"$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER\"\n    if test \"x$GCC\" = xyes; then\n        CFLAGS=\"$CFLAGS -g3 -O0\"\n    fi\n\n    if test \"x$GXX\" = xyes; then\n        CXXFLAGS=\"$CXXFLAGS -g3 -O0\"\n    fi\nfi\n\nERROR_CXXFLAGS=\nif test \"x$enable_werror\" = \"xyes\"; then\n  if test \"x$CXXFLAG_WERROR\" = \"x\"; then\n    AC_MSG_ERROR(\"enable-werror set but -Werror is not usable\")\n  fi\n  AX_CHECK_COMPILE_FLAG([-Werror],[ERROR_CXXFLAGS=\"$ERROR_CXXFLAGS -Werror\"],,[[$CXXFLAG_WERROR]])\nfi\n\nif test \"x$strong_warnings\" = \"xyes\"; then\n  AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS=\"$CXXFLAGS -Wall\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS=\"$CXXFLAGS -Wextra\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS=\"$CXXFLAGS -Wformat\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS=\"$CXXFLAGS -Wvla\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS=\"$CXXFLAGS -Wformat-security\"],,[[$CXXFLAG_WERROR]])\n\n  ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all\n  ## unknown options if any other warning is produced. Test the -Wfoo case, and\n  ## set the -Wno-foo case if it works.\n  AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[CXXFLAGS=\"$CXXFLAGS -Wno-unused-parameter\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wself-assign],[CXXFLAGS=\"$CXXFLAGS -Wno-self-assign\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS=\"$CXXFLAGS -Wno-unused-local-typedef\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS=\"$CXXFLAGS -Wno-deprecated-register\"],,[[$CXXFLAG_WERROR]])\n  AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[CXXFLAGS=\"$CXXFLAGS -Wno-implicit-fallthrough\"],,[[$CXXFLAG_WERROR]])\nfi\nCPPFLAGS=\"$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS\"\n\nAC_ARG_WITH([utils],\n  [AS_HELP_STRING([--with-utils],\n  [build ]_CLI_NAME[ ]_TX_NAME[ binaries (default=yes)])],\n  [build_utils=$withval],\n  [build_utils=yes])\n\nAC_ARG_WITH([node-js-libs],\n  [AS_HELP_STRING([--with-node-js-libs],\n  [build node.js library (default=no)])],\n  [build_libs_node_js=$withval],\n  [build_libs_node_js=no])\n\nAC_ARG_WITH([jni-libs],\n  [AS_HELP_STRING([--with-jni-libs],\n  [build jni library (default=no)])],\n  [build_libs_jni=$withval],\n  [build_libs_jni=no])\n\nAC_ARG_WITH([objc-libs],\n  [AS_HELP_STRING([--with-objc-libs],\n  [build objc library (default=no)])],\n  [build_libs_objc=$withval],\n  [build_libs_objc=no])\n\nAC_ARG_WITH([daemon],\n  [AS_HELP_STRING([--with-daemon],\n  [build ]_DAEMON_NAME[ daemon (default=yes)])],\n  [build_daemon=$withval],\n  [build_daemon=yes])\n\n\ncase $host in\n  *mingw*)\n     TARGET_OS=windows\n     AC_CHECK_LIB([mingwthrd],[main],                    [], [AC_MSG_ERROR([libmingwthrd missing])])\n     AC_CHECK_LIB([kernel32], [GetModuleFileNameA],      [], [AC_MSG_ERROR([libkernel32 missing])])\n     AC_CHECK_LIB([user32],   [main],                    [], [AC_MSG_ERROR([libuser32 missing])])\n     AC_CHECK_LIB([gdi32],    [main],                    [], [AC_MSG_ERROR([libgdi32 missing])])\n     AC_CHECK_LIB([comdlg32], [main],                    [], [AC_MSG_ERROR([libcomdlg32 missing])])\n     AC_CHECK_LIB([winspool], [main],                    [], [AC_MSG_ERROR([libwinspool missing])])\n     AC_CHECK_LIB([winmm],    [main],                    [], [AC_MSG_ERROR([libwinmm missing])])\n     AC_CHECK_LIB([shell32],  [SHGetSpecialFolderPathW], [], [AC_MSG_ERROR([libshell32 missing])])\n     AC_CHECK_LIB([comctl32], [main],                    [], [AC_MSG_ERROR([libcomctl32 missing])])\n     AC_CHECK_LIB([ole32],    [CoCreateInstance],        [], [AC_MSG_ERROR([libole32 missing])])\n     AC_CHECK_LIB([oleaut32], [main],                    [], [AC_MSG_ERROR([liboleaut32 missing])])\n     AC_CHECK_LIB([uuid],     [main],                    [], [AC_MSG_ERROR([libuuid missing])])\n     AC_CHECK_LIB([rpcrt4],   [main],                    [], [AC_MSG_ERROR([librpcrt4 missing])])\n     AC_CHECK_LIB([advapi32], [CryptAcquireContextW],    [], [AC_MSG_ERROR([libadvapi32 missing])])\n     AC_CHECK_LIB([ws2_32],   [WSAStartup],              [], [AC_MSG_ERROR([libws2_32 missing])])\n     AC_CHECK_LIB([mswsock],  [main],                    [], [AC_MSG_ERROR([libmswsock missing])])\n     AC_CHECK_LIB([shlwapi],  [PathRemoveFileSpecW],     [], [AC_MSG_ERROR([libshlwapi missing])])\n     AC_CHECK_LIB([iphlpapi], [GetAdaptersAddresses],    [], [AC_MSG_ERROR([libiphlpapi missing])])\n     AC_CHECK_LIB([crypt32],  [main],                    [], [AC_MSG_ERROR([libcrypt32 missing])])\n\n     dnl -static is interpreted by libtool, where it has a different meaning.\n     dnl In libtool-speak, it's -all-static.\n     AX_CHECK_LINK_FLAG([-static], [LIBTOOL_APP_LDFLAGS=\"$LIBTOOL_APP_LDFLAGS -all-static\"])\n\n     AC_PATH_PROG([MAKENSIS], [makensis], [none])\n     if test \"$MAKENSIS\" = \"none\"; then\n       AC_MSG_WARN([makensis not found. Cannot create installer.])\n     fi\n\n     AC_PATH_TOOL([WINDRES], [windres], [none])\n     if test \"$WINDRES\" = \"none\"; then\n       AC_MSG_ERROR([windres not found])\n     fi\n\n     CPPFLAGS=\"$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601\"\n     if test \"x$CXXFLAGS_overridden\" = \"xno\"; then\n       CXXFLAGS=\"$CXXFLAGS -w\"\n     fi\n     case $host in\n       i?86-*) WINDOWS_BITS=32 ;;\n       x86_64-*) WINDOWS_BITS=64 ;;\n       *) AC_MSG_ERROR(\"Could not determine win32/win64 for installer\") ;;\n     esac\n     AC_SUBST(WINDOWS_BITS)\n\n     dnl libtool insists upon adding -nostdlib and a list of objects/libs to link against.\n     dnl That breaks our ability to build dll's with static libgcc/libstdc++/libssp. Override\n     dnl its command here, with the predeps/postdeps removed, and -static inserted. Postdeps are\n     dnl also overridden to prevent their insertion later.\n     dnl This should only affect dll's.\n     archive_cmds_CXX=\"\\$CC -shared \\$libobjs \\$deplibs \\$compiler_flags -static -o \\$output_objdir/\\$soname \\${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker \\$lib\"\n     postdeps_CXX=\n\n     ;;\n  *darwin*)\n     TARGET_OS=darwin\n     if  test x$cross_compiling != xyes; then\n       BUILD_OS=darwin\n       AC_CHECK_PROG([PORT],port, port)\n       if test x$PORT = xport; then\n         dnl add default macports paths\n         CPPFLAGS=\"$CPPFLAGS -isystem /opt/local/include\"\n         LIBS=\"$LIBS -L/opt/local/lib\"\n         if test -d /opt/local/include/db48; then\n           CPPFLAGS=\"$CPPFLAGS -I/opt/local/include/db48\"\n           LIBS=\"$LIBS -L/opt/local/lib/db48\"\n         fi\n       fi\n\n       AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert)\n       AC_CHECK_PROG([BREW],brew, brew)\n       if test x$BREW = xbrew; then\n         dnl These Homebrew packages may be keg-only, meaning that they won't be found\n         dnl in expected paths because they may conflict with system files. Ask\n         dnl Homebrew where each one is located, then adjust paths accordingly.\n         dnl It's safe to add these paths even if the functionality is disabled by\n         dnl the user (--without-wallet or --without-gui for example).\n\n         openssl_prefix=`$BREW --prefix openssl 2>/dev/null`\n         bdb_prefix=`$BREW --prefix berkeley-db4 2>/dev/null`\n         if test x$openssl_prefix != x; then\n           PKG_CONFIG_PATH=\"$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH\"\n           export PKG_CONFIG_PATH\n         fi\n\n         if test \"$use_bdb\" != \"no\" && $BREW list --versions berkeley-db@4 >/dev/null && test \"$BDB_CFLAGS\" = \"\" && test \"$BDB_LIBS\" = \"\"; then\n           bdb_prefix=$($BREW --prefix berkeley-db@4 2>/dev/null)\n           dnl This must precede the call to CENTURE_FIND_BDB48 below.\n           BDB_CFLAGS=\"-I$bdb_prefix/include\"\n           BDB_LIBS=\"-L$bdb_prefix/lib -ldb_cxx-4.8\"\n         fi\n       fi\n     else\n       case $build_os in\n         *darwin*)\n           BUILD_OS=darwin\n           ;;\n         *)\n           AC_PATH_TOOL([INSTALLNAMETOOL], [install_name_tool], install_name_tool)\n           AC_PATH_TOOL([OTOOL], [otool], otool)\n           AC_PATH_PROGS([GENISOIMAGE], [genisoimage mkisofs],genisoimage)\n           AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert)\n           AC_PATH_PROGS([IMAGEMAGICK_CONVERT], [convert],convert)\n           AC_PATH_PROGS([TIFFCP], [tiffcp],tiffcp)\n\n           dnl libtool will try to strip the static lib, which is a problem for\n           dnl cross-builds because strip attempts to call a hard-coded ld,\n           dnl which may not exist in the path. Stripping the .a is not\n           dnl necessary, so just disable it.\n           old_striplib=\n           ;;\n       esac\n     fi\n\n     AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS=\"$LDFLAGS -Wl,-headerpad_max_install_names\"])\n     CPPFLAGS=\"$CPPFLAGS -DMAC_OSX\"\n     OBJCXXFLAGS=\"$CXXFLAGS\"\n     ;;\n   *android*)\n     dnl make sure android stays above linux for hosts like *linux-android*\n     dnl libtool insists on inserting -nostdlib and other things which break our build, the below works around this\n     archive_cmds_CXX=\"\\$CC -shared \\$libobjs \\$deplibs \\$compiler_flags -o \\$output_objdir/\\$soname\"\n     postdeps_CXX=\n     ;;\n   *linux*)\n     TARGET_OS=linux\n     ;;\nesac\n\nif test x$use_extended_functional_tests != xno; then\n  AC_SUBST(EXTENDED_FUNCTIONAL_TESTS, --extended)\nfi\n\nif test \"$use_lcov\" = \"yes\"; then\n  if test \"$LCOV\" = \"\"; then\n    AC_MSG_ERROR([lcov testing requested but lcov not found])\n  fi\n  if test \"$GCOV\" = \"\"; then\n    AC_MSG_ERROR(\"[lcov testing requested but gcov not found])\n  fi\n  if test \"$PYTHON\" = \"\"; then\n    AC_MSG_ERROR([lcov testing requested but python not found])\n  fi\n  if test \"$GENHTML\" = \"\"; then\n    AC_MSG_ERROR([lcov testing requested but genhtml not found])\n  fi\n  LCOV=\"$LCOV --gcov-tool=$GCOV\"\n  AX_CHECK_LINK_FLAG([[--coverage]], [LDFLAGS=\"$LDFLAGS --coverage\"],\n    [AC_MSG_ERROR(\"lcov testing requested but --coverage linker flag does not work\")])\n  AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS=\"$CXXFLAGS --coverage\"],\n    [AC_MSG_ERROR(\"lcov testing requested but --coverage flag does not work\")])\nfi\n\ndnl Check for endianness\nAC_C_BIGENDIAN\n\ndnl Check for pthread compile/link requirements\nAX_PTHREAD\n\ndnl The following macro will add the necessary defines to build-config.h, but\ndnl they also need to be passed down to any subprojects. Pull the results out of\ndnl the cache and add them to CPPFLAGS.\nAC_SYS_LARGEFILE\ndnl detect POSIX or GNU variant of strerror_r\nAC_FUNC_STRERROR_R\n\nif test \"$ac_cv_sys_file_offset_bits\" != \"\" &&\n   test \"$ac_cv_sys_file_offset_bits\" != \"no\" &&\n   test \"$ac_cv_sys_file_offset_bits\" != \"unknown\"; then\n  CPPFLAGS=\"$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits\"\nfi\n\nif test \"$ac_cv_sys_large_files\" != \"\" &&\n   test \"$ac_cv_sys_large_files\" != \"no\" &&\n   test \"$ac_cv_sys_large_files\" != \"unknown\"; then\n  CPPFLAGS=\"$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files\"\nfi\n\nAX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS=\"$LDFLAGS -Wl,--large-address-aware\"])\n\nAX_GCC_FUNC_ATTRIBUTE([visibility])\nAX_GCC_FUNC_ATTRIBUTE([dllexport])\nAX_GCC_FUNC_ATTRIBUTE([dllimport])\n\nif test \"$enable_gprof\" = \"yes\"; then\n    dnl -pg is incompatible with -pie. Since hardening and profiling together doesn't make sense,\n    dnl we simply make them mutually exclusive here. Additionally, hardened toolchains may force\n    dnl -pie by default, in which case it needs to be turned off with -no-pie.\n\n    if test \"$use_hardening\" = \"yes\"; then\n        AC_MSG_ERROR([gprof profiling is not compatible with hardening. Reconfigure with --disable-hardening or --disable-gprof])\n    fi\n    use_hardening=no\n    AX_CHECK_COMPILE_FLAG([-pg],[GPROF_CXXFLAGS=\"-pg\"],\n        [AC_MSG_ERROR([gprof profiling requested but not available])], [$CXXFLAG_WERROR])\n\n    AX_CHECK_LINK_FLAG([-no-pie], [GPROF_LDFLAGS=\"-no-pie\"])\n    AX_CHECK_LINK_FLAG([-pg], [GPROF_LDFLAGS=\"$GPROF_LDFLAGS -pg\"],\n        [AC_MSG_ERROR([gprof profiling requested but not available])], [$GPROF_LDFLAGS])\nfi\n\nAC_SEARCH_LIBS([clock_gettime],[rt])\n\nif test \"$TARGET_OS\" != \"windows\"; then\n  dnl All windows code is PIC, forcing it on just adds useless compile warnings\n  AX_CHECK_COMPILE_FLAG([-fPIC], [PIC_FLAGS=\"-fPIC\"])\nfi\n\nif test \"$use_hardening\" != \"no\"; then\n  use_hardening=yes\n  AX_CHECK_COMPILE_FLAG([-Wstack-protector], [HARDENED_CXXFLAGS=\"$HARDENED_CXXFLAGS -Wstack-protector\"])\n  AX_CHECK_COMPILE_FLAG([-fstack-protector-all], [HARDENED_CXXFLAGS=\"$HARDENED_CXXFLAGS -fstack-protector-all\"])\n\n  AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=2],[\n    AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[\n      HARDENED_CPPFLAGS=\"$HARDENED_CPPFLAGS -U_FORTIFY_SOURCE\"\n    ])\n    HARDENED_CPPFLAGS=\"$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=2\"\n  ])\n\n  AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,--dynamicbase\"])\n  AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,--nxcompat\"])\n  AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,--high-entropy-va\"])\n  AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,-z,relro\"])\n  AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,-z,now\"])\n\n  if test \"$TARGET_OS\" != \"windows\"; then\n    AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS=\"-fPIE\"])\n    AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -pie\"], [HARDENED_LDFLAGS=\"$HARDENED_LDFLAGS -Wl,-pie\"], [\"-Werror\"])\n  fi\n\n  case $host in\n    *mingw*)\n       AC_CHECK_LIB([ssp], [main], [], [AC_MSG_ERROR([libssp missing])])\n    ;;\n  esac\nfi\n\ndnl this flag screws up non-darwin gcc even when the check fails. special-case it.\nif test x$TARGET_OS = xdarwin; then\n  AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS=\"$LDFLAGS -Wl,-dead_strip\"])\nfi\n\nAC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h])\n\nAC_CHECK_DECLS([getifaddrs, freeifaddrs],,,\n    [#include <sys/types.h>\n    #include <ifaddrs.h>]\n)\nAC_CHECK_DECLS([strnlen])\n\ndnl These are used for daemonization in daemon binary\nAC_CHECK_DECLS([fork])\n\nAC_CHECK_DECLS([le16toh, le32toh, le64toh, htole16, htole32, htole64, be16toh, be32toh, be64toh, htobe16, htobe32, htobe64],,,\n    [#if HAVE_ENDIAN_H\n                 #include <endian.h>\n                 #elif HAVE_SYS_ENDIAN_H\n                 #include <sys/endian.h>\n                 #endif])\n\nAC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,\n    [#if HAVE_BYTESWAP_H\n                 #include <byteswap.h>\n                 #endif])\n\nAC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll])\n\ndnl Check for MSG_NOSIGNAL\nAC_MSG_CHECKING(for MSG_NOSIGNAL)\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],\n [[ int f = MSG_NOSIGNAL; ]])],\n [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_NOSIGNAL, 1,[Define this symbol if you have MSG_NOSIGNAL]) ],\n [ AC_MSG_RESULT(no)]\n)\n\ndnl Check for MSG_DONTWAIT\nAC_MSG_CHECKING(for MSG_DONTWAIT)\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],\n [[ int f = MSG_DONTWAIT; ]])],\n [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ],\n [ AC_MSG_RESULT(no)]\n)\n\ndnl Check for malloc_info (for memory statistics information in getmemoryinfo)\nAC_MSG_CHECKING([for getmemoryinfo])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],\n [[ int f = malloc_info(0, NULL); ]])],\n [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_MALLOC_INFO], [1], [Define this symbol if you have malloc_info]) ],\n [ AC_MSG_RESULT([no])]\n)\n\ndnl Check for mallopt(M_ARENA_MAX) (to set glibc arenas)\nAC_MSG_CHECKING([for mallopt M_ARENA_MAX])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],\n [[ mallopt(M_ARENA_MAX, 1); ]])],\n [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_MALLOPT_ARENA_MAX], [1], [Define this symbol if you have mallopt with M_ARENA_MAX]) ],\n [ AC_MSG_RESULT([no])]\n)\n\nAC_MSG_CHECKING([for visibility attribute])\nAC_LINK_IFELSE([AC_LANG_SOURCE([\n  int foo_def( void ) __attribute__((visibility(\"default\")));\n  int main(){}\n  ])],\n  [\n    AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE,1,[Define if the visibility attribute is supported.])\n    AC_MSG_RESULT(yes)\n  ],\n  [\n    AC_MSG_RESULT([no])\n    if test \"$use_reduce_exports\" = \"yes\"; then\n      AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduce-exports.])\n    fi\n  ]\n)\n\ndnl check for gmtime_r(), fallback to gmtime_s() if that is unavailable\ndnl fail if neither are available.\nAC_MSG_CHECKING([for gmtime_r])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <ctime>]],\n  [[ gmtime_r((const time_t *) nullptr, (struct tm *) nullptr); ]])],\n  [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GMTIME_R], [1], [Define this symbol if gmtime_r is available]) ],\n  [ AC_MSG_RESULT([no]);\n    AC_MSG_CHECKING([for gmtime_s]);\n    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <ctime>]],\n       [[ gmtime_s((struct tm *) nullptr, (const time_t *) nullptr); ]])],\n       [ AC_MSG_RESULT([yes])],\n       [ AC_MSG_RESULT([no]); AC_MSG_ERROR([Both gmtime_r and gmtime_s are unavailable]) ]\n    )\n  ]\n)\n\ndnl Check for different ways of gathering OS randomness\nAC_MSG_CHECKING([for Linux getrandom syscall])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>\n  #include <sys/syscall.h>\n  #include <linux/random.h>]],\n [[ syscall(SYS_getrandom, nullptr, 32, 0); ]])],\n [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_SYS_GETRANDOM], [1], [Define this symbol if the Linux getrandom system call is available]) ],\n [ AC_MSG_RESULT([no])]\n)\n\nAC_MSG_CHECKING([for getentropy])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]],\n [[ getentropy(nullptr, 32) ]])],\n [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETENTROPY], [1], [Define this symbol if the BSD getentropy system call is available]) ],\n [ AC_MSG_RESULT([no])]\n)\n\nAC_MSG_CHECKING(for sysctl KERN_ARND)\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n  #include <sys/sysctl.h>]],\n [[ static const int name[2] = {CTL_KERN, KERN_ARND};\n    sysctl(name, 2, nullptr, nullptr, nullptr, 0); ]])],\n [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL_ARND, 1,[Define this symbol if the BSD sysctl(KERN_ARND) is available]) ],\n [ AC_MSG_RESULT(no)]\n)\n\n# Check for reduced exports\nif test x$use_reduce_exports = xyes; then\n  AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS=\"-fvisibility=hidden\"],\n  [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])])\nfi\n\ndnl Check for libminiupnpc (optional)\nif test x$use_upnp != xno; then\n  AC_CHECK_HEADERS(\n    [miniupnpc/miniwget.h miniupnpc/miniupnpc.h miniupnpc/upnpcommands.h miniupnpc/upnperrors.h],\n    [AC_CHECK_LIB([miniupnpc], [upnpDiscover], [MINIUPNPC_LIBS=-lminiupnpc], [have_miniupnpc=no])],\n    [have_miniupnpc=no]\n  )\nfi\n\nAC_MSG_CHECKING([for fdatasync])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]],\n [[ fdatasync(0); ]])],\n [ AC_MSG_RESULT([yes]); HAVE_FDATASYNC=1 ],\n [ AC_MSG_RESULT([no]); HAVE_FDATASYNC=0 ]\n)\nAC_DEFINE_UNQUOTED([HAVE_FDATASYNC], [$HAVE_FDATASYNC], [Define to 1 if fdatasync is available.])\n\nAC_MSG_CHECKING([for F_FULLFSYNC])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>]],\n [[ fcntl(0, F_FULLFSYNC, 0); ]])],\n [ AC_MSG_RESULT([yes]); HAVE_FULLFSYNC=1 ],\n [ AC_MSG_RESULT([no]); HAVE_FULLFSYNC=0 ]\n)\n\ndnl crc32c platform checks\nAC_MSG_CHECKING([for __builtin_prefetch])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[\n  char data = 0;\n  const char* address = &data;\n  __builtin_prefetch(address, 0, 0);\n  ]])],\n [ AC_MSG_RESULT([yes]); HAVE_BUILTIN_PREFETCH=1 ],\n [ AC_MSG_RESULT([no]); HAVE_BUILTIN_PREFETCH=0 ]\n)\n\nAC_MSG_CHECKING([for _mm_prefetch])\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xmmintrin.h>]], [[\n  char data = 0;\n  const char* address = &data;\n  _mm_prefetch(address, _MM_HINT_NTA);\n  ]])],\n [ AC_MSG_RESULT([yes]); HAVE_MM_PREFETCH=1 ],\n [ AC_MSG_RESULT([no]); HAVE_MM_PREFETCH=0 ]\n)\n\n\ndnl Check for Djinni\nif test x$build_libs_objc != xno; then\n  if test x$DJINNI_OBJCXXFLAGS = x; then\n    DJINNI_OBJCXXFLAGS=-I$prefix/include/objc\n  fi\n  AC_SUBST(DJINNI_OBJCXXFLAGS)\nfi\n\nif test \"$enable_wallet\" != \"no\"; then\n    dnl Check for libdb_cxx only if wallet enabled\n    if test \"$use_bdb\" != \"no\"; then\n      CENTURE_FIND_BDB48\n    fi\n    dnl Disable wallet if --without-bdb\n    if test \"$use_bdb\" = \"no\"; then\n        if test \"$enable_wallet\" = \"yes\"; then\n            AC_MSG_ERROR([wallet functionality requested but no BDB or SQLite support available.])\n        fi\n        enable_wallet=no\n    fi\nfi\n\nif test \"$build_utils$build_libs_node_js$build_libs_jni$build_libs_objc$build_daemon$use_tests$use_bench\" = \"nononononono\"; then\n    use_boost=no\nelse\n    use_boost=yes\nfi\n\nif test \"$use_boost\" = \"yes\"; then\n\ndnl Minimum required Boost version\ndefine(MINIMUM_REQUIRED_BOOST, 1.68.0)\n\ndnl Check for boost libs\nAX_BOOST_BASE([MINIMUM_REQUIRED_BOOST])\nAX_BOOST_SYSTEM\nAX_BOOST_FILESYSTEM\nAX_BOOST_PROGRAM_OPTIONS\nAX_BOOST_THREAD\nAX_BOOST_CHRONO\n\ndnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic\ndnl counter implementations. In 1.63 and later the std::atomic approach is default.\nm4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro\nBOOST_CPPFLAGS=\"-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS\"\n\nif test x$use_reduce_exports = xyes; then\n  AC_MSG_CHECKING([for working boost reduced exports])\n  TEMP_CPPFLAGS=\"$CPPFLAGS\"\n  CPPFLAGS=\"$BOOST_CPPFLAGS $CPPFLAGS\"\n  AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[\n      @%:@include <boost/version.hpp>\n    ]], [[\n      #if BOOST_VERSION >= 104900\n      // Everything is okay\n      #else\n      #  error Boost version is too old\n      #endif\n    ]])],[\n      AC_MSG_RESULT(yes)\n    ],[\n    AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduce-exports.])\n  ])\n  CPPFLAGS=\"$TEMP_CPPFLAGS\"\nfi\nfi\n\nif test \"$use_reduce_export\" = \"yes\"; then\n    CXXFLAGS=\"$CXXFLAGS $RE_CXXFLAGS\"\n    AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]], [RELDFLAGS=\"-Wl,--exclude-libs,ALL\"])\nfi\n\nif test \"$use_tests\" = \"yes\"; then\n\n  if test \"$HEXDUMP\" = \"\"; then\n    AC_MSG_ERROR(hexdump is required for tests)\n  fi\n\n\n  if test \"$use_boost\" = \"yes\"; then\n\n  AX_BOOST_UNIT_TEST_FRAMEWORK\n\n  dnl Determine if -DBOOST_TEST_DYN_LINK is needed\n  AC_MSG_CHECKING([for dynamic linked boost test])\n  TEMP_LIBS=\"$LIBS\"\n  LIBS=\"$LIBS $BOOST_LDFLAGS $BOOST_UNIT_TEST_FRAMEWORK_LIB\"\n  TEMP_CPPFLAGS=\"$CPPFLAGS\"\n  CPPFLAGS=\"$CPPFLAGS $BOOST_CPPFLAGS\"\n  AC_LINK_IFELSE([AC_LANG_SOURCE([\n       #define BOOST_TEST_DYN_LINK\n       #define BOOST_TEST_MAIN\n        #include <boost/test/unit_test.hpp>\n\n       ])],\n    [AC_MSG_RESULT(yes)]\n    [TESTDEFS=\"$TESTDEFS -DBOOST_TEST_DYN_LINK\"],\n    [AC_MSG_RESULT(no)])\n  LIBS=\"$TEMP_LIBS\"\n  CPPFLAGS=\"$TEMP_CPPFLAGS\"\n\n  fi\nfi\n\nif test \"$use_boost\" = \"yes\"; then\n\nBOOST_LIBS=\"$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB\"\n\n\ndnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums\ndnl using c++98 constructs. Unfortunately, this implementation detail leaked into\ndnl the abi. This was fixed in 1.57.\n\ndnl When building against that installed version using c++11, the headers pick up\ndnl on the native c++11 scoped enum support and enable it, however it will fail to\ndnl link. This can be worked around by disabling c++11 scoped enums if linking will\ndnl fail.\ndnl BOOST_NO_SCOPED_ENUMS was changed to BOOST_NO_CXX11_SCOPED_ENUMS in 1.51.\n\nTEMP_LIBS=\"$LIBS\"\nLIBS=\"$BOOST_LIBS $LIBS\"\nTEMP_CPPFLAGS=\"$CPPFLAGS\"\nCPPFLAGS=\"$CPPFLAGS $BOOST_CPPFLAGS\"\nAC_MSG_CHECKING([for mismatched boost c++11 scoped enums])\nAC_LINK_IFELSE([AC_LANG_PROGRAM([[\n  #include <boost/config.hpp>\n  #include <boost/version.hpp>\n  #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700\n  #define BOOST_NO_SCOPED_ENUMS\n  #define BOOST_NO_CXX11_SCOPED_ENUMS\n  #define CHECK\n  #endif\n  #include <boost/filesystem.hpp>\n  ]],[[\n  #if defined(CHECK)\n    boost::filesystem::copy_file(\"foo\", \"bar\");\n  #else\n    choke;\n  #endif\n  ]])],\n  [AC_MSG_RESULT(mismatched); BOOST_CPPFLAGS=\"$BOOST_CPPFLAGS -DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS\"], [AC_MSG_RESULT(ok)])\nLIBS=\"$TEMP_LIBS\"\nCPPFLAGS=\"$TEMP_CPPFLAGS\"\n\ndnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however\ndnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if\ndnl a working version is available, else fall back to sleep. sleep was removed\ndnl after 1.56.\ndnl If neither is available, abort.\nTEMP_LIBS=\"$LIBS\"\nLIBS=\"$BOOST_LIBS $LIBS\"\nTEMP_CPPFLAGS=\"$CPPFLAGS\"\nCPPFLAGS=\"$CPPFLAGS $BOOST_CPPFLAGS\"\nAC_LINK_IFELSE([AC_LANG_PROGRAM([[\n  #include <boost/thread/thread.hpp>\n  #include <boost/version.hpp>\n  ]],[[\n  #if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200)\n      boost::this_thread::sleep_for(boost::chrono::milliseconds(0));\n  #else\n   choke me\n  #endif\n  ]])],\n  [boost_sleep=yes;\n     AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])],\n  [boost_sleep=no])\nLIBS=\"$TEMP_LIBS\"\nCPPFLAGS=\"$TEMP_CPPFLAGS\"\n\nif test x$boost_sleep != xyes; then\nTEMP_LIBS=\"$LIBS\"\nLIBS=\"$BOOST_LIBS $LIBS\"\nTEMP_CPPFLAGS=\"$CPPFLAGS\"\nCPPFLAGS=\"$CPPFLAGS $BOOST_CPPFLAGS\"\nAC_LINK_IFELSE([AC_LANG_PROGRAM([[\n  #include <boost/version.hpp>\n  #include <boost/thread.hpp>\n  #include <boost/date_time/posix_time/posix_time_types.hpp>\n  ]],[[\n  #if BOOST_VERSION <= 105600\n      boost::this_thread::sleep(boost::posix_time::milliseconds(0));\n  #else\n   choke me\n  #endif\n  ]])],\n  [boost_sleep=yes; AC_DEFINE(HAVE_WORKING_BOOST_SLEEP, 1, [Define this symbol if boost sleep works])],\n  [boost_sleep=no])\nLIBS=\"$TEMP_LIBS\"\nCPPFLAGS=\"$TEMP_CPPFLAGS\"\nfi\n\nif test \"$boost_sleep\" != \"yes\"; then\n  AC_MSG_ERROR(No working boost sleep implementation found.)\nfi\n\nfi\n\n: dnl\nm4_ifdef(\n  [PKG_CHECK_MODULES],\n  [\n    PKG_CHECK_MODULES([CRYPTOPP], [libcryptopp],, PKG_CHECK_MODULES([CRYPTOPP], [libcrypto++],, [AC_MSG_ERROR(libcryptopp not found.)]))\n    PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl  not found.)])\n    PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto  not found.)])\n    PKG_CHECK_MODULES([PROTOBUF], [protobuf],[have_protobuf=yes],[have_protobuf=no])\n    if test x$build_utils$build_daemon$use_tests$build_libs_node_js != xnononono; then\n      PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)])\n      if test x$TARGET_OS != xwindows; then\n        PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)])\n      fi\n    fi\n  ]\n)\n\ndnl ZMQ check\n\nif test \"$use_zmq\" = \"yes\"; then\n  PKG_CHECK_MODULES([ZMQ], [libzmq >= 4],\n    AC_DEFINE([ENABLE_ZMQ], [1], [Define to 1 to enable ZMQ functions]),\n    [AC_DEFINE([ENABLE_ZMQ], [0], [Define to 1 to enable ZMQ functions])\n    AC_MSG_WARN([libzmq version 4.x or greater not found, disabling])\n    use_zmq=no])\nelse\n  AC_DEFINE_UNQUOTED([ENABLE_ZMQ], [0], [Define to 1 to enable ZMQ functions])\nfi\n\nif test \"$use_zmq\" = \"yes\"; then\n  dnl Assume libzmq was built for static linking\n  case $host in\n    *mingw*)\n      ZMQ_CFLAGS=\"$ZMQ_CFLAGS -DZMQ_STATIC\"\n    ;;\n  esac\nfi\n\nsave_CXXFLAGS=\"${CXXFLAGS}\"\nCXXFLAGS=\"${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}\"\nAC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT\n#include <openssl/x509_vfy.h>\n])\nCXXFLAGS=\"${save_CXXFLAGS}\"\n\ndnl RapidCheck Property Based Testing\n\nenable_property_tests=no\nif test \"$use_rapidcheck\" = \"auto\"; then\n    AC_CHECK_HEADERS([rapidcheck.h], [enable_property_tests=yes])\nelif test \"$use_rapidcheck\" != \"no\"; then\n    enable_property_tests=yes\nfi\n\nRAPIDCHECK_LIBS=\nif test \"$enable_property_tests\" = \"yes\"; then\n   RAPIDCHECK_LIBS=-lrapidcheck\nfi\nAC_SUBST(RAPIDCHECK_LIBS)\nAM_CONDITIONAL([ENABLE_PROPERTY_TESTS], [test \"$enable_property_tests\" = \"yes\"])\n\n\n\nAC_MSG_CHECKING([whether to build _DAEMON_NAME])\nAM_CONDITIONAL([BUILD_DAEMON], [test \"$build_daemon\" = \"yes\"])\nAC_MSG_RESULT($build_daemon)\n\nAC_MSG_CHECKING([whether to build utils (_CLI_NAME _TX_NAME)])\nAM_CONDITIONAL([BUILD_UTILS], [test \"$build_utils\" = \"yes\"])\nAC_MSG_RESULT($build_utils)\n\nAC_MSG_CHECKING([whether to build node.js libraries])\nAM_CONDITIONAL([BUILD_LIBS_NODE_JS], [test \"$build_libs_node_js\" = \"yes\"])\nAC_MSG_RESULT($build_libs_node_js)\n\n\nAC_MSG_CHECKING([whether to build jni libraries])\nAM_CONDITIONAL([BUILD_LIBS_JNI], [test \"$build_libs_jni\" = \"yes\"])\nAC_MSG_RESULT($build_libs_jni)\n\nAC_MSG_CHECKING([whether to build objc libraries])\nAM_CONDITIONAL([BUILD_LIBS_OBJC], [test \"$build_libs_objc\" = \"yes\"])\nAC_MSG_RESULT($build_libs_objc)\n\nAC_LANG_POP\n\nif test \"$use_ccache\" != \"no\"; then\n  AC_MSG_CHECKING([if ccache should be used])\n  if test \"$CCACHE\" = \"\"; then\n    if test \"$use_ccache\" = \"yes\"; then\n      AC_MSG_ERROR([ccache not found.]);\n    else\n      use_ccache=no\n    fi\n  else\n    use_ccache=yes\n    CC=\"$ac_cv_path_CCACHE $CC\"\n    CXX=\"$ac_cv_path_CCACHE $CXX\"\n  fi\n  AC_MSG_RESULT($use_ccache)\n  if test \"$use_ccache\" = \"yes\"; then\n    AX_CHECK_COMPILE_FLAG([-fdebug-prefix-map=A=B], [DEBUG_CXXFLAGS=\"$DEBUG_CXXFLAGS -fdebug-prefix-map=\\$(abs_top_srcdir)=.\"], [], [$CXXFLAG_WERROR])\n    AX_CHECK_PREPROC_FLAG([-fmacro-prefix-map=A=B], [DEBUG_CPPFLAGS=\"$DEBUG_CPPFLAGS -fmacro-prefix-map=\\$(abs_top_srcdir)=.\"], [], [$CXXFLAG_WERROR])\n  fi\nfi\n\ndnl enable wallet\nAC_MSG_CHECKING([if wallet should be enabled])\nif test \"$enable_wallet\" != \"no\"; then\n  AC_MSG_RESULT([yes])\n  AC_DEFINE_UNQUOTED([ENABLE_WALLET],[1],[Define to 1 to enable wallet functions])\n  enable_wallet=yes\n\nelse\n  AC_MSG_RESULT([no])\nfi\n\ndnl enable upnp support\nAC_MSG_CHECKING([whether to build with support for UPnP])\nif test \"$have_miniupnpc\" = \"no\"; then\n  if test \"$use_upnp\" = \"yes\"; then\n     AC_MSG_ERROR([UPnP requested but cannot be built. Use --without-miniupnpc])\n  fi\n  AC_MSG_RESULT([no])\nelse\n  if test \"$use_upnp\" != \"no\"; then\n    AC_MSG_RESULT([yes])\n    AC_MSG_CHECKING([whether to build with UPnP enabled by default])\n    use_upnp=yes\n    upnp_setting=0\n    if test \"$use_upnp_default\" != \"no\"; then\n      use_upnp_default=yes\n      upnp_setting=1\n    fi\n    AC_MSG_RESULT([$use_upnp_default])\n    AC_DEFINE_UNQUOTED([USE_UPNP],[$upnp_setting],[UPnP support not compiled if undefined, otherwise value (0 or 1) determines default state])\n    if test \"$TARGET_OS\" = \"windows\"; then\n      MINIUPNPC_CPPFLAGS=\"-DSTATICLIB -DMINIUPNP_STATICLIB\"\n    fi\n  else\n    AC_MSG_RESULT([no])\n  fi\nfi\n\nAM_CONDITIONAL([ENABLE_ZMQ], [test \"$use_zmq\" = \"yes\"])\n\nAC_MSG_CHECKING([whether to build test_munt])\nif test \"$use_tests\" = \"yes\"; then\n  AC_MSG_RESULT([yes])\n  BUILD_TEST=\"yes\"\nelse\n  AC_MSG_RESULT([no])\n  BUILD_TEST=\"\"\nfi\n\nAC_MSG_CHECKING([whether to reduce exports])\nif test \"$use_reduce_exports\" = \"yes\"; then\n  AC_MSG_RESULT([yes])\nelse\n  AC_MSG_RESULT([no])\nfi\n\nif test \"$build_utils$build_libs_node_js$build_libs_jni$build_libs_objc$build_daemon$use_bench$use_tests\" = \"nonononononono\"; then\n  AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-jni-libs --with-objc-libs --with-daemon --with-gui --enable-bench or --enable-tests])\nfi\n\nAM_CONDITIONAL([TARGET_DARWIN], [test \"$TARGET_OS\" = \"darwin\"])\nAM_CONDITIONAL([BUILD_DARWIN], [test \"$BUILD_OS\" = \"darwin\"])\nAM_CONDITIONAL([TARGET_WINDOWS], [test \"$TARGET_OS\" = \"windows\"])\nAM_CONDITIONAL([ENABLE_WALLET], [test \"$enable_wallet\" = \"yes\"])\nAM_CONDITIONAL([ENABLE_TESTS], [test \"$BUILD_TEST\" = \"yes\"])\nAM_CONDITIONAL([ENABLE_BENCH], [test \"$use_bench\" = \"yes\"])\nAM_CONDITIONAL([USE_QRCODE], [test \"$use_qr\" = \"yes\"])\nAM_CONDITIONAL([USE_LCOV], [test \"$use_lcov\" = \"yes\"])\nAM_CONDITIONAL([WORDS_BIGENDIAN], [test \"$ac_cv_c_bigendian\" = \"yes\"])\nAM_CONDITIONAL([HARDEN], [test \"$use_hardening\" = \"yes\"])\nAM_CONDITIONAL([TARGET_INTEL], [test x$host_cpu = xx86_64 -o x$host_cpu = xi686])\n\nAC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])\nAC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])\nAC_DEFINE(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION, [Build revision])\nAC_DEFINE(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD, [Version Build])\nAC_DEFINE(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE, [Version is release])\nAC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Copyright year])\nAC_DEFINE(COPYRIGHT_HOLDERS, \"_COPYRIGHT_HOLDERS\", [Copyright holder(s) before %s replacement])\nAC_DEFINE(COPYRIGHT_HOLDERS_SUBSTITUTION, \"_COPYRIGHT_HOLDERS_SUBSTITUTION\", [Replacement for %s in copyright holders string])\ndefine(_COPYRIGHT_HOLDERS_FINAL, [patsubst(_COPYRIGHT_HOLDERS, [%s], [_COPYRIGHT_HOLDERS_SUBSTITUTION])])\nAC_DEFINE(COPYRIGHT_HOLDERS_FINAL, \"_COPYRIGHT_HOLDERS_FINAL\", [Copyright holder(s)])\nAC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR)\nAC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR)\nAC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION)\nAC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD)\nAC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE)\nAC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR)\nAC_SUBST(COPYRIGHT_HOLDERS, \"_COPYRIGHT_HOLDERS\")\nAC_SUBST(COPYRIGHT_HOLDERS_SUBSTITUTION, \"_COPYRIGHT_HOLDERS_SUBSTITUTION\")\nAC_SUBST(COPYRIGHT_HOLDERS_FINAL, \"_COPYRIGHT_HOLDERS_FINAL\")\nAC_SUBST([_DAEMON_NAME])\nAC_SUBST([_GUI_NAME])\nAC_SUBST([_CLI_NAME])\nAC_SUBST([_TX_NAME])\n\nAC_SUBST(RELDFLAGS)\nAC_SUBST(DEBUG_CPPFLAGS)\nAC_SUBST(WARN_CXXFLAGS)\nAC_SUBST(NOWARN_CXXFLAGS)\nAC_SUBST(DEBUG_CXXFLAGS)\nAC_SUBST(COMPAT_LDFLAGS)\nAC_SUBST(ERROR_CXXFLAGS)\nAC_SUBST(HARDENED_CXXFLAGS)\nAC_SUBST(HARDENED_CPPFLAGS)\nAC_SUBST(HARDENED_LDFLAGS)\nAC_SUBST(PIC_FLAGS)\nAC_SUBST(PIE_FLAGS)\nAC_SUBST(SANITIZER_CXXFLAGS)\nAC_SUBST(SANITIZER_LDFLAGS)\nAC_SUBST(LIBTOOL_APP_LDFLAGS)\nAC_SUBST(USE_UPNP)\nAC_SUBST(USE_QRCODE)\nAC_SUBST(BOOST_LIBS)\nAC_SUBST(TESTDEFS)\nAC_SUBST(MINIUPNPC_CPPFLAGS)\nAC_SUBST(MINIUPNPC_LIBS)\nAC_SUBST(HAVE_FDATASYNC)\nAC_SUBST(HAVE_FULLFSYNC)\nAC_SUBST(HAVE_BUILTIN_PREFETCH)\nAC_SUBST(HAVE_MM_PREFETCH)\nAC_SUBST(CRYPTO_LIBS)\nAC_SUBST(QWT_LIBS)\nAC_SUBST(HAVE_WEBENGINE_VIEW)\nAC_SUBST(SSL_LIBS)\nAC_SUBST(EVENT_LIBS)\nAC_SUBST(EVENT_PTHREADS_LIBS)\nAC_SUBST(ZMQ_LIBS)\nAC_SUBST(PROTOBUF_LIBS)\nAC_SUBST(QR_LIBS)\nAC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi test/config.ini])\nAC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])\nAC_CONFIG_FILES([doc/Doxyfile])\nAC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])\nAC_CONFIG_LINKS([test/util/util-test.py:test/util/util-test.py])\n\ndnl boost's m4 checks do something really nasty: they export these vars. As a\ndnl result, they leak into secp256k1's configure and crazy things happen.\ndnl Until this is fixed upstream and we've synced, we'll just un-export them.\nCPPFLAGS_TEMP=\"$CPPFLAGS\"\nunset CPPFLAGS\nCPPFLAGS=\"$CPPFLAGS_TEMP\"\n\nLDFLAGS_TEMP=\"$LDFLAGS\"\nunset LDFLAGS\nLDFLAGS=\"$LDFLAGS_TEMP\"\n\nLIBS_TEMP=\"$LIBS\"\nunset LIBS\nLIBS=\"$LIBS_TEMP\"\n\nPKGCONFIG_PATH_TEMP=\"$PKG_CONFIG_PATH\"\nunset PKG_CONFIG_PATH\nPKG_CONFIG_PATH=\"$PKGCONFIG_PATH_TEMP\"\n\nPKGCONFIG_LIBDIR_TEMP=\"$PKG_CONFIG_LIBDIR\"\nunset PKG_CONFIG_LIBDIR\nPKG_CONFIG_LIBDIR=\"$PKGCONFIG_LIBDIR_TEMP\"\n\nac_configure_args=\"${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery\"\nAC_CONFIG_SUBDIRS([src/secp256k1])\n\nAC_OUTPUT\n\ndnl Taken from https://wiki.debian.org/RpathIssue\ncase $host in\n   *-*-linux-gnu)\n     AC_MSG_RESULT([Fixing libtool for -rpath problems.])\n     sed < libtool > libtool-2 \\\n     's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=\" -D__LIBTOOL_IS_A_FOOL__ \"/'\n     mv libtool-2 libtool\n     chmod 755 libtool\n   ;;\nesac\n\ndnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows\ncase ${OS} in\n   *Windows*)\n     sed  's/BUILDDIR=\"\\/\\([[a-z]]\\)/BUILDDIR=\"\\1:/'  test/config.ini > test/config-2.ini\n     mv test/config-2.ini test/config.ini\n   ;;\nesac\n\necho\necho \"Options used to compile and link:\"\necho \"  with wallet     = $enable_wallet\"\nif test \"$enable_wallet\" != \"no\"; then\n    echo \"    with bdb      = $use_bdb\"\nfi\necho \"  with zmq        = $use_zmq\"\necho \"  with test       = $use_tests\"\necho \"  with bench      = $use_bench\"\necho \"  with upnp       = $use_upnp\"\necho \"  debug enabled   = $enable_debug\"\necho \"  werror          = $enable_werror\"\necho\necho \"  target os       = $TARGET_OS\"\necho \"  build os        = $BUILD_OS\"\necho\necho \"  CC              = $CC\"\necho \"  CFLAGS          = $CFLAGS\"\necho \"  CPPFLAGS        = $CPPFLAGS\"\necho \"  CXX             = $CXX\"\necho \"  CXXFLAGS        = $CXXFLAGS\"\necho \"  LDFLAGS         = $LDFLAGS\"\necho \"  ARFLAGS         = $ARFLAGS\"\necho\necho \" Binaries:\"\necho \"     daemon:  $build_daemon\"\necho \"     cli:     $build_utils\"\necho \"     tx:      $build_utils\"\necho\necho \" Libraries:\"\necho \"     jni:     $build_libs_jni\"\necho \"     objc:    $build_libs_objc\"\necho \"     node_js: $build_libs_node_js\"\n"
  },
  {
    "path": "contrib/Munt-cli.bash-completion",
    "content": "# bash programmable completion for Munt-cli(1)\n# Copyright (c) 2012-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n# call $Munt-cli for RPC\n_munt_rpc() {\n    # determine already specified args necessary for RPC\n    local rpcargs=()\n    for i in ${COMP_LINE}; do\n        case \"$i\" in\n            -conf=*|-datadir=*|-regtest|-rpc*|-testnet)\n                rpcargs=( \"${rpcargs[@]}\" \"$i\" )\n                ;;\n        esac\n    done\n    $munt_cli \"${rpcargs[@]}\" \"$@\"\n}\n\n# Add wallet accounts to COMPREPLY\n_munt_accounts() {\n    local accounts\n    accounts=$(_munt_rpc listaccounts | awk -F '\"' '{ print $2 }')\n    COMPREPLY=( \"${COMPREPLY[@]}\" $( compgen -W \"$accounts\" -- \"$cur\" ) )\n}\n\n_munt_cli() {\n    local cur prev words=() cword\n    local munt_cli\n\n    # save and use original argument to invoke Munt-cli for -help, help and RPC\n    # as Munt-cli might not be in $PATH\n    munt_cli=\"$1\"\n\n    COMPREPLY=()\n    _get_comp_words_by_ref -n = cur prev words cword\n\n    if ((cword > 5)); then\n        case ${words[cword-5]} in\n            sendtoaddress)\n                COMPREPLY=( $( compgen -W \"true false\" -- \"$cur\" ) )\n                return 0\n                ;;\n        esac\n    fi\n\n    if ((cword > 4)); then\n        case ${words[cword-4]} in\n            importaddress|listtransactions|setban)\n                COMPREPLY=( $( compgen -W \"true false\" -- \"$cur\" ) )\n                return 0\n                ;;\n            signrawtransaction)\n                COMPREPLY=( $( compgen -W \"ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY\" -- \"$cur\" ) )\n                return 0\n                ;;\n        esac\n    fi\n\n    if ((cword > 3)); then\n        case ${words[cword-3]} in\n            addmultisigaddress)\n                _munt_accounts\n                return 0\n                ;;\n            getbalance|gettxout|importaddress|importpubkey|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock)\n                COMPREPLY=( $( compgen -W \"true false\" -- \"$cur\" ) )\n                return 0\n                ;;\n        esac\n    fi\n\n    if ((cword > 2)); then\n        case ${words[cword-2]} in\n            addnode)\n                COMPREPLY=( $( compgen -W \"add remove onetry\" -- \"$cur\" ) )\n                return 0\n                ;;\n            setban)\n                COMPREPLY=( $( compgen -W \"add remove\" -- \"$cur\" ) )\n                return 0\n                ;;\n            fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction)\n                COMPREPLY=( $( compgen -W \"true false\" -- \"$cur\" ) )\n                return 0\n                ;;\n            move|setaccount)\n                _munt_accounts\n                return 0\n                ;;\n        esac\n    fi\n\n    case \"$prev\" in\n        backupwallet|dumpwallet|importwallet)\n            _filedir\n            return 0\n            ;;\n        getaddednodeinfo|getrawmempool|lockunspent|setgenerate)\n            COMPREPLY=( $( compgen -W \"true false\" -- \"$cur\" ) )\n            return 0\n            ;;\n        getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany)\n            _munt_accounts\n            return 0\n            ;;\n    esac\n\n    case \"$cur\" in\n        -conf=*)\n            cur=\"${cur#*=}\"\n            _filedir\n            return 0\n            ;;\n        -datadir=*)\n            cur=\"${cur#*=}\"\n            _filedir -d\n            return 0\n            ;;\n        -*=*)\t# prevent nonsense completions\n            return 0\n            ;;\n        *)\n            local helpopts commands\n\n            # only parse -help if senseful\n            if [[ -z \"$cur\" || \"$cur\" =~ ^- ]]; then\n                helpopts=$($munt_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, \"=\"); print $1 }' )\n            fi\n\n            # only parse help if senseful\n            if [[ -z \"$cur\" || \"$cur\" =~ ^[a-z] ]]; then\n                commands=$(_munt_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }')\n            fi\n\n            COMPREPLY=( $( compgen -W \"$helpopts $commands\" -- \"$cur\" ) )\n\n            # Prevent space if an argument is desired\n            if [[ $COMPREPLY == *= ]]; then\n                compopt -o nospace\n            fi\n            return 0\n            ;;\n    esac\n} &&\ncomplete -F _munt_cli Munt-cli\n\n# Local variables:\n# mode: shell-script\n# sh-basic-offset: 4\n# sh-indent-comment: t\n# indent-tabs-mode: nil\n# End:\n# ex: ts=4 sw=4 et filetype=sh\n"
  },
  {
    "path": "contrib/Munt-daemon.bash-completion",
    "content": "# bash programmable completion for Munt-daemon(1) and Munt(1)\n# Copyright (c) 2012-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n_Munt_daemon() {\n    local cur prev words=() cword\n    local Munt_daemon\n\n    # save and use original argument to invoke Munt-daemon for -help\n    # it might not be in $PATH\n    Munt_daemon=\"$1\"\n\n    COMPREPLY=()\n    _get_comp_words_by_ref -n = cur prev words cword\n\n    case \"$cur\" in\n        -conf=*|-pid=*|-loadblock=*|-rootcertificates=*|-rpccookiefile=*|-wallet=*)\n            cur=\"${cur#*=}\"\n            _filedir\n            return 0\n            ;;\n        -datadir=*)\n            cur=\"${cur#*=}\"\n            _filedir -d\n            return 0\n            ;;\n        -*=*)\t# prevent nonsense completions\n            return 0\n            ;;\n        *)\n\n            # only parse -help if senseful\n            if [[ -z \"$cur\" || \"$cur\" =~ ^- ]]; then\n                local helpopts\n                helpopts=$($Munt_daemon -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, \"=\"); print $1 }' )\n                COMPREPLY=( $( compgen -W \"$helpopts\" -- \"$cur\" ) )\n            fi\n\n            # Prevent space if an argument is desired\n            if [[ $COMPREPLY == *= ]]; then\n                compopt -o nospace\n            fi\n            return 0\n            ;;\n    esac\n} &&\ncomplete -F _Munt_daemon Munt-daemon Munt\n\n# Local variables:\n# mode: shell-script\n# sh-basic-offset: 4\n# sh-indent-comment: t\n# indent-tabs-mode: nil\n# End:\n# ex: ts=4 sw=4 et filetype=sh\n"
  },
  {
    "path": "contrib/Munt-tx.bash-completion",
    "content": "# bash programmable completion for Munt-tx(1)\n# Copyright (c) 2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n_munt_tx() {\n    local cur prev words=() cword\n    local munt_tx\n\n    # save and use original argument to invoke Munt-tx for -help\n    # it might not be in $PATH\n    munt_tx=\"$1\"\n\n    COMPREPLY=()\n    _get_comp_words_by_ref -n =: cur prev words cword\n\n    case \"$cur\" in\n        load=*:*)\n            cur=\"${cur#load=*:}\"\n            _filedir\n            return 0\n            ;;\n        *=*)\t# prevent attempts to complete other arguments\n            return 0\n            ;;\n    esac\n\n    if [[ \"$cword\" == 1 || ( \"$prev\" != \"-create\" && \"$prev\" == -* ) ]]; then\n        # only options (or an uncompletable hex-string) allowed\n        # parse Munt-tx -help for options\n        local helpopts\n        helpopts=$($munt_tx -help | sed -e '/^  -/ p' -e d )\n        COMPREPLY=( $( compgen -W \"$helpopts\" -- \"$cur\" ) )\n    else\n        # only commands are allowed\n        # parse -help for commands\n        local helpcmds\n        helpcmds=$($munt_tx -help | sed -e '1,/Commands:/d' -e 's/=.*/=/' -e '/^  [a-z]/ p' -e d )\n        COMPREPLY=( $( compgen -W \"$helpcmds\" -- \"$cur\" ) )\n    fi\n\n    # Prevent space if an argument is desired\n    if [[ $COMPREPLY == *= ]]; then\n        compopt -o nospace\n    fi\n\n    return 0\n} &&\ncomplete -F _munt_tx Munt-tx\n\n# Local variables:\n# mode: shell-script\n# sh-basic-offset: 4\n# sh-indent-comment: t\n# indent-tabs-mode: nil\n# End:\n# ex: ts=4 sw=4 et filetype=sh\n"
  },
  {
    "path": "contrib/README.md",
    "content": "Repository Tools\n---------------------\n\n### [Qos](/contrib/qos) ###\n\nA Linux bash script that will set up traffic control (tc) to limit the outgoing bandwidth for connections to the Munt network. This means one can have an always-on Munt-daemon instance running, and another local Munt-daemon/Munt instance which connects to this node and receives blocks from it.\n\n### [Seeds](/contrib/seeds) ###\nUtility to generate the pnSeed[] array that is compiled into the client.\n\nBuild Tools and Keys\n---------------------\n\n### [guix(/contrib/guix) ###\nNotes on getting guix builds up and running, scripts for running guix builds.\n\n### [MacDeploy](/contrib/macdeploy) ###\nScripts and notes for Mac builds. \n\nTest and Verify Tools \n---------------------\n\n### [TestGen](/contrib/testgen) ###\nUtilities to generate test vectors for the data-driven Munt tests.\n\n"
  },
  {
    "path": "contrib/devtools/security-check.py",
    "content": "#!/usr/bin/env python\n# Copyright (c) 2015-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n'''\nPerform basic ELF security checks on a series of executables.\nExit status will be 0 if successful, and the program will be silent.\nOtherwise the exit status will be 1 and it will log which executables failed which checks.\nNeeds `readelf` (for ELF) and `objdump` (for PE).\n'''\nfrom __future__ import division,print_function,unicode_literals\nimport subprocess\nimport sys\nimport os\n\nREADELF_CMD = os.getenv('READELF', '/usr/bin/readelf')\nOBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')\nNONFATAL = {'HIGH_ENTROPY_VA'} # checks which are non-fatal for now but only generate a warning\n\ndef check_ELF_PIE(executable):\n    '''\n    Check for position independent executable (PIE), allowing for address space randomization.\n    '''\n    p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n\n    ok = False\n    for line in stdout.split(b'\\n'):\n        line = line.split()\n        if len(line)>=2 and line[0] == b'Type:' and line[1] == b'DYN':\n            ok = True\n    return ok\n\ndef get_ELF_program_headers(executable):\n    '''Return type and flags for ELF program headers'''\n    p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n    in_headers = False\n    count = 0\n    headers = []\n    for line in stdout.split(b'\\n'):\n        if line.startswith(b'Program Headers:'):\n            in_headers = True\n        if line == b'':\n            in_headers = False\n        if in_headers:\n            if count == 1: # header line\n                ofs_typ = line.find(b'Type')\n                ofs_offset = line.find(b'Offset')\n                ofs_flags = line.find(b'Flg')\n                ofs_align = line.find(b'Align')\n                if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align  == -1:\n                    raise ValueError('Cannot parse elfread -lW output')\n            elif count > 1:\n                typ = line[ofs_typ:ofs_offset].rstrip()\n                flags = line[ofs_flags:ofs_align].rstrip()\n                headers.append((typ, flags))\n            count += 1\n    return headers\n\ndef check_ELF_NX(executable):\n    '''\n    Check that no sections are writable and executable (including the stack)\n    '''\n    have_wx = False\n    have_gnu_stack = False\n    for (typ, flags) in get_ELF_program_headers(executable):\n        if typ == b'GNU_STACK':\n            have_gnu_stack = True\n        if b'W' in flags and b'E' in flags: # section is both writable and executable\n            have_wx = True\n    return have_gnu_stack and not have_wx\n\ndef check_ELF_RELRO(executable):\n    '''\n    Check for read-only relocations.\n    GNU_RELRO program header must exist\n    Dynamic section must have BIND_NOW flag\n    '''\n    have_gnu_relro = False\n    for (typ, flags) in get_ELF_program_headers(executable):\n        # Note: not checking flags == 'R': here as linkers set the permission differently\n        # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions.\n        # However, the dynamic linker need to write to this area so these are RW.\n        # Glibc itself takes care of mprotecting this area R after relocations are finished.\n        # See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347\n        if typ == b'GNU_RELRO':\n            have_gnu_relro = True\n\n    have_bindnow = False\n    p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n    for line in stdout.split(b'\\n'):\n        tokens = line.split()\n        if len(tokens)>1 and tokens[1] == b'(BIND_NOW)' or (len(tokens)>2 and tokens[1] == b'(FLAGS)' and b'BIND_NOW' in tokens[2]):\n            have_bindnow = True\n    return have_gnu_relro and have_bindnow\n\ndef check_ELF_Canary(executable):\n    '''\n    Check for use of stack canary\n    '''\n    p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n    ok = False\n    for line in stdout.split(b'\\n'):\n        if b'__stack_chk_fail' in line:\n            ok = True\n    return ok\n\ndef get_PE_dll_characteristics(executable):\n    '''\n    Get PE DllCharacteristics bits.\n    Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386'\n    and bits is the DllCharacteristics value.\n    '''\n    p = subprocess.Popen([OBJDUMP_CMD, '-x',  executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n    arch = ''\n    bits = 0\n    for line in stdout.split('\\n'):\n        tokens = line.split()\n        if len(tokens)>=2 and tokens[0] == 'architecture:':\n            arch = tokens[1].rstrip(',')\n        if len(tokens)>=2 and tokens[0] == 'DllCharacteristics':\n            bits = int(tokens[1],16)\n    return (arch,bits)\n\nIMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020\nIMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE    = 0x0040\nIMAGE_DLL_CHARACTERISTICS_NX_COMPAT       = 0x0100\n\ndef check_PE_DYNAMIC_BASE(executable):\n    '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''\n    (arch,bits) = get_PE_dll_characteristics(executable)\n    reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE\n    return (bits & reqbits) == reqbits\n\n# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE\n# to have secure ASLR.\ndef check_PE_HIGH_ENTROPY_VA(executable):\n    '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR'''\n    (arch,bits) = get_PE_dll_characteristics(executable)\n    if arch == 'i386:x86-64': \n        reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA\n    else: # Unnecessary on 32-bit\n        assert(arch == 'i386')\n        reqbits = 0\n    return (bits & reqbits) == reqbits\n\ndef check_PE_NX(executable):\n    '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''\n    (arch,bits) = get_PE_dll_characteristics(executable)\n    return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT\n\nCHECKS = {\n'ELF': [\n    ('PIE', check_ELF_PIE),\n    ('NX', check_ELF_NX),\n    ('RELRO', check_ELF_RELRO),\n    ('Canary', check_ELF_Canary)\n],\n'PE': [\n    ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),\n    ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),\n    ('NX', check_PE_NX)\n]\n}\n\ndef identify_executable(executable):\n    with open(filename, 'rb') as f:\n        magic = f.read(4)\n    if magic.startswith(b'MZ'):\n        return 'PE'\n    elif magic.startswith(b'\\x7fELF'):\n        return 'ELF'\n    return None\n\nif __name__ == '__main__':\n    retval = 0\n    for filename in sys.argv[1:]:\n        try:\n            etype = identify_executable(filename)\n            if etype is None:\n                print('%s: unknown format' % filename)\n                retval = 1\n                continue\n\n            failed = []\n            warning = []\n            for (name, func) in CHECKS[etype]:\n                if not func(filename):\n                    if name in NONFATAL:\n                        warning.append(name)\n                    else:\n                        failed.append(name)\n            if failed:\n                print('%s: failed %s' % (filename, ' '.join(failed)))\n                retval = 1\n            if warning:\n                print('%s: warning %s' % (filename, ' '.join(warning)))\n        except IOError:\n            print('%s: cannot open' % filename)\n            retval = 1\n    exit(retval)\n\n"
  },
  {
    "path": "contrib/devtools/split-debug.sh.in",
    "content": "#!/bin/sh\n\nif [ $# -ne 3 ];\n    then echo \"usage: $0 <input> <stripped-binary> <debug-binary>\"\nfi\n\n@OBJCOPY@ --enable-deterministic-archives -p --only-keep-debug $1 $3\n@OBJCOPY@ --enable-deterministic-archives -p --strip-debug $1 $2\n@STRIP@ --enable-deterministic-archives -p -s $2\n@OBJCOPY@ --enable-deterministic-archives -p --add-gnu-debuglink=$3 $2\n"
  },
  {
    "path": "contrib/devtools/symbol-check.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014 Wladimir J. van der Laan\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n'''\nA script to check that the (Linux) executables produced by guix only contain\nallowed gcc, glibc and libstdc++ version symbols.  This makes sure they are\nstill compatible with the minimum supported Linux distribution versions.\n\nExample usage:\n\n    find ../build -type f -executable | xargs python contrib/devtools/symbol-check.py\n'''\nimport subprocess\nimport re\nimport sys\nimport os\n\n# Debian 6.0.9 (Squeeze) has:\n#\n# - g++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=g%2B%2B)\n# - libc version 2.11.3 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libc6)\n# - libstdc++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libstdc%2B%2B6)\n#\n# Ubuntu 10.04.4 (Lucid Lynx) has:\n#\n# - g++ version 4.4.3 (http://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=lucid&section=all)\n# - libc version 2.11.1 (http://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=lucid&section=all)\n# - libstdc++ version 4.4.3 (http://packages.ubuntu.com/search?suite=lucid&section=all&arch=any&keywords=libstdc%2B%2B&searchon=names)\n#\n# Taking the minimum of these as our target.\n#\n# According to GNU ABI document (http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to:\n#   GCC 4.4.0: GCC_4.4.0\n#   GCC 4.4.2: GLIBCXX_3.4.13, CXXABI_1.3.3\n#   (glibc)    GLIBC_2_11\n#\nMAX_VERSIONS = {\n'GCC':     (4,4,0),\n'CXXABI':  (1,3,3),\n'GLIBCXX': (3,4,13),\n'GLIBC':   (2,11)\n}\n# See here for a description of _IO_stdin_used:\n# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109\n\n# Ignore symbols that are exported as part of every executable\nIGNORE_EXPORTS = {\n'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr'\n}\nREADELF_CMD = os.getenv('READELF', '/usr/bin/readelf')\nCPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')\n# Allowed NEEDED libraries\nALLOWED_LIBRARIES = {\n# Munt-daemon and Munt (qt)\n'libgcc_s.so.1', # GCC base support\n'libc.so.6', # C library\n'libpthread.so.0', # threading\n'libanl.so.1', # DNS resolve\n'libm.so.6', # math library\n'librt.so.1', # real-time (clock)\n'ld-linux-x86-64.so.2', # 64-bit dynamic linker\n'ld-linux.so.2', # 32-bit dynamic linker\n# Munt (qt) only\n'libX11-xcb.so.1', # part of X11\n'libX11.so.6', # part of X11\n'libxcb.so.1', # part of X11\n'libfontconfig.so.1', # font support\n'libfreetype.so.6', # font parsing\n'libdl.so.2' # programming interface to dynamic linker\n}\n\nclass CPPFilt(object):\n    '''\n    Demangle C++ symbol names.\n\n    Use a pipe to the 'c++filt' command.\n    '''\n    def __init__(self):\n        self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)\n\n    def __call__(self, mangled):\n        self.proc.stdin.write(mangled + '\\n')\n        self.proc.stdin.flush()\n        return self.proc.stdout.readline().rstrip()\n\n    def close(self):\n        self.proc.stdin.close()\n        self.proc.stdout.close()\n        self.proc.wait()\n\ndef read_symbols(executable, imports=True):\n    '''\n    Parse an ELF executable and return a list of (symbol,version) tuples\n    for dynamic, imported symbols.\n    '''\n    p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))\n    syms = []\n    for line in stdout.splitlines():\n        line = line.split()\n        if len(line)>7 and re.match('[0-9]+:$', line[0]):\n            (sym, _, version) = line[7].partition('@')\n            is_import = line[6] == 'UND'\n            if version.startswith('@'):\n                version = version[1:]\n            if is_import == imports:\n                syms.append((sym, version))\n    return syms\n\ndef check_version(max_versions, version):\n    if '_' in version:\n        (lib, _, ver) = version.rpartition('_')\n    else:\n        lib = version\n        ver = '0'\n    ver = tuple([int(x) for x in ver.split('.')])\n    if not lib in max_versions:\n        return False\n    return ver <= max_versions[lib]\n\ndef read_libraries(filename):\n    p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)\n    (stdout, stderr) = p.communicate()\n    if p.returncode:\n        raise IOError('Error opening file')\n    libraries = []\n    for line in stdout.splitlines():\n        tokens = line.split()\n        if len(tokens)>2 and tokens[1] == '(NEEDED)':\n            match = re.match('^Shared library: \\[(.*)\\]$', ' '.join(tokens[2:]))\n            if match:\n                libraries.append(match.group(1))\n            else:\n                raise ValueError('Unparseable (NEEDED) specification')\n    return libraries\n\nif __name__ == '__main__':\n    cppfilt = CPPFilt()\n    retval = 0\n    for filename in sys.argv[1:]:\n        # Check imported symbols\n        for sym,version in read_symbols(filename, True):\n            if version and not check_version(MAX_VERSIONS, version):\n                print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))\n                retval = 1\n        # Check exported symbols\n        for sym,version in read_symbols(filename, False):\n            if sym in IGNORE_EXPORTS:\n                continue\n            print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))\n            retval = 1\n        # Check dependency libraries\n        for library_name in read_libraries(filename):\n            if library_name not in ALLOWED_LIBRARIES:\n                print('%s: NEEDED library %s is not allowed' % (filename, library_name))\n                retval = 1\n\n    sys.exit(retval)\n\n\n"
  },
  {
    "path": "contrib/devtools/test-security-check.py",
    "content": "#!/usr/bin/env python2\n# Copyright (c) 2015-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n'''\nTest script for security-check.py\n'''\nfrom __future__ import division,print_function\nimport subprocess\nimport unittest\n\ndef write_testcode(filename):\n    with open(filename, 'w') as f:\n        f.write('''\n    #include <stdio.h>\n    int main()\n    {\n        printf(\"the quick brown fox jumps over the lazy god\\\\n\");\n        return 0;\n    }\n    ''')\n\ndef call_security_check(cc, source, executable, options):\n    subprocess.check_call([cc,source,'-o',executable] + options)\n    p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n    (stdout, stderr) = p.communicate()\n    return (p.returncode, stdout.rstrip())\n\nclass TestSecurityChecks(unittest.TestCase):\n    def test_ELF(self):\n        source = 'test1.c'\n        executable = 'test1'\n        cc = 'gcc'\n        write_testcode(source)\n\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']), \n                (1, executable+': failed PIE NX RELRO Canary'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']), \n                (1, executable+': failed PIE RELRO Canary'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']), \n                (1, executable+': failed PIE RELRO'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']), \n                (1, executable+': failed RELRO'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']), \n                (0, ''))\n\n    def test_PE(self):\n        source = 'test1.c'\n        executable = 'test1.exe'\n        cc = 'i686-w64-mingw32-gcc'\n        write_testcode(source)\n\n        self.assertEqual(call_security_check(cc, source, executable, []), \n                (1, executable+': failed PIE NX'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), \n                (1, executable+': failed PIE'))\n        self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), \n                (0, ''))\n\nif __name__ == '__main__':\n    unittest.main()\n\n"
  },
  {
    "path": "contrib/guix/INSTALL.md",
    "content": "# Guix Installation and Setup\n\nThis only needs to be done once per machine. If you have already completed the\ninstallation and setup, please proceed to [perform a build](./README.md).\n\nOtherwise, you may choose from one of the following options to install Guix:\n\n1. Using the official **shell installer script** [⤓ skip to section][install-script]\n   - Maintained by Guix developers\n   - Easiest (automatically performs *most* setup)\n   - Works on nearly all Linux distributions\n   - Only installs latest release\n   - Binary installation only, requires high level of trust\n   - Note: The script needs to be run as root, so it should be inspected before it's run\n2. Using the official **binary tarball** [⤓ skip to section][install-bin-tarball]\n   - Maintained by Guix developers\n   - Normal difficulty (full manual setup required)\n   - Works on nearly all Linux distributions\n   - Installs any release\n   - Binary installation only, requires high level of trust\n3. Using fanquake's **Docker image** [↗︎ external instructions][install-fanquake-docker]\n   - Maintained by fanquake\n   - Easy (automatically performs *some* setup)\n   - Works wherever Docker images work\n   - Installs any release\n   - Binary installation only, requires high level of trust\n4. Using a **distribution-maintained package** [⤓ skip to section][install-distro-pkg]\n   - Maintained by distribution's Guix package maintainer\n   - Normal difficulty (manual setup required)\n   - Works only on distributions with Guix packaged, see: https://repology.org/project/guix/versions\n   - Installs a release decided on by package maintainer\n   - Source or binary installation depending on the distribution\n5. Building **from source** [⤓ skip to section][install-source]\n   - Maintained by you\n   - Hard, but rewarding\n   - Can be made to work on most Linux distributions\n   - Installs any commit (more granular)\n   - Source installation, requires lower level of trust\n\n## Options 1 and 2: Using the official shell installer script or binary tarball\n\nThe installation instructions for both the official shell installer script and\nthe binary tarballs can be found in the GNU Guix Manual's [Binary Installation\nsection](https://guix.gnu.org/manual/en/html_node/Binary-Installation.html).\n\nNote that running through the binary tarball installation steps is largely\nequivalent to manually performing what the shell installer script does.\n\nNote that at the time of writing (July 5th, 2021), the shell installer script\nautomatically creates an `/etc/profile.d` entry which the binary tarball\ninstallation instructions do not ask you to create. However, you will likely\nneed this entry for better desktop integration. Please see [this\nsection](#add-an-etcprofiled-entry) for instructions on how to add a\n`/etc/profile.d/guix.sh` entry.\n\nRegardless of which installation option you chose, the changes to\n`/etc/profile.d` will not take effect until the next shell or desktop session,\nso you should log out and log back in.\n\n## Option 3: Using fanquake's Docker image\n\nPlease refer to fanquake's instructions\n[here](https://github.com/fanquake/core-review/tree/master/guix).\n\nNote that the `Dockerfile` is largely equivalent to running through the binary\ntarball installation steps.\n\n## Option 4: Using a distribution-maintained package\n\nNote that this section is based on the distro packaging situation at the time of\nwriting (July 2021). Guix is expected to be more widely packaged over time. For\nan up-to-date view on Guix's package status/version across distros, please see:\nhttps://repology.org/project/guix/versions\n\n### Debian 11 (Bullseye)/Ubuntu 21.04 (Hirsute Hippo)\n\nGuix v1.2.0 is available as a distribution package starting in [Debian\n11](https://packages.debian.org/bullseye/guix) and [Ubuntu\n21.04](https://packages.ubuntu.com/hirsute/guix).\n\nNote that if you intend on using Guix without using any substitutes (more\ndetails [here][security-model]), v1.2.0 has a known problem when building GnuTLS\nfrom source. Solutions and workarounds are documented\n[here](#gnutls-test-suite-fail-status-request-revoked).\n\n\nTo install:\n```sh\nsudo apt install guix\n```\n\nFor up-to-date information on Debian and Ubuntu's release history:\n- [Debian release history](https://www.debian.org/releases/)\n- [Ubuntu release history](https://ubuntu.com/about/release-cycle)\n\n### Arch Linux\n\nGuix is available in the AUR as\n[`guix`](https://aur.archlinux.org/packages/guix/), please follow the\ninstallation instructions in the Arch Linux Wiki ([live\nlink](https://wiki.archlinux.org/index.php/Guix#AUR_Package_Installation),\n[2021/03/30\npermalink](https://wiki.archlinux.org/index.php?title=Guix&oldid=637559#AUR_Package_Installation))\nto install Guix.\n\nAt the time of writing (2021/03/30), the `check` phase will fail if the path to\nguix's build directory is longer than 36 characters due to an anachronistic\ncharacter limit on the shebang line. Since the `check` phase happens after the\n`build` phase, which may take quite a long time, it is recommended that users\neither:\n\n1. Skip the `check` phase\n    - For `makepkg`: `makepkg --nocheck ...`\n    - For `yay`: `yay --mflags=\"--nocheck\" ...`\n    - For `paru`: `paru --nocheck ...`\n2. Or, check their build directory's length beforehand\n    - For those building with `makepkg`: `pwd | wc -c`\n\n## Option 5: Building from source\n\nBuilding Guix from source is a rather involved process but a rewarding one for\nthose looking to minimize trust and maximize customizability (e.g. building a\nparticular commit of Guix). Previous experience with using autotools-style build\nsystems to build packages from source will be helpful. *hic sunt dracones.*\n\nI strongly urge you to at least skim through the entire section once before you\nstart issuing commands, as it will save you a lot of unnecessary pain and\nanguish.\n\n### Installing common build tools\n\nThere are a few basic build tools that are required for most things we'll build,\nso let's install them now:\n\nText transformation/i18n:\n- `autopoint` (sometimes packaged in `gettext`)\n- `help2man`\n- `po4a`\n- `texinfo`\n\nBuild system tools:\n- `g++` w/ C++11 support\n- `libtool`\n- `autoconf`\n- `automake`\n- `pkg-config` (sometimes packaged as `pkgconf`)\n- `make`\n- `cmake`\n\nMiscellaneous:\n- `git`\n- `gnupg`\n- `python3`\n\n### Building and Installing Guix's dependencies\n\nIn order to build Guix itself from source, we need to first make sure that the\nnecessary dependencies are installed and discoverable. The most up-to-date list\nof Guix's dependencies is kept in the [\"Requirements\"\nsection](https://guix.gnu.org/manual/en/html_node/Requirements.html) of the Guix\nReference Manual.\n\nDepending on your distribution, most or all of these dependencies may already be\npackaged and installable without manually building and installing.\n\nFor reference, the graphic below outlines Guix v1.3.0's dependency graph:\n\n![bootstrap map](https://user-images.githubusercontent.com/6399679/125064185-a9a59880-e0b0-11eb-82c1-9b8e5dc9950d.png)\n\n#### Guile\n\n##### Choosing a Guile version and sticking to it\n\nOne of the first things you need to decide is which Guile version you want to\nuse: Guile v2.2 or Guile v3.0. Unlike the python2 to python3 transition, Guile\nv2.2 and Guile v3.0 are largely compatible, as evidenced by the fact that most\nGuile packages and even [Guix\nitself](https://guix.gnu.org/en/blog/2020/guile-3-and-guix/) support running on\nboth.\n\nWhat is important here is that you **choose one**, and you **remain consistent**\nwith your choice throughout **all Guile-related packages**, no matter if they\nare installed via the distribution's package manager or installed from source.\nThis is because the files for Guile packages are installed to directories which\nare separated based on the Guile version.\n\n###### Example: Checking that Ubuntu's `guile-git` is compatible with your chosen Guile version\n\nOn Ubuntu Focal:\n\n```sh\n$ apt show guile-git\nPackage: guile-git\n...\nDepends: guile-2.2, guile-bytestructures, libgit2-dev\n...\n```\n\nAs you can see, the package `guile-git` depends on `guile-2.2`, meaning that it\nwas likely built for Guile v2.2. This means that if you decided to use Guile\nv3.0 on Ubuntu Focal, you would need to build guile-git from source instead of\nusing the distribution package.\n\nOn Ubuntu Hirsute:\n\n```sh\n$ apt show guile-git\nPackage: guile-git\n...\nDepends: guile-3.0 | guile-2.2, guile-bytestructures (>= 1.0.7-3~), libgit2-dev (>= 1.0)\n...\n```\n\nIn this case, `guile-git` depends on either `guile-3.0` or `guile-2.2`, meaning\nthat it would work no matter what Guile version you decided to use.\n\n###### Corner case: Multiple versions of Guile on one system\n\nIt is recommended to only install one version of Guile, so that build systems do\nnot get confused about which Guile to use.\n\nHowever, if you insist on having both Guile v2.2 and Guile v3.0 installed on\nyour system, then you need to **consistently** specify one of\n`GUILE_EFFECTIVE_VERSION=3.0` or `GUILE_EFFECTIVE_VERSION=2.2` to all\n`./configure` invocations for Guix and its dependencies.\n\n##### Installing Guile\n\nGuile is most likely already packaged for your distribution, so after you have\n[chosen a Guile version](#choosing-a-guile-version-and-sticking-to-it), install\nit via your distribution's package manager.\n\nIf your distribution splits packages into `-dev`-suffixed and\nnon-`-dev`-suffixed sub-packages (as is the case for Debian-derived\ndistributions), please make sure to install both. For example, to install Guile\nv2.2 on Debian/Ubuntu:\n\n```sh\napt install guile-2.2 guile-2.2-dev\n```\n\n#### Mixing distribution packages and source-built packages\n\nAt the time of writing, most distributions have _some_ of Guix's dependencies\npackaged, but not all. This means that you may want to install the distribution\npackage for some dependencies, and manually build-from-source for others.\n\nDistribution packages usually install to `/usr`, which is different from the\ndefault `./configure` prefix of source-built packages: `/usr/local`.\n\nThis means that if you mix-and-match distribution packages and source-built\npackages and do not specify exactly `--prefix=/usr` to `./configure` for\nsource-built packages, you will need to augment the `GUILE_LOAD_PATH` and\n`GUILE_LOAD_COMPILED_PATH` environment variables so that Guile will look\nunder the right prefix and find your source-built packages.\n\nFor example, if you are using Guile v2.2, and have Guile packages in the\n`/usr/local` prefix, either add the following lines to your `.profile` or\n`.bash_profile` so that the environment variable is properly set for all future\nshell logins, or paste the lines into a POSIX-style shell to temporarily modify\nthe environment variables of your current shell session.\n\n```sh\n# Help Guile v2.2.x find packages in /usr/local\nexport GUILE_LOAD_PATH=\"/usr/local/share/guile/site/2.2${GUILE_LOAD_PATH:+:}$GUILE_LOAD_PATH\"\nexport GUILE_LOAD_COMPILED_PATH=\"/usr/local/lib/guile/2.2/site-ccache${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_COMPILED_LOAD_PATH\"\n```\n\nNote that these environment variables are used to check for packages during\n`./configure`, so they should be set as soon as possible should you want to use\na prefix other than `/usr`.\n\n#### Building and installing source-built packages\n\n***IMPORTANT**: A few dependencies have non-obvious quirks/errata which are\ndocumented in the sub-sections immediately below. Please read these sections\nbefore proceeding to build and install these packages.*\n\nAlthough you should always refer to the README or INSTALL files for the most\naccurate information, most of these dependencies use autoconf-style build\nsystems (check if there's a `configure.ac` file), and will likely do the right\nthing with the following:\n\nClone the repository and check out the latest release:\n```sh\ngit clone <git-repo-of-dependency>/<dependency>.git\ncd <dependency>\ngit tag -l  # check for the latest release\ngit checkout <latest-release>\n```\n\nFor autoconf-based build systems (if `./autogen.sh` or `configure.ac` exists at\nthe root of the repository):\n\n```sh\n./autogen.sh || autoreconf -vfi\n./configure --prefix=<prefix>\nmake\nsudo make install\n```\n\nFor CMake-based build systems (if `CMakeLists.txt` exists at the root of the\nrepository):\n\n```sh\nmkdir build && cd build\ncmake .. -DCMAKE_INSTALL_PREFIX=<prefix>\nsudo cmake --build . --target install\n```\n\nIf you choose not to specify exactly `--prefix=/usr` to `./configure`, please\nmake sure you've carefully read the [previous section] on mixing distribution\npackages and source-built packages.\n\n##### Binding packages require `-dev`-suffixed packages\n\nRelevant for:\n- Everyone\n\nWhen building bindings, the `-dev`-suffixed version of the original package\nneeds to be installed. For example, building `Guile-zlib` on Debian-derived\ndistributions requires that `zlib1g-dev` is installed.\n\nWhen using bindings, the `-dev`-suffixed version of the original package still\nneeds to be installed. This is particularly problematic when distribution\npackages are mispackaged like `guile-sqlite3` is in Ubuntu Focal such that\ninstalling `guile-sqlite3` does not automatically install `libsqlite3-dev` as a\ndependency.\n\nBelow is a list of relevant Guile bindings and their corresponding `-dev`\npackages in Debian at the time of writing.\n\n| Guile binding package | -dev Debian package |\n|-----------------------|---------------------|\n| guile-gcrypt          | libgcrypt-dev       |\n| guile-git             | libgit2-dev         |\n| guile-lzlib           | liblz-dev           |\n| guile-ssh             | libssh-dev          |\n| guile-sqlite3         | libsqlite3-dev      |\n| guile-zlib            | zlib1g-dev          |\n\n##### `guile-git` actually depends on `libgit2 >= 1.1`\n\nRelevant for:\n- Those building `guile-git` from source against `libgit2 < 1.1`\n- Those installing `guile-git` from their distribution where `guile-git` is\n  built against `libgit2 < 1.1`\n\nAs of v0.4.0, `guile-git` claims to only require `libgit2 >= 0.28.0`, however,\nit actually requires `libgit2 >= 1.1`, otherwise, it will be confused by a\nreference of `origin/keyring`: instead of interpreting the reference as \"the\n'keyring' branch of the 'origin' remote\", the reference is interpreted as \"the\nbranch literally named 'origin/keyring'\"\n\nThis is especially notable because Ubuntu Focal packages `libgit2 v0.28.4`, and\n`guile-git` is built against it.\n\nShould you be in this situation, you need to build both `libgit2 v1.1.x` and\n`guile-git` from source.\n\nSource: https://logs.guix.gnu.org/guix/2020-11-12.log#232527\n\n##### `{scheme,guile}-bytestructures` v1.0.8 and v1.0.9 are broken for Guile v2.2\n\nRelevant for:\n- Those building `{scheme,guile}-bytestructures` from source against Guile v2.2\n\nCommit\n[707eea3](https://github.com/TaylanUB/scheme-bytestructures/commit/707eea3a85e1e375e86702229ebf73d496377669)\nintroduced a regression for Guile v2.2 and was first included in v1.0.8, this\nwas later corrected in commit\n[ec9a721](https://github.com/TaylanUB/scheme-bytestructures/commit/ec9a721957c17bcda13148f8faa5f06934431ff7)\nand included in v1.1.0.\n\nTL;DR If you decided to use Guile v2.2, do not use `{scheme,guile}-bytestructures` v1.0.8 or v1.0.9.\n\n### Building and Installing Guix itself\n\nStart by cloning Guix:\n\n```\ngit clone https://git.savannah.gnu.org/git/guix.git\ncd guix\n```\n\nYou will likely want to build the latest release, however, if the latest release\nwhen you're reading this is still 1.2.0 then you may want to use 95aca29 instead\nto avoid a problem in the GnuTLS test suite.\n\n```\ngit branch -a -l 'origin/version-*'  # check for the latest release\ngit checkout <latest-release>\n```\n\nBootstrap the build system:\n```\n./bootstrap\n```\n\nConfigure with the recommended `--localstatedir` flag:\n```\n./configure --localstatedir=/var\n```\n\nNote: If you intend to hack on Guix in the future, you will need to supply the\nsame `--localstatedir=` flag for all future Guix `./configure` invocations. See\nthe last paragraph of this\n[section](https://guix.gnu.org/manual/en/html_node/Requirements.html) for more\ndetails.\n\nBuild Guix (this will take a while):\n```\nmake -j$(nproc)\n```\n\nInstall Guix:\n\n```\nsudo make install\n```\n\n### Post-\"build from source\" Setup\n\n#### Creating and starting a `guix-daemon-original` service with a fixed `argv[0]`\n\nAt this point, guix will be installed to `${bindir}`, which is likely\n`/usr/local/bin` if you did not override directory variables at\n`./configure`-time. More information on standard Automake directory variables\ncan be found\n[here](https://www.gnu.org/software/automake/manual/html_node/Standard-Directory-Variables.html).\n\nHowever, the Guix init scripts and service configurations for Upstart, systemd,\nSysV, and OpenRC are installed (in `${libdir}`) to launch\n`${localstatedir}/guix/profiles/per-user/root/current-guix/bin/guix-daemon`,\nwhich does not yet exist, and will only exist after [`root` performs their first\n`guix pull`](#guix-pull-as-root).\n\nWe need to create a `-original` version of these init scripts that's pointed to\nthe binaries we just built and `make install`'ed in `${bindir}` (normally,\n`/usr/local/bin`).\n\nExample for `systemd`, run as `root`:\n\n```sh\n# Create guix-daemon-original.service by modifying guix-daemon.service\nlibdir=# set according to your PREFIX (default is /usr/local/lib)\nbindir=\"$(dirname $(command -v guix-daemon))\"\nsed -E -e \"s|/\\S*/guix/profiles/per-user/root/current-guix/bin/guix-daemon|${bindir}/guix-daemon|\" \"${libdir}\"/systemd/system/guix-daemon.service > /etc/systemd/system/guix-daemon-original.service\nchmod 664 /etc/systemd/system/guix-daemon-original.service\n\n# Make systemd recognize the new service\nsystemctl daemon-reload\n\n# Make sure that the non-working guix-daemon.service is stopped and disabled\nsystemctl stop guix-daemon\nsystemctl disable guix-daemon\n\n# Make sure that the working guix-daemon-original.service is started and enabled\nsystemctl enable guix-daemon-original\nsystemctl start guix-daemon-original\n```\n\n#### Creating `guix-daemon` users / groups\n\nPlease see the [relevant\nsection](https://guix.gnu.org/manual/en/html_node/Build-Environment-Setup.html)\nin the Guix Reference Manual for more details.\n\n## Optional setup\n\nAt this point, you are set up to [use Guix to build Bitcoin\nCore](./README.md#usage). However, if you want to polish your setup a bit and\nmake it \"what Guix intended\", then read the next few subsections.\n\n### Add an `/etc/profile.d` entry\n\nThis section definitely does not apply to you if you installed Guix using:\n1. The shell installer script\n2. fanquake's Docker image\n3. Debian's `guix` package\n\n#### Background\n\nAlthough Guix knows how to update itself and its packages, it does so in a\nnon-invasive way (it does not modify `/usr/local/bin/guix`).\n\nInstead, it does the following:\n\n- After a `guix pull`, it updates\n  `/var/guix/profiles/per-user/$USER/current-guix`, and creates a symlink\n  targeting this directory at `$HOME/.config/guix/current`\n\n- After a `guix install`, it updates\n  `/var/guix/profiles/per-user/$USER/guix-profile`, and creates a symlink\n  targeting this directory at `$HOME/.guix-profile`\n\nTherefore, in order for these operations to affect your shell/desktop sessions\n(and for the principle of least astonishment to hold), their corresponding\ndirectories have to be added to well-known environment variables like `$PATH`,\n`$INFOPATH`, `$XDG_DATA_DIRS`, etc.\n\nIn other words, if `$HOME/.config/guix/current/bin` does not exist in your\n`$PATH`, a `guix pull` will have no effect on what `guix` you are using. Same\ngoes for `$HOME/.guix-profile/bin`, `guix install`, and installed packages.\n\nHelpfully, after a `guix pull` or `guix install`, a message will be printed like\nso:\n\n```\nhint: Consider setting the necessary environment variables by running:\n\n     GUIX_PROFILE=\"$HOME/.guix-profile\"\n     . \"$GUIX_PROFILE/etc/profile\"\n\nAlternately, see `guix package --search-paths -p \"$HOME/.guix-profile\"'.\n```\n\nHowever, this is somewhat tedious to do for both `guix pull` and `guix install`\nfor each user on the system that wants to properly use `guix`. I recommend that\nyou instead add an entry to `/etc/profile.d` instead. This is done by default\nwhen installing the Debian package later than 1.2.0-4 and when using the shell\nscript installer.\n\n#### Instructions\n\nCreate `/etc/profile.d/guix.sh` with the following content:\n```sh\n# _GUIX_PROFILE: `guix pull` profile\n_GUIX_PROFILE=\"$HOME/.config/guix/current\"\nif [ -L $_GUIX_PROFILE ]; then\n  export PATH=\"$_GUIX_PROFILE/bin${PATH:+:}$PATH\"\n  # Export INFOPATH so that the updated info pages can be found\n  # and read by both /usr/bin/info and/or $GUIX_PROFILE/bin/info\n  # When INFOPATH is unset, add a trailing colon so that Emacs\n  # searches 'Info-default-directory-list'.\n  export INFOPATH=\"$_GUIX_PROFILE/share/info:$INFOPATH\"\nfi\n\n# GUIX_PROFILE: User's default profile\nGUIX_PROFILE=\"$HOME/.guix-profile\"\n[ -L $GUIX_PROFILE ] || return\nGUIX_LOCPATH=\"$GUIX_PROFILE/lib/locale\"\nexport GUIX_PROFILE GUIX_LOCPATH\n\n[ -f \"$GUIX_PROFILE/etc/profile\" ] && . \"$GUIX_PROFILE/etc/profile\"\n\n# set XDG_DATA_DIRS to include Guix installations\nexport XDG_DATA_DIRS=\"$GUIX_PROFILE/share:${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}\"\n```\n\nPlease note that this will not take effect until the next shell or desktop\nsession (log out and log back in).\n\n### `guix pull` as root\n\nBefore you do this, you need to read the section on [choosing your security\nmodel][security-model] and adjust `guix` and `guix-daemon` flags according to\nyour choice, as invoking `guix pull` may pull substitutes from substitute\nservers (which you may not want).\n\nAs mentioned in a previous section, Guix expects\n`${localstatedir}/guix/profiles/per-user/root/current-guix` to be populated with\n`root`'s Guix profile, `guix pull`-ed and built by some former version of Guix.\nHowever, this is not the case when we build from source. Therefore, we need to\nperform a `guix pull` as `root`:\n\n```sh\nsudo --login guix pull --branch=version-<latest-release-version>\n# or\nsudo --login guix pull --commit=<particular-commit>\n```\n\n`guix pull` is quite a long process (especially if you're using\n`--no-substitute`). If you encounter build problems, please refer to the\n[troubleshooting section](#troubleshooting).\n\nNote that running a bare `guix pull` with no commit or branch specified will\npull the latest commit on Guix's master branch, which is likely fine, but not\nrecommended.\n\nIf you installed Guix from source, you may get an error like the following:\n```sh\nerror: while creating symlink '/root/.config/guix/current' No such file or directory\n```\nTo resolve this, simply:\n```\nsudo mkdir -p /root/.config/guix\n```\nThen try the `guix pull` command again.\n\nAfter the `guix pull` finishes successfully,\n`${localstatedir}/guix/profiles/per-user/root/current-guix` should be populated.\n\n#### Using the newly-pulled `guix` by restarting the daemon\n\nDepending on how you installed Guix, you should now make sure that your init\nscripts and service configurations point to the newly-pulled `guix-daemon`.\n\n##### If you built Guix from source\n\nIf you followed the instructions for [fixing argv\\[0\\]][fix-argv0], you can now\ndo the following:\n\n```sh\nsystemctl stop guix-daemon-original\nsystemctl disable guix-daemon-original\n\nsystemctl enable guix-daemon\nsystemctl start guix-daemon\n```\n\n##### If you installed Guix via the Debian/Ubuntu distribution packages\n\nYou will need to create a `guix-daemon-latest` service which points to the new\n`guix` rather than a pinned one.\n\n```sh\n# Create guix-daemon-latest.service by modifying guix-daemon.service\nsed -E -e \"s|/usr/bin/guix-daemon|/var/guix/profiles/per-user/root/current-guix/bin/guix-daemon|\" /etc/systemd/system/guix-daemon.service > /lib/systemd/system/guix-daemon-latest.service\nchmod 664 /lib/systemd/system/guix-daemon-latest.service\n\n# Make systemd recognize the new service\nsystemctl daemon-reload\n\n# Make sure that the old guix-daemon.service is stopped and disabled\nsystemctl stop guix-daemon\nsystemctl disable guix-daemon\n\n# Make sure that the new guix-daemon-latest.service is started and enabled\nsystemctl enable guix-daemon-latest\nsystemctl start guix-daemon-latest\n```\n\n##### If you installed Guix via lantw44's Arch Linux AUR package\n\nAt the time of writing (July 5th, 2021) the systemd unit for \"updated Guix\" is\n`guix-daemon-latest.service`, therefore, you should do the following:\n\n```sh\nsystemctl stop guix-daemon\nsystemctl disable guix-daemon\n\nsystemctl enable guix-daemon-latest\nsystemctl start guix-daemon-latest\n```\n\n##### Otherwise...\n\nSimply do:\n\n```sh\nsystemctl restart guix-daemon\n```\n\n### Checking everything\n\nIf you followed all the steps above to make your Guix setup \"prim and proper,\"\nyou can check that you did everything properly by running through this\nchecklist.\n\n1. `/etc/profile.d/guix.sh` should exist and be sourced at each shell login\n\n2. `guix describe` should not print `guix describe: error: failed to determine\n   origin`, but rather something like:\n\n   ```\n   Generation 38   Feb 22 2021 16:39:31    (current)\n     guix f350df4\n       repository URL: https://git.savannah.gnu.org/git/guix.git\n       branch: version-1.2.0\n       commit: f350df405fbcd5b9e27e6b6aa500da7f101f41e7\n   ```\n\n3. `guix-daemon` should be running from `${localstatedir}/guix/profiles/per-user/root/current-guix`\n\n# Troubleshooting\n\n## Derivation failed to build\n\nWhen you see a build failure like below:\n\n```\nbuilding /gnu/store/...-foo-3.6.12.drv...\n/ 'check' phasenote: keeping build directory `/tmp/guix-build-foo-3.6.12.drv-0'\nbuilder for `/gnu/store/...-foo-3.6.12.drv' failed with exit code 1\nbuild of /gnu/store/...-foo-3.6.12.drv failed\nView build log at '/var/log/guix/drvs/../...-foo-3.6.12.drv.bz2'.\ncannot build derivation `/gnu/store/...-qux-7.69.1.drv': 1 dependencies couldn't be built\ncannot build derivation `/gnu/store/...-bar-3.16.5.drv': 1 dependencies couldn't be built\ncannot build derivation `/gnu/store/...-baz-2.0.5.drv': 1 dependencies couldn't be built\nguix time-machine: error: build of `/gnu/store/...-baz-2.0.5.drv' failed\n```\n\nIt means that `guix` failed to build a package named `foo`, which was a\ndependency of `qux`, `bar`, and `baz`. Importantly, note that the last \"failed\"\nline is not necessarily the root cause, the first \"failed\" line is.\n\nMost of the time, the build failure is due to a spurious test failure or the\npackage's build system/test suite breaking when running multi-threaded. To\nrebuild _just_ this derivation in a single-threaded fashion (please don't forget\nto add other `guix` flags like `--no-substitutes` as appropriate):\n\n```sh\n$ guix build --cores=1 /gnu/store/...-foo-3.6.12.drv\n```\n\nIf the single-threaded rebuild did not succeed, you may need to dig deeper.\nYou may view `foo`'s build logs in `less` like so (please replace paths with the\npath you see in the build failure output):\n\n```sh\n$ bzcat /var/log/guix/drvs/../...-foo-3.6.12.drv.bz2 | less\n```\n\n`foo`'s build directory is also preserved and available at\n`/tmp/guix-build-foo-3.6.12.drv-0`. However, if you fail to build `foo` multiple\ntimes, it may be `/tmp/...drv-1` or `/tmp/...drv-2`. Always consult the build\nfailure output for the most accurate, up-to-date information.\n\n### python(-minimal): [Errno 84] Invalid or incomplete multibyte or wide character\n\nThis error occurs when your `$TMPDIR` (default: /tmp) exists on a filesystem\nwhich rejects characters not present in the UTF-8 character code set. An example\nis ZFS with the utf8only=on option set.\n\nMore information: https://bugs.python.org/issue37584\n\n### GnuTLS: test-suite FAIL: status-request-revoked\n\n*The derivation is likely identified by: `/gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv`*\n\nThis unfortunate error is most common for non-substitute builders who installed\nGuix v1.2.0. The problem stems from the fact that one of GnuTLS's tests uses a\nhardcoded certificate which expired on 2020-10-24.\n\nWhat's more unfortunate is that this GnuTLS derivation is somewhat special in\nGuix's dependency graph and is not affected by the package transformation flags\nlike `--without-tests=`.\n\nThe easiest solution for those encountering this problem is to install a newer\nversion of Guix. However, there are ways to work around this issue:\n\n#### Workaround 1: Using substitutes for this single derivation\n\nIf you've authorized the official Guix build farm's key (more info\n[here](./README.md#step-1-authorize-the-signing-keys)), then you can use\nsubstitutes just for this single derivation by invoking the following:\n\n```sh\nguix build --substitute-urls=\"https://ci.guix.gnu.org\" /gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv\n```\n\nSee [this section](./README.md#removing-authorized-keys) for instructions on how\nto remove authorized keys if you don't want to keep the build farm's key\nauthorized.\n\n#### Workaround 2: Temporarily setting the system clock back\n\nThis workaround was described [here](https://issues.guix.gnu.org/44559#5).\n\nBasically:\n1. Turn off networking\n2. Turn off NTP\n3. Set system time to 2020-10-01\n4. guix build --no-substitutes /gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv\n5. Set system time back to accurate current time\n6. Turn NTP back on\n7. Turn networking back on\n\n### coreutils: FAIL: tests/tail-2/inotify-dir-recreate\n\nThe inotify-dir-create test fails on \"remote\" filesystems such as overlayfs\n(Docker's default filesystem) due to the filesystem being mistakenly recognized\nas non-remote.\n\nA relatively easy workaround to this is to make sure that a somewhat traditional\nfilesystem is mounted at `/tmp` (where `guix-daemon` performs its builds). For\nDocker users, this might mean [using a volume][docker/volumes], [binding\nmounting][docker/bind-mnt] from host, or (for those with enough RAM and swap)\n[mounting a tmpfs][docker/tmpfs] using the `--tmpfs` flag.\n\nPlease see the following links for more details:\n\n- An upstream coreutils bug has been filed: [debbugs#47940](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47940)\n- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935)\n- A commit to skip this test in Guix has been merged into the core-updates branch:\n[savannah/guix@6ba1058](https://git.savannah.gnu.org/cgit/guix.git/commit/?id=6ba1058df0c4ce5611c2367531ae5c3cdc729ab4)\n\n\n[install-script]: #options-1-and-2-using-the-official-shell-installer-script-or-binary-tarball\n[install-bin-tarball]: #options-1-and-2-using-the-official-shell-installer-script-or-binary-tarball\n[install-fanquake-docker]: #option-3-using-fanquakes-docker-image\n[install-distro-pkg]: #option-4-using-a-distribution-maintained-package\n[install-source]: #option-5-building-from-source\n\n[fix-argv0]: #creating-and-starting-a-guix-daemon-original-service-with-a-fixed-argv0\n[security-model]: ./README.md#choosing-your-security-model\n\n[docker/volumes]: https://docs.docker.com/storage/volumes/\n[docker/bind-mnt]: https://docs.docker.com/storage/bind-mounts/\n[docker/tmpfs]: https://docs.docker.com/storage/tmpfs/\n"
  },
  {
    "path": "contrib/guix/README.md",
    "content": "# Bootstrappable Bitcoin Core Builds\n\nThis directory contains the files necessary to perform bootstrappable Bitcoin\nCore builds.\n\n[Bootstrappability][b17e] furthers our binary security guarantees by allowing us\nto _audit and reproduce_ our toolchain instead of blindly _trusting_ binary\ndownloads.\n\nWe achieve bootstrappability by using Guix as a functional package manager.\n\n# Requirements\n\nConservatively, you will need an x86_64 machine with:\n\n- 16GB of free disk space on the partition that /gnu/store will reside in\n- 8GB of free disk space **per platform triple** you're planning on building\n  (see the `HOSTS` [environment variable description][env-vars-list])\n\n# Installation and Setup\n\nIf you don't have Guix installed and set up, please follow the instructions in\n[INSTALL.md](./INSTALL.md)\n\n# Usage\n\nIf you haven't considered your security model yet, please read [the relevant\nsection](#choosing-your-security-model) before proceeding to perform a build.\n\n## Making the Xcode SDK available for macOS cross-compilation\n\nIn order to perform a build for macOS (which is included in the default set of\nplatform triples to build), you'll need to extract the macOS SDK tarball using\ntools found in the [`macdeploy` directory](../macdeploy/README.md).\n\nYou can then either point to the SDK using the `SDK_PATH` environment variable:\n\n```sh\n# Extract the SDK tarball to /path/to/parent/dir/of/extracted/SDK/Xcode-<foo>-<bar>-extracted-SDK-with-libcxx-headers\ntar -C /path/to/parent/dir/of/extracted/SDK -xaf /path/to/Xcode-<foo>-<bar>-extracted-SDK-with-libcxx-headers.tar.gz\n\n# Indicate where to locate the SDK tarball\nexport SDK_PATH=/path/to/parent/dir/of/extracted/SDK\n```\n\nor extract it into `depends/SDKs`:\n\n```sh\nmkdir -p depends/SDKs\ntar -C depends/SDKs -xaf /path/to/SDK/tarball\n```\n\n## Building\n\n*The author highly recommends at least reading over the [common usage patterns\nand examples](#common-guix-build-invocation-patterns-and-examples) section below\nbefore starting a build. For a full list of customization options, see the\n[recognized environment variables][env-vars-list] section.*\n\nTo build Bitcoin Core reproducibly with all default options, invoke the\nfollowing from the top of a clean repository:\n\n```sh\n./contrib/guix/guix-build\n```\n\n## Codesigning build outputs\n\nThe `guix-codesign` command attaches codesignatures (produced by codesigners) to\nexisting non-codesigned outputs. Please see the [release process\ndocumentation](/doc/release-process.md) for more context.\n\nIt respects many of the same environment variable flags as `guix-build`, with 2\ncrucial differences:\n\n1. Since only Windows and macOS build outputs require codesigning, the `HOSTS`\n   environment variable will have a sane default value of `x86_64-w64-mingw32\n   x86_64-apple-darwin arm64-apple-darwin` instead of all the platforms.\n2. The `guix-codesign` command ***requires*** a `DETACHED_SIGS_REPO` flag.\n    * _**DETACHED_SIGS_REPO**_\n\n      Set the directory where detached codesignatures can be found for the current\n      Bitcoin Core version being built.\n\n      _REQUIRED environment variable_\n\nAn invocation with all default options would look like:\n\n```\nenv DETACHED_SIGS_REPO=<path/to/bitcoin-detached-sigs> ./contrib/guix/guix-codesign\n```\n\n## Cleaning intermediate work directories\n\nBy default, `guix-build` leaves all intermediate files or \"work directories\"\n(e.g. `depends/work`, `guix-build-*/distsrc-*`) intact at the end of a build so\nthat they are available to the user (to aid in debugging, etc.). However, these\ndirectories usually take up a large amount of disk space. Therefore, a\n`guix-clean` convenience script is provided which cleans the current `git`\nworktree to save disk space:\n\n```\n./contrib/guix/guix-clean\n```\n\n\n## Attesting to build outputs\n\nMuch like how Gitian build outputs are attested to in a `gitian.sigs`\nrepository, Guix build outputs are attested to in the [`guix.sigs`\nrepository](https://github.com/bitcoin-core/guix.sigs).\n\nAfter you've cloned the `guix.sigs` repository, to attest to the current\nworktree's commit/tag:\n\n```\nenv GUIX_SIGS_REPO=<path/to/guix.sigs> SIGNER=<gpg-key-name> ./contrib/guix/guix-attest\n```\n\nSee `./contrib/guix/guix-attest --help` for more information on the various ways\n`guix-attest` can be invoked.\n\n## Verifying build output attestations\n\nAfter at least one other signer has uploaded their signatures to the `guix.sigs`\nrepository:\n\n```\ngit -C <path/to/guix.sigs> pull\nenv GUIX_SIGS_REPO=<path/to/guix.sigs> ./contrib/guix/guix-verify\n```\n\n\n## Common `guix-build` invocation patterns and examples\n\n### Keeping caches and SDKs outside of the worktree\n\nIf you perform a lot of builds and have a bunch of worktrees, you may find it\nmore efficient to keep the depends tree's download cache, build cache, and SDKs\noutside of the worktrees to avoid duplicate downloads and unnecessary builds. To\nhelp with this situation, the `guix-build` script honours the `SOURCES_PATH`,\n`BASE_CACHE`, and `SDK_PATH` environment variables and will pass them on to the\ndepends tree so that you can do something like:\n\n```sh\nenv SOURCES_PATH=\"$HOME/depends-SOURCES_PATH\" BASE_CACHE=\"$HOME/depends-BASE_CACHE\" SDK_PATH=\"$HOME/macOS-SDKs\" ./contrib/guix/guix-build\n```\n\nNote that the paths that these environment variables point to **must be\ndirectories**, and **NOT symlinks to directories**.\n\nSee the [recognized environment variables][env-vars-list] section for more\ndetails.\n\n### Building a subset of platform triples\n\nSometimes you only want to build a subset of the supported platform triples, in\nwhich case you can override the default list by setting the space-separated\n`HOSTS` environment variable:\n\n```sh\nenv HOSTS='x86_64-w64-mingw32 x86_64-apple-darwin' ./contrib/guix/guix-build\n```\n\nSee the [recognized environment variables][env-vars-list] section for more\ndetails.\n\n### Controlling the number of threads used by `guix` build commands\n\nDepending on your system's RAM capacity, you may want to decrease the number of\nthreads used to decrease RAM usage or vice versa.\n\nBy default, the scripts under `./contrib/guix` will invoke all `guix` build\ncommands with `--cores=\"$JOBS\"`. Note that `$JOBS` defaults to `$(nproc)` if not\nspecified. However, astute manual readers will also notice that `guix` build\ncommands also accept a `--max-jobs=` flag (which defaults to 1 if unspecified).\n\nHere is the difference between `--cores=` and `--max-jobs=`:\n\n> Note: When I say \"derivation,\" think \"package\"\n\n`--cores=`\n\n  - controls the number of CPU cores to build each derivation. This is the value\n    passed to `make`'s `--jobs=` flag.\n\n`--max-jobs=`\n\n  - controls how many derivations can be built in parallel\n  - defaults to 1\n\nTherefore, the default is for `guix` build commands to build one derivation at a\ntime, utilizing `$JOBS` threads.\n\nSpecifying the `$JOBS` environment variable will only modify `--cores=`, but you\ncan also modify the value for `--max-jobs=` by specifying\n`$ADDITIONAL_GUIX_COMMON_FLAGS`. For example, if you have a LOT of memory, you\nmay want to set:\n\n```sh\nexport ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8'\n```\n\nWhich allows for a maximum of 8 derivations to be built at the same time, each\nutilizing `$JOBS` threads.\n\nOr, if you'd like to avoid spurious build failures caused by issues with\nparallelism within a single package, but would still like to build multiple\npackages when the dependency graph allows for it, you may want to try:\n\n```sh\nexport JOBS=1 ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8'\n```\n\nSee the [recognized environment variables][env-vars-list] section for more\ndetails.\n\n## Recognized environment variables\n\n* _**HOSTS**_\n\n  Override the space-separated list of platform triples for which to perform a\n  bootstrappable build.\n\n  _(defaults to \"x86\\_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu\n  riscv64-linux-gnu powerpc64-linux-gnu powerpc64le-linux-gnu\n  x86\\_64-w64-mingw32 x86\\_64-apple-darwin arm64-apple-darwin\")_\n\n* _**SOURCES_PATH**_\n\n  Set the depends tree download cache for sources. This is passed through to the\n  depends tree. Setting this to the same directory across multiple builds of the\n  depends tree can eliminate unnecessary redownloading of package sources.\n\n  The path that this environment variable points to **must be a directory**, and\n  **NOT a symlink to a directory**.\n\n* _**BASE_CACHE**_\n\n  Set the depends tree cache for built packages. This is passed through to the\n  depends tree. Setting this to the same directory across multiple builds of the\n  depends tree can eliminate unnecessary building of packages.\n\n  The path that this environment variable points to **must be a directory**, and\n  **NOT a symlink to a directory**.\n\n* _**SDK_PATH**_\n\n  Set the path where _extracted_ SDKs can be found. This is passed through to\n  the depends tree. Note that this is should be set to the _parent_ directory of\n  the actual SDK (e.g. `SDK_PATH=$HOME/Downloads/macOS-SDKs` instead of\n  `$HOME/Downloads/macOS-SDKs/Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers`).\n\n  The path that this environment variable points to **must be a directory**, and\n  **NOT a symlink to a directory**.\n\n* _**JOBS**_\n\n  Override the number of jobs to run simultaneously, you might want to do so on\n  a memory-limited machine. This may be passed to:\n\n  - `guix` build commands as in `guix environment --cores=\"$JOBS\"`\n  - `make` as in `make --jobs=\"$JOBS\"`\n  - `xargs` as in `xargs -P\"$JOBS\"`\n\n  See [here](#controlling-the-number-of-threads-used-by-guix-build-commands) for\n  more details.\n\n  _(defaults to the value of `nproc` outside the container)_\n\n* _**SOURCE_DATE_EPOCH**_\n\n  Override the reference UNIX timestamp used for bit-for-bit reproducibility,\n  the variable name conforms to [standard][r12e/source-date-epoch].\n\n  _(defaults to the output of `$(git log --format=%at -1)`)_\n\n* _**V**_\n\n  If non-empty, will pass `V=1` to all `make` invocations, making `make` output\n  verbose.\n\n  Note that any given value is ignored. The variable is only checked for\n  emptiness. More concretely, this means that `V=` (setting `V` to the empty\n  string) is interpreted the same way as not setting `V` at all, and that `V=0`\n  has the same effect as `V=1`.\n\n* _**SUBSTITUTE_URLS**_\n\n  A whitespace-delimited list of URLs from which to download pre-built packages.\n  A URL is only used if its signing key is authorized (refer to the [substitute\n  servers section](#option-1-building-with-substitutes) for more details).\n\n* _**ADDITIONAL_GUIX_COMMON_FLAGS**_\n\n  Additional flags to be passed to all `guix` commands.\n\n* _**ADDITIONAL_GUIX_TIMEMACHINE_FLAGS**_\n\n  Additional flags to be passed to `guix time-machine`.\n\n* _**ADDITIONAL_GUIX_ENVIRONMENT_FLAGS**_\n\n  Additional flags to be passed to the invocation of `guix environment` inside\n  `guix time-machine`.\n\n# Choosing your security model\n\nNo matter how you installed Guix, you need to decide on your security model for\nbuilding packages with Guix.\n\nGuix allows us to achieve better binary security by using our CPU time to build\neverything from scratch. However, it doesn't sacrifice user choice in pursuit of\nthis: users can decide whether or not to use **substitutes** (pre-built\npackages).\n\n## Option 1: Building with substitutes\n\n### Step 1: Authorize the signing keys\n\nDepending on the installation procedure you followed, you may have already\nauthorized the Guix build farm key. In particular, the official shell installer\nscript asks you if you want the key installed, and the debian distribution\npackage authorized the key during installation.\n\nYou can check the current list of authorized keys at `/etc/guix/acl`.\n\nAt the time of writing, a `/etc/guix/acl` with just the Guix build farm key\nauthorized looks something like:\n\n```lisp\n(acl\n (entry\n  (public-key\n   (ecc\n    (curve Ed25519)\n    (q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#)\n    )\n   )\n  (tag\n   (guix import)\n   )\n  )\n )\n```\n\nIf you've determined that the official Guix build farm key hasn't been\nauthorized, and you would like to authorize it, run the following as root:\n\n```\nguix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub\n```\n\nIf\n`/var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub`\ndoesn't exist, try:\n\n```sh\nguix archive --authorize < <PREFIX>/share/guix/ci.guix.gnu.org.pub\n```\n\nWhere `<PREFIX>` is likely:\n- `/usr` if you installed from a distribution package\n- `/usr/local` if you installed Guix from source and didn't supply any\n  prefix-modifying flags to Guix's `./configure`\n\nFor dongcarl's substitute server at https://guix.carldong.io, run as root:\n\n```sh\nwget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize\n```\n\n#### Removing authorized keys\n\nTo remove previously authorized keys, simply edit `/etc/guix/acl` and remove the\n`(entry (public-key ...))` entry.\n\n### Step 2: Specify the substitute servers\n\nOnce its key is authorized, the official Guix build farm at\nhttps://ci.guix.gnu.org is automatically used unless the `--no-substitutes` flag\nis supplied. This default list of substitute servers is overridable both on a\n`guix-daemon` level and when you invoke `guix` commands. See examples below for\nthe various ways of adding dongcarl's substitute server after having [authorized\nhis signing key](#authorize-the-signing-keys).\n\nChange the **default list** of substitute servers by starting `guix-daemon` with\nthe `--substitute-urls` option (you will likely need to edit your init script):\n\n```sh\nguix-daemon <cmd> --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org'\n```\n\nOverride the default list of substitute servers by passing the\n`--substitute-urls` option for invocations of `guix` commands:\n\n```sh\nguix <cmd> --substitute-urls='https://guix.carldong.io https://ci.guix.gnu.org'\n```\n\nFor scripts under `./contrib/guix`, set the `SUBSTITUTE_URLS` environment\nvariable:\n\n```sh\nexport SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org'\n```\n\n## Option 2: Disabling substitutes on an ad-hoc basis\n\nIf you prefer not to use any substitutes, make sure to supply `--no-substitutes`\nlike in the following snippet. The first build will take a while, but the\nresulting packages will be cached for future builds.\n\nFor direct invocations of `guix`:\n```sh\nguix <cmd> --no-substitutes\n```\n\nFor the scripts under `./contrib/guix/`:\n```sh\nexport ADDITIONAL_GUIX_COMMON_FLAGS='--no-substitutes'\n```\n\n## Option 3: Disabling substitutes by default\n\n`guix-daemon` accepts a `--no-substitutes` flag, which will make sure that,\nunless otherwise overridden by a command line invocation, no substitutes will be\nused.\n\nIf you start `guix-daemon` using an init script, you can edit said script to\nsupply this flag.\n\n\n# Purging/Uninstalling Guix\n\nIn the extraordinarily rare case where you messed up your Guix installation in\nan irreversible way, you may want to completely purge Guix from your system and\nstart over.\n\n1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt\n   purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source).\n2. Remove all build users and groups\n\n   You may check for relevant users and groups using:\n\n   ```\n   getent passwd | grep guix\n   getent group | grep guix\n   ```\n\n   Then, you may remove users and groups using:\n\n   ```\n   sudo userdel <user>\n   sudo groupdel <group>\n   ```\n\n3. Remove all possible Guix-related directories\n    - `/var/guix/`\n    - `/var/log/guix/`\n    - `/gnu/`\n    - `/etc/guix/`\n    - `/home/*/.config/guix/`\n    - `/home/*/.cache/guix/`\n    - `/home/*/.guix-profile/`\n    - `/root/.config/guix/`\n    - `/root/.cache/guix/`\n    - `/root/.guix-profile/`\n\n[b17e]: https://bootstrappable.org/\n[r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/\n\n[guix/install.sh]: https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh\n[guix/bin-install]: https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html\n[guix/env-setup]: https://www.gnu.org/software/guix/manual/en/html_node/Build-Environment-Setup.html\n[guix/substitutes]: https://www.gnu.org/software/guix/manual/en/html_node/Substitutes.html\n[guix/substitute-server-auth]: https://www.gnu.org/software/guix/manual/en/html_node/Substitute-Server-Authorization.html\n[guix/time-machine]: https://guix.gnu.org/manual/en/html_node/Invoking-guix-time_002dmachine.html\n\n[debian/guix-bullseye]: https://packages.debian.org/bullseye/guix\n[ubuntu/guix-hirsute]: https://packages.ubuntu.com/hirsute/guix\n[fanquake/guix-docker]: https://github.com/fanquake/core-review/tree/master/guix\n\n[env-vars-list]: #recognized-environment-variables\n"
  },
  {
    "path": "contrib/guix/guix-attest",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# Source the common prelude, which:\n#   1. Checks if we're at the top directory of the repository\n#   2. Defines a few common functions and variables\n#\n# shellcheck source=libexec/prelude.bash\nsource \"$(dirname \"${BASH_SOURCE[0]}\")/libexec/prelude.bash\"\n\n\n###################\n## Sanity Checks ##\n###################\n\n################\n# Required non-builtin commands should be invokable\n################\n\ncheck_tools cat env basename mkdir diff sort\n\nif [ -z \"$NO_SIGN\" ]; then\n    # make it possible to override the gpg binary\n    GPG=${GPG:-gpg}\n\n    # $GPG can contain extra arguments passed to the binary\n    # so let's check only the existence of arg[0]\n    # shellcheck disable=SC2206\n    GPG_ARRAY=($GPG)\n    check_tools \"${GPG_ARRAY[0]}\"\nfi\n\n################\n# Required env vars should be non-empty\n################\n\ncmd_usage() {\ncat <<EOF\nSynopsis:\n\n    env GUIX_SIGS_REPO=<path/to/guix.sigs> \\\\\n        SIGNER=GPG_KEY_NAME[=SIGNER_NAME] \\\\\n        [ NO_SIGN=1 ]\n      ./contrib/guix/guix-attest\n\nExample w/o overriding signing name:\n\n    env GUIX_SIGS_REPO=/home/achow101/guix.sigs \\\\\n        SIGNER=achow101 \\\\\n      ./contrib/guix/guix-attest\n\nExample overriding signing name:\n\n    env GUIX_SIGS_REPO=/home/dongcarl/guix.sigs \\\\\n        SIGNER=0x96AB007F1A7ED999=dongcarl \\\\\n      ./contrib/guix/guix-attest\n\nExample w/o signing, just creating SHA256SUMS:\n\n    env GUIX_SIGS_REPO=/home/achow101/guix.sigs \\\\\n        SIGNER=achow101 \\\\\n        NO_SIGN=1 \\\\\n      ./contrib/guix/guix-attest\n\nEOF\n}\n\nif [ -z \"$GUIX_SIGS_REPO\" ] || [ -z \"$SIGNER\" ]; then\n    cmd_usage\n    exit 1\nfi\n\n################\n# GUIX_SIGS_REPO should exist as a directory\n################\n\nif [ ! -d \"$GUIX_SIGS_REPO\" ]; then\ncat << EOF\nERR: The specified GUIX_SIGS_REPO is not an existent directory:\n\n    '$GUIX_SIGS_REPO'\n\nHint: Please clone the guix.sigs repository and point to it with the\n      GUIX_SIGS_REPO environment variable.\n\nEOF\ncmd_usage\nexit 1\nfi\n\n################\n# The key specified in SIGNER should be usable\n################\n\nIFS='=' read -r gpg_key_name signer_name <<< \"$SIGNER\"\nif [ -z \"${signer_name}\" ]; then\n    signer_name=\"$gpg_key_name\"\nfi\n\nif [ -z \"$NO_SIGN\" ] && ! ${GPG} --dry-run --list-secret-keys \"${gpg_key_name}\" >/dev/null 2>&1; then\n    echo \"ERR: GPG can't seem to find any key named '${gpg_key_name}'\"\n    exit 1\nfi\n\n################\n# We should be able to find at least one output\n################\n\necho \"Looking for build output SHA256SUMS fragments in ${OUTDIR_BASE}\"\n\nshopt -s nullglob\nsha256sum_fragments=( \"$OUTDIR_BASE\"/*/SHA256SUMS.part ) # This expands to an array of directories...\nshopt -u nullglob\n\nnoncodesigned_fragments=()\ncodesigned_fragments=()\n\nif (( ${#sha256sum_fragments[@]} )); then\n    echo \"Found build output SHA256SUMS fragments:\"\n    for outdir in \"${sha256sum_fragments[@]}\"; do\n        echo \"    '$outdir'\"\n        case \"$outdir\" in\n            \"$OUTDIR_BASE\"/*-codesigned/SHA256SUMS.part)\n                codesigned_fragments+=(\"$outdir\")\n                ;;\n            *)\n                noncodesigned_fragments+=(\"$outdir\")\n                ;;\n        esac\n    done\n    echo\nelse\n    echo \"ERR: Could not find any build output SHA256SUMS fragments in ${OUTDIR_BASE}\"\n    exit 1\nfi\n\n##############\n##  Attest  ##\n##############\n\n# Usage: out_name $outdir\n#\n#   HOST: The output directory being attested\n#\nout_name() {\n    basename \"$(dirname \"$1\")\"\n}\n\nshasum_already_exists() {\ncat <<EOF\n--\n\nERR: An ${1} file already exists for '${VERSION}' and attests\n     differently. You likely previously attested to a partial build (e.g. one\n     where you specified the HOST environment variable).\n\n     See the diff above for more context.\n\nHint: You may wish to remove the existing attestations and their signatures by\n      invoking:\n\n          rm '${PWD}/${1}'{,.asc}\n\n      Then try running this script again.\n\nEOF\n}\n\necho \"Attesting to build outputs for version: '${VERSION}'\"\necho \"\"\n\n# Given a SHA256SUMS file as stdin that has lines like:\n#     0ba536819b221a91d3d42e978be016aac918f40984754d74058aa0c921cd3ea6  a/b/d/c/d/s/munt-22.0rc2-riscv64-linux-gnu.tar.gz\n#     ...\n#\n# Replace each line's file name with its basename:\n#     0ba536819b221a91d3d42e978be016aac918f40984754d74058aa0c921cd3ea6  munt-22.0rc2-riscv64-linux-gnu.tar.gz\n#     ...\n#\nbasenameify_SHA256SUMS() {\n    sed -E 's@(^[[:xdigit:]]{64}[[:space:]]+).+/([^/]+$)@\\1\\2@'\n}\n\noutsigdir=\"$GUIX_SIGS_REPO/$VERSION/$signer_name\"\nmkdir -p \"$outsigdir\"\n(\n    cd \"$outsigdir\"\n\n    temp_noncodesigned=\"$(mktemp)\"\n    trap 'rm -rf -- \"$temp_noncodesigned\"' EXIT\n\n    if (( ${#noncodesigned_fragments[@]} )); then\n        cat \"${noncodesigned_fragments[@]}\" \\\n            | sort -u \\\n            | sort -k2 \\\n            | basenameify_SHA256SUMS \\\n                > \"$temp_noncodesigned\"\n        if [ -e noncodesigned.SHA256SUMS ]; then\n            # The SHA256SUMS already exists, make sure it's exactly what we\n            # expect, error out if not\n            if diff -u noncodesigned.SHA256SUMS \"$temp_noncodesigned\"; then\n                echo \"A noncodesigned.SHA256SUMS file already exists for '${VERSION}' and is up-to-date.\"\n            else\n                shasum_already_exists noncodesigned.SHA256SUMS\n                exit 1\n            fi\n        else\n            mv \"$temp_noncodesigned\" noncodesigned.SHA256SUMS\n        fi\n    else\n        echo \"ERR: No noncodesigned outputs found for '${VERSION}', exiting...\"\n        exit 1\n    fi\n\n    temp_all=\"$(mktemp)\"\n    trap 'rm -rf -- \"$temp_all\"' EXIT\n\n    if (( ${#codesigned_fragments[@]} )); then\n        # Note: all.SHA256SUMS attests to all of $sha256sum_fragments, but is\n        #       not needed if there are no $codesigned_fragments\n        cat \"${sha256sum_fragments[@]}\" \\\n            | sort -u \\\n            | sort -k2 \\\n            | basenameify_SHA256SUMS \\\n                > \"$temp_all\"\n        if [ -e all.SHA256SUMS ]; then\n            # The SHA256SUMS already exists, make sure it's exactly what we\n            # expect, error out if not\n            if diff -u all.SHA256SUMS \"$temp_all\"; then\n                echo \"An all.SHA256SUMS file already exists for '${VERSION}' and is up-to-date.\"\n            else\n                shasum_already_exists all.SHA256SUMS\n                exit 1\n            fi\n        else\n            mv \"$temp_all\" all.SHA256SUMS\n        fi\n    else\n        # It is fine to have the codesigned outputs be missing (perhaps the\n        # detached codesigs have not been published yet), just print a log\n        # message instead of erroring out\n        echo \"INFO: No codesigned outputs found for '${VERSION}', skipping...\"\n    fi\n\n    if [ -z \"$NO_SIGN\" ]; then\n        echo \"Signing SHA256SUMS to produce SHA256SUMS.asc\"\n        for i in *.SHA256SUMS; do\n            if [ ! -e \"$i\".asc ]; then\n                ${GPG} --detach-sign \\\n                       --digest-algo sha256 \\\n                       --local-user \"$gpg_key_name\" \\\n                       --armor \\\n                       --output \"$i\".asc \"$i\"\n            else\n                echo \"Signature already there\"\n            fi\n        done\n    else\n        echo \"Not signing SHA256SUMS as \\$NO_SIGN is not empty\"\n    fi\n    echo \"\"\n)\n"
  },
  {
    "path": "contrib/guix/guix-build",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# Source the common prelude, which:\n#   1. Checks if we're at the top directory of the repository\n#   2. Defines a few common functions and variables\n#\n# shellcheck source=libexec/prelude.bash\nsource \"$(dirname \"${BASH_SOURCE[0]}\")/libexec/prelude.bash\"\n\n\n###################\n## SANITY CHECKS ##\n###################\n\n################\n# Required non-builtin commands should be invocable\n################\n\ncheck_tools cat mkdir make getent curl git guix\n\n################\n# GUIX_BUILD_OPTIONS should be empty\n################\n#\n# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that\n# can perform builds. This seems like what we want instead of\n# ADDITIONAL_GUIX_COMMON_FLAGS, but the value of GUIX_BUILD_OPTIONS is actually\n# _appended_ to normal command-line options. Meaning that they will take\n# precedence over the command-specific ADDITIONAL_GUIX_<CMD>_FLAGS.\n#\n# This seems like a poor user experience. Thus we check for GUIX_BUILD_OPTIONS's\n# existence here and direct users of this script to use our (more flexible)\n# custom environment variables.\nif [ -n \"$GUIX_BUILD_OPTIONS\" ]; then\ncat << EOF\nError: Environment variable GUIX_BUILD_OPTIONS is not empty:\n  '$GUIX_BUILD_OPTIONS'\n\nUnfortunately this script is incompatible with GUIX_BUILD_OPTIONS, please unset\nGUIX_BUILD_OPTIONS and use ADDITIONAL_GUIX_COMMON_FLAGS to set build options\nacross guix commands or ADDITIONAL_GUIX_<CMD>_FLAGS to set build options for a\nspecific guix command.\n\nSee contrib/guix/README.md for more details.\nEOF\nexit 1\nfi\n\n################\n# The git worktree should not be dirty\n################\n\nif ! git diff-index --quiet HEAD -- && [ -z \"$FORCE_DIRTY_WORKTREE\" ]; then\ncat << EOF\nERR: The current git worktree is dirty, which may lead to broken builds.\n\n     Aborting...\n\nHint: To make your git worktree clean, You may want to:\n      1. Commit your changes,\n      2. Stash your changes, or\n      3. Set the 'FORCE_DIRTY_WORKTREE' environment variable if you insist on\n         using a dirty worktree\nEOF\nexit 1\nfi\n\nmkdir -p \"$VERSION_BASE\"\n\n################\n# Build directories should not exist\n################\n\n# Default to building for all supported HOSTs (overridable by environment)\nexport HOSTS=\"${HOSTS:-x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu powerpc64-linux-gnu powerpc64le-linux-gnu}\"\n\n# Usage: distsrc_for_host HOST\n#\n#   HOST: The current platform triple we're building for\n#\ndistsrc_for_host() {\n    echo \"${DISTSRC_BASE}/distsrc-${VERSION}-${1}\"\n}\n\n# Accumulate a list of build directories that already exist...\nhosts_distsrc_exists=\"\"\nfor host in $HOSTS; do\n    if [ -e \"$(distsrc_for_host \"$host\")\" ]; then\n        hosts_distsrc_exists+=\" ${host}\"\n    fi\ndone\n\nif [ -n \"$hosts_distsrc_exists\" ]; then\n# ...so that we can print them out nicely in an error message\ncat << EOF\nERR: Build directories for this commit already exist for the following platform\n     triples you're attempting to build, probably because of previous builds.\n     Please remove, or otherwise deal with them prior to starting another build.\n\n     Aborting...\n\nHint: To blow everything away, you may want to use:\n\n  $ ./contrib/guix/guix-clean\n\nSpecifically, this will remove all files without an entry in the index,\nexcluding the SDK directory, the depends download cache, the depends built\npackages cache, the garbage collector roots for Guix environments, and the\noutput directory.\nEOF\nfor host in $hosts_distsrc_exists; do\n    echo \"     ${host} '$(distsrc_for_host \"$host\")'\"\ndone\nexit 1\nelse\n    mkdir -p \"$DISTSRC_BASE\"\nfi\n\n################\n# When building for darwin, the macOS SDK should exist\n################\n\nfor host in $HOSTS; do\n    case \"$host\" in\n        *darwin*)\n            OSX_SDK=\"$(make -C \"${PWD}/depends\" --no-print-directory HOST=\"$host\" print-OSX_SDK | sed 's@^[^=]\\+=@@g')\"\n            if [ -e \"$OSX_SDK\" ]; then\n                echo \"Found macOS SDK at '${OSX_SDK}', using...\"\n                break\n            else\n                echo \"macOS SDK does not exist at '${OSX_SDK}', please place the extracted, untarred SDK there to perform darwin builds, exiting...\"\n                exit 1\n            fi\n            ;;\n    esac\ndone\n\n################\n# VERSION_BASE should have enough space\n################\n\navail_KiB=\"$(df -Pk \"$VERSION_BASE\" | sed 1d | tr -s ' ' | cut -d' ' -f4)\"\ntotal_required_KiB=0\nfor host in $HOSTS; do\n    case \"$host\" in\n        *darwin*) required_KiB=440000 ;;\n        *mingw*)  required_KiB=7600000 ;;\n        *)        required_KiB=6400000 ;;\n    esac\n    total_required_KiB=$((total_required_KiB+required_KiB))\ndone\n\nif (( total_required_KiB > avail_KiB )); then\n    total_required_GiB=$((total_required_KiB / 1048576))\n    avail_GiB=$((avail_KiB / 1048576))\n    echo \"Performing a Munt Core Guix build for the selected HOSTS requires ${total_required_GiB} GiB, however, only ${avail_GiB} GiB is available. Please free up some disk space before performing the build.\"\n    exit 1\nfi\n\n################\n# Check that we can connect to the guix-daemon\n################\n\ncat << EOF\nChecking that we can connect to the guix-daemon...\n\nHint: If this hangs, you may want to try turning your guix-daemon off and on\n      again.\n\nEOF\nif ! guix gc --list-failures > /dev/null; then\ncat << EOF\n\nERR: Failed to connect to the guix-daemon, please ensure that one is running and\n     reachable.\nEOF\nexit 1\nfi\n\n# Developer note: we could use `guix repl` for this check and run:\n#\n#     (import (guix store)) (close-connection (open-connection))\n#\n# However, the internal API is likely to change more than the CLI invocation\n\n################\n# Services database must have basic entries\n################\n\nif ! getent services http https ftp > /dev/null 2>&1; then\ncat << EOF\nERR: Your system's C library cannot find service database entries for at least\n     one of the following services: http, https, ftp.\n\nHint: Most likely, /etc/services does not exist yet (common for docker images\n      and minimal distros), or you don't have permissions to access it.\n\n      If /etc/services does not exist yet, you may want to install the\n      appropriate package for your distro which provides it.\n\n          On Debian/Ubuntu: netbase\n          On Arch Linux: iana-etc\n\n      For more information, see: getent(1), services(5)\n\nEOF\n\nfi\n\n#########\n# SETUP #\n#########\n\n# Determine the maximum number of jobs to run simultaneously (overridable by\n# environment)\nJOBS=\"${JOBS:-$(nproc)}\"\n\n# Usage: host_to_commonname HOST\n#\n#   HOST: The current platform triple we're building for\n#\nhost_to_commonname() {\n    case \"$1\" in\n        *darwin*) echo osx ;;\n        *mingw*)  echo win ;;\n        *linux*)  echo linux ;;\n        *)        exit 1 ;;\n    esac\n}\n\n# Determine the reference time used for determinism (overridable by environment)\nSOURCE_DATE_EPOCH=\"${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --format=%at -1)}\"\n\n# Precious directories are those which should not be cleaned between successive\n# guix builds\ndepends_precious_dir_names='SOURCES_PATH BASE_CACHE SDK_PATH CODESIGN_PATH'\nprecious_dir_names=\"${depends_precious_dir_names} OUTDIR_BASE PROFILES_BASE\"\n\n# Usage: contains IFS-SEPARATED-LIST ITEM\ncontains() {\n    for i in ${1}; do\n        if [ \"$i\" = \"${2}\" ]; then\n            return 0  # Found!\n        fi\n    done\n    return 1\n}\n\n# If the user explicitly specified a precious directory, create it so we\n# can map it into the container\nfor precious_dir_name in $precious_dir_names; do\n    precious_dir_path=\"${!precious_dir_name}\"\n    if [ -n \"$precious_dir_path\" ]; then\n        if [ ! -e \"$precious_dir_path\" ]; then\n            mkdir -p \"$precious_dir_path\"\n        elif [ -L \"$precious_dir_path\" ]; then\n            echo \"ERR: ${precious_dir_name} cannot be a symbolic link\"\n            exit 1\n        elif [ ! -d \"$precious_dir_path\" ]; then\n            echo \"ERR: ${precious_dir_name} must be a directory\"\n            exit 1\n        fi\n    fi\ndone\n\nmkdir -p \"$VAR_BASE\"\n\n# Record the _effective_ values of precious directories such that guix-clean can\n# avoid clobbering them if appropriate.\n#\n# shellcheck disable=SC2046,SC2086\n{\n    # Get depends precious dir definitions from depends\n    make -C \"${PWD}/depends\" \\\n         --no-print-directory \\\n         -- $(printf \"print-%s\\n\" $depends_precious_dir_names)\n\n    # Get remaining precious dir definitions from the environment\n    for precious_dir_name in $precious_dir_names; do\n        precious_dir_path=\"${!precious_dir_name}\"\n        if ! contains \"$depends_precious_dir_names\" \"$precious_dir_name\"; then\n            echo \"${precious_dir_name}=${precious_dir_path}\"\n        fi\n    done\n} > \"${VAR_BASE}/precious_dirs\"\n\n# Make sure an output directory exists for our builds\nOUTDIR_BASE=\"${OUTDIR_BASE:-${VERSION_BASE}/output}\"\nmkdir -p \"$OUTDIR_BASE\"\n\n# Download the depends sources now as we won't have internet access in the build\n# container\nfor host in $HOSTS; do\n    make -C \"${PWD}/depends\" -j\"$JOBS\" download-\"$(host_to_commonname \"$host\")\" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH=\"$SOURCES_PATH\"}\ndone\n\n# Usage: outdir_for_host HOST SUFFIX\n#\n#   HOST: The current platform triple we're building for\n#\noutdir_for_host() {\n    echo \"${OUTDIR_BASE}/${1}${2:+-${2}}\"\n}\n\n# Usage: profiledir_for_host HOST SUFFIX\n#\n#   HOST: The current platform triple we're building for\n#\nprofiledir_for_host() {\n    echo \"${PROFILES_BASE}/${1}${2:+-${2}}\"\n}\n\n\n#########\n# BUILD #\n#########\n\n# Function to be called when building for host ${1} and the user interrupts the\n# build\nint_trap() {\ncat << EOF\n** INT received while building ${1}, you may want to clean up the relevant\n   work directories (e.g. distsrc-*) before rebuilding\n\nHint: To blow everything away, you may want to use:\n\n  $ ./contrib/guix/guix-clean\n\nSpecifically, this will remove all files without an entry in the index,\nexcluding the SDK directory, the depends download cache, the depends built\npackages cache, the garbage collector roots for Guix environments, and the\noutput directory.\nEOF\n}\n\n# Deterministically build Munt\n# shellcheck disable=SC2153\nfor host in $HOSTS; do\n\n    # Display proper warning when the user interrupts the build\n    trap 'int_trap ${host}' INT\n\n    (\n        # Required for 'contrib/guix/manifest.scm' to output the right manifest\n        # for the particular $HOST we're building for\n        export HOST=\"$host\"\n\n        # shellcheck disable=SC2030\ncat << EOF\nINFO: Building ${VERSION:?not set} for platform triple ${HOST:?not set}:\n      ...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}\n      ...running at most ${JOBS:?not set} jobs\n      ...from worktree directory: '${PWD}'\n          ...bind-mounted in container to: '/munt'\n      ...in build directory: '$(distsrc_for_host \"$HOST\")'\n          ...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host \"$HOST\")'\n      ...outputting in: '$(outdir_for_host \"$HOST\")'\n          ...bind-mounted in container to: '$(OUTDIR_BASE=/outdir-base && outdir_for_host \"$HOST\")'\nEOF\n\n        # Run the build script 'contrib/guix/libexec/build.sh' in the build\n        # container specified by 'contrib/guix/manifest.scm'.\n        #\n        # Explanation of `guix environment` flags:\n        #\n        #   --container        run command within an isolated container\n        #\n        #     Running in an isolated container minimizes build-time differences\n        #     between machines and improves reproducibility\n        #\n        #   --pure             unset existing environment variables\n        #\n        #     Same rationale as --container\n        #\n        #   --no-cwd           do not share current working directory with an\n        #                      isolated container\n        #\n        #     When --container is specified, the default behavior is to share\n        #     the current working directory with the isolated container at the\n        #     same exact path (e.g. mapping '/home/satoshi/munt/' to\n        #     '/home/satoshi/munt/'). This means that the $PWD inside the\n        #     container becomes a source of irreproducibility. --no-cwd disables\n        #     this behaviour.\n        #\n        #   --share=SPEC       for containers, share writable host file system\n        #                      according to SPEC\n        #\n        #   --share=\"$PWD\"=/munt\n        #\n        #                     maps our current working directory to /munt\n        #                     inside the isolated container, which we later cd\n        #                     into.\n        #\n        #     While we don't want to map our current working directory to the\n        #     same exact path (as this introduces irreproducibility), we do want\n        #     it to be at a _fixed_ path _somewhere_ inside the isolated\n        #     container so that we have something to build. '/munt' was\n        #     chosen arbitrarily.\n        #\n        #   ${SOURCES_PATH:+--share=\"$SOURCES_PATH\"}\n        #\n        #                     make the downloaded depends sources path available\n        #                     inside the isolated container\n        #\n        #     The isolated container has no network access as it's in a\n        #     different network namespace from the main machine, so we have to\n        #     make the downloaded depends sources available to it. The sources\n        #     should have been downloaded prior to this invocation.\n        #\n        #   --keep-failed     keep build tree of failed builds\n        #\n        #     When builds of the Guix environment itself (not Munt Core)\n        #     fail, it is useful for the build tree to be kept for debugging\n        #     purposes.\n        #\n        #  ${SUBSTITUTE_URLS:+--substitute-urls=\"$SUBSTITUTE_URLS\"}\n        #\n        #                     fetch substitute from SUBSTITUTE_URLS if they are\n        #                     authorized\n        #\n        #    Depending on the user's security model, it may be desirable to use\n        #    substitutes (pre-built packages) from servers that the user trusts.\n        #    Please read the README.md in the same directory as this file for\n        #    more information.\n        #\n        # shellcheck disable=SC2086,SC2031\n        time-machine environment --manifest=\"${PWD}/contrib/guix/manifest.scm\" \\\n                                 --container \\\n                                 --pure \\\n                                 --no-cwd \\\n                                 --share=\"$PWD\"=/munt \\\n                                 --share=\"$DISTSRC_BASE\"=/distsrc-base \\\n                                 --share=\"$OUTDIR_BASE\"=/outdir-base \\\n                                 --expose=\"$(git rev-parse --git-common-dir)\" \\\n                                 ${SOURCES_PATH:+--share=\"$SOURCES_PATH\"} \\\n                                 ${BASE_CACHE:+--share=\"$BASE_CACHE\"} \\\n                                 ${SDK_PATH:+--share=\"$SDK_PATH\"} \\\n                                 ${CODESIGN_PATH:+--share=\"$CODESIGN_PATH\"} \\\n                                 --cores=\"$JOBS\" \\\n                                 --keep-failed \\\n                                 --fallback \\\n                                 --link-profile \\\n                                 --root=\"$(profiledir_for_host \"${HOST}\")\" \\\n                                 ${SUBSTITUTE_URLS:+--substitute-urls=\"$SUBSTITUTE_URLS\"} \\\n                                 ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \\\n                                 -- env HOST=\"$host\" \\\n                                        DISTNAME=\"$DISTNAME\" \\\n                                        JOBS=\"$JOBS\" \\\n                                        SOURCE_DATE_EPOCH=\"${SOURCE_DATE_EPOCH:?unable to determine value}\" \\\n                                        ${V:+V=1} \\\n                                        ${SOURCES_PATH:+SOURCES_PATH=\"$SOURCES_PATH\"} \\\n                                        ${BASE_CACHE:+BASE_CACHE=\"$BASE_CACHE\"} \\\n                                        ${SDK_PATH:+SDK_PATH=\"$SDK_PATH\"} \\\n                                        ${CODESIGN_PATH:+CODESIGN_PATH=\"$CODESIGN_PATH\"} \\\n                                        DISTSRC=\"$(DISTSRC_BASE=/distsrc-base && distsrc_for_host \"$HOST\")\" \\\n                                        OUTDIR=\"$(OUTDIR_BASE=/outdir-base && outdir_for_host \"$HOST\")\" \\\n                                        DIST_ARCHIVE_BASE=/outdir-base/dist-archive \\\n                                      bash -c \"cd /munt && bash contrib/guix/libexec/build.sh\"\n    )\n\ndone\n"
  },
  {
    "path": "contrib/guix/guix-clean",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# Source the common prelude, which:\n#   1. Checks if we're at the top directory of the repository\n#   2. Defines a few common functions and variables\n#\n# shellcheck source=libexec/prelude.bash\nsource \"$(dirname \"${BASH_SOURCE[0]}\")/libexec/prelude.bash\"\n\n\n###################\n## Sanity Checks ##\n###################\n\n################\n# Required non-builtin commands should be invokable\n################\n\ncheck_tools cat mkdir make git guix\n\n\n#############\n##  Clean  ##\n#############\n\n# Usage: under_dir MAYBE_PARENT MAYBE_CHILD\n#\n# If MAYBE_CHILD is a subdirectory of MAYBE_PARENT, print the relative path\n# from MAYBE_PARENT to MAYBE_CHILD. Otherwise, return 1 as the error code.\n#\n# NOTE: This does not perform any symlink-resolving or path canonicalization.\n#\nunder_dir() {\n    local path_residue\n    path_residue=\"${2##\"${1}\"}\"\n    if [ -z \"$path_residue\" ] || [ \"$path_residue\" = \"$2\" ]; then\n        return 1\n    else\n        echo \"$path_residue\"\n    fi\n}\n\n# Usage: dir_under_git_root MAYBE_CHILD\n#\n# If MAYBE_CHILD is under the current git repository and exists, print the\n# relative path from the git repository's top-level directory to MAYBE_CHILD,\n# otherwise, exit with an error code.\n#\ndir_under_git_root() {\n    local rv\n    rv=\"$(under_dir \"$(git_root)\" \"$1\")\"\n    [ -n \"$rv\" ] && echo \"$rv\"\n}\n\nshopt -s nullglob\nfound_precious_dirs_files=( \"${version_base_prefix}\"*/\"${var_base_basename}/precious_dirs\" ) # This expands to an array of directories...\nshopt -u nullglob\n\nexclude_flags=()\n\nfor precious_dirs_file in \"${found_precious_dirs_files[@]}\"; do\n    # Make sure the precious directories (e.g. SOURCES_PATH, BASE_CACHE, SDK_PATH)\n    # are excluded from git-clean\n    echo \"Found precious_dirs file: '${precious_dirs_file}'\"\n\n    # Exclude the precious_dirs file itself\n    if dirs_file_exclude_fragment=$(dir_under_git_root \"$(dirname \"$precious_dirs_file\")\"); then\n        exclude_flags+=( --exclude=\"${dirs_file_exclude_fragment}/precious_dirs\" )\n    fi\n\n    # Read each 'name=dir' pair from the precious_dirs file\n    while IFS='=' read -r name dir; do\n        # Add an exclusion flag if the precious directory is under the git root.\n        if under=$(dir_under_git_root \"$dir\"); then\n            echo \"Avoiding ${name}: ${under}\"\n            exclude_flags+=( --exclude=\"$under\" )\n        fi\n    done < \"$precious_dirs_file\"\ndone\n\ngit clean -xdff \"${exclude_flags[@]}\"\n"
  },
  {
    "path": "contrib/guix/guix-codesign",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# Source the common prelude, which:\n#   1. Checks if we're at the top directory of the repository\n#   2. Defines a few common functions and variables\n#\n# shellcheck source=libexec/prelude.bash\nsource \"$(dirname \"${BASH_SOURCE[0]}\")/libexec/prelude.bash\"\n\n\n###################\n## SANITY CHECKS ##\n###################\n\n################\n# Required non-builtin commands should be invocable\n################\n\ncheck_tools cat mkdir git guix\n\n################\n# Required env vars should be non-empty\n################\n\ncmd_usage() {\n    cat <<EOF\nSynopsis:\n\n    env DETACHED_SIGS_REPO=<path/to/munt-detached-sigs> \\\\\n      ./contrib/guix/guix-codesign\n\nEOF\n}\n\nif [ -z \"$DETACHED_SIGS_REPO\" ]; then\n    cmd_usage\n    exit 1\nfi\n\n################\n# GUIX_BUILD_OPTIONS should be empty\n################\n#\n# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that\n# can perform builds. This seems like what we want instead of\n# ADDITIONAL_GUIX_COMMON_FLAGS, but the value of GUIX_BUILD_OPTIONS is actually\n# _appended_ to normal command-line options. Meaning that they will take\n# precedence over the command-specific ADDITIONAL_GUIX_<CMD>_FLAGS.\n#\n# This seems like a poor user experience. Thus we check for GUIX_BUILD_OPTIONS's\n# existence here and direct users of this script to use our (more flexible)\n# custom environment variables.\nif [ -n \"$GUIX_BUILD_OPTIONS\" ]; then\ncat << EOF\nError: Environment variable GUIX_BUILD_OPTIONS is not empty:\n  '$GUIX_BUILD_OPTIONS'\n\nUnfortunately this script is incompatible with GUIX_BUILD_OPTIONS, please unset\nGUIX_BUILD_OPTIONS and use ADDITIONAL_GUIX_COMMON_FLAGS to set build options\nacross guix commands or ADDITIONAL_GUIX_<CMD>_FLAGS to set build options for a\nspecific guix command.\n\nSee contrib/guix/README.md for more details.\nEOF\nexit 1\nfi\n\n################\n# The codesignature git worktree should not be dirty\n################\n\nif ! git -C \"$DETACHED_SIGS_REPO\" diff-index --quiet HEAD -- && [ -z \"$FORCE_DIRTY_WORKTREE\" ]; then\n    cat << EOF\nERR: The DETACHED CODESIGNATURE git worktree is dirty, which may lead to broken builds.\n\n     Aborting...\n\nHint: To make your git worktree clean, You may want to:\n      1. Commit your changes,\n      2. Stash your changes, or\n      3. Set the 'FORCE_DIRTY_WORKTREE' environment variable if you insist on\n         using a dirty worktree\nEOF\n    exit 1\nfi\n\n################\n# Build directories should not exist\n################\n\n# Default to building for all supported HOSTs (overridable by environment)\nexport HOSTS=\"${HOSTS:-x86_64-w64-mingw32 x86_64-apple-darwin arm64-apple-darwin}\"\n\n# Usage: distsrc_for_host HOST\n#\n#   HOST: The current platform triple we're building for\n#\ndistsrc_for_host() {\n    echo \"${DISTSRC_BASE}/distsrc-${VERSION}-${1}-codesigned\"\n}\n\n# Accumulate a list of build directories that already exist...\nhosts_distsrc_exists=\"\"\nfor host in $HOSTS; do\n    if [ -e \"$(distsrc_for_host \"$host\")\" ]; then\n        hosts_distsrc_exists+=\" ${host}\"\n    fi\ndone\n\nif [ -n \"$hosts_distsrc_exists\" ]; then\n# ...so that we can print them out nicely in an error message\ncat << EOF\nERR: Build directories for this commit already exist for the following platform\n     triples you're attempting to build, probably because of previous builds.\n     Please remove, or otherwise deal with them prior to starting another build.\n\n     Aborting...\n\nHint: To blow everything away, you may want to use:\n\n  $ ./contrib/guix/guix-clean\n\nSpecifically, this will remove all files without an entry in the index,\nexcluding the SDK directory, the depends download cache, the depends built\npackages cache, the garbage collector roots for Guix environments, and the\noutput directory.\nEOF\nfor host in $hosts_distsrc_exists; do\n    echo \"     ${host} '$(distsrc_for_host \"$host\")'\"\ndone\nexit 1\nelse\n    mkdir -p \"$DISTSRC_BASE\"\nfi\n\n\n################\n# Unsigned tarballs SHOULD exist\n################\n\n# Usage: outdir_for_host HOST SUFFIX\n#\n#   HOST: The current platform triple we're building for\n#\noutdir_for_host() {\n    echo \"${OUTDIR_BASE}/${1}${2:+-${2}}\"\n}\n\n\nunsigned_tarball_for_host() {\n    case \"$1\" in\n        *mingw*)\n            echo \"$(outdir_for_host \"$1\")/${DISTNAME}-win64-unsigned.tar.gz\"\n            ;;\n        *darwin*)\n            echo \"$(outdir_for_host \"$1\")/${DISTNAME}-${1}-unsigned.tar.gz\"\n            ;;\n        *)\n            exit 1\n            ;;\n    esac\n}\n\n# Accumulate a list of build directories that already exist...\nhosts_unsigned_tarball_missing=\"\"\nfor host in $HOSTS; do\n    if [ ! -e \"$(unsigned_tarball_for_host \"$host\")\" ]; then\n        hosts_unsigned_tarball_missing+=\" ${host}\"\n    fi\ndone\n\nif [ -n \"$hosts_unsigned_tarball_missing\" ]; then\n    # ...so that we can print them out nicely in an error message\n    cat << EOF\nERR: Unsigned tarballs do not exist\n...\n\nEOF\nfor host in $hosts_unsigned_tarball_missing; do\n    echo \"     ${host} '$(unsigned_tarball_for_host \"$host\")'\"\ndone\nexit 1\nfi\n\n################\n# Check that we can connect to the guix-daemon\n################\n\ncat << EOF\nChecking that we can connect to the guix-daemon...\n\nHint: If this hangs, you may want to try turning your guix-daemon off and on\n      again.\n\nEOF\nif ! guix gc --list-failures > /dev/null; then\n    cat << EOF\n\nERR: Failed to connect to the guix-daemon, please ensure that one is running and\n     reachable.\nEOF\n    exit 1\nfi\n\n# Developer note: we could use `guix repl` for this check and run:\n#\n#     (import (guix store)) (close-connection (open-connection))\n#\n# However, the internal API is likely to change more than the CLI invocation\n\n\n#########\n# SETUP #\n#########\n\n# Determine the maximum number of jobs to run simultaneously (overridable by\n# environment)\nJOBS=\"${JOBS:-$(nproc)}\"\n\n# Determine the reference time used for determinism (overridable by environment)\nSOURCE_DATE_EPOCH=\"${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --format=%at -1)}\"\n\n# Make sure an output directory exists for our builds\nOUTDIR_BASE=\"${OUTDIR_BASE:-${VERSION_BASE}/output}\"\nmkdir -p \"$OUTDIR_BASE\"\n\n# Usage: profiledir_for_host HOST SUFFIX\n#\n#   HOST: The current platform triple we're building for\n#\nprofiledir_for_host() {\n    echo \"${PROFILES_BASE}/${1}${2:+-${2}}\"\n}\n\n#########\n# BUILD #\n#########\n\n# Function to be called when codesigning for host ${1} and the user interrupts\n# the codesign\nint_trap() {\ncat << EOF\n** INT received while codesigning ${1}, you may want to clean up the relevant\n   work directories (e.g. distsrc-*) before recodesigning\n\nHint: To blow everything away, you may want to use:\n\n  $ ./contrib/guix/guix-clean\n\nSpecifically, this will remove all files without an entry in the index,\nexcluding the SDK directory, the depends download cache, the depends built\npackages cache, the garbage collector roots for Guix environments, and the\noutput directory.\nEOF\n}\n\n# Deterministically build Munt\n# shellcheck disable=SC2153\nfor host in $HOSTS; do\n\n    # Display proper warning when the user interrupts the build\n    trap 'int_trap ${host}' INT\n\n    (\n        # Required for 'contrib/guix/manifest.scm' to output the right manifest\n        # for the particular $HOST we're building for\n        export HOST=\"$host\"\n\n        # shellcheck disable=SC2030\ncat << EOF\nINFO: Codesigning ${VERSION:?not set} for platform triple ${HOST:?not set}:\n      ...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}\n      ...from worktree directory: '${PWD}'\n          ...bind-mounted in container to: '/munt'\n      ...in build directory: '$(distsrc_for_host \"$HOST\")'\n          ...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host \"$HOST\")'\n      ...outputting in: '$(outdir_for_host \"$HOST\" codesigned)'\n          ...bind-mounted in container to: '$(OUTDIR_BASE=/outdir-base && outdir_for_host \"$HOST\" codesigned)'\n      ...using detached signatures in: '${DETACHED_SIGS_REPO:?not set}'\n          ...bind-mounted in container to: '/detached-sigs'\nEOF\n\n\n        # Run the build script 'contrib/guix/libexec/build.sh' in the build\n        # container specified by 'contrib/guix/manifest.scm'.\n        #\n        # Explanation of `guix environment` flags:\n        #\n        #   --container        run command within an isolated container\n        #\n        #     Running in an isolated container minimizes build-time differences\n        #     between machines and improves reproducibility\n        #\n        #   --pure             unset existing environment variables\n        #\n        #     Same rationale as --container\n        #\n        #   --no-cwd           do not share current working directory with an\n        #                      isolated container\n        #\n        #     When --container is specified, the default behavior is to share\n        #     the current working directory with the isolated container at the\n        #     same exact path (e.g. mapping '/home/satoshi/munt/' to\n        #     '/home/satoshi/munt/'). This means that the $PWD inside the\n        #     container becomes a source of irreproducibility. --no-cwd disables\n        #     this behaviour.\n        #\n        #   --share=SPEC       for containers, share writable host file system\n        #                      according to SPEC\n        #\n        #   --share=\"$PWD\"=/munt\n        #\n        #                     maps our current working directory to /munt\n        #                     inside the isolated container, which we later cd\n        #                     into.\n        #\n        #     While we don't want to map our current working directory to the\n        #     same exact path (as this introduces irreproducibility), we do want\n        #     it to be at a _fixed_ path _somewhere_ inside the isolated\n        #     container so that we have something to build. '/munt' was\n        #     chosen arbitrarily.\n        #\n        #   ${SOURCES_PATH:+--share=\"$SOURCES_PATH\"}\n        #\n        #                     make the downloaded depends sources path available\n        #                     inside the isolated container\n        #\n        #     The isolated container has no network access as it's in a\n        #     different network namespace from the main machine, so we have to\n        #     make the downloaded depends sources available to it. The sources\n        #     should have been downloaded prior to this invocation.\n        #\n        #  ${SUBSTITUTE_URLS:+--substitute-urls=\"$SUBSTITUTE_URLS\"}\n        #\n        #                     fetch substitute from SUBSTITUTE_URLS if they are\n        #                     authorized\n        #\n        #    Depending on the user's security model, it may be desirable to use\n        #    substitutes (pre-built packages) from servers that the user trusts.\n        #    Please read the README.md in the same directory as this file for\n        #    more information.\n        #\n        # shellcheck disable=SC2086,SC2031\n        time-machine environment --manifest=\"${PWD}/contrib/guix/manifest.scm\" \\\n                                 --container \\\n                                 --pure \\\n                                 --no-cwd \\\n                                 --share=\"$PWD\"=/munt \\\n                                 --share=\"$DISTSRC_BASE\"=/distsrc-base \\\n                                 --share=\"$OUTDIR_BASE\"=/outdir-base \\\n                                 --share=\"$DETACHED_SIGS_REPO\"=/detached-sigs \\\n                                 --expose=\"$(git rev-parse --git-common-dir)\" \\\n                                 --expose=\"$(git -C \"$DETACHED_SIGS_REPO\" rev-parse --git-common-dir)\" \\\n                                 ${SOURCES_PATH:+--share=\"$SOURCES_PATH\"} \\\n                                 --cores=\"$JOBS\" \\\n                                 --keep-failed \\\n                                 --fallback \\\n                                 --link-profile \\\n                                 --root=\"$(profiledir_for_host \"${HOST}\" codesigned)\" \\\n                                 ${SUBSTITUTE_URLS:+--substitute-urls=\"$SUBSTITUTE_URLS\"} \\\n                                 ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \\\n                                 -- env HOST=\"$host\" \\\n                                        DISTNAME=\"$DISTNAME\" \\\n                                        JOBS=\"$JOBS\" \\\n                                        SOURCE_DATE_EPOCH=\"${SOURCE_DATE_EPOCH:?unable to determine value}\" \\\n                                        ${V:+V=1} \\\n                                        ${SOURCES_PATH:+SOURCES_PATH=\"$SOURCES_PATH\"} \\\n                                        DISTSRC=\"$(DISTSRC_BASE=/distsrc-base && distsrc_for_host \"$HOST\")\" \\\n                                        OUTDIR=\"$(OUTDIR_BASE=/outdir-base && outdir_for_host \"$HOST\" codesigned)\" \\\n                                        DIST_ARCHIVE_BASE=/outdir-base/dist-archive \\\n                                        DETACHED_SIGS_REPO=/detached-sigs \\\n                                        UNSIGNED_TARBALL=\"$(OUTDIR_BASE=/outdir-base && unsigned_tarball_for_host \"$HOST\")\" \\\n                                      bash -c \"cd /munt && bash contrib/guix/libexec/codesign.sh\"\n    )\n\ndone\n"
  },
  {
    "path": "contrib/guix/guix-verify",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# Source the common prelude, which:\n#   1. Checks if we're at the top directory of the repository\n#   2. Defines a few common functions and variables\n#\n# shellcheck source=libexec/prelude.bash\nsource \"$(dirname \"${BASH_SOURCE[0]}\")/libexec/prelude.bash\"\n\n\n###################\n## Sanity Checks ##\n###################\n\n################\n# Required non-builtin commands should be invokable\n################\n\ncheck_tools cat diff gpg\n\n################\n# Required env vars should be non-empty\n################\n\ncmd_usage() {\ncat <<EOF\nSynopsis:\n\n    env GUIX_SIGS_REPO=<path/to/guix.sigs> [ SIGNER=<signer> ] ./contrib/guix/guix-verify\n\nExample overriding signer's manifest to use as base\n\n    env GUIX_SIGS_REPO=/home/dongcarl/guix.sigs SIGNER=achow101 ./contrib/guix/guix-verify\n\nEOF\n}\n\nif [ -z \"$GUIX_SIGS_REPO\" ]; then\n    cmd_usage\n    exit 1\nfi\n\n################\n# GUIX_SIGS_REPO should exist as a directory\n################\n\nif [ ! -d \"$GUIX_SIGS_REPO\" ]; then\ncat << EOF\nERR: The specified GUIX_SIGS_REPO is not an existent directory:\n\n    '$GUIX_SIGS_REPO'\n\nHint: Please clone the guix.sigs repository and point to it with the\n      GUIX_SIGS_REPO environment variable.\n\nEOF\ncmd_usage\nexit 1\nfi\n\n##############\n##  Verify  ##\n##############\n\nOUTSIGDIR_BASE=\"${GUIX_SIGS_REPO}/${VERSION}\"\necho \"Looking for signature directories in '${OUTSIGDIR_BASE}'\"\necho \"\"\n\n# Usage: verify compare_manifest current_manifest\nverify() {\n    local compare_manifest=\"$1\"\n    local current_manifest=\"$2\"\n    if ! gpg --quiet --batch --verify \"$current_manifest\".asc \"$current_manifest\" 1>&2; then\n        echo \"ERR: Failed to verify GPG signature in '${current_manifest}'\"\n        echo \"\"\n        echo \"Hint: Either the signature is invalid or the public key is missing\"\n        echo \"\"\n        failure=1\n    elif ! diff --report-identical \"$compare_manifest\" \"$current_manifest\" 1>&2; then\n        echo \"ERR: The SHA256SUMS attestation in these two directories differ:\"\n        echo \"    '${compare_manifest}'\"\n        echo \"    '${current_manifest}'\"\n        echo \"\"\n        failure=1\n    else\n        echo \"Verified: '${current_manifest}'\"\n        echo \"\"\n    fi\n}\n\nshopt -s nullglob\nall_noncodesigned=( \"$OUTSIGDIR_BASE\"/*/noncodesigned.SHA256SUMS )\nshopt -u nullglob\n\necho \"--------------------\"\necho \"\"\nif (( ${#all_noncodesigned[@]} )); then\n    compare_noncodesigned=\"${all_noncodesigned[0]}\"\n    if [[ -n \"$SIGNER\" ]]; then\n        signer_noncodesigned=\"$OUTSIGDIR_BASE/$SIGNER/noncodesigned.SHA256SUMS\"\n        if [[ -f \"$signer_noncodesigned\" ]]; then\n            echo \"Using $SIGNER's manifest as the base to compare against\"\n            compare_noncodesigned=\"$signer_noncodesigned\"\n        else\n            echo \"Unable to find $SIGNER's manifest, using the first one found\"\n        fi\n    else\n        echo \"No SIGNER provided, using the first manifest found\"\n    fi\n\n    for current_manifest in \"${all_noncodesigned[@]}\"; do\n        verify \"$compare_noncodesigned\" \"$current_manifest\"\n    done\n\n    echo \"DONE: Checking output signatures for noncodesigned.SHA256SUMS\"\n    echo \"\"\nelse\n    echo \"WARN: No signature directories with noncodesigned.SHA256SUMS found\"\n    echo \"\"\nfi\n\nshopt -s nullglob\nall_all=( \"$OUTSIGDIR_BASE\"/*/all.SHA256SUMS )\nshopt -u nullglob\n\necho \"--------------------\"\necho \"\"\nif (( ${#all_all[@]} )); then\n    compare_all=\"${all_all[0]}\"\n    if [[ -n \"$SIGNER\" ]]; then\n        signer_all=\"$OUTSIGDIR_BASE/$SIGNER/all.SHA256SUMS\"\n        if [[ -f \"$signer_all\" ]]; then\n            echo \"Using $SIGNER's manifest as the base to compare against\"\n            compare_all=\"$signer_all\"\n        else\n            echo \"Unable to find $SIGNER's manifest, using the first one found\"\n        fi\n    else\n        echo \"No SIGNER provided, using the first manifest found\"\n    fi\n\n    for current_manifest in \"${all_all[@]}\"; do\n        verify \"$compare_all\" \"$current_manifest\"\n    done\n\n    # Sanity check: there should be no entries that exist in\n    # noncodesigned.SHA256SUMS that doesn't exist in all.SHA256SUMS\n    if [[ \"$(comm -23 <(sort \"$compare_noncodesigned\") <(sort \"$compare_all\") | wc -c)\" -ne 0 ]]; then\n        echo \"ERR: There are unique lines in noncodesigned.SHA256SUMS which\"\n        echo \"     do not exist in all.SHA256SUMS, something went very wrong.\"\n        exit 1\n    fi\n\n    echo \"DONE: Checking output signatures for all.SHA256SUMS\"\n    echo \"\"\nelse\n    echo \"WARN: No signature directories with all.SHA256SUMS found\"\n    echo \"\"\nfi\n\necho \"====================\"\necho \"\"\nif (( ${#all_noncodesigned[@]} + ${#all_all[@]} == 0 )); then\n    echo \"ERR: Unable to perform any verifications as no signature directories\"\n    echo \"     were found\"\n    echo \"\"\n    exit 1\nfi\n\nif [ -n \"$failure\" ]; then\n    exit 1\nfi\n"
  },
  {
    "path": "contrib/guix/libexec/build.sh",
    "content": "#!/usr/bin/env bash\n# Copyright (c) 2019-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\nexport LC_ALL=C\nset -e -o pipefail\nexport TZ=UTC\n\n# Although Guix _does_ set umask when building its own packages (in our case,\n# this is all packages in manifest.scm), it does not set it for `guix\n# environment`. It does make sense for at least `guix environment --container`\n# to set umask, so if that change gets merged upstream and we bump the\n# time-machine to a commit which includes the aforementioned change, we can\n# remove this line.\n#\n# This line should be placed before any commands which creates files.\numask 0022\n\nif [ -n \"$V\" ]; then\n    # Print both unexpanded (-v) and expanded (-x) forms of commands as they are\n    # read from this file.\n    set -vx\n    # Set VERBOSE for CMake-based builds\n    export VERBOSE=\"$V\"\nfi\n\n# Check that required environment variables are set\ncat << EOF\nRequired environment variables as seen inside the container:\n    DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set}\n    DISTNAME: ${DISTNAME:?not set}\n    HOST: ${HOST:?not set}\n    SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set}\n    JOBS: ${JOBS:?not set}\n    DISTSRC: ${DISTSRC:?not set}\n    OUTDIR: ${OUTDIR:?not set}\nEOF\n\nACTUAL_OUTDIR=\"${OUTDIR}\"\nOUTDIR=\"${DISTSRC}/output\"\n\n#####################\n# Environment Setup #\n#####################\n\n# The depends folder also serves as a base-prefix for depends packages for\n# $HOSTs after successfully building.\nBASEPREFIX=\"${PWD}/depends\"\n\n# Given a package name and an output name, return the path of that output in our\n# current guix environment\nstore_path() {\n    grep --extended-regexp \"/[^-]{32}-${1}-[^-]+${2:+-${2}}\" \"${GUIX_ENVIRONMENT}/manifest\" \\\n        | head --lines=1 \\\n        | sed --expression='s|^[[:space:]]*\"||' \\\n              --expression='s|\"[[:space:]]*$||'\n}\n\n\n# Set environment variables to point the NATIVE toolchain to the right\n# includes/libs\nNATIVE_GCC=\"$(store_path gcc-toolchain)\"\nNATIVE_GCC_STATIC=\"$(store_path gcc-toolchain static)\"\n\nunset LIBRARY_PATH\nunset CPATH\nunset C_INCLUDE_PATH\nunset CPLUS_INCLUDE_PATH\nunset OBJC_INCLUDE_PATH\nunset OBJCPLUS_INCLUDE_PATH\n\nexport LIBRARY_PATH=\"${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64:${NATIVE_GCC_STATIC}/lib:${NATIVE_GCC_STATIC}/lib64\"\nexport C_INCLUDE_PATH=\"${NATIVE_GCC}/include\"\nexport CPLUS_INCLUDE_PATH=\"${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include\"\nexport OBJC_INCLUDE_PATH=\"${NATIVE_GCC}/include\"\nexport OBJCPLUS_INCLUDE_PATH=\"${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include\"\n\nprepend_to_search_env_var() {\n    export \"${1}=${2}${!1:+:}${!1}\"\n}\n\n# Set environment variables to point the CROSS toolchain to the right\n# includes/libs for $HOST\ncase \"$HOST\" in\n    *mingw*)\n        # Determine output paths to use in CROSS_* environment variables\n        CROSS_GLIBC=\"$(store_path \"mingw-w64-x86_64-winpthreads\")\"\n        CROSS_GCC=\"$(store_path \"gcc-cross-${HOST}\")\"\n        CROSS_GCC_LIB_STORE=\"$(store_path \"gcc-cross-${HOST}\" lib)\"\n        CROSS_GCC_LIBS=( \"${CROSS_GCC_LIB_STORE}/lib/gcc/${HOST}\"/* ) # This expands to an array of directories...\n        CROSS_GCC_LIB=\"${CROSS_GCC_LIBS[0]}\" # ...we just want the first one (there should only be one)\n\n        # The search path ordering is generally:\n        #    1. gcc-related search paths\n        #    2. libc-related search paths\n        #    2. kernel-header-related search paths (not applicable to mingw-w64 hosts)\n        export CROSS_C_INCLUDE_PATH=\"${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include\"\n        export CROSS_CPLUS_INCLUDE_PATH=\"${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}\"\n        export CROSS_LIBRARY_PATH=\"${CROSS_GCC_LIB_STORE}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib\"\n        ;;\n    *darwin*)\n        # The CROSS toolchain for darwin uses the SDK and ignores environment variables.\n        # See depends/hosts/darwin.mk for more details.\n        ;;\n    *linux*)\n        CROSS_GLIBC=\"$(store_path \"glibc-cross-${HOST}\")\"\n        CROSS_GLIBC_STATIC=\"$(store_path \"glibc-cross-${HOST}\" static)\"\n        CROSS_KERNEL=\"$(store_path \"linux-libre-headers-cross-${HOST}\")\"\n        CROSS_GCC=\"$(store_path \"gcc-cross-${HOST}\")\"\n        CROSS_GCC_LIB_STORE=\"$(store_path \"gcc-cross-${HOST}\" lib)\"\n        CROSS_GCC_LIBS=( \"${CROSS_GCC_LIB_STORE}/lib/gcc/${HOST}\"/* ) # This expands to an array of directories...\n        CROSS_GCC_LIB=\"${CROSS_GCC_LIBS[0]}\" # ...we just want the first one (there should only be one)\n\n        export CROSS_C_INCLUDE_PATH=\"${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include\"\n        export CROSS_CPLUS_INCLUDE_PATH=\"${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}\"\n        export CROSS_LIBRARY_PATH=\"${CROSS_GCC_LIB_STORE}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib:${CROSS_GLIBC_STATIC}/lib\"\n        ;;\n    *)\n        exit 1 ;;\nesac\n\n# Sanity check CROSS_*_PATH directories\nIFS=':' read -ra PATHS <<< \"${CROSS_C_INCLUDE_PATH}:${CROSS_CPLUS_INCLUDE_PATH}:${CROSS_LIBRARY_PATH}\"\nfor p in \"${PATHS[@]}\"; do\n    if [ -n \"$p\" ] && [ ! -d \"$p\" ]; then\n        echo \"'$p' doesn't exist or isn't a directory... Aborting...\"\n        exit 1\n    fi\ndone\n\n# Disable Guix ld auto-rpath behavior\ncase \"$HOST\" in\n    *darwin*)\n        # The auto-rpath behavior is necessary for darwin builds as some native\n        # tools built by depends refer to and depend on Guix-built native\n        # libraries\n        #\n        # After the native packages in depends are built, the ld wrapper should\n        # no longer affect our build, as clang would instead reach for\n        # x86_64-apple-darwin-ld from cctools\n        ;;\n    *) export GUIX_LD_WRAPPER_DISABLE_RPATH=yes ;;\nesac\n\n# Make /usr/bin if it doesn't exist\n[ -e /usr/bin ] || mkdir -p /usr/bin\n\n# Symlink file and env to a conventional path\n[ -e /usr/bin/file ] || ln -s --no-dereference \"$(command -v file)\" /usr/bin/file\n[ -e /usr/bin/env ]  || ln -s --no-dereference \"$(command -v env)\"  /usr/bin/env\n\n# Determine the correct value for -Wl,--dynamic-linker for the current $HOST\ncase \"$HOST\" in\n    *linux*)\n        glibc_dynamic_linker=$(\n            case \"$HOST\" in\n                i686-linux-gnu)        echo /lib/ld-linux.so.2 ;;\n                x86_64-linux-gnu)      echo /lib64/ld-linux-x86-64.so.2 ;;\n                arm-linux-gnueabihf)   echo /lib/ld-linux-armhf.so.3 ;;\n                aarch64-linux-gnu)     echo /lib/ld-linux-aarch64.so.1 ;;\n                riscv64-linux-gnu)     echo /lib/ld-linux-riscv64-lp64d.so.1 ;;\n                powerpc64-linux-gnu)   echo /lib64/ld64.so.1;;\n                powerpc64le-linux-gnu) echo /lib64/ld64.so.2;;\n                *)                     exit 1 ;;\n            esac\n        )\n        ;;\nesac\n\n# Environment variables for determinism\nexport TAR_OPTIONS=\"--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name\"\nexport TZ=\"UTC\"\ncase \"$HOST\" in\n    *darwin*)\n        # cctools AR, unlike GNU binutils AR, does not have a deterministic mode\n        # or a configure flag to enable determinism by default, it only\n        # understands if this env-var is set or not. See:\n        #\n        # https://github.com/tpoechtrager/cctools-port/blob/55562e4073dea0fbfd0b20e0bf69ffe6390c7f97/cctools/ar/archive.c#L334\n        export ZERO_AR_DATE=yes\n        ;;\nesac\n\n####################\n# Depends Building #\n####################\n\n# Build the depends tree, overriding variables that assume multilib gcc\nmake -C depends --jobs=\"$JOBS\" HOST=\"$HOST\" \\\n                                   ${V:+V=1} \\\n                                   ${SOURCES_PATH+SOURCES_PATH=\"$SOURCES_PATH\"} \\\n                                   ${BASE_CACHE+BASE_CACHE=\"$BASE_CACHE\"} \\\n                                   ${SDK_PATH+SDK_PATH=\"$SDK_PATH\"} \\\n                                   ${CODESIGN_PATH+CODESIGN_PATH=\"$CODESIGN_PATH\"} \\\n                                   i686_linux_CC=i686-linux-gnu-gcc \\\n                                   i686_linux_CXX=i686-linux-gnu-g++ \\\n                                   i686_linux_AR=i686-linux-gnu-ar \\\n                                   i686_linux_RANLIB=i686-linux-gnu-ranlib \\\n                                   i686_linux_NM=i686-linux-gnu-nm \\\n                                   i686_linux_STRIP=i686-linux-gnu-strip \\\n                                   x86_64_linux_CC=x86_64-linux-gnu-gcc \\\n                                   x86_64_linux_CXX=x86_64-linux-gnu-g++ \\\n                                   x86_64_linux_AR=x86_64-linux-gnu-ar \\\n                                   x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \\\n                                   x86_64_linux_NM=x86_64-linux-gnu-nm \\\n                                   x86_64_linux_STRIP=x86_64-linux-gnu-strip \\\n                                   FORCE_USE_SYSTEM_CLANG=1 \\\n                                   EXTRA_PACKAGES='node_addon_api electron_node_headers'\n\n\n###########################\n# Source Tarball Building #\n###########################\n\nGIT_ARCHIVE=\"${DIST_ARCHIVE_BASE}/${DISTNAME}.tar.gz\"\n\n# Create the source tarball if not already there\nif [ ! -e \"$GIT_ARCHIVE\" ]; then\n    mkdir -p \"$(dirname \"$GIT_ARCHIVE\")\"\n    git archive --prefix=\"${DISTNAME}/\" --output=\"$GIT_ARCHIVE\" HEAD\nfi\n\nmkdir -p \"$OUTDIR\"\n\n###########################\n# Binary Tarball Building #\n###########################\n\n# CONFIGFLAGS\nCONFIGFLAGS=\"--enable-reduce-exports --disable-bench --disable-gui-tests --disable-fuzz-binary --disable-man --enable-zmq --with-node-js-libs --with-qrencode\"\n\n# CFLAGS\nHOST_CFLAGS=\"-O2 -g\"\nHOST_CFLAGS+=$(find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n \" -ffile-prefix-map={}=/usr\" \\;)\ncase \"$HOST\" in\n    *linux*)  HOST_CFLAGS+=\" -ffile-prefix-map=${PWD}=.\" ;;\n    *mingw*)\n        HOST_CFLAGS+=\" -fno-ident\"\n        # Hardening currently breaks mingw builds because it pulls libssp in as a dep; even though this isn't meant to happen (gcc is meant to be providing these symbols)\n        # disable for now until we can investigate further\n        CONFIGFLAGS+=\" --disable-hardening \"\n    ;;\n    *darwin*) unset HOST_CFLAGS ;;\nesac\n\n# CXXFLAGS\nHOST_CXXFLAGS=\"$HOST_CFLAGS\"\n\ncase \"$HOST\" in\n    arm-linux-gnueabihf) HOST_CXXFLAGS=\"${HOST_CXXFLAGS} -Wno-psabi\" ;;\nesac\n\n# LDFLAGS\ncase \"$HOST\" in\n# static libstdc++ is giving is undefined symbol issues when using our lib with the latest electron, so remove it for now, but this should be investigated further.\n#    *linux*)  HOST_LDFLAGS=\"-Wl,--as-needed -Wl,--dynamic-linker=$glibc_dynamic_linker -static-libstdc++ -Wl,-O2\" ;;\n    *linux*)  HOST_LDFLAGS=\"-Wl,--as-needed -Wl,--dynamic-linker=$glibc_dynamic_linker -lstdc++ -Wl,-O3\" ;;\n    *mingw*)  HOST_LDFLAGS=\"-Wl,--no-insert-timestamp\" ;;\nesac\n\n# Using --no-tls-get-addr-optimize retains compatibility with glibc 2.18, by\n# avoiding a PowerPC64 optimisation available in glibc 2.22 and later.\n# https://sourceware.org/binutils/docs-2.35/ld/PowerPC64-ELF64.html\ncase \"$HOST\" in\n    *powerpc64*) HOST_LDFLAGS=\"${HOST_LDFLAGS} -Wl,--no-tls-get-addr-optimize\" ;;\nesac\n\ncase \"$HOST\" in\n    powerpc64-linux-*|riscv64-linux-*) HOST_LDFLAGS=\"${HOST_LDFLAGS} -Wl,-z,noexecstack\" ;;\nesac\n\n# Make $HOST-specific native binaries from depends available in $PATH\nexport PATH=\"${BASEPREFIX}/${HOST}/native/bin:${PATH}\"\nmkdir -p \"$DISTSRC\"\n(\n    cd \"$DISTSRC\"\n\n    # Extract the source tarball\n    tar --strip-components=1 -xf \"${GIT_ARCHIVE}\"\n\n    case \"$HOST\" in\n        *mingw*)\n            export HOST_CXXFLAGS=\"${HOST_CXXFLAGS} -I/munt/depends/${HOST}/include/node -I/munt/depends/${HOST}/include/node-addon-api -fPIC -fdata-sections -ffunction-sections -fomit-frame-pointer -DNAPI_VERSION=5 -DDJINNI_NODEJS -DNODE_HOST_BINARY=node.exe -DUSING_UV_SHARED=1 -DUSING_V8_SHARED=1 -DV8_DEPRECATION_WARNINGS=1 -DV8_DEPRECATION_WARNINGS -DV8_IMMINENT_DEPRECATION_WARNINGS -DWIN32 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DBUILDING_NODE_EXTENSION -D_WINDLL -lminiupnpc\"\n            export HOST_LDFLAGS=\"${HOST_LDFLAGS} -fPIC -Bsymbolic -lnode -Wl,--gc-sections\"\n        ;;\n        *darwin*)\n            export HOST_CXXFLAGS=\"${HOST_CXXFLAGS} -I/munt/depends/${HOST}/include/node -I/munt/depends/${HOST}/include/node-addon-api -fPIC -fdata-sections -ffunction-sections -fomit-frame-pointer -DNAPI_VERSION=5 -DDJINNI_NODEJS -D_HAS_EXCEPTIONS=1\"\n            export HOST_LDFLAGS=\"${HOST_LDFLAGS} -fPIC -Bsymbolic -Wl,-undefined -Wl,dynamic_lookup\"\n        ;;\n        *linux*)\n            export HOST_CXXFLAGS=\"${HOST_CXXFLAGS} -I/munt/depends/${HOST}/include/node -I/munt/depends/${HOST}/include/node-addon-api -fPIC -fdata-sections -ffunction-sections -fomit-frame-pointer -DNAPI_VERSION=5 -DDJINNI_NODEJS -lminiupnpc\"\n            export HOST_LDFLAGS=\"${HOST_LDFLAGS} -fPIC -Bsymbolic -Wl,--gc-sections\"\n        ;;\n    esac\n    export HOST_CFLAGS=${HOST_CFLAGS}\n    #end electron specific setup\n\n    ./autogen.sh\n\n    # Configure this DISTSRC for $HOST\n    # shellcheck disable=SC2086\n    env CONFIG_SITE=\"${BASEPREFIX}/${HOST}/share/config.site\" \\\n        ./configure --prefix=/ \\\n                    --disable-ccache \\\n                    --disable-maintainer-mode \\\n                    --disable-dependency-tracking \\\n                    --with-protoc-bindir=/munt/depends/${HOST}/native/bin/ \\\n                    ${CONFIGFLAGS} \\\n                    ${HOST_CFLAGS:+CFLAGS=\"${HOST_CFLAGS}\"} \\\n                    ${HOST_CXXFLAGS:+CXXFLAGS=\"${HOST_CXXFLAGS}\"} \\\n                    ${HOST_LDFLAGS:+LDFLAGS=\"${HOST_LDFLAGS}\"}\n\n    sed -i.old 's/-lstdc++ //g' config.status libtool\n\n    # Build Munt\n    make --jobs=\"$JOBS\" ${V:+V=1}\n\n    # Check that symbol/security checks tools are sane.\n    #make test-security-check ${V:+V=1}\n    # Perform basic security checks on a series of executables.\n    make -C src --jobs=1 check-security ${V:+V=1}\n    # Check that executables only contain allowed version symbols.\n    make -C src --jobs=1 check-symbols  ${V:+V=1}\n\n    mkdir -p \"$OUTDIR\"\n\n    #fixme: We do some duplicate work here (split debug symbols and sign then later do this again); we should improve the process so its only done once.\n    case \"$HOST\" in\n        *mingw*)\n            # Move executables into release folder\n            mkdir release\n            find . -name \"*.exe\" | xargs --max-procs 32 -i cp {} release/\n            # Split debug symbols\n            find \"release\" -type f -executable -print0 | xargs -0 -P\"$JOBS\" -I{} \"${DISTSRC}/contrib/devtools/split-debug.sh\" {} {} {}.dbg\n            #Sign all executables\n            find release -name \"*.exe\" | xargs --max-procs 32 -i sh -c \"(osslsigncode -spc \\\"${CODESIGN_PATH}/codesign.spc\\\" -key \\\"${CODESIGN_PATH}/codesign.key\\\" -n \\\"Munt\\\" -i \\\"https://www.Munt.org\\\" -in \\\"{}\\\" -out \\\"{}s\\\") && (mv {}s {})\"\n            # Make os-specific installer\n            make deploy ${V:+V=1}\n            # Sign the installer as well; place result in output folder\n            find -name \"*setup*.exe\" | xargs -i sh -c \"(osslsigncode -spc \\\"${CODESIGN_PATH}/codesign.spc\\\" -key \\\"${CODESIGN_PATH}/codesign.key\\\" -n \\\"Munt\\\" -i \\\"https://www.Munt.org\\\" -in \\\"{}\\\" -out \\\"${OUTDIR}/${DISTNAME}-win64-setup.exe\\\")\"\n            ;;\n    esac\n\n    # Setup the directory where our Munt build for HOST will be\n    # installed. This directory will also later serve as the input for our\n    # binary tarballs.\n    INSTALLPATH=\"${PWD}/installed/${DISTNAME}\"\n    mkdir -p \"${INSTALLPATH}\"\n    # Install built Munt to $INSTALLPATH\n    case \"$HOST\" in\n        *darwin*)\n            make install-strip DESTDIR=\"${INSTALLPATH}\" ${V:+V=1}\n            ;;\n        *)\n            make install DESTDIR=\"${INSTALLPATH}\" ${V:+V=1}\n            ;;\n    esac\n\n    mkdir ${OUTDIR}/nodelib\n    case \"$HOST\" in\n        *mingw*)\n            cp -f src/.libs/lib_unity_node_js-0.dll ${OUTDIR}/nodelib/libmunt_${HOST}.node\n        ;;\n        *darwin*)\n            cp -f src/.libs/lib_unity_node_js.0.so ${OUTDIR}/nodelib/libmunt_${HOST}.node\n        ;;\n        *)\n            cp -f src/.libs/lib_unity_node_js.so.0.0.0 ${OUTDIR}/nodelib/libmunt_${HOST}.node\n    esac\n\n    #darwin builds choke one split-debug.sh script, but other platforms need to run it or we have giant binaries to deal with\n    #run for every platform except darwin for now until we can make this work also on darwin\n    case \"$HOST\" in\n        *darwin*) ;;\n        *)\n            ${DISTSRC}/contrib/devtools/split-debug.sh ${OUTDIR}/nodelib/libmunt_${HOST}.node ${OUTDIR}/nodelib/libmunt_${HOST}.node ${OUTDIR}/nodelib/libmunt_${HOST}.node.dbg\n    esac\n\n    (\n        cd installed\n\n        # Prune libtool and object archives\n        find . -name \"lib*.la\" -delete\n        find . -name \"lib*.a\" -delete\n\n        # Prune pkg-config files\n        rm -rf \"${DISTNAME}/lib/pkgconfig\"\n\n        case \"$HOST\" in\n            *darwin*) ;;\n            *)\n                # Split binaries and libraries from their debug symbols\n                {\n                    find \"${DISTNAME}/bin\" -type f -executable -print0\n                    if [ -d ${DISTNAME}/lib ]; then\n                      find \"${DISTNAME}/lib\" -type f -print0\n                    fi\n                } | xargs -0 -P\"$JOBS\" -I{} \"${DISTSRC}/contrib/devtools/split-debug.sh\" {} {} {}.dbg\n        esac\n\n        # Sign binaries after debug symbols split\n        case \"$HOST\" in\n        *mingw*)\n            find \"${DISTNAME}/bin\" -name \"*.exe\" | xargs --max-procs 32 -i sh -c \"(osslsigncode -spc \\\"${CODESIGN_PATH}/codesign.spc\\\" -key \\\"${CODESIGN_PATH}/codesign.key\\\" -n \\\"Munt\\\" -i \\\"https://www.Munt.org\\\" -in \\\"{}\\\" -out \\\"{}s\\\") && (mv {}s {})\"\n            ;;\n        esac\n\n        # Finally, deterministically produce {non-,}debug binary tarballs ready\n        # for release\n        case \"$HOST\" in\n            *mingw*)\n                find \"${DISTNAME}\" -not -name \"*.dbg\" -print0 \\\n                    | xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\n                find \"${DISTNAME}\" -not -name \"*.dbg\" \\\n                    | sort \\\n                    | zip -X@ \"${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip\" \\\n                    || ( rm -f \"${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip\" && exit 1 )\n                find \"${DISTNAME}\" -name \"*.dbg\" -print0 \\\n                    | xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\n                find \"${DISTNAME}\" -name \"*.dbg\" \\\n                    | sort \\\n                    | zip -X@ \"${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-debug.zip\" \\\n                    || ( rm -f \"${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-debug.zip\" && exit 1 )\n                ;;\n            *linux*)\n                find \"${DISTNAME}\" -not -name \"*.dbg\" -print0 \\\n                    | sort --zero-terminated \\\n                    | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \\\n                    | pigz -9n > \"${OUTDIR}/${DISTNAME}-${HOST}.tar.gz\" \\\n                    || ( rm -f \"${OUTDIR}/${DISTNAME}-${HOST}.tar.gz\" && exit 1 )\n                find \"${DISTNAME}\" -name \"*.dbg\" -print0 \\\n                    | sort --zero-terminated \\\n                    | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \\\n                    | pigz -9n > \"${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz\" \\\n                    || ( rm -f \"${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz\" && exit 1 )\n                ;;\n            *darwin*)\n                find \"${DISTNAME}\" -print0 \\\n                    | sort --zero-terminated \\\n                    | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \\\n                    | pigz -9n > \"${OUTDIR}/${DISTNAME}-${HOST}.tar.gz\" \\\n                    || ( rm -f \"${OUTDIR}/${DISTNAME}-${HOST}.tar.gz\" && exit 1 )\n                ;;\n        esac\n    )  # $DISTSRC/installed\n)  # $DISTSRC\n\nrm -rf \"$ACTUAL_OUTDIR\"\nmv --no-target-directory \"$OUTDIR\" \"$ACTUAL_OUTDIR\" \\\n    || ( rm -rf \"$ACTUAL_OUTDIR\" && exit 1 )\n\n(\n    cd /outdir-base\n    {\n        echo \"$GIT_ARCHIVE\"\n        find \"$ACTUAL_OUTDIR\" -type f\n    } | xargs realpath --relative-base=\"$PWD\" \\\n      | xargs sha256sum \\\n      | sort -k2 \\\n      | sponge \"$ACTUAL_OUTDIR\"/SHA256SUMS.part\n)\n"
  },
  {
    "path": "contrib/guix/libexec/codesign.sh",
    "content": "#!/usr/bin/env bash\n# Copyright (c) 2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\nexport LC_ALL=C\nset -e -o pipefail\nexport TZ=UTC\n\n# Although Guix _does_ set umask when building its own packages (in our case,\n# this is all packages in manifest.scm), it does not set it for `guix\n# environment`. It does make sense for at least `guix environment --container`\n# to set umask, so if that change gets merged upstream and we bump the\n# time-machine to a commit which includes the aforementioned change, we can\n# remove this line.\n#\n# This line should be placed before any commands which creates files.\numask 0022\n\nif [ -n \"$V\" ]; then\n    # Print both unexpanded (-v) and expanded (-x) forms of commands as they are\n    # read from this file.\n    set -vx\n    # Set VERBOSE for CMake-based builds\n    export VERBOSE=\"$V\"\nfi\n\n# Check that required environment variables are set\ncat << EOF\nRequired environment variables as seen inside the container:\n    UNSIGNED_TARBALL: ${UNSIGNED_TARBALL:?not set}\n    DETACHED_SIGS_REPO: ${DETACHED_SIGS_REPO:?not set}\n    DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set}\n    DISTNAME: ${DISTNAME:?not set}\n    HOST: ${HOST:?not set}\n    SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set}\n    DISTSRC: ${DISTSRC:?not set}\n    OUTDIR: ${OUTDIR:?not set}\nEOF\n\nACTUAL_OUTDIR=\"${OUTDIR}\"\nOUTDIR=\"${DISTSRC}/output\"\n\ngit_head_version() {\n    local recent_tag\n    if recent_tag=\"$(git -C \"$1\" describe --exact-match HEAD 2> /dev/null)\"; then\n        echo \"${recent_tag#v}\"\n    else\n        git -C \"$1\" rev-parse --short=12 HEAD\n    fi\n}\n\nCODESIGNATURE_GIT_ARCHIVE=\"${DIST_ARCHIVE_BASE}/${DISTNAME}-codesignatures-$(git_head_version \"$DETACHED_SIGS_REPO\").tar.gz\"\n\n# Create the codesignature tarball if not already there\nif [ ! -e \"$CODESIGNATURE_GIT_ARCHIVE\" ]; then\n    mkdir -p \"$(dirname \"$CODESIGNATURE_GIT_ARCHIVE\")\"\n    git -C \"$DETACHED_SIGS_REPO\" archive --output=\"$CODESIGNATURE_GIT_ARCHIVE\" HEAD\nfi\n\nmkdir -p \"$OUTDIR\"\n\nmkdir -p \"$DISTSRC\"\n(\n    cd \"$DISTSRC\"\n\n    tar -xf \"$UNSIGNED_TARBALL\"\n\n    mkdir -p codesignatures\n    tar -C codesignatures -xf \"$CODESIGNATURE_GIT_ARCHIVE\"\n\n    case \"$HOST\" in\n        *mingw*)\n            find \"$PWD\" -name \"*-unsigned.exe\" | while read -r infile; do\n                infile_base=\"$(basename \"$infile\")\"\n\n                # Codesigned *-unsigned.exe and output to OUTDIR\n                osslsigncode attach-signature \\\n                                 -in \"$infile\" \\\n                                 -out \"${OUTDIR}/${infile_base/-unsigned}\" \\\n                                 -sigin codesignatures/win/\"$infile_base\".pem\n            done\n            ;;\n        *darwin*)\n            # Apply detached codesignatures to dist/ (in-place)\n            signapple apply dist/Munt-Qt.app codesignatures/osx/dist\n\n            # Make an uncompressed DMG from dist/\n            xorrisofs -D -l -V \"$(< osx_volname)\" -no-pad -r -dir-mode 0755 \\\n                      -o uncompressed.dmg \\\n                      dist \\\n                      -- -volume_date all_file_dates =\"$SOURCE_DATE_EPOCH\"\n\n            # Compress uncompressed.dmg and output to OUTDIR\n            ./dmg dmg uncompressed.dmg \"${OUTDIR}/${DISTNAME}-${HOST}.dmg\"\n            ;;\n        *)\n            exit 1\n            ;;\n    esac\n)  # $DISTSRC\n\nrm -rf \"$ACTUAL_OUTDIR\"\nmv --no-target-directory \"$OUTDIR\" \"$ACTUAL_OUTDIR\" \\\n    || ( rm -rf \"$ACTUAL_OUTDIR\" && exit 1 )\n\n(\n    cd /outdir-base\n    {\n        echo \"$UNSIGNED_TARBALL\"\n        echo \"$CODESIGNATURE_GIT_ARCHIVE\"\n        find \"$ACTUAL_OUTDIR\" -type f\n    } | xargs realpath --relative-base=\"$PWD\" \\\n        | xargs sha256sum \\\n        | sort -k2 \\\n        | sponge \"$ACTUAL_OUTDIR\"/SHA256SUMS.part\n)\n"
  },
  {
    "path": "contrib/guix/libexec/prelude.bash",
    "content": "#!/usr/bin/env bash\nexport LC_ALL=C\nset -e -o pipefail\n\n# shellcheck source=contrib/shell/realpath.bash\nsource contrib/shell/realpath.bash\n\n# shellcheck source=contrib/shell/git-utils.bash\nsource contrib/shell/git-utils.bash\n\n################\n# Required non-builtin commands should be invocable\n################\n\ncheck_tools() {\n    for cmd in \"$@\"; do\n        if ! command -v \"$cmd\" > /dev/null 2>&1; then\n            echo \"ERR: This script requires that '$cmd' is installed and available in your \\$PATH\"\n            exit 1\n        fi\n    done\n}\n\ncheck_tools cat env readlink dirname basename git\n\n################\n# We should be at the top directory of the repository\n################\n\nsame_dir() {\n    local resolved1 resolved2\n    resolved1=\"$(bash_realpath \"${1}\")\"\n    resolved2=\"$(bash_realpath \"${2}\")\"\n    [ \"$resolved1\" = \"$resolved2\" ]\n}\n\nif ! same_dir \"${PWD}\" \"$(git_root)\"; then\ncat << EOF\nERR: This script must be invoked from the top level of the git repository\n\nHint: This may look something like:\n    env FOO=BAR ./contrib/guix/guix-<blah>\n\nEOF\nexit 1\nfi\n\n################\n# Execute \"$@\" in a pinned, possibly older version of Guix, for reproducibility\n# across time.\ntime-machine() {\n    # shellcheck disable=SC2086\n    guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \\\n                      --commit=998eda3067c7d21e0d9bb3310d2f5a14b8f1c681 \\\n                      --cores=\"$JOBS\" \\\n                      --keep-failed \\\n                      --fallback \\\n                      ${SUBSTITUTE_URLS:+--substitute-urls=\"$SUBSTITUTE_URLS\"} \\\n                      ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_TIMEMACHINE_FLAGS} \\\n                      -- \"$@\"\n}\n\n\n################\n# Set common variables\n################\n\nVERSION=\"${FORCE_VERSION:-$(git_head_version)}\"\nDISTNAME=\"${DISTNAME:-munt-${VERSION}}\"\n\nversion_base_prefix=\"${PWD}/guix-build-\"\nVERSION_BASE=\"${version_base_prefix}${VERSION}\"  # TOP\n\nDISTSRC_BASE=\"${DISTSRC_BASE:-${VERSION_BASE}}\"\n\nOUTDIR_BASE=\"${OUTDIR_BASE:-${VERSION_BASE}/output}\"\n\nvar_base_basename=\"var\"\nVAR_BASE=\"${VAR_BASE:-${VERSION_BASE}/${var_base_basename}}\"\n\nprofiles_base_basename=\"profiles\"\nPROFILES_BASE=\"${PROFILES_BASE:-${VAR_BASE}/${profiles_base_basename}}\"\n"
  },
  {
    "path": "contrib/guix/manifest.scm",
    "content": "(use-modules (gnu)\n             (gnu packages)\n             (gnu packages autotools)\n             (gnu packages base)\n             (gnu packages bash)\n             (gnu packages bison)\n             (gnu packages certs)\n             (gnu packages cdrom)\n             (gnu packages check)\n             (gnu packages cmake)\n             (gnu packages commencement)\n             (gnu packages compression)\n             (gnu packages cross-base)\n             (gnu packages curl)\n             (gnu packages file)\n             (gnu packages gawk)\n             (gnu packages gcc)\n             (gnu packages gnome)\n             (gnu packages installers)\n             (gnu packages linux)\n             (gnu packages llvm)\n             (gnu packages mingw)\n             (gnu packages moreutils)\n             (gnu packages perl)\n             (gnu packages pkg-config)\n             (gnu packages python)\n             (gnu packages python-crypto)\n             (gnu packages python-web)\n             (gnu packages shells)\n             (gnu packages tls)\n             (gnu packages version-control)\n             (guix build-system gnu)\n             (guix build-system python)\n             (guix build-system trivial)\n             (guix download)\n             (guix gexp)\n             (guix git-download)\n             ((guix licenses) #:prefix license:)\n             (guix packages)\n             (guix profiles)\n             (guix utils))\n\n(define-syntax-rule (search-our-patches file-name ...)\n  \"Return the list of absolute file names corresponding to each\nFILE-NAME found in ./patches relative to the current file.\"\n  (parameterize\n      ((%patch-path (list (string-append (dirname (current-filename)) \"/patches\"))))\n    (list (search-patch file-name) ...)))\n\n(define (make-ssp-fixed-gcc xgcc)\n  \"Given a XGCC package, return a modified package that uses the SSP function\nfrom glibc instead of from libssp.so. Our `symbol-check' script will complain if\nwe link against libssp.so, and thus will ensure that this works properly.\n\nTaken from:\nhttp://www.linuxfromscratch.org/hlfs/view/development/chapter05/gcc-pass1.html\"\n  (package\n    (inherit xgcc)\n    (arguments\n     (substitute-keyword-arguments (package-arguments xgcc)\n       ((#:make-flags flags)\n        `(cons \"gcc_cv_libc_provides_ssp=yes\" ,flags))))))\n\n(define (make-gcc-rpath-link xgcc)\n  \"Given a XGCC package, return a modified package that replace each instance of\n-rpath in the default system spec that's inserted by Guix with -rpath-link\"\n  (package\n    (inherit xgcc)\n    (arguments\n     (substitute-keyword-arguments (package-arguments xgcc)\n       ((#:phases phases)\n        `(modify-phases ,phases\n           (add-after 'pre-configure 'replace-rpath-with-rpath-link\n             (lambda _\n               (substitute* (cons \"gcc/config/rs6000/sysv4.h\"\n                                  (find-files \"gcc/config\"\n                                              \"^gnu-user.*\\\\.h$\"))\n                 ((\"-rpath=\") \"-rpath-link=\"))\n               #t))))))))\n\n(define building-on (string-append (list-ref (string-split (%current-system) #\\-) 0) \"-guix-linux-gnu\"))\n\n(define (explicit-cross-configure package)\n  (package-with-extra-configure-variable package \"--build\" building-on))\n\n(define (make-cross-toolchain target\n                              base-gcc-for-libc\n                              base-kernel-headers\n                              base-libc\n                              base-gcc)\n  \"Create a cross-compilation toolchain package for TARGET\"\n  (let* ((xbinutils (cross-binutils target))\n         ;; 1. Build a cross-compiling gcc without targeting any libc, derived\n         ;; from BASE-GCC-FOR-LIBC\n         (xgcc-sans-libc (explicit-cross-configure (cross-gcc target\n                                                              #:xgcc base-gcc-for-libc\n                                                              #:xbinutils xbinutils)))\n         ;; 2. Build cross-compiled kernel headers with XGCC-SANS-LIBC, derived\n         ;; from BASE-KERNEL-HEADERS\n         (xkernel (cross-kernel-headers target\n                                        base-kernel-headers\n                                        xgcc-sans-libc\n                                        xbinutils))\n         ;; 3. Build a cross-compiled libc with XGCC-SANS-LIBC and XKERNEL,\n         ;; derived from BASE-LIBC\n         (xlibc (explicit-cross-configure (cross-libc target\n                                                      base-libc\n                                                      xgcc-sans-libc\n                                                      xbinutils\n                                                      xkernel)))\n         ;; 4. Build a cross-compiling gcc targeting XLIBC, derived from\n         ;; BASE-GCC\n         (xgcc (explicit-cross-configure (cross-gcc target\n                                                    #:xgcc base-gcc\n                                                    #:xbinutils xbinutils\n                                                    #:libc xlibc))))\n    ;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and\n    ;; XGCC\n    (package\n      (name (string-append target \"-toolchain\"))\n      (version (package-version xgcc))\n      (source #f)\n      (build-system trivial-build-system)\n      (arguments '(#:builder (begin (mkdir %output) #t)))\n      (propagated-inputs\n       `((\"binutils\" ,xbinutils)\n         (\"libc\" ,xlibc)\n         (\"libc:static\" ,xlibc \"static\")\n         (\"gcc\" ,xgcc)\n         (\"gcc-lib\" ,xgcc \"lib\")))\n      (synopsis (string-append \"Complete GCC tool chain for \" target))\n      (description (string-append \"This package provides a complete GCC tool\nchain for \" target \" development.\"))\n      (home-page (package-home-page xgcc))\n      (license (package-license xgcc)))))\n\n(define base-gcc gcc-10)\n(define base-linux-kernel-headers linux-libre-headers-5.15)\n\n;; https://gcc.gnu.org/install/configure.html\n(define (hardened-gcc gcc)\n  (package-with-extra-configure-variable (\n    package-with-extra-configure-variable gcc\n    \"--enable-default-ssp\" \"yes\")\n    \"--enable-default-pie\" \"yes\"))\n\n(define* (make-munt-cross-toolchain target\n                                       #:key\n                                       (base-gcc-for-libc base-gcc)\n                                       (base-kernel-headers base-linux-kernel-headers)\n                                       (base-libc (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.24)))\n                                       (base-gcc (make-gcc-rpath-link (hardened-gcc base-gcc))))\n  \"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values\ndesirable for building Bitcoin Core release binaries.\"\n  (make-cross-toolchain target\n                        base-gcc-for-libc\n                        base-kernel-headers\n                        base-libc\n                        base-gcc))\n\n(define (make-gcc-with-pthreads gcc)\n  (package-with-extra-configure-variable\n    (package-with-extra-patches gcc\n      (search-our-patches \"gcc-10-remap-guix-store.patch\"))\n    \"--enable-threads\" \"posix\"))\n\n(define (make-mingw-w64-cross-gcc cross-gcc)\n  (package-with-extra-patches cross-gcc\n    (search-our-patches \"vmov-alignment.patch\"\n                        \"gcc-broken-longjmp.patch\")))\n\n(define (make-mingw-pthreads-cross-toolchain target)\n  \"Create a cross-compilation toolchain package for TARGET\"\n  (let* ((xbinutils (cross-binutils target))\n         (pthreads-xlibc mingw-w64-x86_64-winpthreads)\n         (pthreads-xgcc (make-gcc-with-pthreads\n                         (cross-gcc target\n                                    #:xgcc (make-ssp-fixed-gcc (make-mingw-w64-cross-gcc base-gcc))\n                                    #:xbinutils xbinutils\n                                    #:libc pthreads-xlibc))))\n    ;; Define a meta-package that propagates the resulting XBINUTILS, XLIBC, and\n    ;; XGCC\n    (package\n      (name (string-append target \"-posix-toolchain\"))\n      (version (package-version pthreads-xgcc))\n      (source #f)\n      (build-system trivial-build-system)\n      (arguments '(#:builder (begin (mkdir %output) #t)))\n      (propagated-inputs\n       `((\"binutils\" ,xbinutils)\n         (\"libc\" ,pthreads-xlibc)\n         (\"gcc\" ,pthreads-xgcc)\n         (\"gcc-lib\" ,pthreads-xgcc \"lib\")))\n      (synopsis (string-append \"Complete GCC tool chain for \" target))\n      (description (string-append \"This package provides a complete GCC tool\nchain for \" target \" development.\"))\n      (home-page (package-home-page pthreads-xgcc))\n      (license (package-license pthreads-xgcc)))))\n\n(define (make-nsis-for-gcc-10 base-nsis)\n  (package-with-extra-patches base-nsis\n    (search-our-patches \"nsis-gcc-10-memmove.patch\"\n                        \"nsis-disable-installer-reloc.patch\")))\n\n(define (fix-ppc64-nx-default lief)\n  (package-with-extra-patches lief\n    (search-our-patches \"lief-fix-ppc64-nx-default.patch\")))\n\n(define-public lief\n  (package\n   (name \"python-lief\")\n   (version \"0.12.1\")\n   (source\n    (origin\n     (method git-fetch)\n     (uri (git-reference\n           (url \"https://github.com/lief-project/LIEF.git\")\n           (commit version)))\n     (file-name (git-file-name name version))\n     (sha256\n      (base32\n       \"1xzbh3bxy4rw1yamnx68da1v5s56ay4g081cyamv67256g0qy2i1\"))))\n   (build-system python-build-system)\n   (arguments\n    `(#:phases\n      (modify-phases %standard-phases\n        (add-after 'unpack 'parallel-jobs\n          ;; build with multiple cores\n          (lambda _\n            (substitute* \"setup.py\" ((\"self.parallel if self.parallel else 1\") (number->string (parallel-job-count)))))))))\n   (native-inputs\n    `((\"cmake\" ,cmake)))\n   (home-page \"https://github.com/lief-project/LIEF\")\n   (synopsis \"Library to Instrument Executable Formats\")\n   (description \"Python library to to provide a cross platform library which can\nparse, modify and abstract ELF, PE and MachO formats.\")\n   (license license:asl2.0)))\n\n(define osslsigncode\n  (package\n    (name \"osslsigncode\")\n    (version \"2.0\")\n    (source (origin\n              (method url-fetch)\n              (uri (string-append \"https://github.com/mtrojnar/\"\n                                  name \"/archive/\" version \".tar.gz\"))\n              (sha256\n               (base32\n                \"0byri6xny770wwb2nciq44j5071122l14bvv65axdd70nfjf0q2s\"))))\n    (build-system gnu-build-system)\n    (native-inputs\n     `((\"pkg-config\" ,pkg-config)\n       (\"autoconf\" ,autoconf)\n       (\"automake\" ,automake)\n       (\"libtool\" ,libtool)))\n    (inputs\n     `((\"openssl\" ,openssl)))\n    (arguments\n     `(#:configure-flags\n       `(\"--without-gsf\"\n         \"--without-curl\"\n         \"--disable-dependency-tracking\")))\n    (home-page \"https://github.com/mtrojnar/osslsigncode\")\n    (synopsis \"Authenticode signing and timestamping tool\")\n    (description \"osslsigncode is a small tool that implements part of the\nfunctionality of the Microsoft tool signtool.exe - more exactly the Authenticode\nsigning and timestamping. But osslsigncode is based on OpenSSL and cURL, and\nthus should be able to compile on most platforms where these exist.\")\n    (license license:gpl3+))) ; license is with openssl exception\n\n(define-public python-elfesteem\n  (let ((commit \"2eb1e5384ff7a220fd1afacd4a0170acff54fe56\"))\n    (package\n      (name \"python-elfesteem\")\n      (version (git-version \"0.1\" \"1\" commit))\n      (source\n       (origin\n         (method git-fetch)\n         (uri (git-reference\n               (url \"https://github.com/LRGH/elfesteem\")\n               (commit commit)))\n         (file-name (git-file-name name commit))\n         (sha256\n          (base32\n           \"07x6p8clh11z8s1n2kdxrqwqm2almgc5qpkcr9ckb6y5ivjdr5r6\"))))\n      (build-system python-build-system)\n      ;; There are no tests, but attempting to run python setup.py test leads to\n      ;; PYTHONPATH problems, just disable the test\n      (arguments '(#:tests? #f))\n      (home-page \"https://github.com/LRGH/elfesteem\")\n      (synopsis \"ELF/PE/Mach-O parsing library\")\n      (description \"elfesteem parses ELF, PE and Mach-O files.\")\n      (license license:lgpl2.1))))\n\n(define-public python-oscrypto\n  (package\n    (name \"python-oscrypto\")\n    (version \"1.2.1\")\n    (source\n     (origin\n       (method git-fetch)\n       (uri (git-reference\n             (url \"https://github.com/wbond/oscrypto\")\n             (commit version)))\n       (file-name (git-file-name name version))\n       (sha256\n        (base32\n         \"1d4d8s4z340qhvb3g5m5v3436y3a71yc26wk4749q64m09kxqc3l\"))\n       (patches (search-our-patches \"oscrypto-hard-code-openssl.patch\"))))\n    (build-system python-build-system)\n    (native-search-paths\n     (list (search-path-specification\n            (variable \"SSL_CERT_FILE\")\n            (file-type 'regular)\n            (separator #f)                ;single entry\n            (files '(\"etc/ssl/certs/ca-certificates.crt\")))))\n\n    (propagated-inputs\n     `((\"python-asn1crypto\" ,python-asn1crypto)\n       (\"openssl\" ,openssl)))\n    (arguments\n     `(#:phases\n       (modify-phases %standard-phases\n         (add-after 'unpack 'hard-code-path-to-libscrypt\n           (lambda* (#:key inputs #:allow-other-keys)\n             (let ((openssl (assoc-ref inputs \"openssl\")))\n               (substitute* \"oscrypto/__init__.py\"\n                 ((\"@GUIX_OSCRYPTO_USE_OPENSSL@\")\n                  (string-append openssl \"/lib/libcrypto.so\" \",\" openssl \"/lib/libssl.so\")))\n               #t)))\n         (add-after 'unpack 'disable-broken-tests\n           (lambda _\n             ;; This test is broken as there is no keyboard interrupt.\n             (substitute* \"tests/test_trust_list.py\"\n               ((\"^(.*)class TrustListTests\" line indent)\n                (string-append indent\n                               \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                               line)))\n             (substitute* \"tests/test_tls.py\"\n               ((\"^(.*)class TLSTests\" line indent)\n                (string-append indent\n                               \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                               line)))\n             #t))\n         (replace 'check\n           (lambda _\n             (invoke \"python\" \"run.py\" \"tests\")\n             #t)))))\n    (home-page \"https://github.com/wbond/oscrypto\")\n    (synopsis \"Compiler-free Python crypto library backed by the OS\")\n    (description \"oscrypto is a compilation-free, always up-to-date encryption library for Python.\")\n    (license license:expat)))\n\n(define-public python-oscryptotests\n  (package (inherit python-oscrypto)\n    (name \"python-oscryptotests\")\n    (propagated-inputs\n      `((\"python-oscrypto\" ,python-oscrypto)))\n    (arguments\n     `(#:tests? #f\n       #:phases\n       (modify-phases %standard-phases\n         (add-after 'unpack 'hard-code-path-to-libscrypt\n           (lambda* (#:key inputs #:allow-other-keys)\n             (chdir \"tests\")\n             #t)))))))\n\n(define-public python-certvalidator\n  (let ((commit \"a145bf25eb75a9f014b3e7678826132efbba6213\"))\n    (package\n      (name \"python-certvalidator\")\n      (version (git-version \"0.1\" \"1\" commit))\n      (source\n       (origin\n         (method git-fetch)\n         (uri (git-reference\n               (url \"https://github.com/achow101/certvalidator\")\n               (commit commit)))\n         (file-name (git-file-name name commit))\n         (sha256\n          (base32\n           \"1qw2k7xis53179lpqdqyylbcmp76lj7sagp883wmxg5i7chhc96k\"))))\n      (build-system python-build-system)\n      (propagated-inputs\n       `((\"python-asn1crypto\" ,python-asn1crypto)\n         (\"python-oscrypto\" ,python-oscrypto)\n         (\"python-oscryptotests\", python-oscryptotests))) ;; certvalidator tests import oscryptotests\n      (arguments\n       `(#:phases\n         (modify-phases %standard-phases\n           (add-after 'unpack 'disable-broken-tests\n             (lambda _\n               (substitute* \"tests/test_certificate_validator.py\"\n                 ((\"^(.*)class CertificateValidatorTests\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               (substitute* \"tests/test_crl_client.py\"\n                 ((\"^(.*)def test_fetch_crl\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               (substitute* \"tests/test_ocsp_client.py\"\n                 ((\"^(.*)def test_fetch_ocsp\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               (substitute* \"tests/test_registry.py\"\n                 ((\"^(.*)def test_build_paths\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               (substitute* \"tests/test_validate.py\"\n                 ((\"^(.*)def test_revocation_mode_hard\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               (substitute* \"tests/test_validate.py\"\n                 ((\"^(.*)def test_revocation_mode_soft\" line indent)\n                  (string-append indent\n                                 \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                                 line)))\n               #t))\n           (replace 'check\n             (lambda _\n               (invoke \"python\" \"run.py\" \"tests\")\n               #t)))))\n      (home-page \"https://github.com/wbond/certvalidator\")\n      (synopsis \"Python library for validating X.509 certificates and paths\")\n      (description \"certvalidator is a Python library for validating X.509\ncertificates or paths. Supports various options, including: validation at a\nspecific moment in time, whitelisting and revocation checks.\")\n      (license license:expat))))\n\n(define-public python-altgraph\n  (package\n    (name \"python-altgraph\")\n    (version \"0.17\")\n    (source\n     (origin\n       (method git-fetch)\n       (uri (git-reference\n             (url \"https://github.com/ronaldoussoren/altgraph\")\n             (commit (string-append \"v\" version))))\n       (file-name (git-file-name name version))\n       (sha256\n        (base32\n         \"09sm4srvvkw458pn48ga9q7ykr4xlz7q8gh1h9w7nxpf001qgpwb\"))))\n    (build-system python-build-system)\n    (home-page \"https://github.com/ronaldoussoren/altgraph\")\n    (synopsis \"Python graph (network) package\")\n    (description \"altgraph is a fork of graphlib: a graph (network) package for\nconstructing graphs, BFS and DFS traversals, topological sort, shortest paths,\netc. with graphviz output.\")\n    (license license:expat)))\n\n\n(define-public python-macholib\n  (package\n    (name \"python-macholib\")\n    (version \"1.14\")\n    (source\n     (origin\n       (method git-fetch)\n       (uri (git-reference\n             (url \"https://github.com/ronaldoussoren/macholib\")\n             (commit (string-append \"v\" version))))\n       (file-name (git-file-name name version))\n       (sha256\n        (base32\n         \"0aislnnfsza9wl4f0vp45ivzlc0pzhp9d4r08700slrypn5flg42\"))))\n    (build-system python-build-system)\n    (propagated-inputs\n     `((\"python-altgraph\" ,python-altgraph)))\n    (arguments\n     '(#:phases\n       (modify-phases %standard-phases\n         (add-after 'unpack 'disable-broken-tests\n           (lambda _\n             ;; This test is broken as there is no keyboard interrupt.\n             (substitute* \"macholib_tests/test_command_line.py\"\n               ((\"^(.*)class TestCmdLine\" line indent)\n                (string-append indent\n                               \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                               line)))\n             (substitute* \"macholib_tests/test_dyld.py\"\n               ((\"^(.*)def test_\\\\S+_find\" line indent)\n                (string-append indent\n                               \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                               line))\n               ((\"^(.*)def testBasic\" line indent)\n                (string-append indent\n                               \"@unittest.skip(\\\"Disabled by Guix\\\")\\n\"\n                               line))\n               )\n             #t)))))\n    (home-page \"https://github.com/ronaldoussoren/macholib\")\n    (synopsis \"Python library for analyzing and editing Mach-O headers\")\n    (description \"macholib is a Macho-O header analyzer and editor. It's\ntypically used as a dependency analysis tool, and also to rewrite dylib\nreferences in Mach-O headers to be @executable_path relative. Though this tool\ntargets a platform specific file format, it is pure python code that is platform\nand endian independent.\")\n    (license license:expat)))\n\n(define-public python-signapple\n  (let ((commit \"8a945a2e7583be2665cf3a6a89d665b70ecd1ab6\"))\n    (package\n      (name \"python-signapple\")\n      (version (git-version \"0.1\" \"1\" commit))\n      (source\n       (origin\n         (method git-fetch)\n         (uri (git-reference\n               (url \"https://github.com/achow101/signapple\")\n               (commit commit)))\n         (file-name (git-file-name name commit))\n         (sha256\n          (base32\n           \"0fr1hangvfyiwflca6jg5g8zvg3jc9qr7vd2c12ff89pznf38dlg\"))))\n      (build-system python-build-system)\n      (propagated-inputs\n       `((\"python-asn1crypto\" ,python-asn1crypto)\n         (\"python-oscrypto\" ,python-oscrypto)\n         (\"python-certvalidator\" ,python-certvalidator)\n         (\"python-elfesteem\" ,python-elfesteem)\n         (\"python-requests\" ,python-requests)\n         (\"python-macholib\" ,python-macholib)))\n      ;; There are no tests, but attempting to run python setup.py test leads to\n      ;; problems, just disable the test\n      (arguments '(#:tests? #f))\n      (home-page \"https://github.com/achow101/signapple\")\n      (synopsis \"Mach-O binary signature tool\")\n      (description \"signapple is a Python tool for creating, verifying, and\ninspecting signatures in Mach-O binaries.\")\n      (license license:expat))))\n\n(define (make-glibc-without-werror glibc)\n  (package-with-extra-configure-variable glibc \"enable_werror\" \"no\"))\n\n(define (make-glibc-with-stack-protector glibc)\n  (package-with-extra-configure-variable glibc \"--enable-stack-protector\" \"all\"))\n\n(define (make-glibc-with-bind-now glibc)\n  (package-with-extra-configure-variable glibc \"--enable-bind-now\" \"yes\"))\n\n(define-public glibc-2.24\n  (package\n    (inherit glibc-2.31)\n    (version \"2.24\")\n    (source (origin\n              (method git-fetch)\n              (uri (git-reference\n                    (url \"https://sourceware.org/git/glibc.git\")\n                    (commit \"0d7f1ed30969886c8dde62fbf7d2c79967d4bace\")))\n              (file-name (git-file-name \"glibc\" \"0d7f1ed30969886c8dde62fbf7d2c79967d4bace\"))\n              (sha256\n               (base32\n                \"0g5hryia5v1k0qx97qffgwzrz4lr4jw3s5kj04yllhswsxyjbic3\"))\n              (patches (search-our-patches \"glibc-ldd-x86_64.patch\"\n                                           \"glibc-versioned-locpath.patch\"\n                                           \"glibc-2.24-elfm-loadaddr-dynamic-rewrite.patch\"\n                                           \"glibc-2.24-no-build-time-cxx-header-run.patch\"\n                                           \"glibc-2.24-fcommon.patch\"\n                                           \"glibc-2.24-guix-prefix.patch\"))))))\n\n(define-public glibc-2.27/munt-patched\n  (package\n    (inherit glibc-2.31)\n    (version \"2.27\")\n    (source (origin\n              (method git-fetch)\n              (uri (git-reference\n                    (url \"https://sourceware.org/git/glibc.git\")\n                    (commit \"23158b08a0908f381459f273a984c6fd328363cb\")))\n              (file-name (git-file-name \"glibc\" \"23158b08a0908f381459f273a984c6fd328363cb\"))\n              (sha256\n               (base32\n                \"1b2n1gxv9f4fd5yy68qjbnarhf8mf4vmlxk10i3328c1w5pmp0ca\"))\n              (patches (search-our-patches \"glibc-ldd-x86_64.patch\"\n                                           \"glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch\"\n                                           \"glibc-2.27-dont-redefine-nss-database.patch\"\n                                           \"glibc-2.27-guix-prefix.patch\"))))))\n\n(packages->manifest\n (append\n  (list ;; The Basics\n        bash\n        which\n        coreutils\n        util-linux\n        ;; File(system) inspection\n        file\n        grep\n        diffutils\n        findutils\n        ;; File transformation\n        patch\n        gawk\n        sed\n        moreutils\n        ;; Compression and archiving\n        tar\n        bzip2\n        gzip\n        xz\n        pigz\n        ;; Build tools\n        gnu-make\n        libtool-2.4.7\n        autoconf-2.71\n        automake\n        pkg-config\n        bison\n        ;; Native GCC 10 toolchain\n        gcc-toolchain-10\n        (list gcc-toolchain-10 \"static\")\n        ;; Scripting\n        perl\n        python-3\n        ;; Git\n        git-minimal\n        ;; Tests\n        (fix-ppc64-nx-default lief))\n  (let ((target (getenv \"HOST\")))\n    (cond ((string-suffix? \"-mingw32\" target)\n           ;; Windows\n           (list zip\n                 (make-mingw-pthreads-cross-toolchain \"x86_64-w64-mingw32\")\n                 (make-nsis-for-gcc-10 nsis-x86_64)\n                 osslsigncode))\n          ((string-contains target \"-linux-\")\n           (list (cond ((string-contains target \"riscv64-\")\n                        (make-munt-cross-toolchain target\n                                                      #:base-libc (make-glibc-with-stack-protector\n                                                        (make-glibc-with-bind-now (make-glibc-without-werror glibc-2.27/munt-patched)))))\n                       (else\n                        (make-munt-cross-toolchain target)))))\n          ((string-contains target \"darwin\")\n           (list clang-toolchain-10 binutils cmake xorriso python-signapple))\n          (else '())))))\n"
  },
  {
    "path": "contrib/init/README.md",
    "content": "Sample configuration files for:\n```\nSystemD: daemon.service\nUpstart: daemon.conf\nOpenRC:  daemon.openrc\n         daemon.openrcconf\nCentOS:  daemon.init\n```\nhave been made available to assist packagers in creating node packages here.\n\nSee doc/init.md for more information.\n"
  },
  {
    "path": "contrib/init/daemon.conf",
    "content": "description \"Munt Core Daemon\"\n\nstart on runlevel [2345]\nstop on starting rc RUNLEVEL=[016]\n\nenv DAEMON_BIN=\"/usr/bin/Munt-daemon\"\nenv DAEMON_USER=\"munt\"\nenv DAEMON_GROUP=\"munt\"\nenv DAEMON_PIDDIR=\"/var/run/munt_daemon\"\n# upstart can't handle variables constructed with other variables\nenv DAEMON_PIDFILE=\"/var/run/munt_daemon/munt_daemon.pid\"\nenv DAEMON_CONFIGFILE=\"/etc/munt/munt.conf\"\nenv DAEMON_DATADIR=\"/var/lib/munt_daemon\"\n\nexpect fork\n\nrespawn\nrespawn limit 5 120\nkill timeout 60\n\npre-start script\n    # this will catch non-existent config files\n    # daemon will check and exit with this very warning, but it can do so\n    # long after forking, leaving upstart to think everything started fine.\n    # since this is a commonly encountered case on install, just check and\n    # warn here.\n    if ! grep -qs '^rpcpassword=' \"$DAEMON_CONFIGFILE\" ; then\n        echo \"ERROR: You must set a secure rpcpassword.\"\n        echo \"The setting must appear in $DAEMON_CONFIGFILE\"\n        echo\n        echo \"This password is security critical to securing wallets \"\n        echo \"and must not be the same as the rpcuser setting.\"\n        echo \"You can generate a suitable random password using the following\"\n        echo \"command from the shell:\"\n        echo\n        echo \"bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'\"\n        echo\n        echo \"It is also recommended that you also set alertnotify so you are \"\n        echo \"notified of problems:\"\n        echo\n        echo \"ie: alertnotify=echo %%s | mail -s \\\"Munt Alert\\\"\" \\\n            \"admin@foo.com\"\n        echo\n        exit 1\n    fi\n\n    mkdir -p \"$DAEMON_PIDDIR\"\n    chmod 0755 \"$DAEMON_PIDDIR\"\n    chown $DAEMON_USER:$DAEMON_GROUP \"$DAEMON_PIDDIR\"\n    chown $DAEMON_USER:$DAEMON_GROUP \"$DAEMON_CONFIGFILE\"\n    chmod 0660 \"$DAEMON_CONFIGFILE\"\nend script\n\nexec start-stop-daemon \\\n    --start \\\n    --pidfile \"$DAEMON_PIDFILE\" \\\n    --chuid $DAEMON_USER:$DAEMON_GROUP \\\n    --exec \"$DAEMON_BIN\" \\\n    -- \\\n    -pid=\"$DAEMON_PIDFILE\" \\\n    -conf=\"$DAEMON_CONFIGFILE\" \\\n    -datadir=\"$DAEMON_DATADIR\" \\\n    -disablewallet \\\n    -daemon\n\n"
  },
  {
    "path": "contrib/init/daemon.init",
    "content": "#!/bin/bash\n#\n#  Munt-daemon The Munt core server.\n#\n#\n# chkconfig: 345 80 20\n# description: Munt-daemon\n# processname: Munt-daemon\n#\n\n# Source function library.\n. /etc/init.d/functions\n\n# you can override defaults in /etc/sysconfig/munt_daemon, see below\nif [ -f /etc/sysconfig/munt_daemon ]; then\n        . /etc/sysconfig/munt_daemon\nfi\n\nRETVAL=0\n\nprog=Munt-daemon\n# you can override the lockfile via DAEMON_LOCKFILE in /etc/sysconfig/munt_daemon\nlockfile=${DAEMON_LOCKFILE-/var/lock/subsys/munt_daemon}\n\n# daemon bin defaults to /usr/bin/Munt-daemon, override with DAEMON_BIN\ndaemon_bin=${DAEMON_BIN-/usr/bin/Munt-daemon}\n\n# daemon opts default to -disablewallet, override with DAEMON_OPTS\ndaemon_opts=${DAEMON_OPTS--disablewallet}\n\nstart() {\n    echo -n $\"Starting $prog: \"\n    daemon $DAEMONOPTS $daemon_bin $daemon_opts\n    RETVAL=$?\n    echo\n    [ $RETVAL -eq 0 ] && touch $lockfile\n    return $RETVAL\n}\n\nstop() {\n    echo -n $\"Stopping $prog: \"\n    killproc $prog\n    RETVAL=$?\n    echo\n    [ $RETVAL -eq 0 ] && rm -f $lockfile\n    return $RETVAL\n}\n\ncase \"$1\" in\n    start)\n        start\n        ;;\n    stop)\n        stop\n        ;;\n    status)\n        status $prog\n        ;;\n    restart)\n        stop\n        start\n        ;;\n    *)\n        echo \"Usage: service $prog {start|stop|status|restart}\"\n        exit 1\n        ;;\nesac\n"
  },
  {
    "path": "contrib/init/daemon.openrc",
    "content": "#!/sbin/runscript\n\n# backward compatibility for existing gentoo layout \n#\nif [ -d \"/var/lib/munt/.munt\" ]; then\n\tDAEMON_DEFAULT_DATADIR=\"/var/lib/munt/.munt\"\nelse\n\tDAEMON_DEFAULT_DATADIR=\"/var/lib/munt_daemon\"\nfi\n\nDAEMON_CONFIGFILE=${DAEMON_CONFIGFILE:-/etc/munt/munt.conf}\nDAEMON_PIDDIR=${DAEMON_PIDDIR:-/var/run/munt_daemon}\nDAEMON_PIDFILE=${DAEMON_PIDFILE:-${DAEMON_PIDDIR}/munt_daemon.pid}\nDAEMON_DATADIR=${DAEMON_DATADIR:-${DAEMON_DEFAULT_DATADIR}}\nDAEMON_USER=${DAEMON_USER:-${DAEMON_USER:-munt}}\nDAEMON_GROUP=${DAEMON_GROUP:-munt}\nDAEMON_BIN=${DAEMON_BIN:-/usr/bin/Munt-daemon}\nDAEMON_NICE=${DAEMON_NICE:-${NICELEVEL:-0}}\nDAEMON_OPTS=\"${DAEMON_OPTS:-${DAEMON_OPTS}}\"\n\nname=\"Munt Core Daemon\"\ndescription=\"Munt cryptocurrency P2P network daemon\"\n\ncommand=\"/usr/bin/Munt-daemon\"\ncommand_args=\"-pid=\\\"${DAEMON_PIDFILE}\\\" \\\n\t\t-conf=\\\"${DAEMON_CONFIGFILE}\\\" \\\n\t\t-datadir=\\\"${DAEMON_DATADIR}\\\" \\\n\t\t-daemon \\\n\t\t${DAEMON_OPTS}\"\n\nrequired_files=\"${DAEMON_CONFIGFILE}\"\nstart_stop_daemon_args=\"-u ${DAEMON_USER} \\\n\t\t\t-N ${DAEMON_NICE} -w 2000\"\npidfile=\"${DAEMON_PIDFILE}\"\n\n# The retry schedule to use when stopping the daemon. Could be either\n# a timeout in seconds or multiple signal/timeout pairs (like\n# \"SIGKILL/180 SIGTERM/300\")\nretry=\"${DAEMON_SIGTERM_TIMEOUT}\"\n\ndepend() {\n\tneed localmount net\n}\n\n# verify\n# 1) that the datadir exists and is writable (or create it)\n# 2) that a directory for the pid exists and is writable\n# 3) ownership and permissions on the config file\nstart_pre() {\n\tcheckpath \\\n\t-d \\\n\t--mode 0750 \\\n\t--owner \"${DAEMON_USER}:${DAEMON_GROUP}\" \\\n\t\"${DAEMON_DATADIR}\"\n\n\tcheckpath \\\n\t-d \\\n\t--mode 0755 \\\n\t--owner \"${DAEMON_USER}:${DAEMON_GROUP}\" \\\n\t\"${DAEMON_PIDDIR}\"\n\n\tcheckpath -f \\\n\t-o ${DAEMON_USER}:${DAEMON_GROUP} \\\n\t-m 0660 \\\n\t${DAEMON_CONFIGFILE}\n\n\tcheckconfig || return 1\n}\n\ncheckconfig()\n{\n\tif ! grep -qs '^rpcpassword=' \"${DAEMON_CONFIGFILE}\" ; then\n\t\teerror \"\"\n\t\teerror \"ERROR: You must set a secure rpcpassword.\"\n\t\teerror \"The setting must appear in ${DAEMON_CONFIGFILE}\"\n\t\teerror \"\"\n\t\teerror \"This password is security critical to securing wallets \"\n\t\teerror \"and must not be the same as the rpcuser setting.\"\n\t\teerror \"You can generate a suitable random password using the following\"\n\t\teerror \"command from the shell:\"\n\t\teerror \"\"\n\t\teerror \"bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'\"\n\t\teerror \"\"\n\t\teerror \"It is also recommended that you also set alertnotify so you are \"\n\t\teerror \"notified of problems:\"\n\t\teerror \"\"\n\t\teerror \"ie: alertnotify=echo %%s | mail -s \\\"Munt Alert\\\"\" \\\n\t\t\t\"admin@foo.com\"\n\t\teerror \"\"\n\t\treturn 1\n\tfi\n}\n"
  },
  {
    "path": "contrib/init/daemon.openrcconf",
    "content": "# /etc/conf.d/munt_daemon: config file for /etc/init.d/munt_daemon\n\n# Config file location\n#DAEMON_CONFIGFILE=\"/etc/munt/munt.conf\"\n\n# What directory to write pidfile to?  (created and owned by $DAEMON_USER)\n#DAEMON_PIDDIR=\"/var/run/munt_daemon\"\n\n# What filename to give the pidfile\n#DAEMON_PIDFILE=\"${DAEMON_PIDDIR}/munt_daemon.pid\"\n\n# Where to write data (be mindful that the blockchain is large)\n#DAEMON_DATADIR=\"/var/lib/munt_daemon\"\n\n# User and group to own process\n#DAEMON_USER=\"munt\"\n#DAEMON_GROUP=\"munt\"\n\n# Path to executable\n#DAEMON_BIN=\"/usr/bin/Munt-daemon\"\n\n# Nice value to run under\n#DAEMON_NICE=0\n\n# Additional options (avoid -conf and -datadir, use flags above)\n#DAEMON_OPTS=\"\"\n\n# The timeout in seconds OpenRC will wait for daemon to terminate\n# after a SIGTERM has been raised.\n# Note that this will be mapped as argument to start-stop-daemon's\n# '--retry' option, which means you can specify a retry schedule\n# here. For more information see man 8 start-stop-daemon.\nDAEMON_SIGTERM_TIMEOUT=60\n"
  },
  {
    "path": "contrib/init/daemon.service",
    "content": "[Unit]\nDescription=Munt distributed currency daemon\nAfter=network.target\n\n[Service]\nUser=munt\nGroup=munt\n\nType=forking\nPIDFile=/var/lib/munt_daemon/munt_daemon.pid\nExecStart=/usr/bin/Munt-daemon -daemon -pid=/var/lib/munt_daemon/munt_daemon.pid \\\n-conf=/etc/munt/munt.conf -datadir=/var/lib/munt_daemon -disablewallet\n\nRestart=always\nPrivateTmp=true\nTimeoutStopSec=60s\nTimeoutStartSec=2s\nStartLimitInterval=120s\nStartLimitBurst=5\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "contrib/macdeploy/LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "contrib/macdeploy/README.md",
    "content": "### MacDeploy ###\n\nFor Snow Leopard (which uses [Python 2.6](http://www.python.org/download/releases/2.6/)), you will need the param_parser package:\n\t\n\tsudo easy_install argparse\n\nThis script should not be run manually, instead, after building as usual:\n\n\tmake deploy\n\nDuring the process, the disk image window will pop up briefly where the fancy\nsettings are applied. This is normal, please do not interfere.\n\nWhen finished, it will produce `Munt-Core.dmg`.\n\n"
  },
  {
    "path": "contrib/macdeploy/custom_dsstore.py",
    "content": "#!/usr/bin/env python\n# Copyright (c) 2013-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\nfrom __future__ import division,print_function,unicode_literals\nimport biplist\nfrom ds_store import DSStore\nfrom mac_alias import Alias\nimport sys\n\noutput_file = sys.argv[1]\npackage_name_ns = sys.argv[2]\n\nds = DSStore.open(output_file, 'w+')\nds['.']['bwsp'] = {\n    'ShowStatusBar': False,\n    'WindowBounds': b'{{300, 280}, {500, 343}}',\n    'ContainerShowSidebar': False,\n    'SidebarWidth': 0,\n    'ShowTabView': False,\n    'PreviewPaneVisibility': False,\n    'ShowToolbar': False,\n    'ShowSidebar': False,\n    'ShowPathbar': True\n}\n\nicvp = {\n    'gridOffsetX': 0.0,\n    'textSize': 12.0,\n    'viewOptionsVersion': 1,\n    'backgroundImageAlias': b'\\x00\\x00\\x00\\x00\\x02\\x1e\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xd1\\x94\\\\\\xb0H+\\x00\\x05\\x00\\x00\\x00\\x98\\x0fbackground.tiff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x99\\xd19\\xb0\\xf8\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xff\\xff\\xff\\xff\\x00\\x00\\r\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0b.background\\x00\\x00\\x10\\x00\\x08\\x00\\x00\\xd1\\x94\\\\\\xb0\\x00\\x00\\x00\\x11\\x00\\x08\\x00\\x00\\xd19\\xb0\\xf8\\x00\\x00\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x98\\x00\\x0e\\x00 \\x00\\x0f\\x00b\\x00a\\x00c\\x00k\\x00g\\x00r\\x00o\\x00u\\x00n\\x00d\\x00.\\x00t\\x00i\\x00f\\x00f\\x00\\x0f\\x00\\x02\\x00\\x00\\x00\\x12\\x00\\x1c/.background/background.tiff\\x00\\x14\\x01\\x06\\x00\\x00\\x00\\x00\\x01\\x06\\x00\\x02\\x00\\x00\\x0cMacintosh HD\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xce\\x97\\xab\\xc3H+\\x00\\x00\\x01\\x88[\\x88\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02u\\xab\\x8d\\xd1\\x94\\\\\\xb0devrddsk\\xff\\xff\\xff\\xff\\x00\\x00\\t \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x07munt\\x00\\x00\\x10\\x00\\x08\\x00\\x00\\xce\\x97\\xab\\xc3\\x00\\x00\\x00\\x11\\x00\\x08\\x00\\x00\\xd1\\x94\\\\\\xb0\\x00\\x00\\x00\\x01\\x00\\x14\\x01\\x88[\\x88\\x00\\x16\\xa9\\t\\x00\\x08\\xfaR\\x00\\x08\\xfaQ\\x00\\x02d\\x8e\\x00\\x0e\\x00\\x02\\x00\\x00\\x00\\x0f\\x00\\x1a\\x00\\x0c\\x00M\\x00a\\x00c\\x00i\\x00n\\x00t\\x00o\\x00s\\x00h\\x00 \\x00H\\x00D\\x00\\x13\\x00\\x01/\\x00\\x00\\x15\\x00\\x02\\x00\\x14\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00',\n    'backgroundColorBlue': 1.0,\n    'iconSize': 96.0,\n    'backgroundColorGreen': 1.0,\n    'arrangeBy': 'none',\n    'showIconPreview': True,\n    'gridSpacing': 100.0,\n    'gridOffsetY': 0.0,\n    'showItemInfo': False,\n    'labelOnBottom': True,\n    'backgroundType': 2,\n    'backgroundColorRed': 1.0\n}\nalias = Alias.from_bytes(icvp['backgroundImageAlias'])\nalias.volume.name = package_name_ns\nalias.volume.posix_path = '/Volumes/' + package_name_ns\nalias.volume.disk_image_alias.target.filename = package_name_ns + '.temp.dmg'\nalias.volume.disk_image_alias.target.carbon_path = 'Macintosh HD:Users:\\x00muntuser:\\x00Documents:\\x00munt:\\x00munt:\\x00' + package_name_ns + '.temp.dmg'\nalias.volume.disk_image_alias.target.posix_path = 'Users/muntuser/Documents/munt/munt/' + package_name_ns + '.temp.dmg'\nalias.target.carbon_path = package_name_ns + ':.background:\\x00background.tiff'\nicvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())\nds['.']['icvp'] = icvp\n\nds['.']['vSrn'] = ('long', 1)\n\nds['Applications']['Iloc'] = (370, 156)\nds['Munt.app']['Iloc'] = (128, 156)\n\nds.flush()\nds.close()\n"
  },
  {
    "path": "contrib/macdeploy/detached-sig-apply.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2014-2015 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nset -e\n\nUNSIGNED=\"$1\"\nSIGNATURE=\"$2\"\nARCH=x86_64\nROOTDIR=dist\nTEMPDIR=signed.temp\nOUTDIR=signed-app\n\nif [ -z \"$UNSIGNED\" ]; then\n  echo \"usage: $0 <unsigned app> <signature>\"\n  exit 1\nfi\n\nif [ -z \"$SIGNATURE\" ]; then\n  echo \"usage: $0 <unsigned app> <signature>\"\n  exit 1\nfi\n\nrm -rf ${TEMPDIR} && mkdir -p ${TEMPDIR}\ntar -C ${TEMPDIR} -xf ${UNSIGNED}\ncp -rf \"${SIGNATURE}\"/* ${TEMPDIR}\n\nif [ -z \"${PAGESTUFF}\" ]; then\n  PAGESTUFF=${TEMPDIR}/pagestuff\nfi\n\nif [ -z \"${CODESIGN_ALLOCATE}\" ]; then\n  CODESIGN_ALLOCATE=${TEMPDIR}/codesign_allocate\nfi\n\nfind ${TEMPDIR} -name \"*.sign\" | while read i; do\n  SIZE=`stat -c %s \"${i}\"`\n  TARGET_FILE=\"`echo \"${i}\" | sed 's/\\.sign$//'`\"\n\n  echo \"Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}\"\n  ${CODESIGN_ALLOCATE} -i \"${TARGET_FILE}\" -a ${ARCH} ${SIZE} -o \"${i}.tmp\"\n\n  OFFSET=`${PAGESTUFF} \"${i}.tmp\" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'`\n  if [ -z ${QUIET} ]; then\n    echo \"Attaching signature at offset ${OFFSET}\"\n  fi\n\n  dd if=\"$i\" of=\"${i}.tmp\" bs=1 seek=${OFFSET} count=${SIZE} 2>/dev/null\n  mv \"${i}.tmp\" \"${TARGET_FILE}\"\n  rm \"${i}\"\n  echo \"Success.\"\ndone\nmv ${TEMPDIR}/${ROOTDIR} ${OUTDIR}\nrm -rf ${TEMPDIR}\necho \"Signed: ${OUTDIR}\"\n"
  },
  {
    "path": "contrib/macdeploy/detached-sig-create.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2014-2015 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nset -e\n\nROOTDIR=dist\nBUNDLE=\"${ROOTDIR}/Munt.app\"\nCODESIGN=codesign\nTEMPDIR=sign.temp\nTEMPLIST=${TEMPDIR}/signatures.txt\nOUT=signature-osx.tar.gz\nOUTROOT=osx\n\nif [ ! -n \"$1\" ]; then\n  echo \"usage: $0 <codesign args>\"\n  echo \"example: $0 -s MyIdentity\"\n  exit 1\nfi\n\nrm -rf ${TEMPDIR} ${TEMPLIST}\nmkdir -p ${TEMPDIR}\n\n${CODESIGN} -f --file-list ${TEMPLIST} \"$@\" \"${BUNDLE}\"\n\ngrep -v CodeResources < \"${TEMPLIST}\" | while read i; do\n  TARGETFILE=\"${BUNDLE}/`echo \"${i}\" | sed \"s|.*${BUNDLE}/||\"`\"\n  SIZE=`pagestuff \"$i\" -p | tail -2 | grep size | sed 's/[^0-9]*//g'`\n  OFFSET=`pagestuff \"$i\" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'`\n  SIGNFILE=\"${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign\"\n  DIRNAME=\"`dirname \"${SIGNFILE}\"`\"\n  mkdir -p \"${DIRNAME}\"\n  echo \"Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}\"\n  dd if=\"$i\" of=\"${SIGNFILE}\" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null\ndone\n\ngrep CodeResources < \"${TEMPLIST}\" | while read i; do\n  TARGETFILE=\"${BUNDLE}/`echo \"${i}\" | sed \"s|.*${BUNDLE}/||\"`\"\n  RESOURCE=\"${TEMPDIR}/${OUTROOT}/${TARGETFILE}\"\n  DIRNAME=\"`dirname \"${RESOURCE}\"`\"\n  mkdir -p \"${DIRNAME}\"\n  echo \"Adding resource for: \"${TARGETFILE}\"\"\n  cp \"${i}\" \"${RESOURCE}\"\ndone\n\nrm ${TEMPLIST}\n\ntar -C \"${TEMPDIR}\" -czf \"${OUT}\" .\nrm -rf \"${TEMPDIR}\"\necho \"Created ${OUT}\"\n"
  },
  {
    "path": "contrib/macdeploy/extract-osx-sdk.sh",
    "content": "#!/bin/bash\n# Copyright (c) 2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nset -e\n\nINPUTFILE=\"Xcode_7.3.1.dmg\"\nHFSFILENAME=\"5.hfs\"\nSDKDIR=\"Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk\"\n\n7z x \"${INPUTFILE}\" \"${HFSFILENAME}\"\nSDKNAME=\"$(basename \"${SDKDIR}\")\"\nSDKDIRINODE=$(ifind -n \"${SDKDIR}\" \"${HFSFILENAME}\")\nfls \"${HFSFILENAME}\" -rpF ${SDKDIRINODE} |\n while read type inode filename; do\n\tinode=\"${inode::-1}\"\n\tif [ \"${filename:0:14}\" = \"usr/share/man/\" ]; then\n\t\tcontinue\n\tfi\n\tfilename=\"${SDKNAME}/$filename\"\n\techo \"Extracting $filename ...\"\n\tmkdir -p \"$(dirname \"$filename\")\"\n\tif [ \"$type\" = \"l/l\" ]; then\n\t\tln -s \"$(icat \"${HFSFILENAME}\" $inode)\" \"$filename\"\n\telse\n\t\ticat \"${HFSFILENAME}\" $inode >\"$filename\"\n\tfi\ndone\necho \"Building ${SDKNAME}.tar.gz ...\"\nMTIME=\"$(istat \"${HFSFILENAME}\" \"${SDKDIRINODE}\" | perl -nle 'm/Content Modified:\\s+(.*?)\\s\\(/ && print $1')\"\nfind \"${SDKNAME}\" | sort | tar --no-recursion --mtime=\"${MTIME}\" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > \"${SDKNAME}.tar.gz\"\necho 'All done!'\n"
  },
  {
    "path": "contrib/macdeploy/fancy.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>window_bounds</key>\n\t<array>\n\t\t<integer>300</integer>\n\t\t<integer>300</integer>\n\t\t<integer>800</integer>\n\t\t<integer>620</integer>\n\t</array>\n\t<key>background_picture</key>\n\t<string>background.tiff</string>\n\t<key>icon_size</key>\n\t<integer>96</integer>\n\t<key>applications_symlink</key>\n\t<true/>\n\t<key>items_position</key>\n\t<dict>\n\t\t<key>Applications</key>\n\t\t<array>\n\t\t\t<integer>370</integer>\n\t\t\t<integer>156</integer>\n\t\t</array>\n\t\t<key>Munt.app</key>\n\t\t<array>\n\t\t\t<integer>128</integer>\n\t\t\t<integer>156</integer>\n\t\t</array>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "contrib/qos/README.md",
    "content": "### QoS (Quality of service) ###\n\nThis is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Munt network. It limits outbound TCP traffic with a source or destination port of 9231, but not if the destination IP is within a LAN.\n\nThis means one can have an always-on Munt-daemon instance running, and another local Munt-daemon/Munt instance which connects to this node and receives blocks from it.\n"
  },
  {
    "path": "contrib/qos/tc.sh",
    "content": "# Copyright (c) 2017 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#network interface on which to limit traffic\nIF=\"eth0\"\n#limit of the network interface in question\nLINKCEIL=\"1gbit\"\n#limit outbound Munt protocol traffic to this rate\nLIMIT=\"160kbit\"\n#defines the IPv4 address space for which you wish to disable rate limiting\nLOCALNET_V4=\"192.168.0.0/16\"\n#defines the IPv6 address space for which you wish to disable rate limiting\nLOCALNET_V6=\"fe80::/10\"\n\n#delete existing rules\ntc qdisc del dev ${IF} root\n\n#add root class\ntc qdisc add dev ${IF} root handle 1: htb default 10\n\n#add parent class\ntc class add dev ${IF} parent 1: classid 1:1 htb rate ${LINKCEIL} ceil ${LINKCEIL}\n\n#add our two classes. one unlimited, another limited\ntc class add dev ${IF} parent 1:1 classid 1:10 htb rate ${LINKCEIL} ceil ${LINKCEIL} prio 0\ntc class add dev ${IF} parent 1:1 classid 1:11 htb rate ${LIMIT} ceil ${LIMIT} prio 1\n\n#add handles to our classes so packets marked with <x> go into the class with \"... handle <x> fw ...\"\ntc filter add dev ${IF} parent 1: protocol ip prio 1 handle 1 fw classid 1:10\ntc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11\n\nif [ ! -z \"${LOCALNET_V6}\" ] ; then\n\t# v6 cannot have the same priority value as v4\n\ttc filter add dev ${IF} parent 1: protocol ipv6 prio 3 handle 1 fw classid 1:10\n\ttc filter add dev ${IF} parent 1: protocol ipv6 prio 4 handle 2 fw classid 1:11\nfi\n\n#delete any existing rules\n#disable for now\n#ret=0\n#while [ $ret -eq 0 ]; do\n#\tiptables -t mangle -D OUTPUT 1\n#\tret=$?\n#done\n\n#limit outgoing traffic to and from port 9231. but not when dealing with a host on the local network\n#\t(defined by $LOCALNET_V4 and $LOCALNET_V6)\n#\t--set-mark marks packages matching these criteria with the number \"2\" (v4)\n#\t--set-mark marks packages matching these criteria with the number \"4\" (v6)\n#\tthese packets are filtered by the tc filter with \"handle 2\"\n#\tthis filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT}\niptables -t mangle -A OUTPUT -p tcp -m tcp --dport 9231 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2\niptables -t mangle -A OUTPUT -p tcp -m tcp --sport 9231 ! -d ${LOCALNET_V4} -j MARK --set-mark 0x2\n\nif [ ! -z \"${LOCALNET_V6}\" ] ; then\n\tip6tables -t mangle -A OUTPUT -p tcp -m tcp --dport 9231 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4\n\tip6tables -t mangle -A OUTPUT -p tcp -m tcp --sport 9231 ! -d ${LOCALNET_V6} -j MARK --set-mark 0x4\nfi\n"
  },
  {
    "path": "contrib/shell/git-utils.bash",
    "content": "#!/usr/bin/env bash\n\ngit_root() {\n    git rev-parse --show-toplevel 2> /dev/null\n}\n\ngit_head_version() {\n    local recent_tag\n    if recent_tag=\"$(git describe --exact-match HEAD 2> /dev/null)\"; then\n        echo \"${recent_tag#v}\"\n    else\n        git rev-parse --short=12 HEAD\n    fi\n}\n"
  },
  {
    "path": "contrib/shell/realpath.bash",
    "content": "#!/usr/bin/env bash\n\n# Based on realpath.sh written by Michael Kropat\n# Found at: https://github.com/mkropat/sh-realpath/blob/65512368b8155b176b67122aa395ac580d9acc5b/realpath.sh\n\nbash_realpath() {\n    canonicalize_path \"$(resolve_symlinks \"$1\")\"\n}\n\nresolve_symlinks() {\n    _resolve_symlinks \"$1\"\n}\n\n_resolve_symlinks() {\n    _assert_no_path_cycles \"$@\" || return\n\n    local dir_context path\n    if path=$(readlink -- \"$1\"); then\n        dir_context=$(dirname -- \"$1\")\n        _resolve_symlinks \"$(_prepend_dir_context_if_necessary \"$dir_context\" \"$path\")\" \"$@\"\n    else\n        printf '%s\\n' \"$1\"\n    fi\n}\n\n_prepend_dir_context_if_necessary() {\n    if [ \"$1\" = . ]; then\n        printf '%s\\n' \"$2\"\n    else\n        _prepend_path_if_relative \"$1\" \"$2\"\n    fi\n}\n\n_prepend_path_if_relative() {\n    case \"$2\" in\n        /* ) printf '%s\\n' \"$2\" ;;\n         * ) printf '%s\\n' \"$1/$2\" ;;\n    esac\n}\n\n_assert_no_path_cycles() {\n    local target path\n\n    target=$1\n    shift\n\n    for path in \"$@\"; do\n        if [ \"$path\" = \"$target\" ]; then\n            return 1\n        fi\n    done\n}\n\ncanonicalize_path() {\n    if [ -d \"$1\" ]; then\n        _canonicalize_dir_path \"$1\"\n    else\n        _canonicalize_file_path \"$1\"\n    fi\n}\n\n_canonicalize_dir_path() {\n    (cd \"$1\" 2>/dev/null && pwd -P)\n}\n\n_canonicalize_file_path() {\n    local dir file\n    dir=$(dirname -- \"$1\")\n    file=$(basename -- \"$1\")\n    (cd \"$dir\" 2>/dev/null && printf '%s/%s\\n' \"$(pwd -P)\" \"$file\")\n}\n"
  },
  {
    "path": "contrib/testgen/README.md",
    "content": "### TestGen ###\n\nUtilities to generate test vectors for the data-driven Munt tests.\n\nUsage: \n\n    gen_base58_test_vectors.py valid 50 > ../../src/test/data/base58_keys_valid.json\n    gen_base58_test_vectors.py invalid 50 > ../../src/test/data/base58_keys_invalid.json\n"
  },
  {
    "path": "contrib/testgen/base58.py",
    "content": "# Copyright (c) 2012-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n'''\nMunt base58 encoding and decoding.\n\nBased on https://bitcointalk.org/index.php?topic=1026.0 (public domain)\n'''\nimport hashlib\n\n# for compatibility with following code...\nclass SHA256:\n    new = hashlib.sha256\n\nif str != bytes:\n    # Python 3.x\n    def ord(c):\n        return c\n    def chr(n):\n        return bytes( (n,) )\n\n__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\n__b58base = len(__b58chars)\nb58chars = __b58chars\n\ndef b58encode(v):\n    \"\"\" encode v, which is a string of bytes, to base58.\n    \"\"\"\n    long_value = 0\n    for (i, c) in enumerate(v[::-1]):\n        long_value += (256**i) * ord(c)\n\n    result = ''\n    while long_value >= __b58base:\n        div, mod = divmod(long_value, __b58base)\n        result = __b58chars[mod] + result\n        long_value = div\n    result = __b58chars[long_value] + result\n\n    # Munt does a little leading-zero-compression:\n    # leading 0-bytes in the input become leading-1s\n    nPad = 0\n    for c in v:\n        if c == '\\0': nPad += 1\n        else: break\n\n    return (__b58chars[0]*nPad) + result\n\ndef b58decode(v, length = None):\n    \"\"\" decode v into a string of len bytes\n    \"\"\"\n    long_value = 0\n    for (i, c) in enumerate(v[::-1]):\n        long_value += __b58chars.find(c) * (__b58base**i)\n\n    result = bytes()\n    while long_value >= 256:\n        div, mod = divmod(long_value, 256)\n        result = chr(mod) + result\n        long_value = div\n    result = chr(long_value) + result\n\n    nPad = 0\n    for c in v:\n        if c == __b58chars[0]: nPad += 1\n        else: break\n\n    result = chr(0)*nPad + result\n    if length is not None and len(result) != length:\n        return None\n\n    return result\n\ndef checksum(v):\n    \"\"\"Return 32-bit checksum based on SHA256\"\"\"\n    return SHA256.new(SHA256.new(v).digest()).digest()[0:4]\n\ndef b58encode_chk(v):\n    \"\"\"b58encode a string, with 32-bit checksum\"\"\"\n    return b58encode(v + checksum(v))\n\ndef b58decode_chk(v):\n    \"\"\"decode a base58 string, check and remove checksum\"\"\"\n    result = b58decode(v)\n    if result is None:\n        return None\n    if result[-4:] == checksum(result[:-4]):\n        return result[:-4]\n    else:\n        return None\n\ndef get_bcaddress_version(strAddress):\n    \"\"\" Returns None if strAddress is invalid.  Otherwise returns integer version of address. \"\"\"\n    addr = b58decode_chk(strAddress)\n    if addr is None or len(addr)!=21: return None\n    version = addr[0]\n    return ord(version)\n\nif __name__ == '__main__':\n    # Test case (from http://gitorious.org/bitcoin/python-base58.git)\n    assert get_bcaddress_version('15VjRaDX9zpbA8LVnbrCAFzrVzN7ixHNsC') is 0\n    _ohai = 'o hai'.encode('ascii')\n    _tmp = b58encode(_ohai)\n    assert _tmp == 'DYB3oMS'\n    assert b58decode(_tmp, 5) == _ohai\n    print(\"Tests passed\")\n"
  },
  {
    "path": "contrib/testgen/gen_base58_test_vectors.py",
    "content": "#!/usr/bin/env python\n# Copyright (c) 2012-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n'''\nGenerate valid and invalid base58 address and private key test vectors.\n\nUsage: \n    gen_base58_test_vectors.py valid 50 > ../../src/test/data/base58_keys_valid.json\n    gen_base58_test_vectors.py invalid 50 > ../../src/test/data/base58_keys_invalid.json\n'''\n# 2012 Wladimir J. van der Laan\n# Released under MIT License\nimport os\nfrom itertools import islice\nfrom base58 import b58encode_chk, b58decode_chk, b58chars\nimport random\nfrom binascii import b2a_hex\n\n# key types\nPUBKEY_ADDRESS = 38\nSCRIPT_ADDRESS = 98\nPUBKEY_ADDRESS_TEST = 65\nSCRIPT_ADDRESS_TEST = 127\nPRIVKEY = 38+128\nPRIVKEY_TEST = 65+128\n\nmetadata_keys = ['isPrivkey', 'isTestnet', 'addrType', 'isCompressed']\n# templates for valid sequences\ntemplates = [\n  # prefix, payload_size, suffix, metadata\n  #                                  None = N/A\n  ((PUBKEY_ADDRESS,),      20, (),   (False, False, 'pubkey', None)),\n  ((SCRIPT_ADDRESS,),      20, (),   (False, False, 'script',  None)),\n  ((PUBKEY_ADDRESS_TEST,), 20, (),   (False, True,  'pubkey', None)),\n  ((SCRIPT_ADDRESS_TEST,), 20, (),   (False, True,  'script',  None)),\n  ((PRIVKEY,),             32, (),   (True,  False, None,  False)),\n  ((PRIVKEY,),             32, (1,), (True,  False, None,  True)),\n  ((PRIVKEY_TEST,),        32, (),   (True,  True,  None,  False)),\n  ((PRIVKEY_TEST,),        32, (1,), (True,  True,  None,  True))\n]\n\ndef is_valid(v):\n    '''Check vector v for validity'''\n    result = b58decode_chk(v)\n    if result is None:\n        return False\n    for template in templates:\n        prefix = str(bytearray(template[0]))\n        suffix = str(bytearray(template[2]))\n        if result.startswith(prefix) and result.endswith(suffix):\n            if (len(result) - len(prefix) - len(suffix)) == template[1]:\n                return True\n    return False\n\ndef gen_valid_vectors():\n    '''Generate valid test vectors'''\n    while True:\n        for template in templates:\n            prefix = str(bytearray(template[0]))\n            payload = os.urandom(template[1]) \n            suffix = str(bytearray(template[2]))\n            rv = b58encode_chk(prefix + payload + suffix)\n            assert is_valid(rv)\n            metadata = dict([(x,y) for (x,y) in zip(metadata_keys,template[3]) if y is not None])\n            yield (rv, b2a_hex(payload), metadata)\n\ndef gen_invalid_vector(template, corrupt_prefix, randomize_payload_size, corrupt_suffix):\n    '''Generate possibly invalid vector'''\n    if corrupt_prefix:\n        prefix = os.urandom(1)\n    else:\n        prefix = str(bytearray(template[0]))\n    \n    if randomize_payload_size:\n        payload = os.urandom(max(int(random.expovariate(0.5)), 50))\n    else:\n        payload = os.urandom(template[1])\n    \n    if corrupt_suffix:\n        suffix = os.urandom(len(template[2]))\n    else:\n        suffix = str(bytearray(template[2]))\n\n    return b58encode_chk(prefix + payload + suffix)\n\ndef randbool(p = 0.5):\n    '''Return True with P(p)'''\n    return random.random() < p\n\ndef gen_invalid_vectors():\n    '''Generate invalid test vectors'''\n    # start with some manual edge-cases\n    yield \"\",\n    yield \"x\",\n    while True:\n        # kinds of invalid vectors:\n        #   invalid prefix\n        #   invalid payload length\n        #   invalid (randomized) suffix (add random data)\n        #   corrupt checksum\n        for template in templates:\n            val = gen_invalid_vector(template, randbool(0.2), randbool(0.2), randbool(0.2))\n            if random.randint(0,10)<1: # line corruption\n                if randbool(): # add random character to end\n                    val += random.choice(b58chars)\n                else: # replace random character in the middle\n                    n = random.randint(0, len(val))\n                    val = val[0:n] + random.choice(b58chars) + val[n+1:]\n            if not is_valid(val):\n                yield val,\n\nif __name__ == '__main__':\n    import sys, json\n    iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors}\n    try:\n        uiter = iters[sys.argv[1]]\n    except IndexError:\n        uiter = gen_valid_vectors\n    try:\n        count = int(sys.argv[2])\n    except IndexError:\n        count = 0\n   \n    data = list(islice(uiter(), count))\n    json.dump(data, sys.stdout, sort_keys=True, indent=4)\n    sys.stdout.write('\\n')\n\n"
  },
  {
    "path": "contrib/tidy_datadir.sh",
    "content": "#!/bin/bash\n# Copyright (c) 2013 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nif [ -d \"$1\" ]; then\n  cd \"$1\"\nelse\n  echo \"Usage: $0 <datadir>\" >&2\n  echo \"Removes obsolete Munt database files\" >&2\n  exit 1\nfi\n\nLEVEL=0\nif [ -f wallet.dat -a -f addr.dat -a -f blkindex.dat -a -f blk0001.dat ]; then LEVEL=1; fi\nif [ -f wallet.dat -a -f peers.dat -a -f blkindex.dat -a -f blk0001.dat ]; then LEVEL=2; fi\nif [ -f wallet.dat -a -f peers.dat -a -f coins/CURRENT -a -f blktree/CURRENT -a -f blocks/blk00000.dat ]; then LEVEL=3; fi\nif [ -f wallet.dat -a -f peers.dat -a -f chainstate/CURRENT -a -f blocks/index/CURRENT -a -f blocks/blk00000.dat ]; then LEVEL=4; fi\n\ncase $LEVEL in\n  0)\n    echo \"Error: no Munt datadir detected.\"\n    exit 1\n    ;;\n  1)\n    echo \"Detected old Munt datadir (before 0.7).\"\n    echo \"Nothing to do.\"\n    exit 0\n    ;;\n  2)\n    echo \"Detected Munt 0.7 datadir.\"\n    ;;\n  3)\n    echo \"Detected Munt pre-0.8 datadir.\"\n    ;;\n  4)\n    echo \"Detected Munt 0.8 datadir.\"\n    ;;\nesac\n\nFILES=\"\"\nDIRS=\"\"\n\nif [ $LEVEL -ge 3 ]; then FILES=$(echo $FILES blk????.dat blkindex.dat); fi\nif [ $LEVEL -ge 2 ]; then FILES=$(echo $FILES addr.dat); fi\nif [ $LEVEL -ge 4 ]; then DIRS=$(echo $DIRS coins blktree); fi\n\nfor FILE in $FILES; do\n  if [ -f $FILE ]; then\n    echo \"Deleting: $FILE\"\n    rm -f $FILE\n  fi\ndone\n\nfor DIR in $DIRS; do\n  if [ -d $DIR ]; then\n    echo \"Deleting: $DIR/\"\n    rm -rf $DIR\n  fi\ndone\n\necho \"Done.\"\n"
  },
  {
    "path": "contrib/zmq/zmq_sub.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n\"\"\"\n    ZMQ example using python3's asyncio\n\n    Bitcoin should be started with the command line arguments:\n        Munt-daemon -testnet -daemon \\\n                -zmqpubhashblock=tcp://127.0.0.1:28332 \\\n                -zmqpubrawtx=tcp://127.0.0.1:28332 \\\n                -zmqpubhashtx=tcp://127.0.0.1:28332 \\\n                -zmqpubhashblock=tcp://127.0.0.1:28332\n\n    We use the asyncio library here.  `self.handle()` installs itself as a\n    future at the end of the function.  Since it never returns with the event\n    loop having an empty stack of futures, this creates an infinite loop.  An\n    alternative is to wrap the contents of `handle` inside `while True`.\n\n    A blocking example using python 2.7 can be obtained from the git history:\n    https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py\n\"\"\"\n\nimport binascii\nimport asyncio\nimport zmq\nimport zmq.asyncio\nimport signal\nimport struct\nimport sys\n\nif not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):\n    print(\"This example only works with Python 3.5 and greater\")\n    exit(1)\n\nport = 28332\n\nclass ZMQHandler():\n    def __init__(self):\n        self.loop = zmq.asyncio.install()\n        self.zmqContext = zmq.asyncio.Context()\n\n        self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"hashblock\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"hashtx\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"rawblock\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"rawtx\")\n        self.zmqSubSocket.connect(\"tcp://127.0.0.1:%i\" % port)\n\n    async def handle(self) :\n        msg = await self.zmqSubSocket.recv_multipart()\n        topic = msg[0]\n        body = msg[1]\n        sequence = \"Unknown\"\n        if len(msg[-1]) == 4:\n          msgSequence = struct.unpack('<I', msg[-1])[-1]\n          sequence = str(msgSequence)\n        if topic == b\"hashblock\":\n            print('- HASH BLOCK ('+sequence+') -')\n            print(binascii.hexlify(body))\n        elif topic == b\"hashtx\":\n            print('- HASH TX  ('+sequence+') -')\n            print(binascii.hexlify(body))\n        elif topic == b\"rawblock\":\n            print('- RAW BLOCK HEADER ('+sequence+') -')\n            print(binascii.hexlify(body[:80]))\n        elif topic == b\"rawtx\":\n            print('- RAW TX ('+sequence+') -')\n            print(binascii.hexlify(body))\n        # schedule ourselves to receive the next message\n        asyncio.ensure_future(self.handle())\n\n    def start(self):\n        self.loop.add_signal_handler(signal.SIGINT, self.stop)\n        self.loop.create_task(self.handle())\n        self.loop.run_forever()\n\n    def stop(self):\n        self.loop.stop()\n        self.zmqContext.destroy()\n\ndaemon = ZMQHandler()\ndaemon.start()\n"
  },
  {
    "path": "contrib/zmq/zmq_sub3.4.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n\"\"\"\n    ZMQ example using python3's asyncio\n\n    Bitcoin should be started with the command line arguments:\n        Munt-deamon -testnet -daemon \\\n                -zmqpubhashblock=tcp://127.0.0.1:28332 \\\n                -zmqpubrawtx=tcp://127.0.0.1:28332 \\\n                -zmqpubhashtx=tcp://127.0.0.1:28332 \\\n                -zmqpubhashblock=tcp://127.0.0.1:28332\n\n    We use the asyncio library here.  `self.handle()` installs itself as a\n    future at the end of the function.  Since it never returns with the event\n    loop having an empty stack of futures, this creates an infinite loop.  An\n    alternative is to wrap the contents of `handle` inside `while True`.\n\n    The `@asyncio.coroutine` decorator and the `yield from` syntax found here\n    was introduced in python 3.4 and has been deprecated in favor of the `async`\n    and `await` keywords respectively.\n\n    A blocking example using python 2.7 can be obtained from the git history:\n    https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py\n\"\"\"\n\nimport binascii\nimport asyncio\nimport zmq\nimport zmq.asyncio\nimport signal\nimport struct\nimport sys\n\nif not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):\n    print(\"This example only works with Python 3.4 and greater\")\n    exit(1)\n\nport = 28332\n\nclass ZMQHandler():\n    def __init__(self):\n        self.loop = zmq.asyncio.install()\n        self.zmqContext = zmq.asyncio.Context()\n\n        self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"hashblock\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"hashtx\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"rawblock\")\n        self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, \"rawtx\")\n        self.zmqSubSocket.connect(\"tcp://127.0.0.1:%i\" % port)\n\n    @asyncio.coroutine\n    def handle(self) :\n        msg = yield from self.zmqSubSocket.recv_multipart()\n        topic = msg[0]\n        body = msg[1]\n        sequence = \"Unknown\"\n        if len(msg[-1]) == 4:\n          msgSequence = struct.unpack('<I', msg[-1])[-1]\n          sequence = str(msgSequence)\n        if topic == b\"hashblock\":\n            print('- HASH BLOCK ('+sequence+') -')\n            print(binascii.hexlify(body))\n        elif topic == b\"hashtx\":\n            print('- HASH TX  ('+sequence+') -')\n            print(binascii.hexlify(body))\n        elif topic == b\"rawblock\":\n            print('- RAW BLOCK HEADER ('+sequence+') -')\n            print(binascii.hexlify(body[:80]))\n        elif topic == b\"rawtx\":\n            print('- RAW TX ('+sequence+') -')\n            print(binascii.hexlify(body))\n        # schedule ourselves to receive the next message\n        asyncio.ensure_future(self.handle())\n\n    def start(self):\n        self.loop.add_signal_handler(signal.SIGINT, self.stop)\n        self.loop.create_task(self.handle())\n        self.loop.run_forever()\n\n    def stop(self):\n        self.loop.stop()\n        self.zmqContext.destroy()\n\ndaemon = ZMQHandler()\ndaemon.start()\n"
  },
  {
    "path": "dependabot.yml",
    "content": "# Specify a non-default branch for pull requests\n\nversion: 2\nupdates:\n  - package-ecosystem: \"npm\"\n    directory: \"src/frontend/electron_vue\"\n    schedule:\n      interval: \"daily\"\n    # Raise pull requests for version updates against the `develop` branch\n    target-branch: \"develop\"\n    # Labels on pull requests for version updates only\n    labels:\n      - \"electron frontend dependencies\"\n"
  },
  {
    "path": "depends/.gitignore",
    "content": "SDKs/\nwork/\nbuilt/\nsources/\nconfig.site\nx86_64*\ni686*\nmips*\narm*\naarch64*\npowerpc*\nriscv32*\nriscv64*\ns390x*\n"
  },
  {
    "path": "depends/README.md",
    "content": "### Usage\n\nTo build dependencies for the current arch+OS:\n\n    make\n\nTo build for another arch/OS:\n\n    make HOST=host-platform-triplet\n\nFor example:\n\n    make HOST=x86_64-w64-mingw32 -j4\n\nA prefix will be generated that's suitable for plugging into Munt's\nconfigure. In the above example, a dir named x86_64-w64-mingw32 will be\ncreated. To use it for Munt:\n\n    ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32\n\nCommon `host-platform-triplets` for cross compilation are:\n\n- `i686-w64-mingw32` for Win32\n- `x86_64-w64-mingw32` for Win64\n- `x86_64-apple-darwin14` for macOS\n- `arm-linux-gnueabihf` for Linux ARM 32 bit\n- `aarch64-linux-gnu` for Linux ARM 64 bit\n- `riscv32-linux-gnu` for Linux RISC-V 32 bit\n- `riscv64-linux-gnu` for Linux RISC-V 64 bit\n\nNo other options are needed, the paths are automatically configured.\n\n### Install the required dependencies: Ubuntu & Debian\n\n#### For macOS cross compilation\n\n    sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools\n\n#### For Win32/Win64 cross compilation\n\n- see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux)\n\n#### For linux (including i386, ARM) cross compilation\n\nCommon linux dependencies:\n\n    sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3\n\nFor linux ARM cross compilation:\n\n    sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf\n\nFor linux AARCH64 cross compilation:\n\n    sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu\n\nFor linux RISC-V 64-bit cross compilation (there are no packages for 32-bit):\n\n    sudo apt-get install g++-riscv64-linux-gnu binutils-riscv64-linux-gnu\n\nRISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_bitcoin` executable (see https://github.com/bitcoin/bitcoin/pull/13543),\nthis is apparently fixed in gcc-8.1.0.\n\n### Dependency Options\nThe following can be set when running make: make FOO=bar\n\n    SOURCES_PATH: downloaded sources will be placed here\n    BASE_CACHE: built packages will be placed here\n    SDK_PATH: Path where sdk's can be found (used by macOS)\n    FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up\n    NO_QT: Don't download/build/cache qt and its dependencies\n    NO_WALLET: Don't download/build/cache libs needed to enable the wallet\n    NO_UPNP: Don't download/build/cache packages needed for enabling upnp\n    DEBUG: disable some optimizations and enable more runtime checking\n    RAPIDCHECK: build rapidcheck (experimental, requires cmake)\n    HOST_ID_SALT: Optional salt to use when generating host package ids\n    BUILD_ID_SALT: Optional salt to use when generating build package ids\n\nIf some packages are not built, for example `make NO_WALLET=1`, the appropriate\noptions will be passed to Munt's configure. In this case, `--disable-wallet`.\n\n### Additional targets\n\n    download: run 'make download' to fetch all sources without building them\n    download-osx: run 'make download-osx' to fetch all sources needed for macOS builds\n    download-win: run 'make download-win' to fetch all sources needed for win builds\n    download-linux: run 'make download-linux' to fetch all sources needed for linux builds\n\n### Other documentation\n\n- [description.md](description.md): General description of the depends system\n- [packages.md](packages.md): Steps for adding packages\n\n"
  },
  {
    "path": "depends/builders/darwin.mk",
    "content": "OSX_MIN_VERSION=10.10\nOSX_SDK_VERSION?=12.0\nOSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk\nOSX_SYSROOT=--sysroot $(OSX_SDK)\n\nbuild_darwin_CC:=$(shell xcrun -f clang)\nbuild_darwin_CXX:=$(shell xcrun -f clang++)\nbuild_darwin_AR:=$(shell xcrun -f ar)\nbuild_darwin_RANLIB:=$(shell xcrun -f ranlib)\nbuild_darwin_STRIP:=$(shell xcrun -f strip)\nbuild_darwin_OTOOL:=$(shell xcrun -f otool)\nbuild_darwin_NM:=$(shell xcrun -f nm)\nbuild_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool)\nbuild_darwin_SHA256SUM=shasum -a 256\nbuild_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o\n\n#darwin host on darwin builder. overrides darwin host preferences.\ndarwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) $(OSX_SYSROOT)\ndarwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ $(OSX_SYSROOT)\ndarwin_AR:=$(shell xcrun -f ar)\ndarwin_RANLIB:=$(shell xcrun -f ranlib)\ndarwin_STRIP:=$(shell xcrun -f strip)\ndarwin_LIBTOOL:=$(shell xcrun -f libtool)\ndarwin_OTOOL:=$(shell xcrun -f otool)\ndarwin_NM:=$(shell xcrun -f nm)\ndarwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool)\ndarwin_native_binutils=\ndarwin_native_toolchain=\n"
  },
  {
    "path": "depends/builders/default.mk",
    "content": "default_build_CC = gcc\ndefault_build_CXX = g++\ndefault_build_AR = ar\ndefault_build_TAR = tar\ndefault_build_RANLIB = ranlib\ndefault_build_STRIP = strip\ndefault_build_NM = nm\ndefault_build_OTOOL = otool\ndefault_build_INSTALL_NAME_TOOL = install_name_tool\n\ndefine add_build_tool_func\nbuild_$(build_os)_$1 ?= $$(default_build_$1)\nbuild_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1)\nbuild_$1=$$(build_$(build_arch)_$(build_os)_$1)\nendef\n$(foreach var,CC CXX AR TAR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var))))\ndefine add_build_flags_func\nbuild_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1)\nbuild_$1=$$(build_$(build_arch)_$(build_os)_$1)\nendef\n$(foreach flags, CFLAGS CXXFLAGS LDFLAGS, $(eval $(call add_build_flags_func,$(flags))))\n"
  },
  {
    "path": "depends/builders/linux.mk",
    "content": "build_linux_SHA256SUM = sha256sum\nbuild_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o\n"
  },
  {
    "path": "depends/builders/mingw32.mk",
    "content": "build_mingw32_SHA256SUM = sha256sum.exe\nbuild_mingw32_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o\n\nmingw32_CC=gcc.exe\nmingw32_CXX:=g++.exe\n\nbuild_mingw32_BINARYEXT=.exe\n"
  },
  {
    "path": "depends/builders/mingw64.mk",
    "content": "build_mingw64_SHA256SUM = sha256sum.exe\nbuild_mingw64_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o\n\nmingw64_CC=gcc.exe\nmingw64_CXX:=g++.exe\n\nbuild_mingw64_BINARYEXT=.exe\n\n"
  },
  {
    "path": "depends/config.guess",
    "content": "#! /bin/sh\n# Attempt to guess a canonical system name.\n#   Copyright 1992-2021 Free Software Foundation, Inc.\n\ntimestamp='2021-05-24'\n\n# This file is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that\n# program.  This Exception is an additional permission under section 7\n# of the GNU General Public License, version 3 (\"GPLv3\").\n#\n# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.\n#\n# You can get the latest version of this script from:\n# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess\n#\n# Please send patches to <config-patches@gnu.org>.\n\n\nme=$(echo \"$0\" | sed -e 's,.*/,,')\n\nusage=\"\\\nUsage: $0 [OPTION]\n\nOutput the configuration name of the system \\`$me' is run on.\n\nOptions:\n  -h, --help         print this help, then exit\n  -t, --time-stamp   print date of last modification, then exit\n  -v, --version      print version number, then exit\n\nReport bugs and patches to <config-patches@gnu.org>.\"\n\nversion=\"\\\nGNU config.guess ($timestamp)\n\nOriginally written by Per Bothner.\nCopyright 1992-2021 Free Software Foundation, Inc.\n\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\"\n\nhelp=\"\nTry \\`$me --help' for more information.\"\n\n# Parse command line\nwhile test $# -gt 0 ; do\n  case $1 in\n    --time-stamp | --time* | -t )\n       echo \"$timestamp\" ; exit ;;\n    --version | -v )\n       echo \"$version\" ; exit ;;\n    --help | --h* | -h )\n       echo \"$usage\"; exit ;;\n    -- )     # Stop option processing\n       shift; break ;;\n    - )\t# Use stdin as input.\n       break ;;\n    -* )\n       echo \"$me: invalid option $1$help\" >&2\n       exit 1 ;;\n    * )\n       break ;;\n  esac\ndone\n\nif test $# != 0; then\n  echo \"$me: too many arguments$help\" >&2\n  exit 1\nfi\n\n# CC_FOR_BUILD -- compiler used by this script. Note that the use of a\n# compiler to aid in system detection is discouraged as it requires\n# temporary files to be created and, as you can see below, it is a\n# headache to deal with in a portable fashion.\n\n# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still\n# use `HOST_CC' if defined, but it is deprecated.\n\n# Portable tmp directory creation inspired by the Autoconf team.\n\ntmp=\n# shellcheck disable=SC2172\ntrap 'test -z \"$tmp\" || rm -fr \"$tmp\"' 0 1 2 13 15\n\nset_cc_for_build() {\n    # prevent multiple calls if $tmp is already set\n    test \"$tmp\" && return 0\n    : \"${TMPDIR=/tmp}\"\n    # shellcheck disable=SC2039\n    { tmp=$( (umask 077 && mktemp -d \"$TMPDIR/cgXXXXXX\") 2>/dev/null) && test -n \"$tmp\" && test -d \"$tmp\" ; } ||\n\t{ test -n \"$RANDOM\" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir \"$tmp\" 2>/dev/null) ; } ||\n\t{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir \"$tmp\" 2>/dev/null) && echo \"Warning: creating insecure temp directory\" >&2 ; } ||\n\t{ echo \"$me: cannot create a temporary directory in $TMPDIR\" >&2 ; exit 1 ; }\n    dummy=$tmp/dummy\n    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in\n\t,,)    echo \"int x;\" > \"$dummy.c\"\n\t       for driver in cc gcc c89 c99 ; do\n\t\t   if ($driver -c -o \"$dummy.o\" \"$dummy.c\") >/dev/null 2>&1 ; then\n\t\t       CC_FOR_BUILD=\"$driver\"\n\t\t       break\n\t\t   fi\n\t       done\n\t       if test x\"$CC_FOR_BUILD\" = x ; then\n\t\t   CC_FOR_BUILD=no_compiler_found\n\t       fi\n\t       ;;\n\t,,*)   CC_FOR_BUILD=$CC ;;\n\t,*,*)  CC_FOR_BUILD=$HOST_CC ;;\n    esac\n}\n\n# This is needed to find uname on a Pyramid OSx when run in the BSD universe.\n# (ghazi@noc.rutgers.edu 1994-08-24)\nif test -f /.attbin/uname ; then\n\tPATH=$PATH:/.attbin ; export PATH\nfi\n\nUNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown\nUNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown\nUNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown\nUNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown\n\ncase $UNAME_SYSTEM in\nLinux|GNU|GNU/*)\n\tLIBC=unknown\n\n\tset_cc_for_build\n\tcat <<-EOF > \"$dummy.c\"\n\t#include <features.h>\n\t#if defined(__UCLIBC__)\n\tLIBC=uclibc\n\t#elif defined(__dietlibc__)\n\tLIBC=dietlibc\n\t#elif defined(__GLIBC__)\n\tLIBC=gnu\n\t#else\n\t#include <stdarg.h>\n\t/* First heuristic to detect musl libc.  */\n\t#ifdef __DEFINED_va_list\n\tLIBC=musl\n\t#endif\n\t#endif\n\tEOF\n\teval \"$($CC_FOR_BUILD -E \"$dummy.c\" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')\"\n\n\t# Second heuristic to detect musl libc.\n\tif [ \"$LIBC\" = unknown ] &&\n\t   command -v ldd >/dev/null &&\n\t   ldd --version 2>&1 | grep -q ^musl; then\n\t\tLIBC=musl\n\tfi\n\n\t# If the system lacks a compiler, then just pick glibc.\n\t# We could probably try harder.\n\tif [ \"$LIBC\" = unknown ]; then\n\t\tLIBC=gnu\n\tfi\n\t;;\nesac\n\n# Note: order is significant - the case branches are not exclusive.\n\ncase $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in\n    *:NetBSD:*:*)\n\t# NetBSD (nbsd) targets should (where applicable) match one or\n\t# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,\n\t# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently\n\t# switched to ELF, *-*-netbsd* would select the old\n\t# object file format.  This provides both forward\n\t# compatibility and a consistent mechanism for selecting the\n\t# object file format.\n\t#\n\t# Note: NetBSD doesn't particularly care about the vendor\n\t# portion of the name.  We always set it to \"unknown\".\n\tUNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \\\n\t    /sbin/sysctl -n hw.machine_arch 2>/dev/null || \\\n\t    /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \\\n\t    echo unknown))\n\tcase $UNAME_MACHINE_ARCH in\n\t    aarch64eb) machine=aarch64_be-unknown ;;\n\t    armeb) machine=armeb-unknown ;;\n\t    arm*) machine=arm-unknown ;;\n\t    sh3el) machine=shl-unknown ;;\n\t    sh3eb) machine=sh-unknown ;;\n\t    sh5el) machine=sh5le-unknown ;;\n\t    earmv*)\n\t\tarch=$(echo \"$UNAME_MACHINE_ARCH\" | sed -e 's,^e\\(armv[0-9]\\).*$,\\1,')\n\t\tendian=$(echo \"$UNAME_MACHINE_ARCH\" | sed -ne 's,^.*\\(eb\\)$,\\1,p')\n\t\tmachine=\"${arch}${endian}\"-unknown\n\t\t;;\n\t    *) machine=\"$UNAME_MACHINE_ARCH\"-unknown ;;\n\tesac\n\t# The Operating System including object format, if it has switched\n\t# to ELF recently (or will in the future) and ABI.\n\tcase $UNAME_MACHINE_ARCH in\n\t    earm*)\n\t\tos=netbsdelf\n\t\t;;\n\t    arm*|i386|m68k|ns32k|sh3*|sparc|vax)\n\t\tset_cc_for_build\n\t\tif echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t\t\t| grep -q __ELF__\n\t\tthen\n\t\t    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).\n\t\t    # Return netbsd for either.  FIX?\n\t\t    os=netbsd\n\t\telse\n\t\t    os=netbsdelf\n\t\tfi\n\t\t;;\n\t    *)\n\t\tos=netbsd\n\t\t;;\n\tesac\n\t# Determine ABI tags.\n\tcase $UNAME_MACHINE_ARCH in\n\t    earm*)\n\t\texpr='s/^earmv[0-9]/-eabi/;s/eb$//'\n\t\tabi=$(echo \"$UNAME_MACHINE_ARCH\" | sed -e \"$expr\")\n\t\t;;\n\tesac\n\t# The OS release\n\t# Debian GNU/NetBSD machines have a different userland, and\n\t# thus, need a distinct triplet. However, they do not need\n\t# kernel version information, so it can be replaced with a\n\t# suitable tag, in the style of linux-gnu.\n\tcase $UNAME_VERSION in\n\t    Debian*)\n\t\trelease='-gnu'\n\t\t;;\n\t    *)\n\t\trelease=$(echo \"$UNAME_RELEASE\" | sed -e 's/[-_].*//' | cut -d. -f1,2)\n\t\t;;\n\tesac\n\t# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:\n\t# contains redundant information, the shorter form:\n\t# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.\n\techo \"$machine-${os}${release}${abi-}\"\n\texit ;;\n    *:Bitrig:*:*)\n\tUNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')\n\techo \"$UNAME_MACHINE_ARCH\"-unknown-bitrig\"$UNAME_RELEASE\"\n\texit ;;\n    *:OpenBSD:*:*)\n\tUNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')\n\techo \"$UNAME_MACHINE_ARCH\"-unknown-openbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:SecBSD:*:*)\n\tUNAME_MACHINE_ARCH=$(arch | sed 's/SecBSD.//')\n\techo \"$UNAME_MACHINE_ARCH\"-unknown-secbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:LibertyBSD:*:*)\n\tUNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\\.//')\n\techo \"$UNAME_MACHINE_ARCH\"-unknown-libertybsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:MidnightBSD:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-midnightbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:ekkoBSD:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-ekkobsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:SolidBSD:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-solidbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:OS108:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-os108_\"$UNAME_RELEASE\"\n\texit ;;\n    macppc:MirBSD:*:*)\n\techo powerpc-unknown-mirbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:MirBSD:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-mirbsd\"$UNAME_RELEASE\"\n\texit ;;\n    *:Sortix:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-sortix\n\texit ;;\n    *:Twizzler:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-twizzler\n\texit ;;\n    *:Redox:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-redox\n\texit ;;\n    mips:OSF1:*.*)\n\techo mips-dec-osf1\n\texit ;;\n    alpha:OSF1:*:*)\n\t# Reset EXIT trap before exiting to avoid spurious non-zero exit code.\n\ttrap '' 0\n\tcase $UNAME_RELEASE in\n\t*4.0)\n\t\tUNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')\n\t\t;;\n\t*5.*)\n\t\tUNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')\n\t\t;;\n\tesac\n\t# According to Compaq, /usr/sbin/psrinfo has been available on\n\t# OSF/1 and Tru64 systems produced since 1995.  I hope that\n\t# covers most systems running today.  This code pipes the CPU\n\t# types through head -n 1, so we only detect the type of CPU 0.\n\tALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \\(.*\\) processor.*$/\\1/p' | head -n 1)\n\tcase $ALPHA_CPU_TYPE in\n\t    \"EV4 (21064)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"EV4.5 (21064)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"LCA4 (21066/21068)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"EV5 (21164)\")\n\t\tUNAME_MACHINE=alphaev5 ;;\n\t    \"EV5.6 (21164A)\")\n\t\tUNAME_MACHINE=alphaev56 ;;\n\t    \"EV5.6 (21164PC)\")\n\t\tUNAME_MACHINE=alphapca56 ;;\n\t    \"EV5.7 (21164PC)\")\n\t\tUNAME_MACHINE=alphapca57 ;;\n\t    \"EV6 (21264)\")\n\t\tUNAME_MACHINE=alphaev6 ;;\n\t    \"EV6.7 (21264A)\")\n\t\tUNAME_MACHINE=alphaev67 ;;\n\t    \"EV6.8CB (21264C)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.8AL (21264B)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.8CX (21264D)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.9A (21264/EV69A)\")\n\t\tUNAME_MACHINE=alphaev69 ;;\n\t    \"EV7 (21364)\")\n\t\tUNAME_MACHINE=alphaev7 ;;\n\t    \"EV7.9 (21364A)\")\n\t\tUNAME_MACHINE=alphaev79 ;;\n\tesac\n\t# A Pn.n version is a patched version.\n\t# A Vn.n version is a released version.\n\t# A Tn.n version is a released field test version.\n\t# A Xn.n version is an unreleased experimental baselevel.\n\t# 1.2 uses \"1.2\" for uname -r.\n\techo \"$UNAME_MACHINE\"-dec-osf\"$(echo \"$UNAME_RELEASE\" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)\"\n\texit ;;\n    Amiga*:UNIX_System_V:4.0:*)\n\techo m68k-unknown-sysv4\n\texit ;;\n    *:[Aa]miga[Oo][Ss]:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-amigaos\n\texit ;;\n    *:[Mm]orph[Oo][Ss]:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-morphos\n\texit ;;\n    *:OS/390:*:*)\n\techo i370-ibm-openedition\n\texit ;;\n    *:z/VM:*:*)\n\techo s390-ibm-zvmoe\n\texit ;;\n    *:OS400:*:*)\n\techo powerpc-ibm-os400\n\texit ;;\n    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)\n\techo arm-acorn-riscix\"$UNAME_RELEASE\"\n\texit ;;\n    arm*:riscos:*:*|arm*:RISCOS:*:*)\n\techo arm-unknown-riscos\n\texit ;;\n    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)\n\techo hppa1.1-hitachi-hiuxmpp\n\texit ;;\n    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)\n\t# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.\n\tif test \"$( (/bin/universe) 2>/dev/null)\" = att ; then\n\t\techo pyramid-pyramid-sysv3\n\telse\n\t\techo pyramid-pyramid-bsd\n\tfi\n\texit ;;\n    NILE*:*:*:dcosx)\n\techo pyramid-pyramid-svr4\n\texit ;;\n    DRS?6000:unix:4.0:6*)\n\techo sparc-icl-nx6\n\texit ;;\n    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)\n\tcase $(/usr/bin/uname -p) in\n\t    sparc) echo sparc-icl-nx7; exit ;;\n\tesac ;;\n    s390x:SunOS:*:*)\n\techo \"$UNAME_MACHINE\"-ibm-solaris2\"$(echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//')\"\n\texit ;;\n    sun4H:SunOS:5.*:*)\n\techo sparc-hal-solaris2\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*//')\"\n\texit ;;\n    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)\n\techo sparc-sun-solaris2\"$(echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//')\"\n\texit ;;\n    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)\n\techo i386-pc-auroraux\"$UNAME_RELEASE\"\n\texit ;;\n    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)\n\tset_cc_for_build\n\tSUN_ARCH=i386\n\t# If there is a compiler, see if it is configured for 64-bit objects.\n\t# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.\n\t# This test works for both compilers.\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \\\n\t\t(CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\tgrep IS_64BIT_ARCH >/dev/null\n\t    then\n\t\tSUN_ARCH=x86_64\n\t    fi\n\tfi\n\techo \"$SUN_ARCH\"-pc-solaris2\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*//')\"\n\texit ;;\n    sun4*:SunOS:6*:*)\n\t# According to config.sub, this is the proper way to canonicalize\n\t# SunOS6.  Hard to guess exactly what SunOS6 will be like, but\n\t# it's likely to be more like Solaris than SunOS4.\n\techo sparc-sun-solaris3\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*//')\"\n\texit ;;\n    sun4*:SunOS:*:*)\n\tcase $(/usr/bin/arch -k) in\n\t    Series*|S4*)\n\t\tUNAME_RELEASE=$(uname -v)\n\t\t;;\n\tesac\n\t# Japanese Language versions have a version number like `4.1.3-JL'.\n\techo sparc-sun-sunos\"$(echo \"$UNAME_RELEASE\"|sed -e 's/-/_/')\"\n\texit ;;\n    sun3*:SunOS:*:*)\n\techo m68k-sun-sunos\"$UNAME_RELEASE\"\n\texit ;;\n    sun*:*:4.2BSD:*)\n\tUNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)\n\ttest \"x$UNAME_RELEASE\" = x && UNAME_RELEASE=3\n\tcase $(/bin/arch) in\n\t    sun3)\n\t\techo m68k-sun-sunos\"$UNAME_RELEASE\"\n\t\t;;\n\t    sun4)\n\t\techo sparc-sun-sunos\"$UNAME_RELEASE\"\n\t\t;;\n\tesac\n\texit ;;\n    aushp:SunOS:*:*)\n\techo sparc-auspex-sunos\"$UNAME_RELEASE\"\n\texit ;;\n    # The situation for MiNT is a little confusing.  The machine name\n    # can be virtually everything (everything which is not\n    # \"atarist\" or \"atariste\" at least should have a processor\n    # > m68000).  The system name ranges from \"MiNT\" over \"FreeMiNT\"\n    # to the lowercase version \"mint\" (or \"freemint\").  Finally\n    # the system name \"TOS\" denotes a system which is actually not\n    # MiNT.  But MiNT is downward compatible to TOS, so this should\n    # be no problem.\n    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)\n\techo m68k-atari-mint\"$UNAME_RELEASE\"\n\texit ;;\n    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)\n\techo m68k-atari-mint\"$UNAME_RELEASE\"\n\texit ;;\n    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)\n\techo m68k-atari-mint\"$UNAME_RELEASE\"\n\texit ;;\n    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)\n\techo m68k-milan-mint\"$UNAME_RELEASE\"\n\texit ;;\n    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)\n\techo m68k-hades-mint\"$UNAME_RELEASE\"\n\texit ;;\n    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)\n\techo m68k-unknown-mint\"$UNAME_RELEASE\"\n\texit ;;\n    m68k:machten:*:*)\n\techo m68k-apple-machten\"$UNAME_RELEASE\"\n\texit ;;\n    powerpc:machten:*:*)\n\techo powerpc-apple-machten\"$UNAME_RELEASE\"\n\texit ;;\n    RISC*:Mach:*:*)\n\techo mips-dec-mach_bsd4.3\n\texit ;;\n    RISC*:ULTRIX:*:*)\n\techo mips-dec-ultrix\"$UNAME_RELEASE\"\n\texit ;;\n    VAX*:ULTRIX*:*:*)\n\techo vax-dec-ultrix\"$UNAME_RELEASE\"\n\texit ;;\n    2020:CLIX:*:* | 2430:CLIX:*:*)\n\techo clipper-intergraph-clix\"$UNAME_RELEASE\"\n\texit ;;\n    mips:*:*:UMIPS | mips:*:*:RISCos)\n\tset_cc_for_build\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n#ifdef __cplusplus\n#include <stdio.h>  /* for printf() prototype */\n\tint main (int argc, char *argv[]) {\n#else\n\tint main (argc, argv) int argc; char *argv[]; {\n#endif\n\t#if defined (host_mips) && defined (MIPSEB)\n\t#if defined (SYSTYPE_SYSV)\n\t  printf (\"mips-mips-riscos%ssysv\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#if defined (SYSTYPE_SVR4)\n\t  printf (\"mips-mips-riscos%ssvr4\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)\n\t  printf (\"mips-mips-riscos%sbsd\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#endif\n\t  exit (-1);\n\t}\nEOF\n\t$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" &&\n\t  dummyarg=$(echo \"$UNAME_RELEASE\" | sed -n 's/\\([0-9]*\\).*/\\1/p') &&\n\t  SYSTEM_NAME=$(\"$dummy\" \"$dummyarg\") &&\n\t    { echo \"$SYSTEM_NAME\"; exit; }\n\techo mips-mips-riscos\"$UNAME_RELEASE\"\n\texit ;;\n    Motorola:PowerMAX_OS:*:*)\n\techo powerpc-motorola-powermax\n\texit ;;\n    Motorola:*:4.3:PL8-*)\n\techo powerpc-harris-powermax\n\texit ;;\n    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)\n\techo powerpc-harris-powermax\n\texit ;;\n    Night_Hawk:Power_UNIX:*:*)\n\techo powerpc-harris-powerunix\n\texit ;;\n    m88k:CX/UX:7*:*)\n\techo m88k-harris-cxux7\n\texit ;;\n    m88k:*:4*:R4*)\n\techo m88k-motorola-sysv4\n\texit ;;\n    m88k:*:3*:R3*)\n\techo m88k-motorola-sysv3\n\texit ;;\n    AViiON:dgux:*:*)\n\t# DG/UX returns AViiON for all architectures\n\tUNAME_PROCESSOR=$(/usr/bin/uname -p)\n\tif test \"$UNAME_PROCESSOR\" = mc88100 || test \"$UNAME_PROCESSOR\" = mc88110\n\tthen\n\t    if test \"$TARGET_BINARY_INTERFACE\"x = m88kdguxelfx || \\\n\t       test \"$TARGET_BINARY_INTERFACE\"x = x\n\t    then\n\t\techo m88k-dg-dgux\"$UNAME_RELEASE\"\n\t    else\n\t\techo m88k-dg-dguxbcs\"$UNAME_RELEASE\"\n\t    fi\n\telse\n\t    echo i586-dg-dgux\"$UNAME_RELEASE\"\n\tfi\n\texit ;;\n    M88*:DolphinOS:*:*)\t# DolphinOS (SVR3)\n\techo m88k-dolphin-sysv3\n\texit ;;\n    M88*:*:R3*:*)\n\t# Delta 88k system running SVR3\n\techo m88k-motorola-sysv3\n\texit ;;\n    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)\n\techo m88k-tektronix-sysv3\n\texit ;;\n    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)\n\techo m68k-tektronix-bsd\n\texit ;;\n    *:IRIX*:*:*)\n\techo mips-sgi-irix\"$(echo \"$UNAME_RELEASE\"|sed -e 's/-/_/g')\"\n\texit ;;\n    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.\n\techo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id\n\texit ;;               # Note that: echo \"'$(uname -s)'\" gives 'AIX '\n    i*86:AIX:*:*)\n\techo i386-ibm-aix\n\texit ;;\n    ia64:AIX:*:*)\n\tif test -x /usr/bin/oslevel ; then\n\t\tIBM_REV=$(/usr/bin/oslevel)\n\telse\n\t\tIBM_REV=\"$UNAME_VERSION.$UNAME_RELEASE\"\n\tfi\n\techo \"$UNAME_MACHINE\"-ibm-aix\"$IBM_REV\"\n\texit ;;\n    *:AIX:2:3)\n\tif grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then\n\t\tset_cc_for_build\n\t\tsed 's/^\t\t//' << EOF > \"$dummy.c\"\n\t\t#include <sys/systemcfg.h>\n\n\t\tmain()\n\t\t\t{\n\t\t\tif (!__power_pc())\n\t\t\t\texit(1);\n\t\t\tputs(\"powerpc-ibm-aix3.2.5\");\n\t\t\texit(0);\n\t\t\t}\nEOF\n\t\tif $CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" && SYSTEM_NAME=$(\"$dummy\")\n\t\tthen\n\t\t\techo \"$SYSTEM_NAME\"\n\t\telse\n\t\t\techo rs6000-ibm-aix3.2.5\n\t\tfi\n\telif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then\n\t\techo rs6000-ibm-aix3.2.4\n\telse\n\t\techo rs6000-ibm-aix3.2\n\tfi\n\texit ;;\n    *:AIX:*:[4567])\n\tIBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')\n\tif /usr/sbin/lsattr -El \"$IBM_CPU_ID\" | grep ' POWER' >/dev/null 2>&1; then\n\t\tIBM_ARCH=rs6000\n\telse\n\t\tIBM_ARCH=powerpc\n\tfi\n\tif test -x /usr/bin/lslpp ; then\n\t\tIBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |\n\t\t\t   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)\n\telse\n\t\tIBM_REV=\"$UNAME_VERSION.$UNAME_RELEASE\"\n\tfi\n\techo \"$IBM_ARCH\"-ibm-aix\"$IBM_REV\"\n\texit ;;\n    *:AIX:*:*)\n\techo rs6000-ibm-aix\n\texit ;;\n    ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)\n\techo romp-ibm-bsd4.4\n\texit ;;\n    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and\n\techo romp-ibm-bsd\"$UNAME_RELEASE\"   # 4.3 with uname added to\n\texit ;;                             # report: romp-ibm BSD 4.3\n    *:BOSX:*:*)\n\techo rs6000-bull-bosx\n\texit ;;\n    DPX/2?00:B.O.S.:*:*)\n\techo m68k-bull-sysv3\n\texit ;;\n    9000/[34]??:4.3bsd:1.*:*)\n\techo m68k-hp-bsd\n\texit ;;\n    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)\n\techo m68k-hp-bsd4.4\n\texit ;;\n    9000/[34678]??:HP-UX:*:*)\n\tHPUX_REV=$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*.[0B]*//')\n\tcase $UNAME_MACHINE in\n\t    9000/31?)            HP_ARCH=m68000 ;;\n\t    9000/[34]??)         HP_ARCH=m68k ;;\n\t    9000/[678][0-9][0-9])\n\t\tif test -x /usr/bin/getconf; then\n\t\t    sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)\n\t\t    sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)\n\t\t    case $sc_cpu_version in\n\t\t      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0\n\t\t      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1\n\t\t      532)                      # CPU_PA_RISC2_0\n\t\t\tcase $sc_kernel_bits in\n\t\t\t  32) HP_ARCH=hppa2.0n ;;\n\t\t\t  64) HP_ARCH=hppa2.0w ;;\n\t\t\t  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20\n\t\t\tesac ;;\n\t\t    esac\n\t\tfi\n\t\tif test \"$HP_ARCH\" = \"\"; then\n\t\t    set_cc_for_build\n\t\t    sed 's/^\t\t//' << EOF > \"$dummy.c\"\n\n\t\t#define _HPUX_SOURCE\n\t\t#include <stdlib.h>\n\t\t#include <unistd.h>\n\n\t\tint main ()\n\t\t{\n\t\t#if defined(_SC_KERNEL_BITS)\n\t\t    long bits = sysconf(_SC_KERNEL_BITS);\n\t\t#endif\n\t\t    long cpu  = sysconf (_SC_CPU_VERSION);\n\n\t\t    switch (cpu)\n\t\t\t{\n\t\t\tcase CPU_PA_RISC1_0: puts (\"hppa1.0\"); break;\n\t\t\tcase CPU_PA_RISC1_1: puts (\"hppa1.1\"); break;\n\t\t\tcase CPU_PA_RISC2_0:\n\t\t#if defined(_SC_KERNEL_BITS)\n\t\t\t    switch (bits)\n\t\t\t\t{\n\t\t\t\tcase 64: puts (\"hppa2.0w\"); break;\n\t\t\t\tcase 32: puts (\"hppa2.0n\"); break;\n\t\t\t\tdefault: puts (\"hppa2.0\"); break;\n\t\t\t\t} break;\n\t\t#else  /* !defined(_SC_KERNEL_BITS) */\n\t\t\t    puts (\"hppa2.0\"); break;\n\t\t#endif\n\t\t\tdefault: puts (\"hppa1.0\"); break;\n\t\t\t}\n\t\t    exit (0);\n\t\t}\nEOF\n\t\t    (CCOPTS=\"\" $CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" 2>/dev/null) && HP_ARCH=$(\"$dummy\")\n\t\t    test -z \"$HP_ARCH\" && HP_ARCH=hppa\n\t\tfi ;;\n\tesac\n\tif test \"$HP_ARCH\" = hppa2.0w\n\tthen\n\t    set_cc_for_build\n\n\t    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating\n\t    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler\n\t    # generating 64-bit code.  GNU and HP use different nomenclature:\n\t    #\n\t    # $ CC_FOR_BUILD=cc ./config.guess\n\t    # => hppa2.0w-hp-hpux11.23\n\t    # $ CC_FOR_BUILD=\"cc +DA2.0w\" ./config.guess\n\t    # => hppa64-hp-hpux11.23\n\n\t    if echo __LP64__ | (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) |\n\t\tgrep -q __LP64__\n\t    then\n\t\tHP_ARCH=hppa2.0w\n\t    else\n\t\tHP_ARCH=hppa64\n\t    fi\n\tfi\n\techo \"$HP_ARCH\"-hp-hpux\"$HPUX_REV\"\n\texit ;;\n    ia64:HP-UX:*:*)\n\tHPUX_REV=$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*.[0B]*//')\n\techo ia64-hp-hpux\"$HPUX_REV\"\n\texit ;;\n    3050*:HI-UX:*:*)\n\tset_cc_for_build\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n\t#include <unistd.h>\n\tint\n\tmain ()\n\t{\n\t  long cpu = sysconf (_SC_CPU_VERSION);\n\t  /* The order matters, because CPU_IS_HP_MC68K erroneously returns\n\t     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct\n\t     results, however.  */\n\t  if (CPU_IS_PA_RISC (cpu))\n\t    {\n\t      switch (cpu)\n\t\t{\n\t\t  case CPU_PA_RISC1_0: puts (\"hppa1.0-hitachi-hiuxwe2\"); break;\n\t\t  case CPU_PA_RISC1_1: puts (\"hppa1.1-hitachi-hiuxwe2\"); break;\n\t\t  case CPU_PA_RISC2_0: puts (\"hppa2.0-hitachi-hiuxwe2\"); break;\n\t\t  default: puts (\"hppa-hitachi-hiuxwe2\"); break;\n\t\t}\n\t    }\n\t  else if (CPU_IS_HP_MC68K (cpu))\n\t    puts (\"m68k-hitachi-hiuxwe2\");\n\t  else puts (\"unknown-hitachi-hiuxwe2\");\n\t  exit (0);\n\t}\nEOF\n\t$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" && SYSTEM_NAME=$(\"$dummy\") &&\n\t\t{ echo \"$SYSTEM_NAME\"; exit; }\n\techo unknown-hitachi-hiuxwe2\n\texit ;;\n    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)\n\techo hppa1.1-hp-bsd\n\texit ;;\n    9000/8??:4.3bsd:*:*)\n\techo hppa1.0-hp-bsd\n\texit ;;\n    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)\n\techo hppa1.0-hp-mpeix\n\texit ;;\n    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)\n\techo hppa1.1-hp-osf\n\texit ;;\n    hp8??:OSF1:*:*)\n\techo hppa1.0-hp-osf\n\texit ;;\n    i*86:OSF1:*:*)\n\tif test -x /usr/sbin/sysversion ; then\n\t    echo \"$UNAME_MACHINE\"-unknown-osf1mk\n\telse\n\t    echo \"$UNAME_MACHINE\"-unknown-osf1\n\tfi\n\texit ;;\n    parisc*:Lites*:*:*)\n\techo hppa1.1-hp-lites\n\texit ;;\n    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)\n\techo c1-convex-bsd\n\texit ;;\n    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)\n\tif getsysinfo -f scalar_acc\n\tthen echo c32-convex-bsd\n\telse echo c2-convex-bsd\n\tfi\n\texit ;;\n    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)\n\techo c34-convex-bsd\n\texit ;;\n    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)\n\techo c38-convex-bsd\n\texit ;;\n    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)\n\techo c4-convex-bsd\n\texit ;;\n    CRAY*Y-MP:*:*:*)\n\techo ymp-cray-unicos\"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    CRAY*[A-Z]90:*:*:*)\n\techo \"$UNAME_MACHINE\"-cray-unicos\"$UNAME_RELEASE\" \\\n\t| sed -e 's/CRAY.*\\([A-Z]90\\)/\\1/' \\\n\t      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \\\n\t      -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    CRAY*TS:*:*:*)\n\techo t90-cray-unicos\"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    CRAY*T3E:*:*:*)\n\techo alphaev5-cray-unicosmk\"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    CRAY*SV1:*:*:*)\n\techo sv1-cray-unicos\"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    *:UNICOS/mp:*:*)\n\techo craynv-cray-unicosmp\"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)\n\tFUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)\n\tFUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\\///')\n\tFUJITSU_REL=$(echo \"$UNAME_RELEASE\" | sed -e 's/ /_/')\n\techo \"${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}\"\n\texit ;;\n    5000:UNIX_System_V:4.*:*)\n\tFUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\\///')\n\tFUJITSU_REL=$(echo \"$UNAME_RELEASE\" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')\n\techo \"sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}\"\n\texit ;;\n    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\\ Embedded/OS:*:*)\n\techo \"$UNAME_MACHINE\"-pc-bsdi\"$UNAME_RELEASE\"\n\texit ;;\n    sparc*:BSD/OS:*:*)\n\techo sparc-unknown-bsdi\"$UNAME_RELEASE\"\n\texit ;;\n    *:BSD/OS:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-bsdi\"$UNAME_RELEASE\"\n\texit ;;\n    arm:FreeBSD:*:*)\n\tUNAME_PROCESSOR=$(uname -p)\n\tset_cc_for_build\n\tif echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t    | grep -q __ARM_PCS_VFP\n\tthen\n\t    echo \"${UNAME_PROCESSOR}\"-unknown-freebsd\"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')\"-gnueabi\n\telse\n\t    echo \"${UNAME_PROCESSOR}\"-unknown-freebsd\"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')\"-gnueabihf\n\tfi\n\texit ;;\n    *:FreeBSD:*:*)\n\tUNAME_PROCESSOR=$(/usr/bin/uname -p)\n\tcase $UNAME_PROCESSOR in\n\t    amd64)\n\t\tUNAME_PROCESSOR=x86_64 ;;\n\t    i386)\n\t\tUNAME_PROCESSOR=i586 ;;\n\tesac\n\techo \"$UNAME_PROCESSOR\"-unknown-freebsd\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[-(].*//')\"\n\texit ;;\n    i*:CYGWIN*:*)\n\techo \"$UNAME_MACHINE\"-pc-cygwin\n\texit ;;\n    *:MINGW64*:*)\n\techo \"$UNAME_MACHINE\"-pc-mingw64\n\texit ;;\n    *:MINGW*:*)\n\techo \"$UNAME_MACHINE\"-pc-mingw32\n\texit ;;\n    *:MSYS*:*)\n\techo \"$UNAME_MACHINE\"-pc-msys\n\texit ;;\n    i*:PW*:*)\n\techo \"$UNAME_MACHINE\"-pc-pw32\n\texit ;;\n    *:Interix*:*)\n\tcase $UNAME_MACHINE in\n\t    x86)\n\t\techo i586-pc-interix\"$UNAME_RELEASE\"\n\t\texit ;;\n\t    authenticamd | genuineintel | EM64T)\n\t\techo x86_64-unknown-interix\"$UNAME_RELEASE\"\n\t\texit ;;\n\t    IA64)\n\t\techo ia64-unknown-interix\"$UNAME_RELEASE\"\n\t\texit ;;\n\tesac ;;\n    i*:UWIN*:*)\n\techo \"$UNAME_MACHINE\"-pc-uwin\n\texit ;;\n    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)\n\techo x86_64-pc-cygwin\n\texit ;;\n    prep*:SunOS:5.*:*)\n\techo powerpcle-unknown-solaris2\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[^.]*//')\"\n\texit ;;\n    *:GNU:*:*)\n\t# the GNU system\n\techo \"$(echo \"$UNAME_MACHINE\"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo \"$UNAME_RELEASE\"|sed -e 's,/.*$,,')\"\n\texit ;;\n    *:GNU/*:*:*)\n\t# other systems with GNU libc and userland\n\techo \"$UNAME_MACHINE-unknown-$(echo \"$UNAME_SYSTEM\" | sed 's,^[^/]*/,,' | tr \"[:upper:]\" \"[:lower:]\")$(echo \"$UNAME_RELEASE\"|sed -e 's/[-(].*//')-$LIBC\"\n\texit ;;\n    *:Minix:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-minix\n\texit ;;\n    aarch64:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    aarch64_be:Linux:*:*)\n\tUNAME_MACHINE=aarch64_be\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    alpha:Linux:*:*)\n\tcase $(sed -n '/^cpu model/s/^.*: \\(.*\\)/\\1/p' /proc/cpuinfo 2>/dev/null) in\n\t  EV5)   UNAME_MACHINE=alphaev5 ;;\n\t  EV56)  UNAME_MACHINE=alphaev56 ;;\n\t  PCA56) UNAME_MACHINE=alphapca56 ;;\n\t  PCA57) UNAME_MACHINE=alphapca56 ;;\n\t  EV6)   UNAME_MACHINE=alphaev6 ;;\n\t  EV67)  UNAME_MACHINE=alphaev67 ;;\n\t  EV68*) UNAME_MACHINE=alphaev68 ;;\n\tesac\n\tobjdump --private-headers /bin/sh | grep -q ld.so.1\n\tif test \"$?\" = 0 ; then LIBC=gnulibc1 ; fi\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    arc:Linux:*:* | arceb:Linux:*:* | arc64:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    arm*:Linux:*:*)\n\tset_cc_for_build\n\tif echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t    | grep -q __ARM_EABI__\n\tthen\n\t    echo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\telse\n\t    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t\t| grep -q __ARM_PCS_VFP\n\t    then\n\t\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"eabi\n\t    else\n\t\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"eabihf\n\t    fi\n\tfi\n\texit ;;\n    avr32*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    cris:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-axis-linux-\"$LIBC\"\n\texit ;;\n    crisv32:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-axis-linux-\"$LIBC\"\n\texit ;;\n    e2k:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    frv:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    hexagon:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    i*86:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-pc-linux-\"$LIBC\"\n\texit ;;\n    ia64:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    k1om:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    m32r*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    m68*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    mips:Linux:*:* | mips64:Linux:*:*)\n\tset_cc_for_build\n\tIS_GLIBC=0\n\ttest x\"${LIBC}\" = xgnu && IS_GLIBC=1\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n\t#undef CPU\n\t#undef mips\n\t#undef mipsel\n\t#undef mips64\n\t#undef mips64el\n\t#if ${IS_GLIBC} && defined(_ABI64)\n\tLIBCABI=gnuabi64\n\t#else\n\t#if ${IS_GLIBC} && defined(_ABIN32)\n\tLIBCABI=gnuabin32\n\t#else\n\tLIBCABI=${LIBC}\n\t#endif\n\t#endif\n\n\t#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6\n\tCPU=mipsisa64r6\n\t#else\n\t#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6\n\tCPU=mipsisa32r6\n\t#else\n\t#if defined(__mips64)\n\tCPU=mips64\n\t#else\n\tCPU=mips\n\t#endif\n\t#endif\n\t#endif\n\n\t#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)\n\tMIPS_ENDIAN=el\n\t#else\n\t#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)\n\tMIPS_ENDIAN=\n\t#else\n\tMIPS_ENDIAN=\n\t#endif\n\t#endif\nEOF\n\teval \"$($CC_FOR_BUILD -E \"$dummy.c\" 2>/dev/null | grep '^CPU\\|^MIPS_ENDIAN\\|^LIBCABI')\"\n\ttest \"x$CPU\" != x && { echo \"$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI\"; exit; }\n\t;;\n    mips64el:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    openrisc*:Linux:*:*)\n\techo or1k-unknown-linux-\"$LIBC\"\n\texit ;;\n    or32:Linux:*:* | or1k*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    padre:Linux:*:*)\n\techo sparc-unknown-linux-\"$LIBC\"\n\texit ;;\n    parisc64:Linux:*:* | hppa64:Linux:*:*)\n\techo hppa64-unknown-linux-\"$LIBC\"\n\texit ;;\n    parisc:Linux:*:* | hppa:Linux:*:*)\n\t# Look for CPU level\n\tcase $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in\n\t  PA7*) echo hppa1.1-unknown-linux-\"$LIBC\" ;;\n\t  PA8*) echo hppa2.0-unknown-linux-\"$LIBC\" ;;\n\t  *)    echo hppa-unknown-linux-\"$LIBC\" ;;\n\tesac\n\texit ;;\n    ppc64:Linux:*:*)\n\techo powerpc64-unknown-linux-\"$LIBC\"\n\texit ;;\n    ppc:Linux:*:*)\n\techo powerpc-unknown-linux-\"$LIBC\"\n\texit ;;\n    ppc64le:Linux:*:*)\n\techo powerpc64le-unknown-linux-\"$LIBC\"\n\texit ;;\n    ppcle:Linux:*:*)\n\techo powerpcle-unknown-linux-\"$LIBC\"\n\texit ;;\n    riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    s390:Linux:*:* | s390x:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-ibm-linux-\"$LIBC\"\n\texit ;;\n    sh64*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    sh*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    sparc:Linux:*:* | sparc64:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    tile*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    vax:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-dec-linux-\"$LIBC\"\n\texit ;;\n    x86_64:Linux:*:*)\n\tset_cc_for_build\n\tLIBCABI=$LIBC\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \\\n\t\t(CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\tgrep IS_X32 >/dev/null\n\t    then\n\t\tLIBCABI=\"$LIBC\"x32\n\t    fi\n\tfi\n\techo \"$UNAME_MACHINE\"-pc-linux-\"$LIBCABI\"\n\texit ;;\n    xtensa*:Linux:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-linux-\"$LIBC\"\n\texit ;;\n    i*86:DYNIX/ptx:4*:*)\n\t# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.\n\t# earlier versions are messed up and put the nodename in both\n\t# sysname and nodename.\n\techo i386-sequent-sysv4\n\texit ;;\n    i*86:UNIX_SV:4.2MP:2.*)\n\t# Unixware is an offshoot of SVR4, but it has its own version\n\t# number series starting with 2...\n\t# I am not positive that other SVR4 systems won't match this,\n\t# I just have to hope.  -- rms.\n\t# Use sysv4.2uw... so that sysv4* matches it.\n\techo \"$UNAME_MACHINE\"-pc-sysv4.2uw\"$UNAME_VERSION\"\n\texit ;;\n    i*86:OS/2:*:*)\n\t# If we were able to find `uname', then EMX Unix compatibility\n\t# is probably installed.\n\techo \"$UNAME_MACHINE\"-pc-os2-emx\n\texit ;;\n    i*86:XTS-300:*:STOP)\n\techo \"$UNAME_MACHINE\"-unknown-stop\n\texit ;;\n    i*86:atheos:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-atheos\n\texit ;;\n    i*86:syllable:*:*)\n\techo \"$UNAME_MACHINE\"-pc-syllable\n\texit ;;\n    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)\n\techo i386-unknown-lynxos\"$UNAME_RELEASE\"\n\texit ;;\n    i*86:*DOS:*:*)\n\techo \"$UNAME_MACHINE\"-pc-msdosdjgpp\n\texit ;;\n    i*86:*:4.*:*)\n\tUNAME_REL=$(echo \"$UNAME_RELEASE\" | sed 's/\\/MP$//')\n\tif grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then\n\t\techo \"$UNAME_MACHINE\"-univel-sysv\"$UNAME_REL\"\n\telse\n\t\techo \"$UNAME_MACHINE\"-pc-sysv\"$UNAME_REL\"\n\tfi\n\texit ;;\n    i*86:*:5:[678]*)\n\t# UnixWare 7.x, OpenUNIX and OpenServer 6.\n\tcase $(/bin/uname -X | grep \"^Machine\") in\n\t    *486*)\t     UNAME_MACHINE=i486 ;;\n\t    *Pentium)\t     UNAME_MACHINE=i586 ;;\n\t    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;\n\tesac\n\techo \"$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}\"\n\texit ;;\n    i*86:*:3.2:*)\n\tif test -f /usr/options/cb.name; then\n\t\tUNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)\n\t\techo \"$UNAME_MACHINE\"-pc-isc\"$UNAME_REL\"\n\telif /bin/uname -X 2>/dev/null >/dev/null ; then\n\t\tUNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))\n\t\t(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486\n\t\t(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i586\n\t\t(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i686\n\t\t(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i686\n\t\techo \"$UNAME_MACHINE\"-pc-sco\"$UNAME_REL\"\n\telse\n\t\techo \"$UNAME_MACHINE\"-pc-sysv32\n\tfi\n\texit ;;\n    pc:*:*:*)\n\t# Left here for compatibility:\n\t# uname -m prints for DJGPP always 'pc', but it prints nothing about\n\t# the processor, so we play safe by assuming i586.\n\t# Note: whatever this is, it MUST be the same as what config.sub\n\t# prints for the \"djgpp\" host, or else GDB configure will decide that\n\t# this is a cross-build.\n\techo i586-pc-msdosdjgpp\n\texit ;;\n    Intel:Mach:3*:*)\n\techo i386-pc-mach3\n\texit ;;\n    paragon:*:*:*)\n\techo i860-intel-osf1\n\texit ;;\n    i860:*:4.*:*) # i860-SVR4\n\tif grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then\n\t  echo i860-stardent-sysv\"$UNAME_RELEASE\" # Stardent Vistra i860-SVR4\n\telse # Add other i860-SVR4 vendors below as they are discovered.\n\t  echo i860-unknown-sysv\"$UNAME_RELEASE\"  # Unknown i860-SVR4\n\tfi\n\texit ;;\n    mini*:CTIX:SYS*5:*)\n\t# \"miniframe\"\n\techo m68010-convergent-sysv\n\texit ;;\n    mc68k:UNIX:SYSTEM5:3.51m)\n\techo m68k-convergent-sysv\n\texit ;;\n    M680?0:D-NIX:5.3:*)\n\techo m68k-diab-dnix\n\texit ;;\n    M68*:*:R3V[5678]*:*)\n\ttest -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;\n    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)\n\tOS_REL=''\n\ttest -r /etc/.relid \\\n\t&& OS_REL=.$(sed -n 's/[^ ]* [^ ]* \\([0-9][0-9]\\).*/\\1/p' < /etc/.relid)\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t  && { echo i486-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \\\n\t  && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; } ;;\n    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t  && { echo i486-ncr-sysv4; exit; } ;;\n    NCR*:*:4.2:* | MPRAS*:*:4.2:*)\n\tOS_REL='.3'\n\ttest -r /etc/.relid \\\n\t    && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \\([0-9][0-9]\\).*/\\1/p' < /etc/.relid)\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t    && { echo i486-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \\\n\t    && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \\\n\t    && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; } ;;\n    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)\n\techo m68k-unknown-lynxos\"$UNAME_RELEASE\"\n\texit ;;\n    mc68030:UNIX_System_V:4.*:*)\n\techo m68k-atari-sysv4\n\texit ;;\n    TSUNAMI:LynxOS:2.*:*)\n\techo sparc-unknown-lynxos\"$UNAME_RELEASE\"\n\texit ;;\n    rs6000:LynxOS:2.*:*)\n\techo rs6000-unknown-lynxos\"$UNAME_RELEASE\"\n\texit ;;\n    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)\n\techo powerpc-unknown-lynxos\"$UNAME_RELEASE\"\n\texit ;;\n    SM[BE]S:UNIX_SV:*:*)\n\techo mips-dde-sysv\"$UNAME_RELEASE\"\n\texit ;;\n    RM*:ReliantUNIX-*:*:*)\n\techo mips-sni-sysv4\n\texit ;;\n    RM*:SINIX-*:*:*)\n\techo mips-sni-sysv4\n\texit ;;\n    *:SINIX-*:*:*)\n\tif uname -p 2>/dev/null >/dev/null ; then\n\t\tUNAME_MACHINE=$( (uname -p) 2>/dev/null)\n\t\techo \"$UNAME_MACHINE\"-sni-sysv4\n\telse\n\t\techo ns32k-sni-sysv\n\tfi\n\texit ;;\n    PENTIUM:*:4.0*:*)\t# Unisys `ClearPath HMP IX 4000' SVR4/MP effort\n\t\t\t# says <Richard.M.Bartel@ccMail.Census.GOV>\n\techo i586-unisys-sysv4\n\texit ;;\n    *:UNIX_System_V:4*:FTX*)\n\t# From Gerald Hewes <hewes@openmarket.com>.\n\t# How about differentiating between stratus architectures? -djm\n\techo hppa1.1-stratus-sysv4\n\texit ;;\n    *:*:*:FTX*)\n\t# From seanf@swdc.stratus.com.\n\techo i860-stratus-sysv4\n\texit ;;\n    i*86:VOS:*:*)\n\t# From Paul.Green@stratus.com.\n\techo \"$UNAME_MACHINE\"-stratus-vos\n\texit ;;\n    *:VOS:*:*)\n\t# From Paul.Green@stratus.com.\n\techo hppa1.1-stratus-vos\n\texit ;;\n    mc68*:A/UX:*:*)\n\techo m68k-apple-aux\"$UNAME_RELEASE\"\n\texit ;;\n    news*:NEWS-OS:6*:*)\n\techo mips-sony-newsos6\n\texit ;;\n    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)\n\tif test -d /usr/nec; then\n\t\techo mips-nec-sysv\"$UNAME_RELEASE\"\n\telse\n\t\techo mips-unknown-sysv\"$UNAME_RELEASE\"\n\tfi\n\texit ;;\n    BeBox:BeOS:*:*)\t# BeOS running on hardware made by Be, PPC only.\n\techo powerpc-be-beos\n\texit ;;\n    BeMac:BeOS:*:*)\t# BeOS running on Mac or Mac clone, PPC only.\n\techo powerpc-apple-beos\n\texit ;;\n    BePC:BeOS:*:*)\t# BeOS running on Intel PC compatible.\n\techo i586-pc-beos\n\texit ;;\n    BePC:Haiku:*:*)\t# Haiku running on Intel PC compatible.\n\techo i586-pc-haiku\n\texit ;;\n    x86_64:Haiku:*:*)\n\techo x86_64-unknown-haiku\n\texit ;;\n    SX-4:SUPER-UX:*:*)\n\techo sx4-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-5:SUPER-UX:*:*)\n\techo sx5-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-6:SUPER-UX:*:*)\n\techo sx6-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-7:SUPER-UX:*:*)\n\techo sx7-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-8:SUPER-UX:*:*)\n\techo sx8-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-8R:SUPER-UX:*:*)\n\techo sx8r-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    SX-ACE:SUPER-UX:*:*)\n\techo sxace-nec-superux\"$UNAME_RELEASE\"\n\texit ;;\n    Power*:Rhapsody:*:*)\n\techo powerpc-apple-rhapsody\"$UNAME_RELEASE\"\n\texit ;;\n    *:Rhapsody:*:*)\n\techo \"$UNAME_MACHINE\"-apple-rhapsody\"$UNAME_RELEASE\"\n\texit ;;\n    arm64:Darwin:*:*)\n\techo aarch64-apple-darwin\"$UNAME_RELEASE\"\n\texit ;;\n    *:Darwin:*:*)\n\tUNAME_PROCESSOR=$(uname -p)\n\tcase $UNAME_PROCESSOR in\n\t    unknown) UNAME_PROCESSOR=powerpc ;;\n\tesac\n\tif command -v xcode-select > /dev/null 2> /dev/null && \\\n\t\t! xcode-select --print-path > /dev/null 2> /dev/null ; then\n\t    # Avoid executing cc if there is no toolchain installed as\n\t    # cc will be a stub that puts up a graphical alert\n\t    # prompting the user to install developer tools.\n\t    CC_FOR_BUILD=no_compiler_found\n\telse\n\t    set_cc_for_build\n\tfi\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \\\n\t\t   (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\t   grep IS_64BIT_ARCH >/dev/null\n\t    then\n\t\tcase $UNAME_PROCESSOR in\n\t\t    i386) UNAME_PROCESSOR=x86_64 ;;\n\t\t    powerpc) UNAME_PROCESSOR=powerpc64 ;;\n\t\tesac\n\t    fi\n\t    # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc\n\t    if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \\\n\t\t   (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\t   grep IS_PPC >/dev/null\n\t    then\n\t\tUNAME_PROCESSOR=powerpc\n\t    fi\n\telif test \"$UNAME_PROCESSOR\" = i386 ; then\n\t    # uname -m returns i386 or x86_64\n\t    UNAME_PROCESSOR=$UNAME_MACHINE\n\tfi\n\techo \"$UNAME_PROCESSOR\"-apple-darwin\"$UNAME_RELEASE\"\n\texit ;;\n    *:procnto*:*:* | *:QNX:[0123456789]*:*)\n\tUNAME_PROCESSOR=$(uname -p)\n\tif test \"$UNAME_PROCESSOR\" = x86; then\n\t\tUNAME_PROCESSOR=i386\n\t\tUNAME_MACHINE=pc\n\tfi\n\techo \"$UNAME_PROCESSOR\"-\"$UNAME_MACHINE\"-nto-qnx\"$UNAME_RELEASE\"\n\texit ;;\n    *:QNX:*:4*)\n\techo i386-pc-qnx\n\texit ;;\n    NEO-*:NONSTOP_KERNEL:*:*)\n\techo neo-tandem-nsk\"$UNAME_RELEASE\"\n\texit ;;\n    NSE-*:NONSTOP_KERNEL:*:*)\n\techo nse-tandem-nsk\"$UNAME_RELEASE\"\n\texit ;;\n    NSR-*:NONSTOP_KERNEL:*:*)\n\techo nsr-tandem-nsk\"$UNAME_RELEASE\"\n\texit ;;\n    NSV-*:NONSTOP_KERNEL:*:*)\n\techo nsv-tandem-nsk\"$UNAME_RELEASE\"\n\texit ;;\n    NSX-*:NONSTOP_KERNEL:*:*)\n\techo nsx-tandem-nsk\"$UNAME_RELEASE\"\n\texit ;;\n    *:NonStop-UX:*:*)\n\techo mips-compaq-nonstopux\n\texit ;;\n    BS2000:POSIX*:*:*)\n\techo bs2000-siemens-sysv\n\texit ;;\n    DS/*:UNIX_System_V:*:*)\n\techo \"$UNAME_MACHINE\"-\"$UNAME_SYSTEM\"-\"$UNAME_RELEASE\"\n\texit ;;\n    *:Plan9:*:*)\n\t# \"uname -m\" is not consistent, so use $cputype instead. 386\n\t# is converted to i386 for consistency with other x86\n\t# operating systems.\n\tif test \"${cputype-}\" = 386; then\n\t    UNAME_MACHINE=i386\n\telif test \"x${cputype-}\" != x; then\n\t    UNAME_MACHINE=\"$cputype\"\n\tfi\n\techo \"$UNAME_MACHINE\"-unknown-plan9\n\texit ;;\n    *:TOPS-10:*:*)\n\techo pdp10-unknown-tops10\n\texit ;;\n    *:TENEX:*:*)\n\techo pdp10-unknown-tenex\n\texit ;;\n    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)\n\techo pdp10-dec-tops20\n\texit ;;\n    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)\n\techo pdp10-xkl-tops20\n\texit ;;\n    *:TOPS-20:*:*)\n\techo pdp10-unknown-tops20\n\texit ;;\n    *:ITS:*:*)\n\techo pdp10-unknown-its\n\texit ;;\n    SEI:*:*:SEIUX)\n\techo mips-sei-seiux\"$UNAME_RELEASE\"\n\texit ;;\n    *:DragonFly:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-dragonfly\"$(echo \"$UNAME_RELEASE\"|sed -e 's/[-(].*//')\"\n\texit ;;\n    *:*VMS:*:*)\n\tUNAME_MACHINE=$( (uname -p) 2>/dev/null)\n\tcase $UNAME_MACHINE in\n\t    A*) echo alpha-dec-vms ; exit ;;\n\t    I*) echo ia64-dec-vms ; exit ;;\n\t    V*) echo vax-dec-vms ; exit ;;\n\tesac ;;\n    *:XENIX:*:SysV)\n\techo i386-pc-xenix\n\texit ;;\n    i*86:skyos:*:*)\n\techo \"$UNAME_MACHINE\"-pc-skyos\"$(echo \"$UNAME_RELEASE\" | sed -e 's/ .*$//')\"\n\texit ;;\n    i*86:rdos:*:*)\n\techo \"$UNAME_MACHINE\"-pc-rdos\n\texit ;;\n    *:AROS:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-aros\n\texit ;;\n    x86_64:VMkernel:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-esx\n\texit ;;\n    amd64:Isilon\\ OneFS:*:*)\n\techo x86_64-unknown-onefs\n\texit ;;\n    *:Unleashed:*:*)\n\techo \"$UNAME_MACHINE\"-unknown-unleashed\"$UNAME_RELEASE\"\n\texit ;;\nesac\n\n# No uname command or uname output not recognized.\nset_cc_for_build\ncat > \"$dummy.c\" <<EOF\n#ifdef _SEQUENT_\n#include <sys/types.h>\n#include <sys/utsname.h>\n#endif\n#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)\n#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)\n#include <signal.h>\n#if defined(_SIZE_T_) || defined(SIGLOST)\n#include <sys/utsname.h>\n#endif\n#endif\n#endif\nmain ()\n{\n#if defined (sony)\n#if defined (MIPSEB)\n  /* BFD wants \"bsd\" instead of \"newsos\".  Perhaps BFD should be changed,\n     I don't know....  */\n  printf (\"mips-sony-bsd\\n\"); exit (0);\n#else\n#include <sys/param.h>\n  printf (\"m68k-sony-newsos%s\\n\",\n#ifdef NEWSOS4\n  \"4\"\n#else\n  \"\"\n#endif\n  ); exit (0);\n#endif\n#endif\n\n#if defined (NeXT)\n#if !defined (__ARCHITECTURE__)\n#define __ARCHITECTURE__ \"m68k\"\n#endif\n  int version;\n  version=$( (hostinfo | sed -n 's/.*NeXT Mach \\([0-9]*\\).*/\\1/p') 2>/dev/null);\n  if (version < 4)\n    printf (\"%s-next-nextstep%d\\n\", __ARCHITECTURE__, version);\n  else\n    printf (\"%s-next-openstep%d\\n\", __ARCHITECTURE__, version);\n  exit (0);\n#endif\n\n#if defined (MULTIMAX) || defined (n16)\n#if defined (UMAXV)\n  printf (\"ns32k-encore-sysv\\n\"); exit (0);\n#else\n#if defined (CMU)\n  printf (\"ns32k-encore-mach\\n\"); exit (0);\n#else\n  printf (\"ns32k-encore-bsd\\n\"); exit (0);\n#endif\n#endif\n#endif\n\n#if defined (__386BSD__)\n  printf (\"i386-pc-bsd\\n\"); exit (0);\n#endif\n\n#if defined (sequent)\n#if defined (i386)\n  printf (\"i386-sequent-dynix\\n\"); exit (0);\n#endif\n#if defined (ns32000)\n  printf (\"ns32k-sequent-dynix\\n\"); exit (0);\n#endif\n#endif\n\n#if defined (_SEQUENT_)\n  struct utsname un;\n\n  uname(&un);\n  if (strncmp(un.version, \"V2\", 2) == 0) {\n    printf (\"i386-sequent-ptx2\\n\"); exit (0);\n  }\n  if (strncmp(un.version, \"V1\", 2) == 0) { /* XXX is V1 correct? */\n    printf (\"i386-sequent-ptx1\\n\"); exit (0);\n  }\n  printf (\"i386-sequent-ptx\\n\"); exit (0);\n#endif\n\n#if defined (vax)\n#if !defined (ultrix)\n#include <sys/param.h>\n#if defined (BSD)\n#if BSD == 43\n  printf (\"vax-dec-bsd4.3\\n\"); exit (0);\n#else\n#if BSD == 199006\n  printf (\"vax-dec-bsd4.3reno\\n\"); exit (0);\n#else\n  printf (\"vax-dec-bsd\\n\"); exit (0);\n#endif\n#endif\n#else\n  printf (\"vax-dec-bsd\\n\"); exit (0);\n#endif\n#else\n#if defined(_SIZE_T_) || defined(SIGLOST)\n  struct utsname un;\n  uname (&un);\n  printf (\"vax-dec-ultrix%s\\n\", un.release); exit (0);\n#else\n  printf (\"vax-dec-ultrix\\n\"); exit (0);\n#endif\n#endif\n#endif\n#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)\n#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)\n#if defined(_SIZE_T_) || defined(SIGLOST)\n  struct utsname *un;\n  uname (&un);\n  printf (\"mips-dec-ultrix%s\\n\", un.release); exit (0);\n#else\n  printf (\"mips-dec-ultrix\\n\"); exit (0);\n#endif\n#endif\n#endif\n\n#if defined (alliant) && defined (i860)\n  printf (\"i860-alliant-bsd\\n\"); exit (0);\n#endif\n\n  exit (1);\n}\nEOF\n\n$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" 2>/dev/null && SYSTEM_NAME=$($dummy) &&\n\t{ echo \"$SYSTEM_NAME\"; exit; }\n\n# Apollos put the system type in the environment.\ntest -d /usr/apollo && { echo \"$ISP-apollo-$SYSTYPE\"; exit; }\n\necho \"$0: unable to guess system type\" >&2\n\ncase $UNAME_MACHINE:$UNAME_SYSTEM in\n    mips:Linux | mips64:Linux)\n\t# If we got here on MIPS GNU/Linux, output extra information.\n\tcat >&2 <<EOF\n\nNOTE: MIPS GNU/Linux systems require a C compiler to fully recognize\nthe system type. Please install a C compiler and try again.\nEOF\n\t;;\nesac\n\ncat >&2 <<EOF\n\nThis script (version $timestamp), has failed to recognize the\noperating system you are using. If your script is old, overwrite *all*\ncopies of config.guess and config.sub with the latest versions from:\n\n  https://git.savannah.gnu.org/cgit/config.git/plain/config.guess\nand\n  https://git.savannah.gnu.org/cgit/config.git/plain/config.sub\nEOF\n\nyear=$(echo $timestamp | sed 's,-.*,,')\n# shellcheck disable=SC2003\nif test \"$(expr \"$(date +%Y)\" - \"$year\")\" -lt 3 ; then\n   cat >&2 <<EOF\n\nIf $0 has already been updated, send the following data and any\ninformation you think might be pertinent to config-patches@gnu.org to\nprovide the necessary information to handle your system.\n\nconfig.guess timestamp = $timestamp\n\nuname -m = $( (uname -m) 2>/dev/null || echo unknown)\nuname -r = $( (uname -r) 2>/dev/null || echo unknown)\nuname -s = $( (uname -s) 2>/dev/null || echo unknown)\nuname -v = $( (uname -v) 2>/dev/null || echo unknown)\n\n/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)\n/bin/uname -X     = $( (/bin/uname -X) 2>/dev/null)\n\nhostinfo               = $( (hostinfo) 2>/dev/null)\n/bin/universe          = $( (/bin/universe) 2>/dev/null)\n/usr/bin/arch -k       = $( (/usr/bin/arch -k) 2>/dev/null)\n/bin/arch              = $( (/bin/arch) 2>/dev/null)\n/usr/bin/oslevel       = $( (/usr/bin/oslevel) 2>/dev/null)\n/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)\n\nUNAME_MACHINE = \"$UNAME_MACHINE\"\nUNAME_RELEASE = \"$UNAME_RELEASE\"\nUNAME_SYSTEM  = \"$UNAME_SYSTEM\"\nUNAME_VERSION = \"$UNAME_VERSION\"\nEOF\nfi\n\nexit 1\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"timestamp='\"\n# time-stamp-format: \"%:y-%02m-%02d\"\n# time-stamp-end: \"'\"\n# End:\n"
  },
  {
    "path": "depends/config.site.in",
    "content": "# shellcheck shell=sh disable=SC2034 # Many variables set will be used in\n                                     # ./configure but shellcheck doesn't know\n                                     # that, hence: disable=SC2034\n\ntrue  # Dummy command because shellcheck treats all directives before first\n      # command as file-wide, and we only want to disable for one line.\n      #\n      # See: https://github.com/koalaman/shellcheck/wiki/Directive\n\n# shellcheck disable=SC2154\ndepends_prefix=\"$(cd \"$(dirname \"$ac_site_file\")/..\" && pwd)\"\n\ncross_compiling=maybe\nhost_alias=\"@HOST@\"\nac_tool_prefix=\"${host_alias}-\"\n\nif test -z \"$with_boost\"; then\n  with_boost=\"$depends_prefix\"\nfi\nif test -z \"$with_qt_plugindir\"; then\n  with_qt_plugindir=\"${depends_prefix}/plugins\"\nfi\nif test -z \"$with_qt_translationdir\"; then\n  with_qt_translationdir=\"${depends_prefix}/translations\"\nfi\nif test -z \"$with_qt_bindir\" && test -z \"@no_qt@\"; then\n  with_qt_bindir=\"${depends_prefix}/native/bin\"\nfi\nif test -z \"$with_mpgen\" && test -n \"@multiprocess@\"; then\n  with_mpgen=\"${depends_prefix}/native\"\nfi\n\nif test -z \"$with_qrencode\" && test -n \"@no_qr@\"; then\n  with_qrencode=no\nfi\n\nif test -z \"$enable_wallet\" && test -n \"@no_wallet@\"; then\n  enable_wallet=no\nfi\n\nif test -z \"$with_bdb\" && test -n \"@no_bdb@\"; then\n  with_bdb=no\nfi\n\nif test -z \"$with_sqlite\" && test -n \"@no_sqlite@\"; then\n  with_sqlite=no\nfi\n\nif test -z \"$enable_multiprocess\" && test -n \"@multiprocess@\"; then\n  enable_multiprocess=yes\nfi\n\nif test -z \"$with_miniupnpc\" && test -n \"@no_upnp@\"; then\n  with_miniupnpc=no\nfi\n\nif test -z \"$with_natpmp\" && test -n \"@no_natpmp@\"; then\n  with_natpmp=no\nfi\n\nif test -z \"$with_gui\" && test -n \"@no_qt@\"; then\n  with_gui=no\nfi\n\nif test -n \"@debug@\" && test -z \"@no_qt@\" && test \"$with_gui\" != \"no\"; then\n  with_gui=qt5_debug\nfi\n\nif test -z \"$enable_zmq\" && test -n \"@no_zmq@\"; then\n  enable_zmq=no\nfi\n\nif test -z \"$enable_usdt\" && test -n \"@no_usdt@\"; then\n  enable_usdt=no\nfi\n\nif test \"@host_os@\" = darwin; then\n  BREW=no\nfi\n\nPATH=\"${depends_prefix}/native/bin:${PATH}\"\nPKG_CONFIG=\"$(which pkg-config) --static\"\n\n# These two need to remain exported because pkg-config does not see them\n# otherwise. That means they must be unexported at the end of configure.ac to\n# avoid ruining the cache. Sigh.\nexport PKG_CONFIG_PATH=\"${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig\"\nif test -z \"@allow_host_packages@\"; then\n  export PKG_CONFIG_LIBDIR=\"${depends_prefix}/lib/pkgconfig\"\nfi\n\nCPPFLAGS=\"-I${depends_prefix}/include/ ${CPPFLAGS}\"\nLDFLAGS=\"-L${depends_prefix}/lib ${LDFLAGS}\"\n\nif test -n \"@CC@\" -a -z \"${CC}\"; then\n  CC=\"@CC@\"\nfi\nif test -n \"@CXX@\" -a -z \"${CXX}\"; then\n  CXX=\"@CXX@\"\nfi\nPYTHONPATH=\"${depends_prefix}/native/lib/python3/dist-packages${PYTHONPATH:+${PATH_SEPARATOR}}${PYTHONPATH}\"\n\nif test -n \"@AR@\"; then\n  AR=\"@AR@\"\n  ac_cv_path_ac_pt_AR=\"${AR}\"\nfi\n\nif test -n \"@RANLIB@\"; then\n  RANLIB=\"@RANLIB@\"\n  ac_cv_path_ac_pt_RANLIB=\"${RANLIB}\"\nfi\n\nif test -n \"@NM@\"; then\n  NM=\"@NM@\"\n  ac_cv_path_ac_pt_NM=\"${NM}\"\nfi\n\nif test -n \"@debug@\"; then\n  enable_reduce_exports=no\nfi\n\nif test -n \"@CFLAGS@\"; then\n  CFLAGS=\"@CFLAGS@ ${CFLAGS}\"\nfi\nif test -n \"@CXXFLAGS@\"; then\n  CXXFLAGS=\"@CXXFLAGS@ ${CXXFLAGS}\"\nfi\nif test -n \"@CPPFLAGS@\"; then\n  CPPFLAGS=\"@CPPFLAGS@ ${CPPFLAGS}\"\nfi\nif test -n \"@LDFLAGS@\"; then\n  LDFLAGS=\"@LDFLAGS@ ${LDFLAGS}\"\nfi\n"
  },
  {
    "path": "depends/config.sub",
    "content": "#! /bin/sh\n# Configuration validation subroutine script.\n#   Copyright 1992-2021 Free Software Foundation, Inc.\n\ntimestamp='2021-04-30'\n\n# This file is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that\n# program.  This Exception is an additional permission under section 7\n# of the GNU General Public License, version 3 (\"GPLv3\").\n\n\n# Please send patches to <config-patches@gnu.org>.\n#\n# Configuration subroutine to validate and canonicalize a configuration type.\n# Supply the specified configuration type as an argument.\n# If it is invalid, we print an error message on stderr and exit with code 1.\n# Otherwise, we print the canonical config type on stdout and succeed.\n\n# You can get the latest version of this script from:\n# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub\n\n# This file is supposed to be the same for all GNU packages\n# and recognize all the CPU types, system types and aliases\n# that are meaningful with *any* GNU software.\n# Each package is responsible for reporting which valid configurations\n# it does not support.  The user should be able to distinguish\n# a failure to support a valid configuration from a meaningless\n# configuration.\n\n# The goal of this file is to map all the various variations of a given\n# machine specification into a single specification in the form:\n#\tCPU_TYPE-MANUFACTURER-OPERATING_SYSTEM\n# or in some cases, the newer four-part form:\n#\tCPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM\n# It is wrong to echo any other type of specification.\n\nme=$(echo \"$0\" | sed -e 's,.*/,,')\n\nusage=\"\\\nUsage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS\n\nCanonicalize a configuration name.\n\nOptions:\n  -h, --help         print this help, then exit\n  -t, --time-stamp   print date of last modification, then exit\n  -v, --version      print version number, then exit\n\nReport bugs and patches to <config-patches@gnu.org>.\"\n\nversion=\"\\\nGNU config.sub ($timestamp)\n\nCopyright 1992-2021 Free Software Foundation, Inc.\n\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\"\n\nhelp=\"\nTry \\`$me --help' for more information.\"\n\n# Parse command line\nwhile test $# -gt 0 ; do\n  case $1 in\n    --time-stamp | --time* | -t )\n       echo \"$timestamp\" ; exit ;;\n    --version | -v )\n       echo \"$version\" ; exit ;;\n    --help | --h* | -h )\n       echo \"$usage\"; exit ;;\n    -- )     # Stop option processing\n       shift; break ;;\n    - )\t# Use stdin as input.\n       break ;;\n    -* )\n       echo \"$me: invalid option $1$help\" >&2\n       exit 1 ;;\n\n    *local*)\n       # First pass through any local machine types.\n       echo \"$1\"\n       exit ;;\n\n    * )\n       break ;;\n  esac\ndone\n\ncase $# in\n 0) echo \"$me: missing argument$help\" >&2\n    exit 1;;\n 1) ;;\n *) echo \"$me: too many arguments$help\" >&2\n    exit 1;;\nesac\n\n# Split fields of configuration type\n# shellcheck disable=SC2162\nIFS=\"-\" read field1 field2 field3 field4 <<EOF\n$1\nEOF\n\n# Separate into logical components for further validation\ncase $1 in\n\t*-*-*-*-*)\n\t\techo Invalid configuration \\`\"$1\"\\': more than four components >&2\n\t\texit 1\n\t\t;;\n\t*-*-*-*)\n\t\tbasic_machine=$field1-$field2\n\t\tbasic_os=$field3-$field4\n\t\t;;\n\t*-*-*)\n\t\t# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two\n\t\t# parts\n\t\tmaybe_os=$field2-$field3\n\t\tcase $maybe_os in\n\t\t\tnto-qnx* | linux-* | uclinux-uclibc* \\\n\t\t\t| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \\\n\t\t\t| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \\\n\t\t\t| storm-chaos* | os2-emx* | rtmk-nova*)\n\t\t\t\tbasic_machine=$field1\n\t\t\t\tbasic_os=$maybe_os\n\t\t\t\t;;\n\t\t\tandroid-linux)\n\t\t\t\tbasic_machine=$field1-unknown\n\t\t\t\tbasic_os=linux-android\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\tbasic_machine=$field1-$field2\n\t\t\t\tbasic_os=$field3\n\t\t\t\t;;\n\t\tesac\n\t\t;;\n\t*-*)\n\t\t# A lone config we happen to match not fitting any pattern\n\t\tcase $field1-$field2 in\n\t\t\tdecstation-3100)\n\t\t\t\tbasic_machine=mips-dec\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\t*-*)\n\t\t\t\t# Second component is usually, but not always the OS\n\t\t\t\tcase $field2 in\n\t\t\t\t\t# Prevent following clause from handling this valid os\n\t\t\t\t\tsun*os*)\n\t\t\t\t\t\tbasic_machine=$field1\n\t\t\t\t\t\tbasic_os=$field2\n\t\t\t\t\t\t;;\n\t\t\t\t\t# Manufacturers\n\t\t\t\t\tdec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \\\n\t\t\t\t\t| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \\\n\t\t\t\t\t| unicom* | ibm* | next | hp | isi* | apollo | altos* \\\n\t\t\t\t\t| convergent* | ncr* | news | 32* | 3600* | 3100* \\\n\t\t\t\t\t| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \\\n\t\t\t\t\t| ultra | tti* | harris | dolphin | highlevel | gould \\\n\t\t\t\t\t| cbm | ns | masscomp | apple | axis | knuth | cray \\\n\t\t\t\t\t| microblaze* | sim | cisco \\\n\t\t\t\t\t| oki | wec | wrs | winbond)\n\t\t\t\t\t\tbasic_machine=$field1-$field2\n\t\t\t\t\t\tbasic_os=\n\t\t\t\t\t\t;;\n\t\t\t\t\t*)\n\t\t\t\t\t\tbasic_machine=$field1\n\t\t\t\t\t\tbasic_os=$field2\n\t\t\t\t\t\t;;\n\t\t\t\tesac\n\t\t\t;;\n\t\tesac\n\t\t;;\n\t*)\n\t\t# Convert single-component short-hands not valid as part of\n\t\t# multi-component configurations.\n\t\tcase $field1 in\n\t\t\t386bsd)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\ta29khif)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tadobe68k)\n\t\t\t\tbasic_machine=m68010-adobe\n\t\t\t\tbasic_os=scout\n\t\t\t\t;;\n\t\t\talliant)\n\t\t\t\tbasic_machine=fx80-alliant\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\taltos | altos3068)\n\t\t\t\tbasic_machine=m68k-altos\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tam29k)\n\t\t\t\tbasic_machine=a29k-none\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tamdahl)\n\t\t\t\tbasic_machine=580-amdahl\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tamiga)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tamigaos | amigados)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=amigaos\n\t\t\t\t;;\n\t\t\tamigaunix | amix)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tapollo68)\n\t\t\t\tbasic_machine=m68k-apollo\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tapollo68bsd)\n\t\t\t\tbasic_machine=m68k-apollo\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\taros)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=aros\n\t\t\t\t;;\n\t\t\taux)\n\t\t\t\tbasic_machine=m68k-apple\n\t\t\t\tbasic_os=aux\n\t\t\t\t;;\n\t\t\tbalance)\n\t\t\t\tbasic_machine=ns32k-sequent\n\t\t\t\tbasic_os=dynix\n\t\t\t\t;;\n\t\t\tblackfin)\n\t\t\t\tbasic_machine=bfin-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tcegcc)\n\t\t\t\tbasic_machine=arm-unknown\n\t\t\t\tbasic_os=cegcc\n\t\t\t\t;;\n\t\t\tconvex-c1)\n\t\t\t\tbasic_machine=c1-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c2)\n\t\t\t\tbasic_machine=c2-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c32)\n\t\t\t\tbasic_machine=c32-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c34)\n\t\t\t\tbasic_machine=c34-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c38)\n\t\t\t\tbasic_machine=c38-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tcray)\n\t\t\t\tbasic_machine=j90-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tcrds | unos)\n\t\t\t\tbasic_machine=m68k-crds\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tda30)\n\t\t\t\tbasic_machine=m68k-da30\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tdecstation | pmax | pmin | dec3100 | decstatn)\n\t\t\t\tbasic_machine=mips-dec\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tdelta88)\n\t\t\t\tbasic_machine=m88k-motorola\n\t\t\t\tbasic_os=sysv3\n\t\t\t\t;;\n\t\t\tdicos)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=dicos\n\t\t\t\t;;\n\t\t\tdjgpp)\n\t\t\t\tbasic_machine=i586-pc\n\t\t\t\tbasic_os=msdosdjgpp\n\t\t\t\t;;\n\t\t\tebmon29k)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=ebmon\n\t\t\t\t;;\n\t\t\tes1800 | OSE68k | ose68k | ose | OSE)\n\t\t\t\tbasic_machine=m68k-ericsson\n\t\t\t\tbasic_os=ose\n\t\t\t\t;;\n\t\t\tgmicro)\n\t\t\t\tbasic_machine=tron-gmicro\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tgo32)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=go32\n\t\t\t\t;;\n\t\t\th8300hms)\n\t\t\t\tbasic_machine=h8300-hitachi\n\t\t\t\tbasic_os=hms\n\t\t\t\t;;\n\t\t\th8300xray)\n\t\t\t\tbasic_machine=h8300-hitachi\n\t\t\t\tbasic_os=xray\n\t\t\t\t;;\n\t\t\th8500hms)\n\t\t\t\tbasic_machine=h8500-hitachi\n\t\t\t\tbasic_os=hms\n\t\t\t\t;;\n\t\t\tharris)\n\t\t\t\tbasic_machine=m88k-harris\n\t\t\t\tbasic_os=sysv3\n\t\t\t\t;;\n\t\t\thp300 | hp300hpux)\n\t\t\t\tbasic_machine=m68k-hp\n\t\t\t\tbasic_os=hpux\n\t\t\t\t;;\n\t\t\thp300bsd)\n\t\t\t\tbasic_machine=m68k-hp\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\thppaosf)\n\t\t\t\tbasic_machine=hppa1.1-hp\n\t\t\t\tbasic_os=osf\n\t\t\t\t;;\n\t\t\thppro)\n\t\t\t\tbasic_machine=hppa1.1-hp\n\t\t\t\tbasic_os=proelf\n\t\t\t\t;;\n\t\t\ti386mach)\n\t\t\t\tbasic_machine=i386-mach\n\t\t\t\tbasic_os=mach\n\t\t\t\t;;\n\t\t\tisi68 | isi)\n\t\t\t\tbasic_machine=m68k-isi\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tm68knommu)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tmagnum | m3230)\n\t\t\t\tbasic_machine=mips-mips\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tmerlin)\n\t\t\t\tbasic_machine=ns32k-utek\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tmingw64)\n\t\t\t\tbasic_machine=x86_64-pc\n\t\t\t\tbasic_os=mingw64\n\t\t\t\t;;\n\t\t\tmingw32)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=mingw32\n\t\t\t\t;;\n\t\t\tmingw32ce)\n\t\t\t\tbasic_machine=arm-unknown\n\t\t\t\tbasic_os=mingw32ce\n\t\t\t\t;;\n\t\t\tmonitor)\n\t\t\t\tbasic_machine=m68k-rom68k\n\t\t\t\tbasic_os=coff\n\t\t\t\t;;\n\t\t\tmorphos)\n\t\t\t\tbasic_machine=powerpc-unknown\n\t\t\t\tbasic_os=morphos\n\t\t\t\t;;\n\t\t\tmoxiebox)\n\t\t\t\tbasic_machine=moxie-unknown\n\t\t\t\tbasic_os=moxiebox\n\t\t\t\t;;\n\t\t\tmsdos)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=msdos\n\t\t\t\t;;\n\t\t\tmsys)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=msys\n\t\t\t\t;;\n\t\t\tmvs)\n\t\t\t\tbasic_machine=i370-ibm\n\t\t\t\tbasic_os=mvs\n\t\t\t\t;;\n\t\t\tnacl)\n\t\t\t\tbasic_machine=le32-unknown\n\t\t\t\tbasic_os=nacl\n\t\t\t\t;;\n\t\t\tncr3000)\n\t\t\t\tbasic_machine=i486-ncr\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tnetbsd386)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=netbsd\n\t\t\t\t;;\n\t\t\tnetwinder)\n\t\t\t\tbasic_machine=armv4l-rebel\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tnews | news700 | news800 | news900)\n\t\t\t\tbasic_machine=m68k-sony\n\t\t\t\tbasic_os=newsos\n\t\t\t\t;;\n\t\t\tnews1000)\n\t\t\t\tbasic_machine=m68030-sony\n\t\t\t\tbasic_os=newsos\n\t\t\t\t;;\n\t\t\tnecv70)\n\t\t\t\tbasic_machine=v70-nec\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tnh3000)\n\t\t\t\tbasic_machine=m68k-harris\n\t\t\t\tbasic_os=cxux\n\t\t\t\t;;\n\t\t\tnh[45]000)\n\t\t\t\tbasic_machine=m88k-harris\n\t\t\t\tbasic_os=cxux\n\t\t\t\t;;\n\t\t\tnindy960)\n\t\t\t\tbasic_machine=i960-intel\n\t\t\t\tbasic_os=nindy\n\t\t\t\t;;\n\t\t\tmon960)\n\t\t\t\tbasic_machine=i960-intel\n\t\t\t\tbasic_os=mon960\n\t\t\t\t;;\n\t\t\tnonstopux)\n\t\t\t\tbasic_machine=mips-compaq\n\t\t\t\tbasic_os=nonstopux\n\t\t\t\t;;\n\t\t\tos400)\n\t\t\t\tbasic_machine=powerpc-ibm\n\t\t\t\tbasic_os=os400\n\t\t\t\t;;\n\t\t\tOSE68000 | ose68000)\n\t\t\t\tbasic_machine=m68000-ericsson\n\t\t\t\tbasic_os=ose\n\t\t\t\t;;\n\t\t\tos68k)\n\t\t\t\tbasic_machine=m68k-none\n\t\t\t\tbasic_os=os68k\n\t\t\t\t;;\n\t\t\tparagon)\n\t\t\t\tbasic_machine=i860-intel\n\t\t\t\tbasic_os=osf\n\t\t\t\t;;\n\t\t\tparisc)\n\t\t\t\tbasic_machine=hppa-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tpsp)\n\t\t\t\tbasic_machine=mipsallegrexel-sony\n\t\t\t\tbasic_os=psp\n\t\t\t\t;;\n\t\t\tpw32)\n\t\t\t\tbasic_machine=i586-unknown\n\t\t\t\tbasic_os=pw32\n\t\t\t\t;;\n\t\t\trdos | rdos64)\n\t\t\t\tbasic_machine=x86_64-pc\n\t\t\t\tbasic_os=rdos\n\t\t\t\t;;\n\t\t\trdos32)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=rdos\n\t\t\t\t;;\n\t\t\trom68k)\n\t\t\t\tbasic_machine=m68k-rom68k\n\t\t\t\tbasic_os=coff\n\t\t\t\t;;\n\t\t\tsa29200)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tsei)\n\t\t\t\tbasic_machine=mips-sei\n\t\t\t\tbasic_os=seiux\n\t\t\t\t;;\n\t\t\tsequent)\n\t\t\t\tbasic_machine=i386-sequent\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsps7)\n\t\t\t\tbasic_machine=m68k-bull\n\t\t\t\tbasic_os=sysv2\n\t\t\t\t;;\n\t\t\tst2000)\n\t\t\t\tbasic_machine=m68k-tandem\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tstratus)\n\t\t\t\tbasic_machine=i860-stratus\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tsun2)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun2os3)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun2os4)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun3)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun3os3)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun3os4)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun4)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun4os3)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun4os4)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun4sol2)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=solaris2\n\t\t\t\t;;\n\t\t\tsun386 | sun386i | roadrunner)\n\t\t\t\tbasic_machine=i386-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsv1)\n\t\t\t\tbasic_machine=sv1-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tsymmetry)\n\t\t\t\tbasic_machine=i386-sequent\n\t\t\t\tbasic_os=dynix\n\t\t\t\t;;\n\t\t\tt3e)\n\t\t\t\tbasic_machine=alphaev5-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tt90)\n\t\t\t\tbasic_machine=t90-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\ttoad1)\n\t\t\t\tbasic_machine=pdp10-xkl\n\t\t\t\tbasic_os=tops20\n\t\t\t\t;;\n\t\t\ttpf)\n\t\t\t\tbasic_machine=s390x-ibm\n\t\t\t\tbasic_os=tpf\n\t\t\t\t;;\n\t\t\tudi29k)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tultra3)\n\t\t\t\tbasic_machine=a29k-nyu\n\t\t\t\tbasic_os=sym1\n\t\t\t\t;;\n\t\t\tv810 | necv810)\n\t\t\t\tbasic_machine=v810-nec\n\t\t\t\tbasic_os=none\n\t\t\t\t;;\n\t\t\tvaxv)\n\t\t\t\tbasic_machine=vax-dec\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tvms)\n\t\t\t\tbasic_machine=vax-dec\n\t\t\t\tbasic_os=vms\n\t\t\t\t;;\n\t\t\tvsta)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=vsta\n\t\t\t\t;;\n\t\t\tvxworks960)\n\t\t\t\tbasic_machine=i960-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\tvxworks68)\n\t\t\t\tbasic_machine=m68k-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\tvxworks29k)\n\t\t\t\tbasic_machine=a29k-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\txbox)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=mingw32\n\t\t\t\t;;\n\t\t\tymp)\n\t\t\t\tbasic_machine=ymp-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\tbasic_machine=$1\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\n# Decode 1-component or ad-hoc basic machines\ncase $basic_machine in\n\t# Here we handle the default manufacturer of certain CPU types.  It is in\n\t# some cases the only manufacturer, in others, it is the most popular.\n\tw89k)\n\t\tcpu=hppa1.1\n\t\tvendor=winbond\n\t\t;;\n\top50n)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\t;;\n\top60c)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\t;;\n\tibm*)\n\t\tcpu=i370\n\t\tvendor=ibm\n\t\t;;\n\torion105)\n\t\tcpu=clipper\n\t\tvendor=highlevel\n\t\t;;\n\tmac | mpw | mac-mpw)\n\t\tcpu=m68k\n\t\tvendor=apple\n\t\t;;\n\tpmac | pmac-mpw)\n\t\tcpu=powerpc\n\t\tvendor=apple\n\t\t;;\n\n\t# Recognize the various machine names and aliases which stand\n\t# for a CPU type and a company and sometimes even an OS.\n\t3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)\n\t\tcpu=m68000\n\t\tvendor=att\n\t\t;;\n\t3b*)\n\t\tcpu=we32k\n\t\tvendor=att\n\t\t;;\n\tbluegene*)\n\t\tcpu=powerpc\n\t\tvendor=ibm\n\t\tbasic_os=cnk\n\t\t;;\n\tdecsystem10* | dec10*)\n\t\tcpu=pdp10\n\t\tvendor=dec\n\t\tbasic_os=tops10\n\t\t;;\n\tdecsystem20* | dec20*)\n\t\tcpu=pdp10\n\t\tvendor=dec\n\t\tbasic_os=tops20\n\t\t;;\n\tdelta | 3300 | motorola-3300 | motorola-delta \\\n\t      | 3300-motorola | delta-motorola)\n\t\tcpu=m68k\n\t\tvendor=motorola\n\t\t;;\n\tdpx2*)\n\t\tcpu=m68k\n\t\tvendor=bull\n\t\tbasic_os=sysv3\n\t\t;;\n\tencore | umax | mmax)\n\t\tcpu=ns32k\n\t\tvendor=encore\n\t\t;;\n\telxsi)\n\t\tcpu=elxsi\n\t\tvendor=elxsi\n\t\tbasic_os=${basic_os:-bsd}\n\t\t;;\n\tfx2800)\n\t\tcpu=i860\n\t\tvendor=alliant\n\t\t;;\n\tgenix)\n\t\tcpu=ns32k\n\t\tvendor=ns\n\t\t;;\n\th3050r* | hiux*)\n\t\tcpu=hppa1.1\n\t\tvendor=hitachi\n\t\tbasic_os=hiuxwe2\n\t\t;;\n\thp3k9[0-9][0-9] | hp9[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\thp9k2[0-9][0-9] | hp9k31[0-9])\n\t\tcpu=m68000\n\t\tvendor=hp\n\t\t;;\n\thp9k3[2-9][0-9])\n\t\tcpu=m68k\n\t\tvendor=hp\n\t\t;;\n\thp9k6[0-9][0-9] | hp6[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\thp9k7[0-79][0-9] | hp7[0-79][0-9])\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k78[0-9] | hp78[0-9])\n\t\t# FIXME: really hppa2.0-hp\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)\n\t\t# FIXME: really hppa2.0-hp\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[0-9][13679] | hp8[0-9][13679])\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[0-9][0-9] | hp8[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\ti*86v32)\n\t\tcpu=$(echo \"$1\" | sed -e 's/86.*/86/')\n\t\tvendor=pc\n\t\tbasic_os=sysv32\n\t\t;;\n\ti*86v4*)\n\t\tcpu=$(echo \"$1\" | sed -e 's/86.*/86/')\n\t\tvendor=pc\n\t\tbasic_os=sysv4\n\t\t;;\n\ti*86v)\n\t\tcpu=$(echo \"$1\" | sed -e 's/86.*/86/')\n\t\tvendor=pc\n\t\tbasic_os=sysv\n\t\t;;\n\ti*86sol2)\n\t\tcpu=$(echo \"$1\" | sed -e 's/86.*/86/')\n\t\tvendor=pc\n\t\tbasic_os=solaris2\n\t\t;;\n\tj90 | j90-cray)\n\t\tcpu=j90\n\t\tvendor=cray\n\t\tbasic_os=${basic_os:-unicos}\n\t\t;;\n\tiris | iris4d)\n\t\tcpu=mips\n\t\tvendor=sgi\n\t\tcase $basic_os in\n\t\t    irix*)\n\t\t\t;;\n\t\t    *)\n\t\t\tbasic_os=irix4\n\t\t\t;;\n\t\tesac\n\t\t;;\n\tminiframe)\n\t\tcpu=m68000\n\t\tvendor=convergent\n\t\t;;\n\t*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)\n\t\tcpu=m68k\n\t\tvendor=atari\n\t\tbasic_os=mint\n\t\t;;\n\tnews-3600 | risc-news)\n\t\tcpu=mips\n\t\tvendor=sony\n\t\tbasic_os=newsos\n\t\t;;\n\tnext | m*-next)\n\t\tcpu=m68k\n\t\tvendor=next\n\t\tcase $basic_os in\n\t\t    openstep*)\n\t\t        ;;\n\t\t    nextstep*)\n\t\t\t;;\n\t\t    ns2*)\n\t\t      basic_os=nextstep2\n\t\t\t;;\n\t\t    *)\n\t\t      basic_os=nextstep3\n\t\t\t;;\n\t\tesac\n\t\t;;\n\tnp1)\n\t\tcpu=np1\n\t\tvendor=gould\n\t\t;;\n\top50n-* | op60c-*)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\tbasic_os=proelf\n\t\t;;\n\tpa-hitachi)\n\t\tcpu=hppa1.1\n\t\tvendor=hitachi\n\t\tbasic_os=hiuxwe2\n\t\t;;\n\tpbd)\n\t\tcpu=sparc\n\t\tvendor=tti\n\t\t;;\n\tpbb)\n\t\tcpu=m68k\n\t\tvendor=tti\n\t\t;;\n\tpc532)\n\t\tcpu=ns32k\n\t\tvendor=pc532\n\t\t;;\n\tpn)\n\t\tcpu=pn\n\t\tvendor=gould\n\t\t;;\n\tpower)\n\t\tcpu=power\n\t\tvendor=ibm\n\t\t;;\n\tps2)\n\t\tcpu=i386\n\t\tvendor=ibm\n\t\t;;\n\trm[46]00)\n\t\tcpu=mips\n\t\tvendor=siemens\n\t\t;;\n\trtpc | rtpc-*)\n\t\tcpu=romp\n\t\tvendor=ibm\n\t\t;;\n\tsde)\n\t\tcpu=mipsisa32\n\t\tvendor=sde\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tsimso-wrs)\n\t\tcpu=sparclite\n\t\tvendor=wrs\n\t\tbasic_os=vxworks\n\t\t;;\n\ttower | tower-32)\n\t\tcpu=m68k\n\t\tvendor=ncr\n\t\t;;\n\tvpp*|vx|vx-*)\n\t\tcpu=f301\n\t\tvendor=fujitsu\n\t\t;;\n\tw65)\n\t\tcpu=w65\n\t\tvendor=wdc\n\t\t;;\n\tw89k-*)\n\t\tcpu=hppa1.1\n\t\tvendor=winbond\n\t\tbasic_os=proelf\n\t\t;;\n\tnone)\n\t\tcpu=none\n\t\tvendor=none\n\t\t;;\n\tleon|leon[3-9])\n\t\tcpu=sparc\n\t\tvendor=$basic_machine\n\t\t;;\n\tleon-*|leon[3-9]-*)\n\t\tcpu=sparc\n\t\tvendor=$(echo \"$basic_machine\" | sed 's/-.*//')\n\t\t;;\n\n\t*-*)\n\t\t# shellcheck disable=SC2162\n\t\tIFS=\"-\" read cpu vendor <<EOF\n$basic_machine\nEOF\n\t\t;;\n\t# We use `pc' rather than `unknown'\n\t# because (1) that's what they normally are, and\n\t# (2) the word \"unknown\" tends to confuse beginning users.\n\ti*86 | x86_64)\n\t\tcpu=$basic_machine\n\t\tvendor=pc\n\t\t;;\n\t# These rules are duplicated from below for sake of the special case above;\n\t# i.e. things that normalized to x86 arches should also default to \"pc\"\n\tpc98)\n\t\tcpu=i386\n\t\tvendor=pc\n\t\t;;\n\tx64 | amd64)\n\t\tcpu=x86_64\n\t\tvendor=pc\n\t\t;;\n\t# Recognize the basic CPU types without company name.\n\t*)\n\t\tcpu=$basic_machine\n\t\tvendor=unknown\n\t\t;;\nesac\n\nunset -v basic_machine\n\n# Decode basic machines in the full and proper CPU-Company form.\ncase $cpu-$vendor in\n\t# Here we handle the default manufacturer of certain CPU types in canonical form. It is in\n\t# some cases the only manufacturer, in others, it is the most popular.\n\tcraynv-unknown)\n\t\tvendor=cray\n\t\tbasic_os=${basic_os:-unicosmp}\n\t\t;;\n\tc90-unknown | c90-cray)\n\t\tvendor=cray\n\t\tbasic_os=${Basic_os:-unicos}\n\t\t;;\n\tfx80-unknown)\n\t\tvendor=alliant\n\t\t;;\n\tromp-unknown)\n\t\tvendor=ibm\n\t\t;;\n\tmmix-unknown)\n\t\tvendor=knuth\n\t\t;;\n\tmicroblaze-unknown | microblazeel-unknown)\n\t\tvendor=xilinx\n\t\t;;\n\trs6000-unknown)\n\t\tvendor=ibm\n\t\t;;\n\tvax-unknown)\n\t\tvendor=dec\n\t\t;;\n\tpdp11-unknown)\n\t\tvendor=dec\n\t\t;;\n\twe32k-unknown)\n\t\tvendor=att\n\t\t;;\n\tcydra-unknown)\n\t\tvendor=cydrome\n\t\t;;\n\ti370-ibm*)\n\t\tvendor=ibm\n\t\t;;\n\torion-unknown)\n\t\tvendor=highlevel\n\t\t;;\n\txps-unknown | xps100-unknown)\n\t\tcpu=xps100\n\t\tvendor=honeywell\n\t\t;;\n\n\t# Here we normalize CPU types with a missing or matching vendor\n\tdpx20-unknown | dpx20-bull)\n\t\tcpu=rs6000\n\t\tvendor=bull\n\t\tbasic_os=${basic_os:-bosx}\n\t\t;;\n\n\t# Here we normalize CPU types irrespective of the vendor\n\tamd64-*)\n\t\tcpu=x86_64\n\t\t;;\n\tblackfin-*)\n\t\tcpu=bfin\n\t\tbasic_os=linux\n\t\t;;\n\tc54x-*)\n\t\tcpu=tic54x\n\t\t;;\n\tc55x-*)\n\t\tcpu=tic55x\n\t\t;;\n\tc6x-*)\n\t\tcpu=tic6x\n\t\t;;\n\te500v[12]-*)\n\t\tcpu=powerpc\n\t\tbasic_os=${basic_os}\"spe\"\n\t\t;;\n\tmips3*-*)\n\t\tcpu=mips64\n\t\t;;\n\tms1-*)\n\t\tcpu=mt\n\t\t;;\n\tm68knommu-*)\n\t\tcpu=m68k\n\t\tbasic_os=linux\n\t\t;;\n\tm9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)\n\t\tcpu=s12z\n\t\t;;\n\topenrisc-*)\n\t\tcpu=or32\n\t\t;;\n\tparisc-*)\n\t\tcpu=hppa\n\t\tbasic_os=linux\n\t\t;;\n\tpentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)\n\t\tcpu=i586\n\t\t;;\n\tpentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)\n\t\tcpu=i686\n\t\t;;\n\tpentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)\n\t\tcpu=i686\n\t\t;;\n\tpentium4-*)\n\t\tcpu=i786\n\t\t;;\n\tpc98-*)\n\t\tcpu=i386\n\t\t;;\n\tppc-* | ppcbe-*)\n\t\tcpu=powerpc\n\t\t;;\n\tppcle-* | powerpclittle-*)\n\t\tcpu=powerpcle\n\t\t;;\n\tppc64-*)\n\t\tcpu=powerpc64\n\t\t;;\n\tppc64le-* | powerpc64little-*)\n\t\tcpu=powerpc64le\n\t\t;;\n\tsb1-*)\n\t\tcpu=mipsisa64sb1\n\t\t;;\n\tsb1el-*)\n\t\tcpu=mipsisa64sb1el\n\t\t;;\n\tsh5e[lb]-*)\n\t\tcpu=$(echo \"$cpu\" | sed 's/^\\(sh.\\)e\\(.\\)$/\\1\\2e/')\n\t\t;;\n\tspur-*)\n\t\tcpu=spur\n\t\t;;\n\tstrongarm-* | thumb-*)\n\t\tcpu=arm\n\t\t;;\n\ttx39-*)\n\t\tcpu=mipstx39\n\t\t;;\n\ttx39el-*)\n\t\tcpu=mipstx39el\n\t\t;;\n\tx64-*)\n\t\tcpu=x86_64\n\t\t;;\n\txscale-* | xscalee[bl]-*)\n\t\tcpu=$(echo \"$cpu\" | sed 's/^xscale/arm/')\n\t\t;;\n\tarm64-*)\n\t\tcpu=aarch64\n\t\t;;\n\n\t# Recognize the canonical CPU Types that limit and/or modify the\n\t# company names they are paired with.\n\tcr16-*)\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tcrisv32-* | etraxfs*-*)\n\t\tcpu=crisv32\n\t\tvendor=axis\n\t\t;;\n\tcris-* | etrax*-*)\n\t\tcpu=cris\n\t\tvendor=axis\n\t\t;;\n\tcrx-*)\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tneo-tandem)\n\t\tcpu=neo\n\t\tvendor=tandem\n\t\t;;\n\tnse-tandem)\n\t\tcpu=nse\n\t\tvendor=tandem\n\t\t;;\n\tnsr-tandem)\n\t\tcpu=nsr\n\t\tvendor=tandem\n\t\t;;\n\tnsv-tandem)\n\t\tcpu=nsv\n\t\tvendor=tandem\n\t\t;;\n\tnsx-tandem)\n\t\tcpu=nsx\n\t\tvendor=tandem\n\t\t;;\n\tmipsallegrexel-sony)\n\t\tcpu=mipsallegrexel\n\t\tvendor=sony\n\t\t;;\n\ttile*-*)\n\t\tbasic_os=${basic_os:-linux-gnu}\n\t\t;;\n\n\t*)\n\t\t# Recognize the canonical CPU types that are allowed with any\n\t\t# company name.\n\t\tcase $cpu in\n\t\t\t1750a | 580 \\\n\t\t\t| a29k \\\n\t\t\t| aarch64 | aarch64_be \\\n\t\t\t| abacus \\\n\t\t\t| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \\\n\t\t\t| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \\\n\t\t\t| alphapca5[67] | alpha64pca5[67] \\\n\t\t\t| am33_2.0 \\\n\t\t\t| amdgcn \\\n\t\t\t| arc | arceb | arc64 \\\n\t\t\t| arm | arm[lb]e | arme[lb] | armv* \\\n\t\t\t| avr | avr32 \\\n\t\t\t| asmjs \\\n\t\t\t| ba \\\n\t\t\t| be32 | be64 \\\n\t\t\t| bfin | bpf | bs2000 \\\n\t\t\t| c[123]* | c30 | [cjt]90 | c4x \\\n\t\t\t| c8051 | clipper | craynv | csky | cydra \\\n\t\t\t| d10v | d30v | dlx | dsp16xx \\\n\t\t\t| e2k | elxsi | epiphany \\\n\t\t\t| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \\\n\t\t\t| h8300 | h8500 \\\n\t\t\t| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \\\n\t\t\t| hexagon \\\n\t\t\t| i370 | i*86 | i860 | i960 | ia16 | ia64 \\\n\t\t\t| ip2k | iq2000 \\\n\t\t\t| k1om \\\n\t\t\t| le32 | le64 \\\n\t\t\t| lm32 \\\n\t\t\t| loongarch32 | loongarch64 | loongarchx32 \\\n\t\t\t| m32c | m32r | m32rle \\\n\t\t\t| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \\\n\t\t\t| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \\\n\t\t\t| m88110 | m88k | maxq | mb | mcore | mep | metag \\\n\t\t\t| microblaze | microblazeel \\\n\t\t\t| mips | mipsbe | mipseb | mipsel | mipsle \\\n\t\t\t| mips16 \\\n\t\t\t| mips64 | mips64eb | mips64el \\\n\t\t\t| mips64octeon | mips64octeonel \\\n\t\t\t| mips64orion | mips64orionel \\\n\t\t\t| mips64r5900 | mips64r5900el \\\n\t\t\t| mips64vr | mips64vrel \\\n\t\t\t| mips64vr4100 | mips64vr4100el \\\n\t\t\t| mips64vr4300 | mips64vr4300el \\\n\t\t\t| mips64vr5000 | mips64vr5000el \\\n\t\t\t| mips64vr5900 | mips64vr5900el \\\n\t\t\t| mipsisa32 | mipsisa32el \\\n\t\t\t| mipsisa32r2 | mipsisa32r2el \\\n\t\t\t| mipsisa32r3 | mipsisa32r3el \\\n\t\t\t| mipsisa32r5 | mipsisa32r5el \\\n\t\t\t| mipsisa32r6 | mipsisa32r6el \\\n\t\t\t| mipsisa64 | mipsisa64el \\\n\t\t\t| mipsisa64r2 | mipsisa64r2el \\\n\t\t\t| mipsisa64r3 | mipsisa64r3el \\\n\t\t\t| mipsisa64r5 | mipsisa64r5el \\\n\t\t\t| mipsisa64r6 | mipsisa64r6el \\\n\t\t\t| mipsisa64sb1 | mipsisa64sb1el \\\n\t\t\t| mipsisa64sr71k | mipsisa64sr71kel \\\n\t\t\t| mipsr5900 | mipsr5900el \\\n\t\t\t| mipstx39 | mipstx39el \\\n\t\t\t| mmix \\\n\t\t\t| mn10200 | mn10300 \\\n\t\t\t| moxie \\\n\t\t\t| mt \\\n\t\t\t| msp430 \\\n\t\t\t| nds32 | nds32le | nds32be \\\n\t\t\t| nfp \\\n\t\t\t| nios | nios2 | nios2eb | nios2el \\\n\t\t\t| none | np1 | ns16k | ns32k | nvptx \\\n\t\t\t| open8 \\\n\t\t\t| or1k* \\\n\t\t\t| or32 \\\n\t\t\t| orion \\\n\t\t\t| picochip \\\n\t\t\t| pdp10 | pdp11 | pj | pjl | pn | power \\\n\t\t\t| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \\\n\t\t\t| pru \\\n\t\t\t| pyramid \\\n\t\t\t| riscv | riscv32 | riscv32be | riscv64 | riscv64be \\\n\t\t\t| rl78 | romp | rs6000 | rx \\\n\t\t\t| s390 | s390x \\\n\t\t\t| score \\\n\t\t\t| sh | shl \\\n\t\t\t| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \\\n\t\t\t| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \\\n\t\t\t| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \\\n\t\t\t| sparclite \\\n\t\t\t| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \\\n\t\t\t| spu \\\n\t\t\t| tahoe \\\n\t\t\t| thumbv7* \\\n\t\t\t| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \\\n\t\t\t| tron \\\n\t\t\t| ubicom32 \\\n\t\t\t| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \\\n\t\t\t| vax \\\n\t\t\t| visium \\\n\t\t\t| w65 \\\n\t\t\t| wasm32 | wasm64 \\\n\t\t\t| we32k \\\n\t\t\t| x86 | x86_64 | xc16x | xgate | xps100 \\\n\t\t\t| xstormy16 | xtensa* \\\n\t\t\t| ymp \\\n\t\t\t| z8k | z80)\n\t\t\t\t;;\n\n\t\t\t*)\n\t\t\t\techo Invalid configuration \\`\"$1\"\\': machine \\`\"$cpu-$vendor\"\\' not recognized 1>&2\n\t\t\t\texit 1\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\n# Here we canonicalize certain aliases for manufacturers.\ncase $vendor in\n\tdigital*)\n\t\tvendor=dec\n\t\t;;\n\tcommodore*)\n\t\tvendor=cbm\n\t\t;;\n\t*)\n\t\t;;\nesac\n\n# Decode manufacturer-specific aliases for certain operating systems.\n\nif test x$basic_os != x\nthen\n\n# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just\n# set os.\ncase $basic_os in\n\tgnu/linux*)\n\t\tkernel=linux\n\t\tos=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')\n\t\t;;\n\tos2-emx)\n\t\tkernel=os2\n\t\tos=$(echo $basic_os | sed -e 's|os2-emx|emx|')\n\t\t;;\n\tnto-qnx*)\n\t\tkernel=nto\n\t\tos=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')\n\t\t;;\n\t*-*)\n\t\t# shellcheck disable=SC2162\n\t\tIFS=\"-\" read kernel os <<EOF\n$basic_os\nEOF\n\t\t;;\n\t# Default OS when just kernel was specified\n\tnto*)\n\t\tkernel=nto\n\t\tos=$(echo $basic_os | sed -e 's|nto|qnx|')\n\t\t;;\n\tlinux*)\n\t\tkernel=linux\n\t\tos=$(echo $basic_os | sed -e 's|linux|gnu|')\n\t\t;;\n\t*)\n\t\tkernel=\n\t\tos=$basic_os\n\t\t;;\nesac\n\n# Now, normalize the OS (knowing we just have one component, it's not a kernel,\n# etc.)\ncase $os in\n\t# First match some system type aliases that might get confused\n\t# with valid system types.\n\t# solaris* is a basic system type, with this one exception.\n\tauroraux)\n\t\tos=auroraux\n\t\t;;\n\tbluegene*)\n\t\tos=cnk\n\t\t;;\n\tsolaris1 | solaris1.*)\n\t\tos=$(echo $os | sed -e 's|solaris1|sunos4|')\n\t\t;;\n\tsolaris)\n\t\tos=solaris2\n\t\t;;\n\tunixware*)\n\t\tos=sysv4.2uw\n\t\t;;\n\t# es1800 is here to avoid being matched by es* (a different OS)\n\tes1800*)\n\t\tos=ose\n\t\t;;\n\t# Some version numbers need modification\n\tchorusos*)\n\t\tos=chorusos\n\t\t;;\n\tisc)\n\t\tos=isc2.2\n\t\t;;\n\tsco6)\n\t\tos=sco5v6\n\t\t;;\n\tsco5)\n\t\tos=sco3.2v5\n\t\t;;\n\tsco4)\n\t\tos=sco3.2v4\n\t\t;;\n\tsco3.2.[4-9]*)\n\t\tos=$(echo $os | sed -e 's/sco3.2./sco3.2v/')\n\t\t;;\n\tsco*v* | scout)\n\t\t# Don't match below\n\t\t;;\n\tsco*)\n\t\tos=sco3.2v2\n\t\t;;\n\tpsos*)\n\t\tos=psos\n\t\t;;\n\tqnx*)\n\t\tos=qnx\n\t\t;;\n\thiux*)\n\t\tos=hiuxwe2\n\t\t;;\n\tlynx*178)\n\t\tos=lynxos178\n\t\t;;\n\tlynx*5)\n\t\tos=lynxos5\n\t\t;;\n\tlynxos*)\n\t\t# don't get caught up in next wildcard\n\t\t;;\n\tlynx*)\n\t\tos=lynxos\n\t\t;;\n\tmac[0-9]*)\n\t\tos=$(echo \"$os\" | sed -e 's|mac|macos|')\n\t\t;;\n\topened*)\n\t\tos=openedition\n\t\t;;\n\tos400*)\n\t\tos=os400\n\t\t;;\n\tsunos5*)\n\t\tos=$(echo \"$os\" | sed -e 's|sunos5|solaris2|')\n\t\t;;\n\tsunos6*)\n\t\tos=$(echo \"$os\" | sed -e 's|sunos6|solaris3|')\n\t\t;;\n\twince*)\n\t\tos=wince\n\t\t;;\n\tutek*)\n\t\tos=bsd\n\t\t;;\n\tdynix*)\n\t\tos=bsd\n\t\t;;\n\tacis*)\n\t\tos=aos\n\t\t;;\n\tatheos*)\n\t\tos=atheos\n\t\t;;\n\tsyllable*)\n\t\tos=syllable\n\t\t;;\n\t386bsd)\n\t\tos=bsd\n\t\t;;\n\tctix* | uts*)\n\t\tos=sysv\n\t\t;;\n\tnova*)\n\t\tos=rtmk-nova\n\t\t;;\n\tns2)\n\t\tos=nextstep2\n\t\t;;\n\t# Preserve the version number of sinix5.\n\tsinix5.*)\n\t\tos=$(echo $os | sed -e 's|sinix|sysv|')\n\t\t;;\n\tsinix*)\n\t\tos=sysv4\n\t\t;;\n\ttpf*)\n\t\tos=tpf\n\t\t;;\n\ttriton*)\n\t\tos=sysv3\n\t\t;;\n\toss*)\n\t\tos=sysv3\n\t\t;;\n\tsvr4*)\n\t\tos=sysv4\n\t\t;;\n\tsvr3)\n\t\tos=sysv3\n\t\t;;\n\tsysvr4)\n\t\tos=sysv4\n\t\t;;\n\tose*)\n\t\tos=ose\n\t\t;;\n\t*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)\n\t\tos=mint\n\t\t;;\n\tdicos*)\n\t\tos=dicos\n\t\t;;\n\tpikeos*)\n\t\t# Until real need of OS specific support for\n\t\t# particular features comes up, bare metal\n\t\t# configurations are quite functional.\n\t\tcase $cpu in\n\t\t    arm*)\n\t\t\tos=eabi\n\t\t\t;;\n\t\t    *)\n\t\t\tos=elf\n\t\t\t;;\n\t\tesac\n\t\t;;\n\t*)\n\t\t# No normalization, but not necessarily accepted, that comes below.\n\t\t;;\nesac\n\nelse\n\n# Here we handle the default operating systems that come with various machines.\n# The value should be what the vendor currently ships out the door with their\n# machine or put another way, the most popular os provided with the machine.\n\n# Note that if you're going to try to match \"-MANUFACTURER\" here (say,\n# \"-sun\"), then you have to tell the case statement up towards the top\n# that MANUFACTURER isn't an operating system.  Otherwise, code above\n# will signal an error saying that MANUFACTURER isn't an operating\n# system, and we'll never get to this point.\n\nkernel=\ncase $cpu-$vendor in\n\tscore-*)\n\t\tos=elf\n\t\t;;\n\tspu-*)\n\t\tos=elf\n\t\t;;\n\t*-acorn)\n\t\tos=riscix1.2\n\t\t;;\n\tarm*-rebel)\n\t\tkernel=linux\n\t\tos=gnu\n\t\t;;\n\tarm*-semi)\n\t\tos=aout\n\t\t;;\n\tc4x-* | tic4x-*)\n\t\tos=coff\n\t\t;;\n\tc8051-*)\n\t\tos=elf\n\t\t;;\n\tclipper-intergraph)\n\t\tos=clix\n\t\t;;\n\thexagon-*)\n\t\tos=elf\n\t\t;;\n\ttic54x-*)\n\t\tos=coff\n\t\t;;\n\ttic55x-*)\n\t\tos=coff\n\t\t;;\n\ttic6x-*)\n\t\tos=coff\n\t\t;;\n\t# This must come before the *-dec entry.\n\tpdp10-*)\n\t\tos=tops20\n\t\t;;\n\tpdp11-*)\n\t\tos=none\n\t\t;;\n\t*-dec | vax-*)\n\t\tos=ultrix4.2\n\t\t;;\n\tm68*-apollo)\n\t\tos=domain\n\t\t;;\n\ti386-sun)\n\t\tos=sunos4.0.2\n\t\t;;\n\tm68000-sun)\n\t\tos=sunos3\n\t\t;;\n\tm68*-cisco)\n\t\tos=aout\n\t\t;;\n\tmep-*)\n\t\tos=elf\n\t\t;;\n\tmips*-cisco)\n\t\tos=elf\n\t\t;;\n\tmips*-*)\n\t\tos=elf\n\t\t;;\n\tor32-*)\n\t\tos=coff\n\t\t;;\n\t*-tti)\t# must be before sparc entry or we get the wrong os.\n\t\tos=sysv3\n\t\t;;\n\tsparc-* | *-sun)\n\t\tos=sunos4.1.1\n\t\t;;\n\tpru-*)\n\t\tos=elf\n\t\t;;\n\t*-be)\n\t\tos=beos\n\t\t;;\n\t*-ibm)\n\t\tos=aix\n\t\t;;\n\t*-knuth)\n\t\tos=mmixware\n\t\t;;\n\t*-wec)\n\t\tos=proelf\n\t\t;;\n\t*-winbond)\n\t\tos=proelf\n\t\t;;\n\t*-oki)\n\t\tos=proelf\n\t\t;;\n\t*-hp)\n\t\tos=hpux\n\t\t;;\n\t*-hitachi)\n\t\tos=hiux\n\t\t;;\n\ti860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)\n\t\tos=sysv\n\t\t;;\n\t*-cbm)\n\t\tos=amigaos\n\t\t;;\n\t*-dg)\n\t\tos=dgux\n\t\t;;\n\t*-dolphin)\n\t\tos=sysv3\n\t\t;;\n\tm68k-ccur)\n\t\tos=rtu\n\t\t;;\n\tm88k-omron*)\n\t\tos=luna\n\t\t;;\n\t*-next)\n\t\tos=nextstep\n\t\t;;\n\t*-sequent)\n\t\tos=ptx\n\t\t;;\n\t*-crds)\n\t\tos=unos\n\t\t;;\n\t*-ns)\n\t\tos=genix\n\t\t;;\n\ti370-*)\n\t\tos=mvs\n\t\t;;\n\t*-gould)\n\t\tos=sysv\n\t\t;;\n\t*-highlevel)\n\t\tos=bsd\n\t\t;;\n\t*-encore)\n\t\tos=bsd\n\t\t;;\n\t*-sgi)\n\t\tos=irix\n\t\t;;\n\t*-siemens)\n\t\tos=sysv4\n\t\t;;\n\t*-masscomp)\n\t\tos=rtu\n\t\t;;\n\tf30[01]-fujitsu | f700-fujitsu)\n\t\tos=uxpv\n\t\t;;\n\t*-rom68k)\n\t\tos=coff\n\t\t;;\n\t*-*bug)\n\t\tos=coff\n\t\t;;\n\t*-apple)\n\t\tos=macos\n\t\t;;\n\t*-atari*)\n\t\tos=mint\n\t\t;;\n\t*-wrs)\n\t\tos=vxworks\n\t\t;;\n\t*)\n\t\tos=none\n\t\t;;\nesac\n\nfi\n\n# Now, validate our (potentially fixed-up) OS.\ncase $os in\n\t# Sometimes we do \"kernel-libc\", so those need to count as OSes.\n\tmusl* | newlib* | uclibc*)\n\t\t;;\n\t# Likewise for \"kernel-abi\"\n\teabi* | gnueabi*)\n\t\t;;\n\t# VxWorks passes extra cpu info in the 4th filed.\n\tsimlinux | simwindows | spe)\n\t\t;;\n\t# Now accept the basic system types.\n\t# The portable systems comes first.\n\t# Each alternative MUST end in a * to match a version number.\n\tgnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \\\n\t     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \\\n\t     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \\\n\t     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \\\n\t     | hiux* | abug | nacl* | netware* | windows* \\\n\t     | os9* | macos* | osx* | ios* \\\n\t     | mpw* | magic* | mmixware* | mon960* | lnews* \\\n\t     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \\\n\t     | aos* | aros* | cloudabi* | sortix* | twizzler* \\\n\t     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \\\n\t     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \\\n\t     | mirbsd* | netbsd* | dicos* | openedition* | ose* \\\n\t     | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \\\n\t     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \\\n\t     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \\\n\t     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \\\n\t     | udi* | lites* | ieee* | go32* | aux* | hcos* \\\n\t     | chorusrdb* | cegcc* | glidix* | serenity* \\\n\t     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \\\n\t     | midipix* | mingw32* | mingw64* | mint* \\\n\t     | uxpv* | beos* | mpeix* | udk* | moxiebox* \\\n\t     | interix* | uwin* | mks* | rhapsody* | darwin* \\\n\t     | openstep* | oskit* | conix* | pw32* | nonstopux* \\\n\t     | storm-chaos* | tops10* | tenex* | tops20* | its* \\\n\t     | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \\\n\t     | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \\\n\t     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \\\n\t     | skyos* | haiku* | rdos* | toppers* | drops* | es* \\\n\t     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \\\n\t     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \\\n\t     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)\n\t\t;;\n\t# This one is extra strict with allowed versions\n\tsco3.2v2 | sco3.2v[4-9]* | sco5v6*)\n\t\t# Don't forget version if it is 3.2v4 or newer.\n\t\t;;\n\tnone)\n\t\t;;\n\t*)\n\t\techo Invalid configuration \\`\"$1\"\\': OS \\`\"$os\"\\' not recognized 1>&2\n\t\texit 1\n\t\t;;\nesac\n\n# As a final step for OS-related things, validate the OS-kernel combination\n# (given a valid OS), if there is a kernel.\ncase $kernel-$os in\n\tlinux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )\n\t\t;;\n\tuclinux-uclibc* )\n\t\t;;\n\t-dietlibc* | -newlib* | -musl* | -uclibc* )\n\t\t# These are just libc implementations, not actual OSes, and thus\n\t\t# require a kernel.\n\t\techo \"Invalid configuration \\`$1': libc \\`$os' needs explicit kernel.\" 1>&2\n\t\texit 1\n\t\t;;\n\tkfreebsd*-gnu* | kopensolaris*-gnu*)\n\t\t;;\n\tvxworks-simlinux | vxworks-simwindows | vxworks-spe)\n\t\t;;\n\tnto-qnx*)\n\t\t;;\n\tos2-emx)\n\t\t;;\n\t*-eabi* | *-gnueabi*)\n\t\t;;\n\t-*)\n\t\t# Blank kernel with real OS is always fine.\n\t\t;;\n\t*-*)\n\t\techo \"Invalid configuration \\`$1': Kernel \\`$kernel' not known to work with OS \\`$os'.\" 1>&2\n\t\texit 1\n\t\t;;\nesac\n\n# Here we handle the case where we know the os, and the CPU type, but not the\n# manufacturer.  We pick the logical manufacturer.\ncase $vendor in\n\tunknown)\n\t\tcase $cpu-$os in\n\t\t\t*-riscix*)\n\t\t\t\tvendor=acorn\n\t\t\t\t;;\n\t\t\t*-sunos*)\n\t\t\t\tvendor=sun\n\t\t\t\t;;\n\t\t\t*-cnk* | *-aix*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-beos*)\n\t\t\t\tvendor=be\n\t\t\t\t;;\n\t\t\t*-hpux*)\n\t\t\t\tvendor=hp\n\t\t\t\t;;\n\t\t\t*-mpeix*)\n\t\t\t\tvendor=hp\n\t\t\t\t;;\n\t\t\t*-hiux*)\n\t\t\t\tvendor=hitachi\n\t\t\t\t;;\n\t\t\t*-unos*)\n\t\t\t\tvendor=crds\n\t\t\t\t;;\n\t\t\t*-dgux*)\n\t\t\t\tvendor=dg\n\t\t\t\t;;\n\t\t\t*-luna*)\n\t\t\t\tvendor=omron\n\t\t\t\t;;\n\t\t\t*-genix*)\n\t\t\t\tvendor=ns\n\t\t\t\t;;\n\t\t\t*-clix*)\n\t\t\t\tvendor=intergraph\n\t\t\t\t;;\n\t\t\t*-mvs* | *-opened*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-os400*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\ts390-* | s390x-*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-ptx*)\n\t\t\t\tvendor=sequent\n\t\t\t\t;;\n\t\t\t*-tpf*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-vxsim* | *-vxworks* | *-windiss*)\n\t\t\t\tvendor=wrs\n\t\t\t\t;;\n\t\t\t*-aux*)\n\t\t\t\tvendor=apple\n\t\t\t\t;;\n\t\t\t*-hms*)\n\t\t\t\tvendor=hitachi\n\t\t\t\t;;\n\t\t\t*-mpw* | *-macos*)\n\t\t\t\tvendor=apple\n\t\t\t\t;;\n\t\t\t*-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)\n\t\t\t\tvendor=atari\n\t\t\t\t;;\n\t\t\t*-vos*)\n\t\t\t\tvendor=stratus\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\necho \"$cpu-$vendor-${kernel:+$kernel-}$os\"\nexit\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"timestamp='\"\n# time-stamp-format: \"%:y-%02m-%02d\"\n# time-stamp-end: \"'\"\n# End:\n"
  },
  {
    "path": "depends/description.md",
    "content": "This is a system of building and caching dependencies necessary for building Munt. \nThere are several features that make it different from most similar systems:\n\n### It is designed to be builder and host agnostic\n\nIn theory, binaries for any target OS/architecture can be created, from a\nbuilder running any OS/architecture. In practice, build-side tools must be\nspecified when the defaults don't fit, and packages must be amended to work\non new hosts. For now, a build architecture of x86_64 is assumed, either on\nLinux or macOS.\n\n### No reliance on timestamps\n\nFile presence is used to determine what needs to be built. This makes the\nresults distributable and easily digestable by automated builders.\n\n### Each build only has its specified dependencies available at build-time.\n\nFor each build, the sysroot is wiped and the (recursive) dependencies are\ninstalled. This makes each build deterministic, since there will never be any\nunknown files available to cause side-effects.\n\n### Each package is cached and only rebuilt as needed.\n\nBefore building, a unique build-id is generated for each package. This id\nconsists of a hash of all files used to build the package (Makefiles, packages,\netc), and as well as a hash of the same data for each recursive dependency. If\nany portion of a package's build recipe changes, it will be rebuilt as well as\nany other package that depends on it. If any of the main makefiles (Makefile,\nfuncs.mk, etc) are changed, all packages will be rebuilt. After building, the\nresults are cached into a tarball that can be re-used and distributed.\n\n### Package build results are (relatively) deterministic.\n\nEach package is configured and patched so that it will yield the same\nbuild-results with each consequent build, within a reasonable set of\nconstraints. Some things like timestamp insertion are unavoidable, and are\nbeyond the scope of this system. Additionally, the toolchain itself must be\ncapable of deterministic results. When revisions are properly bumped, a cached\nbuild should represent an exact single payload.\n\n### Sources are fetched and verified automatically\n\nEach package must define its source location and checksum. The build will fail\nif the fetched source does not match. Sources may be pre-seeded and/or cached\nas desired.\n\n### Self-cleaning\n\nBuild and staging dirs are wiped after use, and any previous version of a\ncached result is removed following a successful build. Automated builders\nshould be able to build each revision and store the results with no further\nintervention.\n"
  },
  {
    "path": "depends/funcs.mk",
    "content": "define int_vars\n#Set defaults for vars which may be overridden per-package\n$(1)_cc=$$($$($(1)_type)_CC)\n$(1)_cxx=$$($$($(1)_type)_CXX)\n$(1)_objc=$$($$($(1)_type)_OBJC)\n$(1)_objcxx=$$($$($(1)_type)_OBJCXX)\n$(1)_ar=$$($$($(1)_type)_AR)\n$(1)_ranlib=$$($$($(1)_type)_RANLIB)\n$(1)_libtool=$$($$($(1)_type)_LIBTOOL)\n$(1)_nm=$$($$($(1)_type)_NM)\n$(1)_cflags=$$($$($(1)_type)_CFLAGS) \\\n            $$($$($(1)_type)_$$(release_type)_CFLAGS)\n$(1)_cxxflags=$$($$($(1)_type)_CXXFLAGS) \\\n              $$($$($(1)_type)_$$(release_type)_CXXFLAGS)\n$(1)_ldflags=$$($$($(1)_type)_LDFLAGS) \\\n             $$($$($(1)_type)_$$(release_type)_LDFLAGS) \\\n             -L$$($($(1)_type)_prefix)/lib\n$(1)_cppflags=$$($$($(1)_type)_CPPFLAGS) \\\n              $$($$($(1)_type)_$$(release_type)_CPPFLAGS) \\\n              -I$$($$($(1)_type)_prefix)/include\n$(1)_recipe_hash:=\nendef\n\ndefine int_get_all_dependencies\n$(sort $(foreach dep,$(2),$(2) $(call int_get_all_dependencies,$(1),$($(dep)_dependencies))))\nendef\n\ndefine fetch_file_inner\n    ( mkdir -p $$($(1)_download_dir) && echo Fetching $(3) from $(2) && \\\n    $(build_DOWNLOAD) \"$$($(1)_download_dir)/$(4).temp\" \"$(2)/$(3)\" && \\\n    echo \"$(5)  $$($(1)_download_dir)/$(4).temp\" > $$($(1)_download_dir)/.$(4).hash && \\\n    $(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \\\n    mv $$($(1)_download_dir)/$(4).temp $$($(1)_source_dir)/$(4) && \\\n    rm -rf $$($(1)_download_dir) )\nendef\n\ndefine fetch_file\n    ( test -f $$($(1)_source_dir)/$(4) || \\\n    ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \\\n      $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))\nendef\n\ndefine int_get_build_recipe_hash\n$(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d\" \" -f1))\n$(eval $(1)_recipe_hash:=$(shell echo -n \"$($(1)_all_file_checksums)\" | $(build_SHA256SUM) | cut -d\" \" -f1))\nendef\n\ndefine int_get_build_id\n$(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies))\n$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($($(1)_type)_native_binutils) $($(1)_dependencies)))\n$(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash)))\n$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps) $($($(1)_type)_id))\n$(eval $(1)_build_id:=$(shell echo -n \"$($(1)_build_id_long)\" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)))\nfinal_build_id_long+=$($(package)_build_id_long)\n\n#compute package-specific paths\n$(1)_build_subdir?=.\n$(1)_download_file?=$($(1)_file_name)\n$(1)_source_dir:=$(SOURCES_PATH)\n$(1)_source:=$$($(1)_source_dir)/$($(1)_file_name)\n$(1)_staging_dir=$(base_staging_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)\n$(1)_staging_prefix_dir:=$$($(1)_staging_dir)$($($(1)_type)_prefix)\n$(1)_extract_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)\n$(1)_download_dir:=$(base_download_dir)/$(1)-$($(1)_version)\n$(1)_build_dir:=$$($(1)_extract_dir)/$$($(1)_build_subdir)\n$(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz.hash\n$(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id)\n$(1)_prefixbin:=$($($(1)_type)_prefix)/bin/\n$(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz\n$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)\n\n#stamps\n$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash\n$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted\n$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed\n$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned\n$(1)_built=$$($(1)_build_dir)/.stamp_built\n$(1)_configured=$$($(1)_build_dir)/.stamp_configured\n$(1)_staged=$$($(1)_staging_dir)/.stamp_staged\n$(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed\n$(1)_download_path_fixed=$(subst :,\\:,$$($(1)_download_path))\n\n\n#default commands\n# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior\n$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \\:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash))\n$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo \"$$($(1)_sha256_hash)  $$($(1)_source)\" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash &&  $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_TAR) --no-same-owner --strip-components=1 -xf $$($(1)_source)\n$(1)_preprocess_cmds ?=\n$(1)_build_cmds ?=\n$(1)_config_cmds ?=\n$(1)_stage_cmds ?=\n$(1)_set_vars ?=\n\n\nall_sources+=$$($(1)_fetched)\nendef\n#$(foreach dep_target,$($(1)_all_dependencies),$(eval $(1)_dependency_targets=$($(dep_target)_cached)))\n\n\ndefine int_config_attach_build_config\n$(eval $(call $(1)_set_vars,$(1)))\n$(1)_cflags+=$($(1)_cflags_$(release_type))\n$(1)_cflags+=$($(1)_cflags_$(host_arch)) $($(1)_cflags_$(host_arch)_$(release_type))\n$(1)_cflags+=$($(1)_cflags_$(host_os)) $($(1)_cflags_$(host_os)_$(release_type))\n$(1)_cflags+=$($(1)_cflags_$(host_arch)_$(host_os)) $($(1)_cflags_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_cxxflags+=$($(1)_cxxflags_$(release_type))\n$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)) $($(1)_cxxflags_$(host_arch)_$(release_type))\n$(1)_cxxflags+=$($(1)_cxxflags_$(host_os)) $($(1)_cxxflags_$(host_os)_$(release_type))\n$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)_$(host_os)) $($(1)_cxxflags_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_cppflags+=$($(1)_cppflags_$(release_type))\n$(1)_cppflags+=$($(1)_cppflags_$(host_arch)) $($(1)_cppflags_$(host_arch)_$(release_type))\n$(1)_cppflags+=$($(1)_cppflags_$(host_os)) $($(1)_cppflags_$(host_os)_$(release_type))\n$(1)_cppflags+=$($(1)_cppflags_$(host_arch)_$(host_os)) $($(1)_cppflags_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_ldflags+=$($(1)_ldflags_$(release_type))\n$(1)_ldflags+=$($(1)_ldflags_$(host_arch)) $($(1)_ldflags_$(host_arch)_$(release_type))\n$(1)_ldflags+=$($(1)_ldflags_$(host_os)) $($(1)_ldflags_$(host_os)_$(release_type))\n$(1)_ldflags+=$($(1)_ldflags_$(host_arch)_$(host_os)) $($(1)_ldflags_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_build_opts+=$$($(1)_build_opts_$(release_type))\n$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)) $$($(1)_build_opts_$(host_arch)_$(release_type))\n$(1)_build_opts+=$$($(1)_build_opts_$(host_os)) $$($(1)_build_opts_$(host_os)_$(release_type))\n$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)_$(host_os)) $$($(1)_build_opts_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_config_opts+=$$($(1)_config_opts_$(release_type))\n$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)) $$($(1)_config_opts_$(host_arch)_$(release_type))\n$(1)_config_opts+=$$($(1)_config_opts_$(host_os)) $$($(1)_config_opts_$(host_os)_$(release_type))\n$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)_$(host_os)) $$($(1)_config_opts_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_config_env+=$$($(1)_config_env_$(release_type))\n$(1)_config_env+=$($(1)_config_env_$(host_arch)) $($(1)_config_env_$(host_arch)_$(release_type))\n$(1)_config_env+=$($(1)_config_env_$(host_os)) $($(1)_config_env_$(host_os)_$(release_type))\n$(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(host_arch)_$(host_os)_$(release_type))\n\n$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig\n$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig\n$(1)_config_env+=CMAKE_MODULE_PATH=$($($(1)_type)_prefix)/lib/cmake\n$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH)\n$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH)\n$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH)\n\n# Setting a --build type that differs from --host will explicitly enable\n# cross-compilation mode. Note that --build defaults to the output of\n# config.guess, which is what we set it too here. This also quells autoconf\n# warnings, \"If you wanted to set the --build type, don't use --host.\",\n# when using versions older than 2.70.\n$(1)_autoconf=./configure --build=$(BUILD) --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC=\"$$($(1)_cc)\" CXX=\"$$($(1)_cxx)\"\nifneq ($($(1)_nm),)\n$(1)_autoconf += NM=\"$$($(1)_nm)\"\nendif\nifneq ($($(1)_ranlib),)\n$(1)_autoconf += RANLIB=\"$$($(1)_ranlib)\"\nendif\nifneq ($($(1)_ar),)\n$(1)_autoconf += AR=\"$$($(1)_ar)\"\nendif\nifneq ($($(1)_cflags),)\n$(1)_autoconf += CFLAGS=\"$$($(1)_cflags)\"\nendif\nifneq ($($(1)_cxxflags),)\n$(1)_autoconf += CXXFLAGS=\"$$($(1)_cxxflags)\"\nendif\nifneq ($($(1)_cppflags),)\n$(1)_autoconf += CPPFLAGS=\"$$($(1)_cppflags)\"\nendif\nifneq ($($(1)_ldflags),)\n$(1)_autoconf += LDFLAGS=\"$$($(1)_ldflags)\"\nendif\n\n$(1)_cmake=env CC=\"$$($(1)_cc)\" \\\n               CFLAGS=\"$$($(1)_cppflags) $$($(1)_cflags)\" \\\n               CXX=\"$$($(1)_cxx)\" \\\n               CXXFLAGS=\"$$($(1)_cppflags) $$($(1)_cxxflags)\" \\\n               LDFLAGS=\"$$($(1)_ldflags)\" \\\n             cmake -DCMAKE_INSTALL_PREFIX:PATH=\"$$($($(1)_type)_prefix)\"\nifeq ($($(1)_type),build)\n$(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH=\"$$($($(1)_type)_prefix)/lib\"\nelse\nifneq ($(host),$(build))\n$(1)_cmake += -DCMAKE_SYSTEM_NAME=$($(host_os)_cmake_system)\n$(1)_cmake += -DCMAKE_C_COMPILER_TARGET=$(host)\n$(1)_cmake += -DCMAKE_CXX_COMPILER_TARGET=$(host)\nendif\nendif\nendef\n\ndefine int_add_cmds\n$($(1)_fetched):\n\tmkdir -p $$(@D) $(SOURCES_PATH)\n\trm -f $$@\n\ttouch $$@\n\tcd $$(@D); $(call $(1)_fetch_cmds,$(1))\n\tcd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)\n\ttouch $$@\n$($(1)_extracted): | $($(1)_fetched)\n\techo Extracting $(1)...\n\tmkdir -p $$(@D)\n\tcd $$(@D); $(call $(1)_extract_cmds,$(1))\n\ttouch $$@\n$($(1)_preprocessed): | $($(1)_extracted)\n\techo Preprocessing $(1)...\n\tmkdir -p $$(@D) $($(1)_patch_dir)\n\t$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;)\n\tcd $$(@D); $(call $(1)_preprocess_cmds, $(1))\n\ttouch $$@\n$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed)\n\techo Configuring $(1)...\n\trm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), $(build_TAR) --no-same-owner -xf $($(package)_cached); )\n\tmkdir -p $$(@D)\n\t+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1))\n\ttouch $$@\n$($(1)_built): | $($(1)_configured)\n\techo Building $(1)...\n\tmkdir -p $$(@D)\n\t+cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1))\n\ttouch $$@\n$($(1)_staged): | $($(1)_built)\n\techo Staging $(1)...\n\tmkdir -p $($(1)_staging_dir)/$(host_prefix)\n\tcd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1))\n\trm -rf $($(1)_extract_dir)\n\ttouch $$@\n$($(1)_postprocessed): | $($(1)_staged)\n\techo Postprocessing $(1)...\n\tcd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds)\n\ttouch $$@\n$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed)\n\techo Caching $(1)...\n\tcd $$($(1)_staging_dir)/$(host_prefix); find . | sort | $(build_TAR) --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T -\n\tmkdir -p $$(@D)\n\trm -rf $$(@D) && mkdir -p $$(@D)\n\tmv $$($(1)_staging_dir)/$$(@F) $$(@)\n\trm -rf $($(1)_staging_dir)\n$($(1)_cached_checksum): $($(1)_cached)\n\tcd $$(@D); $(build_SHA256SUM) $$(<F) > $$(@)\n\n.PHONY: $(1)\n$(1): | $($(1)_cached_checksum)\n.SECONDARY: $($(1)_cached) $($(1)_postprocessed) $($(1)_staged) $($(1)_built) $($(1)_configured) $($(1)_preprocessed) $($(1)_extracted) $($(1)_fetched)\n\nendef\n\nstages = fetched extracted preprocessed configured built staged postprocessed cached cached_checksum\n\ndefine ext_add_stages\n$(foreach stage,$(stages),\n          $(1)_$(stage): $($(1)_$(stage))\n          .PHONY: $(1)_$(stage))\nendef\n\n# These functions create the build targets for each package. They must be\n# broken down into small steps so that each part is done for all packages\n# before moving on to the next step. Otherwise, a package's info\n# (build-id for example) would only be available to another package if it\n# happened to be computed already.\n\n#set the type for host/build packages.\n$(foreach native_package,$(native_packages),$(eval $(native_package)_type=build))\n$(foreach package,$(packages),$(eval $(package)_type=$(host_arch)_$(host_os)))\n\n#set overridable defaults\n$(foreach package,$(all_packages),$(eval $(call int_vars,$(package))))\n\n#include package files\n$(foreach native_package,$(native_packages),$(eval include packages/$(native_package).mk))\n$(foreach package,$(packages),$(eval include packages/$(package).mk))\n\n#compute a hash of all files that comprise this package's build recipe\n$(foreach package,$(all_packages),$(eval $(call int_get_build_recipe_hash,$(package))))\n\n#generate a unique id for this package, incorporating its dependencies as well\n$(foreach package,$(all_packages),$(eval $(call int_get_build_id,$(package))))\n\n#compute final vars after reading package vars\n$(foreach package,$(all_packages),$(eval $(call int_config_attach_build_config,$(package))))\n\n#create build targets\n$(foreach package,$(all_packages),$(eval $(call int_add_cmds,$(package))))\n\n#special exception: if a toolchain package exists, all non-native packages depend on it\n$(foreach package,$(packages),$(eval $($(package)_extracted): |$($($(host_arch)_$(host_os)_native_toolchain)_cached) $($($(host_arch)_$(host_os)_native_binutils)_cached) ))\n"
  },
  {
    "path": "depends/gen_id",
    "content": "#!/usr/bin/env bash\n\n# Usage: env [ CC=... ] [ CXX=... ] [ AR=... ] [ RANLIB=... ] [ STRIP=... ] \\\n#            [ DEBUG=... ] ./build-id [ID_SALT]...\n#\n# Prints to stdout a SHA256 hash representing the current toolset, used by\n# depends/Makefile as a build id for caching purposes (detecting when the\n# toolset has changed and the cache needs to be invalidated).\n#\n# If the DEBUG environment variable is non-empty and the system has `tee`\n# available in its $PATH, the pre-image to the SHA256 hash will be printed to\n# stderr. This is to help developers debug caching issues in depends.\n\n# This script explicitly does not `set -e` because id determination is mostly\n# opportunistic: it is fine that things fail, as long as they fail consistently.\n\n# Command variables (CC/CXX/AR) which can be blank are invoked with `bash -c`,\n# because the \"command not found\" error message printed by shells often include\n# the line number, like so:\n#\n#     ./depends/gen_id: line 43: --version: command not found\n#\n# By invoking with `bash -c`, we ensure that the line number is always 1\n\n(\n    # Redirect stderr to stdout\n    exec 2>&1\n\n    echo \"BEGIN ALL\"\n\n    # Include any ID salts supplied via command line\n    echo \"BEGIN ID SALT\"\n    echo \"$@\"\n    echo \"END ID SALT\"\n\n    # GCC only prints COLLECT_LTO_WRAPPER when invoked with just \"-v\", but we want\n    # the information from \"-v -E -\" as well, so just include both.\n    echo \"BEGIN CC\"\n    bash -c \"${CC} -v\"\n    bash -c \"${CC} -v -E -xc -o /dev/null - < /dev/null\"\n    bash -c \"${CC} -v -E -xobjective-c -o /dev/null - < /dev/null\"\n    echo \"END CC\"\n\n    echo \"BEGIN CXX\"\n    bash -c \"${CXX} -v\"\n    bash -c \"${CXX} -v -E -xc++ -o /dev/null - < /dev/null\"\n    bash -c \"${CXX} -v -E -xobjective-c++ -o /dev/null - < /dev/null\"\n    echo \"END CXX\"\n\n    echo \"BEGIN AR\"\n    bash -c \"${AR} --version\"\n    env | grep '^AR_'\n    echo \"ZERO_AR_DATE=${ZERO_AR_DATE}\"\n    echo \"END AR\"\n\n    echo \"BEGIN RANLIB\"\n    bash -c \"${RANLIB} --version\"\n    env | grep '^RANLIB_'\n    echo \"END RANLIB\"\n\n    echo \"BEGIN STRIP\"\n    bash -c \"${STRIP} --version\"\n    env | grep '^STRIP_'\n    echo \"END STRIP\"\n\n    echo \"END ALL\"\n) | if [ -n \"$DEBUG\" ] && command -v tee > /dev/null 2>&1; then\n        # When debugging and `tee` is available, output the preimage to stderr\n        # in addition to passing through stdin to stdout\n        tee >(cat 1>&2)\n    else\n        # Otherwise, passthrough stdin to stdout\n        cat\n    fi | ${SHA256SUM} - | cut -d' ' -f1\n"
  },
  {
    "path": "depends/hosts/android.mk",
    "content": "android_cmake_system=Android\n"
  },
  {
    "path": "depends/hosts/darwin.mk",
    "content": "OSX_MIN_VERSION=10.10\nOSX_SDK_VERSION?=12.0\nOSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk\nLD64_VERSION=609\n\ndarwin_native_binutils=native_cctools\n\nifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)\n# FORCE_USE_SYSTEM_CLANG is empty, so we use our depends-managed, pinned clang\n# from llvm.org\n\n# Clang is a dependency of native_cctools when FORCE_USE_SYSTEM_CLANG is empty\ndarwin_native_toolchain=native_cctools\n\nclang_prog=$(build_prefix)/bin/clang\nclangxx_prog=$(clang_prog)++\nllvm_config_prog=$(build_prefix)/bin/llvm-config\n\nclang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version)\nelse\n# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's\n# system\n\ndarwin_native_toolchain=\n\n# We can't just use $(shell command -v clang) because GNU Make handles builtins\n# in a special way and doesn't know that `command` is a POSIX-standard builtin\n# prior to 1af314465e5dfe3e8baa839a32a72e83c04f26ef, first released in v4.2.90.\n# At the time of writing, GNU Make v4.2.1 is still being used in supported\n# distro releases.\n#\n# Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html\nclang_prog=$(shell $(SHELL) $(.SHELLFLAGS) \"command -v clang\")\nclangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) \"command -v clang++\")\nllvm_config_prog=$(shell $(SHELL) $(.SHELLFLAGS) \"command -v llvm-config\")\n\nclang_resource_dir=$(shell clang -print-resource-dir)\nllvm_lib_dir=$(shell $(llvm_config_prog) --libdir)\nendif\n\ncctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL DSYMUTIL\n\n# Make-only lowercase function\nlc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))\n\n# For well-known tools provided by cctools, make sure that their well-known\n# variable is set to the full path of the tool, just like how AC_PATH_{TOO,PROG}\n# would.\n$(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(host)-$(call lc,$(TOOL))))\n\n# Flag explanations:\n#\n#     -mlinker-version\n#\n#         Ensures that modern linker features are enabled. See here for more\n#         details: https://github.com/bitcoin/bitcoin/pull/19407.\n#\n#     -B$(build_prefix)/bin\n#\n#         Explicitly point to our binaries (e.g. cctools) so that they are\n#         ensured to be found and preferred over other possibilities.\n#\n#     -stdlib=libc++ -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1\n#\n#         Forces clang to use the libc++ headers from our SDK and completely\n#         forget about the libc++ headers from the standard directories\n#\n#     -Xclang -*system<path_a> \\\n#     -Xclang -*system<path_b> \\\n#     -Xclang -*system<path_c> ...\n#\n#         Adds path_a, path_b, and path_c to the bottom of clang's list of\n#         include search paths. This is used to explicitly specify the list of\n#         system include search paths and its ordering, rather than rely on\n#         clang's autodetection routine. This routine has been shown to:\n#             1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1\n#                when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034)\n#             2. Fail to pickup C headers in $SYSROOT/usr/include when\n#                C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9)\n#\n#         Talking directly to cc1 with -Xclang here grants us access to specify\n#         more granular categories for these system include search paths, and we\n#         can use the correct categories that these search paths would have been\n#         placed in if the autodetection routine had worked correctly. (see:\n#         https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment)\n#\n#         Furthermore, it places these search paths after any \"non-Xclang\"\n#         specified search paths. This prevents any additional clang options or\n#         environment variables from coming after or in between these system\n#         include search paths, as that would be wrong in general but would also\n#         break #include_next's.\n#\ndarwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \\\n              -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \\\n              -u LIBRARY_PATH \\\n            $(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \\\n              -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \\\n              -isysroot$(OSX_SDK) \\\n              -Xclang -internal-externc-isystem$(clang_resource_dir)/include \\\n              -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include\ndarwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \\\n               -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \\\n               -u LIBRARY_PATH \\\n             $(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \\\n               -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \\\n               -isysroot$(OSX_SDK) \\\n               -stdlib=libc++ \\\n               -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1 \\\n               -Xclang -internal-externc-isystem$(clang_resource_dir)/include \\\n               -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include\n\ndarwin_CFLAGS=-pipe\ndarwin_CXXFLAGS=-pipe\n\nifneq ($(LTO),)\ndarwin_CFLAGS += -flto\ndarwin_CXXFLAGS += -flto\ndarwin_LDFLAGS += -flto\nendif\n\ndarwin_release_CFLAGS=-O2\ndarwin_release_CXXFLAGS=$(darwin_release_CFLAGS)\n\ndarwin_debug_CFLAGS=-O1\ndarwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS)\n\ndarwin_cmake_system=Darwin\n"
  },
  {
    "path": "depends/hosts/default.mk",
    "content": "ifneq ($(host),$(build))\nhost_toolchain:=$(host)-\nendif\n\ndefault_host_CC = $(host_toolchain)gcc\ndefault_host_CXX = $(host_toolchain)g++\ndefault_host_AR = $(host_toolchain)ar\ndefault_host_RANLIB = $(host_toolchain)ranlib\ndefault_host_STRIP = $(host_toolchain)strip\ndefault_host_LIBTOOL = $(host_toolchain)libtool\ndefault_host_INSTALL_NAME_TOOL = $(host_toolchain)install_name_tool\ndefault_host_OTOOL = $(host_toolchain)otool\ndefault_host_NM = $(host_toolchain)nm\n\ndefine add_host_tool_func\nifneq ($(filter $(origin $1),undefined default),)\n# Do not consider the well-known var $1 if it is undefined or is taking a value\n# that is predefined by \"make\" (e.g. the make variable \"CC\" has a predefined\n# value of \"cc\")\n$(host_os)_$1?=$$(default_host_$1)\n$(host_arch)_$(host_os)_$1?=$$($(host_os)_$1)\n$(host_arch)_$(host_os)_$(release_type)_$1?=$$($(host_os)_$1)\nelse\n$(host_os)_$1=$(or $($1),$($(host_os)_$1),$(default_host_$1))\n$(host_arch)_$(host_os)_$1=$(or $($1),$($(host_arch)_$(host_os)_$1),$$($(host_os)_$1))\n$(host_arch)_$(host_os)_$(release_type)_$1=$(or $($1),$($(host_arch)_$(host_os)_$(release_type)_$1),$$($(host_os)_$1))\nendif\nhost_$1=$$($(host_arch)_$(host_os)_$1)\nendef\n\ndefine add_host_flags_func\n$(host_arch)_$(host_os)_$1 += $($(host_os)_$1)\n$(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1)\nhost_$1 = $$($(host_arch)_$(host_os)_$1)\nhost_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1)\nendef\n\n$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL,$(eval $(call add_host_tool_func,$(tool))))\n$(foreach flags,CFLAGS CXXFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags))))\n"
  },
  {
    "path": "depends/hosts/ios.mk",
    "content": "aarch64_ios_SDK=$(shell xcrun --sdk iphoneos --show-sdk-path)\nx86_64_ios_SDK=$(shell xcrun --sdk iphonesimulator --show-sdk-path)\nios_SDK=$($(host_arch)_ios_SDK)\n\nios_ARCH=$(host_arch)\nifeq ($(host_arch),aarch64)\nios_ARCH=arm64\nendif\n\naarch64_ios_SYSTEM=apple-ios\nx86_64_ios_SYSTEM=apple-darwin\nios_SYSTEM=$($(host_arch)_ios_SYSTEM)\n\nios_TARGET=$(ios_ARCH)-$(ios_SYSTEM)\nios_HOST=$(host_arch)-$(ios_SYSTEM)\n\nios_CC=clang -target $(ios_TARGET) -isysroot $(ios_SDK) -fvisibility=default\nios_CXX=clang++ -target $(ios_TARGET) -isysroot $(ios_SDK) -stdlib=libc++ -fvisibility=default\n\nios_CFLAGS=-pipe\nios_CXXFLAGS=$(ios_CFLAGS)\n\nios_release_CFLAGS=-O2\nios_release_CXXFLAGS=$(ios_release_CFLAGS)\n\nios_debug_CFLAGS=-O1\nios_debug_CXXFLAGS=$(ios_debug_CFLAGS)\n\nios_native_toolchain=\n\n\nios_AR=ar\nios_RANLIB=ranlib\n"
  },
  {
    "path": "depends/hosts/linux.mk",
    "content": "linux_CFLAGS=-pipe\nlinux_CXXFLAGS=$(linux_CFLAGS)\n\nlinux_release_CFLAGS=-O2\nlinux_release_CXXFLAGS=$(linux_release_CFLAGS)\n\nlinux_debug_CFLAGS=-O1\nlinux_debug_CXXFLAGS=$(linux_debug_CFLAGS)\n\nlinux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_LIBCPP_DEBUG=1\n\nifeq (86,$(findstring 86,$(build_arch)))\ni686_linux_CC=gcc -m32\ni686_linux_CXX=g++ -m32\ni686_linux_AR=ar\ni686_linux_RANLIB=ranlib\ni686_linux_NM=nm\ni686_linux_STRIP=strip\n\nx86_64_linux_CC=gcc -m64\nx86_64_linux_CXX=g++ -m64\nx86_64_linux_AR=ar\nx86_64_linux_RANLIB=ranlib\nx86_64_linux_NM=nm\nx86_64_linux_STRIP=strip\nelse\ni686_linux_CC=$(default_host_CC) -m32\ni686_linux_CXX=$(default_host_CXX) -m32\nx86_64_linux_CC=$(default_host_CC) -m64\nx86_64_linux_CXX=$(default_host_CXX) -m64\nendif\nlinux_cmake_system=Linux\n"
  },
  {
    "path": "depends/hosts/mingw32.mk",
    "content": "ifneq ($(shell $(SHELL) $(.SHELLFLAGS) \"command -v $(host)-g++-posix\"),)\nmingw32_CXX := $(host)-g++-posix\nendif\n\nmingw32_CFLAGS=-pipe\nmingw32_CXXFLAGS=$(mingw32_CFLAGS)\n\nmingw32_release_CFLAGS=-O2\nmingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS)\n\nmingw32_debug_CFLAGS=-O1\nmingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS)\n\nmingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC\n\nmingw_cmake_system=Windows\n"
  },
  {
    "path": "depends/hosts/mingw64.mk",
    "content": "mingw64_CFLAGS=-pipe\nmingw64_CXXFLAGS=$(mingw64_CFLAGS)\n\nmingw64_release_CFLAGS=-O2\nmingw64_release_CXXFLAGS=$(mingw64_release_CFLAGS)\n\nmingw64_debug_CFLAGS=-O1\nmingw64_debug_CXXFLAGS=$(mingw64_debug_CFLAGS)\n\nmingw64_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC\n\n"
  },
  {
    "path": "depends/packages/bdb.mk",
    "content": "package=bdb\n$(package)_version=4.8.30\n$(package)_download_path=http://download.oracle.com/berkeley-db\n$(package)_file_name=db-$($(package)_version).NC.tar.gz\n$(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef\n$(package)_build_subdir=build_unix\n\ndefine $(package)_set_vars\n$(package)_config_opts=--disable-shared --enable-cxx --disable-replication\n$(package)_config_opts_mingw32=--enable-mingw\n$(package)_config_opts_mingw64=--enable-mingw\n$(package)_config_opts_linux=--with-pic\n$(package)_config_opts_android=--with-pic\n$(package)_cc+=-Wno-error=implicit-function-declaration\n$(package)_config_opts_ios=--host=$(ios_HOST) --enable-posixmutexes\n$(package)_cxxflags=-std=c++11\n$(package)_cflags_ios=-Wno-implicit-function-declaration\nendef\n\ndefine $(package)_preprocess_cmds\n  sed -i.old2 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h && \\\n  sed -i.old 's/atomic_init/atomic_init_db/' dbinc/atomic.h mp/mp_region.c mp/mp_mvcc.c mp/mp_fget.c mutex/mut_method.c mutex/mut_tas.c && \\\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub dist\nendef\n\ndefine $(package)_config_cmds\n  ../dist/$($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) libdb_cxx-4.8.a libdb-4.8.a\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install_lib install_include\nendef\n"
  },
  {
    "path": "depends/packages/boost.mk",
    "content": "package=boost\n$(package)_version=1.77.0\n$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/\n$(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.bz2\n$(package)_sha256_hash=fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854\n\ndefine $(package)_set_vars\n$(package)_config_opts_release=variant=release\n$(package)_config_opts_debug=variant=debug\n$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam\n$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1\n$(package)_config_opts_linux=threadapi=pthread runtime-link=shared\n$(package)_config_opts_darwin=--toolset=clang-darwin runtime-link=shared\n$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static\n$(package)_config_opts_mingw64=binary-format=pe target-os=windows threadapi=win32 runtime-link=static\n$(package)_config_opts_x86_64_mingw32=address-model=64\n$(package)_config_opts_x86_64_mingw64=address-model=64\n$(package)_config_opts_i686_mingw32=address-model=64\n$(package)_config_opts_i686_mingw64=address-model=64\n$(package)_config_opts_i686_linux=address-model=32 architecture=x86\n$(package)_config_opts_aarch64_ios=architecture=x86 target-os=iphone\n$(package)_config_opts_android=define=BOOST_FILESYSTEM_DISABLE_STATX\n$(package)_toolset_$(host_os)=gcc\n$(package)_toolset_darwin=clang-darwin\n$(package)_toolset_ios=darwin\n$(package)_archiver_$(host_os)=$($(package)_ar)\n$(package)_archiver_darwin=$($(package)_ar)\n$(package)_archiver_ios=libtool\n$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test\n$(package)_cxxflags=-std=c++17\n$(package)_cxxflags_$(host_os)=-fvisibility=hidden\n$(package)_cxxflags_linux+=-fPIC\n$(package)_cxxflags_android+=-fPIC\n$(package)_cxxflags_ios=-fvisibility=default\nendef\n\ndefine $(package)_preprocess_cmds\n  echo \"using $($(package)_toolset_$(host_os)) : : $($(package)_cxx) : <cxxflags>\\\"$($(package)_cxxflags) $($(package)_cppflags)\\\" <linkflags>\\\"$($(package)_ldflags)\\\" <archiver>\\\"$($(package)_archiver_$(host_os))\\\" <striper>\\\"$(host_STRIP)\\\"  <ranlib>\\\"$(host_RANLIB)\\\" <rc>\\\"$(host_WINDRES)\\\" : ;\" > user-config.jam\nendef\n\ndefine $(package)_config_cmds\n  ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)\nendef\n\ndefine $(package)_build_cmds\n  ./b2 --ignore-site-config -d2 -j2 -d1 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) stage\nendef\n\ndefine $(package)_stage_cmds\n  ./b2 --ignore-site-config -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) install\nendef\n"
  },
  {
    "path": "depends/packages/djinni.mk",
    "content": "package=djinni\n$(package)_commit=da0f079711e863542b558aa31690605a8688ab55\n$(package)_version=$($(package)_commit)\n$(package)_download_path=https://github.com/mjmacleod/djinni/archive/\n$(package)_file_name=$($(package)_commit).tar.gz\n$(package)_sha256_hash=206c5e81695d9863bf07eee6cb5416c923ffe27d7fb83f4f27261bc24ce4937a\n\ndefine $(package)_build_cmds\n  $(MAKE) djinni && \\\n  ./support-lib/ios-build-support-lib.sh\nendef\n\ndefine $(package)_stage_cmds\n  cp -R src $($(package)_staging_prefix_dir)/$(package) && \\\n  mkdir -p $($(package)_staging_prefix_dir)/bin && \\\n  ln -s ../djinni/run-assume-built $($(package)_staging_prefix_dir)/bin/djinni-run && \\\n  mkdir -p $($(package)_staging_prefix_dir)/lib && \\\n  cp support-lib/out/apple/libdjinni_support_lib_UNIVERSAL.a $($(package)_staging_prefix_dir)/lib/ && \\\n  mkdir -p $($(package)_staging_prefix_dir)/include/objc && \\\n\tcp support-lib/*.hpp $($(package)_staging_prefix_dir)/include && \\\n  cp support-lib/objc/*.h $($(package)_staging_prefix_dir)/include/objc\nendef\n"
  },
  {
    "path": "depends/packages/electron_node_headers.mk",
    "content": "package=electron_node_headers\n$(package)_version=18.15.0\n$(package)_download_path=https://nodejs.org/dist/v$($(package)_version)/\n$(package)_file_name=node-v$($(package)_version)-headers.tar.gz\n$(package)_sha256_hash=5ada31143933f0443d20769ae5942c4b1c5c80fe9f8a8221dae12ed9bec2ad2d\n\n$(package)_patches=node.def\n\n$(package)_makelibnode_mingw32=cp -f $($(package)_patch_dir)/node.def . && x86_64-w64-mingw32-dlltool -d node.def -y libnode.a\n$(package)_instlibnode_mingw32=&& mkdir $($(package)_staging_prefix_dir)/lib/ &&  cp libnode.a $($(package)_staging_prefix_dir)/lib\n\ndefine $(package)_preprocess_cmds\n  $($(package)_makelibnode_$(host_os))\nendef\n\n\ndefine $(package)_stage_cmds\n  cp -r include $($(package)_staging_prefix_dir) $($(package)_instlibnode_$(host_os))\nendef\n"
  },
  {
    "path": "depends/packages/libcryptopp.mk",
    "content": "package=libcryptopp\n$(package)_version=8.2.0\n$(package)_download_path=https://github.com/weidai11/cryptopp/archive/\n\n$(package)_file_name=CRYPTOPP_8_2_0.tar.gz\n$(package)_sha256_hash=e3bcd48a62739ad179ad8064b523346abb53767bcbefc01fe37303412292343e\n\n$(package)_makefile_darwin=GNUmakefile\n$(package)_makefile_linux=GNUmakefile\n$(package)_makefile_mingw32=GNUmakefile\n$(package)_makefile_mingw64=GNUmakefile\n$(package)_makefile=$($(package)_makefile_$(host_os))\n\n$(package)_cxxflags_debug += \n$(package)_cxxflags_release += -DNDEBUG -O3 -fPIC\n$(package)_cxxflags += -std=c++17\n\ndefine $(package)_preprocess_cmds\nendef\n\ndefine $(package)_set_vars\nendef\n\ndefine $(package)_config_cmds\n    sed -Ei.old \"s|[^A-Z][(]CXX[)]|$($(package)_cxx)|\" GNUmakefile && \\\n    sed -Ei.old \"s|AR = libtool|AR = $($(package)_libtool)|\" GNUmakefile && \\\n    sed -Ei.old \"s|CC=gcc|CC=$($(package)_cxx)|\" GNUmakefile && \\\n    sed -Ei.old \"s|CC=clang|CC=$($(package)_cxx)|\" GNUmakefile && \\\n    sed -i.old 's|ifeq ($$$$(IS_ARM32),1)|ifeq ($$$$(IS_ARM32)$$$$(IS_ARMV8),10)|' GNUmakefile &&\\\n    sed -i.old 's|CRYPTOGAMS_AES_FLAG = -march=armv7-a|CRYPTOGAMS_AES_FLAG = -march=armv7-a+fp|g' GNUmakefile &&\\\n    sed -Ei.old \"s|// [#]define CRYPTOPP_NO_CXX17|#define CRYPTOPP_NO_CXX17|\" config.h && \\\n    sed -Ei.old \"s|[#] define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE|//# define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE|\" config.h\nendef\n\ndefine $(package)_build_cmds\n  PREFIX=$($(package)_staging_prefix_dir) CXXFLAGS=\"$($(package)_cxxflags)\" $(MAKE) -f GNUmakefile libcryptopp.pc && \\\n  PREFIX=\"$($(package)_staging_prefix_dir)\" RANLIB=\"$($(package)_ranlib)\" CXXFLAGS=\"$($(package)_cxxflags)\" $(MAKE) -f $($(package)_makefile) static\nendef\n\ndefine $(package)_stage_cmds\n  PREFIX=$($(package)_staging_prefix_dir) RANLIB=$($(package)_ranlib) CXXFLAGS=\"$($(package)_cxxflags)\" $(MAKE) -f $($(package)_makefile) install-lib\nendef\n\ndefine $(package)_postprocess_cmds\nendef\n\n"
  },
  {
    "path": "depends/packages/libcryptoppunity.mk",
    "content": "package=libcryptopp\n$(package)_version=8.2.0\n$(package)_download_path=https://github.com/robobit/cryptopp/archive/\n\n$(package)_file_name=04e8eb372d436acb35a70d9aa8453beffbeaad66.tar.gz\n$(package)_sha256_hash=93e88e5b001cded565908f6c70cd36a5771b24d2a1c6a2d64401b8217b2dc8c0\n\n$(package)_makefile_$(host_os)=GNUmakefile-cross\n$(package)_makefile=$($(package)_makefile_$(host_os))\n\n$(package)_env_script_$(host_os)=./setenv-android-clang.sh\n$(package)_env_script_ios=./setenv-ios.sh\n$(package)_env_script=$($(package)_env_script_$(host_os))\n\n$(package)_cxxflags_debug += -DDEBUG -DDEBUG_LOCKORDER\n$(package)_cxxflags_release += -DNDEBUG -O3 -fPIC\n$(package)_cxxflags += -std=c++17\n\n$(package)_cross_target_$(host_arch)_$(host_os)=$(host_arch)\n$(package)_cross_target_aarch64_ios=arm64\n$(package)_cross_target_x86_64_ios=x86_64\n$(package)_cross_target=$($(package)_cross_target_$(host_arch)_$(host_os))\n\nifeq ($(host_os),android)\n$(package)_env_arch_arm=AOSP_FLAGS=\"-march=armv7-a -mthumb -mfpu=vfpv3-d16 -mfloat-abi=softfp -DCRYPTOPP_DISABLE_ASM -Wl,--fix-cortex-a8 -funwind-tables -fexceptions -frtti\"\n$(package)_env_arch_arm+=AOSP_STL_LIB=\"$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a\"\n\n$(package)_env_arch_aarch64=AOSP_FLAGS=\"-funwind-tables -fexceptions -frtti\"\n$(package)_env_arch_aarch64+=AOSP_STL_LIB=\"$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_static.a\"\n\n$(package)_env_arch_x86_64=AOSP_FLAGS=\"-DCRYPTOPP_DISABLE_ASM\"\n$(package)_env_arch_x86_64+=AOSP_STL_LIB=\"$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a\"\n\n$(package)_env_arch_i686=AOSP_FLAGS=\"-DCRYPTOPP_DISABLE_ASM\"\n$(package)_env_arch_i686+=AOSP_STL_LIB=\"$(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/x86/libc++_static.a\"\n\n$(package)_env=IS_ANDROID=1\n$(package)_env+=$($(package)_env_arch_$(host_arch))\nendif\n\nifeq ($(host_os),ios)\n$(package)_env_arch_aarch64=IOS_FLAGS=\n$(package)_env_arch_x86_64=IOS_FLAGS=-DCRYPTOPP_DISABLE_ASM\n\n$(package)_env=IS_IOS=1\n$(package)_env+=IOS_SYSROOT=$(ios_SDK)\n$(package)_env+=IOS_ARCH=$($(package)_cross_target)\n$(package)_env+=$($(package)_env_arch_$(host_arch))\nendif\n\ndefine $(package)_preprocess_cmds\n    sed -Ei.old \"s|// [#]define CRYPTOPP_NO_CXX17|#define CRYPTOPP_NO_CXX17|\" config.h && \\\n    sed -Ei.old \"s|[#] define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE|//# define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE|\" config.h \nendef\n\ndefine $(package)_set_vars\nendef\n\nifeq ($(host_os),android)\ndefine $(package)_config_cmds\n   cp \"$(NDK_ROOT)/sources/android/cpufeatures/cpu-features.h\" . && \\\n   cp \"$(NDK_ROOT)/sources/android/cpufeatures/cpu-features.c\" .\nendef\nelse\ndefine $(package)_config_cmds\nendef\nendif\n\ndefine $(package)_build_cmds\n  PREFIX=$($(package)_staging_prefix_dir) $(MAKE) -f GNUmakefile libcryptopp.pc && \\\n  $($(package)_env) PREFIX=$($(package)_staging_prefix_dir) RANLIB=$($(package)_ranlib) $(MAKE) -f $($(package)_makefile) static\nendef\n\ndefine $(package)_stage_cmds\n  PREFIX=$($(package)_staging_prefix_dir) RANLIB=$($(package)_ranlib) $(MAKE) -f $($(package)_makefile) install-lib\nendef\n\ndefine $(package)_postprocess_cmds\nendef\n\n"
  },
  {
    "path": "depends/packages/libevent.mk",
    "content": "package=libevent\n$(package)_version=2.1.12-stable\n$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-$($(package)_version)/\n$(package)_file_name=$(package)-$($(package)_version).tar.gz\n$(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb\n\n# When building for Windows, we set _WIN32_WINNT to target the same Windows\n# version as we do in configure. Due to quirks in libevents build system, this\n# is also required to enable support for ipv6. See #19375.\ndefine $(package)_set_vars\n  $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples\n  $(package)_config_opts += --disable-dependency-tracking --enable-option-checking\n  $(package)_config_opts_release=--disable-debug-mode\n  $(package)_config_opts_linux=--with-pic\n  $(package)_config_opts_freebsd=--with-pic\n  $(package)_config_opts_netbsd=--with-pic\n  $(package)_config_opts_openbsd=--with-pic\n  $(package)_config_opts_android=--with-pic\n  $(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601\nendef\n\ndefine $(package)_preprocess_cmds\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux\nendef\n\ndefine $(package)_config_cmds\n  $($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE)\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install\nendef\n\ndefine $(package)_postprocess_cmds\n  rm lib/*.la && \\\n  rm include/ev*.h && \\\n  rm include/event2/*_compat.h\nendef\n"
  },
  {
    "path": "depends/packages/miniupnpc.mk",
    "content": "package=miniupnpc\n$(package)_version=2.2.2\n$(package)_download_path=https://miniupnp.tuxfamily.org/files/\n$(package)_file_name=$(package)-$($(package)_version).tar.gz\n$(package)_sha256_hash=888fb0976ba61518276fe1eda988589c700a3f2a69d71089260d75562afd3687\n$(package)_patches=dont_leak_info.patch\n\ndefine $(package)_set_vars\n$(package)_build_opts=CC=\"$($(package)_cc)\"\n$(package)_build_opts_darwin=LIBTOOL=\"$($(package)_libtool)\"\n$(package)_build_opts_mingw32=-f Makefile.mingw\n$(package)_build_env+=CFLAGS=\"$($(package)_cflags) $($(package)_cppflags)\" AR=\"$($(package)_ar)\"\nendef\n\ndefine $(package)_preprocess_cmds\n  patch -p1 < $($(package)_patch_dir)/dont_leak_info.patch\nendef\n\ndefine $(package)_build_cmds\n\t$(MAKE) libminiupnpc.a $($(package)_build_opts)\nendef\n\ndefine $(package)_stage_cmds\n\tmkdir -p $($(package)_staging_prefix_dir)/include/miniupnpc $($(package)_staging_prefix_dir)/lib &&\\\n\tinstall *.h $($(package)_staging_prefix_dir)/include/miniupnpc &&\\\n\tinstall libminiupnpc.a $($(package)_staging_prefix_dir)/lib\nendef\n"
  },
  {
    "path": "depends/packages/native_biplist.mk",
    "content": "package=native_biplist\n$(package)_version=1.0.3\n$(package)_download_path=https://bitbucket.org/wooster/biplist/downloads\n$(package)_file_name=biplist-$($(package)_version).tar.gz\n$(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6\n$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages\n\ndefine $(package)_build_cmds\n    python3 setup.py build\nendef\n\ndefine $(package)_stage_cmds\n    mkdir -p $($(package)_install_libdir) && \\\n    python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)\nendef\n"
  },
  {
    "path": "depends/packages/native_cctools.mk",
    "content": "package=native_cctools\n$(package)_version=2ef2e931cf641547eb8a68cfebde61003587c9fd\n$(package)_download_path=https://github.com/tpoechtrager/cctools-port/archive\n$(package)_file_name=$($(package)_version).tar.gz\n$(package)_sha256_hash=6b73269efdf5c58a070e7357b66ee760501388549d6a12b423723f45888b074b\n$(package)_build_subdir=cctools\n$(package)_dependencies=native_libtapi\n\ndefine $(package)_set_vars\n  $(package)_config_opts=--target=$(host) --enable-lto-support\n  $(package)_config_opts+=--with-llvm-config=$(llvm_config_prog)\n  $(package)_ldflags+=-Wl,-rpath=\\\\$$$$$$$$\\$$$$$$$$ORIGIN/../lib\n  $(package)_cc=$(clang_prog)\n  $(package)_cxx=$(clangxx_prog)\nendef\n\nifneq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)\ndefine $(package)_preprocess_cmds\n  mkdir -p $($(package)_staging_prefix_dir)/lib && \\\n  cp $(llvm_lib_dir)/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \\\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools\nendef\nelse\ndefine $(package)_preprocess_cmds\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools\nendef\nendif\n\ndefine $(package)_config_cmds\n  $($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE)\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install\nendef\n\ndefine $(package)_postprocess_cmds\n  rm -rf share\nendef\n"
  },
  {
    "path": "depends/packages/native_cdrkit.mk",
    "content": "package=native_cdrkit\n$(package)_version=1.1.11\n$(package)_download_path=http://distro.ibiblio.org/fatdog/source/600/c\n$(package)_file_name=cdrkit-$($(package)_version).tar.bz2\n$(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564\n$(package)_patches=cdrkit-deterministic.patch\n\ndefine $(package)_preprocess_cmds\n  patch -p1 < $($(package)_patch_dir)/cdrkit-deterministic.patch\nendef\n\n# Starting with 10.1, GCC defaults to -fno-common, resulting in linking errors.\n# Pass -fcommon to retain the legacy behaviour.\ndefine $(package)_config_cmds\n  cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) -DCMAKE_C_FLAGS=\"$$($(1)_cflags) -fcommon\"\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) genisoimage\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) -C genisoimage install\nendef\n\ndefine $(package)_postprocess_cmds\n  rm bin/isovfy bin/isoinfo bin/isodump bin/isodebug bin/devdump\nendef\n"
  },
  {
    "path": "depends/packages/native_clang.mk",
    "content": "package=native_clang\n$(package)_version=14.0.0\n$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version)\nifneq (,$(findstring aarch64,$(BUILD)))\n$(package)_file_name=clang+llvm-$($(package)_version)-aarch64-linux-gnu.tar.xz\n$(package)_sha256_hash=1792badcd44066c79148ffeb1746058422cc9d838462be07e3cb19a4b724a1ee\nelse\n$(package)_file_name=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz\n$(package)_sha256_hash=61582215dafafb7b576ea30cc136be92c877ba1f1c31ddbbd372d6d65622fef5\nendif\n\ndefine $(package)_preprocess_cmds\n  rm -f $($(package)_extract_dir)/lib/libc++abi.so*\nendef\n\ndefine $(package)_stage_cmds\n  mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include && \\\n  mkdir -p $($(package)_staging_prefix_dir)/bin && \\\n  cp bin/clang $($(package)_staging_prefix_dir)/bin/ && \\\n  cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ && \\\n  cp bin/dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \\\n  cp bin/llvm-config $($(package)_staging_prefix_dir)/bin/ && \\\n  cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \\\n  cp -r lib/clang/$($(package)_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include/\nendef\n"
  },
  {
    "path": "depends/packages/native_ds_store.mk",
    "content": "package=native_ds_store\n$(package)_version=1.3.0\n$(package)_download_path=https://github.com/dmgbuild/ds_store/archive/\n$(package)_file_name=v$($(package)_version).tar.gz\n$(package)_sha256_hash=76b3280cd4e19e5179defa23fb594a9dd32643b0c80d774bd3108361d94fb46d\n$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages\n\ndefine $(package)_build_cmds\n    python3 setup.py build\nendef\n\ndefine $(package)_stage_cmds\n    mkdir -p $($(package)_install_libdir) && \\\n    python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)\nendef\n"
  },
  {
    "path": "depends/packages/native_libdmg-hfsplus.mk",
    "content": "package=native_libdmg-hfsplus\n$(package)_version=0.1\n$(package)_download_path=https://github.com/theuni/libdmg-hfsplus/archive\n$(package)_file_name=libdmg-hfsplus-v$($(package)_version).tar.gz\n$(package)_sha256_hash=6569a02eb31c2827080d7d59001869ea14484c281efab0ae7f2b86af5c3120b3\n$(package)_build_subdir=build\n\ndefine $(package)_preprocess_cmds\n  mkdir build\nendef\n\ndefine $(package)_config_cmds\n  cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin ..\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) -C dmg\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) -C dmg install\nendef\n"
  },
  {
    "path": "depends/packages/native_libtapi.mk",
    "content": "package=native_libtapi\n$(package)_version=664b8414f89612f2dfd35a9b679c345aa5389026\n$(package)_download_path=https://github.com/tpoechtrager/apple-libtapi/archive\n$(package)_file_name=$($(package)_version).tar.gz\n$(package)_sha256_hash=62e419c12d1c9fad67cc1cd523132bc00db050998337c734c15bc8d73cc02b61\n\nifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)\n$(package)_dependencies=native_clang\nendif\n\ndefine $(package)_build_cmds\n  CC=$(clang_prog) CXX=$(clangxx_prog) INSTALLPREFIX=$($(package)_staging_prefix_dir) ./build.sh\nendef\n\ndefine $(package)_stage_cmds\n  ./install.sh\nendef\n"
  },
  {
    "path": "depends/packages/native_mac_alias.mk",
    "content": "package=native_mac_alias\n$(package)_version=2.2.0\n$(package)_download_path=https://github.com/dmgbuild/mac_alias/archive/\n$(package)_file_name=v$($(package)_version).tar.gz\n$(package)_sha256_hash=421e6d7586d1f155c7db3e7da01ca0dacc9649a509a253ad7077b70174426499\n$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages\n\ndefine $(package)_build_cmds\n    python3 setup.py build\nendef\n\ndefine $(package)_stage_cmds\n    mkdir -p $($(package)_install_libdir) && \\\n    python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)\nendef\n"
  },
  {
    "path": "depends/packages/node_addon_api.mk",
    "content": "package=node_addon_api\n$(package)_version=7.0.0\n$(package)_download_path=https://registry.npmjs.org/node-addon-api/-/\n$(package)_file_name=node-addon-api-$($(package)_version).tgz\n$(package)_sha256_hash=0535f2f93f0d3f0d94b6724884bae940f1b45b08ee4dd5b0b5b85525c1f7748d\n\ndefine $(package)_stage_cmds\n  mkdir -p $($(package)_staging_prefix_dir)/include && \\\n  mkdir -p $($(package)_staging_prefix_dir)/include/node-addon-api && \\\n  cp -r * $($(package)_staging_prefix_dir)/include/node-addon-api/\nendef\n"
  },
  {
    "path": "depends/packages/openssl.mk",
    "content": "package=openssl\n$(package)_version=1.0.1k\n$(package)_download_path=https://www.openssl.org/source/old/1.0.1\n$(package)_file_name=$(package)-$($(package)_version).tar.gz\n$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c\n$(package)_patches=0001-Update-configure-for-m1-builds.patch\n\ndefine $(package)_set_vars\n$(package)_config_env=AR=\"$($(package)_ar)\" RANLIB=\"$($(package)_ranlib)\" CC=\"$($(package)_cc)\"\n$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl\n$(package)_config_opts+=no-camellia\n$(package)_config_opts+=no-capieng\n$(package)_config_opts+=no-cast\n$(package)_config_opts+=no-comp\n$(package)_config_opts+=no-dso\n$(package)_config_opts+=no-dtls1\n$(package)_config_opts+=no-ec_nistp_64_gcc_128\n$(package)_config_opts+=no-gost\n$(package)_config_opts+=no-gmp\n$(package)_config_opts+=no-heartbeats\n$(package)_config_opts+=no-idea\n$(package)_config_opts+=no-jpake\n$(package)_config_opts+=no-krb5\n$(package)_config_opts+=no-libunbound\n$(package)_config_opts+=no-md2\n$(package)_config_opts+=no-mdc2\n$(package)_config_opts+=no-rc4\n$(package)_config_opts+=no-rc5\n$(package)_config_opts+=no-rdrand\n$(package)_config_opts+=no-rfc3779\n$(package)_config_opts+=no-rsax\n$(package)_config_opts+=no-sctp\n$(package)_config_opts+=no-seed\n$(package)_config_opts+=no-sha0\n$(package)_config_opts+=no-shared\n$(package)_config_opts+=no-ssl-trace\n$(package)_config_opts+=no-ssl2\n$(package)_config_opts+=no-ssl3\n$(package)_config_opts+=no-static_engine\n$(package)_config_opts+=no-store\n$(package)_config_opts+=no-unit-test\n$(package)_config_opts+=no-weak-ssl-ciphers\n$(package)_config_opts+=no-whirlpool\n$(package)_config_opts+=no-zlib\n$(package)_config_opts+=no-zlib-dynamic\n$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags)\n$(package)_config_opts_linux=-fPIC -Wa,--noexecstack\n$(package)_config_opts_x86_64_linux=linux-x86_64\n$(package)_config_opts_i686_linux=linux-generic32\n$(package)_config_opts_arm_linux=linux-generic32\n$(package)_config_opts_armv7l_linux=linux-generic32\n$(package)_config_opts_aarch64_linux=linux-generic64\n$(package)_config_opts_mipsel_linux=linux-generic32\n$(package)_config_opts_mips_linux=linux-generic32\n$(package)_config_opts_powerpc_linux=linux-generic32\n$(package)_config_opts_riscv32_linux=linux-generic32\n$(package)_config_opts_riscv64_linux=linux-generic64\n$(package)_config_opts_android=-fPIC -Wa,--noexecstack android\n$(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc\n$(package)_config_opts_aarch64_darwin=darwin64-arm64-cc\n$(package)_config_opts_x86_64_mingw32=mingw64\n$(package)_config_opts_x86_64_mingw64=mingw64\n$(package)_config_opts_i686_mingw32=mingw\n$(package)_config_opts_x86_64_ios=darwin64-x86_64-cc\n$(package)_config_opts_aarch64_ios=iphoneos-cross-arm64\n$(package)_config_env_aarch64_ios=CROSS_TOP=\"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer\" CROSS_SDK=\"iPhoneOS12.0.sdk\"\nendef\n\ndefine $(package)_preprocess_cmds\n  patch -p1 < $($(package)_patch_dir)/0001-Update-configure-for-m1-builds.patch && \\\n  LC_ALL=C sed -i.old \"/define DATE/d\" util/mkbuildinf.pl && \\\n  LC_ALL=C sed -i.old \"s|engines apps test|engines|\" Makefile.org && \\\n  LC_ALL=C sed -i.old \"s|-mandroid||\" Configure && \\\n  LC_ALL=C sed -i.old \"s|# iPhoneOS/iOS|\\\"iphoneos-cross-arm64\\\", \\\"$(package)_cc:-O3 -fomit-frame-pointer -fno-common -fembed-bitcode::-D_REENTRANT:iOS:-Wl,-search_paths_first%:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}:::-fPIC -fno-common::\\\",|\" Configure\nendef\n\ndefine $(package)_config_cmds\n  $($(package)_config_env) ./Configure $($(package)_config_opts)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) INSTALL_PREFIX=$($(package)_staging_dir) -j1 install_sw\nendef\n\ndefine $(package)_postprocess_cmds\n  rm -rf share bin etc\nendef\n"
  },
  {
    "path": "depends/packages/packages.mk",
    "content": "packages:=boost openssl qrencode electron_node_headers node_addon_api\n\nqrencode_linux_packages = qrencode\nqrencode_android_packages = qrencode\nqrencode_darwin_packages = qrencode\nqrencode_mingw32_packages = qrencode\n\nifneq ($(host_os),ios)\nifneq ($(host_os),android)\npackages += libevent libcryptopp\nendif\nendif\n\nios_packages = qrencode djinni libcryptoppunity libevent\nifeq ($(host_os),android)\npackages += libcryptoppunity protobufunity\nendif\n\n\nbdb_packages=bdb\n\nzmq_packages=zeromq\n\nupnp_packages=miniupnpc\nnatpmp_packages=libnatpmp\n\nmultiprocess_packages = libmultiprocess capnp\nmultiprocess_native_packages = native_libmultiprocess native_capnp\n\nusdt_linux_packages=systemtap\n\ndarwin_native_packages = native_ds_store native_mac_alias\n\nifneq ($(build_os),darwin)\ndarwin_native_packages += native_cctools native_libtapi\n\nifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)\ndarwin_native_packages+= native_clang\nendif\n\nendif\n"
  },
  {
    "path": "depends/packages/protobufunity.mk",
    "content": "package=protobuf\n$(package)_version=2.6.1\n$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)\n$(package)_file_name=protobuf-$($(package)_version).tar.bz2\n$(package)_sha256_hash=ee445612d544d885ae240ffbcbf9267faa9f593b7b101f21d58beceb92661910\n$(package)_cxxflags=-std=c++11\n\ndefine $(package)_set_vars\n  $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc\n  $(package)_config_opts_linux=--with-pic\n  $(package)_config_opts_android=--with-pic\nendef\n\ndefine $(package)_config_cmds\n  $($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) -C src libprotobuf.la\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\\\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA\nendef\n\ndefine $(package)_postprocess_cmds\n  rm lib/libprotoc.a && \\\n  rm lib/*.la\nendef\n"
  },
  {
    "path": "depends/packages/qrencode.mk",
    "content": "package=qrencode\n$(package)_version=3.4.4\n$(package)_download_path=https://fukuchi.org/works/qrencode/\n$(package)_file_name=$(package)-$($(package)_version).tar.bz2\n$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5\n\ndefine $(package)_set_vars\n$(package)_config_opts=--disable-shared -without-tools --disable-sdltest\n$(package)_config_opts_linux=--with-pic\n$(package)_config_opts_aarch64_ios=--host aarch64-darwin\n$(package)_config_opts_x86_64_ios=--host x86_64-darwin\nendef\n\ndefine $(package)_preprocess_cmds\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub use\nendef\n\ndefine $(package)_config_cmds\n  $($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE)\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install\nendef\n"
  },
  {
    "path": "depends/packages/rapidcheck.mk",
    "content": "package=rapidcheck\n$(package)_version=3eb9b4ff69f4ff2d9932e8f852c2b2a61d7c20d3\n$(package)_download_path=https://github.com/emil-e/rapidcheck/archive\n$(package)_file_name=$($(package)_version).tar.gz\n$(package)_sha256_hash=5fbf82755c9a647127e62563be079448ff8b1db9ca80a52a673dd9a88fdb714b\n\ndefine $(package)_config_cmds\n  cmake -DCMAKE_INSTALL_PREFIX=$($(package)_staging_dir)$(host_prefix) -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true -DRC_INSTALL_ALL_EXTRAS=ON\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) rapidcheck\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) rapidcheck install\nendef\n"
  },
  {
    "path": "depends/packages/zeromq.mk",
    "content": "package=zeromq\n$(package)_version=4.3.4\n$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/\n$(package)_file_name=$(package)-$($(package)_version).tar.gz\n$(package)_sha256_hash=c593001a89f5a85dd2ddf564805deb860e02471171b3f204944857336295c3e5\n$(package)_patches=remove_libstd_link.patch netbsd_kevent_void.patch\n\ndefine $(package)_set_vars\n  $(package)_config_opts = --without-docs --disable-shared --disable-valgrind\n  $(package)_config_opts += --disable-perf --disable-curve-keygen --disable-curve --disable-libbsd\n  $(package)_config_opts += --without-libsodium --without-libgssapi_krb5 --without-pgm --without-norm --without-vmci\n  $(package)_config_opts += --disable-libunwind --disable-radix-tree --without-gcov --disable-dependency-tracking\n  $(package)_config_opts += --disable-Werror --disable-drafts --enable-option-checking\n  $(package)_config_opts_linux=--with-pic\n  $(package)_config_opts_freebsd=--with-pic\n  $(package)_config_opts_netbsd=--with-pic\n  $(package)_config_opts_openbsd=--with-pic\n  $(package)_config_opts_android=--with-pic\n  $(package)_cxxflags+=-std=c++17\nendef\n\ndefine $(package)_preprocess_cmds\n  patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \\\n  patch -p1 < $($(package)_patch_dir)/netbsd_kevent_void.patch && \\\n  cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config\nendef\n\ndefine $(package)_config_cmds\n  ./autogen.sh && \\\n  $($(package)_autoconf)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) src/libzmq.la\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-pkgconfigDATA\nendef\n\ndefine $(package)_postprocess_cmds\n  rm -rf bin share lib/*.la\nendef\n"
  },
  {
    "path": "depends/packages/zlib.mk",
    "content": "package=zlib\n$(package)_version=1.2.11\n$(package)_download_path=http://www.zlib.net/fossils/\n$(package)_file_name=$(package)-$($(package)_version).tar.gz\n$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1\n$(package)_patches=mingw.patch\n\ndefine $(package)_set_vars\n$(package)_build_opts= CC=\"$($(package)_cc)\"\n$(package)_build_opts+=CFLAGS=\"$($(package)_cflags) $($(package)_cppflags) -fPIC\"\n$(package)_build_opts+=RANLIB=\"$($(package)_ranlib)\"\n$(package)_build_opts+=AR=\"$($(package)_ar)\"\n$(package)_build_opts_darwin+=AR=\"$($(package)_libtool)\"\n$(package)_build_opts_darwin+=ARFLAGS=\"-o\"\nendef\n\ndefine $(package)_preprocess_cmds\n   patch -p1 < $($(package)_patch_dir)/mingw.patch\nendef\n\n\ndefine $(package)_config_cmds\n  ./configure --static --prefix=$(host_prefix)\nendef\n\ndefine $(package)_build_cmds\n  $(MAKE) $($(package)_build_opts) libz.a\nendef\n\ndefine $(package)_stage_cmds\n  $(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)\nendef\n\n"
  },
  {
    "path": "depends/packages.md",
    "content": "Each recipe consists of 3 main parts: defining identifiers, setting build\nvariables, and defining build commands.\n\nThe package \"mylib\" will be used here as an example\n\nGeneral tips:\n- mylib_foo is written as $(package)_foo in order to make recipes more similar.\n- Secondary dependency packages relative to the bitcoin binaries/libraries (i.e.\n  those not in `ALLOWED_LIBRARIES` in `contrib/devtools/symbol-check.py`) don't\n  need to be shared and should be built statically whenever possible. See\n  [below](#secondary-dependencies) for more details.\n\n## Identifiers\nEach package is required to define at least these variables:\n\n    $(package)_version:\n    Version of the upstream library or program. If there is no version, a\n    placeholder such as 1.0 can be used.\n\n    $(package)_download_path:\n    Location of the upstream source, without the file-name. Usually http, https\n    or ftp. Secure transmission options like https should be preferred if\n    available.\n\n    $(package)_file_name:\n    The upstream source filename available at the download path.\n\n    $(package)_sha256_hash:\n    The sha256 hash of the upstream file\n\nThese variables are optional:\n\n    $(package)_build_subdir:\n    cd to this dir before running configure/build/stage commands.\n\n    $(package)_download_file:\n    The file-name of the upstream source if it differs from how it should be\n    stored locally. This can be used to avoid storing file-names with strange\n    characters.\n\n    $(package)_dependencies:\n    Names of any other packages that this one depends on.\n\n    $(package)_patches:\n    Filenames of any patches needed to build the package\n\n    $(package)_extra_sources:\n    Any extra files that will be fetched via $(package)_fetch_cmds. These are\n    specified so that they can be fetched and verified via 'make download'.\n\n\n## Build Variables:\nAfter defining the main identifiers, build variables may be added or customized\nbefore running the build commands. They should be added to a function called\n$(package)_set_vars. For example:\n\n    define $(package)_set_vars\n    ...\n    endef\n\nMost variables can be prefixed with the host, architecture, or both, to make\nthe modifications specific to that case. For example:\n\n    Universal:     $(package)_cc=gcc\n    Linux only:    $(package)_linux_cc=gcc\n    x86_64 only:       $(package)_x86_64_cc = gcc\n    x86_64 linux only: $(package)_x86_64_linux_cc = gcc\n\nThese variables may be set to override or append their default values.\n\n    $(package)_cc\n    $(package)_cxx\n    $(package)_objc\n    $(package)_objcxx\n    $(package)_ar\n    $(package)_ranlib\n    $(package)_libtool\n    $(package)_nm\n    $(package)_cflags\n    $(package)_cxxflags\n    $(package)_ldflags\n    $(package)_cppflags\n    $(package)_config_env\n    $(package)_build_env\n    $(package)_stage_env\n    $(package)_build_opts\n    $(package)_config_opts\n\nThe *_env variables are used to add environment variables to the respective\ncommands.\n\nMany variables respect a debug/release suffix as well, in order to use them for\nonly the appropriate build config. For example:\n\n    $(package)_cflags_release = -O3\n    $(package)_cflags_i686_debug = -g\n    $(package)_config_opts_release = --disable-debug\n\nThese will be used in addition to the options that do not specify\ndebug/release. All builds are considered to be release unless DEBUG=1 is set by\nthe user. Other variables may be defined as needed.\n\n## Build commands:\n\n  For each build, a unique build dir and staging dir are created. For example,\n  `work/build/mylib/1.0-1adac830f6e` and `work/staging/mylib/1.0-1adac830f6e`.\n\n  The following build commands are available for each recipe:\n\n    $(package)_fetch_cmds:\n    Runs from: build dir\n    Fetch the source file. If undefined, it will be fetched and verified\n    against its hash.\n\n    $(package)_extract_cmds:\n    Runs from: build dir\n    Verify the source file against its hash and extract it. If undefined, the\n    source is assumed to be a tarball.\n\n    $(package)_preprocess_cmds:\n    Runs from: build dir/$(package)_build_subdir\n    Preprocess the source as necessary. If undefined, does nothing.\n\n    $(package)_config_cmds:\n    Runs from: build dir/$(package)_build_subdir\n    Configure the source. If undefined, does nothing.\n\n    $(package)_build_cmds:\n    Runs from: build dir/$(package)_build_subdir\n    Build the source. If undefined, does nothing.\n\n    $(package)_stage_cmds:\n    Runs from: build dir/$(package)_build_subdir\n    Stage the build results. If undefined, does nothing.\n\n  The following variables are available for each recipe:\n\n    $(1)_staging_dir: package's destination sysroot path\n    $(1)_staging_prefix_dir: prefix path inside of the package's staging dir\n    $(1)_extract_dir: path to the package's extracted sources\n    $(1)_build_dir: path where configure/build/stage commands will be run\n    $(1)_patch_dir: path where the package's patches (if any) are found\n\nNotes on build commands:\n\nFor packages built with autotools, $($(package)_autoconf) can be used in the\nconfigure step to (usually) correctly configure automatically. Any\n$($(package)_config_opts) will be appended.\n\nMost autotools projects can be properly staged using:\n\n    $(MAKE) DESTDIR=$($(package)_staging_dir) install\n\n## Build outputs:\n\nIn general, the output of a depends package should not contain any libtool\narchives. Instead, the package should output `.pc` (`pkg-config`) files where\npossible.\n\nFrom the [Gentoo Wiki entry](https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Handling_Libtool_Archives):\n\n>  Libtool pulls in all direct and indirect dependencies into the .la files it\n>  creates. This leads to massive overlinking, which is toxic to the Gentoo\n>  ecosystem, as it leads to a massive number of unnecessary rebuilds.\n\n## Secondary dependencies:\n\nSecondary dependency packages relative to the bitcoin binaries/libraries (i.e.\nthose not in `ALLOWED_LIBRARIES` in `contrib/devtools/symbol-check.py`) don't\nneed to be shared and should be built statically whenever possible. This\nimproves general build reliability as illustrated by the following example:\n\nWhen linking an executable against a shared library `libprimary` that has its\nown shared dependency `libsecondary`, we may need to specify the path to\n`libsecondary` on the link command using the `-rpath/-rpath-link` options, it is\nnot sufficient to just say `libprimary`.\n\nFor us, it's much easier to just link a static `libsecondary` into a shared\n`libprimary`. Especially because in our case, we are linking against a dummy\n`libprimary` anyway that we'll throw away. We don't care if the end-user has a\nstatic or dynamic `libsecondary`, that's not our concern. With a static\n`libsecondary`, when we need to link `libprimary` into our executable, there's no\ndependency chain to worry about as `libprimary` has all the symbols.\n\n## Build targets:\n\nTo build an individual package (useful for debugging), following build targets are available.\n\n    make ${package}\n    make ${package}_fetched\n    make ${package}_extracted\n    make ${package}_preprocessed\n    make ${package}_configured\n    make ${package}_built\n    make ${package}_staged\n    make ${package}_postprocessed\n    make ${package}_cached\n    make ${package}_cached_checksum\n"
  },
  {
    "path": "depends/patches/electron_node_headers/node.def",
    "content": "LIBRARY node.exe\nEXPORTS\nuv_default_loop\nuv_queue_work\nnapi_acquire_threadsafe_function\nnapi_add_env_cleanup_hook\nnapi_add_finalizer\nnapi_adjust_external_memory\nnapi_async_destroy\nnapi_async_init\nnapi_call_function\nnapi_call_threadsafe_function\nnapi_cancel_async_work\nnapi_close_callback_scope\nnapi_close_escapable_handle_scope\nnapi_close_handle_scope\nnapi_coerce_to_bool\nnapi_coerce_to_number\nnapi_coerce_to_object\nnapi_coerce_to_string\nnapi_create_array\nnapi_create_array_with_length\nnapi_create_arraybuffer\nnapi_create_async_work\nnapi_create_bigint_int64\nnapi_create_bigint_uint64\nnapi_create_bigint_words\nnapi_create_buffer\nnapi_create_buffer_copy\nnapi_create_dataview\nnapi_create_date\nnapi_create_double\nnapi_create_error\nnapi_create_external\nnapi_create_external_arraybuffer\nnapi_create_external_buffer\nnapi_create_function\nnapi_create_int32\nnapi_create_int64\nnapi_create_object\nnapi_create_promise\nnapi_create_range_error\nnapi_create_reference\nnapi_create_string_latin1\nnapi_create_string_utf16\nnapi_create_string_utf8\nnapi_create_symbol\nnapi_create_threadsafe_function\nnapi_create_type_error\nnapi_create_typedarray\nnapi_create_uint32\nnapi_define_class\nnapi_define_properties\nnapi_delete_async_work\nnapi_delete_element\nnapi_delete_property\nnapi_delete_reference\nnapi_detach_arraybuffer\nnapi_escape_handle\nnapi_fatal_error\nnapi_fatal_exception\nnapi_get_and_clear_last_exception\nnapi_get_array_length\nnapi_get_arraybuffer_info\nnapi_get_boolean\nnapi_get_buffer_info\nnapi_get_cb_info\nnapi_get_dataview_info\nnapi_get_date_value\nnapi_get_element\nnapi_get_global\nnapi_get_instance_data\nnapi_get_last_error_info\nnapi_get_named_property\nnapi_get_new_target\nnapi_get_node_version\nnapi_get_null\nnapi_get_property\nnapi_get_property_names\nnapi_get_prototype\nnapi_get_reference_value\nnapi_get_threadsafe_function_context\nnapi_get_typedarray_info\nnapi_get_undefined\nnapi_get_uv_event_loop\nnapi_get_value_bigint_int64\nnapi_get_value_bigint_uint64\nnapi_get_value_bigint_words\nnapi_get_value_bool\nnapi_get_value_double\nnapi_get_value_external\nnapi_get_value_int32\nnapi_get_value_int64\nnapi_get_value_string_latin1\nnapi_get_value_string_utf16\nnapi_get_value_string_utf8\nnapi_get_value_uint32\nnapi_get_version\nnapi_has_element\nnapi_has_named_property\nnapi_has_own_property\nnapi_has_property\nnapi_instanceof\nnapi_is_array\nnapi_is_arraybuffer\nnapi_is_buffer\nnapi_is_dataview\nnapi_is_date\nnapi_is_detached_arraybuffer\nnapi_is_error\nnapi_is_exception_pending\nnapi_is_promise\nnapi_is_typedarray\nnapi_make_callback\nnapi_module_register\nnapi_new_instance\nnapi_open_callback_scope\nnapi_open_escapable_handle_scope\nnapi_open_handle_scope\nnapi_queue_async_work\nnapi_ref_threadsafe_function\nnapi_reference_ref\nnapi_reference_unref\nnapi_reject_deferred\nnapi_release_threadsafe_function\nnapi_remove_env_cleanup_hook\nnapi_remove_wrap\nnapi_resolve_deferred\nnapi_run_script\nnapi_set_element\nnapi_set_instance_data\nnapi_set_named_property\nnapi_set_property\nnapi_strict_equals\nnapi_throw\nnapi_throw_error\nnapi_throw_range_error\nnapi_throw_type_error\nnapi_typeof\nnapi_unref_threadsafe_function\nnapi_unwrap\nnapi_wrap\n"
  },
  {
    "path": "depends/sdk.guess",
    "content": "#! /bin/sh\n# Attempt to guess an SDK path for MacOS\n# Copyright 2019-2022 The Centure developers\n# Originally written by Malcolm MacLeod (mmacleod@gmx.com)\n\nif [ -d \"$1/SDKs\" ]; then\n  echo \"$1/SDKs\"\n  exit 0\nfi\n\nif [ -d \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/\" ]; then\n   echo \"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/\"\n   exit 0\nfi\n\nif [ -d \"/Library/Developer/CommandLineTools/SDKs/\" ]; then\n   echo \"/Library/Developer/CommandLineTools/SDKs/\"\n   exit 0\nfi\n\nexit 0\n"
  },
  {
    "path": "developer-tools/README.md",
    "content": "Developer tools\n---------------------\n\nThis directory, and sub-directories, contain various scripts that are not a core part of the repository itself, but aid developers with working with maintaining the repository, or building the repository for specific configurations and so forth.\n\n* build_docker.sh        - Build Munt/Munt-daemon binaries inside a docker container\n* build_node.sh          - Build a copy of the Munt core \"unity\" library that can be used from node/electron applications\n* build_android_core.sh  - Build a copy of the Munt core \"unity\" library that can be used from android applications\n* build_ios_core.sh      - Build a copy of the Munt core \"unity\" library that can be used from ios applications\n* gencheckpoints.sh      - Generate updated/recent checkpoints to be used for new builds (result must be manually pasted into chainparams.cpp as appropriate)\n* genbootstrap.sh        - Build a bootstrap file up until most recent blocks; If an existing checkpoint file exists then it will update the existing file instead of starting from genesis each time.\n* update_translations.sh - Sync the translation strings with the latest from translate.munt.org (bi-directional)\n\n\n\nSettings\n---------------------\n### private.conf.example ###\n\nAll developer tools scripts make use of a single configuration file 'private.conf' in which developer specific settings/preferences can be set. 'private.conf' is included in .gitignore to prevent accidental commit to the repository.\n'private.conf'example' serves as an easy reference of all possible options that can be set, new developers can copy this to create 'private.conf' and then alter options as needed. When adding new options to scripts please also add them to 'private.conf.example' to keep it complete.\n\n\n\nAdding/Developing new scripts\n---------------------\n\nNew scripts should be a bash shell script (.sh) that sources `private.conf`.\nIt is okay to use other language such as python to do the bulk of the work, many of the existing scripts already do this, in such a case just place the `.py` part of the script in an appropriate place (e.g. python sub-folder) and have a wrapper `.sh` that sets things up.\n\n"
  },
  {
    "path": "developer-tools/build_docker.sh",
    "content": "#! /bin/bash\nset -e\n\n#Set up docker container\ncd developer-tools/docker-build\ndocker build -t nlg-build .\n\n#Run the build\ncd ../../\ndocker run -it --mount type=bind,src=$PWD,dst=/work -w /work nlg-build\n\n"
  },
  {
    "path": "developer-tools/build_node.sh",
    "content": "#! /bin/bash\nset -e\nset -x\n\nNUM_PROCS=$(getconf _NPROCESSORS_ONLN)\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\nPLATFORM=`./depends/config.guess`\nPLATFORM_VENDOR=`./depends/config.guess | cut -d- -f2`\nPLATFORM_OS=`./depends/config.guess | cut -d- -f3`\n\nif test -f developer-tools/private.conf; then\n    source developer-tools/private.conf\nfi\n\nexport CXXFLAGS=\"-fPIC -fdata-sections -ffunction-sections -fomit-frame-pointer -DNAPI_VERSION=5 -DDJINNI_NODEJS -D_HAS_EXCEPTIONS=1\"\nexport CFLAGS=${CXXFLAGS}\nif [ ${PLATFORM_VENDOR} = \"apple\" ]; then\n    export LDFLAGS=\"-fPIC -Bsymbolic -Wl,-undefined -Wl,dynamic_lookup\"\nelse\n    if [ ${PLATFORM_OS} = \"mingw32\" ] ||  [ ${PLATFORM_OS} = \"mingw64\" ]; then\n        export LDFLAGS=\"-fPIC -Bsymbolic -L${DIR}/../build_node -lnode -Wl,--gc-sections\"\n        export EXTRA_CXX_FLAGS=\"-DNODE_HOST_BINARY=node.exe -DUSING_UV_SHARED=1 -DUSING_V8_SHARED=1 -DV8_DEPRECATION_WARNINGS=1 -DV8_DEPRECATION_WARNINGS -DV8_IMMINENT_DEPRECATION_WARNINGS -DWIN32 -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DBUILDING_NODE_EXTENSION -D_WINDLL\"\n    else\n        export LDFLAGS=\"-fPIC -Bsymbolic -Wl,--gc-sections\"\n    fi\nfi\n\ncd depends\nmake NO_QT=1 NO_UPNP=1 EXTRA_PACKAGES='qrencode node_addon_api electron_node_headers' -j ${NUM_PROCS}\ncd ..\n\nmkdir build_node | true\ncd build_node\n\nexport CXXFLAGS=\"${CXXFLAGS} -I$PWD/../depends/${PLATFORM}/include/node -I$PWD/../depends/${PLATFORM}/include/node-addon-api ${EXTRA_CXX_FLAGS} -O2\"\nexport CFLAGS=${CXXFLAGS}\n\n../autogen.sh\n#NB! Important to pass exmpty config.site here; otherwise msys2 has a default config.site that messes with (overrides) our own from the depends directory...\nCONFIG_SITE='' ../configure --prefix=$PWD/../depends/${PLATFORM} --disable-bench --disable-tests --disable-man --disable-zmq --without-utils  --without-daemon --with-node-js-libs --with-qrencode --with-gui=no\nmake V=1 -j ${NUM_PROCS}\n\ncd ..\n\nif test -f \"build_node/src/.libs/lib_unity_node_js-0.dll\"; then\n    cp build_node/src/.libs/lib_unity_node_js-0.dll src/frontend/electron_sample/lib_unity.node\n    cp build_node/src/.libs/lib_unity_node_js-0.dll src/frontend/electron_vue/src/unity/lib_unity.node\n    cp build_node/src/.libs/lib_unity_node_js-0.dll src/frontend/lite/src/unity/lib_unity.node\nelif test -f \"build_node/src/.libs/lib_unity_node_js.so\"; then\n    cp build_node/src/.libs/lib_unity_node_js.so src/frontend/electron_sample/lib_unity.node\n    cp build_node/src/.libs/lib_unity_node_js.so src/frontend/electron_vue/src/unity/lib_unity.node\n    cp build_node/src/.libs/lib_unity_node_js.so src/frontend/lite/src/unity/lib_unity.node\nfi\n"
  },
  {
    "path": "developer-tools/djinni_generate_bindings.sh",
    "content": "#!/bin/bash\n\nDJINNI_REPO=https://github.com/mjmacleod/djinni.git\n\nif [ ! -d djinni ]; then\n\tgit clone --single-branch --branch gulden ${DJINNI_REPO}\nelse\n\tcd djinni\n\tgit pull origin\n\tcd ..\nfi\nrm -rf src/unity/djinni/*\nrm -rf src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/*\n\ndjinni/src/run \\\n --java-out ./src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/ \\\n   --java-package unity_wallet.jniunifiedbackend \\\n   --java-implement-android-os-parcelable true \\\n   --ident-java-field mFooBar \\\n   --jni-out src/unity/djinni/jni/ \\\n   --ident-jni-class NativeFooBar \\\n   --ident-jni-file NativeFooBar \\\n   --objc-out src/unity/djinni/objc/ \\\n   --objc-type-prefix DB \\\n   --objcpp-out src/unity/djinni/objc/ \\\n   --node-out src/unity/djinni/node_js/ \\\n   --node-package unifiedbackend \\\n   --node-type-prefix NJS \\\n   --cpp-out src/unity/djinni/cpp/ \\\n   --idl src/unity/libunity.djinni\n\nmkdir src/unity/djinni/support-lib\ncp -rf djinni/support-lib/* src/unity/djinni/support-lib/\n"
  },
  {
    "path": "developer-tools/docker-build/Dockerfile",
    "content": "# Build Munt ()\n#\n# VERSION               0.1\n\nFROM ubuntu:18.04\n\n# Generic build tools\nRUN apt-get update && apt-get install  -y \\\n    build-essential \\\n    libtool \\\n    autotools-dev \\\n    automake \\\n    pkg-config \\\n    bsdmainutils \\\n    curl \\\n    git \\\n    ca-certificates \\\n    ccache \\\n    gawk \\\n && apt-get clean \\\n && rm -rf /var/lib/apt/lists/* \n\n# SDK prerequisites\nRUN apt-get update && apt-get install  -y \\\n    libqrencode-dev \\\n    libminiupnpc-dev \\\n    python3-zmq \\\n    protobuf-compiler \\\n    libdbus-1-dev \\\n    libharfbuzz-dev \\\n    libprotobuf-dev \\\n && apt-get clean \\\n && rm -rf /var/lib/apt/lists/* \n\nADD *.sh /root/\nCMD /root/build.sh\n"
  },
  {
    "path": "developer-tools/docker-build/README.md",
    "content": "# Docker image to compile the Munt binaries\n\nThe build is for test and development purposes, the official binaries are build with guix and not this image.\n\nThis image closely matches the [Travis build](https://travis-ci.org/Munt/munt-official/)\n\n## Using this image\n\nPull the Munt repository and run this image on it, like so:\n\n```\ngit clone https://github.com/Munt/munt-official\ncd munt-official\ndocker run -it --mount type=bind,src=$PWD,dst=/work -w /work robobit/nlg-build\n```\n\nThis will pull the image from Docker hub, if you rather build your own:\n```\ngit clone https://github.com/Munt/munt-official\ncd munt-official/developer-tools/docker-build\ndocker build -t nlg-build .\ndocker run -it --mount type=bind,src=$PWD,dst=/work -w /work nlg-build\n```\n"
  },
  {
    "path": "developer-tools/docker-build/build.sh",
    "content": "#!/bin/bash\n\nMAKEJOBS=-j3\nHOST=x86_64-unknown-linux-gnu\nDEP_OPTS=\"NO_UPNP=1 ALLOW_HOST_PACKAGES=1\"\n\nmake $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS\n\n./autogen.sh\nmkdir -p build/$HOST && cd build/$HOST\n../../configure LDFLAGS=\"-static-libstdc++\" --cache-file=config.cache --prefix=/work/depends/$HOST --enable-werror --enable-zmq --enable-reduce-exports\nmake $MAKEJOBS\n"
  },
  {
    "path": "developer-tools/genbootstrap.sh",
    "content": "#! /bin/bash\nset -e\n\nsource developer-tools/private.conf\npython developer-tools/python/genbootstrap.py\n\necho \"compress bootstrap\"\nxz -zkfe9T0 ${BOOTSTRAP_FILENAME}\necho \"done compressing bootstrap\"\n"
  },
  {
    "path": "developer-tools/gencheckpoints.sh",
    "content": "#! /bin/bash\nset -e\n\n#Fetch our private configuration variables and then hand the rest of the work off to python script\nsource developer-tools/private.conf\npython developer-tools/python/gencheckpoints.py > src/data/chainparams_mainnet_static_checkpoint_data.cpp\n"
  },
  {
    "path": "developer-tools/genstaticdiffs.sh",
    "content": "#! /bin/bash\nset -e\n\n#Fetch our private configuration variables and then hand the rest of the work off to python script\nsource developer-tools/private.conf\nHEIGHT=$(python developer-tools/python/genstaticdiffs.py)\nsed -i 's/const int32_t nMaxHeight =.*/const int32_t nMaxHeight = '${HEIGHT}';/g' src/pow/diff_old.cpp\nsed -ri 's/nOldDiffSwitchoverBlock =([^,]+).*/nOldDiffSwitchoverBlock =\\1, '${HEIGHT}');/g' src/pow/diff_common.cpp\nsed -i 's/ //g' ${STATICDIFF_FILENAME}\n"
  },
  {
    "path": "developer-tools/genstaticfilters.sh",
    "content": "#! /bin/bash\nset -e\n\n#Fetch our private configuration variables and then hand the rest of the work off to python script\nsource developer-tools/private.conf\n$(python developer-tools/python/genstaticfilters.py)\n"
  },
  {
    "path": "developer-tools/mobile/android/build_android_core.sh",
    "content": "#! /bin/bash\nset -e\nset -x\n\n#Load NDK config\nsource `dirname $0`/ndk_definitions.conf\n\n#Load private config\nMUNT_DEVTOOLS_CONF=${MUNT_DEVTOOLS_CONF:-developer-tools/private.conf}\nif [ -f $MUNT_DEVTOOLS_CONF ]; then\n  source ${MUNT_DEVTOOLS_CONF}\nfi\n\nTARGETS_PATH=$(dirname ${BASH_SOURCE[0]})/build_targets\n\nwhile :; do\n  case $1 in\n    --nodepends)\n      SKIP_DEPENDS=1\n      ;;\n    --noconfig)\n      SKIP_CONFIG=1\n      ;;\n    --targets)\n      shift\n      delimiter=\",\"\n      s=$1$delimiter\n      NDK_TARGETS=();\n      while [[ $s ]]; do\n        NDK_TARGETS+=( ${TARGETS_PATH}/\"${s%%\"$delimiter\"*}\" );\n        s=${s#*\"$delimiter\"};\n      done;\n      declare -p NDK_TARGETS\n\n      ;;\n    *) # Default case: No more options, so break out of the loop.\n      break\n  esac\n  shift\ndone\n\n\nif [ -z \"${NDK_TARGETS}\" ]; then\n  NDK_TARGETS=( ${TARGETS_PATH}/* )\n  declare -p NDK_TARGETS\nfi\n\nmkdir src/frontend/android/unity_wallet/app/src/main/jniLibs | true\n\nNUM_PROCS=$(getconf _NPROCESSORS_ONLN)\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\nASSETS=src/frontend/android/unity_wallet/app/src/main/assets\n\nmkdir ${ASSETS} | true\nmkdir ${ASSETS}Mainnet | true\nmkdir ${ASSETS}Testnet | true\n\ncp src/data/staticfiltercp ${ASSETS}Mainnet/staticfiltercp\ncp src/data/staticfiltercptestnet ${ASSETS}Testnet/staticfiltercp\ncp src/data/core-packages.licenses ${ASSETS}/core-packages.licenses\n\nexport NDK_ROOT=${NDK_ROOT:-${PWD}/developer-tools/android-ndk/${NDK_VERSION}}\n\ncase \"$OSTYPE\" in\n  darwin*)\n      BUILD_PLATFORM=darwin-x86_64\n      ;;\n  *)\n      BUILD_PLATFORM=linux-x86_64\n      ;;\nesac\n\nPREBUILT=${NDK_ROOT}/toolchains/llvm/prebuilt/${BUILD_PLATFORM}\nLIB_DIR=${PREBUILT}/sysroot/usr/lib\nTOOLS=${PREBUILT}/bin\n\nif [ -z \"$SKIP_CONFIG\" ]\nthen\n    ./autogen.sh\nelse\n    echo Skipping autogen\nfi\n\nfor i in \"${NDK_TARGETS[@]}\"\ndo\n  source ${i}\n  export AR=${TOOLS}/llvm-ar\n  export AS=${TOOLS}/$target_host-as\n  export CC=${TOOLS}/${clang_prefix}${ANDROID_LEVEL}-clang\n  export CXX=${TOOLS}/${clang_prefix}${ANDROID_LEVEL}-clang++\n  export LD=${TOOLS}/llvm-ld\n  export STRIP=${TOOLS}/llvm-strip\n  export RANLIB=${TOOLS}/llvm-ranlib\n  export LIBTOOL=libtool\n  # build with debug symbols, android studio will take care of split-debug and stripping\n  export CXXFLAGS=\"-O3 -fPIC -fdata-sections -ffunction-sections -fomit-frame-pointer ${march_flags} -DANDROID_STL=c++_shared -DEXPERIMENTAL_AUTO_CPP_THREAD_ATTACH ${target_opt_cflags} -g3\"\n  #visibility=hidden\n  export CFLAGS=${CXXFLAGS}\n  export LDFLAGS=\"-fPIC -Bsymbolic -Wl,--no-undefined -Wl,--gc-sections -Wl,--build-id\"\n\n  if [ -z \"$SKIP_DEPENDS\" ]\n  then\n    cd depends\n    make HOST=$target_host NO_QT=1 NO_UPNP=1 EXTRA_PACKAGES='qrencode protobufunity' -j ${NUM_PROCS}\n    cd ..\n  else\n    echo Skipping depends\n  fi\n\n  export TARGET_OS=android\n  mkdir build_android_${target_host} | true\n  cd build_android_${target_host}\n  if [ -z \"$SKIP_CONFIG\" ]\n  then\n    ../configure --prefix=$PWD/../depends/$target_host ac_cv_c_bigendian=no ac_cv_sys_file_offset_bits=$target_bits --host=$target_host --disable-bench --enable-experimental-asm --disable-tests --disable-man --disable-zmq --without-utils --with-libs --without-daemon --with-jni-libs --with-qrencode --with-node-js-libs=no\n  else\n    echo Skipping explicit configure\n  fi\n  make V=1 -j ${NUM_PROCS} V=1\n  cd ..\n\n  mkdir src/frontend/android/unity_wallet/app/src/main/jniLibs/${jni_lib} | true\n  cp build_android_${target_host}/src/.libs/lib_unity_jni.so src/frontend/android/unity_wallet/app/src/main/jniLibs/${jni_lib}/\n  cp ${LIB_DIR}/${target_host}/libc++_shared.so src/frontend/android/unity_wallet/app/src/main/jniLibs/${jni_lib}/\ndone\n"
  },
  {
    "path": "developer-tools/mobile/android/build_targets/aarch64-linux-android-clang",
    "content": "clang_prefix=aarch64-linux-android\ntarget_host=aarch64-linux-android\ntarget_bits=64\njni_lib=arm64-v8a\nlib_dir=sysroot/usr/lib\nmarch_flags=\"-O3\"\ntarget_opt_cflags=\"-DCRYPTOPP_ARM_ACLE_AVAILABLE -D__ARM_FEATURE_CRC32\"\n"
  },
  {
    "path": "developer-tools/mobile/android/build_targets/arm-linux-androideabi-clang",
    "content": "clang_prefix=armv7a-linux-androideabi\ntarget_host=arm-linux-androideabi\ntarget_bits=32\njni_lib=armeabi-v7a\nlib_dir=sysroot/usr/lib\nmarch_flags=\"-mthumb -O3\"\ntarget_opt_cflags=-DCRYPTOPP_ARM_ACLE_AVAILABLE\n"
  },
  {
    "path": "developer-tools/mobile/android/build_targets/x86-clang",
    "content": "clang_prefix=i686-linux-android\ntarget_host=i686-linux-android\ntarget_bits=32\njni_lib=x86\nlib_dir=sysroot/usr/lib\nmarch_flags=\"-march=i686 -mtune=i686 -mssse3 -mfpmath=sse -m32\"\ntarget_opt_cflags=\n"
  },
  {
    "path": "developer-tools/mobile/android/build_targets/x86_64-clang",
    "content": "clang_prefix=x86_64-linux-android\ntarget_host=x86_64-linux-android\ntarget_bits=64\njni_lib=x86_64\nlib_dir=sysroot/usr/lib\nmarch_flags=\"-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=x86-64\"\ntarget_opt_cflags=\n"
  },
  {
    "path": "developer-tools/mobile/android/fetch_android.sh",
    "content": "#!/bin/bash\nset -e\nset -x\n\n#Load NDK config\nsource `dirname $0`/ndk_definitions.conf\n\n#Load private config\nsource developer-tools/private.conf\n\ncase \"$OSTYPE\" in\n  darwin*)\n      PLATFORM=darwin\n      ;;\n  *)\n      PLATFORM=linux\n      ;;\nesac\n\nexport NDK_FILENAME=${NDK_VERSION}-${PLATFORM}.zip\n\n#sha256_file=5dfbbdc2d3ba859fed90d0e978af87c71a91a5be1f6e1c40ba697503d48ccecd\n\nmkdir ./developer-tools/android-ndk | true\ncd ./developer-tools/android-ndk\ncurl -sSO https://dl.google.com/android/repository/${NDK_FILENAME} &> /dev/null\n#echo \"${sha256_file}  ${NDK_FILENAME}\" | shasum -a 256 --check\nunzip -qq ${NDK_FILENAME} &> /dev/null\nrm ${NDK_FILENAME}\ncd -\n"
  },
  {
    "path": "developer-tools/mobile/android/ndk_definitions.conf",
    "content": "NDK_VERSION=android-ndk-r23b\nANDROID_LEVEL=21\n"
  },
  {
    "path": "developer-tools/mobile/ios/build_ios_core.sh",
    "content": "#! /bin/bash\nset -e\nset -x\n\nNPROC=`sysctl -n hw.physicalcpu`\n\nexport CXXFLAGS=\"-O3\"\nexport CFLAGS=${CXXFLAGS}\n\nfor i in $( dirname ${BASH_SOURCE[0]} )/build_targets/*\ndo\n  source ${i}\n\n  cd depends\n  make HOST=$target_host NO_ZMQ=1 NO_QT=1 NO_UPNP=1 -j $NPROC\n  cd ..\n\n  mkdir -p build/${target_host}\n  cd build/${target_host}\n  ../../autogen.sh\n  ../../configure --prefix=$PWD/../../depends/$target_host --host=$target_host --disable-bench --enable-experimental-asm --disable-tests --disable-man --disable-zmq --without-utils --without-daemon --with-objc-libs --with-qrencode\n  make -j $NPROC\n  cd ../..\ndone\n"
  },
  {
    "path": "developer-tools/mobile/ios/build_targets/aarch64",
    "content": "target_host=aarch64-ios\n"
  },
  {
    "path": "developer-tools/mobile/ios/build_targets/x86_64",
    "content": "target_host=x86_64-ios\n"
  },
  {
    "path": "developer-tools/mobile/thirdparty.licenses.sh",
    "content": "#! /bin/bash\nset -e\nset -x\n\nOUTPUT=./src/data/core-packages.licenses\n\necho \"\" > $OUTPUT\n\necho \"-- LevelDB\" >> $OUTPUT\ncat ./src/leveldb/LICENSE >> $OUTPUT\n\necho \"-- QFontIcon\" >> $OUTPUT\ncat ./src/qt/qfonticon/License.md >> $OUTPUT\n\necho \"-- QFontIcon\" >> $OUTPUT\ncat ./src/qt/qfonticon/License.md >> $OUTPUT\n\necho \"-- scrypt\" >> $OUTPUT\ncat ./src/crypto/scrypt/COPYING >> $OUTPUT\n\necho \"-- ctaes\" >> $OUTPUT\ncat ./src/crypto/ctaes/COPYING >> $OUTPUT\n\necho \"-- libsecp256k1\" >> $OUTPUT\ncat ./src/secp256k1/COPYING >> $OUTPUT\n\necho \"-- LRUCache11\" >> $OUTPUT\ncat ./src/LRUCache/COPYING >> $OUTPUT\n\necho \"-- UniValue\" >> $OUTPUT\ncat ./src/univalue/COPYING >> $OUTPUT\n\necho \"-- libqrencode\" >> $OUTPUT\ncat <<EOT >> $OUTPUT\nCopyright (C) 2006-2018 Kentaro Fukuchi\n\nThis library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or any later version.\n\nThis library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\nEOT\n\necho \"-- Bitcoin Core\" >> $OUTPUT\ncat <<EOT >> $OUTPUT\nThe MIT License (MIT)\n\nCopyright (c) 2009-2019 The Bitcoin Core developers\nCopyright (c) 2009-2019 Bitcoin Developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\nEOT\n"
  },
  {
    "path": "developer-tools/node/node.def",
    "content": "LIBRARY node.exe\nEXPORTS\nuv_default_loop\nuv_queue_work\nnapi_acquire_threadsafe_function\nnapi_add_env_cleanup_hook\nnapi_add_finalizer\nnapi_adjust_external_memory\nnapi_async_destroy\nnapi_async_init\nnapi_call_function\nnapi_call_threadsafe_function\nnapi_cancel_async_work\nnapi_close_callback_scope\nnapi_close_escapable_handle_scope\nnapi_close_handle_scope\nnapi_coerce_to_bool\nnapi_coerce_to_number\nnapi_coerce_to_object\nnapi_coerce_to_string\nnapi_create_array\nnapi_create_array_with_length\nnapi_create_arraybuffer\nnapi_create_async_work\nnapi_create_bigint_int64\nnapi_create_bigint_uint64\nnapi_create_bigint_words\nnapi_create_buffer\nnapi_create_buffer_copy\nnapi_create_dataview\nnapi_create_date\nnapi_create_double\nnapi_create_error\nnapi_create_external\nnapi_create_external_arraybuffer\nnapi_create_external_buffer\nnapi_create_function\nnapi_create_int32\nnapi_create_int64\nnapi_create_object\nnapi_create_promise\nnapi_create_range_error\nnapi_create_reference\nnapi_create_string_latin1\nnapi_create_string_utf16\nnapi_create_string_utf8\nnapi_create_symbol\nnapi_create_threadsafe_function\nnapi_create_type_error\nnapi_create_typedarray\nnapi_create_uint32\nnapi_define_class\nnapi_define_properties\nnapi_delete_async_work\nnapi_delete_element\nnapi_delete_property\nnapi_delete_reference\nnapi_detach_arraybuffer\nnapi_escape_handle\nnapi_fatal_error\nnapi_fatal_exception\nnapi_get_and_clear_last_exception\nnapi_get_array_length\nnapi_get_arraybuffer_info\nnapi_get_boolean\nnapi_get_buffer_info\nnapi_get_cb_info\nnapi_get_dataview_info\nnapi_get_date_value\nnapi_get_element\nnapi_get_global\nnapi_get_instance_data\nnapi_get_last_error_info\nnapi_get_named_property\nnapi_get_new_target\nnapi_get_node_version\nnapi_get_null\nnapi_get_property\nnapi_get_property_names\nnapi_get_prototype\nnapi_get_reference_value\nnapi_get_threadsafe_function_context\nnapi_get_typedarray_info\nnapi_get_undefined\nnapi_get_uv_event_loop\nnapi_get_value_bigint_int64\nnapi_get_value_bigint_uint64\nnapi_get_value_bigint_words\nnapi_get_value_bool\nnapi_get_value_double\nnapi_get_value_external\nnapi_get_value_int32\nnapi_get_value_int64\nnapi_get_value_string_latin1\nnapi_get_value_string_utf16\nnapi_get_value_string_utf8\nnapi_get_value_uint32\nnapi_get_version\nnapi_has_element\nnapi_has_named_property\nnapi_has_own_property\nnapi_has_property\nnapi_instanceof\nnapi_is_array\nnapi_is_arraybuffer\nnapi_is_buffer\nnapi_is_dataview\nnapi_is_date\nnapi_is_detached_arraybuffer\nnapi_is_error\nnapi_is_exception_pending\nnapi_is_promise\nnapi_is_typedarray\nnapi_make_callback\nnapi_module_register\nnapi_new_instance\nnapi_open_callback_scope\nnapi_open_escapable_handle_scope\nnapi_open_handle_scope\nnapi_queue_async_work\nnapi_ref_threadsafe_function\nnapi_reference_ref\nnapi_reference_unref\nnapi_reject_deferred\nnapi_release_threadsafe_function\nnapi_remove_env_cleanup_hook\nnapi_remove_wrap\nnapi_resolve_deferred\nnapi_run_script\nnapi_set_element\nnapi_set_instance_data\nnapi_set_named_property\nnapi_set_property\nnapi_strict_equals\nnapi_throw\nnapi_throw_error\nnapi_throw_range_error\nnapi_throw_type_error\nnapi_typeof\nnapi_unref_threadsafe_function\nnapi_unwrap\nnapi_wrap\n"
  },
  {
    "path": "developer-tools/private.conf.example",
    "content": "# Set API key from translate.munt.org here to be able to run translation scripts\n#ONESKY_API_KEY=\n\n# Set this to a system or custom NDK path to have android build scripts use this as opposed to the ones fetched by fetch_android.sh\n#NDK_ROOT=\n\n# Comma delimited list of Android targets in mobile/android/build_targets/ for which to build the Unity library (if not set all will be build)\n#NDK_TARGETS= aarch64-linux-android-clang,arm-linux-androideabi-clang\n\n# Set this to 1 to skip building depends for android\n#SKIP_DEPENDS=1\n\n# Set this to 1 to skip running configure for android \n#SKIP_CONFIG=1\n\n# Set for gencheckpoints.py usage\n#CHECKPOINT_RPC_USER=xxx\n#CHECKPOINT_RPC_PASSWORD=yyy\n#CHECKPOINT_RPC_PORT=9232\n#CHECKPOINT_RPC_IP=127.0.0.1\n#CHECKPOINT_MSG_HEADER=fcfef7e0\n\n"
  },
  {
    "path": "developer-tools/python/genbootstrap.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"Generate bootstrap.dat\n   Script will connect to Munt rpc server and fetch all blocks necessary to create a clean bootstrap.dat file\n   The results are incremental i.e. you can re-run this periodically (if you leave the files in place) and it will update the exiting file with only the latest blocks instead of completely regenerating it\n   First run is slow (few hours) but subsequent runs should be reasonably fast as they have much less work to do\n\"\"\"\n\nfrom bitcoinrpc.authproxy import AuthServiceProxy\nimport sys\nimport string\nimport os\nimport binascii\nimport struct\n\n__copyright__ = 'Copyright (c) 2019-2022 The Centure developers'\n__license__   = 'Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING'\n__author__    = 'Malcolm MacLeod'\n__email__     = 'mmacleod@gmx.com'\n\n# ===== BEGIN USER SETTINGS =====\nrpcuser=os.environ[\"CHECKPOINT_RPC_USER\"]\nrpcpass=os.environ[\"CHECKPOINT_RPC_PASSWORD\"]\nrpcport=os.environ[\"CHECKPOINT_RPC_PORT\"]\nrpcip=os.environ[\"CHECKPOINT_RPC_IP\"]\nmessageheader=os.environ[\"CHECKPOINT_MSG_HEADER\"]\nbootstrapfilename=os.environ[\"BOOTSTRAP_FILENAME\"]\n\n# ====== END USER SETTINGS ======\n\naccess = AuthServiceProxy(\"http://\"+rpcuser+\":\"+rpcpass+\"@\"+rpcip+\":\"+rpcport)\n\nbootstrap_start=0\n\ntry:\n    bootstrap_file_last = open(bootstrapfilename+\".pos\", \"r\")\n    bootstrap_start = int(bootstrap_file_last.read());\n    bootstrap_file_last.close()\n    print(\"pre-existing bootstrap, starting from\", bootstrap_start)\n    bootstrap_file = open(bootstrapfilename, \"ba\")\nexcept IOError as e:\n    print(\"no pre-existing bootstrap, starting from 0\")\n    bootstrap_file = open(bootstrapfilename, \"wb\")\n\ndef print_bootstrap(height):\n    hash = access.getblockhash(height)\n    block_hex = access.getblock(hash, 0)\n    block_bin = binascii.unhexlify(block_hex)\n    bootstrap_file.write(binascii.unhexlify(messageheader))\n    bootstrap_file.write(struct.pack('i', len(block_bin)))\n    bootstrap_file.write(block_bin)\n\n# generate bootstrap from genesis->chaintip-100\nchain_height = access.getblockcount()\nlast_bootstrap = chain_height - 100\n\nh = bootstrap_start\nwhile h < last_bootstrap:\n    if (h % 1000 == 0):\n        print(\"writing block \", h)\n    print_bootstrap(h)\n    h = h + 1\n\n\nbootstrap_file.close()\nbootstrap_file_last = open(bootstrapfilename+\".pos\", \"w\")\nbootstrap_file_last.write(str(last_bootstrap));\nbootstrap_file_last.close()\n\nprint(\"done writing bootstrap, final height: \", last_bootstrap)\n\n"
  },
  {
    "path": "developer-tools/python/gencheckpoints.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"Generate C++ code for the compiled-in checkpoints.\n   Script will connect to Munt rpc server.\n   Generated code goes into chainparams.cpp\n\"\"\"\n\nfrom bitcoinrpc.authproxy import AuthServiceProxy\nimport sys\nimport string\nimport os\n\n__copyright__ = 'Copyright (c) 2018-2022 The Centure developers'\n__license__   = 'Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING'\n__author__    = 'Willem de Jonge'\n__email__     = 'willem@isnapp.nl'\n\n# ===== BEGIN USER SETTINGS =====\nrpcuser=os.environ[\"CHECKPOINT_RPC_USER\"]\nrpcpass=os.environ[\"CHECKPOINT_RPC_PASSWORD\"]\nrpcport=os.environ[\"CHECKPOINT_RPC_PORT\"]\nrpcip=os.environ[\"CHECKPOINT_RPC_IP\"]\n\n\n# ====== END USER SETTINGS ======\n\n# code format example:\n# {  50000, { uint256S(\"0x5baeb5a5c3d5fefbb094623e85e3e16a1ea47875b5ffd1ff5a200e639908a059\"), 1400560264 } },\n\naccess = AuthServiceProxy(\"http://\"+rpcuser+\":\"+rpcpass+\"@\"+rpcip+\":\"+rpcport)\n\ndef print_checkpoint(height):\n    hash = access.getblockhash(height)\n    block = access.getblock(hash)\n    print('    {{ {height:6}, {{ uint256S(\\\"0x{hash}\\\"), {time} }} }},'.format(height=block['height'], hash=block['hash'], time=block['time'], bits=block['bits']))\n\n# checkpoints are generated at regular intervals, in addition 2 extra checkpoints are generated\n# close to the tip this is a performance optimization which is most notable right after a release with new checkpoints\n# the extra before last checkpoint helps initial partial sync, which needs 2 checkpoints for secure initialization\nchain_height = access.getblockcount()\nlast_checkpoint = chain_height - 1 * 576\nextra_before_last = last_checkpoint - 2 * 576\ncheckpoint_period = 5000\n\nh = 0\nwhile  h < extra_before_last:\n    print_checkpoint(h)\n    h = h + checkpoint_period\n\nprint_checkpoint(extra_before_last)\nprint_checkpoint(last_checkpoint)\n"
  },
  {
    "path": "developer-tools/python/genstaticdiffs.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom bitcoinrpc.authproxy import AuthServiceProxy\nimport sys\nimport string\nimport os\n\n__copyright__ = 'Copyright (c) 2018-2022 The Centure developers'\n__license__   = 'Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING'\n__author__    = 'Malcolm MacLeod'\n__email__     = 'mmacleod@gmx.com'\n\n# ===== BEGIN USER SETTINGS =====\nrpcuser=os.environ[\"CHECKPOINT_RPC_USER\"]\nrpcpass=os.environ[\"CHECKPOINT_RPC_PASSWORD\"]\nrpcport=os.environ[\"CHECKPOINT_RPC_PORT\"]\nrpcip=os.environ[\"CHECKPOINT_RPC_IP\"]\ndifffilename=os.environ[\"STATICDIFF_FILENAME\"]\n# ====== END USER SETTINGS ======\n\naccess = AuthServiceProxy(\"http://\"+rpcuser+\":\"+rpcpass+\"@\"+rpcip+\":\"+rpcport)\n\nchain_height = access.getblockcount()\naccess.dumpdiffarray(chain_height, difffilename)\nprint(chain_height)\n"
  },
  {
    "path": "developer-tools/python/genstaticfilters.py",
    "content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\nfrom bitcoinrpc.authproxy import AuthServiceProxy\nimport sys\nimport string\nimport os\n\n__copyright__ = 'Copyright (c) 2022 The Gulden developers'\n__license__   = 'Distributed under the GULDEN software license, see the accompanying file COPYING'\n__author__    = 'Malcolm MacLeod'\n__email__     = 'mmacleod@gmx.com'\n\n# ===== BEGIN USER SETTINGS =====\nrpcuser=os.environ[\"CHECKPOINT_RPC_USER\"]\nrpcpass=os.environ[\"CHECKPOINT_RPC_PASSWORD\"]\nrpcport=os.environ[\"CHECKPOINT_RPC_PORT\"]\nrpcip=os.environ[\"CHECKPOINT_RPC_IP\"]\nfilename=os.environ[\"STATICFILTER_FILENAME\"]\n# ====== END USER SETTINGS ======\n\naccess = AuthServiceProxy(\"http://\"+rpcuser+\":\"+rpcpass+\"@\"+rpcip+\":\"+rpcport)\n\nif os.path.exists(filename):\n    os.remove(filename)\naccess.dumpfiltercheckpoints(filename)\n"
  },
  {
    "path": "doc/.gitignore",
    "content": "Doxyfile\n"
  },
  {
    "path": "doc/Doxyfile.in",
    "content": "# Doxyfile 1.8.12\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all text\n# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv\n# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv\n# for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = \"Munt Core\"\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = @PACKAGE_VERSION@\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"P2P Digital Currency\"\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           = doc/munt_logo_doxygen.png\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doc/doxygen\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-\n# directories (in 2 levels) under the output directory of each output format and\n# will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,\n# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),\n# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,\n# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),\n# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,\n# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,\n# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,\n# Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \"The $name class\" \\\n                         \"The $name widget\" \\\n                         \"The $name file\" \\\n                         is \\\n                         provides \\\n                         specifies \\\n                         contains \\\n                         represents \\\n                         a \\\n                         an \\\n                         the\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = YES\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = YES\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 8\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:\\n\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". You can put \\n's in the value part of an alias to insert\n# newlines.\n\nALIASES                =\n\n# This tag can be used to specify a number of word-keyword mappings (TCL only).\n# A mapping has the form \"name=value\". For example adding \"class=itcl::class\"\n# will allow you to use the command class in the itcl::class meaning.\n\nTCL_SUBST              =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, Javascript,\n# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:\n# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:\n# Fortran. In the later case the parser tries to guess whether the code is fixed\n# or free formatted code, this is the default for Fortran type files), VHDL. For\n# instance to make doxygen treat .inc files as Fortran files (default is PHP),\n# and .f files as C (default is Fortran), use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up\n# to that level are automatically included in the table of contents, even if\n# they do not have an id attribute.\n# Note: This feature currently applies only to Markdown headings.\n# Minimum value: 0, maximum value: 99, default value: 0.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nTOC_INCLUDE_HEADINGS   = 0\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = YES\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = YES\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# (class|struct|union) declarations. If set to NO, these declarations will be\n# included in the documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file\n# names in lower-case letters. If set to YES, upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some parameters\n# in a documented function, or documenting parameters that don't exist or using\n# markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong or incomplete\n# parameter documentation, but not about the absence of documentation.\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = src\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see: http://www.gnu.org/software/libiconv) for the list of\n# possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,\n# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,\n# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.\n\nFILE_PATTERNS          = *.c \\\n                         *.cc \\\n                         *.cxx \\\n                         *.cpp \\\n                         *.c++ \\\n                         *.d \\\n                         *.java \\\n                         *.ii \\\n                         *.ixx \\\n                         *.ipp \\\n                         *.i++ \\\n                         *.inl \\\n                         *.h \\\n                         *.hh \\\n                         *.hxx \\\n                         *.hpp \\\n                         *.h++ \\\n                         *.idl \\\n                         *.odl \\\n                         *.cs \\\n                         *.php \\\n                         *.php3 \\\n                         *.inc \\\n                         *.m \\\n                         *.mm \\\n                         *.dox \\\n                         *.py \\\n                         *.f90 \\\n                         *.f \\\n                         *.for \\\n                         *.vhd \\\n                         *.vhdl\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                = src/leveldb \\\n                         src/json \\\n                         src/test\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        = boost \\\n                         google\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = *\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE =\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = YES\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# function all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see http://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the config file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in\n# which the alphabetical index list will be split.\n# Minimum value: 1, maximum value: 20, default value: 5.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a colorwheel, see\n# http://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use grayscales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see: http://developer.apple.com/tools/xcode/), introduced with\n# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a\n# Makefile in the HTML output directory. Running make will produce the docset in\n# that directory and running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.munt.Munt-Core\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.munt.Munt-Core\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on\n# Windows.\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the master .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-\n# folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location of Qt's\n# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the\n# generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine-tune the look of the index. As an example, the default style\n# sheet generated by doxygen has an example that shows how to put an image at\n# the root of the tree instead of the PROJECT_NAME. Since the tree basically has\n# the same information as the tab index, you could consider setting\n# DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# http://www.mathjax.org) which uses client side Javascript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. See the MathJax site (see:\n# http://docs.mathjax.org/en/latest/output.html) for more details.\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility), NativeMML (i.e. MathML) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from http://www.mathjax.org before deployment.\n# The default value is: http://cdn.mathjax.org/mathjax/latest.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://www.mathjax.org/mathjax\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using Javascript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/). See the section \"External Indexing and\n# Searching\" for details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when enabling USE_PDFLATEX this option is only used for generating\n# bitmaps for formulas in the HTML output, but not in the Makefile that is\n# written to the output directory.\n# The default file is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the\n# generated LaTeX document. The header should contain everything until the first\n# chapter. If it is left blank doxygen will generate a standard header. See\n# section \"Doxygen usage\" for information on how to let doxygen write the\n# default header to a separate file.\n#\n# Note: Only use a user-defined header if you know what you are doing! The\n# following commands have a special meaning inside the header: $title,\n# $datetime, $date, $doxygenversion, $projectname, $projectnumber,\n# $projectbrief, $projectlogo. Doxygen will replace $title with the empty\n# string, for the replacement values of the other commands the user is referred\n# to HTML_HEADER.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the\n# generated LaTeX document. The footer should contain everything after the last\n# chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer.\n#\n# Note: Only use a user-defined footer if you know what you are doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate\n# the PDF file directly from the LaTeX files. Set this option to YES, to get a\n# higher quality PDF documentation.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help. This option is also used\n# when generating formulas in HTML.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source\n# code with syntax highlighting in the LaTeX output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# http://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's config\n# file, i.e. a series of assignments. You only have to provide replacements,\n# missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's config file. A template extensions file can be generated\n# using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code\n# with syntax highlighting in the RTF output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_SOURCE_CODE        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the\n# program listings (including syntax highlighting and cross-referencing\n# information) to the DOCBOOK output. Note that enabling this will significantly\n# increase the size of the DOCBOOK output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_PROGRAMLISTING = NO\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sf.net) file that captures the\n# structure of the code including all documentation. Note that this feature is\n# still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of 'which perl').\n# The default file (with absolute path) is: /usr/bin/perl.\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram\n# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to\n# NO turns the diagrams off. Note that this option also works with HAVE_DOT\n# disabled, but it is recommended to install and use dot, since it yields more\n# powerful graphs.\n# The default value is: YES.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see:\n# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: NO.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for\n# each documented class showing the direct and indirect inheritance relations.\n# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = YES\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = YES\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = svg\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file. If left blank, it is assumed\n# PlantUML is not used or called during a preprocessing step. Doxygen will\n# generate a warning when it encounters a \\startuml command in this case and\n# will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot\n# files that are used to generate the various graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "doc/REST-interface.md",
    "content": "Unauthenticated REST Interface\n==============================\n\nThe REST API can be enabled with the `-rest` option.\n\nThe interface runs on the same port as the JSON-RPC interface, by default port 9232 for mainnet and port 9924 for testnet.\n\nSupported API\n-------------\n\n####Transactions\n`GET /rest/tx/<TX-HASH>.<bin|hex|json>`\n\nGiven a transaction hash: returns a transaction in binary, hex-encoded binary, or JSON formats.\n\nFor full TX query capability, one must enable the transaction index via \"txindex=1\" command line / configuration option.\n\n####Blocks\n`GET /rest/block/<BLOCK-HASH>.<bin|hex|json>`\n`GET /rest/block/notxdetails/<BLOCK-HASH>.<bin|hex|json>`\n\nGiven a block hash: returns a block, in binary, hex-encoded binary or JSON formats.\n\nThe HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request.\n\nWith the /notxdetails/ option JSON response will only contain the transaction hash instead of the complete transaction details. The option only affects the JSON response.\n\n####Blockheaders\n`GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>`\n\nGiven a block hash: returns <COUNT> amount of blockheaders in upward direction.\n\n####Chaininfos\n`GET /rest/chaininfo.json`\n\nReturns various state info regarding block chain processing.\nOnly supports JSON as output format.\n* chain : (string) current network name as defined in BIP70 (main, test, regtest)\n* blocks : (numeric) the current number of blocks processed in the server\n* headers : (numeric) the current number of headers we have validated\n* bestblockhash : (string) the hash of the currently best block\n* difficulty : (numeric) the current difficulty\n* verificationprogress : (numeric) estimate of verification progress [0..1]\n* chainwork : (string) total amount of work in active chain, in hexadecimal\n* pruned : (boolean) if the blocks are subject to pruning\n* pruneheight : (numeric) heighest block available\n* softforks : (array) status of softforks in progress\n\n####Query UTXO set\n`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`\n\nThe getutxo command allows querying of the UTXO set given a set of outpoints.\n\nExample:\n```\n$ curl localhost:9924/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff7627ff72e5e8b0f71210f92ea7a4000c5d75-0.json 2>/dev/null | json_pp\n{\n   \"chaintipHash\" : \"00000000fb01a7f3745a717f8caebee056c484e6e0bfe4a9591c235bb70506fb\",\n   \"chainHeight\" : 325347,\n   \"utxos\" : [\n      {\n         \"scriptPubKey\" : {\n            \"addresses\" : [\n               \"mi7as51dvLJsizWnTMurtRmrP8hG2m1XvD\"\n            ],\n            \"type\" : \"pubkeyhash\",\n            \"hex\" : \"76a9141c7cebb529b86a04c683dfa87be49de35bcf589e88ac\",\n            \"reqSigs\" : 1,\n            \"asm\" : \"OP_DUP OP_HASH160 1c7cebb529b86a04c683dfa87be49de35bcf589e OP_EQUALVERIFY OP_CHECKSIG\"\n         },\n         \"value\" : 8.8687,\n         \"height\" : 2147483647,\n         \"txvers\" : 1\n      }\n   ],\n   \"bitmap\" : \"1\"\n}\n```\n\n####Memory pool\n`GET /rest/mempool/info.json`\n\nReturns various information about the TX mempool.\nOnly supports JSON as output format.\n* size : (numeric) the number of transactions in the TX mempool\n* bytes : (numeric) size of the TX mempool in bytes\n* usage : (numeric) total TX mempool memory usage\n\n`GET /rest/mempool/contents.json`\n\nReturns transactions in the TX mempool.\nOnly supports JSON as output format.\n\nRisks\n-------------\nRunning a web browser on the same node with a REST enabled Munt-daemon can be a risk. Accessing prepared XSS websites could read out tx/block data of your node by placing links like `<script src=\"http://127.0.0.1:9232/rest/tx/1234567890.json\">` which might break the nodes privacy.\n"
  },
  {
    "path": "doc/benchmarking.md",
    "content": "Benchmarking\n============\n\nMunt Core has an internal benchmarking framework, with benchmarks\nfor cryptographic algorithms such as SHA1, SHA256, SHA512 and RIPEMD160. As well as the rolling bloom filter.\n\nAfter compiling munt-core, the benchmarks can be run with:\n`src/bench/bench_munt`\n\nThe output will look similar to:\n```\n#Benchmark,count,min,max,average\nRIPEMD160,448,0.001245033173334,0.002638196945190,0.002461894814457\nRollingBloom-refresh,1,0.000635000000000,0.000635000000000,0.000635000000000\nRollingBloom-refresh,1,0.000108000000000,0.000108000000000,0.000108000000000\nRollingBloom-refresh,1,0.000107000000000,0.000107000000000,0.000107000000000\nRollingBloom-refresh,1,0.000204000000000,0.000204000000000,0.000204000000000\nSHA1,640,0.000909024336207,0.001938136418660,0.001843086257577\nSHA256,256,0.002209486499909,0.008500099182129,0.004300644621253\nSHA512,384,0.001319904176016,0.002813005447388,0.002615700786312\nSleep100ms,10,0.205592155456543,0.210056066513062,0.104166316986084\nTrig,67108864,0.000000014997003,0.000000015448112,0.000000015188842\n```\n\nMore benchmarks are needed for, in no particular order:\n- Script Validation\n- CCoinDBView caching\n- Coins database\n- Memory pool\n- Wallet coin selection\n"
  },
  {
    "path": "doc/building.md",
    "content": "Note\n-----\n\nPlease note that in order to achieve quality and consistency Munt is written to modern software standards, this means that we use the latest languages (C++17) and recent libraries (boost) which may not be present on older distributions.\n\nIn order to build Munt you will therefore require a recent compiler (GCC 7.2 or newer) and recent libraries which means you should either use a recent distro or manually install these.\n\nThese instructions do not deal with this, however we will provide distro specific instructions in future to assist with this.\n\nPlease read all the below instructions before attempting to build the software or asking for assistance with building the software.\n\nBinaries\n-----\nThere are binaries for every release, please reconsider your need to build and unless you have a very good reason to do so rather just download these.\nLatest binaries can always be found here: https://github.com/muntorg/munt-official/releases\nDownload the latest linux*.tar.gz extract it and simply copy Munt-daemon out of it instead of going through the unnecessary hassle of building.\n\nGeneric docker instructions\n-----\n\nWhen to use docker for your builds:\n* You are on an older distribution\n* You want to build with minimal manual fuss and with minimal distruption/changes to your operating system\n\nThe easiest way to build Munt on any distribution with minimal work is to simply use the docker build script.\nInstructions:\n* Follow distro specific steps to install docker (e.g. `apt-get install docker.io && systemctl start docker`)\n* Run the docker build script from the root of this repo `./developer-tools/build_docker.sh`\n* Resulting binaries will be output inside the `build` directory\n\n\nPlatform specific instructions\n-----\n\nThe platform specific instructions attempt to minimise compiling by using native system packages where possible. Note that installing these packages may have unintended consequences for other packages on your system; It is your responsibility to  understand package management and your system. If you cannot deal with the possibility of such side effects it is better to follow the guix instructions.\n\n|Platform|Version|\n|:-----------|:---------|\n|Windows|[10](building_windows.md)|\n|Ubuntu|[14.04.5](https://gist.github.com/mjmacleod/31ad31386fcb421a7ba04948e83ace76#file-ubuntu_14-04-5-txt)|\n|Ubuntu|[16.04.4](https://gist.github.com/mjmacleod/a3562af661661ce6206e5950e406ff9d#file-ubuntu_16-04-4-txt)|\n|Ubuntu|[18.04](https://gist.github.com/mjmacleod/c5be3d05d213317b7ae4cbc50324d5ee#file-ubuntu_18-04-txt)|\n\n\nGeneric instructions\n-----\n\n\nMunt is autotools based, and has a dependency management system capable of building all libraries it requires.\n\nTo build Munt-daemon from this repository please follow these steps which are valid for Ubuntu and Debian but can easily be modified for any distribution:\n* sudo apt-get install curl build-essential libtool autotools-dev autoconf pkg-config libssl-dev\n* ./autogen.sh\n* cd depends\n* make NO_QT=1 NO_UPNP=1\n* cd ..\n* mkdir build && cd build\n* ../configure --prefix=$PWD/../depends/x86_64-pc-linux-gnu/\n* make -j$(nproc)\n\nTo build the full UI version of Munt:\n* sudo apt-get install curl build-essential libtool autotools-dev autoconf pkg-config libssl-dev libpcre++-dev\n* ./autogen.sh  \n* cd depends  \n* make\n* cd ..\n* mkdir build && cd build\n* ../configure --prefix=$PWD/../depends/x86_64-pc-linux-gnu/\n* make -j$(nproc)\n\nNote that it may take a while to build all the dependencies.\nNote if you are using a shell other than bash or your system doesn't have the `nproc` command you will need to manually substitute a number (e.g. 4 for a 4 core cpu) for `$(nproc)` instead.\n\n\n\nDetails for advanced builders\n-----\n\nIf you wish to attempt to use existing dependencies in your distribution instead of using the depends system please note the following.\n\nPrerequisites for building:\n> &gt;=g++-7 pkg-config autoconf libtool automake gperf bison flex\n\nRequired dependencies:\n> &gt;=bdb-4.8.30 &gt;=boost-1_66_0 expat-2 openssl miniupnpc protobuf zeromq\n\nOptional dependencies (depending on configure - e.g. qt only for GUI builds):\n> dbus fontconfig freetype icu libevent libX11 libXau libxcb libXext libXrender libpcre qrencode &gt;=qt-5.6.1 renderproto xcb_proto xextproto xproto xtrans\n\n\n\nguix instructions\n-----\n\nWhen to use guix for your builds:\n* You want to do reproducible builds like the official builds the developers do\n\nInstructions:\n* Install guix\n* Decide which host you want to target (e.g. `x86_64-linux-gnu`)\n* `HOSTS=\"x86_64-linux-gnu\" ./contrib/guix/guix_build`\n\nFor more detailed instructions see contrib/guix/README.md\n\n\nMuntCore framework for iOS\n-----\n\nPrerequisites:\n\n* Xcode 10\n* [Java JDK](https://www.oracle.com/technetwork/java/javase/downloads/index.html), needed by Djinni to generate the ObjC - C++ bridging code.\n* [Homebrew](https://brew.sh) to install required build tools\n\nIn Xcode preferences select the Xcode Command Line Tools.\n\nUse Homebrew to install build tools:\n\n> brew install cmake autoconf automake libtool pkgconfig\n\nBuild the framework library:\n\n> ./developer-tools/mobile/ios/build_ios_core.sh\n\n\nMuntCore framework for android\n-----\n\nFetch build prerequisites:\n* `./developer-tools/mobile/android/fetch_android.sh`\n\nBuild the framework library:\n* `./developer-tools/mobile/android/build_android_core.sh`\n\n\n\n\nTroubleshooting\n-----\n\nIf your distro is missing Berkley DB 4.8 (error: Found Berkeley DB other than 4.8, required for portable wallets)\nEither compile your own BDB, or configure with an incompatible bdb (Your wallet may not be portable to machines using older versions in this case):\n> ./configure --with-incompatible-bdb <otherconfigureflagshere>\n\nBinaries are output as follows by the build process:\n\n|Binary|Location|\n|:-----------|:---------|\n|Qt wallet|build/src/qt/Munt|\n|Munt Daemon/RPC server|build/src/Munt-daemon|\n|Munt RPC client|build/src/Munt-cli|\n|Munt tx utility|build/src/Munt-tx|\n"
  },
  {
    "path": "doc/building_windows.md",
    "content": "Note\n-----\n\nFor development the easiest way to get a working native windows build on a windows host is to use msys2, see instructions below.\n\nIf you are not planning to develop but only run the software you may find using WSL slightly easier or faster, the instructions below detail how to do this. However note the result is not a properly native binary but one that runs through the WSL 'emulation' layer.\n\nIt is also possible to cross compile for windows from a linux machine; this is how the official builds are done, see [regular build instructions](building.md) which can easily be altered to use a cross compiler.\n\nIt should also be possible to compile via msys or cygwin on windows, there are currently no detailed instructions for this, if you attempt this please consider contributing instructions so that others may benefit from your experience.\n\nBinaries\n-----\nThere are binaries for every release, please reconsider your need to build and unless you have a very good reason to do so rather just download these.\nLatest binaries can always be found here: https://github.com/Munt/munt-official/releases\nDownload the latest linux\\*.tar.gz extract it and simply copy Munt-daemon out of it instead of going through the unnecessary hassle of building.\n\n\nInstallation of msys2\n-----\n* Download and run the 64 bit msys installer - www.msys2.org\n* Open the *MSYS2 MinGW 64-bit* console (also called *Mingw-w64 64 bit* in the Mintty launcher)\n* `pacman -Syu`\n* Close and restart the console\n* `pacman -Su`\n* `pacman -S --noconfirm mingw-w64-i686-toolchain mingw-w64-i686-python2 git make patch tar autoconf automake libtool pkg-config mingw-w64-x86_64-gcc`\n\nBuilding under msys2 (nodejs addon)\n-----\n* `git clone https://github.com/muntorg/munt-official`\n* `cd munt-official`\n* `./developer-tools/build_node.sh`\n\nBuilding under msys2\n-----\n* `git clone https://github.com/muntorg/munt-official`\n* `cd munt-official/depends`\n* `make`\n* `cd ..`\n* `./autogen.sh`\n* `mkdir buildwin`\n* `cd buildwin`\n* `CONFIG_SITE=\"$PWD/../depends/i686-pc-mingw32/share/config.site\" CXXFLAGS=\"-I$PWD/../depends/i686-pc-mingw32/include -DZMQ_STATIC\" LDFLAGS=\"-L$PWD/../depends/i686-pc-mingw32/lib\" ../configure --prefix=$PWD/../depends/i686-pc-mingw32 --with-protoc-bindir=$PWD/../depends/i686-pc-mingw32/native/bin`\n* `make`\n\n\nInstallation of WSL\n-----\n\nFirst install the Windows Subsystem for Linux by opening PowerShell as Administrator and run:\n\n`Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux`\n\nRestart computer when prompted and then install Ubuntu from the following link\n\n`https://www.microsoft.com/store/p/ubuntu/9nblggh4msv6`\n\nUpdate and upgrade ubuntu within WSL\n\n`sudo apt update && sudo apt upgrade`\n\nInstall build prerequisites, git and some build dependencies\n\n`sudo apt-get install curl build-essential libtool autotools-dev autoconf pkg-config libssl-dev libpcre++-dev git`\n\nClone a copy of this repository\n\n`git clone https://github.com/muntorg/munt-official.git`\n\n`cd munt-official`\n\n(Optional) If you want to contribute towards development you may want to check out a development branch\n\n`git checkout -b 2.1_development remotes/origin/2.1_development`\n\nBuild Munt dependencies\n\n`cd depends`\n\n`sudo make`\n\n`cd ..`\n\nBuild Munt\n\n`./autogen.sh`\n\n`mkdir build && cd build`\n\n`../configure --prefix=$PWD/../depends/x86_64-pc-linux-gnu/`\n\n`make -j$(nproc)`\n\n\nRunning the compiled software\n-----\n\nIf you want to run the GUI software after compiling it in WSL then some additional steps are necessary, otherwise you will receive the error \"QXcbConnection: Could not connect to display\".\nThis is not necessary for the command line versions of the software.\nSee this guide for more information: https://virtualizationreview.com/articles/2017/02/08/graphical-programs-on-windows-subsystem-on-linux.aspx?m=1\n\nRemove minimal openssh package and replace with the full package\n\n`sudo apt-get remove openssh-server`\n\n`sudo apt-get install openssh-server`\n\nChange WSL SSH port so th at it doesn't conflict with existing windows SSH server; alternatively you can disable the windows one.\n\n`sudo nano /etc/ssh/sshd_config`\n\nPerform the following lines to the file and then save your changes.\n\nAdd:\n\n  ` AllowUsers yourusername`\n\n  ` UsePrivilegeSeparation no`\n\nChange:\n\n  ` PermitRootLogin no`\n\n  ` PasswordAuthentication yes`\n\n  ` ListenAddress 0.0.0.0`\n\n  ` Port 2200`\n\n Restart ssh service\n\n`sudo service ssh --full-restart`\n\nInstall vcXsrv on windows host; Other alternatives like Xming may also be possible\n\n`https://sourceforge.net/projects/vcxsrv/`\n\nAfter installing vcXsrv. Start XLaunch (with default settings) and then on WSL execute:\n\n`export DISPLAY=:0`\n\n`LD_LIBRARY_PATH=depends/x86_64-pc-linux-gnu/lib/ ./src/qt/Munt`\n\nModify the `LD_LIBRARY_PATH` as appropriate for your system.\n\n\nTroubleshooting\n-----\n\nI receive an error \"QXcbConnection: Could not connect to display\" when attempting to run the compiled software\n> Follow the steps \"Running the compiled software\" \n\n"
  },
  {
    "path": "doc/developer-notes.md",
    "content": "Developer Notes\n===============\n\nView [the developer guidelines](./developer-guidelines.md) for basic coding standards and suggestions.\n\nDoxygen comments\n-----------------\n\nTo facilitate the generation of documentation, use doxygen-compatible comment blocks for functions, methods and fields.\n\nFor example, to describe a function use:\n```c++\n/**\n * ... text ...\n * @param[in] arg1    A description\n * @param[in] arg2    Another argument description\n * @pre Precondition for function...\n */\nbool function(int arg1, const char *arg2)\n```\nA complete list of `@xxx` commands can be found at http://www.stack.nl/~dimitri/doxygen/manual/commands.html.\nAs Doxygen recognizes the comments by the delimiters (`/**` and `*/` in this case), you don't\n*need* to provide any commands for a comment to be valid; just a description text is fine.\n\nTo describe a class use the same construct above the class definition:\n```c++\n/**\n * Alerts are for notifying old versions if they become too obsolete and\n * need to upgrade. The message is displayed in the status bar.\n * @see GetWarnings()\n */\nclass CAlert\n{\n```\n\nTo describe a member or variable use:\n```c++\nint var; //!< Detailed description after the member\n```\n\nor\n```cpp\n//! Description before the member\nint var;\n```\n\nAlso OK:\n```c++\n///\n/// ... text ...\n///\nbool function2(int arg1, const char *arg2)\n```\n\nNot OK (used plenty in the current source, but not picked up):\n```c++\n//\n// ... text ...\n//\n```\n\nA full list of comment syntaxes picked up by doxygen can be found at http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html,\nbut if possible use one of the above styles.\n\nDevelopment tips and tricks\n---------------------------\n\n**compiling for debugging**\n\nRun configure with the --enable-debug option, then make. Or run configure with\nCXXFLAGS=\"-g -ggdb -O0\" or whatever debug flags you need.\n\n**debug.log**\n\nIf the code is behaving strangely, take a look in the debug.log file in the data directory;\nerror and debugging messages are written there.\n\nThe -debug=... command-line option controls debugging; running with just -debug or -debug=1 will turn\non all categories (and give you a very large debug.log file).\n\nThe Qt code routes qDebug() output to debug.log under category \"qt\": run with -debug=qt\nto see it.\n\n**testnet and regtest modes**\n\nRun with the -testnet option to run with \"play munts\" on the test network, if you\nare testing multi-machine code that needs to operate across the internet.\n\nIf you are testing something that can run on one machine, run with the -regtest option.\nIn regression test mode, blocks can be created on-demand; see test/functional/ for tests\nthat run in -regtest mode.\n\n**DEBUG_LOCKORDER**\n\nMunt Core is a multithreaded application, and deadlocks or other multithreading bugs\ncan be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure\nCXXFLAGS=\"-DDEBUG_LOCKORDER -g\") inserts run-time checks to keep track of which locks\nare held, and adds warnings to the debug.log file if inconsistencies are detected.\n\nLocking/mutex usage notes\n-------------------------\n\nThe code is multi-threaded, and uses mutexes and the\nLOCK/TRY_LOCK macros to protect data structures.\n\nDeadlocks due to inconsistent lock ordering (thread 1 locks cs_main\nand then cs_wallet, while thread 2 locks them in the opposite order:\nresult, deadlock as each waits for the other to release its lock) are\na problem. Compile with -DDEBUG_LOCKORDER to get lock order\ninconsistencies reported in the debug.log file.\n\nRe-architecting the core code so there are better-defined interfaces\nbetween the various components is a goal, with any necessary locking\ndone by the components (e.g. see the self-contained CKeyStore class\nand its cs_KeyStore lock for example).\n\nThreads\n-------\n\n- ThreadScriptCheck : Verifies block scripts.\n\n- ThreadImport : Loads blocks from blk*.dat files or bootstrap.dat.\n\n- StartNode : Starts other threads.\n\n- ThreadDNSAddressSeed : Loads addresses of peers from the DNS.\n\n- ThreadMapPort : Universal plug-and-play startup/shutdown\n\n- ThreadSocketHandler : Sends/Receives data from peers on port 9231.\n\n- ThreadOpenAddedConnections : Opens network connections to added nodes.\n\n- ThreadOpenConnections : Initiates new connections to peers.\n\n- ThreadMessageHandler : Higher-level message handling (sending and receiving).\n\n- DumpAddresses : Dumps IP addresses of nodes to peers.dat.\n\n- ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used in 500ms.\n\n- ThreadRPCServer : Remote procedure call handler, listens on port 9232 for connections and services them.\n\n- MuntMiner : Generates munts (if wallet is enabled).\n\n- Shutdown : Does an orderly shutdown of everything.\n\nIgnoring IDE/editor files\n--------------------------\n\nIn closed-source environments in which everyone uses the same IDE it is common\nto add temporary files it produces to the project-wide `.gitignore` file.\n\nHowever, in open source software such as Munt Core, where everyone uses\ntheir own editors/IDE/tools, it is less common. Only you know what files your\neditor produces and this may change from version to version. The canonical way\nto do this is thus to create your local gitignore. Add this to `~/.gitconfig`:\n\n```\n[core]\n        excludesfile = /home/.../.gitignore_global\n```\n\n(alternatively, type the command `git config --global core.excludesfile ~/.gitignore_global`\non a terminal)\n\nThen put your favourite tool's temporary filenames in that file, e.g.\n```\n# NetBeans\nnbproject/\n```\n\nAnother option is to create a per-repository excludes file `.git/info/exclude`.\nThese are not committed but apply only to one repository.\n\nIf a set of tools is used by the build system or scripts the repository (for\nexample, lcov) it is perfectly acceptable to add its files to `.gitignore`\nand commit them.\n\nDevelopment guidelines\n============================\n\nA few non-style-related recommendations for developers, as well as points to\npay attention to for reviewers of Munt Core code.\n\nGeneral Munt Core\n----------------------\n\n- New features should be exposed on RPC first, then can be made available in the GUI\n\n  - *Rationale*: RPC allows for better automatic testing. The test suite for\n    the GUI is very limited\n\n- Make sure pull requests pass Travis CI before merging\n\n  - *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing\n     on the master branch. Otherwise all new pull requests will start failing the tests, resulting in\n     confusion and mayhem\n\n  - *Explanation*: If the test suite is to be updated for a change, this has to\n    be done first\n\nWallet\n-------\n\n- Make sure that no crashes happen with run-time option `-disablewallet`.\n\n  - *Rationale*: In RPC code that conditionally uses the wallet (such as\n    `validateaddress`) it is easy to forget that global pointer `pwalletMain`\n    can be NULL. See `test/functional/disablewallet.py` for functional tests\n    exercising the API with `-disablewallet`\n\n- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set\n\n  - *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB\n\n\nThreads and synchronization\n----------------------------\n\n- Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential\n  deadlocks are introduced. As of 0.12, this is defined by default when\n  configuring with `--enable-debug`\n\n- When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of\n  the current scope, so surround the statement and the code that needs the lock\n  with braces\n\n  OK:\n\n```c++\n{\n    TRY_LOCK(cs_vNodes, lockNodes);\n    ...\n}\n```\n\n  Wrong:\n\n```c++\nTRY_LOCK(cs_vNodes, lockNodes);\n{\n    ...\n}\n```\n\nSource code organization\n--------------------------\n\n- Implementation code should go into the `.cpp` file and not the `.h`, unless necessary due to template usage or\n  when performance due to inlining is critical\n\n  - *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time\n\n- Don't import anything into the global namespace (`using namespace ...`). Use\n  fully specified types such as `std::string`.\n\n  - *Rationale*: Avoids symbol conflicts\n\nGUI\n-----\n\n- Do not display or manipulate dialogs in model code (classes `*Model`)\n\n  - *Rationale*: Model classes pass through events and data from the core, they\n    should not interact with the user. That's where View classes come in. The converse also\n    holds: try to not directly access core data structures from Views.\n\nGit and GitHub tips\n---------------------\n\n- For resolving merge/rebase conflicts, it can be useful to enable diff3 style using\n  `git config merge.conflictstyle diff3`. Instead of\n\n        <<<\n        yours\n        ===\n        theirs\n        >>>\n\n  you will see\n\n        <<<\n        yours\n        |||\n        original\n        ===\n        theirs\n        >>>\n\n  This may make it much clearer what caused the conflict. In this style, you can often just look\n  at what changed between *original* and *theirs*, and mechanically apply that to *yours* (or the other way around).\n\n- When reviewing patches which change indentation in C++ files, use `git diff -w` and `git show -w`. This makes\n  the diff algorithm ignore whitespace changes. This feature is also available on github.com, by adding `?w=1`\n  at the end of any URL which shows a diff.\n\n- When reviewing patches that change symbol names in many places, use `git diff --word-diff`. This will instead\n  of showing the patch as deleted/added *lines*, show deleted/added *words*.\n\n- When reviewing patches that move code around, try using\n  `git diff --patience commit~:old/file.cpp commit:new/file/name.cpp`, and ignoring everything except the\n  moved body of code which should show up as neither `+` or `-` lines. In case it was not a pure move, this may\n  even work when combined with the `-w` or `--word-diff` options described above.\n\n- When looking at other's pull requests, it may make sense to add the following section to your `.git/config`\n  file:\n\n        [remote \"upstream-pull\"]\n                fetch = +refs/pull/*:refs/remotes/upstream-pull/*\n                url = git@github.com:muntorg/munt-official.git\n\n  This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all`\n  or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`,\n  `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER.\n\nRPC interface guidelines\n--------------------------\n\nA few guidelines for introducing and reviewing new RPC interfaces:\n\n- Method naming: use consecutive lower-case names such as `getrawtransaction` and `submitblock`\n\n  - *Rationale*: Consistency with existing interface.\n\n- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`)\n\n  - *Rationale*: Consistency with existing interface.\n\n- Use the JSON parser for parsing, don't manually parse integers or strings from\n  arguments unless absolutely necessary.\n\n  - *Rationale*: Introduces hand-rolled string manipulation code at both the caller and callee sites,\n    which is error prone, and it is easy to get things such as escaping wrong.\n    JSON already supports nested data structures, no need to re-invent the wheel.\n\n  - *Exception*: AmountToValue can parse amounts as string. This was introduced because many JSON\n    parsers and formatters hard-code handling decimal numbers as floating point\n    values, resulting in potential loss of precision. This is unacceptable for\n    monetary values. **Always** use `AmountToValue` and `ValueToAmount` when\n    inputting or outputting monetary values. The only exceptions to this are\n    `prioritisetransaction` and `getblocktemplate` because their interface\n    is specified as-is in BIP22.\n\n- Missing arguments and 'null' should be treated the same: as default values. If there is no\n  default value, both cases should fail in the same way.\n\n  - *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments\n  are passed as 'null'.\n\n  - *Exception*: Many legacy exceptions to this exist, one of the worst ones is\n    `getbalance` which follows a completely different code path based on the\n    number of arguments. We are still in the process of cleaning these up. Do not introduce\n    new ones.\n\n- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock(\"hash\")`\n  do different things.\n\n  - *Rationale*: This is impossible to use with `Munt-cli`, and can be surprising to users.\n\n  - *Exception*: Some RPC calls can take both an `int` and `bool`, most notably when a bool was switched\n    to a multi-value, or due to other historical reasons. **Always** have false map to 0 and\n    true to 1 in this case.\n\n- Don't forget to fill in the argument names correctly in the RPC command table.\n\n  - *Rationale*: If not, the call can not be used with name-based arguments.\n\n- Set okSafeMode in the RPC command table to a sensible value: safe mode is when the\n  blockchain is regarded to be in a confused state, and the client deems it unsafe to\n  do anything irreversible such as send. Anything that just queries should be permitted.\n\n  - *Rationale*: Troubleshooting a node in safe mode is difficult if half the\n    RPCs don't work.\n\n- Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`.\n\n  - *Rationale*: `Munt-cli` and the GUI debug console use this table to determine how to\n    convert a plaintext command line to JSON. If the types don't match, the method can be unusable\n    from there.\n\n- A RPC method must either be a wallet method or a non-wallet method. Do not\n  introduce new methods such as `getinfo` and `signrawtransaction` that differ\n  in behavior based on presence of a wallet.\n\n  - *Rationale*: as well as complicating the implementation and interfering\n    with the introduction of multi-wallet, wallet and non-wallet code should be\n    separated to avoid introducing circular dependencies between code units.\n"
  },
  {
    "path": "doc/developer_guidelines.md",
    "content": "Developer Guidelines\n===============\n\nVarious coding styles have been used during the history of the codebase, and the current result is not very consistent.\nHowever, we're now trying to converge to a single style, which will be specified below as it emerges.\n\nPlease attempt to follow the guidelines where possible:\n- **Indentation and whitespace rules**\n  - Braces on new lines\n  - 4 space indentation (no tabs) for every block except namespaces.\n  - No space after function names; one space after `if`, `for` and `while`.\n  - If an `if` only has a single-statement `then`-clause, it can appear\n    on the same line as the `if`, with braces. In every other case,\n    braces are required, and the `then` and `else` clauses must appear\n    correctly indented on a new line.\n\n- **Symbol naming conventions**.\n  - Variable are lowercase with `C`amel`C`ase for word seperation\n    - Global variables have a `g_` prefix e.g. `g_`connManager\n  - Variables can have a type prefix where the author feels it aids readability but it is not required, except in the case of raw pointers where it is strongly encouraged.\n  Where a prefix is used the letter after the type specifier should be capatilised.\n    - `p`ConnManager to signify a raw pointer\n    - `n`Data to specify an integer\n  - Constant names are all uppercase, and use `_` to separate words\n  - Class names and function names start with a capital letter and use CamelCase to seperate words\n  - Method names start with a lower case letter and use CamelCase to seperate words\n  - Method arguments should prefixed with a _ to avoid shadowing class members\n\n- **Other conventions**\n  - Try to apply const correctness as much as possible.\n  - Always think about and specify size for types. i.e. prefer `int32_t` or `int64_t` to `int`; prefer `uint32_t` or `uint64_t` to `unsigned int`\n  - Variables that are intentionally unused should be marked as such using `[[maybe_unused]]` or `(unused)`\n  - Use of `auto` is encouraged in cases where it improves readability e.g. when taking an iterator from a map, but should not be abused in cases where is not necessary e.g. `auto count = 0` is not allowed.\n  - Use of `structured bindings` is highly recommended for readability e.g. `for (const auto& [uuid, account] : pactiveWallet->mapAccounts)` instead of `for (const auto& accountIter : pactiveWallet->mapAccounts)`\n\nBlock style example:\n```c++\nint g_count = 0;\n\nnamespace foo\n{\n\nint ComputeSomething()\n{\n    ++g_count;\n}\n\nclass AccountManager\n{\n    std::string name;\npublic:\n    bool doStuff(const std::string& s_, int n_, [[maybe_unused]] int d_)\n    {\n        // Comment summarising what this section of code does\n        for (int i = 0; i < n; ++i)\n        {\n            int totalSum = 0;\n            // When something fails, return early\n            if (!Something()) { return false; }\n            ...\n            if (SomethingElse(i))\n            {\n                totalSum += ComputeSomething();\n            }\n            else\n            {\n                doStuff(name, totalSum);\n            }\n        }\n\n        // Success return is usually at the end\n        return true;\n    }\n}\n}\n```\n\nGeneral C++\n-------------\n\n- Assertions should not have side-effects\n\n  - *Rationale*: Even though the source code is set to to refuse to compile\n    with assertions disabled, having side-effects in assertions is unexpected and\n    makes the code harder to understand\n\n- If you use the `.h`, you must link the `.cpp`\n\n  - *Rationale*: Include files define the interface for the code in implementation files. Including one but\n      not linking the other is confusing. Please avoid that. Moving functions from\n      the `.h` to the `.cpp` should not result in build errors\n\n- Use the RAII (Resource Acquisition Is Initialization) paradigm where possible. For example by using\n  `unique_ptr` for allocations in a function.\n\n  - *Rationale*: This avoids memory and resource leaks, and ensures exception safety\n\nC++ data structures\n--------------------\n\n- Never use the `std::map []` syntax when reading from a map, but instead use `.find()`\n\n  - *Rationale*: `[]` does an insert (of the default element) if the item doesn't\n    exist in the map yet. This has resulted in memory leaks in the past, as well as\n    race conditions (expecting read-read behavior). Using `[]` is fine for *writing* to a map\n\n- Do not compare an iterator from one data structure with an iterator of\n  another data structure (even if of the same type)\n\n  - *Rationale*: Behavior is undefined. In C++ parlor this means \"may reformat\n    the universe\", in practice this has resulted in at least one hard-to-debug crash bug\n\n- Watch out for out-of-bounds vector access. `&vch[vch.size()]` is illegal,\n  including `&vch[0]` for an empty vector. Use `vch.data()` and `vch.data() +\n  vch.size()` instead.\n\n- Vector bounds checking is only enabled in debug mode. Do not rely on it\n\n- Make sure that constructors initialize all fields. If this is skipped for a\n  good reason (i.e., optimization on the critical path), add an explicit\n  comment about this\n\n  - *Rationale*: Ensure determinism by avoiding accidental use of uninitialized\n    values. Also, static analyzers balk about this.\n\n- Use explicitly signed or unsigned `char`s, or even better `uint8_t` and\n  `int8_t`. Do not use bare `char` unless it is to pass to a third-party API.\n  This type can be signed or unsigned depending on the architecture, which can\n  lead to interoperability problems or dangerous conditions such as\n  out-of-bounds array accesses\n\n- Prefer explicit constructions over implicit ones that rely on 'magical' C++ behavior\n\n  - *Rationale*: Easier to understand what is happening, thus easier to spot mistakes, even for those\n  that are not language lawyers\n\nStrings and formatting\n------------------------\n\n- Be careful of `LogPrint` versus `LogPrintf`. `LogPrint` takes a `category` argument, `LogPrintf` does not.\n\n  - *Rationale*: Confusion of these can result in runtime exceptions due to\n    formatting mismatch, and it is easy to get wrong because of subtly similar naming\n\n- Use `std::string`, avoid C string manipulation functions\n\n  - *Rationale*: C++ string handling is marginally safer, less scope for\n    buffer overflows and surprises with `\\0` characters. Also some C string manipulations\n    tend to act differently depending on platform, or even the user locale\n\n- Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing\n\n  - *Rationale*: These functions do overflow checking, and avoid pesky locale issues\n\n- For `strprintf`, `LogPrint`, `LogPrintf` formatting characters don't need size specifiers\n\n  - *Rationale*: Munt Core uses tinyformat, which is type safe. Leave them out to avoid confusion\n"
  },
  {
    "path": "doc/files.md",
    "content": "\n* banlist.dat: stores the IPs/Subnets of banned nodes\n* munt.conf: contains configuration settings for Munt-daemon or Munt\n* munt_daemon.pid: stores the process id of Munt-daemon while running\n* blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0\n* blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8)\n* blocks/index/*; block index (LevelDB); since 0.8.0\n* chainstate/*; block chain state database (LevelDB); since 0.8.0\n* database/*: BDB database environment; only used for wallet since 0.8.0\n* db.log: wallet database log file\n* debug.log: contains debug information and general logging generated by Munt-daemon or Munt\n* fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0\n* mempool.dat: dump of the mempool's transactions; since 0.14.0.\n* peers.dat: peer IP address database (custom format); since 0.7.0\n* wallet.dat: personal wallet (BDB) with keys and transactions\n* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0\n* onion_private_key: cached Tor hidden service private key for `-listenonion`: since 0.12.0\n\nOnly used in pre-0.8.0\n---------------------\n* blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0\n* coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0\n\nOnly used before 0.8.0\n---------------------\n* blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0\n* blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0\n\nOnly used before 0.7.0\n---------------------\n* addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0\n"
  },
  {
    "path": "doc/fuzzing.md",
    "content": "Fuzz-testing Munt Core\n==========================\n\nA special test harness `test_munt_fuzzy` is provided to provide an easy\nentry point for fuzzers and the like. In this document we'll describe how to\nuse it with AFL.\n\nBuilding AFL\n-------------\n\nIt is recommended to always use the latest version of afl:\n```\nwget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz\ntar -zxvf afl-latest.tgz\ncd afl-<version>\nmake\nexport AFLPATH=$PWD\n```\n\nInstrumentation\n----------------\n\nTo build Munt Core using AFL instrumentation (this assumes that the\n`AFLPATH` was set as above):\n```\n./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++\nexport AFL_HARDEN=1\ncd src/\nmake test/test_munt_fuzzy\n```\nWe disable ccache because we don't want to pollute the ccache with instrumented\nobjects, and similarly don't want to use non-instrumented cached objects linked\nin.\n\nThe fuzzing can be sped up significantly (~200x) by using `afl-clang-fast` and\n`afl-clang-fast++` in place of `afl-gcc` and `afl-g++` when compiling. When\ncompiling using `afl-clang-fast`/`afl-clang-fast++` the resulting\n`test_munt_fuzzy` binary will be instrumented in such a way that the AFL\nfeatures \"persistent mode\" and \"deferred forkserver\" can be used. See\nhttps://github.com/mcarpenter/afl/tree/master/llvm_mode for details.\n\nPreparing fuzzing\n------------------\n\nAFL needs an input directory with examples, and an output directory where it\nwill place examples that it found. These can be anywhere in the file system,\nwe'll define environment variables to make it easy to reference them.\n\n```\nmkdir inputs\nAFLIN=$PWD/inputs\nmkdir outputs\nAFLOUT=$PWD/outputs\n```\n\nExample inputs are available from:\n\n- https://download.visucore.com/bitcoin/bitcoin_fuzzy_in.tar.xz\n- http://strateman.ninja/fuzzing.tar.xz\n\nExtract these (or other starting inputs) into the `inputs` directory before starting fuzzing.\n\nFuzzing\n--------\n\nTo start the actual fuzzing use:\n```\n$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/test_munt_fuzzy\n```\n\nYou may have to change a few kernel parameters to test optimally - `afl-fuzz`\nwill print an error and suggestion if so.\n"
  },
  {
    "path": "doc/init.md",
    "content": "Sample init scripts and service configuration for Munt-daemon\n==========================================================\n\nSample scripts and configuration files for systemd, Upstart and OpenRC\ncan be found in the contrib/init folder.\n\n    contrib/init/daemon.service:    systemd service unit configuration\n    contrib/init/daemon.openrc:     OpenRC compatible SysV style init script\n    contrib/init/daemon.openrcconf: OpenRC conf.d file\n    contrib/init/daemon.conf:       Upstart service configuration file\n    contrib/init/daemon.init:       CentOS compatible SysV style init script\n\n1. Service User\n---------------------------------\n\nAll three Linux startup configurations assume the existence of a \"munt\" user\nand group.  They must be created before attempting to use these scripts.\nThe OS X configuration assumes Munt-daemon will be set up for the current user.\n\n2. Configuration\n---------------------------------\n\nAt a bare minimum, Munt-daemon requires that the rpcpassword setting be set\nwhen running as a daemon.  If the configuration file does not exist or this\nsetting is not set, Munt-deamon will shutdown promptly after startup.\n\nThis password does not have to be remembered or typed as it is mostly used\nas a fixed token that Munt-deamon and client programs read from the configuration\nfile, however it is recommended that a strong and secure password be used\nas this password is security critical to securing the wallet should the\nwallet be enabled.\n\nIf Munt-daemon is run with the \"-server\" flag (set by default), and no rpcpassword is set,\nit will use a special cookie file for authentication. The cookie is generated with random\ncontent when the daemon starts, and deleted when it exits. Read access to this file\ncontrols who can access it through RPC.\n\nBy default the cookie is stored in the data directory, but it's location can be overridden\nwith the option '-rpccookiefile'.\n\nThis allows for running Munt-daemon without having to do any manual configuration.\n\n`conf`, `pid`, and `wallet` accept relative paths which are interpreted as\nrelative to the data directory. `wallet` *only* supports relative paths.\n\nFor an example configuration file that describes the configuration settings,\nsee `contrib/debian/examples/munt.conf`.\n\n3. Paths\n---------------------------------\n\n3a) Linux\n\nAll three configurations assume several paths that might need to be adjusted.\n\nBinary:              `/usr/bin/Munt-daemon`  \nConfiguration file:  `/etc/munt/munt.conf`  \nData directory:      `/var/lib/munt_daemon`  \nPID file:            `/var/run/munt_daemon/munt_daemon.pid` (OpenRC and Upstart) or `/var/lib/munt_daemon/munt_daemon.pid` (systemd)  \nLock file:           `/var/lock/subsys/munt_daemon` (CentOS)  \n\nThe configuration file, PID directory (if applicable) and data directory\nshould all be owned by the munt user and group.  It is advised for security\nreasons to make the configuration file and data directory only readable by the\nmunt user and group.  Access to Munt-cli and other Munt-daemon rpc clients\ncan then be controlled by group membership.\n\n4. Installing Service Configuration\n-----------------------------------\n\n4a) systemd\n\nInstalling this .service file consists of just copying it to\n/usr/lib/systemd/system directory, followed by the command\n`systemctl daemon-reload` in order to update running systemd configuration.\n\nTo test, run `systemctl start Munt-daemon` and to enable for system startup run\n`systemctl enable Munt-daemon`\n\n4b) OpenRC\n\nRename daemon.openrc to Munt-daemon and drop it in /etc/init.d.  Double\ncheck ownership and permissions and make it executable.  Test it with\n`/etc/init.d/Munt-daemon start` and configure it to run on startup with\n`rc-update add Munt-daemon`\n\n4c) Upstart (for Debian/Ubuntu based distributions)\n\nDrop daemon.conf in /etc/init.  Test by running `service Munt-daemon start`\nit will automatically start on reboot.\n\nNOTE: This script is incompatible with CentOS 5 and Amazon Linux 2014 as they\nuse old versions of Upstart and do not supply the start-stop-daemon utility.\n\n4d) CentOS\n\nCopy daemon.init to /etc/init.d/Munt-daemon. Test by running `service Munt-daemon start`.\n\nUsing this script, you can adjust the path and flags to the Munt-daemon program by\nsetting the DAEMON_BIN and DAEMON_OPTS environment variables in the file\n/etc/sysconfig/munt_daemon. You can also use the DAEMON_OPTS environment variable here.\n\n5. Auto-respawn\n-----------------------------------\n\nAuto respawning is currently only configured for Upstart and systemd.\nReasonable defaults have been chosen but YMMV.\n"
  },
  {
    "path": "doc/reduce-traffic.md",
    "content": "Reduce Traffic\n==============\n\nSome node operators need to deal with bandwidth caps imposed by their ISPs.\n\nBy default, munt-core allows up to 125 connections to different peers, 8 of\nwhich are outbound. You can therefore, have at most 117 inbound connections.\n\nThe default settings can result in relatively significant traffic consumption.\n\nWays to reduce traffic:\n\n## 1. Use `-maxuploadtarget=<MiB per day>`\n\nA major component of the traffic is caused by serving historic blocks to other nodes\nduring the initial blocks download phase (syncing up a new node).\nThis option can be specified in MiB per day and is turned off by default.\nThis is *not* a hard limit; only a threshold to minimize the outbound\ntraffic. When the limit is about to be reached, the uploaded data is cut by no\nlonger serving historic blocks (blocks older than one week).\nKeep in mind that new nodes require other nodes that are willing to serve\nhistoric blocks.\n\nWhitelisted peers will never be disconnected, although their traffic counts for\ncalculating the target.\n\n## 2. Disable \"listening\" (`-listen=0`)\n\nDisabling listening will result in fewer nodes connected (remember the maximum of 8\noutbound peers). Fewer nodes will result in less traffic usage as you are relaying\nblocks and transactions to fewer nodes.\n\n## 3. Reduce maximum connections (`-maxconnections=<num>`)\n\nReducing the maximum connected nodes to a minimum could be desirable if traffic\nlimits are tiny. Keep in mind that munt's trustless model works best if you are\nconnected to a handful of nodes.\n"
  },
  {
    "path": "doc/stack_trace_from_frozen_process.md",
    "content": "Often when there is behaviour like a frozen program it can be very situation specific. i.e. something specific to your machine/network/setup/wallet is triggering the freeze and it doesn't necessarily happen for others, or if it does its only a subset of users and the pattern of which users are/aren't affected is often difficult to determine.\nIn such a case the developers sometimes struggle to figure out why such a crash is happening without further information and no way to reproduce the crash themselves.\n\nThe most useful information in this situation is what is called a \"stack trace\" which can provide the developer with some direct insight into what may be triggering the crash.\n\nIf you are reading this it is likely because a developer has asked you for a stack trace, heres how to get one:\n\n1. DO NOT CLOSE THE FROZEN PROGRAM - KEEP IT OPEN\n2. Install `gdb` - on some platforms (linux) it may be already installed easy to install via your package manager, on others (windows) some steps are required.\n* Download and install https://www.msys2.org/\n* Run msys2 console (64 bit version)\n* Run `pacman -S mingw-w64-x86_64-gdb` to install `gdb`\n3. Fetch the debug info file from github for your arcitecture (e.g. `Munt-3.0.0-x86_64-linux-gnu-debug.tar.gz` for 64 bit linux debug info) extract and place in a folder on your harddrive\n* Note the debug file must match the version of the software you are running; make sure to download a version that matches\n4. Launch the application\n5. Determine the pid of the application\n* Windows - This can be found in `task manager` (right click on columns at the top to enable PID column; then search for Munt in the list of running tasks and take note of the PID)\n* Linux/macos - `ps aux | grep Munt` in the console/terminal, then note down the PID\n6. Run `gdb` passing it the PID e.g `gdb --pid 3956` (substitute your own PID here from step 5 here, it changes for every run of the application)\n7. Wait a bit for `gdb` to load, it will pause the application\n8. Type `info files` - at the very top there will be an \"entry point\" note this down\n```\nLocal exec file:\n        `/tmp/.mount_MuntFboNYk/usr/bin/Munt', file type elf64-x86-64.\n        Entry point: 0x55ca5940bb30\n```\n* In this example the entry point is 0x55ca5940bb30\n9. Use the path from step 3 and the `entry point` from step 8 and enter it via the `add-symbol-file` command\n* `add-symbol-file /home/developer/dbg/Munt.dbg 0x55ca5940bb30`\n11. Enter `y` to accept\n12. Run the command `thread apply all bt`\n13. Allow all output to print (push `c` if prompted to have it display it all)\n14. Copy all of the output and provide it to a developer\n\nThis will provide the developer with highly useful and actionable information with which they can proceed to look into the issue. It is recommended to also make a copy of your `debug.log` as the developer may want this as well.\nOnce you have both of these things you can proceed to close the program and restart it.\n"
  },
  {
    "path": "doc/translation_strings_policy.md",
    "content": "Translation Strings Policy\n===========================\n\nThis document provides guidelines for internationalization of the Munt Core software.\n\nHow to translate?\n------------------\n\nTo mark a message as translatable\n\n- In GUI source code (under `src/qt`): use `tr(\"...\")`\n\n- In non-GUI source code (under `src`): use `_(\"...\")`\n\nNo internationalization is used for e.g. developer scripts outside `src`.\n\nStrings to be translated\n-------------------------\n\nOn a high level, these strings are to be translated:\n\n- GUI strings, anything that appears in a dialog or window\n\n- Command-line option documentation\n\n### GUI strings\n\nAnything that appears to the user in the GUI is to be translated. This includes labels, menu items, button texts, tooltips and window titles.\nThis includes messages passed to the GUI through the UI interface through `InitMessage`, `ThreadSafeMessageBox` or `ShowProgress`.\n\n### Command-line options\n\nDocumentation for the command line options in the output of `--help` should be translated as well.\n\nMake sure that default values do not end up in the string, but use string formatting like `strprintf(_(\"Threshold for disconnecting misbehaving peers (default: %u)\"), 100)`. Putting default values in strings has led to accidental translations in the past, and forces the string to be retranslated every time the value changes.\n\nDo not translate messages that are only shown to developers, such as those that only appear when `--help-debug` is used.\n\nGeneral recommendations\n------------------------\n\n### Avoid unnecessary translation strings\n\nTry not to burden translators with translating messages that are e.g. slight variations of other messages.\nIn the GUI, avoid the use of text where an icon or symbol will do.\nMake sure that placeholder texts in forms don't end up in the list of strings to be translated (use `<string notr=\"true\">`).\n\n### Make translated strings understandable\n\nTry to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages\n\n### Do not translate internal errors\n\nDo not translate internal errors, or log messages, or messages that appear on the RPC interface. If an error is to be shown to the user,\nuse a translatable generic message, then log the detailed message to the log. E.g. \"A fatal internal error occurred, see debug.log for details\".\nThis helps troubleshooting; if the error is the same for everyone, the likelihood is increased that it can be found using a search engine.\n\n### Avoid fragments\n\nAvoid dividing up a message into fragments. Translators see every string separately, so may misunderstand the context if the messages are not self-contained.\n\n### Avoid HTML in translation strings\n\nThere have been difficulties with use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages.\nThis may sometimes be at conflict with the recommendation in the previous section.\n\n### Plurals\n\nPlurals can be complex in some languages. A quote from the gettext documentation:\n\n    In Polish we use e.g. plik (file) this way:\n    1 plik,\n    2,3,4 pliki,\n    5-21 pliko'w,\n    22-24 pliki,\n    25-31 pliko'w\n    and so on\n\nIn Qt code use tr's third argument for optional plurality. For example:\n\n    tr(\"%n hour(s)\",\"\",secs/HOUR_IN_SECONDS);\n    tr(\"%n day(s)\",\"\",secs/DAY_IN_SECONDS);\n    tr(\"%n week(s)\",\"\",secs/WEEK_IN_SECONDS);\n\nThis adds `<numerusform>`s to the respective `.ts` file, which can be translated separately depending on the language. In English, this is simply:\n\n    <message numerus=\"yes\">\n        <source>%n active connection(s) to Munt network</source>\n        <translation>\n            <numerusform>%n active connection to Munt network</numerusform>\n            <numerusform>%n active connections to Munt network</numerusform>\n        </translation>\n    </message>\n\nWhere it is possible try to avoid embedding numbers into the flow of the string at all. e.g.\n\n    WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)\n\nversus\n\n    WARNING: check your network connection, less blocks (%d) were received in the last %n hours than expected (%d).\n\nThe second example reduces the number of pluralized words that translators have to handle from three to one, at no cost to comprehensibility of the sentence.\n\n### String freezes\n\nDuring a string freeze (often before a major release), no translation strings are to be added, modified or removed.\n\nThis can be checked by executing `make translate` in the `src` directory, then verifying that `munt_en.ts` remains unchanged.\n"
  },
  {
    "path": "doc/zmq.md",
    "content": "# Block and Transaction Broadcasting with ZeroMQ\n\n[ZeroMQ](http://zeromq.org/) is a lightweight wrapper around TCP\nconnections, inter-process communication, and shared-memory,\nproviding various message-oriented semantics such as publish/subscribe,\nrequest/reply, and push/pull.\n\nThe Munt Core daemon can be configured to act as a trusted \"border\nrouter\", implementing the munt wire protocol and relay, making\nconsensus decisions, maintaining the local blockchain database,\nbroadcasting locally generated transactions into the network, and\nproviding a queryable RPC interface to interact on a polled basis for\nrequesting blockchain related data. However, there exists only a\nlimited service to notify external software of events like the arrival\nof new blocks or transactions.\n\nThe ZeroMQ facility implements a notification interface through a set\nof specific notifiers. Currently there are notifiers that publish\nblocks and transactions. This read-only facility requires only the\nconnection of a corresponding ZeroMQ subscriber port in receiving\nsoftware; it is not authenticated nor is there any two-way protocol\ninvolvement. Therefore, subscribers should validate the received data\nsince it may be out of date, incomplete or even invalid.\n\nZeroMQ sockets are self-connecting and self-healing; that is,\nconnections made between two endpoints will be automatically restored\nafter an outage, and either end may be freely started or stopped in\nany order.\n\nBecause ZeroMQ is message oriented, subscribers receive transactions\nand blocks all-at-once and do not need to implement any sort of\nbuffering or reassembly.\n\n## Prerequisites\n\nThe ZeroMQ feature in Munt Core requires ZeroMQ API version 4.x or\nnewer. Typically, it is packaged by distributions as something like\n*libzmq3-dev*. The C++ wrapper for ZeroMQ is *not* needed.\n\nIn order to run the example Python client scripts in contrib/ one must\nalso install *python3-zmq*, though this is not necessary for daemon\noperation.\n\n## Enabling\n\nBy default, the ZeroMQ feature is automatically compiled in if the\nnecessary prerequisites are found.  To disable, use --disable-zmq\nduring the *configure* step of building Munt-daemon:\n\n    $ ./configure --disable-zmq (other options)\n\nTo actually enable operation, one must set the appropriate options on\nthe command line or in the configuration file.\n\n## Usage\n\nCurrently, the following notifications are supported:\n\n    -zmqpubhashtx=address\n    -zmqpubhashblock=address\n    -zmqpubrawblock=address\n    -zmqpubrawtx=address\n\nThe socket type is PUB and the address must be a valid ZeroMQ socket\naddress. The same address can be used in more than one notification.\n\nFor instance:\n\n    $ Munt-daemon -zmqpubhashtx=tcp://127.0.0.1:28332 \\\n               -zmqpubrawtx=ipc:///tmp/munt_daemon.tx.raw\n\nEach PUB notification has a topic and body, where the header\ncorresponds to the notification type. For instance, for the\nnotification `-zmqpubhashtx` the topic is `hashtx` (no null\nterminator) and the body is the hexadecimal transaction hash (32\nbytes).\n\nThese options can also be provided in munt.conf.\n\nZeroMQ endpoint specifiers for TCP (and others) are documented in the\n[ZeroMQ API](http://api.zeromq.org/4-0:_start).\n\nClient side, then, the ZeroMQ subscriber socket must have the\nZMQ_SUBSCRIBE option set to one or either of these prefixes (for\ninstance, just `hash`); without doing so will result in no messages\narriving. Please see `contrib/zmq/zmq_sub.py` for a working example.\n\n## Remarks\n\nFrom the perspective of Munt-daemon, the ZeroMQ socket is write-only; PUB\nsockets don't even have a read function. Thus, there is no state\nintroduced into Munt-daemon directly. Furthermore, no information is\nbroadcast that wasn't already received from the public P2P network.\n\nNo authentication or authorization is done on connecting clients; it\nis assumed that the ZeroMQ port is exposed only to trusted entities,\nusing other means such as firewalling.\n\nNote that when the block chain tip changes, a reorganisation may occur\nand just the tip will be notified. It is up to the subscriber to\nretrieve the chain from the last known block to the new tip.\n\nThere are several possibilities that ZMQ notification can get lost\nduring transmission depending on the communication type your are\nusing. Munt-daemon appends an up-counting sequence number to each\nnotification which allows listeners to detect lost notifications.\n"
  },
  {
    "path": "libscriptconsensus.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: @PACKAGE_NAME@ consensus library\nDescription: Library for the Munt consensus protocol.\nVersion: @PACKAGE_VERSION@\nLibs: -L${libdir} -lscriptconsensus\nCflags: -I${includedir}\nRequires.private: libcrypto\n"
  },
  {
    "path": "mining_documentation/historical_list_of_mining_pools.md",
    "content": "\nThe below is a historical list of Scrypt mining pools that mined Gulden in the past before the switch to SIGMA CPU mining. It is kept as a convenience for block explorers and other sites that want to look at statistics of the old chain.\nMost of these identifiers were 'sluethed' out by the developers/community after inspecting the chain and doin some detective work. Block explorers can use this to prettify the information they display.\nIf you are/were a mining pool operator and not on this list submit your information to be added.\n\nActive in 2019:\n----\n\n|Suspected pool name|Website|Coinbase tag|Addresses|Confirmation URL|Contact details|\n|----|----|----|----|----|-----|\n|coinpool|www.coinpool.nl|coinpool.nl|GaB1GaCuffaJ98UFncxXfGNAzonAfRtibW|||\n|newpool.eu|www.nlgpool.nl|-|GawCYmSbj1p5VWaP7LqKPcdxUtBcKFp96G|www.nlgpool.nl/blocks/428||\n|Zpool.ca|www.zpool.ca|-|GLoGJBsw2DXtLApZo7sG4w44WTocpZGTKQ, GQqCEDHiHbBaYmNPy49XuqWa66VgtrJ3eV|||\n|guldenpool.nl|www.guldenpool.nl|-|GcpzphoLCjw9oYk8S2YNBYTQUrvBmXLBRSGcpzphoLCjw9oYk8S2YNBYTQUrvBmXLBRS, GLvKzdvd8KvHZsspM3R8zkCDvtg63QrV65, GM7yj7R8nB3HLPAzX7X4Fn9C3hCvCByVEG, GMVfyHTRhjajBuq5kCyanEtsC8NoTHTxoZ, GQScMGXzSm7tLvhiNQcYNiDSCcoRCBofdy, GZJ6jBNCdSWrtF9V2oDFt2UgcRnszXdkNF, GTRBWPqocPNNudbxgUuocN2yLuvXtSmNS6, GTumSsfv6dKUurP3va3adzWszRiUzJ6zkn, GdSra3MYCHdggWuXMvWnk3g63Lj3LRB3G7, GffxbedBp7WvyyeoytrweHhCPydryjgtXe, GX1epLF5rGmAX6asK2zerXc9jBzLrMTadp, GWaXs9uhp5zzNUbmdX35WHMimt4VJQTSMi, GaEnvhs37rGBan6zNg5Wot77J9TX6H2m1k, GJhuM5gfAqsM6qJrxHCs3RUNHpTLmrJ2QJ|||\n|hashing.com|www.hashing.com|Mined by hashing.com|Gdbw1DZyhhzD6Mi8uPLLEkKJwyYURR9NZr|||\n|Ispace.co.uk|www.ispace.co.uk|-|GcyPVRVQxC2qtCS8Nr8PERjHQgiBoNpwDC|||\n|Prohashing|www.prohashing.com|-|GfzEEgfvoE8s84ccSGqGnAUdNmYmCs1TTA, GLqaqmbiPT89S4py9tsBizweBU3etiW4Rr, GHw5BhnXzmS3j3HE5dQU6nqgFLKdemJAzo|||\n|Ipominer|www.ipominer.com|-||||\n|coinmine.pw|www.coinmine.pw|CoinMinePW||||\n|Hashnova||-|GLc6MjJaFGkBFdVAAHRoNQAsmxkotK2teB|||\n|Hash-to-coins.com|www.hash-to-coins.com|-|GaC1mBCzC8kHSHkZK3QdKTfJxWRMSNCP2X|||\n|Btc1337||-|GUNsn8xrwrjT4cDHUjMWbV9BV7QRriFyvR|||\n|Nicehash||-|GRCcdLrHKLRGGWDZ4LeJjvqfqqVwCkynbb|||\n|Multipool|www.multipool.us|Multipool.us|GQSJwbzciexTbUNxgJDQ3zS2DtzGma6sQ4, GU7KDqa2ASeErn25jNrFNQ9FGUdR4SB12h, GL9MJJzLByGQAybPkPEXiK75ZoY1ysDy5Y|||\n|Zergpool|www.zergpool.com/|zerg|GYFKKSwU2VL1NHQ98rkgoPur4v4pRACz9K|||\n|ScryptPools|www.scryptpools.net||GTPp5vjVwG5KnpnmwttQjCQZ2AVqjNYXz5|https://www.scryptpools.net/nlg/public/index.php?page=statistics&action=round&height=746267|https://discord.gg/24EksCN|\n|Blockmasters.co|www.Blockmasters.co||Gc5oUPU2UFAC6AczsGwzuPMY37g24Nx9QR|http://blockmasters.co/explorer/NLG?height=783221||\n|Moonpool.xyz|www.Moonpool.xyz||GfpAe6DVWRYjnZYzNXyqqztSwfmdXkXXY6|||\n|Mining.securepayment.cc|www.mining.securepayment.cc||GHs6q2w9khZF4aM1pzMRqQi4yooFDHqc3D|||\n|Ahashpool|www.ahashpool.com||GWw4cZoCRy4jsRujCvuRMiaQr1FbLGg4aF|||\n|Theogony|www.tpool.io|tpool.io|GgdMXU14f4v5JqEs4V5h6eNsiRh6XppWps|http://tpool.io/pool/nlg/blocks||\n|KHPOOL|hpool01.karpa.us|||nazkov@gmail.com|\n|mininghub||mininghub|GYLqFZZ3tHThPDzuRF2oir78PW97h39178||\n|luckypool|https://gulden.luckypool.org|luckypool|GRH1SKLneAzwYn7yXdKBSuuAwwsmAz9JtQ|https://gulden.luckypool.org/index.php?page=statistics&action=round&height=783000||\n|mining-dutch.nl|www.mining-dutch.nl|-|GPfnm7iRfMkbMMDFprUBgPL4pRe92sdqYF, Ga4vnMZj3Drjh7rPknCokmkBrBsELcZF4k|https://www.mining-dutch.nl/pools/gulden.php?page=statistics&action=blocks||\n|powermining|http://powermining.pw/|-|GJDNGcbaszbXn3To1Gh1c8k5Y3QkacpbHJ|||\n|gos.cx|gos.cx|gos.cx|GhB58vSocyKnM84LwCLdmGi5iqFSfZsULv|https://gos.cx/explorer/NLG||\n|blazepool.com|blazepool.com|blazepool|GKm84pj8kgQ8ecfsKiJEG2jrPsLrAzTX3z|||\n|bsod.pw|bsod.pw|bsod.solo|GREnrdSrTvs7FtahQTDPhFiHAXAJaga1WT|||\n\nAlive but inactive:\n----\n\n|Suspected pool name|Website|Coinbase tag|Addresses|Confirmation URL|Contact details|\n|----|----|----|----|----|-----|\n|Jaypool|www.159.89.239.37||||jaypool@pm.me|\n|Neogulden|www.neogulden.com|Neogulden||||\n|Aikapool|www.aikapool.com|-|GbA6dXtFZjexUrEeKpEF95Ke92UhqUSrmL|https://www.aikapool.com/nlg/index.php?page=statistics&action=blocks||\n|DEGULDENMIJN|www.deguldenmijn.eu|-|GbUoyKgsCVJejTfjX5c2EnSeJw31Bui1eZ|||\n\nUnsure:\n----\n\n|Suspected pool name|Website|Coinbase tag|Addresses|Confirmation URL|Contact details|\n|----|----|----|----|----|-----|\n|cloudminr.com|www.cloudminr.com|-|GT66iYRqaTm5tQLuAMHwbzcbGt5APpA671|||\n|Guldenhash|pool.guldenhash.com|Guldenhash||||\n|Infernopool|www.infernopool.com|Infernopool||||\n|Sharp fire||sharp_fire|GX6sAN5h1HT5AezmtsekB8PDoe29DckiXg|||\n|Suprnova.cc|www.suprnova.cc|-|GL7joZU8hKcLL3kFfH6nK1dw8avLk4vzbj|||\n|Justpools.uk|multi.justpools.uk|-|GSWVtjLHvymiJg6UXzgFupH5seUCXeeCeD|||\n|ffpool.net||-|GKCYMGMYEneWhYVfvXzPb1SEzxCsCnvwSY|||\n|MineYourCoins|www.mineyourcoins.com|-|GZXmmWUk46SNKMuydCXnhxVkpgjWupYNyu|||\n\nDeceased:\n----\n\n|Suspected pool name|Website|Coinbase tag|Addresses|Confirmation URL|Contact details|\n|----|----|----|----|----|-----|\n|Strataspool|www.strataspool.com|Strataspool|GM4U6yt8qN2J9oW73hAPYAWqtV3WCj79Hz, Gd6nHhdJJYQ26Bvj7FgcEqi5z2af6m3oKd, GfoH4AyUdQMWx7VUS2oFPvTdvq1nNarzZx|||\n|Xpool.ca|www.xpool.ca|-|GWKLfUQT4V8rKXVrPxSG3KxJNoTgYx511D|||\n|Clevermining|www.clevermining.com|CMus, CMeu||||\n|Hardcoreminers|nlg.hardcoreminers.com|-|GNDA5MZWcm4AjLtNuEmYpgH8qsxo4vrnY8, GfkimougwyiudBNVrV3ZSqt79yRpXaAMyi, GLfre4jKfLTQx414jwgFsMoMsYU3VAL4ci|||\n"
  },
  {
    "path": "share/genbuild.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2012-2022 The Centure developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nif [ $# -gt 1 ]; then\n    cd \"$2\"\nfi\nif [ $# -gt 0 ]; then\n    FILE=\"$1\"\n    shift\n    if [ -f \"$FILE\" ]; then\n        INFO=\"$(head -n 1 \"$FILE\")\"\n    fi\nelse\n    echo \"Usage: $0 <filename> <srcroot>\"\n    exit 1\nfi\n\ngit_check_in_repo() {\n    ! { git status --porcelain -uall --ignored \"$@\" 2>/dev/null || echo '??'; } | grep -q '?'\n}\n\nDESC=\"\"\nSUFFIX=\"\"\nif [ \"${MUNT_GENBUILD_NO_GIT}\" != \"1\" -a -e \"$(which git 2>/dev/null)\" -a \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" = \"true\" ] && git_check_in_repo share/genbuild.sh; then\n    # clean 'dirty' status of touched files that haven't been modified\n    git diff >/dev/null 2>/dev/null \n\n    # if latest commit is tagged and not dirty, then override using the tag name\n    RAWDESC=$(git describe --abbrev=0 2>/dev/null)\n    if [ \"$(git rev-parse HEAD)\" = \"$(git rev-list -1 $RAWDESC 2>/dev/null)\" ]; then\n        git diff-index --quiet HEAD -- && DESC=$RAWDESC\n    fi\n\n    # otherwise generate suffix from git, i.e. string like \"59887e8-dirty\"\n    SUFFIX=$(git rev-parse --short HEAD)\n    git diff-index --quiet HEAD -- || SUFFIX=\"$SUFFIX-dirty\"\nfi\n\nif [ -n \"$DESC\" ]; then\n    NEWINFO=\"#define BUILD_DESC \\\"$DESC\\\"\"\nelif [ -n \"$SUFFIX\" ]; then\n    NEWINFO=\"#define BUILD_SUFFIX $SUFFIX\"\nelse\n    NEWINFO=\"// No build information available\"\nfi\n\n# only update build.h if necessary\nif [ \"$INFO\" != \"$NEWINFO\" ]; then\n    echo \"$NEWINFO\" >\"$FILE\"\nfi\n"
  },
  {
    "path": "share/rpcauth/README.md",
    "content": "RPC Tools\n---------------------\n\n### [RPCAuth](/share/rpcauth) ###\n\n```\nusage: rpcauth.py [-h] username [password]\n\nCreate login credentials for a JSON-RPC user\n\npositional arguments:\n  username    the username for authentication\n  password    leave empty to generate a random password or specify \"-\" to\n              prompt for password\n\noptional arguments:\n  -h, --help  show this help message and exit\n  ```\n"
  },
  {
    "path": "share/rpcauth/rpcauth.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nfrom argparse import ArgumentParser\nfrom base64 import urlsafe_b64encode\nfrom getpass import getpass\nfrom os import urandom\n\nimport hmac\n\ndef generate_salt(size):\n    \"\"\"Create size byte hex salt\"\"\"\n    return urandom(size).hex()\n\ndef generate_password():\n    \"\"\"Create 32 byte b64 password\"\"\"\n    return urlsafe_b64encode(urandom(32)).decode('utf-8')\n\ndef password_to_hmac(salt, password):\n    m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256')\n    return m.hexdigest()\n\ndef main():\n    parser = ArgumentParser(description='Create login credentials for a JSON-RPC user')\n    parser.add_argument('username', help='the username for authentication')\n    parser.add_argument('password', help='leave empty to generate a random password or specify \"-\" to prompt for password', nargs='?')\n    args = parser.parse_args()\n\n    if not args.password:\n        args.password = generate_password()\n    elif args.password == '-':\n        args.password = getpass()\n\n    # Create 16 byte hex salt\n    salt = generate_salt(16)\n    password_hmac = password_to_hmac(salt, args.password)\n\n    print('String to be appended to bitcoin.conf:')\n    print('rpcauth={0}:{1}${2}'.format(args.username, salt, password_hmac))\n    print('Your password:\\n{0}'.format(args.password))\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "share/rpcuser/README.md",
    "content": "RPC Tools\n---------------------\n\n### [RPCUser](/share/rpcuser) ###\n\nCreate an RPC user login credential.\n\nUsage:\n\n    ./rpcuser.py <username>\n"
  },
  {
    "path": "share/rpcuser/rpcuser.py",
    "content": "#!/usr/bin/env python2 \n# Copyright (c) 2015-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying \n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nimport hashlib\nimport sys\nimport os\nfrom random import SystemRandom\nimport base64\nimport hmac\n\nif len(sys.argv) < 2:\n    sys.stderr.write('Please include username as an argument.\\n')\n    sys.exit(0)\n\nusername = sys.argv[1]\n\n#This uses os.urandom() underneath\ncryptogen = SystemRandom()\n\n#Create 16 byte hex salt\nsalt_sequence = [cryptogen.randrange(256) for i in range(16)]\nhexseq = list(map(hex, salt_sequence))\nsalt = \"\".join([x[2:] for x in hexseq])\n\n#Create 32 byte b64 password\npassword = base64.urlsafe_b64encode(os.urandom(32))\n\ndigestmod = hashlib.sha256\n\nif sys.version_info.major >= 3:\n    password = password.decode('utf-8')\n    digestmod = 'SHA256'\n \nm = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), digestmod)\nresult = m.hexdigest()\n\nprint(\"String to be appended to munt.conf:\")\nprint(\"rpcauth=\"+username+\":\"+salt+\"$\"+result)\nprint(\"Your password:\\n\"+password)\n"
  },
  {
    "path": "share/seeds/nodes_main.txt",
    "content": "# List of fixed seed nodes for main network\n\n# IPv4 nodes (generated using contrib/seeds/makeseeds.py)\n86.85.144.196\n178.62.195.19\n45.32.253.142\n199.247.1.84\n104.238.189\n72 149.210.165\n218 37.139.30\n50 46.101.24.230\n87.213.74.220\n84.105.1.4\n94.23.213.47\n188.165.2.147\n178.62.99.118\n178.62.193.109\n185.27.173.33\n178.62.242.105\n185.36.72.90\n71.175.81.45\n157.161.128.58\n47.17.84.135\n149.210.168.71\n197.87.210.38\n178.62.255.101\n185.27.175.55\n176.31.171.164\n185.27.175.164\n83.83.156.158\n185.27.173.34\n185.27.173.32\n70.168.53.153\n182.92.240.112\n176.9.63.136\n192.99.35.133\n5.39.69.34\n204.45.9.30\n188.166.83.134\n78.8.188.249\n188.165.82.229\n93.157.4.9\n178.62.175.202\n5.149.51.217\n84.24.235.101\n\n# Onion nodes\n"
  },
  {
    "path": "share/seeds/nodes_test.txt",
    "content": "# List of fixed seed nodes for testnet\n83.161.66.135\n87.213.74.220\n84.105.1.4\n94.23.213.47\n188.165.2.147\n178.62.99.118\n178.62.193.109\n185.27.173.33\n178.62.242.105\n185.36.72.90\n71.175.81.45\n157.161.128.58\n47.17.84.135\n149.210.168.71\n197.87.210.38\n178.62.255.101\n185.27.175.55\n176.31.171.164\n185.27.175.164\n83.83.156.158\n185.27.173.34\n185.27.173.32\n70.168.53.153\n182.92.240.112\n176.9.63.136\n192.99.35.133\n5.39.69.34\n204.45.9.30\n188.166.83.134\n78.8.188.249\n188.165.82.229\n93.157.4.9\n178.62.175.202\n5.149.51.217\n84.24.235.101\n\n# Onion nodes\n"
  },
  {
    "path": "share/setup.nsi.in",
    "content": "Name \"@PACKAGE_NAME@ (@WINDOWS_BITS@-bit)\"\n\nRequestExecutionLevel highest\nSetCompressor /SOLID lzma\n\n# General Symbol Definitions\n!define REGKEY \"SOFTWARE\\$(^Name)\"\n!define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@\n!define COMPANY \"@PACKAGE_NAME@ project\"\n!define URL @PACKAGE_URL@\n\n# MUI Symbol Definitions\n!define MUI_ICON \"@abs_top_srcdir@/share/pixmaps/icon.ico\"\n!define MUI_WELCOMEFINISHPAGE_BITMAP \"@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp\"\n!define MUI_HEADERIMAGE\n!define MUI_HEADERIMAGE_RIGHT\n!define MUI_HEADERIMAGE_BITMAP \"@abs_top_srcdir@/share/pixmaps/nsis-header.bmp\"\n!define MUI_FINISHPAGE_NOAUTOCLOSE\n!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM\n!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}\n!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup\n!define MUI_STARTMENUPAGE_DEFAULTFOLDER \"@PACKAGE_NAME@\"\n!define MUI_FINISHPAGE_RUN $INSTDIR\\@_GUI_NAME@@EXEEXT@\n!define MUI_UNICON \"@abs_top_srcdir@/share/pixmaps/icon.ico\"\n!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp\"\n!define MUI_UNFINISHPAGE_NOAUTOCLOSE\n\n# Included files\n!include Sections.nsh\n!include MUI2.nsh\n!if \"@WINDOWS_BITS@\" == \"64\"\n!include x64.nsh\n!endif\n\n# Variables\nVar StartMenuGroup\n\n# Custom font color\n!define MUI_PAGE_CUSTOMFUNCTION_PRE ChangeTitleFGColor\n\n# Installer pages\n!insertmacro MUI_PAGE_WELCOME\n!insertmacro MUI_PAGE_DIRECTORY\n!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup\n!insertmacro MUI_PAGE_INSTFILES\n!insertmacro MUI_PAGE_FINISH\n!insertmacro MUI_UNPAGE_CONFIRM\n!insertmacro MUI_UNPAGE_INSTFILES\n\n# Installer languages\n!insertmacro MUI_LANGUAGE English\n\n# Installer attributes\nOutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-${VERSION}-win@WINDOWS_BITS@-setup.exe\n!if \"@WINDOWS_BITS@\" == \"64\"\nInstallDir $PROGRAMFILES64\\Munt\n!else\nInstallDir $PROGRAMFILES\\Munt\n!endif\nCRCCheck on\nXPStyle on\nBrandingText \" \"\nShowInstDetails show\nVIProductVersion ${VERSION}.@CLIENT_VERSION_BUILD@\nVIAddVersionKey ProductName \"@PACKAGE_NAME@\"\nVIAddVersionKey ProductVersion \"${VERSION}\"\nVIAddVersionKey CompanyName \"${COMPANY}\"\nVIAddVersionKey CompanyWebsite \"${URL}\"\nVIAddVersionKey FileVersion \"${VERSION}\"\nVIAddVersionKey FileDescription \"\"\nVIAddVersionKey LegalCopyright \"\"\nInstallDirRegKey HKCU \"${REGKEY}\" Path\nShowUninstDetails show\n\nfunction ChangeTitleFGColor\n    GetDlgItem $0 $HWNDPARENT 0x40A             ; MUI2 header background\n    SetCtlColors $0 0xFFFFFF 0x111444\n\n    GetDlgItem $0 $HWNDPARENT 0x40D             ; MUI2 header title\n    SetCtlColors $0 0xFFFFFF 0x111444\n\n    GetDlgItem $0 $HWNDPARENT 0x40E             ; MUI2 header subtitle\n    SetCtlColors $0 0xFFFFFF 0x111444\nfunctionend\n\n# Installer sections\nSection -Main SEC0000\n    SetOutPath $INSTDIR\n    SetOverwrite on\n    File @abs_top_srcdir@/release/@_GUI_NAME@@EXEEXT@\n    #File @abs_top_srcdir@/release/*.dll\n    File /oname=COPYING.txt @abs_top_srcdir@/COPYING\n    File /oname=COPYING.txt @abs_top_srcdir@/COPYING_upstream\n    File /oname=COPYING.txt @abs_top_srcdir@/COPYING_munt\n    #SetOutPath $INSTDIR\\platforms\n    #File @abs_top_srcdir@/release/platforms/*\n    #SetOutPath $INSTDIR\\imageformats\n    #File @abs_top_srcdir@/release/imageformats/*\n    SetOutPath $INSTDIR\\daemon\n    File @abs_top_srcdir@/release/@_DAEMON_NAME@@EXEEXT@\n    File @abs_top_srcdir@/release/@_CLI_NAME@@EXEEXT@\n    \n    \n    SetOutPath $INSTDIR\n    WriteRegStr HKCU \"${REGKEY}\\Components\" Main 1\nSectionEnd\n\nSection -post SEC0001\n    WriteRegStr HKCU \"${REGKEY}\" Path $INSTDIR\n    SetOutPath $INSTDIR\n    WriteUninstaller $INSTDIR\\uninstall.exe\n    !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n    CreateDirectory $SMPROGRAMS\\$StartMenuGroup\n    CreateShortcut \"$SMPROGRAMS\\$StartMenuGroup\\$(^Name).lnk\" $INSTDIR\\@_GUI_NAME@@EXEEXT@\n    CreateShortcut \"$SMPROGRAMS\\$StartMenuGroup\\Uninstall $(^Name).lnk\" $INSTDIR\\uninstall.exe\n    !insertmacro MUI_STARTMENU_WRITE_END\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" DisplayName \"$(^Name)\"\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" DisplayVersion \"${VERSION}\"\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" Publisher \"${COMPANY}\"\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" URLInfoAbout \"${URL}\"\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" DisplayIcon $INSTDIR\\uninstall.exe\n    WriteRegStr HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" UninstallString $INSTDIR\\uninstall.exe\n    WriteRegDWORD HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" NoModify 1\n    WriteRegDWORD HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\" NoRepair 1\n    WriteRegStr HKCR \"@PACKAGE_TARNAME@\" \"URL Protocol\" \"\"\n    WriteRegStr HKCR \"@PACKAGE_TARNAME@\" \"\" \"URL:Munt\"\n    WriteRegStr HKCR \"@PACKAGE_TARNAME@\\DefaultIcon\" \"\" $INSTDIR\\@_GUI_NAME@@EXEEXT@\n    WriteRegStr HKCR \"@PACKAGE_TARNAME@\\shell\\open\\command\" \"\" '\"$INSTDIR\\@_GUI_NAME@@EXEEXT@\" \"%1\"'\n    WriteRegStr HKCR \"munt\" \"URL Protocol\" \"\"\n    WriteRegStr HKCR \"munt\" \"\" \"URL:Munt\"\n    WriteRegStr HKCR \"munt\\DefaultIcon\" \"\" $INSTDIR\\Munt.exe\n    WriteRegStr HKCR \"munt\\shell\\open\\command\" \"\" '\"$INSTDIR\\Munt.exe\" \"%1\"'\nSectionEnd\n\n# Macro for selecting uninstaller sections\n!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID\n    Push $R0\n    ReadRegStr $R0 HKCU \"${REGKEY}\\Components\" \"${SECTION_NAME}\"\n    StrCmp $R0 1 0 next${UNSECTION_ID}\n    !insertmacro SelectSection \"${UNSECTION_ID}\"\n    GoTo done${UNSECTION_ID}\nnext${UNSECTION_ID}:\n    !insertmacro UnselectSection \"${UNSECTION_ID}\"\ndone${UNSECTION_ID}:\n    Pop $R0\n!macroend\n\n# Uninstaller sections\nSection /o -un.Main UNSEC0000\n    Delete /REBOOTOK $INSTDIR\\@_GUI_NAME@@EXEEXT@\n    Delete /REBOOTOK $INSTDIR\\COPYING.txt\n    Delete /REBOOTOK $INSTDIR\\readme.txt\n    Delete /REBOOTOK $INSTDIR\\*.dll\n    RMDIR /r /REBOOTOK $INSTDIR\\platforms\n    RMDIR /r /REBOOTOK $INSTDIR\\imageformats\n    RMDir /r /REBOOTOK $INSTDIR\\daemon\n    RMDir /r /REBOOTOK $INSTDIR\\doc\n    DeleteRegValue HKCU \"${REGKEY}\\Components\" Main\nSectionEnd\n\nSection -un.post UNSEC0001\n    DeleteRegKey HKCU \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$(^Name)\"\n    Delete /REBOOTOK \"$SMPROGRAMS\\$StartMenuGroup\\Uninstall $(^Name).lnk\"\n    Delete /REBOOTOK \"$SMPROGRAMS\\$StartMenuGroup\\$(^Name).lnk\"\n    Delete /REBOOTOK \"$SMPROGRAMS\\$StartMenuGroup\\@PACKAGE_NAME@ (testnet, @WINDOWS_BITS@-bit).lnk\"\n    Delete /REBOOTOK \"$SMSTARTUP\\Munt.lnk\"\n    Delete /REBOOTOK $INSTDIR\\uninstall.exe\n    Delete /REBOOTOK $INSTDIR\\debug.log\n    Delete /REBOOTOK $INSTDIR\\db.log\n    DeleteRegValue HKCU \"${REGKEY}\" StartMenuGroup\n    DeleteRegValue HKCU \"${REGKEY}\" Path\n    DeleteRegKey /IfEmpty HKCU \"${REGKEY}\\Components\"\n    DeleteRegKey /IfEmpty HKCU \"${REGKEY}\"\n    DeleteRegKey HKCR \"@PACKAGE_TARNAME@\"\n    RmDir /REBOOTOK $SMPROGRAMS\\$StartMenuGroup\n    RmDir /REBOOTOK $INSTDIR\n    Push $R0\n    StrCpy $R0 $StartMenuGroup 1\n    StrCmp $R0 \">\" no_smgroup\nno_smgroup:\n    Pop $R0\nSectionEnd\n\n# Installer functions\nFunction .onInit\n    InitPluginsDir\n!if \"@WINDOWS_BITS@\" == \"64\"\n    ${If} ${RunningX64}\n      ; disable registry redirection (enable access to 64-bit portion of registry)\n      SetRegView 64\n    ${Else}\n      MessageBox MB_OK|MB_ICONSTOP \"Cannot install 64-bit version on a 32-bit system.\"\n      Abort\n    ${EndIf}\n!endif\nFunctionEnd\n\n# Uninstaller functions\nFunction un.onInit\n    ReadRegStr $INSTDIR HKCU \"${REGKEY}\" Path\n    !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup\n    !insertmacro SELECT_UNSECTION Main ${UNSEC0000}\nFunctionEnd\n"
  },
  {
    "path": "src/LRUCache/COPYING",
    "content": "/*\n * LRUCache11 - a templated C++11 based LRU cache class that allows\n * specification of\n * key, value and optionally the map container type (defaults to\n * std::unordered_map)\n * By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete\n * and\n * refresh operations.\n *\n * This is a header-only library and all you need is the LRUCache11.hpp file\n *\n * Github: https://github.com/mohaps/lrucache11\n *\n * This is a follow-up to the LRUCache project -\n * https://github.com/mohaps/lrucache\n *\n * Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n"
  },
  {
    "path": "src/LRUCache/LRUCache11.hpp",
    "content": "/*\n * LRUCache11 - a templated C++11 based LRU cache class that allows\n * specification of\n * key, value and optionally the map container type (defaults to\n * std::unordered_map)\n * By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete\n * and\n * refresh operations.\n *\n * This is a header-only library and all you need is the LRUCache11.hpp file\n *\n * Github: https://github.com/mohaps/lrucache11\n *\n * This is a follow-up to the LRUCache project -\n * https://github.com/mohaps/lrucache\n *\n * Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n#pragma once\n#include <algorithm>\n#include <cstdint>\n#include <list>\n#include <mutex>\n#include <stdexcept>\n#include <thread>\n#include <unordered_map>\n\nnamespace lru11 {\n/*\n * a noop lockable concept that can be used in place of std::mutex\n */\nclass NullLock {\n public:\n  void lock() {}\n  void unlock() {}\n  bool try_lock() { return true; }\n};\n\n/**\n * error raised when a key not in cache is passed to get()\n */\nclass KeyNotFound : public std::invalid_argument {\n public:\n  KeyNotFound() : std::invalid_argument(\"key_not_found\") {}\n};\n\ntemplate <typename K, typename V>\nstruct KeyValuePair {\n public:\n  K key;\n  V value;\n\n  KeyValuePair(const K& k, const V& v) : key(k), value(v) {}\n};\n\n/**\n *\tThe LRU Cache class templated by\n *\t\tKey - key type\n *\t\tValue - value type\n *\t\tMapType - an associative container like std::unordered_map\n *\t\tLockType - a lock type derived from the Lock class (default:\n *NullLock = no synchronization)\n *\n *\tThe default NullLock based template is not thread-safe, however passing\n *Lock=std::mutex will make it\n *\tthread-safe\n */\ntemplate <class Key, class Value, class Lock = NullLock,\n          class Map = std::unordered_map<\n              Key, typename std::list<KeyValuePair<Key, Value>>::iterator>>\nclass Cache {\n public:\n  typedef KeyValuePair<Key, Value> node_type;\n  typedef std::list<KeyValuePair<Key, Value>> list_type;\n  typedef Map map_type;\n  typedef Lock lock_type;\n  using Guard = std::lock_guard<lock_type>;\n  /**\n   * the maxSize is the soft limit of keys and (maxSize + elasticity) is the\n   * hard limit\n   * the cache is allowed to grow till (maxSize + elasticity) and is pruned back\n   * to maxSize keys\n   * set maxSize = 0 for an unbounded cache (but in that case, you're better off\n   * using a std::unordered_map\n   * directly anyway! :)\n   */\n  explicit Cache(size_t maxSize = 64, size_t elasticity = 10)\n      : maxSize_(maxSize), elasticity_(elasticity) {}\n  virtual ~Cache() = default;\n  size_t size() const {\n    Guard g(lock_);\n    return cache_.size();\n  }\n  bool empty() const {\n    Guard g(lock_);\n    return cache_.empty();\n  }\n  void clear() {\n    Guard g(lock_);\n    cache_.clear();\n    keys_.clear();\n  }\n  void insert(const Key& k, const Value& v) {\n    Guard g(lock_);\n    const auto iter = cache_.find(k);\n    if (iter != cache_.end()) {\n      iter->second->value = v;\n      keys_.splice(keys_.begin(), keys_, iter->second);\n      return;\n    }\n\n    keys_.emplace_front(k, v);\n    cache_[k] = keys_.begin();\n    prune();\n  }\n  bool tryGet(const Key& kIn, Value& vOut) {\n    Guard g(lock_);\n    const auto iter = cache_.find(kIn);\n    if (iter == cache_.end()) {\n      return false;\n    }\n    keys_.splice(keys_.begin(), keys_, iter->second);\n    vOut = iter->second->value;\n    return true;\n  }\n  /**\n   *\tThe const reference returned here is only\n   *    guaranteed to be valid till the next insert/delete\n   */\n  const Value& get(const Key& k) {\n    Guard g(lock_);\n    const auto iter = cache_.find(k);\n    if (iter == cache_.end()) {\n      throw KeyNotFound();\n    }\n    keys_.splice(keys_.begin(), keys_, iter->second);\n    return iter->second->value;\n  }\n  /**\n   * returns a copy of the stored object (if found)\n   */\n  Value getCopy(const Key& k) {\n   return get(k);\n  }\n  bool remove(const Key& k) {\n    Guard g(lock_);\n    auto iter = cache_.find(k);\n    if (iter == cache_.end()) {\n      return false;\n    }\n    keys_.erase(iter->second);\n    cache_.erase(iter);\n    return true;\n  }\n  bool contains(const Key& k) const {\n    Guard g(lock_);\n    return cache_.find(k) != cache_.end();\n  }\n\n  size_t getMaxSize() const { return maxSize_; }\n  size_t getElasticity() const { return elasticity_; }\n  size_t getMaxAllowedSize() const { return maxSize_ + elasticity_; }\n  template <typename F>\n  void cwalk(F& f) const {\n    Guard g(lock_);\n    std::for_each(keys_.begin(), keys_.end(), f);\n  }\n\n protected:\n  size_t prune() {\n    size_t maxAllowed = maxSize_ + elasticity_;\n    if (maxSize_ == 0 || cache_.size() < maxAllowed) {\n      return 0;\n    }\n    size_t count = 0;\n    while (cache_.size() > maxSize_) {\n      cache_.erase(keys_.back().key);\n      keys_.pop_back();\n      ++count;\n    }\n    return count;\n  }\n\n private:\n  // Dissallow copying.\n  Cache(const Cache&) = delete;\n  Cache& operator=(const Cache&) = delete;\n\n  mutable Lock lock_;\n  Map cache_;\n  list_type keys_;\n  size_t maxSize_;\n  size_t elasticity_;\n};\n\n}  // namespace LRUCache11\n"
  },
  {
    "path": "src/Makefile.am",
    "content": "# Copyright (c) 2013-2016 The Bitcoin developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# File contains modifications by: The Centure developers\n# All modifications:\n# Copyright (c) 2016-2022 The Centure developers\n# Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n# Distributed under the GNU Lesser General Public License v3, see the accompanying\n# file COPYING\n\nDIST_SUBDIRS = secp256k1\n\nAM_LDFLAGS_NO_THREADS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS)\nAM_LDFLAGS = $(PTHREAD_CFLAGS) $(AM_LDFLAGS_NO_THREADS)\nAM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS)\nAM_CPPFLAGS = $(HARDENED_CPPFLAGS)\nEXTRA_LIBRARIES =\n\nCONFIG_INCLUDES=-I$(builddir)/config\nCOMMON_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) $(CRYPTOPP_CFLAGS) $(LEVELDB_CPPFLAGS)\n\nCOMMON_INCLUDES += -I$(srcdir)/secp256k1/include\nCOMMON_INCLUDES += -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)\n\nLIB_SERVER=lib_server.a\nLIB_RPC=lib_rpc.a\nLIB_NODE=lib_node.a\nLIB_COMMON=lib_common.a\nLIB_CONSENSUS=lib_consensus.a\nLIB_CLI=lib_cli.a\nLIB_UTIL=lib_util.a\nLIB_GENERIC=lib_generic.a\nLIB_GENERIC_INIT=lib_generic_init.a\nLIB_GENERIC_INIT_NODE=lib_generic_init_node.a\nLIB_CRYPTO_SSE3=crypto/lib_crypto_sse3.a\nLIB_CRYPTO_SSE3_AES=crypto/lib_crypto_sse3_aes.a\nLIB_CRYPTO_SSE4=crypto/lib_crypto_sse4.a\nLIB_CRYPTO_SSE4_SHANI=crypto/lib_crypto_sse4_shani.a\nLIB_CRYPTO_SSE4_AES=crypto/lib_crypto_sse4_aes.a\nLIB_CRYPTO_AVX=crypto/lib_crypto_avx.a\nLIB_CRYPTO_AVX_AES=crypto/lib_crypto_avx_aes.a\nLIB_CRYPTO_AVX2=crypto/lib_crypto_avx2.a\nLIB_CRYPTO_AVX2_AES=crypto/lib_crypto_avx2_aes.a\nLIB_CRYPTO_AVX512F=crypto/lib_crypto_avx512f.a\nLIB_CRYPTO_AVX512F_AES=crypto/lib_crypto_avx512f_aes.a\nLIB_CRYPTO_ARM_CORTEX_A53=crypto/lib_crypto_arm_cortex_a53.a\nLIB_CRYPTO_ARM_CORTEX_A53_AES=crypto/lib_crypto_arm_cortex_a53_aes.a\nLIB_CRYPTO_ARM_CORTEX_A57=crypto/lib_crypto_arm_cortex_a57.a\nLIB_CRYPTO_ARM_CORTEX_A57_AES=crypto/lib_crypto_arm_cortex_a57_aes.a\nLIB_CRYPTO_ARM_CORTEX_A72=crypto/lib_crypto_arm_cortex_a72.a\nLIB_CRYPTO_ARM_CORTEX_A72_AES=crypto/lib_crypto_arm_cortex_a72_aes.a\nLIB_CRYPTO_ARM_THUNDERX_AES=crypto/lib_crypto_arm_thunderx_aes.a\nLIB_CRYPTO_ARM_V8_CRYPTO=crypto/lib_crypto_arm_v8_crypto.a\nLIB_CRYPTO=crypto/lib_crypto.a\nLIBSECP256K1=secp256k1/libsecp256k1.la\n\nif ENABLE_ZMQ\nLIB_ZMQ=lib_zmq.a\nendif\nif BUILD_LIBS_NODE_JS\nLIB_UNITY_NODE_JS=lib_unity_node_js.la\nendif\nif BUILD_LIBS_JNI\nLIB_UNITY_JNI=lib_unity_jni.la\nLIB_ANDROID_COMPAT=lib_android_compat.a\nendif\nif BUILD_LIBS_OBJC\nLIB_UNITY_OBJC=lib_unity_objc.a\nendif\nif ENABLE_WALLET\nLIB_WALLET=lib_wallet.a\nendif\n\n$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)\n\t$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)\n\nLIB_CRYPTO_ARM = $(LIB_CRYPTO_ARM_CORTEX_A53) $(LIB_CRYPTO_ARM_CORTEX_A53_AES) $(LIB_CRYPTO_ARM_CORTEX_A57) $(LIB_CRYPTO_ARM_CORTEX_A57_AES) $(LIB_CRYPTO_ARM_CORTEX_A72) $(LIB_CRYPTO_ARM_CORTEX_A72_AES) $(LIB_CRYPTO_ARM_THUNDERX_AES) $(LIB_CRYPTO_ARM_V8_CRYPTO)\nLIB_CRYPTO_INTEL = $(LIB_CRYPTO_SSE3) $(LIB_CRYPTO_SSE3_AES) $(LIB_CRYPTO_SSE4) $(LIB_CRYPTO_SSE4_SHANI) $(LIB_CRYPTO_SSE4_AES) $(LIB_CRYPTO_AVX) $(LIB_CRYPTO_AVX_AES) $(LIB_CRYPTO_AVX2) $(LIB_CRYPTO_AVX2_AES) $(LIB_CRYPTO_AVX512F) $(LIB_CRYPTO_AVX512F_AES)\nLIB_CRYPTO_ALL = $(LIB_CRYPTO) $(LIB_CRYPTO_INTEL) $(LIB_CRYPTO_ARM)\n\n# Make is not made aware of per-object dependencies to avoid limiting building parallelization\n# But to build the less dependent modules first, we manually select their order here:\nEXTRA_LIBRARIES += \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIB_ANDROID_COMPAT) \\\n  $(LIB_UTIL) \\\n  $(LIB_GENERIC) \\\n  $(LIB_GENERIC_INIT) \\\n  $(LIB_GENERIC_INIT_NODE) \\\n  $(LIB_COMMON) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_SERVER) \\\n  $(LIB_RPC) \\\n  $(LIB_NODE) \\\n  $(LIB_CLI) \\\n  $(LIB_WALLET) \\\n  $(LIB_ZMQ)\n\nlib_LTLIBRARIES = $(LIB_UNITY_JNI) $(LIB_UNITY_NODE_JS)\nnoinst_LTLIBRARIES =\nnoinst_LIBRARIES =\n\nbin_PROGRAMS =\nnoinst_PROGRAMS =\nTESTS =\nBENCHMARKS =\n\nif BUILD_DAEMON\n  bin_PROGRAMS += Munt-daemon\nendif\n\nif BUILD_UTILS\n  bin_PROGRAMS += Munt-cli Munt-tx\nendif\n\n.PHONY: FORCE check-symbols check-security\n\n# core #\nCORE_H = rpc/accounts.h \\\n  pow/diff.h \\\n  pow/diff_delta.h \\\n  pow/diff_old.h \\\n  pow/diff_common.h \\\n  crypto/hash/hash.h \\\n  crypto/hash/city.h \\\n  crypto/hash/cityconfig.h \\\n  wallet/mnemonic.h \\\n  witnessutil.h \\\n  wallet/extwallet.h \\\n  LRUCache/LRUCache11.hpp \\\n  alert.h \\\n  wallet/account.h \\\n  addrdb.h \\\n  addrman.h \\\n  base58.h \\\n  bloom.h \\\n  blockencodings.h \\\n  blockstore.h \\\n  chain.h \\\n  chainparams.h \\\n  chainparamsbase.h \\\n  chainparamsseeds.h \\\n  checkpoints.h \\\n  checkqueue.h \\\n  clientversion.h \\\n  appname.h \\\n  coins.h \\\n  compat.h \\\n  compat/arch.h \\\n  compat/cpuid.h \\\n  compat/sys.h \\\n  compat/sse.h \\\n  compat/sse2neon.h \\\n  compat/byteswap.h \\\n  compat/endian.h \\\n  compat/sanity.h \\\n  compat/assumptions.h \\\n  compressor.h \\\n  blockfilter.h \\\n  consensus/consensus.h \\\n  consensus/tx_verify.h \\\n  core_io.h \\\n  core_memusage.h \\\n  cuckoocache.h \\\n  fs.h \\\n  httprpc.h \\\n  httpserver.h \\\n  indirectmap.h \\\n  init.h \\\n  node/context.h \\\n  unity/appmanager.h \\\n  unity/signals.h \\\n  key.h \\\n  keystore.h \\\n  dbwrapper.h \\\n  limitedmap.h \\\n  memusage.h \\\n  merkleblock.h \\\n  generation/miner.h \\\n  generation/witness.h \\\n  generation/generation.h \\\n  generation/witnessrewardtemplate.h \\\n  net.h \\\n  net_processing.h \\\n  netaddress.h \\\n  netbase.h \\\n  netmessagemaker.h \\\n  noui.h \\\n  policy/feerate.h \\\n  policy/fees.h \\\n  policy/policy.h \\\n  policy/rbf.h \\\n  pow/pow.h \\\n  protocol.h \\\n  random.h \\\n  randomenv.h \\\n  reverselock.h \\\n  reverse_iterator.h \\\n  rpc/blockchain.h \\\n  rpc/client.h \\\n  rpc/protocol.h \\\n  rpc/server.h \\\n  rpc/register.h \\\n  scheduler.h \\\n  script/sigcache.h \\\n  script/sign.h \\\n  script/standard.h \\\n  script/ismine.h \\\n  span.h \\\n  streams.h \\\n  support/allocators/secure.h \\\n  support/allocators/zeroafterfree.h \\\n  support/cleanse.h \\\n  support/events.h \\\n  support/lockedpool.h \\\n  sync.h \\\n  util/thread.h \\\n  threadsafety.h \\\n  threadinterrupt.h \\\n  timedata.h \\\n  torcontrol.h \\\n  txdb.h \\\n  txmempool.h \\\n  ui_interface.h \\\n  undo.h \\\n  logging.h \\\n  util.h \\\n  util/time.h \\\n  util/check.h \\\n  util/macros.h \\\n  util/overloaded.h \\\n  util/syscall_sandbox.h \\\n  util/threadnames.h \\\n  util/getuniquepath.h \\\n  attributes.h \\\n  util/moneystr.h \\\n  util/strencodings.h \\\n  validation/validation.h \\\n  validation/witnessvalidation.h \\\n  validation/versionbitsvalidation.h \\\n  validation/validationinterface.h \\\n  versionbits.h \\\n  wallet/coincontrol.h \\\n  wallet/crypter.h \\\n  wallet/db.h \\\n  wallet/feebumper.h \\\n  wallet/rpcwallet.h \\\n  wallet/spvscanner.h \\\n  wallet/wallet.h \\\n  wallet/merkletx.h \\\n  wallet/wallettx.h \\\n  wallet/walletdb.h \\\n  wallet/walletdberrors.h \\\n  wallet/witness_operations.h \\\n  warnings.h \\\n  zmq/zmqabstractnotifier.h \\\n  zmq/zmqconfig.h\\\n  zmq/zmqnotificationinterface.h \\\n  zmq/zmqpublishnotifier.h\n\n\nobj/build.h: FORCE\n\t@$(MKDIR_P) $(builddir)/obj\n\t@$(top_srcdir)/share/genbuild.sh \"$(abs_top_builddir)/src/obj/build.h\" \\\n\t  \"$(abs_top_srcdir)\"\n\nclientversion.cpp: obj/build.h\n\n# RPC: Daemon and GUI/libs\nlib_rpc_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)\nlib_rpc_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_rpc_a_SOURCES = \\\n  rpc/accounts.cpp \\\n  rpc/blockchain.cpp \\\n  rpc/mining.cpp \\\n  rpc/misc.cpp \\\n  rpc/netrpc.cpp \\\n  rpc/rawtransaction.cpp \\\n  rpc/protocol.cpp \\\n  rpc/server.cpp \\\n  rpc/client.cpp \\\n  $(CORE_H)\n\nif ENABLE_WALLET\nlib_rpc_a_SOURCES += \\\n  wallet/rpcdump.cpp \\\n  wallet/rpcwallet.cpp\nendif\n\n# server: shared between Daemon and GUI client\nlib_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)\nlib_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_server_a_SOURCES = \\\n  httprpc.cpp \\\n  httpserver.cpp \\\n  rest.cpp \\\n  torcontrol.cpp \\\n  $(CORE_H)\n\n# node: shared between Daemon, GUI client and unity libraries.\nlib_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)\nlib_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_node_a_SOURCES = \\\n  addrdb.cpp \\\n  addrman.cpp \\\n  alert.cpp \\\n  bloom.cpp \\\n  blockencodings.cpp \\\n  blockstore.cpp \\\n  chain.cpp \\\n  checkpoints.cpp \\\n  consensus/tx_verify.cpp \\\n  init.cpp \\\n  dbwrapper.cpp \\\n  merkleblock.cpp \\\n  generation/miner.cpp \\\n  generation/witness.cpp \\\n  generation/witnessrewardtemplate.cpp \\\n  net.cpp \\\n  net_processing.cpp \\\n  noui.cpp \\\n  policy/feerate.cpp \\\n  policy/fees.cpp \\\n  policy/policy.cpp \\\n  policy/rbf.cpp \\\n  txdb.cpp \\\n  txmempool.cpp \\\n  witnessutil.cpp \\\n  ui_interface.cpp \\\n  validation/validation.cpp \\\n  validation/validation_mempool.cpp \\\n  validation/validation_misc.cpp \\\n  validation/witnessvalidation.cpp \\\n  validation/versionbitsvalidation.cpp \\\n  validation/validationinterface.cpp \\\n  versionbits.cpp \\\n  warnings.cpp \\\n  script/sigcache.cpp \\\n  script/ismine.cpp \\\n  timedata.cpp \\\n  pow/pow.cpp \\\n  $(CORE_H)\n\n# zmq: shared between Daemon and GUI client, only if zmq enabled\nif ENABLE_ZMQ\nlib_zmq_a_CPPFLAGS = $(COMMON_INCLUDES) $(ZMQ_CFLAGS)\nlib_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_zmq_a_SOURCES = \\\n  zmq/zmqabstractnotifier.cpp \\\n  zmq/zmqnotificationinterface.cpp \\\n  zmq/zmqpublishnotifier.cpp\nendif\n\n\n# wallet: shared between Daemon, GUI client and unity libraries but only linked when wallet enabled\nlib_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_wallet_a_SOURCES = \\\n  wallet/account.cpp \\\n  wallet/mnemonic.cpp \\\n  wallet/extwallet.cpp \\\n  wallet/crypter.cpp \\\n  wallet/db.cpp \\\n  wallet/feebumper.cpp \\\n  wallet/spvscanner.cpp \\\n  wallet/wallet.cpp \\\n  wallet/wallet_ismine.cpp \\\n  wallet/wallet_init.cpp \\\n  wallet/wallet_transaction.cpp \\\n  wallet/wallet_keypool.cpp \\\n  wallet/walletbalance.cpp \\\n  wallet/merkletx.cpp \\\n  wallet/wallettx.cpp \\\n  wallet/walletdb.cpp \\\n  wallet/witness_operations.cpp \\\n  $(CORE_H)\n\n# crypto primitives library: Shared between all binaries and unity libraries\ncrypto_lib_crypto_sse3_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_SSE3_FLAGS)\ncrypto_lib_crypto_sse3_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_SSE3_FLAGS)\ncrypto_lib_crypto_sse3_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse3.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse3.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse3.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse3.cpp\n\ncrypto_lib_crypto_sse3_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_SSE3_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_sse3_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_SSE3_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_sse3_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse3_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse3_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse3_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse3_aes.cpp\n\ncrypto_lib_crypto_sse4_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_SSE4_FLAGS)\ncrypto_lib_crypto_sse4_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_SSE4_FLAGS)\ncrypto_lib_crypto_sse4_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse4.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse4.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse4.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse4.cpp \\\n  crypto/sha256_sse4.cpp\n\ncrypto_lib_crypto_sse4_shani_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_SSE4_SHANI_FLAGS)\ncrypto_lib_crypto_sse4_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_SSE4_SHANI_FLAGS)\ncrypto_lib_crypto_sse4_shani_a_SOURCES = \\\n  crypto/sha256_x86_shani.cpp\n\ncrypto_lib_crypto_sse4_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_SSE4_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_sse4_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_SSE4_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_sse4_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse4_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_sse4_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse4_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_sse4_aes.cpp\n\ncrypto_lib_crypto_avx_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX_FLAGS)\ncrypto_lib_crypto_avx_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX_FLAGS)\ncrypto_lib_crypto_avx_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx.cpp\n\n\ncrypto_lib_crypto_avx_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx_aes.cpp\n\n\ncrypto_lib_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX2_FLAGS)\ncrypto_lib_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX2_FLAGS)\ncrypto_lib_crypto_avx2_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx2.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx2.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx2.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx2.cpp\n\ncrypto_lib_crypto_avx2_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX2_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx2_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX2_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx2_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx2_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx2_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx2_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx2_aes.cpp\n\ncrypto_lib_crypto_avx512f_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX512F_FLAGS)\ncrypto_lib_crypto_avx512f_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX512F_FLAGS)\ncrypto_lib_crypto_avx512f_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx512f.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx512f.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx512f.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx512f.cpp\n\ncrypto_lib_crypto_avx512f_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_AVX512F_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx512f_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_AVX512F_FLAGS) $(PLATFORM_INTRINSICS_AES_FLAGS)\ncrypto_lib_crypto_avx512f_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx512f_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_avx512f_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx512f_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_avx512f_aes.cpp\n\ncrypto_lib_crypto_arm_cortex_a53_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX53_FLAGS)\ncrypto_lib_crypto_arm_cortex_a53_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX53_FLAGS)\ncrypto_lib_crypto_arm_cortex_a53_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53.cpp\n\ncrypto_lib_crypto_arm_cortex_a53_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX53_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a53_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX53_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a53_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53_aes.cpp\n  \ncrypto_lib_crypto_arm_cortex_a57_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX57_FLAGS)\ncrypto_lib_crypto_arm_cortex_a57_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX57_FLAGS)\ncrypto_lib_crypto_arm_cortex_a57_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57.cpp\n\ncrypto_lib_crypto_arm_cortex_a57_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX57_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a57_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX57_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a57_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57_aes.cpp\n\ncrypto_lib_crypto_arm_cortex_a72_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX72_FLAGS)\ncrypto_lib_crypto_arm_cortex_a72_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX72_FLAGS)\ncrypto_lib_crypto_arm_cortex_a72_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72.cpp\n\ncrypto_lib_crypto_arm_cortex_a72_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_CORTEX72_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a72_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_CORTEX72_AES_FLAGS)\ncrypto_lib_crypto_arm_cortex_a72_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72_aes.cpp\n\ncrypto_lib_crypto_arm_thunderx_aes_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_THUNDERX_AES_FLAGS)\ncrypto_lib_crypto_arm_thunderx_aes_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_THUNDERX_AES_FLAGS)\ncrypto_lib_crypto_arm_thunderx_aes_a_SOURCES = \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_thunderx_aes.h \\\n  crypto/hash/sigma/echo256/opt/echo256_opt_arm_thunderx_aes.cpp \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_thunderx_aes.h \\\n  crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_thunderx_aes.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_thunderx_aes.h \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_arm_thunderx_aes.cpp\n  \ncrypto_lib_crypto_arm_v8_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PLATFORM_INTRINSICS_ARMV8_CRYPTO_FLAGS)\ncrypto_lib_crypto_arm_v8_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(PLATFORM_INTRINSICS_ARMV8_CRYPTO_FLAGS)\ncrypto_lib_crypto_arm_v8_crypto_a_SOURCES = \\\n  crypto/sha256_arm_shani.cpp\n\ncrypto_lib_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES)\ncrypto_lib_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\ncrypto_lib_crypto_a_SOURCES = \\\n  util/bytevectorhash.h \\\n  util/bytevectorhash.cpp \\\n  crypto/chacha20.h \\\n  crypto/chacha20.cpp \\\n  crypto/hash/scrypt.h \\\n  crypto/hash/scrypt.cpp \\\n  crypto/scrypt/sha256_scrypt.h \\\n  crypto/scrypt/sha256_scrypt.cpp \\\n  crypto/scrypt/crypto_scrypt.h \\\n  crypto/scrypt/crypto_scrypt.cpp \\\n  crypto/scrypt/crypto_scrypt_smix.h \\\n  crypto/scrypt/crypto_scrypt_smix.cpp \\\n  crypto/scrypt/crypto_scrypt_smix_sse2.h \\\n  crypto/scrypt/crypto_scrypt_smix_sse2.cpp \\\n  crypto/hash/sigma/echo256/sphlib/echo.cpp \\\n  crypto/hash/sigma/echo256/sphlib/sph_types.h \\\n  crypto/hash/sigma/echo256/sphlib/sph_echo.h \\\n  crypto/hash/sigma/echo256/sphlib/aes_helper.c \\\n  crypto/hash/sigma/shavite3_256/ref/AESround.h \\\n  crypto/hash/sigma/shavite3_256/ref/portable.h \\\n  crypto/hash/sigma/shavite3_256/ref/shavite3_256_ref_compress.h \\\n  crypto/hash/sigma/shavite3_256/ref/shavite3_ref.h \\\n  crypto/hash/sigma/shavite3_256/ref/shavite3_ref.cpp \\\n  crypto/hash/sigma/argon_echo/argon2.cpp \\\n  crypto/hash/sigma/argon_echo/core.cpp \\\n  crypto/hash/sigma/argon_echo/core.h \\\n  crypto/hash/sigma/argon_echo/argon_echo.h \\\n  crypto/hash/sigma/argon_echo/ref.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_hybrid.cpp \\\n  crypto/hash/sigma/argon_echo/opt/core_opt_hybrid.h \\\n  crypto/hash/sigma/argon_echo/blake2/blake2.h \\\n  crypto/hash/sigma/argon_echo/blake2/blake2b.cpp \\\n  crypto/hash/sigma/argon_echo/blake2/blake2-impl.h \\\n  crypto/hash/sigma/argon_echo/blake2/blamka-round-ref.h \\\n  crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_sse2.h \\\n  crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_sse3.h \\\n  crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_avx2.h \\\n  crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_avx512f.h \\\n  crypto/hash/sigma/sigma.h \\\n  crypto/hash/sigma/sigma.cpp \\\n  crypto/common.h \\\n  crypto/hmac_sha256.cpp \\\n  crypto/hmac_sha256.h \\\n  crypto/hmac_sha512.cpp \\\n  crypto/hmac_sha512.h \\\n  crypto/ripemd160.cpp \\\n  crypto/ripemd160.h \\\n  crypto/sha1.cpp \\\n  crypto/sha1.h \\\n  crypto/sha256.cpp \\\n  crypto/sha256.h \\\n  crypto/sha512.cpp \\\n  crypto/sha512.h\n\nEXTRA_crypto_lib_crypto_a_SOURCES = \\\n  crypto/hash/sigma/echo256/echo256_opt.h \\\n  crypto/hash/sigma/echo256/echo256_opt.cpp \\\n  crypto/hash/sigma/shavite3_256/shavite3_256_opt.cpp \\\n  crypto/hash/sigma/shavite3_256/shavite3_256_opt.h \\\n  llvm-cpumodel-hack.cpp\n\nif BUILD_LIBS_JNI\n# android compat library; shared between unity and testing framework.\nlib_android_compat_a_CPPFLAGS = $(AM_CPPFLAGS) $(CONFIG_INCLUDES) $(PROTOBUF_CFLAGS)\nlib_android_compat_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_android_compat_a_SOURCES = \\\n  unity/compat/android_wallet.cpp \\\n  unity/compat/android_wallet.h\nendif\n\n# consensus: Included by all executables except CLI; also all unity libraries\nlib_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_consensus_a_SOURCES = \\\n  pow/diff_delta.cpp \\\n  pow/diff_old.cpp \\\n  pow/diff_common.cpp \\\n  crypto/hash/city.cpp \\\n  amount.h \\\n  arith_uint256.cpp \\\n  arith_uint256.h \\\n  consensus/merkle.cpp \\\n  consensus/merkle.h \\\n  consensus/params.h \\\n  consensus/validation.h \\\n  hash.cpp \\\n  hash.h \\\n  prevector.h \\\n  primitives/block.cpp \\\n  primitives/block.h \\\n  primitives/transaction.cpp \\\n  primitives/transaction.h \\\n  pubkey.cpp \\\n  pubkey.h \\\n  script/consensus.cpp \\\n  script/consensus.h \\\n  script/interpreter.cpp \\\n  script/interpreter.h \\\n  script/script.cpp \\\n  script/script.h \\\n  script/script_error.cpp \\\n  script/script_error.h \\\n  serialize.h \\\n  tinyformat.h \\\n  uint256.cpp \\\n  uint256.h \\\n  version.h\n\n# common: shared between Daemon, GUI client and non-server tools\nlib_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_common_a_SOURCES = \\\n  unity/appmanager.cpp \\\n  base58.cpp \\\n  chainparams.cpp \\\n  coins.cpp \\\n  compressor.cpp \\\n  node/context.cpp \\\n  blockfilter.cpp \\\n  key.cpp \\\n  keystore.cpp \\\n  netaddress.cpp \\\n  netbase.cpp \\\n  protocol.cpp \\\n  scheduler.cpp \\\n  script/sign.cpp \\\n  script/standard.cpp \\\n  $(CORE_H)\n\n# util: shared between all executables and unity libraries.\n# This library *must* be included to make sure that the glibc\n# backward-compatibility objects and their sanity checks are linked.\nlib_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_util_a_SOURCES = \\\n  support/lockedpool.cpp \\\n  chainparamsbase.cpp \\\n  clientversion.cpp \\\n  compat/glibc_sanity.cpp \\\n  compat/glibcxx_sanity.cpp \\\n  compat/strnlen.cpp \\\n  fs.cpp \\\n  random.cpp \\\n  randomenv.cpp \\\n  support/cleanse.cpp \\\n  sync.cpp \\\n  util/thread.cpp \\\n  threadinterrupt.cpp \\\n  logging.cpp \\\n  util.cpp \\\n  util/moneystr.cpp \\\n  util/strencodings.cpp \\\n  util/time.cpp \\\n  util/syscall_sandbox.cpp \\\n  util/threadnames.cpp \\\n  util/getuniquepath.cpp \\\n  $(CORE_H)\n\n# generic: shared between everything except the unity libraries (which provide their own specialised implementations)\nlib_generic_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_generic_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_generic_a_SOURCES = \\\n  unity/generic/logging.cpp \\\n  core_read.cpp \\\n  core_write.cpp \\\n  $(CORE_H)\n  \n# generic_init: anything that includes 'generic' library must also include either this or 'generic_init_node' or provide its own init functions depending on if initialisation of http/rpc etc. is required\nlib_generic_init_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_generic_init_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_generic_init_a_SOURCES = \\\n  unity/generic/init_generic.cpp \\\n  $(CORE_H)\n\n# generic_init: anything that includes 'generic' library must also include either this or 'generic_init_server' or provide its own init functions depending on if initialisation of http/rpc etc. is required\nlib_generic_init_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_generic_init_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_generic_init_node_a_SOURCES = \\\n  unity/generic/init_generic_node.cpp \\\n  $(CORE_H)\n\n# cli: cli client only\nlib_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nlib_cli_a_SOURCES = \\\n  rpc/client.cpp \\\n  rpc/protocol.cpp \\\n  $(CORE_H)\n\nnodist_lib_util_a_SOURCES = $(srcdir)/obj/build.h\n#\n\nif TARGET_INTEL\nLIB_UNITY_CRYPTO_OBJ=$(LIB_CRYPTO_INTEL)\nelse\nLIB_UNITY_CRYPTO_OBJ=$(LIB_CRYPTO_ARM)\nendif\n\n# unity library (for node.js)#\nif BUILD_LIBS_NODE_JS\n\nDJINNI_CPP_GEN = \\\n  unity/djinni/cpp/address_record.hpp \\\n  unity/djinni/cpp/account_record.hpp \\\n  unity/djinni/cpp/account_link_record.hpp \\\n  unity/djinni/cpp/balance_record.hpp \\\n  unity/djinni/cpp/result_record.hpp \\\n  unity/djinni/cpp/block_info_record.hpp \\\n  unity/djinni/cpp/i_library_controller.cpp \\\n  unity/djinni/cpp/i_library_controller.hpp \\\n  unity/djinni/cpp/i_library_listener.hpp \\\n  unity/djinni/cpp/legacy_wallet_result.hpp \\\n  unity/djinni/cpp/monitor_listener.hpp \\\n  unity/djinni/cpp/monitor_record.hpp \\\n  unity/djinni/cpp/mutation_record.hpp \\\n  unity/djinni/cpp/mnemonic_record.hpp \\\n  unity/djinni/cpp/peer_record.hpp \\\n  unity/djinni/cpp/banned_peer_record.hpp \\\n  unity/djinni/cpp/qr_code_record.hpp \\\n  unity/djinni/cpp/transaction_record.hpp \\\n  unity/djinni/cpp/transaction_status.hpp \\\n  unity/djinni/cpp/input_record.hpp \\\n  unity/djinni/cpp/output_record.hpp \\\n  unity/djinni/cpp/uri_recipient.hpp \\\n  unity/djinni/cpp/i_rpc_controller.hpp \\\n  unity/djinni/cpp/i_rpc_listener.hpp \\\n  unity/djinni/cpp/i_p2p_network_controller.hpp \\\n  unity/djinni/cpp/i_p2p_network_listener.hpp \\\n  unity/djinni/cpp/i_accounts_controller.hpp \\\n  unity/djinni/cpp/i_witness_controller.hpp \\\n  unity/djinni/cpp/witness_estimate_info_record.hpp \\\n  unity/djinni/cpp/witness_funding_result_record.hpp \\\n  unity/djinni/cpp/witness_account_statistics_record.hpp \\\n  unity/djinni/cpp/i_accounts_listener.hpp \\\n  unity/djinni/cpp/i_wallet_controller.hpp \\\n  unity/djinni/cpp/i_wallet_listener.hpp \\\n  unity/djinni/cpp/i_generation_controller.hpp \\\n  unity/djinni/cpp/i_generation_listener.hpp \\\n  unity/djinni/cpp/uri_record.hpp \\\n  unity/djinni/cpp/wallet_lock_status.hpp\n\n\nDJINNI_NODE_JS_GEN = \\\n  unity/djinni/node_js/unifiedbackend.cpp \\\n  unity/djinni/node_js/NJSMonitorListener.cpp \\\n  unity/djinni/node_js/NJSMonitorListener.hpp \\\n  unity/djinni/node_js/NJSILibraryController.cpp \\\n  unity/djinni/node_js/NJSILibraryController.hpp \\\n  unity/djinni/node_js/NJSILibraryListener.cpp \\\n  unity/djinni/node_js/NJSILibraryListener.hpp \\\n  unity/djinni/node_js/NJSIRpcController.cpp \\\n  unity/djinni/node_js/NJSIRpcController.hpp \\\n  unity/djinni/node_js/NJSIRpcListener.cpp \\\n  unity/djinni/node_js/NJSIRpcListener.hpp \\\n  unity/djinni/node_js/NJSIP2pNetworkController.cpp \\\n  unity/djinni/node_js/NJSIP2pNetworkController.hpp \\\n  unity/djinni/node_js/NJSIP2pNetworkListener.cpp \\\n  unity/djinni/node_js/NJSIP2pNetworkListener.hpp \\\n  unity/djinni/node_js/NJSIWalletController.cpp \\\n  unity/djinni/node_js/NJSIWalletController.hpp \\\n  unity/djinni/node_js/NJSIWalletListener.cpp \\\n  unity/djinni/node_js/NJSIWalletListener.hpp \\\n  unity/djinni/node_js/NJSIAccountsController.cpp \\\n  unity/djinni/node_js/NJSIAccountsController.hpp \\\n  unity/djinni/node_js/NJSIWitnessController.cpp \\\n  unity/djinni/node_js/NJSIWitnessController.hpp \\\n  unity/djinni/node_js/NJSIAccountsListener.cpp \\\n  unity/djinni/node_js/NJSIAccountsListener.hpp \\\n  unity/djinni/node_js/NJSIGenerationController.cpp \\\n  unity/djinni/node_js/NJSIGenerationController.hpp \\\n  unity/djinni/node_js/NJSIGenerationListener.cpp \\\n  unity/djinni/node_js/NJSIGenerationListener.hpp\n\n\n\nlib_unity_node_js_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nlib_unity_node_js_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\n\nlib_unity_node_js_la_SOURCES = \\\n  controllers/rpccontroller.cpp \\\n  controllers/rpccontroller.h \\\n  core_read.cpp \\\n  core_write.cpp \\\n  unity/libinit.cpp \\\n  unity/libinit.h \\\n  unity/node_js/logging_node_js.cpp \\\n  unity/node_js/init_node_js.cpp \\\n  unity/unity_impl.h \\\n  unity/unity_impl.cpp \\\n  unity/controllers/irpccontroller.cpp \\\n  unity/controllers/ip2pnetworkcontroller.cpp \\\n  unity/controllers/iaccountscontroller.cpp \\\n  unity/controllers/iwitnesscontroller.cpp \\\n  unity/controllers/iwalletcontroller.cpp \\\n  unity/controllers/igenerationcontroller.cpp \\\n  unity/djinni/support-lib/nodejs/win_delay_load_hook.cpp \\\n  $(DJINNI_CPP_GEN) \\\n  $(DJINNI_NODE_JS_GEN)\n\n\nNJS_DEPS = $(LIB_CONSENSUS) $(LIB_NODE) $(LIB_UTIL) $(LIB_COMMON) $(LIB_SERVER) $(LIB_RPC) $(LIB_WALLET) $(LIB_CRYPTO_ALL) $(LIB_ZMQ)\nlib_unity_node_js_la_LDFLAGS = -shared -module -no-undefined -export-dynamic $(AM_LDFLAGS) $(RELDFLAGS) -pthread\nlib_unity_node_js_la_LIBADD = $(NJS_DEPS) $(NJS_DEPS) $(LIBSECP256K1) $(SSL_LIBS) $(CRYPTOPP_LIBS) $(BOOST_LIBS) $(BDB_LIBS) $(LIBLEVELDB) $(LIBMEMENV) $(LIBUNIVALUE) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SSL_LIBS) $(ZMQ_LIBS) -lqrencode -lpthread -lcryptopp $(SSL_LIBS) -lcrypto\nlib_unity_node_js_la_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(srcdir)/unity/djinni/node_js -I$(srcdir)/unity/djinni/cpp -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_INTERNAL\nlib_unity_node_js_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(COMMON_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(srcdir)/unity/djinni/node_js -I$(srcdir)/unity/djinni/cpp -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_INTERNAL\nendif\n\n# unity library (for java)#\nif BUILD_LIBS_JNI\nlib_unity_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(PROTOBUF_CFLAGS)\nlib_unity_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\n\nlib_unity_jni_la_SOURCES = \\\n  unity/libinit.cpp \\\n  unity/libinit.h \\\n  unity/android/logging_android.cpp \\\n  unity/android/init_android.cpp \\\n  unity/unity_impl.h \\\n  unity/unity_impl.cpp \\\n  unity/controllers/iwalletcontroller.cpp \\\n  unity/controllers/ip2pnetworkcontroller.cpp \\\n  unity/djinni/jni/NativeBlockInfoRecord.hpp \\\n  unity/djinni/jni/NativeBlockInfoRecord.cpp \\\n  unity/djinni/jni/NativeMonitorListener.cpp \\\n  unity/djinni/jni/NativeMonitorListener.hpp \\\n  unity/djinni/jni/NativeILibraryController.hpp \\\n  unity/djinni/jni/NativeILibraryController.cpp \\\n  unity/djinni/jni/NativeIWalletController.hpp \\\n  unity/djinni/jni/NativeIWalletController.cpp \\\n  unity/djinni/jni/NativeWalletLockStatus.hpp \\\n  unity/djinni/jni/NativeWalletLockStatus.cpp \\\n  unity/djinni/jni/NativeIWalletListener.hpp \\\n  unity/djinni/jni/NativeIWalletListener.cpp \\\n  unity/djinni/jni/NativeILibraryListener.hpp \\\n  unity/djinni/jni/NativeILibraryListener.cpp \\\n  unity/djinni/jni/NativeIP2pNetworkController.hpp \\\n  unity/djinni/jni/NativeIP2pNetworkController.cpp \\\n  unity/djinni/jni/NativeIP2pNetworkListener.hpp \\\n  unity/djinni/jni/NativeIP2pNetworkListener.cpp \\\n  unity/djinni/jni/NativeLegacyWalletResult.hpp \\\n  unity/djinni/jni/NativeMonitorRecord.cpp \\\n  unity/djinni/jni/NativeMonitorRecord.hpp \\\n  unity/djinni/jni/NativeMutationRecord.cpp \\\n  unity/djinni/jni/NativeMnemonicRecord.cpp \\\n  unity/djinni/jni/NativeMutationRecord.hpp \\\n  unity/djinni/jni/NativePaymentResultStatus.hpp \\\n  unity/djinni/jni/NativeBannedPeerRecord.hpp \\\n  unity/djinni/jni/NativeBannedPeerRecord.cpp \\\n  unity/djinni/jni/NativePeerRecord.hpp \\\n  unity/djinni/jni/NativePeerRecord.cpp \\\n  unity/djinni/jni/NativeQrCodeRecord.hpp \\\n  unity/djinni/jni/NativeQrCodeRecord.cpp \\\n  unity/djinni/jni/NativeAddressRecord.hpp \\\n  unity/djinni/jni/NativeAddressRecord.cpp \\\n  unity/djinni/jni/NativeBalanceRecord.hpp \\\n  unity/djinni/jni/NativeBalanceRecord.cpp \\\n  unity/djinni/jni/NativeUriRecord.hpp \\\n  unity/djinni/jni/NativeUriRecord.cpp \\\n  unity/djinni/jni/NativeUriRecipient.hpp \\\n  unity/djinni/jni/NativeUriRecipient.cpp \\\n  unity/djinni/jni/NativeTransactionRecord.hpp \\\n  unity/djinni/jni/NativeTransactionRecord.cpp \\\n  unity/djinni/jni/NativeTransactionStatus.hpp \\\n  unity/djinni/jni/NativeOutputRecord.hpp \\\n  unity/djinni/jni/NativeOutputRecord.cpp \\\n  unity/djinni/jni/NativeInputRecord.hpp \\\n  unity/djinni/jni/NativeInputRecord.cpp \\\n  unity/djinni/support-lib/jni/djinni_support.hpp \\\n  unity/djinni/cpp/i_library_controller.hpp \\\n  unity/djinni/cpp/i_library_controller.cpp \\\n  unity/djinni/cpp/i_library_listener.hpp \\\n  unity/djinni/cpp/balance_record.hpp \\\n  unity/djinni/cpp/mutation_record.hpp \\\n  $(CORE_H)\n\nnodist_lib_unity_jni_la_SOURCES = \\\n  unity/djinni/support-lib/jni/djinni_support.cpp \\\n  unity/djinni/support-lib/jni/djinni_main.cpp\n\nANDROID_DEPS = $(LIB_COMPAT) $(LIB_CONSENSUS) $(LIB_NODE) $(LIB_UTIL) $(LIB_COMMON) $(LIB_WALLET) $(LIB_CRYPTO_ALL) $(LIB_ANDROID_COMPAT)\n\n\nlib_unity_jni_la_LDFLAGS = -shared -module -export-dynamic $(AM_LDFLAGS_NO_THREADS) $(RELDFLAGS) -llog\nlib_unity_jni_la_LIBADD = $(ANDROID_DEPS) $(ANDROID_DEPS) $(LIBSECP256K1) $(SSL_LIBS) -lcrypto $(BOOST_LIBS) $(BDB_LIBS) $(LIBLEVELDB) $(LIBMEMENV) $(PROTOBUF_LIBS) -lqrencode -lcryptopp\nlib_unity_jni_la_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) -I$(srcdir)/unity/djinni/jni -I$(srcdir)/unity/djinni/cpp -I$(builddir)/obj -I$(srcdir)/unity/djinni/support-lib/jni -I$(srcdir)/secp256k1/include -DBUILD_INTERNAL\nlib_unity_jni_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(COMMON_INCLUDES) -I$(srcdir)/unity/djinni/jni -I$(srcdir)/unity/djinni/cpp -I$(builddir)/obj -I$(srcdir)/unity/djinni/support-lib/jni -I$(srcdir)/secp256k1/include -DBUILD_INTERNAL\nendif\n#\n\n# unity library for objc #\nif BUILD_LIBS_OBJC\n\nnoinst_LIBRARIES += $(LIB_UNITY_OBJC)\n\nlib_unity_objc_a_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) -I$(srcdir)/secp256k1/include -DBUILD_INTERNAL\nlib_unity_objc_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -I$(srcdir)/unity/djinni/cpp\nlib_unity_objc_a_OBJCXXFLAGS = -fobjc-arc  -I$(srcdir)/unity/djinni/cpp $(DJINNI_OBJCXXFLAGS)\n\nDJINNI_CPP_GEN = \\\n  unity/djinni/cpp/address_record.hpp \\\n  unity/djinni/cpp/balance_record.hpp \\\n  unity/djinni/cpp/block_info_record.hpp \\\n  unity/djinni/cpp/i_library_controller.cpp \\\n  unity/djinni/cpp/i_library_controller.hpp \\\n  unity/djinni/cpp/i_library_listener.hpp \\\n  unity/djinni/cpp/legacy_wallet_result.hpp \\\n  unity/djinni/cpp/monitor_listener.hpp \\\n  unity/djinni/cpp/monitor_record.hpp \\\n  unity/djinni/cpp/mutation_record.hpp \\\n  unity/djinni/cpp/mnemonic_record.hpp \\\n  unity/djinni/cpp/payment_result_status.hpp \\\n  unity/djinni/cpp/peer_record.hpp \\\n  unity/djinni/cpp/banned_peer_record.hpp \\\n  unity/djinni/cpp/qr_code_record.hpp \\\n  unity/djinni/cpp/transaction_record.hpp \\\n  unity/djinni/cpp/transaction_status.hpp \\\n  unity/djinni/cpp/input_record.hpp \\\n  unity/djinni/cpp/output_record.hpp \\\n  unity/djinni/cpp/uri_recipient.hpp \\\n  unity/djinni/cpp/uri_record.hpp\n\nDJINNI_OBJC_GEN = \\\n  unity/djinni/objc/DBAddressRecord+Private.h \\\n  unity/djinni/objc/DBAddressRecord+Private.mm \\\n  unity/djinni/objc/DBAddressRecord.h \\\n  unity/djinni/objc/DBAddressRecord.mm \\\n  unity/djinni/objc/DBBalanceRecord+Private.h \\\n  unity/djinni/objc/DBBalanceRecord+Private.mm \\\n  unity/djinni/objc/DBBalanceRecord.h \\\n  unity/djinni/objc/DBBalanceRecord.mm \\\n  unity/djinni/objc/DBBlockInfoRecord+Private.h \\\n  unity/djinni/objc/DBBlockInfoRecord+Private.mm \\\n  unity/djinni/objc/DBBlockInfoRecord.h \\\n  unity/djinni/objc/DBBlockInfoRecord.mm \\\n  unity/djinni/objc/DBILibraryController+Private.h \\\n  unity/djinni/objc/DBILibraryController+Private.mm \\\n  unity/djinni/objc/DBILibraryController.h \\\n  unity/djinni/objc/DBILibraryController.mm \\\n  unity/djinni/objc/DBWalletLockStatus.h \\\n  unity/djinni/objc/DBWalletLockStatus.mm \\\n  unity/djinni/objc/DBWalletLockStatus+Private.h \\\n  unity/djinni/objc/DBWalletLockStatus+Private.mm \\\n  unity/djinni/objc/DBILibraryListener+Private.h \\\n  unity/djinni/objc/DBILibraryListener+Private.mm \\\n  unity/djinni/objc/DBILibraryController.h \\\n  unity/djinni/objc/DBIP2pNetworkController+Private.h  \\\n  unity/djinni/objc/DBIP2pNetworkController+Private.mm \\\n  unity/djinni/objc/DBIP2pNetworkListener.h \\\n  unity/djinni/objc/DBIP2pNetworkListener+Private.h \\\n  unity/djinni/objc/DBIP2pNetworkListener+Private.mm \\\n  unity/djinni/objc/DBLegacyWalletResult.h \\\n  unity/djinni/objc/DBLegacyWalletResult+Private.h \\\n  unity/djinni/objc/DBMonitorListener+Private.h \\\n  unity/djinni/objc/DBMonitorListener+Private.mm \\\n  unity/djinni/objc/DBMonitorListener.h \\\n  unity/djinni/objc/DBMonitorRecord+Private.h \\\n  unity/djinni/objc/DBMonitorRecord+Private.mm \\\n  unity/djinni/objc/DBMutationRecord+Private.h \\\n  unity/djinni/objc/DBMutationRecord+Private.mm \\\n  unity/djinni/objc/DBMutationRecord.h \\\n  unity/djinni/objc/DBMutationRecord.mm \\\n  unity/djinni/objc/DBMnemonicRecord+Private.h \\\n  unity/djinni/objc/DBMnemonicRecord+Private.mm \\\n  unity/djinni/objc/DBMnemonicRecord.h \\\n  unity/djinni/objc/DBMnemonicRecord.mm \\\n  unity/djinni/objc/DBMonitorRecord.h \\\n  unity/djinni/objc/DBMonitorRecord.mm \\\n  unity/djinni/objc/DBInputRecord+Private.h \\\n  unity/djinni/objc/DBInputRecord+Private.mm \\\n  unity/djinni/objc/DBInputRecord.h \\\n  unity/djinni/objc/DBInputRecord.mm \\\n  unity/djinni/objc/DBOutputRecord+Private.h \\\n  unity/djinni/objc/DBOutputRecord+Private.mm \\\n  unity/djinni/objc/DBOutputRecord.h \\\n  unity/djinni/objc/DBOutputRecord.mm \\\n  unity/djinni/objc/DBPaymentResultStatus+Private.h \\\n  unity/djinni/objc/DBPaymentResultStatus.h \\\n  unity/djinni/objc/DBPeerRecord+Private.h \\\n  unity/djinni/objc/DBPeerRecord+Private.mm \\\n  unity/djinni/objc/DBPeerRecord.h \\\n  unity/djinni/objc/DBPeerRecord.mm \\\n  unity/djinni/objc/DBBannedPeerRecord+Private.h \\\n  unity/djinni/objc/DBBannedPeerRecord+Private.mm \\\n  unity/djinni/objc/DBBannedPeerRecord.h \\\n  unity/djinni/objc/DBBannedPeerRecord.mm \\\n  unity/djinni/objc/DBQrCodeRecord+Private.h \\\n  unity/djinni/objc/DBQrCodeRecord+Private.mm \\\n  unity/djinni/objc/DBQrCodeRecord.h \\\n  unity/djinni/objc/DBQrCodeRecord.mm \\\n  unity/djinni/objc/DBTransactionRecord+Private.h \\\n  unity/djinni/objc/DBTransactionRecord+Private.mm \\\n  unity/djinni/objc/DBTransactionRecord.h \\\n  unity/djinni/objc/DBTransactionRecord.mm \\\n  unity/djinni/objc/DBTransactionStatus+Private.h \\\n  unity/djinni/objc/DBTransactionStatus.h \\\n  unity/djinni/objc/DBUriRecipient+Private.h \\\n  unity/djinni/objc/DBUriRecipient+Private.mm \\\n  unity/djinni/objc/DBUriRecipient.h \\\n  unity/djinni/objc/DBUriRecipient.mm \\\n  unity/djinni/objc/DBUriRecord+Private.h \\\n  unity/djinni/objc/DBUriRecord+Private.mm \\\n  unity/djinni/objc/DBUriRecord.h \\\n  unity/djinni/objc/DBUriRecord.mm\n\nlib_unity_objc_a_SOURCES = \\\n  unity/libinit.cpp \\\n  unity/libinit.h \\\n  unity/ios/logging_ios.cpp \\\n  unity/ios/init_ios.cpp \\\n  $(lib_wallet_a_SOURCES) \\\n  $(lib_common_a_SOURCES) \\\n  $(lib_util_a_SOURCES) \\\n  $(lib_node_a_SOURCES) \\\n  $(lib_consensus_a_SOURCES) \\\n  $(crypto_lib_crypto_a_SOURCES) \\\n  unity/unity_impl.h \\\n  unity/unity_impl.cpp \\\n  unity/controllers/ip2pnetworkcontroller.cpp \\\n  unity/controllers/iwalletcontroller.cpp \\\n  $(DJINNI_CPP_GEN) \\\n  $(DJINNI_OBJC_GEN) \\\n  $(CORE_H)\n\nLIB_UNITY_CRYPTO=lib_unity_crypto.a\n\n$(LIB_UNITY_CRYPTO): $(LIB_UNITY_CRYPTO_OBJ)\n\tlibtool -static -o $@ $^\n\n$(LIB_UNITY_OBJC): $(LIBSECP256K1) $(LIBLEVELDB) $(LIBMEMENV) $(LIB_UNITY_CRYPTO)\n\nendif\n\n# Daemon binary #\nif BUILD_DAEMON\nMunt_daemon_SOURCES = daemon-main.cpp\nMunt_daemon_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nMunt_daemon_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nMunt_daemon_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\nif TARGET_WINDOWS\nMunt_daemon_SOURCES += daemon-res.rc\nendif\n\nMunt_daemon_LDADD = \\\n  $(LIB_SERVER) \\\n  $(LIB_RPC) \\\n  $(LIB_NODE) \\\n  $(LIB_SERVER) \\\n  $(LIB_RPC) \\\n  $(LIB_NODE) \\\n  $(CRYPTOPP_LIBS) \\\n  $(CRYPTO_LIBS) \\\n  $(LIB_WALLET) \\\n  $(CRYPTOPP_LIBS) \\\n  $(CRYPTO_LIBS) \\\n  $(LIB_COMMON) \\\n  $(LIBUNIVALUE) \\\n  $(LIB_UTIL) \\\n  $(LIB_GENERIC) \\\n  $(LIB_GENERIC_INIT_NODE) \\\n  $(LIB_SERVER) \\\n  $(LIB_RPC) \\\n  $(LIB_ZMQ) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIBLEVELDB) \\\n  $(LIBMEMENV) \\\n  $(LIBSECP256K1)\n\nMunt_daemon_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTOPP_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SSL_LIBS)\nendif\n#\n\n# cli binary #\nif BUILD_UTILS\nMunt_cli_SOURCES = cli-main.cpp\nMunt_cli_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) $(EVENT_CFLAGS)\nMunt_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nMunt_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\nif TARGET_WINDOWS\nMunt_cli_SOURCES += cli-res.rc\nendif\n\nMunt_cli_LDADD = \\\n  $(LIB_CLI) \\\n  $(LIBUNIVALUE) \\\n  $(LIB_UTIL) \\\n  $(LIB_GENERIC) \\\n  $(LIB_GENERIC_INIT) \\\n  $(LIB_CRYPTO_ALL)\n\nMunt_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTOPP_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)\nendif\n#\n\n# tx binary #\nif BUILD_UTILS\nMunt_tx_SOURCES = tx-main.cpp\nMunt_tx_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\nMunt_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nMunt_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\nif TARGET_WINDOWS\nMunt_tx_SOURCES += tx-res.rc\nendif\n\nMunt_tx_LDADD = \\\n  $(LIBUNIVALUE) \\\n  $(LIB_COMMON) \\\n  $(LIB_UTIL) \\\n  $(LIB_GENERIC) \\\n  $(LIB_GENERIC_INIT) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIB_COMMON) \\\n  $(LIB_UTIL) \\\n  $(LIB_GENERIC) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIB_COMMON) \\\n  $(LIBSECP256K1)\n\nMunt_tx_LDADD += $(BOOST_LIBS) $(CRYPTOPP_LIBS) $(CRYPTO_LIBS)\nendif\n#\n\n\nCLEANFILES = $(EXTRA_LIBRARIES)\n\nCLEANFILES += *.gcda *.gcno\nCLEANFILES += compat/*.gcda compat/*.gcno\nCLEANFILES += consensus/*.gcda consensus/*.gcno\nCLEANFILES += crypto/*.gcda crypto/*.gcno\nCLEANFILES += policy/*.gcda policy/*.gcno\nCLEANFILES += primitives/*.gcda primitives/*.gcno\nCLEANFILES += script/*.gcda script/*.gcno\nCLEANFILES += support/*.gcda support/*.gcno\nCLEANFILES += univalue/*.gcda univalue/*.gcno\nCLEANFILES += wallet/*.gcda wallet/*.gcno\nCLEANFILES += wallet/test/*.gcda wallet/test/*.gcno\nCLEANFILES += zmq/*.gcda zmq/*.gcno\n\nDISTCLEANFILES = obj/build.h\n\n\nconfig/build-config.h: config/stamp-h1\n\t@$(MAKE) -C $(top_builddir) $(subdir)/$(@)\nconfig/stamp-h1: $(top_srcdir)/$(subdir)/config/build-config.h.in $(top_builddir)/config.status\n\t$(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@)\n$(top_srcdir)/$(subdir)/config/build-config.h.in:  $(am__configure_deps)\n\t$(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/build-config.h.in\n\nclean-local:\n\t-$(MAKE) -C secp256k1 clean\n\t-rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno\n\t-rm -f config.h\n\t-rm -rf test/__pycache__\n\n.rc.o:\n\t@test -f $(WINDRES)\n\t## FIXME: How to get the appropriate modulename_CPPFLAGS in here?\n\t$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@\n\n.mm.o:\n\t$(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \\\n\t  $(CPPFLAGS) $(AM_CXXFLAGS) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<\n\n%.pb.cc %.pb.h: %.proto\n\t@test -f $(PROTOC)\n\t$(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(<D) $<\n\ninclude Makefile.crc32c.include\ninclude Makefile.leveldb.include\n\nif ENABLE_TESTS\ninclude Makefile.test.include\nendif\n\nif ENABLE_BENCH\n#include Makefile.bench.include\ninclude Makefile.sigmabench.include\nendif\n\ninclude Makefile.univalue.include\n"
  },
  {
    "path": "src/Makefile.bench.include",
    "content": "# Copyright (c) 2015-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nbin_PROGRAMS += bench/bench_munt\nBENCH_SRCDIR = bench\nBENCH_BINARY = bench/bench_munt$(EXEEXT)\n\nRAW_TEST_FILES = \\\n  bench/data/block413567.raw\nGENERATED_TEST_FILES = $(RAW_TEST_FILES:.raw=.raw.h)\n\nbench_bench_munt_SOURCES = \\\n  bench/bench_munt.cpp \\\n  bench/bench.cpp \\\n  bench/bench.h \\\n  bench/checkblock.cpp \\\n  bench/checkqueue.cpp \\\n  bench/Examples.cpp \\\n  bench/rollingbloom.cpp \\\n  bench/crypto_hash.cpp \\\n  bench/ccoins_caching.cpp \\\n  bench/mempool_eviction.cpp \\\n  bench/verify_script.cpp \\\n  bench/base58.cpp \\\n  bench/lockedpool.cpp \\\n  bench/perf.cpp \\\n  bench/perf.h \\\n  bench/prevector_destructor.cpp\n\nnodist_bench_bench_munt_SOURCES = $(GENERATED_TEST_FILES)\n\nbench_bench_munt_CPPFLAGS = $(AM_CPPFLAGS) $(MUNT_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/\nbench_bench_munt_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nbench_bench_munt_LDADD = \\\n  $(LIBMUNT_SERVER) \\\n  $(LIBMUNT_COMMON) \\\n  $(LIBMUNT_UTIL) \\\n  $(LIBMUNT_CONSENSUS) \\\n  $(LIBMUNT_CRYPTO_ALL) \\\n  $(LIBLEVELDB) \\\n  $(LIBMEMENV) \\\n  $(LIBSECP256K1) \\\n  $(LIBUNIVALUE) \\\n  $(LIBMUNT_COMMON)\n\nif ENABLE_ZMQ\nbench_bench_munt_LDADD += $(LIBMUNT_ZMQ) $(ZMQ_LIBS)\nendif\n\nif ENABLE_WALLET\nbench_bench_munt_SOURCES += bench/coin_selection.cpp\nbench_bench_munt_LDADD += $(LIBMUNT_WALLET) $(LIBMUNT_CRYPTO_ALL)\nendif\n\nbench_bench_munt_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTOPP_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)\nbench_bench_munt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\nCLEAN_MUNT_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_TEST_FILES)\n\nCLEANFILES += $(CLEAN_MUNT_BENCH)\n\nbench/checkblock.cpp: bench/data/block413567.raw.h\n\nmunt_bench: $(BENCH_BINARY)\n\nbench: $(BENCH_BINARY) FORCE\n\t$(BENCH_BINARY)\n\nmunt_bench_clean : FORCE\n\trm -f $(CLEAN_MUNT_BENCH) $(bench_bench_munt_OBJECTS) $(BENCH_BINARY)\n\n%.raw.h: %.raw\n\t@$(MKDIR_P) $(@D)\n\t@{ \\\n\t echo \"static unsigned const char $(*F)[] = {\" && \\\n\t $(HEXDUMP) -v -e '8/1 \"0x%02x, \"' -e '\"\\n\"' $< | $(SED) -e 's/0x  ,//g' && \\\n\t echo \"};\"; \\\n\t} > \"$@.new\" && mv -f \"$@.new\" \"$@\"\n\t@echo \"Generated $@\"\n"
  },
  {
    "path": "src/Makefile.crc32c.include",
    "content": "# Copyright (c) 2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nLIBCRC32C_INT = crc32c/libcrc32c.a\nLIBLEVELDB_SSE42_INT  = leveldb/libleveldb_sse42.a\n\nEXTRA_LIBRARIES += $(LIBCRC32C_INT)\n\nLIBCRC32C = $(LIBCRC32C_INT)\n\nCRC32C_CPPFLAGS_INT =\nCRC32C_CPPFLAGS_INT += -I$(srcdir)/crc32c/include\nCRC32C_CPPFLAGS_INT += -DHAVE_BUILTIN_PREFETCH=@HAVE_BUILTIN_PREFETCH@\nCRC32C_CPPFLAGS_INT += -DHAVE_MM_PREFETCH=@HAVE_MM_PREFETCH@\nCRC32C_CPPFLAGS_INT += -DHAVE_STRONG_GETAUXVAL=@HAVE_STRONG_GETAUXVAL@\nCRC32C_CPPFLAGS_INT += -DCRC32C_TESTS_BUILT_WITH_GLOG=0\n\nCRC32C_CPPFLAGS_INT += -DHAVE_SSE42=0\n\nCRC32C_CPPFLAGS_INT += -DHAVE_ARM64_CRC32C=0\n\nif WORDS_BIGENDIAN\nCRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=1\nelse\nCRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=0\nendif\n\ncrc32c_libcrc32c_a_CPPFLAGS = $(AM_CPPFLAGS) $(CRC32C_CPPFLAGS_INT) $(CRC32C_CPPFLAGS)\ncrc32c_libcrc32c_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\n\ncrc32c_libcrc32c_a_SOURCES =\ncrc32c_libcrc32c_a_SOURCES += crc32c/include/crc32c/crc32c.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64_check.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_internal.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_prefetch.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_read_le.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_round_up.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_sse42_check.h\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_sse42.h\n\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c.cc\ncrc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_portable.cc\n\n"
  },
  {
    "path": "src/Makefile.leveldb.include",
    "content": "# Copyright (c) 2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nLIBLEVELDB_INT = leveldb/libleveldb.a\nLIBMEMENV_INT  = leveldb/libmemenv.a\n\nEXTRA_LIBRARIES += $(LIBLEVELDB_INT)\nEXTRA_LIBRARIES += $(LIBMEMENV_INT)\n\nLIBLEVELDB = $(LIBLEVELDB_INT) $(LIBCRC32C)\nLIBMEMENV = $(LIBMEMENV_INT)\n\nLEVELDB_CPPFLAGS =\nLEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include\nLEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv\n\nLEVELDB_CPPFLAGS_INT =\nLEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb\nLEVELDB_CPPFLAGS_INT += -I$(srcdir)/crc32c/include\nLEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS\nLEVELDB_CPPFLAGS_INT += -DHAVE_SNAPPY=0 -DHAVE_CRC32C=1\nLEVELDB_CPPFLAGS_INT += -DHAVE_FDATASYNC=@HAVE_FDATASYNC@\nLEVELDB_CPPFLAGS_INT += -DHAVE_FULLFSYNC=@HAVE_FULLFSYNC@\nLEVELDB_CPPFLAGS_INT += -DHAVE_O_CLOEXEC=@HAVE_O_CLOEXEC@\nLEVELDB_CPPFLAGS_INT += -DFALLTHROUGH_INTENDED=[[fallthrough]]\n\nif WORDS_BIGENDIAN\nLEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=1\nelse\nLEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=0\nendif\n\nif TARGET_WINDOWS\nLEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -D_UNICODE -DUNICODE -D__USE_MINGW_ANSI_STDIO=1\nelse\nLEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX\nendif\n\nleveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB_CPPFLAGS)\nif BUILD_LIBS_JNI\nleveldb_libleveldb_a_CPPFLAGS += -fPIC \nendif\nleveldb_libleveldb_a_CXXFLAGS = $(filter-out -Wconditional-uninitialized -Werror=conditional-uninitialized -Wsuggest-override -Werror=suggest-override, $(AM_CXXFLAGS)) $(PIE_FLAGS)\n\nleveldb_libleveldb_a_SOURCES=\nleveldb_libleveldb_a_SOURCES += leveldb/port/port_stdcxx.h\nleveldb_libleveldb_a_SOURCES += leveldb/port/port.h\nleveldb_libleveldb_a_SOURCES += leveldb/port/thread_annotations.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/db.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/options.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/comparator.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/filter_policy.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/slice.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table_builder.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/env.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/export.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/c.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/iterator.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/cache.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/dumpfile.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/write_batch.h\nleveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/status.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/log_format.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/memtable.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/version_set.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/write_batch_internal.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/filename.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/builder.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/skiplist.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/snapshot.h\nleveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/block.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/merger.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/format.h\nleveldb_libleveldb_a_SOURCES += leveldb/table/iterator_wrapper.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/env_posix_test_helper.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/env_windows_test_helper.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/arena.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/random.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/posix_logger.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/hash.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/histogram.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/coding.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/testutil.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/mutexlock.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/logging.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/no_destructor.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/testharness.h\nleveldb_libleveldb_a_SOURCES += leveldb/util/windows_logger.h\n\nleveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/c.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/dumpfile.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/filename.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/memtable.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/repair.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/version_set.cc\nleveldb_libleveldb_a_SOURCES += leveldb/db/write_batch.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/block.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/format.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/iterator.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/merger.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/table_builder.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/table.cc\nleveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/arena.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/bloom.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/cache.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/coding.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/comparator.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/env.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/filter_policy.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/hash.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/histogram.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/logging.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/options.cc\nleveldb_libleveldb_a_SOURCES += leveldb/util/status.cc\n\nif TARGET_WINDOWS\nleveldb_libleveldb_a_SOURCES += leveldb/util/env_windows.cc\nelse\nleveldb_libleveldb_a_SOURCES += leveldb/util/env_posix.cc\nendif\n\nleveldb_libmemenv_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS)\nleveldb_libmemenv_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS)\nleveldb_libmemenv_a_SOURCES =  leveldb/helpers/memenv/memenv.cc\nleveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h\n"
  },
  {
    "path": "src/Makefile.sigmabench.include",
    "content": "# Copyright (c) 2019-2022 The Centure developers\n# Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n# Distributed under the GNU Lesser General Public License V3, see the accompanying\n# file COPYING\n\nbin_PROGRAMS += bench/bench_sigma\nBENCH_SRCDIR = bench\nBENCH_BINARY = bench/bench_sigma$(EXEEXT)\n\nbench_bench_sigma_SOURCES = \\\n  util.cpp \\\n  bench/bench_sigma.cpp \\\n  util/strencodings.cpp \\\n  support/cleanse.cpp\n\nbench_bench_sigma_CPPFLAGS = $(AM_CPPFLAGS) $(MUNT_INCLUDES) $(SSL_CFLAGS) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/\nbench_bench_sigma_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\nbench_bench_sigma_LDADD = \\\n  $(LIB_SERVER) \\\n  $(LIB_COMMON) \\\n  $(LIB_UTIL) \\\n  $(LIB_NODE) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIBLEVELDB) \\\n  $(LIBMEMENV) \\\n  $(LIBSECP256K1) \\\n  $(LIBUNIVALUE) \\\n  $(BOOST_LIBS) \\\n  $(BDB_LIBS) \\\n  $(SSL_LIBS) \\\n  $(CRYPTOPP_LIBS) \\\n  $(CRYPTO_LIBS) \\\n  $(MINIUPNPC_LIBS) \\\n  $(EVENT_PTHREADS_LIBS) \\\n  $(EVENT_LIBS) \\\n  $(SSL_LIBS)\n\nbench_bench_sigma_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\nmunt_sigma: $(BENCH_BINARY)\n\nbench_sigma: $(BENCH_BINARY) FORCE\n\t$(BENCH_BINARY)\n\nmunt_bench_clean : FORCE\n\trm -f $(bench_bench_sigma_OBJECTS) $(BENCH_BINARY)\n\n"
  },
  {
    "path": "src/Makefile.test.include",
    "content": "# Copyright (c) 2013-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# File contains modifications by: The Centure developers\n# All modifications:\n# Copyright (c) 2016-2022 The Centure developers\n# Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n# Distributed under the GNU Lesser General Public License v3, see the accompanying\n# file COPYING\n\n\nTESTS += test/test_munt\nbin_PROGRAMS += test/test_munt\nnoinst_PROGRAMS += test/test_munt_fuzzy\nTEST_SRCDIR = test\nTEST_BINARY=test/test_munt$(EXEEXT)\n\nTEST_EXTRA_DIST = \\\n  test/data/wallet-seed-no-password-protobuf \\\n  test/data/wallet-seed-password-1234-protobuf \\\n  test/data/wallet-linked-no-password-protobuf \\\n  test/data/wallet-linked-password-5281-protobuf\n\n\nJSON_TEST_FILES = \\\n  test/data/script_tests.json \\\n  test/data/base58_keys_valid.json \\\n  test/data/base58_encode_decode.json \\\n  test/data/base58_keys_invalid.json \\\n  test/data/tx_invalid.json \\\n  test/data/tx_valid.json \\\n  test/data/sighash.json\n\nRAW_TEST_FILES =\n\nGENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)\n\n# test_munt binary #\nTEST_SOURCES =\\\n  test/arith_uint256_tests.cpp \\\n  test/scriptnum10.h \\\n  test/addrman_tests.cpp \\\n  test/amount_tests.cpp \\\n  test/allocator_tests.cpp \\\n  test/base32_tests.cpp \\\n  test/base58_tests.cpp \\\n  test/base64_tests.cpp \\\n  test/bip32_tests.cpp \\\n  test/blockencodings_tests.cpp \\\n  test/bloom_tests.cpp \\\n  test/bswap_tests.cpp \\\n  test/checkqueue_tests.cpp \\\n  test/coins_tests.cpp \\\n  test/compress_tests.cpp \\\n  test/crypto_tests.cpp \\\n  test/cuckoocache_tests.cpp \\\n  test/DoS_tests.cpp \\\n  test/getarg_tests.cpp \\\n  test/hash_tests.cpp \\\n  test/key_tests.cpp \\\n  test/limitedmap_tests.cpp \\\n  test/dbwrapper_tests.cpp \\\n  test/main_tests.cpp \\\n  test/mempool_tests.cpp \\\n  test/merkle_tests.cpp \\\n  test/miner_tests.cpp \\\n  test/multisig_tests.cpp \\\n  test/net_tests.cpp \\\n  test/netbase_tests.cpp \\\n  test/pmt_tests.cpp \\\n  test/policyestimator_tests.cpp \\\n  test/pow_tests.cpp \\\n  test/prevector_tests.cpp \\\n  test/raii_event_tests.cpp \\\n  test/random_tests.cpp \\\n  test/reverselock_tests.cpp \\\n  test/rpc_tests.cpp \\\n  test/sanity_tests.cpp \\\n  test/scheduler_tests.cpp \\\n  test/script_P2SH_tests.cpp \\\n  test/script_tests.cpp \\\n  test/scriptnum_tests.cpp \\\n  test/serialize_tests.cpp \\\n  test/sighash_tests.cpp \\\n  test/sigopcount_tests.cpp \\\n  test/skiplist_tests.cpp \\\n  test/streams_tests.cpp \\\n  test/test.cpp \\\n  test/test.h \\\n  test/test_main.cpp \\\n  test/testutil.cpp \\\n  test/testutil.h \\\n  test/timedata_tests.cpp \\\n  test/torcontrol_tests.cpp \\\n  test/transaction_tests.cpp \\\n  test/txvalidationcache_tests.cpp \\\n  test/versionbits_tests.cpp \\\n  test/uint256_tests.cpp \\\n  test/util_tests.cpp \\\n  test/unity_tests.cpp\n\nif ENABLE_WALLET\nTEST_SOURCES += \\\n  wallet/test/wallet_test_fixture.cpp \\\n  wallet/test/wallet_test_fixture.h \\\n  wallet/test/accounting_tests.cpp \\\n  wallet/test/wallet_tests.cpp \\\n  wallet/test/crypto_tests.cpp\nendif\n\ntest_test_munt_SOURCES = $(TEST_SOURCES) $(JSON_TEST_FILES) $(RAW_TEST_FILES)\ntest_test_munt_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES) -DTESTDATADIR=\\\"$(abs_top_srcdir)/src/test/data/\\\" -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)\ntest_test_munt_LDADD = $(LIB_SERVER) $(LIB_NODE) $(LIB_SERVER) $(LIB_NODE)\nif ENABLE_WALLET\ntest_test_munt_LDADD += $(LIB_WALLET)\nendif\nif ENABLE_ZMQ\ntest_test_munt_LDADD += $(LIB_ZMQ) $(ZMQ_LIBS)\nendif\ntest_test_munt_LDADD += $(LIB_CLI) $(LIB_COMMON) $(LIB_UTIL) $(LIB_CONSENSUS) $(LIB_RPC) $(LIB_SERVER) $(LIB_WALLET) $(LIB_NODE) $(LIB_CRYPTO_ALL) $(LIB_GENERIC) $(LIB_GENERIC_INIT) $(LIB_ANDROID_COMPAT) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \\\n  $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(PROTOBUF_LIBS)\ntest_test_munt_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\n\ntest_test_munt_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTOPP_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)\ntest_test_munt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static\n\n\n#\n\n# test_munt_fuzzy binary #\ntest_test_munt_fuzzy_SOURCES = test/test_fuzzy.cpp\ntest_test_munt_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(COMMON_INCLUDES)\ntest_test_munt_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)\ntest_test_munt_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)\n\ntest_test_munt_fuzzy_LDADD = $(LIB_SERVER) $(LIB_NODE) $(LIB_SERVER) $(LIB_NODE) $(MINIUPNPC_LIBS)\nif ENABLE_WALLET\ntest_test_munt_fuzzy_LDADD +=  $(CRYPTOPP_LIBS) $(CRYPTO_LIBS) $(LIB_WALLET)\nendif\nif ENABLE_ZMQ\ntest_test_munt_fuzzy_LDADD += $(LIB_ZMQ) $(ZMQ_LIBS)\nendif\ntest_test_munt_fuzzy_LDADD += \\\n  $(LIB_COMMON) \\\n  $(LIB_GENERIC) \\\n  $(LIB_GENERIC_INIT) \\\n  $(LIB_UTIL) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIB_NODE) \\\n  $(LIB_UTIL) \\\n  $(LIB_CONSENSUS) \\\n  $(LIB_COMMON) \\\n  $(LIB_WALLET) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIB_COMMON) \\\n  $(LIB_WALLET) \\\n  $(LIB_RPC) \\\n  $(LIB_SERVER) \\\n  $(LIB_NODE) \\\n  $(LIB_COMMON) \\\n  $(LIB_WALLET) \\\n  $(LIB_GENERIC) \\\n  $(LIB_CRYPTO_ALL) \\\n  $(LIBLEVELDB) \\\n  $(BDB_LIBS) \\\n  $(EVENT_LIBS) \\\n  $(LIBSECP256K1) \\\n  $(LIBUNIVALUE) \\\n  $(LIBMEMENV) \\\n  $(EVENT_LIBS) \\\n  $(EVENT_PTHREADS_LIBS) \\\n  $(BOOST_LIBS) \\\n  $(CRYPTOPP_LIBS) \\\n  $(CRYPTO_LIBS)\n\nnodist_test_test_munt_SOURCES = $(GENERATED_TEST_FILES)\n\n$(TEST_SOURCES): $(GENERATED_TEST_FILES)\n\nCLEAN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES)\n\nCLEANFILES += $(CLEAN_TEST)\n\nmunt_test: $(TEST_BINARY)\n\nmunt_test_check: $(TEST_BINARY) FORCE\n\t$(MAKE) check-TESTS TESTS=$^\n\nmunt_test_clean : FORCE\n\trm -f $(CLEAN_TEST) $(test_test_munt_OBJECTS) $(TEST_BINARY)\n\ncheck-local:\n\t@echo \"Running test/util/util-test.py...\"\n\t$(top_builddir)/test/util/util-test.py\n\t$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check\n\n%.json.h: %.json\n\t@$(MKDIR_P) $(@D)\n\t@{ \\\n\t echo \"namespace json_tests{\" && \\\n\t echo \"static unsigned const char $(*F)[] = {\" && \\\n\t $(HEXDUMP) -v -e '8/1 \"0x%02x, \"' -e '\"\\n\"' $< | $(SED) -e 's/0x  ,//g' && \\\n\t echo \"};};\"; \\\n\t} > \"$@.new\" && mv -f \"$@.new\" \"$@\"\n\t@echo \"Generated $@\"\n"
  },
  {
    "path": "src/Makefile.univalue.include",
    "content": "include univalue/sources.mk\n\nLIBUNIVALUE = libunivalue.la\nnoinst_LTLIBRARIES += $(LIBUNIVALUE)\nlibunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) $(UNIVALUE_DIST_HEADERS_INT) $(UNIVALUE_LIB_HEADERS_INT) $(UNIVALUE_TEST_FILES_INT)\nlibunivalue_la_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)\n"
  },
  {
    "path": "src/addrdb.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"addrdb.h\"\n\n#include \"addrman.h\"\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"fs.h\"\n#include \"hash.h\"\n#include \"random.h\"\n#include \"streams.h\"\n#include \"tinyformat.h\"\n#include \"util.h\"\n#include <span.h>\n\n\nCBanDB::CBanDB()\n{\n    pathBanlist = GetDataDir() / \"banlist.dat\";\n}\n\nbool CBanDB::Write(const banmap_t& banSet)\n{\n    // Generate random temporary filename\n    unsigned short randv = 0;\n    GetRandBytes((unsigned char*)&randv, sizeof(randv));\n    std::string tmpfn = strprintf(\"banlist.dat.%04x\", randv);\n\n    // serialize banlist, checksum data up to that point, then append csum\n    CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);\n    ssBanlist << FLATDATA(Params().MessageStart());\n    ssBanlist << banSet;\n    uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());\n    ssBanlist << hash;\n\n    // open temp output file, and associate with CAutoFile\n    fs::path pathTmp = GetDataDir() / tmpfn;\n    FILE *file = fsbridge::fopen(pathTmp, \"wb\");\n    CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);\n    if (fileout.IsNull())\n        return error(\"%s: Failed to open file %s\", __func__, pathTmp.string());\n\n    // Write and commit header, data\n    try {\n        fileout << ssBanlist;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Serialize or I/O error - %s\", __func__, e.what());\n    }\n    FileCommit(fileout.Get());\n    fileout.fclose();\n\n    // replace existing banlist.dat, if any, with new banlist.dat.XXXX\n    if (!RenameOver(pathTmp, pathBanlist))\n        return error(\"%s: Rename-into-place failed\", __func__);\n\n    return true;\n}\n\nbool CBanDB::Read(banmap_t& banSet)\n{\n    // open input file, and associate with CAutoFile\n    FILE *file = fsbridge::fopen(pathBanlist, \"rb\");\n    CAutoFile filein(file, SER_DISK, CLIENT_VERSION);\n    if (filein.IsNull())\n        return error(\"%s: Failed to open file %s\", __func__, pathBanlist.string());\n\n    // use file size to size memory buffer\n    uint64_t fileSize = fs::file_size(pathBanlist);\n    size_t dataSize = 0;\n    // Don't try to resize to a negative number if file is small\n    if (fileSize >= sizeof(uint256))\n        dataSize = fileSize - sizeof(uint256);\n    std::vector<unsigned char> vchData;\n    vchData.resize(dataSize);\n    uint256 hashIn;\n\n    // read data and checksum from file\n    try {\n        filein.read(AsWritableBytes(Span{vchData.data(), dataSize}));\n        filein >> hashIn;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n    }\n    filein.fclose();\n\n    CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION);\n\n    // verify stored checksum matches input data\n    uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end());\n    if (hashIn != hashTmp)\n        return error(\"%s: Checksum mismatch, data corrupted\", __func__);\n\n    unsigned char pchMsgTmp[4];\n    try {\n        // de-serialize file header (network specific magic number) and ..\n        ssBanlist >> FLATDATA(pchMsgTmp);\n\n        // ... verify the network matches ours\n        if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))\n            return error(\"%s: Invalid network magic number\", __func__);\n\n        // de-serialize ban data\n        ssBanlist >> banSet;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n    }\n\n    return true;\n}\n\nCAddrDB::CAddrDB()\n{\n    pathAddr = GetDataDir() / \"peers.dat\";\n}\n\nbool CAddrDB::Write(const CAddrMan& addr)\n{\n    // Generate random temporary filename\n    unsigned short randv = 0;\n    GetRandBytes((unsigned char*)&randv, sizeof(randv));\n    std::string tmpfn = strprintf(\"peers.dat.%04x\", randv);\n\n    // serialize addresses, checksum data up to that point, then append csum\n    CDataStream ssPeers(SER_DISK, CLIENT_VERSION);\n    ssPeers << FLATDATA(Params().MessageStart());\n    ssPeers << addr;\n    uint256 hash = Hash(ssPeers.begin(), ssPeers.end());\n    ssPeers << hash;\n\n    // open temp output file, and associate with CAutoFile\n    fs::path pathTmp = GetDataDir() / tmpfn;\n    FILE *file = fsbridge::fopen(pathTmp, \"wb\");\n    CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);\n    if (fileout.IsNull())\n        return error(\"%s: Failed to open file %s\", __func__, pathTmp.string());\n\n    // Write and commit header, data\n    try {\n        fileout << ssPeers;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Serialize or I/O error - %s\", __func__, e.what());\n    }\n    FileCommit(fileout.Get());\n    fileout.fclose();\n\n    // replace existing peers.dat, if any, with new peers.dat.XXXX\n    if (!RenameOver(pathTmp, pathAddr))\n        return error(\"%s: Rename-into-place failed\", __func__);\n\n    return true;\n}\n\nbool CAddrDB::Read(CAddrMan& addr)\n{\n    // open input file, and associate with CAutoFile\n    FILE *file = fsbridge::fopen(pathAddr, \"rb\");\n    CAutoFile filein(file, SER_DISK, CLIENT_VERSION);\n    if (filein.IsNull())\n        return error(\"%s: Failed to open file %s\", __func__, pathAddr.string());\n\n    // use file size to size memory buffer\n    uint64_t fileSize = fs::file_size(pathAddr);\n    size_t dataSize = 0;\n    // Don't try to resize to a negative number if file is small\n    if (fileSize >= sizeof(uint256))\n        dataSize = fileSize - sizeof(uint256);\n    std::vector<unsigned char> vchData;\n    vchData.resize(dataSize);\n    uint256 hashIn;\n\n    // read data and checksum from file\n    try {\n        filein.read(AsWritableBytes(Span{vchData.data(), dataSize}));\n        filein >> hashIn;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n    }\n    filein.fclose();\n\n    CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);\n\n    // verify stored checksum matches input data\n    uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());\n    if (hashIn != hashTmp)\n        return error(\"%s: Checksum mismatch, data corrupted\", __func__);\n\n    return Read(addr, ssPeers);\n}\n\nbool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)\n{\n    unsigned char pchMsgTmp[4];\n    try {\n        // de-serialize file header (network specific magic number) and ..\n        ssPeers >> FLATDATA(pchMsgTmp);\n\n        // ... verify the network matches ours\n        if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))\n            return error(\"%s: Invalid network magic number\", __func__);\n\n        // de-serialize address data into one CAddrMan object\n        ssPeers >> addr;\n    }\n    catch (const std::exception& e) {\n        // de-serialization has failed, ensure addrman is left in a clean state\n        addr.Clear();\n        return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/addrdb.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ADDRDB_H\n#define ADDRDB_H\n\n#include \"fs.h\"\n#include \"serialize.h\"\n\n#include <string>\n#include <map>\n\nclass CSubNet;\nclass CAddrMan;\nclass CDataStream;\n\ntypedef enum BanReason\n{\n    BanReasonUnknown          = 0,\n    BanReasonNodeMisbehaving  = 1,\n    BanReasonManuallyAdded    = 2\n} BanReason;\n\nclass CBanEntry\n{\npublic:\n    static const int CURRENT_VERSION=1;\n    int nVersion;\n    int64_t nCreateTime;\n    int64_t nBanUntil;\n    uint8_t banReason;\n\n    CBanEntry()\n    {\n        SetNull();\n    }\n\n    CBanEntry(int64_t nCreateTimeIn)\n    {\n        SetNull();\n        nCreateTime = nCreateTimeIn;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(this->nVersion);\n        READWRITE(nCreateTime);\n        READWRITE(nBanUntil);\n        READWRITE(banReason);\n    }\n\n    void SetNull()\n    {\n        nVersion = CBanEntry::CURRENT_VERSION;\n        nCreateTime = 0;\n        nBanUntil = 0;\n        banReason = BanReasonUnknown;\n    }\n\n    std::string banReasonToString() const\n    {\n        switch (banReason) {\n        case BanReasonNodeMisbehaving:\n            return \"node misbehaving\";\n        case BanReasonManuallyAdded:\n            return \"manually added\";\n        default:\n            return \"unknown\";\n        }\n    }\n};\n\ntypedef std::map<CSubNet, CBanEntry> banmap_t;\n\n/** Access to the (IP) address database (peers.dat) */\nclass CAddrDB\n{\nprivate:\n    fs::path pathAddr;\npublic:\n    CAddrDB();\n    bool Write(const CAddrMan& addr);\n    bool Read(CAddrMan& addr);\n    bool Read(CAddrMan& addr, CDataStream& ssPeers);\n};\n\n/** Access to the banlist database (banlist.dat) */\nclass CBanDB\n{\nprivate:\n    fs::path pathBanlist;\npublic:\n    CBanDB();\n    bool Write(const banmap_t& banSet);\n    bool Read(banmap_t& banSet);\n};\n\n#endif\n"
  },
  {
    "path": "src/addrman.cpp",
    "content": "// Copyright (c) 2012 Pieter Wuille\n// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"addrman.h\"\n\n#include \"hash.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n\nint CAddrInfo::GetTriedBucket(const uint256& nKey) const\n{\n    uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << COMPACTSIZEVECTOR(GetKey())).GetHash().GetCheapHash();\n    uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << COMPACTSIZEVECTOR(GetGroup()) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash();\n    return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;\n}\n\nint CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src) const\n{\n    std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();\n    uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << COMPACTSIZEVECTOR(GetGroup()) << COMPACTSIZEVECTOR(vchSourceGroupKey)).GetHash().GetCheapHash();\n    uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << COMPACTSIZEVECTOR(vchSourceGroupKey) << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash();\n    return hash2 % ADDRMAN_NEW_BUCKET_COUNT;\n}\n\nint CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const\n{\n    uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << COMPACTSIZEVECTOR(GetKey())).GetHash().GetCheapHash();\n    return hash1 % ADDRMAN_BUCKET_SIZE;\n}\n\nbool CAddrInfo::IsTerrible(int64_t nNow) const\n{\n    if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute\n        return false;\n\n    if (nTime > nNow + 10 * 60) // came in a flying DeLorean\n        return true;\n\n    if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history\n        return true;\n\n    if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success\n        return true;\n\n    if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week\n        return true;\n\n    return false;\n}\n\ndouble CAddrInfo::GetChance(int64_t nNow) const\n{\n    double fChance = 1.0;\n    int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);\n\n    // deprioritize very recent attempts away\n    if (nSinceLastTry < 60 * 10)\n        fChance *= 0.01;\n\n    // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.\n    fChance *= pow(0.66, std::min(nAttempts, 8));\n\n    return fChance;\n}\n\nCAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)\n{\n    std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);\n    if (it == mapAddr.end())\n        return NULL;\n    if (pnId)\n        *pnId = (*it).second;\n    std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);\n    if (it2 != mapInfo.end())\n        return &(*it2).second;\n    return NULL;\n}\n\nCAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)\n{\n    int nId = nIdCount++;\n    mapInfo[nId] = CAddrInfo(addr, addrSource);\n    mapAddr[addr] = nId;\n    mapInfo[nId].nRandomPos = vRandom.size();\n    vRandom.push_back(nId);\n    if (pnId)\n        *pnId = nId;\n    return &mapInfo[nId];\n}\n\nvoid CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)\n{\n    if (nRndPos1 == nRndPos2)\n        return;\n\n    assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());\n\n    int nId1 = vRandom[nRndPos1];\n    int nId2 = vRandom[nRndPos2];\n\n    assert(mapInfo.count(nId1) == 1);\n    assert(mapInfo.count(nId2) == 1);\n\n    mapInfo[nId1].nRandomPos = nRndPos2;\n    mapInfo[nId2].nRandomPos = nRndPos1;\n\n    vRandom[nRndPos1] = nId2;\n    vRandom[nRndPos2] = nId1;\n}\n\nvoid CAddrMan::Delete(int nId)\n{\n    assert(mapInfo.count(nId) != 0);\n    CAddrInfo& info = mapInfo[nId];\n    assert(!info.fInTried);\n    assert(info.nRefCount == 0);\n\n    SwapRandom(info.nRandomPos, vRandom.size() - 1);\n    vRandom.pop_back();\n    mapAddr.erase(info);\n    mapInfo.erase(nId);\n    nNew--;\n}\n\nvoid CAddrMan::ClearNew(int nUBucket, int nUBucketPos)\n{\n    // if there is an entry in the specified bucket, delete it.\n    if (vvNew[nUBucket][nUBucketPos] != -1) {\n        int nIdDelete = vvNew[nUBucket][nUBucketPos];\n        CAddrInfo& infoDelete = mapInfo[nIdDelete];\n        assert(infoDelete.nRefCount > 0);\n        infoDelete.nRefCount--;\n        vvNew[nUBucket][nUBucketPos] = -1;\n        if (infoDelete.nRefCount == 0) {\n            Delete(nIdDelete);\n        }\n    }\n}\n\nvoid CAddrMan::MakeTried(CAddrInfo& info, int nId)\n{\n    // remove the entry from all new buckets\n    for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {\n        int pos = info.GetBucketPosition(nKey, true, bucket);\n        if (vvNew[bucket][pos] == nId) {\n            vvNew[bucket][pos] = -1;\n            info.nRefCount--;\n        }\n    }\n    nNew--;\n\n    assert(info.nRefCount == 0);\n\n    // which tried bucket to move the entry to\n    int nKBucket = info.GetTriedBucket(nKey);\n    int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);\n\n    // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).\n    if (vvTried[nKBucket][nKBucketPos] != -1) {\n        // find an item to evict\n        int nIdEvict = vvTried[nKBucket][nKBucketPos];\n        assert(mapInfo.count(nIdEvict) == 1);\n        CAddrInfo& infoOld = mapInfo[nIdEvict];\n\n        // Remove the to-be-evicted item from the tried set.\n        infoOld.fInTried = false;\n        vvTried[nKBucket][nKBucketPos] = -1;\n        nTried--;\n\n        // find which new bucket it belongs to\n        int nUBucket = infoOld.GetNewBucket(nKey);\n        int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);\n        ClearNew(nUBucket, nUBucketPos);\n        assert(vvNew[nUBucket][nUBucketPos] == -1);\n\n        // Enter it into the new set again.\n        infoOld.nRefCount = 1;\n        vvNew[nUBucket][nUBucketPos] = nIdEvict;\n        nNew++;\n    }\n    assert(vvTried[nKBucket][nKBucketPos] == -1);\n\n    vvTried[nKBucket][nKBucketPos] = nId;\n    nTried++;\n    info.fInTried = true;\n}\n\nvoid CAddrMan::Good_(const CService& addr, int64_t nTime)\n{\n    int nId;\n\n    nLastGood = nTime;\n\n    CAddrInfo* pinfo = Find(addr, &nId);\n\n    // if not found, bail out\n    if (!pinfo)\n        return;\n\n    CAddrInfo& info = *pinfo;\n\n    // check whether we are talking about the exact same CService (including same port)\n    if (info != addr)\n        return;\n\n    // update info\n    info.nLastSuccess = nTime;\n    info.nLastTry = nTime;\n    info.nAttempts = 0;\n    // nTime is not updated here, to avoid leaking information about\n    // currently-connected peers.\n\n    // if it is already in the tried set, don't do anything else\n    if (info.fInTried)\n        return;\n\n    // find a bucket it is in now\n    int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);\n    int nUBucket = -1;\n    for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {\n        int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;\n        int nBpos = info.GetBucketPosition(nKey, true, nB);\n        if (vvNew[nB][nBpos] == nId) {\n            nUBucket = nB;\n            break;\n        }\n    }\n\n    // if no bucket is found, something bad happened;\n    // TODO: maybe re-add the node, but for now, just bail out\n    if (nUBucket == -1)\n        return;\n\n    LogPrint(BCLog::ADDRMAN, \"Moving %s to tried\\n\", addr.ToString());\n\n    // move nId to the tried tables\n    MakeTried(info, nId);\n}\n\nbool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)\n{\n    if (!addr.IsRoutable())\n        return false;\n\n    bool fNew = false;\n    int nId;\n    CAddrInfo* pinfo = Find(addr, &nId);\n\n    // Do not set a penalty for a source's self-announcement\n    if (addr == source) {\n        nTimePenalty = 0;\n    }\n\n    if (pinfo) {\n        // periodically update nTime\n        bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);\n        int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);\n        if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))\n            pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);\n\n        // add services\n        pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);\n\n        // do not update if no new information is present\n        if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))\n            return false;\n\n        // do not update if the entry was already in the \"tried\" table\n        if (pinfo->fInTried)\n            return false;\n\n        // do not update if the max reference count is reached\n        if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)\n            return false;\n\n        // stochastic test: previous nRefCount == N: 2^N times harder to increase it\n        int nFactor = 1;\n        for (int n = 0; n < pinfo->nRefCount; n++)\n            nFactor *= 2;\n        if (nFactor > 1 && (RandomInt(nFactor) != 0))\n            return false;\n    } else {\n        pinfo = Create(addr, source, &nId);\n        pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);\n        nNew++;\n        fNew = true;\n    }\n\n    int nUBucket = pinfo->GetNewBucket(nKey, source);\n    int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);\n    if (vvNew[nUBucket][nUBucketPos] != nId) {\n        bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;\n        if (!fInsert) {\n            CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];\n            if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {\n                // Overwrite the existing new table entry.\n                fInsert = true;\n            }\n        }\n        if (fInsert) {\n            ClearNew(nUBucket, nUBucketPos);\n            pinfo->nRefCount++;\n            vvNew[nUBucket][nUBucketPos] = nId;\n        } else {\n            if (pinfo->nRefCount == 0) {\n                Delete(nId);\n            }\n        }\n    }\n    return fNew;\n}\n\nvoid CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)\n{\n    CAddrInfo* pinfo = Find(addr);\n\n    // if not found, bail out\n    if (!pinfo)\n        return;\n\n    CAddrInfo& info = *pinfo;\n\n    // check whether we are talking about the exact same CService (including same port)\n    if (info != addr)\n        return;\n\n    // update info\n    info.nLastTry = nTime;\n    if (fCountFailure && info.nLastCountAttempt < nLastGood) {\n        info.nLastCountAttempt = nTime;\n        info.nAttempts++;\n    }\n}\n\nCAddrInfo CAddrMan::Select_(bool newOnly)\n{\n    if (size() == 0)\n        return CAddrInfo();\n\n    if (newOnly && nNew == 0)\n        return CAddrInfo();\n\n    // Use a 50% chance for choosing between tried and new table entries.\n    if (!newOnly &&\n       (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { \n        // use a tried node\n        double fChanceFactor = 1.0;\n        while (1) {\n            int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);\n            int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);\n            while (vvTried[nKBucket][nKBucketPos] == -1) {\n                nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;\n                nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;\n            }\n            int nId = vvTried[nKBucket][nKBucketPos];\n            assert(mapInfo.count(nId) == 1);\n            CAddrInfo& info = mapInfo[nId];\n            if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))\n                return info;\n            fChanceFactor *= 1.2;\n        }\n    } else {\n        // use a new node\n        double fChanceFactor = 1.0;\n        while (1) {\n            int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);\n            int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);\n            while (vvNew[nUBucket][nUBucketPos] == -1) {\n                nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;\n                nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;\n            }\n            int nId = vvNew[nUBucket][nUBucketPos];\n            assert(mapInfo.count(nId) == 1);\n            CAddrInfo& info = mapInfo[nId];\n            if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30))\n                return info;\n            fChanceFactor *= 1.2;\n        }\n    }\n}\n\n#ifdef DEBUG_ADDRMAN\nint CAddrMan::Check_()\n{\n    std::set<int> setTried;\n    std::map<int, int> mapNew;\n\n    if (vRandom.size() != nTried + nNew)\n        return -7;\n\n    for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {\n        int n = (*it).first;\n        CAddrInfo& info = (*it).second;\n        if (info.fInTried) {\n            if (!info.nLastSuccess)\n                return -1;\n            if (info.nRefCount)\n                return -2;\n            setTried.insert(n);\n        } else {\n            if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)\n                return -3;\n            if (!info.nRefCount)\n                return -4;\n            mapNew[n] = info.nRefCount;\n        }\n        if (mapAddr[info] != n)\n            return -5;\n        if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)\n            return -14;\n        if (info.nLastTry < 0)\n            return -6;\n        if (info.nLastSuccess < 0)\n            return -8;\n    }\n\n    if (setTried.size() != nTried)\n        return -9;\n    if (mapNew.size() != nNew)\n        return -10;\n\n    for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {\n        for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {\n             if (vvTried[n][i] != -1) {\n                 if (!setTried.count(vvTried[n][i]))\n                     return -11;\n                 if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n)\n                     return -17;\n                 if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)\n                     return -18;\n                 setTried.erase(vvTried[n][i]);\n             }\n        }\n    }\n\n    for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {\n        for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {\n            if (vvNew[n][i] != -1) {\n                if (!mapNew.count(vvNew[n][i]))\n                    return -12;\n                if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)\n                    return -19;\n                if (--mapNew[vvNew[n][i]] == 0)\n                    mapNew.erase(vvNew[n][i]);\n            }\n        }\n    }\n\n    if (setTried.size())\n        return -13;\n    if (mapNew.size())\n        return -15;\n    if (nKey.IsNull())\n        return -16;\n\n    return 0;\n}\n#endif\n\nvoid CAddrMan::GetAddr_(std::vector<CAddress>& vAddr)\n{\n    unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100;\n    if (nNodes > ADDRMAN_GETADDR_MAX)\n        nNodes = ADDRMAN_GETADDR_MAX;\n\n    // gather a list of random nodes, skipping those of low quality\n    for (unsigned int n = 0; n < vRandom.size(); n++) {\n        if (vAddr.size() >= nNodes)\n            break;\n\n        int nRndPos = RandomInt(vRandom.size() - n) + n;\n        SwapRandom(n, nRndPos);\n        assert(mapInfo.count(vRandom[n]) == 1);\n\n        const CAddrInfo& ai = mapInfo[vRandom[n]];\n        if (!ai.IsTerrible())\n            vAddr.push_back(ai);\n    }\n}\n\nvoid CAddrMan::Connected_(const CService& addr, int64_t nTime)\n{\n    CAddrInfo* pinfo = Find(addr);\n\n    // if not found, bail out\n    if (!pinfo)\n        return;\n\n    CAddrInfo& info = *pinfo;\n\n    // check whether we are talking about the exact same CService (including same port)\n    if (info != addr)\n        return;\n\n    // update info\n    int64_t nUpdateInterval = 20 * 60;\n    if (nTime - info.nTime > nUpdateInterval)\n        info.nTime = nTime;\n}\n\nvoid CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)\n{\n    CAddrInfo* pinfo = Find(addr);\n\n    // if not found, bail out\n    if (!pinfo)\n        return;\n\n    CAddrInfo& info = *pinfo;\n\n    // check whether we are talking about the exact same CService (including same port)\n    if (info != addr)\n        return;\n\n    // update info\n    info.nServices = nServices;\n}\n\nint CAddrMan::RandomInt(int nMax){\n    return GetRandInt(nMax);\n}\n"
  },
  {
    "path": "src/addrman.h",
    "content": "// Copyright (c) 2012 Pieter Wuille\n// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ADDRMAN_H\n#define ADDRMAN_H\n\n#include \"netaddress.h\"\n#include \"protocol.h\"\n#include \"random.h\"\n#include \"sync.h\"\n#include \"timedata.h\"\n#include \"util.h\"\n\n#include <map>\n#include <set>\n#include <stdint.h>\n#include <vector>\n\n/**\n * Extended statistics about a CAddress\n */\nclass CAddrInfo : public CAddress\n{\n\n\npublic:\n    //! last try whatsoever by us (memory only)\n    int64_t nLastTry;\n\n    //! last counted attempt (memory only)\n    int64_t nLastCountAttempt;\n\nprivate:\n    //! where knowledge about this address first came from\n    CNetAddr source;\n\n    //! last successful connection by us\n    int64_t nLastSuccess;\n\n    //! connection attempts since last successful attempt\n    int nAttempts;\n\n    //! reference count in new sets (memory only)\n    int nRefCount;\n\n    //! in tried set? (memory only)\n    bool fInTried;\n\n    //! position in vRandom\n    int nRandomPos;\n\n    friend class CAddrMan;\n\npublic:\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(*(CAddress*)this);\n        READWRITE(source);\n        READWRITE(nLastSuccess);\n        READWRITE(nAttempts);\n    }\n\n    void Init()\n    {\n        nLastSuccess = 0;\n        nLastTry = 0;\n        nLastCountAttempt = 0;\n        nAttempts = 0;\n        nRefCount = 0;\n        fInTried = false;\n        nRandomPos = -1;\n    }\n\n    CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)\n    {\n        Init();\n    }\n\n    CAddrInfo() : CAddress(), source()\n    {\n        Init();\n    }\n\n    //! Calculate in which \"tried\" bucket this entry belongs\n    int GetTriedBucket(const uint256 &nKey) const;\n\n    //! Calculate in which \"new\" bucket this entry belongs, given a certain source\n    int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const;\n\n    //! Calculate in which \"new\" bucket this entry belongs, using its default source\n    int GetNewBucket(const uint256 &nKey) const\n    {\n        return GetNewBucket(nKey, source);\n    }\n\n    //! Calculate in which position of a bucket to store this entry.\n    int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;\n\n    //! Determine whether the statistics about this entry are bad enough so that it can just be deleted\n    bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;\n\n    //! Calculate the relative chance this entry should be given when selecting nodes to connect to\n    double GetChance(int64_t nNow = GetAdjustedTime()) const;\n\n};\n\n/** Stochastic address manager\n *\n * Design goals:\n *  * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.\n *  * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.\n *\n * To that end:\n *  * Addresses are organized into buckets.\n *    * Addresses that have not yet been tried go into 1024 \"new\" buckets.\n *      * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.\n *      * The actual bucket is chosen from one of these, based on the range in which the address itself is located.\n *      * One single address can occur in up to 8 different buckets to increase selection chances for addresses that\n *        are seen frequently. The chance for increasing this multiplicity decreases exponentially.\n *      * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen\n *        ones) is removed from it first.\n *    * Addresses of nodes that are known to be accessible go into 256 \"tried\" buckets.\n *      * Each address range selects at random 8 of these buckets.\n *      * The actual bucket is chosen from one of these, based on the full address.\n *      * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently\n *        tried ones) is evicted from it, back to the \"new\" buckets.\n *    * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not\n *      be observable by adversaries.\n *    * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)\n *      consistency checks for the entire data structure.\n */\n\n//! total number of buckets for tried addresses\n#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8\n\n//! total number of buckets for new addresses\n#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10\n\n//! maximum allowed number of entries in buckets for new and tried addresses\n#define ADDRMAN_BUCKET_SIZE_LOG2 6\n\n//! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread\n#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8\n\n//! over how many buckets entries with new addresses originating from a single group are spread\n#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64\n\n//! in how many buckets for entries with new addresses a single address may occur\n#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8\n\n//! how old addresses can maximally be\n#define ADDRMAN_HORIZON_DAYS 30\n\n//! after how many failed attempts we give up on a new node\n#define ADDRMAN_RETRIES 3\n\n//! how many successive failures are allowed ...\n#define ADDRMAN_MAX_FAILURES 10\n\n//! ... in at least this many days\n#define ADDRMAN_MIN_FAIL_DAYS 7\n\n//! the maximum percentage of nodes to return in a getaddr call\n#define ADDRMAN_GETADDR_MAX_PCT 23\n\n//! the maximum number of nodes to return in a getaddr call\n#define ADDRMAN_GETADDR_MAX 2500\n\n//! Convenience\n#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)\n#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)\n#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)\n\n/** \n * Stochastical (IP) address manager \n */\nclass CAddrMan\n{\nprivate:\n    //! critical section to protect the inner data structures\n    mutable RecursiveMutex cs;\n\n    //! last used nId\n    int nIdCount;\n\n    //! table with information about all nIds\n    std::map<int, CAddrInfo> mapInfo;\n\n    //! find an nId based on its network address\n    std::map<CNetAddr, int> mapAddr;\n\n    //! randomly-ordered vector of all nIds\n    std::vector<int> vRandom;\n\n    // number of \"tried\" entries\n    int nTried;\n\n    //! list of \"tried\" buckets\n    int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];\n\n    //! number of (unique) \"new\" entries\n    int nNew;\n\n    //! list of \"new\" buckets\n    int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];\n\n    //! last time Good was called (memory only)\n    int64_t nLastGood;\n\nprotected:\n    //! secret key to randomize bucket select with\n    uint256 nKey;\n\n    //! Source of random numbers for randomization in inner loops\n    FastRandomContext insecure_rand;\n\n    //! Find an entry.\n    CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);\n\n    //! find an entry, creating it if necessary.\n    //! nTime and nServices of the found node are updated, if necessary.\n    CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL);\n\n    //! Swap two elements in vRandom.\n    void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);\n\n    //! Move an entry from the \"new\" table(s) to the \"tried\" table\n    void MakeTried(CAddrInfo& info, int nId);\n\n    //! Delete an entry. It must not be in tried, and have refcount 0.\n    void Delete(int nId);\n\n    //! Clear a position in a \"new\" table. This is the only place where entries are actually deleted.\n    void ClearNew(int nUBucket, int nUBucketPos);\n\n    //! Mark an entry \"good\", possibly moving it from \"new\" to \"tried\".\n    void Good_(const CService &addr, int64_t nTime);\n\n    //! Add an entry to the \"new\" table.\n    bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);\n\n    //! Mark an entry as attempted to connect.\n    void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);\n\n    //! Select an address to connect to, if newOnly is set to true, only the new table is selected from.\n    CAddrInfo Select_(bool newOnly);\n\n    //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.\n    virtual int RandomInt(int nMax);\n\n#ifdef DEBUG_ADDRMAN\n    //! Perform consistency check. Returns an error code or zero.\n    int Check_();\n#endif\n\n    //! Select several addresses at once.\n    void GetAddr_(std::vector<CAddress> &vAddr);\n\n    //! Mark an entry as currently-connected-to.\n    void Connected_(const CService &addr, int64_t nTime);\n\n    //! Update an entry's service bits.\n    void SetServices_(const CService &addr, ServiceFlags nServices);\n\npublic:\n    /**\n     * serialized format:\n     * * version byte (currently 1)\n     * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)\n     * * nNew\n     * * nTried\n     * * number of \"new\" buckets XOR 2**30\n     * * all nNew addrinfos in vvNew\n     * * all nTried addrinfos in vvTried\n     * * for each bucket:\n     *   * number of elements\n     *   * for each element: index\n     *\n     * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it\n     * as incompatible. This is necessary because it did not check the version number on\n     * deserialization.\n     *\n     * Notice that vvTried, mapAddr and vVector are never encoded explicitly;\n     * they are instead reconstructed from the other information.\n     *\n     * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change,\n     * otherwise it is reconstructed as well.\n     *\n     * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports\n     * changes to the ADDRMAN_ parameters without breaking the on-disk structure.\n     *\n     * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has\n     * very little in common.\n     */\n    template<typename Stream>\n    void Serialize(Stream &s) const\n    {\n        LOCK(cs);\n\n        unsigned char nVersion = 1;\n        s << nVersion;\n        s << ((unsigned char)32);\n        s << nKey;\n        s << nNew;\n        s << nTried;\n\n        int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);\n        s << nUBuckets;\n        std::map<int, int> mapUnkIds;\n        int nIds = 0;\n        for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {\n            mapUnkIds[(*it).first] = nIds;\n            const CAddrInfo &info = (*it).second;\n            if (info.nRefCount) {\n                assert(nIds != nNew); // this means nNew was wrong, oh ow\n                s << info;\n                nIds++;\n            }\n        }\n        nIds = 0;\n        for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) {\n            const CAddrInfo &info = (*it).second;\n            if (info.fInTried) {\n                assert(nIds != nTried); // this means nTried was wrong, oh ow\n                s << info;\n                nIds++;\n            }\n        }\n        for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {\n            int nSize = 0;\n            for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {\n                if (vvNew[bucket][i] != -1)\n                    nSize++;\n            }\n            s << nSize;\n            for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {\n                if (vvNew[bucket][i] != -1) {\n                    int nIndex = mapUnkIds[vvNew[bucket][i]];\n                    s << nIndex;\n                }\n            }\n        }\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        LOCK(cs);\n\n        Clear();\n\n        unsigned char nVersion;\n        s >> nVersion;\n        unsigned char nKeySize;\n        s >> nKeySize;\n        if (nKeySize != 32) throw std::ios_base::failure(\"Incorrect keysize in addrman deserialization\");\n        s >> nKey;\n        s >> nNew;\n        s >> nTried;\n        int nUBuckets = 0;\n        s >> nUBuckets;\n        if (nVersion != 0) {\n            nUBuckets ^= (1 << 30);\n        }\n\n        if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {\n            throw std::ios_base::failure(\"Corrupt CAddrMan serialization, nNew exceeds limit.\");\n        }\n\n        if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) {\n            throw std::ios_base::failure(\"Corrupt CAddrMan serialization, nTried exceeds limit.\");\n        }\n\n        // Deserialize entries from the new table.\n        for (int n = 0; n < nNew; n++) {\n            CAddrInfo &info = mapInfo[n];\n            s >> info;\n            mapAddr[info] = n;\n            info.nRandomPos = vRandom.size();\n            vRandom.push_back(n);\n            if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) {\n                // In case the new table data cannot be used (nVersion unknown, or bucket count wrong),\n                // immediately try to give them a reference based on their primary source address.\n                int nUBucket = info.GetNewBucket(nKey);\n                int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket);\n                if (vvNew[nUBucket][nUBucketPos] == -1) {\n                    vvNew[nUBucket][nUBucketPos] = n;\n                    info.nRefCount++;\n                }\n            }\n        }\n        nIdCount = nNew;\n\n        // Deserialize entries from the tried table.\n        int nLost = 0;\n        for (int n = 0; n < nTried; n++) {\n            CAddrInfo info;\n            s >> info;\n            int nKBucket = info.GetTriedBucket(nKey);\n            int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);\n            if (vvTried[nKBucket][nKBucketPos] == -1) {\n                info.nRandomPos = vRandom.size();\n                info.fInTried = true;\n                vRandom.push_back(nIdCount);\n                mapInfo[nIdCount] = info;\n                mapAddr[info] = nIdCount;\n                vvTried[nKBucket][nKBucketPos] = nIdCount;\n                nIdCount++;\n            } else {\n                nLost++;\n            }\n        }\n        nTried -= nLost;\n\n        // Deserialize positions in the new table (if possible).\n        for (int bucket = 0; bucket < nUBuckets; bucket++) {\n            int nSize = 0;\n            s >> nSize;\n            for (int n = 0; n < nSize; n++) {\n                int nIndex = 0;\n                s >> nIndex;\n                if (nIndex >= 0 && nIndex < nNew) {\n                    CAddrInfo &info = mapInfo[nIndex];\n                    int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);\n                    if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) {\n                        info.nRefCount++;\n                        vvNew[bucket][nUBucketPos] = nIndex;\n                    }\n                }\n            }\n        }\n\n        // Prune new entries with refcount 0 (as a result of collisions).\n        int nLostUnk = 0;\n        for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) {\n            if (!it->second.fInTried && it->second.nRefCount == 0) {\n                std::map<int, CAddrInfo>::const_iterator itCopy = it++;\n                Delete(itCopy->first);\n                nLostUnk++;\n            } else {\n                it++;\n            }\n        }\n        if (nLost + nLostUnk > 0) {\n            LogPrint(BCLog::ADDRMAN, \"addrman lost %i new and %i tried addresses due to collisions\\n\", nLostUnk, nLost);\n        }\n\n        Check();\n    }\n\n    void Clear()\n    {\n        std::vector<int>().swap(vRandom);\n        nKey = GetRandHash();\n        for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {\n            for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {\n                vvNew[bucket][entry] = -1;\n            }\n        }\n        for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {\n            for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {\n                vvTried[bucket][entry] = -1;\n            }\n        }\n\n        nIdCount = 0;\n        nTried = 0;\n        nNew = 0;\n        nLastGood = 1; //Initially at 1 so that \"never\" is strictly worse.\n    }\n\n    CAddrMan()\n    {\n        Clear();\n    }\n\n    ~CAddrMan()\n    {\n        nKey.SetNull();\n    }\n\n    //! Return the number of (unique) addresses in all tables.\n    size_t size() const\n    {\n        LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead\n        return vRandom.size();\n    }\n\n    //! Consistency check\n    void Check()\n    {\n#ifdef DEBUG_ADDRMAN\n        {\n            LOCK(cs);\n            int err;\n            if ((err=Check_()))\n                LogPrintf(\"ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\\n\", err);\n        }\n#endif\n    }\n\n    //! Add a single address.\n    bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)\n    {\n        LOCK(cs);\n        bool fRet = false;\n        Check();\n        fRet |= Add_(addr, source, nTimePenalty);\n        Check();\n        if (fRet) {\n            LogPrint(BCLog::ADDRMAN, \"Added %s from %s: %i tried, %i new\\n\", addr.ToStringIPPort(), source.ToString(), nTried, nNew);\n        }\n        return fRet;\n    }\n\n    //! Add multiple addresses.\n    bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)\n    {\n        LOCK(cs);\n        int nAdd = 0;\n        Check();\n        for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)\n            nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;\n        Check();\n        if (nAdd) {\n            LogPrint(BCLog::ADDRMAN, \"Added %i addresses from %s: %i tried, %i new\\n\", nAdd, source.ToString(), nTried, nNew);\n        }\n        return nAdd > 0;\n    }\n\n    //! Mark an entry as accessible.\n    void Good(const CService &addr, int64_t nTime = GetAdjustedTime())\n    {\n        LOCK(cs);\n        Check();\n        Good_(addr, nTime);\n        Check();\n    }\n\n    //! Mark an entry as connection attempted to.\n    void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())\n    {\n        LOCK(cs);\n        Check();\n        Attempt_(addr, fCountFailure, nTime);\n        Check();\n    }\n\n    /**\n     * Choose an address to connect to.\n     */\n    CAddrInfo Select(bool newOnly = false)\n    {\n        CAddrInfo addrRet;\n        {\n            LOCK(cs);\n            Check();\n            addrRet = Select_(newOnly);\n            Check();\n        }\n        return addrRet;\n    }\n\n    //! Return a bunch of addresses, selected at random.\n    std::vector<CAddress> GetAddr()\n    {\n        Check();\n        std::vector<CAddress> vAddr;\n        {\n            LOCK(cs);\n            GetAddr_(vAddr);\n        }\n        Check();\n        return vAddr;\n    }\n\n    //! Mark an entry as currently-connected-to.\n    void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())\n    {\n        LOCK(cs);\n        Check();\n        Connected_(addr, nTime);\n        Check();\n    }\n\n    void SetServices(const CService &addr, ServiceFlags nServices)\n    {\n        LOCK(cs);\n        Check();\n        SetServices_(addr, nServices);\n        Check();\n    }\n\n};\n\n#endif\n"
  },
  {
    "path": "src/alert.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"alert.h\"\n\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"net.h\"\n#include \"netmessagemaker.h\"\n#include \"pubkey.h\"\n#include \"timedata.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#include <stdint.h>\n#include <algorithm>\n#include <map>\n#include <thread>\n\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/replace.hpp>\n\n\nstd::map<uint256, CAlert> mapAlerts;\nRecursiveMutex cs_mapAlerts;\n\nvoid CUnsignedAlert::SetNull()\n{\n    nVersion = 1;\n    nRelayUntil = 0;\n    nExpiration = 0;\n    nID = 0;\n    nCancel = 0;\n    setCancel.clear();\n    nMinVer = 0;\n    nMaxVer = 0;\n    setSubVer.clear();\n    nPriority = 0;\n\n    strComment.clear();\n    strStatusBar.clear();\n    strReserved.clear();\n}\n\nstd::string CUnsignedAlert::ToString() const\n{\n    std::string strSetCancel;\n    for(int n : setCancel)\n        strSetCancel += strprintf(\"%d \", n);\n    std::string strSetSubVer;\n    for(const std::string& str : setSubVer)\n        strSetSubVer += \"\\\"\" + str + \"\\\" \";\n    return strprintf(\n        \"CAlert(\\n\"\n        \"    nVersion     = %d\\n\"\n        \"    nRelayUntil  = %d\\n\"\n        \"    nExpiration  = %d\\n\"\n        \"    nID          = %d\\n\"\n        \"    nCancel      = %d\\n\"\n        \"    setCancel    = %s\\n\"\n        \"    nMinVer      = %d\\n\"\n        \"    nMaxVer      = %d\\n\"\n        \"    setSubVer    = %s\\n\"\n        \"    nPriority    = %d\\n\"\n        \"    strComment   = \\\"%s\\\"\\n\"\n        \"    strStatusBar = \\\"%s\\\"\\n\"\n        \")\\n\",\n        nVersion,\n        nRelayUntil,\n        nExpiration,\n        nID,\n        nCancel,\n        strSetCancel,\n        nMinVer,\n        nMaxVer,\n        strSetSubVer,\n        nPriority,\n        strComment,\n        strStatusBar);\n}\n\nvoid CAlert::SetNull()\n{\n    CUnsignedAlert::SetNull();\n    vchMsg.clear();\n    vchSig.clear();\n}\n\nbool CAlert::IsNull() const\n{\n    return (nExpiration == 0);\n}\n\nuint256 CAlert::GetHash() const\n{\n    return Hash(this->vchMsg.begin(), this->vchMsg.end());\n}\n\nbool CAlert::IsInEffect() const\n{\n    return (GetAdjustedTime() < nExpiration);\n}\n\nbool CAlert::Cancels(const CAlert& alert) const\n{\n    if (!IsInEffect())\n        return false; // this was a no-op before 31403\n    return (alert.nID <= nCancel || setCancel.count(alert.nID));\n}\n\nbool CAlert::AppliesTo(int _nVersion, const std::string& strSubVerIn) const\n{\n    // TODO: rework for client-version-embedded-in-strSubVer ?\n    return (IsInEffect() &&\n            nMinVer <= _nVersion && _nVersion <= nMaxVer &&\n            (setSubVer.empty() || setSubVer.count(strSubVerIn)));\n}\n\nbool CAlert::AppliesToMe() const\n{\n    return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));\n}\n\nbool CAlert::RelayTo(CNode* pnode) const\n{\n    if (!IsInEffect())\n        return false;\n    // don't relay to nodes which haven't sent their version message\n    if (pnode->nVersion == 0)\n        return false;\n    // returns true if wasn't already contained in the set\n    if (pnode->setKnown.insert(GetHash()).second)\n    {\n        if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||\n            AppliesToMe() ||\n            GetAdjustedTime() < nRelayUntil)\n        {\n            g_connman->PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::ALERT, *this));\n            return true;\n        }\n    }\n    return false;\n}\n\nbool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const\n{\n    CPubKey key(alertKey);\n    if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))\n        return error(\"CAlert::CheckSignature(): verify signature failed\");\n\n    // Now unserialize the data\n    CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);\n    sMsg >> *(CUnsignedAlert*)this;\n    return true;\n}\n\nCAlert CAlert::getAlertByHash(const uint256 &hash)\n{\n    CAlert retval;\n    {\n        LOCK(cs_mapAlerts);\n        std::map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);\n        if(mi != mapAlerts.end())\n            retval = mi->second;\n    }\n    return retval;\n}\n\nbool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)\n{\n    if (!CheckSignature(alertKey))\n        return false;\n    if (!IsInEffect())\n        return false;\n\n    // alert.nID=max is reserved for if the alert key is\n    // compromised. It must have a pre-defined message,\n    // must never expire, must apply to all versions,\n    // and must cancel all previous\n    // alerts or it will be ignored (so an attacker can't\n    // send an \"everything is OK, don't panic\" version that\n    // cannot be overridden):\n    int maxInt = std::numeric_limits<int>::max();\n    if (nID == maxInt)\n    {\n        if (!(\n                nExpiration == maxInt &&\n                nCancel == (maxInt-1) &&\n                nMinVer == 0 &&\n                nMaxVer == maxInt &&\n                setSubVer.empty() &&\n                nPriority == maxInt &&\n                strStatusBar == \"URGENT: Alert key compromised, upgrade required\"\n                ))\n            return false;\n    }\n\n    {\n        LOCK(cs_mapAlerts);\n        // Cancel previous alerts\n        for (std::map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)\n        {\n            const CAlert& alert = (*mi).second;\n            if (Cancels(alert))\n            {\n                LogPrint(BCLog::ALERT, \"cancelling alert %d\\n\", alert.nID);\n                uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);\n                mapAlerts.erase(mi++);\n            }\n            else if (!alert.IsInEffect())\n            {\n                LogPrint(BCLog::ALERT, \"expiring alert %d\\n\", alert.nID);\n                uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);\n                mapAlerts.erase(mi++);\n            }\n            else\n                mi++;\n        }\n\n        // Check if this alert has been cancelled\n        for (const auto& [alertHash, alert] : mapAlerts)\n        {\n            (unused) alertHash;\n            if (alert.Cancels(*this))\n            {\n                LogPrint(BCLog::ALERT, \"alert already cancelled by %d\\n\", alert.nID);\n                return false;\n            }\n        }\n\n        // Add to mapAlerts\n        mapAlerts.insert(std::pair(GetHash(), *this));\n        // Notify UI and -alertnotify if it applies to me\n        if(AppliesToMe())\n        {\n            uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);\n            Notify(strStatusBar, fThread);\n        }\n    }\n\n    LogPrint(BCLog::ALERT, \"accepted alert %d, AppliesToMe()=%d\\n\", nID, AppliesToMe());\n    return true;\n}\n\nvoid CAlert::Notify(const std::string& strMessage, bool fThread, bool fUI)\n{\n    bool notifyCallback = true;\n    std::string strCmd = GetArg(\"-alertnotify\", \"\");\n    if (strCmd.empty())\n        notifyCallback = false;\n\n    if (!fUI && !notifyCallback)\n        return;\n\n    // Alert text should be plain ascii coming from a trusted source, but to\n    // be safe we first strip anything not in safeChars, then add single quotes around\n    // the whole string before passing it to the shell:\n    std::string singleQuote(\"'\");\n    std::string safeStatusCallback = SanitizeString(strMessage);\n    safeStatusCallback = singleQuote+safeStatusCallback+singleQuote;\n    boost::replace_all(strCmd, \"%s\", safeStatusCallback);\n\n    if (fUI)\n    {\n        uiInterface.NotifyUIAlertChanged(strMessage);\n    }\n    if (notifyCallback)\n    {\n        if (fThread)\n            std::thread t(runCommand, strCmd); // thread runs free\n        else\n            runCommand(strCmd);\n    }\n}\n"
  },
  {
    "path": "src/alert.h",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef ALERT_H\n#define ALERT_H\n\n#include \"serialize.h\"\n#include \"sync.h\"\n\n#include <map>\n#include <set>\n#include <stdint.h>\n#include <string>\n\nclass CAlert;\nclass CNode;\nclass uint256;\n\nextern std::map<uint256, CAlert> mapAlerts;\nextern RecursiveMutex cs_mapAlerts;\n\n/** Alerts are for notifying old versions if they become too obsolete and\n * need to upgrade.  The message is displayed in the status bar.\n * Alert messages are broadcast as a vector of signed data.  Unserializing may\n * not read the entire buffer if the alert is for a newer version, but older\n * versions can still relay the original data.\n */\nclass CUnsignedAlert\n{\npublic:\n    int nVersion;\n    int64_t nRelayUntil;      // when newer nodes stop relaying to newer nodes\n    int64_t nExpiration;\n    int nID;\n    int nCancel;\n    std::set<int> setCancel;\n    int nMinVer;            // lowest version inclusive\n    int nMaxVer;            // highest version inclusive\n    std::set<std::string> setSubVer;  // empty matches all\n    int nPriority;\n\n    // Actions\n    std::string strComment;\n    std::string strStatusBar;\n    std::string strReserved;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(this->nVersion);\n        nVersion = this->nVersion;\n        READWRITE(nRelayUntil);\n        READWRITE(nExpiration);\n        READWRITE(nID);\n        READWRITE(nCancel);\n        READWRITE(setCancel);\n        READWRITE(nMinVer);\n        READWRITE(nMaxVer);\n        READWRITE(setSubVer);\n        READWRITE(nPriority);\n\n        READWRITE(LIMITED_STRING(strComment, 65536));\n        READWRITE(LIMITED_STRING(strStatusBar, 256));\n        READWRITE(LIMITED_STRING(strReserved, 256));\n    }\n\n    void SetNull();\n\n    std::string ToString() const;\n};\n\n/** An alert is a combination of a serialized CUnsignedAlert and a signature. */\nclass CAlert : public CUnsignedAlert\n{\npublic:\n    std::vector<unsigned char> vchMsg;\n    std::vector<unsigned char> vchSig;\n\n    CAlert()\n    {\n        SetNull();\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITECOMPACTSIZEVECTOR(vchMsg);\n        READWRITECOMPACTSIZEVECTOR(vchSig);\n    }\n\n    void SetNull();\n    bool IsNull() const;\n    uint256 GetHash() const;\n    bool IsInEffect() const;\n    bool Cancels(const CAlert& alert) const;\n    bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;\n    bool AppliesToMe() const;\n    bool RelayTo(CNode* pnode) const;\n    bool CheckSignature(const std::vector<unsigned char>& alertKey) const;\n    bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread\n\n    //! Notify the user via a callback that something is wrong\n    //! When fUI is true also notify via UI (If UI is open)\n    static void Notify(const std::string& strMessage, bool fThread, bool fUI = false);\n\n    /*\n     * Get copy of (active) alert object by hash. Returns a null alert if it is not found.\n     */\n    static CAlert getAlertByHash(const uint256 &hash);\n};\n\n#endif\n"
  },
  {
    "path": "src/amount.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef AMOUNT_H\n#define AMOUNT_H\n\n#include <stdint.h>\n\n/** Amount in satoshis (Can be negative) */\ntypedef int64_t CAmount;\n\nstatic const CAmount COIN          = 100000000;\nstatic const CAmount DECI          =  10000000;\nstatic const CAmount CENT          =   1000000;\nstatic const CAmount DECICENT      =    100000;\nstatic const CAmount CENTICENT     =     10000;\nstatic const CAmount MILLICENT     =      1000;\nstatic const CAmount MICROCOIN     =       100;\n\n\n/** No amount larger than this (in satoshi) is valid.\n *\n * Note that this constant is *not* the total money supply, but\n * rather a sanity check. As this sanity check is used by consensus-critical\n * validation code, the exact value of the MAX_MONEY constant is consensus\n * critical; in unusual circumstances like a(nother) overflow bug that allowed\n * for the creation of coins out of thin air modification could lead to a fork.\n * */\n//fixme: (PHASE5) Relook at this constant - I don't think the value here is actually right/ideal.\nstatic const CAmount MAX_MONEY = 1680000000 * COIN;\ninline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }\n\n#endif\n"
  },
  {
    "path": "src/appname.h",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef APPNAME_H\n#define APPNAME_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#define GLOBAL_APPNAME \"Munt\"\n#define GLOBAL_APP_URIPREFIX \"munt\"\n#define GLOBAL_COIN_CODE \"MUNT\"\n\n#endif\n"
  },
  {
    "path": "src/arith_uint256.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"arith_uint256.h\"\n\n#include \"uint256.h\"\n#include \"util/strencodings.h\"\n#include \"crypto/common.h\"\n\n#include <stdio.h>\n#include <string.h>\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>::base_uint(const std::string& str)\n{\n    SetHex(str);\n}\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift)\n{\n    base_uint<BITS> a(*this);\n    for (int i = 0; i < WIDTH; i++)\n        pn[i] = 0;\n    int k = shift / 32;\n    shift = shift % 32;\n    for (int i = 0; i < WIDTH; i++) {\n        if (i + k + 1 < WIDTH && shift != 0)\n            pn[i + k + 1] |= (a.pn[i] >> (32 - shift));\n        if (i + k < WIDTH)\n            pn[i + k] |= (a.pn[i] << shift);\n    }\n    return *this;\n}\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift)\n{\n    base_uint<BITS> a(*this);\n    for (int i = 0; i < WIDTH; i++)\n        pn[i] = 0;\n    int k = shift / 32;\n    shift = shift % 32;\n    for (int i = 0; i < WIDTH; i++) {\n        if (i - k - 1 >= 0 && shift != 0)\n            pn[i - k - 1] |= (a.pn[i] << (32 - shift));\n        if (i - k >= 0)\n            pn[i - k] |= (a.pn[i] >> shift);\n    }\n    return *this;\n}\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32)\n{\n    uint64_t carry = 0;\n    for (int i = 0; i < WIDTH; i++) {\n        uint64_t n = carry + (uint64_t)b32 * pn[i];\n        pn[i] = n & 0xffffffff;\n        carry = n >> 32;\n    }\n    return *this;\n}\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b)\n{\n    base_uint<BITS> a = *this;\n    *this = 0;\n    for (int j = 0; j < WIDTH; j++) {\n        uint64_t carry = 0;\n        for (int i = 0; i + j < WIDTH; i++) {\n            uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i];\n            pn[i + j] = n & 0xffffffff;\n            carry = n >> 32;\n        }\n    }\n    return *this;\n}\n\ntemplate <unsigned int BITS>\nbase_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b)\n{\n    base_uint<BITS> div = b;     // make a copy, so we can shift.\n    base_uint<BITS> num = *this; // make a copy, so we can subtract.\n    *this = 0;                   // the quotient.\n    int num_bits = num.bits();\n    int div_bits = div.bits();\n    if (div_bits == 0)\n        throw uint_error(\"Division by zero\");\n    if (div_bits > num_bits) // the result is certainly 0.\n        return *this;\n    int shift = num_bits - div_bits;\n    div <<= shift; // shift so that div and num align.\n    while (shift >= 0) {\n        if (num >= div) {\n            num -= div;\n            pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result.\n        }\n        div >>= 1; // shift back.\n        shift--;\n    }\n    // num now contains the remainder of the division.\n    return *this;\n}\n\ntemplate <unsigned int BITS>\nint base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const\n{\n    for (int i = WIDTH - 1; i >= 0; i--) {\n        if (pn[i] < b.pn[i])\n            return -1;\n        if (pn[i] > b.pn[i])\n            return 1;\n    }\n    return 0;\n}\n\ntemplate <unsigned int BITS>\nbool base_uint<BITS>::EqualTo(uint64_t b) const\n{\n    for (int i = WIDTH - 1; i >= 2; i--) {\n        if (pn[i])\n            return false;\n    }\n    if (pn[1] != (b >> 32))\n        return false;\n    if (pn[0] != (b & 0xfffffffful))\n        return false;\n    return true;\n}\n\ntemplate <unsigned int BITS>\ndouble base_uint<BITS>::getdouble() const\n{\n    double ret = 0.0;\n    double fact = 1.0;\n    for (int i = 0; i < WIDTH; i++) {\n        ret += fact * pn[i];\n        fact *= 4294967296.0;\n    }\n    return ret;\n}\n\ntemplate <unsigned int BITS>\nstd::string base_uint<BITS>::GetHex() const\n{\n    return ArithToUint256(*this).GetHex();\n}\n\ntemplate <unsigned int BITS>\nvoid base_uint<BITS>::SetHex(const char* psz)\n{\n    *this = UintToArith256(uint256S(psz));\n}\n\ntemplate <unsigned int BITS>\nvoid base_uint<BITS>::SetHex(const std::string& str)\n{\n    SetHex(str.c_str());\n}\n\ntemplate <unsigned int BITS>\nstd::string base_uint<BITS>::ToString() const\n{\n    return (GetHex());\n}\n\ntemplate <unsigned int BITS>\nunsigned int base_uint<BITS>::bits() const\n{\n    for (int pos = WIDTH - 1; pos >= 0; pos--) {\n        if (pn[pos]) {\n            for (int nbits = 31; nbits > 0; nbits--) {\n                if (pn[pos] & 1 << nbits)\n                    return 32 * pos + nbits + 1;\n            }\n            return 32 * pos + 1;\n        }\n    }\n    return 0;\n}\n\n// Explicit instantiations for base_uint<256>\ntemplate base_uint<256>::base_uint(const std::string&);\ntemplate base_uint<256>& base_uint<256>::operator<<=(unsigned int);\ntemplate base_uint<256>& base_uint<256>::operator>>=(unsigned int);\ntemplate base_uint<256>& base_uint<256>::operator*=(uint32_t b32);\ntemplate base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b);\ntemplate base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b);\ntemplate int base_uint<256>::CompareTo(const base_uint<256>&) const;\ntemplate bool base_uint<256>::EqualTo(uint64_t) const;\ntemplate double base_uint<256>::getdouble() const;\ntemplate std::string base_uint<256>::GetHex() const;\ntemplate std::string base_uint<256>::ToString() const;\ntemplate void base_uint<256>::SetHex(const char*);\ntemplate void base_uint<256>::SetHex(const std::string&);\ntemplate unsigned int base_uint<256>::bits() const;\n\n// This implementation directly uses shifts instead of going\n// through an intermediate MPI representation.\narith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow)\n{\n    int nSize = nCompact >> 24;\n    uint32_t nWord = nCompact & 0x007fffff;\n    if (nSize <= 3) {\n        nWord >>= 8 * (3 - nSize);\n        *this = nWord;\n    } else {\n        *this = nWord;\n        *this <<= 8 * (nSize - 3);\n    }\n    if (pfNegative)\n        *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;\n    if (pfOverflow)\n        *pfOverflow = nWord != 0 && ((nSize > 34) ||\n                                     (nWord > 0xff && nSize > 33) ||\n                                     (nWord > 0xffff && nSize > 32));\n    return *this;\n}\n\nuint32_t arith_uint256::GetCompact(bool fNegative) const\n{\n    int nSize = (bits() + 7) / 8;\n    uint32_t nCompact = 0;\n    if (nSize <= 3) {\n        nCompact = GetLow64() << 8 * (3 - nSize);\n    } else {\n        arith_uint256 bn = *this >> 8 * (nSize - 3);\n        nCompact = bn.GetLow64();\n    }\n    // The 0x00800000 bit denotes the sign.\n    // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.\n    if (nCompact & 0x00800000) {\n        nCompact >>= 8;\n        nSize++;\n    }\n    assert((nCompact & ~0x007fffff) == 0);\n    assert(nSize < 256);\n    nCompact |= nSize << 24;\n    nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0);\n    return nCompact;\n}\n\nuint256 ArithToUint256(const arith_uint256 &a)\n{\n    uint256 b;\n    for(int x=0; x<a.WIDTH; ++x)\n        WriteLE32(b.begin() + x*4, a.pn[x]);\n    return b;\n}\narith_uint256 UintToArith256(const uint256 &a)\n{\n    arith_uint256 b;\n    for(int x=0; x<b.WIDTH; ++x)\n        b.pn[x] = ReadLE32(a.begin() + x*4);\n    return b;\n}\n"
  },
  {
    "path": "src/arith_uint256.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ARITH_UINT256_H\n#define ARITH_UINT256_H\n\n#include <assert.h>\n#include <cstring>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <vector>\n\nclass uint256;\n\nclass uint_error : public std::runtime_error {\npublic:\n    explicit uint_error(const std::string& str) : std::runtime_error(str) {}\n};\n\n/** Template base class for unsigned big integers. */\ntemplate<unsigned int BITS>\nclass base_uint\n{\nprotected:\n    enum { WIDTH=BITS/32 };\n    uint32_t pn[WIDTH];\npublic:\n\n    base_uint()\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] = 0;\n    }\n\n    base_uint(const base_uint& b)\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] = b.pn[i];\n    }\n\n    base_uint& operator=(const base_uint& b)\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] = b.pn[i];\n        return *this;\n    }\n\n    base_uint(uint64_t b)\n    {\n        pn[0] = (unsigned int)b;\n        pn[1] = (unsigned int)(b >> 32);\n        for (int i = 2; i < WIDTH; i++)\n            pn[i] = 0;\n    }\n\n    explicit base_uint(const std::string& str);\n\n    bool operator!() const\n    {\n        for (int i = 0; i < WIDTH; i++)\n            if (pn[i] != 0)\n                return false;\n        return true;\n    }\n\n    const base_uint operator~() const\n    {\n        base_uint ret;\n        for (int i = 0; i < WIDTH; i++)\n            ret.pn[i] = ~pn[i];\n        return ret;\n    }\n\n    const base_uint operator-() const\n    {\n        base_uint ret;\n        for (int i = 0; i < WIDTH; i++)\n            ret.pn[i] = ~pn[i];\n        ret++;\n        return ret;\n    }\n\n    double getdouble() const;\n\n    base_uint& operator=(uint64_t b)\n    {\n        pn[0] = (unsigned int)b;\n        pn[1] = (unsigned int)(b >> 32);\n        for (int i = 2; i < WIDTH; i++)\n            pn[i] = 0;\n        return *this;\n    }\n\n    base_uint& operator^=(const base_uint& b)\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] ^= b.pn[i];\n        return *this;\n    }\n\n    base_uint& operator&=(const base_uint& b)\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] &= b.pn[i];\n        return *this;\n    }\n\n    base_uint& operator|=(const base_uint& b)\n    {\n        for (int i = 0; i < WIDTH; i++)\n            pn[i] |= b.pn[i];\n        return *this;\n    }\n\n    base_uint& operator^=(uint64_t b)\n    {\n        pn[0] ^= (unsigned int)b;\n        pn[1] ^= (unsigned int)(b >> 32);\n        return *this;\n    }\n\n    base_uint& operator|=(uint64_t b)\n    {\n        pn[0] |= (unsigned int)b;\n        pn[1] |= (unsigned int)(b >> 32);\n        return *this;\n    }\n\n    base_uint& operator<<=(unsigned int shift);\n    base_uint& operator>>=(unsigned int shift);\n\n    base_uint& operator+=(const base_uint& b)\n    {\n        uint64_t carry = 0;\n        for (int i = 0; i < WIDTH; i++)\n        {\n            uint64_t n = carry + pn[i] + b.pn[i];\n            pn[i] = n & 0xffffffff;\n            carry = n >> 32;\n        }\n        return *this;\n    }\n\n    base_uint& operator-=(const base_uint& b)\n    {\n        *this += -b;\n        return *this;\n    }\n\n    base_uint& operator+=(uint64_t b64)\n    {\n        base_uint b;\n        b = b64;\n        *this += b;\n        return *this;\n    }\n\n    base_uint& operator-=(uint64_t b64)\n    {\n        base_uint b;\n        b = b64;\n        *this += -b;\n        return *this;\n    }\n\n    base_uint& operator*=(uint32_t b32);\n    base_uint& operator*=(const base_uint& b);\n    base_uint& operator/=(const base_uint& b);\n\n    base_uint& operator++()\n    {\n        // prefix operator\n        int i = 0;\n        while (++pn[i] == 0 && i < WIDTH-1)\n            i++;\n        return *this;\n    }\n\n    const base_uint operator++(int)\n    {\n        // postfix operator\n        const base_uint ret = *this;\n        ++(*this);\n        return ret;\n    }\n\n    base_uint& operator--()\n    {\n        // prefix operator\n        int i = 0;\n        while (--pn[i] == (uint32_t)-1 && i < WIDTH-1)\n            i++;\n        return *this;\n    }\n\n    const base_uint operator--(int)\n    {\n        // postfix operator\n        const base_uint ret = *this;\n        --(*this);\n        return ret;\n    }\n\n    int CompareTo(const base_uint& b) const;\n    bool EqualTo(uint64_t b) const;\n\n    friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; }\n    friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; }\n    friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; }\n    friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; }\n    friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; }\n    friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; }\n    friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; }\n    friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; }\n    friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; }\n    friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; }\n    friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; }\n    friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; }\n    friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; }\n    friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; }\n    friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; }\n    friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; }\n    friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); }\n    friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); }\n\n    std::string GetHex() const;\n    void SetHex(const char* psz);\n    void SetHex(const std::string& str);\n    std::string ToString() const;\n\n    unsigned int size() const\n    {\n        return sizeof(pn);\n    }\n\n    /**\n     * Returns the position of the highest bit set plus one, or zero if the\n     * value is zero.\n     */\n    unsigned int bits() const;\n\n    uint64_t GetLow64() const\n    {\n        assert(WIDTH >= 2);\n        return pn[0] | (uint64_t)pn[1] << 32;\n    }\n};\n\n/** 256-bit unsigned big integer. */\nclass arith_uint256 : public base_uint<256> {\npublic:\n    arith_uint256() {}\n    arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {}\n    arith_uint256(uint64_t b) : base_uint<256>(b) {}\n    explicit arith_uint256(const std::string& str) : base_uint<256>(str) {}\n\n    /**\n     * The \"compact\" format is a representation of a whole\n     * number N using an unsigned 32bit number similar to a\n     * floating point format.\n     * The most significant 8 bits are the unsigned exponent of base 256.\n     * This exponent can be thought of as \"number of bytes of N\".\n     * The lower 23 bits are the mantissa.\n     * Bit number 24 (0x800000) represents the sign of N.\n     * N = (-1^sign) * mantissa * 256^(exponent-3)\n     *\n     * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn().\n     * MPI uses the most significant bit of the first byte as sign.\n     * Thus 0x1234560000 is compact (0x05123456)\n     * and  0xc0de000000 is compact (0x0600c0de)\n     *\n     * Bitcoin only uses this \"compact\" format for encoding difficulty\n     * targets, which are unsigned 256bit quantities.  Thus, all the\n     * complexities of the sign bit and using base 256 are probably an\n     * implementation accident.\n     */\n    arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL);\n    uint32_t GetCompact(bool fNegative = false) const;\n\n    friend uint256 ArithToUint256(const arith_uint256 &);\n    friend arith_uint256 UintToArith256(const uint256 &);\n};\n\nuint256 ArithToUint256(const arith_uint256 &);\narith_uint256 UintToArith256(const uint256 &);\n\n#endif\n"
  },
  {
    "path": "src/attributes.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_ATTRIBUTES_H\n#define BITCOIN_ATTRIBUTES_H\n\n#if defined(__clang__)\n#  if __has_attribute(lifetimebound)\n#    define LIFETIMEBOUND [[clang::lifetimebound]]\n#  else\n#    define LIFETIMEBOUND\n#  endif\n#else\n#  define LIFETIMEBOUND\n#endif\n\n#endif // BITCOIN_ATTRIBUTES_H\n"
  },
  {
    "path": "src/base58.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"base58.h\"\n\n#include \"hash.h\"\n#include \"uint256.h\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n#include <vector>\n#include <string>\n#include <boost/variant/apply_visitor.hpp>\n#include <boost/variant/static_visitor.hpp>\n\n/** All alphanumeric characters except for \"0\", \"I\", \"O\", and \"l\" */\nstatic const char* pszBase58 = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\nbool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)\n{\n    // Skip leading spaces.\n    while (*psz && isspace(*psz))\n        psz++;\n    // Skip and count leading '1's.\n    int zeroes = 0;\n    int length = 0;\n    while (*psz == '1') {\n        zeroes++;\n        psz++;\n    }\n    // Allocate enough space in big-endian base256 representation.\n    int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.\n    std::vector<unsigned char> b256(size);\n    // Process the characters.\n    while (*psz && !isspace(*psz)) {\n        // Decode base58 character\n        const char* ch = strchr(pszBase58, *psz);\n        if (ch == NULL)\n            return false;\n        // Apply \"b256 = b256 * 58 + ch\".\n        int carry = ch - pszBase58;\n        int i = 0;\n        for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {\n            carry += 58 * (*it);\n            *it = carry % 256;\n            carry /= 256;\n        }\n        assert(carry == 0);\n        length = i;\n        psz++;\n    }\n    // Skip trailing spaces.\n    while (isspace(*psz))\n        psz++;\n    if (*psz != 0)\n        return false;\n    // Skip leading zeroes in b256.\n    std::vector<unsigned char>::iterator it = b256.begin() + (size - length);\n    while (it != b256.end() && *it == 0)\n        it++;\n    // Copy result into output vector.\n    vch.reserve(zeroes + (b256.end() - it));\n    vch.assign(zeroes, 0x00);\n    while (it != b256.end())\n        vch.push_back(*(it++));\n    return true;\n}\n\nstd::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)\n{\n    // Skip & count leading zeroes.\n    int zeroes = 0;\n    int length = 0;\n    while (pbegin != pend && *pbegin == 0) {\n        pbegin++;\n        zeroes++;\n    }\n    // Allocate enough space in big-endian base58 representation.\n    int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.\n    std::vector<unsigned char> b58(size);\n    // Process the bytes.\n    while (pbegin != pend) {\n        int carry = *pbegin;\n        int i = 0;\n        // Apply \"b58 = b58 * 256 + ch\".\n        for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {\n            carry += 256 * (*it);\n            *it = carry % 58;\n            carry /= 58;\n        }\n\n        assert(carry == 0);\n        length = i;\n        pbegin++;\n    }\n    // Skip leading zeroes in base58 result.\n    std::vector<unsigned char>::iterator it = b58.begin() + (size - length);\n    while (it != b58.end() && *it == 0)\n        it++;\n    // Translate the result into a string.\n    std::string str;\n    str.reserve(zeroes + (b58.end() - it));\n    str.assign(zeroes, '1');\n    while (it != b58.end())\n        str += pszBase58[*(it++)];\n    return str;\n}\n\nstd::string EncodeBase58(const std::vector<unsigned char>& vch)\n{\n    return EncodeBase58(&vch[0], &vch[0] + vch.size());\n}\n\nbool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)\n{\n    return DecodeBase58(str.c_str(), vchRet);\n}\n\nstd::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)\n{\n    // add 4-byte hash check to the end\n    std::vector<unsigned char> vch(vchIn);\n    uint256 hash = Hash(vch.begin(), vch.end());\n    vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);\n    return EncodeBase58(vch);\n}\n\nbool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)\n{\n    if (!DecodeBase58(psz, vchRet) ||\n        (vchRet.size() < 4)) {\n        vchRet.clear();\n        return false;\n    }\n    // re-calculate the checksum, ensure it matches the included 4-byte checksum\n    uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);\n    if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {\n        vchRet.clear();\n        return false;\n    }\n    vchRet.resize(vchRet.size() - 4);\n    return true;\n}\n\nbool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)\n{\n    return DecodeBase58Check(str.c_str(), vchRet);\n}\n\nCBase58Data::CBase58Data()\n{\n    vchVersion.clear();\n    vchData.clear();\n}\n\nvoid CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)\n{\n    vchVersion = vchVersionIn;\n    vchData.resize(nSize);\n    if (!vchData.empty())\n        memcpy(&vchData[0], pdata, nSize);\n}\n\nvoid CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)\n{\n    SetData(vchVersionIn, (void*)pbegin, pend - pbegin);\n}\n\nbool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)\n{\n    std::vector<unsigned char> vchTemp;\n    bool rc58 = DecodeBase58Check(psz, vchTemp);\n    if ((!rc58) || (vchTemp.size() < nVersionBytes)) {\n        vchData.clear();\n        vchVersion.clear();\n        return false;\n    }\n    vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);\n    vchData.resize(vchTemp.size() - nVersionBytes);\n    if (!vchData.empty())\n        memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());\n    memory_cleanse(&vchTemp[0], vchTemp.size());\n    return true;\n}\n\nbool CBase58Data::SetString(const std::string& str)\n{\n    return SetString(str.c_str());\n}\n\nstd::string CBase58Data::ToString() const\n{\n    std::vector<unsigned char> vch = vchVersion;\n    vch.insert(vch.end(), vchData.begin(), vchData.end());\n    return EncodeBase58Check(vch);\n}\n\nint CBase58Data::CompareTo(const CBase58Data& b58) const\n{\n    if (vchVersion < b58.vchVersion)\n        return -1;\n    if (vchVersion > b58.vchVersion)\n        return 1;\n    if (vchData < b58.vchData)\n        return -1;\n    if (vchData > b58.vchData)\n        return 1;\n    return 0;\n}\n\nnamespace\n{\nclass CNativeAddressVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    CNativeAddress* addr;\n\npublic:\n    CNativeAddressVisitor(CNativeAddress* addrIn) : addr(addrIn) {}\n\n    bool operator()(const CKeyID& id) const { return addr->Set(id); }\n    bool operator()(const CScriptID& id) const { return addr->Set(id); }\n    bool operator()(const CNoDestination& no) const { return false; }\n    bool operator()(const CPoW2WitnessDestination& dest) const { return addr->Set(dest.spendingKey, dest.witnessKey); }\n};\n\n} // anon namespace\n\nbool CNativeAddress::Set(const CKeyID& spendingKeyID, const CKeyID& witnessKeyID)\n{\n    std::vector<unsigned char> vchData;\n    vchData.reserve(40);\n    vchData.insert(vchData.end(), spendingKeyID.begin(), spendingKeyID.end());\n    vchData.insert(vchData.end(), witnessKeyID.begin(), witnessKeyID.end());\n\n    SetData(Params().Base58Prefix(CChainParams::POW2_WITNESS_ADDRESS), &vchData[0], 40);\n    return true;\n}\n\nbool CNativeAddress::Set(const CKeyID& id)\n{\n    SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);\n    return true;\n}\n\nbool CNativeAddress::Set(const CScriptID& id)\n{\n    SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);\n    return true;\n}\n\nbool CNativeAddress::Set(const CTxDestination& dest)\n{\n    return boost::apply_visitor(CNativeAddressVisitor(this), dest);\n}\n\nbool CNativeAddress::IsValid() const\n{\n    return IsValid(Params());\n}\n\nbool CNativeAddress::IsValid(const CChainParams& params) const\n{\n    if (IsValidWitness(params))\n        return true;\n\n    bool fCorrectSize = vchData.size() == 20;\n    bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||\n                         vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);\n    return fCorrectSize && fKnownVersion;\n}\n\nbool CNativeAddress::IsValidWitness() const\n{\n    return IsValidWitness(Params());\n}\n\nbool CNativeAddress::IsValidWitness(const CChainParams& params) const\n{\n    if (vchData.size() == 40 && vchVersion == params.Base58Prefix(CChainParams::POW2_WITNESS_ADDRESS))\n        return true;\n    return false;\n}\n\nbool CNativeAddress::IsValidBitcoin() const\n{\n    bool fCorrectSize = vchData.size() == 20;\n    bool fKnownVersion = (vchVersion == std::vector<unsigned char>(1, 0) || vchVersion == std::vector<unsigned char>(1, 5));\n    return fCorrectSize && fKnownVersion;\n}\n\nCTxDestination CNativeAddress::Get() const\n{\n    if (!IsValid())\n        return CNoDestination();\n    uint160 id;\n    memcpy(&id, &vchData[0], 20);\n    if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))\n        return CKeyID(id);\n    else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))\n        return CScriptID(id);\n    else if (vchVersion == Params().Base58Prefix(CChainParams::POW2_WITNESS_ADDRESS))\n    {\n        uint160 idWitnessKey;\n        memcpy(&idWitnessKey, &vchData[20], 20);\n        return CPoW2WitnessDestination(id, idWitnessKey);\n    }\n    else\n        return CNoDestination();\n}\n\nbool CNativeAddress::GetKeyID(CKeyID& keyID, CKeyID* pSecondaryKeyID) const\n{\n    if (!IsValid())\n        return false;\n    uint160 id;\n    memcpy(&id, &vchData[0], 20);\n    if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))\n    {\n        keyID = CKeyID(id);\n        return true;\n    }\n    if (!IsValidWitness(Params()))\n        return false;\n    if (vchVersion == Params().Base58Prefix(CChainParams::POW2_WITNESS_ADDRESS))\n    {\n        uint160 idWitnessKey;\n        memcpy(&idWitnessKey, &vchData[20], 20);\n        keyID = idWitnessKey;\n        if (pSecondaryKeyID)\n        {\n            *pSecondaryKeyID = id;\n        }\n        return true;\n    }\n    return false;\n}\n\nbool CNativeAddress::IsScript() const\n{\n    return IsValid() && (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS));\n}\n\nvoid CEncodedSecretKey::SetKey(const CKey& vchSecret)\n{\n    assert(vchSecret.IsValid());\n    SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());\n    if (vchSecret.IsCompressed())\n        vchData.push_back(1);\n}\n\nCKey CEncodedSecretKey::GetKey()\n{\n    CKey ret;\n    assert(vchData.size() >= 32);\n    ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);\n    return ret;\n}\n\nbool CEncodedSecretKey::IsValid() const\n{\n    bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);\n    bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);\n    return fExpectedFormat && fCorrectVersion;\n}\n\nbool CEncodedSecretKey::SetString(const char* pszSecret)\n{\n    return CBase58Data::SetString(pszSecret) && IsValid();\n}\n\nbool CEncodedSecretKey::SetString(const std::string& strSecret)\n{\n    return SetString(strSecret.c_str());\n}\n"
  },
  {
    "path": "src/base58.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n/**\n * Why base-58 instead of standard base-64 encoding?\n * - Don't want 0OIl characters that look the same in some fonts and\n *      could be used to create visually identical looking data.\n * - A string with non-alphanumeric characters is not as easily accepted as input.\n * - E-mail usually won't line-break if there's no punctuation to break at.\n * - Double-clicking selects the whole string as one word if it's all alphanumeric.\n */\n#ifndef BASE58_H\n#define BASE58_H\n\n#include \"chainparams.h\"\n#include \"key.h\"\n#include \"pubkey.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"support/allocators/zeroafterfree.h\"\n#include \"appname.h\"\n\n#include <string>\n#include <vector>\n\n#include <boost/algorithm/string/split.hpp>\n#include <boost/algorithm/string.hpp>\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and ends_with()\n\n/**\n * Encode a byte sequence as a base58-encoded string.\n * pbegin and pend cannot be NULL, unless both are.\n */\nstd::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend);\n\n/**\n * Encode a byte vector as a base58-encoded string\n */\nstd::string EncodeBase58(const std::vector<unsigned char>& vch);\n\n/**\n * Decode a base58-encoded string (psz) into a byte vector (vchRet).\n * return true if decoding is successful.\n * psz cannot be NULL.\n */\nbool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);\n\n/**\n * Decode a base58-encoded string (str) into a byte vector (vchRet).\n * return true if decoding is successful.\n */\nbool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet);\n\n/**\n * Encode a byte vector into a base58-encoded string, including checksum\n */\nstd::string EncodeBase58Check(const std::vector<unsigned char>& vchIn);\n\n/**\n * Decode a base58-encoded string (psz) that includes a checksum into a byte\n * vector (vchRet), return true if decoding is successful\n */\ninline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);\n\n/**\n * Decode a base58-encoded string (str) that includes a checksum into a byte\n * vector (vchRet), return true if decoding is successful\n */\ninline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);\n\n/**\n * Base class for all base58-encoded data\n */\nclass CBase58Data\n{\nprotected:\n    //! the version byte(s)\n    std::vector<unsigned char> vchVersion;\n\n    //! the actually encoded data\n    typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;\n    vector_uchar vchData;\n\n    CBase58Data();\n    void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize);\n    void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend);\n\npublic:\n    bool SetString(const char* psz, unsigned int nVersionBytes = 1);\n    bool SetString(const std::string& str);\n    std::string ToString() const;\n    int CompareTo(const CBase58Data& b58) const;\n\n    bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }\n    bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }\n    bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }\n    bool operator< (const CBase58Data& b58) const { return CompareTo(b58) <  0; }\n    bool operator> (const CBase58Data& b58) const { return CompareTo(b58) >  0; }\n};\n\n/** base58-encoded addresses.\n * Public-key-hash-addresses have version 0 (or 111 testnet).\n * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.\n * Script-hash-addresses have version 5 (or 196 testnet).\n * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.\n */\nclass CNativeAddress : public CBase58Data {\npublic:\n    bool Set(const CKeyID& spendingKeyID, const CKeyID& witnessKeyID);\n    bool Set(const CKeyID &id);\n    bool Set(const CScriptID &id);\n    bool Set(const CTxDestination &dest);\n\n    //! Returns whether the address represents a valid address (this includes witness addresses as well)\n    bool IsValid() const;\n    bool IsValid(const CChainParams &params) const;\n\n    //! Returns whether the address represents a valid witness address as opposed to just a valid address.\n    bool IsValidWitness() const;\n    bool IsValidWitness(const CChainParams& params) const;\n\n    //! Returns whether the address represents a valid Bitcoin address, which can be used by third party payment integrations\n    bool IsValidBitcoin() const;\n\n    CNativeAddress() {}\n    CNativeAddress(const CTxDestination &dest) { Set(dest); }\n    CNativeAddress(const std::string& strAddress) { SetString(strAddress); }\n    CNativeAddress(const char* pszAddress) { SetString(pszAddress); }\n\n    CTxDestination Get() const;\n\n    //! Returns the keyID associated with the address \n    //! In the case of a witness address this is the 'witness key ID'\n    //! If 'pSecondaryKeyID' is passed in then this will be set to the 'spending key ID'\n    bool GetKeyID(CKeyID& keyID, CKeyID* pSecondaryKeyID=nullptr) const;\n\n    bool IsScript() const;\n\n    bool operator==(const CNativeAddress& otherAddress) const { return CBase58Data::CompareTo((CBase58Data)otherAddress) == 0; }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITECOMPACTSIZEVECTOR(vchVersion);\n        READWRITECOMPACTSIZEVECTOR(vchData);\n    }\n};\n\n/**\n * A base58-encoded secret key\n */\nclass CEncodedSecretKey : public CBase58Data\n{\npublic:\n    void SetKey(const CKey& vchSecret);\n    CKey GetKey();\n    bool IsValid() const;\n    bool SetString(const char* pszSecret);\n    bool SetString(const std::string& strSecret);\n\n    CEncodedSecretKey(const CKey& vchSecret) { SetKey(vchSecret); }\n    CEncodedSecretKey() {}\n};\n\n/**\n * A combination base58 and hex encoded secret extended key\n */\ntemplate <typename KeyType> class CEncodedSecretKeyExt \n{\npublic:\n    void SetKey(const KeyType& vchSecret) { key = vchSecret; }\n    KeyType GetKeyFromString()\n    {\n        //fixme: (Bitcoin) Strip creationTime and payAccount\n        KeyType retExt;\n\n        SecureString secretKey = SecureString(secret.begin(), secret.begin() + secret.find('-'));\n        SecureString secretCode = SecureString(secret.begin() + secret.find('-') + 1, secret.end());\n\n        std::vector<unsigned char> vchSecretKey;\n        std::vector<unsigned char> vchSecretCode;\n        DecodeBase58(secretKey.c_str(), vchSecretKey);\n        DecodeBase58(secretCode.c_str(), vchSecretCode);\n\n        if (vchSecretCode.size() == 32)\n        {\n            retExt.GetMutableKey().Set(vchSecretKey.begin(), vchSecretKey.end());\n            retExt.chaincode = uint256(vchSecretCode);\n        }\n        else\n        {\n            //fixme: (PHASE5) Better error handling here - though this should never happen.\n            assert(0);\n        }\n\n        return retExt;\n    }\n\n    bool SetString(const char* pszSecret)\n    {\n        secret = pszSecret;\n        return true;\n    }\n\n\n    bool SetString(const std::string& strSecret)\n    {\n        secret = strSecret;\n        return true;\n    }\n\n    CEncodedSecretKeyExt<KeyType>& SetCreationTime(std::string newCreationTime)\n    {\n        creationTime = newCreationTime;\n        return *this;\n    }\n\n    int64_t getCreationTime() const\n    {\n        if (creationTime.empty())\n        {\n            return -1;\n        }\n        else\n        {\n            return atoi64(creationTime);\n        }\n    }\n\n    CEncodedSecretKeyExt<KeyType>& SetPayAccount(std::string newPayAccount)\n    {\n        payAccount = newPayAccount;\n        return *this;\n    }\n\n    std::string getPayAccount()\n    {\n        return payAccount;\n    }\n\n    bool fromURIString(std::string uri)\n    {\n        std::string syncPrefix = GLOBAL_APP_URIPREFIX\"sync:\";\n        if (!boost::starts_with(uri, syncPrefix))\n            return false;\n\n        uri = std::string(uri.begin()+syncPrefix.length(),uri.end());\n        std::vector<unsigned char> vchSecretKey;\n        std::vector<unsigned char> vchSecretCode;\n        std::vector<unsigned char> vchCreationTime;\n\n        std::vector<std::string> vStrInputParts;\n        boost::split(vStrInputParts, uri, boost::is_any_of(\"-\"));\n        if (vStrInputParts.size() != 2)\n            return false;\n        if (!DecodeBase58(vStrInputParts[0].c_str(), vchSecretKey))\n            return false;\n\n        boost::split(vStrInputParts, vStrInputParts[1], boost::is_any_of(\":\"));\n        if (vStrInputParts.size() != 2)\n            return false;\n        if (!DecodeBase58(vStrInputParts[0].c_str(), vchSecretCode))\n            return false;\n\n        boost::split(vStrInputParts, vStrInputParts[1], boost::is_any_of(\";\"));\n        if (vStrInputParts.size() != 2)\n            return false;\n        if (!DecodeBase58(vStrInputParts[0].c_str(), vchCreationTime))\n            return false;\n\n        creationTime = std::string(vchCreationTime.begin(), vchCreationTime.end());\n        payAccount = vStrInputParts[1];\n        if (vchSecretCode.size() != 32)\n            return false;\n\n        key.GetMutableKey().Set(vchSecretKey.begin(), vchSecretKey.end(), true);\n        key.chaincode = uint256(vchSecretCode);\n\n        return true;\n    }\n\n    std::string ToURIString() const\n    {\n        std::string encodedURI = ToString();\n        encodedURI = encodedURI + \":\" + EncodeBase58( (const unsigned char*)&creationTime[0], (const unsigned char*)&creationTime[0]+creationTime.size() );\n        encodedURI = encodedURI + \";\" + payAccount;\n\n        return encodedURI;\n    }\n\n    std::string ToString() const\n    {\n        std::string encodedString =  EncodeBase58( (const unsigned char*)key.GetKey().begin(), (const unsigned char*)key.GetKey().end() );\n        encodedString = encodedString + \"-\" + EncodeBase58( key.chaincode.begin(), key.chaincode.end() );\n\n        return encodedString;\n    }\n\n    KeyType getKeyRaw() { return key; }\n    CEncodedSecretKeyExt(const KeyType& vchSecret) { SetKey(vchSecret); }\n    CEncodedSecretKeyExt(const std::string& strSecret) { SetString(strSecret); }\n    CEncodedSecretKeyExt() {}\n\nprivate:\n    KeyType key;\n    std::string secret;\n\n    std::string payAccount;\n    std::string creationTime;\n};\n\ntemplate<typename K, int Size, CChainParams::Base58Type Type> class CEncodedSecretExtKeyBase : public CBase58Data\n{\npublic:\n    void SetKey(const K &key) {\n        unsigned char vch[Size];\n        key.Encode(vch);\n        SetData(Params().Base58Prefix(Type), vch, vch+Size);\n    }\n\n    K GetKey() {\n        K ret;\n        if (vchData.size() == Size) {\n            // If base58 encoded data does not hold an ext key, return a !IsValid() key\n            ret.Decode(&vchData[0]);\n        }\n        return ret;\n    }\n\n    CEncodedSecretExtKeyBase(const K &key) {\n        SetKey(key);\n    }\n\n    CEncodedSecretExtKeyBase(const std::string& strBase58c) {\n        SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());\n    }\n\n    CEncodedSecretExtKeyBase() {}\n};\n\ntypedef CEncodedSecretExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CEncodedSecretExt;\ntypedef CEncodedSecretExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CEncodedSecretExtPubKey;\n\n#endif\n"
  },
  {
    "path": "src/bench/.gitignore",
    "content": "bench_munt\n"
  },
  {
    "path": "src/bench/Examples.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"validation/validation.h\"\n#include \"utiltime.h\"\n\n// Sanity test: this should loop ten times, and\n// min/max/average should be close to 100ms.\nstatic void Sleep100ms(benchmark::State& state)\n{\n    while (state.KeepRunning()) {\n        MilliSleep(100);\n    }\n}\n\nBENCHMARK(Sleep100ms);\n\n// Extremely fast-running benchmark:\n#include <math.h>\n\nvolatile double sum = 0.0; // volatile, global so not optimized away\n\nstatic void Trig(benchmark::State& state)\n{\n    double d = 0.01;\n    while (state.KeepRunning()) {\n        sum += sin(d);\n        d += 0.000001;\n    }\n}\n\nBENCHMARK(Trig);\n"
  },
  {
    "path": "src/bench/base58.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n\n#include \"validation/validation.h\"\n#include \"base58.h\"\n\n#include <vector>\n#include <string>\n\n\nstatic void Base58Encode(benchmark::State& state)\n{\n    unsigned char buff[32] = {\n        17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,\n        227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,\n        200, 24\n    };\n    unsigned char* b = buff;\n    while (state.KeepRunning()) {\n        EncodeBase58(b, b + 32);\n    }\n}\n\n\nstatic void Base58CheckEncode(benchmark::State& state)\n{\n    unsigned char buff[32] = {\n        17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,\n        227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,\n        200, 24\n    };\n    unsigned char* b = buff;\n    std::vector<unsigned char> vch;\n    vch.assign(b, b + 32);\n    while (state.KeepRunning()) {\n        EncodeBase58Check(vch);\n    }\n}\n\n\nstatic void Base58Decode(benchmark::State& state)\n{\n    const char* addr = \"17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem\";\n    std::vector<unsigned char> vch;\n    while (state.KeepRunning()) {\n        DecodeBase58(addr, vch);\n    }\n}\n\n\nBENCHMARK(Base58Encode);\nBENCHMARK(Base58CheckEncode);\nBENCHMARK(Base58Decode);\n"
  },
  {
    "path": "src/bench/bench.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"perf.h\"\n\n#include <assert.h>\n#include <iostream>\n#include <iomanip>\n#include <sys/time.h>\n\nbenchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {\n    static std::map<std::string, benchmark::BenchFunction> benchmarks_map;\n    return benchmarks_map;\n}\n\nstatic double gettimedouble(void) {\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return tv.tv_usec * 0.000001 + tv.tv_sec;\n}\n\nbenchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)\n{\n    benchmarks().insert(std::pair(name, func));\n}\n\nvoid\nbenchmark::BenchRunner::RunAll(double elapsedTimeForOne)\n{\n    perf_init();\n    std::cout << \"#Benchmark\" << \",\" << \"count\" << \",\" << \"min\" << \",\" << \"max\" << \",\" << \"average\" << \",\"\n              << \"min_cycles\" << \",\" << \"max_cycles\" << \",\" << \"average_cycles\" << \"\\n\";\n\n    for (const auto &p: benchmarks()) {\n        State state(p.first, elapsedTimeForOne);\n        p.second(state);\n    }\n    perf_fini();\n}\n\nbool benchmark::State::KeepRunning()\n{\n    if (count & countMask) {\n      ++count;\n      return true;\n    }\n    double now;\n    uint64_t nowCycles;\n    if (count == 0) {\n        lastTime = beginTime = now = gettimedouble();\n        lastCycles = beginCycles = nowCycles = perf_cpucycles();\n    }\n    else {\n        now = gettimedouble();\n        double elapsed = now - lastTime;\n        double elapsedOne = elapsed * countMaskInv;\n        if (elapsedOne < minTime) minTime = elapsedOne;\n        if (elapsedOne > maxTime) maxTime = elapsedOne;\n\n        // We only use relative values, so don't have to handle 64-bit wrap-around specially\n        nowCycles = perf_cpucycles();\n        uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;\n        if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;\n        if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;\n\n        if (elapsed*128 < maxElapsed) {\n          // If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.\n          // The restart avoids including the overhead of this code in the measurement.\n          countMask = ((countMask<<3)|7) & ((1LL<<60)-1);\n          countMaskInv = 1./(countMask+1);\n          count = 0;\n          minTime = std::numeric_limits<double>::max();\n          maxTime = std::numeric_limits<double>::min();\n          minCycles = std::numeric_limits<uint64_t>::max();\n          maxCycles = std::numeric_limits<uint64_t>::min();\n          return true;\n        }\n        if (elapsed*16 < maxElapsed) {\n          uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);\n          if ((count & newCountMask)==0) {\n              countMask = newCountMask;\n              countMaskInv = 1./(countMask+1);\n          }\n        }\n    }\n    lastTime = now;\n    lastCycles = nowCycles;\n    ++count;\n\n    if (now - beginTime < maxElapsed) return true; // Keep going\n\n    --count;\n\n    assert(count != 0 && \"count == 0 => (now == 0 && beginTime == 0) => return above\");\n\n    // Output results\n    double average = (now-beginTime)/count;\n    int64_t averageCycles = (nowCycles-beginCycles)/count;\n    std::cout << std::fixed << std::setprecision(15) << name << \",\" << count << \",\" << minTime << \",\" << maxTime << \",\" << average << \",\"\n              << minCycles << \",\" << maxCycles << \",\" << averageCycles << \"\\n\";\n\n    return false;\n}\n"
  },
  {
    "path": "src/bench/bench.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BENCH_BENCH_H\n#define BENCH_BENCH_H\n\n#include <functional>\n#include <limits>\n#include <map>\n#include <string>\n\n#include <boost/preprocessor/cat.hpp>\n#include <boost/preprocessor/stringize.hpp>\n\n// Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark\n// framework (see https://github.com/google/benchmark)\n// Why not use the Google Benchmark framework? Because adding Yet Another Dependency\n// (that uses cmake as its build system and has lots of features we don't need) isn't\n// worth it.\n\n/*\n * Usage:\n\nstatic void CODE_TO_TIME(benchmark::State& state)\n{\n    ... do any setup needed...\n    while (state.KeepRunning()) {\n       ... do stuff you want to time...\n    }\n    ... do any cleanup needed...\n}\n\nBENCHMARK(CODE_TO_TIME);\n\n */\n \nnamespace benchmark {\n\n    class State {\n        std::string name;\n        double maxElapsed;\n        double beginTime;\n        double lastTime, minTime, maxTime, countMaskInv;\n        uint64_t count;\n        uint64_t countMask;\n        uint64_t beginCycles;\n        uint64_t lastCycles;\n        uint64_t minCycles;\n        uint64_t maxCycles;\n    public:\n        State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {\n            minTime = std::numeric_limits<double>::max();\n            maxTime = std::numeric_limits<double>::min();\n            minCycles = std::numeric_limits<uint64_t>::max();\n            maxCycles = std::numeric_limits<uint64_t>::min();\n            countMask = 1;\n            countMaskInv = 1./(countMask + 1);\n        }\n        bool KeepRunning();\n    };\n\n    typedef std::function<void(State&)> BenchFunction;\n\n    class BenchRunner\n    {\n        typedef std::map<std::string, BenchFunction> BenchmarkMap;\n        static BenchmarkMap &benchmarks();\n\n    public:\n        BenchRunner(std::string name, BenchFunction func);\n\n        static void RunAll(double elapsedTimeForOne=1.0);\n    };\n}\n\n// BENCHMARK(foo) expands to:  benchmark::BenchRunner bench_11foo(\"foo\", foo);\n#define BENCHMARK(n) \\\n    benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n);\n\n#endif\n"
  },
  {
    "path": "src/bench/bench_munt.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n\n#include \"key.h\"\n#include \"validation/validation.h\"\n#include \"util.h\"\n\nint\nmain(int argc, char** argv)\n{\n    ECC_Start();\n    SetupEnvironment();\n    fPrintToDebugLog = false; // don't want to write to debug.log file\n\n    benchmark::BenchRunner::RunAll();\n\n    ECC_Stop();\n}\n"
  },
  {
    "path": "src/bench/bench_sigma.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <crypto/hash/sigma/sigma.h>\n#include <iostream>\n#include <boost/program_options.hpp>\n#include <thread>\n\n#include <cryptopp/config.h>\n#include <cryptopp/aes.h>\n#include <cryptopp/modes.h>\n#include <random.h>\n#include \"key.h\"\n\nint LogPrintStr(const std::string &str)\n{\n    std::cout << str;\n    return 1;\n}\n\n// fixme: (BOOST) - Workaround for boost on macOS (when using newer clang) build issue (not detecting string_view properly)\n// Remove this when addressed by Boost's ASIO config.\n// https://www.boost.org/doc/libs/1_67_0/boost/asio/detail/config.hpp\n// Standard library support for std::string_view.\n#define BOOST_ASIO_HAS_STD_STRING_VIEW 1\n#define BOOST_ASIO_DISABLE_STD_STRING_VIEW 1\n#include <boost/asio.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n// Are we running with all options at default or are any overriden by user.\nbool defaultSigma = true;\n\n// User paramaters (adjustable on individual machines)\nuint64_t numThreads = std::thread::hardware_concurrency();\nuint64_t memAllowGb;\nuint64_t numUserVerifyThreads;\nuint64_t numFullHashesTarget = 50000;\nbool mineOnly=false;\n    \nusing namespace boost::program_options;\nstd::vector<std::string> hashTestVector = {\n    \"A\",\n    \"AA\",\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n    \"B33F761F0D3A86BB1051905AEC7A691BD0B5A24C3721F67D8E48D839\",\n    \"D4773C6DAFE49604B4DF73725512483DB17578CD209C27ABB39782D8\", \n    \"15D9174CBD4D22F8C49FE874F45EBBF23806DEEC190B20BC67945833\", \n    \"262C26AD4EDCD692FFB1B859CE729AD61BA67D6FA72AC7A7509D92E8\", \n    \"6FBD09FCE4600327A97540BFF4DF7A99DA7C13F8CB13FA39838EC010\"\n};\n// Test vector results generated against latest reference implementation(s) of SHAvite3 in supercop. Not the website version which appears to\nstd::vector shaviteTestVectorOut = {\n    \"9206c5e42ac244c08d8383caa80093fb6e4d88ae8d11edf9c2d08442cba89337\",\n    \"4f4fd087b2831ca55ad51df0e18cd574bb30ec8089a42340142d2c2bb5b23ccc\",\n    \"2e747b74196c20b94253ca56730a28dda2aa49420bd53e053ed77a329a8f8469\",\n    \"df2318831b70ceb7986c722ba65df78fa51924bf5bd6582dd516b9357a47660f\",\n    \"f75fa0c12a54b93e122a3c5d476dd489e96aab749344f7062814f662d0460fa1\",\n    \"69a8a32cfe0f0f5e510e97f22a63ecb211425fe2f26267827e244e4ebe70774d\",\n    \"d0316c6d924f45913a8f0328a448f218dd18a1b28e38bf5355d8201a65bcc0b2\",\n    \"ad48f660cd6328ebbc5c40a73dfa365aab770e7ba08220b051633c5f8ee4b157\",\n};\nstd::vector echo256TestVectorOut = {\n    \"1ffdd51e506ea633440daf864f02e80eb3c5371da068c39c11e3e7d637f60659\",\n    \"c5ddce445e589b14213707e68afda6d651736b6b4d223733bb5e68489492856e\",\n    \"949e61e69a5c473996432f4f137a98d4774dfaf503020565232e246b73fb8a68\",\n    \"960d74a005576c431a21f3f8ec8a4644094eb98e7ce14394ac92709d23097c03\",\n    \"7c002e865862c73e78c616e36b2f96341abbe018383163f16c6be934c7bebfb0\",\n    \"70de7acca4efe39c85e419964548155a212861dc9378b600f671f82be4ca4df0\",\n    \"a10db9cf5e865376b06a38108dc47397e90b6ffce7d73cb5670450a9ca077611\",\n    \"3d36df7adf6b181e5a6b3b10a09797917dbe2291b5548ec0652dde1e6f16a23c\"\n};\n\nstd::vector argonTestVectorOut = {\n    \"7c11631029847d88604227259b2766bffc8a2a4b969adc64\",\n    \"dd0656eafe82680adc6f43cea85efdba2b42d4a2e3e82226\",\n    \"e922c593f7090000943ae2be1f698ff07a5fb70c637a4717\",\n    \"1a4b0cfc26a2f4aca6f249b4e31b2507138f351bc07ab2cf\",\n    \"6cb626788f54fb1351a1168b22bdef2f527c8befde4f12ea\",\n    \"b6d5ef01b51070c5ebce37aac947ebc7ef5268cdd0cba3bd\",\n    \"752110a06db8d300eaa117dbe9c826f1c6450ad13a83b54a\",\n    \"35435ce1cd1c2be1954bae9780a9106aedabc54f26111943\"\n};\n\nstd::vector prngTestVectorOut = {\n    \"ff2c21f49ae9aa37a80646d739caf085cd94b822db0676413c62b84f51bde9\",\n    \"0c61008393ca6ece11a192182a798cf49f3bafdfbe54c42ff3fa6fa86fc687\",\n    \"30542c1cd581a3ca5d5a4456bac5275663a522bc10f228089cb1a8c6ad6f84\",\n    \"28db8c95db562c79ef25fc9fb7cd640dfb4ae8afe1e5c3115f755d6337282d\",\n    \"51eba29e2a7b21596f5149476f396b58af3cfdcb0f7b2f855f964c0d548324\",\n    \"566af98eb1efe32fc8b07ec571e65f4e64f428c3b68708800133e4d8e920f5\",\n    \"80f0f7bbf45342427938b4bac8c44c81d1dab08b85c73556acc2c6cbc84217\",\n    \"a701a7d61279cbef20fa66c17ed67d7d6308a5035264de1ec64d066bcd6189\"\n};\n\n\nvoid testShaviteReference(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        std::vector<unsigned char> outHash(32);\n        shavite3_ref_hashState ctx_shavite;\n        shavite3_ref_Init(&ctx_shavite);\n        shavite3_ref_Update(&ctx_shavite, (uint8_t*)&data[0], data.size());\n        shavite3_ref_Final(&ctx_shavite, (uint8_t*)&outHash[0]);\n        std::string outHashHex = HexStr(outHash.begin(), outHash.end()).c_str();\n        std::string compare(shaviteTestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testShaviteOptimised(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        std::vector<unsigned char> outHash(32);\n\n        shavite3_256_opt_hashState ctx_shavite;\n        selected_shavite3_256_opt_Init(&ctx_shavite);\n        selected_shavite3_256_opt_Update(&ctx_shavite, (uint8_t*)&data[0], data.size());\n        selected_shavite3_256_opt_Final(&ctx_shavite, &outHash[0]);\n        \n        std::string outHashHex = HexStr(outHash.begin(), outHash.end()).c_str();\n        std::string compare(shaviteTestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testEchoReference(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        std::vector<unsigned char> outHash(32);\n        sph_echo256_context ctx_echo;\n        sph_echo256_init(&ctx_echo);\n        sph_echo256(&ctx_echo, (uint8_t*)&data[0], data.size());\n        sph_echo256_close(&ctx_echo, (void*)&outHash[0]);\n        std::string outHashHex = HexStr(outHash.begin(), outHash.end()).c_str();\n        std::string compare(echo256TestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testEchoOptimised(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        std::vector<unsigned char> outHash(32);\n        \n        echo256_opt_hashState ctx_echo;\n        selected_echo256_opt_Init(&ctx_echo);\n        selected_echo256_opt_Update(&ctx_echo, (uint8_t*)&data[0], data.size());\n        selected_echo256_opt_Final(&ctx_echo, &outHash[0]); \n       \n        std::string outHashHex = HexStr(outHash.begin(), outHash.end()).c_str();\n        std::string compare(echo256TestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testArgonReference(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        \n        __attribute__ ((aligned (16))) uint8_t argonScratch[1024*32];\n        argon2_echo_context context;\n        context.t_cost = 5;\n        context.m_cost = 32;\n        context.allocated_memory = argonScratch;\n        context.pwd = (uint8_t*)&data[0];\n        context.pwdlen = data.size();\n        context.lanes = 4;\n        context.threads = 1;\n        \n        argon2_echo_ctx_ref(&context, true);\n            \n        std::string outHashHex = HexStr((uint8_t*)(&context.outHash[0]), (uint8_t*)(&context.outHash[3])).c_str();\n        std::string compare(argonTestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testArgonOptimised(uint64_t& nTestFailCount)\n{\n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        \n        __attribute__ ((aligned (16))) uint8_t argonScratch[1024*32];\n        argon2_echo_context context;\n        context.t_cost = 5;\n        context.m_cost = 32;\n        context.allocated_memory = argonScratch;\n        context.pwd = (uint8_t*)&data[0];\n        context.pwdlen = data.size();\n        context.lanes = 4;\n        context.threads = 1;\n        \n        selected_argon2_echo_hash(&context, true);\n            \n        std::string outHashHex = HexStr((uint8_t*)(&context.outHash[0]), (uint8_t*)(&context.outHash[3])).c_str();\n        std::string compare(argonTestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\nvoid testPRNG(uint64_t& nTestFailCount)\n{\n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n    \n    \n    for (unsigned int i=0;i<hashTestVector.size();++i)\n    {\n        std::string data = hashTestVector[i];\n        if (data.length() < 32)\n        {\n            data = data + std::string(32-data.length(), 'a');\n        }\n        \n        prng.SetKey((const unsigned char*)&data[0], 32);\n        unsigned char ciphered[32];\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&data[0], 32);\n        memcpy(&data[0], &ciphered[0], (size_t)32);\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&data[0], 32);\n        memcpy(&data[0], &ciphered[0], (size_t)32);\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&data[0], 32);\n        memcpy(&data[0], &ciphered[0], (size_t)32);\n                   \n        std::string outHashHex = HexStr(&ciphered[0], &ciphered[31]).c_str();\n        std::string compare(prngTestVectorOut[i]);\n        if (outHashHex == compare)\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            ++nTestFailCount;\n            printf(\"✘\");\n            printf(\"%s\\n\", outHashHex.c_str());\n        }\n    }\n    printf(\"\\n\");\n}\n\n\nstd::vector<std::string>\nvalidHeaderTestVectorIn = {\n    \"558bad3a37d06f888488cbf263539ea03aae7bb799ec116f84d5d152f3b6bf2d54b0b6771b92513491c47128fd682966e84fb5a6f2afadbc02fece877c15343cf4f37954d552945dffff3f1f0e03892a\",\n    \"66fddd519be388a941d6ee5f11342abdb0984dc9386aa62ff06a1a1e6f88dd271fa32ab0dedc1a5fa5916ba62dc458cc84f13dd24c3258b6f65839daab5977f814220a7c6253945dffff3f1fd202aad9\",\n    \"cd9a7e352c96133e9d24388fb44e786c92c2ecdbc23544c719d405ce0a68c077242dff24e5e167e964af1b179c30587971c3cad8efcbd8e5db42705a6e9219d3dc30e8ed7353945dffff3f1ff9024f8e\",\n    \"6a271c6eeb0ded66181bd069dbcadd57fd8460c5000ea8ad51c4436eef580ea5446844b105781adb6ef768f71ea827e91c17bb6881ad56672e6b509e0da5addb937ff17e8253945dffff3f1f06037abd\",\n    \"b03cee570e79a77fad51dbe5f1b3118483aada975dad7041193739ac1076a64ad6778dd9df9dcf6d9434c314bcdf0ea1d3cf24c5def5c3e54ac882b3379d5427b4ca9a669353945dffff3f1fdc026794\"\n};\nvoid testValidateValidHeaders(sigma_settings settings, uint64_t& nTestFailCount)\n{\n    CBlockHeader header;\n    for (const auto& hash : validHeaderTestVectorIn)\n    {\n        std::vector<unsigned char> data = ParseHex(hash);\n        memcpy(&header.nVersion, &data[0], 80);\n        sigma_verify_context verify(settings, numUserVerifyThreads);\n        if (verify.verifyHeader(header))\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            printf(\"✘\");\n            ++nTestFailCount;\n        }\n        \n    }\n    printf(\"\\n\");\n}\n\nstd::vector<std::string>\ninvalidHeaderTestVectorIn = {\n    \"a0da8101c2c1f7ae98536a4c215f48e38ca17e925f61234c9aa602205d6fd5e27eb0c885452abf7e8515e3e7c4758cefd55c9331760b7c711280a451067c6b01e0e46234a7a5845dffff3f1f1700ee6c\",\n    \"b0d6563c856c89be804b189b9a36856b795770243b2f2b4efab1b8f021962c3129da01148537c2f19b7d52321415d834cc04ddf199022f105ebf194d4e6470f8bab50a21aba5845dffff3f1f0e00b01f\",\n    \"47a5866c8b1e9eeff7f62b654d0cd2e70785cd13c2e1446cc74231df906ba4f4113413a5b56e88336447db61875cf4862e5587ed25d26de8a0c61c8c23070a4a62eea35eaea5845dffff3f1f1a003d51\",\n    \"72b6032ae5c1db9982e2d9135052ec3cc47c7414947da6e55a76e47b4b2ec6744a3140ba0baf06a69dece43f9dbba5008ca490a3098c41d06279af6811c386080ad0b1cdb2a5845dffff3f1f1200d425\",\n    \"73d7b147d565af53774df3252c7dbf358fb8a8328ead1b656c3d216b533a2bffcc16869309825486c5945373a11d4219531948a9d8d5af501b1cdc0fe83c2ebb5f1d37d8b5a5845dffff3f1f1800f632\"\n};\nvoid testValidateInvalidHeaders(sigma_settings settings, uint64_t& nTestFailCount)\n{\n    CBlockHeader header;\n    for (const auto& hash : invalidHeaderTestVectorIn)\n    {\n        std::vector<unsigned char> data = ParseHex(hash);\n        memcpy(&header.nVersion, &data[0], 80);\n        sigma_verify_context verify(settings, numUserVerifyThreads);\n        if (!verify.verifyHeader(header))\n        {\n            printf(\"✔\");\n        }\n        else\n        {\n            printf(\"✘\");\n            ++nTestFailCount;\n        }\n    }\n    printf(\"\\n\");\n}\n\ndouble calculateSustainedHashrateForTimePeriod(uint64_t maxHashesPre, uint64_t maxHashesPost, double nHalfHashAverage, uint64_t nArenaSetuptime, uint64_t nTimePeriodSeconds)\n{\n    // We need to recalculate the arenas every time we exhaust the hash space, or when a new block comes in, whichever comes first.\n    // Block target is 2.5 minutes, so we assume that the maximum time we can mine in between arena calculations is 3 minutes,\n    // or the full hash space, whichever is lower.\n    uint64_t maxHalfHashes = maxHashesPre*maxHashesPost;\n    maxHalfHashes = std::min(maxHalfHashes, (uint64_t)((nTimePeriodSeconds*1000000)/nHalfHashAverage));\n    \n    // The total time is then the arena setup time plus the time that calculating maxHalfHashes would take (all in microseconds)\n    uint64_t nTimeTotal = nArenaSetuptime + (maxHalfHashes*nHalfHashAverage);\n    \n    // Finally we can get a sustained hashrate by calculating the time per hash and then calculating how many hashes per second.\n    double nSustainedMicrosecondsPerHash = ((double)nTimeTotal / (double)maxHalfHashes);\n    double nSustainedHashesPerMicrosecond = (1/nSustainedMicrosecondsPerHash);\n    return nSustainedHashesPerMicrosecond * 1000000;\n}\n    \nint main(int argc, char** argv)\n{\n    memAllowGb = defaultSigmaSettings.arenaSizeKb/1024/1024;\n    numUserVerifyThreads = defaultSigmaSettings.numVerifyThreads;\n    selected_argon2_echo_hash = argon2_echo_ctx_ref;\n    selectOptimisedImplementations();\n\n    srand(GetTimeMicros());\n    \n    // Declare the supported options.\n    options_description desc(\"Allowed options\");\n    desc.add_options()\n    (\"help\", \"produce help message\")\n    (\"mine-threads\", value<int64_t>(), \"Set number of threads to use for mining\")\n    (\"mine-memory\", value<int64_t>(), \"Set how much memory in gb to mine with\")\n    (\"mine-num-hashes\", value<int64_t>(), \"How many full hash attempts to run mining for (default 50000)\")\n    (\"mine-only\", value<bool>()->implicit_value(true), \"Only benchmark actual mining, skip other benchmarks\")\n    (\"verify-threads\", value<int64_t>(), \"How many threads to use for verification, may not exceed sigma_verify_threads (defaults to same as sigma_verify_threads)\")\n    (\"sigma-global-mem\", value<int64_t>(), \"How much global memory optimal mining should require (in gigabytes)\")\n    (\"sigma-num-slow\", value<int64_t>(), \"How many slow hash attempts to allow for each global memory allocation  (maximum 65536)\")\n    (\"sigma-slowhash-mem\", value<int64_t>(), \"How much memory each slow hash should consume (in megabytes)\")\n    (\"sigma-slowhash-cpucost\", value<int64_t>(), \"How many rounds of computation to use in the argon slow hash computation (default 12)\")\n    (\"sigma-arena-cpucost\", value<int64_t>(), \"How many rounds of computation to use in the arena hash computation (default 8)\")\n    (\"sigma-num-fast\", value<int64_t>(), \"How many fast hash attempts to allow for each slow hash (maximum 65536)\")\n    (\"sigma-fasthash-mem\", value<int64_t>(), \"How much of the global memory to digest for each slow hash (bytes - should not exceed the size of a single slow hash)\")\n    (\"sigma-verify-threads\", value<int64_t>(), \"How many threads to allow for slow hashes and therefore verification. (Default 4)\");\n    \n    \n    variables_map vm;\n    try\n    {\n        store(parse_command_line(argc, argv, desc), vm);\n        notify(vm);    \n    }\n    catch (std::exception& e)\n    {\n        printf(\"%s\\n\", e.what());\n        std::cout << desc << \"\\n\";\n        return 1;\n    }\n\n    if (vm.size() == 0)\n    {\n        printf(\"Using default options use '--help' to see a list of possible options.\\n\\n\");\n    }\n    else\n    {\n        printf(\"Using non default options use '--help' to see a list of possible options.\\n\\n\");\n    }\n    \n    if (vm.count(\"help\"))\n    {\n        std::cout << desc << \"\\n\";\n        return 1;\n    }\n\n    if (vm.count(\"mine-threads\"))\n    {\n        numThreads = vm[\"mine-threads\"].as<int64_t>();\n    }\n    if (vm.count(\"sigma-global-mem\"))\n    {\n        defaultSigmaSettings.arenaSizeKb = vm[\"sigma-global-mem\"].as<int64_t>() * 1024 * 1024;\n        defaultSigma = false;\n    }\n    memAllowGb = defaultSigmaSettings.arenaSizeKb / 1024 / 1024;\n    if (vm.count(\"mine-memory\"))\n    {\n        memAllowGb = vm[\"mine-memory\"].as<int64_t>();\n    }\n    if (vm.count(\"mine-num-hashes\"))\n    {\n        numFullHashesTarget = vm[\"mine-num-hashes\"].as<int64_t>();\n    }\n    if (vm.count(\"mine-only\"))\n    {\n        mineOnly = vm[\"mine-only\"].as<bool>();;\n        defaultSigma = false;\n    }\n    if (vm.count(\"verify-threads\"))\n    {\n        numUserVerifyThreads = vm[\"verify-threads\"].as<int64_t>();\n    }\n    if (vm.count(\"sigma-num-slow\"))\n    {\n        defaultSigma = false;\n        defaultSigmaSettings.numHashesPre = vm[\"sigma-num-slow\"].as<int64_t>();\n    }\n    if (vm.count(\"sigma-slowhash-mem\"))\n    {\n        defaultSigmaSettings.argonMemoryCostKb = vm[\"sigma-slowhash-mem\"].as<int64_t>()*1024;\n        defaultSigma = false;\n    }\n    if (vm.count(\"sigma-arena-cpucost\"))\n    {\n        defaultSigmaSettings.argonArenaRoundCost = vm[\"sigma-arena-cpucost\"].as<int64_t>();\n        defaultSigma = false;\n    }\n    if (vm.count(\"sigma-slowhash-cpucost\"))\n    {\n        defaultSigmaSettings.argonSlowHashRoundCost = vm[\"sigma-slowhash-cpucost\"].as<int64_t>();\n        defaultSigma = false;\n    }\n    if (vm.count(\"sigma-num-fast\"))\n    {\n        defaultSigmaSettings.numHashesPost = vm[\"sigma-num-fast\"].as<int64_t>();\n        defaultSigma = false;\n    }\n    if (vm.count(\"sigma-fasthash-mem\"))\n    {\n        defaultSigmaSettings.fastHashSizeBytes = vm[\"sigma-fasthash-mem\"].as<int64_t>();\n        defaultSigma = false;\n    }\n    if (vm.count(\"sigma-verify-threads\"))\n    {\n        defaultSigmaSettings.numVerifyThreads = vm[\"sigma-verify-threads\"].as<int64_t>();\n        defaultSigma = false;\n    }\n    \n    \n    if (numUserVerifyThreads > defaultSigmaSettings.numVerifyThreads)\n    {\n        printf(\"Number of user verify threads may not exceed number of sigma verify threads\");\n        return 1;\n    }\n    \n    printf(\"Configuration=====================================================\\n\\n\");\n    printf(\"NETWORK:\\nGlobal memory cost [%lugb]\\nArgon_echo cpu cost for arenas [%lu rounds]\\nArgon_echo cpu cost for slow hash [%lu rounds]\\nArgon_echo mem cost [%luMb]\\nEcho/Shavite digest size [%lu bytes]\\nNumber of fast hashes per slow hash [%lu]\\nNumber of slow hashes per global arena [%lu]\\nNumber of verify threads [%lu]\\n\\n\", defaultSigmaSettings.arenaSizeKb/1024/1024, defaultSigmaSettings.argonArenaRoundCost ,defaultSigmaSettings.argonSlowHashRoundCost, defaultSigmaSettings.argonMemoryCostKb/1024, defaultSigmaSettings.fastHashSizeBytes, defaultSigmaSettings.numHashesPost, defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numVerifyThreads);\n    printf(\"USER:\\nMining with [%lu] threads\\nMining with [%lu gb] memory.\\nVerifying with [%lu] threads.\\n\\n\", numThreads, memAllowGb, numUserVerifyThreads);\n    \n    uint64_t memAllowKb = memAllowGb*1024*1024;\n    if (memAllowKb == 0)\n    {\n        memAllowKb = 512*1024;\n    }\n        \n    // If we are using the default params then perform some tests to ensure everything runs the same across different machines\n    if (!defaultSigma)\n    {\n        defaultSigmaSettings.verify();\n    }\n    else\n    {\n        printf(\"Tests=============================================================\\n\\n\");\n        uint64_t nTestFailCount=0;\n        \n        printf(\"Verify shavite reference operation\\n\");\n        testShaviteReference(nTestFailCount);\n        \n        if (selected_shavite3_256_opt_Final)\n        {\n            printf(\"Verify shavite optimised operation\\n\");\n            testShaviteOptimised(nTestFailCount);\n        }\n        \n        printf(\"Verify echo reference operation\\n\");\n        testEchoReference(nTestFailCount);\n        \n        if (selected_echo256_opt_Final)\n        {\n            printf(\"Verify echo optimised operation\\n\");\n            testEchoOptimised(nTestFailCount);\n        }\n        \n        printf(\"Verify argon reference operation\\n\");\n        testArgonReference(nTestFailCount);\n        \n        if (selected_argon2_echo_hash)\n        {\n            printf(\"Verify argon optimised operation\\n\");\n            testArgonOptimised(nTestFailCount);\n        }\n        \n        printf(\"Verify PRNG\\n\");\n        testPRNG(nTestFailCount);\n        \n        printf(\"Verify validation of valid headers\\n\");\n        testValidateValidHeaders(defaultSigmaSettings, nTestFailCount);\n        \n        printf(\"Verify validation of invalid headers\\n\");\n        testValidateInvalidHeaders(defaultSigmaSettings, nTestFailCount);\n        \n        if (nTestFailCount > 0)\n        {\n            printf(\"Aborting due to [%lu] failed tests.\\n\", nTestFailCount);\n            exit(EXIT_FAILURE);\n        }\n        printf(\"\\n\");\n    }\n    \n    //Random header to benchmark with, we will randomly change it more throughout the tests.\n    CBlockHeader header;\n    header.nVersion = rand();\n    header.hashPrevBlock = GetRandHash();\n    header.hashMerkleRoot = GetRandHash();\n    header.nTime = rand();\n    header.nBits = rand();\n    header.nNonce = rand();\n    \n    if (!mineOnly)\n    {\n        printf(\"ECC compact recovery============================================================\\n\\n\");\n        {\n            ECC_Start();\n            ECCVerifyHandle globalVerifyHandle;\n            CKey key1;\n            key1.MakeNewKey(true);\n\n            std::vector<std::vector<unsigned char>> signatures;\n            std::vector<uint256> hashes;\n            {\n                uint64_t numHashes = 10000;\n                for (uint64_t i=0; i<numHashes; ++i)\n                {\n                    uint256 hash = GetRandHash();\n                    std::vector<unsigned char> signature;\n                    key1.SignCompact(hash, signature);\n                    hashes.push_back(hash);\n                    signatures.push_back(signature);\n                }\n                CPubKey rkey1;\n            \n                uint64_t nStart = GetTimeMicros(); \n                for (uint64_t i=0; i< numHashes; ++i)\n                {\n                    rkey1.RecoverCompact(hashes[i], signatures[i]);\n                }\n                printf(\"total [%lu micros] per hash: [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numHashes);\n            }\n        }\n        \n        printf(\"SHA-D============================================================\\n\\n\");\n        {\n            uint64_t nStart = GetTimeMicros(); \n            uint64_t numHashes = 1000;\n            arith_uint256 thash;\n            arith_uint256 fhash;\n            for (uint64_t i=0;i<numHashes;++i)\n            {\n                header.nNonce=i;\n                hash_sha256(BEGIN(header.nVersion), 80, thash);\n                hash_sha256(BEGIN(thash), 32, fhash);\n            }\n            printf(\"total [%lu micros] per hash: [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numHashes);\n        }\n            \n        printf(\"Scrypt============================================================\\n\\n\");\n        uint256 hash;    \n        {\n            printf(\"Bench cost [single thread]:\\n\");\n            uint64_t nStart = GetTimeMicros(); \n            uint64_t numHashes = 20;\n            char scratchpad[SCRYPT_SCRATCHPAD_SIZE];\n            for (uint64_t i=0; i< numHashes; ++i)\n            {\n                header.nNonce = i;\n                scrypt_1024_1_1_256_sp(BEGIN(header.nVersion), BEGIN(hash), scratchpad);\n            }\n            printf(\"total [%lu micros] per hash: [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numHashes);\n        }\n        \n        {\n            printf(\"Bench cost [%lu threads]:\\n\", numThreads);\n            uint64_t nStart = GetTimeMicros();\n            uint64_t numHashes = 100;\n            auto workerThreads = new boost::asio::thread_pool(numThreads);\n            for (uint64_t i = 0; i <= numHashes;++i)\n            {\n                boost::asio::post(*workerThreads, [=]() mutable\n                {\n                    char scratchpad[SCRYPT_SCRATCHPAD_SIZE];\n                    header.nNonce = i;\n                    scrypt_1024_1_1_256_sp(BEGIN(header.nVersion), BEGIN(hash), scratchpad);    \n                });\n            }\n            workerThreads->join();\n            printf(\"total [%lu micros] per hash [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numHashes);\n        }\n        \n        printf(\"SIGMA=============================================================\\n\\n\");\n        {\n            sigma_context sigmaContext(defaultSigmaSettings, std::min(memAllowKb, defaultSigmaSettings.arenaSizeKb), numThreads, numThreads);\n            if (!sigmaContext.arenaIsValid())\n            {\n                printf(\"Failed to allocate arena memory, try again with lower memory settings.\\n\");\n                exit(EXIT_FAILURE);\n            }\n            \n            #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY)\n            {\n                printf(\"Bench fast hashes optimised [single thread]:\\n\");\n                uint8_t hashData1[80];\n                for (int i=0;i<80;++i)\n                {\n                    hashData1[i] = rand();\n                }\n                uint8_t hashData2[32];\n                for (int i=0;i<32;++i)\n                {\n                    hashData2[i] = rand();\n                }\n                std::vector<unsigned char> hashData3(defaultSigmaSettings.fastHashSizeBytes);\n                for (uint64_t i=0;i<defaultSigmaSettings.fastHashSizeBytes;++i)\n                {\n                    hashData3[i] = rand();\n                }\n                uint64_t nStart = GetTimeMicros();\n                uint64_t numFastHashes = 20000;\n                sigmaContext.benchmarkFastHashes(hashData1, hashData2, &hashData3[0], numFastHashes);\n                printf(\"total [%lu micros] per hash [%.4f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numFastHashes);\n            }\n            #endif\n            {\n                printf(\"Bench fast hashes reference [single thread]:\\n\");\n                uint8_t hashData1[80];\n                for (int i=0;i<80;++i)\n                {\n                    hashData1[i] = rand();\n                }\n                uint8_t hashData2[32];\n                for (int i=0;i<32;++i)\n                {\n                    hashData2[i] = rand();\n                }\n                std::vector<unsigned char> hashData3(defaultSigmaSettings.fastHashSizeBytes);\n                for (uint64_t i=0;i<defaultSigmaSettings.fastHashSizeBytes;++i)\n                {\n                    hashData3[i] = rand();\n                }\n                uint64_t nStart = GetTimeMicros();\n                uint64_t numFastHashes = 20000;\n                sigmaContext.benchmarkFastHashesRef(hashData1, hashData2, &hashData3[0], numFastHashes);\n                printf(\"total [%lu micros] per hash [%.4f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numFastHashes);\n            }\n            \n            {\n                printf(\"Bench slow hashes [single thread]:\\n\");\n                uint8_t hashData[80];\n                for (int i=0;i<80;++i)\n                {\n                    hashData[i] = rand();\n                }\n                    \n                uint64_t nStart = GetTimeMicros();\n                uint64_t numSlowHashes = 100;\n                sigmaContext.benchmarkSlowHashes(hashData, numSlowHashes);\n                printf(\"total [%lu micros] per hash [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numSlowHashes);\n            }\n            \n            {\n                printf(\"Bench global arena priming [cpu_cost %lurounds] [mem_cost %lumb]:\\n\", defaultSigmaSettings.argonArenaRoundCost, defaultSigmaSettings.argonMemoryCostKb/1024 );\n                uint64_t nStart = GetTimeMicros(); \n                uint64_t numArenas=4;\n                for (uint64_t i=0; i<numArenas; ++i)\n                {\n                    sigmaContext.prepareArenas(header);\n                }\n                printf(\"total [%lu micros] per round: [%.2f micros]\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)numArenas);\n            }  \n        }\n        {\n            {\n                sigma_verify_context verify(defaultSigmaSettings, numUserVerifyThreads);\n                printf(\"Bench verify [single thread]\\n\");\n                uint64_t nVerifyNumber=100;\n                uint64_t nCountValid=0;\n                uint64_t nStart = GetTimeMicros();\n                for (uint64_t i =0; i< nVerifyNumber; ++i)\n                {\n                    header.nNonce = rand();\n                    // Count and log number of successes to avoid possibility of compiler optimising the call out.\n                    if (verify.verifyHeader(header))\n                    {\n                        ++nCountValid;\n                    }\n                }\n                printf(\"total [%lu micros] per verification [%.2f micros] found [%lu] valid random hashes\\n\\n\", (GetTimeMicros() - nStart), ((GetTimeMicros() - nStart)) / (double)nVerifyNumber, nCountValid);\n            }\n        }\n    }\n    \n    uint64_t nArenaSetuptime=0;\n    uint64_t nMineStart = GetTimeMicros();\n    {\n        if (mineOnly)\n        {\n            printf(\"SIGMA=============================================================\\n\\n\");\n        }\n        header.nTime = GetTime();\n        header.nVersion = rand();\n        header.nBits = arith_uint256((~arith_uint256(0) >> 10)).GetCompact();\n        \n        std::vector<sigma_context*> sigmaContexts;\n        std::vector<uint64_t> sigmaMemorySizes;\n        uint64_t nMemoryAllocatedKb=0;\n        \n        while (nMemoryAllocatedKb < memAllowKb)\n        {\n            uint64_t nMemoryChunkKb = std::min((memAllowKb-nMemoryAllocatedKb), defaultSigmaSettings.arenaSizeKb);\n            nMemoryAllocatedKb += nMemoryChunkKb;\n            sigmaMemorySizes.emplace_back(nMemoryChunkKb);\n        }\n        for (auto instanceMemorySizeKb : sigmaMemorySizes)\n        {\n            sigmaContexts.push_back(new sigma_context(defaultSigmaSettings, instanceMemorySizeKb, numThreads/sigmaMemorySizes.size(), numThreads/sigmaMemorySizes.size()));\n        }\n        \n        printf(\"Bench mining for low difficulty target\\n\");\n        uint64_t nStart = GetTimeMicros();\n        std::atomic<uint64_t> slowHashCounter = 0;\n        std::atomic<uint64_t> halfHashCounter = 0;\n        std::atomic<uint64_t> skippedHashCounter = 0;\n        std::atomic<uint64_t> hashCounter = 0;\n        std::atomic<uint64_t> blockCounter = 0;\n        {\n            auto workerThreads = new boost::asio::thread_pool(numThreads);\n            for (auto sigmaContext : sigmaContexts)\n            {\n                boost::asio::post(*workerThreads, [&, header, sigmaContext]() mutable\n                {\n                    sigmaContext->prepareArenas(header);\n                });\n            }\n            workerThreads->join();\n        }\n        double nHalfHashAverage=0;\n        nArenaSetuptime = (GetTimeMicros() - nStart);\n        printf(\"Arena setup time [%lu micros]\\n\", nArenaSetuptime);\n        nStart = GetTimeMicros();\n        {\n            auto workerThreads = new boost::asio::thread_pool(numThreads);\n            for (auto sigmaContext : sigmaContexts)\n            {\n                boost::asio::post(*workerThreads, [&, header, sigmaContext]() mutable\n                {\n                    sigmaContext->benchmarkMining(header, slowHashCounter, halfHashCounter, skippedHashCounter, hashCounter, blockCounter, numFullHashesTarget);\n                });\n            }\n            workerThreads->join();\n        }\n        nHalfHashAverage = ((GetTimeMicros() - nStart)) / (double)halfHashCounter;\n        printf(\"slow-hashes [%lu] half-hashes[%lu] skipped-hashes [%lu] full-hashes [%lu] blocks [%lu] total [%lu micros] per half-hash[%.2f micros] per hash [%.2f micros]\\n\\n\", slowHashCounter.load(), halfHashCounter.load(), skippedHashCounter.load(), hashCounter.load(), blockCounter.load(), (GetTimeMicros() - nStart), nHalfHashAverage, ((GetTimeMicros() - nStart)) / (double)hashCounter);\n        \n        //Extrapolate sustained hashing speed for various time intervals\n        double nSustainedHashesPerSecond30s  = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 30);\n        double nSustainedHashesPerSecond60s  = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 60);\n        double nSustainedHashesPerSecond120s = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 120);\n        double nSustainedHashesPerSecond     = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 150);\n        double nSustainedHashesPerSecond240s = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 240);\n        double nSustainedHashesPerSecond480s = calculateSustainedHashrateForTimePeriod(defaultSigmaSettings.numHashesPre, defaultSigmaSettings.numHashesPost, nHalfHashAverage, nArenaSetuptime, 480);\n        \n        // Convert to the largest unit we can so that output is easier to read\n        std::string labelSustained = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond, labelSustained);\n        std::string labelSustained30s = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond30s, labelSustained30s);\n        std::string labelSustained60s = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond60s, labelSustained60s);\n        std::string labelSustained120s = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond120s, labelSustained120s);\n        std::string labelSustained240s = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond240s, labelSustained240s);\n        std::string labelSustained480s = \" h\";        \n        selectLargesHashUnit(nSustainedHashesPerSecond480s, labelSustained480s);\n        \n        // Log extrapolated speeds\n        printf(\"Extrapolate sustained hashrates for block timings\\n\");\n        printf(\"Estimated 30s hashrate %.2f %s/s\\n\", nSustainedHashesPerSecond30s, labelSustained30s.c_str());\n        printf(\"Estimated 1m hashrate  %.2f %s/s\\n\", nSustainedHashesPerSecond60s, labelSustained60s.c_str());\n        printf(\"Estimated 2m hashrate  %.2f %s/s\\n\", nSustainedHashesPerSecond120s, labelSustained120s.c_str());\n        printf(\"Estimated 4m hashrate  %.2f %s/s\\n\", nSustainedHashesPerSecond240s, labelSustained240s.c_str());\n        printf(\"Estimated 8m hashrate  %.2f %s/s\\n\", nSustainedHashesPerSecond480s, labelSustained480s.c_str());\n        \n        // Log a highly noticeable number for users who just want a number to compare without all the gritty details.\n        printf(\"\\n===========================================================\");\n        printf(\"\\n* Estimated continuous sustained hashrate %10.2f %s/s *\", nSustainedHashesPerSecond, labelSustained.c_str());\n        printf(\"\\n===========================================================\\n\");\n    }\n    \n    uint64_t nMineEnd = GetTimeMicros();\n    printf(\"\\nBenchmarks finished in [%.2f seconds]\\n\", (nMineEnd-nMineStart)*0.000001);\n    \n    if ((nMineEnd-nMineStart)*0.000001<30)\n    {\n        // Calculate hash target to spend 40 seconds running and suggest user set that.\n        // NB! We delibritely test for 30 but calculate on 40 to prevent making people run the program multiple times unnecessarily.\n        uint64_t nTimeSpentMining = (nMineEnd - (nArenaSetuptime+nMineStart));\n        double nMultiplier = ((40*1000000) / nTimeSpentMining);\n        \n        printf(\"Mining benchmark too fast to be accurate recommend running with `--mine-num-hashes=%lu` or larger for at least 30 seconds of benchmarking.\\n\", (uint64_t)(numFullHashesTarget*nMultiplier));\n    }\n    //NB! We leak sigmaContexts here, we don't really care because this is a trivial benchmark program its faster for the user to just exit than to actually free them.\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/bench/ccoins_caching.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"coins.h\"\n#include \"policy/policy.h\"\n#include \"wallet/crypter.h\"\n\n#include <vector>\n\n// FIXME: (Bitcoin) Dedup with SetupDummyInputs in test/transaction_tests.cpp.\n//\n// Helper: create two dummy transactions, each with\n// two outputs.  The first has 11 and 50 CENT outputs\n// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs\n// paid to a TX_PUBKEYHASH.\n//\nstatic std::vector<CMutableTransaction>\nSetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)\n{\n    std::vector<CMutableTransaction> dummyTransactions;\n    //dummyTransactions.resize(2);\n\n    // Add some keys to the keystore:\n    CKey key[4];\n    for (int i = 0; i < 4; i++) {\n        key[i].MakeNewKey(i % 2);\n        keystoreRet.AddKey(key[i]);\n    }\n\n    // Create some dummy input transactions\n    dummyTransactions[0].vout.resize(2);\n    dummyTransactions[0].vout[0].nValue = 11 * CENT;\n    dummyTransactions[0].vout[0].output.scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;\n    dummyTransactions[0].vout[1].nValue = 50 * CENT;\n    dummyTransactions[0].vout[1].output.scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;\n    AddCoins(coinsRet, dummyTransactions[0], 0, 0);\n\n    dummyTransactions[1].vout.resize(2);\n    dummyTransactions[1].vout[0].nValue = 21 * CENT;\n    dummyTransactions[1].vout[0].output.scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());\n    dummyTransactions[1].vout[1].nValue = 22 * CENT;\n    dummyTransactions[1].vout[1].output.scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());\n    AddCoins(coinsRet, dummyTransactions[1], 0, 0);\n\n    return dummyTransactions;\n}\n\n// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from\n// laanwj, \"replicating the actual usage patterns of the client is hard though,\n// many times micro-benchmarks of the database showed completely different\n// characteristics than e.g. reindex timings. But that's not a requirement of\n// every benchmark.\"\n// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)\nstatic void CCoinsCaching(benchmark::State& state)\n{\n    CBasicKeyStore keystore;\n    CCoinsView coinsDummy;\n    CCoinsViewCache coins(&coinsDummy);\n    std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);\n\n    CMutableTransaction t1(1);\n    t1.vin.resize(3);\n    t1.vin[0].prevout.setHash(dummyTransactions[0].GetHash());\n    t1.vin[0].prevout.n = 1;\n    t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);\n    t1.vin[1].prevout.setHash(dummyTransactions[1].GetHash());\n    t1.vin[1].prevout.n = 0;\n    t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);\n    t1.vin[2].prevout.setHash(dummyTransactions[1].GetHash());\n    t1.vin[2].prevout.n = 1;\n    t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);\n    t1.vout.resize(2);\n    t1.vout[0].nValue = 90 * CENT;\n    t1.vout[0].output.scriptPubKey << OP_1;\n\n    // Benchmark.\n    while (state.KeepRunning()) {\n        bool success = AreInputsStandard(t1, coins);\n        assert(success);\n        CAmount value = coins.GetValueIn(t1);\n        assert(value == (50 + 21 + 22) * CENT);\n    }\n}\n\nBENCHMARK(CCoinsCaching);\n"
  },
  {
    "path": "src/bench/checkblock.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n\n#include \"chainparams.h\"\n#include \"validation/validation.h\"\n#include \"streams.h\"\n#include \"consensus/validation.h\"\n\nnamespace block_bench {\n#include \"bench/data/block413567.raw.h\"\n}\n\n// These are the two major time-sinks which happen after we have fully received\n// a block off the wire, but before we can relay the block on to peers using\n// compact block relay.\n\nstatic void DeserializeBlockTest(benchmark::State& state)\n{\n    CDataStream stream((const char*)block_bench::block413567,\n            (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],\n            SER_NETWORK, PROTOCOL_VERSION);\n    char a = '\\0';\n    stream.write(&a, 1); // Prevent compaction\n\n    while (state.KeepRunning()) {\n        CBlock block;\n        stream >> block;\n        assert(stream.Rewind(sizeof(block_bench::block413567)));\n    }\n}\n\nstatic void DeserializeAndCheckBlockTest(benchmark::State& state)\n{\n    CDataStream stream((const char*)block_bench::block413567,\n            (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],\n            SER_NETWORK, PROTOCOL_VERSION);\n    char a = '\\0';\n    stream.write(&a, 1); // Prevent compaction\n\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n\n    while (state.KeepRunning()) {\n        CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here\n        stream >> block;\n        assert(stream.Rewind(sizeof(block_bench::block413567)));\n\n        CValidationState validationState;\n        assert(CheckBlock(block, validationState, chainParams->GetConsensus()));\n    }\n}\n\nBENCHMARK(DeserializeBlockTest);\nBENCHMARK(DeserializeAndCheckBlockTest);\n"
  },
  {
    "path": "src/bench/checkqueue.cpp",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"util.h\"\n#include \"validation/validation.h\"\n#include \"checkqueue.h\"\n#include \"prevector.h\"\n#include <vector>\n#include <boost/thread/thread.hpp>\n#include \"random.h\"\n\n\n// This Benchmark tests the CheckQueue with the lightest\n// weight Checks, so it should make any lock contention\n// particularly visible\nstatic const int MIN_CORES = 2;\nstatic const size_t BATCHES = 101;\nstatic const size_t BATCH_SIZE = 30;\nstatic const int PREVECTOR_SIZE = 28;\nstatic const int QUEUE_BATCH_SIZE = 128;\nstatic void CCheckQueueSpeed(benchmark::State& state)\n{\n    struct FakeJobNoWork {\n        bool operator()()\n        {\n            return true;\n        }\n        void swap(FakeJobNoWork& x){};\n    };\n    CCheckQueue<FakeJobNoWork> queue {QUEUE_BATCH_SIZE};\n    // The main thread should be counted to prevent thread oversubscription, and\n    // to decrease the variance of benchmark results.\n    while (state.KeepRunning()) {\n        CCheckQueueControl<FakeJobNoWork> control(&queue);\n\n        // We call Add a number of times to simulate the behavior of adding\n        // a block of transactions at once.\n\n        std::vector<std::vector<FakeJobNoWork>> vBatches(BATCHES);\n        for (auto& vChecks : vBatches) {\n            vChecks.resize(BATCH_SIZE);\n        }\n        for (auto& vChecks : vBatches) {\n            // We can't make vChecks in the inner loop because we want to measure\n            // the cost of getting the memory to each thread and we might get the same\n            // memory\n            control.Add(vChecks);\n        }\n        // control waits for completion by RAII, but\n        // it is done explicitly here for clarity\n        control.Wait();\n    }\n    queue.StopWorkerThreads();\n}\n\n// This Benchmark tests the CheckQueue with a slightly realistic workload,\n// where checks all contain a prevector that is indirect 50% of the time\n// and there is a little bit of work done between calls to Add.\nstatic void CCheckQueueSpeedPrevectorJob(benchmark::State& state)\n{\n    struct PrevectorJob {\n        prevector<PREVECTOR_SIZE, uint8_t> p;\n        PrevectorJob(){\n        }\n        PrevectorJob(FastRandomContext& insecure_rand){\n            p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));\n        }\n        bool operator()()\n        {\n            return true;\n        }\n        void swap(PrevectorJob& x){p.swap(x.p);};\n    };\n    CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};\n\n    // The main thread should be counted to prevent thread oversubscription, and\n    // to decrease the variance of benchmark results.\n    queue.StartWorkerThreads(std::max(MIN_CORES, GetNumCores()-1));\n\n    while (state.KeepRunning()) {\n        // Make insecure_rand here so that each iteration is identical.\n        FastRandomContext insecure_rand(true);\n        CCheckQueueControl<PrevectorJob> control(&queue);\n        std::vector<std::vector<PrevectorJob>> vBatches(BATCHES);\n        for (auto& vChecks : vBatches) {\n            vChecks.reserve(BATCH_SIZE);\n            for (size_t x = 0; x < BATCH_SIZE; ++x)\n                vChecks.emplace_back(insecure_rand);\n            control.Add(vChecks);\n        }\n        // control waits for completion by RAII, but\n        // it is done explicitly here for clarity\n        control.Wait();\n    }\n    queue.StopWorkerThreads();\n}\nBENCHMARK(CCheckQueueSpeed);\nBENCHMARK(CCheckQueueSpeedPrevectorJob);\n"
  },
  {
    "path": "src/bench/coin_selection.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"wallet/wallet.h\"\n\n#include <set>\n\nstatic void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<COutput>& vCoins)\n{\n    int nInput = 0;\n\n    static int nextLockTime = 0;\n    CMutableTransaction tx(1);\n    tx.nLockTime = nextLockTime++; // so all transactions get different hashes\n    tx.vout.resize(nInput + 1);\n    tx.vout[nInput].nValue = nValue;\n    CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));\n\n    int nAge = 6 * 24;\n    COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);\n    vCoins.push_back(output);\n}\n\n// Simple benchmark for wallet coin selection. Note that it maybe be necessary\n// to build up more complicated scenarios in order to get meaningful\n// measurements of performance. From laanwj, \"Wallet coin selection is probably\n// the hardest, as you need a wider selection of scenarios, just testing the\n// same one over and over isn't too useful. Generating random isn't useful\n// either for measurements.\"\n// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)\nstatic void CoinSelection(benchmark::State& state)\n{\n    const CWallet wallet;\n    std::vector<COutput> vCoins;\n    LOCK(wallet.cs_wallet);\n\n    while (state.KeepRunning()) {\n        // Empty wallet.\n        for (COutput output : vCoins)\n            delete output.tx;\n        vCoins.clear();\n\n        // Add coins.\n        for (int i = 0; i < 1000; i++)\n            addCoin(1000 * COIN, wallet, vCoins);\n        addCoin(3 * COIN, wallet, vCoins);\n\n        std::set<CInputCoin> setCoinsRet;\n        CAmount nValueRet;\n        bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false);\n        assert(success);\n        assert(nValueRet == 1003 * COIN);\n        assert(setCoinsRet.size() == 2);\n    }\n}\n\nBENCHMARK(CoinSelection);\n"
  },
  {
    "path": "src/bench/crypto_hash.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <iostream>\n\n#include \"bench.h\"\n#include \"bloom.h\"\n#include \"hash.h\"\n#include \"random.h\"\n#include \"uint256.h\"\n#include \"utiltime.h\"\n#include \"crypto/ripemd160.h\"\n#include \"crypto/sha1.h\"\n#include \"crypto/sha256.h\"\n#include \"crypto/sha512.h\"\n\n/* Number of bytes to hash per iteration */\nstatic const uint64_t BUFFER_SIZE = 1000*1000;\n\nstatic void RIPEMD160(benchmark::State& state)\n{\n    uint8_t hash[CRIPEMD160::OUTPUT_SIZE];\n    std::vector<uint8_t> in(BUFFER_SIZE,0);\n    while (state.KeepRunning())\n        CRIPEMD160().Write(in.data(), in.size()).Finalize(hash);\n}\n\nstatic void SHA1(benchmark::State& state)\n{\n    uint8_t hash[CSHA1::OUTPUT_SIZE];\n    std::vector<uint8_t> in(BUFFER_SIZE,0);\n    while (state.KeepRunning())\n        CSHA1().Write(in.data(), in.size()).Finalize(hash);\n}\n\nstatic void SHA256(benchmark::State& state)\n{\n    uint8_t hash[CSHA256::OUTPUT_SIZE];\n    std::vector<uint8_t> in(BUFFER_SIZE,0);\n    while (state.KeepRunning())\n        CSHA256().Write(in.data(), in.size()).Finalize(hash);\n}\n\nstatic void SHA256_32b(benchmark::State& state)\n{\n    std::vector<uint8_t> in(32,0);\n    while (state.KeepRunning()) {\n        for (int i = 0; i < 1000000; i++) {\n            CSHA256().Write(in.data(), in.size()).Finalize(&in[0]);\n        }\n    }\n}\n\nstatic void SHA512(benchmark::State& state)\n{\n    uint8_t hash[CSHA512::OUTPUT_SIZE];\n    std::vector<uint8_t> in(BUFFER_SIZE,0);\n    while (state.KeepRunning())\n        CSHA512().Write(in.data(), in.size()).Finalize(hash);\n}\n\nstatic void SipHash_32b(benchmark::State& state)\n{\n    uint256 x;\n    while (state.KeepRunning()) {\n        for (int i = 0; i < 1000000; i++) {\n            *((uint64_t*)x.begin()) = SipHashUint256(0, i, x);\n        }\n    }\n}\n\nstatic void FastRandom_32bit(benchmark::State& state)\n{\n    FastRandomContext rng(true);\n    uint32_t x = 0;\n    while (state.KeepRunning()) {\n        for (int i = 0; i < 1000000; i++) {\n            x += rng.rand32();\n        }\n    }\n}\n\nstatic void FastRandom_1bit(benchmark::State& state)\n{\n    FastRandomContext rng(true);\n    uint32_t x = 0;\n    while (state.KeepRunning()) {\n        for (int i = 0; i < 1000000; i++) {\n            x += rng.randbool();\n        }\n    }\n}\n\nBENCHMARK(RIPEMD160);\nBENCHMARK(SHA1);\nBENCHMARK(SHA256);\nBENCHMARK(SHA512);\n\nBENCHMARK(SHA256_32b);\nBENCHMARK(SipHash_32b);\nBENCHMARK(FastRandom_32bit);\nBENCHMARK(FastRandom_1bit);\n"
  },
  {
    "path": "src/bench/lockedpool.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n\n#include \"support/lockedpool.h\"\n\n#include <iostream>\n#include <vector>\n\n#define ASIZE 2048\n#define BITER 5000\n#define MSIZE 2048\n\nstatic void BenchLockedPool(benchmark::State& state)\n{\n    void *synth_base = reinterpret_cast<void*>(0x08000000);\n    const size_t synth_size = 1024*1024;\n    Arena b(synth_base, synth_size, 16);\n\n    std::vector<void*> addr;\n    for (int x=0; x<ASIZE; ++x)\n        addr.push_back(0);\n    uint32_t s = 0x12345678;\n    while (state.KeepRunning()) {\n        for (int x=0; x<BITER; ++x) {\n            int idx = s & (addr.size()-1);\n            if (s & 0x80000000) {\n                b.free(addr[idx]);\n                addr[idx] = 0;\n            } else if(!addr[idx]) {\n                addr[idx] = b.alloc((s >> 16) & (MSIZE-1));\n            }\n            bool lsb = s & 1;\n            s >>= 1;\n            if (lsb)\n                s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0\n        }\n    }\n    for (void *ptr: addr)\n        b.free(ptr);\n    addr.clear();\n}\n\nBENCHMARK(BenchLockedPool);\n\n"
  },
  {
    "path": "src/bench/mempool_eviction.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"policy/policy.h\"\n#include \"txmempool.h\"\n\n#include <list>\n#include <vector>\n\nstatic void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)\n{\n    int64_t nTime = 0;\n    unsigned int nHeight = 1;\n    bool spendsCoinbase = false;\n    unsigned int sigOpCost = 4;\n    LockPoints lp;\n    pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(\n                                        MakeTransactionRef(tx), nFee, nTime, nHeight,\n                                        spendsCoinbase, sigOpCost, lp));\n}\n\n// Right now this is only testing eviction performance in an extremely small\n// mempool. Code needs to be written to generate a much wider variety of\n// unique transactions for a more meaningful performance measurement.\nstatic void MempoolEviction(benchmark::State& state)\n{\n    CMutableTransaction tx1 = CMutableTransaction(1);\n    tx1.vin.resize(1);\n    tx1.vin[0].scriptSig = CScript() << OP_1;\n    tx1.vout.resize(1);\n    tx1.vout[0].output.scriptPubKey = CScript() << OP_1 << OP_EQUAL;\n    tx1.vout[0].nValue = 10 * COIN;\n\n    CMutableTransaction tx2 = CMutableTransaction(1);\n    tx2.vin.resize(1);\n    tx2.vin[0].scriptSig = CScript() << OP_2;\n    tx2.vout.resize(1);\n    tx2.vout[0].output.scriptPubKey = CScript() << OP_2 << OP_EQUAL;\n    tx2.vout[0].nValue = 10 * COIN;\n\n    CMutableTransaction tx3 = CMutableTransaction(1);\n    tx3.vin.resize(1);\n    tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);\n    tx3.vin[0].scriptSig = CScript() << OP_2;\n    tx3.vout.resize(1);\n    tx3.vout[0].output.scriptPubKey = CScript() << OP_3 << OP_EQUAL;\n    tx3.vout[0].nValue = 10 * COIN;\n\n    CMutableTransaction tx4 = CMutableTransaction(1);\n    tx4.vin.resize(2);\n    tx4.vin[0].prevout.SetNull();\n    tx4.vin[0].scriptSig = CScript() << OP_4;\n    tx4.vin[1].prevout.SetNull();\n    tx4.vin[1].scriptSig = CScript() << OP_4;\n    tx4.vout.resize(2);\n    tx4.vout[0].output.scriptPubKey = CScript() << OP_4 << OP_EQUAL;\n    tx4.vout[0].nValue = 10 * COIN;\n    tx4.vout[1].output.scriptPubKey = CScript() << OP_4 << OP_EQUAL;\n    tx4.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx5 = CMutableTransaction(1);\n    tx5.vin.resize(2);\n    tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);\n    tx5.vin[0].scriptSig = CScript() << OP_4;\n    tx5.vin[1].prevout.SetNull();\n    tx5.vin[1].scriptSig = CScript() << OP_5;\n    tx5.vout.resize(2);\n    tx5.vout[0].output.scriptPubKey = CScript() << OP_5 << OP_EQUAL;\n    tx5.vout[0].nValue = 10 * COIN;\n    tx5.vout[1].output.scriptPubKey = CScript() << OP_5 << OP_EQUAL;\n    tx5.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx6 = CMutableTransaction(1);\n    tx6.vin.resize(2);\n    tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);\n    tx6.vin[0].scriptSig = CScript() << OP_4;\n    tx6.vin[1].prevout.SetNull();\n    tx6.vin[1].scriptSig = CScript() << OP_6;\n    tx6.vout.resize(2);\n    tx6.vout[0].output.scriptPubKey = CScript() << OP_6 << OP_EQUAL;\n    tx6.vout[0].nValue = 10 * COIN;\n    tx6.vout[1].output.scriptPubKey = CScript() << OP_6 << OP_EQUAL;\n    tx6.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx7 = CMutableTransaction(1);\n    tx7.vin.resize(2);\n    tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);\n    tx7.vin[0].scriptSig = CScript() << OP_5;\n    tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);\n    tx7.vin[1].scriptSig = CScript() << OP_6;\n    tx7.vout.resize(2);\n    tx7.vout[0].output.scriptPubKey = CScript() << OP_7 << OP_EQUAL;\n    tx7.vout[0].nValue = 10 * COIN;\n    tx7.vout[1].output.scriptPubKey = CScript() << OP_7 << OP_EQUAL;\n    tx7.vout[1].nValue = 10 * COIN;\n\n    CTxMemPool pool;\n\n    while (state.KeepRunning()) {\n        AddTx(tx1, 10000LL, pool);\n        AddTx(tx2, 5000LL, pool);\n        AddTx(tx3, 20000LL, pool);\n        AddTx(tx4, 7000LL, pool);\n        AddTx(tx5, 1000LL, pool);\n        AddTx(tx6, 1100LL, pool);\n        AddTx(tx7, 9000LL, pool);\n        pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);\n        pool.TrimToSize(GetVirtualTransactionSize(tx1));\n    }\n}\n\nBENCHMARK(MempoolEviction);\n"
  },
  {
    "path": "src/bench/perf.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"perf.h\"\n\n#if defined(__i386__) || defined(__x86_64__)\n\n/* These architectures support querying the cycle counter\n * from user space, no need for any syscall overhead.\n */\nvoid perf_init(void) { }\nvoid perf_fini(void) { }\n\n#elif defined(__linux__)\n\n#include <unistd.h>\n#include <sys/syscall.h>\n#include <linux/perf_event.h>\n\nstatic int fd = -1;\nstatic struct perf_event_attr attr;\n\nvoid perf_init(void)\n{\n    attr.type = PERF_TYPE_HARDWARE;\n    attr.config = PERF_COUNT_HW_CPU_CYCLES;\n    fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);\n}\n\nvoid perf_fini(void)\n{\n    if (fd != -1) {\n        close(fd);\n    }\n}\n\nuint64_t perf_cpucycles(void)\n{\n    uint64_t result = 0;\n    if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {\n        return 0;\n    }\n    return result;\n}\n\n#else /* Unhandled platform */\n\nvoid perf_init(void) { }\nvoid perf_fini(void) { }\nuint64_t perf_cpucycles(void) { return 0; }\n\n#endif\n"
  },
  {
    "path": "src/bench/perf.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n/** Functions for measurement of CPU cycles */\n#ifndef H_PERF\n#define H_PERF\n\n#include <stdint.h>\n\n#if defined(__i386__)\n\nstatic inline uint64_t perf_cpucycles(void)\n{\n    uint64_t x;\n    __asm__ volatile (\".byte 0x0f, 0x31\" : \"=A\" (x));\n    return x;\n}\n\n#elif defined(__x86_64__)\n\nstatic inline uint64_t perf_cpucycles(void)\n{\n    uint32_t hi, lo;\n    __asm__ __volatile__ (\"rdtsc\" : \"=a\"(lo), \"=d\"(hi));\n    return ((uint64_t)lo)|(((uint64_t)hi)<<32);\n}\n#else\n\nuint64_t perf_cpucycles(void);\n\n#endif\n\nvoid perf_init(void);\nvoid perf_fini(void);\n\n#endif // H_PERF\n"
  },
  {
    "path": "src/bench/prevector_destructor.cpp",
    "content": "// Copyright (c) 2015-2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"prevector.h\"\n\nstatic void PrevectorDestructor(benchmark::State& state)\n{\n    while (state.KeepRunning()) {\n        for (auto x = 0; x < 1000; ++x) {\n            prevector<28, unsigned char> t0;\n            prevector<28, unsigned char> t1;\n            t0.resize(28);\n            t1.resize(29);\n        }\n    }\n}\n\nstatic void PrevectorClear(benchmark::State& state)\n{\n\n    while (state.KeepRunning()) {\n        for (auto x = 0; x < 1000; ++x) {\n            prevector<28, unsigned char> t0;\n            prevector<28, unsigned char> t1;\n            t0.resize(28);\n            t0.clear();\n            t1.resize(29);\n            t0.clear();\n        }\n    }\n}\n\nBENCHMARK(PrevectorDestructor);\nBENCHMARK(PrevectorClear);\n"
  },
  {
    "path": "src/bench/rollingbloom.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <iostream>\n\n#include \"bench.h\"\n#include \"bloom.h\"\n#include \"utiltime.h\"\n\nstatic void RollingBloom(benchmark::State& state)\n{\n    CRollingBloomFilter filter(120000, 0.000001);\n    std::vector<unsigned char> data(32);\n    uint32_t count = 0;\n    uint32_t nEntriesPerGeneration = (120000 + 1) / 2;\n    uint32_t countnow = 0;\n    uint64_t match = 0;\n    while (state.KeepRunning()) {\n        count++;\n        data[0] = count;\n        data[1] = count >> 8;\n        data[2] = count >> 16;\n        data[3] = count >> 24;\n        if (countnow == nEntriesPerGeneration) {\n            int64_t b = GetTimeMicros();\n            filter.insert(data);\n            int64_t e = GetTimeMicros();\n            std::cout << \"RollingBloom-refresh,1,\" << (e-b)*0.000001 << \",\" << (e-b)*0.000001 << \",\" << (e-b)*0.000001 << \"\\n\";\n            countnow = 0;\n        } else {\n            filter.insert(data);\n        }\n        countnow++;\n        data[0] = count >> 24;\n        data[1] = count >> 16;\n        data[2] = count >> 8;\n        data[3] = count;\n        match += filter.contains(data);\n    }\n}\n\nBENCHMARK(RollingBloom);\n"
  },
  {
    "path": "src/bench/verify_script.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"bench.h\"\n#include \"key.h\"\n#if defined(HAVE_CONSENSUS_LIB)\n#include \"script/consensus.h\"\n#endif\n#include \"script/script.h\"\n#include \"script/sign.h\"\n#include \"streams.h\"\n\n// FIXME: (Bitcoin) Dedup with BuildCreditingTransaction in test/script_tests.cpp.\nstatic CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)\n{\n    CMutableTransaction txCredit(1);\n    txCredit.nVersion = 1;\n    txCredit.nLockTime = 0;\n    txCredit.vin.resize(1);\n    txCredit.vout.resize(1);\n    txCredit.vin[0].prevout.SetNull();\n    txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);\n    //fixme: (PHASE5)\n    txCredit.vin[0].SetSequence(CTxIn::SEQUENCE_FINAL, 1, CTxInFlags::None);\n    txCredit.vout[0].output.scriptPubKey = scriptPubKey;\n    txCredit.vout[0].nValue = 1;\n\n    return txCredit;\n}\n\n// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.\nstatic CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)\n{\n    CMutableTransaction txSpend(1);\n    txSpend.nVersion = 1;\n    txSpend.nLockTime = 0;\n    txSpend.vin.resize(1);\n    txSpend.vout.resize(1);\n    txSpend.vin[0].prevout.setHash(txCredit.GetHash());\n    txSpend.vin[0].prevout.n = 0;\n    txSpend.vin[0].scriptSig = scriptSig;\n    //fixme: (PHASE5)\n    txSpend.vin[0].SetSequence(CTxIn::SEQUENCE_FINAL, 1, CTxInFlags::None);\n    txSpend.vout[0].output.scriptPubKey = CScript();\n    txSpend.vout[0].nValue = txCredit.vout[0].nValue;\n\n    return txSpend;\n}\n\n// Microbenchmark for verification of a basic P2WPKH script. Can be easily\n// modified to measure performance of other types of scripts.\nstatic void VerifyScriptBench(benchmark::State& state)\n{\n    //fixme: (PHASE5) - implement if needed\n}\n\n//fixme: (PHASE5) - implement if needed\n//BENCHMARK(VerifyScriptBench);\n"
  },
  {
    "path": "src/blockencodings.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"blockencodings.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/validation.h\"\n#include \"chainparams.h\"\n#include \"hash.h\"\n#include \"random.h\"\n#include \"streams.h\"\n#include \"txmempool.h\"\n#include \"validation/validation.h\"\n#include \"util.h\"\n\n#include <unordered_map>\n\n//fixme: (PHASE5) (SEGSIG)\n#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(1), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES))\n\nCBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :\n        nonce(GetRand(std::numeric_limits<uint64_t>::max())),\n        shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {\n    FillShortTxIDSelector();\n    //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase\n    prefilledtxn[0] = {0, block.vtx[0]};\n    for (size_t i = 1; i < block.vtx.size(); i++) {\n        const CTransaction& tx = *block.vtx[i];\n        shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());\n    }\n}\n\nvoid CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << header << nonce;\n    CSHA256 hasher;\n    hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin());\n    uint256 shorttxidhash;\n    hasher.Finalize(shorttxidhash.begin());\n    shorttxidk0 = shorttxidhash.GetUint64(0);\n    shorttxidk1 = shorttxidhash.GetUint64(1);\n}\n\nuint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {\n    static_assert(SHORTTXIDS_LENGTH == 6, \"shorttxids calculation assumes 6-byte shorttxids\");\n    return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;\n}\n\n\n\nReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {\n    if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))\n        return READ_STATUS_INVALID;\n    if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE)\n        return READ_STATUS_INVALID;\n\n    assert(header.IsNull() && txn_available.empty());\n    header = cmpctblock.header;\n    txn_available.resize(cmpctblock.BlockTxCount());\n\n    int32_t lastprefilledindex = -1;\n    for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {\n        if (cmpctblock.prefilledtxn[i].tx->IsNull())\n            return READ_STATUS_INVALID;\n\n        lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so can't overflow here\n        if (lastprefilledindex > std::numeric_limits<uint16_t>::max())\n            return READ_STATUS_INVALID;\n        if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) {\n            // If we are inserting a tx at an index greater than our full list of shorttxids\n            // plus the number of prefilled txn we've inserted, then we have txn for which we\n            // have neither a prefilled txn or a shorttxid!\n            return READ_STATUS_INVALID;\n        }\n        txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;\n    }\n    prefilled_count = cmpctblock.prefilledtxn.size();\n\n    // Calculate map of txids -> positions and check mempool to see what we have (or don't)\n    // Because well-formed cmpctblock messages will have a (relatively) uniform distribution\n    // of short IDs, any highly-uneven distribution of elements can be safely treated as a\n    // READ_STATUS_FAILED.\n    std::unordered_map<uint64_t, uint16_t> shorttxids(cmpctblock.shorttxids.size());\n    uint16_t index_offset = 0;\n    for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) {\n        while (txn_available[i + index_offset])\n            index_offset++;\n        shorttxids[cmpctblock.shorttxids[i]] = i + index_offset;\n        // To determine the chance that the number of entries in a bucket exceeds N,\n        // we use the fact that the number of elements in a single bucket is\n        // binomially distributed (with n = the number of shorttxids S, and p =\n        // 1 / the number of buckets), that in the worst case the number of buckets is\n        // equal to S (due to std::unordered_map having a default load factor of 1.0),\n        // and that the chance for any bucket to exceed N elements is at most\n        // buckets * (the chance that any given bucket is above N elements).\n        // Thus: P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N)).\n        // If we assume blocks of up to 16000, allowing 12 elements per bucket should\n        // only fail once per ~1 million block transfers (per peer and connection).\n        if (shorttxids.bucket_size(shorttxids.bucket(cmpctblock.shorttxids[i])) > 12)\n            return READ_STATUS_FAILED;\n    }\n    // TODO: in the shortid-collision case, we should instead request both transactions\n    // which collided. Falling back to full-block-request here is overkill.\n    if (shorttxids.size() != cmpctblock.shorttxids.size())\n        return READ_STATUS_FAILED; // Short ID collision\n\n    std::vector<bool> have_txn(txn_available.size());\n    {\n    LOCK(pool->cs);\n    const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;\n    for (size_t i = 0; i < vTxHashes.size(); i++) {\n        uint64_t shortid = cmpctblock.GetShortID(vTxHashes[i].first);\n        std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);\n        if (idit != shorttxids.end()) {\n            if (!have_txn[idit->second]) {\n                txn_available[idit->second] = vTxHashes[i].second->GetSharedTx();\n                have_txn[idit->second]  = true;\n                mempool_count++;\n            } else {\n                // If we find two mempool txn that match the short id, just request it.\n                // This should be rare enough that the extra bandwidth doesn't matter,\n                // but eating a round-trip due to FillBlock failure would be annoying\n                if (txn_available[idit->second]) {\n                    txn_available[idit->second].reset();\n                    mempool_count--;\n                }\n            }\n        }\n        // Though ideally we'd continue scanning for the two-txn-match-shortid case,\n        // the performance win of an early exit here is too good to pass up and worth\n        // the extra risk.\n        if (mempool_count == shorttxids.size())\n            break;\n    }\n    }\n\n    for (size_t i = 0; i < extra_txn.size(); i++) {\n        uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);\n        std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);\n        if (idit != shorttxids.end()) {\n            if (!have_txn[idit->second]) {\n                txn_available[idit->second] = extra_txn[i].second;\n                have_txn[idit->second]  = true;\n                mempool_count++;\n                extra_count++;\n            } else {\n                // If we find two mempool/extra txn that match the short id, just\n                // request it.\n                // This should be rare enough that the extra bandwidth doesn't matter,\n                // but eating a round-trip due to FillBlock failure would be annoying\n                // Note that we don't want duplication between extra_txn and mempool to\n                // trigger this case, so we compare witness hashes first\n                if (txn_available[idit->second] &&\n                        txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {\n                    txn_available[idit->second].reset();\n                    mempool_count--;\n                    extra_count--;\n                }\n            }\n        }\n        // Though ideally we'd continue scanning for the two-txn-match-shortid case,\n        // the performance win of an early exit here is too good to pass up and worth\n        // the extra risk.\n        if (mempool_count == shorttxids.size())\n            break;\n    }\n\n    LogPrint(BCLog::CMPCTBLOCK, \"Initialized PartiallyDownloadedBlock for block %s %s using a cmpctblock of size %lu\\n\", cmpctblock.header.GetHashLegacy().ToString(), cmpctblock.header.GetHashPoW2().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));\n\n    return READ_STATUS_OK;\n}\n\nbool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {\n    assert(!header.IsNull());\n    assert(index < txn_available.size());\n    return txn_available[index] ? true : false;\n}\n\nReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) {\n    assert(!header.IsNull());\n    uint256 hash;\n    if (header.nVersionPoW2Witness == 0)\n        hash = header.GetHashLegacy();\n    else\n        hash = header.GetHashPoW2();\n    block = header;\n    block.vtx.resize(txn_available.size());\n\n    size_t tx_missing_offset = 0;\n    for (size_t i = 0; i < txn_available.size(); i++) {\n        if (!txn_available[i]) {\n            if (vtx_missing.size() <= tx_missing_offset)\n                return READ_STATUS_INVALID;\n            block.vtx[i] = vtx_missing[tx_missing_offset++];\n        } else\n            block.vtx[i] = std::move(txn_available[i]);\n    }\n\n    // Make sure we can't call FillBlock again.\n    header.SetNull();\n    txn_available.clear();\n\n    if (vtx_missing.size() != tx_missing_offset)\n        return READ_STATUS_INVALID;\n\n    CValidationState state;\n    if (!CheckBlock(block, state, Params().GetConsensus())) {\n        // TODO: We really want to just check merkle tree manually here,\n        // but that is expensive, and CheckBlock caches a block's\n        // \"checked-status\" (in the CBlock?). CBlock should be able to\n        // check its own merkle root and cache that check.\n        if (state.CorruptionPossible())\n            return READ_STATUS_FAILED; // Possible Short ID collision\n        return READ_STATUS_CHECKBLOCK_FAILED;\n    }\n\n    LogPrint(BCLog::CMPCTBLOCK, \"Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\\n\", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size());\n    if (vtx_missing.size() < 5) {\n        for (const auto& tx : vtx_missing) {\n            LogPrint(BCLog::CMPCTBLOCK, \"Reconstructed block %s required tx %s\\n\", hash.ToString(), tx->GetHash().ToString());\n        }\n    }\n\n    return READ_STATUS_OK;\n}\n"
  },
  {
    "path": "src/blockencodings.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLOCK_ENCODINGS_H\n#define BLOCK_ENCODINGS_H\n\n#include \"primitives/block.h\"\n\n#include <memory>\n\nclass CTxMemPool;\n\n// Dumb helper to handle CTransaction compression at serialize-time\nstruct TransactionCompressor {\nprivate:\n    CTransactionRef& tx;\npublic:\n    TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(tx); //TODO: Compress tx encoding\n    }\n};\n\nclass BlockTransactionsRequest {\npublic:\n    // A BlockTransactionsRequest message\n    uint256 blockhash;\n    std::vector<uint16_t> indexes;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(blockhash);\n        uint64_t indexes_size = (uint64_t)indexes.size();\n        READWRITE(COMPACTSIZE(indexes_size));\n        if (ser_action.ForRead()) {\n            size_t i = 0;\n            while (indexes.size() < indexes_size) {\n                indexes.resize(std::min((uint64_t)(1000 + indexes.size()), indexes_size));\n                for (; i < indexes.size(); i++) {\n                    uint64_t index = 0;\n                    READWRITE(COMPACTSIZE(index));\n                    if (index > std::numeric_limits<uint16_t>::max())\n                        throw std::ios_base::failure(\"index overflowed 16 bits\");\n                    indexes[i] = index;\n                }\n            }\n\n            uint16_t offset = 0;\n            for (size_t j = 0; j < indexes.size(); j++) {\n                if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())\n                    throw std::ios_base::failure(\"indexes overflowed 16 bits\");\n                indexes[j] = indexes[j] + offset;\n                offset = indexes[j] + 1;\n            }\n        } else {\n            for (size_t i = 0; i < indexes.size(); i++) {\n                uint64_t index = indexes[i] - (i == 0 ? 0 : (indexes[i - 1] + 1));\n                READWRITE(COMPACTSIZE(index));\n            }\n        }\n    }\n};\n\nclass BlockTransactions {\npublic:\n    // A BlockTransactions message\n    uint256 blockhash;\n    std::vector<CTransactionRef> txn;\n\n    BlockTransactions() {}\n    BlockTransactions(const BlockTransactionsRequest& req) :\n        blockhash(req.blockhash), txn(req.indexes.size()) {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(blockhash);\n        uint64_t txn_size = (uint64_t)txn.size();\n        READWRITE(COMPACTSIZE(txn_size));\n        if (ser_action.ForRead()) {\n            size_t i = 0;\n            while (txn.size() < txn_size) {\n                txn.resize(std::min((uint64_t)(1000 + txn.size()), txn_size));\n                for (; i < txn.size(); i++)\n                    READWRITE(REF(TransactionCompressor(txn[i])));\n            }\n        } else {\n            for (size_t i = 0; i < txn.size(); i++)\n                READWRITE(REF(TransactionCompressor(txn[i])));\n        }\n    }\n};\n\n// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock\nstruct PrefilledTransaction {\n    // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,\n    // as a proper transaction-in-block-index in PartiallyDownloadedBlock\n    uint16_t index;\n    CTransactionRef tx;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        uint64_t idx = index;\n        READWRITE(COMPACTSIZE(idx));\n        if (idx > std::numeric_limits<uint16_t>::max())\n            throw std::ios_base::failure(\"index overflowed 16-bits\");\n        index = idx;\n        READWRITE(REF(TransactionCompressor(tx)));\n    }\n};\n\ntypedef enum ReadStatus_t\n{\n    READ_STATUS_OK,\n    READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap\n    READ_STATUS_FAILED, // Failed to process object\n    READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a\n                                   // failure in CheckBlock.\n} ReadStatus;\n\nclass CBlockHeaderAndShortTxIDs {\nprivate:\n    mutable uint64_t shorttxidk0, shorttxidk1;\n    uint64_t nonce;\n\n    void FillShortTxIDSelector() const;\n\n    friend class PartiallyDownloadedBlock;\n\n    static const int SHORTTXIDS_LENGTH = 6;\nprotected:\n    std::vector<uint64_t> shorttxids;\n    std::vector<PrefilledTransaction> prefilledtxn;\n\npublic:\n    CBlockHeader header;\n\n    // Dummy for deserialization\n    CBlockHeaderAndShortTxIDs() {}\n\n    CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID);\n\n    uint64_t GetShortID(const uint256& txhash) const;\n\n    size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(header);\n        READWRITE(nonce);\n\n        uint64_t shorttxids_size = (uint64_t)shorttxids.size();\n        READWRITE(COMPACTSIZE(shorttxids_size));\n        if (ser_action.ForRead()) {\n            size_t i = 0;\n            while (shorttxids.size() < shorttxids_size) {\n                shorttxids.resize(std::min((uint64_t)(1000 + shorttxids.size()), shorttxids_size));\n                for (; i < shorttxids.size(); i++) {\n                    uint32_t lsb = 0; uint16_t msb = 0;\n                    READWRITE(lsb);\n                    READWRITE(msb);\n                    shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb);\n                    static_assert(SHORTTXIDS_LENGTH == 6, \"shorttxids serialization assumes 6-byte shorttxids\");\n                }\n            }\n        } else {\n            for (size_t i = 0; i < shorttxids.size(); i++) {\n                uint32_t lsb = shorttxids[i] & 0xffffffff;\n                uint16_t msb = (shorttxids[i] >> 32) & 0xffff;\n                READWRITE(lsb);\n                READWRITE(msb);\n            }\n        }\n\n        READWRITECOMPACTSIZEVECTOR(prefilledtxn);\n\n        if (ser_action.ForRead())\n            FillShortTxIDSelector();\n    }\n};\n\nclass PartiallyDownloadedBlock {\nprotected:\n    std::vector<CTransactionRef> txn_available;\n    size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;\n    CTxMemPool* pool;\npublic:\n    CBlockHeader header;\n    PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}\n\n    // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form\n    ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);\n    bool IsTxAvailable(size_t index) const;\n    ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);\n};\n\n#endif\n"
  },
  {
    "path": "src/blockfilter.cpp",
    "content": "// Copyright (c) 2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <sstream>\n\n#include <blockfilter.h>\n#include <hash.h>\n#include <primitives/transaction.h>\n#include <script/script.h>\n#include <streams.h>\n#include <validation/validation.h>\n#include \"blockstore.h\"\n#include \"checkpoints.h\"\n\n#include <limits>\n#include \"clientversion.h\"\n\n/// SerType used to serialize parameters in GCS filter encoding.\nstatic constexpr int GCS_SER_TYPE = SER_NETWORK;\n\n/// Protocol version used to serialize parameters in GCS filter encoding.\nstatic constexpr int GCS_SER_VERSION = 0;\n\nstatic const std::map<BlockFilterType, std::string> g_filter_types = {\n    {BASIC, \"basic\"},\n};\n\ntemplate <typename OStream>\nstatic void GolombRiceEncode(BitStreamWriter<OStream>& bitwriter, uint8_t P, uint64_t x)\n{\n    // Write quotient as unary-encoded: q 1's followed by one 0.\n    uint64_t q = x >> P;\n    while (q > 0) {\n        int nbits = q <= 64 ? static_cast<int>(q) : 64;\n        bitwriter.Write(~0ULL, nbits);\n        q -= nbits;\n    }\n    bitwriter.Write(0, 1);\n\n    // Write the remainder in P bits. Since the remainder is just the bottom\n    // P bits of x, there is no need to mask first.\n    bitwriter.Write(x, P);\n}\n\ntemplate <typename IStream>\nstatic uint64_t GolombRiceDecode(BitStreamReader<IStream>& bitreader, uint8_t P)\n{\n    // Read unary-encoded quotient: q 1's followed by one 0.\n    uint64_t q = 0;\n    while (bitreader.Read(1) == 1) {\n        ++q;\n    }\n\n    uint64_t r = bitreader.Read(P);\n\n    return (q << P) + r;\n}\n\n// Map a value x that is uniformly distributed in the range [0, 2^64) to a\n// value uniformly distributed in [0, n) by returning the upper 64 bits of\n// x * n.\n//\n// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/\nstatic uint64_t MapIntoRange(uint64_t x, uint64_t n)\n{\n#ifdef __SIZEOF_INT128__\n    return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64;\n#else\n    // To perform the calculation on 64-bit numbers without losing the\n    // result to overflow, split the numbers into the most significant and\n    // least significant 32 bits and perform multiplication piece-wise.\n    //\n    // See: https://stackoverflow.com/a/26855440\n    uint64_t x_hi = x >> 32;\n    uint64_t x_lo = x & 0xFFFFFFFF;\n    uint64_t n_hi = n >> 32;\n    uint64_t n_lo = n & 0xFFFFFFFF;\n\n    uint64_t ac = x_hi * n_hi;\n    uint64_t ad = x_hi * n_lo;\n    uint64_t bc = x_lo * n_hi;\n    uint64_t bd = x_lo * n_lo;\n\n    uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);\n    uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);\n    return upper64;\n#endif\n}\n\nuint64_t GCSFilter::HashToRange(const Element& element) const\n{\n    uint64_t hash = CSipHasher(m_params.m_siphash_k0, m_params.m_siphash_k1)\n        .Write(element.data(), element.size())\n        .Finalize();\n    return MapIntoRange(hash, m_F);\n}\n\nstd::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const\n{\n    std::vector<uint64_t> hashed_elements;\n    hashed_elements.reserve(elements.size());\n    for (const Element& element : elements) {\n        hashed_elements.push_back(HashToRange(element));\n    }\n    std::sort(hashed_elements.begin(), hashed_elements.end());\n    return hashed_elements;\n}\n\nGCSFilter::GCSFilter(const Params& params)\n    : m_params(params), m_N(0), m_F(0), m_encoded{0}\n{}\n\nGCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)\n    : m_params(params), m_encoded(std::move(encoded_filter))\n{\n    VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);\n\n    uint64_t N = ReadCompactSize(stream);\n    m_N = static_cast<uint32_t>(N);\n    if (m_N != N) {\n        throw std::ios_base::failure(\"N must be <2^32\");\n    }\n    m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);\n\n    // Verify that the encoded filter contains exactly N elements. If it has too much or too little\n    // data, a std::ios_base::failure exception will be raised.\n    BitStreamReader<VectorReader> bitreader(stream);\n    for (uint64_t i = 0; i < m_N; ++i) {\n        GolombRiceDecode(bitreader, m_params.m_P);\n    }\n    if (!stream.empty()) {\n        throw std::ios_base::failure(\"encoded_filter contains excess data\");\n    }\n}\n\nGCSFilter::GCSFilter(const Params& params, const ElementSet& elements)\n    : m_params(params)\n{\n    size_t N = elements.size();\n    m_N = static_cast<uint32_t>(N);\n    if (m_N != N) {\n        throw std::invalid_argument(\"N must be <2^32\");\n    }\n    m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);\n\n    CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);\n\n    WriteCompactSize(stream, m_N);\n\n    if (elements.empty()) {\n        return;\n    }\n\n    BitStreamWriter<CVectorWriter> bitwriter(stream);\n\n    uint64_t last_value = 0;\n    for (uint64_t value : BuildHashedSet(elements)) {\n        uint64_t delta = value - last_value;\n        GolombRiceEncode(bitwriter, m_params.m_P, delta);\n        last_value = value;\n    }\n\n    bitwriter.Flush();\n}\n\nbool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const\n{\n    VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);\n\n    // Seek forward by size of N\n    uint64_t N = ReadCompactSize(stream);\n    assert(N == m_N);\n\n    BitStreamReader<VectorReader> bitreader(stream);\n\n    uint64_t value = 0;\n    size_t hashes_index = 0;\n    for (uint32_t i = 0; i < m_N; ++i) {\n        uint64_t delta = GolombRiceDecode(bitreader, m_params.m_P);\n        value += delta;\n\n        while (true) {\n            if (hashes_index == size) {\n                return false;\n            } else if (element_hashes[hashes_index] == value) {\n                return true;\n            } else if (element_hashes[hashes_index] > value) {\n                break;\n            }\n\n            hashes_index++;\n        }\n    }\n\n    return false;\n}\n\nbool GCSFilter::Match(const Element& element) const\n{\n    uint64_t query = HashToRange(element);\n    return MatchInternal(&query, 1);\n}\n\nbool GCSFilter::MatchAny(const ElementSet& elements) const\n{\n    const std::vector<uint64_t> queries = BuildHashedSet(elements);\n    return MatchInternal(queries.data(), queries.size());\n}\n\nunsigned int GCSFilter::NumElements() const\n{\n    return m_N;\n}\n\nconst std::string& BlockFilterTypeName(BlockFilterType filter_type)\n{\n    static std::string unknown_retval = \"\";\n    auto it = g_filter_types.find(filter_type);\n    return it != g_filter_types.end() ? it->second : unknown_retval;\n}\n\nbool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type) {\n    for (auto entry : g_filter_types) {\n        if (entry.second == name) {\n            filter_type = entry.first;\n            return true;\n        }\n    }\n    return false;\n}\n\nconst std::vector<BlockFilterType>& AllBlockFilterTypes()\n{\n    static std::vector<BlockFilterType> retval{\n        BlockFilterType::BASIC,\n    };\n    return retval;\n}\n\nstd::string ListBlockFilterTypes()\n{\n    std::stringstream ret;\n    bool first = true;\n    for (auto filter_type : AllBlockFilterTypes()) {\n        if (!first) ret << \", \";\n        ret << BlockFilterTypeName(filter_type);\n        first = false;\n    }\n    return ret.str();\n}\n\nstatic void BasicFilterElements(GCSFilter::ElementSet& elements, const CTxOut& txout)\n{\n    switch (txout.GetType())\n    {\n        case CTxOutType::ScriptLegacyOutput:\n        {\n            const CScript& script = txout.output.scriptPubKey;\n            if (script.empty() || script[0] == OP_RETURN)\n                break;\n            CKeyID hash;\n            if (script.IsPayToPubkeyHash(hash))\n            {\n                elements.emplace(hash.begin(), hash.end());\n            }\n            break;\n        }\n        case CTxOutType::PoW2WitnessOutput:\n        {\n            const auto& wit = txout.output.witnessDetails;\n            elements.emplace(wit.spendingKeyID.begin(), wit.spendingKeyID.end());\n            elements.emplace(wit.witnessKeyID.begin(), wit.witnessKeyID.end());\n        }\n        case CTxOutType::StandardKeyHashOutput:\n        {\n            const auto& keyID = txout.output.standardKeyHash.keyID;\n            elements.emplace(keyID.begin(), keyID.end());\n        }\n    }\n}\n\nstatic void BasicFilterElements(GCSFilter::ElementSet& elements, const CBlock& block, const CBlockUndo& block_undo)\n{\n    for (const CTransactionRef& tx : block.vtx)\n    {\n        for (const CTxOut& txout : tx->vout)\n        {\n            BasicFilterElements(elements, txout);\n        }\n    }\n    for (const CTxUndo& tx_undo : block_undo.vtxundo)\n    {\n        for (const Coin& prevout : tx_undo.vprevout)\n        {\n            BasicFilterElements(elements, prevout.out);\n        }\n    }\n}\n\nstatic GCSFilter::ElementSet BasicFilterElements(const CBlock& block, const CBlockUndo& block_undo)\n{\n    GCSFilter::ElementSet elements;\n    BasicFilterElements(elements, block, block_undo);\n    return elements;\n}\n\nBlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash, std::vector<unsigned char> filter)\n    : m_filter_type(filter_type), m_block_hash(block_hash)\n{\n    GCSFilter::Params params;\n    if (!BuildParams(params)) {\n        throw std::invalid_argument(\"unknown filter_type\");\n    }\n    m_filter = GCSFilter(params, std::move(filter));\n}\n\nBlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)\n    : m_filter_type(filter_type), m_block_hash(block.GetHashPoW2())\n{\n    GCSFilter::Params params;\n    if (!BuildParams(params)) {\n        throw std::invalid_argument(\"unknown filter_type\");\n    }\n    m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));\n}\n\nbool BlockFilter::BuildParams(GCSFilter::Params& params) const\n{\n    switch (m_filter_type) {\n    case BlockFilterType::BASIC:\n        params.m_siphash_k0 = m_block_hash.GetUint64(0);\n        params.m_siphash_k1 = m_block_hash.GetUint64(1);\n        params.m_P = BASIC_FILTER_P;\n        params.m_M = BASIC_FILTER_M;\n        return true;\n    }\n\n    return false;\n}\n\nuint256 BlockFilter::GetHash() const\n{\n    const std::vector<unsigned char>& data = GetEncodedFilter();\n\n    uint256 result;\n    CHash256().Write(data.data(), data.size()).Finalize(result.begin());\n    return result;\n}\n\nuint256 BlockFilter::ComputeHeader(const uint256& prev_header) const\n{\n    const uint256& filter_hash = GetHash();\n\n    uint256 result;\n    CHash256()\n        .Write(filter_hash.begin(), filter_hash.size())\n        .Write(prev_header.begin(), prev_header.size())\n        .Finalize(result.begin());\n    return result;\n}\n\nRangedCPBlockFilter::RangedCPBlockFilter(const CBlockIndex* startRange, const CBlockIndex* endRange)\n: BlockFilter()\n{\n    GCSFilter::Params params;\n    if (!BuildParams(params))\n    {\n        throw std::invalid_argument(\"unknown filter_type\");\n    }\n    GCSFilter::ElementSet elements;\n    const CBlockIndex* pIndex = endRange;\n    while (true)\n    {\n        CBlock block;\n        if (!ReadBlockFromDisk(block, pIndex, Params()))\n        {\n            throw std::invalid_argument(\"BlockFilter: error reading block from disk\");\n        }\n        CBlockUndo blockUndo;\n        if (pIndex->pprev)\n        {\n            CDiskBlockPos pos = pIndex->GetUndoPos();\n            if (pos.IsNull())\n            {\n                throw std::invalid_argument(\"BlockFilter: error reading undo pos from disk\");\n            }\n\n            if (!blockStore.UndoReadFromDisk(blockUndo, pos, pIndex->pprev->GetBlockHashPoW2()))\n            {\n                throw std::invalid_argument(\"BlockFilter: error reading undo data from disk\");\n            }\n        }\n        BasicFilterElements(elements, block, blockUndo);\n        if (pIndex == startRange || pIndex->pprev == nullptr)\n            break;\n        pIndex=pIndex->pprev;\n    }\n    m_filter = GCSFilter(params, elements);\n}\n\nRangedCPBlockFilter::RangedCPBlockFilter(std::vector<unsigned char> filter)\n{\n    GCSFilter::Params params;\n    if (!BuildParams(params)) {\n        throw std::invalid_argument(\"unknown filter_type\");\n    }\n    m_filter = GCSFilter(params, std::move(filter));\n}\n\nbool RangedCPBlockFilter::BuildParams(GCSFilter::Params& params) const\n{\n    params.m_siphash_k0 = 0;\n    params.m_siphash_k1 = 0;\n    // Filters have a false positive rate of '1/M' while M needs to be roughly '2^P' for optimal space usage, with some possible variance.\n    // Ultimately both P and M, must be altered\n    // For our purposes a \"relatively high\" false positive rate (e.g. about 1%) is tolerable\n    // Some non-comprehensive testing of various sizes leaves us with the following rough results to work with\n    // Tests done using a test vector of 20 random addresses per run and averaging over several runs\n    //gaps: 1000 blocks\n    //P=8  M=256    2965052 bytes      false positive rate = (69/908) ranges\n    //P=10 M=1034   3585205 bytes      false positive rate = (15/908) ranges\n    //P=10 M=2048   3878673 bytes      false positive rate = (9/908) ranges\n    //P=6 M=4096    21772036 bytes     false positive rate = (7/908) ranges\n    //P=12 M=4096   4199978 bytes      false positive rate = (4/908) ranges\n    //gaps: 100 blocks\n    //P=12 M=4096   6280492 bytes\n    //P=12 M=5700   6449605 bytes\n    //We have settled on the current settings for now (using gaps of 100 blocks), however these can easily be changed for future releases\n    //P=12 M=4096   FP = (20 / 4603) = 0,0043%\n    //When/if we decide on more appropriate settings.\n    params.m_P = 12;\n    params.m_M = 4096;\n    return true;\n}\n\n\n//fixme: (POST-PHASE4) We can potentially further improve this by indexing only the actual key hashes and not the entire script\n//This should be slightly smaller and faster\nvoid getBlockFilterBirthAndRanges(uint64_t nHardBirthDate, uint64_t& nSoftBirthDate, const GCSFilter::ElementSet& walletAddresses, std::vector<std::tuple<uint64_t, uint64_t>>& blockFilterRanges)\n{\n    std::string dataFilePath = GetArg(\"-spvstaticfilterfile\", \"\");\n    if (dataFilePath.empty())\n    {\n        LogPrintf(\"Running without a static filtercp file\\n\");\n        nSoftBirthDate = nHardBirthDate;\n        return;\n    }\n    else\n    {\n        \n        FILE *file = fsbridge::fopen(dataFilePath, \"rb\");\n        CAutoFile dataFile(file, SER_DISK, CLIENT_VERSION);            \n        if (dataFile.IsNull() || !dataFile.peek())\n        {\n            LogPrintf(\"Failed to read staticfiltercp file [%s]\\n\", dataFilePath.c_str());\n            nSoftBirthDate = nHardBirthDate;\n            return;\n        }\n        uint64_t nStaticFilterOffset = GetArg(\"-spvstaticfilterfileoffset\", (uint64_t)0);\n        uint64_t nStaticFilterLength = GetArg(\"-spvstaticfilterfilelength\", (uint64_t)0);\n        \n        LogPrintf(\"Loading staticfiltercp file [%s] [%d] [%d]\\n\", dataFilePath, nStaticFilterOffset, nStaticFilterLength);\n        if (nStaticFilterLength == 0)\n        {\n            nStaticFilterLength = boost::filesystem::file_size(dataFilePath);\n        }\n\n        uint64_t nStartIndex = Params().IsTestnet() ? 0 : 250000;//Earliest possible recovery phrase (before this we didn't use phrases)\n        uint64_t nInterval1 = 500;\n        uint64_t nInterval2 = 100;\n        uint64_t nCrossOver = Params().IsTestnet() ? 200000 : 500000;\n        uint32_t nRanges=0;\n        dataFile.seekg(nStaticFilterOffset);\n        while (((uint64_t)dataFile.tellg() - nStaticFilterOffset < nStaticFilterLength) && (dataFile.peek()))\n        {\n            int nInterval = nInterval1;\n            if (nStartIndex >= nCrossOver)\n                nInterval = nInterval2;\n            size_t nDataSize = ReadCompactSize(dataFile);\n            std::vector<unsigned char> vchData;\n            vchData.resize(nDataSize);\n            dataFile.read(AsWritableBytes(Span{vchData.data(), nDataSize}));\n            RangedCPBlockFilter rangeFilter(vchData);\n            ++nRanges;\n            if (rangeFilter.GetFilter().MatchAny(walletAddresses))\n            {\n                // Move the birth date forwards as far as possible from the 'hard' birthdate while still including all possible matches\n                if (nStartIndex > nHardBirthDate && nStartIndex < nSoftBirthDate)\n                {\n                    nSoftBirthDate = nStartIndex;\n                }\n                blockFilterRanges.push_back(std::tuple(nStartIndex, nStartIndex+nInterval));\n            }\n            nStartIndex+=nInterval;\n        }\n        LogPrintf(\"Hard birth block=%d; Soft birth block=%d; Last checkpoint=%d; Addresses=%d; Ranges=%d/%d\\n\", nHardBirthDate, nSoftBirthDate, Checkpoints::LastCheckPointHeight(), walletAddresses.size(), blockFilterRanges.size(), nRanges);\n    }\n}\n"
  },
  {
    "path": "src/blockfilter.h",
    "content": "// Copyright (c) 2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLOCKFILTER_H\n#define BLOCKFILTER_H\n\n#include <stdint.h>\n#include <string>\n#include <unordered_set>\n#include <vector>\n\n#include <primitives/block.h>\n#include <serialize.h>\n#include <uint256.h>\n#include <undo.h>\n#include \"chain.h\"\n#include <util/bytevectorhash.h>\n\n/**\n * This implements a Golomb-coded set as defined in BIP 158. It is a\n * compact, probabilistic data structure for testing set membership.\n */\nclass GCSFilter\n{\npublic:\n    typedef std::vector<unsigned char> Element;\n    typedef std::unordered_set<Element, ByteVectorHash> ElementSet;\n\n    struct Params\n    {\n        uint64_t m_siphash_k0;\n        uint64_t m_siphash_k1;\n        uint8_t m_P;  //!< Golomb-Rice coding parameter\n        uint32_t m_M;  //!< Inverse false positive rate\n\n        Params(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 1)\n            : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M)\n        {}\n    };\n\nprivate:\n    Params m_params;\n    uint32_t m_N;  //!< Number of elements in the filter\n    uint64_t m_F;  //!< Range of element hashes, F = N * M\n    std::vector<unsigned char> m_encoded;\n\n    /** Hash a data element to an integer in the range [0, N * M). */\n    uint64_t HashToRange(const Element& element) const;\n\n    std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const;\n\n    /** Helper method used to implement Match and MatchAny */\n    bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const;\n\npublic:\n\n    /** Constructs an empty filter. */\n    explicit GCSFilter(const Params& params = Params());\n\n    /** Reconstructs an already-created filter from an encoding. */\n    GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter);\n\n    /** Builds a new filter from the params and set of elements. */\n    GCSFilter(const Params& params, const ElementSet& elements);\n\n    uint32_t GetN() const { return m_N; }\n    const Params& GetParams() const { return m_params; }\n    const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }\n\n    /**\n     * Checks if the element may be in the set. False positives are possible\n     * with probability 1/M.\n     */\n    bool Match(const Element& element) const;\n\n    /**\n     * Checks if any of the given elements may be in the set. False positives\n     * are possible with probability 1/M per element checked. This is more\n     * efficient that checking Match on multiple elements separately.\n     */\n    bool MatchAny(const ElementSet& elements) const;\n    unsigned int NumElements() const;\n};\n\nconstexpr uint8_t BASIC_FILTER_P = 19;\nconstexpr uint32_t BASIC_FILTER_M = 784931;\n\nenum BlockFilterType : uint8_t\n{\n    BASIC = 0,\n};\n\n/** Get the human-readable name for a filter type. Returns empty string for unknown types. */\nconst std::string& BlockFilterTypeName(BlockFilterType filter_type);\n\n/** Find a filter type by its human-readable name. */\nbool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type);\n\n/** Get a list of known filter types. */\nconst std::vector<BlockFilterType>& AllBlockFilterTypes();\n\n/** Get a comma-separated list of known filter type names. */\nstd::string ListBlockFilterTypes();\n\n/**\n * Complete block filter struct as defined in BIP 157. Serialization matches\n * payload of \"cfilter\" messages.\n */\nclass BlockFilter\n{\nprotected:\n    BlockFilterType m_filter_type;\n    uint256 m_block_hash;\n    GCSFilter m_filter;\n\n    virtual bool BuildParams(GCSFilter::Params& params) const;\n\npublic:\n\n    BlockFilter() = default;\n\n    //! Reconstruct a BlockFilter from parts.\n    BlockFilter(BlockFilterType filter_type, const uint256& block_hash,\n                std::vector<unsigned char> filter);\n\n    //! Construct a new BlockFilter of the specified type from a block.\n    BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);\n\n    BlockFilterType GetFilterType() const { return m_filter_type; }\n    const uint256& GetBlockHash() const { return m_block_hash; }\n    const GCSFilter& GetFilter() const { return m_filter; }\n\n    const std::vector<unsigned char>& GetEncodedFilter() const\n    {\n        return m_filter.GetEncoded();\n    }\n\n    //! Compute the filter hash.\n    uint256 GetHash() const;\n\n    //! Compute the filter header given the previous one.\n    uint256 ComputeHeader(const uint256& prev_header) const;\n\n    template <typename Stream>\n    void Serialize(Stream& s) const {\n        s << m_block_hash\n          << static_cast<uint8_t>(m_filter_type)\n          << m_filter.GetEncoded();\n    }\n\n    template <typename Stream>\n    void Unserialize(Stream& s) {\n        std::vector<unsigned char> encoded_filter;\n        uint8_t filter_type;\n\n        s >> m_block_hash\n          >> filter_type\n          >> encoded_filter;\n\n        m_filter_type = static_cast<BlockFilterType>(filter_type);\n\n        GCSFilter::Params params;\n        if (!BuildParams(params)) {\n            throw std::ios_base::failure(\"unknown filter_type\");\n        }\n        m_filter = GCSFilter(params, std::move(encoded_filter));\n    }\n};\n\n\n//! Special sub class used only for filtercp used by SPV sync, not for network messages or anything consensus related.\nclass RangedCPBlockFilter : public BlockFilter\n{\npublic:\n    //! Construct a new RangedCPBlockFilter of the specified type from a range.\n    //! Filter contains startRange->endRange - inclusive of start range, exclusive of end range\n    RangedCPBlockFilter(const CBlockIndex* startRange, const CBlockIndex* endRange);\n\n    //! Reconstruct from parts.\n    RangedCPBlockFilter(std::vector<unsigned char> filter);\nprivate:\n    virtual bool BuildParams(GCSFilter::Params& params) const;\n};\n\nvoid getBlockFilterBirthAndRanges(uint64_t nHardBirthDate, uint64_t& nSoftBirthDate, const GCSFilter::ElementSet& walletAddresses, std::vector<std::tuple<uint64_t, uint64_t>>& blockFilterRanges);\n\n#endif\n"
  },
  {
    "path": "src/blockstore.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"blockstore.h\"\n#include \"checkpoints.h\"\n#include \"streams.h\"\n#include \"clientversion.h\"\n#include \"validation/validation.h\" //For cs_main\n#include \"util.h\" // For DO_BENCHMARK\n\nCBlockStore blockStore;\n\nfs::path CBlockStore::GetBlockPosFilename(const CDiskBlockPos &pos, BlockFileType fileType)\n{\n    std::string basename = mainPrefix + (fileType == BlockFileType::block ? \"blk\" : \"rev\");\n    return GetDataDir() / \"blocks\" / strprintf(\"%s%05u.dat\", basename, pos.nFile);\n}\n\nbool CBlockStore::BlockFileExists(const CDiskBlockPos &pos)\n{\n    return fs::exists(GetBlockPosFilename(pos, BlockFileType::block));\n}\n\nFILE* CBlockStore::GetDiskFile(const CDiskBlockPos &pos, BlockFileType fileType, bool fNoCreate)\n{\n    if (pos.IsNull())\n        return NULL;\n\n    if (int(vBlockfiles.size()) <= pos.nFile) {\n        vBlockfiles.resize(pos.nFile + 1);\n    }\n\n    FILE*& file = fileType == BlockFileType::block ? vBlockfiles[pos.nFile].blockfile\n                                                    : vBlockfiles[pos.nFile].undofile;\n    if (!file) {\n        fs::path path = GetBlockPosFilename(pos, fileType);\n        fs::create_directories(path.parent_path());\n        file = fsbridge::fopen(path, \"rb+\");\n        if (!file && !fNoCreate)\n            file = fsbridge::fopen(path, \"wb+\");\n        if (!file) {\n            LogPrintf(\"Unable to open file %s\\n\", path.string());\n            return NULL;\n        }\n    }\n\n    // always fseek, when file will stay open we may switch writing and reading\n    // which has to be interleaved with positioning function\n    // also a previous call left the position not where we want it\n    if (fseek(file, pos.nPos, SEEK_SET)) {\n        LogPrintf(\"Unable to seek to position %u of %s\\n\", pos.nPos, GetBlockPosFilename(pos, fileType).string());\n        fclose(file);\n        file = nullptr;\n        return NULL;\n    }\n\n    return file;\n}\n\nFILE* CBlockStore::GetBlockFile(const CDiskBlockPos &pos, bool fNoCreate) {\n    return GetDiskFile(pos, BlockFileType::block, fNoCreate);\n}\n\nFILE* CBlockStore::GetUndoFile(const CDiskBlockPos &pos, bool fNoCreate) {\n    return GetDiskFile(pos, BlockFileType::undo, fNoCreate);\n}\n\nvoid CBlockStore::CloseBlockFiles()\n{\n    vBlockfiles.clear();\n    LogPrintStr(\"Block and undo files closed\\n\");\n}\n\nbool CBlockStore::WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)\n{\n    DO_BENCHMARK(\"CBlockStore: WriteBlockToDisk\", BCLog::BENCH|BCLog::IO);\n\n    AssertLockHeld(cs_main);\n\n    // Open history file to append\n    CFile fileout(GetBlockFile(pos), SER_DISK, CLIENT_VERSION);\n    if (fileout.IsNull())\n        return error(\"WriteBlockToDisk: OpenBlockFile failed\");\n\n    // Write index header\n    unsigned int nSize = ::GetSerializeSize(fileout, block);\n\n    fileout << FLATDATA(messageStart) << nSize;\n\n    // Write block\n    long fileOutPos = ftell(fileout.Get());\n    if (fileOutPos < 0)\n        return error(\"WriteBlockToDisk: ftell failed\");\n    pos.nPos = (unsigned int)fileOutPos;\n    fileout << block;\n\n    return true;\n}\n\nbool CBlockStore::ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const CChainParams& params, const CBlockIndex* index, int extraSerialisationArgs)\n{\n    DO_BENCHMARK(\"CBlockStore: ReadBlockFromDisk\", BCLog::BENCH|BCLog::IO);\n\n    AssertLockHeld(cs_main);\n\n    block.SetNull();\n\n    // Open history file to read\n    CFile filein(GetBlockFile(pos, true), SER_DISK, CLIENT_VERSION|extraSerialisationArgs);\n    if (filein.IsNull())\n        return error(\"ReadBlockFromDisk: OpenBlockFile failed for %s\", pos.ToString());\n\n    // Read block\n    try {\n        filein >> block;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Deserialize or I/O error - %s at %s\", __func__, e.what(), pos.ToString());\n    }\n\n    if (index && block.GetHashPoW2() != index->GetBlockHashPoW2())\n        return error(\"ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s\",\n                     index->ToString(), pos.ToString());\n\n    bool fPOW_ok = false;\n    if (index && (index->nStatus & BLOCK_VALID_HEADER) != 0 && index->nHeight < Checkpoints::LastCheckPointHeight())\n    {\n        // block header data equals that in our index which is valid and below checkpoint height\n        // the expensive PoW check does not need be done\n        fPOW_ok = true;\n    }\n    else\n    {\n        uint256 hashLegacy = block.GetHashLegacy();\n        if (checkedPoWCache.contains(hashLegacy))\n        {\n            fPOW_ok = checkedPoWCache.get(hashLegacy);\n        }\n        else\n        {\n            //fPOW_ok = CheckProofOfWork(&block, params.GetConsensus());\n            fPOW_ok = true;\n        }\n    }\n\n    if (fPOW_ok)\n        block.fPOWChecked = true;\n    else\n        return error(\"ReadBlockFromDisk: Errors in block header at %s\", pos.ToString());\n\n    return true;\n}\n\nbool CBlockStore::UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)\n{\n    DO_BENCHMARK(\"CBlockStore: UndoWriteToDisk\", BCLog::BENCH|BCLog::IO);\n\n    // Open history file to append\n    CFile fileout(GetUndoFile(pos), SER_DISK, CLIENT_VERSION);\n    if (fileout.IsNull())\n        return error(\"%s: OpenUndoFile failed\", __func__);\n\n    // Write index header\n    unsigned int nSize = ::GetSerializeSize(fileout, blockundo);\n    fileout << FLATDATA(messageStart) << nSize;\n\n    // Write undo data\n    long fileOutPos = ftell(fileout.Get());\n    if (fileOutPos < 0)\n        return error(\"%s: ftell failed\", __func__);\n    pos.nPos = (unsigned int)fileOutPos;\n    fileout << blockundo;\n\n    // calculate & write checksum\n    CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);\n    hasher << hashBlock;\n    hasher << blockundo;\n    fileout << hasher.GetHash();\n\n    return true;\n}\n\nbool CBlockStore::UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)\n{\n    DO_BENCHMARK(\"CBlockStore: UndoReadFromDisk\", BCLog::BENCH|BCLog::IO);\n\n    // Open history file to read\n    CFile filein(GetUndoFile(pos, true), SER_DISK, CLIENT_VERSION);\n    if (filein.IsNull())\n        return error(\"%s: OpenUndoFile failed\", __func__);\n\n    // Read block\n    uint256 hashChecksum;\n    CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data\n    try {\n        verifier << hashBlock;\n        verifier >> blockundo;\n        filein >> hashChecksum;\n    }\n    catch (const std::exception& e) {\n        return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n    }\n\n    // Verify checksum\n    if (hashChecksum != verifier.GetHash())\n        return error(\"%s: Checksum mismatch\", __func__);\n\n    return true;\n}\n\nvoid CBlockStore::UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)\n{\n    for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {\n        int nFile = *it;\n        if (nFile < 0 || nFile >= int(vBlockfiles.size()))\n            break;\n        BlockFilePair& p = vBlockfiles[nFile];\n        if (p.blockfile) {\n            fclose(p.blockfile);\n            p.blockfile = nullptr;\n        }\n        if (p.undofile) {\n            fclose(p.undofile);\n            p.undofile = nullptr;\n        }\n        CDiskBlockPos pos(nFile, 0);\n        fs::remove(GetBlockPosFilename(pos, BlockFileType::block));\n        fs::remove(GetBlockPosFilename(pos, BlockFileType::undo));\n        LogPrintf(\"Prune: %s deleted blk/rev (%05u)\\n\", __func__, *it);\n    }\n}\n\nbool CBlockStore::Rename(const std::string& newPrefix)\n{\n    CloseBlockFiles();\n\n    // Move all the block files into backup files\n    int nFile = 0;\n\n    while (nFile < 1000)\n    {\n        CDiskBlockPos pos(nFile, 0);\n        if (fs::exists(GetBlockPosFilename(pos, BlockFileType::block)))\n        {\n            fs::rename(GetBlockPosFilename(pos, BlockFileType::block), GetBlockPosNewFilename(pos, BlockFileType::block, newPrefix));\n        }\n        if (fs::exists(GetBlockPosFilename(pos, BlockFileType::undo)))\n        {\n            fs::rename(GetBlockPosFilename(pos, BlockFileType::undo), GetBlockPosNewFilename(pos, BlockFileType::undo, newPrefix));\n        }\n        ++nFile;\n    }\n\n    mainPrefix = newPrefix;\n\n    return true;\n}\n\nbool CBlockStore::Delete()\n{\n    CloseBlockFiles();\n\n    // Remove the old backup block files as upgrade is done.\n    int nFile = 0;\n    while (nFile < 1000)\n    {\n        CDiskBlockPos pos(nFile, 0);\n        if (fs::exists(GetBlockPosFilename(pos, BlockFileType::block)))\n        {\n            if (!fs::remove(GetBlockPosFilename(pos, BlockFileType::block)))\n                return error(\"UpgradeBlockIndex: Could not remove old block file after upgrade [%s]\", GetBlockPosFilename(pos, BlockFileType::block));\n        }\n        if (fs::exists(GetBlockPosFilename(pos, BlockFileType::undo)))\n        {\n            if (!fs::remove(GetBlockPosFilename(pos, BlockFileType::undo)))\n                return error(\"UpgradeBlockIndex: Could not remove old block file after upgrade [%s]\", GetBlockPosFilename(pos, BlockFileType::undo));\n        }\n        ++nFile;\n    }\n\n    return true;\n}\n\nfs::path CBlockStore::GetBlockPosNewFilename(const CDiskBlockPos &pos, BlockFileType fileType, const std::string& newPrefix)\n{\n    std::string basename = newPrefix + (fileType == BlockFileType::block ? \"blk\" : \"rev\");\n    return GetDataDir() / \"blocks\" / strprintf(\"%s%05u.dat\", basename, pos.nFile);\n}\n"
  },
  {
    "path": "src/blockstore.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLOCKSTORE_H\n#define BLOCKSTORE_H\n\n//fixme: (POST-PHASE5) methods to support conversion of 1.6 block storage to 2.0 can be reverted once not needed anymore\n// revert the changes in this commit for blockstore.h + .cpp back to 517362d123ce7c7e83de86a962ad099abbf199b0\n\n#include <stdio.h>\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"protocol.h\" // For CMessageHeader::MessageStartChars\n#include \"undo.h\"\n\nclass CBlockStore\n{\npublic:\n    CBlockStore() {}\n\n    bool BlockFileExists(const CDiskBlockPos &pos);\n\n    /** Open a block file (blk?????.dat), creating it if needed.\n        Ownership is NOT transferred, so do not close the file.\n    */\n    FILE* GetBlockFile(const CDiskBlockPos &pos, bool fNoCreate = false);\n\n    /** Open an undo file (rev?????.dat), creating it if needed.\n        Ownership is NOT transferred, so do not close the file.\n    */\n    FILE* GetUndoFile(const CDiskBlockPos &pos, bool fNoCreate = false);\n\n    /** Closes all open block and undo files */\n    void CloseBlockFiles();\n\n\n    bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);\n\n    /** Read block from disk and do basic verifiaction to guard against (disk) corruption.\n        If an index is given which is: BLOCK_VALID_HEADER validated, has height below last checkpoint then the\n        block SHA is checked against the index implying that the PoW will also be valid.\n        For all other cases the PoW will be actually computed and verified (note that this is a local\n        validation so not necessarily a stronger one as the above).\n    */\n    bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const CChainParams& params, const CBlockIndex* index = nullptr, int extraSerialisationArgs=0);\n\n    bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart);\n    bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock);\n\n    /**\n     *  Actually unlink the specified files\n     */\n    void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);\n\n    // block store format conversion support methods:\n\n    /** Close all open files rename with prefix and use those */\n    bool Rename(const std::string& prefix);\n\n    /** Delete all block and undo files */\n    bool Delete();\n\n\nprivate:\n    enum class BlockFileType { block, undo };\n    fs::path GetBlockPosFilename(const CDiskBlockPos &pos, BlockFileType fileType);\n    FILE* GetDiskFile(const CDiskBlockPos &pos, BlockFileType fileType, bool fNoCreate);\n\n    struct BlockFilePair {\n        FILE* blockfile = nullptr;\n        FILE* undofile = nullptr;\n        BlockFilePair() : blockfile(nullptr), undofile(nullptr) {}\n\n        BlockFilePair(BlockFilePair&& other) :\n            blockfile(other.blockfile),\n            undofile(other.undofile)\n        {\n            other.blockfile = nullptr;\n            other.undofile = nullptr;\n        }\n\n        ~BlockFilePair() {\n            if (blockfile)\n                fclose(blockfile);\n            if (undofile)\n                fclose(undofile);\n        }\n    };\n\n    std::vector<BlockFilePair> vBlockfiles;\n\n    // more block store format conversion support:\n    fs::path GetBlockPosNewFilename(const CDiskBlockPos &pos, BlockFileType fileType, const std::string& newPrefix);\n    std::string mainPrefix;\n};\n\nextern CBlockStore blockStore;\n\n#endif // BLOCKSTORE_H\n"
  },
  {
    "path": "src/bloom.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"bloom.h\"\n\n#include \"primitives/transaction.h\"\n#include \"hash.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"random.h\"\n#include \"streams.h\"\n\n#include <math.h>\n#include <stdlib.h>\n\n#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455\n#define LN2 0.6931471805599453094172321214581765680755001343602552\n\nCBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :\n    /**\n     * The ideal size for a bloom filter with a given number of elements and false positive rate is:\n     * - nElements * log(fp rate) / ln(2)^2\n     * We ignore filter parameters which will create a bloom filter larger than the protocol limits\n     */\n    vData(std::min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),\n    /**\n     * The ideal number of hash functions is filter size * ln(2) / number of elements\n     * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits\n     * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas\n     */\n    isFull(false),\n    isEmpty(true),\n    nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),\n    nTweak(nTweakIn),\n    nFlags(nFlagsIn)\n{\n}\n\n// Private constructor used by CRollingBloomFilter\nCBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn) :\n    vData((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)) / 8),\n    isFull(false),\n    isEmpty(true),\n    nHashFuncs((unsigned int)(vData.size() * 8 / nElements * LN2)),\n    nTweak(nTweakIn),\n    nFlags(BLOOM_UPDATE_NONE)\n{\n}\n\ninline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const\n{\n    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.\n    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);\n}\n\nvoid CBloomFilter::insert(const std::vector<unsigned char>& vKey)\n{\n    if (isFull)\n        return;\n    for (unsigned int i = 0; i < nHashFuncs; i++)\n    {\n        unsigned int nIndex = Hash(i, vKey);\n        // Sets bit nIndex of vData\n        vData[nIndex >> 3] |= (1 << (7 & nIndex));\n    }\n    isEmpty = false;\n}\n\n\n\nvoid CBloomFilter::insert(const uint256& hash)\n{\n    std::vector<unsigned char> data(hash.begin(), hash.end());\n    insert(data);\n}\n\nbool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const\n{\n    if (isFull)\n        return true;\n    if (isEmpty)\n        return false;\n    for (unsigned int i = 0; i < nHashFuncs; i++)\n    {\n        unsigned int nIndex = Hash(i, vKey);\n        // Checks bit nIndex of vData\n        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))\n            return false;\n    }\n    return true;\n}\n\nbool CBloomFilter::contains(const uint256& hash) const\n{\n    std::vector<unsigned char> data(hash.begin(), hash.end());\n    return contains(data);\n}\n\nvoid CBloomFilter::clear()\n{\n    vData.assign(vData.size(),0);\n    isFull = false;\n    isEmpty = true;\n}\n\nvoid CBloomFilter::reset(const unsigned int nNewTweak)\n{\n    clear();\n    nTweak = nNewTweak;\n}\n\nbool CBloomFilter::IsWithinSizeConstraints() const\n{\n    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;\n}\n\nvoid CBloomFilter::UpdateEmptyFull()\n{\n    bool full = true;\n    bool empty = true;\n    for (unsigned int i = 0; i < vData.size(); i++)\n    {\n        full &= vData[i] == 0xff;\n        empty &= vData[i] == 0;\n    }\n    isFull = full;\n    isEmpty = empty;\n}\n\nCRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)\n{\n    double logFpRate = log(fpRate);\n    /* The optimal number of hash functions is log(fpRate) / log(0.5), but\n     * restrict it to the range 1-50. */\n    nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));\n    /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */\n    nEntriesPerGeneration = (nElements + 1) / 2;\n    uint32_t nMaxElements = nEntriesPerGeneration * 3;\n    /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)\n     * =>          pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)\n     * =>          1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)\n     * =>          log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits\n     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))\n     * =>          nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))\n     */\n    uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));\n    data.clear();\n    /* For each data element we need to store 2 bits. If both bits are 0, the\n     * bit is treated as unset. If the bits are (01), (10), or (11), the bit is\n     * treated as set in generation 1, 2, or 3 respectively.\n     * These bits are stored in separate integers: position P corresponds to bit\n     * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */\n    data.resize(((nFilterBits + 63) / 64) << 1);\n    reset();\n}\n\n/* Similar to CBloomFilter::Hash */\nstatic inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {\n    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);\n}\n\nvoid CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)\n{\n    if (nEntriesThisGeneration == nEntriesPerGeneration) {\n        nEntriesThisGeneration = 0;\n        nGeneration++;\n        if (nGeneration == 4) {\n            nGeneration = 1;\n        }\n        uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);\n        uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);\n        /* Wipe old entries that used this generation number. */\n        for (uint32_t p = 0; p < data.size(); p += 2) {\n            uint64_t p1 = data[p], p2 = data[p + 1];\n            uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);\n            data[p] = p1 & mask;\n            data[p + 1] = p2 & mask;\n        }\n    }\n    nEntriesThisGeneration++;\n\n    for (int n = 0; n < nHashFuncs; n++) {\n        uint32_t h = RollingBloomHash(n, nTweak, vKey);\n        int bit = h & 0x3F;\n        uint32_t pos = (h >> 6) % data.size();\n        /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */\n        data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;\n        data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;\n    }\n}\n\nvoid CRollingBloomFilter::insert(const uint256& hash)\n{\n    std::vector<unsigned char> vData(hash.begin(), hash.end());\n    insert(vData);\n}\n\nbool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const\n{\n    for (int n = 0; n < nHashFuncs; n++) {\n        uint32_t h = RollingBloomHash(n, nTweak, vKey);\n        int bit = h & 0x3F;\n        uint32_t pos = (h >> 6) % data.size();\n        /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */\n        if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool CRollingBloomFilter::contains(const uint256& hash) const\n{\n    std::vector<unsigned char> vData(hash.begin(), hash.end());\n    return contains(vData);\n}\n\nvoid CRollingBloomFilter::reset()\n{\n    nTweak = GetRand(std::numeric_limits<unsigned int>::max());\n    nEntriesThisGeneration = 0;\n    nGeneration = 1;\n    for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {\n        *it = 0;\n    }\n}\n"
  },
  {
    "path": "src/bloom.h",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLOOM_H\n#define BLOOM_H\n\n#include \"serialize.h\"\n\n#include <vector>\n\nclass COutPoint;\nclass CTransaction;\nclass uint256;\n\n//! 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%\nstatic const unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes\nstatic const unsigned int MAX_HASH_FUNCS = 50;\n\n/**\n * First two bits of nFlags control how much IsRelevantAndUpdate actually updates\n * The remaining bits are reserved\n */\nenum bloomflags\n{\n    BLOOM_UPDATE_NONE = 0,\n    BLOOM_UPDATE_ALL = 1,\n    // Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script\n    BLOOM_UPDATE_P2PUBKEY_ONLY = 2,\n    BLOOM_UPDATE_MASK = 3,\n};\n\n/**\n * BloomFilter is a probabilistic filter which SPV clients provide\n * so that we can filter the transactions we send them.\n * \n * This allows for significantly more efficient transaction and block downloads.\n * \n * Because bloom filters are probabilistic, a SPV node can increase the false-\n * positive rate, making us send it transactions which aren't actually its,\n * allowing clients to trade more bandwidth for more privacy by obfuscating which\n * keys are controlled by them.\n */\nclass CBloomFilter\n{\nprivate:\n    std::vector<unsigned char> vData;\n    bool isFull;\n    bool isEmpty;\n    unsigned int nHashFuncs;\n    unsigned int nTweak;\n    unsigned char nFlags;\n\n    unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;\n\n    // Private constructor for CRollingBloomFilter, no restrictions on size\n    CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak);\n    friend class CRollingBloomFilter;\n\npublic:\n    /**\n     * Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements\n     * Note that if the given parameters will result in a filter outside the bounds of the protocol limits,\n     * the filter created will be as close to the given parameters as possible within the protocol limits.\n     * This will apply if nFPRate is very low or nElements is unreasonably high.\n     * nTweak is a constant which is added to the seed value passed to the hash function\n     * It should generally always be a random value (and is largely only exposed for unit testing)\n     * nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)\n     */\n    CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);\n    CBloomFilter() : isFull(true), isEmpty(false), nHashFuncs(0), nTweak(0), nFlags(0) {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITECOMPACTSIZEVECTOR(vData);\n        READWRITE(nHashFuncs);\n        READWRITE(nTweak);\n        READWRITE(nFlags);\n    }\n\n    void insert(const std::vector<unsigned char>& vKey);\n    void insert(const uint256& hash);\n\n    bool contains(const std::vector<unsigned char>& vKey) const;\n    bool contains(const uint256& hash) const;\n\n    void clear();\n    void reset(const unsigned int nNewTweak);\n\n    //! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS\n    //! (catch a filter which was just deserialized which was too big)\n    bool IsWithinSizeConstraints() const;\n\n    //! Checks for empty and full filters to avoid wasting cpu\n    void UpdateEmptyFull();\n};\n\n/**\n * RollingBloomFilter is a probabilistic \"keep track of most recently inserted\" set.\n * Construct it with the number of items to keep track of, and a false-positive\n * rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically\n * secure random value for you. Similarly rather than clear() the method\n * reset() is provided, which also changes nTweak to decrease the impact of\n * false-positives.\n *\n * contains(item) will always return true if item was one of the last N to 1.5*N\n * insert()'ed ... but may also return true for items that were not inserted.\n *\n * It needs around 1.8 bytes per element per factor 0.1 of false positive rate.\n * (More accurately: 3/(log(256)*log(2)) * log(1/fpRate) * nElements bytes)\n */\nclass CRollingBloomFilter\n{\npublic:\n    // A random bloom filter calls GetRand() at creation time.\n    // Don't create global CRollingBloomFilter objects, as they may be\n    // constructed before the randomizer is properly initialized.\n    CRollingBloomFilter(const unsigned int nElements, const double nFPRate);\n\n    void insert(const std::vector<unsigned char>& vKey);\n    void insert(const uint256& hash);\n    bool contains(const std::vector<unsigned char>& vKey) const;\n    bool contains(const uint256& hash) const;\n\n    void reset();\n\nprivate:\n    int nEntriesPerGeneration;\n    int nEntriesThisGeneration;\n    int nGeneration;\n    std::vector<uint64_t> data;\n    unsigned int nTweak;\n    int nHashFuncs;\n};\n\n#endif\n"
  },
  {
    "path": "src/chain.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n\n/**\n * CChain implementation\n */\nvoid CChain::SetTip(CBlockIndex *pindex) {\n    if (pindex == nullptr) {\n        vChain.clear();\n        vChain.shrink_to_fit();\n        return;\n    }\n    vChain.resize(pindex->nHeight + 1);\n    while (pindex && vChain[pindex->nHeight] != pindex) {\n        vChain[pindex->nHeight] = pindex;\n        pindex = pindex->pprev;\n    }\n}\n\nCBlockLocator CChain::GetLocatorLegacy(const CBlockIndex *pindex) const {\n    int nStep = 1;\n    std::vector<uint256> vHave;\n    vHave.reserve(32);\n\n    if (!pindex)\n        pindex = Tip();\n    while (pindex) {\n        vHave.push_back(pindex->GetBlockHashLegacy());\n        // Stop when we have added the genesis block.\n        if (pindex->nHeight == 0)\n            break;\n        // Exponentially larger steps back, plus the genesis block.\n        int nHeight = std::max(pindex->nHeight - nStep, 0);\n        if (Contains(pindex)) {\n            // Use O(1) CChain index if possible.\n            pindex = (*this)[nHeight];\n        } else {\n            // Otherwise, use O(log n) skiplist.\n            pindex = pindex->GetAncestor(nHeight);\n        }\n        if (vHave.size() > 10)\n            nStep *= 2;\n    }\n\n    return CBlockLocator(vHave);\n}\n\nCBlockLocator CChain::GetLocatorPoW2(const CBlockIndex *pindex) const {\n    int nStep = 1;\n    std::vector<uint256> vHave;\n    vHave.reserve(32);\n\n    if (!pindex)\n        pindex = Tip();\n    while (pindex) {\n        vHave.push_back(pindex->GetBlockHashPoW2());\n        // Stop when we have added the genesis block.\n        if (pindex->nHeight == 0)\n            break;\n        // Exponentially larger steps back, plus the genesis block.\n        int nHeight = std::max(pindex->nHeight - nStep, 0);\n        if (Contains(pindex)) {\n            // Use O(1) CChain index if possible.\n            pindex = (*this)[nHeight];\n        } else {\n            // Otherwise, use O(log n) skiplist.\n            pindex = pindex->GetAncestor(nHeight);\n        }\n        if (vHave.size() > 10)\n            nStep *= 2;\n    }\n\n    return CBlockLocator(vHave);\n}\n\nconst CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {\n    if (pindex == NULL) {\n        return NULL;\n    }\n    if (pindex->nHeight > Height())\n        pindex = pindex->GetAncestor(Height());\n    while (pindex && !Contains(pindex))\n        pindex = pindex->pprev;\n    return pindex;\n}\n\nvoid CCloneChain::FreeMemory()\n{\n    //fixme: (POST-PHASE5) - We should use shared_ptr for the chain instead of raw pointers\n    //This will remove the need for this messy vFree situation; and also allow us to re-enable the miner test that relied on nHeight++ that we have had to disable due to a crash in this FreeMemory call.\n    for (auto index : vFree)\n    {\n        if (vChain[index->nHeight - cloneFrom] == index)\n            vChain[index->nHeight - cloneFrom] = nullptr;\n        delete index;\n    }\n    for (auto index : vChain)\n    {\n        if (index)\n        {\n            delete index;\n        }\n    }\n    vFree.clear();\n    vChain.clear();\n}\n\nCCloneChain::CCloneChain(const CChain& _origin, unsigned int _cloneFrom, const CBlockIndex *retainIndexIn, CBlockIndex *&retainIndexOut)\n: CChain()\n, origin(_origin)\n, cloneFrom(_cloneFrom)\n{\n    //fixme: (POST-PHASE4) - Temporarily allow nested cloning 'getwitnessinfo' needs this; however we should fix this in the near future.\n    // NB! Nested cloning is okay IFF we stick to a fixed clone height, the second we start trying to optimise by using a non-fixed clone height there will be problems.\n    // forbid nested cloning\n    //assert(dynamic_cast<const CCloneChain*>(&origin) == nullptr);\n\n    assert(cloneFrom <= origin.Height());\n    assert(cloneFrom >=0);\n\n    vChain.reserve(origin.Height() + 1 - cloneFrom);\n    vFree.reserve(origin.Height() + 1 - cloneFrom);\n\n    CBlockIndex* pprev = nullptr;\n    for (int i=cloneFrom; i<=origin.Height(); i++)\n    {\n        CBlockIndex* index = origin[i];\n        vChain.emplace_back(new CBlockIndex(*index));\n        vFree.push_back(vChain.back());\n        if (pprev)\n            vChain.back()->pprev = pprev;\n        vChain.back()->pskip = nullptr;\n        vChain.back()->BuildSkip();\n        pprev = vChain.back();\n        if (index == retainIndexIn)\n            retainIndexOut = pprev;\n    }\n\n    // case where retainIndexIn is in the chain before the part we've cloned\n    // you better know what you're doing!\n    if (!retainIndexOut && origin.Contains(retainIndexIn))\n        retainIndexOut = const_cast<CBlockIndex*>(retainIndexIn);\n\n    if (retainIndexIn && !retainIndexOut)\n    {\n        // Link the pprev(s) of our new potential tip with a new pointer thats inside the cloned chain instead of the old pointer to the old chain.\n        retainIndexOut = new CBlockIndex(*retainIndexIn);\n        {\n            //Don't worry about leaks, these become part of tempChain and are cleaned up along with tempChain.\n            CBlockIndex* pNotInChain = retainIndexOut;\n            // We might be sitting multiple blocks ahead of the chain, in which case we need to clone those blocks as well.\n            while (pNotInChain->pprev->nHeight > Tip()->nHeight || pNotInChain->pprev->GetBlockHashPoW2() != vChain[pNotInChain->pprev->nHeight - cloneFrom]->GetBlockHashPoW2())\n            {\n                pNotInChain->pskip = nullptr;\n                pNotInChain->pprev = new CBlockIndex(*pNotInChain->pprev);\n                pNotInChain = pNotInChain->pprev;\n            }\n            while (pNotInChain->pprev != vChain[pNotInChain->pprev->nHeight - cloneFrom])\n            {\n                pNotInChain->pskip = nullptr;\n                pNotInChain->pprev = vChain[pNotInChain->pprev->nHeight - cloneFrom];\n                pNotInChain = pNotInChain->pprev;\n            }\n        }\n    }\n}\n\nCBlockIndex *CCloneChain::operator[](int nHeight) const\n{\n    if (nHeight >= cloneFrom && nHeight <= Height())\n    {\n        return vChain[nHeight - cloneFrom];\n    }\n    else\n        return origin[nHeight];\n}\n\nint CCloneChain::Height() const\n{\n    return cloneFrom + vChain.size() - 1;\n}\n\nvoid CCloneChain::SetTip(CBlockIndex *pindex)\n{\n    // not allowed to modify origin chain\n    assert(pindex != nullptr && pindex->nHeight >= cloneFrom);\n\n    vChain.resize(pindex->nHeight - cloneFrom + 1);\n\n    while (pindex && vChain[pindex->nHeight - cloneFrom] != pindex) {\n        vChain[pindex->nHeight - cloneFrom] = pindex;\n        pindex = pindex->pprev;\n    }\n}\n\nCBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const\n{\n    std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,\n        [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });\n    return (lower == vChain.end() ? nullptr : *lower);\n}\n\n/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */\nint static inline InvertLowestOne(int n) { return n & (n - 1); }\n\n/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */\nint static inline GetSkipHeight(int height) {\n    if (height < 2)\n        return 0;\n\n    // Determine which height to jump back to. Any number strictly lower than height is acceptable,\n    // but the following expression seems to perform well in simulations (max 110 steps to go back\n    // up to 2**18 blocks).\n    return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);\n}\n\nCBlockIndex* CBlockIndex::GetAncestor(int height)\n{\n    if (height > (int)nHeight || height < 0)\n        return NULL;\n\n    CBlockIndex* pindexWalk = this;\n    int heightWalk = nHeight;\n    while (heightWalk > height) {\n        int heightSkip = GetSkipHeight(heightWalk);\n        int heightSkipPrev = GetSkipHeight(heightWalk - 1);\n        if (pindexWalk->pskip != NULL &&\n            (heightSkip == height ||\n             (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&\n                                       heightSkipPrev >= height)))) {\n            // Only follow pskip if pprev->pskip isn't better than pskip->pprev.\n            pindexWalk = pindexWalk->pskip;\n            heightWalk = heightSkip;\n        }\n        else if (pindexWalk->pprev)\n        {\n            pindexWalk = pindexWalk->pprev;\n            heightWalk--;\n        }\n        else\n            return nullptr;\n    }\n    return pindexWalk;\n}\n\nconst CBlockIndex* CBlockIndex::GetAncestor(int height) const\n{\n    return const_cast<CBlockIndex*>(this)->GetAncestor(height);\n}\n\nvoid CBlockIndex::BuildSkip()\n{\n    if (pprev)\n        pskip = pprev->GetAncestor(GetSkipHeight(nHeight));\n}\n\narith_uint256 GetBlockProof(const CBlockIndex& block)\n{\n    arith_uint256 bnTarget;\n    bool fNegative;\n    bool fOverflow;\n    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);\n    if (fNegative || fOverflow || bnTarget == 0)\n        return 0;\n    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256\n    // as it's too large for a arith_uint256. However, as 2**256 is at least as large\n    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,\n    // or ~bnTarget / (nTarget+1) + 1.\n    return (~bnTarget / (bnTarget + 1)) + 1;\n}\n\nconst CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb)\n{\n    if (pa->nHeight > pb->nHeight)\n    {\n        pa = pa->GetAncestor(pb->nHeight);\n    }\n    else if (pb->nHeight > pa->nHeight)\n    {\n        pb = pb->GetAncestor(pa->nHeight);\n    }\n\n    while (pa != pb && pa && pb)\n    {\n        pa = pa->pprev;\n        pb = pb->pprev;\n    }\n\n    // Eventually all chain branches meet at the genesis block.\n    assert(pa == pb);\n    return pa;\n}\n\nint64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)\n{\n    arith_uint256 r;\n    int sign = 1;\n    if (to.nChainWork > from.nChainWork) {\n        r = to.nChainWork - from.nChainWork;\n    } else {\n        r = from.nChainWork - to.nChainWork;\n        sign = -1;\n    }\n    r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);\n    if (r.bits() > 63) {\n        return sign * std::numeric_limits<int64_t>::max();\n    }\n    return sign * r.GetLow64();\n}\n\nCPartialChain::CPartialChain() :\n    nHeightOffset(0)\n{\n\n}\n\nvoid CPartialChain::SetHeightOffset(int offset)\n{\n    // changing the offset is only allowed if the chain is empty\n    assert(vChain.empty());\n\n    nHeightOffset = offset;\n}\n\nint CPartialChain::HeightOffset() const\n{\n    return nHeightOffset;\n}\n\nint CPartialChain::Length() const\n{\n    return vChain.size();\n}\n\nCBlockIndex *CPartialChain::operator[](int nHeight) const\n{\n    if (nHeight>= nHeightOffset && nHeight <= Height())\n        return vChain[nHeight - nHeightOffset];\n    else\n        return nullptr;\n}\n\nint CPartialChain::Height() const\n{\n    return vChain.size() + nHeightOffset - 1;\n}\n\nvoid CPartialChain::SetTip(CBlockIndex *pindex)\n{\n    if (pindex == nullptr) {\n        vChain.clear();\n        vChain.shrink_to_fit();\n        return;\n    }\n\n    assert(pindex->nHeight >= nHeightOffset);\n\n    vChain.resize(pindex->nHeight - nHeightOffset + 1);\n\n    while (pindex && pindex->nHeight >= nHeightOffset && vChain[pindex->nHeight - nHeightOffset] != pindex) {\n        vChain[pindex->nHeight - nHeightOffset] = pindex;\n        pindex = pindex->pprev;\n    }\n}\n\nCBlockLocator CPartialChain::GetLocatorPoW2(const CBlockIndex *pindex) const\n{\n    int nStep = 1;\n    std::vector<uint256> vHave;\n    vHave.reserve(32);\n\n    if (!pindex)\n        pindex = Tip();\n    while (pindex) {\n        vHave.push_back(pindex->GetBlockHashPoW2());\n        // Stop when we have added the genesis block.\n        if (pindex->nHeight == nHeightOffset)\n            break;\n        // Exponentially larger steps back, plus the genesis block.\n        int nHeight = std::max(pindex->nHeight - nStep, nHeightOffset);\n        if (Contains(pindex)) {\n            // Use O(1) CChain index if possible.\n            pindex = (*this)[nHeight];\n        } else {\n            // Otherwise, use O(log n) skiplist.\n            pindex = pindex->GetAncestor(nHeight);\n        }\n        if (vHave.size() > 10)\n            nStep *= 2;\n    }\n\n    return CBlockLocator(vHave);\n}\n\n"
  },
  {
    "path": "src/chain.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CHAIN_H\n#define CHAIN_H\n\n#include \"arith_uint256.h\"\n#include \"primitives/block.h\"\n#include \"pow/pow.h\"\n#include \"tinyformat.h\"\n#include \"uint256.h\"\n\n#include <vector>\n#include <valarray>\n\n#include \"chainparams.h\"\n/**\n * Maximum amount of time that a block timestamp is allowed to exceed the\n * current network-adjusted time before the block will be accepted.\n */\nstatic const int64_t MAX_FUTURE_BLOCK_TIME = 60;\n\n/**\n * Timestamp window used as a grace period by code that compares external\n * timestamps (such as timestamps passed to RPCs, or wallet key creation times)\n * to block timestamps. This should be set at least as high as\n * MAX_FUTURE_BLOCK_TIME.\n */\nstatic const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;\n\nclass CBlockFileInfo\n{\npublic:\n    unsigned int nBlocks;      //!< number of blocks stored in file\n    unsigned int nSize;        //!< number of used bytes of block file\n    unsigned int nUndoSize;    //!< number of used bytes in the undo file\n    unsigned int nHeightFirst; //!< lowest height of block in file\n    unsigned int nHeightLast;  //!< highest height of block in file\n    uint64_t nTimeFirst;       //!< earliest time of block in file\n    uint64_t nTimeLast;        //!< latest time of block in file\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(VARINT(nBlocks));\n        READWRITE(VARINT(nSize));\n        READWRITE(VARINT(nUndoSize));\n        READWRITE(VARINT(nHeightFirst));\n        READWRITE(VARINT(nHeightLast));\n        READWRITE(VARINT(nTimeFirst));\n        READWRITE(VARINT(nTimeLast));\n    }\n\n     void SetNull() {\n         nBlocks = 0;\n         nSize = 0;\n         nUndoSize = 0;\n         nHeightFirst = 0;\n         nHeightLast = 0;\n         nTimeFirst = 0;\n         nTimeLast = 0;\n     }\n\n     CBlockFileInfo() {\n         SetNull();\n     }\n\n     std::string ToString() const;\n\n     /** update statistics (does not update nSize) */\n     void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {\n         if (nBlocks==0 || nHeightFirst > nHeightIn)\n             nHeightFirst = nHeightIn;\n         if (nBlocks==0 || nTimeFirst > nTimeIn)\n             nTimeFirst = nTimeIn;\n         nBlocks++;\n         if (nHeightIn > nHeightLast)\n             nHeightLast = nHeightIn;\n         if (nTimeIn > nTimeLast)\n             nTimeLast = nTimeIn;\n     }\n};\n\nstruct CDiskBlockPos\n{\n    int nFile;\n    unsigned int nPos;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(VARINT(nFile));\n        READWRITE(VARINT(nPos));\n    }\n\n    CDiskBlockPos() {\n        SetNull();\n    }\n\n    CDiskBlockPos(int nFileIn, unsigned int nPosIn) {\n        nFile = nFileIn;\n        nPos = nPosIn;\n    }\n\n    friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) {\n        return (a.nFile == b.nFile && a.nPos == b.nPos);\n    }\n\n    friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) {\n        return !(a == b);\n    }\n    \n    friend bool operator< (const CDiskBlockPos a, const CDiskBlockPos b)\n    {\n        if (a.nFile > b.nFile)\n            return false;\n        else if (a.nFile < b.nFile)\n            return true;\n        if (a.nPos > b.nPos)\n            return false;\n        else if (a.nPos < b.nPos)\n            return true;\n        return false;\n    }\n\n    void SetNull() { nFile = -1; nPos = 0; }\n    bool IsNull() const { return (nFile == -1); }\n\n    std::string ToString() const\n    {\n        return strprintf(\"CBlockDiskPos(nFile=%i, nPos=%i)\", nFile, nPos);\n    }\n\n};\n\nenum BlockStatus: uint32_t {\n    //! Unused.\n    BLOCK_VALID_UNKNOWN      =    0,\n\n    //! Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future\n    BLOCK_VALID_HEADER       =    1,\n\n    //! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents\n    //! are also at least TREE.\n    BLOCK_VALID_TREE         =    2,\n\n    /**\n     * Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,\n     * sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all\n     * parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.\n     */\n    BLOCK_VALID_TRANSACTIONS =    3,\n\n    //! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30.\n    //! Implies all parents are also at least CHAIN.\n    BLOCK_VALID_CHAIN        =    4,\n\n    //! Scripts & signatures ok. Implies all parents are also at least SCRIPTS.\n    BLOCK_VALID_SCRIPTS      =    5,\n\n    //! All validity bits.\n    BLOCK_VALID_MASK         =   BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |\n                                 BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,\n\n    BLOCK_HAVE_DATA          =    8, //!< full block available in blk*.dat\n    BLOCK_HAVE_UNDO          =   16, //!< undo data available in rev*.dat\n    BLOCK_HAVE_MASK          =   BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,\n\n    BLOCK_FAILED_VALID       =   32, //!< stage after last reached validness failed\n    BLOCK_FAILED_CHILD       =   64, //!< descends from failed block\n    BLOCK_FAILED_MASK        =   BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,\n\n    BLOCK_OPT_WITNESS       =   128, //!< block data in blk*.data was received with a witness-enforcing client\n\n    BLOCK_PARTIAL_TREE         =  256, //! block is in partial tree and all parents are also at least BLOCK_PARTIAL_TREE\n    BLOCK_PARTIAL_TRANSACTIONS =  512, //! Partial tree analog of BLOCK_VALID_TRANSACTION, except CBlockIndex::nChainTx is NOT set.\n    BLOCK_PARTIAL_RESERVED1    = 1024, //! Claim bits for future partial validation levels\n    BLOCK_PARTIAL_RESERVED2    = 2048,\n\n    // All validation bits releated to partial tree validation\n    BLOCK_PARTIAL_MASK = BLOCK_PARTIAL_TREE | BLOCK_PARTIAL_TRANSACTIONS | BLOCK_PARTIAL_RESERVED1 | BLOCK_PARTIAL_RESERVED2,\n};\n\n/** The block chain is a tree shaped structure starting with the\n * genesis block at the root, with each block potentially having multiple\n * candidates to be the next block. A blockindex may have multiple pprev pointing\n * to it, but at most one of them can be part of the currently active branch.\n */\nclass CBlockIndex\n{\npublic:\n    //! pointer to the hash of the block, if any. IMPORTANT: Memory is owned by the mapBlockIndex!\n    //! So the hash pointer can only be valid if this CBlockIndex is in mapBlockIndex!\n    const uint256* phashBlock;\n\n    //! pointer to the index of the predecessor of this block\n    CBlockIndex* pprev;\n\n    //! pointer to the index of some further predecessor of this block\n    CBlockIndex* pskip;\n\n    //! height of the entry in the chain. The genesis block has height 0\n    int nHeight;\n\n    //! Which # file this block is stored in (blk?????.dat)\n    int nFile;\n\n    //! Byte offset within blk?????.dat where this block's data is stored\n    unsigned int nDataPos;\n\n    //! Byte offset within rev?????.dat where this block's undo data is stored\n    unsigned int nUndoPos;\n\n    //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block\n    arith_uint256 nChainWork;\n\n    //! Number of transactions in this block.\n    //! Note: in a potential headers-first mode, this number cannot be relied upon\n    unsigned int nTx;\n\n    //! (memory only) Number of transactions in the chain up to and including this block.\n    //! This value will be non-zero only if and only if transactions for this block and all its parents are available.\n    //! Change to 64-bit type when necessary; won't happen before 2030\n    unsigned int nChainTx;\n\n    //! Verification status of this block. See enum BlockStatus\n    unsigned int nStatus;\n\n    //! PoW2 witness block header\n    int32_t nVersionPoW2Witness;\n    uint32_t nTimePoW2Witness;\n    uint256 hashMerkleRootPoW2Witness;\n    std::vector<unsigned char> witnessHeaderPoW2Sig; // 65 bytes\n\n    // Changes in the witness UTXO that this block causes\n    std::vector<unsigned char> witnessUTXODelta;\n\n\n    //! block header\n    int32_t nVersion;\n    uint256 hashMerkleRoot;\n    uint32_t nTime;\n    uint32_t nBits;\n    //fixme: (SIGMA) - Ensure this works on both big and little endian - if not we might have to drop the struct and just use bit manipulation instead.\n    union\n    {\n        struct\n        {\n            uint16_t nPreNonce;\n            uint16_t nPostNonce;\n        };\n        uint32_t nNonce;\n    };\n\n    //! (memory only) Sequential id assigned to distinguish order in which blocks are received.\n    int32_t nSequenceId;\n\n    //! (memory only) Maximum nTime in the chain upto and including this block.\n    unsigned int nTimeMax;\n\n    void SetNull()\n    {\n        phashBlock = NULL;\n        pprev = NULL;\n        pskip = NULL;\n        nHeight = 0;\n        nFile = 0;\n        nDataPos = 0;\n        nUndoPos = 0;\n        nChainWork = arith_uint256();\n        nTx = 0;\n        nChainTx = 0;\n        nStatus = 0;\n        nSequenceId = 0;\n        nTimeMax = 0;\n\n        nVersionPoW2Witness = 0;\n        nTimePoW2Witness = 0;\n        hashMerkleRootPoW2Witness = uint256();\n        witnessHeaderPoW2Sig.clear();\n        witnessUTXODelta.clear();\n\n        nVersion       = 0;\n        hashMerkleRoot = uint256();\n        nTime          = 0;\n        nBits          = 0;\n        nNonce         = 0;\n    }\n\n    CBlockIndex()\n    {\n        SetNull();\n    }\n\n    CBlockIndex(const CBlockHeader& block)\n    {\n        SetNull();\n\n        nVersionPoW2Witness = block.nVersionPoW2Witness;\n        nTimePoW2Witness = block.nTimePoW2Witness;\n        hashMerkleRootPoW2Witness = block.hashMerkleRootPoW2Witness;\n        witnessHeaderPoW2Sig = block.witnessHeaderPoW2Sig;\n        witnessUTXODelta = block.witnessUTXODelta;\n        nVersion       = block.nVersion;\n        hashMerkleRoot = block.hashMerkleRoot;\n        nTime          = block.nTime;\n        nBits          = block.nBits;\n        nNonce         = block.nNonce;\n    }\n\n    CDiskBlockPos GetBlockPos() const {\n        CDiskBlockPos ret;\n        if (nStatus & BLOCK_HAVE_DATA) {\n            ret.nFile = nFile;\n            ret.nPos  = nDataPos;\n        }\n        return ret;\n    }\n\n    CDiskBlockPos GetUndoPos() const {\n        CDiskBlockPos ret;\n        if (nStatus & BLOCK_HAVE_UNDO) {\n            ret.nFile = nFile;\n            ret.nPos  = nUndoPos;\n        }\n        return ret;\n    }\n\n    CBlockHeader GetBlockHeader() const\n    {\n        CBlockHeader block;\n        block.nVersionPoW2Witness = nVersionPoW2Witness;\n        block.nTimePoW2Witness = nTimePoW2Witness;\n        block.hashMerkleRootPoW2Witness = hashMerkleRootPoW2Witness;\n        block.witnessHeaderPoW2Sig = witnessHeaderPoW2Sig;\n        block.witnessUTXODelta = witnessUTXODelta;\n        block.nVersion       = nVersion;\n        if (pprev)\n            block.hashPrevBlock = pprev->GetBlockHashPoW2();\n        block.hashMerkleRoot = hashMerkleRoot;\n        block.nTime          = nTime;\n        block.nBits          = nBits;\n        block.nNonce         = nNonce;\n        return block;\n    }\n\n    //Munt - phashBlock contains 'legacy' hash for PoW blocks and PoW2 hash for witness blocks.\n    //fixme: (PHASE5) (HIGH) - We can get rid of all this legacy/pow2 hash nonsense for 2.1 and just use the same hash everywhere...\n    uint256 GetBlockHashLegacy() const\n    {\n        if (nVersionPoW2Witness == 0)\n            return *phashBlock;\n        else\n            return GetBlockHeader().GetHashLegacy();\n    }\n\n    uint256 GetBlockHashPoW2() const\n    {\n        return *phashBlock;\n    }\n\n    //fixme: (PHASE5) All time related things should be unsigned.\n    int64_t GetBlockTime() const\n    {\n        return (int64_t)nTime;\n    }\n\n    int64_t GetBlockTimePoW2Witness() const\n    {\n        return nTimePoW2Witness == 0 ? (int64_t)nTime : (int64_t)nTimePoW2Witness;\n    }\n\n    int64_t GetBlockTimeMax() const\n    {\n        return (int64_t)nTimeMax;\n    }\n\n    //enum { nMedianTimeSpan=11 };\n\n    int64_t GetMedianTimePast() const\n    {\n        int nMedianTimeSpan = 11;\n        if (nHeight >  437500 || Params().IsTestnet())\n            nMedianTimeSpan = 3;\n\n        //fixme: (PHASE5) - This needs unit tests\n        if (this->nTimePoW2Witness != 0)\n        {\n            nMedianTimeSpan *= 2;\n            int nMid = nMedianTimeSpan/2;\n\n            std::valarray<int64_t> pmedian(nMedianTimeSpan);\n            int64_t* pbegin = &pmedian[0]+nMedianTimeSpan;\n            int64_t* pend = &pmedian[0]+nMedianTimeSpan;\n\n            const CBlockIndex* pindex = this;\n            for (int i = 0; i < nMedianTimeSpan/2 && pindex; i++, pindex = pindex->pprev)\n            {\n                *(--pbegin) = pindex->nTimePoW2Witness == 0 ? pindex->GetBlockTime() : pindex->nTimePoW2Witness;\n                *(--pbegin) = pindex->GetBlockTime();\n            }\n\n            std::sort(pbegin, pend);\n            if (pbegin-pend < nMedianTimeSpan)\n                return pbegin[0];\n\n            return ( pbegin[nMid-1] + pbegin[nMid] ) / 2;\n        }\n        else\n        {\n            std::valarray<int64_t> pmedian(nMedianTimeSpan);\n            int64_t* pbegin = &pmedian[0]+nMedianTimeSpan;\n            int64_t* pend = &pmedian[0]+nMedianTimeSpan;\n\n            const CBlockIndex* pindex = this;\n            for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)\n                *(--pbegin) = pindex->GetBlockTime();\n\n            std::sort(pbegin, pend);\n            if (pbegin-pend < nMedianTimeSpan)\n                return pbegin[0];\n\n            return pbegin[(pend - pbegin)/2];\n        }\n    }\n\n    int64_t GetMedianTimePastPoW() const\n    {\n        int nMedianTimeSpan = 11;\n        if (nHeight >  437500 || Params().IsTestnet())\n            nMedianTimeSpan = 3;\n\n        std::valarray<int64_t> pmedian(nMedianTimeSpan);\n        int64_t* pbegin = &pmedian[0]+nMedianTimeSpan;\n        int64_t* pend = &pmedian[0]+nMedianTimeSpan;\n\n        const CBlockIndex* pindex = this;\n        for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)\n            *(--pbegin) = pindex->GetBlockTime();\n\n        std::sort(pbegin, pend);\n\n        if (pbegin-pend < nMedianTimeSpan)\n            return pbegin[0];\n            \n        return pbegin[(pend - pbegin)/2];\n    }\n\n    int64_t GetMedianTimePastWitness() const\n    {\n        int nMedianTimeSpan = 11;\n        if (nHeight >  437500 || Params().IsTestnet())\n            nMedianTimeSpan = 3;\n\n        std::valarray<int64_t> pmedian(nMedianTimeSpan);\n        int64_t* pbegin = &pmedian[0]+nMedianTimeSpan;\n        int64_t* pend = &pmedian[0]+nMedianTimeSpan;\n\n        const CBlockIndex* pindex = this;\n        for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)\n            *(--pbegin) = pindex->nTimePoW2Witness == 0 ? pindex->GetBlockTime() : pindex->nTimePoW2Witness;\n\n        std::sort(pbegin, pend);\n        \n        if (pbegin-pend < nMedianTimeSpan)\n            return pbegin[0];\n\n        return pbegin[(pend - pbegin)/2];\n    }\n\n    std::string ToString() const\n    {\n        return strprintf(\"CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)\",\n            pprev, nHeight,\n            hashMerkleRoot.ToString(),\n            GetBlockHashPoW2().ToString());\n    }\n\n    //! Check whether this block index entry is valid up to the passed validity level.\n    bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const\n    {\n        assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.\n        if (nStatus & BLOCK_FAILED_MASK)\n            return false;\n        return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);\n    }\n\n    //! Raise the validity level of this block index entry.\n    //! Returns true if the validity was changed.\n    bool RaiseValidity(enum BlockStatus nUpTo)\n    {\n        assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.\n        if (nStatus & BLOCK_FAILED_MASK)\n            return false;\n        if ((nStatus & BLOCK_VALID_MASK) < nUpTo) {\n            nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo;\n            return true;\n        }\n        return false;\n    }\n\n    //! Check whether this block index entry is valid up to the passed partial validity level.\n    bool IsPartialValid(enum BlockStatus nUpTo = BLOCK_PARTIAL_TREE) const\n    {\n        assert(!(nUpTo & ~BLOCK_PARTIAL_MASK)); // Only validity flags allowed.\n        if (nStatus & BLOCK_FAILED_MASK)\n            return false;\n        return ((nStatus & BLOCK_PARTIAL_MASK) >= nUpTo);\n    }\n\n    //! Raise the partial validity level of this block index entry.\n    //! Returns true if the partial validity was changed.\n    bool RaisePartialValidity(enum BlockStatus nUpTo)\n    {\n        assert(!(nUpTo & ~BLOCK_PARTIAL_MASK)); // Only validity flags allowed.\n        if (nStatus & BLOCK_FAILED_MASK)\n            return false;\n        if ((nStatus & BLOCK_PARTIAL_MASK) < nUpTo) {\n            nStatus = (nStatus & ~BLOCK_PARTIAL_MASK) | nUpTo;\n            return true;\n        }\n        return false;\n    }\n\n    //! Build the skiplist pointer for this entry.\n    void BuildSkip();\n\n    //! Efficiently find an ancestor of this block.\n    CBlockIndex* GetAncestor(int height);\n    const CBlockIndex* GetAncestor(int height) const;\n};\n\n/** Find the last common ancestor two blocks have. Both pa and pb must be non-NULL. */\nconst CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb);\n\narith_uint256 GetBlockProof(const CBlockIndex& block);\n/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */\nint64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);\n\n/** Used to marshal pointers into hashes for db storage. */\nclass CDiskBlockIndex : public CBlockIndex\n{\npublic:\n    uint256 hashPrev;\n\n    CDiskBlockIndex() {\n        hashPrev = uint256();\n    }\n\n    explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) {\n        hashPrev = (pprev ? pprev->GetBlockHashPoW2() : uint256());\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        int _nVersion = s.GetVersion();\n        if (!(s.GetType() & SER_GETHASH))\n            READWRITE(VARINT(_nVersion));\n\n        READWRITE(VARINT(nHeight));\n        READWRITE(VARINT(nStatus));\n        READWRITE(VARINT(nTx));\n        if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))\n            READWRITE(VARINT(nFile));\n        if (nStatus & BLOCK_HAVE_DATA)\n            READWRITE(VARINT(nDataPos));\n        if (nStatus & BLOCK_HAVE_UNDO)\n            READWRITE(VARINT(nUndoPos));\n\n        // block header\n        READWRITE(this->nVersion);\n        READWRITE(hashPrev);\n        READWRITE(hashMerkleRoot);\n        READWRITE(nTime);\n        READWRITE(nBits);\n        READWRITE(nNonce);\n\n        try\n        {\n            READWRITE(nVersionPoW2Witness);\n            if (nVersionPoW2Witness != 0)\n            {\n                READWRITE(nTimePoW2Witness);\n                READWRITE(hashMerkleRootPoW2Witness);\n                if (ser_action.ForRead())\n                    witnessHeaderPoW2Sig.resize(65);\n                READWRITENOSIZEVECTOR(witnessHeaderPoW2Sig);\n                \n                if( ((s.GetType() == SER_DISK) && (_nVersion>= 2030013)) || \n                ((s.GetType() == SER_NETWORK) && (_nVersion % 80000 >= WITNESS_SYNC_VERSION)) ||\n                ((s.GetType() == SER_GETHASH) && (witnessUTXODelta.size() > 0)) )\n                {\n                    //fixme: (WITNESS_SYNC) - If size is frequently above 200 then switch to varint instead\n                    READWRITECOMPACTSIZEVECTOR(witnessUTXODelta);\n                }\n            }\n        }\n        catch (...)\n        {\n        }\n    }\n\n    uint256 GetBlockHashLegacy() const\n    {\n        CBlockHeader block;\n        block.nVersionPoW2Witness = nVersionPoW2Witness;\n        block.nTimePoW2Witness = nTimePoW2Witness;\n        block.hashMerkleRootPoW2Witness = hashMerkleRootPoW2Witness;\n        block.witnessHeaderPoW2Sig = witnessHeaderPoW2Sig;\n        block.witnessUTXODelta = witnessUTXODelta;\n        block.nVersion        = nVersion;\n        block.hashPrevBlock   = hashPrev;\n        block.hashMerkleRoot  = hashMerkleRoot;\n        block.nTime           = nTime;\n        block.nBits           = nBits;\n        block.nNonce          = nNonce;\n        return block.GetHashLegacy();\n    }\n\n    uint256 GetBlockHashPoW2(bool force=false) const\n    {\n        CBlockHeader block;\n        block.nVersionPoW2Witness = nVersionPoW2Witness;\n        block.nTimePoW2Witness = nTimePoW2Witness;\n        block.hashMerkleRootPoW2Witness = hashMerkleRootPoW2Witness;\n        block.witnessHeaderPoW2Sig = witnessHeaderPoW2Sig;\n        block.witnessUTXODelta = witnessUTXODelta;\n        block.nVersion        = nVersion;\n        block.hashPrevBlock   = hashPrev;\n        block.hashMerkleRoot  = hashMerkleRoot;\n        block.nTime           = nTime;\n        block.nBits           = nBits;\n        block.nNonce          = nNonce;\n        return block.GetHashPoW2(force);\n    }\n\n\n    std::string ToString() const\n    {\n        std::string str = \"CDiskBlockIndex(\";\n        str += CBlockIndex::ToString();\n        str += strprintf(\"\\n                hashBlockPoW=%s, hashBlockPoW2=%s, hashPrev=%s)\",\n            GetBlockHashLegacy().ToString(),\n            GetBlockHashPoW2().ToString(),\n            hashPrev.ToString());\n        return str;\n    }\n};\n\nclass CCloneChain;\n/** An in-memory indexed chain of blocks. */\nclass CChain {\nprotected:\n    std::vector<CBlockIndex*> vChain;\n\npublic:\n    /** Returns the index entry for the genesis block of this chain, or NULL if none. */\n    CBlockIndex *Genesis() const {\n        return Height() >= 0 ? operator[](0) : nullptr;\n    }\n\n    /** Returns the index entry for the tip of this chain, or NULL if none. */\n    CBlockIndex *Tip() const {\n        return Height() >= 0 ? operator[](Height()) : nullptr;\n    }\n\n    /** Returns the index entry for the previout to tip of this chain, or NULL if none. */\n    CBlockIndex* TipPrev() const\n    {\n        return Height() > 0 ? operator[](Height()-1) : nullptr;\n    }\n\n    /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */\n    virtual CBlockIndex *operator[](int nHeight) const {\n        if (nHeight < 0 || nHeight >= (int)vChain.size())\n            return nullptr;\n        return vChain[nHeight];\n    }\n\n    /** Compare two chains efficiently. */\n    friend bool operator==(const CChain &a, const CChain &b) {\n        return a.Height() == b.Height() &&\n               a[a.Height()] == b[a.Height()];\n    }\n\n    /** Efficiently check whether a block is present in this chain. */\n    bool Contains(const CBlockIndex *pindex) const {\n        return (*this)[pindex->nHeight] == pindex;\n    }\n\n    /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */\n    CBlockIndex *Next(const CBlockIndex *pindex) const {\n        if (Contains(pindex))\n            return (*this)[pindex->nHeight + 1];\n        else\n            return NULL;\n    }\n\n    /** Find the predecessor  of a block in this chain, or NULL if the given index is not found or it is the genisis block. */\n    CBlockIndex *Prev(const CBlockIndex *pindex) const {\n        if (Contains(pindex) && pindex->nHeight>0)\n            return (*this)[pindex->nHeight - 1];\n        else\n            return NULL;\n    }\n\n    /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */\n    virtual int Height() const {\n        return vChain.size() - 1;\n    }\n\n    /** Set/initialize a chain with a given tip. */\n    virtual void SetTip(CBlockIndex *pindex);\n\n    /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */\n    CBlockLocator GetLocatorLegacy(const CBlockIndex *pindex = NULL) const;\n    virtual CBlockLocator GetLocatorPoW2(const CBlockIndex *pindex = NULL) const;\n\n    /** Find the last common block between this chain and a block index entry. */\n    const CBlockIndex *FindFork(const CBlockIndex *pindex) const;\n\n    /** Find the earliest block with timestamp equal or greater than the given. */\n    CBlockIndex* FindEarliestAtLeast(int64_t nTime) const;\n\n    /** Find the youngest (ie. most recent) block index with comp(val, index) == true\n     *  Note that the chain should be ordered with respect to comp.\n    */\n    template<typename T, typename Compare>\n    CBlockIndex* FindYoungest(const T& val, const Compare& comp) {\n        const auto it = std::upper_bound (vChain.rbegin (), vChain.rend(), val, comp);\n        return it == vChain.rend() ? nullptr : *it;\n    }\n\n    virtual ~CChain(){};\n};\n\n/** A partial chain only keeps the chain from a certain height-offset onwards.\n * It does not (unlike the CCloneChain) keep a reference to another (full) chain to forward to\n * for items it does not hold.\n * The partial chain is intended to create light clients (SPV) that will only ever see and keep a part\n * of the chain. Access to blocks below the height-offset is illegal.\n*/\nclass CPartialChain : public CChain\n{\npublic:\n    CPartialChain();\n\n    void SetHeightOffset(int offset);\n    int HeightOffset() const;\n    int Length() const;\n    virtual CBlockIndex *operator[](int nHeight) const override;\n    virtual int Height() const override;\n    virtual void SetTip(CBlockIndex *pindex) override;\n    CBlockLocator GetLocatorPoW2(const CBlockIndex *pindex = NULL) const override;\n\n    template<typename T, typename Compare>\n    int LowerBound(int beginHeight, int endHeight, const T& val, const Compare& comp) const {\n        const auto beginRange = vChain.begin() + (beginHeight - HeightOffset());\n        const auto endRange =  vChain.begin() + (endHeight - HeightOffset());\n        const auto it = std::lower_bound(beginRange, endRange, val, comp);\n        return it == endRange ? -1 : (*it)->nHeight;\n    }\n\n    // Up until latest built in checkpoint height we are only interested in these ranges and not all blocks.\n    //fixme: (UNITY) (SPV) Move this into spvscanner rather.\n    RecursiveMutex cs_blockFilterRanges;\n    std::vector<std::tuple<uint64_t, uint64_t>> blockFilterRanges;\nprivate:\n    int nHeightOffset;\n};\n\n// Simple helper class to control memory of cloned chains.\nclass CCloneChain : public CChain\n{\npublic:\n    CCloneChain() = delete;\n    CCloneChain(const CChain& _origin, unsigned int _cloneFrom, const CBlockIndex* retainIndexIn, CBlockIndex*& retainIndexOut);\n\n    virtual ~CCloneChain()\n    {\n        FreeMemory();\n    }\n\n    virtual CBlockIndex *operator[](int nHeight) const override;\n\n    virtual int Height() const override;\n\n    virtual void SetTip(CBlockIndex *pindex) override;\n\nprivate:\n    void FreeMemory();\n\n    const CChain& origin;\n    int cloneFrom;\n    std::vector<CBlockIndex*> vFree;\n};\n\n#endif\n"
  },
  {
    "path": "src/chainparams.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chainparams.h\"\n#include \"pow/pow.h\"\n#include \"consensus/merkle.h\"\n#include \"crypto/hash/sigma/sigma.h\"\n\n#include \"tinyformat.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#include <assert.h>\n\n#include <cstdio>\n#include \"chainparamsseeds.h\"\n#include <validation/witnessvalidation.h>\n\nstatic CBlock CreateGenesisBlock(const std::vector<unsigned char>& timestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)\n{\n    CMutableTransaction txNew(1);\n    txNew.nVersion = 1;\n    txNew.vin.resize(1);\n    txNew.vout.resize(1);\n    txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << timestamp;\n    txNew.vout[0].nValue = genesisReward;\n    txNew.vout[0].output.scriptPubKey = genesisOutputScript;\n\n    CBlock genesis;\n    genesis.nTime    = nTime;\n    genesis.nBits    = nBits;\n    genesis.nNonce   = nNonce;\n    genesis.nVersion = nVersion;\n    genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));\n    genesis.hashPrevBlock.SetNull();\n    genesis.hashMerkleRoot = BlockMerkleRoot(genesis.vtx.begin(), genesis.vtx.end());\n    return genesis;\n}\n\n/**\n * Build the genesis block. Note that the output of its generation\n * transaction cannot be spent since it did not originally exist in the\n * database.\n *\n * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)\n *   CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)\n *     CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)\n *     CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)\n *   vMerkleTree: 4a5e1e\n */\nstatic CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)\n{\n    const CScript genesisOutputScript = CScript() << 0x0 << OP_CHECKSIG;\n    return CreateGenesisBlock(ParseHex(\"4f6e206a616e756172692031737420746865204475746368206c6f73742074686572652062656c6f7665642047756c64656e\"), genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);\n}\n\nCChainParams::CChainParams(): fIsOfficialTestnetV1(false), fIsTestnet(false), fIsRegtest(false), fIsRegtestLegacy(false) {}\n\nvoid CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)\n{\n    consensus.vDeployments[d].nStartTime = nStartTime;\n    consensus.vDeployments[d].nTimeout = nTimeout;\n}\n\n/**\n * Main network\n */\n/**\n * What makes a good checkpoint block?\n * + Is surrounded by blocks with reasonable timestamps\n *   (no blocks before with a timestamp after, none after with\n *    timestamp before)\n * + Contains no strange transactions\n */\n\nclass CMainParams : public CChainParams {\npublic:\n    CMainParams() {\n        strNetworkID = \"main\";\n        consensus.BIP34Height = 227931;\n        consensus.BIP34Hash = uint256S(\"0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8\");\n        consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0\n        consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931\n        consensus.powLimit =  uint256S(\"0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n        consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days\n        consensus.nPowTargetSpacing = 150; // 2.5 minutes\n        consensus.fPowAllowMinDifficultyBlocks = false;\n        consensus.fPowNoRetargeting = false;\n        consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016\n        consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].type = Consensus::DEPLOYMENT_POW;\n\n        // Deployment of BIP68, BIP112, and BIP113.\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].type = Consensus::DEPLOYMENT_POW;\n       \n        consensus.fixedRewardReductionHeight=250001;\n        consensus.pow2Phase2FirstBlockHeight=778177;\n        consensus.pow2Phase3FirstBlockHeight=778301;\n        consensus.devBlockSubsidyActivationHeight=1030001;\n        consensus.pow2Phase4FirstBlockHeight=1131652;\n        consensus.pow2Phase5FirstBlockHeight=1140958;\n        consensus.pow2WitnessSyncHeight=1'400'000;\n        consensus.halvingIntroductionHeight=consensus.pow2WitnessSyncHeight;     \n        consensus.finalSubsidyBlockHeight=433'009'988;\n\n        // Message start string to avoid accidental cross communication with other chains or software.\n        pchMessageStart[0] = 0xfc; // 'N' + 0xb0\n        pchMessageStart[1] = 0xfe; // 'L' + 0xb0\n        pchMessageStart[2] = 0xf7; // 'G' + 0xb0\n        pchMessageStart[3] = 0xe0; // 0xe0 (e for \"echt\", testnet has 0x02 as last byte)\n        vAlertPubKey = ParseHex(\"073513ffe7147aba88d33aea4da129d8a2829c545526d5d854ab51d5778f4d0625431ba1c5a3245bdfe8736b127fdfdb488de72640727d37355c4c3a66c547efad\");\n        nDefaultPort = 9231;\n        nPruneAfterHeight = 200000;\n\n        genesis = CreateGenesisBlock(1009843200, 2200095, 0x1e0ffff0, 1, 0);\n        consensus.hashGenesisBlock = genesis.GetHashPoW2();\n        assert(consensus.hashGenesisBlock == uint256S(\"0x6c5d71a461b5bff6742bb62e5be53978b8dec5103ce52d1aaab8c6a251582f92\"));\n        assert(genesis.hashMerkleRoot == uint256S(\"0x4bed0bcb3e6097445ae68d455137625bb66f0e7ba06d9db80290bf72e3d6dcf8\"));\n\n        vSeeds.push_back(CDNSSeedData(\"seed 0\",  \"seed.gulden.com\", false));\n        vSeeds.push_back(CDNSSeedData(\"seed 1\",  \"amsterdam.gulden.com\", false));\n        vSeeds.push_back(CDNSSeedData(\"seed 2\",  \"rotterdam.gulden.network\", false));\n        //vSeeds.push_back(CDNSSeedData(\"seed 3\",  \"seed.gulden.network\"));\n        //vSeeds.push_back(CDNSSeedData(\"seed 4\",  \"seed.gulden.blue\"));\n\n        base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,38);// 'G'\n        base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,98);// 'g'\n        base58Prefixes[POW2_WITNESS_ADDRESS] = std::vector<unsigned char>(1,73);// 'W'\n        base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,38+128);\n        base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};\n        base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};\n\n        vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));\n\n        fDefaultConsistencyChecks = false;\n        fRequireStandard = true;\n        fMineBlocksOnDemand = false;\n\n        checkpointData = (CCheckpointData)\n        {\n            {\n                #include \"data/chainparams_mainnet_static_checkpoint_data.cpp\"\n            }\n        };\n\n        // By default assume that the signatures in ancestors of this block are valid.\n        if (!checkpointData.empty())\n        {\n            consensus.defaultAssumeValid = checkpointData.rbegin()->second.hash;\n        }\n        else\n        {\n            consensus.defaultAssumeValid = uint256S(\"\");\n        }\n\n        // The best chain should have at least this much work.\n        consensus.nMinimumChainWork = uint256S(\"0000000000000000000000000000000000000000000000013805bf50536e6868\");\n    }\n};\n\n\nvoid GenerateGenesisBlock(CBlock& genesis, std::string seedKey, CKey& genesisWitnessPrivKey, uint32_t numGenesisWitnesses, uint64_t nTime, uint64_t nBits, uint64_t nNonce, bool blockNeedsGeneration, bool useSigma, Consensus::Params& consensus)\n{\n    // We MUST have ECC active for key generation\n    ECC_Start();\n    {\n        CMutableTransaction txNew(CTransaction::CURRENT_VERSION);\n        txNew.vin.resize(1);\n        txNew.vin[0].SetPrevOutNull();\n        txNew.vin[0].segregatedSignatureData.stack.clear();\n        txNew.vin[0].segregatedSignatureData.stack.push_back(std::vector<unsigned char>());\n        CVectorWriter(0, 0, txNew.vin[0].segregatedSignatureData.stack[0], 0) << VARINT(0);\n        txNew.vin[0].segregatedSignatureData.stack.push_back(ParseHex(\"4f6e206a616e756172692031737420746865204475746368206c6f73742074686572652062656c6f7665642047756c64656e\"));\n        \n        {\n            std::string sKey = seedKey;\n            sKey.resize(32, 0);\n            genesisWitnessPrivKey.Set((unsigned char*)&sKey[0],(unsigned char*)&sKey[0]+32, true);\n            \n            CTxOut renewedWitnessTxOutput;\n            renewedWitnessTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n            renewedWitnessTxOutput.output.witnessDetails.spendingKeyID = genesisWitnessPrivKey.GetPubKey().GetID();\n            renewedWitnessTxOutput.output.witnessDetails.witnessKeyID = genesisWitnessPrivKey.GetPubKey().GetID();\n            renewedWitnessTxOutput.output.witnessDetails.lockFromBlock = 1;\n            renewedWitnessTxOutput.output.witnessDetails.lockUntilBlock = 900000;\n            renewedWitnessTxOutput.output.witnessDetails.failCount = 0;\n            renewedWitnessTxOutput.output.witnessDetails.actionNonce = 1;\n            renewedWitnessTxOutput.nValue=0;\n            for (uint32_t i=0; i<numGenesisWitnesses;++i)\n            {\n                txNew.vout.push_back(renewedWitnessTxOutput);\n            }\n        }\n\n        genesis.nTime    = nTime;\n        genesis.nBits    = nBits;\n        genesis.nNonce   = nNonce;\n            \n        genesis.nVersion = 536870912;\n        genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));\n        genesis.hashPrevBlock.SetNull();\n        genesis.hashMerkleRoot = BlockMerkleRoot(genesis.vtx.begin(), genesis.vtx.end());\n        genesis.hashMerkleRootPoW2Witness = BlockMerkleRoot(genesis.vtx.begin(), genesis.vtx.end());\n        genesis.witnessHeaderPoW2Sig.resize(65);\n\n        if (blockNeedsGeneration)\n        {\n            if (useSigma)\n            {\n                uint256 foundBlockHash;\n                std::atomic<uint64_t> halfHashCounter=0;\n                bool interrupt=false;\n                sigma_context generateContext(defaultSigmaSettings, defaultSigmaSettings.arenaSizeKb, std::max(GetNumCores(), 1), std::max(GetNumCores(), 1));\n                generateContext.prepareArenas(genesis);\n                generateContext.mineBlock(&genesis, halfHashCounter, foundBlockHash, interrupt);\n            }\n            else\n            {\n                while(UintToArith256(genesis.GetPoWHash()) > UintToArith256(consensus.powLimit))\n                {\n                    ++genesis.nNonce;\n                }\n            }\n        }\n        genesis.nTimePoW2Witness = genesis.nTime+1;\n        genesis.nVersionPoW2Witness = genesis.nVersion;\n    }\n    ECC_Stop();\n            \n}\n\n/**\n * Testnet\n */\nclass CTestNetParams : public CChainParams {\npublic:\n    CTestNetParams() {\n        fIsTestnet = true;\n\n        strNetworkID = \"test\";\n        consensus.BIP34Height = 21111;\n        consensus.BIP34Hash = uint256S(\"0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8\");\n        consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6\n        consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182\n        consensus.powLimit =  uint256S(\"0x003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n        consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks\n\n        std::string sTestnetParams = GetArg(\"-testnet\", \"\");\n        if (!sTestnetParams.empty())\n        {\n            assert(sTestnetParams.find(\":\")!=std::string::npos);\n            assert(sTestnetParams[0] == 'S' || sTestnetParams[0] == 'C');\n\n            int targetInterval = atoi(sTestnetParams.substr(sTestnetParams.find(\":\")+1));\n            int64_t seedTimestamp = atoi64(sTestnetParams.substr(1,sTestnetParams.find(\":\")));\n\n            defaultSigmaSettings.activationDate = seedTimestamp+300;\n            if (sTestnetParams == \"S1596003003:60\")\n            {\n                fIsOfficialTestnetV1 = true;\n            }\n\n            consensus.nPowTargetSpacing = targetInterval;\n            consensus.fPowAllowMinDifficultyBlocks = false;\n            consensus.fPowNoRetargeting = false;\n            consensus.nRuleChangeActivationThreshold = 15; // 75% for testchains\n            consensus.nMinerConfirmationWindow = 20; // nPowTargetTimespan / nPowTargetSpacing\n\n            consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 0;\n            consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;\n            consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;\n            consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].type = Consensus::DEPLOYMENT_POW;\n\n            // Deployment of BIP68, BIP112, and BIP113.\n            consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;\n            consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;\n            consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;\n            consensus.vDeployments[Consensus::DEPLOYMENT_CSV].type = Consensus::DEPLOYMENT_POW;\n\n            // The best chain should have at least this much work.\n            consensus.nMinimumChainWork = uint256S(\"\");\n\n            // By default assume that the signatures in ancestors of this block are valid.\n            if (!checkpointData.empty())\n            {\n                consensus.defaultAssumeValid = checkpointData.rbegin()->second.hash;\n            }\n            else\n            {\n                consensus.defaultAssumeValid = uint256S(\"\");\n            }\n\n            consensus.fixedRewardReductionHeight=1;\n            consensus.pow2Phase2FirstBlockHeight=0;\n            consensus.pow2Phase3FirstBlockHeight=0;\n            consensus.devBlockSubsidyActivationHeight=1;\n            consensus.pow2Phase4FirstBlockHeight=0;\n            consensus.pow2Phase5FirstBlockHeight=0;\n            if (fIsOfficialTestnetV1)\n            {\n                consensus.pow2WitnessSyncHeight=352200;\n            }\n            else\n            {\n                consensus.pow2WitnessSyncHeight=10;\n            }\n            consensus.halvingIntroductionHeight=consensus.pow2WitnessSyncHeight;       \n            consensus.finalSubsidyBlockHeight=17727500;\n\n            numGenesisWitnesses = 10;\n            genesisWitnessWeightDivisor = 100;\n            \n            if (fIsOfficialTestnetV1)\n            {\n                GenerateGenesisBlock(genesis, sTestnetParams, genesisWitnessPrivKey, numGenesisWitnesses, 1596003003, 524287999, 4131389449, false, false, consensus);\n            }\n            else\n            {\n                GenerateGenesisBlock(genesis, sTestnetParams, genesisWitnessPrivKey, numGenesisWitnesses, seedTimestamp, arith_uint256((~arith_uint256(0) >> 10)).GetCompact(), 0, true, true, consensus);\n            }\n            \n            consensus.hashGenesisBlock = genesis.GetHashPoW2();\n            LogPrintf(\"genesis nonce: %d\\n\",genesis.nNonce);\n            LogPrintf(\"genesis time: %d\\n\",genesis.nTime);\n            LogPrintf(\"genesis bits: %d\\n\",genesis.nBits);\n            LogPrintf(\"genesis hash: %s\\n\", consensus.hashGenesisBlock.ToString().c_str());\n\n            pchMessageStart[0] = targetInterval & 0xFF;\n            pchMessageStart[1] = (seedTimestamp >> 8) & 0xFF;\n            pchMessageStart[2] = (seedTimestamp >> 16) & 0xFF;\n            pchMessageStart[3] = sTestnetParams[0];\n\n            LogPrintf(\"pchMessageStart (aka magic bytes). decimal:[%d %d %d %d] hex:[%#x %#x %#x %#x]\\n\", pchMessageStart[0], pchMessageStart[1], pchMessageStart[2], pchMessageStart[3], pchMessageStart[0], pchMessageStart[1], pchMessageStart[2], pchMessageStart[3]);\n        }\n\n        vAlertPubKey = ParseHex(\"06087071e40ddf2ecbdf1ae40f536fa8f78e9383006c710dd3ecce957a3cb9292038d0840e3be5042a6b863f75dfbe1cae8755a0f7887ae459af689f66caacab52\");\n        nDefaultPort = 9923;\n        nPruneAfterHeight = 1000;\n\n        vFixedSeeds.clear();\n        vSeeds.clear();\n        //vSeeds.push_back(CDNSSeedData(\"seed 0\", \"testseed.gulden.blue\"));\n\n        base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,65);// 'T'\n        base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,127);// 't'\n        base58Prefixes[POW2_WITNESS_ADDRESS] = std::vector<unsigned char>(1,63);// 'S'\n        base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,65+128);\n        base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};\n        base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};\n\n        vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));\n\n        fDefaultConsistencyChecks = false;\n        fRequireStandard = true;\n        fMineBlocksOnDemand = false;\n\n        checkpointData = {\n            { 0, { genesis.GetHashPoW2(), genesis.nTime } }\n        };\n\n        if (fIsOfficialTestnetV1)\n        {\n            checkpointData = {\n            {      0, { uint256S(\"0x924d4d8a9601594dc5a2adf14cefc354e9df230cb5215d5f42b61d0da60e0b03\"), 1596003004 } },\n            };\n            if (!checkpointData.empty())\n            {\n                consensus.defaultAssumeValid = checkpointData.rbegin()->second.hash;\n            }\n            else\n            {\n                consensus.defaultAssumeValid = uint256S(\"\");\n            }\n        }\n    }\n};\n\n/**\n * Regression test\n */\nclass CRegTestLegacyParams : public CChainParams {\npublic:\n    CRegTestLegacyParams() {\n        fIsRegtestLegacy = true;\n        strNetworkID = \"regtestlegacy\";\n        consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)\n        consensus.BIP34Hash = uint256();\n        consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)\n        consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)\n        consensus.powLimit = uint256S(\"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n        consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks\n        consensus.nPowTargetSpacing = 60;//1 minute\n        consensus.fPowAllowMinDifficultyBlocks = true;\n        consensus.fPowNoRetargeting = true;\n        consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains\n        consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].type = Consensus::DEPLOYMENT_POW;\n        \n        //Never activate\n        defaultSigmaSettings.activationDate = std::numeric_limits<uint64_t>::max();\n\n\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].type = Consensus::DEPLOYMENT_POW;\n\n        consensus.fixedRewardReductionHeight=40600;\n        consensus.pow2Phase2FirstBlockHeight=40800;\n        consensus.pow2Phase3FirstBlockHeight=50000;\n        consensus.devBlockSubsidyActivationHeight=50100;\n        consensus.pow2Phase4FirstBlockHeight=50500;\n        consensus.pow2Phase5FirstBlockHeight=50500;\n\n        // The best chain should have at least this much work.\n        consensus.nMinimumChainWork = uint256S(\"0x00\");\n\n        // By default assume that the signatures in ancestors of this block are valid.\n        if (!checkpointData.empty())\n        {\n            consensus.defaultAssumeValid = checkpointData.rbegin()->second.hash;\n        }\n        else\n        {\n            consensus.defaultAssumeValid = uint256S(\"\");\n        }\n\n        pchMessageStart[0] = 0xfc; // 'N' + 0xb0\n        pchMessageStart[1] = 0xfe; // 'L' + 0xb0\n        pchMessageStart[2] = 0xf7; // 'G' + 0xb0\n        pchMessageStart[3] = 0xFF; // 0xFF\n        nDefaultPort = 18444;\n        nPruneAfterHeight = 1000;\n\n        genesis = CreateGenesisBlock(1296688602, 2, UintToArith256(consensus.powLimit).GetCompact(), 1, 0);\n        consensus.hashGenesisBlock = genesis.GetHashPoW2();\n        assert(consensus.hashGenesisBlock == uint256S(\"0x3e4b830e0f75f7b72060ae5ebcc22fdf5df57c7e2350a2669ac4f8a2d734e1bc\"));\n        assert(genesis.hashMerkleRoot == uint256S(\"0x4bed0bcb3e6097445ae68d455137625bb66f0e7ba06d9db80290bf72e3d6dcf8\"));\n\n        vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.\n        vSeeds.clear();      //!< Regtest mode doesn't have any DNS seeds.\n\n        fDefaultConsistencyChecks = true;\n        fRequireStandard = false;\n        fMineBlocksOnDemand = true;\n\n        checkpointData = {\n            { 0, { genesis.GetHashPoW2(), genesis.nTime } }\n        };\n\n        base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,60);// 'R'\n        base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,122);// 'r'\n        base58Prefixes[POW2_WITNESS_ADDRESS] = std::vector<unsigned char>(1,123);// 'r'\n        base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,60+128);\n        base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};\n        base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};\n    }\n};\n\n/**\n * Regression test\n */\nclass CRegTestParams : public CChainParams {\npublic:\n    CRegTestParams() {\n        fIsRegtest = true;\n        strNetworkID = \"regtest\";\n        consensus.BIP34Height = 0;\n        consensus.BIP34Hash = uint256();\n        consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)\n        consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)\n        consensus.powLimit = uint256S(\"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n        consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks\n        consensus.nPowTargetSpacing = 60;//1 minute\n        consensus.fPowAllowMinDifficultyBlocks = true;\n        consensus.fPowNoRetargeting = true;\n        consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains\n        consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;\n        consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].type = Consensus::DEPLOYMENT_POW;\n        \n        //Never activate\n        defaultSigmaSettings.activationDate = std::numeric_limits<uint64_t>::max();\n\n\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;\n        consensus.vDeployments[Consensus::DEPLOYMENT_CSV].type = Consensus::DEPLOYMENT_POW;\n\n        consensus.fixedRewardReductionHeight=1;\n        consensus.pow2Phase2FirstBlockHeight=0;\n        consensus.pow2Phase3FirstBlockHeight=0;\n        consensus.devBlockSubsidyActivationHeight=1;\n        consensus.pow2Phase4FirstBlockHeight=0;\n        consensus.pow2Phase5FirstBlockHeight=0;\n        consensus.halvingIntroductionHeight=consensus.pow2WitnessSyncHeight;\n        consensus.finalSubsidyBlockHeight=17727500;\n        numGenesisWitnesses = 10;\n        genesisWitnessWeightDivisor = 100;\n\n\n        // The best chain should have at least this much work.\n        consensus.nMinimumChainWork = uint256S(\"0x00\");\n\n        // By default assume that the signatures in ancestors of this block are valid.\n        if (!checkpointData.empty())\n        {\n            consensus.defaultAssumeValid = checkpointData.rbegin()->second.hash;\n        }\n        else\n        {\n            consensus.defaultAssumeValid = uint256S(\"\");\n        }\n\n        pchMessageStart[0] = 0xfc; // 'N' + 0xb0\n        pchMessageStart[1] = 0xfe; // 'L' + 0xb0\n        pchMessageStart[2] = 0xf7; // 'G' + 0xb0\n        pchMessageStart[3] = 0xFF; // 0xFF\n        nDefaultPort = 18444;\n        nPruneAfterHeight = 1000;\n\n        GenerateGenesisBlock(genesis, \"regtestregtestregtestregtest\", genesisWitnessPrivKey, numGenesisWitnesses, 1296688602, UintToArith256(consensus.powLimit).GetCompact(), 0, true, false, consensus);\n\n        consensus.hashGenesisBlock = genesis.GetHashPoW2();\n        //assert(consensus.hashGenesisBlock == uint256S(\"0x3e4b830e0f75f7b72060ae5ebcc22fdf5df57c7e2350a2669ac4f8a2d734e1bc\"));\n        //assert(genesis.hashMerkleRoot == uint256S(\"0x4bed0bcb3e6097445ae68d455137625bb66f0e7ba06d9db80290bf72e3d6dcf8\"));\n\n        vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.\n        vSeeds.clear();      //!< Regtest mode doesn't have any DNS seeds.\n\n        fDefaultConsistencyChecks = false;\n        //fixme: (MED) Turn this back on, its causing issues for witnessing on regtest mode\n        //fDefaultConsistencyChecks = true;\n        fRequireStandard = false;\n        fMineBlocksOnDemand = true;\n\n        checkpointData = {\n            { 0, { genesis.GetHashPoW2(), genesis.nTime } }\n        };\n\n        base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,60);// 'R'\n        base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,122);// 'r'\n        base58Prefixes[POW2_WITNESS_ADDRESS] = std::vector<unsigned char>(1,123);// 'r'\n        base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,60+128);\n        base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};\n        base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};\n    }\n};\n\nstatic std::unique_ptr<CChainParams> globalChainParams;\n\nconst CChainParams &Params() {\n    assert(globalChainParams);\n    return *globalChainParams;\n}\n\nstd::unique_ptr<CChainParams> CreateChainParams(const std::string& chain)\n{\n    if (chain == CBaseChainParams::MAIN)\n        return std::unique_ptr<CChainParams>(new CMainParams());\n    else if (chain == CBaseChainParams::TESTNET)\n        return std::unique_ptr<CChainParams>(new CTestNetParams());\n    else if (chain == CBaseChainParams::REGTEST)\n        return std::unique_ptr<CChainParams>(new CRegTestParams());\n    else if (chain == CBaseChainParams::REGTESTLEGACY)\n        return std::unique_ptr<CChainParams>(new CRegTestLegacyParams());\n    throw std::runtime_error(strprintf(\"%s: Unknown chain %s.\", __func__, chain));\n}\n\nvoid SelectParams(const std::string& network)\n{\n    SelectBaseParams(network);\n    globalChainParams = CreateChainParams(network);\n}\n\nvoid FreeParams()\n{\n    globalChainParams = nullptr;\n}\n\nvoid UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)\n{\n    globalChainParams->UpdateVersionBitsParameters(d, nStartTime, nTimeout);\n}\n"
  },
  {
    "path": "src/chainparams.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CHAINPARAMS_H\n#define CHAINPARAMS_H\n\n#include \"chainparamsbase.h\"\n#include \"consensus/params.h\"\n#include \"primitives/block.h\"\n#include \"protocol.h\"\n#include \"key.h\"\n\n#include <memory>\n#include <vector>\n\nstruct CDNSSeedData {\n    std::string name, host;\n    bool supportsServiceBitsFiltering;\n    CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}\n};\n\nstruct SeedSpec6 {\n    uint8_t addr[16];\n    uint16_t port;\n};\n\nstruct CheckPointEntry\n{\n    CheckPointEntry() : nTime(0) {}\n    CheckPointEntry(uint256 _hash, int64_t _nTime) : hash(_hash), nTime(_nTime) {}\n    uint256 hash;\n    int64_t nTime;\n};\n\nusing CCheckpointData = std::map<int, CheckPointEntry>;\n\n/**\n * CChainParams defines various tweakable parameters of a given instance of the\n * Munt system. There are three: the main network on which people trade goods\n * and services, the public test network which gets reset from time to time and\n * a regression test mode which is intended for private networks only. It has\n * minimal difficulty to ensure that blocks can be found instantly.\n */\nclass CChainParams\n{\npublic:\n    enum Base58Type {\n        PUBKEY_ADDRESS,\n        SCRIPT_ADDRESS,\n        POW2_WITNESS_ADDRESS,\n        SECRET_KEY,\n        EXT_PUBLIC_KEY,\n        EXT_SECRET_KEY,\n\n        MAX_BASE58_TYPES\n    };\n\n    const Consensus::Params& GetConsensus() const { return consensus; }\n    const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }\n    const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }\n    int GetDefaultPort() const { return nDefaultPort; }\n\n    const CBlock& GenesisBlock() const { return genesis; }\n    /** Default value for -checkmempool and -checkblockindex argument */\n    bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }\n    /** Policy: Filter transactions that do not match well-defined patterns */\n    bool RequireStandard() const { return fRequireStandard; }\n    uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }\n    /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */\n    bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }\n    /** Return the BIP70 network string (main, test or regtest) */\n    std::string NetworkIDString() const { return strNetworkID; }\n    const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }\n    const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }\n    const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }\n    const CCheckpointData& Checkpoints() const { return checkpointData; }\n    void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);\n\n    bool IsTestnet() const { return fIsTestnet; }\n    bool IsRegtest() const { return fIsRegtest; }\n    bool IsRegtestLegacy() const { return fIsRegtestLegacy; }\n    //fixme: (testnet) remove after official testnet restarted\n    bool IsOfficialTestnetV1() const { return fIsOfficialTestnetV1; }\n    \n    // Testnet only variable (allow anyone to witness using genesis witness accounts)\n    CKey genesisWitnessPrivKey;\n    // Testnet only variable - specify number of 'genesis witness' accounts to create\n    uint32_t numGenesisWitnesses=0;\n    // Testnet only variable - specify how much each individual 'genesis witness' should be in terms of network weight\n    // NB! This is used as a divisor of the network weight. So '100' == 1% of network weight per account, with 'numGenesisWitnesses' of 10 this would result in 10% total over all accounts\n    uint32_t genesisWitnessWeightDivisor=0;\n    \nprotected:\n    CChainParams();\n\n    Consensus::Params consensus;\n    CMessageHeader::MessageStartChars pchMessageStart;\n    //! Raw pub key bytes for the broadcast alert signing key.\n    std::vector<unsigned char> vAlertPubKey;\n    int nDefaultPort;\n    uint64_t nPruneAfterHeight;\n    std::vector<CDNSSeedData> vSeeds;\n    std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];\n    std::string strNetworkID;\n    CBlock genesis;\n    std::vector<SeedSpec6> vFixedSeeds;\n    bool fDefaultConsistencyChecks;\n    bool fRequireStandard;\n    bool fMineBlocksOnDemand;\n    CCheckpointData checkpointData;\n    bool fIsOfficialTestnetV1;\n    bool fIsTestnet;\n    bool fIsRegtest;\n    bool fIsRegtestLegacy;\n};\n\n/**\n * Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.\n * @returns a CChainParams* of the chosen chain.\n * @throws a std::runtime_error if the chain is not supported.\n */\nstd::unique_ptr<CChainParams> CreateChainParams(const std::string& chain);\n\n/**\n * Return the currently selected parameters. This won't change after app\n * startup, except for unit tests.\n */\nconst CChainParams &Params();\n\n/**\n * Sets the params returned by Params() to those for the given BIP70 chain name.\n * @throws std::runtime_error when the chain is not supported.\n */\nvoid SelectParams(const std::string& chain);\n\n/**\n * Free any globally stored chain params for app shutdown\n */\nvoid FreeParams();\n\n/**\n * Allows modifying the Version Bits regtest parameters.\n */\nvoid UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);\n\n#endif\n"
  },
  {
    "path": "src/chainparamsbase.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chainparamsbase.h\"\n\n#include \"tinyformat.h\"\n#include \"util.h\"\n\n#include <assert.h>\n\nconst std::string CBaseChainParams::MAIN = \"main\";\nconst std::string CBaseChainParams::TESTNET = \"test\";\nconst std::string CBaseChainParams::REGTEST = \"regtest\";\nconst std::string CBaseChainParams::REGTESTLEGACY = \"regtestlegacy\";\n\nvoid AppendParamsHelpMessages(std::string& strUsage, bool debugHelp)\n{\n    strUsage += HelpMessageGroup(_(\"Chain selection options:\"));\n    strUsage += HelpMessageOpt(\"-testnet\", _(\"Use or create a test blockchain. Specify the chain using the format <hashtype><genesistimestamp>:<blockintervaltarget> e.g. S1505211751:20 (Scrypt with 20 second block target) or C1505211751:10 (City hash with 10 second block target). For 'official' testnet chain specifiers view the latest README.md where the latest chains will always be listed.\"));\n    if (debugHelp) {\n        strUsage += HelpMessageOpt(\"-regtest\", \"Enter regression test mode, which uses a special chain in which blocks can be solved instantly. \"\n                                   \"This is intended for regression testing tools and app development.\");\n    }\n}\n\n/**\n * Main network\n */\nclass CBaseMainParams : public CBaseChainParams\n{\npublic:\n    CBaseMainParams()\n    {\n        nRPCPort = 9232;\n    }\n};\n\n/**\n * Testnet (v3)\n */\nclass CBaseTestNetParams : public CBaseChainParams\n{\npublic:\n    CBaseTestNetParams()\n    {\n        nRPCPort = 9924;\n        std::string testnetArgs = GetArg(\"-testnet\", \"\");\n        std::replace( testnetArgs.begin(), testnetArgs.end(), ':', '_');\n        strDataDir = (fs::path(\"testnet\") / testnetArgs).string();\n    }\n};\n\n/*\n * Regression test\n */\nclass CBaseRegTestParams : public CBaseChainParams\n{\npublic:\n    CBaseRegTestParams()\n    {\n        nRPCPort = 18332;\n        strDataDir = \"regtest\";\n    }\n};\n\n/*\n * Regression test\n */\nclass CBaseRegTestLegacyParams : public CBaseChainParams\n{\npublic:\n    CBaseRegTestLegacyParams()\n    {\n        nRPCPort = 18332;\n        strDataDir = \"regtestlegacy\";\n    }\n};\n\nstatic std::unique_ptr<CBaseChainParams> globalChainBaseParams;\n\nconst CBaseChainParams& BaseParams()\n{\n    assert(globalChainBaseParams);\n    return *globalChainBaseParams;\n}\n\nstd::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)\n{\n    if (chain == CBaseChainParams::MAIN)\n        return std::unique_ptr<CBaseChainParams>(new CBaseMainParams());\n    else if (chain == CBaseChainParams::TESTNET)\n        return std::unique_ptr<CBaseChainParams>(new CBaseTestNetParams());\n    else if (chain == CBaseChainParams::REGTEST)\n        return std::unique_ptr<CBaseChainParams>(new CBaseRegTestParams());\n    else if (chain == CBaseChainParams::REGTESTLEGACY)\n        return std::unique_ptr<CBaseChainParams>(new CBaseRegTestLegacyParams());\n    else\n        throw std::runtime_error(strprintf(\"%s: Unknown chain %s.\", __func__, chain));\n}\n\nvoid SelectBaseParams(const std::string& chain)\n{\n    globalChainBaseParams = CreateBaseChainParams(chain);\n}\n\nstd::string ChainNameFromCommandLine()\n{\n    bool fRegTest = GetBoolArg(\"-regtest\", false);\n    bool fRegTestLegacy = GetBoolArg(\"-regtestlegacy\", false);\n    bool fTestNet = IsArgSet(\"-testnet\");\n\n    if (fTestNet && (fRegTest||fRegTestLegacy))\n        throw std::runtime_error(\"Invalid combination of -regtest and -testnet.\");\n    if (fRegTest)\n        return CBaseChainParams::REGTEST;\n    if (fRegTestLegacy)\n        return CBaseChainParams::REGTESTLEGACY;\n    if (fTestNet)\n    {\n        std::string sTestnetParams = GetArg(\"-testnet\", \"\");\n        if (sTestnetParams.empty())\n            throw std::runtime_error(\"Invalid seed timestamp for testnet.\");\n        return CBaseChainParams::TESTNET;\n    }\n    return CBaseChainParams::MAIN;\n}\n"
  },
  {
    "path": "src/chainparamsbase.h",
    "content": "// Copyright (c) 2014-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CHAINPARAMSBASE_H\n#define CHAINPARAMSBASE_H\n\n#include <memory>\n#include <string>\n#include <vector>\n\n/**\n * CBaseChainParams defines the base parameters (shared between CLI and daemon)\n * of a given instance of the Bitcoin system.\n */\nclass CBaseChainParams\n{\npublic:\n    /** BIP70 chain name strings (main, test or regtest) */\n    static const std::string MAIN;\n    static const std::string TESTNET;\n    static const std::string REGTEST;\n    static const std::string REGTESTLEGACY;\n\n    const std::string& DataDir() const { return strDataDir; }\n    int RPCPort() const { return nRPCPort; }\n\nprotected:\n    CBaseChainParams() {}\n\n    int nRPCPort;\n    std::string strDataDir;\n};\n\n/**\n * Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.\n * @returns a CBaseChainParams* of the chosen chain.\n * @throws a std::runtime_error if the chain is not supported.\n */\nstd::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain);\n\n/**\n * Append the help messages for the chainparams options to the\n * parameter string.\n */\nvoid AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true);\n\n/**\n * Return the currently selected parameters. This won't change after app\n * startup, except for unit tests.\n */\nconst CBaseChainParams& BaseParams();\n\n/** Sets the params returned by Params() to those for the given network. */\nvoid SelectBaseParams(const std::string& chain);\n\n/**\n * Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.\n * @return CBaseChainParams::MAX_NETWORK_TYPES if an invalid combination is given. CBaseChainParams::MAIN by default.\n */\nstd::string ChainNameFromCommandLine();\n\n#endif\n"
  },
  {
    "path": "src/chainparamsseeds.h",
    "content": "#ifndef H_CHAINPARAMSSEEDS\n#define H_CHAINPARAMSSEEDS\n/**\n * List of fixed seed nodes for the bitcoin network\n * AUTOGENERATED by share/seeds/generate-seeds.py\n *\n * Each line contains a 16-byte IPv6 address and a port.\n * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.\n */\nstatic SeedSpec6 pnSeed6_main[] = {\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xd5,0x4a,0xdc}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x69,0x01,0x04}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x17,0xd5,0x2f}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0x02,0x93}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x63,0x76}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xc1,0x6d}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x21}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xf2,0x69}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x24,0x48,0x5a}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xaf,0x51,0x2d}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0xa1,0x80,0x3a}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x11,0x54,0x87}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xd2,0xa8,0x47}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc5,0x57,0xd2,0x26}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xff,0x65}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xaf,0x37}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x1f,0xab,0xa4}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xaf,0xa4}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x53,0x9c,0x9e}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x22}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x20}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xa8,0x35,0x99}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb6,0x5c,0xf0,0x70}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x09,0x3f,0x88}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x63,0x23,0x85}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x27,0x45,0x22}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x2d,0x09,0x1e}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa6,0x53,0x86}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x08,0xbc,0xf9}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0x52,0xe5}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x9d,0x04,0x09}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xaf,0xca}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x95,0x33,0xd9}, 9231},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x18,0xeb,0x65}, 9231}\n};\n\nstatic SeedSpec6 pnSeed6_test[] = {\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xd5,0x4a,0xdc}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x69,0x01,0x04}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x17,0xd5,0x2f}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0x02,0x93}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x63,0x76}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xc1,0x6d}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x21}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xf2,0x69}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x24,0x48,0x5a}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xaf,0x51,0x2d}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0xa1,0x80,0x3a}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x11,0x54,0x87}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xd2,0xa8,0x47}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc5,0x57,0xd2,0x26}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xff,0x65}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xaf,0x37}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x1f,0xab,0xa4}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xaf,0xa4}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x53,0x9c,0x9e}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x22}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1b,0xad,0x20}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xa8,0x35,0x99}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb6,0x5c,0xf0,0x70}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x09,0x3f,0x88}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x63,0x23,0x85}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x27,0x45,0x22}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x2d,0x09,0x1e}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa6,0x53,0x86}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x08,0xbc,0xf9}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0x52,0xe5}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x9d,0x04,0x09}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xaf,0xca}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x95,0x33,0xd9}, 9923},\n    {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x18,0xeb,0x65}, 9923}\n};\n#endif\n"
  },
  {
    "path": "src/checkpoints.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"checkpoints.h\"\n\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"validation/validation.h\"\n#include \"uint256.h\"\n\n#include <boost/range/adaptor/reversed.hpp>\n#include <stdint.h>\n#include <boost/range/rbegin.hpp>\n\nnamespace Checkpoints {\n\n    /**\n     * Last checkpoint present in the BlockIndex which connects to the full tree\n     * So checkpoints in the partial tree which don't connect are ignored\n    */\n    CBlockIndex* GetLastCheckpointIndex()\n    {\n        for (const auto& i: boost::adaptors::reverse(Params().Checkpoints()))\n        {\n            BlockMap::const_iterator t = mapBlockIndex.find(i.second.hash);\n            if (t != mapBlockIndex.end() && t->second->IsValid(BLOCK_VALID_TREE))\n            {\n                return t->second;\n            }\n        }\n        return nullptr;\n    }\n\n    int LastCheckPointHeight()\n    {\n        if (Params().Checkpoints().size() > 0)\n        {\n            auto lastCheckpoint = Params().Checkpoints().rbegin();\n            return lastCheckpoint->first;\n        }\n        else\n        {\n            return 0;\n        }\n    }\n\n    int LastCheckpointBeforeBlock(uint64_t blockHeight)\n    {\n        for (const auto& i: boost::adaptors::reverse(Params().Checkpoints()))\n        {\n            if ((uint64_t)i.first <= blockHeight)\n            {\n                return i.first;\n            }\n        }\n        return -1;\n    }\n\n    int LastCheckpointBeforeTime(uint64_t atTime)\n    {\n        for (const auto& i: boost::adaptors::reverse(Params().Checkpoints()))\n        {\n            if ((uint64_t)i.second.nTime <= atTime)\n            {\n                return i.first;\n            }\n        }\n        return -1;\n    }\n\n} // namespace Checkpoints\n"
  },
  {
    "path": "src/checkpoints.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CHECKPOINTS_H\n#define CHECKPOINTS_H\n\n#include \"chainparams.h\"\n\nclass CBlockIndex;\n\n/**\n * Block-chain checkpoints are compiled-in sanity checks.\n * They are updated every release or three.\n */\nnamespace Checkpoints\n{\n\n//! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint in Params()\nCBlockIndex* GetLastCheckpointIndex();\n\n//! Height of last checkpoint in Params()\nint LastCheckPointHeight();\n\n/** Last checkpoint with block height before or at blockHeight.\n    Returns height of the checkpoint, or -1 iof there is none. */\nint LastCheckpointBeforeBlock(uint64_t blockHeight);\n\n/** Last checkpoint with timestamp before or at atTime.\n    Returns height of the checkpoint, or -1 iof there is none. */\nint LastCheckpointBeforeTime(uint64_t atTime);\n\n} //namespace Checkpoints\n\n#endif\n"
  },
  {
    "path": "src/checkqueue.h",
    "content": "// Copyright (c) 2012-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CHECKQUEUE_H\n#define CHECKQUEUE_H\n\n#include <sync.h>\n#include <tinyformat.h>\n#include <util/syscall_sandbox.h>\n#include <util/threadnames.h>\n\n#include <algorithm>\n#include <vector>\n\ntemplate <typename T>\nclass CCheckQueueControl;\n\n/**\n * Queue for verifications that have to be performed.\n  * The verifications are represented by a type T, which must provide an\n  * operator(), returning a bool.\n  *\n  * One thread (the master) is assumed to push batches of verifications\n  * onto the queue, where they are processed by N-1 worker threads. When\n  * the master is done adding work, it temporarily joins the worker pool\n  * as an N'th worker, until all jobs are done.\n  */\ntemplate <typename T>\nclass CCheckQueue\n{\nprivate:\n    //! Mutex to protect the inner state\n    Mutex m_mutex;\n\n    //! Worker threads block on this when out of work\n    std::condition_variable m_worker_cv;\n\n    //! Master thread blocks on this when out of work\n    std::condition_variable m_master_cv;\n\n    //! The queue of elements to be processed.\n    //! As the order of booleans doesn't matter, it is used as a LIFO (stack)\n    std::vector<T> queue GUARDED_BY(m_mutex);\n\n    //! The number of workers (including the master) that are idle.\n    int nIdle GUARDED_BY(m_mutex){0};\n\n    //! The total number of workers (including the master).\n    int nTotal GUARDED_BY(m_mutex){0};\n\n    //! The temporary evaluation result.\n    bool fAllOk GUARDED_BY(m_mutex){true};\n\n    /**\n     * Number of verifications that haven't completed yet.\n     * This includes elements that are no longer queued, but still in the\n     * worker's own batches.\n     */\n    unsigned int nTodo GUARDED_BY(m_mutex){0};\n\n    //! The maximum number of elements to be processed in one batch\n    const unsigned int nBatchSize;\n\n    std::vector<std::thread> m_worker_threads;\n    bool m_request_stop GUARDED_BY(m_mutex){false};\n\n    /** Internal function that does bulk of the verification work. */\n    bool Loop(bool fMaster)\n    {\n        std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv;\n        std::vector<T> vChecks;\n        vChecks.reserve(nBatchSize);\n        unsigned int nNow = 0;\n        bool fOk = true;\n        do {\n            {\n                WAIT_LOCK(m_mutex, lock);\n                // first do the clean-up of the previous loop run (allowing us to do it in the same critsect)\n                if (nNow) {\n                    fAllOk &= fOk;\n                    nTodo -= nNow;\n                    if (nTodo == 0 && !fMaster)\n                        // We processed the last element; inform the master it can exit and return the result\n                        m_master_cv.notify_one();\n                } else {\n                    // first iteration\n                    nTotal++;\n                }\n                // logically, the do loop starts here\n                while (queue.empty() && !m_request_stop) {\n                    if (fMaster && nTodo == 0) {\n                        nTotal--;\n                        bool fRet = fAllOk;\n                        // reset the status for new work later\n                        fAllOk = true;\n                        // return the current status\n                        return fRet;\n                    }\n                    nIdle++;\n                    cond.wait(lock); // wait\n                    nIdle--;\n                }\n                if (m_request_stop) {\n                    return false;\n                }\n\n                // Decide how many work units to process now.\n                // * Do not try to do everything at once, but aim for increasingly smaller batches so\n                //   all workers finish approximately simultaneously.\n                // * Try to account for idle jobs which will instantly start helping.\n                // * Don't do batches smaller than 1 (duh), or larger than nBatchSize.\n                nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));\n                vChecks.resize(nNow);\n                for (unsigned int i = 0; i < nNow; i++) {\n                    // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global\n                    // queue to the local batch vector instead of copying.\n                    vChecks[i].swap(queue.back());\n                    queue.pop_back();\n                }\n                // Check whether we need to do work at all\n                fOk = fAllOk;\n            }\n            // execute work\n            for (T& check : vChecks)\n                if (fOk)\n                    fOk = check();\n            vChecks.clear();\n        } while (true);\n    }\n\npublic:\n    //! Mutex to ensure only one concurrent CCheckQueueControl\n    Mutex m_control_mutex;\n\n    //! Create a new check queue\n    explicit CCheckQueue(unsigned int nBatchSizeIn)\n        : nBatchSize(nBatchSizeIn)\n    {\n    }\n\n    //! Create a pool of new worker threads.\n    void StartWorkerThreads(const int threads_num)\n    {\n        {\n            LOCK(m_mutex);\n            nIdle = 0;\n            nTotal = 0;\n            fAllOk = true;\n        }\n        assert(m_worker_threads.empty());\n        for (int n = 0; n < threads_num; ++n) {\n            m_worker_threads.emplace_back([this, n]() {\n                util::ThreadRename(strprintf(\"scriptch.%i\", n));\n                SetSyscallSandboxPolicy(SyscallSandboxPolicy::VALIDATION_SCRIPT_CHECK);\n                Loop(false /* worker thread */);\n            });\n        }\n    }\n\n    //! Wait until execution finishes, and return whether all evaluations were successful.\n    bool Wait()\n    {\n        return Loop(true /* master thread */);\n    }\n\n    //! Add a batch of checks to the queue\n    void Add(std::vector<T>& vChecks)\n    {\n        if (vChecks.empty()) {\n            return;\n        }\n\n        {\n            LOCK(m_mutex);\n            for (T& check : vChecks) {\n                queue.emplace_back();\n                check.swap(queue.back());\n            }\n            nTodo += vChecks.size();\n        }\n\n        if (vChecks.size() == 1) {\n            m_worker_cv.notify_one();\n        } else {\n            m_worker_cv.notify_all();\n        }\n    }\n\n    //! Stop all of the worker threads.\n    void StopWorkerThreads()\n    {\n        WITH_LOCK(m_mutex, m_request_stop = true);\n        m_worker_cv.notify_all();\n        for (std::thread& t : m_worker_threads) {\n            t.join();\n        }\n        m_worker_threads.clear();\n        WITH_LOCK(m_mutex, m_request_stop = false);\n    }\n\n    ~CCheckQueue()\n    {\n        assert(m_worker_threads.empty());\n    }\n\n};\n\n/**\n * RAII-style controller object for a CCheckQueue that guarantees the passed\n * queue is finished before continuing.\n */\ntemplate <typename T>\nclass CCheckQueueControl\n{\nprivate:\n    CCheckQueue<T> * const pqueue;\n    bool fDone;\n\npublic:\n    CCheckQueueControl() = delete;\n    CCheckQueueControl(const CCheckQueueControl&) = delete;\n    CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;\n    explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)\n    {\n        // passed queue is supposed to be unused, or nullptr\n        if (pqueue != nullptr) {\n            ENTER_CRITICAL_SECTION(pqueue->m_control_mutex);\n        }\n    }\n\n    bool Wait()\n    {\n        if (pqueue == nullptr)\n            return true;\n        bool fRet = pqueue->Wait();\n        fDone = true;\n        return fRet;\n    }\n\n    void Add(std::vector<T>& vChecks)\n    {\n        if (pqueue != nullptr)\n            pqueue->Add(vChecks);\n    }\n\n    ~CCheckQueueControl()\n    {\n        if (!fDone)\n            Wait();\n        if (pqueue != nullptr) {\n            LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex);\n        }\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/cli-main.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"chainparamsbase.h\"\n#include \"clientversion.h\"\n#include \"fs.h\"\n#include \"rpc/client.h\"\n#include \"rpc/protocol.h\"\n#include \"util.h\"\n#include \"util/time.h\"\n#include \"util/strencodings.h\"\n#include <util/thread.h>\n#include <boost/thread.hpp>\n\n#include <stdio.h>\n\n#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */\n#include <event2/buffer.h>\n#include <event2/keyvalq_struct.h>\n#include \"support/events.h\"\n\n#include <univalue.h>\n\nstatic const char DEFAULT_RPCCONNECT[] = \"127.0.0.1\";\nstatic const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;\nstatic const bool DEFAULT_NAMED=false;\nstatic const int CONTINUE_EXECUTION=-1;\n\nstatic std::string HelpMessageCli()\n{\n    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);\n    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);\n    std::string strUsage;\n    strUsage += HelpMessageGroup(_(\"Options:\"));\n    strUsage += HelpMessageOpt(\"-?\", _(\"This help message\"));\n    strUsage += HelpMessageOpt(\"-conf=<file>\", strprintf(_(\"Specify configuration file (default: %s)\"), DEFAULT_CONF_FILENAME));\n    strUsage += HelpMessageOpt(\"-datadir=<dir>\", _(\"Specify data directory\"));\n    AppendParamsHelpMessages(strUsage);\n    strUsage += HelpMessageOpt(\"-named\", strprintf(_(\"Pass named instead of positional arguments (default: %s)\"), DEFAULT_NAMED));\n    strUsage += HelpMessageOpt(\"-rpcconnect=<ip>\", strprintf(_(\"Send commands to node running on <ip> (default: %s)\"), DEFAULT_RPCCONNECT));\n    strUsage += HelpMessageOpt(\"-rpcport=<port>\", strprintf(_(\"Connect to JSON-RPC on <port> (default: %u or testnet: %u)\"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));\n    strUsage += HelpMessageOpt(\"-rpcwait\", _(\"Wait for RPC server to start\"));\n    strUsage += HelpMessageOpt(\"-rpcuser=<user>\", _(\"Username for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcpassword=<pw>\", _(\"Password for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcclienttimeout=<n>\", strprintf(_(\"Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)\"), DEFAULT_HTTP_CLIENT_TIMEOUT));\n    strUsage += HelpMessageOpt(\"-stdin\", _(\"Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)\"));\n\n    return strUsage;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Start\n//\n\n//\n// Exception thrown on connection error.  This error is used to determine\n// when to wait if -rpcwait is given.\n//\nclass CConnectionFailed : public std::runtime_error\n{\npublic:\n\n    explicit inline CConnectionFailed(const std::string& msg) :\n        std::runtime_error(msg)\n    {}\n\n};\n\n//\n// This function returns either one of EXIT_ codes when it's expected to stop the process or\n// CONTINUE_EXECUTION when it's expected to continue further.\n//\nstatic int AppInitRPC(int argc, char* argv[])\n{\n    //\n    // Parameters\n    //\n    ParseParameters(argc, argv);\n    if (argc<2 || IsArgSet(\"-?\") || IsArgSet(\"-h\") || IsArgSet(\"-help\") || IsArgSet(\"-version\")) {\n        std::string strUsage = strprintf(_(\"%s RPC client version\"), _(PACKAGE_NAME)) + \" \" + FormatFullVersion() + \"\\n\";\n        if (!IsArgSet(\"-version\")) {\n            strUsage += \"\\n\" + _(\"Usage:\") + \"\\n\" +\n                  \"  \" CLI_NAME \" [options] <command> [params]  \" + strprintf(_(\"Send command to %s\"), _(PACKAGE_NAME)) + \"\\n\" +\n                  \"  \" CLI_NAME \" [options] -named <command> [name=value] ... \" + strprintf(_(\"Send command to %s (with named arguments)\"), _(PACKAGE_NAME)) + \"\\n\" +\n                  \"  \" CLI_NAME \" [options] help                \" + _(\"List commands\") + \"\\n\" +\n                  \"  \" CLI_NAME \" [options] help <command>      \" + _(\"Get help for a command\") + \"\\n\";\n\n            strUsage += \"\\n\" + HelpMessageCli();\n        }\n\n        fprintf(stdout, \"%s\", strUsage.c_str());\n        if (argc < 2) {\n            fprintf(stderr, \"Error: too few parameters\\n\");\n            return EXIT_FAILURE;\n        }\n        return EXIT_SUCCESS;\n    }\n    if (!fs::is_directory(GetDataDir(false))) {\n        fprintf(stderr, \"Error: Specified data directory \\\"%s\\\" does not exist.\\n\", GetArg(\"-datadir\", \"\").c_str());\n        return EXIT_FAILURE;\n    }\n    try {\n        ReadConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME));\n    } catch (const std::exception& e) {\n        fprintf(stderr,\"Error reading configuration file: %s\\n\", e.what());\n        return EXIT_FAILURE;\n    }\n    // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)\n    try {\n        SelectBaseParams(ChainNameFromCommandLine());\n    } catch (const std::exception& e) {\n        fprintf(stderr, \"Error: %s\\n\", e.what());\n        return EXIT_FAILURE;\n    }\n    if (GetBoolArg(\"-rpcssl\", false))\n    {\n        fprintf(stderr, \"Error: SSL mode for RPC (-rpcssl) is no longer supported.\\n\");\n        return EXIT_FAILURE;\n    }\n    return CONTINUE_EXECUTION;\n}\n\n\n/** Reply structure for request_done to fill in */\nstruct HTTPReply\n{\n    HTTPReply(): status(0), error(-1) {}\n\n    int status;\n    int error;\n    std::string body;\n};\n\nconst char *http_errorstring(int code)\n{\n    switch(code) {\n#if LIBEVENT_VERSION_NUMBER >= 0x02010300\n    case EVREQ_HTTP_TIMEOUT:\n        return \"timeout reached\";\n    case EVREQ_HTTP_EOF:\n        return \"EOF reached\";\n    case EVREQ_HTTP_INVALID_HEADER:\n        return \"error while reading header, or invalid header\";\n    case EVREQ_HTTP_BUFFER_ERROR:\n        return \"error encountered while reading or writing\";\n    case EVREQ_HTTP_REQUEST_CANCEL:\n        return \"request was canceled\";\n    case EVREQ_HTTP_DATA_TOO_LONG:\n        return \"response body is larger than allowed\";\n#endif\n    default:\n        return \"unknown\";\n    }\n}\n\nstatic void http_request_done(struct evhttp_request *req, void *ctx)\n{\n    HTTPReply *reply = static_cast<HTTPReply*>(ctx);\n\n    if (req == NULL) {\n        /* If req is NULL, it means an error occurred while connecting: the\n         * error code will have been passed to http_error_cb.\n         */\n        reply->status = 0;\n        return;\n    }\n\n    reply->status = evhttp_request_get_response_code(req);\n\n    struct evbuffer *buf = evhttp_request_get_input_buffer(req);\n    if (buf)\n    {\n        size_t size = evbuffer_get_length(buf);\n        const char *data = (const char*)evbuffer_pullup(buf, size);\n        if (data)\n            reply->body = std::string(data, size);\n        evbuffer_drain(buf, size);\n    }\n}\n\n#if LIBEVENT_VERSION_NUMBER >= 0x02010300\nstatic void http_error_cb(enum evhttp_request_error err, void *ctx)\n{\n    HTTPReply *reply = static_cast<HTTPReply*>(ctx);\n    reply->error = err;\n}\n#endif\n\nUniValue CallRPC(const std::string& strMethod, const UniValue& params)\n{\n    std::string host = GetArg(\"-rpcconnect\", DEFAULT_RPCCONNECT);\n    int port = GetArg(\"-rpcport\", BaseParams().RPCPort());\n\n    // Obtain event base\n    raii_event_base base = obtain_event_base();\n\n    // Synchronously look up hostname\n    raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);\n    evhttp_connection_set_timeout(evcon.get(), GetArg(\"-rpcclienttimeout\", DEFAULT_HTTP_CLIENT_TIMEOUT));\n\n    HTTPReply response;\n    raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);\n    if (req == NULL)\n        throw std::runtime_error(\"create http request failed\");\n#if LIBEVENT_VERSION_NUMBER >= 0x02010300\n    evhttp_request_set_error_cb(req.get(), http_error_cb);\n#endif\n\n    // Get credentials\n    std::string strRPCUserColonPass;\n    if (GetArg(\"-rpcpassword\", \"\") == \"\") {\n        // Try fall back to cookie-based authentication if no password is provided\n        if (!GetAuthCookie(&strRPCUserColonPass)) {\n            throw std::runtime_error(strprintf(\n                _(\"Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)\"),\n                    GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)).string().c_str()));\n\n        }\n    } else {\n        strRPCUserColonPass = GetArg(\"-rpcuser\", \"\") + \":\" + GetArg(\"-rpcpassword\", \"\");\n    }\n\n    struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());\n    assert(output_headers);\n    evhttp_add_header(output_headers, \"Host\", host.c_str());\n    evhttp_add_header(output_headers, \"Connection\", \"close\");\n    evhttp_add_header(output_headers, \"Authorization\", (std::string(\"Basic \") + EncodeBase64(strRPCUserColonPass)).c_str());\n\n    // Attach request data\n    std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + \"\\n\";\n    struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());\n    assert(output_buffer);\n    evbuffer_add(output_buffer, strRequest.data(), strRequest.size());\n\n    int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, \"/\");\n    req.release(); // ownership moved to evcon in above call\n    if (r != 0) {\n        throw CConnectionFailed(\"send http request failed\");\n    }\n\n    event_base_dispatch(base.get());\n\n    if (response.status == 0)\n        throw CConnectionFailed(strprintf(\"couldn't connect to server: %s (code %d)\\n(make sure server is running and you are connecting to the correct RPC port)\", http_errorstring(response.error), response.error));\n    else if (response.status == HTTP_UNAUTHORIZED)\n        throw std::runtime_error(\"incorrect rpcuser or rpcpassword (authorization failed)\");\n    else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)\n        throw std::runtime_error(strprintf(\"server returned HTTP error %d\", response.status));\n    else if (response.body.empty())\n        throw std::runtime_error(\"no response from server\");\n\n    // Parse reply\n    UniValue valReply(UniValue::VSTR);\n    if (!valReply.read(response.body))\n        throw std::runtime_error(\"couldn't parse reply from server\");\n    const UniValue& reply = valReply.get_obj();\n    if (reply.empty())\n        throw std::runtime_error(\"expected reply to have result, error and id properties\");\n\n    return reply;\n}\n\nint CommandLineRPC(int argc, char *argv[])\n{\n    std::string strPrint;\n    int nRet = 0;\n    try {\n        // Skip switches\n        while (argc > 1 && IsSwitchChar(argv[1][0])) {\n            argc--;\n            argv++;\n        }\n        std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);\n        if (GetBoolArg(\"-stdin\", false)) {\n            // Read one arg per line from stdin and append\n            std::string line;\n            while (std::getline(std::cin,line))\n                args.push_back(line);\n        }\n        if (args.size() < 1)\n            throw std::runtime_error(\"too few parameters (need at least command)\");\n        std::string strMethod = args[0];\n        args.erase(args.begin()); // Remove trailing method name from arguments vector\n\n        UniValue params;\n        if(GetBoolArg(\"-named\", DEFAULT_NAMED)) {\n            params = RPCConvertNamedValues(strMethod, args);\n        } else {\n            params = RPCConvertValues(strMethod, args);\n        }\n\n        // Execute and handle connection failures with -rpcwait\n        const bool fWait = GetBoolArg(\"-rpcwait\", false);\n        do {\n            try {\n                const UniValue reply = CallRPC(strMethod, params);\n\n                // Parse reply\n                const UniValue& result = find_value(reply, \"result\");\n                const UniValue& error  = find_value(reply, \"error\");\n\n                if (!error.isNull()) {\n                    // Error\n                    int code = error[\"code\"].get_int();\n                    if (fWait && code == RPC_IN_WARMUP)\n                        throw CConnectionFailed(\"server in warmup\");\n                    strPrint = \"error: \" + error.write();\n                    nRet = abs(code);\n                    if (error.isObject())\n                    {\n                        UniValue errCode = find_value(error, \"code\");\n                        UniValue errMsg  = find_value(error, \"message\");\n                        strPrint = errCode.isNull() ? \"\" : \"error code: \"+errCode.getValStr()+\"\\n\";\n\n                        if (errMsg.isStr())\n                            strPrint += \"error message:\\n\"+errMsg.get_str();\n                    }\n                } else {\n                    // Result\n                    if (result.isNull())\n                        strPrint = \"\";\n                    else if (result.isStr())\n                        strPrint = result.get_str();\n                    else\n                        strPrint = result.write(2);\n                }\n                // Connection succeeded, no need to retry.\n                break;\n            }\n            catch (const CConnectionFailed&) {\n                if (fWait)\n                    MilliSleep(1000);\n                else\n                    throw;\n            }\n        } while (fWait);\n    }\n    catch (const boost::thread_interrupted&) {\n        throw;\n    }\n    catch (const std::exception& e) {\n        strPrint = std::string(\"error: \") + e.what();\n        nRet = EXIT_FAILURE;\n    }\n    catch (...) {\n        PrintExceptionContinue(NULL, \"CommandLineRPC()\");\n        throw;\n    }\n\n    if (strPrint != \"\") {\n        fprintf((nRet == 0 ? stdout : stderr), \"%s\\n\", strPrint.c_str());\n    }\n    return nRet;\n}\n\nint main(int argc, char* argv[])\n{\n    SetupEnvironment();\n    if (!SetupNetworking()) {\n        fprintf(stderr, \"Error: Initializing networking failed\\n\");\n        return EXIT_FAILURE;\n    }\n\n    try {\n        int ret = AppInitRPC(argc, argv);\n        if (ret != CONTINUE_EXECUTION)\n            return ret;\n    }\n    catch (const std::exception& e) {\n        PrintExceptionContinue(&e, \"AppInitRPC()\");\n        return EXIT_FAILURE;\n    } catch (...) {\n        PrintExceptionContinue(NULL, \"AppInitRPC()\");\n        return EXIT_FAILURE;\n    }\n\n    int ret = EXIT_FAILURE;\n    try {\n        ret = CommandLineRPC(argc, argv);\n    }\n    catch (const std::exception& e) {\n        PrintExceptionContinue(&e, \"CommandLineRPC()\");\n    } catch (...) {\n        PrintExceptionContinue(NULL, \"CommandLineRPC()\");\n    }\n    return ret;\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/cli-res.rc",
    "content": "#include <windows.h>             // needed for VERSIONINFO\n#include \"clientversion.h\"       // holds the needed client version information\n#include \"appname.h\"\n\n#define VER_PRODUCTVERSION     CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD\n#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) \".\" STRINGIZE(CLIENT_VERSION_MINOR) \".\" STRINGIZE(CLIENT_VERSION_REVISION) \".\" STRINGIZE(CLIENT_VERSION_BUILD)\n#define VER_FILEVERSION        VER_PRODUCTVERSION\n#define VER_FILEVERSION_STR    VER_PRODUCTVERSION_STR\n\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION     VER_FILEVERSION\nPRODUCTVERSION  VER_PRODUCTVERSION\nFILEOS          VOS_NT_WINDOWS32\nFILETYPE        VFT_APP\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\" // U.S. English - multilingual (hex)\n        BEGIN\n            VALUE \"CompanyName\",        GLOBAL_APPNAME\"\"\n            VALUE \"FileDescription\",    GLOBAL_APPNAME\"-cli (JSON-RPC client for \" PACKAGE_NAME \")\"\n            VALUE \"FileVersion\",        VER_FILEVERSION_STR\n            VALUE \"InternalName\",       GLOBAL_APPNAME\"-cli\"\n            VALUE \"LegalCopyright\",     COPYRIGHT_STR\n            VALUE \"LegalTrademarks1\",   \"Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING or github.com/muntorg/munt-official/COPYING\"\n            VALUE \"OriginalFilename\",   GLOBAL_APPNAME\"-cli.exe\"\n            VALUE \"ProductName\",        GLOBAL_APPNAME\"-cli\"\n            VALUE \"ProductVersion\",     VER_PRODUCTVERSION_STR\n        END\n    END\n\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0, 1252 // language neutral - multilingual (decimal)\n    END\nEND\n"
  },
  {
    "path": "src/clientversion.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"clientversion.h\"\n#include \"tinyformat.h\"\n\n#include <string>\n\n/**\n * Name of client reported in the 'version' message. Report the same name\n * for all apps, to make it harder for attackers to\n * target servers or GUI users specifically.\n */\nconst std::string CLIENT_NAME(\"Munt\");\n\n/**\n * Client version number\n */\n#define CLIENT_VERSION_SUFFIX \"\"\n\n\n/**\n * The following part of the code determines the CLIENT_BUILD variable.\n * Several mechanisms are used for this:\n * * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is\n *   generated by the build environment, possibly containing the output\n *   of git-describe in a macro called BUILD_DESC\n * * secondly, if this is an exported version of the code, GIT_ARCHIVE will\n *   be defined (automatically using the export-subst git attribute), and\n *   GIT_COMMIT will contain the commit id.\n * * then, three options exist for determining CLIENT_BUILD:\n *   * if BUILD_DESC is defined, use that literally (output of git-describe)\n *   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]\n *   * otherwise, use v[maj].[min].[rev].[build]-unk\n * finally CLIENT_VERSION_SUFFIX is added\n */\n\n//! First, include build.h if requested\n#ifdef HAVE_BUILD_INFO\n#include \"build.h\"\n#endif\n\n//! git will put \"#define GIT_ARCHIVE 1\" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$\n#ifdef GIT_ARCHIVE\n#define GIT_COMMIT_ID \"$Format:%h$\"\n#define GIT_COMMIT_DATE \"$Format:%cD$\"\n#endif\n\n#define BUILD_DESC_WITH_SUFFIX4(maj, min, rev, build, suffix) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(rev) \".\" DO_STRINGIZE(build) \"-\" DO_STRINGIZE(suffix)\n\n#define BUILD_DESC_FROM_COMMIT4(maj, min, rev, build, commit) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(rev) \".\" DO_STRINGIZE(build) \"-g\" commit\n\n#define BUILD_DESC_FROM_UNKNOWN4(maj, min, rev, build) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(rev) \".\" DO_STRINGIZE(build) \"-unk\"\n    \n#define BUILD_DESC_WITH_SUFFIX3(maj, min, build, suffix) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(build) \"-\" DO_STRINGIZE(suffix)\n\n#define BUILD_DESC_FROM_COMMIT3(maj, min, build, commit) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(build) \"-g\" commit\n\n#define BUILD_DESC_FROM_UNKNOWN3(maj, min, build) \\\n    \"v\" DO_STRINGIZE(maj) \".\" DO_STRINGIZE(min) \".\" DO_STRINGIZE(build) \"-unk\"\n\n#ifndef BUILD_DESC\n#ifdef BUILD_SUFFIX\n#define BUILD_DESC BUILD_DESC_WITH_SUFFIX4(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, BUILD_SUFFIX)\n#define BUILD_DESC_ABBREVIATED BUILD_DESC_WITH_SUFFIX3(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_BUILD, BUILD_SUFFIX)\n#elif defined(GIT_COMMIT_ID)\n#define BUILD_DESC BUILD_DESC_FROM_COMMIT4(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)\n#define BUILD_DESC_ABBREVIATED BUILD_DESC_FROM_COMMIT3(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)\n#else\n#define BUILD_DESC BUILD_DESC_FROM_UNKNOWN4(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)\n#define BUILD_DESC_ABBREVIATED BUILD_DESC_FROM_UNKNOWN3(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_BUILD)\n#endif\n#else\n#define BUILD_DESC_ABBREVIATED BUILD_DESC\n#endif\n\nconst std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);\nconst std::string CLIENT_BUILD_ABBREVIATED(BUILD_DESC_ABBREVIATED CLIENT_VERSION_SUFFIX);\n\nstatic std::string FormatVersion(int nVersion)\n{\n    if (nVersion % 100 == 0)\n        return strprintf(\"%d.%d.%d\", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100);\n    else\n        return strprintf(\"%d.%d.%d.%d\", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100);\n}\n\nstd::string FormatFullVersion()\n{\n    return CLIENT_BUILD;\n}\n\nstd::string FormatThreeDigitVersion()\n{\n    return CLIENT_BUILD_ABBREVIATED;\n}\n\n/** \n * Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) \n */\nstd::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)\n{\n    std::ostringstream ss;\n    ss << \"/\";\n    ss << name << \":\" << FormatVersion(nClientVersion);\n    if (!comments.empty())\n    {\n        std::vector<std::string>::const_iterator it(comments.begin());\n        ss << \"(\" << *it;\n        for(++it; it != comments.end(); ++it)\n            ss << \"; \" << *it;\n        ss << \")\";\n    }\n    ss << \"/\";\n    return ss.str();\n}\n\nstd::string UserAgent()\n{\n    return FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>());;\n}\n\nstd::string Version()\n{\n    return FormatVersion(CLIENT_VERSION);\n}\n"
  },
  {
    "path": "src/clientversion.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CLIENTVERSION_H\n#define CLIENTVERSION_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif //HAVE_CONFIG_H\n\n#include <util/macros.h>\n\n// Check that required client information is defined\n#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_REVISION) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR)\n#error Client version information missing: version is not defined by build-config.h or in any other way\n#endif\n\n\n//! Copyright string used in Windows .rc files\n#define COPYRIGHT_STR \"2009-\" STRINGIZE(COPYRIGHT_YEAR) \" \" COPYRIGHT_HOLDERS_FINAL\n\n/**\n * A .rc includes this file, but it cannot cope with real c++ code.\n * WINDRES_PREPROC is defined to indicate that its pre-processor is running.\n * Anything other than a define should be guarded below.\n */\n\n#if !defined(WINDRES_PREPROC)\n\n#include <string>\n#include <vector>\n\nstatic const int CLIENT_VERSION =\n                           1000000 * CLIENT_VERSION_MAJOR\n                         +   10000 * CLIENT_VERSION_MINOR\n                         +     100 * CLIENT_VERSION_REVISION\n                         +       1 * CLIENT_VERSION_BUILD;\n\nextern const std::string CLIENT_NAME;\nextern const std::string CLIENT_BUILD;\nextern const std::string CLIENT_BUILD_ABBREVIATED;\n\n\nstd::string FormatFullVersion();\nstd::string FormatThreeDigitVersion();\nstd::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);\nstd::string UserAgent();\nstd::string Version();\n\n#endif // WINDRES_PREPROC\n\n#endif\n"
  },
  {
    "path": "src/coins.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"coins.h\"\n\n#include \"consensus/consensus.h\"\n#include \"memusage.h\"\n#include \"random.h\"\n\n#include <assert.h>\n\n#include \"txmempool.h\"\n\n#include \"witnessutil.h\"\n\n#include <alert.h>\n#include \"ui_interface.h\"\n\nbool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet) const { return false; }\nbool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }\nuint256 CCoinsView::GetBestBlock() const { return uint256(); }\nbool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }\nCCoinsViewCursor *CCoinsView::Cursor() const { return 0; }\n\n\nCCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }\nbool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet) const { return base->GetCoin(outpoint, coin, pOutpointRet); }\nbool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }\nuint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }\nvoid CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }\nbool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }\nCCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }\nsize_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }\n\nSaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}\n\nCCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn)\n: CCoinsViewBacked(baseIn)\n, cachedCoinsUsage(0)\n, pChainedWitView(nullptr)\n{}\n\nCCoinsViewCache::CCoinsViewCache(CCoinsViewCache *baseIn)\n: CCoinsViewBacked(baseIn)\n, cachedCoinsUsage(0)\n, pChainedWitView(baseIn->pChainedWitView?std::shared_ptr<CCoinsViewCache>(new CCoinsViewCache(baseIn->pChainedWitView.get())):nullptr)\n{}\n\nsize_t CCoinsViewCache::DynamicMemoryUsage() const\n{\n    return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;\n}\n\n\n#if defined(DEBUG) && !defined(PLATFORM_MOBILE)\nvoid CCoinsViewCache::validateInsert(const COutPoint &outpoint, uint64_t block, uint64_t txIndex, uint32_t voutIndex) const\n{\n    // check args\n    assert(outpoint.isHash || (outpoint.getTransactionBlockNumber() == block && outpoint.getTransactionIndex() == txIndex));\n    assert(outpoint.n == voutIndex);\n\n    // cacheCoins and cacheCoinRefs keep a 1:1 correspondence, so any difference in size is a bug for sure\n    // Sadly not quite true:\n    // 1) cacheCoins may contain a dirty entry and a live entry both of which correspond to the same cacheCoinRefs (e.g. reorganisation)\n    // 2) mempool entries don't have a block height (so aren't in cacheCoinRefs), so we track those as 'cacheMempoolRefs' counter and compensate\n    /*if (cacheCoins.size() != cacheCoinRefs.size()+cacheMempoolRefs)\n    {\n        uint64_t nNotSpentCacheCoinsCount = 0;\n        for (const auto& it : cacheCoins)\n        {\n            if (!(it.second.flags&CCoinsCacheEntry::DIRTY && it.second.coin.IsSpent()))\n            {\n                ++nNotSpentCacheCoinsCount;\n            }\n        }\n        assert(nNotSpentCacheCoinsCount == cacheCoinRefs.size()+cacheMempoolRefs);\n    }*/\n\n    CCoinsRefMap::iterator refIt = cacheCoinRefs.find(outpoint.isHash ? COutPoint(block, txIndex, voutIndex) : outpoint);\n    \n    // Mempool entries should never be present in cacheCoinRefs (they have no block height)\n    if (block == MEMPOOL_HEIGHT && txIndex == MEMPOOL_INDEX)\n    {\n        assert(outpoint.isHash);\n        assert(refIt == cacheCoinRefs.end());        \n    }\n    else\n    {    \n        if (refIt != cacheCoinRefs.end())\n        {\n            // entry present in cacheCoinRefs\n            const COutPoint& canonicalOutPoint = refIt->second;\n            CCoinsMap::iterator it = cacheCoins.find(canonicalOutPoint);\n            assert(it != cacheCoins.end());  // verify it is present in cacheCoins as well\n            const Coin& coin = it->second.coin;\n\n            // if canonicalOutPoint is not a hash then something is very wrong\n            assert(canonicalOutPoint.isHash);\n            \n            // If the two don't share an identical transaction hash something is very wrong\n            bool transactionHashesMatch = canonicalOutPoint.getTransactionHash() == outpoint.getTransactionHash();\n            // Unless the other one is spent and marked dirty, in which case thats fine\n            if (!transactionHashesMatch && !(it->second.flags&CCoinsCacheEntry::DIRTY&&it->second.coin.IsSpent()))\n            {\n                std::string warning = strprintf(\"Warning: outpoint mismatch.\\nPlease notify the developers with this information to assist them.\\n\\n\"\n                                                \"cohash:[%s]\\nophash:[%s]\\nblock:[%d] txidx:[%d] outidx:[%d] flags:[%d] spent:[%s] lookupishash: [%s]\",\n                                                canonicalOutPoint.getTransactionHash().ToString(), outpoint.getTransactionHash().ToString(), \n                                                block, txIndex, voutIndex, it->second.flags, (it->second.coin.IsSpent()?\"yes\":\"no\"), (outpoint.isHash?\"yes\":\"no\"));\n                throw std::logic_error(warning);\n            }\n            \n            // Block and index should match up\n            assert(coin.nHeight == block);\n            assert(coin.nTxIndex == txIndex);\n            assert(canonicalOutPoint.n == voutIndex);\n        }\n        else\n        {\n            // no entry in cacheCoinRefs, so it should be absent in cacheCoins also\n            // This assumption is not necessarily true if it was previously in mempool - so has been disabled for now\n            #if 0\n            if (outpoint.isHash)\n            {\n                if (cacheCoins.find(outpoint) != cacheCoins.end())\n                {\n                    CCoinsMap::iterator it = cacheCoins.find(outpoint);\n                    std::string warning = strprintf(\"Warning: outpoint mismatch.\\nPlease notify the developers with this information to assist them.\\n\\n\"\n                                                \"ophash:[%s]\\nblock:[%d] txidx:[%d] outidx:[%d] flags:[%d] spent:[%s] lookupishash: [%s]\",\n                                                outpoint.getTransactionHash().ToString(), \n                                                block, txIndex, voutIndex, it->second.flags, (it->second.coin.IsSpent()?\"yes\":\"no\"), (outpoint.isHash?\"yes\":\"no\"));\n                    uiInterface.NotifyUIAlertChanged(warning);\n                }\n            }\n            #endif\n            // The non-hash output definitely shouldn't be in the cacheCoins ever\n            assert(outpoint.isHash || cacheCoins.find(COutPoint(block, txIndex, voutIndex)) == cacheCoins.end());\n        }\n    }\n}\n#endif\n\nCCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint, CCoinsRefMap::iterator* pRefIterReturn) const\n{\n    // lookup outpoint in either map and return iterators to both maps for it\n    if (outpoint.isHash)\n    {\n        CCoinsMap::iterator coinIter = cacheCoins.find(outpoint);\n        if (coinIter != cacheCoins.end())\n        {\n            if (pRefIterReturn)\n            {\n                if (coinIter->second.coin.nHeight == MEMPOOL_HEIGHT && coinIter->second.coin.nTxIndex == MEMPOOL_INDEX)\n                {\n                    *pRefIterReturn = cacheCoinRefs.end();\n                }\n                else\n                {\n                    *pRefIterReturn = cacheCoinRefs.find(COutPoint(coinIter->second.coin.nHeight, coinIter->second.coin.nTxIndex, outpoint.n));\n                    assert(*pRefIterReturn != cacheCoinRefs.end());\n                }\n            }\n            return coinIter;\n        }\n    }\n    else\n    {\n        assert(!(outpoint.getTransactionBlockNumber() == MEMPOOL_HEIGHT && outpoint.getTransactionIndex() == MEMPOOL_INDEX));\n        CCoinsRefMap::iterator refIter = cacheCoinRefs.find(outpoint);\n        if (refIter != cacheCoinRefs.end())\n        {\n            auto coinIter = cacheCoins.find(refIter->second);\n            assert(coinIter != cacheCoins.end());\n            if (pRefIterReturn)\n                *pRefIterReturn = refIter;\n            return coinIter;\n        }\n    }\n\n    // if outpoint not found, lookup in base view\n    Coin tmp;\n    COutPoint insertOutpoint(outpoint);\n    if (!base->GetCoin(outpoint, tmp, &insertOutpoint))\n        return cacheCoins.end();\n    \n    // Never directly insert non-hash outpoints\n    assert(insertOutpoint.isHash);\n\n    // Ensure consistency\n    validateInsert(insertOutpoint, tmp.nHeight, tmp.nTxIndex, outpoint.n);\n\n    // have it in base view, auto-create copy in the cache   \n    if (tmp.nHeight == MEMPOOL_HEIGHT && tmp.nTxIndex == MEMPOOL_INDEX)\n    {\n        if (pRefIterReturn)\n            *pRefIterReturn = cacheCoinRefs.end();\n            \n    }\n    else\n    {\n        cacheCoinRefs[(COutPoint(tmp.nHeight, tmp.nTxIndex, insertOutpoint.n))] = insertOutpoint;\n        if (pRefIterReturn)\n        {\n            *pRefIterReturn = cacheCoinRefs.find(COutPoint(tmp.nHeight, tmp.nTxIndex, insertOutpoint.n));\n        }\n    }\n    auto retIter = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(insertOutpoint), std::forward_as_tuple(std::move(tmp))).first;\n    \n    \n    // If the parent only has an empty entry for this outpoint; we can consider our version as fresh.\n    if (retIter->second.coin.IsSpent())\n    {\n        retIter->second.flags = CCoinsCacheEntry::FRESH;\n    }\n    cachedCoinsUsage += retIter->second.coin.DynamicMemoryUsage();\n    return retIter;\n}\n\nbool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet) const\n{\n    CCoinsMap::const_iterator it = FetchCoin(outpoint);\n    if (it != cacheCoins.end())\n    {\n        if (pOutpointRet)\n            *pOutpointRet = it->first;\n        coin = it->second.coin;\n        return true;\n    }\n    return false;\n}\n\nvoid CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite)\n{\n    if (pChainedWitView)\n    {\n        if ( IsPow2WitnessOutput(coin.out) )\n        {\n            pChainedWitView->AddCoin(outpoint, Coin(coin.out, coin.nHeight, coin.nTxIndex, coin.fCoinBase, coin.fSegSig), possible_overwrite);\n        }\n    }\n\n    assert(!coin.IsSpent());\n    if (coin.out.IsUnspendable())\n    {\n        return;\n    }\n    \n    // Never directly insert non-hash outpoints\n    assert(outpoint.isHash);\n\n    // Ensure consistency\n    validateInsert(outpoint, coin.nHeight, coin.nTxIndex, outpoint.n);\n\n    // If there is already an existing entry the indexed outpoint map needs to be kept in sync\n    if (cacheCoins.count(outpoint) > 0)\n    {\n        auto coin_entry = cacheCoins[outpoint];\n        auto refIter = cacheCoinRefs.find(COutPoint(coin_entry.coin.nHeight, coin_entry.coin.nTxIndex, outpoint.n));\n\n        // If the existing indexed outpoint is associated with this coin_entry the old entry is erased so there\n        // will be no stale entry left if its index changes\n        if (refIter != cacheCoinRefs.end() && refIter->second.getTransactionHash() == outpoint.getTransactionHash())\n        {\n            cacheCoinRefs.erase(refIter);\n        }\n    }\n\n    if (!(coin.nHeight == MEMPOOL_HEIGHT && coin.nTxIndex == MEMPOOL_INDEX))\n    {\n        cacheCoinRefs[(COutPoint(coin.nHeight, coin.nTxIndex, outpoint.n))] = outpoint;\n    }\n    auto [coinIter, inserted] = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());\n    \n    bool fresh = false;\n    if (!inserted)\n    {\n        cachedCoinsUsage -= coinIter->second.coin.DynamicMemoryUsage();\n    }\n    if (!possible_overwrite)\n    {\n        if (!coinIter->second.coin.IsSpent())\n        {\n            throw std::logic_error(\"Adding new coin that replaces non-pruned entry\");\n        }\n        fresh = !(coinIter->second.flags & CCoinsCacheEntry::DIRTY);\n    }\n    coinIter->second.coin = std::move(coin);\n    coinIter->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);\n    cachedCoinsUsage += coinIter->second.coin.DynamicMemoryUsage();\n}\n\nvoid AddCoins(CCoinsViewCache& cache, const CTransaction &tx, uint32_t nHeight, uint32_t nTxIndex)\n{\n    bool fCoinbase = tx.IsCoinBase();\n    const uint256& txid = tx.GetHash();\n    for (size_t i = 0; i < tx.vout.size(); ++i)\n    {\n        // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly\n        // deal with the pre-BIP30 occurrences of duplicate coinbase transactions.\n        cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, nTxIndex, fCoinbase, !IsOldTransactionVersion(tx.nVersion)), fCoinbase);\n    }\n}\n\nvoid CCoinsViewCache::SpendCoin(const COutPoint &outpoint, CoinUndo* moveout, bool nodeletefresh)\n{\n    if (pChainedWitView)\n    {\n        // NB! The below is essential for the operation of GetWitness function, otherwise it returns unpredictable and incorrect results.\n        // For chained view we force everything to 'dirty' because we need to know about fresh coins that have been removed and can't just erase them.\n        pChainedWitView->SpendCoin(outpoint, NULL, true);\n    }\n\n    CCoinsRefMap::iterator coinRefIter;\n    CCoinsMap::iterator coinIter = FetchCoin(outpoint, &coinRefIter);\n    if (coinIter == cacheCoins.end())\n    {\n        return;\n    }\n    if (!(coinIter->second.coin.nHeight == MEMPOOL_HEIGHT && coinIter->second.coin.nTxIndex == MEMPOOL_INDEX))\n    {\n        assert(coinRefIter != cacheCoinRefs.end());\n    }\n    cachedCoinsUsage -= coinIter->second.coin.DynamicMemoryUsage();\n    if (moveout)\n    {\n        *moveout = CoinUndo(std::move(coinIter->second.coin), coinIter->first.getTransactionHash());\n    }\n    if (!nodeletefresh && coinIter->second.flags & CCoinsCacheEntry::FRESH)\n    {\n        if (coinRefIter != cacheCoinRefs.end())\n        {\n            if ((!outpoint.isHash) || coinRefIter->second == outpoint)\n            {\n                cacheCoinRefs.erase(coinRefIter);\n            }\n        }\n        cacheCoins.erase(coinIter);\n    }\n    else\n    {\n        coinIter->second.flags |= CCoinsCacheEntry::DIRTY;\n        coinIter->second.coin.Spend();\n    }\n}\n\nstatic const Coin coinEmpty;\n\nconst Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const\n{\n    CCoinsMap::const_iterator it = FetchCoin(outpoint);\n    if (it == cacheCoins.end())\n    {\n        return coinEmpty;\n    }\n    else\n    {\n        return it->second.coin;\n    }\n}\n\nbool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const\n{\n    CCoinsMap::const_iterator it = FetchCoin(outpoint);\n    return (it != cacheCoins.end() && !it->second.coin.IsSpent());\n}\n\nbool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const\n{\n    CCoinsMap::const_iterator it = cacheCoins.find(outpoint);\n    return it != cacheCoins.end();\n}\n\nuint256 CCoinsViewCache::GetBestBlock() const\n{\n    if (hashBlock.IsNull())\n        hashBlock = base->GetBestBlock();\n    return hashBlock;\n}\n\nvoid CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn)\n{\n    hashBlock = hashBlockIn;\n}\n\nbool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn)\n{\n    // It is possible (in fact likely) for the same batch to be both erasing and writing the same entryref e.g. if swapping one block 1963 for a competing block 1963\n    // mapCoins is 'randomly' ordered so doing this would create random behaviour and an inconsistent coin database\n    // To overcome this we erase first always, and then pool up the inserts to do at the end, where we must still carefully order the inserts as well\n    std::vector<COutPoint> modificationMap;\n    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();)\n    {\n        // Ignore non-dirty entries (optimization).\n        if (it->second.flags & CCoinsCacheEntry::DIRTY)\n        {\n            CCoinsMap::iterator itUs = cacheCoins.find(it->first);\n            if (itUs == cacheCoins.end())\n            {\n                // The parent cache does not have an entry, while the child does\n                // We can ignore it if it's both FRESH and pruned in the child\n                if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent()))\n                {\n                    // Otherwise we will need to create it in the parent\n                    // and move the data up and mark it as dirty\n                    CCoinsCacheEntry& entry = cacheCoins[it->first];\n                    entry.coin = std::move(it->second.coin);\n                    cachedCoinsUsage += entry.coin.DynamicMemoryUsage();\n                    entry.flags = CCoinsCacheEntry::DIRTY;\n                    // We can mark it FRESH in the parent if it was FRESH in the child\n                    // Otherwise it might have just been flushed from the parent's cache\n                    // and already exist in the grandparent\n                    if (it->second.flags & CCoinsCacheEntry::FRESH)\n                    {\n                        entry.flags |= CCoinsCacheEntry::FRESH;\n                    }\n                    if (!(entry.coin.nHeight == MEMPOOL_HEIGHT && entry.coin.nTxIndex == MEMPOOL_INDEX))\n                    {\n                        modificationMap.push_back(it->first);\n                    }\n                }\n            }\n            else\n            {\n                // Assert that the child cache entry was not marked FRESH if the\n                // parent cache entry has unspent outputs. If this ever happens,\n                // it means the FRESH flag was misapplied and there is a logic\n                // error in the calling code.\n                if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())\n                {\n                    throw std::logic_error(\"FRESH flag misapplied to cache entry for base transaction with spendable outputs\");\n                }\n\n                // Found the entry in the parent cache\n                if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent())\n                {\n                    // The grandparent does not have an entry, and the child is\n                    // modified and being pruned. This means we can just delete\n                    // it from the parent.\n                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();\n                    if (!(itUs->second.coin.nHeight == MEMPOOL_HEIGHT && itUs->second.coin.nTxIndex == MEMPOOL_INDEX))\n                    {\n                        // delete index, but only if it correspends\n                        if (itUs->second.coin.nHeight == it->second.coin.nHeight\n                            && itUs->second.coin.nTxIndex == it->second.coin.nTxIndex\n                            && itUs->first.n == it->first.n)\n                        {\n                            cacheCoinRefs.erase(COutPoint(itUs->second.coin.nHeight, itUs->second.coin.nTxIndex, itUs->first.n));\n                        }\n                    }\n                    cacheCoins.erase(itUs);\n                }\n                else\n                {\n                    // if there is already an indexed entry that is ours then delete it as we might be moving to another index\n                    // if it is not ours then leave it\n                    auto indexed = COutPoint(itUs->second.coin.nHeight, itUs->second.coin.nTxIndex, itUs->first.n);\n                    if (cacheCoinRefs[indexed].getTransactionHash() == it->first.getTransactionHash())\n                    {\n                        cacheCoinRefs.erase(indexed);\n                    }\n\n                    // A normal modification.\n                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();\n                    itUs->second.coin = std::move(it->second.coin);\n                    cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();\n                    itUs->second.flags |= CCoinsCacheEntry::DIRTY;\n\n                    // A \"normal\" modification could also be changing the canonical outpoint that the cacheCoinRefs is pointing to.\n                    // This happens when a re-org causes an earlier (coinbase) coin that is still in the cache (be it spend and dirty)\n                    // gets re-added. If the re-org had a tx with the same index outpoint that will overwrite the (cacheCoinRefs).\n                    // So when the original is re-added again because of a 2nd re-org the index outpoint has to be updated to match again.\n                    // So it is added to the modificationMap to ensure the cacheCoinRefs is updated\n                     modificationMap.push_back(it->first);\n\n                    // NOTE: It is possible the child has a FRESH flag here in\n                    // the event the entry we found in the parent is pruned. But\n                    // we must not copy that FRESH flag to the parent as that\n                    // pruned state likely still needs to be communicated to the\n                    // grandparent.\n                }\n            }\n        }\n        CCoinsMap::iterator itOld = it++;\n        mapCoins.erase(itOld);\n    }\n       \n    for (const auto& outPoint : modificationMap)\n    {\n        const auto iter = cacheCoins.find(outPoint);\n        if (iter != cacheCoins.end())\n        {\n            if (iter->second.coin.IsSpent())\n            {\n                // if there is an existing index entry which points to another coin that is NOT spent then leave it\n                // otherwise update/create an index entry for the (now) spent coin\n                auto indexedOut = COutPoint(iter->second.coin.nHeight, iter->second.coin.nTxIndex, outPoint.n);\n                const auto iterRefs = cacheCoinRefs.find(indexedOut);\n                if (iterRefs != cacheCoinRefs.end() && !cacheCoins[iterRefs->second].coin.IsSpent())\n                {\n                    continue;\n                }\n                cacheCoinRefs[COutPoint(iter->second.coin.nHeight, iter->second.coin.nTxIndex, outPoint.n)] = outPoint;\n            }\n        }\n    }\n    for (const auto& outPoint : modificationMap)\n    {\n        const auto iter = cacheCoins.find(outPoint);\n        if (iter != cacheCoins.end())\n        {\n            if (!iter->second.coin.IsSpent())\n            {\n                cacheCoinRefs[COutPoint(iter->second.coin.nHeight, iter->second.coin.nTxIndex, outPoint.n)] = outPoint;\n            }\n        }\n    }\n    \n    hashBlock = hashBlockIn;\n    return true;\n}\n\nbool CCoinsViewCache::Flush()\n{\n    if (pChainedWitView)\n        pChainedWitView->Flush();\n\n    bool fOk = base->BatchWrite(cacheCoins, hashBlock);\n    cacheCoins.clear();\n    cacheCoinRefs.clear();\n    cachedCoinsUsage = 0;\n    return fOk;\n}\n\nvoid CCoinsViewCache::Uncache(const COutPoint& hash)\n{\n    if (pChainedWitView)\n        pChainedWitView->Uncache(hash);\n\n    //NB! Though it may not seem obvious from browsing the code there is one instance where this function can be called with an index based outpoint instead of a hash\n    //This is when loading a wallet that has a transaction with a prevout that is index based (and not in the wallet)\n    //We then get called from ReacceptWalletTransactions/AcceptToMemoryPool with an index based outpoint\n    //So we handle that special case here then rest of the function MUST work on hash based only as the argument name implies\n    COutPoint canonicalHash = hash;\n    if (!hash.isHash)\n    {\n        auto refIter = cacheCoinRefs.find(hash);\n        if (refIter == cacheCoinRefs.end())\n        {\n            return;\n        }\n        else\n        {\n            canonicalHash = refIter->second;\n        }\n    }\n    \n    \n    CCoinsMap::iterator it = cacheCoins.find(canonicalHash);\n    if (it != cacheCoins.end() && it->second.flags == 0)\n    {\n        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();\n        if (!(it->second.coin.nHeight == MEMPOOL_HEIGHT && it->second.coin.nTxIndex == MEMPOOL_INDEX))\n        {\n            COutPoint indexBased = COutPoint(it->second.coin.nHeight, it->second.coin.nTxIndex, it->first.n);\n            auto refIter = cacheCoinRefs.find(indexBased);\n            if (refIter != cacheCoinRefs.end())\n            {\n                if (refIter->second == canonicalHash)\n                {\n                    cacheCoinRefs.erase(COutPoint(it->second.coin.nHeight, it->second.coin.nTxIndex, it->first.n));\n                }\n            }\n        }\n        cacheCoins.erase(it);\n    }\n}\n\nunsigned int CCoinsViewCache::GetCacheSize() const\n{\n    return cacheCoins.size();\n}\n\nCAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const\n{\n    if (tx.IsCoinBase() && !tx.IsPoW2WitnessCoinBase())\n        return 0;\n\n    CAmount nResult = 0;\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n    {\n        CAmount coinAmount = AccessCoin(tx.vin[i].GetPrevOut()).out.nValue;\n        if (coinAmount != -1)\n        {\n            nResult += coinAmount;\n        }\n    }\n\n    return nResult;\n}\n\nbool CCoinsViewCache::HaveInputs(const CTransaction& tx) const\n{\n    if (!tx.IsCoinBase() || tx.IsPoW2WitnessCoinBase())\n    {\n        for (unsigned int i = 0; i < tx.vin.size(); i++)\n        {\n            if (!HaveCoin(tx.vin[i].GetPrevOut()))\n            {\n                if (!tx.IsPoW2WitnessCoinBase() || !tx.vin[i].GetPrevOut().IsNull())\n                {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n//fixme: (POST-PHASE4) This can potentially be improved.\n//22 is the lower bound for a new SegSig output\nstatic const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / 22; // TODO: merge with similar definition in undo.h.\n\nconst Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)\n{\n    COutPoint iter(txid, 0);\n    while (iter.n < MAX_OUTPUTS_PER_BLOCK)\n    {\n        const Coin& alternate = view.AccessCoin(iter);\n        if (!alternate.IsSpent()) return alternate;\n        ++iter.n;\n    }\n    return coinEmpty;\n}\n"
  },
  {
    "path": "src/coins.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef COINS_H\n#define COINS_H\n\n#include \"primitives/transaction.h\"\n#include \"compressor.h\"\n#include \"core_memusage.h\"\n#include \"hash.h\"\n#include \"memusage.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n\n#include <assert.h>\n#include <stdint.h>\n\n#include <unordered_map>\n\n#include <compat/sys.h>\n\n/**\n * A UTXO entry.\n *\n * Serialized format:\n * - VARINT((height << 2) | (segsig << 1) | (coinbase))\n * - VARINT(index)\n * - the non-spent CTxOut (via CTxOutCompressor)\n */\nclass Coin\n{\npublic:\n    //! unspent transaction output\n    CTxOut out;\n\n    //! whether containing transaction was a coinbase\n    unsigned int fCoinBase : 1;\n    unsigned int fSegSig : 1;\n\n    //! The height this containing transaction was included in the active block chain\n    //NB! This limits us to ~5000 years before we need to update serialisation format - so may eventually have to change but not an issue for now.\n    //MEMPOOL_HEIGHT indicates it is not yet in the chain - any adjustments to the size of this type should also adjust the value of MEMPOOL_HEIGHT\n    uint32_t nHeight : 30;\n    \n    //! The index of the containing transaction within its parent block\n    uint32_t nTxIndex;\n\n    //! construct a Coin from a CTxOut and height/coinbase information.\n    Coin(CTxOut&& outIn, uint32_t nHeightIn, uint32_t nTxIndexIn, bool fCoinBaseIn, bool fSegSigIn)\n    : out(std::move(outIn))\n    , fCoinBase(fCoinBaseIn)\n    , fSegSig(fSegSigIn)\n    , nHeight(nHeightIn)\n    , nTxIndex(nTxIndexIn)\n    {}\n    Coin(const CTxOut& outIn, uint32_t nHeightIn, uint32_t nTxIndexIn, bool fCoinBaseIn, bool fSegSigIn)\n    : out(outIn)\n    , fCoinBase(fCoinBaseIn)\n    , fSegSig(fSegSigIn)\n    , nHeight(nHeightIn)\n    , nTxIndex(nTxIndexIn)\n    {}\n\n    void Clear() {\n        out.SetNull();\n        fCoinBase = false;\n        fSegSig = false;\n        nHeight = 0;\n        nTxIndex = 0;\n    }\n\n    //! empty constructor\n    Coin()\n    : fCoinBase(false)\n    , fSegSig(false)\n    , nHeight(0)\n    , nTxIndex(0)\n    { }\n\n    bool IsCoinBase() const {\n        return fCoinBase;\n    }\n\n    template<typename Stream>\n    void Serialize(Stream &s) const {\n        assert(!IsSpent());\n        uint32_t code = (nHeight<<2) + (fSegSig << 1) + fCoinBase;\n        ::Serialize(s, VARINT(code));\n        ::Serialize(s, VARINT(nTxIndex));\n        out.WriteToStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream &s) {\n        uint32_t code = 0;\n        ::Unserialize(s, VARINT(code));\n        nHeight = ( ((code  & 0b11111111111111111111111111111100) >> 2) );\n        fSegSig = ( (code   & 0b00000000000000000000000000000010) > 0 );\n        fCoinBase = ( (code & 0b00000000000000000000000000000001) > 0 );\n        ::Unserialize(s, VARINT(nTxIndex));\n        out.ReadFromStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n    }\n\n    bool IsSpent() const {\n        return out.IsNull();\n    }\n\n    void Spend() {\n        out.SetNull();\n    }\n\n    size_t DynamicMemoryUsage() const {\n        return RecursiveDynamicUsage(out);\n    }\n};\n\nclass CoinUndo : public Coin\n{\n    public:\n    uint256 prevhash;\n    CoinUndo(Coin&& fromCoin, uint256 hashIn)\n    : Coin(fromCoin)\n    , prevhash(hashIn)\n    {\n    }\n    \n    //! empty constructor\n    CoinUndo() : Coin() {}\n    \n    template<typename Stream>\n    void Serialize(Stream &s) const\n    {\n        assert(!IsSpent());\n        uint32_t code = (nHeight<<2) + (fSegSig << 1) + fCoinBase;\n        ::Serialize(s, VARINT(code));\n        ::Serialize(s, VARINT(nTxIndex));\n        out.WriteToStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n        ::Serialize(s, prevhash);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream &s)\n    {\n        uint32_t code = 0;\n        ::Unserialize(s, VARINT(code));\n        nHeight = ( ((code  & 0b11111111111111111111111111111100) >> 2) );\n        fSegSig = ( (code   & 0b00000000000000000000000000000010) > 0 );\n        fCoinBase = ( (code & 0b00000000000000000000000000000001) > 0 );\n        ::Unserialize(s, VARINT(nTxIndex));\n        out.ReadFromStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n        ::Unserialize(s, prevhash);\n    }\n};\n\nclass SaltedOutpointHasher\n{\nprivate:\n    /** Salt */\n    const uint64_t k0, k1;\n\npublic:\n    SaltedOutpointHasher();\n\n    /**\n     * This *must* return size_t. With Boost 1.46 on 32-bit systems the\n     * unordered_map will behave unpredictably if the custom hasher returns a\n     * uint64_t, resulting in failures when syncing the chain (#4634).\n     */\n    size_t operator()(const COutPoint& id) const {\n        return SipHashUint256Extra(k0, k1, id.getBucketHash(), id.n);\n    }\n};\n\nstruct CCoinsCacheEntry\n{\n    Coin coin; // The actual cached data.\n    unsigned char flags;\n\n    enum Flags {\n        DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.\n        FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).\n        /* Note that FRESH is a performance optimization with which we can\n         * erase coins that are fully spent if we know we do not need to\n         * flush the changes to the parent cache.  It is always safe to\n         * not mark FRESH if that condition is not guaranteed.\n         */\n    };\n\n    CCoinsCacheEntry() : flags(0) {}\n    explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}\n};\n\ntypedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;\ntypedef std::unordered_map<COutPoint, COutPoint, SaltedOutpointHasher> CCoinsRefMap;\n\n/** Cursor for iterating over CoinsView state */\nclass CCoinsViewCursor\n{\npublic:\n    CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}\n    virtual ~CCoinsViewCursor() {}\n\n    virtual bool GetKey(COutPoint &key) const = 0;\n    virtual bool GetValue(Coin &coin) const = 0;\n    virtual unsigned int GetValueSize() const = 0;\n\n    virtual bool Valid() const = 0;\n    virtual void Next() = 0;\n\n    //! Get best block at the time this cursor was created\n    const uint256 &GetBestBlock() const { return hashBlock; }\nprivate:\n    uint256 hashBlock;\n};\n\n/** Abstract view on the open txout dataset. */\nclass CCoinsView\n{\npublic:\n    //! Retrieve the Coin (unspent transaction output) for a given outpoint.\n    virtual bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const;\n\n    //! Just check whether we have data for a given outpoint.\n    //! This may (but cannot always) return true for spent outputs.\n    virtual bool HaveCoin(const COutPoint &outpoint) const;\n\n    //! Retrieve the block hash whose state this CCoinsView currently represents\n    virtual uint256 GetBestBlock() const;\n\n    //! Do a bulk modification (multiple Coin changes + BestBlock change).\n    //! The passed mapCoins can be modified.\n    virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);\n\n    //! Get a cursor to iterate over the whole state\n    virtual CCoinsViewCursor *Cursor() const;\n\n    //! As we use CCoinsViews polymorphically, have a virtual destructor\n    virtual ~CCoinsView() {}\n\n    //! Estimate database size (0 if not implemented)\n    virtual size_t EstimateSize() const { return 0; }\n\n    virtual void GetAllCoins(std::map<COutPoint, Coin>&) const {};\n    virtual void GetAllCoinsIndexBased(std::map<COutPoint, Coin>&) const {};\n    virtual void GetAllCoinsIndexBasedDirect(std::map<COutPoint, Coin>& allCoins) const {};\n};\n\n\n/** CCoinsView backed by another CCoinsView */\nclass CCoinsViewBacked : public CCoinsView\n{\nprotected:\n    CCoinsView *base;\n\npublic:\n    CCoinsViewBacked(CCoinsView *viewIn);\n    bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const override;\n    bool HaveCoin(const COutPoint &outpoint) const override;\n    uint256 GetBestBlock() const override;\n    void SetBackend(CCoinsView &viewIn);\n    bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;\n    CCoinsViewCursor *Cursor() const override;\n    size_t EstimateSize() const override;\n    void GetAllCoins(std::map<COutPoint, Coin>& allCoins) const override\n    {\n        base->GetAllCoins(allCoins);\n    }\n    void GetAllCoinsIndexBased(std::map<COutPoint, Coin>& allCoins) const override\n    {\n        base->GetAllCoinsIndexBased(allCoins);\n    }\n    void GetAllCoinsIndexBasedDirect(std::map<COutPoint, Coin>& allCoins) const override\n    {\n        base->GetAllCoinsIndexBasedDirect(allCoins);\n    }\n};\n\n\n/** CCoinsView that adds a memory cache for transactions to another CCoinsView */\nclass CCoinsViewCache : public CCoinsViewBacked\n{\nprotected:\n    /**\n     * Make mutable so that we can \"fill the cache\" even from Get-methods\n     * declared as \"const\".\n     */\n    mutable uint256 hashBlock;\n    mutable CCoinsMap cacheCoins;\n    mutable CCoinsRefMap cacheCoinRefs;\n    mutable uint64_t cacheMempoolRefs;\n\n    /* Cached dynamic memory usage for the inner Coin objects. */\n    mutable size_t cachedCoinsUsage;\n\npublic:\n    CCoinsViewCache(CCoinsViewCache *baseIn);\n    CCoinsViewCache(CCoinsView *baseIn);\n\n    // Standard CCoinsView methods\n    bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const override;\n    bool HaveCoin(const COutPoint &outpoint) const override;\n    uint256 GetBestBlock() const override;\n    void SetBestBlock(const uint256 &hashBlock);\n    bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;\n    CCoinsViewCursor* Cursor() const override {\n        throw std::logic_error(\"CCoinsViewCache cursor iteration not supported.\");\n    }\n\n    /**\n     * Check if we have the given utxo already loaded in this cache.\n     * The semantics are the same as HaveCoin(), but no calls to\n     * the backing CCoinsView are made.\n     */\n    bool HaveCoinInCache(const COutPoint &outpoint) const;\n\n    /**\n     * Return a reference to Coin in the cache, or a pruned one if not found. This is\n     * more efficient than GetCoin. Modifications to other cache entries are\n     * allowed while accessing the returned pointer.\n     */\n    const Coin& AccessCoin(const COutPoint &output) const;\n\n    /**\n     * Add a coin. Set potential_overwrite to true if a non-pruned version may\n     * already exist.\n     */\n    void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);\n\n    /**\n     * Spend a coin. Pass moveto in order to get the deleted data.\n     * If no unspent output exists for the passed outpoint, this call\n     * has no effect.\n     */\n    void SpendCoin(const COutPoint &outpoint, CoinUndo* moveto = nullptr, bool nodeletefresh = false);\n\n    /**\n     * Push the modifications applied to this cache to its base.\n     * Failure to call this method before destruction will cause the changes to be forgotten.\n     * If false is returned, the state of this cache (and its backing view) will be undefined.\n     */\n    bool Flush();\n\n    /**\n     * Removes the UTXO with the given outpoint from the cache, if it is\n     * not modified.\n     */\n    void Uncache(const COutPoint &outpoint);\n\n    //! Calculate the size of the cache (in number of transaction outputs)\n    unsigned int GetCacheSize() const;\n\n    //! Calculate the size of the cache (in bytes)\n    size_t DynamicMemoryUsage() const;\n\n    /** \n     * Amount of coins coming in to a transaction\n     * Note that lightweight clients may not know anything besides the hash of previous transactions,\n     * so may not be able to calculate this.\n     *\n     * @param[in] tx\ttransaction for which we are checking input total\n     * @return\tSum of value of all inputs (scriptSigs)\n     */\n    CAmount GetValueIn(const CTransaction& tx) const;\n\n    //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view\n    bool HaveInputs(const CTransaction& tx) const;\n\n    // Side view\n    void SetSiblingView(std::shared_ptr<CCoinsViewCache> pChainedWitView_) { pChainedWitView = pChainedWitView_; };\n    std::shared_ptr<CCoinsViewCache> pChainedWitView;\n\n    void GetAllCoins(std::map<COutPoint, Coin>& allCoins) const override\n    {\n        base->GetAllCoins(allCoins);\n\n        for (auto iter : cacheCoins)\n        {\n            if (iter.second.coin.out.IsNull())\n            {\n                if (allCoins.find(iter.first) != allCoins.end())\n                {\n                    allCoins.erase(iter.first);\n                }\n            }\n            else\n            {\n                allCoins[iter.first] = iter.second.coin;\n            }\n        }\n    }\n    \n    void GetAllCoinsIndexBased(std::map<COutPoint, Coin>& allCoinsIndexBased) const override\n    {\n        std::map<COutPoint, Coin> allCoins;\n        GetAllCoins(allCoins);\n        \n        for (auto& [outPoint, coin] : allCoins)\n        {\n            COutPoint indexBased(coin.nHeight, coin.nTxIndex, outPoint.n);\n            allCoinsIndexBased[indexBased] = coin;\n        }\n    }\n    \n    //fixme: (FUT) We keep this form around but don't use it\n    // If/When we can prove beyond a shadow of a doubt that it introduces no problems and that it really is faster consider switching to it, otherwise we should delete and stick to the simpler implementation\n    void GetAllCoinsIndexBasedDirect(std::map<COutPoint, Coin>& allCoinsIndexBased) const override\n    {\n        for (auto iter : cacheCoins)\n        {\n            COutPoint indexBased(iter.second.coin.nHeight, iter.second.coin.nTxIndex, iter.first.n);\n            if (!iter.second.coin.out.IsNull())\n            {\n                allCoinsIndexBased[indexBased] = iter.second.coin;\n            }\n        }\n    }\n\nprivate:\n    CCoinsMap::iterator FetchCoin(const COutPoint &outpoint, CCoinsRefMap::iterator* pRefIterReturn=nullptr) const;\n\n    #if defined(DEBUG) && !defined(PLATFORM_MOBILE)\n    #define DEBUG_COINSCACHE_VALIDATE_INSERTS\n    void validateInsert(const COutPoint &outpoint, uint64_t block, uint64_t txIndex, uint32_t voutIndex) const;\n    #else\n    void validateInsert(const COutPoint &outpoint, uint64_t block, uint64_t txIndex, uint32_t voutIndex) const {};\n    #endif\n\n    /**\n     * By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.\n     */\n    CCoinsViewCache(const CCoinsViewCache &);\n};\n\n//! Utility function to add all of a transaction's outputs to a cache.\n// It assumes that overwrites are only possible for coinbase transactions,\n// TODO: pass in a boolean to limit these possible overwrites to known\n// (pre-BIP34) cases.\nvoid AddCoins(CCoinsViewCache& cache, const CTransaction& tx, uint32_t nHeight, uint32_t nTxIndex);\n\n//! Utility function to find any unspent output with a given txid.\nconst Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);\n\n#endif\n"
  },
  {
    "path": "src/compat/arch.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file defines various architecture flags for both specific architectures and 'families'.\n// The rest of the codebase can just use 'ARCH_CPU_X86_FAMILY' for code that is specific to the x86 family (for instance) - e.g. Some code that contains SSE optimisations, note the file would still have to handle turning that on/off appropriately.\n// Or ARCH_X86_64 for code that is specific to 64 bit 'x86' processors only etc.\n\n#ifndef COMPAT_ARCH_H\n#define COMPAT_ARCH_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#if defined(_M_X64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_AMD64)\n    #define ARCH_CPU_X86_FAMILY 1\n    #define ARCH_X86_64 1\n#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)\n    #define ARCH_X86 1\n    #define ARCH_CPU_X86_FAMILY 1\n#elif defined(__ia64__) || defined(__itanium__) || defined(_M_IA64)\n    #define ARCH_ITANIUM 1\n#elif defined(__aarch64__)\n    #define ARCH_ARM64 1\n    #define ARCH_CPU_ARM_FAMILY 1\n    #define ARCH_CPU_ARM64_FAMILY 1\n    #define __ARM_ARCH 8\n#elif defined(__ARMEL__) || defined(__arm__)\n    #define ARCH_ARM 1\n    #define ARCH_CPU_ARM_FAMILY 1\n#elif defined(__ppc__) || defined(__powerpc__) || defined(_M_PPC)\n    #define ARCH_PPC 1\n    #define ARCH_CPU_PPC_FAMILY 1\n#elif defined(__ppc64__) || defined(__powerpc64__)\n    #define ARCH_PPC64 1\n    #define ARCH_CPU_PPC_FAMILY 1\n#elif defined(__mips__)\n    #define ARCH_MIPS 1\n    #define ARCH_CPU_MIPS_FAMILY 1\n#elif defined(__alpha__) || defined(_M_ALPHA)\n    #define ARCH_CPU_ALPHA 1\n#elif defined(__sparc__)\n    #define ARCH_SPARC 1\n#elif defined(__riscv)\n    #define ARCH_RISC 1\n#endif\n\n\n\n#endif\n"
  },
  {
    "path": "src/compat/assumptions.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n// Compile-time verification of assumptions we make.\n\n#ifndef CORE_COMPAT_ASSUMPTIONS_H\n#define CORE_COMPAT_ASSUMPTIONS_H\n\n#include <limits>\n\n// Assumption: We assume that the macro NDEBUG is not defined.\n// Example(s): We use assert(...) extensively with the assumption of it never\n//             being a noop at runtime.\n#if defined(NDEBUG)\n# error \"Cannot be compiled without assertions.\"\n#endif\n\n// Assumption: We assume a C++17 (ISO/IEC 14882:2017) compiler (minimum requirement).\n// Example(s): We assume the presence of C++17 features everywhere :-)\n// ISO Standard C++17 [cpp.predefined]p1:\n// \"The name __cplusplus is defined to the value 201703L when compiling a C++\n//  translation unit.\"\nstatic_assert(__cplusplus >= 201703L, \"C++17 standard assumed\");\n\n// Assumption: We assume the floating-point types to fulfill the requirements of\n//             IEC 559 (IEEE 754) standard.\n// Example(s): Floating-point division by zero in ConnectBlock, CreateTransaction\n//             and EstimateMedianVal.\nstatic_assert(std::numeric_limits<float>::is_iec559, \"IEEE 754 float assumed\");\nstatic_assert(std::numeric_limits<double>::is_iec559, \"IEEE 754 double assumed\");\n\n// Assumption: We assume eight bits per byte (obviously, but remember: don't\n//             trust -- verify!).\n// Example(s): Everywhere :-)\nstatic_assert(std::numeric_limits<unsigned char>::digits == 8, \"8-bit byte assumed\");\n\n// Assumption: We assume integer widths.\n// Example(s): GetSizeOfCompactSize and WriteCompactSize in the serialization\n//             code.\nstatic_assert(sizeof(short) == 2, \"16-bit short assumed\");\nstatic_assert(sizeof(int) == 4, \"32-bit int assumed\");\nstatic_assert(sizeof(unsigned) == 4, \"32-bit unsigned assumed\");\n\n// Assumption: We assume size_t to be 32-bit or 64-bit.\n// Example(s): size_t assumed to be at least 32-bit in ecdsa_signature_parse_der_lax(...).\n//             size_t assumed to be 32-bit or 64-bit in MallocUsage(...).\nstatic_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, \"size_t assumed to be 32-bit or 64-bit\");\nstatic_assert(sizeof(size_t) == sizeof(void*), \"Sizes of size_t and void* assumed to be equal\");\n\n// Some important things we are NOT assuming (non-exhaustive list):\n// * We are NOT assuming a specific value for std::endian::native.\n// * We are NOT assuming a specific value for std::locale(\"\").name().\n// * We are NOT assuming a specific value for std::numeric_limits<char>::is_signed.\n\n#endif // CORE_COMPAT_ASSUMPTIONS_H\n"
  },
  {
    "path": "src/compat/byteswap.h",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef COMPAT_BYTESWAP_H\n#define COMPAT_BYTESWAP_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <stdint.h>\n\n#if defined(HAVE_BYTESWAP_H)\n#include <byteswap.h>\n#endif\n\n#if defined(__APPLE__)\n\n#if !defined(bswap_16)\n\n// Mac OS X / Darwin features; we include a check for bswap_16 because if it is already defined, protobuf has\n// defined these macros for us already; if it isn't, we do it ourselves. In either case, we get the exact same\n// result regardless which path was taken\n#include <libkern/OSByteOrder.h>\n#define bswap_16(x) OSSwapInt16(x)\n#define bswap_32(x) OSSwapInt32(x)\n#define bswap_64(x) OSSwapInt64(x)\n\n#endif // !defined(bswap_16)\n\n#else\n// Non-Mac OS X / non-Darwin\n\n#if HAVE_DECL_BSWAP_16 == 0\ninline uint16_t bswap_16(uint16_t x)\n{\n    return (x >> 8) | ((x & 0x00ff) << 8);\n}\n#endif // HAVE_DECL_BSWAP16\n\n#if HAVE_DECL_BSWAP_32 == 0\ninline uint32_t bswap_32(uint32_t x)\n{\n    return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >>  8) |\n            ((x & 0x0000ff00U) <<  8) | ((x & 0x000000ffU) << 24));\n}\n#endif // HAVE_DECL_BSWAP32\n\n#if HAVE_DECL_BSWAP_64 == 0\ninline uint64_t bswap_64(uint64_t x)\n{\n     return (((x & 0xff00000000000000ull) >> 56)\n          | ((x & 0x00ff000000000000ull) >> 40)\n          | ((x & 0x0000ff0000000000ull) >> 24)\n          | ((x & 0x000000ff00000000ull) >> 8)\n          | ((x & 0x00000000ff000000ull) << 8)\n          | ((x & 0x0000000000ff0000ull) << 24)\n          | ((x & 0x000000000000ff00ull) << 40)\n          | ((x & 0x00000000000000ffull) << 56));\n}\n#endif // HAVE_DECL_BSWAP64\n\n#endif // defined(__APPLE__)\n\n#endif\n"
  },
  {
    "path": "src/compat/cpuid.h",
    "content": "// Copyright (c) 2017-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_COMPAT_CPUID_H\n#define CORE_COMPAT_CPUID_H\n\n#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)\n#define HAVE_GETCPUID\n\n#include <cpuid.h>\n\n// We can't use cpuid.h's __get_cpuid as it does not support subleafs.\nvoid static inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)\n{\n#ifdef __GNUC__\n    __cpuid_count(leaf, subleaf, a, b, c, d);\n#else\n  __asm__ (\"cpuid\" : \"=a\"(a), \"=b\"(b), \"=c\"(c), \"=d\"(d) : \"0\"(leaf), \"2\"(subleaf));\n#endif\n}\n\n#endif // defined(__x86_64__) || defined(__amd64__) || defined(__i386__)\n#endif // CORE_COMPAT_CPUID_H\n"
  },
  {
    "path": "src/compat/endian.h",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef COMPAT_ENDIAN_H\n#define COMPAT_ENDIAN_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <stdint.h>\n\n#include \"compat/byteswap.h\"\n\n#if defined(HAVE_ENDIAN_H)\n#include <endian.h>\n#elif defined(HAVE_SYS_ENDIAN_H)\n#include <sys/endian.h>\n#endif\n\n#ifndef __FreeBSD__\nstatic inline uint32_t le32dec(const void *pp)\n{\n        const uint8_t *p = (uint8_t const *)pp;\n        return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +\n            ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));\n}\n\nstatic inline void le32enc(void *pp, uint32_t x)\n{\n        uint8_t *p = (uint8_t *)pp;\n        p[0] = x & 0xff;\n        p[1] = (x >> 8) & 0xff;\n        p[2] = (x >> 16) & 0xff;\n        p[3] = (x >> 24) & 0xff;\n}\n\nstatic inline uint32_t be32dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\treturn ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +\n\t    ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));\n}\n\nstatic inline void be32enc(void *pp, uint32_t x)\n{\n\tuint8_t *p = (uint8_t *)pp;\n\tp[3] = x & 0xff;\n\tp[2] = (x >> 8) & 0xff;\n\tp[1] = (x >> 16) & 0xff;\n\tp[0] = (x >> 24) & 0xff;\n}\n\n\nstatic inline uint64_t be64dec(const void * pp)\n{\n\tconst uint8_t * p = (uint8_t const *)pp;\n\n\treturn ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) +\n\t    ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) +\n\t    ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) +\n\t    ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56));\n}\n\nstatic inline void be64enc(void * pp, uint64_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[7] = x & 0xff;\n\tp[6] = (x >> 8) & 0xff;\n\tp[5] = (x >> 16) & 0xff;\n\tp[4] = (x >> 24) & 0xff;\n\tp[3] = (x >> 32) & 0xff;\n\tp[2] = (x >> 40) & 0xff;\n\tp[1] = (x >> 48) & 0xff;\n\tp[0] = (x >> 56) & 0xff;\n}\n\nstatic inline uint64_t le64dec(const void * pp)\n{\n\tconst uint8_t * p = (uint8_t const *)pp;\n\n\treturn ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +\n\t    ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +\n\t    ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +\n\t    ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));\n}\n\nstatic inline void le64enc(void * pp, uint64_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[0] = x & 0xff;\n\tp[1] = (x >> 8) & 0xff;\n\tp[2] = (x >> 16) & 0xff;\n\tp[3] = (x >> 24) & 0xff;\n\tp[4] = (x >> 32) & 0xff;\n\tp[5] = (x >> 40) & 0xff;\n\tp[6] = (x >> 48) & 0xff;\n\tp[7] = (x >> 56) & 0xff;\n}\n#endif\n\n#if defined(WORDS_BIGENDIAN)\n\n#if HAVE_DECL_HTOBE16 == 0\ninline uint16_t htobe16(uint16_t host_16bits)\n{\n    return host_16bits;\n}\n#endif // HAVE_DECL_HTOBE16\n\n#if HAVE_DECL_HTOLE16 == 0\ninline uint16_t htole16(uint16_t host_16bits)\n{\n    return bswap_16(host_16bits);\n}\n#endif // HAVE_DECL_HTOLE16\n\n#if HAVE_DECL_BE16TOH == 0\ninline uint16_t be16toh(uint16_t big_endian_16bits)\n{\n    return big_endian_16bits;\n}\n#endif // HAVE_DECL_BE16TOH\n\n#if HAVE_DECL_LE16TOH == 0\ninline uint16_t le16toh(uint16_t little_endian_16bits)\n{\n    return bswap_16(little_endian_16bits);\n}\n#endif // HAVE_DECL_LE16TOH\n\n#if HAVE_DECL_HTOBE32 == 0\ninline uint32_t htobe32(uint32_t host_32bits)\n{\n    return host_32bits;\n}\n#endif // HAVE_DECL_HTOBE32\n\n#if HAVE_DECL_HTOLE32 == 0\ninline uint32_t htole32(uint32_t host_32bits)\n{\n    return bswap_32(host_32bits);\n}\n#endif // HAVE_DECL_HTOLE32\n\n#if HAVE_DECL_BE32TOH == 0\ninline uint32_t be32toh(uint32_t big_endian_32bits)\n{\n    return big_endian_32bits;\n}\n#endif // HAVE_DECL_BE32TOH\n\n#if HAVE_DECL_LE32TOH == 0\ninline uint32_t le32toh(uint32_t little_endian_32bits)\n{\n    return bswap_32(little_endian_32bits);\n}\n#endif // HAVE_DECL_LE32TOH\n\n#if HAVE_DECL_HTOBE64 == 0\ninline uint64_t htobe64(uint64_t host_64bits)\n{\n    return host_64bits;\n}\n#endif // HAVE_DECL_HTOBE64\n\n#if HAVE_DECL_HTOLE64 == 0\ninline uint64_t htole64(uint64_t host_64bits)\n{\n    return bswap_64(host_64bits);\n}\n#endif // HAVE_DECL_HTOLE64\n\n#if HAVE_DECL_BE64TOH == 0\ninline uint64_t be64toh(uint64_t big_endian_64bits)\n{\n    return big_endian_64bits;\n}\n#endif // HAVE_DECL_BE64TOH\n\n#if HAVE_DECL_LE64TOH == 0\ninline uint64_t le64toh(uint64_t little_endian_64bits)\n{\n    return bswap_64(little_endian_64bits);\n}\n#endif // HAVE_DECL_LE64TOH\n\n#else // WORDS_BIGENDIAN\n\n#if HAVE_DECL_HTOBE16 == 0\ninline uint16_t htobe16(uint16_t host_16bits)\n{\n    return bswap_16(host_16bits);\n}\n#endif // HAVE_DECL_HTOBE16\n\n#if HAVE_DECL_HTOLE16 == 0\ninline uint16_t htole16(uint16_t host_16bits)\n{\n    return host_16bits;\n}\n#endif // HAVE_DECL_HTOLE16\n\n#if HAVE_DECL_BE16TOH == 0\ninline uint16_t be16toh(uint16_t big_endian_16bits)\n{\n    return bswap_16(big_endian_16bits);\n}\n#endif // HAVE_DECL_BE16TOH\n\n#if HAVE_DECL_LE16TOH == 0\ninline uint16_t le16toh(uint16_t little_endian_16bits)\n{\n    return little_endian_16bits;\n}\n#endif // HAVE_DECL_LE16TOH\n\n#if HAVE_DECL_HTOBE32 == 0\ninline uint32_t htobe32(uint32_t host_32bits)\n{\n    return bswap_32(host_32bits);\n}\n#endif // HAVE_DECL_HTOBE32\n\n#if HAVE_DECL_HTOLE32 == 0\ninline uint32_t htole32(uint32_t host_32bits)\n{\n    return host_32bits;\n}\n#endif // HAVE_DECL_HTOLE32\n\n#if HAVE_DECL_BE32TOH == 0\ninline uint32_t be32toh(uint32_t big_endian_32bits)\n{\n    return bswap_32(big_endian_32bits);\n}\n#endif // HAVE_DECL_BE32TOH\n\n#if HAVE_DECL_LE32TOH == 0\ninline uint32_t le32toh(uint32_t little_endian_32bits)\n{\n    return little_endian_32bits;\n}\n#endif // HAVE_DECL_LE32TOH\n\n#if HAVE_DECL_HTOBE64 == 0\ninline uint64_t htobe64(uint64_t host_64bits)\n{\n    return bswap_64(host_64bits);\n}\n#endif // HAVE_DECL_HTOBE64\n\n#if HAVE_DECL_HTOLE64 == 0\ninline uint64_t htole64(uint64_t host_64bits)\n{\n    return host_64bits;\n}\n#endif // HAVE_DECL_HTOLE64\n\n#if HAVE_DECL_BE64TOH == 0\ninline uint64_t be64toh(uint64_t big_endian_64bits)\n{\n    return bswap_64(big_endian_64bits);\n}\n#endif // HAVE_DECL_BE64TOH\n\n#if HAVE_DECL_LE64TOH == 0\ninline uint64_t le64toh(uint64_t little_endian_64bits)\n{\n    return little_endian_64bits;\n}\n#endif // HAVE_DECL_LE64TOH\n\n#endif // WORDS_BIGENDIAN\n\n#endif\n"
  },
  {
    "path": "src/compat/glibc_sanity.cpp",
    "content": "// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <cstddef>\n\n#if defined(HAVE_SYS_SELECT_H)\n#include <sys/select.h>\n#endif\n\nextern \"C\" void* memcpy(void* a, const void* b, size_t c);\nvoid* memcpy_int(void* a, const void* b, size_t c)\n{\n    return memcpy(a, b, c);\n}\n\nnamespace\n{\n// trigger: Use the memcpy_int wrapper which calls our internal memcpy.\n//   A direct call to memcpy may be optimized away by the compiler.\n// test: Fill an array with a sequence of integers. memcpy to a new empty array.\n//   Verify that the arrays are equal. Use an odd size to decrease the odds of\n//   the call being optimized away.\ntemplate <unsigned int T>\nbool sanity_test_memcpy()\n{\n    unsigned int memcpy_test[T];\n    unsigned int memcpy_verify[T] = {};\n    for (unsigned int i = 0; i != T; ++i)\n        memcpy_test[i] = i;\n\n    memcpy_int(memcpy_verify, memcpy_test, sizeof(memcpy_test));\n\n    for (unsigned int i = 0; i != T; ++i) {\n        if (memcpy_verify[i] != i)\n            return false;\n    }\n    return true;\n}\n\n#if defined(HAVE_SYS_SELECT_H)\n// trigger: Call FD_SET to trigger __fdelt_chk. FORTIFY_SOURCE must be defined\n//   as >0 and optimizations must be set to at least -O2.\n// test: Add a file descriptor to an empty fd_set. Verify that it has been\n//   correctly added.\nbool sanity_test_fdelt()\n{\n    fd_set fds;\n    FD_ZERO(&fds);\n    FD_SET(0, &fds);\n    return FD_ISSET(0, &fds);\n}\n#endif\n\n} // anon namespace\n\nbool glibc_sanity_test()\n{\n#if defined(HAVE_SYS_SELECT_H)\n    if (!sanity_test_fdelt())\n        return false;\n#endif\n    return sanity_test_memcpy<1025>();\n}\n"
  },
  {
    "path": "src/compat/glibcxx_sanity.cpp",
    "content": "// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <list>\n#include <locale>\n#include <stdexcept>\n\nnamespace\n{\n// trigger: use ctype<char>::widen to trigger ctype<char>::_M_widen_init().\n// test: convert a char from narrow to wide and back. Verify that the result\n//   matches the original.\nbool sanity_test_widen(char testchar)\n{\n    const std::ctype<char>& test(std::use_facet<std::ctype<char> >(std::locale()));\n    return test.narrow(test.widen(testchar), 'b') == testchar;\n}\n\n// trigger: use list::push_back and list::pop_back to trigger _M_hook and\n//   _M_unhook.\n// test: Push a sequence of integers into a list. Pop them off and verify that\n//   they match the original sequence.\nbool sanity_test_list(unsigned int size)\n{\n    std::list<unsigned int> test;\n    for (unsigned int i = 0; i != size; ++i)\n        test.push_back(i + 1);\n\n    if (test.size() != size)\n        return false;\n\n    while (!test.empty()) {\n        if (test.back() != test.size())\n            return false;\n        test.pop_back();\n    }\n    return true;\n}\n\n} // anon namespace\n\n// trigger: string::at(x) on an empty string to trigger __throw_out_of_range_fmt.\n// test: force std::string to throw an out_of_range exception. Verify that\n//   it's caught correctly.\nstatic bool sanity_test_range_fmt()\n{\n    std::string test;\n    try {\n        test.at(1);\n    } catch (const std::out_of_range&) {\n        return true;\n    } catch (...) {\n    }\n    return false;\n}\n\nbool glibcxx_sanity_test()\n{\n    return sanity_test_widen('a') && sanity_test_list(100) && sanity_test_range_fmt();\n}\n"
  },
  {
    "path": "src/compat/sanity.h",
    "content": "// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef COMPAT_SANITY_H\n#define COMPAT_SANITY_H\n\nbool glibc_sanity_test();\nbool glibcxx_sanity_test();\n\n#endif\n"
  },
  {
    "path": "src/compat/sse.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file defines a basic compatibility layer to compile sse instructions to neon on arm achitectures.\n// The result is not likely to be optimal or as good as a complete neon re-write but still better than a naive non-neon implementation.\n\n#ifndef COMPAT_SSE_H\n#define COMPAT_SSE_H\n\n#include <compat/arch.h>\n#include <cstdint>\n\n#if defined(ARCH_CPU_X86_FAMILY)\n    #include <emmintrin.h>\n    #include <immintrin.h>\n    #ifndef USE_HARDWARE_AES\n        // In the absence of AES-ni simply implement AES in software.\n        #define SOFTWARE_AES\n    #endif\n#elif defined(ARCH_CPU_ARM_FAMILY)\n    // Compat layer for neon intrinsics\n    #if defined(USE_HARDWARE_AES) && !defined(__ARM_FEATURE_CRYPTO)\n    #define __ARM_FEATURE_CRYPTO\n    #endif   \n    #include \"sse2neon.h\"\n    // We currently use the following sse2neon commands:\n    // _mm_mul_epu32 _mm_sub_epi64 _mm_add_epi64 _mm_srli_epi64 _mm_slli_epi64 _mm_unpacklo_epi64 _mm_unpackhi_epi64 _mm_aesenc_si128\n    // _mm_xor_si128 _mm_and_si128 _mm_add_epi32 _mm_loadu_si128 _mm_setzero_si128 _mm_storeu_si128 _mm_add_epi8 _mm_shuffle_epi8 _mm_set_epi32\n    // _mm_srli_epi16 _mm_srli_si128 _mm_slli_si128 _mm_shuffle_epi32 \n    #ifdef USE_HARDWARE_AES\n        // Implements equivalent of 'aesenc' by combining AESE (with an empty key) and AESMC and then manually applying the real key as an xor operation\n        // This unfortunately means an additional xor op; the compiler should be able to optimise this away for repeated calls however\n        // See  https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a for more details.\n        inline __m128i _mm_aesenc_si128(__m128i a, __m128i b)\n        {\n            return vreinterpretq_s32_u8(vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_s32(a), uint8x16_t{})) ^ vreinterpretq_u8_s32(b));\n        }\n    #else\n        #ifdef ARCH_CPU_ARM64_FAMILY\n            // In the absence of crypto extensions, implement aesenc using regular neon intrinsics instead.\n            #define SOFTWARE_AES\n            #define SOFTWARE_AES_NEON\n        #else\n            // As a last resort use a complete software implementation\n            #define SOFTWARE_AES\n        #endif\n    #endif\n#else\n    //fixme: (SIGMA) riscv\n    #include <array>\n    typedef std::array<uint8_t, 16> __m128i;\n#endif\n\n#if defined(SOFTWARE_AES) || defined(SOFTWARE_AES_NEON)\n    static const uint8_t crypto_aes_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };\n    #ifdef SOFTWARE_AES_NEON\n        // See: http://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/ http://www.workofard.com/2017/07/ghash-for-low-end-cores/ and https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52 for more information\n        // Reproduced with permission of the author.\n        inline __m128i _mm_aesenc_si128_sw(__m128i EncBlock, __m128i RoundKey)\n        {\n            static const uint8_t crypto_aes_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };\n            static const uint8_t shift_rows[] = { 0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3, 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb};\n            static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc};\n\n            uint8x16_t v;\n            uint8x16_t w = vreinterpretq_u8_s32(EncBlock);\n\n            // shift rows\n            w = vqtbl1q_u8(w, vld1q_u8(shift_rows));\n\n            // sub bytes\n            v = vqtbl4q_u8(vld1q_u8_x4(crypto_aes_sbox), w);\n            v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x40), w - 0x40);\n            v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0x80), w - 0x80);\n            v = vqtbx4q_u8(v, vld1q_u8_x4(crypto_aes_sbox + 0xc0), w - 0xc0);\n\n            // mix columns\n            w = (v << 1) ^ (uint8x16_t)(((int8x16_t)v >> 7) & 0x1b);\n            w ^= (uint8x16_t)vrev32q_u16((uint16x8_t)v);\n            w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8));\n\n            //  add round key\n            return vreinterpretq_s32_u8(w) ^ RoundKey;\n        }\n    #else\n        #define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b))\n        inline __m128i _mm_aesenc_si128_sw (__m128i a, __m128i b)\n        {\n            typedef union{__m128i u128; unsigned char u8[16];} u128_wrap;            \n            uint8_t i, t, u, v[4][4];\n            for (i = 0; i < 16; ++i)\n            {\n                v[((i / 4) + 4 - (i%4) ) % 4][i % 4] = crypto_aes_sbox[((u128_wrap*)&a)->u8[i]];\n            }\n            for (i = 0; i < 4; ++i)\n            {\n                t = v[i][0];\n                u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3];\n                v[i][0] ^= u ^ XT(v[i][0] ^ v[i][1]);\n                v[i][1] ^= u ^ XT(v[i][1] ^ v[i][2]);\n                v[i][2] ^= u ^ XT( v[i][2] ^ v[i][3]);\n                v[i][3] ^= u ^ XT(v[i][3] ^ t);\n            }\n            for (i = 0; i < 16; ++i)\n            {\n                ((u128_wrap*)&a)->u8[i] = v[i / 4][i % 4] ^ ((u128_wrap*)&b)->u8[i];\n            }\n            return ((u128_wrap*)&a)->u128;\n        }\n    #endif\n#endif\n\n#endif\n"
  },
  {
    "path": "src/compat/sse2neon.h",
    "content": "#ifndef SSE2NEON_H\n#define SSE2NEON_H\n\n// This header file provides a simple API translation layer\n// between SSE intrinsics to their corresponding ARM NEON versions\n//\n// This header file does not yet translate all of the SSE intrinsics.\n//\n// Contributors to this work are:\n//   John W. Ratcliff     : jratcliffscarab@gmail.com\n//   Brandon Rowlett      : browlett@nvidia.com\n//   Ken Fast             : kfast@gdeb.com\n//   Eric van Beurden     : evanbeurden@nvidia.com\n//   Alexander Potylitsin : apotylitsin@nvidia.com\n//   Hasindu Gamaarachchi : hasindu2008@gmail.com\n//   Jim Huang            : jserv@biilabs.io\n//\n// A struct is now defined in this header file called 'SIMDVec' which can be\n// used by applications which attempt to access the contents of an _m128 struct\n// directly.  It is important to note that accessing the __m128 struct directly\n// is bad coding practice by Microsoft: @see:\n// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx\n//\n// However, some legacy source code may try to access the contents of an __m128\n// struct directly so the developer can use the SIMDVec as an alias for it.  Any\n// casting must be done manually by the developer, as you cannot cast or\n// otherwise alias the base NEON data type for intrinsic operations.\n//\n// A bug was found with the _mm_shuffle_ps intrinsic.  If the shuffle\n// permutation was not one of the ones with a custom/unique implementation\n// causing it to fall through to the default shuffle implementation it was\n// failing to return the correct value.  This is now fixed.\n//\n// A bug was found with the _mm_cvtps_epi32 intrinsic.  This converts floating\n// point values to integers. It was not honoring the correct rounding mode.  In\n// SSE the default rounding mode when converting from float to int is to use\n// 'round to even' otherwise known as 'bankers rounding'.  ARMv7 did not support\n// this feature but ARMv8 does. As it stands today, this header file assumes\n// ARMv8.  If you are trying to target really old ARM devices, you may get a\n// build error.\n\n/*\n * The MIT license:\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#if defined(__GNUC__) || defined(__clang__)\n\n#pragma push_macro(\"FORCE_INLINE\")\n#pragma push_macro(\"ALIGN_STRUCT\")\n#define FORCE_INLINE static inline __attribute__((always_inline))\n#define ALIGN_STRUCT(x) __attribute__((aligned(x)))\n\n#else\n\n#error \"Macro name collisions may happens with unknown compiler\"\n#ifdef FORCE_INLINE\n#undef FORCE_INLINE\n#endif\n#define FORCE_INLINE static inline\n#ifndef ALIGN_STRUCT\n#define ALIGN_STRUCT(x) __declspec(align(x))\n#endif\n\n#endif\n\n#include <stdint.h>\n#include \"arm_neon.h\"\n\n/**\n * MACRO for shuffle parameter for _mm_shuffle_ps().\n * Argument fp3 is a digit[0123] that represents the fp from argument \"b\"\n * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same\n * for fp2 in result. fp1 is a digit[0123] that represents the fp from\n * argument \"a\" of mm_shuffle_ps that will be places in fp1 of result.\n * fp0 is the same for fp0 of result.\n */\n#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \\\n    (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))\n\n/* indicate immediate constant argument in a given range */\n#define __constrange(a, b) const\n\ntypedef float32x2_t __m64;\ntypedef float32x4_t __m128;\ntypedef int32x4_t __m128i;\n\n// ******************************************\n// type-safe casting between types\n// ******************************************\n\n#define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x)\n#define vreinterpretq_m128_f32(x) (x)\n#define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x)\n\n#define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x)\n#define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x)\n#define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x)\n#define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x)\n\n#define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x)\n#define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x)\n#define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x)\n#define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x)\n\n#define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x)\n#define vreinterpretq_f32_m128(x) (x)\n#define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x)\n\n#define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x)\n#define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x)\n#define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x)\n#define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x)\n\n#define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x)\n#define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x)\n#define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x)\n#define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x)\n\n#define vreinterpretq_m128i_s8(x) vreinterpretq_s32_s8(x)\n#define vreinterpretq_m128i_s16(x) vreinterpretq_s32_s16(x)\n#define vreinterpretq_m128i_s32(x) (x)\n#define vreinterpretq_m128i_s64(x) vreinterpretq_s32_s64(x)\n\n#define vreinterpretq_m128i_u8(x) vreinterpretq_s32_u8(x)\n#define vreinterpretq_m128i_u16(x) vreinterpretq_s32_u16(x)\n#define vreinterpretq_m128i_u32(x) vreinterpretq_s32_u32(x)\n#define vreinterpretq_m128i_u64(x) vreinterpretq_s32_u64(x)\n\n#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s32(x)\n#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s32(x)\n#define vreinterpretq_s32_m128i(x) (x)\n#define vreinterpretq_s64_m128i(x) vreinterpretq_s64_s32(x)\n\n#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s32(x)\n#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s32(x)\n#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s32(x)\n#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s32(x)\n\n// union intended to allow direct access to an __m128 variable using the names\n// that the MSVC compiler provides.  This union should really only be used when\n// trying to access the members of the vector as integer values.  GCC/clang\n// allow native access to the float members through a simple array access\n// operator (in C since 4.6, in C++ since 4.8).\n//\n// Ideally direct accesses to SIMD vectors should not be used since it can cause\n// a performance hit.  If it really is needed however, the original __m128\n// variable can be aliased with a pointer to this union and used to access\n// individual components.  The use of this union should be hidden behind a macro\n// that is used throughout the codebase to access the members instead of always\n// declaring this type of variable.\n#if defined(__GNUC__) && !defined(__clang__)\ntypedef int32_t sint32_t __attribute__((vector_size(16)));\n#endif\ntypedef union ALIGN_STRUCT(16) SIMDVec {\n    float m128_f32[4];     // as floats - do not to use this.  Added for convenience.\n    int8_t m128_i8[16];    // as signed 8-bit integers.\n    int16_t m128_i16[8];   // as signed 16-bit integers.\n    #if defined(__GNUC__) && !defined(__clang__)\n    sint32_t m128_s32;\n    #endif\n    int32_t m128_i32[4];   // as signed 32-bit integers.\n    int64_t m128_i64[2];   // as signed 64-bit integers.\n    uint8_t m128_u8[16];   // as unsigned 8-bit integers.\n    uint16_t m128_u16[8];  // as unsigned 16-bit integers.\n    uint32_t m128_u32[4];  // as unsigned 32-bit integers.\n    uint64_t m128_u64[2];  // as unsigned 64-bit integers.\n} SIMDVec;\n\n// casting using SIMDVec\n#define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n])\n#define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n])\n\n\n// ******************************************\n// Backwards compatibility for compilers with lack of specific type support\n// ******************************************\n\n// Older gcc does not define vld1q_u8_x4 type\n#if defined(__GNUC__) && !defined(__clang__)\n#if __GNUC__ < 9 || (__GNUC__ == 9 && (__GNUC_MINOR__ <= 2))\nFORCE_INLINE uint8x16x4_t vld1q_u8_x4(const uint8_t *p)\n{\n    uint8x16x4_t ret;\n    ret.val[0] = vld1q_u8(p + 0);\n    ret.val[1] = vld1q_u8(p + 16);\n    ret.val[2] = vld1q_u8(p + 32);\n    ret.val[3] = vld1q_u8(p + 48);\n    return ret;\n}\n#endif\n#endif\n\n\n// ******************************************\n// Set/get methods\n// ******************************************\n\n// Loads one cache line of data from address p to a location closer to the\n// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx\nFORCE_INLINE void _mm_prefetch(const void *p, int i)\n{\n    __builtin_prefetch(p);\n}\n\n// extracts the lower order floating point value from the parameter :\n// https://msdn.microsoft.com/en-us/library/bb514059%28v=vs.120%29.aspx?f=255&MSPPError=-2147217396\nFORCE_INLINE float _mm_cvtss_f32(__m128 a)\n{\n    return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);\n}\n\n// Sets the 128-bit value to zero\n// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_setzero_si128(void)\n{\n    return vreinterpretq_m128i_s32(vdupq_n_s32(0));\n}\n\n// Clears the four single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_setzero_ps(void)\n{\n    return vreinterpretq_m128_f32(vdupq_n_f32(0));\n}\n\n// Sets the four single-precision, floating-point values to w.\n//\n//   r0 := r1 := r2 := r3 := w\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_set1_ps(float _w)\n{\n    return vreinterpretq_m128_f32(vdupq_n_f32(_w));\n}\n\n// Sets the four single-precision, floating-point values to w.\n// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_set_ps1(float _w)\n{\n    return vreinterpretq_m128_f32(vdupq_n_f32(_w));\n}\n\n// Sets the four single-precision, floating-point values to the four inputs.\n// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)\n{\n    float __attribute__((aligned(16))) data[4] = {x, y, z, w};\n    return vreinterpretq_m128_f32(vld1q_f32(data));\n}\n\n// Sets the four single-precision, floating-point values to the four inputs in\n// reverse order.\n// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x)\n{\n    float __attribute__((aligned(16))) data[4] = {w, z, y, x};\n    return vreinterpretq_m128_f32(vld1q_f32(data));\n}\n\n// Sets the 8 signed 16-bit integer values in reverse order.\n//\n// Return Value\n//   r0 := w0\n//   r1 := w1\n//   ...\n//   r7 := w7\nFORCE_INLINE __m128i _mm_setr_epi16(short w0,\n                                    short w1,\n                                    short w2,\n                                    short w3,\n                                    short w4,\n                                    short w5,\n                                    short w6,\n                                    short w7)\n{\n    int16_t __attribute__((aligned(16)))\n    data[8] = {w0, w1, w2, w3, w4, w5, w6, w7};\n    return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data));\n}\n\n// Sets the 4 signed 32-bit integer values in reverse order\n// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0)\n{\n    int32_t __attribute__((aligned(16))) data[4] = {i3, i2, i1, i0};\n    return vreinterpretq_m128i_s32(vld1q_s32(data));\n}\n\n// Sets the 16 signed 8-bit integer values to b.\n//\n//   r0 := b\n//   r1 := b\n//   ...\n//   r15 := b\n//\n// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_set1_epi8(char w)\n{\n    return vreinterpretq_m128i_s8(vdupq_n_s8(w));\n}\n\n// Sets the 8 signed 16-bit integer values to w.\n//\n//   r0 := w\n//   r1 := w\n//   ...\n//   r7 := w\n//\n// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_set1_epi16(short w)\n{\n    return vreinterpretq_m128i_s16(vdupq_n_s16(w));\n}\n\n// Sets the 16 signed 8-bit integer values.\n// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_set_epi8(char b15,\n                                  char b14,\n                                  char b13,\n                                  char b12,\n                                  char b11,\n                                  char b10,\n                                  char b9,\n                                  char b8,\n                                  char b7,\n                                  char b6,\n                                  char b5,\n                                  char b4,\n                                  char b3,\n                                  char b2,\n                                  char b1,\n                                  char b0)\n{\n    int8_t __attribute__((aligned(16)))\n    data[16] = {(int8_t) b0,  (int8_t) b1,  (int8_t) b2,  (int8_t) b3,\n                (int8_t) b4,  (int8_t) b5,  (int8_t) b6,  (int8_t) b7,\n                (int8_t) b8,  (int8_t) b9,  (int8_t) b10, (int8_t) b11,\n                (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};\n    return (__m128i) vld1q_s8(data);\n}\n\n// Sets the 8 signed 16-bit integer values.\n// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_set_epi16(short i7,\n                                   short i6,\n                                   short i5,\n                                   short i4,\n                                   short i3,\n                                   short i2,\n                                   short i1,\n                                   short i0)\n{\n    int16_t __attribute__((aligned(16)))\n    data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};\n    return vreinterpretq_m128i_s16(vld1q_s16(data));\n}\n\n// Sets the 16 signed 8-bit integer values in reverse order.\n// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_setr_epi8(char b0,\n                                   char b1,\n                                   char b2,\n                                   char b3,\n                                   char b4,\n                                   char b5,\n                                   char b6,\n                                   char b7,\n                                   char b8,\n                                   char b9,\n                                   char b10,\n                                   char b11,\n                                   char b12,\n                                   char b13,\n                                   char b14,\n                                   char b15)\n{\n    int8_t __attribute__((aligned(16)))\n    data[16] = {(int8_t) b0,  (int8_t) b1,  (int8_t) b2,  (int8_t) b3,\n                (int8_t) b4,  (int8_t) b5,  (int8_t) b6,  (int8_t) b7,\n                (int8_t) b8,  (int8_t) b9,  (int8_t) b10, (int8_t) b11,\n                (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};\n    return (__m128i) vld1q_s8(data);\n}\n\n// Sets the 4 signed 32-bit integer values to i.\n//\n//   r0 := i\n//   r1 := i\n//   r2 := i\n//   r3 := I\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_set1_epi32(int _i)\n{\n    return vreinterpretq_m128i_s32(vdupq_n_s32(_i));\n}\n\n// Sets the 4 signed 64-bit integer values to i.\n// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_set1_epi64(int64_t _i)\n{\n    return vreinterpretq_m128i_s64(vdupq_n_s64(_i));\n}\n\n// Sets the 4 signed 32-bit integer values.\n// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)\n{\n    int32_t __attribute__((aligned(16))) data[4] = {i0, i1, i2, i3};\n    return vreinterpretq_m128i_s32(vld1q_s32(data));\n}\n\n// Returns the __m128i structure with its two 64-bit integer values\n// initialized to the values of the two 64-bit integers passed in.\n// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx\nFORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2)\n{\n    int64_t __attribute__((aligned(16))) data[2] = {i2, i1};\n    return vreinterpretq_m128i_s64(vld1q_s64(data));\n}\n\n// Stores four single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx\nFORCE_INLINE void _mm_store_ps(float *p, __m128 a)\n{\n    vst1q_f32(p, vreinterpretq_f32_m128(a));\n}\n\n// Stores four single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx\nFORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)\n{\n    vst1q_f32(p, vreinterpretq_f32_m128(a));\n}\n\n// Stores four 32-bit integer values as (as a __m128i value) at the address p.\n// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx\nFORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a)\n{\n    vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));\n}\n\n// Stores four 32-bit integer values as (as a __m128i value) at the address p.\n// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx\nFORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)\n{\n    vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));\n}\n\n// Stores the lower single - precision, floating - point value.\n// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx\nFORCE_INLINE void _mm_store_ss(float *p, __m128 a)\n{\n    vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0);\n}\n\n// Reads the lower 64 bits of b and stores them into the lower 64 bits of a.\n// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx\nFORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b)\n{\n    uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a));\n    uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b));\n    *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi));\n}\n\n// Stores the lower two single-precision floating point values of a to the\n// address p.\n//\n//   *p0 := b0\n//   *p1 := b1\n//\n// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx\nFORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a)\n{\n    *p = vget_low_f32(a);\n}\n\n// Loads a single single-precision, floating-point value, copying it into all\n// four words\n// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_load1_ps(const float *p)\n{\n    return vreinterpretq_m128_f32(vld1q_dup_f32(p));\n}\n#define _mm_load_ps1 _mm_load1_ps\n\n// Sets the lower two single-precision, floating-point values with 64\n// bits of data loaded from the address p; the upper two values are passed\n// through from a.\n//\n// Return Value\n//   r0 := *p0\n//   r1 := *p1\n//   r2 := a2\n//   r3 := a3\n//\n// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *b)\n{\n    return vreinterpretq_m128_f32(\n        vcombine_f32(vld1_f32((const float32_t *) b), vget_high_f32(a)));\n}\n\n// Loads four single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_load_ps(const float *p)\n{\n    return vreinterpretq_m128_f32(vld1q_f32(p));\n}\n\n// Loads four single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx\nFORCE_INLINE __m128 _mm_loadu_ps(const float *p)\n{\n    // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are\n    // equivalent for neon\n    return vreinterpretq_m128_f32(vld1q_f32(p));\n}\n\n// Loads an single - precision, floating - point value into the low word and\n// clears the upper three words.\n// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx\nFORCE_INLINE __m128 _mm_load_ss(const float *p)\n{\n    return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0));\n}\n\nFORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p)\n{\n    /* Load the lower 64 bits of the value pointed to by p into the\n     * lower 64 bits of the result, zeroing the upper 64 bits of the result.\n     */\n    return vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0));\n}\n\n// ******************************************\n// Logic/Binary operations\n// ******************************************\n\n// Compares for inequality.\n// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(vmvnq_u32(\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))));\n}\n\n// Computes the bitwise AND-NOT of the four single-precision, floating-point\n// values of a and b.\n//\n//   r0 := ~a0 & b0\n//   r1 := ~a1 & b1\n//   r2 := ~a2 & b2\n//   r3 := ~a3 & b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_s32(\n        vbicq_s32(vreinterpretq_s32_m128(b),\n                  vreinterpretq_s32_m128(a)));  // *NOTE* argument swap\n}\n\n// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the\n// 128-bit value in a.\n//\n//   r := (~a) & b\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vbicq_s32(vreinterpretq_s32_m128i(b),\n                  vreinterpretq_s32_m128i(a)));  // *NOTE* argument swap\n}\n\n// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in\n// b.\n//\n//   r := a & b\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Computes the bitwise AND of the four single-precision, floating-point values\n// of a and b.\n//\n//   r0 := a0 & b0\n//   r1 := a1 & b1\n//   r2 := a2 & b2\n//   r3 := a3 & b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_s32(\n        vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));\n}\n\n// Computes the bitwise OR of the four single-precision, floating-point values\n// of a and b.\n// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_s32(\n        vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));\n}\n\n// Computes bitwise EXOR (exclusive-or) of the four single-precision,\n// floating-point values of a and b.\n// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_s32(\n        veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));\n}\n\n// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b.\n//\n//   r := a | b\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in\n// b.  https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Moves the upper two values of B into the lower two values of A.\n//\n//   r3 := a3\n//   r2 := a2\n//   r1 := b3\n//   r0 := b2\nFORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B)\n{\n    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A));\n    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B));\n    return vreinterpretq_m128_f32(vcombine_f32(b32, a32));\n}\n\n// Moves the lower two values of B into the upper two values of A.\n//\n//   r3 := b1\n//   r2 := b0\n//   r1 := a1\n//   r0 := a0\nFORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B)\n{\n    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A));\n    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B));\n    return vreinterpretq_m128_f32(vcombine_f32(a10, b10));\n}\n\n// NEON does not provide this method\n// Creates a 4-bit mask from the most significant bits of the four\n// single-precision, floating-point values.\n// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx\nFORCE_INLINE int _mm_movemask_ps(__m128 a)\n{\n#if 0 /* C version */\n    uint32x4_t &ia = *(uint32x4_t *) &a;\n    return (ia[0] >> 31) | ((ia[1] >> 30) & 2) | ((ia[2] >> 29) & 4) |\n           ((ia[3] >> 28) & 8);\n#endif\n    static const uint32x4_t movemask = {1, 2, 4, 8};\n    static const uint32x4_t highbit = {0x80000000, 0x80000000, 0x80000000,\n                                       0x80000000};\n    uint32x4_t t0 = vreinterpretq_u32_m128(a);\n    uint32x4_t t1 = vtstq_u32(t0, highbit);\n    uint32x4_t t2 = vandq_u32(t1, movemask);\n    uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));\n    return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);\n}\n\nFORCE_INLINE __m128i _mm_abs_epi32(__m128i a)\n{\n    return vqabsq_s32(a);\n}\n\nFORCE_INLINE __m128i _mm_abs_epi16(__m128i a)\n{\n    return vreinterpretq_s32_s16(vqabsq_s16(vreinterpretq_s16_s32(a)));\n}\n\n// Takes the upper 64 bits of a and places it in the low end of the result\n// Takes the lower 64 bits of b and places it into the high end of the result.\nFORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)\n{\n    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(vcombine_f32(a32, b10));\n}\n\n// takes the lower two 32-bit values from a and swaps them and places in high\n// end of result takes the higher two 32 bit values from b and swaps them and\n// places in low end of result.\nFORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)\n{\n    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));\n    float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b)));\n    return vreinterpretq_m128_f32(vcombine_f32(a01, b23));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)\n{\n    float32x2_t a21 = vget_high_f32(\n        vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));\n    float32x2_t b03 = vget_low_f32(\n        vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));\n    return vreinterpretq_m128_f32(vcombine_f32(a21, b03));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)\n{\n    float32x2_t a03 = vget_low_f32(\n        vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));\n    float32x2_t b21 = vget_high_f32(\n        vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));\n    return vreinterpretq_m128_f32(vcombine_f32(a03, b21));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)\n{\n    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(vcombine_f32(a10, b10));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)\n{\n    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));\n    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(vcombine_f32(a01, b10));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)\n{\n    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));\n    float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b)));\n    return vreinterpretq_m128_f32(vcombine_f32(a01, b01));\n}\n\n// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the\n// high\nFORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)\n{\n    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(vcombine_f32(a10, b32));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)\n{\n    float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1);\n    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);\n    return vreinterpretq_m128_f32(vcombine_f32(a11, b00));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)\n{\n    float32x2_t a22 =\n        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);\n    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);\n    return vreinterpretq_m128_f32(vcombine_f32(a22, b00));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)\n{\n    float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0);\n    float32x2_t b22 =\n        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0);\n    return vreinterpretq_m128_f32(vcombine_f32(a00, b22));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)\n{\n    float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);\n    float32x2_t a22 =\n        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);\n    float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/\n    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(vcombine_f32(a02, b32));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)\n{\n    float32x2_t a33 =\n        vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1);\n    float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1);\n    return vreinterpretq_m128_f32(vcombine_f32(a33, b11));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)\n{\n    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));\n    float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2);\n    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);\n    float32x2_t b20 = vset_lane_f32(b2, b00, 1);\n    return vreinterpretq_m128_f32(vcombine_f32(a10, b20));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)\n{\n    float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));\n    float32_t b2 = vgetq_lane_f32(b, 2);\n    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);\n    float32x2_t b20 = vset_lane_f32(b2, b00, 1);\n    return vreinterpretq_m128_f32(vcombine_f32(a01, b20));\n}\n\nFORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)\n{\n    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));\n    float32_t b2 = vgetq_lane_f32(b, 2);\n    float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);\n    float32x2_t b20 = vset_lane_f32(b2, b00, 1);\n    return vreinterpretq_m128_f32(vcombine_f32(a32, b20));\n}\n\n// NEON does not support a general purpose permute intrinsic\n// Selects four specific single-precision, floating-point values from a and b,\n// based on the mask i.\n// https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx\n#if 0 /* C version */\nFORCE_INLINE __m128 _mm_shuffle_ps_default(__m128 a,\n                                           __m128 b,\n                                           __constrange(0, 255) int imm)\n{\n    __m128 ret;\n    ret[0] = a[imm & 0x3];\n    ret[1] = a[(imm >> 2) & 0x3];\n    ret[2] = b[(imm >> 4) & 0x03];\n    ret[3] = b[(imm >> 6) & 0x03];\n    return ret;\n}\n#endif\n#define _mm_shuffle_ps_default(a, b, imm)                                  \\\n    ({                                                                     \\\n        float32x4_t ret;                                                   \\\n        ret = vmovq_n_f32(                                                 \\\n            vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) &0x3));        \\\n        ret = vsetq_lane_f32(                                              \\\n            vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \\\n            ret, 1);                                                       \\\n        ret = vsetq_lane_f32(                                              \\\n            vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \\\n            ret, 2);                                                       \\\n        ret = vsetq_lane_f32(                                              \\\n            vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \\\n            ret, 3);                                                       \\\n        vreinterpretq_m128_f32(ret);                                       \\\n    })\n\n// FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255)\n// int imm)\n#define _mm_shuffle_ps(a, b, imm)                          \\\n    ({                                                     \\\n        __m128 ret;                                        \\\n        switch (imm) {                                     \\\n        case _MM_SHUFFLE(1, 0, 3, 2):                      \\\n            ret = _mm_shuffle_ps_1032((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 3, 0, 1):                      \\\n            ret = _mm_shuffle_ps_2301((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(0, 3, 2, 1):                      \\\n            ret = _mm_shuffle_ps_0321((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 1, 0, 3):                      \\\n            ret = _mm_shuffle_ps_2103((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(1, 0, 1, 0):                      \\\n            ret = _mm_movelh_ps((a), (b));                 \\\n            break;                                         \\\n        case _MM_SHUFFLE(1, 0, 0, 1):                      \\\n            ret = _mm_shuffle_ps_1001((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(0, 1, 0, 1):                      \\\n            ret = _mm_shuffle_ps_0101((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(3, 2, 1, 0):                      \\\n            ret = _mm_shuffle_ps_3210((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(0, 0, 1, 1):                      \\\n            ret = _mm_shuffle_ps_0011((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(0, 0, 2, 2):                      \\\n            ret = _mm_shuffle_ps_0022((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 2, 0, 0):                      \\\n            ret = _mm_shuffle_ps_2200((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(3, 2, 0, 2):                      \\\n            ret = _mm_shuffle_ps_3202((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(3, 2, 3, 2):                      \\\n            ret = _mm_movehl_ps((b), (a));                 \\\n            break;                                         \\\n        case _MM_SHUFFLE(1, 1, 3, 3):                      \\\n            ret = _mm_shuffle_ps_1133((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 0, 1, 0):                      \\\n            ret = _mm_shuffle_ps_2010((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 0, 0, 1):                      \\\n            ret = _mm_shuffle_ps_2001((a), (b));           \\\n            break;                                         \\\n        case _MM_SHUFFLE(2, 0, 3, 2):                      \\\n            ret = _mm_shuffle_ps_2032((a), (b));           \\\n            break;                                         \\\n        default:                                           \\\n            ret = _mm_shuffle_ps_default((a), (b), (imm)); \\\n            break;                                         \\\n        }                                                  \\\n        ret;                                               \\\n    })\n\n// Shuffle packed 8-bit integers in a according to shuffle control mask in the\n// corresponding 8-bit element of b, and store the results in dst.\n// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8&expand=5146\n#if 1\n// Alternative implementation from SIMDe - appears to be faster but requires more investigation.\ninline __attribute__((__always_inline__)) __attribute__((__artificial__)) __m128i _mm_shuffle_epi8(__m128i a, __m128i b)\n{\n  __m128i r;\n  for (uint64_t i = 0 ; i < 16 ; i++)\n  {\n    ((SIMDVec*)&r)->m128_u8[i] = ((SIMDVec*)&a)->m128_u8[((SIMDVec*)&b)->m128_u8[i] & 15] * ((~(((SIMDVec*)&b)->m128_u8[i]) >> 7) & 1);\n  }\n  return r;\n}\n#else\nFORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b)\n{\n#if __aarch64__\n    int8x16_t tbl = vreinterpretq_s8_m128i(a);   // input a\n    uint8x16_t idx = vreinterpretq_u8_m128i(b);  // input b\n    uint8_t __attribute__((aligned(16)))\n    mask[16] = {0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,\n                0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F};\n    uint8x16_t idx_masked =\n        vandq_u8(idx, vld1q_u8(mask));  // avoid using meaningless bits\n\n    return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked));\n#else\n    uint8_t *tbl = (uint8_t *) &a;  // input a\n    uint8_t *idx = (uint8_t *) &b;  // input b\n    int32_t r[4];\n\n    r[0] = ((idx[3] & 0x80) ? 0 : tbl[idx[3] % 16]) << 24;\n    r[0] |= ((idx[2] & 0x80) ? 0 : tbl[idx[2] % 16]) << 16;\n    r[0] |= ((idx[1] & 0x80) ? 0 : tbl[idx[1] % 16]) << 8;\n    r[0] |= ((idx[0] & 0x80) ? 0 : tbl[idx[0] % 16]);\n\n    r[1] = ((idx[7] & 0x80) ? 0 : tbl[idx[7] % 16]) << 24;\n    r[1] |= ((idx[6] & 0x80) ? 0 : tbl[idx[6] % 16]) << 16;\n    r[1] |= ((idx[5] & 0x80) ? 0 : tbl[idx[5] % 16]) << 8;\n    r[1] |= ((idx[4] & 0x80) ? 0 : tbl[idx[4] % 16]);\n\n    r[2] = ((idx[11] & 0x80) ? 0 : tbl[idx[11] % 16]) << 24;\n    r[2] |= ((idx[10] & 0x80) ? 0 : tbl[idx[10] % 16]) << 16;\n    r[2] |= ((idx[9] & 0x80) ? 0 : tbl[idx[9] % 16]) << 8;\n    r[2] |= ((idx[8] & 0x80) ? 0 : tbl[idx[8] % 16]);\n\n    r[3] = ((idx[15] & 0x80) ? 0 : tbl[idx[15] % 16]) << 24;\n    r[3] |= ((idx[14] & 0x80) ? 0 : tbl[idx[14] % 16]) << 16;\n    r[3] |= ((idx[13] & 0x80) ? 0 : tbl[idx[13] % 16]) << 8;\n    r[3] |= ((idx[12] & 0x80) ? 0 : tbl[idx[12] % 16]);\n\n    return vld1q_s32(r);\n#endif\n}\n#endif\n\n\n#if defined(__GNUC__) && !defined(__clang__)\n// Alternative implementation from SIMDe - appears to be faster but requires more investigation.\nFORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, int imm)\n{\n    const __m128i tmp_a_ = a;\n    __m128i r;\n    sint32_t args =  { ((imm)) & 3, ((imm) >> 2) & 3, ((imm) >> 4) & 3, ((imm) >> 6) & 3};\n    ((SIMDVec *)&r)->m128_s32 = __builtin_shuffle(\n                               ((SIMDVec *) &tmp_a_)->m128_s32,\n                               ((SIMDVec *) &tmp_a_)->m128_s32,\n                               args);\n       return r;\n}\n#else\n#if defined(ARCH_ARM64)\n    #define _mm_shuffle_epi32_splat(a, imm) vdupq_laneq_s32(a, (imm))\n#else\n    #define _mm_shuffle_epi32_splat(a, imm) vdupq_n_s32(vgetq_lane_s32(a, (imm)))\n#endif\ntemplate<typename A, size_t B> class IntrinsicShuffleEpi32Wrapper\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x4_t ret;\n        ret = vmovq_n_s32(vgetq_lane_s32(a, (B) & 0x3));\n        ret = vsetq_lane_s32(vgetq_lane_s32(a, ((B) >> 2) & 0x3), ret, 1);\n        ret = vsetq_lane_s32(vgetq_lane_s32(a, ((B) >> 4) & 0x3), ret, 2);\n        return vsetq_lane_s32(vgetq_lane_s32(a, ((B) >> 6) & 0x3), ret, 3);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 78>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a32 = vget_high_s32(a);\n        int32x2_t a10 = vget_low_s32(a);\n        return vcombine_s32(a32, a10);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 177>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a01 = vrev64_s32(vget_low_s32(a));\n        int32x2_t a23 = vrev64_s32(vget_high_s32(a));\n        return vcombine_s32(a01, a23);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 57>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return vextq_s32(a, a, 1);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 147>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return vextq_s32(a, a, 3);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 68>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a10 = vget_low_s32(a);\n        return vcombine_s32(a10, a10);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 65>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a01 = vrev64_s32(vget_low_s32(a));\n        int32x2_t a10 = vget_low_s32(a);\n        return vcombine_s32(a01, a10);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 17>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a01 = vrev64_s32(vget_low_s32(a));\n        return vcombine_s32(a01, a01);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 165>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a11 = vdup_lane_s32(vget_low_s32(a), 1);\n        int32x2_t a22 = vdup_lane_s32(vget_high_s32(a), 0);\n        return vcombine_s32(a11, a22);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 26>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a22 = vdup_lane_s32(vget_high_s32(a), 0);\n        int32x2_t a01 = vrev64_s32(vget_low_s32(a));\n        return vcombine_s32(a22, a01);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 254>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        int32x2_t a32 = vget_high_s32(a);\n    int32x2_t a33 = vdup_lane_s32(vget_high_s32(a), 1);\n    return vcombine_s32(a32, a33);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 0>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return _mm_shuffle_epi32_splat((a),0);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 85>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return _mm_shuffle_epi32_splat((a),1);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 170>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return _mm_shuffle_epi32_splat((a),2);\n    }\n};\ntemplate<typename A> class IntrinsicShuffleEpi32Wrapper<A, 255>\n{\n    public:\n    static __m128i perform_mm_shuffle_epi32(A a)\n    {\n        return _mm_shuffle_epi32_splat((a),3);\n    }\n};\n#define _mm_shuffle_epi32(A, B) IntrinsicShuffleEpi32Wrapper<decltype(A), B>::perform_mm_shuffle_epi32(A);\n#endif\n\n// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified\n// by imm.  https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx\n// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,\n// __constrange(0,255) int imm)\n#define _mm_shufflelo_epi16_function(a, imm)                                  \\\n    ({                                                                        \\\n        int16x8_t ret = vreinterpretq_s16_s32(a);                             \\\n        int16x4_t lowBits = vget_low_s16(ret);                                \\\n        ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) &0x3), ret, 4);     \\\n        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \\\n                             5);                                              \\\n        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \\\n                             6);                                              \\\n        ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \\\n                             7);                                              \\\n        vreinterpretq_s32_s16(ret);                                           \\\n    })\n\n// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, __constrange(0,255) int\n// imm)\n#define _mm_shufflelo_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))\n\n// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified\n// by imm.  https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx\n// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,\n// __constrange(0,255) int imm)\n#define _mm_shufflehi_epi16_function(a, imm)                                   \\\n    ({                                                                         \\\n        int16x8_t ret = vreinterpretq_s16_s32(a);                              \\\n        int16x4_t highBits = vget_high_s16(ret);                               \\\n        ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) &0x3), ret, 4);     \\\n        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \\\n                             5);                                               \\\n        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \\\n                             6);                                               \\\n        ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \\\n                             7);                                               \\\n        vreinterpretq_s32_s16(ret);                                            \\\n    })\n\n// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, __constrange(0,255) int\n// imm)\n#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))\n\n// Shifts the 4 signed 32-bit integers in a right by count bits while shifting\n// in the sign bit.\n//\n//   r0 := a0 >> count\n//   r1 := a1 >> count\n//   r2 := a2 >> count\n//   r3 := a3 >> count immediate\nFORCE_INLINE __m128i _mm_srai_epi32(__m128i a, int count)\n{\n    return vshlq_s32(a, vdupq_n_s32(-count));\n}\n\n// Shifts the 8 signed 16-bit integers in a right by count bits while shifting\n// in the sign bit.\n//\n//   r0 := a0 >> count\n//   r1 := a1 >> count\n//   ...\n//   r7 := a7 >> count\nFORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int count)\n{\n    return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count));\n}\n\n// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while\n// shifting in zeros.\n//\n//   r0 := a0 << count\n//   r1 := a1 << count\n//   ...\n//   r7 := a7 << count\n//\n// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx\n#define _mm_slli_epi16(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 31) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_s16(                       \\\n                vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while\n// shifting in zeros. :\n// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx\n// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm)\n#define _mm_slli_epi32(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 31) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_s32(                       \\\n                vshlq_n_s32(vreinterpretq_s32_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and\n// store the results in dst.\n#define _mm_slli_epi64(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 63) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_s64(                       \\\n                vshlq_n_s64(vreinterpretq_s64_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits\n// while shifting in zeros.\n//\n//   r0 := srl(a0, count)\n//   r1 := srl(a1, count)\n//   ...\n//   r7 := srl(a7, count)\n//\n// https://msdn.microsoft.com/en-us/library/6tcwd38t(v=vs.90).aspx\n#define _mm_srli_epi16(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 31) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_u16(                       \\\n                vshrq_n_u16(vreinterpretq_u16_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits\n// while shifting in zeros.\n// https://msdn.microsoft.com/en-us/library/w486zcfa(v=vs.100).aspx FORCE_INLINE\n// __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm)\n#define _mm_srli_epi32(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 31) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_u32(                       \\\n                vshrq_n_u32(vreinterpretq_u32_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and\n// store the results in dst.\n#define _mm_srli_epi64(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 63) {                                 \\\n            ret = _mm_setzero_si128();                           \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_u64(                       \\\n                vshrq_n_u64(vreinterpretq_u64_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shifts the 4 signed 32 - bit integers in a right by count bits while shifting\n// in the sign bit.\n// https://msdn.microsoft.com/en-us/library/z1939387(v=vs.100).aspx\n// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm)\n#define _mm_srai_epi32(a, imm)                                   \\\n    ({                                                           \\\n        __m128i ret;                                             \\\n        if ((imm) <= 0) {                                        \\\n            ret = a;                                             \\\n        } else if ((imm) > 31) {                                 \\\n            ret = vreinterpretq_m128i_s32(                       \\\n                vshrq_n_s32(vreinterpretq_s32_m128i(a), 16));    \\\n            ret = vreinterpretq_m128i_s32(                       \\\n                vshrq_n_s32(vreinterpretq_s32_m128i(ret), 16));  \\\n        } else {                                                 \\\n            ret = vreinterpretq_m128i_s32(                       \\\n                vshrq_n_s32(vreinterpretq_s32_m128i(a), (imm))); \\\n        }                                                        \\\n        ret;                                                     \\\n    })\n\n// Shifts the 128 - bit value in a right by imm bytes while shifting in\n// zeros.imm must be an immediate.\n//\n//   r := srl(a, imm*8)\n//\n// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx\n// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm)\n#define _mm_srli_si128(a, imm)                                              \\\n    ({                                                                      \\\n        __m128i ret;                                                        \\\n        if ((imm) <= 0) {                                                   \\\n            ret = a;                                                        \\\n        } else if ((imm) > 15) {                                            \\\n            ret = _mm_setzero_si128();                                      \\\n        } else {                                                            \\\n            ret = vreinterpretq_m128i_s8(                                   \\\n                vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \\\n        }                                                                   \\\n        ret;                                                                \\\n    })\n\n// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm\n// must be an immediate.\n//\n//   r := a << (imm * 8)\n//\n// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx\n// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm)\n#define _mm_slli_si128(a, imm)                                          \\\n    ({                                                                  \\\n        __m128i ret;                                                    \\\n        if ((imm) <= 0) {                                               \\\n            ret = a;                                                    \\\n        } else if ((imm) > 15) {                                        \\\n            ret = _mm_setzero_si128();                                  \\\n        } else {                                                        \\\n            ret = vreinterpretq_m128i_s8(vextq_s8(                      \\\n                vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \\\n        }                                                               \\\n        ret;                                                            \\\n    })\n\n// NEON does not provide a version of this function, here is an article about\n// some ways to repro the results.\n// http://stackoverflow.com/questions/11870910/sse-mm-movemask-epi8-equivalent-method-for-arm-neon\n// Creates a 16-bit mask from the most significant bits of the 16 signed or\n// unsigned 8-bit integers in a and zero extends the upper bits.\n// https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx\nFORCE_INLINE int _mm_movemask_epi8(__m128i _a)\n{\n    uint8x16_t input = vreinterpretq_u8_m128i(_a);\n    static const int8_t __attribute__((aligned(16)))\n    xr[8] = {-7, -6, -5, -4, -3, -2, -1, 0};\n    uint8x8_t mask_and = vdup_n_u8(0x80);\n    int8x8_t mask_shift = vld1_s8(xr);\n\n    uint8x8_t lo = vget_low_u8(input);\n    uint8x8_t hi = vget_high_u8(input);\n\n    lo = vand_u8(lo, mask_and);\n    lo = vshl_u8(lo, mask_shift);\n\n    hi = vand_u8(hi, mask_and);\n    hi = vshl_u8(hi, mask_shift);\n\n    lo = vpadd_u8(lo, lo);\n    lo = vpadd_u8(lo, lo);\n    lo = vpadd_u8(lo, lo);\n\n    hi = vpadd_u8(hi, hi);\n    hi = vpadd_u8(hi, hi);\n    hi = vpadd_u8(hi, hi);\n\n    return ((hi[0] << 8) | (lo[0] & 0xFF));\n}\n\n// Compute the bitwise AND of 128 bits (representing integer data) in a and\n// mask, and return 1 if the result is zero, otherwise return 0.\n// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros&expand=5871\nFORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask)\n{\n    int64x2_t a_and_mask =\n        vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask));\n    return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0\n                                                                           : 1;\n}\n\n// ******************************************\n// Math operations\n// ******************************************\n\n// Subtracts the four single-precision, floating-point values of a and b.\n//\n//   r0 := a0 - b0\n//   r1 := a1 - b1\n//   r2 := a2 - b2\n//   r3 := a3 - b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_f32(\n        vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a,\n// and store the results in dst.\n//    r0 := a0 - b0\n//    r1 := a1 - b1\nFORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s64(\n        vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));\n}\n\n// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or\n// unsigned 32-bit integers of a.\n//\n//   r0 := a0 - b0\n//   r1 := a1 - b1\n//   r2 := a2 - b2\n//   r3 := a3 - b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128_f32(\n        vsubq_s32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\nFORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\nFORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s8(\n        vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));\n}\n\n// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit\n// integers of a and saturates..\n// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u16(\n        vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));\n}\n\n// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit\n// integers of a and saturates.\n//\n//   r0 := UnsignedSaturate(a0 - b0)\n//   r1 := UnsignedSaturate(a1 - b1)\n//   ...\n//   r15 := UnsignedSaturate(a15 - b15)\n//\n// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90)\nFORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));\n}\n\n// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers\n// of a and saturates.\n//\n//   r0 := SignedSaturate(a0 - b0)\n//   r1 := SignedSaturate(a1 - b1)\n//   ...\n//   r7 := SignedSaturate(a7 - b7)\nFORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\nFORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u16(\n        vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));\n}\n\nFORCE_INLINE __m128i _mm_sign_epi32(__m128i a, __m128i b)\n{\n    __m128i zer0 = vdupq_n_s32(0);\n    __m128i ltMask = vreinterpretq_s32_u32(vcltq_s32(b, zer0));\n    __m128i gtMask = vreinterpretq_s32_u32(vcgtq_s32(b, zer0));\n    __m128i neg = vnegq_s32(a);\n    __m128i tmp = vandq_s32(a, gtMask);\n    return vorrq_s32(tmp, vandq_s32(neg, ltMask));\n}\n\nFORCE_INLINE __m128i _mm_sign_epi16(__m128i a, __m128i b)\n{\n    int16x8_t zer0 = vdupq_n_s16(0);\n    int16x8_t ltMask =\n        vreinterpretq_s16_u16(vcltq_s16(vreinterpretq_s16_s32(b), zer0));\n    int16x8_t gtMask =\n        vreinterpretq_s16_u16(vcgtq_s16(vreinterpretq_s16_s32(b), zer0));\n    int16x8_t neg = vnegq_s16(vreinterpretq_s16_s32(a));\n    int16x8_t tmp = vandq_s16(vreinterpretq_s16_s32(a), gtMask);\n    return vreinterpretq_s32_s16(vorrq_s16(tmp, vandq_s16(neg, ltMask)));\n}\n\n// Adds the four single-precision, floating-point values of a and b.\n//\n//   r0 := a0 + b0\n//   r1 := a1 + b1\n//   r2 := a2 + b2\n//   r3 := a3 + b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_f32(\n        vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// adds the scalar single-precision floating point values of a and b.\n// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)\n{\n    float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);\n    float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0);\n    // the upper values in the result must be the remnants of <a>.\n    return vreinterpretq_m128_f32(vaddq_f32(a, value));\n}\n\n// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or\n// unsigned 32-bit integers in b.\n// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b)\n{\n    return vreinterpretq_s32_s64(\n        vaddq_s64(vreinterpretq_s64_s32(a), vreinterpretq_s64_s32(b)));\n}\n\n// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or\n// unsigned 32-bit integers in b.\n//\n//   r0 := a0 + b0\n//   r1 := a1 + b1\n//   r2 := a2 + b2\n//   r3 := a3 + b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or\n// unsigned 16-bit integers in b.\n// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or\n// unsigned 8-bit integers in b.\n// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90)\nFORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s8(\n        vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));\n}\n\n// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b\n// and saturates.\n//\n//   r0 := SignedSaturate(a0 + b0)\n//   r1 := SignedSaturate(a1 + b1)\n//   ...\n//   r7 := SignedSaturate(a7 + b7)\n//\n// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in\n// b and saturates..\n// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));\n}\n\n// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or\n// unsigned 16-bit integers from b.\n//\n//   r0 := (a0 * b0)[15:0]\n//   r1 := (a1 * b1)[15:0]\n//   ...\n//   r7 := (a7 * b7)[15:0]\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or\n// unsigned 32-bit integers from b.\n// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Multiplies the four single-precision, floating-point values of a and b.\n//\n//   r0 := a0 * b0\n//   r1 := a1 * b1\n//   r2 := a2 * b2\n//   r3 := a3 * b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_f32(\n        vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Multiply the low unsigned 32-bit integers from each packed 64-bit element in\n// a and b, and store the unsigned 64-bit results in dst.\n//\n//   r0 :=  (uint32_t*)a0 * (uint32_t*)b0\n//   r1 :=  (uint32_t*)a3 * (uint32_t*)b3\n#if 1 /* C version */\nFORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)\n{\n    __m128i d;\n    vreinterpretq_nth_u64_m128i(d, 0) =\n        (uint64_t)(vreinterpretq_nth_u32_m128i(a, 0)) *\n        (uint64_t)(vreinterpretq_nth_u32_m128i(b, 0));\n    vreinterpretq_nth_u64_m128i(d, 1) =\n        (uint64_t)(vreinterpretq_nth_u32_m128i(a, 2)) *\n        (uint64_t)(vreinterpretq_nth_u32_m128i(b, 2));\n    return d;\n}\n#else /* Neon version */\n// Neon version not currently viable because there is no 64 bit multiply\n// 'vmulq_s64' Could become viable in future if a 64 bit multiply becomes\n// available.\nFORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)\n{\n    // Mask out the high 32-bit integers and then multiply them as 64-bit\n    uint32_t __attribute__((aligned(16)))\n    data[4] = {0xFFFFFFFF, 0, 0xFFFFFFFF, 0};\n    __m128i mask = vreinterpretq_m128i_u32(vld1q_u32(data));\n    return vreinterpretq_m128i_f32(\n        vmulq_s64(vreinterpretq_u32_m128(_mm_and_si128(a, mask)),\n                  vreinterpretq_u32_m128(_mm_and_si128(b, mask))));\n}\n#endif\n\n// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit\n// integers from b.\n//\n//   r0 := (a0 * b0) + (a1 * b1)\n//   r1 := (a2 * b2) + (a3 * b3)\n//   r2 := (a4 * b4) + (a5 * b5)\n//   r3 := (a6 * b6) + (a7 * b7)\n// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b)\n{\n    int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),\n                              vget_low_s16(vreinterpretq_s16_m128i(b)));\n    int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),\n                               vget_high_s16(vreinterpretq_s16_m128i(b)));\n\n    int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low));\n    int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high));\n\n    return vreinterpretq_s32_m128i(vcombine_s32(low_sum, high_sum));\n}\n\n// Computes the absolute difference of the 16 unsigned 8-bit integers from a\n// and the 16 unsigned 8-bit integers from b.\n//\n// Return Value\n// Sums the upper 8 differences and lower 8 differences and packs the\n// resulting 2 unsigned 16-bit integers into the upper and lower 64-bit\n// elements.\n//\n//   r0 := abs(a0 - b0) + abs(a1 - b1) +...+ abs(a7 - b7)\n//   r1 := 0x0\n//   r2 := 0x0\n//   r3 := 0x0\n//   r4 := abs(a8 - b8) + abs(a9 - b9) +...+ abs(a15 - b15)\n//   r5 := 0x0\n//   r6 := 0x0\n//   r7 := 0x0\nFORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b)\n{\n    uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b));\n    uint16_t r0 = t[0] + t[1] + t[2] + t[3];\n    uint16_t r4 = t[4] + t[5] + t[6] + t[7];\n    uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0);\n    return (__m128i) vsetq_lane_u16(r4, r, 4);\n}\n\n// Divides the four single-precision, floating-point values of a and b.\n//\n//   r0 := a0 / b0\n//   r1 := a1 / b1\n//   r2 := a2 / b2\n//   r3 := a3 / b3\n//\n// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)\n{\n    float32x4_t recip0 = vrecpeq_f32(vreinterpretq_f32_m128(b));\n    float32x4_t recip1 =\n        vmulq_f32(recip0, vrecpsq_f32(recip0, vreinterpretq_f32_m128(b)));\n    return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip1));\n}\n\n// Divides the scalar single-precision floating point value of a by b.\n// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)\n{\n    float32_t value =\n        vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0);\n    return vreinterpretq_m128_f32(\n        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));\n}\n\n// This version does additional iterations to improve accuracy.  Between 1 and 4\n// recommended. Computes the approximations of reciprocals of the four\n// single-precision, floating-point values of a.\n// https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx\nFORCE_INLINE __m128 recipq_newton(__m128 in, int n)\n{\n    int i;\n    float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));\n    for (i = 0; i < n; ++i) {\n        recip =\n            vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));\n    }\n    return vreinterpretq_m128_f32(recip);\n}\n\n// Computes the approximations of reciprocals of the four single-precision,\n// floating-point values of a.\n// https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_rcp_ps(__m128 in)\n{\n    float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));\n    recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));\n    return vreinterpretq_m128_f32(recip);\n}\n\n// Computes the approximations of square roots of the four single-precision,\n// floating-point values of a. First computes reciprocal square roots and then\n// reciprocals of the four values.\n//\n//   r0 := sqrt(a0)\n//   r1 := sqrt(a1)\n//   r2 := sqrt(a2)\n//   r3 := sqrt(a3)\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)\n{\n    float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in));\n    float32x4_t sq = vrecpeq_f32(recipsq);\n    // ??? use step versions of both sqrt and recip for better accuracy?\n    return vreinterpretq_m128_f32(sq);\n}\n\n// Computes the approximation of the square root of the scalar single-precision\n// floating point value of in.\n// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)\n{\n    float32_t value =\n        vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0);\n    return vreinterpretq_m128_f32(\n        vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0));\n}\n\n// Computes the approximations of the reciprocal square roots of the four\n// single-precision floating point values of in.\n// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)\n{\n    return vreinterpretq_m128_f32(vrsqrteq_f32(vreinterpretq_f32_m128(in)));\n}\n\n// Computes the maximums of the four single-precision, floating-point values of\n// a and b.\n// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_f32(\n        vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Computes the minima of the four single-precision, floating-point values of a\n// and b.\n// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_f32(\n        vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Computes the maximum of the two lower scalar single-precision floating point\n// values of a and b.\n// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)\n{\n    float32_t value = vgetq_lane_f32(\n        vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)), 0);\n    return vreinterpretq_m128_f32(\n        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));\n}\n\n// Computes the minimum of the two lower scalar single-precision floating point\n// values of a and b.\n// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)\n{\n    float32_t value = vgetq_lane_f32(\n        vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)), 0);\n    return vreinterpretq_m128_f32(\n        vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));\n}\n\n// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the\n// 16 unsigned 8-bit integers from b.\n// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));\n}\n\n// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the\n// 16 unsigned 8-bit integers from b.\n// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx\nFORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));\n}\n\n// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8\n// signed 16-bit integers from b.\n// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8\n// signed 16-bit integers from b.\n// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// epi versions of min/max\n// Computes the pariwise maximums of the four signed 32-bit integer values of a\n// and b.\n//\n// A 128-bit parameter that can be defined with the following equations:\n//   r0 := (a0 > b0) ? a0 : b0\n//   r1 := (a1 > b1) ? a1 : b1\n//   r2 := (a2 > b2) ? a2 : b2\n//   r3 := (a3 > b3) ? a3 : b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Computes the pariwise minima of the four signed 32-bit integer values of a\n// and b.\n//\n// A 128-bit parameter that can be defined with the following equations:\n//   r0 := (a0 < b0) ? a0 : b0\n//   r1 := (a1 < b1) ? a1 : b1\n//   r2 := (a2 < b2) ? a2 : b2\n//   r3 := (a3 < b3) ? a3 : b3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s32(\n        vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit\n// integers from b.\n//\n//   r0 := (a0 * b0)[31:16]\n//   r1 := (a1 * b1)[31:16]\n//   ...\n//   r7 := (a7 * b7)[31:16]\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)\n{\n    /* FIXME: issue with large values because of result saturation */\n    // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a),\n    // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return\n    // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1));\n    int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a));\n    int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b));\n    int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */\n    int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a));\n    int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b));\n    int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */\n    uint16x8x2_t r =\n        vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654));\n    return vreinterpretq_m128i_u16(r.val[1]);\n}\n\n// Computes pairwise add of each argument as single-precision, floating-point\n// values a and b.\n// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx\nFORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b)\n{\n#if defined(__aarch64__)\n    return vreinterpretq_m128_f32(vpaddq_f32(\n        vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));  // AArch64\n#else\n    float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));\n    float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));\n    float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_f32(\n        vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32)));\n#endif\n}\n\n// ******************************************\n// Compare operations\n// ******************************************\n\n// Compares for less than\n// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(\n        vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Compares for greater than.\n//\n//   r0 := (a0 > b0) ? 0xffffffff : 0x0\n//   r1 := (a1 > b1) ? 0xffffffff : 0x0\n//   r2 := (a2 > b2) ? 0xffffffff : 0x0\n//   r3 := (a3 > b3) ? 0xffffffff : 0x0\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(\n        vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Compares for greater than or equal.\n// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(\n        vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Compares for less than or equal.\n//\n//   r0 := (a0 <= b0) ? 0xffffffff : 0x0\n//   r1 := (a1 <= b1) ? 0xffffffff : 0x0\n//   r2 := (a2 <= b2) ? 0xffffffff : 0x0\n//   r3 := (a3 <= b3) ? 0xffffffff : 0x0\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(\n        vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Compares for equality.\n// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)\n{\n    return vreinterpretq_m128_u32(\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n}\n\n// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or\n// unsigned 8-bit integers in b for equality.\n// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));\n}\n\n// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or\n// unsigned 16-bit integers in b for equality.\n// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u16(\n        vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n// Compare packed 32-bit integers in a and b for equality, and store the results\n// in dst\nFORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u32(\n        vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers\n// in b for lesser than.\n// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));\n}\n\n// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers\n// in b for greater than.\n//\n//   r0 := (a0 > b0) ? 0xff : 0x0\n//   r1 := (a1 > b1) ? 0xff : 0x0\n//   ...\n//   r15 := (a15 > b15) ? 0xff : 0x0\n//\n// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));\n}\n\n// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers\n// in b for greater than.\n//\n//   r0 := (a0 > b0) ? 0xffff : 0x0\n//   r1 := (a1 > b1) ? 0xffff : 0x0\n//   ...\n//   r7 := (a7 > b7) ? 0xffff : 0x0\n//\n// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u16(\n        vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));\n}\n\n\n// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers\n// in b for less than.\n// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u32(\n        vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers\n// in b for greater than.\n// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_u32(\n        vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));\n}\n\n// Compares the four 32-bit floats in a and b to check if any values are NaN.\n// Ordered compare between each value returns true for \"orderable\" and false for\n// \"not orderable\" (NaN).\n// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see\n// also:\n// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean\n// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics\nFORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b)\n{\n    // Note: NEON does not have ordered compare builtin\n    // Need to compare a eq a and b eq b to check for NaN\n    // Do AND of results to get final\n    uint32x4_t ceqaa =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t ceqbb =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb));\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using a less than operation. :\n// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important\n// note!! The documentation on MSDN is incorrect!  If either of the values is a\n// NAN the docs say you will get a one, but in fact, it will return a zero!!\nFORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)\n{\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));\n    uint32x4_t a_lt_b =\n        vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));\n    return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_lt_b), 0) != 0) ? 1 : 0;\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using a greater than operation. :\n// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx\nFORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)\n{\n    // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a),\n    // vreinterpretq_f32_m128(b)), 0);\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);\n    uint32x4_t a_gt_b =\n        vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));\n    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0;\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using a less than or equal operation. :\n// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx\nFORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)\n{\n    // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a),\n    // vreinterpretq_f32_m128(b)), 0);\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));\n    uint32x4_t a_le_b =\n        vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));\n    return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_le_b), 0) != 0) ? 1 : 0;\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using a greater than or equal operation. :\n// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx\nFORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)\n{\n    // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a),\n    // vreinterpretq_f32_m128(b)), 0);\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);\n    uint32x4_t a_ge_b =\n        vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));\n    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0;\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using an equality operation. :\n// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx\nFORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)\n{\n    // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),\n    // vreinterpretq_f32_m128(b)), 0);\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));\n    uint32x4_t a_eq_b =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));\n    return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_eq_b), 0) != 0) ? 1 : 0;\n}\n\n// Compares the lower single-precision floating point scalar values of a and b\n// using an inequality operation. :\n// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx\nFORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)\n{\n    // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),\n    // vreinterpretq_f32_m128(b)), 0);\n    uint32x4_t a_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));\n    uint32x4_t b_not_nan =\n        vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));\n    uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);\n    uint32x4_t a_neq_b = vmvnq_u32(\n        vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));\n    return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_neq_b), 0) != 0) ? 1\n                                                                         : 0;\n}\n\n// according to the documentation, these intrinsics behave the same as the\n// non-'u' versions.  We'll just alias them here.\n#define _mm_ucomilt_ss _mm_comilt_ss\n#define _mm_ucomile_ss _mm_comile_ss\n#define _mm_ucomigt_ss _mm_comigt_ss\n#define _mm_ucomige_ss _mm_comige_ss\n#define _mm_ucomieq_ss _mm_comieq_ss\n#define _mm_ucomineq_ss _mm_comineq_ss\n\n// ******************************************\n// Conversions\n// ******************************************\n\n// Converts the four single-precision, floating-point values of a to signed\n// 32-bit integer values using truncate.\n// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)\n{\n    return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)));\n}\n\n// Converts the four signed 32-bit integer values of a to single-precision,\n// floating-point values\n// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx\nFORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)\n{\n    return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a)));\n}\n\n// Converts the four unsigned 8-bit integers in the lower 32 bits to four\n// unsigned 32-bit integers.\n// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx\nFORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a)\n{\n    uint8x16_t u8x16 = vreinterpretq_u8_s32(a);        /* xxxx xxxx xxxx DCBA */\n    uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16));   /* 0x0x 0x0x 0D0C 0B0A */\n    uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */\n    return vreinterpretq_s32_u32(u32x4);\n}\n\n// Converts the four signed 16-bit integers in the lower 64 bits to four signed\n// 32-bit integers.\n// https://msdn.microsoft.com/en-us/library/bb514079%28v=vs.100%29.aspx\nFORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a)\n{\n    return vreinterpretq_m128i_s32(\n        vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a))));\n}\n\n// Converts the four single-precision, floating-point values of a to signed\n// 32-bit integer values.\n//\n//   r0 := (int) a0\n//   r1 := (int) a1\n//   r2 := (int) a2\n//   r3 := (int) a3\n//\n// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx\n// *NOTE*. The default rounding mode on SSE is 'round to even', which ArmV7-A\n// does not support! It is supported on ARMv8-A however.\nFORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)\n{\n#if defined(__aarch64__)\n    return vcvtnq_s32_f32(a);\n#else\n    uint32x4_t signmask = vdupq_n_u32(0x80000000);\n    float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a),\n                                 vdupq_n_f32(0.5f)); /* +/- 0.5 */\n    int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32(\n        vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/\n    int32x4_t r_trunc =\n        vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */\n    int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32(\n        vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */\n    int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone),\n                                 vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */\n    float32x4_t delta = vsubq_f32(\n        vreinterpretq_f32_m128(a),\n        vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */\n    uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */\n    return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal));\n#endif\n}\n\n// Moves the least significant 32 bits of a to a 32-bit integer.\n// https://msdn.microsoft.com/en-us/library/5z7a9642%28v=vs.90%29.aspx\nFORCE_INLINE int _mm_cvtsi128_si32(__m128i a)\n{\n    return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0);\n}\n\n// Extracts the low order 64-bit integer from the parameter.\n// https://msdn.microsoft.com/en-us/library/bb531384(v=vs.120).aspx\nFORCE_INLINE uint64_t _mm_cvtsi128_si64(__m128i a)\n{\n    return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0);\n}\n\n// Moves 32-bit integer a to the least significant 32 bits of an __m128 object,\n// zero extending the upper bits.\n//\n//   r0 := a\n//   r1 := 0x0\n//   r2 := 0x0\n//   r3 := 0x0\n//\n// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx\nFORCE_INLINE __m128i _mm_cvtsi32_si128(int a)\n{\n    return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0));\n}\n\n// Applies a type cast to reinterpret four 32-bit floating point values passed\n// in as a 128-bit parameter as packed 32-bit integers.\n// https://msdn.microsoft.com/en-us/library/bb514099.aspx\nFORCE_INLINE __m128i _mm_castps_si128(__m128 a)\n{\n    return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a));\n}\n\n// Applies a type cast to reinterpret four 32-bit integers passed in as a\n// 128-bit parameter as packed 32-bit floating point values.\n// https://msdn.microsoft.com/en-us/library/bb514029.aspx\nFORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)\n{\n    return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a));\n}\n\n// Loads 128-bit value. :\n// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx\nFORCE_INLINE __m128i _mm_load_si128(const __m128i *p)\n{\n    return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));\n}\n\n// Loads 128-bit value. :\n// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx\nFORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p)\n{\n    return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));\n}\n\n// ******************************************\n// Miscellaneous Operations\n// ******************************************\n\n// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and\n// saturates.\n// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx\nFORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s8(\n        vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)),\n                    vqmovn_s16(vreinterpretq_s16_m128i(b))));\n}\n\n// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned\n// integers and saturates.\n//\n//   r0 := UnsignedSaturate(a0)\n//   r1 := UnsignedSaturate(a1)\n//   ...\n//   r7 := UnsignedSaturate(a7)\n//   r8 := UnsignedSaturate(b0)\n//   r9 := UnsignedSaturate(b1)\n//   ...\n//   r15 := UnsignedSaturate(b7)\n//\n// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)\n{\n    return vreinterpretq_m128i_u8(\n        vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)),\n                    vqmovun_s16(vreinterpretq_s16_m128i(b))));\n}\n\n// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers\n// and saturates.\n//\n//   r0 := SignedSaturate(a0)\n//   r1 := SignedSaturate(a1)\n//   r2 := SignedSaturate(a2)\n//   r3 := SignedSaturate(a3)\n//   r4 := SignedSaturate(b0)\n//   r5 := SignedSaturate(b1)\n//   r6 := SignedSaturate(b2)\n//   r7 := SignedSaturate(b3)\n//\n// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx\nFORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)\n{\n    return vreinterpretq_m128i_s16(\n        vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)),\n                     vqmovn_s32(vreinterpretq_s32_m128i(b))));\n}\n\n// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower\n// 8 signed or unsigned 8-bit integers in b.\n//\n//   r0 := a0\n//   r1 := b0\n//   r2 := a1\n//   r3 := b1\n//   ...\n//   r14 := a7\n//   r15 := b7\n//\n// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx\nFORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)\n{\n    int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a)));\n    int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b)));\n    int8x8x2_t result = vzip_s8(a1, b1);\n    return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));\n}\n\n// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the\n// lower 4 signed or unsigned 16-bit integers in b.\n//\n//   r0 := a0\n//   r1 := b0\n//   r2 := a1\n//   r3 := b1\n//   r4 := a2\n//   r5 := b2\n//   r6 := a3\n//   r7 := b3\n//\n// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx\nFORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)\n{\n    int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a));\n    int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b));\n    int16x4x2_t result = vzip_s16(a1, b1);\n    return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));\n}\n\n// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the\n// lower 2 signed or unsigned 32 - bit integers in b.\n//\n//   r0 := a0\n//   r1 := b0\n//   r2 := a1\n//   r3 := b1\n//\n// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)\n{\n    int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a));\n    int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b));\n    int32x2x2_t result = vzip_s32(a1, b1);\n    return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));\n}\n\nFORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)\n{\n    int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a));\n    int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b));\n    return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l));\n}\n\n// Selects and interleaves the lower two single-precision, floating-point values\n// from a and b.\n//\n//   r0 := a0\n//   r1 := b0\n//   r2 := a1\n//   r3 := b1\n//\n// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx\nFORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)\n{\n    float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b));\n    float32x2x2_t result = vzip_f32(a1, b1);\n    return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));\n}\n\n// Selects and interleaves the upper two single-precision, floating-point values\n// from a and b.\n//\n//   r0 := a2\n//   r1 := b2\n//   r2 := a3\n//   r3 := b3\n//\n// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx\nFORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)\n{\n    float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a));\n    float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b));\n    float32x2x2_t result = vzip_f32(a1, b1);\n    return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));\n}\n\n// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper\n// 8 signed or unsigned 8-bit integers in b.\n//\n//   r0 := a8\n//   r1 := b8\n//   r2 := a9\n//   r3 := b9\n//   ...\n//   r14 := a15\n//   r15 := b15\n//\n// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)\n{\n    int8x8_t a1 =\n        vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a)));\n    int8x8_t b1 =\n        vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b)));\n    int8x8x2_t result = vzip_s8(a1, b1);\n    return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));\n}\n\n// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the\n// upper 4 signed or unsigned 16-bit integers in b.\n//\n//   r0 := a4\n//   r1 := b4\n//   r2 := a5\n//   r3 := b5\n//   r4 := a6\n//   r5 := b6\n//   r6 := a7\n//   r7 := b7\n//\n// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)\n{\n    int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a));\n    int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b));\n    int16x4x2_t result = vzip_s16(a1, b1);\n    return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));\n}\n\n// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the\n// upper 2 signed or unsigned 32-bit integers in b.\n// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx\nFORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)\n{\n    int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a));\n    int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b));\n    int32x2x2_t result = vzip_s32(a1, b1);\n    return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));\n}\n\n// Interleaves the upper signed or unsigned 64-bit integer in a with the\n// upper signed or unsigned 64-bit integer in b.\n//\n//   r0 := a1\n//   r1 := b1\nFORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)\n{\n    int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a));\n    int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b));\n    return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h));\n}\n\n// REMARK: this is not used in the current neon code and is commented our here\n// because it chokes the compiler (Xcode 11)\n// the parameter to vextq_s8 needs to be a compile-time constant because\n// the value is encoded in the generated arm instruction\n// shift to right\n// https://msdn.microsoft.com/en-us/library/bb514041(v=vs.120).aspx\n// http://blog.csdn.net/hemmingway/article/details/44828303\n//FORCE_INLINE __m128i _mm_alignr_epi8(__m128i a, __m128i b, const int c)\n//{\n//    return (__m128i) vextq_s8((int8x16_t) a, (int8x16_t) b, c);\n//}\n\n// Extracts the selected signed or unsigned 16-bit integer from a and zero\n// extends.  https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx\n// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm)\n#define _mm_extract_epi16(a, imm) \\\n    ({ (vgetq_lane_s16(vreinterpretq_s16_m128i(a), (imm)) & 0x0000ffffUL); })\n\n// Inserts the least significant 16 bits of b into the selected 16-bit integer\n// of a. https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx\n// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, const int b,\n// __constrange(0,8) int imm)\n#define _mm_insert_epi16(a, b, imm)                                  \\\n    ({                                                               \\\n        vreinterpretq_m128i_s16(                                     \\\n            vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \\\n    })\n\n// ******************************************\n// Streaming Extensions\n// ******************************************\n\n// Guarantees that every preceding store is globally visible before any\n// subsequent store.\n// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx\nFORCE_INLINE void _mm_sfence(void)\n{\n    __sync_synchronize();\n}\n\n// Stores the data in a to the address p without polluting the caches.  If the\n// cache line containing address p is already in the cache, the cache will be\n// updated.Address p must be 16 - byte aligned.\n// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx\nFORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)\n{\n    vst1q_s32((int32_t *) p, a);\n}\n\n// Cache line containing p is flushed and invalidated from all caches in the\n// coherency domain. :\n// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx\nFORCE_INLINE void _mm_clflush(void const *p)\n{\n    // no corollary for Neon?\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma pop_macro(\"ALIGN_STRUCT\")\n#pragma pop_macro(\"FORCE_INLINE\")\n#endif\n\n#endif\n\n"
  },
  {
    "path": "src/compat/strnlen.cpp",
    "content": "// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <cstring>\n\n#if HAVE_DECL_STRNLEN == 0\nsize_t strnlen( const char *start, size_t max_len)\n{\n    const char *end = (const char *)memchr(start, '\\0', max_len);\n\n    return end ? (size_t)(end - start) : max_len;\n}\n#endif // HAVE_DECL_STRNLEN\n"
  },
  {
    "path": "src/compat/sys.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file defines various operating system level helpers to get information about the current system\n\n#ifndef COMPAT_SYS_H\n#define COMPAT_SYS_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <stdint.h>\n#include <stdexcept>\n\n#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE!=0)\n    #define PLATFORM_MOBILE\n    #define PLATFORM_MOBILE_IOS\n#endif\n#if defined(__ANDROID__)\n    #define PLATFORM_MOBILE\n    #define PLATFORM_MOBILE_ANDROID\n#endif\n\n#ifdef PLATFORM_MOBILE\ninline uint64_t systemPhysicalMemoryInBytes()\n{\n    throw std::runtime_error(\"Don't call systemPhysicalMemoryInBytes() on mobile\");\n}\n#elif defined(WIN32)\n#include <windows.h>\ninline uint64_t systemPhysicalMemoryInBytes()\n{\n    MEMORYSTATUS status;\n    status.dwLength = sizeof(status);\n    GlobalMemoryStatus(&status);\n    return status.dwTotalPhys;\n}\n#elif defined(__APPLE__)\n#include <sys/types.h>\n#include <sys/sysctl.h>\ninline uint64_t systemPhysicalMemoryInBytes()\n{\n    int dataRequest[2];\n    dataRequest[0] = CTL_HW;\n    dataRequest[1] = HW_MEMSIZE;\n    int64_t totalRam = 0;\n    size_t dataLen = sizeof(totalRam);\n    if (sysctl(dataRequest, 2, &totalRam, &dataLen, nullptr, 0) == 0)\n        return totalRam;\n    return 0;\n}\n#else\n#include <sys/sysinfo.h>\ninline uint64_t systemPhysicalMemoryInBytes()\n{\n    struct sysinfo info;\n    sysinfo(&info);\n    return info.totalram/info.mem_unit;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/compat.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef COMPAT_H\n#define COMPAT_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#ifdef WIN32\n#ifdef _WIN32_WINNT\n#undef _WIN32_WINNT\n#endif\n#define _WIN32_WINNT 0x0501\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN 1\n#endif\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#ifdef FD_SETSIZE\n#undef FD_SETSIZE // prevent redefinition compiler warning\n#endif\n#define FD_SETSIZE 1024 // max number of fds in fd_set\n\n#include <winsock2.h>     // Must be included before mswsock.h and windows.h\n\n#include <mswsock.h>\n#include <windows.h>\n#include <ws2tcpip.h>\n#else\n#include <sys/fcntl.h>\n#include <sys/mman.h>\n#include <sys/select.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <net/if.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n#include <arpa/inet.h>\n#include <ifaddrs.h>\n#include <limits.h>\n#include <netdb.h>\n#include <unistd.h>\n#endif\n\n#ifndef WIN32\ntypedef unsigned int SOCKET;\n#include \"errno.h\"\n#define WSAGetLastError()   errno\n#define WSAEINVAL           EINVAL\n#define WSAEALREADY         EALREADY\n#define WSAEWOULDBLOCK      EWOULDBLOCK\n#define WSAEMSGSIZE         EMSGSIZE\n#define WSAEINTR            EINTR\n#define WSAEINPROGRESS      EINPROGRESS\n#define WSAEADDRINUSE       EADDRINUSE\n#define WSAENOTSOCK         EBADF\n#define INVALID_SOCKET      (SOCKET)(~0)\n#define SOCKET_ERROR        -1\n#endif\n\n#ifdef WIN32\n#ifndef S_IRUSR\n#define S_IRUSR             0400\n#define S_IWUSR             0200\n#endif\n#else\n#define MAX_PATH            1024\n#endif\n\n#if HAVE_DECL_STRNLEN == 0\nsize_t strnlen( const char *start, size_t max_len);\n#endif // HAVE_DECL_STRNLEN\n\n#endif\n"
  },
  {
    "path": "src/compressor.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"compressor.h\"\n\n#include \"hash.h\"\n#include \"pubkey.h\"\n#include \"script/standard.h\"\n\nbool CScriptCompressor::IsToKeyID(CKeyID &hash) const\n{\n    if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160\n                            && script[2] == 20 && script[23] == OP_EQUALVERIFY\n                            && script[24] == OP_CHECKSIG) {\n        memcpy(&hash, &script[3], 20);\n        return true;\n    }\n    return false;\n}\n\nbool CScriptCompressor::IsToScriptID(CScriptID &hash) const\n{\n    if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20\n                            && script[22] == OP_EQUAL) {\n        memcpy(&hash, &script[2], 20);\n        return true;\n    }\n    return false;\n}\n\nbool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const\n{\n    if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG\n                            && (script[1] == 0x02 || script[1] == 0x03)) {\n        pubkey.Set(&script[1], &script[34]);\n        return true;\n    }\n    if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG\n                            && script[1] == 0x04) {\n        pubkey.Set(&script[1], &script[66]);\n        return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible\n    }\n    return false;\n}\n\nbool CScriptCompressor::Compress(std::vector<unsigned char> &out) const\n{\n    CKeyID keyID;\n    if (IsToKeyID(keyID)) {\n        out.resize(21);\n        out[0] = 0x00;\n        memcpy(&out[1], &keyID, 20);\n        return true;\n    }\n    CScriptID scriptID;\n    if (IsToScriptID(scriptID)) {\n        out.resize(21);\n        out[0] = 0x01;\n        memcpy(&out[1], &scriptID, 20);\n        return true;\n    }\n    CPubKey pubkey;\n    if (IsToPubKey(pubkey)) {\n        out.resize(33);\n        memcpy(&out[1], &pubkey[1], 32);\n        if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {\n            out[0] = pubkey[0];\n            return true;\n        } else if (pubkey[0] == 0x04) {\n            out[0] = 0x04 | (pubkey[64] & 0x01);\n            return true;\n        }\n    }\n    return false;\n}\n\nunsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const\n{\n    if (nSize == 0 || nSize == 1)\n        return 20;\n    if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)\n        return 32;\n    return 0;\n}\n\nbool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)\n{\n    switch(nSize) {\n    case 0x00:\n        script.resize(25);\n        script[0] = OP_DUP;\n        script[1] = OP_HASH160;\n        script[2] = 20;\n        memcpy(&script[3], &in[0], 20);\n        script[23] = OP_EQUALVERIFY;\n        script[24] = OP_CHECKSIG;\n        return true;\n    case 0x01:\n        script.resize(23);\n        script[0] = OP_HASH160;\n        script[1] = 20;\n        memcpy(&script[2], &in[0], 20);\n        script[22] = OP_EQUAL;\n        return true;\n    case 0x02:\n    case 0x03:\n        script.resize(35);\n        script[0] = 33;\n        script[1] = nSize;\n        memcpy(&script[2], &in[0], 32);\n        script[34] = OP_CHECKSIG;\n        return true;\n    case 0x04:\n    case 0x05:\n        unsigned char vch[33] = {};\n        vch[0] = nSize - 2;\n        memcpy(&vch[1], &in[0], 32);\n        CPubKey pubkey(&vch[0], &vch[33]);\n        if (!pubkey.Decompress())\n            return false;\n        assert(pubkey.size() == 65);\n        script.resize(67);\n        script[0] = 65;\n        memcpy(&script[1], pubkey.begin(), 65);\n        script[66] = OP_CHECKSIG;\n        return true;\n    }\n    return false;\n}\n\n// Amount compression:\n// * If the amount is 0, output 0\n// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)\n// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)\n//   * call the result n\n//   * output 1 + 10*(9*n + d - 1) + e\n// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9\n// (this is decodable, as d is in [1-9] and e is in [0-9])\nuint64_t CompressAmount(uint64_t n)\n{\n    if (n == 0)\n        return 0;\n    int e = 0;\n    while (((n % 10) == 0) && e < 9) {\n        n /= 10;\n        e++;\n    }\n    if (e < 9) {\n        int d = (n % 10);\n        assert(d >= 1 && d <= 9);\n        n /= 10;\n        return 1 + (n*9 + d - 1)*10 + e;\n    } else {\n        return 1 + (n - 1)*10 + 9;\n    }\n}\n\nuint64_t DecompressAmount(uint64_t x)\n{\n    // x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9\n    if (x == 0)\n        return 0;\n    x--;\n    // x = 10*(9*n + d - 1) + e\n    int e = x % 10;\n    x /= 10;\n    uint64_t n = 0;\n    if (e < 9) {\n        // x = 9*n + d - 1\n        int d = (x % 9) + 1;\n        x /= 9;\n        // x = n\n        n = x*10 + d;\n    } else {\n        n = x+1;\n    }\n    while (e) {\n        n *= 10;\n        e--;\n    }\n    return n;\n}\n"
  },
  {
    "path": "src/compressor.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef COMPRESSOR_H\n#define COMPRESSOR_H\n\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"serialize.h\"\n\nclass CKeyID;\nclass CPubKey;\nclass CScriptID;\n\n/** Compact serializer for scripts.\n *\n *  It detects common cases and encodes them much more efficiently.\n *  3 special cases are defined:\n *  * Pay to pubkey hash (encoded as 21 bytes)\n *  * Pay to script hash (encoded as 21 bytes)\n *  * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)\n *\n *  Other scripts up to 121 bytes require 1 byte + script length. Above\n *  that, scripts up to 16505 bytes require 2 bytes + script length.\n */\nclass CScriptCompressor\n{\nprivate:\n    /**\n     * make this static for now (there are only 6 special scripts defined)\n     * this can potentially be extended together with a new nVersion for\n     * transactions, in which case this value becomes dependent on nVersion\n     * and nHeight of the enclosing transaction.\n     */\n    static const unsigned int nSpecialScripts = 6;\n\n    CScript &script;\nprotected:\n    /**\n     * These check for scripts for which a special case with a shorter encoding is defined.\n     * They are implemented separately from the CScript test, as these test for exact byte\n     * sequence correspondences, and are more strict. For example, IsToPubKey also verifies\n     * whether the public key is valid (as invalid ones cannot be represented in compressed\n     * form).\n     */\n    bool IsToKeyID(CKeyID &hash) const;\n    bool IsToScriptID(CScriptID &hash) const;\n    bool IsToPubKey(CPubKey &pubkey) const;\n\n    bool Compress(std::vector<unsigned char> &out) const;\n    unsigned int GetSpecialSize(unsigned int nSize) const;\n    bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);\npublic:\n    CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }\n\n    template<typename Stream>\n    void Serialize(Stream &s) const {\n        std::vector<unsigned char> compr;\n        if (Compress(compr)) {\n            s << CFlatData(compr);\n            return;\n        }\n        unsigned int nSize = script.size() + nSpecialScripts;\n        s << VARINT(nSize);\n        s << CFlatData(script);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream &s) {\n        unsigned int nSize = 0;\n        s >> VARINT(nSize);\n        if (nSize < nSpecialScripts) {\n            std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);\n            s >> REF(CFlatData(vch));\n            Decompress(nSize, vch);\n            return;\n        }\n        nSize -= nSpecialScripts;\n        if (nSize > MAX_SCRIPT_SIZE) {\n            // Overly long script, replace with a short invalid one\n            script << OP_RETURN;\n            s.ignore(nSize);\n        } else {\n            script.resize(nSize);\n            s >> REF(CFlatData(script));\n        }\n    }\n};\n\n/** wrapper for CTxOut that provides a more compact serialization */\n// This class basically becomes a no-op as our txouts are already compressed.\n#define CTxOutCompressor(x) x\n\nextern uint64_t CompressAmount(uint64_t nAmount);\nextern uint64_t DecompressAmount(uint64_t nAmount);\n\nclass CTxOutCompressorLegacy\n{\nprivate:\n    CTxOut &txout;\n\npublic:\n    CTxOutCompressorLegacy(CTxOut &txoutIn) : txout(txoutIn) { }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        if (!ser_action.ForRead()) {\n            uint64_t nVal = CompressAmount(txout.nValue);\n            READWRITE(VARINT(nVal));\n        } else {\n            uint64_t nVal = 0;\n            READWRITE(VARINT(nVal));\n            txout.nValue = DecompressAmount(nVal);\n        }\n        CScriptCompressor cscript(REF(txout.output.scriptPubKey));\n        READWRITE(cscript);\n    }\n};\n\n#define COMPRESSEDAMOUNT(obj) REF(CAmountCompressor(REF(obj)))\nclass CAmountCompressor\n{\nprivate:\n    CAmount &amount;\n\npublic:\n    CAmountCompressor(CAmount &amountIn) : amount(amountIn) { }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        if (!ser_action.ForRead()) {\n            uint64_t nValCompressed = CompressAmount(amount);\n            READWRITE(VARINT(nValCompressed));\n        } else {\n            uint64_t nValCompressed = 0;\n            READWRITE(VARINT(nValCompressed));\n            amount = DecompressAmount(nValCompressed);\n        }\n    }\n};\n#endif\n"
  },
  {
    "path": "src/config/.empty",
    "content": ""
  },
  {
    "path": "src/consensus/consensus.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CONSENSUS_CONSENSUS_H\n#define CONSENSUS_CONSENSUS_H\n\n#include <stdint.h>\n#include \"chainparams.h\"\n\n/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */\nstatic const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 1000000;\n/** The maximum allowed weight for a block, see BIP 141 (network rule) */\nstatic const unsigned int MAX_BLOCK_WEIGHT = MAX_BLOCK_SERIALIZED_SIZE;\n/** The maximum allowed size for a block excluding witness data, in bytes (network rule) */\nstatic const unsigned int MAX_BLOCK_BASE_SIZE = MAX_BLOCK_SERIALIZED_SIZE;\n/** The maximum allowed number of signature check operations in a block (network rule) */\nstatic const int64_t MAX_BLOCK_SIGOPS_COST = 80000;\n/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */\nstatic const int COINBASE_MATURITY_MAINNET = 100;\nstatic const int COINBASE_MATURITY_TESTNET = 10;\n\n#define COINBASE_MATURITY (::Params().IsTestnet() ? COINBASE_MATURITY_TESTNET : COINBASE_MATURITY_MAINNET)\n\n/** Flags for nSequence and nLockTime locks */\nenum {\n    /* Interpret sequence numbers as relative lock-time constraints. */\n    LOCKTIME_VERIFY_SEQUENCE = (1 << 0),\n\n    /* Use GetMedianTimePast() instead of nTime for end point timestamp. */\n    LOCKTIME_MEDIAN_TIME_PAST = (1 << 1),\n};\n\n#endif\n"
  },
  {
    "path": "src/consensus/merkle.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"merkle.h\"\n#include \"hash.h\"\n#include \"util/strencodings.h\"\n\n/*     WARNING! If you're reading this because you're learning about crypto\n       and/or designing a new system that will use merkle trees, keep in mind\n       that the following merkle tree algorithm has a serious flaw related to\n       duplicate txids, resulting in a vulnerability (CVE-2012-2459).\n\n       The reason is that if the number of hashes in the list at a given time\n       is odd, the last one is duplicated before computing the next level (which\n       is unusual in Merkle trees). This results in certain sequences of\n       transactions leading to the same merkle root. For example, these two\n       trees:\n\n                    A               A\n                  /  \\            /   \\\n                B     C         B       C\n               / \\    |        / \\     / \\\n              D   E   F       D   E   F   F\n             / \\ / \\ / \\     / \\ / \\ / \\ / \\\n             1 2 3 4 5 6     1 2 3 4 5 6 5 6\n\n       for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and\n       6 are repeated) result in the same root hash A (because the hash of both\n       of (F) and (F,F) is C).\n\n       The vulnerability results from being able to send a block with such a\n       transaction list, with the same merkle root, and the same block hash as\n       the original without duplication, resulting in failed validation. If the\n       receiving node proceeds to mark that block as permanently invalid\n       however, it will fail to accept further unmodified (and thus potentially\n       valid) versions of the same block. We defend against this by detecting\n       the case where we would hash two identical hashes at the end of the list\n       together, and treating that identically to the block having an invalid\n       merkle root. Assuming no double-SHA256 collisions, this will detect all\n       known ways of changing the transactions without affecting the merkle\n       root.\n*/\n\n/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */\nstatic void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) {\n    if (pbranch) pbranch->clear();\n    if (leaves.size() == 0) {\n        if (pmutated) *pmutated = false;\n        if (proot) *proot = uint256();\n        return;\n    }\n    bool mutated = false;\n    // count is the number of leaves processed so far.\n    uint32_t count = 0;\n    // inner is an array of eagerly computed subtree hashes, indexed by tree\n    // level (0 being the leaves).\n    // For example, when count is 25 (11001 in binary), inner[4] is the hash of\n    // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to\n    // the last leaf. The other inner entries are undefined.\n    uint256 inner[32];\n    // Which position in inner is a hash that depends on the matching leaf.\n    int matchlevel = -1;\n    // First process all leaves into 'inner' values.\n    while (count < leaves.size()) {\n        uint256 h = leaves[count];\n        bool matchh = count == branchpos;\n        count++;\n        int level;\n        // For each of the lower bits in count that are 0, do 1 step. Each\n        // corresponds to an inner value that existed before processing the\n        // current leaf, and each needs a hash to combine it.\n        for (level = 0; !(count & (((uint32_t)1) << level)); level++) {\n            if (pbranch) {\n                if (matchh) {\n                    pbranch->push_back(inner[level]);\n                } else if (matchlevel == level) {\n                    pbranch->push_back(h);\n                    matchh = true;\n                }\n            }\n            mutated |= (inner[level] == h);\n            CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());\n        }\n        // Store the resulting hash at inner position level.\n        inner[level] = h;\n        if (matchh) {\n            matchlevel = level;\n        }\n    }\n    // Do a final 'sweep' over the rightmost branch of the tree to process\n    // odd levels, and reduce everything to a single top value.\n    // Level is the level (counted from the bottom) up to which we've sweeped.\n    int level = 0;\n    // As long as bit number level in count is zero, skip it. It means there\n    // is nothing left at this level.\n    while (!(count & (((uint32_t)1) << level))) {\n        level++;\n    }\n    uint256 h = inner[level];\n    bool matchh = matchlevel == level;\n    while (count != (((uint32_t)1) << level)) {\n        // If we reach this point, h is an inner value that is not the top.\n        // We combine it with itself (Munt's special rule for odd levels in\n        // the tree) to produce a higher level one.\n        if (pbranch && matchh) {\n            pbranch->push_back(h);\n        }\n        CHash256().Write(h.begin(), 32).Write(h.begin(), 32).Finalize(h.begin());\n        // Increment count to the value it would have if two entries at this\n        // level had existed.\n        count += (((uint32_t)1) << level);\n        level++;\n        // And propagate the result upwards accordingly.\n        while (!(count & (((uint32_t)1) << level))) {\n            if (pbranch) {\n                if (matchh) {\n                    pbranch->push_back(inner[level]);\n                } else if (matchlevel == level) {\n                    pbranch->push_back(h);\n                    matchh = true;\n                }\n            }\n            CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());\n            level++;\n        }\n    }\n    // Return result.\n    if (pmutated) *pmutated = mutated;\n    if (proot) *proot = h;\n}\n\nuint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated) {\n    uint256 hash;\n    MerkleComputation(leaves, &hash, mutated, -1, NULL);\n    return hash;\n}\n\nstd::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) {\n    std::vector<uint256> ret;\n    MerkleComputation(leaves, NULL, NULL, position, &ret);\n    return ret;\n}\n\nuint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& vMerkleBranch, uint32_t nIndex) {\n    uint256 hash = leaf;\n    for (std::vector<uint256>::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) {\n        if (nIndex & 1) {\n            hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));\n        } else {\n            hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));\n        }\n        nIndex >>= 1;\n    }\n    return hash;\n}\n\nuint256 BlockMerkleRoot(const std::vector<CTransactionRef>::const_iterator txStartIter, const std::vector<CTransactionRef>::const_iterator txEndIter, bool* mutated)\n{\n    std::vector<uint256> leaves;\n    leaves.reserve(std::distance(txStartIter, txEndIter));\n    std::transform(txStartIter, txEndIter, std::back_inserter(leaves), [](const CTransactionRef& ref) { return ref->GetHash(); });\n    return ComputeMerkleRoot(leaves, mutated);\n}\n\nuint256 BlockMerkleRoot(const CBlock& block, bool* mutated)\n{\n    return BlockMerkleRoot(block.vtx.begin(), block.vtx.end(), mutated);\n}\n\nstd::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)\n{\n    std::vector<uint256> leaves;\n    leaves.resize(block.vtx.size());\n    for (size_t s = 0; s < block.vtx.size(); s++) {\n        leaves[s] = block.vtx[s]->GetHash();\n    }\n    return ComputeMerkleBranch(leaves, position);\n}\n"
  },
  {
    "path": "src/consensus/merkle.h",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CONSENSUS_MERKLE_H\n#define CONSENSUS_MERKLE_H\n\n#include <stdint.h>\n#include <vector>\n\n#include \"primitives/transaction.h\"\n#include \"primitives/block.h\"\n#include \"uint256.h\"\n\nuint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = NULL);\nstd::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);\nuint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& branch, uint32_t position);\n\n/*\n * Compute the Merkle root of the transactions in a block.\n * *mutated is set to true if a duplicated subtree was found.\n */\nuint256 BlockMerkleRoot(const std::vector<CTransactionRef>::const_iterator txStartIter, const std::vector<CTransactionRef>::const_iterator txEndIter, bool* mutated = NULL);\nuint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);\n\n/*\n * Compute the Merkle branch for the tree of transactions in a block, for a\n * given position.\n * This can be verified using ComputeMerkleRootFromBranch.\n */\nstd::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position);\n\n#endif\n"
  },
  {
    "path": "src/consensus/params.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CONSENSUS_PARAMS_H\n#define CONSENSUS_PARAMS_H\n\n#include \"uint256.h\"\n#include <map>\n#include <string>\n\nnamespace Consensus {\n\nenum DeploymentPos\n{\n    DEPLOYMENT_TESTDUMMY,\n    DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.\n    // NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp\n    MAX_VERSION_BITS_DEPLOYMENTS\n};\n\nenum DeploymentType\n{\n    DEPLOYMENT_POW,\n    DEPLOYMENT_WITNESS,\n    DEPLOYMENT_BOTH\n};\n\n/**\n * Struct for each individual consensus rule change using BIP9.\n */\nstruct BIP9Deployment {\n    BIP9Deployment()\n    {\n        requiredProtoUpgradePercent = 0;\n        protoVersion = 0;\n    };\n\n    /** Bit position to select the particular bit in nVersion. */\n    int bit;\n    /** Start MedianTime for version bits miner confirmation. Can be a date in the past */\n    int64_t nStartTime;\n    /** Timeout/expiry MedianTime for the deployment attempt. */\n    int64_t nTimeout;\n    /** Whether to consider version bits of PoW header, version bits of witness header, or both */\n    DeploymentType type;\n    int requiredProtoUpgradePercent;\n    int protoVersion;\n};\n\n/**\n * Parameters that influence chain consensus.\n */\nstruct Params {\n    uint256 hashGenesisBlock;\n    /** Block height and hash at which BIP34 becomes active */\n    int BIP34Height;\n    uint256 BIP34Hash;\n    /** Block height at which BIP65 becomes active */\n    int BIP65Height;\n    /** Block height at which BIP66 becomes active */\n    int BIP66Height;\n    /**\n     * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,\n     * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.\n     * Examples: 1916 for 95%, 1512 for testchains.\n     */\n    uint32_t nRuleChangeActivationThreshold;\n    uint32_t nMinerConfirmationWindow;\n    BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];\n    uint64_t fixedRewardIntroductionHeight;\n    uint64_t fixedRewardReductionHeight;\n    uint64_t pow2Phase2FirstBlockHeight;\n    uint64_t pow2Phase3FirstBlockHeight;\n    uint64_t devBlockSubsidyActivationHeight;\n    uint64_t pow2Phase4FirstBlockHeight;\n    uint64_t pow2Phase5FirstBlockHeight;\n    uint64_t pow2WitnessSyncHeight;\n    uint64_t halvingIntroductionHeight;\n    uint64_t finalSubsidyBlockHeight;\n    \n    /** Proof of work parameters */\n    uint256 powLimit;\n    bool fPowAllowMinDifficultyBlocks;\n    bool fPowNoRetargeting;\n    int64_t nPowTargetSpacing;\n    int64_t nPowTargetTimespan;\n    uint256 nMinimumChainWork;\n    uint256 defaultAssumeValid;\n};\n} // namespace Consensus\n\n#endif\n"
  },
  {
    "path": "src/consensus/tx_verify.cpp",
    "content": "// Copyright (c) 2017-2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"tx_verify.h\"\n\n#include \"consensus.h\"\n#include \"consensus/validation.h\"\n#include \"script/interpreter.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n\n// TODO remove the following dependencies\n#include \"chain.h\"\n#include \"coins.h\"\n#include \"util/moneystr.h\"\n#include \"base58.h\"\n\n//Munt dependencies\n#include \"witnessutil.h\"\n\nconst uint64_t extraLockLengthAllowance=721;\n\nbool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)\n{\n    if (tx.nLockTime == 0)\n        return true;\n    if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))\n        return true;\n    if (IsOldTransactionVersion(tx.nVersion))\n    {\n        for (const auto& txin : tx.vin) {\n            if (!(txin.GetSequence(tx.nVersion) == CTxIn::SEQUENCE_FINAL))\n                return false;\n        }\n    }\n    else\n    {\n        for (const auto& txin : tx.vin) {\n            if ( txin.FlagIsSet(CTxInFlags::OptInRBF) || txin.FlagIsSet(CTxInFlags::HasLock) )\n                return false;\n        }\n    }\n    return true;\n}\n\nstd::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)\n{\n    assert(prevHeights->size() == tx.vin.size());\n\n    // Will be set to the equivalent height- and time-based nLockTime\n    // values that would be necessary to satisfy all relative lock-\n    // time constraints given our view of block chain history.\n    // The semantics of nLockTime are the last invalid height/time, so\n    // use -1 to have the effect of any height or time being valid.\n    int nMinHeight = -1;\n    int64_t nMinTime = -1;\n\n    // tx.nVersion is signed integer so requires cast to unsigned otherwise\n    // we would be doing a signed comparison and half the range of nVersion\n    // wouldn't support BIP 68.\n    bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2 && (flags & LOCKTIME_VERIFY_SEQUENCE);\n\n    // Do not enforce sequence numbers as a relative lock time\n    // unless we have been instructed to\n    if (!fEnforceBIP68) {\n        return std::pair(nMinHeight, nMinTime);\n    }\n\n    for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++)\n    {\n        const CTxIn& txin = tx.vin[txinIndex];\n\n        // Munt - segsig - if we aren't using relative locktime then we don't have a sequence number at all.\n        // Sequence numbers with the most significant bit set are not\n        // treated as relative lock-times, nor are they given any\n        // consensus-enforced meaning at this point.\n        bool test1 = IsOldTransactionVersion(tx.nVersion) && (txin.GetSequence(tx.nVersion) & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG);\n        bool test2 = !IsOldTransactionVersion(tx.nVersion) && !txin.FlagIsSet(CTxInFlags::HasRelativeLock);\n        if (test1 || test2)\n        {\n            // The height of this input is not relevant for sequence locks\n            (*prevHeights)[txinIndex] = 0;\n            continue;\n        }\n\n        int nCoinHeight = (*prevHeights)[txinIndex];\n\n        bool test3 = IsOldTransactionVersion(tx.nVersion) && (txin.GetSequence(tx.nVersion) & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG);\n        bool test4 = !IsOldTransactionVersion(tx.nVersion) && txin.FlagIsSet(HasTimeBasedRelativeLock);\n        if (test3 || test4)\n        {\n            int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();\n            // NOTE: Subtract 1 to maintain nLockTime semantics\n            // BIP 68 relative lock times have the semantics of calculating\n            // the first block or time at which the transaction would be\n            // valid. When calculating the effective block time or height\n            // for the entire transaction, we switch to using the\n            // semantics of nLockTime which is the last invalid block\n            // time or height.  Thus we subtract 1 from the calculated\n            // time or height.\n\n            // Time-based relative lock-times are measured from the\n            // smallest allowed timestamp of the block containing the\n            // txout being spent, which is the median time past of the\n            // block prior.\n            if (IsOldTransactionVersion(tx.nVersion))\n            {\n                nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.GetSequence(tx.nVersion) & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);\n            }\n            else\n            {\n                nMinTime = std::max(nMinTime, nCoinTime + (txin.GetSequence(tx.nVersion) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);\n            }\n        }\n        else\n        {\n            if (IsOldTransactionVersion(tx.nVersion))\n            {\n                nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.GetSequence(tx.nVersion) & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);\n            }\n            else\n            {\n                nMinHeight = std::max(nMinHeight, nCoinHeight + (int)txin.GetSequence(tx.nVersion) - 1);\n            }\n        }\n    }\n\n    return std::pair(nMinHeight, nMinTime);\n}\n\nbool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)\n{\n    assert(block.pprev);\n    int64_t nBlockTime = block.pprev->GetMedianTimePast();\n    if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)\n        return false;\n\n    return true;\n}\n\nbool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)\n{\n    return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));\n}\n\nunsigned int GetLegacySigOpCount(const CTransaction& tx)\n{\n    unsigned int nSigOps = 0;\n    for (const auto& txin : tx.vin)\n    {\n        nSigOps += txin.scriptSig.GetSigOpCount(false);\n    }\n    for (const auto& txout : tx.vout)\n    {\n        switch (txout.GetType())\n        {\n            case CTxOutType::ScriptLegacyOutput: nSigOps += txout.output.scriptPubKey.GetSigOpCount(false); break;\n            case CTxOutType::StandardKeyHashOutput: nSigOps += 1; break;\n            case CTxOutType::PoW2WitnessOutput: nSigOps += 1; break;\n        }\n    }\n    return nSigOps;\n}\n\nunsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)\n{\n    if (tx.IsCoinBase())\n        return 0;\n\n    unsigned int nSigOps = 0;\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n    {\n        const CTxOut &prevout = inputs.AccessCoin(tx.vin[i].GetPrevOut()).out;\n        if (prevout.GetType() <= CTxOutType::ScriptLegacyOutput && prevout.output.scriptPubKey.IsPayToScriptHash())\n            nSigOps += prevout.output.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);\n    }\n    return nSigOps;\n}\n\nint64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)\n{\n    int64_t nSigOps = GetLegacySigOpCount(tx);\n\n    if (tx.IsCoinBase())\n        return nSigOps;\n\n    if (flags & SCRIPT_VERIFY_P2SH) {\n        nSigOps += GetP2SHSigOpCount(tx, inputs);\n    }\n\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n    {\n        //fixme: (PHASE5) (SEGSIG) - Is this right? - make sure we are counting sigops in segsig scripts correctly\n        const CTxOut &prevout = inputs.AccessCoin(tx.vin[i].GetPrevOut()).out;\n        switch (prevout.GetType())\n        {\n            case CTxOutType::StandardKeyHashOutput: nSigOps += 1; break;\n            case CTxOutType::PoW2WitnessOutput: nSigOps += 1; break;\n            case CTxOutType::ScriptLegacyOutput: /*already handled by GetP2SHSigOpCount*/ break;\n        }\n    }\n    return nSigOps;\n}\n\nbool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)\n{\n    // Basic checks that don't depend on any context\n    if (tx.vin.empty())\n        return state.DoS(10, false, REJECT_INVALID, \"bad-txns-vin-empty\");\n    if (tx.vout.empty())\n        return state.DoS(10, false, REJECT_INVALID, \"bad-txns-vout-empty\");\n    // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)\n    if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES) > MAX_BLOCK_BASE_SIZE)\n        return state.DoS(100, false, REJECT_INVALID, \"bad-txns-oversize\");\n\n    // Check for negative or overflow output values\n    CAmount nValueOut = 0;\n    for (const auto& txout : tx.vout)\n    {\n        if (txout.nValue < 0)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-vout-negative\");\n        if (txout.nValue > MAX_MONEY)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-vout-toolarge\");\n        nValueOut += txout.nValue;\n        if (!MoneyRange(nValueOut))\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-txouttotal-toolarge\");\n    }\n\n    // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock\n    if (fCheckDuplicateInputs) {\n        std::set<COutPoint> vInOutPoints;\n        for (const auto& txin : tx.vin)\n        {\n            if (!vInOutPoints.insert(txin.GetPrevOut()).second)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-inputs-duplicate\");\n        }\n    }\n\n    if (tx.IsCoinBase())\n    {\n        if (IsOldTransactionVersion(tx.nVersion))\n        {\n            if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-cb-length\");\n        }\n        else\n        {\n            if (tx.vin[0].scriptSig.size() != 0)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-cb-length\");\n            if (tx.vin[0].segregatedSignatureData.stack.size() != 2)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-cb-segdata\");\n        }\n    }\n    else\n    {\n        for (const auto& txin : tx.vin)\n        {\n            if (txin.GetPrevOut().IsNull())\n                return state.DoS(10, false, REJECT_INVALID, \"bad-txns-prevout-null\");\n        }\n    }\n\n    return true;\n}\n\n\nbool CheckTransactionContextual(const CTransaction& tx, CValidationState &state, int checkHeight)\n{\n    for (const CTxOut& txout : tx.vout)\n    {\n        if (IsPow2WitnessOutput(txout))\n        {\n            if ( txout.nValue < (gMinimumWitnessAmount * COIN) )\n            {\n                if (txout.output.witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, strprintf(\"PoW² witness output smaller than %d \" GLOBAL_COIN_CODE \" not allowed.\", gMinimumWitnessAmount));\n                }\n            }\n\n            CTxOutPoW2Witness witnessDetails; GetPow2WitnessOutput(txout, witnessDetails);\n            uint64_t nUnused1, nUnused2;\n            int64_t nLockLengthInBlocks = GetPoW2LockLengthInBlocksFromOutput(txout, checkHeight, nUnused1, nUnused2);\n            if (nLockLengthInBlocks < int64_t(MinimumWitnessLockLength()))\n                return state.DoS(10, false, REJECT_INVALID, \"PoW² witness locked for less than minimum of 1 month.\");\n            if (nLockLengthInBlocks > int64_t(MaximumWitnessLockLength()+extraLockLengthAllowance))\n            {\n                if (txout.output.witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, \"PoW² witness locked for greater than maximum of 3 years.\");\n                }\n            }\n\n            int64_t nWeight = GetPoW2RawWeightForAmount(txout.nValue, checkHeight, nLockLengthInBlocks);\n            if (nWeight < gMinimumWitnessWeight)\n            {\n                if (txout.output.witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, \"PoW² witness has insufficient weight.\");\n                }\n            }\n        }\n    }\n    return true;\n}\n\ninline bool IsLockFromConsistent(const CTxOutPoW2Witness& inputDetails, const CTxOutPoW2Witness& outputDetails, uint64_t nInputHeight)\n{\n    // If lockfrom was previously 0 it must become the current block height instead.\n    if (inputDetails.lockFromBlock == 0)\n    {\n        if (outputDetails.lockFromBlock != nInputHeight)\n            return false;\n    }\n    else if (inputDetails.lockFromBlock != outputDetails.lockFromBlock)\n        return false;\n    return true;\n}\n\nbool CWitnessTxBundle::IsLockFromConsistent()\n{\n    // all ouputs must match the actual lockFrom value of the inputs\n    if (inputs.size() > 0 && inputsActualLockFromBlock == 0)\n        return false;\n\n    return std::all_of(outputs.begin(), outputs.end(), [&](const auto& output) {\n        return std::get<1>(output).lockFromBlock == inputsActualLockFromBlock;\n    });\n}\n\n//fixme: (PHASE5) define this with rest of global constants (centralise all constants together)\nstatic const int gMaximumRenewalPenalty = COIN*20;\nstatic const int gPerFailCountRenewalPenalty = (2*COIN)/100;\n\nCAmount CalculateWitnessPenaltyFee(const CTxOut& output)\n{\n    CTxOutPoW2Witness witnessDestination;\n    if (!GetPow2WitnessOutput(output, witnessDestination))\n    {\n        return 0;\n    }\n    CAmount nPenalty = (gPerFailCountRenewalPenalty) * witnessDestination.failCount;\n    if (nPenalty > gMaximumRenewalPenalty)\n        return gMaximumRenewalPenalty;\n    return nPenalty;\n}\n\nvoid IncrementWitnessFailCount(uint64_t& failCount)\n{\n    // Increment fail count (Increments in a sequence: 1 2 4 7 11 17 26 40 61 92 139 209 314 472 709 1064 1597 2396 3595 5393 8090 ...)\n    failCount += (failCount/3);\n    ++failCount;\n    // Avoid overflow - by the time fail count is this high it no longer matters if we don't increment it further\n    if (failCount > std::numeric_limits<uint64_t>::max() / 3)\n        failCount = std::numeric_limits<uint64_t>::max() / 3;\n}\n\ninline bool HasSpendKey(const CTxIn& input, uint64_t nSpendHeight)\n{\n    // At this point we only need to check that there are 2 signatures, spending key and witness key.\n    // The rest is handled by later parts of the code.\n    if (input.segregatedSignatureData.stack.size() != 2)\n        return false;\n    return true;\n}\n\n/*Witness transactions inputs/outputs fall into several different categories.\n* 1) Creation of a new witnessing account: lockfrom must be 0.\n* Output only.\n*/\n\n/*\n* 2) Witnessing: amount should stay the same or increase, fail count can reduced by 1 or 0.\n* If lockfrom was previously 0 it must be set to the height of the block that contains the input.\n* Can only appear as a \"witnesscoinbase\" transaction.\n* Input/Output.\n* Signed by witness key.\n*/\ninline bool IsWitnessBundle(const CTxIn& input, const CTxOutPoW2Witness& inputDetails, const CTxOutPoW2Witness& outputDetails, CAmount nInputAmount, CAmount nOutputAmount, uint64_t nInputHeight, bool isOldTransactionVersion)\n{\n    //Phase 3 (no signatures)\n    //Phase 4, 1 signature - stack will have either 1 or 2 items depending on whether its a script or proper PoW2-witness address.\n    if (isOldTransactionVersion)\n    {\n        return false;\n    }\n    else\n    {\n        if (inputDetails.nType == CTxOutType::PoW2WitnessOutput)\n        {\n            if (input.segregatedSignatureData.stack.size() != 1)\n                return false;\n        }\n        if (inputDetails.nType == ScriptLegacyOutput)\n        {\n            if (input.segregatedSignatureData.stack.size() != 2)\n                return false;\n        }\n    }\n    // Amount in address should stay the same or increase\n    if (nInputAmount > nOutputAmount)\n        return false;\n    // Action nonce always increment\n    if (inputDetails.actionNonce+1 != outputDetails.actionNonce)\n        return false;\n    // Keys and lock unchanged\n    if (inputDetails.spendingKeyID != outputDetails.spendingKeyID)\n        return false;\n    if (inputDetails.witnessKeyID != outputDetails.witnessKeyID)\n        return false;\n    if (inputDetails.lockUntilBlock != outputDetails.lockUntilBlock)\n        return false;\n    if (!IsLockFromConsistent(inputDetails, outputDetails, nInputHeight))\n        return false;\n    // Fail must be reduced by 1 or 0 if it is already 0.\n    if (inputDetails.failCount == outputDetails.failCount + 1)\n        return true;\n    if (outputDetails.failCount == 0)\n        return true;\n    return false;\n}\n\n/*\n* 3) Spending, only amount should change, entire amount should be consumed, current height must be.\n* Input only\n* Signed by spending key.\n*/\ninline bool CWitnessTxBundle::IsValidSpendBundle(uint64_t nCheckHeight, const CTransaction& tx)\n{\n    if (outputs.size() != 0)\n        return false;\n    if (inputs.size() != 1)\n        return false;\n    if (std::get<1>(inputs[0]).lockUntilBlock >= nCheckHeight)\n        return false;\n\n    return true;\n}\n\n/*\n* 4) Renewal, only failcount should change, must be multiplied by 2 then increased by 1.\n* If lockfrom was previously 0 it must be set to the height of the block that contains the input.\n* Input/Output.\n* Signed by spending key.\n*/\ninline bool IsRenewalBundle(const CTxIn& input, const CTxOutPoW2Witness& inputDetails, const CTxOutPoW2Witness& outputDetails, const CTxOut& prevOut, const CTxOut& output, uint64_t nInputHeight, uint64_t nSpendHeight)\n{\n    // Needs 2 signature (spending key)\n    if (!HasSpendKey(input, nSpendHeight))\n    {\n        return false;\n    }\n\n    // Amount keys and lock unchanged.\n    if (prevOut.nValue != output.nValue)\n        return false;\n    // Action nonce always increment\n    if (inputDetails.actionNonce+1 != outputDetails.actionNonce)\n        return false;\n    if (inputDetails.spendingKeyID != outputDetails.spendingKeyID)\n        return false;\n    if (inputDetails.witnessKeyID != outputDetails.witnessKeyID)\n        return false;\n    if (inputDetails.lockUntilBlock != outputDetails.lockUntilBlock)\n        return false;\n    if (!IsLockFromConsistent(inputDetails, outputDetails, nInputHeight))\n        return false;\n    // Fail count must be incremented appropriately\n    uint64_t compFailCount = inputDetails.failCount;\n    IncrementWitnessFailCount(compFailCount);\n    if (compFailCount == outputDetails.failCount)\n        return true;\n    return false;\n}\n\nbool CWitnessTxBundle::IsValidMultiRenewalBundle(uint64_t nSpendHeight)\n{\n    if (nSpendHeight <= Params().GetConsensus().pow2WitnessSyncHeight)\n        return false;\n        \n    if (inputs.size() < 2)\n        return false;\n    if (outputs.size() < 2)\n        return false;\n    if (inputs.size() != outputs.size())\n        return false;\n\n    // Input and outputs must always match in order\n    for (uint64_t inputIndex=0; inputIndex<inputs.size();++inputIndex)\n    {\n        const auto& input = inputs[inputIndex];\n        const auto& output = outputs[inputIndex];\n        \n        // Amount keys and lock unchanged.\n        if (std::get<0>(input).nValue != std::get<0>(output).nValue)\n            return false;\n        // Action nonce always increment\n        if (std::get<1>(input).actionNonce+1 != std::get<1>(output).actionNonce)\n            return false;\n        if (std::get<1>(input).spendingKeyID != std::get<1>(output).spendingKeyID)\n            return false;\n        if (std::get<1>(input).witnessKeyID != std::get<1>(output).witnessKeyID)\n            return false;\n        if (std::get<1>(input).lockUntilBlock != std::get<1>(output).lockUntilBlock)\n            return false;\n        // Fail count must be incremented appropriately\n        uint64_t compFailCount = std::get<1>(input).failCount;\n        IncrementWitnessFailCount(compFailCount);\n        if (compFailCount != std::get<1>(output).failCount)\n            return false;\n    }\n\n    if (!IsLockFromConsistent())\n        return false;\n\n    return true;\n}\n\n\n\n/*\n* 5) Increase amount and/or lock period. Reset lockfrom to 0. Lock period and/or amount must exceed or equal old period/amount.\n* N inputs, M outputs.\n* Signed by spending key.\n* Precondition - we must have already verified externally from here that the scriptwitness stack for the input is of size 2.\n*/\nbool CWitnessTxBundle::IsValidIncreaseBundle()\n{\n    if (inputs.size() < 1)\n        return false;\n    if (outputs.size() < 1)\n        return false;\n\n    const auto& input0 = inputs[0];\n    const auto& input0Details = std::get<1>(input0);\n\n    const auto& output0 = outputs[0];\n    const auto& output0Details = std::get<1>(output0);\n\n    CAmount nInputValue = 0;\n    CAmount nOutputValue = 0;\n\n    uint64_t highestActionNonce = 0;\n    uint64_t highestFailCount = 0;\n\n    // A: verify inputs all have witness properties equal to output0 except lockUntilBlock and lockFromBlock\n    // in addition determine highestActionNonce and highestFailCount\n    for (const auto& input : inputs)\n    {\n        const auto& inputDetails = std::get<1>(input);\n        if (inputDetails.spendingKeyID != output0Details.spendingKeyID)\n            return false;\n        if (inputDetails.witnessKeyID != output0Details.witnessKeyID)\n            return false;\n        if (inputDetails.actionNonce > highestActionNonce)\n            highestActionNonce = inputDetails.actionNonce;\n        if (inputDetails.failCount > highestFailCount)\n            highestFailCount = inputDetails.failCount;\n        nInputValue += std::get<0>(input).nValue;\n    }\n\n    // B: verify outputs all have witness properties equal to input0 except lockUntilBlock\n    // verify values for actionNonce and failCount using highest input values and from block reset\n    for (const auto& output : outputs)\n    {\n        const auto& outputDetails = std::get<1>(output);\n        if (highestActionNonce + 1 != outputDetails.actionNonce)\n            return false;\n        if (highestFailCount != outputDetails.failCount)\n            return false;\n        if (input0Details.spendingKeyID != outputDetails.spendingKeyID)\n            return false;\n        if (input0Details.witnessKeyID != outputDetails.witnessKeyID)\n            return false;\n        if (0 != outputDetails.lockFromBlock)\n            return false;\n        nOutputValue += std::get<0>(output).nValue;\n    }\n\n    // A and B imply that all inputs and outputs have identical witness properties here (except\n\n    // C: verify that all inputs have the same lockUntilBlock\n    if (std::any_of(++inputs.begin(), inputs.end(), [&](const auto& input){ return std::get<1>(input).lockUntilBlock != input0Details.lockUntilBlock; }))\n        return false;\n\n    // D: verify that all outputs have the same lockUntilBlock\n    if (std::any_of(++outputs.begin(), outputs.end(), [&](const auto& output){ return std::get<1>(output).lockUntilBlock != output0Details.lockUntilBlock; }))\n        return false;\n\n    // E: verify that input lockUntilBlock <= output lockUntilBlock\n    if (input0Details.lockUntilBlock > output0Details.lockUntilBlock)\n        return false;\n\n    // F: verify that output value is at least input value\n    if (nOutputValue < nInputValue)\n        return false;\n\n    return true;\n}\n\n/*\n* 6) Rearrange, everything must stay the same, but input(s) may be split or merged into a number of outpus(s) identical outputs.\n* N inputs, M outputs.\n* Signed by spending key.\n* Precondition - we must have already verified externally from here that the scriptwitness stack for the input is of size 2.\n*/\nbool CWitnessTxBundle::IsValidRearrangeBundle()\n{\n    if (inputs.size() < 1)\n        return false;\n    if (outputs.size() < 1)\n        return false;\n\n    const auto& input0 = inputs[0];\n    const auto& input0Details = std::get<1>(input0);\n\n    const auto& output0 = outputs[0];\n    const auto& output0Details = std::get<1>(output0);\n\n    CAmount nInputValue = 0;\n    CAmount nOutputValue = 0;\n\n    uint64_t highestActionNonce = 0;\n    uint64_t highestFailCount = 0;\n\n    // A: verify inputs all have witness properties equal to output0 (except lockFromBlock)\n    for (const auto& input : inputs)\n    {\n        const auto& inputDetails = std::get<1>(input);\n        if (inputDetails.spendingKeyID != output0Details.spendingKeyID)\n            return false;\n        if (inputDetails.witnessKeyID != output0Details.witnessKeyID)\n            return false;\n        if (inputDetails.lockUntilBlock != output0Details.lockUntilBlock)\n            return false;\n        if (inputDetails.actionNonce > highestActionNonce)\n            highestActionNonce = inputDetails.actionNonce;\n        if (inputDetails.failCount > highestFailCount)\n            highestFailCount = inputDetails.failCount;\n        nInputValue += std::get<0>(input).nValue;\n    }\n\n    // B: verify outputs all have witness properties equal to input0\n    for (const auto& output : outputs)\n    {\n        const auto& outputDetails = std::get<1>(output);\n        // Action nonce always increment\n        if (highestActionNonce + 1 != outputDetails.actionNonce)\n            return false;\n        if (highestFailCount != outputDetails.failCount)\n            return false;\n        if (input0Details.spendingKeyID != outputDetails.spendingKeyID)\n            return false;\n        if (input0Details.witnessKeyID != outputDetails.witnessKeyID)\n            return false;\n        if (input0Details.lockUntilBlock != outputDetails.lockUntilBlock)\n            return false;\n        nOutputValue += std::get<0>(output).nValue;\n    }\n\n    // A and B imply that all inputs and outputs have identical witness properties here\n\n    // C: verify input and output value\n    if (nInputValue != nOutputValue)\n        return false;\n\n    // D: verify outputs lockfrom matches actual lockfrom\n    if (!IsLockFromConsistent())\n        return false;\n\n    return true;\n}\n\n/*\n* 7) Update, identical inputs/outputs but witness key changes.\n* M inputs, M outputs.\n* Signed by spending key.\n* Precondition - we must have already verified externally from here that the scriptwitness stack for the input is of size 2.\n*/\ninline bool CWitnessTxBundle::IsValidChangeWitnessKeyBundle()\n{\n    // # of witness inputs equal to # outputs\n    if (inputs.size() < 1 || inputs.size() != outputs.size())\n        return false;\n\n    const auto& output0 = outputs[0];\n    const auto& output0Details = std::get<1>(output0);\n\n    // for every input there is at least one output that matches\n    for (const auto& input : inputs)\n    {\n        const auto& inputDetails = std::get<1>(input);\n\n        if (1 > std::count_if(outputs.begin(), outputs.end(), [&](const auto& output)\n        {\n                const auto& outputDetails = std::get<1>(output);\n                if (std::get<0>(input).nValue != std::get<0>(output).nValue)\n                    return false;\n\n                if (inputDetails.spendingKeyID != outputDetails.spendingKeyID)\n                    return false;\n                if (inputDetails.witnessKeyID == outputDetails.witnessKeyID)\n                    return false;\n                if (inputDetails.lockUntilBlock != outputDetails.lockUntilBlock)\n                    return false;\n                if (inputDetails.actionNonce + 1 != outputDetails.actionNonce)\n                    return false;\n                if (inputDetails.failCount != outputDetails.failCount)\n                    return false;\n                return true;\n            }))\n        {\n            return false;\n        }\n    }\n\n    // verify outputs lockfrom matches actual lockfrom\n    if (!IsLockFromConsistent())\n        return false;\n\n    // all outputs have the same (new) witness key and all outputs have the same spend key\n    if (std::any_of(++outputs.begin(), outputs.end(), [&](const auto& output) {\n            const auto& outputDetails = std::get<1>(output);\n            return (outputDetails.spendingKeyID != output0Details.spendingKeyID) || (outputDetails.witnessKeyID != output0Details.witnessKeyID); }))\n    {\n        return false;\n    }\n\n    // output witness key is different from spend key\n    if (output0Details.witnessKeyID == output0Details.spendingKeyID)\n        return false;\n\n    return true;\n}\n\n//fixme: (PHASE5) (HIGH) Implement unit test code for this function.\nbool CheckTxInputAgainstWitnessBundles(CValidationState& state, std::vector<CWitnessTxBundle>* pWitnessBundles, const CTxOut& prevOut, const CTxIn input, uint64_t inputTxHeight, uint64_t inputTxIndex, uint64_t inputTxOutputIndex, uint64_t nSpendHeight, bool isOldTransactionVersion)\n{\n    if (pWitnessBundles)\n    {\n        if (IsPow2WitnessOutput(prevOut))\n        {\n            CTxOutPoW2Witness inputDetails;\n            GetPow2WitnessOutput(prevOut, inputDetails);\n            // At this point all bundles are currently marked either Creation/Witness - modify the types as we pair them up.\n            bool matchedExistingBundle = false;\n            for (auto& bundle : *pWitnessBundles)\n            {\n                if (bundle.outputs.size() == 1)\n                {\n                    const auto& outputDetails = std::get<1>(bundle.outputs[0]);\n\n                    // Witnessing: amount should stay the same or increase, fail count can reduced by 1 or 0, if lockfrom was previously 0 it must be set to the current block height. Can only appear as a \"witnesscoinbase\" transaction.\n                    if ( IsWitnessBundle(input, inputDetails, outputDetails, prevOut.nValue, std::get<0>(bundle.outputs[0]).nValue, inputTxHeight, isOldTransactionVersion) )\n                    {\n                        if (std::get<0>(bundle.outputs[0]).nValue - prevOut.nValue > gMaximumWitnessCompoundAmount * COIN)\n                        {\n                            return state.DoS(50, false, REJECT_INVALID, \"witness-coinbase-compounding-too-much\");\n                        }\n\n                        matchedExistingBundle = true;\n                        bundle.inputs.push_back(std::tuple(prevOut, std::move(inputDetails), COutPoint(inputTxHeight, inputTxIndex, inputTxOutputIndex)));\n                        bundle.bundleType = CWitnessTxBundle::WitnessTxType::WitnessType;\n                        break;\n                    }\n                    else if ( IsRenewalBundle(input, inputDetails, outputDetails, prevOut, std::get<0>(bundle.outputs[0]), inputTxHeight, nSpendHeight) )\n                    {\n                        matchedExistingBundle = true;\n                        bundle.inputs.push_back(std::tuple(prevOut, std::move(inputDetails), COutPoint(inputTxHeight, inputTxIndex, inputTxOutputIndex)));\n                        bundle.bundleType = CWitnessTxBundle::WitnessTxType::RenewType;\n                        break;\n                    }\n                }\n            }\n            if (!matchedExistingBundle)\n            {\n                //NB! We -must- check here that we have the spending key (2 items on stack) as when we later check the built up RearrangeType bundles, or multi renewal bundles, we have no way to check it then.\n                //So this check is very important, must not be skipped and must come before the bundle creation for these bundle types.\n                //Exception for phase 3 inputs which use the ScriptLegacyOutput, not allowing this can get your witness \"stuck\", ie. not being able to empty it\n                if (!HasSpendKey(input, nSpendHeight))\n                {\n                    if (prevOut.GetType() != CTxOutType::ScriptLegacyOutput) // accept phase 3 inputs\n                        return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-missing-spend-key\");\n                }\n\n                bool matchedExistingBundle = false;\n                uint64_t actualLockFromBlock = inputDetails.lockFromBlock == 0 ? inputTxHeight : inputDetails.lockFromBlock;\n                for (auto& bundle : *pWitnessBundles)\n                {\n                    if (bundle.outputs.size() == 0)\n                        continue;\n                    if ( (bundle.bundleType == CWitnessTxBundle::WitnessTxType::SpendType || bundle.bundleType == CWitnessTxBundle::WitnessTxType::RearrangeType  || bundle.bundleType == CWitnessTxBundle::WitnessTxType::IncreaseType) && (std::get<1>(bundle.outputs[0]).witnessKeyID == inputDetails.witnessKeyID) && (std::get<1>(bundle.outputs[0]).spendingKeyID == inputDetails.spendingKeyID) )\n                    {\n                        bundle.bundleType = std::get<1>(bundle.outputs[0]).lockFromBlock == 0 ? CWitnessTxBundle::WitnessTxType::IncreaseType : CWitnessTxBundle::WitnessTxType::RearrangeType;\n                        if (bundle.inputsActualLockFromBlock == 0)\n                            bundle.inputsActualLockFromBlock = actualLockFromBlock;\n                        else if (bundle.inputsActualLockFromBlock != actualLockFromBlock)\n                            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-bundle-mismatching-lockfrom\");\n                        bundle.inputs.push_back(std::tuple(prevOut, std::move(inputDetails), COutPoint(inputTxHeight, inputTxIndex, inputTxOutputIndex)));\n                        matchedExistingBundle = true;\n                    }\n                    else if ( (bundle.bundleType == CWitnessTxBundle::WitnessTxType::SpendType || bundle.bundleType == CWitnessTxBundle::WitnessTxType::ChangeWitnessKeyType || bundle.bundleType == CWitnessTxBundle::WitnessTxType::RearrangeType) && (std::get<1>(bundle.outputs[0]).witnessKeyID != inputDetails.witnessKeyID) && (std::get<1>(bundle.outputs[0]).spendingKeyID == inputDetails.spendingKeyID) )\n                    {\n                        bundle.bundleType = CWitnessTxBundle::WitnessTxType::ChangeWitnessKeyType;\n                        if (bundle.inputsActualLockFromBlock == 0)\n                            bundle.inputsActualLockFromBlock = actualLockFromBlock;\n                        else if (bundle.inputsActualLockFromBlock != actualLockFromBlock)\n                            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-bundle-mismatching-lockfrom\");\n                        bundle.inputs.push_back(std::tuple(prevOut, std::move(inputDetails), COutPoint(inputTxHeight, inputTxIndex, inputTxOutputIndex)));\n                        matchedExistingBundle = true;\n                    }\n                }\n                if (!matchedExistingBundle)\n                {\n                    CWitnessTxBundle spendBundle = CWitnessTxBundle(CWitnessTxBundle::WitnessTxType::SpendType);\n                    spendBundle.inputsActualLockFromBlock = actualLockFromBlock;\n                    spendBundle.inputs.push_back(std::tuple(prevOut, std::move(inputDetails), COutPoint(inputTxHeight, inputTxIndex, inputTxOutputIndex)));\n                    pWitnessBundles->push_back(spendBundle);\n                }\n            }\n        }\n    }\n    return true;\n}\n\nbool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const std::vector<CWitnessTxBundle>* pWitnessBundles)\n{\n        // This doesn't trigger the DoS code on purpose; if it did, it would make it easier\n        // for an attacker to attempt to split the network.\n        if (tx.IsPoW2WitnessCoinBase())\n        {\n            for (unsigned int i = 0; i < tx.vin.size(); i++)\n            {\n                if (!tx.vin[i].GetPrevOut().IsNull())\n                {\n                    if (!inputs.HaveCoin(tx.vin[i].GetPrevOut()))\n                    {\n                        return state.Invalid(false, 0, \"\", \"Inputs unavailable\");\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (!inputs.HaveInputs(tx))\n                return state.Invalid(false, 0, \"\", \"Inputs unavailable\");\n        }\n        \n        CAmount nValueIn = 0;\n        CAmount nFees = 0;\n        for (unsigned int i = 0; i < tx.vin.size(); i++)\n        {\n            const COutPoint &prevout = tx.vin[i].GetPrevOut();\n            if (prevout.IsNull() && tx.IsPoW2WitnessCoinBase())\n                continue;\n            const Coin& coin = inputs.AccessCoin(prevout);\n            assert(!coin.IsSpent());\n            \n            // If prev is index based, then ensure it has sufficient maturity. (For the sake of simplicity we keep this the same depth as mining maturity)\n            if (!prevout.isHash)\n            {\n                // NB! If we ever change the maturity depth here to a different one than that of coinbase maturity - then we also need to change the below 'else if' control block into an 'if' control block.\n                if (nSpendHeight - coin.nHeight < COINBASE_MATURITY)\n                {\n                    return state.Invalid(false, REJECT_INVALID, \"bad-txns-insufficient-depth-index-input\", strprintf(\"tried to spend input via index at depth %d; Only allowed at depth %d\", nSpendHeight - coin.nHeight, COINBASE_MATURITY));\n                }\n            }\n            // If prev is coinbase, check that it's matured\n            else if (coin.IsCoinBase())\n            {\n                // NB! If we ever change the maturity depth here to a different one than that of prevout-index maturity (control block above this one) - then we also need to change the above 'else if' for this control block into an 'if' instead.\n                if (nSpendHeight - coin.nHeight < COINBASE_MATURITY)\n                {\n                    return state.Invalid(false, REJECT_INVALID, \"bad-txns-premature-spend-of-coinbase\", strprintf(\"tried to spend coinbase at depth %d\", nSpendHeight - coin.nHeight));\n                }\n            }\n\n            // Check for negative or overflow input values\n            nValueIn += coin.out.nValue;\n            if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn))\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-inputvalues-outofrange\");\n        }\n\n        CAmount witnessPenaltyFee = 0;\n        if (pWitnessBundles)\n        {\n            for (auto& bundle : *pWitnessBundles)\n            {\n                if(bundle.bundleType == CWitnessTxBundle::WitnessTxType::RenewType)\n                    witnessPenaltyFee += CalculateWitnessPenaltyFee(std::get<0>(bundle.outputs[0]));\n            }\n        }\n\n        if (nValueIn < tx.GetValueOut())\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-belowout\", false,\n                strprintf(\"value in (%s) < value out (%s)\", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())));\n\n        // Tally transaction fees\n        CAmount nTxFee = nValueIn - tx.GetValueOut();\n        if (nTxFee < 0)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-fee-negative\");\n        if (nTxFee < witnessPenaltyFee)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-fee-missing-witness-renewal-penalty-fee\");\n        nFees += nTxFee;\n        if (!MoneyRange(nFees))\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-fee-outofrange\");\n    return true;\n}\n\nbool BuildWitnessBundles(const CTransaction& tx, CValidationState& state, uint64_t nSpendHeight, uint64_t transactionIndex, std::function<bool(const COutPoint&, CTxOut&, uint64_t&, uint64_t&, uint64_t&)> getTxOut, std::vector<CWitnessTxBundle>& bundles)\n{\n    bundles.clear();\n\n    std::vector<CWitnessTxBundle> resultBundles;\n\n    uint64_t transactionOutputIndex=0;\n    for (const CTxOut& txout : tx.vout)\n    {\n        if (IsPow2WitnessOutput(txout))\n        {\n            CTxOutPoW2Witness witnessDetails; GetPow2WitnessOutput(txout, witnessDetails);\n            if ( txout.nValue < (gMinimumWitnessAmount * COIN) )\n            {\n                if (witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, strprintf(\"PoW² witness output smaller than %d \" GLOBAL_COIN_CODE \" not allowed.\", gMinimumWitnessAmount));\n                }\n            }\n            \n            uint64_t nUnused1, nUnused2;\n            int64_t nLockLengthInBlocks = GetPoW2LockLengthInBlocksFromOutput(txout, nSpendHeight, nUnused1, nUnused2);\n            if (nLockLengthInBlocks < int64_t(MinimumWitnessLockLength()))\n            {\n                return state.DoS(10, false, REJECT_INVALID, \"PoW² witness locked for less than minimum of 1 month.\");\n            }\n            if (nLockLengthInBlocks > int64_t(MaximumWitnessLockLength()+extraLockLengthAllowance))\n            {\n                if (witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, \"PoW² witness locked for greater than maximum of 3 years.\");\n                }\n            }\n\n            int64_t nWeight = GetPoW2RawWeightForAmount(txout.nValue, nSpendHeight, nLockLengthInBlocks);\n            if (nWeight < gMinimumWitnessWeight)\n            {\n                if (witnessDetails.lockFromBlock != 1)\n                {\n                    return state.DoS(10, false, REJECT_INVALID, \"PoW² witness has insufficient weight.\");\n                }\n            }\n\n            if (tx.IsPoW2WitnessCoinBase())\n            {\n                resultBundles.push_back(CWitnessTxBundle(CWitnessTxBundle::WitnessTxType::WitnessType, std::tuple(txout, std::move(witnessDetails), COutPoint(nSpendHeight, transactionIndex, transactionOutputIndex))));\n            }\n            else\n            {\n                bool matchedExistingBundle = false;\n                for (auto& bundle: resultBundles)\n                {\n                    if (bundle.bundleType == CWitnessTxBundle::WitnessTxType::CreationType && witnessDetails.lockFromBlock == 0 && witnessDetails.actionNonce == 0 && std::get<1>(bundle.outputs[0]).witnessKeyID == witnessDetails.witnessKeyID && std::get<1>(bundle.outputs[0]).spendingKeyID == witnessDetails.spendingKeyID)\n                    {\n                        bundle.outputs.push_back(std::tuple(txout, std::move(witnessDetails), COutPoint(nSpendHeight, transactionIndex, transactionOutputIndex)));\n                        matchedExistingBundle = true;\n                    }\n                    else if ( (bundle.bundleType == CWitnessTxBundle::WitnessTxType::SpendType || bundle.bundleType == CWitnessTxBundle::WitnessTxType::RearrangeType) && (std::get<1>(bundle.outputs[0]).witnessKeyID == witnessDetails.witnessKeyID) && std::get<1>(bundle.outputs[0]).spendingKeyID == witnessDetails.spendingKeyID )\n                    {\n                        bundle.bundleType = CWitnessTxBundle::WitnessTxType::RearrangeType;\n                        bundle.outputs.push_back(std::tuple(txout, std::move(witnessDetails), COutPoint(nSpendHeight, transactionIndex, transactionOutputIndex)));\n                        matchedExistingBundle = true;\n                        break;\n                    }\n                }\n                if (!matchedExistingBundle)\n                {\n                    if (witnessDetails.lockFromBlock == 0 && witnessDetails.actionNonce == 0)\n                    {\n                        resultBundles.push_back(CWitnessTxBundle(CWitnessTxBundle::WitnessTxType::CreationType, std::tuple(txout, std::move(witnessDetails), COutPoint(nSpendHeight, transactionIndex, transactionOutputIndex))));\n                    }\n                    else\n                    {\n                        // if not matched to an existing bundle and the output is a witness output, how can it ever be a spend bundle?? it has to be followed by input checking to correct this.\n                        // perhaps better to introduce new bundle type indicating \"undetermined\" or something similar.\n                        CWitnessTxBundle spendBundle = CWitnessTxBundle(CWitnessTxBundle::WitnessTxType::SpendType, std::tuple(txout, std::move(witnessDetails), COutPoint(nSpendHeight, transactionIndex, transactionOutputIndex)));\n                        resultBundles.push_back(spendBundle);\n                    }\n                }\n            }\n        }\n        ++transactionOutputIndex;\n    }\n\n    // match tx inputs to existing bundles or create new\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n    {\n        const COutPoint &prevout = tx.vin[i].GetPrevOut();\n        if (prevout.IsNull() && tx.IsCoinBase())\n        {\n            continue;\n        }\n\n        CTxOut inputTxOut;\n        uint64_t inputTxHeight;\n        uint64_t inputTxIndex;\n        uint64_t inputTxOutputIndex;\n        if (!getTxOut(prevout, inputTxOut, inputTxHeight, inputTxIndex, inputTxOutputIndex))\n        {\n            return false;\n        }\n\n        if (!CheckTxInputAgainstWitnessBundles(state, &resultBundles, inputTxOut, tx.vin[i], inputTxHeight, inputTxIndex, inputTxOutputIndex, nSpendHeight, IsOldTransactionVersion(tx.nVersion)))\n        {\n            return false;\n        }\n    }\n\n    for (auto& bundle: resultBundles)\n    {\n        if (bundle.bundleType == CWitnessTxBundle::WitnessTxType::RearrangeType)\n        {\n            if (!bundle.IsValidRearrangeBundle())\n            {\n                if (bundle.IsValidMultiRenewalBundle(nSpendHeight))\n                {\n                    bundle.bundleType = CWitnessTxBundle::WitnessTxType::RenewType;\n                }\n                else\n                {\n                    return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-invalid-rearrange-bundle\");\n                }\n            }\n        }\n        else if(bundle.bundleType == CWitnessTxBundle::WitnessTxType::SpendType)\n        {\n            if (!bundle.IsValidSpendBundle(nSpendHeight, tx))\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-invalid-spend-bundle\");\n            }\n        }\n        else if(bundle.bundleType == CWitnessTxBundle::WitnessTxType::IncreaseType)\n        {\n            if (!bundle.IsValidIncreaseBundle())\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-invalid-increase-bundle\");\n            }\n        }\n        else if(bundle.bundleType == CWitnessTxBundle::WitnessTxType::ChangeWitnessKeyType)\n        {\n            if (!bundle.IsValidChangeWitnessKeyBundle())\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-in-witness-invalid-changewitnesskey-bundle\");\n            }\n        }\n        else if(bundle.bundleType == CWitnessTxBundle::WitnessTxType::RenewType)\n        {\n            // nop, this case already passed ::IsRenewalBundle()\n        }\n    }\n\n    bundles = std::move(resultBundles);\n    return true;\n}\n\n"
  },
  {
    "path": "src/consensus/tx_verify.h",
    "content": "// Copyright (c) 2017-2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CONSENSUS_TX_VERIFY_H\n#define CONSENSUS_TX_VERIFY_H\n\n#include \"primitives/transaction.h\"\n\n#include <stdint.h>\n#include <vector>\n#include <functional>\n\nclass CBlockIndex;\nclass CCoinsViewCache;\nclass CTransaction;\nclass CValidationState;\n\n/*Witness transactions inputs/outputs fall into several different categories.\n* Creating a new witness account\n* Perform a witness operation\n* Spending coins (when the lock is expired only)\n* Reactivating (renewing) a witness that has been kicked out for non-participation\n* Increasing the lock amount/time on an existing account\n* Rearrange existing accounts where the weight exceeds the ideal taking N inputs and M outputs sharing the same properties and equal total amount\n* Changing the witness key if it has been compromised\n* \n* Depending on the type of operation that is being performed, different constraints apply - can only spend when lock expired but other actions allowed all the time etc.\n* Worse, because we can have multiple inputs/outputs mixed in a transaction we could have one transaction performing more than one operation.\n* When doing CheckTransactionContextual/CheckInputs we first perform an algorithm to try identify the type of operation and categorise the inputs/outputs into 'bundles' of the types.\n* And then ensure the constraints for those types apply.\n* It is important that this acts in a deterministic way.\n* \n* WitnessTxBundle class is used to do this - for more specific details on the constraints/detection of the various types see the details comments in tx_verify.cpp starting at function HasSpendKey()\n*/ \nstruct CWitnessTxBundle\n{\n    enum WitnessTxType\n    {\n        CreationType,\n        WitnessType,\n        SpendType,\n        RenewType,\n        IncreaseType,\n        RearrangeType,\n        ChangeWitnessKeyType\n    };\n    CWitnessTxBundle(WitnessTxType bundleType_, std::tuple<const CTxOut, CTxOutPoW2Witness, COutPoint> output)\n    : bundleType(bundleType_)\n    {\n        outputs.push_back(output);\n    }\n    CWitnessTxBundle(WitnessTxType bundleType_) : bundleType(bundleType_) {}\n    CWitnessTxBundle() {}\n\n    inline bool IsValidRearrangeBundle();\n    inline bool IsValidMultiRenewalBundle(uint64_t nHeight);\n    inline bool IsValidSpendBundle(uint64_t nHeight, const CTransaction& transaction);\n    inline bool IsValidChangeWitnessKeyBundle();\n    inline bool IsValidIncreaseBundle();\n\n    bool IsLockFromConsistent();\n\n    WitnessTxType bundleType=CreationType;\n    uint64_t inputsActualLockFromBlock = 0;\n\n    //NB! The COutPoint's below are not guaranteed to always be available; if we have been serialised/unserialised from disk they will be set as (0, 0, 0)\n    //Any code that relies on the OutPoints should ensure it is working on unserialised copies (or update the serialisation code if appropriate)\n    std::vector<std::tuple<const CTxOut, CTxOutPoW2Witness, COutPoint>> inputs;\n    std::vector<std::tuple<const CTxOut, CTxOutPoW2Witness, COutPoint>> outputs;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(bundleType);\n        READWRITE(inputsActualLockFromBlock);\n        if (ser_action.ForRead())\n        {\n            uint64_t inputSize = ReadCompactSize(s);\n            for (uint64_t i=0; i<inputSize; ++i)\n            {\n                std::pair<const CTxOut, CTxOutPoW2Witness> item;\n                CTxOut& txOut = REF(item.first);\n                txOut.ReadFromStream(s, CTxOut::NEW_FORMAT_VERSION);\n                STRREAD(item.second);\n                inputs.push_back(std::tuple(item.first, item.second, COutPoint()));\n            }\n            uint64_t outputSize = ReadCompactSize(s);\n            for (uint64_t i=0; i<outputSize; ++i)\n            {\n                std::pair<const CTxOut, CTxOutPoW2Witness> item;\n                CTxOut& txOut = REF(item.first);\n                txOut.ReadFromStream(s, CTxOut::NEW_FORMAT_VERSION);\n                STRREAD(item.second);\n                outputs.push_back(std::tuple(item.first, item.second, COutPoint()));\n            }\n        }\n        else\n        {\n            WriteCompactSize(s, inputs.size());\n            for (const auto& [txOut, txOutWitness, outPoint] : inputs)\n            {\n                (void) outPoint;\n                STRWRITE(std::pair(txOut, txOutWitness));\n            }\n            WriteCompactSize(s, outputs.size());\n            for (const auto& [txOut, txOutWitness, outPoint] : outputs)\n            {\n                (void) outPoint;\n                STRWRITE(std::pair(txOut, txOutWitness));\n            }\n        }\n    }\n};\n\n\nstruct CWitnessBundles: std::vector<CWitnessTxBundle>\n{\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        std::vector<CWitnessTxBundle>& vBundles = *this;\n        READWRITECOMPACTSIZEVECTOR(vBundles);\n    }\n\n    CWitnessBundles() {}\n\n    /** This deserializing constructor to support unserialize of const objects. */\n    template <typename Stream>\n    CWitnessBundles(deserialize_type, Stream& s)\n    {\n        Unserialize(s);\n    }\n\n};\n\nbool CheckTxInputAgainstWitnessBundles(CValidationState& state, std::vector<CWitnessTxBundle>* pWitnessBundles, const CTxOut& prevOut, const CTxIn input, uint64_t nInputHeight, uint64_t nSpendHeight, bool isOldTransactionVersion);\n\nCAmount CalculateWitnessPenaltyFee(const CTxOut& output);\nvoid IncrementWitnessFailCount(uint64_t& failCount);\n\n/** Transaction validation functions */\n\n/** Context-independent validity checks */\nbool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);\n\n/** Context-dependent validity checks */\nbool CheckTransactionContextual(const CTransaction& tx, CValidationState& state, int checkHeight);\n\n/** Build witness bundles and witness related validity checks */\nbool BuildWitnessBundles(const CTransaction& tx, CValidationState& state, uint64_t nSpendHeight, uint64_t transactionIndex, std::function<bool(const COutPoint&, CTxOut&, uint64_t&, uint64_t&, uint64_t&)> getTxOut, std::vector<CWitnessTxBundle>& bundles);\n\nnamespace Consensus {\n/**\n * Check whether all inputs of this transaction are valid (no double spends and amounts)\n * This does not modify the UTXO set. This does not check scripts and sigs.\n * Also verifies that all witness input/outputs are groupable in a 'valid' way in terms of the constraints outlined for CWitnessTxBundle for their given type of operation (spend/witness/renew etc.) if witnessBundles\n * witnessBundles should be prepopulated for outputs first by calling CheckTransactionContextual\n * Preconditions: tx.IsCoinBase() is false. witnessBundles is not null if witness transactions are to be verified.\n */\nbool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const std::vector<CWitnessTxBundle>* pWitnessBundles);\n} // namespace Consensus\n\n/** Auxiliary functions for transaction validation (ideally should not be exposed) */\n\n/**\n * Count ECDSA signature operations the old-fashioned (pre-0.6) way\n * @return number of sigops this transaction's outputs will produce when spent\n * @see CTransaction::FetchInputs\n */\nunsigned int GetLegacySigOpCount(const CTransaction& tx);\n\n/**\n * Count ECDSA signature operations in pay-to-script-hash inputs.\n * \n * @param[in] mapInputs Map of previous transactions that have outputs we're spending\n * @return maximum number of sigops required to validate this transaction's inputs\n * @see CTransaction::FetchInputs\n */\nunsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);\n\n/**\n * Compute total signature operation cost of a transaction.\n * @param[in] tx     Transaction for which we are computing the cost\n * @param[in] inputs Map of previous transactions that have outputs we're spending\n * @param[out] flags Script verification flags\n * @return Total signature operation cost of tx\n */\nint64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags);\n\n/**\n * Check if transaction is final and can be included in a block with the\n * specified height and time. Consensus critical.\n */\nbool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);\n\n/**\n * Calculates the block height and previous block's median time past at\n * which the transaction will be considered final in the context of BIP 68.\n * Also removes from the vector of input heights any entries which did not\n * correspond to sequence locked inputs as they do not affect the calculation.\n */\nstd::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);\n\nbool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair);\n/**\n * Check if transaction is final per BIP 68 sequence numbers and can be included in a block.\n * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.\n */\nbool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);\n\n#endif\n"
  },
  {
    "path": "src/consensus/validation.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CONSENSUS_VALIDATION_H\n#define CONSENSUS_VALIDATION_H\n\n#include <string>\n\n//fixme: this constant exists to support gradually factoring out the literal \"576\" used throughout\n// Any literal \"576\" encountered can be replaced by this at any time (assuming this literal is used as daily block target)\n// At any convenient time comment this const and resolve compiler errors the right way, for example using DailyBlocksTarget() where apprapriate\nstatic const int gRefactorDailyBlocksUsage = 576;\n\nstatic const int gMinimumWitnessAmount = 5000;\nstatic const int gMinimumWitnessWeight = 10000;\nstatic const int gMinimumParticipationAge = 100;    // This forces an attacker to split funds into at least 200 accounts to have a high percentage chance of controlling the network.\nstatic const int gMaximumParticipationAge = 365 * gRefactorDailyBlocksUsage; // Witnesses will essentially be required to download and parse the utxo for this many blocks back from current tip.\n                                                    // We try to balance this in such a way that it allows smaller witness accounts but not ones so absurdly small that they force witnesses to unnecessarily keep years of data around.\n                                                    // Currently set at - 1 year (365 days * daily blocks).\n\nstatic const int gStartingWitnessNetworkWeightEstimate  = 260000000;\nstatic const int gMinimumWitnessLockDays                = 30;\nstatic const int gMaximumWitnessLockDays                = 3 * 365;\n#define GLOBAL_MAXIMUM_WITNESS_COMPOUND                  \"40\"\nstatic const int gMaximumWitnessCompoundAmount          = 40;\n\n\n/** \"reject\" message codes */\nstatic const unsigned char REJECT_MALFORMED = 0x01;\nstatic const unsigned char REJECT_INVALID = 0x10;\nstatic const unsigned char REJECT_OBSOLETE = 0x11;\nstatic const unsigned char REJECT_DUPLICATE = 0x12;\nstatic const unsigned char REJECT_NONSTANDARD = 0x40;\n// static const unsigned char REJECT_DUST = 0x41; // part of BIP 61\nstatic const unsigned char REJECT_INSUFFICIENTFEE = 0x42;\nstatic const unsigned char REJECT_CHECKPOINT = 0x43;\n\n/** Capture information about block/transaction validation */\nclass CValidationState {\nprivate:\n    enum mode_state {\n        MODE_VALID,   //!< everything ok\n        MODE_INVALID, //!< network rule violation (DoS value may be set)\n        MODE_ERROR,   //!< run-time error\n    } mode;\n    int nDoS;\n    std::string strRejectReason;\n    unsigned int chRejectCode;\n    bool corruptionPossible;\n    std::string strDebugMessage;\npublic:\n    CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}\n    bool DoS(int level, bool ret = false,\n             unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn=\"\",\n             bool corruptionIn=false,\n             const std::string &strDebugMessageIn=\"\") {\n        chRejectCode = chRejectCodeIn;\n        strRejectReason = strRejectReasonIn;\n        corruptionPossible = corruptionIn;\n        strDebugMessage = strDebugMessageIn;\n        if (mode == MODE_ERROR)\n            return ret;\n        nDoS += level;\n        mode = MODE_INVALID;\n        return ret;\n    }\n    bool Invalid(bool ret = false,\n                 unsigned int _chRejectCode=0, const std::string &_strRejectReason=\"\",\n                 const std::string &_strDebugMessage=\"\") {\n        return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);\n    }\n    bool Error(const std::string& strRejectReasonIn) {\n        if (mode == MODE_VALID)\n            strRejectReason = strRejectReasonIn;\n        mode = MODE_ERROR;\n        return false;\n    }\n    bool IsValid() const {\n        return mode == MODE_VALID;\n    }\n    bool IsInvalid() const {\n        return mode == MODE_INVALID;\n    }\n    bool IsError() const {\n        return mode == MODE_ERROR;\n    }\n    bool IsInvalid(int &nDoSOut) const {\n        if (IsInvalid()) {\n            nDoSOut = nDoS;\n            return true;\n        }\n        return false;\n    }\n    bool CorruptionPossible() const {\n        return corruptionPossible;\n    }\n    void SetCorruptionPossible() {\n        corruptionPossible = true;\n    }\n    unsigned int GetRejectCode() const { return chRejectCode; }\n    std::string GetRejectReason() const { return strRejectReason; }\n    std::string GetDebugMessage() const { return strDebugMessage; }\n    std::string ToString() const\n    {\n        if (IsValid())\n        {\n            return \"Valid\";\n        }\n\n        if (!strDebugMessage.empty()) {\n            return strRejectReason + \", \" + strDebugMessage;\n        }\n\n        return strRejectReason;\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/controllers/rpccontroller.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// File contains modifications by: The Novo developers\n// All modifications:\n// Copyright (c) 2020 The Novo developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the NOVO software license, see the accompanying\n// file COPYING\n\n#include <univalue/include/univalue.h>\n#include <tinyformat.h>\n#include <rpc/server.h>\n#include <rpc/client.h>\n\n#include \"rpccontroller.h\"\n#include <boost/algorithm/string/case_conv.hpp>\n#include <set>\n\nvoid RPCController::executeCommandLine(const std::string& sCommandLine, const std::function<void(const std::string&)>& filteredCommandHandler, const std::function<void(const std::string&, const std::string&)>& errorHandler, const std::function<void(const std::string&, const std::string&)>& successHandler)\n{\n    if(!sCommandLine.empty())\n    {\n        std::string strFilteredCmd;\n        try\n        {\n            std::string dummy;\n            if (!parseCommandLine(dummy, sCommandLine, false, &strFilteredCmd))\n            {\n                // Failed to parse command, so we cannot even filter it for the history\n                errorHandler(strFilteredCmd, \"Invalid command line\");\n                return;\n            }\n        }\n        catch (const std::exception& e)\n        {\n            errorHandler(strFilteredCmd, strprintf(\"Error: %s\", e.what()));\n            return;\n        }\n        filteredCommandHandler(strFilteredCmd);\n\n        std::string result;\n        try\n        {\n            std::string executableCommand = sCommandLine + \"\\n\";\n            parseCommandLine(result, executableCommand, true, NULL);\n        }\n        catch (UniValue& objError)\n        {\n            try // Nice formatting for standard-format error\n            {\n                int code = find_value(objError, \"code\").get_int();\n                std::string message = find_value(objError, \"message\").get_str();\n                errorHandler(strFilteredCmd, strprintf(\"%s (code %d)\", message, code));\n                return;\n            }\n            catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message\n            {   // Show raw JSON object\n                //Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));\n                errorHandler(strFilteredCmd, objError.write());\n                return;\n            }\n        }\n        catch (const std::exception& e)\n        {\n            errorHandler(strFilteredCmd, strprintf(\"Error: %s\", e.what()));\n            return;\n        }\n        successHandler(strFilteredCmd, result);\n        return;\n    }\n    errorHandler(\"\", \"Empty commandline\");\n}\n\nstd::vector<std::string> RPCController::getAutocompleteList()\n{\n    std::vector<std::string> wordList;\n    std::vector<std::string> commandList = tableRPC.listCommands();\n    for (size_t i = 0; i < commandList.size(); ++i)\n    {\n        wordList.push_back(commandList[i].c_str());\n        wordList.push_back(\"help \" + commandList[i]);\n    }\n\n    std::sort(wordList.begin(), wordList.end());\n    return wordList;\n}\n\n//fixme: (NOVO) - improve this list, e.g. command to import witness keys\n// don't add private key handling cmd's to the history\nconst std::set<std::string> historyFilter = {\n    \"importprivkey\",\n    \"importmulti\",\n    \"signmessagewithprivkey\",\n    \"signrawtransaction\",\n    \"walletpassphrase\",\n    \"walletpassphrasechange\",\n    \"encryptwallet\"\n};\n\nbool RPCController::parseCommandLine(std::string& strResult, const std::string& strCommand, const bool fExecute, std::string* const pstrFilteredOut)\n{\n    std::vector< std::vector<std::string> > stack;\n    stack.push_back(std::vector<std::string>());\n\n    enum CmdParseState\n    {\n        STATE_EATING_SPACES,\n        STATE_EATING_SPACES_IN_ARG,\n        STATE_EATING_SPACES_IN_BRACKETS,\n        STATE_ARGUMENT,\n        STATE_SINGLEQUOTED,\n        STATE_DOUBLEQUOTED,\n        STATE_ESCAPE_OUTER,\n        STATE_ESCAPE_DOUBLEQUOTED,\n        STATE_COMMAND_EXECUTED,\n        STATE_COMMAND_EXECUTED_INNER\n    } state = STATE_EATING_SPACES;\n    std::string curarg;\n    UniValue lastResult;\n    unsigned nDepthInsideSensitive = 0;\n    size_t filter_begin_pos = 0, chpos;\n    std::vector<std::pair<size_t, size_t>> filter_ranges;\n\n    auto add_to_current_stack = [&](const std::string& strArg)\n    {\n        std::string argLower = strArg;\n        boost::to_lower(argLower);\n        if (!stack.empty() && stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.find(argLower) != historyFilter.end())\n        {\n            nDepthInsideSensitive = 1;\n            filter_begin_pos = chpos;\n        }\n        // Make sure stack is not empty before adding something\n        if (stack.empty()) {\n            stack.push_back(std::vector<std::string>());\n        }\n        stack.back().push_back(strArg);\n    };\n\n    auto close_out_params = [&]()\n    {\n        if (nDepthInsideSensitive) {\n            if (!--nDepthInsideSensitive) {\n                assert(filter_begin_pos);\n                filter_ranges.push_back(std::pair(filter_begin_pos, chpos));\n                filter_begin_pos = 0;\n            }\n        }\n        stack.pop_back();\n    };\n\n    std::string strCommandTerminated = strCommand;\n    if (strCommandTerminated.back() != '\\n')\n        strCommandTerminated += \"\\n\";\n    for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)\n    {\n        char ch = strCommandTerminated[chpos];\n        switch(state)\n        {\n            case STATE_COMMAND_EXECUTED_INNER:\n            case STATE_COMMAND_EXECUTED:\n            {\n                bool breakParsing = true;\n                switch(ch)\n                {\n                    case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;\n                    default:\n                        if (state == STATE_COMMAND_EXECUTED_INNER)\n                        {\n                            if (ch != ']')\n                            {\n                                // append char to the current argument (which is also used for the query command)\n                                curarg += ch;\n                                break;\n                            }\n                            if (curarg.size() && fExecute)\n                            {\n                                // if we have a value query, query arrays with index and objects with a string key\n                                UniValue subelement;\n                                if (lastResult.isArray())\n                                {\n                                    for(char argch: curarg)\n                                        if (!std::isdigit(argch))\n                                            throw std::runtime_error(\"Invalid result query\");\n                                    subelement = lastResult[atoi(curarg.c_str())];\n                                }\n                                else if (lastResult.isObject())\n                                    subelement = find_value(lastResult, curarg);\n                                else\n                                    throw std::runtime_error(\"Invalid result query\"); //no array or object: abort\n                                lastResult = subelement;\n                            }\n\n                            state = STATE_COMMAND_EXECUTED;\n                            break;\n                        }\n                        // don't break parsing when the char is required for the next argument\n                        breakParsing = false;\n\n                        // pop the stack and return the result to the current command arguments\n                        close_out_params();\n\n                        // don't stringify the json in case of a string to avoid doublequotes\n                        if (lastResult.isStr())\n                            curarg = lastResult.get_str();\n                        else\n                            curarg = lastResult.write(2);\n\n                        // if we have a non empty result, use it as stack argument otherwise as general result\n                        if (curarg.size())\n                        {\n                            if (stack.size())\n                                add_to_current_stack(curarg);\n                            else\n                                strResult = curarg;\n                        }\n                        curarg.clear();\n                        // assume eating space state\n                        state = STATE_EATING_SPACES;\n                }\n                if (breakParsing)\n                    break;\n            }\n            case STATE_ARGUMENT: // In or after argument\n            case STATE_EATING_SPACES_IN_ARG:\n            case STATE_EATING_SPACES_IN_BRACKETS:\n            case STATE_EATING_SPACES: // Handle runs of whitespace\n                switch(ch)\n            {\n                case '\"': state = STATE_DOUBLEQUOTED; break;\n                case '\\'': state = STATE_SINGLEQUOTED; break;\n                case '\\\\': state = STATE_ESCAPE_OUTER; break;\n                case '(': case ')': case '\\n':\n                    if (state == STATE_EATING_SPACES_IN_ARG)\n                        throw std::runtime_error(\"Invalid Syntax\");\n                    if (state == STATE_ARGUMENT)\n                    {\n                        if (ch == '(' && stack.size() && stack.back().size() > 0)\n                        {\n                            if (nDepthInsideSensitive) {\n                                ++nDepthInsideSensitive;\n                            }\n                            stack.push_back(std::vector<std::string>());\n                        }\n\n                        // don't allow commands after executed commands on baselevel\n                        if (!stack.size())\n                            throw std::runtime_error(\"Invalid Syntax\");\n\n                        add_to_current_stack(curarg);\n                        curarg.clear();\n                        state = STATE_EATING_SPACES_IN_BRACKETS;\n                    }\n                    if ((ch == ')' || ch == '\\n') && stack.size() > 0)\n                    {\n                        if (fExecute) {\n                            // Convert argument list to JSON objects in method-dependent way,\n                            // and pass it along with the method name to the dispatcher.\n                            JSONRPCRequest req;\n                            req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));\n                            req.strMethod = stack.back()[0];\n                            lastResult = tableRPC.execute(req);\n                        }\n\n                        state = STATE_COMMAND_EXECUTED;\n                        curarg.clear();\n                    }\n                    break;\n                case ' ': case ',': case '\\t':\n                    if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',')\n                        throw std::runtime_error(\"Invalid Syntax\");\n\n                    else if(state == STATE_ARGUMENT) // Space ends argument\n                    {\n                        add_to_current_stack(curarg);\n                        curarg.clear();\n                    }\n                    if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')\n                    {\n                        state = STATE_EATING_SPACES_IN_ARG;\n                        break;\n                    }\n                    state = STATE_EATING_SPACES;\n                    break;\n                default: curarg += ch; state = STATE_ARGUMENT;\n            }\n                break;\n            case STATE_SINGLEQUOTED: // Single-quoted string\n                switch(ch)\n            {\n                case '\\'': state = STATE_ARGUMENT; break;\n                default: curarg += ch;\n            }\n                break;\n            case STATE_DOUBLEQUOTED: // Double-quoted string\n                switch(ch)\n            {\n                case '\"': state = STATE_ARGUMENT; break;\n                case '\\\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;\n                default: curarg += ch;\n            }\n                break;\n            case STATE_ESCAPE_OUTER: // '\\' outside quotes\n                curarg += ch; state = STATE_ARGUMENT;\n                break;\n            case STATE_ESCAPE_DOUBLEQUOTED: // '\\' in double-quoted text\n                if(ch != '\"' && ch != '\\\\') curarg += '\\\\'; // keep '\\' for everything but the quote and '\\' itself\n                curarg += ch; state = STATE_DOUBLEQUOTED;\n                break;\n        }\n    }\n    if (pstrFilteredOut) {\n        if (STATE_COMMAND_EXECUTED == state) {\n            assert(!stack.empty());\n            close_out_params();\n        }\n        *pstrFilteredOut = strCommand;\n        for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {\n            pstrFilteredOut->replace(i->first, i->second - i->first, \"(…)\");\n        }\n    }\n    switch(state) // final state\n    {\n        case STATE_COMMAND_EXECUTED:\n            if (lastResult.isStr())\n                strResult = lastResult.get_str();\n            else\n                strResult = lastResult.write(2);\n        case STATE_ARGUMENT:\n        case STATE_EATING_SPACES:\n            return true;\n        // ERROR to end in one of the other states\n        case STATE_EATING_SPACES_IN_ARG: case STATE_EATING_SPACES_IN_BRACKETS: case STATE_SINGLEQUOTED: case STATE_DOUBLEQUOTED: case STATE_ESCAPE_OUTER: case STATE_ESCAPE_DOUBLEQUOTED: case STATE_COMMAND_EXECUTED_INNER:\n        default:\n            return false;\n    }\n}\n"
  },
  {
    "path": "src/controllers/rpccontroller.h",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// File contains modifications by: The Novo developers\n// All modifications:\n// Copyright (c) 2020 The Novo developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the NOVO software license, see the accompanying\n// file COPYING\n\n#ifndef CONTROLLERS_RPC_CONTROLLER\n#define CONTROLLERS_RPC_CONTROLLER\n\n#include <univalue/include/univalue.h>\n#include <tinyformat.h>\n#include <rpc/server.h>\n#include <rpc/client.h>\n\nclass RPCController\n{\npublic:\n    void executeCommandLine(const std::string& sCommandLine, const std::function<void(const std::string&)>& filteredCommandHandler, const std::function<void(const std::string&, const std::string&)>& errorHandler, const std::function<void(const std::string&, const std::string&)>& successHandler);\n    std::vector<std::string> getAutocompleteList();\nprivate:\n    bool parseCommandLine(std::string& strResult, const std::string& strCommand, const bool fExecute, std::string* const pstrFilteredOut);\n};\n\n#endif\n"
  },
  {
    "path": "src/core_io.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_IO_H\n#define CORE_IO_H\n\n#include <string>\n#include <vector>\n#include <primitives/transaction.h>\n\nclass CBlock;\nclass CScript;\nclass CTransaction;\nstruct CMutableTransaction;\nclass uint256;\nclass UniValue;\n\n// core_read.cpp\nCScript ParseScript(const std::string& s);\nstd::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);\nbool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);\nbool DecodeHexBlk(CBlock&, const std::string& strHexBlk);\nuint256 ParseHashUV(const UniValue& v, const std::string& strName);\nuint256 ParseHashStr(const std::string&, const std::string& strName);\nstd::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);\n\n// core_write.cpp\nstd::string FormatScript(const CScript& script);\nstd::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);\nvoid StandardKeyHashToUniv(const CTxOut& txout, UniValue& out, bool fIncludeHex);\nvoid PoW2WitnessToUniv(const CTxOut& txout, UniValue& out, bool fIncludeHex);\nvoid ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);\nvoid TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);\n\n#endif\n"
  },
  {
    "path": "src/core_memusage.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_MEMUSAGE_H\n#define CORE_MEMUSAGE_H\n\n#include \"primitives/transaction.h\"\n#include \"primitives/block.h\"\n#include \"memusage.h\"\n\nstatic inline size_t RecursiveDynamicUsage(const CScript& script) {\n    return memusage::DynamicUsage(*static_cast<const CScriptBase*>(&script));\n}\n\nstatic inline size_t RecursiveDynamicUsage([[maybe_unused]] const COutPoint& out) {\n    return 0;\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CTxIn& in) {\n    size_t mem = RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.GetPrevOut()) + memusage::DynamicUsage(in.segregatedSignatureData.stack);\n    for (std::vector<std::vector<unsigned char> >::const_iterator it = in.segregatedSignatureData.stack.begin(); it != in.segregatedSignatureData.stack.end(); it++) {\n         mem += memusage::DynamicUsage(*it);\n    }\n    return mem;\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CTxOut& out) {\n    switch(out.GetType())\n    {\n        case CTxOutType::PoW2WitnessOutput:\n            return sizeof(CTxOutPoW2Witness);\n        case CTxOutType::StandardKeyHashOutput:\n            return sizeof(CTxOutStandardKeyHash);\n        case CTxOutType::ScriptLegacyOutput:\n            break;\n    };\n\n    return RecursiveDynamicUsage(out.output.scriptPubKey);\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CTransaction& tx) {\n    size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);\n    for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {\n        mem += RecursiveDynamicUsage(*it);\n    }\n    for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {\n        mem += RecursiveDynamicUsage(*it);\n    }\n    return mem;\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {\n    size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);\n    for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {\n        mem += RecursiveDynamicUsage(*it);\n    }\n    for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {\n        mem += RecursiveDynamicUsage(*it);\n    }\n    return mem;\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CBlock& block) {\n    size_t mem = memusage::DynamicUsage(block.vtx);\n    for (const auto& tx : block.vtx) {\n        mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx);\n    }\n    return mem;\n}\n\nstatic inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) {\n    return memusage::DynamicUsage(locator.vHave);\n}\n\ntemplate<typename X>\nstatic inline size_t RecursiveDynamicUsage(const std::shared_ptr<X>& p) {\n    return p ? memusage::DynamicUsage(p) + RecursiveDynamicUsage(*p) : 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/core_read.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"core_io.h\"\n\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include <univalue.h>\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"version.h\"\n\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/predicate.hpp>\n#include <boost/algorithm/string/replace.hpp>\n#include <boost/algorithm/string/split.hpp>\n\nCScript ParseScript(const std::string& s)\n{\n    CScript result;\n\n    static std::map<std::string, opcodetype> mapOpNames;\n\n    if (mapOpNames.empty())\n    {\n        for (int op = 0; op <= OP_NOP10; op++)\n        {\n            // Allow OP_RESERVED to get into mapOpNames\n            if (op < OP_NOP && op != OP_RESERVED)\n                continue;\n\n            const char* name = GetOpName((opcodetype)op);\n            if (strcmp(name, \"OP_UNKNOWN\") == 0)\n                continue;\n            std::string strName(name);\n            mapOpNames[strName] = (opcodetype)op;\n            // Convenience: OP_ADD and just ADD are both recognized:\n            boost::algorithm::replace_first(strName, \"OP_\", \"\");\n            mapOpNames[strName] = (opcodetype)op;\n        }\n    }\n\n    std::vector<std::string> words;\n    boost::algorithm::split(words, s, boost::algorithm::is_any_of(\" \\t\\n\"), boost::algorithm::token_compress_on);\n\n    for (std::vector<std::string>::const_iterator w = words.begin(); w != words.end(); ++w)\n    {\n        if (w->empty())\n        {\n            // Empty string, ignore. (boost::split given '' will return one word)\n        }\n        else if (all(*w, boost::algorithm::is_digit()) ||\n            (boost::algorithm::starts_with(*w, \"-\") && all(std::string(w->begin()+1, w->end()), boost::algorithm::is_digit())))\n        {\n            // Number\n            int64_t n = atoi64(*w);\n            result << n;\n        }\n        else if (boost::algorithm::starts_with(*w, \"0x\") && (w->begin()+2 != w->end()) && IsHex(std::string(w->begin()+2, w->end())))\n        {\n            // Raw hex data, inserted NOT pushed onto stack:\n            std::vector<unsigned char> raw = ParseHex(std::string(w->begin()+2, w->end()));\n            result.insert(result.end(), raw.begin(), raw.end());\n        }\n        else if (w->size() >= 2 && boost::algorithm::starts_with(*w, \"'\") && boost::algorithm::ends_with(*w, \"'\"))\n        {\n            // Single-quoted string, pushed as data. NOTE: this is poor-man's\n            // parsing, spaces/tabs/newlines in single-quoted strings won't work.\n            std::vector<unsigned char> value(w->begin()+1, w->end()-1);\n            result << value;\n        }\n        else if (mapOpNames.count(*w))\n        {\n            // opcode, e.g. OP_ADD or ADD:\n            result << mapOpNames[*w];\n        }\n        else\n        {\n            throw std::runtime_error(\"script parse error\");\n        }\n    }\n\n    return result;\n}\n\n// Check that all of the input and output scripts of a transaction contains valid opcodes\nbool CheckTxScriptsSanity(const CMutableTransaction& tx)\n{\n    // Check input scripts for non-coinbase txs\n    // NB! For segsig transactions this is a no-op\n    //fixme: (PHASE5) - we can remove this entirely once all transactions are segsig\n    if (!CTransaction(tx).IsCoinBase()) {\n        for (unsigned int i = 0; i < tx.vin.size(); i++) {\n            if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {\n                return false;\n            }\n        }\n    }\n    // Check output scripts\n    for (unsigned int i = 0; i < tx.vout.size(); i++) {\n        if (tx.vout[i].GetType()  <= CTxOutType::ScriptLegacyOutput)\n        {\n            if (!tx.vout[i].output.scriptPubKey.HasValidOps() || tx.vout[i].output.scriptPubKey.size() > MAX_SCRIPT_SIZE) {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\nbool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)\n{\n    if (!IsHex(strHexTx)) {\n        return false;\n    }\n\n    std::vector<unsigned char> txData(ParseHex(strHexTx));\n\n    if (fTryNoWitness) {\n        CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES);\n        try {\n            ssData >> tx;\n            if (ssData.eof() && CheckTxScriptsSanity(tx)) {\n                return true;\n            }\n        }\n        catch (const std::exception&) {\n            // Fall through.\n        }\n    }\n\n    CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);\n    try {\n        ssData >> tx;\n        if (!ssData.empty()) {\n            return false;\n        }\n    }\n    catch (const std::exception&) {\n        return false;\n    }\n\n    return true;\n}\n\nbool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)\n{\n    if (!IsHex(strHexBlk))\n        return false;\n\n    {\n        std::vector<unsigned char> blockData(ParseHex(strHexBlk));\n        CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);\n        try\n        {\n            ssBlock >> block;\n        }\n        catch (const std::exception& e)\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nuint256 ParseHashUV(const UniValue& v, const std::string& strName)\n{\n    std::string strHex;\n    if (v.isStr())\n        strHex = v.getValStr();\n    return ParseHashStr(strHex, strName);  // Note: ParseHashStr(\"\") throws a runtime_error\n}\n\nuint256 ParseHashStr(const std::string& strHex, const std::string& strName)\n{\n    if (!IsHex(strHex)) // Note: IsHex(\"\") is false\n        throw std::runtime_error(strName + \" must be hexadecimal string (not '\" + strHex + \"')\");\n\n    uint256 result;\n    result.SetHex(strHex);\n    return result;\n}\n\nstd::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)\n{\n    std::string strHex;\n    if (v.isStr())\n        strHex = v.getValStr();\n    if (!IsHex(strHex))\n        throw std::runtime_error(strName + \" must be hexadecimal string (not '\" + strHex + \"')\");\n    return ParseHex(strHex);\n}\n"
  },
  {
    "path": "src/core_write.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"core_io.h\"\n\n#include \"base58.h\"\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include <univalue.h>\n#include \"util.h\"\n#include \"util/moneystr.h\"\n#include \"util/strencodings.h\"\n\n\nstd::string FormatScript(const CScript& script)\n{\n    std::string ret;\n    CScript::const_iterator it = script.begin();\n    opcodetype op;\n    while (it != script.end()) {\n        CScript::const_iterator it2 = it;\n        std::vector<unsigned char> vch;\n        if (script.GetOp2(it, op, &vch)) {\n            if (op == OP_0) {\n                ret += \"0 \";\n                continue;\n            } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) {\n                ret += strprintf(\"%i \", op - OP_1NEGATE - 1);\n                continue;\n            } else if (op >= OP_NOP && op <= OP_NOP10) {\n                std::string str(GetOpName(op));\n                if (str.substr(0, 3) == std::string(\"OP_\")) {\n                    ret += str.substr(3, std::string::npos) + \" \";\n                    continue;\n                }\n            }\n            if (vch.size() > 0) {\n                ret += strprintf(\"0x%x 0x%x \", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it));\n            } else {\n                ret += strprintf(\"0x%x \", HexStr(it2, it));\n            }\n            continue;\n        }\n        ret += strprintf(\"0x%x \", HexStr(it2, script.end()));\n        break;\n    }\n    return ret.substr(0, ret.size() - 1);\n}\n\nconst std::map<unsigned char, std::string> mapSigHashTypes = {\n    {static_cast<unsigned char>(SIGHASH_ALL), std::string(\"ALL\")},\n    {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string(\"ALL|ANYONECANPAY\")},\n    {static_cast<unsigned char>(SIGHASH_NONE), std::string(\"NONE\")},\n    {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string(\"NONE|ANYONECANPAY\")},\n    {static_cast<unsigned char>(SIGHASH_SINGLE), std::string(\"SINGLE\")},\n    {static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string(\"SINGLE|ANYONECANPAY\")},\n};\n\n/**\n * Create the assembly string representation of a CScript object.\n * @param[in] script    CScript object to convert into the asm string representation.\n * @param[in] fAttemptSighashDecode    Whether to attempt to decode sighash types on data within the script that matches the format\n *                                     of a signature. Only pass true for scripts you believe could contain signatures. For example,\n *                                     pass false, or omit the this argument (defaults to false), for scriptPubKeys.\n */\nstd::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)\n{\n    std::string str;\n    opcodetype opcode;\n    std::vector<unsigned char> vch;\n    CScript::const_iterator pc = script.begin();\n    while (pc < script.end()) {\n        if (!str.empty()) {\n            str += \" \";\n        }\n        if (!script.GetOp(pc, opcode, vch)) {\n            str += \"[error]\";\n            return str;\n        }\n        if (0 <= opcode && opcode <= OP_PUSHDATA4) {\n            if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) {\n                str += strprintf(\"%d\", CScriptNum(vch, false).getint());\n            } else {\n                // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature\n                if (fAttemptSighashDecode && !script.IsUnspendable()) {\n                    std::string strSigHashDecode;\n                    // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.\n                    // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to\n                    // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the\n                    // checks in CheckSignatureEncoding.\n                    if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) {\n                        const unsigned char chSigHashType = vch.back();\n                        if (mapSigHashTypes.count(chSigHashType)) {\n                            strSigHashDecode = \"[\" + mapSigHashTypes.find(chSigHashType)->second + \"]\";\n                            vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.\n                        }\n                    }\n                    str += HexStr(vch) + strSigHashDecode;\n                } else {\n                    str += HexStr(vch);\n                }\n            }\n        } else {\n            str += GetOpName(opcode);\n        }\n    }\n    return str;\n}\n\nstd::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)\n{\n    CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags);\n    ssTx << tx;\n    return HexStr(ssTx.begin(), ssTx.end());\n}\n\nvoid ScriptPubKeyToUniv(const CScript& scriptPubKey,\n                        UniValue& out, bool fIncludeHex)\n{\n    txnouttype type;\n    std::vector<CTxDestination> addresses;\n    int nRequired;\n\n    out.pushKV(\"asm\", ScriptToAsmStr(scriptPubKey));\n    if (fIncludeHex)\n        out.pushKV(\"hex\", HexStr(scriptPubKey.begin(), scriptPubKey.end()));\n\n    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {\n        out.pushKV(\"type\", GetTxnOutputType(type));\n        return;\n    }\n\n    out.pushKV(\"reqSigs\", nRequired);\n    out.pushKV(\"type\", GetTxnOutputType(type));\n\n    UniValue a(UniValue::VARR);\n    for(const CTxDestination& addr : addresses)\n        a.push_back(CNativeAddress(addr).ToString());\n    out.pushKV(\"addresses\", a);\n}\n\nvoid StandardKeyHashToUniv(const CTxOut& txout, UniValue& out, bool fIncludeHex)\n{\n    if (fIncludeHex)\n        out.pushKV(\"hex\", txout.output.GetHex());\n\n    out.pushKV(\"address\", CNativeAddress(txout.output.standardKeyHash.keyID).ToString());\n}\n\nvoid PoW2WitnessToUniv(const CTxOut& txout, UniValue& out, bool fIncludeHex)\n{\n    if (fIncludeHex)\n        out.pushKV(\"hex\", txout.output.GetHex());\n\n    out.pushKV(\"lock_from_block\", txout.output.witnessDetails.lockFromBlock);\n    out.pushKV(\"lock_until_block\", txout.output.witnessDetails.lockUntilBlock);\n    out.pushKV(\"fail_count\", txout.output.witnessDetails.failCount);\n    out.pushKV(\"action_nonce\", txout.output.witnessDetails.actionNonce);\n    out.pushKV(\"pubkey_spend\", txout.output.witnessDetails.spendingKeyID.ToString());\n    out.pushKV(\"pubkey_witness\", txout.output.witnessDetails.witnessKeyID.ToString());\n\n    out.pushKV(\"address\", CNativeAddress(CPoW2WitnessDestination(txout.output.witnessDetails.spendingKeyID, txout.output.witnessDetails.witnessKeyID)).ToString());\n}\n\n\n\nvoid TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)\n{\n    entry.pushKV(\"txid\", tx.GetHash().GetHex());\n    entry.pushKV(\"hash\", tx.GetWitnessHash().GetHex());\n    entry.pushKV(\"version\", tx.nVersion);\n    entry.pushKV(\"size\", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));\n    entry.pushKV(\"vsize\", GetTransactionWeight(tx));\n    entry.pushKV(\"locktime\", (int64_t)tx.nLockTime);\n\n    UniValue vin(UniValue::VARR);\n    for (unsigned int i = 0; i < tx.vin.size(); i++) {\n        const CTxIn& txin = tx.vin[i];\n        UniValue in(UniValue::VOBJ);\n        if (tx.IsCoinBase() && !tx.IsPoW2WitnessCoinBase())\n        {\n            in.pushKV(\"coinbase\", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));\n        }\n        else\n        {\n            if ( tx.IsPoW2WitnessCoinBase() )\n            {\n                in.pushKV(\"pow2_coinbase\", \"\");\n            }\n            if (txin.GetPrevOut().isHash)\n            {\n                in.pushKV(\"prevout_type\", \"hash\");\n                in.pushKV(\"txid\", txin.GetPrevOut().getTransactionHash().GetHex());\n                in.pushKV(\"tx_height\", \"\");\n                in.pushKV(\"tx_index\", \"\");\n            }\n            else\n            {\n                in.pushKV(\"prevout_type\", \"index\");\n                in.pushKV(\"txid\", \"\");\n                in.pushKV(\"tx_height\", txin.GetPrevOut().getTransactionBlockNumber());\n                in.pushKV(\"tx_index\", txin.GetPrevOut().getTransactionIndex());\n            }\n            \n            in.pushKV(\"vout\", (int64_t)txin.GetPrevOut().n);\n            UniValue o(UniValue::VOBJ);\n            o.pushKV(\"asm\", ScriptToAsmStr(txin.scriptSig, true));\n            o.pushKV(\"hex\", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));\n            in.pushKV(\"scriptSig\", o);\n            if (!tx.vin[i].segregatedSignatureData.IsNull()) \n            {\n                UniValue txinSigData(UniValue::VARR);\n                for (const auto& item : tx.vin[i].segregatedSignatureData.stack)\n                {\n                    txinSigData.push_back(HexStr(item.begin(), item.end()));\n                }\n                in.pushKV(\"txin_sig_data\", txinSigData);\n            }\n        }\n        if (IsOldTransactionVersion(tx.nVersion) || txin.FlagIsSet(CTxInFlags::HasRelativeLock))\n        {\n            in.pushKV(\"sequence\", (int64_t)txin.GetSequence(tx.nVersion));\n        }\n        if (txin.FlagIsSet(CTxInFlags::OptInRBF))\n        {\n            in.pushKV(\"rbf\", true);\n        }\n        else\n        {\n            in.pushKV(\"rbf\", false);\n        }\n        vin.push_back(in);\n    }\n    entry.pushKV(\"vin\", vin);\n\n    UniValue vout(UniValue::VARR);\n    for (unsigned int i = 0; i < tx.vout.size(); i++)\n    {\n        const CTxOut& txout = tx.vout[i];\n\n        UniValue out(UniValue::VOBJ);\n\n        UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue));\n        out.pushKV(\"value\", outValue);\n        out.pushKV(\"n\", (int64_t)i);\n\n        switch (txout.GetType())\n        {\n            case CTxOutType::ScriptLegacyOutput:\n            {\n                UniValue o(UniValue::VOBJ);\n                ScriptPubKeyToUniv(txout.output.scriptPubKey, o, true);\n                out.pushKV(\"scriptPubKey\", o);\n                vout.push_back(out);\n                break;\n            }\n            case CTxOutType::PoW2WitnessOutput:\n            {\n                UniValue o(UniValue::VOBJ);\n                PoW2WitnessToUniv(txout, o, true);\n                out.pushKV(\"PoW²-witness\", o);\n                vout.push_back(out);\n                break;\n            }\n            case CTxOutType::StandardKeyHashOutput:\n            {\n                UniValue o(UniValue::VOBJ);\n                StandardKeyHashToUniv(txout, o, true);\n                out.pushKV(\"standard-key-hash\", o);\n                vout.push_back(out);\n                break;\n            }\n        }\n    }\n    entry.pushKV(\"vout\", vout);\n\n    if (!hashBlock.IsNull())\n        entry.pushKV(\"blockhash\", hashBlock.GetHex());\n\n    entry.pushKV(\"hex\", EncodeHexTx(tx)); // the hex-encoded transaction. used the name \"hex\" to be consistent with the verbose output of \"getrawtransaction\".\n}\n"
  },
  {
    "path": "src/crc32c/.appveyor.yml",
    "content": "# Build matrix / environment variables are explained on:\n# https://www.appveyor.com/docs/appveyor-yml/\n# This file can be validated on: https://ci.appveyor.com/tools/validate-yaml\n\nversion: \"{build}\"\n\nenvironment:\n  matrix:\n    # AppVeyor currently has no custom job name feature.\n    # http://help.appveyor.com/discussions/questions/1623-can-i-provide-a-friendly-name-for-jobs\n    - JOB: Visual Studio 2019\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019\n      CMAKE_GENERATOR: Visual Studio 16 2019\n\nplatform:\n  - x86\n  - x64\n\nconfiguration:\n  - RelWithDebInfo\n  - Debug\n\nbuild_script:\n  - git submodule update --init --recursive\n  - mkdir build\n  - cd build\n  - if \"%platform%\"==\"x86\" (set CMAKE_GENERATOR_PLATFORM=\"Win32\")\n      else (set CMAKE_GENERATOR_PLATFORM=\"%platform%\")\n  - cmake --version\n  - cmake .. -G \"%CMAKE_GENERATOR%\" -A \"%CMAKE_GENERATOR_PLATFORM%\"\n      -DCMAKE_CONFIGURATION_TYPES=\"%CONFIGURATION%\" -DCRC32C_USE_GLOG=0\n  - cmake --build . --config \"%CONFIGURATION%\"\n  - cd ..\n\ntest_script:\n  - build\\%CONFIGURATION%\\crc32c_tests.exe\n  - build\\%CONFIGURATION%\\crc32c_capi_tests.exe\n  - build\\%CONFIGURATION%\\crc32c_bench.exe\n"
  },
  {
    "path": "src/crc32c/.clang-format",
    "content": "---\nLanguage:      Cpp\nBasedOnStyle:  Google\n"
  },
  {
    "path": "src/crc32c/.clang_complete",
    "content": "-Ibuild/include/\n-Ibuild/third_party/glog/\n-Iinclude/\n-Ithird_party/benchmark/include/\n-Ithird_party/googletest/googletest/include/\n-Ithird_party/googletest/googlemock/include/\n-Ithird_party/glog/src/\n-std=c++11\n"
  },
  {
    "path": "src/crc32c/.gitignore",
    "content": "# Editors.\n*.sw*\n.DS_Store\n/.vscode\n\n# Build directory.\nbuild/\nout/\n"
  },
  {
    "path": "src/crc32c/.gitmodules",
    "content": ""
  },
  {
    "path": "src/crc32c/.travis.yml",
    "content": "# Build matrix / environment variables are explained on:\n# http://about.travis-ci.org/docs/user/build-configuration/\n# This file can be validated on: http://lint.travis-ci.org/\n\nlanguage: cpp\ndist: bionic\nosx_image: xcode12.5\n\ncompiler:\n- gcc\n- clang\nos:\n- linux\n- osx\n\nenv:\n- GLOG=1 SHARED_LIB=0 BUILD_TYPE=Debug\n- GLOG=1 SHARED_LIB=0 BUILD_TYPE=RelWithDebInfo\n- GLOG=0 SHARED_LIB=0 BUILD_TYPE=Debug\n- GLOG=0 SHARED_LIB=0 BUILD_TYPE=RelWithDebInfo\n- GLOG=0 SHARED_LIB=1 BUILD_TYPE=Debug\n- GLOG=0 SHARED_LIB=1 BUILD_TYPE=RelWithDebInfo\n\naddons:\n  apt:\n    sources:\n    - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main'\n      key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'\n    - sourceline: 'ppa:ubuntu-toolchain-r/test'\n    packages:\n    - clang-12\n    - cmake\n    - gcc-11\n    - g++-11\n    - ninja-build\n  homebrew:\n    packages:\n    - cmake\n    - gcc@11\n    - llvm@12\n    - ninja\n    update: true\n\ninstall:\n# The following Homebrew packages aren't linked by default, and need to be\n# prepended to the path explicitly.\n- if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then\n    export PATH=\"$(brew --prefix llvm)/bin:$PATH\";\n  fi\n# /usr/bin/gcc points to an older compiler on both Linux and macOS.\n- if [ \"$CXX\" = \"g++\" ]; then export CXX=\"g++-11\" CC=\"gcc-11\"; fi\n# /usr/bin/clang points to an older compiler on both Linux and macOS.\n#\n# Homebrew's llvm package doesn't ship a versioned clang++ binary, so the values\n# below don't work on macOS. Fortunately, the path change above makes the\n# default values (clang and clang++) resolve to the correct compiler on macOS.\n- if [ \"$TRAVIS_OS_NAME\" = \"linux\" ]; then\n    if [ \"$CXX\" = \"clang++\" ]; then export CXX=\"clang++-12\" CC=\"clang-12\"; fi;\n  fi\n- echo ${CC}\n- echo ${CXX}\n- ${CXX} --version\n- cmake --version\n\nbefore_script:\n- mkdir -p build && cd build\n- cmake .. -G Ninja -DCRC32C_USE_GLOG=$GLOG -DCMAKE_BUILD_TYPE=$BUILD_TYPE\n           -DBUILD_SHARED_LIBS=$SHARED_LIB -DCMAKE_INSTALL_PREFIX=$HOME/.local\n- cmake --build .\n- cd ..\n\nscript:\n- build/crc32c_tests\n- build/crc32c_capi_tests\n- build/crc32c_bench\n- cd build && cmake --build . --target install\n"
  },
  {
    "path": "src/crc32c/.ycm_extra_conf.py",
    "content": "# Copyright 2017 The CRC32C Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license that can be\n# found in the LICENSE file.\n\"\"\"YouCompleteMe configuration that interprets a .clang_complete file.\n\nThis module implementes the YouCompleteMe configuration API documented at:\nhttps://github.com/ycm-core/ycmd#ycm_extra_confpy-specification\n\nThe implementation loads and processes a .clang_complete file, documented at:\nhttps://github.com/xavierd/clang_complete/blob/master/README.md\n\"\"\"\n\nimport os\n\n# Flags added to the list in .clang_complete.\nBASE_FLAGS = [\n    '-Werror',  # Unlike clang_complete, YCM can also be used as a linter.\n    '-DUSE_CLANG_COMPLETER',  # YCM needs this.\n    '-xc++',  # YCM needs this to avoid compiling headers as C code.\n]\n\n# Clang flags that take in paths.\n# See https://clang.llvm.org/docs/ClangCommandLineReference.html\nPATH_FLAGS = [\n    '-isystem',\n    '-I',\n    '-iquote',\n    '--sysroot='\n]\n\n\ndef DirectoryOfThisScript():\n  \"\"\"Returns the absolute path to the directory containing this script.\"\"\"\n  return os.path.dirname(os.path.abspath(__file__))\n\n\ndef MakeRelativePathsInFlagsAbsolute(flags, build_root):\n  \"\"\"Expands relative paths in a list of Clang command-line flags.\n\n  Args:\n    flags: The list of flags passed to Clang.\n    build_root: The current directory when running the Clang compiler. Should be\n        an absolute path.\n\n  Returns:\n    A list of flags with relative paths replaced by absolute paths.\n  \"\"\"\n  new_flags = []\n  make_next_absolute = False\n  for flag in flags:\n    new_flag = flag\n\n    if make_next_absolute:\n      make_next_absolute = False\n      if not flag.startswith('/'):\n        new_flag = os.path.join(build_root, flag)\n\n    for path_flag in PATH_FLAGS:\n      if flag == path_flag:\n        make_next_absolute = True\n        break\n\n      if flag.startswith(path_flag):\n        path = flag[len(path_flag):]\n        new_flag = path_flag + os.path.join(build_root, path)\n        break\n\n    if new_flag:\n      new_flags.append(new_flag)\n  return new_flags\n\n\ndef FindNearest(target, path, build_root):\n  \"\"\"Looks for a file with a specific name closest to a project path.\n\n  This is similar to the logic used by a version-control system (like git) to\n  find its configuration directory (.git) based on the current directory when a\n  command is invoked.\n\n  Args:\n    target: The file name to search for.\n    path: The directory where the search starts. The search will explore the\n        given directory's ascendants using the parent relationship. Should be an\n        absolute path.\n    build_root: A directory that acts as a fence for the search. If the search\n        reaches this directory, it will not advance to its parent. Should be an\n        absolute path.\n\n  Returns:\n    The path to a file with the desired name. None if the search failed.\n  \"\"\"\n  candidate = os.path.join(path, target)\n  if os.path.isfile(candidate):\n    return candidate\n\n  if path == build_root:\n    return None\n\n  parent = os.path.dirname(path)\n  if parent == path:\n    return None\n\n  return FindNearest(target, parent, build_root)\n\n\ndef FlagsForClangComplete(file_path, build_root):\n  \"\"\"Reads the .clang_complete flags for a source file.\n\n  Args:\n    file_path: The path to the source file. Should be inside the project. Used\n      to locate the relevant .clang_complete file.\n    build_root: The current directory when running the Clang compiler for this\n        file. Should be an absolute path.\n\n  Returns:\n    A list of strings, where each element is a Clang command-line flag.\n  \"\"\"\n  clang_complete_path = FindNearest('.clang_complete', file_path, build_root)\n  if clang_complete_path is None:\n    return None\n  clang_complete_flags = open(clang_complete_path, 'r').read().splitlines()\n  return clang_complete_flags\n\n\ndef FlagsForFile(filename, **kwargs):\n  \"\"\"Implements the YouCompleteMe API.\"\"\"\n\n  # kwargs can be used to pass 'client_data' to the YCM configuration. This\n  # configuration script does not need any extra information, so\n  # pylint: disable=unused-argument\n\n  build_root = DirectoryOfThisScript()\n  file_path = os.path.realpath(filename)\n\n  flags = BASE_FLAGS\n  clang_flags = FlagsForClangComplete(file_path, build_root)\n  if clang_flags:\n    flags += clang_flags\n\n  final_flags = MakeRelativePathsInFlagsAbsolute(flags, build_root)\n\n  return {'flags': final_flags}\n"
  },
  {
    "path": "src/crc32c/AUTHORS",
    "content": "# This is the list of CRC32C authors for copyright purposes.\n#\n# This does not necessarily list everyone who has contributed code, since in\n# some cases, their employer may be the copyright holder.  To see the full list\n# of contributors, see the revision history in source control.\nGoogle Inc.\n\nFangming Fang <Fangming.Fang@arm.com>\nVadim Skipin <vadim.skipin@gmail.com>\nRodrigo Tobar <rtobar@icrar.org>\nHarry Mallon <hjmallon@gmail.com>\n"
  },
  {
    "path": "src/crc32c/CMakeLists.txt",
    "content": "# Copyright 2017 The CRC32C Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license that can be\n# found in the LICENSE file. See the AUTHORS file for names of contributors.\n\ncmake_minimum_required(VERSION 3.1)\nproject(Crc32c VERSION 1.1.0 LANGUAGES C CXX)\n\n# C standard can be overridden when this is used as a sub-project.\nif(NOT CMAKE_C_STANDARD)\n  # This project can use C11, but will gracefully decay down to C89.\n  set(CMAKE_C_STANDARD 11)\n  set(CMAKE_C_STANDARD_REQUIRED OFF)\n  set(CMAKE_C_EXTENSIONS OFF)\nendif(NOT CMAKE_C_STANDARD)\n\n# C++ standard can be overridden when this is used as a sub-project.\nif(NOT CMAKE_CXX_STANDARD)\n  # This project requires C++11.\n  set(CMAKE_CXX_STANDARD 11)\n  set(CMAKE_CXX_STANDARD_REQUIRED ON)\n  set(CMAKE_CXX_EXTENSIONS OFF)\nendif(NOT CMAKE_CXX_STANDARD)\n\n# https://github.com/izenecloud/cmake/blob/master/SetCompilerWarningAll.cmake\nif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  # Use the highest warning level for Visual Studio.\n  set(CMAKE_CXX_WARNING_LEVEL 4)\n  if(CMAKE_CXX_FLAGS MATCHES \"/W[0-4]\")\n    string(REGEX REPLACE \"/W[0-4]\" \"/W4\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  else(CMAKE_CXX_FLAGS MATCHES \"/W[0-4]\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /W4\")\n  endif(CMAKE_CXX_FLAGS MATCHES \"/W[0-4]\")\n\n  # Disable C++ exceptions.\n  string(REGEX REPLACE \"/EH[a-z]+\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /EHs-c-\")\n  add_definitions(-D_HAS_EXCEPTIONS=0)\n\n  # Disable RTTI.\n  string(REGEX REPLACE \"/GR\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /GR-\")\nelse(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  # Use -Wall for clang and gcc.\n  if(NOT CMAKE_CXX_FLAGS MATCHES \"-Wall\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall\")\n  endif(NOT CMAKE_CXX_FLAGS MATCHES \"-Wall\")\n\n  # Use -Wextra for clang and gcc.\n  if(NOT CMAKE_CXX_FLAGS MATCHES \"-Wextra\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wextra\")\n  endif(NOT CMAKE_CXX_FLAGS MATCHES \"-Wextra\")\n\n  # Use -Werror for clang and gcc.\n  if(NOT CMAKE_CXX_FLAGS MATCHES \"-Werror\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Werror\")\n  endif(NOT CMAKE_CXX_FLAGS MATCHES \"-Werror\")\n\n  # Disable C++ exceptions.\n  string(REGEX REPLACE \"-fexceptions\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-exceptions\")\n\n  # Disable RTTI.\n  string(REGEX REPLACE \"-frtti\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-rtti\")\nendif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\noption(CRC32C_BUILD_TESTS \"Build CRC32C's unit tests\" ON)\noption(CRC32C_BUILD_BENCHMARKS \"Build CRC32C's benchmarks\" ON)\noption(CRC32C_USE_GLOG \"Build CRC32C's tests with Google Logging\" ON)\noption(CRC32C_INSTALL \"Install CRC32C's header and library\" ON)\n\ninclude(TestBigEndian)\ntest_big_endian(BYTE_ORDER_BIG_ENDIAN)\n\ninclude(CheckCXXCompilerFlag)\n# Used by glog.\ncheck_cxx_compiler_flag(-Wno-deprecated CRC32C_HAVE_NO_DEPRECATED)\n# Used by glog.\ncheck_cxx_compiler_flag(-Wno-sign-compare CRC32C_HAVE_NO_SIGN_COMPARE)\n# Used by glog.\ncheck_cxx_compiler_flag(-Wno-unused-parameter CRC32C_HAVE_NO_UNUSED_PARAMETER)\n# Used by googletest.\ncheck_cxx_compiler_flag(-Wno-missing-field-initializers\n                        CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)\n\n# Check for __builtin_prefetch support in the compiler.\ninclude(CheckCXXSourceCompiles)\ncheck_cxx_source_compiles(\"\nint main() {\n  char data = 0;\n  const char* address = &data;\n  __builtin_prefetch(address, 0, 0);\n  return 0;\n}\n\"  HAVE_BUILTIN_PREFETCH)\n\n# Check for _mm_prefetch support in the compiler.\ninclude(CheckCXXSourceCompiles)\ncheck_cxx_source_compiles(\"\n#if defined(_MSC_VER)\n#include <intrin.h>\n#else  // !defined(_MSC_VER)\n#include <xmmintrin.h>\n#endif  // defined(_MSC_VER)\n\nint main() {\n  char data = 0;\n  const char* address = &data;\n  _mm_prefetch(address, _MM_HINT_NTA);\n  return 0;\n}\n\"  HAVE_MM_PREFETCH)\n\n# Check for SSE4.2 support in the compiler.\nset(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS})\nif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set(CMAKE_REQUIRED_FLAGS \"${CMAKE_REQUIRED_FLAGS} /arch:AVX\")\nelse(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set(CMAKE_REQUIRED_FLAGS \"${CMAKE_REQUIRED_FLAGS} -msse4.2\")\nendif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\ncheck_cxx_source_compiles(\"\n#if defined(_MSC_VER)\n#include <intrin.h>\n#else  // !defined(_MSC_VER)\n#include <cpuid.h>\n#include <nmmintrin.h>\n#endif  // defined(_MSC_VER)\n\nint main() {\n  _mm_crc32_u8(0, 0); _mm_crc32_u32(0, 0);\n#if defined(_M_X64) || defined(__x86_64__)\n   _mm_crc32_u64(0, 0);\n#endif // defined(_M_X64) || defined(__x86_64__)\n  return 0;\n}\n\"  HAVE_SSE42)\nset(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})\n\n# Check for ARMv8 w/ CRC and CRYPTO extensions support in the compiler.\nset(OLD_CMAKE_REQURED_FLAGS ${CMAKE_REQUIRED_FLAGS})\nif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  # TODO(pwnall): Insert correct flag when VS gets ARM CRC32C support.\n  set(CMAKE_REQUIRED_FLAGS \"${CMAKE_REQUIRED_FLAGS} /arch:NOTYET\")\nelse(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set(CMAKE_REQUIRED_FLAGS \"${CMAKE_REQUIRED_FLAGS} -march=armv8-a+crc+crypto\")\nendif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\ncheck_cxx_source_compiles(\"\n#include <arm_acle.h>\n#include <arm_neon.h>\n\nint main() {\n  __crc32cb(0, 0); __crc32ch(0, 0); __crc32cw(0, 0); __crc32cd(0, 0);\n  vmull_p64(0, 0);\n  return 0;\n}\n\" HAVE_ARM64_CRC32C)\nset(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQURED_FLAGS})\n\n# Check for strong getauxval() support in the system headers.\ncheck_cxx_source_compiles(\"\n#include <arm_acle.h>\n#include <arm_neon.h>\n#include <sys/auxv.h>\n\nint main() {\n  getauxval(AT_HWCAP);\n  return 0;\n}\n\" HAVE_STRONG_GETAUXVAL)\n\n# Check for weak getauxval() support in the compiler.\ncheck_cxx_source_compiles(\"\nunsigned long getauxval(unsigned long type) __attribute__((weak));\n#define AT_HWCAP 16\n\nint main() {\n  getauxval(AT_HWCAP);\n  return 0;\n}\n\" HAVE_WEAK_GETAUXVAL)\n\nif(CRC32C_USE_GLOG)\n  # glog requires this setting to avoid using dynamic_cast.\n  set(DISABLE_RTTI ON CACHE BOOL \"\" FORCE)\n\n  # glog's test targets trigger deprecation warnings, and compiling them burns\n  # CPU cycles on the CI.\n  set(BUILD_TESTING_SAVED \"${BUILD_TESTING}\")\n  set(BUILD_TESTING OFF CACHE BOOL \"\" FORCE)\n  add_subdirectory(\"third_party/glog\" EXCLUDE_FROM_ALL)\n  set(BUILD_TESTING \"${BUILD_TESTING_SAVED}\" CACHE BOOL \"\" FORCE)\n\n  # glog triggers deprecation warnings on OSX.\n  # https://github.com/google/glog/issues/185\n  if(CRC32C_HAVE_NO_DEPRECATED)\n    set_property(TARGET glog APPEND PROPERTY COMPILE_OPTIONS -Wno-deprecated)\n  endif(CRC32C_HAVE_NO_DEPRECATED)\n\n  # glog triggers sign comparison warnings on gcc.\n  if(CRC32C_HAVE_NO_SIGN_COMPARE)\n    set_property(TARGET glog APPEND PROPERTY COMPILE_OPTIONS -Wno-sign-compare)\n  endif(CRC32C_HAVE_NO_SIGN_COMPARE)\n\n  # glog triggers unused parameter warnings on clang.\n  if(CRC32C_HAVE_NO_UNUSED_PARAMETER)\n    set_property(TARGET glog\n                 APPEND PROPERTY COMPILE_OPTIONS -Wno-unused-parameter)\n  endif(CRC32C_HAVE_NO_UNUSED_PARAMETER)\n\n  set(CRC32C_TESTS_BUILT_WITH_GLOG 1)\nendif(CRC32C_USE_GLOG)\n\nconfigure_file(\n  \"src/crc32c_config.h.in\"\n  \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n)\n\ninclude_directories(\"${PROJECT_BINARY_DIR}/include\")\n\n# ARM64 CRC32C code is built separately, so we don't accidentally compile\n# unsupported instructions into code that gets run without ARM32 support.\nadd_library(crc32c_arm64 OBJECT \"\")\ntarget_sources(crc32c_arm64\n  PRIVATE\n    \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n    \"src/crc32c_arm64.cc\"\n    \"src/crc32c_arm64.h\"\n)\nif(HAVE_ARM64_CRC32C)\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    # TODO(pwnall): Insert correct flag when VS gets ARM64 CRC32C support.\n    target_compile_options(crc32c_arm64 PRIVATE \"/arch:NOTYET\")\n  else(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    target_compile_options(crc32c_arm64 PRIVATE \"-march=armv8-a+crc+crypto\")\n  endif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\nendif(HAVE_ARM64_CRC32C)\n\n# CMake only enables PIC by default in SHARED and MODULE targets.\nif(BUILD_SHARED_LIBS)\n  set_property(TARGET crc32c_arm64 PROPERTY POSITION_INDEPENDENT_CODE TRUE)\nendif(BUILD_SHARED_LIBS)\n\n# SSE4.2 code is built separately, so we don't accidentally compile unsupported\n# instructions into code that gets run without SSE4.2 support.\nadd_library(crc32c_sse42 OBJECT \"\")\ntarget_sources(crc32c_sse42\n  PRIVATE\n    \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n    \"src/crc32c_sse42.cc\"\n    \"src/crc32c_sse42.h\"\n)\nif(HAVE_SSE42)\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    target_compile_options(crc32c_sse42 PRIVATE \"/arch:AVX\")\n  else(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    target_compile_options(crc32c_sse42 PRIVATE \"-msse4.2\")\n  endif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\nendif(HAVE_SSE42)\n\n# CMake only enables PIC by default in SHARED and MODULE targets.\nif(BUILD_SHARED_LIBS)\n  set_property(TARGET crc32c_sse42 PROPERTY POSITION_INDEPENDENT_CODE TRUE)\nendif(BUILD_SHARED_LIBS)\n\n# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.\ninclude(GNUInstallDirs)\n\nadd_library(crc32c \"\"\n  # TODO(pwnall): Move the TARGET_OBJECTS generator expressions to the PRIVATE\n  # section of target_sources when cmake_minimum_required becomes 3.9 or above.\n  $<TARGET_OBJECTS:crc32c_arm64>\n  $<TARGET_OBJECTS:crc32c_sse42>\n)\ntarget_sources(crc32c\n  PRIVATE\n    \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n    \"src/crc32c_arm64.h\"\n    \"src/crc32c_arm64_check.h\"\n    \"src/crc32c_internal.h\"\n    \"src/crc32c_portable.cc\"\n    \"src/crc32c_prefetch.h\"\n    \"src/crc32c_read_le.h\"\n    \"src/crc32c_round_up.h\"\n    \"src/crc32c_sse42.h\"\n    \"src/crc32c_sse42_check.h\"\n    \"src/crc32c.cc\"\n\n  # Only CMake 3.3+ supports PUBLIC sources in targets exported by \"install\".\n  $<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC>\n    \"include/crc32c/crc32c.h\"\n)\n\ntarget_include_directories(crc32c\n  PUBLIC\n    $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n)\n\ntarget_compile_definitions(crc32c\nPRIVATE\n  CRC32C_HAVE_CONFIG_H=1\n)\n\nset_target_properties(crc32c\n  PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})\n\n# Warnings as errors in Visual Studio for this project's targets.\nif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set_property(TARGET crc32c APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\n  set_property(TARGET crc32c_arm64 APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\n  set_property(TARGET crc32c_sse42 APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\nendif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\nif(CRC32C_BUILD_TESTS)\n  enable_testing()\n\n  # Prevent overriding the parent project's compiler/linker settings on Windows.\n  set(gtest_force_shared_crt ON CACHE BOOL \"\" FORCE)\n  set(install_gtest OFF)\n  set(install_gmock OFF)\n\n  # This project is tested using GoogleTest.\n  add_subdirectory(\"third_party/googletest\")\n\n  # GoogleTest triggers a missing field initializers warning.\n  if(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)\n    set_property(TARGET gtest\n        APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)\n    set_property(TARGET gmock\n        APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)\n  endif(CRC32C_HAVE_NO_MISSING_FIELD_INITIALIZERS)\n\n  add_executable(crc32c_tests \"\")\n  target_sources(crc32c_tests\n    PRIVATE\n      \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n      \"src/crc32c_arm64_unittest.cc\"\n      \"src/crc32c_extend_unittests.h\"\n      \"src/crc32c_portable_unittest.cc\"\n      \"src/crc32c_prefetch_unittest.cc\"\n      \"src/crc32c_read_le_unittest.cc\"\n      \"src/crc32c_round_up_unittest.cc\"\n      \"src/crc32c_sse42_unittest.cc\"\n      \"src/crc32c_unittest.cc\"\n      \"src/crc32c_test_main.cc\"\n  )\n  target_link_libraries(crc32c_tests crc32c gtest)\n\n  # Warnings as errors in Visual Studio for this project's targets.\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    set_property(TARGET crc32c_tests APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\n  endif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\n  if(CRC32C_USE_GLOG)\n    target_link_libraries(crc32c_tests glog)\n  endif(CRC32C_USE_GLOG)\n\n  add_test(NAME crc32c_tests COMMAND crc32c_tests)\n\n  add_executable(crc32c_capi_tests \"\")\n  target_sources(crc32c_capi_tests\n    PRIVATE\n      \"src/crc32c_capi_unittest.c\"\n  )\n  target_link_libraries(crc32c_capi_tests crc32c)\n\n  # Warnings as errors in Visual Studio for this project's targets.\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    set_property(TARGET crc32c_capi_tests APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\n  endif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\n  add_test(NAME crc32c_capi_tests COMMAND crc32c_capi_tests)\nendif(CRC32C_BUILD_TESTS)\n\nif(CRC32C_BUILD_BENCHMARKS)\n  add_executable(crc32c_bench \"\")\n  target_sources(crc32c_bench\n    PRIVATE\n      \"${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h\"\n      \"src/crc32c_benchmark.cc\"\n  )\n  target_link_libraries(crc32c_bench crc32c)\n\n  # This project uses Google benchmark for benchmarking.\n  set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL \"\" FORCE)\n  set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL \"\" FORCE)\n  add_subdirectory(\"third_party/benchmark\")\n  target_link_libraries(crc32c_bench benchmark)\n\n  if(CRC32C_USE_GLOG)\n    target_link_libraries(crc32c_bench glog)\n  endif(CRC32C_USE_GLOG)\n\n  # Warnings as errors in Visual Studio for this project's targets.\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    set_property(TARGET crc32c_bench APPEND PROPERTY COMPILE_OPTIONS \"/WX\")\n  endif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\nendif(CRC32C_BUILD_BENCHMARKS)\n\nif(CRC32C_INSTALL)\n  install(TARGETS crc32c\n    EXPORT Crc32cTargets\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n  )\n  install(\n    FILES\n      \"include/crc32c/crc32c.h\"\n    DESTINATION \"${CMAKE_INSTALL_INCLUDEDIR}/crc32c\"\n  )\n\n  include(CMakePackageConfigHelpers)\n  configure_package_config_file(\n    \"${PROJECT_NAME}Config.cmake.in\"\n    \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\"\n    INSTALL_DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\"\n  )\n  write_basic_package_version_file(\n    \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\"\n    COMPATIBILITY SameMajorVersion\n  )\n  install(\n    EXPORT Crc32cTargets\n    NAMESPACE Crc32c::\n    DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\"\n  )\n  install(\n    FILES\n      \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\"\n      \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\"\n    DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\"\n  )\nendif(CRC32C_INSTALL)\n"
  },
  {
    "path": "src/crc32c/CONTRIBUTING.md",
    "content": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guidelines you need to follow.\n\n## Contributor License Agreement\n\nContributions to this project must be accompanied by a Contributor License\nAgreement. You (or your employer) retain the copyright to your contribution,\nthis simply gives us permission to use and redistribute your contributions as\npart of the project. Head over to <https://cla.developers.google.com/> to see\nyour current agreements on file or to sign a new one.\n\nYou generally only need to submit a CLA once, so if you've already submitted one\n(even if it was for a different project), you probably don't need to do it\nagain.\n\n## Code reviews\n\nAll submissions, including submissions by project members, require review. We\nuse GitHub pull requests for this purpose. Consult\n[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more\ninformation on using pull requests.\n"
  },
  {
    "path": "src/crc32c/Crc32cConfig.cmake.in",
    "content": "# Copyright 2017 The CRC32C Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license that can be\n# found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n@PACKAGE_INIT@\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/Crc32cTargets.cmake\")\n\ncheck_required_components(Crc32c)\n"
  },
  {
    "path": "src/crc32c/LICENSE",
    "content": "Copyright 2017, The CRC32C Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "src/crc32c/README.md",
    "content": "# CRC32C\n\n[![Build Status](https://travis-ci.org/google/crc32c.svg?branch=master)](https://travis-ci.org/google/crc32c)\n[![Build Status](https://ci.appveyor.com/api/projects/status/moiq7331pett4xuj/branch/master?svg=true)](https://ci.appveyor.com/project/pwnall/crc32c)\n\nNew file format authors should consider\n[HighwayHash](https://github.com/google/highwayhash). The initial version of\nthis code was extracted from [LevelDB](https://github.com/google/leveldb), which\nis a stable key-value store that is widely used at Google.\n\nThis project collects a few CRC32C implementations under an umbrella that\ndispatches to a suitable implementation based on the host computer's hardware\ncapabilities.\n\nCRC32C is specified as the CRC that uses the iSCSI polynomial in\n[RFC 3720](https://tools.ietf.org/html/rfc3720#section-12.1). The polynomial was\nintroduced by G. Castagnoli, S. Braeuer and M. Herrmann. CRC32C is used in\nsoftware such as Btrfs, ext4, Ceph and leveldb.\n\n\n## Usage\n\n```cpp\n#include \"crc32c/crc32c.h\"\n\nint main() {\n  const std::uint8_t buffer[] = {0, 0, 0, 0};\n  std::uint32_t result;\n\n  // Process a raw buffer.\n  result = crc32c::Crc32c(buffer, 4);\n\n  // Process a std::string.\n  std::string string;\n  string.resize(4);\n  result = crc32c::Crc32c(string);\n\n  // If you have C++17 support, process a std::string_view.\n  std::string_view string_view(string);\n  result = crc32c::Crc32c(string_view);\n\n  return 0;\n}\n```\n\n\n## Prerequisites\n\nThis project uses [CMake](https://cmake.org/) for building and testing. CMake is\navailable in all popular Linux distributions, as well as in\n[Homebrew](https://brew.sh/).\n\nThis project uses submodules for dependency management.\n\n```bash\ngit submodule update --init --recursive\n```\n\nIf you're using [Atom](https://atom.io/), the following packages can help.\n\n```bash\napm install autocomplete-clang build build-cmake clang-format language-cmake \\\n    linter linter-clang\n```\n\nIf you don't mind more setup in return for more speed, replace\n`autocomplete-clang` and `linter-clang` with `you-complete-me`. This requires\n[setting up ycmd](https://github.com/ycm-core/ycmd#building).\n\n```bash\napm install autocomplete-plus build build-cmake clang-format language-cmake \\\n    linter you-complete-me\n```\n\n## Building\n\nThe following commands build and install the project.\n\n```bash\nmkdir build\ncd build\ncmake -DCRC32C_BUILD_TESTS=0 -DCRC32C_BUILD_BENCHMARKS=0 .. && make all install\n```\n\n\n## Development\n\nThe following command (when executed from `build/`) (re)builds the project and\nruns the tests.\n\n```bash\ncmake .. && cmake --build . && ctest --output-on-failure\n```\n\n\n### Android testing\n\nThe following command builds the project against the Android NDK, which is\nuseful for benchmarking against ARM processors.\n\n```bash\ncmake .. -DCMAKE_SYSTEM_NAME=Android -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \\\n    -DCMAKE_ANDROID_NDK=$HOME/Library/Android/sdk/ndk-bundle \\\n    -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang \\\n    -DCMAKE_ANDROID_STL_TYPE=c++_static -DCRC32C_USE_GLOG=0 \\\n    -DCMAKE_BUILD_TYPE=Release && cmake --build .\n```\n\nThe following commands install and run the benchmarks.\n\n```bash\nadb push crc32c_bench /data/local/tmp\nadb shell chmod +x /data/local/tmp/crc32c_bench\nadb shell 'cd /data/local/tmp && ./crc32c_bench'\nadb shell rm /data/local/tmp/crc32c_bench\n```\n\nThe following commands install and run the tests.\n\n```bash\nadb push crc32c_tests /data/local/tmp\nadb shell chmod +x /data/local/tmp/crc32c_tests\nadb shell 'cd /data/local/tmp && ./crc32c_tests'\nadb shell rm /data/local/tmp/crc32c_tests\n```\n"
  },
  {
    "path": "src/crc32c/include/crc32c/crc32c.h",
    "content": "/* Copyright 2017 The CRC32C Authors. All rights reserved.\n   Use of this source code is governed by a BSD-style license that can be\n   found in the LICENSE file. See the AUTHORS file for names of contributors. */\n\n#ifndef CRC32C_CRC32C_H_\n#define CRC32C_CRC32C_H_\n\n/* The API exported by the CRC32C project. */\n\n#if defined(__cplusplus)\n\n#include <cstddef>\n#include <cstdint>\n#include <string>\n\n#else  /* !defined(__cplusplus) */\n\n#include <stddef.h>\n#include <stdint.h>\n\n#endif  /* !defined(__cplusplus) */\n\n\n/* The C API. */\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif  /* defined(__cplusplus) */\n\n/* Extends \"crc\" with the CRC32C of \"count\" bytes in the buffer pointed by\n   \"data\" */\nuint32_t crc32c_extend(uint32_t crc, const uint8_t* data, size_t count);\n\n/* Computes the CRC32C of \"count\" bytes in the buffer pointed by \"data\". */\nuint32_t crc32c_value(const uint8_t* data, size_t count);\n\n#ifdef __cplusplus\n}  /* end extern \"C\" */\n#endif  /* defined(__cplusplus) */\n\n\n/* The C++ API. */\n\n#if defined(__cplusplus)\n\nnamespace crc32c {\n\n// Extends \"crc\" with the CRC32C of \"count\" bytes in the buffer pointed by\n// \"data\".\nuint32_t Extend(uint32_t crc, const uint8_t* data, size_t count);\n\n// Computes the CRC32C of \"count\" bytes in the buffer pointed by \"data\".\ninline uint32_t Crc32c(const uint8_t* data, size_t count) {\n  return Extend(0, data, count);\n}\n\n// Computes the CRC32C of \"count\" bytes in the buffer pointed by \"data\".\ninline uint32_t Crc32c(const char* data, size_t count) {\n  return Extend(0, reinterpret_cast<const uint8_t*>(data), count);\n}\n\n// Computes the CRC32C of the string's content.\ninline uint32_t Crc32c(const std::string& string) {\n  return Crc32c(reinterpret_cast<const uint8_t*>(string.data()),\n                string.size());\n}\n\n}  // namespace crc32c\n\n#if __cplusplus > 201402L\n#if __has_include(<string_view>)\n#include <string_view>\n\nnamespace crc32c {\n\n// Computes the CRC32C of the bytes in the string_view.\ninline uint32_t Crc32c(const std::string_view& string_view) {\n  return Crc32c(reinterpret_cast<const uint8_t*>(string_view.data()),\n                string_view.size());\n}\n\n}  // namespace crc32c\n\n#endif  // __has_include(<string_view>)\n#endif  // __cplusplus > 201402L\n\n#endif  /* defined(__cplusplus) */\n\n#endif  // CRC32C_CRC32C_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"crc32c/crc32c.h\"\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"./crc32c_arm64.h\"\n#include \"./crc32c_arm64_check.h\"\n#include \"./crc32c_internal.h\"\n#include \"./crc32c_sse42.h\"\n#include \"./crc32c_sse42_check.h\"\n\nnamespace crc32c {\n\nuint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) {\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n  static bool can_use_sse42 = CanUseSse42();\n  if (can_use_sse42) return ExtendSse42(crc, data, count);\n#elif HAVE_ARM64_CRC32C\n  static bool can_use_arm64_crc32 = CanUseArm64Crc32();\n  if (can_use_arm64_crc32) return ExtendArm64(crc, data, count);\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n  return ExtendPortable(crc, data, count);\n}\n\nextern \"C\" uint32_t crc32c_extend(uint32_t crc, const uint8_t* data,\n                                  size_t count) {\n  return crc32c::Extend(crc, data, count);\n}\n\nextern \"C\" uint32_t crc32c_value(const uint8_t* data, size_t count) {\n  return crc32c::Crc32c(data, count);\n}\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_arm64.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_arm64.h\"\n\n// In a separate source file to allow this accelerated CRC32C function to be\n// compiled with the appropriate compiler flags to enable ARM NEON CRC32C\n// instructions.\n\n// This implementation is based on https://github.com/google/leveldb/pull/490.\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"./crc32c_internal.h\"\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_ARM64_CRC32C\n\n#include <arm_acle.h>\n#include <arm_neon.h>\n\n#define KBYTES 1032\n#define SEGMENTBYTES 256\n\n// compute 8bytes for each segment parallelly\n#define CRC32C32BYTES(P, IND)                                             \\\n  do {                                                                    \\\n    crc1 = __crc32cd(                                                     \\\n        crc1, *((const uint64_t *)(P) + (SEGMENTBYTES / 8) * 1 + (IND))); \\\n    crc2 = __crc32cd(                                                     \\\n        crc2, *((const uint64_t *)(P) + (SEGMENTBYTES / 8) * 2 + (IND))); \\\n    crc3 = __crc32cd(                                                     \\\n        crc3, *((const uint64_t *)(P) + (SEGMENTBYTES / 8) * 3 + (IND))); \\\n    crc0 = __crc32cd(                                                     \\\n        crc0, *((const uint64_t *)(P) + (SEGMENTBYTES / 8) * 0 + (IND))); \\\n  } while (0);\n\n// compute 8*8 bytes for each segment parallelly\n#define CRC32C256BYTES(P, IND)      \\\n  do {                              \\\n    CRC32C32BYTES((P), (IND)*8 + 0) \\\n    CRC32C32BYTES((P), (IND)*8 + 1) \\\n    CRC32C32BYTES((P), (IND)*8 + 2) \\\n    CRC32C32BYTES((P), (IND)*8 + 3) \\\n    CRC32C32BYTES((P), (IND)*8 + 4) \\\n    CRC32C32BYTES((P), (IND)*8 + 5) \\\n    CRC32C32BYTES((P), (IND)*8 + 6) \\\n    CRC32C32BYTES((P), (IND)*8 + 7) \\\n  } while (0);\n\n// compute 4*8*8 bytes for each segment parallelly\n#define CRC32C1024BYTES(P)   \\\n  do {                       \\\n    CRC32C256BYTES((P), 0)   \\\n    CRC32C256BYTES((P), 1)   \\\n    CRC32C256BYTES((P), 2)   \\\n    CRC32C256BYTES((P), 3)   \\\n    (P) += 4 * SEGMENTBYTES; \\\n  } while (0)\n\nnamespace crc32c {\n\nuint32_t ExtendArm64(uint32_t crc, const uint8_t *data, size_t size) {\n  int64_t length = size;\n  uint32_t crc0, crc1, crc2, crc3;\n  uint64_t t0, t1, t2;\n\n  // k0=CRC(x^(3*SEGMENTBYTES*8)), k1=CRC(x^(2*SEGMENTBYTES*8)),\n  // k2=CRC(x^(SEGMENTBYTES*8))\n  const poly64_t k0 = 0x8d96551c, k1 = 0xbd6f81f8, k2 = 0xdcb17aa4;\n\n  crc = crc ^ kCRC32Xor;\n\n  while (length >= KBYTES) {\n    crc0 = crc;\n    crc1 = 0;\n    crc2 = 0;\n    crc3 = 0;\n\n    // Process 1024 bytes in parallel.\n    CRC32C1024BYTES(data);\n\n    // Merge the 4 partial CRC32C values.\n    t2 = (uint64_t)vmull_p64(crc2, k2);\n    t1 = (uint64_t)vmull_p64(crc1, k1);\n    t0 = (uint64_t)vmull_p64(crc0, k0);\n    crc = __crc32cd(crc3, *(uint64_t *)data);\n    data += sizeof(uint64_t);\n    crc ^= __crc32cd(0, t2);\n    crc ^= __crc32cd(0, t1);\n    crc ^= __crc32cd(0, t0);\n\n    length -= KBYTES;\n  }\n\n  while (length >= 8) {\n    crc = __crc32cd(crc, *(uint64_t *)data);\n    data += 8;\n    length -= 8;\n  }\n\n  if (length & 4) {\n    crc = __crc32cw(crc, *(uint32_t *)data);\n    data += 4;\n  }\n\n  if (length & 2) {\n    crc = __crc32ch(crc, *(uint16_t *)data);\n    data += 2;\n  }\n\n  if (length & 1) {\n    crc = __crc32cb(crc, *data);\n  }\n\n  return crc ^ kCRC32Xor;\n}\n\n}  // namespace crc32c\n\n#endif  // HAVE_ARM64_CRC32C\n"
  },
  {
    "path": "src/crc32c/src/crc32c_arm64.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// ARM-specific code\n\n#ifndef CRC32C_CRC32C_ARM_H_\n#define CRC32C_CRC32C_ARM_H_\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_ARM64_CRC32C\n\nnamespace crc32c {\n\nuint32_t ExtendArm64(uint32_t crc, const uint8_t* data, size_t count);\n\n}  // namespace crc32c\n\n#endif  // HAVE_ARM64_CRC32C\n\n#endif  // CRC32C_CRC32C_ARM_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_arm64_check.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// ARM-specific code checking for the availability of CRC32C instructions.\n\n#ifndef CRC32C_CRC32C_ARM_CHECK_H_\n#define CRC32C_CRC32C_ARM_CHECK_H_\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_ARM64_CRC32C\n\n#ifdef __linux__\n#if HAVE_STRONG_GETAUXVAL\n#include <sys/auxv.h>\n#elif HAVE_WEAK_GETAUXVAL\n// getauxval() is not available on Android until API level 20. Link it as a weak\n// symbol.\nextern \"C\" unsigned long getauxval(unsigned long type) __attribute__((weak));\n\n#define AT_HWCAP 16\n#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL\n#endif  // defined (__linux__)\n\n#ifdef __APPLE__\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#endif  // defined (__APPLE__)\n\nnamespace crc32c {\n\ninline bool CanUseArm64Crc32() {\n#if defined (__linux__) && (HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL)\n  // From 'arch/arm64/include/uapi/asm/hwcap.h' in Linux kernel source code.\n  constexpr unsigned long kHWCAP_PMULL = 1 << 4;\n  constexpr unsigned long kHWCAP_CRC32 = 1 << 7;\n  unsigned long hwcap =\n#if HAVE_STRONG_GETAUXVAL\n      // Some compilers warn on (&getauxval != nullptr) in the block below.\n      getauxval(AT_HWCAP);\n#elif HAVE_WEAK_GETAUXVAL\n      (&getauxval != nullptr) ? getauxval(AT_HWCAP) : 0;\n#else\n#error This is supposed to be nested inside a check for HAVE_*_GETAUXVAL.\n#endif  // HAVE_STRONG_GETAUXVAL\n  return (hwcap & (kHWCAP_PMULL | kHWCAP_CRC32)) ==\n         (kHWCAP_PMULL | kHWCAP_CRC32);\n#elif defined(__APPLE__)\n  int val = 0;\n  size_t len = sizeof(val);\n  return sysctlbyname(\"hw.optional.armv8_crc32\", &val, &len, nullptr, 0) == 0\n             && val != 0;\n#else\n  return false;\n#endif  // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL\n}\n\n}  // namespace crc32c\n\n#endif  // HAVE_ARM64_CRC32C\n\n#endif  // CRC32C_CRC32C_ARM_CHECK_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_arm64_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"gtest/gtest.h\"\n\n#include \"./crc32c_arm64.h\"\n#include \"./crc32c_extend_unittests.h\"\n\nnamespace crc32c {\n\n#if HAVE_ARM64_CRC32C\n\nstruct Arm64TestTraits {\n  static uint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) {\n    return ExtendArm64(crc, data, count);\n  }\n};\n\nINSTANTIATE_TYPED_TEST_SUITE_P(Arm64, ExtendTest, Arm64TestTraits);\n\n#endif  // HAVE_ARM64_CRC32C\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_benchmark.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#include \"benchmark/benchmark.h\"\n\n#if CRC32C_TESTS_BUILT_WITH_GLOG\n#include \"glog/logging.h\"\n#endif  // CRC32C_TESTS_BUILT_WITH_GLOG\n\n#include \"./crc32c_arm64.h\"\n#include \"./crc32c_arm64_check.h\"\n#include \"./crc32c_internal.h\"\n#include \"./crc32c_sse42.h\"\n#include \"./crc32c_sse42_check.h\"\n#include \"crc32c/crc32c.h\"\n\nclass CRC32CBenchmark : public benchmark::Fixture {\n public:\n  void SetUp(const benchmark::State& state) override {\n    block_size_ = static_cast<size_t>(state.range(0));\n    block_data_ = std::string(block_size_, 'x');\n    block_buffer_ = reinterpret_cast<const uint8_t*>(block_data_.data());\n  }\n\n protected:\n  std::string block_data_;\n  const uint8_t* block_buffer_;\n  size_t block_size_;\n};\n\nBENCHMARK_DEFINE_F(CRC32CBenchmark, Public)(benchmark::State& state) {\n  uint32_t crc = 0;\n  for (auto _ : state)\n    crc = crc32c::Extend(crc, block_buffer_, block_size_);\n  state.SetBytesProcessed(state.iterations() * block_size_);\n}\nBENCHMARK_REGISTER_F(CRC32CBenchmark, Public)\n    ->RangeMultiplier(16)\n    ->Range(256, 16777216);  // Block size.\n\nBENCHMARK_DEFINE_F(CRC32CBenchmark, Portable)(benchmark::State& state) {\n  uint32_t crc = 0;\n  for (auto _ : state)\n    crc = crc32c::ExtendPortable(crc, block_buffer_, block_size_);\n  state.SetBytesProcessed(state.iterations() * block_size_);\n}\nBENCHMARK_REGISTER_F(CRC32CBenchmark, Portable)\n    ->RangeMultiplier(16)\n    ->Range(256, 16777216);  // Block size.\n\n#if HAVE_ARM64_CRC32C\n\nBENCHMARK_DEFINE_F(CRC32CBenchmark, ArmCRC32C)(benchmark::State& state) {\n  if (!crc32c::CanUseArm64Crc32()) {\n    state.SkipWithError(\"ARM CRC32C instructions not available or not enabled\");\n    return;\n  }\n\n  uint32_t crc = 0;\n  for (auto _ : state)\n    crc = crc32c::ExtendArm64(crc, block_buffer_, block_size_);\n  state.SetBytesProcessed(state.iterations() * block_size_);\n}\nBENCHMARK_REGISTER_F(CRC32CBenchmark, ArmCRC32C)\n    ->RangeMultiplier(16)\n    ->Range(256, 16777216);  // Block size.\n\n#endif  // HAVE_ARM64_CRC32C\n\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\nBENCHMARK_DEFINE_F(CRC32CBenchmark, Sse42)(benchmark::State& state) {\n  if (!crc32c::CanUseSse42()) {\n    state.SkipWithError(\"SSE4.2 instructions not available or not enabled\");\n    return;\n  }\n\n  uint32_t crc = 0;\n  for (auto _ : state)\n    crc = crc32c::ExtendSse42(crc, block_buffer_, block_size_);\n  state.SetBytesProcessed(state.iterations() * block_size_);\n}\nBENCHMARK_REGISTER_F(CRC32CBenchmark, Sse42)\n    ->RangeMultiplier(16)\n    ->Range(256, 16777216);  // Block size.\n\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\nint main(int argc, char** argv) {\n#if CRC32C_TESTS_BUILT_WITH_GLOG\n  google::InitGoogleLogging(argv[0]);\n  google::InstallFailureSignalHandler();\n#endif  // CRC32C_TESTS_BUILT_WITH_GLOG\n\n  benchmark::Initialize(&argc, argv);\n  benchmark::RunSpecifiedBenchmarks();\n  return 0;\n}\n"
  },
  {
    "path": "src/crc32c/src/crc32c_capi_unittest.c",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"crc32c/crc32c.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint main() {\n  /* From rfc3720 section B.4. */\n  uint8_t buf[32];\n\n  memset(buf, 0, sizeof(buf));\n  if ((uint32_t)0x8a9136aa != crc32c_value(buf, sizeof(buf))) {\n    printf(\"crc32c_value(zeros) test failed\\n\");\n    return 1;\n  }\n\n  memset(buf, 0xff, sizeof(buf));\n  if ((uint32_t)0x62a8ab43 != crc32c_value(buf, sizeof(buf))) {\n    printf(\"crc32c_value(0xff) test failed\\n\");\n    return 1;\n  }\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = (uint8_t)i;\n  if ((uint32_t)0x46dd794e != crc32c_value(buf, sizeof(buf))) {\n    printf(\"crc32c_value(0..31) test failed\\n\");\n    return 1;\n  }\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = (uint8_t)(31 - i);\n  if ((uint32_t)0x113fdb5c != crc32c_value(buf, sizeof(buf))) {\n    printf(\"crc32c_value(31..0) test failed\\n\");\n    return 1;\n  }\n\n  uint8_t data[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n  if ((uint32_t)0xd9963a56 != crc32c_value(data, sizeof(data))) {\n    printf(\"crc32c_value(31..0) test failed\\n\");\n    return 1;\n  }\n\n  const uint8_t* hello_space_world = (const uint8_t*)\"hello world\";\n  const uint8_t* hello_space = (const uint8_t*)\"hello \";\n  const uint8_t* world = (const uint8_t*)\"world\";\n\n  if (crc32c_value(hello_space_world, 11) !=\n      crc32c_extend(crc32c_value(hello_space, 6), world, 5)) {\n    printf(\"crc32c_extend test failed\\n\");\n    return 1;\n  }\n\n  printf(\"All tests passed\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "src/crc32c/src/crc32c_config.h.in",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_CONFIG_H_\n#define CRC32C_CRC32C_CONFIG_H_\n\n// Define to 1 if building for a big-endian platform.\n#cmakedefine01 BYTE_ORDER_BIG_ENDIAN\n\n// Define to 1 if the compiler has the __builtin_prefetch intrinsic.\n#cmakedefine01 HAVE_BUILTIN_PREFETCH\n\n// Define to 1 if targeting X86 and the compiler has the _mm_prefetch intrinsic.\n#cmakedefine01 HAVE_MM_PREFETCH\n\n// Define to 1 if targeting X86 and the compiler has the _mm_crc32_u{8,32,64}\n// intrinsics.\n#cmakedefine01 HAVE_SSE42\n\n// Define to 1 if targeting ARM and the compiler has the __crc32c{b,h,w,d} and\n// the vmull_p64 intrinsics.\n#cmakedefine01 HAVE_ARM64_CRC32C\n\n// Define to 1 if the system libraries have the getauxval function in the\n// <sys/auxv.h> header. Should be true on Linux and Android API level 20+.\n#cmakedefine01 HAVE_STRONG_GETAUXVAL\n\n// Define to 1 if the compiler supports defining getauxval as a weak symbol.\n// Should be true for any compiler that supports __attribute__((weak)).\n#cmakedefine01 HAVE_WEAK_GETAUXVAL\n\n// Define to 1 if CRC32C tests have been built with Google Logging.\n#cmakedefine01 CRC32C_TESTS_BUILT_WITH_GLOG\n\n#endif  // CRC32C_CRC32C_CONFIG_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_extend_unittests.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_EXTEND_UNITTESTS_H_\n#define CRC32C_CRC32C_EXTEND_UNITTESTS_H_\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n\n#include \"gtest/gtest.h\"\n\n// Common test cases for all implementations of CRC32C_Extend().\n\nnamespace crc32c {\n\ntemplate<typename TestTraits>\nclass ExtendTest : public testing::Test {};\n\nTYPED_TEST_SUITE_P(ExtendTest);\n\nTYPED_TEST_P(ExtendTest, StandardResults) {\n  // From rfc3720 section B.4.\n  uint8_t buf[32];\n\n  std::memset(buf, 0, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x8a9136aa),\n            TypeParam::Extend(0, buf, sizeof(buf)));\n\n  std::memset(buf, 0xff, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x62a8ab43),\n            TypeParam::Extend(0, buf, sizeof(buf)));\n\n  for (int i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(i);\n  EXPECT_EQ(static_cast<uint32_t>(0x46dd794e),\n            TypeParam::Extend(0, buf, sizeof(buf)));\n\n  for (int i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(31 - i);\n  EXPECT_EQ(static_cast<uint32_t>(0x113fdb5c),\n            TypeParam::Extend(0, buf, sizeof(buf)));\n\n  uint8_t data[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n  EXPECT_EQ(static_cast<uint32_t>(0xd9963a56),\n            TypeParam::Extend(0, data, sizeof(data)));\n}\n\nTYPED_TEST_P(ExtendTest, HelloWorld) {\n  const uint8_t* hello_space_world =\n      reinterpret_cast<const uint8_t*>(\"hello world\");\n  const uint8_t* hello_space = reinterpret_cast<const uint8_t*>(\"hello \");\n  const uint8_t* world = reinterpret_cast<const uint8_t*>(\"world\");\n\n  EXPECT_EQ(TypeParam::Extend(0, hello_space_world, 11),\n            TypeParam::Extend(TypeParam::Extend(0, hello_space, 6), world, 5));\n}\n\nTYPED_TEST_P(ExtendTest, BufferSlicing) {\n  uint8_t buffer[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n\n  for (size_t i = 0; i < 48; ++i) {\n    for (size_t j = i + 1; j <= 48; ++j) {\n      uint32_t crc = 0;\n\n      if (i > 0) crc = TypeParam::Extend(crc, buffer, i);\n      crc = TypeParam::Extend(crc, buffer + i, j - i);\n      if (j < 48) crc = TypeParam::Extend(crc, buffer + j, 48 - j);\n\n      EXPECT_EQ(static_cast<uint32_t>(0xd9963a56), crc);\n    }\n  }\n}\n\nTYPED_TEST_P(ExtendTest, LargeBufferSlicing) {\n  uint8_t buffer[2048];\n  for (size_t i = 0; i < 2048; i++)\n    buffer[i] = static_cast<uint8_t>(3 * i * i + 7 * i + 11);\n\n  for (size_t i = 0; i < 2048; ++i) {\n    for (size_t j = i + 1; j <= 2048; ++j) {\n      uint32_t crc = 0;\n\n      if (i > 0) crc = TypeParam::Extend(crc, buffer, i);\n      crc = TypeParam::Extend(crc, buffer + i, j - i);\n      if (j < 2048) crc = TypeParam::Extend(crc, buffer + j, 2048 - j);\n\n      EXPECT_EQ(static_cast<uint32_t>(0x36dcc753), crc);\n    }\n  }\n}\n\nREGISTER_TYPED_TEST_SUITE_P(ExtendTest,\n    StandardResults,\n    HelloWorld,\n    BufferSlicing,\n    LargeBufferSlicing);\n\n}  // namespace crc32c\n\n#endif  // CRC32C_CRC32C_EXTEND_UNITTESTS_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_internal.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_INTERNAL_H_\n#define CRC32C_CRC32C_INTERNAL_H_\n\n// Internal functions that may change between releases.\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace crc32c {\n\n// Un-accelerated implementation that works on all CPUs.\nuint32_t ExtendPortable(uint32_t crc, const uint8_t* data, size_t count);\n\n// CRCs are pre- and post- conditioned by xoring with all ones.\nstatic constexpr const uint32_t kCRC32Xor = static_cast<uint32_t>(0xffffffffU);\n\n}  // namespace crc32c\n\n#endif  // CRC32C_CRC32C_INTERNAL_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_portable.cc",
    "content": "// Copyright 2008 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_internal.h\"\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"./crc32c_prefetch.h\"\n#include \"./crc32c_read_le.h\"\n#include \"./crc32c_round_up.h\"\n\nnamespace {\n\nconst uint32_t kByteExtensionTable[256] = {\n    0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,\n    0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,\n    0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,\n    0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,\n    0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,\n    0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,\n    0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,\n    0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,\n    0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,\n    0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,\n    0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,\n    0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,\n    0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,\n    0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,\n    0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,\n    0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,\n    0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,\n    0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,\n    0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,\n    0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,\n    0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,\n    0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,\n    0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,\n    0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,\n    0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,\n    0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,\n    0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,\n    0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,\n    0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,\n    0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,\n    0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,\n    0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,\n    0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,\n    0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,\n    0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,\n    0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,\n    0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,\n    0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,\n    0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,\n    0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,\n    0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,\n    0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,\n    0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351};\n\nconst uint32_t kStrideExtensionTable0[256] = {\n    0x00000000, 0x30d23865, 0x61a470ca, 0x517648af, 0xc348e194, 0xf39ad9f1,\n    0xa2ec915e, 0x923ea93b, 0x837db5d9, 0xb3af8dbc, 0xe2d9c513, 0xd20bfd76,\n    0x4035544d, 0x70e76c28, 0x21912487, 0x11431ce2, 0x03171d43, 0x33c52526,\n    0x62b36d89, 0x526155ec, 0xc05ffcd7, 0xf08dc4b2, 0xa1fb8c1d, 0x9129b478,\n    0x806aa89a, 0xb0b890ff, 0xe1ced850, 0xd11ce035, 0x4322490e, 0x73f0716b,\n    0x228639c4, 0x125401a1, 0x062e3a86, 0x36fc02e3, 0x678a4a4c, 0x57587229,\n    0xc566db12, 0xf5b4e377, 0xa4c2abd8, 0x941093bd, 0x85538f5f, 0xb581b73a,\n    0xe4f7ff95, 0xd425c7f0, 0x461b6ecb, 0x76c956ae, 0x27bf1e01, 0x176d2664,\n    0x053927c5, 0x35eb1fa0, 0x649d570f, 0x544f6f6a, 0xc671c651, 0xf6a3fe34,\n    0xa7d5b69b, 0x97078efe, 0x8644921c, 0xb696aa79, 0xe7e0e2d6, 0xd732dab3,\n    0x450c7388, 0x75de4bed, 0x24a80342, 0x147a3b27, 0x0c5c750c, 0x3c8e4d69,\n    0x6df805c6, 0x5d2a3da3, 0xcf149498, 0xffc6acfd, 0xaeb0e452, 0x9e62dc37,\n    0x8f21c0d5, 0xbff3f8b0, 0xee85b01f, 0xde57887a, 0x4c692141, 0x7cbb1924,\n    0x2dcd518b, 0x1d1f69ee, 0x0f4b684f, 0x3f99502a, 0x6eef1885, 0x5e3d20e0,\n    0xcc0389db, 0xfcd1b1be, 0xada7f911, 0x9d75c174, 0x8c36dd96, 0xbce4e5f3,\n    0xed92ad5c, 0xdd409539, 0x4f7e3c02, 0x7fac0467, 0x2eda4cc8, 0x1e0874ad,\n    0x0a724f8a, 0x3aa077ef, 0x6bd63f40, 0x5b040725, 0xc93aae1e, 0xf9e8967b,\n    0xa89eded4, 0x984ce6b1, 0x890ffa53, 0xb9ddc236, 0xe8ab8a99, 0xd879b2fc,\n    0x4a471bc7, 0x7a9523a2, 0x2be36b0d, 0x1b315368, 0x096552c9, 0x39b76aac,\n    0x68c12203, 0x58131a66, 0xca2db35d, 0xfaff8b38, 0xab89c397, 0x9b5bfbf2,\n    0x8a18e710, 0xbacadf75, 0xebbc97da, 0xdb6eafbf, 0x49500684, 0x79823ee1,\n    0x28f4764e, 0x18264e2b, 0x18b8ea18, 0x286ad27d, 0x791c9ad2, 0x49cea2b7,\n    0xdbf00b8c, 0xeb2233e9, 0xba547b46, 0x8a864323, 0x9bc55fc1, 0xab1767a4,\n    0xfa612f0b, 0xcab3176e, 0x588dbe55, 0x685f8630, 0x3929ce9f, 0x09fbf6fa,\n    0x1baff75b, 0x2b7dcf3e, 0x7a0b8791, 0x4ad9bff4, 0xd8e716cf, 0xe8352eaa,\n    0xb9436605, 0x89915e60, 0x98d24282, 0xa8007ae7, 0xf9763248, 0xc9a40a2d,\n    0x5b9aa316, 0x6b489b73, 0x3a3ed3dc, 0x0aecebb9, 0x1e96d09e, 0x2e44e8fb,\n    0x7f32a054, 0x4fe09831, 0xddde310a, 0xed0c096f, 0xbc7a41c0, 0x8ca879a5,\n    0x9deb6547, 0xad395d22, 0xfc4f158d, 0xcc9d2de8, 0x5ea384d3, 0x6e71bcb6,\n    0x3f07f419, 0x0fd5cc7c, 0x1d81cddd, 0x2d53f5b8, 0x7c25bd17, 0x4cf78572,\n    0xdec92c49, 0xee1b142c, 0xbf6d5c83, 0x8fbf64e6, 0x9efc7804, 0xae2e4061,\n    0xff5808ce, 0xcf8a30ab, 0x5db49990, 0x6d66a1f5, 0x3c10e95a, 0x0cc2d13f,\n    0x14e49f14, 0x2436a771, 0x7540efde, 0x4592d7bb, 0xd7ac7e80, 0xe77e46e5,\n    0xb6080e4a, 0x86da362f, 0x97992acd, 0xa74b12a8, 0xf63d5a07, 0xc6ef6262,\n    0x54d1cb59, 0x6403f33c, 0x3575bb93, 0x05a783f6, 0x17f38257, 0x2721ba32,\n    0x7657f29d, 0x4685caf8, 0xd4bb63c3, 0xe4695ba6, 0xb51f1309, 0x85cd2b6c,\n    0x948e378e, 0xa45c0feb, 0xf52a4744, 0xc5f87f21, 0x57c6d61a, 0x6714ee7f,\n    0x3662a6d0, 0x06b09eb5, 0x12caa592, 0x22189df7, 0x736ed558, 0x43bced3d,\n    0xd1824406, 0xe1507c63, 0xb02634cc, 0x80f40ca9, 0x91b7104b, 0xa165282e,\n    0xf0136081, 0xc0c158e4, 0x52fff1df, 0x622dc9ba, 0x335b8115, 0x0389b970,\n    0x11ddb8d1, 0x210f80b4, 0x7079c81b, 0x40abf07e, 0xd2955945, 0xe2476120,\n    0xb331298f, 0x83e311ea, 0x92a00d08, 0xa272356d, 0xf3047dc2, 0xc3d645a7,\n    0x51e8ec9c, 0x613ad4f9, 0x304c9c56, 0x009ea433};\n\nconst uint32_t kStrideExtensionTable1[256] = {\n    0x00000000, 0x54075546, 0xa80eaa8c, 0xfc09ffca, 0x55f123e9, 0x01f676af,\n    0xfdff8965, 0xa9f8dc23, 0xabe247d2, 0xffe51294, 0x03eced5e, 0x57ebb818,\n    0xfe13643b, 0xaa14317d, 0x561dceb7, 0x021a9bf1, 0x5228f955, 0x062fac13,\n    0xfa2653d9, 0xae21069f, 0x07d9dabc, 0x53de8ffa, 0xafd77030, 0xfbd02576,\n    0xf9cabe87, 0xadcdebc1, 0x51c4140b, 0x05c3414d, 0xac3b9d6e, 0xf83cc828,\n    0x043537e2, 0x503262a4, 0xa451f2aa, 0xf056a7ec, 0x0c5f5826, 0x58580d60,\n    0xf1a0d143, 0xa5a78405, 0x59ae7bcf, 0x0da92e89, 0x0fb3b578, 0x5bb4e03e,\n    0xa7bd1ff4, 0xf3ba4ab2, 0x5a429691, 0x0e45c3d7, 0xf24c3c1d, 0xa64b695b,\n    0xf6790bff, 0xa27e5eb9, 0x5e77a173, 0x0a70f435, 0xa3882816, 0xf78f7d50,\n    0x0b86829a, 0x5f81d7dc, 0x5d9b4c2d, 0x099c196b, 0xf595e6a1, 0xa192b3e7,\n    0x086a6fc4, 0x5c6d3a82, 0xa064c548, 0xf463900e, 0x4d4f93a5, 0x1948c6e3,\n    0xe5413929, 0xb1466c6f, 0x18beb04c, 0x4cb9e50a, 0xb0b01ac0, 0xe4b74f86,\n    0xe6add477, 0xb2aa8131, 0x4ea37efb, 0x1aa42bbd, 0xb35cf79e, 0xe75ba2d8,\n    0x1b525d12, 0x4f550854, 0x1f676af0, 0x4b603fb6, 0xb769c07c, 0xe36e953a,\n    0x4a964919, 0x1e911c5f, 0xe298e395, 0xb69fb6d3, 0xb4852d22, 0xe0827864,\n    0x1c8b87ae, 0x488cd2e8, 0xe1740ecb, 0xb5735b8d, 0x497aa447, 0x1d7df101,\n    0xe91e610f, 0xbd193449, 0x4110cb83, 0x15179ec5, 0xbcef42e6, 0xe8e817a0,\n    0x14e1e86a, 0x40e6bd2c, 0x42fc26dd, 0x16fb739b, 0xeaf28c51, 0xbef5d917,\n    0x170d0534, 0x430a5072, 0xbf03afb8, 0xeb04fafe, 0xbb36985a, 0xef31cd1c,\n    0x133832d6, 0x473f6790, 0xeec7bbb3, 0xbac0eef5, 0x46c9113f, 0x12ce4479,\n    0x10d4df88, 0x44d38ace, 0xb8da7504, 0xecdd2042, 0x4525fc61, 0x1122a927,\n    0xed2b56ed, 0xb92c03ab, 0x9a9f274a, 0xce98720c, 0x32918dc6, 0x6696d880,\n    0xcf6e04a3, 0x9b6951e5, 0x6760ae2f, 0x3367fb69, 0x317d6098, 0x657a35de,\n    0x9973ca14, 0xcd749f52, 0x648c4371, 0x308b1637, 0xcc82e9fd, 0x9885bcbb,\n    0xc8b7de1f, 0x9cb08b59, 0x60b97493, 0x34be21d5, 0x9d46fdf6, 0xc941a8b0,\n    0x3548577a, 0x614f023c, 0x635599cd, 0x3752cc8b, 0xcb5b3341, 0x9f5c6607,\n    0x36a4ba24, 0x62a3ef62, 0x9eaa10a8, 0xcaad45ee, 0x3eced5e0, 0x6ac980a6,\n    0x96c07f6c, 0xc2c72a2a, 0x6b3ff609, 0x3f38a34f, 0xc3315c85, 0x973609c3,\n    0x952c9232, 0xc12bc774, 0x3d2238be, 0x69256df8, 0xc0ddb1db, 0x94dae49d,\n    0x68d31b57, 0x3cd44e11, 0x6ce62cb5, 0x38e179f3, 0xc4e88639, 0x90efd37f,\n    0x39170f5c, 0x6d105a1a, 0x9119a5d0, 0xc51ef096, 0xc7046b67, 0x93033e21,\n    0x6f0ac1eb, 0x3b0d94ad, 0x92f5488e, 0xc6f21dc8, 0x3afbe202, 0x6efcb744,\n    0xd7d0b4ef, 0x83d7e1a9, 0x7fde1e63, 0x2bd94b25, 0x82219706, 0xd626c240,\n    0x2a2f3d8a, 0x7e2868cc, 0x7c32f33d, 0x2835a67b, 0xd43c59b1, 0x803b0cf7,\n    0x29c3d0d4, 0x7dc48592, 0x81cd7a58, 0xd5ca2f1e, 0x85f84dba, 0xd1ff18fc,\n    0x2df6e736, 0x79f1b270, 0xd0096e53, 0x840e3b15, 0x7807c4df, 0x2c009199,\n    0x2e1a0a68, 0x7a1d5f2e, 0x8614a0e4, 0xd213f5a2, 0x7beb2981, 0x2fec7cc7,\n    0xd3e5830d, 0x87e2d64b, 0x73814645, 0x27861303, 0xdb8fecc9, 0x8f88b98f,\n    0x267065ac, 0x727730ea, 0x8e7ecf20, 0xda799a66, 0xd8630197, 0x8c6454d1,\n    0x706dab1b, 0x246afe5d, 0x8d92227e, 0xd9957738, 0x259c88f2, 0x719bddb4,\n    0x21a9bf10, 0x75aeea56, 0x89a7159c, 0xdda040da, 0x74589cf9, 0x205fc9bf,\n    0xdc563675, 0x88516333, 0x8a4bf8c2, 0xde4cad84, 0x2245524e, 0x76420708,\n    0xdfbadb2b, 0x8bbd8e6d, 0x77b471a7, 0x23b324e1};\n\nconst uint32_t kStrideExtensionTable2[256] = {\n    0x00000000, 0x678efd01, 0xcf1dfa02, 0xa8930703, 0x9bd782f5, 0xfc597ff4,\n    0x54ca78f7, 0x334485f6, 0x3243731b, 0x55cd8e1a, 0xfd5e8919, 0x9ad07418,\n    0xa994f1ee, 0xce1a0cef, 0x66890bec, 0x0107f6ed, 0x6486e636, 0x03081b37,\n    0xab9b1c34, 0xcc15e135, 0xff5164c3, 0x98df99c2, 0x304c9ec1, 0x57c263c0,\n    0x56c5952d, 0x314b682c, 0x99d86f2f, 0xfe56922e, 0xcd1217d8, 0xaa9cead9,\n    0x020fedda, 0x658110db, 0xc90dcc6c, 0xae83316d, 0x0610366e, 0x619ecb6f,\n    0x52da4e99, 0x3554b398, 0x9dc7b49b, 0xfa49499a, 0xfb4ebf77, 0x9cc04276,\n    0x34534575, 0x53ddb874, 0x60993d82, 0x0717c083, 0xaf84c780, 0xc80a3a81,\n    0xad8b2a5a, 0xca05d75b, 0x6296d058, 0x05182d59, 0x365ca8af, 0x51d255ae,\n    0xf94152ad, 0x9ecfafac, 0x9fc85941, 0xf846a440, 0x50d5a343, 0x375b5e42,\n    0x041fdbb4, 0x639126b5, 0xcb0221b6, 0xac8cdcb7, 0x97f7ee29, 0xf0791328,\n    0x58ea142b, 0x3f64e92a, 0x0c206cdc, 0x6bae91dd, 0xc33d96de, 0xa4b36bdf,\n    0xa5b49d32, 0xc23a6033, 0x6aa96730, 0x0d279a31, 0x3e631fc7, 0x59ede2c6,\n    0xf17ee5c5, 0x96f018c4, 0xf371081f, 0x94fff51e, 0x3c6cf21d, 0x5be20f1c,\n    0x68a68aea, 0x0f2877eb, 0xa7bb70e8, 0xc0358de9, 0xc1327b04, 0xa6bc8605,\n    0x0e2f8106, 0x69a17c07, 0x5ae5f9f1, 0x3d6b04f0, 0x95f803f3, 0xf276fef2,\n    0x5efa2245, 0x3974df44, 0x91e7d847, 0xf6692546, 0xc52da0b0, 0xa2a35db1,\n    0x0a305ab2, 0x6dbea7b3, 0x6cb9515e, 0x0b37ac5f, 0xa3a4ab5c, 0xc42a565d,\n    0xf76ed3ab, 0x90e02eaa, 0x387329a9, 0x5ffdd4a8, 0x3a7cc473, 0x5df23972,\n    0xf5613e71, 0x92efc370, 0xa1ab4686, 0xc625bb87, 0x6eb6bc84, 0x09384185,\n    0x083fb768, 0x6fb14a69, 0xc7224d6a, 0xa0acb06b, 0x93e8359d, 0xf466c89c,\n    0x5cf5cf9f, 0x3b7b329e, 0x2a03aaa3, 0x4d8d57a2, 0xe51e50a1, 0x8290ada0,\n    0xb1d42856, 0xd65ad557, 0x7ec9d254, 0x19472f55, 0x1840d9b8, 0x7fce24b9,\n    0xd75d23ba, 0xb0d3debb, 0x83975b4d, 0xe419a64c, 0x4c8aa14f, 0x2b045c4e,\n    0x4e854c95, 0x290bb194, 0x8198b697, 0xe6164b96, 0xd552ce60, 0xb2dc3361,\n    0x1a4f3462, 0x7dc1c963, 0x7cc63f8e, 0x1b48c28f, 0xb3dbc58c, 0xd455388d,\n    0xe711bd7b, 0x809f407a, 0x280c4779, 0x4f82ba78, 0xe30e66cf, 0x84809bce,\n    0x2c139ccd, 0x4b9d61cc, 0x78d9e43a, 0x1f57193b, 0xb7c41e38, 0xd04ae339,\n    0xd14d15d4, 0xb6c3e8d5, 0x1e50efd6, 0x79de12d7, 0x4a9a9721, 0x2d146a20,\n    0x85876d23, 0xe2099022, 0x878880f9, 0xe0067df8, 0x48957afb, 0x2f1b87fa,\n    0x1c5f020c, 0x7bd1ff0d, 0xd342f80e, 0xb4cc050f, 0xb5cbf3e2, 0xd2450ee3,\n    0x7ad609e0, 0x1d58f4e1, 0x2e1c7117, 0x49928c16, 0xe1018b15, 0x868f7614,\n    0xbdf4448a, 0xda7ab98b, 0x72e9be88, 0x15674389, 0x2623c67f, 0x41ad3b7e,\n    0xe93e3c7d, 0x8eb0c17c, 0x8fb73791, 0xe839ca90, 0x40aacd93, 0x27243092,\n    0x1460b564, 0x73ee4865, 0xdb7d4f66, 0xbcf3b267, 0xd972a2bc, 0xbefc5fbd,\n    0x166f58be, 0x71e1a5bf, 0x42a52049, 0x252bdd48, 0x8db8da4b, 0xea36274a,\n    0xeb31d1a7, 0x8cbf2ca6, 0x242c2ba5, 0x43a2d6a4, 0x70e65352, 0x1768ae53,\n    0xbffba950, 0xd8755451, 0x74f988e6, 0x137775e7, 0xbbe472e4, 0xdc6a8fe5,\n    0xef2e0a13, 0x88a0f712, 0x2033f011, 0x47bd0d10, 0x46bafbfd, 0x213406fc,\n    0x89a701ff, 0xee29fcfe, 0xdd6d7908, 0xbae38409, 0x1270830a, 0x75fe7e0b,\n    0x107f6ed0, 0x77f193d1, 0xdf6294d2, 0xb8ec69d3, 0x8ba8ec25, 0xec261124,\n    0x44b51627, 0x233beb26, 0x223c1dcb, 0x45b2e0ca, 0xed21e7c9, 0x8aaf1ac8,\n    0xb9eb9f3e, 0xde65623f, 0x76f6653c, 0x1178983d};\n\nconst uint32_t kStrideExtensionTable3[256] = {\n    0x00000000, 0xf20c0dfe, 0xe1f46d0d, 0x13f860f3, 0xc604aceb, 0x3408a115,\n    0x27f0c1e6, 0xd5fccc18, 0x89e52f27, 0x7be922d9, 0x6811422a, 0x9a1d4fd4,\n    0x4fe183cc, 0xbded8e32, 0xae15eec1, 0x5c19e33f, 0x162628bf, 0xe42a2541,\n    0xf7d245b2, 0x05de484c, 0xd0228454, 0x222e89aa, 0x31d6e959, 0xc3dae4a7,\n    0x9fc30798, 0x6dcf0a66, 0x7e376a95, 0x8c3b676b, 0x59c7ab73, 0xabcba68d,\n    0xb833c67e, 0x4a3fcb80, 0x2c4c517e, 0xde405c80, 0xcdb83c73, 0x3fb4318d,\n    0xea48fd95, 0x1844f06b, 0x0bbc9098, 0xf9b09d66, 0xa5a97e59, 0x57a573a7,\n    0x445d1354, 0xb6511eaa, 0x63add2b2, 0x91a1df4c, 0x8259bfbf, 0x7055b241,\n    0x3a6a79c1, 0xc866743f, 0xdb9e14cc, 0x29921932, 0xfc6ed52a, 0x0e62d8d4,\n    0x1d9ab827, 0xef96b5d9, 0xb38f56e6, 0x41835b18, 0x527b3beb, 0xa0773615,\n    0x758bfa0d, 0x8787f7f3, 0x947f9700, 0x66739afe, 0x5898a2fc, 0xaa94af02,\n    0xb96ccff1, 0x4b60c20f, 0x9e9c0e17, 0x6c9003e9, 0x7f68631a, 0x8d646ee4,\n    0xd17d8ddb, 0x23718025, 0x3089e0d6, 0xc285ed28, 0x17792130, 0xe5752cce,\n    0xf68d4c3d, 0x048141c3, 0x4ebe8a43, 0xbcb287bd, 0xaf4ae74e, 0x5d46eab0,\n    0x88ba26a8, 0x7ab62b56, 0x694e4ba5, 0x9b42465b, 0xc75ba564, 0x3557a89a,\n    0x26afc869, 0xd4a3c597, 0x015f098f, 0xf3530471, 0xe0ab6482, 0x12a7697c,\n    0x74d4f382, 0x86d8fe7c, 0x95209e8f, 0x672c9371, 0xb2d05f69, 0x40dc5297,\n    0x53243264, 0xa1283f9a, 0xfd31dca5, 0x0f3dd15b, 0x1cc5b1a8, 0xeec9bc56,\n    0x3b35704e, 0xc9397db0, 0xdac11d43, 0x28cd10bd, 0x62f2db3d, 0x90fed6c3,\n    0x8306b630, 0x710abbce, 0xa4f677d6, 0x56fa7a28, 0x45021adb, 0xb70e1725,\n    0xeb17f41a, 0x191bf9e4, 0x0ae39917, 0xf8ef94e9, 0x2d1358f1, 0xdf1f550f,\n    0xcce735fc, 0x3eeb3802, 0xb13145f8, 0x433d4806, 0x50c528f5, 0xa2c9250b,\n    0x7735e913, 0x8539e4ed, 0x96c1841e, 0x64cd89e0, 0x38d46adf, 0xcad86721,\n    0xd92007d2, 0x2b2c0a2c, 0xfed0c634, 0x0cdccbca, 0x1f24ab39, 0xed28a6c7,\n    0xa7176d47, 0x551b60b9, 0x46e3004a, 0xb4ef0db4, 0x6113c1ac, 0x931fcc52,\n    0x80e7aca1, 0x72eba15f, 0x2ef24260, 0xdcfe4f9e, 0xcf062f6d, 0x3d0a2293,\n    0xe8f6ee8b, 0x1afae375, 0x09028386, 0xfb0e8e78, 0x9d7d1486, 0x6f711978,\n    0x7c89798b, 0x8e857475, 0x5b79b86d, 0xa975b593, 0xba8dd560, 0x4881d89e,\n    0x14983ba1, 0xe694365f, 0xf56c56ac, 0x07605b52, 0xd29c974a, 0x20909ab4,\n    0x3368fa47, 0xc164f7b9, 0x8b5b3c39, 0x795731c7, 0x6aaf5134, 0x98a35cca,\n    0x4d5f90d2, 0xbf539d2c, 0xacabfddf, 0x5ea7f021, 0x02be131e, 0xf0b21ee0,\n    0xe34a7e13, 0x114673ed, 0xc4babff5, 0x36b6b20b, 0x254ed2f8, 0xd742df06,\n    0xe9a9e704, 0x1ba5eafa, 0x085d8a09, 0xfa5187f7, 0x2fad4bef, 0xdda14611,\n    0xce5926e2, 0x3c552b1c, 0x604cc823, 0x9240c5dd, 0x81b8a52e, 0x73b4a8d0,\n    0xa64864c8, 0x54446936, 0x47bc09c5, 0xb5b0043b, 0xff8fcfbb, 0x0d83c245,\n    0x1e7ba2b6, 0xec77af48, 0x398b6350, 0xcb876eae, 0xd87f0e5d, 0x2a7303a3,\n    0x766ae09c, 0x8466ed62, 0x979e8d91, 0x6592806f, 0xb06e4c77, 0x42624189,\n    0x519a217a, 0xa3962c84, 0xc5e5b67a, 0x37e9bb84, 0x2411db77, 0xd61dd689,\n    0x03e11a91, 0xf1ed176f, 0xe215779c, 0x10197a62, 0x4c00995d, 0xbe0c94a3,\n    0xadf4f450, 0x5ff8f9ae, 0x8a0435b6, 0x78083848, 0x6bf058bb, 0x99fc5545,\n    0xd3c39ec5, 0x21cf933b, 0x3237f3c8, 0xc03bfe36, 0x15c7322e, 0xe7cb3fd0,\n    0xf4335f23, 0x063f52dd, 0x5a26b1e2, 0xa82abc1c, 0xbbd2dcef, 0x49ded111,\n    0x9c221d09, 0x6e2e10f7, 0x7dd67004, 0x8fda7dfa};\n\nconstexpr const ptrdiff_t kPrefetchHorizon = 256;\n\n}  // namespace\n\nnamespace crc32c {\n\nuint32_t ExtendPortable(uint32_t crc, const uint8_t* data, size_t size) {\n  const uint8_t* p = data;\n  const uint8_t* e = p + size;\n  uint32_t l = crc ^ kCRC32Xor;\n\n// Process one byte at a time.\n#define STEP1                              \\\n  do {                                     \\\n    int c = (l & 0xff) ^ *p++;             \\\n    l = kByteExtensionTable[c] ^ (l >> 8); \\\n  } while (0)\n\n// Process one of the 4 strides of 4-byte data.\n#define STEP4(s)                                                               \\\n  do {                                                                         \\\n    crc##s = ReadUint32LE(p + s * 4) ^ kStrideExtensionTable3[crc##s & 0xff] ^ \\\n             kStrideExtensionTable2[(crc##s >> 8) & 0xff] ^                    \\\n             kStrideExtensionTable1[(crc##s >> 16) & 0xff] ^                   \\\n             kStrideExtensionTable0[crc##s >> 24];                             \\\n  } while (0)\n\n// Process a 16-byte swath of 4 strides, each of which has 4 bytes of data.\n#define STEP16 \\\n  do {         \\\n    STEP4(0);  \\\n    STEP4(1);  \\\n    STEP4(2);  \\\n    STEP4(3);  \\\n    p += 16;   \\\n  } while (0)\n\n// Process 4 bytes that were already loaded into a word.\n#define STEP4W(w)                                   \\\n  do {                                              \\\n    w ^= l;                                         \\\n    for (size_t i = 0; i < 4; ++i) {                \\\n      w = (w >> 8) ^ kByteExtensionTable[w & 0xff]; \\\n    }                                               \\\n    l = w;                                          \\\n  } while (0)\n\n  // Point x at first 4-byte aligned byte in the buffer. This might be past the\n  // end of the buffer.\n  const uint8_t* x = RoundUp<4>(p);\n  if (x <= e) {\n    // Process bytes p is 4-byte aligned.\n    while (p != x) {\n      STEP1;\n    }\n  }\n\n  if ((e - p) >= 16) {\n    // Load a 16-byte swath into the stride partial results.\n    uint32_t crc0 = ReadUint32LE(p + 0 * 4) ^ l;\n    uint32_t crc1 = ReadUint32LE(p + 1 * 4);\n    uint32_t crc2 = ReadUint32LE(p + 2 * 4);\n    uint32_t crc3 = ReadUint32LE(p + 3 * 4);\n    p += 16;\n\n    while ((e - p) > kPrefetchHorizon) {\n      RequestPrefetch(p + kPrefetchHorizon);\n\n      // Process 64 bytes at a time.\n      STEP16;\n      STEP16;\n      STEP16;\n      STEP16;\n    }\n\n    // Process one 16-byte swath at a time.\n    while ((e - p) >= 16) {\n      STEP16;\n    }\n\n    // Advance one word at a time as far as possible.\n    while ((e - p) >= 4) {\n      STEP4(0);\n      uint32_t tmp = crc0;\n      crc0 = crc1;\n      crc1 = crc2;\n      crc2 = crc3;\n      crc3 = tmp;\n      p += 4;\n    }\n\n    // Combine the 4 partial stride results.\n    l = 0;\n    STEP4W(crc0);\n    STEP4W(crc1);\n    STEP4W(crc2);\n    STEP4W(crc3);\n  }\n\n  // Process the last few bytes.\n  while (p != e) {\n    STEP1;\n  }\n#undef STEP4W\n#undef STEP16\n#undef STEP4\n#undef STEP1\n  return l ^ kCRC32Xor;\n}\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_portable_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"gtest/gtest.h\"\n\n#include \"./crc32c_extend_unittests.h\"\n#include \"./crc32c_internal.h\"\n\nnamespace crc32c {\n\nstruct PortableTestTraits {\n  static uint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) {\n    return ExtendPortable(crc, data, count);\n  }\n};\n\nINSTANTIATE_TYPED_TEST_SUITE_P(Portable, ExtendTest, PortableTestTraits);\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_prefetch.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_PREFETCH_H_\n#define CRC32C_CRC32C_PREFETCH_H_\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_MM_PREFETCH\n\n#if defined(_MSC_VER)\n#include <intrin.h>\n#else  // !defined(_MSC_VER)\n#include <xmmintrin.h>\n#endif  // defined(_MSC_VER)\n\n#endif  // HAVE_MM_PREFETCH\n\nnamespace crc32c {\n\n// Ask the hardware to prefetch the data at the given address into the L1 cache.\ninline void RequestPrefetch(const uint8_t* address) {\n#if HAVE_BUILTIN_PREFETCH\n  // Clang and GCC implement the __builtin_prefetch non-standard extension,\n  // which maps to the best instruction on the target architecture.\n  __builtin_prefetch(reinterpret_cast<const char*>(address), 0 /* Read only. */,\n                     0 /* No temporal locality. */);\n#elif HAVE_MM_PREFETCH\n  // Visual Studio doesn't implement __builtin_prefetch, but exposes the\n  // PREFETCHNTA instruction via the _mm_prefetch intrinsic.\n  _mm_prefetch(reinterpret_cast<const char*>(address), _MM_HINT_NTA);\n#else\n  // No prefetch support. Silence compiler warnings.\n  (void)address;\n#endif  // HAVE_BUILTIN_PREFETCH\n}\n\n}  // namespace crc32c\n\n#endif  // CRC32C_CRC32C_ROUND_UP_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_prefetch_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_prefetch.h\"\n\n// There is no easy way to test cache prefetching. We can only test that the\n// crc32c_prefetch.h header compiles on its own, so it doesn't have any unstated\n// dependencies.\n"
  },
  {
    "path": "src/crc32c/src/crc32c_read_le.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_READ_LE_H_\n#define CRC32C_CRC32C_READ_LE_H_\n\n#include <cstdint>\n#include <cstring>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\nnamespace crc32c {\n\n// Reads a little-endian 32-bit integer from a 32-bit-aligned buffer.\ninline uint32_t ReadUint32LE(const uint8_t* buffer) {\n#if BYTE_ORDER_BIG_ENDIAN\n  return ((static_cast<uint32_t>(static_cast<uint8_t>(buffer[0]))) |\n          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[1])) << 8) |\n          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[2])) << 16) |\n          (static_cast<uint32_t>(static_cast<uint8_t>(buffer[3])) << 24));\n#else   // !BYTE_ORDER_BIG_ENDIAN\n  uint32_t result;\n  // This should be optimized to a single instruction.\n  std::memcpy(&result, buffer, sizeof(result));\n  return result;\n#endif  // BYTE_ORDER_BIG_ENDIAN\n}\n\n// Reads a little-endian 64-bit integer from a 64-bit-aligned buffer.\ninline uint64_t ReadUint64LE(const uint8_t* buffer) {\n#if BYTE_ORDER_BIG_ENDIAN\n  return ((static_cast<uint64_t>(static_cast<uint8_t>(buffer[0]))) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[1])) << 8) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[2])) << 16) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[3])) << 24) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[4])) << 32) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[5])) << 40) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[6])) << 48) |\n          (static_cast<uint64_t>(static_cast<uint8_t>(buffer[7])) << 56));\n#else   // !BYTE_ORDER_BIG_ENDIAN\n  uint64_t result;\n  // This should be optimized to a single instruction.\n  std::memcpy(&result, buffer, sizeof(result));\n  return result;\n#endif  // BYTE_ORDER_BIG_ENDIAN\n}\n\n}  // namespace crc32c\n\n#endif  // CRC32C_CRC32C_READ_LE_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_read_le_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_read_le.h\"\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"gtest/gtest.h\"\n\n#include \"./crc32c_round_up.h\"\n\nnamespace crc32c {\n\nTEST(Crc32CReadLETest, ReadUint32LE) {\n  // little-endian 0x12345678\n  alignas(4) uint8_t bytes[] = {0x78, 0x56, 0x34, 0x12};\n\n  ASSERT_EQ(RoundUp<4>(bytes), bytes) << \"Stack array is not aligned\";\n  EXPECT_EQ(static_cast<uint32_t>(0x12345678), ReadUint32LE(bytes));\n}\n\nTEST(Crc32CReadLETest, ReadUint64LE) {\n  // little-endian 0x123456789ABCDEF0\n  alignas(8) uint8_t bytes[] = {0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12};\n\n  ASSERT_EQ(RoundUp<8>(bytes), bytes) << \"Stack array is not aligned\";\n  EXPECT_EQ(static_cast<uint64_t>(0x123456789ABCDEF0), ReadUint64LE(bytes));\n}\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_round_up.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_ROUND_UP_H_\n#define CRC32C_CRC32C_ROUND_UP_H_\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace crc32c {\n\n// Returns the smallest number >= the given number that is evenly divided by N.\n//\n// N must be a power of two.\ntemplate <int N>\nconstexpr inline uintptr_t RoundUp(uintptr_t pointer) {\n  static_assert((N & (N - 1)) == 0, \"N must be a power of two\");\n  return (pointer + (N - 1)) & ~(N - 1);\n}\n\n// Returns the smallest address >= the given address that is aligned to N bytes.\n//\n// N must be a power of two.\ntemplate <int N>\nconstexpr inline const uint8_t* RoundUp(const uint8_t* pointer) {\n  static_assert((N & (N - 1)) == 0, \"N must be a power of two\");\n  return reinterpret_cast<uint8_t*>(\n      RoundUp<N>(reinterpret_cast<uintptr_t>(pointer)));\n}\n\n}  // namespace crc32c\n\n#endif  // CRC32C_CRC32C_ROUND_UP_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_round_up_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_round_up.h\"\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"gtest/gtest.h\"\n\nnamespace crc32c {\n\nTEST(CRC32CRoundUpTest, RoundUpUintptr) {\n  uintptr_t zero = 0;\n\n  ASSERT_EQ(zero, RoundUp<1>(zero));\n  ASSERT_EQ(1U, RoundUp<1>(1U));\n  ASSERT_EQ(2U, RoundUp<1>(2U));\n  ASSERT_EQ(3U, RoundUp<1>(3U));\n  ASSERT_EQ(~static_cast<uintptr_t>(0), RoundUp<1>(~static_cast<uintptr_t>(0)));\n  ASSERT_EQ(~static_cast<uintptr_t>(1), RoundUp<1>(~static_cast<uintptr_t>(1)));\n  ASSERT_EQ(~static_cast<uintptr_t>(2), RoundUp<1>(~static_cast<uintptr_t>(2)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<1>(~static_cast<uintptr_t>(3)));\n\n  ASSERT_EQ(zero, RoundUp<2>(zero));\n  ASSERT_EQ(2U, RoundUp<2>(1U));\n  ASSERT_EQ(2U, RoundUp<2>(2U));\n  ASSERT_EQ(4U, RoundUp<2>(3U));\n  ASSERT_EQ(4U, RoundUp<2>(4U));\n  ASSERT_EQ(6U, RoundUp<2>(5U));\n  ASSERT_EQ(6U, RoundUp<2>(6U));\n  ASSERT_EQ(8U, RoundUp<2>(7U));\n  ASSERT_EQ(8U, RoundUp<2>(8U));\n  ASSERT_EQ(~static_cast<uintptr_t>(1), RoundUp<2>(~static_cast<uintptr_t>(1)));\n  ASSERT_EQ(~static_cast<uintptr_t>(1), RoundUp<2>(~static_cast<uintptr_t>(2)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<2>(~static_cast<uintptr_t>(3)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<2>(~static_cast<uintptr_t>(4)));\n\n  ASSERT_EQ(zero, RoundUp<4>(zero));\n  ASSERT_EQ(4U, RoundUp<4>(1U));\n  ASSERT_EQ(4U, RoundUp<4>(2U));\n  ASSERT_EQ(4U, RoundUp<4>(3U));\n  ASSERT_EQ(4U, RoundUp<4>(4U));\n  ASSERT_EQ(8U, RoundUp<4>(5U));\n  ASSERT_EQ(8U, RoundUp<4>(6U));\n  ASSERT_EQ(8U, RoundUp<4>(7U));\n  ASSERT_EQ(8U, RoundUp<4>(8U));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<4>(~static_cast<uintptr_t>(3)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<4>(~static_cast<uintptr_t>(4)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<4>(~static_cast<uintptr_t>(5)));\n  ASSERT_EQ(~static_cast<uintptr_t>(3), RoundUp<4>(~static_cast<uintptr_t>(6)));\n  ASSERT_EQ(~static_cast<uintptr_t>(7), RoundUp<4>(~static_cast<uintptr_t>(7)));\n  ASSERT_EQ(~static_cast<uintptr_t>(7), RoundUp<4>(~static_cast<uintptr_t>(8)));\n  ASSERT_EQ(~static_cast<uintptr_t>(7), RoundUp<4>(~static_cast<uintptr_t>(9)));\n}\n\nTEST(CRC32CRoundUpTest, RoundUpPointer) {\n  uintptr_t zero = 0, three = 3, four = 4, seven = 7, eight = 8;\n\n  const uint8_t* zero_ptr = reinterpret_cast<const uint8_t*>(zero);\n  const uint8_t* three_ptr = reinterpret_cast<const uint8_t*>(three);\n  const uint8_t* four_ptr = reinterpret_cast<const uint8_t*>(four);\n  const uint8_t* seven_ptr = reinterpret_cast<const uint8_t*>(seven);\n  const uint8_t* eight_ptr = reinterpret_cast<uint8_t*>(eight);\n\n  ASSERT_EQ(zero_ptr, RoundUp<1>(zero_ptr));\n  ASSERT_EQ(zero_ptr, RoundUp<4>(zero_ptr));\n  ASSERT_EQ(zero_ptr, RoundUp<8>(zero_ptr));\n\n  ASSERT_EQ(three_ptr, RoundUp<1>(three_ptr));\n  ASSERT_EQ(four_ptr, RoundUp<4>(three_ptr));\n  ASSERT_EQ(eight_ptr, RoundUp<8>(three_ptr));\n\n  ASSERT_EQ(four_ptr, RoundUp<1>(four_ptr));\n  ASSERT_EQ(four_ptr, RoundUp<4>(four_ptr));\n  ASSERT_EQ(eight_ptr, RoundUp<8>(four_ptr));\n\n  ASSERT_EQ(seven_ptr, RoundUp<1>(seven_ptr));\n  ASSERT_EQ(eight_ptr, RoundUp<4>(seven_ptr));\n  ASSERT_EQ(eight_ptr, RoundUp<8>(four_ptr));\n}\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_sse42.cc",
    "content": "// Copyright 2008 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"./crc32c_sse42.h\"\n\n// In a separate source file to allow this accelerated CRC32C function to be\n// compiled with the appropriate compiler flags to enable SSE4.2 instructions.\n\n// This implementation is loosely based on Intel Pub 323405 from April 2011,\n// \"Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction\".\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"./crc32c_internal.h\"\n#include \"./crc32c_prefetch.h\"\n#include \"./crc32c_read_le.h\"\n#include \"./crc32c_round_up.h\"\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n#if defined(_MSC_VER)\n#include <intrin.h>\n#else  // !defined(_MSC_VER)\n#include <nmmintrin.h>\n#endif  // defined(_MSC_VER)\n\nnamespace crc32c {\n\nnamespace {\n\nconstexpr const ptrdiff_t kGroups = 3;\nconstexpr const ptrdiff_t kBlock0Size = 16 * 1024 / kGroups / 64 * 64;\nconstexpr const ptrdiff_t kBlock1Size = 4 * 1024 / kGroups / 8 * 8;\nconstexpr const ptrdiff_t kBlock2Size = 1024 / kGroups / 8 * 8;\n\nconst uint32_t kBlock0SkipTable[8][16] = {\n    {0x00000000, 0xff770459, 0xfb027e43, 0x04757a1a, 0xf3e88a77, 0x0c9f8e2e,\n     0x08eaf434, 0xf79df06d, 0xe23d621f, 0x1d4a6646, 0x193f1c5c, 0xe6481805,\n     0x11d5e868, 0xeea2ec31, 0xead7962b, 0x15a09272},\n    {0x00000000, 0xc196b2cf, 0x86c1136f, 0x4757a1a0, 0x086e502f, 0xc9f8e2e0,\n     0x8eaf4340, 0x4f39f18f, 0x10dca05e, 0xd14a1291, 0x961db331, 0x578b01fe,\n     0x18b2f071, 0xd92442be, 0x9e73e31e, 0x5fe551d1},\n    {0x00000000, 0x21b940bc, 0x43728178, 0x62cbc1c4, 0x86e502f0, 0xa75c424c,\n     0xc5978388, 0xe42ec334, 0x08267311, 0x299f33ad, 0x4b54f269, 0x6aedb2d5,\n     0x8ec371e1, 0xaf7a315d, 0xcdb1f099, 0xec08b025},\n    {0x00000000, 0x104ce622, 0x2099cc44, 0x30d52a66, 0x41339888, 0x517f7eaa,\n     0x61aa54cc, 0x71e6b2ee, 0x82673110, 0x922bd732, 0xa2fefd54, 0xb2b21b76,\n     0xc354a998, 0xd3184fba, 0xe3cd65dc, 0xf38183fe},\n    {0x00000000, 0x012214d1, 0x024429a2, 0x03663d73, 0x04885344, 0x05aa4795,\n     0x06cc7ae6, 0x07ee6e37, 0x0910a688, 0x0832b259, 0x0b548f2a, 0x0a769bfb,\n     0x0d98f5cc, 0x0cbae11d, 0x0fdcdc6e, 0x0efec8bf},\n    {0x00000000, 0x12214d10, 0x24429a20, 0x3663d730, 0x48853440, 0x5aa47950,\n     0x6cc7ae60, 0x7ee6e370, 0x910a6880, 0x832b2590, 0xb548f2a0, 0xa769bfb0,\n     0xd98f5cc0, 0xcbae11d0, 0xfdcdc6e0, 0xefec8bf0},\n    {0x00000000, 0x27f8a7f1, 0x4ff14fe2, 0x6809e813, 0x9fe29fc4, 0xb81a3835,\n     0xd013d026, 0xf7eb77d7, 0x3a294979, 0x1dd1ee88, 0x75d8069b, 0x5220a16a,\n     0xa5cbd6bd, 0x8233714c, 0xea3a995f, 0xcdc23eae},\n    {0x00000000, 0x745292f2, 0xe8a525e4, 0x9cf7b716, 0xd4a63d39, 0xa0f4afcb,\n     0x3c0318dd, 0x48518a2f, 0xaca00c83, 0xd8f29e71, 0x44052967, 0x3057bb95,\n     0x780631ba, 0x0c54a348, 0x90a3145e, 0xe4f186ac},\n};\nconst uint32_t kBlock1SkipTable[8][16] = {\n    {0x00000000, 0x79113270, 0xf22264e0, 0x8b335690, 0xe1a8bf31, 0x98b98d41,\n     0x138adbd1, 0x6a9be9a1, 0xc6bd0893, 0xbfac3ae3, 0x349f6c73, 0x4d8e5e03,\n     0x2715b7a2, 0x5e0485d2, 0xd537d342, 0xac26e132},\n    {0x00000000, 0x889667d7, 0x14c0b95f, 0x9c56de88, 0x298172be, 0xa1171569,\n     0x3d41cbe1, 0xb5d7ac36, 0x5302e57c, 0xdb9482ab, 0x47c25c23, 0xcf543bf4,\n     0x7a8397c2, 0xf215f015, 0x6e432e9d, 0xe6d5494a},\n    {0x00000000, 0xa605caf8, 0x49e7e301, 0xefe229f9, 0x93cfc602, 0x35ca0cfa,\n     0xda282503, 0x7c2deffb, 0x2273faf5, 0x8476300d, 0x6b9419f4, 0xcd91d30c,\n     0xb1bc3cf7, 0x17b9f60f, 0xf85bdff6, 0x5e5e150e},\n    {0x00000000, 0x44e7f5ea, 0x89cfebd4, 0xcd281e3e, 0x1673a159, 0x529454b3,\n     0x9fbc4a8d, 0xdb5bbf67, 0x2ce742b2, 0x6800b758, 0xa528a966, 0xe1cf5c8c,\n     0x3a94e3eb, 0x7e731601, 0xb35b083f, 0xf7bcfdd5},\n    {0x00000000, 0x59ce8564, 0xb39d0ac8, 0xea538fac, 0x62d66361, 0x3b18e605,\n     0xd14b69a9, 0x8885eccd, 0xc5acc6c2, 0x9c6243a6, 0x7631cc0a, 0x2fff496e,\n     0xa77aa5a3, 0xfeb420c7, 0x14e7af6b, 0x4d292a0f},\n    {0x00000000, 0x8eb5fb75, 0x1887801b, 0x96327b6e, 0x310f0036, 0xbfbafb43,\n     0x2988802d, 0xa73d7b58, 0x621e006c, 0xecabfb19, 0x7a998077, 0xf42c7b02,\n     0x5311005a, 0xdda4fb2f, 0x4b968041, 0xc5237b34},\n    {0x00000000, 0xc43c00d8, 0x8d947741, 0x49a87799, 0x1ec49873, 0xdaf898ab,\n     0x9350ef32, 0x576cefea, 0x3d8930e6, 0xf9b5303e, 0xb01d47a7, 0x7421477f,\n     0x234da895, 0xe771a84d, 0xaed9dfd4, 0x6ae5df0c},\n    {0x00000000, 0x7b1261cc, 0xf624c398, 0x8d36a254, 0xe9a5f1c1, 0x92b7900d,\n     0x1f813259, 0x64935395, 0xd6a79573, 0xadb5f4bf, 0x208356eb, 0x5b913727,\n     0x3f0264b2, 0x4410057e, 0xc926a72a, 0xb234c6e6},\n};\nconst uint32_t kBlock2SkipTable[8][16] = {\n    {0x00000000, 0x8f158014, 0x1bc776d9, 0x94d2f6cd, 0x378eedb2, 0xb89b6da6,\n     0x2c499b6b, 0xa35c1b7f, 0x6f1ddb64, 0xe0085b70, 0x74daadbd, 0xfbcf2da9,\n     0x589336d6, 0xd786b6c2, 0x4354400f, 0xcc41c01b},\n    {0x00000000, 0xde3bb6c8, 0xb99b1b61, 0x67a0ada9, 0x76da4033, 0xa8e1f6fb,\n     0xcf415b52, 0x117aed9a, 0xedb48066, 0x338f36ae, 0x542f9b07, 0x8a142dcf,\n     0x9b6ec055, 0x4555769d, 0x22f5db34, 0xfcce6dfc},\n    {0x00000000, 0xde85763d, 0xb8e69a8b, 0x6663ecb6, 0x742143e7, 0xaaa435da,\n     0xccc7d96c, 0x1242af51, 0xe84287ce, 0x36c7f1f3, 0x50a41d45, 0x8e216b78,\n     0x9c63c429, 0x42e6b214, 0x24855ea2, 0xfa00289f},\n    {0x00000000, 0xd569796d, 0xaf3e842b, 0x7a57fd46, 0x5b917ea7, 0x8ef807ca,\n     0xf4affa8c, 0x21c683e1, 0xb722fd4e, 0x624b8423, 0x181c7965, 0xcd750008,\n     0xecb383e9, 0x39dafa84, 0x438d07c2, 0x96e47eaf},\n    {0x00000000, 0x6ba98c6d, 0xd75318da, 0xbcfa94b7, 0xab4a4745, 0xc0e3cb28,\n     0x7c195f9f, 0x17b0d3f2, 0x5378f87b, 0x38d17416, 0x842be0a1, 0xef826ccc,\n     0xf832bf3e, 0x939b3353, 0x2f61a7e4, 0x44c82b89},\n    {0x00000000, 0xa6f1f0f6, 0x480f971d, 0xeefe67eb, 0x901f2e3a, 0x36eedecc,\n     0xd810b927, 0x7ee149d1, 0x25d22a85, 0x8323da73, 0x6dddbd98, 0xcb2c4d6e,\n     0xb5cd04bf, 0x133cf449, 0xfdc293a2, 0x5b336354},\n    {0x00000000, 0x4ba4550a, 0x9748aa14, 0xdcecff1e, 0x2b7d22d9, 0x60d977d3,\n     0xbc3588cd, 0xf791ddc7, 0x56fa45b2, 0x1d5e10b8, 0xc1b2efa6, 0x8a16baac,\n     0x7d87676b, 0x36233261, 0xeacfcd7f, 0xa16b9875},\n    {0x00000000, 0xadf48b64, 0x5e056039, 0xf3f1eb5d, 0xbc0ac072, 0x11fe4b16,\n     0xe20fa04b, 0x4ffb2b2f, 0x7df9f615, 0xd00d7d71, 0x23fc962c, 0x8e081d48,\n     0xc1f33667, 0x6c07bd03, 0x9ff6565e, 0x3202dd3a},\n};\n\nconstexpr const ptrdiff_t kPrefetchHorizon = 256;\n\n}  // namespace\n\nuint32_t ExtendSse42(uint32_t crc, const uint8_t* data, size_t size) {\n  const uint8_t* p = data;\n  const uint8_t* e = data + size;\n  uint32_t l = crc ^ kCRC32Xor;\n\n#define STEP1                  \\\n  do {                         \\\n    l = _mm_crc32_u8(l, *p++); \\\n  } while (0)\n\n#define STEP4(crc)                             \\\n  do {                                         \\\n    crc = _mm_crc32_u32(crc, ReadUint32LE(p)); \\\n    p += 4;                                    \\\n  } while (0)\n\n#define STEP8(crc, data)                          \\\n  do {                                            \\\n    crc = _mm_crc32_u64(crc, ReadUint64LE(data)); \\\n    data += 8;                                    \\\n  } while (0)\n\n#define STEP8BY3(crc0, crc1, crc2, p0, p1, p2) \\\n  do {                                         \\\n    STEP8(crc0, p0);                           \\\n    STEP8(crc1, p1);                           \\\n    STEP8(crc2, p2);                           \\\n  } while (0)\n\n#define STEP8X3(crc0, crc1, crc2, bs)                     \\\n  do {                                                    \\\n    crc0 = _mm_crc32_u64(crc0, ReadUint64LE(p));          \\\n    crc1 = _mm_crc32_u64(crc1, ReadUint64LE(p + bs));     \\\n    crc2 = _mm_crc32_u64(crc2, ReadUint64LE(p + 2 * bs)); \\\n    p += 8;                                               \\\n  } while (0)\n\n#define SKIP_BLOCK(crc, tab)                                      \\\n  do {                                                            \\\n    crc = tab[0][crc & 0xf] ^ tab[1][(crc >> 4) & 0xf] ^          \\\n          tab[2][(crc >> 8) & 0xf] ^ tab[3][(crc >> 12) & 0xf] ^  \\\n          tab[4][(crc >> 16) & 0xf] ^ tab[5][(crc >> 20) & 0xf] ^ \\\n          tab[6][(crc >> 24) & 0xf] ^ tab[7][(crc >> 28) & 0xf];  \\\n  } while (0)\n\n  // Point x at first 8-byte aligned byte in the buffer. This might be past the\n  // end of the buffer.\n  const uint8_t* x = RoundUp<8>(p);\n  if (x <= e) {\n    // Process bytes p is 8-byte aligned.\n    while (p != x) {\n      STEP1;\n    }\n  }\n\n  // Proccess the data in predetermined block sizes with tables for quickly\n  // combining the checksum. Experimentally it's better to use larger block\n  // sizes where possible so use a hierarchy of decreasing block sizes.\n  uint64_t l64 = l;\n  while ((e - p) >= kGroups * kBlock0Size) {\n    uint64_t l641 = 0;\n    uint64_t l642 = 0;\n    for (int i = 0; i < kBlock0Size; i += 8 * 8) {\n      // Prefetch ahead to hide latency.\n      RequestPrefetch(p + kPrefetchHorizon);\n      RequestPrefetch(p + kBlock0Size + kPrefetchHorizon);\n      RequestPrefetch(p + 2 * kBlock0Size + kPrefetchHorizon);\n\n      // Process 64 bytes at a time.\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n      STEP8X3(l64, l641, l642, kBlock0Size);\n    }\n\n    // Combine results.\n    SKIP_BLOCK(l64, kBlock0SkipTable);\n    l64 ^= l641;\n    SKIP_BLOCK(l64, kBlock0SkipTable);\n    l64 ^= l642;\n    p += (kGroups - 1) * kBlock0Size;\n  }\n  while ((e - p) >= kGroups * kBlock1Size) {\n    uint64_t l641 = 0;\n    uint64_t l642 = 0;\n    for (int i = 0; i < kBlock1Size; i += 8) {\n      STEP8X3(l64, l641, l642, kBlock1Size);\n    }\n    SKIP_BLOCK(l64, kBlock1SkipTable);\n    l64 ^= l641;\n    SKIP_BLOCK(l64, kBlock1SkipTable);\n    l64 ^= l642;\n    p += (kGroups - 1) * kBlock1Size;\n  }\n  while ((e - p) >= kGroups * kBlock2Size) {\n    uint64_t l641 = 0;\n    uint64_t l642 = 0;\n    for (int i = 0; i < kBlock2Size; i += 8) {\n      STEP8X3(l64, l641, l642, kBlock2Size);\n    }\n    SKIP_BLOCK(l64, kBlock2SkipTable);\n    l64 ^= l641;\n    SKIP_BLOCK(l64, kBlock2SkipTable);\n    l64 ^= l642;\n    p += (kGroups - 1) * kBlock2Size;\n  }\n\n  // Process bytes 16 at a time\n  while ((e - p) >= 16) {\n    STEP8(l64, p);\n    STEP8(l64, p);\n  }\n\n  l = static_cast<uint32_t>(l64);\n  // Process the last few bytes.\n  while (p != e) {\n    STEP1;\n  }\n#undef SKIP_BLOCK\n#undef STEP8X3\n#undef STEP8BY3\n#undef STEP8\n#undef STEP4\n#undef STEP1\n\n  return l ^ kCRC32Xor;\n}\n\n}  // namespace crc32c\n\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n"
  },
  {
    "path": "src/crc32c/src/crc32c_sse42.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_SSE42_H_\n#define CRC32C_CRC32C_SSE42_H_\n\n// X86-specific code.\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n// The hardware-accelerated implementation is only enabled for 64-bit builds,\n// because a straightforward 32-bit implementation actually runs slower than the\n// portable version. Most X86 machines are 64-bit nowadays, so it doesn't make\n// much sense to spend time building an optimized hardware-accelerated\n// implementation.\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\nnamespace crc32c {\n\n// SSE4.2-accelerated implementation in crc32c_sse42.cc\nuint32_t ExtendSse42(uint32_t crc, const uint8_t* data, size_t count);\n\n}  // namespace crc32c\n\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n#endif  // CRC32C_CRC32C_SSE42_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_sse42_check.h",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef CRC32C_CRC32C_SSE42_CHECK_H_\n#define CRC32C_CRC32C_SSE42_CHECK_H_\n\n// X86-specific code checking the availability of SSE4.2 instructions.\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n// If the compiler supports SSE4.2, it definitely supports X86.\n\n#if defined(_MSC_VER)\n#include <intrin.h>\n\nnamespace crc32c {\n\ninline bool CanUseSse42() {\n  int cpu_info[4];\n  __cpuid(cpu_info, 1);\n  return (cpu_info[2] & (1 << 20)) != 0;\n}\n\n}  // namespace crc32c\n\n#else  // !defined(_MSC_VER)\n#include <cpuid.h>\n\nnamespace crc32c {\n\ninline bool CanUseSse42() {\n  unsigned int eax, ebx, ecx, edx;\n  return __get_cpuid(1, &eax, &ebx, &ecx, &edx) && ((ecx & (1 << 20)) != 0);\n}\n\n}  // namespace crc32c\n\n#endif  // defined(_MSC_VER)\n\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n#endif  // CRC32C_CRC32C_SSE42_CHECK_H_\n"
  },
  {
    "path": "src/crc32c/src/crc32c_sse42_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"gtest/gtest.h\"\n\n#include \"./crc32c_extend_unittests.h\"\n#include \"./crc32c_sse42.h\"\n\nnamespace crc32c {\n\n#if HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\nstruct Sse42TestTraits {\n  static uint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) {\n    return ExtendSse42(crc, data, count);\n  }\n};\n\nINSTANTIATE_TYPED_TEST_SUITE_P(Sse42, ExtendTest, Sse42TestTraits);\n\n#endif  // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__))\n\n}  // namespace crc32c\n"
  },
  {
    "path": "src/crc32c/src/crc32c_test_main.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifdef CRC32C_HAVE_CONFIG_H\n#include \"crc32c/crc32c_config.h\"\n#endif\n\n#include \"gtest/gtest.h\"\n\n#if CRC32C_TESTS_BUILT_WITH_GLOG\n#include \"glog/logging.h\"\n#endif  // CRC32C_TESTS_BUILT_WITH_GLOG\n\nint main(int argc, char** argv) {\n#if CRC32C_TESTS_BUILT_WITH_GLOG\n  google::InitGoogleLogging(argv[0]);\n  google::InstallFailureSignalHandler();\n#endif  // CRC32C_TESTS_BUILT_WITH_GLOG\n  testing::InitGoogleTest(&argc, argv);\n  return RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "src/crc32c/src/crc32c_unittest.cc",
    "content": "// Copyright 2017 The CRC32C Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"crc32c/crc32c.h\"\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n\n#include \"gtest/gtest.h\"\n\n#include \"./crc32c_extend_unittests.h\"\n\nTEST(Crc32CTest, Crc32c) {\n  // From rfc3720 section B.4.\n  uint8_t buf[32];\n\n  std::memset(buf, 0, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x8a9136aa),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  std::memset(buf, 0xff, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x62a8ab43),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(i);\n  EXPECT_EQ(static_cast<uint32_t>(0x46dd794e),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(31 - i);\n  EXPECT_EQ(static_cast<uint32_t>(0x113fdb5c),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  uint8_t data[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n  EXPECT_EQ(static_cast<uint32_t>(0xd9963a56),\n            crc32c::Crc32c(data, sizeof(data)));\n}\n\nnamespace crc32c {\n\nstruct ApiTestTraits {\n  static uint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) {\n    return ::crc32c::Extend(crc, data, count);\n  }\n};\n\nINSTANTIATE_TYPED_TEST_SUITE_P(Api, ExtendTest, ApiTestTraits);\n\n}  // namespace crc32c\n\nTEST(CRC32CTest, Crc32cCharPointer) {\n  char buf[32];\n\n  std::memset(buf, 0, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x8a9136aa),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  std::memset(buf, 0xff, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x62a8ab43),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<char>(i);\n  EXPECT_EQ(static_cast<uint32_t>(0x46dd794e),\n            crc32c::Crc32c(buf, sizeof(buf)));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<char>(31 - i);\n  EXPECT_EQ(static_cast<uint32_t>(0x113fdb5c),\n            crc32c::Crc32c(buf, sizeof(buf)));\n}\n\nTEST(CRC32CTest, Crc32cStdString) {\n  std::string buf;\n  buf.resize(32);\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<char>(0x00);\n  EXPECT_EQ(static_cast<uint32_t>(0x8a9136aa), crc32c::Crc32c(buf));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = '\\xff';\n  EXPECT_EQ(static_cast<uint32_t>(0x62a8ab43), crc32c::Crc32c(buf));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<char>(i);\n  EXPECT_EQ(static_cast<uint32_t>(0x46dd794e), crc32c::Crc32c(buf));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<char>(31 - i);\n  EXPECT_EQ(static_cast<uint32_t>(0x113fdb5c), crc32c::Crc32c(buf));\n}\n\n#if __cplusplus > 201402L\n#if __has_include(<string_view>)\n\nTEST(CRC32CTest, Crc32cStdStringView) {\n  uint8_t buf[32];\n  std::string_view view(reinterpret_cast<const char*>(buf), sizeof(buf));\n\n  std::memset(buf, 0, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x8a9136aa), crc32c::Crc32c(view));\n\n  std::memset(buf, 0xff, sizeof(buf));\n  EXPECT_EQ(static_cast<uint32_t>(0x62a8ab43), crc32c::Crc32c(view));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(i);\n  EXPECT_EQ(static_cast<uint32_t>(0x46dd794e), crc32c::Crc32c(view));\n\n  for (size_t i = 0; i < 32; ++i)\n    buf[i] = static_cast<uint8_t>(31 - i);\n  EXPECT_EQ(static_cast<uint32_t>(0x113fdb5c), crc32c::Crc32c(view));\n}\n\n#endif  // __has_include(<string_view>)\n#endif  // __cplusplus > 201402L\n\n#define TESTED_EXTEND Extend\n#include \"./crc32c_extend_unittests.h\"\n#undef TESTED_EXTEND\n"
  },
  {
    "path": "src/crypto/chacha20.cpp",
    "content": "// Copyright (c) 2017-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n// Based on the public domain implementation 'merged' by D. J. Bernstein\n// See https://cr.yp.to/chacha.html.\n\n#include <crypto/common.h>\n#include <crypto/chacha20.h>\n\n#include <string.h>\n\nconstexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }\n\n#define QUARTERROUND(a,b,c,d) \\\n  a += b; d = rotl32(d ^ a, 16); \\\n  c += d; b = rotl32(b ^ c, 12); \\\n  a += b; d = rotl32(d ^ a, 8); \\\n  c += d; b = rotl32(b ^ c, 7);\n\nstatic const unsigned char sigma[] = \"expand 32-byte k\";\nstatic const unsigned char tau[] = \"expand 16-byte k\";\n\nvoid ChaCha20::SetKey(const unsigned char* k, size_t keylen)\n{\n    const unsigned char *constants;\n\n    input[4] = ReadLE32(k + 0);\n    input[5] = ReadLE32(k + 4);\n    input[6] = ReadLE32(k + 8);\n    input[7] = ReadLE32(k + 12);\n    if (keylen == 32) { /* recommended */\n        k += 16;\n        constants = sigma;\n    } else { /* keylen == 16 */\n        constants = tau;\n    }\n    input[8] = ReadLE32(k + 0);\n    input[9] = ReadLE32(k + 4);\n    input[10] = ReadLE32(k + 8);\n    input[11] = ReadLE32(k + 12);\n    input[0] = ReadLE32(constants + 0);\n    input[1] = ReadLE32(constants + 4);\n    input[2] = ReadLE32(constants + 8);\n    input[3] = ReadLE32(constants + 12);\n    input[12] = 0;\n    input[13] = 0;\n    input[14] = 0;\n    input[15] = 0;\n}\n\nChaCha20::ChaCha20()\n{\n    memset(input, 0, sizeof(input));\n}\n\nChaCha20::ChaCha20(const unsigned char* k, size_t keylen)\n{\n    SetKey(k, keylen);\n}\n\nvoid ChaCha20::SetIV(uint64_t iv)\n{\n    input[14] = iv;\n    input[15] = iv >> 32;\n}\n\nvoid ChaCha20::Seek(uint64_t pos)\n{\n    input[12] = pos;\n    input[13] = pos >> 32;\n}\n\nvoid ChaCha20::Keystream(unsigned char* c, size_t bytes)\n{\n    uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;\n    uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;\n    unsigned char *ctarget = nullptr;\n    unsigned char tmp[64];\n    unsigned int i;\n\n    if (!bytes) return;\n\n    j0 = input[0];\n    j1 = input[1];\n    j2 = input[2];\n    j3 = input[3];\n    j4 = input[4];\n    j5 = input[5];\n    j6 = input[6];\n    j7 = input[7];\n    j8 = input[8];\n    j9 = input[9];\n    j10 = input[10];\n    j11 = input[11];\n    j12 = input[12];\n    j13 = input[13];\n    j14 = input[14];\n    j15 = input[15];\n\n    for (;;) {\n        if (bytes < 64) {\n            ctarget = c;\n            c = tmp;\n        }\n        x0 = j0;\n        x1 = j1;\n        x2 = j2;\n        x3 = j3;\n        x4 = j4;\n        x5 = j5;\n        x6 = j6;\n        x7 = j7;\n        x8 = j8;\n        x9 = j9;\n        x10 = j10;\n        x11 = j11;\n        x12 = j12;\n        x13 = j13;\n        x14 = j14;\n        x15 = j15;\n        for (i = 20;i > 0;i -= 2) {\n            QUARTERROUND( x0, x4, x8,x12)\n            QUARTERROUND( x1, x5, x9,x13)\n            QUARTERROUND( x2, x6,x10,x14)\n            QUARTERROUND( x3, x7,x11,x15)\n            QUARTERROUND( x0, x5,x10,x15)\n            QUARTERROUND( x1, x6,x11,x12)\n            QUARTERROUND( x2, x7, x8,x13)\n            QUARTERROUND( x3, x4, x9,x14)\n        }\n        x0 += j0;\n        x1 += j1;\n        x2 += j2;\n        x3 += j3;\n        x4 += j4;\n        x5 += j5;\n        x6 += j6;\n        x7 += j7;\n        x8 += j8;\n        x9 += j9;\n        x10 += j10;\n        x11 += j11;\n        x12 += j12;\n        x13 += j13;\n        x14 += j14;\n        x15 += j15;\n\n        ++j12;\n        if (!j12) ++j13;\n\n        WriteLE32(c + 0, x0);\n        WriteLE32(c + 4, x1);\n        WriteLE32(c + 8, x2);\n        WriteLE32(c + 12, x3);\n        WriteLE32(c + 16, x4);\n        WriteLE32(c + 20, x5);\n        WriteLE32(c + 24, x6);\n        WriteLE32(c + 28, x7);\n        WriteLE32(c + 32, x8);\n        WriteLE32(c + 36, x9);\n        WriteLE32(c + 40, x10);\n        WriteLE32(c + 44, x11);\n        WriteLE32(c + 48, x12);\n        WriteLE32(c + 52, x13);\n        WriteLE32(c + 56, x14);\n        WriteLE32(c + 60, x15);\n\n        if (bytes <= 64) {\n            if (bytes < 64) {\n                for (i = 0;i < bytes;++i) ctarget[i] = c[i];\n            }\n            input[12] = j12;\n            input[13] = j13;\n            return;\n        }\n        bytes -= 64;\n        c += 64;\n    }\n}\n\nvoid ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)\n{\n    uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;\n    uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;\n    unsigned char *ctarget = nullptr;\n    unsigned char tmp[64];\n    unsigned int i;\n\n    if (!bytes) return;\n\n    j0 = input[0];\n    j1 = input[1];\n    j2 = input[2];\n    j3 = input[3];\n    j4 = input[4];\n    j5 = input[5];\n    j6 = input[6];\n    j7 = input[7];\n    j8 = input[8];\n    j9 = input[9];\n    j10 = input[10];\n    j11 = input[11];\n    j12 = input[12];\n    j13 = input[13];\n    j14 = input[14];\n    j15 = input[15];\n\n    for (;;) {\n        if (bytes < 64) {\n            // if m has fewer than 64 bytes available, copy m to tmp and\n            // read from tmp instead\n            for (i = 0;i < bytes;++i) tmp[i] = m[i];\n            m = tmp;\n            ctarget = c;\n            c = tmp;\n        }\n        x0 = j0;\n        x1 = j1;\n        x2 = j2;\n        x3 = j3;\n        x4 = j4;\n        x5 = j5;\n        x6 = j6;\n        x7 = j7;\n        x8 = j8;\n        x9 = j9;\n        x10 = j10;\n        x11 = j11;\n        x12 = j12;\n        x13 = j13;\n        x14 = j14;\n        x15 = j15;\n        for (i = 20;i > 0;i -= 2) {\n            QUARTERROUND( x0, x4, x8,x12)\n            QUARTERROUND( x1, x5, x9,x13)\n            QUARTERROUND( x2, x6,x10,x14)\n            QUARTERROUND( x3, x7,x11,x15)\n            QUARTERROUND( x0, x5,x10,x15)\n            QUARTERROUND( x1, x6,x11,x12)\n            QUARTERROUND( x2, x7, x8,x13)\n            QUARTERROUND( x3, x4, x9,x14)\n        }\n        x0 += j0;\n        x1 += j1;\n        x2 += j2;\n        x3 += j3;\n        x4 += j4;\n        x5 += j5;\n        x6 += j6;\n        x7 += j7;\n        x8 += j8;\n        x9 += j9;\n        x10 += j10;\n        x11 += j11;\n        x12 += j12;\n        x13 += j13;\n        x14 += j14;\n        x15 += j15;\n\n        x0 ^= ReadLE32(m + 0);\n        x1 ^= ReadLE32(m + 4);\n        x2 ^= ReadLE32(m + 8);\n        x3 ^= ReadLE32(m + 12);\n        x4 ^= ReadLE32(m + 16);\n        x5 ^= ReadLE32(m + 20);\n        x6 ^= ReadLE32(m + 24);\n        x7 ^= ReadLE32(m + 28);\n        x8 ^= ReadLE32(m + 32);\n        x9 ^= ReadLE32(m + 36);\n        x10 ^= ReadLE32(m + 40);\n        x11 ^= ReadLE32(m + 44);\n        x12 ^= ReadLE32(m + 48);\n        x13 ^= ReadLE32(m + 52);\n        x14 ^= ReadLE32(m + 56);\n        x15 ^= ReadLE32(m + 60);\n\n        ++j12;\n        if (!j12) ++j13;\n\n        WriteLE32(c + 0, x0);\n        WriteLE32(c + 4, x1);\n        WriteLE32(c + 8, x2);\n        WriteLE32(c + 12, x3);\n        WriteLE32(c + 16, x4);\n        WriteLE32(c + 20, x5);\n        WriteLE32(c + 24, x6);\n        WriteLE32(c + 28, x7);\n        WriteLE32(c + 32, x8);\n        WriteLE32(c + 36, x9);\n        WriteLE32(c + 40, x10);\n        WriteLE32(c + 44, x11);\n        WriteLE32(c + 48, x12);\n        WriteLE32(c + 52, x13);\n        WriteLE32(c + 56, x14);\n        WriteLE32(c + 60, x15);\n\n        if (bytes <= 64) {\n            if (bytes < 64) {\n                for (i = 0;i < bytes;++i) ctarget[i] = c[i];\n            }\n            input[12] = j12;\n            input[13] = j13;\n            return;\n        }\n        bytes -= 64;\n        c += 64;\n        m += 64;\n    }\n}\n"
  },
  {
    "path": "src/crypto/chacha20.h",
    "content": "// Copyright (c) 2017-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_CRYPTO_CHACHA20_H\n#define BITCOIN_CRYPTO_CHACHA20_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein\n    https://cr.yp.to/chacha/chacha-20080128.pdf */\nclass ChaCha20\n{\nprivate:\n    uint32_t input[16];\n\npublic:\n    ChaCha20();\n    ChaCha20(const unsigned char* key, size_t keylen);\n    void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */\n    void SetIV(uint64_t iv); // set the 64bit nonce\n    void Seek(uint64_t pos); // set the 64bit block counter\n\n    /** outputs the keystream of size <bytes> into <c> */\n    void Keystream(unsigned char* c, size_t bytes);\n\n    /** enciphers the message <input> of length <bytes> and write the enciphered representation into <output>\n     *  Used for encryption and decryption (XOR)\n     */\n    void Crypt(const unsigned char* input, unsigned char* output, size_t bytes);\n};\n\n#endif // BITCOIN_CRYPTO_CHACHA20_H\n"
  },
  {
    "path": "src/crypto/common.h",
    "content": "// Copyright (c) 2014-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_COMMON_H\n#define CRYPTO_COMMON_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"compat/endian.h\"\n\nuint16_t static inline ReadLE16(const unsigned char* ptr)\n{\n    uint16_t x;\n    memcpy((char*)&x, ptr, 2);\n    return le16toh(x);\n}\n\nuint32_t static inline ReadLE32(const unsigned char* ptr)\n{\n    uint32_t x;\n    memcpy((char*)&x, ptr, 4);\n    return le32toh(x);\n}\n\nuint64_t static inline ReadLE64(const unsigned char* ptr)\n{\n    uint64_t x;\n    memcpy((char*)&x, ptr, 8);\n    return le64toh(x);\n}\n\nvoid static inline WriteLE16(unsigned char* ptr, uint16_t x)\n{\n    uint16_t v = htole16(x);\n    memcpy(ptr, (char*)&v, 2);\n}\n\nvoid static inline WriteLE32(unsigned char* ptr, uint32_t x)\n{\n    uint32_t v = htole32(x);\n    memcpy(ptr, (char*)&v, 4);\n}\n\nvoid static inline WriteLE64(unsigned char* ptr, uint64_t x)\n{\n    uint64_t v = htole64(x);\n    memcpy(ptr, (char*)&v, 8);\n}\n\nuint16_t static inline ReadBE16(const unsigned char* ptr)\n{\n    uint16_t x;\n    memcpy((char*)&x, ptr, 2);\n    return be16toh(x);\n}\n\nuint32_t static inline ReadBE32(const unsigned char* ptr)\n{\n    uint32_t x;\n    memcpy((char*)&x, ptr, 4);\n    return be32toh(x);\n}\n\nuint64_t static inline ReadBE64(const unsigned char* ptr)\n{\n    uint64_t x;\n    memcpy((char*)&x, ptr, 8);\n    return be64toh(x);\n}\n\nvoid static inline WriteBE32(unsigned char* ptr, uint32_t x)\n{\n    uint32_t v = htobe32(x);\n    memcpy(ptr, (char*)&v, 4);\n}\n\nvoid static inline WriteBE64(unsigned char* ptr, uint64_t x)\n{\n    uint64_t v = htobe64(x);\n    memcpy(ptr, (char*)&v, 8);\n}\n\n/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */\nuint64_t static inline CountBits(uint64_t x)\n{\n#ifdef HAVE_DECL___BUILTIN_CLZL\n    if (sizeof(unsigned long) >= sizeof(uint64_t)) {\n        return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;\n    }\n#endif\n#ifdef HAVE_DECL___BUILTIN_CLZLL\n    if (sizeof(unsigned long long) >= sizeof(uint64_t)) {\n        return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;\n    }\n#endif\n    int ret = 0;\n    while (x) {\n        x >>= 1;\n        ++ret;\n    }\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/city.cpp",
    "content": "// Copyright (c) 2011 Google, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n//\n// CityHash, by Geoff Pike and Jyrki Alakuijala\n//\n// This file provides CityHash64() and related functions.\n//\n// It's probably possible to create even faster hash functions by\n// writing a program that systematically explores some of the space of\n// possible hash functions, by using SIMD instructions, or by\n// compromising on hash quality.\n\n#include \"city.h\"\n\n#include <algorithm>\n#include <string.h>  // for memcpy and memset\n\nusing namespace std;\n\nstatic uint64 UNALIGNED_LOAD64(const char *p) {\n  uint64 result;\n  memcpy(&result, p, sizeof(result));\n  return result;\n}\n\nstatic uint32 UNALIGNED_LOAD32(const char *p) {\n  uint32 result;\n  memcpy(&result, p, sizeof(result));\n  return result;\n}\n\n#ifdef _MSC_VER\n\n#include <stdlib.h>\n#define bswap_32(x) _byteswap_ulong(x)\n#define bswap_64(x) _byteswap_uint64(x)\n\n#elif defined(__APPLE__)\n\n// Mac OS X / Darwin features\n#include <libkern/OSByteOrder.h>\n#define bswap_32(x) OSSwapInt32(x)\n#define bswap_64(x) OSSwapInt64(x)\n\n#elif defined(__NetBSD__)\n\n#include <sys/types.h>\n#include <machine/bswap.h>\n#if defined(__BSWAP_RENAME) && !defined(__bswap_32)\n#define bswap_32(x) bswap32(x)\n#define bswap_64(x) bswap64(x)\n#endif\n\n#else\n\n#include <compat/byteswap.h>\n\n#endif\n\n#ifndef HAVE_DLFCN_H\n#include \"cityconfig.h\"\n#endif\n\n#ifdef WORDS_BIGENDIAN\n#define uint32_in_expected_order(x) (bswap_32(x))\n#define uint64_in_expected_order(x) (bswap_64(x))\n#else\n#define uint32_in_expected_order(x) (x)\n#define uint64_in_expected_order(x) (x)\n#endif\n\n#if !defined(LIKELY)\n#ifdef HAVE_BUILTIN_EXPECT\n#define LIKELY(x) (__builtin_expect(!!(x), 1))\n#else\n#define LIKELY(x) (x)\n#endif\n#endif\n\nstatic uint64 Fetch64(const char *p) {\n  return uint64_in_expected_order(UNALIGNED_LOAD64(p));\n}\n\nstatic uint32 Fetch32(const char *p) {\n  return uint32_in_expected_order(UNALIGNED_LOAD32(p));\n}\n\n// Some primes between 2^63 and 2^64 for various uses.\nstatic const uint64 k0 = 0xc3a5c85c97cb3127ULL;\nstatic const uint64 k1 = 0xb492b66fbe98f273ULL;\nstatic const uint64 k2 = 0x9ae16a3b2f90404fULL;\n\n// Magic numbers for 32-bit hashing.  Copied from Murmur3.\nstatic const uint32_t c1 = 0xcc9e2d51;\nstatic const uint32_t c2 = 0x1b873593;\n\n// A 32-bit to 32-bit integer hash copied from Murmur3.\nstatic uint32 fmix(uint32 h)\n{\n  h ^= h >> 16;\n  h *= 0x85ebca6b;\n  h ^= h >> 13;\n  h *= 0xc2b2ae35;\n  h ^= h >> 16;\n  return h;\n}\n\nstatic uint32 Rotate32(uint32 val, int shift) {\n  // Avoid shifting by 32: doing so yields an undefined result.\n  return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));\n}\n\n#undef PERMUTE3\n#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)\n\nstatic uint32 Mur(uint32 a, uint32 h) {\n  // Helper from Murmur3 for combining two 32-bit values.\n  a *= c1;\n  a = Rotate32(a, 17);\n  a *= c2;\n  h ^= a;\n  h = Rotate32(h, 19);\n  return h * 5 + 0xe6546b64;\n}\n\nstatic uint32 Hash32Len13to24(const char *s, size_t len) {\n  uint32 a = Fetch32(s - 4 + (len >> 1));\n  uint32 b = Fetch32(s + 4);\n  uint32 c = Fetch32(s + len - 8);\n  uint32 d = Fetch32(s + (len >> 1));\n  uint32 e = Fetch32(s);\n  uint32 f = Fetch32(s + len - 4);\n  uint32 h = len;\n\n  return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));\n}\n\nstatic uint32 Hash32Len0to4(const char *s, size_t len) {\n  uint32 b = 0;\n  uint32 c = 9;\n  for (size_t i = 0; i < len; i++) {\n    signed char v = s[i];\n    b = b * c1 + v;\n    c ^= b;\n  }\n  return fmix(Mur(b, Mur(len, c)));\n}\n\nstatic uint32 Hash32Len5to12(const char *s, size_t len) {\n  uint32 a = len, b = len * 5, c = 9, d = b;\n  a += Fetch32(s);\n  b += Fetch32(s + len - 4);\n  c += Fetch32(s + ((len >> 1) & 4));\n  return fmix(Mur(c, Mur(b, Mur(a, d))));\n}\n\nuint32 CityHash32(const char *s, size_t len) {\n  if (len <= 24) {\n    return len <= 12 ?\n        (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :\n        Hash32Len13to24(s, len);\n  }\n\n  // len > 24\n  uint32 h = len, g = c1 * len, f = g;\n  uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;\n  uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;\n  uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;\n  uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;\n  uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;\n  h ^= a0;\n  h = Rotate32(h, 19);\n  h = h * 5 + 0xe6546b64;\n  h ^= a2;\n  h = Rotate32(h, 19);\n  h = h * 5 + 0xe6546b64;\n  g ^= a1;\n  g = Rotate32(g, 19);\n  g = g * 5 + 0xe6546b64;\n  g ^= a3;\n  g = Rotate32(g, 19);\n  g = g * 5 + 0xe6546b64;\n  f += a4;\n  f = Rotate32(f, 19);\n  f = f * 5 + 0xe6546b64;\n  size_t iters = (len - 1) / 20;\n  do {\n    uint32 a00 = Rotate32(Fetch32(s) * c1, 17) * c2;\n    uint32 a11 = Fetch32(s + 4);\n    uint32 a22 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;\n    uint32 a33 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;\n    uint32 a44 = Fetch32(s + 16);\n    h ^= a00;\n    h = Rotate32(h, 18);\n    h = h * 5 + 0xe6546b64;\n    f += a11;\n    f = Rotate32(f, 19);\n    f = f * c1;\n    g += a22;\n    g = Rotate32(g, 18);\n    g = g * 5 + 0xe6546b64;\n    h ^= a33 + a11;\n    h = Rotate32(h, 19);\n    h = h * 5 + 0xe6546b64;\n    g ^= a44;\n    g = bswap_32(g) * 5;\n    h += a44 * 5;\n    h = bswap_32(h);\n    f += a00;\n    PERMUTE3(f, h, g);\n    s += 20;\n  } while (--iters != 0);\n  g = Rotate32(g, 11) * c1;\n  g = Rotate32(g, 17) * c1;\n  f = Rotate32(f, 11) * c1;\n  f = Rotate32(f, 17) * c1;\n  h = Rotate32(h + g, 19);\n  h = h * 5 + 0xe6546b64;\n  h = Rotate32(h, 17) * c1;\n  h = Rotate32(h + f, 19);\n  h = h * 5 + 0xe6546b64;\n  h = Rotate32(h, 17) * c1;\n  return h;\n}\n\n// Bitwise right rotate.  Normally this will compile to a single\n// instruction, especially if the shift is a manifest constant.\nstatic uint64 Rotate(uint64 val, int shift) {\n  // Avoid shifting by 64: doing so yields an undefined result.\n  return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));\n}\n\nstatic uint64 ShiftMix(uint64 val) {\n  return val ^ (val >> 47);\n}\n\nstatic uint64 HashLen16(uint64 u, uint64 v) {\n  return Hash128to64(uint128(u, v));\n}\n\nstatic uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {\n  // Murmur-inspired hashing.\n  uint64 a = (u ^ v) * mul;\n  a ^= (a >> 47);\n  uint64 b = (v ^ a) * mul;\n  b ^= (b >> 47);\n  b *= mul;\n  return b;\n}\n\nstatic uint64 HashLen0to16(const char *s, size_t len) {\n  if (len >= 8) {\n    uint64 mul = k2 + len * 2;\n    uint64 a = Fetch64(s) + k2;\n    uint64 b = Fetch64(s + len - 8);\n    uint64 c = Rotate(b, 37) * mul + a;\n    uint64 d = (Rotate(a, 25) + b) * mul;\n    return HashLen16(c, d, mul);\n  }\n  if (len >= 4) {\n    uint64 mul = k2 + len * 2;\n    uint64 a = Fetch32(s);\n    return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);\n  }\n  if (len > 0) {\n    uint8 a = s[0];\n    uint8 b = s[len >> 1];\n    uint8 c = s[len - 1];\n    uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);\n    uint32 z = len + (static_cast<uint32>(c) << 2);\n    return ShiftMix(y * k2 ^ z * k0) * k2;\n  }\n  return k2;\n}\n\n// This probably works well for 16-byte strings as well, but it may be overkill\n// in that case.\nstatic uint64 HashLen17to32(const char *s, size_t len) {\n  uint64 mul = k2 + len * 2;\n  uint64 a = Fetch64(s) * k1;\n  uint64 b = Fetch64(s + 8);\n  uint64 c = Fetch64(s + len - 8) * mul;\n  uint64 d = Fetch64(s + len - 16) * k2;\n  return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d,\n                   a + Rotate(b + k2, 18) + c, mul);\n}\n\n// Return a 16-byte hash for 48 bytes.  Quick and dirty.\n// Callers do best to use \"random-looking\" values for a and b.\nstatic pair<uint64, uint64> WeakHashLen32WithSeeds(\n    uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) {\n  a += w;\n  b = Rotate(b + a + z, 21);\n  uint64 c = a;\n  a += x;\n  a += y;\n  b += Rotate(a, 44);\n  return pair(a + z, b + c);\n}\n\n// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.\nstatic pair<uint64, uint64> WeakHashLen32WithSeeds(\n    const char* s, uint64 a, uint64 b) {\n  return WeakHashLen32WithSeeds(Fetch64(s),\n                                Fetch64(s + 8),\n                                Fetch64(s + 16),\n                                Fetch64(s + 24),\n                                a,\n                                b);\n}\n\n// Return an 8-byte hash for 33 to 64 bytes.\nstatic uint64 HashLen33to64(const char *s, size_t len) {\n  uint64 mul = k2 + len * 2;\n  uint64 a = Fetch64(s) * k2;\n  uint64 b = Fetch64(s + 8);\n  uint64 c = Fetch64(s + len - 24);\n  uint64 d = Fetch64(s + len - 32);\n  uint64 e = Fetch64(s + 16) * k2;\n  uint64 f = Fetch64(s + 24) * 9;\n  uint64 g = Fetch64(s + len - 8);\n  uint64 h = Fetch64(s + len - 16) * mul;\n  uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;\n  uint64 v = ((a + g) ^ d) + f + 1;\n  uint64 w = bswap_64((u + v) * mul) + h;\n  uint64 x = Rotate(e + f, 42) + c;\n  uint64 y = (bswap_64((v + w) * mul) + g) * mul;\n  uint64 z = e + f + c;\n  a = bswap_64((x + z) * mul + y) + b;\n  b = ShiftMix((z + a) * mul + d + h) * mul;\n  return b + x;\n}\n\nuint64 CityHash64(const char *s, size_t len) {\n  if (len <= 32) {\n    if (len <= 16) {\n      return HashLen0to16(s, len);\n    } else {\n      return HashLen17to32(s, len);\n    }\n  } else if (len <= 64) {\n    return HashLen33to64(s, len);\n  }\n\n  // For strings over 64 bytes we hash the end first, and then as we\n  // loop we keep 56 bytes of state: v, w, x, y, and z.\n  uint64 x = Fetch64(s + len - 40);\n  uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);\n  uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));\n  pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);\n  pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);\n  x = x * k1 + Fetch64(s);\n\n  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.\n  len = (len - 1) & ~static_cast<size_t>(63);\n  do {\n    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;\n    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;\n    x ^= w.second;\n    y += v.first + Fetch64(s + 40);\n    z = Rotate(z + w.first, 33) * k1;\n    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);\n    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));\n    std::swap(z, x);\n    s += 64;\n    len -= 64;\n  } while (len != 0);\n  return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,\n                   HashLen16(v.second, w.second) + x);\n}\n\nuint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) {\n  return CityHash64WithSeeds(s, len, k2, seed);\n}\n\nuint64 CityHash64WithSeeds(const char *s, size_t len,\n                           uint64 seed0, uint64 seed1) {\n  return HashLen16(CityHash64(s, len) - seed0, seed1);\n}\n\n// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings\n// of any length representable in signed long.  Based on City and Murmur.\nstatic uint128 CityMurmur(const char *s, size_t len, uint128 seed) {\n  uint64 a = Uint128Low64(seed);\n  uint64 b = Uint128High64(seed);\n  uint64 c = 0;\n  uint64 d = 0;\n  signed long l = len - 16;\n  if (l <= 0) {  // len <= 16\n    a = ShiftMix(a * k1) * k1;\n    c = b * k1 + HashLen0to16(s, len);\n    d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));\n  } else {  // len > 16\n    c = HashLen16(Fetch64(s + len - 8) + k1, a);\n    d = HashLen16(b + len, c + Fetch64(s + len - 16));\n    a += d;\n    do {\n      a ^= ShiftMix(Fetch64(s) * k1) * k1;\n      a *= k1;\n      b ^= a;\n      c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;\n      c *= k1;\n      d ^= c;\n      s += 16;\n      l -= 16;\n    } while (l > 0);\n  }\n  a = HashLen16(a, c);\n  b = HashLen16(d, b);\n  return uint128(a ^ b, HashLen16(b, a));\n}\n\nuint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {\n  if (len < 128) {\n    return CityMurmur(s, len, seed);\n  }\n\n  // We expect len >= 128 to be the common case.  Keep 56 bytes of state:\n  // v, w, x, y, and z.\n  pair<uint64, uint64> v, w;\n  uint64 x = Uint128Low64(seed);\n  uint64 y = Uint128High64(seed);\n  uint64 z = len * k1;\n  v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);\n  v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);\n  w.first = Rotate(y + z, 35) * k1 + x;\n  w.second = Rotate(x + Fetch64(s + 88), 53) * k1;\n\n  // This is the same inner loop as CityHash64(), manually unrolled.\n  do {\n    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;\n    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;\n    x ^= w.second;\n    y += v.first + Fetch64(s + 40);\n    z = Rotate(z + w.first, 33) * k1;\n    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);\n    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));\n    std::swap(z, x);\n    s += 64;\n    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;\n    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;\n    x ^= w.second;\n    y += v.first + Fetch64(s + 40);\n    z = Rotate(z + w.first, 33) * k1;\n    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);\n    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));\n    std::swap(z, x);\n    s += 64;\n    len -= 128;\n  } while (LIKELY(len >= 128));\n  x += Rotate(v.first + z, 49) * k0;\n  y = y * k0 + Rotate(w.second, 37);\n  z = z * k0 + Rotate(w.first, 27);\n  w.first *= 9;\n  v.first *= k0;\n  // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.\n  for (size_t tail_done = 0; tail_done < len; ) {\n    tail_done += 32;\n    y = Rotate(x + y, 42) * k0 + v.second;\n    w.first += Fetch64(s + len - tail_done + 16);\n    x = x * k0 + w.first;\n    z += w.second + Fetch64(s + len - tail_done);\n    w.second += v.first;\n    v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);\n    v.first *= k0;\n  }\n  // At this point our 56 bytes of state should contain more than\n  // enough information for a strong 128-bit hash.  We use two\n  // different 56-byte-to-8-byte hashes to get a 16-byte final result.\n  x = HashLen16(x, v.first);\n  y = HashLen16(y + z, w.first);\n  return uint128(HashLen16(x + v.second, w.second) + y,\n                 HashLen16(x + w.second, y + v.second));\n}\n\nuint128 CityHash128(const char *s, size_t len) {\n  return len >= 16 ?\n      CityHash128WithSeed(s + 16, len - 16,\n                          uint128(Fetch64(s), Fetch64(s + 8) + k0)) :\n      CityHash128WithSeed(s, len, uint128(k0, k1));\n}\n\n\n"
  },
  {
    "path": "src/crypto/hash/city.h",
    "content": "// Copyright (c) 2011 Google, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n//\n// CityHash, by Geoff Pike and Jyrki Alakuijala\n//\n// http://code.google.com/p/cityhash/\n//\n// This file provides a few functions for hashing strings.  All of them are\n// high-quality functions in the sense that they pass standard tests such\n// as Austin Appleby's SMHasher.  They are also fast.\n//\n// For 64-bit x86 code, on short strings, we don't know of anything faster than\n// CityHash64 that is of comparable quality.  We believe our nearest competitor\n// is Murmur3.  For 64-bit x86 code, CityHash64 is an excellent choice for hash\n// tables and most other hashing (excluding cryptography).\n//\n// For 64-bit x86 code, on long strings, the picture is more complicated.\n// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,\n// CityHashCrc128 appears to be faster than all competitors of comparable\n// quality.  CityHash128 is also good but not quite as fast.  We believe our\n// nearest competitor is Bob Jenkins' Spooky.  We don't have great data for\n// other 64-bit CPUs, but for long strings we know that Spooky is slightly\n// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.\n// Note that CityHashCrc128 is declared in citycrc.h.\n//\n// For 32-bit x86 code, we don't know of anything faster than CityHash32 that\n// is of comparable quality.  We believe our nearest competitor is Murmur3A.\n// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)\n//\n// Functions in the CityHash family are not suitable for cryptography.\n//\n// Please see CityHash's README file for more details on our performance\n// measurements and so on.\n//\n// WARNING: This code has been only lightly tested on big-endian platforms!\n// It is known to work well on little-endian platforms that have a small penalty\n// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.\n// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;\n// bug reports are welcome.\n//\n// By the way, for some hash functions, given strings a and b, the hash\n// of a+b is easily derived from the hashes of a and b.  This property\n// doesn't hold for any hash functions in this file.\n\n#ifndef CITY_HASH_H_\n#define CITY_HASH_H_\n\n#include <stdlib.h>  // for size_t.\n#include <stdint.h>\n#include <utility>\n\ntypedef uint8_t uint8;\ntypedef uint32_t uint32;\ntypedef uint64_t uint64;\ntypedef std::pair<uint64, uint64> uint128;\n\ninline uint64 Uint128Low64(const uint128& x) { return x.first; }\ninline uint64 Uint128High64(const uint128& x) { return x.second; }\n\n// Hash function for a byte array.\nuint64 CityHash64(const char *buf, size_t len);\n\n// Hash function for a byte array.  For convenience, a 64-bit seed is also\n// hashed into the result.\nuint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed);\n\n// Hash function for a byte array.  For convenience, two seeds are also\n// hashed into the result.\nuint64 CityHash64WithSeeds(const char *buf, size_t len, uint64 seed0, uint64 seed1);\n\n// Hash function for a byte array.\nuint128 CityHash128(const char *s, size_t len);\n\n// Hash function for a byte array.  For convenience, a 128-bit seed is also\n// hashed into the result.\nuint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);\n\n// Hash function for a byte array.  Most useful in 32-bit binaries.\nuint32 CityHash32(const char *buf, size_t len);\n\n// Hash 128 input bits down to 64 bits of output.\n// This is intended to be a reasonably good hash function.\ninline uint64 Hash128to64(const uint128& x) {\n  // Murmur-inspired hashing.\n  const uint64 kMul = 0x9ddfea08eb382d69ULL;\n  uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;\n  a ^= (a >> 47);\n  uint64 b = (Uint128High64(x) ^ a) * kMul;\n  b ^= (b >> 47);\n  b *= kMul;\n  return b;\n}\n\n#endif  // CITY_HASH_H_\n"
  },
  {
    "path": "src/crypto/hash/cityconfig.h",
    "content": "/* Define to 1 if the compiler supports __builtin_expect. */\n#define HAVE_BUILTIN_EXPECT\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H\n\n/* Define to 1 if you have the <strings.h> header file. */\n#undef HAVE_STRINGS_H\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n#undef inline\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/hash.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_HASH_HASH_H\n#define CRYPTO_HASH_HASH_H\n\n#include <hash.h>\n#include <uint256.h>\n#include \"crypto/hash/scrypt.h\"\n#include \"crypto/hash/city.h\"\n\ninline void hash_sha256(const void* pData, unsigned int size, unsigned char* hash)\n{\n    CSHA256 sha;\n    sha.Write((unsigned char*)pData, size);\n    sha.Finalize((unsigned char*)hash);\n}\n\ninline void hash_sha256(const void* pData, unsigned int size, arith_uint256& thash)\n{\n    CSHA256 sha;\n    sha.Write((unsigned char*)pData, size);\n    sha.Finalize((unsigned char*)&thash);\n}\n\ninline void hash_city(const void* pData, arith_uint256& thash)\n{\n    //For testing purposes\n    uint128 temphash =  CityHash128((char*)pData, 80);\n    thash |= temphash.first;\n    thash <<= 64;\n    thash |= temphash.second;\n    thash <<= 64;\n    temphash = CityHash128((char*)ArithToUint256(thash).begin(), 32);\n    thash |= temphash.first;\n    thash <<= 64;\n    thash |= temphash.second;\n}\n\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/scrypt-sse2.cpp",
    "content": "/*\n * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * This file was originally written by Colin Percival as part of the Tarsnap\n * online backup system.\n */\n\n#include \"scrypt.h\"\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <openssl/sha.h>\n\n#include <emmintrin.h>\n#include <compat/endian.h>\n\nstatic inline void xor_salsa8_sse2(__m128i B[4], const __m128i Bx[4])\n{\n\t__m128i X0, X1, X2, X3;\n\t__m128i T;\n\tint i;\n\n\tX0 = B[0] = _mm_xor_si128(B[0], Bx[0]);\n\tX1 = B[1] = _mm_xor_si128(B[1], Bx[1]);\n\tX2 = B[2] = _mm_xor_si128(B[2], Bx[2]);\n\tX3 = B[3] = _mm_xor_si128(B[3], Bx[3]);\n\n\tfor (i = 0; i < 8; i += 2) {\n\t\t/* Operate on \"columns\". */\n\t\tT = _mm_add_epi32(X0, X3);\n\t\tX1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));\n\t\tX1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));\n\t\tT = _mm_add_epi32(X1, X0);\n\t\tX2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));\n\t\tX2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));\n\t\tT = _mm_add_epi32(X2, X1);\n\t\tX3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));\n\t\tX3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));\n\t\tT = _mm_add_epi32(X3, X2);\n\t\tX0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));\n\t\tX0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));\n\n\t\t/* Rearrange data. */\n\t\tX1 = _mm_shuffle_epi32(X1, 0x93);\n\t\tX2 = _mm_shuffle_epi32(X2, 0x4E);\n\t\tX3 = _mm_shuffle_epi32(X3, 0x39);\n\n\t\t/* Operate on \"rows\". */\n\t\tT = _mm_add_epi32(X0, X1);\n\t\tX3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));\n\t\tX3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));\n\t\tT = _mm_add_epi32(X3, X0);\n\t\tX2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));\n\t\tX2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));\n\t\tT = _mm_add_epi32(X2, X3);\n\t\tX1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));\n\t\tX1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));\n\t\tT = _mm_add_epi32(X1, X2);\n\t\tX0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));\n\t\tX0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));\n\n\t\t/* Rearrange data. */\n\t\tX1 = _mm_shuffle_epi32(X1, 0x39);\n\t\tX2 = _mm_shuffle_epi32(X2, 0x4E);\n\t\tX3 = _mm_shuffle_epi32(X3, 0x93);\n\t}\n\n\tB[0] = _mm_add_epi32(B[0], X0);\n\tB[1] = _mm_add_epi32(B[1], X1);\n\tB[2] = _mm_add_epi32(B[2], X2);\n\tB[3] = _mm_add_epi32(B[3], X3);\n}\n\nvoid scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad)\n{\n\tuint8_t B[128];\n\tunion {\n\t\t__m128i i128[8];\n\t\tuint32_t u32[32];\n\t} X;\n\t__m128i *V;\n\tuint32_t i, j, k;\n\n\tV = (__m128i *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63));\n\n\tPBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128);\n\n\tfor (k = 0; k < 2; k++) {\n\t\tfor (i = 0; i < 16; i++) {\n\t\t\tX.u32[k * 16 + i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);\n\t\t}\n\t}\n\n\tfor (i = 0; i < 1024; i++) {\n\t\tfor (k = 0; k < 8; k++)\n\t\t\tV[i * 8 + k] = X.i128[k];\n\t\txor_salsa8_sse2(&X.i128[0], &X.i128[4]);\n\t\txor_salsa8_sse2(&X.i128[4], &X.i128[0]);\n\t}\n\tfor (i = 0; i < 1024; i++) {\n\t\tj = 8 * (X.u32[16] & 1023);\n\t\tfor (k = 0; k < 8; k++)\n\t\t\tX.i128[k] = _mm_xor_si128(X.i128[k], V[j + k]);\n\t\txor_salsa8_sse2(&X.i128[0], &X.i128[4]);\n\t\txor_salsa8_sse2(&X.i128[4], &X.i128[0]);\n\t}\n\n\tfor (k = 0; k < 2; k++) {\n\t\tfor (i = 0; i < 16; i++) {\n\t\t\tle32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X.u32[k * 16 + i]);\n\t\t}\n\t}\n\n\tPBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32);\n}\n"
  },
  {
    "path": "src/crypto/hash/scrypt.cpp",
    "content": "/*\n * Copyright 2009 Colin Percival, 2011 ArtForz, 2012-2013 pooler\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * This file was originally written by Colin Percival as part of the Tarsnap\n * online backup system.\n */\n\n#include \"scrypt.h\"\n#include \"util.h\"\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <openssl/sha.h>\n#include <compat/endian.h>\n\n#if defined(USE_SSE2) && !defined(USE_SSE2_ALWAYS)\n#ifdef _MSC_VER\n// MSVC 64bit is unable to use inline asm\n#include <intrin.h>\n#else\n// GCC Linux or i686-w64-mingw32\n#include <cpuid.h>\n#endif\n#endif\n\n#define ROTL(a, b) (((a) << (b)) | ((a) >> (32 - (b))))\n\nstatic inline void xor_salsa8(uint32_t B[16], const uint32_t Bx[16])\n{\n\tuint32_t x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15;\n\tint i;\n\n\tx00 = (B[ 0] ^= Bx[ 0]);\n\tx01 = (B[ 1] ^= Bx[ 1]);\n\tx02 = (B[ 2] ^= Bx[ 2]);\n\tx03 = (B[ 3] ^= Bx[ 3]);\n\tx04 = (B[ 4] ^= Bx[ 4]);\n\tx05 = (B[ 5] ^= Bx[ 5]);\n\tx06 = (B[ 6] ^= Bx[ 6]);\n\tx07 = (B[ 7] ^= Bx[ 7]);\n\tx08 = (B[ 8] ^= Bx[ 8]);\n\tx09 = (B[ 9] ^= Bx[ 9]);\n\tx10 = (B[10] ^= Bx[10]);\n\tx11 = (B[11] ^= Bx[11]);\n\tx12 = (B[12] ^= Bx[12]);\n\tx13 = (B[13] ^= Bx[13]);\n\tx14 = (B[14] ^= Bx[14]);\n\tx15 = (B[15] ^= Bx[15]);\n\tfor (i = 0; i < 8; i += 2) {\n\t\t/* Operate on columns. */\n\t\tx04 ^= ROTL(x00 + x12,  7);  x09 ^= ROTL(x05 + x01,  7);\n\t\tx14 ^= ROTL(x10 + x06,  7);  x03 ^= ROTL(x15 + x11,  7);\n\n\t\tx08 ^= ROTL(x04 + x00,  9);  x13 ^= ROTL(x09 + x05,  9);\n\t\tx02 ^= ROTL(x14 + x10,  9);  x07 ^= ROTL(x03 + x15,  9);\n\n\t\tx12 ^= ROTL(x08 + x04, 13);  x01 ^= ROTL(x13 + x09, 13);\n\t\tx06 ^= ROTL(x02 + x14, 13);  x11 ^= ROTL(x07 + x03, 13);\n\n\t\tx00 ^= ROTL(x12 + x08, 18);  x05 ^= ROTL(x01 + x13, 18);\n\t\tx10 ^= ROTL(x06 + x02, 18);  x15 ^= ROTL(x11 + x07, 18);\n\n\t\t/* Operate on rows. */\n\t\tx01 ^= ROTL(x00 + x03,  7);  x06 ^= ROTL(x05 + x04,  7);\n\t\tx11 ^= ROTL(x10 + x09,  7);  x12 ^= ROTL(x15 + x14,  7);\n\n\t\tx02 ^= ROTL(x01 + x00,  9);  x07 ^= ROTL(x06 + x05,  9);\n\t\tx08 ^= ROTL(x11 + x10,  9);  x13 ^= ROTL(x12 + x15,  9);\n\n\t\tx03 ^= ROTL(x02 + x01, 13);  x04 ^= ROTL(x07 + x06, 13);\n\t\tx09 ^= ROTL(x08 + x11, 13);  x14 ^= ROTL(x13 + x12, 13);\n\n\t\tx00 ^= ROTL(x03 + x02, 18);  x05 ^= ROTL(x04 + x07, 18);\n\t\tx10 ^= ROTL(x09 + x08, 18);  x15 ^= ROTL(x14 + x13, 18);\n\t}\n\tB[ 0] += x00;\n\tB[ 1] += x01;\n\tB[ 2] += x02;\n\tB[ 3] += x03;\n\tB[ 4] += x04;\n\tB[ 5] += x05;\n\tB[ 6] += x06;\n\tB[ 7] += x07;\n\tB[ 8] += x08;\n\tB[ 9] += x09;\n\tB[10] += x10;\n\tB[11] += x11;\n\tB[12] += x12;\n\tB[13] += x13;\n\tB[14] += x14;\n\tB[15] += x15;\n}\n\nvoid scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad)\n{\n\tuint8_t B[128];\n\tuint32_t X[32];\n\tuint32_t *V;\n\tuint32_t i, j, k;\n\n\tV = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63));\n\n\tPBKDF2_SHA256((const uint8_t *)input, 80, (const uint8_t *)input, 80, 1, B, 128);\n\n\tfor (k = 0; k < 32; k++)\n\t\tX[k] = le32dec(&B[4 * k]);\n\n\tfor (i = 0; i < 1024; i++) {\n\t\tmemcpy(&V[i * 32], X, 128);\n\t\txor_salsa8(&X[0], &X[16]);\n\t\txor_salsa8(&X[16], &X[0]);\n\t}\n\tfor (i = 0; i < 1024; i++) {\n\t\tj = 32 * (X[16] & 1023);\n\t\tfor (k = 0; k < 32; k++)\n\t\t\tX[k] ^= V[j + k];\n\t\txor_salsa8(&X[0], &X[16]);\n\t\txor_salsa8(&X[16], &X[0]);\n\t}\n\n\tfor (k = 0; k < 32; k++)\n\t\tle32enc(&B[4 * k], X[k]);\n\n\tPBKDF2_SHA256((const uint8_t *)input, 80, B, 128, 1, (uint8_t *)output, 32);\n}\n\n#if defined(USE_SSE2)\n// By default, set to generic scrypt function. This will prevent crash in case when scrypt_detect_sse2() wasn't called\nvoid (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad) = &scrypt_1024_1_1_256_sp_generic;\n\nvoid scrypt_detect_sse2()\n{\n#if defined(USE_SSE2_ALWAYS)\n    printf(\"scrypt: using scrypt-sse2 as built.\\n\");\n#else // USE_SSE2_ALWAYS\n    // 32bit x86 Linux or Windows, detect cpuid features\n    unsigned int cpuid_edx=0;\n#if defined(_MSC_VER)\n    // MSVC\n    int x86cpuid[4];\n    __cpuid(x86cpuid, 1);\n    cpuid_edx = (unsigned int)buffer[3];\n#else // _MSC_VER\n    // Linux or i686-w64-mingw32 (gcc-4.6.3)\n    unsigned int eax, ebx, ecx;\n    __get_cpuid(1, &eax, &ebx, &ecx, &cpuid_edx);\n#endif // _MSC_VER\n\n    if (cpuid_edx & 1<<26)\n    {\n        scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_sse2;\n        printf(\"scrypt: using scrypt-sse2 as detected.\\n\");\n    }\n    else\n    {\n        scrypt_1024_1_1_256_sp_detected = &scrypt_1024_1_1_256_sp_generic;\n        printf(\"scrypt: using scrypt-generic, SSE2 unavailable.\\n\");\n    }\n#endif // USE_SSE2_ALWAYS\n}\n#endif\n\nvoid scrypt_1024_1_1_256(const char *input, char *output)\n{\n\tchar scratchpad[SCRYPT_SCRATCHPAD_SIZE];\n    scrypt_1024_1_1_256_sp(input, output, scratchpad);\n}\n\n\n\n#include <openssl/evp.h>\n\nvoid PBKDF2_SHA512(const char* pass, size_t passwdlen, const unsigned char* salt,  size_t saltlen, int32_t iterations, unsigned char* digest, uint32_t outputbytes)\n{\n    PKCS5_PBKDF2_HMAC(pass, passwdlen, salt, saltlen, iterations, EVP_sha512(), outputbytes, digest);\n}\n\n\n"
  },
  {
    "path": "src/crypto/hash/scrypt.h",
    "content": "#ifndef SCRYPT_H\n#define SCRYPT_H\n#include <stdlib.h>\n#include <stdint.h>\n\nstatic const int SCRYPT_SCRATCHPAD_SIZE = 131072 + 63;\n\nvoid scrypt_1024_1_1_256(const char *input, char *output);\nvoid scrypt_1024_1_1_256_sp_generic(const char *input, char *output, char *scratchpad);\n\n#if defined(USE_SSE2)\n#if defined(_M_X64) || defined(__x86_64__) || defined(_M_AMD64) || (defined(MAC_OSX) && defined(__i386__))\n#define USE_SSE2_ALWAYS 1\n#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_sse2((input), (output), (scratchpad))\n#else\n#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_detected((input), (output), (scratchpad))\n#endif\n\nvoid scrypt_detect_sse2();\nvoid scrypt_1024_1_1_256_sp_sse2(const char *input, char *output, char *scratchpad);\nextern void (*scrypt_1024_1_1_256_sp_detected)(const char *input, char *output, char *scratchpad);\n#else\n#define scrypt_1024_1_1_256_sp(input, output, scratchpad) scrypt_1024_1_1_256_sp_generic((input), (output), (scratchpad))\n#endif\n\nvoid PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen);\n\nvoid PBKDF2_SHA512(const char* pass, size_t passwdlen, const unsigned char* salt,  size_t saltlen, int32_t iterations, unsigned char* digest, uint32_t outputbytes);\n\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/README.md",
    "content": "This directory contains SIGMA and several component hash functions (argon/echo/shavite) that form parts of SIGMA.\nNB! The implementations of these hash functions have been specifically tailored to SIGMAs specific use case. Assumptions are made about their operating conditions (operating on already publically known data; not needing to be concerned about side channel attacks and various other things)\nThey are not appropriate for and should not be reused for other cryptographic purposes (even within the Munt code base), but rather a regular/different implementation should be used in their place.\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/argon2.cpp",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"argon_echo.h\"\n#include \"core.h\"\n\n#if defined(ARGON2_CORE_OPT_IMPL) || defined(ARGON2_CORE_REF_IMPL)\nint argon2_echo_ctx(argon2_echo_context *context, bool doHash)\n{\n    /* 1. Validate all inputs */\n    int result = validate_inputs(context);\n    uint32_t memory_blocks, segment_length;\n    argon2_echo_instance_t instance;\n\n    if (ARGON2_OK != result)\n    {\n        return result;\n    }\n\n    /* 2. Align memory size */\n    /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */\n    memory_blocks = context->m_cost;\n\n    if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes)\n    {\n        memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;\n    }\n\n    segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);\n    /* Ensure that all segments have equal length */\n    memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);\n\n    instance.memory = NULL;\n    instance.passes = context->t_cost;\n    instance.memory_blocks = memory_blocks;\n    instance.segment_length = segment_length;\n    instance.lane_length = segment_length * ARGON2_SYNC_POINTS;\n    instance.lanes = context->lanes;\n    instance.threads = context->threads;\n\n    if (instance.threads > instance.lanes)\n    {\n        instance.threads = instance.lanes;\n    }\n\n    /* 3. Initialization: Hashing inputs, allocating memory, filling first\n     * blocks\n     */\n    result = initialize(&instance, context);\n\n    if (ARGON2_OK != result)\n    {\n        return result;\n    }\n\n    /* 4. Filling memory */\n    result = fill_memory_blocks(&instance);\n\n    if (ARGON2_OK != result)\n    {\n        return result;\n    }\n\n    /* 5. Finalization */\n    //NB! We only bother to finalize if we are interested in the actual hash (doHash=true)\n    //If we are only using argon to fill memory (doHash=false) then we don't actually care about the resulting hash.\n    if (doHash)\n    {\n        finalize(context, &instance);\n    }\n    \n    return ARGON2_OK;\n}\n\n#else\n\nconst char *argon2_echo_error_message(int error_code)\n{\n    switch (error_code)\n    {\n        case ARGON2_OK:\n            return \"OK\";\n        case ARGON2_OUTPUT_PTR_NULL:\n            return \"Output pointer is NULL\";\n        case ARGON2_OUTPUT_TOO_SHORT:\n            return \"Output is too short\";\n        case ARGON2_OUTPUT_TOO_LONG:\n            return \"Output is too long\";\n        case ARGON2_PWD_TOO_SHORT:\n            return \"Password is too short\";\n        case ARGON2_PWD_TOO_LONG:\n            return \"Password is too long\";\n        case ARGON2_TIME_TOO_SMALL:\n            return \"Time cost is too small\";\n        case ARGON2_TIME_TOO_LARGE:\n            return \"Time cost is too large\";\n        case ARGON2_MEMORY_TOO_LITTLE:\n            return \"Memory cost is too small\";\n        case ARGON2_MEMORY_TOO_MUCH:\n            return \"Memory cost is too large\";\n        case ARGON2_LANES_TOO_FEW:\n            return \"Too few lanes\";\n        case ARGON2_LANES_TOO_MANY:\n            return \"Too many lanes\";\n        case ARGON2_PWD_PTR_MISMATCH:\n            return \"Password pointer is NULL, but password length is not 0\";\n        case ARGON2_MEMORY_ALLOCATION_ERROR:\n            return \"Memory allocation error\";\n        case ARGON2_INCORRECT_PARAMETER:\n            return \"Context is NULL\";\n        case ARGON2_THREADS_TOO_FEW:\n            return \"Not enough threads\";\n        case ARGON2_THREADS_TOO_MANY:\n            return \"Too many threads\";\n        case ARGON2_MISSING_ARGS:\n            return \"Missing arguments\";\n        case ARGON2_THREAD_FAIL:\n            return \"Threading failure\";\n        default:\n            return \"Unknown error code\";\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/argon_echo.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n\n\n\n#ifndef ARGON2_CORE_OPT_IMPL\n#ifndef ARGON2_ECHO_H\n#define ARGON2_ECHO_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <limits.h>\n#include <stdlib.h>\n#include <array>\n#include <compat/arch.h>\n\n/*\n * Argon2 input parameter restrictions\n */\n/* Minimum and maximum number of lanes (degree of parallelism) */\n#define ARGON2_MIN_LANES UINT32_C(1)\n#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF)\n\n/* Minimum and maximum number of threads */\n#define ARGON2_MIN_THREADS UINT32_C(1)\n#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF)\n\n/* Number of synchronization points between lanes per pass */\n#define ARGON2_SYNC_POINTS UINT32_C(4)\n\n/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */\n#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */\n\n#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))\n/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */\n#define ARGON2_MAX_MEMORY_BITS ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1))\n#define ARGON2_MAX_MEMORY ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)\n\n/* Minimum and maximum number of passes */\n#define ARGON2_MIN_TIME UINT32_C(1)\n#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF)\n\n/* Minimum and maximum password length in bytes */\n#define ARGON2_MIN_PWD_LENGTH UINT32_C(1)\n#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF)\n\n/* Flags to determine which fields are securely wiped (default = no wipe). */\n#define ARGON2_DEFAULT_FLAGS UINT32_C(0)\n#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0)\n#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)\n\n/* Error codes */\nenum argon2_error_codes\n{\n    ARGON2_OK = 0,\n    ARGON2_OUTPUT_PTR_NULL = -1,\n    ARGON2_OUTPUT_TOO_SHORT = -2,\n    ARGON2_OUTPUT_TOO_LONG = -3,\n    ARGON2_PWD_TOO_SHORT = -4,\n    ARGON2_PWD_TOO_LONG = -5,\n    ARGON2_TIME_TOO_SMALL = -12,\n    ARGON2_TIME_TOO_LARGE = -13,\n    ARGON2_MEMORY_TOO_LITTLE = -14,\n    ARGON2_MEMORY_TOO_MUCH = -15,\n    ARGON2_LANES_TOO_FEW = -16,\n    ARGON2_LANES_TOO_MANY = -17,\n    ARGON2_PWD_PTR_MISMATCH = -18,    /* NULL ptr with non-zero length */\n    ARGON2_MEMORY_ALLOCATION_ERROR = -22,\n    ARGON2_INCORRECT_PARAMETER = -25,\n    ARGON2_THREADS_TOO_FEW = -28,\n    ARGON2_THREADS_TOO_MANY = -29,\n    ARGON2_MISSING_ARGS = -30,\n    ARGON2_THREAD_FAIL = -33\n};\n\n/* Argon2 external data structures */\n/*\n * Context: structure to hold Argon2 inputs:\n *  output array and its length,\n *  password and its length,\n *  number of passes, amount of used memory (in KBytes, can be rounded up a bit)\n *  number of parallel threads that will be run.\n */\nstruct argon2_echo_context\n{\n    uint8_t* pwd;    /* password array */\n    uint32_t pwdlen; /* password length */\n\n    std::array<uint64_t, 4> outHash;\n\n    uint32_t t_cost;  /* number of passes */\n    uint32_t m_cost;  /* amount of memory requested (KB) */\n    uint32_t lanes;   /* number of lanes */\n    uint32_t threads; /* maximum number of threads */\n\n    uint32_t version; /* version number */\n\n    uint8_t* allocated_memory; /* pointer to pre-allocated memory */\n};\n\nextern int (*selected_argon2_echo_hash)(argon2_echo_context* context, bool doHash);\n\n/**\n * Get the associated error message for given error code\n * @return  The error message associated with the given error code\n */\nconst char* argon2_echo_error_message(int error_code);\n\n#include \"opt/core_opt_hybrid.h\"\n//fixme: (SIGMA) - Implement sse2 (we have argon version but not echo etc.)\n//#include \"opt/core_opt_sse2.h\"\n//#include \"opt/core_opt_sse2_aes.h\"\n#ifdef ARCH_CPU_X86_FAMILY\n#include \"opt/core_opt_sse3.h\"\n#include \"opt/core_opt_sse3_aes.h\"\n#include \"opt/core_opt_sse4.h\"\n#include \"opt/core_opt_sse4_aes.h\"\n#include \"opt/core_opt_avx.h\"\n#include \"opt/core_opt_avx_aes.h\"\n#include \"opt/core_opt_avx2.h\"\n#include \"opt/core_opt_avx2_aes.h\"\n#include \"opt/core_opt_avx512f.h\"\n#include \"opt/core_opt_avx512f_aes.h\"\n#endif\n\n#ifdef ARCH_CPU_ARM_FAMILY\n#include \"opt/core_opt_arm_cortex_a53.h\"\n#include \"opt/core_opt_arm_cortex_a53_aes.h\"\n#include \"opt/core_opt_arm_cortex_a57.h\"\n#include \"opt/core_opt_arm_cortex_a57_aes.h\"\n#include \"opt/core_opt_arm_cortex_a72.h\"\n#include \"opt/core_opt_arm_cortex_a72_aes.h\"\n#include \"opt/core_opt_arm_thunderx_aes.h\"\n#endif\n\nint argon2_echo_ctx_ref(argon2_echo_context* context, bool doHash);\n#endif\n#else\n/*\n * Function that performs memory-hard hashing with certain degree of parallelism\n * @param  context  Pointer to the Argon2 internal structure\n * @return Error code if smth is wrong, ARGON2_OK otherwise\n */\nint argon2_echo_ctx(argon2_echo_context* context, bool doHash);\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blake2-impl.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef PORTABLE_BLAKE2_IMPL_H\n#define PORTABLE_BLAKE2_IMPL_H\n\n#include <stdint.h>\n#include <string.h>\n\n#if defined(_MSC_VER)\n#define BLAKE2_INLINE __inline\n#elif defined(__GNUC__) || defined(__clang__)\n#define BLAKE2_INLINE __inline__\n#else\n#define BLAKE2_INLINE\n#endif\n\n/* Argon2 Team - Begin Code */\n/*\n   Not an exhaustive list, but should cover the majority of modern platforms\n   Additionally, the code will always be correct---this is only a performance\n   tweak.\n*/\n#if (defined(__BYTE_ORDER__) &&                                                \\\n     (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) ||                           \\\n    defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \\\n    defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) ||       \\\n    defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) ||                \\\n    defined(_M_ARM)\n#define NATIVE_LITTLE_ENDIAN\n#endif\n/* Argon2 Team - End Code */\n\nstatic BLAKE2_INLINE uint32_t load32(const void *src)\n{\n#if defined(NATIVE_LITTLE_ENDIAN)\n    uint32_t w;\n    memcpy(&w, src, sizeof w);\n    return w;\n#else\n    const uint8_t *p = (const uint8_t *)src;\n    uint32_t w = *p++;\n    w |= (uint32_t)(*p++) << 8;\n    w |= (uint32_t)(*p++) << 16;\n    w |= (uint32_t)(*p++) << 24;\n    return w;\n#endif\n}\n\nstatic BLAKE2_INLINE uint64_t load64(const void *src)\n{\n#if defined(NATIVE_LITTLE_ENDIAN)\n    uint64_t w;\n    memcpy(&w, src, sizeof w);\n    return w;\n#else\n    const uint8_t *p = (const uint8_t *)src;\n    uint64_t w = *p++;\n    w |= (uint64_t)(*p++) << 8;\n    w |= (uint64_t)(*p++) << 16;\n    w |= (uint64_t)(*p++) << 24;\n    w |= (uint64_t)(*p++) << 32;\n    w |= (uint64_t)(*p++) << 40;\n    w |= (uint64_t)(*p++) << 48;\n    w |= (uint64_t)(*p++) << 56;\n    return w;\n#endif\n}\n\nstatic BLAKE2_INLINE void store32(void *dst, uint32_t w)\n{\n#if defined(NATIVE_LITTLE_ENDIAN)\n    memcpy(dst, &w, sizeof w);\n#else\n    uint8_t *p = (uint8_t *)dst;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n#endif\n}\n\nstatic BLAKE2_INLINE void store64(void *dst, uint64_t w)\n{\n#if defined(NATIVE_LITTLE_ENDIAN)\n    memcpy(dst, &w, sizeof w);\n#else\n    uint8_t *p = (uint8_t *)dst;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n#endif\n}\n\nstatic BLAKE2_INLINE uint64_t load48(const void *src)\n{\n    const uint8_t *p = (const uint8_t *)src;\n    uint64_t w = *p++;\n    w |= (uint64_t)(*p++) << 8;\n    w |= (uint64_t)(*p++) << 16;\n    w |= (uint64_t)(*p++) << 24;\n    w |= (uint64_t)(*p++) << 32;\n    w |= (uint64_t)(*p++) << 40;\n    return w;\n}\n\nstatic BLAKE2_INLINE void store48(void *dst, uint64_t w)\n{\n    uint8_t *p = (uint8_t *)dst;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n    w >>= 8;\n    *p++ = (uint8_t)w;\n}\n\nstatic BLAKE2_INLINE uint32_t rotr32(const uint32_t w, const unsigned c)\n{\n    return (w >> c) | (w << (32 - c));\n}\n\nstatic BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c)\n{\n    return (w >> c) | (w << (64 - c));\n}\n\nvoid clear_internal_memory(void *v, size_t n);\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blake2.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef PORTABLE_BLAKE2_H\n#define PORTABLE_BLAKE2_H\n\n#include \"../argon_echo.h\"\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n\nenum blake2b_constant\n{\n    BLAKE2B_BLOCKBYTES = 128,\n    BLAKE2B_OUTBYTES = 64,\n    BLAKE2B_KEYBYTES = 64,\n    BLAKE2B_SALTBYTES = 16,\n    BLAKE2B_PERSONALBYTES = 16\n};\n\n#pragma pack(push, 1)\ntypedef struct __blake2b_param\n{\n    uint8_t digest_length;                   /* 1 */\n    uint8_t key_length;                      /* 2 */\n    uint8_t fanout;                          /* 3 */\n    uint8_t depth;                           /* 4 */\n    uint32_t leaf_length;                    /* 8 */\n    uint64_t node_offset;                    /* 16 */\n    uint8_t node_depth;                      /* 17 */\n    uint8_t inner_length;                    /* 18 */\n    uint8_t reserved[14];                    /* 32 */\n    uint8_t salt[BLAKE2B_SALTBYTES];         /* 48 */\n    uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */\n} blake2b_param;\n#pragma pack(pop)\n\ntypedef struct __blake2b_state\n{\n    uint64_t h[8];\n    uint64_t t[2];\n    uint64_t f[2];\n    uint8_t buf[BLAKE2B_BLOCKBYTES];\n    unsigned buflen;\n    unsigned outlen;\n    uint8_t last_node;\n} blake2b_state;\n\n/* Ensure param structs have not been wrongly padded */\n/* Poor man's static_assert */\nenum\n{\n    blake2_size_check_0 = 1 / !!(CHAR_BIT == 8),\n    blake2_size_check_2 = 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT)\n};\n\n/* Streaming API */\nint blake2b_init(blake2b_state *S, size_t outlen);\nint blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen);\nint blake2b_init_param(blake2b_state *S, const blake2b_param *P);\nint blake2b_update(blake2b_state *S, const void *in, size_t inlen);\nint blake2b_final(blake2b_state *S, void *out, size_t outlen);\n\n/* Simple API */\nint blake2b(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen);\n\n/* Argon2 Team - Begin Code */\nint blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);\n/* Argon2 Team - End Code */\n\n#if defined(__cplusplus)\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blake2b.cpp",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <stdint.h>\n#include <string.h>\n#include <stdio.h>\n\n#include \"blake2.h\"\n#include \"blake2-impl.h\"\n\nstatic const uint64_t blake2b_IV[8] = {\n    UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),\n    UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),\n    UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f),\n    UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)};\n\nstatic const unsigned int blake2b_sigma[12][16] = {\n    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},\n    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},\n    {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},\n    {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},\n    {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},\n    {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},\n    {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},\n    {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},\n    {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},\n    {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},\n    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},\n    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},\n};\n\nstatic BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S)\n{\n    S->f[1] = (uint64_t)-1;\n}\n\nstatic BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S)\n{\n    if (S->last_node)\n    {\n        blake2b_set_lastnode(S);\n    }\n    S->f[0] = (uint64_t)-1;\n}\n\nstatic BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S, uint64_t inc)\n{\n    S->t[0] += inc;\n    S->t[1] += (S->t[0] < inc);\n}\n\nstatic BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S)\n{\n    memset(S, 0, sizeof(*S));      /* wipe */\n    blake2b_set_lastblock(S); /* invalidate for further use */\n}\n\nstatic BLAKE2_INLINE void blake2b_init0(blake2b_state *S)\n{\n    memset(S, 0, sizeof(*S));\n    memcpy(S->h, blake2b_IV, sizeof(S->h));\n}\n\nint blake2b_init_param(blake2b_state *S, const blake2b_param *P)\n{\n    const unsigned char *p = (const unsigned char *)P;\n    unsigned int i;\n\n    if (NULL == P || NULL == S)\n    {\n        return -1;\n    }\n\n    blake2b_init0(S);\n    /* IV XOR Parameter Block */\n    for (i = 0; i < 8; ++i)\n    {\n        S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);\n    }\n    S->outlen = P->digest_length;\n    return 0;\n}\n\n/* Sequential blake2b initialization */\nint blake2b_init(blake2b_state *S, size_t outlen)\n{\n    blake2b_param P;\n\n    if (S == NULL) {\n        return -1;\n    }\n\n    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES))\n    {\n        blake2b_invalidate_state(S);\n        return -1;\n    }\n\n    /* Setup Parameter Block for unkeyed BLAKE2 */\n    P.digest_length = (uint8_t)outlen;\n    P.key_length = 0;\n    P.fanout = 1;\n    P.depth = 1;\n    P.leaf_length = 0;\n    P.node_offset = 0;\n    P.node_depth = 0;\n    P.inner_length = 0;\n    memset(P.reserved, 0, sizeof(P.reserved));\n    memset(P.salt, 0, sizeof(P.salt));\n    memset(P.personal, 0, sizeof(P.personal));\n\n    return blake2b_init_param(S, &P);\n}\n\nint blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen)\n{\n    blake2b_param P;\n\n    if (S == NULL) {\n        return -1;\n    }\n\n    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES))\n    {\n        blake2b_invalidate_state(S);\n        return -1;\n    }\n\n    if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES))\n    {\n        blake2b_invalidate_state(S);\n        return -1;\n    }\n\n    /* Setup Parameter Block for keyed BLAKE2 */\n    P.digest_length = (uint8_t)outlen;\n    P.key_length = (uint8_t)keylen;\n    P.fanout = 1;\n    P.depth = 1;\n    P.leaf_length = 0;\n    P.node_offset = 0;\n    P.node_depth = 0;\n    P.inner_length = 0;\n    memset(P.reserved, 0, sizeof(P.reserved));\n    memset(P.salt, 0, sizeof(P.salt));\n    memset(P.personal, 0, sizeof(P.personal));\n\n    if (blake2b_init_param(S, &P) < 0)\n    {\n        blake2b_invalidate_state(S);\n        return -1;\n    }\n\n    {\n        uint8_t block[BLAKE2B_BLOCKBYTES];\n        memset(block, 0, BLAKE2B_BLOCKBYTES);\n        memcpy(block, key, keylen);\n        blake2b_update(S, block, BLAKE2B_BLOCKBYTES);\n        /* Burn the key from stack */\n        //clear_internal_memory(block, BLAKE2B_BLOCKBYTES);\n    }\n    return 0;\n}\n\nstatic void blake2b_compress(blake2b_state *S, const uint8_t *block)\n{\n    uint64_t m[16];\n    uint64_t v[16];\n    unsigned int i, r;\n\n    for (i = 0; i < 16; ++i)\n    {\n        m[i] = load64(block + i * sizeof(m[i]));\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        v[i] = S->h[i];\n    }\n\n    v[8] = blake2b_IV[0];\n    v[9] = blake2b_IV[1];\n    v[10] = blake2b_IV[2];\n    v[11] = blake2b_IV[3];\n    v[12] = blake2b_IV[4] ^ S->t[0];\n    v[13] = blake2b_IV[5] ^ S->t[1];\n    v[14] = blake2b_IV[6] ^ S->f[0];\n    v[15] = blake2b_IV[7] ^ S->f[1];\n\n#define G(r, i, a, b, c, d)                                                    \\\n    do {                                                                       \\\n        a = a + b + m[blake2b_sigma[r][2 * i + 0]];                            \\\n        d = rotr64(d ^ a, 32);                                                 \\\n        c = c + d;                                                             \\\n        b = rotr64(b ^ c, 24);                                                 \\\n        a = a + b + m[blake2b_sigma[r][2 * i + 1]];                            \\\n        d = rotr64(d ^ a, 16);                                                 \\\n        c = c + d;                                                             \\\n        b = rotr64(b ^ c, 63);                                                 \\\n    } while ((void)0, 0)\n\n#define ROUND(r)                                                               \\\n    do {                                                                       \\\n        G(r, 0, v[0], v[4], v[8], v[12]);                                      \\\n        G(r, 1, v[1], v[5], v[9], v[13]);                                      \\\n        G(r, 2, v[2], v[6], v[10], v[14]);                                     \\\n        G(r, 3, v[3], v[7], v[11], v[15]);                                     \\\n        G(r, 4, v[0], v[5], v[10], v[15]);                                     \\\n        G(r, 5, v[1], v[6], v[11], v[12]);                                     \\\n        G(r, 6, v[2], v[7], v[8], v[13]);                                      \\\n        G(r, 7, v[3], v[4], v[9], v[14]);                                      \\\n    } while ((void)0, 0)\n\n    for (r = 0; r < 12; ++r) {\n        ROUND(r);\n    }\n\n    for (i = 0; i < 8; ++i) {\n        S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];\n    }\n\n#undef G\n#undef ROUND\n}\n\nint blake2b_update(blake2b_state *S, const void *in, size_t inlen)\n{\n    const uint8_t *pin = (const uint8_t *)in;\n\n    if (inlen == 0)\n    {\n        return 0;\n    }\n\n    /* Sanity check */\n    if (S == NULL || in == NULL)\n    {\n        return -1;\n    }\n\n    /* Is this a reused state? */\n    if (S->f[0] != 0)\n    {\n        return -1;\n    }\n\n    if (S->buflen + inlen > BLAKE2B_BLOCKBYTES)\n    {\n        /* Complete current block */\n        size_t left = S->buflen;\n        size_t fill = BLAKE2B_BLOCKBYTES - left;\n        memcpy(&S->buf[left], pin, fill);\n        blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);\n        blake2b_compress(S, S->buf);\n        S->buflen = 0;\n        inlen -= fill;\n        pin += fill;\n        /* Avoid buffer copies when possible */\n        while (inlen > BLAKE2B_BLOCKBYTES)\n        {\n            blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);\n            blake2b_compress(S, pin);\n            inlen -= BLAKE2B_BLOCKBYTES;\n            pin += BLAKE2B_BLOCKBYTES;\n        }\n    }\n    memcpy(&S->buf[S->buflen], pin, inlen);\n    S->buflen += (unsigned int)inlen;\n    return 0;\n}\n\nint blake2b_final(blake2b_state *S, void *out, size_t outlen)\n{\n    uint8_t buffer[BLAKE2B_OUTBYTES] = {0};\n    unsigned int i;\n\n    /* Sanity checks */\n    if (S == NULL || out == NULL || outlen < S->outlen)\n    {\n        return -1;\n    }\n\n    /* Is this a reused state? */\n    if (S->f[0] != 0)\n    {\n        return -1;\n    }\n\n    blake2b_increment_counter(S, S->buflen);\n    blake2b_set_lastblock(S);\n    memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */\n    blake2b_compress(S, S->buf);\n\n    for (i = 0; i < 8; ++i)\n    { \n        /* Output full hash to temp buffer */\n        store64(buffer + sizeof(S->h[i]) * i, S->h[i]);\n    }\n\n    memcpy(out, buffer, S->outlen);\n    //clear_internal_memory(buffer, sizeof(buffer));\n    memset(S->buf, 0, sizeof(S->buf));\n    memset(S->h, 0, sizeof(S->h));\n    return 0;\n}\n\nint blake2b(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)\n{\n    blake2b_state S;\n    int ret = -1;\n\n    /* Verify parameters */\n    if (NULL == in && inlen > 0)\n    {\n        goto fail;\n    }\n\n    if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES)\n    {\n        goto fail;\n    }\n\n    if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES)\n    {\n        goto fail;\n    }\n\n    if (keylen > 0)\n    {\n        if (blake2b_init_key(&S, outlen, key, keylen) < 0)\n        {\n            goto fail;\n        }\n    }\n    else\n    {\n        if (blake2b_init(&S, outlen) < 0)\n        {\n            goto fail;\n        }\n    }\n\n    if (blake2b_update(&S, in, inlen) < 0)\n    {\n        goto fail;\n    }\n    ret = blake2b_final(&S, out, outlen);\n\nfail:\n    //clear_internal_memory(&S, sizeof(S));\n    return ret;\n}\n\n/* Argon2 Team - Begin Code */\n/* Argon2 Team - Begin Code */\nint blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen)\n{\n    uint8_t *out = (uint8_t *)pout;\n    blake2b_state blake_state;\n    uint8_t outlen_bytes[sizeof(uint32_t)] = {0};\n    int ret = -1;\n\n    if (outlen > UINT32_MAX)\n    {\n        goto fail;\n    }\n\n    /* Ensure little-endian byte order! */\n    store32(outlen_bytes, (uint32_t)outlen);\n\n#define TRY(statement)                                                         \\\n    do                                                                         \\\n    {                                                                          \\\n        ret = statement;                                                       \\\n        if (ret < 0) {                                                         \\\n            goto fail;                                                         \\\n        }                                                                      \\\n    } while ((void)0, 0)\n\n    if (outlen <= BLAKE2B_OUTBYTES)\n    {\n        TRY(blake2b_init(&blake_state, outlen));\n        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));\n        TRY(blake2b_update(&blake_state, in, inlen));\n        TRY(blake2b_final(&blake_state, out, outlen));\n    }\n    else\n    {\n        uint32_t toproduce;\n        uint8_t out_buffer[BLAKE2B_OUTBYTES];\n        uint8_t in_buffer[BLAKE2B_OUTBYTES];\n        TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));\n        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));\n        TRY(blake2b_update(&blake_state, in, inlen));\n        TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));\n        memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);\n        out += BLAKE2B_OUTBYTES / 2;\n        toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2;\n\n        while (toproduce > BLAKE2B_OUTBYTES)\n        {\n            memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);\n            TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, BLAKE2B_OUTBYTES, NULL, 0));\n            memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);\n            out += BLAKE2B_OUTBYTES / 2;\n            toproduce -= BLAKE2B_OUTBYTES / 2;\n        }\n\n        memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);\n        TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, 0));\n        memcpy(out, out_buffer, toproduce);\n    }\nfail:\n    memset(&blake_state, 0, sizeof(blake_state));\n    return ret;\n#undef TRY\n}\n/* Argon2 Team - End Code */\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_avx2.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLAKE_ROUND_MKA_OPT_AVX2_H\n#define BLAKE_ROUND_MKA_OPT_AVX2_H\n\n#include <compat/arch.h>\n#ifdef ARCH_CPU_X86_FAMILY // Only x86 family CPUs have AVX2\n\n#include \"blake2-impl.h\"\n\n#include \"compat.h\"\n\n#include <immintrin.h>\n\n#define rotr32(x)   _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))\n#define rotr24(x)   _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))\n#define rotr16(x)   _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))\n#define rotr63(x)   _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))\n\n#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo { \\\n    __m256i ml = _mm256_mul_epu32(A0, B0); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \\\n    D0 = _mm256_xor_si256(D0, A0); \\\n    D0 = rotr32(D0); \\\n    ml = _mm256_mul_epu32(C0, D0); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \\\n    B0 = _mm256_xor_si256(B0, C0); \\\n    B0 = rotr24(B0); \\\n    ml = _mm256_mul_epu32(A1, B1); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \\\n    D1 = _mm256_xor_si256(D1, A1); \\\n    D1 = rotr32(D1); \\\n    ml = _mm256_mul_epu32(C1, D1); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \\\n    B1 = _mm256_xor_si256(B1, C1); \\\n    B1 = rotr24(B1); \\\n} while((void)0, 0);\n\n#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo { \\\n    __m256i ml = _mm256_mul_epu32(A0, B0); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \\\n    D0 = _mm256_xor_si256(D0, A0); \\\n    D0 = rotr16(D0); \\\n    ml = _mm256_mul_epu32(C0, D0); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \\\n    B0 = _mm256_xor_si256(B0, C0); \\\n    B0 = rotr63(B0); \\\n    ml = _mm256_mul_epu32(A1, B1); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \\\n    D1 = _mm256_xor_si256(D1, A1); \\\n    D1 = rotr16(D1); \\\n    ml = _mm256_mul_epu32(C1, D1); \\\n    ml = _mm256_add_epi64(ml, ml); \\\n    C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \\\n    B1 = _mm256_xor_si256(B1, C1); \\\n    B1 = rotr63(B1); \\\n} while((void)0, 0);\n\n#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \\\n} while((void)0, 0);\n\n#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo { \\\n    __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \\\n    __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \\\n    B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \\\n    B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \\\n    tmp1 = C0; \\\n    C0 = C1; \\\n    C1 = tmp1; \\\n    tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \\\n    tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \\\n    D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \\\n    D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \\\n} while(0);\n\n#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \\\n} while((void)0, 0);\n\n#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo { \\\n    __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \\\n    __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \\\n    B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \\\n    B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \\\n    tmp1 = C0; \\\n    C0 = C1; \\\n    C1 = tmp1; \\\n    tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \\\n    tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \\\n    D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \\\n    D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \\\n} while((void)0, 0);\n\n#define BLAKE2_ROUND_AVX2_1(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo{ \\\n    G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \\\n    G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \\\n} while((void)0, 0);\n\n#define BLAKE2_ROUND_AVX2_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo{ \\\n    G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n    UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\n} while((void)0, 0);\n\n#endif\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_avx512f.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLAKE_ROUND_MKA_OPT_AVX512F_H\n#define BLAKE_ROUND_MKA_OPT_AVX512F_H\n\n#include <compat/arch.h>\n#ifdef ARCH_CPU_X86_FAMILY // Only x86 family CPUs have AVX512F\n\n#include \"blake2-impl.h\"\n\n#include \"compat.h\"\n\n#include <immintrin.h>\n\n#define ror64(x, n) _mm512_ror_epi64((x), (n))\n\nstatic __m512i muladd(__m512i x, __m512i y)\n{\n    __m512i z = _mm512_mul_epu32(x, y);\n    return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));\n}\n\n#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    A0 = muladd(A0, B0); \\\n    A1 = muladd(A1, B1); \\\n    D0 = _mm512_xor_si512(D0, A0); \\\n    D1 = _mm512_xor_si512(D1, A1); \\\n    D0 = ror64(D0, 32); \\\n    D1 = ror64(D1, 32); \\\n    C0 = muladd(C0, D0); \\\n    C1 = muladd(C1, D1); \\\n    B0 = _mm512_xor_si512(B0, C0); \\\n    B1 = _mm512_xor_si512(B1, C1); \\\n    B0 = ror64(B0, 24); \\\n    B1 = ror64(B1, 24); \\\n} while ((void)0, 0)\n\n#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    A0 = muladd(A0, B0); \\\n    A1 = muladd(A1, B1); \\\n    D0 = _mm512_xor_si512(D0, A0); \\\n    D1 = _mm512_xor_si512(D1, A1); \\\n    D0 = ror64(D0, 16); \\\n    D1 = ror64(D1, 16); \\\n    C0 = muladd(C0, D0); \\\n    C1 = muladd(C1, D1); \\\n    B0 = _mm512_xor_si512(B0, C0); \\\n    B1 = _mm512_xor_si512(B1, C1); \\\n    B0 = ror64(B0, 63); \\\n    B1 = ror64(B1, 63); \\\n} while ((void)0, 0)\n\n#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \\\n} while ((void)0, 0)\n\n#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \\\n    C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \\\n    D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \\\n    D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \\\n} while ((void)0, 0)\n\n#define BLAKE2_ROUND_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1) \\\ndo { \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \\\n} while ((void)0, 0)\n\n#define SWAP_HALVES(A0, A1) \\\ndo { \\\n    __m512i t0, t1; \\\n    t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \\\n    t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \\\n    A0 = t0; \\\n    A1 = t1; \\\n} while((void)0, 0)\n\n#define SWAP_QUARTERS(A0, A1) \\\ndo { \\\n    SWAP_HALVES(A0, A1); \\\n    A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \\\n    A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \\\n} while((void)0, 0)\n\n#define UNSWAP_QUARTERS(A0, A1) \\\ndo { \\\n    A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \\\n    A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \\\n    SWAP_HALVES(A0, A1); \\\n} while((void)0, 0)\n\n#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \\\ndo { \\\n    SWAP_HALVES(A0, B0); \\\n    SWAP_HALVES(C0, D0); \\\n    SWAP_HALVES(A1, B1); \\\n    SWAP_HALVES(C1, D1); \\\n    BLAKE2_ROUND_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    SWAP_HALVES(A0, B0); \\\n    SWAP_HALVES(C0, D0); \\\n    SWAP_HALVES(A1, B1); \\\n    SWAP_HALVES(C1, D1); \\\n} while ((void)0, 0)\n\n#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \\\ndo { \\\n    SWAP_QUARTERS(A0, A1); \\\n    SWAP_QUARTERS(B0, B1); \\\n    SWAP_QUARTERS(C0, C1); \\\n    SWAP_QUARTERS(D0, D1); \\\n    BLAKE2_ROUND_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \\\n    UNSWAP_QUARTERS(A0, A1); \\\n    UNSWAP_QUARTERS(B0, B1); \\\n    UNSWAP_QUARTERS(C0, C1); \\\n    UNSWAP_QUARTERS(D0, D1); \\\n} while ((void)0, 0)\n\n#endif\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_sse2.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLAKE_ROUND_MKA_OPT_SSE2_H\n#define BLAKE_ROUND_MKA_OPT_SSE2_H\n\n#include <compat/arch.h>\n// We only implement aes-ni/sse equivalent optimisations for x86 and arm processors currently.\n#if defined(ARCH_CPU_X86_FAMILY) || defined ARCH_CPU_ARM_FAMILY\n\n#include \"blake2-impl.h\"\n#include \"compat.h\"\n\n#include <compat/sse.h>\n\n#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))\n\nstatic BLAKE2_INLINE __m128i fBlaMka_SSE2(__m128i x, __m128i y)\n{\n    const __m128i z = _mm_mul_epu32(x, y);\n    return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));\n}\n\n#define G1(A0, B0, C0, D0, A1, B1, C1, D1)                                 \\\ndo {                                                                       \\\n    A0 = fBlaMka_SSE2(A0, B0);                                             \\\n    A1 = fBlaMka_SSE2(A1, B1);                                             \\\n    D0 = _mm_xor_si128(D0, A0);                                            \\\n    D1 = _mm_xor_si128(D1, A1);                                            \\\n    D0 = _mm_roti_epi64(D0, -32);                                          \\\n    D1 = _mm_roti_epi64(D1, -32);                                          \\\n    C0 = fBlaMka_SSE2(C0, D0);                                             \\\n    C1 = fBlaMka_SSE2(C1, D1);                                             \\\n    B0 = _mm_xor_si128(B0, C0);                                            \\\n    B1 = _mm_xor_si128(B1, C1);                                            \\\n    B0 = _mm_roti_epi64(B0, -24);                                          \\\n    B1 = _mm_roti_epi64(B1, -24);                                          \\\n} while ((void)0, 0)\n\n#define G2(A0, B0, C0, D0, A1, B1, C1, D1)                                 \\\ndo {                                                                       \\\n    A0 = fBlaMka_SSE2(A0, B0);                                             \\\n    A1 = fBlaMka_SSE2(A1, B1);                                             \\\n    D0 = _mm_xor_si128(D0, A0);                                            \\\n    D1 = _mm_xor_si128(D1, A1);                                            \\\n    D0 = _mm_roti_epi64(D0, -16);                                          \\\n    D1 = _mm_roti_epi64(D1, -16);                                          \\\n    C0 = fBlaMka_SSE2(C0, D0);                                             \\\n    C1 = fBlaMka_SSE2(C1, D1);                                             \\\n    B0 = _mm_xor_si128(B0, C0);                                            \\\n    B1 = _mm_xor_si128(B1, C1);                                            \\\n    B0 = _mm_roti_epi64(B0, -63);                                          \\\n    B1 = _mm_roti_epi64(B1, -63);                                          \\\n} while ((void)0, 0)\n\n#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                        \\\ndo {                                                                       \\\n    __m128i t0 = D0;                                                       \\\n    __m128i t1 = B0;                                                       \\\n    D0 = C0;                                                               \\\n    C0 = C1;                                                               \\\n    C1 = D0;                                                               \\\n    D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0));               \\\n    D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1));               \\\n    B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1));               \\\n    B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1));               \\\n} while ((void)0, 0)\n\n#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                      \\\ndo {                                                                       \\\n    __m128i t0, t1;                                                        \\\n    t0 = C0;                                                               \\\n    C0 = C1;                                                               \\\n    C1 = t0;                                                               \\\n    t0 = B0;                                                               \\\n    t1 = D0;                                                               \\\n    B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0));               \\\n    B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1));               \\\n    D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1));               \\\n    D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1));               \\\n} while ((void)0, 0)\n\n#define BLAKE2_ROUND_SSE2(A0, A1, B0, B1, C0, C1, D0, D1)                  \\\ndo {                                                                       \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                           \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                         \\\n} while ((void)0, 0)\n\n#endif\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blamka-round-opt_sse3.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLAKE_ROUND_MKA_OPT_SSE3_H\n#define BLAKE_ROUND_MKA_OPT_SSE3_H\n\n#include <compat/arch.h>\n#ifdef ARCH_CPU_X86_FAMILY // Only x86 family CPUs have SSE3\n\n#include \"blake2-impl.h\"\n#include \"compat.h\"\n\n#include <emmintrin.h>\n#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */\n\n\n#define r16 (_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))\n#define r24 (_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))\n#define _mm_roti_epi64(x, c)                                                   \\\n    (-(c) == 32)                                                               \\\n        ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1))                      \\\n        : (-(c) == 24)                                                         \\\n              ? _mm_shuffle_epi8((x), r24)                                     \\\n              : (-(c) == 16)                                                   \\\n                    ? _mm_shuffle_epi8((x), r16)                               \\\n                    : (-(c) == 63)                                             \\\n                          ? _mm_xor_si128(_mm_srli_epi64((x), -(c)),           \\\n                                          _mm_add_epi64((x), (x)))             \\\n                          : _mm_xor_si128(_mm_srli_epi64((x), -(c)),           \\\n                                          _mm_slli_epi64((x), 64 - (-(c))))\n\n\nstatic BLAKE2_INLINE __m128i fBlaMka_SSE3(__m128i x, __m128i y)\n{\n    const __m128i z = _mm_mul_epu32(x, y);\n    return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));\n}\n\n#define G1(A0, B0, C0, D0, A1, B1, C1, D1)                                 \\\ndo {                                                                       \\\n    A0 = fBlaMka_SSE3(A0, B0);                                             \\\n    A1 = fBlaMka_SSE3(A1, B1);                                             \\\n    D0 = _mm_xor_si128(D0, A0);                                            \\\n    D1 = _mm_xor_si128(D1, A1);                                            \\\n    D0 = _mm_roti_epi64(D0, -32);                                          \\\n    D1 = _mm_roti_epi64(D1, -32);                                          \\\n    C0 = fBlaMka_SSE3(C0, D0);                                             \\\n    C1 = fBlaMka_SSE3(C1, D1);                                             \\\n    B0 = _mm_xor_si128(B0, C0);                                            \\\n    B1 = _mm_xor_si128(B1, C1);                                            \\\n    B0 = _mm_roti_epi64(B0, -24);                                          \\\n    B1 = _mm_roti_epi64(B1, -24);                                          \\\n} while ((void)0, 0)\n\n#define G2(A0, B0, C0, D0, A1, B1, C1, D1)                                 \\\ndo {                                                                       \\\n    A0 = fBlaMka_SSE3(A0, B0);                                             \\\n    A1 = fBlaMka_SSE3(A1, B1);                                             \\\n    D0 = _mm_xor_si128(D0, A0);                                            \\\n    D1 = _mm_xor_si128(D1, A1);                                            \\\n    D0 = _mm_roti_epi64(D0, -16);                                          \\\n    D1 = _mm_roti_epi64(D1, -16);                                          \\\n    C0 = fBlaMka_SSE3(C0, D0);                                             \\\n    C1 = fBlaMka_SSE3(C1, D1);                                             \\\n    B0 = _mm_xor_si128(B0, C0);                                            \\\n    B1 = _mm_xor_si128(B1, C1);                                            \\\n    B0 = _mm_roti_epi64(B0, -63);                                          \\\n    B1 = _mm_roti_epi64(B1, -63);                                          \\\n} while ((void)0, 0)\n\n#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                        \\\ndo {                                                                       \\\n    __m128i t0 = _mm_alignr_epi8(B1, B0, 8);                               \\\n    __m128i t1 = _mm_alignr_epi8(B0, B1, 8);                               \\\n    B0 = t0;                                                               \\\n    B1 = t1;                                                               \\\n    t0 = C0;                                                               \\\n    C0 = C1;                                                               \\\n    C1 = t0;                                                               \\\n    t0 = _mm_alignr_epi8(D1, D0, 8);                                       \\\n    t1 = _mm_alignr_epi8(D0, D1, 8);                                       \\\n    D0 = t1;                                                               \\\n    D1 = t0;                                                               \\\n} while ((void)0, 0)\n\n#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1)                      \\\ndo {                                                                       \\\n    __m128i t0 = _mm_alignr_epi8(B0, B1, 8);                               \\\n    __m128i t1 = _mm_alignr_epi8(B1, B0, 8);                               \\\n    B0 = t0;                                                               \\\n    B1 = t1;                                                               \\\n    t0 = C0;                                                               \\\n    C0 = C1;                                                               \\\n    C1 = t0;                                                               \\\n    t0 = _mm_alignr_epi8(D0, D1, 8);                                       \\\n    t1 = _mm_alignr_epi8(D1, D0, 8);                                       \\\n    D0 = t1;                                                               \\\n    D1 = t0;                                                               \\\n} while ((void)0, 0)\n\n#define BLAKE2_ROUND_SSE3(A0, A1, B0, B1, C0, C1, D0, D1)                  \\\ndo {                                                                       \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                           \\\n    G1(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    G2(A0, B0, C0, D0, A1, B1, C1, D1);                                    \\\n    UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1);                         \\\n} while ((void)0, 0)\n\n#endif\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/blake2/blamka-round-ref.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef BLAKE_ROUND_MKA_H\n#define BLAKE_ROUND_MKA_H\n\n#include \"blake2.h\"\n#include \"blake2-impl.h\"\n\n/* designed by the Lyra PHC team */\nstatic BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y)\n{\n    const uint64_t m = UINT64_C(0xFFFFFFFF);\n    const uint64_t xy = (x & m) * (y & m);\n    return x + y + 2 * xy;\n}\n\n#define G(a, b, c, d)                                                          \\\n    do {                                                                       \\\n        a = fBlaMka(a, b);                                                     \\\n        d = rotr64(d ^ a, 32);                                                 \\\n        c = fBlaMka(c, d);                                                     \\\n        b = rotr64(b ^ c, 24);                                                 \\\n        a = fBlaMka(a, b);                                                     \\\n        d = rotr64(d ^ a, 16);                                                 \\\n        c = fBlaMka(c, d);                                                     \\\n        b = rotr64(b ^ c, 63);                                                 \\\n    } while ((void)0, 0)\n\n#define BLAKE2_ROUND_NOMSG_REF(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,   \\\n                           v12, v13, v14, v15)                                 \\\n    do {                                                                       \\\n        G(v0, v4, v8, v12);                                                    \\\n        G(v1, v5, v9, v13);                                                    \\\n        G(v2, v6, v10, v14);                                                   \\\n        G(v3, v7, v11, v15);                                                   \\\n        G(v0, v5, v10, v15);                                                   \\\n        G(v1, v6, v11, v12);                                                   \\\n        G(v2, v7, v8, v13);                                                    \\\n        G(v3, v4, v9, v14);                                                    \\\n    } while ((void)0, 0)\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/core.cpp",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <compat/arch.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"core.h\"\n\n\n#if defined(ARGON2_CORE_OPT_IMPL) || defined(ARGON2_CORE_REF_IMPL)\n#include \"blake2/blake2.h\"\n#include \"blake2/blake2-impl.h\"\n#include <pthread.h>\n \n#include <crypto/hash/sigma/echo256/echo256_opt.h>\n#include <crypto/hash/sigma/echo256/sphlib/sph_echo.h>\n\n/***************Instance and Position constructors**********/\nvoid init_block_value(argon2_echo_block* b, uint8_t in)\n{\n    memset(b->v, in, sizeof(b->v));\n}\n\nvoid copy_block(argon2_echo_block* dst, const argon2_echo_block* src)\n{\n    memcpy(dst->v, src->v, sizeof(uint64_t)* ARGON2_QWORDS_IN_BLOCK);\n}\n\nvoid xor_block(argon2_echo_block* dst, const argon2_echo_block* src)\n{\n    int i;\n    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i)\n    {\n        dst->v[i] ^= src->v[i];\n    }\n}\n\nstatic void load_block(argon2_echo_block* dst, const void* input)\n{\n    unsigned i;\n    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i)\n    {\n        dst->v[i] = load64((const uint8_t*)input + i * sizeof(dst->v[i]));\n    }\n}\n\nstatic void store_block(void *output, const argon2_echo_block *src) {\n    unsigned i;\n    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {\n        store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);\n    }\n}\n\nconstexpr int sigma_version=1;\nvoid finalize(const argon2_echo_context* context, argon2_echo_instance_t* instance)\n{\n    if (context != NULL && instance != NULL)\n    {\n        //fixme: (SIGMA2) - Consider switching back to this once we can assume slightly faster 'slowest' machines (the pi3's can't handle this)\n        if constexpr(sigma_version==2)\n        {\n            /* Hash the entire memory to produce our final output hash */\n            ECHO_HASH_256(instance->memory, instance->memory_blocks * ARGON2_BLOCK_SIZE, (unsigned char*)context->outHash.begin());\n        }\n        else\n        {\n            argon2_echo_block blockhash;\n            uint32_t l;\n            \n            copy_block(&blockhash, instance->memory + instance->lane_length - 1);\n\n            /* XOR the last blocks */\n            for (l = 1; l < instance->lanes; ++l) {\n                uint32_t last_block_in_lane =\n                    l * instance->lane_length + (instance->lane_length - 1);\n                xor_block(&blockhash, instance->memory + last_block_in_lane);\n            }\n\n            /* Hash the result */\n            {\n                uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];\n                store_block(blockhash_bytes, &blockhash);\n                blake2b_long((unsigned char*)context->outHash.begin(), 32, blockhash_bytes, ARGON2_BLOCK_SIZE);\n            }\n        }\n    }\n}\n\n/*\n* Pass 0:\n*      This lane : all already finished segments plus already constructed\n* blocks in this segment\n*      Other lanes : all already finished segments\n* Pass 1+:\n*      This lane : (SYNC_POINTS - 1) last segments plus already constructed\n* blocks in this segment\n*      Other lanes : (SYNC_POINTS - 1) last segments\n*/\nuint32_t index_alpha(const argon2_echo_instance_t* instance, const argon2_echo_position_t* position, uint32_t pseudo_rand, int same_lane)\n{   \n    uint32_t reference_area_size;\n    uint64_t relative_position;\n    uint32_t start_position, absolute_position;\n\n    if (0 == position->pass) /* First pass */\n    {\n        if (0 == position->slice) /* First slice */\n        {\n            reference_area_size = position->index - 1; /* all but the previous */\n        }\n        else\n        {\n            if (same_lane) /* The same lane => add current segment */\n            {\n                reference_area_size = position->slice * instance->segment_length + position->index - 1;\n            }\n            else\n            {\n                reference_area_size = position->slice * instance->segment_length + ((position->index == 0) ? (-1) : 0);\n            }\n        }\n    }\n    else /* Second pass */\n    {   \n        if (same_lane)\n        {\n            reference_area_size = instance->lane_length - instance->segment_length + position->index - 1;\n        }\n        else\n        {\n            reference_area_size = instance->lane_length - instance->segment_length + ((position->index == 0) ? (-1) : 0);\n        }\n    }\n\n    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce relative position */\n    relative_position = pseudo_rand;\n    relative_position = relative_position * relative_position >> 32;\n    relative_position = reference_area_size - 1 - (reference_area_size * relative_position >> 32);\n\n    /* 1.2.5 Computing starting position */\n    start_position = 0;\n\n    if (0 != position->pass)\n    {\n        start_position = (position->slice == ARGON2_SYNC_POINTS - 1) ? 0 : (position->slice + 1) * instance->segment_length;\n    }\n\n    /* 1.2.6. Computing absolute position */\n    absolute_position = (start_position + relative_position) % instance->lane_length; /* absolute position */\n    return absolute_position;\n}\n\n/* Single-threaded version for p=1 case */\nstatic int fill_memory_blocks_st(argon2_echo_instance_t* instance)\n{\n    uint32_t r, s, l;\n\n    for (r = 0; r < instance->passes; ++r)\n    {\n        for (s = 0; s < ARGON2_SYNC_POINTS; ++s)\n        {\n            for (l = 0; l < instance->lanes; ++l)\n            {\n                argon2_echo_position_t position = {r, l, (uint8_t)s, 0};\n                fill_segment(instance, position);\n            }\n        }\n    }\n    return ARGON2_OK;\n}\n\nstatic void* fill_segment_thr(void* thread_data)\n{\n    argon2_echo_thread_data* my_data = static_cast<argon2_echo_thread_data*>(thread_data);\n    fill_segment(my_data->instance_ptr, my_data->pos);\n    pthread_exit(nullptr);\n    return 0;\n}\n\n/* Multi-threaded version for p > 1 case */\nstatic int fill_memory_blocks_mt(argon2_echo_instance_t* instance)\n{\n    uint32_t r, s;\n    pthread_t* thread = nullptr;\n    argon2_echo_thread_data* thr_data = nullptr;\n    int rc = ARGON2_OK;\n\n    /* 1. Allocating space for threads */\n    thread = static_cast<pthread_t*>(calloc(instance->lanes, sizeof(pthread_t)));\n    if (thread == NULL)\n    {\n        rc = ARGON2_MEMORY_ALLOCATION_ERROR;\n        goto fail;\n    }\n\n    thr_data = static_cast<argon2_echo_thread_data*>(calloc(instance->lanes, sizeof(argon2_echo_thread_data)));\n    if (thr_data == NULL)\n    {\n        rc = ARGON2_MEMORY_ALLOCATION_ERROR;\n        goto fail;\n    }\n\n    for (r = 0; r < instance->passes; ++r)\n    {\n        for (s = 0; s < ARGON2_SYNC_POINTS; ++s)\n        {\n            uint32_t l, ll;\n\n            /* 2. Calling threads */\n            for (l = 0; l < instance->lanes; ++l)\n            {\n                argon2_echo_position_t position;\n\n                /* 2.1 Join a thread if limit is exceeded */\n                if (l >= instance->threads)\n                {\n                    if (pthread_join(thread[l - instance->threads], nullptr))\n                    {\n                        rc = ARGON2_THREAD_FAIL;\n                        goto fail;\n                    }\n                }\n\n                /* 2.2 Create thread */\n                position.pass = r;\n                position.lane = l;\n                position.slice = (uint8_t)s;\n                position.index = 0;\n                thr_data[l].instance_ptr = instance; /* preparing the thread input */\n                memcpy(&(thr_data[l].pos), &position, sizeof(argon2_echo_position_t));\n                if (pthread_create(&thread[l], nullptr, &fill_segment_thr, (void*)&thr_data[l]))\n                {\n                    /* Wait for already running threads */\n                    for (ll = 0; ll < l; ++ll)\n                    {\n                        pthread_join(thread[ll], nullptr);\n                    }\n                    rc = ARGON2_THREAD_FAIL;\n                    goto fail;\n                }\n\n                /* fill_segment(instance, position); */\n                /*Non-thread equivalent of the lines above */\n            }\n\n            /* 3. Joining remaining threads */\n            for (l = instance->lanes - instance->threads; l < instance->lanes; ++l)\n            {\n                if (pthread_join(thread[l], nullptr))\n                {\n                    rc = ARGON2_THREAD_FAIL;\n                    goto fail;\n                }\n            }\n        }\n    }\n\nfail:\n    if (thread != NULL)\n    {\n        free(thread);\n    }\n    if (thr_data != NULL)\n    {\n        free(thr_data);\n    }\n    return rc;\n}\n\nint fill_memory_blocks(argon2_echo_instance_t* instance)\n{\n    if (instance == NULL || instance->lanes == 0)\n    {\n        return ARGON2_INCORRECT_PARAMETER;\n    }\n    return instance->threads == 1 ? fill_memory_blocks_st(instance) : fill_memory_blocks_mt(instance);\n}\n\nvoid fill_first_blocks(uint8_t* blockhash, const argon2_echo_instance_t* instance)\n{\n    uint32_t l;\n    /* Make the first and second block in each lane as G(H0||0||i) or G(H0||1||i) */\n    uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];\n    for (l = 0; l < instance->lanes; ++l)\n    {\n        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);\n        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);\n        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, ARGON2_PREHASH_SEED_LENGTH);\n        load_block(&instance->memory[l * instance->lane_length + 0], blockhash_bytes);\n\n        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);\n        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, ARGON2_PREHASH_SEED_LENGTH);\n        load_block(&instance->memory[l * instance->lane_length + 1], blockhash_bytes);\n    }\n    // NB! Ordinarily argon would erase the memory here to keep sensitive data out of memory.\n    // For our use case (PoW) this is not necessary, as we are hashing a block header that is anyway public knowledge.\n}\n\nvoid initial_hash(uint8_t* blockhash, argon2_echo_context* context)\n{\n    if (NULL == context || NULL == blockhash)\n    {\n        return;\n    }\n\n    // NB! Ordinarily argon2 would produce a 64 bit blake hash of the various input paramaters here.\n    // However we have stripped away most the paramaters we aren't using, and the remaining paramaters are all constant (m_cost, t_cost, pwdlen are all constant so no point hashing these)\n    // So we perform a double echo-256 hash on the password instead to obtain the full 512 bits argon requires for initalisation.\n    ECHO_HASH_256(context->pwd, context->pwdlen, blockhash);\n    ECHO_HASH_256(blockhash, 32, blockhash+32);\n}\n\n#ifdef ARGON2_CORE_OPT_IMPL\nstatic void next_addresses(argon2_echo_block* address_block, argon2_echo_block* input_block)\n{\n    /*Temporary zero-initialized blocks*/\n    ARGON2_BLOCK_WORD_SIZE zero_block[ARGON2_BLOCK_WORD_COUNT];\n    ARGON2_BLOCK_WORD_SIZE zero2_block[ARGON2_BLOCK_WORD_COUNT];\n\n    memset(zero_block, 0, sizeof(zero_block));\n    memset(zero2_block, 0, sizeof(zero2_block));\n\n    /*Increasing index counter*/\n    input_block->v[6]++;\n\n    /*First iteration of G*/\n    fill_block(zero_block, input_block, address_block, 0);\n\n    /*Second iteration of G*/\n    fill_block(zero2_block, address_block, address_block, 0);\n}\n\nvoid fill_segment(const argon2_echo_instance_t *instance, argon2_echo_position_t position)\n{\n    argon2_echo_block *ref_block = NULL, *curr_block = NULL;\n    argon2_echo_block address_block, input_block;\n    uint64_t pseudo_rand, ref_index, ref_lane;\n    uint32_t prev_offset, curr_offset;\n    uint32_t starting_index, i;\n    ARGON2_BLOCK_WORD_SIZE state[ARGON2_BLOCK_WORD_COUNT];\n\n    //Argon2d always has data dependent addressing\n    bool data_independent_addressing = false;\n\n    if (instance == NULL)\n    {\n        return;\n    }\n\n    //data_independent_addressing = (instance->type == Argon2_i) || (instance->type == Argon2_id && (position.pass == 0) && (position.slice < ARGON2_SYNC_POINTS / 2));\n\n    if (data_independent_addressing)\n    {\n        init_block_value(&input_block, 0);\n\n        input_block.v[0] = position.pass;\n        input_block.v[1] = position.lane;\n        input_block.v[2] = position.slice;\n        input_block.v[3] = instance->memory_blocks;\n        input_block.v[4] = instance->passes;\n        //input_block.v[5] = instance->type;\n    }\n\n    starting_index = 0;\n\n    if ((0 == position.pass) && (0 == position.slice))\n    {\n        starting_index = 2; /* we have already generated the first two blocks */\n\n        /* Don't forget to generate the first block of addresses: */\n        if (data_independent_addressing)\n        {\n            next_addresses(&address_block, &input_block);\n        }\n    }\n\n    /* Offset of the current block */\n    curr_offset = position.lane * instance->lane_length + position.slice * instance->segment_length + starting_index;\n\n    if (0 == curr_offset % instance->lane_length)\n    {\n        /* Last block in this lane */\n        prev_offset = curr_offset + instance->lane_length - 1;\n    }\n    else\n    {\n        /* Previous block */\n        prev_offset = curr_offset - 1;\n    }\n\n    memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);\n\n    for (i = starting_index; i < instance->segment_length; ++i, ++curr_offset, ++prev_offset)\n    {\n        /*1.1 Rotating prev_offset if needed */\n        if (curr_offset % instance->lane_length == 1)\n        {\n            prev_offset = curr_offset - 1;\n        }\n\n        /* 1.2 Computing the index of the reference block */\n        /* 1.2.1 Taking pseudo-random value from the previous block */\n        if (data_independent_addressing)\n        {\n            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0)\n            {\n                next_addresses(&address_block, &input_block);\n            }\n            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];\n        }\n        else\n        {\n            pseudo_rand = instance->memory[prev_offset].v[0];\n        }\n\n        /* 1.2.2 Computing the lane of the reference block */\n        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;\n\n        if ((position.pass == 0) && (position.slice == 0))\n        {\n            /* Can not reference other lanes yet */\n            ref_lane = position.lane;\n        }\n\n        /* 1.2.3 Computing the number of possible reference block within the\n         * lane.\n         */\n        position.index = i;\n        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, ref_lane == position.lane);\n\n        /* 2 Creating a new block */\n        ref_block = instance->memory + instance->lane_length * ref_lane + ref_index;\n        curr_block = instance->memory + curr_offset;\n            \n        if(0 == position.pass)\n        {\n            fill_block(state, ref_block, curr_block, 0);\n        }\n        else\n        {\n            fill_block(state, ref_block, curr_block, 1);\n        }\n    }\n}\n#endif\n\nint initialize(argon2_echo_instance_t* instance, argon2_echo_context* context)\n{\n    uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];\n\n    if (instance == NULL || context == NULL)\n    {\n        return ARGON2_INCORRECT_PARAMETER;\n    }\n    instance->context_ptr = context;\n\n    /* 1. Memory allocation */\n    // Ordinarily argon would allocate memory here, but for our implementation we let the caller pre-allocate instead so we just grab out memory from 'allocated_memory'\n    instance->memory = (argon2_echo_block*)context->allocated_memory;\n\n    /* 2. Initial hashing */\n    /* H_0 + 8 extra bytes to produce the first blocks */\n    /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */\n    /* Hashing all inputs */\n    initial_hash(blockhash, context);\n    /* Zeroing 8 extra bytes */\n    memset(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0, ARGON2_PREHASH_SEED_LENGTH - ARGON2_PREHASH_DIGEST_LENGTH);\n\n    /* 3. Creating first blocks, we always have at least two blocks in a slice */\n    fill_first_blocks(blockhash, instance);\n    \n    /* Clearing the hash */\n    // NB! Ordinarily argon would erase the memory here to keep sensitive data out of memory.\n    // For our use case (PoW) this is not necessary, as we are hashing a block header that is anyway public knowledge.\n    return ARGON2_OK;\n}\n#else\nint validate_inputs(const argon2_echo_context* context)\n{\n    if (NULL == context)\n    {\n        return ARGON2_INCORRECT_PARAMETER;\n    }\n\n    /* Validate password (required param) */\n    if (NULL == context->pwd)\n    {\n        if (0 != context->pwdlen)\n        {\n            return ARGON2_PWD_PTR_MISMATCH;\n        }\n    }\n\n    if (ARGON2_MIN_PWD_LENGTH > context->pwdlen)\n    {\n        return ARGON2_PWD_TOO_SHORT;\n    }\n\n    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen)\n    {\n        return ARGON2_PWD_TOO_LONG;\n    }\n\n    /* Validate memory cost */\n    if (ARGON2_MIN_MEMORY > context->m_cost)\n    {\n        return ARGON2_MEMORY_TOO_LITTLE;\n    }\n\n    if (ARGON2_MAX_MEMORY < context->m_cost)\n    {\n        return ARGON2_MEMORY_TOO_MUCH;\n    }\n\n    if (context->m_cost < 8 * context->lanes)\n    {\n        return ARGON2_MEMORY_TOO_LITTLE;\n    }\n\n    /* Validate time cost */\n    if (ARGON2_MIN_TIME > context->t_cost)\n    {\n        return ARGON2_TIME_TOO_SMALL;\n    }\n\n    if (ARGON2_MAX_TIME < context->t_cost)\n    {\n        return ARGON2_TIME_TOO_LARGE;\n    }\n\n    /* Validate lanes */\n    if (ARGON2_MIN_LANES > context->lanes)\n    {\n        return ARGON2_LANES_TOO_FEW;\n    }\n\n    if (ARGON2_MAX_LANES < context->lanes)\n    {\n        return ARGON2_LANES_TOO_MANY;\n    }\n\n    /* Validate threads */\n    if (ARGON2_MIN_THREADS > context->threads)\n    {\n        return ARGON2_THREADS_TOO_FEW;\n    }\n\n    if (ARGON2_MAX_THREADS < context->threads)\n    {\n        return ARGON2_THREADS_TOO_MANY;\n    }\n\n    return ARGON2_OK;\n}\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/core.h",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef ARGON2_CORE_OPT_IMPL\n#ifndef ARGON2_ECHO_CORE_H\n#define ARGON2_ECHO_CORE_H\n\n#include \"argon_echo.h\"\n\n/**********************Argon2 internal constants*******************************/\n\nenum argon2_echo_core_constants\n{\n    /* Memory block size in bytes */\n    ARGON2_BLOCK_SIZE = 1024,\n    ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,\n    ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,\n    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,\n    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,\n\n    /* Number of pseudo-random values generated by one call to Blake in Argon2i to generate reference block positions */\n    ARGON2_ADDRESSES_IN_BLOCK = 128,\n\n    /* Pre-hashing digest length and its extension*/\n    ARGON2_PREHASH_DIGEST_LENGTH = 64,\n    ARGON2_PREHASH_SEED_LENGTH = 72\n};\n\n/*************************Argon2 internal data types***********************/\n\n/*\n * Structure for the (1KB) memory block implemented as 128 64-bit words.\n * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no\n * bounds checking).\n */\nstruct argon2_echo_block\n{\n    uint64_t v[ARGON2_QWORDS_IN_BLOCK];\n};\n\n/*\n * Argon2 instance: memory pointer, number of passes, amount of memory,\n * and derived values.\n * Used to evaluate the number and location of blocks to construct in each\n * thread\n */\nstruct argon2_echo_instance_t\n{\n    argon2_echo_block* memory;        /* Memory pointer */\n    uint32_t passes;                  /* Number of passes */\n    uint32_t memory_blocks;           /* Number of blocks in memory */\n    uint32_t segment_length;\n    uint32_t lane_length;\n    uint32_t lanes;\n    uint32_t threads;\n    int print_internals;              /* whether to print the memory blocks */\n    argon2_echo_context* context_ptr; /* points back to original context */\n};\n\n/*\n * Argon2 position: where we construct the block right now. Used to distribute\n * work between threads.\n */\nstruct argon2_echo_position_t\n{\n    uint32_t pass=0;\n    uint32_t lane;\n    uint8_t slice;\n    uint32_t index;\n};\n\n/*Struct that holds the inputs for thread handling FillSegment*/\nstruct argon2_echo_thread_data\n{\n    argon2_echo_instance_t *instance_ptr;\n    argon2_echo_position_t pos;\n};\n\n#endif\n#endif\n\n/*****************Functions that work with the block******************/\n\n/* Initialize each byte of the block with @in */\nvoid init_block_value(argon2_echo_block* b, uint8_t in);\n\n/* Copy block @src to block @dst */\nvoid copy_block(argon2_echo_block* dst, const argon2_echo_block* src);\n\n/* XOR @src onto @dst bytewise */\nvoid xor_block(argon2_echo_block* dst, const argon2_echo_block* src);\n\n/*************************Argon2_echo core functions********************************/\n/*\n * Computes absolute position of reference block in the lane following a skewed\n * distribution and using a pseudo-random value as input\n * @param instance Pointer to the current instance\n * @param position Pointer to the current position\n * @param pseudo_rand 32-bit pseudo-random value used to determine the position\n * @param same_lane Indicates if the block will be taken from the current lane.\n * If so we can reference the current segment\n * @pre All pointers must be valid\n */\nuint32_t index_alpha(const argon2_echo_instance_t* instance, const argon2_echo_position_t* position, uint32_t pseudo_rand, int same_lane);\n\n/*\n * Function that validates all inputs against predefined restrictions and return\n * an error code\n * @param context Pointer to current Argon2 context\n * @return ARGON2_OK if everything is all right, otherwise one of error codes\n * (all defined in <argon2.h>\n */\nint validate_inputs(const argon2_echo_context* context);\n\n/*\n * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears\n * password and secret if needed\n * @param  context  Pointer to the Argon2 internal structure containing memory\n * pointer, and parameters for time and space requirements.\n * @param  blockhash Buffer for pre-hashing digest\n  * @pre    @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes\n * allocated\n */\nvoid initial_hash(uint8_t* blockhash, argon2_echo_context* context);\n\n/*\n * Function creates first 2 blocks per lane\n * @param instance Pointer to the current instance\n * @param blockhash Pointer to the pre-hashing digest\n * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values\n */\nvoid fill_first_blocks(uint8_t* blockhash, const argon2_echo_instance_t* instance);\n\n/*\n * Function allocates memory, hashes the inputs with Blake,  and creates first\n * two blocks. Returns the pointer to the main memory with 2 blocks per lane\n * initialized\n * @param  context  Pointer to the Argon2 internal structure containing memory\n * pointer, and parameters for time and space requirements.\n * @param  instance Current Argon2 instance\n * @return Zero if successful, -1 if memory failed to allocate. @context->state\n * will be modified if successful.\n */\nint initialize(argon2_echo_instance_t* instance, argon2_echo_context* context);\n\n/*\n * XORing the last block of each lane, hashing it, making the tag. Deallocates\n * the memory.\n * @param context Pointer to current Argon2 context (use only the out parameters\n * from it)\n * @param instance Pointer to current instance of Argon2\n * @pre instance->state must point to necessary amount of memory\n * @pre if context->free_cbk is not NULL, it should point to a function that\n * deallocates memory\n */\nvoid finalize(const argon2_echo_context* context, argon2_echo_instance_t* instance);\n\n/*\n * Function that fills the segment using previous segments also from other\n * threads\n * @param context current context\n * @param instance Pointer to the current instance\n * @param position Current position\n * @pre all block pointers must be valid\n */\nvoid fill_segment(const argon2_echo_instance_t* instance, argon2_echo_position_t position);\n\n/*\n * Function that fills the entire memory t_cost times based on the first two\n * blocks in each lane\n * @param instance Pointer to the current instance\n * @return ARGON2_OK if successful, @context->state\n */\nint fill_memory_blocks(argon2_echo_instance_t* instance);\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a53_next_addresses\n#define fill_segment       arm_cortex_a53_fill_segment\n#define fill_block         arm_cortex_a53_fill_block\n#define initialize         arm_cortex_a53_initialize\n#define fill_memory_blocks arm_cortex_a53_fill_memory_blocks\n#define Compress           arm_cortex_a53_argon2_echo_compress\n#define init_block_value   arm_cortex_a53_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a53_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a53_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a53_argon2_echo_finalize\n#define index_alpha        arm_cortex_a53_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a53_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a53_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a53\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a53_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a53_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a53_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a53_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A53_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A53_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a53\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a53_aes_next_addresses\n#define fill_segment       arm_cortex_a53_aes_fill_segment\n#define fill_block         arm_cortex_a53_aes_fill_block\n#define initialize         arm_cortex_a53_aes_initialize\n#define fill_memory_blocks arm_cortex_a53_aes_fill_memory_blocks\n#define Compress           arm_cortex_a53_aes_argon2_echo_compress\n#define init_block_value   arm_cortex_a53_aes_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a53_aes_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a53_aes_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a53_aes_argon2_echo_finalize\n#define index_alpha        arm_cortex_a53_aes_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a53_aes_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a53_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a53_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a53_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a53_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a53_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a53_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a53_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A53_AES_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A53_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a53_aes\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a57_next_addresses\n#define fill_segment       arm_cortex_a57_fill_segment\n#define fill_block         arm_cortex_a57_fill_block\n#define initialize         arm_cortex_a57_initialize\n#define fill_memory_blocks arm_cortex_a57_fill_memory_blocks\n#define Compress           arm_cortex_a57_argon2_echo_compress\n#define init_block_value   arm_cortex_a57_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a57_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a57_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a57_argon2_echo_finalize\n#define index_alpha        arm_cortex_a57_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a57_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a57_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a57\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a57_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a57_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a57_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a57_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A57_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A57_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a57\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a57_aes_next_addresses\n#define fill_segment       arm_cortex_a57_aes_fill_segment\n#define fill_block         arm_cortex_a57_aes_fill_block\n#define initialize         arm_cortex_a57_aes_initialize\n#define fill_memory_blocks arm_cortex_a57_aes_fill_memory_blocks\n#define Compress           arm_cortex_a57_aes_argon2_echo_compress\n#define init_block_value   arm_cortex_a57_aes_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a57_aes_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a57_aes_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a57_aes_argon2_echo_finalize\n#define index_alpha        arm_cortex_a57_aes_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a57_aes_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a57_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a57_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a57_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a57_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a57_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a57_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a57_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A57_AES_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A57_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a57_aes\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a72_next_addresses\n#define fill_segment       arm_cortex_a72_fill_segment\n#define fill_block         arm_cortex_a72_fill_block\n#define initialize         arm_cortex_a72_initialize\n#define fill_memory_blocks arm_cortex_a72_fill_memory_blocks\n#define Compress           arm_cortex_a72_argon2_echo_compress\n#define init_block_value   arm_cortex_a72_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a72_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a72_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a72_argon2_echo_finalize\n#define index_alpha        arm_cortex_a72_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a72_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a72_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a72\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a72_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a72_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a72_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a72_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A72_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A72_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a72\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_cortex_a72_aes_next_addresses\n#define fill_segment       arm_cortex_a72_aes_fill_segment\n#define fill_block         arm_cortex_a72_aes_fill_block\n#define initialize         arm_cortex_a72_aes_initialize\n#define fill_memory_blocks arm_cortex_a72_aes_fill_memory_blocks\n#define Compress           arm_cortex_a72_aes_argon2_echo_compress\n#define init_block_value   arm_cortex_a72_aes_argon2_echo_init_block_value\n#define copy_block         arm_cortex_a72_aes_argon2_echo_copy_block_value\n#define xor_block          arm_cortex_a72_aes_argon2_echo_xor_block_value\n#define finalize           arm_cortex_a72_aes_argon2_echo_finalize\n#define index_alpha        arm_cortex_a72_aes_argon2_echo_index_alpha\n#define initial_hash       arm_cortex_a72_aes_argon2_echo_initial_hash\n#define fill_first_blocks  arm_cortex_a72_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_cortex_a72_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                               \\\n{                                                                                            \\\n    echo256_opt_hashState ctx_echo;                                                          \\\n    echo256_opt_arm_cortex_a72_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_cortex_a72_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_cortex_a72_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_cortex_a72_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_cortex_a72_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_CORTEX_A72_AES_H\n#define HASH_ARGON2_ECHO_ARM_CORTEX_A72_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_cortex_a72_aes\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_thunderx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_THUNDERX_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     arm_thunderx_aes_next_addresses\n#define fill_segment       arm_thunderx_aes_fill_segment\n#define fill_block         arm_thunderx_aes_fill_block\n#define initialize         arm_thunderx_aes_initialize\n#define fill_memory_blocks arm_thunderx_aes_fill_memory_blocks\n#define Compress           arm_thunderx_aes_argon2_echo_compress\n#define init_block_value   arm_thunderx_aes_argon2_echo_init_block_value\n#define copy_block         arm_thunderx_aes_argon2_echo_copy_block_value\n#define xor_block          arm_thunderx_aes_argon2_echo_xor_block_value\n#define finalize           arm_thunderx_aes_argon2_echo_finalize\n#define index_alpha        arm_thunderx_aes_argon2_echo_index_alpha\n#define initial_hash       arm_thunderx_aes_argon2_echo_initial_hash\n#define fill_first_blocks  arm_thunderx_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx    argon2_echo_ctx_arm_thunderx_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                                 \\\n{                                                                                              \\\n    echo256_opt_hashState ctx_echo;                                                            \\\n    echo256_opt_arm_thunderx_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_arm_thunderx_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_arm_thunderx_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE2 version that we compile with substituted neon intrinsics and flags; it might theoretically be possible to speed this up with explicit NEON intrinsic design.\nstatic void arm_thunderx_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_arm_thunderx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_ARM_THUNDERX_AES_H\n#define HASH_ARGON2_ECHO_ARM_THUNDERX_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_arm_thunderx_aes\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     avx_next_addresses\n#define fill_segment       avx_fill_segment\n#define fill_block         avx_fill_block\n#define initialize         avx_initialize\n#define fill_memory_blocks avx_fill_memory_blocks\n#define Compress           avx_argon2_echo_compress\n#define init_block_value   avx_argon2_echo_init_block_value\n#define copy_block         avx_argon2_echo_copy_block_value\n#define xor_block          avx_argon2_echo_xor_block_value\n#define finalize           avx_argon2_echo_finalize\n#define index_alpha        avx_argon2_echo_index_alpha\n#define initial_hash       avx_argon2_echo_initial_hash\n#define fill_first_blocks  avx_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                    \\\n{                                                                                 \\\n    echo256_opt_hashState ctx_echo;                                               \\\n    echo256_opt_avx_Init(&ctx_echo);                                              \\\n    echo256_opt_avx_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE3 version that we compile with AVX flags; it might theoretically be possible to speed this up with explicit AVX intrinsics.\nstatic void avx_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX_H\n#define HASH_ARGON2_ECHO_AVX_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx2.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_avx2.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m256i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_HWORDS_IN_BLOCK\n#define next_addresses     avx2_next_addresses\n#define fill_segment       avx2_fill_segment\n#define fill_block         avx2_fill_block\n#define initialize         avx2_initialize\n#define fill_memory_blocks avx2_fill_memory_blocks\n#define Compress           avx2_argon2_echo_compress\n#define init_block_value   avx2_argon2_echo_init_block_value\n#define copy_block         avx2_argon2_echo_copy_block_value\n#define xor_block          avx2_argon2_echo_xor_block_value\n#define finalize           avx2_argon2_echo_finalize\n#define index_alpha        avx2_argon2_echo_index_alpha\n#define initial_hash       avx2_argon2_echo_initial_hash\n#define fill_first_blocks  avx2_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx2\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                     \\\n{                                                                                  \\\n    echo256_opt_hashState ctx_echo;                                                \\\n    echo256_opt_avx2_Init(&ctx_echo);                                              \\\n    echo256_opt_avx2_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx2_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void avx2_fill_block(__m256i* state, const argon2_echo_block* ref_block, argon2_echo_block* next_block, int with_xor)\n{\n    __m256i block_XY[ARGON2_HWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));\n            block_XY[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 4; ++i)\n    {\n        BLAKE2_ROUND_AVX2_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 4; ++i)\n    {\n        BLAKE2_ROUND_AVX2_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], state[16 + i], state[20 + i], state[24 + i], state[28 + i]);\n    }\n\n    for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm256_xor_si256(state[i], block_XY[i]);\n        _mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx2.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX2_H\n#define HASH_ARGON2_ECHO_AVX2_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx2\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx2_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_avx2.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m256i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_HWORDS_IN_BLOCK\n#define next_addresses     avx2_aes_next_addresses\n#define fill_segment       avx2_aes_fill_segment\n#define fill_block         avx2_aes_fill_block\n#define initialize         avx2_aes_initialize\n#define fill_memory_blocks avx2_aes_fill_memory_blocks\n#define Compress           avx2_aes_argon2_echo_compress\n#define init_block_value   avx2_aes_argon2_echo_init_block_value\n#define copy_block         avx2_aes_argon2_echo_copy_block_value\n#define xor_block          avx2_aes_argon2_echo_xor_block_value\n#define finalize           avx2_aes_argon2_echo_finalize\n#define index_alpha        avx2_aes_argon2_echo_index_alpha\n#define initial_hash       avx2_aes_argon2_echo_initial_hash\n#define fill_first_blocks  avx2_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx2_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                         \\\n{                                                                                      \\\n    echo256_opt_hashState ctx_echo;                                                    \\\n    echo256_opt_avx2_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_avx2_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx2_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void avx2_aes_fill_block(__m256i* state, const argon2_echo_block* ref_block, argon2_echo_block* next_block, int with_xor)\n{\n    __m256i block_XY[ARGON2_HWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));\n            block_XY[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 4; ++i)\n    {\n        BLAKE2_ROUND_AVX2_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 4; ++i)\n    {\n        BLAKE2_ROUND_AVX2_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], state[16 + i], state[20 + i], state[24 + i], state[28 + i]);\n    }\n\n    for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm256_xor_si256(state[i], block_XY[i]);\n        _mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx2_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX2_AES_H\n#define HASH_ARGON2_ECHO_AVX2_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx2_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx512f.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_avx512f.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m512i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_512BIT_WORDS_IN_BLOCK\n#define next_addresses     avx512f_next_addresses\n#define fill_segment       avx512f_fill_segment\n#define fill_block         avx512f_fill_block\n#define initialize         avx512f_initialize\n#define fill_memory_blocks avx512f_fill_memory_blocks\n#define Compress           avx512f_argon2_echo_compress\n#define init_block_value   avx512f_argon2_echo_init_block_value\n#define copy_block         avx512f_argon2_echo_copy_block_value\n#define xor_block          avx512f_argon2_echo_xor_block_value\n#define finalize           avx512f_argon2_echo_finalize\n#define index_alpha        avx512f_argon2_echo_index_alpha\n#define initial_hash       avx512f_argon2_echo_initial_hash\n#define fill_first_blocks  avx512f_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx512f\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                        \\\n{                                                                                     \\\n    echo256_opt_hashState ctx_echo;                                                   \\\n    echo256_opt_avx512f_Init(&ctx_echo);                                              \\\n    echo256_opt_avx512f_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx512f_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void avx512f_fill_block(__m512i* state, const argon2_echo_block* ref_block, argon2_echo_block* next_block, int with_xor)\n{\n    __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));\n            block_XY[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 2; ++i)\n    {\n        BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 2; ++i)\n    {\n        BLAKE2_ROUND_2(state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm512_xor_si512(state[i], block_XY[i]);\n        _mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx512f.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX512F_H\n#define HASH_ARGON2_ECHO_AVX512F_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx512f\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx512f_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_avx512f.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m512i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_512BIT_WORDS_IN_BLOCK\n#define next_addresses     avx512f_aes_next_addresses\n#define fill_segment       avx512f_aes_fill_segment\n#define fill_block         avx512f_aes_fill_block\n#define initialize         avx512f_aes_initialize\n#define fill_memory_blocks avx512f_aes_fill_memory_blocks\n#define Compress           avx512f_aes_argon2_echo_compress\n#define init_block_value   avx512f_aes_argon2_echo_init_block_value\n#define copy_block         avx512f_aes_argon2_echo_copy_block_value\n#define xor_block          avx512f_aes_argon2_echo_xor_block_value\n#define finalize           avx512f_aes_argon2_echo_finalize\n#define index_alpha        avx512f_aes_argon2_echo_index_alpha\n#define initial_hash       avx512f_aes_argon2_echo_initial_hash\n#define fill_first_blocks  avx512f_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx512f_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                            \\\n{                                                                                         \\\n    echo256_opt_hashState ctx_echo;                                                       \\\n    echo256_opt_avx512f_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_avx512f_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx512f_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void avx512f_aes_fill_block(__m512i* state, const argon2_echo_block* ref_block, argon2_echo_block* next_block, int with_xor)\n{\n    __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));\n            block_XY[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm512_xor_si512(state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 2; ++i)\n    {\n        BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 2; ++i)\n    {\n        BLAKE2_ROUND_2(state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm512_xor_si512(state[i], block_XY[i]);\n        _mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx512f_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX512F_AES_H\n#define HASH_ARGON2_ECHO_AVX512F_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx512f_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     avx_aes_next_addresses\n#define fill_segment       avx_aes_fill_segment\n#define fill_block         avx_aes_fill_block\n#define initialize         avx_aes_initialize\n#define fill_memory_blocks avx_aes_fill_memory_blocks\n#define Compress           avx_aes_argon2_echo_compress\n#define init_block_value   avx_aes_argon2_echo_init_block_value\n#define copy_block         avx_aes_argon2_echo_copy_block_value\n#define xor_block          avx_aes_argon2_echo_xor_block_value\n#define finalize           avx_aes_argon2_echo_finalize\n#define index_alpha        avx_aes_argon2_echo_index_alpha\n#define initial_hash       avx_aes_argon2_echo_initial_hash\n#define fill_first_blocks  avx_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_avx_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                        \\\n{                                                                                     \\\n    echo256_opt_hashState ctx_echo;                                                   \\\n    echo256_opt_avx_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_avx_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_avx_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE3 version that we compile with AVX flags; it might theoretically be possible to speed this up with explicit AVX intrinsics.\nstatic void avx_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_avx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_AVX_AES_H\n#define HASH_ARGON2_ECHO_AVX_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_avx_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_hybrid.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#include \"../blake2/blamka-round-ref.h\"\n#include \"../blake2/blake2-impl.h\"\n#include \"../blake2/blake2.h\"\n\n#define next_addresses         next_addresses_hybrid\n#define fill_segment             fill_segment_hybrid\n#define fill_block                 fill_block_hybrid\n#define initialize                 initialize_hybrid\n#define fill_memory_blocks fill_memory_blocks_hybrid\n#define argon2_echo_ctx       argon2_echo_ctx_hybrid\n#define init_block_value     init_block_value_hybrid\n#define copy_block                 copy_block_hybrid\n#define xor_block                   xor_block_hybrid\n#define finalize                     finalize_hybrid\n#define fill_first_blocks   fill_first_blocks_hybrid\n#define initial_hash             initial_hash_hybrid\n#define fill_segment_ref         fill_segment_hybrid\n#define fill_segment_thr     fill_segment_thr_hybrid\n#define index_alpha               index_alpha_hybrid\n\n\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                         \\\n{                                                                                      \\\n    echo256_opt_hashState ctx_echo;                                                    \\\n    selected_echo256_opt_Init(&ctx_echo);                                              \\\n    selected_echo256_opt_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    selected_echo256_opt_Final(&ctx_echo, HASH);                                       \\\n}\n\n#define ARGON2_CORE_REF_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n\n/*\n * Function fills a new memory block and optionally XORs the old block over the new one.\n * @next_block must be initialized.\n * @param prev_block Pointer to the previous block\n * @param ref_block Pointer to the reference block\n * @param next_block Pointer to the block to be constructed\n * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)\n * @pre all block pointers must be valid\n */\nstatic void fill_block_hybrid(const argon2_echo_block *prev_block, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    argon2_echo_block blockR, block_tmp;\n    unsigned i;\n\n    copy_block(&blockR, ref_block);\n    xor_block(&blockR, prev_block);\n    copy_block(&block_tmp, &blockR);\n    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */\n    if (with_xor)\n    {\n        /* Saving the next block contents for XOR over: */\n        xor_block(&block_tmp, next_block);\n        /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block + next_block */\n    }\n\n    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then (16,17,..31)... finally (112,113,...127) */\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_NOMSG_REF(\n            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],\n            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],\n            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],\n            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],\n            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],\n            blockR.v[16 * i + 15]);\n    }\n\n    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */\n    for (i = 0; i < 8; i++)\n    {\n        BLAKE2_ROUND_NOMSG_REF(\n            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],\n            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],\n            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],\n            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],\n            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],\n            blockR.v[2 * i + 113]);\n    }\n\n    copy_block(next_block, &block_tmp);\n    xor_block(next_block, &blockR);\n}\n\nstatic void next_addresses_hybrid(argon2_echo_block *address_block, argon2_echo_block *input_block, const argon2_echo_block *zero_block)\n{\n    input_block->v[6]++;\n    fill_block_hybrid(zero_block, input_block, address_block, 0);\n    fill_block_hybrid(zero_block, address_block, address_block, 0);\n}\n\nvoid fill_segment_hybrid(const argon2_echo_instance_t *instance, argon2_echo_position_t position)\n{\n    argon2_echo_block *ref_block = NULL, *curr_block = NULL;\n    argon2_echo_block address_block, input_block, zero_block;\n    uint64_t pseudo_rand, ref_index, ref_lane;\n    uint32_t prev_offset, curr_offset;\n    uint32_t starting_index;\n    uint32_t i;\n    \n    //Always false for Argon2d\n    bool data_independent_addressing = false;\n\n    if (instance == NULL)\n    {\n        return;\n    }\n\n    //data_independent_addressing = (instance->type == Argon2_i) || (instance->type == Argon2_id && (position.pass == 0) && (position.slice < ARGON2_SYNC_POINTS / 2));\n\n    if (data_independent_addressing)\n    {\n        init_block_value(&zero_block, 0);\n        init_block_value(&input_block, 0);\n\n        input_block.v[0] = position.pass;\n        input_block.v[1] = position.lane;\n        input_block.v[2] = position.slice;\n        input_block.v[3] = instance->memory_blocks;\n        input_block.v[4] = instance->passes;\n        //input_block.v[5] = instance->type;\n    }\n\n    starting_index = 0;\n\n    if ((0 == position.pass) && (0 == position.slice))\n    {\n        starting_index = 2; /* we have already generated the first two blocks */\n\n        /* Don't forget to generate the first block of addresses: */\n        if (data_independent_addressing)\n        {\n            next_addresses_hybrid(&address_block, &input_block, &zero_block);\n        }\n    }\n\n    /* Offset of the current block */\n    curr_offset = position.lane * instance->lane_length + position.slice * instance->segment_length + starting_index;\n\n    if (0 == curr_offset % instance->lane_length)\n    {\n        /* Last block in this lane */\n        prev_offset = curr_offset + instance->lane_length - 1;\n    }\n    else\n    {\n        /* Previous block */\n        prev_offset = curr_offset - 1;\n    }\n\n    for (i = starting_index; i < instance->segment_length; ++i, ++curr_offset, ++prev_offset)\n    {\n        /*1.1 Rotating prev_offset if needed */\n        if (curr_offset % instance->lane_length == 1)\n        {\n            prev_offset = curr_offset - 1;\n        }\n\n        /* 1.2 Computing the index of the reference block */\n        /* 1.2.1 Taking pseudo-random value from the previous block */\n        if (data_independent_addressing)\n        {\n            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0)\n            {\n                next_addresses_hybrid(&address_block, &input_block, &zero_block);\n            }\n            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];\n        }\n        else\n        {\n            pseudo_rand = instance->memory[prev_offset].v[0];\n        }\n\n        /* 1.2.2 Computing the lane of the reference block */\n        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;\n\n        if ((position.pass == 0) && (position.slice == 0))\n        {\n            /* Can not reference other lanes yet */\n            ref_lane = position.lane;\n        }\n\n        /* 1.2.3 Computing the number of possible reference block within the\n         * lane.\n         */\n        position.index = i;\n        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, ref_lane == position.lane);\n\n        /* 2 Creating a new block */\n        ref_block = instance->memory + instance->lane_length * ref_lane + ref_index;\n        curr_block = instance->memory + curr_offset;\n\n        if(0 == position.pass)\n        {\n            fill_block_hybrid(instance->memory + prev_offset, ref_block, curr_block, 0);\n        }\n        else\n        {\n            fill_block_hybrid(instance->memory + prev_offset, ref_block, curr_block, 1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_hybrid.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_HYBRID_H\n#define HASH_ARGON2_ECHO_HYBRID_H\n    #define argon2_echo_ctx argon2_echo_ctx_hybrid\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse2.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE2)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse2_next_addresses\n#define fill_segment       sse2_fill_segment\n#define fill_block         sse2_fill_block\n#define initialize         sse2_initialize\n#define fill_memory_blocks sse2_fill_memory_blocks\n#define Compress           sse2_argon2_echo_compress\n#define init_block_value   sse2_argon2_echo_init_block_value\n#define copy_block         sse2_argon2_echo_copy_block_value\n#define xor_block          sse2_argon2_echo_xor_block_value\n#define finalize           sse2_argon2_echo_finalize\n#define index_alpha        sse2_argon2_echo_index_alpha\n#define initial_hash       sse2_argon2_echo_initial_hash\n#define fill_first_blocks  sse2_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse2\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                     \\\n{                                                                                  \\\n    sph_echo256_context ctx_echo;                                                  \\\n    sph_echo256_init(&ctx_echo);                                                   \\\n    sph_echo256(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN);             \\\n    sph_echo256_close(&ctx_echo, HASH);                                            \\\n}\n\nstatic void sse2_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse2.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE2_H\n#define HASH_ARGON2_ECHO_SSE2_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse2\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse2_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE2) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse2.h\"\n#include \"../../echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse2_aes_next_addresses\n#define fill_segment       sse2_aes_fill_segment\n#define fill_block         sse2_aes_fill_block\n#define initialize         sse2_aes_initialize\n#define fill_memory_blocks sse2_aes_fill_memory_blocks\n#define Compress           sse2_aes_argon2_echo_compress\n#define init_block_value   sse2_aes_argon2_echo_init_block_value\n#define copy_block         sse2_aes_argon2_echo_copy_block_value\n#define xor_block          sse2_aes_argon2_echo_xor_block_value\n#define finalize           sse2_aes_argon2_echo_finalize\n#define index_alpha        sse2_aes_argon2_echo_index_alpha\n#define initial_hash       sse2_aes_argon2_echo_initial_hash\n#define fill_first_blocks  sse2_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse2_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                         \\\n{                                                                                      \\\n    echo256_opt_sse2_aes_hashState ctx_echo;                                           \\\n    echo256_opt_sse2_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_sse2_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_sse2_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void sse2_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE2(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse2_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE2_AES_H\n#define HASH_ARGON2_ECHO_SSE2_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse2_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse3.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse3_next_addresses\n#define fill_segment       sse3_fill_segment\n#define fill_block         sse3_fill_block\n#define initialize         sse3_initialize\n#define fill_memory_blocks sse3_fill_memory_blocks\n#define Compress           sse3_argon2_echo_compress\n#define init_block_value   sse3_argon2_echo_init_block_value\n#define copy_block         sse3_argon2_echo_copy_block_value\n#define xor_block          sse3_argon2_echo_xor_block_value\n#define finalize           sse3_argon2_echo_finalize\n#define index_alpha        sse3_argon2_echo_index_alpha\n#define initial_hash       sse3_argon2_echo_initial_hash\n#define fill_first_blocks  sse3_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse3\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                     \\\n{                                                                                  \\\n    echo256_opt_hashState ctx_echo;                                                \\\n    echo256_opt_sse3_Init(&ctx_echo);                                              \\\n    echo256_opt_sse3_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_sse3_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void sse3_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse3.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE3_H\n#define HASH_ARGON2_ECHO_SSE3_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse3\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse3_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse3_aes_next_addresses\n#define fill_segment       sse3_aes_fill_segment\n#define fill_block         sse3_aes_fill_block\n#define initialize         sse3_aes_initialize\n#define fill_memory_blocks sse3_aes_fill_memory_blocks\n#define Compress           sse3_aes_argon2_echo_compress\n#define init_block_value   sse3_aes_argon2_echo_init_block_value\n#define copy_block         sse3_aes_argon2_echo_copy_block_value\n#define xor_block          sse3_aes_argon2_echo_xor_block_value\n#define finalize           sse3_aes_argon2_echo_finalize\n#define index_alpha        sse3_aes_argon2_echo_index_alpha\n#define initial_hash       sse3_aes_argon2_echo_initial_hash\n#define fill_first_blocks  sse3_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse3_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                         \\\n{                                                                                      \\\n    echo256_opt_hashState ctx_echo;                                                    \\\n    echo256_opt_sse3_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_sse3_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_sse3_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\nstatic void sse3_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse3_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE3_AES_H\n#define HASH_ARGON2_ECHO_SSE3_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse3_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse4.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse4_next_addresses\n#define fill_segment       sse4_fill_segment\n#define fill_block         sse4_fill_block\n#define initialize         sse4_initialize\n#define fill_memory_blocks sse4_fill_memory_blocks\n#define Compress           sse4_argon2_echo_compress\n#define init_block_value   sse4_argon2_echo_init_block_value\n#define copy_block         sse4_argon2_echo_copy_block_value\n#define xor_block          sse4_argon2_echo_xor_block_value\n#define finalize           sse4_argon2_echo_finalize\n#define index_alpha        sse4_argon2_echo_index_alpha\n#define initial_hash       sse4_argon2_echo_initial_hash\n#define fill_first_blocks  sse4_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse4\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                     \\\n{                                                                                  \\\n    echo256_opt_hashState ctx_echo;                                                \\\n    echo256_opt_sse4_Init(&ctx_echo);                                              \\\n    echo256_opt_sse4_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_sse4_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE3 version that we compile with SSE4 flags; it might theoretically be possible to speed this up with explicit SSE4 intrinsics.\nstatic void sse4_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse4.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE4_H\n#define HASH_ARGON2_ECHO_SSE4_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse4\n\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse4_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4) && defined(COMPILER_HAS_AES)\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"../blake2/blake2.h\"\n#include \"../blake2/blamka-round-opt_sse3.h\"\n#include \"../../../sigma/echo256/echo256_opt.h\"\n#include \"../argon_echo.h\"\n#include \"../core.h\"\n\n#define ARGON2_BLOCK_WORD_SIZE __m128i\n#define ARGON2_BLOCK_WORD_COUNT ARGON2_OWORDS_IN_BLOCK\n#define next_addresses     sse4_aes_next_addresses\n#define fill_segment       sse4_aes_fill_segment\n#define fill_block         sse4_aes_fill_block\n#define initialize         sse4_aes_initialize\n#define fill_memory_blocks sse4_aes_fill_memory_blocks\n#define Compress           sse4_aes_argon2_echo_compress\n#define init_block_value   sse4_aes_argon2_echo_init_block_value\n#define copy_block         sse4_aes_argon2_echo_copy_block_value\n#define xor_block          sse4_aes_argon2_echo_xor_block_value\n#define finalize           sse4_aes_argon2_echo_finalize\n#define index_alpha        sse4_aes_argon2_echo_index_alpha\n#define initial_hash       sse4_aes_argon2_echo_initial_hash\n#define fill_first_blocks  sse4_aes_argon2_echo_fill_first_blocks\n\n#define argon2_echo_ctx argon2_echo_ctx_sse4_aes\n\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                         \\\n{                                                                                      \\\n    echo256_opt_hashState ctx_echo;                                                    \\\n    echo256_opt_sse4_aes_Init(&ctx_echo);                                              \\\n    echo256_opt_sse4_aes_Update(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN); \\\n    echo256_opt_sse4_aes_Final(&ctx_echo, HASH);                                       \\\n}\n\n//fixme: (SIGMA) (CBSU) - This is just a direct copy of the SSE3 version that we compile with SSE4 flags; it might theoretically be possible to speed this up with explicit SSE4 intrinsics.\nstatic void sse4_aes_fill_block(__m128i *state, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];\n    unsigned int i;\n\n    if (with_xor)\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n            block_XY[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));\n        }\n    }\n    else\n    {\n        for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n        {\n            block_XY[i] = state[i] = _mm_xor_si128(state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));\n        }\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);\n    }\n\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_SSE3(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);\n    }\n\n    for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++)\n    {\n        state[i] = _mm_xor_si128(state[i], block_XY[i]);\n        _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);\n    }\n}\n\n#define USE_HARDWARE_AES\n#define ARGON2_CORE_OPT_IMPL\n#include \"../core.cpp\"\n#include \"../argon2.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/opt/core_opt_sse4_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'argon2_echo_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ARGON2_ECHO_SSE4_AES_H\n#define HASH_ARGON2_ECHO_SSE4_AES_H\n    #define argon2_echo_ctx argon2_echo_ctx_sse4_aes\n\n    #define USE_HARDWARE_AES\n    #define ARGON2_CORE_OPT_IMPL\n    #include \"../argon_echo.h\"\n    #undef ARGON2_CORE_OPT_IMPL\n\n    #undef argon2_echo_ctx\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/argon_echo/ref.cpp",
    "content": "/*\n * Argon2 reference source code package - reference C implementations\n *\n * Copyright 2015\n * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves\n *\n * You may use this work under the terms of a Creative Commons CC0 1.0\n * License/Waiver or the Apache Public License 2.0, at your option. The terms of\n * these licenses can be found at:\n *\n * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0\n * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0\n *\n * You should have received a copy of both of these licenses along with this\n * software. If not, they may be obtained at the above URLs.\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"argon_echo.h\"\n#include \"core.h\"\n\n#include \"blake2/blamka-round-ref.h\"\n#include \"blake2/blake2-impl.h\"\n#include \"blake2/blake2.h\"\n\n#define next_addresses next_addresses_ref\n#define fill_segment fill_segment_ref\n#define fill_block fill_block_ref\n#define initialize initialize_ref\n#define fill_memory_blocks fill_memory_blocks_ref\n#define argon2_echo_ctx argon2_echo_ctx_ref\n#define ECHO_HASH_256(DATA, DATABYTELEN, HASH)                                  \\\n{                                                                               \\\n    sph_echo256_context ctx_echo;                                               \\\n    sph_echo256_init(&ctx_echo);                                                \\\n    sph_echo256(&ctx_echo, (const unsigned char*)(DATA), DATABYTELEN);          \\\n    sph_echo256_close(&ctx_echo, HASH);                                         \\\n}\n\n#define ARGON2_CORE_REF_IMPL\n#include \"core.cpp\"\n#include \"argon2.cpp\"\n\n/*\n * Function fills a new memory block and optionally XORs the old block over the new one.\n * @next_block must be initialized.\n * @param prev_block Pointer to the previous block\n * @param ref_block Pointer to the reference block\n * @param next_block Pointer to the block to be constructed\n * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)\n * @pre all block pointers must be valid\n */\nstatic void fill_block_ref(const argon2_echo_block *prev_block, const argon2_echo_block *ref_block, argon2_echo_block *next_block, int with_xor)\n{\n    argon2_echo_block blockR, block_tmp;\n    unsigned i;\n\n    copy_block(&blockR, ref_block);\n    xor_block(&blockR, prev_block);\n    copy_block(&block_tmp, &blockR);\n    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */\n    if (with_xor)\n    {\n        /* Saving the next block contents for XOR over: */\n        xor_block(&block_tmp, next_block);\n        /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block + next_block */\n    }\n\n    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then (16,17,..31)... finally (112,113,...127) */\n    for (i = 0; i < 8; ++i)\n    {\n        BLAKE2_ROUND_NOMSG_REF(\n            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],\n            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],\n            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],\n            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],\n            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],\n            blockR.v[16 * i + 15]);\n    }\n\n    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */\n    for (i = 0; i < 8; i++)\n    {\n        BLAKE2_ROUND_NOMSG_REF(\n            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],\n            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],\n            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],\n            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],\n            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],\n            blockR.v[2 * i + 113]);\n    }\n\n    copy_block(next_block, &block_tmp);\n    xor_block(next_block, &blockR);\n}\n\nstatic void next_addresses_ref(argon2_echo_block *address_block, argon2_echo_block *input_block, const argon2_echo_block *zero_block)\n{\n    input_block->v[6]++;\n    fill_block_ref(zero_block, input_block, address_block, 0);\n    fill_block_ref(zero_block, address_block, address_block, 0);\n}\n\nvoid fill_segment_ref(const argon2_echo_instance_t *instance, argon2_echo_position_t position)\n{\n    argon2_echo_block *ref_block = NULL, *curr_block = NULL;\n    argon2_echo_block address_block, input_block, zero_block;\n    uint64_t pseudo_rand, ref_index, ref_lane;\n    uint32_t prev_offset, curr_offset;\n    uint32_t starting_index;\n    uint32_t i;\n    \n    //Always false for Argon2d\n    bool data_independent_addressing = false;\n\n    if (instance == NULL)\n    {\n        return;\n    }\n\n    //data_independent_addressing = (instance->type == Argon2_i) || (instance->type == Argon2_id && (position.pass == 0) && (position.slice < ARGON2_SYNC_POINTS / 2));\n\n    if (data_independent_addressing)\n    {\n        init_block_value(&zero_block, 0);\n        init_block_value(&input_block, 0);\n\n        input_block.v[0] = position.pass;\n        input_block.v[1] = position.lane;\n        input_block.v[2] = position.slice;\n        input_block.v[3] = instance->memory_blocks;\n        input_block.v[4] = instance->passes;\n        //input_block.v[5] = instance->type;\n    }\n\n    starting_index = 0;\n\n    if ((0 == position.pass) && (0 == position.slice))\n    {\n        starting_index = 2; /* we have already generated the first two blocks */\n\n        /* Don't forget to generate the first block of addresses: */\n        if (data_independent_addressing)\n        {\n            next_addresses_ref(&address_block, &input_block, &zero_block);\n        }\n    }\n\n    /* Offset of the current block */\n    curr_offset = position.lane * instance->lane_length + position.slice * instance->segment_length + starting_index;\n\n    if (0 == curr_offset % instance->lane_length)\n    {\n        /* Last block in this lane */\n        prev_offset = curr_offset + instance->lane_length - 1;\n    }\n    else\n    {\n        /* Previous block */\n        prev_offset = curr_offset - 1;\n    }\n\n    for (i = starting_index; i < instance->segment_length; ++i, ++curr_offset, ++prev_offset)\n    {\n        /*1.1 Rotating prev_offset if needed */\n        if (curr_offset % instance->lane_length == 1)\n        {\n            prev_offset = curr_offset - 1;\n        }\n\n        /* 1.2 Computing the index of the reference block */\n        /* 1.2.1 Taking pseudo-random value from the previous block */\n        if (data_independent_addressing)\n        {\n            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0)\n            {\n                next_addresses_ref(&address_block, &input_block, &zero_block);\n            }\n            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];\n        }\n        else\n        {\n            pseudo_rand = instance->memory[prev_offset].v[0];\n        }\n\n        /* 1.2.2 Computing the lane of the reference block */\n        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;\n\n        if ((position.pass == 0) && (position.slice == 0))\n        {\n            /* Can not reference other lanes yet */\n            ref_lane = position.lane;\n        }\n\n        /* 1.2.3 Computing the number of possible reference block within the\n         * lane.\n         */\n        position.index = i;\n        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, ref_lane == position.lane);\n\n        /* 2 Creating a new block */\n        ref_block = instance->memory + instance->lane_length * ref_lane + ref_index;\n        curr_block = instance->memory + curr_offset;\n\n        if(0 == position.pass)\n        {\n            fill_block_ref(instance->memory + prev_offset, ref_block, curr_block, 0);\n        }\n        else\n        {\n            fill_block_ref(instance->memory + prev_offset, ref_block, curr_block, 1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/COPYING",
    "content": "The files in this folder are derived from the supercop library in some cases with major modifications.\nPlease consult the comments in each individual file for author attribution and copyright/licensing specifics.\n\nUnless specified otherwise inside the file or if not explicitely specified the licensing of the Supercop project applies. \n\nSupercop licensing:\nThis Work was prepared by a United States Government employee and, therefore, is excluded from copyright by Section 105 of the Copyright Act of 1976.\nCopyright and Related Rights in the Work worldwide are waived through the CC0 1.0 Universal license.\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/echo256_opt.cpp",
    "content": "/*\n * file        : echo_vperm.c\n * version     : 1.0.208\n * date        : 14.12.2010\n * \n * - vperm and aes_ni implementations of hash function ECHO\n * - implements NIST hash api\n * - assumes that message length is multiple of 8-bits\n * - _ECHO_VPERM_ must be defined if compiling with ../main.c\n * -  define NO_AES_NI for aes_ni version\n *\n * Cagdas Calik\n * ccalik@metu.edu.tr\n * Institute of Applied Mathematics, Middle East Technical University, Turkey.\n *\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <stdint.h>\n#include \"echo256_opt.h\"\n\n#ifndef USE_HARDWARE_AES\n#define _mm_aesenc_si128 _mm_aesenc_si128_sw\n#endif\n\n#ifdef ECHO256_OPT_IMPL\n\n#include <memory.h>\n#define M128(x) *((__m128i*)x)\n\n__attribute__((aligned(16))) const unsigned int const1[]        = {0x00000001, 0x00000000, 0x00000000, 0x00000000};\n__attribute__((aligned(16))) const unsigned int mul2mask[]      = {0x00001b00, 0x00000000, 0x00000000, 0x00000000};\n__attribute__((aligned(16))) const unsigned int lsbmask[]       = {0x01010101, 0x01010101, 0x01010101, 0x01010101};\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n#define ECHO_SUBBYTES(state, i, j) \\\n    state[i][j] = _mm_aesenc_si128(state[i][j], k1);\\\n    state[i][j] = _mm_aesenc_si128(state[i][j], _mm_setzero_si128());\\\n    k1 = _mm_add_epi32(k1, M128(const1))\n\n#define ECHO_MIXBYTES(state1, state2, j, t1, t2, s2) \\\n    s2 = _mm_add_epi8(state1[0][j], state1[0][j]);\\\n    t1 = _mm_srli_epi16(state1[0][j], 7);\\\n    t1 = _mm_and_si128(t1, M128(lsbmask));\\\n    t2 = _mm_shuffle_epi8(M128(mul2mask), t1);\\\n    s2 = _mm_xor_si128(s2, t2);\\\n    state2[0][j] = s2;\\\n    state2[1][j] = state1[0][j];\\\n    state2[2][j] = state1[0][j];\\\n    state2[3][j] = _mm_xor_si128(s2, state1[0][j]);\\\n    s2 = _mm_add_epi8(state1[1][(j + 1) & 3], state1[1][(j + 1) & 3]);\\\n    t1 = _mm_srli_epi16(state1[1][(j + 1) & 3], 7);\\\n    t1 = _mm_and_si128(t1, M128(lsbmask));\\\n    t2 = _mm_shuffle_epi8(M128(mul2mask), t1);\\\n    s2 = _mm_xor_si128(s2, t2);\\\n    state2[0][j] = _mm_xor_si128(state2[0][j], _mm_xor_si128(s2, state1[1][(j + 1) & 3]));\\\n    state2[1][j] = _mm_xor_si128(state2[1][j], s2);\\\n    state2[2][j] = _mm_xor_si128(state2[2][j], state1[1][(j + 1) & 3]);\\\n    state2[3][j] = _mm_xor_si128(state2[3][j], state1[1][(j + 1) & 3]);\\\n    s2 = _mm_add_epi8(state1[2][(j + 2) & 3], state1[2][(j + 2) & 3]);\\\n    t1 = _mm_srli_epi16(state1[2][(j + 2) & 3], 7);\\\n    t1 = _mm_and_si128(t1, M128(lsbmask));\\\n    t2 = _mm_shuffle_epi8(M128(mul2mask), t1);\\\n    s2 = _mm_xor_si128(s2, t2);\\\n    state2[0][j] = _mm_xor_si128(state2[0][j], state1[2][(j + 2) & 3]);\\\n    state2[1][j] = _mm_xor_si128(state2[1][j], _mm_xor_si128(s2, state1[2][(j + 2) & 3]));\\\n    state2[2][j] = _mm_xor_si128(state2[2][j], s2);\\\n    state2[3][j] = _mm_xor_si128(state2[3][j], state1[2][(j + 2) & 3]);\\\n    s2 = _mm_add_epi8(state1[3][(j + 3) & 3], state1[3][(j + 3) & 3]);\\\n    t1 = _mm_srli_epi16(state1[3][(j + 3) & 3], 7);\\\n    t1 = _mm_and_si128(t1, M128(lsbmask));\\\n    t2 = _mm_shuffle_epi8(M128(mul2mask), t1);\\\n    s2 = _mm_xor_si128(s2, t2);\\\n    state2[0][j] = _mm_xor_si128(state2[0][j], state1[3][(j + 3) & 3]);\\\n    state2[1][j] = _mm_xor_si128(state2[1][j], state1[3][(j + 3) & 3]);\\\n    state2[2][j] = _mm_xor_si128(state2[2][j], _mm_xor_si128(s2, state1[3][(j + 3) & 3]));\\\n    state2[3][j] = _mm_xor_si128(state2[3][j], s2)\n\n\n#define ECHO_ROUND_UNROLL2 \\\n    ECHO_SUBBYTES(_state, 0, 0);\\\n    ECHO_SUBBYTES(_state, 1, 0);\\\n    ECHO_SUBBYTES(_state, 2, 0);\\\n    ECHO_SUBBYTES(_state, 3, 0);\\\n    ECHO_SUBBYTES(_state, 0, 1);\\\n    ECHO_SUBBYTES(_state, 1, 1);\\\n    ECHO_SUBBYTES(_state, 2, 1);\\\n    ECHO_SUBBYTES(_state, 3, 1);\\\n    ECHO_SUBBYTES(_state, 0, 2);\\\n    ECHO_SUBBYTES(_state, 1, 2);\\\n    ECHO_SUBBYTES(_state, 2, 2);\\\n    ECHO_SUBBYTES(_state, 3, 2);\\\n    ECHO_SUBBYTES(_state, 0, 3);\\\n    ECHO_SUBBYTES(_state, 1, 3);\\\n    ECHO_SUBBYTES(_state, 2, 3);\\\n    ECHO_SUBBYTES(_state, 3, 3);\\\n    ECHO_MIXBYTES(_state, _state2, 0, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state, _state2, 1, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state, _state2, 2, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state, _state2, 3, t1, t2, s2);\\\n    ECHO_SUBBYTES(_state2, 0, 0);\\\n    ECHO_SUBBYTES(_state2, 1, 0);\\\n    ECHO_SUBBYTES(_state2, 2, 0);\\\n    ECHO_SUBBYTES(_state2, 3, 0);\\\n    ECHO_SUBBYTES(_state2, 0, 1);\\\n    ECHO_SUBBYTES(_state2, 1, 1);\\\n    ECHO_SUBBYTES(_state2, 2, 1);\\\n    ECHO_SUBBYTES(_state2, 3, 1);\\\n    ECHO_SUBBYTES(_state2, 0, 2);\\\n    ECHO_SUBBYTES(_state2, 1, 2);\\\n    ECHO_SUBBYTES(_state2, 2, 2);\\\n    ECHO_SUBBYTES(_state2, 3, 2);\\\n    ECHO_SUBBYTES(_state2, 0, 3);\\\n    ECHO_SUBBYTES(_state2, 1, 3);\\\n    ECHO_SUBBYTES(_state2, 2, 3);\\\n    ECHO_SUBBYTES(_state2, 3, 3);\\\n    ECHO_MIXBYTES(_state2, _state, 0, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state2, _state, 1, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state2, _state, 2, t1, t2, s2);\\\n    ECHO_MIXBYTES(_state2, _state, 3, t1, t2, s2)\n\n\n\n#define SAVESTATE(dst, src)\\\n    dst[0][0] = src[0][0];\\\n    dst[0][1] = src[0][1];\\\n    dst[0][2] = src[0][2];\\\n    dst[0][3] = src[0][3];\\\n    dst[1][0] = src[1][0];\\\n    dst[1][1] = src[1][1];\\\n    dst[1][2] = src[1][2];\\\n    dst[1][3] = src[1][3];\\\n    dst[2][0] = src[2][0];\\\n    dst[2][1] = src[2][1];\\\n    dst[2][2] = src[2][2];\\\n    dst[2][3] = src[2][3];\\\n    dst[3][0] = src[3][0];\\\n    dst[3][1] = src[3][1];\\\n    dst[3][2] = src[3][2];\\\n    dst[3][3] = src[3][3]\n\n\n\nvoid Compress(echo256_opt_hashState* ctx, const unsigned char* pmsg, unsigned int uBlockCount)\n{    \n    unsigned int r, b, i, j;\n    __m128i t1, t2, s2, k1;\n    __m128i _state[4][4], _state2[4][4], _statebackup[4][4]; \n\n    for(i = 0; i < 4; i++)\n    {\n        _state[i][0] = ctx->state[i][0];\n    }\n\n    for(b = 0; b < uBlockCount; b++)\n    {\n        ctx->k = _mm_add_epi64(ctx->k, ctx->const1536);\n\n        // load message\n        for(j = 1; j < 4; j++)\n        {\n            for(i = 0; i < 4; i++)\n            {\n                _state[i][j] = _mm_loadu_si128((__m128i*)pmsg + 4 * (j - 1) + i);\n            }\n        }\n\n        // save state\n        SAVESTATE(_statebackup, _state);\n\n        k1 = ctx->k;\n\n        for(r = 0; r < ctx->uRounds / 2; r++)\n        {\n            ECHO_ROUND_UNROLL2;\n        }\n\n        for(i = 0; i < 4; i++)\n        {\n            _state[i][0] = _mm_xor_si128(_state[i][0], _state[i][1]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _state[i][2]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _state[i][3]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _statebackup[i][0]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _statebackup[i][1]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _statebackup[i][2]);\n            _state[i][0] = _mm_xor_si128(_state[i][0], _statebackup[i][3]);\n        }\n        pmsg += ctx->uBlockLength;\n    }\n    SAVESTATE(ctx->state, _state);\n}\n#pragma GCC diagnostic pop\n\n\n__attribute__((aligned(16))) const unsigned int constinit1[] = {0x00000100, 0x00000000, 0x00000000, 0x00000000};\n__attribute__((aligned(16))) const unsigned int constinit2[] = {0x00000600, 0x00000000, 0x00000000, 0x00000000};\n\nHashReturn echo256_opt_Init(echo256_opt_hashState *ctx)\n{\n    int i, j;\n\n    ctx->k = _mm_setzero_si128(); \n    ctx->processed_bits = 0;\n    ctx->uBufferBytes = 0;\n\n    ctx->uHashSize = 256;\n    ctx->uBlockLength = 192;\n    ctx->uRounds = 8;\n    ctx->hashsize = _mm_loadu_si128((__m128i*)constinit1);\n    ctx->const1536 = _mm_loadu_si128((__m128i*)constinit2);\n\n    for(i = 0; i < 4; i++)\n    {\n        ctx->state[i][0] = ctx->hashsize;\n    }\n\n    for(i = 0; i < 4; i++)\n    {\n        for(j = 1; j < 4; j++)\n        {\n            ctx->state[i][j] = _mm_setzero_si128();\n        }\n    }\n    return SUCCESS;\n}\n\nHashReturn echo256_opt_Update(echo256_opt_hashState* state, const unsigned char* data, uint64_t dataByteLength)\n{\n    unsigned int uBlockCount, uRemainingBytes;\n\n    if((state->uBufferBytes + dataByteLength) >= state->uBlockLength)\n    {\n        if(state->uBufferBytes != 0)\n        {\n            // Fill the buffer\n            memcpy(state->buffer + state->uBufferBytes, (void*)data, state->uBlockLength - state->uBufferBytes);\n\n            // Process buffer\n            Compress(state, state->buffer, 1);\n            state->processed_bits += state->uBlockLength * 8;\n\n            data += state->uBlockLength - state->uBufferBytes;\n            dataByteLength -= state->uBlockLength - state->uBufferBytes;\n        }\n\n        // buffer now does not contain any unprocessed bytes\n\n        uBlockCount = dataByteLength / state->uBlockLength;\n        uRemainingBytes = dataByteLength % state->uBlockLength;\n\n        if(uBlockCount > 0)\n        {\n            Compress(state, data, uBlockCount);\n\n            state->processed_bits += uBlockCount * state->uBlockLength * 8;\n            data += uBlockCount * state->uBlockLength;\n        }\n\n        if(uRemainingBytes > 0)\n        {\n            memcpy(state->buffer, (void*)data, uRemainingBytes);\n        }\n\n        state->uBufferBytes = uRemainingBytes;\n    }\n    else\n    {\n        memcpy(state->buffer + state->uBufferBytes, (void*)data, dataByteLength);\n        state->uBufferBytes += dataByteLength;\n    }\n\n    return SUCCESS;\n}\n\nHashReturn echo256_opt_Final(echo256_opt_hashState* state, unsigned char* hashval)\n{\n    __m128i remainingbits;\n\n    // Add remaining bytes in the buffer\n    state->processed_bits += state->uBufferBytes * 8;\n\n    __attribute__((aligned(16))) const unsigned int load_buffer_bytes[] = {state->uBufferBytes * 8, 0x00000000, 0x00000000, 0x00000000};\n    remainingbits = _mm_loadu_si128((__m128i*)load_buffer_bytes);\n\n    // Pad with 0x80\n    state->buffer[state->uBufferBytes++] = 0x80;\n\n    // Enough buffer space for padding in this block?\n    if((state->uBlockLength - state->uBufferBytes) >= 18)\n    {\n        // Pad with zeros\n        memset(state->buffer + state->uBufferBytes, 0, state->uBlockLength - (state->uBufferBytes + 18));\n\n        // Hash size\n        *((unsigned short*)(state->buffer + state->uBlockLength - 18)) = state->uHashSize;\n\n        // Processed bits\n        *((uint64_t*)(state->buffer + state->uBlockLength - 16)) = state->processed_bits;\n        *((uint64_t*)(state->buffer + state->uBlockLength - 8)) = 0;\n\n        // Last block contains message bits?\n        if(state->uBufferBytes == 1)\n        {\n            state->k = _mm_xor_si128(state->k, state->k);\n            state->k = _mm_sub_epi64(state->k, state->const1536);\n        }\n        else\n        {\n            state->k = _mm_add_epi64(state->k, remainingbits);\n            state->k = _mm_sub_epi64(state->k, state->const1536);\n        }\n\n        // Compress\n        Compress(state, state->buffer, 1);\n    }\n    else\n    {\n        // Fill with zero and compress\n        memset(state->buffer + state->uBufferBytes, 0, state->uBlockLength - state->uBufferBytes);\n        state->k = _mm_add_epi64(state->k, remainingbits);\n        state->k = _mm_sub_epi64(state->k, state->const1536);\n        Compress(state, state->buffer, 1);\n\n        // Last block\n        memset(state->buffer, 0, state->uBlockLength - 18);\n\n        // Hash size\n        *((unsigned short*)(state->buffer + state->uBlockLength - 18)) = state->uHashSize;\n\n        // Processed bits\n        *((uint64_t*)(state->buffer + state->uBlockLength - 16)) = state->processed_bits;\n        *((uint64_t*)(state->buffer + state->uBlockLength - 8)) = 0;\n\n        // Compress the last block\n        state->k = _mm_xor_si128(state->k, state->k);\n        state->k = _mm_sub_epi64(state->k, state->const1536);\n        Compress(state, state->buffer, 1);\n    }\n\n    // Store the hash value\n    _mm_storeu_si128((__m128i*)hashval + 0, state->state[0][0]);\n    _mm_storeu_si128((__m128i*)hashval + 1, state->state[1][0]);\n\n    return SUCCESS;\n}\n\nHashReturn echo256_opt_UpdateFinal( echo256_opt_hashState* state, unsigned char* hashval, const unsigned char* data, uint64_t dataByteLength )\n{\n    unsigned int uBlockCount, uRemainingBytes;\n\n    if( (state->uBufferBytes + dataByteLength) >= state->uBlockLength )\n    {\n        if( state->uBufferBytes != 0 )\n        {\n            // Fill the buffer\n            memcpy( state->buffer + state->uBufferBytes, (void*)data, state->uBlockLength - state->uBufferBytes );\n\n            // Process buffer\n            Compress( state, state->buffer, 1 );\n            state->processed_bits += state->uBlockLength * 8;\n\n            data += state->uBlockLength - state->uBufferBytes;\n            dataByteLength -= state->uBlockLength - state->uBufferBytes;\n        }\n\n        // buffer now does not contain any unprocessed bytes\n\n        uBlockCount = dataByteLength / state->uBlockLength;\n        uRemainingBytes = dataByteLength % state->uBlockLength;\n\n        if( uBlockCount > 0 )\n        {\n            Compress( state, data, uBlockCount );\n            state->processed_bits += uBlockCount * state->uBlockLength * 8;\n            data += uBlockCount * state->uBlockLength;\n        }\n\n        if( uRemainingBytes > 0 )\n        memcpy(state->buffer, (void*)data, uRemainingBytes);\n\n        state->uBufferBytes = uRemainingBytes;\n    }\n    else\n    {\n        memcpy( state->buffer + state->uBufferBytes, (void*)data, dataByteLength );\n        state->uBufferBytes += dataByteLength;\n    }\n\n    __m128i remainingbits;\n\n    // Add remaining bytes in the buffer\n    state->processed_bits += state->uBufferBytes * 8;\n\n    __attribute__((aligned(16))) const unsigned int load_buffer_bytes[] = {state->uBufferBytes * 8, 0x00000000, 0x00000000, 0x00000000};\n    remainingbits = _mm_loadu_si128((__m128i*)load_buffer_bytes);\n\n    // Pad with 0x80\n    state->buffer[state->uBufferBytes++] = 0x80;\n    // Enough buffer space for padding in this block?\n    if( (state->uBlockLength - state->uBufferBytes) >= 18 )\n    {\n        // Pad with zeros\n        memset( state->buffer + state->uBufferBytes, 0, state->uBlockLength - (state->uBufferBytes + 18) );\n\n        // Hash size\n        *( (unsigned short*)(state->buffer + state->uBlockLength - 18) ) = state->uHashSize;\n\n        // Processed bits\n        *( (uint64_t*)(state->buffer + state->uBlockLength - 16) ) = state->processed_bits;\n        *( (uint64_t*)(state->buffer + state->uBlockLength - 8) ) = 0;\n\n        // Last block contains message bits?\n        if( state->uBufferBytes == 1 )\n        {\n            state->k = _mm_xor_si128( state->k, state->k );\n            state->k = _mm_sub_epi64( state->k, state->const1536 );\n        }\n        else\n        {\n            state->k = _mm_add_epi64( state->k, remainingbits );\n            state->k = _mm_sub_epi64( state->k, state->const1536 );\n        }\n\n        // Compress\n        Compress( state, state->buffer, 1 );\n    }\n    else\n    {\n        // Fill with zero and compress\n        memset( state->buffer + state->uBufferBytes, 0, state->uBlockLength - state->uBufferBytes );\n        state->k = _mm_add_epi64( state->k, remainingbits );\n        state->k = _mm_sub_epi64( state->k, state->const1536 );\n        Compress( state, state->buffer, 1 );\n\n        // Last block\n        memset( state->buffer, 0, state->uBlockLength - 18 );\n\n        // Hash size\n        *( (unsigned short*)(state->buffer + state->uBlockLength - 18) ) = state->uHashSize;\n\n        // Processed bits\n        *( (uint64_t*)(state->buffer + state->uBlockLength - 16) ) = state->processed_bits;\n        *( (uint64_t*)(state->buffer + state->uBlockLength - 8) ) = 0;\n        // Compress the last block\n        state->k = _mm_xor_si128( state->k, state->k );\n        state->k = _mm_sub_epi64( state->k, state->const1536 );\n        Compress( state, state->buffer, 1) ;\n    }\n\n    // Store the hash value\n    _mm_storeu_si128( (__m128i*)hashval + 0, state->state[0][0] );\n    _mm_storeu_si128( (__m128i*)hashval + 1, state->state[1][0] );\n\n    return SUCCESS;\n}\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/echo256_opt.h",
    "content": "/*\n * file        : hash_api.h\n * version     : 1.0.208\n * date        : 14.12.2010\n * \n * ECHO vperm implementation Hash API\n *\n * Cagdas Calik\n * ccalik@metu.edu.tr\n * Institute of Applied Mathematics, Middle East Technical University, Turkey.\n *\n */\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef ECHO256_OPT_H\n#define ECHO256_OPT_H\nenum HashReturn\n{\n    SUCCESS = 0,\n    FAIL = 1,\n    BAD_HASHBITLEN = 2\n};\n\n#include \"compat.h\"\n#include <compat/arch.h>\n#include <compat/sse.h>\ntypedef struct\n{\n    __m128i        state[4][4];\n    unsigned char  buffer[192];\n    __m128i        k;\n    __m128i        hashsize;\n    __m128i        const1536;\n    unsigned int   uRounds;\n    unsigned int   uHashSize;\n    unsigned int   uBlockLength;\n    unsigned int   uBufferBytes;\n    uint64_t       processed_bits;\n} echo256_opt_hashState __attribute__ ((aligned (64)));\n\nextern HashReturn (*selected_echo256_opt_Init)(echo256_opt_hashState* state);\nextern HashReturn (*selected_echo256_opt_Update)(echo256_opt_hashState* state, const unsigned char* data, uint64_t databitlen);\nextern HashReturn (*selected_echo256_opt_Final)(echo256_opt_hashState* state, unsigned char* hashval);\nextern HashReturn (*selected_echo256_opt_UpdateFinal)(echo256_opt_hashState* state, unsigned char* hashval, const unsigned char* data, uint64_t databitlen);\n#endif\n\n#ifndef ECHO256_OPT_IMPL\n\n#ifdef ARCH_CPU_X86_FAMILY\n#include \"opt/echo256_opt_sse3.h\"\n#include \"opt/echo256_opt_sse3_aes.h\"\n#include \"opt/echo256_opt_sse4.h\"\n#include \"opt/echo256_opt_sse4_aes.h\"\n#include \"opt/echo256_opt_avx.h\"\n#include \"opt/echo256_opt_avx_aes.h\"\n#include \"opt/echo256_opt_avx2.h\"\n#include \"opt/echo256_opt_avx2_aes.h\"\n#include \"opt/echo256_opt_avx512f.h\"\n#include \"opt/echo256_opt_avx512f_aes.h\"\n#endif\n\n#ifdef ARCH_CPU_ARM_FAMILY\n#include \"opt/echo256_opt_arm_cortex_a53.h\"\n#include \"opt/echo256_opt_arm_cortex_a53_aes.h\"\n#include \"opt/echo256_opt_arm_cortex_a57.h\"\n#include \"opt/echo256_opt_arm_cortex_a57_aes.h\"\n#include \"opt/echo256_opt_arm_cortex_a72.h\"\n#include \"opt/echo256_opt_arm_cortex_a72_aes.h\"\n#include \"opt/echo256_opt_arm_thunderx_aes.h\"\n#endif\n\n#else\n\nHashReturn echo256_opt_Init(echo256_opt_hashState* state);\nHashReturn echo256_opt_Update(echo256_opt_hashState* state, const unsigned char* data, uint64_t databitlen);\nHashReturn echo256_opt_Final(echo256_opt_hashState* state, unsigned char* hashval);\nHashReturn echo256_opt_UpdateFinal(echo256_opt_hashState* state, unsigned char* hashval, const unsigned char* data, uint64_t databitlen);\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a53_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a53_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a53_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a53_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a53_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A53_H\n#define HASH_ECHO_256_ARM_CORTEX_A53_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a53_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a53_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a53_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a53_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53_AES)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a53_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a53_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a53_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a53_aes_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a53_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a53_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A53_AES_H\n#define HASH_ECHO_256_ARM_CORTEX_A53_AES_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a53_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a53_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a53_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a53_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a57_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a57_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a57_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a57_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a57_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A57_H\n#define HASH_ECHO_256_ARM_CORTEX_A57_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a57_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a57_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a57_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a57_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57_AES)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a57_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a57_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a57_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a57_aes_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a57_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a57_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A57_AES_H\n#define HASH_ECHO_256_ARM_CORTEX_A57_AES_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a57_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a57_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a57_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a57_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a72_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a72_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a72_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a72_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a72_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A72_H\n#define HASH_ECHO_256_ARM_CORTEX_A72_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a72_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a72_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a72_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a72_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72_AES)\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a72_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a72_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a72_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a72_aes_UpdateFinal\n    #define Compress                echo256_opt_arm_cortex_a72_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_cortex_a72_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_CORTEX_A72_AES_H\n#define HASH_ECHO_256_ARM_CORTEX_A72_AES_H\n    #define echo256_opt_Init        echo256_opt_arm_cortex_a72_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_cortex_a72_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_cortex_a72_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_cortex_a72_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_thunderx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_THUNDERX_AES)\n    #define echo256_opt_Init        echo256_opt_arm_thunderx_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_thunderx_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_thunderx_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_thunderx_aes_UpdateFinal\n    #define Compress                echo256_opt_arm_thunderx_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_arm_thunderx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_ARM_THUNDERX_AES_H\n#define HASH_ECHO_256_ARM_THUNDERX_AES_H\n    #define echo256_opt_Init        echo256_opt_arm_thunderx_aes_Init\n    #define echo256_opt_Update      echo256_opt_arm_thunderx_aes_Update\n    #define echo256_opt_Final       echo256_opt_arm_thunderx_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_arm_thunderx_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX)\n    #define echo256_opt_Init        echo256_opt_avx_Init\n    #define echo256_opt_Update      echo256_opt_avx_Update\n    #define echo256_opt_Final       echo256_opt_avx_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx_UpdateFinal\n    #define Compress                echo256_opt_avx_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX_H\n#define HASH_ECHO_256_AVX_H\n    #define echo256_opt_Init        echo256_opt_avx_Init\n    #define echo256_opt_Update      echo256_opt_avx_Update\n    #define echo256_opt_Final       echo256_opt_avx_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx2.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2)\n    #define echo256_opt_Init        echo256_opt_avx2_Init\n    #define echo256_opt_Update      echo256_opt_avx2_Update\n    #define echo256_opt_Final       echo256_opt_avx2_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx2_UpdateFinal\n    #define Compress                echo256_opt_avx2_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx2.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX2_H\n#define HASH_ECHO_256_AVX2_H\n    #define echo256_opt_Init        echo256_opt_avx2_Init\n    #define echo256_opt_Update      echo256_opt_avx2_Update\n    #define echo256_opt_Final       echo256_opt_avx2_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx2_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx2_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2) && defined(COMPILER_HAS_AES)\n    #define echo256_opt_Init        echo256_opt_avx2_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx2_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx2_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx2_aes_UpdateFinal\n    #define Compress                echo256_opt_avx2_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx2_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX2_AES_H\n#define HASH_ECHO_256_AVX2_AES_H\n    #define echo256_opt_Init        echo256_opt_avx2_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx2_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx2_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx2_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx512f.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F)\n    #define echo256_opt_Init        echo256_opt_avx512f_Init\n    #define echo256_opt_Update      echo256_opt_avx512f_Update\n    #define echo256_opt_Final       echo256_opt_avx512f_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx512f_UpdateFinal\n    #define Compress                echo256_opt_avx512f_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx512f.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX512F_H\n#define HASH_ECHO_256_AVX512F_H\n    #define echo256_opt_Init        echo256_opt_avx512f_Init\n    #define echo256_opt_Update      echo256_opt_avx512f_Update\n    #define echo256_opt_Final       echo256_opt_avx512f_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx512f_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx512f_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F) && defined(COMPILER_HAS_AES)\n    #define echo256_opt_Init        echo256_opt_avx512f_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx512f_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx512f_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx512f_aes_UpdateFinal\n    #define Compress                echo256_opt_avx512f_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx512f_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX512F_AES_H\n#define HASH_ECHO_256_AVX512F_AES_H\n    #define echo256_opt_Init        echo256_opt_avx512f_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx512f_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx512f_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx512f_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX) && defined(COMPILER_HAS_AES)\n    #define echo256_opt_Init        echo256_opt_avx_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx_aes_UpdateFinal\n    #define Compress                echo256_opt_avx_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_avx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_AVX_AES_H\n#define HASH_ECHO_256_AVX_AES_H\n    #define echo256_opt_Init        echo256_opt_avx_aes_Init\n    #define echo256_opt_Update      echo256_opt_avx_aes_Update\n    #define echo256_opt_Final       echo256_opt_avx_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_avx_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse3.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3)\n    #define echo256_opt_Init        echo256_opt_sse3_Init\n    #define echo256_opt_Update      echo256_opt_sse3_Update\n    #define echo256_opt_Final       echo256_opt_sse3_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse3_UpdateFinal\n    #define Compress                echo256_opt_sse3_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse3.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_SSE3_H\n#define HASH_ECHO_256_SSE3_H\n    #define echo256_opt_Init        echo256_opt_sse3_Init\n    #define echo256_opt_Update      echo256_opt_sse3_Update\n    #define echo256_opt_Final       echo256_opt_sse3_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse3_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse3_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3) && defined(COMPILER_HAS_AES)\n    #define echo256_opt_Init        echo256_opt_sse3_aes_Init\n    #define echo256_opt_Update      echo256_opt_sse3_aes_Update\n    #define echo256_opt_Final       echo256_opt_sse3_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse3_aes_UpdateFinal\n    #define Compress                echo256_opt_sse3_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse3_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_SSE3_AES_H\n#define HASH_ECHO_256_SSE3_AES_H\n    #define echo256_opt_Init        echo256_opt_sse3_aes_Init\n    #define echo256_opt_Update      echo256_opt_sse3_aes_Update\n    #define echo256_opt_Final       echo256_opt_sse3_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse3_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse4.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4)\n    #define echo256_opt_Init        echo256_opt_sse4_Init\n    #define echo256_opt_Update      echo256_opt_sse4_Update\n    #define echo256_opt_Final       echo256_opt_sse4_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse4_UpdateFinal\n    #define Compress                echo256_opt_sse4_compress\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse4.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_SSE4_H\n#define HASH_ECHO_256_SSE4_H\n    #define echo256_opt_Init        echo256_opt_sse4_Init\n    #define echo256_opt_Update      echo256_opt_sse4_Update\n    #define echo256_opt_Final       echo256_opt_sse4_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse4_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse4_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4) && defined(COMPILER_HAS_AES)\n    #define echo256_opt_Init        echo256_opt_sse4_aes_Init\n    #define echo256_opt_Update      echo256_opt_sse4_aes_Update\n    #define echo256_opt_Final       echo256_opt_sse4_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse4_aes_UpdateFinal\n    #define Compress                echo256_opt_sse4_aes_compress\n\n    #define USE_HARDWARE_AES\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/opt/echo256_opt_sse4_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'echo256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_ECHO_256_SSE4_AES_H\n#define HASH_ECHO_256_SSE4_AES_H\n    #define echo256_opt_Init        echo256_opt_sse4_aes_Init\n    #define echo256_opt_Update      echo256_opt_sse4_aes_Update\n    #define echo256_opt_Final       echo256_opt_sse4_aes_Final\n    #define echo256_opt_UpdateFinal echo256_opt_sse4_aes_UpdateFinal\n\n    #define ECHO256_OPT_IMPL\n    #include \"../echo256_opt.h\"\n    #undef ECHO256_OPT_IMPL\n\n    #undef echo256_opt_Init\n    #undef echo256_opt_Update\n    #undef echo256_opt_Final\n    #undef echo256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/sphlib/aes_helper.c",
    "content": "/* $Id: aes_helper.c 220 2010-06-09 09:21:50Z tp $ */\n/*\n * AES tables. This file is not meant to be compiled by itself; it\n * is included by some hash function implementations. It contains\n * the precomputed tables and helper macros for evaluating an AES\n * round, optionally with a final XOR with a subkey.\n *\n * By default, this file defines the tables and macros for little-endian\n * processing (i.e. it is assumed that the input bytes have been read\n * from memory and assembled with the little-endian convention). If\n * the 'AES_BIG_ENDIAN' macro is defined (to a non-zero integer value)\n * when this file is included, then the tables and macros for big-endian\n * processing are defined instead. The big-endian tables and macros have\n * names distinct from the little-endian tables and macros, hence it is\n * possible to have both simultaneously, by including this file twice\n * (with and without the AES_BIG_ENDIAN macro).\n *\n * ==========================(LICENSE BEGIN)============================\n *\n * Copyright (c) 2007-2010  Projet RNRT SAPHIR\n * \n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n * \n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * ===========================(LICENSE END)=============================\n *\n * @author   Thomas Pornin <thomas.pornin@cryptolog.com>\n */\n\n#include \"sph_types.h\"\n\n#if AES_BIG_ENDIAN\n\n#define AESx(x)   ( ((SPH_C32(x) >> 24) & SPH_C32(0x000000FF)) \\\n                  | ((SPH_C32(x) >>  8) & SPH_C32(0x0000FF00)) \\\n                  | ((SPH_C32(x) <<  8) & SPH_C32(0x00FF0000)) \\\n                  | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000)))\n\n#define AES0      AES0_BE\n#define AES1      AES1_BE\n#define AES2      AES2_BE\n#define AES3      AES3_BE\n\n#define AES_ROUND_BE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3)   do { \\\n        (Y0) = AES0[((X0) >> 24) & 0xFF] \\\n            ^ AES1[((X1) >> 16) & 0xFF] \\\n            ^ AES2[((X2) >> 8) & 0xFF] \\\n            ^ AES3[(X3) & 0xFF] ^ (K0); \\\n        (Y1) = AES0[((X1) >> 24) & 0xFF] \\\n            ^ AES1[((X2) >> 16) & 0xFF] \\\n            ^ AES2[((X3) >> 8) & 0xFF] \\\n            ^ AES3[(X0) & 0xFF] ^ (K1); \\\n        (Y2) = AES0[((X2) >> 24) & 0xFF] \\\n            ^ AES1[((X3) >> 16) & 0xFF] \\\n            ^ AES2[((X0) >> 8) & 0xFF] \\\n            ^ AES3[(X1) & 0xFF] ^ (K2); \\\n        (Y3) = AES0[((X3) >> 24) & 0xFF] \\\n            ^ AES1[((X0) >> 16) & 0xFF] \\\n            ^ AES2[((X1) >> 8) & 0xFF] \\\n            ^ AES3[(X2) & 0xFF] ^ (K3); \\\n    } while (0)\n\n#define AES_ROUND_NOKEY_BE(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \\\n    AES_ROUND_BE(X0, X1, X2, X3, 0, 0, 0, 0, Y0, Y1, Y2, Y3)\n\n#else\n\n#define AESx(x)   SPH_C32(x)\n#define AES0      AES0_LE\n#define AES1      AES1_LE\n#define AES2      AES2_LE\n#define AES3      AES3_LE\n\n#define AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3)   do { \\\n        (Y0) = AES0[(X0) & 0xFF] \\\n            ^ AES1[((X1) >> 8) & 0xFF] \\\n            ^ AES2[((X2) >> 16) & 0xFF] \\\n            ^ AES3[((X3) >> 24) & 0xFF] ^ (K0); \\\n        (Y1) = AES0[(X1) & 0xFF] \\\n            ^ AES1[((X2) >> 8) & 0xFF] \\\n            ^ AES2[((X3) >> 16) & 0xFF] \\\n            ^ AES3[((X0) >> 24) & 0xFF] ^ (K1); \\\n        (Y2) = AES0[(X2) & 0xFF] \\\n            ^ AES1[((X3) >> 8) & 0xFF] \\\n            ^ AES2[((X0) >> 16) & 0xFF] \\\n            ^ AES3[((X1) >> 24) & 0xFF] ^ (K2); \\\n        (Y3) = AES0[(X3) & 0xFF] \\\n            ^ AES1[((X0) >> 8) & 0xFF] \\\n            ^ AES2[((X1) >> 16) & 0xFF] \\\n            ^ AES3[((X2) >> 24) & 0xFF] ^ (K3); \\\n    } while (0)\n\n#define AES_ROUND_NOKEY_LE(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \\\n    AES_ROUND_LE(X0, X1, X2, X3, 0, 0, 0, 0, Y0, Y1, Y2, Y3)\n\n#endif\n\n/*\n * The AES*[] tables allow us to perform a fast evaluation of an AES\n * round; table AESi[] combines SubBytes for a byte at row i, and\n * MixColumns for the column where that byte goes after ShiftRows.\n */\n\nstatic const sph_u32 AES0[256] = {\n    AESx(0xA56363C6), AESx(0x847C7CF8), AESx(0x997777EE), AESx(0x8D7B7BF6),\n    AESx(0x0DF2F2FF), AESx(0xBD6B6BD6), AESx(0xB16F6FDE), AESx(0x54C5C591),\n    AESx(0x50303060), AESx(0x03010102), AESx(0xA96767CE), AESx(0x7D2B2B56),\n    AESx(0x19FEFEE7), AESx(0x62D7D7B5), AESx(0xE6ABAB4D), AESx(0x9A7676EC),\n    AESx(0x45CACA8F), AESx(0x9D82821F), AESx(0x40C9C989), AESx(0x877D7DFA),\n    AESx(0x15FAFAEF), AESx(0xEB5959B2), AESx(0xC947478E), AESx(0x0BF0F0FB),\n    AESx(0xECADAD41), AESx(0x67D4D4B3), AESx(0xFDA2A25F), AESx(0xEAAFAF45),\n    AESx(0xBF9C9C23), AESx(0xF7A4A453), AESx(0x967272E4), AESx(0x5BC0C09B),\n    AESx(0xC2B7B775), AESx(0x1CFDFDE1), AESx(0xAE93933D), AESx(0x6A26264C),\n    AESx(0x5A36366C), AESx(0x413F3F7E), AESx(0x02F7F7F5), AESx(0x4FCCCC83),\n    AESx(0x5C343468), AESx(0xF4A5A551), AESx(0x34E5E5D1), AESx(0x08F1F1F9),\n    AESx(0x937171E2), AESx(0x73D8D8AB), AESx(0x53313162), AESx(0x3F15152A),\n    AESx(0x0C040408), AESx(0x52C7C795), AESx(0x65232346), AESx(0x5EC3C39D),\n    AESx(0x28181830), AESx(0xA1969637), AESx(0x0F05050A), AESx(0xB59A9A2F),\n    AESx(0x0907070E), AESx(0x36121224), AESx(0x9B80801B), AESx(0x3DE2E2DF),\n    AESx(0x26EBEBCD), AESx(0x6927274E), AESx(0xCDB2B27F), AESx(0x9F7575EA),\n    AESx(0x1B090912), AESx(0x9E83831D), AESx(0x742C2C58), AESx(0x2E1A1A34),\n    AESx(0x2D1B1B36), AESx(0xB26E6EDC), AESx(0xEE5A5AB4), AESx(0xFBA0A05B),\n    AESx(0xF65252A4), AESx(0x4D3B3B76), AESx(0x61D6D6B7), AESx(0xCEB3B37D),\n    AESx(0x7B292952), AESx(0x3EE3E3DD), AESx(0x712F2F5E), AESx(0x97848413),\n    AESx(0xF55353A6), AESx(0x68D1D1B9), AESx(0x00000000), AESx(0x2CEDEDC1),\n    AESx(0x60202040), AESx(0x1FFCFCE3), AESx(0xC8B1B179), AESx(0xED5B5BB6),\n    AESx(0xBE6A6AD4), AESx(0x46CBCB8D), AESx(0xD9BEBE67), AESx(0x4B393972),\n    AESx(0xDE4A4A94), AESx(0xD44C4C98), AESx(0xE85858B0), AESx(0x4ACFCF85),\n    AESx(0x6BD0D0BB), AESx(0x2AEFEFC5), AESx(0xE5AAAA4F), AESx(0x16FBFBED),\n    AESx(0xC5434386), AESx(0xD74D4D9A), AESx(0x55333366), AESx(0x94858511),\n    AESx(0xCF45458A), AESx(0x10F9F9E9), AESx(0x06020204), AESx(0x817F7FFE),\n    AESx(0xF05050A0), AESx(0x443C3C78), AESx(0xBA9F9F25), AESx(0xE3A8A84B),\n    AESx(0xF35151A2), AESx(0xFEA3A35D), AESx(0xC0404080), AESx(0x8A8F8F05),\n    AESx(0xAD92923F), AESx(0xBC9D9D21), AESx(0x48383870), AESx(0x04F5F5F1),\n    AESx(0xDFBCBC63), AESx(0xC1B6B677), AESx(0x75DADAAF), AESx(0x63212142),\n    AESx(0x30101020), AESx(0x1AFFFFE5), AESx(0x0EF3F3FD), AESx(0x6DD2D2BF),\n    AESx(0x4CCDCD81), AESx(0x140C0C18), AESx(0x35131326), AESx(0x2FECECC3),\n    AESx(0xE15F5FBE), AESx(0xA2979735), AESx(0xCC444488), AESx(0x3917172E),\n    AESx(0x57C4C493), AESx(0xF2A7A755), AESx(0x827E7EFC), AESx(0x473D3D7A),\n    AESx(0xAC6464C8), AESx(0xE75D5DBA), AESx(0x2B191932), AESx(0x957373E6),\n    AESx(0xA06060C0), AESx(0x98818119), AESx(0xD14F4F9E), AESx(0x7FDCDCA3),\n    AESx(0x66222244), AESx(0x7E2A2A54), AESx(0xAB90903B), AESx(0x8388880B),\n    AESx(0xCA46468C), AESx(0x29EEEEC7), AESx(0xD3B8B86B), AESx(0x3C141428),\n    AESx(0x79DEDEA7), AESx(0xE25E5EBC), AESx(0x1D0B0B16), AESx(0x76DBDBAD),\n    AESx(0x3BE0E0DB), AESx(0x56323264), AESx(0x4E3A3A74), AESx(0x1E0A0A14),\n    AESx(0xDB494992), AESx(0x0A06060C), AESx(0x6C242448), AESx(0xE45C5CB8),\n    AESx(0x5DC2C29F), AESx(0x6ED3D3BD), AESx(0xEFACAC43), AESx(0xA66262C4),\n    AESx(0xA8919139), AESx(0xA4959531), AESx(0x37E4E4D3), AESx(0x8B7979F2),\n    AESx(0x32E7E7D5), AESx(0x43C8C88B), AESx(0x5937376E), AESx(0xB76D6DDA),\n    AESx(0x8C8D8D01), AESx(0x64D5D5B1), AESx(0xD24E4E9C), AESx(0xE0A9A949),\n    AESx(0xB46C6CD8), AESx(0xFA5656AC), AESx(0x07F4F4F3), AESx(0x25EAEACF),\n    AESx(0xAF6565CA), AESx(0x8E7A7AF4), AESx(0xE9AEAE47), AESx(0x18080810),\n    AESx(0xD5BABA6F), AESx(0x887878F0), AESx(0x6F25254A), AESx(0x722E2E5C),\n    AESx(0x241C1C38), AESx(0xF1A6A657), AESx(0xC7B4B473), AESx(0x51C6C697),\n    AESx(0x23E8E8CB), AESx(0x7CDDDDA1), AESx(0x9C7474E8), AESx(0x211F1F3E),\n    AESx(0xDD4B4B96), AESx(0xDCBDBD61), AESx(0x868B8B0D), AESx(0x858A8A0F),\n    AESx(0x907070E0), AESx(0x423E3E7C), AESx(0xC4B5B571), AESx(0xAA6666CC),\n    AESx(0xD8484890), AESx(0x05030306), AESx(0x01F6F6F7), AESx(0x120E0E1C),\n    AESx(0xA36161C2), AESx(0x5F35356A), AESx(0xF95757AE), AESx(0xD0B9B969),\n    AESx(0x91868617), AESx(0x58C1C199), AESx(0x271D1D3A), AESx(0xB99E9E27),\n    AESx(0x38E1E1D9), AESx(0x13F8F8EB), AESx(0xB398982B), AESx(0x33111122),\n    AESx(0xBB6969D2), AESx(0x70D9D9A9), AESx(0x898E8E07), AESx(0xA7949433),\n    AESx(0xB69B9B2D), AESx(0x221E1E3C), AESx(0x92878715), AESx(0x20E9E9C9),\n    AESx(0x49CECE87), AESx(0xFF5555AA), AESx(0x78282850), AESx(0x7ADFDFA5),\n    AESx(0x8F8C8C03), AESx(0xF8A1A159), AESx(0x80898909), AESx(0x170D0D1A),\n    AESx(0xDABFBF65), AESx(0x31E6E6D7), AESx(0xC6424284), AESx(0xB86868D0),\n    AESx(0xC3414182), AESx(0xB0999929), AESx(0x772D2D5A), AESx(0x110F0F1E),\n    AESx(0xCBB0B07B), AESx(0xFC5454A8), AESx(0xD6BBBB6D), AESx(0x3A16162C)\n};\n\nstatic const sph_u32 AES1[256] = {\n    AESx(0x6363C6A5), AESx(0x7C7CF884), AESx(0x7777EE99), AESx(0x7B7BF68D),\n    AESx(0xF2F2FF0D), AESx(0x6B6BD6BD), AESx(0x6F6FDEB1), AESx(0xC5C59154),\n    AESx(0x30306050), AESx(0x01010203), AESx(0x6767CEA9), AESx(0x2B2B567D),\n    AESx(0xFEFEE719), AESx(0xD7D7B562), AESx(0xABAB4DE6), AESx(0x7676EC9A),\n    AESx(0xCACA8F45), AESx(0x82821F9D), AESx(0xC9C98940), AESx(0x7D7DFA87),\n    AESx(0xFAFAEF15), AESx(0x5959B2EB), AESx(0x47478EC9), AESx(0xF0F0FB0B),\n    AESx(0xADAD41EC), AESx(0xD4D4B367), AESx(0xA2A25FFD), AESx(0xAFAF45EA),\n    AESx(0x9C9C23BF), AESx(0xA4A453F7), AESx(0x7272E496), AESx(0xC0C09B5B),\n    AESx(0xB7B775C2), AESx(0xFDFDE11C), AESx(0x93933DAE), AESx(0x26264C6A),\n    AESx(0x36366C5A), AESx(0x3F3F7E41), AESx(0xF7F7F502), AESx(0xCCCC834F),\n    AESx(0x3434685C), AESx(0xA5A551F4), AESx(0xE5E5D134), AESx(0xF1F1F908),\n    AESx(0x7171E293), AESx(0xD8D8AB73), AESx(0x31316253), AESx(0x15152A3F),\n    AESx(0x0404080C), AESx(0xC7C79552), AESx(0x23234665), AESx(0xC3C39D5E),\n    AESx(0x18183028), AESx(0x969637A1), AESx(0x05050A0F), AESx(0x9A9A2FB5),\n    AESx(0x07070E09), AESx(0x12122436), AESx(0x80801B9B), AESx(0xE2E2DF3D),\n    AESx(0xEBEBCD26), AESx(0x27274E69), AESx(0xB2B27FCD), AESx(0x7575EA9F),\n    AESx(0x0909121B), AESx(0x83831D9E), AESx(0x2C2C5874), AESx(0x1A1A342E),\n    AESx(0x1B1B362D), AESx(0x6E6EDCB2), AESx(0x5A5AB4EE), AESx(0xA0A05BFB),\n    AESx(0x5252A4F6), AESx(0x3B3B764D), AESx(0xD6D6B761), AESx(0xB3B37DCE),\n    AESx(0x2929527B), AESx(0xE3E3DD3E), AESx(0x2F2F5E71), AESx(0x84841397),\n    AESx(0x5353A6F5), AESx(0xD1D1B968), AESx(0x00000000), AESx(0xEDEDC12C),\n    AESx(0x20204060), AESx(0xFCFCE31F), AESx(0xB1B179C8), AESx(0x5B5BB6ED),\n    AESx(0x6A6AD4BE), AESx(0xCBCB8D46), AESx(0xBEBE67D9), AESx(0x3939724B),\n    AESx(0x4A4A94DE), AESx(0x4C4C98D4), AESx(0x5858B0E8), AESx(0xCFCF854A),\n    AESx(0xD0D0BB6B), AESx(0xEFEFC52A), AESx(0xAAAA4FE5), AESx(0xFBFBED16),\n    AESx(0x434386C5), AESx(0x4D4D9AD7), AESx(0x33336655), AESx(0x85851194),\n    AESx(0x45458ACF), AESx(0xF9F9E910), AESx(0x02020406), AESx(0x7F7FFE81),\n    AESx(0x5050A0F0), AESx(0x3C3C7844), AESx(0x9F9F25BA), AESx(0xA8A84BE3),\n    AESx(0x5151A2F3), AESx(0xA3A35DFE), AESx(0x404080C0), AESx(0x8F8F058A),\n    AESx(0x92923FAD), AESx(0x9D9D21BC), AESx(0x38387048), AESx(0xF5F5F104),\n    AESx(0xBCBC63DF), AESx(0xB6B677C1), AESx(0xDADAAF75), AESx(0x21214263),\n    AESx(0x10102030), AESx(0xFFFFE51A), AESx(0xF3F3FD0E), AESx(0xD2D2BF6D),\n    AESx(0xCDCD814C), AESx(0x0C0C1814), AESx(0x13132635), AESx(0xECECC32F),\n    AESx(0x5F5FBEE1), AESx(0x979735A2), AESx(0x444488CC), AESx(0x17172E39),\n    AESx(0xC4C49357), AESx(0xA7A755F2), AESx(0x7E7EFC82), AESx(0x3D3D7A47),\n    AESx(0x6464C8AC), AESx(0x5D5DBAE7), AESx(0x1919322B), AESx(0x7373E695),\n    AESx(0x6060C0A0), AESx(0x81811998), AESx(0x4F4F9ED1), AESx(0xDCDCA37F),\n    AESx(0x22224466), AESx(0x2A2A547E), AESx(0x90903BAB), AESx(0x88880B83),\n    AESx(0x46468CCA), AESx(0xEEEEC729), AESx(0xB8B86BD3), AESx(0x1414283C),\n    AESx(0xDEDEA779), AESx(0x5E5EBCE2), AESx(0x0B0B161D), AESx(0xDBDBAD76),\n    AESx(0xE0E0DB3B), AESx(0x32326456), AESx(0x3A3A744E), AESx(0x0A0A141E),\n    AESx(0x494992DB), AESx(0x06060C0A), AESx(0x2424486C), AESx(0x5C5CB8E4),\n    AESx(0xC2C29F5D), AESx(0xD3D3BD6E), AESx(0xACAC43EF), AESx(0x6262C4A6),\n    AESx(0x919139A8), AESx(0x959531A4), AESx(0xE4E4D337), AESx(0x7979F28B),\n    AESx(0xE7E7D532), AESx(0xC8C88B43), AESx(0x37376E59), AESx(0x6D6DDAB7),\n    AESx(0x8D8D018C), AESx(0xD5D5B164), AESx(0x4E4E9CD2), AESx(0xA9A949E0),\n    AESx(0x6C6CD8B4), AESx(0x5656ACFA), AESx(0xF4F4F307), AESx(0xEAEACF25),\n    AESx(0x6565CAAF), AESx(0x7A7AF48E), AESx(0xAEAE47E9), AESx(0x08081018),\n    AESx(0xBABA6FD5), AESx(0x7878F088), AESx(0x25254A6F), AESx(0x2E2E5C72),\n    AESx(0x1C1C3824), AESx(0xA6A657F1), AESx(0xB4B473C7), AESx(0xC6C69751),\n    AESx(0xE8E8CB23), AESx(0xDDDDA17C), AESx(0x7474E89C), AESx(0x1F1F3E21),\n    AESx(0x4B4B96DD), AESx(0xBDBD61DC), AESx(0x8B8B0D86), AESx(0x8A8A0F85),\n    AESx(0x7070E090), AESx(0x3E3E7C42), AESx(0xB5B571C4), AESx(0x6666CCAA),\n    AESx(0x484890D8), AESx(0x03030605), AESx(0xF6F6F701), AESx(0x0E0E1C12),\n    AESx(0x6161C2A3), AESx(0x35356A5F), AESx(0x5757AEF9), AESx(0xB9B969D0),\n    AESx(0x86861791), AESx(0xC1C19958), AESx(0x1D1D3A27), AESx(0x9E9E27B9),\n    AESx(0xE1E1D938), AESx(0xF8F8EB13), AESx(0x98982BB3), AESx(0x11112233),\n    AESx(0x6969D2BB), AESx(0xD9D9A970), AESx(0x8E8E0789), AESx(0x949433A7),\n    AESx(0x9B9B2DB6), AESx(0x1E1E3C22), AESx(0x87871592), AESx(0xE9E9C920),\n    AESx(0xCECE8749), AESx(0x5555AAFF), AESx(0x28285078), AESx(0xDFDFA57A),\n    AESx(0x8C8C038F), AESx(0xA1A159F8), AESx(0x89890980), AESx(0x0D0D1A17),\n    AESx(0xBFBF65DA), AESx(0xE6E6D731), AESx(0x424284C6), AESx(0x6868D0B8),\n    AESx(0x414182C3), AESx(0x999929B0), AESx(0x2D2D5A77), AESx(0x0F0F1E11),\n    AESx(0xB0B07BCB), AESx(0x5454A8FC), AESx(0xBBBB6DD6), AESx(0x16162C3A)\n};\n\nstatic const sph_u32 AES2[256] = {\n    AESx(0x63C6A563), AESx(0x7CF8847C), AESx(0x77EE9977), AESx(0x7BF68D7B),\n    AESx(0xF2FF0DF2), AESx(0x6BD6BD6B), AESx(0x6FDEB16F), AESx(0xC59154C5),\n    AESx(0x30605030), AESx(0x01020301), AESx(0x67CEA967), AESx(0x2B567D2B),\n    AESx(0xFEE719FE), AESx(0xD7B562D7), AESx(0xAB4DE6AB), AESx(0x76EC9A76),\n    AESx(0xCA8F45CA), AESx(0x821F9D82), AESx(0xC98940C9), AESx(0x7DFA877D),\n    AESx(0xFAEF15FA), AESx(0x59B2EB59), AESx(0x478EC947), AESx(0xF0FB0BF0),\n    AESx(0xAD41ECAD), AESx(0xD4B367D4), AESx(0xA25FFDA2), AESx(0xAF45EAAF),\n    AESx(0x9C23BF9C), AESx(0xA453F7A4), AESx(0x72E49672), AESx(0xC09B5BC0),\n    AESx(0xB775C2B7), AESx(0xFDE11CFD), AESx(0x933DAE93), AESx(0x264C6A26),\n    AESx(0x366C5A36), AESx(0x3F7E413F), AESx(0xF7F502F7), AESx(0xCC834FCC),\n    AESx(0x34685C34), AESx(0xA551F4A5), AESx(0xE5D134E5), AESx(0xF1F908F1),\n    AESx(0x71E29371), AESx(0xD8AB73D8), AESx(0x31625331), AESx(0x152A3F15),\n    AESx(0x04080C04), AESx(0xC79552C7), AESx(0x23466523), AESx(0xC39D5EC3),\n    AESx(0x18302818), AESx(0x9637A196), AESx(0x050A0F05), AESx(0x9A2FB59A),\n    AESx(0x070E0907), AESx(0x12243612), AESx(0x801B9B80), AESx(0xE2DF3DE2),\n    AESx(0xEBCD26EB), AESx(0x274E6927), AESx(0xB27FCDB2), AESx(0x75EA9F75),\n    AESx(0x09121B09), AESx(0x831D9E83), AESx(0x2C58742C), AESx(0x1A342E1A),\n    AESx(0x1B362D1B), AESx(0x6EDCB26E), AESx(0x5AB4EE5A), AESx(0xA05BFBA0),\n    AESx(0x52A4F652), AESx(0x3B764D3B), AESx(0xD6B761D6), AESx(0xB37DCEB3),\n    AESx(0x29527B29), AESx(0xE3DD3EE3), AESx(0x2F5E712F), AESx(0x84139784),\n    AESx(0x53A6F553), AESx(0xD1B968D1), AESx(0x00000000), AESx(0xEDC12CED),\n    AESx(0x20406020), AESx(0xFCE31FFC), AESx(0xB179C8B1), AESx(0x5BB6ED5B),\n    AESx(0x6AD4BE6A), AESx(0xCB8D46CB), AESx(0xBE67D9BE), AESx(0x39724B39),\n    AESx(0x4A94DE4A), AESx(0x4C98D44C), AESx(0x58B0E858), AESx(0xCF854ACF),\n    AESx(0xD0BB6BD0), AESx(0xEFC52AEF), AESx(0xAA4FE5AA), AESx(0xFBED16FB),\n    AESx(0x4386C543), AESx(0x4D9AD74D), AESx(0x33665533), AESx(0x85119485),\n    AESx(0x458ACF45), AESx(0xF9E910F9), AESx(0x02040602), AESx(0x7FFE817F),\n    AESx(0x50A0F050), AESx(0x3C78443C), AESx(0x9F25BA9F), AESx(0xA84BE3A8),\n    AESx(0x51A2F351), AESx(0xA35DFEA3), AESx(0x4080C040), AESx(0x8F058A8F),\n    AESx(0x923FAD92), AESx(0x9D21BC9D), AESx(0x38704838), AESx(0xF5F104F5),\n    AESx(0xBC63DFBC), AESx(0xB677C1B6), AESx(0xDAAF75DA), AESx(0x21426321),\n    AESx(0x10203010), AESx(0xFFE51AFF), AESx(0xF3FD0EF3), AESx(0xD2BF6DD2),\n    AESx(0xCD814CCD), AESx(0x0C18140C), AESx(0x13263513), AESx(0xECC32FEC),\n    AESx(0x5FBEE15F), AESx(0x9735A297), AESx(0x4488CC44), AESx(0x172E3917),\n    AESx(0xC49357C4), AESx(0xA755F2A7), AESx(0x7EFC827E), AESx(0x3D7A473D),\n    AESx(0x64C8AC64), AESx(0x5DBAE75D), AESx(0x19322B19), AESx(0x73E69573),\n    AESx(0x60C0A060), AESx(0x81199881), AESx(0x4F9ED14F), AESx(0xDCA37FDC),\n    AESx(0x22446622), AESx(0x2A547E2A), AESx(0x903BAB90), AESx(0x880B8388),\n    AESx(0x468CCA46), AESx(0xEEC729EE), AESx(0xB86BD3B8), AESx(0x14283C14),\n    AESx(0xDEA779DE), AESx(0x5EBCE25E), AESx(0x0B161D0B), AESx(0xDBAD76DB),\n    AESx(0xE0DB3BE0), AESx(0x32645632), AESx(0x3A744E3A), AESx(0x0A141E0A),\n    AESx(0x4992DB49), AESx(0x060C0A06), AESx(0x24486C24), AESx(0x5CB8E45C),\n    AESx(0xC29F5DC2), AESx(0xD3BD6ED3), AESx(0xAC43EFAC), AESx(0x62C4A662),\n    AESx(0x9139A891), AESx(0x9531A495), AESx(0xE4D337E4), AESx(0x79F28B79),\n    AESx(0xE7D532E7), AESx(0xC88B43C8), AESx(0x376E5937), AESx(0x6DDAB76D),\n    AESx(0x8D018C8D), AESx(0xD5B164D5), AESx(0x4E9CD24E), AESx(0xA949E0A9),\n    AESx(0x6CD8B46C), AESx(0x56ACFA56), AESx(0xF4F307F4), AESx(0xEACF25EA),\n    AESx(0x65CAAF65), AESx(0x7AF48E7A), AESx(0xAE47E9AE), AESx(0x08101808),\n    AESx(0xBA6FD5BA), AESx(0x78F08878), AESx(0x254A6F25), AESx(0x2E5C722E),\n    AESx(0x1C38241C), AESx(0xA657F1A6), AESx(0xB473C7B4), AESx(0xC69751C6),\n    AESx(0xE8CB23E8), AESx(0xDDA17CDD), AESx(0x74E89C74), AESx(0x1F3E211F),\n    AESx(0x4B96DD4B), AESx(0xBD61DCBD), AESx(0x8B0D868B), AESx(0x8A0F858A),\n    AESx(0x70E09070), AESx(0x3E7C423E), AESx(0xB571C4B5), AESx(0x66CCAA66),\n    AESx(0x4890D848), AESx(0x03060503), AESx(0xF6F701F6), AESx(0x0E1C120E),\n    AESx(0x61C2A361), AESx(0x356A5F35), AESx(0x57AEF957), AESx(0xB969D0B9),\n    AESx(0x86179186), AESx(0xC19958C1), AESx(0x1D3A271D), AESx(0x9E27B99E),\n    AESx(0xE1D938E1), AESx(0xF8EB13F8), AESx(0x982BB398), AESx(0x11223311),\n    AESx(0x69D2BB69), AESx(0xD9A970D9), AESx(0x8E07898E), AESx(0x9433A794),\n    AESx(0x9B2DB69B), AESx(0x1E3C221E), AESx(0x87159287), AESx(0xE9C920E9),\n    AESx(0xCE8749CE), AESx(0x55AAFF55), AESx(0x28507828), AESx(0xDFA57ADF),\n    AESx(0x8C038F8C), AESx(0xA159F8A1), AESx(0x89098089), AESx(0x0D1A170D),\n    AESx(0xBF65DABF), AESx(0xE6D731E6), AESx(0x4284C642), AESx(0x68D0B868),\n    AESx(0x4182C341), AESx(0x9929B099), AESx(0x2D5A772D), AESx(0x0F1E110F),\n    AESx(0xB07BCBB0), AESx(0x54A8FC54), AESx(0xBB6DD6BB), AESx(0x162C3A16)\n};\n\nstatic const sph_u32 AES3[256] = {\n    AESx(0xC6A56363), AESx(0xF8847C7C), AESx(0xEE997777), AESx(0xF68D7B7B),\n    AESx(0xFF0DF2F2), AESx(0xD6BD6B6B), AESx(0xDEB16F6F), AESx(0x9154C5C5),\n    AESx(0x60503030), AESx(0x02030101), AESx(0xCEA96767), AESx(0x567D2B2B),\n    AESx(0xE719FEFE), AESx(0xB562D7D7), AESx(0x4DE6ABAB), AESx(0xEC9A7676),\n    AESx(0x8F45CACA), AESx(0x1F9D8282), AESx(0x8940C9C9), AESx(0xFA877D7D),\n    AESx(0xEF15FAFA), AESx(0xB2EB5959), AESx(0x8EC94747), AESx(0xFB0BF0F0),\n    AESx(0x41ECADAD), AESx(0xB367D4D4), AESx(0x5FFDA2A2), AESx(0x45EAAFAF),\n    AESx(0x23BF9C9C), AESx(0x53F7A4A4), AESx(0xE4967272), AESx(0x9B5BC0C0),\n    AESx(0x75C2B7B7), AESx(0xE11CFDFD), AESx(0x3DAE9393), AESx(0x4C6A2626),\n    AESx(0x6C5A3636), AESx(0x7E413F3F), AESx(0xF502F7F7), AESx(0x834FCCCC),\n    AESx(0x685C3434), AESx(0x51F4A5A5), AESx(0xD134E5E5), AESx(0xF908F1F1),\n    AESx(0xE2937171), AESx(0xAB73D8D8), AESx(0x62533131), AESx(0x2A3F1515),\n    AESx(0x080C0404), AESx(0x9552C7C7), AESx(0x46652323), AESx(0x9D5EC3C3),\n    AESx(0x30281818), AESx(0x37A19696), AESx(0x0A0F0505), AESx(0x2FB59A9A),\n    AESx(0x0E090707), AESx(0x24361212), AESx(0x1B9B8080), AESx(0xDF3DE2E2),\n    AESx(0xCD26EBEB), AESx(0x4E692727), AESx(0x7FCDB2B2), AESx(0xEA9F7575),\n    AESx(0x121B0909), AESx(0x1D9E8383), AESx(0x58742C2C), AESx(0x342E1A1A),\n    AESx(0x362D1B1B), AESx(0xDCB26E6E), AESx(0xB4EE5A5A), AESx(0x5BFBA0A0),\n    AESx(0xA4F65252), AESx(0x764D3B3B), AESx(0xB761D6D6), AESx(0x7DCEB3B3),\n    AESx(0x527B2929), AESx(0xDD3EE3E3), AESx(0x5E712F2F), AESx(0x13978484),\n    AESx(0xA6F55353), AESx(0xB968D1D1), AESx(0x00000000), AESx(0xC12CEDED),\n    AESx(0x40602020), AESx(0xE31FFCFC), AESx(0x79C8B1B1), AESx(0xB6ED5B5B),\n    AESx(0xD4BE6A6A), AESx(0x8D46CBCB), AESx(0x67D9BEBE), AESx(0x724B3939),\n    AESx(0x94DE4A4A), AESx(0x98D44C4C), AESx(0xB0E85858), AESx(0x854ACFCF),\n    AESx(0xBB6BD0D0), AESx(0xC52AEFEF), AESx(0x4FE5AAAA), AESx(0xED16FBFB),\n    AESx(0x86C54343), AESx(0x9AD74D4D), AESx(0x66553333), AESx(0x11948585),\n    AESx(0x8ACF4545), AESx(0xE910F9F9), AESx(0x04060202), AESx(0xFE817F7F),\n    AESx(0xA0F05050), AESx(0x78443C3C), AESx(0x25BA9F9F), AESx(0x4BE3A8A8),\n    AESx(0xA2F35151), AESx(0x5DFEA3A3), AESx(0x80C04040), AESx(0x058A8F8F),\n    AESx(0x3FAD9292), AESx(0x21BC9D9D), AESx(0x70483838), AESx(0xF104F5F5),\n    AESx(0x63DFBCBC), AESx(0x77C1B6B6), AESx(0xAF75DADA), AESx(0x42632121),\n    AESx(0x20301010), AESx(0xE51AFFFF), AESx(0xFD0EF3F3), AESx(0xBF6DD2D2),\n    AESx(0x814CCDCD), AESx(0x18140C0C), AESx(0x26351313), AESx(0xC32FECEC),\n    AESx(0xBEE15F5F), AESx(0x35A29797), AESx(0x88CC4444), AESx(0x2E391717),\n    AESx(0x9357C4C4), AESx(0x55F2A7A7), AESx(0xFC827E7E), AESx(0x7A473D3D),\n    AESx(0xC8AC6464), AESx(0xBAE75D5D), AESx(0x322B1919), AESx(0xE6957373),\n    AESx(0xC0A06060), AESx(0x19988181), AESx(0x9ED14F4F), AESx(0xA37FDCDC),\n    AESx(0x44662222), AESx(0x547E2A2A), AESx(0x3BAB9090), AESx(0x0B838888),\n    AESx(0x8CCA4646), AESx(0xC729EEEE), AESx(0x6BD3B8B8), AESx(0x283C1414),\n    AESx(0xA779DEDE), AESx(0xBCE25E5E), AESx(0x161D0B0B), AESx(0xAD76DBDB),\n    AESx(0xDB3BE0E0), AESx(0x64563232), AESx(0x744E3A3A), AESx(0x141E0A0A),\n    AESx(0x92DB4949), AESx(0x0C0A0606), AESx(0x486C2424), AESx(0xB8E45C5C),\n    AESx(0x9F5DC2C2), AESx(0xBD6ED3D3), AESx(0x43EFACAC), AESx(0xC4A66262),\n    AESx(0x39A89191), AESx(0x31A49595), AESx(0xD337E4E4), AESx(0xF28B7979),\n    AESx(0xD532E7E7), AESx(0x8B43C8C8), AESx(0x6E593737), AESx(0xDAB76D6D),\n    AESx(0x018C8D8D), AESx(0xB164D5D5), AESx(0x9CD24E4E), AESx(0x49E0A9A9),\n    AESx(0xD8B46C6C), AESx(0xACFA5656), AESx(0xF307F4F4), AESx(0xCF25EAEA),\n    AESx(0xCAAF6565), AESx(0xF48E7A7A), AESx(0x47E9AEAE), AESx(0x10180808),\n    AESx(0x6FD5BABA), AESx(0xF0887878), AESx(0x4A6F2525), AESx(0x5C722E2E),\n    AESx(0x38241C1C), AESx(0x57F1A6A6), AESx(0x73C7B4B4), AESx(0x9751C6C6),\n    AESx(0xCB23E8E8), AESx(0xA17CDDDD), AESx(0xE89C7474), AESx(0x3E211F1F),\n    AESx(0x96DD4B4B), AESx(0x61DCBDBD), AESx(0x0D868B8B), AESx(0x0F858A8A),\n    AESx(0xE0907070), AESx(0x7C423E3E), AESx(0x71C4B5B5), AESx(0xCCAA6666),\n    AESx(0x90D84848), AESx(0x06050303), AESx(0xF701F6F6), AESx(0x1C120E0E),\n    AESx(0xC2A36161), AESx(0x6A5F3535), AESx(0xAEF95757), AESx(0x69D0B9B9),\n    AESx(0x17918686), AESx(0x9958C1C1), AESx(0x3A271D1D), AESx(0x27B99E9E),\n    AESx(0xD938E1E1), AESx(0xEB13F8F8), AESx(0x2BB39898), AESx(0x22331111),\n    AESx(0xD2BB6969), AESx(0xA970D9D9), AESx(0x07898E8E), AESx(0x33A79494),\n    AESx(0x2DB69B9B), AESx(0x3C221E1E), AESx(0x15928787), AESx(0xC920E9E9),\n    AESx(0x8749CECE), AESx(0xAAFF5555), AESx(0x50782828), AESx(0xA57ADFDF),\n    AESx(0x038F8C8C), AESx(0x59F8A1A1), AESx(0x09808989), AESx(0x1A170D0D),\n    AESx(0x65DABFBF), AESx(0xD731E6E6), AESx(0x84C64242), AESx(0xD0B86868),\n    AESx(0x82C34141), AESx(0x29B09999), AESx(0x5A772D2D), AESx(0x1E110F0F),\n    AESx(0x7BCBB0B0), AESx(0xA8FC5454), AESx(0x6DD6BBBB), AESx(0x2C3A1616)\n};\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/sphlib/echo.cpp",
    "content": "/* $Id: echo.c 227 2010-06-16 17:28:38Z tp $ */\n/*\n * ECHO implementation.\n *\n * ==========================(LICENSE BEGIN)============================\n *\n * Copyright (c) 2007-2010  Projet RNRT SAPHIR\n * \n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n * \n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * ===========================(LICENSE END)=============================\n *\n * @author   Thomas Pornin <thomas.pornin@cryptolog.com>\n */\n\n#include <stddef.h>\n#include <string.h>\n#include <limits.h>\n\n#include \"sph_echo.h\"\n\n#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_ECHO\n#define SPH_SMALL_FOOTPRINT_ECHO   1\n#endif\n\n/*\n * Some measures tend to show that the 64-bit implementation offers\n * better performance only on a \"64-bit architectures\", those which have\n * actual 64-bit registers.\n */\n#if !defined SPH_ECHO_64 && SPH_64_TRUE\n#define SPH_ECHO_64   1\n#endif\n\n/*\n * We can use a 64-bit implementation only if a 64-bit type is available.\n */\n#if !SPH_64\n#undef SPH_ECHO_64\n#endif\n\n#define T32   SPH_T32\n#define C32   SPH_C32\n#if SPH_64\n#define C64   SPH_C64\n#endif\n\n#define AES_BIG_ENDIAN   0\n#include \"aes_helper.c\"\n\n#if SPH_ECHO_64\n\n#define DECL_STATE_SMALL sph_u64 W[16][2];\n\n#define DECL_STATE_BIGsph_u64 W[16][2];\n\n#define INPUT_BLOCK_SMALL(sc)   do { \\\n        unsigned u; \\\n        memcpy(W, sc->u.Vb, 8 * sizeof(sph_u64)); \\\n        for (u = 0; u < 12; u ++) { \\\n            W[u + 4][0] = sph_dec64le_aligned( \\\n                sc->buf + 16 * u); \\\n            W[u + 4][1] = sph_dec64le_aligned( \\\n                sc->buf + 16 * u + 8); \\\n        } \\\n    } while (0)\n\n#if SPH_SMALL_FOOTPRINT_ECHO\n\nstatic void aes_2rounds_all(sph_u64 W[16][2], sph_u32 *pK0, sph_u32 *pK1, sph_u32 *pK2, sph_u32 *pK3)\n{\n    int n;\n    sph_u32 K0 = *pK0;\n    sph_u32 K1 = *pK1;\n    sph_u32 K2 = *pK2;\n    sph_u32 K3 = *pK3;\n\n    for (n = 0; n < 16; n ++)\n    {\n        sph_u64 Wl = W[n][0];\n        sph_u64 Wh = W[n][1];\n        sph_u32 X0 = (sph_u32)Wl;\n        sph_u32 X1 = (sph_u32)(Wl >> 32);\n        sph_u32 X2 = (sph_u32)Wh;\n        sph_u32 X3 = (sph_u32)(Wh >> 32);\n        sph_u32 Y0, Y1, Y2, Y3; \\\n        AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3);\n        AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X0, X1, X2, X3);\n        W[n][0] = (sph_u64)X0 | ((sph_u64)X1 << 32);\n        W[n][1] = (sph_u64)X2 | ((sph_u64)X3 << 32);\n        if ((K0 = T32(K0 + 1)) == 0)\n        {\n            if ((K1 = T32(K1 + 1)) == 0)\n            {\n                if ((K2 = T32(K2 + 1)) == 0)\n                {\n                    K3 = T32(K3 + 1);\n                }\n            }\n        }\n    }\n    *pK0 = K0;\n    *pK1 = K1;\n    *pK2 = K2;\n    *pK3 = K3;\n}\n\n#define BIG_SUB_WORDS   do { \\\n        aes_2rounds_all(W, &K0, &K1, &K2, &K3); \\\n    } while (0)\n\n#else\n\n#define AES_2ROUNDS(X)   do { \\\n        sph_u32 X0 = (sph_u32)(X[0]); \\\n        sph_u32 X1 = (sph_u32)(X[0] >> 32); \\\n        sph_u32 X2 = (sph_u32)(X[1]); \\\n        sph_u32 X3 = (sph_u32)(X[1] >> 32); \\\n        sph_u32 Y0, Y1, Y2, Y3; \\\n        AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3); \\\n        AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X0, X1, X2, X3); \\\n        X[0] = (sph_u64)X0 | ((sph_u64)X1 << 32); \\\n        X[1] = (sph_u64)X2 | ((sph_u64)X3 << 32); \\\n        if ((K0 = T32(K0 + 1)) == 0) { \\\n            if ((K1 = T32(K1 + 1)) == 0) \\\n                if ((K2 = T32(K2 + 1)) == 0) \\\n                    K3 = T32(K3 + 1); \\\n        } \\\n    } while (0)\n\n#define BIG_SUB_WORDS   do { \\\n        AES_2ROUNDS(W[ 0]); \\\n        AES_2ROUNDS(W[ 1]); \\\n        AES_2ROUNDS(W[ 2]); \\\n        AES_2ROUNDS(W[ 3]); \\\n        AES_2ROUNDS(W[ 4]); \\\n        AES_2ROUNDS(W[ 5]); \\\n        AES_2ROUNDS(W[ 6]); \\\n        AES_2ROUNDS(W[ 7]); \\\n        AES_2ROUNDS(W[ 8]); \\\n        AES_2ROUNDS(W[ 9]); \\\n        AES_2ROUNDS(W[10]); \\\n        AES_2ROUNDS(W[11]); \\\n        AES_2ROUNDS(W[12]); \\\n        AES_2ROUNDS(W[13]); \\\n        AES_2ROUNDS(W[14]); \\\n        AES_2ROUNDS(W[15]); \\\n    } while (0)\n\n#endif\n\n#define SHIFT_ROW1(a, b, c, d)   do { \\\n        sph_u64 tmp; \\\n        tmp = W[a][0]; \\\n        W[a][0] = W[b][0]; \\\n        W[b][0] = W[c][0]; \\\n        W[c][0] = W[d][0]; \\\n        W[d][0] = tmp; \\\n        tmp = W[a][1]; \\\n        W[a][1] = W[b][1]; \\\n        W[b][1] = W[c][1]; \\\n        W[c][1] = W[d][1]; \\\n        W[d][1] = tmp; \\\n    } while (0)\n\n#define SHIFT_ROW2(a, b, c, d)   do { \\\n        sph_u64 tmp; \\\n        tmp = W[a][0]; \\\n        W[a][0] = W[c][0]; \\\n        W[c][0] = tmp; \\\n        tmp = W[b][0]; \\\n        W[b][0] = W[d][0]; \\\n        W[d][0] = tmp; \\\n        tmp = W[a][1]; \\\n        W[a][1] = W[c][1]; \\\n        W[c][1] = tmp; \\\n        tmp = W[b][1]; \\\n        W[b][1] = W[d][1]; \\\n        W[d][1] = tmp; \\\n    } while (0)\n\n#define SHIFT_ROW3(a, b, c, d)   SHIFT_ROW1(d, c, b, a)\n\n#define BIG_SHIFT_ROWS   do { \\\n        SHIFT_ROW1(1, 5, 9, 13); \\\n        SHIFT_ROW2(2, 6, 10, 14); \\\n        SHIFT_ROW3(3, 7, 11, 15); \\\n    } while (0)\n\n#if SPH_SMALL_FOOTPRINT_ECHO\n\nstatic void mix_column(sph_u64 W[16][2], int ia, int ib, int ic, int id)\n{\n    int n;\n\n    for (n = 0; n < 2; n ++)\n    {\n        sph_u64 a = W[ia][n];\n        sph_u64 b = W[ib][n];\n        sph_u64 c = W[ic][n];\n        sph_u64 d = W[id][n];\n        sph_u64 ab = a ^ b;\n        sph_u64 bc = b ^ c;\n        sph_u64 cd = c ^ d;\n        sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1);\n        sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1);\n        sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1);\n        W[ia][n] = abx ^ bc ^ d;\n        W[ib][n] = bcx ^ a ^ cd;\n        W[ic][n] = cdx ^ ab ^ d;\n        W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c;\n    }\n}\n\n#define MIX_COLUMN(a, b, c, d)   mix_column(W, a, b, c, d)\n\n#else\n\n#define MIX_COLUMN1(ia, ib, ic, id, n)   do { \\\n        sph_u64 a = W[ia][n]; \\\n        sph_u64 b = W[ib][n]; \\\n        sph_u64 c = W[ic][n]; \\\n        sph_u64 d = W[id][n]; \\\n        sph_u64 ab = a ^ b; \\\n        sph_u64 bc = b ^ c; \\\n        sph_u64 cd = c ^ d; \\\n        sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1); \\\n        sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1); \\\n        sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1); \\\n        W[ia][n] = abx ^ bc ^ d; \\\n        W[ib][n] = bcx ^ a ^ cd; \\\n        W[ic][n] = cdx ^ ab ^ d; \\\n        W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; \\\n    } while (0)\n\n#define MIX_COLUMN(a, b, c, d)   do { \\\n        MIX_COLUMN1(a, b, c, d, 0); \\\n        MIX_COLUMN1(a, b, c, d, 1); \\\n    } while (0)\n\n#endif\n\n#define BIG_MIX_COLUMNS   do { \\\n        MIX_COLUMN(0, 1, 2, 3); \\\n        MIX_COLUMN(4, 5, 6, 7); \\\n        MIX_COLUMN(8, 9, 10, 11); \\\n        MIX_COLUMN(12, 13, 14, 15); \\\n    } while (0)\n\n#define BIG_ROUND   do { \\\n        BIG_SUB_WORDS; \\\n        BIG_SHIFT_ROWS; \\\n        BIG_MIX_COLUMNS; \\\n    } while (0)\n\n#define FINAL_SMALL   do { \\\n        unsigned u; \\\n        sph_u64 *VV = &sc->u.Vb[0][0]; \\\n        sph_u64 *WW = &W[0][0]; \\\n        for (u = 0; u < 8; u ++) { \\\n            VV[u] ^= sph_dec64le_aligned(sc->buf + (u * 8)) ^ sph_dec64le_aligned(sc->buf + (u * 8) + 64) ^ sph_dec64le_aligned(sc->buf + (u * 8) + 128) ^ WW[u] ^ WW[u + 8] ^ WW[u + 16] ^ WW[u + 24]; \\\n        } \\\n    } while (0)\n\n#define COMPRESS_SMALL(sc)   do { \\\n        sph_u32 K0 = sc->C0; \\\n        sph_u32 K1 = sc->C1; \\\n        sph_u32 K2 = sc->C2; \\\n        sph_u32 K3 = sc->C3; \\\n        unsigned u; \\\n        INPUT_BLOCK_SMALL(sc); \\\n        for (u = 0; u < 8; u ++) { \\\n            BIG_ROUND; \\\n        } \\\n        FINAL_SMALL; \\\n    } while (0)\n\n#else\n\n#define DECL_STATE_SMALL   \\\n    sph_u32 W[16][4];\n\n#define DECL_STATE_BIG   \\\n    sph_u32 W[16][4];\n\n#define INPUT_BLOCK_SMALL(sc)   do { \\\n        unsigned u; \\\n        memcpy(W, sc->u.Vs, 16 * sizeof(sph_u32)); \\\n        for (u = 0; u < 12; u ++) { \\\n            W[u + 4][0] = sph_dec32le_aligned( \\\n                sc->buf + 16 * u); \\\n            W[u + 4][1] = sph_dec32le_aligned( \\\n                sc->buf + 16 * u + 4); \\\n            W[u + 4][2] = sph_dec32le_aligned( \\\n                sc->buf + 16 * u + 8); \\\n            W[u + 4][3] = sph_dec32le_aligned( \\\n                sc->buf + 16 * u + 12); \\\n        } \\\n    } while (0)\n\n#if SPH_SMALL_FOOTPRINT_ECHO\n\nstatic void aes_2rounds_all(sph_u32 W[16][4], sph_u32 *pK0, sph_u32 *pK1, sph_u32 *pK2, sph_u32 *pK3)\n{\n    int n;\n    sph_u32 K0 = *pK0;\n    sph_u32 K1 = *pK1;\n    sph_u32 K2 = *pK2;\n    sph_u32 K3 = *pK3;\n\n    for (n = 0; n < 16; n ++) {\n        sph_u32 *X = W[n];\n        sph_u32 Y0, Y1, Y2, Y3;\n        AES_ROUND_LE(X[0], X[1], X[2], X[3], K0, K1, K2, K3, Y0, Y1, Y2, Y3);\n        AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X[0], X[1], X[2], X[3]);\n        if ((K0 = T32(K0 + 1)) == 0)\n        {\n            if ((K1 = T32(K1 + 1)) == 0)\n            {\n                if ((K2 = T32(K2 + 1)) == 0)\n                {\n                    K3 = T32(K3 + 1);\n                }\n            }\n        }\n    }\n    *pK0 = K0;\n    *pK1 = K1;\n    *pK2 = K2;\n    *pK3 = K3;\n}\n\n#define BIG_SUB_WORDS   do { \\\n        aes_2rounds_all(W, &K0, &K1, &K2, &K3); \\\n    } while (0)\n\n#else\n\n#define AES_2ROUNDS(X)   do { \\\n        sph_u32 Y0, Y1, Y2, Y3; \\\n        AES_ROUND_LE(X[0], X[1], X[2], X[3], \\\n            K0, K1, K2, K3, Y0, Y1, Y2, Y3); \\\n        AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X[0], X[1], X[2], X[3]); \\\n        if ((K0 = T32(K0 + 1)) == 0) { \\\n            if ((K1 = T32(K1 + 1)) == 0) \\\n                if ((K2 = T32(K2 + 1)) == 0) \\\n                    K3 = T32(K3 + 1); \\\n        } \\\n    } while (0)\n\n#define BIG_SUB_WORDS   do { \\\n        AES_2ROUNDS(W[ 0]); \\\n        AES_2ROUNDS(W[ 1]); \\\n        AES_2ROUNDS(W[ 2]); \\\n        AES_2ROUNDS(W[ 3]); \\\n        AES_2ROUNDS(W[ 4]); \\\n        AES_2ROUNDS(W[ 5]); \\\n        AES_2ROUNDS(W[ 6]); \\\n        AES_2ROUNDS(W[ 7]); \\\n        AES_2ROUNDS(W[ 8]); \\\n        AES_2ROUNDS(W[ 9]); \\\n        AES_2ROUNDS(W[10]); \\\n        AES_2ROUNDS(W[11]); \\\n        AES_2ROUNDS(W[12]); \\\n        AES_2ROUNDS(W[13]); \\\n        AES_2ROUNDS(W[14]); \\\n        AES_2ROUNDS(W[15]); \\\n    } while (0)\n\n#endif\n\n#define SHIFT_ROW1(a, b, c, d)   do { \\\n        sph_u32 tmp; \\\n        tmp = W[a][0]; \\\n        W[a][0] = W[b][0]; \\\n        W[b][0] = W[c][0]; \\\n        W[c][0] = W[d][0]; \\\n        W[d][0] = tmp; \\\n        tmp = W[a][1]; \\\n        W[a][1] = W[b][1]; \\\n        W[b][1] = W[c][1]; \\\n        W[c][1] = W[d][1]; \\\n        W[d][1] = tmp; \\\n        tmp = W[a][2]; \\\n        W[a][2] = W[b][2]; \\\n        W[b][2] = W[c][2]; \\\n        W[c][2] = W[d][2]; \\\n        W[d][2] = tmp; \\\n        tmp = W[a][3]; \\\n        W[a][3] = W[b][3]; \\\n        W[b][3] = W[c][3]; \\\n        W[c][3] = W[d][3]; \\\n        W[d][3] = tmp; \\\n    } while (0)\n\n#define SHIFT_ROW2(a, b, c, d)   do { \\\n        sph_u32 tmp; \\\n        tmp = W[a][0]; \\\n        W[a][0] = W[c][0]; \\\n        W[c][0] = tmp; \\\n        tmp = W[b][0]; \\\n        W[b][0] = W[d][0]; \\\n        W[d][0] = tmp; \\\n        tmp = W[a][1]; \\\n        W[a][1] = W[c][1]; \\\n        W[c][1] = tmp; \\\n        tmp = W[b][1]; \\\n        W[b][1] = W[d][1]; \\\n        W[d][1] = tmp; \\\n        tmp = W[a][2]; \\\n        W[a][2] = W[c][2]; \\\n        W[c][2] = tmp; \\\n        tmp = W[b][2]; \\\n        W[b][2] = W[d][2]; \\\n        W[d][2] = tmp; \\\n        tmp = W[a][3]; \\\n        W[a][3] = W[c][3]; \\\n        W[c][3] = tmp; \\\n        tmp = W[b][3]; \\\n        W[b][3] = W[d][3]; \\\n        W[d][3] = tmp; \\\n    } while (0)\n\n#define SHIFT_ROW3(a, b, c, d)   SHIFT_ROW1(d, c, b, a)\n\n#define BIG_SHIFT_ROWS   do { \\\n        SHIFT_ROW1(1, 5, 9, 13); \\\n        SHIFT_ROW2(2, 6, 10, 14); \\\n        SHIFT_ROW3(3, 7, 11, 15); \\\n    } while (0)\n\n#if SPH_SMALL_FOOTPRINT_ECHO\n\nstatic void mix_column(sph_u32 W[16][4], int ia, int ib, int ic, int id)\n{\n    int n;\n\n    for (n = 0; n < 4; n ++)\n    {\n        sph_u32 a = W[ia][n];\n        sph_u32 b = W[ib][n];\n        sph_u32 c = W[ic][n];\n        sph_u32 d = W[id][n];\n        sph_u32 ab = a ^ b;\n        sph_u32 bc = b ^ c;\n        sph_u32 cd = c ^ d;\n        sph_u32 abx = ((ab & C32(0x80808080)) >> 7) * 27U ^ ((ab & C32(0x7F7F7F7F)) << 1);\n        sph_u32 bcx = ((bc & C32(0x80808080)) >> 7) * 27U ^ ((bc & C32(0x7F7F7F7F)) << 1);\n        sph_u32 cdx = ((cd & C32(0x80808080)) >> 7) * 27U ^ ((cd & C32(0x7F7F7F7F)) << 1);\n        W[ia][n] = abx ^ bc ^ d;\n        W[ib][n] = bcx ^ a ^ cd;\n        W[ic][n] = cdx ^ ab ^ d;\n        W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c;\n    }\n}\n\n#define MIX_COLUMN(a, b, c, d)   mix_column(W, a, b, c, d)\n\n#else\n\n#define MIX_COLUMN1(ia, ib, ic, id, n)   do { \\\n        sph_u32 a = W[ia][n]; \\\n        sph_u32 b = W[ib][n]; \\\n        sph_u32 c = W[ic][n]; \\\n        sph_u32 d = W[id][n]; \\\n        sph_u32 ab = a ^ b; \\\n        sph_u32 bc = b ^ c; \\\n        sph_u32 cd = c ^ d; \\\n        sph_u32 abx = ((ab & C32(0x80808080)) >> 7) * 27U ^ ((ab & C32(0x7F7F7F7F)) << 1); \\\n        sph_u32 bcx = ((bc & C32(0x80808080)) >> 7) * 27U ^ ((bc & C32(0x7F7F7F7F)) << 1); \\\n        sph_u32 cdx = ((cd & C32(0x80808080)) >> 7) * 27U ^ ((cd & C32(0x7F7F7F7F)) << 1); \\\n        W[ia][n] = abx ^ bc ^ d; \\\n        W[ib][n] = bcx ^ a ^ cd; \\\n        W[ic][n] = cdx ^ ab ^ d; \\\n        W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; \\\n    } while (0)\n\n#define MIX_COLUMN(a, b, c, d)   do { \\\n        MIX_COLUMN1(a, b, c, d, 0); \\\n        MIX_COLUMN1(a, b, c, d, 1); \\\n        MIX_COLUMN1(a, b, c, d, 2); \\\n        MIX_COLUMN1(a, b, c, d, 3); \\\n    } while (0)\n\n#endif\n\n#define BIG_MIX_COLUMNS   do { \\\n        MIX_COLUMN(0, 1, 2, 3); \\\n        MIX_COLUMN(4, 5, 6, 7); \\\n        MIX_COLUMN(8, 9, 10, 11); \\\n        MIX_COLUMN(12, 13, 14, 15); \\\n    } while (0)\n\n#define BIG_ROUND   do { \\\n        BIG_SUB_WORDS; \\\n        BIG_SHIFT_ROWS; \\\n        BIG_MIX_COLUMNS; \\\n    } while (0)\n\n#define FINAL_SMALL   do { \\\n        unsigned u; \\\n        sph_u32 *VV = &sc->u.Vs[0][0]; \\\n        sph_u32 *WW = &W[0][0]; \\\n        for (u = 0; u < 16; u ++) { \\\n            VV[u] ^= sph_dec32le_aligned(sc->buf + (u * 4)) ^ sph_dec32le_aligned(sc->buf + (u * 4) + 64) ^ sph_dec32le_aligned(sc->buf + (u * 4) + 128) ^ WW[u] ^ WW[u + 16] ^ WW[u + 32] ^ WW[u + 48]; \\\n        } \\\n    } while (0)\n\n#define COMPRESS_SMALL(sc)   do { \\\n        sph_u32 K0 = sc->C0; \\\n        sph_u32 K1 = sc->C1; \\\n        sph_u32 K2 = sc->C2; \\\n        sph_u32 K3 = sc->C3; \\\n        unsigned u; \\\n        INPUT_BLOCK_SMALL(sc); \\\n        for (u = 0; u < 8; u ++) { \\\n            BIG_ROUND; \\\n        } \\\n        FINAL_SMALL; \\\n    } while (0)\n\n#endif\n\n#define INCR_COUNTER(sc, val)   do { \\\n        sc->C0 = T32(sc->C0 + (sph_u32)(val)); \\\n        if (sc->C0 < (sph_u32)(val)) { \\\n            if ((sc->C1 = T32(sc->C1 + 1)) == 0) \\\n                if ((sc->C2 = T32(sc->C2 + 1)) == 0) \\\n                    sc->C3 = T32(sc->C3 + 1); \\\n        } \\\n    } while (0)\n\nstatic void echo_small_init(sph_echo256_context *sc, unsigned out_len)\n{\n#if SPH_ECHO_64\n    sc->u.Vb[0][0] = (sph_u64)out_len;\n    sc->u.Vb[0][1] = 0;\n    sc->u.Vb[1][0] = (sph_u64)out_len;\n    sc->u.Vb[1][1] = 0;\n    sc->u.Vb[2][0] = (sph_u64)out_len;\n    sc->u.Vb[2][1] = 0;\n    sc->u.Vb[3][0] = (sph_u64)out_len;\n    sc->u.Vb[3][1] = 0;\n#else\n    sc->u.Vs[0][0] = (sph_u32)out_len;\n    sc->u.Vs[0][1] = sc->u.Vs[0][2] = sc->u.Vs[0][3] = 0;\n    sc->u.Vs[1][0] = (sph_u32)out_len;\n    sc->u.Vs[1][1] = sc->u.Vs[1][2] = sc->u.Vs[1][3] = 0;\n    sc->u.Vs[2][0] = (sph_u32)out_len;\n    sc->u.Vs[2][1] = sc->u.Vs[2][2] = sc->u.Vs[2][3] = 0;\n    sc->u.Vs[3][0] = (sph_u32)out_len;\n    sc->u.Vs[3][1] = sc->u.Vs[3][2] = sc->u.Vs[3][3] = 0;\n#endif\n    sc->ptr = 0;\n    sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;\n}\n\nstatic void echo_small_compress(sph_echo256_context *sc)\n{\n    DECL_STATE_SMALL\n\n    COMPRESS_SMALL(sc);\n}\n\nstatic void echo_small_core(sph_echo256_context *sc, const unsigned char *data, size_t len)\n{\n    unsigned char *buf;\n    size_t ptr;\n\n    buf = sc->buf;\n    ptr = sc->ptr;\n    if (len < (sizeof sc->buf) - ptr)\n    {\n        memcpy(buf + ptr, data, len);\n        ptr += len;\n        sc->ptr = ptr;\n        return;\n    }\n\n    while (len > 0)\n    {\n        size_t clen;\n\n        clen = (sizeof sc->buf) - ptr;\n        if (clen > len)\n            clen = len;\n        memcpy(buf + ptr, data, clen);\n        ptr += clen;\n        data += clen;\n        len -= clen;\n        if (ptr == sizeof sc->buf)\n        {\n            INCR_COUNTER(sc, 1536);\n            echo_small_compress(sc);\n            ptr = 0;\n        }\n    }\n    sc->ptr = ptr;\n}\n\nstatic void echo_small_close(sph_echo256_context *sc, unsigned ub, unsigned n, void *dst, unsigned out_size_w32)\n{\n    unsigned char *buf;\n    size_t ptr;\n    unsigned z;\n    unsigned elen;\n    union\n    {\n        unsigned char tmp[32];\n        sph_u32 dummy;\n#if SPH_ECHO_64\n        sph_u64 dummy2;\n#endif\n    } u;\n#if SPH_ECHO_64\n    sph_u64 *VV;\n#else\n    sph_u32 *VV;\n#endif\n    unsigned k;\n\n    buf = sc->buf;\n    ptr = sc->ptr;\n    elen = ((unsigned)ptr << 3) + n;\n    INCR_COUNTER(sc, elen);\n    sph_enc32le_aligned(u.tmp, sc->C0);\n    sph_enc32le_aligned(u.tmp + 4, sc->C1);\n    sph_enc32le_aligned(u.tmp + 8, sc->C2);\n    sph_enc32le_aligned(u.tmp + 12, sc->C3);\n    /*\n     * If elen is zero, then this block actually contains no message\n     * bit, only the first padding bit.\n     */\n    if (elen == 0)\n    {\n        sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;\n    }\n    z = 0x80 >> n;\n    buf[ptr ++] = ((ub & -z) | z) & 0xFF;\n    memset(buf + ptr, 0, (sizeof sc->buf) - ptr);\n    if (ptr > ((sizeof sc->buf) - 18))\n    {\n        echo_small_compress(sc);\n        sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;\n        memset(buf, 0, sizeof sc->buf);\n    }\n    sph_enc16le(buf + (sizeof sc->buf) - 18, out_size_w32 << 5);\n    memcpy(buf + (sizeof sc->buf) - 16, u.tmp, 16);\n    echo_small_compress(sc);\n#if SPH_ECHO_64\n    for (VV = &sc->u.Vb[0][0], k = 0; k < ((out_size_w32 + 1) >> 1); k ++)\n    {\n        sph_enc64le_aligned(u.tmp + (k << 3), VV[k]);\n    }\n#else\n    for (VV = &sc->u.Vs[0][0], k = 0; k < out_size_w32; k ++)\n    {\n        sph_enc32le_aligned(u.tmp + (k << 2), VV[k]);\n    }\n#endif\n    memcpy(dst, u.tmp, out_size_w32 << 2);\n    echo_small_init(sc, out_size_w32 << 5);\n}\n\n/* see sph_echo.h */\nvoid sph_echo256_init(void *cc)\n{\n    echo_small_init((sph_echo256_context*)cc, 256);\n}\n\n/* see sph_echo.h */\nvoid sph_echo256(void *cc, const void *data, size_t len)\n{\n    echo_small_core((sph_echo256_context*)cc, (const unsigned char*)data, len);\n}\n\n/* see sph_echo.h */\nvoid sph_echo256_close(void *cc, void *dst)\n{\n    echo_small_close((sph_echo256_context*)cc, 0, 0, dst, 8);\n}\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/sphlib/sph_echo.h",
    "content": "/* $Id: sph_echo.h 216 2010-06-08 09:46:57Z tp $ */\n/**\n * ECHO interface. ECHO is a family of functions which differ by\n * their output size; this implementation defines ECHO for output\n * sizes 224, 256, 384 and 512 bits.\n *\n * ==========================(LICENSE BEGIN)============================\n *\n * Copyright (c) 2007-2010  Projet RNRT SAPHIR\n * \n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n * \n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * ===========================(LICENSE END)=============================\n *\n * @file     sph_echo.h\n * @author   Thomas Pornin <thomas.pornin@cryptolog.com>\n */\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SPH_ECHO_H__\n#define SPH_ECHO_H__\n\n#include <stddef.h>\n#include \"sph_types.h\"\n\n/**\n * This structure is a context for ECHO computations: it contains the\n * intermediate values and some data from the last entered block. Once\n * an ECHO computation has been performed, the context can be reused for\n * another computation. This specific structure is used for ECHO-224\n * and ECHO-256.\n *\n * The contents of this structure are private. A running ECHO computation\n * can be cloned by copying the context (e.g. with a simple\n * <code>memcpy()</code>).\n */\ntypedef struct {\n    unsigned char buf[192];    /* first field, for alignment */\n    size_t ptr;\n    union {\n        sph_u32 Vs[4][4];\n#if SPH_64\n        sph_u64 Vb[4][2];\n#endif\n    } u;\n    sph_u32 C0, C1, C2, C3;\n} sph_echo256_context;\n\n/**\n * Initialize an ECHO-256 context. This process performs no memory allocation.\n *\n * @param cc   the ECHO-256 context (pointer to a\n *             <code>sph_echo256_context</code>)\n */\nvoid sph_echo256_init(void *cc);\n\n/**\n * Process some data bytes. It is acceptable that <code>len</code> is zero\n * (in which case this function does nothing).\n *\n * @param cc     the ECHO-256 context\n * @param data   the input data\n * @param len    the input data length (in bytes)\n */\nvoid sph_echo256(void *cc, const void *data, size_t len);\n\n/**\n * Terminate the current ECHO-256 computation and output the result into\n * the provided buffer. The destination buffer must be wide enough to\n * accomodate the result (32 bytes). The context is automatically\n * reinitialized.\n *\n * @param cc    the ECHO-256 context\n * @param dst   the destination buffer\n */\nvoid sph_echo256_close(void *cc, void *dst);\n\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/echo256/sphlib/sph_types.h",
    "content": "/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */\n/**\n * Basic type definitions.\n *\n * This header file defines the generic integer types that will be used\n * for the implementation of hash functions; it also contains helper\n * functions which encode and decode multi-byte integer values, using\n * either little-endian or big-endian conventions.\n *\n * This file contains a compile-time test on the size of a byte\n * (the <code>unsigned char</code> C type). If bytes are not octets,\n * i.e. if they do not have a size of exactly 8 bits, then compilation\n * is aborted. Architectures where bytes are not octets are relatively\n * rare, even in the embedded devices market. We forbid non-octet bytes\n * because there is no clear convention on how octet streams are encoded\n * on such systems.\n *\n * ==========================(LICENSE BEGIN)============================\n *\n * Copyright (c) 2007-2010  Projet RNRT SAPHIR\n * \n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n * \n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * ===========================(LICENSE END)=============================\n *\n * @file     sph_types.h\n * @author   Thomas Pornin <thomas.pornin@cryptolog.com>\n */\n\n#ifndef SPH_TYPES_H__\n#define SPH_TYPES_H__\n\n#include <limits.h>\n\n/*\n * All our I/O functions are defined over octet streams. We do not know\n * how to handle input data if bytes are not octets.\n */\n#if CHAR_BIT != 8\n#error This code requires 8-bit bytes\n#endif\n\n/* ============= BEGIN documentation block for Doxygen ============ */\n\n#ifdef DOXYGEN_IGNORE\n\n/** @mainpage sphlib C code documentation\n *\n * @section overview Overview\n *\n * <code>sphlib</code> is a library which contains implementations of\n * various cryptographic hash functions. These pages have been generated\n * with <a href=\"http://www.doxygen.org/index.html\">doxygen</a> and\n * document the API for the C implementations.\n *\n * The API is described in appropriate header files, which are available\n * in the \"Files\" section. Each hash function family has its own header,\n * whose name begins with <code>\"sph_\"</code> and contains the family\n * name. For instance, the API for the RIPEMD hash functions is available\n * in the header file <code>sph_ripemd.h</code>.\n *\n * @section principles API structure and conventions\n *\n * @subsection io Input/output conventions\n *\n * In all generality, hash functions operate over strings of bits.\n * Individual bits are rarely encountered in C programming or actual\n * communication protocols; most protocols converge on the ubiquitous\n * \"octet\" which is a group of eight bits. Data is thus expressed as a\n * stream of octets. The C programming language contains the notion of a\n * \"byte\", which is a data unit managed under the type <code>\"unsigned\n * char\"</code>. The C standard prescribes that a byte should hold at\n * least eight bits, but possibly more. Most modern architectures, even\n * in the embedded world, feature eight-bit bytes, i.e. map bytes to\n * octets.\n *\n * Nevertheless, for some of the implemented hash functions, an extra\n * API has been added, which allows the input of arbitrary sequences of\n * bits: when the computation is about to be closed, 1 to 7 extra bits\n * can be added. The functions for which this API is implemented include\n * the SHA-2 functions and all SHA-3 candidates.\n *\n * <code>sphlib</code> defines hash function which may hash octet streams,\n * i.e. streams of bits where the number of bits is a multiple of eight.\n * The data input functions in the <code>sphlib</code> API expect data\n * as anonymous pointers (<code>\"const void *\"</code>) with a length\n * (of type <code>\"size_t\"</code>) which gives the input data chunk length\n * in bytes. A byte is assumed to be an octet; the <code>sph_types.h</code>\n * header contains a compile-time test which prevents compilation on\n * architectures where this property is not met.\n *\n * The hash function output is also converted into bytes. All currently\n * implemented hash functions have an output width which is a multiple of\n * eight, and this is likely to remain true for new designs.\n *\n * Most hash functions internally convert input data into 32-bit of 64-bit\n * words, using either little-endian or big-endian conversion. The hash\n * output also often consists of such words, which are encoded into output\n * bytes with a similar endianness convention. Some hash functions have\n * been only loosely specified on that subject; when necessary,\n * <code>sphlib</code> has been tested against published \"reference\"\n * implementations in order to use the same conventions.\n *\n * @subsection shortname Function short name\n *\n * Each implemented hash function has a \"short name\" which is used\n * internally to derive the identifiers for the functions and context\n * structures which the function uses. For instance, MD5 has the short\n * name <code>\"md5\"</code>. Short names are listed in the next section,\n * for the implemented hash functions. In subsequent sections, the\n * short name will be assumed to be <code>\"XXX\"</code>: replace with the\n * actual hash function name to get the C identifier.\n *\n * Note: some functions within the same family share the same core\n * elements, such as update function or context structure. Correspondingly,\n * some of the defined types or functions may actually be macros which\n * transparently evaluate to another type or function name.\n *\n * @subsection context Context structure\n *\n * Each implemented hash fonction has its own context structure, available\n * under the type name <code>\"sph_XXX_context\"</code> for the hash function\n * with short name <code>\"XXX\"</code>. This structure holds all needed\n * state for a running hash computation.\n *\n * The contents of these structures are meant to be opaque, and private\n * to the implementation. However, these contents are specified in the\n * header files so that application code which uses <code>sphlib</code>\n * may access the size of those structures.\n *\n * The caller is responsible for allocating the context structure,\n * whether by dynamic allocation (<code>malloc()</code> or equivalent),\n * static allocation (a global permanent variable), as an automatic\n * variable (\"on the stack\"), or by any other mean which ensures proper\n * structure alignment. <code>sphlib</code> code performs no dynamic\n * allocation by itself.\n *\n * The context must be initialized before use, using the\n * <code>sph_XXX_init()</code> function. This function sets the context\n * state to proper initial values for hashing.\n *\n * Since all state data is contained within the context structure,\n * <code>sphlib</code> is thread-safe and reentrant: several hash\n * computations may be performed in parallel, provided that they do not\n * operate on the same context. Moreover, a running computation can be\n * cloned by copying the context (with a simple <code>memcpy()</code>):\n * the context and its clone are then independant and may be updated\n * with new data and/or closed without interfering with each other.\n * Similarly, a context structure can be moved in memory at will:\n * context structures contain no pointer, in particular no pointer to\n * themselves.\n *\n * @subsection dataio Data input\n *\n * Hashed data is input with the <code>sph_XXX()</code> fonction, which\n * takes as parameters a pointer to the context, a pointer to the data\n * to hash, and the number of data bytes to hash. The context is updated\n * with the new data.\n *\n * Data can be input in one or several calls, with arbitrary input lengths.\n * However, it is best, performance wise, to input data by relatively big\n * chunks (say a few kilobytes), because this allows <code>sphlib</code> to\n * optimize things and avoid internal copying.\n *\n * When all data has been input, the context can be closed with\n * <code>sph_XXX_close()</code>. The hash output is computed and written\n * into the provided buffer. The caller must take care to provide a\n * buffer of appropriate length; e.g., when using SHA-1, the output is\n * a 20-byte word, therefore the output buffer must be at least 20-byte\n * long.\n *\n * For some hash functions, the <code>sph_XXX_addbits_and_close()</code>\n * function can be used instead of <code>sph_XXX_close()</code>. This\n * function can take a few extra <strong>bits</strong> to be added at\n * the end of the input message. This allows hashing messages with a\n * bit length which is not a multiple of 8. The extra bits are provided\n * as an unsigned integer value, and a bit count. The bit count must be\n * between 0 and 7, inclusive. The extra bits are provided as bits 7 to\n * 0 (bits of numerical value 128, 64, 32... downto 0), in that order.\n * For instance, to add three bits of value 1, 1 and 0, the unsigned\n * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count\n * will be 3.\n *\n * The <code>SPH_SIZE_XXX</code> macro is defined for each hash function;\n * it evaluates to the function output size, expressed in bits. For instance,\n * <code>SPH_SIZE_sha1</code> evaluates to <code>160</code>.\n *\n * When closed, the context is automatically reinitialized and can be\n * immediately used for another computation. It is not necessary to call\n * <code>sph_XXX_init()</code> after a close. Note that\n * <code>sph_XXX_init()</code> can still be called to \"reset\" a context,\n * i.e. forget previously input data, and get back to the initial state.\n *\n * @subsection alignment Data alignment\n *\n * \"Alignment\" is a property of data, which is said to be \"properly\n * aligned\" when its emplacement in memory is such that the data can\n * be optimally read by full words. This depends on the type of access;\n * basically, some hash functions will read data by 32-bit or 64-bit\n * words. <code>sphlib</code> does not mandate such alignment for input\n * data, but using aligned data can substantially improve performance.\n *\n * As a rule, it is best to input data by chunks whose length (in bytes)\n * is a multiple of eight, and which begins at \"generally aligned\"\n * addresses, such as the base address returned by a call to\n * <code>malloc()</code>.\n *\n * @section functions Implemented functions\n *\n * We give here the list of implemented functions. They are grouped by\n * family; to each family corresponds a specific header file. Each\n * individual function has its associated \"short name\". Please refer to\n * the documentation for that header file to get details on the hash\n * function denomination and provenance.\n *\n * Note: the functions marked with a '(64)' in the list below are\n * available only if the C compiler provides an integer type of length\n * 64 bits or more. Such a type is mandatory in the latest C standard\n * (ISO 9899:1999, aka \"C99\") and is present in several older compilers\n * as well, so chances are that such a type is available.\n *\n * - HAVAL family: file <code>sph_haval.h</code>\n *   - HAVAL-128/3 (128-bit, 3 passes): short name: <code>haval128_3</code>\n *   - HAVAL-128/4 (128-bit, 4 passes): short name: <code>haval128_4</code>\n *   - HAVAL-128/5 (128-bit, 5 passes): short name: <code>haval128_5</code>\n *   - HAVAL-160/3 (160-bit, 3 passes): short name: <code>haval160_3</code>\n *   - HAVAL-160/4 (160-bit, 4 passes): short name: <code>haval160_4</code>\n *   - HAVAL-160/5 (160-bit, 5 passes): short name: <code>haval160_5</code>\n *   - HAVAL-192/3 (192-bit, 3 passes): short name: <code>haval192_3</code>\n *   - HAVAL-192/4 (192-bit, 4 passes): short name: <code>haval192_4</code>\n *   - HAVAL-192/5 (192-bit, 5 passes): short name: <code>haval192_5</code>\n *   - HAVAL-224/3 (224-bit, 3 passes): short name: <code>haval224_3</code>\n *   - HAVAL-224/4 (224-bit, 4 passes): short name: <code>haval224_4</code>\n *   - HAVAL-224/5 (224-bit, 5 passes): short name: <code>haval224_5</code>\n *   - HAVAL-256/3 (256-bit, 3 passes): short name: <code>haval256_3</code>\n *   - HAVAL-256/4 (256-bit, 4 passes): short name: <code>haval256_4</code>\n *   - HAVAL-256/5 (256-bit, 5 passes): short name: <code>haval256_5</code>\n * - MD2: file <code>sph_md2.h</code>, short name: <code>md2</code>\n * - MD4: file <code>sph_md4.h</code>, short name: <code>md4</code>\n * - MD5: file <code>sph_md5.h</code>, short name: <code>md5</code>\n * - PANAMA: file <code>sph_panama.h</code>, short name: <code>panama</code>\n * - RadioGatun family: file <code>sph_radiogatun.h</code>\n *   - RadioGatun[32]: short name: <code>radiogatun32</code>\n *   - RadioGatun[64]: short name: <code>radiogatun64</code> (64)\n * - RIPEMD family: file <code>sph_ripemd.h</code>\n *   - RIPEMD: short name: <code>ripemd</code>\n *   - RIPEMD-128: short name: <code>ripemd128</code>\n *   - RIPEMD-160: short name: <code>ripemd160</code>\n * - SHA-0: file <code>sph_sha0.h</code>, short name: <code>sha0</code>\n * - SHA-1: file <code>sph_sha1.h</code>, short name: <code>sha1</code>\n * - SHA-2 family, 32-bit hashes: file <code>sph_sha2.h</code>\n *   - SHA-224: short name: <code>sha224</code>\n *   - SHA-256: short name: <code>sha256</code>\n *   - SHA-384: short name: <code>sha384</code> (64)\n *   - SHA-512: short name: <code>sha512</code> (64)\n * - Tiger family: file <code>sph_tiger.h</code>\n *   - Tiger: short name: <code>tiger</code> (64)\n *   - Tiger2: short name: <code>tiger2</code> (64)\n * - WHIRLPOOL family: file <code>sph_whirlpool.h</code>\n *   - WHIRLPOOL-0: short name: <code>whirlpool0</code> (64)\n *   - WHIRLPOOL-1: short name: <code>whirlpool1</code> (64)\n *   - WHIRLPOOL: short name: <code>whirlpool</code> (64)\n *\n * The fourteen second-round SHA-3 candidates are also implemented;\n * when applicable, the implementations follow the \"final\" specifications\n * as published for the third round of the SHA-3 competition (BLAKE,\n * Groestl, JH, Keccak and Skein have been tweaked for third round).\n *\n * - BLAKE family: file <code>sph_blake.h</code>\n *   - BLAKE-224: short name: <code>blake224</code>\n *   - BLAKE-256: short name: <code>blake256</code>\n *   - BLAKE-384: short name: <code>blake384</code>\n *   - BLAKE-512: short name: <code>blake512</code>\n * - BMW (Blue Midnight Wish) family: file <code>sph_bmw.h</code>\n *   - BMW-224: short name: <code>bmw224</code>\n *   - BMW-256: short name: <code>bmw256</code>\n *   - BMW-384: short name: <code>bmw384</code> (64)\n *   - BMW-512: short name: <code>bmw512</code> (64)\n * - CubeHash family: file <code>sph_cubehash.h</code> (specified as\n *   CubeHash16/32 in the CubeHash specification)\n *   - CubeHash-224: short name: <code>cubehash224</code>\n *   - CubeHash-256: short name: <code>cubehash256</code>\n *   - CubeHash-384: short name: <code>cubehash384</code>\n *   - CubeHash-512: short name: <code>cubehash512</code>\n * - ECHO family: file <code>sph_echo.h</code>\n *   - ECHO-224: short name: <code>echo224</code>\n *   - ECHO-256: short name: <code>echo256</code>\n *   - ECHO-384: short name: <code>echo384</code>\n *   - ECHO-512: short name: <code>echo512</code>\n * - Fugue family: file <code>sph_fugue.h</code>\n *   - Fugue-224: short name: <code>fugue224</code>\n *   - Fugue-256: short name: <code>fugue256</code>\n *   - Fugue-384: short name: <code>fugue384</code>\n *   - Fugue-512: short name: <code>fugue512</code>\n * - Groestl family: file <code>sph_groestl.h</code>\n *   - Groestl-224: short name: <code>groestl224</code>\n *   - Groestl-256: short name: <code>groestl256</code>\n *   - Groestl-384: short name: <code>groestl384</code>\n *   - Groestl-512: short name: <code>groestl512</code>\n * - Hamsi family: file <code>sph_hamsi.h</code>\n *   - Hamsi-224: short name: <code>hamsi224</code>\n *   - Hamsi-256: short name: <code>hamsi256</code>\n *   - Hamsi-384: short name: <code>hamsi384</code>\n *   - Hamsi-512: short name: <code>hamsi512</code>\n * - JH family: file <code>sph_jh.h</code>\n *   - JH-224: short name: <code>jh224</code>\n *   - JH-256: short name: <code>jh256</code>\n *   - JH-384: short name: <code>jh384</code>\n *   - JH-512: short name: <code>jh512</code>\n * - Keccak family: file <code>sph_keccak.h</code>\n *   - Keccak-224: short name: <code>keccak224</code>\n *   - Keccak-256: short name: <code>keccak256</code>\n *   - Keccak-384: short name: <code>keccak384</code>\n *   - Keccak-512: short name: <code>keccak512</code>\n * - Luffa family: file <code>sph_luffa.h</code>\n *   - Luffa-224: short name: <code>luffa224</code>\n *   - Luffa-256: short name: <code>luffa256</code>\n *   - Luffa-384: short name: <code>luffa384</code>\n *   - Luffa-512: short name: <code>luffa512</code>\n * - Shabal family: file <code>sph_shabal.h</code>\n *   - Shabal-192: short name: <code>shabal192</code>\n *   - Shabal-224: short name: <code>shabal224</code>\n *   - Shabal-256: short name: <code>shabal256</code>\n *   - Shabal-384: short name: <code>shabal384</code>\n *   - Shabal-512: short name: <code>shabal512</code>\n * - SHAvite-3 family: file <code>sph_shavite.h</code>\n *   - SHAvite-224 (nominally \"SHAvite-3 with 224-bit output\"):\n *     short name: <code>shabal224</code>\n *   - SHAvite-256 (nominally \"SHAvite-3 with 256-bit output\"):\n *     short name: <code>shabal256</code>\n *   - SHAvite-384 (nominally \"SHAvite-3 with 384-bit output\"):\n *     short name: <code>shabal384</code>\n *   - SHAvite-512 (nominally \"SHAvite-3 with 512-bit output\"):\n *     short name: <code>shabal512</code>\n * - SIMD family: file <code>sph_simd.h</code>\n *   - SIMD-224: short name: <code>simd224</code>\n *   - SIMD-256: short name: <code>simd256</code>\n *   - SIMD-384: short name: <code>simd384</code>\n *   - SIMD-512: short name: <code>simd512</code>\n * - Skein family: file <code>sph_skein.h</code>\n *   - Skein-224 (nominally specified as Skein-512-224): short name:\n *     <code>skein224</code> (64)\n *   - Skein-256 (nominally specified as Skein-512-256): short name:\n *     <code>skein256</code> (64)\n *   - Skein-384 (nominally specified as Skein-512-384): short name:\n *     <code>skein384</code> (64)\n *   - Skein-512 (nominally specified as Skein-512-512): short name:\n *     <code>skein512</code> (64)\n *\n * For the second-round SHA-3 candidates, the functions are as specified\n * for round 2, i.e. with the \"tweaks\" that some candidates added\n * between round 1 and round 2. Also, some of the submitted packages for\n * round 2 contained errors, in the specification, reference code, or\n * both. <code>sphlib</code> implements the corrected versions.\n */\n\n/** @hideinitializer\n * Unsigned integer type whose length is at least 32 bits; on most\n * architectures, it will have a width of exactly 32 bits. Unsigned C\n * types implement arithmetics modulo a power of 2; use the\n * <code>SPH_T32()</code> macro to ensure that the value is truncated\n * to exactly 32 bits. Unless otherwise specified, all macros and\n * functions which accept <code>sph_u32</code> values assume that these\n * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures\n * where <code>sph_u32</code> is larger than that.\n */\ntypedef __arch_dependant__ sph_u32;\n\n/** @hideinitializer\n * Signed integer type corresponding to <code>sph_u32</code>; it has\n * width 32 bits or more.\n */\ntypedef __arch_dependant__ sph_s32;\n\n/** @hideinitializer\n * Unsigned integer type whose length is at least 64 bits; on most\n * architectures which feature such a type, it will have a width of\n * exactly 64 bits. C99-compliant platform will have this type; it\n * is also defined when the GNU compiler (gcc) is used, and on\n * platforms where <code>unsigned long</code> is large enough. If this\n * type is not available, then some hash functions which depends on\n * a 64-bit type will not be available (most notably SHA-384, SHA-512,\n * Tiger and WHIRLPOOL).\n */\ntypedef __arch_dependant__ sph_u64;\n\n/** @hideinitializer\n * Signed integer type corresponding to <code>sph_u64</code>; it has\n * width 64 bits or more.\n */\ntypedef __arch_dependant__ sph_s64;\n\n/**\n * This macro expands the token <code>x</code> into a suitable\n * constant expression of type <code>sph_u32</code>. Depending on\n * how this type is defined, a suffix such as <code>UL</code> may\n * be appended to the argument.\n *\n * @param x   the token to expand into a suitable constant expression\n */\n#define SPH_C32(x)\n\n/**\n * Truncate a 32-bit value to exactly 32 bits. On most systems, this is\n * a no-op, recognized as such by the compiler.\n *\n * @param x   the value to truncate (of type <code>sph_u32</code>)\n */\n#define SPH_T32(x)\n\n/**\n * Rotate a 32-bit value by a number of bits to the left. The rotate\n * count must reside between 1 and 31. This macro assumes that its\n * first argument fits in 32 bits (no extra bit allowed on machines where\n * <code>sph_u32</code> is wider); both arguments may be evaluated\n * several times.\n *\n * @param x   the value to rotate (of type <code>sph_u32</code>)\n * @param n   the rotation count (between 1 and 31, inclusive)\n */\n#define SPH_ROTL32(x, n)\n\n/**\n * Rotate a 32-bit value by a number of bits to the left. The rotate\n * count must reside between 1 and 31. This macro assumes that its\n * first argument fits in 32 bits (no extra bit allowed on machines where\n * <code>sph_u32</code> is wider); both arguments may be evaluated\n * several times.\n *\n * @param x   the value to rotate (of type <code>sph_u32</code>)\n * @param n   the rotation count (between 1 and 31, inclusive)\n */\n#define SPH_ROTR32(x, n)\n\n/**\n * This macro is defined on systems for which a 64-bit type has been\n * detected, and is used for <code>sph_u64</code>.\n */\n#define SPH_64\n\n/**\n * This macro is defined on systems for the \"native\" integer size is\n * 64 bits (64-bit values fit in one register).\n */\n#define SPH_64_TRUE\n\n/**\n * This macro expands the token <code>x</code> into a suitable\n * constant expression of type <code>sph_u64</code>. Depending on\n * how this type is defined, a suffix such as <code>ULL</code> may\n * be appended to the argument. This macro is defined only if a\n * 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param x   the token to expand into a suitable constant expression\n */\n#define SPH_C64(x)\n\n/**\n * Truncate a 64-bit value to exactly 64 bits. On most systems, this is\n * a no-op, recognized as such by the compiler. This macro is defined only\n * if a 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param x   the value to truncate (of type <code>sph_u64</code>)\n */\n#define SPH_T64(x)\n\n/**\n * Rotate a 64-bit value by a number of bits to the left. The rotate\n * count must reside between 1 and 63. This macro assumes that its\n * first argument fits in 64 bits (no extra bit allowed on machines where\n * <code>sph_u64</code> is wider); both arguments may be evaluated\n * several times. This macro is defined only if a 64-bit type was detected\n * and used for <code>sph_u64</code>.\n *\n * @param x   the value to rotate (of type <code>sph_u64</code>)\n * @param n   the rotation count (between 1 and 63, inclusive)\n */\n#define SPH_ROTL64(x, n)\n\n/**\n * Rotate a 64-bit value by a number of bits to the left. The rotate\n * count must reside between 1 and 63. This macro assumes that its\n * first argument fits in 64 bits (no extra bit allowed on machines where\n * <code>sph_u64</code> is wider); both arguments may be evaluated\n * several times. This macro is defined only if a 64-bit type was detected\n * and used for <code>sph_u64</code>.\n *\n * @param x   the value to rotate (of type <code>sph_u64</code>)\n * @param n   the rotation count (between 1 and 63, inclusive)\n */\n#define SPH_ROTR64(x, n)\n\n/**\n * This macro evaluates to <code>inline</code> or an equivalent construction,\n * if available on the compilation platform, or to nothing otherwise. This\n * is used to declare inline functions, for which the compiler should\n * endeavour to include the code directly in the caller. Inline functions\n * are typically defined in header files as replacement for macros.\n */\n#define SPH_INLINE\n\n/**\n * This macro is defined if the platform has been detected as using\n * little-endian convention. This implies that the <code>sph_u32</code>\n * type (and the <code>sph_u64</code> type also, if it is defined) has\n * an exact width (i.e. exactly 32-bit, respectively 64-bit).\n */\n#define SPH_LITTLE_ENDIAN\n\n/**\n * This macro is defined if the platform has been detected as using\n * big-endian convention. This implies that the <code>sph_u32</code>\n * type (and the <code>sph_u64</code> type also, if it is defined) has\n * an exact width (i.e. exactly 32-bit, respectively 64-bit).\n */\n#define SPH_BIG_ENDIAN\n\n/**\n * This macro is defined if 32-bit words (and 64-bit words, if defined)\n * can be read from and written to memory efficiently in little-endian\n * convention. This is the case for little-endian platforms, and also\n * for the big-endian platforms which have special little-endian access\n * opcodes (e.g. Ultrasparc).\n */\n#define SPH_LITTLE_FAST\n\n/**\n * This macro is defined if 32-bit words (and 64-bit words, if defined)\n * can be read from and written to memory efficiently in big-endian\n * convention. This is the case for little-endian platforms, and also\n * for the little-endian platforms which have special big-endian access\n * opcodes.\n */\n#define SPH_BIG_FAST\n\n/**\n * On some platforms, this macro is defined to an unsigned integer type\n * into which pointer values may be cast. The resulting value can then\n * be tested for being a multiple of 2, 4 or 8, indicating an aligned\n * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses.\n */\n#define SPH_UPTR\n\n/**\n * When defined, this macro indicates that unaligned memory accesses\n * are possible with only a minor penalty, and thus should be prefered\n * over strategies which first copy data to an aligned buffer.\n */\n#define SPH_UNALIGNED\n\n/**\n * Byte-swap a 32-bit word (i.e. <code>0x12345678</code> becomes\n * <code>0x78563412</code>). This is an inline function which resorts\n * to inline assembly on some platforms, for better performance.\n *\n * @param x   the 32-bit value to byte-swap\n * @return  the byte-swapped value\n */\nstatic inline sph_u32 sph_bswap32(sph_u32 x);\n\n/**\n * Byte-swap a 64-bit word. This is an inline function which resorts\n * to inline assembly on some platforms, for better performance. This\n * function is defined only if a suitable 64-bit type was found for\n * <code>sph_u64</code>\n *\n * @param x   the 64-bit value to byte-swap\n * @return  the byte-swapped value\n */\nstatic inline sph_u64 sph_bswap64(sph_u64 x);\n\n/**\n * Decode a 16-bit unsigned value from memory, in little-endian convention\n * (least significant byte comes first).\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline unsigned sph_dec16le(const void *src);\n\n/**\n * Encode a 16-bit unsigned value into memory, in little-endian convention\n * (least significant byte comes first).\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc16le(void *dst, unsigned val);\n\n/**\n * Decode a 16-bit unsigned value from memory, in big-endian convention\n * (most significant byte comes first).\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline unsigned sph_dec16be(const void *src);\n\n/**\n * Encode a 16-bit unsigned value into memory, in big-endian convention\n * (most significant byte comes first).\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc16be(void *dst, unsigned val);\n\n/**\n * Decode a 32-bit unsigned value from memory, in little-endian convention\n * (least significant byte comes first).\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u32 sph_dec32le(const void *src);\n\n/**\n * Decode a 32-bit unsigned value from memory, in little-endian convention\n * (least significant byte comes first). This function assumes that the\n * source address is suitably aligned for a direct access, if the platform\n * supports such things; it can thus be marginally faster than the generic\n * <code>sph_dec32le()</code> function.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u32 sph_dec32le_aligned(const void *src);\n\n/**\n * Encode a 32-bit unsigned value into memory, in little-endian convention\n * (least significant byte comes first).\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc32le(void *dst, sph_u32 val);\n\n/**\n * Encode a 32-bit unsigned value into memory, in little-endian convention\n * (least significant byte comes first). This function assumes that the\n * destination address is suitably aligned for a direct access, if the\n * platform supports such things; it can thus be marginally faster than\n * the generic <code>sph_enc32le()</code> function.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc32le_aligned(void *dst, sph_u32 val);\n\n/**\n * Decode a 32-bit unsigned value from memory, in big-endian convention\n * (most significant byte comes first).\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u32 sph_dec32be(const void *src);\n\n/**\n * Decode a 32-bit unsigned value from memory, in big-endian convention\n * (most significant byte comes first). This function assumes that the\n * source address is suitably aligned for a direct access, if the platform\n * supports such things; it can thus be marginally faster than the generic\n * <code>sph_dec32be()</code> function.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u32 sph_dec32be_aligned(const void *src);\n\n/**\n * Encode a 32-bit unsigned value into memory, in big-endian convention\n * (most significant byte comes first).\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc32be(void *dst, sph_u32 val);\n\n/**\n * Encode a 32-bit unsigned value into memory, in big-endian convention\n * (most significant byte comes first). This function assumes that the\n * destination address is suitably aligned for a direct access, if the\n * platform supports such things; it can thus be marginally faster than\n * the generic <code>sph_enc32be()</code> function.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc32be_aligned(void *dst, sph_u32 val);\n\n/**\n * Decode a 64-bit unsigned value from memory, in little-endian convention\n * (least significant byte comes first). This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u64 sph_dec64le(const void *src);\n\n/**\n * Decode a 64-bit unsigned value from memory, in little-endian convention\n * (least significant byte comes first). This function assumes that the\n * source address is suitably aligned for a direct access, if the platform\n * supports such things; it can thus be marginally faster than the generic\n * <code>sph_dec64le()</code> function. This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u64 sph_dec64le_aligned(const void *src);\n\n/**\n * Encode a 64-bit unsigned value into memory, in little-endian convention\n * (least significant byte comes first). This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc64le(void *dst, sph_u64 val);\n\n/**\n * Encode a 64-bit unsigned value into memory, in little-endian convention\n * (least significant byte comes first). This function assumes that the\n * destination address is suitably aligned for a direct access, if the\n * platform supports such things; it can thus be marginally faster than\n * the generic <code>sph_enc64le()</code> function. This function is defined\n * only if a suitable 64-bit type was detected and used for\n * <code>sph_u64</code>.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc64le_aligned(void *dst, sph_u64 val);\n\n/**\n * Decode a 64-bit unsigned value from memory, in big-endian convention\n * (most significant byte comes first). This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u64 sph_dec64be(const void *src);\n\n/**\n * Decode a 64-bit unsigned value from memory, in big-endian convention\n * (most significant byte comes first). This function assumes that the\n * source address is suitably aligned for a direct access, if the platform\n * supports such things; it can thus be marginally faster than the generic\n * <code>sph_dec64be()</code> function. This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param src   the source address\n * @return  the decoded value\n */\nstatic inline sph_u64 sph_dec64be_aligned(const void *src);\n\n/**\n * Encode a 64-bit unsigned value into memory, in big-endian convention\n * (most significant byte comes first). This function is defined only\n * if a suitable 64-bit type was detected and used for <code>sph_u64</code>.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc64be(void *dst, sph_u64 val);\n\n/**\n * Encode a 64-bit unsigned value into memory, in big-endian convention\n * (most significant byte comes first). This function assumes that the\n * destination address is suitably aligned for a direct access, if the\n * platform supports such things; it can thus be marginally faster than\n * the generic <code>sph_enc64be()</code> function. This function is defined\n * only if a suitable 64-bit type was detected and used for\n * <code>sph_u64</code>.\n *\n * @param dst   the destination buffer\n * @param val   the value to encode\n */\nstatic inline void sph_enc64be_aligned(void *dst, sph_u64 val);\n\n#endif\n\n/* ============== END documentation block for Doxygen ============= */\n\n#ifndef DOXYGEN_IGNORE\n\n/*\n * We want to define the types \"sph_u32\" and \"sph_u64\" which hold\n * unsigned values of at least, respectively, 32 and 64 bits. These\n * tests should select appropriate types for most platforms. The\n * macro \"SPH_64\" is defined if the 64-bit is supported.\n */\n\n#undef SPH_64\n#undef SPH_64_TRUE\n\n#if defined __STDC__ && __STDC_VERSION__ >= 199901L\n\n/*\n * On C99 implementations, we can use <stdint.h> to get an exact 64-bit\n * type, if any, or otherwise use a wider type (which must exist, for\n * C99 conformance).\n */\n\n#include <stdint.h>\n\n#ifdef UINT32_MAX\ntypedef uint32_t sph_u32;\ntypedef int32_t sph_s32;\n#else\ntypedef uint_fast32_t sph_u32;\ntypedef int_fast32_t sph_s32;\n#endif\n#if !SPH_NO_64\n#ifdef UINT64_MAX\ntypedef uint64_t sph_u64;\ntypedef int64_t sph_s64;\n#else\ntypedef uint_fast64_t sph_u64;\ntypedef int_fast64_t sph_s64;\n#endif\n#endif\n\n#define SPH_C32(x)    ((sph_u32)(x))\n#if !SPH_NO_64\n#define SPH_C64(x)    ((sph_u64)(x))\n#define SPH_64  1\n#endif\n\n#else\n\n/*\n * On non-C99 systems, we use \"unsigned int\" if it is wide enough,\n * \"unsigned long\" otherwise. This supports all \"reasonable\" architectures.\n * We have to be cautious: pre-C99 preprocessors handle constants\n * differently in '#if' expressions. Hence the shifts to test UINT_MAX.\n */\n\n#if ((UINT_MAX >> 11) >> 11) >= 0x3FF\n\ntypedef unsigned int sph_u32;\ntypedef int sph_s32;\n\n#define SPH_C32(x)    ((sph_u32)(x ## U))\n\n#else\n\ntypedef unsigned long sph_u32;\ntypedef long sph_s32;\n\n#define SPH_C32(x)    ((sph_u32)(x ## UL))\n\n#endif\n\n#if !SPH_NO_64\n\n/*\n * We want a 64-bit type. We use \"unsigned long\" if it is wide enough (as\n * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9),\n * \"unsigned long long\" otherwise, if available. We use ULLONG_MAX to\n * test whether \"unsigned long long\" is available; we also know that\n * gcc features this type, even if the libc header do not know it.\n */\n\n#if ((ULONG_MAX >> 31) >> 31) >= 3\n\ntypedef unsigned long sph_u64;\ntypedef long sph_s64;\n\n#define SPH_C64(x)    ((sph_u64)(x ## UL))\n\n#define SPH_64  1\n\n#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__\n\ntypedef unsigned long long sph_u64;\ntypedef long long sph_s64;\n\n#define SPH_C64(x)    ((sph_u64)(x ## ULL))\n\n#define SPH_64  1\n\n#else\n\n/*\n * No 64-bit type...\n */\n\n#endif\n\n#endif\n\n#endif\n\n/*\n * If the \"unsigned long\" type has length 64 bits or more, then this is\n * a \"true\" 64-bit architectures. This is also true with Visual C on\n * amd64, even though the \"long\" type is limited to 32 bits.\n */\n#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64)\n#define SPH_64_TRUE   1\n#endif\n\n/*\n * Implementation note: some processors have specific opcodes to perform\n * a rotation. Recent versions of gcc recognize the expression above and\n * use the relevant opcodes, when appropriate.\n */\n\n#define SPH_T32(x)    ((x) & SPH_C32(0xFFFFFFFF))\n#define SPH_ROTL32(x, n)   SPH_T32(((x) << (n)) | ((x) >> (32 - (n))))\n#define SPH_ROTR32(x, n)   SPH_ROTL32(x, (32 - (n)))\n\n#if SPH_64\n\n#define SPH_T64(x)    ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF))\n#define SPH_ROTL64(x, n)   SPH_T64(((x) << (n)) | ((x) >> (64 - (n))))\n#define SPH_ROTR64(x, n)   SPH_ROTL64(x, (64 - (n)))\n\n#endif\n\n#ifndef DOXYGEN_IGNORE\n/*\n * Define SPH_INLINE to be an \"inline\" qualifier, if available. We define\n * some small macro-like functions which benefit greatly from being inlined.\n */\n#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__\n#define SPH_INLINE inline\n#elif defined _MSC_VER\n#define SPH_INLINE __inline\n#else\n#define SPH_INLINE\n#endif\n#endif\n\n/*\n * We define some macros which qualify the architecture. These macros\n * may be explicit set externally (e.g. as compiler parameters). The\n * code below sets those macros if they are not already defined.\n *\n * Most macros are boolean, thus evaluate to either zero or non-zero.\n * The SPH_UPTR macro is special, in that it evaluates to a C type,\n * or is not defined.\n *\n * SPH_UPTR             if defined: unsigned type to cast pointers into\n *\n * SPH_UNALIGNED        non-zero if unaligned accesses are efficient\n * SPH_LITTLE_ENDIAN    non-zero if architecture is known to be little-endian\n * SPH_BIG_ENDIAN       non-zero if architecture is known to be big-endian\n * SPH_LITTLE_FAST      non-zero if little-endian decoding is fast\n * SPH_BIG_FAST         non-zero if big-endian decoding is fast\n *\n * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit\n * values will try to be \"smart\". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN\n * _must_ be non-zero in those situations. The 32-bit and 64-bit types\n * _must_ also have an exact width.\n *\n * SPH_SPARCV9_GCC_32   UltraSPARC-compatible with gcc, 32-bit mode\n * SPH_SPARCV9_GCC_64   UltraSPARC-compatible with gcc, 64-bit mode\n * SPH_SPARCV9_GCC      UltraSPARC-compatible with gcc\n * SPH_I386_GCC         x86-compatible (32-bit) with gcc\n * SPH_I386_MSVC        x86-compatible (32-bit) with Microsoft Visual C\n * SPH_AMD64_GCC        x86-compatible (64-bit) with gcc\n * SPH_AMD64_MSVC       x86-compatible (64-bit) with Microsoft Visual C\n * SPH_PPC32_GCC        PowerPC, 32-bit, with gcc\n * SPH_PPC64_GCC        PowerPC, 64-bit, with gcc\n *\n * TODO: enhance automatic detection, for more architectures and compilers.\n * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with\n * some very fast functions (e.g. MD4) when using unaligned input data.\n * The CPU-specific-with-GCC macros are useful only for inline assembly,\n * normally restrained to this header file.\n */\n\n/*\n * 32-bit x86, aka \"i386 compatible\".\n */\n#if defined __i386__ || defined _M_IX86\n\n#define SPH_DETECT_UNALIGNED         1\n#define SPH_DETECT_LITTLE_ENDIAN     1\n#define SPH_DETECT_UPTR              sph_u32\n#ifdef __GNUC__\n#define SPH_DETECT_I386_GCC          1\n#endif\n#ifdef _MSC_VER\n#define SPH_DETECT_I386_MSVC         1\n#endif\n\n/*\n * 64-bit x86, hereafter known as \"amd64\".\n */\n#elif defined __x86_64 || defined _M_X64\n\n#define SPH_DETECT_UNALIGNED         1\n#define SPH_DETECT_LITTLE_ENDIAN     1\n#define SPH_DETECT_UPTR              sph_u64\n#ifdef __GNUC__\n#define SPH_DETECT_AMD64_GCC         1\n#endif\n#ifdef _MSC_VER\n#define SPH_DETECT_AMD64_MSVC        1\n#endif\n\n/*\n * 64-bit Sparc architecture (implies v9).\n */\n#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \\\n    || defined __sparcv9\n\n#define SPH_DETECT_BIG_ENDIAN        1\n#define SPH_DETECT_UPTR              sph_u64\n#ifdef __GNUC__\n#define SPH_DETECT_SPARCV9_GCC_64    1\n#define SPH_DETECT_LITTLE_FAST       1\n#endif\n\n/*\n * 32-bit Sparc.\n */\n#elif (defined __sparc__ || defined __sparc) \\\n    && !(defined __sparcv9 || defined __arch64__)\n\n#define SPH_DETECT_BIG_ENDIAN        1\n#define SPH_DETECT_UPTR              sph_u32\n#if defined __GNUC__ && defined __sparc_v9__\n#define SPH_DETECT_SPARCV9_GCC_32    1\n#define SPH_DETECT_LITTLE_FAST       1\n#endif\n\n/*\n * ARM, little-endian.\n */\n#elif defined __arm__ && __ARMEL__\n\n#define SPH_DETECT_LITTLE_ENDIAN     1\n\n/*\n * MIPS, little-endian.\n */\n#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__\n\n#define SPH_DETECT_LITTLE_ENDIAN     1\n\n/*\n * MIPS, big-endian.\n */\n#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__\n\n#define SPH_DETECT_BIG_ENDIAN        1\n\n/*\n * PowerPC.\n */\n#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \\\n    || defined _ARCH_PPC\n\n/*\n * Note: we do not declare cross-endian access to be \"fast\": even if\n * using inline assembly, implementation should still assume that\n * keeping the decoded word in a temporary is faster than decoding\n * it again.\n */\n#if defined __GNUC__\n#if SPH_64_TRUE\n#define SPH_DETECT_PPC64_GCC         1\n#else\n#define SPH_DETECT_PPC32_GCC         1\n#endif\n#endif\n\n#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN\n#define SPH_DETECT_BIG_ENDIAN        1\n#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN\n#define SPH_DETECT_LITTLE_ENDIAN     1\n#endif\n\n/*\n * Itanium, 64-bit.\n */\n#elif defined __ia64 || defined __ia64__ \\\n    || defined __itanium__ || defined _M_IA64\n\n#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN\n#define SPH_DETECT_BIG_ENDIAN        1\n#else\n#define SPH_DETECT_LITTLE_ENDIAN     1\n#endif\n#if defined __LP64__ || defined _LP64\n#define SPH_DETECT_UPTR              sph_u64\n#else\n#define SPH_DETECT_UPTR              sph_u32\n#endif\n\n#endif\n\n#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64\n#define SPH_DETECT_SPARCV9_GCC       1\n#endif\n\n#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED\n#define SPH_UNALIGNED         SPH_DETECT_UNALIGNED\n#endif\n#if defined SPH_DETECT_UPTR && !defined SPH_UPTR\n#define SPH_UPTR              SPH_DETECT_UPTR\n#endif\n#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN\n#define SPH_LITTLE_ENDIAN     SPH_DETECT_LITTLE_ENDIAN\n#endif\n#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN\n#define SPH_BIG_ENDIAN        SPH_DETECT_BIG_ENDIAN\n#endif\n#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST\n#define SPH_LITTLE_FAST       SPH_DETECT_LITTLE_FAST\n#endif\n#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST\n#define SPH_BIG_FAST    SPH_DETECT_BIG_FAST\n#endif\n#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32\n#define SPH_SPARCV9_GCC_32    SPH_DETECT_SPARCV9_GCC_32\n#endif\n#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64\n#define SPH_SPARCV9_GCC_64    SPH_DETECT_SPARCV9_GCC_64\n#endif\n#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC\n#define SPH_SPARCV9_GCC       SPH_DETECT_SPARCV9_GCC\n#endif\n#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC\n#define SPH_I386_GCC          SPH_DETECT_I386_GCC\n#endif\n#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC\n#define SPH_I386_MSVC         SPH_DETECT_I386_MSVC\n#endif\n#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC\n#define SPH_AMD64_GCC         SPH_DETECT_AMD64_GCC\n#endif\n#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC\n#define SPH_AMD64_MSVC        SPH_DETECT_AMD64_MSVC\n#endif\n#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC\n#define SPH_PPC32_GCC         SPH_DETECT_PPC32_GCC\n#endif\n#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC\n#define SPH_PPC64_GCC         SPH_DETECT_PPC64_GCC\n#endif\n\n#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST\n#define SPH_LITTLE_FAST              1\n#endif\n#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST\n#define SPH_BIG_FAST                 1\n#endif\n\n#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN)\n#error SPH_UPTR defined, but endianness is not known.\n#endif\n\n#if SPH_I386_GCC && !SPH_NO_ASM\n\n/*\n * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit\n * values.\n */\n\nstatic SPH_INLINE sph_u32\nsph_bswap32(sph_u32 x)\n{\n    __asm__ __volatile__ (\"bswapl %0\" : \"=r\" (x) : \"0\" (x));\n    return x;\n}\n\n#if SPH_64\n\nstatic SPH_INLINE sph_u64\nsph_bswap64(sph_u64 x)\n{\n    return ((sph_u64)sph_bswap32((sph_u32)x) << 32)\n        | (sph_u64)sph_bswap32((sph_u32)(x >> 32));\n}\n\n#endif\n\n#elif SPH_AMD64_GCC && !SPH_NO_ASM\n\n/*\n * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit\n * and 64-bit values.\n */\n\nstatic SPH_INLINE sph_u32\nsph_bswap32(sph_u32 x)\n{\n    __asm__ __volatile__ (\"bswapl %0\" : \"=r\" (x) : \"0\" (x));\n    return x;\n}\n\n#if SPH_64\n\nstatic SPH_INLINE sph_u64\nsph_bswap64(sph_u64 x)\n{\n    __asm__ __volatile__ (\"bswapq %0\" : \"=r\" (x) : \"0\" (x));\n    return x;\n}\n\n#endif\n\n/*\n * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough\n * to generate proper opcodes for endianness swapping with the pure C\n * implementation below.\n *\n\n#elif SPH_I386_MSVC && !SPH_NO_ASM\n\nstatic __inline sph_u32 __declspec(naked) __fastcall\nsph_bswap32(sph_u32 x)\n{\n    __asm {\n        bswap  ecx\n        mov    eax,ecx\n        ret\n    }\n}\n\n#if SPH_64\n\nstatic SPH_INLINE sph_u64\nsph_bswap64(sph_u64 x)\n{\n    return ((sph_u64)sph_bswap32((sph_u32)x) << 32)\n        | (sph_u64)sph_bswap32((sph_u32)(x >> 32));\n}\n\n#endif\n\n *\n * [end of disabled code]\n */\n\n#else\n\nstatic SPH_INLINE sph_u32\nsph_bswap32(sph_u32 x)\n{\n    x = SPH_T32((x << 16) | (x >> 16));\n    x = ((x & SPH_C32(0xFF00FF00)) >> 8)\n        | ((x & SPH_C32(0x00FF00FF)) << 8);\n    return x;\n}\n\n#if SPH_64\n\n/**\n * Byte-swap a 64-bit value.\n *\n * @param x   the input value\n * @return  the byte-swapped value\n */\nstatic SPH_INLINE sph_u64\nsph_bswap64(sph_u64 x)\n{\n    x = SPH_T64((x << 32) | (x >> 32));\n    x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16)\n        | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16);\n    x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8)\n        | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8);\n    return x;\n}\n\n#endif\n\n#endif\n\n#if SPH_SPARCV9_GCC && !SPH_NO_ASM\n\n/*\n * On UltraSPARC systems, native ordering is big-endian, but it is\n * possible to perform little-endian read accesses by specifying the\n * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use\n * the opcode \"lda [%reg]0x88,%dst\", where %reg is the register which\n * contains the source address and %dst is the destination register,\n * or we use \"lda [%reg+imm]%asi,%dst\", which uses the %asi register\n * to get the address space name. The latter format is better since it\n * combines an addition and the actual access in a single opcode; but\n * it requires the setting (and subsequent resetting) of %asi, which is\n * slow. Some operations (i.e. MD5 compression function) combine many\n * successive little-endian read accesses, which may share the same\n * %asi setting. The macros below contain the appropriate inline\n * assembly.\n */\n\n#define SPH_SPARCV9_SET_ASI   \\\n    sph_u32 sph_sparcv9_asi; \\\n    __asm__ __volatile__ ( \\\n        \"rd %%asi,%0\\n\\twr %%g0,0x88,%%asi\" : \"=r\" (sph_sparcv9_asi));\n\n#define SPH_SPARCV9_RESET_ASI  \\\n    __asm__ __volatile__ (\"wr %%g0,%0,%%asi\" : : \"r\" (sph_sparcv9_asi));\n\n#define SPH_SPARCV9_DEC32LE(base, idx)   ({ \\\n        sph_u32 sph_sparcv9_tmp; \\\n        __asm__ __volatile__ (\"lda [%1+\" #idx \"*4]%%asi,%0\" \\\n            : \"=r\" (sph_sparcv9_tmp) : \"r\" (base)); \\\n        sph_sparcv9_tmp; \\\n    })\n\n#endif\n\nstatic SPH_INLINE void\nsph_enc16be(void *dst, unsigned val)\n{\n    ((unsigned char *)dst)[0] = (val >> 8);\n    ((unsigned char *)dst)[1] = val;\n}\n\nstatic SPH_INLINE unsigned\nsph_dec16be(const void *src)\n{\n    return ((unsigned)(((const unsigned char *)src)[0]) << 8)\n        | (unsigned)(((const unsigned char *)src)[1]);\n}\n\nstatic SPH_INLINE void\nsph_enc16le(void *dst, unsigned val)\n{\n    ((unsigned char *)dst)[0] = val;\n    ((unsigned char *)dst)[1] = val >> 8;\n}\n\nstatic SPH_INLINE unsigned\nsph_dec16le(const void *src)\n{\n    return (unsigned)(((const unsigned char *)src)[0])\n        | ((unsigned)(((const unsigned char *)src)[1]) << 8);\n}\n\n/**\n * Encode a 32-bit value into the provided buffer (big endian convention).\n *\n * @param dst   the destination buffer\n * @param val   the 32-bit value to encode\n */\nstatic SPH_INLINE void\nsph_enc32be(void *dst, sph_u32 val)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_LITTLE_ENDIAN\n    val = sph_bswap32(val);\n#endif\n    *(sph_u32 *)dst = val;\n#else\n    if (((SPH_UPTR)dst & 3) == 0) {\n#if SPH_LITTLE_ENDIAN\n        val = sph_bswap32(val);\n#endif\n        *(sph_u32 *)dst = val;\n    } else {\n        ((unsigned char *)dst)[0] = (val >> 24);\n        ((unsigned char *)dst)[1] = (val >> 16);\n        ((unsigned char *)dst)[2] = (val >> 8);\n        ((unsigned char *)dst)[3] = val;\n    }\n#endif\n#else\n    ((unsigned char *)dst)[0] = (val >> 24);\n    ((unsigned char *)dst)[1] = (val >> 16);\n    ((unsigned char *)dst)[2] = (val >> 8);\n    ((unsigned char *)dst)[3] = val;\n#endif\n}\n\n/**\n * Encode a 32-bit value into the provided buffer (big endian convention).\n * The destination buffer must be properly aligned.\n *\n * @param dst   the destination buffer (32-bit aligned)\n * @param val   the value to encode\n */\nstatic SPH_INLINE void\nsph_enc32be_aligned(void *dst, sph_u32 val)\n{\n#if SPH_LITTLE_ENDIAN\n    *(sph_u32 *)dst = sph_bswap32(val);\n#elif SPH_BIG_ENDIAN\n    *(sph_u32 *)dst = val;\n#else\n    ((unsigned char *)dst)[0] = (val >> 24);\n    ((unsigned char *)dst)[1] = (val >> 16);\n    ((unsigned char *)dst)[2] = (val >> 8);\n    ((unsigned char *)dst)[3] = val;\n#endif\n}\n\n/**\n * Decode a 32-bit value from the provided buffer (big endian convention).\n *\n * @param src   the source buffer\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u32\nsph_dec32be(const void *src)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_LITTLE_ENDIAN\n    return sph_bswap32(*(const sph_u32 *)src);\n#else\n    return *(const sph_u32 *)src;\n#endif\n#else\n    if (((SPH_UPTR)src & 3) == 0) {\n#if SPH_LITTLE_ENDIAN\n        return sph_bswap32(*(const sph_u32 *)src);\n#else\n        return *(const sph_u32 *)src;\n#endif\n    } else {\n        return ((sph_u32)(((const unsigned char *)src)[0]) << 24)\n            | ((sph_u32)(((const unsigned char *)src)[1]) << 16)\n            | ((sph_u32)(((const unsigned char *)src)[2]) << 8)\n            | (sph_u32)(((const unsigned char *)src)[3]);\n    }\n#endif\n#else\n    return ((sph_u32)(((const unsigned char *)src)[0]) << 24)\n        | ((sph_u32)(((const unsigned char *)src)[1]) << 16)\n        | ((sph_u32)(((const unsigned char *)src)[2]) << 8)\n        | (sph_u32)(((const unsigned char *)src)[3]);\n#endif\n}\n\n/**\n * Decode a 32-bit value from the provided buffer (big endian convention).\n * The source buffer must be properly aligned.\n *\n * @param src   the source buffer (32-bit aligned)\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u32\nsph_dec32be_aligned(const void *src)\n{\n#if SPH_LITTLE_ENDIAN\n    return sph_bswap32(*(const sph_u32 *)src);\n#elif SPH_BIG_ENDIAN\n    return *(const sph_u32 *)src;\n#else\n    return ((sph_u32)(((const unsigned char *)src)[0]) << 24)\n        | ((sph_u32)(((const unsigned char *)src)[1]) << 16)\n        | ((sph_u32)(((const unsigned char *)src)[2]) << 8)\n        | (sph_u32)(((const unsigned char *)src)[3]);\n#endif\n}\n\n/**\n * Encode a 32-bit value into the provided buffer (little endian convention).\n *\n * @param dst   the destination buffer\n * @param val   the 32-bit value to encode\n */\nstatic SPH_INLINE void\nsph_enc32le(void *dst, sph_u32 val)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_BIG_ENDIAN\n    val = sph_bswap32(val);\n#endif\n    *(sph_u32 *)dst = val;\n#else\n    if (((SPH_UPTR)dst & 3) == 0) {\n#if SPH_BIG_ENDIAN\n        val = sph_bswap32(val);\n#endif\n        *(sph_u32 *)dst = val;\n    } else {\n        ((unsigned char *)dst)[0] = val;\n        ((unsigned char *)dst)[1] = (val >> 8);\n        ((unsigned char *)dst)[2] = (val >> 16);\n        ((unsigned char *)dst)[3] = (val >> 24);\n    }\n#endif\n#else\n    ((unsigned char *)dst)[0] = val;\n    ((unsigned char *)dst)[1] = (val >> 8);\n    ((unsigned char *)dst)[2] = (val >> 16);\n    ((unsigned char *)dst)[3] = (val >> 24);\n#endif\n}\n\n/**\n * Encode a 32-bit value into the provided buffer (little endian convention).\n * The destination buffer must be properly aligned.\n *\n * @param dst   the destination buffer (32-bit aligned)\n * @param val   the value to encode\n */\nstatic SPH_INLINE void\nsph_enc32le_aligned(void *dst, sph_u32 val)\n{\n#if SPH_LITTLE_ENDIAN\n    *(sph_u32 *)dst = val;\n#elif SPH_BIG_ENDIAN\n    *(sph_u32 *)dst = sph_bswap32(val);\n#else\n    ((unsigned char *)dst)[0] = val;\n    ((unsigned char *)dst)[1] = (val >> 8);\n    ((unsigned char *)dst)[2] = (val >> 16);\n    ((unsigned char *)dst)[3] = (val >> 24);\n#endif\n}\n\n/**\n * Decode a 32-bit value from the provided buffer (little endian convention).\n *\n * @param src   the source buffer\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u32\nsph_dec32le(const void *src)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_BIG_ENDIAN\n    return sph_bswap32(*(const sph_u32 *)src);\n#else\n    return *(const sph_u32 *)src;\n#endif\n#else\n    if (((SPH_UPTR)src & 3) == 0) {\n#if SPH_BIG_ENDIAN\n#if SPH_SPARCV9_GCC && !SPH_NO_ASM\n        sph_u32 tmp;\n\n        /*\n         * \"__volatile__\" is needed here because without it,\n         * gcc-3.4.3 miscompiles the code and performs the\n         * access before the test on the address, thus triggering\n         * a bus error...\n         */\n        __asm__ __volatile__ (\n            \"lda [%1]0x88,%0\" : \"=r\" (tmp) : \"r\" (src));\n        return tmp;\n/*\n * On PowerPC, this turns out not to be worth the effort: the inline\n * assembly makes GCC optimizer uncomfortable, which tends to nullify\n * the decoding gains.\n *\n * For most hash functions, using this inline assembly trick changes\n * hashing speed by less than 5% and often _reduces_ it. The biggest\n * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is\n * less then 10%. The speed gain on CubeHash is probably due to the\n * chronic shortage of registers that CubeHash endures; for the other\n * functions, the generic code appears to be efficient enough already.\n *\n#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM\n        sph_u32 tmp;\n\n        __asm__ __volatile__ (\n            \"lwbrx %0,0,%1\" : \"=r\" (tmp) : \"r\" (src));\n        return tmp;\n */\n#else\n        return sph_bswap32(*(const sph_u32 *)src);\n#endif\n#else\n        return *(const sph_u32 *)src;\n#endif\n    } else {\n        return (sph_u32)(((const unsigned char *)src)[0])\n            | ((sph_u32)(((const unsigned char *)src)[1]) << 8)\n            | ((sph_u32)(((const unsigned char *)src)[2]) << 16)\n            | ((sph_u32)(((const unsigned char *)src)[3]) << 24);\n    }\n#endif\n#else\n    return (sph_u32)(((const unsigned char *)src)[0])\n        | ((sph_u32)(((const unsigned char *)src)[1]) << 8)\n        | ((sph_u32)(((const unsigned char *)src)[2]) << 16)\n        | ((sph_u32)(((const unsigned char *)src)[3]) << 24);\n#endif\n}\n\n/**\n * Decode a 32-bit value from the provided buffer (little endian convention).\n * The source buffer must be properly aligned.\n *\n * @param src   the source buffer (32-bit aligned)\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u32\nsph_dec32le_aligned(const void *src)\n{\n#if SPH_LITTLE_ENDIAN\n    return *(const sph_u32 *)src;\n#elif SPH_BIG_ENDIAN\n#if SPH_SPARCV9_GCC && !SPH_NO_ASM\n    sph_u32 tmp;\n\n    __asm__ __volatile__ (\"lda [%1]0x88,%0\" : \"=r\" (tmp) : \"r\" (src));\n    return tmp;\n/*\n * Not worth it generally.\n *\n#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM\n    sph_u32 tmp;\n\n    __asm__ __volatile__ (\"lwbrx %0,0,%1\" : \"=r\" (tmp) : \"r\" (src));\n    return tmp;\n */\n#else\n    return sph_bswap32(*(const sph_u32 *)src);\n#endif\n#else\n    return (sph_u32)(((const unsigned char *)src)[0])\n        | ((sph_u32)(((const unsigned char *)src)[1]) << 8)\n        | ((sph_u32)(((const unsigned char *)src)[2]) << 16)\n        | ((sph_u32)(((const unsigned char *)src)[3]) << 24);\n#endif\n}\n\n#if SPH_64\n\n/**\n * Encode a 64-bit value into the provided buffer (big endian convention).\n *\n * @param dst   the destination buffer\n * @param val   the 64-bit value to encode\n */\nstatic SPH_INLINE void\nsph_enc64be(void *dst, sph_u64 val)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_LITTLE_ENDIAN\n    val = sph_bswap64(val);\n#endif\n    *(sph_u64 *)dst = val;\n#else\n    if (((SPH_UPTR)dst & 7) == 0) {\n#if SPH_LITTLE_ENDIAN\n        val = sph_bswap64(val);\n#endif\n        *(sph_u64 *)dst = val;\n    } else {\n        ((unsigned char *)dst)[0] = (val >> 56);\n        ((unsigned char *)dst)[1] = (val >> 48);\n        ((unsigned char *)dst)[2] = (val >> 40);\n        ((unsigned char *)dst)[3] = (val >> 32);\n        ((unsigned char *)dst)[4] = (val >> 24);\n        ((unsigned char *)dst)[5] = (val >> 16);\n        ((unsigned char *)dst)[6] = (val >> 8);\n        ((unsigned char *)dst)[7] = val;\n    }\n#endif\n#else\n    ((unsigned char *)dst)[0] = (val >> 56);\n    ((unsigned char *)dst)[1] = (val >> 48);\n    ((unsigned char *)dst)[2] = (val >> 40);\n    ((unsigned char *)dst)[3] = (val >> 32);\n    ((unsigned char *)dst)[4] = (val >> 24);\n    ((unsigned char *)dst)[5] = (val >> 16);\n    ((unsigned char *)dst)[6] = (val >> 8);\n    ((unsigned char *)dst)[7] = val;\n#endif\n}\n\n/**\n * Encode a 64-bit value into the provided buffer (big endian convention).\n * The destination buffer must be properly aligned.\n *\n * @param dst   the destination buffer (64-bit aligned)\n * @param val   the value to encode\n */\nstatic SPH_INLINE void\nsph_enc64be_aligned(void *dst, sph_u64 val)\n{\n#if SPH_LITTLE_ENDIAN\n    *(sph_u64 *)dst = sph_bswap64(val);\n#elif SPH_BIG_ENDIAN\n    *(sph_u64 *)dst = val;\n#else\n    ((unsigned char *)dst)[0] = (val >> 56);\n    ((unsigned char *)dst)[1] = (val >> 48);\n    ((unsigned char *)dst)[2] = (val >> 40);\n    ((unsigned char *)dst)[3] = (val >> 32);\n    ((unsigned char *)dst)[4] = (val >> 24);\n    ((unsigned char *)dst)[5] = (val >> 16);\n    ((unsigned char *)dst)[6] = (val >> 8);\n    ((unsigned char *)dst)[7] = val;\n#endif\n}\n\n/**\n * Decode a 64-bit value from the provided buffer (big endian convention).\n *\n * @param src   the source buffer\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u64\nsph_dec64be(const void *src)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_LITTLE_ENDIAN\n    return sph_bswap64(*(const sph_u64 *)src);\n#else\n    return *(const sph_u64 *)src;\n#endif\n#else\n    if (((SPH_UPTR)src & 7) == 0) {\n#if SPH_LITTLE_ENDIAN\n        return sph_bswap64(*(const sph_u64 *)src);\n#else\n        return *(const sph_u64 *)src;\n#endif\n    } else {\n        return ((sph_u64)(((const unsigned char *)src)[0]) << 56)\n            | ((sph_u64)(((const unsigned char *)src)[1]) << 48)\n            | ((sph_u64)(((const unsigned char *)src)[2]) << 40)\n            | ((sph_u64)(((const unsigned char *)src)[3]) << 32)\n            | ((sph_u64)(((const unsigned char *)src)[4]) << 24)\n            | ((sph_u64)(((const unsigned char *)src)[5]) << 16)\n            | ((sph_u64)(((const unsigned char *)src)[6]) << 8)\n            | (sph_u64)(((const unsigned char *)src)[7]);\n    }\n#endif\n#else\n    return ((sph_u64)(((const unsigned char *)src)[0]) << 56)\n        | ((sph_u64)(((const unsigned char *)src)[1]) << 48)\n        | ((sph_u64)(((const unsigned char *)src)[2]) << 40)\n        | ((sph_u64)(((const unsigned char *)src)[3]) << 32)\n        | ((sph_u64)(((const unsigned char *)src)[4]) << 24)\n        | ((sph_u64)(((const unsigned char *)src)[5]) << 16)\n        | ((sph_u64)(((const unsigned char *)src)[6]) << 8)\n        | (sph_u64)(((const unsigned char *)src)[7]);\n#endif\n}\n\n/**\n * Decode a 64-bit value from the provided buffer (big endian convention).\n * The source buffer must be properly aligned.\n *\n * @param src   the source buffer (64-bit aligned)\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u64\nsph_dec64be_aligned(const void *src)\n{\n#if SPH_LITTLE_ENDIAN\n    return sph_bswap64(*(const sph_u64 *)src);\n#elif SPH_BIG_ENDIAN\n    return *(const sph_u64 *)src;\n#else\n    return ((sph_u64)(((const unsigned char *)src)[0]) << 56)\n        | ((sph_u64)(((const unsigned char *)src)[1]) << 48)\n        | ((sph_u64)(((const unsigned char *)src)[2]) << 40)\n        | ((sph_u64)(((const unsigned char *)src)[3]) << 32)\n        | ((sph_u64)(((const unsigned char *)src)[4]) << 24)\n        | ((sph_u64)(((const unsigned char *)src)[5]) << 16)\n        | ((sph_u64)(((const unsigned char *)src)[6]) << 8)\n        | (sph_u64)(((const unsigned char *)src)[7]);\n#endif\n}\n\n/**\n * Encode a 64-bit value into the provided buffer (little endian convention).\n *\n * @param dst   the destination buffer\n * @param val   the 64-bit value to encode\n */\nstatic SPH_INLINE void\nsph_enc64le(void *dst, sph_u64 val)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_BIG_ENDIAN\n    val = sph_bswap64(val);\n#endif\n    *(sph_u64 *)dst = val;\n#else\n    if (((SPH_UPTR)dst & 7) == 0) {\n#if SPH_BIG_ENDIAN\n        val = sph_bswap64(val);\n#endif\n        *(sph_u64 *)dst = val;\n    } else {\n        ((unsigned char *)dst)[0] = val;\n        ((unsigned char *)dst)[1] = (val >> 8);\n        ((unsigned char *)dst)[2] = (val >> 16);\n        ((unsigned char *)dst)[3] = (val >> 24);\n        ((unsigned char *)dst)[4] = (val >> 32);\n        ((unsigned char *)dst)[5] = (val >> 40);\n        ((unsigned char *)dst)[6] = (val >> 48);\n        ((unsigned char *)dst)[7] = (val >> 56);\n    }\n#endif\n#else\n    ((unsigned char *)dst)[0] = val;\n    ((unsigned char *)dst)[1] = (val >> 8);\n    ((unsigned char *)dst)[2] = (val >> 16);\n    ((unsigned char *)dst)[3] = (val >> 24);\n    ((unsigned char *)dst)[4] = (val >> 32);\n    ((unsigned char *)dst)[5] = (val >> 40);\n    ((unsigned char *)dst)[6] = (val >> 48);\n    ((unsigned char *)dst)[7] = (val >> 56);\n#endif\n}\n\n/**\n * Encode a 64-bit value into the provided buffer (little endian convention).\n * The destination buffer must be properly aligned.\n *\n * @param dst   the destination buffer (64-bit aligned)\n * @param val   the value to encode\n */\nstatic SPH_INLINE void\nsph_enc64le_aligned(void *dst, sph_u64 val)\n{\n#if SPH_LITTLE_ENDIAN\n    *(sph_u64 *)dst = val;\n#elif SPH_BIG_ENDIAN\n    *(sph_u64 *)dst = sph_bswap64(val);\n#else\n    ((unsigned char *)dst)[0] = val;\n    ((unsigned char *)dst)[1] = (val >> 8);\n    ((unsigned char *)dst)[2] = (val >> 16);\n    ((unsigned char *)dst)[3] = (val >> 24);\n    ((unsigned char *)dst)[4] = (val >> 32);\n    ((unsigned char *)dst)[5] = (val >> 40);\n    ((unsigned char *)dst)[6] = (val >> 48);\n    ((unsigned char *)dst)[7] = (val >> 56);\n#endif\n}\n\n/**\n * Decode a 64-bit value from the provided buffer (little endian convention).\n *\n * @param src   the source buffer\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u64\nsph_dec64le(const void *src)\n{\n#if defined SPH_UPTR\n#if SPH_UNALIGNED\n#if SPH_BIG_ENDIAN\n    return sph_bswap64(*(const sph_u64 *)src);\n#else\n    return *(const sph_u64 *)src;\n#endif\n#else\n    if (((SPH_UPTR)src & 7) == 0) {\n#if SPH_BIG_ENDIAN\n#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM\n        sph_u64 tmp;\n\n        __asm__ __volatile__ (\n            \"ldxa [%1]0x88,%0\" : \"=r\" (tmp) : \"r\" (src));\n        return tmp;\n/*\n * Not worth it generally.\n *\n#elif SPH_PPC32_GCC && !SPH_NO_ASM\n        return (sph_u64)sph_dec32le_aligned(src)\n            | ((sph_u64)sph_dec32le_aligned(\n                (const char *)src + 4) << 32);\n#elif SPH_PPC64_GCC && !SPH_NO_ASM\n        sph_u64 tmp;\n\n        __asm__ __volatile__ (\n            \"ldbrx %0,0,%1\" : \"=r\" (tmp) : \"r\" (src));\n        return tmp;\n */\n#else\n        return sph_bswap64(*(const sph_u64 *)src);\n#endif\n#else\n        return *(const sph_u64 *)src;\n#endif\n    } else {\n        return (sph_u64)(((const unsigned char *)src)[0])\n            | ((sph_u64)(((const unsigned char *)src)[1]) << 8)\n            | ((sph_u64)(((const unsigned char *)src)[2]) << 16)\n            | ((sph_u64)(((const unsigned char *)src)[3]) << 24)\n            | ((sph_u64)(((const unsigned char *)src)[4]) << 32)\n            | ((sph_u64)(((const unsigned char *)src)[5]) << 40)\n            | ((sph_u64)(((const unsigned char *)src)[6]) << 48)\n            | ((sph_u64)(((const unsigned char *)src)[7]) << 56);\n    }\n#endif\n#else\n    return (sph_u64)(((const unsigned char *)src)[0])\n        | ((sph_u64)(((const unsigned char *)src)[1]) << 8)\n        | ((sph_u64)(((const unsigned char *)src)[2]) << 16)\n        | ((sph_u64)(((const unsigned char *)src)[3]) << 24)\n        | ((sph_u64)(((const unsigned char *)src)[4]) << 32)\n        | ((sph_u64)(((const unsigned char *)src)[5]) << 40)\n        | ((sph_u64)(((const unsigned char *)src)[6]) << 48)\n        | ((sph_u64)(((const unsigned char *)src)[7]) << 56);\n#endif\n}\n\n/**\n * Decode a 64-bit value from the provided buffer (little endian convention).\n * The source buffer must be properly aligned.\n *\n * @param src   the source buffer (64-bit aligned)\n * @return  the decoded value\n */\nstatic SPH_INLINE sph_u64\nsph_dec64le_aligned(const void *src)\n{\n#if SPH_LITTLE_ENDIAN\n    return *(const sph_u64 *)src;\n#elif SPH_BIG_ENDIAN\n#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM\n    sph_u64 tmp;\n\n    __asm__ __volatile__ (\"ldxa [%1]0x88,%0\" : \"=r\" (tmp) : \"r\" (src));\n    return tmp;\n/*\n * Not worth it generally.\n *\n#elif SPH_PPC32_GCC && !SPH_NO_ASM\n    return (sph_u64)sph_dec32le_aligned(src)\n        | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32);\n#elif SPH_PPC64_GCC && !SPH_NO_ASM\n    sph_u64 tmp;\n\n    __asm__ __volatile__ (\"ldbrx %0,0,%1\" : \"=r\" (tmp) : \"r\" (src));\n    return tmp;\n */\n#else\n    return sph_bswap64(*(const sph_u64 *)src);\n#endif\n#else\n    return (sph_u64)(((const unsigned char *)src)[0])\n        | ((sph_u64)(((const unsigned char *)src)[1]) << 8)\n        | ((sph_u64)(((const unsigned char *)src)[2]) << 16)\n        | ((sph_u64)(((const unsigned char *)src)[3]) << 24)\n        | ((sph_u64)(((const unsigned char *)src)[4]) << 32)\n        | ((sph_u64)(((const unsigned char *)src)[5]) << 40)\n        | ((sph_u64)(((const unsigned char *)src)[6]) << 48)\n        | ((sph_u64)(((const unsigned char *)src)[7]) << 56);\n#endif\n}\n\n#endif\n\n#endif /* Doxygen excluded block */\n\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/COPYING",
    "content": "The files in this folder are derived from the supercop library in some cases with major modifications.\nPlease consult the comments in each individual file for author attribution and copyright/licensing specifics.\n\nUnless specified otherwise inside the file or if not explicitely specified the licensing of the Supercop project applies. \n\nSupercop licensing:\nThis Work was prepared by a United States Government employee and, therefore, is excluded from copyright by Section 105 of the Copyright Act of 1976.\nCopyright and Related Rights in the Work worldwide are waived through the CC0 1.0 Universal license.\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a53_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a53_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a53_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a53_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a53_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A53_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A53_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a53_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a53_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a53_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a53_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX53_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a53_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a53_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a53_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a53_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a53_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a53_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A53_AES_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A53_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a53_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a53_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a53_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a53_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a57_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a57_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a57_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a57_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a57_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A57_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A57_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a57_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a57_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a57_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a57_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX57_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a57_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a57_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a57_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a57_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a57_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a57_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A57_AES_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A57_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a57_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a57_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a57_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a57_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a72_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a72_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a72_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a72_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a72_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A72_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A72_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a72_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a72_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a72_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a72_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_CORTEX72_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a72_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a72_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a72_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a72_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_cortex_a72_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_cortex_a72_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_CORTEX_A72_AES_H\n#define HASH_SHAVITE3_256_ARM_CORTEX_A72_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_cortex_a72_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_cortex_a72_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_cortex_a72_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_cortex_a72_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_thunderx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_THUNDERX_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_thunderx_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_thunderx_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_thunderx_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_thunderx_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_arm_thunderx_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_arm_thunderx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_ARM_THUNDERX_AES_H\n#define HASH_SHAVITE3_256_ARM_THUNDERX_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_arm_thunderx_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_arm_thunderx_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_arm_thunderx_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_arm_thunderx_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX_H\n#define HASH_SHAVITE3_256_AVX_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx2_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx2_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx2_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx2_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx2_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX2_H\n#define HASH_SHAVITE3_256_AVX2_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx2_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx2_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx2_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx2_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX2) && defined(COMPILER_HAS_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx2_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx2_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx2_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx2_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx2_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx2_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX2_AES_H\n#define HASH_SHAVITE3_256_AVX2_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx2_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx2_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx2_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx2_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHABITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx512f_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx512f_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx512f_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx512f_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx512f_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX512F_H\n#define HASH_SHAVITE3_256_AVX512F_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx512f_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx512f_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx512f_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx512f_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX512F) && defined(COMPILER_HAS_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx512f_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx512f_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx512f_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx512f_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx512f_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx512f_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX512F_AES_H\n#define HASH_SHAVITE3_256_AVX512F_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx512f_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx512f_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx512f_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx512f_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_AVX) && defined(COMPILER_HAS_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_avx_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_avx_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_AVX_AES_H\n#define HASH_SHAVITE3_256_AVX_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_avx_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_avx_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_avx_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_avx_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3)\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse3_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse3_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse3_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse3_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_sse3_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_SSE3_H\n#define HASH_SHAVITE3_256_SSE3_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse3_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse3_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse3_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse3_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE3) && defined(COMPILER_HAS_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse3_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse3_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse3_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse3_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_sse3_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse3_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_SSE3_AES_H\n#define HASH_SHAVITE3_256_SSE3_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse3_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse3_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse3_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse3_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4)\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse4_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse4_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse4_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse4_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_sse4_Compress256\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_SSE4_H\n#define HASH_SHAVITE3_256_SSE4_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse4_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse4_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse4_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse4_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4_aes.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt' implementation, along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#if defined(COMPILER_HAS_SSE4) && defined(COMPILER_HAS_AES)\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse4_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse4_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse4_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse4_aes_UpdateFinal\n    #define shavite3_256_opt_Compress256 shavite3_256_opt_sse4_aes_Compress256\n\n    #define USE_HARDWARE_AES\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.cpp\"\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/opt/shavite3_256_opt_sse4_aes.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING\n\n// This file is a thin wrapper around the actual 'shavite3_256_aesni_opt', along with various other similarly named files.\n// The build system compiles each file with slightly different optimisation flags so that we have optimised implementations for a wide spread of processors.\n\n#ifndef HASH_SHAVITE3_256_SSE4_AES_H\n#define HASH_SHAVITE3_256_SSE4_AES_H\n    #define shavite3_256_opt_Init        shavite3_256_opt_sse4_aes_Init\n    #define shavite3_256_opt_Update      shavite3_256_opt_sse4_aes_Update\n    #define shavite3_256_opt_Final       shavite3_256_opt_sse4_aes_Final\n    #define shavite3_256_opt_UpdateFinal shavite3_256_opt_sse4_aes_UpdateFinal\n\n    #define SHAVITE3_256_OPT_IMPL\n    #include \"../shavite3_256_opt.h\"\n    #undef SHAVITE3_256_OPT_IMPL\n\n    #undef shavite3_256_opt_Init\n    #undef shavite3_256_opt_Update\n    #undef shavite3_256_opt_Final\n    #undef shavite3_256_opt_UpdateFinal\n#endif\n\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/ref/AESround.h",
    "content": "// File originates from the supercop project\n#ifndef AESROUND_H\n#define AESROUND_H\n\n// Tables of the combined SubBytes MixColumns operation\nstatic const uint32_t AESTable0[256] = {\n0xA56363C6U, 0x847C7CF8U, 0x997777EEU, 0x8D7B7BF6U, 0x0DF2F2FFU, 0xBD6B6BD6U, \n0xB16F6FDEU, 0x54C5C591U, 0x50303060U, 0x03010102U, 0xA96767CEU, 0x7D2B2B56U, \n0x19FEFEE7U, 0x62D7D7B5U, 0xE6ABAB4DU, 0x9A7676ECU, 0x45CACA8FU, 0x9D82821FU, \n0x40C9C989U, 0x877D7DFAU, 0x15FAFAEFU, 0xEB5959B2U, 0xC947478EU, 0x0BF0F0FBU, \n0xECADAD41U, 0x67D4D4B3U, 0xFDA2A25FU, 0xEAAFAF45U, 0xBF9C9C23U, 0xF7A4A453U, \n0x967272E4U, 0x5BC0C09BU, 0xC2B7B775U, 0x1CFDFDE1U, 0xAE93933DU, 0x6A26264CU, \n0x5A36366CU, 0x413F3F7EU, 0x02F7F7F5U, 0x4FCCCC83U, 0x5C343468U, 0xF4A5A551U, \n0x34E5E5D1U, 0x08F1F1F9U, 0x937171E2U, 0x73D8D8ABU, 0x53313162U, 0x3F15152AU, \n0x0C040408U, 0x52C7C795U, 0x65232346U, 0x5EC3C39DU, 0x28181830U, 0xA1969637U, \n0x0F05050AU, 0xB59A9A2FU, 0x0907070EU, 0x36121224U, 0x9B80801BU, 0x3DE2E2DFU, \n0x26EBEBCDU, 0x6927274EU, 0xCDB2B27FU, 0x9F7575EAU, 0x1B090912U, 0x9E83831DU, \n0x742C2C58U, 0x2E1A1A34U, 0x2D1B1B36U, 0xB26E6EDCU, 0xEE5A5AB4U, 0xFBA0A05BU, \n0xF65252A4U, 0x4D3B3B76U, 0x61D6D6B7U, 0xCEB3B37DU, 0x7B292952U, 0x3EE3E3DDU, \n0x712F2F5EU, 0x97848413U, 0xF55353A6U, 0x68D1D1B9U, 0x00000000U, 0x2CEDEDC1U, \n0x60202040U, 0x1FFCFCE3U, 0xC8B1B179U, 0xED5B5BB6U, 0xBE6A6AD4U, 0x46CBCB8DU, \n0xD9BEBE67U, 0x4B393972U, 0xDE4A4A94U, 0xD44C4C98U, 0xE85858B0U, 0x4ACFCF85U, \n0x6BD0D0BBU, 0x2AEFEFC5U, 0xE5AAAA4FU, 0x16FBFBEDU, 0xC5434386U, 0xD74D4D9AU, \n0x55333366U, 0x94858511U, 0xCF45458AU, 0x10F9F9E9U, 0x06020204U, 0x817F7FFEU, \n0xF05050A0U, 0x443C3C78U, 0xBA9F9F25U, 0xE3A8A84BU, 0xF35151A2U, 0xFEA3A35DU, \n0xC0404080U, 0x8A8F8F05U, 0xAD92923FU, 0xBC9D9D21U, 0x48383870U, 0x04F5F5F1U, \n0xDFBCBC63U, 0xC1B6B677U, 0x75DADAAFU, 0x63212142U, 0x30101020U, 0x1AFFFFE5U, \n0x0EF3F3FDU, 0x6DD2D2BFU, 0x4CCDCD81U, 0x140C0C18U, 0x35131326U, 0x2FECECC3U, \n0xE15F5FBEU, 0xA2979735U, 0xCC444488U, 0x3917172EU, 0x57C4C493U, 0xF2A7A755U, \n0x827E7EFCU, 0x473D3D7AU, 0xAC6464C8U, 0xE75D5DBAU, 0x2B191932U, 0x957373E6U, \n0xA06060C0U, 0x98818119U, 0xD14F4F9EU, 0x7FDCDCA3U, 0x66222244U, 0x7E2A2A54U, \n0xAB90903BU, 0x8388880BU, 0xCA46468CU, 0x29EEEEC7U, 0xD3B8B86BU, 0x3C141428U, \n0x79DEDEA7U, 0xE25E5EBCU, 0x1D0B0B16U, 0x76DBDBADU, 0x3BE0E0DBU, 0x56323264U, \n0x4E3A3A74U, 0x1E0A0A14U, 0xDB494992U, 0x0A06060CU, 0x6C242448U, 0xE45C5CB8U, \n0x5DC2C29FU, 0x6ED3D3BDU, 0xEFACAC43U, 0xA66262C4U, 0xA8919139U, 0xA4959531U, \n0x37E4E4D3U, 0x8B7979F2U, 0x32E7E7D5U, 0x43C8C88BU, 0x5937376EU, 0xB76D6DDAU, \n0x8C8D8D01U, 0x64D5D5B1U, 0xD24E4E9CU, 0xE0A9A949U, 0xB46C6CD8U, 0xFA5656ACU, \n0x07F4F4F3U, 0x25EAEACFU, 0xAF6565CAU, 0x8E7A7AF4U, 0xE9AEAE47U, 0x18080810U, \n0xD5BABA6FU, 0x887878F0U, 0x6F25254AU, 0x722E2E5CU, 0x241C1C38U, 0xF1A6A657U, \n0xC7B4B473U, 0x51C6C697U, 0x23E8E8CBU, 0x7CDDDDA1U, 0x9C7474E8U, 0x211F1F3EU, \n0xDD4B4B96U, 0xDCBDBD61U, 0x868B8B0DU, 0x858A8A0FU, 0x907070E0U, 0x423E3E7CU, \n0xC4B5B571U, 0xAA6666CCU, 0xD8484890U, 0x05030306U, 0x01F6F6F7U, 0x120E0E1CU, \n0xA36161C2U, 0x5F35356AU, 0xF95757AEU, 0xD0B9B969U, 0x91868617U, 0x58C1C199U, \n0x271D1D3AU, 0xB99E9E27U, 0x38E1E1D9U, 0x13F8F8EBU, 0xB398982BU, 0x33111122U, \n0xBB6969D2U, 0x70D9D9A9U, 0x898E8E07U, 0xA7949433U, 0xB69B9B2DU, 0x221E1E3CU, \n0x92878715U, 0x20E9E9C9U, 0x49CECE87U, 0xFF5555AAU, 0x78282850U, 0x7ADFDFA5U, \n0x8F8C8C03U, 0xF8A1A159U, 0x80898909U, 0x170D0D1AU, 0xDABFBF65U, 0x31E6E6D7U, \n0xC6424284U, 0xB86868D0U, 0xC3414182U, 0xB0999929U, 0x772D2D5AU, 0x110F0F1EU, \n0xCBB0B07BU, 0xFC5454A8U, 0xD6BBBB6DU, 0x3A16162CU, \n};\n\nstatic const uint32_t AESTable1[256] = {\n0x6363C6A5U, 0x7C7CF884U, 0x7777EE99U, 0x7B7BF68DU, 0xF2F2FF0DU, 0x6B6BD6BDU, \n0x6F6FDEB1U, 0xC5C59154U, 0x30306050U, 0x01010203U, 0x6767CEA9U, 0x2B2B567DU, \n0xFEFEE719U, 0xD7D7B562U, 0xABAB4DE6U, 0x7676EC9AU, 0xCACA8F45U, 0x82821F9DU, \n0xC9C98940U, 0x7D7DFA87U, 0xFAFAEF15U, 0x5959B2EBU, 0x47478EC9U, 0xF0F0FB0BU, \n0xADAD41ECU, 0xD4D4B367U, 0xA2A25FFDU, 0xAFAF45EAU, 0x9C9C23BFU, 0xA4A453F7U, \n0x7272E496U, 0xC0C09B5BU, 0xB7B775C2U, 0xFDFDE11CU, 0x93933DAEU, 0x26264C6AU, \n0x36366C5AU, 0x3F3F7E41U, 0xF7F7F502U, 0xCCCC834FU, 0x3434685CU, 0xA5A551F4U, \n0xE5E5D134U, 0xF1F1F908U, 0x7171E293U, 0xD8D8AB73U, 0x31316253U, 0x15152A3FU, \n0x0404080CU, 0xC7C79552U, 0x23234665U, 0xC3C39D5EU, 0x18183028U, 0x969637A1U, \n0x05050A0FU, 0x9A9A2FB5U, 0x07070E09U, 0x12122436U, 0x80801B9BU, 0xE2E2DF3DU, \n0xEBEBCD26U, 0x27274E69U, 0xB2B27FCDU, 0x7575EA9FU, 0x0909121BU, 0x83831D9EU, \n0x2C2C5874U, 0x1A1A342EU, 0x1B1B362DU, 0x6E6EDCB2U, 0x5A5AB4EEU, 0xA0A05BFBU, \n0x5252A4F6U, 0x3B3B764DU, 0xD6D6B761U, 0xB3B37DCEU, 0x2929527BU, 0xE3E3DD3EU, \n0x2F2F5E71U, 0x84841397U, 0x5353A6F5U, 0xD1D1B968U, 0x00000000U, 0xEDEDC12CU, \n0x20204060U, 0xFCFCE31FU, 0xB1B179C8U, 0x5B5BB6EDU, 0x6A6AD4BEU, 0xCBCB8D46U, \n0xBEBE67D9U, 0x3939724BU, 0x4A4A94DEU, 0x4C4C98D4U, 0x5858B0E8U, 0xCFCF854AU, \n0xD0D0BB6BU, 0xEFEFC52AU, 0xAAAA4FE5U, 0xFBFBED16U, 0x434386C5U, 0x4D4D9AD7U, \n0x33336655U, 0x85851194U, 0x45458ACFU, 0xF9F9E910U, 0x02020406U, 0x7F7FFE81U, \n0x5050A0F0U, 0x3C3C7844U, 0x9F9F25BAU, 0xA8A84BE3U, 0x5151A2F3U, 0xA3A35DFEU, \n0x404080C0U, 0x8F8F058AU, 0x92923FADU, 0x9D9D21BCU, 0x38387048U, 0xF5F5F104U, \n0xBCBC63DFU, 0xB6B677C1U, 0xDADAAF75U, 0x21214263U, 0x10102030U, 0xFFFFE51AU, \n0xF3F3FD0EU, 0xD2D2BF6DU, 0xCDCD814CU, 0x0C0C1814U, 0x13132635U, 0xECECC32FU, \n0x5F5FBEE1U, 0x979735A2U, 0x444488CCU, 0x17172E39U, 0xC4C49357U, 0xA7A755F2U, \n0x7E7EFC82U, 0x3D3D7A47U, 0x6464C8ACU, 0x5D5DBAE7U, 0x1919322BU, 0x7373E695U, \n0x6060C0A0U, 0x81811998U, 0x4F4F9ED1U, 0xDCDCA37FU, 0x22224466U, 0x2A2A547EU, \n0x90903BABU, 0x88880B83U, 0x46468CCAU, 0xEEEEC729U, 0xB8B86BD3U, 0x1414283CU, \n0xDEDEA779U, 0x5E5EBCE2U, 0x0B0B161DU, 0xDBDBAD76U, 0xE0E0DB3BU, 0x32326456U, \n0x3A3A744EU, 0x0A0A141EU, 0x494992DBU, 0x06060C0AU, 0x2424486CU, 0x5C5CB8E4U, \n0xC2C29F5DU, 0xD3D3BD6EU, 0xACAC43EFU, 0x6262C4A6U, 0x919139A8U, 0x959531A4U, \n0xE4E4D337U, 0x7979F28BU, 0xE7E7D532U, 0xC8C88B43U, 0x37376E59U, 0x6D6DDAB7U, \n0x8D8D018CU, 0xD5D5B164U, 0x4E4E9CD2U, 0xA9A949E0U, 0x6C6CD8B4U, 0x5656ACFAU, \n0xF4F4F307U, 0xEAEACF25U, 0x6565CAAFU, 0x7A7AF48EU, 0xAEAE47E9U, 0x08081018U, \n0xBABA6FD5U, 0x7878F088U, 0x25254A6FU, 0x2E2E5C72U, 0x1C1C3824U, 0xA6A657F1U, \n0xB4B473C7U, 0xC6C69751U, 0xE8E8CB23U, 0xDDDDA17CU, 0x7474E89CU, 0x1F1F3E21U, \n0x4B4B96DDU, 0xBDBD61DCU, 0x8B8B0D86U, 0x8A8A0F85U, 0x7070E090U, 0x3E3E7C42U, \n0xB5B571C4U, 0x6666CCAAU, 0x484890D8U, 0x03030605U, 0xF6F6F701U, 0x0E0E1C12U, \n0x6161C2A3U, 0x35356A5FU, 0x5757AEF9U, 0xB9B969D0U, 0x86861791U, 0xC1C19958U, \n0x1D1D3A27U, 0x9E9E27B9U, 0xE1E1D938U, 0xF8F8EB13U, 0x98982BB3U, 0x11112233U, \n0x6969D2BBU, 0xD9D9A970U, 0x8E8E0789U, 0x949433A7U, 0x9B9B2DB6U, 0x1E1E3C22U, \n0x87871592U, 0xE9E9C920U, 0xCECE8749U, 0x5555AAFFU, 0x28285078U, 0xDFDFA57AU, \n0x8C8C038FU, 0xA1A159F8U, 0x89890980U, 0x0D0D1A17U, 0xBFBF65DAU, 0xE6E6D731U, \n0x424284C6U, 0x6868D0B8U, 0x414182C3U, 0x999929B0U, 0x2D2D5A77U, 0x0F0F1E11U, \n0xB0B07BCBU, 0x5454A8FCU, 0xBBBB6DD6U, 0x16162C3AU, \n};\n\nstatic const uint32_t AESTable2[256] = {\n0x63C6A563U, 0x7CF8847CU, 0x77EE9977U, 0x7BF68D7BU, 0xF2FF0DF2U, 0x6BD6BD6BU, \n0x6FDEB16FU, 0xC59154C5U, 0x30605030U, 0x01020301U, 0x67CEA967U, 0x2B567D2BU, \n0xFEE719FEU, 0xD7B562D7U, 0xAB4DE6ABU, 0x76EC9A76U, 0xCA8F45CAU, 0x821F9D82U, \n0xC98940C9U, 0x7DFA877DU, 0xFAEF15FAU, 0x59B2EB59U, 0x478EC947U, 0xF0FB0BF0U, \n0xAD41ECADU, 0xD4B367D4U, 0xA25FFDA2U, 0xAF45EAAFU, 0x9C23BF9CU, 0xA453F7A4U, \n0x72E49672U, 0xC09B5BC0U, 0xB775C2B7U, 0xFDE11CFDU, 0x933DAE93U, 0x264C6A26U, \n0x366C5A36U, 0x3F7E413FU, 0xF7F502F7U, 0xCC834FCCU, 0x34685C34U, 0xA551F4A5U, \n0xE5D134E5U, 0xF1F908F1U, 0x71E29371U, 0xD8AB73D8U, 0x31625331U, 0x152A3F15U, \n0x04080C04U, 0xC79552C7U, 0x23466523U, 0xC39D5EC3U, 0x18302818U, 0x9637A196U, \n0x050A0F05U, 0x9A2FB59AU, 0x070E0907U, 0x12243612U, 0x801B9B80U, 0xE2DF3DE2U, \n0xEBCD26EBU, 0x274E6927U, 0xB27FCDB2U, 0x75EA9F75U, 0x09121B09U, 0x831D9E83U, \n0x2C58742CU, 0x1A342E1AU, 0x1B362D1BU, 0x6EDCB26EU, 0x5AB4EE5AU, 0xA05BFBA0U, \n0x52A4F652U, 0x3B764D3BU, 0xD6B761D6U, 0xB37DCEB3U, 0x29527B29U, 0xE3DD3EE3U, \n0x2F5E712FU, 0x84139784U, 0x53A6F553U, 0xD1B968D1U, 0x00000000U, 0xEDC12CEDU, \n0x20406020U, 0xFCE31FFCU, 0xB179C8B1U, 0x5BB6ED5BU, 0x6AD4BE6AU, 0xCB8D46CBU, \n0xBE67D9BEU, 0x39724B39U, 0x4A94DE4AU, 0x4C98D44CU, 0x58B0E858U, 0xCF854ACFU, \n0xD0BB6BD0U, 0xEFC52AEFU, 0xAA4FE5AAU, 0xFBED16FBU, 0x4386C543U, 0x4D9AD74DU, \n0x33665533U, 0x85119485U, 0x458ACF45U, 0xF9E910F9U, 0x02040602U, 0x7FFE817FU, \n0x50A0F050U, 0x3C78443CU, 0x9F25BA9FU, 0xA84BE3A8U, 0x51A2F351U, 0xA35DFEA3U, \n0x4080C040U, 0x8F058A8FU, 0x923FAD92U, 0x9D21BC9DU, 0x38704838U, 0xF5F104F5U, \n0xBC63DFBCU, 0xB677C1B6U, 0xDAAF75DAU, 0x21426321U, 0x10203010U, 0xFFE51AFFU, \n0xF3FD0EF3U, 0xD2BF6DD2U, 0xCD814CCDU, 0x0C18140CU, 0x13263513U, 0xECC32FECU, \n0x5FBEE15FU, 0x9735A297U, 0x4488CC44U, 0x172E3917U, 0xC49357C4U, 0xA755F2A7U, \n0x7EFC827EU, 0x3D7A473DU, 0x64C8AC64U, 0x5DBAE75DU, 0x19322B19U, 0x73E69573U, \n0x60C0A060U, 0x81199881U, 0x4F9ED14FU, 0xDCA37FDCU, 0x22446622U, 0x2A547E2AU, \n0x903BAB90U, 0x880B8388U, 0x468CCA46U, 0xEEC729EEU, 0xB86BD3B8U, 0x14283C14U, \n0xDEA779DEU, 0x5EBCE25EU, 0x0B161D0BU, 0xDBAD76DBU, 0xE0DB3BE0U, 0x32645632U, \n0x3A744E3AU, 0x0A141E0AU, 0x4992DB49U, 0x060C0A06U, 0x24486C24U, 0x5CB8E45CU, \n0xC29F5DC2U, 0xD3BD6ED3U, 0xAC43EFACU, 0x62C4A662U, 0x9139A891U, 0x9531A495U, \n0xE4D337E4U, 0x79F28B79U, 0xE7D532E7U, 0xC88B43C8U, 0x376E5937U, 0x6DDAB76DU, \n0x8D018C8DU, 0xD5B164D5U, 0x4E9CD24EU, 0xA949E0A9U, 0x6CD8B46CU, 0x56ACFA56U, \n0xF4F307F4U, 0xEACF25EAU, 0x65CAAF65U, 0x7AF48E7AU, 0xAE47E9AEU, 0x08101808U, \n0xBA6FD5BAU, 0x78F08878U, 0x254A6F25U, 0x2E5C722EU, 0x1C38241CU, 0xA657F1A6U, \n0xB473C7B4U, 0xC69751C6U, 0xE8CB23E8U, 0xDDA17CDDU, 0x74E89C74U, 0x1F3E211FU, \n0x4B96DD4BU, 0xBD61DCBDU, 0x8B0D868BU, 0x8A0F858AU, 0x70E09070U, 0x3E7C423EU, \n0xB571C4B5U, 0x66CCAA66U, 0x4890D848U, 0x03060503U, 0xF6F701F6U, 0x0E1C120EU, \n0x61C2A361U, 0x356A5F35U, 0x57AEF957U, 0xB969D0B9U, 0x86179186U, 0xC19958C1U, \n0x1D3A271DU, 0x9E27B99EU, 0xE1D938E1U, 0xF8EB13F8U, 0x982BB398U, 0x11223311U, \n0x69D2BB69U, 0xD9A970D9U, 0x8E07898EU, 0x9433A794U, 0x9B2DB69BU, 0x1E3C221EU, \n0x87159287U, 0xE9C920E9U, 0xCE8749CEU, 0x55AAFF55U, 0x28507828U, 0xDFA57ADFU, \n0x8C038F8CU, 0xA159F8A1U, 0x89098089U, 0x0D1A170DU, 0xBF65DABFU, 0xE6D731E6U, \n0x4284C642U, 0x68D0B868U, 0x4182C341U, 0x9929B099U, 0x2D5A772DU, 0x0F1E110FU, \n0xB07BCBB0U, 0x54A8FC54U, 0xBB6DD6BBU, 0x162C3A16U, \n};\n\nstatic const uint32_t AESTable3[256] = {\n0xC6A56363U, 0xF8847C7CU, 0xEE997777U, 0xF68D7B7BU, 0xFF0DF2F2U, 0xD6BD6B6BU, \n0xDEB16F6FU, 0x9154C5C5U, 0x60503030U, 0x02030101U, 0xCEA96767U, 0x567D2B2BU, \n0xE719FEFEU, 0xB562D7D7U, 0x4DE6ABABU, 0xEC9A7676U, 0x8F45CACAU, 0x1F9D8282U, \n0x8940C9C9U, 0xFA877D7DU, 0xEF15FAFAU, 0xB2EB5959U, 0x8EC94747U, 0xFB0BF0F0U, \n0x41ECADADU, 0xB367D4D4U, 0x5FFDA2A2U, 0x45EAAFAFU, 0x23BF9C9CU, 0x53F7A4A4U, \n0xE4967272U, 0x9B5BC0C0U, 0x75C2B7B7U, 0xE11CFDFDU, 0x3DAE9393U, 0x4C6A2626U, \n0x6C5A3636U, 0x7E413F3FU, 0xF502F7F7U, 0x834FCCCCU, 0x685C3434U, 0x51F4A5A5U, \n0xD134E5E5U, 0xF908F1F1U, 0xE2937171U, 0xAB73D8D8U, 0x62533131U, 0x2A3F1515U, \n0x080C0404U, 0x9552C7C7U, 0x46652323U, 0x9D5EC3C3U, 0x30281818U, 0x37A19696U, \n0x0A0F0505U, 0x2FB59A9AU, 0x0E090707U, 0x24361212U, 0x1B9B8080U, 0xDF3DE2E2U, \n0xCD26EBEBU, 0x4E692727U, 0x7FCDB2B2U, 0xEA9F7575U, 0x121B0909U, 0x1D9E8383U, \n0x58742C2CU, 0x342E1A1AU, 0x362D1B1BU, 0xDCB26E6EU, 0xB4EE5A5AU, 0x5BFBA0A0U, \n0xA4F65252U, 0x764D3B3BU, 0xB761D6D6U, 0x7DCEB3B3U, 0x527B2929U, 0xDD3EE3E3U, \n0x5E712F2FU, 0x13978484U, 0xA6F55353U, 0xB968D1D1U, 0x00000000U, 0xC12CEDEDU, \n0x40602020U, 0xE31FFCFCU, 0x79C8B1B1U, 0xB6ED5B5BU, 0xD4BE6A6AU, 0x8D46CBCBU, \n0x67D9BEBEU, 0x724B3939U, 0x94DE4A4AU, 0x98D44C4CU, 0xB0E85858U, 0x854ACFCFU, \n0xBB6BD0D0U, 0xC52AEFEFU, 0x4FE5AAAAU, 0xED16FBFBU, 0x86C54343U, 0x9AD74D4DU, \n0x66553333U, 0x11948585U, 0x8ACF4545U, 0xE910F9F9U, 0x04060202U, 0xFE817F7FU, \n0xA0F05050U, 0x78443C3CU, 0x25BA9F9FU, 0x4BE3A8A8U, 0xA2F35151U, 0x5DFEA3A3U, \n0x80C04040U, 0x058A8F8FU, 0x3FAD9292U, 0x21BC9D9DU, 0x70483838U, 0xF104F5F5U, \n0x63DFBCBCU, 0x77C1B6B6U, 0xAF75DADAU, 0x42632121U, 0x20301010U, 0xE51AFFFFU, \n0xFD0EF3F3U, 0xBF6DD2D2U, 0x814CCDCDU, 0x18140C0CU, 0x26351313U, 0xC32FECECU, \n0xBEE15F5FU, 0x35A29797U, 0x88CC4444U, 0x2E391717U, 0x9357C4C4U, 0x55F2A7A7U, \n0xFC827E7EU, 0x7A473D3DU, 0xC8AC6464U, 0xBAE75D5DU, 0x322B1919U, 0xE6957373U, \n0xC0A06060U, 0x19988181U, 0x9ED14F4FU, 0xA37FDCDCU, 0x44662222U, 0x547E2A2AU, \n0x3BAB9090U, 0x0B838888U, 0x8CCA4646U, 0xC729EEEEU, 0x6BD3B8B8U, 0x283C1414U, \n0xA779DEDEU, 0xBCE25E5EU, 0x161D0B0BU, 0xAD76DBDBU, 0xDB3BE0E0U, 0x64563232U, \n0x744E3A3AU, 0x141E0A0AU, 0x92DB4949U, 0x0C0A0606U, 0x486C2424U, 0xB8E45C5CU, \n0x9F5DC2C2U, 0xBD6ED3D3U, 0x43EFACACU, 0xC4A66262U, 0x39A89191U, 0x31A49595U, \n0xD337E4E4U, 0xF28B7979U, 0xD532E7E7U, 0x8B43C8C8U, 0x6E593737U, 0xDAB76D6DU, \n0x018C8D8DU, 0xB164D5D5U, 0x9CD24E4EU, 0x49E0A9A9U, 0xD8B46C6CU, 0xACFA5656U, \n0xF307F4F4U, 0xCF25EAEAU, 0xCAAF6565U, 0xF48E7A7AU, 0x47E9AEAEU, 0x10180808U, \n0x6FD5BABAU, 0xF0887878U, 0x4A6F2525U, 0x5C722E2EU, 0x38241C1CU, 0x57F1A6A6U, \n0x73C7B4B4U, 0x9751C6C6U, 0xCB23E8E8U, 0xA17CDDDDU, 0xE89C7474U, 0x3E211F1FU, \n0x96DD4B4BU, 0x61DCBDBDU, 0x0D868B8BU, 0x0F858A8AU, 0xE0907070U, 0x7C423E3EU, \n0x71C4B5B5U, 0xCCAA6666U, 0x90D84848U, 0x06050303U, 0xF701F6F6U, 0x1C120E0EU, \n0xC2A36161U, 0x6A5F3535U, 0xAEF95757U, 0x69D0B9B9U, 0x17918686U, 0x9958C1C1U, \n0x3A271D1DU, 0x27B99E9EU, 0xD938E1E1U, 0xEB13F8F8U, 0x2BB39898U, 0x22331111U, \n0xD2BB6969U, 0xA970D9D9U, 0x07898E8EU, 0x33A79494U, 0x2DB69B9BU, 0x3C221E1EU, \n0x15928787U, 0xC920E9E9U, 0x8749CECEU, 0xAAFF5555U, 0x50782828U, 0xA57ADFDFU, \n0x038F8C8CU, 0x59F8A1A1U, 0x09808989U, 0x1A170D0DU, 0x65DABFBFU, 0xD731E6E6U, \n0x84C64242U, 0xD0B86868U, 0x82C34141U, 0x29B09999U, 0x5A772D2DU, 0x1E110F0FU, \n0x7BCBB0B0U, 0xA8FC5454U, 0x6DD6BBBBU, 0x2C3A1616U, \n};\n\n#define roundAESnokey(_input0, _input1, _input2, _input3, _output0, _output1, _output2, _output3) \\\n{ \\\n  _output0 = AESTable0[_input0 & 0xff ] ^ AESTable1[(_input1 >> 8) & 0xff] ^ AESTable2[(_input2 >> 16) & 0xff] ^ AESTable3[_input3 >> 24]; \\\n  _output1 = AESTable0[_input1 & 0xff ] ^ AESTable1[(_input2 >> 8) & 0xff] ^ AESTable2[(_input3 >> 16) & 0xff] ^ AESTable3[_input0 >> 24]; \\\n  _output2 = AESTable0[_input2 & 0xff ] ^ AESTable1[(_input3 >> 8) & 0xff] ^ AESTable2[(_input0 >> 16) & 0xff] ^ AESTable3[_input1 >> 24]; \\\n  _output3 = AESTable0[_input3 & 0xff ] ^ AESTable1[(_input0 >> 8) & 0xff] ^ AESTable2[(_input1 >> 16) & 0xff] ^ AESTable3[_input2 >> 24]; \\\n}\n\n#define roundAES(_input0, _input1, _input2, _input3, _output0, _output1, _output2, _output3, _key0, _key1, _key2, _key3) \\\n{ \\\n  _output0 = AESTable0[_input0 & 0xff ] ^ AESTable1[(_input1 >> 8) & 0xff] ^ AESTable2[(_input2 >> 16) & 0xff] ^ AESTable3[_input3 >> 24]^_key0; \\\n  _output1 = AESTable0[_input1 & 0xff ] ^ AESTable1[(_input2 >> 8) & 0xff] ^ AESTable2[(_input3 >> 16) & 0xff] ^ AESTable3[_input0 >> 24]^_key1; \\\n  _output2 = AESTable0[_input2 & 0xff ] ^ AESTable1[(_input3 >> 8) & 0xff] ^ AESTable2[(_input0 >> 16) & 0xff] ^ AESTable3[_input1 >> 24]^_key2; \\\n  _output3 = AESTable0[_input3 & 0xff ] ^ AESTable1[(_input0 >> 8) & 0xff] ^ AESTable2[(_input1 >> 16) & 0xff] ^ AESTable3[_input2 >> 24]^_key3; \\\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/ref/portable.h",
    "content": "// File originates from the supercop project\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n/*\n * IT IS ADVISABLE TO INCLUDE THIS FILE AS THE FIRST INCLUDE in the\n * source, as it makes some optimizations over some other include\n * files, which are not possible if the other include files are\n * included first (this is now applicable to string.h)\n */\n\n#ifndef SHAVITE_PORTABLE_C__\n#define SHAVITE_PORTABLE_C__\n\n/* __USE_STRING_INLINES tells GCC to optimize memcpy when the number */\n/* of bytes is constant (see /usr/include/string.h) */\n#if defined(__GNUC__) && !defined(__USE_STRING_INLINES)\n#define __USE_STRING_INLINES\n#endif\n#include <string.h>\n#include <stdlib.h>\n#include <math.h>\n#include <stdio.h>\n\n\n#include <limits.h>\n#include <stdint.h>\n#include <compat/arch.h>\n\n#if UINT_MAX >= 4294967295UL\n#define ONE32   0xFFFFFFFFU\n#else\n#define ONE32   0xFFFFFFFFUL\n#endif\n#define ONE8    0xFFU\n#define ONE16   0xFFFFU\n#define T8(x)   ((x) & ONE8)\n#define T16(x)  ((x) & ONE16)\n#define T32(x)  ((x) & ONE32)\n\n#define ONE64   LL(0xFFFFFFFFFFFFFFFF)\n#define T64(x)  ((x) & ONE64)\n\n// U16TO8_LITTLE(c, v) stores the 16-bit-value v in little-endian convention into the unsigned char array pointed to by c.\n#ifndef WORDS_BIGENDIAN\n#define U16TO8_LITTLE(c, v) memcpy(c, &v, 2)\n#else\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U16TO8_LITTLE(c, v)    do { \\\n    uint16_t tmp_portable_h_x = (v); \\\n    uint8_t* tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8); \\\n} while (0)\n#endif\n\n// U8TO32_LITTLE(c) returns the 32-bit value stored in little-endian convention in the unsigned char array pointed to by c.\n#ifndef WORDS_BIGENDIAN\n#define U8TO32_LITTLE(c)  (((uint32_t*)(c))[0])\n#else\n#define U8TO32_LITTLE(c)  (((uint32_t)T8(*((uint8_t*)(c)))) | ((uint32_t)T8(*(((uint8_t*)(c)) + 1)) << 8) | ((uint32_t)T8(*(((uint8_t*)(c)) + 2)) << 16) | ((uint32_t)T8(*(((uint8_t*)(c)) + 3)) << 24))\n#endif\n\n// U32TO8_LITTLE(c, v) stores the 32-bit-value v in little-endian convention into the unsigned char array pointed to by c.\n#ifndef WORDS_BIGENDIAN\n#define U32TO8_LITTLE(c, v) memcpy(c, &v, 4)\n#else\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U32TO8_LITTLE(c, v)    do { \\\n    uint32_t tmp_portable_h_x = (v); \\\n    uint8_t* tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8); \\\n    tmp_portable_h_d[2] = T8(tmp_portable_h_x >> 16); \\\n    tmp_portable_h_d[3] = T8(tmp_portable_h_x >> 24); \\\n} while (0)\n#endif\n\n// U64TO8_LITTLE(c, v) stores the 64-bit-value v in little-endian convention into the unsigned char array pointed to by c.\n#ifndef WORDS_BIGENDIAN\n#define U64TO8_LITTLE(c, v) memcpy(c, &v, 8)\n#else\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U64TO8_LITTLE(c, v)    do { \\\n    uint64_t tmp_portable_h_x = (v); \\\n    uint8_t *tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8);  \\\n    tmp_portable_h_d[2] = T8(tmp_portable_h_x >> 16); \\\n    tmp_portable_h_d[3] = T8(tmp_portable_h_x >> 24); \\\n    tmp_portable_h_d[4] = T8(tmp_portable_h_x >> 32); \\\n    tmp_portable_h_d[5] = T8(tmp_portable_h_x >> 40); \\\n    tmp_portable_h_d[6] = T8(tmp_portable_h_x >> 48); \\\n    tmp_portable_h_d[7] = T8(tmp_portable_h_x >> 56); \\\n} while (0)\n#endif\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/ref/shavite3_256_ref_compress.h",
    "content": "// File originates from the supercop project\n// Authors: Eli Biham and Orr Dunkelman\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SHAVITE_REF_256_H\n#define SHAVITE_REF_256_H\n\n#include \"portable.h\"\n#include \"AESround.h\"\n#include \"shavite3_ref.h\"\n\n\n#define InternalRounds 3\n#define ExternalRounds 12\n#define ExpandedMessageSize (ExternalRounds*4*(InternalRounds))\n\n// The message expansion takes a 16 words (stored in rk[0,.,15]) and the counter values to produce the full expanded message\n// Generates 16 more words in rk[] using the nonlinear expansion step new words: rk[16..31]\n#define NonLinExpansion16(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3)\\\n{\\\n\tx0 = rk[1];\\\n        x1 = rk[2];\\\n        x2 = rk[3];\\\n        x3 = rk[0];\\\n        roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n        rk[16] = y0^rk[12]^counter[0];\\\n        rk[17] = y1^rk[13]^~counter[1];\\\n        rk[18] = y2^rk[14];\\\n        rk[19] = y3^rk[15];\\\n        x0 = rk[5];\\\n        x1 = rk[6];\\\n        x2 = rk[7];\\\n        x3 = rk[4];\\\n        roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n        rk[20] = y0^rk[16];\\\n        rk[21] = y1^rk[17];\\\n        rk[22] = y2^rk[18];\\\n        rk[23] = y3^rk[19];\\\n\tx0 = rk[9];\\\n        x1 = rk[10];\\\n        x2 = rk[11];\\\n        x3 = rk[8];\\\n        roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n        rk[24] = y0^rk[20];\\\n        rk[25] = y1^rk[21];\\\n        rk[26] = y2^rk[22];\\\n        rk[27] = y3^rk[23];\\\n        x0 = rk[13];\\\n        x1 = rk[14];\\\n        x2 = rk[15];\\\n        x3 = rk[12];\\\n        roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n        rk[28] = y0^rk[24];\\\n        rk[29] = y1^rk[25];\\\n        rk[30] = y2^rk[26];\\\n        rk[31] = y3^rk[27];\\\n}\n\n// Generates 16 more words in rk[] using the nonlinear expansion step new words: rk[48..63]\n#define NonLinExpansion48(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3)\\\n{\\\n    x0 = rk[33];\\\n    x1 = rk[34];\\\n    x2 = rk[35];\\\n    x3 = rk[32];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[48] = y0^rk[44];\\\n    rk[49] = y1^rk[45];\\\n    rk[50] = y2^rk[46];\\\n    rk[51] = y3^rk[47];\\\n    x0 = rk[37];\\\n    x1 = rk[38];\\\n    x2 = rk[39];\\\n    x3 = rk[36];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[52] = y0^rk[48];\\\n    rk[53] = y1^rk[49];\\\n    rk[54] = y2^rk[50];\\\n    rk[55] = y3^rk[51];\\\n    x0 = rk[41];\\\n    x1 = rk[42];\\\n    x2 = rk[43];\\\n    x3 = rk[40];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[56] = y0^rk[52];\\\n    rk[57] = y1^rk[53]^counter[1];\\\n    rk[58] = y2^rk[54]^~counter[0];\\\n    rk[59] = y3^rk[55];\\\n    x0 = rk[45];\\\n    x1 = rk[46];\\\n    x2 = rk[47];\\\n    x3 = rk[44];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[60] = y0^rk[56];\\\n    rk[61] = y1^rk[57];\\\n    rk[62] = y2^rk[58];\\\n    rk[63] = y3^rk[59];\\\n}\n\n// Generates 16 more words in rk[] using the nonlinear expansion step new words: rk[80..95]\n#define NonLinExpansion80(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3)\\\n{\\\n    x0 = rk[65];\\\n    x1 = rk[66];\\\n    x2 = rk[67];\\\n    x3 = rk[64];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[80] = y0^rk[76];\\\n    rk[81] = y1^rk[77];\\\n    rk[82] = y2^rk[78];\\\n    rk[83] = y3^rk[79];\\\n    x0 = rk[69];\\\n    x1 = rk[70];\\\n    x2 = rk[71];\\\n    x3 = rk[68];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[84] = y0^rk[80];\\\n    rk[85] = y1^rk[81];\\\n    rk[86] = y2^rk[82]^counter[1];\\\n    rk[87] = y3^rk[83]^~counter[0];\\\n    x0 = rk[73];\\\n    x1 = rk[74];\\\n    x2 = rk[75];\\\n    x3 = rk[72];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[88] = y0^rk[84];\\\n    rk[89] = y1^rk[85];\\\n    rk[90] = y2^rk[86];\\\n    rk[91] = y3^rk[87];\\\n    x0 = rk[77];\\\n    x1 = rk[78];\\\n    x2 = rk[79];\\\n    x3 = rk[76];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[92] = y0^rk[88];\\\n    rk[93] = y1^rk[89];\\\n    rk[94] = y2^rk[90];\\\n    rk[95] = y3^rk[91];\\\n}\n\n// Generates 16 more words in rk[] using the nonlinear expansion step new words: rk[112..127]\n#define NonLinExpansion112(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3)\\\n{\\\n    x0 = rk[97];\\\n    x1 = rk[98];\\\n    x2 = rk[99];\\\n    x3 = rk[96];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[112] = y0^rk[108];\\\n    rk[113] = y1^rk[109];\\\n    rk[114] = y2^rk[110];\\\n    rk[115] = y3^rk[111];\\\n    x0 = rk[101];\\\n    x1 = rk[102];\\\n    x2 = rk[103];\\\n    x3 = rk[100];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[116] = y0^rk[112];\\\n    rk[117] = y1^rk[113];\\\n    rk[118] = y2^rk[114];\\\n    rk[119] = y3^rk[115];\\\n    x0 = rk[105];\\\n    x1 = rk[106];\\\n    x2 = rk[107];\\\n    x3 = rk[104];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[120] = y0^rk[116];\\\n    rk[121] = y1^rk[117];\\\n    rk[122] = y2^rk[118];\\\n    rk[123] = y3^rk[119];\\\n    x0 = rk[109];\\\n    x1 = rk[110];\\\n    x2 = rk[111];\\\n    x3 = rk[108];\\\n    roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n    rk[124] = y0^rk[120]^counter[0];\\\n    rk[125] = y1^rk[121];\\\n    rk[126] = y2^rk[122];\\\n    rk[127] = y3^rk[123]^~counter[1];\\\n}\n\n#define LinExpansion(rk,position,temp0,temp1,temp2)\\\n{\\\n   temp0=position; temp1=position-16; temp2=position-3;\\\n   for (;temp1<position;temp0++,temp1++,temp2++)\\\n     rk[temp0] = rk[temp1]^rk[temp2];\\\n}\n\n\n#define two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,x0,x1,x2,x3,y0,y1,y2,y3,rk,position)\\\n{\\\n   x0 = state4^rk[position];\\\n   x1 = state5^rk[position+1];\\\n   x2 = state6^rk[position+2];\\\n   x3 = state7^rk[position+3];\\\n   roundAES(x0,x1,x2,x3,y0,y1,y2,y3,rk[position+4],rk[position+5],rk[position+6],rk[position+7]);\\\n   roundAES(y0,y1,y2,y3,x0,x1,x2,x3,rk[position+8],rk[position+9],rk[position+10],rk[position+11]);\\\n   roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n   state0 ^= y0;\\\n   state1 ^= y1;\\\n   state2 ^= y2;\\\n   state3 ^= y3;\\\n   x0 = state0^rk[position+12];\\\n   x1 = state1^rk[position+13];\\\n   x2 = state2^rk[position+14];\\\n   x3 = state3^rk[position+15];\\\n   roundAES(x0,x1,x2,x3,y0,y1,y2,y3,rk[position+16],rk[position+17],rk[position+18],rk[position+19]);\\\n   roundAES(y0,y1,y2,y3,x0,x1,x2,x3,rk[position+20],rk[position+21],rk[position+22],rk[position+23]);\\\n   roundAESnokey(x0,x1,x2,x3,y0,y1,y2,y3);\\\n   state4^=y0;\\\n   state5^=y1;\\\n   state6^=y2;\\\n   state7^=y3;\\\n}\n\ninline void E256_ref(uint32_t pt[8], uint32_t ct[8], uint32_t message[16], uint32_t counter[2])\n{\n    uint32_t state0,state1,state2,state3,state4,state5,state6,state7,i,j,k;\n    uint32_t x0,x1,x2,x3,y0,y1,y2,y3;\n    uint32_t rk[ExpandedMessageSize];\n\n    state0=pt[0]; \n    state1=pt[1]; \n    state2=pt[2]; \n    state3=pt[3];\n    state4=pt[4];\n    state5=pt[5];\n    state6=pt[6];\n    state7=pt[7];\n    for (i=0;i<16;i++) rk[i]=message[i];\n\n    NonLinExpansion16(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3);\n\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,0);\n    LinExpansion(rk,32,i,j,k);\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,24);\n    NonLinExpansion48(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3);\n    LinExpansion(rk,64,i,j,k);\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,48);\n    NonLinExpansion80(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3);\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,72);\n    LinExpansion(rk,96,i,j,k);\n    NonLinExpansion112(rk,counter,x0,x1,x2,x3,y0,y1,y2,y3);\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,96);\n    LinExpansion(rk,128,i,j,k);\n    two_rounds(state0,state1,state2,state3,state4,state5,state6,state7,y0,y1,y2,y3,x0,x1,x2,x3,rk,120);\n\n    ct[0]=state0; \n    ct[1]=state1; \n    ct[2]=state2; \n    ct[3]=state3;\n    ct[4]=state4;\n    ct[5]=state5;\n    ct[6]=state6;\n    ct[7]=state7;\n\n    return;\n}\n\n// The actual compression function C_{256}\ninline void Compress256_ref(const uint8_t* message_block, uint8_t* chaining_value, uint64_t counter)\n{    \n    uint32_t pt[8],ct[8];\n    uint32_t msg_u32[16];\n    uint32_t cnt[2];\n    int i;\n\n    // Translating all the inputs to 32-bit words\n    for (i=0;i<8;i++)\n    {\n        pt[i]=U8TO32_LITTLE(chaining_value+4*i);\n    }\n\n    for (i=0;i<16;i++)\n    {\n        msg_u32[i]=U8TO32_LITTLE(message_block+4*i);\n    }\n\n    cnt[1]=(uint32_t)(counter>>32);\n    cnt[0]=(uint32_t)(counter & 0xFFFFFFFFULL);\n\n    // Computing the encryption function\n    E256_ref(pt, ct, msg_u32, cnt);\n\n    // Davies-Meyer transformation\n    for (i=0; i<8; i++)\n    {\n        pt[i]^=ct[i];\n    }\n\n    // Translating the output to 8-bit words\n    for (i=0; i<8; i++)\n    {\n        U32TO8_LITTLE(chaining_value+i*4, pt[i]);\n    }\n\n   return;\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/ref/shavite3_ref.cpp",
    "content": "// File originates from the supercop project\n// Authors: Eli Biham and Orr Dunkelman\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"portable.h\"\n#include \"shavite3_256_ref_compress.h\"\n#include \"shavite3_ref.h\"\n#include <assert.h>\n\nuint32_t IV_256[8] = {0x49BB3E47, 0x2674860D, 0xA8B392AC, 0x021AC4E6, 0x409283CF, 0x620E5D86, 0x6D929DCB, 0x96CC2A8B};\n\n// Initialization of the internal state of the hash function\nbool shavite3_ref_Init(shavite3_ref_hashState* state)\n{\n    int i;\n\n    // Initialization of the counter of number of bits that were hashed so far\n    state->bitcount = 0;\n\n    // Store the requested digest size\n    state->DigestSize = 256;\n\n    // Initialize the message block to empty\n    memset(state->buffer,0,128);\n\n    //Set the input to the compression function to all zero\n    memset(state->chaining_value,0,64); \n\n    // Set the message block to zero\n    memset(state->buffer,0,128);\n\n    // Load the correct IV\n    for (i=0;i<8;i++)\n    {\n        U32TO8_LITTLE(state->chaining_value + 4*i, IV_256[i]);\n    }\n    state->BlockSize = 512;\n    return true;\n}\n\n\n\n// Compressing the input data, and updating the internal state\nbool shavite3_ref_Update(shavite3_ref_hashState* state, const uint8_t* data, uint64_t dataLenBytes)\n{\n    // p is a pointer to the current location inside data that we need to process\n    // (i.e., the first byte of the data which was not used as an input to the compression function\n    uint8_t* p = (uint8_t*)data;\n\n    // len is the size of the data that was not process yet in bytes\n    int len = dataLenBytes;\n\n    // BlockSizeB is the size of the message block of the compression function\n    int BlockSizeB = (state->BlockSize/8);\n\n    // bufcnt stores the number of bytes that are were \"sent\" to the compression function, but were not yet processed, as a full block has not been obtained\n    int bufcnt= (state->bitcount>>3)%BlockSizeB;\n\n    // local_bitcount contains the number of bits actually hashed so far\n    uint64_t local_bitcount;\n\n    // load the number of bits hashed so far into local_bitcount\n    local_bitcount=state->bitcount;\n\n    // mark that we processed more bits\n    state->bitcount += dataLenBytes*8;\n\n    // Check if we have enough data to call the compression function\n    // If not, just copy the input to the buffer of the message block\n    if (bufcnt + len < BlockSizeB)\n    {\n        memcpy(&state->buffer[bufcnt], p, len);\n        return true;\n    }\n\n    // There is enough data to start calling the compression function. \n    // We first check whether there is data remaining from previous calls\n    if (bufcnt>0)\n    {\n        // Copy from the input the required number of bytes to fill a block\n        memcpy(&state->buffer[bufcnt], p, BlockSizeB-bufcnt);\n\n        // Update the location of the first byte that was not processed\n        p += BlockSizeB-bufcnt;\n\n        // Update the remaining number of bytes to process\n        len -= BlockSizeB-bufcnt;\n\n        // Update the number of bits hashed so far (locally)\n        local_bitcount+=8*(BlockSizeB-bufcnt);\n\n        // Call the respective compression function to process the current block\n        Compress256_ref(state->buffer, state->chaining_value, local_bitcount);\n    }\n\n    // At this point, the only remaining data is from the message block call the compression function as many times as possible, and store the remaining bytes in the buffer\n    // Each step of the loop compresses BlockSizeB bytes\n    for( ; len>=BlockSizeB; len-=BlockSizeB, p+=BlockSizeB)\n    {\n        // Update the number of bits hashed so far (locally)\n        local_bitcount+=8*BlockSizeB;\n\n        // Call the respective compression function to process the current block\n        Compress256_ref(p, state->chaining_value, local_bitcount);\n    }\n\n    // If there are still unprocessed bytes, store them locally and wait for more\n    if (len>0)\n    {\n        memcpy(state->buffer, p, len);\n    }\n\n   return true;\n}\n\n\n// Performing the padding scheme, and dealing with any remaining bits\nbool shavite3_ref_Final(shavite3_ref_hashState* state, uint8_t* hashval)\n{\n    // Stores inputs (message blocks) to the compression function\n    uint8_t block[128];\n\n    // Stores results (chaining value) of the compression function\n    uint8_t result[64];\n\n    // BlockSizeB is the size of the message block of the compression function\n    uint64_t BlockSizeB = (state->BlockSize/8);\n\n    // bufcnt stores the number of bytes that are were \"sent\" to the compression function, but were not yet processed, as a full block has not been obtained\n    uint64_t bufcnt= ((uint64_t)state->bitcount>>3)%BlockSizeB;\n\n    // Copy the current chaining value into result (as a temporary step)\n    if (state->DigestSize < 257)\n    {\n        memcpy(result, state->chaining_value, 32);\n    }\n    else\n    {\n        memcpy(result, state->chaining_value, 64);\n    }\n\n\n    // Initialize block as the message block to compress with the bytes that were not processed yet\n    memset(block, 0, BlockSizeB);\n    memcpy(block, state->buffer, bufcnt);\n\n    // Pad the buffer with the byte which contains the fraction of bytes  from and a bit equal to 1\n    block[bufcnt] = (state->partial_byte& ~((0x80 >> (state->bitcount&7))-1)) | (0x80 >> (state->bitcount&7));\n\n    // Compress the last block (according to the digest size)\n    // An additional message block is required if there are less than 10\n    // more bytes for message length and digest length encoding\n    if (bufcnt>=BlockSizeB-10)\n    {\n        // Compress the current block\n        Compress256_ref(block,result,state->bitcount);\n\n        // Generate the full padding block\n        memset(block, 0, BlockSizeB);\n        U64TO8_LITTLE(block+BlockSizeB-10, state->bitcount);\n        U16TO8_LITTLE(block+BlockSizeB-2, state->DigestSize);\n\n        // Compress the full padding block\n        Compress256_ref(block,result,0x0ULL);\n    }\n    else\n    {\n        // Pad the number of bits hashed so far and the digest size to the last message block and compress it\n        U64TO8_LITTLE(block+BlockSizeB-10, state->bitcount);\n        U16TO8_LITTLE(block+BlockSizeB-2, state->DigestSize);\n        if (state->bitcount % state->BlockSize)\n        {\n            Compress256_ref(block,result, state->bitcount);\n        }\n        else\n        {\n            Compress256_ref(block,result, 0x0ULL);\n        }\n    }\n\n    // Copy the result into the supplied array of bytes.\n    for (int i=0;i<(state->DigestSize+7)/8;i++)\n    {\n        hashval[i]=result[i];\n    }\n\n\n    // Treat cases where the digest size is not a multiple of a byte\n    if ((state->DigestSize)&7)\n    {\n       hashval[(state->DigestSize+7)/8] &= (0xFF<<(8-((state->DigestSize)%8)))&0xFF;\n    }\n    return true;\n}\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/ref/shavite3_ref.h",
    "content": "// File originates from the supercop project\n// Authors: Eli Biham and Orr Dunkelman\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// definitions imposed by the API\n#ifndef SHA3API_H\n#define SHA3API_H\n\n#include <stdint.h>\n\n// SHAvite-3 definition\nstruct shavite3_ref_hashState\n{\n   uint64_t bitcount;            // The number of bits compressed so far\n   uint8_t chaining_value[64];   // An array containing the chaining value\n   uint8_t buffer[128];          // A buffer storing bytes until they are compressed\n   uint8_t partial_byte=0;         // A byte to store a fraction of a byte in case the input is not fully byte alligned\n   int DigestSize;               // The requested digest size\n   int BlockSize;                // The message block size\n};\n\n// Function calls imposed by the API\nbool shavite3_ref_Init(shavite3_ref_hashState* state);\nbool shavite3_ref_Update(shavite3_ref_hashState* state, const uint8_t* data, uint64_t dataLenBytes);\nbool shavite3_ref_Final(shavite3_ref_hashState* state, uint8_t* hashval);\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/shavite3_256_aesni.h",
    "content": ""
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/shavite3_256_opt.cpp",
    "content": "// File originates from the supercop project\n// Authors: Eli Biham and Orr Dunkelman\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n\n#include \"shavite3_256_opt.h\"\n\n#ifndef USE_HARDWARE_AES\n#define _mm_aesenc_si128 _mm_aesenc_si128_sw\n#endif\n\n#ifdef SHAVITE3_256_OPT_IMPL\n\n#include \"compat.h\"\n#include \"assert.h\"\n#include <memory.h>\n\n#define T8(x) ((x) & 0xff)\n\n/// Encrypts the plaintext pt[] using the key message[], and counter[], to produce the ciphertext ct[]\n\n\n#define SHAVITE_MIXING_256_OPT   \\\n    x11 = x15;                   \\\n    x10 = x14;                   \\\n    x9 =  x13;                   \\\n    x8 = x12;                    \\\n                                 \\\n    x6 = x11;                    \\\n    x6 = _mm_srli_si128(x6, 4);  \\\n    x8 = _mm_xor_si128(x8,  x6); \\\n    x6 = x8;                     \\\n    x6 = _mm_slli_si128(x6,  12);\\\n    x8 = _mm_xor_si128(x8, x6);  \\\n                                 \\\n    x7 = x8;                     \\\n    x7 =  _mm_srli_si128(x7,  4);\\\n    x9 = _mm_xor_si128(x9,  x7); \\\n    x7 = x9;                     \\\n    x7 = _mm_slli_si128(x7, 12); \\\n    x9 = _mm_xor_si128(x9, x7);  \\\n                                 \\\n    x6 = x9;                     \\\n    x6 =  _mm_srli_si128(x6, 4); \\\n    x10 = _mm_xor_si128(x10, x6);\\\n    x6 = x10;                    \\\n    x6 = _mm_slli_si128(x6,  12);\\\n    x10 = _mm_xor_si128(x10, x6);\\\n                                 \\\n    x7 = x10;                    \\\n    x7 = _mm_srli_si128(x7,  4); \\\n    x11 = _mm_xor_si128(x11, x7);\\\n    x7 = x11;                    \\\n    x7 = _mm_slli_si128(x7,  12);\\\n    x11 = _mm_xor_si128(x11, x7);\n\n// encryption + Davies-Meyer transform\nvoid shavite3_256_opt_Compress256(const unsigned char* message_block, unsigned char* chaining_value, uint64_t counter)\n{\n    __attribute__ ((aligned (16))) static const unsigned int SHAVITE_REVERSE[4] = {0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x03020100 };\n    __attribute__ ((aligned (16))) static const unsigned int SHAVITE256_XOR2[4] = {0x0, 0xFFFFFFFF, 0x0, 0x0};\n    __attribute__ ((aligned (16))) static const unsigned int SHAVITE256_XOR3[4] = {0x0, 0x0, 0xFFFFFFFF, 0x0};\n    __attribute__ ((aligned (16))) static const unsigned int SHAVITE256_XOR4[4] = {0x0, 0x0, 0x0, 0xFFFFFFFF};\n    __attribute__ ((aligned (16))) const unsigned int SHAVITE_CNTS[4] = {(unsigned int)(counter & 0xFFFFFFFFULL),(unsigned int)(counter>>32),0,0}; \n\n    __m128i x0;\n    __m128i x1;\n    __m128i x2;\n    __m128i x3;\n    __m128i x4;\n    __m128i x6;\n    __m128i x7;\n    __m128i x8;\n    __m128i x9;\n    __m128i x10;\n    __m128i x11;\n    __m128i x12;\n    __m128i x13;\n    __m128i x14;\n    __m128i x15;\n\n    // (L,R) = (xmm0,xmm1)\n    const __m128i ptxt1 = _mm_loadu_si128((const __m128i*)chaining_value);\n    const __m128i ptxt2 = _mm_loadu_si128((const __m128i*)(chaining_value+16));\n\n    x0 = ptxt1;\n    x1 = ptxt2;\n\n    x3 = _mm_loadu_si128((__m128i*)SHAVITE_CNTS);\n    x4 = _mm_loadu_si128((__m128i*)SHAVITE256_XOR2);\n    x2 = _mm_setzero_si128();\n\n    // init key schedule\n    x8 = _mm_loadu_si128((__m128i*)message_block);\n    x9 = _mm_loadu_si128((__m128i*)(((unsigned int*)message_block)+4));\n    x10 = _mm_loadu_si128((__m128i*)(((unsigned int*)message_block)+8));\n    x11 = _mm_loadu_si128((__m128i*)(((unsigned int*)message_block)+12));\n\n    // xmm8..xmm11 = rk[0..15]\n    // start key schedule\n    x12 = x8;\n    x13 = x9;\n    x14 = x10;\n    x15 = x11;\n\n    const __m128i xtemp = _mm_loadu_si128((__m128i*)SHAVITE_REVERSE);\n    x12 = _mm_shuffle_epi8(x12, xtemp);\n    x13 = _mm_shuffle_epi8(x13, xtemp);\n    x14 = _mm_shuffle_epi8(x14, xtemp);\n    x15 = _mm_shuffle_epi8(x15, xtemp);\n\n    x12 = _mm_aesenc_si128(x12, x2);\n    x13 = _mm_aesenc_si128(x13, x2);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x15 = _mm_aesenc_si128(x15, x2);\n\n    x12 = _mm_xor_si128(x12, x3);\n    x12 = _mm_xor_si128(x12, x4);\n    x4 =  _mm_loadu_si128((__m128i*)SHAVITE256_XOR3);\n    x12 = _mm_xor_si128(x12, x11);\n    x13 = _mm_xor_si128(x13, x12);\n    x14 = _mm_xor_si128(x14, x13);\n    x15 = _mm_xor_si128(x15, x14);\n   \n    // xmm12..xmm15 = rk[16..31]\n    // F3 - first round \n    x6 = x8;\n    x8 = _mm_xor_si128(x8, x1);\n    x8 = _mm_aesenc_si128(x8, x9);\n    x8 = _mm_aesenc_si128(x8, x10);\n    x8 = _mm_aesenc_si128(x8, x2);\n    x0 = _mm_xor_si128(x0, x8);\n    x8 = x6;\n\n    // F3 - second round\n    x6 = x11;\n    x11 = _mm_xor_si128(x11, x0);\n    x11 = _mm_aesenc_si128(x11, x12);\n    x11 = _mm_aesenc_si128(x11, x13);\n    x11 = _mm_aesenc_si128(x11, x2);\n    x1 = _mm_xor_si128(x1, x11);\n    x11 = x6;\n\n    // key schedule\n    SHAVITE_MIXING_256_OPT\n\n    // xmm8..xmm11 - rk[32..47]\n    // F3 - third round\n    x6 = x14;\n    x14 = _mm_xor_si128(x14, x1);\n    x14 = _mm_aesenc_si128(x14, x15);\n    x14 = _mm_aesenc_si128(x14, x8);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x0 = _mm_xor_si128(x0, x14);\n    x14 = x6;\n\n    // key schedule\n    x3 = _mm_shuffle_epi32(x3, 135);\n\n    x12 = x8;\n    x13 = x9;\n    x14 = x10;\n    x15 = x11;\n    x12 = _mm_shuffle_epi8(x12, xtemp);\n    x13 = _mm_shuffle_epi8(x13, xtemp);\n    x14 = _mm_shuffle_epi8(x14, xtemp);\n    x15 = _mm_shuffle_epi8(x15, xtemp);\n    x12 = _mm_aesenc_si128(x12, x2);\n    x13 = _mm_aesenc_si128(x13, x2);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x15 = _mm_aesenc_si128(x15, x2);\n\n    x12 = _mm_xor_si128(x12, x11);\n    x14 = _mm_xor_si128(x14, x3);\n    x14 = _mm_xor_si128(x14, x4);\n    x4 = _mm_loadu_si128((__m128i*)SHAVITE256_XOR4);\n    x13 = _mm_xor_si128(x13, x12);\n    x14 = _mm_xor_si128(x14, x13);\n    x15 = _mm_xor_si128(x15, x14);\n\n    // xmm12..xmm15 - rk[48..63]\n\n    // F3 - fourth round\n    x6 = x9;\n    x9 = _mm_xor_si128(x9, x0);\n    x9 = _mm_aesenc_si128(x9, x10);\n    x9 = _mm_aesenc_si128(x9, x11);\n    x9 = _mm_aesenc_si128(x9, x2);\n    x1 = _mm_xor_si128(x1, x9);\n    x9 = x6;\n\n    // key schedule\n    SHAVITE_MIXING_256_OPT\n    // xmm8..xmm11 = rk[64..79]\n    // F3  - fifth round\n    x6 = x12;\n    x12 = _mm_xor_si128(x12, x1);\n    x12 = _mm_aesenc_si128(x12, x13);\n    x12 = _mm_aesenc_si128(x12, x14);\n    x12 = _mm_aesenc_si128(x12, x2);\n    x0 = _mm_xor_si128(x0, x12);\n    x12 = x6;\n\n    // F3 - sixth round\n    x6 = x15;\n    x15 = _mm_xor_si128(x15, x0);\n    x15 = _mm_aesenc_si128(x15, x8);\n    x15 = _mm_aesenc_si128(x15, x9);\n    x15 = _mm_aesenc_si128(x15, x2);\n    x1 = _mm_xor_si128(x1, x15);\n    x15 = x6;\n\n    // key schedule\n    x3 = _mm_shuffle_epi32(x3, 147);\n\n    x12 = x8;\n    x13 = x9;\n    x14 = x10;\n    x15 = x11;\n    x12 = _mm_shuffle_epi8(x12, xtemp);\n    x13 = _mm_shuffle_epi8(x13, xtemp);\n    x14 = _mm_shuffle_epi8(x14, xtemp);\n    x15 = _mm_shuffle_epi8(x15, xtemp);\n    x12 = _mm_aesenc_si128(x12, x2);\n    x13 = _mm_aesenc_si128(x13, x2);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x15 = _mm_aesenc_si128(x15, x2);\n    x12 = _mm_xor_si128(x12, x11);\n    x13 = _mm_xor_si128(x13, x3);\n    x13 = _mm_xor_si128(x13, x4);\n    x13 = _mm_xor_si128(x13, x12);\n    x14 = _mm_xor_si128(x14, x13);\n    x15 = _mm_xor_si128(x15, x14);\n\n    // xmm12..xmm15 = rk[80..95]\n    // F3 - seventh round\n    x6 = x10;\n    x10 = _mm_xor_si128(x10, x1);\n    x10 = _mm_aesenc_si128(x10, x11);\n    x10 = _mm_aesenc_si128(x10, x12);\n    x10 = _mm_aesenc_si128(x10, x2);\n    x0 = _mm_xor_si128(x0, x10);\n    x10 = x6;\n\n    // key schedule\n    SHAVITE_MIXING_256_OPT\n\n    // xmm8..xmm11 = rk[96..111]\n    // F3 - eigth round\n    x6 = x13;\n    x13 = _mm_xor_si128(x13, x0);\n    x13 = _mm_aesenc_si128(x13, x14);\n    x13 = _mm_aesenc_si128(x13, x15);\n    x13 = _mm_aesenc_si128(x13, x2);\n    x1 = _mm_xor_si128(x1, x13);\n    x13 = x6;\n\n\n    // key schedule\n    x3 = _mm_shuffle_epi32(x3, 135);\n\n    x12 = x8;\n    x13 = x9;\n    x14 = x10;\n    x15 = x11;\n    x12 = _mm_shuffle_epi8(x12, xtemp);\n    x13 = _mm_shuffle_epi8(x13, xtemp);\n    x14 = _mm_shuffle_epi8(x14, xtemp);\n    x15 = _mm_shuffle_epi8(x15, xtemp);\n    x12 = _mm_aesenc_si128(x12, x2);\n    x13 = _mm_aesenc_si128(x13, x2);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x15 = _mm_aesenc_si128(x15, x2);\n    x12 = _mm_xor_si128(x12, x11);\n    x15 = _mm_xor_si128(x15, x3);\n    x15 = _mm_xor_si128(x15, x4);\n    x13 = _mm_xor_si128(x13, x12);\n    x14 = _mm_xor_si128(x14, x13);\n    x15 = _mm_xor_si128(x15, x14);\n\n    // xmm12..xmm15 = rk[112..127]\n    // F3 - ninth round\n    x6 = x8;\n    x8 = _mm_xor_si128(x8, x1);\n    x8 = _mm_aesenc_si128(x8, x9);\n    x8 = _mm_aesenc_si128(x8, x10);\n    x8 = _mm_aesenc_si128(x8, x2);\n    x0 = _mm_xor_si128(x0, x8);\n    x8 = x6;\n    // F3 - tenth round\n    x6 = x11;\n    x11 = _mm_xor_si128(x11, x0);\n    x11 = _mm_aesenc_si128(x11, x12);\n    x11 = _mm_aesenc_si128(x11, x13);\n    x11 = _mm_aesenc_si128(x11, x2);\n    x1 = _mm_xor_si128(x1, x11);\n    x11 = x6;\n\n    // key schedule\n    SHAVITE_MIXING_256_OPT\n\n    // xmm8..xmm11 = rk[128..143]\n    // F3 - eleventh round\n    x6 = x14;\n    x14 = _mm_xor_si128(x14, x1);\n    x14 = _mm_aesenc_si128(x14, x15);\n    x14 = _mm_aesenc_si128(x14, x8);\n    x14 = _mm_aesenc_si128(x14, x2);\n    x0 = _mm_xor_si128(x0, x14);\n    x14 = x6;\n\n    // F3 - twelfth round\n    x6 = x9;\n    x9 = _mm_xor_si128(x9, x0);\n    x9 = _mm_aesenc_si128(x9, x10);\n    x9 = _mm_aesenc_si128(x9, x11);\n    x9 = _mm_aesenc_si128(x9, x2);\n    x1 = _mm_xor_si128(x1, x9);\n    x9 = x6;\n\n\n    // feedforward\n    x0 = _mm_xor_si128(x0, ptxt1);\n    x1 = _mm_xor_si128(x1, ptxt2);\n    _mm_storeu_si128((__m128i *)chaining_value, x0);\n    _mm_storeu_si128((__m128i *)(chaining_value + 16), x1);\n\n    return;\n}\n\n#define U8TO16_LITTLE(c)  (((uint16_t)T8(*((uint8_t*)(c)))) | ((uint16_t)T8(*(((uint8_t*)(c)) + 1)) << 8))\n\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U16TO8_LITTLE(c, v) do { \\\n    uint16_t tmp_portable_h_x = (v); \\\n    uint8_t *tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8); \\\n} while (0)\n\n#define U8TO32_LITTLE(c)  (((uint32_t)T8(*((uint8_t*)(c)))) | ((uint32_t)T8(*(((uint8_t*)(c)) + 1)) << 8) | ((uint32_t)T8(*(((uint8_t*)(c)) + 2)) << 16) | ((uint32_t)T8(*(((uint8_t*)(c)) + 3)) << 24))\n\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U32TO8_LITTLE(c, v) do { \\\n    uint32_t tmp_portable_h_x = (v); \\\n    uint8_t *tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8); \\\n    tmp_portable_h_d[2] = T8(tmp_portable_h_x >> 16); \\\n    tmp_portable_h_d[3] = T8(tmp_portable_h_x >> 24); \\\n} while (0)\n\n// Make sure that the local variable names do not collide with variables of the calling code (i.e., those used in c, v)\n#define U64TO8_LITTLE(c, v)    do { \\\n    uint64_t tmp_portable_h_x = (v); \\\n    uint8_t *tmp_portable_h_d = (c); \\\n    tmp_portable_h_d[0] = T8(tmp_portable_h_x); \\\n    tmp_portable_h_d[1] = T8(tmp_portable_h_x >> 8);  \\\n    tmp_portable_h_d[2] = T8(tmp_portable_h_x >> 16); \\\n    tmp_portable_h_d[3] = T8(tmp_portable_h_x >> 24); \\\n    tmp_portable_h_d[4] = T8(tmp_portable_h_x >> 32); \\\n    tmp_portable_h_d[5] = T8(tmp_portable_h_x >> 40); \\\n    tmp_portable_h_d[6] = T8(tmp_portable_h_x >> 48); \\\n    tmp_portable_h_d[7] = T8(tmp_portable_h_x >> 56); \\\n} while (0)\n\n// Initialization of the internal state of the hash function\nbool shavite3_256_opt_Init ( shavite3_256_opt_hashState* state)\n{\n    // Initialization of the counter of number of bits that were hashed so far\n    state->bitcount = 0;\n\n    // Store the requested digest size\n    state->DigestSize = 256;\n\n    // Initialize the message block to empty\n    memset(state->buffer,0,64);\n\n    // Set the input to the compression function to all zero\n    memset(state->chaining_value,0,32); \n\n    // Compute MIV_{256}\n    shavite3_256_opt_Compress256(state->buffer,state->chaining_value,0x0ULL);\n\n    // Set the message block to the size of the requested digest size\n    U16TO8_LITTLE(state->buffer,256);\n\n    // Compute IV_m\n    shavite3_256_opt_Compress256(state->buffer,state->chaining_value,0x0ULL);\n\n    // Set the block size to be 512 bits (as required for C_{256})\n    state->BlockSize=512; \n\n    // Set the message block to zero\n    memset(state->buffer,0,64);\n    return true;\n}\n\n\n\n// Compressing the input data, and updating the internal state\nbool shavite3_256_opt_Update ( shavite3_256_opt_hashState* state, const unsigned char* data, uint64_t dataLenBytes)\n{\n    // p is a pointer to the current location inside data that we need to process (i.e., the first byte of the data which was not used as an input to the compression function\n    uint8_t* p = (uint8_t*)data;\n\n    // len is the size of the data that was not process yet in bytes\n    int len = dataLenBytes;\n\n    // BlockSizeB is the size of the message block of the compression function\n    int BlockSizeB = (state->BlockSize/8);\n\n    // bufcnt stores the number of bytes that are were \"sent\" to the compression function, but were not yet processed, as a full block has not been obtained\n    int bufcnt= (state->bitcount>>3)%BlockSizeB;\n\n    // local_bitcount contains the number of bits actually hashed so far\n    uint64_t SHAVITE_CNT;\n\n    // load the number of bits hashed so far into SHAVITE_CNT\n    SHAVITE_CNT=state->bitcount;\n\n    // mark that we processed more bits\n    state->bitcount += dataLenBytes*8;\n\n    // Check if we have enough data to call the compression function\n    // If not, just copy the input to the buffer of the message block\n    if (bufcnt + len < BlockSizeB)\n    {\n        memcpy(&state->buffer[bufcnt], p, len);\n        return true;\n    }\n\n    // There is enough data to start calling the compression function.\n    // We first check whether there is data remaining from previous calls\n    if (bufcnt>0)\n    {\n        // Copy from the input the required number of bytes to fill a block\n        memcpy(&state->buffer[bufcnt], p, BlockSizeB-bufcnt);\n\n        // Update the location of the first byte that was not processed\n        p += BlockSizeB-bufcnt;\n\n        // Update the remaining number of bytes to process\n        len -= BlockSizeB-bufcnt;\n\n        // Update the number of bits hashed so far (locally)\n        SHAVITE_CNT+=8*(BlockSizeB-bufcnt);\n\n        // Call the compression function to process the current block\n        shavite3_256_opt_Compress256(state->buffer, state->chaining_value, SHAVITE_CNT);\n    }\n\n\n    // At this point, the only remaining data is from the message block call the compression function as many times as possible, and store the remaining bytes in the buffer\n    // Each step of the loop compresses BlockSizeB bytes\n    for( ; len>=BlockSizeB; len-=BlockSizeB, p+=BlockSizeB)\n    {\n        // Update the number of bits hashed so far (locally)\n        SHAVITE_CNT+=8*BlockSizeB;\n\n        // Call the compression function to process the current block\n        shavite3_256_opt_Compress256(p, state->chaining_value, SHAVITE_CNT);\n    }\n\n    // If there are still unprocessed bytes, store them locally and wait for more\n    if (len>0)\n    {\n        memcpy(state->buffer, p, len);\n    }\n    return true;\n}\n\n\n// Performing the padding scheme, and dealing with any remaining bits\nbool shavite3_256_opt_Final ( shavite3_256_opt_hashState *state, unsigned char *hashval)\n{\n    // Stores inputs (message blocks) to the compression function\n    uint8_t block[64];\n\n    // Stores results (chaining value) of the compression function\n    uint8_t result[32];\n\n    // BlockSizeB is the size of the message block of the compression function\n    int BlockSizeB = (state->BlockSize/8);\n\n    // bufcnt stores the number of bytes that are were \"sent\" to the compression function, but were not yet processed, as a full block has not been obtained\n    int bufcnt= ((uint32_t)state->bitcount>>3)%BlockSizeB;\n\n    int i;\n    // Copy the current chaining value into result (as a temporary step)\n    memcpy(result, state->chaining_value, 32);\n\n\n    // Initialize block as the message block to compress with the bytes that were not processed yet\n    memset(block, 0, BlockSizeB);\n    memcpy(block, state->buffer, bufcnt);\n\n    // Pad the buffer with the byte which contains the fraction of bytes from and a bit equal to 1\n   block[bufcnt] = (state->partial_byte & ~((0x80 >> (state->bitcount&7))-1)) | (0x80 >> (state->bitcount&7));\n\n    // Compress the last block (according to the digest size)\n    // An additional message block is required if there are less than 10 more bytes for message length and digest length encoding\n    if (bufcnt>=BlockSizeB-10)\n    {\n        // Compress the current block\n        shavite3_256_opt_Compress256(block,result,state->bitcount);\n\n        // Generate the full padding block\n        memset(block, 0, BlockSizeB);\n        U64TO8_LITTLE(block+BlockSizeB-10, state->bitcount);\n        U16TO8_LITTLE(block+BlockSizeB-2, state->DigestSize);\n\n        // Compress the full padding block\n        shavite3_256_opt_Compress256(block,result,0x0UL);\n    }\n    else\n    {\n        // Pad the number of bits hashed so far and the digest size to the last message block and compress it\n        U64TO8_LITTLE(block+BlockSizeB-10, state->bitcount);\n        U16TO8_LITTLE(block+BlockSizeB-2, state->DigestSize);\n        if ((state->bitcount&(state->BlockSize-1))==0)\n        {\n            shavite3_256_opt_Compress256(block,result, 0ULL);\n        }\n        else\n        {\n            shavite3_256_opt_Compress256(block,result, state->bitcount);\n        }\n    }\n    \n    // Copy the result into the supplied array of bytes.\n    for (i=0;i<(state->DigestSize+7)/8;i++)\n    {\n        hashval[i]=result[i];\n    }\n\n    // Treat cases where the digest size is not a multiple of a byte\n    if ((state->DigestSize)&7)\n    {\n        hashval[(state->DigestSize+7)/8] &= (0xFF<<(8-((state->DigestSize)%8)))&0xFF;\n    }\n    return true;\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/shavite3_256/shavite3_256_opt.h",
    "content": "// File originates from the supercop project\n// Authors: Eli Biham and Orr Dunkelman\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SHAVITE3_256_OPT_H\n#define SHAVITE3_256_OPT_H\n#include <stdint.h>\n\nstruct shavite3_256_opt_hashState \n{\n   uint64_t bitcount;                // The number of bits compressed so far\n   uint8_t chaining_value[64];       // An array containing the chaining value\n   uint8_t buffer[128];              // A buffer storing bytes until they are compressed\n   uint8_t partial_byte=0;           // A byte to store a fraction of a byte in case the input is not fully byte alligned\n   int DigestSize;                   // The requested digest size\n   int BlockSize;                    // The message block size\n};\n\nextern bool (*selected_shavite3_256_opt_Init)(shavite3_256_opt_hashState* state);\nextern bool (*selected_shavite3_256_opt_Update)(shavite3_256_opt_hashState* state, const unsigned char* data, uint64_t dataLenBytes);\nextern bool (*selected_shavite3_256_opt_Final)(shavite3_256_opt_hashState* state, unsigned char* hashval);\n#endif\n\n\n#ifndef SHAVITE3_256_OPT_IMPL\n#include \"opt/shavite3_256_opt_sse3.h\"\n#include \"opt/shavite3_256_opt_sse3_aes.h\"\n#include \"opt/shavite3_256_opt_sse4.h\"\n#include \"opt/shavite3_256_opt_sse4_aes.h\"\n#include \"opt/shavite3_256_opt_avx.h\"\n#include \"opt/shavite3_256_opt_avx_aes.h\"\n#include \"opt/shavite3_256_opt_avx2.h\"\n#include \"opt/shavite3_256_opt_avx2_aes.h\"\n#include \"opt/shavite3_256_opt_avx512f.h\"\n#include \"opt/shavite3_256_opt_avx512f_aes.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a53.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a53_aes.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a57.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a57_aes.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a72.h\"\n#include \"opt/shavite3_256_opt_arm_cortex_a72_aes.h\"\n#include \"opt/shavite3_256_opt_arm_thunderx_aes.h\"\n#else\n#include \"compat.h\"\n#include <compat/arch.h>\n#include <compat/sse.h>\n\n// Initialization of the internal state of the hash function\nbool shavite3_256_opt_Init(shavite3_256_opt_hashState* state);\n\n// Compressing the input data, and updating the internal state\nbool shavite3_256_opt_Update(shavite3_256_opt_hashState* state, const unsigned char* data, uint64_t dataLenBytes);\n\n// Performing the padding scheme, and dealing with any remaining bits\nbool shavite3_256_opt_Final(shavite3_256_opt_hashState* state, unsigned char* hashval);\n#endif\n"
  },
  {
    "path": "src/crypto/hash/sigma/sigma.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"sigma.h\"\n\n#include <compat/arch.h>\n#include \"util.h\"\n#include \"primitives/block.h\"\n\n#include <cryptopp/config.h>\n#include <cryptopp/aes.h>\n#include <cryptopp/modes.h>\n\n#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()\n\n#include <stddef.h>\n#include <limits.h>\n#include <stdlib.h>\n\n#include <boost/scope_exit.hpp>\n#include <thread>\n\n#ifdef __APPLE__\n#include <TargetConditionals.h>\n#endif\n\nsigma_settings defaultSigmaSettings;\n\ninline void sigmaRandomFastHash(uint64_t nPseudoRandomAlg, uint8_t* data1, uint64_t data1Size, uint8_t* data2, uint64_t data2Size, uint8_t* data3, uint64_t data3Size, uint256& outHash)\n{\n    switch (nPseudoRandomAlg)\n    {\n        case 0:\n        {\n            //fixme: (SIGMA) - We can obtain a slight speedup by removing this if statement and normalising to always using a pointer for everything\n            if (selected_echo256_opt_Init)\n            {\n                echo256_opt_hashState ctx_echo;\n                selected_echo256_opt_Init(&ctx_echo);\n                selected_echo256_opt_Update(&ctx_echo, data1, data1Size);\n                selected_echo256_opt_Update(&ctx_echo, data2, data2Size);\n                selected_echo256_opt_Update(&ctx_echo, data3, data3Size);\n                selected_echo256_opt_Final(&ctx_echo, outHash.begin());\n            }\n            else\n            {\n                sph_echo256_context ctx_echo;\n                sph_echo256_init(&ctx_echo);\n                sph_echo256(&ctx_echo, data1, data1Size);\n                sph_echo256(&ctx_echo, data2, data2Size);\n                sph_echo256(&ctx_echo, data3, data3Size);\n                sph_echo256_close(&ctx_echo, outHash.begin());\n            }\n            break;\n        }\n        case 1:\n        {\n            //fixme: (SIGMA) - We can obtain a slight speedup by removing this if statement and normalising to always using a pointer for everything\n            if (selected_shavite3_256_opt_Init)\n            {\n                shavite3_256_opt_hashState ctx_shavite;\n                selected_shavite3_256_opt_Init (&ctx_shavite);\n                selected_shavite3_256_opt_Update (&ctx_shavite, data1, data1Size);\n                selected_shavite3_256_opt_Update (&ctx_shavite, data2, data2Size);\n                selected_shavite3_256_opt_Update (&ctx_shavite, data3, data3Size);\n                selected_shavite3_256_opt_Final (&ctx_shavite, outHash.begin());\n            }\n            else\n            {\n                shavite3_ref_hashState ctx_shavite;\n                shavite3_ref_Init(&ctx_shavite);\n                shavite3_ref_Update(&ctx_shavite, data1, data1Size);\n                shavite3_ref_Update(&ctx_shavite, data2, data2Size);\n                shavite3_ref_Update(&ctx_shavite, data3, data3Size);\n                shavite3_ref_Final(&ctx_shavite, (uint8_t*)outHash.begin());\n            }\n            break;\n        }\n        default:\n            assert(0);\n    }\n}\n\ninline void sigmaRandomFastHashRef(uint64_t nPseudoRandomAlg, uint8_t* data1, uint64_t data1Size, uint8_t* data2, uint64_t data2Size, uint8_t* data3, uint64_t data3Size, uint256& outHash)\n{\n    {\n        switch (nPseudoRandomAlg)\n        {\n            case 0:\n            {\n                sph_echo256_context ctx_echo;\n                sph_echo256_init(&ctx_echo);\n                sph_echo256(&ctx_echo, data1, data1Size);\n                sph_echo256(&ctx_echo, data2, data2Size);\n                sph_echo256(&ctx_echo, data3, data3Size);\n                sph_echo256_close(&ctx_echo, outHash.begin());\n                break;\n            }\n            case 1:\n            {\n                shavite3_ref_hashState ctx_shavite;\n                shavite3_ref_Init(&ctx_shavite);\n                shavite3_ref_Update(&ctx_shavite, data1, data1Size);\n                shavite3_ref_Update(&ctx_shavite, data2, data2Size);\n                shavite3_ref_Update(&ctx_shavite, data3, data3Size);\n                shavite3_ref_Final(&ctx_shavite, (uint8_t*)outHash.begin());\n                break;\n            }\n            default:\n                assert(0);\n        }\n    }\n}\n\nuint64_t gSelShavite=0;\nuint64_t gSelEcho=0;\nuint64_t gSelArgon=0;\n\nuint64_t nNumShaviteTrials=100;\nuint64_t nNumEchoTrials=100;\nuint64_t nNumArgonTrials=10;\n#define SELECT_OPTIMISED_SHAVITE(CPU, IDX) \\\n{\\\n    uint64_t nStart = GetTimeMicros();\\\n    shavite3_256_opt_##CPU##_Init(&ctx_shavite);\\\n    for (uint64_t i=0;i<nNumShaviteTrials;++i)\\\n    {\\\n        shavite3_256_opt_##CPU##_Update(&ctx_shavite, (uint8_t*)&data[0], data.size());\\\n    }\\\n    shavite3_256_opt_##CPU##_Final(&ctx_shavite, (uint8_t*)&outHash[0]);\\\n    uint64_t nTime = GetTimeMicros() - nStart;\\\n    if (nTime < nBestTimeShavite)\\\n    {\\\n        selected_shavite3_256_opt_Init   = shavite3_256_opt_##CPU##_Init;\\\n        selected_shavite3_256_opt_Update = shavite3_256_opt_##CPU##_Update;\\\n        selected_shavite3_256_opt_Final  = shavite3_256_opt_##CPU##_Final;\\\n        nBestTimeShavite=nTime;\\\n        gSelShavite=IDX;\\\n    }\\\n}\n#define SELECT_OPTIMISED_ECHO(CPU, IDX) \\\n{\\\n    uint64_t nStart = GetTimeMicros();\\\n    echo256_opt_##CPU##_Init(&ctx_echo);\\\n    for (uint64_t i=0;i<nNumEchoTrials;++i)\\\n    {\\\n        echo256_opt_##CPU##_Update(&ctx_echo, (uint8_t*)&data[0], data.size());\\\n    }\\\n    echo256_opt_##CPU##_Final(&ctx_echo, (uint8_t*)&outHash[0]);\\\n    uint64_t nTime = GetTimeMicros() - nStart;\\\n    if (nTime < nBestTimeEcho)\\\n    {\\\n        selected_echo256_opt_Init        = echo256_opt_##CPU##_Init;\\\n        selected_echo256_opt_Update      = echo256_opt_##CPU##_Update;\\\n        selected_echo256_opt_Final       = echo256_opt_##CPU##_Final;\\\n        selected_echo256_opt_UpdateFinal = echo256_opt_##CPU##_UpdateFinal;\\\n        nBestTimeEcho=nTime;\\\n        gSelEcho=IDX;\\\n    }\\\n}\n#define SELECT_OPTIMISED_ARGON(CPU, IDX) \\\n{\\\n    uint8_t argonScratch[1024];\\\n    argon2_echo_context context;\\\n    context.t_cost = 5;\\\n    context.m_cost = 1;\\\n    context.allocated_memory = argonScratch;\\\n    context.pwd = (uint8_t*)&data[0];\\\n    context.pwdlen = data.size();\\\n    context.lanes = 4;\\\n    context.threads = 1;\\\n    uint64_t nStart = GetTimeMicros();\\\n    for (uint64_t i=0;i<nNumArgonTrials;++i)\\\n    {\\\n        argon2_echo_ctx_##CPU(&context, true);\\\n    }\\\n    uint64_t nTime = GetTimeMicros() - nStart;\\\n    if (nTime < nBestTimeArgon)\\\n    {\\\n        selected_argon2_echo_hash = argon2_echo_ctx_##CPU;\\\n        nBestTimeArgon=nTime;\\\n        gSelArgon=IDX;\\\n    }\\\n}\n#define FORCE_SELECT_OPTIMISED_SHAVITE(CPU, IDX) \\\n{\\\n    selected_shavite3_256_opt_Init   = shavite3_256_opt_##CPU##_Init;\\\n    selected_shavite3_256_opt_Update = shavite3_256_opt_##CPU##_Update;\\\n    selected_shavite3_256_opt_Final  = shavite3_256_opt_##CPU##_Final;\\\n    gSelShavite=IDX;\\\n}\n#define FORCE_SELECT_OPTIMISED_ECHO(CPU, IDX) \\\n{\\\n    selected_echo256_opt_Init        = echo256_opt_##CPU##_Init;\\\n    selected_echo256_opt_Update      = echo256_opt_##CPU##_Update;\\\n    selected_echo256_opt_Final       = echo256_opt_##CPU##_Final;\\\n    selected_echo256_opt_UpdateFinal = echo256_opt_##CPU##_UpdateFinal;\\\n    gSelEcho=IDX;\\\n}\n#define FORCE_SELECT_OPTIMISED_ARGON(CPU, IDX) \\\n{\\\n    selected_argon2_echo_hash = argon2_echo_ctx_##CPU;\\\n    gSelArgon=IDX;\\\n}\n\n#ifdef ARCH_CPU_X86_FAMILY\nstd::string selectedAlgorithmName(uint64_t nSel)\n{\n    switch (nSel)\n    {\n        case 0:\n            return \"reference implementation\";\n        case 1:\n            return \"avx512f-aes\";\n        case 2:\n            return \"avx2-aes\";\n        case 3:\n            return \"avx-aes\";\n        case 4:\n            return \"sse4-aes\";\n        case 5:\n            return \"sse3-aes\";\n        case 6:\n            return \"sse2-aes\";\n        case 7:\n            return \"avx512f\";\n        case 8:\n            return \"avx2\";\n        case 9:\n            return \"avx\";\n        case 10:\n            return \"sse4\";\n        case 11:\n            return \"sse3\";\n        case 12:\n            return \"sse2\";\n        case 9999:\n            return \"hybrid implementation\";\n    }\n    return \"\";\n}\n#elif defined(ARCH_CPU_ARM_FAMILY)\nstd::string selectedAlgorithmName(uint64_t nSel)\n{\n    switch (nSel)\n    {\n         case 0:\n            return \"reference implementation (no NEON support)\";\n        case 1:\n            return \"Cortex-A53 optimised NEON support (no hardware AES)\";\n        case 2:\n            return \"Cortex-A57 optimised NEON support (no hardware AES)\";\n        case 3:\n            return \"Cortex-A72 optimised NEON support (no hardware AES)\";\n        case 4:\n            return \"Cortex-A53 optimised NEON+AES support\";\n        case 5:\n            return \"Cortex-A57 optimised NEON+AES support\";\n        case 6:\n            return \"Cortex-A72 optimised NEON+AES support\";\n        case 7:\n            return \"Thunderx optimised NEON+AES support\";\n        case 9999:\n            return \"hybrid implementation\";\n    }\n    return \"\";\n}\n#ifndef __APPLE__\n#include <sys/auxv.h>\n#endif\n#else\nstd::string selectedAlgorithmName(uint64_t nSel)\n{\n    //fixme: (SIGMA) Implement for riscv\n    return \"\";\n}\n#endif\n\nvoid LogSelection(uint64_t nSel, std::string sAlgoName)\n{\n    std::string sAlgoImplementation = selectedAlgorithmName(nSel);\n    LogPrintf(\"[%s] Selected %s\\n\", sAlgoName, sAlgoImplementation);\n}\n\nvoid selectOptimisedImplementations()\n{\n    #ifndef ARCH_CPU_X86_FAMILY\n    std::string data = \"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\";\n    std::vector<unsigned char> outHash(32);\n    shavite3_256_opt_hashState ctx_shavite;\n    echo256_opt_hashState ctx_echo;\n\n    uint64_t nBestTimeShavite = std::numeric_limits<uint64_t>::max();\n    uint64_t nBestTimeEcho = std::numeric_limits<uint64_t>::max();\n    uint64_t nBestTimeArgon = std::numeric_limits<uint64_t>::max();\n\n    {\n        uint64_t nStart = GetTimeMicros();\n        shavite3_ref_hashState ctx_shavite_ref;\n        shavite3_ref_Init(&ctx_shavite_ref);\n        for (uint64_t i=0;i<nNumShaviteTrials;++i)\n        {\n            shavite3_ref_Update(&ctx_shavite_ref, (uint8_t*)&data[0], data.size());\n        }\n        shavite3_ref_Final(&ctx_shavite_ref, (uint8_t*)&outHash[0]);\n        nBestTimeShavite = GetTimeMicros() - nStart;\n    }\n    {\n        uint64_t nStart = GetTimeMicros();\n        sph_echo256_context ctx_echo_ref;\n        sph_echo256_init(&ctx_echo_ref);\n        for (uint64_t i=0;i<nNumEchoTrials;++i)\n        {\n            sph_echo256(&ctx_echo_ref, (uint8_t*)&data[0], data.size());\n        }\n        sph_echo256_close(&ctx_echo_ref, (uint8_t*)&outHash[0]);\n        nBestTimeEcho = GetTimeMicros() - nStart;\n    }\n    {\n        uint8_t argonScratch[1024];\n        argon2_echo_context context;\n        context.t_cost = 5;\n        context.m_cost = 1;\n        context.allocated_memory = argonScratch;\n        context.pwd = (uint8_t*)&data[0];\n        context.pwdlen = data.size();\n        context.lanes = 4;\n        context.threads = 1;\n\n        uint64_t nStart = GetTimeMicros();\n        for (uint64_t i=0;i<nNumArgonTrials;++i)\n        {\n            argon2_echo_ctx_ref(&context, true);\n        }\n        nBestTimeArgon = GetTimeMicros() - nStart;\n    }\n    #endif\n\n    #ifdef ARCH_CPU_X86_FAMILY\n    {\n        std::string forceSigmaAlgo = GetArg(\"-sigmaalgo\", \"\");\n        #define SELECT_ALGO(x) ((__builtin_cpu_supports(x) && forceSigmaAlgo.empty()) || (forceSigmaAlgo==x))\n        #if defined(COMPILER_HAS_AES)\n        if (__builtin_cpu_supports(\"aes\") && (forceSigmaAlgo.empty() || boost::algorithm::ends_with(forceSigmaAlgo, \"aes\")))\n        {\n            if (!forceSigmaAlgo.empty())\n            {\n                forceSigmaAlgo.erase(forceSigmaAlgo.length()-3);\n            }\n            #if defined(COMPILER_HAS_AVX512F)\n            if (SELECT_ALGO(\"avx512f\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx512f_aes, 1);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx512f_aes, 1);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx512f_aes, 1);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_AVX2)\n            if (SELECT_ALGO(\"avx2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx2_aes, 2);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx2_aes, 2);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx2_aes, 2);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_AVX)\n            if (SELECT_ALGO(\"avx\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx_aes, 3);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx_aes, 3);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx_aes, 3);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE4)\n            if (SELECT_ALGO(\"sse4.2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse4_aes, 4);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse4_aes, 4);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse4_aes, 4);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE3)\n            if (SELECT_ALGO(\"ssse3\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse3_aes, 5);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse3_aes, 5);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse3_aes, 5);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE2)\n            #if 0\n            //fixme: (SIGMA)\n            if (SELECT_ALGO(\"sse2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse2_aes, 6);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse2_aes, 6);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse2_aes, 6);\n                goto logselection;\n            }\n            #endif\n            #endif\n        }\n        else\n        #endif\n        {\n            #if defined(COMPILER_HAS_AVX512F)\n            if (SELECT_ALGO(\"avx512f\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx512f, 7);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx512f, 7);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx512f, 7);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_AVX2)\n            if (SELECT_ALGO(\"avx2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx2, 8);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx2, 8);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx2, 8);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_AVX)\n            if (SELECT_ALGO(\"avx\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(avx, 9);\n                FORCE_SELECT_OPTIMISED_ECHO   (avx, 9);\n                FORCE_SELECT_OPTIMISED_ARGON  (avx, 9);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE4)\n            if (SELECT_ALGO(\"sse4.2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse4, 10);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse4, 10);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse4, 10);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE3)\n            if (SELECT_ALGO(\"ssse3\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse3, 11);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse3, 11);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse3, 11);\n                goto logselection;\n            }\n            #endif\n            #if defined(COMPILER_HAS_SSE2)\n            #if 0\n            //fixme: (SIGMA)\n            else if (SELECT_ALGO(\"sse2\"))\n            {\n                FORCE_SELECT_OPTIMISED_SHAVITE(sse2, 12);\n                FORCE_SELECT_OPTIMISED_ECHO   (sse2, 12);\n                FORCE_SELECT_OPTIMISED_ARGON  (sse2, 12);\n                goto logselection;\n            }\n            #endif\n            #endif\n        }\n    }\n    #elif defined (ARCH_CPU_ARM_FAMILY)\n    {\n        #if defined(__APPLE__) && TARGET_OS_IPHONE == 1\n        // All iOS hardware running iOS 5 or later supports Neon\n        bool haveAES=true;\n        #else\n        bool haveAES=false;\n        #if defined HWCAP_AES\n        long hwcaps2 = getauxval(AT_HWCAP);\n        if(hwcaps2 & HWCAP_AES)\n        {\n            haveAES=true;\n        }\n        #elif defined HWCAP2_AES\n        long hwcaps2 = getauxval(AT_HWCAP2);\n        if(hwcaps2 & HWCAP2_AES)\n        {\n            haveAES=true;\n        }\n        #endif\n        #endif\n        #ifdef COMPILER_HAS_CORTEX53\n        SELECT_OPTIMISED_SHAVITE(arm_cortex_a53, 1);\n        SELECT_OPTIMISED_ECHO(arm_cortex_a53, 1);\n        SELECT_OPTIMISED_ARGON(arm_cortex_a53, 1);\n        #endif\n        #ifdef COMPILER_HAS_CORTEX57\n        SELECT_OPTIMISED_SHAVITE(arm_cortex_a57, 2);\n        SELECT_OPTIMISED_ECHO(arm_cortex_a57, 2);\n        SELECT_OPTIMISED_ARGON(arm_cortex_a57, 2);\n        #endif\n        #ifdef COMPILER_HAS_CORTEX72\n        SELECT_OPTIMISED_SHAVITE(arm_cortex_a72, 3);\n        SELECT_OPTIMISED_ECHO(arm_cortex_a72, 3);\n        SELECT_OPTIMISED_ARGON(arm_cortex_a72, 3);\n        #endif\n        if (haveAES)\n        {\n            #ifdef COMPILER_HAS_CORTEX53_AES\n            SELECT_OPTIMISED_SHAVITE(arm_cortex_a53_aes, 4);\n            SELECT_OPTIMISED_ECHO(arm_cortex_a53_aes, 4);\n            SELECT_OPTIMISED_ARGON(arm_cortex_a53_aes, 4);\n            #endif\n            #ifdef COMPILER_HAS_CORTEX57_AES\n            SELECT_OPTIMISED_SHAVITE(arm_cortex_a57_aes, 5);\n            SELECT_OPTIMISED_ECHO(arm_cortex_a57_aes, 5);\n            SELECT_OPTIMISED_ARGON(arm_cortex_a57_aes, 5);\n            #endif\n            #ifdef COMPILER_HAS_CORTEX72_AES\n            SELECT_OPTIMISED_SHAVITE(arm_cortex_a72_aes, 6);\n            SELECT_OPTIMISED_ECHO(arm_cortex_a72_aes, 6);\n            SELECT_OPTIMISED_ARGON(arm_cortex_a72_aes, 6);\n            #endif\n            #ifdef COMPILER_HAS_THUNDERX_AES\n            SELECT_OPTIMISED_SHAVITE(arm_thunderx_aes, 7);\n            SELECT_OPTIMISED_ECHO(arm_thunderx_aes, 7);\n            SELECT_OPTIMISED_ARGON(arm_thunderx_aes, 7);\n            #endif\n        }\n    }\n\n    // Finally (only after we have fastest echo implementation) give the hybrid argon_echo a go\n    // Just in case it happens to be faster.\n    if (selected_echo256_opt_Init && selected_shavite3_256_opt_Init)\n    {\n        SELECT_OPTIMISED_ARGON(hybrid, 9999);\n    }\n    #endif\n\nlogselection:\n    LogSelection(gSelShavite, \"shavite\");\n    LogSelection(gSelEcho, \"echo\");\n    LogSelection(gSelArgon, \"argon\");\n}\n\nvoid normaliseBufferSize(uint64_t& nBufferSizeBytes)\n{\n    nBufferSizeBytes = (nBufferSizeBytes / (defaultSigmaSettings.argonMemoryCostKb*1024)) * (defaultSigmaSettings.argonMemoryCostKb*1024);\n}\n\nsigma_settings::sigma_settings()\n{\n    verify();\n}\n\nvoid sigma_settings::verify()\n{\n    assert(arenaSizeKb%argonMemoryCostKb==0);\n    assert(numHashesPre <= (uint64_t)std::numeric_limits<uint16_t>::max()+1);\n    assert(numHashesPost <= (uint64_t)std::numeric_limits<uint16_t>::max()+1);\n    arenaChunkSizeBytes = (arenaSizeKb*1024)/numHashesPost;\n    assert(fastHashSizeBytes<=arenaChunkSizeBytes);\n}\n\n\nsigma_context::sigma_context(sigma_settings settings_, uint64_t allocateArenaSizeKb_, uint64_t numThreads_, uint64_t numArenaThreads_)\n: numThreads(numThreads_)\n, numArenaThreads(numArenaThreads_)\n, allocatedArenaSizeKb(allocateArenaSizeKb_)\n, settings(settings_)\n{\n    assert(allocatedArenaSizeKb <= settings.arenaSizeKb);\n    assert(allocatedArenaSizeKb%settings.argonMemoryCostKb==0);\n\n    // Node/electron addons have issues with large memory (>2gb) allocations, due to chrome overriding malloc and doing various custom things with it\n    // Work around this by bypassing malloc and doing a direct mmap instead\n    #if (defined(__linux__)||defined(__APPLE__)) && defined(DJINNI_NODEJS)\n    arena = (uint8_t*)mmap(0, (allocatedArenaSizeKb*1024), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,-1, 0);\n    if (arena)\n    {\n        memset(arena, 0, allocatedArenaSizeKb*1024);\n    }\n    #else\n    arena = (uint8_t*)malloc(allocatedArenaSizeKb*1024);\n    #endif\n\n    numHashesPossibleWithAvailableMemory = (allocatedArenaSizeKb*1024)/settings.arenaChunkSizeBytes;\n}\n\nbool sigma_context::arenaIsValid()\n{\n    return (arena != nullptr);\n}\n\nvoid sigma_context::prepareArenas(CBlockHeader& headerData)\n{\n    uint32_t numHashes = allocatedArenaSizeKb/settings.argonMemoryCostKb;\n\n    // Set the nonce to something quasi random, thats difficult for an attacker to control.\n    // It doesn't matter exactly what the value is they key thing is that it makes it harder for an attacker to manipulate the arena values, or re-use them across blocks, or to compute the argon hash faster.\n    // As it takes away a part of the hashed data that would otherwise be constant.\n    // Even if he should find a way to otherwise manipulate things, this measure makes it a bit trickier.\n    // This is a bit of a paranoid measure as realistically the argon hashes are of the block header which should always be different anyway.\n    uint32_t nBaseNonce = headerData.nBits ^ (uint32_t)(headerData.hashPrevBlock.GetCheapHash());\n    std::vector<std::thread> workerPool;\n    workerPool.reserve(numArenaThreads);\n    for (uint32_t nThreadIndex=0; nThreadIndex<numArenaThreads; ++nThreadIndex)\n    {\n        workerPool.emplace_back( [&,headerData, nThreadIndex]() mutable\n        {\n            #ifdef SIGMA_SET_THREAD_AFFINITY\n            cpu_set_t cpuset;\n            CPU_ZERO(&cpuset);\n            CPU_SET(nThreadIndex, &cpuset);\n            sched_setaffinity(0, sizeof(cpuset), &cpuset);\n            #endif\n\n            for (;nThreadIndex<numHashes;nThreadIndex+=numArenaThreads)\n            {\n                headerData.nNonce = nBaseNonce+nThreadIndex;\n                argon2_echo_context context;\n                context.t_cost = settings.argonArenaRoundCost;\n                context.m_cost = settings.argonMemoryCostKb;\n                context.allocated_memory = &arena[(settings.argonMemoryCostKb*1024)*nThreadIndex];\n                context.pwd = (uint8_t*)&headerData.nVersion;\n                context.pwdlen = 80;\n\n                context.lanes = settings.numVerifyThreads;\n                context.threads = 1;\n\n                if (selected_argon2_echo_hash(&context, false) != ARGON2_OK)\n                    assert(0);\n            }\n        });\n    }\n    for (auto& thread : workerPool) { thread.join(); }\n}\n\nvoid sigma_context::benchmarkSlowHashes(uint8_t* hashData, uint64_t numSlowHashes)\n{\n    uint8_t* hashMem = new uint8_t[settings.argonMemoryCostKb*1024];\n    {\n        BOOST_SCOPE_EXIT(&hashMem) { delete[] hashMem; } BOOST_SCOPE_EXIT_END\n\n        argon2_echo_context argonContext;\n        argonContext.t_cost = settings.argonSlowHashRoundCost;\n        argonContext.m_cost = settings.argonMemoryCostKb;\n        argonContext.allocated_memory = hashMem;\n        argonContext.pwd = (uint8_t*)&hashData[0];\n        argonContext.pwdlen = 80;\n\n        argonContext.lanes = settings.numVerifyThreads;\n        argonContext.threads = 1;\n\n        for (uint64_t i=0;i<numSlowHashes;++i)\n        {\n            hashData[rand()%80] = rand();\n            hashData[rand()%80] = rand();\n            hashData[rand()%80] = rand();\n            hashData[rand()%80] = rand();\n\n            if (selected_argon2_echo_hash(&argonContext, true) != ARGON2_OK)\n                assert(0);\n        }\n    }\n}\n\nvoid sigma_context::benchmarkFastHashes(uint8_t* hashData1, uint8_t* hashData2, uint8_t* hashData3, uint64_t numFastHashes)\n{\n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n    prng.SetKey((const unsigned char*)&hashData2[0], 32);\n    unsigned char ciphered[32];\n\n    uint256 outHash;\n    for (uint64_t i=0;i<numFastHashes;++i)\n    {\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&hashData2[0], 32);\n        memcpy(&hashData2[0], &ciphered[0], (size_t)32);\n\n        hashData1[rand()%80] = rand();\n        hashData1[rand()%80] = i;\n        hashData2[rand()%32] = i;\n        hashData2[rand()%32] = i;\n        sigmaRandomFastHash(i%2, (uint8_t*)&hashData1[0], 80, (uint8_t*)&hashData2, 32,  (uint8_t*)&hashData3[0], settings.fastHashSizeBytes, outHash);\n    }\n}\n\nvoid sigma_context::benchmarkFastHashesRef(uint8_t* hashData1, uint8_t* hashData2, uint8_t* hashData3, uint64_t numFastHashes)\n{\n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n    prng.SetKey((const unsigned char*)&hashData2[0], 32);\n    unsigned char ciphered[32];\n\n    uint256 outHash;\n    for (uint64_t i=0;i<numFastHashes;++i)\n    {\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&hashData2[0], 32);\n        memcpy(&hashData2[0], &ciphered[0], (size_t)32);\n\n        hashData1[rand()%80] = rand();\n        hashData1[rand()%80] = i;\n        hashData2[rand()%32] = i;\n        hashData2[rand()%32] = i;\n        sigmaRandomFastHashRef(i%2, (uint8_t*)&hashData1[0], 80, (uint8_t*)&hashData2, 32,  (uint8_t*)&hashData3[0], settings.fastHashSizeBytes, outHash);\n    }\n}\n\n\n//fixme: (SIGMA) - dedup with benchmarkMining\nvoid sigma_context::mineBlock(CBlock* pBlock, std::atomic<uint64_t>& halfHashCounter, uint256& foundBlockHash, bool& interrupt)\n{\n    CBlockHeader headerData = pBlock->GetBlockHeader();\n\n    arith_uint256 hashTarget = arith_uint256().SetCompact(headerData.nBits);\n\n    std::vector<std::thread> workerPool;\n    workerPool.reserve(numThreads);\n    {\n        BOOST_SCOPE_EXIT(&workerPool) { for (auto& thread : workerPool) { thread.join(); } } BOOST_SCOPE_EXIT_END\n\n        for (uint16_t nThreadIndex=0; nThreadIndex<numThreads; ++nThreadIndex)\n        {\n            workerPool.emplace_back( [&,headerData, nThreadIndex]() mutable\n            {\n                #ifdef SIGMA_SET_THREAD_AFFINITY\n                cpu_set_t cpuset;\n                CPU_ZERO(&cpuset);\n                CPU_SET(nThreadIndex, &cpuset);\n                sched_setaffinity(0, sizeof(cpuset), &cpuset);\n                #endif\n\n                //fixme: (CBSU) - Theoretically we can reduce thread contention here if we allocate on the stack (VLA) instead of the heap...\n                uint8_t* hashMem = new uint8_t[settings.argonMemoryCostKb*1024];\n                //fixme: (SIGMA) - Return false and handle this in the external mining loop.\n                if (!hashMem)\n                    return;\n\n                argon2_echo_context argonContext;\n                argonContext.t_cost = settings.argonSlowHashRoundCost;\n                argonContext.m_cost = settings.argonMemoryCostKb;\n                argonContext.allocated_memory = hashMem;\n                argonContext.pwdlen = 80;\n                argonContext.lanes = settings.numVerifyThreads;\n                argonContext.threads = 1;\n\n                for (; nThreadIndex <= settings.numHashesPre;nThreadIndex+=numThreads)\n                {\n                    if (UNLIKELY(interrupt))\n                    {\n                        delete[] hashMem;\n                        return;\n                    }\n\n                    uint16_t nPreNonce = nThreadIndex;\n                    uint32_t nBaseNonce = headerData.nBits ^ (uint32_t)(headerData.hashPrevBlock.GetCheapHash());\n\n                    // 1. Reset nonce to base nonce and select the pre nonce.\n                    // This leaves the post nonce in a 'default' but 'psuedo random' state.\n                    // We do this instead of zeroing out the post-nonce to reduce the predictability of the data to be hashed and therefore make it harder to attack the hash functions.\n                    {\n                        headerData.nNonce = nBaseNonce;\n                        headerData.nPreNonce = nPreNonce;\n\n                        // 2. Perform the \"slow\" (argon) hash of header with pre-nonce\n                        argonContext.pwd = (uint8_t*)&headerData.nVersion;\n                        if (selected_argon2_echo_hash(&argonContext, true) != ARGON2_OK)\n                        {\n                            delete[] hashMem;\n                            //fixme: (SIGMA) - Return false and handle this in the external mining loop.\n                            return;\n                        }\n\n                        // 3. Set the initial state of the seed for the 'pseudo random' nonces.\n                        // PRNG notes:\n                        // We specifically want a PRNG that does not allow jumping\n                        // This forces linear instead of parallel PRNG generation which helps to penalise GPU implementations (which thrive on parallelism)\n                        // Ideally we want something for which CPUs have special instructions so as to be comepetitive with ASICs and faster than GPUs in the PRNG phase.\n                        // An AES based PRNG is therefore a good fit for this.\n                        // We do not specifically care about the distribution being 100% perfectly random.\n                        // Reasonable distribution and randomness are desirable so that certain portions of the memory buffer are not over/under utilised.\n                        // Non predictability is also desirable to prevent any pre-fetch/order optimisations .\n                        //\n                        // We construct a simple PRNG by passing our seed data through AES in ECB mode and then repeatedly feeding it back in.\n                        // This is possibly not the most high quality RNG ever; however should be perfect for our specific needs.\n                        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n                        prng.SetKey((const unsigned char*)&argonContext.outHash[0], 32);\n                        unsigned char ciphered[32];\n\n                        // 4. Iterate through all 'post' nonce combinations, calculating 2 hashes from the global memory.\n                        // The input of one is determined by the 'post' nonce, while the second is determined by the 'pseudo random' nonce, forcing random memory access.\n                        headerData.nPostNonce = 0;\n                        while(true)\n                        {\n                            if (UNLIKELY(interrupt))\n                            {\n                                delete[] hashMem;\n                                return;\n                            }\n\n                            // 4.1. For each iteration advance the state of the pseudo random nonce\n                            prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&argonContext.outHash[0], 32);\n                            memcpy(&argonContext.outHash[0], &ciphered[0], (size_t)32);\n\n                            uint64_t nPseudoRandomNonce1 = (argonContext.outHash[0] ^ argonContext.outHash[1]) % settings.numHashesPost;\n                            uint64_t nPseudoRandomNonce2 = (argonContext.outHash[2] ^ argonContext.outHash[3]) % settings.numHashesPost;\n\n                            if (bool skip = nPseudoRandomNonce1 >= numHashesPossibleWithAvailableMemory || nPseudoRandomNonce2 >= numHashesPossibleWithAvailableMemory; LIKELY(!skip))\n                            {\n                                uint64_t nPseudoRandomAlg1 = (argonContext.outHash[0] ^ argonContext.outHash[3]) % 2;\n                                uint64_t nPseudoRandomAlg2 = (argonContext.outHash[1] ^ argonContext.outHash[2]) % 2;\n\n                                uint64_t nFastHashOffset1 = (argonContext.outHash[0] ^ argonContext.outHash[2])%(settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n                                uint64_t nFastHashOffset2 = (argonContext.outHash[1] ^ argonContext.outHash[3])%(settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n\n                                // 4.2 Calculate first hash\n                                uint256 fastHash;\n                                sigmaRandomFastHash(nPseudoRandomAlg1, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)&argonContext.outHash, 32,  &arena[(nPseudoRandomNonce1*settings.arenaChunkSizeBytes)+nFastHashOffset1], settings.fastHashSizeBytes, fastHash);\n                                ++halfHashCounter;\n\n                                // 4.3 Evaluate first hash (short circuit evaluation)\n                                if (UNLIKELY(UintToArith256(fastHash) <= hashTarget))\n                                {\n                                    // 4.4 Calculate second hash\n                                    sigmaRandomFastHash(nPseudoRandomAlg2, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)&argonContext.outHash, 32,  &arena[(nPseudoRandomNonce2*settings.arenaChunkSizeBytes)+nFastHashOffset2], settings.fastHashSizeBytes, fastHash);\n\n                                    // 4.5 See if we have a valid block\n                                    if (UNLIKELY(UintToArith256(fastHash) <= hashTarget))\n                                    {\n                                        // Found a block, set it and exit.\n                                        delete[] hashMem;\n                                        pBlock->nNonce = headerData.nNonce;\n                                        foundBlockHash = fastHash;\n                                        interrupt=true;\n                                        return;\n                                    }\n                                }\n                            }\n                            if (UNLIKELY(headerData.nPostNonce == settings.numHashesPost-1))\n                            {\n                                break;\n                            }\n                            ++headerData.nPostNonce;\n                        }\n                    }\n                }\n                delete[] hashMem;\n            });\n        }\n    }\n}\n\nvoid sigma_context::benchmarkMining(CBlockHeader& headerData, std::atomic<uint64_t>& slowHashCounter, std::atomic<uint64_t>& halfHashCounter, std::atomic<uint64_t>& skippedHashCounter, std::atomic<uint64_t>&hashCounter, std::atomic<uint64_t>&blockCounter, uint64_t nRoundsTarget)\n{\n    arith_uint256 hashTarget = arith_uint256().SetCompact(headerData.nBits);\n    std::atomic<uint16_t> nGlobalPreNonce=0;\n    std::vector<std::thread> workerPool;\n    workerPool.reserve(numThreads);\n    {\n        BOOST_SCOPE_EXIT(&workerPool) { for (auto& thread : workerPool) { thread.join(); } } BOOST_SCOPE_EXIT_END\n\n        for (uint16_t nThreadIndex=0; nThreadIndex<numThreads; ++nThreadIndex)\n        {\n            workerPool.emplace_back( [&,headerData, nThreadIndex]() mutable\n            {\n                #ifdef SIGMA_SET_THREAD_AFFINITY\n                cpu_set_t cpuset; \n                CPU_ZERO(&cpuset);\n                CPU_SET(nThreadIndex, &cpuset);\n                sched_setaffinity(0, sizeof(cpuset), &cpuset);\n                #endif\n\n                //fixme: (CBSU) - Theoretically we can reduce thread contention here if we allocate on the stack (VLA) instead of the heap...\n                uint8_t* hashMem = new uint8_t[settings.argonMemoryCostKb*1024];\n                //fixme: (SIGMA) - Return false and handle this in the external mining loop.\n                if (!hashMem)\n                    return;\n\n                argon2_echo_context argonContext;\n                argonContext.t_cost = settings.argonSlowHashRoundCost;\n                argonContext.m_cost = settings.argonMemoryCostKb;\n                argonContext.allocated_memory = hashMem;\n                argonContext.pwdlen = 80;\n                argonContext.lanes = settings.numVerifyThreads;\n                argonContext.threads = 1;\n\n                for (; nThreadIndex <= settings.numHashesPre;nThreadIndex+=numThreads)\n                {\n                    uint16_t nPreNonce = nThreadIndex;\n                    uint32_t nBaseNonce = headerData.nBits ^ (uint32_t)(headerData.hashPrevBlock.GetCheapHash());\n\n                    if (hashCounter >= nRoundsTarget)\n                        return;\n\n                    // 1. Reset nonce to base nonce and select the pre nonce.\n                    // This leaves the post nonce in a 'default' but 'psuedo random' state.\n                    // We do this instead of zeroing out the post-nonce to reduce the predictability of the data to be hashed and therefore make it harder to attack the hash functions.\n                    {\n                        headerData.nNonce = nBaseNonce;\n                        headerData.nPreNonce = nPreNonce;\n\n                        // 2. Perform the \"slow\" (argon) hash of header with pre-nonce\n                        argonContext.pwd = (uint8_t*)&headerData.nVersion;\n                        ++slowHashCounter;\n\n                        if (selected_argon2_echo_hash(&argonContext, true) != ARGON2_OK)\n                        {\n                            delete[] hashMem;\n                            assert(0);\n                        }\n\n                        // 3. Set the initial state of the seed for the 'pseudo random' nonces.\n                        // PRNG notes:\n                        // We specifically want a PRNG that does not allow jumping\n                        // This forces linear instead of parallel PRNG generation which helps to penalise GPU implementations (which thrive on parallelism)\n                        // Ideally we want something for which CPUs have special instructions so as to be comepetitive with ASICs and faster than GPUs in the PRNG phase.\n                        // An AES based PRNG is therefore a good fit for this.\n                        // We do not specifically care about the distribution being 100% perfectly random.\n                        // Reasonable distribution and randomness are desirable so that certain portions of the memory buffer are not over/under utilised.\n                        // Non predictability is also desirable to prevent any pre-fetch/order optimisations .\n                        //\n                        // We construct a simple PRNG by passing our seed data through AES in ECB mode and then repeatedly feeding it back in.\n                        // This is possibly not the most high quality RNG ever; however should be perfect for our specific needs.\n                        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n                        prng.SetKey((const unsigned char*)&argonContext.outHash[0], 32);\n                        unsigned char ciphered[32];\n\n                        // 4. Iterate through all 'post' nonce combinations, calculating 2 hashes from the global memory.\n                        // The input of one is determined by the 'post' nonce, while the second is determined by the 'pseudo random' nonce, forcing random memory access.\n                        headerData.nPostNonce = 0;\n                        while(true)\n                        {\n                            if (UNLIKELY(hashCounter >= nRoundsTarget))\n                                break;\n\n                            // 4.1. For each iteration advance the state of the pseudo random nonce\n                            prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&argonContext.outHash[0], 32);\n                            memcpy(&argonContext.outHash[0], &ciphered[0], (size_t)32);\n\n                            uint64_t nPseudoRandomNonce1 = (argonContext.outHash[0] ^ argonContext.outHash[1]) % settings.numHashesPost;\n                            uint64_t nPseudoRandomNonce2 = (argonContext.outHash[2] ^ argonContext.outHash[3]) % settings.numHashesPost;\n                            if (bool skip = nPseudoRandomNonce1 >= numHashesPossibleWithAvailableMemory || nPseudoRandomNonce2 >= numHashesPossibleWithAvailableMemory; UNLIKELY(skip))\n                            {\n                                ++skippedHashCounter;\n                            }\n                            else\n                            {\n                                uint64_t nPseudoRandomAlg1 = (argonContext.outHash[0] ^ argonContext.outHash[3]) % 2;\n                                uint64_t nPseudoRandomAlg2 = (argonContext.outHash[1] ^ argonContext.outHash[2]) % 2;\n\n                                uint64_t nFastHashOffset1 = (argonContext.outHash[0] ^ argonContext.outHash[2])%(settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n                                uint64_t nFastHashOffset2 = (argonContext.outHash[1] ^ argonContext.outHash[3])%(settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n\n                                // 4.2 Calculate first hash\n                                uint256 fastHash;\n                                sigmaRandomFastHash(nPseudoRandomAlg1, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)&argonContext.outHash, 32,  &arena[(nPseudoRandomNonce1*settings.arenaChunkSizeBytes)+nFastHashOffset1], settings.fastHashSizeBytes, fastHash);\n                                ++halfHashCounter;\n\n                                // 4.3 Evaluate first hash (short circuit evaluation)\n                                if (UNLIKELY(UintToArith256(fastHash) <= hashTarget))\n                                {\n                                    // 4.4 Calculate second hash\n                                    sigmaRandomFastHash(nPseudoRandomAlg2, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)&argonContext.outHash, 32,  &arena[(nPseudoRandomNonce2*settings.arenaChunkSizeBytes)+nFastHashOffset2], settings.fastHashSizeBytes, fastHash);\n                                    ++hashCounter;\n\n                                    // 4.5 See if we have a valid block\n                                    if (UNLIKELY(UintToArith256(fastHash) <= hashTarget))\n                                    {\n                                        //#define LOG_VALID_BLOCK\n                                        #ifdef LOG_VALID_BLOCK\n                                        LogPrintf(\"Found block [%s]\\n\", HexStr((uint8_t*)&headerData.nVersion, (uint8_t*)&headerData.nVersion+80).c_str());\n                                        LogPrintf(\"pseudorandomnonce1[%d] pseudorandomalg1[%d] fasthashoffset1[%d] arenaoffset1[%d]\\n\", nPseudoRandomNonce1, nPseudoRandomAlg1, nFastHashOffset1, (nPseudoRandomNonce1*settings.arenaChunkSizeBytes)+nFastHashOffset1);\n                                        LogPrintf(\"pseudorandomnonce2[%d] pseudorandomalg2[%d] fasthashoffset2[%d] arenaoffset2[%d]\\n\", nPseudoRandomNonce2, nPseudoRandomAlg2, nFastHashOffset2, (nPseudoRandomNonce2*settings.arenaChunkSizeBytes)+nFastHashOffset2);\n                                        LogPrintf(\"base [%d] pre [%d] post [%d] nversion [%d] nbits [%d] ntime [%d]\\n\", nBaseNonce, headerData.nPreNonce, headerData.nPostNonce, headerData.nVersion, headerData.nBits, headerData.nTime);\n                                        #endif\n                                        ++blockCounter;\n                                    }\n                                    if (UNLIKELY(hashCounter >= nRoundsTarget))\n                                    {\n                                        break;\n                                    }\n                                }\n                            }\n                            if (UNLIKELY(headerData.nPostNonce == settings.numHashesPost-1))\n                            {\n                                break;\n                            }\n                            ++headerData.nPostNonce;\n                        }\n                    }\n                }\n                delete[] hashMem;\n            });\n        }\n    }\n}\n\nsigma_context::~sigma_context()\n{\n    #if (defined(__linux__)||defined(__APPLE__)) && defined(DJINNI_NODEJS)\n    (uint8_t*)munmap(arena, (allocatedArenaSizeKb*1024));\n    #else\n    free(arena);\n    #endif\n}\n\n\nsigma_verify_context::sigma_verify_context(sigma_settings settings_, uint64_t numUserVerifyThreads_)\n: settings(settings_)\n, numUserVerifyThreads(numUserVerifyThreads_)\n{\n    assert(numUserVerifyThreads <= settings.numVerifyThreads);\n    hashMem = new uint8_t[settings.argonMemoryCostKb*1024];\n\n    //fixme: (SIGMA) - Instead of argon allocating and destroying threads internally we should create threads once per verify context and keep them for the life of the context.\n    //This should provide speed benefits when verifying multiple headers in a row.\n}\n\ntemplate<int verifyLevel> bool sigma_verify_context::verifyHeader(CBlockHeader headerData)\n{\n    arith_uint256 hashTarget = arith_uint256().SetCompact(headerData.nBits);\n\n    uint32_t nBaseNonce = headerData.nBits ^ (uint32_t)(headerData.hashPrevBlock.GetCheapHash());\n    uint64_t nPostNonce = headerData.nPostNonce;\n    uint64_t nPreNonce = headerData.nPreNonce;\n\n    // 1. Reset nonce to base nonce and select the pre nonce.\n    // This leaves the post nonce in a 'default' but 'pseudo random' state.\n    // We do this instead of zeroing out the post-nonce to reduce the predictability of the data to be hashed and therefore make it harder to attack the hash functions.\n    headerData.nNonce = nBaseNonce;\n    headerData.nPreNonce = nPreNonce;\n\n    // 2. Perform the \"slow\" (argon) hash of header with pre-nonce\n    argon2_echo_context argonContext;\n    argonContext.t_cost = settings.argonSlowHashRoundCost;\n    argonContext.m_cost = settings.argonMemoryCostKb;\n    argonContext.allocated_memory = hashMem;\n    argonContext.pwd = (uint8_t*)&headerData.nVersion;\n    argonContext.pwdlen = 80;\n\n    argonContext.lanes = settings.numVerifyThreads;\n    #ifdef WIN32\n    //fixme: (HIGH) argon threading code is causing crashes on win32 since we switched to the new GUIX based toolchain (not when called from mining thread though...)\n    //We use 1 thread for now to prevent this, but we should look into this more when time allows\n    argonContext.threads = 1;\n    #else\n    argonContext.threads = numUserVerifyThreads;\n    #endif\n\n    if (selected_argon2_echo_hash(&argonContext, true) != ARGON2_OK)\n        assert(0);\n\n    // 3. Set the initial state of the seed for the 'pseudo random' nonces.\n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption prng;\n    prng.SetKey((const unsigned char*)&argonContext.outHash[0], 32);\n    unsigned char ciphered[32];\n\n    // 4. Advance PRNG to 'post' nonce\n    headerData.nPostNonce=0;\n    for (uint64_t i=0; i<=nPostNonce; ++i)\n    {\n        prng.ProcessData((unsigned char*)&ciphered[0], (const unsigned char*)&argonContext.outHash[0], 32);\n        memcpy(&argonContext.outHash[0], &ciphered[0], (size_t)32);\n        ++headerData.nPostNonce;\n    }\n\n    [[maybe_unused]] uint64_t nPseudoRandomNonce1 = (argonContext.outHash[0] ^ argonContext.outHash[1]) % settings.numHashesPost;\n    [[maybe_unused]] uint64_t nPseudoRandomNonce2 = (argonContext.outHash[2] ^ argonContext.outHash[3]) % settings.numHashesPost;\n    [[maybe_unused]] uint64_t nPseudoRandomAlg1   = (argonContext.outHash[0] ^ argonContext.outHash[3]) % 2;\n    [[maybe_unused]] uint64_t nPseudoRandomAlg2   = (argonContext.outHash[1] ^ argonContext.outHash[2]) % 2;\n    [[maybe_unused]] uint64_t nFastHashOffset1    = (argonContext.outHash[0] ^ argonContext.outHash[2]) % (settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n    [[maybe_unused]] uint64_t nFastHashOffset2    = (argonContext.outHash[1] ^ argonContext.outHash[3]) % (settings.arenaChunkSizeBytes-settings.fastHashSizeBytes);\n    std::array<uint64_t, 4> slowHash = std::move(argonContext.outHash);\n\n    [[maybe_unused]] uint64_t nArenaMemoryIndex1  = (settings.arenaChunkSizeBytes*nPseudoRandomNonce1) / (settings.argonMemoryCostKb*1024);\n    [[maybe_unused]] uint64_t nArenaMemoryOffset1 = (settings.arenaChunkSizeBytes*nPseudoRandomNonce1) % (settings.argonMemoryCostKb*1024);\n    [[maybe_unused]] uint64_t nArenaMemoryIndex2  = (settings.arenaChunkSizeBytes*nPseudoRandomNonce2) / (settings.argonMemoryCostKb*1024);\n    [[maybe_unused]] uint64_t nArenaMemoryOffset2 = (settings.arenaChunkSizeBytes*nPseudoRandomNonce2) % (settings.argonMemoryCostKb*1024);\n\n    if (nArenaMemoryOffset1+nFastHashOffset1 >= settings.argonMemoryCostKb*1024)\n    {\n        nArenaMemoryIndex1++;\n        nFastHashOffset1 = (nArenaMemoryOffset1+nFastHashOffset1)-(settings.argonMemoryCostKb*1024);\n        nArenaMemoryOffset1 = 0;\n    }\n    if (nArenaMemoryOffset2+nFastHashOffset2 >= settings.argonMemoryCostKb*1024)\n    {\n        nArenaMemoryIndex2++;\n        nFastHashOffset2 = (nArenaMemoryOffset2+nFastHashOffset2)-(settings.argonMemoryCostKb*1024);\n        nArenaMemoryOffset2 = 0;\n    }\n\n\n    // 5. Generate the part(s) of the arena we need as we don't have the whole arena like a miner would.\n    {\n        uint256 fastHash;\n        argonContext.t_cost = settings.argonArenaRoundCost;\n\n        // For each fast hash, set the pre and post nonce to the final values the miner claims he was using\n        // Then calculate the fast hash and compare against the hash target to see if it meets it or not\n        // NB!!! As a special optimisation we allow the caller to execute discretion and skip the check for one of the two fast hashes\n        // This is fine if used sparingly and with other precautions in place but caution should be exercised as if used carelessly it can make it easier to split the chain\n        // NB!!! Do not make use of this unless you fully understand the repercussions\n\n        // 6. Verify first fast hash\n        if constexpr (verifyLevel == 0 || verifyLevel == 1)\n        {\n            headerData.nNonce = nBaseNonce+nArenaMemoryIndex1;\n            if (selected_argon2_echo_hash(&argonContext, false) != ARGON2_OK)\n                assert(0);\n            headerData.nPreNonce = nPreNonce;\n            headerData.nPostNonce = nPostNonce;\n\n            if (nArenaMemoryOffset1+nFastHashOffset1 >= settings.argonMemoryCostKb*1024)\n                return false;\n\n            sigmaRandomFastHash(nPseudoRandomAlg1, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)slowHash.begin(), 32,  &argonContext.allocated_memory[nArenaMemoryOffset1+nFastHashOffset1], settings.fastHashSizeBytes, fastHash);\n            if (UintToArith256(fastHash) > hashTarget)\n            {\n                return false;\n            }\n        }\n\n        // 7. First fast hash checks out, repeat process for second fast hash\n        if constexpr (verifyLevel == 0 || verifyLevel == 2)\n        {\n            headerData.nNonce = nBaseNonce+nArenaMemoryIndex2;\n            if (selected_argon2_echo_hash(&argonContext, false) != ARGON2_OK)\n                assert(0);\n            headerData.nPreNonce = nPreNonce;\n            headerData.nPostNonce = nPostNonce;\n\n            if (nArenaMemoryOffset2+nFastHashOffset2 >= settings.argonMemoryCostKb*1024)\n                return false;\n\n            sigmaRandomFastHash(nPseudoRandomAlg2, (uint8_t*)&headerData.nVersion, 80, (uint8_t*)slowHash.begin(), 32,  &argonContext.allocated_memory[nArenaMemoryOffset2+nFastHashOffset2], settings.fastHashSizeBytes, fastHash);\n            if (UintToArith256(fastHash) > hashTarget)\n            {\n                return false;\n            }\n        }\n\n        // 8. Hooray! the block is valid.\n        return true;\n    }\n    return false;\n}\ntemplate bool sigma_verify_context::verifyHeader<0>(CBlockHeader);\ntemplate bool sigma_verify_context::verifyHeader<1>(CBlockHeader);\ntemplate bool sigma_verify_context::verifyHeader<2>(CBlockHeader);\n\nsigma_verify_context::~sigma_verify_context()\n{\n    delete[] hashMem;\n}\n"
  },
  {
    "path": "src/crypto/hash/sigma/sigma.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CRYPTO_HASH_SIGMA_HASH_H\n#define CRYPTO_HASH_SIGMA_HASH_H\n\n#include <stdint.h>\n#include <primitives/block.h>\n\n#include <crypto/hash/sigma/argon_echo/argon_echo.h>\n#include <crypto/hash/sigma/echo256/sphlib/sph_echo.h>\n#include <crypto/hash/sigma/echo256/echo256_opt.h>\n#include <crypto/hash/sigma/shavite3_256/shavite3_256_opt.h>\n#include <crypto/hash/sigma/shavite3_256/ref/shavite3_ref.h>\n\n//  SIGMA hash\n// *S*emi\n// *I*terated               - A key part of the algorithm is that parts of the hash can be iterated over cheaply.\n// *G*lobal\n// *M*emory                 - A large global memory buffer is also a key part of the algorithm\n// *A*rgon                  - Argon is used extensively throughout the algorithm\n//\n// SIGMA attempts to be a 'CPU friendly' PoW algorithm that counteracts the advantages that ASICs and GPU miners would normally have:\n// * The primary mechanism through which this is achieved is by requiring large quantities of memory in an asymmetrical way. i.e. for mining memory requirements are large, but verification can be done cheaply.\n// * In addition we attempt to rely on computational features where CPUs are already highly optimised (like AES-ni)\n// * We build on top of various existing hash functions and simply combine them.\n//\n// Operation:\n// * A large (4gb/8gb/12gb etc.) global arena (G) is populated by performing multiple argon2d (modified to fill memory) hashes of the block (with the nonce zeroed out).\n// * The first half of the nonce is iterated X times and for each iteration an argon2d hash (S) is performed of it.\n// * For each S the second half of the nonce is then iterated Y times and for each iteration N random indices are generated with a PRNG seeded by S.\n// * For each N a fast hash Fn is generated based on S and a chunk of memory from G that corresponds to N.\n// * If for a set of N all Fn meet the difficulty criteria then we have a valid block.\n// \n// Considerations:\n// * F should be substantially slower than S such that T(S) >= (T(F)*Y)\n// * Assuming 'T(S) >= (T(F)*Y)' it can be shown that when N=2 hashing with G/2 memory instead of the full memory will result in a slowdown such that only 1/4 of the hashes can be generated in the same time, for greater N the slow down would be greater..\n// * Validation speed is also limited by 'F' however so 'F' should not be too slow either, a balance is required.\n// * Y can also be reduced to balance this equation\n// * Increasing N also increases the time penalty, but every extra N also means slower (full) validation. In some cases nodes could potentially randomly validate only parts of the hash bypassing part of this penalty.\n//\n// Munt specific details:\n// Some extra details apply that are specific to our current implementation of SIGMA but could also be done differently:\n// * We use a slightly modified 'argon' which we call 'argon_echo' to break compatibility with any argon specific chip implementations.\n// * We use two different hash algorithms 'shavite' and 'echo' for the fast hashes, the choice of which to use is generated randomly along with the indices.\n//   This is done to force extra branching with 50/50 probability and slow parallelisation on GPUs, as well as a way to force extra cost for ASIC implementations.\n//   Both are chosen for their ability to use AES-ni (or other dedicated AES instructions) that most modern CPUs have to achieve performance that will be difficult to drastically beat on a GPU or ASIC.\n// * We use AES as the PRNG - for similar reasons to above.\n//\n// There are various ways in which SIGMA can/could be adjusted the main parameters are outlined below:\n// Arena size (currently 4gb):\n// * The overall memory required by the algorithm for optimal generation performance.\n// * The larger this is the less likely GPUs can perform the algorithm, and the more expensive and dominated by RAM price ASIC implementations are thus making them less competitive with CPUs.\n// Argon memory cost (currently 4mb):\n// * How much memory each individual argon hash uses.\n// * Increasing this increases GPU resistance, but also increases verification requirements.\n// Argon arena round cost (currently 8):\n// * Increasing this affects how long the argon hashes for the initial arena takes (in conjunction with the memory cost)\n// * Should be lower than the slow hash cost but high enough to still be secure\n// Argon slow hash round cost (currently 12):\n// * Increasing this affects how long the argon slow hashes take (in conjunction with the memory cost)\n// * Longer is better, however also means longer verification\n// Num pre-hashes (currently 65536):\n// * Affects how many times the same global memory buffer can be hashed before a new one must be generated\n// Num post-hashes (currently 40000):\n// * Affects how many fast hashes we can perform per slow hash\n// Fast hash size (currently 300 bytes):\n// * Affects how much memory from the global buffer is consumed by each fast hash.\n// * This ultimately affects the speed of the fast hash\n\n\n// Consensus level SIGMA options and global defaults.\n// NB! Must call verify after changing any settings.\nclass sigma_settings\n{\npublic:\n    sigma_settings();\n    void verify();\npublic:\n    uint64_t numVerifyThreads=4;         // Allow verification with 4 threads\n    uint64_t arenaSizeKb=4*1024*1024;    // 4gb overall arena size\n    uint64_t argonMemoryCostKb=4*1024;   // 4mb per arena/slow hash\n    uint64_t argonArenaRoundCost=8;      // 8 rounds per arena hash\n    uint64_t argonSlowHashRoundCost=12;  // 12 rounds per slow hash\n    uint64_t numHashesPre=65536;         // 65536 pre-hashes\n    uint64_t numHashesPost=65536;        // 65536 post-hashes \n    uint64_t fastHashSizeBytes=300;      // 300 bytes per fast hash\n    \n    // Calculated from other values in constructor.\n    uint64_t arenaChunkSizeBytes=0;\n    // Affects program behaviour (SIGMA activation block) not SIGMA itself.\n    uint64_t activationDate=1571234400;\n};\n// Consensus level SIGMA defaults.\nextern sigma_settings defaultSigmaSettings;\n\n\n// We select the optimal implementation of these hash functions to match our CPU once at program start and then just use the function pointers throghout the SIGMA code.\nvoid selectOptimisedImplementations();\nextern uint64_t gSelShavite;\nextern uint64_t gSelEcho;\nextern uint64_t gSelArgon;\n// Get a human readable name for the selections above\nstd::string selectedAlgorithmName(uint64_t nSel);\n\ninline HashReturn (*selected_echo256_opt_Init)(echo256_opt_hashState* state) = nullptr;\ninline HashReturn (*selected_echo256_opt_Update)(echo256_opt_hashState* state, const unsigned char* data, uint64_t databitlen) = nullptr;\ninline HashReturn (*selected_echo256_opt_Final)(echo256_opt_hashState* state, unsigned char* hashval) = nullptr;\ninline HashReturn (*selected_echo256_opt_UpdateFinal)(echo256_opt_hashState* state, unsigned char* hashval, const unsigned char* data, uint64_t databitlen) = nullptr;\ninline bool (*selected_shavite3_256_opt_Init)(shavite3_256_opt_hashState* state) = nullptr;\ninline bool (*selected_shavite3_256_opt_Update)(shavite3_256_opt_hashState* state, const unsigned char* data, uint64_t dataLenBytes) = nullptr;\ninline bool (*selected_shavite3_256_opt_Final)(shavite3_256_opt_hashState* state, unsigned char* hashval) = nullptr;\ninline int (*selected_argon2_echo_hash)(argon2_echo_context* context, bool doHash) = argon2_echo_ctx_ref;\n\nvoid normaliseBufferSize(uint64_t& nBufferSizeBytes);\n\n// Heavy weight sigma context for mining - allocated the entire arena (currently 4gb)\n// NB!!! Take care creating/using these they allocate lots of memory..\nclass sigma_context\n{\npublic:\n    sigma_context(sigma_settings settings_, uint64_t allocateArenaSizeKb_, uint64_t numThreads_, uint64_t numArenaThreads_);\n    bool arenaIsValid();\n    void prepareArenas(CBlockHeader& headerData);\n    void benchmarkSlowHashes(uint8_t* hashData, uint64_t numSlowHashes);\n    void benchmarkFastHashes(uint8_t* hashData1, uint8_t* hashData2, uint8_t* hashData3, uint64_t numFastHashes);\n    void benchmarkFastHashesRef(uint8_t* hashData1, uint8_t* hashData2, uint8_t* hashData3, uint64_t numFastHashes);\n    void benchmarkMining(CBlockHeader& headerData, std::atomic<uint64_t>& slowHashCounter, std::atomic<uint64_t>& halfHashCounter, std::atomic<uint64_t>& skippedHashCounter, std::atomic<uint64_t>&hashCounter, std::atomic<uint64_t>&blockCounter, uint64_t nRoundsTarget);\n    void mineBlock(CBlock* pBlock, std::atomic<uint64_t>& halfHashCounter, uint256& foundBlockHash, bool& interrupt);\n    virtual ~sigma_context();\n    sigma_context(const sigma_context&) = delete;\n    sigma_context& operator=(const sigma_context&) = delete;\npublic:\n    uint64_t numThreads=0;\n    uint64_t numArenaThreads=0;\n    uint64_t allocatedArenaSizeKb=0;\n    uint8_t* arena=nullptr;\nprivate:\n    sigma_settings settings;\n    uint64_t numHashesPossibleWithAvailableMemory=0;\n};\n\n// Light weight sigma context for header verification - allocates just the size of one argon round (16mb)\nclass sigma_verify_context\n{\npublic:\n    sigma_verify_context(sigma_settings settings_, uint64_t numUserVerifyThreads_);\n    // Use verifyLevel to determine which of the fast hashes to check\n    // 0 = Check both\n    // 1 = Check first hash\n    // 2 = Check second hash\n    // NB! Do not use 1 or 2 unless you fully understand the repercussions; If in doubt stick to the default 0\n    // Careless use of 1/2 can allow for carefully crafted attacks to split the chain.\n    template<int verifyLevel=0> bool verifyHeader(CBlockHeader headerData);\n    virtual ~sigma_verify_context();\n    sigma_verify_context(const sigma_verify_context&) = delete;\n    sigma_verify_context& operator=(const sigma_verify_context&) = delete;\nprivate:\n    sigma_settings settings;\n    uint64_t numUserVerifyThreads;\n    uint8_t* hashMem;\n};\n\n#endif\n"
  },
  {
    "path": "src/crypto/hmac_sha256.cpp",
    "content": "// Copyright (c) 2014-2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/hmac_sha256.h\"\n\n#include <string.h>\n\nCHMAC_SHA256::CHMAC_SHA256(const unsigned char* key, size_t keylen)\n{\n    unsigned char rkey[64];\n    if (keylen <= 64) {\n        memcpy(rkey, key, keylen);\n        memset(rkey + keylen, 0, 64 - keylen);\n    } else {\n        CSHA256().Write(key, keylen).Finalize(rkey);\n        memset(rkey + 32, 0, 32);\n    }\n\n    for (int n = 0; n < 64; n++)\n        rkey[n] ^= 0x5c;\n    outer.Write(rkey, 64);\n\n    for (int n = 0; n < 64; n++)\n        rkey[n] ^= 0x5c ^ 0x36;\n    inner.Write(rkey, 64);\n}\n\nvoid CHMAC_SHA256::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    unsigned char temp[32];\n    inner.Finalize(temp);\n    outer.Write(temp, 32).Finalize(hash);\n}\n"
  },
  {
    "path": "src/crypto/hmac_sha256.h",
    "content": "// Copyright (c) 2014-2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_HMAC_SHA256_H\n#define CRYPTO_HMAC_SHA256_H\n\n#include \"crypto/sha256.h\"\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A hasher class for HMAC-SHA-256. */\nclass CHMAC_SHA256\n{\nprivate:\n    CSHA256 outer;\n    CSHA256 inner;\n\npublic:\n    static const size_t OUTPUT_SIZE = 32;\n\n    CHMAC_SHA256(const unsigned char* key, size_t keylen);\n    CHMAC_SHA256& Write(const unsigned char* data, size_t len)\n    {\n        inner.Write(data, len);\n        return *this;\n    }\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n};\n\n#endif\n"
  },
  {
    "path": "src/crypto/hmac_sha512.cpp",
    "content": "// Copyright (c) 2014-2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/hmac_sha512.h\"\n\n#include <string.h>\n\nCHMAC_SHA512::CHMAC_SHA512(const unsigned char* key, size_t keylen)\n{\n    unsigned char rkey[128];\n    if (keylen <= 128) {\n        memcpy(rkey, key, keylen);\n        memset(rkey + keylen, 0, 128 - keylen);\n    } else {\n        CSHA512().Write(key, keylen).Finalize(rkey);\n        memset(rkey + 64, 0, 64);\n    }\n\n    for (int n = 0; n < 128; n++)\n        rkey[n] ^= 0x5c;\n    outer.Write(rkey, 128);\n\n    for (int n = 0; n < 128; n++)\n        rkey[n] ^= 0x5c ^ 0x36;\n    inner.Write(rkey, 128);\n}\n\nvoid CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    unsigned char temp[64];\n    inner.Finalize(temp);\n    outer.Write(temp, 64).Finalize(hash);\n}\n"
  },
  {
    "path": "src/crypto/hmac_sha512.h",
    "content": "// Copyright (c) 2014-2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_HMAC_SHA512_H\n#define CRYPTO_HMAC_SHA512_H\n\n#include \"crypto/sha512.h\"\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A hasher class for HMAC-SHA-512. */\nclass CHMAC_SHA512\n{\nprivate:\n    CSHA512 outer;\n    CSHA512 inner;\n\npublic:\n    static const size_t OUTPUT_SIZE = 64;\n\n    CHMAC_SHA512(const unsigned char* key, size_t keylen);\n    CHMAC_SHA512& Write(const unsigned char* data, size_t len)\n    {\n        inner.Write(data, len);\n        return *this;\n    }\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n};\n\n#endif\n"
  },
  {
    "path": "src/crypto/ripemd160.cpp",
    "content": "// Copyright (c) 2014-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/ripemd160.h\"\n\n#include \"crypto/common.h\"\n\n#include <string.h>\n\n// Internal implementation code.\nnamespace\n{\n/// Internal RIPEMD-160 implementation.\nnamespace ripemd160\n{\nuint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; }\nuint32_t inline f2(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); }\nuint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; }\nuint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); }\nuint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); }\n\n/** Initialize RIPEMD-160 state. */\nvoid inline Initialize(uint32_t* s)\n{\n    s[0] = 0x67452301ul;\n    s[1] = 0xEFCDAB89ul;\n    s[2] = 0x98BADCFEul;\n    s[3] = 0x10325476ul;\n    s[4] = 0xC3D2E1F0ul;\n}\n\nuint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32 - i)); }\n\nvoid inline Round(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r)\n{\n    a = rol(a + f + x + k, r) + e;\n    c = rol(c, 10);\n}\n\nvoid inline R11(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }\nvoid inline R21(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); }\nvoid inline R31(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); }\nvoid inline R41(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); }\nvoid inline R51(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); }\n\nvoid inline R12(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); }\nvoid inline R22(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); }\nvoid inline R32(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); }\nvoid inline R42(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); }\nvoid inline R52(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); }\n\n/** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */\nvoid Transform(uint32_t* s, const unsigned char* chunk)\n{\n    uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4];\n    uint32_t a2 = a1, b2 = b1, c2 = c1, d2 = d1, e2 = e1;\n    uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12);\n    uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28);\n    uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44);\n    uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60);\n\n    R11(a1, b1, c1, d1, e1, w0, 11);\n    R12(a2, b2, c2, d2, e2, w5, 8);\n    R11(e1, a1, b1, c1, d1, w1, 14);\n    R12(e2, a2, b2, c2, d2, w14, 9);\n    R11(d1, e1, a1, b1, c1, w2, 15);\n    R12(d2, e2, a2, b2, c2, w7, 9);\n    R11(c1, d1, e1, a1, b1, w3, 12);\n    R12(c2, d2, e2, a2, b2, w0, 11);\n    R11(b1, c1, d1, e1, a1, w4, 5);\n    R12(b2, c2, d2, e2, a2, w9, 13);\n    R11(a1, b1, c1, d1, e1, w5, 8);\n    R12(a2, b2, c2, d2, e2, w2, 15);\n    R11(e1, a1, b1, c1, d1, w6, 7);\n    R12(e2, a2, b2, c2, d2, w11, 15);\n    R11(d1, e1, a1, b1, c1, w7, 9);\n    R12(d2, e2, a2, b2, c2, w4, 5);\n    R11(c1, d1, e1, a1, b1, w8, 11);\n    R12(c2, d2, e2, a2, b2, w13, 7);\n    R11(b1, c1, d1, e1, a1, w9, 13);\n    R12(b2, c2, d2, e2, a2, w6, 7);\n    R11(a1, b1, c1, d1, e1, w10, 14);\n    R12(a2, b2, c2, d2, e2, w15, 8);\n    R11(e1, a1, b1, c1, d1, w11, 15);\n    R12(e2, a2, b2, c2, d2, w8, 11);\n    R11(d1, e1, a1, b1, c1, w12, 6);\n    R12(d2, e2, a2, b2, c2, w1, 14);\n    R11(c1, d1, e1, a1, b1, w13, 7);\n    R12(c2, d2, e2, a2, b2, w10, 14);\n    R11(b1, c1, d1, e1, a1, w14, 9);\n    R12(b2, c2, d2, e2, a2, w3, 12);\n    R11(a1, b1, c1, d1, e1, w15, 8);\n    R12(a2, b2, c2, d2, e2, w12, 6);\n\n    R21(e1, a1, b1, c1, d1, w7, 7);\n    R22(e2, a2, b2, c2, d2, w6, 9);\n    R21(d1, e1, a1, b1, c1, w4, 6);\n    R22(d2, e2, a2, b2, c2, w11, 13);\n    R21(c1, d1, e1, a1, b1, w13, 8);\n    R22(c2, d2, e2, a2, b2, w3, 15);\n    R21(b1, c1, d1, e1, a1, w1, 13);\n    R22(b2, c2, d2, e2, a2, w7, 7);\n    R21(a1, b1, c1, d1, e1, w10, 11);\n    R22(a2, b2, c2, d2, e2, w0, 12);\n    R21(e1, a1, b1, c1, d1, w6, 9);\n    R22(e2, a2, b2, c2, d2, w13, 8);\n    R21(d1, e1, a1, b1, c1, w15, 7);\n    R22(d2, e2, a2, b2, c2, w5, 9);\n    R21(c1, d1, e1, a1, b1, w3, 15);\n    R22(c2, d2, e2, a2, b2, w10, 11);\n    R21(b1, c1, d1, e1, a1, w12, 7);\n    R22(b2, c2, d2, e2, a2, w14, 7);\n    R21(a1, b1, c1, d1, e1, w0, 12);\n    R22(a2, b2, c2, d2, e2, w15, 7);\n    R21(e1, a1, b1, c1, d1, w9, 15);\n    R22(e2, a2, b2, c2, d2, w8, 12);\n    R21(d1, e1, a1, b1, c1, w5, 9);\n    R22(d2, e2, a2, b2, c2, w12, 7);\n    R21(c1, d1, e1, a1, b1, w2, 11);\n    R22(c2, d2, e2, a2, b2, w4, 6);\n    R21(b1, c1, d1, e1, a1, w14, 7);\n    R22(b2, c2, d2, e2, a2, w9, 15);\n    R21(a1, b1, c1, d1, e1, w11, 13);\n    R22(a2, b2, c2, d2, e2, w1, 13);\n    R21(e1, a1, b1, c1, d1, w8, 12);\n    R22(e2, a2, b2, c2, d2, w2, 11);\n\n    R31(d1, e1, a1, b1, c1, w3, 11);\n    R32(d2, e2, a2, b2, c2, w15, 9);\n    R31(c1, d1, e1, a1, b1, w10, 13);\n    R32(c2, d2, e2, a2, b2, w5, 7);\n    R31(b1, c1, d1, e1, a1, w14, 6);\n    R32(b2, c2, d2, e2, a2, w1, 15);\n    R31(a1, b1, c1, d1, e1, w4, 7);\n    R32(a2, b2, c2, d2, e2, w3, 11);\n    R31(e1, a1, b1, c1, d1, w9, 14);\n    R32(e2, a2, b2, c2, d2, w7, 8);\n    R31(d1, e1, a1, b1, c1, w15, 9);\n    R32(d2, e2, a2, b2, c2, w14, 6);\n    R31(c1, d1, e1, a1, b1, w8, 13);\n    R32(c2, d2, e2, a2, b2, w6, 6);\n    R31(b1, c1, d1, e1, a1, w1, 15);\n    R32(b2, c2, d2, e2, a2, w9, 14);\n    R31(a1, b1, c1, d1, e1, w2, 14);\n    R32(a2, b2, c2, d2, e2, w11, 12);\n    R31(e1, a1, b1, c1, d1, w7, 8);\n    R32(e2, a2, b2, c2, d2, w8, 13);\n    R31(d1, e1, a1, b1, c1, w0, 13);\n    R32(d2, e2, a2, b2, c2, w12, 5);\n    R31(c1, d1, e1, a1, b1, w6, 6);\n    R32(c2, d2, e2, a2, b2, w2, 14);\n    R31(b1, c1, d1, e1, a1, w13, 5);\n    R32(b2, c2, d2, e2, a2, w10, 13);\n    R31(a1, b1, c1, d1, e1, w11, 12);\n    R32(a2, b2, c2, d2, e2, w0, 13);\n    R31(e1, a1, b1, c1, d1, w5, 7);\n    R32(e2, a2, b2, c2, d2, w4, 7);\n    R31(d1, e1, a1, b1, c1, w12, 5);\n    R32(d2, e2, a2, b2, c2, w13, 5);\n\n    R41(c1, d1, e1, a1, b1, w1, 11);\n    R42(c2, d2, e2, a2, b2, w8, 15);\n    R41(b1, c1, d1, e1, a1, w9, 12);\n    R42(b2, c2, d2, e2, a2, w6, 5);\n    R41(a1, b1, c1, d1, e1, w11, 14);\n    R42(a2, b2, c2, d2, e2, w4, 8);\n    R41(e1, a1, b1, c1, d1, w10, 15);\n    R42(e2, a2, b2, c2, d2, w1, 11);\n    R41(d1, e1, a1, b1, c1, w0, 14);\n    R42(d2, e2, a2, b2, c2, w3, 14);\n    R41(c1, d1, e1, a1, b1, w8, 15);\n    R42(c2, d2, e2, a2, b2, w11, 14);\n    R41(b1, c1, d1, e1, a1, w12, 9);\n    R42(b2, c2, d2, e2, a2, w15, 6);\n    R41(a1, b1, c1, d1, e1, w4, 8);\n    R42(a2, b2, c2, d2, e2, w0, 14);\n    R41(e1, a1, b1, c1, d1, w13, 9);\n    R42(e2, a2, b2, c2, d2, w5, 6);\n    R41(d1, e1, a1, b1, c1, w3, 14);\n    R42(d2, e2, a2, b2, c2, w12, 9);\n    R41(c1, d1, e1, a1, b1, w7, 5);\n    R42(c2, d2, e2, a2, b2, w2, 12);\n    R41(b1, c1, d1, e1, a1, w15, 6);\n    R42(b2, c2, d2, e2, a2, w13, 9);\n    R41(a1, b1, c1, d1, e1, w14, 8);\n    R42(a2, b2, c2, d2, e2, w9, 12);\n    R41(e1, a1, b1, c1, d1, w5, 6);\n    R42(e2, a2, b2, c2, d2, w7, 5);\n    R41(d1, e1, a1, b1, c1, w6, 5);\n    R42(d2, e2, a2, b2, c2, w10, 15);\n    R41(c1, d1, e1, a1, b1, w2, 12);\n    R42(c2, d2, e2, a2, b2, w14, 8);\n\n    R51(b1, c1, d1, e1, a1, w4, 9);\n    R52(b2, c2, d2, e2, a2, w12, 8);\n    R51(a1, b1, c1, d1, e1, w0, 15);\n    R52(a2, b2, c2, d2, e2, w15, 5);\n    R51(e1, a1, b1, c1, d1, w5, 5);\n    R52(e2, a2, b2, c2, d2, w10, 12);\n    R51(d1, e1, a1, b1, c1, w9, 11);\n    R52(d2, e2, a2, b2, c2, w4, 9);\n    R51(c1, d1, e1, a1, b1, w7, 6);\n    R52(c2, d2, e2, a2, b2, w1, 12);\n    R51(b1, c1, d1, e1, a1, w12, 8);\n    R52(b2, c2, d2, e2, a2, w5, 5);\n    R51(a1, b1, c1, d1, e1, w2, 13);\n    R52(a2, b2, c2, d2, e2, w8, 14);\n    R51(e1, a1, b1, c1, d1, w10, 12);\n    R52(e2, a2, b2, c2, d2, w7, 6);\n    R51(d1, e1, a1, b1, c1, w14, 5);\n    R52(d2, e2, a2, b2, c2, w6, 8);\n    R51(c1, d1, e1, a1, b1, w1, 12);\n    R52(c2, d2, e2, a2, b2, w2, 13);\n    R51(b1, c1, d1, e1, a1, w3, 13);\n    R52(b2, c2, d2, e2, a2, w13, 6);\n    R51(a1, b1, c1, d1, e1, w8, 14);\n    R52(a2, b2, c2, d2, e2, w14, 5);\n    R51(e1, a1, b1, c1, d1, w11, 11);\n    R52(e2, a2, b2, c2, d2, w0, 15);\n    R51(d1, e1, a1, b1, c1, w6, 8);\n    R52(d2, e2, a2, b2, c2, w3, 13);\n    R51(c1, d1, e1, a1, b1, w15, 5);\n    R52(c2, d2, e2, a2, b2, w9, 11);\n    R51(b1, c1, d1, e1, a1, w13, 6);\n    R52(b2, c2, d2, e2, a2, w11, 11);\n\n    uint32_t t = s[0];\n    s[0] = s[1] + c1 + d2;\n    s[1] = s[2] + d1 + e2;\n    s[2] = s[3] + e1 + a2;\n    s[3] = s[4] + a1 + b2;\n    s[4] = t + b1 + c2;\n}\n\n} // namespace ripemd160\n\n} // namespace\n\n////// RIPEMD160\n\nCRIPEMD160::CRIPEMD160() : bytes(0)\n{\n    ripemd160::Initialize(s);\n}\n\nCRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len)\n{\n    const unsigned char* end = data + len;\n    size_t bufsize = bytes % 64;\n    if (bufsize && bufsize + len >= 64) {\n        // Fill the buffer, and process it.\n        memcpy(buf + bufsize, data, 64 - bufsize);\n        bytes += 64 - bufsize;\n        data += 64 - bufsize;\n        ripemd160::Transform(s, buf);\n        bufsize = 0;\n    }\n    while (end - data >= 64) {\n        // Process full chunks directly from the source.\n        ripemd160::Transform(s, data);\n        bytes += 64;\n        data += 64;\n    }\n    if (end > data) {\n        // Fill the buffer with what remains.\n        memcpy(buf + bufsize, data, end - data);\n        bytes += end - data;\n    }\n    return *this;\n}\n\nvoid CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    static const unsigned char pad[64] = {0x80};\n    unsigned char sizedesc[8];\n    WriteLE64(sizedesc, bytes << 3);\n    Write(pad, 1 + ((119 - (bytes % 64)) % 64));\n    Write(sizedesc, 8);\n    WriteLE32(hash, s[0]);\n    WriteLE32(hash + 4, s[1]);\n    WriteLE32(hash + 8, s[2]);\n    WriteLE32(hash + 12, s[3]);\n    WriteLE32(hash + 16, s[4]);\n}\n\nCRIPEMD160& CRIPEMD160::Reset()\n{\n    bytes = 0;\n    ripemd160::Initialize(s);\n    return *this;\n}\n"
  },
  {
    "path": "src/crypto/ripemd160.h",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_RIPEMD160_H\n#define CRYPTO_RIPEMD160_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A hasher class for RIPEMD-160. */\nclass CRIPEMD160\n{\nprivate:\n    uint32_t s[5];\n    unsigned char buf[64];\n    uint64_t bytes;\n\npublic:\n    static const size_t OUTPUT_SIZE = 20;\n\n    CRIPEMD160();\n    CRIPEMD160& Write(const unsigned char* data, size_t len);\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n    CRIPEMD160& Reset();\n};\n\n#endif\n"
  },
  {
    "path": "src/crypto/scrypt/COPYING",
    "content": "The included code and documentation (\"scrypt\") is distributed under the\nfollowing terms:\n\nCopyright 2005-2016 Colin Percival.  All rights reserved.\nCopyright 2005-2016 Tarsnap Backup Inc.  All rights reserved.\nCopyright 2014 Sean Kelly.  All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "src/crypto/scrypt/README.md",
    "content": "This implementation of scrypt is taken from the original scrypt author Colin Percival - repo  https://github.com/Tarsnap/scrypt and modified for use in the Munt codebase.\nFor copyright see file COPYING\n\nCurrently updated to upstream commit 0d154538000209fb6099ff0356295249b85ea1e0\nPlease update the commit hash in this file when merging any changes from upstream.\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt.cpp",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#include <sys/types.h>\n//#include <sys/mman.h>\n\n#include <errno.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <crypto/sha256.h>\n#include \"sha256_scrypt.h\"\n\n#include \"crypto_scrypt_smix.h\"\n#include \"crypto_scrypt_smix_sse2.h\"\n\n#include \"crypto_scrypt.h\"\n\nstatic void (*smix_func)(uint8_t*, size_t, uint64_t, void*, void*) = NULL;\n\n/* _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix):\n * Perform the requested scrypt computation, using ${smix} as the smix routine.\n */\nstatic int _crypto_scrypt(const uint8_t* passwd, size_t passwdlen, const uint8_t* salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, uint8_t* buf, size_t buflen, void (*smix)(uint8_t*, size_t, uint64_t, void*, void*))\n{\n    void* B0; void* V0; void* XY0;\n    uint8_t* B;\n    uint32_t* V;\n    uint32_t* XY;\n    size_t r = _r, p = _p;\n    uint32_t i;\n\n    // Sanity-check parameters.\n#if SIZE_MAX > UINT32_MAX\n    if (buflen > (((uint64_t)(1) << 32) - 1) * 32)\n    {\n        errno = EFBIG;\n        goto err0;\n    }\n#endif\n    if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30))\n    {\n        errno = EFBIG;\n        goto err0;\n    }\n    if (((N & (N - 1)) != 0) || (N < 2))\n    {\n        errno = EINVAL;\n        goto err0;\n    }\n    if ((r > SIZE_MAX / 128 / p) ||\n#if SIZE_MAX / 256 <= UINT32_MAX\n        (r > (SIZE_MAX - 64) / 256) ||\n#endif\n        (N > SIZE_MAX / 128 / r))\n    {\n        errno = ENOMEM;\n        goto err0;\n    }\n\n    // Allocate memory.\n#ifdef HAVE_POSIX_MEMALIGN\n    if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)\n        goto err0;\n    B = (uint8_t *)(B0);\n    (errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)\n        goto err1;\n    XY = (uint32_t *)(XY0);\n#if !defined(MAP_ANON) || !defined(HAVE_MMAP)\n    if ((errno = posix_memalign(&V0, 64, (size_t)(128 * r * N))) != 0)\n        goto err2;\n    V = (uint32_t *)(V0);\n#endif\n#else\n    if ((B0 = malloc(128 * r * p + 63)) == NULL)\n        goto err0;\n    B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));\n    if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)\n        goto err1;\n    XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));\n#if !defined(MAP_ANON) || !defined(HAVE_MMAP)\n    if ((V0 = malloc(128 * r * N + 63)) == NULL)\n        goto err2;\n    V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));\n#endif\n#endif\n#if defined(MAP_ANON) && defined(HAVE_MMAP)\n    if ((V0 = mmap(NULL, (size_t)(128 * r * N), PROT_READ | PROT_WRITE,\n#ifdef MAP_NOCORE\n        MAP_ANON | MAP_PRIVATE | MAP_NOCORE,\n#else\n        MAP_ANON | MAP_PRIVATE,\n#endif\n        -1, 0)) == MAP_FAILED)\n        goto err2;\n    V = (uint32_t *)(V0);\n#endif\n\n    // 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen)\n    PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);\n\n    // 2: for i = 0 to p - 1 do\n    for (i = 0; i < p; i++)\n    {\n        // 3: B_i <-- MF(B_i, N)\n        (smix)(&B[i * 128 * r], r, N, V, XY);\n    }\n\n    // 5: DK <-- PBKDF2(P, B, 1, dkLen)\n    PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);\n\n    // Free memory.\n#if defined(MAP_ANON) && defined(HAVE_MMAP)\n    if (munmap(V0, (size_t)(128 * r * N)))\n        goto err2;\n#else\n    free(V0);\n#endif\n    free(XY0);\n    free(B0);\n\n    // Success!\n    return (0);\n\nerr2:\n    free(XY0);\nerr1:\n    free(B0);\nerr0:\n    // Failure!\n    return (-1);\n}\n\n#define TESTLEN 64\nstatic struct scrypt_test {\n    const char* passwd;\n    const char* salt;\n    uint64_t N;\n    uint32_t r;\n    uint32_t p;\n    uint8_t result[TESTLEN];\n} testcase = {\n    .passwd = \"pleaseletmein\",\n    .salt = \"SodiumChloride\",\n    .N = 16,\n    .r = 8,\n    .p = 1,\n    .result = { 0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09, 0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16, 0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf, 0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf, 0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b, 0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11, 0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7, 0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b }\n};\n\nstatic bool testsmix(void (*smix)(uint8_t*, size_t, uint64_t, void*, void*))\n{\n    uint8_t hbuf[TESTLEN];\n\n    // Perform the computation.\n    if (_crypto_scrypt(\n        (const uint8_t*)testcase.passwd, strlen(testcase.passwd),\n        (const uint8_t*)testcase.salt, strlen(testcase.salt),\n        testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix))\n        return true;\n\n    // Does it match?\n    return (memcmp(testcase.result, hbuf, TESTLEN) == 0);\n}\n\nstatic void selectsmix(void)\n{\n\n#ifdef CPUSUPPORT_X86_SSE2\n    // If we're running on an SSE2-capable CPU, try that code.\n    if (cpusupport_x86_sse2()) {\n        // If SSE2ized smix works, use it.\n        if (testsmix(crypto_scrypt_smix_sse2)) {\n            smix_func = crypto_scrypt_smix_sse2;\n            return;\n        }\n        //fixme: (FUT) Re-enable warning here\n        //warn0(\"Disabling broken SSE2 scrypt support - please report bug!\");\n    }\n#endif\n\n    // If generic smix works, use it.\n    if (testsmix(crypto_scrypt_smix)) {\n        smix_func = crypto_scrypt_smix;\n        return;\n    }\n    //fixme: (FUT) Re-enable warning here\n    //warn0(\"Generic scrypt code is broken - please report bug!\");\n\n    // If we get here, something really bad happened.\n    abort();\n}\n\nint crypto_scrypt(const uint8_t* passwd, size_t passwdlen, const uint8_t* salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, uint8_t* buf, size_t buflen)\n{\n    if (smix_func == NULL)\n        selectsmix();\n\n    return (_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p,\n        buf, buflen, smix_func));\n}\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt.h",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n\n#ifndef _CRYPTO_SCRYPT_H_\n#define _CRYPTO_SCRYPT_H_\n\n#include <stdint.h>\n#include <unistd.h>\n\n/**\n * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):\n * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,\n * p, buflen) and write the result into buf.  The parameters r, p, and buflen\n * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N\n * must be a power of 2 greater than 1.\n *\n * Return 0 on success; or -1 on error.\n */\nint crypto_scrypt(const uint8_t*, size_t, const uint8_t*, size_t, uint64_t, uint32_t, uint32_t, uint8_t*, size_t);\n\n#endif\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt_smix.cpp",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#include <stdint.h>\n\n#include \"crypto_scrypt_smix.h\"\n#include <compat/endian.h>\n\nstatic void blkcpy(void*, const void*, size_t);\nstatic void blkxor(void*, const void*, size_t);\nstatic void salsa20_8(uint32_t[16]);\nstatic void blockmix_salsa8(const uint32_t*, uint32_t*, uint32_t*, size_t);\nstatic uint64_t integerify(const void *, size_t);\n\nstatic void blkcpy(void* dest, const void* src, size_t len)\n{\n    size_t* D = (size_t*)dest;\n    const size_t * S = (const size_t*)src;\n    size_t L = len / sizeof(size_t);\n    size_t i;\n\n    for (i = 0; i < L; i++)\n    {\n        D[i] = S[i];\n    }\n}\n\nstatic void blkxor(void* dest, const void* src, size_t len)\n{\n    size_t* D = (size_t*)dest;\n    const size_t * S = (size_t*)src;\n    size_t L = len / sizeof(size_t);\n    size_t i;\n\n    for (i = 0; i < L; i++)\n    {\n        D[i] ^= S[i];\n    }\n}\n\n/* salsa20_8(B):\n * Apply the salsa20/8 core to the provided block.\n */\nstatic void salsa20_8(uint32_t B[16])\n{\n    uint32_t x[16];\n    size_t i;\n\n    blkcpy(x, B, 64);\n    for (i = 0; i < 8; i += 2)\n    {\n#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))\n        // Operate on columns.\n        x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);\n        x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);\n\n        x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);\n        x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);\n\n        x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);\n        x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);\n\n        x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);\n        x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);\n\n        // Operate on rows.\n        x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);\n        x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);\n\n        x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);\n        x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);\n\n        x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);\n        x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);\n\n        x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);\n        x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);\n#undef R\n    }\n    for (i = 0; i < 16; i++)\n    {\n        B[i] += x[i];\n    }\n}\n\n/* blockmix_salsa8(Bin, Bout, X, r):\n * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r\n * bytes in length; the output Bout must also be the same size.  The\n * temporary space X must be 64 bytes.\n */\nstatic void blockmix_salsa8(const uint32_t* Bin, uint32_t* Bout, uint32_t* X, size_t r)\n{\n    size_t i;\n\n    // 1: X <-- B_{2r - 1}\n    blkcpy(X, &Bin[(2 * r - 1) * 16], 64);\n\n    // 2: for i = 0 to 2r - 1 do\n    for (i = 0; i < 2 * r; i += 2)\n    {\n        // 3: X <-- H(X \\xor B_i)\n        blkxor(X, &Bin[i * 16], 64);\n        salsa20_8(X);\n\n        // 4: Y_i <-- X\n        // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})\n        blkcpy(&Bout[i * 8], X, 64);\n\n        // 3: X <-- H(X \\xor B_i)\n        blkxor(X, &Bin[i * 16 + 16], 64);\n        salsa20_8(X);\n\n        // 4: Y_i <-- X\n        // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})\n        blkcpy(&Bout[i * 8 + r * 16], X, 64);\n    }\n}\n\n\n/* integerify(B, r):\n * Return the result of parsing B_{2r-1} as a little-endian integer.\n */\nstatic uint64_t integerify(const void* B, size_t r)\n{\n    const uint32_t * X = (const uint32_t*)((uintptr_t)(B) + (2 * r - 1) * 64);\n\n    return (((uint64_t)(X[1]) << 32) + X[0]);\n}\n\nvoid crypto_scrypt_smix(uint8_t* B, size_t r, uint64_t N, void* _V, void* XY)\n{\n    uint32_t* X = (uint32_t*)XY;\n    uint32_t* Y = (uint32_t*)((uint8_t*)(XY) + 128 * r);\n    uint32_t* Z = (uint32_t*)((uint8_t*)(XY) + 256 * r);\n    uint32_t* V = (uint32_t*)_V;\n    uint64_t i;\n    uint64_t j;\n    size_t k;\n\n    // 1: X <-- B\n    for (k = 0; k < 32 * r; k++)\n    {\n        X[k] = le32dec(&B[4 * k]);\n    }\n\n    // 2: for i = 0 to N - 1 do\n    for (i = 0; i < N; i += 2)\n    {\n        // 3: V_i <-- X\n        blkcpy(&V[i * (32 * r)], X, 128 * r);\n\n        // 4: X <-- H(X)\n        blockmix_salsa8(X, Y, Z, r);\n\n        // 3: V_i <-- X\n        blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);\n\n        // 4: X <-- H(X)\n        blockmix_salsa8(Y, X, Z, r);\n    }\n\n    // 6: for i = 0 to N - 1 do\n    for (i = 0; i < N; i += 2)\n    {\n        // 7: j <-- Integerify(X) mod N\n        j = integerify(X, r) & (N - 1);\n\n        // 8: X <-- H(X \\xor V_j)\n        blkxor(X, &V[j * (32 * r)], 128 * r);\n        blockmix_salsa8(X, Y, Z, r);\n\n        // 7: j <-- Integerify(X) mod N\n        j = integerify(Y, r) & (N - 1);\n\n        // 8: X <-- H(X \\xor V_j)\n        blkxor(Y, &V[j * (32 * r)], 128 * r);\n        blockmix_salsa8(Y, X, Z, r);\n    }\n\n    // 10: B' <-- X\n    for (k = 0; k < 32 * r; k++)\n    {\n        le32enc(&B[4 * k], X[k]);\n    }\n}\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt_smix.h",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n\n#ifndef _CRYPTO_SCRYPT_SMIX_H_\n#define _CRYPTO_SCRYPT_SMIX_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\n/**\n * crypto_scrypt_smix(B, r, N, V, XY):\n * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;\n * the temporary storage V must be 128rN bytes in length; the temporary\n * storage XY must be 256r + 64 bytes in length.  The value N must be a\n * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a\n * multiple of 64 bytes.\n */\nvoid crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *);\n\n#endif\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt_smix_sse2.cpp",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#if defined(USE_SSE2)\n\n#include <emmintrin.h>\n#include <stdint.h>\n\n#include \"sysendian.h\"\n\n#include \"crypto_scrypt_smix_sse2.h\"\n\nstatic void blkcpy(void*, const void*, size_t);\nstatic void blkxor(void*, const void*, size_t);\nstatic void salsa20_8(__m128i*);\nstatic void blockmix_salsa8(const __m128i*, __m128i*, __m128i*, size_t);\nstatic uint64_t integerify(const void*, size_t);\n\nstatic void blkcpy(void* dest, const void* src, size_t len)\n{\n    __m128i* D = dest;\n    const __m128i* S = src;\n    size_t L = len / 16;\n    size_t i;\n\n    for (i = 0; i < L; i++)\n    {\n        D[i] = S[i];\n    }\n}\n\nstatic void blkxor(void* dest, const void* src, size_t len)\n{\n    __m128i* D = dest;\n    const __m128i* S = src;\n    size_t L = len / 16;\n    size_t i;\n\n    for (i = 0; i < L; i++)\n    {\n        D[i] = _mm_xor_si128(D[i], S[i]);\n    }\n}\n\n/* salsa20_8(B):\n * Apply the salsa20/8 core to the provided block.\n */\nstatic void salsa20_8(__m128i B[4])\n{\n    __m128i X0, X1, X2, X3;\n    __m128i T;\n    size_t i;\n\n    X0 = B[0];\n    X1 = B[1];\n    X2 = B[2];\n    X3 = B[3];\n\n    for (i = 0; i < 8; i += 2)\n    {\n        // Operate on \"columns\".\n        T = _mm_add_epi32(X0, X3);\n        X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));\n        X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));\n        T = _mm_add_epi32(X1, X0);\n        X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));\n        X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));\n        T = _mm_add_epi32(X2, X1);\n        X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));\n        X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));\n        T = _mm_add_epi32(X3, X2);\n        X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));\n        X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));\n\n        // Rearrange data.\n        X1 = _mm_shuffle_epi32(X1, 0x93);\n        X2 = _mm_shuffle_epi32(X2, 0x4E);\n        X3 = _mm_shuffle_epi32(X3, 0x39);\n\n        // Operate on \"rows\".\n        T = _mm_add_epi32(X0, X1);\n        X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));\n        X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));\n        T = _mm_add_epi32(X3, X0);\n        X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));\n        X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));\n        T = _mm_add_epi32(X2, X3);\n        X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));\n        X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));\n        T = _mm_add_epi32(X1, X2);\n        X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));\n        X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));\n\n        // Rearrange data.\n        X1 = _mm_shuffle_epi32(X1, 0x39);\n        X2 = _mm_shuffle_epi32(X2, 0x4E);\n        X3 = _mm_shuffle_epi32(X3, 0x93);\n    }\n\n    B[0] = _mm_add_epi32(B[0], X0);\n    B[1] = _mm_add_epi32(B[1], X1);\n    B[2] = _mm_add_epi32(B[2], X2);\n    B[3] = _mm_add_epi32(B[3], X3);\n}\n\n/* blockmix_salsa8(Bin, Bout, X, r):\n * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r\n * bytes in length; the output Bout must also be the same size.  The\n * temporary space X must be 64 bytes.\n */\nstatic void blockmix_salsa8(const __m128i* Bin, __m128i* Bout, __m128i* X, size_t r)\n{\n    size_t i;\n\n    // 1: X <-- B_{2r - 1}\n    blkcpy(X, &Bin[8 * r - 4], 64);\n\n    // 2: for i = 0 to 2r - 1 do\n    for (i = 0; i < r; i++) {\n        // 3: X <-- H(X \\xor B_i)\n        blkxor(X, &Bin[i * 8], 64);\n        salsa20_8(X);\n\n        // 4: Y_i <-- X\n        // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})\n        blkcpy(&Bout[i * 4], X, 64);\n\n        /* 3: X <-- H(X \\xor B_i) */\n        blkxor(X, &Bin[i * 8 + 4], 64);\n        salsa20_8(X);\n\n        // 4: Y_i <-- X\n        // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})\n        blkcpy(&Bout[(r + i) * 4], X, 64);\n    }\n}\n\n/* integerify(B, r):\n * Return the result of parsing B_{2r-1} as a little-endian integer.\n * Note that B's layout is permuted compared to the generic implementation.\n */\nstatic uint64_t integerify(const void* B, size_t r)\n{\n    const uint32_t* X = (const void*)((uintptr_t)(B) + (2 * r - 1) * 64);\n\n    return (((uint64_t)(X[13]) << 32) + X[0]);\n}\n\nvoid crypto_scrypt_smix_sse2(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)\n{\n    __m128i* X = XY;\n    __m128i* Y = (void*)((uintptr_t)(XY) + 128 * r);\n    __m128i* Z = (void*)((uintptr_t)(XY) + 256 * r);\n    uint32_t* X32 = (void*)X;\n    uint64_t i, j;\n    size_t k;\n\n    // 1: X <-- B\n    for (k = 0; k < 2 * r; k++)\n    {\n        for (i = 0; i < 16; i++)\n        {\n            X32[k * 16 + i] = le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);\n        }\n    }\n\n    // 2: for i = 0 to N - 1 do\n    for (i = 0; i < N; i += 2)\n    {\n        // 3: V_i <-- X\n        blkcpy((void*)((uintptr_t)(V) + i * 128 * r), X, 128 * r);\n\n        // 4: X <-- H(X)\n        blockmix_salsa8(X, Y, Z, r);\n\n        // 3: V_i <-- X\n        blkcpy((void*)((uintptr_t)(V) + (i + 1) * 128 * r), Y, 128 * r);\n\n        // 4: X <-- H(X)\n        blockmix_salsa8(Y, X, Z, r);\n    }\n\n    // 6: for i = 0 to N - 1 do\n    for (i = 0; i < N; i += 2)\n    {\n        // 7: j <-- Integerify(X) mod N\n        j = integerify(X, r) & (N - 1);\n\n        // 8: X <-- H(X \\xor V_j)\n        blkxor(X, (void*)((uintptr_t)(V) + j * 128 * r), 128 * r);\n        blockmix_salsa8(X, Y, Z, r);\n\n        // 7: j <-- Integerify(X) mod N\n        j = integerify(Y, r) & (N - 1);\n\n        // 8: X <-- H(X \\xor V_j)\n        blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);\n        blockmix_salsa8(Y, X, Z, r);\n    }\n\n    // 10: B' <-- X\n    for (k = 0; k < 2 * r; k++)\n    {\n        for (i = 0; i < 16; i++)\n        {\n            le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], X32[k * 16 + i]);\n        }\n    }\n}\n\n#endif /* CPUSUPPORT_X86_SSE2 */\n"
  },
  {
    "path": "src/crypto/scrypt/crypto_scrypt_smix_sse2.h",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#ifndef _CRYPTO_SCRYPT_SMIX_SSE2_H_\n#define _CRYPTO_SCRYPT_SMIX_SSE2_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\n/**\n * crypto_scrypt_smix_sse2(B, r, N, V, XY):\n * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;\n * the temporary storage V must be 128rN bytes in length; the temporary\n * storage XY must be 256r + 64 bytes in length.  The value N must be a\n * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a\n * multiple of 64 bytes.\n *\n * Use SSE2 instructions.\n */\nvoid crypto_scrypt_smix_sse2(uint8_t*, size_t, uint64_t, void*, void*);\n\n#endif\n"
  },
  {
    "path": "src/crypto/scrypt/sha256_scrypt.cpp",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#include \"sha256_scrypt.h\"\n\n#include <assert.h>\n#include \"string.h\"\n#include <crypto/sha256.h>\n\n\nvoid HMAC_SHA256_Init(HMAC_SHA256_CTX* ctx, const void* _K, size_t Klen)\n{\n    unsigned char pad[64];\n    unsigned char khash[32];\n    const unsigned char *K = (const unsigned char *)_K;\n    size_t i;\n\n    // If Klen > 64, the key is really SHA256(K).\n    if (Klen > 64)\n    {\n        ctx->ictx.Reset();\n        ctx->ictx.Write(K, Klen);\n        ctx->ictx.Finalize(khash);\n        K = khash;\n        Klen = 32;\n    }\n\n    // Inner SHA256 operation is SHA256(K xor [block of 0x36] || data).\n    ctx->ictx.Reset();\n    memset(pad, 0x36, 64);\n    for (i = 0; i < Klen; i++)\n    {\n        pad[i] ^= K[i];\n    }\n    ctx->ictx.Write(pad, 64);\n\n    // Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash).\n    ctx->octx.Reset();\n    memset(pad, 0x5c, 64);\n    for (i = 0; i < Klen; i++)\n    {\n        pad[i] ^= K[i];\n    }\n    ctx->octx.Write(pad, 64);\n\n    // Clean the stack.\n    memset(khash, 0, 32);\n}\n\nvoid HMAC_SHA256_Update(HMAC_SHA256_CTX* ctx, const void* in, size_t len)\n{\n    // Feed data to the inner SHA256 operation.\n    ctx->ictx.Write((unsigned char*)in, len);\n}\n\nvoid HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX* ctx)\n{\n    unsigned char ihash[32];\n\n    // Finish the inner SHA256 operation.\n    ctx->ictx.Finalize(ihash);\n\n    // Feed the inner hash to the outer SHA256 operation.\n    ctx->octx.Write(ihash, 32);\n\n    // Finish the outer SHA256 operation.\n    ctx->octx.Finalize(digest);\n\n    // Clean the stack.\n    memset(ihash, 0, 32);\n}\n\nvoid PBKDF2_SHA256(const uint8_t* passwd, size_t passwdlen, const uint8_t* salt, size_t saltlen, uint64_t c, uint8_t* buf, size_t dkLen)\n{\n    HMAC_SHA256_CTX PShctx, hctx;\n    size_t i;\n    uint8_t ivec[4];\n    uint8_t U[32];\n    uint8_t T[32];\n    uint64_t j;\n    int k;\n    size_t clen;\n\n    // Compute HMAC state after processing P and S.\n    HMAC_SHA256_Init(&PShctx, passwd, passwdlen);\n    HMAC_SHA256_Update(&PShctx, salt, saltlen);\n\n    // Iterate through the blocks.\n    for (i = 0; i * 32 < dkLen; i++)\n    {\n        // Generate INT(i + 1).\n        be32enc(ivec, (uint32_t)(i + 1));\n\n        // Compute U_1 = PRF(P, S || INT(i)).\n        memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));\n        HMAC_SHA256_Update(&hctx, ivec, 4);\n        HMAC_SHA256_Final(U, &hctx);\n\n        // T_i = U_1 ...\n        memcpy(T, U, 32);\n\n        for (j = 2; j <= c; j++)\n        {\n            // Compute U_j.\n            HMAC_SHA256_Init(&hctx, passwd, passwdlen);\n            HMAC_SHA256_Update(&hctx, U, 32);\n            HMAC_SHA256_Final(U, &hctx);\n\n            // ... xor U_j ...\n            for (k = 0; k < 32; k++)\n            {\n                T[k] ^= U[k];\n            }\n        }\n\n        // Copy as many bytes as necessary into buf.\n        clen = dkLen - i * 32;\n        if (clen > 32)\n        {\n            clen = 32;\n        }\n        memcpy(&buf[i * 32], T, clen);\n    }\n\n    // Clean PShctx, since we never called _Final on it.\n    memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));\n}\n"
  },
  {
    "path": "src/crypto/scrypt/sha256_scrypt.h",
    "content": "// -\n// Copyright 2009 Colin Percival\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n// SUCH DAMAGE.\n//\n// The code in this file is taken from a file which was originally written by Colin Percival as part of the Tarsnap\n// online backup system.\n// -\n//\n// File contains modifications by: Centure developers\n// All modifications:\n// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING in the root of this repository\n\n#include <assert.h>\n#include <compat/endian.h>\n#include <support/cleanse.h>\n#include <crypto/sha256.h>\n\n/* Context structure for HMAC-SHA256 operations. */\ntypedef struct {\n\tCSHA256 ictx;\n\tCSHA256 octx;\n} HMAC_SHA256_CTX;\n\n/* SHA256 round constants. */\nstatic const uint32_t Krnd[64] = {\n\t0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\n\t0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n\t0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n\t0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n\t0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n\t0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n\t0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\n\t0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n\t0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n\t0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n\t0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\n\t0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n\t0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\n\t0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n\t0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n\t0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n};\n\n\n/* Initialize an HMAC-SHA256 operation with the given key. */\nvoid HMAC_SHA256_Init(HMAC_SHA256_CTX* ctx, const void *_K, size_t Klen);\n\n/* Add bytes to the HMAC-SHA256 operation. */\nvoid HMAC_SHA256_Update(HMAC_SHA256_CTX* ctx, const void *in, size_t len);\n\n/* Finish an HMAC-SHA256 operation. */\nvoid HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX* ctx);\n\n/**\n * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):\n * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and\n * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).\n */\nvoid PBKDF2_SHA256(const uint8_t* passwd, size_t passwdlen, const uint8_t* salt, size_t saltlen, uint64_t c, uint8_t* buf, size_t dkLen);\n"
  },
  {
    "path": "src/crypto/sha1.cpp",
    "content": "// Copyright (c) 2014-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/sha1.h\"\n\n#include \"crypto/common.h\"\n\n#include <string.h>\n\n// Internal implementation code.\nnamespace\n{\n/// Internal SHA-1 implementation.\nnamespace sha1\n{\n/** One round of SHA-1. */\nvoid inline Round(uint32_t a, uint32_t& b, uint32_t c, uint32_t d, uint32_t& e, uint32_t f, uint32_t k, uint32_t w)\n{\n    e += ((a << 5) | (a >> 27)) + f + k + w;\n    b = (b << 30) | (b >> 2);\n}\n\nuint32_t inline f1(uint32_t b, uint32_t c, uint32_t d) { return d ^ (b & (c ^ d)); }\nuint32_t inline f2(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; }\nuint32_t inline f3(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (d & (b | c)); }\n\nuint32_t inline left(uint32_t x) { return (x << 1) | (x >> 31); }\n\n/** Initialize SHA-1 state. */\nvoid inline Initialize(uint32_t* s)\n{\n    s[0] = 0x67452301ul;\n    s[1] = 0xEFCDAB89ul;\n    s[2] = 0x98BADCFEul;\n    s[3] = 0x10325476ul;\n    s[4] = 0xC3D2E1F0ul;\n}\n\nconst uint32_t k1 = 0x5A827999ul;\nconst uint32_t k2 = 0x6ED9EBA1ul;\nconst uint32_t k3 = 0x8F1BBCDCul;\nconst uint32_t k4 = 0xCA62C1D6ul;\n\n/** Perform a SHA-1 transformation, processing a 64-byte chunk. */\nvoid Transform(uint32_t* s, const unsigned char* chunk)\n{\n    uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4];\n    uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;\n\n    Round(a, b, c, d, e, f1(b, c, d), k1, w0 = ReadBE32(chunk + 0));\n    Round(e, a, b, c, d, f1(a, b, c), k1, w1 = ReadBE32(chunk + 4));\n    Round(d, e, a, b, c, f1(e, a, b), k1, w2 = ReadBE32(chunk + 8));\n    Round(c, d, e, a, b, f1(d, e, a), k1, w3 = ReadBE32(chunk + 12));\n    Round(b, c, d, e, a, f1(c, d, e), k1, w4 = ReadBE32(chunk + 16));\n    Round(a, b, c, d, e, f1(b, c, d), k1, w5 = ReadBE32(chunk + 20));\n    Round(e, a, b, c, d, f1(a, b, c), k1, w6 = ReadBE32(chunk + 24));\n    Round(d, e, a, b, c, f1(e, a, b), k1, w7 = ReadBE32(chunk + 28));\n    Round(c, d, e, a, b, f1(d, e, a), k1, w8 = ReadBE32(chunk + 32));\n    Round(b, c, d, e, a, f1(c, d, e), k1, w9 = ReadBE32(chunk + 36));\n    Round(a, b, c, d, e, f1(b, c, d), k1, w10 = ReadBE32(chunk + 40));\n    Round(e, a, b, c, d, f1(a, b, c), k1, w11 = ReadBE32(chunk + 44));\n    Round(d, e, a, b, c, f1(e, a, b), k1, w12 = ReadBE32(chunk + 48));\n    Round(c, d, e, a, b, f1(d, e, a), k1, w13 = ReadBE32(chunk + 52));\n    Round(b, c, d, e, a, f1(c, d, e), k1, w14 = ReadBE32(chunk + 56));\n    Round(a, b, c, d, e, f1(b, c, d), k1, w15 = ReadBE32(chunk + 60));\n\n    Round(e, a, b, c, d, f1(a, b, c), k1, w0 = left(w0 ^ w13 ^ w8 ^ w2));\n    Round(d, e, a, b, c, f1(e, a, b), k1, w1 = left(w1 ^ w14 ^ w9 ^ w3));\n    Round(c, d, e, a, b, f1(d, e, a), k1, w2 = left(w2 ^ w15 ^ w10 ^ w4));\n    Round(b, c, d, e, a, f1(c, d, e), k1, w3 = left(w3 ^ w0 ^ w11 ^ w5));\n    Round(a, b, c, d, e, f2(b, c, d), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6));\n    Round(e, a, b, c, d, f2(a, b, c), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7));\n    Round(d, e, a, b, c, f2(e, a, b), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8));\n    Round(c, d, e, a, b, f2(d, e, a), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9));\n    Round(b, c, d, e, a, f2(c, d, e), k2, w8 = left(w8 ^ w5 ^ w0 ^ w10));\n    Round(a, b, c, d, e, f2(b, c, d), k2, w9 = left(w9 ^ w6 ^ w1 ^ w11));\n    Round(e, a, b, c, d, f2(a, b, c), k2, w10 = left(w10 ^ w7 ^ w2 ^ w12));\n    Round(d, e, a, b, c, f2(e, a, b), k2, w11 = left(w11 ^ w8 ^ w3 ^ w13));\n    Round(c, d, e, a, b, f2(d, e, a), k2, w12 = left(w12 ^ w9 ^ w4 ^ w14));\n    Round(b, c, d, e, a, f2(c, d, e), k2, w13 = left(w13 ^ w10 ^ w5 ^ w15));\n    Round(a, b, c, d, e, f2(b, c, d), k2, w14 = left(w14 ^ w11 ^ w6 ^ w0));\n    Round(e, a, b, c, d, f2(a, b, c), k2, w15 = left(w15 ^ w12 ^ w7 ^ w1));\n\n    Round(d, e, a, b, c, f2(e, a, b), k2, w0 = left(w0 ^ w13 ^ w8 ^ w2));\n    Round(c, d, e, a, b, f2(d, e, a), k2, w1 = left(w1 ^ w14 ^ w9 ^ w3));\n    Round(b, c, d, e, a, f2(c, d, e), k2, w2 = left(w2 ^ w15 ^ w10 ^ w4));\n    Round(a, b, c, d, e, f2(b, c, d), k2, w3 = left(w3 ^ w0 ^ w11 ^ w5));\n    Round(e, a, b, c, d, f2(a, b, c), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6));\n    Round(d, e, a, b, c, f2(e, a, b), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7));\n    Round(c, d, e, a, b, f2(d, e, a), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8));\n    Round(b, c, d, e, a, f2(c, d, e), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9));\n    Round(a, b, c, d, e, f3(b, c, d), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10));\n    Round(e, a, b, c, d, f3(a, b, c), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11));\n    Round(d, e, a, b, c, f3(e, a, b), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12));\n    Round(c, d, e, a, b, f3(d, e, a), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13));\n    Round(b, c, d, e, a, f3(c, d, e), k3, w12 = left(w12 ^ w9 ^ w4 ^ w14));\n    Round(a, b, c, d, e, f3(b, c, d), k3, w13 = left(w13 ^ w10 ^ w5 ^ w15));\n    Round(e, a, b, c, d, f3(a, b, c), k3, w14 = left(w14 ^ w11 ^ w6 ^ w0));\n    Round(d, e, a, b, c, f3(e, a, b), k3, w15 = left(w15 ^ w12 ^ w7 ^ w1));\n\n    Round(c, d, e, a, b, f3(d, e, a), k3, w0 = left(w0 ^ w13 ^ w8 ^ w2));\n    Round(b, c, d, e, a, f3(c, d, e), k3, w1 = left(w1 ^ w14 ^ w9 ^ w3));\n    Round(a, b, c, d, e, f3(b, c, d), k3, w2 = left(w2 ^ w15 ^ w10 ^ w4));\n    Round(e, a, b, c, d, f3(a, b, c), k3, w3 = left(w3 ^ w0 ^ w11 ^ w5));\n    Round(d, e, a, b, c, f3(e, a, b), k3, w4 = left(w4 ^ w1 ^ w12 ^ w6));\n    Round(c, d, e, a, b, f3(d, e, a), k3, w5 = left(w5 ^ w2 ^ w13 ^ w7));\n    Round(b, c, d, e, a, f3(c, d, e), k3, w6 = left(w6 ^ w3 ^ w14 ^ w8));\n    Round(a, b, c, d, e, f3(b, c, d), k3, w7 = left(w7 ^ w4 ^ w15 ^ w9));\n    Round(e, a, b, c, d, f3(a, b, c), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10));\n    Round(d, e, a, b, c, f3(e, a, b), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11));\n    Round(c, d, e, a, b, f3(d, e, a), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12));\n    Round(b, c, d, e, a, f3(c, d, e), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13));\n    Round(a, b, c, d, e, f2(b, c, d), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14));\n    Round(e, a, b, c, d, f2(a, b, c), k4, w13 = left(w13 ^ w10 ^ w5 ^ w15));\n    Round(d, e, a, b, c, f2(e, a, b), k4, w14 = left(w14 ^ w11 ^ w6 ^ w0));\n    Round(c, d, e, a, b, f2(d, e, a), k4, w15 = left(w15 ^ w12 ^ w7 ^ w1));\n\n    Round(b, c, d, e, a, f2(c, d, e), k4, w0 = left(w0 ^ w13 ^ w8 ^ w2));\n    Round(a, b, c, d, e, f2(b, c, d), k4, w1 = left(w1 ^ w14 ^ w9 ^ w3));\n    Round(e, a, b, c, d, f2(a, b, c), k4, w2 = left(w2 ^ w15 ^ w10 ^ w4));\n    Round(d, e, a, b, c, f2(e, a, b), k4, w3 = left(w3 ^ w0 ^ w11 ^ w5));\n    Round(c, d, e, a, b, f2(d, e, a), k4, w4 = left(w4 ^ w1 ^ w12 ^ w6));\n    Round(b, c, d, e, a, f2(c, d, e), k4, w5 = left(w5 ^ w2 ^ w13 ^ w7));\n    Round(a, b, c, d, e, f2(b, c, d), k4, w6 = left(w6 ^ w3 ^ w14 ^ w8));\n    Round(e, a, b, c, d, f2(a, b, c), k4, w7 = left(w7 ^ w4 ^ w15 ^ w9));\n    Round(d, e, a, b, c, f2(e, a, b), k4, w8 = left(w8 ^ w5 ^ w0 ^ w10));\n    Round(c, d, e, a, b, f2(d, e, a), k4, w9 = left(w9 ^ w6 ^ w1 ^ w11));\n    Round(b, c, d, e, a, f2(c, d, e), k4, w10 = left(w10 ^ w7 ^ w2 ^ w12));\n    Round(a, b, c, d, e, f2(b, c, d), k4, w11 = left(w11 ^ w8 ^ w3 ^ w13));\n    Round(e, a, b, c, d, f2(a, b, c), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14));\n    Round(d, e, a, b, c, f2(e, a, b), k4, left(w13 ^ w10 ^ w5 ^ w15));\n    Round(c, d, e, a, b, f2(d, e, a), k4, left(w14 ^ w11 ^ w6 ^ w0));\n    Round(b, c, d, e, a, f2(c, d, e), k4, left(w15 ^ w12 ^ w7 ^ w1));\n\n    s[0] += a;\n    s[1] += b;\n    s[2] += c;\n    s[3] += d;\n    s[4] += e;\n}\n\n} // namespace sha1\n\n} // namespace\n\n////// SHA1\n\nCSHA1::CSHA1() : bytes(0)\n{\n    sha1::Initialize(s);\n}\n\nCSHA1& CSHA1::Write(const unsigned char* data, size_t len)\n{\n    const unsigned char* end = data + len;\n    size_t bufsize = bytes % 64;\n    if (bufsize && bufsize + len >= 64) {\n        // Fill the buffer, and process it.\n        memcpy(buf + bufsize, data, 64 - bufsize);\n        bytes += 64 - bufsize;\n        data += 64 - bufsize;\n        sha1::Transform(s, buf);\n        bufsize = 0;\n    }\n    while (end - data >= 64) {\n        // Process full chunks directly from the source.\n        sha1::Transform(s, data);\n        bytes += 64;\n        data += 64;\n    }\n    if (end > data) {\n        // Fill the buffer with what remains.\n        memcpy(buf + bufsize, data, end - data);\n        bytes += end - data;\n    }\n    return *this;\n}\n\nvoid CSHA1::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    static const unsigned char pad[64] = {0x80};\n    unsigned char sizedesc[8];\n    WriteBE64(sizedesc, bytes << 3);\n    Write(pad, 1 + ((119 - (bytes % 64)) % 64));\n    Write(sizedesc, 8);\n    WriteBE32(hash, s[0]);\n    WriteBE32(hash + 4, s[1]);\n    WriteBE32(hash + 8, s[2]);\n    WriteBE32(hash + 12, s[3]);\n    WriteBE32(hash + 16, s[4]);\n}\n\nCSHA1& CSHA1::Reset()\n{\n    bytes = 0;\n    sha1::Initialize(s);\n    return *this;\n}\n"
  },
  {
    "path": "src/crypto/sha1.h",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_SHA1_H\n#define CRYPTO_SHA1_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A hasher class for SHA1. */\nclass CSHA1\n{\nprivate:\n    uint32_t s[5];\n    unsigned char buf[64];\n    uint64_t bytes;\n\npublic:\n    static const size_t OUTPUT_SIZE = 20;\n\n    CSHA1();\n    CSHA1& Write(const unsigned char* data, size_t len);\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n    CSHA1& Reset();\n};\n\n#endif\n"
  },
  {
    "path": "src/crypto/sha256.cpp",
    "content": "// Copyright (c) 2014-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <crypto/sha256.h>\n#include <crypto/common.h>\n\n#include <assert.h>\n#include \"common.h\"\n#include <support/cleanse.h>\n\n#include <string.h>\n\n#include <compat/cpuid.h>\n#include <compat/arch.h>\n#include <compat/sse.h>\n#include <compat/sys.h>\n\n#if defined(__linux__) && defined(COMPILER_HAS_ARMV8_CRYPTO)\n#include <sys/auxv.h>\n#include <asm/hwcap.h>\n#endif\n\n#if defined(MAC_OSX) && defined(COMPILER_HAS_ARMV8_CRYPTO)\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#endif\n\n#if defined(ARCH_X86_64) && defined(COMPILER_HAS_SSE4) && !defined(PLATFORM_MOBILE_ANDROID)\nnamespace sha256_sse4\n{\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);\n}\n#endif\n\n#if defined(COMPILER_HAS_SSE4_SHANI) && !defined(PLATFORM_MOBILE_ANDROID)\nnamespace sha256_x86_shani\n{\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);\n}\n#endif\n\n#if defined(COMPILER_HAS_ARMV8_CRYPTO)\nnamespace sha256_arm_shani\n{\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);\n}\n#endif\n\n// Internal implementation code.\nnamespace\n{\n/// Internal SHA-256 implementation.\nnamespace sha256\n{\nuint32_t inline Ch(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); }\nuint32_t inline Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (z & (x | y)); }\nuint32_t inline Sigma0(uint32_t x) { return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10); }\nuint32_t inline Sigma1(uint32_t x) { return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7); }\nuint32_t inline sigma0(uint32_t x) { return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3); }\nuint32_t inline sigma1(uint32_t x) { return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10); }\n\n/** One round of SHA-256. */\nvoid inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t& d, uint32_t e, uint32_t f, uint32_t g, uint32_t& h, uint32_t k)\n{\n    uint32_t t1 = h + Sigma1(e) + Ch(e, f, g) + k;\n    uint32_t t2 = Sigma0(a) + Maj(a, b, c);\n    d += t1;\n    h = t1 + t2;\n}\n\n/** Initialize SHA-256 state. */\nvoid inline Initialize(uint32_t* s)\n{\n    s[0] = 0x6a09e667ul;\n    s[1] = 0xbb67ae85ul;\n    s[2] = 0x3c6ef372ul;\n    s[3] = 0xa54ff53aul;\n    s[4] = 0x510e527ful;\n    s[5] = 0x9b05688cul;\n    s[6] = 0x1f83d9abul;\n    s[7] = 0x5be0cd19ul;\n}\n\n/** Perform a number of SHA-256 transformations, processing 64-byte chunks. */\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)\n{\n    while (blocks--) {\n        uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n        uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;\n\n        Round(a, b, c, d, e, f, g, h, 0x428a2f98 + (w0 = ReadBE32(chunk + 0)));\n        Round(h, a, b, c, d, e, f, g, 0x71374491 + (w1 = ReadBE32(chunk + 4)));\n        Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf + (w2 = ReadBE32(chunk + 8)));\n        Round(f, g, h, a, b, c, d, e, 0xe9b5dba5 + (w3 = ReadBE32(chunk + 12)));\n        Round(e, f, g, h, a, b, c, d, 0x3956c25b + (w4 = ReadBE32(chunk + 16)));\n        Round(d, e, f, g, h, a, b, c, 0x59f111f1 + (w5 = ReadBE32(chunk + 20)));\n        Round(c, d, e, f, g, h, a, b, 0x923f82a4 + (w6 = ReadBE32(chunk + 24)));\n        Round(b, c, d, e, f, g, h, a, 0xab1c5ed5 + (w7 = ReadBE32(chunk + 28)));\n        Round(a, b, c, d, e, f, g, h, 0xd807aa98 + (w8 = ReadBE32(chunk + 32)));\n        Round(h, a, b, c, d, e, f, g, 0x12835b01 + (w9 = ReadBE32(chunk + 36)));\n        Round(g, h, a, b, c, d, e, f, 0x243185be + (w10 = ReadBE32(chunk + 40)));\n        Round(f, g, h, a, b, c, d, e, 0x550c7dc3 + (w11 = ReadBE32(chunk + 44)));\n        Round(e, f, g, h, a, b, c, d, 0x72be5d74 + (w12 = ReadBE32(chunk + 48)));\n        Round(d, e, f, g, h, a, b, c, 0x80deb1fe + (w13 = ReadBE32(chunk + 52)));\n        Round(c, d, e, f, g, h, a, b, 0x9bdc06a7 + (w14 = ReadBE32(chunk + 56)));\n        Round(b, c, d, e, f, g, h, a, 0xc19bf174 + (w15 = ReadBE32(chunk + 60)));\n\n        Round(a, b, c, d, e, f, g, h, 0xe49b69c1 + (w0 += sigma1(w14) + w9 + sigma0(w1)));\n        Round(h, a, b, c, d, e, f, g, 0xefbe4786 + (w1 += sigma1(w15) + w10 + sigma0(w2)));\n        Round(g, h, a, b, c, d, e, f, 0x0fc19dc6 + (w2 += sigma1(w0) + w11 + sigma0(w3)));\n        Round(f, g, h, a, b, c, d, e, 0x240ca1cc + (w3 += sigma1(w1) + w12 + sigma0(w4)));\n        Round(e, f, g, h, a, b, c, d, 0x2de92c6f + (w4 += sigma1(w2) + w13 + sigma0(w5)));\n        Round(d, e, f, g, h, a, b, c, 0x4a7484aa + (w5 += sigma1(w3) + w14 + sigma0(w6)));\n        Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc + (w6 += sigma1(w4) + w15 + sigma0(w7)));\n        Round(b, c, d, e, f, g, h, a, 0x76f988da + (w7 += sigma1(w5) + w0 + sigma0(w8)));\n        Round(a, b, c, d, e, f, g, h, 0x983e5152 + (w8 += sigma1(w6) + w1 + sigma0(w9)));\n        Round(h, a, b, c, d, e, f, g, 0xa831c66d + (w9 += sigma1(w7) + w2 + sigma0(w10)));\n        Round(g, h, a, b, c, d, e, f, 0xb00327c8 + (w10 += sigma1(w8) + w3 + sigma0(w11)));\n        Round(f, g, h, a, b, c, d, e, 0xbf597fc7 + (w11 += sigma1(w9) + w4 + sigma0(w12)));\n        Round(e, f, g, h, a, b, c, d, 0xc6e00bf3 + (w12 += sigma1(w10) + w5 + sigma0(w13)));\n        Round(d, e, f, g, h, a, b, c, 0xd5a79147 + (w13 += sigma1(w11) + w6 + sigma0(w14)));\n        Round(c, d, e, f, g, h, a, b, 0x06ca6351 + (w14 += sigma1(w12) + w7 + sigma0(w15)));\n        Round(b, c, d, e, f, g, h, a, 0x14292967 + (w15 += sigma1(w13) + w8 + sigma0(w0)));\n\n        Round(a, b, c, d, e, f, g, h, 0x27b70a85 + (w0 += sigma1(w14) + w9 + sigma0(w1)));\n        Round(h, a, b, c, d, e, f, g, 0x2e1b2138 + (w1 += sigma1(w15) + w10 + sigma0(w2)));\n        Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc + (w2 += sigma1(w0) + w11 + sigma0(w3)));\n        Round(f, g, h, a, b, c, d, e, 0x53380d13 + (w3 += sigma1(w1) + w12 + sigma0(w4)));\n        Round(e, f, g, h, a, b, c, d, 0x650a7354 + (w4 += sigma1(w2) + w13 + sigma0(w5)));\n        Round(d, e, f, g, h, a, b, c, 0x766a0abb + (w5 += sigma1(w3) + w14 + sigma0(w6)));\n        Round(c, d, e, f, g, h, a, b, 0x81c2c92e + (w6 += sigma1(w4) + w15 + sigma0(w7)));\n        Round(b, c, d, e, f, g, h, a, 0x92722c85 + (w7 += sigma1(w5) + w0 + sigma0(w8)));\n        Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1 + (w8 += sigma1(w6) + w1 + sigma0(w9)));\n        Round(h, a, b, c, d, e, f, g, 0xa81a664b + (w9 += sigma1(w7) + w2 + sigma0(w10)));\n        Round(g, h, a, b, c, d, e, f, 0xc24b8b70 + (w10 += sigma1(w8) + w3 + sigma0(w11)));\n        Round(f, g, h, a, b, c, d, e, 0xc76c51a3 + (w11 += sigma1(w9) + w4 + sigma0(w12)));\n        Round(e, f, g, h, a, b, c, d, 0xd192e819 + (w12 += sigma1(w10) + w5 + sigma0(w13)));\n        Round(d, e, f, g, h, a, b, c, 0xd6990624 + (w13 += sigma1(w11) + w6 + sigma0(w14)));\n        Round(c, d, e, f, g, h, a, b, 0xf40e3585 + (w14 += sigma1(w12) + w7 + sigma0(w15)));\n        Round(b, c, d, e, f, g, h, a, 0x106aa070 + (w15 += sigma1(w13) + w8 + sigma0(w0)));\n\n        Round(a, b, c, d, e, f, g, h, 0x19a4c116 + (w0 += sigma1(w14) + w9 + sigma0(w1)));\n        Round(h, a, b, c, d, e, f, g, 0x1e376c08 + (w1 += sigma1(w15) + w10 + sigma0(w2)));\n        Round(g, h, a, b, c, d, e, f, 0x2748774c + (w2 += sigma1(w0) + w11 + sigma0(w3)));\n        Round(f, g, h, a, b, c, d, e, 0x34b0bcb5 + (w3 += sigma1(w1) + w12 + sigma0(w4)));\n        Round(e, f, g, h, a, b, c, d, 0x391c0cb3 + (w4 += sigma1(w2) + w13 + sigma0(w5)));\n        Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a + (w5 += sigma1(w3) + w14 + sigma0(w6)));\n        Round(c, d, e, f, g, h, a, b, 0x5b9cca4f + (w6 += sigma1(w4) + w15 + sigma0(w7)));\n        Round(b, c, d, e, f, g, h, a, 0x682e6ff3 + (w7 += sigma1(w5) + w0 + sigma0(w8)));\n        Round(a, b, c, d, e, f, g, h, 0x748f82ee + (w8 += sigma1(w6) + w1 + sigma0(w9)));\n        Round(h, a, b, c, d, e, f, g, 0x78a5636f + (w9 += sigma1(w7) + w2 + sigma0(w10)));\n        Round(g, h, a, b, c, d, e, f, 0x84c87814 + (w10 += sigma1(w8) + w3 + sigma0(w11)));\n        Round(f, g, h, a, b, c, d, e, 0x8cc70208 + (w11 += sigma1(w9) + w4 + sigma0(w12)));\n        Round(e, f, g, h, a, b, c, d, 0x90befffa + (w12 += sigma1(w10) + w5 + sigma0(w13)));\n        Round(d, e, f, g, h, a, b, c, 0xa4506ceb + (w13 += sigma1(w11) + w6 + sigma0(w14)));\n        Round(c, d, e, f, g, h, a, b, 0xbef9a3f7 + (w14 + sigma1(w12) + w7 + sigma0(w15)));\n        Round(b, c, d, e, f, g, h, a, 0xc67178f2 + (w15 + sigma1(w13) + w8 + sigma0(w0)));\n\n        s[0] += a;\n        s[1] += b;\n        s[2] += c;\n        s[3] += d;\n        s[4] += e;\n        s[5] += f;\n        s[6] += g;\n        s[7] += h;\n        chunk += 64;\n    }\n}\n\n} // namespace sha256\n\ntypedef void (*TransformType)(uint32_t*, const unsigned char*, size_t);\n\nTransformType Transform = sha256::Transform;\n\nbool SelfTest() {\n    // Input state (equal to the initial SHA256 state)\n    static const uint32_t init[8] = {\n        0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul\n    };\n    // Some random input data to test with\n    static const unsigned char data[641] = \"-\" // Intentionally not aligned\n        \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do \"\n        \"eiusmod tempor incididunt ut labore et dolore magna aliqua. Et m\"\n        \"olestie ac feugiat sed lectus vestibulum mattis ullamcorper. Mor\"\n        \"bi blandit cursus risus at ultrices mi tempus imperdiet nulla. N\"\n        \"unc congue nisi vita suscipit tellus mauris. Imperdiet proin fer\"\n        \"mentum leo vel orci. Massa tempor nec feugiat nisl pretium fusce\"\n        \" id velit. Telus in metus vulputate eu scelerisque felis. Mi tem\"\n        \"pus imperdiet nulla malesuada pellentesque. Tristique magna sit.\";\n    // Expected output state for hashing the i*64 first input bytes above (excluding SHA256 padding).\n    static const uint32_t result[9][8] = {\n        {0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul},\n        {0x91f8ec6bul, 0x4da10fe3ul, 0x1c9c292cul, 0x45e18185ul, 0x435cc111ul, 0x3ca26f09ul, 0xeb954caeul, 0x402a7069ul},\n        {0xcabea5acul, 0x374fb97cul, 0x182ad996ul, 0x7bd69cbful, 0x450ff900ul, 0xc1d2be8aul, 0x6a41d505ul, 0xe6212dc3ul},\n        {0xbcff09d6ul, 0x3e76f36eul, 0x3ecb2501ul, 0x78866e97ul, 0xe1c1e2fdul, 0x32f4eafful, 0x8aa6c4e5ul, 0xdfc024bcul},\n        {0xa08c5d94ul, 0x0a862f93ul, 0x6b7f2f40ul, 0x8f9fae76ul, 0x6d40439ful, 0x79dcee0cul, 0x3e39ff3aul, 0xdc3bdbb1ul},\n        {0x216a0895ul, 0x9f1a3662ul, 0xe99946f9ul, 0x87ba4364ul, 0x0fb5db2cul, 0x12bed3d3ul, 0x6689c0c7ul, 0x292f1b04ul},\n        {0xca3067f8ul, 0xbc8c2656ul, 0x37cb7e0dul, 0x9b6b8b0ful, 0x46dc380bul, 0xf1287f57ul, 0xc42e4b23ul, 0x3fefe94dul},\n        {0x3e4c4039ul, 0xbb6fca8cul, 0x6f27d2f7ul, 0x301e44a4ul, 0x8352ba14ul, 0x5769ce37ul, 0x48a1155ful, 0xc0e1c4c6ul},\n        {0xfe2fa9ddul, 0x69d0862bul, 0x1ae0db23ul, 0x471f9244ul, 0xf55c0145ul, 0xc30f9c3bul, 0x40a84ea0ul, 0x5b8a266cul},\n    };\n\n    // Test Transform() for 0 through 8 transformations.\n    for (size_t i = 0; i <= 8; ++i) {\n        uint32_t state[8];\n        std::copy(init, init + 8, state);\n        Transform(state, data + 1, i);\n        if (!std::equal(state, state + 8, result[i])) return false;\n    }\n\n    return true;\n}\n\n#ifdef COMPILER_HAS_AVX\n/** Check whether the OS has enabled AVX registers. */\nbool AVXEnabled()\n{\n    uint32_t a, d;\n    __asm__(\"xgetbv\" : \"=a\"(a), \"=d\"(d) : \"c\"(0));\n    return (a & 6) == 6;\n}\n#endif\n} // namespace\n\n\nstd::string SHA256AutoDetect()\n{\n    std::string ret = \"standard\";\n\n    bool have_sse4 = false;\n    bool have_xsave = false;\n    bool have_avx = false;\n    bool have_avx2 = false;\n    bool have_x86_shani = false;\n    bool enabled_avx = false;\n\n    (void)have_sse4;\n    (void)have_avx;\n    (void)have_xsave;\n    (void)have_avx2;\n    (void)have_x86_shani;\n    (void)enabled_avx;\n\n#ifdef HAVE_GETCPUID\n    {\n        uint32_t eax, ebx, ecx, edx;\n        GetCPUID(1, 0, eax, ebx, ecx, edx);\n        have_sse4 = (ecx >> 19) & 1;\n        have_xsave = (ecx >> 27) & 1;\n        have_avx = (ecx >> 28) & 1;\n        if (have_xsave && have_avx) {\n            enabled_avx = AVXEnabled();\n        }\n        if (have_sse4) {\n            GetCPUID(7, 0, eax, ebx, ecx, edx);\n            have_avx2 = (ebx >> 5) & 1;\n            have_x86_shani = (ebx >> 29) & 1;\n        }\n    }\n#endif\n\n#if defined(COMPILER_HAS_SSE4_SHANI) && !defined(PLATFORM_MOBILE_ANDROID)\n    {\n        if (have_x86_shani)\n        {\n            Transform = sha256_x86_shani::Transform;\n            ret = \"x86_shani\";\n            have_sse4 = false; // Disable SSE4/AVX2;\n            have_avx2 = false;\n        }\n    }\n#endif\n\n#if defined(ARCH_X86_64) && defined(COMPILER_HAS_SSE4) && !defined(PLATFORM_MOBILE_ANDROID)\n    {\n        if (have_sse4)\n        {\n            Transform = sha256_sse4::Transform;\n            ret = \"sse4\";\n        }\n    }\n#endif\n\n#ifdef COMPILER_HAS_ARMV8_CRYPTO\n    {\n        bool have_arm_shani = false;\n#if defined(__linux__)\n        {\n#ifdef ARCH_ARM\n            {\n                if (getauxval(AT_HWCAP2) & HWCAP2_SHA2)\n                {\n                    have_arm_shani = true;\n                }\n            }\n#endif\n#ifdef ARCH_ARM64\n            {\n                if (getauxval(AT_HWCAP) & HWCAP_SHA2)\n                {\n                    have_arm_shani = true;\n                }\n            }\n#endif\n        }\n#endif\n#if defined(MAC_OSX)\n        {\n            int val = 0;\n            size_t len = sizeof(val);\n            if (sysctlbyname(\"hw.optional.arm.FEAT_SHA256\", &val, &len, nullptr, 0) == 0)\n            {\n                have_arm_shani = val != 0;\n            }\n        }\n#endif\n        if (have_arm_shani)\n        {\n            Transform = sha256_arm_shani::Transform;\n            ret = \"arm_shani\";\n        }\n    }\n#endif\n\n    assert(SelfTest());\n    return ret;\n}\n\n////// SHA-256\n\nCSHA256::CSHA256() : bytes(0)\n{\n    sha256::Initialize(s);\n}\n\nCSHA256& CSHA256::Write(const unsigned char* data, size_t len)\n{\n    const unsigned char* end = data + len;\n    size_t bufsize = bytes % 64;\n    if (bufsize && bufsize + len >= 64) {\n        // Fill the buffer, and process it.\n        memcpy(buf + bufsize, data, 64 - bufsize);\n        bytes += 64 - bufsize;\n        data += 64 - bufsize;\n        Transform(s, buf, 1);\n        bufsize = 0;\n    }\n    if (end - data >= 64) {\n        size_t blocks = (end - data) / 64;\n        Transform(s, data, blocks);\n        data += 64 * blocks;\n        bytes += 64 * blocks;\n    }\n    if (end > data) {\n        // Fill the buffer with what remains.\n        memcpy(buf + bufsize, data, end - data);\n        bytes += end - data;\n    }\n    return *this;\n}\n\nvoid CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    static const unsigned char pad[64] = {0x80};\n    unsigned char sizedesc[8];\n    WriteBE64(sizedesc, bytes << 3);\n    Write(pad, 1 + ((119 - (bytes % 64)) % 64));\n    Write(sizedesc, 8);\n    WriteBE32(hash, s[0]);\n    WriteBE32(hash + 4, s[1]);\n    WriteBE32(hash + 8, s[2]);\n    WriteBE32(hash + 12, s[3]);\n    WriteBE32(hash + 16, s[4]);\n    WriteBE32(hash + 20, s[5]);\n    WriteBE32(hash + 24, s[6]);\n    WriteBE32(hash + 28, s[7]);\n\n    memory_cleanse(&buf[0], 64);\n    memory_cleanse(&s[0], 32);\n}\n\nCSHA256& CSHA256::Reset()\n{\n    bytes = 0;\n    sha256::Initialize(s);\n    return *this;\n}\n"
  },
  {
    "path": "src/crypto/sha256.h",
    "content": "// Copyright (c) 2014-2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_CRYPTO_SHA256_H\n#define CORE_CRYPTO_SHA256_H\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string>\n\n/** A hasher class for SHA-256. */\nclass CSHA256\n{\nprivate:\n    uint32_t s[8];\n    unsigned char buf[64];\n    uint64_t bytes;\n\npublic:\n    static const size_t OUTPUT_SIZE = 32;\n\n    CSHA256();\n    CSHA256& Write(const unsigned char* data, size_t len);\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n    CSHA256& Reset();\n};\n\n/** Autodetect the best available SHA256 implementation.\n *  Returns the name of the implementation.\n */\nstd::string SHA256AutoDetect();\n#endif // CORE_CRYPTO_SHA256_H\n"
  },
  {
    "path": "src/crypto/sha256_arm_shani.cpp",
    "content": "// Copyright (c) 2022 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// Based on https://github.com/noloader/SHA-Intrinsics/blob/master/sha256-arm.c,\n// Written and placed in public domain by Jeffrey Walton.\n// Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and\n// Barry O'Rourke for the mbedTLS project.\n// Variant specialized for 64-byte inputs added by Pieter Wuille.\n\n#ifdef COMPILER_HAS_ARMV8_CRYPTO\n\n#include <array>\n#include <cstdint>\n#include <cstddef>\n#include <arm_acle.h>\n#include <arm_neon.h>\n\nnamespace {\nalignas(uint32x4_t) static constexpr std::array<uint32_t, 64> K =\n{\n    0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,\n    0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,\n    0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,\n    0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,\n    0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,\n    0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,\n    0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,\n    0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,\n    0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,\n    0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,\n    0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,\n    0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,\n    0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,\n    0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,\n    0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,\n    0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,\n};\n}\n\nnamespace sha256_arm_shani {\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)\n{\n    uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE;\n    uint32x4_t MSG0, MSG1, MSG2, MSG3;\n    uint32x4_t TMP0, TMP2;\n\n    // Load state\n    STATE0 = vld1q_u32(&s[0]);\n    STATE1 = vld1q_u32(&s[4]);\n\n    while (blocks--)\n    {\n        // Save state\n        ABEF_SAVE = STATE0;\n        CDGH_SAVE = STATE1;\n\n        // Load and convert input chunk to Big Endian\n        MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 0)));\n        MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 16)));\n        MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 32)));\n        MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 48)));\n        chunk += 64;\n\n        // Original implemenation preloaded message and constant addition which was 1-3% slower.\n        // Now included as first step in quad round code saving one Q Neon register\n        // \"TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0]));\"\n\n        // Rounds 1-4\n        TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0]));\n        TMP2 = STATE0;\n        MSG0 = vsha256su0q_u32(MSG0, MSG1);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);\n\n        // Rounds 5-8\n        TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[4]));\n        TMP2 = STATE0;\n        MSG1 = vsha256su0q_u32(MSG1, MSG2);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);\n\n        // Rounds 9-12\n        TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[8]));\n        TMP2 = STATE0;\n        MSG2 = vsha256su0q_u32(MSG2, MSG3);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);\n\n        // Rounds 13-16\n        TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[12]));\n        TMP2 = STATE0;\n        MSG3 = vsha256su0q_u32(MSG3, MSG0);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);\n\n        // Rounds 17-20\n        TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[16]));\n        TMP2 = STATE0;\n        MSG0 = vsha256su0q_u32(MSG0, MSG1);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);\n\n        // Rounds 21-24\n        TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[20]));\n        TMP2 = STATE0;\n        MSG1 = vsha256su0q_u32(MSG1, MSG2);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);\n\n        // Rounds 25-28\n        TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[24]));\n        TMP2 = STATE0;\n        MSG2 = vsha256su0q_u32(MSG2, MSG3);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);\n\n        // Rounds 29-32\n        TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[28]));\n        TMP2 = STATE0;\n        MSG3 = vsha256su0q_u32(MSG3, MSG0);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);\n\n        // Rounds 33-36\n        TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[32]));\n        TMP2 = STATE0;\n        MSG0 = vsha256su0q_u32(MSG0, MSG1);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3);\n\n        // Rounds 37-40\n        TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[36]));\n        TMP2 = STATE0;\n        MSG1 = vsha256su0q_u32(MSG1, MSG2);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0);\n\n        // Rounds 41-44\n        TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[40]));\n        TMP2 = STATE0;\n        MSG2 = vsha256su0q_u32(MSG2, MSG3);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1);\n\n        // Rounds 45-48\n        TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[44]));\n        TMP2 = STATE0;\n        MSG3 = vsha256su0q_u32(MSG3, MSG0);\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n        MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2);\n\n        // Rounds 49-52\n        TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[48]));\n        TMP2 = STATE0;\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n\n        // Rounds 53-56\n        TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[52]));\n        TMP2 = STATE0;\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n\n        // Rounds 57-60\n        TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[56]));\n        TMP2 = STATE0;\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n\n        // Rounds 61-64\n        TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[60]));\n        TMP2 = STATE0;\n        STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0);\n        STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0);\n\n        // Update state\n        STATE0 = vaddq_u32(STATE0, ABEF_SAVE);\n        STATE1 = vaddq_u32(STATE1, CDGH_SAVE);\n    }\n\n    // Save final state\n    vst1q_u32(&s[0], STATE0);\n    vst1q_u32(&s[4], STATE1);\n}\n}\n\nnamespace sha256d64_arm_shani {\nvoid Transform_2way(unsigned char* output, const unsigned char* input)\n{\n    /* Initial state. */\n    alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> INIT = {\n        0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,\n        0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19\n    };\n\n    /* Precomputed message schedule for the 2nd transform. */\n    alignas(uint32x4_t) static constexpr std::array<uint32_t, 64> MIDS = {\n        0xc28a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\n        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf374,\n        0x649b69c1, 0xf0fe4786, 0x0fe1edc6, 0x240cf254,\n        0x4fe9346f, 0x6cc984be, 0x61b9411e, 0x16f988fa,\n        0xf2c65152, 0xa88e5a6d, 0xb019fc65, 0xb9d99ec7,\n        0x9a1231c3, 0xe70eeaa0, 0xfdb1232b, 0xc7353eb0,\n        0x3069bad5, 0xcb976d5f, 0x5a0f118f, 0xdc1eeefd,\n        0x0a35b689, 0xde0b7a04, 0x58f4ca9d, 0xe15d5b16,\n        0x007f3e86, 0x37088980, 0xa507ea32, 0x6fab9537,\n        0x17406110, 0x0d8cd6f1, 0xcdaa3b6d, 0xc0bbbe37,\n        0x83613bda, 0xdb48a363, 0x0b02e931, 0x6fd15ca7,\n        0x521afaca, 0x31338431, 0x6ed41a95, 0x6d437890,\n        0xc39c91f2, 0x9eccabbd, 0xb5c9a0e6, 0x532fb63c,\n        0xd2c741c6, 0x07237ea3, 0xa4954b68, 0x4c191d76\n    };\n\n    /* A few precomputed message schedule values for the 3rd transform. */\n    alignas(uint32x4_t) static constexpr std::array<uint32_t, 12> FINS = {\n        0x5807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n        0x80000000, 0x00000000, 0x00000000, 0x00000000,\n        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf274\n    };\n\n    /* Padding processed in the 3rd transform (byteswapped). */\n    alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> FINAL = {0x80000000, 0, 0, 0, 0, 0, 0, 0x100};\n\n    uint32x4_t STATE0A, STATE0B, STATE1A, STATE1B, ABEF_SAVEA, ABEF_SAVEB, CDGH_SAVEA, CDGH_SAVEB;\n    uint32x4_t MSG0A, MSG0B, MSG1A, MSG1B, MSG2A, MSG2B, MSG3A, MSG3B;\n    uint32x4_t TMP0A, TMP0B, TMP2A, TMP2B, TMP;\n\n    // Transform 1: Load state\n    STATE0A = vld1q_u32(&INIT[0]);\n    STATE0B = STATE0A;\n    STATE1A = vld1q_u32(&INIT[4]);\n    STATE1B = STATE1A;\n\n    // Transform 1: Load and convert input chunk to Big Endian\n    MSG0A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 0)));\n    MSG1A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 16)));\n    MSG2A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 32)));\n    MSG3A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 48)));\n    MSG0B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 64)));\n    MSG1B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 80)));\n    MSG2B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 96)));\n    MSG3B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 112)));\n\n    // Transform 1: Rounds 1-4\n    TMP = vld1q_u32(&K[0]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 1: Rounds 5-8\n    TMP = vld1q_u32(&K[4]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 1: Rounds 9-12\n    TMP = vld1q_u32(&K[8]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vsha256su0q_u32(MSG2A, MSG3A);\n    MSG2B = vsha256su0q_u32(MSG2B, MSG3B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 1: Rounds 13-16\n    TMP = vld1q_u32(&K[12]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 1: Rounds 17-20\n    TMP = vld1q_u32(&K[16]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 1: Rounds 21-24\n    TMP = vld1q_u32(&K[20]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 1: Rounds 25-28\n    TMP = vld1q_u32(&K[24]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vsha256su0q_u32(MSG2A, MSG3A);\n    MSG2B = vsha256su0q_u32(MSG2B, MSG3B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 1: Rounds 29-32\n    TMP = vld1q_u32(&K[28]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 1: Rounds 33-36\n    TMP = vld1q_u32(&K[32]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 1: Rounds 37-40\n    TMP = vld1q_u32(&K[36]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 1: Rounds 41-44\n    TMP = vld1q_u32(&K[40]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vsha256su0q_u32(MSG2A, MSG3A);\n    MSG2B = vsha256su0q_u32(MSG2B, MSG3B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 1: Rounds 45-48\n    TMP = vld1q_u32(&K[44]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 1: Rounds 49-52\n    TMP = vld1q_u32(&K[48]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 1: Rounds 53-56\n    TMP = vld1q_u32(&K[52]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 1: Rounds 57-60\n    TMP = vld1q_u32(&K[56]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 1: Rounds 61-64\n    TMP = vld1q_u32(&K[60]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 1: Update state\n    TMP = vld1q_u32(&INIT[0]);\n    STATE0A = vaddq_u32(STATE0A, TMP);\n    STATE0B = vaddq_u32(STATE0B, TMP);\n    TMP = vld1q_u32(&INIT[4]);\n    STATE1A = vaddq_u32(STATE1A, TMP);\n    STATE1B = vaddq_u32(STATE1B, TMP);\n\n    // Transform 2: Save state\n    ABEF_SAVEA = STATE0A;\n    ABEF_SAVEB = STATE0B;\n    CDGH_SAVEA = STATE1A;\n    CDGH_SAVEB = STATE1B;\n\n    // Transform 2: Rounds 1-4\n    TMP = vld1q_u32(&MIDS[0]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 5-8\n    TMP = vld1q_u32(&MIDS[4]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 9-12\n    TMP = vld1q_u32(&MIDS[8]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 13-16\n    TMP = vld1q_u32(&MIDS[12]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 17-20\n    TMP = vld1q_u32(&MIDS[16]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 21-24\n    TMP = vld1q_u32(&MIDS[20]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 25-28\n    TMP = vld1q_u32(&MIDS[24]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 29-32\n    TMP = vld1q_u32(&MIDS[28]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 33-36\n    TMP = vld1q_u32(&MIDS[32]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 37-40\n    TMP = vld1q_u32(&MIDS[36]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 41-44\n    TMP = vld1q_u32(&MIDS[40]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 45-48\n    TMP = vld1q_u32(&MIDS[44]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 49-52\n    TMP = vld1q_u32(&MIDS[48]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 53-56\n    TMP = vld1q_u32(&MIDS[52]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 57-60\n    TMP = vld1q_u32(&MIDS[56]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Rounds 61-64\n    TMP = vld1q_u32(&MIDS[60]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n\n    // Transform 2: Update state\n    STATE0A = vaddq_u32(STATE0A, ABEF_SAVEA);\n    STATE0B = vaddq_u32(STATE0B, ABEF_SAVEB);\n    STATE1A = vaddq_u32(STATE1A, CDGH_SAVEA);\n    STATE1B = vaddq_u32(STATE1B, CDGH_SAVEB);\n\n    // Transform 3: Pad previous output\n    MSG0A = STATE0A;\n    MSG0B = STATE0B;\n    MSG1A = STATE1A;\n    MSG1B = STATE1B;\n    MSG2A = vld1q_u32(&FINAL[0]);\n    MSG2B = MSG2A;\n    MSG3A = vld1q_u32(&FINAL[4]);\n    MSG3B = MSG3A;\n\n    // Transform 3: Load state\n    STATE0A = vld1q_u32(&INIT[0]);\n    STATE0B = STATE0A;\n    STATE1A = vld1q_u32(&INIT[4]);\n    STATE1B = STATE1A;\n\n    // Transform 3: Rounds 1-4\n    TMP = vld1q_u32(&K[0]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 3: Rounds 5-8\n    TMP = vld1q_u32(&K[4]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 3: Rounds 9-12\n    TMP = vld1q_u32(&FINS[0]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vld1q_u32(&FINS[4]);\n    MSG2B = MSG2A;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 3: Rounds 13-16\n    TMP = vld1q_u32(&FINS[8]);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 3: Rounds 17-20\n    TMP = vld1q_u32(&K[16]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 3: Rounds 21-24\n    TMP = vld1q_u32(&K[20]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 3: Rounds 25-28\n    TMP = vld1q_u32(&K[24]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vsha256su0q_u32(MSG2A, MSG3A);\n    MSG2B = vsha256su0q_u32(MSG2B, MSG3B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 3: Rounds 29-32\n    TMP = vld1q_u32(&K[28]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 3: Rounds 33-36\n    TMP = vld1q_u32(&K[32]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG0A = vsha256su0q_u32(MSG0A, MSG1A);\n    MSG0B = vsha256su0q_u32(MSG0B, MSG1B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A);\n    MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B);\n\n    // Transform 3: Rounds 37-40\n    TMP = vld1q_u32(&K[36]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG1A = vsha256su0q_u32(MSG1A, MSG2A);\n    MSG1B = vsha256su0q_u32(MSG1B, MSG2B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A);\n    MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B);\n\n    // Transform 3: Rounds 41-44\n    TMP = vld1q_u32(&K[40]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG2A = vsha256su0q_u32(MSG2A, MSG3A);\n    MSG2B = vsha256su0q_u32(MSG2B, MSG3B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A);\n    MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B);\n\n    // Transform 3: Rounds 45-48\n    TMP = vld1q_u32(&K[44]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    MSG3A = vsha256su0q_u32(MSG3A, MSG0A);\n    MSG3B = vsha256su0q_u32(MSG3B, MSG0B);\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n    MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A);\n    MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B);\n\n    // Transform 3: Rounds 49-52\n    TMP = vld1q_u32(&K[48]);\n    TMP0A = vaddq_u32(MSG0A, TMP);\n    TMP0B = vaddq_u32(MSG0B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 3: Rounds 53-56\n    TMP = vld1q_u32(&K[52]);\n    TMP0A = vaddq_u32(MSG1A, TMP);\n    TMP0B = vaddq_u32(MSG1B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 3: Rounds 57-60\n    TMP = vld1q_u32(&K[56]);\n    TMP0A = vaddq_u32(MSG2A, TMP);\n    TMP0B = vaddq_u32(MSG2B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 3: Rounds 61-64\n    TMP = vld1q_u32(&K[60]);\n    TMP0A = vaddq_u32(MSG3A, TMP);\n    TMP0B = vaddq_u32(MSG3B, TMP);\n    TMP2A = STATE0A;\n    TMP2B = STATE0B;\n    STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A);\n    STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B);\n    STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A);\n    STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B);\n\n    // Transform 3: Update state\n    TMP = vld1q_u32(&INIT[0]);\n    STATE0A = vaddq_u32(STATE0A, TMP);\n    STATE0B = vaddq_u32(STATE0B, TMP);\n    TMP = vld1q_u32(&INIT[4]);\n    STATE1A = vaddq_u32(STATE1A, TMP);\n    STATE1B = vaddq_u32(STATE1B, TMP);\n\n    // Store result\n    vst1q_u8(output, vrev32q_u8(vreinterpretq_u8_u32(STATE0A)));\n    vst1q_u8(output + 16, vrev32q_u8(vreinterpretq_u8_u32(STATE1A)));\n    vst1q_u8(output + 32, vrev32q_u8(vreinterpretq_u8_u32(STATE0B)));\n    vst1q_u8(output + 48, vrev32q_u8(vreinterpretq_u8_u32(STATE1B)));\n}\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/sha256_sse4.cpp",
    "content": "// Copyright (c) 2017-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// This is a translation to GCC extended asm syntax from YASM code by Intel\n// (available at the bottom of this file).\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#include <compat/sys.h>\n#include <compat/arch.h>\n\n#if defined(ARCH_X86_64) && defined(COMPILER_HAS_SSE4) && !defined(PLATFORM_MOBILE_ANDROID)\n\nnamespace sha256_sse4\n{\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)\n{\n    static const uint32_t K256 alignas(16) [] = {\n        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\n        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\n        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\n        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\n        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n    };\n    static const uint32_t FLIP_MASK alignas(16) [] = {0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f};\n    static const uint32_t SHUF_00BA alignas(16) [] = {0x03020100, 0x0b0a0908, 0xffffffff, 0xffffffff};\n    static const uint32_t SHUF_DC00 alignas(16) [] = {0xffffffff, 0xffffffff, 0x03020100, 0x0b0a0908};\n    uint32_t a, b, c, d, f, g, h, y0, y1, y2;\n    uint64_t tbl;\n    uint64_t inp_end, inp;\n    uint32_t xfer alignas(16) [4];\n\n    __asm__ __volatile__(\n        \"shl    $0x6,%2;\"\n        \"je     Ldone_hash_%=;\"\n        \"add    %1,%2;\"\n        \"mov    %2,%14;\"\n        \"mov    (%0),%3;\"\n        \"mov    0x4(%0),%4;\"\n        \"mov    0x8(%0),%5;\"\n        \"mov    0xc(%0),%6;\"\n        \"mov    0x10(%0),%k2;\"\n        \"mov    0x14(%0),%7;\"\n        \"mov    0x18(%0),%8;\"\n        \"mov    0x1c(%0),%9;\"\n        \"movdqa %18,%%xmm12;\"\n        \"movdqa %19,%%xmm10;\"\n        \"movdqa %20,%%xmm11;\"\n\n        \"Lloop0_%=:\"\n        \"lea    %17,%13;\"\n        \"movdqu (%1),%%xmm4;\"\n        \"pshufb %%xmm12,%%xmm4;\"\n        \"movdqu 0x10(%1),%%xmm5;\"\n        \"pshufb %%xmm12,%%xmm5;\"\n        \"movdqu 0x20(%1),%%xmm6;\"\n        \"pshufb %%xmm12,%%xmm6;\"\n        \"movdqu 0x30(%1),%%xmm7;\"\n        \"pshufb %%xmm12,%%xmm7;\"\n        \"mov    %1,%15;\"\n        \"mov    $3,%1;\"\n\n        \"Lloop1_%=:\"\n        \"movdqa 0x0(%13),%%xmm9;\"\n        \"paddd  %%xmm4,%%xmm9;\"\n        \"movdqa %%xmm9,%16;\"\n        \"movdqa %%xmm7,%%xmm0;\"\n        \"mov    %k2,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %3,%11;\"\n        \"palignr $0x4,%%xmm6,%%xmm0;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %k2,%10;\"\n        \"mov    %7,%12;\"\n        \"ror    $0x5,%10;\"\n        \"movdqa %%xmm5,%%xmm1;\"\n        \"xor    %3,%11;\"\n        \"xor    %8,%12;\"\n        \"paddd  %%xmm4,%%xmm0;\"\n        \"xor    %k2,%10;\"\n        \"and    %k2,%12;\"\n        \"ror    $0xb,%11;\"\n        \"palignr $0x4,%%xmm4,%%xmm1;\"\n        \"xor    %3,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %8,%12;\"\n        \"movdqa %%xmm1,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    %16,%12;\"\n        \"movdqa %%xmm1,%%xmm3;\"\n        \"mov    %3,%10;\"\n        \"add    %12,%9;\"\n        \"mov    %3,%12;\"\n        \"pslld  $0x19,%%xmm1;\"\n        \"or     %5,%10;\"\n        \"add    %9,%6;\"\n        \"and    %5,%12;\"\n        \"psrld  $0x7,%%xmm2;\"\n        \"and    %4,%10;\"\n        \"add    %11,%9;\"\n        \"por    %%xmm2,%%xmm1;\"\n        \"or     %12,%10;\"\n        \"add    %10,%9;\"\n        \"movdqa %%xmm3,%%xmm2;\"\n        \"mov    %6,%10;\"\n        \"mov    %9,%11;\"\n        \"movdqa %%xmm3,%%xmm8;\"\n        \"ror    $0xe,%10;\"\n        \"xor    %6,%10;\"\n        \"mov    %k2,%12;\"\n        \"ror    $0x9,%11;\"\n        \"pslld  $0xe,%%xmm3;\"\n        \"xor    %9,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %7,%12;\"\n        \"psrld  $0x12,%%xmm2;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %6,%10;\"\n        \"and    %6,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm1;\"\n        \"xor    %9,%11;\"\n        \"xor    %7,%12;\"\n        \"psrld  $0x3,%%xmm8;\"\n        \"add    %10,%12;\"\n        \"add    4+%16,%12;\"\n        \"ror    $0x2,%11;\"\n        \"pxor   %%xmm2,%%xmm1;\"\n        \"mov    %9,%10;\"\n        \"add    %12,%8;\"\n        \"mov    %9,%12;\"\n        \"pxor   %%xmm8,%%xmm1;\"\n        \"or     %4,%10;\"\n        \"add    %8,%5;\"\n        \"and    %4,%12;\"\n        \"pshufd $0xfa,%%xmm7,%%xmm2;\"\n        \"and    %3,%10;\"\n        \"add    %11,%8;\"\n        \"paddd  %%xmm1,%%xmm0;\"\n        \"or     %12,%10;\"\n        \"add    %10,%8;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %5,%10;\"\n        \"mov    %8,%11;\"\n        \"ror    $0xe,%10;\"\n        \"movdqa %%xmm2,%%xmm8;\"\n        \"xor    %5,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %6,%12;\"\n        \"xor    %8,%11;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %k2,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %5,%10;\"\n        \"and    %5,%12;\"\n        \"psrld  $0xa,%%xmm8;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %8,%11;\"\n        \"xor    %k2,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm8;\"\n        \"mov    %8,%10;\"\n        \"add    %12,%7;\"\n        \"mov    %8,%12;\"\n        \"pshufb %%xmm10,%%xmm8;\"\n        \"or     %3,%10;\"\n        \"add    %7,%4;\"\n        \"and    %3,%12;\"\n        \"paddd  %%xmm8,%%xmm0;\"\n        \"and    %9,%10;\"\n        \"add    %11,%7;\"\n        \"pshufd $0x50,%%xmm0,%%xmm2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%7;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %4,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %7,%11;\"\n        \"movdqa %%xmm2,%%xmm4;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %4,%10;\"\n        \"mov    %5,%12;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %7,%11;\"\n        \"xor    %6,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %4,%10;\"\n        \"and    %4,%12;\"\n        \"ror    $0xb,%11;\"\n        \"psrld  $0xa,%%xmm4;\"\n        \"xor    %7,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %6,%12;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    12+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm4;\"\n        \"mov    %7,%10;\"\n        \"add    %12,%k2;\"\n        \"mov    %7,%12;\"\n        \"pshufb %%xmm11,%%xmm4;\"\n        \"or     %9,%10;\"\n        \"add    %k2,%3;\"\n        \"and    %9,%12;\"\n        \"paddd  %%xmm0,%%xmm4;\"\n        \"and    %8,%10;\"\n        \"add    %11,%k2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%k2;\"\n        \"movdqa 0x10(%13),%%xmm9;\"\n        \"paddd  %%xmm5,%%xmm9;\"\n        \"movdqa %%xmm9,%16;\"\n        \"movdqa %%xmm4,%%xmm0;\"\n        \"mov    %3,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %k2,%11;\"\n        \"palignr $0x4,%%xmm7,%%xmm0;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %3,%10;\"\n        \"mov    %4,%12;\"\n        \"ror    $0x5,%10;\"\n        \"movdqa %%xmm6,%%xmm1;\"\n        \"xor    %k2,%11;\"\n        \"xor    %5,%12;\"\n        \"paddd  %%xmm5,%%xmm0;\"\n        \"xor    %3,%10;\"\n        \"and    %3,%12;\"\n        \"ror    $0xb,%11;\"\n        \"palignr $0x4,%%xmm5,%%xmm1;\"\n        \"xor    %k2,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %5,%12;\"\n        \"movdqa %%xmm1,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    %16,%12;\"\n        \"movdqa %%xmm1,%%xmm3;\"\n        \"mov    %k2,%10;\"\n        \"add    %12,%6;\"\n        \"mov    %k2,%12;\"\n        \"pslld  $0x19,%%xmm1;\"\n        \"or     %8,%10;\"\n        \"add    %6,%9;\"\n        \"and    %8,%12;\"\n        \"psrld  $0x7,%%xmm2;\"\n        \"and    %7,%10;\"\n        \"add    %11,%6;\"\n        \"por    %%xmm2,%%xmm1;\"\n        \"or     %12,%10;\"\n        \"add    %10,%6;\"\n        \"movdqa %%xmm3,%%xmm2;\"\n        \"mov    %9,%10;\"\n        \"mov    %6,%11;\"\n        \"movdqa %%xmm3,%%xmm8;\"\n        \"ror    $0xe,%10;\"\n        \"xor    %9,%10;\"\n        \"mov    %3,%12;\"\n        \"ror    $0x9,%11;\"\n        \"pslld  $0xe,%%xmm3;\"\n        \"xor    %6,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %4,%12;\"\n        \"psrld  $0x12,%%xmm2;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %9,%10;\"\n        \"and    %9,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm1;\"\n        \"xor    %6,%11;\"\n        \"xor    %4,%12;\"\n        \"psrld  $0x3,%%xmm8;\"\n        \"add    %10,%12;\"\n        \"add    4+%16,%12;\"\n        \"ror    $0x2,%11;\"\n        \"pxor   %%xmm2,%%xmm1;\"\n        \"mov    %6,%10;\"\n        \"add    %12,%5;\"\n        \"mov    %6,%12;\"\n        \"pxor   %%xmm8,%%xmm1;\"\n        \"or     %7,%10;\"\n        \"add    %5,%8;\"\n        \"and    %7,%12;\"\n        \"pshufd $0xfa,%%xmm4,%%xmm2;\"\n        \"and    %k2,%10;\"\n        \"add    %11,%5;\"\n        \"paddd  %%xmm1,%%xmm0;\"\n        \"or     %12,%10;\"\n        \"add    %10,%5;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %8,%10;\"\n        \"mov    %5,%11;\"\n        \"ror    $0xe,%10;\"\n        \"movdqa %%xmm2,%%xmm8;\"\n        \"xor    %8,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %9,%12;\"\n        \"xor    %5,%11;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %3,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %8,%10;\"\n        \"and    %8,%12;\"\n        \"psrld  $0xa,%%xmm8;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %5,%11;\"\n        \"xor    %3,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm8;\"\n        \"mov    %5,%10;\"\n        \"add    %12,%4;\"\n        \"mov    %5,%12;\"\n        \"pshufb %%xmm10,%%xmm8;\"\n        \"or     %k2,%10;\"\n        \"add    %4,%7;\"\n        \"and    %k2,%12;\"\n        \"paddd  %%xmm8,%%xmm0;\"\n        \"and    %6,%10;\"\n        \"add    %11,%4;\"\n        \"pshufd $0x50,%%xmm0,%%xmm2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%4;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %7,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %4,%11;\"\n        \"movdqa %%xmm2,%%xmm5;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %7,%10;\"\n        \"mov    %8,%12;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %4,%11;\"\n        \"xor    %9,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %7,%10;\"\n        \"and    %7,%12;\"\n        \"ror    $0xb,%11;\"\n        \"psrld  $0xa,%%xmm5;\"\n        \"xor    %4,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %9,%12;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    12+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm5;\"\n        \"mov    %4,%10;\"\n        \"add    %12,%3;\"\n        \"mov    %4,%12;\"\n        \"pshufb %%xmm11,%%xmm5;\"\n        \"or     %6,%10;\"\n        \"add    %3,%k2;\"\n        \"and    %6,%12;\"\n        \"paddd  %%xmm0,%%xmm5;\"\n        \"and    %5,%10;\"\n        \"add    %11,%3;\"\n        \"or     %12,%10;\"\n        \"add    %10,%3;\"\n        \"movdqa 0x20(%13),%%xmm9;\"\n        \"paddd  %%xmm6,%%xmm9;\"\n        \"movdqa %%xmm9,%16;\"\n        \"movdqa %%xmm5,%%xmm0;\"\n        \"mov    %k2,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %3,%11;\"\n        \"palignr $0x4,%%xmm4,%%xmm0;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %k2,%10;\"\n        \"mov    %7,%12;\"\n        \"ror    $0x5,%10;\"\n        \"movdqa %%xmm7,%%xmm1;\"\n        \"xor    %3,%11;\"\n        \"xor    %8,%12;\"\n        \"paddd  %%xmm6,%%xmm0;\"\n        \"xor    %k2,%10;\"\n        \"and    %k2,%12;\"\n        \"ror    $0xb,%11;\"\n        \"palignr $0x4,%%xmm6,%%xmm1;\"\n        \"xor    %3,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %8,%12;\"\n        \"movdqa %%xmm1,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    %16,%12;\"\n        \"movdqa %%xmm1,%%xmm3;\"\n        \"mov    %3,%10;\"\n        \"add    %12,%9;\"\n        \"mov    %3,%12;\"\n        \"pslld  $0x19,%%xmm1;\"\n        \"or     %5,%10;\"\n        \"add    %9,%6;\"\n        \"and    %5,%12;\"\n        \"psrld  $0x7,%%xmm2;\"\n        \"and    %4,%10;\"\n        \"add    %11,%9;\"\n        \"por    %%xmm2,%%xmm1;\"\n        \"or     %12,%10;\"\n        \"add    %10,%9;\"\n        \"movdqa %%xmm3,%%xmm2;\"\n        \"mov    %6,%10;\"\n        \"mov    %9,%11;\"\n        \"movdqa %%xmm3,%%xmm8;\"\n        \"ror    $0xe,%10;\"\n        \"xor    %6,%10;\"\n        \"mov    %k2,%12;\"\n        \"ror    $0x9,%11;\"\n        \"pslld  $0xe,%%xmm3;\"\n        \"xor    %9,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %7,%12;\"\n        \"psrld  $0x12,%%xmm2;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %6,%10;\"\n        \"and    %6,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm1;\"\n        \"xor    %9,%11;\"\n        \"xor    %7,%12;\"\n        \"psrld  $0x3,%%xmm8;\"\n        \"add    %10,%12;\"\n        \"add    4+%16,%12;\"\n        \"ror    $0x2,%11;\"\n        \"pxor   %%xmm2,%%xmm1;\"\n        \"mov    %9,%10;\"\n        \"add    %12,%8;\"\n        \"mov    %9,%12;\"\n        \"pxor   %%xmm8,%%xmm1;\"\n        \"or     %4,%10;\"\n        \"add    %8,%5;\"\n        \"and    %4,%12;\"\n        \"pshufd $0xfa,%%xmm5,%%xmm2;\"\n        \"and    %3,%10;\"\n        \"add    %11,%8;\"\n        \"paddd  %%xmm1,%%xmm0;\"\n        \"or     %12,%10;\"\n        \"add    %10,%8;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %5,%10;\"\n        \"mov    %8,%11;\"\n        \"ror    $0xe,%10;\"\n        \"movdqa %%xmm2,%%xmm8;\"\n        \"xor    %5,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %6,%12;\"\n        \"xor    %8,%11;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %k2,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %5,%10;\"\n        \"and    %5,%12;\"\n        \"psrld  $0xa,%%xmm8;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %8,%11;\"\n        \"xor    %k2,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm8;\"\n        \"mov    %8,%10;\"\n        \"add    %12,%7;\"\n        \"mov    %8,%12;\"\n        \"pshufb %%xmm10,%%xmm8;\"\n        \"or     %3,%10;\"\n        \"add    %7,%4;\"\n        \"and    %3,%12;\"\n        \"paddd  %%xmm8,%%xmm0;\"\n        \"and    %9,%10;\"\n        \"add    %11,%7;\"\n        \"pshufd $0x50,%%xmm0,%%xmm2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%7;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %4,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %7,%11;\"\n        \"movdqa %%xmm2,%%xmm6;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %4,%10;\"\n        \"mov    %5,%12;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %7,%11;\"\n        \"xor    %6,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %4,%10;\"\n        \"and    %4,%12;\"\n        \"ror    $0xb,%11;\"\n        \"psrld  $0xa,%%xmm6;\"\n        \"xor    %7,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %6,%12;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    12+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm6;\"\n        \"mov    %7,%10;\"\n        \"add    %12,%k2;\"\n        \"mov    %7,%12;\"\n        \"pshufb %%xmm11,%%xmm6;\"\n        \"or     %9,%10;\"\n        \"add    %k2,%3;\"\n        \"and    %9,%12;\"\n        \"paddd  %%xmm0,%%xmm6;\"\n        \"and    %8,%10;\"\n        \"add    %11,%k2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%k2;\"\n        \"movdqa 0x30(%13),%%xmm9;\"\n        \"paddd  %%xmm7,%%xmm9;\"\n        \"movdqa %%xmm9,%16;\"\n        \"add    $0x40,%13;\"\n        \"movdqa %%xmm6,%%xmm0;\"\n        \"mov    %3,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %k2,%11;\"\n        \"palignr $0x4,%%xmm5,%%xmm0;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %3,%10;\"\n        \"mov    %4,%12;\"\n        \"ror    $0x5,%10;\"\n        \"movdqa %%xmm4,%%xmm1;\"\n        \"xor    %k2,%11;\"\n        \"xor    %5,%12;\"\n        \"paddd  %%xmm7,%%xmm0;\"\n        \"xor    %3,%10;\"\n        \"and    %3,%12;\"\n        \"ror    $0xb,%11;\"\n        \"palignr $0x4,%%xmm7,%%xmm1;\"\n        \"xor    %k2,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %5,%12;\"\n        \"movdqa %%xmm1,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    %16,%12;\"\n        \"movdqa %%xmm1,%%xmm3;\"\n        \"mov    %k2,%10;\"\n        \"add    %12,%6;\"\n        \"mov    %k2,%12;\"\n        \"pslld  $0x19,%%xmm1;\"\n        \"or     %8,%10;\"\n        \"add    %6,%9;\"\n        \"and    %8,%12;\"\n        \"psrld  $0x7,%%xmm2;\"\n        \"and    %7,%10;\"\n        \"add    %11,%6;\"\n        \"por    %%xmm2,%%xmm1;\"\n        \"or     %12,%10;\"\n        \"add    %10,%6;\"\n        \"movdqa %%xmm3,%%xmm2;\"\n        \"mov    %9,%10;\"\n        \"mov    %6,%11;\"\n        \"movdqa %%xmm3,%%xmm8;\"\n        \"ror    $0xe,%10;\"\n        \"xor    %9,%10;\"\n        \"mov    %3,%12;\"\n        \"ror    $0x9,%11;\"\n        \"pslld  $0xe,%%xmm3;\"\n        \"xor    %6,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %4,%12;\"\n        \"psrld  $0x12,%%xmm2;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %9,%10;\"\n        \"and    %9,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm1;\"\n        \"xor    %6,%11;\"\n        \"xor    %4,%12;\"\n        \"psrld  $0x3,%%xmm8;\"\n        \"add    %10,%12;\"\n        \"add    4+%16,%12;\"\n        \"ror    $0x2,%11;\"\n        \"pxor   %%xmm2,%%xmm1;\"\n        \"mov    %6,%10;\"\n        \"add    %12,%5;\"\n        \"mov    %6,%12;\"\n        \"pxor   %%xmm8,%%xmm1;\"\n        \"or     %7,%10;\"\n        \"add    %5,%8;\"\n        \"and    %7,%12;\"\n        \"pshufd $0xfa,%%xmm6,%%xmm2;\"\n        \"and    %k2,%10;\"\n        \"add    %11,%5;\"\n        \"paddd  %%xmm1,%%xmm0;\"\n        \"or     %12,%10;\"\n        \"add    %10,%5;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %8,%10;\"\n        \"mov    %5,%11;\"\n        \"ror    $0xe,%10;\"\n        \"movdqa %%xmm2,%%xmm8;\"\n        \"xor    %8,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %9,%12;\"\n        \"xor    %5,%11;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %3,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %8,%10;\"\n        \"and    %8,%12;\"\n        \"psrld  $0xa,%%xmm8;\"\n        \"ror    $0xb,%11;\"\n        \"xor    %5,%11;\"\n        \"xor    %3,%12;\"\n        \"ror    $0x6,%10;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm8;\"\n        \"mov    %5,%10;\"\n        \"add    %12,%4;\"\n        \"mov    %5,%12;\"\n        \"pshufb %%xmm10,%%xmm8;\"\n        \"or     %k2,%10;\"\n        \"add    %4,%7;\"\n        \"and    %k2,%12;\"\n        \"paddd  %%xmm8,%%xmm0;\"\n        \"and    %6,%10;\"\n        \"add    %11,%4;\"\n        \"pshufd $0x50,%%xmm0,%%xmm2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%4;\"\n        \"movdqa %%xmm2,%%xmm3;\"\n        \"mov    %7,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %4,%11;\"\n        \"movdqa %%xmm2,%%xmm7;\"\n        \"ror    $0x9,%11;\"\n        \"xor    %7,%10;\"\n        \"mov    %8,%12;\"\n        \"ror    $0x5,%10;\"\n        \"psrlq  $0x11,%%xmm2;\"\n        \"xor    %4,%11;\"\n        \"xor    %9,%12;\"\n        \"psrlq  $0x13,%%xmm3;\"\n        \"xor    %7,%10;\"\n        \"and    %7,%12;\"\n        \"ror    $0xb,%11;\"\n        \"psrld  $0xa,%%xmm7;\"\n        \"xor    %4,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %9,%12;\"\n        \"pxor   %%xmm3,%%xmm2;\"\n        \"ror    $0x2,%11;\"\n        \"add    %10,%12;\"\n        \"add    12+%16,%12;\"\n        \"pxor   %%xmm2,%%xmm7;\"\n        \"mov    %4,%10;\"\n        \"add    %12,%3;\"\n        \"mov    %4,%12;\"\n        \"pshufb %%xmm11,%%xmm7;\"\n        \"or     %6,%10;\"\n        \"add    %3,%k2;\"\n        \"and    %6,%12;\"\n        \"paddd  %%xmm0,%%xmm7;\"\n        \"and    %5,%10;\"\n        \"add    %11,%3;\"\n        \"or     %12,%10;\"\n        \"add    %10,%3;\"\n        \"sub    $0x1,%1;\"\n        \"jne    Lloop1_%=;\"\n        \"mov    $0x2,%1;\"\n\n        \"Lloop2_%=:\"\n        \"paddd  0x0(%13),%%xmm4;\"\n        \"movdqa %%xmm4,%16;\"\n        \"mov    %k2,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %3,%11;\"\n        \"xor    %k2,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %7,%12;\"\n        \"xor    %3,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %8,%12;\"\n        \"xor    %k2,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %k2,%12;\"\n        \"xor    %3,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %8,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    %16,%12;\"\n        \"mov    %3,%10;\"\n        \"add    %12,%9;\"\n        \"mov    %3,%12;\"\n        \"or     %5,%10;\"\n        \"add    %9,%6;\"\n        \"and    %5,%12;\"\n        \"and    %4,%10;\"\n        \"add    %11,%9;\"\n        \"or     %12,%10;\"\n        \"add    %10,%9;\"\n        \"mov    %6,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %9,%11;\"\n        \"xor    %6,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %k2,%12;\"\n        \"xor    %9,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %7,%12;\"\n        \"xor    %6,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %6,%12;\"\n        \"xor    %9,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %7,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    4+%16,%12;\"\n        \"mov    %9,%10;\"\n        \"add    %12,%8;\"\n        \"mov    %9,%12;\"\n        \"or     %4,%10;\"\n        \"add    %8,%5;\"\n        \"and    %4,%12;\"\n        \"and    %3,%10;\"\n        \"add    %11,%8;\"\n        \"or     %12,%10;\"\n        \"add    %10,%8;\"\n        \"mov    %5,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %8,%11;\"\n        \"xor    %5,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %6,%12;\"\n        \"xor    %8,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %k2,%12;\"\n        \"xor    %5,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %5,%12;\"\n        \"xor    %8,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %k2,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"mov    %8,%10;\"\n        \"add    %12,%7;\"\n        \"mov    %8,%12;\"\n        \"or     %3,%10;\"\n        \"add    %7,%4;\"\n        \"and    %3,%12;\"\n        \"and    %9,%10;\"\n        \"add    %11,%7;\"\n        \"or     %12,%10;\"\n        \"add    %10,%7;\"\n        \"mov    %4,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %7,%11;\"\n        \"xor    %4,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %5,%12;\"\n        \"xor    %7,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %6,%12;\"\n        \"xor    %4,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %4,%12;\"\n        \"xor    %7,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %6,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    12+%16,%12;\"\n        \"mov    %7,%10;\"\n        \"add    %12,%k2;\"\n        \"mov    %7,%12;\"\n        \"or     %9,%10;\"\n        \"add    %k2,%3;\"\n        \"and    %9,%12;\"\n        \"and    %8,%10;\"\n        \"add    %11,%k2;\"\n        \"or     %12,%10;\"\n        \"add    %10,%k2;\"\n        \"paddd  0x10(%13),%%xmm5;\"\n        \"movdqa %%xmm5,%16;\"\n        \"add    $0x20,%13;\"\n        \"mov    %3,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %k2,%11;\"\n        \"xor    %3,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %4,%12;\"\n        \"xor    %k2,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %5,%12;\"\n        \"xor    %3,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %3,%12;\"\n        \"xor    %k2,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %5,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    %16,%12;\"\n        \"mov    %k2,%10;\"\n        \"add    %12,%6;\"\n        \"mov    %k2,%12;\"\n        \"or     %8,%10;\"\n        \"add    %6,%9;\"\n        \"and    %8,%12;\"\n        \"and    %7,%10;\"\n        \"add    %11,%6;\"\n        \"or     %12,%10;\"\n        \"add    %10,%6;\"\n        \"mov    %9,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %6,%11;\"\n        \"xor    %9,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %3,%12;\"\n        \"xor    %6,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %4,%12;\"\n        \"xor    %9,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %9,%12;\"\n        \"xor    %6,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %4,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    4+%16,%12;\"\n        \"mov    %6,%10;\"\n        \"add    %12,%5;\"\n        \"mov    %6,%12;\"\n        \"or     %7,%10;\"\n        \"add    %5,%8;\"\n        \"and    %7,%12;\"\n        \"and    %k2,%10;\"\n        \"add    %11,%5;\"\n        \"or     %12,%10;\"\n        \"add    %10,%5;\"\n        \"mov    %8,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %5,%11;\"\n        \"xor    %8,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %9,%12;\"\n        \"xor    %5,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %3,%12;\"\n        \"xor    %8,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %8,%12;\"\n        \"xor    %5,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %3,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    8+%16,%12;\"\n        \"mov    %5,%10;\"\n        \"add    %12,%4;\"\n        \"mov    %5,%12;\"\n        \"or     %k2,%10;\"\n        \"add    %4,%7;\"\n        \"and    %k2,%12;\"\n        \"and    %6,%10;\"\n        \"add    %11,%4;\"\n        \"or     %12,%10;\"\n        \"add    %10,%4;\"\n        \"mov    %7,%10;\"\n        \"ror    $0xe,%10;\"\n        \"mov    %4,%11;\"\n        \"xor    %7,%10;\"\n        \"ror    $0x9,%11;\"\n        \"mov    %8,%12;\"\n        \"xor    %4,%11;\"\n        \"ror    $0x5,%10;\"\n        \"xor    %9,%12;\"\n        \"xor    %7,%10;\"\n        \"ror    $0xb,%11;\"\n        \"and    %7,%12;\"\n        \"xor    %4,%11;\"\n        \"ror    $0x6,%10;\"\n        \"xor    %9,%12;\"\n        \"add    %10,%12;\"\n        \"ror    $0x2,%11;\"\n        \"add    12+%16,%12;\"\n        \"mov    %4,%10;\"\n        \"add    %12,%3;\"\n        \"mov    %4,%12;\"\n        \"or     %6,%10;\"\n        \"add    %3,%k2;\"\n        \"and    %6,%12;\"\n        \"and    %5,%10;\"\n        \"add    %11,%3;\"\n        \"or     %12,%10;\"\n        \"add    %10,%3;\"\n        \"movdqa %%xmm6,%%xmm4;\"\n        \"movdqa %%xmm7,%%xmm5;\"\n        \"sub    $0x1,%1;\"\n        \"jne    Lloop2_%=;\"\n        \"add    (%0),%3;\"\n        \"mov    %3,(%0);\"\n        \"add    0x4(%0),%4;\"\n        \"mov    %4,0x4(%0);\"\n        \"add    0x8(%0),%5;\"\n        \"mov    %5,0x8(%0);\"\n        \"add    0xc(%0),%6;\"\n        \"mov    %6,0xc(%0);\"\n        \"add    0x10(%0),%k2;\"\n        \"mov    %k2,0x10(%0);\"\n        \"add    0x14(%0),%7;\"\n        \"mov    %7,0x14(%0);\"\n        \"add    0x18(%0),%8;\"\n        \"mov    %8,0x18(%0);\"\n        \"add    0x1c(%0),%9;\"\n        \"mov    %9,0x1c(%0);\"\n        \"mov    %15,%1;\"\n        \"add    $0x40,%1;\"\n        \"cmp    %14,%1;\"\n        \"jne    Lloop0_%=;\"\n\n        \"Ldone_hash_%=:\"\n\n        : \"+r\"(s), \"+r\"(chunk), \"+r\"(blocks), \"=r\"(a), \"=r\"(b), \"=r\"(c), \"=r\"(d), /* e = chunk */ \"=r\"(f), \"=r\"(g), \"=r\"(h), \"=r\"(y0), \"=r\"(y1), \"=r\"(y2), \"=r\"(tbl), \"+m\"(inp_end), \"+m\"(inp), \"+m\"(xfer)\n        : \"m\"(K256), \"m\"(FLIP_MASK), \"m\"(SHUF_00BA), \"m\"(SHUF_DC00)\n        : \"cc\", \"memory\", \"xmm0\", \"xmm1\", \"xmm2\", \"xmm3\", \"xmm4\", \"xmm5\", \"xmm6\", \"xmm7\", \"xmm8\", \"xmm9\", \"xmm10\", \"xmm11\", \"xmm12\"\n   );\n}\n}\n\n/*\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Copyright (c) 2012, Intel Corporation \n; \n; All rights reserved. \n; \n; Redistribution and use in source and binary forms, with or without\n; modification, are permitted provided that the following conditions are\n; met: \n; \n; * Redistributions of source code must retain the above copyright\n;   notice, this list of conditions and the following disclaimer.  \n; \n; * Redistributions in binary form must reproduce the above copyright\n;   notice, this list of conditions and the following disclaimer in the\n;   documentation and/or other materials provided with the\n;   distribution. \n; \n; * Neither the name of the Intel Corporation nor the names of its\n;   contributors may be used to endorse or promote products derived from\n;   this software without specific prior written permission. \n; \n; \n; THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION \"AS IS\" AND ANY\n; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR\n; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;\n; Example YASM command lines:\n; Windows:  yasm -Xvc -f x64 -rnasm -pnasm -o sha256_sse4.obj -g cv8 sha256_sse4.asm\n; Linux:    yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o sha256_sse4.o sha256_sse4.asm\n;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;\n; This code is described in an Intel White-Paper:\n; \"Fast SHA-256 Implementations on Intel Architecture Processors\"\n;\n; To find it, surf to https://www.intel.com/p/en_US/embedded\n; and search for that title.\n; The paper is expected to be released roughly at the end of April, 2012\n;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; This code schedules 1 blocks at a time, with 4 lanes per block\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n%define\tMOVDQ movdqu ;; assume buffers not aligned \n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Define Macros\n\n; addm [mem], reg\n; Add reg to mem using reg-mem add and store\n%macro addm 2\n    add\t%2, %1\n    mov\t%1, %2\n%endm\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; COPY_XMM_AND_BSWAP xmm, [mem], byte_flip_mask\n; Load xmm with mem and byte swap each dword\n%macro COPY_XMM_AND_BSWAP 3\n    MOVDQ %1, %2\n    pshufb %1, %3\n%endmacro\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n%define X0 xmm4\n%define X1 xmm5\n%define X2 xmm6\n%define X3 xmm7\n\n%define XTMP0 xmm0\n%define XTMP1 xmm1\n%define XTMP2 xmm2\n%define XTMP3 xmm3\n%define XTMP4 xmm8\n%define XFER  xmm9\n\n%define SHUF_00BA\txmm10 ; shuffle xBxA -> 00BA\n%define SHUF_DC00\txmm11 ; shuffle xDxC -> DC00\n%define BYTE_FLIP_MASK\txmm12\n    \n%ifdef LINUX\n%define NUM_BLKS rdx\t; 3rd arg\n%define CTX\trsi\t; 2nd arg\n%define INP\trdi\t; 1st arg\n\n%define SRND\trdi\t; clobbers INP\n%define c\tecx\n%define d \tr8d\n%define e \tedx\n%else\n%define NUM_BLKS r8\t; 3rd arg\n%define CTX\trdx \t; 2nd arg\n%define INP\trcx \t; 1st arg\n\n%define SRND\trcx\t; clobbers INP\n%define c \tedi \n%define d\tesi \n%define e \tr8d\n    \n%endif\n%define TBL\trbp\n%define a eax\n%define b ebx\n\n%define f r9d\n%define g r10d\n%define h r11d\n\n%define y0 r13d\n%define y1 r14d\n%define y2 r15d\n\n\n\n_INP_END_SIZE\tequ 8\n_INP_SIZE\tequ 8\n_XFER_SIZE\tequ 8\n%ifdef LINUX\n_XMM_SAVE_SIZE\tequ 0\n%else\n_XMM_SAVE_SIZE\tequ 7*16\n%endif\n; STACK_SIZE plus pushes must be an odd multiple of 8\n_ALIGN_SIZE\tequ 8\n\n_INP_END\tequ 0\n_INP\t\tequ _INP_END  + _INP_END_SIZE\n_XFER\t\tequ _INP      + _INP_SIZE\n_XMM_SAVE\tequ _XFER     + _XFER_SIZE + _ALIGN_SIZE\nSTACK_SIZE\tequ _XMM_SAVE + _XMM_SAVE_SIZE\n\n; rotate_Xs\n; Rotate values of symbols X0...X3\n%macro rotate_Xs 0\n%xdefine X_ X0\n%xdefine X0 X1\n%xdefine X1 X2\n%xdefine X2 X3\n%xdefine X3 X_\n%endm\n\n; ROTATE_ARGS\n; Rotate values of symbols a...h\n%macro ROTATE_ARGS 0\n%xdefine TMP_ h\n%xdefine h g\n%xdefine g f\n%xdefine f e\n%xdefine e d\n%xdefine d c\n%xdefine c b\n%xdefine b a\n%xdefine a TMP_\n%endm\n\n%macro FOUR_ROUNDS_AND_SCHED 0\n\t;; compute s0 four at a time and s1 two at a time\n\t;; compute W[-16] + W[-7] 4 at a time\n\tmovdqa\tXTMP0, X3\n    mov\ty0, e\t\t; y0 = e\n    ror\ty0, (25-11)\t; y0 = e >> (25-11)\n    mov\ty1, a\t\t; y1 = a\n\tpalignr\tXTMP0, X2, 4\t; XTMP0 = W[-7]\n    ror\ty1, (22-13)\t; y1 = a >> (22-13)\n    xor\ty0, e\t\t; y0 = e ^ (e >> (25-11))\n    mov\ty2, f\t\t; y2 = f\n    ror\ty0, (11-6)\t; y0 = (e >> (11-6)) ^ (e >> (25-6))\n\tmovdqa\tXTMP1, X1\n    xor\ty1, a\t\t; y1 = a ^ (a >> (22-13)\n    xor\ty2, g\t\t; y2 = f^g\n\tpaddd\tXTMP0, X0\t; XTMP0 = W[-7] + W[-16]\n    xor\ty0, e\t\t; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))\n    and\ty2, e\t\t; y2 = (f^g)&e\n    ror\ty1, (13-2)\t; y1 = (a >> (13-2)) ^ (a >> (22-2))\n\t;; compute s0\n\tpalignr\tXTMP1, X0, 4\t; XTMP1 = W[-15]\n    xor\ty1, a\t\t; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))\n    ror\ty0, 6\t\t; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)\n    xor\ty2, g\t\t; y2 = CH = ((f^g)&e)^g\n\tmovdqa\tXTMP2, XTMP1\t; XTMP2 = W[-15]\n    ror\ty1, 2\t\t; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)\n    add\ty2, y0\t\t; y2 = S1 + CH\n    add\ty2, [rsp + _XFER + 0*4]\t; y2 = k + w + S1 + CH\n\tmovdqa\tXTMP3, XTMP1\t; XTMP3 = W[-15]\n    mov\ty0, a\t\t; y0 = a\n    add\th, y2\t\t; h = h + S1 + CH + k + w\n    mov\ty2, a\t\t; y2 = a\n\tpslld\tXTMP1, (32-7)\n    or\ty0, c\t\t; y0 = a|c\n    add\td, h\t\t; d = d + h + S1 + CH + k + w\n    and\ty2, c\t\t; y2 = a&c\n\tpsrld\tXTMP2, 7\n    and\ty0, b\t\t; y0 = (a|c)&b\n    add\th, y1\t\t; h = h + S1 + CH + k + w + S0\n\tpor\tXTMP1, XTMP2\t; XTMP1 = W[-15] ror 7\n    or\ty0, y2\t\t; y0 = MAJ = (a|c)&b)|(a&c)\n    add\th, y0\t\t; h = h + S1 + CH + k + w + S0 + MAJ\n\nROTATE_ARGS\n\tmovdqa\tXTMP2, XTMP3\t; XTMP2 = W[-15]\n    mov\ty0, e\t\t; y0 = e\n    mov\ty1, a\t\t; y1 = a\n\tmovdqa\tXTMP4, XTMP3\t; XTMP4 = W[-15]\n    ror\ty0, (25-11)\t; y0 = e >> (25-11)\n    xor\ty0, e\t\t; y0 = e ^ (e >> (25-11))\n    mov\ty2, f\t\t; y2 = f\n    ror\ty1, (22-13)\t; y1 = a >> (22-13)\n\tpslld\tXTMP3, (32-18)\n    xor\ty1, a\t\t; y1 = a ^ (a >> (22-13)\n    ror\ty0, (11-6)\t; y0 = (e >> (11-6)) ^ (e >> (25-6))\n    xor\ty2, g\t\t; y2 = f^g\n\tpsrld\tXTMP2, 18\n    ror\ty1, (13-2)\t; y1 = (a >> (13-2)) ^ (a >> (22-2))\n    xor\ty0, e\t\t; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))\n    and\ty2, e\t\t; y2 = (f^g)&e\n    ror\ty0, 6\t\t; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)\n\tpxor\tXTMP1, XTMP3\n    xor\ty1, a\t\t; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))\n    xor\ty2, g\t\t; y2 = CH = ((f^g)&e)^g\n\tpsrld\tXTMP4, 3\t; XTMP4 = W[-15] >> 3\n    add\ty2, y0\t\t; y2 = S1 + CH\n    add\ty2, [rsp + _XFER + 1*4]\t; y2 = k + w + S1 + CH\n    ror\ty1, 2\t\t; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)\n\tpxor\tXTMP1, XTMP2\t; XTMP1 = W[-15] ror 7 ^ W[-15] ror 18\n    mov\ty0, a\t\t; y0 = a\n    add\th, y2\t\t; h = h + S1 + CH + k + w\n    mov\ty2, a\t\t; y2 = a\n\tpxor\tXTMP1, XTMP4\t; XTMP1 = s0\n    or\ty0, c\t\t; y0 = a|c\n    add\td, h\t\t; d = d + h + S1 + CH + k + w\n    and\ty2, c\t\t; y2 = a&c\n\t;; compute low s1\n\tpshufd\tXTMP2, X3, 11111010b\t; XTMP2 = W[-2] {BBAA}\n    and\ty0, b\t\t; y0 = (a|c)&b\n    add\th, y1\t\t; h = h + S1 + CH + k + w + S0\n\tpaddd\tXTMP0, XTMP1\t; XTMP0 = W[-16] + W[-7] + s0\n    or\ty0, y2\t\t; y0 = MAJ = (a|c)&b)|(a&c)\n    add\th, y0\t\t; h = h + S1 + CH + k + w + S0 + MAJ\n\nROTATE_ARGS\n\tmovdqa\tXTMP3, XTMP2\t; XTMP3 = W[-2] {BBAA}\n    mov\ty0, e\t\t; y0 = e\n    mov\ty1, a\t\t; y1 = a\n    ror\ty0, (25-11)\t; y0 = e >> (25-11)\n\tmovdqa\tXTMP4, XTMP2\t; XTMP4 = W[-2] {BBAA}\n    xor\ty0, e\t\t; y0 = e ^ (e >> (25-11))\n    ror\ty1, (22-13)\t; y1 = a >> (22-13)\n    mov\ty2, f\t\t; y2 = f\n    xor\ty1, a\t\t; y1 = a ^ (a >> (22-13)\n    ror\ty0, (11-6)\t; y0 = (e >> (11-6)) ^ (e >> (25-6))\n\tpsrlq\tXTMP2, 17\t; XTMP2 = W[-2] ror 17 {xBxA}\n    xor\ty2, g\t\t; y2 = f^g\n\tpsrlq\tXTMP3, 19\t; XTMP3 = W[-2] ror 19 {xBxA}\n    xor\ty0, e\t\t; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))\n    and\ty2, e\t\t; y2 = (f^g)&e\n\tpsrld\tXTMP4, 10\t; XTMP4 = W[-2] >> 10 {BBAA}\n    ror\ty1, (13-2)\t; y1 = (a >> (13-2)) ^ (a >> (22-2))\n    xor\ty1, a\t\t; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))\n    xor\ty2, g\t\t; y2 = CH = ((f^g)&e)^g\n    ror\ty0, 6\t\t; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)\n\tpxor\tXTMP2, XTMP3\n    add\ty2, y0\t\t; y2 = S1 + CH\n    ror\ty1, 2\t\t; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)\n    add\ty2, [rsp + _XFER + 2*4]\t; y2 = k + w + S1 + CH\n\tpxor\tXTMP4, XTMP2\t; XTMP4 = s1 {xBxA}\n    mov\ty0, a\t\t; y0 = a\n    add\th, y2\t\t; h = h + S1 + CH + k + w\n    mov\ty2, a\t\t; y2 = a\n\tpshufb\tXTMP4, SHUF_00BA\t; XTMP4 = s1 {00BA}\n    or\ty0, c\t\t; y0 = a|c\n    add\td, h\t\t; d = d + h + S1 + CH + k + w\n    and\ty2, c\t\t; y2 = a&c\n\tpaddd\tXTMP0, XTMP4\t; XTMP0 = {..., ..., W[1], W[0]}\n    and\ty0, b\t\t; y0 = (a|c)&b\n    add\th, y1\t\t; h = h + S1 + CH + k + w + S0\n\t;; compute high s1\n\tpshufd\tXTMP2, XTMP0, 01010000b\t; XTMP2 = W[-2] {DDCC}\n    or\ty0, y2\t\t; y0 = MAJ = (a|c)&b)|(a&c)\n    add\th, y0\t\t; h = h + S1 + CH + k + w + S0 + MAJ\n\nROTATE_ARGS\n\tmovdqa\tXTMP3, XTMP2\t; XTMP3 = W[-2] {DDCC}\n    mov\ty0, e\t\t; y0 = e\n    ror\ty0, (25-11)\t; y0 = e >> (25-11)\n    mov\ty1, a\t\t; y1 = a\n\tmovdqa\tX0,    XTMP2\t; X0    = W[-2] {DDCC}\n    ror\ty1, (22-13)\t; y1 = a >> (22-13)\n    xor\ty0, e\t\t; y0 = e ^ (e >> (25-11))\n    mov\ty2, f\t\t; y2 = f\n    ror\ty0, (11-6)\t; y0 = (e >> (11-6)) ^ (e >> (25-6))\n\tpsrlq\tXTMP2, 17\t; XTMP2 = W[-2] ror 17 {xDxC}\n    xor\ty1, a\t\t; y1 = a ^ (a >> (22-13)\n    xor\ty2, g\t\t; y2 = f^g\n\tpsrlq\tXTMP3, 19\t; XTMP3 = W[-2] ror 19 {xDxC}\n    xor\ty0, e\t\t; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))\n    and\ty2, e\t\t; y2 = (f^g)&e\n    ror\ty1, (13-2)\t; y1 = (a >> (13-2)) ^ (a >> (22-2))\n\tpsrld\tX0,    10\t; X0 = W[-2] >> 10 {DDCC}\n    xor\ty1, a\t\t; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))\n    ror\ty0, 6\t\t; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)\n    xor\ty2, g\t\t; y2 = CH = ((f^g)&e)^g\n\tpxor\tXTMP2, XTMP3\n    ror\ty1, 2\t\t; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)\n    add\ty2, y0\t\t; y2 = S1 + CH\n    add\ty2, [rsp + _XFER + 3*4]\t; y2 = k + w + S1 + CH\n\tpxor\tX0, XTMP2\t; X0 = s1 {xDxC}\n    mov\ty0, a\t\t; y0 = a\n    add\th, y2\t\t; h = h + S1 + CH + k + w\n    mov\ty2, a\t\t; y2 = a\n\tpshufb\tX0, SHUF_DC00\t; X0 = s1 {DC00}\n    or\ty0, c\t\t; y0 = a|c\n    add\td, h\t\t; d = d + h + S1 + CH + k + w\n    and\ty2, c\t\t; y2 = a&c\n\tpaddd\tX0, XTMP0\t; X0 = {W[3], W[2], W[1], W[0]}\n    and\ty0, b\t\t; y0 = (a|c)&b\n    add\th, y1\t\t; h = h + S1 + CH + k + w + S0\n    or\ty0, y2\t\t; y0 = MAJ = (a|c)&b)|(a&c)\n    add\th, y0\t\t; h = h + S1 + CH + k + w + S0 + MAJ\n\nROTATE_ARGS\nrotate_Xs\n%endm\n\n;; input is [rsp + _XFER + %1 * 4]\n%macro DO_ROUND 1\n    mov\ty0, e\t\t; y0 = e\n    ror\ty0, (25-11)\t; y0 = e >> (25-11)\n    mov\ty1, a\t\t; y1 = a\n    xor\ty0, e\t\t; y0 = e ^ (e >> (25-11))\n    ror\ty1, (22-13)\t; y1 = a >> (22-13)\n    mov\ty2, f\t\t; y2 = f\n    xor\ty1, a\t\t; y1 = a ^ (a >> (22-13)\n    ror\ty0, (11-6)\t; y0 = (e >> (11-6)) ^ (e >> (25-6))\n    xor\ty2, g\t\t; y2 = f^g\n    xor\ty0, e\t\t; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))\n    ror\ty1, (13-2)\t; y1 = (a >> (13-2)) ^ (a >> (22-2))\n    and\ty2, e\t\t; y2 = (f^g)&e\n    xor\ty1, a\t\t; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))\n    ror\ty0, 6\t\t; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)\n    xor\ty2, g\t\t; y2 = CH = ((f^g)&e)^g\n    add\ty2, y0\t\t; y2 = S1 + CH\n    ror\ty1, 2\t\t; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)\n    add\ty2, [rsp + _XFER + %1 * 4]\t; y2 = k + w + S1 + CH\n    mov\ty0, a\t\t; y0 = a\n    add\th, y2\t\t; h = h + S1 + CH + k + w\n    mov\ty2, a\t\t; y2 = a\n    or\ty0, c\t\t; y0 = a|c\n    add\td, h\t\t; d = d + h + S1 + CH + k + w\n    and\ty2, c\t\t; y2 = a&c\n    and\ty0, b\t\t; y0 = (a|c)&b\n    add\th, y1\t\t; h = h + S1 + CH + k + w + S0\n    or\ty0, y2\t\t; y0 = MAJ = (a|c)&b)|(a&c)\n    add\th, y0\t\t; h = h + S1 + CH + k + w + S0 + MAJ\n    ROTATE_ARGS\n%endm\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; void sha256_sse4(void *input_data, UINT32 digest[8], UINT64 num_blks)\n;; arg 1 : pointer to input data\n;; arg 2 : pointer to digest\n;; arg 3 : Num blocks\nsection .text\nglobal sha256_sse4\nalign 32\nsha256_sse4:\n    push\trbx\n%ifndef LINUX\n    push\trsi\n    push\trdi\n%endif\n    push\trbp\n    push\tr13\n    push\tr14\n    push\tr15\n\n    sub\trsp,STACK_SIZE\n%ifndef LINUX\n    movdqa\t[rsp + _XMM_SAVE + 0*16],xmm6\t\n    movdqa\t[rsp + _XMM_SAVE + 1*16],xmm7\n    movdqa\t[rsp + _XMM_SAVE + 2*16],xmm8\t\n    movdqa\t[rsp + _XMM_SAVE + 3*16],xmm9\t\n    movdqa\t[rsp + _XMM_SAVE + 4*16],xmm10\n    movdqa\t[rsp + _XMM_SAVE + 5*16],xmm11\n    movdqa\t[rsp + _XMM_SAVE + 6*16],xmm12\n%endif\n\n    shl\tNUM_BLKS, 6\t; convert to bytes\n    jz\tdone_hash\n    add\tNUM_BLKS, INP\t; pointer to end of data\n    mov\t[rsp + _INP_END], NUM_BLKS\n\n    ;; load initial digest\n    mov\ta,[4*0 + CTX]\n    mov\tb,[4*1 + CTX]\n    mov\tc,[4*2 + CTX]\n    mov\td,[4*3 + CTX]\n    mov\te,[4*4 + CTX]\n    mov\tf,[4*5 + CTX]\n    mov\tg,[4*6 + CTX]\n    mov\th,[4*7 + CTX]\n\n    movdqa\tBYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]\n    movdqa\tSHUF_00BA, [_SHUF_00BA wrt rip]\n    movdqa\tSHUF_DC00, [_SHUF_DC00 wrt rip]\n\nloop0:\n    lea\tTBL,[K256 wrt rip]\n\n    ;; byte swap first 16 dwords\n    COPY_XMM_AND_BSWAP\tX0, [INP + 0*16], BYTE_FLIP_MASK\n    COPY_XMM_AND_BSWAP\tX1, [INP + 1*16], BYTE_FLIP_MASK\n    COPY_XMM_AND_BSWAP\tX2, [INP + 2*16], BYTE_FLIP_MASK\n    COPY_XMM_AND_BSWAP\tX3, [INP + 3*16], BYTE_FLIP_MASK\n    \n    mov\t[rsp + _INP], INP\n\n    ;; schedule 48 input dwords, by doing 3 rounds of 16 each\n    mov\tSRND, 3\nalign 16\nloop1:\n    movdqa\tXFER, [TBL + 0*16]\n    paddd\tXFER, X0\n    movdqa\t[rsp + _XFER], XFER\n    FOUR_ROUNDS_AND_SCHED\n\n    movdqa\tXFER, [TBL + 1*16]\n    paddd\tXFER, X0\n    movdqa\t[rsp + _XFER], XFER\n    FOUR_ROUNDS_AND_SCHED\n\n    movdqa\tXFER, [TBL + 2*16]\n    paddd\tXFER, X0\n    movdqa\t[rsp + _XFER], XFER\n    FOUR_ROUNDS_AND_SCHED\n\n    movdqa\tXFER, [TBL + 3*16]\n    paddd\tXFER, X0\n    movdqa\t[rsp + _XFER], XFER\n    add\tTBL, 4*16\n    FOUR_ROUNDS_AND_SCHED\n\n    sub\tSRND, 1\n    jne\tloop1\n\n    mov\tSRND, 2\nloop2:\n    paddd\tX0, [TBL + 0*16]\n    movdqa\t[rsp + _XFER], X0\n    DO_ROUND\t0\n    DO_ROUND\t1\n    DO_ROUND\t2\n    DO_ROUND\t3\n    paddd\tX1, [TBL + 1*16]\n    movdqa\t[rsp + _XFER], X1\n    add\tTBL, 2*16\n    DO_ROUND\t0\n    DO_ROUND\t1\n    DO_ROUND\t2\n    DO_ROUND\t3\n\n    movdqa\tX0, X2\n    movdqa\tX1, X3\n\n    sub\tSRND, 1\n    jne\tloop2\n\n    addm\t[4*0 + CTX],a\n    addm\t[4*1 + CTX],b\n    addm\t[4*2 + CTX],c\n    addm\t[4*3 + CTX],d\n    addm\t[4*4 + CTX],e\n    addm\t[4*5 + CTX],f\n    addm\t[4*6 + CTX],g\n    addm\t[4*7 + CTX],h\n\n    mov\tINP, [rsp + _INP]\n    add\tINP, 64\n    cmp\tINP, [rsp + _INP_END]\n    jne\tloop0\n\ndone_hash:\n%ifndef LINUX\n    movdqa\txmm6,[rsp + _XMM_SAVE + 0*16]\n    movdqa\txmm7,[rsp + _XMM_SAVE + 1*16]\n    movdqa\txmm8,[rsp + _XMM_SAVE + 2*16]\n    movdqa\txmm9,[rsp + _XMM_SAVE + 3*16]\n    movdqa\txmm10,[rsp + _XMM_SAVE + 4*16]\n    movdqa\txmm11,[rsp + _XMM_SAVE + 5*16]\n    movdqa\txmm12,[rsp + _XMM_SAVE + 6*16]\n%endif\n\n    add\trsp, STACK_SIZE\n\n    pop\tr15\n    pop\tr14\n    pop\tr13\n    pop\trbp\n%ifndef LINUX\n    pop\trdi\n    pop\trsi\n%endif\n    pop\trbx\n\n    ret\t\n    \n\nsection .data\nalign 64\nK256:\n    dd\t0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5\n    dd\t0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5\n    dd\t0xd807aa98,0x12835b01,0x243185be,0x550c7dc3\n    dd\t0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174\n    dd\t0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc\n    dd\t0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da\n    dd\t0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7\n    dd\t0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967\n    dd\t0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13\n    dd\t0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85\n    dd\t0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3\n    dd\t0xd192e819,0xd6990624,0xf40e3585,0x106aa070\n    dd\t0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5\n    dd\t0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3\n    dd\t0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208\n    dd\t0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2\n\nPSHUFFLE_BYTE_FLIP_MASK: ddq 0x0c0d0e0f08090a0b0405060700010203\n\n; shuffle xBxA -> 00BA\n_SHUF_00BA:              ddq 0xFFFFFFFFFFFFFFFF0b0a090803020100\n\n; shuffle xDxC -> DC00\n_SHUF_DC00:              ddq 0x0b0a090803020100FFFFFFFFFFFFFFFF\n*/\n\n#endif\n"
  },
  {
    "path": "src/crypto/sha256_x86_shani.cpp",
    "content": "// Copyright (c) 2018-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// Based on https://github.com/noloader/SHA-Intrinsics/blob/master/sha256-x86.c,\n// Written and placed in public domain by Jeffrey Walton.\n// Based on code from Intel, and by Sean Gulley for the miTLS project.\n\n#include <compat/sys.h>\n#include <compat/sse.h>\n\n#if defined(COMPILER_HAS_SSE4_SHANI) && !defined(PLATFORM_MOBILE_ANDROID)\n\nnamespace {\n\nalignas(__m128i) const uint8_t MASK[16] = {0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c};\nalignas(__m128i) const uint8_t INIT0[16] = {0x8c, 0x68, 0x05, 0x9b, 0x7f, 0x52, 0x0e, 0x51, 0x85, 0xae, 0x67, 0xbb, 0x67, 0xe6, 0x09, 0x6a};\nalignas(__m128i) const uint8_t INIT1[16] = {0x19, 0xcd, 0xe0, 0x5b, 0xab, 0xd9, 0x83, 0x1f, 0x3a, 0xf5, 0x4f, 0xa5, 0x72, 0xf3, 0x6e, 0x3c};\n\nvoid inline  __attribute__((always_inline)) QuadRound(__m128i& state0, __m128i& state1, uint64_t k1, uint64_t k0)\n{\n    const __m128i msg = _mm_set_epi64x(k1, k0);\n    state1 = _mm_sha256rnds2_epu32(state1, state0, msg);\n    state0 = _mm_sha256rnds2_epu32(state0, state1, _mm_shuffle_epi32(msg, 0x0e));\n}\n\nvoid inline  __attribute__((always_inline)) QuadRound(__m128i& state0, __m128i& state1, __m128i m, uint64_t k1, uint64_t k0)\n{\n    const __m128i msg = _mm_add_epi32(m, _mm_set_epi64x(k1, k0));\n    state1 = _mm_sha256rnds2_epu32(state1, state0, msg);\n    state0 = _mm_sha256rnds2_epu32(state0, state1, _mm_shuffle_epi32(msg, 0x0e));\n}\n\nvoid inline  __attribute__((always_inline)) ShiftMessageA(__m128i& m0, __m128i m1)\n{\n    m0 = _mm_sha256msg1_epu32(m0, m1);\n}\n\nvoid inline  __attribute__((always_inline)) ShiftMessageC(__m128i& m0, __m128i m1, __m128i& m2)\n{\n    m2 = _mm_sha256msg2_epu32(_mm_add_epi32(m2, _mm_alignr_epi8(m1, m0, 4)), m1);\n}\n\nvoid inline __attribute__((always_inline)) ShiftMessageB(__m128i& m0, __m128i m1, __m128i& m2)\n{\n    ShiftMessageC(m0, m1, m2);\n    ShiftMessageA(m0, m1);\n}\n\nvoid inline __attribute__((always_inline)) Shuffle(__m128i& s0, __m128i& s1)\n{\n    const __m128i t1 = _mm_shuffle_epi32(s0, 0xB1);\n    const __m128i t2 = _mm_shuffle_epi32(s1, 0x1B);\n    s0 = _mm_alignr_epi8(t1, t2, 0x08);\n    s1 = _mm_blend_epi16(t2, t1, 0xF0);\n}\n\nvoid inline __attribute__((always_inline)) Unshuffle(__m128i& s0, __m128i& s1)\n{\n    const __m128i t1 = _mm_shuffle_epi32(s0, 0x1B);\n    const __m128i t2 = _mm_shuffle_epi32(s1, 0xB1);\n    s0 = _mm_blend_epi16(t1, t2, 0xF0);\n    s1 = _mm_alignr_epi8(t2, t1, 0x08);\n}\n\n__m128i inline  __attribute__((always_inline)) Load(const unsigned char* in)\n{\n    return _mm_shuffle_epi8(_mm_loadu_si128((const __m128i*)in), _mm_load_si128((const __m128i*)MASK));\n}\n\nvoid inline  __attribute__((always_inline)) Save(unsigned char* out, __m128i s)\n{\n    _mm_storeu_si128((__m128i*)out, _mm_shuffle_epi8(s, _mm_load_si128((const __m128i*)MASK)));\n}\n}\n\nnamespace sha256_x86_shani {\nvoid Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)\n{\n    __m128i m0, m1, m2, m3, s0, s1, so0, so1;\n\n    /* Load state */\n    s0 = _mm_loadu_si128((const __m128i*)s);\n    s1 = _mm_loadu_si128((const __m128i*)(s + 4));\n    Shuffle(s0, s1);\n\n    while (blocks--) {\n        /* Remember old state */\n        so0 = s0;\n        so1 = s1;\n\n        /* Load data and transform */\n        m0 = Load(chunk);\n        QuadRound(s0, s1, m0, 0xe9b5dba5b5c0fbcfull, 0x71374491428a2f98ull);\n        m1 = Load(chunk + 16);\n        QuadRound(s0, s1, m1, 0xab1c5ed5923f82a4ull, 0x59f111f13956c25bull);\n        ShiftMessageA(m0, m1);\n        m2 = Load(chunk + 32);\n        QuadRound(s0, s1, m2, 0x550c7dc3243185beull, 0x12835b01d807aa98ull);\n        ShiftMessageA(m1, m2);\n        m3 = Load(chunk + 48);\n        QuadRound(s0, s1, m3, 0xc19bf1749bdc06a7ull, 0x80deb1fe72be5d74ull);\n        ShiftMessageB(m2, m3, m0);\n        QuadRound(s0, s1, m0, 0x240ca1cc0fc19dc6ull, 0xefbe4786E49b69c1ull);\n        ShiftMessageB(m3, m0, m1);\n        QuadRound(s0, s1, m1, 0x76f988da5cb0a9dcull, 0x4a7484aa2de92c6full);\n        ShiftMessageB(m0, m1, m2);\n        QuadRound(s0, s1, m2, 0xbf597fc7b00327c8ull, 0xa831c66d983e5152ull);\n        ShiftMessageB(m1, m2, m3);\n        QuadRound(s0, s1, m3, 0x1429296706ca6351ull, 0xd5a79147c6e00bf3ull);\n        ShiftMessageB(m2, m3, m0);\n        QuadRound(s0, s1, m0, 0x53380d134d2c6dfcull, 0x2e1b213827b70a85ull);\n        ShiftMessageB(m3, m0, m1);\n        QuadRound(s0, s1, m1, 0x92722c8581c2c92eull, 0x766a0abb650a7354ull);\n        ShiftMessageB(m0, m1, m2);\n        QuadRound(s0, s1, m2, 0xc76c51A3c24b8b70ull, 0xa81a664ba2bfe8a1ull);\n        ShiftMessageB(m1, m2, m3);\n        QuadRound(s0, s1, m3, 0x106aa070f40e3585ull, 0xd6990624d192e819ull);\n        ShiftMessageB(m2, m3, m0);\n        QuadRound(s0, s1, m0, 0x34b0bcb52748774cull, 0x1e376c0819a4c116ull);\n        ShiftMessageB(m3, m0, m1);\n        QuadRound(s0, s1, m1, 0x682e6ff35b9cca4full, 0x4ed8aa4a391c0cb3ull);\n        ShiftMessageC(m0, m1, m2);\n        QuadRound(s0, s1, m2, 0x8cc7020884c87814ull, 0x78a5636f748f82eeull);\n        ShiftMessageC(m1, m2, m3);\n        QuadRound(s0, s1, m3, 0xc67178f2bef9A3f7ull, 0xa4506ceb90befffaull);\n\n        /* Combine with old state */\n        s0 = _mm_add_epi32(s0, so0);\n        s1 = _mm_add_epi32(s1, so1);\n\n        /* Advance */\n        chunk += 64;\n    }\n\n    Unshuffle(s0, s1);\n    _mm_storeu_si128((__m128i*)s, s0);\n    _mm_storeu_si128((__m128i*)(s + 4), s1);\n}\n}\n\n#endif\n"
  },
  {
    "path": "src/crypto/sha512.cpp",
    "content": "// Copyright (c) 2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/sha512.h\"\n\n#include \"crypto/common.h\"\n#include <support/cleanse.h>\n\n#include <string.h>\n\n// Internal implementation code.\nnamespace\n{\n/// Internal SHA-512 implementation.\nnamespace sha512\n{\nuint64_t inline Ch(uint64_t x, uint64_t y, uint64_t z) { return z ^ (x & (y ^ z)); }\nuint64_t inline Maj(uint64_t x, uint64_t y, uint64_t z) { return (x & y) | (z & (x | y)); }\nuint64_t inline Sigma0(uint64_t x) { return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); }\nuint64_t inline Sigma1(uint64_t x) { return (x >> 14 | x << 50) ^ (x >> 18 | x << 46) ^ (x >> 41 | x << 23); }\nuint64_t inline sigma0(uint64_t x) { return (x >> 1 | x << 63) ^ (x >> 8 | x << 56) ^ (x >> 7); }\nuint64_t inline sigma1(uint64_t x) { return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); }\n\n/** One round of SHA-512. */\nvoid inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, uint64_t f, uint64_t g, uint64_t& h, uint64_t k, uint64_t w)\n{\n    uint64_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w;\n    uint64_t t2 = Sigma0(a) + Maj(a, b, c);\n    d += t1;\n    h = t1 + t2;\n}\n\n/** Initialize SHA-256 state. */\nvoid inline Initialize(uint64_t* s)\n{\n    s[0] = 0x6a09e667f3bcc908ull;\n    s[1] = 0xbb67ae8584caa73bull;\n    s[2] = 0x3c6ef372fe94f82bull;\n    s[3] = 0xa54ff53a5f1d36f1ull;\n    s[4] = 0x510e527fade682d1ull;\n    s[5] = 0x9b05688c2b3e6c1full;\n    s[6] = 0x1f83d9abfb41bd6bull;\n    s[7] = 0x5be0cd19137e2179ull;\n}\n\n/** Perform one SHA-512 transformation, processing a 128-byte chunk. */\nvoid Transform(uint64_t* s, const unsigned char* chunk)\n{\n    uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n    uint64_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;\n\n    Round(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22ull, w0 = ReadBE64(chunk + 0));\n    Round(h, a, b, c, d, e, f, g, 0x7137449123ef65cdull, w1 = ReadBE64(chunk + 8));\n    Round(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2full, w2 = ReadBE64(chunk + 16));\n    Round(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbcull, w3 = ReadBE64(chunk + 24));\n    Round(e, f, g, h, a, b, c, d, 0x3956c25bf348b538ull, w4 = ReadBE64(chunk + 32));\n    Round(d, e, f, g, h, a, b, c, 0x59f111f1b605d019ull, w5 = ReadBE64(chunk + 40));\n    Round(c, d, e, f, g, h, a, b, 0x923f82a4af194f9bull, w6 = ReadBE64(chunk + 48));\n    Round(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118ull, w7 = ReadBE64(chunk + 56));\n    Round(a, b, c, d, e, f, g, h, 0xd807aa98a3030242ull, w8 = ReadBE64(chunk + 64));\n    Round(h, a, b, c, d, e, f, g, 0x12835b0145706fbeull, w9 = ReadBE64(chunk + 72));\n    Round(g, h, a, b, c, d, e, f, 0x243185be4ee4b28cull, w10 = ReadBE64(chunk + 80));\n    Round(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2ull, w11 = ReadBE64(chunk + 88));\n    Round(e, f, g, h, a, b, c, d, 0x72be5d74f27b896full, w12 = ReadBE64(chunk + 96));\n    Round(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1ull, w13 = ReadBE64(chunk + 104));\n    Round(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235ull, w14 = ReadBE64(chunk + 112));\n    Round(b, c, d, e, f, g, h, a, 0xc19bf174cf692694ull, w15 = ReadBE64(chunk + 120));\n\n    Round(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65ull, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275ull, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483ull, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x76f988da831153b5ull, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0x983e5152ee66dfabull, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0xa831c66d2db43210ull, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0xb00327c898fb213full, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4ull, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0(w0));\n\n    Round(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aedull, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x53380d139d95b3dfull, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x650a73548baf63deull, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8ull, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6ull, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x92722c851482353bull, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364ull, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0xa81a664bbc423001ull, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791ull, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0xc76c51a30654be30ull, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0(w0));\n\n    Round(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99ull, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8ull, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63ull, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acbull, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373ull, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fcull, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0x78a5636f43172f60ull, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72ull, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0x8cc702081a6439ecull, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0(w0));\n\n    Round(a, b, c, d, e, f, g, h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1eull, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178ull, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x06f067aa72176fbaull, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6ull, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x113f9804bef90daeull, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x1b710b35131c471bull, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0x28db77f523047d84ull, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0x32caab7b40c72493ull, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebcull, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0x431d67c49c100d4cull, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faecull, w14 + sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0x6c44198c4a475817ull, w15 + sigma1(w13) + w8 + sigma0(w0));\n\n    s[0] += a;\n    s[1] += b;\n    s[2] += c;\n    s[3] += d;\n    s[4] += e;\n    s[5] += f;\n    s[6] += g;\n    s[7] += h;\n}\n\n} // namespace sha512\n\n} // namespace\n\n\n////// SHA-512\n\nCSHA512::CSHA512() : bytes(0)\n{\n    sha512::Initialize(s);\n}\n\nCSHA512& CSHA512::Write(const unsigned char* data, size_t len)\n{\n    const unsigned char* end = data + len;\n    size_t bufsize = bytes % 128;\n    if (bufsize && bufsize + len >= 128) {\n        // Fill the buffer, and process it.\n        memcpy(buf + bufsize, data, 128 - bufsize);\n        bytes += 128 - bufsize;\n        data += 128 - bufsize;\n        sha512::Transform(s, buf);\n        bufsize = 0;\n    }\n    while (end - data >= 128) {\n        // Process full chunks directly from the source.\n        sha512::Transform(s, data);\n        data += 128;\n        bytes += 128;\n    }\n    if (end > data) {\n        // Fill the buffer with what remains.\n        memcpy(buf + bufsize, data, end - data);\n        bytes += end - data;\n    }\n    return *this;\n}\n\nvoid CSHA512::Finalize(unsigned char hash[OUTPUT_SIZE])\n{\n    static const unsigned char pad[128] = {0x80};\n    unsigned char sizedesc[16] = {0x00};\n    WriteBE64(sizedesc + 8, bytes << 3);\n    Write(pad, 1 + ((239 - (bytes % 128)) % 128));\n    Write(sizedesc, 16);\n    WriteBE64(hash, s[0]);\n    WriteBE64(hash + 8, s[1]);\n    WriteBE64(hash + 16, s[2]);\n    WriteBE64(hash + 24, s[3]);\n    WriteBE64(hash + 32, s[4]);\n    WriteBE64(hash + 40, s[5]);\n    WriteBE64(hash + 48, s[6]);\n    WriteBE64(hash + 56, s[7]);\n\n    memory_cleanse(&buf[0], 128);\n    memory_cleanse(&s[0], 32);\n}\n\nCSHA512& CSHA512::Reset()\n{\n    bytes = 0;\n    sha512::Initialize(s);\n    return *this;\n}\n"
  },
  {
    "path": "src/crypto/sha512.h",
    "content": "// Copyright (c) 2014-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CRYPTO_SHA512_H\n#define CRYPTO_SHA512_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n/** A hasher class for SHA-512. */\nclass CSHA512\n{\nprivate:\n    uint64_t s[8];\n    unsigned char buf[128];\n    uint64_t bytes;\n\npublic:\n    static constexpr size_t OUTPUT_SIZE = 64;\n\n    CSHA512();\n    CSHA512& Write(const unsigned char* data, size_t len);\n    void Finalize(unsigned char hash[OUTPUT_SIZE]);\n    CSHA512& Reset();\n    uint64_t Size() const { return bytes; }\n};\n\n#endif\n"
  },
  {
    "path": "src/cuckoocache.h",
    "content": "// Copyright (c) 2016 Jeremy Rubin\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CUCKOOCACHE_H\n#define CUCKOOCACHE_H\n\n#include <array>\n#include <algorithm>\n#include <atomic>\n#include <cstring>\n#include <cmath>\n#include <memory>\n#include <vector>\n\n\n/** namespace CuckooCache provides high performance cache primitives\n *\n * Summary:\n *\n * 1) bit_packed_atomic_flags is bit-packed atomic flags for garbage collection\n *\n * 2) cache is a cache which is performant in memory usage and lookup speed. It\n * is lockfree for erase operations. Elements are lazily erased on the next\n * insert.\n */\nnamespace CuckooCache\n{\n/** bit_packed_atomic_flags implements a container for garbage collection flags\n * that is only thread unsafe on calls to setup. This class bit-packs collection\n * flags for memory efficiency.\n *\n * All operations are std::memory_order_relaxed so external mechanisms must\n * ensure that writes and reads are properly synchronized.\n *\n * On setup(n), all bits up to n are marked as collected.\n *\n * Under the hood, because it is an 8-bit type, it makes sense to use a multiple\n * of 8 for setup, but it will be safe if that is not the case as well.\n *\n */\nclass bit_packed_atomic_flags\n{\n    std::unique_ptr<std::atomic<uint8_t>[]> mem;\n\npublic:\n    /** No default constructor as there must be some size */\n    bit_packed_atomic_flags() = delete;\n\n    /**\n     * bit_packed_atomic_flags constructor creates memory to sufficiently\n     * keep track of garbage collection information for size entries.\n     *\n     * @param size the number of elements to allocate space for\n     *\n     * @post bit_set, bit_unset, and bit_is_set function properly forall x. x <\n     * size\n     * @post All calls to bit_is_set (without subsequent bit_unset) will return\n     * true.\n     */\n    bit_packed_atomic_flags(uint32_t size)\n    {\n        // pad out the size if needed\n        size = (size + 7) / 8;\n        mem.reset(new std::atomic<uint8_t>[size]);\n        for (uint32_t i = 0; i < size; ++i)\n            mem[i].store(0xFF);\n    };\n\n    /** setup marks all entries and ensures that bit_packed_atomic_flags can store\n     * at least size entries\n     *\n     * @param b the number of elements to allocate space for\n     * @post bit_set, bit_unset, and bit_is_set function properly forall x. x <\n     * b\n     * @post All calls to bit_is_set (without subsequent bit_unset) will return\n     * true.\n     */\n    inline void setup(uint32_t b)\n    {\n        bit_packed_atomic_flags d(b);\n        std::swap(mem, d.mem);\n    }\n\n    /** bit_set sets an entry as discardable.\n     *\n     * @param s the index of the entry to bit_set.\n     * @post immediately subsequent call (assuming proper external memory\n     * ordering) to bit_is_set(s) == true.\n     *\n     */\n    inline void bit_set(uint32_t s)\n    {\n        mem[s >> 3].fetch_or(1 << (s & 7), std::memory_order_relaxed);\n    }\n\n    /**  bit_unset marks an entry as something that should not be overwritten\n     *\n     * @param s the index of the entry to bit_unset.\n     * @post immediately subsequent call (assuming proper external memory\n     * ordering) to bit_is_set(s) == false.\n     */\n    inline void bit_unset(uint32_t s)\n    {\n        mem[s >> 3].fetch_and(~(1 << (s & 7)), std::memory_order_relaxed);\n    }\n\n    /** bit_is_set queries the table for discardability at s\n     *\n     * @param s the index of the entry to read.\n     * @returns if the bit at index s was set.\n     * */\n    inline bool bit_is_set(uint32_t s) const\n    {\n        return (1 << (s & 7)) & mem[s >> 3].load(std::memory_order_relaxed);\n    }\n};\n\n/** cache implements a cache with properties similar to a cuckoo-set\n *\n *  The cache is able to hold up to (~(uint32_t)0) - 1 elements.\n *\n *  Read Operations:\n *      - contains(*, false)\n *\n *  Read+Erase Operations:\n *      - contains(*, true)\n *\n *  Erase Operations:\n *      - allow_erase()\n *\n *  Write Operations:\n *      - setup()\n *      - setup_bytes()\n *      - insert()\n *      - please_keep()\n *\n *  Synchronization Free Operations:\n *      - invalid()\n *      - compute_hashes()\n *\n * User Must Guarantee:\n *\n * 1) Write Requires synchronized access (e.g., a lock)\n * 2) Read Requires no concurrent Write, synchronized with the last insert.\n * 3) Erase requires no concurrent Write, synchronized with last insert.\n * 4) An Erase caller must release all memory before allowing a new Writer.\n *\n *\n * Note on function names:\n *   - The name \"allow_erase\" is used because the real discard happens later.\n *   - The name \"please_keep\" is used because elements may be erased anyways on insert.\n *\n * @tparam Element should be a movable and copyable type\n * @tparam Hash should be a function/callable which takes a template parameter\n * hash_select and an Element and extracts a hash from it. Should return\n * high-entropy uint32_t hashes for `Hash h; h<0>(e) ... h<7>(e)`.\n */\ntemplate <typename Element, typename Hash>\nclass cache\n{\nprivate:\n    /** table stores all the elements */\n    std::vector<Element> table;\n\n    /** size stores the total available slots in the hash table */\n    uint32_t size;\n\n    /** The bit_packed_atomic_flags array is marked mutable because we want\n     * garbage collection to be allowed to occur from const methods */\n    mutable bit_packed_atomic_flags collection_flags;\n\n    /** epoch_flags tracks how recently an element was inserted into\n     * the cache. true denotes recent, false denotes not-recent. See insert()\n     * method for full semantics.\n     */\n    mutable std::vector<bool> epoch_flags;\n\n    /** epoch_heuristic_counter is used to determine when a epoch might be aged\n     * & an expensive scan should be done.  epoch_heuristic_counter is\n     * decremented on insert and reset to the new number of inserts which would\n     * cause the epoch to reach epoch_size when it reaches zero.\n     */\n    uint32_t epoch_heuristic_counter;\n\n    /** epoch_size is set to be the number of elements supposed to be in a\n     * epoch. When the number of non-erased elements in a epoch\n     * exceeds epoch_size, a new epoch should be started and all\n     * current entries demoted. epoch_size is set to be 45% of size because\n     * we want to keep load around 90%, and we support 3 epochs at once --\n     * one \"dead\" which has been erased, one \"dying\" which has been marked to be\n     * erased next, and one \"living\" which new inserts add to.\n     */\n    uint32_t epoch_size;\n\n    /** depth_limit determines how many elements insert should try to replace.\n     * Should be set to log2(n)*/\n    uint8_t depth_limit;\n\n    /** hash_function is a const instance of the hash function. It cannot be\n     * static or initialized at call time as it may have internal state (such as\n     * a nonce).\n     * */\n    const Hash hash_function;\n\n    /** compute_hashes is convenience for not having to write out this\n     * expression everywhere we use the hash values of an Element.\n     *\n     * @param e the element whose hashes will be returned\n     * @returns std::array<uint32_t, 8> of deterministic hashes derived from e\n     */\n    inline std::array<uint32_t, 8> compute_hashes(const Element& e) const\n    {\n        return {{(uint32_t)((hash_function.template operator()<0>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<1>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<2>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<3>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<4>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<5>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<6>(e) * (uint64_t)size) >> 32),\n                 (uint32_t)((hash_function.template operator()<7>(e) * (uint64_t)size) >> 32)}};\n    }\n\n    /* end\n     * @returns a constexpr index that can never be inserted to */\n    constexpr uint32_t invalid() const\n    {\n        return ~(uint32_t)0;\n    }\n\n    /** allow_erase marks the element at index n as discardable. Threadsafe\n     * without any concurrent insert.\n     * @param n the index to allow erasure of\n     */\n    inline void allow_erase(uint32_t n) const\n    {\n        collection_flags.bit_set(n);\n    }\n\n    /** please_keep marks the element at index n as an entry that should be kept.\n     * Threadsafe without any concurrent insert.\n     * @param n the index to prioritize keeping\n     */\n    inline void please_keep(uint32_t n) const\n    {\n        collection_flags.bit_unset(n);\n    }\n\n    /** epoch_check handles the changing of epochs for elements stored in the\n     * cache. epoch_check should be run before every insert.\n     *\n     * First, epoch_check decrements and checks the cheap heuristic, and then does\n     * a more expensive scan if the cheap heuristic runs out. If the expensive\n     * scan succeeds, the epochs are aged and old elements are allow_erased. The\n     * cheap heuristic is reset to retrigger after the worst case growth of the\n     * current epoch's elements would exceed the epoch_size.\n     */\n    void epoch_check()\n    {\n        if (epoch_heuristic_counter != 0) {\n            --epoch_heuristic_counter;\n            return;\n        }\n        // count the number of elements from the latest epoch which\n        // have not been erased.\n        uint32_t epoch_unused_count = 0;\n        for (uint32_t i = 0; i < size; ++i)\n            epoch_unused_count += epoch_flags[i] &&\n                                  !collection_flags.bit_is_set(i);\n        // If there are more non-deleted entries in the current epoch than the\n        // epoch size, then allow_erase on all elements in the old epoch (marked\n        // false) and move all elements in the current epoch to the old epoch\n        // but do not call allow_erase on their indices.\n        if (epoch_unused_count >= epoch_size) {\n            for (uint32_t i = 0; i < size; ++i)\n                if (epoch_flags[i])\n                    epoch_flags[i] = false;\n                else\n                    allow_erase(i);\n            epoch_heuristic_counter = epoch_size;\n        } else\n            // reset the epoch_heuristic_counter to next do a scan when worst\n            // case behavior (no intermittent erases) would exceed epoch size,\n            // with a reasonable minimum scan size.\n            // Ordinarily, we would have to sanity check std::min(epoch_size,\n            // epoch_unused_count), but we already know that `epoch_unused_count\n            // < epoch_size` in this branch\n            epoch_heuristic_counter = std::max(1u, std::max(epoch_size / 16,\n                        epoch_size - epoch_unused_count));\n    }\n\npublic:\n    /** You must always construct a cache with some elements via a subsequent\n     * call to setup or setup_bytes, otherwise operations may segfault.\n     */\n    cache() : table(), size(), collection_flags(0), epoch_flags(),\n    epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function()\n    {\n    }\n\n    /** setup initializes the container to store no more than new_size\n     * elements.\n     *\n     * setup should only be called once.\n     *\n     * @param new_size the desired number of elements to store\n     * @returns the maximum number of elements storable\n     **/\n    uint32_t setup(uint32_t new_size)\n    {\n        // depth_limit must be at least one otherwise errors can occur.\n        depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(std::max((uint32_t)2, new_size))));\n        size = std::max<uint32_t>(2, new_size);\n        table.resize(size);\n        collection_flags.setup(size);\n        epoch_flags.resize(size);\n        // Set to 45% as described above\n        epoch_size = std::max((uint32_t)1, (45 * size) / 100);\n        // Initially set to wait for a whole epoch\n        epoch_heuristic_counter = epoch_size;\n        return size;\n    }\n\n    /** setup_bytes is a convenience function which accounts for internal memory\n     * usage when deciding how many elements to store. It isn't perfect because\n     * it doesn't account for any overhead (struct size, MallocUsage, collection\n     * and epoch flags). This was done to simplify selecting a power of two\n     * size. In the expected use case, an extra two bits per entry should be\n     * negligible compared to the size of the elements.\n     *\n     * @param bytes the approximate number of bytes to use for this data\n     * structure.\n     * @returns the maximum number of elements storable (see setup()\n     * documentation for more detail)\n     */\n    uint32_t setup_bytes(size_t bytes)\n    {\n        return setup(bytes/sizeof(Element));\n    }\n\n    /** insert loops at most depth_limit times trying to insert a hash\n     * at various locations in the table via a variant of the Cuckoo Algorithm\n     * with eight hash locations.\n     *\n     * It drops the last tried element if it runs out of depth before\n     * encountering an open slot.\n     *\n     * Thus\n     *\n     * insert(x);\n     * return contains(x, false);\n     *\n     * is not guaranteed to return true.\n     *\n     * @param e the element to insert\n     * @post one of the following: All previously inserted elements and e are\n     * now in the table, one previously inserted element is evicted from the\n     * table, the entry attempted to be inserted is evicted.\n     *\n     */\n    inline void insert(Element e)\n    {\n        epoch_check();\n        uint32_t last_loc = invalid();\n        bool last_epoch = true;\n        std::array<uint32_t, 8> locs = compute_hashes(e);\n        // Make sure we have not already inserted this element\n        // If we have, make sure that it does not get deleted\n        for (uint32_t loc : locs)\n            if (table[loc] == e) {\n                please_keep(loc);\n                epoch_flags[loc] = last_epoch;\n                return;\n            }\n        for (uint8_t depth = 0; depth < depth_limit; ++depth) {\n            // First try to insert to an empty slot, if one exists\n            for (uint32_t loc : locs) {\n                if (!collection_flags.bit_is_set(loc))\n                    continue;\n                table[loc] = std::move(e);\n                please_keep(loc);\n                epoch_flags[loc] = last_epoch;\n                return;\n            }\n            /** Swap with the element at the location that was\n            * not the last one looked at. Example:\n            *\n            * 1) On first iteration, last_loc == invalid(), find returns last, so\n            *    last_loc defaults to locs[0].\n            * 2) On further iterations, where last_loc == locs[k], last_loc will\n            *    go to locs[k+1 % 8], i.e., next of the 8 indices wrapping around\n            *    to 0 if needed.\n            *\n            * This prevents moving the element we just put in.\n            *\n            * The swap is not a move -- we must switch onto the evicted element\n            * for the next iteration.\n            */\n            last_loc = locs[(1 + (std::find(locs.begin(), locs.end(), last_loc) - locs.begin())) & 7];\n            std::swap(table[last_loc], e);\n            // Can't std::swap a std::vector<bool>::reference and a bool&.\n            bool epoch = last_epoch;\n            last_epoch = epoch_flags[last_loc];\n            epoch_flags[last_loc] = epoch;\n\n            // Recompute the locs -- unfortunately happens one too many times!\n            locs = compute_hashes(e);\n        }\n    }\n\n    /* contains iterates through the hash locations for a given element\n     * and checks to see if it is present.\n     *\n     * contains does not check garbage collected state (in other words,\n     * garbage is only collected when the space is needed), so:\n     *\n     * insert(x);\n     * if (contains(x, true))\n     *     return contains(x, false);\n     * else\n     *     return true;\n     *\n     * executed on a single thread will always return true!\n     *\n     * This is a great property for re-org performance for example.\n     *\n     * contains returns a bool set true if the element was found.\n     *\n     * @param e the element to check\n     * @param erase\n     *\n     * @post if erase is true and the element is found, then the garbage collect\n     * flag is set\n     * @returns true if the element is found, false otherwise\n     */\n    inline bool contains(const Element& e, const bool erase) const\n    {\n        std::array<uint32_t, 8> locs = compute_hashes(e);\n        for (uint32_t loc : locs)\n            if (table[loc] == e) {\n                if (erase)\n                    allow_erase(loc);\n                return true;\n            }\n        return false;\n    }\n};\n} // namespace CuckooCache\n\n#endif\n"
  },
  {
    "path": "src/daemon-main.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"compat.h\"\n#include \"fs.h\"\n#include \"rpc/server.h\"\n#include \"init.h\"\n#include \"noui.h\"\n#include \"scheduler.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"httpserver.h\"\n#include \"httprpc.h\"\n#include \"util/strencodings.h\"\n#include \"net.h\"\n#include <unity/appmanager.h>\n\n#include <boost/bind/bind.hpp>\nusing namespace boost::placeholders;\n#include <boost/thread.hpp>\n#include <boost/interprocess/sync/file_lock.hpp>\n\n\n#include <stdio.h>\n\n#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */\n\n\n/* Introduction text for doxygen: */\n\n/*! \\mainpage Developer documentation\n *\n * \\section intro_sec Introduction\n *\n * This is the developer documentation of the reference client for an experimental new digital currency called Munt (https://www.munt.org),\n * which enables instant payments to anyone, anywhere in the world. Munt uses peer-to-peer technology to operate\n * with no central authority: managing transactions and issuing money are carried out collectively by the network.\n *\n * The software is a community-driven open source project, released under the GNU Lesser General Public License v3.\n *\n * \\section Navigation\n * Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.\n */\n\nint exitStatus = EXIT_SUCCESS;\nbool shutDownFinalised = false;\n\nstatic void handleFinalShutdown()\n{\n    shutDownFinalised = true;\n}\n\nstatic void WaitForShutdown()\n{\n    while (!shutDownFinalised)\n    {\n        MilliSleep(200);\n    }\n}\n\nvoid handlePostInitMain()\n{\n}\n\nstatic void handleAppInitResult(bool bResult)\n{\n    if (!bResult)\n    {\n        // InitError will have been called with detailed error, which ends up on console\n        exitStatus = EXIT_FAILURE;\n        AppLifecycleManager::gApp->shutdown();\n        return;\n    }\n    handlePostInitMain();\n}\n\nstatic bool handlePreInitMain()\n{\n    return true;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Start\n//\nstatic void AppInit(int argc, char* argv[])\n{\n    AppLifecycleManager appManager; \n    appManager.signalAppInitializeResult.connect(boost::bind(handleAppInitResult, _1));\n    appManager.signalAboutToInitMain.connect(&handlePreInitMain);\n    appManager.signalAppShutdownFinished.connect(&handleFinalShutdown);\n\n    //fixme: (UNITY) - refactor this some more so that init is taken care of inside the app manager (like with qt app)\n\n    //\n    // Parameters\n    //\n    // If Qt is used, parameters/.conf are parsed in the qt clients main() implementation\n    ParseParameters(argc, argv);\n\n    // Process help and version before taking care about datadir\n    if (IsArgSet(\"-?\") || IsArgSet(\"-h\") ||  IsArgSet(\"-help\") || IsArgSet(\"-version\"))\n    {\n        std::string strUsage = strprintf(_(\"%s Daemon\"), _(PACKAGE_NAME)) + \" \" + _(\"version\") + \" \" + FormatFullVersion() + \"\\n\";\n\n        if (IsArgSet(\"-version\"))\n        {\n            strUsage += FormatParagraph(LicenseInfo());\n        }\n        else\n        {\n            strUsage += \"\\n\" + _(\"Usage:\") + \"\\n\" + \"  \" + DAEMON_NAME + \" [options]                     \" + strprintf(_(\"Start %s Daemon\"), _(PACKAGE_NAME)) + \"\\n\";\n            strUsage += \"\\n\" + HelpMessage(HMM_DAEMON);\n        }\n        fprintf(stdout, \"%s\", strUsage.c_str());\n        return;\n    }\n\n    //NB! Must be set before AppInitMain.\n    fNoUI = true;\n\n    try\n    {\n        if (!fs::is_directory(GetDataDir(false)))\n        {\n            fprintf(stderr, \"Error: Specified data directory \\\"%s\\\" does not exist.\\n\", GetArg(\"-datadir\", \"\").c_str());\n            exitStatus = EXIT_FAILURE;\n            return;\n        }\n        try\n        {\n            ReadConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME));\n        }\n        catch (const std::exception& e)\n        {\n            fprintf(stderr,\"Error reading configuration file: %s\\n\", e.what());\n            exitStatus = EXIT_FAILURE;\n            return;\n        }\n        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)\n        try\n        {\n            SelectParams(ChainNameFromCommandLine());\n        }\n        catch (const std::exception& e)\n        {\n            fprintf(stderr, \"Error: %s\\n\", e.what());\n            exitStatus = EXIT_FAILURE;\n            return;\n        }\n\n        // Error out when loose non-argument tokens are encountered on command line\n        for (int i = 1; i < argc; i++)\n        {\n            if (!IsSwitchChar(argv[i][0]))\n            {\n                fprintf(stderr, \"Error: Command line contains unexpected token '%s', see \" DAEMON_NAME \" -h for a list of options.\\n\", argv[i]);\n                exitStatus = EXIT_FAILURE;\n                return;\n            }\n        }\n\n        // -server defaults to true for daemon but not for the GUI so do this here\n        SoftSetBoolArg(\"-server\", true);\n        // Set this early so that parameter interactions go to console\n        InitLogging();\n        InitParameterInteraction();\n\n        //fixme: (UNITY) - This is now duplicated, factor this out into a common helper.\n        // NB! This has to happen before we deamonise\n        // Make sure only a single process is using the data directory.\n        {\n            fs::path pathLockFile = GetDataDir() / \".lock\";\n            FILE* file = fopen(pathLockFile.string().c_str(), \"a\"); // empty lock file; created if it doesn't exist.\n            if (file)\n                fclose(file);\n\n            try\n            {\n                static boost::interprocess::file_lock lock(pathLockFile.string().c_str());\n                if (!lock.try_lock())\n                {\n                    fprintf(stderr, \"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());\n                    exitStatus = EXIT_FAILURE;\n                    AppLifecycleManager::gApp->shutdown();\n                    return;\n                }\n            }\n            catch(const boost::interprocess::interprocess_exception& e)\n            {\n                fprintf(stderr, \"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());\n                exitStatus = EXIT_FAILURE;\n                AppLifecycleManager::gApp->shutdown();\n                return;\n            }\n        }\n\n        if (GetBoolArg(\"-daemon\", false))\n        {\n            fprintf(stdout, \"%s server starting\\n\", _(PACKAGE_NAME).c_str());\n            if (!AppLifecycleManager::gApp->daemonise())\n            {\n                LogPrintf(\"Failed to daemonise\\n\");\n                exitStatus = EXIT_FAILURE;\n                return;\n            }\n        }\n\n        appManager.initialize();\n    }\n    catch (const std::exception& e)\n    {\n        PrintExceptionContinue(&e, \"AppInit()\");\n    }\n    catch (...)\n    {\n        PrintExceptionContinue(NULL, \"AppInit()\");\n    }\n\n    //fixme: (UNITY) - It would be much better to wait on a condition variable here.\n    // Busy poll for shutdown and allow app to exit when we reach there.\n    WaitForShutdown();\n}\n\nint main(int argc, char* argv[])\n{\n    SetupEnvironment();\n\n    // Connect daemon signal handlers\n    noui_connect();\n\n    AppInit(argc, argv);\n\n    return exitStatus;\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/daemon-res.rc",
    "content": "#include <windows.h>             // needed for VERSIONINFO\n#include \"clientversion.h\"       // holds the needed client version information\n#include \"appname.h\"\n\n#define VER_PRODUCTVERSION     CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD\n#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) \".\" STRINGIZE(CLIENT_VERSION_MINOR) \".\" STRINGIZE(CLIENT_VERSION_REVISION) \".\" STRINGIZE(CLIENT_VERSION_BUILD)\n#define VER_FILEVERSION        VER_PRODUCTVERSION\n#define VER_FILEVERSION_STR    VER_PRODUCTVERSION_STR\n\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION     VER_FILEVERSION\nPRODUCTVERSION  VER_PRODUCTVERSION\nFILEOS          VOS_NT_WINDOWS32\nFILETYPE        VFT_APP\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\" // U.S. English - multilingual (hex)\n        BEGIN\n            VALUE \"CompanyName\",        GLOBAL_APPNAME\"\"\n            VALUE \"FileDescription\",    GLOBAL_APPNAME\"-daemon (\"GLOBAL_APPNAME\" node with a JSON-RPC server)\"\n            VALUE \"FileVersion\",        VER_FILEVERSION_STR\n            VALUE \"InternalName\",       GLOBAL_APPNAME\"-daemon\"\n            VALUE \"LegalCopyright\",     COPYRIGHT_STR\n            VALUE \"LegalTrademarks1\",   \"Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING or github.com/muntorg/munt-official/COPYING\"\n            VALUE \"OriginalFilename\",   GLOBAL_APPNAME\"-daemon.exe\"\n            VALUE \"ProductName\",        GLOBAL_APPNAME\"-daemon\"\n            VALUE \"ProductVersion\",     VER_PRODUCTVERSION_STR\n        END\n    END\n\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0, 1252 // language neutral - multilingual (decimal)\n    END\nEND\n"
  },
  {
    "path": "src/data/chainparams_mainnet_static_checkpoint_data.cpp",
    "content": "    {      0, { uint256S(\"0x6c5d71a461b5bff6742bb62e5be53978b8dec5103ce52d1aaab8c6a251582f92\"), 1009843200 } },\n    {   5000, { uint256S(\"0x07ba1142fe1c0f4514b8ef029a687e45d08f4f930e14c753b8b8131df6d33a5b\"), 1396776675 } },\n    {  10000, { uint256S(\"0x25a619632ea07771156d61791245e7b3497ae987ef6be5348c41380291848974\"), 1396928263 } },\n    {  15000, { uint256S(\"0x944e0468c38392c5f32818f8f50c10aa6deb5986d85a72e9aaddfe94acc74a5c\"), 1397078470 } },\n    {  20000, { uint256S(\"0xbaf0214a1e00f2c265ac64a25c309dea2fa0fc2c56f1f40501981e1936405a38\"), 1397230260 } },\n    {  25000, { uint256S(\"0xe83e474bcad07e9b09caa5932d35c39812a485dadad3dba97ff1c2f842ab1cbf\"), 1397382466 } },\n    {  30000, { uint256S(\"0xb388498efce825de5df82c458513b11a657b3499b62be70aac36720ba661a792\"), 1397535343 } },\n    {  35000, { uint256S(\"0xe14bac6cfea31014bb057500160fb5a962e492ce16652b14fa07314fd9e523ff\"), 1398287041 } },\n    {  40000, { uint256S(\"0x7e460787e1820d608fac250d7b53404b131804eec4800e9efc80a5eca7b30349\"), 1399043662 } },\n    {  45000, { uint256S(\"0x97b4cff99eda714dbff09881e339d1159e5558486e31198affd712ca806f0b1d\"), 1399803213 } },\n    {  50000, { uint256S(\"0x5baeb5a5c3d5fefbb094623e85e3e16a1ea47875b5ffd1ff5a200e639908a059\"), 1400560264 } },\n    {  55000, { uint256S(\"0x48bcc20fe91362c87727f710aa99523cc24fd95e2d2badd7fddfe220b4824747\"), 1401308606 } },\n    {  60000, { uint256S(\"0x289c63315033285a31661ce4f26b49cdb5f25f78edb87a7ab89c2718240eaab4\"), 1402055764 } },\n    {  65000, { uint256S(\"0xea528b9c5da15983e0c070da93a8c352c3227c9c1f4e55f4c6c737a9e5a9bcad\"), 1402815392 } },\n    {  70000, { uint256S(\"0xce9267eeaca828d4152315e714b4089ada5ce91f5d31aff8b6394b3680d39d99\"), 1403573297 } },\n    {  75000, { uint256S(\"0xc6ccc28c6dbe5760ce5154f7e9cea405f6521d6b4f9ec21c988f5f7e626b451f\"), 1404317484 } },\n    {  80000, { uint256S(\"0xba0038c46553013f8ac4a6440363e0b65a2a56be4e2c1ad92af694330dd2dc44\"), 1405072543 } },\n    {  85000, { uint256S(\"0x25a78f44abf0c5ec967a77f458ad6d2ad8f9647d409206bb857e2b4bf6ac13ac\"), 1405826320 } },\n    {  90000, { uint256S(\"0x46b0f4d321a56aa18f96eff03728de63069fdf5e6309b00feee87f10f25f5003\"), 1406575129 } },\n    {  95000, { uint256S(\"0xaf68270d7fd7a60e94131c963f00632169434d6a7d1aed41143739b32e466b18\"), 1407328518 } },\n    { 100000, { uint256S(\"0x5e831ed155d05f6ac7f17635022dbc348bf73942309ac403c6f8c2990e2e0af1\"), 1408078859 } },\n    { 105000, { uint256S(\"0xea94d0eb8f10c9957b34e6edb7be406258270564f585114e70e478b7470f5685\"), 1408820382 } },\n    { 110000, { uint256S(\"0x3f87ae7d4f4c6ec94b17e82f0e0998a3a85c98a3131952b5e258da69ab9d2aeb\"), 1409573417 } },\n    { 115000, { uint256S(\"0xc6e30bd59160fbcd460f1144be7b40bc078b37347149beeb09ebd3442aa85934\"), 1410324413 } },\n    { 120000, { uint256S(\"0x38004f47dbff789f7ca48e366f89b3ff4e0f6334d6742e234f8dd166a063347b\"), 1411089720 } },\n    { 125000, { uint256S(\"0xee27d0f4b6596f302eb591072136ae196bb318d776c16625b23cc7383052b564\"), 1411871556 } },\n    { 130000, { uint256S(\"0x9fd52400fb1a461311eaa2aafc32467808189f8fa2d81d2a8cbc1dd8539446fd\"), 1412655875 } },\n    { 135000, { uint256S(\"0x573e70d731f245fd4f4e79a6d28f5dfbfe45255da70685e303625a5a82d9954d\"), 1413447624 } },\n    { 140000, { uint256S(\"0x010019afea8185a2692981fb040fd1eb8ab05479d65137849a0cf66d39bfddbb\"), 1414276483 } },\n    { 145000, { uint256S(\"0x4b6b2182ce2445e76c00e3487fbe83ee436935911599b058818d08aebea0be8c\"), 1415061802 } },\n    { 150000, { uint256S(\"0x97fdb21189d5a958d42fcb58f8d300e737a20fad91878dabdd925d11fc614013\"), 1415846757 } },\n    { 155000, { uint256S(\"0x61ca04d27282ab659c087bf8877f461e0d978f2933bd32a660c5096deb72fe4d\"), 1416631222 } },\n    { 160000, { uint256S(\"0x87e7dbf8f3cdc490fdb05c4c1ebf691bc68e566095d51713132e53584961d5c2\"), 1417416595 } },\n    { 165000, { uint256S(\"0x4b9efbb5350a2a3052b516ca9a1fa526b0efa68deec20767ba5c1c99dcac798f\"), 1418202928 } },\n    { 170000, { uint256S(\"0x91ad5405df477c70a01e9cb4ff10cc4f1d80487aa4d9e86a4867b8084a7c216f\"), 1418987643 } },\n    { 175000, { uint256S(\"0xda6aa09113ddd62d871e9aacad6131831d5841a26968f1665a9b829fd30a29e3\"), 1419771515 } },\n    { 180000, { uint256S(\"0x4bde66d4babf6e480587582ab62f09bfa11450a66f753e4ed40d7540f917476e\"), 1420557596 } },\n    { 185000, { uint256S(\"0x4d0413eaf446bf4b071f401b3b3410c1ff3653be2a2d24c9047cadb29d01e8ff\"), 1421342229 } },\n    { 190000, { uint256S(\"0x2e1e89c211c3431a0c3d2b2901f22295975d1e7f7fc1013d9732f10d93708a9a\"), 1422128561 } },\n    { 195000, { uint256S(\"0xc18c38f7fa1bdf626861c38e0b4e3b785e926ab3465e651a7b854a800cd9af56\"), 1422958219 } },\n    { 200000, { uint256S(\"0x4e80313f4eb23093a63218f3736379084d1eeae46c4343668f3cdc9c0c5ca260\"), 1424526562 } },\n    { 205000, { uint256S(\"0xd2b896c1dd16dde4d70dac46cd2157fc6ab6b7875e5932b211362758803be366\"), 1426695052 } },\n    { 210000, { uint256S(\"0x1f1b4e0ac592bcf62ae9a26c6d6e76c96f72d6f2aeb352d0d6237f32ebc66f8b\"), 1429105034 } },\n    { 215000, { uint256S(\"0xc858f6f5f922307867a640c7b1ae7f496653a9811c0cff807a81b0fbe4b18151\"), 1432175570 } },\n    { 220000, { uint256S(\"0x6b7b5585d8a1d84ac1c7312930389da5ada65fd5b25e40e74e157d909a8a0521\"), 1433232658 } },\n    { 225000, { uint256S(\"0xc9a5c5226d8f103972ffee38c31c3508189b694e0d4f93a394ccea2cac82ce49\"), 1434583308 } },\n    { 230000, { uint256S(\"0x2a1588f8f138a189d1890be022f607e9b3a00b68c2062fcc1efd3a68b4c0946e\"), 1435964425 } },\n    { 235000, { uint256S(\"0x35c62070ec88311335f347839e07aaf00205c3cc8fb5017b95aa41f1264a8694\"), 1437298404 } },\n    { 240000, { uint256S(\"0x72783fe0d761d29561f05ee43c77fdc3f59a9540b7ac1b5849f346e9474cf6ca\"), 1438670438 } },\n    { 245000, { uint256S(\"0xbcace89a7a4d69e4a8e4efb4e41bcd921a2a2892035df04e86ac63bf6b7394f5\"), 1439984025 } },\n    { 250000, { uint256S(\"0xa6635e1dbce15cfb4be7f3f464f612205dd13ba96828535000b99ce04648500d\"), 1441212522 } },\n    { 255000, { uint256S(\"0xcecee67fb8baf21d4995015f26f3933b841c7f69c8645c500783d33108c6676b\"), 1442094027 } },\n    { 260000, { uint256S(\"0x42c2254ffd8be411386b9089fec985fe3a06d5fc386ff0bd494b5a3aa292f107\"), 1443116050 } },\n    { 265000, { uint256S(\"0x9fee70b9671b30396c80559500e146924cafafc16f673772b9bbb38d364c08aa\"), 1444174457 } },\n    { 270000, { uint256S(\"0xfa3c642f0c44da06892edaace1e2da0e66f62574401e1a8b7482264a1bbc59ba\"), 1445327681 } },\n    { 275000, { uint256S(\"0x3f602d877314f330da40bfda7cc41198eec3f1ebd64ecb8defa30efe62fcb8d0\"), 1446402538 } },\n    { 280000, { uint256S(\"0x2f33b4d16cceef28540a62c7fe061b465cdea93dd1a32b787152fd11c719b4ed\"), 1447507603 } },\n    { 285000, { uint256S(\"0x58eb0593b7ba41d06f4edc58a4ef6b1029ff6962ea3ad87a286bbe72251a4120\"), 1448529827 } },\n    { 290000, { uint256S(\"0x57622177fa40aae7dfdd6636c0ccd436e0f95c09714126fcf809915ca40cb7e7\"), 1449675808 } },\n    { 295000, { uint256S(\"0xb2d3a1d1c622683524d15216e3ac137bf43587116d4494fe20c08d82c4211674\"), 1450705596 } },\n    { 300000, { uint256S(\"0xf0f99e78c90d20ac4e376ffd1a7e8a89cd1bd152ad1a40f7be31bbf8e0b492c5\"), 1451816529 } },\n    { 305000, { uint256S(\"0x01fb036d4a39e9476e63c6c681b29ae9fb96dccdc8e548957ab736b6a5847cb5\"), 1452856123 } },\n    { 310000, { uint256S(\"0x6a77548fcb36d46053e883eb9814cd70f165f2dbc0325aab2261410666361dd4\"), 1453885717 } },\n    { 315000, { uint256S(\"0x27ebdefc75e8ba0611b4397e8d58ef7356bfcf7169c4824930f181289f587cf5\"), 1455011314 } },\n    { 320000, { uint256S(\"0xffd2c9c93b15e32875664cb80ad974b8c7847e5c6eb5d970a9fad6df126c4366\"), 1456152463 } },\n    { 325000, { uint256S(\"0xa00bccd7a68495771f03856633786a16d3106b38adeafc4d610918b5b118ec9e\"), 1457341408 } },\n    { 330000, { uint256S(\"0x23f895ebde2aac83769aa475f063cc2b96bc6f4a8ffa9e7f473bf520707f8858\"), 1458367876 } },\n    { 335000, { uint256S(\"0xa5a2446a295cebb6eeec80e8d844b198308aad99d86c70208783575926ecddf2\"), 1459407891 } },\n    { 340000, { uint256S(\"0xe69c9f1a872760c26b222f9762ccfa8924a9aae419334b6aabccef7e5a77e07c\"), 1460363950 } },\n    { 345000, { uint256S(\"0x417b9800461461bc1346e1659726b424a5b81d273df3af4972d4487506a56412\"), 1461334497 } },\n    { 350000, { uint256S(\"0xa4c92744d47ada905f5cacc7ee91d86f0e646d52d5d8cafdab5d288490002196\"), 1462316267 } },\n    { 355000, { uint256S(\"0x0ecfa10c0e7b43669f72483285c0bbab1ff333af0574f7415c774e3334f6b9dc\"), 1463405995 } },\n    { 360000, { uint256S(\"0xdfc2eeae2ff681fdc1426a4b6da0c0a3d19d8409668515dae8834d98be93e6e7\"), 1464432780 } },\n    { 365000, { uint256S(\"0x736e3eec11888374e93ba5962d1203d3ead84b2e90152e97199f1e26d7fb76c3\"), 1465519318 } },\n    { 370000, { uint256S(\"0xfc8a004796035eedc19f43ad79ea153f2f10ceb3557d7349e90c95f1f2c55364\"), 1466632020 } },\n    { 375000, { uint256S(\"0xa1c3e45a3b4bbf823a35433f604d33c89749a3950a793becc90cddbecd03409c\"), 1467984054 } },\n    { 380000, { uint256S(\"0x67e151608de36d87336931ddb0ec381f24348663a68e7032f0c768fb1cf054e2\"), 1469127714 } },\n    { 385000, { uint256S(\"0x379d523bc9fd29b7cb260b5161dbde9cd07d1a57cf4600ee689e31d643e48004\"), 1470263618 } },\n    { 390000, { uint256S(\"0xf18a084d2d73fa07e2c0e2cdfe8c2ddff1b01c721aa2a4b63687f35b79ff2247\"), 1471554451 } },\n    { 395000, { uint256S(\"0xe3058781206326a193b851a80489b30fbf660c3cca62816a0f57f993cb1cd4c3\"), 1472708456 } },\n    { 400000, { uint256S(\"0xe4b072d2861b8041f42dcf2e8f5d1caaaff36bc952518e99f6d3fac89e1e1133\"), 1473722382 } },\n    { 405000, { uint256S(\"0x63666839cf8138a012b4bf6c29c54246c9ce32875a349cbd09847e37ac8602d1\"), 1474733451 } },\n    { 410000, { uint256S(\"0x6196ce0df794d8b0456ea7b1c2dad12ae312aa3ad5dbb6ec59028f4770e37e37\"), 1475808812 } },\n    { 415000, { uint256S(\"0x34d62d2bff54f6e86209d34162538e33cf74c9becbd4e682c568f945a2271bc3\"), 1476973453 } },\n    { 420000, { uint256S(\"0xe77dda63bd507c5925720695c480feee3ca85cb6fd62ccbafd319e7dd919a863\"), 1478078687 } },\n    { 425000, { uint256S(\"0x0dd5aa1302943e7b4fff1963ce1c32a1aa3db15d652515a3ca8bf4aad84952d7\"), 1479092395 } },\n    { 430000, { uint256S(\"0x4296798738369477be63e58ffcdf6eeb1dcf3c61f7e7af08f5712317c079ff7f\"), 1480146233 } },\n    { 435000, { uint256S(\"0x0d7bacd32a25637740bdad6b8d21d635414be1766527053fa2161c2cf3ac7fbc\"), 1481251184 } },\n    { 440000, { uint256S(\"0x2b06689877981bd04ecf34d281ab96af1d7decb1438e4df40a2236562ca5b09d\"), 1482179411 } },\n    { 445000, { uint256S(\"0x55669afdefdf89251fbac44bd1eb1788b14d8f2dd9aa5887486229180529c6b6\"), 1482927930 } },\n    { 450000, { uint256S(\"0xfa4f46c846b053104ce5956578d72f9a5fa87c4ae49a6450e5d66c4fd37d6d66\"), 1483665997 } },\n    { 455000, { uint256S(\"0x46bc63bc67a0baaf1fecc1cf2e435458587180212450af24a37df7b0b02002b2\"), 1484406588 } },\n    { 460000, { uint256S(\"0x7da617ca15be1f39dee7294d26a95f192fbb72e3cee8ca804e9d1d27f661fb83\"), 1485145394 } },\n    { 465000, { uint256S(\"0x3032195da4adb3209d55ba881831dec748695c4206cd18052fdcf046d142bb49\"), 1485889227 } },\n    { 470000, { uint256S(\"0x0656688a2c1db2cf5a3c8412ad05d2d1784e1ee630444f007c33f83765bad579\"), 1486626192 } },\n    { 475000, { uint256S(\"0xa730a89a11332ee0133c458c5feccbda857ace9572ab5a048701cccb0239cf4c\"), 1487361080 } },\n    { 480000, { uint256S(\"0x4616acf55fe787c99843ec3d32d881f0b70a9d03490b00a22e2eb03ef6e174fb\"), 1488099040 } },\n    { 485000, { uint256S(\"0xa6f242ae9811b724d7f446e9482991cde00da6c4c69db25b570ee19818eea4a3\"), 1488834434 } },\n    { 490000, { uint256S(\"0x9bea668c533839f89941ff66467a7f9690116d49121b69bebdcecbf7c137d94f\"), 1489569017 } },\n    { 495000, { uint256S(\"0xa6bd3510860377e0f998eae41b901b13f41686dd39bc3116d155819616d5b4bf\"), 1490302633 } },\n    { 500000, { uint256S(\"0xd30e19c8b8c567b23c09fc022b4f5ca8014a8cb3c1504782e9a68af349757afa\"), 1491057581 } },\n    { 505000, { uint256S(\"0x56bce924eb7613b6fd4ac859a06a13f7643817d6a593d19951ab293182a021cb\"), 1491810603 } },\n    { 510000, { uint256S(\"0x17b078729613bf93c40d605ec1f763e0ba9bd23eb0902c3e74afba8f291aa834\"), 1492558829 } },\n    { 515000, { uint256S(\"0xbc1264dd2417fede0c18d18f10cb2b96bea78eb5e38f3b90b0069cdcf0b44c84\"), 1493304469 } },\n    { 520000, { uint256S(\"0x5627419fa4a289e54c18b5b74c0692248b2b7e6c5612cf15717afbdee7a8c525\"), 1494051639 } },\n    { 525000, { uint256S(\"0x1d3f4de346830365474b24f7b9dd7b332215dbe0e9e175c70df040446e2c4185\"), 1494799318 } },\n    { 530000, { uint256S(\"0x1f283d04cde433cd21fc37bce84e24ab5bd91a162c9cbd65917ab61b64faa4c8\"), 1495545207 } },\n    { 535000, { uint256S(\"0x53ee7fa548f92b54ff29f8015d647f4c2525f91f2eb624f12ffec932bc0af294\"), 1496295697 } },\n    { 540000, { uint256S(\"0x62e5636387aaa74f6c48ba812710481620efdc35e9fd5eb1bdc895e64d110a3c\"), 1497037983 } },\n    { 545000, { uint256S(\"0xecd86540dd3faebbf860f35a9fa92e1145c3470e998dcad3716fff241d0e25fb\"), 1497785963 } },\n    { 550000, { uint256S(\"0x3d7fc31f64905e2e6559298b826b914a3716ae160caea485ae46230890a4144d\"), 1498527420 } },\n    { 555000, { uint256S(\"0x8d17e332f8a2121434fb6f7c650c6cae7f575b2e4f8be6566d8d08ba09bb152c\"), 1499259716 } },\n    { 560000, { uint256S(\"0xbd60ce2fee93534e73d4b339c986e0c251a07902caad18de54049daf282d6560\"), 1499991286 } },\n    { 565000, { uint256S(\"0x617df1fa71f67eeb4ab9cf36e99c24602716f21a717e404838a8f01690fb4994\"), 1500728771 } },\n    { 570000, { uint256S(\"0xc2a212411ae8d01c113161ee4e261890186dc98aaf0e1fbc202d5af7cf85ff1d\"), 1501459330 } },\n    { 575000, { uint256S(\"0x728d0d7edd0c1fcc0fa0f80bfbf8c06e2afb9a8ba0358fa434d3114a982003e6\"), 1502185812 } },\n    { 580000, { uint256S(\"0xa92b260332276147a552e2350a95a04fe7fca1164eb066e7f02dca3ae7a68b3e\"), 1502918516 } },\n    { 585000, { uint256S(\"0x1fa14d4a816fb35386873f49ff822d1cf225989ed45332ce31d21575638e8c7c\"), 1503650754 } },\n    { 590000, { uint256S(\"0x9b5e5464538123fd0542735875bc4502246a58aff68e0fd9c3ab0d2f2977faea\"), 1504390043 } },\n    { 595000, { uint256S(\"0xf80a3148c3f333ae17d6e7e84229cde85b63f2bd93d73aa3fa84bb17ffe1f38a\"), 1505128175 } },\n    { 600000, { uint256S(\"0xd6f49c4bf3b3a0e82392809b8925c485a518acdeacf8bdd9a9326e4c68456d6b\"), 1505870868 } },\n    { 605000, { uint256S(\"0x44562c273753696c5d0bdf2995445ee25a514d36f61644aa65ddc48c739979cf\"), 1506603940 } },\n    { 610000, { uint256S(\"0xbbafa1669017ee72cbb24092d16cf42fa667ad3dd178d60391ecba22ef3e51fa\"), 1507344623 } },\n    { 615000, { uint256S(\"0xccda751664a400dc813bd4ad91671a2c7b82f75326eb336060675f66315ff57b\"), 1508088529 } },\n    { 620000, { uint256S(\"0x288777a4c134b9582fa81f4bb342fcadd2c58bd2cba9c7c61fb66fabc38b7b66\"), 1508829713 } },\n    { 625000, { uint256S(\"0x0d067e2b98621356f67c0d969c8dbccd62a6bea757a006a6640e42becfe54740\"), 1509573613 } },\n    { 630000, { uint256S(\"0xa6ba7f5eb8aae5d636f7057ef101452015be4831f08dfdbf9e4870b2794a97f6\"), 1510318993 } },\n    { 635000, { uint256S(\"0x880773d0d7085341798b7b7411506eef6e397808ad3265ea090850db7f2636c6\"), 1511062514 } },\n    { 640000, { uint256S(\"0xeba2fff77eee4bfbd49f8bce8d3ac125f8894d817be8a10524d1f592ff0c171d\"), 1511809837 } },\n    { 645000, { uint256S(\"0x760ee56cbc369f217832d72ac6b618646113a6d5aaddb86a15fef7aaa2b143f8\"), 1512550170 } },\n    { 650000, { uint256S(\"0x0fcd45353b44036efdabed53931b6a49db8f44fa91ede6be64189bccc5f2af53\"), 1513296093 } },\n    { 655000, { uint256S(\"0x4ed2f0a00af3fe478395c78fa56e14599c8e83b336d023412e8121716f4c77e3\"), 1514033954 } },\n    { 660000, { uint256S(\"0x8fd5e894f1a3b1662fd68ccbe8df3f6cf7bf9daf7d01b2bc0b58d98be05bb2f7\"), 1514768121 } },\n    { 665000, { uint256S(\"0x83a68b3a7ff7c9418fecf987e4f641ac1e941128df3e38f094056bfa555b514e\"), 1515497950 } },\n    { 670000, { uint256S(\"0x9de98c27385e461e105dc7821ad2b8d534b20400faf3c13367c96ca5bf2ae3b7\"), 1516229841 } },\n    { 675000, { uint256S(\"0xed520161b5954c1a800497fe334e320bc481f2b103f78e8319a0db6cbbd2dcb1\"), 1516960413 } },\n    { 680000, { uint256S(\"0xa7efadd6fd29ea5d74a36dad4ada8be0be7562ffb3a023629ca70fd3d3a9d852\"), 1517694897 } },\n    { 685000, { uint256S(\"0xeb30f10408b7b0e9732f0e93f3609e890f19cf598e6d79ca58fa0a5927e0a8ae\"), 1518425478 } },\n    { 690000, { uint256S(\"0x632da89ac12d274dfabb7912fa3ad5a95a4664213d5ee96532195a44999b4944\"), 1519157224 } },\n    { 695000, { uint256S(\"0x0172de09b4224dbb4235be95bfda6ad8bf9e6546da06cdebc1ab287255fbbfab\"), 1519887659 } },\n    { 700000, { uint256S(\"0x7cdbb7bef28741aa682570703ca03cd77a6524011aed588fd0aabe5f0038f124\"), 1520617979 } },\n    { 705000, { uint256S(\"0x071156c7d447e7a5940d2b2bf75935a542b953c6f075264563b0723e70ecfbcf\"), 1521353177 } },\n    { 710000, { uint256S(\"0x9d21c021202747451b5caf77477bee39b0f7307b058e7551ef55c7955e68de9b\"), 1522089013 } },\n    { 715000, { uint256S(\"0x185c3c38a6a33b4c6803d58d67f8435cec67a2d4bcb61ffa34acc390503cb04a\"), 1522822445 } },\n    { 720000, { uint256S(\"0xcefa30dadbae53f7e1e3400489ad2b55c9490a6ce91a9d74e5702c09f37986de\"), 1523551635 } },\n    { 725000, { uint256S(\"0xef7425f36695916b23a14e9a23572fda9ca5ceb39d7029274889b1700cd65436\"), 1524283360 } },\n    { 730000, { uint256S(\"0x25e40efb33eb713784c86fee4013c52efafed7a0ad5aa0b4a4266e73cd619289\"), 1525012542 } },\n    { 735000, { uint256S(\"0x17d9585d6c2d4312a1ce583611d7193759a8ec29301c18b090693fa5f80bcbd9\"), 1525741792 } },\n    { 740000, { uint256S(\"0xba1d907e5b328323778e88a76730ee3ae38fecc432bb288c0eadec26fa4f6544\"), 1526472312 } },\n    { 745000, { uint256S(\"0xcd2111fa34197e4d8eeaa5ab014bde09e2f823bfaac2ff823367f04710a2d1c3\"), 1527202765 } },\n    { 750000, { uint256S(\"0x22330a217c970fce0ac14f954793f0116df6931b1fd9f2c9e469884a71ef4d96\"), 1527932637 } },\n    { 755000, { uint256S(\"0xa678f0896638028ecadd4d17fa139c834a4a158a73a0e8d9377e38a8f2d2ae96\"), 1528666208 } },\n    { 760000, { uint256S(\"0x6c311893597eb070949de2929b655c364cff0fe5486aaa5e6de4ae6db41e36f2\"), 1529400789 } },\n    { 765000, { uint256S(\"0x6bad0bc8dea23fea8a6cf7755436dc6ff765a5bdfa01a10bfffd0a21e24868e5\"), 1530130251 } },\n    { 770000, { uint256S(\"0xe55b1550d0f06f5ba51cb101b23fa181d646f3bfbcd512ba3466ebff29393194\"), 1530859532 } },\n    { 775000, { uint256S(\"0xab6660b98b64cb58f0c7595dd46a749ebe76fdfe20996c84defca6573df2c2b1\"), 1531598367 } },\n    { 780000, { uint256S(\"0xddca858d7e0bf263ac4a2641831b2e8578b1ef8418a0621f9f6263666737539b\"), 1532400008 } },\n    { 785000, { uint256S(\"0x318762ff8a035075584065c1101dae5c7cac5b5d3c26a666027c9a5e6f3aee49\"), 1533172593 } },\n    { 790000, { uint256S(\"0xd148b595af81bcfb5611b93aa75814cb5558e8774bbe1adc068ea7696bbbdbaf\"), 1533924977 } },\n    { 795000, { uint256S(\"0xc12484777b90ba6274f3f618e7ad24b002aa09d89f5ed50154db1097d6b5e6e7\"), 1534668951 } },\n    { 800000, { uint256S(\"0x6e5d2d9c616921061743fa3206bf26f20dea7fda1abec6309f453e4b9bdf84ac\"), 1535429535 } },\n    { 805000, { uint256S(\"0x02bdbc0a65044ca98855bfe2bc91690029537f265fa52bae9d0da9936c4934e8\"), 1536190924 } },\n    { 810000, { uint256S(\"0xdf61ac9e368f000411e0a5a05617c27f5b51c989d096919c4fe1dc27d2e6ef28\"), 1536954107 } },\n    { 815000, { uint256S(\"0xd40c7c94d9247688cff0d68261ae1589745eacfdcc65bde576d14e8f0eb8970c\"), 1537712836 } },\n    { 820000, { uint256S(\"0xe70b21679f7c1a33e34a60abc90f7fa11290ad34f261f2976d6096b3613df3ae\"), 1538471583 } },\n    { 825000, { uint256S(\"0xe60fa4bcc9594d03ca687101cab8a7bd2ee52c14104d04d5194fc85c69f17064\"), 1539232375 } },\n    { 830000, { uint256S(\"0x6b19deb12fd14da4f62233027410d447925f169fd5a76c932ced28f022edaa74\"), 1539986915 } },\n    { 835000, { uint256S(\"0x382fe6505b3dbde4604d67930b1a4f0b2b77452bd776046e30da6a31138227fa\"), 1540750990 } },\n    { 840000, { uint256S(\"0xca680727ba57555a1d80add71a81d63f57592612237f370b4adc96d906b508c3\"), 1541516632 } },\n    { 845000, { uint256S(\"0xc20ec608f7de7a3c44fcc4df3c96a3afb27e176673f80881da96f9d0a407bb35\"), 1542276904 } },\n    { 850000, { uint256S(\"0x9d2ecf60d1e0cca1510eb211ed3fd2e049a467ccfdf13d10b02c90ea8e92e6b9\"), 1543034510 } },\n    { 855000, { uint256S(\"0xdcfdea952f6fb298692dfc32135ade0084707c0491673075a630a78a40f8eb55\"), 1543797247 } },\n    { 860000, { uint256S(\"0xbe7ba1721a7b5975f7ca41fb0a439ee2c8be287852d81583f58acf7476338511\"), 1544567932 } },\n    { 865000, { uint256S(\"0xf99f37ca66473eb3449e058cd4f922aca0ef402ce43b305af56ef6f8f81afeb7\"), 1545338530 } },\n    { 870000, { uint256S(\"0x0b20b92f4a99e8daf371ebd8842e87e19bd027e630232d804a9265bc74fa3154\"), 1546115851 } },\n    { 875000, { uint256S(\"0x6f20cd84b85f38d9885c7abfd27ab64e848e1c9d59d20087928d73be8d332856\"), 1546883119 } },\n    { 880000, { uint256S(\"0xe0afba09a075054eb901cc4fbacda150625ecad21e4c43c5b3ce59f8c5195160\"), 1547662599 } },\n    { 885000, { uint256S(\"0xa3ff2a300d41777d8c5a1f5220a185fded836dc221d0a0d625c0628eb19c15a2\"), 1548441034 } },\n    { 890000, { uint256S(\"0x0a53aa18822f68dfc2fc5a7f5999e5b31320a6ea1a9955287faf358f7dc69546\"), 1549219818 } },\n    { 895000, { uint256S(\"0x6a448ebc37915c1847d99c043a5948091d761221da9dea068d377d4dbd85a61d\"), 1550006783 } },\n    { 900000, { uint256S(\"0x7fc71149acd4dd79f27e7f73b33170d1eb35b132fdec54d84551a1b677b41f50\"), 1550803236 } },\n    { 905000, { uint256S(\"0xeaa2d4441498ab892dc8a2e112bbe8261c4555bc665b23545365b2ba71605a4c\"), 1551600103 } },\n    { 910000, { uint256S(\"0xb19ca1b1ea65fec4bb5eac8e548e29327281973a2ae0e4a4d307500a88bc7ee1\"), 1552394784 } },\n    { 915000, { uint256S(\"0x7e552505c649392fd80b63a6ecbb3c76add9edbcb8adeff019a38e59ed8a96bb\"), 1553182683 } },\n    { 920000, { uint256S(\"0x4399d4087d11da194b8385c07dd48cc1246a0ae0be66d9708d8f6f1b4a5b1a4a\"), 1553976785 } },\n    { 925000, { uint256S(\"0xc4ffcc0bff959d3bdcc4031672dc3d46d1c4964e51164387ad3d72ac67ea06b8\"), 1554773170 } },\n    { 930000, { uint256S(\"0xa0108826cc23b4717b3d3af82c9aa81c94b5382c9871bfdb2ce8ad0182d4878f\"), 1555573024 } },\n    { 935000, { uint256S(\"0x751db5ba72ab5c1f16e9f022716849dc0b87b8b132bcf4bb0363283869faf26e\"), 1556361428 } },\n    { 940000, { uint256S(\"0x03c175f4910b7779c2c6904f6aab59d4aeaff888b772830dc41973db47ea1242\"), 1557134813 } },\n    { 945000, { uint256S(\"0x7aa4c67348fbbd6435188b95fd7208269e8a803bc8d9df2bda36c6d317419675\"), 1557925912 } },\n    { 950000, { uint256S(\"0x781f3d6fde2b93c9e739016a0c4606769a64d834711262769d79226f3b8a4894\"), 1558735021 } },\n    { 955000, { uint256S(\"0x807b9d6a9eed15702bbfcb3c2748a50c7c03e34346476d8f2a7ba63bda8b813f\"), 1559547345 } },\n    { 960000, { uint256S(\"0xab00c23dbec9661f3e16330e78d22d2aed2df8e00bb3f2ac5997bd6c302e72e9\"), 1560360440 } },\n    { 965000, { uint256S(\"0xea173786128a536c7b9d2e5a40e5183674e52ffc9e4ce59dfbad30daba37627f\"), 1561162218 } },\n    { 970000, { uint256S(\"0xf08289e2f82fe8a07865db96824b3a88fff7290bc418f690784cb7243e2cdaac\"), 1561972044 } },\n    { 975000, { uint256S(\"0x570071efb5f68bb16f14af8ad9150d67b5d9940243aa1ca60dc0697f91881318\"), 1562776125 } },\n    { 980000, { uint256S(\"0xc7d52ea351c8def62d52f3f102d1b68d1d420a6b62a2cb6cacb1a57ccab447e0\"), 1563573643 } },\n    { 985000, { uint256S(\"0xa107e2c619a693015d5cd897ff181ddadedb4ebe09d9b6d774166386f5f765f6\"), 1564371268 } },\n    { 990000, { uint256S(\"0xe69a5eb05ec6c09019275eb57c9d95cb955128024592cba5fb7ffc5e82c3b736\"), 1565184825 } },\n    { 995000, { uint256S(\"0xabfefe12298e0f690767e341b2092517afd6745116ea2cd03a5c292a73668f77\"), 1566037355 } },\n    { 1000000, { uint256S(\"0x738a101e6024f9f4715793dbf684a0aa6328526fca068254ad6a56191acb5be2\"), 1566810491 } },\n    { 1005000, { uint256S(\"0x90d54954a253d456c1815982adc19af4161d3ed18403a9e8bc80d0943165ad58\"), 1567588577 } },\n    { 1010000, { uint256S(\"0x82b509dfce9edc470801e725e701530720e6badbbdfdf472b3c9379c0545f3e7\"), 1568363651 } },\n    { 1015000, { uint256S(\"0x6499eda9640f312cb9959df4f41182829d9b8ca271566cb4b232f490e9cdda02\"), 1569129744 } },\n    { 1020000, { uint256S(\"0x2a923cbf76079c29f2c181842531f903bb59bbd666dab4e048daa46d7548cdae\"), 1569894326 } },\n    { 1025000, { uint256S(\"0x46e4629e2a9d47c0cacdbd1ebfe1b337dd626263b8d18a297d707891927a21bb\"), 1570665822 } },\n    { 1030000, { uint256S(\"0x2f0bb472a7b73e1c7d68e30b19bd1f7588f29abd7355c0ff6be8f7c7a139ba7c\"), 1571511759 } },\n    { 1035000, { uint256S(\"0xf61c183cb5a0f95cd088c9c55234b577954ae1456a7acd2aea6433daca3abd6b\"), 1572244451 } },\n    { 1040000, { uint256S(\"0xdd73c2ea83c105a92538f5b6048fb7aa92b4c6c81124e4902aa958488d685d6f\"), 1572975627 } },\n    { 1045000, { uint256S(\"0x6b5dfd02c66cea52b8d6f07adac8d6ec87149680975159204e806674ca3b9671\"), 1573699139 } },\n    { 1050000, { uint256S(\"0xc51e7082a3281c8e8cfd8276207790067570df6d13103a0fd19bafef1517490f\"), 1574423442 } },\n    { 1055000, { uint256S(\"0xd1f48d9609840a608f9dfa0c2659a44bddc679ef9b46562bd818576b50ca0082\"), 1575144908 } },\n    { 1060000, { uint256S(\"0x8d0bf241dd3cb41ad2db731940344c7407a94629aacb9f026dcd94f5ce2ef714\"), 1575868859 } },\n    { 1065000, { uint256S(\"0x290c1653a28b44f97b4855a32f467de1886fd12f1cd85e386b5f8850a31d4e57\"), 1576592228 } },\n    { 1070000, { uint256S(\"0xa1a5dfe6ed73e8d32991ec1a0ed13268cc088e8dfefa01a51798ddc8a82c7951\"), 1577315316 } },\n    { 1075000, { uint256S(\"0xb4901b8546f0a594e44902e5ebefa20734783c13ef7ee89a75ad380c0ddc256b\"), 1578035849 } },\n    { 1080000, { uint256S(\"0x09e8ac6b33b48cf8701a8e84eea363c258d9cd0097f16a7f11316211b0f4e2ad\"), 1578760843 } },\n    { 1085000, { uint256S(\"0xb9c78d02108c55f033fc403d12d58741485160a8513f8e4a856d3b0f08d1322e\"), 1579483986 } },\n    { 1090000, { uint256S(\"0x062d9fbb5fc3328bd5ee52a556fe04e99a79b06ee354d8d13b92ef9ce098fcdc\"), 1580197107 } },\n    { 1095000, { uint256S(\"0xfaff013edffee9ea47d72bca92108725111c599734e2f664afe053f0f4f93186\"), 1580898910 } },\n    { 1100000, { uint256S(\"0x18b8b018d783b030e06dd9896689f6a140dce791795121ab226183011a39316e\"), 1581596575 } },\n    { 1105000, { uint256S(\"0x0ddf02d575ad50e237f359492e0f00bef7a86cd2336bfc932133e8b57a0f07d4\"), 1582293978 } },\n    { 1110000, { uint256S(\"0xeaa096c7a263ea485c8be90d26de2cf4b22a8f50252dc2a1c080f54213acf0b9\"), 1582991681 } },\n    { 1115000, { uint256S(\"0x9b6d256fbb6048c997a179f941bcdbe1b1b2aba9cd6ef6e522cef714f7d6de62\"), 1583691830 } },\n    { 1120000, { uint256S(\"0xbcc3bcb3213bc9f88a74bda5b9f30044da262733d2678bc10811c987b17c71b7\"), 1584388403 } },\n    { 1125000, { uint256S(\"0xd3d0d507764229ef0c676c87a5df6f1963f6dfa2845330ef94955de0ecc60271\"), 1585084828 } },\n    { 1130000, { uint256S(\"0x3a4c11d187451f340d928bf487e5d942d11559cb38f889cf69f05510ae8ff299\"), 1585791393 } },\n    { 1135000, { uint256S(\"0xbc68728519d04280048031d79e29e7f8595e68641349547491902b4d219d5f1a\"), 1586491711 } },\n    { 1140000, { uint256S(\"0xcf61d5736257e91d7e84807d84fc72fbe63436e1b94784e05262e62ac424845f\"), 1587195878 } },\n    { 1145000, { uint256S(\"0x7bc2e5a18b2c826ca3bda075045ddbf79b081e431c5c697bb392bad4f1f41bcd\"), 1587900574 } },\n    { 1150000, { uint256S(\"0xd593880023a1512c3440a2f3b7165d4a1a5bbfe2f3937612151a8f82ae19fd62\"), 1588605016 } },\n    { 1155000, { uint256S(\"0xd90ac0f57bce337bbe54b2a8ac5b11def15eed6de9f825a7f680a628801d9361\"), 1589309493 } },\n    { 1160000, { uint256S(\"0xdd68bbc925549eae05d86b0c0f3dbe32c30bacde455bae6d56b3955d83e0d3f5\"), 1590010809 } },\n    { 1165000, { uint256S(\"0xbb8a4aa9e9f3c8c009538d439cd180cdd9eb90be93cf2d73bba30742847ed785\"), 1590712627 } },\n    { 1170000, { uint256S(\"0x7f7c3efeec5ad3e323a5230dab50830dc7afe307a67660c26a612d85e8644ed0\"), 1591413120 } },\n    { 1175000, { uint256S(\"0xc8d3588ecb056da4436c35b0656bb195dd7e6efa1acd9244dd9d5aeb71a8fded\"), 1592113483 } },\n    { 1180000, { uint256S(\"0x829e9d8ecf96eabd375e339e2cf4fa431e4d15bbea003bd44ad575b7d42873c6\"), 1592816604 } },\n    { 1185000, { uint256S(\"0x83cdbe709fe811e5ca4399d938798003dcc0d9982bb4c7dd2b89bcf81a385eee\"), 1593520142 } },\n    { 1190000, { uint256S(\"0xc92271fde62831ff6da804f6e7772ed89c25fa376f36a92718752261fbfcd79a\"), 1594223236 } },\n    { 1195000, { uint256S(\"0x4169bb52e7500a2c4cca01792276f9a5afe6099557108d5ba536cefe67b9921b\"), 1594925832 } },\n    { 1200000, { uint256S(\"0x5ec6e687902cb425f96d2f90e9f9355b048f161e0c451c940815296b617fc3c7\"), 1595629353 } },\n    { 1205000, { uint256S(\"0x2998d4ec25e80416822a80d9fad910bab622e1eb3b3787d40e9c850075760ae4\"), 1596332441 } },\n    { 1210000, { uint256S(\"0x1c563dd95c69eea2335c789307352bebde0c20daab3950196056c2a61577ffb7\"), 1597034176 } },\n    { 1215000, { uint256S(\"0xeee8b2c439207ef2bf67e7d35da49531ae50253fbabc311a84a8f0974a45a696\"), 1597735210 } },\n    { 1220000, { uint256S(\"0x6625d9d0047ca7cdcf07568c96de8a5b7797278c673dfaa745204fed2a85496a\"), 1598436485 } },\n    { 1225000, { uint256S(\"0x53d40b79a1c57e6f230d8a07841324b0e0bd8eba772350093c6cba88c185c0fb\"), 1599134212 } },\n    { 1230000, { uint256S(\"0xb151a07f8b99512a105e735f7da07e8fd3c1b96f18346aecf0397e7ede4f9343\"), 1599865525 } },\n    { 1235000, { uint256S(\"0x488a9152c2d7bf33d054c44c5b2a226935ae30bef44da0d4bc45d68f499dc869\"), 1600610142 } },\n    { 1240000, { uint256S(\"0xfe92e653d665cbb0d4c6b377d63629c67b5fd71a07516d9a6b38a3bbc83c3c40\"), 1601355269 } },\n    { 1245000, { uint256S(\"0x342747aaf0c2a53fb918f0491a164ac94af567d8feab68fe66b0d20b2c4187d6\"), 1602100920 } },\n    { 1250000, { uint256S(\"0x98deb3f3940497ae37c19496aa2f32102c6b93e09266851eda3ed21019856f45\"), 1602846003 } },\n    { 1255000, { uint256S(\"0xdf0ca63264e8fb6b4532a50e94723dd79b207fa09d795a6164e8aede0bb11d2d\"), 1603591156 } },\n    { 1260000, { uint256S(\"0x05eab59283802392fad86b29fa075cd863f0bb7378276a59bf0c98a70944a856\"), 1604337439 } },\n    { 1265000, { uint256S(\"0xe018fde01ae5a7e7f0d39032c91eb38d97a2833f2eca5887813be7fc0a2a6eac\"), 1605082576 } },\n    { 1270000, { uint256S(\"0x5de5fa476f8b634315599358a9b5dd845c5ea17c5294d5b32ed85441383c55ec\"), 1605828651 } },\n    { 1275000, { uint256S(\"0x77cbeb014135626ba2a8191815119943471f85dc6cde66c2eaba9f27a5d0ef97\"), 1606573931 } },\n    { 1280000, { uint256S(\"0xd4d75792f8d7b0e9b1489adf6cf2df61ebd70cd525a8d4118c70bf7b2437c27a\"), 1607321658 } },\n    { 1285000, { uint256S(\"0x920c3d728b3e02824c11e16c61edf8afa932dbccc66590cdccebf10673df79d5\"), 1608068604 } },\n    { 1290000, { uint256S(\"0x7fa8dc91ee720ca301f3b078c8e67193524d7f01ebd1a6137b61314c7f5266e9\"), 1608817138 } },\n    { 1295000, { uint256S(\"0xc8c97d4664fcb75d4190e4b8d4a51167e11d49943cbbae1b173a22dfd3d8fc92\"), 1609565083 } },\n    { 1300000, { uint256S(\"0xc5bc69bedf064d5da7c4fa2dd226f5b1da54bc42633b9f457e63e2b394dd436f\"), 1610312313 } },\n    { 1305000, { uint256S(\"0x8ffa879b8a64b62233531b0e6be6eaaae5ffff92605a4f8afec97583d901e896\"), 1611057504 } },\n    { 1310000, { uint256S(\"0xa24b0f0f8263244376d2353ff99ed03ae554988a1983c3830cc24eef99c21729\"), 1611803649 } },\n    { 1315000, { uint256S(\"0x366095609c4bebf41fc2ce597e650bfe77461845e473efaa64e910ea50652f7b\"), 1612550568 } },\n    { 1320000, { uint256S(\"0xbe41fa7b84059e9e6aa46cd8c7705d3f6260696085491d456ee093b3f7f3f793\"), 1613296350 } },\n    { 1325000, { uint256S(\"0x02e5d27592130f6d5db878b572bb112fd4d47d05180613bc9ea0d2fdc01399a6\"), 1614042479 } },\n    { 1330000, { uint256S(\"0x2bce6f1b78835a429a408a6f3c81b96605e69d4a9c4d2f3b8368caccd623c515\"), 1614788591 } },\n    { 1335000, { uint256S(\"0x90796a847a77150a0057b3da2cde138d3363d15a108dfa971e12d452b325f259\"), 1615533362 } },\n    { 1340000, { uint256S(\"0xce51881827cf514d6db7906373a67ccc74158d93e4c0c6cf230fe4bf62491cb5\"), 1616279463 } },\n    { 1345000, { uint256S(\"0xe76a579fb016fcb9adf0d11c5b77b3ba8aa852edbb7e707875d37b5a61ecb70d\"), 1617024846 } },\n    { 1350000, { uint256S(\"0x82e37803712a73107720a7df67289b3f89c9eaffad6cf86cade0fe37f4d868a5\"), 1617764633 } },\n    { 1355000, { uint256S(\"0xd26dc371da8662ba73ecbeb427f64003b22f07821e607898dd6ea5d6a5d9e249\"), 1618511024 } },\n    { 1360000, { uint256S(\"0x18d8b9b8d578ef0b2852ea5e2685dae041ed26b752d9da5994673dff501d6ae4\"), 1619255919 } },\n    { 1365000, { uint256S(\"0xcafe06c20561246d0b093baa06ff0a46614c817e8e2a22a34d8d2dd8599c5007\"), 1620003026 } },\n    { 1370000, { uint256S(\"0x13942aa883b672824a3050be76625779e4f58162016f05423fbef389a517e849\"), 1620749406 } },\n    { 1375000, { uint256S(\"0x5029ce417fcb584c95f9a8f3af5ef35b6b02df0ebd89d24b5ac718868f6b42c1\"), 1621496378 } },\n    { 1380000, { uint256S(\"0xfd4cc3d7d6bf2395b05efcc3b0a08eabbcc104940f8f8da63e6f641281856f9d\"), 1622242242 } },\n    { 1385000, { uint256S(\"0x88ca7e22f25798832449acfe64cb8d5c8c93a0f896fbd13a992fbd476e858b02\"), 1622987304 } },\n    { 1390000, { uint256S(\"0x665724aa8b514deab8ee9cbaf0592f320a2ec787e8204347d086f64c0413df69\"), 1623733290 } },\n    { 1395000, { uint256S(\"0xb06164f6307cae47d8d210fbb839b859081c7b461bd1097737f0030ab326379a\"), 1624480080 } },\n    { 1400000, { uint256S(\"0x519a000bdb38c2afb815ebe376222405073acd7d6cd8e9e0b4069f3945ff8d0c\"), 1625225613 } },\n    { 1405000, { uint256S(\"0x23e446ca75d6cec3d6a94f50c93e64e064cab3a867046058f08ebc0c6bee6ee2\"), 1625969610 } },\n    { 1410000, { uint256S(\"0x4d71dfdc4e8b7981bf639f9dd18a2041ec620fb4c556037a90925af95331d76f\"), 1626714016 } },\n    { 1415000, { uint256S(\"0xf81a3feea87a703c66ffb9c1344600830ed02578de932c06b8b469bfa21ec346\"), 1627457979 } },\n    { 1420000, { uint256S(\"0x943e735ea96cadd10baa4a6d487b5c6ab100628ff33f75c84463c8eed1d737f7\"), 1628202047 } },\n    { 1425000, { uint256S(\"0xaad14f60b6cf713f8c0e04f6ec4e999bb29a6d9ae21bfe30ed2e25839af33c4e\"), 1628947262 } },\n    { 1430000, { uint256S(\"0x18c14586a6ac68d29bc266848774ca39c6dc90c456c25716099bf66c00c160b3\"), 1629692331 } },\n    { 1435000, { uint256S(\"0x181adc08360424df12fdf56d35fc18ed01f045a717f1f553638db6c01015cb0c\"), 1630438477 } },\n    { 1440000, { uint256S(\"0x8bd72d8da36cba75923a531f9611205d25b66bb0bc7e69f712f17a34b8164bad\"), 1631183783 } },\n    { 1445000, { uint256S(\"0xc629fd1947d70465d54d157fe742bf147bcd4afe50f11d982fcc26ed172af5b8\"), 1631929027 } },\n    { 1450000, { uint256S(\"0xe1dab5a53debd18bc93ec66fd491d752206966075cde6026897fe6150ccbf0e4\"), 1632673571 } },\n    { 1455000, { uint256S(\"0x44cf0a34e621671c774b3dbc418f3d7fd9205961260a3a909b20a83c01a842c6\"), 1633418759 } },\n    { 1460000, { uint256S(\"0xeddf7c6b2cfd48657da9dca2ce327003cfdbb73ca00caaeeae26d1646cced4d8\"), 1634165058 } },\n    { 1465000, { uint256S(\"0xb069072de34c5d7755a214940140db4c1bd142b8b63f3c8210bedac7c61105c9\"), 1634910088 } },\n    { 1470000, { uint256S(\"0xda93e57970dd0884245897f71ffb3c30cb48624f465f6b93717d65fdf002e9a4\"), 1635655816 } },\n    { 1475000, { uint256S(\"0xa7f743d7d0f9b3bfedba3e9e66a06fd2fca3b99a01091d3dcc4520149d824235\"), 1636401419 } },\n    { 1480000, { uint256S(\"0xc8eaea494b43f9fc509a92c78185c01ef5fd9eefd628d715f8afd07997f84be3\"), 1637148184 } },\n    { 1485000, { uint256S(\"0x3026473682330318ae53162fe55cfea2f04274c5f97efaedc5ae1dfb7fe90797\"), 1637893733 } },\n    { 1490000, { uint256S(\"0x3a14bfe1a2f44e0e9863f4c2425853d83b9ee966b7f12fc9bdcd451068cf7bc5\"), 1638638143 } },\n    { 1495000, { uint256S(\"0x538bc6a24714de2ca233c50af1ca8c1edaa499e441447018888a2a4e4ce5882a\"), 1639383400 } },\n    { 1500000, { uint256S(\"0x9d9278b3cd32a7034279d99ac6623a0214c7217982520b6051207a1458e848b3\"), 1640128490 } },\n    { 1505000, { uint256S(\"0x68910ebf1581b694e33983820ce4226555f32082dc6450b5dd2ca363dab83c94\"), 1640872735 } },\n    { 1510000, { uint256S(\"0xcec9aadad52eee28154a75765454c86d5495c6d48fc5fc7b2ad228d1fd0092de\"), 1641618088 } },\n    { 1515000, { uint256S(\"0x6f43aee73d91be191af5db7a1b946300d913709e8a4f271a72374d45c824306e\"), 1642362794 } },\n    { 1520000, { uint256S(\"0x278c4502ebfc23e06d9e181f48ac449dbe5d45b7a07f748822786cd3f5c7139f\"), 1643107949 } },\n    { 1525000, { uint256S(\"0x9596095dd60454a617e52cceb1976503f752cafff9d3f2d019221600fbf56ea6\"), 1643853535 } },\n    { 1530000, { uint256S(\"0x39f694a8ed6e64e40c527c87a1f072085f77ac17a1f72bc2c0dd1e3c4d8915d7\"), 1644598722 } },\n    { 1535000, { uint256S(\"0x6c642b81ebd0b9b29c76fbed838f9c19bb2eed03dc63d779907e2dd3e636ff43\"), 1645342909 } },\n    { 1540000, { uint256S(\"0x8534bf73be4d91f4228fba2a12cd0a9b490998cfbaae6953016d652306fd04a8\"), 1646087950 } },\n    { 1545000, { uint256S(\"0x97d1c3271acac5e4f2d56dad10c225fc98194c4e030b3dec8161da274bd69fd8\"), 1646832551 } },\n    { 1550000, { uint256S(\"0x1634ba366e3441fa49164608ac82922c19b2a2a7fbc9cd325b1c9e604272a923\"), 1647576323 } },\n    { 1555000, { uint256S(\"0xac7999271471658d766c261917e5c904f10b1b49895d41073327eaafc24d19ae\"), 1648321834 } },\n    { 1560000, { uint256S(\"0xa39a0854fb7b06e4d6dd5fe37f4049e2ab1f98b0a5075f7f8449fa84f3e934c9\"), 1649063390 } },\n    { 1565000, { uint256S(\"0x2328e182f0a619e29d8667701b8400dd0ae3ababb35ab4e97f35c549ed221cdd\"), 1649808681 } },\n    { 1570000, { uint256S(\"0xea88e102106b29296b0c24901f39c10f8a37d50d3b9ab82fed95f06ca2942d89\"), 1650553743 } },\n    { 1575000, { uint256S(\"0xf5269e1088f88429e1954ecb99f402d682ee56b1947926c9cb2d4acccc846924\"), 1651299448 } },\n    { 1580000, { uint256S(\"0x02c25c6109fec8f5b60661fef954ae8986c1c5620b0955b1d1f8da306cff5e90\"), 1652043637 } },\n    { 1585000, { uint256S(\"0xea93ab7111830ac691f763af4a5d5a8322f7b88d9a406681ee9662a68fe16a83\"), 1652788230 } },\n    { 1590000, { uint256S(\"0xbbf35eb252f5cf4614e90b2ecfff8c40632cbcde2ba55a93963515ce43309a4b\"), 1653532285 } },\n    { 1595000, { uint256S(\"0xe8ac4e384530267a7b48898de8d03619197fbc7bd58ccf88d277802a5c4ae799\"), 1654276121 } },\n    { 1600000, { uint256S(\"0xebed5d5a1d49ee803cf0730d6d85bd97f215568a6ee9aaf9cda81594e0823d4f\"), 1655020815 } },\n    { 1605000, { uint256S(\"0xa00132fb5b90e0a2906e9de41690281360c935d100009dc09f151bc06884b9b4\"), 1655763985 } },\n    { 1610000, { uint256S(\"0xbfdf7a063d60ea13c5941170a1b643894077502af5eb0a01f5f1d2183189df13\"), 1656509069 } },\n    { 1615000, { uint256S(\"0xa463bf89f287ad1a54a7710a4dfe87996ba2b1e9a75f310e25f9416ad9e7e988\"), 1657254743 } },\n    { 1620000, { uint256S(\"0x69d676efc47b173f56380ac27f1527225a53e6a1bd2f7e945e52d2c177f12b26\"), 1658010763 } },\n    { 1625000, { uint256S(\"0x937c7bdb57cfee05bc0b95bcb790f18d0c5d39d90d927ea7ace17d1bb6f37e26\"), 1658743227 } },\n    { 1630000, { uint256S(\"0xd2d8361c8f1e244233802ab4d9281eb76c272d4e4aee68bf63deac2ba7bce074\"), 1659487169 } },\n    { 1635000, { uint256S(\"0x2b026e3263b506c4cd0a40f52fff468b51082d639a6d9931e3d29148176efdd6\"), 1660230553 } },\n    { 1640000, { uint256S(\"0x68041745c63e5a0e76408222053953f175fb94874713215b98d371bfd140a4bc\"), 1660974571 } },\n    { 1645000, { uint256S(\"0xc913109540a97f6f1d4e52911a7e84d0682dfc30b9b457f71dee1db882eaab09\"), 1661718982 } },\n    { 1650000, { uint256S(\"0x566386c0dd3e347900b7e35f747d4c2d0ff57efa106be78cfb451584412fec15\"), 1662463301 } },\n    { 1655000, { uint256S(\"0x224be463b0fbb1ea8ecb73570ac6159eede9b05d14c11c71152c88aa74327522\"), 1663207276 } },\n    { 1660000, { uint256S(\"0xc1bbbba77770c7dccecdba80195214f7ec23440608241e52a677917c0f1becfb\"), 1663951120 } },\n    { 1665000, { uint256S(\"0xdff307b21adec4ff7b39a9238f3d8843ac3bd0b73bec807146a0fb334cb2da15\"), 1664694507 } },\n    { 1670000, { uint256S(\"0xf51cd43d75ca981aa75626f5a14e8cf111544d703ee6352fb66a54080f1bd66c\"), 1665437585 } },\n    { 1675000, { uint256S(\"0x07c2b954391202b53212cb31713015ee8b6981c6579d700c15793248359964a2\"), 1666179652 } },\n    { 1680000, { uint256S(\"0x0335118a4fcc09c1be95c13ca27440b9b506306a0062f321e42ff5dfd0d5d262\"), 1666922828 } },\n    { 1685000, { uint256S(\"0xc79674375fa1a3a86a0d9a555d587833577adaee788e6d2e53665d23cd170ad8\"), 1667666168 } },\n    { 1690000, { uint256S(\"0xa51ae96b7358c4f75288105bdc5bb042483418af27cc9a2f5288319c06c7b523\"), 1668409229 } },\n    { 1695000, { uint256S(\"0x222fcb3cf6312fc01db09e6717a11ad0de59ed2a308a040c4199818e569a8c7b\"), 1669152300 } },\n    { 1700000, { uint256S(\"0x0ba1d19adae5018b8dbb96d4dc010c08be1f9e2e6e92aeefcbf37d7f7b3c22f1\"), 1669896300 } },\n    { 1705000, { uint256S(\"0x43dde22457ab50f502e4002d83ddb2100e325ec5df74f3830930a9385f8b05cb\"), 1670639634 } },\n    { 1710000, { uint256S(\"0xad851f13ab99d85f3376c5990b3611adc240232447ecac592462359f14e5b804\"), 1671382920 } },\n    { 1715000, { uint256S(\"0x025507f6b30cace03eeb440dc017ad288afa4e3c851ee3af1ba365757b435668\"), 1672125332 } },\n    { 1720000, { uint256S(\"0xb14b6f52f35b1416ffd0c698784c35e161300847f1e2c2636600d92047ebbdbd\"), 1672868424 } },\n    { 1725000, { uint256S(\"0x49dc222b29b372e66cc75801e25694bf9141a00e46f627305dbb917bb1434594\"), 1673612943 } },\n    { 1730000, { uint256S(\"0xd2813dd9ed242fabd9dba1572b8a8b51da985eb32248215626aedf0225bfcb1d\"), 1674356034 } },\n    { 1735000, { uint256S(\"0xa16e252f4bcb40de204740f57e17eb7d1f66014bbefb422bab3f58327576675c\"), 1675099276 } },\n    { 1740000, { uint256S(\"0x3ea031c589b70942f7331a60b31e994ad0e1c71b58b0f74c83f85b6f8e135c45\"), 1675843881 } },\n    { 1745000, { uint256S(\"0xe51985e8bfd1b91887843fd116a394b8cd005d986085f4e455f63d81636e805e\"), 1676588398 } },\n    { 1750000, { uint256S(\"0x7efcb6e8affaccbc546cfb1402be834e2c3ac7120fea173a717a024f27ec0805\"), 1677333340 } },\n    { 1755000, { uint256S(\"0x7c8a5aa38226c9ad3d2e3a4d531b4ba52a37d9683bac022bc26775a303a69d29\"), 1678077092 } },\n    { 1760000, { uint256S(\"0x0a2557ab2052b04dfc2ed2e74051865a0cced7ba04708ac80f7be171a23df733\"), 1678820978 } },\n    { 1765000, { uint256S(\"0xd021da7f0c66bdc7c547a0e1c661c94a4c5d0cc48bfa35c0694de5d9a864ded7\"), 1679564284 } },\n    { 1770000, { uint256S(\"0x5847ab4c285505e2a80ebcfa3a6ca668afadb60b5fa5ec76c1aae1b5f95ac9fe\"), 1680308258 } },\n    { 1775000, { uint256S(\"0x90a3da090304b5a6a03b2e52d800451bdc8cec67227d07a24adaba4ff7b4efc9\"), 1681048125 } },\n    { 1780000, { uint256S(\"0x9e09696b83b06e7bf2a06e0f204eb14c81fe4bbc9ef8695f17527e3c8f81b590\"), 1681793220 } },\n    { 1785000, { uint256S(\"0x64209caf155d6abb2132f5068be7f06568689c12e6757f16f583bf0fc8b3cdb2\"), 1682536099 } },\n    { 1790000, { uint256S(\"0x794870c13c2664ef867ed462a4882b8b086831c82bd0fe4d05e0ca0b49b8d7cf\"), 1683279888 } },\n    { 1795000, { uint256S(\"0x8529b4f62bac0f5ce02915e889579036afdbdee50d876df05f7677c2f6be2bdd\"), 1684023415 } },\n    { 1800000, { uint256S(\"0x41269e8fcaa2420726680b3330b5109bf044194dee7a0cb492db76bf01264ed2\"), 1684766311 } },\n    { 1805000, { uint256S(\"0xd1498e95b8d2cf0aaeca2d87f791b9d198b4944b9c360572c50863ca4062e2a1\"), 1685510286 } },\n    { 1810000, { uint256S(\"0x4f32d37e0a35758196f77310595eec01193dff761c58815e73d6a22a49a9c2a1\"), 1686253727 } },\n    { 1815000, { uint256S(\"0x8048be7a35d256fe8cf937c6bab38ebed8f59ccb727510db4c733890e90e6f19\"), 1686998694 } },\n    { 1820000, { uint256S(\"0xd5facd1233a81fa17dcc0f0ecd8cc6bd3fe78539e788ca2a00a3436d2a2aa81d\"), 1687742996 } },\n    { 1825000, { uint256S(\"0x4554d94110b15d438ee0fb1591c2ee6b9e206d59a016dca8726ba635ba94b519\"), 1688485136 } },\n    { 1830000, { uint256S(\"0x9d2f9320c3eddc43bab1e2cd0ddf97614a18e8de6a6c5a6438f2b082ddfff206\"), 1689228563 } },\n    { 1835000, { uint256S(\"0xaa868446efa0c438a18dbaed6734616bf2f94925d936d6b85be9c657fd72c019\"), 1689972517 } },\n    { 1840000, { uint256S(\"0xb5279fae6931bfadc1f44ddc69d0bc30c57958ce50d9fb1eca0e99367761d4a2\"), 1690717074 } },\n    { 1845000, { uint256S(\"0x61f6690fd14bfc430881de7468639c36aefa2d110d54a415828562e0cc7223c0\"), 1691459722 } },\n    { 1850000, { uint256S(\"0x09edf19c3243534e5e09086249dc8bcfbb247676e4c86d4e907cae7f1b84fe97\"), 1692200631 } },\n    { 1854760, { uint256S(\"0xe02107de6b86565ea8e900e0e6fddc638eb336703f904ae9bbda408d5e51d9bf\"), 1692908658 } },\n    { 1855912, { uint256S(\"0x9e9f37df34722539fec5b453ecb8610cbef8e9dd2b4a014e8938b82161b58806\"), 1693080717 } },\n"
  },
  {
    "path": "src/data/core-packages.licenses",
    "content": "\n-- LevelDB\nCopyright (c) 2011 The LevelDB Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-- QFontIcon\nCopyright (c) 2017 Sacha SCHUTZ\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to \nwhom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR \nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-- QFontIcon\nCopyright (c) 2017 Sacha SCHUTZ\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to \nwhom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR \nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-- scrypt\nThe included code and documentation (\"scrypt\") is distributed under the\nfollowing terms:\n\nCopyright 2005-2016 Colin Percival.  All rights reserved.\nCopyright 2005-2016 Tarsnap Backup Inc.  All rights reserved.\nCopyright 2014 Sean Kelly.  All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n-- ctaes\nThe MIT License (MIT)\n\nCopyright (c) 2016 Pieter Wuille\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n-- libsecp256k1\nCopyright (c) 2013 Pieter Wuille\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n-- LRUCache11\n/*\n * LRUCache11 - a templated C++11 based LRU cache class that allows\n * specification of\n * key, value and optionally the map container type (defaults to\n * std::unordered_map)\n * By using the std::unordered_map and a linked list of keys it allows O(1) insert, delete\n * and\n * refresh operations.\n *\n * This is a header-only library and all you need is the LRUCache11.hpp file\n *\n * Github: https://github.com/mohaps/lrucache11\n *\n * This is a follow-up to the LRUCache project -\n * https://github.com/mohaps/lrucache\n *\n * Copyright (c) 2012-22 SAURAV MOHAPATRA <mohaps@gmail.com>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n-- UniValue\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n-- libqrencode\nCopyright (C) 2006-2018 Kentaro Fukuchi\n\nThis library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or any later version.\n\nThis library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n-- Bitcoin Core\nThe MIT License (MIT)\n\nCopyright (c) 2009-2019 The Bitcoin Core developers\nCopyright (c) 2009-2019 Bitcoin Developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "src/dbwrapper.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"dbwrapper.h\"\n\n#include \"fs.h\"\n#include \"util.h\"\n#include \"random.h\"\n\n#include <leveldb/cache.h>\n#include <leveldb/env.h>\n#include <leveldb/filter_policy.h>\n#include <memenv.h>\n#include <stdint.h>\n#include <algorithm>\n\nclass CLevelDBLogger : public leveldb::Logger {\npublic:\n    // This code is adapted from posix_logger.h, which is why it is using vsprintf.\n    // Please do not do this in normal code\n    virtual void Logv(const char * format, va_list ap) override {\n            if (!LogAcceptCategory(BCLog::LEVELDB)) {\n                return;\n            }\n            char buffer[500];\n            for (int iter = 0; iter < 2; iter++) {\n                char* base;\n                int bufsize;\n                if (iter == 0) {\n                    bufsize = sizeof(buffer);\n                    base = buffer;\n                }\n                else {\n                    bufsize = 30000;\n                    base = new char[bufsize];\n                }\n                char* p = base;\n                char* limit = base + bufsize;\n\n                // Print the message\n                if (p < limit) {\n                    va_list backup_ap;\n                    va_copy(backup_ap, ap);\n                    // Do not use vsnprintf elsewhere in Munt source code, see above.\n                    p += vsnprintf(p, limit - p, format, backup_ap);\n                    va_end(backup_ap);\n                }\n\n                // Truncate to available space if necessary\n                if (p >= limit) {\n                    if (iter == 0) {\n                        continue;       // Try again with larger buffer\n                    }\n                    else {\n                        p = limit - 1;\n                    }\n                }\n\n                // Add newline if necessary\n                if (p == base || p[-1] != '\\n') {\n                    *p++ = '\\n';\n                }\n\n                assert(p <= limit);\n                base[std::min(bufsize - 1, (int)(p - base))] = '\\0';\n                LogPrintStr(base);\n                if (base != buffer) {\n                    delete[] base;\n                }\n                break;\n            }\n    }\n};\n\nstatic leveldb::Options GetOptions(size_t nCacheSize)\n{\n    leveldb::Options options;\n    options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);\n    options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously\n    options.filter_policy = leveldb::NewBloomFilterPolicy(10);\n    options.compression = leveldb::kNoCompression;\n    options.max_open_files = 64;\n    options.info_log = new CLevelDBLogger();\n    if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {\n        // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error\n        // on corruption in later versions.\n        options.paranoid_checks = true;\n    }\n    return options;\n}\n\nCDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)\n{\n    penv = NULL;\n    readoptions.verify_checksums = true;\n    iteroptions.verify_checksums = true;\n    iteroptions.fill_cache = false;\n    syncoptions.sync = true;\n    options = GetOptions(nCacheSize);\n    options.create_if_missing = true;\n    if (fMemory) {\n        penv = leveldb::NewMemEnv(leveldb::Env::Default());\n        options.env = penv;\n    } else {\n        if (fWipe) {\n            LogPrintf(\"Wiping LevelDB in %s\\n\", path.string());\n            leveldb::Status result = leveldb::DestroyDB(path.string(), options);\n            dbwrapper_private::HandleError(result);\n        }\n        TryCreateDirectory(path);\n        LogPrintf(\"Opening LevelDB in %s\\n\", path.string());\n    }\n    leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);\n    dbwrapper_private::HandleError(status);\n    LogPrintf(\"Opened LevelDB successfully\\n\");\n\n    // The base-case obfuscation key, which is a noop.\n    obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\\000');\n\n    bool key_exists = Read(OBFUSCATE_KEY_KEY, COMPACTSIZEVECTOR(obfuscate_key));\n\n    if (!key_exists && obfuscate && IsEmpty()) {\n        // Initialize non-degenerate obfuscation if it won't upset\n        // existing, non-obfuscated data.\n        std::vector<unsigned char> new_key = CreateObfuscateKey();\n\n        // Write `new_key` so we don't obfuscate the key with itself\n        Write(OBFUSCATE_KEY_KEY, COMPACTSIZEVECTOR(new_key));\n        obfuscate_key = new_key;\n\n        LogPrintf(\"Wrote new obfuscate key for %s: %s\\n\", path.string(), HexStr(obfuscate_key));\n    }\n\n    LogPrintf(\"Using obfuscation key for %s: %s\\n\", path.string(), HexStr(obfuscate_key));\n}\n\nCDBWrapper::~CDBWrapper()\n{\n    delete pdb;\n    pdb = NULL;\n    delete options.filter_policy;\n    options.filter_policy = NULL;\n    delete options.info_log;\n    options.info_log = NULL;\n    delete options.block_cache;\n    options.block_cache = NULL;\n    delete penv;\n    options.env = NULL;\n}\n\nbool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)\n{\n    leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);\n    dbwrapper_private::HandleError(status);\n    return true;\n}\n\n// Prefixed with null character to avoid collisions with other keys\n//\n// We must use a string constructor which specifies length so that we copy\n// past the null-terminator.\nconst std::string CDBWrapper::OBFUSCATE_KEY_KEY(\"\\000obfuscate_key\", 14);\n\nconst unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;\n\n/**\n * Returns a string (consisting of 8 random bytes) suitable for use as an\n * obfuscating XOR key.\n */\nstd::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const\n{\n    unsigned char buff[OBFUSCATE_KEY_NUM_BYTES];\n    GetRandBytes(buff, OBFUSCATE_KEY_NUM_BYTES);\n    return std::vector<unsigned char>(&buff[0], &buff[OBFUSCATE_KEY_NUM_BYTES]);\n\n}\n\nbool CDBWrapper::IsEmpty()\n{\n    std::unique_ptr<CDBIterator> it(NewIterator());\n    it->SeekToFirst();\n    return !(it->Valid());\n}\n\nCDBIterator::~CDBIterator() { delete piter; }\nbool CDBIterator::Valid() { return piter->Valid(); }\nvoid CDBIterator::SeekToFirst() { piter->SeekToFirst(); }\nvoid CDBIterator::Next() { piter->Next(); }\n\nnamespace dbwrapper_private {\n\nvoid HandleError(const leveldb::Status& status)\n{\n    if (status.ok())\n        return;\n    LogPrintf(\"%s\\n\", status.ToString());\n    if (status.IsCorruption())\n        throw dbwrapper_error(\"Database corrupted\");\n    if (status.IsIOError())\n        throw dbwrapper_error(\"Database I/O error\");\n    if (status.IsNotFound())\n        throw dbwrapper_error(\"Database entry missing\");\n    throw dbwrapper_error(\"Unknown database error\");\n}\n\nconst std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)\n{\n    return w.obfuscate_key;\n}\n\n};\n"
  },
  {
    "path": "src/dbwrapper.h",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef DBWRAPPER_H\n#define DBWRAPPER_H\n\n#include \"clientversion.h\"\n#include \"fs.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"version.h\"\n\n#include <leveldb/db.h>\n#include <leveldb/write_batch.h>\n\nstatic const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;\nstatic const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;\n\nclass dbwrapper_error : public std::runtime_error\n{\npublic:\n    dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}\n};\n\nclass CDBWrapper;\n\n/** These should be considered an implementation detail of the specific database.\n */\nnamespace dbwrapper_private {\n\n/** Handle database error by throwing dbwrapper_error exception.\n */\nvoid HandleError(const leveldb::Status& status);\n\n/** Work around circular dependency, as well as for testing in dbwrapper_tests.\n * Database obfuscation should be considered an implementation detail of the\n * specific database.\n */\nconst std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);\n\n};\n\n/** Batch of changes queued to be written to a CDBWrapper */\nclass CDBBatch\n{\n    friend class CDBWrapper;\n\nprivate:\n    const CDBWrapper &parent;\n    leveldb::WriteBatch batch;\n\n    CDataStream ssKey;\n    CDataStream ssValue;\n\n    size_t size_estimate;\n\npublic:\n    /**\n     * @param[in] _parent   CDBWrapper that this batch is to be submitted to\n     */\n    CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };\n\n    void Clear()\n    {\n        batch.Clear();\n        size_estimate = 0;\n    }\n\n    template <typename K, typename V>\n    void Write(const K& key, const V& value)\n    {\n        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey << key;\n        leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());\n\n        ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);\n        ssValue << value;\n        ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));\n        leveldb::Slice slValue((const char*)ssValue.data(), ssValue.size());\n\n        batch.Put(slKey, slValue);\n        // LevelDB serializes writes as:\n        // - byte: header\n        // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)\n        // - byte[]: key\n        // - varint: value length\n        // - byte[]: value\n        // The formula below assumes the key and value are both less than 16k.\n        size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();\n        ssKey.clear();\n        ssValue.clear();\n    }\n\n    template <typename K>\n    void Erase(const K& key)\n    {\n        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey << key;\n        leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());\n\n        batch.Delete(slKey);\n        // LevelDB serializes erases as:\n        // - byte: header\n        // - varint: key length\n        // - byte[]: key\n        // The formula below assumes the key is less than 16kB.\n        size_estimate += 2 + (slKey.size() > 127) + slKey.size();\n        ssKey.clear();\n    }\n\n    size_t SizeEstimate() const { return size_estimate; }\n};\n\nclass CDBIterator\n{\nprivate:\n    const CDBWrapper &parent;\n    leveldb::Iterator *piter;\n\npublic:\n\n    /**\n     * @param[in] _parent          Parent CDBWrapper instance.\n     * @param[in] _piter           The original leveldb iterator.\n     */\n    CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :\n        parent(_parent), piter(_piter) { };\n    ~CDBIterator();\n\n    bool Valid();\n\n    void SeekToFirst();\n\n    template<typename K> void Seek(const K& key) {\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey << key;\n        leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());\n        piter->Seek(slKey);\n    }\n\n    void Next();\n\n    template<typename K> bool GetKey(K& key) {\n        leveldb::Slice slKey = piter->key();\n        try {\n            CDataStream ssKey(MakeByteSpan(slKey.ToString()), SER_DISK, CLIENT_VERSION);\n            ssKey >> key;\n        } catch (const std::exception&) {\n            return false;\n        }\n        return true;\n    }\n\n    template<typename V> bool GetValue(V& value) {\n        leveldb::Slice slValue = piter->value();\n        try {\n            CDataStream ssValue(MakeByteSpan(slValue.ToString()), SER_DISK, CLIENT_VERSION);\n            ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));\n            ssValue >> value;\n        } catch (const std::exception&) {\n            return false;\n        }\n        return true;\n    }\n\n    template<typename V> bool GetValueLegacy(V& value) {\n        leveldb::Slice slValue = piter->value();\n        try {\n            CDataStream ssValue(MakeByteSpan(slValue.ToString()), SER_DISK, CLIENT_VERSION);\n            ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));\n            value.UnserializeLegacy(ssValue);\n        } catch (const std::exception& e) {\n            std::string sDebugInfo = e.what();\n            return false;\n        }\n        return true;\n    }\n\n    unsigned int GetValueSize() {\n        return piter->value().size();\n    }\n\n};\n\nclass CDBWrapper\n{\n    friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);\nprivate:\n    //! custom environment this database is using (may be NULL in case of default environment)\n    leveldb::Env* penv;\n\n    //! database options used\n    leveldb::Options options;\n\n    //! options used when reading from the database\n    leveldb::ReadOptions readoptions;\n\n    //! options used when iterating over values of the database\n    leveldb::ReadOptions iteroptions;\n\n    //! options used when writing to the database\n    leveldb::WriteOptions writeoptions;\n\n    //! options used when sync writing to the database\n    leveldb::WriteOptions syncoptions;\n\n    //! the database itself\n    leveldb::DB* pdb;\n\n    //! a key used for optional XOR-obfuscation of the database\n    std::vector<unsigned char> obfuscate_key;\n\n    //! the key under which the obfuscation key is stored\n    static const std::string OBFUSCATE_KEY_KEY;\n\n    //! the length of the obfuscate key in number of bytes\n    static const unsigned int OBFUSCATE_KEY_NUM_BYTES;\n\n    std::vector<unsigned char> CreateObfuscateKey() const;\n\npublic:\n    /**\n     * @param[in] path        Location in the filesystem where leveldb data will be stored.\n     * @param[in] nCacheSize  Configures various leveldb cache settings.\n     * @param[in] fMemory     If true, use leveldb's memory environment.\n     * @param[in] fWipe       If true, remove all existing data.\n     * @param[in] obfuscate   If true, store data obfuscated via simple XOR. If false, XOR\n     *                        with a zero'd byte array.\n     */\n    CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);\n    ~CDBWrapper();\n\n    template <typename K, typename V>\n    bool Read(const K& key, V& value) const\n    {\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey << key;\n        leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());\n\n        std::string strValue;\n        leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);\n        if (!status.ok()) {\n            if (status.IsNotFound())\n                return false;\n            LogPrintf(\"LevelDB read failure: %s\\n\", status.ToString());\n            dbwrapper_private::HandleError(status);\n        }\n        try {\n            CDataStream ssValue(MakeWritableByteSpan(strValue), SER_DISK, CLIENT_VERSION);\n            ssValue.Xor(obfuscate_key);\n            ssValue >> value;\n        } catch (const std::exception&) {\n            return false;\n        }\n        return true;\n    }\n\n    template <typename K, typename V>\n    bool Write(const K& key, const V& value, bool fSync = false)\n    {\n        CDBBatch batch(*this);\n        batch.Write(key, value);\n        return WriteBatch(batch, fSync);\n    }\n\n    template <typename K>\n    bool Exists(const K& key) const\n    {\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey << key;\n        leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());\n\n        std::string strValue;\n        leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);\n        if (!status.ok()) {\n            if (status.IsNotFound())\n                return false;\n            LogPrintf(\"LevelDB read failure: %s\\n\", status.ToString());\n            dbwrapper_private::HandleError(status);\n        }\n        return true;\n    }\n\n    template <typename K>\n    bool Erase(const K& key, bool fSync = false)\n    {\n        CDBBatch batch(*this);\n        batch.Erase(key);\n        return WriteBatch(batch, fSync);\n    }\n\n    bool WriteBatch(CDBBatch& batch, bool fSync = false);\n\n    // not available for LevelDB; provide for compatibility with BDB\n    bool Flush()\n    {\n        return true;\n    }\n\n    bool Sync()\n    {\n        CDBBatch batch(*this);\n        return WriteBatch(batch, true);\n    }\n\n    CDBIterator *NewIterator()\n    {\n        return new CDBIterator(*this, pdb->NewIterator(iteroptions));\n    }\n\n    /**\n     * Return true if the database managed by this class contains no entries.\n     */\n    bool IsEmpty();\n\n    template<typename K>\n    size_t EstimateSize(const K& key_begin, const K& key_end) const\n    {\n        CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);\n        ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);\n        ssKey1 << key_begin;\n        ssKey2 << key_end;\n        leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());\n        leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());\n        uint64_t size = 0;\n        leveldb::Range range(slKey1, slKey2);\n        pdb->GetApproximateSizes(&range, 1, &size);\n        return size;\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\napp/src/main/assets\napp/src/main/jniLibs\napp/build\n\nstaticfiltercp\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/build.gradle",
    "content": "plugins {\n    id \"com.jaredsburrows.license\" version \"0.8.42\"\n}\n\napply plugin: 'com.android.application'\n\napply plugin: 'kotlin-android'\n\napply plugin: 'kotlin-android-extensions'\n\napply plugin: 'kotlin-kapt'\n\nandroid {\n    compileSdkVersion 32\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 32\n        multiDexEnabled true\n        versionCode 1\n        versionName \"1.0\"\n        ndk {\n            debugSymbolLevel 'FULL'\n        }\n        ndkPath \"$projectDir/../../../../../developer-tools/android-ndk/android-ndk-r23b/\"\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n        vectorDrawables.useSupportLibrary = true\n    }\n\n    packagingOptions {\n        jniLibs {\n            useLegacyPackaging false\n        }\n    }\n\n    //This file can't (and shouldn't ever) be compressed.\n    aaptOptions {\n        noCompress 'staticfiltercp'\n    }\n\n    //Latest okhttp requires java 8 minimum.\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n\n    buildTypes {\n        all {\n            shrinkResources true\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        debug {\n            shrinkResources false\n            minifyEnabled false\n            debuggable true\n        }\n    }\n\n    // Flavour specific config.\n    flavorDimensions \"default\"\n    productFlavors {\n        munt_testnet {\n            applicationId 'com.gulden.testnet'\n            archivesBaseName = 'munt'\n            resValue \"string\", \"app_name\", \"Munt-testnet\"\n            buildConfigField \"boolean\", \"TESTNET\", \"true\"\n            buildConfigField \"String\", \"OLD_WALLET_PROTOBUF_FILENAME\", '\"wallet-protobuf-testnet\"'\n            versionCode 300504\n            versionName = \"3.0.2\"\n            resValue \"string\", \"about_text_app_name\", \"Munt testnet $versionName ($versionCode)\"\n            resValue \"string\", \"about_text_app_copyright\", \"© 2022 Centure.com BV\"\n        }\n\n        munt_mainnet {\n            applicationId 'com.gulden.wallet'\n            archivesBaseName = 'munt'\n            resValue \"string\", \"app_name\", \"Munt\"\n            buildConfigField \"boolean\", \"TESTNET\", \"false\"\n            buildConfigField \"String\", \"OLD_WALLET_PROTOBUF_FILENAME\", '\"wallet-protobuf\"'\n            versionCode 504\n            versionName = \"3.0.2\"\n            resValue \"string\", \"about_text_app_name\", \"Munt $versionName ($versionCode)\"\n            resValue \"string\", \"about_text_app_copyright\", \"© 2022 Centure.com BV\"\n        }\n    }\n\n    sourceSets {\n        munt_testnet {\n            assets.srcDirs = ['src/main/assets', 'src/main/assetsTestnet']\n        }\n        munt_mainnet {\n            assets.srcDirs = ['src/main/assets', 'src/main/assetsMainnet']\n        }\n    }\n\n    // Build a separate apk for each native architecture we support.\n    splits\n    {\n        abi\n        {\n            enable true\n            reset()\n            include \"x86\", \"armeabi-v7a\", \"arm64-v8a\", \"x86_64\"\n            universalApk false\n        }\n    }\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\n    implementation 'com.google.android.material:material:1.8.0-alpha01'\n    implementation 'com.google.android.gms:play-services-vision:20.1.3'\n    implementation 'androidx.versionedparcelable:versionedparcelable:1.1.1'\n    implementation 'androidx.preference:preference-ktx:1.2.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'\n    implementation 'androidx.vectordrawable:vectordrawable:1.2.0-beta01'\n    implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n    implementation 'androidx.appcompat:appcompat:1.5.1'\n    implementation \"androidx.work:work-runtime:2.7.1\"\n    implementation \"androidx.work:work-runtime-ktx:2.7.1\"\n    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'\n    implementation \"androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1\"\n    implementation \"androidx.concurrent:concurrent-futures:1.1.0\"\n    implementation \"androidx.concurrent:concurrent-futures-ktx:1.1.0\"\n    implementation \"commons-validator:commons-validator:1.6\" exclude module: \"commons-logging\"\n    implementation \"commons-io:commons-io:2.6\"\n    implementation 'com.squareup.okhttp3:okhttp:4.2.1'\n    implementation 'com.localebro:okhttpprofiler:1.0.8'\n    implementation 'com.squareup.moshi:moshi:1.8.0'\n    implementation 'se.ansman.kotshi:api:2.0-rc1'\n    implementation 'com.jayway.jsonpath:json-path:2.4.0'\n    kapt 'se.ansman.kotshi:compiler:2.0-rc1'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'androidx.test:runner:1.4.0'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' exclude group: 'com.google.code.findbugs', module: 'jsr305'\n    //todo: get rid of this ASAP\n    implementation 'com.github.alvinhkh:TextDrawable:f9f516c43b'\n    implementation 'com.android.volley:volley:1.2.1'\n}\n\nlicenseReport {\n    generateHtmlReport = true\n    generateJsonReport = true\n\n    // These options are ignored for Java projects\n    copyHtmlReportToAssets = true\n    copyJsonReportToAssets = true\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/proguard-rules.pro",
    "content": "# Support\n# Below is probably overkill, but keep it like this for now; we can slowly tune it to be less aggressive later.\n# Otherwise there were issues with ActionMode and other things\n-dontwarn com.google.android.material.**\n-keep class com.google.android.material.** { *; }\n-dontwarn androidx.**\n-keep class androidx.** { *; }\n-keep interface androidx.** { *; }\n-dontwarn android.support.v4.**\n-keep class android.support.v4.** { *; }\n-dontwarn android.support.v7.**\n-keep class android.support.v7.** { *; }\n\n# unity backend\n-keep class unity_wallet.jniunifiedbackend.** { *; }\n-keep interface unity_wallet.jniunifiedbackend.** { *; }\n\n#### OkHttp, Retrofit and Moshi\n-dontwarn okio.**\n-dontwarn javax.annotation.**\n-keepclasseswithmembers class * { @retrofit2.http.* <methods>; }\n-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase\n-dontwarn org.codehaus.mojo.animal_sniffer.*\n-dontwarn okhttp3.internal.platform.ConscryptPlatform\n\n-dontwarn org.apache.**\n-dontwarn org.apache.commons.logging.**\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/androidTest/java/unity_wallet/ExampleInstrumentedTest.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport androidx.test.InstrumentationRegistry\nimport androidx.test.runner.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest\n{\n    @Test fun useAppContext()\n    {\n        // Context of the app under test.\n        val appContext = InstrumentationRegistry.getTargetContext()\n        assertEquals(\"unity_wallet\", appContext.packageName)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"unity_wallet\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n\n    <uses-feature android:name=\"android.hardware.camera.autofocus\" />\n    <uses-feature\n        android:name=\"android.hardware.camera\"\n        android:required=\"true\" />\n\n    <application\n        android:allowBackup=\"false\"\n        android:name=\"ActivityManager\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:ignore=\"GoogleAppIndexingWarning\">\n\n        <activity\n            android:name=\".UpgradeActivity\"\n            android:label=\"Upgrading\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.BlueBackground.NoActionBar\" />\n        <activity\n            android:name=\".URIHandlerActivity\"\n            android:label=\"@string/app_name\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.Transparent\"\n            android:exported=\"true\">\n            <!-- As we are transparent don't request a screenOrientation - this causes errors on some phones -->\n            <!-- URI handlers for send fragment-->\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n                <data android:scheme=\"munt\"/>\n                <data android:scheme=\"Munt\" tools:ignore=\"AppLinkUrlError\" />\n                <data android:scheme=\"iban\"/>\n                <data android:scheme=\"Iban\" tools:ignore=\"AppLinkUrlError\" />\n                <data android:scheme=\"IBAN\" tools:ignore=\"AppLinkUrlError\" />\n                <data android:scheme=\"sepa\"/>\n                <data android:scheme=\"Sepa\" tools:ignore=\"AppLinkUrlError\" />\n                <data android:scheme=\"SEPA\" tools:ignore=\"AppLinkUrlError\" />\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n                <category android:name=\"android.intent.category.BROWSABLE\"/>\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".WalletActivity\"\n            android:label=\"@string/app_name\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".WelcomeActivity\"\n            android:label=\"@string/title_activity_welcome\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.BlueBackground.NoActionBar\" />\n        <activity\n            android:name=\".ui.EnterRecoveryPhraseActivity\"\n            android:label=\"@string/title_activity_enter_recovery_phrase\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n        <activity\n            android:name=\".ui.ShowRecoveryPhraseActivity\"\n            android:label=\"@string/title_activity_enter_recovery_phrase\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n        <activity\n            android:name=\"barcodereader.BarcodeCaptureActivity\"\n            android:label=\"@string/title_activity_barcode_capture\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n        <activity\n            android:name=\".TransactionInfoActivity\"\n            android:label=\"@string/title_activity_transaction_info\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n        <activity\n            android:name=\".ui.monitor.NetworkMonitorActivity\"\n            android:label=\"Network monitor\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n        <activity android:name=\".LicenseActivity\"\n            android:label=\"License\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n\n        <service android:name=\".SyncService\" />\n\n        <receiver android:name=\".BootReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\"/>\n            </intent-filter>\n        </receiver>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/assets/font_awesome_free.license.txt",
    "content": "SIL OPEN FONT LICENSE\n\nVersion 1.1 - 26 February 2007\nPREAMBLE\n\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\nDEFINITIONS\n\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting — in part or in whole — any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\nPERMISSION & CONDITIONS\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\nTERMINATION\n\nThis license becomes null and void if any of the above conditions are\nnot met.\nDISCLAIMER\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE."
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/assets/font_awesome_pro.license.txt",
    "content": "Fonticons, Inc., a Delaware corporation (the Company) and the company or individual buying a Font Awesome Pro license through the Web Store at fontawesome.com (the Customer) agree:\nBackground\n\nThe Company develops Font Awesome Free, a set of icons, related computer software, and other material published at github.com/FortAwesome/Font-Awesome and fontawesome.com. This license is for Font Awesome Pro, a suite of additional Pro Icons and Pro Software:\n\n    Pro Icon Packs of Pro Icons not available in Font Awesome Free, and variants of Font Awesome Free icons in different styles\n    Duotone Icons, Pro Icons that are variants of Font Awesome Free and Font Awesome Pro icons in two colors, rather than one\n    Design Plugins, Pro Software that makes using Font Awesome Free and Font Awesome Pro in graphics editing applications easier\n    Icon Subsetters, Pro Software for preparing files that contain subsets of Font Awesome Free and Font Awesome Pro icons that are more efficient to Embed\n\nLicense\nLicense Grant\n\nIn exchange for the fee the Customer owes under Payment, the Company grants the Customer a license, under all the copyrights and any patent rights the Company can license during the term of this agreement, to use Font Awesome Pro as described in What the Customer May Do, What Creators May Do, and What Creators May Not Do.\nPublic Licenses\n\nThe license granted under this agreement is in addition to, and separate from, the Company's public licenses for Font Awesome Free. This agreement and the public licenses for Font Awesome Free will be read separately, as independent legal documents.\nWhat the Customer May Do\nManage Creators\n\nThe Customer's Seat Count is the number of \"seats\" the Customer bought through the Web Store. The Customer may appoint up to that many individuals as Creators under this agreement at any given time. The Customer may remove people as Creators under this agreement, to make room for others within the Customer's Seat Count. To remove Creators, the Customer must first ensure that they stop using Pro Icons and remove copies of Pro Icons and Pro Software from their computers.\nDownload, Backup, and Share with Creators\n\nThe Customer may download Pro Icons and Pro Software from the Web Store, make backups, and share copies with their Creators.\nWhat Creators May Do\nCopy, Change, and Share with Other Creators\n\nCreators may makes copies of Pro Icons and Pro Software, make changes to Pro Icons, and share their changes with other Creators.\nEmbed in Projects\n\nCreators may Embed Pro Icons, with or without changes, in Projects. For example:\n\n    Creators may Embed Pro Icons in documents.\n    Creators may Embed Pro Icons in designs and graphic art.\n    Creators may Embed Pro Icons in websites, e-books, and apps.\n\nPass on Permission to Use Projects\n\nCreators may pass on permission to others to copy, publicly display, and perform Projects that Embed Pro Icons, as part of those Projects. For example:\n\n    Creators may Embed Pro Icons in documents.\n    Creators may Embed Pro Icons in designs and graphic art.\n    Creators may Embed Pro Icons in websites, e-books, and apps.\n\nUse Pro Software\n\nCreators may install and run Pro Software for their own use, on their own computers.\nWhat Creators May Not Do\nDistribute to Non-Creators\n\nCreators may not make, share, or publish standalone copies of Pro Icons or Pro Software for non-Creators.\nPass on Permission to Make Changes\n\nCreators may not give non-Creators permission to make changes to Pro Icons or Projects that Embed Pro Icons.\nPass on Permission to Embed\n\nCreators may not give non-Creators permission to Embed Pro Icons in new Projects of their own, or to Embed them in Projects in new ways.\nUpdates\nCoverage\n\nThis agreement covers:\n\n    currently available Pro Icons, and any new Pro Icons the Company releases as part of Font Awesome Pro during the term of this agreement.\n    current versions of Pro Software, and any new versions of Pro Software the Company releases during the term of this agreement\n\nAfter this Agreement Ends\n\nWhen this agreement ends, the Customer's license continues for versions already covered by this agreement under Updates. The Customer's license will not cover new versions released after this agreement ends. The Customer may continue to add and remove Creators under Manage Creators.\nDownloads\n\nWhile this agreement continues, the Company agrees to make the latest versions of Pro Icons and Pro Software available to download via the Web Store.\nWeb Store Credentials and Keys\n\nThe Customer agrees to keep license keys for Font Awesome Pro confidential, and to ensure that the Customer's employees, contractors, Creators, and other personnel keep them confidential, as well. The Customer agrees to keep the Customer's Web Store access credentials confidential, and to ensure that only the Customer accesses the Web Store with the Customer's credentials.\nPayment\n\nThe Customer agrees to pay the license fee for Font Awesome Pro specified via the Web Store at the time Customer entered this agreement, using a payment method accepted by the Web Store.\nTerm\n\nThis agreement will continue for the term specified via the Web Store. When that term ends, this agreement will expire.\nEnforcement\n\nIf the Company discovers reason to believe the Customer or any of their Creators has breached this agreement, the Company may terminate this agreement, restrict the Customer's ability to download Pro Icons and Pro Software from the Web Store, or both. The Company agrees to send notice to the e-mail address the Customer provided via the Web Store promptly after terminating this agreement or restricting access. These abilities do not limit the Company's ability to enforce this this agreement in other ways, such as by taking legal action.\nGuarantee\n\nThe Company guarantees that the Company has all legal rights needed to license the Pro Icons and Pro Software under this agreement.\nDisclaimer\n\nThe Company makes only the guarantee in Guarantee. Otherwise, the Company provides Font Awesome Pro entirely as is, without any warranty at all.\nLimited Damages\n\nIf the Customer takes legal action against the Company related to Font Awesome Pro, under contract law, tort law, or any other kind of law, the Customer's damages will be capped at the amount of fees the Customer actually paid the Company under this agreement.\nGeneral Contract Terms\nEntire Agreement\n\nThese are the final, complete, and only expression of our agreement about Font Awesome Pro.\nEnforcement by the Parties\n\nOnly the Customer and the Company can enforce rights under this agreement.\nAmendments\n\nWe will change or add to the terms of this agreement only by cosigning written amendments.\nNo Assignment\n\nThe Customer may not assign any right or license under this agreement. The Company may assign its rights and obligations under this agreement, as a whole, to a new legal entity created to change its jurisdiction or legal form of organization, or to an entity that acquires Company assets related to Font Awesome Pro or enough securities to control the Company's management. Any attempt to assign against the terms of this agreement will have no legal effect.\nDelaware Law\n\nThe law of the State of Delaware will govern this agreement.\nDisputes\n\nForum - The parties agree to bring any lawsuits related to this agreement in the United States District Court for the Western District of Arkansas or the state courts sitting in Bentonville, Arkansas, the Designated Courts.\n\nExclusive Jurisdiction - Each party consents to the exclusive jurisdiction of the Designated Courts, but that exclusive jurisdiction will not prohibit enforcement of any judgment obtained from Designated Courts in any other appropriate forum.\n\nInconvenient Forum Waiver - Each party waives any objection to venue for lawsuits related to this agreement in the Designated Courts, as well as any claim that a lawsuit related to this agreement in the Designated Courts is brought in an inconvenient forum."
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/assets/glyphicons_license.txt",
    "content": "Regular license\n\nThis is a legal agreement between you, the customer, and GLYPHICONS.com, the seller. By downloading icons from GLYPHICONS.com you agree to be bound by the terms of this license terms.\n\nThe license is non-exclusive, non-sublicensable and non-transferable and it is always tied with one email address, unique order ID (you may find this number in your first email with download link) and the name of the customer.\n\nCustomer can be either a natural person (individual human being) or a legal person (company/business).\n\nThis license is intended only for end customers; therefore you cannot purchase icons on behalf of someone else. GLYPHICONS.com does not cooperate with any resellers, each customer have to buy license directly.\nWhat is allowed\n\nYou may use icons in personal or commercial projects, repeatedly and you do not need to buy an extra license for every new project.\n\nEvery customer can lend icons to officially contracted employees during the time they work in your company, but you are fully responsible for how they are being used.\n\nThe price includes future updates of the product, which means that no additional purchase is required and you will receive new updates automatically in your mailbox as soon, as the new version is available.\n\nYou do not have to indicate the name of the author or giving any credits to GLYPHICONS.com, although it is always appreciated.\nWhat is not allowed\n\nYou cannot use icons in any product intended for further processing or where your customer is not a final owner. It is strictly prohibited to bundle icons in any HTML themes, frameworks, as a library of shapes/images or wherever icons would generate a significant value of the final product.\n\nAlso, it isn’t possible to use them on a product where the icons would be used repeatedly in larger series. For example as prints of t-shirts, mugs, posters or any other product which have a character of repeated production.\n\nIt is not allowed to resell the icons (license) as such, because the icons remain the intellectual property of the author.\n\nAny other use must be approved in writing. It is not possible to request any changes in this license before or after the purchase.\n\nIf customer violates any terms and conditions in this license, it will terminate this license automatically.\n\nAll icons are provided \"as they are\" without a warranty of any kind, either expressed or implied. GLYPHICONS.com is not liable for any damages or loss of profits (earnings) caused of any defects in these icon sets.\nContact\n\nIf you have any questions or need to clarify things, do not hesitate to contact me at: glyphicons@gmail.com.\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/barcodereader/BarcodeCaptureActivity.kt",
    "content": "/*\n * Copyright (C) The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * This file contains modifications by The Centure developers\n * All modifications copyright (C) The Centure developers\n */\npackage barcodereader\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.AlertDialog\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.pm.PackageManager\nimport android.graphics.Rect\nimport android.hardware.Camera\nimport android.hardware.Camera.Parameters.FLASH_MODE_OFF\nimport android.hardware.Camera.Parameters.FLASH_MODE_TORCH\nimport android.os.Bundle\nimport com.google.android.material.snackbar.Snackbar\nimport androidx.core.app.ActivityCompat\nimport androidx.appcompat.app.AppCompatActivity\nimport android.util.Log\nimport android.view.MotionEvent\nimport android.view.ScaleGestureDetector\nimport android.view.View\nimport android.widget.ImageView\nimport android.widget.Toast\n\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.GoogleApiAvailability\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.vision.Detector\nimport com.google.android.gms.vision.FocusingProcessor\nimport com.google.android.gms.vision.Tracker\nimport com.google.android.gms.vision.barcode.Barcode\nimport com.google.android.gms.vision.barcode.BarcodeDetector\nimport unity_wallet.R\nimport kotlinx.android.synthetic.main.barcode_capture.*\nimport android.os.Handler\nimport android.os.Looper\n\nimport java.io.IOException\n\n\n// Only detect barcodes that fall within our target area\nclass TargetBarcodeFocusingProcessor(preview : CameraSourcePreview, detectionBox: Rect, detector: Detector<Barcode>, tracker: Tracker<Barcode>) : FocusingProcessor<Barcode>(detector, tracker)\n{\n    private var detectionBoundingBox = detectionBox\n    private var mPreview = preview\n\n    private var widthScaleFactor = 1.0f\n    private var heightScaleFactor = 1.0f\n\n    private fun scaleX(horizontal: Int): Int\n    {\n        return (horizontal * widthScaleFactor).toInt()\n    }\n\n\n    private fun scaleY(vertical: Int): Int\n    {\n        return (vertical * heightScaleFactor).toInt()\n    }\n\n    private fun translateX(x: Int): Int\n    {\n        return scaleX(x)\n    }\n\n    private fun translateY(y: Int): Int\n    {\n        return scaleY(y)\n    }\n\n    override fun selectFocus(detections: Detector.Detections<Barcode>?): Int\n    {\n        val barcodes = detections?.detectedItems\n        heightScaleFactor = mPreview.previewHeight / (detections?.frameMetadata?.height)?.toFloat()!!\n        widthScaleFactor = mPreview.previewWidth / (detections.frameMetadata.width).toFloat()\n\n        for (i in 0 .. barcodes!!.size())\n        {\n            val barcodeID = barcodes.keyAt(i)\n            val barcode = barcodes.get(barcodeID)\n            val barcodeBoundingBox = barcode.boundingBox\n            barcodeBoundingBox.top = translateY(barcodeBoundingBox.top)\n            barcodeBoundingBox.bottom = translateY(barcodeBoundingBox.bottom)\n            barcodeBoundingBox.left = translateX(barcodeBoundingBox.left)\n            barcodeBoundingBox.right = translateX(barcodeBoundingBox.right)\n            if (detectionBoundingBox.intersect(barcodeBoundingBox))\n            {\n                return barcodeID\n            }\n        }\n        return -1\n    }\n}\n\n/**\n * Activity for barcode scanning.This app detects barcodes with the\n * rear facing camera.\n */\nclass BarcodeCaptureActivity : AppCompatActivity(), BarcodeTracker.BarcodeUpdateListener\n{\n    private var mCameraSource: CameraSource? = null\n    private var mPreview: CameraSourcePreview? = null\n    private var mTargetOverlay: ImageView? = null\n    private var mProcessor: TargetBarcodeFocusingProcessor? = null\n    private var mUseFlash : Boolean = false\n    private var mAutoFocus : Boolean = false\n\n    // helper objects for detecting taps and pinches.\n    private var scaleGestureDetector: ScaleGestureDetector? = null\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    /**\n     * Initializes the UI and creates the detector pipeline.\n     */\n    public override fun onCreate(icicle: Bundle?)\n    {\n        super.onCreate(icicle)\n        setContentView(R.layout.barcode_capture)\n\n        mPreview = findViewById<View>(R.id.preview) as CameraSourcePreview\n        mTargetOverlay = findViewById<View>(R.id.scanTargetOverlayImage) as ImageView\n\n        // read parameters from the intent used to launch the activity.\n        mAutoFocus = intent.getBooleanExtra(AutoFocus, false)\n        mUseFlash = intent.getBooleanExtra(UseFlash, false)\n\n        scanCancelButton.setOnClickListener { finish() }\n        scanToggleFlashButton.setOnClickListener { mUseFlash = !mUseFlash; mCameraSource?.setFlashMode(if (mUseFlash) {FLASH_MODE_TORCH} else { FLASH_MODE_OFF}) }\n\n\n        // Below relies on sizing of view items so can only run after the view is visible\n        handler.post {\n            // Check for the camera permission before accessing the camera.  If the  permission is not granted yet, request permission.\n            val rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)\n            if (rc == PackageManager.PERMISSION_GRANTED)\n            {\n                createCameraSource(mAutoFocus, mUseFlash)\n                startCameraSource()\n            }\n            else\n            {\n                requestCameraPermission()\n            }\n        }\n\n        scaleGestureDetector = ScaleGestureDetector(this, ScaleListener())\n\n        Snackbar.make(mPreview!!, \"Pinch/Stretch to zoom\", Snackbar.LENGTH_LONG).show()\n    }\n\n    /**\n     * Handles the requesting of the camera permission.  This includes\n     * showing a \"Snackbar\" message of why the permission is needed then\n     * sending the request.\n     */\n    private fun requestCameraPermission()\n    {\n        Log.w(TAG, \"Camera permission is not granted. Requesting permission\")\n\n        val permissions = arrayOf(Manifest.permission.CAMERA)\n\n        if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA))\n        {\n            ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM)\n            return\n        }\n\n        val thisActivity = this\n\n        val listener = View.OnClickListener {\n            ActivityCompat.requestPermissions(thisActivity, permissions, RC_HANDLE_CAMERA_PERM)\n        }\n\n        findViewById<View>(R.id.topLayout).setOnClickListener(listener)\n        Snackbar.make(mPreview!!, \"Camera permission required to scan QR code\", Snackbar.LENGTH_INDEFINITE).setAction(\"ok\", listener).show()\n    }\n\n    override fun onTouchEvent(e: MotionEvent): Boolean\n    {\n        if (scaleGestureDetector!!.onTouchEvent(e))\n            return true\n\n        return super.onTouchEvent(e)\n    }\n\n    /**\n     * Creates and starts the camera.  Note that this uses a higher resolution in comparison\n     * to other detection examples to enable the barcode detector to detect small barcodes\n     * at long distances.\n     *\n     * Suppressing InlinedApi since there is a check that the minimum version is met before using\n     * the constant.\n     */\n    @SuppressLint(\"InlinedApi\")\n    private fun createCameraSource(autoFocus: Boolean, useFlash: Boolean)\n    {\n        val context = applicationContext\n\n        // A barcode detector is created to track barcodes.\n        //  An associated focusing-processor instance  is set to receive the barcode detection results, track the barcodes, and maintain\n        // graphics for each barcode on screen.  The factory is used by the multi-processor to\n        // create a separate tracker instance for each barcode.\n        val barcodeDetector = BarcodeDetector.Builder(context).build()\n        val tracker = BarcodeTracker(this)\n\n        val targetOverlayRect = Rect()\n        mTargetOverlay!!.getGlobalVisibleRect(targetOverlayRect)\n\n        mProcessor = TargetBarcodeFocusingProcessor(mPreview!!, targetOverlayRect, barcodeDetector, tracker)\n        barcodeDetector.setProcessor(mProcessor)\n\n        if (!barcodeDetector.isOperational)\n        {\n            // Note: The first time that an app using the barcode or face API is installed on a\n            // device, GMS will download a native libraries to the device in order to do detection.\n            // Usually this completes before the app is run for the first time.  But if that\n            // download has not yet completed, then the above call will not detect any barcodes\n            // and/or faces.\n            //\n            // isOperational() can be used to check if the required native libraries are currently\n            // available.  The detectors will automatically become operational once the library\n            // downloads complete on device.\n            Log.w(TAG, \"Detector dependencies are not yet available.\")\n\n            // Check for low storage.  If there is low storage, the native library will not be\n            // downloaded, so detection will not become operational.\n            val lowstorageFilter = IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW)\n            val hasLowStorage = registerReceiver(null, lowstorageFilter) != null\n\n            if (hasLowStorage)\n            {\n                Toast.makeText(this, \"No space available to install qr code scanner\", Toast.LENGTH_LONG).show()\n                Log.w(TAG, \"No space available to install qr code scanner\")\n            }\n        }\n\n        // Creates and starts the camera.  Note that this uses a higher resolution in comparison\n        // to other detection examples to enable the barcode detector to detect small barcodes\n        // at long distances.\n        var builder = CameraSource.Builder(applicationContext, barcodeDetector).setFacing(CameraSource.CAMERA_FACING_BACK).setRequestedPreviewSize(1600, 1024).setRequestedFps(15.0f)\n\n        if (autoFocus)\n            builder = builder.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)\n\n        if (useFlash)\n            builder.setFlashMode(FLASH_MODE_TORCH)\n\n        mCameraSource = builder.build()\n    }\n\n    /**\n     * Restarts the camera.\n     */\n    override fun onResume()\n    {\n        super.onResume()\n        startCameraSource()\n    }\n\n    /**\n     * Stops the camera.\n     */\n    override fun onPause()\n    {\n        super.onPause()\n        if (mPreview != null)\n        {\n            mPreview?.stop()\n        }\n    }\n\n    /**\n     * Releases the resources associated with the camera source, the associated detectors, and the\n     * rest of the processing pipeline.\n     */\n    override fun onDestroy()\n    {\n        super.onDestroy()\n        if (mPreview != null)\n        {\n            mPreview?.release()\n        }\n    }\n\n    // Handle camera permissions for scanning.\n    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray)\n    {\n        if (requestCode != RC_HANDLE_CAMERA_PERM)\n        {\n            Log.d(TAG, \"Got unexpected permission result: $requestCode\")\n            super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n            return\n        }\n\n        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)\n        {\n            Log.d(TAG, \"Camera permission granted - initialize the camera source\")\n            // we have permission, so create the camerasource\n            createCameraSource(mAutoFocus, mUseFlash)\n            startCameraSource()\n            return\n        }\n\n        Log.e(TAG, \"Permission not granted: results len = \" + grantResults.size + \" Result code = \" + if (grantResults.isNotEmpty()) grantResults[0] else \"(empty)\")\n\n        val listener = DialogInterface.OnClickListener { _, id -> finish() }\n\n        val builder = AlertDialog.Builder(this)\n        builder.setTitle(\"Munt\").setMessage(\"Unable to get camera permission\").setPositiveButton(\"ok\", listener).show()\n    }\n\n    /**\n     * Starts or restarts the camera source, if it exists.  If the camera source doesn't exist yet\n     * (e.g., because onResume was called before the camera source was created), this will be called\n     * again when the camera source is created.\n     */\n    @Throws(SecurityException::class)\n    private fun startCameraSource()\n    {\n        // check that the device has play services available.\n        val code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(applicationContext)\n        if (code != ConnectionResult.SUCCESS)\n        {\n            val dlg = GoogleApiAvailability.getInstance().getErrorDialog(this, code, RC_HANDLE_GMS)\n            dlg.show()\n        }\n\n        if (mCameraSource != null)\n        {\n            try\n            {\n                mPreview?.start(mCameraSource as CameraSource)\n            }\n            catch (e: IOException)\n            {\n                Log.e(TAG, \"Unable to start camera source.\", e)\n                mCameraSource?.release()\n                mCameraSource = null\n            }\n\n        }\n    }\n\n    private inner class ScaleListener : ScaleGestureDetector.OnScaleGestureListener\n    {\n        override fun onScale(detector: ScaleGestureDetector): Boolean\n        {\n            return false\n        }\n\n        override fun onScaleBegin(detector: ScaleGestureDetector): Boolean\n        {\n            return true\n        }\n\n        override fun onScaleEnd(detector: ScaleGestureDetector)\n        {\n            mCameraSource?.doZoom(detector.scaleFactor)\n        }\n    }\n\n    override fun onBarcodeDetected(barcode: Barcode?)\n    {\n        val data = Intent()\n        data.putExtra(BarcodeObject, barcode)\n        setResult(CommonStatusCodes.SUCCESS, data)\n        finish()\n    }\n\n    companion object\n    {\n        private const val TAG = \"Barcode-reader\"\n\n        // intent request code to handle updating play services if needed.\n        private const val RC_HANDLE_GMS = 9001\n\n        // permission request codes need to be < 256\n        private  const val RC_HANDLE_CAMERA_PERM = 2\n\n        // constants used to pass extra data in the intent\n        const val AutoFocus = \"AutoFocus\"\n        const val UseFlash = \"UseFlash\"\n        const val BarcodeObject = \"Barcode\"\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/barcodereader/BarcodeTracker.kt",
    "content": "/*\n * Copyright (C) The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * This file contains modifications by The Centure developers\n * All modifications copyright (C) The Centure developers\n */\npackage barcodereader\n\nimport android.content.Context\nimport androidx.annotation.UiThread\n\nimport com.google.android.gms.vision.Tracker\nimport com.google.android.gms.vision.barcode.Barcode\n\n\n// Monitor for new barcode detections and alert via BarcodeUpdateListener interface.\nclass BarcodeTracker internal constructor(context: Context) : Tracker<Barcode>()\n{\n\n    private var mBarcodeUpdateListener: BarcodeUpdateListener? = null\n\n    interface BarcodeUpdateListener\n    {\n        @UiThread\n        fun onBarcodeDetected(barcode: Barcode?)\n    }\n\n    init\n    {\n        if (context is BarcodeUpdateListener)\n        {\n            this.mBarcodeUpdateListener = context\n        }\n        else\n        {\n            throw RuntimeException(\"Hosting activity must implement BarcodeUpdateListener\")\n        }\n    }\n\n    override fun onNewItem(id: Int, item: Barcode?)\n    {\n        mBarcodeUpdateListener?.onBarcodeDetected(item)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/barcodereader/CameraSource.kt",
    "content": "/*\n * Copyright (C) The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * This file contains modifications by The Centure developers\n * All modifications copyright (C) The Centure developers\n */\npackage barcodereader\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.annotation.TargetApi\nimport android.content.Context\nimport android.graphics.ImageFormat\nimport android.hardware.Camera\nimport android.hardware.Camera.CameraInfo\nimport android.os.Build\nimport android.os.SystemClock\nimport android.util.Log\nimport android.view.Surface\nimport android.view.TextureView\nimport android.view.WindowManager\nimport androidx.annotation.RequiresPermission\nimport androidx.annotation.StringDef\nimport com.google.android.gms.common.images.Size\nimport com.google.android.gms.vision.Detector\nimport com.google.android.gms.vision.Frame\nimport java.io.IOException\nimport java.lang.Thread.State\nimport java.lang.annotation.Retention\nimport java.lang.annotation.RetentionPolicy\nimport java.nio.ByteBuffer\nimport java.util.*\n\n// Note: This requires Google Play Services 8.1 or higher, due to using indirect byte buffers for\n// storing images.\n\n/**\n * Manages the camera in conjunction with an underlying\n * [com.google.android.gms.vision.Detector].  This receives preview frames from the camera at\n * a specified rate, sending those frames to the detector as fast as it is able to process those\n * frames.\n *\n *\n * This camera source makes a best effort to manage processing on preview frames as fast as\n * possible, while at the same time minimizing lag.  As such, frames may be dropped if the detector\n * is unable to keep up with the rate of frames generated by the camera.  You should use\n * [CameraSource.Builder.setRequestedFps] to specify a frame rate that works well with\n * the capabilities of the camera hardware and the detector options that you have selected.  If CPU\n * utilization is higher than you'd like, then you may want to consider reducing FPS.  If the camera\n * preview or detector results are too \"jerky\", then you may want to consider increasing FPS.\n *\n *\n * The following Android permission is required to use the camera:\n *\n *  * android.permissions.CAMERA\n *\n */\nclass CameraSource\n//==============================================================================================\n// Private\n//==============================================================================================\n\n/**\n * Only allow creation via the builder class.\n */\nprivate constructor()\n{\n\n    private var mContext: Context? = null\n\n    private val mCameraLock = Any()\n\n    // Guarded by mCameraLock\n    private var mCamera: Camera? = null\n\n    /**\n     * Returns the selected camera; one of [.CAMERA_FACING_BACK] or\n     * [.CAMERA_FACING_FRONT].\n     */\n    var cameraFacing = CAMERA_FACING_BACK\n        private set\n\n    /**\n     * Rotation of the device, and thus the associated preview images captured from the device.\n     * See [Frame.Metadata.getRotation].\n     */\n    private var mRotation: Int = 0\n\n    /**\n     * Returns the preview size that is currently in use by the underlying camera.\n     */\n    var previewSize: Size? = null\n        private set\n\n    // These values may be requested by the caller.  Due to hardware limitations, we may need to\n    // select close, but not exactly the same values for these.\n    private var mRequestedFps = 30.0f\n    private var mRequestedPreviewWidth = 1024\n    private var mRequestedPreviewHeight = 768\n\n\n    private var mFocusMode: String? = null\n    private var mFlashMode: String? = null\n\n        /**\n     * Dedicated thread and associated runnable for calling into the detector with frames, as the\n     * frames become available from the camera.\n     */\n    private var mProcessingThread: Thread? = null\n    private var mFrameProcessor: FrameProcessingRunnable? = null\n\n    /**\n     * Map to convert between a byte array, received from the camera, and its associated byte\n     * buffer.  We use byte buffers internally because this is a more efficient way to call into\n     * native code later (avoids a potential copy).\n     */\n    private val mBytesToByteBuffer = HashMap<ByteArray, ByteBuffer>()\n\n    @StringDef(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE, Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, Camera.Parameters.FOCUS_MODE_AUTO, Camera.Parameters.FOCUS_MODE_EDOF, Camera.Parameters.FOCUS_MODE_FIXED, Camera.Parameters.FOCUS_MODE_INFINITY, Camera.Parameters.FOCUS_MODE_MACRO)\n    @Retention(RetentionPolicy.SOURCE)\n    private annotation class FocusMode\n\n    @StringDef(Camera.Parameters.FLASH_MODE_ON, Camera.Parameters.FLASH_MODE_OFF, Camera.Parameters.FLASH_MODE_AUTO, Camera.Parameters.FLASH_MODE_RED_EYE, Camera.Parameters.FLASH_MODE_TORCH)\n    @Retention(RetentionPolicy.SOURCE)\n    private annotation class FlashMode\n\n    //==============================================================================================\n    // Builder\n    //==============================================================================================\n\n    /**\n     * Builder for configuring and creating an associated camera source.\n     */\n    class Builder\n    /**\n     * Creates a camera source builder with the supplied context and detector.  Camera preview\n     * images will be streamed to the associated detector upon starting the camera source.\n     */\n    (context: Context?, private val mDetector: Detector<*>?)\n    {\n        private val mCameraSource = CameraSource()\n\n        init\n        {\n            if (context == null)\n            {\n                throw IllegalArgumentException(\"No context supplied.\")\n            }\n            if (mDetector == null)\n            {\n                throw IllegalArgumentException(\"No detector supplied.\")\n            }\n            mCameraSource.mContext = context\n        }\n\n        /**\n         * Sets the requested frame rate in frames per second.  If the exact requested value is not\n         * not available, the best matching available value is selected.   Default: 30.\n         */\n        fun setRequestedFps(fps: Float): Builder\n        {\n            if (fps <= 0)\n            {\n                throw IllegalArgumentException(\"Invalid fps: $fps\")\n            }\n            mCameraSource.mRequestedFps = fps\n            return this\n        }\n\n        fun setFocusMode(@FocusMode mode: String): Builder\n        {\n            mCameraSource.mFocusMode = mode\n            return this\n        }\n\n        fun setFlashMode(@FlashMode mode: String): Builder\n        {\n            mCameraSource.mFlashMode = mode\n            return this\n        }\n\n        /**\n         * Sets the desired width and height of the camera frames in pixels.  If the exact desired\n         * values are not available options, the best matching available options are selected.\n         * Also, we try to select a preview size which corresponds to the aspect ratio of an\n         * associated full picture size, if applicable.  Default: 1024x768.\n         */\n        fun setRequestedPreviewSize(width: Int, height: Int): Builder\n        {\n            // Restrict the requested range to something within the realm of possibility.  The\n            // choice of 1000000 is a bit arbitrary -- intended to be well beyond resolutions that\n            // devices can support.  We bound this to avoid int overflow in the code later.\n            val maxPreviewSize = 1000000\n            if (width <= 0 || width > maxPreviewSize || height <= 0 || height > maxPreviewSize)\n            {\n                throw IllegalArgumentException(\"Invalid preview size: \" + width + \"x\" + height)\n            }\n            mCameraSource.mRequestedPreviewWidth = width\n            mCameraSource.mRequestedPreviewHeight = height\n            return this\n        }\n\n        /**\n         * Sets the camera to use (either [.CAMERA_FACING_BACK] or\n         * [.CAMERA_FACING_FRONT]). Default: back facing.\n         */\n        fun setFacing(facing: Int): Builder\n        {\n            if (facing != CAMERA_FACING_BACK && facing != CAMERA_FACING_FRONT)\n            {\n                throw IllegalArgumentException(\"Invalid camera: $facing\")\n            }\n            mCameraSource.cameraFacing = facing\n            return this\n        }\n\n        /**\n         * Creates an instance of the camera source.\n         */\n        fun build(): CameraSource\n        {\n            mCameraSource.mFrameProcessor = mCameraSource.FrameProcessingRunnable(mDetector)\n            return mCameraSource\n        }\n    }\n\n    //==============================================================================================\n    // Bridge Functionality for the Camera1 API\n    //==============================================================================================\n\n    /**\n     * Callback interface used to signal the moment of actual image capture.\n     */\n    interface ShutterCallback\n    {\n        /**\n         * Called as near as possible to the moment when a photo is captured from the sensor. This\n         * is a good opportunity to play a shutter sound or give other feedback of camera operation.\n         * This may be some time after the photo was triggered, but some time before the actual data\n         * is available.\n         */\n        fun onShutter()\n    }\n\n    /**\n     * Callback interface used to supply image data from a photo capture.\n     */\n    interface PictureCallback\n    {\n        /**\n         * Called when image data is available after a picture is taken.  The format of the data\n         * is a jpeg binary.\n         */\n        fun onPictureTaken(data: ByteArray)\n    }\n\n    /**\n     * Callback interface used to notify on completion of camera auto focus.\n     */\n    interface AutoFocusCallback\n    {\n        /**\n         * Called when the camera auto focus completes.  If the camera\n         * does not support auto-focus and autoFocus is called,\n         * onAutoFocus will be called immediately with a fake value of\n         * `success` set to `true`.\n         *\n         *\n         * The auto-focus routine does not lock auto-exposure and auto-white\n         * balance after it completes.\n         *\n         * @param success true if focus was successful, false if otherwise\n         */\n        fun onAutoFocus(success: Boolean)\n    }\n\n    /**\n     * Callback interface used to notify on auto focus start and stop.\n     *\n     *\n     *\n     * This is only supported in continuous autofocus modes -- [ ][Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO] and [ ][Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE]. Applications can show\n     * autofocus animation based on this.\n     */\n    interface AutoFocusMoveCallback\n    {\n        /**\n         * Called when the camera auto focus starts or stops.\n         *\n         * @param start true if focus starts to move, false if focus stops to move\n         */\n        fun onAutoFocusMoving(start: Boolean)\n    }\n\n    //==============================================================================================\n    // Public\n    //==============================================================================================\n\n    /**\n     * Stops the camera and releases the resources of the camera and underlying detector.\n     */\n    fun release()\n    {\n        synchronized(mCameraLock) {\n            stop()\n            mFrameProcessor?.release()\n        }\n    }\n\n\n    /**\n     * Opens the camera and starts sending preview frames to the underlying detector.  The supplied\n     * texture view is used for the preview so frames can be displayed to the user.\n     *\n     * @param textureView the texture view to use for the preview frames\n     * @throws IOException if the supplied surface holder could not be used as the preview display\n     */\n    @RequiresPermission(Manifest.permission.CAMERA)\n    @Throws(IOException::class)\n    fun start(textureView : TextureView): CameraSource\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null)\n            {\n                return this\n            }\n\n            mCamera = createCamera()\n            mCamera?.setPreviewTexture(textureView.surfaceTexture)\n            mCamera?.startPreview()\n\n            mProcessingThread = Thread(mFrameProcessor)\n            mFrameProcessor?.setActive(true)\n            mProcessingThread?.start()\n        }\n        return this\n    }\n\n\n\n    /**\n     * Closes the camera and stops sending frames to the underlying frame detector.\n     *\n     *\n     * This camera source may be restarted again by calling [.start] or\n     * [.start].\n     *\n     *\n     * Call [.release] instead to completely shut down this camera source and release the\n     * resources of the underlying detector.\n     */\n    fun stop()\n    {\n        synchronized(mCameraLock) {\n            mFrameProcessor?.setActive(false)\n            if (mProcessingThread != null)\n            {\n                try\n                {\n                    // Wait for the thread to complete to ensure that we can't have multiple threads\n                    // executing at the same time (i.e., which would happen if we called start too\n                    // quickly after stop).\n                    mProcessingThread?.join()\n                }\n                catch (e: InterruptedException)\n                {\n                    Log.d(TAG, \"Frame processing thread interrupted on release.\")\n                }\n\n                mProcessingThread = null\n            }\n\n            // clear the buffer to prevent oom exceptions\n            mBytesToByteBuffer.clear()\n\n            if (mCamera != null)\n            {\n                mCamera?.stopPreview()\n                mCamera?.setPreviewCallbackWithBuffer(null)\n                try\n                {\n                    mCamera?.setPreviewTexture(null)\n                }\n                catch (e: Exception)\n                {\n                    Log.e(TAG, \"Failed to clear camera preview: $e\")\n                }\n\n                mCamera?.release()\n                mCamera = null\n            }\n        }\n    }\n\n    fun doZoom(scale: Float): Int\n    {\n        synchronized(mCameraLock) {\n            if (mCamera == null)\n            {\n                return 0\n            }\n            var currentZoom = 0\n            val maxZoom: Int\n            val parameters = mCamera?.parameters\n            if (!parameters!!.isZoomSupported)\n            {\n                Log.w(TAG, \"Zoom is not supported on this device\")\n                return currentZoom\n            }\n            maxZoom = parameters.maxZoom\n\n            currentZoom = parameters.zoom + 1\n            val newZoom: Float\n            newZoom = if (scale > 1)\n            {\n                currentZoom + scale * (maxZoom / 10)\n            }\n            else\n            {\n                currentZoom * scale\n            }\n            currentZoom = Math.round(newZoom) - 1\n            if (currentZoom < 0)\n            {\n                currentZoom = 0\n            }\n            else if (currentZoom > maxZoom)\n            {\n                currentZoom = maxZoom\n            }\n            parameters.zoom = currentZoom\n            mCamera?.parameters = parameters\n            return currentZoom\n        }\n    }\n\n\n\n    /**\n     * Gets the current focus mode setting.\n     *\n     * @return current focus mode. This value is null if the camera is not yet created. Applications should call [ ][.autoFocus] to start the focus if focus\n     * mode is FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.\n     */\n    @FocusMode\n    fun getFocusMode(): String?\n    {\n        return mFocusMode\n    }\n\n    /**\n     * Sets the focus mode.\n     *\n     * @param mode the focus mode\n     * @return `true` if the focus mode is set, `false` otherwise\n     * @see .getFocusMode\n     */\n    fun setFocusMode(@FocusMode mode: String?): Boolean\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null && mode != null)\n            {\n                val parameters = mCamera?.parameters\n                if (parameters?.supportedFocusModes!!.contains(mode))\n                {\n                    parameters.focusMode = mode\n                    mCamera?.parameters = parameters\n                    mFocusMode = mode\n                    return true\n                }\n            }\n\n            return false\n        }\n    }\n\n    /**\n     * Gets the current flash mode setting.\n     *\n     * @return current flash mode. null if flash mode setting is not\n     * supported or the camera is not yet created.\n     * @see Camera.Parameters.FLASH_MODE_OFF\n     *\n     * @see Camera.Parameters.FLASH_MODE_AUTO\n     *\n     * @see Camera.Parameters.FLASH_MODE_ON\n     *\n     * @see Camera.Parameters.FLASH_MODE_RED_EYE\n     *\n     * @see Camera.Parameters.FLASH_MODE_TORCH\n     */\n    @FlashMode\n    fun getFlashMode(): String?\n    {\n        return mFlashMode\n    }\n\n    /**\n     * Sets the flash mode.\n     *\n     * @param mode flash mode.\n     * @return `true` if the flash mode is set, `false` otherwise\n     * @see .getFlashMode\n     */\n    fun setFlashMode(@FlashMode mode: String?): Boolean\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null && mode != null)\n            {\n                val parameters = mCamera?.parameters\n                if (parameters?.supportedFlashModes!!.contains(mode))\n                {\n                    parameters.flashMode = mode\n                    mCamera?.parameters = parameters\n                    mFlashMode = mode\n                    return true\n                }\n            }\n\n            return false\n        }\n    }\n\n    /**\n     * Starts camera auto-focus and registers a callback function to run when\n     * the camera is focused.  This method is only valid when preview is active\n     * (between [.start] or [.start] and before [.stop] or [.release]).\n     *\n     *\n     *\n     * Callers should check\n     * [.getFocusMode] to determine if\n     * this method should be called. If the camera does not support auto-focus,\n     * it is a no-op and [AutoFocusCallback.onAutoFocus]\n     * callback will be called immediately.\n     *\n     *\n     *\n     * If the current flash mode is not\n     * [Camera.Parameters.FLASH_MODE_OFF], flash may be\n     * fired during auto-focus, depending on the driver and camera hardware.\n     *\n     *\n     *\n     * @param cb the callback to run\n     * @see .cancelAutoFocus\n     */\n    fun autoFocus(cb: AutoFocusCallback?)\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null)\n            {\n                var autoFocusCallback: CameraAutoFocusCallback? = null\n                if (cb != null)\n                {\n                    autoFocusCallback = CameraAutoFocusCallback()\n                    autoFocusCallback.mDelegate = cb\n                }\n                mCamera?.autoFocus(autoFocusCallback)\n            }\n        }\n    }\n\n    /**\n     * Cancels any auto-focus function in progress.\n     * Whether or not auto-focus is currently in progress,\n     * this function will return the focus position to the default.\n     * If the camera does not support auto-focus, this is a no-op.\n     *\n     * @see .autoFocus\n     */\n    fun cancelAutoFocus()\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null)\n            {\n                mCamera?.cancelAutoFocus()\n            }\n        }\n    }\n\n    /**\n     * Sets camera auto-focus move callback.\n     *\n     * @param cb the callback to run\n     * @return `true` if the operation is supported (i.e. from Jelly Bean), `false` otherwise\n     */\n    fun setAutoFocusMoveCallback(cb: AutoFocusMoveCallback?): Boolean\n    {\n        synchronized(mCameraLock) {\n            if (mCamera != null)\n            {\n                var autoFocusMoveCallback: CameraAutoFocusMoveCallback? = null\n                if (cb != null)\n                {\n                    autoFocusMoveCallback = CameraAutoFocusMoveCallback()\n                    autoFocusMoveCallback.mDelegate = cb\n                }\n                mCamera?.setAutoFocusMoveCallback(autoFocusMoveCallback)\n            }\n        }\n\n        return true\n    }\n\n    /**\n     * Wraps the camera1 auto focus callback so that the deprecated API isn't exposed.\n     */\n    private inner class CameraAutoFocusCallback : Camera.AutoFocusCallback\n    {\n        var mDelegate: AutoFocusCallback? = null\n\n        override fun onAutoFocus(success: Boolean, camera: Camera)\n        {\n            mDelegate?.onAutoFocus(success)\n        }\n    }\n\n    /**\n     * Wraps the camera1 auto focus move callback so that the deprecated API isn't exposed.\n     */\n    private inner class CameraAutoFocusMoveCallback : Camera.AutoFocusMoveCallback\n    {\n        var mDelegate: AutoFocusMoveCallback? = null\n\n        override fun onAutoFocusMoving(start: Boolean, camera: Camera)\n        {\n            mDelegate?.onAutoFocusMoving(start)\n        }\n    }\n\n    /**\n     * Opens the camera and applies the user settings.\n     *\n     * @throws RuntimeException if the method fails\n     */\n    @SuppressLint(\"InlinedApi\")\n    private fun createCamera(): Camera\n    {\n        val requestedCameraId = getIdForRequestedCamera(cameraFacing)\n        if (requestedCameraId == -1)\n        {\n            throw RuntimeException(\"Could not find requested camera.\")\n        }\n        val camera = Camera.open(requestedCameraId)\n\n        val sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight) ?: throw RuntimeException(\"Could not find suitable preview size.\")\n        val pictureSize = sizePair.pictureSize()\n        previewSize = sizePair.previewSize()\n\n        val previewFpsRange = selectPreviewFpsRange(camera, mRequestedFps) ?: throw RuntimeException(\"Could not find suitable preview frames per second range.\")\n\n        val parameters = camera.parameters\n\n        if (pictureSize != null)\n        {\n            parameters.setPictureSize(pictureSize.width, pictureSize.height)\n        }\n\n        parameters.setPreviewSize(previewSize!!.width, previewSize!!.height)\n        parameters.setPreviewFpsRange(previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX])\n        parameters.previewFormat = ImageFormat.NV21\n\n        setRotation(camera, parameters, requestedCameraId)\n\n        if (mFocusMode != null)\n        {\n            if (parameters.supportedFocusModes.contains(mFocusMode))\n            {\n                parameters.focusMode = mFocusMode\n            }\n            else\n            {\n                Log.i(TAG, \"Camera focus mode: $mFocusMode is not supported on this device.\")\n            }\n        }\n\n        // setting mFocusMode to the one set in the params\n        mFocusMode = parameters.focusMode\n\n        if (mFlashMode != null)\n        {\n            if (parameters.supportedFlashModes != null)\n            {\n                if (parameters.supportedFlashModes.contains(mFlashMode))\n                {\n                    parameters.flashMode = mFlashMode\n                }\n                else\n                {\n                    Log.i(TAG, \"Camera flash mode: $mFlashMode is not supported on this device.\")\n                }\n            }\n        }\n\n        // setting mFlashMode to the one set in the params\n        mFlashMode = parameters.flashMode\n\n        camera.parameters = parameters\n\n        // Four frame buffers are needed for working with the camera:\n        //\n        //   one for the frame that is currently being executed upon in doing detection\n        //   one for the next pending frame to process immediately upon completing detection\n        //   two for the frames that the camera uses to populate future preview images\n        camera.setPreviewCallbackWithBuffer(CameraPreviewCallback())\n        camera.addCallbackBuffer(createPreviewBuffer(previewSize!!))\n        camera.addCallbackBuffer(createPreviewBuffer(previewSize!!))\n        camera.addCallbackBuffer(createPreviewBuffer(previewSize!!))\n        camera.addCallbackBuffer(createPreviewBuffer(previewSize!!))\n\n        return camera\n    }\n\n    /**\n     * Stores a preview size and a corresponding same-aspect-ratio picture size.  To avoid distorted\n     * preview images on some devices, the picture size must be set to a size that is the same\n     * aspect ratio as the preview size or the preview may end up being distorted.  If the picture\n     * size is null, then there is no picture size with the same aspect ratio as the preview size.\n     */\n    private class SizePair(previewSize: Camera.Size, pictureSize: Camera.Size?)\n    {\n        private val mPreview: Size = Size(previewSize.width, previewSize.height)\n        private var mPicture: Size? = null\n\n        init\n        {\n            if (pictureSize != null)\n            {\n                mPicture = Size(pictureSize.width, pictureSize.height)\n            }\n        }\n\n        fun previewSize(): Size\n        {\n            return mPreview\n        }\n\n        fun pictureSize(): Size?\n        {\n            return mPicture\n        }\n    }\n\n    /**\n     * Selects the most suitable preview frames per second range, given the desired frames per\n     * second.\n     *\n     * @param camera            the camera to select a frames per second range from\n     * @param desiredPreviewFps the desired frames per second for the camera preview frames\n     * @return the selected preview frames per second range\n     */\n    private fun selectPreviewFpsRange(camera: Camera, desiredPreviewFps: Float): IntArray?\n    {\n        // The camera API uses integers scaled by a factor of 1000 instead of floating-point frame\n        // rates.\n        val desiredPreviewFpsScaled = (desiredPreviewFps * 1000.0f).toInt()\n\n        // The method for selecting the best range is to minimize the sum of the differences between\n        // the desired value and the upper and lower bounds of the range.  This may select a range\n        // that the desired value is outside of, but this is often preferred.  For example, if the\n        // desired frame rate is 29.97, the range (30, 30) is probably more desirable than the\n        // range (15, 30).\n        var selectedFpsRange: IntArray? = null\n        var minDiff = Integer.MAX_VALUE\n        val previewFpsRangeList = camera.parameters.supportedPreviewFpsRange\n        for (range in previewFpsRangeList)\n        {\n            val deltaMin = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]\n            val deltaMax = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]\n            val diff = Math.abs(deltaMin) + Math.abs(deltaMax)\n            if (diff < minDiff)\n            {\n                selectedFpsRange = range\n                minDiff = diff\n            }\n        }\n        return selectedFpsRange\n    }\n\n    /**\n     * Calculates the correct rotation for the given camera id and sets the rotation in the\n     * parameters.  It also sets the camera's display orientation and rotation.\n     *\n     * @param parameters the camera parameters for which to set the rotation\n     * @param cameraId   the camera id to set rotation based on\n     */\n    private fun setRotation(camera: Camera, parameters: Camera.Parameters, cameraId: Int)\n    {\n        val windowManager = mContext!!.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n        var degrees = 0\n        when (val rotation = windowManager.defaultDisplay.rotation)\n        {\n            Surface.ROTATION_0 -> degrees = 0\n            Surface.ROTATION_90 -> degrees = 90\n            Surface.ROTATION_180 -> degrees = 180\n            Surface.ROTATION_270 -> degrees = 270\n            else -> Log.e(TAG, \"Bad rotation value: $rotation\")\n        }\n\n        val cameraInfo = CameraInfo()\n        Camera.getCameraInfo(cameraId, cameraInfo)\n\n        val angle: Int\n        val displayAngle: Int\n        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT)\n        {\n            angle = (cameraInfo.orientation + degrees) % 360\n            displayAngle = (360 - angle) % 360 // compensate for it being mirrored\n        }\n        else\n        {  // back-facing\n            angle = (cameraInfo.orientation - degrees + 360) % 360\n            displayAngle = angle\n        }\n\n        // This corresponds to the rotation constants in {@link Frame}.\n        mRotation = angle / 90\n\n        camera.setDisplayOrientation(displayAngle)\n        parameters.setRotation(angle)\n    }\n\n    /**\n     * Creates one buffer for the camera preview callback.  The size of the buffer is based off of\n     * the camera preview size and the format of the camera image.\n     *\n     * @return a new preview buffer of the appropriate size for the current camera settings\n     */\n    private fun createPreviewBuffer(previewSize: Size): ByteArray\n    {\n        val bitsPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.NV21)\n        val sizeInBits = (previewSize.height * previewSize.width * bitsPerPixel).toLong()\n        val bufferSize = Math.ceil(sizeInBits / 8.0).toInt() + 1\n\n        //\n        // NOTICE: This code only works when using play services v. 8.1 or higher.\n        //\n\n        // Creating the byte array this way and wrapping it, as opposed to using .allocate(),\n        // should guarantee that there will be an array to work with.\n        val byteArray = ByteArray(bufferSize)\n        val buffer = ByteBuffer.wrap(byteArray)\n        if (!buffer.hasArray() || !buffer.array().contentEquals(byteArray))\n        {\n            // I don't think that this will ever happen.  But if it does, then we wouldn't be\n            // passing the preview content to the underlying detector later.\n            throw IllegalStateException(\"Failed to create valid buffer for camera source.\")\n        }\n\n        mBytesToByteBuffer[byteArray] = buffer\n        return byteArray\n    }\n\n    //==============================================================================================\n    // Frame processing\n    //==============================================================================================\n\n    /**\n     * Called when the camera has a new preview frame.\n     */\n    private inner class CameraPreviewCallback : Camera.PreviewCallback\n    {\n        override fun onPreviewFrame(data: ByteArray, camera: Camera)\n        {\n            mFrameProcessor?.setNextFrame(data, camera)\n        }\n    }\n\n    /**\n     * This runnable controls access to the underlying receiver, calling it to process frames when\n     * available from the camera.  This is designed to run detection on frames as fast as possible\n     * (i.e., without unnecessary context switching or waiting on the next frame).\n     *\n     *\n     * While detection is running on a frame, new frames may be received from the camera.  As these\n     * frames come in, the most recent frame is held onto as pending.  As soon as detection and its\n     * associated processing are done for the previous frame, detection on the mostly recently\n     * received frame will immediately start on the same thread.\n     */\n    private inner class FrameProcessingRunnable(private var mDetector: Detector<*>?) : Runnable\n    {\n        private val mStartTimeMillis = SystemClock.elapsedRealtime()\n\n        // This lock guards all of the member variables below.\n        private val mLock = Object()\n        private var mActive = true\n\n        // These pending variables hold the state associated with the new frame awaiting processing.\n        private var mPendingTimeMillis: Long = 0\n        private var mPendingFrameId = 0\n        private var mPendingFrameData: ByteBuffer? = null\n\n        /**\n         * Releases the underlying receiver.  This is only safe to do after the associated thread\n         * has completed, which is managed in camera source's release method above.\n         */\n        @SuppressLint(\"Assert\")\n        fun release()\n        {\n            mDetector?.release()\n            mDetector = null\n        }\n\n        /**\n         * Marks the runnable as active/not active.  Signals any blocked threads to continue.\n         */\n        fun setActive(active: Boolean)\n        {\n            synchronized(mLock) {\n                mActive = active\n                mLock.notifyAll()\n            }\n        }\n\n        /**\n         * Sets the frame data received from the camera.  This adds the previous unused frame buffer\n         * (if present) back to the camera, and keeps a pending reference to the frame data for\n         * future use.\n         */\n        fun setNextFrame(data: ByteArray, camera: Camera)\n        {\n            synchronized(mLock) {\n                if (mPendingFrameData != null)\n                {\n                    camera.addCallbackBuffer(mPendingFrameData?.array())\n                    mPendingFrameData = null\n                }\n\n                if (!mBytesToByteBuffer.containsKey(data))\n                {\n                    Log.d(TAG, \"Skipping frame.  Could not find ByteBuffer associated with the image \" + \"data from the camera.\")\n                    return\n                }\n\n                // Timestamp and frame ID are maintained here, which will give downstream code some\n                // idea of the timing of frames received and when frames were dropped along the way.\n                mPendingTimeMillis = SystemClock.elapsedRealtime() - mStartTimeMillis\n                mPendingFrameId++\n                mPendingFrameData = mBytesToByteBuffer[data]\n\n                // Notify the processor thread if it is waiting on the next frame (see below).\n                mLock.notifyAll()\n            }\n        }\n\n        /**\n         * As long as the processing thread is active, this executes detection on frames\n         * continuously.  The next pending frame is either immediately available or hasn't been\n         * received yet.  Once it is available, we transfer the frame info to local variables and\n         * run detection on that frame.  It immediately loops back for the next frame without\n         * pausing.\n         *\n         *\n         * If detection takes longer than the time in between new frames from the camera, this will\n         * mean that this loop will run without ever waiting on a frame, avoiding any context\n         * switching or frame acquisition time latency.\n         *\n         *\n         * If you find that this is using more CPU than you'd like, you should probably decrease the\n         * FPS setting above to allow for some idle time in between frames.\n         */\n        override fun run()\n        {\n            lateinit var outputFrame: Frame\n            lateinit var data: ByteBuffer\n\n            while (true)\n            {\n                synchronized(mLock)\n                {\n                    while (mActive && mPendingFrameData == null)\n                    {\n                        try\n                        {\n                            // Wait for the next frame to be received from the camera, since we\n                            // don't have it yet.\n                            mLock.wait()\n                        }\n                        catch (e: InterruptedException)\n                        {\n                            Log.d(TAG, \"Frame processing loop terminated.\", e)\n                            return\n                        }\n\n                    }\n\n                    if (!mActive)\n                    {\n                        // Exit the loop once this camera source is stopped or released.  We check\n                        // this here, immediately after the wait() above, to handle the case where\n                        // setActive(false) had been called, triggering the termination of this\n                        // loop.\n                        return\n                    }\n\n                    outputFrame = Frame.Builder().setImageData(mPendingFrameData!!, previewSize!!.width, previewSize!!.height, ImageFormat.NV21).setId(mPendingFrameId).setTimestampMillis(mPendingTimeMillis).setRotation(mRotation).build()\n\n                    // Hold onto the frame data locally, so that we can use this for detection\n                    // below.  We need to clear mPendingFrameData to ensure that this buffer isn't\n                    // recycled back to the camera before we are done using that data.\n                    data = mPendingFrameData as ByteBuffer\n                    mPendingFrameData = null\n                }\n\n                // The code below needs to run outside of synchronization, because this will allow\n                // the camera to add pending frame(s) while we are running detection on the current\n                // frame.\n\n                try\n                {\n                    mDetector?.receiveFrame(outputFrame)\n                }\n                catch (t: Throwable)\n                {\n                    Log.e(TAG, \"Exception thrown from receiver.\", t)\n                }\n                finally\n                {\n                    mCamera?.addCallbackBuffer(data.array())\n                }\n            }\n        }\n    }\n\n    companion object\n    {\n        @SuppressLint(\"InlinedApi\")\n        val CAMERA_FACING_BACK = CameraInfo.CAMERA_FACING_BACK\n        @SuppressLint(\"InlinedApi\")\n        val CAMERA_FACING_FRONT = CameraInfo.CAMERA_FACING_FRONT\n\n        private const val TAG = \"OpenCameraSource\"\n\n        /**\n         * If the absolute difference between a preview size aspect ratio and a picture size aspect\n         * ratio is less than this tolerance, they are considered to be the same aspect ratio.\n         */\n        private const val ASPECT_RATIO_TOLERANCE = 0.01f\n\n        /**\n         * Gets the id for the camera specified by the direction it is facing.  Returns -1 if no such\n         * camera was found.\n         *\n         * @param facing the desired camera (front-facing or rear-facing)\n         */\n        private fun getIdForRequestedCamera(facing: Int): Int\n        {\n            val cameraInfo = CameraInfo()\n            for (i in 0 until Camera.getNumberOfCameras())\n            {\n                Camera.getCameraInfo(i, cameraInfo)\n                if (cameraInfo.facing == facing)\n                {\n                    return i\n                }\n            }\n            return -1\n        }\n\n        /**\n         * Selects the most suitable preview and picture size, given the desired width and height.\n         *\n         *\n         * Even though we may only need the preview size, it's necessary to find both the preview\n         * size and the picture size of the camera together, because these need to have the same aspect\n         * ratio.  On some hardware, if you would only set the preview size, you will get a distorted\n         * image.\n         *\n         * @param camera        the camera to select a preview size from\n         * @param desiredWidth  the desired width of the camera preview frames\n         * @param desiredHeight the desired height of the camera preview frames\n         * @return the selected preview and picture size pair\n         */\n        private fun selectSizePair(camera: Camera, desiredWidth: Int, desiredHeight: Int): SizePair?\n        {\n            val validPreviewSizes = generateValidPreviewSizeList(camera)\n\n            // The method for selecting the best size is to minimize the sum of the differences between\n            // the desired values and the actual values for width and height.  This is certainly not the\n            // only way to select the best size, but it provides a decent trade off between using the\n            // closest aspect ratio vs. using the closest pixel area.\n            var selectedPair: SizePair? = null\n            var minDiff = Integer.MAX_VALUE\n            for (sizePair in validPreviewSizes)\n            {\n                val size = sizePair.previewSize()\n                val diff = Math.abs(size.width - desiredWidth) + Math.abs(size.height - desiredHeight)\n                if (diff < minDiff)\n                {\n                    selectedPair = sizePair\n                    minDiff = diff\n                }\n            }\n\n            return selectedPair\n        }\n\n        /**\n         * Generates a list of acceptable preview sizes.  Preview sizes are not acceptable if there is\n         * not a corresponding picture size of the same aspect ratio.  If there is a corresponding\n         * picture size of the same aspect ratio, the picture size is paired up with the preview size.\n         *\n         *\n         * This is necessary because even if we don't use still pictures, the still picture size must be\n         * set to a size that is the same aspect ratio as the preview size we choose.  Otherwise, the\n         * preview images may be distorted on some devices.\n         */\n        private fun generateValidPreviewSizeList(camera: Camera): List<SizePair>\n        {\n            val parameters = camera.parameters\n            val supportedPreviewSizes = parameters.supportedPreviewSizes\n            val supportedPictureSizes = parameters.supportedPictureSizes\n            val validPreviewSizes = ArrayList<SizePair>()\n            for (previewSize in supportedPreviewSizes)\n            {\n                val previewAspectRatio = previewSize.width.toFloat() / previewSize.height.toFloat()\n\n                // By looping through the picture sizes in order, we favor the higher resolutions.\n                // We choose the highest resolution in order to support taking the full resolution\n                // picture later.\n                for (pictureSize in supportedPictureSizes)\n                {\n                    val pictureAspectRatio = pictureSize.width.toFloat() / pictureSize.height.toFloat()\n                    if (Math.abs(previewAspectRatio - pictureAspectRatio) < ASPECT_RATIO_TOLERANCE)\n                    {\n                        validPreviewSizes.add(SizePair(previewSize, pictureSize))\n                        break\n                    }\n                }\n            }\n\n            // If there are no picture sizes with the same aspect ratio as any preview sizes, allow all\n            // of the preview sizes and hope that the camera can handle it.  Probably unlikely, but we\n            // still account for it.\n            if (validPreviewSizes.size == 0)\n            {\n                Log.w(TAG, \"No preview sizes have a corresponding same-aspect-ratio picture size\")\n                for (previewSize in supportedPreviewSizes)\n                {\n                    // The null picture size will let us know that we shouldn't set a picture size.\n                    validPreviewSizes.add(SizePair(previewSize, null))\n                }\n            }\n\n            return validPreviewSizes\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/barcodereader/CameraSourcePreview.kt",
    "content": "/*\n * Copyright (C) The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * This file contains modifications by The Centure developers\n * All modifications copyright (C) The Centure developers\n */\npackage barcodereader\n\nimport android.Manifest\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.graphics.SurfaceTexture\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.TextureView\nimport androidx.annotation.RequiresPermission\nimport java.io.IOException\n\n\nclass CameraSourcePreview(private val mContext: Context, attrs: AttributeSet) : TextureView(mContext, attrs), TextureView.SurfaceTextureListener\n{\n    private var textureHeight : Int = 0\n    private var textureWidth : Int = 0\n    var previewHeight : Int = 0\n    var previewWidth : Int = 0\n    private var mStartRequested: Boolean = false\n    private var mSurfaceAvailable: Boolean = false\n    private var mCameraSource: CameraSource? = null\n\n    private val isPortraitMode: Boolean\n        get()\n        {\n            val orientation = mContext.resources.configuration.orientation\n            if (orientation == Configuration.ORIENTATION_LANDSCAPE)\n            {\n                return false\n            }\n            if (orientation == Configuration.ORIENTATION_PORTRAIT)\n            {\n                return true\n            }\n\n            Log.d(TAG, \"isPortraitMode returning false by default\")\n            return false\n        }\n\n    init\n    {\n        mStartRequested = false\n        mSurfaceAvailable = false\n\n        surfaceTextureListener = this\n    }\n\n    /*Texture view listener overrides begin*/\n    override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int)\n    {\n        mSurfaceAvailable = true\n        textureHeight = height\n        textureWidth = width\n        try\n        {\n            startIfReady()\n        }\n        catch (e: Exception)\n        {\n            Log.e(TAG, \"Could not start camera source.\", e)\n        }\n\n    }\n\n    override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int)\n    {\n        textureHeight = height\n        textureWidth = width\n    }\n\n    override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean\n    {\n        mSurfaceAvailable = false\n        return true\n    }\n\n    override fun onSurfaceTextureUpdated(texture: SurfaceTexture)\n    {\n    }\n    /*Texture view listener overrides end*/\n\n\n    @RequiresPermission(Manifest.permission.CAMERA)\n    @Throws(IOException::class, SecurityException::class)\n    fun start(cameraSource: CameraSource?)\n    {\n        if (cameraSource == null)\n        {\n            stop()\n        }\n\n        mCameraSource = cameraSource\n\n        if (mCameraSource != null)\n        {\n            mStartRequested = true\n            startIfReady()\n        }\n    }\n\n    fun stop()\n    {\n        if (mCameraSource != null)\n        {\n            mCameraSource?.stop()\n        }\n    }\n\n    fun release()\n    {\n        if (mCameraSource != null)\n        {\n            mCameraSource?.release()\n            mCameraSource = null\n        }\n    }\n\n    @RequiresPermission(Manifest.permission.CAMERA)\n    @Throws(IOException::class, SecurityException::class)\n    private fun startIfReady()\n    {\n        if (mStartRequested && mSurfaceAvailable)\n        {\n            mCameraSource?.start(this)\n            mStartRequested = false\n        }\n    }\n\n    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int)\n    {\n        previewHeight = bottom - top\n        previewWidth = right - left\n\n        try\n        {\n            startIfReady()\n        }\n        catch (se: SecurityException)\n        {\n            Log.e(TAG, \"Do not have permission to start the camera\", se)\n        }\n        catch (e: IOException)\n        {\n            Log.e(TAG, \"Could not start camera source.\", e)\n        }\n\n    }\n\n    companion object\n    {\n        private const val TAG = \"CameraSourcePreview\"\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ActivityManager.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com) & Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.app.*\nimport androidx.lifecycle.Lifecycle\nimport androidx.lifecycle.LifecycleObserver\nimport androidx.lifecycle.OnLifecycleEvent\nimport androidx.lifecycle.ProcessLifecycleOwner\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.graphics.Color\nimport android.os.Build\nimport android.util.Log\nimport androidx.core.app.NotificationCompat\nimport androidx.preference.PreferenceManager\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.MutationRecord\nimport unity_wallet.jniunifiedbackend.TransactionRecord\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.SupervisorJob\nimport kotlin.coroutines.CoroutineContext\nimport kotlin.system.exitProcess\nimport android.os.Handler\nimport android.os.Looper\n\n\nprivate const val TAG = \"activity-manager\"\n\nclass ActivityManager : Application(), LifecycleObserver, UnityCore.Observer, SharedPreferences.OnSharedPreferenceChangeListener, CoroutineScope {\n\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    private var lastAudibleNotification = 0L\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    override fun onCreate()\n    {\n        super.onCreate()\n\n        AppContext.instance = baseContext\n\n        val assetFD = assets?.openFd(\"staticfiltercp\")\n        UnityCore.instance.configure(\n            UnityConfig(dataDir = applicationContext.applicationInfo.dataDir, apkPath = applicationContext.packageResourcePath, staticFilterOffset = assetFD?.startOffset!!, staticFilterLength = assetFD.length, testnet = Constants.TEST)\n        )\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { handler.post { callback() }})\n\n        val preferences = PreferenceManager.getDefaultSharedPreferences(this)\n        preferences.registerOnSharedPreferenceChangeListener(this)\n\n        setupBackgroundSync(this)\n\n        ProcessLifecycleOwner.get().lifecycle.addObserver(this)\n    }\n\n    override fun onCoreShutdown() {\n        ProcessLifecycleOwner.get().lifecycle.removeObserver(this)\n\n        //fixme: In future see if we can restart the core here\n        exitProcess(-1)\n    }\n\n    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {\n        when (key) {\n            \"preference_background_sync\" -> {\n                setupBackgroundSync(this)\n            }\n        }\n    }\n\n    // O upwards requires notification channels\n    private var notificationChannel : NotificationChannel? = null\n    private fun getNotificationChannelID() : String\n    {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)\n        {\n            if (notificationChannel == null)\n            {\n                val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n\n                // The id of the channel.\n                val id = \"coin_transactions_notification_channel\"\n\n                // The user-visible name of the channel.\n                val name = getString(R.string.notification_transaction_channel_name)\n\n                // The user-visible description of the channel.\n                val description = getString(R.string.notification_transaction_channel_description)\n\n                // Default importance, adjustable by user in preferences\n                val importance = NotificationManager.IMPORTANCE_HIGH\n\n                notificationChannel = NotificationChannel(id, name, importance)\n\n                // Sets the notification light color for notifications posted to this, if the device supports this feature.\n                notificationChannel?.enableLights(true)\n                notificationChannel?.lightColor = Color.GREEN\n\n                // Sets vibration for notifications\n                notificationChannel?.enableVibration(true)\n                notificationChannel?.vibrationPattern = longArrayOf(0, 1000, 500, 1000)\n\n                notificationChannel?.description = description\n                mNotificationManager.createNotificationChannel(notificationChannel!!)\n            }\n            if (notificationChannel != null)\n                return notificationChannel?.id!!\n        }\n        return \"\"\n    }\n\n    override fun onNewMutation(mutation: MutationRecord, selfCommitted: Boolean) {\n        try\n        {\n            val preferences = PreferenceManager.getDefaultSharedPreferences(this)\n            // only notify of mutations that are not initiated by our own payments, have a net change effect != 0\n            // and when notifications are enabled in preferences\n            if (preferences.getBoolean(\"preference_notify_transaction_activity\", true)\n                    && !selfCommitted\n                    && mutation.change != 0L) {\n                val notificationIntent = Intent(this, WalletActivity::class.java)\n                val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                    PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE)\n                } else {\n                    PendingIntent.getActivity(this, 0, notificationIntent, 0)\n                }\n\n                val title = getString(if (mutation.change > 0) R.string.notify_received else R.string.notify_sent)\n                val notification = with(NotificationCompat.Builder(this)) {\n                    setSmallIcon(R.drawable.ic_logo)\n                    setContentTitle(title)\n                    setTicker(title)\n                    setContentText(formatNative(mutation.change))\n                    //setPublicVersion()\n                    //setTimeoutAfter()\n                    if (getNotificationChannelID() != \"\")\n                        setChannelId(getNotificationChannelID())\n                    setContentIntent(pendingIntent)\n                    setOngoing(false)\n                    setAutoCancel(true)\n                    setVisibility(NotificationCompat.VISIBILITY_PUBLIC)\n                    setDefaults(Notification.DEFAULT_ALL)\n                    //setLargeIcon(Bitmap.createScaledBitmap(R.drawable.ic_g_logo, 128, 128, false))\n                    val now = System.currentTimeMillis()\n                    if (now - lastAudibleNotification > Config.AUDIBLE_NOTIFICATIONS_INTERVAL)\n                        lastAudibleNotification = now\n                    else\n                        setOnlyAlertOnce(true)\n                    build()\n                }\n                val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n                notificationManager.notify(1, notification)\n            }\n        }\n        catch(e : Exception)\n        {\n            //TODO - analytics\n        }\n    }\n\n    override fun updatedTransaction(transaction: TransactionRecord) {\n        Log.i(TAG, \"updatedTransaction: $transaction\")\n    }\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)\n    fun processCreated()\n    {\n        UnityCore.instance.startCore()\n    }\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)\n    fun allActivitiesStopped()\n    {\n        val deferred = UnityCore.instance.walletReady\n        if (deferred.isCompleted && !deferred.isCancelled) {\n            ILibraryController.PersistAndPruneForSPV()\n            ILibraryController.LockWallet()\n            //TODO: This lock call should be powered via core events and not directly\n            Authentication.instance.lock()\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/AppContext.kt",
    "content": "package unity_wallet\n\nimport android.content.Context\n\nclass AppContext {\n    companion object {\n        lateinit var instance: Context\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/Authentication.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.text.Editable\nimport android.text.TextWatcher\nimport android.text.format.DateUtils\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.animation.AnimationUtils\nimport android.view.inputmethod.InputMethodManager\nimport androidx.preference.PreferenceManager\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.Constants.ACCESS_CODE_ATTEMPTS_ALLOWED\nimport unity_wallet.Constants.ACCESS_CODE_LENGTH\nimport kotlinx.android.synthetic.main.access_code_entry.view.*\nimport kotlinx.android.synthetic.main.access_code_recovery.view.*\n\n\nprivate const val TAG = \"authentication\"\n\nprivate const val BLOCK_DURATION = 241 * DateUtils.MINUTE_IN_MILLIS\nprivate const val BLOCKED_UNTIL_KEY = \"authentication-blocked-until\"\nprivate const val NUM_FAILED_ATTEMPTS_KEY = \"authentication-num-failed-attempts\"\n\nclass Authentication {\n    interface LockingObserver {\n        fun onUnlock()\n        fun onLock()\n    }\n\n    fun addObserver(lockingObserver: LockingObserver) {\n        lockingObservers.add(lockingObserver)\n    }\n\n    fun removeObserver(lockingObserver: LockingObserver) {\n        lockingObservers.remove(lockingObserver)\n    }\n\n    fun isLocked(): Boolean {\n        return locked\n    }\n\n    fun unlock(context: Context, title: String?, msg: String?) {\n        unlock(context, title, msg) { }\n    }\n\n    /**\n     * Unlock after successful authentication. All lockingObservers are\n     * notified and then action is executed.\n     *\n     */\n    //TODO: lock()/unlock() should rather be driven by signals coming from the unity core.\n    private fun unlock(context: Context, title: String?, msg: String?, action: () -> Unit) {\n        if (isLocked()) {\n            authenticate(context, title, msg) {\n                locked = false\n                lockingObservers.forEach {\n                    it.onUnlock()\n                }\n                action()\n            }\n        } else // not locked just execute action\n            action()\n    }\n\n    //TODO: lock()/unlock() should rather be driven by signals coming from the unity core.\n    fun lock() {\n        if (!isLocked()) {\n            locked = true\n            lockingObservers.forEach { it.onLock() }\n        }\n    }\n\n    private fun isBlocked(context: Context): Boolean {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val blockedUntil = preferences.getLong(BLOCKED_UNTIL_KEY, 0)\n        val now = System.currentTimeMillis()\n        return now < blockedUntil\n    }\n\n    fun block(context: Context) {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val editor = preferences.edit()\n        val blockUntil = System.currentTimeMillis() + BLOCK_DURATION\n        editor.putLong(BLOCKED_UNTIL_KEY, blockUntil)\n        editor.apply()\n\n        resetFailedAttempts(context)\n    }\n\n    private fun unblock(context: Context) {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val editor = preferences.edit()\n        editor.remove(BLOCKED_UNTIL_KEY)\n        editor.apply()\n    }\n\n    fun showBlocking(context: Context) {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val blockedUntil = preferences.getLong(BLOCKED_UNTIL_KEY, 0)\n        val alert = MaterialAlertDialogBuilder(context)\n                .setTitle(context.getString(R.string.authentication_blocked_title))\n        alert.setPositiveButton(context.getString(R.string.authentication_blocked_later_btn)) { dialog: DialogInterface?, whichButton: Int ->\n                    // TODO: recovery using the mnemonic is not possible because the (core) wallet needs to be unlocked to verify the mnemonic\n                    // so this is a chicken egg problem. it could be fixed for example by storing a hashed version of the mnemonic for this purpose\n                    if (false /*ILibraryController.IsMnemonicWallet()*/) {\n                        alert.setMessage(context.getString(R.string.authentication_blocked_msg_recovery).format(\n                                DateUtils.getRelativeTimeSpanString(blockedUntil, System.currentTimeMillis(), 0, 0).toString().lowercase()))\n\n                        alert.setNeutralButton(context.getString(R.string.authentication_blocked_choose_new_btn)) { dialog: DialogInterface?, whichButton: Int ->\n                            chooseNewWithRecovery(context)\n                        }\n                    } else {\n                        alert.setMessage(context.getString(R.string.authentication_blocked_msg).format(\n                                DateUtils.getRelativeTimeSpanString(blockedUntil, System.currentTimeMillis(), 0, 0).toString().lowercase()))\n                    }\n                }\n        alert.show()\n    }\n\n    private fun chooseNewWithRecovery(context: Context) {\n        val contentView = LayoutInflater.from(context).inflate(R.layout.access_code_recovery, null)\n\n        val alert = MaterialAlertDialogBuilder(context)\n                .setView(contentView)\n                .setTitle(context.getString(R.string.authentication_blocked_title))\n                .setNegativeButton(android.R.string.cancel) { dialog: DialogInterface?, whichButton: Int -> }\n        alert.setPositiveButton(context.getString(android.R.string.ok)) { dialog: DialogInterface?, whichButton: Int ->\n            if (UnityCore.instance.walletReady.isCompleted && ILibraryController.IsMnemonicCorrect(contentView.recoveryPhrase.text.toString())) {\n                chooseAccessCode(\n                        context,\n                        null,\n                        action = fun(password: CharArray) {\n                            unblock(context)\n                        },\n                        cancelled = fun(){}\n                )\n            } else {\n                MaterialAlertDialogBuilder(context)\n                        .setTitle(context.getString(R.string.authentication_blocked_title))\n                        .setMessage(context.getString(R.string.access_code_recovery_incorrect))\n                        .show()\n            }\n        }\n        alert.show()\n    }\n\n    /**\n     * Present user with authentication method.\n     * On successful authentication action is executed.\n     */\n    fun authenticate(context: Context, title: String?, msg: String?, action: (CharArray) -> Unit) {\n\n\n        if (isBlocked(context)) {\n            showBlocking(context)\n            return\n        }\n\n        val contentView = LayoutInflater.from(context).inflate(R.layout.access_code_entry, null)\n        msg?.let { contentView.message.text = msg }\n\n        val dialog = MaterialAlertDialogBuilder(context)\n                .setTitle(title ?: context.getString(R.string.access_code_entry_title))\n                .setView(contentView)\n                .setNegativeButton(\"Cancel\") { dialogInterface: DialogInterface, i: Int -> }\n                .create()\n\n        dialog.setOnShowListener {\n            contentView.accessCode.addTextChangedListener(\n                    object : TextWatcher {\n\n                        override fun afterTextChanged(s: Editable?) {\n                            if (s?.length == ACCESS_CODE_LENGTH)\n                            {\n                                var chosenCode = CharArray(ACCESS_CODE_LENGTH)\n                                s.getChars(0, s.length, chosenCode, 0)\n\n                                if (UnityCore.instance.walletReady.isCompleted && ILibraryController.UnlockWallet(chosenCode.joinToString(\"\"), 600)) {\n                                    Log.i(TAG, \"successful authentication\")\n                                    resetFailedAttempts(context)\n                                    it.dismiss()\n                                    action(chosenCode)\n                                } else {\n                                    val numAttemptsRemaining = ACCESS_CODE_ATTEMPTS_ALLOWED - incFailedAttempts(context)\n                                    if (numAttemptsRemaining > 0) {\n                                        s.clear()\n                                        contentView.accessCode.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake))\n                                        contentView.attemptsRemaining.text = context.resources.getQuantityString(R.plurals.access_code_entry_remaining, numAttemptsRemaining, numAttemptsRemaining)\n                                    } else {\n                                        Log.i(TAG, \"failed authentication\")\n                                        block(context)\n                                        showBlocking(context)\n                                        it.dismiss()\n                                    }\n                                }\n                                s.clear()\n                                @Suppress(\"UNUSED_VALUE\")\n                                chosenCode = CharArray(ACCESS_CODE_LENGTH)\n                            }\n                        }\n\n                        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}\n                        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}\n                    })\n\n            contentView.accessCode.requestFocus()\n            contentView.accessCode.post {\n                val imm = context.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                imm.showSoftInput(contentView.accessCode, InputMethodManager.SHOW_IMPLICIT)\n            }\n        }\n        dialog.show()\n    }\n\n    fun chooseAccessCode(context: Context, title: String?, action: (CharArray) -> Unit, cancelled: () -> Unit) {\n        val contentView = LayoutInflater.from(context).inflate(R.layout.access_code_entry, null)\n\n        val dialog = MaterialAlertDialogBuilder(context)\n                .setTitle(title ?: context.getString(R.string.access_code_choose_title))\n                .setView(contentView)\n                .setNegativeButton(\"Cancel\") { dialogInterface: DialogInterface, i: Int -> \n                    cancelled()\n                }\n                .create()\n\n        dialog.setOnShowListener {\n            contentView.accessCode.addTextChangedListener(\n                    object : TextWatcher {\n                        var verifying = false\n                        var chosenCode: CharArray = CharArray(ACCESS_CODE_LENGTH)\n                        override fun afterTextChanged(s: Editable?) {\n                            if (s?.length == ACCESS_CODE_LENGTH)\n                            {\n                                var code = CharArray(ACCESS_CODE_LENGTH)\n                                s.getChars(0, s.length, code, 0)\n                                if (verifying) {\n                                    if (code.contentEquals(chosenCode)) {\n                                        Log.i(TAG, \"access code successfully chosen\")\n                                        it.dismiss()\n                                        action(chosenCode)\n                                        s.clear()\n                                        chosenCode = CharArray(ACCESS_CODE_LENGTH)\n                                        @Suppress(\"UNUSED_VALUE\")\n                                        code = CharArray(ACCESS_CODE_LENGTH)\n                                    }\n                                    else {\n                                        verifying = false\n                                        s.clear()\n                                        chosenCode = CharArray(ACCESS_CODE_LENGTH)\n                                        @Suppress(\"UNUSED_VALUE\")\n                                        code = CharArray(ACCESS_CODE_LENGTH)\n                                        contentView.accessCode.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake))\n                                        contentView.message.text = \"\"\n                                    }\n                                }\n                                else {\n                                    chosenCode = code\n                                    verifying = true\n                                    s.clear()\n                                    @Suppress(\"UNUSED_VALUE\")\n                                    code = CharArray(ACCESS_CODE_LENGTH)\n                                    contentView.message.text = context.getString(R.string.access_code_choose_verify)\n                                }\n                            }\n                        }\n\n                        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}\n                        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}\n                    })\n\n            contentView.accessCode.requestFocus()\n            contentView.accessCode.post {\n                val imm = context.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                imm.showSoftInput(contentView.accessCode, InputMethodManager.SHOW_IMPLICIT)\n            }\n        }\n        dialog.show()\n    }\n\n    private fun incFailedAttempts(context: Context): Int {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val numFailedAttempts = 1 + preferences.getInt(NUM_FAILED_ATTEMPTS_KEY, 0)\n        val editor = preferences.edit()\n        editor.putInt(NUM_FAILED_ATTEMPTS_KEY, numFailedAttempts)\n        editor.apply()\n        return numFailedAttempts\n    }\n\n    private fun resetFailedAttempts(context: Context) {\n        val preferences = PreferenceManager.getDefaultSharedPreferences(context)\n        val editor = preferences.edit()\n        editor.remove(NUM_FAILED_ATTEMPTS_KEY)\n        editor.apply()\n    }\n\n    private var lockingObservers: MutableSet<LockingObserver> = mutableSetOf()\n    private var locked = true\n\n    companion object {\n        val instance: Authentication = Authentication()\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/BackgroundSync.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.app.*\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build\nimport android.os.IBinder\nimport androidx.core.app.NotificationCompat\nimport android.util.Log\nimport android.content.BroadcastReceiver\nimport android.os.SystemClock.sleep\nimport androidx.preference.PreferenceManager\nimport androidx.core.content.ContextCompat\nimport androidx.work.PeriodicWorkRequestBuilder\nimport androidx.work.WorkManager\nimport androidx.work.Worker\nimport androidx.work.WorkerParameters\nimport kotlinx.coroutines.*\nimport android.os.Handler\nimport android.os.Looper\nimport androidx.annotation.RequiresApi\nimport java.util.concurrent.TimeUnit\nimport kotlin.coroutines.CoroutineContext\n\nprivate const val TAG = \"background_sync\"\nconst val APP_PERIODIC_SYNC = \"APP_PERIODIC_SYNC\"\n\nfun setupBackgroundSync(context: Context) {\n\n    // get syncType from preferences\n    val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)\n    val syncType = sharedPreferences.getString(\"preference_background_sync\", context.getString(R.string.background_sync_default))!!\n\n    Log.i(TAG, \"Starting background sync: $syncType\")\n\n    val serviceIntent = Intent(context, SyncService::class.java)\n\n    context.stopService(serviceIntent)\n    WorkManager.getInstance().cancelAllWorkByTag(APP_PERIODIC_SYNC)\n\n    when (syncType) {\n        \"BACKGROUND_SYNC_OFF\" -> {\n        }\n\n        \"BACKGROUND_SYNC_DAILY\" -> {\n            val work = PeriodicWorkRequestBuilder<SyncWorker>(24, TimeUnit.HOURS)\n                    .addTag(APP_PERIODIC_SYNC)\n                    .build()\n            WorkManager.getInstance().enqueue(work)\n        }\n\n        \"BACKGROUND_SYNC_CONTINUOUS\" -> {\n            var tryForeground = true\n            if (Build.MANUFACTURER == \"samsung\")\n                tryForeground = false\n\n            if (tryForeground) {\n                try {\n                    ContextCompat.startForegroundService(context, serviceIntent)\n                } catch (e: Exception) {\n                    tryForeground = false\n                }\n            }\n            if(!tryForeground) {\n                //fixme: (HIGH) - as of API 32 the above is \"illegal\" and leads to ForegroundServiceStartNotAllowedException\n                //see: https://stackoverflow.com/questions/69604951/getting-android-app-foregroundservicestartnotallowedexception-in-android-12-sdk\n                //\n                //For now instead we just call the periodic sync a lot more frequently, however I don't know if this is the best solution, we should look at something else in future\n                val work = PeriodicWorkRequestBuilder<SyncWorker>(10, TimeUnit.MINUTES)\n                        .addTag(APP_PERIODIC_SYNC)\n                        .build()\n                WorkManager.getInstance().enqueue(work)\n            }\n        }\n    }\n}\n\n\nprivate var NOTIFICATION_ID_FOREGROUND_SERVICE = 2\n\nclass SyncService : Service(), UnityCore.Observer\n{\n    override fun onBind(intent: Intent?): IBinder? {\n        TODO(\"not implemented\") //To change body of created functions use File | Settings | File Templates.\n    }\n\n    override fun syncProgressChanged(percent: Float) {\n        Log.i(TAG, \"sync progress = $percent\")\n        try\n        {\n            if (builder != null)\n            {\n                val b: NotificationCompat.Builder = builder!!\n                builder!!.setContentText(\"progress $percent\")\n                val notificationManager =\n                    getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n                notificationManager.notify(NOTIFICATION_ID_FOREGROUND_SERVICE, b.build())\n            }\n        }\n        catch (e : Exception)\n        {\n            //TODO - analytics\n        }\n    }\n\n    private var builder: NotificationCompat.Builder? = null\n\n    private val channelID = \"unity_wallet.service.channel\"\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    private fun startInForeground()\n    {\n\n        try\n        {\n            val notificationIntent = Intent(this, WalletActivity::class.java)\n            val pendingIntent =\n                PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE)\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                val notificationChannel = NotificationChannel(\n                    channelID,\n                    getString(R.string.notification_service_channel_name),\n                    NotificationManager.IMPORTANCE_LOW\n                )\n                (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(\n                    notificationChannel\n                )\n                notificationChannel.description =\n                    getString(R.string.notification_service_channel_description)\n                notificationChannel.enableLights(false)\n                notificationChannel.setShowBadge(false)\n            }\n\n\n            builder = NotificationCompat.Builder(this, channelID)\n                .setContentTitle(\"Munt\")\n                .setTicker(\"Munt\")\n                .setContentText(\"Munt\")\n                .setSmallIcon(R.drawable.ic_logo)\n                .setContentIntent(pendingIntent)\n                .setOngoing(true)\n\n            val notification = builder?.build()\n            startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, notification)\n        }\n        catch (e : Exception)\n        {\n            //TODO - Analytics\n        }\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int\n    {\n        startInForeground()\n        return super.onStartCommand(intent, flags, startId)\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { handler.post { callback() }})\n        UnityCore.instance.startCore()\n    }\n    override fun onDestroy() {\n        super.onDestroy()\n\n        UnityCore.instance.removeObserver(this)\n    }\n}\n\nclass BootReceiver : BroadcastReceiver() {\n\n    override fun onReceive(context: Context, intent: Intent) {\n        if (Intent.ACTION_BOOT_COMPLETED == intent.action) {\n            setupBackgroundSync(context)\n        }\n    }\n\n}\n\nclass SyncWorker(context : Context, params : WorkerParameters)\n    : UnityCore.Observer, Worker(context, params), CoroutineScope {\n\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    override fun syncProgressChanged(percent: Float) {\n        Log.i(TAG, \"periodic sync progress = $percent\")\n    }\n\n    override fun doWork(): Result {\n        Log.i(TAG, \"Periodic sync started\")\n\n        UnityCore.instance.addObserver(this)\n        UnityCore.instance.startCore()\n\n        // wait for wallet ready (or get killed by the OS which ever comes first)\n        try {\n            runBlocking {\n                UnityCore.instance.walletReady.await()\n            }\n        }\n        catch (e: CancellationException) {\n            return Result.retry()\n        }\n\n        // wait until sync is complete (or get killed by the OS which ever comes first)\n        while (UnityCore.instance.progressPercent < 100.0) {\n            sleep(5000)\n        }\n\n        Log.i(TAG, \"Periodic sync finished\")\n\n        // Indicate success or failure with your return value:\n        return Result.success()\n\n        // (Returning RETRY tells WorkManager to try this task again\n        // later; FAILURE says not to try again.)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/Common.kt",
    "content": "package unity_wallet\n\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.net.Uri\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.UriRecipient\nimport unity_wallet.jniunifiedbackend.UriRecord\nimport org.apache.commons.validator.routines.IBANValidator\nimport java.util.HashMap\n\nfun Uri.getParameters(): HashMap<String, String> {\n    val items : HashMap<String, String> = HashMap()\n    if (isOpaque)\n        return items\n\n    val query = encodedQuery ?: return items\n\n    var start = 0\n    do {\n        val nextAmpersand = query.indexOf('&', start)\n        val end = if (nextAmpersand != -1) nextAmpersand else query.length\n\n        var separator = query.indexOf('=', start)\n        if (separator > end || separator == -1) {\n            separator = end\n        }\n\n        if (separator == end) {\n            items[Uri.decode(query.substring(start, separator))] = \"\"\n        } else {\n            items[Uri.decode(query.substring(start, separator))] = Uri.decode(query.substring(separator + 1, end))\n        }\n\n        // Move start to end of name.\n        if (nextAmpersand != -1) {\n            start = nextAmpersand + 1\n        } else {\n            break\n        }\n    } while (true)\n    return items\n}\n\nclass InvalidRecipientException(message: String): RuntimeException(message)\n\nfun createRecipient(text: String): UriRecipient {\n    var uri = Uri.parse(text)\n\n    // If Uri has been parsed as non-hierarchical force it to reparse as hierarchical so that we can access any query portions correctly.\n    if (!uri.isHierarchical)\n        uri = Uri.parse(text.replaceFirst(\":\", \"://\"))\n\n    if (uri.scheme == null)\n        uri = Uri.parse(\"munt://$text\")\n\n    val address = uri.host ?: throw InvalidRecipientException(\"No recipient address\")\n    val amount = uri.getQueryParameter(\"amount\")?.toDoubleOrZero()?.toNative() ?: 0\n    val label = uri.getQueryParameter(\"label\") ?: \"\"\n    val description = uri.getQueryParameter(\"description\") ?: \"\"\n\n    if (IBANValidator.getInstance().isValid(address))\n        return UriRecipient(false, address, label, description, amount)\n\n    // if there is a scheme it should equal munt, but that will be checked inside C++, so just pass it through\n    val coreRecipient = ILibraryController.IsValidRecipient(UriRecord(uri.scheme, address, HashMap<String, String>()))\n    if (!coreRecipient.valid)\n        throw InvalidRecipientException(\"Core deemed recipient invalid\")\n\n    return UriRecipient(true, coreRecipient.address, if (coreRecipient.label != \"\") coreRecipient.label else label, if (coreRecipient.desc != \"\") coreRecipient.desc else description, amount)\n}\n\nfun ellipsizeString(sourceString: String, maxLength: Int): String\n{\n    //Remove 3 chars for \"ellipses\" length and then split into two equal halves\n    val halfStringLength = (maxLength - 3) / 2\n    return when\n    {\n        sourceString.length > maxLength -> sourceString.replaceFirst(Regex(\"(.{$halfStringLength}).+(.{$halfStringLength})\"), \"$1…$2\")\n        else -> sourceString\n    }\n}\n\nfun internalErrorAlert(context: Context, msg: String) {\n    MaterialAlertDialogBuilder(context)\n            .setTitle(\"Internal error!\")\n            .setMessage(\"An unexpected error occurred, this is likely a bug. Please contact the developers.\\n\\n$msg\")\n            .setPositiveButton(android.R.string.ok) { dialogInterface: DialogInterface, i: Int -> }\n            .show()\n}\n\nfun String.toDoubleOrZero(): Double {\n    return toDoubleOrNull() ?: 0.0\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/Config.kt",
    "content": "package unity_wallet\n\nclass Config {\n    companion object {\n        const val COIN = 100000000\n        const val PRECISION_SHORT = 2\n        const val PRECISION_FULL = 8\n        val DEFAULT_CURRENCY_CODE get() = getDefaultCurrencyCode()\n        const val USER_AGENT = \"/Munt android:${BuildConfig.VERSION_NAME}/\"\n        const val BLOCK_EXPLORER_TX_TEMPLATE = \"https://munt.chainviewer.org/tx/%s\"\n        const val BLOCK_EXPLORER_BLOCK_TEMPLATE = \"https://explorer.munt.org/block/%s\"\n        const val AUDIBLE_NOTIFICATIONS_INTERVAL = 30 * 1000\n        const val USE_RATE_PRECISION = true\n        const val RATE_FETCH_INTERVAL = 60 * 1000 // minimum interval for fetching new exchange rates\n\n        private fun getDefaultCurrencyCode(): String {\n            return AppContext.instance.getString(R.string.default_currency_code)\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/Constants.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nobject Constants\n{\n    const val TEST = BuildConfig.TESTNET\n    const val RECOMMENDED_CONFIRMATIONS = 3\n    const val ACCESS_CODE_ATTEMPTS_ALLOWED = 3\n    const val ACCESS_CODE_LENGTH = 6\n    const val OLD_WALLET_PROTOBUF_FILENAME = BuildConfig.OLD_WALLET_PROTOBUF_FILENAME\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/Currency.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.preference.PreferenceManager\nimport android.util.Log\nimport unity_wallet.Config.Companion.RATE_FETCH_INTERVAL\nimport kotlinx.coroutines.*\nimport org.json.JSONObject\nimport java.net.URL\nimport java.text.DecimalFormat\nimport java.util.*\nimport kotlin.math.floor\nimport kotlin.math.roundToLong\n\nprivate const val TAG = \"currency\"\n\nprivate const val APP_MARKET_URL = \"https://api.munt.org/api/v1/ticker\"\n\n/**\n * Fetch currency conversion rate from server (suspended, use from co-routine)\n *\n * @param code currency code\n * @throws Throwable on any error\n * @return conversion rate to convert from munt to specified currency (ie. value = munt * rate)\n */\nsuspend fun fetchCurrencyRate(code: String): Double\n{\n    return fetchAllCurrencyRates().getValue(code)\n}\n\nsuspend fun fetchAllCurrencyRates(): Map<String, Double> {\n    // use cached currency rates if last fetch within RATE_FETCH_INTERVAL\n    val now = System.currentTimeMillis()\n    if (now - currencyRatesLastFetched > RATE_FETCH_INTERVAL) {\n        currencyRates = reallyfetchAllCurrencyRates()\n        currencyRatesLastFetched = now\n    }\n    return currencyRates\n}\n\n// caching of currency rates\nprivate var currencyRatesLastFetched = 0L\nprivate var currencyRates = mapOf<String, Double>()\n\nprivate suspend fun reallyfetchAllCurrencyRates(): Map<String, Double> {\n    Log.i(TAG, \"reallyfetchAllCurrencyRates\")\n\n    // fetch rate data from server\n    lateinit var data: String\n    try {\n        data  = withContext(Dispatchers.IO) {\n            URL(APP_MARKET_URL).readText()\n        }\n    }\n    catch (e: Throwable) {\n        Log.i(TAG, \"Failed to fetch currency rates from $APP_MARKET_URL\")\n        throw e\n    }\n\n    // parse json rate data from server\n    val rates = TreeMap<String, Double>()\n    try {\n        val json = JSONObject(data).getJSONArray(\"data\")\n        for (i in 0 until json.length()) {\n            val cCode: String = json.getJSONObject(i).getString(\"code\")\n            val cRate: Double = json.getJSONObject(i).getString(\"rate\").toDouble()\n            if (cRate > 0.0)\n                rates[cCode] = cRate\n        }\n    }\n    catch (e: Throwable) {\n        Log.i(TAG, \"Failed to decode currency rates\")\n        throw e\n    }\n\n    return rates\n}\n\ndata class Currency (val code: String, val name: String, val short: String, val precision: Int, val ratePrecision: Int) {\n    fun formatRate(rate: Double, usePrefix: Boolean = true): String\n    {\n        val appliedPrecision = if (Config.USE_RATE_PRECISION) ratePrecision else precision\n        val rateStr = if (appliedPrecision > 0) {\n            val pattern = \"#,##0.%s;-#\".format(\"0\".repeat(appliedPrecision))\n            DecimalFormat(pattern).format(rate)\n        }\n        else {\n            rate.roundToLong().toString()\n        }\n        return \"%s %s\".format(short, rateStr)\n    }\n}\n\nclass Currencies {\n    companion object {\n        var knownCurrencies = TreeMap<String, Currency>()\n\n        init {\n            val codes = AppContext.instance.resources.getStringArray(R.array.currency_codes)\n            val names = AppContext.instance.resources.getStringArray(R.array.currency_names)\n            val shorts = AppContext.instance.resources.getStringArray(R.array.currency_shorts)\n            val precisions = AppContext.instance.resources.getIntArray(R.array.currency_precisions)\n            val ratePrecisions = AppContext.instance.resources.getIntArray(R.array.currency_rate_precisions)\n\n            for (i in codes.indices) {\n                val c = Currency(code = codes[i], name = names[i], short = shorts[i], precision = precisions[i], ratePrecision = ratePrecisions[i])\n                knownCurrencies[codes[i]] = c\n            }\n        }\n    }\n}\n\nval localCurrency: Currency\n    get() {\n        val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(AppContext.instance)\n        val code = sharedPreferences.getString(\"preference_local_currency\", Config.DEFAULT_CURRENCY_CODE)!!\n        return Currencies.knownCurrencies[code]!!\n    }\n\n/**\n * Format native amount using nu thousands separator, no locale (ie. always use \".\" (dot) for decimal separator) and PRECISION_SHORT decimals\n */\nfun formatNativeSimple(nativeAmount: Long): String\n{\n    return String.format(Locale.ROOT,\"%.${Config.PRECISION_SHORT}f\", nativeAmount.toDouble() / 100000000)\n}\n\nfun formatNative(nativeAmount: Long, useNativePrefix: Boolean = true): String\n{\n    return \"%s %s\".format(if (useNativePrefix) \"\" else \"\",\n            (DecimalFormat(\"+#,##0.00;-#\").format(nativeAmount.toDouble() / 100000000)))\n}\n\nfun formatNativeAndLocal(nativeAmount: Long, conversionRate: Double, useNativePrefix: Boolean = true, nativeFirst: Boolean = true): String\n{\n    val native = formatNative(nativeAmount, useNativePrefix)\n\n    return if (conversionRate > 0.0) {\n        val pattern = \"+#,##0.%s;-#\".format(\"0\".repeat(localCurrency.precision))\n        val local = DecimalFormat(pattern).format(conversionRate * nativeAmount.toDouble() / 100000000)\n        if (nativeFirst)\n            \"%s (%s %s)\".format(native, localCurrency.short, local)\n        else\n            \"(%s %s) %s\".format(localCurrency.short, local, native)\n    }\n    else\n        native\n}\n\n/**\n * Convert native amount to locale agnostic, ie. api/json compatible string\n */\nfun wireFormatNative(nativeAmount: Double): String {\n    return String.format(Locale.ROOT,\"%.${Config.PRECISION_FULL}f\", nativeAmount)\n}\n\nfun Double.toNative(): Long {\n    return floor(this * 100000000.0).toLong()\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/LicenseActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport kotlinx.android.synthetic.main.activity_license.*\nimport org.apache.commons.io.IOUtils\n\n\nclass LicenseActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_license)\n        val inStream = resources.openRawResource(R.raw.license)\n        licenseTextView.text = IOUtils.toString(inStream, \"utf-8\")\n        inStream.close()\n\n        backButton.setOnClickListener{\n            onBackButtonPushed(it)\n        }\n    }\n\n    private fun onBackButtonPushed(view: View) {\n        finish()\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/SendCoinsFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.app.Activity\nimport android.app.Dialog\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.os.Bundle\nimport android.text.SpannableString\nimport android.text.style.ImageSpan\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.Button\nimport android.widget.EditText\nimport android.widget.TextView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.constraintlayout.widget.ConstraintLayout\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport unity_wallet.jniunifiedbackend.AddressRecord\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.UriRecipient\nimport unity_wallet.Config.Companion.PRECISION_SHORT\nimport unity_wallet.R.layout.text_input_address_label\nimport unity_wallet.ui.getDisplayDimensions\nimport unity_wallet.util.invokeNowOrOnSuccessfulCompletion\nimport kotlinx.android.synthetic.main.fragment_send_coins.view.*\nimport kotlinx.android.synthetic.main.text_input_address_label.view.*\nimport kotlinx.coroutines.*\nimport kotlin.coroutines.CoroutineContext\n\n\nclass SendCoinsFragment : BottomSheetDialogFragment(), CoroutineScope\n{\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    private var localRate: Double = 0.0\n    private lateinit var recipient: UriRecipient\n    private var foreignCurrency = localCurrency\n    private enum class EntryMode {\n        Native,\n        Local\n    }\n    private var entryMode = EntryMode.Native\n        set(value)\n        {\n            field = value\n            var nativeIcon = SpannableString(\" \")\n            nativeIcon.setSpan(ImageSpan(requireContext(), R.drawable.ic_logo_white), 0, 1, 0)\n            when (entryMode)\n            {\n                EntryMode.Local -> mMainlayout.findViewById<TextView>(R.id.button_currency).text = nativeIcon;\n                EntryMode.Native -> mMainlayout.findViewById<TextView>(R.id.button_currency).text = foreignCurrency.short\n            }\n        }\n    private var amountEditStr: String = \"0\"\n        set(value) {\n            field = value\n            updateDisplayAmount()\n        }\n\n    private val amount: Double\n        get() = amountEditStr.toDoubleOrZero()\n\n    private val foreignAmount: Double\n        get() {\n            return when (entryMode) {\n                EntryMode.Local -> amountEditStr.toDoubleOrZero()\n                EntryMode.Native -> amountEditStr.toDoubleOrZero() * localRate\n            }\n        }\n\n    private val recipientDisplayAddress: String\n        get () {\n            return if (recipient.label.isEmpty()) recipient.address else \"${recipient.label} (${recipient.address})\"\n        }\n\n\n    companion object {\n        const val EXTRA_RECIPIENT = \"recipient\"\n        const val EXTRA_FINISH_ACTIVITY_ON_CLOSE = \"finish_on_close\"\n        fun newInstance(recipient: UriRecipient, finishActivityOnClose : Boolean) = SendCoinsFragment().apply {\n            arguments = Bundle().apply {\n                putParcelable(EXTRA_RECIPIENT, recipient)\n                putBoolean(EXTRA_FINISH_ACTIVITY_ON_CLOSE, finishActivityOnClose)\n            }\n        }\n    }\n\n    private lateinit var fragmentActivity : Activity\n\n    private var mBehavior: BottomSheetBehavior<*>? = null\n    private lateinit var mSendCoinsReceivingStaticAddress : TextView\n    private lateinit var mSendCoinsReceivingStaticLabel : TextView\n    private lateinit var mLabelRemoveFromAddressBook : TextView\n    private lateinit var mLabelAddToAddressBook : TextView\n    private lateinit var mMainlayout : View\n\n    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog\n    {\n        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog\n        mMainlayout = View.inflate(context, R.layout.fragment_send_coins, null)\n\n        // test layout using display dimens\n        val outSize = getDisplayDimensions(requireContext())\n        mMainlayout.measure(outSize.x, outSize.y)\n\n        // height that the entire bottom sheet wants to be\n        val preferredHeight = mMainlayout.measuredHeight\n\n        // maximum height that we allow it to be, to be sure that the balance shows through (if not hidden)\n        val allowedHeight = outSize.y - requireContext().resources.getDimensionPixelSize(R.dimen.top_space_send_coins)\n\n        // programmatically adjust layout, only if needed\n        if (preferredHeight > allowedHeight) {\n            // for the preferredHeight numeric_keypad is square due to the ratio constraint, squeeze it to fit allowed height\n            val newHeight = outSize.x - (preferredHeight - allowedHeight)\n\n            // setup new layout params, stripping ratio constaint and adding newly calculatied height\n            val params = mMainlayout.numeric_keypad_holder.layoutParams as ConstraintLayout.LayoutParams\n            params.dimensionRatio = null\n            params.height = newHeight\n            params.matchConstraintMaxHeight = newHeight\n\n            // apply new layout\n            mMainlayout.numeric_keypad_holder.layoutParams = params\n        }\n\n        mSendCoinsReceivingStaticAddress = mMainlayout.findViewById(R.id.send_coins_receiving_static_address)\n        mSendCoinsReceivingStaticLabel = mMainlayout.findViewById(R.id.send_coins_receiving_static_label)\n        mLabelRemoveFromAddressBook = mMainlayout.findViewById(R.id.labelRemoveFromAddressBook)\n        mLabelAddToAddressBook = mMainlayout.findViewById(R.id.labelAddToAddressBook)\n        mSendCoinsReceivingStaticAddress = mMainlayout.findViewById(R.id.send_coins_receiving_static_address)\n\n        mMainlayout.findViewById<View>(R.id.button_0).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_1).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_2).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_3).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_4).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_5).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_6).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_7).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_8).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_9).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_send).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_currency).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_decimal).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_backspace).setOnClickListener { view -> handleKeypadButtonClick(view) }\n        mMainlayout.findViewById<View>(R.id.button_backspace).setOnLongClickListener { view -> handleKeypadButtonLongClick(view) }\n        mMainlayout.findViewById<View>(R.id.labelAddToAddressBook).setOnClickListener { view -> handleAddToAddressBookClick(view) }\n        mMainlayout.findViewById<View>(R.id.labelRemoveFromAddressBook).setOnClickListener { view -> handleRemoveFromAddressBookClick(view) }\n\n\n        dialog.setContentView(mMainlayout)\n\n        mBehavior = BottomSheetBehavior.from(mMainlayout.parent as View)\n\n        return dialog\n    }\n\n    override fun onStart()\n    {\n        super.onStart()\n\n        mBehavior!!.skipCollapsed = true\n        mBehavior!!.state = BottomSheetBehavior.STATE_EXPANDED\n    }\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n    {\n        val view = super.onCreateView(inflater, container, savedInstanceState)\n\n\n        fragmentActivity = super.requireActivity()\n\n        arguments?.getParcelable<UriRecipient>(EXTRA_RECIPIENT)?.let {\n            recipient = it\n        }\n\n        if (recipient.amount != 0L)\n            amountEditStr = formatNativeSimple(recipient.amount)\n        updateDisplayAmount()\n\n        mSendCoinsReceivingStaticAddress.text = recipient.address\n\n        setAddressLabel(recipient.label)\n\n        foreignCurrency = localCurrency\n\n        setupRate()\n\n        return view\n    }\n\n    private fun updateDisplayAmount() {\n        var primaryStr = \"\"\n        var secondaryStr = \"\"\n        val amount = amountEditStr.toDoubleOrZero()\n        val primaryTextView = (mMainlayout.findViewById<View>(R.id.send_coins_amount_primary) as TextView?)\n        val secondaryTextView = (mMainlayout.findViewById<View>(R.id.send_coins_amount_secondary) as TextView?)\n        when (entryMode) {\n            EntryMode.Native -> {\n                primaryStr = \"%s\".format(amountEditStr)\n                if (localRate > 0.0) {\n                    secondaryStr = String.format(\"(%s %.${foreignCurrency.precision}f)\", foreignCurrency.short, localRate * amount)\n                }\n            }\n            EntryMode.Local -> {\n                primaryStr = \"%s %s\".format(foreignCurrency.short, amountEditStr)\n                if (localRate > 0.0) {\n                    secondaryStr = String.format(\"(%.${PRECISION_SHORT}f)\", amount / localRate)\n                }\n            }\n        }\n        primaryTextView?.text = primaryStr\n        secondaryTextView?.text = secondaryStr\n    }\n\n    private fun performAuthenticatedPayment(d : Dialog, request : UriRecipient, msg: String?, subtractFee: Boolean = false)\n    {\n        val amountStr = String.format(\"%.${PRECISION_SHORT}f\", request.amount.toDouble() / 100000000)\n        val message = msg ?: getString(R.string.send_coins_confirm_template, amountStr, recipientDisplayAddress)\n        Authentication.instance.authenticate(this@SendCoinsFragment.requireActivity(),\n                null, msg = message) {\n            try {\n                ILibraryController.performPaymentToRecipient(request, subtractFee)\n                d.dismiss()\n            }\n            catch (exception: RuntimeException) {\n                errorMessage(exception.message!!)\n            }\n        }\n    }\n\n    private fun confirmAndCommitCoinPayment()\n    {\n        val amountNativeStr = when (entryMode) {\n            EntryMode.Local -> (amountEditStr.toDoubleOrZero() / localRate).toString()\n            EntryMode.Native -> amountEditStr\n        }.toDoubleOrZero()\n\n        val amountNative = amountNativeStr.toNative()\n\n        try {\n            val paymentRequest = UriRecipient(true, recipient.address, recipient.label, recipient.desc, amountNative)\n            val fee = ILibraryController.feeForRecipient(paymentRequest)\n            val balance = ILibraryController.GetBalance()\n            if (fee > balance) {\n                errorMessage(getString(R.string.send_insufficient_balance))\n                return\n            }\n            if (fee + amountNative > balance) {\n                // alert dialog for confirmation of payment and reduction of amount since amount + fee exceeds balance\n                MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(getString(R.string.send_all_instead_title))\n                        .setMessage(getString(R.string.send_all_instead_msg))\n                        // on confirmation compose recipient with reduced amount and execute payment with subtractFee fee from amount\n                        .setPositiveButton(getString(R.string.send_all_btn)) { dialogInterface: DialogInterface, i: Int ->\n                            val sendAllRequest = UriRecipient(true, recipient.address, recipient.label, recipient.desc, balance)\n                            performAuthenticatedPayment(dialog!!, sendAllRequest, null,true)\n                        }\n                        .setNegativeButton(getString(R.string.cancel_btn)) { dialogInterface: DialogInterface, i: Int -> }\n                        .show()\n            } else {\n                // create styled message from resource template and arguments bundle\n                val amountStr = String.format(\"%.${PRECISION_SHORT}f\", amountNativeStr)\n                val message = getString(R.string.send_coins_confirm_template, amountStr, recipientDisplayAddress)\n\n                // alert dialog for confirmation\n                MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(getString(R.string.send_coins_title))\n                        .setMessage(message)\n                        // on confirmation compose recipient and execute payment\n                        .setPositiveButton(getString(R.string.send_btn)) { dialogInterface: DialogInterface, i: Int ->\n                            performAuthenticatedPayment(dialog!!, paymentRequest, null,false)\n                        }\n                        .setNegativeButton(getString(R.string.cancel_btn)) { dialogInterface: DialogInterface, i: Int -> }\n                        .show()\n            }\n        } catch (exception: RuntimeException) {\n            errorMessage(exception.message!!)\n        }\n    }\n\n    private fun errorMessage(msg: String) {\n        MaterialAlertDialogBuilder(requireContext())\n                .setTitle(getString(R.string.send_coins_title))\n                .setMessage(msg)\n                // on confirmation compose recipient and execute payment\n                .setPositiveButton(getString(R.string.send_coins_error_acknowledge)) { dialogInterface: DialogInterface, i: Int ->\n                }\n                .show()\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n\n        coroutineContext[Job]!!.cancel()\n\n        // Let the invisible URI activity know to close itself\n        arguments?.getBoolean(EXTRA_FINISH_ACTIVITY_ON_CLOSE)?.let {\n            if (it) {\n                activity?.moveTaskToBack(true)\n                activity?.finish()\n            }\n        }\n    }\n\n    private fun setupRate()\n    {\n        entryMode = EntryMode.Native\n\n        this.launch( Dispatchers.Main) {\n            try {\n                localRate = fetchCurrencyRate(foreignCurrency.code)\n            }\n            catch (e: Throwable) {\n                entryMode = EntryMode.Native\n            }\n            updateDisplayAmount()\n        }\n    }\n\n    private fun setAddressLabel(label : String)\n    {\n        mSendCoinsReceivingStaticLabel.text = label\n\n        if (label.isNotEmpty()) {\n            mSendCoinsReceivingStaticLabel.visibility = View.VISIBLE\n            mLabelRemoveFromAddressBook.visibility = View.INVISIBLE // use for layout already, when wallet is ready will become visible (or will be switched to add to address book)\n            mLabelAddToAddressBook.visibility = View.GONE\n        }\n        else {\n            mSendCoinsReceivingStaticLabel.visibility = View.GONE\n            mLabelRemoveFromAddressBook.visibility = View.GONE\n            mLabelAddToAddressBook.visibility = View.INVISIBLE // use for layout already, will become visible when wallet is ready\n        }\n\n        UnityCore.instance.walletReady.invokeNowOrOnSuccessfulCompletion(this) {\n            if (label.isNotEmpty())\n            {\n                val isInAddressBook = ILibraryController.getAddressBookRecords().count { it.name.equals(other = label, ignoreCase = true) } > 0\n                if (isInAddressBook) {\n                    mLabelRemoveFromAddressBook.visibility = View.VISIBLE\n                    mLabelAddToAddressBook.visibility = View.GONE\n                }\n                else {\n                    mLabelRemoveFromAddressBook.visibility = View.GONE\n                    mLabelAddToAddressBook.visibility = View.VISIBLE\n                }\n            }\n            else\n            {\n                mLabelRemoveFromAddressBook.visibility = View.GONE\n                mLabelAddToAddressBook.visibility = View.VISIBLE\n            }\n        }\n    }\n\n    private fun allowedDecimals(): Int {\n        return when(entryMode) {\n            EntryMode.Native -> PRECISION_SHORT\n            EntryMode.Local -> foreignCurrency.precision\n        }\n    }\n\n    private fun numFractionalDigits(amount:String): Int {\n        val pos = amount.indexOfLast { it == '.' }\n        return if (pos > 0) amount.length - pos - 1 else 0\n    }\n\n    private fun numWholeDigits(amount:String): Int {\n        val pos = amount.indexOfFirst { it == '.' }\n        return if (pos > 0) pos else amount.length\n    }\n\n    private fun chopExcessDecimals() {\n        if (numFractionalDigits(amountEditStr) > allowedDecimals()) {\n            amountEditStr = amountEditStr.substring(0, amountEditStr.length - (numFractionalDigits(amountEditStr) - allowedDecimals()))\n        }\n    }\n\n    private fun appendNumberToAmount(number : String) {\n        if (amountEditStr == \"0\")\n        {\n            amountEditStr = number\n        }\n        else\n        {\n            if (!amountEditStr.contains(\".\"))\n            {\n                if (numWholeDigits(amountEditStr) < 8)\n                {\n                    amountEditStr += number\n                }\n            }\n            else if (numFractionalDigits(amountEditStr) < allowedDecimals())\n            {\n                amountEditStr += number\n            }\n            else\n            {\n                if (numFractionalDigits(amountEditStr) < allowedDecimals())\n                {\n                    amountEditStr += number\n                }\n                else\n                {\n                    if (numWholeDigits(amountEditStr) < 8)\n                    {\n                        amountEditStr = buildString {\n                            append(amountEditStr)\n                            deleteCharAt(lastIndexOf(\".\"))\n                            append(number)\n                            insert(length - allowedDecimals(), \".\")\n                        }.trimStart('0')\n                    }\n                }\n            }\n        }\n    }\n\n    private fun handleKeypadButtonLongClick(view : View) : Boolean\n    {\n        when (view.id)\n        {\n            R.id.button_backspace ->\n            {\n                amountEditStr = \"0\"\n            }\n        }\n        return true\n    }\n\n    private fun handleSendButton()\n    {\n        if (!UnityCore.instance.walletReady.isCompleted) {\n            errorMessage(getString(R.string.core_not_ready_yet))\n            return\n        }\n\n        run {\n            if ((amountEditStr.isEmpty()) || (foreignAmount<=0 && amount<=0))\n            {\n                errorMessage(\"Enter an amount to pay\")\n                return@run\n            }\n\n            confirmAndCommitCoinPayment()\n        }\n    }\n\n    private fun handleKeypadButtonClick(view : View)\n    {\n        when (view.id)\n        {\n            R.id.button_1 -> appendNumberToAmount(\"1\")\n            R.id.button_2 -> appendNumberToAmount(\"2\")\n            R.id.button_3 -> appendNumberToAmount(\"3\")\n            R.id.button_4 -> appendNumberToAmount(\"4\")\n            R.id.button_5 -> appendNumberToAmount(\"5\")\n            R.id.button_6 -> appendNumberToAmount(\"6\")\n            R.id.button_7 -> appendNumberToAmount(\"7\")\n            R.id.button_8 -> appendNumberToAmount(\"8\")\n            R.id.button_9 -> appendNumberToAmount(\"9\")\n            R.id.button_0 ->\n            {\n                if (amountEditStr.isEmpty()) amountEditStr += \"0.\"\n                else if (amountEditStr != \"0\" && amountEditStr != \"0.00\") appendNumberToAmount(\"0\")\n            }\n            R.id.button_backspace ->\n            {\n                amountEditStr = if (amountEditStr.length > 1)\n                    amountEditStr.dropLast(1)\n                else\n                    \"0\"\n            }\n            R.id.button_decimal ->\n            {\n                if (!amountEditStr.contains(\".\"))\n                {\n                    amountEditStr = if (amountEditStr.isEmpty()) \"0.\"\n                    else \"$amountEditStr.\"\n                }\n            }\n            R.id.button_currency ->\n            {\n                entryMode = when (entryMode) {\n                    EntryMode.Local -> EntryMode.Native\n                    EntryMode.Native -> EntryMode.Local\n                }\n                chopExcessDecimals()\n                updateDisplayAmount()\n            }\n            R.id.button_send ->\n            {\n                handleSendButton()\n            }\n\n        }\n    }\n\n    private fun handleAddToAddressBookClick(view : View)\n    {\n        if (!UnityCore.instance.walletReady.isCompleted) {\n            errorMessage(getString(R.string.core_not_ready_yet))\n            return\n        }\n\n        val builder = AlertDialog.Builder(fragmentActivity)\n        builder.setTitle(getString(R.string.dialog_title_add_address))\n        val layoutInflater : LayoutInflater = fragmentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater\n        val viewInflated : View = layoutInflater.inflate(text_input_address_label, view.rootView as ViewGroup, false)\n        viewInflated.labelAddAddressAddress.text = mSendCoinsReceivingStaticAddress.text\n        val input = viewInflated.findViewById(R.id.addAddressInput) as EditText\n        if (recipient.label.isNotEmpty()) {\n            input.setText(recipient.label)\n        }\n        builder.setView(viewInflated)\n        builder.setPositiveButton(android.R.string.ok) { dialog, _ ->\n            dialog.dismiss()\n            val label = input.text.toString()\n            val record = AddressRecord(mSendCoinsReceivingStaticAddress.text.toString(), label, \"\", \"Send\")\n            UnityCore.instance.addAddressBookRecord(record)\n            setAddressLabel(label)\n        }\n        builder.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.cancel() }\n        val dialog = builder.create()\n        dialog.setOnShowListener {\n            viewInflated.addAddressInput.requestFocus()\n            viewInflated.addAddressInput.post {\n                val imm = fragmentActivity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                imm.showSoftInput(viewInflated.addAddressInput, InputMethodManager.SHOW_IMPLICIT)\n            }\n        }\n        dialog.show()\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun handleRemoveFromAddressBookClick(view : View)\n    {\n        if (!UnityCore.instance.walletReady.isCompleted) {\n            errorMessage(getString(R.string.core_not_ready_yet))\n            return\n        }\n\n        val record = AddressRecord(mSendCoinsReceivingStaticAddress.text.toString(), mSendCoinsReceivingStaticLabel.text.toString(), \"\", \"Send\")\n        UnityCore.instance.deleteAddressBookRecord(record)\n        setAddressLabel(\"\")\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/TransactionInfoActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.TextView\nimport androidx.core.content.ContextCompat\nimport unity_wallet.jniunifiedbackend.MonitorListener\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.TransactionRecord\nimport unity_wallet.jniunifiedbackend.TransactionStatus\nimport unity_wallet.util.AppBaseActivity\nimport kotlinx.android.synthetic.main.activity_transaction_info.*\nimport kotlinx.android.synthetic.main.content_transaction_info.*\nimport kotlinx.android.synthetic.main.transaction_info_item.view.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\n\nclass TransactionInfoActivity : AppBaseActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_transaction_info)\n        setSupportActionBar(toolbar)\n    }\n\n    override fun onWalletReady() {\n        fillTxInfo()\n    }\n\n    private fun fillTxInfo() {\n        val txHash = intent.getStringExtra(EXTRA_TRANSACTION)\n        try {\n            val tx = ILibraryController.getTransaction(txHash)\n\n            // transaction id\n            transactionId.text = tx.txHash\n\n            // view transaction in browser\n            transactionId.setOnClickListener {\n                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(Config.BLOCK_EXPLORER_TX_TEMPLATE.format(tx.txHash)))\n                startActivity(intent)\n            }\n\n            // status\n            status.text = statusText(tx)\n\n            // Amount instantly\n            amount.text = formatNativeAndLocal(tx.amount, 0.0)\n            setAmountAndColor(amount, tx.amount, 0.0, true)\n\n            // inputs\n            tx.inputs.forEach { output ->\n                val v = layoutInflater.inflate(R.layout.transaction_info_item, null)\n                if (output.address.isNotEmpty())\n                    v.address.text = output.address\n                else {\n                    v.address.text = getString(R.string.tx_detail_address_unavailable)\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                        v.address.setTextAppearance(R.style.TxDetailMissing)\n                    }\n                }\n                if (output.isMine)\n                    v.subscript.text = getString(R.string.tx_detail_wallet_address)\n                else {\n                    if (output.label.isNotEmpty())\n                        v.subscript.text = output.label\n                    else\n                        v.subscript.text = getString(R.string.tx_detail_sending_address)\n                }\n                from_container.addView(v)\n            }\n\n            // Update amount and display tx output details after getting rate (or failure)\n            this.launch(Dispatchers.Main) {\n                var rate = 0.0\n                try {\n                    rate = fetchCurrencyRate(localCurrency.code)\n                } catch (e: Throwable) {\n                    // silently ignore failure of getting rate here\n                }\n\n                this@TransactionInfoActivity.setAmountAndColor(amount, tx.amount, rate, true)\n\n                // internal transfer if all inputs and outputs are mine\n                val internalTransfer = (tx.inputs.size == tx.inputs.count { it.isMine }) && (tx.outputs.size == tx.outputs.count { it.isMine })\n\n                // outputs\n                val signedByMe = tx.fee > 0\n                tx.outputs.forEach { output ->\n                    if (output.isMine && !signedByMe || internalTransfer) {\n                        val v = layoutInflater.inflate(R.layout.transaction_info_item, null)\n                        v.address.text = output.address\n                        v.subscript.text = getString(R.string.tx_detail_wallet_address)\n                        v.amount.setTextColor( ContextCompat.getColor(this@TransactionInfoActivity, R.color.change_positive))\n                        v.amount.text = formatNativeAndLocal(output.amount, rate, useNativePrefix = true, nativeFirst = false)\n                        to_container.addView(v)\n                    }\n                    else if (!output.isMine && signedByMe) {\n                        val v = layoutInflater.inflate(R.layout.transaction_info_item, null)\n                        v.address.text = output.address\n                        if (output.label.isNotEmpty())\n                            v.subscript.text = output.label\n                        else\n                            v.subscript.text = getString(R.string.tx_detail_payment_address)\n                        v.amount.setTextColor( ContextCompat.getColor(this@TransactionInfoActivity, R.color.change_negative))\n                        v.amount.text = formatNativeAndLocal(-output.amount, rate, useNativePrefix = true, nativeFirst = false)\n                        to_container.addView(v)\n                    }\n                    //else {\n                        // output.isMine && signedByMe, this is likely change so don't display\n                        // !output.isMine && !signedByMe, this is likely change for the other side or something else we don't care about\n                    //}\n                }\n\n                // fee\n                if (signedByMe) { // transaction created by me, show fee\n                    val v = layoutInflater.inflate(R.layout.transaction_info_item, null)\n                    v.address.visibility = View.GONE\n                    v.subscript.text = getString(R.string.tx_detail_network_fee)\n                    this@TransactionInfoActivity.setAmountAndColor(v.amount, -tx.fee, rate,false)\n                    to_container.addView(v)\n                }\n            }\n        }\n        catch (e: Throwable)\n        {\n            transactionId.text = getString(R.string.no_tx_details).format(txHash)\n        }\n    }\n\n    private fun setAmountAndColor(textView: TextView, nativeAmount: Long, rate: Double, nativeFirst: Boolean = true) {\n        textView.setTextColor( ContextCompat.getColor(this,\n                if (nativeAmount > 0)\n                    R.color.change_positive\n                else\n                    R.color.change_negative))\n        textView.text = formatNativeAndLocal(nativeAmount, rate, true, nativeFirst)\n    }\n\n    private fun statusText(tx: TransactionRecord): String {\n        return when (tx.status) {\n            TransactionStatus.ABANDONED -> getString(R.string.tx_status_abandoned)\n            TransactionStatus.CONFLICTED -> getString(R.string.tx_status_conflicted)\n            TransactionStatus.CONFIRMING -> getString(R.string.tx_status_confirming)\n                    .format(tx.depth, Constants.RECOMMENDED_CONFIRMATIONS)\n            TransactionStatus.UNCONFIRMED -> getString(R.string.tx_status_unconfirmed)\n            TransactionStatus.CONFIRMED -> getString(R.string.tx_status_confirmed)\n                    .format(tx.height, java.text.SimpleDateFormat(\"HH:mm\").format(java.util.Date(tx.blockTime * 1000L)))\n            else -> getString(R.string.tx_status_unknown)\n        }\n    }\n\n    override fun onSupportNavigateUp(): Boolean {\n        onBackPressed()\n        return true\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        ILibraryController.RegisterMonitorListener(monitoringListener)\n    }\n\n    override fun onPause() {\n        ILibraryController.UnregisterMonitorListener(monitoringListener)\n\n        super.onPause()\n    }\n\n    private val monitoringListener = object: MonitorListener() {\n        override fun onPruned(height: Int) {}\n\n        override fun onProcessedSPVBlocks(height: Int) {}\n\n        override fun onPartialChain(height: Int, probableHeight: Int, offset: Int) {\n            runOnUiThread {\n                val txHash = intent.getStringExtra(EXTRA_TRANSACTION)\n                try {\n                    val tx = ILibraryController.getTransaction(txHash)\n                    status.text = statusText(tx)\n                }\n                catch (e: Throwable)\n                {\n                    // silently ignore\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val EXTRA_TRANSACTION = \"transaction\"\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/URIHandlerActivity.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.widget.Toast\nimport unity_wallet.util.AppBaseActivity\n\n// URI handlers need unity core active to function - however as they may be called when app is closed it is necessary to manually start the core in some cases\n// All URI handlers therefore come via this transparent activity\n// Which takes care of detecting whether core is already active or not and then handles the URI appropriately\n\nclass URIHandlerActivity : AppBaseActivity()\n{\n    private fun toastAndExit()\n    {\n        Toast.makeText(this, getString(R.string.toast_warn_uri_attempt_before_wallet_creation), Toast.LENGTH_SHORT).show()\n        finish()\n    }\n\n    override fun onWalletCreate() {\n        toastAndExit()\n    }\n\n    private fun handleURIAndClose()\n    {\n        if ((intentUri != null) && (scheme != null))\n        {\n            try\n            {\n                val recipient = createRecipient(intentUri.toString())\n                SendCoinsFragment.newInstance(recipient, true).show(supportFragmentManager, SendCoinsFragment::class.java.simpleName)\n            }\n            catch (e : Exception)\n            {\n                //TODO: Improve error handling here\n                finish()\n            }\n        }\n    }\n\n    private var intentUri : Uri? = null\n    private var scheme : String? = null\n\n    private fun isValidCoinUri(uri: Uri?): Boolean {\n        uri?.run {\n            scheme?.run {\n                lowercase().run {\n                    return startsWith(\"munt\")\n                            || startsWith(\"iban\")\n                            || startsWith(\"sepa\")\n                }\n            }\n        }\n        return false\n    }\n\n    override fun onWalletReady() {\n\n        intentUri = intent.data\n        scheme = intentUri?.scheme\n        if (Intent.ACTION_VIEW == intent.action && isValidCoinUri(intentUri)) {\n            handleURIAndClose()\n        } else {\n            finish()\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/UnityCore.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.util.Log\nimport unity_wallet.jniunifiedbackend.*\nimport kotlinx.coroutines.CompletableDeferred\nimport java.util.concurrent.locks.Lock\nimport java.util.concurrent.locks.ReentrantLock\nimport kotlin.concurrent.thread\nimport kotlin.concurrent.withLock\n\nprivate const val TAG = \"unity_core\"\n\ndata class UnityConfig(val dataDir: String, val apkPath: String, val staticFilterOffset: Long, val staticFilterLength: Long, val testnet: Boolean)\n\nclass UnityCore {\n    val walletReady\n        get() = intWalletReady\n    val walletCreate\n        get() = intWalletCreate\n\n    private var intWalletReady = CompletableDeferred<Unit>()\n    private var intWalletCreate = CompletableDeferred<Unit>()\n\n    interface Observer {\n        fun syncProgressChanged(percent: Float) {}\n        fun walletBalanceChanged(balance: Long) {}\n        fun onCoreShutdown() {}\n        fun onNewMutation(mutation: MutationRecord, selfCommitted: Boolean) {}\n        fun updatedTransaction(transaction: TransactionRecord) {}\n        fun onAddressBookChanged() {}\n    }\n\n    companion object {\n        val instance: UnityCore = UnityCore()\n        // Have we previously been started\n        var started = false\n    }\n\n    @Synchronized\n    fun configure(_config: UnityConfig) {\n        if (config != null)\n            throw RuntimeException(\"Can only configure once\")\n        config = _config\n    }\n\n    fun addObserver(observer: Observer, wrapper: (() -> Unit)-> Unit = fun (body: () -> Unit) { body() }) {\n        observersLock.withLock {\n            observers.add(ObserverEntry(observer, wrapper))\n        }\n    }\n\n    fun removeObserver(observer: Observer) {\n        observersLock.withLock {\n            observers.removeAll(\n                observers.filter { it.observer == observer }.toSet()\n            )\n        }\n    }\n\n    @Synchronized\n    fun startCore() {\n        if (!started) {\n            if (config == null)\n                throw RuntimeException(\"Configure before starting Unity core\")\n\n            val cfg: UnityConfig = config as UnityConfig\n\n            thread(true)\n            {\n                // Use this sleep to delay loading of the library. This will catch most of premature usage of\n                // Unity API calls which will then blow up by an unsatisfied link error.\n                // Thread.sleep(10000)\n                System.loadLibrary(\"_unity_jni\")\n                buildInfo = ILibraryController.BuildInfo()\n                Log.i(TAG, \"Unity library loaded: $buildInfo\")\n                ILibraryController.InitUnityLib(cfg.dataDir, cfg.apkPath, cfg.staticFilterOffset, cfg.staticFilterLength, cfg.testnet, true, coreLibrarySignalHandler, \"\")\n            }\n\n            started = true\n        }\n    }\n\n    var buildInfo = \"lib not loaded (yet?)\"\n\n    fun isCoreReady(): Boolean {\n        val deferred = walletReady\n        return deferred.isCompleted && !deferred.isCancelled\n    }\n\n    private var config: UnityConfig? = null\n\n    class ObserverEntry(val observer: Observer, val wrapper: (() ->Unit) -> Unit)\n    private var observersLock: Lock = ReentrantLock()\n    private var observers: MutableSet<ObserverEntry> = mutableSetOf()\n\n    private var stateTrackLock:  Lock = ReentrantLock()\n\n    val progressPercent: Float\n        get() {\n            return ILibraryController.getUnifiedProgress() * 100\n        }\n\n    var balanceAmount: Long = 0\n        set(value) {\n            stateTrackLock.withLock {\n                field = value\n            }\n        }\n        get() {\n            stateTrackLock.withLock {\n                return field\n            }\n        }\n\n    // TODO wrappers here could be moved into core later\n    fun addAddressBookRecord(record: AddressRecord) {\n        ILibraryController.addAddressBookRecord(record)\n        coreLibrarySignalHandler.notifyAddressBookChanged()\n    }\n\n    fun deleteAddressBookRecord(record: AddressRecord) {\n        ILibraryController.deleteAddressBookRecord(record)\n        coreLibrarySignalHandler.notifyAddressBookChanged()\n    }\n\n    fun addMonitorObserver(observer: MonitorListener, wrapper: (() -> Unit)-> Unit = fun (body: () -> Unit) { body() }) {\n        monitorObserversLock.withLock {\n            monitorObservers.add(MonitorObserverEntry(observer, wrapper))\n        }\n    }\n\n    fun removeMonitorObserver(observer: MonitorListener) {\n        monitorObserversLock.withLock {\n            monitorObservers.removeAll(\n                monitorObservers.filter { it.observer == observer }.toSet()\n            )\n        }\n    }\n\n    class MonitorObserverEntry(val observer: MonitorListener, val wrapper: (() ->Unit) -> Unit)\n    private var monitorObserversLock: Lock = ReentrantLock()\n    private var monitorObservers: MutableSet<MonitorObserverEntry> = mutableSetOf()\n\n    private val monitorHandler = object: MonitorListener() {\n        override fun onPartialChain(height: Int, probableHeight: Int, offset: Int) {\n            monitorObserversLock.withLock {\n                monitorObservers.forEach {\n                    it.wrapper { it.observer.onPartialChain(height, probableHeight, offset)}\n                }\n            }\n        }\n\n        override fun onPruned(height: Int) {\n            monitorObserversLock.withLock {\n                monitorObservers.forEach {\n                    it.wrapper { it.observer.onPruned(height)}\n                }\n            }\n        }\n\n        override fun onProcessedSPVBlocks(height: Int) {\n            monitorObserversLock.withLock {\n                monitorObservers.forEach {\n                    it.wrapper { it.observer.onProcessedSPVBlocks(height)}\n                }\n            }\n        }\n\n    }\n\n    // Handle signals from core library, convert and broadcast to all registered observers\n    private val coreLibrarySignalHandler = object : ILibraryListener() {\n        override fun logPrint(str: String?) {\n            // logging already done at C++ level\n        }\n\n        override fun notifyUnifiedProgress(progress: Float) {\n            val percent: Float = 100 * progress\n\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper { it.observer.syncProgressChanged(percent) }\n                }\n            }\n        }\n\n        override fun notifyBalanceChange(newBalance: BalanceRecord) {\n            balanceAmount = newBalance.availableIncludingLocked + newBalance.immatureIncludingLocked + newBalance.unconfirmedIncludingLocked\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper {\n                        it.observer.walletBalanceChanged(balanceAmount)\n                    }\n                }\n            }\n        }\n\n        override fun notifyNewMutation(mutation: MutationRecord, selfCommitted: Boolean) {\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper { it.observer.onNewMutation(mutation, selfCommitted) }\n                }\n            }\n        }\n\n        override fun notifyUpdatedTransaction(transaction: TransactionRecord) {\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper { it.observer.updatedTransaction(transaction) }\n                }\n            }\n        }\n\n        override fun notifyShutdown() {\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper { it.observer.onCoreShutdown() }\n                }\n            }\n        }\n\n        override fun notifyCoreReady() {\n            try {\n                // We have a functioning wallet, there will never be a notifyInitWithoutExistingWallet event,\n                // so cancel the current walletCreate. Though it might have completed already, so create a new\n                // one and cancel that as well.\n                intWalletCreate.cancel()\n                intWalletCreate = CompletableDeferred<Unit>()\n                intWalletCreate.cancel()\n                walletReady.complete(Unit)\n            }\n            catch (e: Throwable) {\n                Log.e(TAG, \"Exception in Java/Kotlin notification handler notifyCoreReady() $e\")\n            }\n            monitorObserversLock.withLock {\n                ILibraryController.RegisterMonitorListener(monitorHandler)\n            }\n        }\n\n        override fun notifyInitWithExistingWallet() {\n            // not used\n        }\n\n        override fun notifySyncDone() {\n            //TODO: handle sync done based on this instead of our own complex logic (see desktop wallet)\n        }\n\n        override fun notifyError(error: String?) {\n            //TODO: submit a crash/analytic report here...\n        }\n\n        override fun notifyInitWithoutExistingWallet() {\n            try {\n                // There is no wallet yet. Cancel anything that is currently waiting for the wallet to get ready\n                // and put a new deferred there that can be waited on after the wallet create is properly handled.\n                intWalletReady.cancel()\n                intWalletReady = CompletableDeferred<Unit>()\n                walletCreate.complete(Unit)\n            }\n            catch (e: Throwable) {\n                Log.e(TAG, \"Exception in Java/Kotlin notification handler notifyInitWithoutExistingWallet() $e\")\n            }\n        }\n\n        /*override*/ fun notifyAddressBookChanged() {\n            observersLock.withLock {\n                observers.forEach {\n                    it.wrapper { it.observer.onAddressBookChanged() }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/UpgradeActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl), Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Build\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.view.inputmethod.InputMethodManager\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport com.google.android.material.snackbar.Snackbar\nimport kotlinx.android.synthetic.main.activity_upgrade.*\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.LegacyWalletResult\nimport unity_wallet.Constants.OLD_WALLET_PROTOBUF_FILENAME\nimport unity_wallet.util.AppBaseActivity\nimport kotlinx.android.synthetic.main.upgrade_password.view.*\nimport java.io.File\nimport kotlin.concurrent.thread\nimport kotlin.system.exitProcess\n\nclass UpgradeActivity : AppBaseActivity(), UnityCore.Observer\n{\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_upgrade)\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n\n        restartFresh.setOnClickListener{  onStartFresh(it) }\n        upgradeButton.setOnClickListener{  onUpgrade(it) }\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        UnityCore.instance.removeObserver(this)\n    }\n\n    private fun onUpgradeWithPassword(view : View, oldPassword : String)\n    {\n        thread(true)\n        {\n            val result = ILibraryController.isValidAndroidLegacyProtoWallet(filesDir.toString() + File.separator + OLD_WALLET_PROTOBUF_FILENAME, oldPassword)\n            try\n            {\n                when (result)\n                {\n                    LegacyWalletResult.ENCRYPTED_PASSWORD_REQUIRED, LegacyWalletResult.PASSWORD_INVALID -> this.runOnUiThread { Snackbar.make(view, getString(R.string.upgrade_wrong_password), Snackbar.LENGTH_LONG).show() }\n                    LegacyWalletResult.INVALID_OR_CORRUPT -> this.runOnUiThread { Snackbar.make(view, \"Unable to upgrade old wallet, contact support for assistance.\", Snackbar.LENGTH_LONG).show() }\n                    else -> chooseNewAccessCodeAndUpgrade(oldPassword, view)\n                }\n            }\n            catch (e : Exception)\n            {\n                Log.e(\"UpgradeActivity\", \"Starting upgrade activity without Unity in place, exit to retry on next run\")\n                exitProcess(1)\n            }\n        }\n    }\n\n    private var processingUpgrade = false\n    private fun onUpgrade(view: View)\n    {\n        // TODO ensure core is started and create wallet mode is active\n        // TODO fix race here that is not handled properly with the processingUpgrade bool\n        if (processingUpgrade)\n            return\n        processingUpgrade = true\n\n        thread(true)\n        {\n            when (ILibraryController.isValidAndroidLegacyProtoWallet(filesDir.toString() + File.separator + OLD_WALLET_PROTOBUF_FILENAME, \"\"))\n            {\n                LegacyWalletResult.ENCRYPTED_PASSWORD_REQUIRED ->\n                {\n                    this.runOnUiThread {\n                        val upgradeDialogView = layoutInflater.inflate(R.layout.upgrade_password, null)\n                        val dialog = MaterialAlertDialogBuilder(this)\n                                .setTitle(getString(R.string.upgrade_enter_password))\n                                .setView(upgradeDialogView)\n                                .setPositiveButton(android.R.string.ok) { dialogInterface: DialogInterface, i: Int ->\n                                    onUpgradeWithPassword(view, upgradeDialogView.password.text.toString())\n                                }\n                                .create()\n\n                        dialog.setOnShowListener {\n                            upgradeDialogView.password.requestFocus()\n                            upgradeDialogView.password.post {\n                                val imm = application.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                                imm.showSoftInput(upgradeDialogView.password, InputMethodManager.SHOW_IMPLICIT)\n                            }\n                        }\n                        dialog.show()\n                    }\n                }\n                LegacyWalletResult.VALID ->\n                {\n                    chooseNewAccessCodeAndUpgrade(\"\", view)\n                }\n                else ->\n                {\n                    this.runOnUiThread {\n                        Snackbar.make(view, \"Unable to upgrade old wallet, contact support for assistance.\", Snackbar.LENGTH_LONG).show()\n                    }\n                }\n            }\n        }\n\n        processingUpgrade = false\n    }\n\n    private fun chooseNewAccessCodeAndUpgrade(oldPassword: String, view: View) {\n        this.runOnUiThread {\n            Authentication.instance.chooseAccessCode(\n                    this,\n                    getString(R.string.access_code_choose_upgrade_title),\n                    action = { accessCode ->\n                        thread(true) {\n                            val newPassword = accessCode.joinToString(\"\")\n                            ILibraryController.InitWalletFromAndroidLegacyProtoWallet(filesDir.toString() + File.separator + OLD_WALLET_PROTOBUF_FILENAME, oldPassword, newPassword)\n                        }\n\n                        this.runOnUiThread {\n                            Snackbar.make(view, \"Wallet upgrade in progress\", Snackbar.LENGTH_LONG).show()\n                        }\n                    },\n                    cancelled = {}\n            )\n        }\n    }\n\n    override fun onWalletReady() {\n        // create marker file to indicate upgrade\n        // this prevents prompting for an upgrade again later should the user remove his wallet\n        // still the data of the old wallet is retained so if (god forbid) should something go wrong with upgrades\n        // in the field a fix can be published which could ignore the upgrade marker\n        val upgradedMarkerFile = getFileStreamPath(\"$OLD_WALLET_PROTOBUF_FILENAME.upgraded\")\n        if (!upgradedMarkerFile.exists()) {\n            val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                packageManager.getPackageInfo(packageName, 0).longVersionCode\n            } else {\n                @Suppress(\"DEPRECATION\")\n                packageManager.getPackageInfo(packageName, 0).versionCode.toLong()\n            }\n            upgradedMarkerFile.writeText(\"%d\\n\".format(versionCode))\n        }\n\n        gotoActivity(WalletActivity::class.java)\n    }\n\n    override fun onWalletCreate() {\n        // do nothing, we are supposed to sit here until the wallet was created\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onStartFresh(view: View)\n    {\n        MaterialAlertDialogBuilder(this)\n                .setTitle(getString(R.string.upgrade_start_fresh_title))\n                .setMessage(getString(R.string.upgrade_start_fresh_desription))\n                .setPositiveButton(\"Start fresh\") { dialogInterface: DialogInterface, i: Int ->\n                    gotoActivity(WelcomeActivity::class.java)\n                }\n                .show()\n    }\n\n    private fun gotoActivity(cls: Class<*> )\n    {\n        val intent = Intent(this, cls)\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)\n        startActivity(intent)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/WalletActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.widget.TextViewCompat\nimport androidx.fragment.app.Fragment\nimport androidx.preference.PreferenceManager\nimport com.android.volley.*\nimport com.android.volley.toolbox.StringRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.material.bottomnavigation.BottomNavigationView\nimport com.google.android.material.snackbar.Snackbar\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.IWalletController\nimport unity_wallet.main_activity_fragments.*\nimport unity_wallet.ui.getDisplayDimensions\nimport unity_wallet.ui.monitor.NetworkMonitorActivity\nimport unity_wallet.util.AppBaseActivity\nimport unity_wallet.util.getAndroidVersion\nimport unity_wallet.util.getDeviceName\nimport kotlinx.android.synthetic.main.activity_main.*\nimport kotlinx.android.synthetic.main.pref_about_app.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.launch\nimport org.json.JSONObject\nimport kotlin.concurrent.thread\n\n\nclass WalletActivity : UnityCore.Observer, AppBaseActivity(),\n        SharedPreferences.OnSharedPreferenceChangeListener\n{\n    override fun syncProgressChanged(percent: Float) {\n        setSyncProgress(percent)\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?)\n    {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_main)\n\n        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)\n\n        syncProgress.max = 1000000\n        syncProgressTextual.text = \"\"\n\n\n        val preferences = PreferenceManager.getDefaultSharedPreferences(this)\n        preferences.registerOnSharedPreferenceChangeListener(this)\n\n        topLayoutBarSettingsBackButton.setOnClickListener { onBackPressed() }\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n\n        try\n        {\n            coroutineContext[Job]!!.cancel()\n            val preferences = PreferenceManager.getDefaultSharedPreferences(this)\n            preferences.unregisterOnSharedPreferenceChangeListener(this)\n        }\n        catch (e : Exception)\n        {\n\n        }\n    }\n\n    override fun onStart() {\n        super.onStart()\n        UnityCore.instance.addObserver(this@WalletActivity, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n\n        if (supportFragmentManager.fragments.isEmpty()) {\n            addFragment(SendFragment(), R.id.mainLayout)\n        }\n    }\n\n    override fun onWalletReady() {\n        setSyncProgress(UnityCore.instance.progressPercent)\n        setWalletBalance(UnityCore.instance.balanceAmount)\n    }\n\n    override fun onStop() {\n        super.onStop()\n\n        UnityCore.instance.removeObserver(this)\n    }\n\n    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {\n        when (key) {\n            \"preference_local_currency\" -> {\n                setWalletBalance(UnityCore.instance.balanceAmount)\n            }\n        }\n    }\n\n    fun onRequestAdvancedSettings(view: View? = null)\n    {\n        val intent = Intent(this, NetworkMonitorActivity::class.java)\n        startActivity(intent)\n    }\n\n    fun onRequestSupport(view: View? = null)\n    {\n        try\n        {\n            val i = Intent(Intent.ACTION_SENDTO)\n            i.type = \"message/rfc822\"\n            i.data = Uri.parse(\"mailto:\")\n            i.putExtra(Intent.EXTRA_EMAIL, arrayOf(\"support@munt.org\"))\n            i.putExtra(Intent.EXTRA_SUBJECT, \"Support request\")\n            i.putExtra(Intent.EXTRA_TEXT, getDeviceName() + \" / \" + getAndroidVersion() + \" / \" +  getString(R.string.about_text_app_name) + System.getProperty(\"line.separator\") )\n            startActivity(Intent.createChooser(i, \"Send mail...\"))\n        }\n        catch (ex: android.content.ActivityNotFoundException)\n        {\n            Toast.makeText(this, \"No email app installed.\", Toast.LENGTH_SHORT).show()\n        }\n\n    }\n\n    fun onRequestLicense(view: View? = null)\n    {\n        startActivity(Intent(this, LicenseActivity::class.java))\n    }\n\n    private fun gotoPage(page: Fragment) {\n        gotoFragment(page, R.id.mainLayout)\n    }\n\n    fun pushWalletSettingsPage()\n    {\n        pushFragment(WalletSettingsFragment(), R.id.mainLayout)\n    }\n\n    fun pushCurrencyPage()\n    {\n        pushFragment(LocalCurrencyFragment(), R.id.mainLayout)\n    }\n\n    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->\n        val page =\n         when (item.itemId) {\n            R.id.navigation_send -> SendFragment()\n            R.id.navigation_receive -> ReceiveFragment()\n            R.id.navigation_transactions -> MutationFragment()\n            R.id.navigation_settings -> SettingsFragment()\n             else -> return@OnNavigationItemSelectedListener false\n        }\n        gotoPage(page)\n        true\n    }\n\n    fun performLink(linkURI: String)\n    {\n        Authentication.instance.authenticate(this, null, getString(R.string.link_wallet_auth_desc)) { password ->\n            // ReplaceWalletLinkedFromURI can be long running, so run it in a thread that isn't the UI thread.\n            thread(start = true)\n            {\n                if (!ILibraryController.ReplaceWalletLinkedFromURI(linkURI, password.joinToString(\"\")))\n                {\n                    runOnUiThread {\n                        AlertDialog.Builder(this)\n                                .setTitle(getString(R.string.no_qrsync_warning_title))\n                                .setMessage(getString(R.string.no_qrsync_warning))\n                                .setPositiveButton(getString(R.string.button_ok)) {\n                                    dialogInterface, i -> dialogInterface.dismiss()\n                                }.setCancelable(true).create().show()\n                    }\n                }\n                else\n                {\n                    runOnUiThread {\n                        Snackbar.make(View(this@WalletActivity), getString(R.string.rescan_started), Snackbar.LENGTH_SHORT).show()\n                        gotoPage(ReceiveFragment())\n                    }\n                }\n            }\n        }\n    }\n\n\n    private fun setSyncProgress(percent: Float)\n    {\n        val textualProgress = if (percent <= 0.0) getString(R.string.label_sync_progress_connecting) else getString(R.string.label_sync_progress_syncing).format(percent)\n        syncProgress.progress = (syncProgress.max * (percent/100)).toInt()\n        syncProgressTextual.text = textualProgress\n        if (percent < 100.0)\n        {\n            syncProgressTextual.visibility = View.VISIBLE\n            syncProgress.visibility = View.VISIBLE\n        }\n        else\n        {\n            syncProgressTextual.visibility = View.INVISIBLE\n            syncProgress.visibility = View.INVISIBLE\n        }\n    }\n\n    private fun setWalletBalance(balance : Long)\n    {\n        val coins = balance.toDouble() / Config.COIN\n        walletBalance.text = String.format(\"%.2f\", coins)\n        walletBalance.visibility = View.VISIBLE\n\n        this.launch( Dispatchers.Main) {\n            try {\n                val rate = fetchCurrencyRate(localCurrency.code)\n                walletBalanceLocal.text = String.format(\" (${localCurrency.short} %.${localCurrency.precision}f)\",\n                        coins * rate)\n                walletBalanceLocal.visibility = View.VISIBLE\n\n                // set auto size text if native and local amounts will not fit on a single line\n                // this will only kick in in very very rare circumstances\n                // like huge balance (> G 10M and very limited device with largest font setting)\n                // (before the sync text was moved out of balance display it was a lot easier to trigger)\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)\n                {\n                    val outSize = getDisplayDimensions(this@WalletActivity)\n                    balanceSection.measure(outSize.x, outSize.y)\n                    val preferredWidth = balanceSection.measuredWidth\n                    TextViewCompat.setAutoSizeTextTypeWithDefaults(\n                            walletBalanceLocal,\n                            if (preferredWidth > outSize.x)  TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM else TextView.AUTO_SIZE_TEXT_TYPE_NONE)\n                    balanceSection.invalidate()\n                }\n            }\n            catch (e: Throwable) {\n                walletBalanceLocal.text = \"\"\n                walletBalanceLocal.visibility = View.GONE\n            }\n        }\n    }\n\n    override fun walletBalanceChanged(balance: Long) {\n        setWalletBalance(balance)\n    }\n\n    fun showSettingsTitle(title : String)\n    {\n        topLayoutBarSettingsHeader.visibility = View.VISIBLE\n        topLayoutBar.visibility = View.GONE\n        topLayoutBarSettingsTitle.text = title\n    }\n\n    fun hideSettingsTitle()\n    {\n        topLayoutBarSettingsHeader.visibility = View.GONE\n        topLayoutBar.visibility = View.VISIBLE\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun gotoBuyActivity(view : View? = null)\n    {\n        // Send a post request to blockhut with our wallet/address info; and then launch the site if we get a positive response.\n        val MyRequestQueue = Volley.newRequestQueue(this)\n        val failURL = \"https://munt.org/buy\"\n        val request = object : StringRequest(Request.Method.POST,\"https://blockhut.com/buysession.php\",\n            Response.Listener { response ->\n                try\n                {\n                    var jsonResponse = JSONObject(response)\n                    if (jsonResponse.getInt(\"status_code\") == 200)\n                    {\n                        var sessionID = jsonResponse.getString(\"sessionid\")\n                        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(\"https://blockhut.com/buy.php?sessionid=%s\".format(sessionID)))\n                        startActivity(intent)\n                    }\n                    else\n                    {\n                        // Redirect user to the default fallback site\n                        //fixme: Do something with the status message here\n                        //var statusMessage = jsonResponse.getString(\"status_message\")\n                        val intent = Intent(failURL)\n                        if (intent.resolveActivity(packageManager) != null)\n                        {\n                            startActivity(intent)\n                        }\n                    }\n                }\n                catch (e:Exception)\n                {\n                    // Redirect user to the default fallback site\n                    //fixme: Do something with the error message here\n                    val intent = Intent(failURL)\n                    startActivity(intent)\n                }\n            },\n            Response.ErrorListener\n            {\n               // If we are sure its a local connectivity issue, alert the user, otherwise send them to the default fallback site\n               if (it is NetworkError || it is AuthFailureError || it is NoConnectionError)\n               {\n                   Toast.makeText(this, getString(R.string.error_check_internet_connection), Toast.LENGTH_SHORT).show()\n               }\n               else\n               {\n                   val intent = Intent(failURL)\n                   startActivity(intent)\n               }\n            }\n        )\n        // Force values to be send at x-www-form-urlencoded\n        {\n            override fun getParams(): MutableMap<String, String> {\n                val params = HashMap<String,String>()\n                params[\"address\"] = ILibraryController.GetReceiveAddress().toString()\n                params[\"uuid\"] = IWalletController.GetUUID()\n                params[\"currency\"] = \"munt\"\n                params[\"wallettype\"] = \"android\"\n                return params\n            }\n            override fun getHeaders(): MutableMap<String, String> {\n                val params = HashMap<String, String>()\n                params.put(\"Content-Type\",\"application/x-www-form-urlencoded\")\n                return params\n            }\n        }\n\n        // Volley request policy, only one time request to avoid duplicate transaction\n        request.retryPolicy = DefaultRetryPolicy(\n                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS,\n                1, // DefaultRetryPolicy.DEFAULT_MAX_RETRIES = 2\n                1f // DefaultRetryPolicy.DEFAULT_BACKOFF_MULT\n        )\n\n        // Add the volley post request to the request queue\n        MyRequestQueue.add(request)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/WelcomeActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.View\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.vision.barcode.Barcode\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport barcodereader.BarcodeCaptureActivity\nimport kotlinx.android.synthetic.main.activity_welcome.*\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.ui.EnterRecoveryPhraseActivity\nimport unity_wallet.ui.ShowRecoveryPhraseActivity\nimport unity_wallet.util.AppBaseActivity\nimport unity_wallet.util.gotoWalletActivity\nimport kotlin.concurrent.thread\nimport kotlin.system.exitProcess\n\nclass WelcomeActivity : AppBaseActivity(), UnityCore.Observer\n{\n    private val erasedWallet = UnityCore.instance.isCoreReady()\n\n    override fun onCreate(savedInstanceState: Bundle?)\n    {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_welcome)\n\n        new_wallet_button.setOnClickListener{\n            onCreateNewWallet(it)\n        }\n\n        recover_wallet_button.setOnClickListener{\n            onRecoverExistingWallet(it)\n        }\n\n        sync_with_desktop_button.setOnClickListener{\n            onSyncWithDesktop(it)\n        }\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n    }\n\n    override fun onDestroy()\n    {\n        super.onDestroy()\n\n        UnityCore.instance.removeObserver(this)\n    }\n\n    override fun onBackPressed() {\n        super.onBackPressed()\n\n        // finish and kill myself so a next session is properly started\n        // note this is now only because of the weird wiring which happens when a wallet is erased\n        // consider introducing query API in Unity that would allow getting the erased wallet state\n        // or some other construct such that logic on the Unity client side can be clearer\n        finish()\n        exitProcess(0)\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onCreateNewWallet(view: View)\n    {\n        thread(true)\n        {\n            val recoveryMnemonic = ILibraryController.GenerateRecoveryMnemonic()\n            this.runOnUiThread()\n            {\n                val newIntent = Intent(this, ShowRecoveryPhraseActivity::class.java)\n                //TODO: (MUNT) Probably not the greatest way to do this - snooping?\n                newIntent.putExtra(this.packageName + \"recovery_phrase_with_birth\", recoveryMnemonic.phraseWithBirthNumber)\n                newIntent.putExtra(this.packageName + \"recovery_phrase\", recoveryMnemonic.phrase)\n                startActivity(newIntent)\n            }\n        }\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onSyncWithDesktop(view: View)\n    {\n        val intent = Intent(applicationContext, BarcodeCaptureActivity::class.java)\n        intent.putExtra(BarcodeCaptureActivity.AutoFocus, true)\n        startActivityForResult(intent, REQUEST_CODE_SCAN_FOR_LINK)\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)\n    {\n        // TODO must have core started and createWallet signal\n        if (requestCode == REQUEST_CODE_SCAN_FOR_LINK)\n        {\n            if (resultCode == CommonStatusCodes.SUCCESS && data != null)\n            {\n                val barcode = data.getParcelableExtra<Barcode>(BarcodeCaptureActivity.BarcodeObject)\n                Authentication.instance.chooseAccessCode(\n                        this,\n                        null,\n                        action = { password->\n                            if (UnityCore.instance.isCoreReady()) {\n                                if (ILibraryController.ContinueWalletLinkedFromURI(barcode?.displayValue, password.joinToString(\"\"))) {\n                                    gotoWalletActivity(this)\n                                    return@chooseAccessCode\n                                }\n                            } else {\n                                // Create the new wallet, a coreReady event will follow which will proceed to the main activity\n                                if (ILibraryController.InitWalletLinkedFromURI(barcode?.displayValue, password.joinToString(\"\"))) {\n                                    return@chooseAccessCode\n                                }\n                            }\n\n                            // Got here so there was an error in init or continue linked wallet\n                            val dialog = MaterialAlertDialogBuilder(this)\n                                    .setTitle(getString(R.string.no_qrsync_warning_title))\n                                    .setMessage(getString(R.string.no_qrsync_warning))\n                                    .setPositiveButton(android.R.string.ok) { dialog: DialogInterface, i: Int ->\n                                        dialog.dismiss()\n                                    }\n                                    .show()\n                        },\n                        cancelled = {}\n                )\n            }\n        }\n        else\n        {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onRecoverExistingWallet(view: View)\n    {\n        startActivity(Intent(this, EnterRecoveryPhraseActivity::class.java))\n    }\n\n    override fun onWalletReady() {\n        if (!erasedWallet)\n            gotoWalletActivity(this)\n    }\n\n    override fun onWalletCreate() {\n        // do nothing, we are supposed to sit here until the wallet was created\n    }\n\n    companion object\n    {\n        private const val REQUEST_CODE_SCAN_FOR_LINK = 0\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/AccountLinkRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/**Data record representing a link between an account and an external service (e.g. Holdin.com) */\npublic final class AccountLinkRecord {\n\n\n    /*package*/ final String mServiceName;\n\n    /*package*/ final String mServiceData;\n\n    public AccountLinkRecord(\n            String serviceName,\n            String serviceData) {\n        this.mServiceName = serviceName;\n        this.mServiceData = serviceData;\n    }\n\n    /** What service is it (each service should use a unique string to identify itself)  */\n    public String getServiceName() {\n        return mServiceName;\n    }\n\n    /** Any data unique to the service, e.g. a key used for secure communication or similar */\n    public String getServiceData() {\n        return mServiceData;\n    }\n\n    @Override\n    public String toString() {\n        return \"AccountLinkRecord{\" +\n                \"mServiceName=\" + mServiceName +\n                \",\" + \"mServiceData=\" + mServiceData +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/AccountRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\n\npublic final class AccountRecord {\n\n\n    /*package*/ final String mUUID;\n\n    /*package*/ final String mLabel;\n\n    /*package*/ final String mState;\n\n    /*package*/ final String mType;\n\n    /*package*/ final boolean mIsHD;\n\n    /*package*/ final ArrayList<AccountLinkRecord> mAccountLinks;\n\n    public AccountRecord(\n            String UUID,\n            String label,\n            String state,\n            String type,\n            boolean isHD,\n            ArrayList<AccountLinkRecord> accountLinks) {\n        this.mUUID = UUID;\n        this.mLabel = label;\n        this.mState = state;\n        this.mType = type;\n        this.mIsHD = isHD;\n        this.mAccountLinks = accountLinks;\n    }\n\n    public String getUUID() {\n        return mUUID;\n    }\n\n    public String getLabel() {\n        return mLabel;\n    }\n\n    public String getState() {\n        return mState;\n    }\n\n    public String getType() {\n        return mType;\n    }\n\n    /**Is this account 'HD' (i.e. part of what can be recovered from a recovery phrase) */\n    public boolean getIsHD() {\n        return mIsHD;\n    }\n\n    /**Has this account been linked to any other services/wallets; if so which see 'account_link_record' for more information */\n    public ArrayList<AccountLinkRecord> getAccountLinks() {\n        return mAccountLinks;\n    }\n\n    @Override\n    public String toString() {\n        return \"AccountRecord{\" +\n                \"mUUID=\" + mUUID +\n                \",\" + \"mLabel=\" + mLabel +\n                \",\" + \"mState=\" + mState +\n                \",\" + \"mType=\" + mType +\n                \",\" + \"mIsHD=\" + mIsHD +\n                \",\" + \"mAccountLinks=\" + mAccountLinks +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/AddressRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class AddressRecord implements android.os.Parcelable {\n\n\n    /*package*/ final String mAddress;\n\n    /*package*/ final String mName;\n\n    /*package*/ final String mDesc;\n\n    /*package*/ final String mPurpose;\n\n    public AddressRecord(\n            String address,\n            String name,\n            String desc,\n            String purpose) {\n        this.mAddress = address;\n        this.mName = name;\n        this.mDesc = desc;\n        this.mPurpose = purpose;\n    }\n\n    public String getAddress() {\n        return mAddress;\n    }\n\n    public String getName() {\n        return mName;\n    }\n\n    public String getDesc() {\n        return mDesc;\n    }\n\n    public String getPurpose() {\n        return mPurpose;\n    }\n\n    @Override\n    public String toString() {\n        return \"AddressRecord{\" +\n                \"mAddress=\" + mAddress +\n                \",\" + \"mName=\" + mName +\n                \",\" + \"mDesc=\" + mDesc +\n                \",\" + \"mPurpose=\" + mPurpose +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<AddressRecord> CREATOR\n        = new android.os.Parcelable.Creator<AddressRecord>() {\n        @Override\n        public AddressRecord createFromParcel(android.os.Parcel in) {\n            return new AddressRecord(in);\n        }\n\n        @Override\n        public AddressRecord[] newArray(int size) {\n            return new AddressRecord[size];\n        }\n    };\n\n    public AddressRecord(android.os.Parcel in) {\n        this.mAddress = in.readString();\n        this.mName = in.readString();\n        this.mDesc = in.readString();\n        this.mPurpose = in.readString();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeString(this.mAddress);\n        out.writeString(this.mName);\n        out.writeString(this.mDesc);\n        out.writeString(this.mPurpose);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/BalanceRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class BalanceRecord {\n\n\n    /*package*/ final long mAvailableIncludingLocked;\n\n    /*package*/ final long mAvailableExcludingLocked;\n\n    /*package*/ final long mAvailableLocked;\n\n    /*package*/ final long mUnconfirmedIncludingLocked;\n\n    /*package*/ final long mUnconfirmedExcludingLocked;\n\n    /*package*/ final long mUnconfirmedLocked;\n\n    /*package*/ final long mImmatureIncludingLocked;\n\n    /*package*/ final long mImmatureExcludingLocked;\n\n    /*package*/ final long mImmatureLocked;\n\n    /*package*/ final long mTotalLocked;\n\n    public BalanceRecord(\n            long availableIncludingLocked,\n            long availableExcludingLocked,\n            long availableLocked,\n            long unconfirmedIncludingLocked,\n            long unconfirmedExcludingLocked,\n            long unconfirmedLocked,\n            long immatureIncludingLocked,\n            long immatureExcludingLocked,\n            long immatureLocked,\n            long totalLocked) {\n        this.mAvailableIncludingLocked = availableIncludingLocked;\n        this.mAvailableExcludingLocked = availableExcludingLocked;\n        this.mAvailableLocked = availableLocked;\n        this.mUnconfirmedIncludingLocked = unconfirmedIncludingLocked;\n        this.mUnconfirmedExcludingLocked = unconfirmedExcludingLocked;\n        this.mUnconfirmedLocked = unconfirmedLocked;\n        this.mImmatureIncludingLocked = immatureIncludingLocked;\n        this.mImmatureExcludingLocked = immatureExcludingLocked;\n        this.mImmatureLocked = immatureLocked;\n        this.mTotalLocked = totalLocked;\n    }\n\n    public long getAvailableIncludingLocked() {\n        return mAvailableIncludingLocked;\n    }\n\n    public long getAvailableExcludingLocked() {\n        return mAvailableExcludingLocked;\n    }\n\n    public long getAvailableLocked() {\n        return mAvailableLocked;\n    }\n\n    public long getUnconfirmedIncludingLocked() {\n        return mUnconfirmedIncludingLocked;\n    }\n\n    public long getUnconfirmedExcludingLocked() {\n        return mUnconfirmedExcludingLocked;\n    }\n\n    public long getUnconfirmedLocked() {\n        return mUnconfirmedLocked;\n    }\n\n    public long getImmatureIncludingLocked() {\n        return mImmatureIncludingLocked;\n    }\n\n    public long getImmatureExcludingLocked() {\n        return mImmatureExcludingLocked;\n    }\n\n    public long getImmatureLocked() {\n        return mImmatureLocked;\n    }\n\n    public long getTotalLocked() {\n        return mTotalLocked;\n    }\n\n    @Override\n    public String toString() {\n        return \"BalanceRecord{\" +\n                \"mAvailableIncludingLocked=\" + mAvailableIncludingLocked +\n                \",\" + \"mAvailableExcludingLocked=\" + mAvailableExcludingLocked +\n                \",\" + \"mAvailableLocked=\" + mAvailableLocked +\n                \",\" + \"mUnconfirmedIncludingLocked=\" + mUnconfirmedIncludingLocked +\n                \",\" + \"mUnconfirmedExcludingLocked=\" + mUnconfirmedExcludingLocked +\n                \",\" + \"mUnconfirmedLocked=\" + mUnconfirmedLocked +\n                \",\" + \"mImmatureIncludingLocked=\" + mImmatureIncludingLocked +\n                \",\" + \"mImmatureExcludingLocked=\" + mImmatureExcludingLocked +\n                \",\" + \"mImmatureLocked=\" + mImmatureLocked +\n                \",\" + \"mTotalLocked=\" + mTotalLocked +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/BannedPeerRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class BannedPeerRecord {\n\n\n    /*package*/ final String mAddress;\n\n    /*package*/ final long mBannedUntil;\n\n    /*package*/ final long mBannedFrom;\n\n    /*package*/ final String mReason;\n\n    public BannedPeerRecord(\n            String address,\n            long bannedUntil,\n            long bannedFrom,\n            String reason) {\n        this.mAddress = address;\n        this.mBannedUntil = bannedUntil;\n        this.mBannedFrom = bannedFrom;\n        this.mReason = reason;\n    }\n\n    public String getAddress() {\n        return mAddress;\n    }\n\n    public long getBannedUntil() {\n        return mBannedUntil;\n    }\n\n    public long getBannedFrom() {\n        return mBannedFrom;\n    }\n\n    public String getReason() {\n        return mReason;\n    }\n\n    @Override\n    public String toString() {\n        return \"BannedPeerRecord{\" +\n                \"mAddress=\" + mAddress +\n                \",\" + \"mBannedUntil=\" + mBannedUntil +\n                \",\" + \"mBannedFrom=\" + mBannedFrom +\n                \",\" + \"mReason=\" + mReason +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/BlockInfoRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class BlockInfoRecord {\n\n\n    /*package*/ final int mHeight;\n\n    /*package*/ final long mTimeStamp;\n\n    /*package*/ final String mBlockHash;\n\n    public BlockInfoRecord(\n            int height,\n            long timeStamp,\n            String blockHash) {\n        this.mHeight = height;\n        this.mTimeStamp = timeStamp;\n        this.mBlockHash = blockHash;\n    }\n\n    public int getHeight() {\n        return mHeight;\n    }\n\n    public long getTimeStamp() {\n        return mTimeStamp;\n    }\n\n    public String getBlockHash() {\n        return mBlockHash;\n    }\n\n    @Override\n    public String toString() {\n        return \"BlockInfoRecord{\" +\n                \"mHeight=\" + mHeight +\n                \",\" + \"mTimeStamp=\" + mTimeStamp +\n                \",\" + \"mBlockHash=\" + mBlockHash +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IAccountsController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** C++ interface to control accounts */\npublic abstract class IAccountsController {\n    /** Register listener to be notified of account related events */\n    public static void setListener(IAccountsListener accountslistener)\n    {\n        CppProxy.setListener(accountslistener);\n    }\n\n    /** List all currently visible accounts in the wallet */\n    public static ArrayList<AccountRecord> listAccounts()\n    {\n        return CppProxy.listAccounts();\n    }\n\n    /** Set the currently active account */\n    public static boolean setActiveAccount(String accountUUID)\n    {\n        return CppProxy.setActiveAccount(accountUUID);\n    }\n\n    /** Get the currently active account */\n    public static String getActiveAccount()\n    {\n        return CppProxy.getActiveAccount();\n    }\n\n    /** Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account */\n    public static String createAccount(String accountName, String accountType)\n    {\n        return CppProxy.createAccount(accountName,\n                                      accountType);\n    }\n\n    /** Check name of account */\n    public static String getAccountName(String accountUUID)\n    {\n        return CppProxy.getAccountName(accountUUID);\n    }\n\n    /** Rename an account */\n    public static boolean renameAccount(String accountUUID, String newAccountName)\n    {\n        return CppProxy.renameAccount(accountUUID,\n                                      newAccountName);\n    }\n\n    /** Delete an account, account remains available in background but is hidden from user */\n    public static boolean deleteAccount(String accountUUID)\n    {\n        return CppProxy.deleteAccount(accountUUID);\n    }\n\n    /**\n     * Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n     * If it is a Legacy or imported witness key or similar account then it will be gone forever\n     * Generally prefer 'deleteAccount' and use this with caution\n     */\n    public static boolean purgeAccount(String accountUUID)\n    {\n        return CppProxy.purgeAccount(accountUUID);\n    }\n\n    /** Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure.  */\n    public static String getAccountLinkURI(String accountUUID)\n    {\n        return CppProxy.getAccountLinkURI(accountUUID);\n    }\n\n    /** Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account */\n    public static String getWitnessKeyURI(String accountUUID)\n    {\n        return CppProxy.getWitnessKeyURI(accountUUID);\n    }\n\n    /**\n     * Create a new \"witness-only\" account from a previously exported URI\n     * Returns UUID on success, empty string on failiure\n     */\n    public static String createAccountFromWitnessKeyURI(String witnessKeyURI, String newAccountName)\n    {\n        return CppProxy.createAccountFromWitnessKeyURI(witnessKeyURI,\n                                                       newAccountName);\n    }\n\n    /** Get a receive address for account */\n    public static String getReceiveAddress(String accountUUID)\n    {\n        return CppProxy.getReceiveAddress(accountUUID);\n    }\n\n    /** Get list of all transactions account has been involved in */\n    public static ArrayList<TransactionRecord> getTransactionHistory(String accountUUID)\n    {\n        return CppProxy.getTransactionHistory(accountUUID);\n    }\n\n    /** Get list of mutations for account */\n    public static ArrayList<MutationRecord> getMutationHistory(String accountUUID)\n    {\n        return CppProxy.getMutationHistory(accountUUID);\n    }\n\n    /** Check balance for active account */\n    public static BalanceRecord getActiveAccountBalance()\n    {\n        return CppProxy.getActiveAccountBalance();\n    }\n\n    /** Check balance for account */\n    public static BalanceRecord getAccountBalance(String accountUUID)\n    {\n        return CppProxy.getAccountBalance(accountUUID);\n    }\n\n    /** Check balance for all accounts, returns a map of account_uuid->balance_record */\n    public static HashMap<String, BalanceRecord> getAllAccountBalances()\n    {\n        return CppProxy.getAllAccountBalances();\n    }\n\n    /**Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key) */\n    public static boolean addAccountLink(String accountUUID, String serviceName, String data)\n    {\n        return CppProxy.addAccountLink(accountUUID,\n                                       serviceName,\n                                       data);\n    }\n\n    /**Register with wallet to remove an existing link */\n    public static boolean removeAccountLink(String accountUUID, String serviceName)\n    {\n        return CppProxy.removeAccountLink(accountUUID,\n                                          serviceName);\n    }\n\n    /**List all active account links that we have previously registered */\n    public static ArrayList<AccountLinkRecord> listAccountLinks(String accountUUID)\n    {\n        return CppProxy.listAccountLinks(accountUUID);\n    }\n\n    private static final class CppProxy extends IAccountsController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native void setListener(IAccountsListener accountslistener);\n\n        public static native ArrayList<AccountRecord> listAccounts();\n\n        public static native boolean setActiveAccount(String accountUUID);\n\n        public static native String getActiveAccount();\n\n        public static native String createAccount(String accountName, String accountType);\n\n        public static native String getAccountName(String accountUUID);\n\n        public static native boolean renameAccount(String accountUUID, String newAccountName);\n\n        public static native boolean deleteAccount(String accountUUID);\n\n        public static native boolean purgeAccount(String accountUUID);\n\n        public static native String getAccountLinkURI(String accountUUID);\n\n        public static native String getWitnessKeyURI(String accountUUID);\n\n        public static native String createAccountFromWitnessKeyURI(String witnessKeyURI, String newAccountName);\n\n        public static native String getReceiveAddress(String accountUUID);\n\n        public static native ArrayList<TransactionRecord> getTransactionHistory(String accountUUID);\n\n        public static native ArrayList<MutationRecord> getMutationHistory(String accountUUID);\n\n        public static native BalanceRecord getActiveAccountBalance();\n\n        public static native BalanceRecord getAccountBalance(String accountUUID);\n\n        public static native HashMap<String, BalanceRecord> getAllAccountBalances();\n\n        public static native boolean addAccountLink(String accountUUID, String serviceName, String data);\n\n        public static native boolean removeAccountLink(String accountUUID, String serviceName);\n\n        public static native ArrayList<AccountLinkRecord> listAccountLinks(String accountUUID);\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IAccountsListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Interface to receive updates about accounts */\npublic abstract class IAccountsListener {\n    /** Notify that the active account has changed */\n    public abstract void onActiveAccountChanged(String accountUUID);\n\n    /** Notify that the active account name has changed */\n    public abstract void onActiveAccountNameChanged(String newAccountName);\n\n    /** Notify that an account name has changed */\n    public abstract void onAccountNameChanged(String accountUUID, String newAccountName);\n\n    /** Notify that a new account has been added */\n    public abstract void onAccountAdded(String accountUUID, String accountName);\n\n    /** Notify that an account has been deleted */\n    public abstract void onAccountDeleted(String accountUUID);\n\n    /** Notify that an account has been modified */\n    public abstract void onAccountModified(String accountUUID, AccountRecord accountData);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IGenerationController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** C++ interface to control generation of blocks (proof of work) */\npublic abstract class IGenerationController {\n    /** Register listener to be notified of generation related events */\n    public static void setListener(IGenerationListener generationListener)\n    {\n        CppProxy.setListener(generationListener);\n    }\n\n    /**\n     * Activate block generation (proof of work)\n     * Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n     */\n    public static boolean startGeneration(int numThreads, int numArenaThreads, String memoryLimit)\n    {\n        return CppProxy.startGeneration(numThreads,\n                                        numArenaThreads,\n                                        memoryLimit);\n    }\n\n    /** Stop any active block generation (proof of work) */\n    public static boolean stopGeneration()\n    {\n        return CppProxy.stopGeneration();\n    }\n\n    /**\n     * Get the address of the account that is used for generation by default. Empty on failiure\n     * Note that this isn't necessarily the actual generation address as there might be an override\n     * See: getGenerationOverrideAddress\n     */\n    public static String getGenerationAddress()\n    {\n        return CppProxy.getGenerationAddress();\n    }\n\n    /**\n     * Get the 'override' address for generation, if one has been set\n     * The override address, when present it used for all block generation in place of the default account address\n     */\n    public static String getGenerationOverrideAddress()\n    {\n        return CppProxy.getGenerationOverrideAddress();\n    }\n\n    /** Set an override address to use for block generation in place of the default */\n    public static boolean setGenerationOverrideAddress(String overrideAddress)\n    {\n        return CppProxy.setGenerationOverrideAddress(overrideAddress);\n    }\n\n    public static long getAvailableCores()\n    {\n        return CppProxy.getAvailableCores();\n    }\n\n    public static long getMinimumMemory()\n    {\n        return CppProxy.getMinimumMemory();\n    }\n\n    public static long getMaximumMemory()\n    {\n        return CppProxy.getMaximumMemory();\n    }\n\n    private static final class CppProxy extends IGenerationController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native void setListener(IGenerationListener generationListener);\n\n        public static native boolean startGeneration(int numThreads, int numArenaThreads, String memoryLimit);\n\n        public static native boolean stopGeneration();\n\n        public static native String getGenerationAddress();\n\n        public static native String getGenerationOverrideAddress();\n\n        public static native boolean setGenerationOverrideAddress(String overrideAddress);\n\n        public static native long getAvailableCores();\n\n        public static native long getMinimumMemory();\n\n        public static native long getMaximumMemory();\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IGenerationListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Interface to receive updates about block generation */\npublic abstract class IGenerationListener {\n    /** Signal that block generation has started */\n    public abstract void onGenerationStarted();\n\n    /** Signal that block generation has stopped */\n    public abstract void onGenerationStopped();\n\n    /** Periodically signal latest block generation statistics */\n    public abstract void onStatsUpdated(double hashesPerSecond, String hashesPerSecondUnit, double rollingHashesPerSecond, String rollingHashesPerSecondUnit, double bestHashesPerSecond, String bestHashesPerSecondUnit, double arenaSetupTime);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/ILibraryController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * The library controller is used to Init/Terminate the library, and other similar tasks.\n * It is also home to various generic utility functions that don't (yet) have a place in more specific controllers\n * Specific functionality should go in specific controllers; account related functionality -> accounts_controller, network related functionality -> network_controller and so on\n */\npublic abstract class ILibraryController {\n    /** Interface constants */\n    public static final int VERSION = 1;\n\n    /** Get the build information (ie. commit id and status) */\n    public static String BuildInfo()\n    {\n        return CppProxy.BuildInfo();\n    }\n\n    /**\n     * Start the library\n     * extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n     * NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n     * If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n     */\n    public static int InitUnityLib(String dataDir, String staticFilterPath, long staticFilterOffset, long staticFilterLength, boolean testnet, boolean spvMode, ILibraryListener signalHandler, String extraArgs)\n    {\n        return CppProxy.InitUnityLib(dataDir,\n                                     staticFilterPath,\n                                     staticFilterOffset,\n                                     staticFilterLength,\n                                     testnet,\n                                     spvMode,\n                                     signalHandler,\n                                     extraArgs);\n    }\n\n    /** Threaded implementation of InitUnityLib */\n    public static void InitUnityLibThreaded(String dataDir, String staticFilterPath, long staticFilterOffset, long staticFilterLength, boolean testnet, boolean spvMode, ILibraryListener signalHandler, String extraArgs)\n    {\n        CppProxy.InitUnityLibThreaded(dataDir,\n                                      staticFilterPath,\n                                      staticFilterOffset,\n                                      staticFilterLength,\n                                      testnet,\n                                      spvMode,\n                                      signalHandler,\n                                      extraArgs);\n    }\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    public static boolean InitWalletFromRecoveryPhrase(String phrase, String password)\n    {\n        return CppProxy.InitWalletFromRecoveryPhrase(phrase,\n                                                     password);\n    }\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    public static boolean ContinueWalletFromRecoveryPhrase(String phrase, String password)\n    {\n        return CppProxy.ContinueWalletFromRecoveryPhrase(phrase,\n                                                         password);\n    }\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    public static boolean InitWalletLinkedFromURI(String linkedUri, String password)\n    {\n        return CppProxy.InitWalletLinkedFromURI(linkedUri,\n                                                password);\n    }\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    public static boolean ContinueWalletLinkedFromURI(String linkedUri, String password)\n    {\n        return CppProxy.ContinueWalletLinkedFromURI(linkedUri,\n                                                    password);\n    }\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    public static boolean InitWalletFromAndroidLegacyProtoWallet(String walletFile, String oldPassword, String newPassword)\n    {\n        return CppProxy.InitWalletFromAndroidLegacyProtoWallet(walletFile,\n                                                               oldPassword,\n                                                               newPassword);\n    }\n\n    /** Check if a file is a valid legacy proto wallet */\n    public static LegacyWalletResult isValidAndroidLegacyProtoWallet(String walletFile, String oldPassword)\n    {\n        return CppProxy.isValidAndroidLegacyProtoWallet(walletFile,\n                                                        oldPassword);\n    }\n\n    /** Check link URI for validity */\n    public static boolean IsValidLinkURI(String phrase)\n    {\n        return CppProxy.IsValidLinkURI(phrase);\n    }\n\n    /** Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet. */\n    public static boolean ReplaceWalletLinkedFromURI(String linkedUri, String password)\n    {\n        return CppProxy.ReplaceWalletLinkedFromURI(linkedUri,\n                                                   password);\n    }\n\n    /**\n     * Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n     * After calling this it will be necessary to create a new linked account or recovery phrase account again.\n     * NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n     */\n    public static boolean EraseWalletSeedsAndAccounts()\n    {\n        return CppProxy.EraseWalletSeedsAndAccounts();\n    }\n\n    /**\n     * Check recovery phrase for (syntactic) validity\n     * Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n     */\n    public static boolean IsValidRecoveryPhrase(String phrase)\n    {\n        return CppProxy.IsValidRecoveryPhrase(phrase);\n    }\n\n    /** Generate a new recovery mnemonic */\n    public static MnemonicRecord GenerateRecoveryMnemonic()\n    {\n        return CppProxy.GenerateRecoveryMnemonic();\n    }\n\n    public static String GenerateGenesisKeys()\n    {\n        return CppProxy.GenerateGenesisKeys();\n    }\n\n    /** Compute recovery phrase with birth number */\n    public static MnemonicRecord ComposeRecoveryPhrase(String mnemonic, long birthTime)\n    {\n        return CppProxy.ComposeRecoveryPhrase(mnemonic,\n                                              birthTime);\n    }\n\n    /** Stop the library */\n    public static void TerminateUnityLib()\n    {\n        CppProxy.TerminateUnityLib();\n    }\n\n    /** Generate a QR code for a string, QR code will be as close to widthHint as possible when applying simple scaling. */\n    public static QrCodeRecord QRImageFromString(String qrString, int widthHint)\n    {\n        return CppProxy.QRImageFromString(qrString,\n                                          widthHint);\n    }\n\n    /** Get a receive address for the active account */\n    public static String GetReceiveAddress()\n    {\n        return CppProxy.GetReceiveAddress();\n    }\n\n    /** Get the recovery phrase for the wallet */\n    public static MnemonicRecord GetRecoveryPhrase()\n    {\n        return CppProxy.GetRecoveryPhrase();\n    }\n\n    /** Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet) */\n    public static boolean IsMnemonicWallet()\n    {\n        return CppProxy.IsMnemonicWallet();\n    }\n\n    /** Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time) */\n    public static boolean IsMnemonicCorrect(String phrase)\n    {\n        return CppProxy.IsMnemonicCorrect(phrase);\n    }\n\n    /**\n     * Get the 'dictionary' of valid words that a recovery phrase can be composed of\n     * NB! Not all combinations of these words are valid\n     * Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n     * This function should only be used for input validation/auto-completion\n     */\n    public static ArrayList<String> GetMnemonicDictionary()\n    {\n        return CppProxy.GetMnemonicDictionary();\n    }\n\n    /** Unlock wallet; wallet will automatically relock after \"timeoutInSeconds\" */\n    public static boolean UnlockWallet(String password, long timeoutInSeconds)\n    {\n        return CppProxy.UnlockWallet(password,\n                                     timeoutInSeconds);\n    }\n\n    /** Forcefully lock wallet again */\n    public static boolean LockWallet()\n    {\n        return CppProxy.LockWallet();\n    }\n\n    public static WalletLockStatus GetWalletLockStatus()\n    {\n        return CppProxy.GetWalletLockStatus();\n    }\n\n    /** Change the wallet password */\n    public static boolean ChangePassword(String oldPassword, String newPassword)\n    {\n        return CppProxy.ChangePassword(oldPassword,\n                                       newPassword);\n    }\n\n    /** Rescan blockchain for wallet transactions */\n    public static void DoRescan()\n    {\n        CppProxy.DoRescan();\n    }\n\n    /** Check if text/address is something we are capable of sending money too */\n    public static UriRecipient IsValidRecipient(UriRecord request)\n    {\n        return CppProxy.IsValidRecipient(request);\n    }\n\n    /** Check if text/address is a native (to our blockchain) address */\n    public static boolean IsValidNativeAddress(String address)\n    {\n        return CppProxy.IsValidNativeAddress(address);\n    }\n\n    /** Check if text/address is a valid bitcoin address */\n    public static boolean IsValidBitcoinAddress(String address)\n    {\n        return CppProxy.IsValidBitcoinAddress(address);\n    }\n\n    /** Compute the fee required to send amount to given recipient */\n    public static long feeForRecipient(UriRecipient request)\n    {\n        return CppProxy.feeForRecipient(request);\n    }\n\n    /** Attempt to pay a recipient, will throw on failure with description */\n    public static PaymentResultStatus performPaymentToRecipient(UriRecipient request, boolean substractFee)\n    {\n        return CppProxy.performPaymentToRecipient(request,\n                                                  substractFee);\n    }\n\n    /**\n     * Get the wallet transaction for the hash\n     * Will throw if not found\n     */\n    public static TransactionRecord getTransaction(String txHash)\n    {\n        return CppProxy.getTransaction(txHash);\n    }\n\n    /** resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail */\n    public static String resendTransaction(String txHash)\n    {\n        return CppProxy.resendTransaction(txHash);\n    }\n\n    /** Get list of all address book entries */\n    public static ArrayList<AddressRecord> getAddressBookRecords()\n    {\n        return CppProxy.getAddressBookRecords();\n    }\n\n    /** Add a record to the address book */\n    public static void addAddressBookRecord(AddressRecord address)\n    {\n        CppProxy.addAddressBookRecord(address);\n    }\n\n    /** Delete a record from the address book */\n    public static void deleteAddressBookRecord(AddressRecord address)\n    {\n        CppProxy.deleteAddressBookRecord(address);\n    }\n\n    /** Interim persist and prune of state. Use at key moments like app backgrounding. */\n    public static void PersistAndPruneForSPV()\n    {\n        CppProxy.PersistAndPruneForSPV();\n    }\n\n    /**\n     * Reset progress notification. In cases where there has been no progress for a long time, but the process\n     * is still running the progress can be reset and will represent work to be done from this reset onwards.\n     * For example when the process is in the background on iOS for a long long time (but has not been terminated\n     * by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n     */\n    public static void ResetUnifiedProgress()\n    {\n        CppProxy.ResetUnifiedProgress();\n    }\n\n    /** Get info of last blocks (at most 32) in SPV chain */\n    public static ArrayList<BlockInfoRecord> getLastSPVBlockInfos()\n    {\n        return CppProxy.getLastSPVBlockInfos();\n    }\n\n    public static float getUnifiedProgress()\n    {\n        return CppProxy.getUnifiedProgress();\n    }\n\n    public static MonitorRecord getMonitoringStats()\n    {\n        return CppProxy.getMonitoringStats();\n    }\n\n    public static void RegisterMonitorListener(MonitorListener listener)\n    {\n        CppProxy.RegisterMonitorListener(listener);\n    }\n\n    public static void UnregisterMonitorListener(MonitorListener listener)\n    {\n        CppProxy.UnregisterMonitorListener(listener);\n    }\n\n    public static HashMap<String, String> getClientInfo()\n    {\n        return CppProxy.getClientInfo();\n    }\n\n    /**\n     * Get list of wallet mutations\n     *NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n     */\n    public static ArrayList<MutationRecord> getMutationHistory()\n    {\n        return CppProxy.getMutationHistory();\n    }\n\n    /**\n     * Get list of all transactions wallet has been involved in\n     *NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n     */\n    public static ArrayList<TransactionRecord> getTransactionHistory()\n    {\n        return CppProxy.getTransactionHistory();\n    }\n\n    /**\n     * Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n     *NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n     */\n    public static boolean HaveUnconfirmedFunds()\n    {\n        return CppProxy.HaveUnconfirmedFunds();\n    }\n\n    /**\n     * Check current wallet balance (including unconfirmed funds)\n     *NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n     */\n    public static long GetBalance()\n    {\n        return CppProxy.GetBalance();\n    }\n\n    private static final class CppProxy extends ILibraryController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native String BuildInfo();\n\n        public static native int InitUnityLib(String dataDir, String staticFilterPath, long staticFilterOffset, long staticFilterLength, boolean testnet, boolean spvMode, ILibraryListener signalHandler, String extraArgs);\n\n        public static native void InitUnityLibThreaded(String dataDir, String staticFilterPath, long staticFilterOffset, long staticFilterLength, boolean testnet, boolean spvMode, ILibraryListener signalHandler, String extraArgs);\n\n        public static native boolean InitWalletFromRecoveryPhrase(String phrase, String password);\n\n        public static native boolean ContinueWalletFromRecoveryPhrase(String phrase, String password);\n\n        public static native boolean InitWalletLinkedFromURI(String linkedUri, String password);\n\n        public static native boolean ContinueWalletLinkedFromURI(String linkedUri, String password);\n\n        public static native boolean InitWalletFromAndroidLegacyProtoWallet(String walletFile, String oldPassword, String newPassword);\n\n        public static native LegacyWalletResult isValidAndroidLegacyProtoWallet(String walletFile, String oldPassword);\n\n        public static native boolean IsValidLinkURI(String phrase);\n\n        public static native boolean ReplaceWalletLinkedFromURI(String linkedUri, String password);\n\n        public static native boolean EraseWalletSeedsAndAccounts();\n\n        public static native boolean IsValidRecoveryPhrase(String phrase);\n\n        public static native MnemonicRecord GenerateRecoveryMnemonic();\n\n        public static native String GenerateGenesisKeys();\n\n        public static native MnemonicRecord ComposeRecoveryPhrase(String mnemonic, long birthTime);\n\n        public static native void TerminateUnityLib();\n\n        public static native QrCodeRecord QRImageFromString(String qrString, int widthHint);\n\n        public static native String GetReceiveAddress();\n\n        public static native MnemonicRecord GetRecoveryPhrase();\n\n        public static native boolean IsMnemonicWallet();\n\n        public static native boolean IsMnemonicCorrect(String phrase);\n\n        public static native ArrayList<String> GetMnemonicDictionary();\n\n        public static native boolean UnlockWallet(String password, long timeoutInSeconds);\n\n        public static native boolean LockWallet();\n\n        public static native WalletLockStatus GetWalletLockStatus();\n\n        public static native boolean ChangePassword(String oldPassword, String newPassword);\n\n        public static native void DoRescan();\n\n        public static native UriRecipient IsValidRecipient(UriRecord request);\n\n        public static native boolean IsValidNativeAddress(String address);\n\n        public static native boolean IsValidBitcoinAddress(String address);\n\n        public static native long feeForRecipient(UriRecipient request);\n\n        public static native PaymentResultStatus performPaymentToRecipient(UriRecipient request, boolean substractFee);\n\n        public static native TransactionRecord getTransaction(String txHash);\n\n        public static native String resendTransaction(String txHash);\n\n        public static native ArrayList<AddressRecord> getAddressBookRecords();\n\n        public static native void addAddressBookRecord(AddressRecord address);\n\n        public static native void deleteAddressBookRecord(AddressRecord address);\n\n        public static native void PersistAndPruneForSPV();\n\n        public static native void ResetUnifiedProgress();\n\n        public static native ArrayList<BlockInfoRecord> getLastSPVBlockInfos();\n\n        public static native float getUnifiedProgress();\n\n        public static native MonitorRecord getMonitoringStats();\n\n        public static native void RegisterMonitorListener(MonitorListener listener);\n\n        public static native void UnregisterMonitorListener(MonitorListener listener);\n\n        public static native HashMap<String, String> getClientInfo();\n\n        public static native ArrayList<MutationRecord> getMutationHistory();\n\n        public static native ArrayList<TransactionRecord> getTransactionHistory();\n\n        public static native boolean HaveUnconfirmedFunds();\n\n        public static native long GetBalance();\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/ILibraryListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Interface to receive events from the core */\npublic abstract class ILibraryListener {\n    /**\n     * Fraction of work done since session start or last progress reset [0..1]\n     * Unified progress combines connection state, header and block sync\n     */\n    public abstract void notifyUnifiedProgress(float progress);\n\n    /** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n    public abstract void notifySyncDone();\n\n    public abstract void notifyBalanceChange(BalanceRecord newBalance);\n\n    /**\n     * Notification of new mutations\n     * If selfCommitted it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !selfCommitted (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    public abstract void notifyNewMutation(MutationRecord mutation, boolean selfCommitted);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    public abstract void notifyUpdatedTransaction(TransactionRecord transaction);\n\n    public abstract void notifyInitWithExistingWallet();\n\n    public abstract void notifyInitWithoutExistingWallet();\n\n    public abstract void notifyShutdown();\n\n    public abstract void notifyCoreReady();\n\n    public abstract void notifyError(String error);\n\n    public abstract void logPrint(String str);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IP2pNetworkController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** C++ interface to control networking related aspects of the software */\npublic abstract class IP2pNetworkController {\n    /** Register listener to be notified of networking events */\n    public static void setListener(IP2pNetworkListener networklistener)\n    {\n        CppProxy.setListener(networklistener);\n    }\n\n    /** Turn p2p networking off */\n    public static void disableNetwork()\n    {\n        CppProxy.disableNetwork();\n    }\n\n    /** Turn p2p networking on */\n    public static void enableNetwork()\n    {\n        CppProxy.enableNetwork();\n    }\n\n    /** Get connected peer info */\n    public static ArrayList<PeerRecord> getPeerInfo()\n    {\n        return CppProxy.getPeerInfo();\n    }\n\n    /** Get all banned peers */\n    public static ArrayList<BannedPeerRecord> listBannedPeers()\n    {\n        return CppProxy.listBannedPeers();\n    }\n\n    public static boolean banPeer(String address, long banTimeInSeconds)\n    {\n        return CppProxy.banPeer(address,\n                                banTimeInSeconds);\n    }\n\n    /** Unban a single peer */\n    public static boolean unbanPeer(String address)\n    {\n        return CppProxy.unbanPeer(address);\n    }\n\n    /** Disconnect a specific peer */\n    public static boolean disconnectPeer(long nodeid)\n    {\n        return CppProxy.disconnectPeer(nodeid);\n    }\n\n    /** Clear all banned peers */\n    public static boolean ClearBanned()\n    {\n        return CppProxy.ClearBanned();\n    }\n\n    private static final class CppProxy extends IP2pNetworkController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native void setListener(IP2pNetworkListener networklistener);\n\n        public static native void disableNetwork();\n\n        public static native void enableNetwork();\n\n        public static native ArrayList<PeerRecord> getPeerInfo();\n\n        public static native ArrayList<BannedPeerRecord> listBannedPeers();\n\n        public static native boolean banPeer(String address, long banTimeInSeconds);\n\n        public static native boolean unbanPeer(String address);\n\n        public static native boolean disconnectPeer(long nodeid);\n\n        public static native boolean ClearBanned();\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IP2pNetworkListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Interface to receive updates about network status */\npublic abstract class IP2pNetworkListener {\n    /** Notify that p2p networking has been enabled */\n    public abstract void onNetworkEnabled();\n\n    /** Notify that p2p networking has been disabled */\n    public abstract void onNetworkDisabled();\n\n    /** Notify that number of peers has changed */\n    public abstract void onConnectionCountChanged(int numConnections);\n\n    /** Notify that amount of data sent/received has changed */\n    public abstract void onBytesChanged(int totalRecv, int totalSent);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IRpcController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** C++ interface to execute RPC commands */\npublic abstract class IRpcController {\n    public static void execute(String rpcCommandLine, IRpcListener resultListener)\n    {\n        CppProxy.execute(rpcCommandLine,\n                         resultListener);\n    }\n\n    public static ArrayList<String> getAutocompleteList()\n    {\n        return CppProxy.getAutocompleteList();\n    }\n\n    private static final class CppProxy extends IRpcController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native void execute(String rpcCommandLine, IRpcListener resultListener);\n\n        public static native ArrayList<String> getAutocompleteList();\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IRpcListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/**\n * Interface to handle result of RPC commands\n * Calls either onSuccess or onError depending on whether command suceedes or fails\n */\npublic abstract class IRpcListener {\n    /**\n     * Returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    public abstract void onFilteredCommand(String filteredCommand);\n\n    /**\n     * Returns the result and a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    public abstract void onSuccess(String filteredCommand, String result);\n\n    /**\n     * Returns an error message which might be a plain string or JSON depending on the type of error\n     * Also returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    public abstract void onError(String filteredCommand, String errorMessage);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IWalletController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Controller to perform functions at a wallet level (e.g. get balance of the entire wallet)\n * For per account functionality see accounts_controller\n */\npublic abstract class IWalletController {\n    /** Set listener to be notified of wallet events */\n    public static void setListener(IWalletListener networklistener)\n    {\n        CppProxy.setListener(networklistener);\n    }\n\n    /** Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait. */\n    public static boolean HaveUnconfirmedFunds()\n    {\n        return CppProxy.HaveUnconfirmedFunds();\n    }\n\n    /** Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds */\n    public static long GetBalanceSimple()\n    {\n        return CppProxy.GetBalanceSimple();\n    }\n\n    /** Check current wallet balance */\n    public static BalanceRecord GetBalance()\n    {\n        return CppProxy.GetBalance();\n    }\n\n    /** Abandon a transaction */\n    public static boolean AbandonTransaction(String txHash)\n    {\n        return CppProxy.AbandonTransaction(txHash);\n    }\n\n    /** Get a unique UUID that identifies this wallet */\n    public static String GetUUID()\n    {\n        return CppProxy.GetUUID();\n    }\n\n    private static final class CppProxy extends IWalletController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native void setListener(IWalletListener networklistener);\n\n        public static native boolean HaveUnconfirmedFunds();\n\n        public static native long GetBalanceSimple();\n\n        public static native BalanceRecord GetBalance();\n\n        public static native boolean AbandonTransaction(String txHash);\n\n        public static native String GetUUID();\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IWalletListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Interface to receive wallet level events */\npublic abstract class IWalletListener {\n    /** Notification of change in overall wallet balance */\n    public abstract void notifyBalanceChange(BalanceRecord newBalance);\n\n    /**\n     * Notification of new mutations.\n     * If selfCommitted it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !selfCommitted (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    public abstract void notifyNewMutation(MutationRecord mutation, boolean selfCommitted);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    public abstract void notifyUpdatedTransaction(TransactionRecord transaction);\n\n    /** Wallet unlocked */\n    public abstract void notifyWalletUnlocked();\n\n    /** Wallet locked */\n    public abstract void notifyWalletLocked();\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    public abstract void notifyCoreWantsUnlock(String reason);\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    public abstract void notifyCoreInfo(String type, String caption, String message);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/IWitnessController.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/** C++ interface to control witness accounts */\npublic abstract class IWitnessController {\n    /** Get information on min/max witness periods, weights etc. */\n    public static HashMap<String, String> getNetworkLimits()\n    {\n        return CppProxy.getNetworkLimits();\n    }\n\n    /** Get an estimate of weights/parts that a witness account will be funded with */\n    public static WitnessEstimateInfoRecord getEstimatedWeight(long amountToLock, long lockPeriodInBlocks)\n    {\n        return CppProxy.getEstimatedWeight(amountToLock,\n                                           lockPeriodInBlocks);\n    }\n\n    /** Fund a witness account */\n    public static WitnessFundingResultRecord fundWitnessAccount(String fundingAccountUUID, String witnessAccountUUID, long fundingAmount, long requestedLockPeriodInBlocks)\n    {\n        return CppProxy.fundWitnessAccount(fundingAccountUUID,\n                                           witnessAccountUUID,\n                                           fundingAmount,\n                                           requestedLockPeriodInBlocks);\n    }\n\n    /** Renew a witness account */\n    public static WitnessFundingResultRecord renewWitnessAccount(String fundingAccountUUID, String witnessAccountUUID)\n    {\n        return CppProxy.renewWitnessAccount(fundingAccountUUID,\n                                            witnessAccountUUID);\n    }\n\n    /** Get information on account weight and other witness statistics for account */\n    public static WitnessAccountStatisticsRecord getAccountWitnessStatistics(String witnessAccountUUID)\n    {\n        return CppProxy.getAccountWitnessStatistics(witnessAccountUUID);\n    }\n\n    /** Turn compounding on/off */\n    public static void setAccountCompounding(String witnessAccountUUID, int percentToCompount)\n    {\n        CppProxy.setAccountCompounding(witnessAccountUUID,\n                                       percentToCompount);\n    }\n\n    /** Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding */\n    public static int isAccountCompounding(String witnessAccountUUID)\n    {\n        return CppProxy.isAccountCompounding(witnessAccountUUID);\n    }\n\n    /** Get the witness address of the account */\n    public static String getWitnessAddress(String witnessAccountUUID)\n    {\n        return CppProxy.getWitnessAddress(witnessAccountUUID);\n    }\n\n    /** Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\" */\n    public static ArrayList<Long> getOptimalWitnessDistribution(long amount, long durationInBlocks, long totalNetworkWeight)\n    {\n        return CppProxy.getOptimalWitnessDistribution(amount,\n                                                      durationInBlocks,\n                                                      totalNetworkWeight);\n    }\n\n    /** Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values */\n    public static ArrayList<Long> getOptimalWitnessDistributionForAccount(String witnessAccountUUID)\n    {\n        return CppProxy.getOptimalWitnessDistributionForAccount(witnessAccountUUID);\n    }\n\n    /** Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this */\n    public static ResultRecord optimiseWitnessAccount(String witnessAccountUUID, String fundingAccountUUID, ArrayList<Long> optimalDistribution)\n    {\n        return CppProxy.optimiseWitnessAccount(witnessAccountUUID,\n                                               fundingAccountUUID,\n                                               optimalDistribution);\n    }\n\n    private static final class CppProxy extends IWitnessController\n    {\n        private final long nativeRef;\n        private final AtomicBoolean destroyed = new AtomicBoolean(false);\n\n        private CppProxy(long nativeRef)\n        {\n            if (nativeRef == 0) throw new RuntimeException(\"nativeRef is zero\");\n            this.nativeRef = nativeRef;\n        }\n\n        private native void nativeDestroy(long nativeRef);\n        public void _djinni_private_destroy()\n        {\n            boolean destroyed = this.destroyed.getAndSet(true);\n            if (!destroyed) nativeDestroy(this.nativeRef);\n        }\n        protected void finalize() throws java.lang.Throwable\n        {\n            _djinni_private_destroy();\n            super.finalize();\n        }\n\n        public static native HashMap<String, String> getNetworkLimits();\n\n        public static native WitnessEstimateInfoRecord getEstimatedWeight(long amountToLock, long lockPeriodInBlocks);\n\n        public static native WitnessFundingResultRecord fundWitnessAccount(String fundingAccountUUID, String witnessAccountUUID, long fundingAmount, long requestedLockPeriodInBlocks);\n\n        public static native WitnessFundingResultRecord renewWitnessAccount(String fundingAccountUUID, String witnessAccountUUID);\n\n        public static native WitnessAccountStatisticsRecord getAccountWitnessStatistics(String witnessAccountUUID);\n\n        public static native void setAccountCompounding(String witnessAccountUUID, int percentToCompount);\n\n        public static native int isAccountCompounding(String witnessAccountUUID);\n\n        public static native String getWitnessAddress(String witnessAccountUUID);\n\n        public static native ArrayList<Long> getOptimalWitnessDistribution(long amount, long durationInBlocks, long totalNetworkWeight);\n\n        public static native ArrayList<Long> getOptimalWitnessDistributionForAccount(String witnessAccountUUID);\n\n        public static native ResultRecord optimiseWitnessAccount(String witnessAccountUUID, String fundingAccountUUID, ArrayList<Long> optimalDistribution);\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/InputRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class InputRecord implements android.os.Parcelable {\n\n\n    /*package*/ final String mAddress;\n\n    /*package*/ final String mLabel;\n\n    /*package*/ final String mDesc;\n\n    /*package*/ final boolean mIsMine;\n\n    public InputRecord(\n            String address,\n            String label,\n            String desc,\n            boolean isMine) {\n        this.mAddress = address;\n        this.mLabel = label;\n        this.mDesc = desc;\n        this.mIsMine = isMine;\n    }\n\n    public String getAddress() {\n        return mAddress;\n    }\n\n    public String getLabel() {\n        return mLabel;\n    }\n\n    public String getDesc() {\n        return mDesc;\n    }\n\n    public boolean getIsMine() {\n        return mIsMine;\n    }\n\n    @Override\n    public String toString() {\n        return \"InputRecord{\" +\n                \"mAddress=\" + mAddress +\n                \",\" + \"mLabel=\" + mLabel +\n                \",\" + \"mDesc=\" + mDesc +\n                \",\" + \"mIsMine=\" + mIsMine +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<InputRecord> CREATOR\n        = new android.os.Parcelable.Creator<InputRecord>() {\n        @Override\n        public InputRecord createFromParcel(android.os.Parcel in) {\n            return new InputRecord(in);\n        }\n\n        @Override\n        public InputRecord[] newArray(int size) {\n            return new InputRecord[size];\n        }\n    };\n\n    public InputRecord(android.os.Parcel in) {\n        this.mAddress = in.readString();\n        this.mLabel = in.readString();\n        this.mDesc = in.readString();\n        this.mIsMine = in.readByte() != 0;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeString(this.mAddress);\n        out.writeString(this.mLabel);\n        out.writeString(this.mDesc);\n        out.writeByte(this.mIsMine ? (byte)1 : 0);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/LegacyWalletResult.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic enum LegacyWalletResult {\n    UNSUPPORTED_ON_THIS_PLATFORM,\n    INVALID_OR_CORRUPT,\n    ENCRYPTED_PASSWORD_REQUIRED,\n    PASSWORD_INVALID,\n    VALID,\n    ;\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/MnemonicRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class MnemonicRecord {\n\n\n    /*package*/ final String mPhraseWithBirthNumber;\n\n    /*package*/ final String mPhrase;\n\n    /*package*/ final long mBirthNumber;\n\n    public MnemonicRecord(\n            String phraseWithBirthNumber,\n            String phrase,\n            long birthNumber) {\n        this.mPhraseWithBirthNumber = phraseWithBirthNumber;\n        this.mPhrase = phrase;\n        this.mBirthNumber = birthNumber;\n    }\n\n    public String getPhraseWithBirthNumber() {\n        return mPhraseWithBirthNumber;\n    }\n\n    public String getPhrase() {\n        return mPhrase;\n    }\n\n    public long getBirthNumber() {\n        return mBirthNumber;\n    }\n\n    @Override\n    public String toString() {\n        return \"MnemonicRecord{\" +\n                \"mPhraseWithBirthNumber=\" + mPhraseWithBirthNumber +\n                \",\" + \"mPhrase=\" + mPhrase +\n                \",\" + \"mBirthNumber=\" + mBirthNumber +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/MonitorListener.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** Monitoring events */\npublic abstract class MonitorListener {\n    public abstract void onPartialChain(int height, int probableHeight, int offset);\n\n    public abstract void onPruned(int height);\n\n    public abstract void onProcessedSPVBlocks(int height);\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/MonitorRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/** monitoring stats */\npublic final class MonitorRecord {\n\n\n    /*package*/ final int mPartialHeight;\n\n    /*package*/ final int mPartialOffset;\n\n    /*package*/ final int mPrunedHeight;\n\n    /*package*/ final int mProcessedSPVHeight;\n\n    /*package*/ final int mProbableHeight;\n\n    public MonitorRecord(\n            int partialHeight,\n            int partialOffset,\n            int prunedHeight,\n            int processedSPVHeight,\n            int probableHeight) {\n        this.mPartialHeight = partialHeight;\n        this.mPartialOffset = partialOffset;\n        this.mPrunedHeight = prunedHeight;\n        this.mProcessedSPVHeight = processedSPVHeight;\n        this.mProbableHeight = probableHeight;\n    }\n\n    public int getPartialHeight() {\n        return mPartialHeight;\n    }\n\n    public int getPartialOffset() {\n        return mPartialOffset;\n    }\n\n    public int getPrunedHeight() {\n        return mPrunedHeight;\n    }\n\n    public int getProcessedSPVHeight() {\n        return mProcessedSPVHeight;\n    }\n\n    public int getProbableHeight() {\n        return mProbableHeight;\n    }\n\n    @Override\n    public String toString() {\n        return \"MonitorRecord{\" +\n                \"mPartialHeight=\" + mPartialHeight +\n                \",\" + \"mPartialOffset=\" + mPartialOffset +\n                \",\" + \"mPrunedHeight=\" + mPrunedHeight +\n                \",\" + \"mProcessedSPVHeight=\" + mProcessedSPVHeight +\n                \",\" + \"mProbableHeight=\" + mProbableHeight +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/MutationRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class MutationRecord {\n\n\n    /*package*/ final long mChange;\n\n    /*package*/ final long mTimestamp;\n\n    /*package*/ final String mTxHash;\n\n    /*package*/ final String mRecipientAddresses;\n\n    /*package*/ final TransactionStatus mStatus;\n\n    /*package*/ final int mDepth;\n\n    public MutationRecord(\n            long change,\n            long timestamp,\n            String txHash,\n            String recipientAddresses,\n            TransactionStatus status,\n            int depth) {\n        this.mChange = change;\n        this.mTimestamp = timestamp;\n        this.mTxHash = txHash;\n        this.mRecipientAddresses = recipientAddresses;\n        this.mStatus = status;\n        this.mDepth = depth;\n    }\n\n    public long getChange() {\n        return mChange;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public String getTxHash() {\n        return mTxHash;\n    }\n\n    /** Address(es) of transaction recipient(s) (if transaction is sent by us then this excludes e.g. change and only has other wallets addresses) */\n    public String getRecipientAddresses() {\n        return mRecipientAddresses;\n    }\n\n    public TransactionStatus getStatus() {\n        return mStatus;\n    }\n\n    public int getDepth() {\n        return mDepth;\n    }\n\n    @Override\n    public String toString() {\n        return \"MutationRecord{\" +\n                \"mChange=\" + mChange +\n                \",\" + \"mTimestamp=\" + mTimestamp +\n                \",\" + \"mTxHash=\" + mTxHash +\n                \",\" + \"mRecipientAddresses=\" + mRecipientAddresses +\n                \",\" + \"mStatus=\" + mStatus +\n                \",\" + \"mDepth=\" + mDepth +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/OutputRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class OutputRecord implements android.os.Parcelable {\n\n\n    /*package*/ final long mAmount;\n\n    /*package*/ final String mAddress;\n\n    /*package*/ final String mLabel;\n\n    /*package*/ final String mDesc;\n\n    /*package*/ final boolean mIsMine;\n\n    public OutputRecord(\n            long amount,\n            String address,\n            String label,\n            String desc,\n            boolean isMine) {\n        this.mAmount = amount;\n        this.mAddress = address;\n        this.mLabel = label;\n        this.mDesc = desc;\n        this.mIsMine = isMine;\n    }\n\n    public long getAmount() {\n        return mAmount;\n    }\n\n    public String getAddress() {\n        return mAddress;\n    }\n\n    public String getLabel() {\n        return mLabel;\n    }\n\n    public String getDesc() {\n        return mDesc;\n    }\n\n    public boolean getIsMine() {\n        return mIsMine;\n    }\n\n    @Override\n    public String toString() {\n        return \"OutputRecord{\" +\n                \"mAmount=\" + mAmount +\n                \",\" + \"mAddress=\" + mAddress +\n                \",\" + \"mLabel=\" + mLabel +\n                \",\" + \"mDesc=\" + mDesc +\n                \",\" + \"mIsMine=\" + mIsMine +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<OutputRecord> CREATOR\n        = new android.os.Parcelable.Creator<OutputRecord>() {\n        @Override\n        public OutputRecord createFromParcel(android.os.Parcel in) {\n            return new OutputRecord(in);\n        }\n\n        @Override\n        public OutputRecord[] newArray(int size) {\n            return new OutputRecord[size];\n        }\n    };\n\n    public OutputRecord(android.os.Parcel in) {\n        this.mAmount = in.readLong();\n        this.mAddress = in.readString();\n        this.mLabel = in.readString();\n        this.mDesc = in.readString();\n        this.mIsMine = in.readByte() != 0;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeLong(this.mAmount);\n        out.writeString(this.mAddress);\n        out.writeString(this.mLabel);\n        out.writeString(this.mDesc);\n        out.writeByte(this.mIsMine ? (byte)1 : 0);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/PaymentResultStatus.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic enum PaymentResultStatus {\n    SUCCESS,\n    INSUFFICIENT_FUNDS,\n    ;\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/PeerRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class PeerRecord {\n\n\n    /*package*/ final long mId;\n\n    /*package*/ final String mIp;\n\n    /*package*/ final String mHostname;\n\n    /*package*/ final String mAddrLocal;\n\n    /*package*/ final String mAddrBind;\n\n    /*package*/ final long mStartHeight;\n\n    /*package*/ final long mSyncedHeight;\n\n    /*package*/ final long mCommonHeight;\n\n    /*package*/ final long mTimeConnected;\n\n    /*package*/ final long mTimeOffset;\n\n    /*package*/ final long mLatency;\n\n    /*package*/ final long mLastSend;\n\n    /*package*/ final long mLastReceive;\n\n    /*package*/ final long mSendBytes;\n\n    /*package*/ final long mReceiveBytes;\n\n    /*package*/ final String mUserAgent;\n\n    /*package*/ final long mProtocol;\n\n    /*package*/ final long mServices;\n\n    /*package*/ final boolean mInbound;\n\n    /*package*/ final boolean mWhitelisted;\n\n    /*package*/ final boolean mAddnode;\n\n    /*package*/ final boolean mRelayTxes;\n\n    /*package*/ final long mBanscore;\n\n    public PeerRecord(\n            long id,\n            String ip,\n            String hostname,\n            String addrLocal,\n            String addrBind,\n            long startHeight,\n            long syncedHeight,\n            long commonHeight,\n            long timeConnected,\n            long timeOffset,\n            long latency,\n            long lastSend,\n            long lastReceive,\n            long sendBytes,\n            long receiveBytes,\n            String userAgent,\n            long protocol,\n            long services,\n            boolean inbound,\n            boolean whitelisted,\n            boolean addnode,\n            boolean relayTxes,\n            long banscore) {\n        this.mId = id;\n        this.mIp = ip;\n        this.mHostname = hostname;\n        this.mAddrLocal = addrLocal;\n        this.mAddrBind = addrBind;\n        this.mStartHeight = startHeight;\n        this.mSyncedHeight = syncedHeight;\n        this.mCommonHeight = commonHeight;\n        this.mTimeConnected = timeConnected;\n        this.mTimeOffset = timeOffset;\n        this.mLatency = latency;\n        this.mLastSend = lastSend;\n        this.mLastReceive = lastReceive;\n        this.mSendBytes = sendBytes;\n        this.mReceiveBytes = receiveBytes;\n        this.mUserAgent = userAgent;\n        this.mProtocol = protocol;\n        this.mServices = services;\n        this.mInbound = inbound;\n        this.mWhitelisted = whitelisted;\n        this.mAddnode = addnode;\n        this.mRelayTxes = relayTxes;\n        this.mBanscore = banscore;\n    }\n\n    public long getId() {\n        return mId;\n    }\n\n    public String getIp() {\n        return mIp;\n    }\n\n    public String getHostname() {\n        return mHostname;\n    }\n\n    public String getAddrLocal() {\n        return mAddrLocal;\n    }\n\n    public String getAddrBind() {\n        return mAddrBind;\n    }\n\n    public long getStartHeight() {\n        return mStartHeight;\n    }\n\n    public long getSyncedHeight() {\n        return mSyncedHeight;\n    }\n\n    public long getCommonHeight() {\n        return mCommonHeight;\n    }\n\n    public long getTimeConnected() {\n        return mTimeConnected;\n    }\n\n    public long getTimeOffset() {\n        return mTimeOffset;\n    }\n\n    public long getLatency() {\n        return mLatency;\n    }\n\n    public long getLastSend() {\n        return mLastSend;\n    }\n\n    public long getLastReceive() {\n        return mLastReceive;\n    }\n\n    public long getSendBytes() {\n        return mSendBytes;\n    }\n\n    public long getReceiveBytes() {\n        return mReceiveBytes;\n    }\n\n    public String getUserAgent() {\n        return mUserAgent;\n    }\n\n    public long getProtocol() {\n        return mProtocol;\n    }\n\n    public long getServices() {\n        return mServices;\n    }\n\n    public boolean getInbound() {\n        return mInbound;\n    }\n\n    public boolean getWhitelisted() {\n        return mWhitelisted;\n    }\n\n    public boolean getAddnode() {\n        return mAddnode;\n    }\n\n    public boolean getRelayTxes() {\n        return mRelayTxes;\n    }\n\n    public long getBanscore() {\n        return mBanscore;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof PeerRecord)) {\n            return false;\n        }\n        PeerRecord other = (PeerRecord) obj;\n        return this.mId == other.mId &&\n                this.mIp.equals(other.mIp) &&\n                this.mHostname.equals(other.mHostname) &&\n                this.mAddrLocal.equals(other.mAddrLocal) &&\n                this.mAddrBind.equals(other.mAddrBind) &&\n                this.mStartHeight == other.mStartHeight &&\n                this.mSyncedHeight == other.mSyncedHeight &&\n                this.mCommonHeight == other.mCommonHeight &&\n                this.mTimeConnected == other.mTimeConnected &&\n                this.mTimeOffset == other.mTimeOffset &&\n                this.mLatency == other.mLatency &&\n                this.mLastSend == other.mLastSend &&\n                this.mLastReceive == other.mLastReceive &&\n                this.mSendBytes == other.mSendBytes &&\n                this.mReceiveBytes == other.mReceiveBytes &&\n                this.mUserAgent.equals(other.mUserAgent) &&\n                this.mProtocol == other.mProtocol &&\n                this.mServices == other.mServices &&\n                this.mInbound == other.mInbound &&\n                this.mWhitelisted == other.mWhitelisted &&\n                this.mAddnode == other.mAddnode &&\n                this.mRelayTxes == other.mRelayTxes &&\n                this.mBanscore == other.mBanscore;\n    }\n\n    @Override\n    public int hashCode() {\n        // Pick an arbitrary non-zero starting value\n        int hashCode = 17;\n        hashCode = hashCode * 31 + ((int) (mId ^ (mId >>> 32)));\n        hashCode = hashCode * 31 + mIp.hashCode();\n        hashCode = hashCode * 31 + mHostname.hashCode();\n        hashCode = hashCode * 31 + mAddrLocal.hashCode();\n        hashCode = hashCode * 31 + mAddrBind.hashCode();\n        hashCode = hashCode * 31 + ((int) (mStartHeight ^ (mStartHeight >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mSyncedHeight ^ (mSyncedHeight >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mCommonHeight ^ (mCommonHeight >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mTimeConnected ^ (mTimeConnected >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mTimeOffset ^ (mTimeOffset >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mLatency ^ (mLatency >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mLastSend ^ (mLastSend >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mLastReceive ^ (mLastReceive >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mSendBytes ^ (mSendBytes >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mReceiveBytes ^ (mReceiveBytes >>> 32)));\n        hashCode = hashCode * 31 + mUserAgent.hashCode();\n        hashCode = hashCode * 31 + ((int) (mProtocol ^ (mProtocol >>> 32)));\n        hashCode = hashCode * 31 + ((int) (mServices ^ (mServices >>> 32)));\n        hashCode = hashCode * 31 + (mInbound ? 1 : 0);\n        hashCode = hashCode * 31 + (mWhitelisted ? 1 : 0);\n        hashCode = hashCode * 31 + (mAddnode ? 1 : 0);\n        hashCode = hashCode * 31 + (mRelayTxes ? 1 : 0);\n        hashCode = hashCode * 31 + ((int) (mBanscore ^ (mBanscore >>> 32)));\n        return hashCode;\n    }\n\n    @Override\n    public String toString() {\n        return \"PeerRecord{\" +\n                \"mId=\" + mId +\n                \",\" + \"mIp=\" + mIp +\n                \",\" + \"mHostname=\" + mHostname +\n                \",\" + \"mAddrLocal=\" + mAddrLocal +\n                \",\" + \"mAddrBind=\" + mAddrBind +\n                \",\" + \"mStartHeight=\" + mStartHeight +\n                \",\" + \"mSyncedHeight=\" + mSyncedHeight +\n                \",\" + \"mCommonHeight=\" + mCommonHeight +\n                \",\" + \"mTimeConnected=\" + mTimeConnected +\n                \",\" + \"mTimeOffset=\" + mTimeOffset +\n                \",\" + \"mLatency=\" + mLatency +\n                \",\" + \"mLastSend=\" + mLastSend +\n                \",\" + \"mLastReceive=\" + mLastReceive +\n                \",\" + \"mSendBytes=\" + mSendBytes +\n                \",\" + \"mReceiveBytes=\" + mReceiveBytes +\n                \",\" + \"mUserAgent=\" + mUserAgent +\n                \",\" + \"mProtocol=\" + mProtocol +\n                \",\" + \"mServices=\" + mServices +\n                \",\" + \"mInbound=\" + mInbound +\n                \",\" + \"mWhitelisted=\" + mWhitelisted +\n                \",\" + \"mAddnode=\" + mAddnode +\n                \",\" + \"mRelayTxes=\" + mRelayTxes +\n                \",\" + \"mBanscore=\" + mBanscore +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/QrCodeRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class QrCodeRecord {\n\n\n    /*package*/ final int mWidth;\n\n    /*package*/ final byte[] mPixelData;\n\n    public QrCodeRecord(\n            int width,\n            byte[] pixelData) {\n        this.mWidth = width;\n        this.mPixelData = pixelData;\n    }\n\n    public int getWidth() {\n        return mWidth;\n    }\n\n    public byte[] getPixelData() {\n        return mPixelData;\n    }\n\n    @Override\n    public String toString() {\n        return \"QrCodeRecord{\" +\n                \"mWidth=\" + mWidth +\n                \",\" + \"mPixelData=\" + mPixelData +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/ResultRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\n/**\n * Copyright (c) 2018-2022 The Centure developers\n * Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n * Distributed under the GNU Lesser General Public License v3, see the accompanying\n * file COPYING\n */\npublic final class ResultRecord {\n\n\n    /*package*/ final boolean mResult;\n\n    /*package*/ final String mInfo;\n\n    public ResultRecord(\n            boolean result,\n            String info) {\n        this.mResult = result;\n        this.mInfo = info;\n    }\n\n    public boolean getResult() {\n        return mResult;\n    }\n\n    public String getInfo() {\n        return mInfo;\n    }\n\n    @Override\n    public String toString() {\n        return \"ResultRecord{\" +\n                \"mResult=\" + mResult +\n                \",\" + \"mInfo=\" + mInfo +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/TransactionRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.ArrayList;\n\npublic final class TransactionRecord implements android.os.Parcelable {\n\n\n    /*package*/ final String mTxHash;\n\n    /*package*/ final long mTimeStamp;\n\n    /*package*/ final long mAmount;\n\n    /*package*/ final long mFee;\n\n    /*package*/ final TransactionStatus mStatus;\n\n    /*package*/ final int mHeight;\n\n    /*package*/ final long mBlockTime;\n\n    /*package*/ final int mDepth;\n\n    /*package*/ final ArrayList<InputRecord> mInputs;\n\n    /*package*/ final ArrayList<OutputRecord> mOutputs;\n\n    public TransactionRecord(\n            String txHash,\n            long timeStamp,\n            long amount,\n            long fee,\n            TransactionStatus status,\n            int height,\n            long blockTime,\n            int depth,\n            ArrayList<InputRecord> inputs,\n            ArrayList<OutputRecord> outputs) {\n        this.mTxHash = txHash;\n        this.mTimeStamp = timeStamp;\n        this.mAmount = amount;\n        this.mFee = fee;\n        this.mStatus = status;\n        this.mHeight = height;\n        this.mBlockTime = blockTime;\n        this.mDepth = depth;\n        this.mInputs = inputs;\n        this.mOutputs = outputs;\n    }\n\n    public String getTxHash() {\n        return mTxHash;\n    }\n\n    public long getTimeStamp() {\n        return mTimeStamp;\n    }\n\n    public long getAmount() {\n        return mAmount;\n    }\n\n    public long getFee() {\n        return mFee;\n    }\n\n    public TransactionStatus getStatus() {\n        return mStatus;\n    }\n\n    public int getHeight() {\n        return mHeight;\n    }\n\n    public long getBlockTime() {\n        return mBlockTime;\n    }\n\n    public int getDepth() {\n        return mDepth;\n    }\n\n    public ArrayList<InputRecord> getInputs() {\n        return mInputs;\n    }\n\n    public ArrayList<OutputRecord> getOutputs() {\n        return mOutputs;\n    }\n\n    @Override\n    public String toString() {\n        return \"TransactionRecord{\" +\n                \"mTxHash=\" + mTxHash +\n                \",\" + \"mTimeStamp=\" + mTimeStamp +\n                \",\" + \"mAmount=\" + mAmount +\n                \",\" + \"mFee=\" + mFee +\n                \",\" + \"mStatus=\" + mStatus +\n                \",\" + \"mHeight=\" + mHeight +\n                \",\" + \"mBlockTime=\" + mBlockTime +\n                \",\" + \"mDepth=\" + mDepth +\n                \",\" + \"mInputs=\" + mInputs +\n                \",\" + \"mOutputs=\" + mOutputs +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<TransactionRecord> CREATOR\n        = new android.os.Parcelable.Creator<TransactionRecord>() {\n        @Override\n        public TransactionRecord createFromParcel(android.os.Parcel in) {\n            return new TransactionRecord(in);\n        }\n\n        @Override\n        public TransactionRecord[] newArray(int size) {\n            return new TransactionRecord[size];\n        }\n    };\n\n    public TransactionRecord(android.os.Parcel in) {\n        this.mTxHash = in.readString();\n        this.mTimeStamp = in.readLong();\n        this.mAmount = in.readLong();\n        this.mFee = in.readLong();\n        this.mStatus = TransactionStatus.values()[in.readInt()];\n        this.mHeight = in.readInt();\n        this.mBlockTime = in.readLong();\n        this.mDepth = in.readInt();\n        this.mInputs = new ArrayList<InputRecord>();\n        in.readList(this.mInputs, getClass().getClassLoader());\n        this.mOutputs = new ArrayList<OutputRecord>();\n        in.readList(this.mOutputs, getClass().getClassLoader());\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeString(this.mTxHash);\n        out.writeLong(this.mTimeStamp);\n        out.writeLong(this.mAmount);\n        out.writeLong(this.mFee);\n        out.writeInt(this.mStatus.ordinal());\n        out.writeInt(this.mHeight);\n        out.writeLong(this.mBlockTime);\n        out.writeInt(this.mDepth);\n        out.writeList(this.mInputs);\n        out.writeList(this.mOutputs);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/TransactionStatus.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic enum TransactionStatus {\n    UNCONFIRMED,\n    CONFIRMING,\n    CONFIRMED,\n    ABANDONED,\n    CONFLICTED,\n    ;\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/UriRecipient.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class UriRecipient implements android.os.Parcelable {\n\n\n    /*package*/ final boolean mValid;\n\n    /*package*/ final String mAddress;\n\n    /*package*/ final String mLabel;\n\n    /*package*/ final String mDesc;\n\n    /*package*/ final long mAmount;\n\n    public UriRecipient(\n            boolean valid,\n            String address,\n            String label,\n            String desc,\n            long amount) {\n        this.mValid = valid;\n        this.mAddress = address;\n        this.mLabel = label;\n        this.mDesc = desc;\n        this.mAmount = amount;\n    }\n\n    public boolean getValid() {\n        return mValid;\n    }\n\n    public String getAddress() {\n        return mAddress;\n    }\n\n    public String getLabel() {\n        return mLabel;\n    }\n\n    public String getDesc() {\n        return mDesc;\n    }\n\n    public long getAmount() {\n        return mAmount;\n    }\n\n    @Override\n    public String toString() {\n        return \"UriRecipient{\" +\n                \"mValid=\" + mValid +\n                \",\" + \"mAddress=\" + mAddress +\n                \",\" + \"mLabel=\" + mLabel +\n                \",\" + \"mDesc=\" + mDesc +\n                \",\" + \"mAmount=\" + mAmount +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<UriRecipient> CREATOR\n        = new android.os.Parcelable.Creator<UriRecipient>() {\n        @Override\n        public UriRecipient createFromParcel(android.os.Parcel in) {\n            return new UriRecipient(in);\n        }\n\n        @Override\n        public UriRecipient[] newArray(int size) {\n            return new UriRecipient[size];\n        }\n    };\n\n    public UriRecipient(android.os.Parcel in) {\n        this.mValid = in.readByte() != 0;\n        this.mAddress = in.readString();\n        this.mLabel = in.readString();\n        this.mDesc = in.readString();\n        this.mAmount = in.readLong();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeByte(this.mValid ? (byte)1 : 0);\n        out.writeString(this.mAddress);\n        out.writeString(this.mLabel);\n        out.writeString(this.mDesc);\n        out.writeLong(this.mAmount);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/UriRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\nimport java.util.HashMap;\n\npublic final class UriRecord {\n\n\n    /*package*/ final String mScheme;\n\n    /*package*/ final String mPath;\n\n    /*package*/ final HashMap<String, String> mItems;\n\n    public UriRecord(\n            String scheme,\n            String path,\n            HashMap<String, String> items) {\n        this.mScheme = scheme;\n        this.mPath = path;\n        this.mItems = items;\n    }\n\n    public String getScheme() {\n        return mScheme;\n    }\n\n    public String getPath() {\n        return mPath;\n    }\n\n    public HashMap<String, String> getItems() {\n        return mItems;\n    }\n\n    @Override\n    public String toString() {\n        return \"UriRecord{\" +\n                \"mScheme=\" + mScheme +\n                \",\" + \"mPath=\" + mPath +\n                \",\" + \"mItems=\" + mItems +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/WalletLockStatus.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class WalletLockStatus {\n\n\n    /*package*/ final boolean mLocked;\n\n    /*package*/ final long mLockTimeout;\n\n    public WalletLockStatus(\n            boolean locked,\n            long lockTimeout) {\n        this.mLocked = locked;\n        this.mLockTimeout = lockTimeout;\n    }\n\n    public boolean getLocked() {\n        return mLocked;\n    }\n\n    public long getLockTimeout() {\n        return mLockTimeout;\n    }\n\n    @Override\n    public String toString() {\n        return \"WalletLockStatus{\" +\n                \"mLocked=\" + mLocked +\n                \",\" + \"mLockTimeout=\" + mLockTimeout +\n        \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/WitnessAccountStatisticsRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class WitnessAccountStatisticsRecord implements android.os.Parcelable {\n\n\n    /*package*/ final String mRequestStatus;\n\n    /*package*/ final String mAccountStatus;\n\n    /*package*/ final long mBlocksSinceLastActivity;\n\n    /*package*/ final long mAccountWeight;\n\n    /*package*/ final long mAccountWeightAtCreation;\n\n    /*package*/ final long mAccountParts;\n\n    /*package*/ final long mAccountAmountLocked;\n\n    /*package*/ final long mAccountAmountLockedAtCreation;\n\n    /*package*/ final long mNetworkTipTotalWeight;\n\n    /*package*/ final long mNetworkTotalWeightAtCreation;\n\n    /*package*/ final long mAccountInitialLockPeriodInBlocks;\n\n    /*package*/ final long mAccountRemainingLockPeriodInBlocks;\n\n    /*package*/ final long mAccountExpectedWitnessPeriodInBlocks;\n\n    /*package*/ final long mAccountEstimatedWitnessPeriodInBlocks;\n\n    /*package*/ final long mAccountInitialLockCreationBlockHeight;\n\n    /*package*/ final int mCompoundingPercent;\n\n    /*package*/ final boolean mIsOptimal;\n\n    public WitnessAccountStatisticsRecord(\n            String requestStatus,\n            String accountStatus,\n            long blocksSinceLastActivity,\n            long accountWeight,\n            long accountWeightAtCreation,\n            long accountParts,\n            long accountAmountLocked,\n            long accountAmountLockedAtCreation,\n            long networkTipTotalWeight,\n            long networkTotalWeightAtCreation,\n            long accountInitialLockPeriodInBlocks,\n            long accountRemainingLockPeriodInBlocks,\n            long accountExpectedWitnessPeriodInBlocks,\n            long accountEstimatedWitnessPeriodInBlocks,\n            long accountInitialLockCreationBlockHeight,\n            int compoundingPercent,\n            boolean isOptimal) {\n        this.mRequestStatus = requestStatus;\n        this.mAccountStatus = accountStatus;\n        this.mBlocksSinceLastActivity = blocksSinceLastActivity;\n        this.mAccountWeight = accountWeight;\n        this.mAccountWeightAtCreation = accountWeightAtCreation;\n        this.mAccountParts = accountParts;\n        this.mAccountAmountLocked = accountAmountLocked;\n        this.mAccountAmountLockedAtCreation = accountAmountLockedAtCreation;\n        this.mNetworkTipTotalWeight = networkTipTotalWeight;\n        this.mNetworkTotalWeightAtCreation = networkTotalWeightAtCreation;\n        this.mAccountInitialLockPeriodInBlocks = accountInitialLockPeriodInBlocks;\n        this.mAccountRemainingLockPeriodInBlocks = accountRemainingLockPeriodInBlocks;\n        this.mAccountExpectedWitnessPeriodInBlocks = accountExpectedWitnessPeriodInBlocks;\n        this.mAccountEstimatedWitnessPeriodInBlocks = accountEstimatedWitnessPeriodInBlocks;\n        this.mAccountInitialLockCreationBlockHeight = accountInitialLockCreationBlockHeight;\n        this.mCompoundingPercent = compoundingPercent;\n        this.mIsOptimal = isOptimal;\n    }\n\n    /** Success if request succeeded, otherwise an error message */\n    public String getRequestStatus() {\n        return mRequestStatus;\n    }\n\n    /** Current state of the witness account, one of: \"empty\", \"empty_with_remainder\", \"pending\", \"witnessing\", \"ended\", \"expired\", \"emptying\" */\n    public String getAccountStatus() {\n        return mAccountStatus;\n    }\n\n    /** Account weight */\n    public long getBlocksSinceLastActivity() {\n        return mBlocksSinceLastActivity;\n    }\n\n    /** Account weight */\n    public long getAccountWeight() {\n        return mAccountWeight;\n    }\n\n    /** Account weight when it was created */\n    public long getAccountWeightAtCreation() {\n        return mAccountWeightAtCreation;\n    }\n\n    /** How many parts the account weight is split up into */\n    public long getAccountParts() {\n        return mAccountParts;\n    }\n\n    /** Account amount currently locked */\n    public long getAccountAmountLocked() {\n        return mAccountAmountLocked;\n    }\n\n    /** Account amount locked when it was created */\n    public long getAccountAmountLockedAtCreation() {\n        return mAccountAmountLockedAtCreation;\n    }\n\n    /** Current network weight */\n    public long getNetworkTipTotalWeight() {\n        return mNetworkTipTotalWeight;\n    }\n\n    /** Network weight when account was created */\n    public long getNetworkTotalWeightAtCreation() {\n        return mNetworkTotalWeightAtCreation;\n    }\n\n    /** Account total lock period in blocks (from creation block) */\n    public long getAccountInitialLockPeriodInBlocks() {\n        return mAccountInitialLockPeriodInBlocks;\n    }\n\n    /** Account remaining lock period in blocks (from chain tip) */\n    public long getAccountRemainingLockPeriodInBlocks() {\n        return mAccountRemainingLockPeriodInBlocks;\n    }\n\n    /** How often the account is \"expected\" by the network to witness in order to not be kicked off */\n    public long getAccountExpectedWitnessPeriodInBlocks() {\n        return mAccountExpectedWitnessPeriodInBlocks;\n    }\n\n    /** How often the account is estimated to witness */\n    public long getAccountEstimatedWitnessPeriodInBlocks() {\n        return mAccountEstimatedWitnessPeriodInBlocks;\n    }\n\n    /** Height at which the account lock first entered the chain */\n    public long getAccountInitialLockCreationBlockHeight() {\n        return mAccountInitialLockCreationBlockHeight;\n    }\n\n    /** How much of the reward that this account earns is set to be compound */\n    public int getCompoundingPercent() {\n        return mCompoundingPercent;\n    }\n\n    /** Is the account weight split in an optimal way */\n    public boolean getIsOptimal() {\n        return mIsOptimal;\n    }\n\n    @Override\n    public String toString() {\n        return \"WitnessAccountStatisticsRecord{\" +\n                \"mRequestStatus=\" + mRequestStatus +\n                \",\" + \"mAccountStatus=\" + mAccountStatus +\n                \",\" + \"mBlocksSinceLastActivity=\" + mBlocksSinceLastActivity +\n                \",\" + \"mAccountWeight=\" + mAccountWeight +\n                \",\" + \"mAccountWeightAtCreation=\" + mAccountWeightAtCreation +\n                \",\" + \"mAccountParts=\" + mAccountParts +\n                \",\" + \"mAccountAmountLocked=\" + mAccountAmountLocked +\n                \",\" + \"mAccountAmountLockedAtCreation=\" + mAccountAmountLockedAtCreation +\n                \",\" + \"mNetworkTipTotalWeight=\" + mNetworkTipTotalWeight +\n                \",\" + \"mNetworkTotalWeightAtCreation=\" + mNetworkTotalWeightAtCreation +\n                \",\" + \"mAccountInitialLockPeriodInBlocks=\" + mAccountInitialLockPeriodInBlocks +\n                \",\" + \"mAccountRemainingLockPeriodInBlocks=\" + mAccountRemainingLockPeriodInBlocks +\n                \",\" + \"mAccountExpectedWitnessPeriodInBlocks=\" + mAccountExpectedWitnessPeriodInBlocks +\n                \",\" + \"mAccountEstimatedWitnessPeriodInBlocks=\" + mAccountEstimatedWitnessPeriodInBlocks +\n                \",\" + \"mAccountInitialLockCreationBlockHeight=\" + mAccountInitialLockCreationBlockHeight +\n                \",\" + \"mCompoundingPercent=\" + mCompoundingPercent +\n                \",\" + \"mIsOptimal=\" + mIsOptimal +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<WitnessAccountStatisticsRecord> CREATOR\n        = new android.os.Parcelable.Creator<WitnessAccountStatisticsRecord>() {\n        @Override\n        public WitnessAccountStatisticsRecord createFromParcel(android.os.Parcel in) {\n            return new WitnessAccountStatisticsRecord(in);\n        }\n\n        @Override\n        public WitnessAccountStatisticsRecord[] newArray(int size) {\n            return new WitnessAccountStatisticsRecord[size];\n        }\n    };\n\n    public WitnessAccountStatisticsRecord(android.os.Parcel in) {\n        this.mRequestStatus = in.readString();\n        this.mAccountStatus = in.readString();\n        this.mBlocksSinceLastActivity = in.readLong();\n        this.mAccountWeight = in.readLong();\n        this.mAccountWeightAtCreation = in.readLong();\n        this.mAccountParts = in.readLong();\n        this.mAccountAmountLocked = in.readLong();\n        this.mAccountAmountLockedAtCreation = in.readLong();\n        this.mNetworkTipTotalWeight = in.readLong();\n        this.mNetworkTotalWeightAtCreation = in.readLong();\n        this.mAccountInitialLockPeriodInBlocks = in.readLong();\n        this.mAccountRemainingLockPeriodInBlocks = in.readLong();\n        this.mAccountExpectedWitnessPeriodInBlocks = in.readLong();\n        this.mAccountEstimatedWitnessPeriodInBlocks = in.readLong();\n        this.mAccountInitialLockCreationBlockHeight = in.readLong();\n        this.mCompoundingPercent = in.readInt();\n        this.mIsOptimal = in.readByte() != 0;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeString(this.mRequestStatus);\n        out.writeString(this.mAccountStatus);\n        out.writeLong(this.mBlocksSinceLastActivity);\n        out.writeLong(this.mAccountWeight);\n        out.writeLong(this.mAccountWeightAtCreation);\n        out.writeLong(this.mAccountParts);\n        out.writeLong(this.mAccountAmountLocked);\n        out.writeLong(this.mAccountAmountLockedAtCreation);\n        out.writeLong(this.mNetworkTipTotalWeight);\n        out.writeLong(this.mNetworkTotalWeightAtCreation);\n        out.writeLong(this.mAccountInitialLockPeriodInBlocks);\n        out.writeLong(this.mAccountRemainingLockPeriodInBlocks);\n        out.writeLong(this.mAccountExpectedWitnessPeriodInBlocks);\n        out.writeLong(this.mAccountEstimatedWitnessPeriodInBlocks);\n        out.writeLong(this.mAccountInitialLockCreationBlockHeight);\n        out.writeInt(this.mCompoundingPercent);\n        out.writeByte(this.mIsOptimal ? (byte)1 : 0);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/WitnessEstimateInfoRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class WitnessEstimateInfoRecord implements android.os.Parcelable {\n\n\n    /*package*/ final long mNetworkWeight;\n\n    /*package*/ final long mWeight;\n\n    /*package*/ final long mParts;\n\n    /*package*/ final double mEstimatedWitnessProbability;\n\n    /*package*/ final double mEstimatedBlocksPerDay;\n\n    /*package*/ final long mEstimatedDailyEarnings;\n\n    /*package*/ final long mEstimatedLifetimeEarnings;\n\n    public WitnessEstimateInfoRecord(\n            long networkWeight,\n            long weight,\n            long parts,\n            double estimatedWitnessProbability,\n            double estimatedBlocksPerDay,\n            long estimatedDailyEarnings,\n            long estimatedLifetimeEarnings) {\n        this.mNetworkWeight = networkWeight;\n        this.mWeight = weight;\n        this.mParts = parts;\n        this.mEstimatedWitnessProbability = estimatedWitnessProbability;\n        this.mEstimatedBlocksPerDay = estimatedBlocksPerDay;\n        this.mEstimatedDailyEarnings = estimatedDailyEarnings;\n        this.mEstimatedLifetimeEarnings = estimatedLifetimeEarnings;\n    }\n\n    /** Current network weight */\n    public long getNetworkWeight() {\n        return mNetworkWeight;\n    }\n\n    /** Weight of resulting witness account */\n    public long getWeight() {\n        return mWeight;\n    }\n\n    /** How many parts this weight will be split into */\n    public long getParts() {\n        return mParts;\n    }\n\n    /** The per block probability of resulting account witnesing */\n    public double getEstimatedWitnessProbability() {\n        return mEstimatedWitnessProbability;\n    }\n\n    /** The estimated number of blocks the resulting account should find per day */\n    public double getEstimatedBlocksPerDay() {\n        return mEstimatedBlocksPerDay;\n    }\n\n    /** The estimated earnings the account should make per day */\n    public long getEstimatedDailyEarnings() {\n        return mEstimatedDailyEarnings;\n    }\n\n    /** The estimated earnings the account should make over its entire lifetime */\n    public long getEstimatedLifetimeEarnings() {\n        return mEstimatedLifetimeEarnings;\n    }\n\n    @Override\n    public String toString() {\n        return \"WitnessEstimateInfoRecord{\" +\n                \"mNetworkWeight=\" + mNetworkWeight +\n                \",\" + \"mWeight=\" + mWeight +\n                \",\" + \"mParts=\" + mParts +\n                \",\" + \"mEstimatedWitnessProbability=\" + mEstimatedWitnessProbability +\n                \",\" + \"mEstimatedBlocksPerDay=\" + mEstimatedBlocksPerDay +\n                \",\" + \"mEstimatedDailyEarnings=\" + mEstimatedDailyEarnings +\n                \",\" + \"mEstimatedLifetimeEarnings=\" + mEstimatedLifetimeEarnings +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<WitnessEstimateInfoRecord> CREATOR\n        = new android.os.Parcelable.Creator<WitnessEstimateInfoRecord>() {\n        @Override\n        public WitnessEstimateInfoRecord createFromParcel(android.os.Parcel in) {\n            return new WitnessEstimateInfoRecord(in);\n        }\n\n        @Override\n        public WitnessEstimateInfoRecord[] newArray(int size) {\n            return new WitnessEstimateInfoRecord[size];\n        }\n    };\n\n    public WitnessEstimateInfoRecord(android.os.Parcel in) {\n        this.mNetworkWeight = in.readLong();\n        this.mWeight = in.readLong();\n        this.mParts = in.readLong();\n        this.mEstimatedWitnessProbability = in.readDouble();\n        this.mEstimatedBlocksPerDay = in.readDouble();\n        this.mEstimatedDailyEarnings = in.readLong();\n        this.mEstimatedLifetimeEarnings = in.readLong();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeLong(this.mNetworkWeight);\n        out.writeLong(this.mWeight);\n        out.writeLong(this.mParts);\n        out.writeDouble(this.mEstimatedWitnessProbability);\n        out.writeDouble(this.mEstimatedBlocksPerDay);\n        out.writeLong(this.mEstimatedDailyEarnings);\n        out.writeLong(this.mEstimatedLifetimeEarnings);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/jniunifiedbackend/WitnessFundingResultRecord.java",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\npackage unity_wallet.jniunifiedbackend;\n\npublic final class WitnessFundingResultRecord implements android.os.Parcelable {\n\n\n    /*package*/ final String mStatus;\n\n    /*package*/ final String mTxid;\n\n    /*package*/ final long mFee;\n\n    public WitnessFundingResultRecord(\n            String status,\n            String txid,\n            long fee) {\n        this.mStatus = status;\n        this.mTxid = txid;\n        this.mFee = fee;\n    }\n\n    /** \"success\" on success, otherwise an error message */\n    public String getStatus() {\n        return mStatus;\n    }\n\n    /** txid of the funding transaction, empty on failure */\n    public String getTxid() {\n        return mTxid;\n    }\n\n    /** fee charged by the transaction, 0 on failure */\n    public long getFee() {\n        return mFee;\n    }\n\n    @Override\n    public String toString() {\n        return \"WitnessFundingResultRecord{\" +\n                \"mStatus=\" + mStatus +\n                \",\" + \"mTxid=\" + mTxid +\n                \",\" + \"mFee=\" + mFee +\n        \"}\";\n    }\n\n\n    public static final android.os.Parcelable.Creator<WitnessFundingResultRecord> CREATOR\n        = new android.os.Parcelable.Creator<WitnessFundingResultRecord>() {\n        @Override\n        public WitnessFundingResultRecord createFromParcel(android.os.Parcel in) {\n            return new WitnessFundingResultRecord(in);\n        }\n\n        @Override\n        public WitnessFundingResultRecord[] newArray(int size) {\n            return new WitnessFundingResultRecord[size];\n        }\n    };\n\n    public WitnessFundingResultRecord(android.os.Parcel in) {\n        this.mStatus = in.readString();\n        this.mTxid = in.readString();\n        this.mFee = in.readLong();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(android.os.Parcel out, int flags) {\n        out.writeString(this.mStatus);\n        out.writeString(this.mTxid);\n        out.writeLong(this.mFee);\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/LocalCurrencyFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport unity_wallet.Currencies\nimport unity_wallet.R\nimport unity_wallet.WalletActivity\nimport unity_wallet.fetchAllCurrencyRates\nimport unity_wallet.ui.LocalCurrenciesAdapter\nimport unity_wallet.util.AppBaseActivity\nimport kotlinx.android.synthetic.main.fragment_local_currencies.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\n\n\nclass LocalCurrencyFragment : androidx.fragment.app.Fragment() {\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n    {\n        return inflater.inflate(R.layout.fragment_local_currencies, container, false)\n    }\n\n    override fun onResume()\n    {\n        super.onResume()\n        (activity as WalletActivity).showSettingsTitle(getString(R.string.title_select_currency))\n    }\n\n    override fun onStop()\n    {\n        super.onStop()\n        (activity as WalletActivity).hideSettingsTitle()\n    }\n\n    override fun onActivityCreated(savedInstanceState: Bundle?)\n    {\n        super.onActivityCreated(savedInstanceState)\n\n        // Get conversion rates\n        (this.activity as AppBaseActivity).launch(Dispatchers.Main) {\n            try {\n                (currenciesList.adapter as LocalCurrenciesAdapter).updateAllRates(fetchAllCurrencyRates())\n            } catch (e: Throwable) {\n                // silently ignore failure of getting rate here\n            }\n        }\n\n        val adapter = LocalCurrenciesAdapter(this.requireContext(), Currencies.knownCurrencies)\n        currenciesList.adapter = adapter\n        currenciesList.setOnItemClickListener { parent, _, position, _ ->\n            adapter.setSelectedPosition(position)\n            adapter.notifyDataSetChanged()\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/MutationFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.MutationRecord\nimport unity_wallet.jniunifiedbackend.TransactionRecord\nimport unity_wallet.*\nimport unity_wallet.ui.MutationAdapter\nimport unity_wallet.util.AppBaseFragment\nimport unity_wallet.util.invokeNowOrOnSuccessfulCompletion\nimport kotlinx.android.synthetic.main.fragment_mutation.*\nimport kotlinx.coroutines.*\nimport android.os.Handler\nimport android.os.Looper\n\n\nclass MutationFragment : AppBaseFragment(), UnityCore.Observer, CoroutineScope {\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n    {\n        return inflater.inflate(R.layout.fragment_mutation, container, false)\n    }\n\n    override fun onActivityCreated(savedInstanceState: Bundle?)\n    {\n        super.onActivityCreated(savedInstanceState)\n\n        // if wallet ready setup list immediately so list does not briefly flash empty content and\n        // scroll position is kept on switching from and to this fragment\n        UnityCore.instance.walletReady.invokeNowOrOnSuccessfulCompletion(this) {\n            mutationList?.emptyView = emptyMutationListView\n            val mutations = ILibraryController.getMutationHistory()\n\n            val adapter = MutationAdapter(requireContext(), mutations)\n            mutationList.adapter = adapter\n\n            mutationList.setOnItemClickListener { parent, _, position, _ ->\n                val mutation = parent.adapter.getItem(position) as MutationRecord\n                val intent =\n                    Intent(requireContext(), TransactionInfoActivity::class.java)\n                intent.putExtra(TransactionInfoActivity.EXTRA_TRANSACTION, mutation.txHash)\n                startActivity(intent)\n            }\n\n            buyYourFirstText.setOnClickListener {\n                (activity as WalletActivity).gotoBuyActivity()\n            }\n            noTransactionsText.setOnClickListener {\n                (activity as WalletActivity).gotoBuyActivity()\n            }\n\n\n            launch {\n                try {\n                    (mutationList.adapter as MutationAdapter).updateRate(fetchCurrencyRate(localCurrency.code))\n                } catch (e: Throwable) {\n                    // silently ignore failure of getting rate here\n                }\n            }\n        }\n    }\n\n    override fun onAttach(context: Context)\n    {\n        UnityCore.instance.addObserver(this)\n\n        super.onAttach(context)\n    }\n\n    override fun onDetach() {\n        UnityCore.instance.removeObserver(this)\n\n        super.onDetach()\n    }\n\n    override fun onNewMutation(mutation: MutationRecord, selfCommitted: Boolean) {\n        //TODO: Update only the single mutation we have received\n        val mutations = ILibraryController.getMutationHistory()\n        handler.post {\n            val adapter = mutationList.adapter as MutationAdapter\n            adapter.updateDataSource(mutations)\n        }\n    }\n\n    override fun updatedTransaction(transaction: TransactionRecord)\n    {\n        //TODO: Update only the single mutation we have received\n        val mutations = ILibraryController.getMutationHistory()\n        handler.post {\n            val adapter = mutationList.adapter as MutationAdapter\n            adapter.updateDataSource(mutations)\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/ReceiveFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Intent\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.view.Gravity\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Toast\nimport androidx.core.content.ContextCompat.getSystemService\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.R\nimport unity_wallet.WalletActivity\nimport unity_wallet.util.AppBaseFragment\nimport kotlinx.android.synthetic.main.fragment_receive.*\nimport java.nio.ByteBuffer\n\n\n/* Handle display of current address; as well as copying/sharing of address */\nclass ReceiveFragment : AppBaseFragment() {\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n    {\n        return inflater.inflate(R.layout.fragment_receive, container, false)\n    }\n\n    override fun onWalletReady() {\n        updateAddress()\n        buyButton.setOnClickListener { (activity as WalletActivity).gotoBuyActivity() }\n        shareButton.setOnClickListener {\n            val share = Intent(Intent.ACTION_SEND)\n            share.type = \"text/plain\"\n            share.putExtra(Intent.EXTRA_TEXT, currentAddressLabel.text)\n            startActivity(Intent.createChooser(share, getString(R.string.receive_fragment_share_title)))\n        }\n\n        currentAddressQrView.setOnLongClickListener {\n            copyToClipboard()\n        }\n\n        currentAddressLabel.setOnLongClickListener {\n            copyToClipboard()\n        }\n    }\n\n    private fun copyToClipboard(): Boolean {\n        val clip: ClipData = ClipData.newPlainText(getString(R.string.coin_address_clipboard_label), currentAddressLabel.text)\n        val clipboard = getSystemService<ClipboardManager>(requireActivity(), ClipboardManager::class.java) as ClipboardManager\n        clipboard.setPrimaryClip(clip)\n\n        val toast = Toast.makeText(context, getString(R.string.copied_to_clipboard_toast), Toast.LENGTH_SHORT)\n        toast.setGravity(Gravity.TOP, 0, requireContext().resources.getDimensionPixelSize(R.dimen.top_toast_offset) )\n        toast.show()\n\n        return true\n    }\n\n    private fun updateAddress()\n    {\n        if (currentAddressQrView != null)\n        {\n            val address = ILibraryController.GetReceiveAddress()\n            val imageData = ILibraryController.QRImageFromString(\"munt://$address\", 600)\n            val bitmap = Bitmap.createBitmap(imageData.width, imageData.width, Bitmap.Config.ALPHA_8)\n            bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(imageData.pixelData))\n            currentAddressQrView.setImageBitmap(bitmap)\n            currentAddressLabel.text = address\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/SendFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport android.text.Editable\nimport android.text.Html\nimport android.text.SpannableString\nimport android.text.TextWatcher\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.EditText\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.ContextCompat\nimport androidx.recyclerview.widget.ItemTouchHelper\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.android.volley.*\nimport com.android.volley.toolbox.StringRequest\nimport com.android.volley.toolbox.Volley\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.vision.barcode.Barcode\nimport barcodereader.BarcodeCaptureActivity\nimport unity_wallet.jniunifiedbackend.AddressRecord\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.jniunifiedbackend.IWalletController\nimport unity_wallet.jniunifiedbackend.UriRecipient\nimport unity_wallet.*\nimport unity_wallet.ui.AddressBookAdapter\nimport unity_wallet.util.AppBaseFragment\nimport unity_wallet.util.SwipeToDeleteCallback\nimport kotlinx.android.synthetic.main.add_address_entry.view.*\nimport kotlinx.android.synthetic.main.fragment_send.*\nimport android.os.Handler\nimport android.os.Looper\nimport org.json.JSONObject\n\n\nclass SendFragment : AppBaseFragment(), UnityCore.Observer {\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?\n    {\n        return inflater.inflate(unity_wallet.R.layout.fragment_send, container, false)\n    }\n\n    private fun handleAddToAddressBookButtonClick(view : View)\n    {\n        val builder = AlertDialog.Builder(this.requireContext())\n        builder.setTitle(getString(unity_wallet.R.string.dialog_title_add_address))\n        val layoutInflater : LayoutInflater = this.requireContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater\n        val viewInflated : View = layoutInflater.inflate(unity_wallet.R.layout.add_address_entry, view.rootView as ViewGroup, false)\n        val inputAddress = viewInflated.findViewById(unity_wallet.R.id.address) as EditText\n        val inputLabel = viewInflated.findViewById(unity_wallet.R.id.addressName) as EditText\n        builder.setView(viewInflated)\n        builder.setPositiveButton(android.R.string.ok) { dialog, _ ->\n            val address = inputAddress.text.toString()\n            val label = inputLabel.text.toString()\n            val record = AddressRecord(address, label, \"\", \"Send\")\n            UnityCore.instance.addAddressBookRecord(record)\n            dialog.dismiss()\n        }\n\n        builder.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.cancel() }\n        val dialog = builder.create()\n        dialog.setOnShowListener {\n            val okBtn = dialog.getButton(AlertDialog.BUTTON_POSITIVE)\n            okBtn.isEnabled = false\n\n            val textChangedListener = object : TextWatcher {\n                override fun afterTextChanged(s: Editable?) {\n                    s?.run {\n                        val address = inputAddress.text.toString()\n                        val label = inputLabel.text.toString()\n                        var enable = false\n                        if (address != \"\" && label != \"\")\n                        {\n                            try {\n                                createRecipient(address)\n                                enable = true\n                            }\n                            catch (e: InvalidRecipientException) {\n                                // silently ignore, use can continue typing until a valid recipient is entered\n                            }\n                        }\n                        okBtn.isEnabled = enable\n                    }\n                }\n                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}\n                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}\n            }\n\n            inputAddress.addTextChangedListener(textChangedListener)\n            inputLabel.addTextChangedListener(textChangedListener)\n\n            viewInflated.address.requestFocus()\n            viewInflated.address.post {\n                val imm = this.requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                imm.showSoftInput(viewInflated.address, InputMethodManager.SHOW_IMPLICIT)\n            }\n        }\n        dialog.show()\n    }\n\n    fun setupAddressBookButton()\n    {\n        imageViewAddToAddressBook.setOnClickListener {\n            handleAddToAddressBookButtonClick(requireView())\n        }\n    }\n\n    fun setupClipboardButton()\n    {\n        clipboardButton.setOnClickListener {\n            val text = clipboardText()\n            try {\n                SendCoinsFragment.newInstance(createRecipient(text), false).show(requireActivity().supportFragmentManager, SendCoinsFragment::class.java.simpleName)\n            }\n            catch (e: InvalidRecipientException) {\n                errorMessage(getString(unity_wallet.R.string.clipboard_no_valid_address))\n            }\n        }\n    }\n\n    fun setupQRButton()\n    {\n        qrButton.setOnClickListener {\n            val intent = Intent(context, BarcodeCaptureActivity::class.java)\n            intent.putExtra(BarcodeCaptureActivity.AutoFocus, true)\n            startActivityForResult(intent, BARCODE_READER_REQUEST_CODE)\n        }\n    }\n\n    fun setupSellButton()\n    {\n        sellButton.setOnClickListener {\n            // Send a post request to blockhut with our wallet/address info; and then launch the site if we get a positive response.\n            val MyRequestQueue = Volley.newRequestQueue(context)\n            val failURL = \"https://munt.org/sell\"\n            val request = object : StringRequest(Request.Method.POST,\"https://blockhut.com/buysession.php\",\n                Response.Listener { response ->\n                    try\n                    {\n                        var jsonResponse = JSONObject(response);\n                        if (jsonResponse.getInt(\"status_code\") == 200)\n                        {\n                            var sessionID = jsonResponse.getString(\"sessionid\")\n                            try\n                            {\n                                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(\"https://blockhut.com/sell.php?sessionid=%s\".format(sessionID)))\n                                startActivity(intent)\n                            }\n                            catch (e:IllegalStateException)\n                            {\n                                //TODO: Add analytics here to figure out why this happens\n                            }\n                        }\n                        else\n                        {\n                            // Redirect user to the default fallback site\n                            //fixme: Do something with the status message here\n                            //var statusMessage = jsonResponse.getString(\"status_message\")\n                            try\n                            {\n                                val intent = Intent(failURL)\n                                startActivity(intent)\n                            }\n                            catch (e:IllegalStateException)\n                            {\n                                //TODO: Add analytics here to figure out why this happens\n                            }\n                        }\n                    }\n                    catch (e:Exception)\n                    {\n                        // Redirect user to the default fallback site\n                        //fixme: Do something with the error message here\n                        try\n                        {\n                            val intent = Intent(failURL)\n                            startActivity(intent)\n                        }\n                        catch (e:IllegalStateException)\n                        {\n                            //TODO: Add analytics here to figure out why this happens\n                        }\n                    }\n                },\n                Response.ErrorListener\n                {\n                    // If we are sure its a local connectivity issue, alert the user, otherwise send them to the default fallback site\n                    if (it is NetworkError || it is AuthFailureError || it is NoConnectionError)\n                    {\n                        Toast.makeText(context, getString(unity_wallet.R.string.error_check_internet_connection), Toast.LENGTH_SHORT).show()\n                    }\n                    else\n                    {\n                        // Redirect user to the default fallback site\n                        //fixme: Do something with the status message here\n                        //var statusMessage = jsonResponse.getString(\"status_message\")\n                        try\n                        {\n                            val intent = Intent(failURL)\n                            startActivity(intent)\n                        }\n                        catch (e:IllegalStateException)\n                        {\n                            //TODO: Add analytics here to figure out why this happens\n                        }\n                    }\n                }\n            )\n            // Force values to be send at x-www-form-urlencoded\n            {\n                override fun getParams(): MutableMap<String, String> {\n                    val params = HashMap<String,String>()\n                    params[\"address\"] = ILibraryController.GetReceiveAddress().toString()\n                    params[\"uuid\"] = IWalletController.GetUUID()\n                    params[\"currency\"] = \"munt\"\n                    params[\"wallettype\"] = \"android\"\n                    return params\n                }\n                override fun getHeaders(): MutableMap<String, String> {\n                    val params = HashMap<String, String>()\n                    params.put(\"Content-Type\",\"application/x-www-form-urlencoded\")\n                    return params\n                }\n            }\n\n            // Volley request policy, only one time request to avoid duplicate transaction\n            request.retryPolicy = DefaultRetryPolicy(\n                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS,\n                1, // DefaultRetryPolicy.DEFAULT_MAX_RETRIES = 2\n                1f // DefaultRetryPolicy.DEFAULT_BACKOFF_MULT\n            )\n\n            // Add the volley post request to the request queue\n            MyRequestQueue.add(request)\n        }\n    }\n\n    fun setupClipboardManager()\n    {\n        ClipboardManager.OnPrimaryClipChangedListener { checkClipboardEnable() }\n    }\n\n    fun setupAddressbook()\n    {\n        val addresses = ILibraryController.getAddressBookRecords()\n        val adapter = AddressBookAdapter(addresses) { position, address ->\n            val recipient = UriRecipient(true, address.address, address.name, address.desc, 0)\n            SendCoinsFragment.newInstance(recipient, false).show(requireActivity().supportFragmentManager, SendCoinsFragment::class.java.simpleName)\n        }\n\n        addressBookList.adapter = adapter\n        addressBookList.layoutManager = LinearLayoutManager(context)\n\n        val swipeHandler = object : SwipeToDeleteCallback(requireContext()) {\n            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {\n                adapter.removeAt(viewHolder.adapterPosition)\n            }\n        }\n        val itemTouchHelper = ItemTouchHelper(swipeHandler)\n        itemTouchHelper.attachToRecyclerView(addressBookList)\n    }\n\n    override fun onWalletReady()\n    {\n        if (clipboardButton != null) {\n            setupClipboardButton();\n            setupAddressBookButton();\n            setupQRButton();\n            setupSellButton();\n            setupClipboardManager();\n            setupAddressbook();\n            updateEmptyViewState()\n            checkClipboardEnable()\n        }\n    }\n\n    private fun updateEmptyViewState()\n    {\n        val adapter = addressBookList.adapter\n        adapter?.run {\n            if (itemCount > 0) {\n                addressBookList.visibility = View.VISIBLE\n                emptyAddressBookView.visibility = View.GONE\n            }\n            else {\n                addressBookList.visibility = View.GONE\n                emptyAddressBookView.visibility = View.VISIBLE\n            }\n        }\n    }\n\n    override fun onAttach(context: Context)\n    {\n        UnityCore.instance.addObserver(this)\n\n        super.onAttach(context)\n    }\n\n    override fun onDetach() {\n        UnityCore.instance.removeObserver(this)\n\n        super.onDetach()\n    }\n\n    private fun clipboardText(): String\n    {\n        try\n        {\n            val clipboard = ContextCompat.getSystemService(requireContext(), ClipboardManager::class.java)\n            return (clipboard?.primaryClip?.getItemAt(0)?.coerceToText(context)).toString()\n        }\n        catch (e : Exception)\n        {\n            //TODO: We are receiving SecurityException here on some LG G3 android 6 devices, during performResume() - look into in more detail\n            return \"\"\n        }\n    }\n\n    private fun setClipButtonText(text : String)\n    {\n        val styledText = SpannableString(Html.fromHtml(getString(unity_wallet.R.string.send_fragment_clipboard_label) + \"<br/>\" + \"<small> <font color='\"+resources.getColor(unity_wallet.R.color.text_button_secondary)+\"'>\" + ellipsizeString(text, 18) + \"</font> </small>\"))\n        clipboardButton.text = styledText\n    }\n\n    private fun checkClipboardEnable()\n    {\n        // Enable clipboard button if it contains a valid IBAN, Munt address or Uri\n        val text = clipboardText()\n        try {\n            setClipButtonText(createRecipient(text).address)\n        }\n        catch (e: Throwable) {\n            clipboardButton.text = getString(unity_wallet.R.string.send_fragment_clipboard_label)\n        }\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == BARCODE_READER_REQUEST_CODE) {\n            if (resultCode == CommonStatusCodes.SUCCESS)\n            {\n                if (data != null) {\n                    val barcode = data.getParcelableExtra<Barcode>(BarcodeCaptureActivity.BarcodeObject)\n                    val qrContent = barcode?.displayValue\n                    val recipient = try {\n                        createRecipient(qrContent!!)\n                    }\n                    catch (e: InvalidRecipientException) {\n                        errorMessage(getString(unity_wallet.R.string.not_coin_qr, qrContent))\n                        return\n                    }\n                    SendCoinsFragment.newInstance(recipient, false).show(requireActivity().supportFragmentManager, SendCoinsFragment::class.java.simpleName)\n                }\n            }\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    override fun onAddressBookChanged() {\n        val newAddresses = ILibraryController.getAddressBookRecords()\n        handler.post {\n            val adapter = addressBookList.adapter as AddressBookAdapter\n            adapter.updateDataSource(newAddresses)\n            updateEmptyViewState()\n        }\n    }\n\n    companion object {\n        private const val BARCODE_READER_REQUEST_CODE = 1\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/SettingsFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.os.Bundle\nimport androidx.preference.Preference\nimport androidx.preference.SwitchPreference\nimport unity_wallet.Authentication\nimport unity_wallet.R\nimport unity_wallet.WalletActivity\nimport unity_wallet.localCurrency\n\n\nclass SettingsFragment : androidx.preference.PreferenceFragmentCompat()\n{\n    override fun onCreatePreferences(savedInstance: Bundle?, rootKey: String?)\n    {\n        setPreferencesFromResource(R.xml.fragment_settings, rootKey)\n\n        val pref = findPreference<SwitchPreference>(\"preference_hide_balance\")\n        pref?.setOnPreferenceChangeListener { preference, newValue ->\n            val switch = preference as SwitchPreference\n            val hide = newValue as Boolean\n\n            // require authentication to disable hide balance\n            if (!hide) {\n                Authentication.instance.authenticate(requireContext(), null,null) {\n                    switch.isChecked = false\n                }\n                return@setOnPreferenceChangeListener false\n            }\n            else\n                return@setOnPreferenceChangeListener true\n        }\n    }\n\n    override fun onResume()\n    {\n        super.onResume()\n\n        try\n        {\n            val localCurrencyPreference: Preference? = findPreference(\"preference_local_currency\")\n            localCurrencyPreference?.summary = localCurrency.code\n        }\n        catch(e : Exception)\n        {\n            //TODO: Look into why we have a stack trace with KotlinNullPointerException here.\n        }\n    }\n\n    override fun onPreferenceTreeClick(preference: Preference): Boolean\n    {\n        when (preference.key){\n            \"preference_local_currency\" ->  (activity as WalletActivity).pushCurrencyPage()\n            \"preference_show_wallet_settings\" ->  (activity as WalletActivity).pushWalletSettingsPage()\n        }\n        return preference.let { super.onPreferenceTreeClick(it) }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/main_activity_fragments/WalletSettingsFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.main_activity_fragments\n\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Bundle\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.preference.Preference\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.gms.vision.barcode.Barcode\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport com.google.android.material.snackbar.Snackbar\nimport barcodereader.BarcodeCaptureActivity\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.*\nimport unity_wallet.util.invokeNowOrOnSuccessfulCompletion\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.SupervisorJob\nimport kotlin.coroutines.CoroutineContext\n\n\nclass WalletSettingsFragment : androidx.preference.PreferenceFragmentCompat(), CoroutineScope {\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    override fun onCreatePreferences(savedInstance: Bundle?, rootKey: String?) {\n        setPreferencesFromResource(R.xml.fragment_wallet_settings, rootKey)\n\n        // if wallet ready, setup preference fields immediately so settings don't get removed in sight of user\n        UnityCore.instance.walletReady.invokeNowOrOnSuccessfulCompletion(this) {\n            if (ILibraryController.IsMnemonicWallet()) {\n                preferenceScreen.removePreferenceRecursively(\"recovery_linked_preference\")\n                preferenceScreen.removePreferenceRecursively(\"preference_unlink_wallet\")\n            } else {\n                preferenceScreen.removePreferenceRecursively(\"recovery_view_preference\")\n                preferenceScreen.removePreferenceRecursively(\"preference_remove_wallet\")\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        (activity as WalletActivity).showSettingsTitle(getString(R.string.title_wallet_settings))\n\n    }\n\n    override fun onStop() {\n        super.onStop()\n        (activity as WalletActivity).hideSettingsTitle()\n    }\n\n    override fun onPreferenceTreeClick(preference: Preference): Boolean {\n        when (preference.key) {\n            \"preference_link_wallet\" -> {\n                val intent = Intent(context, BarcodeCaptureActivity::class.java)\n                intent.putExtra(BarcodeCaptureActivity.AutoFocus, true)\n                startActivityForResult(intent, REQUEST_CODE_SCAN_FOR_LINK)\n            }\n            \"preference_change_pass_code\" -> {\n                Authentication.instance.authenticate(requireActivity(), getString(R.string.change_passcode_auth_title), getString(R.string.change_passcode_auth_desc)) { oldPassword ->\n                    Authentication.instance.chooseAccessCode(\n                            requireActivity(),\n                            getString(R.string.change_passcode_auth_title),\n                            action = { newPassword ->\n                                if (!ILibraryController.ChangePassword(oldPassword.joinToString(\"\"), newPassword.joinToString(\"\"))) {\n                                    Toast.makeText(context, \"Failed to change password\", Toast.LENGTH_LONG).show()\n                                }\n                            },\n                            cancelled = {}\n                    )\n                }\n            }\n            \"preference_rescan_wallet\" -> {\n                val dialog = MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(getString(R.string.rescan_confirm_title))\n                        .setMessage(getString(R.string.rescan_confirm_msg))\n                        .setPositiveButton(getString(R.string.rescan_confirm_btn)) { dialogInterface: DialogInterface, i: Int ->\n                            ILibraryController.DoRescan()\n                            Snackbar.make(requireView(), getString(R.string.rescan_started), Snackbar.LENGTH_LONG).show()\n                        }\n                        .setNegativeButton(getString(R.string.cancel_btn)) { dialogInterface: DialogInterface, i: Int -> }\n                        .show()\n            }\n            \"preference_remove_wallet\", \"preference_unlink_wallet\" -> {\n                val msg = \"%s%s\".format(\n                        if (ILibraryController.IsMnemonicWallet())\n                            getString(R.string.remove_wallet_auth_desc_recovery_warn)\n                        else \"\",\n                        getString(R.string.remove_wallet_auth_desc))\n                Authentication.instance.authenticate(requireActivity(), getString(R.string.remove_wallet_auth_title), msg) {\n                    ILibraryController.EraseWalletSeedsAndAccounts()\n                    val intent = Intent(activity, WelcomeActivity::class.java)\n                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)\n                    startActivity(intent)\n                }\n            }\n        }\n        return super.onPreferenceTreeClick(preference)\n    }\n\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        if (requestCode == REQUEST_CODE_SCAN_FOR_LINK) {\n            if (resultCode == CommonStatusCodes.SUCCESS) {\n                if (data != null) {\n                    val barcode = data.getParcelableExtra<Barcode>(BarcodeCaptureActivity.BarcodeObject)\n\n                    if (!ILibraryController.IsValidLinkURI(barcode?.displayValue)) {\n                        AlertDialog.Builder(requireContext())\n                                .setTitle(getString(R.string.no_qrsync_warning_title))\n                                .setMessage(getString(R.string.no_qrsync_warning))\n                                .setPositiveButton(getString(R.string.button_ok)) { dialogInterface, i ->\n                                    dialogInterface.dismiss()\n                                }\n                                .setCancelable(true)\n                                .create()\n                                .show()\n                        return\n                    }\n\n                    // dialog helper used below\n                    fun performDialog(titleResId: Int, msgResId: Int, withCancel: Boolean, action: (dialogInterface: DialogInterface) -> Unit) {\n                        val builder = AlertDialog.Builder(requireContext())\n                                .setTitle(getString(titleResId))\n                                .setMessage(getString(msgResId))\n                                .setPositiveButton(getString(R.string.button_ok)) { dialogInterface, i ->\n                                    action(dialogInterface)\n                                }\n                                .setCancelable(true)\n                        if (withCancel)\n                            builder.setNegativeButton(getString(R.string.button_cancel)) { dialogInterface, i ->\n                                dialogInterface.dismiss()\n                            }\n                        builder.create().show()\n                    }\n\n                    if (ILibraryController.HaveUnconfirmedFunds()) {\n                        performDialog(R.string.failed_qrsync_warning_title, R.string.failed_qrsync_unconfirmed_funds_message, false) {\n                            it.dismiss()\n                        }\n                        return\n                    }\n\n                    //TODO: Refuse to link if we are in the process of a sync.\n\n                    performDialog(\n                            R.string.qrsync_info_title,\n                            if (ILibraryController.GetBalance() > 0) R.string.qrsync_info_message_non_empty_wallet else R.string.qrsync_info_message_empty_wallet, true\n                    ) {\n                        it.dismiss()\n                        (activity as WalletActivity).performLink(barcode!!.displayValue)\n                    }\n                }\n            }\n        } else {\n            super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    companion object {\n        private const val REQUEST_CODE_SCAN_FOR_LINK = 0\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/AddressBookAdapter.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.recyclerview.widget.RecyclerView\nimport unity_wallet.jniunifiedbackend.AddressRecord\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport kotlinx.android.synthetic.main.address_book_list_item.view.*\n\nclass AddressBookAdapter(private var dataSource: ArrayList<AddressRecord>, val onItemClick: (position: Int, address: AddressRecord) -> Unit) : RecyclerView.Adapter<AddressBookAdapter.MyViewHolder>() {\n\n    fun updateDataSource(newDataSource: ArrayList<AddressRecord>) {\n        dataSource = newDataSource\n        notifyDataSetChanged()\n    }\n\n    class MyViewHolder(val view: View): RecyclerView.ViewHolder(view)\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {\n        val view = LayoutInflater.from(parent.context)\n                .inflate(R.layout.address_book_list_item, parent, false)\n        // set the view's size, margins, padding and layout parameters\n        return MyViewHolder(view)\n    }\n\n    override fun getItemCount(): Int {\n        return dataSource.size\n    }\n\n    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {\n        val view = holder.itemView\n\n        val addressRecord = dataSource[position]\n        view.textViewLabel.text = addressRecord.name\n\n        view.setOnClickListener {\n            onItemClick(position, addressRecord)\n        }\n    }\n\n    override fun getItemId(position: Int): Long {\n        return position.toLong()\n    }\n\n    fun removeAt(position: Int) {\n        UnityCore.instance.deleteAddressBookRecord(dataSource[position])\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/DisplayHelpers.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui\n\nimport android.content.Context\nimport android.graphics.Point\nimport android.util.DisplayMetrics\nimport android.view.WindowManager\n\nfun Dp2Px(context: Context, dp: Int): Int {\n    return Math.round(dp * (context.resources.displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))\n}\n\nfun Px2Dp(context: Context, px: Int): Int {\n    return Math.round(px / (context.resources.displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))\n}\n\nfun getDisplayDimensions(context: Context): Point {\n    val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager\n    val display = wm.defaultDisplay\n\n    val metrics = DisplayMetrics()\n    display.getMetrics(metrics)\n    val screenWidth = metrics.widthPixels\n    var screenHeight = metrics.heightPixels\n\n    // find out if status bar has already been subtracted from screenHeight\n    display.getRealMetrics(metrics)\n    val physicalHeight = metrics.heightPixels\n    val statusBarHeight = getStatusBarHeight(context)\n    val navigationBarHeight = getNavigationBarHeight(context)\n    val heightDelta = physicalHeight - screenHeight\n    if (heightDelta == 0 || heightDelta == navigationBarHeight) {\n        screenHeight -= statusBarHeight\n    }\n\n    return Point(screenWidth, screenHeight)\n}\n\nfun getStatusBarHeight(context: Context): Int {\n    val resources = context.resources\n    val resourceId = resources.getIdentifier(\"status_bar_height\", \"dimen\", \"android\")\n    return if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0\n}\n\nfun getNavigationBarHeight(context: Context): Int {\n    val resources = context.resources\n    val resourceId = resources.getIdentifier(\"navigation_bar_height\", \"dimen\", \"android\")\n    return if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/EnterRecoveryPhraseActivity.kt",
    "content": "package unity_wallet.ui\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.text.Editable\nimport android.text.TextWatcher\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.inputmethod.EditorInfo\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.MultiAutoCompleteTextView\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.Authentication\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.internalErrorAlert\nimport unity_wallet.util.AppBaseActivity\nimport unity_wallet.util.gotoWalletActivity\nimport unity_wallet.util.setFauxButtonEnabledState\nimport kotlinx.android.synthetic.main.activity_enter_recovery_phrase.*\n\nprivate const val TAG = \"enter-recovery-activity\"\n\nclass EnterRecoveryPhraseActivity : AppBaseActivity(), UnityCore.Observer\n{\n    private val erasedWallet = UnityCore.instance.isCoreReady()\n\n    private val recoveryPhrase: String\n        get() = recover_from_phrase_text_view.text.toString().trim { it <= ' ' }\n\n    inner class SpaceTokenizer : MultiAutoCompleteTextView.Tokenizer\n    {\n        override fun findTokenStart(text: CharSequence, cursor: Int): Int\n        {\n            var i = cursor\n\n            while (i > 0 && text[i - 1] != ' ')\n            {\n                i--\n            }\n            while (i < cursor && text[i] == ' ')\n            {\n                i++\n            }\n\n            return i\n        }\n\n        override fun findTokenEnd(text: CharSequence?, cursor: Int): Int\n        {\n            var len = 0\n            if (text != null)\n            {\n                var i = cursor\n                len = text.length\n\n                while (i < len)\n                {\n                    if (text[i] == ' ')\n                    {\n                        return i\n                    }\n                    else\n                    {\n                        i++\n                    }\n                }\n            }\n\n            return len\n        }\n\n        override fun terminateToken(text: CharSequence): CharSequence\n        {\n            return text.toString().trim { it <= ' ' } + \" \"\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?)\n    {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_enter_recovery_phrase)\n\n        recover_from_phrase_proceed_button.setOnClickListener{  onAcceptRecoverFromPhrase(it) }\n\n        recover_from_phrase_text_view.run {\n            addTextChangedListener(object : TextWatcher {\n                override fun afterTextChanged(s: Editable)\n                {\n                    updateView()\n                }\n\n                override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int)\n                {\n\n                }\n\n                override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int)\n                {\n\n                }\n            })\n            imeOptions = EditorInfo.IME_ACTION_DONE\n            setOnEditorActionListener(TextView.OnEditorActionListener { _, actionId, _ ->\n                if (actionId == EditorInfo.IME_ACTION_DONE)\n                {\n                    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n                    imm.hideSoftInputFromWindow(windowToken, 0)\n                    return@OnEditorActionListener true\n                }\n                false\n            })\n            setTokenizer(SpaceTokenizer())\n        }\n\n        supportActionBar?.hide()\n\n        updateView()\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n\n        UnityCore.instance.removeObserver(this)\n    }\n\n    override fun onWalletReady() {\n        if (!erasedWallet)\n            gotoWalletActivity(this)\n    }\n\n    override fun onWalletCreate() {\n        // do nothing, we are supposed to sit here until the wallet was created\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean\n    {\n        when (item.itemId)\n        {\n            android.R.id.home ->\n            {\n                finish()\n                return true\n            }\n        }\n\n        return super.onOptionsItemSelected(item)\n    }\n\n    private fun chooseAccessCodeAndProceed(mnemonicPhrase : String)\n    {\n        // TODO must have core started and createWallet signal\n\n        val originaButtonState = recover_from_phrase_proceed_button.visibility\n        recover_from_phrase_proceed_button.visibility = View.INVISIBLE\n        Authentication.instance.chooseAccessCode(\n                this,\n                null,\n                action = { password->\n                    if (UnityCore.instance.isCoreReady()) {\n                        if (ILibraryController.ContinueWalletFromRecoveryPhrase(mnemonicPhrase, password.joinToString(\"\"))) {\n                            gotoWalletActivity(this)\n                        } else {\n                            internalErrorAlert(this, \"$TAG continuation failed\")\n                        }\n                    } else {\n                        // Create the new wallet, a coreReady event will follow which will proceed to the main activity\n                        if (!ILibraryController.InitWalletFromRecoveryPhrase(mnemonicPhrase, password.joinToString(\"\")))\n                            internalErrorAlert(this, \"$TAG init failed\")\n                    }\n                },\n                cancelled = fun() {recover_from_phrase_proceed_button.visibility = originaButtonState}\n        )\n    }\n\n    private fun promptUserForBirthDate()\n    {\n        val builder = AlertDialog.Builder(this)\n\n        //TODO: Display info message 'R.string.wallet_birth_info' here (requires a custom dialog as AlertDialog can't handle both)\n        //TODO: Create a nicer looking dialog here (look at using a bottom drawer for instance)\n        builder.setTitle(getString(R.string.wallet_birth_heading))\n                .setItems(R.array.wallet_birth_date) { dialog, selection ->\n                    val unixTime = System.currentTimeMillis() / 1000L\n                    when (selection)\n                    {\n                        0 -> chooseAccessCodeAndProceed(ILibraryController.ComposeRecoveryPhrase(recoveryPhrase, unixTime-(86400*31)).phraseWithBirthNumber)\n                        1 -> chooseAccessCodeAndProceed(ILibraryController.ComposeRecoveryPhrase(recoveryPhrase, unixTime-(86400*365)).phraseWithBirthNumber)\n                        2 -> chooseAccessCodeAndProceed(recoveryPhrase)\n                    }\n                }\n        builder.create().show()\n    }\n\n    private fun onAcceptRecoverFromPhrase(view: View)\n    {\n        if (!ILibraryController.IsValidRecoveryPhrase(recoveryPhrase))\n        {\n            Toast.makeText(applicationContext, \"Invalid recovery phrase\", Toast.LENGTH_LONG).show()\n            return\n        }\n\n        if (recoveryPhrase == recoveryPhrase.trimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '))\n        {\n            promptUserForBirthDate()\n        }\n        else\n        {\n            chooseAccessCodeAndProceed(recoveryPhrase)\n        }\n    }\n\n    fun updateView()\n    {\n        // Toggle button visual disabled/enabled indicator while still keeping it clickable\n        setFauxButtonEnabledState(recover_from_phrase_proceed_button, ILibraryController.IsValidRecoveryPhrase(recoveryPhrase))\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/LocalCurrenciesAdapter.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui\n\nimport android.content.Context\nimport android.preference.PreferenceManager\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport unity_wallet.AppContext\nimport unity_wallet.Currency\nimport unity_wallet.R\nimport unity_wallet.localCurrency\nimport kotlinx.android.synthetic.main.local_currency_list_item.view.*\nimport java.util.*\n\nclass LocalCurrenciesAdapter(context: Context, private val dataSource: TreeMap<String, Currency>) : BaseAdapter() {\n    private val inflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater\n    private var allRates = mapOf<String, Double>()\n\n    override fun getCount(): Int {\n        return dataSource.size\n    }\n\n    override fun getItem(position: Int) : Currency\n    {\n        return dataSource.values.toTypedArray()[position]\n    }\n\n    override fun getItemId(position: Int): Long {\n        return position.toLong()\n    }\n\n    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n\n        val currencyRecord = getItem(position)\n        val rowView = inflater.inflate(R.layout.local_currency_list_item, parent, false)\n        rowView.textViewCurrencyName.text = currencyRecord.name\n        rowView.textViewCurrencyCode.text = currencyRecord.code\n        rowView.imageViewCurrencySelected.visibility = if (currencyRecord.code == localCurrency.code)\n        {\n            View.VISIBLE\n        }\n        else\n        {\n            View.GONE\n        }\n        if (currencyRecord.code == localCurrency.code && allRates.containsKey(currencyRecord.code)) {\n            val rate = allRates.getValue(currencyRecord.code)\n            rowView.exchangeRateView.text = currencyRecord.formatRate(rate)\n            rowView.exchangeRateView.visibility = View.VISIBLE\n        }\n        else {\n            rowView.exchangeRateView.visibility = View.GONE\n        }\n        return rowView\n    }\n\n    fun setSelectedPosition(position: Int) = PreferenceManager.getDefaultSharedPreferences(AppContext.instance).edit().putString(\"preference_local_currency\",\n        getItem(position).code\n    ).apply()\n\n    fun updateAllRates(rates: Map<String, Double>) {\n        allRates = rates\n        notifyDataSetChanged()\n    }\n}\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/MutationAdapter.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui\n\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport androidx.core.content.ContextCompat\nimport unity_wallet.jniunifiedbackend.MutationRecord\nimport unity_wallet.jniunifiedbackend.TransactionStatus\nimport unity_wallet.R\nimport unity_wallet.formatNativeAndLocal\nimport kotlinx.android.synthetic.main.mutation_list_item.view.*\nimport kotlinx.android.synthetic.main.mutation_list_item_with_header.view.*\nimport java.util.*\n\nclass MutationAdapter(context: Context, private var dataSource: ArrayList<MutationRecord>) : BaseAdapter() {\n    private val inflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater\n    private var rate = 0.0\n    private var mContext = context\n\n    //NB! This may cause a minor cosmetic glitch if user is on transaction screen when year crosses over (years just won't display so nothing too terrible)\n    //This is preferable to the performance penalty of constantly creating calendar instances\n    private val currentYear = Calendar.getInstance().get(Calendar.YEAR)\n\n    fun updateRate(rate_: Double) {\n        rate = rate_\n        notifyDataSetChanged()\n    }\n\n    fun updateDataSource(newDataSource: ArrayList<MutationRecord>) {\n        dataSource = newDataSource\n        notifyDataSetChanged()\n    }\n\n    override fun getCount(): Int {\n        return dataSource.size\n    }\n\n    override fun getItem(position: Int): Any {\n        return dataSource[position]\n    }\n\n    override fun getItemId(position: Int): Long {\n        return position.toLong()\n    }\n\n    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n\n        val mutationRecord = getItem(position) as MutationRecord\n        val date = if (Date(mutationRecord.timestamp * 1000L).year + 1900 != currentYear)\n        {\n            java.text.SimpleDateFormat(\"dd MMM. yyyy\").format(Date(mutationRecord.timestamp * 1000L))\n        }\n        else\n        {\n            java.text.SimpleDateFormat(\"MMMM dd\").format(Date(mutationRecord.timestamp * 1000L))\n        }\n        var prevDate = \"\"\n        if (position != 0) {\n            val prevMutationRecord = getItem(position-1) as MutationRecord\n            prevDate = if (Date(prevMutationRecord.timestamp * 1000L).year + 1900 != currentYear)\n            {\n                java.text.SimpleDateFormat(\"dd MMM. yyyy\").format(Date(prevMutationRecord.timestamp * 1000L))\n            }\n            else\n            {\n                java.text.SimpleDateFormat(\"MMMM dd\").format(Date(prevMutationRecord.timestamp * 1000L))\n            }\n        }\n\n\n        val rowView : View\n        if (date != prevDate)\n        {\n            rowView = inflater.inflate(R.layout.mutation_list_item_with_header, parent, false)\n            rowView.transactionItemHeading.text = date\n        }\n        else\n        {\n            rowView = inflater.inflate(R.layout.mutation_list_item, parent, false)\n        }\n\n        rowView.textViewTime.text = java.text.SimpleDateFormat(\"HH:mm\").format(Date(mutationRecord.timestamp * 1000L))\n        rowView.textViewAmount.text = formatNativeAndLocal(mutationRecord.change,rate)\n        rowView.textViewAmount.setTextColor(ContextCompat.getColor(rowView.context, if (mutationRecord.change >= 0) R.color.change_positive else R.color.change_negative))\n\n        when (mutationRecord.status) {\n            TransactionStatus.CONFIRMED -> {\n                rowView.textViewStatus.text = \"\"\n            }\n            TransactionStatus.CONFIRMING -> {\n                rowView.textViewStatus.text = mContext.resources.getQuantityString(R.plurals.transaction_confirmation_text, mutationRecord.depth, mutationRecord.depth)\n            }\n            TransactionStatus.CONFLICTED -> {\n                rowView.textViewStatus.text = mContext.resources.getString(R.string.transaction_confirmation_text_conflicted)\n            }\n            TransactionStatus.ABANDONED -> {\n                rowView.textViewStatus.text = mContext.resources.getString(R.string.transaction_confirmation_text_abandoned)\n            }\n            TransactionStatus.UNCONFIRMED -> {\n                rowView.textViewStatus.text = mContext.resources.getString(R.string.transaction_confirmation_text_pending)\n            }\n        }\n        return rowView\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/ShowRecoveryPhraseActivity.kt",
    "content": "package unity_wallet.ui\n\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.text.Spannable\nimport android.text.SpannableString\nimport android.text.style.BackgroundColorSpan\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.view.View\nimport android.widget.Toast\nimport androidx.appcompat.view.ActionMode\nimport androidx.appcompat.widget.ShareActionProvider\nimport androidx.core.view.MenuItemCompat\nimport com.google.android.material.color.MaterialColors\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.*\nimport unity_wallet.util.AppBaseActivity\nimport unity_wallet.util.gotoWalletActivity\nimport unity_wallet.util.setFauxButtonEnabledState\nimport kotlinx.android.synthetic.main.activity_show_recovery_phrase.*\n\nprivate const val TAG = \"show-recovery-activity\"\n\nclass ShowRecoveryPhraseActivity : AppBaseActivity(), UnityCore.Observer\n{\n    private val erasedWallet = UnityCore.instance.isCoreReady()\n\n    //fixme: (MUNT) Change to char[] to we can securely wipe.\n    private var recoveryPhrase: String? = null\n    internal var recoveryPhraseTrimmed: String? = null\n\n    private var shareActionProvider: ShareActionProvider? = null\n\n    override fun onCreate(savedInstanceState: Bundle?)\n    {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_show_recovery_phrase)\n\n        recoveryPhrase = intent.getStringExtra(this.packageName + \"recovery_phrase_with_birth\")\n        recoveryPhraseTrimmed = intent.getStringExtra(this.packageName + \"recovery_phrase\")\n        recovery_phrase_text_view.run {\n            //TODO: Reintroduce showing birth time here if/when we decide we want it in future\n            text = recoveryPhraseTrimmed\n            setOnClickListener { setFocusOnRecoveryPhrase() }\n        }\n\n        supportActionBar?.hide()\n\n        updateView()\n\n        acknowledge_recovery_phrase.setOnClickListener{  onAcknowledgeRecoveryPhrase(it) }\n        button_accept_recovery_phrase.setOnClickListener{  onAcceptRecoveryPhrase(it) }\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n    }\n\n    override fun onOptionsItemSelected(item: MenuItem): Boolean\n    {\n        when (item.itemId)\n        {\n            android.R.id.home ->\n            {\n                finish()\n                return true\n            }\n        }\n\n        return super.onOptionsItemSelected(item)\n    }\n\n    override fun onDestroy()\n    {\n        UnityCore.instance.removeObserver(this)\n        //fixme: (MUNT) Securely wipe.\n        recoveryPhrase = \"\"\n        recoveryPhraseTrimmed = \"\"\n        super.onDestroy()\n    }\n\n    override fun onWalletReady() {\n        if (!erasedWallet)\n            gotoWalletActivity(this)\n    }\n\n    override fun onWalletCreate() {\n        // do nothing, we are supposed to sit here until the wallet was created\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onAcceptRecoveryPhrase(view: View)\n    {\n        // Only allow user to move on once they have acknowledged writing the recovery phrase down.\n        if (!acknowledge_recovery_phrase.isChecked)\n        {\n            Toast.makeText(applicationContext, \"Write down your recovery phrase\", Toast.LENGTH_LONG).show()\n            return\n        }\n\n        button_accept_recovery_phrase.visibility = View.INVISIBLE\n        // TODO must have core started and createWallet signal\n\n        Authentication.instance.chooseAccessCode(\n                this,\n                null,\n                action = fun(password: CharArray) {\n                    if (UnityCore.instance.isCoreReady()) {\n                        if (ILibraryController.ContinueWalletFromRecoveryPhrase(recoveryPhrase, password.joinToString(\"\"))) {\n                            gotoWalletActivity(this)\n                        } else {\n                            internalErrorAlert(this, \"$TAG continuation failed\")\n                        }\n                    } else {\n                        // Create the new wallet, a coreReady event will follow which will proceed to the main activity\n                        if (!ILibraryController.InitWalletFromRecoveryPhrase(recoveryPhrase, password.joinToString(\"\")))\n                            internalErrorAlert(this, \"$TAG init failed\")\n                    }\n                },\n                cancelled = fun() {button_accept_recovery_phrase.visibility = View.VISIBLE}\n        )\n    }\n\n    @Suppress(\"UNUSED_PARAMETER\")\n    fun onAcknowledgeRecoveryPhrase(view: View)\n    {\n        updateView()\n    }\n\n    private fun updateView()\n    {\n        setFauxButtonEnabledState(button_accept_recovery_phrase, acknowledge_recovery_phrase.isChecked)\n    }\n\n    internal inner class ActionBarCallBack : ActionMode.Callback\n    {\n        override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean\n        {\n            return if (item.itemId == R.id.item_copy_to_clipboard)\n            {\n                val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager\n                val clip = ClipData.newPlainText(\"backup\", recoveryPhraseTrimmed)\n                clipboard.setPrimaryClip(clip)\n                mode.finish()\n                Toast.makeText(applicationContext, R.string.recovery_phrase_copy, Toast.LENGTH_LONG).show()\n                true\n            }\n            else false\n\n        }\n\n\n        override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean\n        {\n            mode.menuInflater.inflate(R.menu.share_menu, menu)\n\n            // Handle buy button\n            val itemBuy = menu.findItem(R.id.item_buy_coins)\n            itemBuy.isVisible = false\n\n            // Handle copy button\n            //MenuItem itemCopy = menu.findItem(R.id.item_copy_to_clipboard);\n\n            // Handle share button\n            val itemShare = menu.findItem(R.id.action_share)\n            shareActionProvider = ShareActionProvider(this@ShowRecoveryPhraseActivity)\n            MenuItemCompat.setActionProvider(itemShare, shareActionProvider)\n\n            val intent = Intent(Intent.ACTION_SEND)\n            intent.type = \"text/plain\"\n            intent.putExtra(Intent.EXTRA_TEXT, recoveryPhraseTrimmed)\n            shareActionProvider!!.setShareIntent(intent)\n\n            @Suppress(\"DEPRECATION\")\n            val color = MaterialColors.getColor(recovery_phrase_text_view, R.attr.colorControlHighlight)\n            val spannableString = SpannableString(recovery_phrase_text_view.text)\n            spannableString.setSpan(BackgroundColorSpan(color), 0, recovery_phrase_text_view.text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)\n            recovery_phrase_text_view.text = spannableString\n\n            return true\n        }\n\n        override fun onDestroyActionMode(mode: ActionMode)\n        {\n            shareActionProvider = null\n\n            recovery_phrase_text_view.text = recoveryPhraseTrimmed ?: \"\"\n        }\n\n        override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean\n        {\n            return false\n        }\n    }\n\n    private fun setFocusOnRecoveryPhrase()\n    {\n        startSupportActionMode(ActionBarCallBack())\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/BlockListAdapter.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.text.format.DateUtils\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.PopupMenu\nimport androidx.recyclerview.widget.DiffUtil\nimport androidx.recyclerview.widget.ListAdapter\nimport androidx.recyclerview.widget.RecyclerView\nimport unity_wallet.jniunifiedbackend.BlockInfoRecord\nimport unity_wallet.Config\nimport unity_wallet.R\nimport kotlinx.android.synthetic.main.block_row.view.*\n\nclass BlockListAdapter : ListAdapter<BlockInfoRecord, BlockListAdapter.ItemViewHolder>(BlockDiffCallback()) {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {\n        return ItemViewHolder(\n                LayoutInflater.from(parent.context)\n                        .inflate(R.layout.block_row, parent, false)\n        )\n    }\n\n    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {\n        holder.bind(getItem(position))\n    }\n\n    class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n        fun bind(item: BlockInfoRecord) = with(itemView) {\n            itemView.block_list_row_height.text = item.height.toString()\n            val ms = item.timeStamp * DateUtils.SECOND_IN_MILLIS\n            itemView.block_list_row_time.text =\n                    if (ms < System.currentTimeMillis() - DateUtils.MINUTE_IN_MILLIS) {\n                        DateUtils.getRelativeDateTimeString(context, ms, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0).toString()\n                    } else\n                        context.getString(R.string.block_row_now)\n            itemView.block_list_row_hash.text = item.blockHash\n            itemView.block_list_row_menu.setOnClickListener {\n                val popupMenu = PopupMenu(context, itemView.block_list_row_menu)\n                popupMenu.inflate(R.menu.blocks_context)\n                popupMenu.setOnMenuItemClickListener { menuItem ->\n                    when (menuItem.itemId) {\n                        R.id.blocks_context_browse -> {\n                            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(Config.BLOCK_EXPLORER_BLOCK_TEMPLATE.format(item.blockHash)))\n                            context.startActivity(intent)\n                        }\n                    }\n                    return@setOnMenuItemClickListener true\n                }\n                popupMenu.show()\n            }\n        }\n    }\n}\n\nprivate class BlockDiffCallback : DiffUtil.ItemCallback<BlockInfoRecord>() {\n    override fun areItemsTheSame(oldItem: BlockInfoRecord, newItem: BlockInfoRecord): Boolean {\n        return oldItem.blockHash == newItem.blockHash\n    }\n\n    override fun areContentsTheSame(oldItem: BlockInfoRecord, newItem: BlockInfoRecord): Boolean {\n        return oldItem == newItem\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/BlockListFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.lifecycle.ViewModelProviders\nimport androidx.recyclerview.widget.DividerItemDecoration\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport unity_wallet.jniunifiedbackend.MonitorListener\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.util.AppBaseFragment\nimport kotlinx.android.synthetic.main.block_list_fragment.*\nimport kotlinx.android.synthetic.main.block_list_fragment.view.*\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\n\nclass BlockListFragment : AppBaseFragment() {\n    private lateinit var viewModel: BlockListViewModel\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,\n                              savedInstanceState: Bundle?): View? {\n\n        val adapter = BlockListAdapter()\n\n        viewModel = ViewModelProviders.of(this).get(BlockListViewModel::class.java)\n\n        // observe changes\n        viewModel.getBlocks().observe(viewLifecycleOwner, { blocks ->\n            if (blocks.isEmpty()) {\n                block_list_group.displayedChild = 0\n            } else {\n                block_list_group.displayedChild = 1\n                adapter.submitList(blocks)\n            }\n        })\n\n        val view = inflater.inflate(R.layout.block_list_fragment, container, false)\n\n        view.block_list.let { recycler ->\n            recycler.layoutManager = LinearLayoutManager(context)\n            recycler.adapter = adapter\n            recycler.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))\n        }\n\n        return view\n    }\n\n    override fun onWalletReady() {\n        launch(Dispatchers.Main) {\n            // update data once\n            updateBlocks()\n        }\n    }\n\n    private suspend fun updateBlocks() {\n        val data = withContext(Dispatchers.IO) {\n            ILibraryController.getLastSPVBlockInfos()\n        }\n        viewModel.setBlocks(data)\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        UnityCore.instance.addMonitorObserver(monitoringListener)\n    }\n\n    override fun onPause() {\n        UnityCore.instance.removeMonitorObserver(monitoringListener)\n\n        super.onPause()\n    }\n\n    private val monitoringListener = object: MonitorListener() {\n        override fun onPruned(height: Int) {}\n\n        override fun onProcessedSPVBlocks(height: Int) {}\n\n        override fun onPartialChain(height: Int, probableHeight: Int, offset: Int) {\n            this@BlockListFragment.launch(Dispatchers.Main) {\n                updateBlocks()\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/BlockListViewModel.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport unity_wallet.jniunifiedbackend.BlockInfoRecord\n\nclass BlockListViewModel : ViewModel() {\n    private lateinit var blocks: MutableLiveData<List<BlockInfoRecord>>\n\n    fun getBlocks(): LiveData<List<BlockInfoRecord>> {\n        if (!::blocks.isInitialized) {\n            blocks = MutableLiveData()\n        }\n        return blocks\n    }\n\n    fun setBlocks(blocks_: List<BlockInfoRecord>) {\n        if (!::blocks.isInitialized) {\n            blocks = MutableLiveData()\n        }\n        blocks.value = blocks_\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/NetworkMonitorActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.os.Bundle\nimport android.view.View\nimport com.google.android.material.bottomnavigation.BottomNavigationView\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.util.AppBaseActivity\nimport kotlinx.android.synthetic.main.activity_main.navigation\nimport kotlinx.android.synthetic.main.activity_main.syncProgress\nimport kotlinx.android.synthetic.main.activity_network_monitor.*\nimport kotlinx.coroutines.Job\n\nclass NetworkMonitorActivity : UnityCore.Observer, AppBaseActivity()\n{\n    override fun onCreate(savedInstanceState: Bundle?)\n    {\n        super.onCreate(savedInstanceState)\n\n        setContentView(R.layout.activity_network_monitor)\n\n        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)\n\n        syncProgress.max = 1000000\n\n        networkMonitorBackButton.setOnClickListener{  onBackButtonPushed(it) }\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n\n        coroutineContext[Job]!!.cancel()\n    }\n\n    override fun onStart() {\n        super.onStart()\n\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { runOnUiThread { callback() }})\n\n        if (supportFragmentManager.fragments.isEmpty()) {\n            addFragment(PeerListFragment(), R.id.networkMonitorMainLayout)\n        }\n    }\n\n    override fun onStop() {\n        super.onStop()\n        UnityCore.instance.removeObserver(this)\n    }\n\n    override fun onWalletReady() {\n        setSyncProgress(UnityCore.instance.progressPercent)\n    }\n\n    private fun onBackButtonPushed(view : View) {\n        finish()\n    }\n\n    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->\n        val page = when (item.itemId) {\n            R.id.navigation_peers -> PeerListFragment()\n            R.id.navigation_blocks -> BlockListFragment()\n            R.id.navigation_processing -> ProcessingFragment()\n            else -> return@OnNavigationItemSelectedListener false\n        }\n        gotoFragment(page, R.id.networkMonitorMainLayout)\n        true\n    }\n\n\n    override fun syncProgressChanged(percent: Float) {\n        setSyncProgress(percent)\n    }\n\n    private fun setSyncProgress(percent: Float)\n    {\n        syncProgress.progress = (syncProgress.max * (percent/100)).toInt()\n        if (percent < 100.0)\n            syncProgress.visibility = View.VISIBLE\n        else\n            syncProgress.visibility = View.INVISIBLE\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/PeerListAdapter.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.annotation.SuppressLint\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.recyclerview.widget.DiffUtil\nimport androidx.recyclerview.widget.ListAdapter\nimport androidx.recyclerview.widget.RecyclerView\nimport unity_wallet.jniunifiedbackend.PeerRecord\nimport unity_wallet.R\nimport kotlinx.android.synthetic.main.peer_list_row.view.*\n\n\n\nclass PeerListAdapter : ListAdapter<PeerRecord, PeerListAdapter.ItemViewHolder>(DiffCallback())  {\n\n    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {\n        return ItemViewHolder(\n                LayoutInflater.from(parent.context)\n                        .inflate(R.layout.peer_list_row, parent, false)\n        )\n    }\n\n    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {\n        holder.bind(getItem(position))\n    }\n\n    class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {\n        fun bind(item: PeerRecord) = with(itemView) {\n\n            itemView.peer_list_row_ip.text = if (item.hostname.isEmpty()) item.ip else item.hostname\n            itemView.peer_list_row_height.text = if (item.syncedHeight > 0) item.syncedHeight.toString() + \" blocks\" else if (item.startHeight > 0) item.startHeight.toString() + \" blocks\" else null\n            itemView.peer_list_row_user_agent.text = item.userAgent\n            itemView.peer_list_row_protocol.text = item.protocol.toString()\n            @SuppressLint(\"SetTextI18n\")\n            itemView.peer_list_row_ping.text = item.latency.toString()+\"ms\"\n        }\n    }\n\n    override fun getItemId(position: Int): Long\n    {\n        val product = getItem(position)\n        return product.id\n    }\n}\n\nclass DiffCallback : DiffUtil.ItemCallback<PeerRecord>() {\n    override fun areItemsTheSame(oldItem: PeerRecord, newItem: PeerRecord): Boolean {\n        return oldItem.ip == newItem.ip\n    }\n\n    override fun areContentsTheSame(oldItem: PeerRecord, newItem: PeerRecord): Boolean {\n        return oldItem == newItem\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/PeerListFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.lifecycle.ViewModelProviders\nimport androidx.recyclerview.widget.DividerItemDecoration\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport unity_wallet.jniunifiedbackend.IP2pNetworkController\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.util.AppBaseFragment\nimport kotlinx.android.synthetic.main.peer_list_fragment.*\nimport kotlinx.android.synthetic.main.peer_list_fragment.view.*\nimport kotlinx.coroutines.*\nimport kotlin.coroutines.CoroutineContext\n\nclass PeerListFragment : AppBaseFragment(), CoroutineScope {\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    private var peerUpdateJob: Job? = null\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,\n                              savedInstanceState: Bundle?): View? {\n\n        val adapter = PeerListAdapter()\n        adapter.setHasStableIds(true)\n\n        val viewModel = ViewModelProviders.of(this).get(PeerListViewModel::class.java)\n\n        // observe peer changes\n        viewModel.getPeers().observe(viewLifecycleOwner, { peers ->\n            if (peers.isEmpty()) {\n                peer_list_group.displayedChild = 1\n            } else {\n                peer_list_group.displayedChild = 2\n                adapter.submitList(peers)\n            }\n        })\n\n        // periodically update peers\n        peerUpdateJob = launch(Dispatchers.Main) {\n            try {\n                UnityCore.instance.walletReady.await()\n                while (isActive) {\n                    val peers = withContext(Dispatchers.IO) {\n                        IP2pNetworkController.getPeerInfo()\n                    }\n                    viewModel.setPeers(peers)\n                    delay(3000)\n                }\n            }\n            catch (e: Throwable) {\n                // silently ignore walletReady failure (deferred was cancelled or completed with exception)\n            }\n        }\n\n        val view = inflater.inflate(R.layout.peer_list_fragment, container, false)\n\n        view.peer_list.let { recycler ->\n            recycler.layoutManager = LinearLayoutManager(context)\n            recycler.adapter = adapter\n            recycler.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))\n\n            // Turn off item animation as it causes annoying flicker every time we do an update (every 3000ms)\n            recycler.itemAnimator = null\n            // Turn off scroll bar fading as otherwise the scroll bar annoyingly keeps appearing and re-appearing when we do an update (every 3000ms)\n            recycler.isScrollbarFadingEnabled = false\n        }\n\n        return view\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        peerUpdateJob?.cancel()\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/PeerListViewModel.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport unity_wallet.jniunifiedbackend.PeerRecord\n\nclass PeerListViewModel : ViewModel() {\n    private lateinit var peers: MutableLiveData<List<PeerRecord>>\n\n    fun getPeers(): LiveData<List<PeerRecord>> {\n        if (!::peers.isInitialized) {\n            peers = MutableLiveData()\n        }\n        return peers\n    }\n\n    fun setPeers(_peers: List<PeerRecord>) {\n        if (!::peers.isInitialized) {\n            peers = MutableLiveData()\n        }\n        peers.value = _peers\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/monitor/ProcessingFragment.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.monitor\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport unity_wallet.jniunifiedbackend.MonitorListener\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.util.AppBaseFragment\nimport kotlinx.android.synthetic.main.processing_fragment.*\nimport kotlinx.android.synthetic.main.processing_fragment.view.*\nimport android.os.Handler\nimport android.os.Looper\n\nclass ProcessingFragment : AppBaseFragment() {\n\n    private val handler = Handler(Looper.getMainLooper())\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,\n                              savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.processing_fragment, container, false)\n    }\n\n    override fun onWalletReady() {\n        val stats = ILibraryController.getMonitoringStats()\n        with(stats) {\n            view?.let { view ->\n                view.processing_group_probable.text = probableHeight.toString()\n                view.processing_group_height.text = partialHeight.toString()\n                view.processing_group_processed.text = processedSPVHeight.toString()\n                view.processing_group_offset.text = partialOffset.toString()\n                view.processing_group_length.text = (partialHeight - partialOffset).toString()\n                view.processing_group_prune.text = prunedHeight.toString()\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n\n        UnityCore.instance.addMonitorObserver(monitoringListener, fun(callback: () -> Unit) { handler.post { callback() } })\n    }\n\n    override fun onPause() {\n        UnityCore.instance.removeMonitorObserver(monitoringListener)\n\n        super.onPause()\n    }\n\n    private val monitoringListener = object : MonitorListener() {\n        override fun onPruned(height: Int) {\n            this@ProcessingFragment.processing_group_prune?.text = height.toString()\n        }\n\n        override fun onProcessedSPVBlocks(height: Int) {\n            this@ProcessingFragment.processing_group_processed?.text = height.toString()\n        }\n\n        override fun onPartialChain(height: Int, probableHeight: Int, offset: Int) {\n            this@ProcessingFragment.processing_group_probable?.text = probableHeight.toString()\n            this@ProcessingFragment.processing_group_height?.text = height.toString()\n            this@ProcessingFragment.processing_group_offset?.text = offset.toString()\n            this@ProcessingFragment.processing_group_length?.text = (height - offset).toString()\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/widgets/ActionMultiAutoCompleteTextView.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.widgets\n\nimport android.content.Context\nimport androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView\nimport android.util.AttributeSet\nimport android.view.inputmethod.EditorInfo\nimport android.view.inputmethod.InputConnection\n\nclass ActionMultiAutoCompleteTextView : AppCompatMultiAutoCompleteTextView\n{\n    constructor(context: Context) : super(context)\n\n    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)\n\n    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)\n\n    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection\n    {\n        val conn = super.onCreateInputConnection(outAttrs)\n        outAttrs.imeOptions = outAttrs.imeOptions and EditorInfo.IME_FLAG_NO_ENTER_ACTION.inv()\n        return conn\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/widgets/AuthenticatedRecoveryView.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl), Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.widgets\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.widget.ViewSwitcher\nimport unity_wallet.jniunifiedbackend.ILibraryController\nimport unity_wallet.Authentication\nimport unity_wallet.R\nimport kotlinx.android.synthetic.main.pref_view_recovery.view.*\n\nclass AuthenticatedRecoveryView(context: Context?, attrs: AttributeSet?) : ViewSwitcher(context, attrs) {\n\n    override fun onFinishInflate() {\n        super.onFinishInflate()\n        val lockedView = getChildAt(0)\n        lockedView.setOnClickListener {\n            Authentication.instance.authenticate(context!!, null, context?.getString(R.string.show_recovery_msg)) {\n                displayedChild = 1\n                //TODO: Reintroduce showing birth time here if/when we decide we want it in future\n                recoveryPhrase.text = ILibraryController.GetRecoveryPhrase().phrase\n            }\n        }\n        recoveryPhrase.setOnClickListener {\n            displayedChild = 0\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/widgets/HideBalanceView.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.widgets\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport android.content.SharedPreferences.OnSharedPreferenceChangeListener\nimport android.util.AttributeSet\nimport android.view.Gravity\nimport android.widget.Toast\nimport android.widget.ViewSwitcher\nimport androidx.preference.PreferenceManager\nimport unity_wallet.Authentication\nimport unity_wallet.R\nimport unity_wallet.UnityCore\nimport unity_wallet.util.invokeNowOrOnSuccessfulCompletion\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.SupervisorJob\nimport android.os.Handler\nimport android.os.Looper\nimport kotlin.coroutines.CoroutineContext\n\nclass HideBalanceView(context: Context?, attrs: AttributeSet?) : ViewSwitcher(context, attrs), Authentication.LockingObserver, UnityCore.Observer, OnSharedPreferenceChangeListener, CoroutineScope {\n\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    private val handler = Handler(Looper.getMainLooper())\n    private var syncToastShowed = false // used to show it just once (unless triggered explicitly by tapping)\n    private var syncToastLastShowed = 0L\n    private val SYNC_TOAST_RATE_LIMIT_MS = 10000 // show toast only if previously shown at least this long ago\n    private val preferences = PreferenceManager.getDefaultSharedPreferences(context!!)\n    private val isHideBalanceSet: Boolean\n            get() {\n              return preferences.getBoolean(\"preference_hide_balance\", true)\n            }\n\n    override fun onFinishInflate() {\n        super.onFinishInflate()\n        val viewWhenHidden = getChildAt(0)\n        viewWhenHidden.setOnClickListener {\n            if (Authentication.instance.isLocked() && isHideBalanceSet)\n                Authentication.instance.unlock(context!!, null, null)\n            else\n                // not locked or hide balance pref is disabled so balance is not showing because not synced\n                showSyncToast()\n        }\n\n        preferences.registerOnSharedPreferenceChangeListener(this)\n    }\n\n    private fun showSyncToast() {\n        val now = System.currentTimeMillis()\n        if (now - syncToastLastShowed > SYNC_TOAST_RATE_LIMIT_MS) {\n            val toast = Toast.makeText(context, context.getString(R.string.show_balance_when_synced), Toast.LENGTH_LONG)\n            toast.setGravity(Gravity.TOP, 0 , context.resources.getDimensionPixelSize(R.dimen.top_toast_offset))\n            toast.show()\n            syncToastLastShowed = now\n        }\n    }\n\n    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {\n        if (key == \"preference_hide_balance\")\n            updateViewState()\n    }\n\n    private fun updateViewState() {\n        UnityCore.instance.walletReady.invokeNowOrOnSuccessfulCompletion(this) {\n            val isSynced = UnityCore.instance.progressPercent >= 100.0\n            val isLocked = Authentication.instance.isLocked()\n\n            val showBalance = isSynced && !(isLocked && isHideBalanceSet)\n            displayedChild = if (showBalance) 1 else 0\n\n            // when balance not shown due to not being synced show toast (just once)\n            if (!isSynced && !(isLocked && isHideBalanceSet) && !syncToastShowed)\n            {\n                showSyncToast()\n                syncToastShowed = true\n            }\n        }\n    }\n\n    override fun onAttachedToWindow() {\n        super.onAttachedToWindow()\n        updateViewState()\n        Authentication.instance.addObserver(this)\n        UnityCore.instance.addObserver(this, fun (callback:() -> Unit) { handler.post { callback() }})\n    }\n\n    override fun onDetachedFromWindow() {\n        super.onDetachedFromWindow()\n        Authentication.instance.removeObserver(this)\n        UnityCore.instance.removeObserver(this)\n    }\n\n    override fun onUnlock() {\n        updateViewState()\n    }\n\n    override fun onLock() {\n        updateViewState()\n    }\n\n    override fun syncProgressChanged(percent: Float) {\n        updateViewState()\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/widgets/LockView.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.widgets\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.widget.ViewSwitcher\nimport unity_wallet.Authentication\n\nclass LockView(context: Context?, attrs: AttributeSet?) : ViewSwitcher(context, attrs), Authentication.LockingObserver {\n\n    override fun onFinishInflate() {\n        super.onFinishInflate()\n        val lockedView = getChildAt(0)\n        lockedView.setOnClickListener {\n            Authentication.instance.unlock(context!!, null, null)\n        }\n    }\n\n    private fun displayLockingState() {\n        displayedChild = if (Authentication.instance.isLocked()) 0 else 1\n    }\n\n    override fun onAttachedToWindow() {\n        super.onAttachedToWindow()\n        displayLockingState()\n        Authentication.instance.addObserver(this)\n    }\n\n    override fun onDetachedFromWindow() {\n        super.onDetachedFromWindow()\n        Authentication.instance.removeObserver(this)\n    }\n\n    override fun onUnlock() {\n        displayLockingState()\n    }\n\n    override fun onLock() {\n        displayLockingState()\n    }\n\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/ui/widgets/UnityBuildInfoView.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.ui.widgets\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.view.View\nimport android.widget.TextView\nimport unity_wallet.BuildConfig\nimport unity_wallet.UnityCore\n\nclass UnityBuildInfoView(context: Context?, attrs: AttributeSet?) : androidx.appcompat.widget.AppCompatTextView(context!!, attrs) {\n    init {\n        @Suppress(\"ConstantConditionIf\")\n        if (BuildConfig.TESTNET) {\n            text = \"Unity core ${UnityCore.instance.buildInfo}\"\n        }\n        else {\n            visibility = View.GONE\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/ActivityHelpers.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.util\n\nimport android.app.Activity\nimport android.content.Intent\nimport unity_wallet.WalletActivity\n\nfun gotoWalletActivity(activity: Activity)\n{\n    val intent = Intent(activity, WalletActivity::class.java)\n    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)\n    activity.startActivity(intent)\n    activity.finish()\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/AppBaseActivity.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.util\n\nimport android.content.Intent\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragment.app.FragmentManager\nimport unity_wallet.*\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.SupervisorJob\nimport kotlin.coroutines.CoroutineContext\n\ninline fun FragmentManager.inTransaction(func: androidx.fragment.app.FragmentTransaction.() -> androidx.fragment.app.FragmentTransaction) {\n    beginTransaction().func().commit()\n}\n\nabstract class AppBaseActivity : AppCompatActivity(), CoroutineScope {\n\n    /**\n     * Called when walletReady is completed, but always after onResume\n     * This can be used instead of using the walletReady deferred to simplify code.\n     * Do NOT call the super method.\n     */\n    open fun onWalletReady() {}\n\n    /**\n     * Called when a wallet needs to be created. This is linked to the core notifyInitWithoutExistingWallet event.\n     * This is always called after onResume.\n     * The default behaviour will either continue to the welcome or upgrade activity,\n     * when overriding this you should normally NOT CALL the super method.\n     */\n    open fun onWalletCreate() {\n        welcomeOrUpgrade()\n    }\n\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    override fun onResume() {\n        super.onResume()\n\n        // schedule onWalletReady\n        UnityCore.instance.walletReady.invokeOnCompletion { handler ->\n            if (handler == null) {\n                runOnUiThread { onWalletReady() }\n            }\n        }\n\n        // schedule onWalletCreate\n        UnityCore.instance.walletCreate.invokeOnCompletion { handler ->\n            if (handler == null) {\n                runOnUiThread { onWalletCreate() }\n            }\n        }\n    }\n\n    private fun welcomeOrUpgrade() {\n        // upgrade old wallet when a protobuf wallet file is present and is not marked as upgraded\n        val upgradedMarkerFile = getFileStreamPath(Constants.OLD_WALLET_PROTOBUF_FILENAME+\".upgraded\")\n        if (!upgradedMarkerFile.exists() && getFileStreamPath(Constants.OLD_WALLET_PROTOBUF_FILENAME).exists())\n            gotoActivity(UpgradeActivity::class.java)\n        else\n            gotoActivity(WelcomeActivity::class.java)\n    }\n\n    private fun gotoActivity(cls: Class<*> )\n    {\n        val intent = Intent(this, cls)\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)\n        startActivity(intent)\n\n        finish()\n    }\n\n    fun gotoFragment(fragment: androidx.fragment.app.Fragment, frameId: Int) {\n        supportFragmentManager.popBackStackImmediate()\n        supportFragmentManager.inTransaction { replace(frameId, fragment) }\n    }\n\n    fun pushFragment(fragment: androidx.fragment.app.Fragment, frameId: Int) {\n        supportFragmentManager.inTransaction { replace(R.id.mainLayout, fragment).addToBackStack(null) }\n    }\n\n    fun addFragment(fragment: androidx.fragment.app.Fragment, frameId: Int) {\n        supportFragmentManager.inTransaction { add(frameId, fragment) }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/AppBaseFragment.kt",
    "content": "package unity_wallet.util\n\nimport android.content.DialogInterface\nimport unity_wallet.UnityCore\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.SupervisorJob\nimport android.os.Handler\nimport android.os.Looper\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport kotlin.coroutines.CoroutineContext\n\nabstract class AppBaseFragment : androidx.fragment.app.Fragment(), CoroutineScope {\n\n    private val handlerUI = Handler(Looper.getMainLooper())\n\n    /**\n     * Called when walletReady is completed, but always after onResume\n     * This can be used instead of using the walletReady deferred to simplify code.\n     * Do NOT call the super method.\n     */\n    open fun onWalletReady() {}\n\n    override val coroutineContext: CoroutineContext = Dispatchers.Main + SupervisorJob()\n\n    override fun onResume() {\n        super.onResume()\n\n        // schedule onWalletReady\n        UnityCore.instance.walletReady.invokeOnCompletion { handler ->\n            if (handler == null) {\n                handlerUI.post { onWalletReady() }\n            }\n        }\n    }\n\n    fun errorMessage(msg: String) {\n        context?.run {\n            MaterialAlertDialogBuilder(requireContext())\n                    .setMessage(msg)\n                    .setPositiveButton(android.R.string.ok) { dialogInterface: DialogInterface, i: Int -> }\n                    .show()\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/Button.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.util\n\nimport android.widget.Button\nimport unity_wallet.R\n\n// Helper function to visually toggle a button as enabled/disabled while still keeping it clickable\nfun setFauxButtonEnabledState(button : Button, enabled : Boolean)\n{\n    // Toggle button visual disabled/enabled indicator while still keeping it clickable\n    var buttonBackground = R.drawable.shape_square_button_disabled\n    if (enabled)\n        buttonBackground = R.drawable.shape_square_button_enabled\n    button.setBackgroundResource(buttonBackground)\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/CoroutineHelpers.kt",
    "content": "package unity_wallet.util\n\nimport kotlinx.coroutines.CompletableDeferred\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\n\nfun <T> CompletableDeferred<T>.invokeNowOrOnSuccessfulCompletion(scope: CoroutineScope, func: () -> Unit) {\n    if (isCompleted && !isCancelled)\n        func()\n    else {\n        invokeOnCompletion { handler ->\n            if (handler == null) {\n                scope.launch(Dispatchers.Main) { func() }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/DeviceInfo.kt",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet.util\n\nimport android.os.Build\n\n\nfun getDeviceName(): String?\n{\n    val manufacturer = Build.MANUFACTURER\n    val model = Build.MODEL\n    return if (model.startsWith(manufacturer)) model else \"$manufacturer $model\"\n}\n\nfun getAndroidVersion(): String\n{\n    val version = Build.VERSION.RELEASE.toString()\n    return if (version.startsWith(\"Android\")) version else \"Android $version\"\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/SwipeToDeleteCallback.kt",
    "content": "package unity_wallet.util\n\nimport android.content.Context\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.Paint\nimport android.graphics.PorterDuff\nimport android.graphics.PorterDuffXfermode\nimport android.graphics.drawable.ColorDrawable\nimport androidx.core.content.ContextCompat\nimport androidx.recyclerview.widget.ItemTouchHelper\nimport androidx.recyclerview.widget.RecyclerView\nimport unity_wallet.R\n\n\nabstract class SwipeToDeleteCallback(context: Context) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {\n\n    private val deleteIcon = ContextCompat.getDrawable(context, R.drawable.ic_fontawesome_trash)!!\n    private val intrinsicWidth = 60\n    private val intrinsicHeight = 60\n    private val background = ColorDrawable()\n    private val backgroundColor = Color.parseColor(\"#f44336\")\n    private val clearPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }\n\n\n    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {\n        /**\n         * To disable \"swipe\" for specific item return 0 here.\n         * For example:\n         * if (viewHolder?.itemViewType == YourAdapter.SOME_TYPE) return 0\n         * if (viewHolder?.adapterPosition == 0) return 0\n         */\n        if (viewHolder.adapterPosition == 10) return 0\n        return super.getMovementFlags(recyclerView, viewHolder)\n    }\n\n    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {\n        return false\n    }\n\n    override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {\n        val itemView = viewHolder.itemView\n        val itemHeight = itemView.bottom - itemView.top\n        val isCanceled = dX == 0f && !isCurrentlyActive\n\n        if (isCanceled) {\n            clearCanvas(c, itemView.right + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat())\n            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)\n            return\n        }\n\n        // Draw the red delete background\n        background.color = backgroundColor\n        background.setBounds(itemView.right + dX.toInt(), itemView.top, itemView.right, itemView.bottom)\n        background.draw(c)\n\n        // Calculate position of delete icon\n        val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2\n        val deleteIconMargin = (itemHeight - intrinsicHeight) / 2\n        val deleteIconLeft = itemView.right - deleteIconMargin - intrinsicWidth\n        val deleteIconRight = itemView.right - deleteIconMargin\n        val deleteIconBottom = deleteIconTop + intrinsicHeight\n\n        // Draw the delete icon\n        deleteIcon.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)\n        deleteIcon.draw(c)\n\n        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)\n    }\n\n    private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {\n        c?.drawRect(left, top, right, bottom, clearPaint)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/java/unity_wallet/util/ViewPagerTabs.java",
    "content": "/*\n * Copyright 2011-2015 the original author or authors.\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <https://www.gnu.org/licenses/>.\n */\n\npackage unity_wallet.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport androidx.viewpager.widget.ViewPager.OnPageChangeListener;\n\n/**\n * @author Andreas Schildbach\n */\npublic class ViewPagerTabs extends View implements OnPageChangeListener {\n    private final List<String> labels = new ArrayList<>();\n    private final Paint paint = new Paint();\n    private int maxWidth = 0;\n\n    // instance state\n    private int pagePosition = 0;\n    private float pageOffset = 0;\n\n    public ViewPagerTabs(final Context context, final AttributeSet attrs) {\n        super(context, attrs);\n\n        setSaveEnabled(true);\n\n        paint.setTextSize(getResources().getDimension(unity_wallet.R.dimen.font_size_tiny));\n        paint.setColor(Color.BLACK);\n        paint.setAntiAlias(true);\n        paint.setShadowLayer(2, 0, 0, Color.WHITE);\n    }\n\n    public void addTabLabels(final int... labelResId) {\n        final Context context = getContext();\n\n        paint.setTypeface(Typeface.DEFAULT_BOLD);\n\n        for (final int resId : labelResId) {\n            final String label = context.getString(resId);\n\n            final int width = (int) paint.measureText(label);\n\n            if (width > maxWidth)\n                maxWidth = width;\n\n            labels.add(label);\n        }\n    }\n\n    private final Path path = new Path();\n\n    @Override\n    protected void onDraw(final Canvas canvas) {\n        super.onDraw(canvas);\n\n        final int viewWidth = getWidth();\n        final int viewHalfWidth = viewWidth / 2;\n        final int viewBottom = getHeight();\n\n        final float density = getResources().getDisplayMetrics().density;\n        final float spacing = 32 * density;\n\n        path.reset();\n        path.moveTo(viewHalfWidth, viewBottom - 5 * density);\n        path.lineTo(viewHalfWidth + 5 * density, viewBottom);\n        path.lineTo(viewHalfWidth - 5 * density, viewBottom);\n        path.close();\n\n        paint.setColor(Color.WHITE);\n        canvas.drawPath(path, paint);\n\n        paint.setTypeface(Typeface.DEFAULT_BOLD);\n        final float y = getPaddingTop() - paint.getFontMetrics().top;\n\n        for (int i = 0; i < labels.size(); i++) {\n            final String label = labels.get(i);\n\n            paint.setTypeface(i == pagePosition ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);\n            paint.setColor(i == pagePosition ? Color.BLACK : Color.DKGRAY);\n\n            final float x = viewHalfWidth + (maxWidth + spacing) * (i - pageOffset);\n            final float labelWidth = paint.measureText(label);\n            final float labelHalfWidth = labelWidth / 2;\n\n            final float labelLeft = x - labelHalfWidth;\n            final float labelVisibleLeft = labelLeft >= 0 ? 1f : 1f - (-labelLeft / labelWidth);\n\n            final float labelRight = x + labelHalfWidth;\n            final float labelVisibleRight = labelRight < viewWidth ? 1f : 1f - ((labelRight - viewWidth) / labelWidth);\n\n            final float labelVisible = Math.min(labelVisibleLeft, labelVisibleRight);\n\n            paint.setAlpha((int) (labelVisible * 255));\n\n            canvas.drawText(label, labelLeft, y, paint);\n        }\n    }\n\n    @Override\n    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {\n        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);\n        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);\n\n        int width=0;\n        switch (widthMode)\n        {\n            case MeasureSpec.EXACTLY:\n                width = widthSize;\n                break;\n            case MeasureSpec.AT_MOST:\n                width = Math.min(getMeasuredWidth(), widthSize);\n                break;\n            case MeasureSpec.UNSPECIFIED:\n                break;\n        }\n\n        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);\n        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);\n\n        int height = 0;\n        switch (heightMode)\n        {\n            case MeasureSpec.EXACTLY:\n                height = heightSize;\n                break;\n            case MeasureSpec.AT_MOST:\n                height = Math.min(getSuggestedMinimumHeight(), heightSize);\n                break;\n            case MeasureSpec.UNSPECIFIED:\n                height = getSuggestedMinimumHeight();\n                break;\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    @Override\n    protected int getSuggestedMinimumHeight() {\n        paint.setTypeface(Typeface.DEFAULT_BOLD);\n        return (int) (-paint.getFontMetrics().top + paint.getFontMetrics().bottom) + getPaddingTop()\n                + getPaddingBottom();\n    }\n\n    @Override\n    public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {\n        pageOffset = position + positionOffset;\n        invalidate();\n    }\n\n    @Override\n    public void onPageSelected(final int position) {\n        pagePosition = position;\n        invalidate();\n    }\n\n    @Override\n    public void onPageScrollStateChanged(final int state) {\n    }\n\n    @Override\n    public Parcelable onSaveInstanceState() {\n        final Bundle state = new Bundle();\n        state.putParcelable(\"super_state\", super.onSaveInstanceState());\n        state.putInt(\"page_position\", pagePosition);\n        state.putFloat(\"page_offset\", pageOffset);\n        return state;\n    }\n\n    @Override\n    public void onRestoreInstanceState(final Parcelable state) {\n        if (state instanceof Bundle) {\n            Bundle bundle = (Bundle) state;\n            pagePosition = bundle.getInt(\"page_position\");\n            pageOffset = bundle.getFloat(\"page_offset\");\n            super.onRestoreInstanceState(bundle.getParcelable(\"super_state\"));\n            return;\n        }\n\n        super.onRestoreInstanceState(state);\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/anim/shake.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2019-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n<translate android:duration=\"50\"\n    android:fromXDelta=\"-2%\"\n    android:toXDelta=\"2%\"\n    android:repeatCount=\"5\"\n    android:repeatMode=\"reverse\"\n/>\n</set>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/color/bottom_nav_color_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_checked=\"true\" android:color=\"@color/colorPrimary\" />\n    <item android:state_pressed=\"true\" android:state_enabled=\"true\" android:color=\"@color/bg_list\" />\n    <item android:color=\"@color/bg_list\" />\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_arrow_up_right_from_square.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_arrow_up_right_from_square_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_arrow_up_right_from_square_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_arrow_up_right_from_square_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M280,80C266.7,80 256,69.25 256,56C256,42.75 266.7,32 280,32H424C437.3,32 448,42.75 448,56V200C448,213.3 437.3,224 424,224C410.7,224 400,213.3 400,200V113.9L200.1,312.1C191.6,322.3 176.4,322.3 167,312.1C157.7,303.6 157.7,288.4 167,279L366.1,80H280zM0,120C0,89.07 25.07,64 56,64H168C181.3,64 192,74.75 192,88C192,101.3 181.3,112 168,112H56C51.58,112 48,115.6 48,120V424C48,428.4 51.58,432 56,432H360C364.4,432 368,428.4 368,424V312C368,298.7 378.7,288 392,288C405.3,288 416,298.7 416,312V424C416,454.9 390.9,480 360,480H56C25.07,480 0,454.9 0,424V120z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_arrow_up_right_from_square_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M288,32c-17.7,0 -32,14.3 -32,32s14.3,32 32,32h50.7L169.4,265.4c-12.5,12.5 -12.5,32.8 0,45.3s32.8,12.5 45.3,0L384,141.3V192c0,17.7 14.3,32 32,32s32,-14.3 32,-32V64c0,-17.7 -14.3,-32 -32,-32H288zM80,64C35.8,64 0,99.8 0,144V400c0,44.2 35.8,80 80,80H336c44.2,0 80,-35.8 80,-80V320c0,-17.7 -14.3,-32 -32,-32s-32,14.3 -32,32v80c0,8.8 -7.2,16 -16,16H80c-8.8,0 -16,-7.2 -16,-16V144c0,-8.8 7.2,-16 16,-16h80c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32H80z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_bolt_lightning.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_bolt_lightning_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_bolt_lightning_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_bolt_lightning_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"384dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"384\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M381.2,172.8C377.1,164.9 368.9,160 360,160h-156.6l50.84,-127.1c2.97,-7.38 2.06,-15.78 -2.41,-22.38S239.1,0 232,0h-176C43.97,0 33.81,8.91 32.22,20.84l-32,240C-0.72,267.7 1.38,274.6 5.94,279.8C10.5,285 17.09,288 24,288h146.3l-41.78,194.1c-2.41,11.22 3.47,22.56 14,27.09C145.6,511.4 148.8,512 152,512c7.72,0 15.22,-3.75 19.81,-10.44l208,-304C384.8,190.2 385.4,180.7 381.2,172.8zM201,373.9l22.47,-104.8c1.53,-7.09 -0.25,-14.47 -4.81,-20.12C214.1,243.3 207.3,240 200,240H51.41l25.59,-192h119.6L145.7,175.1C142.8,182.5 143.7,190.9 148.1,197.5S160,208 168,208h146.5L201,373.9z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_bolt_lightning_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"384dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"384\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M0,256L28.5,28c2,-16 15.6,-28 31.8,-28H228.9c15,0 27.1,12.1 27.1,27.1c0,3.2 -0.6,6.5 -1.7,9.5L208,160H347.3c20.2,0 36.7,16.4 36.7,36.7c0,7.4 -2.2,14.6 -6.4,20.7l-192.2,281c-5.9,8.6 -15.6,13.7 -25.9,13.7h-2.9c-15.7,0 -28.5,-12.8 -28.5,-28.5c0,-2.3 0.3,-4.6 0.9,-6.9L176,288H32c-17.7,0 -32,-14.3 -32,-32z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_chart_network.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_chart_network_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_chart_network_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_chart_network_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"640dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"640\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M288,64C288,80.85 281.5,96.18 270.8,107.6L297.7,165.2C309.9,161.8 322.7,160 336,160C374.1,160 410.4,175.5 436.3,200.7L513.9,143.7C512.7,138.7 512,133.4 512,128C512,92.65 540.7,64 576,64C611.3,64 640,92.65 640,128C640,163.3 611.3,192 576,192C563.7,192 552.1,188.5 542.3,182.4L464.7,239.4C474.5,258.8 480,280.8 480,304C480,322.5 476.5,340.2 470.1,356.5L537.5,396.9C548.2,388.8 561.5,384 576,384C611.3,384 640,412.7 640,448C640,483.3 611.3,512 576,512C540.7,512 512,483.3 512,448C512,444.6 512.3,441.3 512.8,438.1L445.4,397.6C418.1,428.5 379.8,448 336,448C264.6,448 205.4,396.1 193.1,328H123.3C113.9,351.5 90.86,368 64,368C28.65,368 0,339.3 0,304C0,268.7 28.65,240 64,240C90.86,240 113.9,256.5 123.3,280H193.1C200.6,240.9 222.9,207.1 254.2,185.5L227.3,127.9C226.2,127.1 225.1,128 224,128C188.7,128 160,99.35 160,64C160,28.65 188.7,0 224,0C259.3,0 288,28.65 288,64V64zM336,400C389,400 432,357 432,304C432,250.1 389,208 336,208C282.1,208 240,250.1 240,304C240,357 282.1,400 336,400z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_chart_network_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"640dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"640\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M288,64c0,13.7 -4.3,26.3 -11.6,36.7l29.2,62.5c9.8,-2.1 20,-3.2 30.4,-3.2c36.1,0 69,13.3 94.3,35.2L512.4,135c-0.2,-2.3 -0.4,-4.6 -0.4,-7c0,-35.3 28.7,-64 64,-64s64,28.7 64,64s-28.7,64 -64,64c-9.2,0 -17.9,-1.9 -25.8,-5.4l-82,60.2c7.6,17.5 11.8,36.9 11.8,57.2c0,15.6 -2.5,30.7 -7.1,44.8l72,43.2c9.2,-5.1 19.8,-8 31.1,-8c35.3,0 64,28.7 64,64s-28.7,64 -64,64s-64,-28.7 -64,-64l0,-1.1 -72.1,-43.3C413.7,431 376.8,448 336,448c-68.5,0 -125.9,-47.9 -140.4,-112L119.4,336c-11.1,19.1 -31.7,32 -55.4,32c-35.3,0 -64,-28.7 -64,-64s28.7,-64 64,-64c23.7,0 44.4,12.9 55.4,32h76.1c7.5,-33 26.3,-61.6 52.1,-81.7l-29.2,-62.5C185.7,124.9 160,97.5 160,64c0,-35.3 28.7,-64 64,-64s64,28.7 64,64zM336,352c26.5,0 48,-21.5 48,-48s-21.5,-48 -48,-48s-48,21.5 -48,48s21.5,48 48,48z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_down.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_circle_arrow_down_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_circle_arrow_down_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_down_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M342.4,247.7L280,314.9V144c0,-13.25 -10.75,-24 -24,-24S232,130.8 232,144v170.9L169.6,247.7C160.5,237.9 145.4,237.4 135.7,246.4C125.1,255.4 125.4,270.6 134.4,280.3l104,112C242.1,397.2 249.3,400 256,400s13.03,-2.78 17.59,-7.66l104,-112c9,-9.72 8.44,-24.91 -1.25,-33.94C366.6,237.4 351.5,237.9 342.4,247.7zM256,0C114.6,0 0,114.6 0,256s114.6,256 256,256s256,-114.6 256,-256S397.4,0 256,0zM256,464c-114.7,0 -208,-93.31 -208,-208S141.3,48 256,48s208,93.31 208,208S370.7,464 256,464z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_down_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M256,0C114.6,0 0,114.6 0,256S114.6,512 256,512s256,-114.6 256,-256S397.4,0 256,0zM127,297c-9.4,-9.4 -9.4,-24.6 0,-33.9s24.6,-9.4 33.9,0l71,71L232,120c0,-13.3 10.7,-24 24,-24s24,10.7 24,24l0,214.1 71,-71c9.4,-9.4 24.6,-9.4 33.9,0s9.4,24.6 0,33.9L273,409c-9.4,9.4 -24.6,9.4 -33.9,0L127,297z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_up.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_circle_arrow_up_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_circle_arrow_up_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_up_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M273.6,119.7C269,114.8 262.7,112 256,112S242.1,114.8 238.4,119.7l-104,112c-9,9.72 -8.44,24.91 1.25,33.94c9.72,9 24.88,8.47 33.94,-1.25L232,197.1V368c0,13.25 10.75,24 24,24s24,-10.75 24,-24V197.1l62.41,67.21c9.06,9.72 24.22,10.25 33.94,1.25c9.69,-9.03 10.25,-24.22 1.25,-33.94L273.6,119.7zM256,0C114.6,0 0,114.6 0,256s114.6,256 256,256s256,-114.6 256,-256S397.4,0 256,0zM256,464c-114.7,0 -208,-93.31 -208,-208S141.3,48 256,48s208,93.31 208,208S370.7,464 256,464z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_circle_arrow_up_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M256,512c141.4,0 256,-114.6 256,-256S397.4,0 256,0S0,114.6 0,256S114.6,512 256,512zM385,215c9.4,9.4 9.4,24.6 0,33.9s-24.6,9.4 -33.9,0l-71,-71V392c0,13.3 -10.7,24 -24,24s-24,-10.7 -24,-24V177.9l-71,71c-9.4,9.4 -24.6,9.4 -33.9,0s-9.4,-24.6 0,-33.9L239,103c9.4,-9.4 24.6,-9.4 33.9,0L385,215z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_copy.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_copy_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_copy_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_copy_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M502.6,70.63l-61.25,-61.25C435.4,3.37 427.2,0 418.7,0H255.1c-35.35,0 -64,28.66 -64,64l0.02,256C192,355.4 220.7,384 256,384h192c35.2,0 64,-28.8 64,-64V93.25C512,84.77 508.6,76.63 502.6,70.63zM464,320c0,8.84 -7.16,16 -16,16H255.1c-8.84,0 -16,-7.16 -16,-16L239.1,64.13c0,-8.84 7.16,-16 16,-16h128L384,96c0,17.67 14.33,32 32,32h47.1V320zM272,448c0,8.84 -7.16,16 -16,16H63.1c-8.84,0 -16,-7.16 -16,-16L47.98,192.1c0,-8.84 7.16,-16 16,-16H160V128H63.99c-35.35,0 -64,28.65 -64,64l0.01,256C0,483.3 28.66,512 64,512h192c35.2,0 64,-28.8 64,-64v-32h-47.1L272,448z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_copy_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M224,0c-35.3,0 -64,28.7 -64,64V288c0,35.3 28.7,64 64,64H448c35.3,0 64,-28.7 64,-64V64c0,-35.3 -28.7,-64 -64,-64H224zM64,160c-35.3,0 -64,28.7 -64,64V448c0,35.3 28.7,64 64,64H288c35.3,0 64,-28.7 64,-64V384H288v64H64V224h64V160H64z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_cube.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_cube_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_cube_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_cube_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M236.1,5.86C248.9,1.01 263.1,1.01 275.9,5.86L475.9,81.73C497.6,89.98 512,110.8 512,134.1V377.9C512,401.2 497.6,422 475.9,430.3L275.9,506.1C263.1,510.1 248.9,510.1 236.1,506.1L36.14,430.3C14.39,422 0,401.2 0,377.9V134.1C0,110.8 14.39,89.98 36.14,81.73L236.1,5.86zM258.8,50.74C257,50.05 254.1,50.05 253.2,50.74L63.62,122.6L256,198.2L448.4,122.6L258.8,50.74zM53.16,385.4L232,453.2V240.4L48,168.1V377.9C48,381.2 50.06,384.2 53.16,385.4zM280,453.2L458.8,385.4C461.9,384.2 464,381.2 464,377.9V168.1L280,240.4V453.2z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_cube_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M234.5,5.7c13.9,-5 29.1,-5 43.1,0l192,68.6C495,83.4 512,107.5 512,134.6L512,377.4c0,27 -17,51.2 -42.5,60.3l-192,68.6c-13.9,5 -29.1,5 -43.1,0l-192,-68.6C17,428.6 0,404.5 0,377.4L0,134.6c0,-27 17,-51.2 42.5,-60.3l192,-68.6zM256,66L82.3,128 256,190l173.7,-62L256,66zM288,434.6l160,-57.1v-188L288,246.6v188z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_gear.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_gear_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_gear_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_gear_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M160,256C160,202.1 202.1,160 256,160C309,160 352,202.1 352,256C352,309 309,352 256,352C202.1,352 160,309 160,256zM256,208C229.5,208 208,229.5 208,256C208,282.5 229.5,304 256,304C282.5,304 304,282.5 304,256C304,229.5 282.5,208 256,208zM293.1,0C315.3,0 334.6,15.19 339.8,36.74L347.6,69.21C356.1,73.36 364.2,78.07 371.9,83.28L404,73.83C425.3,67.56 448.1,76.67 459.2,95.87L496.3,160.1C507.3,179.3 503.8,203.6 487.8,218.9L463.5,241.1C463.8,246.6 464,251.3 464,256C464,260.7 463.8,265.4 463.5,270L487.8,293.1C503.8,308.4 507.3,332.7 496.3,351.9L459.2,416.1C448.1,435.3 425.3,444.4 404,438.2L371.9,428.7C364.2,433.9 356.1,438.6 347.6,442.8L339.8,475.3C334.6,496.8 315.3,512 293.1,512H218.9C196.7,512 177.4,496.8 172.2,475.3L164.4,442.8C155.9,438.6 147.8,433.9 140.1,428.7L107.1,438.2C86.73,444.4 63.94,435.3 52.85,416.1L15.75,351.9C4.66,332.7 8.17,308.4 24.23,293.1L48.47,270C48.16,265.4 48,260.7 48,255.1C48,251.3 48.16,246.6 48.47,241.1L24.23,218.9C8.17,203.6 4.66,179.3 15.75,160.1L52.85,95.87C63.94,76.67 86.73,67.56 107.1,73.83L140.1,83.28C147.8,78.07 155.9,73.36 164.4,69.21L172.2,36.74C177.4,15.18 196.7,0 218.9,0L293.1,0zM205.5,103.6L194.3,108.3C181.6,113.6 169.8,120.5 159.1,128.7L149.4,136.1L94.42,119.9L57.31,184.1L98.81,223.6L97.28,235.6C96.44,242.3 96,249.1 96,256C96,262.9 96.44,269.7 97.28,276.4L98.81,288.4L57.32,327.9L94.42,392.1L149.4,375.9L159.1,383.3C169.8,391.5 181.6,398.4 194.3,403.7L205.5,408.4L218.9,464H293.1L306.5,408.4L317.7,403.7C330.4,398.4 342.2,391.5 352.9,383.3L362.6,375.9L417.6,392.1L454.7,327.9L413.2,288.4L414.7,276.4C415.6,269.7 416,262.9 416,256C416,249.1 415.6,242.3 414.7,235.6L413.2,223.6L454.7,184.1L417.6,119.9L362.6,136.1L352.9,128.7C342.2,120.5 330.4,113.6 317.7,108.3L306.5,103.6L293.1,48H218.9L205.5,103.6z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_gear_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"512dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M495.9,166.6c3.2,8.7 0.5,18.4 -6.4,24.6l-43.3,39.4c1.1,8.3 1.7,16.8 1.7,25.4s-0.6,17.1 -1.7,25.4l43.3,39.4c6.9,6.2 9.6,15.9 6.4,24.6c-4.4,11.9 -9.7,23.3 -15.8,34.3l-4.7,8.1c-6.6,11 -14,21.4 -22.1,31.2c-5.9,7.2 -15.7,9.6 -24.5,6.8l-55.7,-17.7c-13.4,10.3 -28.2,18.9 -44,25.4l-12.5,57.1c-2,9.1 -9,16.3 -18.2,17.8c-13.8,2.3 -28,3.5 -42.5,3.5s-28.7,-1.2 -42.5,-3.5c-9.2,-1.5 -16.2,-8.7 -18.2,-17.8l-12.5,-57.1c-15.8,-6.5 -30.6,-15.1 -44,-25.4L83.1,425.9c-8.8,2.8 -18.6,0.3 -24.5,-6.8c-8.1,-9.8 -15.5,-20.2 -22.1,-31.2l-4.7,-8.1c-6.1,-11 -11.4,-22.4 -15.8,-34.3c-3.2,-8.7 -0.5,-18.4 6.4,-24.6l43.3,-39.4C64.6,273.1 64,264.6 64,256s0.6,-17.1 1.7,-25.4L22.4,191.2c-6.9,-6.2 -9.6,-15.9 -6.4,-24.6c4.4,-11.9 9.7,-23.3 15.8,-34.3l4.7,-8.1c6.6,-11 14,-21.4 22.1,-31.2c5.9,-7.2 15.7,-9.6 24.5,-6.8l55.7,17.7c13.4,-10.3 28.2,-18.9 44,-25.4l12.5,-57.1c2,-9.1 9,-16.3 18.2,-17.8C227.3,1.2 241.5,0 256,0s28.7,1.2 42.5,3.5c9.2,1.5 16.2,8.7 18.2,17.8l12.5,57.1c15.8,6.5 30.6,15.1 44,25.4l55.7,-17.7c8.8,-2.8 18.6,-0.3 24.5,6.8c8.1,9.8 15.5,20.2 22.1,31.2l4.7,8.1c6.1,11 11.4,22.4 15.8,34.3zM256,336c44.2,0 80,-35.8 80,-80s-35.8,-80 -80,-80s-80,35.8 -80,80s35.8,80 80,80z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_lock.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_lock_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_lock_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_lock_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M96,192V128C96,57.31 153.3,0 224,0C294.7,0 352,57.31 352,128V192H384C419.3,192 448,220.7 448,256V448C448,483.3 419.3,512 384,512H64C28.65,512 0,483.3 0,448V256C0,220.7 28.65,192 64,192H96zM144,192H304V128C304,83.82 268.2,48 224,48C179.8,48 144,83.82 144,128V192zM48,448C48,456.8 55.16,464 64,464H384C392.8,464 400,456.8 400,448V256C400,247.2 392.8,240 384,240H64C55.16,240 48,247.2 48,256V448z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_lock_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M144,144v48H304V144c0,-44.2 -35.8,-80 -80,-80s-80,35.8 -80,80zM80,192V144C80,64.5 144.5,0 224,0s144,64.5 144,144v48h16c35.3,0 64,28.7 64,64V448c0,35.3 -28.7,64 -64,64H64c-35.3,0 -64,-28.7 -64,-64V256c0,-35.3 28.7,-64 64,-64H80z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_share_nodes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_share_nodes_light\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_share_nodes_solid\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_share_nodes_light.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M448,112C448,156.2 412.2,192 368,192C345.1,192 324.4,182.4 309.9,166.1L158.9,242.5C159.6,246.9 160,251.4 160,256C160,260.6 159.6,265.1 158.9,269.5L309.9,345C324.4,329.6 345.1,320 368,320C412.2,320 448,355.8 448,400C448,444.2 412.2,480 368,480C323.8,480 288,444.2 288,400C288,390.3 289.7,380.1 292.9,372.3L147.2,299.5C132.9,321.5 108.2,336 80,336C35.82,336 0,300.2 0,256C0,211.8 35.82,176 80,176C108.2,176 132.9,190.5 147.2,212.5L292.9,139.7C289.7,131 288,121.7 288,112C288,67.82 323.8,32 368,32C412.2,32 448,67.82 448,112L448,112zM79.1,304C106.5,304 127.1,282.5 127.1,256C127.1,229.5 106.5,208 79.1,208C53.49,208 31.1,229.5 31.1,256C31.1,282.5 53.49,304 79.1,304zM368,64C341.5,64 320,85.49 320,112C320,138.5 341.5,160 368,160C394.5,160 416,138.5 416,112C416,85.49 394.5,64 368,64zM368,448C394.5,448 416,426.5 416,400C416,373.5 394.5,352 368,352C341.5,352 320,373.5 320,400C320,426.5 341.5,448 368,448z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_share_nodes_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M352,224c53,0 96,-43 96,-96s-43,-96 -96,-96s-96,43 -96,96c0,4 0.2,8 0.7,11.9l-94.1,47C145.4,170.2 121.9,160 96,160c-53,0 -96,43 -96,96s43,96 96,96c25.9,0 49.4,-10.2 66.6,-26.9l94.1,47c-0.5,3.9 -0.7,7.8 -0.7,11.9c0,53 43,96 96,96s96,-43 96,-96s-43,-96 -96,-96c-25.9,0 -49.4,10.2 -66.6,26.9l-94.1,-47c0.5,-3.9 0.7,-7.8 0.7,-11.9s-0.2,-8 -0.7,-11.9l94.1,-47C302.6,213.8 326.1,224 352,224z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_square_list_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_square_list_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_list_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M128,192C110.3,192 96,177.7 96,160C96,142.3 110.3,128 128,128C145.7,128 160,142.3 160,160C160,177.7 145.7,192 128,192zM200,160C200,146.7 210.7,136 224,136H320C333.3,136 344,146.7 344,160C344,173.3 333.3,184 320,184H224C210.7,184 200,173.3 200,160zM200,256C200,242.7 210.7,232 224,232H320C333.3,232 344,242.7 344,256C344,269.3 333.3,280 320,280H224C210.7,280 200,269.3 200,256zM200,352C200,338.7 210.7,328 224,328H320C333.3,328 344,338.7 344,352C344,365.3 333.3,376 320,376H224C210.7,376 200,365.3 200,352zM128,224C145.7,224 160,238.3 160,256C160,273.7 145.7,288 128,288C110.3,288 96,273.7 96,256C96,238.3 110.3,224 128,224zM128,384C110.3,384 96,369.7 96,352C96,334.3 110.3,320 128,320C145.7,320 160,334.3 160,352C160,369.7 145.7,384 128,384zM0,96C0,60.65 28.65,32 64,32H384C419.3,32 448,60.65 448,96V416C448,451.3 419.3,480 384,480H64C28.65,480 0,451.3 0,416V96zM48,96V416C48,424.8 55.16,432 64,432H384C392.8,432 400,424.8 400,416V96C400,87.16 392.8,80 384,80H64C55.16,80 48,87.16 48,96z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_list_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M0,96C0,60.7 28.7,32 64,32L384,32c35.3,0 64,28.7 64,64L448,416c0,35.3 -28.7,64 -64,64L64,480c-35.3,0 -64,-28.7 -64,-64L0,96zM96,288c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32s-32,14.3 -32,32s14.3,32 32,32zM128,160c0,-17.7 -14.3,-32 -32,-32s-32,14.3 -32,32s14.3,32 32,32s32,-14.3 32,-32zM96,384c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32s-32,14.3 -32,32s14.3,32 32,32zM192,136c-13.3,0 -24,10.7 -24,24s10.7,24 24,24L352,184c13.3,0 24,-10.7 24,-24s-10.7,-24 -24,-24L192,136zM192,232c-13.3,0 -24,10.7 -24,24s10.7,24 24,24L352,280c13.3,0 24,-10.7 24,-24s-10.7,-24 -24,-24L192,232zM192,328c-13.3,0 -24,10.7 -24,24s10.7,24 24,24L352,376c13.3,0 24,-10.7 24,-24s-10.7,-24 -24,-24L192,328z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_x.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_square_x_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_square_x_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_x_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M384,32H64C28.65,32 0,60.65 0,96v320c0,35.35 28.65,64 64,64h320c35.35,0 64,-28.65 64,-64V96C448,60.65 419.3,32 384,32zM400,416c0,8.82 -7.18,16 -16,16H64c-8.82,0 -16,-7.18 -16,-16V96c0,-8.82 7.18,-16 16,-16h320c8.82,0 16,7.18 16,16V416zM327.5,133.7c-10.11,-8.58 -25.28,-7.3 -33.83,2.83L224,218.8L154.3,136.5C145.8,126.4 130.6,125.1 120.5,133.7C110.4,142.2 109.1,157.4 117.7,167.5L192.6,256l-74.88,88.5c-8.56,10.11 -7.3,25.27 2.83,33.83C125,382.1 130.5,384 135.1,384c6.81,0 13.59,-2.89 18.34,-8.5L224,293.2l69.67,82.34C298.4,381.1 305.2,384 312,384c5.47,0 10.98,-1.86 15.48,-5.67c10.12,-8.56 11.39,-23.72 2.83,-33.83L255.4,256l74.88,-88.5C338.9,157.4 337.6,142.2 327.5,133.7z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_square_x_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M64,32C28.7,32 0,60.7 0,96L0,416c0,35.3 28.7,64 64,64L384,480c35.3,0 64,-28.7 64,-64L448,96c0,-35.3 -28.7,-64 -64,-64L64,32zM154.3,136.5L224,218.8l69.7,-82.3c8.6,-10.1 23.7,-11.4 33.8,-2.8s11.4,23.7 2.8,33.8L255.4,256l74.9,88.5c8.6,10.1 7.3,25.3 -2.8,33.8s-25.3,7.3 -33.8,-2.8L224,293.2l-69.7,82.3c-8.6,10.1 -23.7,11.4 -33.8,2.8s-11.4,-23.7 -2.8,-33.8L192.6,256l-74.9,-88.5c-8.6,-10.1 -7.3,-25.3 2.8,-33.8s25.3,-7.3 33.8,2.8z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_trash.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_trash_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_trash_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_trash_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M424,80C437.3,80 448,90.75 448,104C448,117.3 437.3,128 424,128H412.4L388.4,452.7C385.9,486.1 358.1,512 324.6,512H123.4C89.92,512 62.09,486.1 59.61,452.7L35.56,128H24C10.75,128 0,117.3 0,104C0,90.75 10.75,80 24,80H93.82L130.5,24.94C140.9,9.36 158.4,0 177.1,0H270.9C289.6,0 307.1,9.36 317.5,24.94L354.2,80H424zM177.1,48C174.5,48 171.1,49.34 170.5,51.56L151.5,80H296.5L277.5,51.56C276,49.34 273.5,48 270.9,48H177.1zM364.3,128H83.69L107.5,449.2C108.1,457.5 115.1,464 123.4,464H324.6C332.9,464 339.9,457.5 340.5,449.2L364.3,128z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_trash_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"448dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"448\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M135.2,17.7L128,32H32C14.3,32 0,46.3 0,64S14.3,96 32,96H416c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32H320l-7.2,-14.3C307.4,6.8 296.3,0 284.2,0H163.8c-12.1,0 -23.2,6.8 -28.6,17.7zM416,128H32L53.2,467c1.6,25.3 22.6,45 47.9,45H346.9c25.3,0 46.3,-19.7 47.9,-45L416,128z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_wave_pulse.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_fontawesome_wave_pulse_solid\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_fontawesome_wave_pulse_regular\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_wave_pulse_regular.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"640dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"640\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M640,255.1C640,269.3 629.3,280 616,280h-120.8l-57.5,122.2c-4.38,9.13 -13.5,14.75 -24,13.63c-10,-0.88 -18.5,-8 -21,-17.87l-70,-268.6L247.5,492.9C245.2,503.8 235.9,511.6 224.8,512H224c-10.75,0 -20.25,-7.25 -23.12,-17.62L141.8,280H23.1C10.75,280 0,269.3 0,256S10.75,232 23.1,232H160c10.79,0 20.25,7.21 23.12,17.61l37.5,136L296.5,19.12C298.8,8.25 308.4,0.25 319.5,0H320c10.88,0 20.5,7.38 23.25,18l79.25,303.9l35.75,-76.12C462.2,237.4 470.8,232 480,232h136C629.3,232 640,242.7 640,255.1z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_fontawesome_wave_pulse_solid.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"640dp\"\n    android:height=\"512dp\"\n    android:viewportWidth=\"640\"\n    android:viewportHeight=\"512\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M319.1,0c14.8,-0.4 27.9,9.3 31.8,23.6l74,271.2 17.7,-35.4c10.8,-21.7 33,-35.4 57.2,-35.4H608c17.7,0 32,14.3 32,32s-14.3,32 -32,32H499.8L444.6,398.3c-5.9,11.9 -18.6,18.8 -31.8,17.5s-24.2,-10.6 -27.7,-23.4L323.7,167.3 255.3,486.7c-3.1,14.4 -15.5,24.8 -30.2,25.3s-27.8,-9.1 -31.8,-23.2L135.9,288H32c-17.7,0 -32,-14.3 -32,-32s14.3,-32 32,-32H135.9c28.6,0 53.7,18.9 61.5,46.4L219.6,348 288.7,25.3C291.8,10.9 304.4,0.4 319.1,0z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n  <group android:scaleX=\"2.4545455\"\n      android:scaleY=\"2.4545455\"\n      android:translateX=\"27\"\n      android:translateY=\"27\">\n    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M11,21.985A10.987,10.987 0,0 1,0.138 12.648h5.621a5.492,5.492 0,1 0,0 -3.3L4.621,9.348a6.589,6.589 0,0 1,12.946 1.1h3.3a9.885,9.885 0,0 0,-19.617 -1.1L0.138,9.348A10.985,10.985 0,1 1,11 21.985zM20.337,11.549h-2.771a6.588,6.588 0,0 1,-12.555 2.2L3.82,13.749a7.688,7.688 0,0 0,14.69 -1.1h1.119a8.785,8.785 0,0 1,-16.975 1.1L1.506,13.749a9.884,9.884 0,0 0,19.365 -2.2h-0.534zM1.663,10.449h0.568a8.785,8.785 0,0 1,17.4 -1.1L18.51,9.349a7.688,7.688 0,0 0,-15.178 1.1h2.2l-0.027,0.549 0.027,0.549L0.029,11.547Q0.015,11.276 0.015,11q0,-0.276 0.014,-0.549h1.634z\"\n        android:fillType=\"evenOdd\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_logo.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"22dp\"\n    android:height=\"22dp\"\n    android:viewportWidth=\"22\"\n    android:viewportHeight=\"22\">\n  <path\n      android:fillColor=\"#FF000000\"\n      android:pathData=\"M11,21.985A10.987,10.987 0,0 1,0.138 12.648h5.621a5.492,5.492 0,1 0,0 -3.3L4.621,9.348a6.589,6.589 0,0 1,12.946 1.1h3.3a9.885,9.885 0,0 0,-19.617 -1.1L0.138,9.348A10.985,10.985 0,1 1,11 21.985zM20.337,11.549h-2.771a6.588,6.588 0,0 1,-12.555 2.2L3.82,13.749a7.688,7.688 0,0 0,14.69 -1.1h1.119a8.785,8.785 0,0 1,-16.975 1.1L1.506,13.749a9.884,9.884 0,0 0,19.365 -2.2h-0.534zM1.663,10.449h0.568a8.785,8.785 0,0 1,17.4 -1.1L18.51,9.349a7.688,7.688 0,0 0,-15.178 1.1h2.2l-0.027,0.549 0.027,0.549L0.029,11.547Q0.015,11.276 0.015,11q0,-0.276 0.014,-0.549h1.634z\"\n      android:fillType=\"evenOdd\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_logo_white.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"22dp\"\n    android:height=\"22dp\"\n    android:viewportWidth=\"22\"\n    android:viewportHeight=\"22\">\n  <path\n      android:fillColor=\"#FFFFFFFF\"\n      android:pathData=\"M11,21.985A10.987,10.987 0,0 1,0.138 12.648h5.621a5.492,5.492 0,1 0,0 -3.3L4.621,9.348a6.589,6.589 0,0 1,12.946 1.1h3.3a9.885,9.885 0,0 0,-19.617 -1.1L0.138,9.348A10.985,10.985 0,1 1,11 21.985zM20.337,11.549h-2.771a6.588,6.588 0,0 1,-12.555 2.2L3.82,13.749a7.688,7.688 0,0 0,14.69 -1.1h1.119a8.785,8.785 0,0 1,-16.975 1.1L1.506,13.749a9.884,9.884 0,0 0,19.365 -2.2h-0.534zM1.663,10.449h0.568a8.785,8.785 0,0 1,17.4 -1.1L18.51,9.349a7.688,7.688 0,0 0,-15.178 1.1h2.2l-0.027,0.549 0.027,0.549L0.029,11.547Q0.015,11.276 0.015,11q0,-0.276 0.014,-0.549h1.634z\"\n      android:fillType=\"evenOdd\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/ic_scan_target.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"725\"\n    android:viewportWidth=\"725\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M161.7,724.87c-25.93,-1 -51.55,-0.28 -76.76,-3.16 -42.73,-4.87 -74.8,-36.55 -80.62,-76.8 -2.85,-19.66 -2.46,-39.8 -3.34,-59.73 -0.32,-7.13 -0.05,-14.3 -0.05,-21.88L49.1,563.3v5.73l1,59.43c0.95,26 19,44.76 45.13,46.24 20.26,1.14 40.6,0.9 60.9,1.26h5.55zM675.72,563.12h48l0.32,3.94c-0.32,21.3 0,42.65 -1.15,63.92 -2.58,49.4 -38,86.87 -85.66,90.95 -24.45,2.1 -49.1,2 -74,2.88v-48.88h17.58c18.28,-0.6 36.65,-0.3 54.78,-2.27 17.45,-1.9 30.45,-11.9 35.63,-29.14 2.83,-9.4 3.94,-19.55 4.33,-29.42 0.66,-17.1 0.17,-34.3 0.17,-51.98zM161.84,0.2v48.85h-5.9L96.5,50.23c-15.13,0.63 -28.1,6.34 -37.33,19.07a47.11,47.11 0,0 0,-9 26c-0.83,20.14 -0.82,40.3 -1.15,60.46v5.88L1.6,161.64c-0.12,-0.17 -0.5,-0.43 -0.48,-0.68 0.54,-24.8 -0.3,-49.73 2,-74.38 4.2,-45.46 39.8,-80 85.3,-83.64C112.6,1.05 137,1.08 161.84,0.2zM724.86,161.84L676,161.84l-0.07,-36.57c-0.3,-11.63 -0.5,-23.32 -2,-34.84 -3.08,-24.5 -20.93,-38.63 -44.4,-40.15 -19.25,-1.24 -38.6,-0.88 -57.9,-1.22h-8.32L563.31,1h6.7c20,0.3 40,0.1 59.92,1.07 50.1,2.46 87.75,37.52 92,85.73 2.18,24.43 2.06,49.1 2.92,74.04zM282.2,1.06h160.7v47.82L282.2,48.88zM48.9,443L1.13,443L1.13,282.24L48.9,282.24zM676.13,282.07L724,282.07L724,442.9h-47.87zM282,723.9v-47.85h160.94v47.85z\"/>\n</vector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/shape_square_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_enabled=\"true\" android:drawable=\"@drawable/shape_square_button_enabled\" />\n    <item android:state_enabled=\"false\" android:drawable=\"@drawable/shape_square_button_disabled\" />\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/shape_square_button_disabled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\" android:padding=\"10dp\">\n    <solid android:color=\"@color/colorPrimaryDark\"/>\n</shape>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/shape_square_button_enabled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\" android:padding=\"10dp\">\n    <solid android:color=\"@color/colorPrimary\"/>\n</shape>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable/shape_square_button_with_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\" android:padding=\"10dp\">\n    <solid android:color=\"@color/colorPrimary\"/>\n    <stroke android:width=\"2px\" android:color=\"@color/buttonBorder\" />\n</shape>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/drawable-v24/shape_square_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_enabled=\"true\" android:drawable=\"@drawable/shape_square_button_enabled\" />\n    <item android:state_enabled=\"false\" android:drawable=\"@drawable/shape_square_button_disabled\" />\n</selector>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/access_code_entry.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2019-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"24dp\"\n    android:paddingRight=\"24dp\">\n\n    <TextView\n        android:id=\"@+id/message\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:id=\"@+id/attemptsRemaining\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:singleLine=\"true\" />\n\n    <EditText\n        android:id=\"@+id/accessCode\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:hint=\"@string/access_code_choose_hint\"\n        android:imeOptions=\"flagNoExtractUi\"\n        android:inputType=\"numberPassword\"\n        android:singleLine=\"true\">\n\n        <requestFocus />\n    </EditText>\n\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/access_code_recovery.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2019-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"24dp\"\n    android:paddingRight=\"24dp\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Enter recovery phrase to reset access code.\"/>\n\n    <EditText\n        android:id=\"@+id/recoveryPhrase\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"120dp\"\n        android:autofillHints=\"\"\n        android:hint=\"Recovery phrase\"\n        android:imeOptions=\"flagNoExtractUi\"\n        android:inputType=\"textMultiLine\"\n        android:scrollHorizontally=\"false\"\n        tools:ignore=\"UnusedAttribute\">\n\n        <requestFocus />\n    </EditText>\n\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_enter_recovery_phrase.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:tools=\"http://schemas.android.com/tools\"\n              tools:context=\"unity_wallet.ui.EnterRecoveryPhraseActivity\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"fill_parent\"\n              android:orientation=\"vertical\"\n              android:gravity=\"center_vertical|center_horizontal\"\n              android:paddingBottom=\"20dp\"\n              android:paddingTop=\"20dp\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_vertical|center_horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            android:text=\"@string/recover_from_phrase_intro\"\n            android:layout_marginBottom=\"20dp\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:textColor=\"@color/text_main\"\n            android:focusableInTouchMode=\"false\"\n            android:enabled=\"false\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"\n            />\n\n        <unity_wallet.ui.widgets.ActionMultiAutoCompleteTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/recover_from_phrase_text_view\"\n            android:imeOptions=\"actionDone\"\n            android:height=\"150dp\"\n            android:enabled=\"true\"\n            android:inputType=\"textAutoComplete|textImeMultiLine|textAutoCorrect|text|textMultiLine\"\n            android:gravity=\"center_vertical|center_horizontal\"\n            android:maxLines=\"4\"\n            android:minLines=\"4\"\n            android:background=\"@color/bg_sub\"\n            android:textColor=\"@color/text_main\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:layout_marginBottom=\"20dp\"\n            />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"12sp\"\n            android:text=\"@string/show_recovery_phrase_EULA\"\n            android:id=\"@+id/recoverFromPhraseEULA\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:enabled=\"false\"\n            android:textColor=\"@color/text_main\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"\n            />\n\n    </LinearLayout>\n\n\n    <RelativeLayout\n        android:orientation=\"horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        >\n\n        <Button\n            android:id=\"@+id/recover_from_phrase_proceed_button\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/recovery_phrase_continue\"\n            android:padding=\"10dp\"\n            android:layout_marginRight=\"20dp\"\n            android:layout_alignParentRight=\"true\"\n            android:textColor=\"@color/text_button\"\n            android:background=\"@drawable/shape_square_button\"\n            tools:ignore=\"RelativeOverlap\" />\n\n    </RelativeLayout>\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_license.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"0dp\"\n    android:layout_marginStart=\"0dp\"\n    android:layout_marginLeft=\"0dp\"\n    android:layout_marginTop=\"0dp\"\n    android:layout_marginEnd=\"0dp\"\n    android:layout_marginRight=\"0dp\"\n    android:layout_marginBottom=\"0dp\"\n    android:orientation=\"vertical\"\n    android:padding=\"0dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    tools:context=\"unity_wallet.LicenseActivity\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id=\"@+id/topLayoutBarSettingsHeader\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_margin=\"0dp\"\n        android:background=\"@color/bg_main\">\n\n        <ImageButton\n            android:id=\"@+id/backButton\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:background=\"@null\"\n            android:padding=\"24dp\"\n            android:src=\"?attr/homeAsUpIndicator\"\n            android:text=\"\"\n            app:tint=\"@color/text_main\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            tools:ignore=\"ContentDescription\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"8dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center_vertical\"\n            android:text=\"@string/license_title\"\n            android:textColor=\"@color/text_main\"\n            android:textSize=\"22sp\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintStart_toEndOf=\"@+id/backButton\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:textColor=\"@color/text_main\" />\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <View\n        style=\"@style/ThinHorizontalDivider\"\n        android:layout_width=\"match_parent\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"fill_parent\"\n        android:background=\"@color/bg_main\"\n        android:textColor=\"@color/text_main\"\n        android:paddingStart=\"8dp\"\n        android:paddingEnd=\"8dp\">\n\n        <TextView\n            android:id=\"@+id/licenseTextView\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"8dp\"\n            android:paddingBottom=\"8dp\"/>\n    </ScrollView>\n\n\n</LinearLayout>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"0dp\"\n    android:padding=\"0dp\"\n    tools:context=\"unity_wallet.WalletActivity\">\n\n    <com.google.android.material.bottomnavigation.BottomNavigationView\n        android:id=\"@+id/navigation\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"60dp\"\n        android:background=\"@color/bg_main\"\n        android:paddingTop=\"6dp\"\n        app:elevation=\"0dp\"\n        app:itemIconSize=\"@dimen/bottom_nav_icon_size\"\n        app:itemIconTint=\"@color/text_main\"\n        app:itemTextColor=\"@color/text_main\"\n        app:labelVisibilityMode=\"labeled\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:menu=\"@menu/navigation\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:layout_marginStart=\"0dp\"\n        android:layout_marginLeft=\"0dp\"\n        android:layout_marginTop=\"0dp\"\n        android:layout_marginEnd=\"0dp\"\n        android:layout_marginRight=\"0dp\"\n        android:layout_marginBottom=\"0dp\"\n        android:orientation=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@id/navigation\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <LinearLayout\n            android:id=\"@+id/topLayoutBar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_margin=\"0dp\"\n            android:background=\"@color/bg_main\"\n            android:orientation=\"horizontal\">\n\n\n            <unity_wallet.ui.widgets.HideBalanceView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1\">\n\n                <androidx.constraintlayout.widget.ConstraintLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                    <ImageView\n                        android:id=\"@+id/walletLogo\"\n                        app:layout_constraintStart_toStartOf=\"parent\"\n                        app:layout_constraintTop_toTopOf=\"parent\"\n                        app:layout_constraintBottom_toBottomOf=\"parent\"\n                        android:layout_width=\"@dimen/top_logo_size\"\n                        android:layout_height=\"@dimen/top_logo_size\"\n                        android:layout_marginLeft=\"16dp\"\n                        android:contentDescription=\"@string/image_content_description_logo\"\n                        app:tint=\"@color/text_main\"\n                        android:visibility=\"visible\"\n                        app:srcCompat=\"@drawable/ic_logo\" />\n\n                    <TextView\n                        android:id=\"@+id/syncProgressTextual\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_weight=\"1\"\n                        android:gravity=\"center_vertical\"\n                        android:paddingLeft=\"8dp\"\n                        android:paddingRight=\"16dp\"\n                        android:text=\"@string/label_sync_progress_connecting\"\n                        android:textColor=\"@color/text_main\"\n                        android:textSize=\"14sp\"\n                        android:translationY=\"3sp\"\n                        app:layout_constraintBottom_toBottomOf=\"@+id/walletLogo\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        tools:ignore=\"HardcodedText\"\n                        tools:textColor=\"@color/text_main\" />\n                </androidx.constraintlayout.widget.ConstraintLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/balanceSection\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:orientation=\"horizontal\">\n\n                    <ImageView\n                        android:layout_width=\"@dimen/top_logo_size\"\n                        android:layout_height=\"@dimen/top_logo_size\"\n                        android:layout_marginLeft=\"16dp\"\n                        android:contentDescription=\"@string/image_content_description_logo\"\n                        app:tint=\"@color/text_main\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:visibility=\"visible\"\n                        app:srcCompat=\"@drawable/ic_logo\" />\n\n                    <TextView\n                        android:id=\"@+id/walletBalance\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\"0.00\"\n                        android:textColor=\"@color/colorPrimary\"\n                        android:textSize=\"22sp\"\n                        android:maxLines=\"1\"\n                        android:visibility=\"invisible\"\n                        android:paddingLeft=\"6dp\"\n                        tools:ignore=\"HardcodedText\"\n                        tools:textColor=\"@color/colorPrimary\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/walletBalanceLocal\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\"€0.00\"\n                        android:textColor=\"@color/colorPrimary\"\n                        android:textSize=\"18sp\"\n                        android:maxLines=\"1\"\n                        android:visibility=\"invisible\"\n                        tools:ignore=\"HardcodedText\"\n                        tools:textColor=\"@color/colorPrimary\" />\n                </LinearLayout>\n            </unity_wallet.ui.widgets.HideBalanceView>\n\n        </LinearLayout>\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:id=\"@+id/topLayoutBarSettingsHeader\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_margin=\"0dp\"\n            android:background=\"@color/bg_main\">\n\n            <ImageButton\n                android:id=\"@+id/topLayoutBarSettingsBackButton\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:background=\"@null\"\n                android:padding=\"24dp\"\n                android:src=\"?attr/homeAsUpIndicator\"\n                android:text=\"\"\n                app:tint=\"@color/colorPrimary\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\" />\n\n            <TextView\n                android:id=\"@+id/topLayoutBarSettingsTitle\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"8dp\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center_vertical\"\n                android:textColor=\"@color/colorPrimary\"\n                android:textSize=\"22sp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toEndOf=\"@+id/topLayoutBarSettingsBackButton\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:textColor=\"@color/colorPrimary\" />\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"2dp\"\n            android:layout_margin=\"0dp\">\n\n            <ProgressBar\n                android:id=\"@+id/syncProgress\"\n                style=\"?android:attr/progressBarStyleHorizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"2dp\"\n                android:layout_margin=\"0dp\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                android:max=\"100\"\n                android:padding=\"0dp\"\n                android:progress=\"40\"\n                android:progressBackgroundTint=\"@android:color/transparent\"\n                android:progressTint=\"@color/colorPrimary\"/>\n\n            <View\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                style=\"@style/ThinHorizontalDivider\"/>\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <FrameLayout\n            android:id=\"@+id/mainLayout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/bg_main\">\n\n        </FrameLayout>\n\n    </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_network_monitor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\"\n    tools:context=\"unity_wallet.ui.monitor.NetworkMonitorActivity\">\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:orientation=\"vertical\"\n        app:layout_constraintBottom_toTopOf=\"@id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:id=\"@+id/topLayoutBar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_margin=\"0dp\"\n            android:background=\"@color/bg_main\">\n\n            <ImageButton\n                android:id=\"@+id/networkMonitorBackButton\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:background=\"@null\"\n                app:tint=\"@color/text_main\"\n                android:padding=\"24dp\"\n                android:src=\"?attr/homeAsUpIndicator\"\n                android:text=\"\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                />\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"2dp\"\n            android:layout_margin=\"0dp\">\n\n            <ProgressBar\n                android:id=\"@+id/syncProgress\"\n                style=\"?android:attr/progressBarStyleHorizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"2dp\"\n                android:layout_margin=\"0dp\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                android:max=\"100\"\n                android:padding=\"0dp\"\n                android:progress=\"40\"\n                android:progressBackgroundTint=\"@android:color/transparent\"\n                android:progressTint=\"@color/colorPrimary\"/>\n\n            <View\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                style=\"@style/ThinHorizontalDivider\"/>\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <FrameLayout\n            android:id=\"@+id/networkMonitorMainLayout\"\n            android:background=\"@color/bg_main\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n        </FrameLayout>\n\n    </LinearLayout>\n\n    <View\n        android:id=\"@+id/divider\"\n        app:layout_constraintBottom_toTopOf=\"@+id/navigation\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n    <com.google.android.material.bottomnavigation.BottomNavigationView\n        android:id=\"@+id/navigation\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"60dp\"\n        android:background=\"@color/bg_main\"\n        android:paddingTop=\"4dp\"\n        app:elevation=\"0dp\"\n        app:itemIconSize=\"@dimen/bottom_nav_icon_size\"\n        app:itemIconTint=\"@color/text_main\"\n        app:itemTextColor=\"@color/text_main\"\n        app:labelVisibilityMode=\"labeled\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:menu=\"@menu/network_monitor_navigation\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_show_recovery_phrase.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    tools:context=\"unity_wallet.ui.ShowRecoveryPhraseActivity\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"fill_parent\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:gravity=\"center_vertical|center_horizontal\"\n    android:background=\"@color/bg_main\"\n    android:paddingBottom=\"20dp\"\n    android:paddingTop=\"20dp\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_vertical|center_horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            android:text=\"@string/show_recovery_phrase_introtext\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:enabled=\"false\"\n            android:textColor=\"@color/text_main\"\n            android:layout_marginBottom=\"20dp\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"/>\n\n        <TextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/recovery_phrase_text_view\"\n            android:textIsSelectable=\"false\"\n            android:selectAllOnFocus=\"false\"\n            android:enabled=\"true\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:background=\"@color/bg_sub\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:layout_marginBottom=\"20dp\"\n            android:textColor=\"@color/text_main\"\n            />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"12sp\"\n            android:text=\"@string/show_recovery_phrase_EULA\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:enabled=\"false\"\n            android:textColor=\"@color/text_main\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"/>\n    </LinearLayout>\n\n    <RelativeLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"48dp\">\n\n        <CheckBox\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/recovery_phrase_acknowledge_writing_down\"\n            android:id=\"@+id/acknowledge_recovery_phrase\"\n            android:layout_gravity=\"left\"\n            android:textColor=\"@color/text_main\"\n            android:singleLine=\"true\"\n            android:gravity=\"left|center_vertical\"\n            android:layout_alignParentBottom=\"false\"\n            android:layout_centerVertical=\"true\"\n            android:layout_alignParentLeft=\"false\"\n            android:layout_alignParentStart=\"true\"\n            android:layout_marginLeft=\"20dp\"\n            />\n\n        <Button\n            android:id=\"@+id/button_accept_recovery_phrase\"\n            style=\"?android:attr/buttonStyleSmall\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@drawable/shape_square_button_with_border\"\n            android:padding=\"10dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_marginRight=\"20dp\"\n            android:text=\"@string/recovery_phrase_continue\"\n            android:textColor=\"@color/text_button\" />\n    </RelativeLayout>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_transaction_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"unity_wallet.TransactionInfoActivity\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <androidx.appcompat.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:navigationIcon=\"?android:attr/actionModeCloseDrawable\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"\n            app:title=\"Transaction details\" />\n\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <LinearLayout\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n        <View\n            style=\"@style/ThinHorizontalDivider\"\n            android:layout_width=\"match_parent\" />\n\n        <include layout=\"@layout/content_transaction_info\" />\n    </LinearLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_upgrade.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2019-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/linearLayout7\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center_vertical|center_horizontal\"\n    tools:context=\"unity_wallet.UpgradeActivity\">\n\n        <ImageView\n            android:id=\"@+id/AppLogo\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"28dp\"\n            android:layout_marginTop=\"16dp\"\n            android:contentDescription=\"@string/image_content_description_logo\"\n            android:src=\"@drawable/ic_logo\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:srcCompat=\"@drawable/ic_logo\" />\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"28dp\"\n        android:layout_marginRight=\"28dp\"\n        android:clickable=\"false\"\n        android:enabled=\"false\"\n        android:focusable=\"false\"\n        android:focusableInTouchMode=\"false\"\n        android:justificationMode=\"inter_word\"\n        android:text=\"@string/upgrade_explanation\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textColor=\"@color/text_main\"\n        app:layout_constraintBottom_toTopOf=\"@+id/upgradeButton\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/AppLogo\" />\n\n    <Button\n        android:id=\"@+id/upgradeButton\"\n        style=\"?android:attr/buttonStyleSmall\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"28dp\"\n        android:layout_marginEnd=\"28dp\"\n        android:background=\"@drawable/shape_square_button\"\n        android:paddingTop=\"10dp\"\n        android:paddingBottom=\"10dp\"\n        android:text=\"@string/upgrade_btn\"\n        android:textColor=\"@color/text_button\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/restartFresh\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"28dp\"\n        android:layout_marginBottom=\"20dp\"\n        android:text=\"@string/upgrade_start_fresh\"\n        android:textColor=\"@color/text_main\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/activity_welcome.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/linearLayout3\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:baselineAligned=\"false\"\n    android:gravity=\"center_vertical|center_horizontal\"\n    tools:context=\"unity_wallet.WelcomeActivity\">\n\n\n    <TableLayout\n        android:id=\"@+id/tableLayout\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"28dp\"\n        android:layout_marginEnd=\"28dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n\n        <Button\n            android:id=\"@+id/new_wallet_button\"\n            style=\"?android:attr/buttonStyleSmall\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@drawable/shape_square_button\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:text=\"@string/welcome_activity_create_new_wallet\"\n            android:textColor=\"@color/text_button\" />\n\n        <Button\n            android:id=\"@+id/recover_wallet_button\"\n            style=\"?android:attr/buttonStyleSmall\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"30dp\"\n            android:background=\"@drawable/shape_square_button\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:text=\"@string/welcome_activity_recover_existing_wallet\"\n            android:textColor=\"@color/text_button\" />\n\n        <Button\n            android:id=\"@+id/sync_with_desktop_button\"\n            style=\"?android:attr/buttonStyleSmall\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"30dp\"\n            android:background=\"@drawable/shape_square_button\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:text=\"@string/welcome_activity_sync_with_desktop\"\n            android:textColor=\"@color/text_button\" />\n    </TableLayout>\n\n    <ImageView\n        android:id=\"@+id/imageView2\"\n        android:layout_width=\"@dimen/top_logo_size\"\n        android:layout_height=\"@dimen/top_logo_size\"\n        android:layout_marginStart=\"16dp\"\n        android:layout_marginTop=\"16dp\"\n        android:contentDescription=\"@string/image_content_description_logo\"\n        android:src=\"@drawable/ic_logo\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_logo\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/add_address_entry.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2019-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"20dp\"\n    android:paddingRight=\"20dp\">\n\n    <EditText\n        android:id=\"@+id/address\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:hint=\"@string/hint_iban_or_coin_address\"\n        android:singleLine=\"true\"\n        android:inputType=\"text\">\n        <requestFocus/>\n    </EditText>\n\n    <EditText\n        android:id=\"@+id/addressName\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:hint=\"@string/iban_account_holder_name\"\n        android:singleLine=\"true\"\n        android:inputType=\"text\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/address_book_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"40dp\"\n    android:layout_marginLeft=\"0dp\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"9dp\"\n    android:paddingRight=\"8dp\">\n\n    <TextView\n        android:id=\"@+id/textViewLabel\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"item\"\n        tools:ignore=\"HardcodedText\" />\n\n    <android.widget.Space\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"10\" />\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/barcode_capture.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/topLayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\"\n    android:keepScreenOn=\"true\">\n\n    <ImageView\n        android:id=\"@+id/scanTargetOverlayImage\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:elevation=\"24dp\"\n        app:layout_constraintWidth_percent=\"0.6\"\n        app:layout_constraintDimensionRatio=\"H,1:1\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_scan_target\"\n        android:contentDescription=\"@string/image_content_description_qr_scan_target_rectangle\" />\n\n    <barcodereader.CameraSourcePreview\n        android:id=\"@+id/preview\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:elevation=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:background=\"#80141414\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\">\n\n        <ImageButton\n            android:id=\"@+id/scanCancelButton\"\n            android:background=\"@android:color/transparent\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_weight=\"1\"\n            android:padding=\"8dp\"\n            android:scaleType=\"fitCenter\"\n            app:srcCompat=\"@drawable/ic_fontawesome_square_x\"\n            app:tint=\"@color/bg_main\" />\n\n        <android.widget.Space\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1000\" />\n\n        <ImageButton\n            android:id=\"@+id/scanToggleFlashButton\"\n            android:background=\"@android:color/transparent\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_weight=\"1\"\n            android:padding=\"8dp\"\n            android:scaleType=\"fitCenter\"\n            app:srcCompat=\"@drawable/ic_fontawesome_bolt_lightning\"\n            app:tint=\"@color/bg_main\" />\n    </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/block_list_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ViewAnimator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/block_list_group\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    >\n\n    <ProgressBar\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/block_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"vertical\" />\n\n</ViewAnimator>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/block_row.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"wrap_content\"\n             android:background=\"@color/bg_list\">\n\n    <LinearLayout\n        android:id=\"@+id/block_list_row_transactions_group\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/list_entry_padding_horizontal\"\n        android:paddingTop=\"@dimen/list_entry_padding_vertical\"\n        android:paddingRight=\"@dimen/list_entry_padding_horizontal\"\n        android:paddingBottom=\"@dimen/list_entry_padding_vertical\">\n\n        <LinearLayout\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:baselineAligned=\"true\"\n                android:orientation=\"horizontal\"\n                android:paddingBottom=\"2dp\">\n\n                <TextView\n                    android:id=\"@+id/block_list_row_height\"\n                    android:layout_width=\"0px\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:textStyle=\"bold\" />\n\n                <android.widget.Space\n                    android:layout_width=\"24dp\"\n                    android:layout_height=\"0px\"\n                    android:layout_weight=\"1\" />\n\n                <TextView\n                    android:id=\"@+id/block_list_row_time\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\" />\n\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/block_list_row_hash\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingTop=\"2dp\" />\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/block_list_row_menu\"\n            android:layout_width=\"28dp\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:attr/panelBackground\"\n            android:paddingLeft=\"8dp\"\n            android:paddingRight=\"0dp\"\n            android:scaleType=\"fitCenter\"\n            android:src=\"@drawable/ic_fontawesome_arrow_up_right_from_square\" />\n    </LinearLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/content_transaction_info.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/bg_main\"\n    tools:context=\"unity_wallet.TransactionInfoActivity\"\n    tools:showIn=\"@layout/activity_transaction_info\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:context=\".TransactionInfoActivity\"\n        tools:showIn=\"@layout/activity_transaction_info\">\n\n\n        <TextView\n            android:id=\"@+id/transactionId_label\"\n            style=\"@style/TxDetailHeader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/transaction_id\" />\n\n        <TextView\n            android:id=\"@+id/transactionId\"\n            style=\"@style/TxDetailParagraph\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <android.widget.Space\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/transaction_details_item_spacing\" />\n\n        <TextView\n            android:id=\"@+id/status_label\"\n            style=\"@style/TxDetailHeader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/status\" />\n\n        <TextView\n            android:id=\"@+id/status\"\n            style=\"@style/TxDetailParagraph\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <android.widget.Space\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/transaction_details_item_spacing\" />\n\n        <TextView\n            android:id=\"@+id/amount_label\"\n            style=\"@style/TxDetailHeader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/amount_label\" />\n\n        <TextView\n            android:id=\"@+id/amount\"\n            style=\"@style/TxDetailParagraph\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <android.widget.Space\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/transaction_details_item_spacing\" />\n\n        <TextView\n            android:id=\"@+id/from_label\"\n            style=\"@style/TxDetailHeader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/from_label\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            style=\"@style/ThinHorizontalDivider\"/>\n        <LinearLayout\n            android:id=\"@+id/from_container\"\n            style=\"@style/TxDetailParagraph\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" />\n\n        <android.widget.Space\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/transaction_details_item_spacing\" />\n\n        <TextView\n            android:id=\"@+id/to_label\"\n            style=\"@style/TxDetailHeader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/to_label\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            style=\"@style/ThinHorizontalDivider\"/>\n        <LinearLayout\n            android:id=\"@+id/to_container\"\n            style=\"@style/TxDetailParagraph\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" />\n\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/fragment_local_currencies.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/frameLayout2\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    tools:context=\"unity_wallet.main_activity_fragments.MutationFragment\">\n\n    <ListView\n        android:id=\"@+id/currenciesList\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"8dp\"\n        android:divider=\"@null\"\n        android:dividerHeight=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <View\n        android:id=\"@+id/divider\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/fragment_mutation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/frameLayout2\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"unity_wallet.main_activity_fragments.MutationFragment\">\n\n    <unity_wallet.ui.widgets.LockView\n        android:id=\"@+id/viewAnimator\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"@+id/divider\"\n        app:layout_constraintStart_toStartOf=\"@+id/divider\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <ImageView\n                android:id=\"@+id/unlockImage\"\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:layout_margin=\"0dp\"\n                android:clickable=\"false\"\n                android:contentDescription=\"@string/unlock\"\n                android:src=\"@drawable/ic_fontawesome_lock_solid\"\n                app:tint=\"@color/text_main\" />\n        </FrameLayout>\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginRight=\"8dp\">\n\n            <ListView\n                android:id=\"@+id/mutationList\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginTop=\"8dp\"\n                android:divider=\"@null\"\n                android:dividerHeight=\"0dp\" />\n\n            <LinearLayout\n                android:id=\"@+id/emptyMutationListView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginTop=\"38dp\"\n                android:layout_marginLeft=\"8dp\"\n                android:gravity=\"top\"\n                android:orientation=\"vertical\"\n                app:layout_constraintBottom_toBottomOf=\"@+id/divider\"\n                app:layout_constraintEnd_toEndOf=\"@+id/divider\"\n                app:layout_constraintStart_toStartOf=\"@+id/divider\"\n                app:layout_constraintTop_toTopOf=\"parent\">\n\n                <TextView\n                    android:id=\"@+id/noTransactionsText\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"@android:color/black\"\n                    android:text=\"@string/transaction_list_empty_title\" />\n\n                <TextView\n                    android:id=\"@+id/buyYourFirstText\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"1dp\"\n                    android:layout_marginTop=\"16dp\"\n                    android:text=\"@string/transaction_list_empty_message\" />\n\n            </LinearLayout>\n        </FrameLayout>\n\n    </unity_wallet.ui.widgets.LockView>\n\n    <View\n        android:id=\"@+id/divider\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/fragment_receive.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/linearLayout2\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center_vertical|center_horizontal\"\n    tools:context=\"unity_wallet.main_activity_fragments.ReceiveFragment\"\n    android:background=\"@color/bg_main\">\n\n    <android.widget.Space\n        android:id=\"@+id/top\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        />\n\n    <ImageView\n        android:id=\"@+id/currentAddressQrView\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:scaleType=\"fitCenter\"\n        android:src=\"@null\"\n        app:layout_constraintBottom_toTopOf=\"@id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHeight_max=\"200dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:ignore=\"ContentDescription\" />\n\n    <TextView\n        android:id=\"@+id/currentAddressLabel\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"24dp\"\n        android:layout_marginTop=\"24dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:textAlignment=\"center\"\n        app:autoSizeTextType=\"uniform\"\n        app:autoSizeMaxTextSize=\"16dp\"\n        app:autoSizeMinTextSize=\"12dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/currentAddressQrView\"\n        app:layout_constraintBottom_toTopOf=\"@id/divider\" />\n\n    <View\n        android:id=\"@+id/divider\"\n        style=\"@style/ThinHorizontalDivider\"\n        app:layout_constraintBottom_toTopOf=\"@+id/buttonLayout\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <LinearLayout\n        android:id=\"@+id/buttonLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:background=\"@color/bg_main\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\">\n\n        <Button\n            android:id=\"@+id/buyButton\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginStart=\"8dp\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginTop=\"8dp\"\n            android:layout_marginEnd=\"4dp\"\n            android:layout_marginRight=\"4dp\"\n            android:layout_marginBottom=\"4dp\"\n            android:layout_weight=\"1\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/action_bar_buy\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"@color/text_button\" />\n\n        <Button\n            android:id=\"@+id/shareButton\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginStart=\"4dp\"\n            android:layout_marginLeft=\"4dp\"\n            android:layout_marginTop=\"8dp\"\n            android:layout_marginEnd=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:layout_marginBottom=\"4dp\"\n            android:layout_weight=\"1\"\n            android:background=\"@drawable/shape_square_button\"\n            android:maxLines=\"2\"\n            android:text=\"@string/action_bar_share\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"@color/text_button\" />\n\n    </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/fragment_send.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/frameLayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"unity_wallet.main_activity_fragments.SendFragment\">\n\n    <unity_wallet.ui.widgets.LockView\n        android:id=\"@+id/lockSwitcher\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:background=\"@color/bg_main\">\n\n        <!-- 62dp margin to offset the bottom navigation bar, so that lock icon aligns with same one on transaction screen (where there is no bar)-->\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginTop=\"61dp\"\n            android:background=\"@color/bg_main\">\n\n            <ImageView\n                android:id=\"@+id/unlockImage\"\n                android:layout_width=\"24dp\"\n                android:layout_height=\"24dp\"\n                android:layout_gravity=\"center\"\n                android:layout_margin=\"0dp\"\n                android:clickable=\"false\"\n                android:contentDescription=\"@string/unlock\"\n                android:src=\"@drawable/ic_fontawesome_lock_solid\"\n                app:tint=\"@color/text_main\" />\n        </FrameLayout>\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"0dp\"\n            android:layout_marginRight=\"0dp\">\n\n            <LinearLayout\n                android:id=\"@+id/layoutAddressBook\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_margin=\"8dp\"\n                android:gravity=\"top\"\n                android:orientation=\"vertical\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                >\n\n                <LinearLayout\n                    android:id=\"@+id/layoutAddressBookHeader\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"40dp\"\n                    android:orientation=\"horizontal\"\n                    android:gravity=\"center_vertical\"\n                    android:layout_marginTop=\"18dp\"\n                    android:layout_marginLeft=\"8dp\"\n                    android:layout_marginRight=\"0dp\"\n                    android:layout_marginBottom=\"14dp\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintEnd_toEndOf=\"parent\"\n                    app:layout_constraintStart_toStartOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    >\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:paddingLeft=\"1dp\"\n                        android:textColor=\"@android:color/black\"\n                        android:text=\"@string/address_book_title\" />\n\n                    <android.widget.Space\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"10\" />\n\n                    <TextView\n                        android:id=\"@+id/imageViewAddToAddressBook\"\n                        android:textColor=\"@android:color/black\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:fontFamily=\"@font/fa5ps\"\n                        android:paddingLeft=\"24dp\"\n                        android:paddingTop=\"10dp\"\n                        android:paddingRight=\"10dp\"\n                        android:paddingBottom=\"10dp\"\n                        android:text=\"\"\n                        android:textSize=\"18dp\"\n                        app:layout_constraintBottom_toBottomOf=\"parent\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        app:layout_constraintStart_toEndOf=\"parent\"\n                        app:layout_constraintTop_toTopOf=\"parent\"\n                        tools:ignore=\"HardcodedText,SpUsage\" />\n\n                </LinearLayout>\n\n                <!-- Set large margin right so that users don't accidentally click list items when aiming for \"add\" button -->\n                <androidx.recyclerview.widget.RecyclerView\n                    android:id=\"@+id/addressBookList\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:divider=\"@null\"\n                    android:dividerHeight=\"0dp\">\n                </androidx.recyclerview.widget.RecyclerView>\n\n                <LinearLayout\n                    android:id=\"@+id/emptyAddressBookView\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    >\n\n                    <TextView\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginLeft=\"8dp\"\n                        android:layout_marginRight=\"50dp\"\n                        android:text=\"@string/address_book_empty_message\" />\n\n                </LinearLayout>\n            </LinearLayout>\n        </androidx.constraintlayout.widget.ConstraintLayout>\n    </unity_wallet.ui.widgets.LockView>\n\n    <View\n        android:id=\"@+id/divider\"\n        app:layout_constraintBottom_toTopOf=\"@+id/buttonLayout\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n    <LinearLayout\n        android:id=\"@+id/buttonLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:background=\"@color/bg_main\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\">\n\n        <!-- NB! We have to turn off all caps as otherwise spannable strings (which we use for dual line text styling) do not work correctly!-->\n        <Button\n            android:id=\"@+id/qrButton\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginStart=\"8dp\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginTop=\"8dp\"\n            android:layout_marginEnd=\"4dp\"\n            android:layout_marginRight=\"4dp\"\n            android:layout_marginBottom=\"4dp\"\n            android:layout_weight=\"1\"\n            android:background=\"@drawable/shape_square_button\"\n            android:ellipsize=\"middle\"\n            android:text=\"@string/send_fragment_scan_label\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"@color/text_button\" />\n\n        <Button\n            android:id=\"@+id/sellButton\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginStart=\"8dp\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginTop=\"8dp\"\n            android:layout_marginEnd=\"4dp\"\n            android:layout_marginRight=\"4dp\"\n            android:layout_marginBottom=\"4dp\"\n            android:layout_weight=\"1\"\n            android:background=\"@drawable/shape_square_button\"\n            android:ellipsize=\"middle\"\n            android:text=\"@string/send_fragment_sell_label\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"@color/text_button\" />\n\n        <Button\n            android:id=\"@+id/clipboardButton\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginStart=\"4dp\"\n            android:layout_marginLeft=\"4dp\"\n            android:layout_marginTop=\"8dp\"\n            android:layout_marginEnd=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:layout_marginBottom=\"4dp\"\n            android:layout_weight=\"1\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_fragment_clipboard_label\"\n            android:textAllCaps=\"false\"\n            android:maxLines=\"2\"\n            android:textColor=\"@color/text_button\" />\n\n    </LinearLayout>\n\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/fragment_send_coins.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\">\n\n    <LinearLayout\n        android:id=\"@+id/send_coins_amount_group\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"end\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        >\n\n        <TextView\n            android:id=\"@+id/send_coins_amount_secondary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:textSize=\"18sp\"\n            android:hint=\"(€ 0,00)\"\n            android:gravity=\"end\"\n            android:inputType=\"none\"\n            tools:clickable=\"false\"\n            tools:ignore=\"HardcodedText\" />\n\n        <android.widget.Space\n            android:layout_width=\"12dp\"\n            android:layout_height=\"0dp\" />\n\n        <TextView\n            android:id=\"@+id/send_coins_amount_primary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:gravity=\"end\"\n            android:textSize=\"24sp\"\n            android:hint=\"0,00\"\n            android:inputType=\"none\"\n            tools:clickable=\"false\"\n            tools:ignore=\"HardcodedText\" />\n\n    </LinearLayout>\n\n    <View\n        android:id=\"@+id/top_divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginBottom=\"0dp\"\n        android:background=\"@color/colorPrimaryDark\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/send_coins_amount_group\"\n        />\n\n    <include\n        android:id=\"@+id/numeric_keypad_holder\"\n        layout=\"@layout/numeric_keypad\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"10dp\"\n        app:layout_constraintDimensionRatio=\"H,1:1\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/top_divider\"\n        app:layout_constraintBottom_toTopOf=\"@id/divider\" />\n\n    <View\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginBottom=\"16dp\"\n        android:background=\"@color/colorPrimaryDark\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintBottom_toTopOf=\"@id/send_coins_info_group\"\n        />\n\n    <LinearLayout\n        android:id=\"@+id/send_coins_info_group\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingBottom=\"8dp\"\n        android:orientation=\"vertical\"\n        android:showDividers=\"middle\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/send_coins_receiving_static_label\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"8dp\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:textColor=\"@color/text_main\"\n                android:singleLine=\"false\"\n                android:textStyle=\"bold\" />\n\n            <TextView\n                android:id=\"@+id/send_coins_receiving_static_address\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:ellipsize=\"middle\"\n                android:singleLine=\"true\"\n                android:textColor=\"@color/text_main\" />\n\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/labelAddToAddressBook\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:textColor=\"@color/text_main\"\n            android:textStyle=\"bold\"\n            android:text=\"@string/send_coins_label_add_to_address_book\" />\n\n        <TextView\n            android:id=\"@+id/labelRemoveFromAddressBook\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:textColor=\"@color/text_main\"\n            android:textStyle=\"bold\"\n            android:text=\"@string/send_coins_label_remove_from_address_book\" />\n\n    </LinearLayout>\n\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/local_currency_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/linearLayout5\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"48dp\"\n    android:layout_marginLeft=\"0dp\"\n    android:gravity=\"center_vertical\">\n\n    <LinearLayout\n        android:id=\"@+id/linearLayout6\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"0dp\"\n        android:layout_marginStart=\"16dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <TextView\n            android:id=\"@+id/textViewCurrencyCode\"\n            android:layout_width=\"42dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"0dp\"\n            android:layout_marginEnd=\"0dp\"\n            android:layout_weight=\"0\"\n            android:text=\"Code\"\n            android:textStyle=\"bold\"\n            tools:ignore=\"HardcodedText\" />\n\n        <TextView\n            android:id=\"@+id/textViewCurrencyName\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:layout_marginStart=\"0dp\"\n            android:text=\"Name\"\n            tools:ignore=\"HardcodedText\" />\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/exchangeRateView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"12dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toStartOf=\"@id/imageViewCurrencySelected\"/>\n\n    <TextView\n        android:id=\"@+id/imageViewCurrencySelected\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:fontFamily=\"@font/fa5pl\"\n        android:paddingEnd=\"48dp\"\n        android:text=\"\"\n        android:textSize=\"24sp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toEndOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:ignore=\"HardcodedText\" />\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/mutation_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"40dp\"\n    android:layout_marginLeft=\"0dp\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"10dp\"\n    android:paddingRight=\"10dp\">\n\n    <TextView\n        android:id=\"@+id/textViewTime\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"10:00\"\n        tools:ignore=\"HardcodedText\" />\n\n    <android.widget.Space\n        android:layout_width=\"20dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\" />\n\n    <TextView\n        android:id=\"@+id/textViewAmount\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"0.00\"\n        tools:ignore=\"HardcodedText\" />\n\n    <android.widget.Space\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"10\" />\n\n    <TextView\n        android:id=\"@+id/textViewStatus\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"Unconfirmed\"\n        tools:ignore=\"HardcodedText\" />\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/mutation_list_item_with_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"90dp\"\n    android:layout_marginLeft=\"0dp\"\n    android:gravity=\"bottom\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"0dp\"\n    android:paddingRight=\"0dp\">\n\n    <TextView\n        android:id=\"@+id/transactionItemHeading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:gravity=\"bottom\"\n        android:paddingLeft=\"10dp\"\n        android:paddingRight=\"10dp\"\n        android:paddingBottom=\"10dp\"\n        android:text=\"Heading\"\n        android:textColor=\"@android:color/black\"\n        tools:ignore=\"HardcodedText\" />\n\n    <include\n        layout=\"@layout/mutation_list_item\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"30dp\"/>\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/numeric_keypad.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/numeric_keypad\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:columnCount=\"3\"\n    android:orientation=\"horizontal\"\n    android:stretchColumns=\"*\"\n    >\n\n    <TableRow\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:layout_marginBottom=\"@dimen/keypad_key_gap_size\"\n        >\n\n        <Button\n            android:id=\"@+id/button_1\"\n            style=\"@style/NumPadDigit\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:elegantTextHeight=\"false\"\n            android:text=\"@string/send_keypad_digit_1\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_2\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginLeft=\"@dimen/keypad_key_gap_size\"\n            android:layout_marginRight=\"@dimen/keypad_key_gap_size\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_2\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_3\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_3\"\n            android:textColor=\"@android:color/white\" />\n\n    </TableRow>\n\n    <TableRow\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:layout_marginBottom=\"@dimen/keypad_key_gap_size\"\n        >\n\n        <Button\n            android:id=\"@+id/button_4\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_4\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_5\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginLeft=\"@dimen/keypad_key_gap_size\"\n            android:layout_marginRight=\"@dimen/keypad_key_gap_size\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_5\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_6\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_6\"\n            android:textColor=\"@android:color/white\" />\n\n    </TableRow>\n\n    <TableRow\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:layout_marginBottom=\"@dimen/keypad_key_gap_size\"\n        >\n        <Button\n            android:id=\"@+id/button_7\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_7\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_8\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginLeft=\"@dimen/keypad_key_gap_size\"\n            android:layout_marginRight=\"@dimen/keypad_key_gap_size\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_8\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_9\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_9\"\n            android:textColor=\"@android:color/white\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:layout_marginBottom=\"@dimen/keypad_key_gap_size\"\n        >\n\n        <Button\n            android:id=\"@+id/button_decimal\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_decimal_separator\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_0\"\n            style=\"@style/NumPadDigit\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginLeft=\"@dimen/keypad_key_gap_size\"\n            android:layout_marginRight=\"@dimen/keypad_key_gap_size\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_digit_0\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_backspace\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/send_keypad_button_delete\"\n            android:textColor=\"@android:color/white\"\n            app:srcCompat=\"@android:drawable/ic_notification_clear_all\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_weight=\"0.5\"\n        android:gravity=\"center\"\n        android:layout_marginBottom=\"@dimen/keypad_key_gap_size\"\n        >\n\n        <TextView\n            android:id=\"@+id/button_currency\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"\"\n            android:gravity=\"center\"\n            android:textColor=\"@android:color/white\" />\n\n        <Button\n            android:id=\"@+id/button_send\"\n            android:layout_height=\"match_parent\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginLeft=\"@dimen/keypad_key_gap_size\"\n            android:layout_span=\"2\"\n            android:background=\"@drawable/shape_square_button\"\n            android:text=\"@string/numeric_keypad_send_button\"\n            android:textColor=\"@android:color/white\"\n            app:srcCompat=\"@android:drawable/ic_notification_clear_all\" />\n\n    </TableRow>\n\n</TableLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/peer_list_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ViewAnimator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/peer_list_group\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"unity_wallet.ui.monitor.PeerListFragment\">\n\n    <ProgressBar\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/bg_main\"\n        android:textColor=\"@color/text_main\"\n        android:gravity=\"center\"\n        android:text=\"@string/peer_list_fragment_empty\"\n        android:textSize=\"@dimen/font_size_small\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/peer_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"vertical\" />\n\n</ViewAnimator>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/peer_list_row.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@color/bg_list\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"@dimen/list_entry_padding_vertical\"\n    android:paddingLeft=\"@dimen/list_entry_padding_horizontal\"\n    android:paddingRight=\"@dimen/list_entry_padding_horizontal\"\n    android:paddingTop=\"@dimen/list_entry_padding_vertical\" >\n\n    <TextView\n        android:id=\"@+id/peer_list_row_ip\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textStyle=\"bold\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\" >\n\n        <TextView\n            android:id=\"@+id/peer_list_row_user_agent\"\n            android:layout_width=\"0px\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\" />\n\n        <TextView\n            android:id=\"@+id/peer_list_row_height\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\" >\n\n        <TextView\n            android:id=\"@+id/peer_list_row_protocol\"\n            android:layout_width=\"0px\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\" />\n\n        <TextView\n            android:id=\"@+id/peer_list_row_ping\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/pref_about_app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clipToPadding=\"false\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"vertical\"\n    >\n\n    <View\n        android:layout_marginBottom=\"59dp\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n    <TextView\n        android:id=\"@+id/textView2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:text=\"@string/about_text_app_name\" />\n\n    <unity_wallet.ui.widgets.UnityBuildInfoView\n        android:id=\"@+id/textUnityCoreBuild\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        />\n\n    <TextView\n        android:id=\"@+id/textView3\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_horizontal\"\n        android:text=\"@string/about_text_app_copyright\"\n        />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingBottom=\"18dp\"\n        android:orientation=\"horizontal\">\n\n        <android.widget.Space\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"10\" />\n\n        <TextView\n            android:id=\"@+id/textViewSupport\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:onClick=\"onRequestSupport\"\n            android:padding=\"10dp\"\n            android:text=\"@string/preferences_support_button\"\n            android:textColor=\"@color/colorPrimary\" />\n\n        <TextView\n            android:id=\"@+id/textViewAdvancedSettings\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:onClick=\"onRequestAdvancedSettings\"\n            android:padding=\"10dp\"\n            android:text=\"@string/preferences_advanced_button\"\n            android:textColor=\"@color/colorPrimary\" />\n\n        <TextView\n            android:id=\"@+id/textViewLicense\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:onClick=\"onRequestLicense\"\n            android:padding=\"10dp\"\n            android:text=\"@string/preferences_license_button\"\n            android:textColor=\"@color/colorPrimary\" />\n\n        <android.widget.Space\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"10\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/pref_view_recovery.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by:\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?attr/listPreferredItemHeightSmall\"\n    android:gravity=\"center_vertical\"\n    android:paddingStart=\"?attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?attr/listPreferredItemPaddingEnd\"\n    android:clipToPadding=\"false\"\n    android:baselineAligned=\"false\">\n\n    <RelativeLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"16dp\"\n        android:paddingBottom=\"16dp\">\n        <TextView android:id=\"@android:id/title\"\n            android:gravity=\"left\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?attr/textAppearanceListItem\"\n            android:ellipsize=\"marquee\" />\n        <unity_wallet.ui.widgets.AuthenticatedRecoveryView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:minHeight=\"48dp\"\n            android:layout_below=\"@android:id/title\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:gravity=\"center_vertical\"\n            >\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"48dp\">\n\n                <ImageView\n                    android:id=\"@+id/unlockImage\"\n                    android:layout_width=\"14dp\"\n                    android:layout_height=\"14dp\"\n                    android:layout_gravity=\"center\"\n                    android:clickable=\"false\"\n                    android:contentDescription=\"@string/unlock\"\n                    android:src=\"@drawable/ic_fontawesome_lock_solid\"\n                    app:tint=\"@color/text_main\" />\n            </FrameLayout>\n\n            <TextView\n                android:id=\"@+id/recoveryPhrase\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:maxLines=\"10\"\n                android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                android:textStyle=\"bold\" />\n        </unity_wallet.ui.widgets.AuthenticatedRecoveryView>\n    </RelativeLayout>\n    <!-- Preference should place its actual preference widget here. -->\n    <LinearLayout android:id=\"@+id/widget_frame\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"end|center_vertical\"\n        android:paddingStart=\"16dp\"\n        android:orientation=\"vertical\" />\n</LinearLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/preference_fragment_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n\n<!-- Ensure custom preference layout so that we can put custom borders/controls on it other than just the list view it has by default -->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"8dp\"\n    >\n\n    <!-- This layout with id is required for PreferenceFragmentCompat, everything else is optional  -->\n    <FrameLayout\n        android:id=\"@android:id/list_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        app:layout_constraintBottom_toTopOf=\"@+id/divider\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:ignore=\"NewApi\" />\n\n    <View\n        android:id=\"@+id/divider\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/processing_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<TableLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"@dimen/list_entry_padding_horizontal\"\n    android:paddingRight=\"@dimen/list_entry_padding_horizontal\"\n    android:paddingTop=\"@dimen/list_entry_padding_vertical\"\n    android:paddingBottom=\"@dimen/list_entry_padding_vertical\"\n    android:stretchColumns=\"1\">\n\n    <TableRow>\n        <TextView\n            android:layout_column=\"1\"\n            android:padding=\"3dip\"\n            android:text=\"@string/chain_status_label_probable_height\" />\n        <TextView\n            android:id=\"@+id/processing_group_probable\"\n            android:gravity=\"right\"\n            android:padding=\"3dip\"\n            android:text=\"-\"\n            tools:ignore=\"HardcodedText\" />\n    </TableRow>\n\n    <TableRow>\n        <TextView\n            android:layout_column=\"1\"\n            android:padding=\"3dip\"\n            android:text=\"@string/chain_status_label_partial_height\" />\n        <TextView\n            android:id=\"@+id/processing_group_height\"\n            android:gravity=\"right\"\n            android:padding=\"3dip\"\n            android:text=\"-\"\n            tools:ignore=\"HardcodedText\" />\n    </TableRow>\n\n    <TableRow>\n        <TextView\n            android:layout_column=\"1\"\n            android:padding=\"3dip\"\n            android:text=\"@string/chain_status_label_processed_height\" />\n        <TextView\n            android:id=\"@+id/processing_group_processed\"\n            android:gravity=\"right\"\n            android:padding=\"3dip\"\n            android:text=\"-\"\n            tools:ignore=\"HardcodedText\" />\n    </TableRow>\n\n    <TableRow>\n        <TextView\n            android:layout_column=\"1\"\n            android:padding=\"3dip\"\n            android:text=\"@string/chain_status_label_chain_offset\" />\n        <TextView\n            android:id=\"@+id/processing_group_offset\"\n            android:gravity=\"right\"\n            android:padding=\"3dip\"\n            android:text=\"-\"\n            tools:ignore=\"HardcodedText\" />\n    </TableRow>\n\n<TableRow>\n    <TextView\n        android:layout_column=\"1\"\n        android:padding=\"3dip\"\n        android:text=\"@string/chain_status_label_chain_length\" />\n    <TextView\n        android:id=\"@+id/processing_group_length\"\n        android:gravity=\"right\"\n        android:padding=\"3dip\"\n        android:text=\"-\"\n        tools:ignore=\"HardcodedText\" />\n</TableRow>\n\n    <TableRow>\n        <TextView\n            android:layout_column=\"1\"\n            android:padding=\"3dip\"\n            android:text=\"@string/chain_status_label_pruned_height\" />\n        <TextView\n            android:id=\"@+id/processing_group_prune\"\n            android:gravity=\"right\"\n            android:padding=\"3dip\"\n            android:text=\"-\"\n            tools:ignore=\"HardcodedText\" />\n    </TableRow>\n\n</TableLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/text_input_address_label.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginLeft=\"20dp\"\n        android:layout_marginTop=\"18dp\"\n        android:layout_marginRight=\"20dp\"\n        android:layout_marginBottom=\"18dp\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/labelAddAddressAddress\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:paddingLeft=\"4dp\"\n            android:paddingRight=\"4dp\"\n            android:text=\"address\"\n            tools:ignore=\"HardcodedText\">\n        </TextView>\n\n        <EditText\n            android:id=\"@+id/addAddressInput\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:hint=\"Label\"\n            android:imeOptions=\"actionDone\"\n            android:inputType=\"text\"\n            tools:ignore=\"HardcodedText\">\n        </EditText>\n\n    </LinearLayout>\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n    </com.google.android.material.textfield.TextInputLayout>\n</FrameLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/transaction_info_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"6dp\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <TextView\n        android:id=\"@+id/address\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:paddingTop=\"4dp\"\n        android:paddingBottom=\"6dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n        <TextView\n            android:id=\"@+id/subscript\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            android:textSize=\"@dimen/font_size_tiny\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n        <TextView\n            android:id=\"@+id/amount\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            android:textSize=\"@dimen/font_size_tiny\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        style=\"@style/ThinHorizontalDivider\"/>\n\n</LinearLayout>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout/upgrade_password.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"20dp\"\n    android:paddingRight=\"20dp\">\n\n    <EditText\n        android:id=\"@+id/password\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:hint=\"@string/upgrade_enter_password_hint\"\n        android:imeOptions=\"flagNoExtractUi\"\n        android:inputType=\"numberPassword\"\n        android:singleLine=\"true\">\n        <requestFocus/>\n    </EditText>\n\n</LinearLayout>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/layout-land/barcode_capture.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/topLayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\"\n    android:keepScreenOn=\"true\">\n\n    <ImageView\n        android:id=\"@+id/scanTargetOverlayImage\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:elevation=\"24dp\"\n        app:layout_constraintHeight_percent=\"0.6\"\n        app:layout_constraintDimensionRatio=\"V,1:1\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_scan_target\"\n        android:contentDescription=\"@string/image_content_description_qr_scan_target_rectangle\" />\n\n    <barcodereader.CameraSourcePreview\n        android:id=\"@+id/preview\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:elevation=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:background=\"#80141414\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\">\n\n        <ImageButton\n            android:id=\"@+id/scanCancelButton\"\n            android:background=\"@android:color/transparent\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_weight=\"1\"\n            android:padding=\"8dp\"\n            android:scaleType=\"fitCenter\"\n            app:srcCompat=\"@drawable/ic_fontawesome_square_x\"\n            app:tint=\"@color/bg_main\" />\n\n        <android.widget.Space\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1000\" />\n\n        <ImageButton\n            android:id=\"@+id/scanToggleFlashButton\"\n            android:background=\"@android:color/transparent\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_weight=\"1\"\n            android:padding=\"8dp\"\n            android:scaleType=\"fitCenter\"\n            app:srcCompat=\"@drawable/ic_fontawesome_bolt_lightning\"\n            app:tint=\"@color/bg_main\" />\n    </LinearLayout>\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/menu/blocks_context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/blocks_context_browse\"\n        app:showAsAction=\"never\"\n        android:title=\"@string/action_browse\"/>\n\n</menu>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/menu/navigation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/navigation_send\"\n        android:icon=\"@drawable/ic_fontawesome_circle_arrow_up\"\n        android:title=\"@string/title_send\" />\n\n    <item\n        android:id=\"@+id/navigation_receive\"\n        android:icon=\"@drawable/ic_fontawesome_circle_arrow_down\"\n        android:title=\"@string/title_receive\" />\n\n    <item\n        android:id=\"@+id/navigation_transactions\"\n        android:icon=\"@drawable/ic_fontawesome_square_list\"\n        android:title=\"@string/title_transactions\" />\n\n    <item\n        android:id=\"@+id/navigation_settings\"\n        android:icon=\"@drawable/ic_fontawesome_gear\"\n        android:title=\"@string/title_settings\" />\n\n</menu>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/menu/network_monitor_navigation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/navigation_peers\"\n        android:icon=\"@drawable/ic_fontawesome_chart_network\"\n        android:title=\"@string/title_peers\" />\n\n    <item\n        android:id=\"@+id/navigation_blocks\"\n        android:icon=\"@drawable/ic_fontawesome_cube\"\n        android:title=\"@string/title_blocks\" />\n\n    <item\n        android:id=\"@+id/navigation_processing\"\n        android:icon=\"@drawable/ic_fontawesome_wave_pulse\"\n        android:title=\"@string/title_processing\" />\n\n</menu>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/menu/share_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/item_buy_coins\"\n        app:showAsAction=\"always|withText\"\n        android:title=\"@string/action_bar_buy\"\n        android:titleCondensed=\"@string/action_bar_buy\"\n        />\n    <item\n        android:id=\"@+id/item_copy_to_clipboard\"\n        android:icon=\"@drawable/ic_fontawesome_copy\"\n        app:showAsAction=\"ifRoom|withText\"\n        android:title=\"@string/action_bar_copy_long\"\n        android:titleCondensed=\"@string/action_bar_copy\"\n        />\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_fontawesome_share_nodes\"\n        app:showAsAction=\"always\"\n        android:title=\"@string/action_bar_share\"\n        android:titleCondensed=\"@string/action_bar_share\"\n        app:actionProviderClass=\"androidx.appcompat.widget.ShareActionProvider\"/>\n</menu>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/raw/license.txt",
    "content": "Munt© is written and maintained by \"The Centure Developers\" under the employ of \"Centure.com BV\" and all code and products produced are licensed under the GNU Lesser General Public License v3.\n\nIn addition to our own source code Munt makes use of source code, fonts and assets from a multitude of third party projects, and is compliant with the licensing for all of these projects, most of which are free and open source.\n\nThe license information for these projects can be found alongside the source code at \"https://github.com/muntorg/munt-official\" as well as in text/json format distributed as part of the application bundle in the assets sub folder.\n\n\nGNU LESSER GENERAL PUBLIC LICENSE\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\n\nThis version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.\n0. Additional Definitions.\n\nAs used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License.\n\n“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.\n\nAn “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.\n\nA “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”.\n\nThe “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.\n\nThe “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.\n1. Exception to Section 3 of the GNU GPL.\n\nYou may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.\n2. Conveying Modified Versions.\n\nIf you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:\n\n    a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or\n    b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.\n\n3. Object Code Incorporating Material from Library Header Files.\n\nThe object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:\n\n    a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the object code with a copy of the GNU GPL and this license document.\n\n4. Combined Works.\n\nYou may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:\n\n    a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.\n    b) Accompany the Combined Work with a copy of the GNU GPL and this license document.\n    c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.\n    d) Do one of the following:\n        0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.\n        1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.\n    e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)\n\n5. Combined Libraries.\n\nYou may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:\n\n    a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.\n    b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.\n\n6. Revised Versions of the GNU Lesser General Public License.\n\nThe Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.\n\nIf the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<resources>\n    <!-- general -->\n    <color name=\"colorPrimary\">#000000</color>\n    <color name=\"colorPrimaryDark\">#909090</color>\n    <color name=\"colorAccent\">#000000</color>\n    <color name=\"colorhighlight\">#575ba0</color>\n\n    <!-- buttons -->\n    <color name=\"buttonBorder\">#FFFFFF</color>\n\n    <!-- foreground text on button-->\n    <color name=\"text_button\">#FFFFFF</color>\n    <!-- foreground colour of secondary text on button; e.g. address line on clipboard button-->\n    <color name=\"text_button_secondary\">#40ffffff</color>\n    <!-- Colour of action bar icons -->\n    <color name=\"action_icon_main\">#000000</color>\n    <!-- default background colour of all screens -->\n    <color name=\"bg_main\">#FFFFFF</color>\n    <!-- default background colour of sub area of screen that needs to stand out; e.g. the password phrase area of password phrase screen, rest of the screen is regular background colour -->\n    <color name=\"bg_sub\">#F5F5F5</color>\n    <!-- default text colour of all screens -->\n    <color name=\"text_main\">#000000</color>\n    <!-- background of popup list selection dialogs -->\n    <color name=\"bg_list\">#40ffffff</color>\n\n    <!-- mutation depending on balance effect -->\n    <color name=\"change_positive\">#4CAF50</color>\n    <color name=\"change_negative\">#AF4C50</color>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n\n    <dimen name=\"top_logo_size\">32dp</dimen>\n    <dimen name=\"bottom_nav_icon_size\">30dp</dimen>\n\n    <!-- Bottom navigation bar. -->\n    <dimen tools:override=\"true\" name=\"design_bottom_navigation_height\">64dp</dimen>\n    <dimen tools:override=\"true\" name=\"design_bottom_navigation_margin\">0dp</dimen>\n\n\n    <dimen name=\"keypad_key_gap_size\">10dp</dimen>\n\n\n    <dimen name=\"font_size_tiny\">12sp</dimen>\n    <dimen name=\"font_size_small\">15sp</dimen>\n    <!--<dimen name=\"list_entry_padding_horizontal_cram\">6dp</dimen>-->\n    <dimen name=\"list_entry_padding_horizontal\">12dp</dimen>\n    <!--<dimen name=\"list_entry_padding_horizontal_lax\">20dp</dimen>-->\n    <!--<dimen name=\"list_entry_padding_vertical_cram\">3dp</dimen>-->\n    <dimen name=\"list_entry_padding_vertical\">6dp</dimen>\n    <!--<dimen name=\"list_entry_padding_vertical_lax\">10dp</dimen>-->\n\n    <dimen name=\"transaction_details_item_spacing\">30dp</dimen>\n\n    <!-- This is a hack/workaround to suppress enlargement of selected item -->\n    <dimen tools:override=\"true\" name=\"design_bottom_navigation_active_text_size\">@dimen/design_bottom_navigation_text_size</dimen>\n\n    <dimen name=\"top_toast_offset\">60dp</dimen>\n    <dimen name=\"top_space_send_coins\">54dp</dimen>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#FFFFFF</color>\n</resources>"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n\n<!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n<!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n<!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Send</string>\n    <string name=\"title_receive\">Receive</string>\n    <string name=\"title_transactions\">Transactions</string>\n    <string name=\"title_settings\">Settings</string>\n    <string name=\"title_activity_barcode_capture\">Scan QR code</string>\n    <string name=\"title_activity_transaction_info\">Transaction info</string>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_copy_long\">Copy to clipboard</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link wallet</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Enter recovery phrase</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"address_book_empty_message\">To add an address, start a payment and tap \\\"Add to address book\\\".</string>\n    <string name=\"address_book_title\">Address book</string>\n    <string name=\"transaction_list_empty_title\">No Transactions received</string>\n    <string name=\"transaction_list_empty_message\">Touch here to buy your first Munt</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nto %2$s</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n    <string name=\"background_sync_off\">Off</string>\n    <string name=\"background_sync_daily\">Daily</string>\n    <string name=\"background_sync_always\">Always</string>\n    <string name=\"transaction_id\">Transaction ID</string>\n    <string name=\"status\">Status</string>\n    <string name=\"amount_label\">Amount</string>\n    <string name=\"from_label\">From</string>\n    <string name=\"to_label\">To</string>\n    <string name=\"tx_status_abandoned\">Abandoned</string>\n    <string name=\"tx_status_conflicted\">Conflicted</string>\n    <string name=\"tx_status_confirming\">Confirming %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Unconfirmed</string>\n    <string name=\"tx_status_confirmed\">Confirmed in block #%d at %s</string>\n    <string name=\"tx_status_unknown\">Unknown (you found a bug)</string>\n    <string name=\"no_tx_details\">No transaction details for [%s]</string>\n    <string name=\"no_qrsync_warning_title\">Invalid QR code</string>\n    <string name=\"no_qrsync_warning\">This QR code does not contain a valid Munt sync code, please try again with a valid code.</string>\n    <string name=\"failed_qrsync_warning_title\">Could not perform link</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Some of your funds are awaiting confirmation, please allow for them to fully confirm before attempting the link process again.</string>\n    <string name=\"qrsync_info_title\">Link with desktop wallet</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">You are about to establish a link with your desktop wallet. The current addresses in this wallet will be deleted and no longer available after the link is established. The current funds in this wallet will be transferred into the desktop wallet before the link is established, and will be temporarily unavailable from this wallet until the link finishes establishing. Please ensure you save a copy of your old recovery phrase somewhere in case you ever find the need to access these addresses again.</string>\n    <string name=\"qrsync_info_message_empty_wallet\">You are about to establish a link with your desktop wallet. The current addresses in this wallet will be deleted and no longer available after the link is established. Please ensure you save a copy of your old recovery phrase somewhere in case you ever find the need to access these addresses again.</string>\n    <string name=\"preference_fragment_title\">Preferences</string>\n    <string name=\"preference_fragment_recovery_label\">Recovery phrase</string>\n    <string name=\"preference_fragment_link_label\">Link wallet</string>\n    <string name=\"preference_fragment_pass_code_label\">Change passcode</string>\n    <string name=\"preference_fragment_rescan_label\">Rescan wallet</string>\n    <string name=\"preference_fragment_remove_label\">Remove wallet</string>\n    <string name=\"preference_fragment_fiat_label\">Local currency</string>\n    <string name=\"preference_fragment_notification_label\">Notifications</string>\n    <string name=\"preference_fragment_background_sync_label\">Background synchronisation</string>\n    <string name=\"send_coins_label_add_to_address_book\">Add to address book</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Remove from address book</string>\n    <string name=\"send_fragment_scan_label\">Scan QR</string>\n    <string name=\"send_fragment_clipboard_label\">Clipboard</string>\n    <string name=\"chain_status_label_probable_height\">Probable height</string>\n    <string name=\"chain_status_label_partial_height\">Partial chain height</string>\n    <string name=\"chain_status_label_processed_height\">Processed height</string>\n    <string name=\"chain_status_label_chain_offset\">Partial chain offset</string>\n    <string name=\"chain_status_label_chain_length\">Partial chain length</string>\n    <string name=\"chain_status_label_pruned_height\">Pruned below height</string>\n    <string name=\"title_peers\">Peers</string>\n    <string name=\"title_blocks\">Blocks</string>\n    <string name=\"title_processing\">Processing</string>\n    <string name=\"rescan_confirm_msg\">Rescanning the blockchain can take a long time. Are you sure?</string>\n    <string name=\"rescan_confirm_title\">Rescan?</string>\n    <string name=\"rescan_confirm_btn\">Rescan</string>\n    <string name=\"cancel_btn\">Cancel</string>\n    <string name=\"rescan_started\">Rescan started</string>\n    <string name=\"upgrade_wrong_password\">Wrong password?</string>\n    <string name=\"upgrade_explanation\">Munt requires an update. This can take a few minutes, but Munt will be faster, easier to use and more lightweight as a result.</string>\n    <string name=\"upgrade_btn\">Upgrade</string>\n    <string name=\"upgrade_enter_password\">Enter your password</string>\n    <string name=\"upgrade_enter_password_hint\">PIN</string>\n    <string name=\"upgrade_start_fresh\">Don\\'t upgrade, start fresh</string>\n    <string name=\"upgrade_start_fresh_desription\">If you don\\'t have the recovery phrase of your old wallet you will lose it forever if you start fresh. Are you sure?</string>\n    <string name=\"upgrade_start_fresh_title\">Start fresh?</string>\n    <string name=\"notify_received\">Funds received</string>\n    <string name=\"notify_sent\">Funds sent</string>\n    <string name=\"unlock\">Unlock</string>\n    <string name=\"access_code_entry_title\">Access code for \\\"Munt\\\"</string>\n    <plurals name=\"access_code_entry_remaining\">\n        <item quantity=\"one\">%d attempt remaining</item>\n        <item quantity=\"other\">%d attempts remaining</item>\n    </plurals>\n    <string name=\"access_code_choose_upgrade_title\">Choose your new \\\"Munt\\\" access code</string>\n    <string name=\"access_code_choose_title\">Choose your \\\"Munt\\\" access code</string>\n    <string name=\"access_code_choose_verify\">Verify your access code</string>\n    <string name=\"access_code_choose_hint\">6 digit PIN</string>\n    <string name=\"show_recovery_msg\">Don\\'t show your recovery phrase to anyone, or they will be able to spend your Munt.</string>\n    <string name=\"send_coins_error_acknowledge\">OK</string>\n    <string name=\"authentication_blocked_title\">Wallet disabled</string>\n    <string name=\"authentication_blocked_msg_recovery\">Try again %s or choose a new access code using your recovery phrase.</string>\n    <string name=\"authentication_blocked_msg\">Try again %s.</string>\n    <string name=\"authentication_blocked_later_btn\">Try later</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Choose new code</string>\n    <string name=\"access_code_recovery_incorrect\">Incorrect recovery phrase.</string>\n    <string name=\"preference_linked_recovery_descr\">View your recovery phrase on your desktop app.</string>\n    <string name=\"remove_wallet_auth_title\">Remove wallet</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">If you don\\'t have the recovery phrase of your wallet you will lose it forever if you remove it now, also for funds received in the future on its old addresses.\\n\\n</string>\n    <string name=\"remove_wallet_auth_desc\">Enter access code to proceed and remove your wallet.</string>\n    <string name=\"change_passcode_auth_title\">Change code</string>\n    <string name=\"change_passcode_auth_desc\">Enter old access code to proceed and change to a new code.</string>\n    <string name=\"wallet_birth_heading\">How old is this wallet?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Less than a month</string>\n    <string name=\"wallet_birth_less_than_a_year\">Less than a year</string>\n    <string name=\"wallet_birth_unsure\">Older / I\\'m not sure</string>\n    <string name=\"link_wallet_auth_desc\">Enter access code to proceed and link your wallet.</string>\n    <string name=\"numeric_keypad_send_button\">Send</string>\n    <string name=\"preferences_support_button\">Support</string>\n    <string name=\"preferences_advanced_button\">Advanced</string>\n    <string name=\"clipboard_no_valid_address\">No valid Munt address on clipboard</string>\n    <string name=\"transaction_confirmation_text_conflicted\">Conflicted</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Abandoned</string>\n    <string name=\"transaction_confirmation_text_pending\">Pending</string>\n    <string name=\"receive_fragment_share_title\">Share Munt address</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d confirmation</item>\n        <item quantity=\"other\">%d confirmations</item>\n    </plurals>\n    <string name=\"preferences_license_button\">License</string>\n    <string name=\"license_title\">License</string>\n    <string name=\"tx_detail_wallet_address\">Wallet address</string>\n    <string name=\"tx_detail_sending_address\">Sending address</string>\n    <string name=\"tx_detail_payment_address\">Payment address</string>\n    <string name=\"tx_detail_network_fee\">Munt network fee</string>\n    <string name=\"iban_account_holder_name\">Name</string>\n    <string name=\"tx_detail_address_unavailable\">unavailable</string>\n    <string name=\"notification_transaction_channel_name\">Transactions</string>\n    <string name=\"notification_transaction_channel_description\">Transaction notifications</string>\n    <string name=\"notification_service_channel_name\">Service</string>\n    <string name=\"notification_service_channel_description\">Service to keep data synchronised and monitor for transactions when the app is closed, can be turned on/off from inside the app settings</string>\n    <string name=\"dialog_title_add_address\">Add address</string>\n    <string name=\"hint_iban_or_coin_address\">Munt address</string>\n    <string name=\"toast_warn_uri_attempt_before_wallet_creation\">You need to set up a Munt wallet before you can use this URI</string>\n    <string name=\"preference_fragment_link_summary\">Link your mobile wallet with your desktop wallet</string>\n    <string name=\"preference_fragment_remove_summary\">Remove this wallet in order to start or recover another wallet</string>\n    <string name=\"preference_fragment_unlink_label\">Unlink wallet</string>\n    <string name=\"preference_fragment_unlink_summary\">Unlink this wallet in order to start or recover another wallet</string>\n    <string name=\"title_wallet_settings\">Wallet settings</string>\n    <string name=\"title_select_currency\">Select currency</string>\n    <string name=\"label_sync_progress_connecting\">Connecting…</string>\n    <string name=\"label_sync_progress_syncing\">Syncing %.1f%%</string>\n    <string name=\"preference_fragment_hide_balance\">Hide balance</string>\n    <string name=\"show_balance_when_synced\">Balance not visible. Please wait.</string>\n    <string name=\"copied_to_clipboard_toast\">Copied</string>\n    <string name=\"coin_address_clipboard_label\">Munt address</string>\n    <string name=\"send_all_instead_title\">Insufficient balance</string>\n    <string name=\"send_all_instead_msg\">Lower the amount and send all your Munt instead? Amount transferred will be all your Munt minus network fee.</string>\n    <string name=\"send_all_btn\">Send all</string>\n    <string name=\"send_coins_title\">Send Munt?</string>\n    <string name=\"send_btn\">Send</string>\n    <string name=\"core_not_ready_yet\">Unity core not ready yet, please try again in a few seconds</string>\n    <string name=\"send_insufficient_balance\">Insufficient balance</string>\n    <string name=\"not_coin_qr\">Not a valid Munt QR:\\n\\n%1$s</string>\n    <string name=\"error_check_internet_connection\">Please check your internet connection</string>\n    <string name=\"send_fragment_sell_label\">Sell</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.DarkActionBar.Bridge\">\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"coordinatorLayoutStyle\">@style/Widget.Support.CoordinatorLayout</item>\n        <item name=\"floatingActionButtonStyle\">@style/Widget.Design.FloatingActionButton</item>\n        <item name=\"actionBarStyle\">@style/MyActionBar</item>\n\n\n\n        <item name=\"android:actionModeBackground\">@color/bg_main</item>\n        <item name=\"actionModeCloseDrawable\">@color/colorPrimary</item>\n        <item name=\"android:actionModeStyle\">@style/MyActionBar</item>\n        <item name=\"actionModeShareDrawable\">@drawable/ic_fontawesome_share_nodes</item>\n\n        <item name=\"preferenceTheme\">@style/AppTheme.PreferenceThemeOverlay</item>\n    </style>\n\n    <!-- Ensure custom preference layout so that we can put custom borders/controls on it other than just the list view it has by default -->\n    <style name=\"AppTheme.PreferenceThemeOverlay\" parent=\"@style/PreferenceThemeOverlay\">\n        <item name=\"android:layout\">@layout/preference_fragment_layout</item>\n    </style>\n\n    <style name=\"AppTheme.NoActionBar\" parent=\"Theme.MaterialComponents.Light.NoActionBar.Bridge\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"AppTheme.BlueBackground.NoActionBar\" parent=\"AppTheme.NoActionBar\">\n        <item name=\"android:windowBackground\">@color/bg_main</item>\n    </style>\n\n    <style name=\"Theme.Transparent\" parent=\"AppTheme\">\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:backgroundDimEnabled\">false</item>\n    </style>\n\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.MaterialComponents.Dark.ActionBar\">\n        <!-- remove shadow below action bar -->\n        <item name=\"android:elevation\">0dp</item>\n        <!-- Support library compatibility -->\n        <item name=\"elevation\">0dp</item>\n    </style>\n\n    <style name=\"AppTheme.PopupOverlay\" parent=\"Theme.MaterialComponents.Light\">\n    </style>\n\n    <style name=\"MyActionBar\" parent=\"Theme.MaterialComponents.Light.DarkActionBar\">\n        <item name=\"android:background\">@color/bg_main</item>\n    </style>\n\n    <style name=\"NumPadDigit\">\n        <item name=\"android:textSize\">24sp</item>\n        <item name=\"android:fontFamily\">sans-serif-light</item>\n    </style>\n\n    <style name=\"ThinHorizontalDivider\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">1px</item>\n        <item name=\"android:background\">@color/text_main</item>\n    </style>\n\n    <style name=\"TxDetailHeader\">\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textColor\">@color/text_main</item>\n        <item name=\"android:colorControlNormal\">@color/text_main</item>\n    </style>\n\n    <style name=\"TxDetailParagraph\">\n        <item name=\"android:textColor\">@color/text_main</item>\n        <item name=\"android:colorControlNormal\">@color/text_main</item>\n    </style>\n\n    <style name=\"TxDetailMissing\">\n        <item name=\"android:textColor\">@color/text_main</item>\n        <item name=\"android:colorControlNormal\">@color/text_main</item>\n        <item name=\"android:textStyle\">italic</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Don't allow localisation of string-array directly (strings.xml) as this can lead to strange errors if there are missing or removed items in the translations !-->\n    <!-- All string arrays go here instead and then reference into strings.xml via @string/xyz  as necessary for translations !-->\n    <string-array name=\"wallet_birth_date\">\n        <item>@string/wallet_birth_less_than_a_month</item>\n        <item>@string/wallet_birth_less_than_a_year</item>\n        <item>@string/wallet_birth_unsure</item>\n    </string-array>\n    <string-array name=\"currency_codes\">\n        <item>EUR</item>\n        <item>BTC</item>\n        <item>AUD</item>\n        <item>BRL</item>\n        <!--<item>CNY</item>-->\n        <item>GBP</item>\n        <!--<item>RUB</item>-->\n        <item>USD</item>\n        <item>ZAR</item>\n        <item>KRW</item>\n        <item>JPY</item>\n    </string-array>\n    <string-array name=\"currency_names\">\n        <item>Euro</item>\n        <item>Bitcoin</item>\n        <item>Australian Dollar</item>\n        <item>Brazilian Real</item>\n        <!--<item>Chinese Yuan</item>-->\n        <item>British Pound</item>\n        <!--<item>Russian Roebel</item>-->\n        <item>US Dollar</item>\n        <item>South African Rand</item>\n        <item>South Korean Won</item>\n        <item>Japanese Yen</item>\n    </string-array>\n    <string-array name=\"currency_shorts\">\n        <item>€</item>\n        <item>BTC</item>\n        <item>AU$</item>\n        <item>R$</item>\n        <!--<item>CN¥</item>-->\n        <item>£</item>\n        <!--<item>₽</item>-->\n        <item>US$</item>\n        <item>R</item>\n        <item>₩</item>\n        <item>JP¥</item>\n    </string-array>\n    <integer-array\n        name=\"currency_precisions\">\n        <item>2</item>\n        <item>8</item>\n        <item>2</item>\n        <item>2</item>\n        <!--<item>CN¥</item>-->\n        <item>2</item>\n        <!--<item>₽</item>-->\n        <item>2</item>\n        <item>2</item>\n        <item>0</item>\n        <item>0</item>\n    </integer-array>\n    <integer-array\n        name=\"currency_rate_precisions\">\n        <item>4</item>\n        <item>8</item>\n        <item>4</item>\n        <item>4</item>\n        <!--<item>CN¥</item>-->\n        <item>4</item>\n        <!--<item>₽</item>-->\n        <item>4</item>\n        <item>4</item>\n        <item>2</item>\n        <item>2</item>\n    </integer-array>\n\n    <string-array name=\"background_sync_entries\">\n        <item>@string/background_sync_off</item>\n        <item>@string/background_sync_daily</item>\n        <item>@string/background_sync_always</item>\n    </string-array>\n\n    <string-array name=\"background_sync_values\">\n        <item>BACKGROUND_SYNC_OFF</item>\n        <item>BACKGROUND_SYNC_DAILY</item>\n        <item>BACKGROUND_SYNC_CONTINUOUS</item>\n    </string-array>\n\n    <!-- Default value that is localisable by region not language, avoid having translators deal with this !-->\n    <string name=\"default_currency_code\">EUR</string>\n    <string name=\"background_sync_default\">BACKGROUND_SYNC_OFF</string>\n    <string name=\"title_activity_welcome\">Welcome activity</string>\n\n    <!-- UI can't currently handle these being translated, so don't allow it !-->\n    <string name=\"send_keypad_digit_1\">1</string>\n    <string name=\"send_keypad_digit_2\">2</string>\n    <string name=\"send_keypad_digit_3\">3</string>\n    <string name=\"send_keypad_digit_4\">4</string>\n    <string name=\"send_keypad_digit_5\">5</string>\n    <string name=\"send_keypad_digit_6\">6</string>\n    <string name=\"send_keypad_digit_7\">7</string>\n    <string name=\"send_keypad_digit_8\">8</string>\n    <string name=\"send_keypad_digit_9\">9</string>\n    <string name=\"send_keypad_digit_0\">0</string>\n    <string name=\"send_keypad_decimal_separator\">.</string>\n    <string name=\"send_keypad_button_delete\">⌫</string>\n\n    <!-- Only visible in case of major error, or via things like screen readers so avoid burdening translators !-->\n    <string name=\"image_content_description_logo\">Munt logo</string>\n    <string name=\"image_content_description_qr_scan_target_rectangle\">QR scan target rectangle</string>\n\n    <!-- Platform provides default translations so avoid unnecessary translation by translators !-->\n    <string name=\"button_ok\">@android:string/ok</string>\n    <string name=\"button_cancel\">@android:string/cancel</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copia</string>\n    <string name=\"action_bar_share\">Comparteix</string>\n    <string name=\"action_bar_buy\">Compra</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nova cartera</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recupera cartera</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Enllaç amb escriptori</string>\n    <string name=\"recover_from_phrase_intro\">Escriu la frase de recuperació a partir de la qual vulguis realitzar una recuperació.</string>\n    <string name=\"show_recovery_phrase_EULA\">Si fas servir l\\'aplicació Munt, acceptes de forma explícita i incondicional que ets l\\'únic responsable de la gestió i l\\'emmagatzematge dels teus Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continua</string>\n    <string name=\"show_recovery_phrase_introtext\">A continuació es mostra la teva frase de recuperació secreta. Escriu-la i guarda-la en un lloc segur. Si perds la frase, perdràs els Munt. Si una altra persona accedeix a la frase, també perdràs els Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">L\\'he escrita</string>\n    <string name=\"recovery_phrase_copy\">Frase de recuperació copiada al porta-retalls.</string>\n    <string name=\"peer_list_fragment_empty\">Cap parell connectat</string>\n    <string name=\"block_row_now\">ara mateix</string>\n    <string name=\"action_browse\">Navega</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ca/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Senden</string>\n    <string name=\"title_receive\">Empfangen</string>\n    <string name=\"title_transactions\">Transaktionen</string>\n    <string name=\"title_settings\">Einstellungen</string>\n    <string name=\"title_activity_barcode_capture\">Scanne QR code</string>\n    <string name=\"title_activity_transaction_info\">Transaktionsinformationen</string>\n    <string name=\"action_bar_copy\">Kopieren</string>\n    <string name=\"action_bar_copy_long\">In Zwischenablage kopieren</string>\n    <string name=\"action_bar_share\">Teilen</string>\n    <string name=\"action_bar_buy\">Kaufen</string>\n    <string name=\"welcome_activity_create_new_wallet\">Neues Wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Wallet wiederherstellen</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Wallet verbinden</string>\n    <string name=\"recover_from_phrase_intro\">Wiederherstellungsphrase eingeben, mit der eine Wiederherstellung durchgeführt werden soll</string>\n    <string name=\"show_recovery_phrase_EULA\">Mit Benutzung der Munt App erklärst du dich ausdrücklich und bedingungslos einverstanden, dass du alle Verantwortung für die Verwaltung und Speicherung deiner Munt übernimmst.</string>\n    <string name=\"recovery_phrase_continue\">Fortsetzen</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Wiederherstellungsphrase eingeben</string>\n    <string name=\"show_recovery_phrase_introtext\">Unten angezeigt steht deine geheime Wiederherstellungsphrase; schreibe sie dir auf und verwahre sie sicher. Wiederherstellungsphrase verlieren = Munt verlieren. Jemand anders Zugang zu deiner Phrase = auch Munt weg.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Ich habe es aufgeschrieben</string>\n    <string name=\"recovery_phrase_copy\">Wiederherstellungsphrase in die Zwischenablage kopiert</string>\n    <string name=\"address_book_empty_message\">Um eine Adresse hinzuzufügen, starte eine Bezahlung und tippe auf \\\"Zum Adressbuch hinzufügen\\\"</string>\n    <string name=\"address_book_title\">Adressbuch</string>\n    <string name=\"transaction_list_empty_title\">Keine Überweisungen erhalten</string>\n    <string name=\"transaction_list_empty_message\">Hier tippen um deine ersten Munt zu kaufen.</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nnach %2$s</string>\n    <string name=\"peer_list_fragment_empty\">Keine Peers verbunden</string>\n    <string name=\"block_row_now\">gerade eben</string>\n    <string name=\"action_browse\">Im Browser öffnen</string>\n    <string name=\"background_sync_off\">Aus</string>\n    <string name=\"background_sync_daily\">Täglich</string>\n    <string name=\"background_sync_always\">Immer</string>\n    <string name=\"transaction_id\">Transaktions-ID</string>\n    <string name=\"status\">Status</string>\n    <string name=\"amount_label\">Betrag</string>\n    <string name=\"from_label\">Von</string>\n    <string name=\"to_label\">An</string>\n    <string name=\"tx_status_abandoned\">Transaktion verworfen</string>\n    <string name=\"tx_status_conflicted\">in Konflikt geraten</string>\n    <string name=\"tx_status_confirming\">Wird bestätigt %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Unbestätigt</string>\n    <string name=\"tx_status_confirmed\">Bestätigt in Block #%d um %s</string>\n    <string name=\"tx_status_unknown\">Unbekannt (du hast einen Fehler gefunden)</string>\n    <string name=\"no_tx_details\">Keine Transaktionsdetails für [%s]</string>\n    <string name=\"no_qrsync_warning_title\">Ungültiger QR-Code</string>\n    <string name=\"no_qrsync_warning\">Dieser QR-Code enthält keinen gültigen Munt-Synchronisierungscode. Bitte versuchen Sie es erneut mit einem gültigen Code.</string>\n    <string name=\"failed_qrsync_warning_title\">Verbindung zwischen Mobil und Desktop Wallet fehlgeschlagen</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Einige deiner Geldmittel warten noch auf ihre Bestätigung. Bitte erlaube Ihnen vollständig bestätigt zu werden, bevor du die Verbindung zwischen Mobil und Destkop Wallet erneut versuchst.</string>\n    <string name=\"qrsync_info_title\">Verbinden mit Desktop Wallet</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">Du bist im Begriff, eine Verbindung zum Desktop Wallet herzustellen. Die aktuellen Adressen in diesem Wallet werden gelöscht und sind nach der Verbindung nicht länger verfügbar. Die aktuellen Geldmittel werden vor der Verbindung zum Desktop Wallet transferiert und sind kurzfristig nicht verfügbar, bis die Verbindung hergestellt wurde. Bitte stelle sicher, dass du eine Kopie deiner Wiederherstellungsphrase gespeichert hast, falls du später wieder darauf zugreifen musst.</string>\n    <string name=\"qrsync_info_message_empty_wallet\">Du bist im Begriff, eine Verbindung zum Desktop Wallet herzustellen. Die aktuellen Adressen in diesem Wallet werden gelöscht und sind nach der Verbindung nicht länger verfügbar.\nBitte stelle sicher, dass du eine Kopie deiner Wiederherstellungsphrase gespeichert hast, falls du später wieder darauf zugreifen musst.</string>\n    <string name=\"preference_fragment_title\">Einstellungen</string>\n    <string name=\"preference_fragment_recovery_label\">Wiederherstellungsphrase</string>\n    <string name=\"preference_fragment_link_label\">Wallet verbinden</string>\n    <string name=\"preference_fragment_pass_code_label\">Passcode ändern</string>\n    <string name=\"preference_fragment_rescan_label\">Wallet erneut scannen</string>\n    <string name=\"preference_fragment_remove_label\">Wallet löschen</string>\n    <string name=\"preference_fragment_fiat_label\">Lokale Währung</string>\n    <string name=\"preference_fragment_notification_label\">Benachrichtigungen</string>\n    <string name=\"preference_fragment_background_sync_label\">Hintergrund Synchronisation</string>\n    <string name=\"send_coins_label_add_to_address_book\">Zum Adressbuch hinzufügen</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Vom Adressbuch entfernen</string>\n    <string name=\"send_fragment_scan_label\">Scanne den QR Code</string>\n    <string name=\"send_fragment_clipboard_label\">Zwischenablage</string>\n    <string name=\"chain_status_label_probable_height\">Wahrscheinliche Höhe</string>\n    <string name=\"chain_status_label_partial_height\">Teilweise Kettenhöhe</string>\n    <string name=\"chain_status_label_processed_height\">Bearbeitete Höhe</string>\n    <string name=\"chain_status_label_chain_offset\">Partielle Kettenversatz</string>\n    <string name=\"chain_status_label_chain_length\">Partielle Kettenlänge</string>\n    <string name=\"chain_status_label_pruned_height\">Unterhalb der Höhe beschnitten</string>\n    <string name=\"title_peers\">Peers</string>\n    <string name=\"title_blocks\">Blöcke</string>\n    <string name=\"title_processing\">Bearbeitung</string>\n    <string name=\"rescan_confirm_msg\">Erneutes Scannen der Blockkette kann eine lange Zeit in Anspruch nehmen. Bist du dir sicher?</string>\n    <string name=\"rescan_confirm_title\">Erneut scannen?</string>\n    <string name=\"rescan_confirm_btn\">Erneut scannen</string>\n    <string name=\"cancel_btn\">Abbrechen</string>\n    <string name=\"rescan_started\">Erneuter Scan gestartet</string>\n    <string name=\"upgrade_wrong_password\">Falsches Passwort?</string>\n    <string name=\"upgrade_explanation\">Munt benötigt eine Aktualisierung. Dies kann einige Minuten dauern. Danach ist Munt schneller, einfacher zu verwenden und eine leichtgewichtigere Anwendung.</string>\n    <string name=\"upgrade_btn\">Aktualisierung</string>\n    <string name=\"upgrade_enter_password\">Passwort eingeben</string>\n    <string name=\"upgrade_enter_password_hint\">PIN</string>\n    <string name=\"upgrade_start_fresh\">Nicht aktualisieren, neu beginnen</string>\n    <string name=\"upgrade_start_fresh_desription\">Wenn du die Wiederherstellungsphrase vom alten Wallet nicht hast, verlierst du es für immer wenn du jetzt neu beginnst. Bist du dir sicher?</string>\n    <string name=\"upgrade_start_fresh_title\">Neu beginnen?</string>\n    <string name=\"notify_received\">Geldmittel erhalten</string>\n    <string name=\"notify_sent\">Geldmittel gesendet</string>\n    <string name=\"unlock\">Entsperren</string>\n    <string name=\"access_code_entry_title\">Zugangscode für \\\"Munt\\\"</string>\n    <plurals name=\"access_code_entry_remaining\">\n        <item quantity=\"one\">Noch %d Versuch</item>\n        <item quantity=\"other\">%d verbleibende Versuche</item>\n    </plurals>\n    <string name=\"access_code_choose_upgrade_title\">Wähle deinen neuen \\\"Munt\\\" Zugangscode</string>\n    <string name=\"access_code_choose_title\">Wähle deinen \\\"Munt\\\" Zugangscode</string>\n    <string name=\"access_code_choose_verify\">Bestätige deinen Zugangscode</string>\n    <string name=\"access_code_choose_hint\">6-stelliger PIN</string>\n    <string name=\"show_recovery_msg\">Zeige deine Wiederherstellungsphrase niemandem, sonst können sie deine Munt ausgeben.</string>\n    <string name=\"send_coins_error_acknowledge\">OK</string>\n    <string name=\"authentication_blocked_title\">Wallet deaktiviert</string>\n    <string name=\"authentication_blocked_msg_recovery\">Versuche %s erneut, oder wähle einen neuen Zugangscode unter Verwendung deiner Wiederherstellungsphrase.</string>\n    <string name=\"authentication_blocked_msg\">Versuche %s erneut.</string>\n    <string name=\"authentication_blocked_later_btn\">Versuche es später</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Wähle einen neuen Code</string>\n    <string name=\"access_code_recovery_incorrect\">Falsche Wiederherstellungsphrase.</string>\n    <string name=\"preference_linked_recovery_descr\">Zeige die Wiederherstellungsphrase auf deinem Desktop Wallet.</string>\n    <string name=\"remove_wallet_auth_title\">Wallet löschen</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">Wenn Sie den Wiederherstellungssatz Ihrer Wallet nicht haben, werden Sie ihn für immer verlieren, wenn Sie ihn jetzt entfernen. Dies gilt auch für zukünftig an Ihre alten Adressen erhaltene Gelder.\\n</string>\n    <string name=\"remove_wallet_auth_desc\">Gib den Zugangscode ein um das Wallet zu löschen.</string>\n    <string name=\"change_passcode_auth_title\">Zugangscode ändern</string>\n    <string name=\"change_passcode_auth_desc\">Gib den alten Zugangscode ein um einen neuen hinzuzufügen.</string>\n    <string name=\"wallet_birth_heading\">Wie alt ist dieses Wallet?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Weniger als ein Monat</string>\n    <string name=\"wallet_birth_less_than_a_year\">Weniger als ein Jahr</string>\n    <string name=\"wallet_birth_unsure\">Älter / Ich bin mir nicht sicher</string>\n    <string name=\"link_wallet_auth_desc\">Zugangscode eingeben, um fortzufahren und Ihre Wallet zu verbinden.</string>\n    <string name=\"numeric_keypad_send_button\">Senden</string>\n    <string name=\"preferences_support_button\">Hilfe</string>\n    <string name=\"preferences_advanced_button\">Fortgeschritten</string>\n    <string name=\"clipboard_no_valid_address\">Keine gültige Munt-Adresse in der Zwischenablage</string>\n    <string name=\"transaction_confirmation_text_conflicted\">In Konflikt geraten</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Verlassen</string>\n    <string name=\"transaction_confirmation_text_pending\">Steht aus</string>\n    <string name=\"receive_fragment_share_title\">Munt Adresse teilen</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d Bestätigung</item>\n        <item quantity=\"other\">%d Bestätigungen</item>\n    </plurals>\n    <string name=\"preferences_license_button\">Lizenz</string>\n    <string name=\"license_title\">Lizenz</string>\n    <string name=\"tx_detail_wallet_address\">Wallet Adresse</string>\n    <string name=\"tx_detail_sending_address\">Sendeadresse</string>\n    <string name=\"tx_detail_payment_address\">Zahlungsadresse</string>\n    <string name=\"tx_detail_network_fee\">Munt Netzwerk-Gebühr</string>\n    <string name=\"iban_account_holder_name\">Name</string>\n    <string name=\"tx_detail_address_unavailable\">nicht verfügbar</string>\n    <string name=\"notification_transaction_channel_name\">Transaktionen</string>\n    <string name=\"notification_transaction_channel_description\">Transaktionsbenachrichtigungen</string>\n    <string name=\"notification_service_channel_name\">Service</string>\n    <string name=\"notification_service_channel_description\">Dienst, der die Daten synchron hält und Transaktionen überwacht, wenn die App geschlossen wird, kann in den App-Einstellungen aktiviert / deaktiviert werden.</string>\n    <string name=\"dialog_title_add_address\">Adresse hinzufügen</string>\n    <string name=\"hint_iban_or_coin_address\">Munt-Adresse</string>\n    <string name=\"toast_warn_uri_attempt_before_wallet_creation\">Du musst eine Munt-Wallet einrichten, bevor du diese URI verwenden kannst</string>\n    <string name=\"preference_fragment_link_summary\">Verbinde dein mobiles Wallet mit deinem Desktop-Wallet</string>\n    <string name=\"preference_fragment_remove_summary\">Entferne dieses Wallet, um eine anderes Wallet zu starten oder wiederherzustellen</string>\n    <string name=\"preference_fragment_unlink_label\">Verbindung aufheben</string>\n    <string name=\"preference_fragment_unlink_summary\">Verbindung aufheben, um eine anderes Wallet zu starten oder wiederherzustellen</string>\n    <string name=\"title_wallet_settings\">Wallet-Einstellungen</string>\n    <string name=\"title_select_currency\">Währung auswählen</string>\n    <string name=\"label_sync_progress_connecting\">Verbinde…</string>\n    <string name=\"label_sync_progress_syncing\">Synchronisiere %.1f%%</string>\n    <string name=\"preference_fragment_hide_balance\">Kontostand verbergen</string>\n    <string name=\"show_balance_when_synced\">Kontostand nicht sichtbar. Bitte warten.</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-de/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rAU/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link with desktop</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rAU/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">AUD</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rCA/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link with desktop</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rCA/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">USD</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rGB/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Send</string>\n    <string name=\"title_receive\">Receive</string>\n    <string name=\"title_transactions\">Transactions</string>\n    <string name=\"title_settings\">Settings</string>\n    <string name=\"title_activity_barcode_capture\">Scan QR code</string>\n    <string name=\"title_activity_transaction_info\">Transaction info</string>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_copy_long\">Copy to clipboard</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link wallet</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Enter recovery phrase</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"address_book_empty_message\">To add an address, start a payment and tap \\\"Add to address book\\\".</string>\n    <string name=\"address_book_title\">Address book</string>\n    <string name=\"transaction_list_empty_title\">No Transactions received</string>\n    <string name=\"transaction_list_empty_message\">Touch here to buy your first Munt</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nto %2$s</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n    <string name=\"background_sync_off\">Off</string>\n    <string name=\"background_sync_daily\">Daily</string>\n    <string name=\"background_sync_always\">Always</string>\n    <string name=\"transaction_id\">Transaction ID</string>\n    <string name=\"status\">Status</string>\n    <string name=\"amount_label\">Amount</string>\n    <string name=\"from_label\">From</string>\n    <string name=\"to_label\">To</string>\n    <string name=\"tx_status_abandoned\">Abandoned</string>\n    <string name=\"tx_status_conflicted\">Conflicted</string>\n    <string name=\"tx_status_confirming\">Confirming %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Unconfirmed</string>\n    <string name=\"tx_status_confirmed\">Confirmed in block #%d at %s</string>\n    <string name=\"tx_status_unknown\">Unknown (you found a bug)</string>\n    <string name=\"no_tx_details\">No transaction details for [%s]</string>\n    <string name=\"no_qrsync_warning_title\">Invalid QR code</string>\n    <string name=\"no_qrsync_warning\">This QR code does not contain a valid Munt sync code, please try again with a valid code.</string>\n    <string name=\"failed_qrsync_warning_title\">Could not perform link</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Some of your funds are awaiting confirmation, please allow for them to fully confirm before attempting the link process again.</string>\n    <string name=\"qrsync_info_title\">Link with desktop wallet</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">You are about to establish a link with your desktop wallet. The current addresses in this wallet will be deleted and no longer available after the link is established. The current funds in this wallet will be transferred into the desktop wallet before the link is established, and will be temporarily unavailable from this wallet until the link finishes establishing. Please ensure you save a copy of your old recovery phrase somewhere in case you ever find the need to access these addresses again.</string>\n    <string name=\"qrsync_info_message_empty_wallet\">You are about to establish a link with your desktop wallet. The current addresses in this wallet will be deleted and no longer available after the link is established. Please ensure you save a copy of your old recovery phrase somewhere in case you ever find the need to access these addresses again.</string>\n    <string name=\"preference_fragment_title\">Preferences</string>\n    <string name=\"preference_fragment_recovery_label\">Recovery phrase</string>\n    <string name=\"preference_fragment_link_label\">Link wallet</string>\n    <string name=\"preference_fragment_pass_code_label\">Change passcode</string>\n    <string name=\"preference_fragment_rescan_label\">Rescan wallet</string>\n    <string name=\"preference_fragment_remove_label\">Remove wallet</string>\n    <string name=\"preference_fragment_fiat_label\">Local currency</string>\n    <string name=\"preference_fragment_notification_label\">Notifications</string>\n    <string name=\"preference_fragment_background_sync_label\">Background synchronisation</string>\n    <string name=\"send_coins_label_add_to_address_book\">Add to address book</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Remove from address book</string>\n    <string name=\"send_fragment_scan_label\">Scan QR</string>\n    <string name=\"send_fragment_clipboard_label\">Clipboard</string>\n    <string name=\"chain_status_label_probable_height\">Probable height</string>\n    <string name=\"chain_status_label_partial_height\">Partial chain height</string>\n    <string name=\"chain_status_label_processed_height\">Processed height</string>\n    <string name=\"chain_status_label_chain_offset\">Partial chain offset</string>\n    <string name=\"chain_status_label_chain_length\">Partial chain length</string>\n    <string name=\"chain_status_label_pruned_height\">Pruned below height</string>\n    <string name=\"title_peers\">Peers</string>\n    <string name=\"title_blocks\">Blocks</string>\n    <string name=\"title_processing\">Processing</string>\n    <string name=\"rescan_confirm_msg\">Rescanning the blockchain can take a long time. Are you sure?</string>\n    <string name=\"rescan_confirm_title\">Rescan?</string>\n    <string name=\"rescan_confirm_btn\">Rescan</string>\n    <string name=\"cancel_btn\">Cancel</string>\n    <string name=\"rescan_started\">Rescan started</string>\n    <string name=\"upgrade_wrong_password\">Wrong password?</string>\n    <string name=\"upgrade_explanation\">Munt requires an update. This can take a few minutes, but Munt will be faster, easier to use and more lightweight as a result.</string>\n    <string name=\"upgrade_btn\">Upgrade</string>\n    <string name=\"upgrade_enter_password\">Enter your password</string>\n    <string name=\"upgrade_enter_password_hint\">PIN</string>\n    <string name=\"upgrade_start_fresh\">Don\\'t upgrade, start fresh</string>\n    <string name=\"upgrade_start_fresh_desription\">If you don\\'t have the recovery phrase of your old wallet you will lose it forever if you start fresh. Are you sure?</string>\n    <string name=\"upgrade_start_fresh_title\">Start fresh?</string>\n    <string name=\"notify_received\">Funds received</string>\n    <string name=\"notify_sent\">Funds sent</string>\n    <string name=\"unlock\">Unlock</string>\n    <string name=\"access_code_entry_title\">Access code for \\\"Munt\\\"</string>\n    <plurals name=\"access_code_entry_remaining\">\n        <item quantity=\"one\">%d attempt remaining</item>\n        <item quantity=\"other\">%d attempts remaining</item>\n    </plurals>\n    <string name=\"access_code_choose_upgrade_title\">Choose your new \\\"Munt\\\" access code</string>\n    <string name=\"access_code_choose_title\">Choose your \\\"Munt\\\" access code</string>\n    <string name=\"access_code_choose_verify\">Verify your access code</string>\n    <string name=\"access_code_choose_hint\">6 digit PIN</string>\n    <string name=\"show_recovery_msg\">Don\\'t show your recovery phrase to anyone, or they will be able to spend your Munt.</string>\n    <string name=\"send_coins_error_acknowledge\">OK</string>\n    <string name=\"authentication_blocked_title\">Wallet disabled</string>\n    <string name=\"authentication_blocked_msg_recovery\">Try again %s or choose a new access code using your recovery phrase.</string>\n    <string name=\"authentication_blocked_msg\">Try again %s.</string>\n    <string name=\"authentication_blocked_later_btn\">Try later</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Choose new code</string>\n    <string name=\"access_code_recovery_incorrect\">Incorrect recovery phrase.</string>\n    <string name=\"preference_linked_recovery_descr\">View your recovery phrase on your desktop app.</string>\n    <string name=\"remove_wallet_auth_title\">Remove wallet</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">If you don\\'t have the recovery phrase of your wallet you will lose it forever if you remove it now, also for funds received in the future on its old addresses.\\n\\n</string>\n    <string name=\"remove_wallet_auth_desc\">Enter access code to proceed and remove your wallet.</string>\n    <string name=\"change_passcode_auth_title\">Change code</string>\n    <string name=\"change_passcode_auth_desc\">Enter old access code to proceed and change to a new code.</string>\n    <string name=\"wallet_birth_heading\">How old is this wallet?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Less than a month</string>\n    <string name=\"wallet_birth_less_than_a_year\">Less than a year</string>\n    <string name=\"wallet_birth_unsure\">Older / I\\'m not sure</string>\n    <string name=\"link_wallet_auth_desc\">Enter access code to proceed and link your wallet.</string>\n    <string name=\"numeric_keypad_send_button\">Send</string>\n    <string name=\"preferences_support_button\">Support</string>\n    <string name=\"preferences_advanced_button\">Advanced</string>\n    <string name=\"clipboard_no_valid_address\">No valid Munt address on clipboard</string>\n    <string name=\"transaction_confirmation_text_conflicted\">Conflicted</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Abandoned</string>\n    <string name=\"transaction_confirmation_text_pending\">Pending</string>\n    <string name=\"receive_fragment_share_title\">Share Munt address</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d confirmation</item>\n        <item quantity=\"other\">%d confirmations</item>\n    </plurals>\n    <string name=\"preferences_license_button\">License</string>\n    <string name=\"license_title\">License</string>\n    <string name=\"tx_detail_wallet_address\">Wallet address</string>\n    <string name=\"tx_detail_sending_address\">Sending address</string>\n    <string name=\"tx_detail_payment_address\">Payment address</string>\n    <string name=\"tx_detail_network_fee\">Munt network fee</string>\n    <string name=\"iban_account_holder_name\">Name</string>\n    <string name=\"tx_detail_address_unavailable\">unavailable</string>\n    <string name=\"notification_transaction_channel_name\">Transactions</string>\n    <string name=\"notification_transaction_channel_description\">Transaction notifications</string>\n    <string name=\"notification_service_channel_name\">Service</string>\n    <string name=\"notification_service_channel_description\">Service to keep data synchronised and monitor for transactions when the app is closed, can be turned on/off from inside the app settings</string>\n    <string name=\"dialog_title_add_address\">Add address</string>\n    <string name=\"hint_iban_or_coin_address\">Munt address</string>\n    <string name=\"toast_warn_uri_attempt_before_wallet_creation\">You need to set up a Munt wallet before you can use this URI</string>\n    <string name=\"preference_fragment_link_summary\">Link your mobile wallet with your desktop wallet</string>\n    <string name=\"preference_fragment_remove_summary\">Remove this wallet in order to start or recover another wallet</string>\n    <string name=\"preference_fragment_unlink_label\">Unlink wallet</string>\n    <string name=\"preference_fragment_unlink_summary\">Unlink this wallet in order to start or recover another wallet</string>\n    <string name=\"title_wallet_settings\">Wallet settings</string>\n    <string name=\"title_select_currency\">Select currency</string>\n    <string name=\"label_sync_progress_connecting\">Connecting…</string>\n    <string name=\"label_sync_progress_syncing\">Syncing %.1f%%</string>\n    <string name=\"preference_fragment_hide_balance\">Hide balance</string>\n    <string name=\"show_balance_when_synced\">Balance not visible. Please wait.</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rGB/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rUS/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link with desktop</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rUS/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">USD</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rZA/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copy</string>\n    <string name=\"action_bar_share\">Share</string>\n    <string name=\"action_bar_buy\">Buy</string>\n    <string name=\"welcome_activity_create_new_wallet\">New wallet</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recover wallet</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Link with desktop</string>\n    <string name=\"recover_from_phrase_intro\">Enter your recovery phrase from which to perform a recovery</string>\n    <string name=\"show_recovery_phrase_EULA\">By using the Munt app you explicitly and unconditionally agree that you carry all responsibility for the management and storage of your Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continue</string>\n    <string name=\"show_recovery_phrase_introtext\">Below is your secret recovery phrase, write it down and keep it safe. Lose phrase = lose Munt. Someone else with access to the phrase = lose Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">I wrote it down</string>\n    <string name=\"recovery_phrase_copy\">Recovery phrase copied to clipboard</string>\n    <string name=\"peer_list_fragment_empty\">No peers connected</string>\n    <string name=\"block_row_now\">just now</string>\n    <string name=\"action_browse\">Browse</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-en-rZA/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">ZAR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copiar</string>\n    <string name=\"action_bar_share\">Compartir</string>\n    <string name=\"action_bar_buy\">Comprar</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nuevo monedero</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recuperar monedero</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Contectar a computadora</string>\n    <string name=\"recover_from_phrase_intro\">Entre su frase de recuperación para realizar una recuperación</string>\n    <string name=\"show_recovery_phrase_EULA\">Al usar la aplicación Munt acuerdas explícita e incondicionalmente que cargas con la responsabilidad de la gestión y del depósito de tus Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continuar</string>\n    <string name=\"show_recovery_phrase_introtext\">Abajo está su frase de recuperación secreta, anótala y manténgala segura. Perder frase = perder Munt. Otra persona tiene acceso a la frase = perder Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">La he anotado</string>\n    <string name=\"recovery_phrase_copy\">Frase de recuperación copiada al portapapeles</string>\n    <string name=\"peer_list_fragment_empty\">No hay pares conectados</string>\n    <string name=\"block_row_now\">justo ahora</string>\n    <string name=\"action_browse\">Navegar</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-es/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Kopioi</string>\n    <string name=\"action_bar_share\">Jaa</string>\n    <string name=\"action_bar_buy\">Osta</string>\n    <string name=\"welcome_activity_create_new_wallet\">Uusi lompakko</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Palauta lompakko</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Yhdistä pöytäkoneeseen</string>\n    <string name=\"recover_from_phrase_intro\">Syötä palautuksessa käytettävä palautuslauseke</string>\n    <string name=\"show_recovery_phrase_EULA\">Munt-sovellusta käyttämällä ilmaiset ottavasi kaiken vastuun Muntiesi hallinnoinnista ja talletuksesta.</string>\n    <string name=\"recovery_phrase_continue\">Jatka</string>\n    <string name=\"show_recovery_phrase_introtext\">Alla on salainen palautuslausekkeesi; kirjoita se muistiin ja pidä hyvässä tallessa. Lausekkeen menetys = Muntien menetys. Joku toinen saa lausekkeen haltuunsa = Muntien menetys.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Kirjoitin sen muistiin</string>\n    <string name=\"recovery_phrase_copy\">Palauta leikepöydälle kopioitu lauseke</string>\n    <string name=\"peer_list_fragment_empty\">Ei yhteyksiä vertaisiin</string>\n    <string name=\"block_row_now\">tällä hetkellä</string>\n    <string name=\"action_browse\">Selaa</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-fi/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Envoyer</string>\n    <string name=\"title_receive\">Recevoir</string>\n    <string name=\"title_transactions\">Transactions</string>\n    <string name=\"title_settings\">Réglages</string>\n    <string name=\"title_activity_barcode_capture\">Scanner le code QR</string>\n    <string name=\"title_activity_transaction_info\">Infos sur les transactions</string>\n    <string name=\"action_bar_copy\">Copier</string>\n    <string name=\"action_bar_copy_long\">Copier dans le presse-papiers</string>\n    <string name=\"action_bar_share\">Partager</string>\n    <string name=\"action_bar_buy\">Acheter</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nouveau portefeuille</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Récupérer le portefeuille</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Lien avec le bureau</string>\n    <string name=\"recover_from_phrase_intro\">Entrez votre phrase de récupération afin d\\'effectuer une récupération</string>\n    <string name=\"show_recovery_phrase_EULA\">En utilisant l\\'application Munt, vous acceptez explicitement et inconditionnellement que vous assumez toute la responsabilité de la gestion et du stockage de vos Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continuer</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Entrer la phrase de récupération</string>\n    <string name=\"show_recovery_phrase_introtext\">Voici votre phrase de récupération, écrivez-la et gardez-la en sécurité. Si vous perdez votre phrase vous perdez vos Munt. Si une autre personne a accès à la phrase vous perdez vos Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Je l\\'ai écrit</string>\n    <string name=\"recovery_phrase_copy\">La phrase de récupération est copiée dans le presse-papier</string>\n    <string name=\"address_book_empty_message\">Pour ajouter une adresse, lancez un paiement et touchez \\\"Ajouter au carnet d\\'adresses\\\".</string>\n    <string name=\"address_book_title\">Carnet d\\'adresses</string>\n    <string name=\"transaction_list_empty_title\">Aucun transaction n\\'a reçu jusqu\\'à présent.</string>\n    <string name=\"transaction_list_empty_message\">Touchez ici pour acheter votre premier Munt.</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nà %2$s</string>\n    <string name=\"peer_list_fragment_empty\">Aucun pair connecté</string>\n    <string name=\"block_row_now\">Maintenant</string>\n    <string name=\"action_browse\">Naviguer</string>\n    <string name=\"background_sync_off\">Désactivé</string>\n    <string name=\"background_sync_daily\">Quotidien</string>\n    <string name=\"background_sync_always\">Toujours</string>\n    <string name=\"transaction_id\">ID de transaction</string>\n    <string name=\"status\">État</string>\n    <string name=\"amount_label\">Montant</string>\n    <string name=\"from_label\">De</string>\n    <string name=\"to_label\">À</string>\n    <string name=\"tx_status_abandoned\">Abandonné</string>\n    <string name=\"tx_status_conflicted\">Conflit</string>\n    <string name=\"tx_status_confirming\">Confirmation %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Non confirmé</string>\n    <string name=\"tx_status_confirmed\">Confirmé dans le bloc #%d à %s</string>\n    <string name=\"tx_status_unknown\">Inconnu (vous avez trouvé un bug)</string>\n    <string name=\"no_tx_details\">Pas de détails de transaction pour[%s]</string>\n    <string name=\"no_qrsync_warning_title\">Code QR invalide</string>\n    <string name=\"no_qrsync_warning\">Ce code QR ne contient pas de code de synchronisation Munt valide, veuillez réessayer avec un code valide.</string>\n    <string name=\"failed_qrsync_warning_title\">Impossible d\\'effectuer la liaison</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Certains de vos fonds sont en attente de confirmation, s\\'il vous plaît leur permettre de confirmer pleinement avant de tenter à nouveau le processus de lien.</string>\n    <string name=\"qrsync_info_title\">Lien avec le porte-monnaie de bureau</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">Vous êtes sur le point d\\'établir un lien avec votre portefeuille de bureau. Les adresses actuelles de ce portefeuille seront supprimées et ne seront plus disponibles une fois le lien établi. Les fonds qui se trouvent actuellement dans ce portefeuille seront transférés dans le portefeuille de bureau avant que le lien ne soit établi et seront temporairement indisponibles de ce portefeuille jusqu\\'à ce que le lien soit établi. Veuillez vous assurer d\\'enregistrer une copie de votre ancienne phrase de récupération quelque part au cas où vous auriez besoin d\\'accéder de nouveau à ces adresses.</string>\n    <string name=\"qrsync_info_message_empty_wallet\">Vous êtes sur le point d\\'établir un lien avec votre portefeuille de bureau. Les adresses actuelles de ce portefeuille seront supprimées et ne seront plus disponibles une fois le lien établi. Veuillez vous assurer d\\'enregistrer une copie de votre ancienne phrase de récupération quelque part au cas où vous auriez besoin d\\'accéder de nouveau à ces adresses.</string>\n    <string name=\"preference_fragment_title\">Préférences</string>\n    <string name=\"preference_fragment_recovery_label\">Phrase de récupération</string>\n    <string name=\"preference_fragment_link_label\">Lien avec le portefeuille bureau</string>\n    <string name=\"preference_fragment_pass_code_label\">Changer mot de passe</string>\n    <string name=\"preference_fragment_rescan_label\">Portefeuille Rescan</string>\n    <string name=\"preference_fragment_remove_label\">Retirer le portefeuille</string>\n    <string name=\"preference_fragment_fiat_label\">La monnaie locale</string>\n    <string name=\"preference_fragment_notification_label\">Notifications</string>\n    <string name=\"preference_fragment_background_sync_label\">Synchronisation en arrière-plan</string>\n    <string name=\"send_coins_label_add_to_address_book\">Ajouter au carnet d\\'adresses</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Retirer du carnet d\\'adresses</string>\n    <string name=\"send_fragment_scan_label\">Scannez le QR code</string>\n    <string name=\"send_fragment_clipboard_label\">Le presse-papier</string>\n    <string name=\"chain_status_label_probable_height\">Hauteur probable</string>\n    <string name=\"chain_status_label_partial_height\">Hauteur de chaîne partielle</string>\n    <string name=\"chain_status_label_processed_height\">Hauteur traitée</string>\n    <string name=\"chain_status_label_chain_offset\">Décalage partiel de la chaîne</string>\n    <string name=\"chain_status_label_chain_length\">Longueur de chaîne partielle</string>\n    <string name=\"chain_status_label_pruned_height\">Taillée en dessous de la hauteur</string>\n    <string name=\"title_peers\">Pairs</string>\n    <string name=\"title_blocks\">Blocs</string>\n    <string name=\"title_processing\">Traitement</string>\n    <string name=\"rescan_confirm_msg\">Le réenregistrement de la chaîne de blocage peut prendre beaucoup de temps. T\\'es sûr de toi?</string>\n    <string name=\"rescan_confirm_title\">Rescanner</string>\n    <string name=\"rescan_confirm_btn\">Rescan</string>\n    <string name=\"cancel_btn\">Annuler</string>\n    <string name=\"rescan_started\">Rescan a commencé</string>\n    <string name=\"upgrade_wrong_password\">Mot de passe erroné?</string>\n    <string name=\"upgrade_explanation\">Munt a besoin d\\'une mise à jour. Cela peut prendre quelques minutes, mais Munt sera plus rapide, plus facile à utiliser et plus léger.</string>\n    <string name=\"upgrade_btn\">Mise à niveau</string>\n    <string name=\"upgrade_enter_password\">Entrez votre mot de passe</string>\n    <string name=\"upgrade_enter_password_hint\">NIP</string>\n    <string name=\"upgrade_start_fresh\">Ne mettez pas à niveau, recommencez à zéro</string>\n    <string name=\"upgrade_start_fresh_desription\">Si vous n\\'avez pas la phrase de récupération de votre ancien portefeuille, vous le perdrez à jamais si vous recommencez à zéro. T\\'es sûr de toi ?</string>\n    <string name=\"upgrade_start_fresh_title\">Repartir à zéro?</string>\n    <string name=\"notify_received\">Fonds reçus</string>\n    <string name=\"notify_sent\">Fonds envoyés</string>\n    <string name=\"unlock\">Déverrouiller</string>\n    <string name=\"access_code_entry_title\">Code d\\'accès pour \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_upgrade_title\">Choisissez votre nouveau code d\\'accès \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_title\">Choisissez votre code d\\'accès \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_verify\">Vérifiez votre code d\\'accès</string>\n    <string name=\"access_code_choose_hint\">NIP à 6 chiffres</string>\n    <string name=\"show_recovery_msg\">Ne montrez votre phrase de récupération à personne, ou ils pourront dépenser votre Munt.</string>\n    <string name=\"send_coins_error_acknowledge\">OK</string>\n    <string name=\"authentication_blocked_title\">Portefeuille desactivé</string>\n    <string name=\"authentication_blocked_msg_recovery\">Essayez à nouveau %s ou choisissez un nouveau code d\\'accès en utilisant votre phrase de récupération.</string>\n    <string name=\"authentication_blocked_msg\">Essayez à nouveau %s.</string>\n    <string name=\"authentication_blocked_later_btn\">Essayez plus tard</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Choisir un nouveau code</string>\n    <string name=\"access_code_recovery_incorrect\">Phrase de récupération incorrecte.</string>\n    <string name=\"preference_linked_recovery_descr\">Affichez votre phrase de récupération sur votre application de bureau.</string>\n    <string name=\"remove_wallet_auth_title\">Retirer le portefeuille</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">Si vous n\\'avez pas la phrase de récupération de votre portefeuille, vous le perdrez à jamais si vous le retirez maintenant, même pour les fonds reçus à l\\'avenir sur ses anciennes adresses.\\n</string>\n    <string name=\"remove_wallet_auth_desc\">Entrez le code d\\'accès pour continuer et retirer votre portefeuille.</string>\n    <string name=\"change_passcode_auth_title\">Modifier le code</string>\n    <string name=\"change_passcode_auth_desc\">Entrez l\\'ancien code d\\'accès pour continuer et changer de code.</string>\n    <string name=\"wallet_birth_heading\">Quel âge a ce portefeuille?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Moins d\\'un mois</string>\n    <string name=\"wallet_birth_less_than_a_year\">Moins d\\'un an</string>\n    <string name=\"wallet_birth_unsure\">Plus vieux / Je ne suis pas sûr</string>\n    <string name=\"link_wallet_auth_desc\">Entrez le code d\\'accès pour continuer et lier votre porte-monnaie.</string>\n    <string name=\"numeric_keypad_send_button\">Envoyer</string>\n    <string name=\"preferences_support_button\">Support</string>\n    <string name=\"preferences_advanced_button\">Avancé</string>\n    <string name=\"clipboard_no_valid_address\">Pas d\\'adresse Munt valide dans le presse-papiers</string>\n    <string name=\"transaction_confirmation_text_conflicted\">Conflit</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Abandonné</string>\n    <string name=\"transaction_confirmation_text_pending\">En attente</string>\n    <string name=\"receive_fragment_share_title\">Partager l\\'adresse de Munt</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d confirmation</item>\n        <item quantity=\"other\">%d confirmations</item>\n    </plurals>\n    <string name=\"preferences_license_button\">Licence</string>\n    <string name=\"license_title\">Licence</string>\n    <string name=\"tx_detail_wallet_address\">Adresse du portefeuille</string>\n    <string name=\"tx_detail_sending_address\">Adresse d\\'envoi</string>\n    <string name=\"tx_detail_payment_address\">Adresse de paiement</string>\n    <string name=\"tx_detail_network_fee\">Frais de réseau Munt</string>\n    <string name=\"iban_account_holder_name\">Nom</string>\n    <string name=\"tx_detail_address_unavailable\">indisponible</string>\n    <string name=\"notification_transaction_channel_name\">Transactions</string>\n    <string name=\"notification_transaction_channel_description\">Notification des transactions</string>\n    <string name=\"notification_service_channel_name\">Service</string>\n    <string name=\"notification_service_channel_description\">Service pour garder les données synchronisées et surveiller les transactions lorsque l\\'application est fermée, peut être activé/désactivé depuis les paramètres de l\\'application.</string>\n    <string name=\"dialog_title_add_address\">Ajouter une adresse</string>\n    <string name=\"hint_iban_or_coin_address\">Munt adresse</string>\n    <string name=\"label_sync_progress_syncing\">Concordance %.1f%%</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-fr/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Invia</string>\n    <string name=\"title_receive\">Ricevi</string>\n    <string name=\"title_transactions\">Transazione</string>\n    <string name=\"title_settings\">Configurazione</string>\n    <string name=\"title_activity_barcode_capture\">Scansiona il codice QR</string>\n    <string name=\"title_activity_transaction_info\">Informazioni sulla transazione</string>\n    <string name=\"action_bar_copy\">Copia</string>\n    <string name=\"action_bar_share\">Condividi</string>\n    <string name=\"action_bar_buy\">Compra</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nuovo portafoglio</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recupera portafoglio</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Collega con il desktop</string>\n    <string name=\"recover_from_phrase_intro\">Inserisci la frase di recupero da usare</string>\n    <string name=\"show_recovery_phrase_EULA\">\"\nUsando l'app Munt accetti in maniera esplicita ed incondizionata di essere responsabile della gestione e del deposito dei tuoi Munt.\"</string>\n    <string name=\"recovery_phrase_continue\">Continua</string>\n    <string name=\"show_recovery_phrase_introtext\">Di seguito trovi la tua frase segreta di recupero, ricopiala e conservala per futuro riferimento. Se perdi la frase, perderai Munt. Se qualcun altro ha accesso alla frase, perderai Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">L\\'ho ricopiata</string>\n    <string name=\"recovery_phrase_copy\">Fase di recupero copiata negli appunti</string>\n    <string name=\"peer_list_fragment_empty\">Nessun peer connesso</string>\n    <string name=\"block_row_now\">proprio ora</string>\n    <string name=\"action_browse\">Sfoglia</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-it/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">コピー</string>\n    <string name=\"action_bar_share\">共有</string>\n    <string name=\"action_bar_buy\">購入</string>\n    <string name=\"welcome_activity_create_new_wallet\">新しいウォレット</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">ウォレットの復元</string>\n    <string name=\"welcome_activity_sync_with_desktop\">デスクトップとリンク</string>\n    <string name=\"recover_from_phrase_intro\">復元するには、復元フレーズを入力してください</string>\n    <string name=\"show_recovery_phrase_EULA\">Muntアプリを使用すれば、Muntの管理と保管に関するすべての責任を携帯できることをおわかりいただけます。</string>\n    <string name=\"recovery_phrase_continue\">続ける</string>\n    <string name=\"show_recovery_phrase_introtext\">以下は秘密の復元フレーズです。メモを取り、安全な場所に保管してください。フレーズをなくした場合、Muntが失われます。誰かがこのフレーズを使用してアクセスした場合、Muntが失われます。</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">メモを取りました</string>\n    <string name=\"recovery_phrase_copy\">復元フレーズがクリップボードにコピーされました</string>\n    <string name=\"peer_list_fragment_empty\">接続済みのピアはありません</string>\n    <string name=\"block_row_now\">たった今</string>\n    <string name=\"action_browse\">ブラウズ</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ja/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">JPY</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">복사</string>\n    <string name=\"action_bar_share\">공유</string>\n    <string name=\"action_bar_buy\">구매</string>\n    <string name=\"welcome_activity_create_new_wallet\">새 지갑</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">지갑 복구</string>\n    <string name=\"welcome_activity_sync_with_desktop\">데스크톱과 링크</string>\n    <string name=\"recover_from_phrase_intro\">복구를 위해 복구 문장을 입력하세요.</string>\n    <string name=\"show_recovery_phrase_EULA\">Munt 앱을 사용하면 Munt의 관리 및 저장에 대한 모든 책임이 귀하에게 있다는 사실에 명시적으로, 그리고 무조건 동의하는 것으로 간주합니다.</string>\n    <string name=\"recovery_phrase_continue\">계속</string>\n    <string name=\"show_recovery_phrase_introtext\">다음은 귀하의 비밀 복구 문장입니다. 이를 적어 안전하게 보관하세요.\n이 문장을 분실하면 Munt도 잃게 됩니다. 이 문장에 다른 사람이 액세스 해도 Munt을 잃게 됩니다.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">적었습니다.</string>\n    <string name=\"recovery_phrase_copy\">클립보드에 복구 문장이 복사되었습니다.</string>\n    <string name=\"peer_list_fragment_empty\">피어(Peer)에 연결되지 않은 상태입니다.</string>\n    <string name=\"block_row_now\">바로 지금</string>\n    <string name=\"action_browse\">블럭체인 탐색</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ko/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">KRW</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Verstuur</string>\n    <string name=\"title_receive\">Ontvang</string>\n    <string name=\"title_transactions\">Transacties</string>\n    <string name=\"title_settings\">Instellingen</string>\n    <string name=\"title_activity_barcode_capture\">Scan QR-code</string>\n    <string name=\"title_activity_transaction_info\">Transactie-info</string>\n    <string name=\"action_bar_copy\">Kopieer</string>\n    <string name=\"action_bar_copy_long\">Kopieer naar klembord</string>\n    <string name=\"action_bar_share\">Deel</string>\n    <string name=\"action_bar_buy\">Koop</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nieuwe portemonnee</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Herstel portemonnee</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Koppel met desktop</string>\n    <string name=\"recover_from_phrase_intro\">Vul je herstelzin in</string>\n    <string name=\"show_recovery_phrase_EULA\">Wanneer je de Munt-app gebruikt ga je er uitdrukkelijk en onvoorwaardelijk mee akkoord dat alleen jij verantwoordelijk bent voor het beheren en bewaren van je Munt.</string>\n    <string name=\"recovery_phrase_continue\">Verder</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Voer herstelzin in</string>\n    <string name=\"show_recovery_phrase_introtext\">Dit is je herstelzin, bewaar deze op een veilige plek. Zin kwijtraken = Munt weg. Iemand toegang tot je zin = Munt weg.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Ik heb het opgeschreven</string>\n    <string name=\"recovery_phrase_copy\">Herstelzin gekopieerd naar klembord</string>\n    <string name=\"address_book_empty_message\">Om een adres toe te voegen, start een betaling en tap op \\\"Aan adresboek toevoegen\\\"</string>\n    <string name=\"address_book_title\">Adresboek</string>\n    <string name=\"transaction_list_empty_title\">Geen transacties ontvangen</string>\n    <string name=\"transaction_list_empty_message\">Tik hier om je eerste Munt te kopen</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nnaar %2$s</string>\n    <string name=\"peer_list_fragment_empty\">Geen connecties</string>\n    <string name=\"block_row_now\">alleen nu</string>\n    <string name=\"action_browse\">Bladeren</string>\n    <string name=\"background_sync_off\">Uit</string>\n    <string name=\"background_sync_daily\">Dagelijks</string>\n    <string name=\"background_sync_always\">Altijd</string>\n    <string name=\"transaction_id\">Transactie-ID</string>\n    <string name=\"status\">Status</string>\n    <string name=\"amount_label\">Bedrag</string>\n    <string name=\"from_label\">Van</string>\n    <string name=\"to_label\">Naar</string>\n    <string name=\"tx_status_abandoned\">Verlaten</string>\n    <string name=\"tx_status_conflicted\">Conflicterend</string>\n    <string name=\"tx_status_confirming\">Bevestigen %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Onbevestigd</string>\n    <string name=\"tx_status_confirmed\">Bevestigd in blok #%d om %s</string>\n    <string name=\"tx_status_unknown\">Onbekend (je hebt een bug gevonden)</string>\n    <string name=\"no_tx_details\">Geen transactiedetails voor [%s]</string>\n    <string name=\"no_qrsync_warning_title\">Onjuiste QR-code</string>\n    <string name=\"no_qrsync_warning\">Deze QR-code bevat geen geldige Munt sync code, probeer het opnieuw met een geldige code.</string>\n    <string name=\"failed_qrsync_warning_title\">Koppelen niet geslaagd</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Een deel van je saldo wacht nog op bevestiging. Wacht tot deze volledig bevestigd zijn voordat je nogmaals probeert te koppelen.</string>\n    <string name=\"qrsync_info_title\">Koppelen met desktop portemonnee</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">\"Je staat op het punt om te koppelen met je desktop portemonnee. De huidige adressen in deze portemonnee worden verwijderd en zijn niet meer beschikbaar na het koppelen. Het huidige saldo in deze portemonnee wordt naar de desktop portemonnee verplaatst voor het koppelen, en zal tijdelijk niet beschikbaar zijn in deze portemonnee totdat het koppelen afgerond is. Zorg ervoor dat je een een kopie van je oude herstelzin goed bewaard, voor het geval je in de toekomst toegang wilt hebben tot deze oude adressen. \"</string>\n    <string name=\"qrsync_info_message_empty_wallet\">\"Je staat op het punt om te koppelen met je desktop portemonnee. De huidige adressen in deze portemonnee worden verwijderd en zijn niet meer beschikbaar na het koppelen. Zorg ervoor dat je een een kopie van je oude herstelzin goed bewaard, voor het geval je in de toekomst toegang wilt hebben tot deze oude adressen. \"</string>\n    <string name=\"preference_fragment_title\">Voorkeuren</string>\n    <string name=\"preference_fragment_recovery_label\">Herstelzin</string>\n    <string name=\"preference_fragment_link_label\">Portemonnee koppelen</string>\n    <string name=\"preference_fragment_pass_code_label\">Wijzig toegangscode</string>\n    <string name=\"preference_fragment_rescan_label\">Scan portemonnee opnieuw</string>\n    <string name=\"preference_fragment_remove_label\">Verwijder portemonnee</string>\n    <string name=\"preference_fragment_fiat_label\">Lokale valuta</string>\n    <string name=\"preference_fragment_notification_label\">Notificaties</string>\n    <string name=\"preference_fragment_background_sync_label\">Synchronisatie op achtergrond</string>\n    <string name=\"send_coins_label_add_to_address_book\">Voeg toe aan adresboek</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Verwijder uit adresboek</string>\n    <string name=\"send_fragment_scan_label\">Scan QR</string>\n    <string name=\"send_fragment_clipboard_label\">Klembord</string>\n    <string name=\"chain_status_label_probable_height\">Waarschijnlijke hoogte</string>\n    <string name=\"chain_status_label_partial_height\">Gedeeltelijke chain hoogte</string>\n    <string name=\"chain_status_label_processed_height\">Verwerkte hoogte</string>\n    <string name=\"chain_status_label_chain_offset\">Gedeeltelijke chain offset</string>\n    <string name=\"chain_status_label_chain_length\">Gedeeltelijke chain lengte</string>\n    <string name=\"chain_status_label_pruned_height\">Gesnoeid tot hoogte</string>\n    <string name=\"title_peers\">Peers</string>\n    <string name=\"title_blocks\">Blokken</string>\n    <string name=\"title_processing\">Verwerken</string>\n    <string name=\"rescan_confirm_msg\">Het herscannen van de blockchain kan enige tijd duren. Weet je het zeker?</string>\n    <string name=\"rescan_confirm_title\">Herscan?</string>\n    <string name=\"rescan_confirm_btn\">Herscan</string>\n    <string name=\"cancel_btn\">Annuleren</string>\n    <string name=\"rescan_started\">Herscan gestart</string>\n    <string name=\"upgrade_wrong_password\">Onjuist wachtwoord?</string>\n    <string name=\"upgrade_explanation\">Munt moet worden geüpdatet. Dit kan enkele minuten duren, maar Munt zal daar sneller, makkelijker en lichter door werken.</string>\n    <string name=\"upgrade_btn\">Bijwerken</string>\n    <string name=\"upgrade_enter_password\">Voer je wachtwoord in</string>\n    <string name=\"upgrade_enter_password_hint\">PIN</string>\n    <string name=\"upgrade_start_fresh\">Niet bijwerken, verse start maken</string>\n    <string name=\"upgrade_start_fresh_desription\">Als je je herstelzin niet hebt van je oude wallet, zul je deze permanent kwijt zij als je een verse start maakt. Weet je het zeker?</string>\n    <string name=\"upgrade_start_fresh_title\">Vers starten?</string>\n    <string name=\"notify_received\">Bedrag ontvangen</string>\n    <string name=\"notify_sent\">Bedrag verstuurd</string>\n    <string name=\"unlock\">Openen</string>\n    <string name=\"access_code_entry_title\">Toegangscode voor \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_upgrade_title\">Kies je nieuwe \\\"Munt\\\"-toegangscode</string>\n    <string name=\"access_code_choose_title\">Kies je \\\"Munt\\\"-toegangscode</string>\n    <string name=\"access_code_choose_verify\">Verifiëer je toegangscode</string>\n    <string name=\"access_code_choose_hint\">6 cijferige PIN</string>\n    <string name=\"show_recovery_msg\">Toon je herstelzin aan NIEMAND, of ze kunnen met je Munt aan de haal gaan!</string>\n    <string name=\"send_coins_error_acknowledge\">OK</string>\n    <string name=\"authentication_blocked_title\">Portemonnee uitgeschakeld</string>\n    <string name=\"authentication_blocked_msg_recovery\">Probeer nogmaals %s of kies een nieuwe toegangscode met behulp van je herstelzin.</string>\n    <string name=\"authentication_blocked_msg\">Probeer nogmaals %s.</string>\n    <string name=\"authentication_blocked_later_btn\">Probeer later</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Kies nieuwe code</string>\n    <string name=\"access_code_recovery_incorrect\">Onjuiste herstelzin.</string>\n    <string name=\"preference_linked_recovery_descr\">Bekijk je herstelzin in de desktop app.</string>\n    <string name=\"remove_wallet_auth_title\">Portemonnee verwijderen</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">Als je de herstelzin van je portemonnee niet hebt bewaard, verlies je deze voorgoed als je deze nu verwijderd, ook voor toekomstig ontvangen bedragen op de oude adresssen.</string>\n    <string name=\"remove_wallet_auth_desc\">\"Voer je toegangscode in om door te gaan en je portemonnee te verwijderen. \"</string>\n    <string name=\"change_passcode_auth_title\">Wijzig code</string>\n    <string name=\"change_passcode_auth_desc\">Voer je oude toegangscode in om een nieuwe code in te kunnen stellen.</string>\n    <string name=\"wallet_birth_heading\">Hoe oud is deze portemonnee?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Jonger dan een maand.</string>\n    <string name=\"wallet_birth_less_than_a_year\">Jonger dan een jaar.</string>\n    <string name=\"wallet_birth_unsure\">Ouder / ik weet het niet zeker.</string>\n    <string name=\"link_wallet_auth_desc\">Voer je toegangscode in om door te gaan en je portemonnee te koppelen.</string>\n    <string name=\"numeric_keypad_send_button\">Verstuur</string>\n    <string name=\"preferences_support_button\">Support</string>\n    <string name=\"preferences_advanced_button\">Geavanceerd</string>\n    <string name=\"clipboard_no_valid_address\">Geen geldig Munt-adres op het klembord</string>\n    <string name=\"transaction_confirmation_text_conflicted\">Conflicterend</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Verlaten</string>\n    <string name=\"transaction_confirmation_text_pending\">In behandeling</string>\n    <string name=\"receive_fragment_share_title\">Deel Munt-adres</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d bevestiging</item>\n        <item quantity=\"other\">%d bevestigingen</item>\n    </plurals>\n    <string name=\"preferences_license_button\">Licensie</string>\n    <string name=\"license_title\">Licensie</string>\n    <string name=\"tx_detail_wallet_address\">Adres portemonnee</string>\n    <string name=\"tx_detail_sending_address\">Verzendadres</string>\n    <string name=\"tx_detail_payment_address\">Betaaladres</string>\n    <string name=\"tx_detail_network_fee\">Munt-netwerkkosten</string>\n    <string name=\"iban_account_holder_name\">Naam</string>\n    <string name=\"tx_detail_address_unavailable\">niet beschikbaar</string>\n    <string name=\"notification_transaction_channel_name\">Transacties</string>\n    <string name=\"notification_transaction_channel_description\">Transactie notificatie</string>\n    <string name=\"notification_service_channel_name\">Service</string>\n    <string name=\"notification_service_channel_description\">Service om data te synchroniseren en transacties te signaleren terwijl de app afgesloten is, kan aan/uit gezet worden in de instellingen van de app.</string>\n    <string name=\"dialog_title_add_address\">Adres toevoegen</string>\n    <string name=\"hint_iban_or_coin_address\">Munt adres</string>\n    <string name=\"toast_warn_uri_attempt_before_wallet_creation\">Je moet een Munt-portemonnee instellen voordat je deze URI kunt gebruiken</string>\n    <string name=\"preference_fragment_link_summary\">Koppel je mobiele portemonnee aan je desktop portemonnee</string>\n    <string name=\"preference_fragment_remove_summary\">Verwijder deze portemonnee om een nieuwe te starten of te herstellen</string>\n    <string name=\"preference_fragment_unlink_label\">Ontkoppel portemonnee</string>\n    <string name=\"preference_fragment_unlink_summary\">Ontkoppel deze portemonnee om een nieuwe te starten of te herstellen</string>\n    <string name=\"title_wallet_settings\">Instellingen portemonnee</string>\n    <string name=\"title_select_currency\">Selecteer valuta</string>\n    <string name=\"label_sync_progress_connecting\">Verbinden…</string>\n    <string name=\"label_sync_progress_syncing\">Synchroniseren %.1f%%</string>\n    <string name=\"preference_fragment_hide_balance\">Verberg saldo</string>\n    <string name=\"show_balance_when_synced\">Saldo pas beschikbaar na volledige synchronisatie</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-nl/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-no/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Kopier</string>\n    <string name=\"action_bar_share\">Del</string>\n    <string name=\"action_bar_buy\">Kjøp</string>\n    <string name=\"welcome_activity_create_new_wallet\">Ny lommebok</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Gjenopprett lommebok</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Koble med datamaskinen</string>\n    <string name=\"recover_from_phrase_intro\">Skriv inn gjenopprettelsesetningen som skal brukes til gjenopprettelse</string>\n    <string name=\"show_recovery_phrase_EULA\">Ved å bruke Munt-appen gir du ditt uforbeholdne samtykke til at du tar ditt fulle ansvar for å administrere og oppbevare dine Munt.</string>\n    <string name=\"recovery_phrase_continue\">Fortsett</string>\n    <string name=\"show_recovery_phrase_introtext\">Nedenfor er din hemmelige gjenopprettelsesetning, skriv den ned og hold den sikker. Tapt setning = tapte Munt. Andre som har tilgang til setningen = tapte Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Jeg skrev den ned</string>\n    <string name=\"recovery_phrase_copy\">Gjenopprettelsesetning kopiert til utklippstavlen</string>\n    <string name=\"peer_list_fragment_empty\">Ingen peers tilkoblet</string>\n    <string name=\"block_row_now\">akkurat nå</string>\n    <string name=\"action_browse\">Se gjennom</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-no/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"title_send\">Wyślij</string>\n    <string name=\"title_receive\">Otrzymać</string>\n    <string name=\"title_transactions\">Transakcje</string>\n    <string name=\"title_settings\">Ustawienia</string>\n    <string name=\"title_activity_barcode_capture\">Skanuj kod QR</string>\n    <string name=\"title_activity_transaction_info\">Informacje o transakcji</string>\n    <string name=\"action_bar_copy\">Kopiuj</string>\n    <string name=\"action_bar_copy_long\">Skopiuj do schowka</string>\n    <string name=\"action_bar_share\">Udostępnij</string>\n    <string name=\"action_bar_buy\">Zakup</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nowy portfel</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Odzyskaj portfel</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Łącze z portfelem</string>\n    <string name=\"recover_from_phrase_intro\">Wprowadź hasło passphrase, z którego chcesz odzyskać</string>\n    <string name=\"show_recovery_phrase_EULA\">Korzystając z aplikacji Munt, akceptujesz i bezwarunkowo zgadzasz się, że ponosisz wszelką odpowiedzialność za zarządzanie i przechowywanie swojego Munt.</string>\n    <string name=\"recovery_phrase_continue\">Kontynuj</string>\n    <string name=\"title_activity_enter_recovery_phrase\">Wprowadź hasło passphrase</string>\n    <string name=\"show_recovery_phrase_introtext\">Poniżej jest sekretne hasło passphrase (kopia zapasowa), zapisz to i zachowaj w bezpiecznym miejscu. Jeśli stracisz hasło passphrase = Stracisz Munt. Ktoś niepowołany z dostępem do hasła passphrase = stracisz Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Zapisałem to w bezpiecznym miejscu</string>\n    <string name=\"recovery_phrase_copy\">Hasło passphrase zostało skopiowane do schowka</string>\n    <string name=\"address_book_empty_message\">Aby dodać adres, rozpocznij płatność i dotknij \\\"Dodaj do książki adresowej\\\".</string>\n    <string name=\"address_book_title\">Książka adresowa</string>\n    <string name=\"transaction_list_empty_title\">Brak otrzymanych transakcji</string>\n    <string name=\"transaction_list_empty_message\">Dotknij tutaj, aby kupić swój pierwszy Munt</string>\n    <string name=\"send_coins_confirm_template\">%1$s MUNT\\n\\nto %2$s</string>\n    <string name=\"peer_list_fragment_empty\">Brak połączonych partnerów</string>\n    <string name=\"block_row_now\">tylko teraz</string>\n    <string name=\"action_browse\">Przeglądaj</string>\n    <string name=\"background_sync_off\">Poza</string>\n    <string name=\"background_sync_daily\">Codziennie</string>\n    <string name=\"background_sync_always\">Zawsze</string>\n    <string name=\"transaction_id\">Identyfikator transakcji</string>\n    <string name=\"status\">Status</string>\n    <string name=\"amount_label\">Kwota</string>\n    <string name=\"from_label\">Od</string>\n    <string name=\"to_label\">Do</string>\n    <string name=\"tx_status_abandoned\">Opuszczony</string>\n    <string name=\"tx_status_conflicted\">Konflikt</string>\n    <string name=\"tx_status_confirming\">Potwierdzam %s/%s</string>\n    <string name=\"tx_status_unconfirmed\">Nie potwierdzone</string>\n    <string name=\"tx_status_confirmed\">Potwierdzono w bloku #%d w %s</string>\n    <string name=\"tx_status_unknown\">Nieznany (znalazłeś błąd)</string>\n    <string name=\"no_tx_details\">Brak szczegółów transakcji dla  [%s]</string>\n    <string name=\"no_qrsync_warning_title\">Nieprawidłowy kod QR</string>\n    <string name=\"no_qrsync_warning\">Ten kod QR nie zawiera prawidłowego kodu synchronizacji Munt. Spróbuj ponownie, podając poprawny kod.</string>\n    <string name=\"failed_qrsync_warning_title\">Nie można wykonać linku</string>\n    <string name=\"failed_qrsync_unconfirmed_funds_message\">Niektóre środki oczekują na potwierdzenie, proszę pozwolić im w pełni potwierdzić przed ponowną próbą połączenia.</string>\n    <string name=\"qrsync_info_title\">Łącze z portfelem komputera</string>\n    <string name=\"qrsync_info_message_non_empty_wallet\">Zamierzasz nawiązać połączenie z portfelem stacjonarnym. Bieżące adresy w tym portfelu zostaną usunięte i przestaną być dostępne po nawiązaniu połączenia. Obecne środki w tym portfelu zostaną przeniesione do portfela na komputery przed ustanowieniem połączenia i będą tymczasowo niedostępne z tego portfela, dopóki połączenie nie zostanie zakończone. Upewnij się, że zachowałeś kopię hasła phrase  na wypadek gdybyś kiedykolwiek musiał ponownie uzyskać dostęp do tych adresów.</string>\n    <string name=\"qrsync_info_message_empty_wallet\">Zamierzasz nawiązać połączenie z portfelem stacjonarnym. Bieżące adresy w tym portfelu zostaną usunięte i przestaną być dostępne po nawiązaniu połączenia. Upewnij się, że zachowałeś kopię hasła phrase na wypadek, gdybyś kiedykolwiek musiał ponownie uzyskać dostęp do tych adresów.</string>\n    <string name=\"preference_fragment_title\">Preferencje</string>\n    <string name=\"preference_fragment_recovery_label\">Kopia zapasowa hasła phrase</string>\n    <string name=\"preference_fragment_link_label\">Łącze z portfelem</string>\n    <string name=\"preference_fragment_pass_code_label\">Zmień hasło</string>\n    <string name=\"preference_fragment_rescan_label\">Ponownie skanuj portfel</string>\n    <string name=\"preference_fragment_remove_label\">Usuń portfel</string>\n    <string name=\"preference_fragment_fiat_label\">Lokalna waluta</string>\n    <string name=\"preference_fragment_notification_label\">Powiadomienia</string>\n    <string name=\"preference_fragment_background_sync_label\">Synchronizacja w tle</string>\n    <string name=\"send_coins_label_add_to_address_book\">Dodaj do książki adresowej</string>\n    <string name=\"send_coins_label_remove_from_address_book\">Usuń z książki adresowej</string>\n    <string name=\"send_fragment_scan_label\">Skanuj QR</string>\n    <string name=\"send_fragment_clipboard_label\">Schowek</string>\n    <string name=\"chain_status_label_probable_height\">Prawdopodobna wysokość</string>\n    <string name=\"chain_status_label_partial_height\">Częściowa wysokość łańcucha</string>\n    <string name=\"chain_status_label_processed_height\">Przetworzona wysokość</string>\n    <string name=\"chain_status_label_chain_offset\">Częściowe przesunięcie łańcucha</string>\n    <string name=\"chain_status_label_chain_length\">Częściowa długość łańcucha</string>\n    <string name=\"chain_status_label_pruned_height\">Przycięty poniżej wysokości</string>\n    <string name=\"title_peers\">Połączenia</string>\n    <string name=\"title_blocks\">Bloki</string>\n    <string name=\"title_processing\">Przetwarzanie</string>\n    <string name=\"rescan_confirm_msg\">Ponowne skanowanie łańcucha bloków może zająć dużo czasu. Jesteś pewny?</string>\n    <string name=\"rescan_confirm_title\">Ponownie skanuj?</string>\n    <string name=\"rescan_confirm_btn\">Ponownie skanuj</string>\n    <string name=\"cancel_btn\">Anuluj</string>\n    <string name=\"rescan_started\">Rozpoczęto skanowanie</string>\n    <string name=\"upgrade_wrong_password\">Niewłaściwe hasło?</string>\n    <string name=\"upgrade_explanation\">Munt wymaga aktualizacji. Może to zająć kilka minut, Munt będzie szybszy, łatwiejszy w użyciu i w rezultacie bardziej lekki.</string>\n    <string name=\"upgrade_btn\">Aktualizacja</string>\n    <string name=\"upgrade_enter_password\">Wprowadź hasło</string>\n    <string name=\"upgrade_enter_password_hint\">PIN</string>\n    <string name=\"upgrade_start_fresh\">Nie aktualizuj, zacznij od nowa</string>\n    <string name=\"upgrade_start_fresh_desription\">Jeśli nie masz hasła phrase starego portfela, stracisz go na zawsze, jeśli zaczniesz od nowa. Jesteś pewny?</string>\n    <string name=\"upgrade_start_fresh_title\">Świeży start?</string>\n    <string name=\"notify_received\">Otrzymane fundusze</string>\n    <string name=\"notify_sent\">Wysłane fundusze</string>\n    <string name=\"unlock\">Odblokować</string>\n    <string name=\"access_code_entry_title\">Kod dostępu do \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_upgrade_title\">Wybierz swój nowy kod dostępu \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_title\">Wybierz swój kod dostępu \\\"Munt\\\"</string>\n    <string name=\"access_code_choose_verify\">Zweryfikuj swój kod dostępu</string>\n    <string name=\"access_code_choose_hint\">6-cyfrowy PIN</string>\n    <string name=\"show_recovery_msg\">Nie pokazuj nikomu swojego hasła phrase, oni będą mogli wydać swoje Munt.</string>\n    <string name=\"send_coins_error_acknowledge\">dobrze</string>\n    <string name=\"authentication_blocked_title\">Portfel został wyłączony</string>\n    <string name=\"authentication_blocked_msg_recovery\">Spróbuj ponownie %s lub wybierz nowy kod dostępu za pomocą hasła phrase.</string>\n    <string name=\"authentication_blocked_msg\">Spróbuj ponownie %s.</string>\n    <string name=\"authentication_blocked_later_btn\">Spróbuj później</string>\n    <string name=\"authentication_blocked_choose_new_btn\">Wybierz nowy kod</string>\n    <string name=\"access_code_recovery_incorrect\">Niepoprawne hasło phrase</string>\n    <string name=\"preference_linked_recovery_descr\">Wyświetl hasło phrase w aplikacji na komputer.</string>\n    <string name=\"remove_wallet_auth_title\">Usuń portfel</string>\n    <string name=\"remove_wallet_auth_desc_recovery_warn\">Jeśli nie posiadasz hasła phrase ze swojego  portfela, stracisz go na zawsze, jeśli usuniesz go teraz, również w przypadku środków otrzymanych w przyszłości na starych adresach.</string>\n    <string name=\"remove_wallet_auth_desc\">Wprowadź kod dostępu, aby kontynuować i usunąć portfel.</string>\n    <string name=\"change_passcode_auth_title\">Zmień kod</string>\n    <string name=\"change_passcode_auth_desc\">Wprowadź stary kod dostępu, aby kontynuować i zmienić na nowy kod.</string>\n    <string name=\"wallet_birth_heading\">W jakim wieku jest ten portfel?</string>\n    <string name=\"wallet_birth_less_than_a_month\">Mniej niż miesiąc</string>\n    <string name=\"wallet_birth_less_than_a_year\">Mniej niż rok</string>\n    <string name=\"wallet_birth_unsure\">Starszy / nie jestem pewien</string>\n    <string name=\"link_wallet_auth_desc\">Wprowadź kod dostępu, aby kontynuować i połączyć swój portfel.</string>\n    <string name=\"numeric_keypad_send_button\">Wysłać</string>\n    <string name=\"preferences_support_button\">Wsparcie</string>\n    <string name=\"preferences_advanced_button\">Zaawansowane</string>\n    <string name=\"clipboard_no_valid_address\">Brak prawidłowego adresu Munt w schowku</string>\n    <string name=\"transaction_confirmation_text_conflicted\">Konflikt</string>\n    <string name=\"transaction_confirmation_text_abandoned\">Opuszczony</string>\n    <string name=\"transaction_confirmation_text_pending\">W oczekiwaniu</string>\n    <string name=\"receive_fragment_share_title\">Udostępnij adres Munt</string>\n    <plurals name=\"transaction_confirmation_text\">\n        <item quantity=\"one\">%d potwierdzenie</item>\n        <item quantity=\"other\">%d potwierdzenia</item>\n        <item quantity=\"few\">%d potwierdzenia</item>\n        <item quantity=\"many\">%d potwierdzeniń</item>\n    </plurals>\n    <string name=\"preferences_license_button\">Licencja</string>\n    <string name=\"license_title\">Licencja</string>\n    <string name=\"tx_detail_wallet_address\">Adres portfela</string>\n    <string name=\"tx_detail_sending_address\">Adres wysyłania</string>\n    <string name=\"tx_detail_payment_address\">Adres do płatności</string>\n    <string name=\"tx_detail_network_fee\">Opłata za sieć Munt</string>\n    <string name=\"iban_account_holder_name\">Imię</string>\n    <string name=\"tx_detail_address_unavailable\">niedostępne</string>\n    <string name=\"notification_transaction_channel_name\">Transakcje</string>\n    <string name=\"notification_transaction_channel_description\">Powiadomienia o transakcjach</string>\n    <string name=\"notification_service_channel_name\">Usługa</string>\n    <string name=\"notification_service_channel_description\">Usługa umożliwiająca synchronizację danych i monitorowanie transakcji po zamknięciu aplikacji, można ją włączyć / wyłączyć z poziomu ustawień aplikacji</string>\n    <string name=\"dialog_title_add_address\">Dodaj adres</string>\n    <string name=\"hint_iban_or_coin_address\">Munt adres</string>\n    <string name=\"toast_warn_uri_attempt_before_wallet_creation\">Przed użyciem tego identyfikatora URI musisz skonfigurować portfel Munt</string>\n    <string name=\"preference_fragment_link_summary\">Połącz swój mobilny portfel z portfelem na komputerze</string>\n    <string name=\"preference_fragment_remove_summary\">Usuń ten portfel, aby uruchomić lub odzyskać inny portfel</string>\n    <string name=\"preference_fragment_unlink_label\">Odłącz portfel</string>\n    <string name=\"preference_fragment_unlink_summary\">Odłącz ten portfel, aby uruchomić lub odzyskać inny portfel</string>\n    <string name=\"title_wallet_settings\">Ustawienia portfela</string>\n    <string name=\"title_select_currency\">Wybierz walutę</string>\n    <string name=\"label_sync_progress_connecting\">Złączony</string>\n    <string name=\"label_sync_progress_syncing\">Synchronizacja %.1f%%</string>\n    <string name=\"preference_fragment_hide_balance\">Ukryj saldo</string>\n    <string name=\"show_balance_when_synced\">Saldo nie jest widoczne. Proszę czekać.</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pl/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copiar</string>\n    <string name=\"action_bar_share\">Partilhar</string>\n    <string name=\"action_bar_buy\">Comprar</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nova carteira</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recuperar carteira</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Partilhar com o desktop</string>\n    <string name=\"recover_from_phrase_intro\">Introduzir a frase de recuperação da qual executar a recuperaçãao</string>\n    <string name=\"show_recovery_phrase_EULA\">Ao utilizar a aplicação Munt está a aceitar explicitamente e incondicionalmente que você é responsável por toda a gestão e armazenamento das suas Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continuar</string>\n    <string name=\"show_recovery_phrase_introtext\">Segue-se a sua frase secreta de recuperação, escreva-a e mantenha-a segura. Perder a frase = perder Munt. Outra pessoa com acesso à frase = perder Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Eu anotei-a</string>\n    <string name=\"recovery_phrase_copy\">Frase de recuperação copiada para área de transferência</string>\n    <string name=\"peer_list_fragment_empty\">Nenhum par conectado</string>\n    <string name=\"block_row_now\">agora</string>\n    <string name=\"action_browse\">Navegar</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pt/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">EUR</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Copiar</string>\n    <string name=\"action_bar_share\">Partilhar</string>\n    <string name=\"action_bar_buy\">Comprar</string>\n    <string name=\"welcome_activity_create_new_wallet\">Nova carteira</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Recuperar carteira</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Partilhar com o desktop</string>\n    <string name=\"recover_from_phrase_intro\">Introduzir a frase de recuperação da qual executar a recuperaçãao</string>\n    <string name=\"show_recovery_phrase_EULA\">Ao utilizar a aplicação Munt está a aceitar explicitamente e incondicionalmente que você é responsável por toda a gestão e armazenamento das suas Munt.</string>\n    <string name=\"recovery_phrase_continue\">Continuar</string>\n    <string name=\"show_recovery_phrase_introtext\">Segue-se a sua frase secreta de recuperação, escreva-a e mantenha-a segura. Perder a frase = perder Munt. Outra pessoa com acesso à frase = perder Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Eu anotei-a</string>\n    <string name=\"recovery_phrase_copy\">Frase de recuperação copiada para área de transferência</string>\n    <string name=\"peer_list_fragment_empty\">Sem pontos conectados</string>\n    <string name=\"block_row_now\">agora</string>\n    <string name=\"action_browse\">Navegar</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-pt-rBR/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">BRL</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"peer_list_fragment_empty\">Нет подключений</string>\n    <string name=\"block_row_now\">сейчас</string>\n    <string name=\"action_browse\">Обзор</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-ru/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">RUB</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-v23/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<resources>\n\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <item name=\"android:statusBarColor\">@color/bg_main</item>\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"colorPrimary\">@color/text_main</item>\n        <item name=\"colorPrimaryDark\">@color/text_main</item>\n        <item name=\"colorAccent\">@color/text_main</item>\n        <item name=\"coordinatorLayoutStyle\">@style/Widget.Support.CoordinatorLayout</item>\n        <item name=\"floatingActionButtonStyle\">@style/Widget.Design.FloatingActionButton</item>\n        <item name=\"actionBarStyle\">@style/MyActionBar</item>\n\n\n        <item name=\"android:actionModeBackground\">@color/bg_main</item>\n        <item name=\"actionModeCloseDrawable\">@color/text_main</item>\n        <item name=\"android:actionModeStyle\">@style/MyActionBar</item>\n        <item name=\"actionModeShareDrawable\">@drawable/ic_fontawesome_share_nodes</item>\n\n        <item name=\"preferenceTheme\">@style/AppTheme.PreferenceThemeOverlay</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">Sao chép</string>\n    <string name=\"action_bar_share\">Chia sẻ</string>\n    <string name=\"action_bar_buy\">Mua</string>\n    <string name=\"welcome_activity_create_new_wallet\">Ví mới</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">Khôi phục ví</string>\n    <string name=\"welcome_activity_sync_with_desktop\">Liên kết với desktop</string>\n    <string name=\"recover_from_phrase_intro\">Nhập từ khóa khôi phục của bạn qua đó để thực hiện khôi phục</string>\n    <string name=\"show_recovery_phrase_EULA\">Bằng cách sử dụng ứng dụng Munt bạn hiểu và đồng ý vô điều kiện rằng mình sẽ chịu hoàn toàn trách nhiệm cho việc quản lý và lưu trữ Munt của mình.</string>\n    <string name=\"recovery_phrase_continue\">Tiếp tục</string>\n    <string name=\"show_recovery_phrase_introtext\">Dưới đây là từ khóa khôi phục bí mật của bạn, hãy ghi lại và lưu giữ ở nơi an toàn. Mất từ khóa = mất Guildens. Một ai đó khác có quyền truy cập vào từ khóa = mất Munt.</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">Tôi đã ghi nó lại</string>\n    <string name=\"recovery_phrase_copy\">Từ khóa khôi phục được sao chép vào bộ nhớ đệm</string>\n    <string name=\"peer_list_fragment_empty\">Không có mạng ngang hàng nào kết nối</string>\n    <string name=\"block_row_now\">ngay bây giờ</string>\n    <string name=\"action_browse\">Duyệt</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-vi/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">CNY</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">复制</string>\n    <string name=\"action_bar_share\">分享</string>\n    <string name=\"action_bar_buy\">购买</string>\n    <string name=\"welcome_activity_create_new_wallet\">新钱包</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">恢复钱包</string>\n    <string name=\"welcome_activity_sync_with_desktop\">与桌面关联</string>\n    <string name=\"recover_from_phrase_intro\">输入用于执行恢复的恢复短语</string>\n    <string name=\"show_recovery_phrase_EULA\">使用Munt应用即表示您明确且无条件地同意：您对Munt的管理和存储承担全部责任。</string>\n    <string name=\"recovery_phrase_continue\">继续</string>\n    <string name=\"show_recovery_phrase_introtext\">以下是您的机密恢复短语，请记下来并妥善保管。丢失短语意味着丢失Munt。他人可以访问短语也意味着丢失Munt。</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">我记下来了</string>\n    <string name=\"recovery_phrase_copy\">回复短语已复制到剪贴板</string>\n    <string name=\"peer_list_fragment_empty\">没有已连接的peer</string>\n    <string name=\"block_row_now\">刚刚</string>\n    <string name=\"action_browse\">浏览</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-zh-rCN/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">CNY</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!--\nCopyright (c) 2018-2022 The Centure developers\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n    <!-- All translatable items, that we want translators to actually translate directly, should go in this file !-->\n    <!-- If a resource should not be translated, or should be dealt with specially place it in values.xml instead !-->\n    <!-- Never place string-array items here, those should always go in values.xml !-->\n<resources>\n    <string name=\"action_bar_copy\">複製</string>\n    <string name=\"action_bar_share\">分享</string>\n    <string name=\"action_bar_buy\">購買</string>\n    <string name=\"welcome_activity_create_new_wallet\">新錢包</string>\n    <string name=\"welcome_activity_recover_existing_wallet\">復原錢包</string>\n    <string name=\"welcome_activity_sync_with_desktop\">與桌面電腦連接</string>\n    <string name=\"recover_from_phrase_intro\">輸入你的回復碼以回復錢包</string>\n    <string name=\"show_recovery_phrase_EULA\">當你使用 Munt 時，你明白並同意你將負上所有管理及儲存 Munt 的責任。</string>\n    <string name=\"recovery_phrase_continue\">繼續</string>\n    <string name=\"show_recovery_phrase_introtext\">以下是你的秘密回復碼，請將它寫下及妥善保管。遺失回復碼就遺失了 Munt。讓其他人得知了回復碼也等於遺失了 Munt。</string>\n    <string name=\"recovery_phrase_acknowledge_writing_down\">我已記下了它</string>\n    <string name=\"recovery_phrase_copy\">已經把回復碼複製到剪貼簿</string>\n    <string name=\"peer_list_fragment_empty\">沒有節點連線</string>\n    <string name=\"block_row_now\">剛剛</string>\n    <string name=\"action_browse\">瀏覽</string>\n</resources>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/values-zh-rTW/values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"default_currency_code\">CNY</string>\n</resources>\n\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/xml/fragment_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:title=\"@string/preference_fragment_title\"\n    tools:context=\".main_activity_fragments.SettingsFragment\">\n\n    <Preference\n        android:key=\"preference_show_wallet_settings\"\n        android:persistent=\"false\"\n        android:summary=\"Backup, recovery and linking\"\n        android:title=\"Wallet\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_local_currency\"\n        android:summary=\"\"\n        app:iconSpaceReserved=\"false\"\n        android:defaultValue=\"@string/default_currency_code\"\n        android:title=\"@string/preference_fragment_fiat_label\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <ListPreference\n        android:key=\"preference_background_sync\"\n        app:iconSpaceReserved=\"false\"\n        android:title=\"@string/preference_fragment_background_sync_label\"\n        android:summary=\"%s\"\n        android:entries=\"@array/background_sync_entries\"\n        android:entryValues=\"@array/background_sync_values\"\n        android:defaultValue=\"@string/background_sync_default\" />\n\n    <SwitchPreference\n        android:key=\"preference_notify_transaction_activity\"\n        app:iconSpaceReserved=\"false\"\n        android:persistent=\"true\"\n        android:defaultValue=\"true\"\n        android:summary=\"\"\n        android:title=\"@string/preference_fragment_notification_label\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <SwitchPreference\n        android:key=\"preference_hide_balance\"\n        app:iconSpaceReserved=\"false\"\n        android:persistent=\"true\"\n        android:defaultValue=\"true\"\n        android:summary=\"\"\n        android:title=\"@string/preference_fragment_hide_balance\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_about_app\"\n        app:iconSpaceReserved=\"false\"\n        android:persistent=\"false\"\n        android:summary=\"\"\n        android:layout=\"@layout/pref_about_app\"\n        tools:ignore=\"UnusedAttribute\" />\n\n\n\n</PreferenceScreen>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/main/res/xml/fragment_wallet_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright (c) 2018-2022 The Centure developers\nAuthored by: Malcolm MacLeod (mmacleod@gmx.com)\nDistributed under the GNU Lesser General Public License v3, see the accompanying\nfile COPYING\n!-->\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:title=\"Wallet\"\n    tools:context=\".main_activity_fragments.SettingsFragment\">\n    <Preference\n        android:key=\"recovery_view_preference\"\n        android:layout=\"@layout/pref_view_recovery\"\n        android:persistent=\"false\"\n        android:summary=\"\"\n        android:title=\"@string/preference_fragment_recovery_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"recovery_linked_preference\"\n        android:persistent=\"false\"\n        android:summary=\"@string/preference_linked_recovery_descr\"\n        android:title=\"@string/preference_fragment_recovery_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_link_wallet\"\n        android:persistent=\"false\"\n        android:summary=\"@string/preference_fragment_link_summary\"\n        android:title=\"@string/preference_fragment_link_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_change_pass_code\"\n        android:persistent=\"false\"\n        android:summary=\"\"\n        android:title=\"@string/preference_fragment_pass_code_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_rescan_wallet\"\n        android:persistent=\"false\"\n        android:summary=\"\"\n        android:title=\"@string/preference_fragment_rescan_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_remove_wallet\"\n        android:persistent=\"false\"\n        android:summary=\"@string/preference_fragment_remove_summary\"\n        android:title=\"@string/preference_fragment_remove_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n\n    <Preference\n        android:key=\"preference_unlink_wallet\"\n        android:persistent=\"false\"\n        android:summary=\"@string/preference_fragment_unlink_summary\"\n        android:title=\"@string/preference_fragment_unlink_label\"\n        app:iconSpaceReserved=\"false\"\n        tools:ignore=\"UnusedAttribute\" />\n</PreferenceScreen>\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/app/src/test/java/unity_wallet/ExampleUnitTest.kt",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com), Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\npackage unity_wallet\n\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest\n{\n    @Test fun addition_isCorrect()\n    {\n        assertEquals(4, 2 + 2)\n    }\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.5.31'\n    repositories {\n        google()\n        mavenCentral()\n        maven {\n            url 'https://jitpack.io'\n        }\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.2.2'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10\"\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n    configurations.all {\n        resolutionStrategy {\n        }\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n        maven {\n            url 'https://jitpack.io'\n        }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Jul 01 00:30:02 SAST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.3.3-all.zip\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\nandroid.enableJetifier=true\nandroid.useAndroidX=true\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "src/frontend/android/unity_wallet/settings.gradle",
    "content": "include ':app'\n"
  },
  {
    "path": "src/frontend/electron_sample/.gitignore",
    "content": "wallet\nnode_modules\n*.node\npackage-lock.json\n"
  },
  {
    "path": "src/frontend/electron_sample/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Munt electron sample</title>\n  </head>\n  <body>\n    <h1>Munt electron sample</h1>\n\n    Node.js: <script>document.write(process.versions.node)</script>,\n    Chromium: <script>document.write(process.versions.chrome)</script>,\n    Electron: <script>document.write(process.versions.electron)</script>\n\n    <p>sync progress: <span id=\"sync_progress\"></span></p>\n    <p>balance: <span id=\"balance\"></span></p>\n    <p>address: <span id=\"address\"></span></p>\n    <p>last log message: <span id=\"lastlog\"></span></p>\n    <script>\n    require('electron').ipcRenderer.on('notifyCoreReady', (event) => {\n        document.getElementById(\"address\").innerHTML = require('electron').remote.getGlobal(\"corebackend\").GetReceiveAddress()\n    })\n    require('electron').ipcRenderer.on('logPrint', (event, message) => {\n        document.getElementById(\"lastlog\").innerHTML = message\n    })\n    require('electron').ipcRenderer.on('notifyUnifiedProgress', (event, progress) => {\n        document.getElementById(\"sync_progress\").innerHTML = progress + \"%\"\n    })\n    require('electron').ipcRenderer.on('notifyBalanceChange', (event, new_balance) => {\n        if (new_balance > 0)\n        {\n            document.getElementById(\"balance\").innerHTML = new_balance / 100000000\n        }\n        else\n        {\n            document.getElementById(\"balance\").innerHTML = 0\n        }\n    })\n    require('electron').ipcRenderer.on('notifyNewMutation', (event, mutation, self_committed) => {\n        //empty\n    })\n    require('electron').ipcRenderer.on('notifyUpdatedTransaction', (event, transaction) => {\n        //empty\n    })\n    require('electron').ipcRenderer.on('notifyInitWithExistingWallet', (event) => {\n        //empty\n    })\n    require('electron').ipcRenderer.on('notifyInitWithoutExistingWallet', (event) => {\n        //empty\n    })\n    require('electron').ipcRenderer.on('notifyShutdown', (event) => {\n        //empty\n    })\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "src/frontend/electron_sample/main.js",
    "content": "// Modules to control application life and create native browser window\nconst {app, BrowserWindow} = require('electron')\n\n// Keep global references of all these objects\nlet libcore\nlet corebackend\nlet signalhandler\n\nlet coreIsRunning=false\nlet allowExit=false\nlet terminateCore=false\n\n// Keep a global reference of the window object, if you don't, the window will\n// be closed automatically when the JavaScript object is garbage collected.\nlet mainWindow\n\nfunction createWindow () {\n  // Create the browser window.\n  mainWindow = new BrowserWindow({\n    width: 800,\n    height: 600,\n    webPreferences: {\n      nodeIntegration: true\n    }\n  })\n\n  // and load the index.html of the app.\n  mainWindow.loadFile('index.html')\n\n  // Open the DevTools.\n   mainWindow.webContents.openDevTools()\n\n  // Emitted when the window is closed.\n  mainWindow.on('closed', function () {\n    // Dereference the window object, usually you would store windows\n    // in an array if your app supports multi windows, this is the time\n    // when you should delete the corresponding element.\n    mainWindow = null\n  })\n\n  mainWindow.on('close', (e) => {\n      if (coreIsRunning)\n      {\n          console.log(\"terminate core from mainWindow close\")\n          e.preventDefault();\n          corebackend.TerminateUnityLib()\n      }\n      else if (!allowExit)\n      {\n          console.log(\"set core to terminate from mainWindow close\")\n          terminateCore=true\n          e.preventDefault();\n      }\n      else\n      {\n         console.log(\"allow app to exit, from mainwindow close\")\n      }\n  })\n\n  unitySetup();\n}\n\nfunction unitySetup() {\n    var basepath = app.getAppPath();\n\n    global.libcore = libcore = require('./lib_unity')\n    global.corebackend = corebackend = new libcore.NJSILibraryController\n    signalhandler = global.signalhandler = new libcore.NJSILibraryListener();\n\n    // Receive signals from the core and marshall them as needed to the main window\n    signalhandler.notifyCoreReady = function() {\n        coreIsRunning=true\n        console.log(\"received: notifyCoreReady\")\n        mainWindow.webContents.send('notifyCoreReady')\n        if (terminateCore)\n        {\n            console.log(\"terminate core immediately after init\")\n            terminateCore=false\n            corebackend.TerminateUnityLib()\n        }\n    }\n    signalhandler.logPrint  = function(message) {\n        console.log(\"unity_core: \" + message)\n        mainWindow.webContents.send('logPrint', message)\n    }\n    signalhandler.notifyUnifiedProgress  = function (progress) {\n        console.log(\"received: notifyUnifiedProgress\")\n        mainWindow.webContents.send('notifyUnifiedProgress', progress)\n    }\n    signalhandler.notifyBalanceChange = function (new_balance) {\n        console.log(\"received: notifyBalanceChange\")\n        mainWindow.webContents.send('notifyBalanceChange', new_balance)\n    }\n    signalhandler.notifyNewMutation  = function (mutation, self_committed) {\n        console.log(\"received: notifyNewMutation\")\n        mainWindow.webContents.send('notifyNewMutation', mutation, self_committed)\n    }\n    signalhandler.notifyUpdatedTransaction  = function (transaction) {\n        console.log(\"received: notifyUpdatedTransaction\")\n        mainWindow.webContents.send('notifyUpdatedTransaction', transaction)\n    }\n    signalhandler.notifyInitWithExistingWallet = function () {\n        console.log(\"received: notifyInitWithExistingWallet\")\n        mainWindow.webContents.send('notifyInitWithExistingWallet')\n    }\n    signalhandler.notifyInitWithoutExistingWallet = function () {\n        console.log(\"received: notifyInitWithoutExistingWallet\")\n        mainWindow.webContents.send('notifyInitWithoutExistingWallet')\n        corebackend.InitWalletFromRecoveryPhrase(corebackend.GenerateRecoveryMnemonic().phrase_with_birth_number ,\"password\")\n    }\n    signalhandler.notifyShutdown = function () {\n\n        console.log(\"call app.quit from notifyShutdown\")\n        allowExit=true\n        coreIsRunning=false\n        app.quit()\n    }\n\n    // Start the unified backend\n    corebackend.InitUnityLibThreaded(basepath+\"/\"+\"wallet\", \"\", -1, -1, false, true, signalhandler, \"\")\n}\n\n// This method will be called when Electron has finished\n// initialization and is ready to create browser windows.\n// Some APIs can only be used after this event occurs.\napp.on('ready', createWindow)\n\n// Quit when all windows are closed.\napp.on('window-all-closed', function () {\n  // On macOS it is common for applications and their menu bar\n  // to stay active until the user quits explicitly with Cmd + Q\n  if (process.platform !== 'darwin')\n  {\n      if (coreIsRunning)\n      {\n            console.log(\"terminate core from window-all-closed\")\n          corebackend.TerminateUnityLib()\n      }\n      else\n      {\n          console.log(\"set core to terminate after init window-all-closed\")\n          terminateCore=true\n      }\n  }\n})\n\napp.on('activate', function () {\n  // On macOS it's common to re-create a window in the app when the\n  // dock icon is clicked and there are no other windows open.\n  if (mainWindow === null) createWindow()\n})\n\n"
  },
  {
    "path": "src/frontend/electron_sample/package.json",
    "content": "{\n  \"name\": \"electron-sample\",\n  \"version\": \"3.0.7\",\n  \"description\": \"A minimal Electron application using unified backend\",\n  \"author\": \"Malcolm MacLeod\",\n  \"license\": \"GNU Lesser General Public License v3\",\n  \"main\": \"main.js\",\n  \"homepage\": \"https://www.Munt.org\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/muntorg/munt-official\"\n  },\n  \"scripts\": {\n    \"start\": \"electron .\"\n  },\n  \"devDependencies\": {\n    \"electron\": \"^22.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/frontend/electron_sample/renderer.js",
    "content": "// This file is required by the index.html file and will\n// be executed in the renderer process for that window.\n// All of the Node.js APIs are available in this process.\n"
  },
  {
    "path": "src/frontend/electron_sample/run.sh",
    "content": "#! /bin/bash\nset -e\nset -x\n\nif test -f \"../../../build_node/src/.libs/lib_unity_node_js-0.dll\"; then\n    cp ../../../build_node/src/.libs/lib_unity_node_js-0.dll lib_unity.node\nelif test -f \"../../../build_node/src/.libs/lib_unity_node_js.so\"; then\n    cp ../../../build_node/src/.libs/lib_unity_node_js.so lib_unity.node\nfi\n\nnpm install\nmkdir wallet | true\nnpm start\n"
  },
  {
    "path": "src/frontend/electron_vue/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n#Electron-builder output\n/dist_electron\n\n# Exclude libunity .node file\n/src/unity/*.node\n\n# Confidential Credentials\nholdinAPI.js\n\nyarn.lock\n"
  },
  {
    "path": "src/frontend/electron_vue/README.md",
    "content": "# Munt Electron Wallet\n\n## Project setup\n```\nyarn\n```\n\n### Copy os specific unity lib to src/unity folder\n```\nyarn libunity:copy\n```\n\n### Compiles and hot-reloads for development\n```\nyarn electron:serve\n```\n\n### Compiles and minifies for production\n```\nyarn electron:build\n```\n\n### Lints and fixes files\n```\nyarn lint\n```\n"
  },
  {
    "path": "src/frontend/electron_vue/babel.config.js",
    "content": "module.exports = {\n  presets: [\"@vue/cli-plugin-babel/preset\"],\n  plugins: []\n};\n"
  },
  {
    "path": "src/frontend/electron_vue/holdinAPI.js.in",
    "content": "const apiKey = null;\n\nexport { apiKey };\n"
  },
  {
    "path": "src/frontend/electron_vue/libunity/copy.js",
    "content": "var os = require(\"os\");\n\nlet repo =\n  \"https://github.com/muntorg/munt-official/releases/download/development/\";\n\nlet file = \"\";\nif (os.platform() === \"win32\") {\n  file = \"libmunt_win_\" + os.arch() + \".node\";\n} else if (os.platform() === \"linux\") {\n  file = \"libmunt_linux_\" + os.arch() + \".node\";\n} else if (os.platform() === \"darwin\") {\n    file = \"libmunt_macos_\" + os.arch() + \".node\";\n} else {\n  throw \"Unable to determine platform\";\n}\n\nconst fs = require(\"fs\");\nconst request = require(\"request\");\nlet error;\nconst download = (uri, filename) => {\n  request(uri)\n    .on(\"error\", err => {\n      error = err;\n    })\n    .on(\"response\", response => {\n      if (response.statusCode !== 200) {\n        error = `error downloading ${uri} : ${response.statusCode}`;\n      } else {\n        console.log(`downloading ${uri}...`);\n      }\n    })\n    .pipe(fs.createWriteStream(filename))\n    .on(\"close\", () => {\n      if (error !== undefined) console.error(error);\n      else console.log(`fetched ${src} -> ${dst}`);\n    });\n};\n\nconst path = require(\"path\");\nlet src = repo + file;\nlet dst = path.join(__dirname, `../src/unity/lib_unity.node`);\ndownload(src, dst);\n"
  },
  {
    "path": "src/frontend/electron_vue/libunity/generate.js",
    "content": "var fs = require(\"fs\");\nvar path = require(\"path\");\n\nlet inputFile = path.join(__dirname, \"../../../unity/djinni/node_js/unifiedbackend_doc.js\");\n\nlet controllerFile = path.join(__dirname, \"/../src/unity/Controllers.js\");\nlet libUnityFile = path.join(__dirname, \"/../src/unity/LibUnity.js\");\n\nlet fileToParse = fs.readFileSync(inputFile, \"utf8\");\nlet dataToParse = fileToParse.split(\"\\n\");\n\nlet controllers = [\n  {\n    className: \"NJSILibraryController\",\n    exclude: [\n      \"InitUnityLib\",\n      \"InitUnityLibThreaded\",\n      \"ContinueWalletFromRecoveryPhrase\",\n      \"InitWalletLinkedFromURI\",\n      \"ContinueWalletLinkedFromURI\",\n      \"InitWalletFromAndroidLegacyProtoWallet\",\n      \"isValidAndroidLegacyProtoWallet\",\n      \"PersistAndPruneForSPV\",\n      \"getMutationHistory\",\n      \"getTransactionHistory\",\n      \"HaveUnconfirmedFunds\",\n      \"GetBalance\"\n    ]\n  },\n  {\n    className: \"NJSIWalletController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIRpcController\",\n    exclude: [\"execute\"],\n    custom: [\n      {\n        name: \"Execute\",\n        args: [\"command\"]\n      }\n    ]\n  },\n  {\n    className: \"NJSIP2pNetworkController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIAccountsController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIWitnessController\"\n  },\n  {\n    className: \"NJSIGenerationController\",\n    exclude: [\"setListener\"]\n  }\n];\n\nfor (let i = 0; i < controllers.length; i++) {\n  getFunctionsFor(controllers[i]);\n}\n\nfunction getFunctionsFor(controller) {\n  controller.functions = [];\n  let exclude = controller.exclude || [];\n\n  let startFound = false;\n  let endFound = false;\n\n  let i = 0;\n  while (endFound === false) {\n    let line = dataToParse[i++].trim();\n    if (startFound === false) {\n      if (line.indexOf(`declare class ${controller.className}`) !== -1) {\n        startFound = true;\n      }\n      continue;\n    } else if (line === \"}\") {\n      endFound = true;\n      continue;\n    }\n\n    line = line.replace(\"\\r\\n\", \"\");\n    if (line.startsWith(\"static declare function\") === false) continue;\n    line = line.replace(\"static declare function\", \"\").trim();\n\n    let openingBracketIdx = line.indexOf(\"(\");\n    let closingBracketIdx = line.indexOf(\")\");\n    let name = line.substr(0, openingBracketIdx);\n\n    let skip = false;\n    for (let j = 0; j < exclude.length; j++) {\n      if (name.toLowerCase() === exclude[j].toLowerCase()) {\n        skip = true;\n        break;\n      }\n    }\n    if (skip) continue;\n\n    let args = line.substr(openingBracketIdx + 1, closingBracketIdx - openingBracketIdx - 1);\n\n    if (args.length > 0) {\n      let argsSplit = args.split(\", \");\n      let arr = [];\n      argsSplit.forEach(arg => {\n        arr.push(arg.substr(0, arg.indexOf(\":\")));\n      });\n\n      args = arr.join(\", \");\n    }\n\n    controller.functions.push({ name: name, args: args });\n  }\n}\n\nfunction getControllerCode() {\n  let code = [];\n\n  for (let i = 0; i < controllers.length; i++) {\n    let controller = controllers[i];\n    let custom = controller.custom || [];\n\n    code.push(`class ${controller.className.replace(\"NJSI\", \"\")} {`);\n\n    for (let j = 0; j < custom.length; j++) {\n      let f = custom[j];\n      if (j > 0) code.push(``);\n      code.push(`static async ${f.name}Async(${f.args}) {`);\n      code.push(\n        `return handleError(await ipc.callMain(\"${controller.className}.${f.name}Async\"${f.args.length > 0 ? \", {\" + f.args + \"}\" : \"\"})\n        );`\n      );\n      code.push(`}`);\n      code.push(``);\n      code.push(`static ${f.name}(${f.args}) {`);\n      code.push(\n        `return handleError(ipc.sendSync(\"${controller.className}.${f.name}\"${f.args.length > 0 ? \", \" + f.args : \"\"})\n        );`\n      );\n      code.push(`}`);\n    }\n\n    for (let j = 0; j < controller.functions.length; j++) {\n      let f = controller.functions[j];\n      if (j > 0) code.push(``);\n      code.push(`static async ${PascalCase(f.name)}Async(${f.args}) {`);\n      code.push(`return handleError(await ipc.callMain(\"${controller.className}.${f.name}Async\"${f.args.length > 0 ? \", {\" + f.args + \"}\" : \"\"}));`);\n      code.push(`}`);\n      code.push(``);\n      code.push(`static ${PascalCase(f.name)}(${f.args}) {`);\n      code.push(`return handleError(ipc.sendSync(\"${controller.className}.${f.name}\"${f.args.length > 0 ? \", \" + f.args : \"\"}));`);\n      code.push(`}`);\n    }\n\n    code.push(`}`);\n    code.push(``);\n  }\n\n  code.push(`export {`);\n\n  for (let i = 0; i < controllers.length; i++) {\n    code.push(`${controllers[i].className.replace(\"NJSI\", \"\")}${i + 1 < controllers.length ? \",\" : \"\"}`);\n  }\n\n  code.push(`}`);\n  code.push(``);\n\n  return code;\n}\n\nfunction getLibUnityCode() {\n  let code = [];\n\n  for (let i = 0; i < controllers.length; i++) {\n    let controller = controllers[i];\n    let className = controller.className.replace(\"NJSI\", \"\");\n    className = className.charAt(0).toLowerCase() + className.substr(1);\n\n    if (i > 0) code.push(``);\n    code.push(`// Register ${controller.className} ipc handlers`);\n\n    for (let j = 0; j < controller.functions.length; j++) {\n      let f = controller.functions[j];\n      if (j > 0) code.push(``);\n      code.push(`ipc.answerRenderer(\"${controller.className}.${f.name}Async\", async ${f.args.length > 0 ? \"data\" : \"()\"} => {`);\n\n      let args = f.args.length > 0 ? f.args.split(\", \") : [];\n      let consoleArgs = \"\";\n      if (args.length > 0) {\n        for (let k = 0; k < args.length; k++) {\n          consoleArgs += k > 0 ? \", \" : \"\";\n          consoleArgs += \"${data.\" + args[k] + \"}\";\n        }\n      }\n\n      code.push(`\n        console.log(\\`IPC: ${className}.${f.name}Async(${consoleArgs})\\`);\n        try {\n          let result = this.${className}.${f.name}(\n            ${f.args.length > 0 ? \"data.\" + f.args.split(\", \").join(\", data.\") : \"\"}\n          );\n          return {\n            success: true,\n            result: result\n          };\n        }\n        catch(e) {\n          return handleError(e);\n        }\n      `);\n      code.push(`});`);\n      code.push(``);\n      code.push(`ipc.on(\"${controller.className}.${f.name}\", ${f.args.length > 0 ? \"(event, \" + f.args + \")\" : \"event\"} => {`);\n\n      args = f.args.length > 0 ? f.args.split(\", \") : [];\n      consoleArgs = \"\";\n      if (args.length > 0) {\n        for (let k = 0; k < args.length; k++) {\n          consoleArgs += k > 0 ? \", \" : \"\";\n          consoleArgs += \"${\" + args[k] + \"}\";\n        }\n      }\n\n      code.push(`\n        console.log(\\`IPC: ${className}.${f.name}(${consoleArgs})\\`);\n        try {\n          let result = this.${className}.${f.name}(${f.args});\n          event.returnValue = {\n            success: true,\n            result: result\n          };\n        }\n        catch(e) {\n          event.returnValue = handleError(e);\n        }\n      `);\n      code.push(`});`);\n    }\n  }\n\n  code.push(``);\n  return code;\n}\n\nlet controllerData = fs.readFileSync(controllerFile, \"utf-8\");\n\nlet replace = \"\";\nreplace += \"/* inject:generated-code */\\r\\n\";\nreplace += getControllerCode().join(\"\\r\\n\");\nreplace += \"/* inject:generated-code */\";\n\nlet result = controllerData.replace(/\\/\\* inject:generated-code \\*\\/(.)+\\/\\* inject:generated-code \\*\\//s, replace);\nfs.writeFileSync(controllerFile, result, \"utf-8\");\n\nlet libUnityData = fs.readFileSync(libUnityFile, \"utf-8\");\nreplace = \"\";\nreplace += \"/* inject:generated-code */\\r\\n\";\nreplace += getLibUnityCode().join(\"\\r\\n\");\nreplace += \"/* inject:generated-code */\";\n\nresult = libUnityData.replace(/\\/\\* inject:generated-code \\*\\/(.)+\\/\\* inject:generated-code \\*\\//s, replace);\nfs.writeFileSync(libUnityFile, result, \"utf-8\");\n\nfunction PascalCase(line) {\n  return line.charAt(0).toUpperCase() + line.substr(1);\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/notarize.js",
    "content": "\"use strict\";\n\nconst path = require(\"path\");\nconst { notarize } = require(\"electron-notarize\");\n\nconst getAuthInfo = () => {\n  const { APPLE_ID: appleId, APPLE_ID_PASSWORD: appleIdPassword, APP_ID: appId } = process.env;\n\n  if (!appleId || !appleIdPassword) {\n    throw new Error(\"One of APPLE_ID and APPLE_ID_PASSWORD environment variables is missing for notarization.\");\n  }\n  if (!appId) {\n    throw new Error(\"Unable to determine appID\");\n  }\n\n  return {\n    appleId,\n    appleIdPassword\n  };\n};\n\nmodule.exports = async params => {\n  if (params.electronPlatformName !== \"darwin\") {\n    return;\n  }\n\n  // Read and validate auth information from environment variables\n  let authInfo;\n  try {\n    authInfo = getAuthInfo();\n  } catch (error) {\n    console.log(`Skipping notarization: ${error.message}`);\n    return;\n  }\n\n  let appId = authInfo.appId;\n  const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);\n\n  const notarizeOptions = { appBundleId: appId, appPath };\n  notarizeOptions.appleId = authInfo.appleId;\n  notarizeOptions.appleIdPassword = authInfo.appleIdPassword;\n\n  console.log(`Notarizing ${appId} found at ${appPath}`);\n  await notarize(notarizeOptions);\n  console.log(`Done notarizing ${appId}`);\n};\n"
  },
  {
    "path": "src/frontend/electron_vue/package.json",
    "content": "{\n  \"name\": \"Munt\",\n  \"description\": \"Munt currency\",\n  \"author\": \"Centure.com BV\",\n  \"version\": \"3.0.7\",\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"node ./setup.js && vue-cli-service lint\",\n    \"electron:build\": \"node ./setup.js && vue-cli-service electron:build\",\n    \"electron:serve\": \"node ./setup.js && vue-cli-service electron:serve\",\n    \"electron:generate-icons\": \"electron-icon-builder --input=./public/icon.png --output=build --flatten\",\n    \"i18n:report\": \"vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'\",\n    \"postinstall\": \"electron-builder install-app-deps\",\n    \"postuninstall\": \"electron-builder install-app-deps\",\n    \"libunity:copy\": \"node ./libunity/copy.js\",\n    \"libunity:generate\": \"node ./libunity/generate.js && yarn lint\"\n  },\n  \"main\": \"background.js\",\n  \"dependencies\": {\n    \"@fortawesome/fontawesome-pro\": \"^6.4.0\",\n    \"@fortawesome/fontawesome-svg-core\": \"^6.1.0\",\n    \"@fortawesome/pro-light-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/pro-regular-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/vue-fontawesome\": \"^2.0.2\",\n    \"@json2csv/plainjs\": \"^7.0.1\",\n    \"axios\": \"^1.3.4\",\n    \"core-js\": \"^3.31.1\",\n    \"electron-better-ipc\": \"^2.0.1\",\n    \"electron-store\": \"^8.1.0\",\n    \"lodash.clonedeep\": \"^4.5.0\",\n    \"portal-vue\": \"^2.1.7\",\n    \"qrcode\": \"^1.5.1\",\n    \"vue\": \"^2.6.12\",\n    \"vue-i18n\": \"^8.24.2\",\n    \"vue-js-toggle-button\": \"^1.3.3\",\n    \"vue-qrcode\": \"^0.3.5\",\n    \"vue-router\": \"^3.5.1\",\n    \"vue-slider-component\": \"^3.2.11\",\n    \"vuex\": \"^3.6.2\",\n    \"vuex-electron\": \"https://github.com/devlz303/vuex-electron.git#v1.0.4\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.12.16\",\n    \"@babel/eslint-parser\": \"^7.12.16\",\n    \"@oshell/vue-cli-plugin-electron-builder-notarize\": \"^1.0.2\",\n    \"@vue/cli-plugin-babel\": \"~5.0.8\",\n    \"@vue/cli-plugin-eslint\": \"~5.0.8\",\n    \"@vue/cli-plugin-router\": \"~5.0.8\",\n    \"@vue/cli-plugin-vuex\": \"~5.0.8\",\n    \"@vue/cli-service\": \"~5.0.8\",\n    \"@vue/eslint-config-prettier\": \"^6.0.0\",\n    \"babel-plugin-import\": \"^1.13.3\",\n    \"electron\": \"^25.3.0\",\n    \"electron-builder\": \"^24.4.0\",\n    \"electron-icon-builder\": \"^2.0.1\",\n    \"eslint\": \"^8.45.0\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"eslint-plugin-vue\": \"^8.0.3\",\n    \"less\": \"^4.1.1\",\n    \"less-loader\": \"^11.1.3\",\n    \"native-ext-loader\": \"^2.3.0\",\n    \"prettier\": \"^2.4.1\",\n    \"vue-cli-plugin-ant-design\": \"~1.0.1\",\n    \"vue-cli-plugin-electron-builder\": \"~2.1.1\",\n    \"vue-cli-plugin-i18n\": \"~2.3.1\",\n    \"vue-template-compiler\": \"^2.6.12\",\n    \"webpack\": \"^5.88.1\"\n  },\n  \"resolutions\": {\n    \"**/@achrinza/node-ipc\": \"^10.1.9\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"env\": {\n      \"node\": true\n    },\n    \"extends\": [\n      \"plugin:vue/essential\",\n      \"eslint:recommended\",\n      \"@vue/prettier\"\n    ],\n    \"parserOptions\": {\n      \"parser\": \"@babel/eslint-parser\"\n    },\n    \"rules\": {\n      \"no-unused-vars\": [\n        \"warn\",\n        {\n          \"argsIgnorePattern\": \"^_\",\n          \"varsIgnorePattern\": \"^_\"\n        }\n      ],\n      \"vue/multi-word-component-names\": [\n        \"error\",\n        {\n          \"ignores\": [\n            \"Send\",\n            \"Receive\",\n            \"Transactions\",\n            \"Account\",\n            \"index\",\n            \"Setup\"\n          ]\n        }\n      ],\n      \"comma-dangle\": \"off\",\n      \"wrap-iife\": \"off\",\n      \"arrow-parens\": \"off\",\n      \"linebreak-style\": \"off\"\n    }\n  },\n  \"prettier\": {\n    \"printWidth\": 160,\n    \"trailingComma\": \"none\",\n    \"arrowParens\": \"avoid\",\n    \"singleAttributePerLine\": false\n  },\n  \"browserslist\": [\n    \"Electron >= 17.1.0\"\n  ]\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "src/frontend/electron_vue/setup.js",
    "content": "const fs = require(\"fs\");\nconst path = require(\"path\");\nlet src = path.join(__dirname, `holdinAPI.js.in`);\nlet dst = path.join(__dirname, `holdinAPI.js`);\nfs.copyFile(src, dst, fs.constants.COPYFILE_EXCL, err => {\n  console.warn(err);\n});\n"
  },
  {
    "path": "src/frontend/electron_vue/sign.js",
    "content": "exports.default = async function (configuration) {\n  const CERTIFICATE_PATH = process.env.CERTIFICATE_PATH;\n  const CERTIFICATE_KEY = process.env.CERTIFICATE_KEY;\n  const CERTIFICATE_NAME = process.env.CERTIFICATE_NAME;\n  const CERTIFICATE_URL = process.env.CERTIFICATE_URL;\n  const CERTIFICATE_PASS = process.env.CERTIFICATE_PASS;\n  require(\"child_process\").execSync(\n    `osslsigncode-2.0/osslsigncode -pass \"${CERTIFICATE_PASS}\" -spc \"${CERTIFICATE_PATH}\" -key \"${CERTIFICATE_KEY}\" -n \"${CERTIFICATE_NAME}\" -i \"${CERTIFICATE_URL}\" -in \"${configuration.path}\" -out \"${configuration.path}2\" && mv \"${configuration.path}2\" \"${configuration.path}\"`,\n    {\n      stdio: \"inherit\"\n    }\n  );\n};\n"
  },
  {
    "path": "src/frontend/electron_vue/src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <app-wallet v-if=\"isWallet\" />\n    <router-view v-else />\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppWallet from \"./AppWallet\";\n\nexport default {\n  name: \"App\",\n  components: {\n    AppWallet\n  },\n  created() {\n    this.changeLanguage(this.language);\n    document.querySelector(\"html\").dataset.theme = this.theme;\n  },\n  watch: {\n    language() {\n      this.changeLanguage(this.language);\n    },\n    theme() {\n      document.querySelector(\"html\").dataset.theme = this.theme;\n    }\n  },\n  computed: {\n    ...mapState(\"app\", [\"language\", \"theme\"]),\n    isWallet() {\n      switch (window.location.hash.toLowerCase()) {\n        case \"#/debug\":\n          return false;\n        case \"#/about\":\n          return false;\n        default:\n          return true;\n      }\n    }\n  },\n  methods: {\n    changeLanguage(language) {\n      if (this.$i18n.locale === language) return;\n      this.$i18n.locale = language;\n      this.$forceUpdate();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\">\n@import \"./css/app.less\";\n\n*,\n#app {\n  font-family: euclid, Helvetica, sans-serif;\n  font-style: normal;\n  font-weight: 400;\n  font-size: 15px;\n  -webkit-text-size-adjust: none;\n  text-rendering: optimizeLegibility;\n  font-variant-ligatures: none;\n  -webkit-font-smoothing: antialiased;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/AppStatus.js",
    "content": "const AppStatus = {\n  start: \"start\",\n  setup: \"setup\",\n  synchronize: \"synchronize\",\n  ready: \"ready\",\n  shutdown: \"shutdown\"\n};\n\nexport default AppStatus;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/AppWallet.vue",
    "content": "<template>\n  <div class=\"app-wallet\">\n    <app-loader />\n    <modal-dialog v-model=\"modal\" />\n    <unlock-wallet-dialog />\n    <activity-indicator v-if=\"activityIndicator\" />\n    <component :is=\"layout\">\n      <router-view />\n    </component>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppStatus from \"./AppStatus\";\nimport AppLoader from \"./components/AppLoader\";\nimport ModalDialog from \"./components/ModalDialog\";\nimport EventBus from \"./EventBus.js\";\nimport ActivityIndicator from \"./components/ActivityIndicator.vue\";\nimport UnlockWalletDialog from \"./components/UnlockWalletDialog\";\n\nimport SetupLayout from \"./layouts/SetupLayout\";\nimport WalletLayout from \"./layouts/WalletLayout\";\n\nexport default {\n  name: \"AppWallet\",\n  data() {\n    return {\n      modal: null\n    };\n  },\n  components: {\n    AppLoader,\n    ModalDialog,\n    SetupLayout,\n    WalletLayout,\n    ActivityIndicator,\n    UnlockWalletDialog\n  },\n  created() {\n    this.onStatusChanged();\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.closeModal);\n    EventBus.$on(\"show-dialog\", this.showModal);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"close-dialog\", this.closeModal);\n    EventBus.$off(\"show-dialog\", this.showModal);\n  },\n  computed: {\n    ...mapState(\"app\", [\"status\", \"activityIndicator\"]),\n    layout() {\n      return this.$route.meta.layout || WalletLayout;\n    }\n  },\n  watch: {\n    status() {\n      this.onStatusChanged();\n    }\n  },\n  methods: {\n    onStatusChanged() {\n      let routeName;\n      switch (this.status) {\n        case AppStatus.setup:\n          routeName = \"setup\";\n          break;\n        case AppStatus.synchronize:\n          routeName = \"account\";\n          break;\n        case AppStatus.ready:\n          routeName = \"account\";\n          break;\n      }\n      if (routeName === undefined || this.$route.name === routeName) return;\n      this.$router.push({ name: routeName });\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    showModal(modal) {\n      this.modal = modal;\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/EventBus.js",
    "content": "import Vue from \"vue\";\nexport default new Vue();\n"
  },
  {
    "path": "src/frontend/electron_vue/src/background.js",
    "content": "\"use strict\";\n/* global __static */\n\nimport { app, protocol, Menu, BrowserWindow, shell } from \"electron\";\nimport {\n  createProtocol\n  /* installVueDevtools */\n} from \"vue-cli-plugin-electron-builder/lib\";\n\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\nconst os = require(\"os\");\n\nimport path from \"path\";\nimport fs from \"fs\";\n\nimport LibUnity from \"./unity/LibUnity\";\nimport walletPath from \"./walletPath\";\n\nimport store from \"./store\";\nimport AppStatus from \"./AppStatus\";\nimport axios from \"axios\";\n\n// Keep a global reference of the window object, if you don't, the window will\n// be closed automatically when the JavaScript object is garbage collected.\nlet winMain;\nlet winDebug;\nlet winAbout;\nlet libUnity = new LibUnity({ walletPath });\n\n// Handle URI links (munt: munt://)\n// If we are launching a second instance then terminate and let the first instance handle it instead\n//NB! This must happen before all other app related code (especially libulden init) as otherwise second process can crash\nconst gotTheLock = app.requestSingleInstanceLock();\nif (!gotTheLock) {\n  app.quit();\n} else {\n  app.on(\"second-instance\", (_event, _commandLine, _workingDirectory) => {\n    focusMainWindow();\n  });\n  // Protocol handler for osx\n  app.on(\"open-url\", (event, _url) => {\n    event.preventDefault();\n    focusMainWindow();\n  });\n}\nif (process.defaultApp) {\n  if (process.argv.length >= 2) {\n    app.setAsDefaultProtocolClient(\"munt\", process.execPath, [path.resolve(process.argv[1])]);\n  }\n} else {\n  app.setAsDefaultProtocolClient(\"munt\");\n}\n// End of URI handling\n\n/* TODO: refactor into function and add option to libmunt to remove existing wallet folder */\nif (isDevelopment) {\n  let args = process.argv.slice(2);\n  for (var i = 0; i < args.length; i++) {\n    switch (args[i].toLowerCase()) {\n      case \"new-wallet\":\n        fs.rmdirSync(walletPath, {\n          recursive: true\n        });\n        break;\n      default:\n        console.error(`unknown argument: ${args[i]}`);\n        break;\n    }\n  }\n}\n\n// Scheme must be registered before the app is ready\nprotocol.registerSchemesAsPrivileged([{ scheme: \"app\", privileges: { secure: true, standard: true } }]);\n\nfunction createMainWindow() {\n  console.log(\"createMainWindow\");\n  let options = {\n    width: 800,\n    minWidth: 800,\n    height: 600,\n    minHeight: 600,\n    show: false,\n    title: \"Munt\",\n    webPreferences: {\n      // Use pluginOptions.nodeIntegration, leave this alone\n      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info\n      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,\n      contextIsolation: false\n    }\n  };\n  if (os.platform() === \"linux\") {\n    options = Object.assign({}, options, {\n      icon: path.join(__static, \"icon.png\")\n    });\n  }\n  winMain = new BrowserWindow(options);\n\n  var menuTemplate = [\n    {\n      label: \"File\",\n      submenu: [{ role: \"quit\" }]\n    },\n    {\n      label: \"Edit\",\n      submenu: [{ role: \"cut\" }, { role: \"copy\" }, { role: \"paste\" }]\n    },\n    {\n      label: \"Help\",\n      submenu: [\n        {\n          label: \"Debug window\",\n          enabled: store.state.app.coreReady,\n          click() {\n            createDebugWindow();\n          }\n        },\n        {\n          label: \"About\",\n          click() {\n            createAboutWindow();\n          }\n        }\n      ]\n    }\n  ];\n\n  if (isDevelopment) {\n    menuTemplate.push({\n      label: \"Development\",\n      submenu: [{ role: \"toggleDevTools\" }]\n    });\n  }\n\n  var menu = Menu.buildFromTemplate(menuTemplate);\n\n  Menu.setApplicationMenu(menu);\n\n  if (process.env.WEBPACK_DEV_SERVER_URL) {\n    // Load the url of the dev server if in development mode\n    winMain.loadURL(process.env.WEBPACK_DEV_SERVER_URL);\n    //if (!process.env.IS_TEST) win.webContents.openDevTools();\n  } else {\n    createProtocol(\"app\");\n    // Load the index.html when not in development\n    winMain.loadURL(\"app://./index.html\");\n  }\n\n  winMain.on(\"ready-to-show\", () => {\n    console.log(\"ready-to-show main window\");\n    libUnity.SetMainWindowReady();\n    winMain.show();\n  });\n\n  winMain.on(\"close\", event => {\n    console.log(\"winMain.on:close\");\n    if (process.platform !== \"darwin\") {\n      EnsureUnityLibTerminated(event);\n    }\n  });\n\n  winMain.on(\"closed\", () => {\n    console.log(\"winMain.on:closed\");\n    winMain = null;\n  });\n\n  // Force external hrefs to open in external browser\n  winMain.webContents.on(\"new-window\", function (e, url) {\n    e.preventDefault();\n    shell.openExternal(url);\n  });\n}\n\nfunction createDebugWindow() {\n  if (winDebug) {\n    return winDebug.show();\n  }\n\n  let options = {\n    width: 600,\n    minWidth: 400,\n    height: 600,\n    minHeight: 400,\n    show: false,\n    parent: winMain,\n    title: \"Munt Debug Window\",\n    skipTaskBar: true,\n    autoHideMenuBar: true,\n    webPreferences: {\n      // Use pluginOptions.nodeIntegration, leave this alone\n      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info\n      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,\n      contextIsolation: false\n    }\n  };\n  if (os.platform() === \"linux\") {\n    options = Object.assign({}, options, {\n      icon: path.join(__static, \"icon.png\")\n    });\n  }\n  winDebug = new BrowserWindow(options);\n\n  let url = process.env.WEBPACK_DEV_SERVER_URL ? `${process.env.WEBPACK_DEV_SERVER_URL}#/debug` : `app://./index.html#/debug`;\n\n  if (process.env.WEBPACK_DEV_SERVER_URL) {\n    // Load the url of the dev server if in development mode\n    winDebug.loadURL(url);\n    //if (!process.env.IS_TEST) win.webContents.openDevTools();\n  } else {\n    createProtocol(\"app\");\n    // Load the index.html when not in development\n    winDebug.loadURL(url);\n  }\n\n  winDebug.on(\"ready-to-show\", () => {\n    winDebug.show();\n  });\n\n  winDebug.on(\"close\", event => {\n    console.log(\"winDebug.on:close\");\n    if (libUnity === null || libUnity.isTerminated) return;\n    event.preventDefault();\n    winDebug.hide();\n  });\n\n  winDebug.on(\"closed\", () => {\n    console.log(\"winDebug.on:closed\");\n    winDebug = null;\n  });\n}\n\nfunction createAboutWindow() {\n  if (winAbout) {\n    return winAbout.show();\n  }\n\n  let options = {\n    width: 600,\n    minWidth: 400,\n    height: 635,\n    minHeight: 400,\n    show: false,\n    parent: winMain,\n    title: \"About Munt\",\n    skipTaskBar: true,\n    autoHideMenuBar: true,\n    webPreferences: {\n      // Use pluginOptions.nodeIntegration, leave this alone\n      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info\n      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,\n      contextIsolation: false\n    }\n  };\n  if (os.platform() === \"linux\") {\n    options = Object.assign({}, options, {\n      icon: path.join(__static, \"icon.png\")\n    });\n  }\n  winAbout = new BrowserWindow(options);\n\n  let url = process.env.WEBPACK_DEV_SERVER_URL ? `${process.env.WEBPACK_DEV_SERVER_URL}#/about` : `app://./index.html#/about`;\n\n  if (process.env.WEBPACK_DEV_SERVER_URL) {\n    // Load the url of the dev server if in development mode\n    winAbout.loadURL(url);\n    //if (!process.env.IS_TEST) win.webContents.openDevTools();\n  } else {\n    createProtocol(\"app\");\n    // Load the index.html when not in development\n    winAbout.loadURL(url);\n  }\n\n  winAbout.on(\"ready-to-show\", () => {\n    winAbout.show();\n  });\n\n  winAbout.on(\"close\", event => {\n    console.log(\"winAbout.on:close\");\n    if (libUnity === null || libUnity.isTerminated) return;\n    event.preventDefault();\n    winAbout.hide();\n  });\n\n  winAbout.on(\"closed\", () => {\n    console.log(\"winAbout.on:closed\");\n    winAbout = null;\n  });\n}\n\napp.on(\"will-quit\", event => {\n  console.log(\"app.on:will-quit\");\n  if (libUnity === null || libUnity.isTerminated) return;\n  store.dispatch(\"app/SET_STATUS\", AppStatus.shutdown);\n  event.preventDefault();\n  libUnity.TerminateUnityLib();\n});\n\n// Quit when all windows are closed.\napp.on(\"window-all-closed\", event => {\n  console.log(\"app.on:window-all-closed\");\n  // On macOS it is common for applications and their menu bar\n  // to stay active until the user quits explicitly with Cmd + Q\n  if (process.platform !== \"darwin\") {\n    EnsureUnityLibTerminated(event);\n  }\n});\n\napp.on(\"activate\", () => {\n  // On macOS it's common to re-create a window in the app when the\n  // dock icon is clicked and there are no other windows open.\n  if (winMain === null) {\n    createMainWindow();\n  }\n});\n\n// This method will be called when Electron has finished\n// initialization and is ready to create browser windows.\n// Some APIs can only be used after this event occurs.\napp.on(\"ready\", async () => {\n  if (isDevelopment && !process.env.IS_TEST) {\n    // Install Vue Devtools\n    // Devtools extensions are broken in Electron 6.0.0 and greater\n    // See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info\n    // Electron will not launch with Devtools extensions installed on Windows 10 with dark mode\n    // If you are not using Windows 10 dark mode, you may uncomment these lines\n    // In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines\n    // try {\n    //   await installVueDevtools()\n    // } catch (e) {\n    //   console.error('Vue Devtools failed to install:', e.toString())\n    // }\n  }\n\n  store.dispatch(\"app/SET_WALLET_VERSION\", app.getVersion());\n  libUnity.Initialize();\n\n  updateRate(60);\n\n  createMainWindow();\n});\n\nasync function updateRate(seconds) {\n  try {\n    // use blockhut api instead of https://api.munt.org/api/v1/ticker\n    //const response = await axios.get(\"https://blockhut.com/munt/munteuro.json\");\n    const response = await axios.get(\"https://munt.chainviewer.org/api/v1/ticker\");\n    const currentRate = response.data.data.find(item => item.code.toLowerCase() === store.state.app.currency.value.toLowerCase());\n\n    store.dispatch(\"app/SET_RATE\", currentRate.rate);\n    store.dispatch(\"app/SET_CURRENCIES\", response.data.data);\n  } catch (error) {\n    console.error(error);\n  } finally {\n    setTimeout(() => {\n      updateRate(seconds);\n    }, seconds * 1000);\n  }\n}\n\nfunction EnsureUnityLibTerminated(event) {\n  if (libUnity === null || libUnity.isTerminated) return;\n  store.dispatch(\"app/SET_STATUS\", AppStatus.shutdown);\n  event.preventDefault();\n  libUnity.TerminateUnityLib();\n}\n\n// Exit cleanly on request from parent process in development mode.\nif (isDevelopment) {\n  if (process.platform === \"win32\") {\n    process.on(\"message\", data => {\n      if (data === \"graceful-exit\") {\n        app.quit();\n      }\n    });\n  } else {\n    process.on(\"SIGTERM\", () => {\n      app.quit();\n    });\n  }\n}\n\nfunction focusMainWindow() {\n  if (winMain) {\n    if (winMain.isMinimized()) winMain.restore();\n    else winMain.show();\n    winMain.focus();\n  }\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/AccountHeader.vue",
    "content": "<template>\n  <div>\n    <confirm-dialog v-model=\"modal\" />\n    <div class=\"account-header\">\n      <div v-if=\"!editMode\" class=\"flex-row\">\n        <div v-if=\"isSingleAccount\" class=\"flex-row flex-1\">\n          <div class=\"logo\" />\n          <div class=\"balance-row flex-1\">\n            <span>{{ balanceForDisplay }}</span>\n            <span>{{ totalBalanceFiat }}</span>\n          </div>\n        </div>\n        <div v-else class=\"left-colum\">\n          <div>\n            <account-tooltip type=\"Account\" :account=\"account\">\n              <div style=\"display: flex; flex-direction: row\">\n                <div style=\"width: calc(100% - 45px)\" @click=\"editName\" class=\"flex-row flex-1\">\n                  <div class=\"accountname ellipsis\">{{ name }}</div>\n                  <fa-icon class=\"pen\" :icon=\"['fal', 'fa-pen']\" />\n                </div>\n                <div style=\"width: 40px; text-align: center\" @click=\"deleteAccount\" class=\"trash flex-row\">\n                  <fa-icon :icon=\"['fal', 'fa-trash']\" />\n                </div>\n              </div>\n              <div class=\"balance-row\">\n                <span>{{ balanceForDisplay }}</span>\n                <span>{{ totalBalanceFiat }}</span>\n              </div>\n            </account-tooltip>\n          </div>\n        </div>\n        <div v-if=\"showBuySellButtons\">\n          <button outlined class=\"small\" @click=\"buyCoins\" :disabled=\"buyDisabled\">{{ $t(\"buttons.buy\") }}</button>\n          <button outlined class=\"small\" @click=\"sellCoins\" :disabled=\"sellDisabled\">{{ $t(\"buttons.sell\") }}</button>\n        </div>\n        <div v-if=\"!showBuySellButtons && showHoldinButtons\">\n          <div v-if=\"!isLinkedToHoldin\">\n            <button outlined class=\"small\" @click=\"linkToHoldin('add')\" :disabled=\"sellDisabled\">\n              {{ $t(\"saving_account.add_to_holdin\") }}\n            </button>\n          </div>\n          <div v-else>\n            <button outlined class=\"small\" @click=\"linkToHoldin('remove')\" :disabled=\"sellDisabled\">\n              {{ $t(\"saving_account.remove_from_holdin\") }}\n            </button>\n          </div>\n        </div>\n        <div v-if=\"isSingleAccount\" class=\"flex-row icon-buttons\">\n          <div class=\"icon-button\">\n            <fa-icon :icon=\"['fal', 'cog']\" @click=\"showSettings\" />\n          </div>\n          <div class=\"icon-button\">\n            <fa-icon :icon=\"['fal', lockIcon]\" @click=\"changeLockSettings\" />\n          </div>\n        </div>\n      </div>\n      <input v-else ref=\"accountNameInput\" type=\"text\" v-model=\"newAccountName\" @keydown=\"onKeydown\" @blur=\"cancelEdit\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { AccountsController, BackendUtilities, WitnessController, GenerationController } from \"../unity/Controllers\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport AccountTooltip from \"./AccountTooltip.vue\";\nimport EventBus from \"../EventBus\";\nimport { apiKey } from \"../../holdinAPI\";\nimport ConfirmDialog from \"./ConfirmDialog.vue\";\n\nexport default {\n  components: { AccountTooltip, ConfirmDialog },\n  name: \"AccountHeader\",\n  data() {\n    return {\n      editMode: false,\n      newAccountName: null,\n      buyDisabled: false,\n      sellDisabled: false,\n      requestLinkToHoldin: false,\n      isLinkedToHoldin: false,\n      keyHash: \"\",\n      modal: null\n    };\n  },\n  props: {\n    account: {\n      type: Object,\n      default: () => {}\n    },\n    isSingleAccount: {\n      type: Boolean,\n      default: false\n    }\n  },\n  computed: {\n    ...mapState(\"app\", [\"rate\", \"currency\"]),\n    ...mapState(\"wallet\", [\"walletPassword\", \"unlocked\"]),\n    name() {\n      return this.account ? this.account.label : null;\n    },\n    totalBalanceFiat() {\n      if (!this.rate) return \"\";\n      return `${this.currency.symbol || \"\"} ${formatMoneyForDisplay(this.account.balance * this.rate, true)}`;\n    },\n    balanceForDisplay() {\n      if (!this.account || this.account.balance === undefined) return \"\";\n      return formatMoneyForDisplay(this.account.balance);\n    },\n    showBuySellButtons() {\n      return !this.account || (this.account.type === \"Desktop\" && !this.editMode);\n    },\n    showHoldinButtons() {\n      return apiKey;\n    },\n    lockIcon() {\n      return this.unlocked ? \"unlock\" : \"lock\";\n    }\n  },\n  watch: {\n    name: {\n      immediate: true,\n      handler() {\n        this.editMode = false;\n      }\n    },\n    unlocked: {\n      immediate: true,\n      handler() {\n        if (this.unlocked && this.requestLinkToHoldin) {\n          // Check if add or remove.\n          if (this.isLinkedToHoldin) {\n            this.holdinAPI(\"remove\");\n          } else {\n            this.holdinAPI(\"add\");\n          }\n        }\n      }\n    },\n    account: {\n      immediate: true,\n      handler() {\n        if (!this.showBuySellButtons) {\n          this.checkForHoldinLink();\n        }\n      }\n    }\n  },\n  mounted() {\n    if (!this.showBuySellButtons) {\n      this.checkForHoldinLink();\n    }\n  },\n  methods: {\n    checkForHoldinLink() {\n      AccountsController.ListAccountLinksAsync(this.account.UUID).then(result => {\n        const findHoldin = result.find(element => element.serviceName == \"holdin\");\n        this.isLinkedToHoldin = findHoldin && findHoldin.serviceName === \"holdin\";\n        if (this.isLinkedToHoldin) {\n          this.keyHash = findHoldin.serviceData;\n        }\n      });\n    },\n    editName() {\n      this.newAccountName = this.name;\n      this.editMode = true;\n      this.$nextTick(() => {\n        this.$refs[\"accountNameInput\"].focus();\n      });\n    },\n    deleteAccount() {\n      this.showConfirmModal();\n    },\n    onKeydown(e) {\n      switch (e.keyCode) {\n        case 13:\n          this.changeAccountName();\n          break;\n        case 27:\n          this.editMode = false;\n          break;\n      }\n    },\n    changeAccountName() {\n      if (this.newAccountName !== this.account.label) {\n        AccountsController.RenameAccount(this.account.UUID, this.newAccountName);\n      }\n      this.editMode = false;\n    },\n    cancelEdit() {\n      this.editMode = false;\n    },\n    dismissIndicator() {\n      setTimeout(() => {\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n      }, 1000);\n    },\n    async sellCoins() {\n      try {\n        this.sellDisabled = true;\n        const url = await BackendUtilities.GetSellSessionUrl();\n        window.open(url, \"sell-coins\");\n      } finally {\n        this.sellDisabled = false;\n      }\n    },\n    async buyCoins() {\n      try {\n        this.buyDisabled = true;\n        const url = await BackendUtilities.GetBuySessionUrl();\n        window.open(url, \"buy-coins\");\n      } finally {\n        this.buyDisabled = false;\n      }\n    },\n    showSettings() {\n      if (this.$route.path === \"/settings/\") return;\n      this.$router.push({ name: \"settings\" });\n    },\n    changeLockSettings() {\n      EventBus.$emit(this.unlocked ? \"lock-wallet\" : \"unlock-wallet\");\n    },\n    linkToHoldin(action) {\n      this.requestLinkToHoldin = true;\n\n      if (!this.unlocked) {\n        EventBus.$emit(\"unlock-wallet\");\n      } else {\n        this.holdinAPI(action);\n      }\n    },\n    async holdinAPI(action) {\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n      AccountsController.GetWitnessKeyURIAsync(this.account.UUID).then(async key => {\n        let result = null;\n\n        if (action === \"add\") {\n          let infoResult = await BackendUtilities.holdinAPIActions(key, \"getinfo\");\n          const keyHashLocal = infoResult.data.keyhash;\n\n          if (infoResult.data.available === 1 && infoResult.data.active === \"1\") {\n            // Account was linked elsewhere. Note that on Gulden and update the compound value.\n            GenerationController.GetGenerationAddressAsync()\n              .then(async payoutAddress => {\n                // Add payout address to Holdin..\n                await BackendUtilities.holdinAPIActions(key, \"payoutaddress\", payoutAddress);\n                this.addAccountLink(this.account.UUID, keyHashLocal, infoResult.data.compound);\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else if (infoResult.data.available === 1 && infoResult.data.active === \"0\") {\n            // Account was linked and then removed. Reactivate.\n            GenerationController.GetGenerationAddressAsync()\n              .then(async payoutAddress => {\n                result = await BackendUtilities.holdinAPIActions(key, \"activate\");\n                if (result.status_code === 200) {\n                  await BackendUtilities.holdinAPIActions(key, \"payoutaddress\", payoutAddress);\n                  this.addAccountLink(this.account.UUID, keyHashLocal);\n                } else {\n                  alert(`Holdin: ${result.status_message}`);\n                }\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else if (infoResult.data.available === 0) {\n            // Add account for the first time.\n            result = await BackendUtilities.holdinAPIActions(key, \"add\");\n            if (result.status_code === 200) {\n              this.addAccountLink(this.account.UUID, keyHashLocal);\n            } else {\n              this.dismissIndicator();\n              alert(`Holdin: ${result.status_message}`);\n            }\n          } else {\n            this.dismissIndicator();\n            alert(\"Holdin: API Error\");\n          }\n        } else {\n          result = await BackendUtilities.holdinAPIActions(key, \"remove\");\n          if (result.status_code === 200) {\n            AccountsController.RemoveAccountLinkAsync(this.account.UUID, \"holdin\")\n              .then(() => {\n                this.isLinkedToHoldin = false;\n                this.requestLinkToHoldin = false;\n                this.dismissIndicator();\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else {\n            alert(`Holdin: ${result.status_message}`);\n          }\n        }\n      });\n    },\n    addAccountLink(accountUID, keyHash, compound) {\n      AccountsController.AddAccountLinkAsync(accountUID, \"holdin\", keyHash)\n        .then(() => {\n          if (compound) {\n            WitnessController.SetAccountCompoundingAsync(accountUID, compound).then(() => {\n              this.dismissIndicator();\n              this.requestLinkToHoldin = false;\n              this.isLinkedToHoldin = true;\n            });\n          } else {\n            this.dismissIndicator();\n            this.requestLinkToHoldin = false;\n            this.isLinkedToHoldin = true;\n          }\n        })\n        .catch(err => {\n          alert(err.message);\n        });\n    },\n    showConfirmModal() {\n      if (\n        this.account.allBalances.availableIncludingLocked === 0 &&\n        this.account.allBalances.unconfirmedIncludingLocked === 0 &&\n        this.account.allBalances.immatureIncludingLocked === 0\n      ) {\n        this.modal = { title: \"Confirm Delete\", message: \"Are you sure you want to delete the account?\", closeModal: this.closeModal, confirm: this.confirm };\n      } else {\n        this.modal = { title: \"Error\", message: \"Your account needs to be empty before you can delete it\", showButtons: false, closeModal: this.closeModal };\n      }\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    confirm() {\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n      this.modal = null;\n      setTimeout(() => {\n        AccountsController.DeleteAccountAsync(this.account.UUID)\n          .then(() => {\n            this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n          })\n          .catch(err => {\n            this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n            alert(err.message);\n          });\n      }, 1000);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.account-header {\n  width: 100%;\n  height: var(--header-height);\n  line-height: var(--header-height);\n\n  & > div {\n    align-items: center;\n    justify-content: center;\n    height: var(--header-height);\n  }\n}\n\n.left-colum {\n  display: flex;\n  flex-direction: column;\n  flex: 1;\n  white-space: nowrap;\n  overflow: hidden;\n  height: 40px;\n  cursor: pointer;\n  position: relative;\n}\n\n.balance-row {\n  line-height: 20px;\n  font-size: 0.9em;\n\n  & :first-child {\n    margin-right: 10px;\n  }\n}\n\nbutton.small {\n  height: 20px !important;\n  line-height: 20px !important;\n  font-size: 10px !important;\n  padding: 0 10px !important;\n  margin-left: 5px;\n}\n\n.accountname {\n  flex: 1;\n  font-size: 1em;\n  font-weight: 500;\n  line-height: 20px;\n  margin-right: 30px;\n}\n\n.pen {\n  display: none;\n  position: absolute;\n  right: 45px;\n  line-height: 20px;\n}\n\n.trash {\n  display: none;\n  position: absolute;\n  right: 5px;\n  line-height: 18px;\n}\n\n.left-colum:hover .trash {\n  display: block;\n  color: #ff0000;\n}\n\n.left-colum:hover .pen {\n  display: block;\n}\n\n.logo {\n  width: 22px;\n  min-width: 22px;\n  height: 22px;\n  min-height: 22px;\n  background: url(\"../img/logo-black.svg\"), linear-gradient(transparent, transparent);\n  background-size: cover;\n  margin-right: 10px;\n}\n\n.icon-buttons {\n  margin-left: 10px;\n}\n\n.icon-button {\n  display: inline-block;\n  padding: 0 13px;\n  line-height: 40px;\n  height: 40px;\n  font-weight: 500;\n  font-size: 1em;\n  color: var(--primary-color);\n  text-align: center;\n  cursor: pointer;\n\n  &:hover {\n    background-color: #f5f5f5;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/AccountTooltip.vue",
    "content": "<template>\n  <div class=\"tooltip\" @mouseleave=\"hideTooltip\">\n    <div @mouseenter=\"showTooltip\">\n      <slot></slot>\n    </div>\n    <div @mouseenter=\"showTooltip\" class=\"tooltip-container\" v-if=\"show\">\n      <div class=\"tooltip-heading\" v-if=\"type == 'Account'\">{{ $t(\"tooltip.account_balance\") }}</div>\n      <div class=\"tooltip-heading\" v-else>{{ $t(\"tooltip.wallet_balance\") }}</div>\n      <div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.total\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.total }}</div>\n        </div>\n        <div v-if=\"account.type === 'Holding' || account.type === 'Witness' || type === 'Wallet'\" class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.locked\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.locked }}</div>\n        </div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.spendable\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.spendable }}</div>\n        </div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.pending\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.pending }}</div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\n\nexport default {\n  name: \"AccountTooltip\",\n  data() {\n    return {\n      show: false,\n      accountObject: {},\n      timeout: undefined\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"totalBalance\", \"lockedBalance\", \"spendableBalance\", \"pendingBalance\", \"immatureBalance\"])\n  },\n  props: {\n    account: {},\n    type: {\n      type: String\n    }\n  },\n  methods: {\n    showTooltip: function () {\n      clearTimeout(this.timeout);\n      this.show = true;\n      this.getValues();\n    },\n    hideTooltip() {\n      clearTimeout(this.timeout);\n      this.timeout = setTimeout(() => {\n        this.show = false;\n      }, 100);\n    },\n    getValues() {\n      if (this.type === \"Account\") {\n        const locked = this.account.allBalances.totalLocked || 0;\n        const spendable = this.account.allBalances.availableExcludingLocked || 0;\n        const pending = this.account.allBalances.unconfirmedExcludingLocked || 0;\n        const immature = this.account.allBalances.immatureExcludingLocked || 0;\n\n        this.accountObject = {\n          locked: formatMoneyForDisplay(locked),\n          spendable: formatMoneyForDisplay(spendable),\n          pending: formatMoneyForDisplay(pending),\n          immature: formatMoneyForDisplay(immature),\n          total: formatMoneyForDisplay(locked + spendable + pending + immature)\n        };\n      } else {\n        const locked = this.lockedBalance || 0;\n        const spendable = this.spendableBalance || 0;\n        const pending = this.pendingBalance || 0;\n        const immature = this.immatureBalance || 0;\n\n        this.accountObject = {\n          locked: formatMoneyForDisplay(locked),\n          spendable: formatMoneyForDisplay(spendable),\n          pending: formatMoneyForDisplay(pending),\n          immature: formatMoneyForDisplay(immature),\n          total: formatMoneyForDisplay(locked + spendable + pending + immature)\n        };\n      }\n    }\n  },\n  mounted() {\n    this.getValues();\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.tooltip {\n  position: relative;\n  z-index: 99;\n}\n.tooltip-container {\n  position: fixed;\n  z-index: 9990;\n  display: flex;\n  flex-direction: column;\n  margin-top: 6px;\n  padding: 5px;\n  border-radius: 2px;\n  background-color: #fff;\n  width: 200px;\n  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;\n}\n.tooltip-heading {\n  font-size: 1em;\n  margin-right: 10px;\n  font-weight: bold;\n  margin-bottom: 12px;\n  color: #000;\n  line-height: 22px;\n}\n.tooltip-content {\n  font-size: 0.85em;\n  color: #000;\n  line-height: 22px;\n}\n.tooltip-row {\n  display: flex;\n  flex-direction: row;\n  width: 100%;\n  margin-right: 10px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/ActivityIndicator.vue",
    "content": "<template>\n  <div :class=\"modalClass\" class=\"flex-col\">\n    <div class=\"spinner\"></div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ActivityIndicator\",\n  props: {\n    paddingHidden: {\n      type: Boolean,\n      default: false\n    }\n  },\n  computed: {\n    modalClass() {\n      return this.paddingHidden ? \"modal-no-padding\" : \"modal-mask\";\n    }\n  }\n};\n</script>\n\n<style>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: var(--sidebar-left-width);\n  width: calc(100% - var(--sidebar-left-width));\n  height: 100%;\n  background-color: rgba(255, 255, 255, 0.8);\n  margin-top: 0;\n  align-items: center;\n  justify-content: center;\n  z-index: 9998;\n}\n\n.modal-no-padding {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100vw;\n  height: 100%;\n  background-color: rgba(255, 255, 255, 0.8);\n  margin-top: 0;\n  align-items: center;\n  justify-content: center;\n  z-index: 9998;\n}\n\n.spinner {\n  position: relative;\n  display: inline-block;\n  width: 60px;\n  height: 60px;\n  border-style: solid;\n  border-radius: 100%;\n  border-width: 6px;\n  border-left-color: transparent;\n  color: var(--primary-color);\n  opacity: 0;\n\n  animation-name: rotate, fadeIn;\n  animation-duration: 800ms, 600ms;\n  animation-timing-function: linear, ease;\n  animation-iteration-count: infinite, 1;\n  animation-delay: 400ms;\n  animation-fill-mode: forwards;\n}\n\n@keyframes rotate {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes fadeIn {\n  0% {\n    opacity: 0;\n  }\n  100% {\n    opacity: 1;\n  }\n}\n\n@media (max-width: 960px) {\n  .modal-mask {\n    left: var(--sidebar-left-width-small);\n    width: calc(100% - var(--sidebar-left-width-small));\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/AppLoader.vue",
    "content": "<template>\n  <div class=\"app-loader flex-col\" v-if=\"showLoader\">\n    <div class=\"logo-outer flex-col\">\n      <div class=\"logo-inner\"></div>\n    </div>\n    <div class=\"info\">\n      <p v-show=\"isShuttingDown\">\n        {{ $t(\"loader.shutdown\") }}\n      </p>\n      <div v-show=\"isSynchronizing\">\n        <div class=\"sync-desc\">{{ $t(\"loader.synchronizing\") }}</div>\n        <progress ref=\"progress\" max=\"130\" value=\"0\"></progress>\n      </div>\n    </div>\n    <div class=\"version-container\">\n      <span>Munt</span>\n      <span class=\"divider\">|</span>\n      <span>Unity: {{ unityVersion }}</span>\n      <span class=\"divider\">|</span>\n      <span>Wallet: {{ walletVersion }}</span>\n      <span class=\"divider\">|</span>\n      <span>Electron: {{ electronVersion }}</span>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppStatus from \"../AppStatus\";\nimport { LibraryController } from \"../unity/Controllers\";\n\nlet progressTimeout = null;\n\n// How many times we have polled for progress while the app is still in a loading state and is not yet synchronising\nlet preProgressCount = 0;\n\nexport default {\n  name: \"AppLoader\",\n  data() {\n    return {\n      electronVersion: process.versions.electron,\n      progress: 0\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"splashReady\", \"syncDone\", \"status\", \"unityVersion\", \"walletVersion\"]),\n    showLoader() {\n      return this.splashReady === false || (this.status !== AppStatus.setup && this.syncDone === false) || this.status === AppStatus.shutdown;\n    },\n    isShuttingDown() {\n      return this.status === AppStatus.shutdown;\n    },\n    isSynchronizing() {\n      return this.status === AppStatus.synchronize;\n    }\n  },\n  watch: {\n    status() {\n      this.onStatusChanged();\n    },\n    progress() {\n      if (this.$refs.progress) {\n        this.$refs.progress.value = parseInt(this.progress * 100);\n      }\n    }\n  },\n  created() {\n    this.onStatusChanged();\n  },\n  mounted() {\n    setTimeout(() => {\n      this.$store.dispatch(\"app/SET_SPLASH_READY\");\n    }, 2500);\n  },\n  methods: {\n    onStatusChanged() {\n      let routeName;\n      switch (this.status) {\n        case AppStatus.setup:\n          routeName = \"setup\";\n          break;\n        case AppStatus.synchronize:\n          routeName = \"account\";\n          this.updateProgress();\n          break;\n        case AppStatus.ready:\n          routeName = \"account\";\n          break;\n      }\n      if (routeName === undefined || this.$route.name === routeName) return;\n      this.$router.push({ name: routeName });\n    },\n    updateProgress() {\n      clearTimeout(progressTimeout);\n      if (this.status !== AppStatus.synchronize) return;\n\n      const progress = LibraryController.GetUnifiedProgress();\n      console.log(`progress: ${progress}`);\n\n      // App goes through two basic loading processes:\n      // a. Setting up wallet, loading transactions/accounts, starting up of internal services network threads etc.\n      // b. Synchronising with network\n      // While we are in 'a' its not possible to determine progress and we get only a response of 200 from 'GetUnifiedProgress' to indicate this\n      // Once we are in 'b' we get a fraction of between 0..1 expressing the percentage we are in terms of complete.\n      //\n      // To deal with this we do the following:\n      // 1. We make our total progress target \"130\" instead of \"100\"\n      // 2. The first 30 of that 130 we proportion to \"a\" the second 100 we proportion to \"b\"\n      // 3. While in a we slowly increment over time from 0..30 to show the user progress is taking place\n      // 4. While in b we assume we are already starting from 30 and just add the return value of 'GetUnifiedProgress' on top of that\n      //\n      // Room for improvement:\n      // 1. Instead of starting b from 30 we should determine where 'a' left off (e.g. maybe it was only at 10) and start from there, and drop the progress total to match.\n      // 2. Improve the API call to return an object that properly specifies this instead of the magic \"200\" number\n      // 3. Fine tune what percentage of the sync we proportion to \"a\"\n      // 4. Use different proportions if we are performing an initial sync on a new wallet vs catching up on a previously synced wallet\n      // 'b' takes substantially longer on 'b' while if I open/close a recently synced wallet most time will be spent in 'a'\n\n      if (!this.syncDone) {\n        if (progress > 190) {\n          this.progress = (0.3 / 20) * preProgressCount;\n          if (preProgressCount < 20) {\n            preProgressCount++;\n          }\n          progressTimeout = setTimeout(this.updateProgress, 1000);\n        } else {\n          this.progress = 0.3 + progress;\n          progressTimeout = setTimeout(this.updateProgress, 2500);\n        }\n      } else {\n        // we always wait for syncDone to be true before continuing\n        this.progress = 1.3;\n        this.$store.dispatch(\"app/SET_STATUS\", AppStatus.ready);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-loader {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  background-color: #fff;\n  z-index: 9999;\n}\n\n.logo-outer {\n  margin: 0 0 50px 0;\n  background: transparent;\n  width: 128px;\n  height: 128px;\n  border-radius: 50%;\n  align-items: center;\n  justify-content: center;\n  text-align: center;\n}\n\n.logo-inner {\n  width: 128px;\n  height: 128px;\n  background: url(\"../img/logo-black.svg\");\n  background-size: cover;\n}\n\n.version-container {\n  font-size: 0.8em;\n  text-transform: uppercase;\n  color: #999;\n\n  & .divider {\n    margin: 0 8px;\n  }\n}\n\n.info {\n  margin: 0 0 50px 0;\n}\n\n.sync-desc {\n  margin: 0 0 10px 0;\n}\n\nprogress[value] {\n  appearance: none;\n  width: 100%;\n  height: 5px;\n}\n\nprogress[value]::-webkit-progress-bar {\n  background-color: #efefef;\n}\n\nprogress[value]::-webkit-progress-value {\n  background-color: var(--primary-color);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/ClipboardField.vue",
    "content": "<template>\n  <div class=\"clipboard-field\">\n    <span class=\"field\" @click=\"copyToClipboard\">\n      <span v-if=\"confirmCopy\">\n        {{ $t(confirmation) }}\n      </span>\n      <span v-else>\n        {{ value }}\n        <fa-icon :icon=\"['fal', 'copy']\" class=\"copy\" />\n      </span>\n    </span>\n  </div>\n</template>\n\n<script>\nimport { clipboard } from \"electron\";\n\nexport default {\n  name: \"ClipboardField\",\n  props: {\n    value: {\n      type: String\n    },\n    confirmation: {\n      type: String,\n      default: \"clipboard_field.copied_to_clipboard\"\n    }\n  },\n  data() {\n    return {\n      confirmCopy: false\n    };\n  },\n  methods: {\n    copyToClipboard() {\n      clipboard.writeText(this.value);\n      if (this.confirmation) {\n        this.confirmCopy = true;\n        setTimeout(() => {\n          this.confirmCopy = false;\n        }, 1500);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.clipboard-field {\n  text-align: center;\n  padding: 10px 0;\n}\n\n.field {\n  padding: 10px;\n  cursor: pointer;\n}\n\n.clipboard-field:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n}\n\n.copy {\n  margin-left: 10px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/ConfirmDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" @click=\"closeModal\" v-if=\"showModal\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span :class=\"type\">{{ title }}</span>\n        <div class=\"close\" @click=\"closeModal\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div class=\"content\">\n        {{ message }}\n      </div>\n      <app-button-section class=\"buttons\" v-if=\"showButtons\">\n        <template v-slot:right>\n          <button @click=\"closeModal\">{{ $t(\"buttons.cancel\") }}</button>\n          <button @click=\"confirm\">{{ $t(\"buttons.confirm\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ConfirmDialog\",\n  props: {\n    value: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    showModal() {\n      return this.value !== null;\n    },\n    title() {\n      return this.value.title || \"Are you sure?\";\n    },\n    showButtons() {\n      return typeof this.value.showButtons === \"boolean\" ? this.value.showButtons : true;\n    },\n    type() {\n      return this.value.type;\n    },\n    message() {\n      return this.value.message;\n    },\n    component() {\n      return this.value.component;\n    },\n    componentProps() {\n      return this.value.componentProps;\n    }\n  },\n  methods: {\n    closeModal() {\n      this.value.closeModal();\n    },\n    confirm() {\n      this.value.confirm();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content {\n  margin: 30px 0;\n  padding: 0 30px;\n  height: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n\n.error {\n  color: var(--error-color, #dd3333);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/CurrencyInput.vue",
    "content": "<template>\n  <input type=\"text\" v-model=\"displayValue\" @focus=\"isFocussed = true\" @blur=\"isFocussed = false\" @keydown=\"validateInput\" @paste=\"preventPaste\" />\n</template>\n\n<script>\nexport default {\n  name: \"CurrencyInput\",\n  props: {\n    value: {\n      type: [String, Number],\n      default: \"\"\n    },\n    currency: {\n      type: String,\n      default: \"\"\n    }\n  },\n  data() {\n    return {\n      isFocussed: false,\n      innerValue: this.value\n    };\n  },\n  watch: {\n    innerValue() {\n      this.$emit(\"input\", this.innerValue);\n    }\n  },\n  computed: {\n    displayValue: {\n      get: function () {\n        if (this.innerValue === null || this.innerValue === undefined || this.innerValue.toString().trim() === \"\") return null;\n\n        if (this.isFocussed) {\n          return this.innerValue;\n        } else {\n          return `${this.currency} ${this.innerValue.toString().replace(/(\\d)(?=(\\d{3})+(?:\\.\\d+)?$)/g, \"$1 \")}`.trim();\n        }\n      },\n      set: function (modifiedValue) {\n        let newValue = modifiedValue.replace(/[^0-9.]/g, \"\").replace(/(\\..*)\\./g, \"$1\");\n\n        let periodIdx = newValue.indexOf(\".\");\n        if (periodIdx !== -1 && newValue.length - periodIdx > 3) {\n          newValue = `${newValue.slice(0, periodIdx)}${newValue.slice(periodIdx + 1, periodIdx + 2)}.${newValue.slice(periodIdx + 2)}`;\n        }\n\n        this.innerValue = newValue;\n      }\n    }\n  },\n  methods: {\n    preventPaste(e) {\n      e.preventDefault();\n    },\n    validateInput(e) {\n      if (\n        (e.keyCode >= 48 && e.keyCode <= 58 && e.shiftKey == false) || // 0-9\n        (e.keyCode >= 96 && e.keyCode <= 105) || // 0-9 numeric pad\n        ((e.keyCode == 190 || e.keyCode === 110) && this.displayValue.toString().indexOf(\".\") === -1) || // only allow single .\n        e.keyCode === 8 || // backspace\n        e.keyCode === 9 || // tab\n        e.keyCode === 13 || // enter\n        (e.keyCode >= 33 && e.keyCode <= 40) || // ...\n        e.keyCode === 45 || // insert\n        e.keyCode === 46 // delete\n      )\n        return;\n\n      e.preventDefault();\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/ModalDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" @click=\"closeModal\" v-if=\"showModal\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span :class=\"type\">{{ title }}</span>\n        <div class=\"close\" @click=\"closeModal\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div :class=\"contentClass\">\n        {{ message }}\n        <component v-if=\"component\" :is=\"component\" v-bind=\"componentProps\"></component>\n      </div>\n      <app-button-section class=\"buttons\" v-if=\"showButtons\">\n        <template v-slot:right>\n          <button @click=\"closeModal\">{{ $t(\"buttons.ok\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"../EventBus\";\n\nexport default {\n  name: \"ModalDialog\",\n  props: {\n    value: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    showModal() {\n      return this.value !== null;\n    },\n    title() {\n      return this.value.title || \"title\";\n    },\n    contentClass() {\n      return `content ${this.value.noMargin ? \"no-margin\" : \"\"}`;\n    },\n    showButtons() {\n      return typeof this.value.showButtons === \"boolean\" ? this.value.showButtons : true;\n    },\n    type() {\n      return this.value.type;\n    },\n    message() {\n      return this.value.message;\n    },\n    component() {\n      return this.value.component;\n    },\n    componentProps() {\n      return this.value.componentProps;\n    }\n  },\n  methods: {\n    closeModal() {\n      EventBus.$emit(\"close-dialog\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content:not(.no-margin) {\n  margin: 30px 0;\n  padding: 0 30px;\n  overflow-y: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n\n.error {\n  color: var(--error-color, #dd3333);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/PhraseInput.vue",
    "content": "<template>\n  <div class=\"phrase-input-wrapper\">\n    <input\n      v-for=\"(word, index) in words\"\n      :key=\"index\"\n      type=\"text\"\n      class=\"word-input\"\n      ref=\"input\"\n      @input=\"onInput(index, $event)\"\n      @focus=\"onFocus(index)\"\n      @blur=\"onBlur(index)\"\n      @keydown=\"validatePraseOnEnter\"\n      v-model=\"inputs[index]\"\n      :class=\"getCssClass(index)\"\n      :disabled=\"isInputDisabled(index)\"\n    />\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"PhraseInput\",\n  props: {\n    validate: {\n      type: [String, Object],\n      default: \"\"\n    },\n    isPhraseInvalid: {\n      type: Boolean,\n      default: false\n    },\n    autofocus: {\n      type: Boolean,\n      default: true\n    }\n  },\n  data() {\n    return {\n      inputs: []\n    };\n  },\n  mounted() {\n    if (this.autofocus) {\n      this.$nextTick(() => {\n        this.$refs.input[0].focus();\n      });\n    }\n  },\n  computed: {\n    isRecovery() {\n      return typeof this.validate !== \"string\";\n    },\n    words() {\n      return this.isRecovery ? Array(this.validate.length).join(\".\").split(\".\") : this.validate.split(\" \");\n    }\n  },\n  methods: {\n    clear() {\n      this.inputs = [];\n      this.$nextTick(() => {\n        this.$refs.input[0].focus();\n      });\n    },\n    onFocus(index) {\n      // force sequential input. make sure the first input is focused which doesn't have a valid word\n      for (var i = 0; i < index; i++) {\n        if (this.isMatch(i) === false) {\n          // this input doesn't contain a valid word, so put the focus on that word\n          this.$refs.input[i].focus();\n          return;\n        }\n      }\n\n      if (this.isMatch(index)) {\n        // focus set on input by the user, so let's clear the input\n        this.inputs[index] = \"\";\n        this.$refs.input[index].value = \"\";\n        this.$emit(\"possible-phrase\", null);\n      }\n      if (!this.isRecovery) console.log(this.words[index]);\n    },\n    onBlur(index) {\n      if (this.isMatch(index) === false) {\n        this.inputs[index] = \"\";\n        this.$refs.input[index].value = \"\";\n      }\n    },\n    onInput(index) {\n      if (this.inputs.length === 12 && this.isMatch(index)) {\n        this.$emit(\"possible-phrase\", this.inputs.join(\" \"));\n        return;\n      }\n      this.$emit(\"possible-phrase\", null);\n\n      if (this.isExactMatch(index)) {\n        let nextIndex;\n        for (nextIndex = index + 1; nextIndex <= this.inputs.length; nextIndex++) {\n          if (this.inputs[nextIndex] === undefined) break;\n          if (this.isMatch(nextIndex) === false) break;\n        }\n\n        let next = this.$refs.input[nextIndex];\n        if (next) next.focus();\n      }\n    },\n    getCssClass(index) {\n      if (this.isPhraseInvalid) return \"\";\n      if (this.isInvalid(index)) return \"error\";\n      if (this.isMatch(index)) return \"success\";\n      return \"\";\n    },\n    isInputDisabled(index) {\n      if (this.isRecovery) return false;\n      if (index === this.words.length - 1) return false;\n      return this.isExactMatch(index);\n    },\n    isExactMatch(index) {\n      let inputWord = this.inputs[index];\n      if (inputWord === undefined || inputWord.length === 0) return false;\n\n      if (this.isRecovery) {\n        let validWords = this.getValidWords(index);\n        return validWords.length === 1 && inputWord === validWords[0];\n      } else {\n        return inputWord === this.words[index];\n      }\n    },\n    isMatch(index) {\n      if (this.isRecovery) {\n        let inputWord = this.inputs[index];\n        if (inputWord === undefined || inputWord.length === 0) return false;\n        return this.getValidWords(index).indexOf(inputWord) !== -1;\n      } else return this.isExactMatch(index);\n    },\n    isInvalid(index) {\n      let inputWord = this.inputs[index];\n      if (inputWord === undefined || inputWord.length === 0) return false;\n\n      if (this.isRecovery) {\n        return this.getValidWords(index).length === 0;\n      } else {\n        let word = this.words[index];\n        return inputWord.length > word.length ? true : word.indexOf(inputWord) !== 0;\n      }\n    },\n    getValidWords(index) {\n      return this.validate.words.filter(x => x.indexOf(this.inputs[index]) === 0);\n    },\n    validatePraseOnEnter(event) {\n      if (event.keyCode === 13) this.$emit(\"enter\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.phrase-input-wrapper {\n  width: calc(100% + 10px);\n  margin: -5px 0 0 -5px;\n}\n\n.word-input {\n  width: calc(25% - 10px);\n  margin: 5px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/SelectList.vue",
    "content": "<template>\n  <div class=\"select-list-wrapper\" :tabindex=\"tabindex\" @blur=\"open = false\">\n    <div class=\"selected\" :class=\"{ open: open }\" @click=\"open = !open\">\n      {{ typeof selected === \"object\" ? selected.label : selected }}\n    </div>\n    <div class=\"arrow\" @click=\"open = !open\">\n      <fa-icon :icon=\"['fal', 'chevron-down']\" />\n    </div>\n    <div class=\"items\" :class=\"{ selectHide: !open }\">\n      <div\n        v-for=\"(option, i) of options\"\n        :key=\"i\"\n        @click=\"\n          selected = option;\n          open = false;\n          $emit('input', option);\n        \"\n      >\n        {{ typeof option === \"object\" ? option.label : option }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"SelectList\",\n  props: {\n    options: {\n      type: Array,\n      required: true\n    },\n    default: {\n      type: [String, Object],\n      required: false,\n      default: null\n    },\n    tabindex: {\n      type: Number,\n      required: false,\n      default: 0\n    }\n  },\n  data() {\n    return {\n      selected: this.default ? this.default : this.options.length > 0 ? this.options[0] : null,\n      open: false\n    };\n  },\n  mounted() {\n    this.$emit(\"input\", this.selected);\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.select-list-wrapper {\n  position: relative;\n  width: 100%;\n  text-align: left;\n  outline: none;\n  line-height: 40px;\n  font-style: normal;\n  font-weight: 500;\n  font-size: 14px;\n  color: #000;\n  padding-bottom: 10px;\n}\n\n.select-list-wrapper .selected {\n  padding-left: 10px;\n  cursor: pointer;\n  user-select: none;\n  background-color: #fff;\n  border: 1px solid #ccc;\n}\n\n.select-list-wrapper .selected.open {\n  border: 1px solid #ccc;\n}\n\n.arrow {\n  position: absolute;\n  top: 0;\n  right: 10px;\n  font-size: 12px;\n  line-height: 40px;\n  cursor: pointer;\n}\n\n.select-list-wrapper .items {\n  overflow: hidden;\n  border-right: 1px solid #ccc;\n  border-left: 1px solid #ccc;\n  border-bottom: 1px solid #ccc;\n  position: absolute;\n  background-color: #fff;\n  left: 0;\n  right: 0;\n  z-index: 1;\n}\n\n.select-list-wrapper .items div {\n  padding-left: 1em;\n  cursor: pointer;\n  user-select: none;\n}\n\n.select-list-wrapper .items div:hover {\n  color: #fff;\n  background-color: var(--primary-color);\n}\n\n.selectHide {\n  display: none;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/TransactionDetailsDialog.vue",
    "content": "<template>\n  <div class=\"transaction-details-dialog\">\n    <div class=\"tx-date\">{{ computedTimestamp }}</div>\n    <div class=\"tx-amount\">{{ computedAmount }}</div>\n    <div class=\"tx-to\">\n      <fa-icon :icon=\"['far', 'long-arrow-down']\" />\n    </div>\n    <div class=\"tx-address\">\n      <clipboard-field :value=\"mutation.recipient_addresses\" />\n    </div>\n    <div class=\"tx-id\">TX ID:<clipboard-field :value=\"mutation.txHash\" /></div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"../EventBus\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport ClipboardField from \"./ClipboardField.vue\";\n\nexport default {\n  components: { ClipboardField },\n  name: \"TransactionDetailsDialog\",\n  props: {\n    mutation: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    computedTimestamp() {\n      let timestamp = new Date(this.mutation.timestamp * 1000);\n      return `${this.formatDate(timestamp)} ${this.formatTime(timestamp)}`;\n    },\n    computedAmount() {\n      return `${formatMoneyForDisplay(this.mutation.change)} ` + this.$t(\"common.ticker_symbol\");\n    }\n  },\n  methods: {\n    close() {\n      EventBus.$emit(\"close-dialog\");\n    },\n    formatDate(d) {\n      let date = new Date(d);\n      let options = {\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\"\n      };\n      if (date.getFullYear() === new Date().getFullYear()) delete options.year;\n      return date.toLocaleString(this.$i18n.locale, options);\n    },\n    formatTime(timestamp) {\n      let date = new Date(timestamp * 1000);\n      return `${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transaction-details-dialog {\n  text-align: center;\n\n  & > h4 {\n    margin: 25px 0 0 0;\n  }\n}\n.tx-date {\n  margin: 0 0 10px 0;\n  font-size: 0.9em;\n}\n.tx-amount {\n  font-size: 1.6em;\n  font-weight: 600;\n}\n.tx-address {\n  font-weight: 500;\n}\n.tx-to {\n  margin: 20px 0 10px 0;\n  font-size: 1.6em;\n}\n.tx-id {\n  margin: 20px 0 0 0;\n  padding: 10px;\n  font-size: 0.75em;\n  line-height: 1em;\n  text-transform: uppercase;\n  & .clipboard-field {\n    display: inline-block;\n    margin: 0 0 0 5px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/UnlockWalletDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" v-if=\"visible\" @click=\"onCancel\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span>{{ $t(this.options.title) }}</span>\n        <div class=\"close\" @click=\"onCancel\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div class=\"content\">\n        <app-form-field title=\"unlock_wallet_dialog.unlock_for\" v-if=\"options.timeout == null\">\n          <select-list :options=\"timeoutOptions\" :default=\"timeoutOptions[0]\" v-model=\"timeout\" />\n        </app-form-field>\n        <content-wrapper :content=\"options.message\">\n          <app-form-field title=\"common.password\">\n            <input ref=\"pwd\" v-model=\"password\" type=\"password\" @keydown=\"resetStatus\" @keydown.enter=\"tryUnlock\" :class=\"passwordStatus\" />\n          </app-form-field>\n        </content-wrapper>\n      </div>\n      <app-button-section class=\"buttons\">\n        <template v-slot:right>\n          <button @click=\"tryUnlock\">{{ $t(\"buttons.unlock\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { LibraryController } from \"../unity/Controllers\";\nimport EventBus from \"../EventBus\";\n\nexport default {\n  name: \"UnlockWalletDialog\",\n  data() {\n    return {\n      visible: false,\n      isUnlocked: null,\n      timeout: 1,\n      options: {},\n      password: \"\",\n      error: false\n    };\n  },\n  mounted() {\n    EventBus.$on(\"unlock-wallet\", this.unlockWallet);\n    EventBus.$on(\"lock-wallet\", this.lockWallet);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"unlock-wallet\", this.unlockWallet);\n    EventBus.$off(\"lock-wallet\", this.lockWallet);\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"unlocked\"]),\n    timeoutOptions() {\n      return [1, 5, 10].map(i => {\n        return { value: 60 * i, label: this.$tc(\"unlock_wallet_dialog.minute\", i) };\n      });\n    },\n    passwordStatus() {\n      return this.error ? \"error\" : \"\";\n    }\n  },\n  methods: {\n    async lockWallet() {\n      await LibraryController.LockWalletAsync();\n    },\n    async unlockWallet(options) {\n      // note:\n      // it can happen if unlocked is true now, but is false right after the callback\n      // find a solution for this situation...\n      // maybe LibraryController.GetWalletLockStatus can be used to determine if wallet is still unlocked for a while?\n      if (this.unlocked) {\n        if (typeof options.callback === \"function\") {\n          return options.callback();\n        }\n      }\n\n      this.options = {\n        title: \"unlock_wallet_dialog.title\",\n        message: null,\n        timeout: options && options.callback ? 10 : null,\n        ...options\n      };\n\n      this.visible = true;\n      this.$nextTick(() => {\n        this.$refs.pwd.focus();\n      });\n    },\n    onCancel() {\n      this.password = null;\n      this.visible = false;\n      this.error = false;\n    },\n    async resetStatus() {\n      this.error = false;\n    },\n    async tryUnlock() {\n      var result = await LibraryController.UnlockWalletAsync(this.password, this.options.timeout || this.timeout.value);\n      if (result) {\n        this.password = null;\n        this.visible = false;\n\n        if (this.options.callback) {\n          // call and await the callback function\n          await this.options.callback();\n\n          // lock the wallet after callback finishes\n          LibraryController.LockWallet();\n        }\n      } else {\n        this.error = true;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content {\n  margin: 30px 0;\n  padding: 0 30px;\n  overflow-y: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/index.js",
    "content": "import Vue from \"vue\";\n\nimport CurrencyInput from \"./CurrencyInput\";\nimport ClipboardField from \"./ClipboardField\";\nimport MainHeader from \"./layout/MainHeader\";\nimport AppButtonSection from \"./layout/AppButtonSection\";\nimport AppFormField from \"./layout/AppFormField\";\nimport AppSection from \"./layout/AppSection\";\nimport SelectList from \"./SelectList\";\nimport FooterButton from \"./layout/FooterButton\";\nimport ContentWrapper from \"./layout/ContentWrapper\";\nimport AccountHeader from \"./AccountHeader\";\n\nVue.component(ClipboardField.name, ClipboardField);\nVue.component(CurrencyInput.name, CurrencyInput);\nVue.component(MainHeader.name, MainHeader);\nVue.component(AppButtonSection.name, AppButtonSection);\nVue.component(AppFormField.name, AppFormField);\nVue.component(AppSection.name, AppSection);\nVue.component(SelectList.name, SelectList);\nVue.component(FooterButton.name, FooterButton);\nVue.component(ContentWrapper.name, ContentWrapper);\nVue.component(AccountHeader.name, AccountHeader);\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/AppButtonSection.vue",
    "content": "<template>\n  <div class=\"app-button-section flex-row\">\n    <div class=\"left\">\n      <slot name=\"left\" />\n    </div>\n    <div class=\"middle\">\n      <slot name=\"middle\" />\n    </div>\n    <div class=\"right\">\n      <slot />\n      <slot name=\"right\" />\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"AppButtonSection\"\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-button-section {\n  width: 100%;\n\n  & .left {\n    float: left;\n\n    & > button:not(:last-child) {\n      margin: 0 20px 0 0;\n    }\n\n    & > button:not([disabled]) {\n      background-color: #fff;\n      border: 1px solid var(--primary-color);\n      color: var(--primary-color);\n    }\n  }\n\n  & .middle {\n    flex: 1;\n  }\n\n  & .right {\n    text-align: right;\n\n    & > button:not(:first-child) {\n      margin: 0 0 0 20px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/AppFormField.vue",
    "content": "<template>\n  <app-section class=\"app-form-field\">\n    <h2 v-if=\"hasTitle\">{{ $t(title) }}</h2>\n    <slot></slot>\n  </app-section>\n</template>\n\n<script>\nimport AppSection from \"./AppSection\";\n\nexport default {\n  name: \"AppFormField\",\n  props: {\n    title: {\n      type: String,\n      default: \"\"\n    }\n  },\n  components: {\n    AppSection\n  },\n  computed: {\n    hasTitle() {\n      return this.title !== null && this.title.trim().length > 0;\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/AppSection.vue",
    "content": "<template>\n  <div class=\"section\">\n    <slot />\n  </div>\n</template>\n\n<style lang=\"less\" scoped>\n.section {\n  margin: 0 0 20px 0;\n}\n</style>\n\n<script>\nexport default {\n  name: \"AppSection\"\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/ContentWrapper.vue",
    "content": "<template>\n  <div>\n    <h2 v-if=\"heading\" :class=\"headingStyle\">{{ $t(heading) }}</h2>\n    <p v-if=\"content\">\n      {{ $t(content) }}\n    </p>\n    <slot></slot>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ContentWrapper\",\n  props: {\n    heading: {\n      type: String,\n      default: null\n    },\n    headingStyle: {\n      type: String,\n      default: null,\n      validator: value => {\n        return [\"warning\"].includes(value);\n      }\n    },\n    content: {\n      type: String,\n      default: null\n    }\n  }\n};\n</script>\n\n<style scoped>\np {\n  text-align: inherit;\n  white-space: pre-line; /* Allow \\n to be treated as newline */\n}\n\nh2.warning {\n  color: var(--error-color);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/FooterButton.vue",
    "content": "<template>\n  <div :class=\"getClass(isActive)\" @click=\"$emit('click', routeName)\">\n    <fa-icon class=\"left\" v-if=\"showIcon('left')\" :icon=\"icon\" />\n    {{ $t(this.title) }}\n    <slot></slot>\n    <fa-icon class=\"right\" v-if=\"showIcon('right')\" :icon=\"icon\" />\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"FooterButton\",\n  props: {\n    routeName: {\n      type: String\n    },\n    title: {\n      type: String,\n      default: null\n    },\n    params: {\n      type: Object,\n      value: () => {}\n    },\n    icon: {\n      type: Array,\n      value: () => []\n    },\n    iconPosition: {\n      type: String,\n      default: \"left\",\n      validator: value => {\n        return [\"left\", \"right\"].includes(value);\n      }\n    }\n  },\n  computed: {\n    isActive() {\n      return this.$route.name === this.routeName;\n    }\n  },\n  methods: {\n    getClass(isActive) {\n      return `footer-button ${isActive ? \"active\" : \"\"}`;\n    },\n    showIcon(position) {\n      if (!this.icon) return false;\n      return this.iconPosition === position;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.footer-button {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  flex-wrap: nowrap;\n  align-items: center;\n  padding: 0 20px;\n  font-weight: 600;\n  font-size: 0.85em;\n  text-transform: uppercase;\n  letter-spacing: 0.03em;\n  line-height: calc(var(--footer-height) - 20px);\n  max-width: 160px;\n  height: 45px;\n  white-space: nowrap;\n  margin-top: 5px;\n  cursor: pointer;\n\n  & svg {\n    font-size: 14px;\n  }\n\n  & svg.left {\n    margin-right: 5px;\n  }\n\n  & svg.right {\n    margin-left: 5px;\n  }\n\n  &.active {\n    color: var(--primary-color);\n    cursor: default;\n  }\n\n  &:not(.active):hover {\n    background: var(--hover-color);\n    color: var(--primary-color);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/components/layout/MainHeader.vue",
    "content": "<template>\n  <div class=\"main-header\" :class=\"mainHeaderClass\">\n    <div class=\"title ellipsis\">\n      {{ $t(title) }}\n    </div>\n    <div class=\"subtitle ellipsis\" v-if=\"hasSubtitle\">\n      {{ $t(subtitle) }}\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"MainHeader\",\n  props: {\n    title: {\n      type: String,\n      default: null\n    },\n    subtitle: {\n      type: String,\n      default: null\n    }\n  },\n  computed: {\n    hasSubtitle() {\n      return this.subtitle && this.subtitle.trim().length > 0;\n    },\n    mainHeaderClass() {\n      return this.hasSubtitle ? \"\" : \"no-subtitle\";\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.main-header {\n  height: var(--header-height);\n  line-height: 20px;\n  padding: calc((var(--header-height) - 40px) / 2) 0;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n\n  &.no-subtitle {\n    padding: calc((var(--header-height) - 20px) / 2) 0;\n  }\n}\n\n.title {\n  font-size: 1.1em;\n  font-weight: 500;\n  line-height: 20px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/css/app.less",
    "content": "@import \"./variables.less\";\n@import \"./fonts.less\";\n@import \"./css-reset.css\";\n@import \"./app_styles.less\";\n"
  },
  {
    "path": "src/frontend/electron_vue/src/css/app_styles.less",
    "content": "h1 {\n  font-weight: 600;\n  font-size: 3.2em;\n  line-height: 1.2em;\n  margin: 0 0 60px 0;\n  letter-spacing: -0.02em;\n}\n\nh2 {\n  font-weight: 600;\n  font-size: 1.05em;\n  margin: 0 0 15px 0;\n}\n\nh3 {\n  font-weight: 500;\n  font-size: 0.85em;\n  line-height: 1.2em;\n  margin: 0 0 10px 0;\n  text-transform: uppercase;\n}\n\nh4 {\n  font-weight: 500;\n  font-size: 0.85em;\n  line-height: 1.2em;\n  margin: 0 0 20px 0;\n  text-transform: uppercase;\n}\n\nh5 {\n  font-weight: 600;\n  font-size: .85em;\n  line-height: 1.2em;\n  margin: 0 0 10px 0;\n  text-transform: uppercase;\n}\n\nb,\nstrong {\n  font-weight: 600;\n}\n\np {\n  margin: 0 0 20px 0;\n  font-size: 1em;\n  line-height: 1.45em;\n  color: #222;\n}\n\ndel {\n  text-decoration: line-through;\n}\n\na,\na:active,\na:visited {\n  text-decoration: none;\n  color: #000;\n}\n\na:hover {\n  color: #000;\n}\n\nimg,\na {\n  user-select: none;\n  -webkit-user-drag: none;\n}\n\n.select-all {\n  user-select: all;\n}\n\n/* input / select / range */\n::placeholder {\n  color: var(--primary-color);\n}\n\ninput:not([type]),\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"number\"],\ninput[type=\"range\"],\nselect {\n  width: 100%;\n  font-style: normal;\n  font-weight: 500;\n  line-height: 22px;\n  font-size: 15px;\n  height: 40px;\n  border-radius: 0px;\n  border: 0;\n  color: var(--primary-color);\n  background-color: #efefef;\n  margin: 0 0 10px 0;\n}\n\nselect {\n  padding: 0 10px;\n  margin: 0 0 20px 0;\n  -webkit-appearance: none;\n}\n\n/* input / select */\ninput:not([type]),\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"number\"] {\n  padding: 0 10px;\n  background-color: #f5f5f5;\n\n  &:focus,\n  &.success,\n  &:focus.success {\n    color: var(--success-color);\n    border-color: var(--success-color);\n  }\n\n  &.error,\n  &:focus.error {\n    color: var(--error-color);\n    border-color: var(--error-color);\n  }\n}\n\n/* remove up/down buttons for number input */\ninput[type=\"number\"]::-webkit-inner-spin-button {\n  -webkit-appearance: none;\n}\n\n/* show default cursor for readonly input */\ninput[readonly] {\n  cursor: default;\n}\n\n/* button */\nbutton {\n  padding: 0 20px 0 20px;\n  font-style: normal;\n  font-weight: 600;\n  font-size: 0.75em;\n  line-height: 40px;\n  text-transform: uppercase;\n  letter-spacing: 0.03em;\n  text-align: center;\n  text-decoration: none;\n  border: 0;\n  cursor: pointer;\n  -webkit-appearance: none;\n  -webkit-font-smoothing: antialiased !important;\n  transition: all 0.3s;\n  border-radius: 0px;\n  color: #fff;\n  background-color: var(--success-color);\n\n  &:hover {\n    background-color: var(--success-color--hover);\n  }\n\n  &[disabled=\"disabled\"],\n  &[disabled=\"disabled\"]:hover {\n    background-color: var(--disabled-color);\n    cursor: default;\n  }\n\n  &.error {\n    background-color: var(--error-color);\n  }\n  &.error:hover {\n    background-color: var(--error-color--hover);\n  }\n}\n\nbutton[outlined] {\n  height: 40px;\n}\n\nbutton[outlined]:not([disabled]) {\n  line-height: 39px;\n  background-color: #fff;\n  border: 1px solid var(--primary-color);\n  color: var(--primary-color);\n}\n\nbutton[small] {\n  height: 20px;\n  line-height: 20px !important;\n  font-size: 10px;\n  padding: 0 10px;\n}\n\n/* range slider */\ninput[type=\"range\"] {\n  width: 100%;\n}\n\n/* common styles */\n.important {\n  color: var(--error-color);\n}\n\n.ellipsis {\n  text-overflow: ellipsis;\n  /* Required for text-overflow to do anything */\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.vertical-center {\n  margin: 0;\n  position: absolute;\n  top: 50%;\n  transform: translateY(-50%);\n}\n\n.flex-row {\n  display: flex;\n  flex-direction: row;\n}\n\n.flex-col {\n  display: flex;\n  flex-direction: column;\n}\n\n.flex-1 {\n  flex: 1;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.scrollable {\n  overflow: hidden;\n\n  &:hover {\n    overflow-y: overlay;\n  }\n\n  &.scrollable-x:hover {\n    overflow-x: overlay;\n  }\n\n  &::-webkit-scrollbar {\n    width: 10px;\n  }\n\n  &::-webkit-scrollbar-track {\n    background: var(--scrollbar-background-color);\n  }\n\n  &::-webkit-scrollbar-thumb {\n    border: 2px solid rgba(0, 0, 0, 0);\n    background-clip: padding-box;\n    background-color: var(--thumb-background-color);\n    border-radius: 14px;\n  }\n\n  &.dark {\n    &::-webkit-scrollbar-track {\n      background: rgba(0, 0, 0, 0);\n    }\n\n    &::-webkit-scrollbar-thumb {\n      background-color: var(--thumb-background-color-dark);\n    }\n  }\n}\n\n// set the range slider color to let it fit in the UI\n.vue-slider-process {\n  background-color: var(--primary-color) !important;\n}\n\n.vue-slider-dot-handle {\n  border-color: var(--primary-color) !important;\n}\n\n.vue-slider-disabled {\n  .vue-slider-process {\n    background-color: #a7a7a7 !important;\n  }\n}\n\n.vue-slider-dot-handle-disabled {\n  cursor: not-allowed;\n  border-color: #ddd !important;\n}\n\n.insufficient {\n  & .vue-slider-process {\n    background-color: var(--error-color) !important;\n  }\n  & .vue-slider-dot-handle {\n    border-color: var(--error-color) !important;\n  }\n}\n\n.transactionicon {\n  width: 25px;\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/css/css-reset.css",
    "content": "html, body, div, span, h1, h2, h3, h4, h5, h6, h7, p, a, img, strong, b, form, label {\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tfont-size: 100%;\n\tfont: inherit;\n\tvertical-align: baseline;\n}\n\nul,li {\n\tlist-style: none;\n}\n\nbody {\n\tline-height: 1;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tbackground-repeat: no-repeat;\n\tbackground-position: center center;\n\tuser-select: none; /* remove user-select from all elements */\n}\n\nhtml, *, *:before, *:after {\n  box-sizing: border-box;\n}\n\n* :focus {outline: none;}\n\nhtml,\nbody {\n  height: 100%;\n}"
  },
  {
    "path": "src/frontend/electron_vue/src/css/fonts.less",
    "content": "/*\nThis CSS resource incorporates links to font software which is the valuable copyrighted\nproperty of Monotype Imaging and/or its suppliers. You may not attempt to copy, install,\nredistribute, convert, modify or reverse engineer this font software. Please contact Monotype\nImaging with any questions regarding Web Fonts:  http://www.fonts.com\n*/\n\n/* -------------------------------------------------------------- Euclid Circular B */\n\n@font-face{ \n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Light-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Light-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 300;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Regular-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Regular-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 400;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Medium-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Medium-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 500;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Semibold-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Semibold-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 600;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Bold-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Bold-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 700;\n\tfont-style: normal;\n}"
  },
  {
    "path": "src/frontend/electron_vue/src/css/variables.less",
    "content": "@primary-color: #000000;\n@hover-color: #00000010;\n@success-color: @primary-color;\n@error-color: #dd3333;\n@disabled-color: #eee;\n@secondary-color: #000;\n\n@success-color--hover: lighten(@success-color, 4%); \n@error-color--hover: lighten(@error-color, 8%);\n\n:root {\n  --primary-color: @primary-color;\n  --secondary-color: @secondary-color;\n  \n  --error-color: @error-color;\n\n  --success-color: @success-color;\n  --error-color: @error-color;\n  --disabled-color: @disabled-color;\n\n  --success-color--hover: @success-color--hover;\n  --error-color--hover: @error-color--hover;\n\n  --header-height: 62px;\n  --footer-height: 56px;\n\n  --sidebar-left-width: 300px;\n  --sidebar-left-width-small: 260px;\n  --sidebar-left-background-color: #000;\n  --sidebar-left-color: #ccc;\n  --sidebar-left-border-color: #333;\n\n  --account-background-color--active: var(--primary-color);\n  --account-background-color--hover: #222;\n  \n  --main-border-color: #ddd;\n\n  --hover-color: @hover-color;\n\n  --scrollbar-background-color: #fff;\n  --thumb-background-color: rgba(204, 204, 204, 0.7);\n  \n  --scrollbar-background-color-dark: var(--sidebar-left-background-color);\n  --thumb-background-color-dark: rgba(204, 204, 204, 0.7);\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/i18n.js",
    "content": "import Vue from \"vue\";\nimport VueI18n from \"vue-i18n\";\n\nVue.use(VueI18n);\n\nfunction loadLocaleMessages() {\n  const locales = require.context(\"./locales\", true, /[A-Za-z0-9-_,\\s]+\\.json$/i);\n  const messages = {};\n  locales.keys().forEach(key => {\n    const matched = key.match(/([A-Za-z0-9-_]+)\\./i);\n    if (matched && matched.length > 1) {\n      const locale = matched[1];\n      messages[locale] = locales(key);\n    }\n  });\n  return messages;\n}\n\nlet language = window.navigator.language.slice(0, 2);\n\nexport default new VueI18n({\n  locale: process.env.VUE_APP_I18N_LOCALE || language,\n  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || \"en\",\n  messages: loadLocaleMessages()\n});\n"
  },
  {
    "path": "src/frontend/electron_vue/src/layouts/AccountsSection.vue",
    "content": "<template>\n  <section class=\"accounts\">\n    <h4>{{ $t(\"accounts_section.accounts\") }}</h4>\n    <section class=\"scrollable dark\">\n      <div v-for=\"category in categories\" :key=\"category\">\n        <div class=\"category flex-row\">\n          <div class=\"toggle\" @click=\"toggleCategory(category)\">\n            <fa-icon :icon=\"['fal', getCategoryToggleIcon(category)]\" />\n          </div>\n          <div class=\"info\" @click=\"toggleCategory(category)\">\n            <div class=\"title ellipsis\">\n              {{ $t(`accounts_section.categories.${category}`) }}\n            </div>\n            <div class=\"balance\">{{ getBalanceFor(category) }}</div>\n          </div>\n          <div class=\"add\">\n            <div class=\"button\" @click=\"addAccountFor(category)\">\n              <fa-icon :icon=\"['fal', 'plus']\" />\n            </div>\n          </div>\n        </div>\n        <div class=\"account active\" v-if=\"showNewAccountFor(category) && false\">\n          <div>New account</div>\n          <div class=\"balance\">0</div>\n        </div>\n        <div v-if=\"opened[category]\">\n          <div v-for=\"account in getAccountsFor(category)\" :key=\"account.UUID\" class=\"account\" :class=\"accountClass(account.UUID)\">\n            <router-link\n              :disabled=\"isActiveAccount(account.UUID)\"\n              :event=\"!isActiveAccount(account.UUID) ? 'click' : ''\"\n              class=\"flex-col\"\n              :to=\"{ name: 'account', params: { id: account.UUID } }\"\n            >\n              <span class=\"ellipsis\">{{ account.label }}</span>\n              <span class=\"balance\">{{ displayBalanceForAccount(account) }}</span>\n            </router-link>\n          </div>\n        </div>\n      </div>\n    </section>\n  </section>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport UIConfig from \"../../ui-config.json\";\n\nexport default {\n  name: \"AccountsSection\",\n  data() {\n    const categories = [\"spending\"];\n    if (!UIConfig.isSPV) {\n      categories.push(\"saving\");\n    }\n\n    return {\n      categories,\n      opened: {\n        spending: false,\n        saving: false\n      }\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"activeAccount\"]),\n    ...mapState(\"app\", [\"coreReady\"]),\n    ...mapGetters(\"wallet\", [\"accounts\"]),\n    activeCategory() {\n      if (this.activeAccount === null) return null;\n      let account = this.accounts.find(x => x.UUID === this.activeAccount);\n      if (account === undefined) return null;\n      switch (account.type) {\n        case \"Desktop\":\n          return \"spending\";\n        case \"Holding\":\n        case \"Witness\":\n          return \"saving\";\n      }\n      return null;\n    }\n  },\n  watch: {\n    activeCategory() {\n      this.toggleCategory(this.activeCategory, true);\n    }\n  },\n  methods: {\n    isActiveAccount(accountUUID) {\n      return this.$route.path.indexOf(\"/account\") == 0 && accountUUID === this.activeAccount;\n    },\n    accountClass(accountUUID) {\n      return this.isActiveAccount(accountUUID) ? \"active\" : \"\";\n    },\n    displayBalanceForAccount(account) {\n      return formatMoneyForDisplay(account.balance);\n    },\n    getAccountsFor(category) {\n      let types;\n      switch (category) {\n        case \"spending\":\n          types = [\"Desktop\"];\n          break;\n        case \"saving\":\n          types = [\"Witness\", \"Holding\"];\n          break;\n      }\n      if (types === undefined) return [];\n      return this.accounts.filter(x => x.state === \"Normal\" && types.indexOf(x.type) !== -1);\n    },\n    getCategoryToggleIcon(category) {\n      return this.opened[category] ? \"chevron-down\" : \"chevron-right\";\n    },\n    toggleCategory(category, open) {\n      if (this.categories.indexOf(category) === -1) return;\n      this.opened[category] = open || !this.opened[category];\n    },\n    getBalanceFor(category) {\n      let accounts = this.getAccountsFor(category);\n      return formatMoneyForDisplay(\n        accounts.reduce(function (acc, obj) {\n          return acc + obj.balance;\n        }, 0)\n      );\n    },\n    showNewAccountFor(category) {\n      switch (category) {\n        case \"saving\":\n          return this.$route.name === \"add-saving-account\";\n        case \"spending\":\n          return this.$route.name === \"add-spending-account\";\n        default:\n          return false;\n      }\n    },\n    addAccountFor(category) {\n      switch (category) {\n        case \"saving\":\n          this.$router.push({ name: \"add-saving-account\" });\n          break;\n        case \"spending\":\n          this.$router.push({ name: \"add-spending-account\" });\n          break;\n        default:\n          console.log(`add account for ${category} not implemented yet`);\n          break;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.accounts {\n  height: 100%;\n\n  & h4 {\n    padding: 20px 20px 0 20px;\n    margin-bottom: 5px;\n    font-weight: 500;\n    font-size: 0.8em;\n  }\n\n  & > .scrollable {\n    height: calc(100% - 48px);\n  }\n}\n\n.category {\n  padding: 10px 0;\n\n  & > .toggle {\n    width: 44px;\n    padding: 0 0 0 20px;\n    font-size: 12px;\n    line-height: 16px;\n    cursor: pointer;\n\n    &.hide {\n      visibility: hidden;\n    }\n  }\n\n  & > .info {\n    width: 150px;\n    margin-right: 10px;\n    cursor: pointer;\n\n    & > .title {\n      line-height: 16px;\n      font-size: 0.85em;\n      font-weight: 600;\n      letter-spacing: 0.02em;\n      text-transform: uppercase;\n    }\n\n    & > .balance {\n      margin: 4px 0 1px 0;\n      line-height: 12px;\n      font-size: 0.8em;\n      font-weight: 500;\n      letter-spacing: 0.02em;\n      text-transform: uppercase;\n    }\n  }\n\n  & > .add {\n    flex: 1;\n    text-align: right;\n    margin: 0 24px 0 0;\n    line-height: 16px;\n    font-size: 16px;\n    cursor: pointer;\n\n    & > .button:hover {\n      padding: 4px 5px;\n      margin: -4px -5px;\n      background: #333;\n    }\n  }\n}\n\n.category.empty {\n  & > .toggle {\n    visibility: hidden;\n  }\n\n  & > .info {\n    cursor: default;\n  }\n}\n\n.account {\n  padding: 8px 24px;\n  font-size: 1em;\n  color: #ccc;\n  line-height: 16px;\n\n  &:hover {\n    background-color: var(--account-background-color--hover);\n  }\n\n  & a {\n    color: #ccc;\n    cursor: pointer;\n  }\n\n  &.active {\n    color: #fff;\n    background-color: var(--account-background-color--active);\n\n    & a {\n      color: #fff;\n    }\n  }\n\n  & .balance {\n    margin: 4px 0 1px 0;\n    font-size: 0.8em;\n    line-height: 12px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/layouts/SetupLayout.vue",
    "content": "<template>\n  <section class=\"setup-layout\">\n    <section class=\"header\">\n      <div class=\"logo\" />\n    </section>\n    <section class=\"main\">\n      <router-view />\n    </section>\n  </section>\n</template>\n\n<script>\nexport default {\n  name: \"SetupLayout\"\n};\n</script>\n\n<style lang=\"less\" scoped>\n.setup-layout {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n\n  & .header {\n    height: var(--header-height);\n    border-bottom: 1px solid var(--main-border-color);\n    padding: 20px;\n    font-size: 1.1em;\n    line-height: 42px;\n\n    & .logo {\n      width: 22px;\n      height: 22px;\n      background: url(\"../img/logo-start.svg\"), linear-gradient(transparent, transparent);\n      background-size: cover;\n    }\n  }\n\n  & .main {\n    height: calc(100vh - var(--header-height));\n    padding: 40px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/layouts/WalletLayout.vue",
    "content": "<template>\n  <section class=\"wallet-layout flex-row\" :class=\"walletLayoutClasses\">\n    <section v-if=\"!isSingleAccount\" class=\"sidebar-left\">\n      <section class=\"header flex-row\">\n        <div class=\"logo\" />\n        <div class=\"total-balance flex-row\">\n          <account-tooltip type=\"Wallet\" :account=\"account\">\n            <div class=\"flex-row\">\n              <div class=\"coin\">\n                {{ balanceForDisplay }}\n              </div>\n              <div class=\"fiat\">{{ totalBalanceFiat }}</div>\n            </div>\n          </account-tooltip>\n        </div>\n      </section>\n      <accounts-section class=\"accounts\" />\n      <section class=\"footer flex-row\">\n        <div class=\"status\" />\n        <div class=\"button\" @click=\"handleWalletLock\">\n          <fa-icon :icon=\"['fal', lockIcon]\" />\n        </div>\n        <div v-if=\"!isSPV\" class=\"button\" @click=\"showMining\">\n          <fa-icon :icon=\"['fal', 'gem']\" />\n        </div>\n        <div class=\"button\" @click=\"showSettings\">\n          <fa-icon :icon=\"['fal', 'user-circle']\" />\n        </div>\n      </section>\n    </section>\n    <section class=\"main\">\n      <section class=\"header\">\n        <account-header v-if=\"isSingleAccount\" :account=\"account\" :is-single-account=\"true\"></account-header>\n        <portal-target v-else ref=\"headerSlot\" name=\"header-slot\" @change=\"headerSlotChanged\"></portal-target>\n      </section>\n      <section class=\"content scrollable\">\n        <router-view />\n      </section>\n      <section class=\"footer\">\n        <div v-if=\"isSingleAccount\" style=\"display: flex\">\n          <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"account\" @click=\"routeTo\" />\n          <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send\" @click=\"routeTo\" />\n          <footer-button title=\"buttons.receive\" :icon=\"['fal', 'arrow-to-bottom']\" routeName=\"receive\" @click=\"routeTo\" />\n        </div>\n        <portal-target v-else ref=\"footerSlot\" name=\"footer-slot\" @change=\"footerSlotChanged\"></portal-target>\n      </section>\n    </section>\n  </section>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport EventBus from \"../EventBus\";\nimport UIConfig from \"../../ui-config.json\";\nimport { AccountsController } from \"../unity/Controllers\";\nimport AccountsSection from \"./AccountsSection.vue\";\nimport AccountTooltip from \"../components/AccountTooltip.vue\";\nimport AccountHeader from \"../components/AccountHeader.vue\";\n\nexport default {\n  name: \"WalletLayout\",\n  data() {\n    return {\n      isHeaderSlotEmpty: true,\n      isFooterSlotEmpty: true,\n      isSingleAccount: UIConfig.isSingleAccount,\n      isSPV: UIConfig.isSPV\n    };\n  },\n  components: {\n    AccountsSection,\n    AccountHeader,\n    AccountTooltip\n  },\n  computed: {\n    ...mapState(\"app\", [\"progress\", \"rate\", \"currency\"]),\n    ...mapState(\"wallet\", [\"activeAccount\", \"unlocked\"]),\n    ...mapGetters(\"wallet\", [\"totalBalance\", \"miningAccount\", \"account\"]),\n    walletLayoutClasses() {\n      let classes = [];\n      if (!this.isSingleAccount) {\n        if (this.isHeaderSlotEmpty) classes.push(\"no-header\");\n        if (this.isFooterSlotEmpty) classes.push(\"no-footer\");\n      } else {\n        classes.push(\"no-sidebar-left\");\n      }\n      return classes;\n    },\n    lockIcon() {\n      return this.unlocked ? \"unlock\" : \"lock\";\n    },\n    totalBalanceFiat() {\n      if (!this.rate) return \"\";\n      return `${this.currency.symbol || \"\"} ${formatMoneyForDisplay(this.totalBalance * this.rate, true)}`;\n    },\n    balanceForDisplay() {\n      if (this.totalBalance == null) return \"\";\n      return formatMoneyForDisplay(this.totalBalance);\n    }\n  },\n  methods: {\n    headerSlotChanged(newContent) {\n      this.isHeaderSlotEmpty = !newContent;\n    },\n    footerSlotChanged(newContent) {\n      this.isFooterSlotEmpty = !newContent;\n    },\n    showMining() {\n      if (this.miningAccount) {\n        if (this.$route.path.indexOf(\"/account\") == 0 && this.miningAccount.UUID === this.activeAccount) return;\n        this.$router.push({\n          name: \"account\",\n          params: { id: this.miningAccount.UUID }\n        });\n      } else {\n        EventBus.$emit(\"unlock-wallet\", {\n          timeout: 5,\n          title: \"setup_mining.title\",\n          message: \"setup_mining.information\",\n          callback: async () => {\n            let uuid = null;\n            try {\n              // NOTE:\n              // Dont' know if it is actually needed to show the activity indicator when unlocking the wallet and creating the account, but for now I leave it here.\n              this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n              uuid = AccountsController.CreateAccount(\"Mining\", \"Mining\");\n            } finally {\n              // route to the new account when we have a uuid\n              if (uuid) {\n                // activity indicator is set to true in the router, so no need to remove it here\n                this.$router.push({ name: \"account\", params: { id: uuid } });\n              } else {\n                // remove the activity indicator\n                this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n              }\n            }\n          }\n        });\n      }\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    },\n    getButtonClassNames(route) {\n      let classNames = [\"button\"];\n      if (route === this.$route.name) classNames.push(\"active\");\n      return classNames;\n    },\n    showSettings() {\n      if (this.$route.path === \"/settings/\") return;\n      this.$router.push({ name: \"settings\" });\n    },\n    handleWalletLock() {\n      EventBus.$emit(this.unlocked ? \"lock-wallet\" : \"unlock-wallet\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.wallet-layout {\n  height: 100vh;\n  overflow: hidden;\n\n  --header-height-main: var(--header-height);\n  --footer-height-main: var(--footer-height);\n\n  &.no-header {\n    --header-height-main: 0px;\n\n    & > .main > .header {\n      display: none;\n    }\n  }\n\n  &.no-footer {\n    --footer-height-main: 0px;\n    & > .main > .footer {\n      display: none;\n    }\n  }\n\n  & > .sidebar-left {\n    width: var(--sidebar-left-width);\n    background: var(--sidebar-left-background-color);\n    color: var(--sidebar-left-color);\n\n    & > .header {\n      height: var(--header-height);\n      border-bottom: 1px solid var(--sidebar-left-border-color);\n    }\n\n    & > .accounts {\n      height: calc(100% - var(--header-height) - var(--footer-height));\n    }\n\n    & > .footer {\n      height: var(--footer-height);\n      border-top: 1px solid var(--sidebar-left-border-color);\n    }\n  }\n\n  & > .main {\n    width: calc(100% - var(--sidebar-left-width));\n\n    & > .header {\n      height: var(--header-height);\n      border-bottom: 1px solid var(--main-border-color);\n      padding: 0 30px;\n\n      & > .logo {\n        position: relative;\n        top: 50%;\n        transform: translateY(-50%);\n      }\n    }\n\n    & > .content {\n      height: calc(100% - var(--header-height-main) - var(--footer-height-main));\n      padding: 40px 30px 30px 30px;\n\n      & > * {\n        height: 100%;\n      }\n    }\n\n    & > .footer {\n      height: var(--footer-height);\n      border-top: 1px solid var(--main-border-color);\n      line-height: calc(var(--footer-height) - 2px);\n      text-align: center;\n    }\n  }\n\n  &.no-sidebar-left {\n    & > .main {\n      width: 100%;\n    }\n  }\n}\n\n.sidebar-left > .header {\n  padding: 20px;\n  color: #fff;\n\n  & .total-balance {\n    padding: 0 0 0 10px;\n    line-height: 22px;\n  }\n\n  & .fiat {\n    margin-left: 10px;\n    color: #999;\n  }\n}\n\n.sidebar-left > .footer {\n  font-size: 16px;\n  font-weight: 400;\n\n  & .status {\n    flex: 1;\n  }\n\n  & .button {\n    line-height: 52px;\n    padding: 0 20px;\n    cursor: pointer;\n\n    &:hover {\n      background-color: #222;\n    }\n  }\n}\n\n.logo {\n  width: 22px;\n  min-width: 22px;\n  height: 22px;\n  min-height: 22px;\n  background: url(\"../img/logo.svg\"), linear-gradient(transparent, transparent);\n  background-size: cover;\n}\n\n@media (max-width: 1000px) {\n  .wallet-layout {\n    & > .sidebar-left {\n      width: var(--sidebar-left-width-small);\n    }\n\n    & > .main {\n      width: calc(100% - var(--sidebar-left-width-small));\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/locales/en.json",
    "content": "{\n  \"accounts_section\": {\n    \"accounts\": \"Accounts\",\n    \"categories\": {\n      \"spending\": \"Spending\",\n      \"saving\": \"Witness\"\n    }\n  },\n  \"account_settings\": {\n    \"title\": \"Account settings\",\n    \"name\": \"Name\"\n  },\n  \"add_saving_account\": {\n    \"daily\": \"daily\",\n    \"estimated_earnings\": \"Estimated earnings\",\n    \"funding_account\": \"Funding account\",\n    \"lock_for\": \"Lock for\",\n    \"overall\": \"overall\",\n    \"title\": \"Add witness account\"\n  },\n  \"add_spending_account\": {\n    \"title\": \"Add spending account\"\n  },\n  \"buttons\": {\n    \"back\": \"Back\",\n    \"buy\": \"Buy\",\n    \"sell\": \"Sell\",\n    \"buy_your_first_coins\": \"Buy Munt\",\n    \"clear\": \"Clear\",\n    \"confirm\": \"Confirm\",\n    \"cancel\": \"Cancel\",\n    \"change_password\": \"Change password\",\n    \"create_mining_account\": \"Create mining account\",\n    \"finish\": \"Finish\",\n    \"lock\": \"Lock\",\n    \"next\": \"Next\",\n    \"ok\": \"OK\",\n    \"previous\": \"Previous\",\n    \"ready\": \"Ready\",\n    \"receive\": \"Receive\",\n    \"download\": \"Download\",\n    \"renew\": \"Renew\",\n    \"send\": \"Send\",\n    \"start\": \"Start\",\n    \"stop\": \"Stop\",\n    \"transactions\": \"Transactions\",\n    \"unlock\": \"Unlock\",\n    \"done\": \"Done\",\n    \"saving_key\": \"Witness Key\",\n    \"info\": \"Info\",\n    \"optimise\": \"Optimise\"\n  },\n  \"clipboard_field\": {\n    \"copied_to_clipboard\": \"Copied to clipboard\"\n  },\n  \"common\": {\n    \"account_name\": \"Account name\",\n    \"amount\": \"Amount\",\n    \"enter_your_password\": \"Enter your password\",\n    \"important\": \"Important\",\n    \"information\": \"Information\",\n    \"months\": \"Months\",\n    \"on\": \"on\",\n    \"off\": \"off\",\n    \"password\": \"Password\",\n    \"receiving_address\": \"Receiving address\",\n    \"days\": \"days\",\n    \"ticker_symbol\": \"MUNT\"\n  },\n  \"new_wallet\": {\n    \"title\": \"Welcome to your Munt wallet\",\n    \"information\": \"This wallet is only stored on your device.\\nNever give anyone else access to your wallet.\\nKeep the backup phrase you see at installation in a safe place.\\nLose phrase or someone else with access to the phrase = lose Munt.\"\n  },\n  \"saving_account\": {\n    \"compound_earnings\": \"Compound Earnings\",\n    \"status\": \"Status\",\n    \"parts\": \"Parts\",\n    \"coins_locked\": \"Initial amount locked\",\n    \"coins_earned\": \"Amount earned\",\n    \"locked_from_block\": \"Locked from block\",\n    \"locked_until_block\": \"Locked until block\",\n    \"lock_duration\": \"Lock duration\",\n    \"blocks\": \"blocks\",\n    \"remaining_lock_period\": \"Remaining lock period\",\n    \"required_earnings_frequency\": \"Required earnings frequency\",\n    \"expected_earnings_frequency\": \"Expected earnings frequency\",\n    \"account_weight\": \"Account weight\",\n    \"network_weight\": \"Network weight\",\n    \"empty\": \"This witness account is empty\",\n    \"percent\": \"%\",\n    \"add_to_holdin\": \"Add to holdin.com\",\n    \"remove_from_holdin\": \"Remove from holdin.com\",\n    \"optimise_holding_account\": \"Select Funding Account\",\n    \"optimise_info\": \"Your account currently has {parts} parts. After optimisation, your account will have {futureOptimalAmount} parts.\"\n  },\n  \"loader\": {\n    \"shutdown\": \"Shutting down...\",\n    \"synchronizing\": \"Your wallet is now synchronizing with the Munt network. This may take some time to complete.\"\n  },\n  \"mining\": {\n    \"arena_setup_time\": \"Arena setup time\",\n    \"best_reported_speed\": \"Best reported speed\",\n    \"last_reported_speed\": \"Last reported speed\",\n    \"memory_to_use\": \"Memory usage\",\n    \"moving_average\": \"Moving average\",\n    \"number_of_threads\": \"Number of threads\",\n    \"number_of_arena_threads\": \"Number of arena setup threads\",\n    \"statistics\": \"Statistics\",\n    \"thread\": \"thread | threads\",\n    \"settings\": \"Settings\",\n    \"current_of_max\": \"{current} of {max}\",\n    \"warning_performance\": \"Performance is degraded due to reduced memory usage\",\n    \"address\": \"My Mining Address\"\n  },\n  \"password_dialog\": {\n    \"unlock_wallet\": \"Unlock wallet\"\n  },\n  \"settings\": {\n    \"header\": \"Settings\",\n    \"change_password\": \"Change password\",\n    \"view_recovery_phrase\": \"View recovery phrase\",\n    \"choose_theme\": \"Theme\",\n    \"choose_language\": \"Language\",\n    \"choose_decimal_places\": \"Decimal places\",\n    \"english\": \"EN\",\n    \"dutch\": \"NL\",\n    \"select_display_currency\": \"Select Display Currency\"\n  },\n  \"setup\": {\n    \"choose_password\": \"Choose a password of at least 6 characters\",\n    \"choose_password_information\": \"You will need your password to unlock your wallet.\",\n    \"create_new\": \"I want to create a new wallet\",\n    \"enter_existing_recovery_phrase\": \"Enter your recovery phrase in the boxes below to restore your wallet.\",\n    \"enter_recovery_phrase\": \"Enter recovery phrase\",\n    \"invalid_recovery_phrase\": {\n      \"title\": \"Invalid recovery phrase\",\n      \"message\": \"This combination is not a valid recovery phrase. Correct the error(s) and try again.\"\n    },\n    \"recover_existing\": \"I want to recover my wallet using my recovery phrase\",\n    \"repeat_password\": \"Repeat password\",\n    \"repeat_your_recovery_phrase\": \"To make sure you have correctly written down your recovery phrase, enter your phrase in the boxes below.\",\n    \"setup_your_wallet\": \"Setup your Munt wallet\",\n    \"this_is_your_recovery_phrase\": \"This is your recovery phrase. Keep your backup phrase in a safe place. Lose phrase or someone else with access to the phrase = lose Munt.\"\n  },\n  \"setup_mining\": {\n    \"title\": \"Setup mining\",\n    \"information\": \"Before you can start mining Munt a mining account needs to be created. Enter your password to unlock your wallet and create a mining account.\"\n  },\n  \"transaction_details\": {\n    \"title\": {\n      \"incoming_transaction\": \"Incoming transaction\",\n      \"outgoing_transaction\": \"Outgoing transaction\"\n    },\n    \"hash\": \"Hash\"\n  },\n  \"receive_coins\": {\n    \"address_copied_to_clipboard\": \"Address copied to clipboard\",\n    \"buy_or_receive_coins\": \"Buy or receive Munt\",\n    \"click_to_copy_qr\": \"Click to copy QR\",\n    \"information\": \"After each transaction you will receive a new address, but the previous address will still work.\",\n    \"your_address\": \"Your Munt address\",\n    \"qr_copied_to_clipboard\": \"QR copied to clipboard\"\n  },\n  \"send_coins\": {\n    \"enter_label\": \"Enter label\",\n    \"enter_coins_address\": \"Enter Munt address\",\n    \"confirm_transaction\": \"Confirm transaction\",\n    \"target_account\": \"Send to account\",\n    \"fee_will_be_subtracted\": \"Fee will be subtracted from the amount\",\n    \"unlock_your_wallet_to_complete_the_transaction\": \"Unlock your wallet to complete the transaction\",\n    \"select_account\": \"Select Account\"\n  },\n  \"renew_saving_account\": {\n    \"funding_account\": \"Pay renewal fee from account\"\n  },\n  \"link_saving_account\": {\n    \"title\": \"Your witness key\",\n    \"information\": \"Use your witness key only for trusted cloud witness services. Your witness key provides access to your rewards, so never show it to other people.\",\n    \"no_funds\": \"Witness account must be funded with locked funds before it is possible to link it with other wallets.\"\n  },\n  \"peers\": {\n    \"node_id\": \"Node ID\",\n    \"node_service\": \"Node/Service\",\n    \"user_agent\": \"User Agent\",\n    \"address\": \"Address\",\n    \"reason\": \"Reason\",\n    \"peers\": \"Peers:\",\n    \"banned_peers\": \"Banned Peers\",\n    \"whitelisted\": \"Whitelisted\",\n    \"direction\": \"Direction\",\n    \"services\": \"Services\",\n    \"starting_block\": \"Starting Block\",\n    \"synced_headers\": \"Synced Headers\",\n    \"synced_blocks\": \"Synced Blocks\",\n    \"ban_score\": \"Ban Score\",\n    \"connection_time\": \"Connection Time\",\n    \"last_send\": \"Last Send\",\n    \"last_receive\": \"Last Receive\",\n    \"sent\": \"Sent\",\n    \"received\": \"Received\",\n    \"ping_time\": \"Ping Time\",\n    \"time_offset\": \"Time Offset\",\n    \"banned_from\": \"Banned From\",\n    \"banned_until\": \"Banned Until\",\n    \"peer_details\": \"Peer Details\",\n    \"ban\": \"Ban\",\n    \"buttons\": {\n      \"clear_banned\": \"Clear banned\",\n      \"disconnect\": \"Disconnect\",\n      \"ban_hour\": \"1 Hour\",\n      \"ban_day\": \"1 Day\",\n      \"ban_week\": \"1 Week\",\n      \"ban_year\": \"1 Year\",\n      \"un_ban\": \"Unban Peer\",\n      \"optimise\": \"Optimise\"\n    }\n  },\n  \"tooltip\": {\n    \"account_balance\": \"Account Balance\",\n    \"wallet_balance\": \"Wallet Balance\",\n    \"total\": \"Total\",\n    \"locked\": \"Locked\",\n    \"spendable\": \"Spendable\",\n    \"pending\": \"Pending\"\n  },\n  \"unlock_wallet_dialog\": {\n    \"title\": \"Unlock wallet\",\n    \"unlock_for\": \"Unlock for...\",\n    \"minute\": \"{n} minute | {n} minutes\"\n  }\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/locales/nl.json",
    "content": "{\n  \"accounts_section\": {\n    \"accounts\": \"Rekeningen\",\n    \"categories\": {\n      \"spending\": \"Betalen\",\n      \"saving\": \"Witness\"\n    }\n  },\n  \"account_settings\": {\n    \"title\": \"Rekening instellingen\",\n    \"name\": \"Naam\"\n  },\n  \"add_saving_account\": {\n    \"daily\": \"per dag\",\n    \"estimated_earnings\": \"Geschatte opbrengst\",\n    \"funding_account\": \"Financieringsrekening\",\n    \"lock_for\": \"Vastzetten voor\",\n    \"overall\": \"totaal\",\n    \"title\": \"Witness rekening aanmaken\"\n  },\n  \"add_spending_account\": {\n    \"title\": \"Betaalrekening aanmaken\"\n  },\n  \"buttons\": {\n    \"back\": \"Terug\",\n    \"buy\": \"Koop\",\n    \"sell\": \"Verkoop\",\n    \"buy_your_first_coins\": \"Koop Munt\",\n    \"clear\": \"Wissen\",\n    \"confirm\": \"Bevestig\",\n    \"cancel\": \"Annuleren\",\n    \"change_password\": \"Verander wachtwoord\",\n    \"create_mining_account\": \"Mining rekening aanmaken\",\n    \"finish\": \"Klaar\",\n    \"lock\": \"Vastzetten\",\n    \"next\": \"Volgende\",\n    \"ok\": \"OK\",\n    \"previous\": \"Vorige\",\n    \"ready\": \"Klaar\",\n    \"receive\": \"Ontvangen\",\n    \"renew\": \"Vernieuwen\",\n    \"send\": \"Versturen\",\n    \"start\": \"Start\",\n    \"stop\": \"Stop\",\n    \"transactions\": \"Transacties\",\n    \"unlock\": \"Ontgrendelen\",\n    \"done\": \"Klaar\",\n    \"saving_key\": \"Witness key\",\n    \"info\": \"Info\",\n    \"optimise\": \"Optimise\"\n  },\n  \"clipboard_field\": {\n    \"copied_to_clipboard\": \"Gekopieërd naar klembord\"\n  },\n  \"common\": {\n    \"account_name\": \"Rekeningnaam\",\n    \"amount\": \"Bedrag\",\n    \"enter_your_password\": \"Voer jouw wachtwoord in\",\n    \"important\": \"Belangrijk\",\n    \"information\": \"Informatie\",\n    \"months\": \"Maanden\",\n    \"on\": \"Aan\",\n    \"off\": \"Uit\",\n    \"password\": \"Wachtwoord\",\n    \"receiving_address\": \"Ontvangstadres\",\n    \"days\": \"Dagen\",\n    \"ticker_symbol\": \"MUNT\"\n  },\n  \"new_wallet\": {\n    \"title\": \"Welkom bij jouw Munt wallet\",\n    \"information\": \"Deze wallet staat alleen op jouw apparaat.\\nGeef nooit iemand anders toegang tot jouw wallet.\\nBewaar de herstelzin die je te zien krijgt tijdens installatie op een veilige plek.\\nHerstelzin kwijt of iemand toegang tot je herstelzin = Munt weg.\"\n  },\n  \"saving_account\": {\n    \"compound_earnings\": \"Cumulatieve Inkomsten\",\n    \"status\": \"Status\",\n    \"parts\": \"Delen\",\n    \"coins_locked\": \"Primair vastgezette aantal\",\n    \"coins_earned\": \"Aantal verdiend\",\n    \"locked_from_block\": \"Vastgezet vanaf blok\",\n    \"locked_until_block\": \"Vastgezet tot blok\",\n    \"lock_duration\": \"Looptijd\",\n    \"blocks\": \"blokken\",\n    \"remaining_lock_period\": \"Resterende looptijd\",\n    \"required_earnings_frequency\": \"Benodigde beloningstijd\",\n    \"expected_earnings_frequency\": \"Verwachte beloningstijd\",\n    \"account_weight\": \"Gewicht\",\n    \"network_weight\": \"Netwerk gewicht\",\n    \"empty\": \"Deze witness rekening is leeg\",\n    \"percent\": \"%\",\n    \"add_to_holdin\": \"Add to holdin.com\",\n    \"remove_from_holdin\": \"Remove from holdin.com\",\n    \"optimise_holding_account\": \"Select Funding Account\"\n  },\n  \"loader\": {\n    \"shutdown\": \"Bezig met afsluiten...\",\n    \"synchronizing\": \"Jouw wallet is aan het synchroniseren met het Munt netwerk. Dit kan enige tijd duren.\"\n  },\n  \"mining\": {\n    \"arena_setup_time\": \"Arena setup tijd\",\n    \"best_reported_speed\": \"Beste geregistreerde snelheid\",\n    \"last_reported_speed\": \"Laatst geregistreerde snelheid\",\n    \"memory_to_use\": \"Geheugengebruik\",\n    \"moving_average\": \"Voortschrijdend gemiddelde\",\n    \"number_of_threads\": \"Aantal threads\",\n    \"number_of_arena_threads\": \"Aantal arena setup threads\",\n    \"statistics\": \"Statistieken\",\n    \"thread\": \"thread | threads\",\n    \"settings\": \"Instellingen\",\n    \"current_of_max\": \"{current} van {max}\",\n    \"warning_performance\": \"Prestaties zijn verminderd door lager geheugengebruik\",\n    \"address\": \"Mining adres\"\n  },\n  \"password_dialog\": {\n    \"unlock_wallet\": \"Ontgrendel wallet\"\n  },\n  \"settings\": {\n    \"header\": \"Instellingen\",\n    \"change_password\": \"Verander wachtwoord\",\n    \"view_recovery_phrase\": \"Bekijk herstelzin\",\n    \"choose_theme\": \"Thema\",\n    \"choose_language\": \"Taal\",\n    \"choose_decimal_places\": \"Aantal decimalen\",\n    \"english\": \"EN\",\n    \"dutch\": \"NL\"\n  },\n  \"setup\": {\n    \"choose_password\": \"Kies een wachtwoord van minimaal 6 karakters.\",\n    \"choose_password_information\": \"Een wachtwoord is vereist voor het ontgrendelen van jouw wallet.\",\n    \"create_new\": \"Ik wil een nieuwe wallet starten\",\n    \"enter_existing_recovery_phrase\": \"Voer jouw herstelzin in om jouw wallet te herstellen.\",\n    \"enter_recovery_phrase\": \"Voer herstelzin in\",\n    \"invalid_recovery_phrase\": {\n      \"title\": \"Ongeldige herstelzin\",\n      \"message\": \"Deze combinatie vormt geen geldige herstelzin. Corrigeer de fout(en) en probeer het nogmaals.\"\n    },\n    \"recover_existing\": \"Ik wil mijn wallet herstellen met mijn herstelzin\",\n    \"repeat_password\": \"Herhaal wachtwoord\",\n    \"repeat_your_recovery_phrase\": \"Voer jouw herstelzin in om te controleren dat je deze goed hebt opgeschreven.\",\n    \"setup_your_wallet\": \"Installeer jouw Munt wallet\",\n    \"this_is_your_recovery_phrase\": \"Dit is jouw herstelzin. Bewaar de herstelzin op een veilige plek. Zin kwijt of iemand toegang tot je zin = Munt weg.\"\n  },\n  \"setup_mining\": {\n    \"title\": \"Mining instellen\",\n    \"information\": \"Voordat je kunt beginnen met minen van Munt moet een mining rekening worden aangemaakt. Voer je wachtwoord in om je wallet te ontgrendelen en een mining rekening aan te maken.\"\n  },\n  \"transaction_details\": {\n    \"title\": {\n      \"incoming_transaction\": \"Inkomende transactie\",\n      \"outgoing_transaction\": \"Uitgaande transactie\"\n    },\n    \"hash\": \"Hash\"\n  },\n  \"receive_coins\": {\n    \"address_copied_to_clipboard\": \"Adres gekopieërd naar klembord\",\n    \"buy_or_receive_coins\": \"Koop of ontvang Munt\",\n    \"click_to_copy_qr\": \"Klik om QR te kopiëren\",\n    \"information\": \"Na iedere transactie krijg je een nieuw adres, maar het vorige adres blijft werken.\",\n    \"your_address\": \"Jouw Munt adres\",\n    \"qr_copied_to_clipboard\": \"QR gekopieërd naar klembord\"\n  },\n  \"send_coins\": {\n    \"enter_label\": \"Voer label in\",\n    \"enter_coins_address\": \"Voer Munt adres in\",\n    \"confirm_transaction\": \"Bevestig transactie\",\n    \"target_account\": \"Verstuur naar rekening\",\n    \"fee_will_be_subtracted\": \"De transactie fee wordt van het bedrag afgehaald\",\n    \"unlock_your_wallet_to_complete_the_transaction\": \"Ontgrendel je portemonnee om de transactie af te ronden\"\n  },\n  \"renew_saving_account\": {\n    \"funding_account\": \"Betaal vergoeding van rekening\"\n  },\n  \"link_saving_account\": {\n    \"title\": \"Jouw witness key\",\n    \"information\": \"Gebruik je witness key alleen voor vertrouwde cloud witness services. Jouw witness key geeft toegang tot jouw beloningen, laat deze dus nooit aan andere mensen zien.\",\n    \"no_funds\": \"Witness rekening moet worden gevuld met vastgezette Munt voordat het mogelijk is om deze te koppelen met andere wallets.\"\n  },\n  \"peers\": {\n    \"node_id\": \"Node ID\",\n    \"node_service\": \"Node/Service\",\n    \"user_agent\": \"User Agent\",\n    \"address\": \"Adres\",\n    \"reason\": \"Reden\",\n    \"peers\": \"Peers:\",\n    \"banned_peers\": \"Geblokeerde Peers\",\n    \"whitelisted\": \"Whitelisted\",\n    \"direction\": \"Richting\",\n    \"services\": \"Services\",\n    \"starting_block\": \"Startende block\",\n    \"synced_headers\": \"Gesyncroniseerde Headers\",\n    \"synced_blocks\": \"Gesyncroniseerde Blocks\",\n    \"ban_score\": \"Blokeer Score\",\n    \"connection_time\": \"Connectietijd\",\n    \"last_send\": \"Laatst verzonden\",\n    \"last_receive\": \"Laatst ontvangen\",\n    \"sent\": \"Verzonden\",\n    \"received\": \"Ontvangen\",\n    \"ping_time\": \"Ping Time\",\n    \"time_offset\": \"Time Offset\",\n    \"banned_from\": \"Geblokkeerd sinds\",\n    \"banned_until\": \"Geblokkeerd tot\",\n    \"peer_details\": \"Peer Details\",\n    \"ban\": \"Blokkeren\",\n    \"buttons\": {\n      \"clear_banned\": \"Alles deblokkeren\",\n      \"disconnect\": \"Verbinden verbreken\",\n      \"ban_hour\": \"1 Uur\",\n      \"ban_day\": \"1 Dag\",\n      \"ban_week\": \"1 Week\",\n      \"ban_year\": \"1 Jaar\",\n      \"un_ban\": \"Deblokkeren\",\n      \"optimise\": \"Optimaliseren\"\n    }\n  },\n  \"tooltip\": {\n    \"account_balance\": \"Account balans\",\n    \"wallet_balance\": \"Portemonnee balans\",\n    \"total\": \"Totaal\",\n    \"locked\": \"Vastgezet\",\n    \"spendable\": \"Te spenderen\",\n    \"pending\": \"In afwachting\"\n  },\n  \"unlock_wallet_dialog\": {\n    \"title\": \"Portemonnee ontgrendelen\",\n    \"unlock_for\": \"Ontgrendelen voor...\",\n    \"minute\": \"{n} minuut | {n} minuten\"\n  }\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/main.js",
    "content": "import Vue from \"vue\";\nimport App from \"./App.vue\";\nimport store from \"./store\";\nimport router from \"./router\";\nimport i18n from \"./i18n\";\n\nimport \"./components\";\n\nimport VueSlider from \"vue-slider-component\";\nimport \"vue-slider-component/theme/antd.css\";\nVue.component(\"VueSlider\", VueSlider);\n\nimport ToggleButton from \"vue-js-toggle-button\";\nVue.use(ToggleButton);\n\nimport PortalVue from \"portal-vue\";\nVue.use(PortalVue);\n\nimport { FontAwesomeIcon } from \"@fortawesome/vue-fontawesome\";\nimport { library } from \"@fortawesome/fontawesome-svg-core\";\nimport {\n  faAngleDoubleLeft,\n  faAngleDoubleRight,\n  faArrowFromBottom,\n  faArrowLeft,\n  faArrowToBottom,\n  faBan,\n  faChevronDown,\n  faChevronRight,\n  faCog,\n  faCopy,\n  faCreditCard,\n  faEraser,\n  faGem,\n  faHourglassStart,\n  faLock,\n  faLongArrowLeft,\n  faLongArrowRight,\n  faPen,\n  faPlus,\n  faSearchMinus,\n  faSearchPlus,\n  faShield,\n  faShieldCheck,\n  faTimes,\n  faUniversity,\n  faUnlock,\n  faUserCircle,\n  faRedoAlt,\n  faKey,\n  faInfoCircle,\n  faExclamationTriangle,\n  faUndo,\n  faTrash,\n  faFileSearch,\n  faDownload\n} from \"@fortawesome/pro-light-svg-icons\";\n\nimport { faListUl, faLongArrowDown } from \"@fortawesome/pro-regular-svg-icons\";\n\nlibrary.add([\n  faAngleDoubleLeft,\n  faAngleDoubleRight,\n  faArrowFromBottom,\n  faArrowLeft,\n  faArrowToBottom,\n  faBan,\n  faChevronDown,\n  faChevronRight,\n  faCog,\n  faCopy,\n  faCreditCard,\n  faEraser,\n  faGem,\n  faHourglassStart,\n  faLock,\n  faLongArrowLeft,\n  faLongArrowRight,\n  faPen,\n  faPlus,\n  faSearchMinus,\n  faSearchPlus,\n  faShield,\n  faShieldCheck,\n  faTimes,\n  faUniversity,\n  faUnlock,\n  faUserCircle,\n  faRedoAlt,\n  faKey,\n  faLongArrowDown,\n  faListUl,\n  faInfoCircle,\n  faExclamationTriangle,\n  faUndo,\n  faTrash,\n  faFileSearch,\n  faDownload\n]);\n\nVue.component(\"fa-icon\", FontAwesomeIcon);\n\nVue.config.productionTip = false;\n\nnew Vue({\n  store,\n  router,\n  i18n,\n  render: h => h(App)\n}).$mount(\"#app\");\n"
  },
  {
    "path": "src/frontend/electron_vue/src/router/index.js",
    "content": "import Vue from \"vue\";\nimport VueRouter from \"vue-router\";\nimport Account from \"../views/Account\";\n\nimport { AccountsController } from \"../unity/Controllers\";\nimport store from \"../store\";\n\nVue.use(VueRouter);\n\nconst routes = [\n  {\n    path: \"/account/:id?\",\n    name: \"account\",\n    props: true,\n    component: Account,\n    children: [\n      {\n        path: \"send\",\n        name: \"send\",\n        component: () => import(/* webpackChunkName: \"account-send\" */ \"../views/Account/SpendingAccount/Send.vue\")\n      },\n      {\n        path: \"receive\",\n        name: \"receive\",\n        component: () => import(/* webpackChunkName: \"account-receive\" */ \"../views/Account/SpendingAccount/Receive.vue\")\n      },\n      {\n        path: \"link-saving-account\",\n        name: \"link-saving-account\",\n        component: () => import(/* webpackChunkName: \"link-saving-account\" */ \"../views/Account/SavingAccount/LinkSavingAccount.vue\")\n      },\n      {\n        path: \"send-saving\",\n        name: \"send-saving\",\n        component: () => import(/* webpackChunkName: \"send-saving\" */ \"../views/Account/MiningAccount/Send.vue\")\n      },\n      {\n        path: \"renew-account\",\n        name: \"renew-account\",\n        component: () => import(/* webpackChunkName: \"renew-account\" */ \"../views/Account/SavingAccount/RenewAccount.vue\")\n      },\n      {\n        path: \"optimise-account\",\n        name: \"optimise-account\",\n        component: () => import(/* webpackChunkName: \"optimise-account\" */ \"../views/Account/SavingAccount/OptimiseAccount.vue\")\n      },\n      {\n        path: \"transactions\",\n        name: \"transactions\",\n        component: () => import(/* webpackChunkName: \"transactions\" */ \"../views/Account/SpendingAccount/Transactions.vue\")\n      }\n    ]\n  },\n  {\n    path: \"/add-saving-account\",\n    name: \"add-saving-account\",\n    component: () => import(/* webpackChunkName: \"add-saving-account\" */ \"../views/Account/SavingAccount/AddSavingAccount.vue\")\n  },\n  {\n    path: \"/add-spending-account\",\n    name: \"add-spending-account\",\n    component: () => import(/* webpackChunkName: \"add-saving-account\" */ \"../views/Account/SpendingAccount/AddSpendingAccount.vue\")\n  },\n  {\n    path: \"/setup\",\n    name: \"setup\",\n    component: () => import(/* webpackChunkName: \"setup\" */ \"../views/Setup.vue\"),\n    meta: {\n      layout: \"setup-layout\"\n    }\n  },\n  {\n    path: \"/settings\",\n    component: () => import(/* webpackChunkName: \"settings\" */ \"../views/Settings\"),\n    children: [\n      {\n        path: \"\",\n        name: \"settings\",\n        component: () => import(/* webpackChunkName: \"settings-list\" */ \"../views/Settings/SettingsList.vue\")\n      },\n      {\n        path: \"view-recovery-phrase\",\n        name: \"view-recovery-phrase\",\n        component: () => import(/* webpackChunkName: \"view-recovery-phrase\" */ \"../views/Settings/ViewRecoveryPhrase.vue\")\n      },\n      {\n        path: \"change-password\",\n        name: \"change-password\",\n        component: () => import(/* webpackChunkName: \"change-password\" */ \"../views/Settings/ChangePassword.vue\")\n      }\n    ]\n  },\n  {\n    path: \"/debug\",\n    name: \"debug\",\n    component: () => import(/* webpackChunkName: \"debug-dialog\" */ \"../views/DebugDialog\")\n  },\n  {\n    path: \"/about\",\n    name: \"about\",\n    component: () => import(/* webpackChunkName: \"about-dialog\" */ \"../views/AboutDialog\")\n  }\n];\n\nconst router = new VueRouter({\n  routes\n});\n\nrouter.beforeEach((to, from, next) => {\n  console.log(`route to ${to.name}`);\n\n  if (to.name === \"account\" && to.params.id !== undefined) {\n    // If the id of the account doesn't change there is no need to call SetActiveAccount\n    // This happens for example when routing from send or receive child view to the transactions view\n    if (to.params.id !== from.params.id) {\n      console.log(`account: ${to.params.id}`);\n\n      // set activity indicator to true when switching accounts\n      store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n\n      // set active account to specified id\n      AccountsController.SetActiveAccount(to.params.id);\n\n      // IMPORTANT: Do not set activity indicator to false here!\n      // 1. AccountsController.SetActiveAccount tells the backend to change the account (but it isn't changed immediately).\n      // 2. When the account has been changed the onActiveAccountChanged handler in unity/LibUnity.js will update the store with new account data.\n      // 3. After the account in the store has been changed the onAccountChanged handler in views/Account/index.vue will set the activity indicator to false.\n    }\n  }\n\n  next();\n});\n\nexport default router;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/index.js",
    "content": "import Vue from \"vue\";\nimport Vuex from \"vuex\";\nimport { createPersistedState, createSharedMutations } from \"vuex-electron\";\nimport syncState from \"./syncState\";\nimport Store from \"electron-store\";\nimport walletPath from \"../walletPath\";\n\nimport modules from \"./modules\";\n\nVue.use(Vuex);\n\nlet userSettingsPersistedState = () => {};\n// create persistate state in main process only\nif (process.type !== \"renderer\") {\n  // use user-settings.json file to store settings in wallet folder\n  let store = new Store({ cwd: walletPath, name: \"user-settings\" });\n\n  userSettingsPersistedState = createPersistedState({\n    storage: store,\n    invertIgnored: true, // use invertIgnored because we only want to store the paths in the ignoredPaths list and only persist on specific commits\n    ignoredPaths: [\n      // only store the paths listed below\n      \"mining.settings\",\n      \"app.language\",\n      \"app.decimals\",\n      \"app.currency\"\n    ],\n    ignoredCommits: [\n      // only update persisted state on commits listed below\n      \"mining/SET_MEMORY_SIZE\",\n      \"mining/SET_THREAD_COUNT\",\n      \"mining/SET_ARENA_THREAD_COUNT\",\n      \"app/SET_LANGUAGE\",\n      \"app/SET_CURRENCY\",\n      \"app/SET_DECIMALS\"\n    ]\n  });\n}\nexport default new Vuex.Store({\n  modules: modules,\n  plugins: [syncState, userSettingsPersistedState, createSharedMutations()]\n});\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/modules/app.js",
    "content": "import AppStatus from \"../../AppStatus\";\nimport { Menu } from \"electron\";\n\nfunction EnableDebugWindowOnCoreReady() {\n  try {\n    let menu = Menu.getApplicationMenu();\n    if (menu === null) return;\n    menu.items.find(x => x.label === \"Help\").submenu.items.find(x => x.label === \"Debug window\").enabled = true;\n  } catch (e) {\n    console.error(e);\n  }\n}\n\nconst app = {\n  namespaced: true,\n  state: {\n    coreReady: false,\n    syncDone: false,\n    activityIndicator: false,\n    splashReady: false,\n    status: AppStatus.start,\n    theme: null,\n    unityVersion: null,\n    walletExists: null,\n    walletVersion: null,\n    rate: null,\n    language: \"en\",\n    decimals: 2,\n    currency: { value: \"Eur\", label: \"Euro\", symbol: \"€\" }\n  },\n  mutations: {\n    SET_CORE_READY(state) {\n      state.coreReady = true;\n    },\n    SET_SYNC_DONE(state) {\n      state.syncDone = true;\n    },\n    SET_SPLASH_READY(state) {\n      state.splashReady = true;\n    },\n    SET_STATUS(state, status) {\n      if (state.status === AppStatus.shutdown) return; // shutdown in progress, do not switch to other status\n      state.status = status;\n    },\n    SET_THEME(state, theme) {\n      state.theme = theme;\n    },\n    SET_UNITY_VERSION(state, version) {\n      state.unityVersion = version;\n    },\n    SET_RATE(state, rate) {\n      state.rate = rate;\n    },\n    SET_CURRENCIES(state, currencies) {\n      state.currencies = currencies;\n    },\n    SET_WALLET_EXISTS(state, walletExists) {\n      state.walletExists = walletExists;\n    },\n    SET_WALLET_VERSION(state, version) {\n      state.walletVersion = version;\n    },\n    SET_ACTIVITY_INDICATOR(state, activityIndicator) {\n      state.activityIndicator = activityIndicator;\n    },\n    SET_LANGUAGE(state, language) {\n      state.language = language;\n    },\n    SET_CURRENCY(state, currency) {\n      state.currency = currency;\n    },\n    SET_DECIMALS(state, decimal) {\n      state.decimals = decimal;\n    }\n  },\n  actions: {\n    SET_CORE_READY({ commit, state }) {\n      commit(\"SET_STATUS\", state.progress === 1 ? AppStatus.ready : AppStatus.synchronize);\n      commit(\"SET_CORE_READY\");\n      EnableDebugWindowOnCoreReady();\n    },\n    SET_SYNC_DONE({ commit }) {\n      commit(\"SET_SYNC_DONE\");\n    },\n    SET_SPLASH_READY({ commit }) {\n      commit(\"SET_SPLASH_READY\");\n    },\n    SET_STATUS({ commit }, status) {\n      commit(\"SET_STATUS\", status);\n    },\n    SET_THEME({ commit }, theme) {\n      commit(\"SET_THEME\", theme);\n    },\n    SET_UNITY_VERSION({ commit }, version) {\n      commit(\"SET_UNITY_VERSION\", version);\n    },\n    SET_RATE({ commit }, rate) {\n      commit(\"SET_RATE\", rate);\n    },\n    SET_CURRENCIES({ commit }, currencies) {\n      commit(\"SET_CURRENCIES\", currencies);\n    },\n    SET_ACTIVITY_INDICATOR({ commit }, activityIndicator) {\n      commit(\"SET_ACTIVITY_INDICATOR\", activityIndicator);\n    },\n    SET_LANGUAGE({ commit }, language) {\n      commit(\"SET_LANGUAGE\", language);\n    },\n    SET_CURRENCY({ commit }, currency) {\n      commit(\"SET_CURRENCY\", currency);\n    },\n    SET_DECIMALS({ commit }, decimal) {\n      commit(\"SET_DECIMALS\", decimal);\n    },\n    SET_WALLET_EXISTS({ commit }, walletExists) {\n      let status = walletExists ? AppStatus.synchronize : AppStatus.setup;\n      commit(\"SET_STATUS\", status);\n      commit(\"SET_WALLET_EXISTS\", walletExists);\n    },\n    SET_WALLET_VERSION({ commit }, version) {\n      commit(\"SET_WALLET_VERSION\", version);\n    }\n  }\n};\n\nexport default app;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/modules/index.js",
    "content": "import app from \"./app\";\nimport mining from \"./mining\";\nimport wallet from \"./wallet\";\n\nconst modules = { app, mining, wallet };\n\nexport default modules;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/modules/mining.js",
    "content": "const mining = {\n  namespaced: true,\n  state: {\n    active: false,\n    stats: null,\n    settings: {\n      memorySize: null,\n      threadCount: null,\n      arenaThreadCount: null\n    }\n  },\n  mutations: {\n    SET_ACTIVE(state, active) {\n      state.active = active;\n    },\n    SET_MEMORY_SIZE(state, memorySize) {\n      state.settings.memorySize = memorySize;\n    },\n    SET_STATS(state, stats) {\n      state.stats = stats;\n    },\n    SET_THREAD_COUNT(state, threadCount) {\n      state.settings.threadCount = threadCount;\n    },\n    SET_ARENA_THREAD_COUNT(state, arenaThreadCount) {\n      state.settings.arenaThreadCount = arenaThreadCount;\n    }\n  },\n  actions: {\n    SET_ACTIVE({ commit }, active) {\n      commit(\"SET_ACTIVE\", active);\n    },\n    SET_MEMORY_SIZE({ commit }, memorySize) {\n      commit(\"SET_MEMORY_SIZE\", memorySize);\n    },\n    SET_STATS({ commit }, stats) {\n      commit(\"SET_STATS\", stats);\n    },\n    SET_THREAD_COUNT({ commit }, threadCount) {\n      commit(\"SET_THREAD_COUNT\", threadCount);\n    },\n    SET_ARENA_THREAD_COUNT({ commit }, arenaThreadCount) {\n      commit(\"SET_ARENA_THREAD_COUNT\", arenaThreadCount);\n    }\n  }\n};\n\nexport default mining;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/modules/wallet.js",
    "content": "const wallet = {\n  namespaced: true,\n  state: {\n    accounts: [],\n    activeAccount: null,\n    balance: null,\n    mutations: null,\n    receiveAddress: null,\n    walletBalance: null,\n    walletPassword: null,\n    unlocked: false\n  },\n  mutations: {\n    SET_ACCOUNTS(state, accounts) {\n      state.accounts = accounts;\n    },\n    SET_ACTIVE_ACCOUNT(state, accountUUID) {\n      state.activeAccount = accountUUID;\n    },\n    SET_BALANCE(state, balance) {\n      state.balance = balance;\n    },\n    SET_MUTATIONS(state, mutations) {\n      state.mutations = mutations;\n    },\n    SET_RECEIVE_ADDRESS(state, receiveAddress) {\n      state.receiveAddress = receiveAddress;\n    },\n    SET_WALLET_BALANCE(state, walletBalance) {\n      state.walletBalance = walletBalance;\n    },\n    SET_WALLET_PASSWORD(state, password) {\n      state.walletPassword = password;\n    },\n    SET_UNLOCKED(state, unlocked) {\n      state.unlocked = unlocked;\n    },\n    SET_WALLET(state, payload) {\n      // batch update state properties from payload\n      for (const [key, value] of Object.entries(payload)) {\n        state[key] = value;\n      }\n    }\n  },\n  actions: {\n    SET_ACCOUNT_NAME({ state, commit }, payload) {\n      let accounts = [...state.accounts];\n      let account = accounts.find(x => x.UUID === payload.accountUUID);\n      account.label = payload.newAccountName;\n      commit(\"SET_ACCOUNTS\", accounts);\n    },\n    SET_ACCOUNTS({ commit }, accounts) {\n      commit(\"SET_ACCOUNTS\", accounts);\n    },\n    SET_ACTIVE_ACCOUNT({ commit }, accountUUID) {\n      // clear mutations and receive address\n      commit(\"SET_RECEIVE_ADDRESS\", { receiveAddress: \"\" });\n      commit(\"SET_ACTIVE_ACCOUNT\", accountUUID);\n      commit(\"SET_MUTATIONS\", { mutations: null });\n    },\n    SET_BALANCE({ commit }, new_balance) {\n      commit(\"SET_BALANCE\", new_balance);\n    },\n    SET_MUTATIONS({ commit }, mutations) {\n      commit(\"SET_MUTATIONS\", mutations);\n    },\n    SET_RECEIVE_ADDRESS({ commit }, receiveAddress) {\n      commit(\"SET_RECEIVE_ADDRESS\", receiveAddress);\n    },\n    SET_WALLET_BALANCE({ commit }, walletBalance) {\n      commit(\"SET_WALLET_BALANCE\", walletBalance);\n    },\n    SET_WALLET_PASSWORD({ commit }, password) {\n      commit(\"SET_WALLET_PASSWORD\", password);\n    },\n    SET_UNLOCKED({ commit }, unlocked) {\n      commit(\"SET_UNLOCKED\", unlocked);\n    },\n    SET_WALLET({ commit }, payload) {\n      commit(\"SET_WALLET\", payload);\n    }\n  },\n  getters: {\n    totalBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.availableIncludingLocked + balance.unconfirmedIncludingLocked + balance.immatureIncludingLocked;\n    },\n    lockedBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.totalLocked;\n    },\n    spendableBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.availableExcludingLocked;\n    },\n    pendingBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.unconfirmedExcludingLocked;\n    },\n    immatureBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.immatureIncludingLocked;\n    },\n    accounts: state => {\n      return state.accounts\n        .filter(x => x.state === \"Normal\")\n        .sort((a, b) => {\n          const labelA = a.label.toUpperCase();\n          const labelB = b.label.toUpperCase();\n\n          let comparison = 0;\n          if (labelA > labelB) {\n            comparison = 1;\n          } else if (labelA < labelB) {\n            comparison = -1;\n          }\n          return comparison;\n        });\n    },\n    account: state => {\n      return state.accounts.find(x => x.UUID === state.activeAccount);\n    },\n    miningAccount: state => {\n      return state.accounts.find(x => x.type === \"Mining\" && x.state === \"Normal\"); // this will retrieve the first account of type Mining\n    }\n  }\n};\n\nexport default wallet;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/store/syncState.js",
    "content": "import { ipcMain, ipcRenderer } from \"electron\";\nimport cloneDeep from \"lodash.clonedeep\";\n\nexport default store => {\n  if (process.type === \"renderer\") {\n    // replace the renderer state by the main state\n    ipcRenderer.on(\"vuex-connected\", (event, state) => {\n      console.log(\"vuex-connected\");\n      let newState = cloneDeep(state);\n      store.replaceState(newState);\n    });\n    // send vuex-connect message to receive the main state\n    ipcRenderer.send(\"vuex-connect\");\n  } else {\n    // on vuex-connect send the current state to the renderer\n    ipcMain.on(\"vuex-connect\", event => {\n      console.log(\"vuex-connect\");\n      event.sender.send(\"vuex-connected\", store.state);\n    });\n  }\n};\n"
  },
  {
    "path": "src/frontend/electron_vue/src/unity/Controllers.js",
    "content": "import { ipcRenderer as ipc } from \"electron-better-ipc\";\n\n/* inject:generated-code */\nclass LibraryController {\n  static async BuildInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.BuildInfoAsync\"));\n  }\n\n  static BuildInfo() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.BuildInfo\"));\n  }\n\n  static async InitWalletFromRecoveryPhraseAsync(phrase, password) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.InitWalletFromRecoveryPhraseAsync\", { phrase, password }));\n  }\n\n  static InitWalletFromRecoveryPhrase(phrase, password) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.InitWalletFromRecoveryPhrase\", phrase, password));\n  }\n\n  static async IsValidLinkURIAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidLinkURIAsync\", { phrase }));\n  }\n\n  static IsValidLinkURI(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidLinkURI\", phrase));\n  }\n\n  static async ReplaceWalletLinkedFromURIAsync(linked_uri, password) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ReplaceWalletLinkedFromURIAsync\", { linked_uri, password }));\n  }\n\n  static ReplaceWalletLinkedFromURI(linked_uri, password) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ReplaceWalletLinkedFromURI\", linked_uri, password));\n  }\n\n  static async EraseWalletSeedsAndAccountsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.EraseWalletSeedsAndAccountsAsync\"));\n  }\n\n  static EraseWalletSeedsAndAccounts() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.EraseWalletSeedsAndAccounts\"));\n  }\n\n  static async IsValidRecoveryPhraseAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidRecoveryPhraseAsync\", { phrase }));\n  }\n\n  static IsValidRecoveryPhrase(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidRecoveryPhrase\", phrase));\n  }\n\n  static async GenerateRecoveryMnemonicAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GenerateRecoveryMnemonicAsync\"));\n  }\n\n  static GenerateRecoveryMnemonic() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GenerateRecoveryMnemonic\"));\n  }\n\n  static async GenerateGenesisKeysAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GenerateGenesisKeysAsync\"));\n  }\n\n  static GenerateGenesisKeys() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GenerateGenesisKeys\"));\n  }\n\n  static async ComposeRecoveryPhraseAsync(mnemonic, birthTime) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ComposeRecoveryPhraseAsync\", { mnemonic, birthTime }));\n  }\n\n  static ComposeRecoveryPhrase(mnemonic, birthTime) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ComposeRecoveryPhrase\", mnemonic, birthTime));\n  }\n\n  static async TerminateUnityLibAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.TerminateUnityLibAsync\"));\n  }\n\n  static TerminateUnityLib() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.TerminateUnityLib\"));\n  }\n\n  static async QRImageFromStringAsync(qr_string, width_hint) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.QRImageFromStringAsync\", { qr_string, width_hint }));\n  }\n\n  static QRImageFromString(qr_string, width_hint) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.QRImageFromString\", qr_string, width_hint));\n  }\n\n  static async GetReceiveAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetReceiveAddressAsync\"));\n  }\n\n  static GetReceiveAddress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetReceiveAddress\"));\n  }\n\n  static async GetRecoveryPhraseAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetRecoveryPhraseAsync\"));\n  }\n\n  static GetRecoveryPhrase() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetRecoveryPhrase\"));\n  }\n\n  static async IsMnemonicWalletAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsMnemonicWalletAsync\"));\n  }\n\n  static IsMnemonicWallet() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsMnemonicWallet\"));\n  }\n\n  static async IsMnemonicCorrectAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsMnemonicCorrectAsync\", { phrase }));\n  }\n\n  static IsMnemonicCorrect(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsMnemonicCorrect\", phrase));\n  }\n\n  static async GetMnemonicDictionaryAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetMnemonicDictionaryAsync\"));\n  }\n\n  static GetMnemonicDictionary() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetMnemonicDictionary\"));\n  }\n\n  static async UnlockWalletAsync(password, timeout_in_seconds) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.UnlockWalletAsync\", { password, timeout_in_seconds }));\n  }\n\n  static UnlockWallet(password, timeout_in_seconds) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.UnlockWallet\", password, timeout_in_seconds));\n  }\n\n  static async LockWalletAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.LockWalletAsync\"));\n  }\n\n  static LockWallet() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.LockWallet\"));\n  }\n\n  static async GetWalletLockStatusAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetWalletLockStatusAsync\"));\n  }\n\n  static GetWalletLockStatus() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetWalletLockStatus\"));\n  }\n\n  static async ChangePasswordAsync(oldPassword, newPassword) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ChangePasswordAsync\", { oldPassword, newPassword }));\n  }\n\n  static ChangePassword(oldPassword, newPassword) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ChangePassword\", oldPassword, newPassword));\n  }\n\n  static async DoRescanAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.DoRescanAsync\"));\n  }\n\n  static DoRescan() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.DoRescan\"));\n  }\n\n  static async IsValidRecipientAsync(request) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidRecipientAsync\", { request }));\n  }\n\n  static IsValidRecipient(request) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidRecipient\", request));\n  }\n\n  static async IsValidNativeAddressAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidNativeAddressAsync\", { address }));\n  }\n\n  static IsValidNativeAddress(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidNativeAddress\", address));\n  }\n\n  static async IsValidBitcoinAddressAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidBitcoinAddressAsync\", { address }));\n  }\n\n  static IsValidBitcoinAddress(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidBitcoinAddress\", address));\n  }\n\n  static async FeeForRecipientAsync(request) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.feeForRecipientAsync\", { request }));\n  }\n\n  static FeeForRecipient(request) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.feeForRecipient\", request));\n  }\n\n  static async PerformPaymentToRecipientAsync(request, substract_fee) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.performPaymentToRecipientAsync\", { request, substract_fee }));\n  }\n\n  static PerformPaymentToRecipient(request, substract_fee) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.performPaymentToRecipient\", request, substract_fee));\n  }\n\n  static async GetTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getTransactionAsync\", { txHash }));\n  }\n\n  static GetTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getTransaction\", txHash));\n  }\n\n  static async ResendTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.resendTransactionAsync\", { txHash }));\n  }\n\n  static ResendTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.resendTransaction\", txHash));\n  }\n\n  static async GetAddressBookRecordsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getAddressBookRecordsAsync\"));\n  }\n\n  static GetAddressBookRecords() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getAddressBookRecords\"));\n  }\n\n  static async AddAddressBookRecordAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.addAddressBookRecordAsync\", { address }));\n  }\n\n  static AddAddressBookRecord(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.addAddressBookRecord\", address));\n  }\n\n  static async DeleteAddressBookRecordAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.deleteAddressBookRecordAsync\", { address }));\n  }\n\n  static DeleteAddressBookRecord(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.deleteAddressBookRecord\", address));\n  }\n\n  static async ResetUnifiedProgressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ResetUnifiedProgressAsync\"));\n  }\n\n  static ResetUnifiedProgress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ResetUnifiedProgress\"));\n  }\n\n  static async GetLastSPVBlockInfosAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getLastSPVBlockInfosAsync\"));\n  }\n\n  static GetLastSPVBlockInfos() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getLastSPVBlockInfos\"));\n  }\n\n  static async GetUnifiedProgressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getUnifiedProgressAsync\"));\n  }\n\n  static GetUnifiedProgress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getUnifiedProgress\"));\n  }\n\n  static async GetMonitoringStatsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getMonitoringStatsAsync\"));\n  }\n\n  static GetMonitoringStats() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getMonitoringStats\"));\n  }\n\n  static async RegisterMonitorListenerAsync(listener) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.RegisterMonitorListenerAsync\", { listener }));\n  }\n\n  static RegisterMonitorListener(listener) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.RegisterMonitorListener\", listener));\n  }\n\n  static async UnregisterMonitorListenerAsync(listener) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.UnregisterMonitorListenerAsync\", { listener }));\n  }\n\n  static UnregisterMonitorListener(listener) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.UnregisterMonitorListener\", listener));\n  }\n\n  static async GetClientInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getClientInfoAsync\"));\n  }\n\n  static GetClientInfo() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getClientInfo\"));\n  }\n}\n\nclass WalletController {\n  static async HaveUnconfirmedFundsAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.HaveUnconfirmedFundsAsync\"));\n  }\n\n  static HaveUnconfirmedFunds() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.HaveUnconfirmedFunds\"));\n  }\n\n  static async GetBalanceSimpleAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetBalanceSimpleAsync\"));\n  }\n\n  static GetBalanceSimple() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetBalanceSimple\"));\n  }\n\n  static async GetBalanceAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetBalanceAsync\"));\n  }\n\n  static GetBalance() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetBalance\"));\n  }\n\n  static async AbandonTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSIWalletController.AbandonTransactionAsync\", { txHash }));\n  }\n\n  static AbandonTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSIWalletController.AbandonTransaction\", txHash));\n  }\n\n  static async GetUUIDAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetUUIDAsync\"));\n  }\n\n  static GetUUID() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetUUID\"));\n  }\n}\n\nclass RpcController {\n  static async ExecuteAsync(command) {\n    return handleError(await ipc.callMain(\"NJSIRpcController.ExecuteAsync\", { command }));\n  }\n\n  static Execute(command) {\n    return handleError(ipc.sendSync(\"NJSIRpcController.Execute\", command));\n  }\n  static async GetAutocompleteListAsync() {\n    return handleError(await ipc.callMain(\"NJSIRpcController.getAutocompleteListAsync\"));\n  }\n\n  static GetAutocompleteList() {\n    return handleError(ipc.sendSync(\"NJSIRpcController.getAutocompleteList\"));\n  }\n}\n\nclass P2pNetworkController {\n  static async DisableNetworkAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.disableNetworkAsync\"));\n  }\n\n  static DisableNetwork() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.disableNetwork\"));\n  }\n\n  static async EnableNetworkAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.enableNetworkAsync\"));\n  }\n\n  static EnableNetwork() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.enableNetwork\"));\n  }\n\n  static async GetPeerInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.getPeerInfoAsync\"));\n  }\n\n  static GetPeerInfo() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.getPeerInfo\"));\n  }\n\n  static async ListBannedPeersAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.listBannedPeersAsync\"));\n  }\n\n  static ListBannedPeers() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.listBannedPeers\"));\n  }\n\n  static async BanPeerAsync(address, banTimeInSeconds) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.banPeerAsync\", { address, banTimeInSeconds }));\n  }\n\n  static BanPeer(address, banTimeInSeconds) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.banPeer\", address, banTimeInSeconds));\n  }\n\n  static async UnbanPeerAsync(address) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.unbanPeerAsync\", { address }));\n  }\n\n  static UnbanPeer(address) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.unbanPeer\", address));\n  }\n\n  static async DisconnectPeerAsync(nodeid) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.disconnectPeerAsync\", { nodeid }));\n  }\n\n  static DisconnectPeer(nodeid) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.disconnectPeer\", nodeid));\n  }\n\n  static async ClearBannedAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.ClearBannedAsync\"));\n  }\n\n  static ClearBanned() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.ClearBanned\"));\n  }\n}\n\nclass AccountsController {\n  static async ListAccountsAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.listAccountsAsync\"));\n  }\n\n  static ListAccounts() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.listAccounts\"));\n  }\n\n  static async SetActiveAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.setActiveAccountAsync\", { accountUUID }));\n  }\n\n  static SetActiveAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.setActiveAccount\", accountUUID));\n  }\n\n  static async GetActiveAccountAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getActiveAccountAsync\"));\n  }\n\n  static GetActiveAccount() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getActiveAccount\"));\n  }\n\n  static async CreateAccountAsync(accountName, accountType) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.createAccountAsync\", { accountName, accountType }));\n  }\n\n  static CreateAccount(accountName, accountType) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.createAccount\", accountName, accountType));\n  }\n\n  static async GetAccountNameAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountNameAsync\", { accountUUID }));\n  }\n\n  static GetAccountName(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountName\", accountUUID));\n  }\n\n  static async RenameAccountAsync(accountUUID, newAccountName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.renameAccountAsync\", { accountUUID, newAccountName }));\n  }\n\n  static RenameAccount(accountUUID, newAccountName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.renameAccount\", accountUUID, newAccountName));\n  }\n\n  static async DeleteAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.deleteAccountAsync\", { accountUUID }));\n  }\n\n  static DeleteAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.deleteAccount\", accountUUID));\n  }\n\n  static async PurgeAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.purgeAccountAsync\", { accountUUID }));\n  }\n\n  static PurgeAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.purgeAccount\", accountUUID));\n  }\n\n  static async GetAccountLinkURIAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountLinkURIAsync\", { accountUUID }));\n  }\n\n  static GetAccountLinkURI(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountLinkURI\", accountUUID));\n  }\n\n  static async GetWitnessKeyURIAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getWitnessKeyURIAsync\", { accountUUID }));\n  }\n\n  static GetWitnessKeyURI(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getWitnessKeyURI\", accountUUID));\n  }\n\n  static async CreateAccountFromWitnessKeyURIAsync(witnessKeyURI, newAccountName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.createAccountFromWitnessKeyURIAsync\", { witnessKeyURI, newAccountName }));\n  }\n\n  static CreateAccountFromWitnessKeyURI(witnessKeyURI, newAccountName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.createAccountFromWitnessKeyURI\", witnessKeyURI, newAccountName));\n  }\n\n  static async GetReceiveAddressAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getReceiveAddressAsync\", { accountUUID }));\n  }\n\n  static GetReceiveAddress(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getReceiveAddress\", accountUUID));\n  }\n\n  static async GetTransactionHistoryAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getTransactionHistoryAsync\", { accountUUID }));\n  }\n\n  static GetTransactionHistory(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getTransactionHistory\", accountUUID));\n  }\n\n  static async GetMutationHistoryAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getMutationHistoryAsync\", { accountUUID }));\n  }\n\n  static GetMutationHistory(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getMutationHistory\", accountUUID));\n  }\n\n  static async GetActiveAccountBalanceAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getActiveAccountBalanceAsync\"));\n  }\n\n  static GetActiveAccountBalance() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getActiveAccountBalance\"));\n  }\n\n  static async GetAccountBalanceAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountBalanceAsync\", { accountUUID }));\n  }\n\n  static GetAccountBalance(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountBalance\", accountUUID));\n  }\n\n  static async GetAllAccountBalancesAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAllAccountBalancesAsync\"));\n  }\n\n  static GetAllAccountBalances() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAllAccountBalances\"));\n  }\n\n  static async AddAccountLinkAsync(accountUUID, serviceName, data) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.addAccountLinkAsync\", { accountUUID, serviceName, data }));\n  }\n\n  static AddAccountLink(accountUUID, serviceName, data) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.addAccountLink\", accountUUID, serviceName, data));\n  }\n\n  static async RemoveAccountLinkAsync(accountUUID, serviceName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.removeAccountLinkAsync\", { accountUUID, serviceName }));\n  }\n\n  static RemoveAccountLink(accountUUID, serviceName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.removeAccountLink\", accountUUID, serviceName));\n  }\n\n  static async ListAccountLinksAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.listAccountLinksAsync\", { accountUUID }));\n  }\n\n  static ListAccountLinks(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.listAccountLinks\", accountUUID));\n  }\n}\n\nclass WitnessController {\n  static async GetNetworkLimitsAsync() {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getNetworkLimitsAsync\"));\n  }\n\n  static GetNetworkLimits() {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getNetworkLimits\"));\n  }\n\n  static async GetEstimatedWeightAsync(amount_to_lock, lock_period_in_blocks) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getEstimatedWeightAsync\", { amount_to_lock, lock_period_in_blocks }));\n  }\n\n  static GetEstimatedWeight(amount_to_lock, lock_period_in_blocks) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getEstimatedWeight\", amount_to_lock, lock_period_in_blocks));\n  }\n\n  static async FundWitnessAccountAsync(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) {\n    return handleError(\n      await ipc.callMain(\"NJSIWitnessController.fundWitnessAccountAsync\", {\n        funding_account_UUID,\n        witness_account_UUID,\n        funding_amount,\n        requestedLockPeriodInBlocks\n      })\n    );\n  }\n\n  static FundWitnessAccount(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) {\n    return handleError(\n      ipc.sendSync(\"NJSIWitnessController.fundWitnessAccount\", funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks)\n    );\n  }\n\n  static async RenewWitnessAccountAsync(funding_account_UUID, witness_account_UUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.renewWitnessAccountAsync\", { funding_account_UUID, witness_account_UUID }));\n  }\n\n  static RenewWitnessAccount(funding_account_UUID, witness_account_UUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.renewWitnessAccount\", funding_account_UUID, witness_account_UUID));\n  }\n\n  static async GetAccountWitnessStatisticsAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getAccountWitnessStatisticsAsync\", { witnessAccountUUID }));\n  }\n\n  static GetAccountWitnessStatistics(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getAccountWitnessStatistics\", witnessAccountUUID));\n  }\n\n  static async SetAccountCompoundingAsync(witnessAccountUUID, percent_to_compount) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.setAccountCompoundingAsync\", { witnessAccountUUID, percent_to_compount }));\n  }\n\n  static SetAccountCompounding(witnessAccountUUID, percent_to_compount) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.setAccountCompounding\", witnessAccountUUID, percent_to_compount));\n  }\n\n  static async IsAccountCompoundingAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.isAccountCompoundingAsync\", { witnessAccountUUID }));\n  }\n\n  static IsAccountCompounding(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.isAccountCompounding\", witnessAccountUUID));\n  }\n\n  static async GetWitnessAddressAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getWitnessAddressAsync\", { witnessAccountUUID }));\n  }\n\n  static GetWitnessAddress(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getWitnessAddress\", witnessAccountUUID));\n  }\n\n  static async GetOptimalWitnessDistributionAsync(amount, durationInBlocks, totalNetworkWeight) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getOptimalWitnessDistributionAsync\", { amount, durationInBlocks, totalNetworkWeight }));\n  }\n\n  static GetOptimalWitnessDistribution(amount, durationInBlocks, totalNetworkWeight) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getOptimalWitnessDistribution\", amount, durationInBlocks, totalNetworkWeight));\n  }\n\n  static async GetOptimalWitnessDistributionForAccountAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getOptimalWitnessDistributionForAccountAsync\", { witnessAccountUUID }));\n  }\n\n  static GetOptimalWitnessDistributionForAccount(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getOptimalWitnessDistributionForAccount\", witnessAccountUUID));\n  }\n\n  static async OptimiseWitnessAccountAsync(witnessAccountUUID, fundingAccountUUID, optimalDistribution) {\n    return handleError(\n      await ipc.callMain(\"NJSIWitnessController.optimiseWitnessAccountAsync\", { witnessAccountUUID, fundingAccountUUID, optimalDistribution })\n    );\n  }\n\n  static OptimiseWitnessAccount(witnessAccountUUID, fundingAccountUUID, optimalDistribution) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.optimiseWitnessAccount\", witnessAccountUUID, fundingAccountUUID, optimalDistribution));\n  }\n}\n\nclass GenerationController {\n  static async StartGenerationAsync(numThreads, numArenaThreads, memoryLimit) {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.startGenerationAsync\", { numThreads, numArenaThreads, memoryLimit }));\n  }\n\n  static StartGeneration(numThreads, numArenaThreads, memoryLimit) {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.startGeneration\", numThreads, numArenaThreads, memoryLimit));\n  }\n\n  static async StopGenerationAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.stopGenerationAsync\"));\n  }\n\n  static StopGeneration() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.stopGeneration\"));\n  }\n\n  static async GetGenerationAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getGenerationAddressAsync\"));\n  }\n\n  static GetGenerationAddress() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getGenerationAddress\"));\n  }\n\n  static async GetGenerationOverrideAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getGenerationOverrideAddressAsync\"));\n  }\n\n  static GetGenerationOverrideAddress() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getGenerationOverrideAddress\"));\n  }\n\n  static async SetGenerationOverrideAddressAsync(overrideAddress) {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.setGenerationOverrideAddressAsync\", { overrideAddress }));\n  }\n\n  static SetGenerationOverrideAddress(overrideAddress) {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.setGenerationOverrideAddress\", overrideAddress));\n  }\n\n  static async GetAvailableCoresAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getAvailableCoresAsync\"));\n  }\n\n  static GetAvailableCores() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getAvailableCores\"));\n  }\n\n  static async GetMinimumMemoryAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getMinimumMemoryAsync\"));\n  }\n\n  static GetMinimumMemory() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getMinimumMemory\"));\n  }\n\n  static async GetMaximumMemoryAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getMaximumMemoryAsync\"));\n  }\n\n  static GetMaximumMemory() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getMaximumMemory\"));\n  }\n}\n\nexport { LibraryController, WalletController, RpcController, P2pNetworkController, AccountsController, WitnessController, GenerationController };\n/* inject:generated-code */\n\nclass BackendUtilities {\n  static GetBuySessionUrl() {\n    return handleError(ipc.sendSync(\"BackendUtilities.GetBuySessionUrl\"));\n  }\n  static GetSellSessionUrl() {\n    return handleError(ipc.sendSync(\"BackendUtilities.GetSellSessionUrl\"));\n  }\n  static holdinAPIActions(witnessKey, action, data) {\n    return handleError(ipc.sendSync(\"BackendUtilities.holdinAPIActions\", { witnessKey, action, data }));\n  }\n}\n\nexport { BackendUtilities };\n\nfunction handleError(response) {\n  if (response.error) {\n    // todo: maybe keep a list of notifications which can be shown\n    console.error(response.error);\n    return null;\n  }\n  return response.result;\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/unity/LibUnity.js",
    "content": "import { app } from \"electron\";\nimport { ipcMain as ipc } from \"electron-better-ipc\";\nimport fs from \"fs\";\nimport axios from \"axios\";\nimport store from \"../store\";\nimport { apiKey } from \"../../holdinAPI\";\n\nimport libUnity from \"native-ext-loader!./lib_unity.node\";\n\nclass LibUnity {\n  constructor(options) {\n    this.initialized = false;\n    this.isTerminated = false;\n    this.isCoreReady = false;\n    this.isMainWindowReady = false;\n\n    this.options = {\n      useTestnet: process.env.UNITY_USE_TESTNET ? process.env.UNITY_USE_TESTNET : false,\n      extraArgs: process.env.UNITY_EXTRA_ARGS ? process.env.UNITY_EXTRA_ARGS : \"\",\n      ...options\n    };\n\n    this.libraryController = new libUnity.NJSILibraryController();\n    this.libraryListener = new libUnity.NJSILibraryListener();\n\n    this.walletController = new libUnity.NJSIWalletController();\n    this.walletListener = new libUnity.NJSIWalletListener();\n\n    this.accountsController = new libUnity.NJSIAccountsController();\n    this.accountsListener = new libUnity.NJSIAccountsListener();\n\n    this.generationController = new libUnity.NJSIGenerationController();\n    this.generationListener = new libUnity.NJSIGenerationListener();\n\n    this.witnessController = new libUnity.NJSIWitnessController();\n\n    this.rpcController = new libUnity.NJSIRpcController();\n\n    this.p2pNetworkController = new libUnity.NJSIP2pNetworkController();\n\n    let buildInfo = this.libraryController.BuildInfo();\n\n    store.dispatch(\"app/SET_UNITY_VERSION\", buildInfo.substr(1, buildInfo.indexOf(\"-\") - 1));\n  }\n\n  SetMainWindowReady() {\n    if (this.isMainWindowReady === true) return; // set core state once\n    this.isMainWindowReady = true;\n    this._setStateWhenCoreAndMainWindowReady();\n  }\n\n  Initialize() {\n    if (this.initialized) return;\n\n    this.initialized = true;\n\n    this._registerIpcHandlers();\n    this._registerSignalHandlers();\n    this._startUnityLib();\n  }\n\n  TerminateUnityLib() {\n    if (this.libraryController === null || this.isTerminated) return;\n    console.log(`terminating unity lib`);\n    // TODO:\n    // Maybe the call to terminate comes before the core is ready.\n    // Then it's better to wait for the coreReady signal and then call TerminateUnityLib\n    this.libraryController.TerminateUnityLib();\n  }\n\n  _initializeWalletController() {\n    console.log(\"_initializeWalletController\");\n\n    this.walletListener.notifyBalanceChange = function (new_balance) {\n      console.log(`walletListener.notifyBalanceChange`);\n      store.dispatch(\"wallet/SET_WALLET_BALANCE\", new_balance);\n    };\n\n    this.walletListener.notifyWalletUnlocked = function () {\n      console.log(\"receive: notifyWalletUnlocked\");\n      store.dispatch(\"wallet/SET_UNLOCKED\", true);\n    };\n\n    this.walletListener.notifyWalletLocked = function () {\n      console.log(\"receive: notifyWalletLocked\");\n      store.dispatch(\"wallet/SET_UNLOCKED\", false);\n    };\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    this.walletListener.notifyCoreWantsUnlock = function (reason) {\n      console.log(\"receive: notifyCoreWantsUnlock\", reason);\n      // TODO: show unlock dialog with reason (localized?)\n    };\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    this.walletListener.notifyCoreInfo = function (type, caption, message) {\n      console.log(\"receive: notifyCoreInfo\", type, caption, message);\n      // TODO: dispatch message event. add message to queue??\n    };\n\n    this.walletController.setListener(this.walletListener);\n  }\n\n  _updateAccounts(dispatch = true) {\n    let accounts = this.accountsController.listAccounts();\n    let accountBalances = this.accountsController.getAllAccountBalances();\n\n    Object.keys(accountBalances).forEach(key => {\n      let currentAccount = accounts.find(x => x.UUID === key);\n      let currentBalance = accountBalances[key];\n\n      currentAccount.balance = currentBalance.availableIncludingLocked + currentBalance.immatureIncludingLocked;\n      currentAccount.allBalances = currentBalance;\n\n      // make sure spendable is always 0 or more\n      currentAccount.spendable = Math.max(currentBalance.availableExcludingLocked, 0);\n    });\n\n    if (dispatch) {\n      store.dispatch(\"wallet/SET_ACCOUNTS\", accounts);\n    }\n    return accounts;\n  }\n\n  _initializeAccountsController() {\n    console.log(\"_initializeAccountsController\");\n\n    let self = this;\n    let libraryController = this.libraryController;\n\n    this.accountsListener.onAccountNameChanged = function (accountUUID, newAccountName) {\n      store.dispatch(\"wallet/SET_ACCOUNT_NAME\", {\n        accountUUID,\n        newAccountName\n      });\n    };\n\n    this.accountsListener.onActiveAccountChanged = function (accountUUID) {\n      // combine all properties into one payload object\n      const receiveAddress = libraryController.GetReceiveAddress();\n      const mutations = libraryController.getMutationHistory();\n      const payload = {\n        activeAccount: accountUUID,\n        receiveAddress,\n        mutations\n      };\n\n      // and then dispatch one event to update alle properties at once\n      store.dispatch(\"wallet/SET_WALLET\", payload);\n    };\n\n    this.accountsListener.onAccountAdded = function () {\n      self._updateAccounts();\n    };\n\n    this.accountsListener.onAccountDeleted = function () {\n      self._updateAccounts();\n    };\n\n    this.accountsController.setListener(this.accountsListener);\n  }\n\n  _initializeGenerationController() {\n    console.log(\"_initializeGenerationController\");\n\n    this.generationListener.onGenerationStarted = function () {\n      console.log(\"GENERATION STARTED\");\n      store.dispatch(\"mining/SET_ACTIVE\", true);\n    };\n\n    this.generationListener.onGenerationStopped = function () {\n      console.log(\"GENERATION STOPPED\");\n\n      store.dispatch(\"mining/SET_ACTIVE\", false);\n      store.dispatch(\"mining/SET_STATS\", null);\n    };\n\n    this.generationListener.onStatsUpdated = function (\n      hashesPerSecond,\n      hashesPerSecondUnit,\n      rollingHashesPerSecond,\n      rollingHashesPerSecondUnit,\n      bestHashesPerSecond,\n      bestHashesPerSecondUnit,\n      arenaSetupTime\n    ) {\n      store.dispatch(\"mining/SET_STATS\", {\n        hashesPerSecond: `${hashesPerSecond.toFixed(2)}${hashesPerSecondUnit}`,\n        rollingHashesPerSecond: `${rollingHashesPerSecond.toFixed(2)}${rollingHashesPerSecondUnit}`,\n        bestHashesPerSecond: `${bestHashesPerSecond.toFixed(2)}${bestHashesPerSecondUnit}`,\n        arenaSetupTime: arenaSetupTime\n      });\n    };\n\n    this.generationController.setListener(this.generationListener);\n  }\n\n  _startUnityLib() {\n    if (!fs.existsSync(this.options.walletPath)) {\n      console.log(`create wallet folder ${this.options.walletPath}`);\n      fs.mkdirSync(this.options.walletPath, { recursive: true });\n    } else {\n      console.log(`wallet folder ${this.options.walletPath} already exists`);\n    }\n\n    var staticFilterPath = \"\";\n    var staticFilterOffset = -1;\n    var staticFilterLength = -1;\n    //Load static filter files here if/when we start using them for non spv clients.\n    var spvMode = false;\n\n    console.log(`init unity lib threaded`);\n    this.libraryController.InitUnityLibThreaded(\n      this.options.walletPath,\n      staticFilterPath,\n      staticFilterOffset,\n      staticFilterLength,\n      this.options.useTestnet,\n      spvMode,\n      this.libraryListener,\n      this.options.extraArgs\n    );\n  }\n\n  _setStateWhenCoreAndMainWindowReady() {\n    if (!this.isCoreReady || !this.isMainWindowReady)\n      return console.log(`isCoreReady: ${this.isCoreReady}, isMainWindowReady: ${this.isMainWindowReady} -> return`);\n    console.log(\"_setStateWhenCoreAndMainWindowReady: start\");\n\n    // code to update the store has been moved to notifySyncDone event handler because that's when we need the data\n\n    // note: for now also dispatch separate \"core ready\" event because it is still needed to enable debug dialog\n    store.dispatch(\"app/SET_CORE_READY\");\n    console.log(\"_setStateWhenCoreAndMainWindowReady: end\");\n  }\n\n  _registerSignalHandlers() {\n    let self = this;\n    let libraryListener = this.libraryListener;\n    let libraryController = this.libraryController;\n\n    let walletController = this.walletController;\n    let accountsController = this.accountsController;\n\n    libraryListener.notifyCoreReady = function () {\n      console.log(\"received: notifyCoreReady\");\n\n      self._initializeWalletController();\n      self._initializeAccountsController();\n      self._initializeGenerationController();\n\n      self.isCoreReady = true;\n      self._setStateWhenCoreAndMainWindowReady();\n    };\n\n    libraryListener.notifySyncDone = function () {\n      console.log(\"received: notifySyncDone\");\n\n      console.log(\"get the wallet balance\");\n      const walletBalance = walletController.GetBalance();\n      console.log(\"get the accounts\");\n      const accounts = self._updateAccounts(false);\n      console.log(\"get the active account\");\n      const activeAccount = accountsController.getActiveAccount();\n      console.log(\"get the receive address\");\n      const receiveAddress = libraryController.GetReceiveAddress();\n      console.log(\"get the mutations\");\n      const mutations = libraryController.getMutationHistory();\n\n      console.log(\"combine data and dispatch SET_WALLET to update the store\");\n      const payload = {\n        accounts,\n        walletBalance,\n        activeAccount,\n        receiveAddress,\n        mutations\n      };\n\n      // and then dispatch one event to update alle properties at once\n      store.dispatch(\"wallet/SET_WALLET\", payload);\n\n      // dispatch SET_SYNC_DONE to notify wallet is synced and ready for use\n      store.dispatch(\"app/SET_SYNC_DONE\");\n    };\n\n    // Note: turned this listener off, only enable it when needed in debug mode\n    // libraryListener.logPrint = function(message) {\n    //   console.log(\"unity_core: \" + message);\n    // };\n\n    libraryListener.notifyBalanceChange = function (new_balance) {\n      console.log(\"received: notifyBalanceChange\");\n      store.dispatch(\"wallet/SET_BALANCE\", new_balance);\n    };\n\n    libraryListener.notifyNewMutation = function (/*mutation, self_committed*/) {\n      console.log(\"received: notifyNewMutation\");\n      store.dispatch(\"wallet/SET_MUTATIONS\", libraryController.getMutationHistory());\n      store.dispatch(\"wallet/SET_RECEIVE_ADDRESS\", libraryController.GetReceiveAddress());\n\n      self._updateAccounts();\n    };\n\n    libraryListener.notifyUpdatedTransaction = function (/*transaction*/) {\n      console.log(\"received: notifyUpdatedTransaction\");\n      store.dispatch(\"wallet/SET_MUTATIONS\", libraryController.getMutationHistory());\n    };\n\n    libraryListener.notifyInitWithExistingWallet = function () {\n      console.log(\"received: notifyInitWithExistingWallet\");\n      store.dispatch(\"app/SET_WALLET_EXISTS\", true);\n    };\n\n    libraryListener.notifyInitWithoutExistingWallet = function () {\n      console.log(\"received: notifyInitWithoutExistingWallet\");\n      self.newRecoveryPhrase = libraryController.GenerateRecoveryMnemonic();\n      store.dispatch(\"app/SET_WALLET_EXISTS\", false);\n    };\n\n    libraryListener.notifyShutdown = function () {\n      //NB! It is important to set the libraryListener to null here as this is the last thing the core lib is waiting on for clean exit; once we set this to null we are free to quit the app\n      libraryListener = null;\n      console.log(\"received: notifyShutdown\");\n      self.isTerminated = true;\n\n      // We call this inside a timeout because if we don't we get a crash on macOS; its not yet 100% clear why but for now its better to just avoid the crash until we can debug further\n      // TODO: Investigate this further\n      setTimeout(function () {\n        app.quit();\n      }, 1000);\n    };\n  }\n\n  _registerIpcHandlers() {\n    // ipc for rpc controller\n    ipc.answerRenderer(\"NJSIRpcController.ExecuteAsync\", async data => {\n      let rpcListener = new libUnity.NJSIRpcListener();\n\n      return new Promise(resolve => {\n        rpcListener.onSuccess = (filteredCommand, result) => {\n          console.log(`RPC success: ${filteredCommand}`);\n          resolve({\n            result: {\n              success: true,\n              data: result,\n              command: filteredCommand\n            }\n          });\n        };\n\n        rpcListener.onError = (filteredCommand, error) => {\n          console.error(`RPC error: ${filteredCommand}`);\n          resolve({\n            result: {\n              success: false,\n              data: error,\n              command: filteredCommand\n            }\n          });\n        };\n\n        this.rpcController.execute(data.command, rpcListener);\n      });\n    });\n\n    ipc.on(\"NJSIRpcController.Execute\", (event, command) => {\n      let rpcListener = new libUnity.NJSIRpcListener();\n\n      rpcListener.onSuccess = (filteredCommand, result) => {\n        console.log(`RPC success: ${filteredCommand}`);\n        event.returnValue = {\n          result: {\n            success: true,\n            data: result,\n            command: filteredCommand\n          }\n        };\n      };\n\n      rpcListener.onError = (filteredCommand, error) => {\n        console.error(`RPC error: ${filteredCommand}`);\n        event.returnValue = {\n          result: {\n            success: false,\n            data: error,\n            command: filteredCommand\n          }\n        };\n      };\n\n      this.rpcController.execute(command, rpcListener);\n    });\n\n    /* inject:generated-code */\n    // Register NJSILibraryController ipc handlers\n    ipc.answerRenderer(\"NJSILibraryController.BuildInfoAsync\", async () => {\n      console.log(`IPC: libraryController.BuildInfoAsync()`);\n      try {\n        let result = this.libraryController.BuildInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.BuildInfo\", event => {\n      console.log(`IPC: libraryController.BuildInfo()`);\n      try {\n        let result = this.libraryController.BuildInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.InitWalletFromRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.InitWalletFromRecoveryPhraseAsync(${data.phrase}, ${data.password})`);\n      try {\n        let result = this.libraryController.InitWalletFromRecoveryPhrase(data.phrase, data.password);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.InitWalletFromRecoveryPhrase\", (event, phrase, password) => {\n      console.log(`IPC: libraryController.InitWalletFromRecoveryPhrase(${phrase}, ${password})`);\n      try {\n        let result = this.libraryController.InitWalletFromRecoveryPhrase(phrase, password);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidLinkURIAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidLinkURIAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsValidLinkURI(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidLinkURI\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsValidLinkURI(${phrase})`);\n      try {\n        let result = this.libraryController.IsValidLinkURI(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ReplaceWalletLinkedFromURIAsync\", async data => {\n      console.log(`IPC: libraryController.ReplaceWalletLinkedFromURIAsync(${data.linked_uri}, ${data.password})`);\n      try {\n        let result = this.libraryController.ReplaceWalletLinkedFromURI(data.linked_uri, data.password);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ReplaceWalletLinkedFromURI\", (event, linked_uri, password) => {\n      console.log(`IPC: libraryController.ReplaceWalletLinkedFromURI(${linked_uri}, ${password})`);\n      try {\n        let result = this.libraryController.ReplaceWalletLinkedFromURI(linked_uri, password);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.EraseWalletSeedsAndAccountsAsync\", async () => {\n      console.log(`IPC: libraryController.EraseWalletSeedsAndAccountsAsync()`);\n      try {\n        let result = this.libraryController.EraseWalletSeedsAndAccounts();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.EraseWalletSeedsAndAccounts\", event => {\n      console.log(`IPC: libraryController.EraseWalletSeedsAndAccounts()`);\n      try {\n        let result = this.libraryController.EraseWalletSeedsAndAccounts();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidRecoveryPhraseAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsValidRecoveryPhrase(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidRecoveryPhrase\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsValidRecoveryPhrase(${phrase})`);\n      try {\n        let result = this.libraryController.IsValidRecoveryPhrase(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GenerateRecoveryMnemonicAsync\", async () => {\n      console.log(`IPC: libraryController.GenerateRecoveryMnemonicAsync()`);\n      try {\n        let result = this.libraryController.GenerateRecoveryMnemonic();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GenerateRecoveryMnemonic\", event => {\n      console.log(`IPC: libraryController.GenerateRecoveryMnemonic()`);\n      try {\n        let result = this.libraryController.GenerateRecoveryMnemonic();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GenerateGenesisKeysAsync\", async () => {\n      console.log(`IPC: libraryController.GenerateGenesisKeysAsync()`);\n      try {\n        let result = this.libraryController.GenerateGenesisKeys();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GenerateGenesisKeys\", event => {\n      console.log(`IPC: libraryController.GenerateGenesisKeys()`);\n      try {\n        let result = this.libraryController.GenerateGenesisKeys();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ComposeRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.ComposeRecoveryPhraseAsync(${data.mnemonic}, ${data.birthTime})`);\n      try {\n        let result = this.libraryController.ComposeRecoveryPhrase(data.mnemonic, data.birthTime);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ComposeRecoveryPhrase\", (event, mnemonic, birthTime) => {\n      console.log(`IPC: libraryController.ComposeRecoveryPhrase(${mnemonic}, ${birthTime})`);\n      try {\n        let result = this.libraryController.ComposeRecoveryPhrase(mnemonic, birthTime);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.TerminateUnityLibAsync\", async () => {\n      console.log(`IPC: libraryController.TerminateUnityLibAsync()`);\n      try {\n        let result = this.libraryController.TerminateUnityLib();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.TerminateUnityLib\", event => {\n      console.log(`IPC: libraryController.TerminateUnityLib()`);\n      try {\n        let result = this.libraryController.TerminateUnityLib();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.QRImageFromStringAsync\", async data => {\n      console.log(`IPC: libraryController.QRImageFromStringAsync(${data.qr_string}, ${data.width_hint})`);\n      try {\n        let result = this.libraryController.QRImageFromString(data.qr_string, data.width_hint);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.QRImageFromString\", (event, qr_string, width_hint) => {\n      console.log(`IPC: libraryController.QRImageFromString(${qr_string}, ${width_hint})`);\n      try {\n        let result = this.libraryController.QRImageFromString(qr_string, width_hint);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetReceiveAddressAsync\", async () => {\n      console.log(`IPC: libraryController.GetReceiveAddressAsync()`);\n      try {\n        let result = this.libraryController.GetReceiveAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetReceiveAddress\", event => {\n      console.log(`IPC: libraryController.GetReceiveAddress()`);\n      try {\n        let result = this.libraryController.GetReceiveAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetRecoveryPhraseAsync\", async () => {\n      console.log(`IPC: libraryController.GetRecoveryPhraseAsync()`);\n      try {\n        let result = this.libraryController.GetRecoveryPhrase();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetRecoveryPhrase\", event => {\n      console.log(`IPC: libraryController.GetRecoveryPhrase()`);\n      try {\n        let result = this.libraryController.GetRecoveryPhrase();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsMnemonicWalletAsync\", async () => {\n      console.log(`IPC: libraryController.IsMnemonicWalletAsync()`);\n      try {\n        let result = this.libraryController.IsMnemonicWallet();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsMnemonicWallet\", event => {\n      console.log(`IPC: libraryController.IsMnemonicWallet()`);\n      try {\n        let result = this.libraryController.IsMnemonicWallet();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsMnemonicCorrectAsync\", async data => {\n      console.log(`IPC: libraryController.IsMnemonicCorrectAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsMnemonicCorrect(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsMnemonicCorrect\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsMnemonicCorrect(${phrase})`);\n      try {\n        let result = this.libraryController.IsMnemonicCorrect(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetMnemonicDictionaryAsync\", async () => {\n      console.log(`IPC: libraryController.GetMnemonicDictionaryAsync()`);\n      try {\n        let result = this.libraryController.GetMnemonicDictionary();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetMnemonicDictionary\", event => {\n      console.log(`IPC: libraryController.GetMnemonicDictionary()`);\n      try {\n        let result = this.libraryController.GetMnemonicDictionary();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.UnlockWalletAsync\", async data => {\n      console.log(`IPC: libraryController.UnlockWalletAsync(${data.password}, ${data.timeout_in_seconds})`);\n      try {\n        let result = this.libraryController.UnlockWallet(data.password, data.timeout_in_seconds);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.UnlockWallet\", (event, password, timeout_in_seconds) => {\n      console.log(`IPC: libraryController.UnlockWallet(${password}, ${timeout_in_seconds})`);\n      try {\n        let result = this.libraryController.UnlockWallet(password, timeout_in_seconds);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.LockWalletAsync\", async () => {\n      console.log(`IPC: libraryController.LockWalletAsync()`);\n      try {\n        let result = this.libraryController.LockWallet();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.LockWallet\", event => {\n      console.log(`IPC: libraryController.LockWallet()`);\n      try {\n        let result = this.libraryController.LockWallet();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetWalletLockStatusAsync\", async () => {\n      console.log(`IPC: libraryController.GetWalletLockStatusAsync()`);\n      try {\n        let result = this.libraryController.GetWalletLockStatus();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetWalletLockStatus\", event => {\n      console.log(`IPC: libraryController.GetWalletLockStatus()`);\n      try {\n        let result = this.libraryController.GetWalletLockStatus();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ChangePasswordAsync\", async data => {\n      console.log(`IPC: libraryController.ChangePasswordAsync(${data.oldPassword}, ${data.newPassword})`);\n      try {\n        let result = this.libraryController.ChangePassword(data.oldPassword, data.newPassword);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ChangePassword\", (event, oldPassword, newPassword) => {\n      console.log(`IPC: libraryController.ChangePassword(${oldPassword}, ${newPassword})`);\n      try {\n        let result = this.libraryController.ChangePassword(oldPassword, newPassword);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.DoRescanAsync\", async () => {\n      console.log(`IPC: libraryController.DoRescanAsync()`);\n      try {\n        let result = this.libraryController.DoRescan();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.DoRescan\", event => {\n      console.log(`IPC: libraryController.DoRescan()`);\n      try {\n        let result = this.libraryController.DoRescan();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidRecipientAsync(${data.request})`);\n      try {\n        let result = this.libraryController.IsValidRecipient(data.request);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidRecipient\", (event, request) => {\n      console.log(`IPC: libraryController.IsValidRecipient(${request})`);\n      try {\n        let result = this.libraryController.IsValidRecipient(request);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidNativeAddressAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidNativeAddressAsync(${data.address})`);\n      try {\n        let result = this.libraryController.IsValidNativeAddress(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidNativeAddress\", (event, address) => {\n      console.log(`IPC: libraryController.IsValidNativeAddress(${address})`);\n      try {\n        let result = this.libraryController.IsValidNativeAddress(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidBitcoinAddressAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidBitcoinAddressAsync(${data.address})`);\n      try {\n        let result = this.libraryController.IsValidBitcoinAddress(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidBitcoinAddress\", (event, address) => {\n      console.log(`IPC: libraryController.IsValidBitcoinAddress(${address})`);\n      try {\n        let result = this.libraryController.IsValidBitcoinAddress(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.feeForRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.feeForRecipientAsync(${data.request})`);\n      try {\n        let result = this.libraryController.feeForRecipient(data.request);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.feeForRecipient\", (event, request) => {\n      console.log(`IPC: libraryController.feeForRecipient(${request})`);\n      try {\n        let result = this.libraryController.feeForRecipient(request);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.performPaymentToRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.performPaymentToRecipientAsync(${data.request}, ${data.substract_fee})`);\n      try {\n        let result = this.libraryController.performPaymentToRecipient(data.request, data.substract_fee);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.performPaymentToRecipient\", (event, request, substract_fee) => {\n      console.log(`IPC: libraryController.performPaymentToRecipient(${request}, ${substract_fee})`);\n      try {\n        let result = this.libraryController.performPaymentToRecipient(request, substract_fee);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getTransactionAsync\", async data => {\n      console.log(`IPC: libraryController.getTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.libraryController.getTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getTransaction\", (event, txHash) => {\n      console.log(`IPC: libraryController.getTransaction(${txHash})`);\n      try {\n        let result = this.libraryController.getTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.resendTransactionAsync\", async data => {\n      console.log(`IPC: libraryController.resendTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.libraryController.resendTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.resendTransaction\", (event, txHash) => {\n      console.log(`IPC: libraryController.resendTransaction(${txHash})`);\n      try {\n        let result = this.libraryController.resendTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getAddressBookRecordsAsync\", async () => {\n      console.log(`IPC: libraryController.getAddressBookRecordsAsync()`);\n      try {\n        let result = this.libraryController.getAddressBookRecords();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getAddressBookRecords\", event => {\n      console.log(`IPC: libraryController.getAddressBookRecords()`);\n      try {\n        let result = this.libraryController.getAddressBookRecords();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.addAddressBookRecordAsync\", async data => {\n      console.log(`IPC: libraryController.addAddressBookRecordAsync(${data.address})`);\n      try {\n        let result = this.libraryController.addAddressBookRecord(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.addAddressBookRecord\", (event, address) => {\n      console.log(`IPC: libraryController.addAddressBookRecord(${address})`);\n      try {\n        let result = this.libraryController.addAddressBookRecord(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.deleteAddressBookRecordAsync\", async data => {\n      console.log(`IPC: libraryController.deleteAddressBookRecordAsync(${data.address})`);\n      try {\n        let result = this.libraryController.deleteAddressBookRecord(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.deleteAddressBookRecord\", (event, address) => {\n      console.log(`IPC: libraryController.deleteAddressBookRecord(${address})`);\n      try {\n        let result = this.libraryController.deleteAddressBookRecord(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ResetUnifiedProgressAsync\", async () => {\n      console.log(`IPC: libraryController.ResetUnifiedProgressAsync()`);\n      try {\n        let result = this.libraryController.ResetUnifiedProgress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ResetUnifiedProgress\", event => {\n      console.log(`IPC: libraryController.ResetUnifiedProgress()`);\n      try {\n        let result = this.libraryController.ResetUnifiedProgress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getLastSPVBlockInfosAsync\", async () => {\n      console.log(`IPC: libraryController.getLastSPVBlockInfosAsync()`);\n      try {\n        let result = this.libraryController.getLastSPVBlockInfos();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getLastSPVBlockInfos\", event => {\n      console.log(`IPC: libraryController.getLastSPVBlockInfos()`);\n      try {\n        let result = this.libraryController.getLastSPVBlockInfos();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getUnifiedProgressAsync\", async () => {\n      console.log(`IPC: libraryController.getUnifiedProgressAsync()`);\n      try {\n        let result = this.libraryController.getUnifiedProgress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getUnifiedProgress\", event => {\n      console.log(`IPC: libraryController.getUnifiedProgress()`);\n      try {\n        let result = this.libraryController.getUnifiedProgress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getMonitoringStatsAsync\", async () => {\n      console.log(`IPC: libraryController.getMonitoringStatsAsync()`);\n      try {\n        let result = this.libraryController.getMonitoringStats();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getMonitoringStats\", event => {\n      console.log(`IPC: libraryController.getMonitoringStats()`);\n      try {\n        let result = this.libraryController.getMonitoringStats();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.RegisterMonitorListenerAsync\", async data => {\n      console.log(`IPC: libraryController.RegisterMonitorListenerAsync(${data.listener})`);\n      try {\n        let result = this.libraryController.RegisterMonitorListener(data.listener);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.RegisterMonitorListener\", (event, listener) => {\n      console.log(`IPC: libraryController.RegisterMonitorListener(${listener})`);\n      try {\n        let result = this.libraryController.RegisterMonitorListener(listener);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.UnregisterMonitorListenerAsync\", async data => {\n      console.log(`IPC: libraryController.UnregisterMonitorListenerAsync(${data.listener})`);\n      try {\n        let result = this.libraryController.UnregisterMonitorListener(data.listener);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.UnregisterMonitorListener\", (event, listener) => {\n      console.log(`IPC: libraryController.UnregisterMonitorListener(${listener})`);\n      try {\n        let result = this.libraryController.UnregisterMonitorListener(listener);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getClientInfoAsync\", async () => {\n      console.log(`IPC: libraryController.getClientInfoAsync()`);\n      try {\n        let result = this.libraryController.getClientInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getClientInfo\", event => {\n      console.log(`IPC: libraryController.getClientInfo()`);\n      try {\n        let result = this.libraryController.getClientInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIWalletController ipc handlers\n    ipc.answerRenderer(\"NJSIWalletController.HaveUnconfirmedFundsAsync\", async () => {\n      console.log(`IPC: walletController.HaveUnconfirmedFundsAsync()`);\n      try {\n        let result = this.walletController.HaveUnconfirmedFunds();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.HaveUnconfirmedFunds\", event => {\n      console.log(`IPC: walletController.HaveUnconfirmedFunds()`);\n      try {\n        let result = this.walletController.HaveUnconfirmedFunds();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetBalanceSimpleAsync\", async () => {\n      console.log(`IPC: walletController.GetBalanceSimpleAsync()`);\n      try {\n        let result = this.walletController.GetBalanceSimple();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetBalanceSimple\", event => {\n      console.log(`IPC: walletController.GetBalanceSimple()`);\n      try {\n        let result = this.walletController.GetBalanceSimple();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetBalanceAsync\", async () => {\n      console.log(`IPC: walletController.GetBalanceAsync()`);\n      try {\n        let result = this.walletController.GetBalance();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetBalance\", event => {\n      console.log(`IPC: walletController.GetBalance()`);\n      try {\n        let result = this.walletController.GetBalance();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.AbandonTransactionAsync\", async data => {\n      console.log(`IPC: walletController.AbandonTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.walletController.AbandonTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.AbandonTransaction\", (event, txHash) => {\n      console.log(`IPC: walletController.AbandonTransaction(${txHash})`);\n      try {\n        let result = this.walletController.AbandonTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetUUIDAsync\", async () => {\n      console.log(`IPC: walletController.GetUUIDAsync()`);\n      try {\n        let result = this.walletController.GetUUID();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetUUID\", event => {\n      console.log(`IPC: walletController.GetUUID()`);\n      try {\n        let result = this.walletController.GetUUID();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIRpcController ipc handlers\n    ipc.answerRenderer(\"NJSIRpcController.getAutocompleteListAsync\", async () => {\n      console.log(`IPC: rpcController.getAutocompleteListAsync()`);\n      try {\n        let result = this.rpcController.getAutocompleteList();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIRpcController.getAutocompleteList\", event => {\n      console.log(`IPC: rpcController.getAutocompleteList()`);\n      try {\n        let result = this.rpcController.getAutocompleteList();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIP2pNetworkController ipc handlers\n    ipc.answerRenderer(\"NJSIP2pNetworkController.disableNetworkAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.disableNetworkAsync()`);\n      try {\n        let result = this.p2pNetworkController.disableNetwork();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.disableNetwork\", event => {\n      console.log(`IPC: p2pNetworkController.disableNetwork()`);\n      try {\n        let result = this.p2pNetworkController.disableNetwork();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.enableNetworkAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.enableNetworkAsync()`);\n      try {\n        let result = this.p2pNetworkController.enableNetwork();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.enableNetwork\", event => {\n      console.log(`IPC: p2pNetworkController.enableNetwork()`);\n      try {\n        let result = this.p2pNetworkController.enableNetwork();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.getPeerInfoAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.getPeerInfoAsync()`);\n      try {\n        let result = this.p2pNetworkController.getPeerInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.getPeerInfo\", event => {\n      console.log(`IPC: p2pNetworkController.getPeerInfo()`);\n      try {\n        let result = this.p2pNetworkController.getPeerInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.listBannedPeersAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.listBannedPeersAsync()`);\n      try {\n        let result = this.p2pNetworkController.listBannedPeers();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.listBannedPeers\", event => {\n      console.log(`IPC: p2pNetworkController.listBannedPeers()`);\n      try {\n        let result = this.p2pNetworkController.listBannedPeers();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.banPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.banPeerAsync(${data.address}, ${data.banTimeInSeconds})`);\n      try {\n        let result = this.p2pNetworkController.banPeer(data.address, data.banTimeInSeconds);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.banPeer\", (event, address, banTimeInSeconds) => {\n      console.log(`IPC: p2pNetworkController.banPeer(${address}, ${banTimeInSeconds})`);\n      try {\n        let result = this.p2pNetworkController.banPeer(address, banTimeInSeconds);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.unbanPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.unbanPeerAsync(${data.address})`);\n      try {\n        let result = this.p2pNetworkController.unbanPeer(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.unbanPeer\", (event, address) => {\n      console.log(`IPC: p2pNetworkController.unbanPeer(${address})`);\n      try {\n        let result = this.p2pNetworkController.unbanPeer(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.disconnectPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.disconnectPeerAsync(${data.nodeid})`);\n      try {\n        let result = this.p2pNetworkController.disconnectPeer(data.nodeid);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.disconnectPeer\", (event, nodeid) => {\n      console.log(`IPC: p2pNetworkController.disconnectPeer(${nodeid})`);\n      try {\n        let result = this.p2pNetworkController.disconnectPeer(nodeid);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.ClearBannedAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.ClearBannedAsync()`);\n      try {\n        let result = this.p2pNetworkController.ClearBanned();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.ClearBanned\", event => {\n      console.log(`IPC: p2pNetworkController.ClearBanned()`);\n      try {\n        let result = this.p2pNetworkController.ClearBanned();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIAccountsController ipc handlers\n    ipc.answerRenderer(\"NJSIAccountsController.listAccountsAsync\", async () => {\n      console.log(`IPC: accountsController.listAccountsAsync()`);\n      try {\n        let result = this.accountsController.listAccounts();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.listAccounts\", event => {\n      console.log(`IPC: accountsController.listAccounts()`);\n      try {\n        let result = this.accountsController.listAccounts();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.setActiveAccountAsync\", async data => {\n      console.log(`IPC: accountsController.setActiveAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.setActiveAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.setActiveAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.setActiveAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.setActiveAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getActiveAccountAsync\", async () => {\n      console.log(`IPC: accountsController.getActiveAccountAsync()`);\n      try {\n        let result = this.accountsController.getActiveAccount();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getActiveAccount\", event => {\n      console.log(`IPC: accountsController.getActiveAccount()`);\n      try {\n        let result = this.accountsController.getActiveAccount();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.createAccountAsync\", async data => {\n      console.log(`IPC: accountsController.createAccountAsync(${data.accountName}, ${data.accountType})`);\n      try {\n        let result = this.accountsController.createAccount(data.accountName, data.accountType);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.createAccount\", (event, accountName, accountType) => {\n      console.log(`IPC: accountsController.createAccount(${accountName}, ${accountType})`);\n      try {\n        let result = this.accountsController.createAccount(accountName, accountType);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountNameAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountNameAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountName(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountName\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountName(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountName(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.renameAccountAsync\", async data => {\n      console.log(`IPC: accountsController.renameAccountAsync(${data.accountUUID}, ${data.newAccountName})`);\n      try {\n        let result = this.accountsController.renameAccount(data.accountUUID, data.newAccountName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.renameAccount\", (event, accountUUID, newAccountName) => {\n      console.log(`IPC: accountsController.renameAccount(${accountUUID}, ${newAccountName})`);\n      try {\n        let result = this.accountsController.renameAccount(accountUUID, newAccountName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.deleteAccountAsync\", async data => {\n      console.log(`IPC: accountsController.deleteAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.deleteAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.deleteAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.deleteAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.deleteAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.purgeAccountAsync\", async data => {\n      console.log(`IPC: accountsController.purgeAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.purgeAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.purgeAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.purgeAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.purgeAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountLinkURIAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountLinkURIAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountLinkURI(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountLinkURI\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountLinkURI(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountLinkURI(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getWitnessKeyURIAsync\", async data => {\n      console.log(`IPC: accountsController.getWitnessKeyURIAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getWitnessKeyURI(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getWitnessKeyURI\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getWitnessKeyURI(${accountUUID})`);\n      try {\n        let result = this.accountsController.getWitnessKeyURI(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.createAccountFromWitnessKeyURIAsync\", async data => {\n      console.log(`IPC: accountsController.createAccountFromWitnessKeyURIAsync(${data.witnessKeyURI}, ${data.newAccountName})`);\n      try {\n        let result = this.accountsController.createAccountFromWitnessKeyURI(data.witnessKeyURI, data.newAccountName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.createAccountFromWitnessKeyURI\", (event, witnessKeyURI, newAccountName) => {\n      console.log(`IPC: accountsController.createAccountFromWitnessKeyURI(${witnessKeyURI}, ${newAccountName})`);\n      try {\n        let result = this.accountsController.createAccountFromWitnessKeyURI(witnessKeyURI, newAccountName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getReceiveAddressAsync\", async data => {\n      console.log(`IPC: accountsController.getReceiveAddressAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getReceiveAddress(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getReceiveAddress\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getReceiveAddress(${accountUUID})`);\n      try {\n        let result = this.accountsController.getReceiveAddress(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getTransactionHistoryAsync\", async data => {\n      console.log(`IPC: accountsController.getTransactionHistoryAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getTransactionHistory(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getTransactionHistory\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getTransactionHistory(${accountUUID})`);\n      try {\n        let result = this.accountsController.getTransactionHistory(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getMutationHistoryAsync\", async data => {\n      console.log(`IPC: accountsController.getMutationHistoryAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getMutationHistory(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getMutationHistory\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getMutationHistory(${accountUUID})`);\n      try {\n        let result = this.accountsController.getMutationHistory(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getActiveAccountBalanceAsync\", async () => {\n      console.log(`IPC: accountsController.getActiveAccountBalanceAsync()`);\n      try {\n        let result = this.accountsController.getActiveAccountBalance();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getActiveAccountBalance\", event => {\n      console.log(`IPC: accountsController.getActiveAccountBalance()`);\n      try {\n        let result = this.accountsController.getActiveAccountBalance();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountBalanceAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountBalanceAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountBalance(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountBalance\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountBalance(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountBalance(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAllAccountBalancesAsync\", async () => {\n      console.log(`IPC: accountsController.getAllAccountBalancesAsync()`);\n      try {\n        let result = this.accountsController.getAllAccountBalances();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAllAccountBalances\", event => {\n      console.log(`IPC: accountsController.getAllAccountBalances()`);\n      try {\n        let result = this.accountsController.getAllAccountBalances();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.addAccountLinkAsync\", async data => {\n      console.log(`IPC: accountsController.addAccountLinkAsync(${data.accountUUID}, ${data.serviceName}, ${data.data})`);\n      try {\n        let result = this.accountsController.addAccountLink(data.accountUUID, data.serviceName, data.data);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.addAccountLink\", (event, accountUUID, serviceName, data) => {\n      console.log(`IPC: accountsController.addAccountLink(${accountUUID}, ${serviceName}, ${data})`);\n      try {\n        let result = this.accountsController.addAccountLink(accountUUID, serviceName, data);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.removeAccountLinkAsync\", async data => {\n      console.log(`IPC: accountsController.removeAccountLinkAsync(${data.accountUUID}, ${data.serviceName})`);\n      try {\n        let result = this.accountsController.removeAccountLink(data.accountUUID, data.serviceName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.removeAccountLink\", (event, accountUUID, serviceName) => {\n      console.log(`IPC: accountsController.removeAccountLink(${accountUUID}, ${serviceName})`);\n      try {\n        let result = this.accountsController.removeAccountLink(accountUUID, serviceName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.listAccountLinksAsync\", async data => {\n      console.log(`IPC: accountsController.listAccountLinksAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.listAccountLinks(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.listAccountLinks\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.listAccountLinks(${accountUUID})`);\n      try {\n        let result = this.accountsController.listAccountLinks(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIWitnessController ipc handlers\n    ipc.answerRenderer(\"NJSIWitnessController.getNetworkLimitsAsync\", async () => {\n      console.log(`IPC: witnessController.getNetworkLimitsAsync()`);\n      try {\n        let result = this.witnessController.getNetworkLimits();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getNetworkLimits\", event => {\n      console.log(`IPC: witnessController.getNetworkLimits()`);\n      try {\n        let result = this.witnessController.getNetworkLimits();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getEstimatedWeightAsync\", async data => {\n      console.log(`IPC: witnessController.getEstimatedWeightAsync(${data.amount_to_lock}, ${data.lock_period_in_blocks})`);\n      try {\n        let result = this.witnessController.getEstimatedWeight(data.amount_to_lock, data.lock_period_in_blocks);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getEstimatedWeight\", (event, amount_to_lock, lock_period_in_blocks) => {\n      console.log(`IPC: witnessController.getEstimatedWeight(${amount_to_lock}, ${lock_period_in_blocks})`);\n      try {\n        let result = this.witnessController.getEstimatedWeight(amount_to_lock, lock_period_in_blocks);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.fundWitnessAccountAsync\", async data => {\n      console.log(\n        `IPC: witnessController.fundWitnessAccountAsync(${data.funding_account_UUID}, ${data.witness_account_UUID}, ${data.funding_amount}, ${data.requestedLockPeriodInBlocks})`\n      );\n      try {\n        let result = this.witnessController.fundWitnessAccount(\n          data.funding_account_UUID,\n          data.witness_account_UUID,\n          data.funding_amount,\n          data.requestedLockPeriodInBlocks\n        );\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.fundWitnessAccount\", (event, funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) => {\n      console.log(\n        `IPC: witnessController.fundWitnessAccount(${funding_account_UUID}, ${witness_account_UUID}, ${funding_amount}, ${requestedLockPeriodInBlocks})`\n      );\n      try {\n        let result = this.witnessController.fundWitnessAccount(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.renewWitnessAccountAsync\", async data => {\n      console.log(`IPC: witnessController.renewWitnessAccountAsync(${data.funding_account_UUID}, ${data.witness_account_UUID})`);\n      try {\n        let result = this.witnessController.renewWitnessAccount(data.funding_account_UUID, data.witness_account_UUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.renewWitnessAccount\", (event, funding_account_UUID, witness_account_UUID) => {\n      console.log(`IPC: witnessController.renewWitnessAccount(${funding_account_UUID}, ${witness_account_UUID})`);\n      try {\n        let result = this.witnessController.renewWitnessAccount(funding_account_UUID, witness_account_UUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getAccountWitnessStatisticsAsync\", async data => {\n      console.log(`IPC: witnessController.getAccountWitnessStatisticsAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getAccountWitnessStatistics(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getAccountWitnessStatistics\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getAccountWitnessStatistics(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getAccountWitnessStatistics(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.setAccountCompoundingAsync\", async data => {\n      console.log(`IPC: witnessController.setAccountCompoundingAsync(${data.witnessAccountUUID}, ${data.percent_to_compount})`);\n      try {\n        let result = this.witnessController.setAccountCompounding(data.witnessAccountUUID, data.percent_to_compount);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.setAccountCompounding\", (event, witnessAccountUUID, percent_to_compount) => {\n      console.log(`IPC: witnessController.setAccountCompounding(${witnessAccountUUID}, ${percent_to_compount})`);\n      try {\n        let result = this.witnessController.setAccountCompounding(witnessAccountUUID, percent_to_compount);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.isAccountCompoundingAsync\", async data => {\n      console.log(`IPC: witnessController.isAccountCompoundingAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.isAccountCompounding(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.isAccountCompounding\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.isAccountCompounding(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.isAccountCompounding(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getWitnessAddressAsync\", async data => {\n      console.log(`IPC: witnessController.getWitnessAddressAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getWitnessAddress(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getWitnessAddress\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getWitnessAddress(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getWitnessAddress(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getOptimalWitnessDistributionAsync\", async data => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionAsync(${data.amount}, ${data.durationInBlocks}, ${data.totalNetworkWeight})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistribution(data.amount, data.durationInBlocks, data.totalNetworkWeight);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getOptimalWitnessDistribution\", (event, amount, durationInBlocks, totalNetworkWeight) => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistribution(${amount}, ${durationInBlocks}, ${totalNetworkWeight})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistribution(amount, durationInBlocks, totalNetworkWeight);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getOptimalWitnessDistributionForAccountAsync\", async data => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionForAccountAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistributionForAccount(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getOptimalWitnessDistributionForAccount\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionForAccount(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistributionForAccount(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.optimiseWitnessAccountAsync\", async data => {\n      console.log(`IPC: witnessController.optimiseWitnessAccountAsync(${data.witnessAccountUUID}, ${data.fundingAccountUUID}, ${data.optimalDistribution})`);\n      try {\n        let result = this.witnessController.optimiseWitnessAccount(data.witnessAccountUUID, data.fundingAccountUUID, data.optimalDistribution);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.optimiseWitnessAccount\", (event, witnessAccountUUID, fundingAccountUUID, optimalDistribution) => {\n      console.log(`IPC: witnessController.optimiseWitnessAccount(${witnessAccountUUID}, ${fundingAccountUUID}, ${optimalDistribution})`);\n      try {\n        let result = this.witnessController.optimiseWitnessAccount(witnessAccountUUID, fundingAccountUUID, optimalDistribution);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIGenerationController ipc handlers\n    ipc.answerRenderer(\"NJSIGenerationController.startGenerationAsync\", async data => {\n      console.log(`IPC: generationController.startGenerationAsync(${data.numThreads}, ${data.numArenaThreads}, ${data.memoryLimit})`);\n      try {\n        let result = this.generationController.startGeneration(data.numThreads, data.numArenaThreads, data.memoryLimit);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.startGeneration\", (event, numThreads, numArenaThreads, memoryLimit) => {\n      console.log(`IPC: generationController.startGeneration(${numThreads}, ${numArenaThreads}, ${memoryLimit})`);\n      try {\n        let result = this.generationController.startGeneration(numThreads, numArenaThreads, memoryLimit);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.stopGenerationAsync\", async () => {\n      console.log(`IPC: generationController.stopGenerationAsync()`);\n      try {\n        let result = this.generationController.stopGeneration();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.stopGeneration\", event => {\n      console.log(`IPC: generationController.stopGeneration()`);\n      try {\n        let result = this.generationController.stopGeneration();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getGenerationAddressAsync\", async () => {\n      console.log(`IPC: generationController.getGenerationAddressAsync()`);\n      try {\n        let result = this.generationController.getGenerationAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getGenerationAddress\", event => {\n      console.log(`IPC: generationController.getGenerationAddress()`);\n      try {\n        let result = this.generationController.getGenerationAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getGenerationOverrideAddressAsync\", async () => {\n      console.log(`IPC: generationController.getGenerationOverrideAddressAsync()`);\n      try {\n        let result = this.generationController.getGenerationOverrideAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getGenerationOverrideAddress\", event => {\n      console.log(`IPC: generationController.getGenerationOverrideAddress()`);\n      try {\n        let result = this.generationController.getGenerationOverrideAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.setGenerationOverrideAddressAsync\", async data => {\n      console.log(`IPC: generationController.setGenerationOverrideAddressAsync(${data.overrideAddress})`);\n      try {\n        let result = this.generationController.setGenerationOverrideAddress(data.overrideAddress);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.setGenerationOverrideAddress\", (event, overrideAddress) => {\n      console.log(`IPC: generationController.setGenerationOverrideAddress(${overrideAddress})`);\n      try {\n        let result = this.generationController.setGenerationOverrideAddress(overrideAddress);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getAvailableCoresAsync\", async () => {\n      console.log(`IPC: generationController.getAvailableCoresAsync()`);\n      try {\n        let result = this.generationController.getAvailableCores();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getAvailableCores\", event => {\n      console.log(`IPC: generationController.getAvailableCores()`);\n      try {\n        let result = this.generationController.getAvailableCores();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getMinimumMemoryAsync\", async () => {\n      console.log(`IPC: generationController.getMinimumMemoryAsync()`);\n      try {\n        let result = this.generationController.getMinimumMemory();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getMinimumMemory\", event => {\n      console.log(`IPC: generationController.getMinimumMemory()`);\n      try {\n        let result = this.generationController.getMinimumMemory();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getMaximumMemoryAsync\", async () => {\n      console.log(`IPC: generationController.getMaximumMemoryAsync()`);\n      try {\n        let result = this.generationController.getMaximumMemory();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getMaximumMemory\", event => {\n      console.log(`IPC: generationController.getMaximumMemory()`);\n      try {\n        let result = this.generationController.getMaximumMemory();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n    /* inject:generated-code */\n\n    ipc.on(\"BackendUtilities.GetBuySessionUrl\", async event => {\n      console.log(`IPC: BackendUtilities.GetBuySessionUrl()`);\n      event.returnValue = {\n        success: true,\n        result: \"https://munt.org/buy\"\n      };\n    });\n\n    ipc.on(\"BackendUtilities.GetSellSessionUrl\", async event => {\n      console.log(`IPC: BackendUtilities.GetSellSessionUrl()`);\n      event.returnValue = {\n        success: true,\n        result: \"https://munt.org/sell\"\n      };\n    });\n\n    ipc.on(\"BackendUtilities.holdinAPIActions\", async (event, params) => {\n      console.log(`IPC: BackendUtilities.holdinAPIActions()`);\n\n      try {\n        let data = {};\n\n        if (params.action == \"payoutaddress\") {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action,\n            payoutaddress: params.data\n          });\n        } else if (params.action == \"distribution\") {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action,\n            compoundpercentage: params.data\n          });\n        } else {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action\n          });\n        }\n\n        var config = {\n          method: \"post\",\n          url: \"https://api.holdin.com/api/v1/\",\n          headers: {\n            Authorization: apiKey,\n            \"Content-Type\": \"application/json\"\n          },\n          data: data\n        };\n\n        axios(config)\n          .then(function (response) {\n            event.returnValue = {\n              success: response.data.status_code === 200,\n              result: response.data\n            };\n          })\n          .catch(function (error) {\n            event.returnValue = handleError(error);\n          });\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n  }\n}\n\nfunction handleError(error) {\n  console.error(error);\n  return {\n    error: error,\n    result: null\n  };\n}\n\nexport default LibUnity;\n"
  },
  {
    "path": "src/frontend/electron_vue/src/util.js",
    "content": "import store from \"./store\";\nimport { Parser } from \"@json2csv/plainjs\";\n\nexport function formatMoneyForDisplay(monetaryAmount, isFiat = false, minimumAmountOfDecimals = 0) {\n  // default use 2 decimals;\n  let decimals = 2;\n\n  // for fiat we always use 2 decimals, but if it's not for fiat...\n  if (!isFiat) {\n    // get number of decimals decimals from state\n    decimals = store.state.app.decimals;\n    // use minimumAmountOfDecimals if it's more than current decimals\n    if (minimumAmountOfDecimals > decimals) {\n      decimals = minimumAmountOfDecimals;\n    }\n  }\n\n  // trunctate the amount to specified decimal places\n  return (Math.floor(monetaryAmount / Math.pow(10, 8 - decimals)) / Math.pow(10, decimals)).toFixed(decimals);\n}\n\nexport function displayToMonetary(displayAmount) {\n  // note: do not divide by 100000000 because it will sometimes give rounding issues\n\n  // convert the amount to string\n  let str = displayAmount.toString();\n  // find the index decimal separator\n  let idx = str.indexOf(\".\");\n\n  // if the decimal separator doesn't exist...\n  if (idx === -1) {\n    // add the decimal separator at the end\n    str += \".\";\n    // and update the index\n    idx = str.length;\n  }\n  // add 8 zeroes at the end, maybe there are too many now\n  str += \"0\".repeat(8);\n  // but here they are removed from the tail\n  str = str.substring(0, idx + 9);\n  // now remove the . and then parse the string to integer\n  return parseInt(str.replace(\".\", \"\"));\n}\n\nfunction formatTime(timestamp) {\n  let date = new Date(timestamp * 1000);\n  return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}, ${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n}\n\nexport function downloadTransactionList(transactions, fileName) {\n  var transformedTransactionArray = [];\n  transactions.forEach(async (tx, index) => {\n    transformedTransactionArray.push({\n      ...tx,\n      timestamp: formatTime(tx.timestamp),\n      change: formatMoneyForDisplay(tx.change)\n    });\n\n    if (index + 1 === transactions.length) {\n      try {\n        const parser = new Parser();\n        const csv = parser.parse(transformedTransactionArray);\n        var blob = new Blob([csv], { type: \"text/csv\" });\n        var url = URL.createObjectURL(blob);\n\n        var downloadLink = document.createElement(\"a\");\n        downloadLink.href = url;\n        downloadLink.setAttribute(\"download\", `${fileName}.csv`);\n        downloadLink.click();\n      } catch (err) {\n        alert(err.message);\n      }\n    }\n  });\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/AboutDialog/index.vue",
    "content": "<template>\n  <div class=\"app-debug\">\n    <modal-dialog v-model=\"modal\" />\n    <div class=\"main scrollable\">\n      Copyright (C) 2023 \"The Centure developers\"<br /><br />\n      This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free\n      Software Foundation; either version 2.1 of the License, or (at your option) any later version.<br /><br />\n      This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n      FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.<br /><br />\n      Portions of this software not written by us, and libraries that we make use of are licensed under a variety of other licenses for more licensing\n      information and a copy of the source code visit <a href=\"https://github.com/muntorg/munt-official/blob/master/COPYING\">our code repository</a\n      ><br /><br />\n      The below is a list of most major libraries used and their licensing, the list may not be comprehensive for a comprehensive list consult the\n      repository.<br />\n      <div class=\"copyright-table-wrapper\">\n        <table class=\"copyright-table\">\n          <tr>\n            <td>Bitcoin</td>\n            <td>The MIT License</td>\n          </tr>\n          <tr>\n            <td>Boost</td>\n            <td>Boost Software License 1.0</td>\n          </tr>\n          <tr>\n            <td>BDB</td>\n            <td>The MIT license</td>\n          </tr>\n          <tr>\n            <td>Cryptopp</td>\n            <td>Boost Software License 1.0</td>\n          </tr>\n          <tr>\n            <td>Electron</td>\n            <td>The MIT License</td>\n          </tr>\n          <tr>\n            <td>Nodejs</td>\n            <td>The MIT License</td>\n          </tr>\n          <tr>\n            <td>OpenSSL</td>\n            <td>Apache License v2</td>\n          </tr>\n          <tr>\n            <td>Protobuf</td>\n            <td>BSD</td>\n          </tr>\n          <tr>\n            <td>ZeroMQ</td>\n            <td>Mozilla Public License 2.0</td>\n          </tr>\n          <tr>\n            <td>Zlib</td>\n            <td>Zlib</td>\n          </tr>\n        </table>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport ModalDialog from \"../../components/ModalDialog\";\nimport EventBus from \"../../EventBus.js\";\n\nexport default {\n  data() {\n    return {\n      modal: null\n    };\n  },\n  components: {\n    ModalDialog\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.closeModal);\n    EventBus.$on(\"show-dialog\", this.showModal);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"close-dialog\", this.closeModal);\n    EventBus.$off(\"show-dialog\", this.showModal);\n  },\n  methods: {\n    closeModal() {\n      this.modal = null;\n    },\n    showModal(modal) {\n      this.modal = modal;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-about {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n  font-size: 0.85em;\n}\n\n.main {\n  height: calc(100% - 48px);\n  padding: 20px;\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n.copyright-table-wrapper {\n  display: block;\n  width: 100%;\n  overflow: hidden;\n  font-size: 0.85em;\n}\n\n.copyright-table {\n  margin-top: 25px;\n  margin-left: auto;\n  margin-right: auto;\n  font-size: 0.9em;\n  font-family: sans-serif;\n  border: 1px solid black;\n  border-collapse: collapse;\n}\n.copyright-table tr {\n  border: 1px solid black;\n  border-collapse: collapse;\n}\n.copyright-table td {\n  padding: 5px;\n  padding-left: 15px;\n  padding-right: 15px;\n  border: 1px solid black;\n  border-collapse: collapse;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/AccountSettings.vue",
    "content": "<template>\n  <div class=\"account-settings flex-col\">\n    <div class=\"main\">\n      <h5>{{ $t(\"account_settings.name\") }}</h5>\n      <input type=\"text\" v-model=\"newAccountName\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { AccountsController } from \"../../unity/Controllers\";\n\nexport default {\n  name: \"AccountSettings\",\n  props: {\n    account: null\n  },\n  data() {\n    return {\n      newAccountName: null\n    };\n  },\n  created() {\n    this.newAccountName = this.account.label;\n  },\n  watch: {\n    newAccountName() {\n      if (this.newAccountName && this.newAccountName !== this.account.label) {\n        AccountsController.RenameAccount(this.account.UUID, this.newAccountName);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.account-settings {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/MiningAccount/Send.vue",
    "content": "<template>\n  <div class=\"send-coins flex-col\">\n    <div class=\"main\">\n      <app-form-field>\n        <input v-model=\"computedAmount\" ref=\"amount\" type=\"text\" readonly />\n      </app-form-field>\n      <app-form-field title=\"send_coins.target_account\">\n        <select-list :options=\"fundingAccounts\" :default=\"fundingAccount\" v-model=\"fundingAccount\" />\n      </app-form-field>\n    </div>\n    <button @click=\"showConfirmation\" :disabled=\"disableSendButton\">\n      {{ $t(\"buttons.send\") }}\n    </button>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { LibraryController, AccountsController } from \"../../../unity/Controllers\";\nimport ConfirmTransactionDialog from \"../SpendingAccount/ConfirmTransactionDialog\";\nimport EventBus from \"@/EventBus\";\n\nexport default {\n  name: \"Send\",\n  data() {\n    return {\n      address: null,\n      fundingAccount: null\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"accounts\", \"account\"]),\n    computedAmount() {\n      return formatMoneyForDisplay(this.account.spendable, false, 8);\n    },\n    fundingAccounts() {\n      return this.accounts.filter(x => x.state === \"Normal\" && [\"Desktop\"].indexOf(x.type) !== -1);\n    },\n    disableSendButton() {\n      if (this.account.spendable <= 0) return true;\n      return false;\n    }\n  },\n  mounted() {\n    this.$refs.amount.focus();\n    EventBus.$on(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  methods: {\n    showConfirmation() {\n      // use the original spendable amount to validate because when you convert the displayed amount back to monetary it can be higher than the original amount!\n      const amount = this.account.spendable;\n\n      // validate the address\n      let address = AccountsController.GetReceiveAddress(this.fundingAccount.UUID);\n      let addressInvalid = !LibraryController.IsValidNativeAddress(address);\n\n      // fixme: when address is invalid the user does not know what's wrong because we don't show an error\n      if (addressInvalid) return;\n\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(\"send_coins.confirm_transaction\"),\n        component: ConfirmTransactionDialog,\n        componentProps: {\n          amount: amount,\n          address: address,\n          subtractFee: true\n        },\n        showButtons: false\n      });\n    },\n    onTransactionSucceeded() {\n      this.$router.push({ name: \"account\" });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.send-coins {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n}\n\nbutton {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/MiningAccount/SetupMining.vue",
    "content": "<template>\n  <div class=\"setup-mining\">\n    <portal to=\"header-slot\">\n      <main-header title=\"setup_mining.title\"></main-header>\n    </portal>\n\n    <content-wrapper content=\"setup_mining.information\">\n      <app-form-field title=\"common.password\">\n        <input type=\"password\" v-model=\"password\" :class=\"computedStatus\" @keydown=\"createMiningAccountOnEnter\" />\n      </app-form-field>\n    </content-wrapper>\n\n    <div class=\"flex-1\"></div>\n    <app-button-section>\n      <button @click=\"createMiningAccount(password)\" :disabled=\"!isEnableMiningButtonEnabled\">\n        {{ $t(\"buttons.create_mining_account\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { LibraryController, AccountsController } from \"../../../unity/Controllers\";\n\nexport default {\n  name: \"SetupMining\",\n  data() {\n    return {\n      password: null,\n      isPasswordInvalid: false\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"walletPassword\"]),\n    ...mapGetters(\"wallet\", [\"miningAccount\"]),\n    computedStatus() {\n      return this.isPasswordInvalid ? \"error\" : \"\";\n    },\n    isEnableMiningButtonEnabled() {\n      return this.password && this.password.trim().length > 0;\n    }\n  },\n  watch: {\n    walletPassword() {\n      this.createMiningAccount(this.walletPassword);\n    }\n  },\n  created() {\n    if (this.walletPassword) {\n      this.createMiningAccount(this.walletPassword);\n    }\n  },\n  methods: {\n    createMiningAccountOnEnter() {\n      this.isPasswordInvalid = false;\n      if (event.keyCode === 13) this.createMiningAccount(this.password);\n    },\n    createMiningAccount(password) {\n      let uuid = null;\n\n      try {\n        // NOTE:\n        // Dont' know if it is actually needed to show the activity indicator when unlockking the wallet and creating the account,\n        // but for now I leave it here.\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n        if (LibraryController.UnlockWallet(password, 120) === false) {\n          this.isPasswordInvalid = true;\n          return;\n        }\n\n        uuid = AccountsController.CreateAccount(\"Munt Mining\", \"Mining\");\n        LibraryController.LockWallet();\n      } finally {\n        // route to the new account when we have a uuid\n        if (uuid) {\n          // activity indicator is set to true in the router, so no need to remove it here\n          this.$router.push({ name: \"account\", params: { id: uuid } });\n        } else {\n          // remove the activity indicator\n          this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n        }\n      }\n    }\n  }\n};\n</script>\n<style lang=\"less\" scoped>\n.setup-mining {\n  display: flex;\n  flex-direction: column;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/MiningAccount/index.vue",
    "content": "<template>\n  <div class=\"mining-account\">\n    <portal to=\"header-slot\">\n      <account-header :account=\"account\"></account-header>\n    </portal>\n\n    <router-view />\n\n    <app-section v-if=\"isMiningView\">\n      <div v-if=\"!isActive\">\n        <div>\n          <app-form-field title=\"mining.address\">\n            <div class=\"address-container\">\n              <div @click=\"editAddress\" v-if=\"!editMiningAddress\" class=\"address-row\">\n                <p class=\"address-value\">{{ miningAddress }}</p>\n              </div>\n              <div v-else class=\"flex flex-row\" style=\"width: 100%\">\n                <input :class=\"computedStatus\" ref=\"miningAddressInput\" type=\"text\" v-model=\"newMiningAddress\" @keydown=\"onKeydown\" />\n              </div>\n              <div class=\"action-row\" v-if=\"!editMiningAddress\">\n                <div @click=\"copyToClipboard\" class=\"action-icon\">\n                  <fa-icon :icon=\"['fal', 'copy']\" />\n                </div>\n                <div @click=\"resetOverrideAddress\" class=\"action-icon\" v-if=\"usingOverride\">\n                  <fa-icon :icon=\"['fal', 'undo']\" />\n                </div>\n                <div @click=\"editAddress\" class=\"action-icon\">\n                  <fa-icon :icon=\"['fal', 'pen']\" />\n                </div>\n              </div>\n            </div>\n            <div style=\"height: 10px\">\n              <span class=\"copy-confirmation\" v-if=\"confirmCopy\"> {{ $t(confirmation) }} </span>\n            </div>\n          </app-form-field>\n        </div>\n\n        <app-form-field title=\"mining.number_of_threads\">\n          <div class=\"flex-row\">\n            <vue-slider :min=\"1\" :max=\"availableCores\" :value=\"currentThreadCount\" v-model=\"currentThreadCount\" class=\"slider\" :disabled=\"isActive\" />\n            <div class=\"slider-info\">\n              {{ currentThreadCount }}\n              {{ $tc(\"mining.thread\", currentThreadCount) }}\n            </div>\n          </div>\n        </app-form-field>\n\n        <app-form-field title=\"mining.number_of_arena_threads\">\n          <div class=\"flex-row\">\n            <vue-slider :min=\"1\" :max=\"availableCores\" :value=\"currentArenaThreadCount\" v-model=\"currentArenaThreadCount\" class=\"slider\" :disabled=\"isActive\" />\n            <div class=\"slider-info\">\n              {{ currentArenaThreadCount }}\n              {{ $tc(\"mining.thread\", currentArenaThreadCount) }}\n            </div>\n          </div>\n        </app-form-field>\n\n        <app-form-field title=\"mining.memory_to_use\">\n          <div class=\"flex-row\">\n            <vue-slider :min=\"minimumMemory\" :max=\"maximumMemory\" :value=\"currentMemorySize\" v-model=\"currentMemorySize\" class=\"slider\" :disabled=\"isActive\" />\n            <div class=\"slider-info\">{{ currentMemorySize }} Gb</div>\n          </div>\n        </app-form-field>\n      </div>\n      <div v-else>\n        <app-form-field class=\"mining-statistics\" title=\"mining.settings\">\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.number_of_threads\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ $t(\"mining.current_of_max\", { current: currentThreadCount, max: availableCores }) }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.number_of_arena_threads\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ $t(\"mining.current_of_max\", { current: currentArenaThreadCount, max: availableCores }) }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div>\n              {{ $t(\"mining.memory_to_use\") }}\n              <fa-icon\n                v-if=\"currentMemorySize < maximumMemory\"\n                class=\"warning\"\n                :title=\"$t('mining.warning_performance')\"\n                :icon=\"['fal', 'fa-exclamation-triangle']\"\n              ></fa-icon>\n            </div>\n            <div class=\"flex-1 align-right\">\n              <span> {{ currentMemorySize }} Gb</span>\n            </div>\n          </div>\n        </app-form-field>\n\n        <app-form-field class=\"mining-statistics\" title=\"mining.statistics\">\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.last_reported_speed\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ hashesPerSecond }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.moving_average\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ rollingHashesPerSecond }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.best_reported_speed\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ bestHashesPerSecond }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div>{{ $t(\"mining.arena_setup_time\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ arenaSetupTime }}\n            </div>\n          </div>\n        </app-form-field>\n      </div>\n    </app-section>\n\n    <button v-if=\"isMiningView\" @click=\"toggleGeneration\" :disabled=\"generationButtonDisabled\">\n      {{ isActive ? $t(\"buttons.stop\") : $t(\"buttons.start\") }}\n    </button>\n\n    <portal to=\"footer-slot\">\n      <div style=\"display: flex\">\n        <footer-button title=\"buttons.info\" :icon=\"['fal', 'info-circle']\" routeName=\"account\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"transactions\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send-saving\" @click=\"routeTo\" />\n      </div>\n    </portal>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { GenerationController, LibraryController } from \"../../../unity/Controllers\";\nimport { clipboard } from \"electron\";\n\nexport default {\n  name: \"MiningAccount\",\n  props: {\n    account: null,\n    confirmation: {\n      type: String,\n      default: \"clipboard_field.copied_to_clipboard\"\n    }\n  },\n  data() {\n    return {\n      currentMemorySize: 2,\n      currentThreadCount: 4,\n      currentArenaThreadCount: 4,\n      availableCores: 0,\n      minimumMemory: 0,\n      maximumMemory: 0,\n      generationButtonDisabled: false,\n      miningAddress: null,\n      editMiningAddress: false,\n      newMiningAddress: null,\n      addressInvalid: false,\n      usingOverride: false,\n      confirmCopy: false\n    };\n  },\n  created() {\n    this.availableCores = GenerationController.GetAvailableCores();\n    this.currentThreadCount = this.settings.threadCount || (this.availableCores < 4 ? 1 : this.availableCores - 2);\n\n    this.currentArenaThreadCount = this.settings.arenaThreadCount || (this.availableCores < 4 ? 1 : this.availableCores / 2);\n\n    this.minimumMemory = 1; // for now just use 1 Gb as a minimum\n    this.maximumMemory = Math.floor(GenerationController.GetMaximumMemory() / 1024);\n    this.currentMemorySize = this.settings.memorySize || this.maximumMemory;\n    const overrideAddress = GenerationController.GetGenerationOverrideAddress();\n    if (overrideAddress) {\n      this.miningAddress = overrideAddress;\n      this.usingOverride = true;\n    } else {\n      this.miningAddress = GenerationController.GetGenerationAddress();\n      this.usingOverride = false;\n    }\n  },\n  computed: {\n    ...mapState(\"mining\", {\n      isActive: \"active\",\n      stats: \"stats\",\n      settings: \"settings\",\n      totalBalanceFiat() {\n        if (!this.rate) return \"\";\n        return `${this.currency.symbol || \"\"} ${formatMoneyForDisplay(this.account.balance * this.rate, true)}`;\n      },\n      balanceForDisplay() {\n        if (this.account.balance == null) return \"\";\n        return formatMoneyForDisplay(this.account.balance);\n      }\n    }),\n    ...mapState(\"app\", [\"rate\", \"currency\"]),\n    isMiningView() {\n      return this.$route.name === \"account\";\n    },\n    hashesPerSecond() {\n      return this.formatStats(this.stats, \"hashesPerSecond\");\n    },\n    rollingHashesPerSecond() {\n      return this.formatStats(this.stats, \"rollingHashesPerSecond\");\n    },\n    bestHashesPerSecond() {\n      return this.formatStats(this.stats, \"bestHashesPerSecond\");\n    },\n    arenaSetupTime() {\n      return this.formatStats(this.stats, \"arenaSetupTime\", \" s\");\n    },\n    computedStatus() {\n      return this.addressInvalid ? \"error\" : \"\";\n    }\n  },\n  watch: {\n    isActive() {\n      this.generationButtonDisabled = false;\n    },\n    currentMemorySize() {\n      this.$store.dispatch(\"mining/SET_MEMORY_SIZE\", this.currentMemorySize);\n    },\n    currentThreadCount() {\n      this.$store.dispatch(\"mining/SET_THREAD_COUNT\", this.currentThreadCount);\n    },\n    currentArenaThreadCount() {\n      this.$store.dispatch(\"mining/SET_ARENA_THREAD_COUNT\", this.currentArenaThreadCount);\n    }\n  },\n  methods: {\n    toggleGeneration() {\n      this.generationButtonDisabled = true;\n      if (this.isActive) {\n        GenerationController.StopGeneration();\n      } else {\n        let result = GenerationController.StartGeneration(this.currentThreadCount, this.currentArenaThreadCount, this.currentMemorySize + \"G\");\n        if (result === false) {\n          // todo: starting failed, notify user\n        }\n      }\n    },\n    routeTo(route) {\n      if (this.$route.name === route) return;\n      this.$router.push({ name: route, params: { id: this.account.UUID } });\n    },\n    formatStats(stats, which, postfix = \"/s\") {\n      if (!stats) return null;\n      const current = stats[which];\n      const result = /[a-z]/i.exec(current);\n      return result === null ? `${current}${postfix}` : `${current.substr(0, result.index)} ${current.substr(result.index)}${postfix}`;\n    },\n    editAddress() {\n      this.newMiningAddress = this.miningAddress;\n      this.editMiningAddress = true;\n      this.$nextTick(() => {\n        this.$refs[\"miningAddressInput\"].focus();\n      });\n    },\n    onKeydown(e) {\n      switch (e.keyCode) {\n        case 13:\n          this.changeAccountAddress();\n          break;\n        case 27:\n          this.editMiningAddress = false;\n          break;\n      }\n    },\n    changeAccountAddress() {\n      if (this.newMiningAddress === \"\") {\n        this.resetOverrideAddress();\n        return;\n      }\n      if (this.newMiningAddress === this.miningAddress) {\n        return;\n      }\n\n      this.addressInvalid = !LibraryController.IsValidNativeAddress(this.newMiningAddress);\n\n      if (this.addressInvalid) {\n        return;\n      }\n\n      GenerationController.SetGenerationOverrideAddress(this.newMiningAddress);\n      this.miningAddress = this.newMiningAddress;\n      this.usingOverride = true;\n      this.editMiningAddress = false;\n    },\n    resetOverrideAddress() {\n      GenerationController.SetGenerationOverrideAddress(\"\");\n      this.miningAddress = GenerationController.GetGenerationAddress();\n      this.usingOverride = false;\n      this.editMiningAddress = false;\n    },\n    copyToClipboard() {\n      clipboard.writeText(this.miningAddress);\n      if (this.confirmation) {\n        this.confirmCopy = true;\n        setTimeout(() => {\n          this.confirmCopy = false;\n        }, 1500);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.mining-account {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n}\n\n.address-container {\n  display: flex;\n  flex-direction: row;\n  width: 100%;\n  height: 40px;\n}\n\n.address-row {\n  height: 40px;\n  margin: 0 -10px;\n  padding: 10px;\n  flex: 1;\n}\n\n.address-value {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  cursor: pointer;\n}\n.action-row {\n  width: 100px;\n  height: 40px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.action-icon {\n  width: 30px;\n  height: 30px;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: 3px;\n}\n\n.action-icon:hover {\n  color: var(--primary-color);\n  background: var(--hover-color);\n}\n\n.copy-confirmation {\n  width: calc(100%) !important;\n  display: flex;\n  justify-content: flex-end;\n}\n\n.slider {\n  width: calc(100% - 100px) !important;\n  display: inline-block;\n}\n\n.slider-info {\n  text-align: right;\n  line-height: 18px;\n  flex: 1;\n}\n\n.mining-statistics .flex-row {\n  line-height: 20px;\n}\n\n.warning {\n  color: var(--error-color);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SavingAccount/AddSavingAccount.vue",
    "content": "<template>\n  <div class=\"add-saving-account\">\n    <portal to=\"header-slot\">\n      <main-header :title=\"$t('add_saving_account.title')\"></main-header>\n    </portal>\n\n    <section class=\"content\">\n      <section class=\"step-1\" v-if=\"current === 1\">\n        <app-form-field title=\"add_saving_account.funding_account\">\n          <select-list :options=\"fundingAccounts\" :default=\"fundingAccount\" v-model=\"fundingAccount\" />\n        </app-form-field>\n        <app-form-field title=\"common.amount\">\n          <input type=\"number\" min=\"50\" v-model=\"amount\" :max=\"maxAmountForAccount\" :class=\"amountClass\" />\n        </app-form-field>\n        <app-form-field title=\"add_saving_account.lock_for\">\n          <div class=\"flex-row\">\n            <vue-slider :min=\"2\" :max=\"36\" class=\"lock-time-slider\" :class=\"lockTimeClass\" :value=\"lockTimeInMonths\" v-model=\"lockTimeInMonths\" />\n            <div class=\"lock-time-info\">{{ lockTimeInMonths }} {{ $t(\"common.months\") }}</div>\n          </div>\n        </app-form-field>\n\n        <app-form-field title=\"add_saving_account.estimated_earnings\" v-if=\"isWeightSufficient\">\n          <div class=\"flex-row\">\n            <div class=\"earnings\">{{ $t(\"add_saving_account.daily\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ this.formatMoneyForDisplay(this.estimatedWeight.estimated_daily_earnings) }}\n            </div>\n          </div>\n          <div class=\"flex-row\">\n            <div class=\"earnings\">{{ $t(\"add_saving_account.overall\") }}</div>\n            <div class=\"flex-1 align-right\">\n              {{ this.formatMoneyForDisplay(this.estimatedWeight.estimated_lifetime_earnings) }}\n            </div>\n          </div>\n        </app-form-field>\n      </section>\n      <section class=\"step-2\" v-else>\n        <app-form-field title=\"common.account_name\">\n          <input type=\"text\" v-model=\"accountName\" maxlength=\"30\" ref=\"accountName\" />\n        </app-form-field>\n      </section>\n    </section>\n\n    <div class=\"flex-1\"></div>\n\n    <app-button-section>\n      <template v-slot:left>\n        <button @click=\"current--\" v-if=\"current !== 1\">\n          {{ $t(\"buttons.previous\") }}\n        </button>\n      </template>\n      <button @click=\"nextStep\" :disabled=\"!isWeightSufficient\" v-if=\"current === 1\">\n        {{ $t(\"buttons.next\") }}\n      </button>\n      <button @click=\"tryCreateAndFundSavingAccount\" :disabled=\"disableLockButton\" v-else>\n        {{ $t(\"buttons.lock\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay, displayToMonetary } from \"../../../util.js\";\nimport { WitnessController, AccountsController } from \"../../../unity/Controllers\";\nimport EventBus from \"../../../EventBus.js\";\n\nexport default {\n  name: \"AddSavingAccount\",\n  data() {\n    return {\n      current: 1,\n      networkLimits: null,\n      accountName: \"\",\n      fundingAccount: null,\n      amount: 50,\n      lockTimeInMonths: 36\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"accounts\"]),\n    amountClass() {\n      return this.amount < parseInt(this.networkLimits.minimum_witness_amount) || this.amount > this.maxAmountForAccount ? \"error\" : \"\";\n    },\n    fundingAccounts() {\n      return this.accounts.filter(x => x.state === \"Normal\" && [\"Desktop\", \"Mining\"].indexOf(x.type) !== -1 && x.balance >= 50);\n    },\n    maxAmountForAccount() {\n      return this.fundingAccount\n        ? Math.floor(this.fundingAccount.balance / 100000000) // make sure balance is divided by 100000000\n        : 0;\n    },\n    lockTimeInBlocks() {\n      return this.lockTimeInMonths * (this.networkLimits.maximum_lock_period_blocks / 36);\n    },\n    isWeightSufficient() {\n      return this.estimatedWeight.weight >= this.networkLimits.minimum_witness_weight;\n    },\n    lockTimeClass() {\n      return this.isWeightSufficient ? \"\" : \"insufficient\";\n    },\n    estimatedWeight() {\n      let estimation = WitnessController.GetEstimatedWeight(displayToMonetary(this.amount), this.lockTimeInBlocks);\n\n      return estimation;\n    },\n    disableLockButton() {\n      if (this.accountName.trim().length === 0) return true;\n      return false;\n    }\n  },\n  created() {\n    this.networkLimits = WitnessController.GetNetworkLimits();\n  },\n  mounted() {\n    if (this.fundingAccounts.length) {\n      this.fundingAccount = this.fundingAccounts[0];\n    }\n  },\n  methods: {\n    formatMoneyForDisplay(amount) {\n      return formatMoneyForDisplay(amount);\n    },\n    nextStep() {\n      this.current++;\n      this.$nextTick(() => {\n        this.$refs.accountName.focus();\n      });\n    },\n    tryCreateAndFundSavingAccount() {\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          let result = null;\n          let uuid = null;\n\n          try {\n            this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n\n            uuid = AccountsController.CreateAccount(this.accountName, \"Witness\");\n\n            // Always lock for slightly longer than the minimum to allow a bit of time for transaction to enter the chain\n            // If we don't then its possible that the transaction becomes invalid before entering the chain\n            let finalLockTime = this.lockTimeInBlocks + 50 < this.networkLimits.maximum_lock_period_blocks ? this.lockTimeInBlocks + 50 : this.lockTimeInBlocks;\n\n            result = WitnessController.FundWitnessAccount(this.fundingAccount.UUID, uuid, this.amount * 100000000, finalLockTime);\n\n            if (result.status !== \"success\") {\n              AccountsController.DeleteAccount(uuid); // something went wrong, so delete the account\n            }\n          } finally {\n            if (result.status === \"success\") {\n              // route to the saving account when successfully created and funded\n              this.$router.push({ name: \"account\", params: { id: uuid } });\n            } else {\n              // remove the activity indicator\n              this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n            }\n          }\n        }\n      });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.add-saving-account {\n  display: flex;\n  flex-direction: column;\n}\n.earnings {\n  line-height: 1.2em;\n}\n.lock-time-slider {\n  width: calc(100% - 100px) !important;\n  display: inline-block;\n}\n.lock-time-info {\n  text-align: right;\n  line-height: 18px;\n  flex: 1;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SavingAccount/LinkSavingAccount.vue",
    "content": "<template>\n  <div class=\"link-saving-account flex-col\">\n    <div class=\"main\">\n      <content-wrapper v-if=\"!hasWitnessKey\" heading=\"link_saving_account.title\" content=\"link_saving_account.information\"> </content-wrapper>\n\n      <content-wrapper v-else heading=\"link_saving_account.title\">\n        <div v-if=\"account.balance > 0\">\n          <div class=\"qr\" @click=\"copyQr\">\n            <vue-qrcode ref=\"qrcode\" class=\"qrcode\" :width=\"280\" :margin=\"0\" :value=\"witnessKey\" :color=\"{ dark: `#000000`, light: `#FFFFFF` }\" />\n          </div>\n          <div class=\"address-row flex-row\">\n            <div class=\"flex-1\" />\n            <clipboard-field class=\"address\" :value=\"witnessKey\" confirmation=\"receive_coins.address_copied_to_clipboard\"></clipboard-field>\n            <div class=\"flex-1\" />\n          </div>\n        </div>\n        <div v-if=\"account.balance === 0\">\n          <p class=\"information\">{{ $t(\"link_saving_account.no_funds\") }}</p>\n        </div>\n      </content-wrapper>\n    </div>\n    <app-button-section>\n      <button @click=\"tryGetWitnessKey\" v-if=\"!hasWitnessKey\">\n        {{ $t(\"buttons.next\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n<script>\nimport { mapGetters } from \"vuex\";\nimport { clipboard, nativeImage } from \"electron\";\nimport { AccountsController } from \"../../../unity/Controllers\";\nimport VueQrcode from \"vue-qrcode\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"LinkSavingAccount\",\n  components: {\n    VueQrcode\n  },\n  data() {\n    return {\n      witnessKey: null\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"account\"]),\n    hasWitnessKey() {\n      return this.witnessKey !== null;\n    }\n  },\n  methods: {\n    tryGetWitnessKey() {\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          this.witnessKey = AccountsController.GetWitnessKeyURI(this.account.UUID);\n        }\n      });\n    },\n    copyQr() {\n      let img = nativeImage.createFromDataURL(this.$refs.qrcode.$el.src);\n      clipboard.writeImage(img);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.link-saving-account {\n  height: 100%;\n  text-align: center;\n\n  .main {\n    flex: 1;\n  }\n\n  & .qr {\n    text-align: center;\n    cursor: pointer;\n    margin: 0 auto;\n  }\n  & .qrcode {\n    width: 100%;\n    max-width: 140px;\n  }\n  & .address-row {\n    width: 100%;\n    text-align: center;\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    flex-wrap: wrap;\n  }\n  & .address {\n    width: 100%;\n    margin: 5px 0 0 0;\n    font-weight: 500;\n    font-size: 1em;\n    line-height: 1.4em;\n    word-wrap: break-word;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SavingAccount/OptimiseAccount.vue",
    "content": "<template>\n  <div class=\"send-coins flex-col\">\n    <portal to=\"sidebar-right-title\">\n      {{ $t(\"buttons.optimise\") }}\n    </portal>\n\n    <div class=\"main\">\n      <p>\n        {{ $t(\"saving_account.optimise_info\", { parts: parts, futureOptimalAmount: futureOptimalAmount }) }}\n      </p>\n      <app-form-field title=\"saving_account.optimise_holding_account\">\n        <select-list :options=\"fundingAccounts\" :default=\"fundingAccount\" v-model=\"fundingAccount\" />\n      </app-form-field>\n\n      <input\n        v-model=\"password\"\n        type=\"password\"\n        v-show=\"walletPassword === null\"\n        :placeholder=\"$t('common.enter_your_password')\"\n        :class=\"passwordClass\"\n        @keydown=\"onPasswordKeydown\"\n      />\n    </div>\n    <button @click=\"tryOptimise\" :disabled=\"disableSendButton\">\n      {{ $t(\"buttons.optimise\") }}\n    </button>\n  </div>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { LibraryController, AccountsController, WitnessController } from \"../../../unity/Controllers\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"OptimiseAccount\",\n  data() {\n    return {\n      password: null,\n      fundingAccount: null,\n      isAmountInvalid: false,\n      isPasswordInvalid: false,\n      parts: null,\n      futureOptimalAmount: null\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"walletPassword\"]),\n    ...mapGetters(\"wallet\", [\"accounts\", \"account\"]),\n    computedPassword() {\n      return this.walletPassword ? this.walletPassword : this.password || \"\";\n    },\n    passwordClass() {\n      return this.isPasswordInvalid ? \"error\" : \"\";\n    },\n    fundingAccounts() {\n      return this.accounts.filter(x => x.state === \"Normal\" && [\"Desktop\"].indexOf(x.type) !== -1);\n    },\n    hasErrors() {\n      return this.isPasswordInvalid;\n    },\n    disableSendButton() {\n      if (this.computedPassword.trim().length === 0) return true;\n      return false;\n    },\n    accountParts() {\n      return this.getStatistics(\"account_parts\");\n    }\n  },\n  mounted() {\n    const stats = WitnessController.GetAccountWitnessStatistics(this.account.UUID);\n    this.parts = stats[\"account_parts\"];\n\n    let optimalAmounts = WitnessController.GetOptimalWitnessDistributionForAccount(this.account.UUID);\n    this.futureOptimalAmount = optimalAmounts.length;\n\n    if (this.fundingAccounts.length) {\n      this.fundingAccount = this.fundingAccounts[0];\n    }\n  },\n  methods: {\n    onPasswordKeydown() {\n      this.isPasswordInvalid = false;\n    },\n    tryOptimise() {\n      if (LibraryController.UnlockWallet(this.computedPassword, 120) === false) {\n        this.isPasswordInvalid = true;\n      }\n\n      if (this.hasErrors) {\n        alert(\"Invalid password\");\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n        return;\n      }\n\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n\n      let accountUUID = AccountsController.GetActiveAccount();\n      let optimalAmounts = WitnessController.GetOptimalWitnessDistributionForAccount(accountUUID);\n\n      let result = WitnessController.OptimiseWitnessAccount(this.account.UUID, this.fundingAccount.UUID, optimalAmounts);\n\n      if (result.result === true) {\n        this.password = null;\n        this.fundingAccount = null;\n\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n        EventBus.$emit(\"close-right-sidebar\");\n        alert(\"Operation was successful\");\n      } else {\n        alert(result.info);\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n      }\n\n      LibraryController.LockWallet();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.send-coins {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n}\n\nbutton {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SavingAccount/RenewAccount.vue",
    "content": "<template>\n  <div class=\"send-coins flex-col\">\n    <div class=\"main\">\n      <app-form-field title=\"renew_saving_account.funding_account\">\n        <select-list :options=\"fundingAccounts\" :default=\"fundingAccount\" v-model=\"fundingAccount\" />\n      </app-form-field>\n    </div>\n    <button @click=\"tryRenew\" :disabled=\"disableSendButton\">\n      {{ $t(\"buttons.send\") }}\n    </button>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { AccountsController, WitnessController } from \"../../../unity/Controllers\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"RenewAccount\",\n  data() {\n    return {\n      fundingAccount: null\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"accounts\", \"account\"]),\n    fundingAccounts() {\n      return this.accounts.filter(x => x.state === \"Normal\" && [\"Desktop\"].indexOf(x.type) !== -1);\n    },\n    disableSendButton() {\n      return this.fundingAccounts.length === 0;\n    }\n  },\n  mounted() {\n    if (this.fundingAccounts.length) {\n      this.fundingAccount = this.fundingAccounts[0];\n    }\n  },\n  methods: {\n    async tryRenew() {\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          let accountUUID = AccountsController.GetActiveAccount();\n          let result = WitnessController.RenewWitnessAccount(this.fundingAccount.UUID, accountUUID);\n\n          if (result.status === \"success\") {\n            this.fundingAccount = null;\n          } else {\n            // todo: handle error\n            console.log(result);\n          }\n        }\n      });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.send-coins {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n}\n\nbutton {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SavingAccount/index.vue",
    "content": "<template>\n  <div class=\"saving-account\">\n    <portal to=\"header-slot\">\n      <account-header :account=\"account\"></account-header>\n    </portal>\n\n    <div v-if=\"isAccountView && accountIsFunded\">\n      <app-form-field title=\"saving_account.compound_earnings\">\n        <div class=\"flex-row\">\n          <vue-slider :min=\"0\" :max=\"100\" :value=\"compoundingPercent\" v-model=\"compoundingPercent\" class=\"slider\" />\n          <div class=\"slider-info\">\n            {{ compoundingPercent }}\n            {{ $tc(\"saving_account.percent\") }}\n          </div>\n        </div>\n      </app-form-field>\n    </div>\n\n    <app-section v-if=\"isAccountView && accountIsFunded\" class=\"saving-information\">\n      <h2>{{ $t(\"common.information\") }}</h2>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.status\") }}</div>\n        <div>{{ accountStatus }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.parts\") }}</div>\n        <div>{{ accountParts }}</div>\n      </div>\n\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.coins_locked\") }}</div>\n        <div>{{ accountAmountLockedAtCreation }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.coins_earned\") }}</div>\n        <div>{{ accountAmountEarned }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.locked_from_block\") }}</div>\n        <div>{{ lockedFrom }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.locked_until_block\") }}</div>\n        <div>{{ lockedUntil }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.lock_duration\") }}</div>\n        <div>{{ lockDuration }} {{ $t(\"common.days\") }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.remaining_lock_period\") }}</div>\n        <div>{{ remainingLockPeriod }} {{ $t(\"common.days\") }}</div>\n      </div>\n\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.required_earnings_frequency\") }}</div>\n        <div>{{ requiredEarningsFrequency }} {{ $t(\"common.days\") }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.expected_earnings_frequency\") }}</div>\n        <div>{{ expectedEarningsFrequency }} {{ $t(\"common.days\") }}</div>\n      </div>\n\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.account_weight\") }}</div>\n        <div>{{ accountWeight }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>{{ $t(\"saving_account.network_weight\") }}</div>\n        <div>{{ networkWeight }}</div>\n      </div>\n    </app-section>\n\n    <app-section v-show=\"isAccountView && !accountIsFunded\" class=\"saving-empty\">\n      {{ $t(\"saving_account.empty\") }}\n    </app-section>\n\n    <router-view />\n    <div>\n      <portal to=\"footer-slot\">\n        <div style=\"display: flex\">\n          <div\n            id=\"footer-layout\"\n            v-on:scroll.passive=\"handleScroll\"\n            class=\"footer-layout\"\n            :style=\"{ justifyContent: !showOverFlowArrowRight && !showOverFlowArrowLeft ? 'center' : null }\"\n          >\n            <div @click=\"scrollToStart\" class=\"scroll-arrow-left\" v-if=\"showOverFlowArrowLeft\">\n              <fa-icon class=\"pen\" :icon=\"['fal', 'fa-long-arrow-left']\" />\n            </div>\n            <div @click=\"scrollToEnd\" class=\"scroll-arrow-right\" v-if=\"showOverFlowArrowRight\">\n              <fa-icon class=\"pen\" :icon=\"['fal', 'fa-long-arrow-right']\" />\n            </div>\n            <footer-button title=\"buttons.info\" :icon=\"['fal', 'info-circle']\" routeName=\"account\" @click=\"routeTo\" />\n            <footer-button title=\"buttons.saving_key\" :icon=\"['fal', 'key']\" routeName=\"link-saving-account\" @click=\"routeTo\" />\n            <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"transactions\" @click=\"routeTo\" />\n            <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send-saving\" @click=\"routeTo\" />\n            <footer-button :class=\"optimiseButtonClass\" title=\"buttons.optimise\" :icon=\"['fal', 'redo-alt']\" routeName=\"optimise-account\" @click=\"routeTo\" />\n            <footer-button v-if=\"renewButtonVisible\" title=\"buttons.renew\" :icon=\"['fal', 'redo-alt']\" routeName=\"renew-account\" @click=\"routeTo\" />\n            <footer-button title=\"buttons.download\" :icon=\"['fal', 'download']\" @click=\"downloadCSV\" />\n          </div>\n        </div>\n        xx\n      </portal>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { WitnessController, AccountsController, BackendUtilities } from \"../../../unity/Controllers\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { mapState } from \"vuex\";\nimport { downloadTransactionList } from \"../../../util.js\";\n\nlet timeout;\n\nexport default {\n  name: \"SavingAccount\",\n  props: {\n    account: null\n  },\n  data() {\n    return {\n      rightSection: null,\n      rightSectionComponent: null,\n      statistics: null,\n      compoundingPercent: 0,\n      keyHash: null,\n      showOverFlowArrowRight: false,\n      showOverFlowArrowLeft: false\n    };\n  },\n  mounted() {\n    this.isOverflown();\n  },\n  computed: {\n    ...mapState(\"app\", [\"rate\", \"activityIndicator\", \"currency\"]),\n    ...mapState(\"wallet\", [\"mutations\"]),\n    isAccountView() {\n      return this.$route.name === \"account\";\n    },\n    accountStatus() {\n      return this.getStatistics(\"account_status\");\n    },\n    accountAmountLockedAtCreation() {\n      return formatMoneyForDisplay(this.getStatistics(\"account_amount_locked_at_creation\"));\n    },\n    accountAmountEarned() {\n      let earnings = formatMoneyForDisplay(this.account.balance - this.getStatistics(\"account_amount_locked_at_creation\"));\n      if (earnings < 0) return formatMoneyForDisplay(0);\n      return earnings;\n    },\n    accountIsFunded() {\n      if (this.getStatistics(\"account_status\") == \"empty\") return false;\n      if (this.getStatistics(\"account_status\") == \"empty_with_remainder\") return false;\n      return true;\n    },\n    lockedFrom() {\n      return this.getStatistics(\"account_initial_lock_creation_block_height\");\n    },\n    lockedUntil() {\n      return this.getStatistics(\"account_initial_lock_creation_block_height\") + this.getStatistics(\"account_initial_lock_period_in_blocks\");\n    },\n    lockDuration() {\n      return (this.getStatistics(\"account_initial_lock_period_in_blocks\") / 288).toFixed(2);\n    },\n    remainingLockPeriod() {\n      return (this.getStatistics(\"account_remaining_lock_period_in_blocks\") / 288).toFixed(2);\n    },\n    requiredEarningsFrequency() {\n      return (this.getStatistics(\"account_expected_witness_period_in_blocks\") / 288).toFixed(2);\n    },\n    expectedEarningsFrequency() {\n      return (this.getStatistics(\"account_estimated_witness_period_in_blocks\") / 288).toFixed(2);\n    },\n    accountWeight() {\n      return this.getStatistics(\"account_weight\");\n    },\n    networkWeight() {\n      return this.getStatistics(\"network_tip_total_weight\");\n    },\n    accountParts() {\n      return this.getStatistics(\"account_parts\");\n    },\n    renewButtonVisible() {\n      return this.accountStatus === \"expired\";\n    },\n    optimiseButtonVisible() {\n      return this.getStatistics(\"is_optimal\") === false;\n    },\n    optimiseButtonClass() {\n      if (this.getStatistics(\"is_optimal\") === true && this.getStatistics(\"blocks_since_last_activity\") < 100) {\n        return \"optimise-button-inactive\";\n      } else if (this.getStatistics(\"is_optimal\") === false) {\n        return \"optimise-button-hidden\";\n      }\n      return \"\";\n    },\n    totalBalanceFiat() {\n      if (!this.rate) return \"\";\n      return `${this.currency.symbol || \"\"} ${formatMoneyForDisplay(this.account.balance * this.rate, true)}`;\n    },\n    balanceForDisplay() {\n      if (this.account.balance == null) return \"\";\n      return formatMoneyForDisplay(this.account.balance);\n    }\n  },\n  beforeDestroy() {\n    clearTimeout(timeout);\n  },\n  created() {\n    this.initialize();\n  },\n  destroyed() {\n    window.removeEventListener(\"resize\", this.isOverflown);\n  },\n  watch: {\n    account() {\n      this.initialize();\n    },\n    compoundingPercent(newVal) {\n      // Prevent calling this on initialization.\n      if (this.compoundingPercent === 0) {\n        return;\n      } else {\n        const timeoutHandler = setTimeout(() => {\n          if (newVal == this.compoundingPercent) {\n            if (this.keyHash) {\n              BackendUtilities.holdinAPIActions(this.keyHash, \"distribution\", this.compoundingPercent);\n              WitnessController.SetAccountCompounding(this.account.UUID, this.compoundingPercent);\n            } else {\n              WitnessController.SetAccountCompounding(this.account.UUID, this.compoundingPercent);\n            }\n          }\n        }, 1000);\n\n        return timeoutHandler;\n      }\n    }\n  },\n  methods: {\n    initialize() {\n      this.updateStatistics();\n\n      this.compoundingPercent = parseInt(WitnessController.GetAccountWitnessStatistics(this.account.UUID).compounding_percent) || 0;\n\n      AccountsController.ListAccountLinksAsync(this.account.UUID).then(async result => {\n        const findHoldin = result.find(element => element.serviceName == \"holdin\");\n\n        if (findHoldin) {\n          // Use the Holdin %\n          this.keyHash = findHoldin.serviceData;\n          let infoResult = await BackendUtilities.holdinAPIActions(this.keyHash, \"getinfo\");\n\n          if (infoResult.data.compound) {\n            this.compoundingPercent = parseInt(infoResult.data.compound);\n          } else {\n            this.compoundingPercent = parseInt(WitnessController.GetAccountWitnessStatistics(this.account.UUID).compounding_percent) || 0;\n          }\n        } else {\n          // Use the Gulden compounding Percent\n          this.compoundingPercent = parseInt(WitnessController.GetAccountWitnessStatistics(this.account.UUID).compounding_percent) || 0;\n        }\n      });\n\n      window.addEventListener(\"resize\", this.isOverflown);\n    },\n    getStatistics(which) {\n      return this.statistics[which];\n    },\n    updateStatistics() {\n      return new Promise(resolve => {\n        clearTimeout(timeout);\n        this.statistics = WitnessController.GetAccountWitnessStatistics(this.account.UUID);\n        timeout = setTimeout(this.updateStatistics, 2 * 60 * 1000); // update statistics every two minutes\n        if (this.statistics) {\n          resolve();\n        }\n      });\n    },\n    getButtonClassNames(route) {\n      let classNames = [\"button\"];\n      if (route === this.$route.name) {\n        classNames.push(\"active\");\n      }\n      return classNames;\n    },\n    routeTo(route) {\n      if (route === \"optimise-account\" && this.optimiseButtonClass === \"optimise-button-inactive\") {\n        alert(\"Cannot perform this operation while account is in cooldown, please wait and try again later.\");\n      } else {\n        if (this.$route.name === route) return;\n        this.$router.push({ name: route, params: { id: this.account.UUID } });\n      }\n    },\n    isOverflown(e) {\n      // Determine whether to show the overflow arrow\n      if (e) {\n        const width = e.currentTarget.innerWidth;\n        if (width && width <= 1000) {\n          if (this.renewButtonVisible || this.optimiseButtonVisible) {\n            this.showOverFlowArrowRight = true;\n          } else {\n            this.showOverFlowArrowRight = false;\n          }\n        } else {\n          this.showOverFlowArrowRight = false;\n        }\n      } else {\n        // Triggered on page load.\n        if (window.innerWidth <= 1000) {\n          if (this.renewButtonVisible || this.optimiseButtonVisible) {\n            this.showOverFlowArrowRight = true;\n          } else {\n            this.showOverFlowArrowRight = false;\n          }\n        } else {\n          this.showOverFlowArrowRight = false;\n        }\n      }\n    },\n    handleScroll(e) {\n      // Determine when user it at the end of the horizontal scroll bar.\n      if (e.target.scrollWidth - e.target.scrollLeft === e.target.clientWidth) {\n        this.showOverFlowArrowRight = false;\n        this.showOverFlowArrowLeft = true;\n      } else {\n        this.showOverFlowArrowRight = true;\n        this.showOverFlowArrowLeft = false;\n      }\n    },\n    scrollToEnd() {\n      var container = document.querySelector(\"#footer-layout\");\n      container.scrollLeft = container.scrollWidth;\n    },\n    scrollToStart() {\n      var container = document.querySelector(\"#footer-layout\");\n      container.scrollLeft = 0;\n    },\n    downloadCSV() {\n      downloadTransactionList(this.mutations, this.account.label);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.saving-information {\n  & .flex-row > div {\n    line-height: 18px;\n  }\n  & .flex-row :first-child {\n    min-width: 220px;\n  }\n}\n.slider {\n  width: calc(100% - 60px) !important;\n  display: inline-block;\n}\n.slider-info {\n  text-align: right;\n  line-height: 18px;\n  flex: 1;\n}\n.footer-layout {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  overflow-x: scroll;\n  width: 100%;\n}\n.footer-layout::-webkit-scrollbar {\n  display: none;\n}\n.scroll-arrow-right {\n  cursor: pointer;\n  background-image: linear-gradient(90deg, rgba(255, 255, 255, 0.9), #ffffff);\n  height: 55px;\n  width: 55px;\n  position: absolute;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-items: center;\n  right: 0;\n  bottom: 0;\n}\n.scroll-arrow-left {\n  cursor: pointer;\n  background-image: linear-gradient(270deg, rgba(255, 255, 255, 0.9), #ffffff);\n  height: 55px;\n  width: 55px;\n  position: absolute;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  left: -30;\n  align-items: center;\n  bottom: 0;\n}\n.optimise-button-inactive {\n  color: #a8a8a8;\n}\n.optimise-button-hidden {\n  display: none !important;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/AddSpendingAccount.vue",
    "content": "<template>\n  <div class=\"add-spending-account\">\n    <portal to=\"header-slot\">\n      <main-header title=\"add_spending_account.title\"></main-header>\n    </portal>\n\n    <section class=\"content\">\n      <section>\n        <app-form-field title=\"common.account_name\">\n          <input type=\"text\" v-model=\"accountName\" maxlength=\"30\" ref=\"accountName\" />\n        </app-form-field>\n      </section>\n    </section>\n    <div class=\"flex-1\"></div>\n    <app-button-section>\n      <button @click=\"tryAddSpendingAccount\" :disabled=\"accountName.length < 3\">\n        {{ $t(\"buttons.done\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { AccountsController } from \"../../../unity/Controllers\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"AddSpendingAccount\",\n  data() {\n    return {\n      accountName: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"accounts\"]),\n    disableLockButton() {\n      if (this.accountName.trim().length === 0) return true;\n      return false;\n    }\n  },\n  methods: {\n    tryAddSpendingAccount() {\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          let accountId = AccountsController.CreateAccount(this.accountName, \"HD\");\n\n          if (accountId) {\n            this.$router.push({ name: \"account\", params: { id: accountId } });\n          } else {\n            console.log(\"Error\");\n            AccountsController.DeleteAccount(accountId); // something went wrong, so delete the account\n          }\n        }\n      });\n    }\n  }\n};\n</script>\n\n<style scoped>\n.add-spending-account {\n  display: flex;\n  flex-direction: column;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/ConfirmTransactionDialog.vue",
    "content": "<template>\n  <div class=\"confirm-transaction-dialog\">\n    <div class=\"tx-amount\">{{ computedAmount }}</div>\n    <div class=\"tx-fee\">{{ computedFee }}</div>\n    <div class=\"tx-fee-message\" v-if=\"subtractFee\">{{ $t(\"send_coins.fee_will_be_subtracted\") }}</div>\n    <div class=\"tx-to\">\n      <fa-icon :icon=\"['far', 'long-arrow-down']\" />\n    </div>\n    <div class=\"tx-address\">{{ address }}</div>\n    <button @click=\"confirm\" class=\"button\">\n      {{ $t(\"buttons.confirm\") }}\n    </button>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"@/EventBus\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { LibraryController } from \"@/unity/Controllers\";\n\nexport default {\n  name: \"ConfirmTransactionDialog\",\n  props: {\n    amount: null,\n    address: null,\n    subtractFee: null\n  },\n  computed: {\n    computedRequest() {\n      return {\n        valid: true,\n        address: this.address,\n        label: \"\",\n        desc: \"\",\n        amount: this.amount\n      };\n    },\n    computedAmount() {\n      return `${formatMoneyForDisplay(this.amount, false, 8)} ${this.$t(\"common.ticker_symbol\")}`;\n    },\n    computedFee() {\n      return `${formatMoneyForDisplay(this.fee, false, 8)} ${this.$t(\"common.ticker_symbol\")} FEE`;\n    }\n  },\n  watch: {\n    amount: {\n      immediate: true,\n      handler() {\n        this.fee = LibraryController.FeeForRecipient(this.computedRequest);\n      }\n    }\n  },\n  methods: {\n    confirm() {\n      EventBus.$emit(\"unlock-wallet\", {\n        message: \"send_coins.unlock_your_wallet_to_complete_the_transaction\",\n        callback: async () => {\n          // try to make the payment\n          let result = LibraryController.PerformPaymentToRecipient(this.computedRequest, this.subtractFee);\n\n          if (result !== 0) {\n            // payment failed, log an error. have to make this more robust\n            console.error(result);\n          }\n\n          EventBus.$emit(\"transaction-succeeded\");\n          EventBus.$emit(\"close-dialog\");\n        }\n      });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.confirm-transaction-dialog {\n  text-align: center;\n\n  & > h4 {\n    margin: 20px 0 0 0;\n  }\n}\n.tx-amount {\n  font-size: 1.6em;\n  font-weight: 600;\n  margin: 0 0 10px 0;\n}\n.tx-fee {\n  font-size: 0.9em;\n}\n.tx-fee-message {\n  font-size: 0.9em;\n  margin-top: 5px;\n}\n.tx-to {\n  margin: 20px 0 10px 0;\n  font-size: 1.6em;\n}\n.tx-address {\n  padding: 10px 0 40px 0;\n  font-weight: 500;\n}\n.button {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/Receive.vue",
    "content": "<template>\n  <div class=\"receive-view flex-col\">\n    <div class=\"main\">\n      <content-wrapper heading=\"receive_coins.your_address\" content=\"receive_coins.information\"> </content-wrapper>\n\n      <div class=\"qr\" @click=\"copyQr\">\n        <vue-qrcode ref=\"qrcode\" class=\"qrcode\" :width=\"280\" :margin=\"0\" :value=\"receiveAddress\" :color=\"{ dark: '#000000', light: '#ffffff' }\" />\n      </div>\n    </div>\n    <div class=\"address-row flex-row\">\n      <div class=\"flex-1\" />\n      <clipboard-field class=\"address\" :value=\"receiveAddress\" confirmation=\"receive_coins.address_copied_to_clipboard\"></clipboard-field>\n      <div class=\"flex-1\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport VueQrcode from \"vue-qrcode\";\nimport { clipboard, nativeImage } from \"electron\";\nimport UIConfig from \"../../../../ui-config.json\";\nimport ContentWrapper from \"../../../components/layout/ContentWrapper.vue\";\n\nexport default {\n  name: \"Receive\",\n  components: {\n    VueQrcode,\n    ContentWrapper\n  },\n  data() {\n    return {\n      UIConfig: UIConfig\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"receiveAddress\"])\n  },\n  methods: {\n    copyQr() {\n      let img = nativeImage.createFromDataURL(this.$refs.qrcode.$el.src);\n      clipboard.writeImage(img);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.receive-view {\n  height: 100%;\n  text-align: center;\n\n  & .information {\n    margin: 0 0 30px 0;\n  }\n  & .qr {\n    text-align: center;\n    cursor: pointer;\n    margin: 0 auto;\n  }\n  & .qrcode {\n    width: 100%;\n    max-width: 140px;\n  }\n  & .address-row {\n    width: 100%;\n    text-align: center;\n  }\n  & .address {\n    margin: 5px 0 0 0;\n    font-weight: 500;\n    font-size: 1em;\n    line-height: 1.4em;\n  }\n  & .buy-coins {\n    width: 100%;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/Send.vue",
    "content": "<template>\n  <div class=\"send-view flex-col\">\n    <div class=\"main\">\n      <div class=\"flex flex-row\">\n        <input\n          helper=\"TEST\"\n          :class=\"getSendClass()\"\n          v-model=\"amount\"\n          ref=\"amount\"\n          type=\"number\"\n          step=\"0.00000001\"\n          :placeholder=\"computedAmountPlaceholder\"\n          min=\"0\"\n        />\n        <button v-if=\"maxAmount > 0\" outlined class=\"max\" @click=\"setUseMax\" :disabled=\"useMax\">max</button>\n      </div>\n      <content-wrapper>\n        <p>\n          {{ this.useMax ? $t(\"send_coins.fee_will_be_subtracted\") : \"&nbsp;\" }}\n        </p>\n      </content-wrapper>\n      <div class=\"flex-row\">\n        <div @click=\"selectedTab = 'address'\" :class=\"selectedTab === 'address' ? 'selected-tab' : 'unselected-tab'\">\n          <h4>Receiving Address</h4>\n        </div>\n        <div @click=\"selectedTab = 'accounts'\" :class=\"selectedTab === 'accounts' ? 'selected-tab' : 'unselected-tab'\">\n          <h4>My Accounts</h4>\n        </div>\n      </div>\n      <div v-if=\"selectedTab === 'address'\">\n        <input v-model=\"address\" type=\"text\" :placeholder=\"$t('send_coins.enter_coins_address')\" :class=\"getAddressClass()\" />\n        <input v-model=\"label\" type=\"text\" :placeholder=\"$t('send_coins.enter_label')\" />\n      </div>\n      <div v-else>\n        <app-form-field title=\"send_coins.select_account\">\n          <select-list :options=\"accountsList\" :default=\"accountsList[0]\" v-model=\"selectedAccount\" />\n        </app-form-field>\n      </div>\n    </div>\n    <div class=\"flex-row\">\n      <button class=\"send\" @click=\"showConfirmation\" :disabled=\"disableSendButton\">\n        {{ $t(\"buttons.send\") }}\n      </button>\n      <button class=\"clear\" outlined @click=\"clearInputs\" :disabled=\"disableClearButton\">{{ $t(\"buttons.clear\") }}</button>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { displayToMonetary, formatMoneyForDisplay } from \"../../../util.js\";\nimport { LibraryController, AccountsController } from \"@/unity/Controllers\";\nimport ConfirmTransactionDialog from \"./ConfirmTransactionDialog\";\nimport EventBus from \"@/EventBus\";\n\nexport default {\n  name: \"Send\",\n  data() {\n    return {\n      amount: \"\",\n      maxAmount: null,\n      address: \"\",\n      label: \"\",\n      isAddressInvalid: false,\n      sellDisabled: false,\n      useMax: false,\n      selectedTab: \"address\",\n      accountsList: [],\n      selectedAccount: []\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"decimals\"]),\n    ...mapGetters(\"wallet\", [\"account\", \"accounts\"]),\n    computedAmountPlaceholder() {\n      return `0.${\"0\".repeat(this.decimals)}`;\n    },\n    computedMaxForDisplay() {\n      return formatMoneyForDisplay(this.maxAmount, false, 8);\n    },\n    addressClass() {\n      return this.isAddressInvalid ? \"error\" : \"\";\n    },\n    hasErrors() {\n      return this.isAddressInvalid;\n    },\n    disableSendButton() {\n      if (isNaN(parseFloat(this.amount))) return true;\n      if (this.address === null || this.address.trim().length === 0) return true;\n      if (this.amount > this.account.balance) return true;\n      if (!LibraryController.IsValidNativeAddress(this.address)) return true;\n      return false;\n    },\n    disableClearButton() {\n      return this.amount === \"\" && this.address === \"\" && this.label === \"\";\n    }\n  },\n  mounted() {\n    this.$refs.amount.focus();\n    this.accountsList = this.accounts.filter(item => item.UUID !== this.account.UUID);\n    EventBus.$on(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  watch: {\n    account: {\n      immediate: true,\n      handler() {\n        this.maxAmount = this.account.spendable;\n      }\n    },\n    selectedAccount(value) {\n      this.address = AccountsController.GetReceiveAddress(value.UUID);\n      this.label = value.label;\n    },\n    maxAmount() {\n      if (this.useMax) {\n        this.amount = this.computedMaxForDisplay;\n      }\n    },\n    amount() {\n      // this will prevent entering more than 8 decimals\n      const idx = this.amount.indexOf(\".\");\n      if (idx !== -1 && idx + 9 < this.amount.length) {\n        this.amount = this.amount.slice(0, idx + 9);\n      }\n\n      if (displayToMonetary(this.amount) >= this.maxAmount) {\n        this.useMax = true;\n      } else {\n        this.useMax = false;\n      }\n    },\n    useMax() {\n      if (this.useMax) {\n        this.amount = this.computedMaxForDisplay;\n      }\n    }\n  },\n  methods: {\n    clearInputs() {\n      this.amount = \"\";\n      this.address = \"\";\n      this.label = \"\";\n      this.$refs.amount.focus();\n    },\n    getSendClass() {\n      if (this.amount > this.account.balance) return \"error\";\n      return \"\";\n    },\n    getAddressClass() {\n      if (!LibraryController.IsValidNativeAddress(this.address)) return \"error\";\n      return \"\";\n    },\n    showConfirmation() {\n      // amount is always less then or equal to the floored spendable amount\n      // if useMax is checked, use the maxAmount and subtract the fee from the amount\n      let amount = this.useMax ? this.maxAmount : displayToMonetary(this.amount);\n\n      // validate address\n      this.isAddressInvalid = !LibraryController.IsValidNativeAddress(this.address);\n\n      if (this.hasErrors) return;\n\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(\"send_coins.confirm_transaction\"),\n        component: ConfirmTransactionDialog,\n        componentProps: {\n          amount: amount,\n          address: this.address,\n          subtractFee: this.useMax\n        },\n        showButtons: false\n      });\n    },\n    onTransactionSucceeded() {\n      this.$router.push({ name: \"transactions\" });\n    },\n    setUseMax() {\n      this.useMax = true;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.send-view {\n  height: 100%;\n  flex: 1;\n\n  .main {\n    flex: 1;\n  }\n}\n.selected-tab {\n  border-bottom: 2px solid #000000;\n  margin: 0px 10px 10px 10px;\n}\n.unselected-tab {\n  margin: 0px 10px 10px 10px;\n}\n.account-name {\n  font-size: 0.85em;\n  width: 100%;\n  margin-right: 10px;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n.accounts-list {\n  padding-left: 10px;\n  height: 50%;\n  overflow: scroll;\n}\n\nbutton.max,\nbutton.clear {\n  margin-left: 10px;\n  padding: 0 15px;\n}\n\nbutton.send {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/TransactionDetails.vue",
    "content": "<template>\n  <div class=\"transaction-details flex-col\">\n    <div class=\"main\">\n      <h5>{{ $t(\"transaction_details.hash\") }}</h5>\n      <div class=\"tx-hash\">{{ txHash }}</div>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"TransactionDetails\",\n  props: {\n    txHash: null\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transaction-details {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n\n  .tx-address {\n    margin: 0 0 20px 0;\n    padding: 10px;\n    font-size: 0.9em;\n    line-height: 1.2em;\n    user-select: text;\n    word-wrap: break-word;\n    background-color: #fff;\n  }\n\n  .tx-hash {\n    margin: 0;\n    padding: 10px;\n    font-size: 0.8em;\n    line-height: 1.2em;\n    user-select: text;\n    word-wrap: break-word;\n    background-color: #fff;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/Transactions.vue",
    "content": "<template>\n  <div class=\"transactions-view\">\n    <div v-if=\"hasMutations\" class=\"flex\">\n      <div class=\"mutations-list\" v-for=\"(mutation, index) in mutations\" :key=\"mutation.txHash\">\n        <h4 v-if=\"showDateHeader(index)\">\n          {{ formatDateHeader(mutation.timestamp) }}\n        </h4>\n        <div class=\"mutation-row flex-row\" @click=\"showTransactionDetails(mutation)\" :class=\"mutationRowClass(mutation.txHash)\">\n          <div class=\"icon\">\n            <fa-icon :icon=\"['fal', mutationIcon(mutation)]\" />\n          </div>\n          <div class=\"time\">{{ formatTime(mutation.timestamp) }}</div>\n          <div class=\"tx-details\">\n            {{ mutation.recipient_addresses || mutation.txHash }}\n          </div>\n          <div class=\"amount\">{{ formatAmount(mutation.change) }}</div>\n        </div>\n      </div>\n    </div>\n\n    <content-wrapper class=\"flex\" v-else heading=\"new_wallet.title\" content=\"new_wallet.information\">\n      <div class=\"flex-1\"></div>\n      <app-button-section>\n        <template v-slot:middle>\n          <button @click=\"buyCoins\" class=\"buy-coins\" :disabled=\"buyDisabled\">\n            {{ $t(\"buttons.buy_your_first_coins\") }}\n          </button>\n        </template>\n      </app-button-section>\n    </content-wrapper>\n  </div>\n</template>\n\n<script>\nimport { BackendUtilities } from \"@/unity/Controllers\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { mapState } from \"vuex\";\nimport TransactionDetailsDialog from \"../../../components/TransactionDetailsDialog\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"Transactions\",\n  data() {\n    return {\n      buyDisabled: false\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"mutations\"]),\n    hasMutations() {\n      return this.mutations ? this.mutations.length > 0 : false;\n    }\n  },\n  methods: {\n    mutationIcon(mutation) {\n      switch (mutation.status) {\n        case 0: // UNCONFIRMED\n          return \"hourglass-start\";\n        case 1: // CONFIRMING\n          return \"shield\";\n        case 2: // CONFIRMED\n          return \"shield-check\";\n        case 3: // ABANDONED\n        case 4: // CONFLICTED\n          return \"ban\";\n      }\n    },\n    showDateHeader(index) {\n      // only show a date header if the current date is different than previous date\n      if (index === 0) return true; // always show the date if it's the first item\n\n      const current = new Date(this.mutations[index].timestamp * 1000);\n      const previous = new Date(this.mutations[index - 1].timestamp * 1000);\n\n      if (current.getDate() !== previous.getDate()) return true;\n      if (current.getMonth() !== previous.getMonth()) return true;\n      if (current.getFullYear() !== previous.getFullYear()) return true;\n\n      return false;\n    },\n    formatDateHeader(timestamp) {\n      let date = new Date(timestamp * 1000);\n      let options = {\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\"\n      };\n      if (date.getFullYear() === new Date().getFullYear()) delete options.year;\n      return date.toLocaleString(this.$i18n.locale, options);\n    },\n    formatTime(timestamp) {\n      let date = new Date(timestamp * 1000);\n      return `${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n    },\n    formatAmount(amount) {\n      return `${formatMoneyForDisplay(amount)}`;\n    },\n    mutationRowClass(txHash) {\n      return txHash === this.txHash ? \"selected\" : \"\";\n    },\n    showTransactionDetails(mutation) {\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(`transaction_details.title.${mutation.change > 0 ? \"incoming_transaction\" : \"outgoing_transaction\"}`),\n        component: TransactionDetailsDialog,\n        componentProps: {\n          mutation: mutation\n        },\n        showButtons: false\n      });\n    },\n    async buyCoins() {\n      try {\n        this.buyDisabled = true;\n        const url = await BackendUtilities.GetBuySessionUrl();\n        window.open(url, \"buy-coins\");\n      } finally {\n        this.buyDisabled = false;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transactions-view {\n  height: 100%;\n}\n\n.flex {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n\n.mutations-list:not(:first-child) > h4 {\n  margin-top: 30px;\n}\n\n.mutation-group {\n  margin-bottom: 30px;\n}\n\nh4 {\n  margin-bottom: 10px;\n}\n\n.mutation-row {\n  width: calc(100% + 20px);\n  margin: 0 0 0 -10px;\n  padding: 5px 10px 5px 10px;\n  font-size: 0.95em;\n  line-height: 18px;\n  cursor: pointer;\n\n  & > .icon {\n    flex: 0 0 30px;\n  }\n\n  & > .time {\n    flex: 0 0 70px;\n  }\n\n  & > .tx-details {\n    font-size: 0.85em;\n    width: 100%;\n    margin-right: 10px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n\n  & .amount {\n    flex: 1;\n    text-align: right;\n  }\n\n  &:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n\n  &.selected {\n    color: #fff;\n    background: var(--primary-color);\n  }\n}\n\n.new-wallet {\n  height: 100%;\n}\n\n.buy-coins {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/SpendingAccount/index.vue",
    "content": "<template>\n  <div class=\"spending-account\">\n    <portal to=\"header-slot\">\n      <account-header :account=\"account\"></account-header>\n    </portal>\n\n    <transactions v-if=\"isAccountView\" :mutations=\"mutations\" @tx-hash=\"onTxHash\" :tx-hash=\"txHash\" />\n\n    <router-view />\n\n    <portal to=\"footer-slot\">\n      <div style=\"display: flex; justify-content: center\">\n        <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"account\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.receive\" :icon=\"['fal', 'arrow-to-bottom']\" routeName=\"receive\" @click=\"routeTo\" />\n        <footer-button v-if=\"mutations.length > 0\" title=\"buttons.download\" :icon=\"['fal', 'download']\" @click=\"downloadCSV\" />\n      </div>\n    </portal>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport Transactions from \"./Transactions\";\nimport { downloadTransactionList } from \"../../../util.js\";\n\nexport default {\n  name: \"SpendingAccount\",\n  props: {\n    account: null\n  },\n  data() {\n    return {\n      txHash: null\n    };\n  },\n  components: {\n    Transactions\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"mutations\"]),\n    isAccountView() {\n      return this.$route.name === \"account\";\n    }\n  },\n  methods: {\n    routeTo(route) {\n      if (this.$route.name === route) return;\n      this.$router.push({ name: route, params: { id: this.account.UUID } });\n    },\n    onTxHash(txHash) {\n      this.txHash = txHash;\n    },\n    downloadCSV() {\n      downloadTransactionList(this.mutations, this.account.label);\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Account/index.vue",
    "content": "<template>\n  <component :is=\"accountType\" :account=\"account\" />\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\n\nimport SpendingAccount from \"./SpendingAccount\";\nimport SavingAccount from \"./SavingAccount\";\nimport MiningAccount from \"./MiningAccount\";\n\nexport default {\n  name: \"Account\",\n  data() {\n    return {\n      accountType: \"div\"\n    };\n  },\n  props: {\n    id: null\n  },\n  components: {\n    SpendingAccount,\n    SavingAccount,\n    MiningAccount\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"account\"])\n  },\n  watch: {\n    account() {\n      this.onAccountChanged();\n    }\n  },\n  mounted() {\n    this.onAccountChanged();\n  },\n  methods: {\n    onAccountChanged() {\n      if (this.account) {\n        switch (this.account.type) {\n          case \"Desktop\":\n            this.accountType = SpendingAccount;\n            break;\n          case \"Holding\":\n          case \"Witness\":\n            this.accountType = SavingAccount;\n            break;\n          case \"Mining\":\n            this.accountType = MiningAccount;\n            break;\n          default:\n            this.accountType = \"div\";\n            break;\n        }\n      }\n      // remove the activity indicator at this point\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/DebugDialog/DebugConsole.vue",
    "content": "<template>\n  <div class=\"debug-console flex-col\" v-if=\"show\">\n    <div class=\"output-buttons\">\n      <fa-icon :icon=\"['fal', 'search-minus']\" class=\"button\" @click=\"decreaseFontSize\" />\n      <fa-icon :icon=\"['fal', 'search-plus']\" class=\"button\" @click=\"increaseFontSize\" />\n      <fa-icon :icon=\"['fal', 'eraser']\" class=\"button\" @click=\"clearOutput\" />\n    </div>\n\n    <div ref=\"output\" class=\"output scrollable\" :style=\"outputStyle\">\n      <div class=\"row\">\n        <div class=\"info\">Use up and down arrows to navigate history. Type <span class=\"help\">help</span> for an overview of available commands.</div>\n      </div>\n      <div class=\"row\" v-for=\"(item, index) in output\" :key=\"index\">\n        <fa-icon class=\"icon\" :icon=\"getIcon(item.type)\" />\n        <pre class=\"data\" :style=\"outputStyle\">{{ item.data }}</pre>\n      </div>\n    </div>\n\n    <div class=\"input\">\n      <input ref=\"command\" type=\"text\" spellcheck=\"false\" v-model=\"command\" @keydown=\"onRpcInputKeyDown\" list=\"history\" />\n      <datalist id=\"history\">\n        <option v-for=\"item in filteredAutocompleteList\" :key=\"item\" :value=\"item\" />\n      </datalist>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { RpcController } from \"../../unity/Controllers\";\n\nexport default {\n  name: \"DebugConsole\",\n  data() {\n    return {\n      command: \"\",\n      fontSize: 0.8,\n      history: [],\n      output: [],\n      index: 0,\n      autocomplete: {\n        all: [],\n        command: null,\n        filtered: [],\n        disabled: false\n      }\n    };\n  },\n  props: {\n    show: {\n      type: Boolean\n    }\n  },\n  computed: {\n    outputStyle() {\n      return `font-size: ${this.fontSize}rem;`;\n    },\n    filteredAutocompleteList() {\n      return this.autocomplete.filtered.slice(0, 20);\n    }\n  },\n  created() {\n    this.autocomplete.all = RpcController.GetAutocompleteList();\n  },\n  watch: {\n    output: {\n      immediate: true,\n      handler() {\n        this.focusCommand();\n      }\n    },\n    show: {\n      immediate: true,\n      handler() {\n        if (this.show) {\n          this.focusCommand();\n        }\n      }\n    },\n    command() {\n      this.filterAutocompleteList();\n    }\n  },\n  methods: {\n    moveToEnd() {\n      let command = this.$refs.command;\n      setTimeout(function () {\n        command.selectionStart = command.selectionEnd = command.value.length;\n      }, 0);\n    },\n    getIcon(type) {\n      return [\"fal\", `angle-double-${type === \"command\" ? \"left\" : \"right\"}`];\n    },\n    async onRpcInputKeyDown(e) {\n      this.autocomplete.disabled = false;\n      switch (e.keyCode) {\n        case 13: {\n          let result = await RpcController.ExecuteAsync(this.command);\n          this.command = \"\";\n\n          this.output.push({\n            type: \"command\",\n            data: result.command\n          });\n          this.output.push({ type: \"result\", ...result });\n\n          this.scrollToBottom();\n\n          let index = this.history.indexOf(result.command);\n          if (index !== -1) {\n            this.history.splice(index, 1);\n          }\n          this.history.push(result.command);\n          this.index = this.history.length;\n          return;\n        }\n        case 38: // arrow up\n          if (this.index > 0) this.index--;\n          if (this.history.length > 0) {\n            this.autocomplete.disabled = true;\n            this.command = this.history[this.index];\n            this.moveToEnd();\n            e.preventDefault();\n          }\n          break;\n        case 40: // arrow down\n          if (this.index < this.history.length) this.index++;\n          if (this.index < this.history.length && this.history.length > 0) {\n            this.autocomplete.disabled = true;\n            this.command = this.history[this.index];\n            this.moveToEnd();\n            e.preventDefault();\n          } else {\n            this.command = \"\";\n          }\n          break;\n      }\n    },\n    clearOutput() {\n      this.output = [];\n    },\n    focusCommand() {\n      this.$nextTick(() => {\n        this.$refs.command.focus();\n      });\n    },\n    scrollToBottom() {\n      this.$nextTick(() => {\n        this.$refs.output.scrollTop = this.$refs.output.scrollHeight;\n      });\n    },\n    increaseFontSize() {\n      if (this.fontSize >= 1.3) return;\n      this.fontSize += 0.05;\n    },\n    decreaseFontSize() {\n      if (this.fontSize <= 0.6) return;\n      this.fontSize -= 0.05;\n    },\n    filterAutocompleteList() {\n      if (this.autocomplete.disabled) return;\n\n      let filteredList = [];\n      const command = this.command && this.command.trim().length > 0 ? this.command.trim() : null;\n      if (command) {\n        filteredList = command.startsWith(this.autocomplete.command) ? this.autocomplete.filtered : this.autocomplete.all;\n      }\n\n      this.autocomplete.filtered = filteredList.filter(x => x.startsWith(command));\n      this.autocomplete.command = command;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.debug-console {\n  width: 100%;\n  height: 100%;\n}\n\n.output-buttons {\n  line-height: 20px;\n  text-align: right;\n\n  & .button {\n    margin: 4px;\n    cursor: pointer;\n  }\n}\n\n.output {\n  flex: 1;\n  margin-bottom: 8px;\n  border: 1px solid #ccc;\n  user-select: text;\n  padding: 4px;\n\n  & .help {\n    color: var(--primary-color);\n  }\n\n  & * {\n    user-select: text;\n  }\n\n  & .error {\n    color: var(--error-color);\n  }\n}\n\n.row {\n  display: flex;\n  flex-direction: row;\n  padding-top: 5px;\n\n  & > * {\n    padding-right: 5px;\n  }\n\n  & > .icon {\n    flex: 0 0 20px;\n  }\n}\n\n.row:last-of-type {\n  margin-bottom: 10px;\n}\n\npre {\n  white-space: pre-wrap;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/DebugDialog/InformationPage.vue",
    "content": "<template>\n  <div class=\"information-page\">\n    <app-section>\n      <h4>General</h4>\n\n      <div class=\"flex-row\">\n        <div>Client version</div>\n        <div>{{ clientInfo.client_version }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Useragent</div>\n        <div>{{ clientInfo.user_agent }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Data dir</div>\n        <div class=\"path-row\">\n          <div @click=\"openFile(clientInfo.datadir_path)\" class=\"list-item-icon\">\n            <fa-icon :icon=\"['fal', 'file-search']\" />\n          </div>\n          <div class=\"selectable\">{{ clientInfo.datadir_path }}</div>\n        </div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Log file</div>\n        <div class=\"path-row\">\n          <div @click=\"openFile(clientInfo.logfile_path)\" class=\"list-item-icon\">\n            <fa-icon :icon=\"['fal', 'file-search']\" />\n          </div>\n          <div class=\"selectable\">\n            {{ clientInfo.logfile_path }}\n          </div>\n        </div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Startup time</div>\n        <div>{{ startupTime }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Network</h4>\n      <div class=\"flex-row\">\n        <div>Status</div>\n        <div>{{ clientInfo.network_status }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Connection count</div>\n        <div>{{ numberOfConnections }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Block chain</h4>\n      <div class=\"flex-row\">\n        <div>Number of blocks</div>\n        <div>{{ clientInfo.chain_tip_height }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Last block time</div>\n        <div>{{ lastBlockTime }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Last block hash</div>\n        <div>{{ clientInfo.chain_tip_hash }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Memory pool</h4>\n      <div class=\"flex-row\">\n        <div>Number of transactions</div>\n        <div>{{ clientInfo.mempool_transaction_count }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Memory usage</div>\n        <div>{{ clientInfo.mempool_memory_size }}</div>\n      </div>\n    </app-section>\n  </div>\n</template>\n\n<script>\nimport { LibraryController } from \"../../unity/Controllers\";\nconst { shell } = require(\"electron\"); // deconstructing assignment\n\nlet timeout;\n\nexport default {\n  data() {\n    return {\n      clientInfo: null,\n      isDestroyed: false\n    };\n  },\n  name: \"InformationPage\",\n  computed: {\n    startupTime() {\n      return this.formatDate(this.clientInfo.startup_timestamp);\n    },\n    lastBlockTime() {\n      return this.formatDate(this.clientInfo.chain_tip_time);\n    },\n    numberOfConnections() {\n      let connections_in = parseInt(this.clientInfo.num_connections_in);\n      let connections_out = parseInt(this.clientInfo.num_connections_out);\n\n      return `${connections_in + connections_out} (In: ${connections_in} / Out: ${connections_out})`;\n    }\n  },\n  created() {\n    this.updateClientInfo();\n  },\n  beforeDestroy() {\n    this.isDestroyed = true;\n    clearTimeout(timeout);\n  },\n  methods: {\n    updateClientInfo() {\n      clearTimeout(timeout);\n      this.clientInfo = LibraryController.GetClientInfo();\n      if (this.isDestroyed) return;\n      timeout = setTimeout(this.updateClientInfo, 10 * 1000);\n    },\n    formatDate(timestamp) {\n      const date = new Date(timestamp * 1000);\n      return date.toLocaleString(this.$i18n.locale, {\n        weekday: \"short\",\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\",\n        hour: \"2-digit\",\n        minute: \"2-digit\",\n        second: \"2-digit\"\n      });\n    },\n    openFile(path) {\n      shell.openPath(path);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.information-page {\n  width: 100%;\n  height: 100%;\n\n  & h4 {\n    margin-bottom: 5px;\n  }\n  & h4:not(:first) {\n    margin-top: 5px;\n  }\n\n  & .flex-row > div {\n    font-size: 0.85rem;\n    line-height: 20px;\n    margin-bottom: 5px;\n  }\n  & .flex-row :first-child {\n    flex: 0 0 180px;\n  }\n  & .flex-row :last-child {\n    flex: 1;\n    overflow-wrap: break-word;\n    word-break: break-word;\n  }\n}\n\n.list-item-icon {\n  max-width: 30px;\n  cursor: pointer;\n}\n\n.path-row {\n  display: flex;\n  flex-direction: row;\n}\n\n.selectable {\n  user-select: all;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/DebugDialog/PeerDetailsDialog.vue",
    "content": "<template>\n  <div class=\"peer-details-dialog\">\n    <activity-indicator v-if=\"loading\" :paddingHidden=\"true\" />\n    <div class=\"peer-info scrollable\">\n      <div v-for=\"(value, propertyName) in peerInfo\" :key=\"propertyName\" class=\"row\">\n        <h4>{{ $t(`peers.${propertyName}`) }}</h4>\n        <div>{{ value }}</div>\n      </div>\n    </div>\n    <div class=\"buttons\">\n      <button @click=\"unBanPeer(peer)\" outlined small v-if=\"isBanned\">\n        {{ $t(\"peers.buttons.un_ban\") }}\n      </button>\n      <button @click=\"disconnectPeer(peer)\" outlined small v-if=\"!isBanned\">\n        {{ $t(\"peers.buttons.disconnect\") }}\n      </button>\n\n      <div style=\"display: flex\" v-if=\"!isBanned\">\n        <div>{{ $t(\"peers.ban\") }}</div>\n        <button @click=\"banPeer(3600)\" outlined small>\n          {{ $t(\"peers.buttons.ban_hour\") }}\n        </button>\n        <button @click=\"banPeer(86400)\" outlined small>\n          {{ $t(\"peers.buttons.ban_day\") }}\n        </button>\n        <button @click=\"banPeer(604800)\" outlined small>\n          {{ $t(\"peers.buttons.ban_week\") }}\n        </button>\n        <button @click=\"banPeer(31449600)\" outlined small>\n          {{ $t(\"peers.buttons.ban_year\") }}\n        </button>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"@/EventBus\";\nimport { P2pNetworkController } from \"@/unity/Controllers\";\nimport ActivityIndicator from \"@/components/ActivityIndicator.vue\";\n\nexport default {\n  data() {\n    return {\n      loading: false\n    };\n  },\n  name: \"PeerDetailsDialog\",\n  props: {\n    peer: {\n      type: Object,\n      default: null\n    }\n  },\n  components: {\n    ActivityIndicator\n  },\n  computed: {\n    isBanned() {\n      return this.peer.banned_from !== undefined;\n    },\n    peerInfo() {\n      const peer = this.peer;\n\n      return this.isBanned\n        ? {\n            address: peer.address,\n            banned_from: this.formatDate(peer.banned_from),\n            banned_until: this.formatDate(peer.banned_until),\n            reason: peer.reason\n          }\n        : {\n            node_id: peer.id,\n            node_service: peer.ip,\n            whitelisted: peer.whitelisted ? \"Yes\" : \"No\",\n            direction: peer.inbound ? \"Inbound\" : \"Outbound\",\n            user_agent: peer.userAgent,\n            services: peer.services,\n            starting_block: peer.start_height,\n            synced_headers: peer.synced_height,\n            synced_blocks: peer.common_height,\n            ban_score: peer.banscore,\n            connection_time: this.formatDateFrom(peer.time_connected),\n            last_send: this.formatDateFrom(peer.last_send),\n            last_receive: this.formatDateFrom(peer.last_receive),\n            sent: peer.send_bytes,\n            received: peer.receive_bytes,\n            ping_time: peer.latency,\n            time_offset: peer.time_offset\n          };\n    }\n  },\n  methods: {\n    formatDateFrom(date) {\n      const now = Date.now() / 1000;\n      return parseInt(now - date);\n    },\n    formatDate(date) {\n      const dateTimeString = new Date(date * 1000).toLocaleString();\n      return dateTimeString;\n    },\n    async disconnectPeer() {\n      this.loading = true;\n      const result = await P2pNetworkController.DisconnectPeerAsync(this.peer.id);\n      this.closeDialog(result);\n    },\n    async banPeer(interval) {\n      this.loading = true;\n      const result = await P2pNetworkController.BanPeerAsync(this.peer.addrBind, interval);\n      this.closeDialog(result);\n    },\n    async unBanPeer() {\n      this.loading = true;\n      const result = await P2pNetworkController.UnbanPeerAsync(this.peer.address);\n      this.closeDialog(result);\n    },\n    closeDialog(result) {\n      console.log(result); // todo: do something usefull with result\n\n      setTimeout(() => {\n        this.loading = false;\n        EventBus.$emit(\"close-dialog\");\n      }, 1000);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.peer-details-dialog {\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  max-height: calc(100vh - 100px);\n  margin-top: 10px;\n\n  & > div {\n    padding: 0 30px;\n  }\n}\n\n.peer-info {\n  flex: 1;\n}\n\n.row {\n  display: flex;\n\n  & > h4 {\n    flex: 1;\n    margin-bottom: 10px;\n  }\n\n  & > div {\n    flex: 1;\n  }\n}\n\n.buttons {\n  line-height: 50px;\n  height: 50px;\n  display: flex;\n  align-items: center;\n  justify-content: flex-end;\n\n  & > div {\n    flex: 1 0 0;\n    display: flex;\n    align-items: center;\n    justify-content: flex-end;\n\n    & > button {\n      margin-left: 10px;\n      min-width: 60px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/DebugDialog/PeersPage.vue",
    "content": "<template>\n  <div class=\"layout\">\n    <activity-indicator v-if=\"loading\" :paddingHidden=\"true\" />\n    <div v-else>\n      <div class=\"header\">\n        <h4>{{ $t(\"peers.node_id\") }}</h4>\n        <h4>{{ $t(\"peers.node_service\") }}</h4>\n        <h4>{{ $t(\"peers.user_agent\") }}</h4>\n      </div>\n      <div class=\"list scrollable\">\n        <div v-for=\"peer in peerInfo.peers\" :key=\"peer.id\" @click=\"showPeerDetails(peer)\" @contextmenu.prevent=\"onRightClick\">\n          <div>{{ peer.id }}</div>\n          <div>{{ peer.ip }}</div>\n          <div>{{ peer.userAgent }}</div>\n        </div>\n      </div>\n    </div>\n    <div v-if=\"hasBannedPeers\">\n      <div class=\"header\">\n        <h4>{{ $t(\"peers.banned_peers\") }}</h4>\n        <h4>{{ $t(\"peers.reason\") }}</h4>\n      </div>\n      <div class=\"list scrollable\">\n        <div v-for=\"peer in peerInfo.banned\" :key=\"peer.id\" @click=\"showPeerDetails(peer)\" @contextmenu.prevent=\"onRightClick\">\n          <div>{{ peer.address }}</div>\n          <div>{{ peer.reason }}</div>\n        </div>\n      </div>\n    </div>\n    <div class=\"buttons\" v-if=\"hasBannedPeers\">\n      <button @click=\"clearBannedPeers\" v-if=\"peerInfo.banned.length > 0\" class=\"clear-banned\" outlined small>\n        {{ $t(\"peers.buttons.clear_banned\") }}\n      </button>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { P2pNetworkController } from \"@/unity/Controllers\";\nimport PeerDetailsDialog from \"./PeerDetailsDialog\";\nimport EventBus from \"@/EventBus\";\nimport ActivityIndicator from \"@/components/ActivityIndicator.vue\";\n\nlet timeout;\n\nexport default {\n  data() {\n    return {\n      peerInfo: {\n        peers: [],\n        banned: []\n      },\n      isDestroyed: false,\n      loading: true\n    };\n  },\n  name: \"PeersPage2\",\n  components: {\n    ActivityIndicator\n  },\n  computed: {\n    hasBannedPeers() {\n      return this.peerInfo.banned.length;\n    }\n  },\n  methods: {\n    onRightClick() {\n      // TODO: Right Click\n      // Add Context menu on Right Click\n    },\n    async getPeers() {\n      clearTimeout(timeout);\n\n      this.peerInfo = {\n        peers: await P2pNetworkController.GetPeerInfoAsync(),\n        banned: await P2pNetworkController.ListBannedPeersAsync()\n      };\n\n      setTimeout(() => {\n        this.loading = false;\n      }, 1000);\n\n      if (this.isDestroyed) return;\n      timeout = setTimeout(this.getPeers, 10 * 1000);\n    },\n    showPeerDetails(peer) {\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(\"peers.peer_details\"),\n        component: PeerDetailsDialog,\n        componentProps: {\n          peer: peer\n        },\n        noMargin: true,\n        showButtons: false\n      });\n    },\n    async clearBannedPeers() {\n      await P2pNetworkController.ClearBannedAsync();\n      this.getPeers();\n    }\n  },\n  created() {\n    this.getPeers();\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.getPeers);\n  },\n  beforeDestroy() {\n    this.isDestroyed = true;\n    clearTimeout(timeout);\n    EventBus.$off(\"close-dialog\", this.getPeers);\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.layout {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n\n  & > div:not(.buttons) {\n    flex: 1 0 0;\n    margin-bottom: 10px;\n\n    display: flex;\n    flex-direction: column;\n  }\n\n  & > div.buttons {\n    text-align: right;\n  }\n}\n\n.header,\n.list > div {\n  display: flex;\n\n  & :first-child {\n    flex: 1 0 0;\n  }\n\n  & :not(:first-child) {\n    flex: 2 0 0;\n  }\n}\n\n.list {\n  border: solid 0.5px #888888;\n  padding: 0 5px;\n  flex: 1 0 0;\n\n  & > div {\n    cursor: pointer;\n    padding: 5px 0;\n  }\n\n  & > div:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\nh4 {\n  margin-bottom: 5px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/DebugDialog/index.vue",
    "content": "<template>\n  <div class=\"app-debug\">\n    <modal-dialog v-model=\"modal\" />\n    <div class=\"topbar flex-row\">\n      <div v-for=\"(tab, index) in tabs\" :key=\"index\" :class=\"getTabClass(index)\" @click=\"setTab(index)\">\n        {{ tab.title }}\n      </div>\n    </div>\n    <div class=\"main scrollable\">\n      <information-page v-if=\"current === 0\" />\n      <debug-console :show=\"current === 1\" />\n      <peers-page v-if=\"current === 2\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport InformationPage from \"./InformationPage\";\nimport DebugConsole from \"./DebugConsole\";\nimport PeersPage from \"./PeersPage\";\nimport ModalDialog from \"../../components/ModalDialog\";\nimport EventBus from \"../../EventBus.js\";\n\nexport default {\n  data() {\n    return {\n      current: 0,\n      tabs: [\n        {\n          title: \"Information\"\n        },\n        {\n          title: \"Console\"\n        },\n        {\n          title: \"Peers\"\n        }\n      ],\n      modal: null\n    };\n  },\n  components: {\n    InformationPage,\n    DebugConsole,\n    PeersPage,\n    ModalDialog\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.closeModal);\n    EventBus.$on(\"show-dialog\", this.showModal);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"close-dialog\", this.closeModal);\n    EventBus.$off(\"show-dialog\", this.showModal);\n  },\n  methods: {\n    getTabClass(index) {\n      return index === this.current ? \"active\" : \"\";\n    },\n    setTab(index) {\n      this.current = index;\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    showModal(modal) {\n      this.modal = modal;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-debug {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n}\n\n.topbar {\n  width: 100%;\n  height: 56px;\n  color: #000;\n  border-bottom: 1px solid var(--main-border-color);\n\n  & div {\n    padding: 0 20px;\n    font-weight: 600;\n    font-size: 0.85em;\n    line-height: 56px;\n    text-transform: uppercase;\n    letter-spacing: 0.03em;\n    cursor: pointer;\n\n    &:hover {\n      color: var(--primary-color);\n      background: var(--hover-color);\n    }\n\n    &.active,\n    .active:hover {\n      color: var(--primary-color);\n    }\n  }\n}\n\n.main {\n  height: calc(100% - 48px);\n  padding: 20px;\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Settings/ChangePassword.vue",
    "content": "<template>\n  <div class=\"change-password-view\">\n    <content-wrapper heading=\"common.enter_your_password\">\n      <app-form-field>\n        <input ref=\"currentPassword\" type=\"password\" v-model=\"currentPassword\" @keydown=\"resetStatus\" :class=\"currentPasswordStatus\" />\n      </app-form-field>\n    </content-wrapper>\n\n    <content-wrapper>\n      <app-form-field title=\"setup.choose_password\">\n        <input ref=\"password1\" type=\"password\" v-model=\"password1\" :class=\"password2Status\" />\n      </app-form-field>\n      <app-form-field title=\"setup.repeat_password\">\n        <input type=\"password\" v-model=\"password2\" :class=\"password2Status\" @keydown=\"validatePasswordRepeatOnEnter\" />\n      </app-form-field>\n    </content-wrapper>\n\n    <div class=\"flex-1\" />\n    <portal v-if=\"!isSingleAccount\" to=\"footer-slot\">\n      <app-button-section>\n        <button @click=\"tryChangePassword\" :disabled=\"isButtonDisabled\">\n          {{ $t(\"buttons.change_password\") }}\n        </button>\n      </app-button-section>\n    </portal>\n    <app-button-section v-else>\n      <template v-slot:left>\n        <button @click=\"routeTo('settings')\">\n          {{ $t(\"buttons.back\") }}\n        </button>\n      </template>\n      <template v-slot:right>\n        <button @click=\"tryChangePassword\" :disabled=\"isButtonDisabled\">\n          {{ $t(\"buttons.change_password\") }}\n        </button>\n      </template>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { LibraryController } from \"../../unity/Controllers\";\nimport UIConfig from \"../../../ui-config.json\";\n\nexport default {\n  data() {\n    return {\n      currentPassword: \"\",\n      password1: \"\",\n      password2: \"\",\n      isCurrentPasswordInvalid: false,\n      isSingleAccount: UIConfig.isSingleAccount\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"walletPassword\"]),\n    currentPasswordStatus() {\n      return this.isCurrentPasswordInvalid ? \"error\" : \"\";\n    },\n    password2Status() {\n      if (this.password2.length === 0) return \"\";\n      if (this.password2.length > this.password1.length) return \"error\";\n      return this.password1.indexOf(this.password2) === 0 ? \"\" : \"error\";\n    },\n    passwordsValidated() {\n      if (this.password1 === null || this.password1.length < 6) return false;\n      if (this.password2 === null || this.password2.length < this.password1.length) return false;\n\n      return this.password1 === this.password2;\n    },\n    isButtonDisabled() {\n      return this.currentPassword.trim().length === 0 || this.passwordsValidated === false;\n    }\n  },\n  mounted() {\n    this.$refs.currentPassword.focus();\n  },\n  methods: {\n    tryChangePassword() {\n      if (LibraryController.UnlockWallet(this.currentPassword, 10)) {\n        if (LibraryController.ChangePassword(this.currentPassword, this.password2)) {\n          LibraryController.LockWallet();\n          this.routeTo(\"account\");\n        }\n      } else {\n        this.isCurrentPasswordInvalid = true;\n      }\n    },\n    async resetStatus() {\n      this.isCurrentPasswordInvalid = false;\n    },\n    validatePasswordRepeatOnEnter(e) {\n      if (e.keyCode === 13 && this.passwordsValidated) this.tryChangePassword();\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.change-password-view {\n  display: flex;\n  height: 100%;\n  flex-direction: column;\n  flex-wrap: nowrap;\n  justify-content: space-between;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Settings/SettingsList.vue",
    "content": "<template>\n  <div class=\"settings-list-view\">\n    <portal v-if=\"!isSingleAccount\" to=\"header-slot\">\n      <main-header title=\"settings.header\" />\n    </portal>\n    <h2 v-else>{{ $t(\"settings.header\") }}</h2>\n\n    <router-link :to=\"{ name: 'view-recovery-phrase' }\">\n      <div class=\"settings-row\">\n        {{ $t(\"settings.view_recovery_phrase\") }}\n        <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n      </div>\n    </router-link>\n    <router-link :to=\"{ name: 'change-password' }\">\n      <div class=\"settings-row\">\n        {{ $t(\"settings.change_password\") }}\n        <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n      </div>\n    </router-link>\n    <div>\n      <div v-if=\"hasThemes\" class=\"settings-row-no-hover flex-row\">\n        <div class=\"flex-1\">{{ $t(\"settings.choose_theme\") }}</div>\n        <div v-for=\"(theme, index) in themes\" :key=\"theme.name\">\n          <div :class=\"getThemeSelectClassNames(theme.name, index)\" :style=\"getThemeStyle(theme.color)\" @click=\"switchTheme(theme.name)\"></div>\n        </div>\n      </div>\n    </div>\n    <div class=\"settings-row-no-hover flex-row\">\n      <div class=\"flex-1\">{{ $t(\"settings.choose_language\") }}</div>\n      <div :class=\"`language-select ${this.language === 'en' ? 'selected' : ''}`\" @click=\"changeLanguage('en')\">\n        {{ $t(\"settings.english\") }}\n      </div>\n      <div :class=\"`language-select ${this.language === 'nl' ? 'selected' : ''}`\" @click=\"changeLanguage('nl')\">\n        {{ $t(\"settings.dutch\") }}\n      </div>\n    </div>\n    <div class=\"settings-row-no-hover flex-row\">\n      <div class=\"flex-1\">{{ $t(\"settings.choose_decimal_places\") }}</div>\n      <div :class=\"`decimal-select ${this.decimals === 2 ? 'selected' : ''}`\" @click=\"changeDecimals(2)\">2</div>\n      <div :class=\"`decimal-select ${this.decimals === 3 ? 'selected' : ''}`\" @click=\"changeDecimals(3)\">3</div>\n      <div :class=\"`decimal-select ${this.decimals === 4 ? 'selected' : ''}`\" @click=\"changeDecimals(4)\">4</div>\n    </div>\n    <div class=\"settings-row-no-hover flex-row\"></div>\n    <app-form-field title=\"settings.select_display_currency\">\n      <select-list :options=\"currencyOptions\" :default=\"this.currency\" v-model=\"currencyLocal\" />\n    </app-form-field>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport UIConfig from \"../../../ui-config.json\";\n\nexport default {\n  data() {\n    return {\n      isSingleAccount: UIConfig.isSingleAccount,\n      themes: UIConfig.themes,\n      currencyLocal: this.currency\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"theme\", \"language\", \"decimals\", \"currency\", \"currencies\"]),\n    hasThemes() {\n      return this.themes && this.themes.length;\n    },\n    currencyOptions() {\n      var currencyArray = [];\n      this.currencies.forEach(item => {\n        currencyArray.push({\n          value: item.code,\n          label: item.name,\n          rate: item.rate\n        });\n      });\n      return currencyArray;\n    }\n  },\n  methods: {\n    getThemeSelectClassNames(theme, index) {\n      const classNames = [\"theme-select\"];\n      if (theme === this.theme || (!this.theme && index === 0)) classNames.push(\"selected\");\n      return classNames.join(\" \");\n    },\n    getThemeStyle(color) {\n      return `background-color: ${color}`;\n    },\n    switchTheme(theme) {\n      this.$store.dispatch(\"app/SET_THEME\", theme);\n    },\n    changeLanguage(language) {\n      this.$store.dispatch(\"app/SET_LANGUAGE\", language);\n      this.$forceUpdate();\n    },\n    changeDecimals(decimal) {\n      this.$store.dispatch(\"app/SET_DECIMALS\", decimal);\n      this.$forceUpdate();\n    },\n    changeCurrency(currency) {\n      this.$store.dispatch(\"app/SET_CURRENCY\", currency);\n      this.$store.dispatch(\"app/SET_RATE\", currency.rate);\n\n      this.$forceUpdate();\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  },\n  watch: {\n    currencyLocal(newValue, oldValue) {\n      const symbolArray = [\n        { value: \"Eur\", symbol: \"€\" },\n        { value: \"BTC\", symbol: \"₿\" },\n        { value: \"AUD\", symbol: \"A$\" },\n        { value: \"BRL\", symbol: \"R$\" },\n        { value: \"CNT\", symbol: \"CN¥\" },\n        { value: \"GBP\", symbol: \"£\" },\n        { value: \"RUB\", symbol: \"₽\" },\n        { value: \"USD\", symbol: \"$\" },\n        { value: \"ZAR\", symbol: \"R\" },\n        { value: \"KRW\", symbol: \"₩\" },\n        { value: \"JPY\", symbol: \"¥\" }\n      ];\n      if (newValue.value !== oldValue.value) {\n        newValue.symbol = symbolArray.find(item => item.value.toLowerCase() === newValue.value.toLowerCase()).symbol;\n        this.changeCurrency(newValue);\n      } else {\n        this.currency.symbol = symbolArray.find(item => item.value.toLowerCase() === this.currency.value.toLowerCase()).symbol;\n        this.changeCurrency(this.currency);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.settings-list-view {\n  display: flex;\n  flex-direction: column;\n}\n\n.settings-row {\n  margin: 0 -10px;\n  padding: 10px;\n}\n\n.settings-row-no-hover {\n  margin: 0 -10px;\n  padding: 10px;\n}\n\n.settings-row:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n  cursor: pointer;\n}\n\n.arrow {\n  float: right;\n}\n\n.theme-select {\n  border: 2px solid #fff;\n  border-radius: 18px;\n  height: 20px;\n  width: 20px;\n  cursor: pointer;\n  margin-left: 5px;\n}\n\n.language-select {\n  font-size: 12px;\n  border-radius: 18px;\n  line-height: 20px;\n  width: 40px;\n  text-align: center;\n  cursor: pointer;\n  margin-left: 15px;\n}\n\n.language-select:hover {\n  cursor: pointer;\n}\n\n.decimal-select {\n  font-size: 12px;\n  border-radius: 18px;\n  line-height: 20px;\n  width: 40px;\n  text-align: center;\n  cursor: pointer;\n  margin-left: 15px;\n}\n\n.selected {\n  box-shadow: 0 0 0 1px #000;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Settings/ViewRecoveryPhrase.vue",
    "content": "<template>\n  <div class=\"view-recovery-phrase-view\">\n    <div>\n      <content-wrapper heading=\"common.important\" heading-style=\"warning\" content=\"setup.this_is_your_recovery_phrase\">\n        <app-section class=\"phrase\">\n          {{ computedPhrase }}\n        </app-section>\n      </content-wrapper>\n    </div>\n\n    <div class=\"flex-1\"></div>\n\n    <app-button-section>\n      <button @click=\"viewRecoveryPhrase\" v-if=\"!recoveryPhrase\">\n        {{ $t(\"buttons.unlock\") }}\n      </button>\n      <button @click=\"back\">\n        {{ $t(\"buttons.back\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport EventBus from \"../../EventBus\";\nimport { LibraryController } from \"../../unity/Controllers\";\n\nexport default {\n  data() {\n    return {\n      recoveryPhrase: null\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"unlocked\"]),\n    computedPhrase() {\n      if (this.recoveryPhrase !== null) return this.recoveryPhrase;\n      else return \"In order to see your recovery phrase you need to unlock your wallet\";\n    }\n  },\n  watch: {\n    unlocked: {\n      immediate: true,\n      handler() {\n        if (this.unlocked) {\n          this.viewRecoveryPhrase();\n        }\n      }\n    }\n  },\n  methods: {\n    viewRecoveryPhrase() {\n      if (this.recoveryPhrase) return;\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          this.recoveryPhrase = LibraryController.GetRecoveryPhrase().phrase;\n        }\n      });\n    },\n    back() {\n      this.$router.push({ name: \"settings\" });\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.view-recovery-phrase-view {\n  display: flex;\n  height: 100%;\n  flex-direction: column;\n  flex-wrap: nowrap;\n  justify-content: space-between;\n}\n\n.phrase {\n  padding: 15px;\n  font-size: 1.05em;\n  font-weight: 500;\n  text-align: center;\n  word-spacing: 4px;\n  background-color: #f5f5f5;\n  user-select: none;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Settings/index.vue",
    "content": "<template>\n  <div class=\"settings-main\">\n    <router-view />\n  </div>\n</template>\n\n<style>\n.settings-main {\n  height: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/views/Setup.vue",
    "content": "<template>\n  <div class=\"setup-view flex-col\">\n    <div class=\"steps-container\">\n      <!-- step 1: choose setup type -->\n      <content-wrapper heading=\"setup.setup_your_wallet\" v-if=\"current === 1\">\n        <div class=\"settings-row\" @click=\"setupWallet(false)\">\n          {{ $t(\"setup.create_new\") }}\n          <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n        </div>\n        <div class=\"settings-row\" @click=\"setupWallet(true)\">\n          {{ $t(\"setup.recover_existing\") }}\n          <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n        </div>\n      </content-wrapper>\n\n      <!-- step 2: show recovery phrase -->\n      <content-wrapper heading=\"common.important\" headingStyle=\"warning\" content=\"setup.this_is_your_recovery_phrase\" v-else-if=\"current === 2\">\n        <app-section class=\"phrase\">\n          {{ recoveryPhrase }}\n        </app-section>\n      </content-wrapper>\n\n      <!-- step 3: enter/repeat recovery phrase -->\n      <content-wrapper\n        heading=\"setup.enter_recovery_phrase\"\n        :content=\"isRecovery ? 'setup.this_is_your_recovery_phrase' : 'setup.enter_existing_recovery_phrase'\"\n        v-else-if=\"current === 3\"\n      >\n        <phrase-input\n          ref=\"phraseinput\"\n          :validate=\"validate\"\n          :autofocus=\"true\"\n          :isPhraseInvalid=\"isRecoveryPhraseInvalid === true\"\n          :reset=\"reset\"\n          @possible-phrase=\"onPossiblePhrase\"\n          @enter=\"validatePhraseOnEnter\"\n        />\n      </content-wrapper>\n\n      <!-- step 4: enter a password -->\n      <content-wrapper heading=\"setup.choose_password\" content=\"setup.choose_password_information\" v-else-if=\"current === 4\">\n        <app-form-field title=\"common.password\">\n          <input ref=\"password\" type=\"password\" v-model=\"password1\" />\n        </app-form-field>\n        <app-form-field title=\"setup.repeat_password\">\n          <input type=\"password\" v-model=\"password2\" :class=\"password2Status\" @keydown=\"validatePasswordsOnEnter\" />\n        </app-form-field>\n      </content-wrapper>\n    </div>\n\n    <app-button-section class=\"steps-buttons\">\n      <template slot:left>\n        <button v-if=\"showPreviousButton\" @click=\"previousStep\">\n          {{ $t(\"buttons.previous\") }}\n        </button>\n      </template>\n      <template v-slot:right>\n        <button @click=\"nextStep\" :disabled=\"!isNextEnabled\">\n          <span v-show=\"showNextButton\">\n            {{ $t(\"buttons.next\") }}\n          </span>\n          <span v-show=\"showFinishButton\">\n            {{ $t(\"buttons.finish\") }}\n          </span>\n        </button>\n        <button @click=\"nextStep\" v-show=\"showValidateButton\" :disabled=\"!isValidateButtonEnabled\">\n          {{ $t(\"buttons.next\") }}\n        </button>\n      </template>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { LibraryController } from \"../unity/Controllers\";\nimport PhraseInput from \"../components/PhraseInput\";\nimport EventBus from \"../EventBus.js\";\nimport AppStatus from \"../AppStatus\";\nimport ContentWrapper from \"../components/layout/ContentWrapper.vue\";\n\nexport default {\n  data() {\n    return {\n      current: 1,\n      isRecovery: null,\n      recoveryPhrase: \"\",\n      possiblePhrase: null,\n      isRecoveryPhraseInvalid: null,\n      generatedRecoveryPhrase: null,\n      password1: \"\",\n      password2: \"\",\n      reset: false\n    };\n  },\n  components: {\n    PhraseInput,\n    ContentWrapper\n  },\n  computed: {\n    validate() {\n      if (this.isRecovery) {\n        return {\n          length: 12,\n          words: LibraryController.GetMnemonicDictionary()\n        };\n      } else {\n        return this.recoveryPhrase;\n      }\n    },\n    password2Status() {\n      if (this.password2.length === 0) return \"\";\n      if (this.password2.length > this.password1.length) return \"error\";\n      return this.password1.indexOf(this.password2) === 0 ? \"\" : \"error\";\n    },\n    passwordsValidated() {\n      if (this.password1 === null || this.password1.length < 6) return false;\n      if (this.password2 === null || this.password2.length < this.password1.length) return false;\n\n      return this.password1 === this.password2;\n    },\n    showPreviousButton() {\n      return this.current === 2 || this.current === 3;\n    },\n    showNextButton() {\n      return this.current === 2;\n    },\n    showValidateButton() {\n      return this.current === 3;\n    },\n    showFinishButton() {\n      return this.current === 4;\n    },\n    isNextEnabled() {\n      switch (this.current) {\n        case 2:\n          return this.recoveryPhrase !== null;\n        case 4:\n          return this.passwordsValidated;\n      }\n      return false;\n    },\n    isValidateButtonEnabled() {\n      return this.possiblePhrase !== null && this.isRecoveryPhraseInvalid !== true;\n    },\n    validateButtonClass() {\n      return this.isRecoveryPhraseInvalid ? \"error\" : \"\";\n    }\n  },\n  watch: {\n    current() {\n      let current = this.current;\n\n      this.$nextTick(() => {\n        switch (current) {\n          case 1:\n            this.isRecovery = null;\n            break;\n          case 4:\n            this.$refs.password.focus();\n            break;\n        }\n      });\n    }\n  },\n  methods: {\n    setupWallet(isRecovery) {\n      this.isRecovery = isRecovery;\n      this.nextStep();\n    },\n    nextStep() {\n      let next = this.current + 1;\n\n      switch (this.current) {\n        case 1:\n          if (this.isRecovery) {\n            this.recoveryPhrase = \"\";\n            next = 3;\n          } else {\n            if (this.generatedRecoveryPhrase === null) {\n              var mnemonic = LibraryController.GenerateRecoveryMnemonic();\n              this.generatedRecoveryPhrase = mnemonic.phrase_with_birth_number;\n              this.recoveryPhrase = mnemonic.phrase;\n            }\n          }\n          break;\n        case 3:\n          if (LibraryController.IsValidRecoveryPhrase(this.possiblePhrase)) {\n            this.recoveryPhrase = this.possiblePhrase;\n          } else {\n            EventBus.$emit(\"show-dialog\", {\n              type: \"error\",\n              title: this.$t(\"setup.invalid_recovery_phrase.title\"),\n              message: this.$t(\"setup.invalid_recovery_phrase.message\")\n            });\n\n            this.isRecoveryPhraseInvalid = true;\n            return;\n          }\n          break;\n        case 4:\n          if (this.isRecovery) {\n            if (LibraryController.InitWalletFromRecoveryPhrase(this.recoveryPhrase, this.password1)) {\n              this.$store.dispatch(\"app/SET_STATUS\", AppStatus.synchronize);\n            }\n          } else {\n            if (LibraryController.InitWalletFromRecoveryPhrase(this.generatedRecoveryPhrase, this.password1)) {\n              this.$store.dispatch(\"app/SET_STATUS\", AppStatus.synchronize);\n            }\n          }\n          break;\n      }\n      this.current = next;\n    },\n    previousStep() {\n      if (this.current === 3 && this.isRecovery) this.current = 1;\n      else this.current--;\n    },\n    recoverFromPhrase() {\n      this.isRecovery = true;\n      this.nextStep();\n    },\n    onPossiblePhrase(phrase) {\n      this.isRecoveryPhraseInvalid = null;\n      this.possiblePhrase = phrase;\n    },\n    validatePhraseOnEnter() {\n      if (this.possiblePhrase !== null) {\n        this.nextStep();\n      }\n    },\n    validatePasswordsOnEnter() {\n      if (event.keyCode === 13 && this.passwordsValidated) this.nextStep();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.setup-view {\n  height: 100%;\n}\n\n.steps-container {\n  flex: 1;\n}\n\n.settings-row {\n  margin: 0 -10px;\n  padding: 10px;\n  cursor: pointer;\n}\n\n.settings-row:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n}\n\n.arrow {\n  float: right;\n  color: #000;\n}\n\n.settings-row:hover > .arrow {\n  color: #000;\n}\n\n.phrase {\n  padding: 10px;\n  font-size: 1.05em;\n  font-weight: 500;\n  text-align: center;\n  word-spacing: 4px;\n  background-color: #f5f5f5;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/electron_vue/src/walletPath.js",
    "content": "import { app } from \"electron\";\n\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\nimport os from \"os\";\nimport path from \"path\";\n\nlet walletPath = \"\";\n\nif (process.type !== \"renderer\") {\n  if (os.platform() === \"linux\") {\n    walletPath = path.join(app.getPath(\"home\"), isDevelopment ? \".munt_dev\" : \".munt\");\n  } else {\n    walletPath = app.getPath(\"userData\");\n    if (isDevelopment) walletPath = walletPath + \"_dev\";\n  }\n}\n\nexport default walletPath;\n"
  },
  {
    "path": "src/frontend/electron_vue/ui-config.json",
    "content": "{\n  \"isSingleAccount\": false,\n  \"isSPV\": false,\n  \"themes\": []\n}\n"
  },
  {
    "path": "src/frontend/electron_vue/vue.config.js",
    "content": "module.exports = {\n  configureWebpack: {\n    // Configuration applied to all builds\n  },\n  pluginOptions: {\n    electronBuilder: {\n      nodeIntegration: true,\n      mainProcessWatch: [],\n      mainProcessArgs: [],\n      builderOptions: {\n        appId: \"org.munt.desktop-wallet\",\n        productName: \"Munt\",\n        extraFiles: [],\n        publish: null,\n        afterSign: \"./notarize.js\",\n        mac: {\n          category: \"public.app-category.finance\",\n          asar: false,\n          hardenedRuntime: true\n        },\n        win: {\n          sign: \"./sign.js\"\n        },\n        linux: {\n          category: \"public.app-category.finance\"\n        },\n        dmg: {\n          background: \"./build/background.tiff\",\n          contents: [\n            {\n              x: 410,\n              y: 190,\n              type: \"link\",\n              path: \"/Applications\"\n            },\n            {\n              x: 130,\n              y: 190,\n              type: \"file\"\n            }\n          ]\n        }\n      },\n      // HACK! Work around issues with electron-vue-builder being too old and new webpack... (files not loading without this)\n      customFileProtocol: \"./\"\n    },\n    i18n: {\n      locale: \"en\",\n      fallbackLocale: \"en\",\n      localeDir: \"locales\",\n      enableInSFC: false\n    }\n  },\n  css: {\n    loaderOptions: {\n      less: {},\n      postcss: { postcssOptions: { config: false } }\n    }\n  }\n};\n\n// HACK: OpenSSL 3 does not support md4 any more, but webpack hardcodes it all over the place: https://github.com/webpack/webpack/issues/13572\nconst crypto = require(\"crypto\");\nconst crypto_orig_createHash = crypto.createHash;\ncrypto.createHash = algorithm => crypto_orig_createHash(algorithm == \"md4\" ? \"sha256\" : algorithm);\n"
  },
  {
    "path": "src/frontend/lite/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n#Electron-builder output\n/dist_electron\n\n# Exclude libunity .node file\n/src/unity/*.node\n\n# Confidential Credentials\nholdinAPI.js\n\n# We use public folder to work around electron builders/webpack deficiencies (no other way to include files like staticfiltercp in app.asar)\n# However we automatically copy all files into here when building, so shouldn't ever commit them\n/public/staticfiltercp\n\nyarn.lock\n"
  },
  {
    "path": "src/frontend/lite/README.md",
    "content": "# Munt-lite Electron Wallet\n\n## Project setup\n```\nyarn\n```\n\n### Copy os specific unity lib to src/unity folder\n```\nyarn libunity:copy\n```\n\n### Compiles and hot-reloads for development\n```\nyarn electron:serve\n```\n\n### Compiles and minifies for production\n```\nyarn electron:build\n```\n\n### Lints and fixes files\n```\nyarn lint\n```\n"
  },
  {
    "path": "src/frontend/lite/babel.config.js",
    "content": "module.exports = {\n  presets: [\"@vue/cli-plugin-babel/preset\"],\n  plugins: []\n};\n"
  },
  {
    "path": "src/frontend/lite/holdinAPI.js.in",
    "content": "const apiKey = null;\n\nexport { apiKey };\n"
  },
  {
    "path": "src/frontend/lite/libunity/copy.js",
    "content": "var os = require(\"os\");\n\nlet repo =\n  \"https://github.com/muntorg/munt-official/releases/download/development/\";\n\nlet file = \"\";\nif (os.platform() === \"win32\") {\n  file = \"libmunt_win_\" + os.arch() + \".node\";\n} else if (os.platform() === \"linux\") {\n  file = \"libmunt_linux_\" + os.arch() + \".node\";\n} else if (os.platform() === \"darwin\") {\n    file = \"libmunt_macos_\" + os.arch() + \".node\";\n} else {\n  throw \"Unable to determine platform\";\n}\n\nconst fs = require(\"fs\");\nconst request = require(\"request\");\nlet error;\nconst download = (uri, filename) => {\n  request(uri)\n    .on(\"error\", err => {\n      error = err;\n    })\n    .on(\"response\", response => {\n      if (response.statusCode !== 200) {\n        error = `error downloading ${uri} : ${response.statusCode}`;\n      } else {\n        console.log(`downloading ${uri}...`);\n      }\n    })\n    .pipe(fs.createWriteStream(filename))\n    .on(\"close\", () => {\n      if (error !== undefined) console.error(error);\n      else console.log(`fetched ${src} -> ${dst}`);\n    });\n};\n\nconst path = require(\"path\");\nlet src = repo + file;\nlet dst = path.join(__dirname, `../src/unity/lib_unity.node`);\ndownload(src, dst);\n"
  },
  {
    "path": "src/frontend/lite/libunity/generate.js",
    "content": "var fs = require(\"fs\");\nvar path = require(\"path\");\n\nlet inputFile = path.join(__dirname, \"../../../unity/djinni/node_js/unifiedbackend_doc.js\");\n\nlet controllerFile = path.join(__dirname, \"/../src/unity/Controllers.js\");\nlet libUnityFile = path.join(__dirname, \"/../src/unity/LibUnity.js\");\n\nlet fileToParse = fs.readFileSync(inputFile, \"utf8\");\nlet dataToParse = fileToParse.split(\"\\n\");\n\nlet controllers = [\n  {\n    className: \"NJSILibraryController\",\n    exclude: [\n      \"InitUnityLib\",\n      \"InitUnityLibThreaded\",\n      \"ContinueWalletFromRecoveryPhrase\",\n      \"InitWalletLinkedFromURI\",\n      \"ContinueWalletLinkedFromURI\",\n      \"InitWalletFromAndroidLegacyProtoWallet\",\n      \"isValidAndroidLegacyProtoWallet\",\n      \"PersistAndPruneForSPV\",\n      \"getMutationHistory\",\n      \"getTransactionHistory\",\n      \"HaveUnconfirmedFunds\",\n      \"GetBalance\"\n    ]\n  },\n  {\n    className: \"NJSIWalletController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIRpcController\",\n    exclude: [\"execute\"],\n    custom: [\n      {\n        name: \"Execute\",\n        args: [\"command\"]\n      }\n    ]\n  },\n  {\n    className: \"NJSIP2pNetworkController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIAccountsController\",\n    exclude: [\"setListener\"]\n  },\n  {\n    className: \"NJSIWitnessController\"\n  },\n  {\n    className: \"NJSIGenerationController\",\n    exclude: [\"setListener\"]\n  }\n];\n\nfor (let i = 0; i < controllers.length; i++) {\n  getFunctionsFor(controllers[i]);\n}\n\nfunction getFunctionsFor(controller) {\n  controller.functions = [];\n  let exclude = controller.exclude || [];\n\n  let startFound = false;\n  let endFound = false;\n\n  let i = 0;\n  while (endFound === false) {\n    let line = dataToParse[i++].trim();\n    if (startFound === false) {\n      if (line.indexOf(`declare class ${controller.className}`) !== -1) {\n        startFound = true;\n      }\n      continue;\n    } else if (line === \"}\") {\n      endFound = true;\n      continue;\n    }\n\n    line = line.replace(\"\\r\\n\", \"\");\n    if (line.startsWith(\"static declare function\") === false) continue;\n    line = line.replace(\"static declare function\", \"\").trim();\n\n    let openingBracketIdx = line.indexOf(\"(\");\n    let closingBracketIdx = line.indexOf(\")\");\n    let name = line.substr(0, openingBracketIdx);\n\n    let skip = false;\n    for (let j = 0; j < exclude.length; j++) {\n      if (name.toLowerCase() === exclude[j].toLowerCase()) {\n        skip = true;\n        break;\n      }\n    }\n    if (skip) continue;\n\n    let args = line.substr(openingBracketIdx + 1, closingBracketIdx - openingBracketIdx - 1);\n\n    if (args.length > 0) {\n      let argsSplit = args.split(\", \");\n      let arr = [];\n      argsSplit.forEach(arg => {\n        arr.push(arg.substr(0, arg.indexOf(\":\")));\n      });\n\n      args = arr.join(\", \");\n    }\n\n    controller.functions.push({ name: name, args: args });\n  }\n}\n\nfunction getControllerCode() {\n  let code = [];\n\n  for (let i = 0; i < controllers.length; i++) {\n    let controller = controllers[i];\n    let custom = controller.custom || [];\n\n    code.push(`class ${controller.className.replace(\"NJSI\", \"\")} {`);\n\n    for (let j = 0; j < custom.length; j++) {\n      let f = custom[j];\n      if (j > 0) code.push(``);\n      code.push(`static async ${f.name}Async(${f.args}) {`);\n      code.push(\n        `return handleError(await ipc.callMain(\"${controller.className}.${f.name}Async\"${f.args.length > 0 ? \", {\" + f.args + \"}\" : \"\"})\n        );`\n      );\n      code.push(`}`);\n      code.push(``);\n      code.push(`static ${f.name}(${f.args}) {`);\n      code.push(\n        `return handleError(ipc.sendSync(\"${controller.className}.${f.name}\"${f.args.length > 0 ? \", \" + f.args : \"\"})\n        );`\n      );\n      code.push(`}`);\n    }\n\n    for (let j = 0; j < controller.functions.length; j++) {\n      let f = controller.functions[j];\n      if (j > 0) code.push(``);\n      code.push(`static async ${PascalCase(f.name)}Async(${f.args}) {`);\n      code.push(`return handleError(await ipc.callMain(\"${controller.className}.${f.name}Async\"${f.args.length > 0 ? \", {\" + f.args + \"}\" : \"\"}));`);\n      code.push(`}`);\n      code.push(``);\n      code.push(`static ${PascalCase(f.name)}(${f.args}) {`);\n      code.push(`return handleError(ipc.sendSync(\"${controller.className}.${f.name}\"${f.args.length > 0 ? \", \" + f.args : \"\"}));`);\n      code.push(`}`);\n    }\n\n    code.push(`}`);\n    code.push(``);\n  }\n\n  code.push(`export {`);\n\n  for (let i = 0; i < controllers.length; i++) {\n    code.push(`${controllers[i].className.replace(\"NJSI\", \"\")}${i + 1 < controllers.length ? \",\" : \"\"}`);\n  }\n\n  code.push(`}`);\n  code.push(``);\n\n  return code;\n}\n\nfunction getLibUnityCode() {\n  let code = [];\n\n  for (let i = 0; i < controllers.length; i++) {\n    let controller = controllers[i];\n    let className = controller.className.replace(\"NJSI\", \"\");\n    className = className.charAt(0).toLowerCase() + className.substr(1);\n\n    if (i > 0) code.push(``);\n    code.push(`// Register ${controller.className} ipc handlers`);\n\n    for (let j = 0; j < controller.functions.length; j++) {\n      let f = controller.functions[j];\n      if (j > 0) code.push(``);\n      code.push(`ipc.answerRenderer(\"${controller.className}.${f.name}Async\", async ${f.args.length > 0 ? \"data\" : \"()\"} => {`);\n\n      let args = f.args.length > 0 ? f.args.split(\", \") : [];\n      let consoleArgs = \"\";\n      if (args.length > 0) {\n        for (let k = 0; k < args.length; k++) {\n          consoleArgs += k > 0 ? \", \" : \"\";\n          consoleArgs += \"${data.\" + args[k] + \"}\";\n        }\n      }\n\n      code.push(`\n        console.log(\\`IPC: ${className}.${f.name}Async(${consoleArgs})\\`);\n        try {\n          let result = this.${className}.${f.name}(\n            ${f.args.length > 0 ? \"data.\" + f.args.split(\", \").join(\", data.\") : \"\"}\n          );\n          return {\n            success: true,\n            result: result\n          };\n        }\n        catch(e) {\n          return handleError(e);\n        }\n      `);\n      code.push(`});`);\n      code.push(``);\n      code.push(`ipc.on(\"${controller.className}.${f.name}\", ${f.args.length > 0 ? \"(event, \" + f.args + \")\" : \"event\"} => {`);\n\n      args = f.args.length > 0 ? f.args.split(\", \") : [];\n      consoleArgs = \"\";\n      if (args.length > 0) {\n        for (let k = 0; k < args.length; k++) {\n          consoleArgs += k > 0 ? \", \" : \"\";\n          consoleArgs += \"${\" + args[k] + \"}\";\n        }\n      }\n\n      code.push(`\n        console.log(\\`IPC: ${className}.${f.name}(${consoleArgs})\\`);\n        try {\n          let result = this.${className}.${f.name}(${f.args});\n          event.returnValue = {\n            success: true,\n            result: result\n          };\n        }\n        catch(e) {\n          event.returnValue = handleError(e);\n        }\n      `);\n      code.push(`});`);\n    }\n  }\n\n  code.push(``);\n  return code;\n}\n\nlet controllerData = fs.readFileSync(controllerFile, \"utf-8\");\n\nlet replace = \"\";\nreplace += \"/* inject:generated-code */\\r\\n\";\nreplace += getControllerCode().join(\"\\r\\n\");\nreplace += \"/* inject:generated-code */\";\n\nlet result = controllerData.replace(/\\/\\* inject:generated-code \\*\\/(.)+\\/\\* inject:generated-code \\*\\//s, replace);\nfs.writeFileSync(controllerFile, result, \"utf-8\");\n\nlet libUnityData = fs.readFileSync(libUnityFile, \"utf-8\");\nreplace = \"\";\nreplace += \"/* inject:generated-code */\\r\\n\";\nreplace += getLibUnityCode().join(\"\\r\\n\");\nreplace += \"/* inject:generated-code */\";\n\nresult = libUnityData.replace(/\\/\\* inject:generated-code \\*\\/(.)+\\/\\* inject:generated-code \\*\\//s, replace);\nfs.writeFileSync(libUnityFile, result, \"utf-8\");\n\nfunction PascalCase(line) {\n  return line.charAt(0).toUpperCase() + line.substr(1);\n}\n"
  },
  {
    "path": "src/frontend/lite/notarize.js",
    "content": "\"use strict\";\n\nconst path = require(\"path\");\nconst { notarize } = require(\"electron-notarize\");\n\nconst getAuthInfo = () => {\n  const { APPLE_ID: appleId, APPLE_ID_PASSWORD: appleIdPassword, APP_ID: appId } = process.env;\n\n  if (!appleId || !appleIdPassword) {\n    throw new Error(\"One of APPLE_ID and APPLE_ID_PASSWORD environment variables is missing for notarization.\");\n  }\n  if (!appId) {\n    throw new Error(\"Unable to determine appID\");\n  }\n\n  return {\n    appleId,\n    appleIdPassword\n  };\n};\n\nmodule.exports = async params => {\n  if (params.electronPlatformName !== \"darwin\") {\n    return;\n  }\n\n  // Read and validate auth information from environment variables\n  let authInfo;\n  try {\n    authInfo = getAuthInfo();\n  } catch (error) {\n    console.log(`Skipping notarization: ${error.message}`);\n    return;\n  }\n\n  let appId = authInfo.appId;\n  const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);\n\n  const notarizeOptions = { appBundleId: appId, appPath };\n  notarizeOptions.appleId = authInfo.appleId;\n  notarizeOptions.appleIdPassword = authInfo.appleIdPassword;\n\n  console.log(`Notarizing ${appId} found at ${appPath}`);\n  await notarize(notarizeOptions);\n  console.log(`Done notarizing ${appId}`);\n};\n"
  },
  {
    "path": "src/frontend/lite/package.json",
    "content": "{\n  \"name\": \"Munt-lite\",\n  \"description\": \"Munt currency, light/SPV based wallet\",\n  \"author\": \"Centure.com BV\",\n  \"version\": \"3.0.7\",\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"node ./setup.js && vue-cli-service lint\",\n    \"electron:build\": \"node ./setup.js && vue-cli-service electron:build\",\n    \"electron:serve\": \"node ./setup.js && vue-cli-service electron:serve\",\n    \"electron:generate-icons\": \"electron-icon-builder --input=./public/icon.png --output=build --flatten\",\n    \"i18n:report\": \"vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'\",\n    \"postinstall\": \"electron-builder install-app-deps\",\n    \"postuninstall\": \"electron-builder install-app-deps\",\n    \"libunity:copy\": \"node ./libunity/copy.js\",\n    \"libunity:generate\": \"node ./libunity/generate.js && yarn lint\"\n  },\n  \"main\": \"background.js\",\n  \"dependencies\": {\n    \"@fortawesome/fontawesome-pro\": \"^6.4.0\",\n    \"@fortawesome/fontawesome-svg-core\": \"^6.1.0\",\n    \"@fortawesome/pro-light-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/pro-regular-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/vue-fontawesome\": \"^2.0.2\",\n    \"@json2csv/plainjs\": \"^7.0.1\",\n    \"axios\": \"^1.3.4\",\n    \"core-js\": \"^3.31.1\",\n    \"electron-better-ipc\": \"^2.0.1\",\n    \"electron-store\": \"^8.1.0\",\n    \"lodash.clonedeep\": \"^4.5.0\",\n    \"portal-vue\": \"^2.1.7\",\n    \"qrcode\": \"^1.5.1\",\n    \"vue\": \"^2.6.12\",\n    \"vue-i18n\": \"^8.24.2\",\n    \"vue-js-toggle-button\": \"^1.3.3\",\n    \"vue-qrcode\": \"^0.3.5\",\n    \"vue-router\": \"^3.5.1\",\n    \"vue-slider-component\": \"^3.2.11\",\n    \"vuex\": \"^3.6.2\",\n    \"vuex-electron\": \"https://github.com/devlz303/vuex-electron.git#v1.0.4\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.12.16\",\n    \"@babel/eslint-parser\": \"^7.12.16\",\n    \"@oshell/vue-cli-plugin-electron-builder-notarize\": \"^1.0.2\",\n    \"@vue/cli-plugin-babel\": \"~5.0.8\",\n    \"@vue/cli-plugin-eslint\": \"~5.0.8\",\n    \"@vue/cli-plugin-router\": \"~5.0.8\",\n    \"@vue/cli-plugin-vuex\": \"~5.0.8\",\n    \"@vue/cli-service\": \"~5.0.8\",\n    \"@vue/eslint-config-prettier\": \"^6.0.0\",\n    \"babel-plugin-import\": \"^1.13.3\",\n    \"electron\": \"^25.3.0\",\n    \"electron-builder\": \"^24.4.0\",\n    \"electron-icon-builder\": \"^2.0.1\",\n    \"eslint\": \"^8.45.0\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"eslint-plugin-vue\": \"^8.0.3\",\n    \"less\": \"^4.1.1\",\n    \"less-loader\": \"^11.1.3\",\n    \"native-ext-loader\": \"^2.3.0\",\n    \"prettier\": \"^2.4.1\",\n    \"vue-cli-plugin-ant-design\": \"~1.0.1\",\n    \"vue-cli-plugin-electron-builder\": \"~2.1.1\",\n    \"vue-cli-plugin-i18n\": \"~2.3.1\",\n    \"vue-template-compiler\": \"^2.6.12\",\n    \"webpack\": \"^5.88.1\"\n  },\n  \"resolutions\": {\n    \"**/@achrinza/node-ipc\": \"^10.1.9\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"env\": {\n      \"node\": true\n    },\n    \"extends\": [\n      \"plugin:vue/essential\",\n      \"eslint:recommended\",\n      \"@vue/prettier\"\n    ],\n    \"parserOptions\": {\n      \"parser\": \"@babel/eslint-parser\"\n    },\n    \"rules\": {\n      \"no-unused-vars\": [\n        \"warn\",\n        {\n          \"argsIgnorePattern\": \"^_\",\n          \"varsIgnorePattern\": \"^_\"\n        }\n      ],\n      \"vue/multi-word-component-names\": [\n        \"error\",\n        {\n          \"ignores\": [\n            \"Send\",\n            \"Receive\",\n            \"Transactions\",\n            \"Account\",\n            \"index\",\n            \"Setup\"\n          ]\n        }\n      ],\n      \"comma-dangle\": \"off\",\n      \"wrap-iife\": \"off\",\n      \"arrow-parens\": \"off\",\n      \"linebreak-style\": \"off\"\n    }\n  },\n  \"prettier\": {\n    \"printWidth\": 160,\n    \"trailingComma\": \"none\",\n    \"arrowParens\": \"avoid\",\n    \"singleAttributePerLine\": false\n  },\n  \"browserslist\": [\n    \"Electron >= 17.1.0\"\n  ]\n}\n"
  },
  {
    "path": "src/frontend/lite/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "src/frontend/lite/setup.js",
    "content": "const fs = require(\"fs\");\nconst path = require(\"path\");\nlet src = path.join(__dirname, `holdinAPI.js.in`);\nlet dst = path.join(__dirname, `holdinAPI.js`);\nfs.copyFile(src, dst, fs.constants.COPYFILE_EXCL, err => {});\n\nlet src_filter = path.join(__dirname, `../../data/staticfiltercp`);\nlet dst_filter = path.join(__dirname, `/public/staticfiltercp`);\nfs.copyFile(src_filter, dst_filter, fs.constants.COPYFILE_EXCL, err => {});\n"
  },
  {
    "path": "src/frontend/lite/sign.js",
    "content": "exports.default = async function (configuration) {\n  const CERTIFICATE_PATH = process.env.CERTIFICATE_PATH;\n  const CERTIFICATE_KEY = process.env.CERTIFICATE_KEY;\n  const CERTIFICATE_NAME = process.env.CERTIFICATE_NAME;\n  const CERTIFICATE_URL = process.env.CERTIFICATE_URL;\n  const CERTIFICATE_PASS = process.env.CERTIFICATE_PASS;\n  require(\"child_process\").execSync(\n    `osslsigncode-2.0/osslsigncode -pass \"${CERTIFICATE_PASS}\" -spc \"${CERTIFICATE_PATH}\" -key \"${CERTIFICATE_KEY}\" -n \"${CERTIFICATE_NAME}\" -i \"${CERTIFICATE_URL}\" -in \"${configuration.path}\" -out \"${configuration.path}2\" && mv \"${configuration.path}2\" \"${configuration.path}\"`,\n    {\n      stdio: \"inherit\"\n    }\n  );\n};\n"
  },
  {
    "path": "src/frontend/lite/src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <app-wallet v-if=\"isWallet\" />\n    <router-view v-else />\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppWallet from \"./AppWallet\";\n\nexport default {\n  name: \"App\",\n  components: {\n    AppWallet\n  },\n  created() {\n    this.changeLanguage(this.language);\n    document.querySelector(\"html\").dataset.theme = this.theme;\n  },\n  watch: {\n    language() {\n      this.changeLanguage(this.language);\n    },\n    theme() {\n      document.querySelector(\"html\").dataset.theme = this.theme;\n    }\n  },\n  computed: {\n    ...mapState(\"app\", [\"language\", \"theme\"]),\n    isWallet() {\n      switch (window.location.hash.toLowerCase()) {\n        case \"#/debug\":\n          return false;\n        default:\n          return true;\n      }\n    }\n  },\n  methods: {\n    changeLanguage(language) {\n      if (this.$i18n.locale === language) return;\n      this.$i18n.locale = language;\n      this.$forceUpdate();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\">\n@import \"./css/app.less\";\n\n*,\n#app {\n  font-family: euclid, Helvetica, sans-serif;\n  font-style: normal;\n  font-weight: 400;\n  font-size: 15px;\n  -webkit-text-size-adjust: none;\n  text-rendering: optimizeLegibility;\n  font-variant-ligatures: none;\n  -webkit-font-smoothing: antialiased;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/AppStatus.js",
    "content": "const AppStatus = {\n  start: \"start\",\n  setup: \"setup\",\n  synchronize: \"synchronize\",\n  ready: \"ready\",\n  shutdown: \"shutdown\"\n};\n\nexport default AppStatus;\n"
  },
  {
    "path": "src/frontend/lite/src/AppWallet.vue",
    "content": "<template>\n  <div class=\"app-wallet\">\n    <app-loader />\n    <modal-dialog v-model=\"modal\" />\n    <unlock-wallet-dialog />\n    <activity-indicator v-if=\"activityIndicator\" />\n    <component :is=\"layout\">\n      <router-view />\n    </component>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppStatus from \"./AppStatus\";\nimport AppLoader from \"./components/AppLoader\";\nimport ModalDialog from \"./components/ModalDialog\";\nimport EventBus from \"./EventBus.js\";\nimport ActivityIndicator from \"./components/ActivityIndicator.vue\";\nimport UnlockWalletDialog from \"./components/UnlockWalletDialog\";\n\nimport SetupLayout from \"./layouts/SetupLayout\";\nimport WalletLayout from \"./layouts/WalletLayout\";\n\nexport default {\n  name: \"AppWallet\",\n  data() {\n    return {\n      modal: null\n    };\n  },\n  components: {\n    AppLoader,\n    ModalDialog,\n    SetupLayout,\n    WalletLayout,\n    ActivityIndicator,\n    UnlockWalletDialog\n  },\n  created() {\n    this.onStatusChanged();\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.closeModal);\n    EventBus.$on(\"show-dialog\", this.showModal);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"close-dialog\", this.closeModal);\n    EventBus.$off(\"show-dialog\", this.showModal);\n  },\n  computed: {\n    ...mapState(\"app\", [\"status\", \"activityIndicator\"]),\n    layout() {\n      return this.$route.meta.layout || WalletLayout;\n    }\n  },\n  watch: {\n    status() {\n      this.onStatusChanged();\n    }\n  },\n  methods: {\n    onStatusChanged() {\n      let routeName;\n      switch (this.status) {\n        case AppStatus.setup:\n          routeName = \"setup\";\n          break;\n        case AppStatus.synchronize:\n          routeName = \"account\";\n          break;\n        case AppStatus.ready:\n          routeName = \"account\";\n          break;\n      }\n      if (routeName === undefined || this.$route.name === routeName) return;\n      this.$router.push({ name: routeName });\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    showModal(modal) {\n      this.modal = modal;\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/EventBus.js",
    "content": "import Vue from \"vue\";\nexport default new Vue();\n"
  },
  {
    "path": "src/frontend/lite/src/background.js",
    "content": "\"use strict\";\n/* global __static */\n\nimport { app, protocol, Menu, BrowserWindow, shell } from \"electron\";\nimport {\n  createProtocol\n  /* installVueDevtools */\n} from \"vue-cli-plugin-electron-builder/lib\";\n\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\nconst os = require(\"os\");\n\nimport path from \"path\";\nimport fs from \"fs\";\n\nimport LibUnity from \"./unity/LibUnity\";\nimport walletPath from \"./walletPath\";\n\nimport store from \"./store\";\nimport AppStatus from \"./AppStatus\";\nimport axios from \"axios\";\n\n// Keep a global reference of the window object, if you don't, the window will\n// be closed automatically when the JavaScript object is garbage collected.\nlet winMain;\nlet winDebug;\nlet libUnity = new LibUnity({ walletPath });\n\n// Handle URI links (munt: muntlite://)\n// If we are launching a second instance then terminate and let the first instance handle it instead\n//NB! This must happen before all other app related code (especially libulden init) as otherwise second process can crash\nconst gotTheLock = app.requestSingleInstanceLock();\nif (!gotTheLock) {\n  app.quit();\n} else {\n  app.on(\"second-instance\", (_event, _commandLine, _workingDirectory) => {\n    focusMainWindow();\n  });\n  // Protocol handler for osx\n  app.on(\"open-url\", (event, _url) => {\n    event.preventDefault();\n    focusMainWindow();\n  });\n}\nif (process.defaultApp) {\n  if (process.argv.length >= 2) {\n    app.setAsDefaultProtocolClient(\"muntlite\", process.execPath, [path.resolve(process.argv[1])]);\n  }\n} else {\n  app.setAsDefaultProtocolClient(\"muntlite\");\n}\n// End of URI handling\n\n/* TODO: refactor into function and add option to libmunt to remove existing wallet folder */\nif (isDevelopment) {\n  let args = process.argv.slice(2);\n  for (var i = 0; i < args.length; i++) {\n    switch (args[i].toLowerCase()) {\n      case \"new-wallet\":\n        fs.rmdirSync(walletPath, {\n          recursive: true\n        });\n        break;\n      default:\n        console.error(`unknown argument: ${args[i]}`);\n        break;\n    }\n  }\n}\n\n// Scheme must be registered before the app is ready\nprotocol.registerSchemesAsPrivileged([{ scheme: \"app\", privileges: { secure: true, standard: true } }]);\n\nfunction createMainWindow() {\n  console.log(\"createMainWindow\");\n  let options = {\n    width: 800,\n    minWidth: 800,\n    height: 600,\n    minHeight: 600,\n    show: false,\n    title: \"Munt-lite\",\n    webPreferences: {\n      // Use pluginOptions.nodeIntegration, leave this alone\n      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info\n      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,\n      contextIsolation: false\n    }\n  };\n  if (os.platform() === \"linux\") {\n    options = Object.assign({}, options, {\n      icon: path.join(__static, \"icon.png\")\n    });\n  }\n  winMain = new BrowserWindow(options);\n\n  var menuTemplate = [\n    {\n      label: \"File\",\n      submenu: [{ role: \"quit\" }]\n    },\n    {\n      label: \"Edit\",\n      submenu: [{ role: \"cut\" }, { role: \"copy\" }, { role: \"paste\" }]\n    },\n    {\n      label: \"Help\",\n      submenu: [\n        {\n          label: \"Debug window\",\n          enabled: store.state.app.coreReady,\n          click() {\n            createDebugWindow();\n          }\n        }\n      ]\n    }\n  ];\n\n  if (isDevelopment) {\n    menuTemplate.push({\n      label: \"Development\",\n      submenu: [{ role: \"toggleDevTools\" }]\n    });\n  }\n\n  var menu = Menu.buildFromTemplate(menuTemplate);\n\n  Menu.setApplicationMenu(menu);\n\n  if (process.env.WEBPACK_DEV_SERVER_URL) {\n    // Load the url of the dev server if in development mode\n    winMain.loadURL(process.env.WEBPACK_DEV_SERVER_URL);\n    //if (!process.env.IS_TEST) win.webContents.openDevTools();\n  } else {\n    createProtocol(\"app\");\n    // Load the index.html when not in development\n    winMain.loadURL(\"app://./index.html\");\n  }\n\n  winMain.on(\"ready-to-show\", () => {\n    console.log(\"ready-to-show main window\");\n    libUnity.SetMainWindowReady();\n    winMain.show();\n  });\n\n  winMain.on(\"close\", event => {\n    console.log(\"winMain.on:close\");\n    if (process.platform !== \"darwin\") {\n      EnsureUnityLibTerminated(event);\n    }\n  });\n\n  winMain.on(\"closed\", () => {\n    console.log(\"winMain.on:closed\");\n    winMain = null;\n  });\n\n  // Force external hrefs to open in external browser\n  winMain.webContents.on(\"new-window\", function (e, url) {\n    e.preventDefault();\n    shell.openExternal(url);\n  });\n}\n\nfunction createDebugWindow() {\n  if (winDebug) {\n    return winDebug.show();\n  }\n\n  let options = {\n    width: 600,\n    minWidth: 400,\n    height: 600,\n    minHeight: 400,\n    show: false,\n    parent: winMain,\n    title: \"Munt Debug Window\",\n    skipTaskBar: true,\n    autoHideMenuBar: true,\n    webPreferences: {\n      // Use pluginOptions.nodeIntegration, leave this alone\n      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info\n      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,\n      contextIsolation: false\n    }\n  };\n  if (os.platform() === \"linux\") {\n    options = Object.assign({}, options, {\n      icon: path.join(__static, \"icon.png\")\n    });\n  }\n  winDebug = new BrowserWindow(options);\n\n  let url = process.env.WEBPACK_DEV_SERVER_URL ? `${process.env.WEBPACK_DEV_SERVER_URL}#/debug` : `app://./index.html#/debug`;\n\n  if (process.env.WEBPACK_DEV_SERVER_URL) {\n    // Load the url of the dev server if in development mode\n    winDebug.loadURL(url);\n    //if (!process.env.IS_TEST) win.webContents.openDevTools();\n  } else {\n    createProtocol(\"app\");\n    // Load the index.html when not in development\n    winDebug.loadURL(url);\n  }\n\n  winDebug.on(\"ready-to-show\", () => {\n    winDebug.show();\n  });\n\n  winDebug.on(\"close\", event => {\n    console.log(\"winDebug.on:close\");\n    if (libUnity === null || libUnity.isTerminated) return;\n    event.preventDefault();\n    winDebug.hide();\n  });\n\n  winDebug.on(\"closed\", () => {\n    console.log(\"winDebug.on:closed\");\n    winDebug = null;\n  });\n}\n\napp.on(\"will-quit\", event => {\n  console.log(\"app.on:will-quit\");\n  if (libUnity === null || libUnity.isTerminated) return;\n  store.dispatch(\"app/SET_STATUS\", AppStatus.shutdown);\n  event.preventDefault();\n  libUnity.TerminateUnityLib();\n});\n\n// Quit when all windows are closed.\napp.on(\"window-all-closed\", event => {\n  console.log(\"app.on:window-all-closed\");\n  // On macOS it is common for applications and their menu bar\n  // to stay active until the user quits explicitly with Cmd + Q\n  if (process.platform !== \"darwin\") {\n    EnsureUnityLibTerminated(event);\n  }\n});\n\napp.on(\"activate\", () => {\n  // On macOS it's common to re-create a window in the app when the\n  // dock icon is clicked and there are no other windows open.\n  if (winMain === null) {\n    createMainWindow();\n  }\n});\n\n// This method will be called when Electron has finished\n// initialization and is ready to create browser windows.\n// Some APIs can only be used after this event occurs.\napp.on(\"ready\", async () => {\n  if (isDevelopment && !process.env.IS_TEST) {\n    // Install Vue Devtools\n    // Devtools extensions are broken in Electron 6.0.0 and greater\n    // See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info\n    // Electron will not launch with Devtools extensions installed on Windows 10 with dark mode\n    // If you are not using Windows 10 dark mode, you may uncomment these lines\n    // In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines\n    // try {\n    //   await installVueDevtools()\n    // } catch (e) {\n    //   console.error('Vue Devtools failed to install:', e.toString())\n    // }\n  }\n\n  store.dispatch(\"app/SET_WALLET_VERSION\", app.getVersion());\n  libUnity.Initialize();\n\n  updateRate(60);\n\n  createMainWindow();\n});\n\nasync function updateRate(seconds) {\n  try {\n    // use blockhut api instead of https://api.munt.org/api/v1/ticker\n    const response = await axios.get(\"https://blockhut.com/munt/munteuro.json\");\n\n    store.dispatch(\"app/SET_RATE\", response.data.eurmunt);\n  } catch (error) {\n    console.error(error);\n  } finally {\n    setTimeout(() => {\n      updateRate(seconds);\n    }, seconds * 1000);\n  }\n}\n\nfunction EnsureUnityLibTerminated(event) {\n  if (libUnity === null || libUnity.isTerminated) return;\n  store.dispatch(\"app/SET_STATUS\", AppStatus.shutdown);\n  event.preventDefault();\n  libUnity.TerminateUnityLib();\n}\n\n// Exit cleanly on request from parent process in development mode.\nif (isDevelopment) {\n  if (process.platform === \"win32\") {\n    process.on(\"message\", data => {\n      if (data === \"graceful-exit\") {\n        app.quit();\n      }\n    });\n  } else {\n    process.on(\"SIGTERM\", () => {\n      app.quit();\n    });\n  }\n}\n\nfunction focusMainWindow() {\n  if (winMain) {\n    if (winMain.isMinimized()) winMain.restore();\n    else winMain.show();\n    winMain.focus();\n  }\n}\n"
  },
  {
    "path": "src/frontend/lite/src/components/AccountHeader.vue",
    "content": "<template>\n  <div>\n    <confirm-dialog v-model=\"modal\" />\n    <div class=\"account-header\">\n      <div v-if=\"!editMode\" class=\"flex-row\">\n        <div v-if=\"isSingleAccount\" class=\"flex-row flex-1\">\n          <div class=\"logo\" />\n          <div class=\"balance-row flex-1\">\n            <span>{{ balanceForDisplay }}</span>\n            <span>{{ totalBalanceFiat }}</span>\n          </div>\n        </div>\n        <div v-else class=\"left-colum\">\n          <div>\n            <account-tooltip type=\"Account\" :account=\"account\">\n              <div style=\"display: flex; flex-direction: row\">\n                <div style=\"width: calc(100% - 45px)\" @click=\"editName\" class=\"flex-row flex-1\">\n                  <div class=\"accountname ellipsis\">{{ name }}</div>\n                  <fa-icon class=\"pen\" :icon=\"['fal', 'fa-pen']\" />\n                </div>\n                <div style=\"width: 40px; text-align: center\" @click=\"deleteAccount\" class=\"trash flex-row\">\n                  <fa-icon :icon=\"['fal', 'fa-trash']\" />\n                </div>\n              </div>\n              <div class=\"balance-row\">\n                <span>{{ balanceForDisplay }}</span>\n                <span>{{ totalBalanceFiat }}</span>\n              </div>\n            </account-tooltip>\n          </div>\n        </div>\n        <div v-if=\"showBuySellButtons\">\n          <button outlined class=\"small\" @click=\"buyCoins\" :disabled=\"buyDisabled\">{{ $t(\"buttons.buy\") }}</button>\n          <button outlined class=\"small\" @click=\"sellCoins\" :disabled=\"sellDisabled\">{{ $t(\"buttons.sell\") }}</button>\n        </div>\n        <div v-if=\"!showBuySellButtons && showHoldinButtons\">\n          <div v-if=\"!isLinkedToHoldin\">\n            <button outlined class=\"small\" @click=\"linkToHoldin('add')\" :disabled=\"sellDisabled\">\n              {{ $t(\"saving_account.add_to_holdin\") }}\n            </button>\n          </div>\n          <div v-else>\n            <button outlined class=\"small\" @click=\"linkToHoldin('remove')\" :disabled=\"sellDisabled\">\n              {{ $t(\"saving_account.remove_from_holdin\") }}\n            </button>\n          </div>\n        </div>\n        <div v-if=\"isSingleAccount\" class=\"flex-row icon-buttons\">\n          <div class=\"icon-button\">\n            <fa-icon :icon=\"['fal', 'cog']\" @click=\"showSettings\" />\n          </div>\n          <div class=\"icon-button\">\n            <fa-icon :icon=\"['fal', lockIcon]\" @click=\"changeLockSettings\" />\n          </div>\n        </div>\n      </div>\n      <input v-else ref=\"accountNameInput\" type=\"text\" v-model=\"newAccountName\" @keydown=\"onKeydown\" @blur=\"cancelEdit\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { AccountsController, BackendUtilities, WitnessController, GenerationController } from \"../unity/Controllers\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport AccountTooltip from \"./AccountTooltip.vue\";\nimport EventBus from \"../EventBus\";\nimport { apiKey } from \"../../holdinAPI\";\nimport ConfirmDialog from \"./ConfirmDialog.vue\";\n\nexport default {\n  components: { AccountTooltip, ConfirmDialog },\n  name: \"AccountHeader\",\n  data() {\n    return {\n      editMode: false,\n      newAccountName: null,\n      buyDisabled: false,\n      sellDisabled: false,\n      requestLinkToHoldin: false,\n      isLinkedToHoldin: false,\n      keyHash: \"\",\n      modal: null\n    };\n  },\n  props: {\n    account: {\n      type: Object,\n      default: () => {}\n    },\n    isSingleAccount: {\n      type: Boolean,\n      default: false\n    }\n  },\n  computed: {\n    ...mapState(\"app\", [\"rate\"]),\n    ...mapState(\"wallet\", [\"walletPassword\", \"unlocked\"]),\n    name() {\n      return this.account ? this.account.label : null;\n    },\n    totalBalanceFiat() {\n      if (!this.rate) return \"\";\n      return `€ ${formatMoneyForDisplay(this.account.balance * this.rate, true)}`;\n    },\n    balanceForDisplay() {\n      if (!this.account || this.account.balance === undefined) return \"\";\n      return formatMoneyForDisplay(this.account.balance);\n    },\n    showBuySellButtons() {\n      return !this.account || (this.account.type === \"Desktop\" && !this.editMode);\n    },\n    showHoldinButtons() {\n      return apiKey;\n    },\n    lockIcon() {\n      return this.unlocked ? \"unlock\" : \"lock\";\n    }\n  },\n  watch: {\n    name: {\n      immediate: true,\n      handler() {\n        this.editMode = false;\n      }\n    },\n    unlocked: {\n      immediate: true,\n      handler() {\n        if (this.unlocked && this.requestLinkToHoldin) {\n          // Check if add or remove.\n          if (this.isLinkedToHoldin) {\n            this.holdinAPI(\"remove\");\n          } else {\n            this.holdinAPI(\"add\");\n          }\n        }\n      }\n    },\n    account: {\n      immediate: true,\n      handler() {\n        if (!this.showBuySellButtons) {\n          this.checkForHoldinLink();\n        }\n      }\n    }\n  },\n  mounted() {\n    if (!this.showBuySellButtons) {\n      this.checkForHoldinLink();\n    }\n  },\n  methods: {\n    checkForHoldinLink() {\n      AccountsController.ListAccountLinksAsync(this.account.UUID).then(result => {\n        const findHoldin = result.find(element => element.serviceName == \"holdin\");\n        this.isLinkedToHoldin = findHoldin && findHoldin.serviceName === \"holdin\";\n        if (this.isLinkedToHoldin) {\n          this.keyHash = findHoldin.serviceData;\n        }\n      });\n    },\n    editName() {\n      this.newAccountName = this.name;\n      this.editMode = true;\n      this.$nextTick(() => {\n        this.$refs[\"accountNameInput\"].focus();\n      });\n    },\n    deleteAccount() {\n      this.showConfirmModal();\n    },\n    onKeydown(e) {\n      switch (e.keyCode) {\n        case 13:\n          this.changeAccountName();\n          break;\n        case 27:\n          this.editMode = false;\n          break;\n      }\n    },\n    changeAccountName() {\n      if (this.newAccountName !== this.account.label) {\n        AccountsController.RenameAccount(this.account.UUID, this.newAccountName);\n      }\n      this.editMode = false;\n    },\n    cancelEdit() {\n      this.editMode = false;\n    },\n    dismissIndicator() {\n      setTimeout(() => {\n        this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n      }, 1000);\n    },\n    async sellCoins() {\n      try {\n        this.sellDisabled = true;\n        const url = await BackendUtilities.GetSellSessionUrl();\n        window.open(url, \"sell-coins\");\n      } finally {\n        this.sellDisabled = false;\n      }\n    },\n    async buyCoins() {\n      try {\n        this.buyDisabled = true;\n        const url = await BackendUtilities.GetBuySessionUrl();\n        window.open(url, \"buy-coins\");\n      } finally {\n        this.buyDisabled = false;\n      }\n    },\n    showSettings() {\n      if (this.$route.path === \"/settings/\") return;\n      this.$router.push({ name: \"settings\" });\n    },\n    changeLockSettings() {\n      EventBus.$emit(this.unlocked ? \"lock-wallet\" : \"unlock-wallet\");\n    },\n    linkToHoldin(action) {\n      this.requestLinkToHoldin = true;\n\n      if (!this.unlocked) {\n        EventBus.$emit(\"unlock-wallet\");\n      } else {\n        this.holdinAPI(action);\n      }\n    },\n    async holdinAPI(action) {\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n      AccountsController.GetWitnessKeyURIAsync(this.account.UUID).then(async key => {\n        let result = null;\n\n        if (action === \"add\") {\n          let infoResult = await BackendUtilities.holdinAPIActions(key, \"getinfo\");\n          const keyHashLocal = infoResult.data.keyhash;\n\n          if (infoResult.data.available === 1 && infoResult.data.active === \"1\") {\n            // Account was linked elsewhere. Note that on Gulden and update the compound value.\n            GenerationController.GetGenerationAddressAsync()\n              .then(async payoutAddress => {\n                // Add payout address to Holdin..\n                await BackendUtilities.holdinAPIActions(key, \"payoutaddress\", payoutAddress);\n                this.addAccountLink(this.account.UUID, keyHashLocal, infoResult.data.compound);\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else if (infoResult.data.available === 1 && infoResult.data.active === \"0\") {\n            // Account was linked and then removed. Reactivate.\n            GenerationController.GetGenerationAddressAsync()\n              .then(async payoutAddress => {\n                result = await BackendUtilities.holdinAPIActions(key, \"activate\");\n                if (result.status_code === 200) {\n                  await BackendUtilities.holdinAPIActions(key, \"payoutaddress\", payoutAddress);\n                  this.addAccountLink(this.account.UUID, keyHashLocal);\n                } else {\n                  alert(`Holdin: ${result.status_message}`);\n                }\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else if (infoResult.data.available === 0) {\n            // Add account for the first time.\n            result = await BackendUtilities.holdinAPIActions(key, \"add\");\n            if (result.status_code === 200) {\n              this.addAccountLink(this.account.UUID, keyHashLocal);\n            } else {\n              this.dismissIndicator();\n              alert(`Holdin: ${result.status_message}`);\n            }\n          } else {\n            this.dismissIndicator();\n            alert(\"Holdin: API Error\");\n          }\n        } else {\n          result = await BackendUtilities.holdinAPIActions(key, \"remove\");\n          if (result.status_code === 200) {\n            AccountsController.RemoveAccountLinkAsync(this.account.UUID, \"holdin\")\n              .then(() => {\n                this.isLinkedToHoldin = false;\n                this.requestLinkToHoldin = false;\n                this.dismissIndicator();\n              })\n              .catch(err => {\n                alert(err.message);\n                this.dismissIndicator();\n              });\n          } else {\n            alert(`Holdin: ${result.status_message}`);\n          }\n        }\n      });\n    },\n    addAccountLink(accountUID, keyHash, compound) {\n      AccountsController.AddAccountLinkAsync(accountUID, \"holdin\", keyHash)\n        .then(() => {\n          if (compound) {\n            WitnessController.SetAccountCompoundingAsync(accountUID, compound).then(() => {\n              this.dismissIndicator();\n              this.requestLinkToHoldin = false;\n              this.isLinkedToHoldin = true;\n            });\n          } else {\n            this.dismissIndicator();\n            this.requestLinkToHoldin = false;\n            this.isLinkedToHoldin = true;\n          }\n        })\n        .catch(err => {\n          alert(err.message);\n        });\n    },\n    showConfirmModal() {\n      if (\n        this.account.allBalances.availableIncludingLocked === 0 &&\n        this.account.allBalances.unconfirmedIncludingLocked === 0 &&\n        this.account.allBalances.immatureIncludingLocked === 0\n      ) {\n        this.modal = { title: \"Confirm Delete\", message: \"Are you sure you want to delete the account?\", closeModal: this.closeModal, confirm: this.confirm };\n      } else {\n        this.modal = { title: \"Error\", message: \"Your account needs to be empty before you can delete it\", showButtons: false, closeModal: this.closeModal };\n      }\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    confirm() {\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n      this.modal = null;\n      setTimeout(() => {\n        AccountsController.DeleteAccountAsync(this.account.UUID)\n          .then(() => {\n            this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n          })\n          .catch(err => {\n            this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n            alert(err.message);\n          });\n      }, 1000);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.account-header {\n  width: 100%;\n  height: var(--header-height);\n  line-height: var(--header-height);\n\n  & > div {\n    align-items: center;\n    justify-content: center;\n    height: var(--header-height);\n  }\n}\n\n.left-colum {\n  display: flex;\n  flex-direction: column;\n  flex: 1;\n  white-space: nowrap;\n  overflow: hidden;\n  height: 40px;\n  cursor: pointer;\n  position: relative;\n}\n\n.balance-row {\n  line-height: 20px;\n  font-size: 0.9em;\n\n  & :first-child {\n    margin-right: 10px;\n  }\n}\n\nbutton.small {\n  height: 20px !important;\n  line-height: 20px !important;\n  font-size: 10px !important;\n  padding: 0 10px !important;\n  margin-left: 5px;\n}\n\n.accountname {\n  flex: 1;\n  font-size: 1em;\n  font-weight: 500;\n  line-height: 20px;\n  margin-right: 30px;\n}\n\n.pen {\n  display: none;\n  position: absolute;\n  right: 45px;\n  line-height: 20px;\n}\n\n.trash {\n  display: none;\n  position: absolute;\n  right: 5px;\n  line-height: 18px;\n}\n\n.left-colum:hover .trash {\n  display: block;\n  color: #ff0000;\n}\n\n.left-colum:hover .pen {\n  display: block;\n}\n\n.logo {\n  width: 22px;\n  min-width: 22px;\n  height: 22px;\n  min-height: 22px;\n  background: url(\"../img/logo-black.svg\"), linear-gradient(transparent, transparent);\n  background-size: cover;\n  margin-right: 10px;\n}\n\n.icon-buttons {\n  margin-left: 10px;\n}\n\n.icon-button {\n  display: inline-block;\n  padding: 0 13px;\n  line-height: 40px;\n  height: 40px;\n  font-weight: 500;\n  font-size: 1em;\n  color: var(--primary-color);\n  text-align: center;\n  cursor: pointer;\n\n  &:hover {\n    background-color: #f5f5f5;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/AccountTooltip.vue",
    "content": "<template>\n  <div class=\"tooltip\" @mouseleave=\"hideTooltip\">\n    <div @mouseenter=\"showTooltip\">\n      <slot></slot>\n    </div>\n    <div @mouseenter=\"showTooltip\" class=\"tooltip-container\" v-if=\"show\">\n      <div class=\"tooltip-heading\" v-if=\"type == 'Account'\">{{ $t(\"tooltip.account_balance\") }}</div>\n      <div class=\"tooltip-heading\" v-else>{{ $t(\"tooltip.wallet_balance\") }}</div>\n      <div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.total\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.total }}</div>\n        </div>\n        <div v-if=\"account.type === 'Holding' || account.type === 'Witness' || type === 'Wallet'\" class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.locked\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.locked }}</div>\n        </div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.spendable\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.spendable }}</div>\n        </div>\n        <div class=\"tooltip-row\">\n          <div class=\"tooltip-content\" style=\"flex: 1\">{{ $t(\"tooltip.pending\") }}</div>\n          <div class=\"tooltip-content\">{{ accountObject.pending }}</div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\n\nexport default {\n  name: \"AccountTooltip\",\n  data() {\n    return {\n      show: false,\n      accountObject: {},\n      timeout: undefined\n    };\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"totalBalance\", \"lockedBalance\", \"spendableBalance\", \"pendingBalance\", \"immatureBalance\"])\n  },\n  props: {\n    account: {},\n    type: {\n      type: String\n    }\n  },\n  methods: {\n    showTooltip: function () {\n      clearTimeout(this.timeout);\n      this.show = true;\n      this.getValues();\n    },\n    hideTooltip() {\n      clearTimeout(this.timeout);\n      this.timeout = setTimeout(() => {\n        this.show = false;\n      }, 100);\n    },\n    getValues() {\n      if (this.type === \"Account\") {\n        const locked = this.account.allBalances.totalLocked || 0;\n        const spendable = this.account.allBalances.availableExcludingLocked || 0;\n        const pending = this.account.allBalances.unconfirmedExcludingLocked || 0;\n        const immature = this.account.allBalances.immatureExcludingLocked || 0;\n\n        this.accountObject = {\n          locked: formatMoneyForDisplay(locked),\n          spendable: formatMoneyForDisplay(spendable),\n          pending: formatMoneyForDisplay(pending),\n          immature: formatMoneyForDisplay(immature),\n          total: formatMoneyForDisplay(locked + spendable + pending + immature)\n        };\n      } else {\n        const locked = this.lockedBalance || 0;\n        const spendable = this.spendableBalance || 0;\n        const pending = this.pendingBalance || 0;\n        const immature = this.immatureBalance || 0;\n\n        this.accountObject = {\n          locked: formatMoneyForDisplay(locked),\n          spendable: formatMoneyForDisplay(spendable),\n          pending: formatMoneyForDisplay(pending),\n          immature: formatMoneyForDisplay(immature),\n          total: formatMoneyForDisplay(locked + spendable + pending + immature)\n        };\n      }\n    }\n  },\n  mounted() {\n    this.getValues();\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.tooltip {\n  position: relative;\n  z-index: 99;\n}\n.tooltip-container {\n  position: fixed;\n  z-index: 9990;\n  display: flex;\n  flex-direction: column;\n  margin-top: 6px;\n  padding: 5px;\n  border-radius: 2px;\n  background-color: #fff;\n  width: 200px;\n  box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;\n}\n.tooltip-heading {\n  font-size: 1em;\n  margin-right: 10px;\n  font-weight: bold;\n  margin-bottom: 12px;\n  color: #000;\n  line-height: 22px;\n}\n.tooltip-content {\n  font-size: 0.85em;\n  color: #000;\n  line-height: 22px;\n}\n.tooltip-row {\n  display: flex;\n  flex-direction: row;\n  width: 100%;\n  margin-right: 10px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/ActivityIndicator.vue",
    "content": "<template>\n  <div :class=\"modalClass\" class=\"flex-col\">\n    <div class=\"spinner\"></div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ActivityIndicator\",\n  props: {\n    paddingHidden: {\n      type: Boolean,\n      default: false\n    }\n  },\n  computed: {\n    modalClass() {\n      return this.paddingHidden ? \"modal-no-padding\" : \"modal-mask\";\n    }\n  }\n};\n</script>\n\n<style>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: var(--sidebar-left-width);\n  width: calc(100% - var(--sidebar-left-width));\n  height: 100%;\n  background-color: rgba(255, 255, 255, 0.8);\n  margin-top: 0;\n  align-items: center;\n  justify-content: center;\n  z-index: 9998;\n}\n\n.modal-no-padding {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100vw;\n  height: 100%;\n  background-color: rgba(255, 255, 255, 0.8);\n  margin-top: 0;\n  align-items: center;\n  justify-content: center;\n  z-index: 9998;\n}\n\n.spinner {\n  position: relative;\n  display: inline-block;\n  width: 60px;\n  height: 60px;\n  border-style: solid;\n  border-radius: 100%;\n  border-width: 6px;\n  border-left-color: transparent;\n  color: var(--primary-color);\n  opacity: 0;\n\n  animation-name: rotate, fadeIn;\n  animation-duration: 800ms, 600ms;\n  animation-timing-function: linear, ease;\n  animation-iteration-count: infinite, 1;\n  animation-delay: 400ms;\n  animation-fill-mode: forwards;\n}\n\n@keyframes rotate {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes fadeIn {\n  0% {\n    opacity: 0;\n  }\n  100% {\n    opacity: 1;\n  }\n}\n\n@media (max-width: 960px) {\n  .modal-mask {\n    left: var(--sidebar-left-width-small);\n    width: calc(100% - var(--sidebar-left-width-small));\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/AppLoader.vue",
    "content": "<template>\n  <div class=\"app-loader flex-col\" v-if=\"showLoader\">\n    <div class=\"logo-outer flex-col\">\n      <div class=\"logo-inner\"></div>\n    </div>\n    <div class=\"info\">\n      <p v-show=\"isShuttingDown\">\n        {{ $t(\"loader.shutdown\") }}\n      </p>\n      <div v-show=\"isSynchronizing\">\n        <div class=\"sync-desc\">{{ $t(\"loader.synchronizing\") }}</div>\n        <progress ref=\"progress\" max=\"130\" value=\"0\"></progress>\n      </div>\n    </div>\n    <div class=\"version-container\">\n      <span>Munt LITE</span>\n      <span class=\"divider\">|</span>\n      <span>Unity: {{ unityVersion }}</span>\n      <span class=\"divider\">|</span>\n      <span>Wallet: {{ walletVersion }}</span>\n      <span class=\"divider\">|</span>\n      <span>Electron: {{ electronVersion }}</span>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport AppStatus from \"../AppStatus\";\nimport { LibraryController } from \"../unity/Controllers\";\n\nlet progressTimeout = null;\n\n// How many times we have polled for progress while the app is still in a loading state and is not yet synchronising\nlet preProgressCount = 0;\n\nexport default {\n  name: \"AppLoader\",\n  data() {\n    return {\n      electronVersion: process.versions.electron,\n      progress: 0\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"splashReady\", \"syncDone\", \"status\", \"unityVersion\", \"walletVersion\"]),\n    showLoader() {\n      return this.splashReady === false || (this.status !== AppStatus.setup && this.syncDone === false) || this.status === AppStatus.shutdown;\n    },\n    isShuttingDown() {\n      return this.status === AppStatus.shutdown;\n    },\n    isSynchronizing() {\n      return this.status === AppStatus.synchronize;\n    }\n  },\n  watch: {\n    status() {\n      this.onStatusChanged();\n    },\n    progress() {\n      if (this.$refs.progress) {\n        this.$refs.progress.value = parseInt(this.progress * 100);\n      }\n    }\n  },\n  created() {\n    this.onStatusChanged();\n  },\n  mounted() {\n    setTimeout(() => {\n      this.$store.dispatch(\"app/SET_SPLASH_READY\");\n    }, 2500);\n  },\n  methods: {\n    onStatusChanged() {\n      let routeName;\n      switch (this.status) {\n        case AppStatus.setup:\n          routeName = \"setup\";\n          break;\n        case AppStatus.synchronize:\n          routeName = \"account\";\n          this.updateProgress();\n          break;\n        case AppStatus.ready:\n          routeName = \"account\";\n          break;\n      }\n      if (routeName === undefined || this.$route.name === routeName) return;\n      this.$router.push({ name: routeName });\n    },\n    updateProgress() {\n      clearTimeout(progressTimeout);\n      if (this.status !== AppStatus.synchronize) return;\n\n      const progress = LibraryController.GetUnifiedProgress();\n      console.log(`progress: ${progress}`);\n\n      // App goes through two basic loading processes:\n      // a. Setting up wallet, loading transactions/accounts, starting up of internal services network threads etc.\n      // b. Synchronising with network\n      // While we are in 'a' its not possible to determine progress and we get only a response of 200 from 'GetUnifiedProgress' to indicate this\n      // Once we are in 'b' we get a fraction of between 0..1 expressing the percentage we are in terms of complete.\n      //\n      // To deal with this we do the following:\n      // 1. We make our total progress target \"130\" instead of \"100\"\n      // 2. The first 30 of that 130 we proportion to \"a\" the second 100 we proportion to \"b\"\n      // 3. While in a we slowly increment over time from 0..30 to show the user progress is taking place\n      // 4. While in b we assume we are already starting from 30 and just add the return value of 'GetUnifiedProgress' on top of that\n      //\n      // Room for improvement:\n      // 1. Instead of starting b from 30 we should determine where 'a' left off (e.g. maybe it was only at 10) and start from there, and drop the progress total to match.\n      // 2. Improve the API call to return an object that properly specifies this instead of the magic \"200\" number\n      // 3. Fine tune what percentage of the sync we proportion to \"a\"\n      // 4. Use different proportions if we are performing an initial sync on a new wallet vs catching up on a previously synced wallet\n      // 'b' takes substantially longer on 'b' while if I open/close a recently synced wallet most time will be spent in 'a'\n\n      if (!this.syncDone) {\n        if (progress > 190) {\n          this.progress = (0.3 / 20) * preProgressCount;\n          if (preProgressCount < 20) {\n            preProgressCount++;\n          }\n          progressTimeout = setTimeout(this.updateProgress, 1000);\n        } else {\n          this.progress = 0.3 + progress;\n          progressTimeout = setTimeout(this.updateProgress, 2500);\n        }\n      } else {\n        // we always wait for syncDone to be true before continuing\n        this.progress = 1.3;\n        this.$store.dispatch(\"app/SET_STATUS\", AppStatus.ready);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-loader {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  background-color: #fff;\n  z-index: 9999;\n}\n\n.logo-outer {\n  margin: 0 0 50px 0;\n  background: transparent;\n  width: 128px;\n  height: 128px;\n  border-radius: 50%;\n  align-items: center;\n  justify-content: center;\n  text-align: center;\n}\n\n.logo-inner {\n  width: 128px;\n  height: 128px;\n  background: url(\"../img/logo-black.svg\");\n  background-size: cover;\n}\n\n.version-container {\n  font-size: 0.8em;\n  text-transform: uppercase;\n  color: #999;\n\n  & .divider {\n    margin: 0 8px;\n  }\n}\n\n.info {\n  margin: 0 0 50px 0;\n}\n\n.sync-desc {\n  margin: 0 0 10px 0;\n}\n\nprogress[value] {\n  appearance: none;\n  width: 100%;\n  height: 5px;\n}\n\nprogress[value]::-webkit-progress-bar {\n  background-color: #efefef;\n}\n\nprogress[value]::-webkit-progress-value {\n  background-color: var(--primary-color);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/ClipboardField.vue",
    "content": "<template>\n  <div class=\"clipboard-field\">\n    <span class=\"field\" @click=\"copyToClipboard\">\n      <span v-if=\"confirmCopy\">\n        {{ $t(confirmation) }}\n      </span>\n      <span v-else>\n        {{ value }}\n        <fa-icon :icon=\"['fal', 'copy']\" class=\"copy\" />\n      </span>\n    </span>\n  </div>\n</template>\n\n<script>\nimport { clipboard } from \"electron\";\n\nexport default {\n  name: \"ClipboardField\",\n  props: {\n    value: {\n      type: String\n    },\n    confirmation: {\n      type: String,\n      default: \"clipboard_field.copied_to_clipboard\"\n    }\n  },\n  data() {\n    return {\n      confirmCopy: false\n    };\n  },\n  methods: {\n    copyToClipboard() {\n      clipboard.writeText(this.value);\n      if (this.confirmation) {\n        this.confirmCopy = true;\n        setTimeout(() => {\n          this.confirmCopy = false;\n        }, 1500);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.clipboard-field {\n  text-align: center;\n  padding: 10px 0;\n}\n\n.field {\n  padding: 10px;\n  cursor: pointer;\n}\n\n.clipboard-field:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n}\n\n.copy {\n  margin-left: 10px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/ConfirmDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" @click=\"closeModal\" v-if=\"showModal\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span :class=\"type\">{{ title }}</span>\n        <div class=\"close\" @click=\"closeModal\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div class=\"content\">\n        {{ message }}\n      </div>\n      <app-button-section class=\"buttons\" v-if=\"showButtons\">\n        <template v-slot:right>\n          <button @click=\"closeModal\">{{ $t(\"buttons.cancel\") }}</button>\n          <button @click=\"confirm\">{{ $t(\"buttons.confirm\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ConfirmDialog\",\n  props: {\n    value: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    showModal() {\n      return this.value !== null;\n    },\n    title() {\n      return this.value.title || \"Are you sure?\";\n    },\n    showButtons() {\n      return typeof this.value.showButtons === \"boolean\" ? this.value.showButtons : true;\n    },\n    type() {\n      return this.value.type;\n    },\n    message() {\n      return this.value.message;\n    },\n    component() {\n      return this.value.component;\n    },\n    componentProps() {\n      return this.value.componentProps;\n    }\n  },\n  methods: {\n    closeModal() {\n      this.value.closeModal();\n    },\n    confirm() {\n      this.value.confirm();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content {\n  margin: 30px 0;\n  padding: 0 30px;\n  height: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n\n.error {\n  color: var(--error-color, #dd3333);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/CurrencyInput.vue",
    "content": "<template>\n  <input type=\"text\" v-model=\"displayValue\" @focus=\"isFocussed = true\" @blur=\"isFocussed = false\" @keydown=\"validateInput\" @paste=\"preventPaste\" />\n</template>\n\n<script>\nexport default {\n  name: \"CurrencyInput\",\n  props: {\n    value: {\n      type: [String, Number],\n      default: \"\"\n    },\n    currency: {\n      type: String,\n      default: \"\"\n    }\n  },\n  data() {\n    return {\n      isFocussed: false,\n      innerValue: this.value\n    };\n  },\n  watch: {\n    innerValue() {\n      this.$emit(\"input\", this.innerValue);\n    }\n  },\n  computed: {\n    displayValue: {\n      get: function () {\n        if (this.innerValue === null || this.innerValue === undefined || this.innerValue.toString().trim() === \"\") return null;\n\n        if (this.isFocussed) {\n          return this.innerValue;\n        } else {\n          return `${this.currency} ${this.innerValue.toString().replace(/(\\d)(?=(\\d{3})+(?:\\.\\d+)?$)/g, \"$1 \")}`.trim();\n        }\n      },\n      set: function (modifiedValue) {\n        let newValue = modifiedValue.replace(/[^0-9.]/g, \"\").replace(/(\\..*)\\./g, \"$1\");\n\n        let periodIdx = newValue.indexOf(\".\");\n        if (periodIdx !== -1 && newValue.length - periodIdx > 3) {\n          newValue = `${newValue.slice(0, periodIdx)}${newValue.slice(periodIdx + 1, periodIdx + 2)}.${newValue.slice(periodIdx + 2)}`;\n        }\n\n        this.innerValue = newValue;\n      }\n    }\n  },\n  methods: {\n    preventPaste(e) {\n      e.preventDefault();\n    },\n    validateInput(e) {\n      if (\n        (e.keyCode >= 48 && e.keyCode <= 58 && e.shiftKey == false) || // 0-9\n        (e.keyCode >= 96 && e.keyCode <= 105) || // 0-9 numeric pad\n        ((e.keyCode == 190 || e.keyCode === 110) && this.displayValue.toString().indexOf(\".\") === -1) || // only allow single .\n        e.keyCode === 8 || // backspace\n        e.keyCode === 9 || // tab\n        e.keyCode === 13 || // enter\n        (e.keyCode >= 33 && e.keyCode <= 40) || // ...\n        e.keyCode === 45 || // insert\n        e.keyCode === 46 // delete\n      )\n        return;\n\n      e.preventDefault();\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/components/ModalDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" @click=\"closeModal\" v-if=\"showModal\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span :class=\"type\">{{ title }}</span>\n        <div class=\"close\" @click=\"closeModal\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div :class=\"contentClass\">\n        {{ message }}\n        <component v-if=\"component\" :is=\"component\" v-bind=\"componentProps\"></component>\n      </div>\n      <app-button-section class=\"buttons\" v-if=\"showButtons\">\n        <template v-slot:right>\n          <button @click=\"closeModal\">{{ $t(\"buttons.ok\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"../EventBus\";\n\nexport default {\n  name: \"ModalDialog\",\n  props: {\n    value: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    showModal() {\n      return this.value !== null;\n    },\n    title() {\n      return this.value.title || \"title\";\n    },\n    contentClass() {\n      return `content ${this.value.noMargin ? \"no-margin\" : \"\"}`;\n    },\n    showButtons() {\n      return typeof this.value.showButtons === \"boolean\" ? this.value.showButtons : true;\n    },\n    type() {\n      return this.value.type;\n    },\n    message() {\n      return this.value.message;\n    },\n    component() {\n      return this.value.component;\n    },\n    componentProps() {\n      return this.value.componentProps;\n    }\n  },\n  methods: {\n    closeModal() {\n      EventBus.$emit(\"close-dialog\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content:not(.no-margin) {\n  margin: 30px 0;\n  padding: 0 30px;\n  overflow-y: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n\n.error {\n  color: var(--error-color, #dd3333);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/PhraseInput.vue",
    "content": "<template>\n  <div class=\"phrase-input-wrapper\">\n    <input\n      v-for=\"(word, index) in words\"\n      :key=\"index\"\n      type=\"text\"\n      class=\"word-input\"\n      ref=\"input\"\n      @input=\"onInput(index, $event)\"\n      @focus=\"onFocus(index)\"\n      @blur=\"onBlur(index)\"\n      @keydown=\"validatePraseOnEnter\"\n      v-model=\"inputs[index]\"\n      :class=\"getCssClass(index)\"\n      :disabled=\"isInputDisabled(index)\"\n    />\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"PhraseInput\",\n  props: {\n    validate: {\n      type: [String, Object],\n      default: \"\"\n    },\n    isPhraseInvalid: {\n      type: Boolean,\n      default: false\n    },\n    autofocus: {\n      type: Boolean,\n      default: true\n    }\n  },\n  data() {\n    return {\n      inputs: []\n    };\n  },\n  mounted() {\n    if (this.autofocus) {\n      this.$nextTick(() => {\n        this.$refs.input[0].focus();\n      });\n    }\n  },\n  computed: {\n    isRecovery() {\n      return typeof this.validate !== \"string\";\n    },\n    words() {\n      return this.isRecovery ? Array(this.validate.length).join(\".\").split(\".\") : this.validate.split(\" \");\n    }\n  },\n  methods: {\n    clear() {\n      this.inputs = [];\n      this.$nextTick(() => {\n        this.$refs.input[0].focus();\n      });\n    },\n    onFocus(index) {\n      // force sequential input. make sure the first input is focused which doesn't have a valid word\n      for (var i = 0; i < index; i++) {\n        if (this.isMatch(i) === false) {\n          // this input doesn't contain a valid word, so put the focus on that word\n          this.$refs.input[i].focus();\n          return;\n        }\n      }\n\n      if (this.isMatch(index)) {\n        // focus set on input by the user, so let's clear the input\n        this.inputs[index] = \"\";\n        this.$refs.input[index].value = \"\";\n        this.$emit(\"possible-phrase\", null);\n      }\n      if (!this.isRecovery) console.log(this.words[index]);\n    },\n    onBlur(index) {\n      if (this.isMatch(index) === false) {\n        this.inputs[index] = \"\";\n        this.$refs.input[index].value = \"\";\n      }\n    },\n    onInput(index) {\n      if (this.inputs.length === 12 && this.isMatch(index)) {\n        this.$emit(\"possible-phrase\", this.inputs.join(\" \"));\n        return;\n      }\n      this.$emit(\"possible-phrase\", null);\n\n      if (this.isExactMatch(index)) {\n        let nextIndex;\n        for (nextIndex = index + 1; nextIndex <= this.inputs.length; nextIndex++) {\n          if (this.inputs[nextIndex] === undefined) break;\n          if (this.isMatch(nextIndex) === false) break;\n        }\n\n        let next = this.$refs.input[nextIndex];\n        if (next) next.focus();\n      }\n    },\n    getCssClass(index) {\n      if (this.isPhraseInvalid) return \"\";\n      if (this.isInvalid(index)) return \"error\";\n      if (this.isMatch(index)) return \"success\";\n      return \"\";\n    },\n    isInputDisabled(index) {\n      if (this.isRecovery) return false;\n      if (index === this.words.length - 1) return false;\n      return this.isExactMatch(index);\n    },\n    isExactMatch(index) {\n      let inputWord = this.inputs[index];\n      if (inputWord === undefined || inputWord.length === 0) return false;\n\n      if (this.isRecovery) {\n        let validWords = this.getValidWords(index);\n        return validWords.length === 1 && inputWord === validWords[0];\n      } else {\n        return inputWord === this.words[index];\n      }\n    },\n    isMatch(index) {\n      if (this.isRecovery) {\n        let inputWord = this.inputs[index];\n        if (inputWord === undefined || inputWord.length === 0) return false;\n        return this.getValidWords(index).indexOf(inputWord) !== -1;\n      } else return this.isExactMatch(index);\n    },\n    isInvalid(index) {\n      let inputWord = this.inputs[index];\n      if (inputWord === undefined || inputWord.length === 0) return false;\n\n      if (this.isRecovery) {\n        return this.getValidWords(index).length === 0;\n      } else {\n        let word = this.words[index];\n        return inputWord.length > word.length ? true : word.indexOf(inputWord) !== 0;\n      }\n    },\n    getValidWords(index) {\n      return this.validate.words.filter(x => x.indexOf(this.inputs[index]) === 0);\n    },\n    validatePraseOnEnter(event) {\n      if (event.keyCode === 13) this.$emit(\"enter\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.phrase-input-wrapper {\n  width: calc(100% + 10px);\n  margin: -5px 0 0 -5px;\n}\n\n.word-input {\n  width: calc(25% - 10px);\n  margin: 5px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/SelectList.vue",
    "content": "<template>\n  <div class=\"select-list-wrapper\" :tabindex=\"tabindex\" @blur=\"open = false\">\n    <div class=\"selected\" :class=\"{ open: open }\" @click=\"open = !open\">\n      {{ typeof selected === \"object\" ? selected.label : selected }}\n    </div>\n    <div class=\"arrow\" @click=\"open = !open\">\n      <fa-icon :icon=\"['fal', 'chevron-down']\" />\n    </div>\n    <div class=\"items\" :class=\"{ selectHide: !open }\">\n      <div\n        v-for=\"(option, i) of options\"\n        :key=\"i\"\n        @click=\"\n          selected = option;\n          open = false;\n          $emit('input', option);\n        \"\n      >\n        {{ typeof option === \"object\" ? option.label : option }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"SelectList\",\n  props: {\n    options: {\n      type: Array,\n      required: true\n    },\n    default: {\n      type: [String, Object],\n      required: false,\n      default: null\n    },\n    tabindex: {\n      type: Number,\n      required: false,\n      default: 0\n    }\n  },\n  data() {\n    return {\n      selected: this.default ? this.default : this.options.length > 0 ? this.options[0] : null,\n      open: false\n    };\n  },\n  mounted() {\n    this.$emit(\"input\", this.selected);\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.select-list-wrapper {\n  position: relative;\n  width: 100%;\n  text-align: left;\n  outline: none;\n  line-height: 40px;\n  font-style: normal;\n  font-weight: 500;\n  font-size: 14px;\n  color: #000;\n  padding-bottom: 10px;\n}\n\n.select-list-wrapper .selected {\n  padding-left: 10px;\n  cursor: pointer;\n  user-select: none;\n  background-color: #fff;\n  border: 1px solid #ccc;\n}\n\n.select-list-wrapper .selected.open {\n  border: 1px solid #ccc;\n}\n\n.arrow {\n  position: absolute;\n  top: 0;\n  right: 10px;\n  font-size: 12px;\n  line-height: 40px;\n  cursor: pointer;\n}\n\n.select-list-wrapper .items {\n  overflow: hidden;\n  border-right: 1px solid #ccc;\n  border-left: 1px solid #ccc;\n  border-bottom: 1px solid #ccc;\n  position: absolute;\n  background-color: #fff;\n  left: 0;\n  right: 0;\n  z-index: 1;\n}\n\n.select-list-wrapper .items div {\n  padding-left: 1em;\n  cursor: pointer;\n  user-select: none;\n}\n\n.select-list-wrapper .items div:hover {\n  color: #fff;\n  background-color: var(--primary-color);\n}\n\n.selectHide {\n  display: none;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/TransactionDetailsDialog.vue",
    "content": "<template>\n  <div class=\"transaction-details-dialog\">\n    <div class=\"tx-date\">{{ computedTimestamp }}</div>\n    <div class=\"tx-amount\">{{ computedAmount }}</div>\n    <div class=\"tx-to\">\n      <fa-icon :icon=\"['far', 'long-arrow-down']\" />\n    </div>\n    <div class=\"tx-address\">\n      <clipboard-field :value=\"mutation.recipient_addresses\" />\n    </div>\n    <div class=\"tx-id\">TX ID:<clipboard-field :value=\"mutation.txHash\" /></div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"../EventBus\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport ClipboardField from \"./ClipboardField.vue\";\n\nexport default {\n  components: { ClipboardField },\n  name: \"TransactionDetailsDialog\",\n  props: {\n    mutation: {\n      type: Object,\n      default: null\n    }\n  },\n  computed: {\n    computedTimestamp() {\n      let timestamp = new Date(this.mutation.timestamp * 1000);\n      return `${this.formatDate(timestamp)} ${this.formatTime(timestamp)}`;\n    },\n    computedAmount() {\n      return `${formatMoneyForDisplay(this.mutation.change)} ` + this.$t(\"common.ticker_symbol\");\n    }\n  },\n  methods: {\n    close() {\n      EventBus.$emit(\"close-dialog\");\n    },\n    formatDate(d) {\n      let date = new Date(d);\n      let options = {\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\"\n      };\n      if (date.getFullYear() === new Date().getFullYear()) delete options.year;\n      return date.toLocaleString(this.$i18n.locale, options);\n    },\n    formatTime(timestamp) {\n      let date = new Date(timestamp * 1000);\n      return `${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transaction-details-dialog {\n  text-align: center;\n\n  & > h4 {\n    margin: 25px 0 0 0;\n  }\n}\n.tx-date {\n  margin: 0 0 10px 0;\n  font-size: 0.9em;\n}\n.tx-amount {\n  font-size: 1.6em;\n  font-weight: 600;\n}\n.tx-address {\n  font-weight: 500;\n}\n.tx-to {\n  margin: 20px 0 10px 0;\n  font-size: 1.6em;\n}\n.tx-id {\n  margin: 20px 0 0 0;\n  padding: 10px;\n  font-size: 0.75em;\n  line-height: 1em;\n  text-transform: uppercase;\n  & .clipboard-field {\n    display: inline-block;\n    margin: 0 0 0 5px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/UnlockWalletDialog.vue",
    "content": "<template>\n  <div class=\"modal-mask flex-col\" v-if=\"visible\" @click=\"onCancel\">\n    <div class=\"modal-container\" @click.stop>\n      <div class=\"header\">\n        <span>{{ $t(this.options.title) }}</span>\n        <div class=\"close\" @click=\"onCancel\">\n          <span class=\"icon\">\n            <fa-icon :icon=\"['fal', 'times']\" />\n          </span>\n        </div>\n      </div>\n      <div class=\"content\">\n        <app-form-field title=\"unlock_wallet_dialog.unlock_for\" v-if=\"options.timeout == null\">\n          <select-list :options=\"timeoutOptions\" :default=\"timeoutOptions[0]\" v-model=\"timeout\" />\n        </app-form-field>\n        <content-wrapper :content=\"options.message\">\n          <app-form-field title=\"common.password\">\n            <input ref=\"pwd\" v-model=\"password\" type=\"password\" @keydown=\"resetStatus\" @keydown.enter=\"tryUnlock\" :class=\"passwordStatus\" />\n          </app-form-field>\n        </content-wrapper>\n      </div>\n      <app-button-section class=\"buttons\">\n        <template v-slot:right>\n          <button @click=\"tryUnlock\">{{ $t(\"buttons.unlock\") }}</button>\n        </template>\n      </app-button-section>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { LibraryController } from \"../unity/Controllers\";\nimport EventBus from \"../EventBus\";\n\nexport default {\n  name: \"UnlockWalletDialog\",\n  data() {\n    return {\n      visible: false,\n      isUnlocked: null,\n      timeout: 1,\n      options: {},\n      password: \"\",\n      error: false\n    };\n  },\n  mounted() {\n    EventBus.$on(\"unlock-wallet\", this.unlockWallet);\n    EventBus.$on(\"lock-wallet\", this.lockWallet);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"unlock-wallet\", this.unlockWallet);\n    EventBus.$off(\"lock-wallet\", this.lockWallet);\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"unlocked\"]),\n    timeoutOptions() {\n      return [1, 5, 10].map(i => {\n        return { value: 60 * i, label: this.$tc(\"unlock_wallet_dialog.minute\", i) };\n      });\n    },\n    passwordStatus() {\n      return this.error ? \"error\" : \"\";\n    }\n  },\n  methods: {\n    async lockWallet() {\n      await LibraryController.LockWalletAsync();\n    },\n    async unlockWallet(options) {\n      // note:\n      // it can happen if unlocked is true now, but is false right after the callback\n      // find a solution for this situation...\n      // maybe LibraryController.GetWalletLockStatus can be used to determine if wallet is still unlocked for a while?\n      if (this.unlocked) {\n        if (typeof options.callback === \"function\") {\n          return options.callback();\n        }\n      }\n\n      this.options = {\n        title: \"unlock_wallet_dialog.title\",\n        message: null,\n        timeout: options && options.callback ? 10 : null,\n        ...options\n      };\n\n      this.visible = true;\n      this.$nextTick(() => {\n        this.$refs.pwd.focus();\n      });\n    },\n    onCancel() {\n      this.password = null;\n      this.visible = false;\n      this.error = false;\n    },\n    async resetStatus() {\n      this.error = false;\n    },\n    async tryUnlock() {\n      var result = await LibraryController.UnlockWalletAsync(this.password, this.options.timeout || this.timeout.value);\n      if (result) {\n        this.password = null;\n        this.visible = false;\n\n        if (this.options.callback) {\n          // call and await the callback function\n          await this.options.callback();\n\n          // lock the wallet after callback finishes\n          LibraryController.LockWallet();\n        }\n      } else {\n        this.error = true;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.modal-mask {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  margin-top: 0;\n  margin-left: 0;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n  z-index: 9998;\n}\n\n.modal-container {\n  max-width: 800px;\n  max-height: 700px;\n  width: calc(100% - 40px);\n  height: auto;\n  margin: 0px auto;\n  background-color: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  transition: all 0.3s ease;\n}\n\n.header {\n  height: 56px;\n  line-height: 56px;\n  padding: 0 30px;\n  border-bottom: 1px solid var(--main-border-color);\n  font-weight: 600;\n  font-size: 1.05rem;\n\n  & .close {\n    float: right;\n    margin: 0 -10px 0 0;\n  }\n\n  & .icon {\n    line-height: 42px;\n    font-size: 1.2em;\n    font-weight: 300;\n    padding: 0 10px;\n    cursor: pointer;\n  }\n\n  & .icon:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\n.content {\n  margin: 30px 0;\n  padding: 0 30px;\n  overflow-y: auto;\n}\n\n.buttons {\n  height: 64px;\n  padding: 0 12px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/WalletPasswordDialog.vue",
    "content": "<template>\n  <div class=\"wallet-password-dialog\">\n    <app-form-field title=\"common.password\">\n      <input ref=\"password\" type=\"password\" v-model=\"password\" @keydown=\"validatePasswordOnEnter\" :class=\"computedStatus\" />\n    </app-form-field>\n    <app-button-section class=\"buttons\">\n      <button slot=\"right\" @click=\"validatePassword\" :disabled=\"isButtonDisabled\">\n        {{ $t(\"buttons.unlock\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { LibraryController } from \"../unity/Controllers\";\nimport EventBus from \"../EventBus\";\n\nexport default {\n  name: \"WalletPasswordDialog\",\n  props: {\n    value: {\n      type: String,\n      default: null\n    }\n  },\n  data() {\n    return {\n      password: \"\",\n      isPasswordInvalid: false\n    };\n  },\n  computed: {\n    computedStatus() {\n      return this.isPasswordInvalid ? \"error\" : \"\";\n    },\n    isButtonDisabled() {\n      return this.password.trim().length === 0;\n    }\n  },\n  mounted() {\n    this.$refs.password.focus();\n  },\n  methods: {\n    validatePasswordOnEnter() {\n      this.isPasswordInvalid = false;\n      if (event.keyCode === 13) this.validatePassword();\n    },\n    validatePassword() {\n      if (LibraryController.UnlockWallet(this.password, 120)) {\n        LibraryController.LockWallet();\n        this.$store.dispatch(\"wallet/SET_WALLET_PASSWORD\", this.password);\n        EventBus.$emit(\"close-dialog\");\n      } else {\n        this.isPasswordInvalid = true;\n      }\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/components/index.js",
    "content": "import Vue from \"vue\";\n\nimport CurrencyInput from \"./CurrencyInput\";\nimport ClipboardField from \"./ClipboardField\";\nimport MainHeader from \"./layout/MainHeader\";\nimport AppButtonSection from \"./layout/AppButtonSection\";\nimport AppFormField from \"./layout/AppFormField\";\nimport AppSection from \"./layout/AppSection\";\nimport SelectList from \"./SelectList\";\nimport FooterButton from \"./layout/FooterButton\";\nimport ContentWrapper from \"./layout/ContentWrapper\";\nimport AccountHeader from \"./AccountHeader\";\n\nVue.component(ClipboardField.name, ClipboardField);\nVue.component(CurrencyInput.name, CurrencyInput);\nVue.component(MainHeader.name, MainHeader);\nVue.component(AppButtonSection.name, AppButtonSection);\nVue.component(AppFormField.name, AppFormField);\nVue.component(AppSection.name, AppSection);\nVue.component(SelectList.name, SelectList);\nVue.component(FooterButton.name, FooterButton);\nVue.component(ContentWrapper.name, ContentWrapper);\nVue.component(AccountHeader.name, AccountHeader);\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/AppButtonSection.vue",
    "content": "<template>\n  <div class=\"app-button-section flex-row\">\n    <div class=\"left\">\n      <slot name=\"left\" />\n    </div>\n    <div class=\"middle\">\n      <slot name=\"middle\" />\n    </div>\n    <div class=\"right\">\n      <slot />\n      <slot name=\"right\" />\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"AppButtonSection\"\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-button-section {\n  width: 100%;\n\n  & .left {\n    float: left;\n\n    & > button:not(:last-child) {\n      margin: 0 20px 0 0;\n    }\n\n    & > button:not([disabled]) {\n      background-color: #fff;\n      border: 1px solid var(--primary-color);\n      color: var(--primary-color);\n    }\n  }\n\n  & .middle {\n    flex: 1;\n  }\n\n  & .right {\n    text-align: right;\n\n    & > button:not(:first-child) {\n      margin: 0 0 0 20px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/AppFormField.vue",
    "content": "<template>\n  <app-section class=\"app-form-field\">\n    <h2 v-if=\"hasTitle\">{{ $t(title) }}</h2>\n    <slot></slot>\n  </app-section>\n</template>\n\n<script>\nimport AppSection from \"./AppSection\";\n\nexport default {\n  name: \"AppFormField\",\n  props: {\n    title: {\n      type: String,\n      default: \"\"\n    }\n  },\n  components: {\n    AppSection\n  },\n  computed: {\n    hasTitle() {\n      return this.title !== null && this.title.trim().length > 0;\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/AppSection.vue",
    "content": "<template>\n  <div class=\"section\">\n    <slot />\n  </div>\n</template>\n\n<style lang=\"less\" scoped>\n.section {\n  margin: 0 0 20px 0;\n}\n</style>\n\n<script>\nexport default {\n  name: \"AppSection\"\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/ContentWrapper.vue",
    "content": "<template>\n  <div>\n    <h2 v-if=\"heading\" :class=\"headingStyle\">{{ $t(heading) }}</h2>\n    <p v-if=\"content\">\n      {{ $t(content) }}\n    </p>\n    <slot></slot>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"ContentWrapper\",\n  props: {\n    heading: {\n      type: String,\n      default: null\n    },\n    headingStyle: {\n      type: String,\n      default: null,\n      validator: value => {\n        return [\"warning\"].includes(value);\n      }\n    },\n    content: {\n      type: String,\n      default: null\n    }\n  }\n};\n</script>\n\n<style scoped>\np {\n  text-align: inherit;\n  white-space: pre-line; /* Allow \\n to be treated as newline */\n}\n\nh2.warning {\n  color: var(--error-color);\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/FooterButton.vue",
    "content": "<template>\n  <div :class=\"getClass(isActive)\" @click=\"$emit('click', routeName)\">\n    <fa-icon class=\"left\" v-if=\"showIcon('left')\" :icon=\"icon\" />\n    {{ $t(this.title) }}\n    <slot></slot>\n    <fa-icon class=\"right\" v-if=\"showIcon('right')\" :icon=\"icon\" />\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"FooterButton\",\n  props: {\n    routeName: {\n      type: String\n    },\n    title: {\n      type: String,\n      default: null\n    },\n    params: {\n      type: Object,\n      value: () => {}\n    },\n    icon: {\n      type: Array,\n      value: () => []\n    },\n    iconPosition: {\n      type: String,\n      default: \"left\",\n      validator: value => {\n        return [\"left\", \"right\"].includes(value);\n      }\n    }\n  },\n  computed: {\n    isActive() {\n      return this.$route.name === this.routeName;\n    }\n  },\n  methods: {\n    getClass(isActive) {\n      return `footer-button ${isActive ? \"active\" : \"\"}`;\n    },\n    showIcon(position) {\n      if (!this.icon) return false;\n      return this.iconPosition === position;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.footer-button {\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  flex-wrap: nowrap;\n  align-items: center;\n  padding: 0 20px;\n  font-weight: 600;\n  font-size: 0.85em;\n  text-transform: uppercase;\n  letter-spacing: 0.03em;\n  line-height: calc(var(--footer-height) - 20px);\n  max-width: 160px;\n  height: 45px;\n  white-space: nowrap;\n  margin-top: 5px;\n  cursor: pointer;\n\n  & svg {\n    font-size: 14px;\n  }\n\n  & svg.left {\n    margin-right: 5px;\n  }\n\n  & svg.right {\n    margin-left: 5px;\n  }\n\n  &.active {\n    color: var(--primary-color);\n    cursor: default;\n  }\n\n  &:not(.active):hover {\n    background: var(--hover-color);\n    color: var(--primary-color);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/components/layout/MainHeader.vue",
    "content": "<template>\n  <div class=\"main-header\" :class=\"mainHeaderClass\">\n    <div class=\"title ellipsis\">\n      {{ $t(title) }}\n    </div>\n    <div class=\"subtitle ellipsis\" v-if=\"hasSubtitle\">\n      {{ $t(subtitle) }}\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"MainHeader\",\n  props: {\n    title: {\n      type: String,\n      default: null\n    },\n    subtitle: {\n      type: String,\n      default: null\n    }\n  },\n  computed: {\n    hasSubtitle() {\n      return this.subtitle && this.subtitle.trim().length > 0;\n    },\n    mainHeaderClass() {\n      return this.hasSubtitle ? \"\" : \"no-subtitle\";\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.main-header {\n  height: var(--header-height);\n  line-height: 20px;\n  padding: calc((var(--header-height) - 40px) / 2) 0;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n\n  &.no-subtitle {\n    padding: calc((var(--header-height) - 20px) / 2) 0;\n  }\n}\n\n.title {\n  font-size: 1.1em;\n  font-weight: 500;\n  line-height: 20px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/css/app.less",
    "content": "@import \"./variables.less\";\n@import \"./fonts.less\";\n@import \"./css-reset.css\";\n@import \"./app_styles.less\";"
  },
  {
    "path": "src/frontend/lite/src/css/app_styles.less",
    "content": "h1 {\n  font-weight: 600;\n  font-size: 3.2em;\n  line-height: 1.2em;\n  margin: 0 0 60px 0;\n  letter-spacing: -0.02em;\n}\n\nh2 {\n  font-weight: 600;\n  font-size: 1.05em;\n  margin: 0 0 15px 0;\n}\n\nh3 {\n  font-weight: 500;\n  font-size: 0.85em;\n  line-height: 1.2em;\n  margin: 0 0 10px 0;\n  text-transform: uppercase;\n}\n\nh4 {\n  font-weight: 500;\n  font-size: 0.85em;\n  line-height: 1.2em;\n  margin: 0 0 20px 0;\n  text-transform: uppercase;\n}\n\nh5 {\n  font-weight: 600;\n  font-size: .85em;\n  line-height: 1.2em;\n  margin: 0 0 10px 0;\n  text-transform: uppercase;\n}\n\nb,\nstrong {\n  font-weight: 600;\n}\n\np {\n  margin: 0 0 20px 0;\n  font-size: 1em;\n  line-height: 1.45em;\n  color: #222;\n}\n\ndel {\n  text-decoration: line-through;\n}\n\na,\na:active,\na:visited {\n  text-decoration: none;\n  color: #000;\n}\n\na:hover {\n  color: #000;\n}\n\nimg,\na {\n  user-select: none;\n  -webkit-user-drag: none;\n}\n\n.select-all {\n  user-select: all;\n}\n\n/* input / select / range */\n::placeholder {\n  color: var(--primary-color);\n}\n\ninput:not([type]),\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"number\"],\ninput[type=\"range\"],\nselect {\n  width: 100%;\n  font-style: normal;\n  font-weight: 500;\n  line-height: 22px;\n  font-size: 15px;\n  height: 40px;\n  border-radius: 0px;\n  border: 0;\n  color: var(--primary-color);\n  background-color: #efefef;\n  margin: 0 0 10px 0;\n}\n\nselect {\n  padding: 0 10px;\n  margin: 0 0 20px 0;\n  -webkit-appearance: none;\n}\n\n/* input / select */\ninput:not([type]),\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"number\"] {\n  padding: 0 10px;\n  background-color: #f5f5f5;\n\n  &:focus,\n  &.success,\n  &:focus.success {\n    color: var(--success-color);\n    border-color: var(--success-color);\n  }\n\n  &.error,\n  &:focus.error {\n    color: var(--error-color);\n    border-color: var(--error-color);\n  }\n}\n\n/* remove up/down buttons for number input */\ninput[type=\"number\"]::-webkit-inner-spin-button {\n  -webkit-appearance: none;\n}\n\n/* show default cursor for readonly input */\ninput[readonly] {\n  cursor: default;\n}\n\n/* button */\nbutton {\n  padding: 0 20px 0 20px;\n  font-style: normal;\n  font-weight: 600;\n  font-size: 0.75em;\n  line-height: 40px;\n  text-transform: uppercase;\n  letter-spacing: 0.03em;\n  text-align: center;\n  text-decoration: none;\n  border: 0;\n  cursor: pointer;\n  -webkit-appearance: none;\n  -webkit-font-smoothing: antialiased !important;\n  transition: all 0.3s;\n  border-radius: 0px;\n  color: #fff;\n  background-color: var(--success-color);\n\n  &:hover {\n    background-color: var(--success-color--hover);\n  }\n\n  &[disabled=\"disabled\"],\n  &[disabled=\"disabled\"]:hover {\n    background-color: var(--disabled-color);\n    cursor: default;\n  }\n\n  &.error {\n    background-color: var(--error-color);\n  }\n  &.error:hover {\n    background-color: var(--error-color--hover);\n  }\n}\n\nbutton[outlined] {\n  height: 40px;\n}\n\nbutton[outlined]:not([disabled]) {\n  line-height: 39px;\n  background-color: #fff;\n  border: 1px solid var(--primary-color);\n  color: var(--primary-color);\n}\n\nbutton[small] {\n  height: 20px;\n  line-height: 20px !important;\n  font-size: 10px;\n  padding: 0 10px;\n}\n\n/* range slider */\ninput[type=\"range\"] {\n  width: 100%;\n}\n\n/* common styles */\n.important {\n  color: var(--error-color);\n}\n\n.ellipsis {\n  text-overflow: ellipsis;\n  /* Required for text-overflow to do anything */\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.vertical-center {\n  margin: 0;\n  position: absolute;\n  top: 50%;\n  transform: translateY(-50%);\n}\n\n.flex-row {\n  display: flex;\n  flex-direction: row;\n}\n\n.flex-col {\n  display: flex;\n  flex-direction: column;\n}\n\n.flex-1 {\n  flex: 1;\n}\n\n.align-right {\n  text-align: right;\n}\n\n.scrollable {\n  overflow: hidden;\n\n  &:hover {\n    overflow-y: overlay;\n  }\n\n  &.scrollable-x:hover {\n    overflow-x: overlay;\n  }\n\n  &::-webkit-scrollbar {\n    width: 10px;\n  }\n\n  &::-webkit-scrollbar-track {\n    background: var(--scrollbar-background-color);\n  }\n\n  &::-webkit-scrollbar-thumb {\n    border: 2px solid rgba(0, 0, 0, 0);\n    background-clip: padding-box;\n    background-color: var(--thumb-background-color);\n    border-radius: 14px;\n  }\n\n  &.dark {\n    &::-webkit-scrollbar-track {\n      background: rgba(0, 0, 0, 0);\n    }\n\n    &::-webkit-scrollbar-thumb {\n      background-color: var(--thumb-background-color-dark);\n    }\n  }\n}\n\n// set the range slider color to let it fit in the UI\n.vue-slider-process {\n  background-color: var(--primary-color) !important;\n}\n\n.vue-slider-dot-handle {\n  border-color: var(--primary-color) !important;\n}\n\n.vue-slider-disabled {\n  .vue-slider-process {\n    background-color: #a7a7a7 !important;\n  }\n}\n\n.vue-slider-dot-handle-disabled {\n  cursor: not-allowed;\n  border-color: #ddd !important;\n}\n\n.insufficient {\n  & .vue-slider-process {\n    background-color: var(--error-color) !important;\n  }\n  & .vue-slider-dot-handle {\n    border-color: var(--error-color) !important;\n  }\n}\n\n.transactionicon {\n  width: 25px;\n}\n"
  },
  {
    "path": "src/frontend/lite/src/css/css-reset.css",
    "content": "html, body, div, span, h1, h2, h3, h4, h5, h6, h7, p, a, img, strong, b, form, label {\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tfont-size: 100%;\n\tfont: inherit;\n\tvertical-align: baseline;\n}\n\nul,li {\n\tlist-style: none;\n}\n\nbody {\n\tline-height: 1;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tbackground-repeat: no-repeat;\n\tbackground-position: center center;\n\tuser-select: none; /* remove user-select from all elements */\n}\n\nhtml, *, *:before, *:after {\n  box-sizing: border-box;\n}\n\n* :focus {outline: none;}\n\nhtml,\nbody {\n  height: 100%;\n}"
  },
  {
    "path": "src/frontend/lite/src/css/fonts.less",
    "content": "/*\nThis CSS resource incorporates links to font software which is the valuable copyrighted\nproperty of Monotype Imaging and/or its suppliers. You may not attempt to copy, install,\nredistribute, convert, modify or reverse engineer this font software. Please contact Monotype\nImaging with any questions regarding Web Fonts:  http://www.fonts.com\n*/\n\n/* -------------------------------------------------------------- Euclid Circular B */\n\n@font-face{ \n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Light-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Light-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Light-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 300;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Regular-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Regular-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Regular-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 400;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Medium-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Medium-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Medium-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 500;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Semibold-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Semibold-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Semibold-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 600;\n\tfont-style: normal;\n}\n\n@font-face{\n    font-family: euclid;\n    src: url(\"./fonts/EuclidCircularB-Bold-WebS.eot?#iefix\");\n    src: url(\"./fonts/EuclidCircularB-Bold-WebS.eot?#iefix\") format(\"eot\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.woff2\") format(\"woff2\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.woff\") format(\"woff\"),\n    \t url(\"./fonts/EuclidCircularB-Bold-WebS.ttf\") format(\"truetype\");\n\tfont-weight: 700;\n\tfont-style: normal;\n}"
  },
  {
    "path": "src/frontend/lite/src/css/variables.less",
    "content": "// main theme\n@primary-color: #000000;\n@hover-color: #00000010;\n@success-color: @primary-color;\n@success-color--hover: lighten(@success-color, 4%); \n\n:root {\n  --primary-color: @primary-color;\n  --hover-color: @hover-color;\n  --success-color: @primary-color;\n  --success-color--hover: @success-color--hover;\n}\n\n// orange theme\n@primary-color--orange: #ee6622;\n@hover-color--orange: #ee662210;\n@success-color--orange: @primary-color--orange;\n@success-color--hover--orange: lighten(@success-color--orange, 4%); \n\n:root[data-theme=\"orange\"] {\n  --primary-color: @primary-color--orange;\n  --hover-color: @hover-color--orange;\n  --success-color: @primary-color--orange;\n  --success-color--hover: @success-color--hover--orange;\n}\n\n// common colors\n@secondary-color: #111444;\n@error-color: #dd3333;\n@disabled-color: #eee;\n@error-color--hover: lighten(@error-color, 8%);\n\n\n// common variables\n:root {\n  --header-height: 62px;\n  --footer-height: 56px;\n\n  --sidebar-left-width: 300px;\n  --sidebar-left-width-small: 260px;\n  --sidebar-left-background-color: #000;\n  --sidebar-left-color: #ccc;\n  --sidebar-left-border-color: #333;\n\n  --secondary-color: @secondary-color;\n  \n  --error-color: @error-color;\n  --error-color--hover: @error-color--hover;\n  \n  --disabled-color: @disabled-color;\n\n  --account-background-color--active: var(--primary-color);\n  --account-background-color--hover: #222;\n  \n  --main-border-color: #ddd;\n  --scrollbar-background-color: #fff;\n  --thumb-background-color: rgba(204, 204, 204, 0.7);\n\n  --scrollbar-background-color-dark: var(--sidebar-left-background-color);\n  --thumb-background-color-dark: rgba(204, 204, 204, 0.7);\n}\n"
  },
  {
    "path": "src/frontend/lite/src/i18n.js",
    "content": "import Vue from \"vue\";\nimport VueI18n from \"vue-i18n\";\n\nVue.use(VueI18n);\n\nfunction loadLocaleMessages() {\n  const locales = require.context(\"./locales\", true, /[A-Za-z0-9-_,\\s]+\\.json$/i);\n  const messages = {};\n  locales.keys().forEach(key => {\n    const matched = key.match(/([A-Za-z0-9-_]+)\\./i);\n    if (matched && matched.length > 1) {\n      const locale = matched[1];\n      messages[locale] = locales(key);\n    }\n  });\n  return messages;\n}\n\nlet language = window.navigator.language.slice(0, 2);\n\nexport default new VueI18n({\n  locale: process.env.VUE_APP_I18N_LOCALE || language,\n  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || \"en\",\n  messages: loadLocaleMessages()\n});\n"
  },
  {
    "path": "src/frontend/lite/src/layouts/AccountsSection.vue",
    "content": "<template>\n  <section class=\"accounts\">\n    <h4>{{ $t(\"accounts_section.accounts\") }}</h4>\n    <section class=\"scrollable dark\">\n      <div v-for=\"category in categories\" :key=\"category\">\n        <div class=\"category flex-row\">\n          <div class=\"toggle\" @click=\"toggleCategory(category)\">\n            <fa-icon :icon=\"['fal', getCategoryToggleIcon(category)]\" />\n          </div>\n          <div class=\"info\" @click=\"toggleCategory(category)\">\n            <div class=\"title ellipsis\">\n              {{ $t(`accounts_section.categories.${category}`) }}\n            </div>\n            <div class=\"balance\">{{ getBalanceFor(category) }}</div>\n          </div>\n          <div class=\"add\">\n            <div class=\"button\" @click=\"addAccountFor(category)\">\n              <fa-icon :icon=\"['fal', 'plus']\" />\n            </div>\n          </div>\n        </div>\n        <div class=\"account active\" v-if=\"showNewAccountFor(category) && false\">\n          <div>New account</div>\n          <div class=\"balance\">0</div>\n        </div>\n        <div v-if=\"opened[category]\">\n          <div v-for=\"account in getAccountsFor(category)\" :key=\"account.UUID\" class=\"account\" :class=\"accountClass(account.UUID)\">\n            <router-link\n              :disabled=\"isActiveAccount(account.UUID)\"\n              :event=\"!isActiveAccount(account.UUID) ? 'click' : ''\"\n              class=\"flex-col\"\n              :to=\"{ name: 'account', params: { id: account.UUID } }\"\n            >\n              <span class=\"ellipsis\">{{ account.label }}</span>\n              <span class=\"balance\">{{ displayBalanceForAccount(account) }}</span>\n            </router-link>\n          </div>\n        </div>\n      </div>\n    </section>\n  </section>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport UIConfig from \"../../ui-config.json\";\n\nexport default {\n  name: \"AccountsSection\",\n  data() {\n    const categories = [\"spending\"];\n    if (!UIConfig.isSPV) {\n      categories.push(\"saving\");\n    }\n\n    return {\n      categories,\n      opened: {\n        spending: false,\n        saving: false\n      }\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"activeAccount\"]),\n    ...mapState(\"app\", [\"coreReady\"]),\n    ...mapGetters(\"wallet\", [\"accounts\"]),\n    activeCategory() {\n      if (this.activeAccount === null) return null;\n      let account = this.accounts.find(x => x.UUID === this.activeAccount);\n      if (account === undefined) return null;\n      switch (account.type) {\n        case \"Desktop\":\n          return \"spending\";\n        case \"Holding\":\n        case \"Witness\":\n          return \"saving\";\n      }\n      return null;\n    }\n  },\n  watch: {\n    activeCategory() {\n      this.toggleCategory(this.activeCategory, true);\n    }\n  },\n  methods: {\n    isActiveAccount(accountUUID) {\n      return this.$route.path.indexOf(\"/account\") == 0 && accountUUID === this.activeAccount;\n    },\n    accountClass(accountUUID) {\n      return this.isActiveAccount(accountUUID) ? \"active\" : \"\";\n    },\n    displayBalanceForAccount(account) {\n      return formatMoneyForDisplay(account.balance);\n    },\n    getAccountsFor(category) {\n      let types;\n      switch (category) {\n        case \"spending\":\n          types = [\"Desktop\"];\n          break;\n        case \"saving\":\n          types = [\"Witness\", \"Holding\"];\n          break;\n      }\n      if (types === undefined) return [];\n      return this.accounts.filter(x => x.state === \"Normal\" && types.indexOf(x.type) !== -1);\n    },\n    getCategoryToggleIcon(category) {\n      return this.opened[category] ? \"chevron-down\" : \"chevron-right\";\n    },\n    toggleCategory(category, open) {\n      if (this.categories.indexOf(category) === -1) return;\n      this.opened[category] = open || !this.opened[category];\n    },\n    getBalanceFor(category) {\n      let accounts = this.getAccountsFor(category);\n      return formatMoneyForDisplay(\n        accounts.reduce(function (acc, obj) {\n          return acc + obj.balance;\n        }, 0)\n      );\n    },\n    showNewAccountFor(category) {\n      switch (category) {\n        case \"saving\":\n          return this.$route.name === \"add-saving-account\";\n        case \"spending\":\n          return this.$route.name === \"add-spending-account\";\n        default:\n          return false;\n      }\n    },\n    addAccountFor(category) {\n      switch (category) {\n        case \"saving\":\n          this.$router.push({ name: \"add-saving-account\" });\n          break;\n        case \"spending\":\n          this.$router.push({ name: \"add-spending-account\" });\n          break;\n        default:\n          console.log(`add account for ${category} not implemented yet`);\n          break;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.accounts {\n  height: 100%;\n\n  & h4 {\n    padding: 20px 20px 0 20px;\n    margin-bottom: 5px;\n    font-weight: 500;\n    font-size: 0.8em;\n  }\n\n  & > .scrollable {\n    height: calc(100% - 48px);\n  }\n}\n\n.category {\n  padding: 10px 0;\n\n  & > .toggle {\n    width: 44px;\n    padding: 0 0 0 20px;\n    font-size: 12px;\n    line-height: 16px;\n    cursor: pointer;\n\n    &.hide {\n      visibility: hidden;\n    }\n  }\n\n  & > .info {\n    width: 150px;\n    margin-right: 10px;\n    cursor: pointer;\n\n    & > .title {\n      line-height: 16px;\n      font-size: 0.85em;\n      font-weight: 600;\n      letter-spacing: 0.02em;\n      text-transform: uppercase;\n    }\n\n    & > .balance {\n      margin: 4px 0 1px 0;\n      line-height: 12px;\n      font-size: 0.8em;\n      font-weight: 500;\n      letter-spacing: 0.02em;\n      text-transform: uppercase;\n    }\n  }\n\n  & > .add {\n    flex: 1;\n    text-align: right;\n    margin: 0 24px 0 0;\n    line-height: 16px;\n    font-size: 16px;\n    cursor: pointer;\n\n    & > .button:hover {\n      padding: 4px 5px;\n      margin: -4px -5px;\n      background: #333;\n    }\n  }\n}\n\n.category.empty {\n  & > .toggle {\n    visibility: hidden;\n  }\n\n  & > .info {\n    cursor: default;\n  }\n}\n\n.account {\n  padding: 8px 24px;\n  font-size: 1em;\n  color: #ccc;\n  line-height: 16px;\n\n  &:hover {\n    background-color: var(--account-background-color--hover);\n  }\n\n  & a {\n    color: #ccc;\n    cursor: pointer;\n  }\n\n  &.active {\n    color: #fff;\n    background-color: var(--account-background-color--active);\n\n    & a {\n      color: #fff;\n    }\n  }\n\n  & .balance {\n    margin: 4px 0 1px 0;\n    font-size: 0.8em;\n    line-height: 12px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/layouts/SetupLayout.vue",
    "content": "<template>\n  <section class=\"setup-layout\">\n    <section class=\"header\">\n      <div class=\"logo\" />\n    </section>\n    <section class=\"main\">\n      <router-view />\n    </section>\n  </section>\n</template>\n\n<script>\nexport default {\n  name: \"SetupLayout\"\n};\n</script>\n\n<style lang=\"less\" scoped>\n.setup-layout {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n\n  & .header {\n    height: var(--header-height);\n    border-bottom: 1px solid var(--main-border-color);\n    padding: 20px;\n    font-size: 1.1em;\n    line-height: 42px;\n\n    & .logo {\n      width: 22px;\n      height: 22px;\n      background: url(\"../img/logo-start.svg\"), linear-gradient(transparent, transparent);\n      background-size: cover;\n    }\n  }\n\n  & .main {\n    height: calc(100vh - var(--header-height));\n    padding: 40px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/layouts/WalletLayout.vue",
    "content": "<template>\n  <section class=\"wallet-layout flex-row\" :class=\"walletLayoutClasses\">\n    <section v-if=\"!isSingleAccount\" class=\"sidebar-left\">\n      <section class=\"header flex-row\">\n        <div class=\"logo\" />\n        <div class=\"total-balance flex-row\">\n          <account-tooltip type=\"Wallet\" :account=\"account\">\n            <div class=\"flex-row\">\n              <div class=\"coin\">\n                {{ balanceForDisplay }}\n              </div>\n              <div class=\"fiat\">{{ totalBalanceFiat }}</div>\n            </div>\n          </account-tooltip>\n        </div>\n      </section>\n      <accounts-section class=\"accounts\" />\n      <section class=\"footer flex-row\">\n        <div class=\"status\" />\n        <div class=\"button\" @click=\"handleWalletLock\">\n          <fa-icon :icon=\"['fal', lockIcon]\" />\n        </div>\n        <div v-if=\"!isSPV\" class=\"button\" @click=\"showMining\">\n          <fa-icon :icon=\"['fal', 'gem']\" />\n        </div>\n        <div class=\"button\" @click=\"showSettings\">\n          <fa-icon :icon=\"['fal', 'user-circle']\" />\n        </div>\n      </section>\n    </section>\n    <section class=\"main\">\n      <section class=\"header\">\n        <account-header v-if=\"isSingleAccount\" :account=\"account\" :is-single-account=\"true\"></account-header>\n        <portal-target v-else ref=\"headerSlot\" name=\"header-slot\" @change=\"headerSlotChanged\"></portal-target>\n      </section>\n      <section class=\"content scrollable\">\n        <router-view />\n      </section>\n      <section class=\"footer\">\n        <div v-if=\"isSingleAccount\" style=\"display: flex\">\n          <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"account\" @click=\"routeTo\" />\n          <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send\" @click=\"routeTo\" />\n          <footer-button title=\"buttons.receive\" :icon=\"['fal', 'arrow-to-bottom']\" routeName=\"receive\" @click=\"routeTo\" />\n        </div>\n        <portal-target v-else ref=\"footerSlot\" name=\"footer-slot\" @change=\"footerSlotChanged\"></portal-target>\n      </section>\n    </section>\n  </section>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { formatMoneyForDisplay } from \"../util.js\";\nimport EventBus from \"../EventBus\";\nimport UIConfig from \"../../ui-config.json\";\nimport { AccountsController } from \"../unity/Controllers\";\nimport AccountsSection from \"./AccountsSection.vue\";\nimport AccountTooltip from \"../components/AccountTooltip.vue\";\nimport AccountHeader from \"../components/AccountHeader.vue\";\n\nexport default {\n  name: \"WalletLayout\",\n  data() {\n    return {\n      isHeaderSlotEmpty: true,\n      isFooterSlotEmpty: true,\n      isSingleAccount: UIConfig.isSingleAccount,\n      isSPV: UIConfig.isSPV\n    };\n  },\n  components: {\n    AccountsSection,\n    AccountHeader,\n    AccountTooltip\n  },\n  computed: {\n    ...mapState(\"app\", [\"progress\", \"rate\"]),\n    ...mapState(\"wallet\", [\"activeAccount\", \"unlocked\"]),\n    ...mapGetters(\"wallet\", [\"totalBalance\", \"miningAccount\", \"account\"]),\n    walletLayoutClasses() {\n      let classes = [];\n      if (!this.isSingleAccount) {\n        if (this.isHeaderSlotEmpty) classes.push(\"no-header\");\n        if (this.isFooterSlotEmpty) classes.push(\"no-footer\");\n      } else {\n        classes.push(\"no-sidebar-left\");\n      }\n      return classes;\n    },\n    lockIcon() {\n      return this.unlocked ? \"unlock\" : \"lock\";\n    },\n    totalBalanceFiat() {\n      if (!this.rate) return \"\";\n      return `€ ${formatMoneyForDisplay(this.totalBalance * this.rate, true)}`;\n    },\n    balanceForDisplay() {\n      if (this.totalBalance == null) return \"\";\n      return formatMoneyForDisplay(this.totalBalance);\n    }\n  },\n  methods: {\n    headerSlotChanged(newContent) {\n      this.isHeaderSlotEmpty = !newContent;\n    },\n    footerSlotChanged(newContent) {\n      this.isFooterSlotEmpty = !newContent;\n    },\n    showMining() {\n      if (this.miningAccount) {\n        if (this.$route.path.indexOf(\"/account\") == 0 && this.miningAccount.UUID === this.activeAccount) return;\n        this.$router.push({\n          name: \"account\",\n          params: { id: this.miningAccount.UUID }\n        });\n      } else {\n        EventBus.$emit(\"unlock-wallet\", {\n          timeout: 5,\n          title: \"setup_mining.title\",\n          message: \"setup_mining.information\",\n          callback: async () => {\n            let uuid = null;\n            try {\n              // NOTE:\n              // Dont' know if it is actually needed to show the activity indicator when unlocking the wallet and creating the account, but for now I leave it here.\n              this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n              uuid = AccountsController.CreateAccount(\"Mining\", \"Mining\");\n            } finally {\n              // route to the new account when we have a uuid\n              if (uuid) {\n                // activity indicator is set to true in the router, so no need to remove it here\n                this.$router.push({ name: \"account\", params: { id: uuid } });\n              } else {\n                // remove the activity indicator\n                this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n              }\n            }\n          }\n        });\n      }\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    },\n    getButtonClassNames(route) {\n      let classNames = [\"button\"];\n      if (route === this.$route.name) classNames.push(\"active\");\n      return classNames;\n    },\n    showSettings() {\n      if (this.$route.path === \"/settings/\") return;\n      this.$router.push({ name: \"settings\" });\n    },\n    handleWalletLock() {\n      EventBus.$emit(this.unlocked ? \"lock-wallet\" : \"unlock-wallet\");\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.wallet-layout {\n  height: 100vh;\n  overflow: hidden;\n\n  --header-height-main: var(--header-height);\n  --footer-height-main: var(--footer-height);\n\n  &.no-header {\n    --header-height-main: 0px;\n\n    & > .main > .header {\n      display: none;\n    }\n  }\n\n  &.no-footer {\n    --footer-height-main: 0px;\n    & > .main > .footer {\n      display: none;\n    }\n  }\n\n  & > .sidebar-left {\n    width: var(--sidebar-left-width);\n    background: var(--sidebar-left-background-color);\n    color: var(--sidebar-left-color);\n\n    & > .header {\n      height: var(--header-height);\n      border-bottom: 1px solid var(--sidebar-left-border-color);\n    }\n\n    & > .accounts {\n      height: calc(100% - var(--header-height) - var(--footer-height));\n    }\n\n    & > .footer {\n      height: var(--footer-height);\n      border-top: 1px solid var(--sidebar-left-border-color);\n    }\n  }\n\n  & > .main {\n    width: calc(100% - var(--sidebar-left-width));\n\n    & > .header {\n      height: var(--header-height);\n      border-bottom: 1px solid var(--main-border-color);\n      padding: 0 30px;\n\n      & > .logo {\n        position: relative;\n        top: 50%;\n        transform: translateY(-50%);\n      }\n    }\n\n    & > .content {\n      height: calc(100% - var(--header-height-main) - var(--footer-height-main));\n      padding: 40px 30px 30px 30px;\n\n      & > * {\n        height: 100%;\n      }\n    }\n\n    & > .footer {\n      height: var(--footer-height);\n      border-top: 1px solid var(--main-border-color);\n      line-height: calc(var(--footer-height) - 2px);\n      text-align: center;\n    }\n  }\n\n  &.no-sidebar-left {\n    & > .main {\n      width: 100%;\n    }\n  }\n}\n\n.sidebar-left > .header {\n  padding: 20px;\n  color: #fff;\n\n  & .total-balance {\n    padding: 0 0 0 10px;\n    line-height: 22px;\n  }\n\n  & .fiat {\n    margin-left: 10px;\n    color: #999;\n  }\n}\n\n.sidebar-left > .footer {\n  font-size: 16px;\n  font-weight: 400;\n\n  & .status {\n    flex: 1;\n  }\n\n  & .button {\n    line-height: 52px;\n    padding: 0 20px;\n    cursor: pointer;\n\n    &:hover {\n      background-color: #222;\n    }\n  }\n}\n\n.logo {\n  width: 22px;\n  min-width: 22px;\n  height: 22px;\n  min-height: 22px;\n  background: url(\"../img/logo.svg\"), linear-gradient(transparent, transparent);\n  background-size: cover;\n}\n\n@media (max-width: 1000px) {\n  .wallet-layout {\n    & > .sidebar-left {\n      width: var(--sidebar-left-width-small);\n    }\n\n    & > .main {\n      width: calc(100% - var(--sidebar-left-width-small));\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/locales/en.json",
    "content": "{\n  \"accounts_section\": {\n    \"accounts\": \"Accounts\",\n    \"categories\": {\n      \"spending\": \"Spending\",\n      \"saving\": \"Witness\"\n    }\n  },\n  \"account_settings\": {\n    \"title\": \"Account settings\",\n    \"name\": \"Name\"\n  },\n  \"add_saving_account\": {\n    \"daily\": \"daily\",\n    \"estimated_earnings\": \"Estimated earnings\",\n    \"funding_account\": \"Funding account\",\n    \"lock_for\": \"Lock for\",\n    \"overall\": \"overall\",\n    \"title\": \"Add witness account\"\n  },\n  \"add_spending_account\": {\n    \"title\": \"Add spending account\"\n  },\n  \"buttons\": {\n    \"back\": \"Back\",\n    \"buy\": \"Buy\",\n    \"sell\": \"Sell\",\n    \"buy_your_first_coins\": \"Buy Munt\",\n    \"clear\": \"Clear\",\n    \"confirm\": \"Confirm\",\n    \"cancel\": \"Cancel\",\n    \"change_password\": \"Change password\",\n    \"create_mining_account\": \"Create mining account\",\n    \"finish\": \"Finish\",\n    \"lock\": \"Lock\",\n    \"next\": \"Next\",\n    \"ok\": \"OK\",\n    \"previous\": \"Previous\",\n    \"ready\": \"Ready\",\n    \"receive\": \"Receive\",\n    \"download\": \"Download\",\n    \"renew\": \"Renew\",\n    \"send\": \"Send\",\n    \"start\": \"Start\",\n    \"stop\": \"Stop\",\n    \"transactions\": \"Transactions\",\n    \"unlock\": \"Unlock\",\n    \"done\": \"Done\",\n    \"saving_key\": \"Witness Key\",\n    \"info\": \"Info\",\n    \"optimise\": \"Optimise\"\n  },\n  \"clipboard_field\": {\n    \"copied_to_clipboard\": \"Copied to clipboard\"\n  },\n  \"common\": {\n    \"account_name\": \"Account name\",\n    \"amount\": \"Amount\",\n    \"enter_your_password\": \"Enter your password\",\n    \"important\": \"Important\",\n    \"information\": \"Information\",\n    \"months\": \"Months\",\n    \"on\": \"on\",\n    \"off\": \"off\",\n    \"password\": \"Password\",\n    \"receiving_address\": \"Receiving address\",\n    \"days\": \"days\",\n    \"ticker_symbol\": \"MUNT\"\n  },\n  \"new_wallet\": {\n    \"title\": \"Welcome to your Munt wallet\",\n    \"information\": \"This wallet is only stored on your device.\\nNever give anyone else access to your wallet.\\nKeep the backup phrase you see at installation in a safe place.\\nLose phrase or someone else with access to the phrase = lose Munt.\"\n  },\n  \"saving_account\": {\n    \"compound_earnings\": \"Compound Earnings\",\n    \"status\": \"Status\",\n    \"parts\": \"Parts\",\n    \"coins_locked\": \"Initial amount locked\",\n    \"coins_earned\": \"Amount earned\",\n    \"locked_from_block\": \"Locked from block\",\n    \"locked_until_block\": \"Locked until block\",\n    \"lock_duration\": \"Lock duration\",\n    \"blocks\": \"blocks\",\n    \"remaining_lock_period\": \"Remaining lock period\",\n    \"required_earnings_frequency\": \"Required earnings frequency\",\n    \"expected_earnings_frequency\": \"Expected earnings frequency\",\n    \"account_weight\": \"Account weight\",\n    \"network_weight\": \"Network weight\",\n    \"empty\": \"This witness account is empty\",\n    \"percent\": \"%\",\n    \"add_to_holdin\": \"Add to holdin.com\",\n    \"remove_from_holdin\": \"Remove from holdin.com\",\n    \"optimise_holding_account\": \"Select Funding Account\"\n  },\n  \"loader\": {\n    \"shutdown\": \"Shutting down...\",\n    \"synchronizing\": \"Your wallet is now synchronizing with the Munt network. This may take some time to complete.\"\n  },\n  \"mining\": {\n    \"arena_setup_time\": \"Arena setup time\",\n    \"best_reported_speed\": \"Best reported speed\",\n    \"last_reported_speed\": \"Last reported speed\",\n    \"memory_to_use\": \"Memory usage\",\n    \"moving_average\": \"Moving average\",\n    \"number_of_threads\": \"Number of threads\",\n    \"number_of_arena_threads\": \"Number of arena setup threads\",\n    \"statistics\": \"Statistics\",\n    \"thread\": \"thread | threads\",\n    \"settings\": \"Settings\",\n    \"current_of_max\": \"{current} of {max}\",\n    \"warning_performance\": \"Performance is degraded due to reduced memory usage\",\n    \"address\": \"My Mining Address\"\n  },\n  \"password_dialog\": {\n    \"unlock_wallet\": \"Unlock wallet\"\n  },\n  \"settings\": {\n    \"header\": \"Settings\",\n    \"change_password\": \"Change password\",\n    \"view_recovery_phrase\": \"View recovery phrase\",\n    \"choose_theme\": \"Theme\",\n    \"choose_language\": \"Language\",\n    \"choose_decimal_places\": \"Decimal places\",\n    \"english\": \"EN\",\n    \"dutch\": \"NL\"\n  },\n  \"setup\": {\n    \"choose_password\": \"Choose a password of at least 6 characters\",\n    \"choose_password_information\": \"You will need your password to unlock your wallet. Make sure it is not easy to guess because anyone who knows your password can access your funds.\",\n    \"create_new\": \"I do not have a Munt wallet yet\",\n    \"enter_existing_recovery_phrase\": \"Munt LITE is not suitable for a full desktop wallet recovery phrase (with witness and mining functionality).\",\n    \"enter_recovery_phrase\": \"Enter recovery phrase\",\n    \"invalid_recovery_phrase\": {\n      \"title\": \"Invalid recovery phrase\",\n      \"message\": \"This combination is not a valid recovery phrase. Correct the error(s) and try again.\"\n    },\n    \"recover_existing\": \"I already have a Munt wallet\",\n    \"repeat_password\": \"Repeat password\",\n    \"repeat_your_recovery_phrase\": \"To make sure you have correctly written down your recovery phrase, enter your phrase in the boxes below.\",\n    \"setup_your_wallet\": \"Make a choice\",\n    \"this_is_your_recovery_phrase\": \"This is your recovery phrase. Keep your backup phrase in a safe place. Lose phrase or someone else with access to the phrase = lose Munt.\"\n  },\n  \"setup_mining\": {\n    \"title\": \"Setup mining\",\n    \"information\": \"Before you can start mining Munt a mining account needs to be created. Enter your password to unlock your wallet and create a mining account.\"\n  },\n  \"transaction_details\": {\n    \"title\": {\n      \"incoming_transaction\": \"Incoming transaction\",\n      \"outgoing_transaction\": \"Outgoing transaction\"\n    },\n    \"hash\": \"Hash\"\n  },\n  \"receive_coins\": {\n    \"address_copied_to_clipboard\": \"Address copied to clipboard\",\n    \"buy_or_receive_coins\": \"Buy or receive Munt\",\n    \"click_to_copy_qr\": \"Click to copy QR\",\n    \"information\": \"After each transaction you will receive a new address, but the previous address will still work.\",\n    \"your_address\": \"Your Munt address\",\n    \"qr_copied_to_clipboard\": \"QR copied to clipboard\"\n  },\n  \"send_coins\": {\n    \"enter_label\": \"Enter label\",\n    \"enter_coins_address\": \"Enter Munt address\",\n    \"confirm_transaction\": \"Confirm transaction\",\n    \"target_account\": \"Send to account\",\n    \"fee_will_be_subtracted\": \"Fee will be subtracted from the amount\",\n    \"unlock_your_wallet_to_complete_the_transaction\": \"Unlock your wallet to complete the transaction\"\n  },\n  \"renew_saving_account\": {\n    \"funding_account\": \"Pay renewal fee from account\"\n  },\n  \"link_saving_account\": {\n    \"title\": \"Your witness key\",\n    \"information\": \"Use your witness key only for trusted cloud witness services. Your witness key provides access to your rewards, so never show it to other people.\",\n    \"no_funds\": \"Witness account must be funded with locked funds before it is possible to link it with other wallets.\"\n  },\n  \"peers\": {\n    \"node_id\": \"Node ID\",\n    \"node_service\": \"Node/Service\",\n    \"user_agent\": \"User Agent\",\n    \"address\": \"Address\",\n    \"reason\": \"Reason\",\n    \"peers\": \"Peers:\",\n    \"banned_peers\": \"Banned Peers\",\n    \"whitelisted\": \"Whitelisted\",\n    \"direction\": \"Direction\",\n    \"services\": \"Services\",\n    \"starting_block\": \"Starting Block\",\n    \"synced_headers\": \"Synced Headers\",\n    \"synced_blocks\": \"Synced Blocks\",\n    \"ban_score\": \"Ban Score\",\n    \"connection_time\": \"Connection Time\",\n    \"last_send\": \"Last Send\",\n    \"last_receive\": \"Last Receive\",\n    \"sent\": \"Sent\",\n    \"received\": \"Received\",\n    \"ping_time\": \"Ping Time\",\n    \"time_offset\": \"Time Offset\",\n    \"banned_from\": \"Banned From\",\n    \"banned_until\": \"Banned Until\",\n    \"peer_details\": \"Peer Details\",\n    \"ban\": \"Ban\",\n    \"buttons\": {\n      \"clear_banned\": \"Clear banned\",\n      \"disconnect\": \"Disconnect\",\n      \"ban_hour\": \"1 Hour\",\n      \"ban_day\": \"1 Day\",\n      \"ban_week\": \"1 Week\",\n      \"ban_year\": \"1 Year\",\n      \"un_ban\": \"Unban Peer\",\n      \"optimise\": \"Optimise\"\n    }\n  },\n  \"tooltip\": {\n    \"account_balance\": \"Account Balance\",\n    \"wallet_balance\": \"Wallet Balance\",\n    \"total\": \"Total\",\n    \"locked\": \"Locked\",\n    \"spendable\": \"Spendable\",\n    \"pending\": \"Pending\"\n  },\n  \"unlock_wallet_dialog\": {\n    \"title\": \"Unlock wallet\",\n    \"unlock_for\": \"Unlock for...\",\n    \"minute\": \"{n} minute | {n} minutes\"\n  }\n}\n"
  },
  {
    "path": "src/frontend/lite/src/locales/nl.json",
    "content": "{\n  \"accounts_section\": {\n    \"accounts\": \"Rekeningen\",\n    \"categories\": {\n      \"spending\": \"Betalen\",\n      \"saving\": \"Witness\"\n    }\n  },\n  \"account_settings\": {\n    \"title\": \"Rekening instellingen\",\n    \"name\": \"Naam\"\n  },\n  \"add_saving_account\": {\n    \"daily\": \"per dag\",\n    \"estimated_earnings\": \"Geschatte opbrengst\",\n    \"funding_account\": \"Financieringsrekening\",\n    \"lock_for\": \"Vastzetten voor\",\n    \"overall\": \"totaal\",\n    \"title\": \"Witness rekening aanmaken\"\n  },\n  \"add_spending_account\": {\n    \"title\": \"Betaalrekening aanmaken\"\n  },\n  \"buttons\": {\n    \"back\": \"Terug\",\n    \"buy\": \"Koop\",\n    \"sell\": \"Verkoop\",\n    \"buy_your_first_coins\": \"Koop Munt\",\n    \"clear\": \"Wissen\",\n    \"confirm\": \"Bevestig\",\n    \"cancel\": \"Annuleren\",\n    \"change_password\": \"Verander wachtwoord\",\n    \"create_mining_account\": \"Mining rekening aanmaken\",\n    \"finish\": \"Klaar\",\n    \"lock\": \"Vastzetten\",\n    \"next\": \"Volgende\",\n    \"ok\": \"OK\",\n    \"previous\": \"Vorige\",\n    \"ready\": \"Klaar\",\n    \"receive\": \"Ontvangen\",\n    \"renew\": \"Vernieuwen\",\n    \"send\": \"Versturen\",\n    \"start\": \"Start\",\n    \"stop\": \"Stop\",\n    \"transactions\": \"Transacties\",\n    \"unlock\": \"Ontgrendelen\",\n    \"done\": \"Klaar\",\n    \"saving_key\": \"Witness key\",\n    \"info\": \"Info\",\n    \"optimise\": \"Optimise\"\n  },\n  \"clipboard_field\": {\n    \"copied_to_clipboard\": \"Gekopieërd naar klembord\"\n  },\n  \"common\": {\n    \"account_name\": \"Rekeningnaam\",\n    \"amount\": \"Bedrag\",\n    \"enter_your_password\": \"Voer jouw wachtwoord in\",\n    \"important\": \"Belangrijk\",\n    \"information\": \"Informatie\",\n    \"months\": \"Maanden\",\n    \"on\": \"Aan\",\n    \"off\": \"Uit\",\n    \"password\": \"Wachtwoord\",\n    \"receiving_address\": \"Ontvangstadres\",\n    \"days\": \"Dagen\",\n    \"ticker_symbol\": \"MUNT\"\n  },\n  \"new_wallet\": {\n    \"title\": \"Welkom bij jouw Munt wallet\",\n    \"information\": \"Deze wallet staat alleen op jouw apparaat.\\nGeef nooit iemand anders toegang tot jouw wallet.\\nBewaar de herstelzin die je te zien krijgt tijdens installatie op een veilige plek.\\nHerstelzin kwijt of iemand toegang tot je herstelzin = Munt weg.\"\n  },\n  \"saving_account\": {\n    \"compound_earnings\": \"Cumulatieve Inkomsten\",\n    \"status\": \"Status\",\n    \"parts\": \"Delen\",\n    \"coins_locked\": \"Primair vastgezette aantal\",\n    \"coins_earned\": \"Aantal verdiend\",\n    \"locked_from_block\": \"Vastgezet vanaf blok\",\n    \"locked_until_block\": \"Vastgezet tot blok\",\n    \"lock_duration\": \"Looptijd\",\n    \"blocks\": \"blokken\",\n    \"remaining_lock_period\": \"Resterende looptijd\",\n    \"required_earnings_frequency\": \"Benodigde beloningstijd\",\n    \"expected_earnings_frequency\": \"Verwachte beloningstijd\",\n    \"account_weight\": \"Gewicht\",\n    \"network_weight\": \"Netwerk gewicht\",\n    \"empty\": \"Deze witness rekening is leeg\",\n    \"percent\": \"%\",\n    \"add_to_holdin\": \"Add to holdin.com\",\n    \"remove_from_holdin\": \"Remove from holdin.com\",\n    \"optimise_holding_account\": \"Select Funding Account\"\n  },\n  \"loader\": {\n    \"shutdown\": \"Bezig met afsluiten...\",\n    \"synchronizing\": \"Jouw wallet is aan het synchroniseren met het Munt netwerk. Dit kan enige tijd duren.\"\n  },\n  \"mining\": {\n    \"arena_setup_time\": \"Arena setup tijd\",\n    \"best_reported_speed\": \"Beste geregistreerde snelheid\",\n    \"last_reported_speed\": \"Laatst geregistreerde snelheid\",\n    \"memory_to_use\": \"Geheugengebruik\",\n    \"moving_average\": \"Voortschrijdend gemiddelde\",\n    \"number_of_threads\": \"Aantal threads\",\n    \"number_of_arena_threads\": \"Aantal arena setup threads\",\n    \"statistics\": \"Statistieken\",\n    \"thread\": \"thread | threads\",\n    \"settings\": \"Instellingen\",\n    \"current_of_max\": \"{current} van {max}\",\n    \"warning_performance\": \"Prestaties zijn verminderd door lager geheugengebruik\",\n    \"address\": \"Mining adres\"\n  },\n  \"password_dialog\": {\n    \"unlock_wallet\": \"Ontgrendel wallet\"\n  },\n  \"settings\": {\n    \"header\": \"Instellingen\",\n    \"change_password\": \"Verander wachtwoord\",\n    \"view_recovery_phrase\": \"Bekijk herstelzin\",\n    \"choose_theme\": \"Thema\",\n    \"choose_language\": \"Taal\",\n    \"choose_decimal_places\": \"Aantal decimalen\",\n    \"english\": \"EN\",\n    \"dutch\": \"NL\"\n  },\n  \"setup\": {\n    \"choose_password\": \"Kies een wachtwoord van minimaal 6 karakters.\",\n    \"choose_password_information\": \"Een wachtwoord is vereist voor het ontgrendelen van jouw wallet. Kies een sterk wachtwoord, zodat niemand anders toegang kan krijgen tot jouw Munt.\",\n    \"create_new\": \"I do not have a Munt wallet yet\",\n    \"enter_existing_recovery_phrase\": \"Munt LITE is not suitable for a full desktop wallet recovery phrase (with witness and mining functionality).\",\n    \"enter_recovery_phrase\": \"Voer herstelzin in\",\n    \"invalid_recovery_phrase\": {\n      \"title\": \"Ongeldige herstelzin\",\n      \"message\": \"Deze combinatie vormt geen geldige herstelzin. Corrigeer de fout(en) en probeer het nogmaals.\"\n    },\n    \"recover_existing\": \"I already have a Munt wallet\",\n    \"repeat_password\": \"Herhaal wachtwoord\",\n    \"repeat_your_recovery_phrase\": \"Voer jouw herstelzin in om te controleren dat je deze goed hebt opgeschreven.\",\n    \"setup_your_wallet\": \"Make a choice\",\n    \"this_is_your_recovery_phrase\": \"Dit is jouw herstelzin. Bewaar de herstelzin op een veilige plek. Zin kwijt of iemand toegang tot je zin = Munt weg.\"\n  },\n  \"setup_mining\": {\n    \"title\": \"Mining instellen\",\n    \"information\": \"Voordat je kunt beginnen met minen van Munt moet een mining rekening worden aangemaakt. Voer je wachtwoord in om je wallet te ontgrendelen en een mining rekening aan te maken.\"\n  },\n  \"transaction_details\": {\n    \"title\": {\n      \"incoming_transaction\": \"Inkomende transactie\",\n      \"outgoing_transaction\": \"Uitgaande transactie\"\n    },\n    \"hash\": \"Hash\"\n  },\n  \"receive_coins\": {\n    \"address_copied_to_clipboard\": \"Adres gekopieërd naar klembord\",\n    \"buy_or_receive_coins\": \"Koop of ontvang Munt\",\n    \"click_to_copy_qr\": \"Klik om QR te kopiëren\",\n    \"information\": \"Na iedere transactie krijg je een nieuw adres, maar het vorige adres blijft werken.\",\n    \"your_address\": \"Jouw Munt adres\",\n    \"qr_copied_to_clipboard\": \"QR gekopieërd naar klembord\"\n  },\n  \"send_coins\": {\n    \"enter_label\": \"Voer label in\",\n    \"enter_coins_address\": \"Voer Munt adres in\",\n    \"confirm_transaction\": \"Bevestig transactie\",\n    \"target_account\": \"Verstuur naar rekening\",\n    \"fee_will_be_subtracted\": \"De transactie fee wordt van het bedrag afgehaald\",\n    \"unlock_your_wallet_to_complete_the_transaction\": \"Ontgrendel je portemonnee om de transactie af te ronden\"\n  },\n  \"renew_saving_account\": {\n    \"funding_account\": \"Betaal vergoeding van rekening\"\n  },\n  \"link_saving_account\": {\n    \"title\": \"Jouw witness key\",\n    \"information\": \"Gebruik je witness key alleen voor vertrouwde cloud witness services. Jouw witness key geeft toegang tot jouw beloningen, laat deze dus nooit aan andere mensen zien.\",\n    \"no_funds\": \"Witness rekening moet worden gevuld met vastgezette Munt voordat het mogelijk is om deze te koppelen met andere wallets.\"\n  },\n  \"peers\": {\n    \"node_id\": \"Node ID\",\n    \"node_service\": \"Node/Service\",\n    \"user_agent\": \"User Agent\",\n    \"address\": \"Adres\",\n    \"reason\": \"Reden\",\n    \"peers\": \"Peers:\",\n    \"banned_peers\": \"Geblokeerde Peers\",\n    \"whitelisted\": \"Whitelisted\",\n    \"direction\": \"Richting\",\n    \"services\": \"Services\",\n    \"starting_block\": \"Startende block\",\n    \"synced_headers\": \"Gesyncroniseerde Headers\",\n    \"synced_blocks\": \"Gesyncroniseerde Blocks\",\n    \"ban_score\": \"Blokeer Score\",\n    \"connection_time\": \"Connectietijd\",\n    \"last_send\": \"Laatst verzonden\",\n    \"last_receive\": \"Laatst ontvangen\",\n    \"sent\": \"Verzonden\",\n    \"received\": \"Ontvangen\",\n    \"ping_time\": \"Ping Time\",\n    \"time_offset\": \"Time Offset\",\n    \"banned_from\": \"Geblokkeerd sinds\",\n    \"banned_until\": \"Geblokkeerd tot\",\n    \"peer_details\": \"Peer Details\",\n    \"ban\": \"Blokkeren\",\n    \"buttons\": {\n      \"clear_banned\": \"Alles deblokkeren\",\n      \"disconnect\": \"Verbinden verbreken\",\n      \"ban_hour\": \"1 Uur\",\n      \"ban_day\": \"1 Dag\",\n      \"ban_week\": \"1 Week\",\n      \"ban_year\": \"1 Jaar\",\n      \"un_ban\": \"Deblokkeren\",\n      \"optimise\": \"Optimaliseren\"\n    }\n  },\n  \"tooltip\": {\n    \"account_balance\": \"Account balans\",\n    \"wallet_balance\": \"Portemonnee balans\",\n    \"total\": \"Totaal\",\n    \"locked\": \"Vastgezet\",\n    \"spendable\": \"Te spenderen\",\n    \"pending\": \"In afwachting\"\n  },\n  \"unlock_wallet_dialog\": {\n    \"title\": \"Portemonnee ontgrendelen\",\n    \"unlock_for\": \"Ontgrendelen voor...\",\n    \"minute\": \"{n} minuut | {n} minuten\"\n  }\n}\n"
  },
  {
    "path": "src/frontend/lite/src/main.js",
    "content": "import Vue from \"vue\";\nimport App from \"./App.vue\";\nimport store from \"./store\";\nimport router from \"./router\";\nimport i18n from \"./i18n\";\n\nimport \"./components\";\n\nimport VueSlider from \"vue-slider-component\";\nimport \"vue-slider-component/theme/antd.css\";\nVue.component(\"VueSlider\", VueSlider);\n\nimport ToggleButton from \"vue-js-toggle-button\";\nVue.use(ToggleButton);\n\nimport PortalVue from \"portal-vue\";\nVue.use(PortalVue);\n\nimport { FontAwesomeIcon } from \"@fortawesome/vue-fontawesome\";\nimport { library } from \"@fortawesome/fontawesome-svg-core\";\nimport {\n  faAngleDoubleLeft,\n  faAngleDoubleRight,\n  faArrowFromBottom,\n  faArrowLeft,\n  faArrowToBottom,\n  faBan,\n  faChevronDown,\n  faChevronRight,\n  faCog,\n  faCopy,\n  faCreditCard,\n  faEraser,\n  faGem,\n  faHourglassStart,\n  faLock,\n  faLongArrowLeft,\n  faLongArrowRight,\n  faPen,\n  faPlus,\n  faSearchMinus,\n  faSearchPlus,\n  faShield,\n  faShieldCheck,\n  faTimes,\n  faUniversity,\n  faUnlock,\n  faUserCircle,\n  faRedoAlt,\n  faKey,\n  faInfoCircle,\n  faExclamationTriangle,\n  faUndo,\n  faTrash,\n  faFileSearch,\n  faDownload\n} from \"@fortawesome/pro-light-svg-icons\";\n\nimport { faListUl, faLongArrowDown } from \"@fortawesome/pro-regular-svg-icons\";\n\nlibrary.add([\n  faAngleDoubleLeft,\n  faAngleDoubleRight,\n  faArrowFromBottom,\n  faArrowLeft,\n  faArrowToBottom,\n  faBan,\n  faChevronDown,\n  faChevronRight,\n  faCog,\n  faCopy,\n  faCreditCard,\n  faEraser,\n  faGem,\n  faHourglassStart,\n  faLock,\n  faLongArrowLeft,\n  faLongArrowRight,\n  faPen,\n  faPlus,\n  faSearchMinus,\n  faSearchPlus,\n  faShield,\n  faShieldCheck,\n  faTimes,\n  faUniversity,\n  faUnlock,\n  faUserCircle,\n  faRedoAlt,\n  faKey,\n  faLongArrowDown,\n  faListUl,\n  faInfoCircle,\n  faExclamationTriangle,\n  faUndo,\n  faTrash,\n  faFileSearch,\n  faDownload\n]);\n\nVue.component(\"fa-icon\", FontAwesomeIcon);\n\nVue.config.productionTip = false;\n\nnew Vue({\n  store,\n  router,\n  i18n,\n  render: h => h(App)\n}).$mount(\"#app\");\n"
  },
  {
    "path": "src/frontend/lite/src/router/index.js",
    "content": "import Vue from \"vue\";\nimport VueRouter from \"vue-router\";\nimport Account from \"../views/Account\";\n\nimport { AccountsController } from \"../unity/Controllers\";\nimport store from \"../store\";\n\nVue.use(VueRouter);\n\nconst routes = [\n  {\n    path: \"/account/:id?\",\n    name: \"account\",\n    props: true,\n    component: Account,\n    children: [\n      {\n        path: \"send\",\n        name: \"send\",\n        component: () => import(/* webpackChunkName: \"account-send\" */ \"../views/Account/SpendingAccount/Send.vue\")\n      },\n      {\n        path: \"receive\",\n        name: \"receive\",\n        component: () => import(/* webpackChunkName: \"account-receive\" */ \"../views/Account/SpendingAccount/Receive.vue\")\n      },\n      {\n        path: \"transactions\",\n        name: \"transactions\",\n        component: () => import(/* webpackChunkName: \"transactions\" */ \"../views/Account/SpendingAccount/Transactions.vue\")\n      }\n    ]\n  },\n  {\n    path: \"/setup\",\n    name: \"setup\",\n    component: () => import(/* webpackChunkName: \"setup\" */ \"../views/Setup.vue\"),\n    meta: {\n      layout: \"setup-layout\"\n    }\n  },\n  {\n    path: \"/settings\",\n    component: () => import(/* webpackChunkName: \"settings\" */ \"../views/Settings\"),\n    children: [\n      {\n        path: \"\",\n        name: \"settings\",\n        component: () => import(/* webpackChunkName: \"settings-list\" */ \"../views/Settings/SettingsList.vue\")\n      },\n      {\n        path: \"view-recovery-phrase\",\n        name: \"view-recovery-phrase\",\n        component: () => import(/* webpackChunkName: \"view-recovery-phrase\" */ \"../views/Settings/ViewRecoveryPhrase.vue\")\n      },\n      {\n        path: \"change-password\",\n        name: \"change-password\",\n        component: () => import(/* webpackChunkName: \"change-password\" */ \"../views/Settings/ChangePassword.vue\")\n      }\n    ]\n  },\n  {\n    path: \"/debug\",\n    name: \"debug\",\n    component: () => import(/* webpackChunkName: \"debug-dialog\" */ \"../views/DebugDialog\")\n  }\n];\n\nconst router = new VueRouter({\n  routes\n});\n\nrouter.beforeEach((to, from, next) => {\n  console.log(`route to ${to.name}`);\n\n  if (to.name === \"account\" && to.params.id !== undefined) {\n    // If the id of the account doesn't change there is no need to call SetActiveAccount\n    // This happens for example when routing from send or receive child view to the transactions view\n    if (to.params.id !== from.params.id) {\n      console.log(`account: ${to.params.id}`);\n\n      // set activity indicator to true when switching accounts\n      store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", true);\n\n      // set active account to specified id\n      AccountsController.SetActiveAccount(to.params.id);\n\n      // IMPORTANT: Do not set activity indicator to false here!\n      // 1. AccountsController.SetActiveAccount tells the backend to change the account (but it isn't changed immediately).\n      // 2. When the account has been changed the onActiveAccountChanged handler in unity/LibUnity.js will update the store with new account data.\n      // 3. After the account in the store has been changed the onAccountChanged handler in views/Account/index.vue will set the activity indicator to false.\n    }\n  }\n\n  next();\n});\n\nexport default router;\n"
  },
  {
    "path": "src/frontend/lite/src/store/index.js",
    "content": "import Vue from \"vue\";\nimport Vuex from \"vuex\";\nimport { createPersistedState, createSharedMutations } from \"vuex-electron\";\nimport syncState from \"./syncState\";\nimport Store from \"electron-store\";\nimport walletPath from \"../walletPath\";\n\nimport modules from \"./modules\";\n\nVue.use(Vuex);\n\nlet userSettingsPersistedState = () => {};\n// create persistate state in main process only\nif (process.type !== \"renderer\") {\n  // use user-settings.json file to store settings in wallet folder\n  let store = new Store({ cwd: walletPath, name: \"user-settings\" });\n\n  userSettingsPersistedState = createPersistedState({\n    storage: store,\n    invertIgnored: true, // use invertIgnored because we only want to store the paths in the ignoredPaths list and only persist on specific commits\n    ignoredPaths: [\n      // only store the paths listed below\n      \"mining.settings\",\n      \"app.language\",\n      \"app.decimals\"\n    ],\n    ignoredCommits: [\n      // only update persisted state on commits listed below\n      \"mining/SET_MEMORY_SIZE\",\n      \"mining/SET_THREAD_COUNT\",\n      \"mining/SET_ARENA_THREAD_COUNT\",\n      \"app/SET_LANGUAGE\",\n      \"app/SET_DECIMALS\"\n    ]\n  });\n}\nexport default new Vuex.Store({\n  modules: modules,\n  plugins: [syncState, userSettingsPersistedState, createSharedMutations()]\n});\n"
  },
  {
    "path": "src/frontend/lite/src/store/modules/app.js",
    "content": "import AppStatus from \"../../AppStatus\";\nimport { Menu } from \"electron\";\n\nfunction EnableDebugWindowOnCoreReady() {\n  try {\n    let menu = Menu.getApplicationMenu();\n    if (menu === null) return;\n    menu.items.find(x => x.label === \"Help\").submenu.items.find(x => x.label === \"Debug window\").enabled = true;\n  } catch (e) {\n    console.error(e);\n  }\n}\n\nconst app = {\n  namespaced: true,\n  state: {\n    coreReady: false,\n    syncDone: false,\n    activityIndicator: false,\n    splashReady: false,\n    status: AppStatus.start,\n    theme: null,\n    unityVersion: null,\n    walletExists: null,\n    walletVersion: null,\n    rate: null,\n    language: \"en\",\n    decimals: 2\n  },\n  mutations: {\n    SET_CORE_READY(state) {\n      state.coreReady = true;\n    },\n    SET_SYNC_DONE(state) {\n      state.syncDone = true;\n    },\n    SET_SPLASH_READY(state) {\n      state.splashReady = true;\n    },\n    SET_STATUS(state, status) {\n      if (state.status === AppStatus.shutdown) return; // shutdown in progress, do not switch to other status\n      state.status = status;\n    },\n    SET_THEME(state, theme) {\n      state.theme = theme;\n    },\n    SET_UNITY_VERSION(state, version) {\n      state.unityVersion = version;\n    },\n    SET_RATE(state, rate) {\n      state.rate = rate;\n    },\n    SET_WALLET_EXISTS(state, walletExists) {\n      state.walletExists = walletExists;\n    },\n    SET_WALLET_VERSION(state, version) {\n      state.walletVersion = version;\n    },\n    SET_ACTIVITY_INDICATOR(state, activityIndicator) {\n      state.activityIndicator = activityIndicator;\n    },\n    SET_LANGUAGE(state, language) {\n      state.language = language;\n    },\n    SET_DECIMALS(state, decimal) {\n      state.decimals = decimal;\n    }\n  },\n  actions: {\n    SET_CORE_READY({ commit, state }) {\n      commit(\"SET_STATUS\", state.progress === 1 ? AppStatus.ready : AppStatus.synchronize);\n      commit(\"SET_CORE_READY\");\n      EnableDebugWindowOnCoreReady();\n    },\n    SET_SYNC_DONE({ commit }) {\n      commit(\"SET_SYNC_DONE\");\n    },\n    SET_SPLASH_READY({ commit }) {\n      commit(\"SET_SPLASH_READY\");\n    },\n    SET_STATUS({ commit }, status) {\n      commit(\"SET_STATUS\", status);\n    },\n    SET_THEME({ commit }, theme) {\n      commit(\"SET_THEME\", theme);\n    },\n    SET_UNITY_VERSION({ commit }, version) {\n      commit(\"SET_UNITY_VERSION\", version);\n    },\n    SET_RATE({ commit }, rate) {\n      commit(\"SET_RATE\", rate);\n    },\n    SET_ACTIVITY_INDICATOR({ commit }, activityIndicator) {\n      commit(\"SET_ACTIVITY_INDICATOR\", activityIndicator);\n    },\n    SET_LANGUAGE({ commit }, language) {\n      commit(\"SET_LANGUAGE\", language);\n    },\n    SET_DECIMALS({ commit }, decimal) {\n      commit(\"SET_DECIMALS\", decimal);\n    },\n    SET_WALLET_EXISTS({ commit }, walletExists) {\n      let status = walletExists ? AppStatus.synchronize : AppStatus.setup;\n      commit(\"SET_STATUS\", status);\n      commit(\"SET_WALLET_EXISTS\", walletExists);\n    },\n    SET_WALLET_VERSION({ commit }, version) {\n      commit(\"SET_WALLET_VERSION\", version);\n    }\n  }\n};\n\nexport default app;\n"
  },
  {
    "path": "src/frontend/lite/src/store/modules/index.js",
    "content": "import app from \"./app\";\nimport mining from \"./mining\";\nimport wallet from \"./wallet\";\n\nconst modules = { app, mining, wallet };\n\nexport default modules;\n"
  },
  {
    "path": "src/frontend/lite/src/store/modules/mining.js",
    "content": "const mining = {\n  namespaced: true,\n  state: {\n    active: false,\n    stats: null,\n    settings: {\n      memorySize: null,\n      threadCount: null,\n      arenaThreadCount: null\n    }\n  },\n  mutations: {\n    SET_ACTIVE(state, active) {\n      state.active = active;\n    },\n    SET_MEMORY_SIZE(state, memorySize) {\n      state.settings.memorySize = memorySize;\n    },\n    SET_STATS(state, stats) {\n      state.stats = stats;\n    },\n    SET_THREAD_COUNT(state, threadCount) {\n      state.settings.threadCount = threadCount;\n    },\n    SET_ARENA_THREAD_COUNT(state, arenaThreadCount) {\n      state.settings.arenaThreadCount = arenaThreadCount;\n    }\n  },\n  actions: {\n    SET_ACTIVE({ commit }, active) {\n      commit(\"SET_ACTIVE\", active);\n    },\n    SET_MEMORY_SIZE({ commit }, memorySize) {\n      commit(\"SET_MEMORY_SIZE\", memorySize);\n    },\n    SET_STATS({ commit }, stats) {\n      commit(\"SET_STATS\", stats);\n    },\n    SET_THREAD_COUNT({ commit }, threadCount) {\n      commit(\"SET_THREAD_COUNT\", threadCount);\n    },\n    SET_ARENA_THREAD_COUNT({ commit }, arenaThreadCount) {\n      commit(\"SET_ARENA_THREAD_COUNT\", arenaThreadCount);\n    }\n  }\n};\n\nexport default mining;\n"
  },
  {
    "path": "src/frontend/lite/src/store/modules/wallet.js",
    "content": "const wallet = {\n  namespaced: true,\n  state: {\n    accounts: [],\n    activeAccount: null,\n    balance: null,\n    mutations: null,\n    receiveAddress: null,\n    walletBalance: null,\n    walletPassword: null,\n    unlocked: false\n  },\n  mutations: {\n    SET_ACCOUNTS(state, accounts) {\n      state.accounts = accounts;\n    },\n    SET_ACTIVE_ACCOUNT(state, accountUUID) {\n      state.activeAccount = accountUUID;\n    },\n    SET_BALANCE(state, balance) {\n      state.balance = balance;\n    },\n    SET_MUTATIONS(state, mutations) {\n      state.mutations = mutations;\n    },\n    SET_RECEIVE_ADDRESS(state, receiveAddress) {\n      state.receiveAddress = receiveAddress;\n    },\n    SET_WALLET_BALANCE(state, walletBalance) {\n      state.walletBalance = walletBalance;\n    },\n    SET_WALLET_PASSWORD(state, password) {\n      state.walletPassword = password;\n    },\n    SET_UNLOCKED(state, unlocked) {\n      state.unlocked = unlocked;\n    },\n    SET_WALLET(state, payload) {\n      // batch update state properties from payload\n      for (const [key, value] of Object.entries(payload)) {\n        state[key] = value;\n      }\n    }\n  },\n  actions: {\n    SET_ACCOUNT_NAME({ state, commit }, payload) {\n      let accounts = [...state.accounts];\n      let account = accounts.find(x => x.UUID === payload.accountUUID);\n      account.label = payload.newAccountName;\n      commit(\"SET_ACCOUNTS\", accounts);\n    },\n    SET_ACCOUNTS({ commit }, accounts) {\n      commit(\"SET_ACCOUNTS\", accounts);\n    },\n    SET_ACTIVE_ACCOUNT({ commit }, accountUUID) {\n      // clear mutations and receive address\n      commit(\"SET_RECEIVE_ADDRESS\", { receiveAddress: \"\" });\n      commit(\"SET_ACTIVE_ACCOUNT\", accountUUID);\n      commit(\"SET_MUTATIONS\", { mutations: null });\n    },\n    SET_BALANCE({ commit }, new_balance) {\n      commit(\"SET_BALANCE\", new_balance);\n    },\n    SET_MUTATIONS({ commit }, mutations) {\n      commit(\"SET_MUTATIONS\", mutations);\n    },\n    SET_RECEIVE_ADDRESS({ commit }, receiveAddress) {\n      commit(\"SET_RECEIVE_ADDRESS\", receiveAddress);\n    },\n    SET_WALLET_BALANCE({ commit }, walletBalance) {\n      commit(\"SET_WALLET_BALANCE\", walletBalance);\n    },\n    SET_WALLET_PASSWORD({ commit }, password) {\n      commit(\"SET_WALLET_PASSWORD\", password);\n    },\n    SET_UNLOCKED({ commit }, unlocked) {\n      commit(\"SET_UNLOCKED\", unlocked);\n    },\n    SET_WALLET({ commit }, payload) {\n      commit(\"SET_WALLET\", payload);\n    }\n  },\n  getters: {\n    totalBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.availableIncludingLocked + balance.unconfirmedIncludingLocked + balance.immatureIncludingLocked;\n    },\n    lockedBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.totalLocked;\n    },\n    spendableBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.availableExcludingLocked;\n    },\n    pendingBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.unconfirmedExcludingLocked;\n    },\n    immatureBalance: state => {\n      let balance = state.walletBalance;\n      if (balance === undefined || balance === null) return null;\n      return balance.immatureIncludingLocked;\n    },\n    accounts: state => {\n      return state.accounts\n        .filter(x => x.state === \"Normal\")\n        .sort((a, b) => {\n          const labelA = a.label.toUpperCase();\n          const labelB = b.label.toUpperCase();\n\n          let comparison = 0;\n          if (labelA > labelB) {\n            comparison = 1;\n          } else if (labelA < labelB) {\n            comparison = -1;\n          }\n          return comparison;\n        });\n    },\n    account: state => {\n      return state.accounts.find(x => x.UUID === state.activeAccount);\n    }\n  }\n};\n\nexport default wallet;\n"
  },
  {
    "path": "src/frontend/lite/src/store/syncState.js",
    "content": "import { ipcMain, ipcRenderer } from \"electron\";\nimport cloneDeep from \"lodash.clonedeep\";\n\nexport default store => {\n  if (process.type === \"renderer\") {\n    // replace the renderer state by the main state\n    ipcRenderer.on(\"vuex-connected\", (event, state) => {\n      console.log(\"vuex-connected\");\n      let newState = cloneDeep(state);\n      store.replaceState(newState);\n    });\n    // send vuex-connect message to receive the main state\n    ipcRenderer.send(\"vuex-connect\");\n  } else {\n    // on vuex-connect send the current state to the renderer\n    ipcMain.on(\"vuex-connect\", event => {\n      console.log(\"vuex-connect\");\n      event.sender.send(\"vuex-connected\", store.state);\n    });\n  }\n};\n"
  },
  {
    "path": "src/frontend/lite/src/unity/Controllers.js",
    "content": "import { ipcRenderer as ipc } from \"electron-better-ipc\";\n\n/* inject:generated-code */\nclass LibraryController {\n  static async BuildInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.BuildInfoAsync\"));\n  }\n\n  static BuildInfo() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.BuildInfo\"));\n  }\n\n  static async InitWalletFromRecoveryPhraseAsync(phrase, password) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.InitWalletFromRecoveryPhraseAsync\", { phrase, password }));\n  }\n\n  static InitWalletFromRecoveryPhrase(phrase, password) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.InitWalletFromRecoveryPhrase\", phrase, password));\n  }\n\n  static async IsValidLinkURIAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidLinkURIAsync\", { phrase }));\n  }\n\n  static IsValidLinkURI(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidLinkURI\", phrase));\n  }\n\n  static async ReplaceWalletLinkedFromURIAsync(linked_uri, password) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ReplaceWalletLinkedFromURIAsync\", { linked_uri, password }));\n  }\n\n  static ReplaceWalletLinkedFromURI(linked_uri, password) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ReplaceWalletLinkedFromURI\", linked_uri, password));\n  }\n\n  static async EraseWalletSeedsAndAccountsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.EraseWalletSeedsAndAccountsAsync\"));\n  }\n\n  static EraseWalletSeedsAndAccounts() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.EraseWalletSeedsAndAccounts\"));\n  }\n\n  static async IsValidRecoveryPhraseAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidRecoveryPhraseAsync\", { phrase }));\n  }\n\n  static IsValidRecoveryPhrase(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidRecoveryPhrase\", phrase));\n  }\n\n  static async GenerateRecoveryMnemonicAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GenerateRecoveryMnemonicAsync\"));\n  }\n\n  static GenerateRecoveryMnemonic() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GenerateRecoveryMnemonic\"));\n  }\n\n  static async GenerateGenesisKeysAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GenerateGenesisKeysAsync\"));\n  }\n\n  static GenerateGenesisKeys() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GenerateGenesisKeys\"));\n  }\n\n  static async ComposeRecoveryPhraseAsync(mnemonic, birthTime) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ComposeRecoveryPhraseAsync\", { mnemonic, birthTime }));\n  }\n\n  static ComposeRecoveryPhrase(mnemonic, birthTime) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ComposeRecoveryPhrase\", mnemonic, birthTime));\n  }\n\n  static async TerminateUnityLibAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.TerminateUnityLibAsync\"));\n  }\n\n  static TerminateUnityLib() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.TerminateUnityLib\"));\n  }\n\n  static async QRImageFromStringAsync(qr_string, width_hint) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.QRImageFromStringAsync\", { qr_string, width_hint }));\n  }\n\n  static QRImageFromString(qr_string, width_hint) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.QRImageFromString\", qr_string, width_hint));\n  }\n\n  static async GetReceiveAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetReceiveAddressAsync\"));\n  }\n\n  static GetReceiveAddress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetReceiveAddress\"));\n  }\n\n  static async GetRecoveryPhraseAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetRecoveryPhraseAsync\"));\n  }\n\n  static GetRecoveryPhrase() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetRecoveryPhrase\"));\n  }\n\n  static async IsMnemonicWalletAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsMnemonicWalletAsync\"));\n  }\n\n  static IsMnemonicWallet() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsMnemonicWallet\"));\n  }\n\n  static async IsMnemonicCorrectAsync(phrase) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsMnemonicCorrectAsync\", { phrase }));\n  }\n\n  static IsMnemonicCorrect(phrase) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsMnemonicCorrect\", phrase));\n  }\n\n  static async GetMnemonicDictionaryAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetMnemonicDictionaryAsync\"));\n  }\n\n  static GetMnemonicDictionary() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetMnemonicDictionary\"));\n  }\n\n  static async UnlockWalletAsync(password, timeout_in_seconds) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.UnlockWalletAsync\", { password, timeout_in_seconds }));\n  }\n\n  static UnlockWallet(password, timeout_in_seconds) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.UnlockWallet\", password, timeout_in_seconds));\n  }\n\n  static async LockWalletAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.LockWalletAsync\"));\n  }\n\n  static LockWallet() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.LockWallet\"));\n  }\n\n  static async GetWalletLockStatusAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.GetWalletLockStatusAsync\"));\n  }\n\n  static GetWalletLockStatus() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.GetWalletLockStatus\"));\n  }\n\n  static async ChangePasswordAsync(oldPassword, newPassword) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ChangePasswordAsync\", { oldPassword, newPassword }));\n  }\n\n  static ChangePassword(oldPassword, newPassword) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ChangePassword\", oldPassword, newPassword));\n  }\n\n  static async DoRescanAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.DoRescanAsync\"));\n  }\n\n  static DoRescan() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.DoRescan\"));\n  }\n\n  static async IsValidRecipientAsync(request) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidRecipientAsync\", { request }));\n  }\n\n  static IsValidRecipient(request) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidRecipient\", request));\n  }\n\n  static async IsValidNativeAddressAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidNativeAddressAsync\", { address }));\n  }\n\n  static IsValidNativeAddress(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidNativeAddress\", address));\n  }\n\n  static async IsValidBitcoinAddressAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.IsValidBitcoinAddressAsync\", { address }));\n  }\n\n  static IsValidBitcoinAddress(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.IsValidBitcoinAddress\", address));\n  }\n\n  static async FeeForRecipientAsync(request) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.feeForRecipientAsync\", { request }));\n  }\n\n  static FeeForRecipient(request) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.feeForRecipient\", request));\n  }\n\n  static async PerformPaymentToRecipientAsync(request, substract_fee) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.performPaymentToRecipientAsync\", { request, substract_fee }));\n  }\n\n  static PerformPaymentToRecipient(request, substract_fee) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.performPaymentToRecipient\", request, substract_fee));\n  }\n\n  static async GetTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getTransactionAsync\", { txHash }));\n  }\n\n  static GetTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getTransaction\", txHash));\n  }\n\n  static async ResendTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.resendTransactionAsync\", { txHash }));\n  }\n\n  static ResendTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.resendTransaction\", txHash));\n  }\n\n  static async GetAddressBookRecordsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getAddressBookRecordsAsync\"));\n  }\n\n  static GetAddressBookRecords() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getAddressBookRecords\"));\n  }\n\n  static async AddAddressBookRecordAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.addAddressBookRecordAsync\", { address }));\n  }\n\n  static AddAddressBookRecord(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.addAddressBookRecord\", address));\n  }\n\n  static async DeleteAddressBookRecordAsync(address) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.deleteAddressBookRecordAsync\", { address }));\n  }\n\n  static DeleteAddressBookRecord(address) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.deleteAddressBookRecord\", address));\n  }\n\n  static async ResetUnifiedProgressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.ResetUnifiedProgressAsync\"));\n  }\n\n  static ResetUnifiedProgress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.ResetUnifiedProgress\"));\n  }\n\n  static async GetLastSPVBlockInfosAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getLastSPVBlockInfosAsync\"));\n  }\n\n  static GetLastSPVBlockInfos() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getLastSPVBlockInfos\"));\n  }\n\n  static async GetUnifiedProgressAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getUnifiedProgressAsync\"));\n  }\n\n  static GetUnifiedProgress() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getUnifiedProgress\"));\n  }\n\n  static async GetMonitoringStatsAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getMonitoringStatsAsync\"));\n  }\n\n  static GetMonitoringStats() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getMonitoringStats\"));\n  }\n\n  static async RegisterMonitorListenerAsync(listener) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.RegisterMonitorListenerAsync\", { listener }));\n  }\n\n  static RegisterMonitorListener(listener) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.RegisterMonitorListener\", listener));\n  }\n\n  static async UnregisterMonitorListenerAsync(listener) {\n    return handleError(await ipc.callMain(\"NJSILibraryController.UnregisterMonitorListenerAsync\", { listener }));\n  }\n\n  static UnregisterMonitorListener(listener) {\n    return handleError(ipc.sendSync(\"NJSILibraryController.UnregisterMonitorListener\", listener));\n  }\n\n  static async GetClientInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSILibraryController.getClientInfoAsync\"));\n  }\n\n  static GetClientInfo() {\n    return handleError(ipc.sendSync(\"NJSILibraryController.getClientInfo\"));\n  }\n}\n\nclass WalletController {\n  static async HaveUnconfirmedFundsAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.HaveUnconfirmedFundsAsync\"));\n  }\n\n  static HaveUnconfirmedFunds() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.HaveUnconfirmedFunds\"));\n  }\n\n  static async GetBalanceSimpleAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetBalanceSimpleAsync\"));\n  }\n\n  static GetBalanceSimple() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetBalanceSimple\"));\n  }\n\n  static async GetBalanceAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetBalanceAsync\"));\n  }\n\n  static GetBalance() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetBalance\"));\n  }\n\n  static async AbandonTransactionAsync(txHash) {\n    return handleError(await ipc.callMain(\"NJSIWalletController.AbandonTransactionAsync\", { txHash }));\n  }\n\n  static AbandonTransaction(txHash) {\n    return handleError(ipc.sendSync(\"NJSIWalletController.AbandonTransaction\", txHash));\n  }\n\n  static async GetUUIDAsync() {\n    return handleError(await ipc.callMain(\"NJSIWalletController.GetUUIDAsync\"));\n  }\n\n  static GetUUID() {\n    return handleError(ipc.sendSync(\"NJSIWalletController.GetUUID\"));\n  }\n}\n\nclass RpcController {\n  static async ExecuteAsync(command) {\n    return handleError(await ipc.callMain(\"NJSIRpcController.ExecuteAsync\", { command }));\n  }\n\n  static Execute(command) {\n    return handleError(ipc.sendSync(\"NJSIRpcController.Execute\", command));\n  }\n  static async GetAutocompleteListAsync() {\n    return handleError(await ipc.callMain(\"NJSIRpcController.getAutocompleteListAsync\"));\n  }\n\n  static GetAutocompleteList() {\n    return handleError(ipc.sendSync(\"NJSIRpcController.getAutocompleteList\"));\n  }\n}\n\nclass P2pNetworkController {\n  static async DisableNetworkAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.disableNetworkAsync\"));\n  }\n\n  static DisableNetwork() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.disableNetwork\"));\n  }\n\n  static async EnableNetworkAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.enableNetworkAsync\"));\n  }\n\n  static EnableNetwork() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.enableNetwork\"));\n  }\n\n  static async GetPeerInfoAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.getPeerInfoAsync\"));\n  }\n\n  static GetPeerInfo() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.getPeerInfo\"));\n  }\n\n  static async ListBannedPeersAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.listBannedPeersAsync\"));\n  }\n\n  static ListBannedPeers() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.listBannedPeers\"));\n  }\n\n  static async BanPeerAsync(address, banTimeInSeconds) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.banPeerAsync\", { address, banTimeInSeconds }));\n  }\n\n  static BanPeer(address, banTimeInSeconds) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.banPeer\", address, banTimeInSeconds));\n  }\n\n  static async UnbanPeerAsync(address) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.unbanPeerAsync\", { address }));\n  }\n\n  static UnbanPeer(address) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.unbanPeer\", address));\n  }\n\n  static async DisconnectPeerAsync(nodeid) {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.disconnectPeerAsync\", { nodeid }));\n  }\n\n  static DisconnectPeer(nodeid) {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.disconnectPeer\", nodeid));\n  }\n\n  static async ClearBannedAsync() {\n    return handleError(await ipc.callMain(\"NJSIP2pNetworkController.ClearBannedAsync\"));\n  }\n\n  static ClearBanned() {\n    return handleError(ipc.sendSync(\"NJSIP2pNetworkController.ClearBanned\"));\n  }\n}\n\nclass AccountsController {\n  static async ListAccountsAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.listAccountsAsync\"));\n  }\n\n  static ListAccounts() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.listAccounts\"));\n  }\n\n  static async SetActiveAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.setActiveAccountAsync\", { accountUUID }));\n  }\n\n  static SetActiveAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.setActiveAccount\", accountUUID));\n  }\n\n  static async GetActiveAccountAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getActiveAccountAsync\"));\n  }\n\n  static GetActiveAccount() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getActiveAccount\"));\n  }\n\n  static async CreateAccountAsync(accountName, accountType) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.createAccountAsync\", { accountName, accountType }));\n  }\n\n  static CreateAccount(accountName, accountType) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.createAccount\", accountName, accountType));\n  }\n\n  static async GetAccountNameAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountNameAsync\", { accountUUID }));\n  }\n\n  static GetAccountName(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountName\", accountUUID));\n  }\n\n  static async RenameAccountAsync(accountUUID, newAccountName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.renameAccountAsync\", { accountUUID, newAccountName }));\n  }\n\n  static RenameAccount(accountUUID, newAccountName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.renameAccount\", accountUUID, newAccountName));\n  }\n\n  static async DeleteAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.deleteAccountAsync\", { accountUUID }));\n  }\n\n  static DeleteAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.deleteAccount\", accountUUID));\n  }\n\n  static async PurgeAccountAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.purgeAccountAsync\", { accountUUID }));\n  }\n\n  static PurgeAccount(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.purgeAccount\", accountUUID));\n  }\n\n  static async GetAccountLinkURIAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountLinkURIAsync\", { accountUUID }));\n  }\n\n  static GetAccountLinkURI(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountLinkURI\", accountUUID));\n  }\n\n  static async GetWitnessKeyURIAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getWitnessKeyURIAsync\", { accountUUID }));\n  }\n\n  static GetWitnessKeyURI(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getWitnessKeyURI\", accountUUID));\n  }\n\n  static async CreateAccountFromWitnessKeyURIAsync(witnessKeyURI, newAccountName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.createAccountFromWitnessKeyURIAsync\", { witnessKeyURI, newAccountName }));\n  }\n\n  static CreateAccountFromWitnessKeyURI(witnessKeyURI, newAccountName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.createAccountFromWitnessKeyURI\", witnessKeyURI, newAccountName));\n  }\n\n  static async GetReceiveAddressAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getReceiveAddressAsync\", { accountUUID }));\n  }\n\n  static GetReceiveAddress(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getReceiveAddress\", accountUUID));\n  }\n\n  static async GetTransactionHistoryAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getTransactionHistoryAsync\", { accountUUID }));\n  }\n\n  static GetTransactionHistory(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getTransactionHistory\", accountUUID));\n  }\n\n  static async GetMutationHistoryAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getMutationHistoryAsync\", { accountUUID }));\n  }\n\n  static GetMutationHistory(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getMutationHistory\", accountUUID));\n  }\n\n  static async GetActiveAccountBalanceAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getActiveAccountBalanceAsync\"));\n  }\n\n  static GetActiveAccountBalance() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getActiveAccountBalance\"));\n  }\n\n  static async GetAccountBalanceAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAccountBalanceAsync\", { accountUUID }));\n  }\n\n  static GetAccountBalance(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAccountBalance\", accountUUID));\n  }\n\n  static async GetAllAccountBalancesAsync() {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.getAllAccountBalancesAsync\"));\n  }\n\n  static GetAllAccountBalances() {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.getAllAccountBalances\"));\n  }\n\n  static async AddAccountLinkAsync(accountUUID, serviceName, data) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.addAccountLinkAsync\", { accountUUID, serviceName, data }));\n  }\n\n  static AddAccountLink(accountUUID, serviceName, data) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.addAccountLink\", accountUUID, serviceName, data));\n  }\n\n  static async RemoveAccountLinkAsync(accountUUID, serviceName) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.removeAccountLinkAsync\", { accountUUID, serviceName }));\n  }\n\n  static RemoveAccountLink(accountUUID, serviceName) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.removeAccountLink\", accountUUID, serviceName));\n  }\n\n  static async ListAccountLinksAsync(accountUUID) {\n    return handleError(await ipc.callMain(\"NJSIAccountsController.listAccountLinksAsync\", { accountUUID }));\n  }\n\n  static ListAccountLinks(accountUUID) {\n    return handleError(ipc.sendSync(\"NJSIAccountsController.listAccountLinks\", accountUUID));\n  }\n}\n\nclass WitnessController {\n  static async GetNetworkLimitsAsync() {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getNetworkLimitsAsync\"));\n  }\n\n  static GetNetworkLimits() {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getNetworkLimits\"));\n  }\n\n  static async GetEstimatedWeightAsync(amount_to_lock, lock_period_in_blocks) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getEstimatedWeightAsync\", { amount_to_lock, lock_period_in_blocks }));\n  }\n\n  static GetEstimatedWeight(amount_to_lock, lock_period_in_blocks) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getEstimatedWeight\", amount_to_lock, lock_period_in_blocks));\n  }\n\n  static async FundWitnessAccountAsync(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) {\n    return handleError(\n      await ipc.callMain(\"NJSIWitnessController.fundWitnessAccountAsync\", {\n        funding_account_UUID,\n        witness_account_UUID,\n        funding_amount,\n        requestedLockPeriodInBlocks\n      })\n    );\n  }\n\n  static FundWitnessAccount(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) {\n    return handleError(\n      ipc.sendSync(\"NJSIWitnessController.fundWitnessAccount\", funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks)\n    );\n  }\n\n  static async RenewWitnessAccountAsync(funding_account_UUID, witness_account_UUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.renewWitnessAccountAsync\", { funding_account_UUID, witness_account_UUID }));\n  }\n\n  static RenewWitnessAccount(funding_account_UUID, witness_account_UUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.renewWitnessAccount\", funding_account_UUID, witness_account_UUID));\n  }\n\n  static async GetAccountWitnessStatisticsAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getAccountWitnessStatisticsAsync\", { witnessAccountUUID }));\n  }\n\n  static GetAccountWitnessStatistics(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getAccountWitnessStatistics\", witnessAccountUUID));\n  }\n\n  static async SetAccountCompoundingAsync(witnessAccountUUID, percent_to_compount) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.setAccountCompoundingAsync\", { witnessAccountUUID, percent_to_compount }));\n  }\n\n  static SetAccountCompounding(witnessAccountUUID, percent_to_compount) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.setAccountCompounding\", witnessAccountUUID, percent_to_compount));\n  }\n\n  static async IsAccountCompoundingAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.isAccountCompoundingAsync\", { witnessAccountUUID }));\n  }\n\n  static IsAccountCompounding(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.isAccountCompounding\", witnessAccountUUID));\n  }\n\n  static async GetWitnessAddressAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getWitnessAddressAsync\", { witnessAccountUUID }));\n  }\n\n  static GetWitnessAddress(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getWitnessAddress\", witnessAccountUUID));\n  }\n\n  static async GetOptimalWitnessDistributionAsync(amount, durationInBlocks, totalNetworkWeight) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getOptimalWitnessDistributionAsync\", { amount, durationInBlocks, totalNetworkWeight }));\n  }\n\n  static GetOptimalWitnessDistribution(amount, durationInBlocks, totalNetworkWeight) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getOptimalWitnessDistribution\", amount, durationInBlocks, totalNetworkWeight));\n  }\n\n  static async GetOptimalWitnessDistributionForAccountAsync(witnessAccountUUID) {\n    return handleError(await ipc.callMain(\"NJSIWitnessController.getOptimalWitnessDistributionForAccountAsync\", { witnessAccountUUID }));\n  }\n\n  static GetOptimalWitnessDistributionForAccount(witnessAccountUUID) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.getOptimalWitnessDistributionForAccount\", witnessAccountUUID));\n  }\n\n  static async OptimiseWitnessAccountAsync(witnessAccountUUID, fundingAccountUUID, optimalDistribution) {\n    return handleError(\n      await ipc.callMain(\"NJSIWitnessController.optimiseWitnessAccountAsync\", { witnessAccountUUID, fundingAccountUUID, optimalDistribution })\n    );\n  }\n\n  static OptimiseWitnessAccount(witnessAccountUUID, fundingAccountUUID, optimalDistribution) {\n    return handleError(ipc.sendSync(\"NJSIWitnessController.optimiseWitnessAccount\", witnessAccountUUID, fundingAccountUUID, optimalDistribution));\n  }\n}\n\nclass GenerationController {\n  static async StartGenerationAsync(numThreads, numArenaThreads, memoryLimit) {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.startGenerationAsync\", { numThreads, numArenaThreads, memoryLimit }));\n  }\n\n  static StartGeneration(numThreads, numArenaThreads, memoryLimit) {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.startGeneration\", numThreads, numArenaThreads, memoryLimit));\n  }\n\n  static async StopGenerationAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.stopGenerationAsync\"));\n  }\n\n  static StopGeneration() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.stopGeneration\"));\n  }\n\n  static async GetGenerationAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getGenerationAddressAsync\"));\n  }\n\n  static GetGenerationAddress() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getGenerationAddress\"));\n  }\n\n  static async GetGenerationOverrideAddressAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getGenerationOverrideAddressAsync\"));\n  }\n\n  static GetGenerationOverrideAddress() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getGenerationOverrideAddress\"));\n  }\n\n  static async SetGenerationOverrideAddressAsync(overrideAddress) {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.setGenerationOverrideAddressAsync\", { overrideAddress }));\n  }\n\n  static SetGenerationOverrideAddress(overrideAddress) {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.setGenerationOverrideAddress\", overrideAddress));\n  }\n\n  static async GetAvailableCoresAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getAvailableCoresAsync\"));\n  }\n\n  static GetAvailableCores() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getAvailableCores\"));\n  }\n\n  static async GetMinimumMemoryAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getMinimumMemoryAsync\"));\n  }\n\n  static GetMinimumMemory() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getMinimumMemory\"));\n  }\n\n  static async GetMaximumMemoryAsync() {\n    return handleError(await ipc.callMain(\"NJSIGenerationController.getMaximumMemoryAsync\"));\n  }\n\n  static GetMaximumMemory() {\n    return handleError(ipc.sendSync(\"NJSIGenerationController.getMaximumMemory\"));\n  }\n}\n\nexport { LibraryController, WalletController, RpcController, P2pNetworkController, AccountsController, WitnessController, GenerationController };\n/* inject:generated-code */\n\nclass BackendUtilities {\n  static GetBuySessionUrl() {\n    return handleError(ipc.sendSync(\"BackendUtilities.GetBuySessionUrl\"));\n  }\n  static GetSellSessionUrl() {\n    return handleError(ipc.sendSync(\"BackendUtilities.GetSellSessionUrl\"));\n  }\n  static holdinAPIActions(witnessKey, action, data) {\n    return handleError(ipc.sendSync(\"BackendUtilities.holdinAPIActions\", { witnessKey, action, data }));\n  }\n}\n\nexport { BackendUtilities };\n\nfunction handleError(response) {\n  if (response.error) {\n    // todo: maybe keep a list of notifications which can be shown\n    console.error(response.error);\n    return null;\n  }\n  return response.result;\n}\n"
  },
  {
    "path": "src/frontend/lite/src/unity/LibUnity.js",
    "content": "import { app } from \"electron\";\nimport { ipcMain as ipc } from \"electron-better-ipc\";\nimport fs from \"fs\";\nimport axios from \"axios\";\nimport store from \"../store\";\nimport { apiKey } from \"../../holdinAPI\";\n\nimport libUnity from \"native-ext-loader!./lib_unity.node\";\n\n// Needed to get index/offset of staticfiltercp file inside asar\nimport disk from \"asar/lib/disk\";\nimport path from \"path\";\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\n\nclass LibUnity {\n  constructor(options) {\n    this.initialized = false;\n    this.isTerminated = false;\n    this.isCoreReady = false;\n    this.isMainWindowReady = false;\n\n    this.options = {\n      useTestnet: process.env.UNITY_USE_TESTNET ? process.env.UNITY_USE_TESTNET : false,\n      extraArgs: process.env.UNITY_EXTRA_ARGS ? process.env.UNITY_EXTRA_ARGS : \"\",\n      ...options\n    };\n\n    this.libraryController = new libUnity.NJSILibraryController();\n    this.libraryListener = new libUnity.NJSILibraryListener();\n\n    this.walletController = new libUnity.NJSIWalletController();\n    this.walletListener = new libUnity.NJSIWalletListener();\n\n    this.accountsController = new libUnity.NJSIAccountsController();\n    this.accountsListener = new libUnity.NJSIAccountsListener();\n\n    this.rpcController = new libUnity.NJSIRpcController();\n\n    this.p2pNetworkController = new libUnity.NJSIP2pNetworkController();\n\n    let buildInfo = this.libraryController.BuildInfo();\n\n    store.dispatch(\"app/SET_UNITY_VERSION\", buildInfo.substr(1, buildInfo.indexOf(\"-\") - 1));\n  }\n\n  SetMainWindowReady() {\n    if (this.isMainWindowReady === true) return; // set core state once\n    this.isMainWindowReady = true;\n    this._setStateWhenCoreAndMainWindowReady();\n  }\n\n  Initialize() {\n    if (this.initialized) return;\n\n    this.initialized = true;\n\n    this._registerIpcHandlers();\n    this._registerSignalHandlers();\n    this._startUnityLib();\n  }\n\n  TerminateUnityLib() {\n    if (this.libraryController === null || this.isTerminated) return;\n    console.log(`terminating unity lib`);\n    // TODO:\n    // Maybe the call to terminate comes before the core is ready.\n    // Then it's better to wait for the coreReady signal and then call TerminateUnityLib\n    this.libraryController.TerminateUnityLib();\n  }\n\n  _initializeWalletController() {\n    console.log(\"_initializeWalletController\");\n\n    this.walletListener.notifyBalanceChange = function (new_balance) {\n      console.log(`walletListener.notifyBalanceChange`);\n      store.dispatch(\"wallet/SET_WALLET_BALANCE\", new_balance);\n    };\n\n    this.walletListener.notifyWalletUnlocked = function () {\n      console.log(\"receive: notifyWalletUnlocked\");\n      store.dispatch(\"wallet/SET_UNLOCKED\", true);\n    };\n\n    this.walletListener.notifyWalletLocked = function () {\n      console.log(\"receive: notifyWalletLocked\");\n      store.dispatch(\"wallet/SET_UNLOCKED\", false);\n    };\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    this.walletListener.notifyCoreWantsUnlock = function (reason) {\n      console.log(\"receive: notifyCoreWantsUnlock\", reason);\n      // TODO: show unlock dialog with reason (localized?)\n    };\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    this.walletListener.notifyCoreInfo = function (type, caption, message) {\n      console.log(\"receive: notifyCoreInfo\", type, caption, message);\n      // TODO: dispatch message event. add message to queue??\n    };\n\n    this.walletController.setListener(this.walletListener);\n  }\n\n  _updateAccounts(dispatch = true) {\n    let accounts = this.accountsController.listAccounts();\n    let accountBalances = this.accountsController.getAllAccountBalances();\n\n    Object.keys(accountBalances).forEach(key => {\n      let currentAccount = accounts.find(x => x.UUID === key);\n      let currentBalance = accountBalances[key];\n\n      currentAccount.balance = currentBalance.availableIncludingLocked + currentBalance.immatureIncludingLocked;\n      currentAccount.allBalances = currentBalance;\n\n      // make sure spendable is always 0 or more\n      currentAccount.spendable = Math.max(currentBalance.availableExcludingLocked, 0);\n    });\n\n    if (dispatch) {\n      store.dispatch(\"wallet/SET_ACCOUNTS\", accounts);\n    }\n    return accounts;\n  }\n\n  _initializeAccountsController() {\n    console.log(\"_initializeAccountsController\");\n\n    let self = this;\n    let libraryController = this.libraryController;\n\n    this.accountsListener.onAccountNameChanged = function (accountUUID, newAccountName) {\n      store.dispatch(\"wallet/SET_ACCOUNT_NAME\", {\n        accountUUID,\n        newAccountName\n      });\n    };\n\n    this.accountsListener.onActiveAccountChanged = function (accountUUID) {\n      // combine all properties into one payload object\n      const receiveAddress = libraryController.GetReceiveAddress();\n      const mutations = libraryController.getMutationHistory();\n      const payload = {\n        activeAccount: accountUUID,\n        receiveAddress,\n        mutations\n      };\n\n      // and then dispatch one event to update alle properties at once\n      store.dispatch(\"wallet/SET_WALLET\", payload);\n    };\n\n    this.accountsListener.onAccountAdded = function () {\n      self._updateAccounts();\n    };\n\n    this.accountsListener.onAccountDeleted = function () {\n      self._updateAccounts();\n    };\n\n    this.accountsController.setListener(this.accountsListener);\n  }\n\n  _initializeGenerationController() {\n    console.log(\"_initializeGenerationController\");\n\n    this.generationListener.onGenerationStarted = function () {\n      console.log(\"GENERATION STARTED\");\n      store.dispatch(\"mining/SET_ACTIVE\", true);\n    };\n\n    this.generationListener.onGenerationStopped = function () {\n      console.log(\"GENERATION STOPPED\");\n\n      store.dispatch(\"mining/SET_ACTIVE\", false);\n      store.dispatch(\"mining/SET_STATS\", null);\n    };\n\n    this.generationListener.onStatsUpdated = function (\n      hashesPerSecond,\n      hashesPerSecondUnit,\n      rollingHashesPerSecond,\n      rollingHashesPerSecondUnit,\n      bestHashesPerSecond,\n      bestHashesPerSecondUnit,\n      arenaSetupTime\n    ) {\n      store.dispatch(\"mining/SET_STATS\", {\n        hashesPerSecond: `${hashesPerSecond.toFixed(2)}${hashesPerSecondUnit}`,\n        rollingHashesPerSecond: `${rollingHashesPerSecond.toFixed(2)}${rollingHashesPerSecondUnit}`,\n        bestHashesPerSecond: `${bestHashesPerSecond.toFixed(2)}${bestHashesPerSecondUnit}`,\n        arenaSetupTime: arenaSetupTime\n      });\n    };\n\n    this.generationController.setListener(this.generationListener);\n  }\n\n  _startUnityLib() {\n    if (!fs.existsSync(this.options.walletPath)) {\n      console.log(`create wallet folder ${this.options.walletPath}`);\n      fs.mkdirSync(this.options.walletPath, { recursive: true });\n    } else {\n      console.log(`wallet folder ${this.options.walletPath} already exists`);\n    }\n\n    var staticFilterPath = \"\";\n    var staticFilterOffset = 0;\n    var staticFilterLength = 0;\n    if (isDevelopment) {\n      staticFilterPath = path.join(app.getAppPath(), \"../../../data/staticfiltercp\");\n    } else {\n      staticFilterPath = app.getAppPath();\n      if (staticFilterPath.endsWith(\".asar\")) {\n        const filesystem = disk.readFilesystemSync(staticFilterPath);\n        const fileInfo = filesystem.getFile(\"staticfiltercp\", true);\n        staticFilterOffset = parseInt(fileInfo.offset) + parseInt(8) + parseInt(filesystem.headerSize);\n        staticFilterLength = parseInt(fileInfo.size);\n      } else {\n        staticFilterPath = path.join(staticFilterPath, \"staticfiltercp\");\n      }\n    }\n    var spvMode = true;\n\n    console.log(`init unity lib threaded`);\n    this.libraryController.InitUnityLibThreaded(\n      this.options.walletPath,\n      staticFilterPath,\n      staticFilterOffset,\n      staticFilterLength,\n      this.options.useTestnet,\n      spvMode,\n      this.libraryListener,\n      this.options.extraArgs\n    );\n  }\n\n  _setStateWhenCoreAndMainWindowReady() {\n    if (!this.isCoreReady || !this.isMainWindowReady)\n      return console.log(`isCoreReady: ${this.isCoreReady}, isMainWindowReady: ${this.isMainWindowReady} -> return`);\n    console.log(\"_setStateWhenCoreAndMainWindowReady: start\");\n\n    // code to update the store has been moved to notifySyncDone event handler because that's when we need the data\n\n    // note: for now also dispatch separate \"core ready\" event because it is still needed to enable debug dialog\n    store.dispatch(\"app/SET_CORE_READY\");\n    console.log(\"_setStateWhenCoreAndMainWindowReady: end\");\n  }\n\n  _registerSignalHandlers() {\n    let self = this;\n    let libraryListener = this.libraryListener;\n    let libraryController = this.libraryController;\n\n    let walletController = this.walletController;\n    let accountsController = this.accountsController;\n\n    libraryListener.notifyCoreReady = function () {\n      console.log(\"received: notifyCoreReady\");\n\n      self._initializeWalletController();\n      self._initializeAccountsController();\n\n      self.isCoreReady = true;\n      self._setStateWhenCoreAndMainWindowReady();\n    };\n\n    libraryListener.notifySyncDone = function () {\n      console.log(\"received: notifySyncDone\");\n\n      console.log(\"get the wallet balance\");\n      const walletBalance = walletController.GetBalance();\n      console.log(\"get the accounts\");\n      const accounts = self._updateAccounts(false);\n      console.log(\"get the active account\");\n      const activeAccount = accountsController.getActiveAccount();\n      console.log(\"get the receive address\");\n      const receiveAddress = libraryController.GetReceiveAddress();\n      console.log(\"get the mutations\");\n      const mutations = libraryController.getMutationHistory();\n\n      console.log(\"combine data and dispatch SET_WALLET to update the store\");\n      const payload = {\n        accounts,\n        walletBalance,\n        activeAccount,\n        receiveAddress,\n        mutations\n      };\n\n      // and then dispatch one event to update alle properties at once\n      store.dispatch(\"wallet/SET_WALLET\", payload);\n\n      // dispatch SET_SYNC_DONE to notify wallet is synced and ready for use\n      store.dispatch(\"app/SET_SYNC_DONE\");\n    };\n\n    // Note: turned this listener off, only enable it when needed in debug mode\n    // libraryListener.logPrint = function(message) {\n    //   console.log(\"unity_core: \" + message);\n    // };\n\n    libraryListener.notifyBalanceChange = function (new_balance) {\n      console.log(\"received: notifyBalanceChange\");\n      store.dispatch(\"wallet/SET_BALANCE\", new_balance);\n    };\n\n    libraryListener.notifyNewMutation = function (/*mutation, self_committed*/) {\n      console.log(\"received: notifyNewMutation\");\n      store.dispatch(\"wallet/SET_MUTATIONS\", libraryController.getMutationHistory());\n      store.dispatch(\"wallet/SET_RECEIVE_ADDRESS\", libraryController.GetReceiveAddress());\n\n      self._updateAccounts();\n    };\n\n    libraryListener.notifyUpdatedTransaction = function (/*transaction*/) {\n      console.log(\"received: notifyUpdatedTransaction\");\n      store.dispatch(\"wallet/SET_MUTATIONS\", libraryController.getMutationHistory());\n    };\n\n    libraryListener.notifyInitWithExistingWallet = function () {\n      console.log(\"received: notifyInitWithExistingWallet\");\n      store.dispatch(\"app/SET_WALLET_EXISTS\", true);\n    };\n\n    libraryListener.notifyInitWithoutExistingWallet = function () {\n      console.log(\"received: notifyInitWithoutExistingWallet\");\n      self.newRecoveryPhrase = libraryController.GenerateRecoveryMnemonic();\n      store.dispatch(\"app/SET_WALLET_EXISTS\", false);\n    };\n\n    libraryListener.notifyShutdown = function () {\n      //NB! It is important to set the libraryListener to null here as this is the last thing the core lib is waiting on for clean exit; once we set this to null we are free to quit the app\n      libraryListener = null;\n      console.log(\"received: notifyShutdown\");\n      self.isTerminated = true;\n\n      // We call this inside a timeout because if we don't we get a crash on macOS; its not yet 100% clear why but for now its better to just avoid the crash until we can debug further\n      // TODO: Investigate this further\n      setTimeout(function () {\n        app.quit();\n      }, 1000);\n    };\n  }\n\n  _registerIpcHandlers() {\n    // ipc for rpc controller\n    ipc.answerRenderer(\"NJSIRpcController.ExecuteAsync\", async data => {\n      let rpcListener = new libUnity.NJSIRpcListener();\n\n      return new Promise(resolve => {\n        rpcListener.onSuccess = (filteredCommand, result) => {\n          console.log(`RPC success: ${filteredCommand}`);\n          resolve({\n            result: {\n              success: true,\n              data: result,\n              command: filteredCommand\n            }\n          });\n        };\n\n        rpcListener.onError = (filteredCommand, error) => {\n          console.error(`RPC error: ${filteredCommand}`);\n          resolve({\n            result: {\n              success: false,\n              data: error,\n              command: filteredCommand\n            }\n          });\n        };\n\n        this.rpcController.execute(data.command, rpcListener);\n      });\n    });\n\n    ipc.on(\"NJSIRpcController.Execute\", (event, command) => {\n      let rpcListener = new libUnity.NJSIRpcListener();\n\n      rpcListener.onSuccess = (filteredCommand, result) => {\n        console.log(`RPC success: ${filteredCommand}`);\n        event.returnValue = {\n          result: {\n            success: true,\n            data: result,\n            command: filteredCommand\n          }\n        };\n      };\n\n      rpcListener.onError = (filteredCommand, error) => {\n        console.error(`RPC error: ${filteredCommand}`);\n        event.returnValue = {\n          result: {\n            success: false,\n            data: error,\n            command: filteredCommand\n          }\n        };\n      };\n\n      this.rpcController.execute(command, rpcListener);\n    });\n\n    /* inject:generated-code */\n    // Register NJSILibraryController ipc handlers\n    ipc.answerRenderer(\"NJSILibraryController.BuildInfoAsync\", async () => {\n      console.log(`IPC: libraryController.BuildInfoAsync()`);\n      try {\n        let result = this.libraryController.BuildInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.BuildInfo\", event => {\n      console.log(`IPC: libraryController.BuildInfo()`);\n      try {\n        let result = this.libraryController.BuildInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.InitWalletFromRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.InitWalletFromRecoveryPhraseAsync(${data.phrase}, ${data.password})`);\n      try {\n        let result = this.libraryController.InitWalletFromRecoveryPhrase(data.phrase, data.password);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.InitWalletFromRecoveryPhrase\", (event, phrase, password) => {\n      console.log(`IPC: libraryController.InitWalletFromRecoveryPhrase(${phrase}, ${password})`);\n      try {\n        let result = this.libraryController.InitWalletFromRecoveryPhrase(phrase, password);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidLinkURIAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidLinkURIAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsValidLinkURI(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidLinkURI\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsValidLinkURI(${phrase})`);\n      try {\n        let result = this.libraryController.IsValidLinkURI(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ReplaceWalletLinkedFromURIAsync\", async data => {\n      console.log(`IPC: libraryController.ReplaceWalletLinkedFromURIAsync(${data.linked_uri}, ${data.password})`);\n      try {\n        let result = this.libraryController.ReplaceWalletLinkedFromURI(data.linked_uri, data.password);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ReplaceWalletLinkedFromURI\", (event, linked_uri, password) => {\n      console.log(`IPC: libraryController.ReplaceWalletLinkedFromURI(${linked_uri}, ${password})`);\n      try {\n        let result = this.libraryController.ReplaceWalletLinkedFromURI(linked_uri, password);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.EraseWalletSeedsAndAccountsAsync\", async () => {\n      console.log(`IPC: libraryController.EraseWalletSeedsAndAccountsAsync()`);\n      try {\n        let result = this.libraryController.EraseWalletSeedsAndAccounts();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.EraseWalletSeedsAndAccounts\", event => {\n      console.log(`IPC: libraryController.EraseWalletSeedsAndAccounts()`);\n      try {\n        let result = this.libraryController.EraseWalletSeedsAndAccounts();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidRecoveryPhraseAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsValidRecoveryPhrase(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidRecoveryPhrase\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsValidRecoveryPhrase(${phrase})`);\n      try {\n        let result = this.libraryController.IsValidRecoveryPhrase(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GenerateRecoveryMnemonicAsync\", async () => {\n      console.log(`IPC: libraryController.GenerateRecoveryMnemonicAsync()`);\n      try {\n        let result = this.libraryController.GenerateRecoveryMnemonic();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GenerateRecoveryMnemonic\", event => {\n      console.log(`IPC: libraryController.GenerateRecoveryMnemonic()`);\n      try {\n        let result = this.libraryController.GenerateRecoveryMnemonic();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GenerateGenesisKeysAsync\", async () => {\n      console.log(`IPC: libraryController.GenerateGenesisKeysAsync()`);\n      try {\n        let result = this.libraryController.GenerateGenesisKeys();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GenerateGenesisKeys\", event => {\n      console.log(`IPC: libraryController.GenerateGenesisKeys()`);\n      try {\n        let result = this.libraryController.GenerateGenesisKeys();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ComposeRecoveryPhraseAsync\", async data => {\n      console.log(`IPC: libraryController.ComposeRecoveryPhraseAsync(${data.mnemonic}, ${data.birthTime})`);\n      try {\n        let result = this.libraryController.ComposeRecoveryPhrase(data.mnemonic, data.birthTime);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ComposeRecoveryPhrase\", (event, mnemonic, birthTime) => {\n      console.log(`IPC: libraryController.ComposeRecoveryPhrase(${mnemonic}, ${birthTime})`);\n      try {\n        let result = this.libraryController.ComposeRecoveryPhrase(mnemonic, birthTime);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.TerminateUnityLibAsync\", async () => {\n      console.log(`IPC: libraryController.TerminateUnityLibAsync()`);\n      try {\n        let result = this.libraryController.TerminateUnityLib();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.TerminateUnityLib\", event => {\n      console.log(`IPC: libraryController.TerminateUnityLib()`);\n      try {\n        let result = this.libraryController.TerminateUnityLib();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.QRImageFromStringAsync\", async data => {\n      console.log(`IPC: libraryController.QRImageFromStringAsync(${data.qr_string}, ${data.width_hint})`);\n      try {\n        let result = this.libraryController.QRImageFromString(data.qr_string, data.width_hint);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.QRImageFromString\", (event, qr_string, width_hint) => {\n      console.log(`IPC: libraryController.QRImageFromString(${qr_string}, ${width_hint})`);\n      try {\n        let result = this.libraryController.QRImageFromString(qr_string, width_hint);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetReceiveAddressAsync\", async () => {\n      console.log(`IPC: libraryController.GetReceiveAddressAsync()`);\n      try {\n        let result = this.libraryController.GetReceiveAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetReceiveAddress\", event => {\n      console.log(`IPC: libraryController.GetReceiveAddress()`);\n      try {\n        let result = this.libraryController.GetReceiveAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetRecoveryPhraseAsync\", async () => {\n      console.log(`IPC: libraryController.GetRecoveryPhraseAsync()`);\n      try {\n        let result = this.libraryController.GetRecoveryPhrase();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetRecoveryPhrase\", event => {\n      console.log(`IPC: libraryController.GetRecoveryPhrase()`);\n      try {\n        let result = this.libraryController.GetRecoveryPhrase();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsMnemonicWalletAsync\", async () => {\n      console.log(`IPC: libraryController.IsMnemonicWalletAsync()`);\n      try {\n        let result = this.libraryController.IsMnemonicWallet();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsMnemonicWallet\", event => {\n      console.log(`IPC: libraryController.IsMnemonicWallet()`);\n      try {\n        let result = this.libraryController.IsMnemonicWallet();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsMnemonicCorrectAsync\", async data => {\n      console.log(`IPC: libraryController.IsMnemonicCorrectAsync(${data.phrase})`);\n      try {\n        let result = this.libraryController.IsMnemonicCorrect(data.phrase);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsMnemonicCorrect\", (event, phrase) => {\n      console.log(`IPC: libraryController.IsMnemonicCorrect(${phrase})`);\n      try {\n        let result = this.libraryController.IsMnemonicCorrect(phrase);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetMnemonicDictionaryAsync\", async () => {\n      console.log(`IPC: libraryController.GetMnemonicDictionaryAsync()`);\n      try {\n        let result = this.libraryController.GetMnemonicDictionary();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetMnemonicDictionary\", event => {\n      console.log(`IPC: libraryController.GetMnemonicDictionary()`);\n      try {\n        let result = this.libraryController.GetMnemonicDictionary();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.UnlockWalletAsync\", async data => {\n      console.log(`IPC: libraryController.UnlockWalletAsync(${data.password}, ${data.timeout_in_seconds})`);\n      try {\n        let result = this.libraryController.UnlockWallet(data.password, data.timeout_in_seconds);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.UnlockWallet\", (event, password, timeout_in_seconds) => {\n      console.log(`IPC: libraryController.UnlockWallet(${password}, ${timeout_in_seconds})`);\n      try {\n        let result = this.libraryController.UnlockWallet(password, timeout_in_seconds);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.LockWalletAsync\", async () => {\n      console.log(`IPC: libraryController.LockWalletAsync()`);\n      try {\n        let result = this.libraryController.LockWallet();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.LockWallet\", event => {\n      console.log(`IPC: libraryController.LockWallet()`);\n      try {\n        let result = this.libraryController.LockWallet();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.GetWalletLockStatusAsync\", async () => {\n      console.log(`IPC: libraryController.GetWalletLockStatusAsync()`);\n      try {\n        let result = this.libraryController.GetWalletLockStatus();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.GetWalletLockStatus\", event => {\n      console.log(`IPC: libraryController.GetWalletLockStatus()`);\n      try {\n        let result = this.libraryController.GetWalletLockStatus();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ChangePasswordAsync\", async data => {\n      console.log(`IPC: libraryController.ChangePasswordAsync(${data.oldPassword}, ${data.newPassword})`);\n      try {\n        let result = this.libraryController.ChangePassword(data.oldPassword, data.newPassword);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ChangePassword\", (event, oldPassword, newPassword) => {\n      console.log(`IPC: libraryController.ChangePassword(${oldPassword}, ${newPassword})`);\n      try {\n        let result = this.libraryController.ChangePassword(oldPassword, newPassword);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.DoRescanAsync\", async () => {\n      console.log(`IPC: libraryController.DoRescanAsync()`);\n      try {\n        let result = this.libraryController.DoRescan();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.DoRescan\", event => {\n      console.log(`IPC: libraryController.DoRescan()`);\n      try {\n        let result = this.libraryController.DoRescan();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidRecipientAsync(${data.request})`);\n      try {\n        let result = this.libraryController.IsValidRecipient(data.request);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidRecipient\", (event, request) => {\n      console.log(`IPC: libraryController.IsValidRecipient(${request})`);\n      try {\n        let result = this.libraryController.IsValidRecipient(request);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidNativeAddressAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidNativeAddressAsync(${data.address})`);\n      try {\n        let result = this.libraryController.IsValidNativeAddress(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidNativeAddress\", (event, address) => {\n      console.log(`IPC: libraryController.IsValidNativeAddress(${address})`);\n      try {\n        let result = this.libraryController.IsValidNativeAddress(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.IsValidBitcoinAddressAsync\", async data => {\n      console.log(`IPC: libraryController.IsValidBitcoinAddressAsync(${data.address})`);\n      try {\n        let result = this.libraryController.IsValidBitcoinAddress(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.IsValidBitcoinAddress\", (event, address) => {\n      console.log(`IPC: libraryController.IsValidBitcoinAddress(${address})`);\n      try {\n        let result = this.libraryController.IsValidBitcoinAddress(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.feeForRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.feeForRecipientAsync(${data.request})`);\n      try {\n        let result = this.libraryController.feeForRecipient(data.request);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.feeForRecipient\", (event, request) => {\n      console.log(`IPC: libraryController.feeForRecipient(${request})`);\n      try {\n        let result = this.libraryController.feeForRecipient(request);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.performPaymentToRecipientAsync\", async data => {\n      console.log(`IPC: libraryController.performPaymentToRecipientAsync(${data.request}, ${data.substract_fee})`);\n      try {\n        let result = this.libraryController.performPaymentToRecipient(data.request, data.substract_fee);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.performPaymentToRecipient\", (event, request, substract_fee) => {\n      console.log(`IPC: libraryController.performPaymentToRecipient(${request}, ${substract_fee})`);\n      try {\n        let result = this.libraryController.performPaymentToRecipient(request, substract_fee);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getTransactionAsync\", async data => {\n      console.log(`IPC: libraryController.getTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.libraryController.getTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getTransaction\", (event, txHash) => {\n      console.log(`IPC: libraryController.getTransaction(${txHash})`);\n      try {\n        let result = this.libraryController.getTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.resendTransactionAsync\", async data => {\n      console.log(`IPC: libraryController.resendTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.libraryController.resendTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.resendTransaction\", (event, txHash) => {\n      console.log(`IPC: libraryController.resendTransaction(${txHash})`);\n      try {\n        let result = this.libraryController.resendTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getAddressBookRecordsAsync\", async () => {\n      console.log(`IPC: libraryController.getAddressBookRecordsAsync()`);\n      try {\n        let result = this.libraryController.getAddressBookRecords();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getAddressBookRecords\", event => {\n      console.log(`IPC: libraryController.getAddressBookRecords()`);\n      try {\n        let result = this.libraryController.getAddressBookRecords();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.addAddressBookRecordAsync\", async data => {\n      console.log(`IPC: libraryController.addAddressBookRecordAsync(${data.address})`);\n      try {\n        let result = this.libraryController.addAddressBookRecord(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.addAddressBookRecord\", (event, address) => {\n      console.log(`IPC: libraryController.addAddressBookRecord(${address})`);\n      try {\n        let result = this.libraryController.addAddressBookRecord(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.deleteAddressBookRecordAsync\", async data => {\n      console.log(`IPC: libraryController.deleteAddressBookRecordAsync(${data.address})`);\n      try {\n        let result = this.libraryController.deleteAddressBookRecord(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.deleteAddressBookRecord\", (event, address) => {\n      console.log(`IPC: libraryController.deleteAddressBookRecord(${address})`);\n      try {\n        let result = this.libraryController.deleteAddressBookRecord(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.ResetUnifiedProgressAsync\", async () => {\n      console.log(`IPC: libraryController.ResetUnifiedProgressAsync()`);\n      try {\n        let result = this.libraryController.ResetUnifiedProgress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.ResetUnifiedProgress\", event => {\n      console.log(`IPC: libraryController.ResetUnifiedProgress()`);\n      try {\n        let result = this.libraryController.ResetUnifiedProgress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getLastSPVBlockInfosAsync\", async () => {\n      console.log(`IPC: libraryController.getLastSPVBlockInfosAsync()`);\n      try {\n        let result = this.libraryController.getLastSPVBlockInfos();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getLastSPVBlockInfos\", event => {\n      console.log(`IPC: libraryController.getLastSPVBlockInfos()`);\n      try {\n        let result = this.libraryController.getLastSPVBlockInfos();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getUnifiedProgressAsync\", async () => {\n      console.log(`IPC: libraryController.getUnifiedProgressAsync()`);\n      try {\n        let result = this.libraryController.getUnifiedProgress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getUnifiedProgress\", event => {\n      console.log(`IPC: libraryController.getUnifiedProgress()`);\n      try {\n        let result = this.libraryController.getUnifiedProgress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getMonitoringStatsAsync\", async () => {\n      console.log(`IPC: libraryController.getMonitoringStatsAsync()`);\n      try {\n        let result = this.libraryController.getMonitoringStats();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getMonitoringStats\", event => {\n      console.log(`IPC: libraryController.getMonitoringStats()`);\n      try {\n        let result = this.libraryController.getMonitoringStats();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.RegisterMonitorListenerAsync\", async data => {\n      console.log(`IPC: libraryController.RegisterMonitorListenerAsync(${data.listener})`);\n      try {\n        let result = this.libraryController.RegisterMonitorListener(data.listener);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.RegisterMonitorListener\", (event, listener) => {\n      console.log(`IPC: libraryController.RegisterMonitorListener(${listener})`);\n      try {\n        let result = this.libraryController.RegisterMonitorListener(listener);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.UnregisterMonitorListenerAsync\", async data => {\n      console.log(`IPC: libraryController.UnregisterMonitorListenerAsync(${data.listener})`);\n      try {\n        let result = this.libraryController.UnregisterMonitorListener(data.listener);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.UnregisterMonitorListener\", (event, listener) => {\n      console.log(`IPC: libraryController.UnregisterMonitorListener(${listener})`);\n      try {\n        let result = this.libraryController.UnregisterMonitorListener(listener);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSILibraryController.getClientInfoAsync\", async () => {\n      console.log(`IPC: libraryController.getClientInfoAsync()`);\n      try {\n        let result = this.libraryController.getClientInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSILibraryController.getClientInfo\", event => {\n      console.log(`IPC: libraryController.getClientInfo()`);\n      try {\n        let result = this.libraryController.getClientInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIWalletController ipc handlers\n    ipc.answerRenderer(\"NJSIWalletController.HaveUnconfirmedFundsAsync\", async () => {\n      console.log(`IPC: walletController.HaveUnconfirmedFundsAsync()`);\n      try {\n        let result = this.walletController.HaveUnconfirmedFunds();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.HaveUnconfirmedFunds\", event => {\n      console.log(`IPC: walletController.HaveUnconfirmedFunds()`);\n      try {\n        let result = this.walletController.HaveUnconfirmedFunds();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetBalanceSimpleAsync\", async () => {\n      console.log(`IPC: walletController.GetBalanceSimpleAsync()`);\n      try {\n        let result = this.walletController.GetBalanceSimple();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetBalanceSimple\", event => {\n      console.log(`IPC: walletController.GetBalanceSimple()`);\n      try {\n        let result = this.walletController.GetBalanceSimple();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetBalanceAsync\", async () => {\n      console.log(`IPC: walletController.GetBalanceAsync()`);\n      try {\n        let result = this.walletController.GetBalance();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetBalance\", event => {\n      console.log(`IPC: walletController.GetBalance()`);\n      try {\n        let result = this.walletController.GetBalance();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.AbandonTransactionAsync\", async data => {\n      console.log(`IPC: walletController.AbandonTransactionAsync(${data.txHash})`);\n      try {\n        let result = this.walletController.AbandonTransaction(data.txHash);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.AbandonTransaction\", (event, txHash) => {\n      console.log(`IPC: walletController.AbandonTransaction(${txHash})`);\n      try {\n        let result = this.walletController.AbandonTransaction(txHash);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWalletController.GetUUIDAsync\", async () => {\n      console.log(`IPC: walletController.GetUUIDAsync()`);\n      try {\n        let result = this.walletController.GetUUID();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWalletController.GetUUID\", event => {\n      console.log(`IPC: walletController.GetUUID()`);\n      try {\n        let result = this.walletController.GetUUID();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIRpcController ipc handlers\n    ipc.answerRenderer(\"NJSIRpcController.getAutocompleteListAsync\", async () => {\n      console.log(`IPC: rpcController.getAutocompleteListAsync()`);\n      try {\n        let result = this.rpcController.getAutocompleteList();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIRpcController.getAutocompleteList\", event => {\n      console.log(`IPC: rpcController.getAutocompleteList()`);\n      try {\n        let result = this.rpcController.getAutocompleteList();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIP2pNetworkController ipc handlers\n    ipc.answerRenderer(\"NJSIP2pNetworkController.disableNetworkAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.disableNetworkAsync()`);\n      try {\n        let result = this.p2pNetworkController.disableNetwork();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.disableNetwork\", event => {\n      console.log(`IPC: p2pNetworkController.disableNetwork()`);\n      try {\n        let result = this.p2pNetworkController.disableNetwork();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.enableNetworkAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.enableNetworkAsync()`);\n      try {\n        let result = this.p2pNetworkController.enableNetwork();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.enableNetwork\", event => {\n      console.log(`IPC: p2pNetworkController.enableNetwork()`);\n      try {\n        let result = this.p2pNetworkController.enableNetwork();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.getPeerInfoAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.getPeerInfoAsync()`);\n      try {\n        let result = this.p2pNetworkController.getPeerInfo();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.getPeerInfo\", event => {\n      console.log(`IPC: p2pNetworkController.getPeerInfo()`);\n      try {\n        let result = this.p2pNetworkController.getPeerInfo();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.listBannedPeersAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.listBannedPeersAsync()`);\n      try {\n        let result = this.p2pNetworkController.listBannedPeers();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.listBannedPeers\", event => {\n      console.log(`IPC: p2pNetworkController.listBannedPeers()`);\n      try {\n        let result = this.p2pNetworkController.listBannedPeers();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.banPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.banPeerAsync(${data.address}, ${data.banTimeInSeconds})`);\n      try {\n        let result = this.p2pNetworkController.banPeer(data.address, data.banTimeInSeconds);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.banPeer\", (event, address, banTimeInSeconds) => {\n      console.log(`IPC: p2pNetworkController.banPeer(${address}, ${banTimeInSeconds})`);\n      try {\n        let result = this.p2pNetworkController.banPeer(address, banTimeInSeconds);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.unbanPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.unbanPeerAsync(${data.address})`);\n      try {\n        let result = this.p2pNetworkController.unbanPeer(data.address);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.unbanPeer\", (event, address) => {\n      console.log(`IPC: p2pNetworkController.unbanPeer(${address})`);\n      try {\n        let result = this.p2pNetworkController.unbanPeer(address);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.disconnectPeerAsync\", async data => {\n      console.log(`IPC: p2pNetworkController.disconnectPeerAsync(${data.nodeid})`);\n      try {\n        let result = this.p2pNetworkController.disconnectPeer(data.nodeid);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.disconnectPeer\", (event, nodeid) => {\n      console.log(`IPC: p2pNetworkController.disconnectPeer(${nodeid})`);\n      try {\n        let result = this.p2pNetworkController.disconnectPeer(nodeid);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIP2pNetworkController.ClearBannedAsync\", async () => {\n      console.log(`IPC: p2pNetworkController.ClearBannedAsync()`);\n      try {\n        let result = this.p2pNetworkController.ClearBanned();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIP2pNetworkController.ClearBanned\", event => {\n      console.log(`IPC: p2pNetworkController.ClearBanned()`);\n      try {\n        let result = this.p2pNetworkController.ClearBanned();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIAccountsController ipc handlers\n    ipc.answerRenderer(\"NJSIAccountsController.listAccountsAsync\", async () => {\n      console.log(`IPC: accountsController.listAccountsAsync()`);\n      try {\n        let result = this.accountsController.listAccounts();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.listAccounts\", event => {\n      console.log(`IPC: accountsController.listAccounts()`);\n      try {\n        let result = this.accountsController.listAccounts();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.setActiveAccountAsync\", async data => {\n      console.log(`IPC: accountsController.setActiveAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.setActiveAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.setActiveAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.setActiveAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.setActiveAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getActiveAccountAsync\", async () => {\n      console.log(`IPC: accountsController.getActiveAccountAsync()`);\n      try {\n        let result = this.accountsController.getActiveAccount();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getActiveAccount\", event => {\n      console.log(`IPC: accountsController.getActiveAccount()`);\n      try {\n        let result = this.accountsController.getActiveAccount();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.createAccountAsync\", async data => {\n      console.log(`IPC: accountsController.createAccountAsync(${data.accountName}, ${data.accountType})`);\n      try {\n        let result = this.accountsController.createAccount(data.accountName, data.accountType);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.createAccount\", (event, accountName, accountType) => {\n      console.log(`IPC: accountsController.createAccount(${accountName}, ${accountType})`);\n      try {\n        let result = this.accountsController.createAccount(accountName, accountType);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountNameAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountNameAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountName(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountName\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountName(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountName(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.renameAccountAsync\", async data => {\n      console.log(`IPC: accountsController.renameAccountAsync(${data.accountUUID}, ${data.newAccountName})`);\n      try {\n        let result = this.accountsController.renameAccount(data.accountUUID, data.newAccountName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.renameAccount\", (event, accountUUID, newAccountName) => {\n      console.log(`IPC: accountsController.renameAccount(${accountUUID}, ${newAccountName})`);\n      try {\n        let result = this.accountsController.renameAccount(accountUUID, newAccountName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.deleteAccountAsync\", async data => {\n      console.log(`IPC: accountsController.deleteAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.deleteAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.deleteAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.deleteAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.deleteAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.purgeAccountAsync\", async data => {\n      console.log(`IPC: accountsController.purgeAccountAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.purgeAccount(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.purgeAccount\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.purgeAccount(${accountUUID})`);\n      try {\n        let result = this.accountsController.purgeAccount(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountLinkURIAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountLinkURIAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountLinkURI(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountLinkURI\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountLinkURI(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountLinkURI(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getWitnessKeyURIAsync\", async data => {\n      console.log(`IPC: accountsController.getWitnessKeyURIAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getWitnessKeyURI(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getWitnessKeyURI\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getWitnessKeyURI(${accountUUID})`);\n      try {\n        let result = this.accountsController.getWitnessKeyURI(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.createAccountFromWitnessKeyURIAsync\", async data => {\n      console.log(`IPC: accountsController.createAccountFromWitnessKeyURIAsync(${data.witnessKeyURI}, ${data.newAccountName})`);\n      try {\n        let result = this.accountsController.createAccountFromWitnessKeyURI(data.witnessKeyURI, data.newAccountName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.createAccountFromWitnessKeyURI\", (event, witnessKeyURI, newAccountName) => {\n      console.log(`IPC: accountsController.createAccountFromWitnessKeyURI(${witnessKeyURI}, ${newAccountName})`);\n      try {\n        let result = this.accountsController.createAccountFromWitnessKeyURI(witnessKeyURI, newAccountName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getReceiveAddressAsync\", async data => {\n      console.log(`IPC: accountsController.getReceiveAddressAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getReceiveAddress(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getReceiveAddress\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getReceiveAddress(${accountUUID})`);\n      try {\n        let result = this.accountsController.getReceiveAddress(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getTransactionHistoryAsync\", async data => {\n      console.log(`IPC: accountsController.getTransactionHistoryAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getTransactionHistory(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getTransactionHistory\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getTransactionHistory(${accountUUID})`);\n      try {\n        let result = this.accountsController.getTransactionHistory(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getMutationHistoryAsync\", async data => {\n      console.log(`IPC: accountsController.getMutationHistoryAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getMutationHistory(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getMutationHistory\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getMutationHistory(${accountUUID})`);\n      try {\n        let result = this.accountsController.getMutationHistory(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getActiveAccountBalanceAsync\", async () => {\n      console.log(`IPC: accountsController.getActiveAccountBalanceAsync()`);\n      try {\n        let result = this.accountsController.getActiveAccountBalance();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getActiveAccountBalance\", event => {\n      console.log(`IPC: accountsController.getActiveAccountBalance()`);\n      try {\n        let result = this.accountsController.getActiveAccountBalance();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAccountBalanceAsync\", async data => {\n      console.log(`IPC: accountsController.getAccountBalanceAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountBalance(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAccountBalance\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.getAccountBalance(${accountUUID})`);\n      try {\n        let result = this.accountsController.getAccountBalance(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.getAllAccountBalancesAsync\", async () => {\n      console.log(`IPC: accountsController.getAllAccountBalancesAsync()`);\n      try {\n        let result = this.accountsController.getAllAccountBalances();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.getAllAccountBalances\", event => {\n      console.log(`IPC: accountsController.getAllAccountBalances()`);\n      try {\n        let result = this.accountsController.getAllAccountBalances();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.addAccountLinkAsync\", async data => {\n      console.log(`IPC: accountsController.addAccountLinkAsync(${data.accountUUID}, ${data.serviceName}, ${data.data})`);\n      try {\n        let result = this.accountsController.addAccountLink(data.accountUUID, data.serviceName, data.data);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.addAccountLink\", (event, accountUUID, serviceName, data) => {\n      console.log(`IPC: accountsController.addAccountLink(${accountUUID}, ${serviceName}, ${data})`);\n      try {\n        let result = this.accountsController.addAccountLink(accountUUID, serviceName, data);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.removeAccountLinkAsync\", async data => {\n      console.log(`IPC: accountsController.removeAccountLinkAsync(${data.accountUUID}, ${data.serviceName})`);\n      try {\n        let result = this.accountsController.removeAccountLink(data.accountUUID, data.serviceName);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.removeAccountLink\", (event, accountUUID, serviceName) => {\n      console.log(`IPC: accountsController.removeAccountLink(${accountUUID}, ${serviceName})`);\n      try {\n        let result = this.accountsController.removeAccountLink(accountUUID, serviceName);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIAccountsController.listAccountLinksAsync\", async data => {\n      console.log(`IPC: accountsController.listAccountLinksAsync(${data.accountUUID})`);\n      try {\n        let result = this.accountsController.listAccountLinks(data.accountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIAccountsController.listAccountLinks\", (event, accountUUID) => {\n      console.log(`IPC: accountsController.listAccountLinks(${accountUUID})`);\n      try {\n        let result = this.accountsController.listAccountLinks(accountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIWitnessController ipc handlers\n    ipc.answerRenderer(\"NJSIWitnessController.getNetworkLimitsAsync\", async () => {\n      console.log(`IPC: witnessController.getNetworkLimitsAsync()`);\n      try {\n        let result = this.witnessController.getNetworkLimits();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getNetworkLimits\", event => {\n      console.log(`IPC: witnessController.getNetworkLimits()`);\n      try {\n        let result = this.witnessController.getNetworkLimits();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getEstimatedWeightAsync\", async data => {\n      console.log(`IPC: witnessController.getEstimatedWeightAsync(${data.amount_to_lock}, ${data.lock_period_in_blocks})`);\n      try {\n        let result = this.witnessController.getEstimatedWeight(data.amount_to_lock, data.lock_period_in_blocks);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getEstimatedWeight\", (event, amount_to_lock, lock_period_in_blocks) => {\n      console.log(`IPC: witnessController.getEstimatedWeight(${amount_to_lock}, ${lock_period_in_blocks})`);\n      try {\n        let result = this.witnessController.getEstimatedWeight(amount_to_lock, lock_period_in_blocks);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.fundWitnessAccountAsync\", async data => {\n      console.log(\n        `IPC: witnessController.fundWitnessAccountAsync(${data.funding_account_UUID}, ${data.witness_account_UUID}, ${data.funding_amount}, ${data.requestedLockPeriodInBlocks})`\n      );\n      try {\n        let result = this.witnessController.fundWitnessAccount(\n          data.funding_account_UUID,\n          data.witness_account_UUID,\n          data.funding_amount,\n          data.requestedLockPeriodInBlocks\n        );\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.fundWitnessAccount\", (event, funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks) => {\n      console.log(\n        `IPC: witnessController.fundWitnessAccount(${funding_account_UUID}, ${witness_account_UUID}, ${funding_amount}, ${requestedLockPeriodInBlocks})`\n      );\n      try {\n        let result = this.witnessController.fundWitnessAccount(funding_account_UUID, witness_account_UUID, funding_amount, requestedLockPeriodInBlocks);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.renewWitnessAccountAsync\", async data => {\n      console.log(`IPC: witnessController.renewWitnessAccountAsync(${data.funding_account_UUID}, ${data.witness_account_UUID})`);\n      try {\n        let result = this.witnessController.renewWitnessAccount(data.funding_account_UUID, data.witness_account_UUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.renewWitnessAccount\", (event, funding_account_UUID, witness_account_UUID) => {\n      console.log(`IPC: witnessController.renewWitnessAccount(${funding_account_UUID}, ${witness_account_UUID})`);\n      try {\n        let result = this.witnessController.renewWitnessAccount(funding_account_UUID, witness_account_UUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getAccountWitnessStatisticsAsync\", async data => {\n      console.log(`IPC: witnessController.getAccountWitnessStatisticsAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getAccountWitnessStatistics(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getAccountWitnessStatistics\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getAccountWitnessStatistics(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getAccountWitnessStatistics(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.setAccountCompoundingAsync\", async data => {\n      console.log(`IPC: witnessController.setAccountCompoundingAsync(${data.witnessAccountUUID}, ${data.percent_to_compount})`);\n      try {\n        let result = this.witnessController.setAccountCompounding(data.witnessAccountUUID, data.percent_to_compount);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.setAccountCompounding\", (event, witnessAccountUUID, percent_to_compount) => {\n      console.log(`IPC: witnessController.setAccountCompounding(${witnessAccountUUID}, ${percent_to_compount})`);\n      try {\n        let result = this.witnessController.setAccountCompounding(witnessAccountUUID, percent_to_compount);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.isAccountCompoundingAsync\", async data => {\n      console.log(`IPC: witnessController.isAccountCompoundingAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.isAccountCompounding(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.isAccountCompounding\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.isAccountCompounding(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.isAccountCompounding(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getWitnessAddressAsync\", async data => {\n      console.log(`IPC: witnessController.getWitnessAddressAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getWitnessAddress(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getWitnessAddress\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getWitnessAddress(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getWitnessAddress(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getOptimalWitnessDistributionAsync\", async data => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionAsync(${data.amount}, ${data.durationInBlocks}, ${data.totalNetworkWeight})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistribution(data.amount, data.durationInBlocks, data.totalNetworkWeight);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getOptimalWitnessDistribution\", (event, amount, durationInBlocks, totalNetworkWeight) => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistribution(${amount}, ${durationInBlocks}, ${totalNetworkWeight})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistribution(amount, durationInBlocks, totalNetworkWeight);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.getOptimalWitnessDistributionForAccountAsync\", async data => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionForAccountAsync(${data.witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistributionForAccount(data.witnessAccountUUID);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.getOptimalWitnessDistributionForAccount\", (event, witnessAccountUUID) => {\n      console.log(`IPC: witnessController.getOptimalWitnessDistributionForAccount(${witnessAccountUUID})`);\n      try {\n        let result = this.witnessController.getOptimalWitnessDistributionForAccount(witnessAccountUUID);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIWitnessController.optimiseWitnessAccountAsync\", async data => {\n      console.log(`IPC: witnessController.optimiseWitnessAccountAsync(${data.witnessAccountUUID}, ${data.fundingAccountUUID}, ${data.optimalDistribution})`);\n      try {\n        let result = this.witnessController.optimiseWitnessAccount(data.witnessAccountUUID, data.fundingAccountUUID, data.optimalDistribution);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIWitnessController.optimiseWitnessAccount\", (event, witnessAccountUUID, fundingAccountUUID, optimalDistribution) => {\n      console.log(`IPC: witnessController.optimiseWitnessAccount(${witnessAccountUUID}, ${fundingAccountUUID}, ${optimalDistribution})`);\n      try {\n        let result = this.witnessController.optimiseWitnessAccount(witnessAccountUUID, fundingAccountUUID, optimalDistribution);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    // Register NJSIGenerationController ipc handlers\n    ipc.answerRenderer(\"NJSIGenerationController.startGenerationAsync\", async data => {\n      console.log(`IPC: generationController.startGenerationAsync(${data.numThreads}, ${data.numArenaThreads}, ${data.memoryLimit})`);\n      try {\n        let result = this.generationController.startGeneration(data.numThreads, data.numArenaThreads, data.memoryLimit);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.startGeneration\", (event, numThreads, numArenaThreads, memoryLimit) => {\n      console.log(`IPC: generationController.startGeneration(${numThreads}, ${numArenaThreads}, ${memoryLimit})`);\n      try {\n        let result = this.generationController.startGeneration(numThreads, numArenaThreads, memoryLimit);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.stopGenerationAsync\", async () => {\n      console.log(`IPC: generationController.stopGenerationAsync()`);\n      try {\n        let result = this.generationController.stopGeneration();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.stopGeneration\", event => {\n      console.log(`IPC: generationController.stopGeneration()`);\n      try {\n        let result = this.generationController.stopGeneration();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getGenerationAddressAsync\", async () => {\n      console.log(`IPC: generationController.getGenerationAddressAsync()`);\n      try {\n        let result = this.generationController.getGenerationAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getGenerationAddress\", event => {\n      console.log(`IPC: generationController.getGenerationAddress()`);\n      try {\n        let result = this.generationController.getGenerationAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getGenerationOverrideAddressAsync\", async () => {\n      console.log(`IPC: generationController.getGenerationOverrideAddressAsync()`);\n      try {\n        let result = this.generationController.getGenerationOverrideAddress();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getGenerationOverrideAddress\", event => {\n      console.log(`IPC: generationController.getGenerationOverrideAddress()`);\n      try {\n        let result = this.generationController.getGenerationOverrideAddress();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.setGenerationOverrideAddressAsync\", async data => {\n      console.log(`IPC: generationController.setGenerationOverrideAddressAsync(${data.overrideAddress})`);\n      try {\n        let result = this.generationController.setGenerationOverrideAddress(data.overrideAddress);\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.setGenerationOverrideAddress\", (event, overrideAddress) => {\n      console.log(`IPC: generationController.setGenerationOverrideAddress(${overrideAddress})`);\n      try {\n        let result = this.generationController.setGenerationOverrideAddress(overrideAddress);\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getAvailableCoresAsync\", async () => {\n      console.log(`IPC: generationController.getAvailableCoresAsync()`);\n      try {\n        let result = this.generationController.getAvailableCores();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getAvailableCores\", event => {\n      console.log(`IPC: generationController.getAvailableCores()`);\n      try {\n        let result = this.generationController.getAvailableCores();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getMinimumMemoryAsync\", async () => {\n      console.log(`IPC: generationController.getMinimumMemoryAsync()`);\n      try {\n        let result = this.generationController.getMinimumMemory();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getMinimumMemory\", event => {\n      console.log(`IPC: generationController.getMinimumMemory()`);\n      try {\n        let result = this.generationController.getMinimumMemory();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n\n    ipc.answerRenderer(\"NJSIGenerationController.getMaximumMemoryAsync\", async () => {\n      console.log(`IPC: generationController.getMaximumMemoryAsync()`);\n      try {\n        let result = this.generationController.getMaximumMemory();\n        return {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        return handleError(e);\n      }\n    });\n\n    ipc.on(\"NJSIGenerationController.getMaximumMemory\", event => {\n      console.log(`IPC: generationController.getMaximumMemory()`);\n      try {\n        let result = this.generationController.getMaximumMemory();\n        event.returnValue = {\n          success: true,\n          result: result\n        };\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n    /* inject:generated-code */\n\n    ipc.on(\"BackendUtilities.GetBuySessionUrl\", async event => {\n      console.log(`IPC: BackendUtilities.GetBuySessionUrl()`);\n      event.returnValue = {\n        success: true,\n        result: \"https://munt.org/buy\"\n      };\n    });\n\n    ipc.on(\"BackendUtilities.GetSellSessionUrl\", async event => {\n      console.log(`IPC: BackendUtilities.GetSellSessionUrl()`);\n      event.returnValue = {\n        success: true,\n        result: \"https://munt.org/sell\"\n      };\n    });\n\n    ipc.on(\"BackendUtilities.holdinAPIActions\", async (event, params) => {\n      console.log(`IPC: BackendUtilities.holdinAPIActions()`);\n\n      try {\n        let data = {};\n\n        if (params.action == \"payoutaddress\") {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action,\n            payoutaddress: params.data\n          });\n        } else if (params.action == \"distribution\") {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action,\n            compoundpercentage: params.data\n          });\n        } else {\n          data = JSON.stringify({\n            witnesskey: params.witnessKey,\n            action: params.action\n          });\n        }\n\n        var config = {\n          method: \"post\",\n          url: \"https://api.holdin.com/api/v1/\",\n          headers: {\n            Authorization: apiKey,\n            \"Content-Type\": \"application/json\"\n          },\n          data: data\n        };\n\n        axios(config)\n          .then(function (response) {\n            event.returnValue = {\n              success: response.data.status_code === 200,\n              result: response.data\n            };\n          })\n          .catch(function (error) {\n            event.returnValue = handleError(error);\n          });\n      } catch (e) {\n        event.returnValue = handleError(e);\n      }\n    });\n  }\n}\n\nfunction handleError(error) {\n  console.error(error);\n  return {\n    error: error,\n    result: null\n  };\n}\n\nexport default LibUnity;\n"
  },
  {
    "path": "src/frontend/lite/src/util.js",
    "content": "import store from \"./store\";\nimport { Parser } from \"@json2csv/plainjs\";\n\nexport function formatMoneyForDisplay(monetaryAmount, isFiat = false, minimumAmountOfDecimals = 0) {\n  // default use 2 decimals;\n  let decimals = 2;\n\n  // for fiat we always use 2 decimals, but if it's not for fiat...\n  if (!isFiat) {\n    // get number of decimals decimals from state\n    decimals = store.state.app.decimals;\n    // use minimumAmountOfDecimals if it's more than current decimals\n    if (minimumAmountOfDecimals > decimals) {\n      decimals = minimumAmountOfDecimals;\n    }\n  }\n\n  // trunctate the amount to specified decimal places\n  return (Math.floor(monetaryAmount / Math.pow(10, 8 - decimals)) / Math.pow(10, decimals)).toFixed(decimals);\n}\n\nexport function displayToMonetary(displayAmount) {\n  // note: do not divide by 100000000 because it will sometimes give rounding issues\n\n  // convert the amount to string\n  let str = displayAmount.toString();\n  // find the index decimal separator\n  let idx = str.indexOf(\".\");\n\n  // if the decimal separator doesn't exist...\n  if (idx === -1) {\n    // add the decimal separator at the end\n    str += \".\";\n    // and update the index\n    idx = str.length;\n  }\n  // add 8 zeroes at the end, maybe there are too many now\n  str += \"0\".repeat(8);\n  // but here they are removed from the tail\n  str = str.substring(0, idx + 9);\n  // now remove the . and then parse the string to integer\n  return parseInt(str.replace(\".\", \"\"));\n}\n\nfunction formatTime(timestamp) {\n  let date = new Date(timestamp * 1000);\n  return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}, ${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n}\n\nexport function downloadTransactionList(transactions, fileName) {\n  var transformedTransactionArray = [];\n  transactions.forEach(async (tx, index) => {\n    transformedTransactionArray.push({\n      ...tx,\n      timestamp: formatTime(tx.timestamp),\n      change: formatMoneyForDisplay(tx.change)\n    });\n\n    if (index + 1 === transactions.length) {\n      try {\n        const parser = new Parser();\n        const csv = parser.parse(transformedTransactionArray);\n        var blob = new Blob([csv], { type: \"text/csv\" });\n        var url = URL.createObjectURL(blob);\n\n        var downloadLink = document.createElement(\"a\");\n        downloadLink.href = url;\n        downloadLink.setAttribute(\"download\", `${fileName}.csv`);\n        downloadLink.click();\n      } catch (err) {\n        alert(err.message);\n      }\n    }\n  });\n}\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/AccountSettings.vue",
    "content": "<template>\n  <div class=\"account-settings flex-col\">\n    <div class=\"main\">\n      <h5>{{ $t(\"account_settings.name\") }}</h5>\n      <input type=\"text\" v-model=\"newAccountName\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { AccountsController } from \"../../unity/Controllers\";\n\nexport default {\n  name: \"AccountSettings\",\n  props: {\n    account: null\n  },\n  data() {\n    return {\n      newAccountName: null\n    };\n  },\n  created() {\n    this.newAccountName = this.account.label;\n  },\n  watch: {\n    newAccountName() {\n      if (this.newAccountName && this.newAccountName !== this.account.label) {\n        AccountsController.RenameAccount(this.account.UUID, this.newAccountName);\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.account-settings {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/ConfirmTransactionDialog.vue",
    "content": "<template>\n  <div class=\"confirm-transaction-dialog\">\n    <div class=\"tx-amount\">{{ computedAmount }}</div>\n    <div class=\"tx-fee\">{{ computedFee }}</div>\n    <div class=\"tx-fee-message\" v-if=\"subtractFee\">{{ $t(\"send_coins.fee_will_be_subtracted\") }}</div>\n    <div class=\"tx-to\">\n      <fa-icon :icon=\"['far', 'long-arrow-down']\" />\n    </div>\n    <div class=\"tx-address\">{{ address }}</div>\n    <button @click=\"confirm\" class=\"button\">\n      {{ $t(\"buttons.confirm\") }}\n    </button>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"@/EventBus\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { LibraryController } from \"@/unity/Controllers\";\n\nexport default {\n  name: \"ConfirmTransactionDialog\",\n  props: {\n    amount: null,\n    address: null,\n    subtractFee: null\n  },\n  computed: {\n    computedRequest() {\n      return {\n        valid: true,\n        address: this.address,\n        label: \"\",\n        desc: \"\",\n        amount: this.amount\n      };\n    },\n    computedAmount() {\n      return `${formatMoneyForDisplay(this.amount, false, 8)} ${this.$t(\"common.ticker_symbol\")}`;\n    },\n    computedFee() {\n      return `${formatMoneyForDisplay(this.fee, false, 8)} ${this.$t(\"common.ticker_symbol\")} FEE`;\n    }\n  },\n  watch: {\n    amount: {\n      immediate: true,\n      handler() {\n        this.fee = LibraryController.FeeForRecipient(this.computedRequest);\n      }\n    }\n  },\n  methods: {\n    confirm() {\n      EventBus.$emit(\"unlock-wallet\", {\n        message: \"send_coins.unlock_your_wallet_to_complete_the_transaction\",\n        callback: async () => {\n          // try to make the payment\n          let result = LibraryController.PerformPaymentToRecipient(this.computedRequest, this.subtractFee);\n\n          if (result !== 0) {\n            // payment failed, log an error. have to make this more robust\n            console.error(result);\n          }\n\n          EventBus.$emit(\"transaction-succeeded\");\n          EventBus.$emit(\"close-dialog\");\n        }\n      });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.confirm-transaction-dialog {\n  text-align: center;\n\n  & > h4 {\n    margin: 20px 0 0 0;\n  }\n}\n.tx-amount {\n  font-size: 1.6em;\n  font-weight: 600;\n  margin: 0 0 10px 0;\n}\n.tx-fee {\n  font-size: 0.9em;\n}\n.tx-fee-message {\n  font-size: 0.9em;\n  margin-top: 5px;\n}\n.tx-to {\n  margin: 20px 0 10px 0;\n  font-size: 1.6em;\n}\n.tx-address {\n  padding: 10px 0 40px 0;\n  font-weight: 500;\n}\n.button {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/Receive.vue",
    "content": "<template>\n  <div class=\"receive-view flex-col\">\n    <div class=\"main\">\n      <content-wrapper heading=\"receive_coins.your_address\" content=\"receive_coins.information\"> </content-wrapper>\n\n      <div class=\"qr\" @click=\"copyQr\">\n        <vue-qrcode ref=\"qrcode\" class=\"qrcode\" :width=\"280\" :margin=\"0\" :value=\"receiveAddress\" :color=\"{ dark: '#000000', light: '#ffffff' }\" />\n      </div>\n    </div>\n    <div class=\"address-row flex-row\">\n      <div class=\"flex-1\" />\n      <clipboard-field class=\"address\" :value=\"receiveAddress\" confirmation=\"receive_coins.address_copied_to_clipboard\"></clipboard-field>\n      <div class=\"flex-1\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport VueQrcode from \"vue-qrcode\";\nimport { clipboard, nativeImage } from \"electron\";\nimport UIConfig from \"../../../../ui-config.json\";\nimport ContentWrapper from \"../../../components/layout/ContentWrapper.vue\";\n\nexport default {\n  name: \"Receive\",\n  components: {\n    VueQrcode,\n    ContentWrapper\n  },\n  data() {\n    return {\n      UIConfig: UIConfig\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"receiveAddress\"])\n  },\n  methods: {\n    copyQr() {\n      let img = nativeImage.createFromDataURL(this.$refs.qrcode.$el.src);\n      clipboard.writeImage(img);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.receive-view {\n  height: 100%;\n  text-align: center;\n\n  & .information {\n    margin: 0 0 30px 0;\n  }\n  & .qr {\n    text-align: center;\n    cursor: pointer;\n    margin: 0 auto;\n  }\n  & .qrcode {\n    width: 100%;\n    max-width: 140px;\n  }\n  & .address-row {\n    width: 100%;\n    text-align: center;\n  }\n  & .address {\n    margin: 5px 0 0 0;\n    font-weight: 500;\n    font-size: 1em;\n    line-height: 1.4em;\n  }\n  & .buy-coins {\n    width: 100%;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/Send.vue",
    "content": "<template>\n  <div class=\"send-view flex-col\">\n    <div class=\"main\">\n      <div class=\"flex flex-row\">\n        <input\n          helper=\"TEST\"\n          :class=\"getSendClass()\"\n          v-model=\"amount\"\n          ref=\"amount\"\n          type=\"number\"\n          step=\"0.00000001\"\n          :placeholder=\"computedAmountPlaceholder\"\n          min=\"0\"\n        />\n        <button v-if=\"maxAmount > 0\" outlined class=\"max\" @click=\"setUseMax\" :disabled=\"useMax\">max</button>\n      </div>\n      <content-wrapper>\n        <p>\n          {{ this.useMax ? $t(\"send_coins.fee_will_be_subtracted\") : \"&nbsp;\" }}\n        </p>\n      </content-wrapper>\n      <input v-model=\"address\" type=\"text\" :placeholder=\"$t('send_coins.enter_coins_address')\" :class=\"getAddressClass()\" />\n      <input v-model=\"label\" type=\"text\" :placeholder=\"$t('send_coins.enter_label')\" />\n    </div>\n    <div class=\"flex-row\">\n      <button class=\"send\" @click=\"showConfirmation\" :disabled=\"disableSendButton\">\n        {{ $t(\"buttons.send\") }}\n      </button>\n      <button class=\"clear\" outlined @click=\"clearInputs\" :disabled=\"disableClearButton\">{{ $t(\"buttons.clear\") }}</button>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState, mapGetters } from \"vuex\";\nimport { displayToMonetary, formatMoneyForDisplay } from \"../../../util.js\";\nimport { LibraryController } from \"@/unity/Controllers\";\nimport ConfirmTransactionDialog from \"./ConfirmTransactionDialog\";\nimport EventBus from \"@/EventBus\";\n\nexport default {\n  name: \"Send\",\n  data() {\n    return {\n      amount: \"\",\n      maxAmount: null,\n      address: \"\",\n      label: \"\",\n      isAddressInvalid: false,\n      sellDisabled: false,\n      useMax: false\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"decimals\"]),\n    ...mapGetters(\"wallet\", [\"account\"]),\n    computedAmountPlaceholder() {\n      return `0.${\"0\".repeat(this.decimals)}`;\n    },\n    computedMaxForDisplay() {\n      return formatMoneyForDisplay(this.maxAmount, false, 8);\n    },\n    addressClass() {\n      return this.isAddressInvalid ? \"error\" : \"\";\n    },\n    hasErrors() {\n      return this.isAddressInvalid;\n    },\n    disableSendButton() {\n      if (isNaN(parseFloat(this.amount))) return true;\n      if (this.address === null || this.address.trim().length === 0) return true;\n      if (this.amount > this.account.balance) return true;\n      if (!LibraryController.IsValidNativeAddress(this.address)) return true;\n      return false;\n    },\n    disableClearButton() {\n      return this.amount === \"\" && this.address === \"\" && this.label === \"\";\n    }\n  },\n  mounted() {\n    this.$refs.amount.focus();\n    EventBus.$on(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"transaction-succeeded\", this.onTransactionSucceeded);\n  },\n  watch: {\n    account: {\n      immediate: true,\n      handler() {\n        this.maxAmount = this.account.spendable;\n      }\n    },\n    maxAmount() {\n      if (this.useMax) {\n        this.amount = this.computedMaxForDisplay;\n      }\n    },\n    amount() {\n      // this will prevent entering more than 8 decimals\n      const idx = this.amount.indexOf(\".\");\n      if (idx !== -1 && idx + 9 < this.amount.length) {\n        this.amount = this.amount.slice(0, idx + 9);\n      }\n\n      if (displayToMonetary(this.amount) >= this.maxAmount) {\n        this.useMax = true;\n      } else {\n        this.useMax = false;\n      }\n    },\n    useMax() {\n      if (this.useMax) {\n        this.amount = this.computedMaxForDisplay;\n      }\n    }\n  },\n  methods: {\n    clearInputs() {\n      this.amount = \"\";\n      this.address = \"\";\n      this.label = \"\";\n      this.$refs.amount.focus();\n    },\n    getSendClass() {\n      if (this.amount > this.account.balance) return \"error\";\n      return \"\";\n    },\n    getAddressClass() {\n      if (!LibraryController.IsValidNativeAddress(this.address)) return \"error\";\n      return \"\";\n    },\n    showConfirmation() {\n      // amount is always less then or equal to the floored spendable amount\n      // if useMax is checked, use the maxAmount and subtract the fee from the amount\n      let amount = this.useMax ? this.maxAmount : displayToMonetary(this.amount);\n\n      // validate address\n      this.isAddressInvalid = !LibraryController.IsValidNativeAddress(this.address);\n\n      if (this.hasErrors) return;\n\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(\"send_coins.confirm_transaction\"),\n        component: ConfirmTransactionDialog,\n        componentProps: {\n          amount: amount,\n          address: this.address,\n          subtractFee: this.useMax\n        },\n        showButtons: false\n      });\n    },\n    onTransactionSucceeded() {\n      this.$router.push({ name: \"transactions\" });\n    },\n    setUseMax() {\n      this.useMax = true;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.send-view {\n  height: 100%;\n  flex: 1;\n\n  .main {\n    flex: 1;\n  }\n}\n\nbutton.max,\nbutton.clear {\n  margin-left: 10px;\n  padding: 0 15px;\n}\n\nbutton.send {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/TransactionDetails.vue",
    "content": "<template>\n  <div class=\"transaction-details flex-col\">\n    <div class=\"main\">\n      <h5>{{ $t(\"transaction_details.hash\") }}</h5>\n      <div class=\"tx-hash\">{{ txHash }}</div>\n    </div>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: \"TransactionDetails\",\n  props: {\n    txHash: null\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transaction-details {\n  height: 100%;\n\n  .main {\n    flex: 1;\n  }\n\n  .tx-address {\n    margin: 0 0 20px 0;\n    padding: 10px;\n    font-size: 0.9em;\n    line-height: 1.2em;\n    user-select: text;\n    word-wrap: break-word;\n    background-color: #fff;\n  }\n\n  .tx-hash {\n    margin: 0;\n    padding: 10px;\n    font-size: 0.8em;\n    line-height: 1.2em;\n    user-select: text;\n    word-wrap: break-word;\n    background-color: #fff;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/Transactions.vue",
    "content": "<template>\n  <div class=\"transactions-view\">\n    <div v-if=\"hasMutations\" class=\"flex\">\n      <div class=\"mutations-list\" v-for=\"(mutation, index) in mutations\" :key=\"mutation.txHash\">\n        <h4 v-if=\"showDateHeader(index)\">\n          {{ formatDateHeader(mutation.timestamp) }}\n        </h4>\n        <div class=\"mutation-row flex-row\" @click=\"showTransactionDetails(mutation)\" :class=\"mutationRowClass(mutation.txHash)\">\n          <div class=\"icon\">\n            <fa-icon :icon=\"['fal', mutationIcon(mutation)]\" />\n          </div>\n          <div class=\"time\">{{ formatTime(mutation.timestamp) }}</div>\n          <div class=\"tx-details\">\n            {{ mutation.recipient_addresses || mutation.txHash }}\n          </div>\n          <div class=\"amount\">{{ formatAmount(mutation.change) }}</div>\n        </div>\n      </div>\n    </div>\n\n    <content-wrapper class=\"flex\" v-else heading=\"new_wallet.title\" content=\"new_wallet.information\">\n      <div class=\"flex-1\"></div>\n      <app-button-section>\n        <template v-slot:middle>\n          <button @click=\"buyCoins\" class=\"buy-coins\" :disabled=\"buyDisabled\">\n            {{ $t(\"buttons.buy_your_first_coins\") }}\n          </button>\n        </template>\n      </app-button-section>\n    </content-wrapper>\n  </div>\n</template>\n\n<script>\nimport { BackendUtilities } from \"@/unity/Controllers\";\nimport { formatMoneyForDisplay } from \"../../../util.js\";\nimport { mapState } from \"vuex\";\nimport TransactionDetailsDialog from \"../../../components/TransactionDetailsDialog\";\nimport EventBus from \"../../../EventBus\";\n\nexport default {\n  name: \"Transactions\",\n  data() {\n    return {\n      buyDisabled: false\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"mutations\"]),\n    hasMutations() {\n      return this.mutations ? this.mutations.length > 0 : false;\n    }\n  },\n  methods: {\n    mutationIcon(mutation) {\n      switch (mutation.status) {\n        case 0: // UNCONFIRMED\n          return \"hourglass-start\";\n        case 1: // CONFIRMING\n          return \"shield\";\n        case 2: // CONFIRMED\n          return \"shield-check\";\n        case 3: // ABANDONED\n        case 4: // CONFLICTED\n          return \"ban\";\n      }\n    },\n    showDateHeader(index) {\n      // only show a date header if the current date is different than previous date\n      if (index === 0) return true; // always show the date if it's the first item\n\n      const current = new Date(this.mutations[index].timestamp * 1000);\n      const previous = new Date(this.mutations[index - 1].timestamp * 1000);\n\n      if (current.getDate() !== previous.getDate()) return true;\n      if (current.getMonth() !== previous.getMonth()) return true;\n      if (current.getFullYear() !== previous.getFullYear()) return true;\n\n      return false;\n    },\n    formatDateHeader(timestamp) {\n      let date = new Date(timestamp * 1000);\n      let options = {\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\"\n      };\n      if (date.getFullYear() === new Date().getFullYear()) delete options.year;\n      return date.toLocaleString(this.$i18n.locale, options);\n    },\n    formatTime(timestamp) {\n      let date = new Date(timestamp * 1000);\n      return `${(\"0\" + date.getHours()).slice(-2)}:${(\"0\" + date.getMinutes()).slice(-2)}`;\n    },\n    formatAmount(amount) {\n      return `${formatMoneyForDisplay(amount)}`;\n    },\n    mutationRowClass(txHash) {\n      return txHash === this.txHash ? \"selected\" : \"\";\n    },\n    showTransactionDetails(mutation) {\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(`transaction_details.title.${mutation.change > 0 ? \"incoming_transaction\" : \"outgoing_transaction\"}`),\n        component: TransactionDetailsDialog,\n        componentProps: {\n          mutation: mutation\n        },\n        showButtons: false\n      });\n    },\n    async buyCoins() {\n      try {\n        this.buyDisabled = true;\n        const url = await BackendUtilities.GetBuySessionUrl();\n        window.open(url, \"buy-coins\");\n      } finally {\n        this.buyDisabled = false;\n      }\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.transactions-view {\n  height: 100%;\n}\n\n.flex {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n\n.mutations-list:not(:first-child) > h4 {\n  margin-top: 30px;\n}\n\n.mutation-group {\n  margin-bottom: 30px;\n}\n\nh4 {\n  margin-bottom: 10px;\n}\n\n.mutation-row {\n  width: calc(100% + 20px);\n  margin: 0 0 0 -10px;\n  padding: 5px 10px 5px 10px;\n  font-size: 0.95em;\n  line-height: 18px;\n  cursor: pointer;\n\n  & > .icon {\n    flex: 0 0 30px;\n  }\n\n  & > .time {\n    flex: 0 0 70px;\n  }\n\n  & > .tx-details {\n    font-size: 0.85em;\n    width: 100%;\n    margin-right: 10px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n\n  & .amount {\n    flex: 1;\n    text-align: right;\n  }\n\n  &:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n\n  &.selected {\n    color: #fff;\n    background: var(--primary-color);\n  }\n}\n\n.new-wallet {\n  height: 100%;\n}\n\n.buy-coins {\n  width: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/SpendingAccount/index.vue",
    "content": "<template>\n  <div class=\"spending-account\">\n    <portal to=\"header-slot\">\n      <account-header :account=\"account\"></account-header>\n    </portal>\n\n    <transactions v-if=\"isAccountView\" :mutations=\"mutations\" @tx-hash=\"onTxHash\" :tx-hash=\"txHash\" />\n\n    <router-view />\n\n    <portal to=\"footer-slot\">\n      <div style=\"display: flex\">\n        <footer-button title=\"buttons.transactions\" :icon=\"['far', 'list-ul']\" routeName=\"account\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.send\" :icon=\"['fal', 'arrow-from-bottom']\" routeName=\"send\" @click=\"routeTo\" />\n        <footer-button title=\"buttons.receive\" :icon=\"['fal', 'arrow-to-bottom']\" routeName=\"receive\" @click=\"routeTo\" />\n      </div>\n    </portal>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport Transactions from \"./Transactions\";\nimport { downloadTransactionList } from \"../../../util.js\";\n\nexport default {\n  name: \"SpendingAccount\",\n  props: {\n    account: null\n  },\n  data() {\n    return {\n      txHash: null\n    };\n  },\n  components: {\n    Transactions\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"mutations\"]),\n    isAccountView() {\n      return this.$route.name === \"account\";\n    }\n  },\n  methods: {\n    routeTo(route) {\n      if (this.$route.name === route) return;\n      this.$router.push({ name: route, params: { id: this.account.UUID } });\n    },\n    onTxHash(txHash) {\n      this.txHash = txHash;\n    },\n    downloadCSV() {\n      downloadTransactionList(this.mutations, this.account.label);\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Account/index.vue",
    "content": "<template>\n  <component :is=\"accountType\" :account=\"account\" />\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\n\nimport SpendingAccount from \"./SpendingAccount\";\n\nexport default {\n  name: \"Account\",\n  data() {\n    return {\n      accountType: \"div\"\n    };\n  },\n  props: {\n    id: null\n  },\n  components: {\n    SpendingAccount\n  },\n  computed: {\n    ...mapGetters(\"wallet\", [\"account\"])\n  },\n  watch: {\n    account() {\n      this.onAccountChanged();\n    }\n  },\n  mounted() {\n    this.onAccountChanged();\n  },\n  methods: {\n    onAccountChanged() {\n      if (this.account) {\n        switch (this.account.type) {\n          case \"Desktop\":\n            this.accountType = SpendingAccount;\n            break;\n          default:\n            this.accountType = \"div\";\n            break;\n        }\n      }\n      // remove the activity indicator at this point\n      this.$store.dispatch(\"app/SET_ACTIVITY_INDICATOR\", false);\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/frontend/lite/src/views/DebugDialog/DebugConsole.vue",
    "content": "<template>\n  <div class=\"debug-console flex-col\" v-if=\"show\">\n    <div class=\"output-buttons\">\n      <fa-icon :icon=\"['fal', 'search-minus']\" class=\"button\" @click=\"decreaseFontSize\" />\n      <fa-icon :icon=\"['fal', 'search-plus']\" class=\"button\" @click=\"increaseFontSize\" />\n      <fa-icon :icon=\"['fal', 'eraser']\" class=\"button\" @click=\"clearOutput\" />\n    </div>\n\n    <div ref=\"output\" class=\"output scrollable\" :style=\"outputStyle\">\n      <div class=\"row\">\n        <div class=\"info\">Use up and down arrows to navigate history. Type <span class=\"help\">help</span> for an overview of available commands.</div>\n      </div>\n      <div class=\"row\" v-for=\"(item, index) in output\" :key=\"index\">\n        <fa-icon class=\"icon\" :icon=\"getIcon(item.type)\" />\n        <pre class=\"data\" :style=\"outputStyle\">{{ item.data }}</pre>\n      </div>\n    </div>\n\n    <div class=\"input\">\n      <input ref=\"command\" type=\"text\" spellcheck=\"false\" v-model=\"command\" @keydown=\"onRpcInputKeyDown\" list=\"history\" />\n      <datalist id=\"history\">\n        <option v-for=\"item in filteredAutocompleteList\" :key=\"item\" :value=\"item\" />\n      </datalist>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { RpcController } from \"../../unity/Controllers\";\n\nexport default {\n  name: \"DebugConsole\",\n  data() {\n    return {\n      command: \"\",\n      fontSize: 0.8,\n      history: [],\n      output: [],\n      index: 0,\n      autocomplete: {\n        all: [],\n        command: null,\n        filtered: [],\n        disabled: false\n      }\n    };\n  },\n  props: {\n    show: {\n      type: Boolean\n    }\n  },\n  computed: {\n    outputStyle() {\n      return `font-size: ${this.fontSize}rem;`;\n    },\n    filteredAutocompleteList() {\n      return this.autocomplete.filtered.slice(0, 20);\n    }\n  },\n  created() {\n    this.autocomplete.all = RpcController.GetAutocompleteList();\n  },\n  watch: {\n    output: {\n      immediate: true,\n      handler() {\n        this.focusCommand();\n      }\n    },\n    show: {\n      immediate: true,\n      handler() {\n        if (this.show) {\n          this.focusCommand();\n        }\n      }\n    },\n    command() {\n      this.filterAutocompleteList();\n    }\n  },\n  methods: {\n    moveToEnd() {\n      let command = this.$refs.command;\n      setTimeout(function () {\n        command.selectionStart = command.selectionEnd = command.value.length;\n      }, 0);\n    },\n    getIcon(type) {\n      return [\"fal\", `angle-double-${type === \"command\" ? \"left\" : \"right\"}`];\n    },\n    async onRpcInputKeyDown(e) {\n      this.autocomplete.disabled = false;\n      switch (e.keyCode) {\n        case 13: {\n          let result = await RpcController.ExecuteAsync(this.command);\n          this.command = \"\";\n\n          this.output.push({\n            type: \"command\",\n            data: result.command\n          });\n          this.output.push({ type: \"result\", ...result });\n\n          this.scrollToBottom();\n\n          let index = this.history.indexOf(result.command);\n          if (index !== -1) {\n            this.history.splice(index, 1);\n          }\n          this.history.push(result.command);\n          this.index = this.history.length;\n          return;\n        }\n        case 38: // arrow up\n          if (this.index > 0) this.index--;\n          if (this.history.length > 0) {\n            this.autocomplete.disabled = true;\n            this.command = this.history[this.index];\n            this.moveToEnd();\n            e.preventDefault();\n          }\n          break;\n        case 40: // arrow down\n          if (this.index < this.history.length) this.index++;\n          if (this.index < this.history.length && this.history.length > 0) {\n            this.autocomplete.disabled = true;\n            this.command = this.history[this.index];\n            this.moveToEnd();\n            e.preventDefault();\n          } else {\n            this.command = \"\";\n          }\n          break;\n      }\n    },\n    clearOutput() {\n      this.output = [];\n    },\n    focusCommand() {\n      this.$nextTick(() => {\n        this.$refs.command.focus();\n      });\n    },\n    scrollToBottom() {\n      this.$nextTick(() => {\n        this.$refs.output.scrollTop = this.$refs.output.scrollHeight;\n      });\n    },\n    increaseFontSize() {\n      if (this.fontSize >= 1.3) return;\n      this.fontSize += 0.05;\n    },\n    decreaseFontSize() {\n      if (this.fontSize <= 0.6) return;\n      this.fontSize -= 0.05;\n    },\n    filterAutocompleteList() {\n      if (this.autocomplete.disabled) return;\n\n      let filteredList = [];\n      const command = this.command && this.command.trim().length > 0 ? this.command.trim() : null;\n      if (command) {\n        filteredList = command.startsWith(this.autocomplete.command) ? this.autocomplete.filtered : this.autocomplete.all;\n      }\n\n      this.autocomplete.filtered = filteredList.filter(x => x.startsWith(command));\n      this.autocomplete.command = command;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.debug-console {\n  width: 100%;\n  height: 100%;\n}\n\n.output-buttons {\n  line-height: 20px;\n  text-align: right;\n\n  & .button {\n    margin: 4px;\n    cursor: pointer;\n  }\n}\n\n.output {\n  flex: 1;\n  margin-bottom: 8px;\n  border: 1px solid #ccc;\n  user-select: text;\n  padding: 4px;\n\n  & .help {\n    color: var(--primary-color);\n  }\n\n  & * {\n    user-select: text;\n  }\n\n  & .error {\n    color: var(--error-color);\n  }\n}\n\n.row {\n  display: flex;\n  flex-direction: row;\n  padding-top: 5px;\n\n  & > * {\n    padding-right: 5px;\n  }\n\n  & > .icon {\n    flex: 0 0 20px;\n  }\n}\n\n.row:last-of-type {\n  margin-bottom: 10px;\n}\n\npre {\n  white-space: pre-wrap;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/DebugDialog/InformationPage.vue",
    "content": "<template>\n  <div class=\"information-page\">\n    <app-section>\n      <h4>General</h4>\n\n      <div class=\"flex-row\">\n        <div>Client version</div>\n        <div>{{ clientInfo.client_version }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Useragent</div>\n        <div>{{ clientInfo.user_agent }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Data dir</div>\n        <div class=\"path-row\">\n          <div @click=\"openFile(clientInfo.datadir_path)\" class=\"list-item-icon\">\n            <fa-icon :icon=\"['fal', 'file-search']\" />\n          </div>\n          <div class=\"selectable\">{{ clientInfo.datadir_path }}</div>\n        </div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Log file</div>\n        <div class=\"path-row\">\n          <div @click=\"openFile(clientInfo.logfile_path)\" class=\"list-item-icon\">\n            <fa-icon :icon=\"['fal', 'file-search']\" />\n          </div>\n          <div class=\"selectable\">\n            {{ clientInfo.logfile_path }}\n          </div>\n        </div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Startup time</div>\n        <div>{{ startupTime }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Network</h4>\n      <div class=\"flex-row\">\n        <div>Status</div>\n        <div>{{ clientInfo.network_status }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Connection count</div>\n        <div>{{ numberOfConnections }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Block chain</h4>\n      <div class=\"flex-row\">\n        <div>Number of blocks</div>\n        <div>{{ clientInfo.chain_tip_height }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Last block time</div>\n        <div>{{ lastBlockTime }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Last block hash</div>\n        <div>{{ clientInfo.chain_tip_hash }}</div>\n      </div>\n    </app-section>\n\n    <app-section>\n      <h4>Memory pool</h4>\n      <div class=\"flex-row\">\n        <div>Number of transactions</div>\n        <div>{{ clientInfo.mempool_transaction_count }}</div>\n      </div>\n      <div class=\"flex-row\">\n        <div>Memory usage</div>\n        <div>{{ clientInfo.mempool_memory_size }}</div>\n      </div>\n    </app-section>\n  </div>\n</template>\n\n<script>\nimport { LibraryController } from \"../../unity/Controllers\";\nconst { shell } = require(\"electron\"); // deconstructing assignment\n\nlet timeout;\n\nexport default {\n  data() {\n    return {\n      clientInfo: null,\n      isDestroyed: false\n    };\n  },\n  name: \"InformationPage\",\n  computed: {\n    startupTime() {\n      return this.formatDate(this.clientInfo.startup_timestamp);\n    },\n    lastBlockTime() {\n      return this.formatDate(this.clientInfo.chain_tip_time);\n    },\n    numberOfConnections() {\n      let connections_in = parseInt(this.clientInfo.num_connections_in);\n      let connections_out = parseInt(this.clientInfo.num_connections_out);\n\n      return `${connections_in + connections_out} (In: ${connections_in} / Out: ${connections_out})`;\n    }\n  },\n  created() {\n    this.updateClientInfo();\n  },\n  beforeDestroy() {\n    this.isDestroyed = true;\n    clearTimeout(timeout);\n  },\n  methods: {\n    updateClientInfo() {\n      clearTimeout(timeout);\n      this.clientInfo = LibraryController.GetClientInfo();\n      if (this.isDestroyed) return;\n      timeout = setTimeout(this.updateClientInfo, 10 * 1000);\n    },\n    formatDate(timestamp) {\n      const date = new Date(timestamp * 1000);\n      return date.toLocaleString(this.$i18n.locale, {\n        weekday: \"short\",\n        year: \"numeric\",\n        month: \"long\",\n        day: \"numeric\",\n        hour: \"2-digit\",\n        minute: \"2-digit\",\n        second: \"2-digit\"\n      });\n    },\n    openFile(path) {\n      shell.openPath(path);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.information-page {\n  width: 100%;\n  height: 100%;\n\n  & h4 {\n    margin-bottom: 5px;\n  }\n  & h4:not(:first) {\n    margin-top: 5px;\n  }\n\n  & .flex-row > div {\n    font-size: 0.85rem;\n    line-height: 20px;\n    margin-bottom: 5px;\n  }\n  & .flex-row :first-child {\n    flex: 0 0 180px;\n  }\n  & .flex-row :last-child {\n    flex: 1;\n    overflow-wrap: break-word;\n    word-break: break-word;\n  }\n}\n\n.list-item-icon {\n  max-width: 30px;\n  cursor: pointer;\n}\n\n.path-row {\n  display: flex;\n  flex-direction: row;\n}\n\n.selectable {\n  user-select: all;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/DebugDialog/PeerDetailsDialog.vue",
    "content": "<template>\n  <div class=\"peer-details-dialog\">\n    <activity-indicator v-if=\"loading\" :paddingHidden=\"true\" />\n    <div class=\"peer-info scrollable\">\n      <div v-for=\"(value, propertyName) in peerInfo\" :key=\"propertyName\" class=\"row\">\n        <h4>{{ $t(`peers.${propertyName}`) }}</h4>\n        <div>{{ value }}</div>\n      </div>\n    </div>\n    <div class=\"buttons\">\n      <button @click=\"unBanPeer(peer)\" outlined small v-if=\"isBanned\">\n        {{ $t(\"peers.buttons.un_ban\") }}\n      </button>\n      <button @click=\"disconnectPeer(peer)\" outlined small v-if=\"!isBanned\">\n        {{ $t(\"peers.buttons.disconnect\") }}\n      </button>\n\n      <div style=\"display: flex\" v-if=\"!isBanned\">\n        <div>{{ $t(\"peers.ban\") }}</div>\n        <button @click=\"banPeer(3600)\" outlined small>\n          {{ $t(\"peers.buttons.ban_hour\") }}\n        </button>\n        <button @click=\"banPeer(86400)\" outlined small>\n          {{ $t(\"peers.buttons.ban_day\") }}\n        </button>\n        <button @click=\"banPeer(604800)\" outlined small>\n          {{ $t(\"peers.buttons.ban_week\") }}\n        </button>\n        <button @click=\"banPeer(31449600)\" outlined small>\n          {{ $t(\"peers.buttons.ban_year\") }}\n        </button>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport EventBus from \"@/EventBus\";\nimport { P2pNetworkController } from \"@/unity/Controllers\";\nimport ActivityIndicator from \"@/components/ActivityIndicator.vue\";\n\nexport default {\n  data() {\n    return {\n      loading: false\n    };\n  },\n  name: \"PeerDetailsDialog\",\n  props: {\n    peer: {\n      type: Object,\n      default: null\n    }\n  },\n  components: {\n    ActivityIndicator\n  },\n  computed: {\n    isBanned() {\n      return this.peer.banned_from !== undefined;\n    },\n    peerInfo() {\n      const peer = this.peer;\n\n      return this.isBanned\n        ? {\n            address: peer.address,\n            banned_from: this.formatDate(peer.banned_from),\n            banned_until: this.formatDate(peer.banned_until),\n            reason: peer.reason\n          }\n        : {\n            node_id: peer.id,\n            node_service: peer.ip,\n            whitelisted: peer.whitelisted ? \"Yes\" : \"No\",\n            direction: peer.inbound ? \"Inbound\" : \"Outbound\",\n            user_agent: peer.userAgent,\n            services: peer.services,\n            starting_block: peer.start_height,\n            synced_headers: peer.synced_height,\n            synced_blocks: peer.common_height,\n            ban_score: peer.banscore,\n            connection_time: this.formatDateFrom(peer.time_connected),\n            last_send: this.formatDateFrom(peer.last_send),\n            last_receive: this.formatDateFrom(peer.last_receive),\n            sent: peer.send_bytes,\n            received: peer.receive_bytes,\n            ping_time: peer.latency,\n            time_offset: peer.time_offset\n          };\n    }\n  },\n  methods: {\n    formatDateFrom(date) {\n      const now = Date.now() / 1000;\n      return parseInt(now - date);\n    },\n    formatDate(date) {\n      const dateTimeString = new Date(date * 1000).toLocaleString();\n      return dateTimeString;\n    },\n    async disconnectPeer() {\n      this.loading = true;\n      const result = await P2pNetworkController.DisconnectPeerAsync(this.peer.id);\n      this.closeDialog(result);\n    },\n    async banPeer(interval) {\n      this.loading = true;\n      const result = await P2pNetworkController.BanPeerAsync(this.peer.addrBind, interval);\n      this.closeDialog(result);\n    },\n    async unBanPeer() {\n      this.loading = true;\n      const result = await P2pNetworkController.UnbanPeerAsync(this.peer.address);\n      this.closeDialog(result);\n    },\n    closeDialog(result) {\n      console.log(result); // todo: do something usefull with result\n\n      setTimeout(() => {\n        this.loading = false;\n        EventBus.$emit(\"close-dialog\");\n      }, 1000);\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.peer-details-dialog {\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  max-height: calc(100vh - 100px);\n  margin-top: 10px;\n\n  & > div {\n    padding: 0 30px;\n  }\n}\n\n.peer-info {\n  flex: 1;\n}\n\n.row {\n  display: flex;\n\n  & > h4 {\n    flex: 1;\n    margin-bottom: 10px;\n  }\n\n  & > div {\n    flex: 1;\n  }\n}\n\n.buttons {\n  line-height: 50px;\n  height: 50px;\n  display: flex;\n  align-items: center;\n  justify-content: flex-end;\n\n  & > div {\n    flex: 1 0 0;\n    display: flex;\n    align-items: center;\n    justify-content: flex-end;\n\n    & > button {\n      margin-left: 10px;\n      min-width: 60px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/DebugDialog/PeersPage.vue",
    "content": "<template>\n  <div class=\"layout\">\n    <div>\n      <div class=\"header\">\n        <h4>{{ $t(\"peers.node_id\") }}</h4>\n        <h4>{{ $t(\"peers.node_service\") }}</h4>\n        <h4>{{ $t(\"peers.user_agent\") }}</h4>\n      </div>\n      <div class=\"list scrollable\">\n        <div v-for=\"peer in peerInfo.peers\" :key=\"peer.id\" @click=\"showPeerDetails(peer)\" @contextmenu.prevent=\"onRightClick\">\n          <div>{{ peer.id }}</div>\n          <div>{{ peer.ip }}</div>\n          <div>{{ peer.userAgent }}</div>\n        </div>\n      </div>\n    </div>\n    <div v-if=\"hasBannedPeers\">\n      <div class=\"header\">\n        <h4>{{ $t(\"peers.banned_peers\") }}</h4>\n        <h4>{{ $t(\"peers.reason\") }}</h4>\n      </div>\n      <div class=\"list scrollable\">\n        <div v-for=\"peer in peerInfo.banned\" :key=\"peer.id\" @click=\"showPeerDetails(peer)\" @contextmenu.prevent=\"onRightClick\">\n          <div>{{ peer.address }}</div>\n          <div>{{ peer.reason }}</div>\n        </div>\n      </div>\n    </div>\n    <div class=\"buttons\" v-if=\"hasBannedPeers\">\n      <button @click=\"clearBannedPeers\" v-if=\"peerInfo.banned.length > 0\" class=\"clear-banned\" outlined small>\n        {{ $t(\"peers.buttons.clear_banned\") }}\n      </button>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { P2pNetworkController } from \"@/unity/Controllers\";\nimport PeerDetailsDialog from \"./PeerDetailsDialog\";\nimport EventBus from \"@/EventBus\";\n\nlet timeout;\n\nexport default {\n  data() {\n    return {\n      peerInfo: {\n        peers: [],\n        banned: []\n      },\n      isDestroyed: false\n    };\n  },\n  name: \"PeersPage2\",\n  computed: {\n    hasBannedPeers() {\n      return this.peerInfo.banned.length;\n    }\n  },\n  methods: {\n    onRightClick() {\n      // TODO: Right Click\n      // Add Context menu on Right Click\n    },\n    getPeers() {\n      clearTimeout(timeout);\n\n      this.peerInfo = {\n        peers: P2pNetworkController.GetPeerInfo(),\n        banned: P2pNetworkController.ListBannedPeers()\n      };\n\n      if (this.isDestroyed) return;\n      timeout = setTimeout(this.getPeers, 10 * 1000);\n    },\n    showPeerDetails(peer) {\n      EventBus.$emit(\"show-dialog\", {\n        title: this.$t(\"peers.peer_details\"),\n        component: PeerDetailsDialog,\n        componentProps: {\n          peer: peer\n        },\n        noMargin: true,\n        showButtons: false\n      });\n    },\n    async clearBannedPeers() {\n      await P2pNetworkController.ClearBannedAsync();\n      this.getPeers();\n    }\n  },\n  created() {\n    this.getPeers();\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.getPeers);\n  },\n  beforeDestroy() {\n    this.isDestroyed = true;\n    clearTimeout(timeout);\n    EventBus.$off(\"close-dialog\", this.getPeers);\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.layout {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n\n  & > div:not(.buttons) {\n    flex: 1 0 0;\n    margin-bottom: 10px;\n\n    display: flex;\n    flex-direction: column;\n  }\n\n  & > div.buttons {\n    text-align: right;\n  }\n}\n\n.header,\n.list > div {\n  display: flex;\n\n  & :first-child {\n    flex: 1 0 0;\n  }\n\n  & :not(:first-child) {\n    flex: 2 0 0;\n  }\n}\n\n.list {\n  border: solid 0.5px #888888;\n  padding: 0 5px;\n  flex: 1 0 0;\n\n  & > div {\n    cursor: pointer;\n    padding: 5px 0;\n  }\n\n  & > div:hover {\n    color: var(--primary-color);\n    background: var(--hover-color);\n  }\n}\n\nh4 {\n  margin-bottom: 5px;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/DebugDialog/index.vue",
    "content": "<template>\n  <div class=\"app-debug\">\n    <modal-dialog v-model=\"modal\" />\n    <div class=\"topbar flex-row\">\n      <div v-for=\"(tab, index) in tabs\" :key=\"index\" :class=\"getTabClass(index)\" @click=\"setTab(index)\">\n        {{ tab.title }}\n      </div>\n    </div>\n    <div class=\"main scrollable\">\n      <information-page v-if=\"current === 0\" />\n      <debug-console :show=\"current === 1\" />\n      <peers-page v-if=\"current === 2\" />\n    </div>\n  </div>\n</template>\n\n<script>\nimport InformationPage from \"./InformationPage\";\nimport DebugConsole from \"./DebugConsole\";\nimport PeersPage from \"./PeersPage\";\nimport ModalDialog from \"../../components/ModalDialog\";\nimport EventBus from \"../../EventBus.js\";\n\nexport default {\n  data() {\n    return {\n      current: 0,\n      tabs: [\n        {\n          title: \"Information\"\n        },\n        {\n          title: \"Console\"\n        },\n        {\n          title: \"Peers\"\n        }\n      ],\n      modal: null\n    };\n  },\n  components: {\n    InformationPage,\n    DebugConsole,\n    PeersPage,\n    ModalDialog\n  },\n  mounted() {\n    EventBus.$on(\"close-dialog\", this.closeModal);\n    EventBus.$on(\"show-dialog\", this.showModal);\n  },\n  beforeDestroy() {\n    EventBus.$off(\"close-dialog\", this.closeModal);\n    EventBus.$off(\"show-dialog\", this.showModal);\n  },\n  methods: {\n    getTabClass(index) {\n      return index === this.current ? \"active\" : \"\";\n    },\n    setTab(index) {\n      this.current = index;\n    },\n    closeModal() {\n      this.modal = null;\n    },\n    showModal(modal) {\n      this.modal = modal;\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.app-debug {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n}\n\n.topbar {\n  width: 100%;\n  height: 56px;\n  color: #000;\n  border-bottom: 1px solid var(--main-border-color);\n\n  & div {\n    padding: 0 20px;\n    font-weight: 600;\n    font-size: 0.85em;\n    line-height: 56px;\n    text-transform: uppercase;\n    letter-spacing: 0.03em;\n    cursor: pointer;\n\n    &:hover {\n      color: var(--primary-color);\n      background: var(--hover-color);\n    }\n\n    &.active,\n    .active:hover {\n      color: var(--primary-color);\n    }\n  }\n}\n\n.main {\n  height: calc(100% - 48px);\n  padding: 20px;\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Settings/ChangePassword.vue",
    "content": "<template>\n  <div class=\"change-password-view\">\n    <content-wrapper heading=\"common.enter_your_password\">\n      <app-form-field>\n        <input ref=\"currentPassword\" type=\"password\" v-model=\"currentPassword\" @keydown=\"resetStatus\" :class=\"currentPasswordStatus\" />\n      </app-form-field>\n    </content-wrapper>\n\n    <content-wrapper>\n      <app-form-field title=\"setup.choose_password\">\n        <input ref=\"password1\" type=\"password\" v-model=\"password1\" :class=\"password2Status\" />\n      </app-form-field>\n      <app-form-field title=\"setup.repeat_password\">\n        <input type=\"password\" v-model=\"password2\" :class=\"password2Status\" @keydown=\"validatePasswordRepeatOnEnter\" />\n      </app-form-field>\n    </content-wrapper>\n\n    <div class=\"flex-1\" />\n    <portal v-if=\"!isSingleAccount\" to=\"footer-slot\">\n      <app-button-section>\n        <button @click=\"tryChangePassword\" :disabled=\"isButtonDisabled\">\n          {{ $t(\"buttons.change_password\") }}\n        </button>\n      </app-button-section>\n    </portal>\n    <app-button-section v-else>\n      <template v-slot:left>\n        <button @click=\"routeTo('settings')\">\n          {{ $t(\"buttons.back\") }}\n        </button>\n      </template>\n      <template v-slot:right>\n        <button @click=\"tryChangePassword\" :disabled=\"isButtonDisabled\">\n          {{ $t(\"buttons.change_password\") }}\n        </button>\n      </template>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport { LibraryController } from \"../../unity/Controllers\";\nimport UIConfig from \"../../../ui-config.json\";\n\nexport default {\n  data() {\n    return {\n      currentPassword: \"\",\n      password1: \"\",\n      password2: \"\",\n      isCurrentPasswordInvalid: false,\n      isSingleAccount: UIConfig.isSingleAccount\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"walletPassword\"]),\n    currentPasswordStatus() {\n      return this.isCurrentPasswordInvalid ? \"error\" : \"\";\n    },\n    password2Status() {\n      if (this.password2.length === 0) return \"\";\n      if (this.password2.length > this.password1.length) return \"error\";\n      return this.password1.indexOf(this.password2) === 0 ? \"\" : \"error\";\n    },\n    passwordsValidated() {\n      if (this.password1 === null || this.password1.length < 6) return false;\n      if (this.password2 === null || this.password2.length < this.password1.length) return false;\n\n      return this.password1 === this.password2;\n    },\n    isButtonDisabled() {\n      return this.currentPassword.trim().length === 0 || this.passwordsValidated === false;\n    }\n  },\n  mounted() {\n    this.$refs.currentPassword.focus();\n  },\n  methods: {\n    tryChangePassword() {\n      if (LibraryController.UnlockWallet(this.currentPassword, 10)) {\n        if (LibraryController.ChangePassword(this.currentPassword, this.password2)) {\n          LibraryController.LockWallet();\n          this.routeTo(\"account\");\n        }\n      } else {\n        this.isCurrentPasswordInvalid = true;\n      }\n    },\n    async resetStatus() {\n      this.isCurrentPasswordInvalid = false;\n    },\n    validatePasswordRepeatOnEnter(e) {\n      if (e.keyCode === 13 && this.passwordsValidated) this.tryChangePassword();\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.change-password-view {\n  display: flex;\n  height: 100%;\n  flex-direction: column;\n  flex-wrap: nowrap;\n  justify-content: space-between;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Settings/SettingsList.vue",
    "content": "<template>\n  <div class=\"settings-list-view\">\n    <portal v-if=\"!isSingleAccount\" to=\"header-slot\">\n      <main-header title=\"settings.header\" />\n    </portal>\n    <h2 v-else>{{ $t(\"settings.header\") }}</h2>\n\n    <router-link :to=\"{ name: 'view-recovery-phrase' }\">\n      <div class=\"settings-row\">\n        {{ $t(\"settings.view_recovery_phrase\") }}\n        <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n      </div>\n    </router-link>\n    <router-link :to=\"{ name: 'change-password' }\">\n      <div class=\"settings-row\">\n        {{ $t(\"settings.change_password\") }}\n        <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n      </div>\n    </router-link>\n    <div>\n      <div v-if=\"hasThemes\" class=\"settings-row-no-hover flex-row\">\n        <div class=\"flex-1\">{{ $t(\"settings.choose_theme\") }}</div>\n        <div v-for=\"(theme, index) in themes\" :key=\"theme.name\">\n          <div :class=\"getThemeSelectClassNames(theme.name, index)\" :style=\"getThemeStyle(theme.color)\" @click=\"switchTheme(theme.name)\"></div>\n        </div>\n      </div>\n    </div>\n    <div class=\"settings-row-no-hover flex-row\">\n      <div class=\"flex-1\">{{ $t(\"settings.choose_language\") }}</div>\n      <div :class=\"`language-select ${this.language === 'en' ? 'selected' : ''}`\" @click=\"changeLanguage('en')\">\n        {{ $t(\"settings.english\") }}\n      </div>\n      <div :class=\"`language-select ${this.language === 'nl' ? 'selected' : ''}`\" @click=\"changeLanguage('nl')\">\n        {{ $t(\"settings.dutch\") }}\n      </div>\n    </div>\n    <div class=\"settings-row-no-hover flex-row\">\n      <div class=\"flex-1\">{{ $t(\"settings.choose_decimal_places\") }}</div>\n      <div :class=\"`decimal-select ${this.decimals === 2 ? 'selected' : ''}`\" @click=\"changeDecimals(2)\">2</div>\n      <div :class=\"`decimal-select ${this.decimals === 3 ? 'selected' : ''}`\" @click=\"changeDecimals(3)\">3</div>\n      <div :class=\"`decimal-select ${this.decimals === 4 ? 'selected' : ''}`\" @click=\"changeDecimals(4)\">4</div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport UIConfig from \"../../../ui-config.json\";\n\nexport default {\n  data() {\n    return {\n      isSingleAccount: UIConfig.isSingleAccount,\n      themes: UIConfig.themes\n    };\n  },\n  computed: {\n    ...mapState(\"app\", [\"theme\", \"language\", \"decimals\"]),\n    hasThemes() {\n      return this.themes && this.themes.length;\n    }\n  },\n  methods: {\n    getThemeSelectClassNames(theme, index) {\n      const classNames = [\"theme-select\"];\n      if (theme === this.theme || (!this.theme && index === 0)) classNames.push(\"selected\");\n      return classNames.join(\" \");\n    },\n    getThemeStyle(color) {\n      return `background-color: ${color}`;\n    },\n    switchTheme(theme) {\n      this.$store.dispatch(\"app/SET_THEME\", theme);\n    },\n    changeLanguage(language) {\n      this.$store.dispatch(\"app/SET_LANGUAGE\", language);\n      this.$forceUpdate();\n    },\n    changeDecimals(decimal) {\n      this.$store.dispatch(\"app/SET_DECIMALS\", decimal);\n      this.$forceUpdate();\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.settings-list-view {\n  display: flex;\n  flex-direction: column;\n}\n\n.settings-row {\n  margin: 0 -10px;\n  padding: 10px;\n}\n\n.settings-row-no-hover {\n  margin: 0 -10px;\n  padding: 10px;\n}\n\n.settings-row:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n  cursor: pointer;\n}\n\n.arrow {\n  float: right;\n}\n\n.theme-select {\n  border: 2px solid #fff;\n  border-radius: 18px;\n  height: 20px;\n  width: 20px;\n  cursor: pointer;\n  margin-left: 5px;\n}\n\n.language-select {\n  font-size: 12px;\n  border-radius: 18px;\n  line-height: 20px;\n  width: 40px;\n  text-align: center;\n  cursor: pointer;\n  margin-left: 15px;\n}\n\n.language-select:hover {\n  cursor: pointer;\n}\n\n.decimal-select {\n  font-size: 12px;\n  border-radius: 18px;\n  line-height: 20px;\n  width: 40px;\n  text-align: center;\n  cursor: pointer;\n  margin-left: 15px;\n}\n\n.selected {\n  box-shadow: 0 0 0 1px #000;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Settings/ViewRecoveryPhrase.vue",
    "content": "<template>\n  <div class=\"view-recovery-phrase-view\">\n    <div>\n      <content-wrapper heading=\"common.important\" heading-style=\"warning\" content=\"setup.this_is_your_recovery_phrase\">\n        <app-section class=\"phrase\">\n          {{ computedPhrase }}\n        </app-section>\n      </content-wrapper>\n    </div>\n\n    <div class=\"flex-1\"></div>\n\n    <app-button-section>\n      <button @click=\"viewRecoveryPhrase\" v-if=\"!recoveryPhrase\">\n        {{ $t(\"buttons.unlock\") }}\n      </button>\n      <button @click=\"back\">\n        {{ $t(\"buttons.back\") }}\n      </button>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\nimport EventBus from \"../../EventBus\";\nimport { LibraryController } from \"../../unity/Controllers\";\n\nexport default {\n  data() {\n    return {\n      recoveryPhrase: null\n    };\n  },\n  computed: {\n    ...mapState(\"wallet\", [\"unlocked\"]),\n    computedPhrase() {\n      if (this.recoveryPhrase !== null) return this.recoveryPhrase;\n      else return \"In order to see your recovery phrase you need to unlock your wallet\";\n    }\n  },\n  watch: {\n    unlocked: {\n      immediate: true,\n      handler() {\n        if (this.unlocked) {\n          this.viewRecoveryPhrase();\n        }\n      }\n    }\n  },\n  methods: {\n    viewRecoveryPhrase() {\n      if (this.recoveryPhrase) return;\n      EventBus.$emit(\"unlock-wallet\", {\n        callback: async () => {\n          this.recoveryPhrase = LibraryController.GetRecoveryPhrase().phrase;\n        }\n      });\n    },\n    back() {\n      this.$router.push({ name: \"settings\" });\n    },\n    routeTo(route) {\n      this.$router.push({ name: route });\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.view-recovery-phrase-view {\n  display: flex;\n  height: 100%;\n  flex-direction: column;\n  flex-wrap: nowrap;\n  justify-content: space-between;\n}\n\n.phrase {\n  padding: 15px;\n  font-size: 1.05em;\n  font-weight: 500;\n  text-align: center;\n  word-spacing: 4px;\n  background-color: #f5f5f5;\n  user-select: none;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Settings/index.vue",
    "content": "<template>\n  <div class=\"settings-main\">\n    <router-view />\n  </div>\n</template>\n\n<style>\n.settings-main {\n  height: 100%;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/views/Setup.vue",
    "content": "<template>\n  <div class=\"setup-view flex-col\">\n    <div class=\"steps-container\">\n      <!-- step 1: choose setup type -->\n      <content-wrapper heading=\"setup.setup_your_wallet\" v-if=\"current === 1\">\n        <div class=\"settings-row\" @click=\"setupWallet(false)\">\n          {{ $t(\"setup.create_new\") }}\n          <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n        </div>\n        <div class=\"settings-row\" @click=\"setupWallet(true)\">\n          {{ $t(\"setup.recover_existing\") }}\n          <fa-icon :icon=\"['fal', 'chevron-right']\" class=\"arrow\" />\n        </div>\n      </content-wrapper>\n\n      <!-- step 2: show recovery phrase -->\n      <content-wrapper heading=\"common.important\" headingStyle=\"warning\" content=\"setup.this_is_your_recovery_phrase\" v-else-if=\"current === 2\">\n        <app-section class=\"phrase\">\n          {{ recoveryPhrase }}\n        </app-section>\n      </content-wrapper>\n\n      <!-- step 3: enter/repeat recovery phrase -->\n      <content-wrapper\n        heading=\"setup.enter_recovery_phrase\"\n        :content=\"isRecovery ? 'setup.this_is_your_recovery_phrase' : 'setup.enter_existing_recovery_phrase'\"\n        v-else-if=\"current === 3\"\n      >\n        <phrase-input\n          ref=\"phraseinput\"\n          :validate=\"validate\"\n          :autofocus=\"true\"\n          :isPhraseInvalid=\"isRecoveryPhraseInvalid === true\"\n          :reset=\"reset\"\n          @possible-phrase=\"onPossiblePhrase\"\n          @enter=\"validatePhraseOnEnter\"\n        />\n      </content-wrapper>\n\n      <!-- step 4: enter a password -->\n      <content-wrapper heading=\"setup.choose_password\" content=\"setup.choose_password_information\" v-else-if=\"current === 4\">\n        <app-form-field title=\"common.password\">\n          <input ref=\"password\" type=\"password\" v-model=\"password1\" />\n        </app-form-field>\n        <app-form-field title=\"setup.repeat_password\">\n          <input type=\"password\" v-model=\"password2\" :class=\"password2Status\" @keydown=\"validatePasswordsOnEnter\" />\n        </app-form-field>\n      </content-wrapper>\n    </div>\n\n    <app-button-section class=\"steps-buttons\">\n      <template slot:left>\n        <button v-if=\"showPreviousButton\" @click=\"previousStep\">\n          {{ $t(\"buttons.previous\") }}\n        </button>\n      </template>\n      <template v-slot:right>\n        <button @click=\"nextStep\" :disabled=\"!isNextEnabled\">\n          <span v-show=\"showNextButton\">\n            {{ $t(\"buttons.next\") }}\n          </span>\n          <span v-show=\"showFinishButton\">\n            {{ $t(\"buttons.finish\") }}\n          </span>\n        </button>\n        <button @click=\"nextStep\" v-show=\"showValidateButton\" :disabled=\"!isValidateButtonEnabled\">\n          {{ $t(\"buttons.next\") }}\n        </button>\n      </template>\n    </app-button-section>\n  </div>\n</template>\n\n<script>\nimport { LibraryController } from \"../unity/Controllers\";\nimport PhraseInput from \"../components/PhraseInput\";\nimport EventBus from \"../EventBus.js\";\nimport AppStatus from \"../AppStatus\";\nimport ContentWrapper from \"../components/layout/ContentWrapper.vue\";\n\nexport default {\n  data() {\n    return {\n      current: 1,\n      isRecovery: null,\n      recoveryPhrase: \"\",\n      possiblePhrase: null,\n      isRecoveryPhraseInvalid: null,\n      generatedRecoveryPhrase: null,\n      password1: \"\",\n      password2: \"\",\n      reset: false\n    };\n  },\n  components: {\n    PhraseInput,\n    ContentWrapper\n  },\n  computed: {\n    validate() {\n      if (this.isRecovery) {\n        return {\n          length: 12,\n          words: LibraryController.GetMnemonicDictionary()\n        };\n      } else {\n        return this.recoveryPhrase;\n      }\n    },\n    password2Status() {\n      if (this.password2.length === 0) return \"\";\n      if (this.password2.length > this.password1.length) return \"error\";\n      return this.password1.indexOf(this.password2) === 0 ? \"\" : \"error\";\n    },\n    passwordsValidated() {\n      if (this.password1 === null || this.password1.length < 6) return false;\n      if (this.password2 === null || this.password2.length < this.password1.length) return false;\n\n      return this.password1 === this.password2;\n    },\n    showPreviousButton() {\n      return this.current === 2 || this.current === 3;\n    },\n    showNextButton() {\n      return this.current === 2;\n    },\n    showValidateButton() {\n      return this.current === 3;\n    },\n    showFinishButton() {\n      return this.current === 4;\n    },\n    isNextEnabled() {\n      switch (this.current) {\n        case 2:\n          return this.recoveryPhrase !== null;\n        case 4:\n          return this.passwordsValidated;\n      }\n      return false;\n    },\n    isValidateButtonEnabled() {\n      return this.possiblePhrase !== null && this.isRecoveryPhraseInvalid !== true;\n    },\n    validateButtonClass() {\n      return this.isRecoveryPhraseInvalid ? \"error\" : \"\";\n    }\n  },\n  watch: {\n    current() {\n      let current = this.current;\n\n      this.$nextTick(() => {\n        switch (current) {\n          case 1:\n            this.isRecovery = null;\n            break;\n          case 4:\n            this.$refs.password.focus();\n            break;\n        }\n      });\n    }\n  },\n  methods: {\n    setupWallet(isRecovery) {\n      this.isRecovery = isRecovery;\n      this.nextStep();\n    },\n    nextStep() {\n      let next = this.current + 1;\n\n      switch (this.current) {\n        case 1:\n          if (this.isRecovery) {\n            this.recoveryPhrase = \"\";\n            next = 3;\n          } else {\n            if (this.generatedRecoveryPhrase === null) {\n              var mnemonic = LibraryController.GenerateRecoveryMnemonic();\n              this.generatedRecoveryPhrase = mnemonic.phrase_with_birth_number;\n              this.recoveryPhrase = mnemonic.phrase;\n            }\n          }\n          break;\n        case 3:\n          if (LibraryController.IsValidRecoveryPhrase(this.possiblePhrase)) {\n            this.recoveryPhrase = this.possiblePhrase;\n          } else {\n            EventBus.$emit(\"show-dialog\", {\n              type: \"error\",\n              title: this.$t(\"setup.invalid_recovery_phrase.title\"),\n              message: this.$t(\"setup.invalid_recovery_phrase.message\")\n            });\n\n            this.isRecoveryPhraseInvalid = true;\n            return;\n          }\n          break;\n        case 4:\n          if (this.isRecovery) {\n            if (LibraryController.InitWalletFromRecoveryPhrase(this.recoveryPhrase, this.password1)) {\n              this.$store.dispatch(\"app/SET_STATUS\", AppStatus.synchronize);\n            }\n          } else {\n            if (LibraryController.InitWalletFromRecoveryPhrase(this.generatedRecoveryPhrase, this.password1)) {\n              this.$store.dispatch(\"app/SET_STATUS\", AppStatus.synchronize);\n            }\n          }\n          break;\n      }\n      this.current = next;\n    },\n    previousStep() {\n      if (this.current === 3 && this.isRecovery) this.current = 1;\n      else this.current--;\n    },\n    recoverFromPhrase() {\n      this.isRecovery = true;\n      this.nextStep();\n    },\n    onPossiblePhrase(phrase) {\n      this.isRecoveryPhraseInvalid = null;\n      this.possiblePhrase = phrase;\n    },\n    validatePhraseOnEnter() {\n      if (this.possiblePhrase !== null) {\n        this.nextStep();\n      }\n    },\n    validatePasswordsOnEnter() {\n      if (event.keyCode === 13 && this.passwordsValidated) this.nextStep();\n    }\n  }\n};\n</script>\n\n<style lang=\"less\" scoped>\n.setup-view {\n  height: 100%;\n}\n\n.steps-container {\n  flex: 1;\n}\n\n.settings-row {\n  margin: 0 -10px;\n  padding: 10px;\n  cursor: pointer;\n}\n\n.settings-row:hover {\n  color: var(--primary-color);\n  background-color: var(--hover-color);\n}\n\n.arrow {\n  float: right;\n  color: #000;\n}\n\n.settings-row:hover > .arrow {\n  color: #000;\n}\n\n.phrase {\n  padding: 10px;\n  font-size: 1.05em;\n  font-weight: 500;\n  text-align: center;\n  word-spacing: 4px;\n  background-color: #f5f5f5;\n}\n</style>\n"
  },
  {
    "path": "src/frontend/lite/src/walletPath.js",
    "content": "import { app } from \"electron\";\n\nconst isDevelopment = process.env.NODE_ENV !== \"production\";\nimport os from \"os\";\nimport path from \"path\";\n\nlet walletPath = \"\";\n\nif (process.type !== \"renderer\") {\n  if (os.platform() === \"linux\") {\n    walletPath = path.join(app.getPath(\"home\"), isDevelopment ? \".munt_lite_dev\" : \".munt_lite\");\n  } else {\n    walletPath = app.getPath(\"userData\");\n    if (isDevelopment) walletPath = walletPath + \"_dev\";\n  }\n}\n\nexport default walletPath;\n"
  },
  {
    "path": "src/frontend/lite/ui-config.json",
    "content": "{\n  \"isSingleAccount\": true,\n  \"isSPV\": true,\n  \"themes\": [\n    { \"name\": \"black\", \"color\": \"#000000\" },\n    { \"name\": \"orange\", \"color\": \"#ee6622\" }\n  ]\n}\n"
  },
  {
    "path": "src/frontend/lite/vue.config.js",
    "content": "module.exports = {\n  configureWebpack: {\n    // Configuration applied to all builds\n  },\n  pluginOptions: {\n    electronBuilder: {\n      nodeIntegration: true,\n      mainProcessWatch: [],\n      mainProcessArgs: [],\n      builderOptions: {\n        appId: \"org.munt.lite-desktop-wallet\",\n        productName: \"Munt-lite\",\n        extraFiles: [],\n        publish: null,\n        afterSign: \"./notarize.js\",\n        protocols: [\n          {\n            name: \"muntlite\",\n            role: \"Viewer\",\n            schemes: [\"muntlite\", \"munt\"]\n          }\n        ],\n        mac: {\n          category: \"public.app-category.finance\",\n          asar: false,\n          hardenedRuntime: true\n        },\n        win: {\n          sign: \"./sign.js\"\n        },\n        linux: {\n          category: \"public.app-category.finance\"\n        },\n        dmg: {\n          background: \"./build/background.tiff\",\n          contents: [\n            {\n              x: 410,\n              y: 190,\n              type: \"link\",\n              path: \"/Applications\"\n            },\n            {\n              x: 130,\n              y: 190,\n              type: \"file\"\n            }\n          ]\n        }\n      },\n      // HACK! Work around issues with electron-vue-builder being too old and new webpack... (files not loading without this)\n      customFileProtocol: \"./\"\n    },\n    i18n: {\n      locale: \"en\",\n      fallbackLocale: \"en\",\n      localeDir: \"locales\",\n      enableInSFC: false\n    }\n  },\n  css: {\n    loaderOptions: {\n      less: {},\n      postcss: { postcssOptions: { config: false } }\n    }\n  }\n};\n\n// HACK: OpenSSL 3 does not support md4 any more, but webpack hardcodes it all over the place: https://github.com/webpack/webpack/issues/13572\nconst crypto = require(\"crypto\");\nconst crypto_orig_createHash = crypto.createHash;\ncrypto.createHash = algorithm => crypto_orig_createHash(algorithm == \"md4\" ? \"sha256\" : algorithm);\n"
  },
  {
    "path": "src/fs.cpp",
    "content": "#include \"fs.h\"\n\nnamespace fsbridge {\n\nFILE *fopen(const fs::path& p, const char *mode)\n{\n    return ::fopen(p.string().c_str(), mode);\n}\n\nFILE *freopen(const fs::path& p, const char *mode, FILE *stream)\n{\n    return ::freopen(p.string().c_str(), mode, stream);\n}\n\n} // fsbridge\n"
  },
  {
    "path": "src/fs.h",
    "content": "// Copyright (c) 2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef FS_BRIDGE_H\n#define FS_BRIDGE_H\n\n#include <stdio.h>\n#include <string>\n\n#include <boost/filesystem.hpp>\n#include <boost/filesystem/fstream.hpp>\n#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>\n\n/** Filesystem operations and types */\nnamespace fs = boost::filesystem;\n\n/** Bridge operations to C stdio */\nnamespace fsbridge {\n    FILE *fopen(const fs::path& p, const char *mode);\n    FILE *freopen(const fs::path& p, const char *mode, FILE *stream);\n};\n\n#endif\n"
  },
  {
    "path": "src/generation/generation.h",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef GENERATION_GENERATION_H\n#define GENERATION_GENERATION_H\n\n#include \"sync.h\" //CCriticalSection\n#include \"script/script.h\"\n\n#ifdef ENABLE_WALLET\n#include \"pubkey.h\"\n\nclass CWallet;\nclass CAccount;\n/** A key allocated from the key pool. */\nclass CReserveKeyOrScript : public CReserveScript\n{\nprotected:\n    CWallet* pwallet;\n    int64_t nIndex;\n    int64_t nKeyChain;\n    CPubKey vchPubKey;\n    CKeyID pubKeyID;\npublic:\n    //fixme: (POST-PHASE5): make private again.\n    CAccount* account;\n    CReserveKeyOrScript(CWallet* pwalletIn, CAccount* forAccount, int64_t forKeyChain);\n    CReserveKeyOrScript(CScript& script);\n    CReserveKeyOrScript(CPubKey &pubkey);\n    CReserveKeyOrScript(CKeyID &pubKeyID_);\n    CReserveKeyOrScript() = default;\n    CReserveKeyOrScript(const CReserveKeyOrScript&) = delete;\n    CReserveKeyOrScript& operator=(const CReserveKeyOrScript&) = delete;\n    CReserveKeyOrScript(CReserveKeyOrScript&&) = default;\n    CReserveKeyOrScript& operator=(CReserveKeyOrScript&&) = default;\n    virtual ~CReserveKeyOrScript();\n    bool scriptOnly();\n    void ReturnKey();\n    bool GetReservedKey(CPubKey &pubkey);\n    bool GetReservedKeyID(CKeyID &pubKeyID_);\n    void KeepKey();\n    void KeepScript() override;\n    void keepScriptOnDestroy() override;\nprivate:\n    bool shouldKeepOnDestroy=false;\n};\n#else\ntypedef CReserveScript CReserveKeyOrScript;\n#endif\n\n//! Prevent both mining and witnessing from trying to process a block at the same time.\nextern RecursiveMutex processBlockCS;\n\n#endif\n"
  },
  {
    "path": "src/generation/miner.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"generation/generation.h\"\n#include \"miner.h\"\n\n#include \"net.h\"\n\n#include \"alert.h\"\n#include \"amount.h\"\n#include \"appname.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"coins.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/merkle.h\"\n#include \"consensus/validation.h\"\n#include \"hash.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"policy/feerate.h\"\n#include \"policy/policy.h\"\n#include \"pow/pow.h\"\n#include \"primitives/transaction.h\"\n#include \"script/standard.h\"\n#include \"timedata.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/threadnames.h\"\n#include \"util/time.h\"\n#include \"util/moneystr.h\"\n#include \"validation/validationinterface.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/extwallet.h>\n#endif\n\n#include <algorithm>\n#include <queue>\n#include <utility>\n\n#include <pow/diff.h>\n#include <crypto/hash/hash.h>\n#include <witnessutil.h>\n#include <openssl/sha.h>\n\n#include <boost/thread.hpp>\n\n#include \"txdb.h\"\n\n//Munt includes\n#include \"streams.h\"\n#include <boost/scope_exit.hpp>\n\n#include \"base58.h\"\n\n//\n// Unconfirmed transactions in the memory pool often depend on other\n// transactions in the memory pool. When we select transactions from the\n// pool, we select by highest fee rate of a transaction combined with all\n// its ancestors.\nuint64_t nLastBlockTx = 0;\nuint64_t nLastBlockSize = 0;\nuint64_t nLastBlockWeight = 0;\n\nuint64_t CalculateMissedTimeSteps(uint64_t nEnd, uint64_t nStart)\n{\n    static const uint64_t nDrift   = 1;\n    static uint64_t nLongTimeLimit = ((6 * nDrift)) * 60;\n    static uint64_t nLongTimeStep  = nDrift * 60;\n    uint64_t nNumMissedSteps = 0;\n    if ((nEnd - nStart) > nLongTimeLimit)\n    {\n        nNumMissedSteps = ((nEnd - nStart - nLongTimeLimit) / nLongTimeStep) + 1;\n    }\n    return nNumMissedSteps;\n}\n\nuint64_t GetAdjustedFutureTime()\n{\n    return GetAdjustedTime()+MAX_FUTURE_BLOCK_TIME-1;\n}\n\nint64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)\n{\n    int64_t nOldTime = pblock->nTime;\n    int64_t nNewTime = std::max((uint64_t)pindexPrev->GetMedianTimePastWitness()+1, GetAdjustedFutureTime());\n\n    if (nOldTime < nNewTime)\n        pblock->nTime = nNewTime;\n\n    //fixme: (PHASE5) - We can likely remove this\n    // Allow miners to control maximum diff drop to suit their hashrate (prevent sudden self-ddos from 100s of blocks being found per second)\n    int64_t nMaxMissedSteps = GetArg(\"-limitdeltadiffdrop\", 5000);\n    // Forbid diff drop when mining on a fork (stalled witness)\n    {\n        LOCK(cs_main);\n        if (chainActive.Tip() && (pindexPrev->nHeight > chainActive.Tip()->nHeight))\n        {\n            nMaxMissedSteps=0;\n        }\n    }\n\n    if (pindexPrev->pprev)\n    {\n        while (pblock->nTime - 10 > pindexPrev->GetMedianTimePastWitness()+1)\n        {\n            int64_t nNumMissedSteps = CalculateMissedTimeSteps(pblock->nTime, pindexPrev->GetBlockTime());        \n            if (nNumMissedSteps <= nMaxMissedSteps)\n                break;\n            pblock->nTime -= 10;\n        }\n    }\n    \n    if (pblock->nTime <= pindexPrev->GetMedianTimePastWitness())\n    {\n        pblock->nTime = pindexPrev->GetMedianTimePastWitness()+1;\n    }\n\n    // Updating time can change work required (Delta)\n    pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);\n\n    return nNewTime - nOldTime;\n}\n\nBlockAssembler::Options::Options() {\n    blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);\n    nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;\n    nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;\n}\n\nBlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)\n{\n    blockMinFeeRate = options.blockMinFeeRate;\n    // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:\n    nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));\n    // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:\n    nBlockMaxSize = std::max<size_t>(1000, std::min<size_t>(MAX_BLOCK_SERIALIZED_SIZE - 1000, options.nBlockMaxSize));\n    // Whether we need to account for byte usage (in addition to weight usage)\n    fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE - 1000);\n}\n\nstatic BlockAssembler::Options DefaultOptions(const CChainParams& params)\n{\n    // Block resource limits\n    // If neither -blockmaxsize or -blockmaxweight is given, limit to DEFAULT_BLOCK_MAX_*\n    // If only one is given, only restrict the specified resource.\n    // If both are given, restrict both.\n    BlockAssembler::Options options;\n    options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;\n    options.nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;\n    bool fWeightSet = false;\n    if (IsArgSet(\"-blockmaxweight\")) {\n        options.nBlockMaxWeight = GetArg(\"-blockmaxweight\", DEFAULT_BLOCK_MAX_WEIGHT);\n        options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;\n        fWeightSet = true;\n    }\n    if (IsArgSet(\"-blockmaxsize\")) {\n        options.nBlockMaxSize = GetArg(\"-blockmaxsize\", DEFAULT_BLOCK_MAX_SIZE);\n        if (!fWeightSet) {\n            options.nBlockMaxWeight = options.nBlockMaxSize;\n        }\n    }\n    if (IsArgSet(\"-blockmintxfee\")) {\n        CAmount n = 0;\n        ParseMoney(GetArg(\"-blockmintxfee\", \"\"), n);\n        options.blockMinFeeRate = CFeeRate(n);\n    } else {\n        options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);\n    }\n    return options;\n}\n\nBlockAssembler::BlockAssembler(const CChainParams& params)\n: BlockAssembler(params, DefaultOptions(params))\n{\n}\n\nvoid BlockAssembler::resetBlock()\n{\n    inBlock.clear();\n\n    // Reserve space for coinbase tx\n    nBlockSize = 1000;\n    nBlockWeight = 4000;\n    nBlockSigOpsCost = 400;\n    fIncludeSegSig = false;\n\n    // These counters do not include coinbase tx\n    nBlockTx = 0;\n    nFees = 0;\n}\n\n\nstatic bool InsertPoW2WitnessIntoCoinbase(CBlock& block, const CBlockIndex* pindexPrev, const CChainParams& params, CBlockIndex* pWitnessBlockToEmbed, int nParentPoW2Phase)\n{\n    assert(pindexPrev->nHeight == pWitnessBlockToEmbed->nHeight);\n    assert(pindexPrev->pprev == pWitnessBlockToEmbed->pprev);\n\n    // Phase 3 restriction - we force the miners nVersion to reflect the version the witness of the block before had - thus allowing control of voting for phase 4 to be controlled by witnesses.\n    block.nVersion = pWitnessBlockToEmbed->nVersionPoW2Witness;\n\n    std::vector<unsigned char> commitment;\n    int commitpos = GetPoW2WitnessCoinbaseIndex(block);\n\n    assert(pWitnessBlockToEmbed);\n    std::shared_ptr<CBlock> pWitnessBlock(new CBlock);\n    {\n        LOCK(cs_main); // For ReadBlockFromDisk\n        if (!ReadBlockFromDisk(*pWitnessBlock, pWitnessBlockToEmbed, params))\n            return error(\"PoWGenerate: Could not read witness block in order to insert into coinbase. pindexprev=%s pWitnessBlockToEmbed=%s\", pindexPrev->GetBlockHashPoW2().ToString(), pWitnessBlockToEmbed->GetBlockHashPoW2().ToString());\n    }\n\n    if (commitpos == -1)\n    {\n        std::vector<unsigned char> serialisedWitnessHeaderInfo;\n        {\n            CVectorWriter serialisedWitnessHeaderInfoStream(SER_NETWORK, INIT_PROTO_VERSION, serialisedWitnessHeaderInfo, 0);\n            ::Serialize(serialisedWitnessHeaderInfoStream, pWitnessBlockToEmbed->nVersionPoW2Witness); //4 bytes\n            ::Serialize(serialisedWitnessHeaderInfoStream, pWitnessBlockToEmbed->nTimePoW2Witness); //4 bytes\n            ::Serialize(serialisedWitnessHeaderInfoStream, pWitnessBlockToEmbed->hashMerkleRootPoW2Witness); // 32 bytes\n            ::Serialize(serialisedWitnessHeaderInfoStream, NOSIZEVECTOR(pWitnessBlockToEmbed->witnessHeaderPoW2Sig)); //65 bytes\n            ::Serialize(serialisedWitnessHeaderInfoStream, pindexPrev->GetBlockHashLegacy()); //32 bytes\n        }\n\n        assert(serialisedWitnessHeaderInfo.size() == 137);\n\n        CTxOut out;\n        out.nValue = 0;\n        out.output.scriptPubKey.resize(143); // 1 + 5 + 137\n        out.output.scriptPubKey[0] = OP_RETURN;\n        // 0x506f57c2b2 = PoW²\n        out.output.scriptPubKey[1] = 0x50;\n        out.output.scriptPubKey[2] = 0x6f;\n        out.output.scriptPubKey[3] = 0x57;\n        out.output.scriptPubKey[4] = 0xc2;\n        out.output.scriptPubKey[5] = 0xb2;\n        std::copy(serialisedWitnessHeaderInfo.begin(), serialisedWitnessHeaderInfo.end(), out.output.scriptPubKey.begin()+6);\n\n        unsigned int nWitnessCoinbasePos = 0;\n        for (unsigned int i = 0; i < pWitnessBlock->vtx.size(); i++)\n        {\n            if (pWitnessBlock->vtx[i]->IsPoW2WitnessCoinBase())\n            {\n                nWitnessCoinbasePos = i;\n                break;\n            }\n        }\n        assert(nWitnessCoinbasePos != 0);\n\n        // Append to the coinbase a single output containing:\n        // Serialised PoW2 witness header (witness portion only)\n        // Followed by a single transaction for the witness reward (20 NLG witness reward)\n        {\n            CMutableTransaction coinbaseTx(*block.vtx[0]);\n            coinbaseTx.vout.push_back(out);\n            coinbaseTx.vout.push_back(pWitnessBlock->vtx[nWitnessCoinbasePos]->vout[1]); // Witness subsidy\n            block.vtx[0] = MakeTransactionRef(std::move(coinbaseTx));\n        }\n\n        // Straight after coinbase we must contain the witness transaction, which contains a single input and two outputs, the single witness output and a 'fake' output containing nothing but OP_RETURN and the blockheight.\n        // The second fake output is required to ensure that the witness transaction has a different hash for every block.\n        CMutableTransaction witnessTx(1);\n        witnessTx.vin.push_back(pWitnessBlock->vtx[nWitnessCoinbasePos]->vin[1]); // old selectedWitnessOutPoint\n        witnessTx.vout.push_back(pWitnessBlock->vtx[nWitnessCoinbasePos]->vout[0]); // new selectedWitnessOutPoint\n        CTxOut fakeOut; fakeOut.output.scriptPubKey = CScript() << OP_RETURN << pindexPrev->nHeight + 1; fakeOut.nValue = 0;\n        witnessTx.vout.push_back(fakeOut);\n        block.vtx.insert(block.vtx.begin()+1, MakeTransactionRef(std::move(witnessTx)));\n    }\n    return true;\n}\n\n\n\nstd::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CBlockIndex* pParent, std::shared_ptr<CReserveKeyOrScript> coinbaseReservedKey, bool fMineSegSig, CBlockIndex* pWitnessBlockToEmbed, bool noValidityCheck, uint32_t nExtraNonce)\n{\n    fMineSegSig = true;\n\n    int64_t nTimeStart = GetTimeMicros();\n\n    resetBlock();\n\n    pblocktemplate.reset(new CBlockTemplate());\n\n    if(!pblocktemplate.get())\n        return nullptr;\n    pblock = &pblocktemplate->block; // pointer for convenience\n\n    // Add dummy coinbase tx as first transaction\n    pblock->vtx.emplace_back();\n    pblocktemplate->vTxFees.push_back(-1); // updated at end\n    pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end\n\n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    nHeight = pParent->nHeight + 1;\n\n    int nParentPoW2Phase = GetPoW2Phase(pParent);\n    int nGrandParentPoW2Phase = GetPoW2Phase(pParent->pprev);\n    bool bSegSigIsEnabled = IsSegSigEnabled(pParent->pprev?pParent->pprev:pParent);\n\n    //Until PoW2 activates mining subsidy remains full, after it activates PoW part of subsidy is reduced.\n    //fixme: (PHASE5) (CLEANUP) - We can remove this after phase4 becomes active.\n    Consensus::Params consensusParams = chainparams.GetConsensus();\n    CAmount nSubsidy = GetBlockSubsidy(nHeight).total;\n    CAmount nSubsidyWitness = 0;\n    if (nParentPoW2Phase >= 3)\n    {\n        nSubsidyWitness = GetBlockSubsidy(nHeight).witness;\n        nSubsidy -= nSubsidyWitness;\n    }\n\n\n    // First 'active' block of phase 4 (first block with a phase 4 parent) contains two witness subsidies so miner loses out on 20 NLG for this block\n    // This block is treated special. (but special casing can dissapear for PHASE5 release.\n    if (nGrandParentPoW2Phase == 3 && nParentPoW2Phase == 4)\n        nSubsidy -= GetBlockSubsidy(nHeight-1).witness;\n    \n    CAmount nSubsidyDev = GetBlockSubsidy(nHeight).dev;\n    nSubsidy -= nSubsidyDev;\n\n    // PoW mining on top of a PoS block during phase 3 indicates an error of some kind.\n    if (nParentPoW2Phase <= 3)\n        assert(pParent->nVersionPoW2Witness == 0);\n\n    pblock->nVersion = ComputeBlockVersion(pParent, consensusParams);\n    // -regtest only: allow overriding block.nVersion with\n    // -blockversion=N to test forking scenarios\n    if (chainparams.MineBlocksOnDemand())\n        pblock->nVersion = GetArg(\"-blockversion\", pblock->nVersion);\n\n    pblock->nTime = GetAdjustedFutureTime();\n\n    const int64_t nMedianTimePast = pParent->GetMedianTimePastWitness();\n\n    nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)\n                       ? nMedianTimePast\n                       : pblock->GetBlockTime();\n\n    int nPackagesSelected = 0;\n    int nDescendantsUpdated = 0;\n\n    bool miningBelowTip=false;\n\n    // For phase 3 we need to do some gymnastics to ensure the right chain tip before calling TestBlockValidity.\n    CValidationState state;\n    CCoinsViewCache viewNew(pcoinsTip);\n    CBlockIndex* pindexPrev_ = nullptr;\n    CCloneChain tempChain(chainActive, GetPow2ValidationCloneHeight(chainActive, pParent, 1), pParent, pindexPrev_);\n    assert(pindexPrev_);\n    ForceActivateChain(pindexPrev_, nullptr, state, chainparams, tempChain, viewNew);\n    {\n        LOCK(mempool.cs);\n\n        // Decide whether to include segsig signature information\n        // This is only needed in case the segsig signature activation is reverted\n        // (which would require a very deep reorganization) or when\n        // -promiscuousmempoolflags is used.\n        // TODO: replace this with a call to main to assess validity of a mempool\n        // transaction (which in most cases can be a no-op).\n        fIncludeSegSig = bSegSigIsEnabled && fMineSegSig;\n\n        // The transaction canibilisation code is complex, and seems to be causing some very rare but difficult to isolate issues\n        // For now we disable it to see if it fixes the stability issues we were seeing\n        // We can add it back later once we are more certain.\n        //\n        // For now we just mine an empty block instead.\n        #if 1\n        if (nHeight <= chainActive.Tip()->nHeight)\n        {\n            miningBelowTip = true;\n        }\n        #else\n        // If we are mining below the tip (orphaned tip due to absent witness) - it is desirable to include first all transactions that are in the tip.\n        // If we do not do this we can end up creating invalid blocks, due to the fact that we don't rewind the mempool here\n        // Which can lead to inclusion of transactions without their ancestors (ancestors are in tip) for instance.\n        // It is also however beneficial to the chain that transactions already in the chain stay in the chain for new block...\n        std::deque<CBlockIndex*> canabalizeBlocks;\n        CBlockIndex* pCannibalTip = chainActive.Tip();\n        while (nHeight <= pCannibalTip->nHeight)\n        {\n            canabalizeBlocks.push_front(pCannibalTip);\n            pCannibalTip = pCannibalTip->pprev;\n        }\n        std::vector<CTransactionRef> canabalizeTransactions;\n        for (const auto& pIndexCannibalBlock : canabalizeBlocks)\n        {\n            std::shared_ptr<CBlock> pBlockCannibal(new CBlock);\n            if (!ReadBlockFromDisk(*pBlockCannibal.get(), pIndexCannibalBlock, Params()))\n            {\n                LogPrintf(\"Error in CreateNewBlock: could not read block from disk.\\n\");\n                return nullptr;\n            }\n            //fixme: (PHASE5)\n            // We don't want to canabalize coinbase transaction or 'witness refresh' transaction as these are 'generated' by miner and not actual transactions.\n            for (uint32_t i = (bSegSigIsEnabled?1:2); i < pBlockCannibal.get()->vtx.size(); ++i)\n            {\n                canabalizeTransactions.push_back(pBlockCannibal.get()->vtx[i]);\n            }\n        }\n        addPackageTxs(nPackagesSelected, nDescendantsUpdated, &canabalizeTransactions, &viewNew);\n        #endif\n        if (!miningBelowTip)\n        {\n            addPackageTxs(nPackagesSelected, nDescendantsUpdated, nullptr, nullptr);\n        }\n    }\n\n    int64_t nTime1 = GetTimeMicros();\n\n    nLastBlockTx = nBlockTx;\n    nLastBlockSize = nBlockSize;\n    nLastBlockWeight = nBlockWeight;\n\n    // Create coinbase transaction.\n    CMutableTransaction coinbaseTx( bSegSigIsEnabled ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1);\n    coinbaseTx.vin.resize(1);\n    coinbaseTx.vin[0].SetPrevOutNull();\n    coinbaseTx.vout.resize((nSubsidyDev>0)?2:1);\n    #ifdef ENABLE_WALLET\n    CKeyID pubKeyID;\n    if (bSegSigIsEnabled && !coinbaseReservedKey->scriptOnly() && coinbaseReservedKey->GetReservedKeyID(pubKeyID))\n    {\n        coinbaseTx.vout[0].SetType(CTxOutType::StandardKeyHashOutput);\n        coinbaseTx.vout[0].output.standardKeyHash = CTxOutStandardKeyHash(pubKeyID);\n    }\n    else\n    #endif\n    {\n        coinbaseTx.vout[0].SetType(CTxOutType::ScriptLegacyOutput);\n        coinbaseTx.vout[0].output.scriptPubKey = coinbaseReservedKey->reserveScript;\n    }\n    coinbaseTx.vout[0].nValue = nFees + nSubsidy;\n    \n    if (nSubsidyDev > 0)\n    {\n        std::string devSubsidyAddressFinal = devSubsidyAddress1;\n        if (nSubsidyDev > 1'000'000*COIN)\n        {\n            devSubsidyAddressFinal = devSubsidyAddress2;\n        }\n        std::vector<unsigned char> data(ParseHex(devSubsidyAddressFinal));\n        CPubKey addressPubKey(data.begin(), data.end());\n        if (bSegSigIsEnabled)\n        {\n            coinbaseTx.vout[1].SetType(CTxOutType::StandardKeyHashOutput);\n            coinbaseTx.vout[1].output.standardKeyHash = CTxOutStandardKeyHash(addressPubKey.GetID());\n        }\n        else\n        {    \n            coinbaseTx.vout[1].SetType(CTxOutType::ScriptLegacyOutput);\n            coinbaseTx.vout[1].output.scriptPubKey = (CScript() << ToByteVector(addressPubKey) << OP_CHECKSIG);\n        }\n        coinbaseTx.vout[1].nValue = nSubsidyDev;\n    }\n\n    // Insert the height into the coinbase (to ensure all coinbase transactions have a unique hash)\n    // Further, also insert any optional 'signature' data (identifier of miner or other private miner data etc.)\n    std::string coinbaseSignature = GetArg(\"-coinbasesignature\", \"\");\n    if (bSegSigIsEnabled)\n    {\n        coinbaseTx.vin[0].segregatedSignatureData.stack.clear();\n        coinbaseTx.vin[0].segregatedSignatureData.stack.push_back(std::vector<unsigned char>());\n        CVectorWriter(0, 0, coinbaseTx.vin[0].segregatedSignatureData.stack[0], 0) << VARINT(nHeight);\n        std::string finalCoinbaseSignature = strprintf(\"%d%s\", nExtraNonce, coinbaseSignature.c_str());\n        coinbaseTx.vin[0].segregatedSignatureData.stack.push_back(std::vector<unsigned char>(finalCoinbaseSignature.begin(), finalCoinbaseSignature.end()));\n    }\n    else\n    {\n        coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0 << nExtraNonce << std::vector<unsigned char>(coinbaseSignature.begin(), coinbaseSignature.end());\n    }\n\n    pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));\n    pblocktemplate->vTxFees[0] = -nFees;\n\n    // From second 'active' phase 3 block (second block whose parent is phase 3) - embed the PoW2 witness. First doesn't have a witness to embed.\n    if (nGrandParentPoW2Phase == 3)\n    {\n        if (pWitnessBlockToEmbed)\n        {\n            //NB! Modifies block version so must be called *after* ComputeBlockVersion and not before.\n            if (!InsertPoW2WitnessIntoCoinbase(*pblock, pParent, chainparams, pWitnessBlockToEmbed, nParentPoW2Phase))\n                return nullptr;\n        }\n    }\n\n    // Until phase 4 activates we don't point to the hash of the previous PoW2 block but rather the hash of the previous PoW block (as we need to communicate with legacy clients that don't know about PoW blocks)\n    // We embed the hash of the contents of the PoW2 block in a special coinbase transaction.\n    if (nParentPoW2Phase >= 4)\n    {\n        pblock->hashPrevBlock  = pParent->GetBlockHashPoW2();\n    }\n    else\n    {\n        pblock->hashPrevBlock  = pParent->GetBlockHashLegacy();\n    }\n\n\n    //uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);\n    //LogPrintf(\"CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\\n\", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);\n\n    UpdateTime(pblock, consensusParams, pParent);\n    \n    if (pWitnessBlockToEmbed)\n    {\n        LogPrintf(\"CreateNewBlock: parent height [%d]; embedded witness height [%d]; our height [%d]; Difficulty [%d]\\n\", pParent->nHeight, pWitnessBlockToEmbed->nHeight, nHeight, GetHumanDifficultyFromBits(pblock->nBits));\n        assert(pParent->nHeight == pWitnessBlockToEmbed->nHeight);\n    }\n    else\n    {\n        LogPrintf(\"CreateNewBlock: parent height [%d]; our height [%d]; Difficulty [%d]\\n\", pParent->nHeight, nHeight, GetHumanDifficultyFromBits(pblock->nBits));\n    }\n\n    // (MUNT) Already done inside UpdateTime - don't need to do it again.\n    //pblock->nBits          = GetNextWorkRequired(pParent, pblock, consensusParams);\n    pblock->nNonce         = 0;\n    pblocktemplate->vTxSigOpsCost[0] = GetLegacySigOpCount(*pblock->vtx[0]);\n\n    if (!noValidityCheck && !TestBlockValidity(tempChain, state, chainparams, *pblock, pindexPrev_, false, false, &viewNew))\n    {\n        LogPrintf(\"Error in CreateNewBlock: TestBlockValidity failed.\\n\");\n        return nullptr;\n    }\n    int64_t nTime2 = GetTimeMicros();\n\n    LogPrint(BCLog::BENCH, \"CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\\n\", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));\n\n    return std::move(pblocktemplate);\n}\n\nvoid BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)\n{\n    for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) {\n        // Only test txs not already in the block\n        if (inBlock.count(*iit)) {\n            testSet.erase(iit++);\n        }\n        else {\n            iit++;\n        }\n    }\n}\n\nbool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost)\n{\n    // TODO: switch to weight-based accounting for packages instead of vsize-based accounting.\n    if (nBlockWeight + packageSize >= nBlockMaxWeight)\n        return false;\n    if (nBlockSigOpsCost + packageSigOpsCost >= MAX_BLOCK_SIGOPS_COST)\n        return false;\n    return true;\n}\n\n// Perform transaction-level checks before adding to block:\n// - transaction finality (locktime)\n// - premature segregated signatures (in case segsig transactions are added to mempool before phase 4 activation)\n// - serialized size (in case -blockmaxsize is in use)\nbool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)\n{\n    uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting\n    for (const CTxMemPool::txiter it : package) {\n        if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))\n            return false;\n        if (!fIncludeSegSig && it->GetTx().HasSegregatedSignatures())\n            return false;\n        CValidationState state;\n        if (!CheckTransactionContextual(it->GetTx(), state, nHeight))\n            return false;\n        if (fNeedSizeAccounting) {\n            uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);\n            if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) {\n                return false;\n            }\n            nPotentialBlockSize += nTxSize;\n        }\n    }\n    return true;\n}\n\nvoid BlockAssembler::AddToBlock(CTxMemPool::txiter iter)\n{\n    pblock->vtx.emplace_back(iter->GetSharedTx());\n    pblocktemplate->vTxFees.push_back(iter->GetFee());\n    pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());\n    if (fNeedSizeAccounting) {\n        nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION);\n    }\n    nBlockWeight += iter->GetTxWeight();\n    ++nBlockTx;\n    nBlockSigOpsCost += iter->GetSigOpCost();\n    nFees += iter->GetFee();\n    inBlock.insert(iter);\n\n    bool fPrintPriority = GetBoolArg(\"-printpriority\", DEFAULT_PRINTPRIORITY);\n    if (fPrintPriority) {\n        LogPrintf(\"fee %s txid %s\\n\",\n                  CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),\n                  iter->GetTx().GetHash().ToString());\n    }\n}\n\nint BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded,\n        indexed_modified_transaction_set &mapModifiedTx)\n{\n    int nDescendantsUpdated = 0;\n    for(const CTxMemPool::txiter it : alreadyAdded) {\n        CTxMemPool::setEntries descendants;\n        mempool.CalculateDescendants(it, descendants);\n        // Insert all descendants (not yet in block) into the modified set\n        for(CTxMemPool::txiter desc : descendants) {\n            if (alreadyAdded.count(desc))\n                continue;\n            ++nDescendantsUpdated;\n            modtxiter mit = mapModifiedTx.find(desc);\n            if (mit == mapModifiedTx.end()) {\n                CTxMemPoolModifiedEntry modEntry(desc);\n                modEntry.nSizeWithAncestors -= it->GetTxSize();\n                modEntry.nModFeesWithAncestors -= it->GetModifiedFee();\n                modEntry.nSigOpCostWithAncestors -= it->GetSigOpCost();\n                mapModifiedTx.insert(modEntry);\n            } else {\n                mapModifiedTx.modify(mit, update_for_parent_inclusion(it));\n            }\n        }\n    }\n    return nDescendantsUpdated;\n}\n\n// Skip entries in mapTx that are already in a block or are present\n// in mapModifiedTx (which implies that the mapTx ancestor state is\n// stale due to ancestor inclusion in the block)\n// Also skip transactions that we've already failed to add. This can happen if\n// we consider a transaction in mapModifiedTx and it fails: we can then\n// potentially consider it again while walking mapTx.  It's currently\n// guaranteed to fail again, but as a belt-and-suspenders check we put it in\n// failedTx and avoid re-evaluation, since the re-evaluation would be using\n// cached size/sigops/fee values that are not actually correct.\nbool BlockAssembler::SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx)\n{\n    assert (it != mempool.mapTx.end());\n    return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);\n}\n\nvoid BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries)\n{\n    // Sort package by ancestor count\n    // If a transaction A depends on transaction B, then A's ancestor count\n    // must be greater than B's.  So this is sufficient to validly order the\n    // transactions for block inclusion.\n    sortedEntries.clear();\n    sortedEntries.insert(sortedEntries.begin(), package.begin(), package.end());\n    std::sort(sortedEntries.begin(), sortedEntries.end(), CompareTxIterByAncestorCount());\n}\n\n// This transaction selection algorithm orders the mempool based\n// on feerate of a transaction including all unconfirmed ancestors.\n// Since we don't remove transactions from the mempool as we select them\n// for block inclusion, we need an alternate method of updating the feerate\n// of a transaction with its not-yet-selected ancestors as we go.\n// This is accomplished by walking the in-mempool descendants of selected\n// transactions and storing a temporary modified state in mapModifiedTxs.\n// Each time through the loop, we compare the best transaction in\n// mapModifiedTxs with the next transaction in the mempool to decide what\n// transaction package to work on next.\nvoid BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, std::vector<CTransactionRef>* pCannabalizeTransactions, CCoinsViewCache* pViewIn)\n{\n    // mapModifiedTx will store sorted packages after they are modified\n    // because some of their txs are already in the block\n    indexed_modified_transaction_set mapModifiedTx;\n    // Keep track of entries that failed inclusion, to avoid duplicate work\n    CTxMemPool::setEntries failedTx;\n\n    // First canabalise all the transactions from the existing chain that space will allow, in preserved order, only afterwards add new transactions.\n    if (pCannabalizeTransactions && pViewIn)\n    {\n        for (const auto& cannabalisedTransaction : *pCannabalizeTransactions)\n        {\n            if (nBlockWeight + GetTransactionWeight(*cannabalisedTransaction) > nBlockMaxWeight)\n                return;\n\n            pblock->vtx.push_back(cannabalisedTransaction);\n            int nFee = pViewIn->GetValueIn(*cannabalisedTransaction);\n            // If the inputs aren't in the cache they may also be canabalised so search the list for them\n            for (const auto& cannabalisedInputTransaction : *pCannabalizeTransactions)\n            {\n                for (const auto& thisTransactionInputs : cannabalisedTransaction->vin)\n                {\n                    uint256 txHash;\n                    if (GetTxHash(thisTransactionInputs.GetPrevOut(), txHash) && txHash == cannabalisedInputTransaction->GetHash())\n                    {\n                        nFee += cannabalisedInputTransaction->vout[thisTransactionInputs.GetPrevOut().n].nValue;\n                    }\n                }\n            }\n            nFee -= cannabalisedTransaction->GetValueOut();\n            pblocktemplate->vTxFees.push_back(nFee);\n            int nSigOpsCost = GetTransactionSigOpCost(*cannabalisedTransaction, *pViewIn, STANDARD_SCRIPT_VERIFY_FLAGS);\n            pblocktemplate->vTxSigOpsCost.push_back(nSigOpsCost);\n            if (fNeedSizeAccounting)\n            {\n                nBlockSize += ::GetSerializeSize(*cannabalisedTransaction, SER_NETWORK, PROTOCOL_VERSION);\n            }\n            nBlockWeight += GetTransactionWeight(*cannabalisedTransaction);\n            ++nBlockTx;\n            nBlockSigOpsCost += nSigOpsCost;\n            nFees += nFee;\n        }\n    }\n\n    // Start by adding all descendants of previously added txs to mapModifiedTx\n    // and modifying them for their already included ancestors\n    UpdatePackagesForAdded(inBlock, mapModifiedTx);\n\n\n\n    CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = mempool.mapTx.get<ancestor_score>().begin();\n    CTxMemPool::txiter iter;\n\n    // Limit the number of attempts to add transactions to the block when it is\n    // close to full; this is just a simple heuristic to finish quickly if the\n    // mempool has a lot of entries.\n    const int64_t MAX_CONSECUTIVE_FAILURES = 1000;\n    int64_t nConsecutiveFailed = 0;\n\n    while (mi != mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty())\n    {\n        // First try to find a new transaction in mapTx to evaluate.\n        if (mi != mempool.mapTx.get<ancestor_score>().end() && SkipMapTxEntry(mempool.mapTx.project<0>(mi), mapModifiedTx, failedTx)) {\n            ++mi;\n            continue;\n        }\n\n        // Now that mi is not stale, determine which transaction to evaluate:\n        // the next entry from mapTx, or the best from mapModifiedTx?\n        bool fUsingModified = false;\n\n        modtxscoreiter modit = mapModifiedTx.get<ancestor_score>().begin();\n        if (mi == mempool.mapTx.get<ancestor_score>().end())\n        {\n            // We're out of entries in mapTx; use the entry from mapModifiedTx\n            iter = modit->iter;\n            fUsingModified = true;\n        }\n        else\n        {\n            // Try to compare the mapTx entry to the mapModifiedTx entry\n            iter = mempool.mapTx.project<0>(mi);\n            if (modit != mapModifiedTx.get<ancestor_score>().end() && CompareModifiedEntry()(*modit, CTxMemPoolModifiedEntry(iter)))\n            {\n                // The best entry in mapModifiedTx has higher score\n                // than the one from mapTx.\n                // Switch which transaction (package) to consider\n                iter = modit->iter;\n                fUsingModified = true;\n            }\n            else\n            {\n                // Either no entry in mapModifiedTx, or it's worse than mapTx.\n                // Increment mi for the next loop iteration.\n                ++mi;\n            }\n        }\n\n        // If we are mining a side-chain (in the case of an absent PoW2 witness) we need to be careful not to include mempool transactions that may have already entered the chain.\n        if (pViewIn)\n        {\n            CTransactionRef transactionRef;\n            if (fUsingModified)\n                transactionRef = modit->iter->GetSharedTx();\n            else\n                transactionRef = iter->GetSharedTx();\n\n            bool transactionAlreadyInView = false;\n            for (size_t o = 0; o < transactionRef->vout.size(); o++)\n            {\n                if (pViewIn->HaveCoin(COutPoint(transactionRef->GetHash(), o)))\n                {\n                    transactionAlreadyInView =  true;\n                    break;\n                }\n            }\n            if (transactionAlreadyInView)\n                continue;\n        }\n\n        // We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't\n        // contain anything that is inBlock.\n        assert(!inBlock.count(iter));\n\n        uint64_t packageSize = iter->GetSizeWithAncestors();\n        CAmount packageFees = iter->GetModFeesWithAncestors();\n        int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();\n        if (fUsingModified)\n        {\n            packageSize = modit->nSizeWithAncestors;\n            packageFees = modit->nModFeesWithAncestors;\n            packageSigOpsCost = modit->nSigOpCostWithAncestors;\n        }\n\n        if (packageFees < blockMinFeeRate.GetFee(packageSize))\n        {\n            // Everything else we might consider has a lower fee rate\n            return;\n        }\n\n        if (!TestPackage(packageSize, packageSigOpsCost))\n        {\n            if (fUsingModified)\n            {\n                // Since we always look at the best entry in mapModifiedTx,\n                // we must erase failed entries so that we can consider the\n                // next best entry on the next loop iteration\n                mapModifiedTx.get<ancestor_score>().erase(modit);\n                failedTx.insert(iter);\n            }\n\n            ++nConsecutiveFailed;\n\n            if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight > nBlockMaxWeight - 4000)\n            {\n                // Give up if we're close to full and haven't succeeded in a while\n                break;\n            }\n            continue;\n        }\n\n        CTxMemPool::setEntries ancestors;\n        uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();\n        std::string dummy;\n        mempool.CalculateMemPoolAncestors(*iter, ancestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);\n\n        onlyUnconfirmed(ancestors);\n        ancestors.insert(iter);\n\n        // Test if all tx's are Final\n        if (!TestPackageTransactions(ancestors))\n        {\n            if (fUsingModified)\n            {\n                mapModifiedTx.get<ancestor_score>().erase(modit);\n                failedTx.insert(iter);\n            }\n            continue;\n        }\n\n        // This transaction will make it in; reset the failed counter.\n        nConsecutiveFailed = 0;\n\n        // Package can be added. Sort the entries in a valid order.\n        std::vector<CTxMemPool::txiter> sortedEntries;\n        SortForBlock(ancestors, iter, sortedEntries);\n\n        for (size_t i=0; i<sortedEntries.size(); ++i)\n        {\n            AddToBlock(sortedEntries[i]);\n            // Erase from the modified set, if present\n            mapModifiedTx.erase(sortedEntries[i]);\n        }\n\n        ++nPackagesSelected;\n\n        // Update transactions that depend on each of these\n        nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);\n    }\n}\n\nvoid IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)\n{\n    // Update nExtraNonce\n    static uint256 hashPrevBlock;\n    if (hashPrevBlock != pblock->hashPrevBlock)\n    {\n        nExtraNonce = 0;\n        hashPrevBlock = pblock->hashPrevBlock;\n    }\n    ++nExtraNonce;\n    pblock->hashMerkleRoot = BlockMerkleRoot(pblock->vtx.begin(), pblock->vtx.end());\n}\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Internal miner\n//\nbool ProcessBlockFound(const std::shared_ptr<const CBlock> pblock, const CChainParams& chainparams)\n{\n    LogPrintf(\"%s\\n\", pblock->ToString());\n    LogPrintf(\"Generated: hash=%s hashpow2=%s amt=%s\\n\", pblock->GetHashLegacy().ToString(), pblock->GetHashPoW2().ToString(), FormatMoney(pblock->vtx[0]->vout[0].nValue));\n\n    //fixme: (POST-PHASE5) we should avoid submitting stale blocks here\n    //but only if they are really stale (there are cases where we want to mine not on the tip (stalled chain)\n    //so detecting this is a bit tricky...\n\n    // Found a solution\n    // Process this block the same as if we had received it from another node\n    if (!ProcessNewBlock(chainparams, pblock, true, NULL, false, true))\n        return error(\"ProcessBlockFound: block not accepted\");\n\n    return true;\n}\n\nCBlockIndex* FindMiningTip(CBlockIndex* pIndexParent, const CChainParams& chainparams, std::string& strError, CBlockIndex*& pWitnessBlockToEmbed)\n{\n    if (!pIndexParent)\n        return nullptr;\n    pWitnessBlockToEmbed = nullptr;\n\n    // If PoW2 witnessing is active.\n    // Phase 3 - We always mine on the last PoW block for which we have a witness.\n    // This is always tip~1\n    // In the case where the current tip is a witness block, we want to embed the witness block and mine on top of the previous PoW block. (new chain tip)\n    // In the case where the current tip is a PoW block we want to mine on top of the PoW block that came before it. (competing chain tip to the current one - in case there is no witness for the current one)\n    // Phase 4 - We always mine on the last witnessed block.\n    // Tip if last mined block was a witness block. (Mining new chain tip)\n    // Tip~1 if the last mine block was a PoW block. (Competing chain tip to the current one - in case there is no witness for the current one)\n    //int nPoW2PhaseTip = GetPoW2Phase(pindexTip, Params(), chainActive);\n    int nPoW2PhaseGreatGrandParent = pIndexParent->pprev && pIndexParent->pprev->pprev ? GetPoW2Phase(pIndexParent->pprev->pprev) : 1;\n    int nPoW2PhaseGrandParent = pIndexParent->pprev ? GetPoW2Phase(pIndexParent->pprev) : 1;\n    boost::this_thread::interruption_point();\n\n    if (nPoW2PhaseGrandParent >= 3)\n    {\n        if (pIndexParent->nVersionPoW2Witness != 0)\n        {\n            if (nPoW2PhaseGrandParent == 3)\n            {\n                LOCK(cs_main); // Required for GetPoWBlockForPoSBlock\n                pWitnessBlockToEmbed = pIndexParent;\n                pIndexParent = GetPoWBlockForPoSBlock(pIndexParent);\n\n                if (!pIndexParent)\n                {\n                    strError = \"PoWGenerate: Stalled, unable to read the witness block we intend to embed.\";\n                    return nullptr;\n                }\n            }\n        }\n        else\n        {\n            if (nPoW2PhaseGreatGrandParent >= 3)\n            {\n                // See if there are higher level witness blocks with less work (delta diff drop) - if there are then we mine those first to try build a new larger chain.\n                bool tryHighLevelCandidate = false;\n                auto candidateIters = GetTopLevelWitnessOrphans(pIndexParent->nHeight);\n                for (auto candidateIter = candidateIters.rbegin(); candidateIter != candidateIters.rend(); ++candidateIter )\n                {\n                    if (nPoW2PhaseGreatGrandParent >= 4)\n                    {\n                        if ((*candidateIter)->nVersionPoW2Witness != 0)\n                        {\n                            pIndexParent = *candidateIter;\n                            tryHighLevelCandidate = true;\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        LOCK(cs_main); // Required for GetPoWBlockForPoSBlock\n                        CBlockIndex* pParentPoW = GetPoWBlockForPoSBlock(*candidateIter);\n                        if (pParentPoW)\n                        {\n                            if (nPoW2PhaseGrandParent == 3)\n                                pWitnessBlockToEmbed = *candidateIter;\n                            pIndexParent = pParentPoW;\n                            tryHighLevelCandidate = true;\n                            break;\n                        }\n                    }\n                }\n\n                // No higher level blocks - chain might be stalled; absent witness(es); so drop further back in the history and try mine a different chain.\n                if (!tryHighLevelCandidate && nPoW2PhaseGrandParent >= 4)\n                {\n                    pIndexParent = pIndexParent->pprev;\n                }\n                else if (!tryHighLevelCandidate)\n                {\n                    int nCount=0;\n                    while (pIndexParent->pprev && ++nCount < 10)\n                    {\n                        // Grab the witness from our index.\n                        pWitnessBlockToEmbed = GetWitnessOrphanForBlock(pIndexParent->pprev->nHeight, pIndexParent->pprev->GetBlockHashLegacy(), pIndexParent->pprev->GetBlockHashLegacy());\n\n                        if (!pWitnessBlockToEmbed)\n                        {\n                            pIndexParent = pIndexParent->pprev;\n                            continue;\n                        }\n                    }\n                    if (!pWitnessBlockToEmbed)\n                    {\n                        strError = \"PoWGenerate: stalled, unable to locate suitable witness block to embed.\\n\";\n                        return nullptr;\n                    }\n                    if (pIndexParent->nHeight != pWitnessBlockToEmbed->nHeight)\n                        pIndexParent = pIndexParent->pprev;\n                }\n            }\n            else\n            {\n                pIndexParent = pIndexParent->pprev;\n                pWitnessBlockToEmbed = nullptr;\n            }\n        }\n    }\n\n    if (nPoW2PhaseGreatGrandParent >= 4)\n    {\n        if (pIndexParent->nVersionPoW2Witness == 0)\n        {\n            strError = \"PoWGenerate: stalled, unable to locate suitable witness tip on which to build.\\n\";\n            return nullptr;\n        }\n    }\n\n    return pIndexParent;\n}\n\ndouble dBestHashesPerSec = 0.0;\ndouble dRollingHashesPerSec = 0.0;\ndouble dHashesPerSec = 0.0;\nint64_t nArenaSetupTime = 0;\nint64_t nHPSTimerStart = 0;\nint64_t nHashCounter=0;\nstd::atomic<int64_t> nHashThrottle(-1);\nstatic RecursiveMutex timerCS;\n\ninline void updateHashesPerSec(uint64_t& nStart, uint64_t nStop, uint64_t nCount)\n{\n    if (nCount > 0)\n    {\n        dHashesPerSec = (nCount*1000) / (nStop-nStart);\n        dBestHashesPerSec = std::max(dBestHashesPerSec, dHashesPerSec);\n        if (dRollingHashesPerSec == 0 && dHashesPerSec > 0)\n        {\n            dRollingHashesPerSec = dHashesPerSec;\n        }\n        else\n        {\n            dRollingHashesPerSec = ((dRollingHashesPerSec*19) + dHashesPerSec)/20;\n        }\n        #ifdef ENABLE_WALLET\n        static_cast<CExtWallet*>(pactiveWallet)->NotifyGenerationStatisticsUpdate();\n        #endif\n    }\n}\n\ninline void clearHashesPerSecondStatistics()\n{\n    if (dHashesPerSec > 0 || dBestHashesPerSec > 0 || dRollingHashesPerSec > 0 || nArenaSetupTime > 0)\n    {\n        nArenaSetupTime = 0;\n        nHPSTimerStart = 0;\n        nHashCounter=0;\n        nHPSTimerStart = 0;\n        nHashCounter=0;\n    }\n    #ifdef ENABLE_WALLET\n    static_cast<CExtWallet*>(pactiveWallet)->NotifyGenerationStatisticsUpdate();\n    #endif\n}\n\nvoid static PoWGenerate(const CChainParams& chainparams, CAccount* forAccount, uint64_t nThreads, uint64_t nArenaThreads, uint64_t nMemoryKb)\n{\n    LogPrintf(\"PoWGenerate thread started\\n\");\n    util::ThreadRename(GLOBAL_APPNAME\"-generate\");\n\n    int64_t nUpdateTimeStart = GetTimeMillis();\n\n    static bool testnet = Params().IsTestnet();\n    static bool regTest = Params().IsRegtest();\n    static bool regTestLegacy = Params().IsRegtestLegacy();\n    \n    // Start with fresh statistics for every mining run\n    clearHashesPerSecondStatistics();\n\n    unsigned int nExtraNonce = 0;\n    std::shared_ptr<CReserveKeyOrScript> coinbaseScript;\n    if (fixedGenerateAddress.size() > 0)\n    {\n        CNativeAddress address(fixedGenerateAddress);\n        if (!address.IsValid())\n        {\n            CAlert::Notify(\"Invalid mining address\", true, true);\n            return;\n        }\n        #ifdef ENABLE_WALLET\n        if (IsPow2Phase4Active(chainActive.Tip()))\n        {\n            CKeyID addressKeyID;\n            address.GetKeyID(addressKeyID);\n            coinbaseScript = std::make_shared<CReserveKeyOrScript>(addressKeyID);\n        }\n        else\n        #endif\n        {\n            CScript outputScript = GetScriptForDestination(address.Get());\n            coinbaseScript = std::make_shared<CReserveKeyOrScript>(outputScript);\n        }\n    }\n    else\n    {\n        GetMainSignals().ScriptForMining(coinbaseScript, forAccount);\n    }\n\n    try {\n        // Throw an error if no script was provided.  This can happen\n        // due to some internal error but also if the keypool is empty.\n        // In the latter case, already the pointer is NULL.\n        \n        #ifdef ENABLE_WALLET\n        if (!coinbaseScript || (coinbaseScript->scriptOnly() && coinbaseScript->reserveScript.empty()))\n        #else\n        if (!coinbaseScript || coinbaseScript->reserveScript.empty())\n        #endif\n        {\n            throw std::runtime_error(\"No coinbase script available (mining requires a wallet)\");\n        }\n\n\n\n        // Ensure we are reasonably caught up with peers, so we don't waste time mining on an obsolete chain.\n        // In testnet/regtest mode we expect to be able to mine without peers.\n        if (!regTest && !regTestLegacy && !testnet)\n        {\n            while (true)\n            {\n                if (IsChainNearPresent() && !IsInitialBlockDownload())\n                {\n                    break;\n                }\n                MilliSleep(1000);\n            }\n        }\n\n        while (true)\n        {\n            // If we have no peers, pause mining until we do, otherwise theres no real point in mining.\n            // In testnet/regtest mode we expect to be able to mine without peers.\n            if (!regTest && !regTestLegacy && !testnet)\n            {\n                while (true)\n                {\n                    if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) > 0)\n                    {\n                        break;\n                    }\n                    MilliSleep(100);\n                }\n            }\n\n            //\n            // Create new block\n            //\n            unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();\n            CBlockIndex* pindexParent = nullptr;\n            {\n                LOCK(cs_main);\n                pindexParent = chainActive.Tip();\n            }\n            CBlockIndex* pTipAtStartOfMining = pindexParent;\n            uint64_t nOrphansAtStartOfMining = GetTopLevelWitnessOrphans(pTipAtStartOfMining->nHeight).size();\n\n            if ( !pindexParent )\n                continue;\n\n            boost::this_thread::interruption_point();\n\n            std::string strError = \"\";\n            CBlockIndex* pWitnessBlockToEmbed = nullptr;\n            pindexParent = FindMiningTip(pindexParent, chainparams, strError, pWitnessBlockToEmbed);\n            if (!pindexParent)\n            {\n                if (GetTimeMillis() - nUpdateTimeStart > 5000)\n                {\n                    CAlert::Notify(strError.c_str(), true, true);\n                    LogPrintf(\"%s\\n\", strError.c_str());\n                    dHashesPerSec = 0;\n                }\n                continue;\n            }\n\n            std::unique_ptr<CBlockTemplate> pblocktemplate;\n            {\n                TRY_LOCK(processBlockCS, lockProcessBlock);\n                if(!lockProcessBlock)\n                {\n                    continue;\n                }\n\n                pblocktemplate = BlockAssembler(Params()).CreateNewBlock(pindexParent, coinbaseScript, true, pWitnessBlockToEmbed, false, nExtraNonce);\n                if (!pblocktemplate.get())\n                {\n                    LogPrintf(\"PoWGenerate: Failed to create block-template.\\n\");\n                    if (GetTimeMillis() - nUpdateTimeStart > 5000)\n                        dHashesPerSec = 0;\n                    continue;\n                }\n            }\n            CBlock *pblock = &pblocktemplate->block;\n            IncrementExtraNonce(pblock, pindexParent, nExtraNonce);\n\n            //\n            // Search\n            //\n            uint64_t nStart = GetTimeMillis();\n            std::uint64_t nMissedSteps = CalculateMissedTimeSteps(GetAdjustedFutureTime(), pindexParent->GetBlockTime());\n            arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);\n            if (pblock->nTime > defaultSigmaSettings.activationDate)\n            {\n                std::vector<std::unique_ptr<sigma_context>> sigmaContexts;\n                std::vector<uint64_t> sigmaMemorySizes;\n                uint64_t nMemoryAllocatedKb=0;\n                \n                \n                while (nMemoryAllocatedKb < nMemoryKb)\n                {\n                    uint64_t nMemoryChunkKb = std::min((nMemoryKb-nMemoryAllocatedKb), defaultSigmaSettings.arenaSizeKb);\n                    nMemoryAllocatedKb += nMemoryChunkKb;\n                    sigmaMemorySizes.emplace_back(nMemoryChunkKb);\n                }\n                //fixme: (SIGMA) - better memory size handling - right now we just blindly allocate until we succeed...\n                //And we don't even attempt to account for swap, so if the user sets a memory size too large for system memory we will just happily swap and perform worse than if the user picked a more reasonable size.\n                for (auto instanceMemorySizeKb : sigmaMemorySizes)\n                {\n                    uint64_t trySizeBytes = instanceMemorySizeKb*1024;\n                    while (trySizeBytes > 0)\n                    {\n                        normaliseBufferSize(trySizeBytes);\n                        try\n                        {\n                            sigmaContexts.push_back(std::unique_ptr<sigma_context>(new sigma_context(defaultSigmaSettings, trySizeBytes/1024, nThreads/sigmaMemorySizes.size(), nArenaThreads/sigmaMemorySizes.size())));\n                            break;\n                        }\n                        catch (...)\n                        {\n                            // reduce by 256mb and try again.\n                            if (trySizeBytes < 256*1024*1024)\n                                break;\n                            trySizeBytes -= 256*1024*1024;\n                        }\n                    }\n                }\n                \n                // Prepare arenas\n                CBlockHeader header = pblock->GetBlockHeader();\n                {\n                    auto workerThreads = new boost::asio::thread_pool(nThreads);\n                    for (const auto& sigmaContext : sigmaContexts)\n                    {\n                        boost::asio::post(*workerThreads, [&, header]() mutable\n                        {\n                            sigmaContext->prepareArenas(header);\n                        });\n                    }\n                    workerThreads->join();\n                }\n                nArenaSetupTime = GetTimeMillis() - nStart;\n                #ifdef ENABLE_WALLET\n                static_cast<CExtWallet*>(pactiveWallet)->NotifyGenerationStatisticsUpdate();\n                #endif\n                \n                // Mine\n                {\n                    //fixme: (SIGMA) use hash instead of bool so we can log it\n                    //fixme: (SIGMA) set limitdeltadiffdrop for mining from wallet (SoftSetArg)\n                    uint256 foundBlockHash;\n                    std::atomic<uint64_t> halfHashCounter=0;\n                    std::atomic<uint64_t> nThreadCounter=0;\n                    bool interrupt = false;\n                    \n                    auto workerThreads = new boost::asio::thread_pool(nThreads);\n                    for (const auto& sigmaContext : sigmaContexts)\n                    {\n                        ++nThreadCounter;\n                        boost::asio::post(*workerThreads, [&, header]() mutable\n                        {\n                            sigmaContext->mineBlock(pblock, halfHashCounter, foundBlockHash, interrupt);\n                            --nThreadCounter;\n                        });\n                    }\n                    {\n                        // If this thread gets interrupted then terminate mining\n                        BOOST_SCOPE_EXIT(&workerThreads, &interrupt) { interrupt=true; workerThreads->stop(); workerThreads->join(); delete workerThreads;} BOOST_SCOPE_EXIT_END\n                        int nCount = 0;\n                        while (true)\n                        {\n                            //fixme: (SIGMA) - Instead of busy polling it would be better if we could wait here on various signals, we would need to wait on several signals\n                            // 1) A signal for block found by one of our mining threads\n                            // 2) A signal for chain tip change\n                            // 3) A signal for 'top level witness orphan' changes\n                            MilliSleep(100);\n\n                            // If we have found a block then exit loop and process it immediately\n                            if (foundBlockHash != uint256())\n                                break;\n                            \n                            //fixme: (SIGMA) - This can be improved in cases where we have 'uneven' contexts, one may still have lots of work when another is finished, we might want to only restart one of them and not both...\n                            // If at least one of the threads is done working then abandon the rest of them, and then see if we have found a block or need to start again with a different block etc.\n                            if (nThreadCounter < sigmaContexts.size())\n                            {\n                                break;\n                            }\n                            \n                            // Abort mining and start mining a new block instead if chain tip changed\n                            {\n                                LOCK(cs_main);\n                                if (pTipAtStartOfMining != chainActive.Tip())\n                                    break;\n                            }\n                            \n                            // Abort mining and start mining a new block instead if alternative chain tip changed\n                            if (nOrphansAtStartOfMining != GetTopLevelWitnessOrphans(pTipAtStartOfMining->nHeight).size())\n                            {\n                                nOrphansAtStartOfMining = GetTopLevelWitnessOrphans(pTipAtStartOfMining->nHeight).size();\n                                if (pindexParent != FindMiningTip(pindexParent, chainparams, strError, pWitnessBlockToEmbed))\n                                    break;\n                            }\n                            \n                            if (++nCount>5)\n                            {\n                                updateHashesPerSec(nStart, GetTimeMillis(), halfHashCounter);\n                                nCount=0;\n                                \n                                // Abort for timestamp update if difficulty has dropped\n                                std::uint64_t nUpdateMissedSteps = CalculateMissedTimeSteps(GetAdjustedFutureTime(), pindexParent->GetBlockTime());\n                                if (nMissedSteps != nUpdateMissedSteps)\n                                {\n                                    //fixme: (2.1) Calculate the optimal \"break even\" proportion here based on arena setup time and increased chance of block discovery instead of this hardcoded 'estimated' solution.\n                                    //For machines with really slow arena setup time we only apply this for every second missed step, but starting from the first one.\n                                    if (nUpdateMissedSteps % 2 == 1 || nArenaSetupTime < 30000.0)\n                                    {\n                                        break;\n                                    }\n                                }\n                            }\n                            \n                            // Allow opportunity for user to terminate mining.\n                            boost::this_thread::interruption_point();\n                        }\n                    \n                        updateHashesPerSec(nStart, GetTimeMillis(), halfHashCounter);\n\n                        if (foundBlockHash != uint256())\n                        {\n                            TRY_LOCK(processBlockCS, lockProcessBlock);\n                            if(!lockProcessBlock)\n                                continue;\n\n                            // Found a solution\n                            LogPrintf(\"generated PoW\\n  hash: %s\\n  diff: %s\\n\", foundBlockHash.GetHex(), hashTarget.GetHex());\n                            std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);\n                            ProcessBlockFound(shared_pblock, chainparams);\n                            coinbaseScript->keepScriptOnDestroy();\n\n                            // In regression test mode, stop mining after a block is found.\n                            if (chainparams.MineBlocksOnDemand())\n                                throw boost::thread_interrupted();\n                        }\n                    }\n                    boost::this_thread::interruption_point();\n                    // Try again with a new updated block header\n                    continue;\n                }\n            }\n            else\n            {\n                // Check if something found\n                arith_uint256 hashMined;\n                while (true)\n                {\n                    // Check for stop or if block needs to be rebuilt\n                    boost::this_thread::interruption_point();\n                    if (GetTimeMillis() - nUpdateTimeStart > 5000)\n                    {\n                        nUpdateTimeStart = GetTimeMillis();\n                        // Update nTime every few seconds\n                        if (UpdateTime(pblock, chainparams.GetConsensus(), pindexParent) < 0)\n                            break; // Recreate the block if the clock has run backwards,so that we can use the correct time.\n                    }\n                    if (nHashThrottle != -1 && nHashCounter > nHashThrottle)\n                    {\n                        MilliSleep(50);\n                        continue;\n                    }\n\n                    hashMined = UintToArith256(pblock->GetPoWHash());\n\n                    if (hashMined <= hashTarget)\n                    {\n                        TRY_LOCK(processBlockCS, lockProcessBlock);\n                        if(!lockProcessBlock)\n                            break;\n\n                        {\n                            // Found a solution\n                            LogPrintf(\"generated PoW\\n  hash: %s\\n  diff: %s\\n\", hashMined.GetHex(), hashTarget.GetHex());\n                            std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);\n                            ProcessBlockFound(shared_pblock, chainparams);\n                            coinbaseScript->keepScriptOnDestroy();\n\n                            // In regression test mode, stop mining after a block is found.\n                            if (chainparams.MineBlocksOnDemand())\n                                throw boost::thread_interrupted();\n\n                            break;\n                        }\n                    }\n                    pblock->nNonce += 1;\n                    ++nHashCounter;\n\n                    if (pblock->nNonce >= 0xffff0000)\n                        break;\n                    if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)\n                        break;\n                    {\n                        LOCK(cs_main);\n                        if (pTipAtStartOfMining != chainActive.Tip())\n                            break;\n                    }\n                }\n            }\n        }\n    }\n    catch (const boost::thread_interrupted&)\n    {\n        LogPrintf(\"Generate thread terminated\\n\");\n        throw;\n    }\n    catch (const std::runtime_error &e)\n    {\n        LogPrintf(\"Generate thread runtime error: %s\\n\", e.what());\n        return;\n    }\n}\n\nboost::thread* minerThread = nullptr;\nRecursiveMutex miningCS;\n\nvoid PoWStopGeneration(bool notify)\n{\n    LOCK(miningCS);\n    fixedGenerateAddress=\"\";\n    if (minerThread != nullptr)\n    {\n        //fixme: (SIGMA) - The interrupt here doesn't work fast enough.\n        minerThread->interrupt();\n        minerThread->join();\n        delete minerThread;\n        minerThread = nullptr;\n    }\n    #ifdef ENABLE_WALLET\n    if (notify)\n    {\n        static_cast<CExtWallet*>(pactiveWallet)->NotifyGenerationStopped();\n    }\n    #endif\n}\n\nvoid PoWGenerateBlocks(bool fGenerate, int64_t nThreads, int64_t nArenaThreads, int64_t nMemory, const CChainParams& chainparams, CAccount* forAccount, std::string generateAddress)\n{\n    LOCK(miningCS);\n    if (nThreads < 0)\n        nThreads = GetNumCores();\n\n    PoWStopGeneration(false);\n\n    if (nThreads == 0 || !fGenerate)\n        return;\n    \n    if (nArenaThreads < 0)\n        nArenaThreads = nThreads;\n\n    fixedGenerateAddress = generateAddress;\n    minerThread = new boost::thread(boost::bind(&PoWGenerate, boost::cref(chainparams), forAccount, nThreads, nArenaThreads, nMemory));\n    #ifdef ENABLE_WALLET\n    static_cast<CExtWallet*>(pactiveWallet)->NotifyGenerationStarted();\n    #endif\n}\n\nbool PoWGenerationIsActive()\n{\n    LOCK(miningCS);\n    return minerThread != nullptr;\n}\n"
  },
  {
    "path": "src/generation/miner.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef GENERATION_MINER_H\n#define GENERATION_MINER_H\n\n#include \"primitives/block.h\"\n#include \"txmempool.h\"\n\n#include \"generation/generation.h\"\n\n#include <stdint.h>\n#include <memory>\n#include \"boost/multi_index_container.hpp\"\n#include \"boost/multi_index/ordered_index.hpp\"\n\n#include <crypto/hash/scrypt.h>\n#include <boost/thread/thread.hpp>\n\nclass CBlockIndex;\nclass CChainParams;\nclass CScript;\nclass CWallet;\nclass CAccount;\n\nextern double dBestHashesPerSec;\nextern double dRollingHashesPerSec;\nextern double dHashesPerSec;\nextern int64_t nArenaSetupTime;\nextern int64_t nHPSTimerStart;\nextern std::atomic<int64_t> nHashThrottle;\n\nbool ProcessBlockFound(const std::shared_ptr<const CBlock> pblock, const CChainParams& chainparams);\n\nnamespace Consensus { struct Params; };\n\nstatic const bool DEFAULT_GENERATE = false;\nstatic const int DEFAULT_GENERATE_THREADS = 1;\n\nstatic const bool DEFAULT_PRINTPRIORITY = false;\n\nstruct CBlockTemplate\n{\n    CBlock block;\n    std::vector<CAmount> vTxFees;\n    std::vector<int64_t> vTxSigOpsCost;\n};\n\n// Container for tracking updates to ancestor feerate as we include (parent)\n// transactions in a block\nstruct CTxMemPoolModifiedEntry {\n    CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)\n    {\n        iter = entry;\n        nSizeWithAncestors = entry->GetSizeWithAncestors();\n        nModFeesWithAncestors = entry->GetModFeesWithAncestors();\n        nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();\n    }\n\n    CTxMemPool::txiter iter;\n    uint64_t nSizeWithAncestors;\n    CAmount nModFeesWithAncestors;\n    int64_t nSigOpCostWithAncestors;\n};\n\n/** Comparator for CTxMemPool::txiter objects.\n *  It simply compares the internal memory address of the CTxMemPoolEntry object\n *  pointed to. This means it has no meaning, and is only useful for using them\n *  as key in other indexes.\n */\nstruct CompareCTxMemPoolIter {\n    bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const\n    {\n        return &(*a) < &(*b);\n    }\n};\n\nstruct modifiedentry_iter {\n    typedef CTxMemPool::txiter result_type;\n    result_type operator() (const CTxMemPoolModifiedEntry &entry) const\n    {\n        return entry.iter;\n    }\n};\n\n// This matches the calculation in CompareTxMemPoolEntryByAncestorFee,\n// except operating on CTxMemPoolModifiedEntry.\n// TODO: refactor to avoid duplication of this logic.\nstruct CompareModifiedEntry {\n    bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b) const\n    {\n        double f1 = (double)a.nModFeesWithAncestors * b.nSizeWithAncestors;\n        double f2 = (double)b.nModFeesWithAncestors * a.nSizeWithAncestors;\n        if (f1 == f2) {\n            return CTxMemPool::CompareIteratorByHash()(a.iter, b.iter);\n        }\n        return f1 > f2;\n    }\n};\n\n// A comparator that sorts transactions based on number of ancestors.\n// This is sufficient to sort an ancestor package in an order that is valid\n// to appear in a block.\nstruct CompareTxIterByAncestorCount {\n    bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b)\n    {\n        if (a->GetCountWithAncestors() != b->GetCountWithAncestors())\n            return a->GetCountWithAncestors() < b->GetCountWithAncestors();\n        return CTxMemPool::CompareIteratorByHash()(a, b);\n    }\n};\n\ntypedef boost::multi_index_container<\n    CTxMemPoolModifiedEntry,\n    boost::multi_index::indexed_by<\n        boost::multi_index::ordered_unique<\n            modifiedentry_iter,\n            CompareCTxMemPoolIter\n        >,\n        // sorted by modified ancestor fee rate\n        boost::multi_index::ordered_non_unique<\n            // Reuse same tag from CTxMemPool's similar index\n            boost::multi_index::tag<ancestor_score>,\n            boost::multi_index::identity<CTxMemPoolModifiedEntry>,\n            CompareModifiedEntry\n        >\n    >\n> indexed_modified_transaction_set;\n\ntypedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter;\ntypedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator modtxscoreiter;\n\nstruct update_for_parent_inclusion\n{\n    update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}\n\n    void operator() (CTxMemPoolModifiedEntry &e)\n    {\n        e.nModFeesWithAncestors -= iter->GetFee();\n        e.nSizeWithAncestors -= iter->GetTxSize();\n        e.nSigOpCostWithAncestors -= iter->GetSigOpCost();\n    }\n\n    CTxMemPool::txiter iter;\n};\n\n//! Find the block in the chain on which PoW miners should be building.\n//! This is no longer necessarily the tip, as the tip could be unwitnessed.\nCBlockIndex* FindMiningTip(CBlockIndex* pIndexParent, const CChainParams& chainparams, std::string& strError, CBlockIndex*& pWitnessBlockToEmbed);\n\ninline std::string fixedGenerateAddress=\"\";\n//! Run the block generation threads\nvoid PoWGenerateBlocks(bool fGenerate, int64_t nThreads, int64_t nArenaThreads, int64_t nMemoryKb, const CChainParams& chainparams, CAccount* forAccount = nullptr, std::string generateAddress=\"\");\n\n//! Stop the block generation threads if they are currently active\nvoid PoWStopGeneration(bool notify=true);\n\n//! Determine whether block generation is currently active or not.\nbool PoWGenerationIsActive();\n\n/** Generate a new block, without valid proof-of-work */\nclass BlockAssembler\n{\nprivate:\n    // The constructed block template\n    std::unique_ptr<CBlockTemplate> pblocktemplate;\n    // A convenience pointer that always refers to the CBlock in pblocktemplate\n    CBlock* pblock;\n\n    // Configuration parameters for the block size\n    bool fIncludeSegSig;\n    unsigned int nBlockMaxWeight, nBlockMaxSize;\n    bool fNeedSizeAccounting;\n    CFeeRate blockMinFeeRate;\n\n    // Information on the current status of the block\n    uint64_t nBlockWeight;\n    uint64_t nBlockSize;\n    uint64_t nBlockTx;\n    uint64_t nBlockSigOpsCost;\n    CAmount nFees;\n    CTxMemPool::setEntries inBlock;\n\n    // Chain context for the block\n    int nHeight;\n    int64_t nLockTimeCutoff;\n    const CChainParams& chainparams;\n\npublic:\n    struct Options {\n        Options();\n        size_t nBlockMaxWeight;\n        size_t nBlockMaxSize;\n        CFeeRate blockMinFeeRate;\n    };\n\n    BlockAssembler(const CChainParams& params);\n    BlockAssembler(const CChainParams& params, const Options& options);\n\n    /** Construct a new block template with coinbase to scriptPubKeyIn */\n    std::unique_ptr<CBlockTemplate> CreateNewBlock(CBlockIndex* pIndexPrev, std::shared_ptr<CReserveKeyOrScript> coinbaseReservedKey, bool fMineWitnessTx=true, CBlockIndex* pWitnessBlockIndex=nullptr, bool noValidityCheck=false, uint32_t nExtraNonce=0);\n\nprivate:\n    // utility functions\n    /** Clear the block's state and prepare for assembling a new block */\n    void resetBlock();\n    /** Add a tx to the block */\n    void AddToBlock(CTxMemPool::txiter iter);\n\n    // Methods for how to add transactions to a block.\n    /** Add transactions based on feerate including unconfirmed ancestors\n      * Increments nPackagesSelected / nDescendantsUpdated with corresponding\n      * statistics from the package selection (for logging statistics). */\n    void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, std::vector<CTransactionRef>* pCannabalizeTransactions = nullptr, CCoinsViewCache* pViewIn=nullptr);\n\n    // helper functions for addPackageTxs()\n    /** Remove confirmed (inBlock) entries from given set */\n    void onlyUnconfirmed(CTxMemPool::setEntries& testSet);\n    /** Test if a new package would \"fit\" in the block */\n    bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost);\n    /** Perform checks on each transaction in a package:\n      * locktime, premature-witness, serialized size (if necessary)\n      * These checks should always succeed, and they're here\n      * only as an extra check in case of suboptimal node configuration */\n    bool TestPackageTransactions(const CTxMemPool::setEntries& package);\n    /** Return true if given transaction from mapTx has already been evaluated,\n      * or if the transaction's cached data in mapTx is incorrect. */\n    bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx);\n    /** Sort the package in an order that is valid to appear in a block */\n    void SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries);\n    /** Add descendants of given transactions to mapModifiedTx with ancestor\n      * state updated assuming given transactions are inBlock. Returns number\n      * of updated descendants. */\n    int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx);\n};\n\n/** Modify the extranonce in a block */\nvoid IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);\nint64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);\n\n#endif\n"
  },
  {
    "path": "src/generation/witness.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"witness.h\"\n#include \"generation.h\"\n#include \"miner.h\"\n\n#include \"net.h\"\n\n#include \"alert.h\"\n#include \"appname.h\"\n#include \"amount.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"coins.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/merkle.h\"\n#include \"consensus/validation.h\"\n#include \"hash.h\"\n#include \"key.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"policy/feerate.h\"\n#include \"policy/policy.h\"\n#include \"pow/pow.h\"\n#include \"primitives/transaction.h\"\n#include \"script/standard.h\"\n#include \"timedata.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/threadnames.h\"\n#include \"util/time.h\"\n#include \"util/moneystr.h\"\n#include \"validation/validationinterface.h\"\n#include \"init.h\"\n\n#include <algorithm>\n#include <numeric>\n#include <queue>\n#include <utility>\n\n#include <crypto/hash/hash.h>\n#include <witnessutil.h>\n#include <openssl/sha.h>\n\n#include <boost/thread.hpp>\n\n#include \"txdb.h\"\n\n//Munt includes\n#include \"streams.h\"\n\nRecursiveMutex processBlockCS;\n\n#ifdef ENABLE_WALLET\nCReserveKeyOrScript::CReserveKeyOrScript(CWallet* pwalletIn, CAccount* forAccount, int64_t forKeyChain)\n{\n    pwallet = pwalletIn;\n    account = forAccount;\n    nIndex = -1;\n    nKeyChain = forKeyChain;\n}\n\nCReserveKeyOrScript::CReserveKeyOrScript(CScript& script)\n{\n    pwallet = nullptr;\n    account = nullptr;\n    nIndex = -1;\n    nKeyChain = -1;\n    reserveScript = script;\n}\n\nCReserveKeyOrScript::CReserveKeyOrScript(CPubKey &pubkey)\n{\n    pwallet = nullptr;\n    account = nullptr;\n    // By setting index as -1 we ensure key is not returned.\n    nIndex = -1;\n    nKeyChain = -1;\n    vchPubKey = pubkey;\n}\n\nCReserveKeyOrScript::CReserveKeyOrScript(CKeyID &pubKeyID_)\n{\n    pwallet = nullptr;\n    account = nullptr;\n    // By setting index as -1 we ensure key is not returned.\n    nIndex = -1;\n    nKeyChain = -1;\n    pubKeyID = pubKeyID_;\n}\n\nCReserveKeyOrScript::~CReserveKeyOrScript()\n{\n    if (shouldKeepOnDestroy)\n        KeepScript();\n    if (!scriptOnly())\n        ReturnKey();\n}\n\nbool CReserveKeyOrScript::scriptOnly()\n{\n    if (account == nullptr && pwallet == nullptr && pubKeyID.IsNull())\n        return true;\n    return false;\n}\n\nvoid CReserveKeyOrScript::KeepScript()\n{\n    if (!scriptOnly())\n        KeepKey();\n}\n\nvoid CReserveKeyOrScript::keepScriptOnDestroy()\n{\n    shouldKeepOnDestroy = true;\n}\n\nstatic bool SignBlockAsWitness(std::shared_ptr<CBlock> pBlock, CTxOut fittestWitnessOutput, CAccount* signingAccount)\n{\n    assert(pBlock->nVersionPoW2Witness != 0);\n\n    CKeyID witnessKeyID;\n\n\n    if (fittestWitnessOutput.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        witnessKeyID = fittestWitnessOutput.output.witnessDetails.witnessKeyID;\n    }\n    else\n    {\n        assert(0);\n    }\n\n    CKey key;\n    if (!signingAccount->GetKey(witnessKeyID, key))\n    {\n        std::string strErrorMessage = strprintf(\"Failed to obtain key to sign as witness: chain-tip-height[%d]\", chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n        CAlert::Notify(strErrorMessage, true, true);\n        LogPrintf(\"%s\\n\", strErrorMessage.c_str());\n        return false;\n    }\n\n    // Do not allow uncompressed keys.\n    if (!key.IsCompressed())\n    {\n        std::string strErrorMessage = strprintf(\"Invalid witness key - uncompressed keys not allowed: chain-tip-height[%d]\", chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n        CAlert::Notify(strErrorMessage, true, true);\n        LogPrintf(\"%s\\n\", strErrorMessage.c_str());\n        return false;\n    }\n\n    //Sign the hash of the block as proof that it has been witnessed.\n    uint256 hash = pBlock->GetHashPoW2();\n    if (!key.SignCompact(hash, pBlock->witnessHeaderPoW2Sig))\n        return false;\n\n    return true;\n}\n\nstatic bool alert(const std::string& msg)\n{\n    CAlert::Notify(msg, true, true);\n    LogPrintf(\"%s\", msg.c_str());\n    return false;\n}\n\nstatic bool CreateWitnessSubsidyOutputs(CTxOutPoW2Witness& witnessInput, CMutableTransaction& coinbaseTx, const CWitnessRewardTemplate& rewardTemplate, std::shared_ptr<CReserveKeyOrScript> coinbaseReservedKey, const CAmount witnessBlockSubsidy, const CAmount witnessFeeSubsidy, CTxOut& selectedWitnessOutput, COutPoint& selectedWitnessOutPoint, bool bSegSigIsEnabled, unsigned int nSelectedWitnessBlockHeight)\n{\n    // Ammend some details of the input that must change in the new output.\n    CPoW2WitnessDestination witnessDestination;\n    witnessDestination.spendingKey = witnessInput.spendingKeyID;\n    witnessDestination.witnessKey = witnessInput.witnessKeyID;\n    witnessDestination.lockFromBlock = witnessInput.lockFromBlock;\n    witnessDestination.lockUntilBlock = witnessInput.lockUntilBlock;\n    witnessDestination.failCount = witnessInput.failCount;\n    witnessDestination.actionNonce = witnessInput.actionNonce+1;\n\n    // If this is the first time witnessing the lockFromBlock won't yet be filled in so fill it in now.\n    if (witnessDestination.lockFromBlock == 0)\n        witnessDestination.lockFromBlock = nSelectedWitnessBlockHeight;\n\n    // If fail count is non-zero then we are allowed to decrement it by one every time we witness.\n    if (witnessDestination.failCount > 0)\n        witnessDestination.failCount = witnessDestination.failCount - 1;\n\n    CAmount compoundWitnessBlockSubsidy = witnessBlockSubsidy + witnessFeeSubsidy;\n\n    CAmount fixedTotal = rewardTemplate.fixedAmountsSum();\n    if (fixedTotal > compoundWitnessBlockSubsidy)\n        return alert(strprintf(\"%s, Witness template fixed amounts total (%s) exceed subsidy (%s)\", __PRETTY_FUNCTION__, FormatMoney(fixedTotal), FormatMoney(compoundWitnessBlockSubsidy)));\n\n    CAmount percentageSum = rewardTemplate.percentagesSum();\n    if (percentageSum < 0.0 || percentageSum > 1.0)\n        return alert(strprintf(\"%s, Witness template percentage total (%f) out of range [0..100]\", __PRETTY_FUNCTION__, percentageSum * 100.0));\n\n    CAmount flexibleTotal = compoundWitnessBlockSubsidy - fixedTotal;\n\n    CAmount percentageTotalAmount = std::accumulate(rewardTemplate.destinations.begin(), rewardTemplate.destinations.end(), CAmount(0), [&](const CAmount& acc, const CWitnessRewardDestination& dest){\n        return acc + dest.percent * flexibleTotal;\n    });\n\n    if (percentageTotalAmount > flexibleTotal)\n        return alert(strprintf(\"%s, Witness template percentages rounding error, specifiy less percentages and use remainder\", __PRETTY_FUNCTION__));\n\n    // Calculate remainder\n    bool remainderDone = false;\n    CAmount remainderAmount = flexibleTotal - percentageTotalAmount;\n\n    // Calculate compound\n    CAmount compoundAmount = std::accumulate(rewardTemplate.destinations.begin(), rewardTemplate.destinations.end(), CAmount(0), [&](const CAmount& acc, const CWitnessRewardDestination& dest){\n        return acc + (dest.type == CWitnessRewardDestination::DestType::Compound ? dest.amount + dest.percent * flexibleTotal : 0);\n    });\n\n    // Calculate overflow (adjusting compound)\n    const CAmount effectiveCompoundLimit  = bSegSigIsEnabled ? gMaximumWitnessCompoundAmount * COIN : 0;\n    bool overflowDone = false;\n    CAmount overflowAmount = 0;\n    if (compoundAmount > effectiveCompoundLimit) {\n        overflowAmount = compoundAmount - effectiveCompoundLimit;\n        compoundAmount = effectiveCompoundLimit;\n    }\n\n    // Special case for compound overflow while no overflow destination defined\n    if (overflowAmount > 0 && 0 == std::count_if(rewardTemplate.destinations.begin(), rewardTemplate.destinations.end(),\n                                                 [](const CWitnessRewardDestination& dest) { return dest.takesCompoundOverflow; })) {\n        // must have remainder, but not on a compound destination\n        bool hasRemainder = false;\n        for (const CWitnessRewardDestination& dest: rewardTemplate.destinations) {\n            hasRemainder = hasRemainder || dest.takesRemainder;\n            if (dest.takesRemainder && dest.type == CWitnessRewardDestination::DestType::Compound)\n                return alert(strprintf(\"%s, Witness template could not output overflow\", __PRETTY_FUNCTION__));\n        }\n        if (!hasRemainder)\n            return alert(strprintf(\"%s, Witness template needed remainder to output overflow\", __PRETTY_FUNCTION__));\n\n        // Move overflow to remainder\n        remainderAmount += overflowAmount;\n        overflowDone = true;\n    }\n\n    // Create the witness output\n    coinbaseTx.vout.resize(1);\n    if (bSegSigIsEnabled)\n    {\n        coinbaseTx.vout[0].SetType(CTxOutType::PoW2WitnessOutput);\n        coinbaseTx.vout[0].output.witnessDetails.spendingKeyID = witnessDestination.spendingKey;\n        coinbaseTx.vout[0].output.witnessDetails.witnessKeyID = witnessDestination.witnessKey;\n        coinbaseTx.vout[0].output.witnessDetails.lockFromBlock = witnessDestination.lockFromBlock;\n        coinbaseTx.vout[0].output.witnessDetails.lockUntilBlock = witnessDestination.lockUntilBlock;\n        coinbaseTx.vout[0].output.witnessDetails.failCount = witnessDestination.failCount;\n        coinbaseTx.vout[0].output.witnessDetails.actionNonce = witnessDestination.actionNonce;\n    }\n    else\n    {\n        coinbaseTx.vout[0].SetType(CTxOutType::ScriptLegacyOutput);\n        coinbaseTx.vout[0].output.scriptPubKey = GetScriptForDestination(witnessDestination);\n    }\n    coinbaseTx.vout[0].nValue = selectedWitnessOutput.nValue + compoundAmount;\n\n    for (const CWitnessRewardDestination& dest: rewardTemplate.destinations) {\n        // Calculate amount for this dest. Important: exact same calculation method here as in the above accumulation\n        CAmount amount = dest.amount + dest.percent * flexibleTotal;\n        if (dest.takesRemainder && !remainderDone) {\n            amount += remainderAmount;\n            remainderDone = true;\n        }\n        if (dest.takesCompoundOverflow && !overflowDone) {\n            amount += overflowAmount;\n            overflowDone = true;\n        }\n\n        // Don't create output for 0 amounts (for example a compound_overflow where there is no overflow)\n        if (amount == 0)\n            continue;\n\n        switch (dest.type) {\n        case CWitnessRewardDestination::DestType::Account:\n        {\n            CTxOut txOut;\n            txOut.nValue = amount;\n            if (bSegSigIsEnabled && !coinbaseReservedKey->scriptOnly())\n            {\n                txOut.SetType(CTxOutType::StandardKeyHashOutput);\n                CPubKey addressPubKey;\n                if (!coinbaseReservedKey->GetReservedKey(addressPubKey))\n                    return alert(strprintf(\"%s, failed to get reserved key with which to sign as witness: chain-tip-height[%d]\", __PRETTY_FUNCTION__, chainActive.Tip()? chainActive.Tip()->nHeight : 0));\n                txOut.output.standardKeyHash = CTxOutStandardKeyHash(addressPubKey.GetID());\n            }\n            else\n            {\n                txOut.SetType(CTxOutType::ScriptLegacyOutput);\n                txOut.output.scriptPubKey = coinbaseReservedKey->reserveScript;\n            }\n            coinbaseTx.vout.push_back(txOut);\n            break;\n        }\n        case CWitnessRewardDestination::DestType::Address:\n            coinbaseTx.vout.push_back(CTxOut(amount, GetScriptForDestination(dest.address.Get())));\n            break;\n        default: // DestType::Compound is handled in witness output\n            break;\n        }\n    }\n\n    if (remainderAmount > 0 && !remainderDone)\n        return alert(strprintf(\"%s, Witness template could not output remainder\", __PRETTY_FUNCTION__));\n\n    if (overflowAmount > 0 && !overflowDone)\n        return alert(strprintf(\"%s, Witness template could not output remainder\", __PRETTY_FUNCTION__));\n\n    return true;\n}\n\nstatic std::tuple<bool, CMutableTransaction, CWitnessBundles> CreateWitnessCoinbase(int nWitnessHeight, CBlockIndex* pIndexPrev, int nPoW2PhaseParent, std::shared_ptr<CReserveKeyOrScript> coinbaseScript, const CAmount witnessBlockSubsidy, const CAmount witnessFeeSubsidy, CTxOut& selectedWitnessOutput, COutPoint& selectedWitnessOutPoint, unsigned int nSelectedWitnessBlockHeight, CAccount* selectedWitnessAccount, uint64_t nTransactionIndex)\n{\n    // We will calculate and return a witness bundle for this transaction so the caller can append it to the non mutable transaction\n    CWitnessBundles coinbaseWitnessBundles;\n    \n    // Obtain the details of the signing witness transaction which must be consumed as an input and recreated as an output.\n    CTxOutPoW2Witness witnessInput; GetPow2WitnessOutput(selectedWitnessOutput, witnessInput);\n\n    bool bSegSigIsEnabled = IsSegSigEnabled(pIndexPrev);\n\n    CMutableTransaction coinbaseTx(bSegSigIsEnabled ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::CURRENT_VERSION);\n    coinbaseTx.vin.resize(2);\n    coinbaseTx.vin[0].SetPrevOutNull();\n    coinbaseTx.vin[0].SetSequence(0, coinbaseTx.nVersion, CTxInFlags::None);\n    coinbaseTx.vin[1].SetPrevOut(selectedWitnessOutPoint);\n    coinbaseTx.vin[1].SetSequence(0, coinbaseTx.nVersion, CTxInFlags::None);\n\n    if (bSegSigIsEnabled)\n    {\n        std::string coinbaseSignature = GetArg(\"-coinbasesignature\", \"\");\n        coinbaseTx.vin[0].segregatedSignatureData.stack.clear();\n        coinbaseTx.vin[0].segregatedSignatureData.stack.push_back(std::vector<unsigned char>());\n        CVectorWriter(0, 0, coinbaseTx.vin[0].segregatedSignatureData.stack[0], 0) << VARINT(nWitnessHeight);\n        coinbaseTx.vin[0].segregatedSignatureData.stack.push_back(std::vector<unsigned char>(coinbaseSignature.begin(), coinbaseSignature.end()));\n    }\n    else\n    {\n        // Phase 3 - we restrict the coinbase signature to only the block height.\n        // This helps simplify the logic for the PoW mining (which has to stuff all this info into it's own coinbase signature).\n        coinbaseTx.vin[0].scriptSig = CScript() << nWitnessHeight;\n    }\n\n    // Sign witness coinbase.\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        if (!pactiveWallet->SignTransaction(selectedWitnessAccount, coinbaseTx, SignType::Witness, &selectedWitnessOutput))\n        {\n            std::string strErrorMessage = strprintf(\"Failed to sign witness coinbase: height[%d] chain-tip-height[%d]\", nWitnessHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n            CAlert::Notify(strErrorMessage, true, true);\n            LogPrintf(\"%s\\n\", strErrorMessage.c_str());\n            return std::tuple(false, coinbaseTx, coinbaseWitnessBundles);\n        }\n    }\n\n    CWitnessRewardTemplate rewardTemplate;\n    // If an explicit template has been set then use that, otherwise create a default template\n    if (selectedWitnessAccount->hasRewardTemplate())\n    {\n        LOCK(pactiveWallet->cs_wallet);\n        rewardTemplate = selectedWitnessAccount->getRewardTemplate();\n    }\n    else\n    {\n        if (selectedWitnessAccount->getCompounding() > 0)\n        {\n            auto compoundAmount = selectedWitnessAccount->getCompounding();\n            if (compoundAmount == MAX_MONEY)\n            {\n                compoundAmount = witnessBlockSubsidy;\n                // Subsidy and any overflow fees to compound\n                rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Compound, CNativeAddress(), compoundAmount, 0.0, true, false));\n                // Any compound overflow to script\n                rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Account, CNativeAddress(), 0, 0.0, false, true));\n            }\n            else\n            {\n                // Pay up until requested amount to compound\n                rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Compound, CNativeAddress(), compoundAmount, 0.0, false, false));\n                // Any remaining fees/overflow to script\n                rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Account, CNativeAddress(), 0, 0.0, true, true));\n            }\n        }\n        else\n        {\n            // Compound nothing, all money into 'reward script'\n            rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Compound, CNativeAddress(), 0, 0.0, false, false));\n            rewardTemplate.destinations.push_back(CWitnessRewardDestination(CWitnessRewardDestination::DestType::Account, CNativeAddress(), 0, 0.0, true, true));\n        }\n    }\n\n    // Output for subsidy and refresh witness address.\n    if (!CreateWitnessSubsidyOutputs(witnessInput, coinbaseTx, rewardTemplate, coinbaseScript, witnessBlockSubsidy, witnessFeeSubsidy, selectedWitnessOutput, selectedWitnessOutPoint, bSegSigIsEnabled, nSelectedWitnessBlockHeight))\n    {\n        // Error message already handled inside function\n        return std::tuple(false, coinbaseTx, coinbaseWitnessBundles);\n    }\n    \n    CWitnessTxBundle bundle;\n    if (!selectedWitnessOutPoint.isHash)\n    {\n        bundle.bundleType = CWitnessTxBundle::WitnessTxType::WitnessType;\n        bundle.outputs.push_back(std::tuple(coinbaseTx.vout[0], coinbaseTx.vout[0].output.witnessDetails, COutPoint(nWitnessHeight, nTransactionIndex, 0)));\n        bundle.inputs.push_back(std::tuple(selectedWitnessOutput, std::move(witnessInput), COutPoint(nSelectedWitnessBlockHeight, selectedWitnessOutPoint.getTransactionIndex(), selectedWitnessOutPoint.n)));\n        coinbaseWitnessBundles.push_back(bundle);\n    }\n    return std::tuple(true, coinbaseTx, coinbaseWitnessBundles);\n}\n\n\nvoid TryPopulateAndSignWitnessBlock(CBlockIndex* candidateIter, CChainParams& chainparams, Consensus::Params& consensusParams, CGetWitnessInfo witnessInfo, std::shared_ptr<CBlock> pWitnessBlock, std::map<boost::uuids::uuid, std::shared_ptr<CReserveKeyOrScript>>& reserveKeys, bool& encounteredError, bool& signedBlock)\n{\n    signedBlock = false;\n    encounteredError = false;\n\n    CAmount witnessBlockSubsidy = GetBlockSubsidy(candidateIter->nHeight).witness;\n    CAmount witnessFeesSubsidy = 0;\n\n    bool isMineAny = (pactiveWallet->IsMineWitness(witnessInfo.selectedWitnessTransaction) == ISMINE_WITNESS);\n    bool isMineTestnetGenesis = false;\n    CAccount* selectedWitnessAccount = nullptr;\n    std::shared_ptr<CAccount> deleteAccount = nullptr;\n    if (isMineAny)\n    {\n        selectedWitnessAccount = pactiveWallet->FindBestWitnessAccountForTransaction(witnessInfo.selectedWitnessTransaction);\n    }\n    else if (chainparams.genesisWitnessPrivKey.IsValid())\n    {\n        if (witnessInfo.selectedWitnessTransaction.output.witnessDetails.witnessKeyID == chainparams.genesisWitnessPrivKey.GetPubKey().GetID())\n        {\n            isMineTestnetGenesis = true;\n            selectedWitnessAccount = new CAccount();\n            selectedWitnessAccount->m_Type = AccountType::ImportedPrivateKeyAccount;\n            selectedWitnessAccount->AddKeyPubKey(chainparams.genesisWitnessPrivKey, chainparams.genesisWitnessPrivKey.GetPubKey(), KEYCHAIN_WITNESS);\n            deleteAccount = std::shared_ptr<CAccount>(selectedWitnessAccount);\n        }\n    }   \n    if (selectedWitnessAccount)\n    {\n        //We must do this before we add the blank coinbase otherwise GetBlockWeight crashes on a NULL pointer dereference.\n        int nStartingBlockWeight = GetBlockWeight(*pWitnessBlock);\n\n        /** First we add the new witness coinbase to the block, this acts as a seperator between transactions from the initial mined block and the witness block **/\n        /** We add a placeholder for now as we don't know the fees we will generate **/\n        pWitnessBlock->vtx.emplace_back();\n        unsigned int nWitnessCoinbaseIndex = pWitnessBlock->vtx.size()-1;\n        nStartingBlockWeight += 200;\n\n        std::shared_ptr<CReserveKeyOrScript> coinbaseScript = nullptr;\n        if (!isMineTestnetGenesis)\n        {\n            if (witnessScriptsAreDirty)\n            {\n                reserveKeys.clear();\n            }\n            auto findIter = reserveKeys.find(selectedWitnessAccount->getUUID());\n            if (findIter != reserveKeys.end())\n            {\n                coinbaseScript = findIter->second;\n            }\n            else\n            {\n                GetMainSignals().ScriptForWitnessing(coinbaseScript, selectedWitnessAccount);\n                // Don't attempt to witness if we have nowhere to pay the rewards.\n                // ScriptForWitnessing will have alerted the user.\n                if (coinbaseScript == nullptr)\n                {\n                    std::string strErrorMessage = strprintf(\"Failed to create payout for witness block [%d] current chain tip [%d].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                    CAlert::Notify(strErrorMessage, true, true);\n                    LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n                    encounteredError=true;\n                    return;\n                }\n                reserveKeys[selectedWitnessAccount->getUUID()] = coinbaseScript;\n            }\n        }\n        else\n        {\n            CScript script;\n            coinbaseScript = std::make_shared<CReserveKeyOrScript>(script);\n        }\n\n        int nPoW2PhaseParent = GetPoW2Phase(candidateIter->pprev);\n        \n        /** Now add any additional transactions if there is space left **/\n        //fixme: (FUT): In an attempt to work around a potential rare issue that causes chain stalls we temporarily avoid adding transactions if witnessing a non tip node\n        //In future we should add the transactions back again\n        if (nPoW2PhaseParent >= 4 && candidateIter == chainActive.Tip())\n        {\n            // Piggy back off existing block assembler code to grab the transactions we want to include.\n            // Setup maximum size for assembler so that size of existing (PoW) block transactions are subtracted from overall maximum.\n            BlockAssembler::Options assemblerOptions;\n            assemblerOptions.nBlockMaxWeight = GetArg(\"-blockmaxweight\", DEFAULT_BLOCK_MAX_WEIGHT) - nStartingBlockWeight;\n            assemblerOptions.nBlockMaxSize = GetArg(\"-blockmaxsize\", DEFAULT_BLOCK_MAX_SIZE) - nStartingBlockWeight;\n\n            std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params(), assemblerOptions).CreateNewBlock(candidateIter, coinbaseScript, true, nullptr, true));\n            if (!pblocktemplate.get())\n            {\n                std::string strErrorMessage = strprintf(\"Failed to get block template [%d] current chain tip [%d].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                CAlert::Notify(strErrorMessage, true, true);\n                LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n                encounteredError=true;\n                return;\n            }\n\n            // Skip the coinbase as we obviously don't want this included again, it is already in the PoW part of the block.\n            size_t nSkipCoinbase = 1;\n            //fixme: (FUT) (CBSU)? pre-allocate for vtx.size().\n            for (size_t i=nSkipCoinbase; i < pblocktemplate->block.vtx.size(); i++)\n            {\n                bool bSkip = false;\n                //fixme: (PHASE5) Check why we were getting duplicates - something to do with mempool not being updated for latest block or something?\n                // Exclude any duplicates that somehow creep in.\n                for(size_t j=0; j < nWitnessCoinbaseIndex; j++)\n                {\n                    if (pWitnessBlock->vtx[j]->GetHash() == pblocktemplate->block.vtx[i]->GetHash())\n                    {\n                        bSkip = true;\n                        break;\n                    }\n                }\n                \n                //Forbid any transactions that would affect the witness set, as these would throw simplified witness utxo tracking off\n                //fixme: (WITNESS_SYNC); Ensure witnesses are still adding transactions here\n                //fixme: (WITNESS_SYNC); We should rather do this inside the block assembler\n                if (!bSkip)\n                {\n                    const auto& tx = pblocktemplate->block.vtx[i];\n                    if (!tx->witnessBundles || tx->witnessBundles->size()>0)\n                    {\n                        bSkip = true;\n                    }\n                }\n                if (!bSkip)\n                {\n                    //fixme: (FUT) emplace_back for better performace?\n                    pWitnessBlock->vtx.push_back(pblocktemplate->block.vtx[i]);\n                    witnessFeesSubsidy += (pblocktemplate->vTxFees[i]);\n                }\n            }\n        }\n\n        /** Populate witness coinbase placeholder with real information now that we have it **/\n        const auto& [result, coinbaseTx, witnessBundles] = CreateWitnessCoinbase(candidateIter->nHeight, candidateIter->pprev, nPoW2PhaseParent, coinbaseScript, witnessBlockSubsidy, witnessFeesSubsidy, witnessInfo.selectedWitnessTransaction, witnessInfo.selectedWitnessOutpoint, witnessInfo.selectedWitnessBlockHeight, selectedWitnessAccount, nWitnessCoinbaseIndex);\n        if (result)\n        {\n            pWitnessBlock->vtx[nWitnessCoinbaseIndex] = MakeTransactionRef(std::move(coinbaseTx));\n            pWitnessBlock->vtx[nWitnessCoinbaseIndex]->witnessBundles = std::make_shared<CWitnessBundles>(witnessBundles);\n\n            /** Set witness specific block header information **/\n            {\n                // ComputeBlockVersion returns the right version flag to signal for phase 4 activation here, assuming we are already in phase 3 and 95 percent of peers are upgraded.\n                pWitnessBlock->nVersionPoW2Witness = ComputeBlockVersion(candidateIter->pprev, consensusParams);\n\n                // Second witness timestamp gets added to the block as an additional time source to the miner timestamp.\n                // Witness timestamp must exceed median of previous mined timestamps.\n                pWitnessBlock->nTimePoW2Witness = std::max(candidateIter->GetMedianTimePastPoW()+1, GetAdjustedTime());\n\n                // Set witness merkle hash.\n                pWitnessBlock->hashMerkleRootPoW2Witness = BlockMerkleRoot(pWitnessBlock->vtx.begin()+nWitnessCoinbaseIndex, pWitnessBlock->vtx.end());\n                \n                // Set the simplified witness UTXO change delta\n                if ((uint64_t)candidateIter->nHeight  > consensusParams.pow2WitnessSyncHeight)\n                {\n                    std::shared_ptr<SimplifiedWitnessUTXOSet> pow2SimplifiedWitnessUTXOForPrevBlock = std::make_shared<SimplifiedWitnessUTXOSet>();\n                    if (!GetSimplifiedWitnessUTXOSetForIndex(candidateIter->pprev, *pow2SimplifiedWitnessUTXOForPrevBlock))\n                    {\n                        std::string strErrorMessage = strprintf(\"Failed to compute UTXO for prev block [%d] current chain tip [%d].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                        CAlert::Notify(strErrorMessage, true, true);\n                        LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n                        encounteredError=true;\n                        return;\n                    }\n                    if (!GetSimplifiedWitnessUTXODeltaForBlock(candidateIter, *pWitnessBlock, pow2SimplifiedWitnessUTXOForPrevBlock, pWitnessBlock->witnessUTXODelta, nullptr))\n                    {\n                        std::string strErrorMessage = strprintf(\"Failed to compute UTXO delta for block [%d] current chain tip [%d].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                        CAlert::Notify(strErrorMessage, true, true);\n                        LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n                        encounteredError=true;\n                        return;\n                    }\n                }\n            }\n\n            /** Do the witness operation (Sign the block using our witness key) and broadcast the final product to the network. **/\n            if (SignBlockAsWitness(pWitnessBlock, witnessInfo.selectedWitnessTransaction, selectedWitnessAccount))\n            {\n                ProcessBlockFound(pWitnessBlock, chainparams);\n                coinbaseScript->keepScriptOnDestroy();\n                signedBlock=true;\n                return;\n            }\n            else\n            {\n                std::string strErrorMessage = strprintf(\"Signature error, failed to witness block [%d] current chain tip [%d].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                CAlert::Notify(strErrorMessage, true, true);\n                LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n                encounteredError=true;\n                return;\n            }\n        }\n        else\n        {\n            std::string strErrorMessage = strprintf(\"Coinbase error, failed to create coinbase for witness block [%d] current chain tip [%d] address [%s].\\n\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0, CNativeAddress(CPoW2WitnessDestination(witnessInfo.selectedWitnessTransaction.output.witnessDetails.spendingKeyID, witnessInfo.selectedWitnessTransaction.output.witnessDetails.witnessKeyID)).ToString());\n            CAlert::Notify(strErrorMessage, true, true);\n            LogPrintf(\"MuntWitness: [Error] %s\\n\", strErrorMessage.c_str());\n            encounteredError=true;\n            return;\n        }\n    }\n}\n\nstruct CBlockIndexCacheComparator\n{\n    bool operator()(CBlockIndex *pa, CBlockIndex *pb) const {\n        if (pa->nHeight > pb->nHeight) return false;\n        if (pa->nHeight < pb->nHeight) return true;\n\n        if (pa < pb) return false;\n        if (pa > pb) return true;\n\n        return false;\n    }\n};\n//fixme: (POST-PHASE5) We should also check for already signed block coming from ourselves (from e.g. a different machine - think witness devices for instance) - Don't sign it if we already have a signed copy of the block lurking around...\nstd::set<CBlockIndex*, CBlockIndexCacheComparator> cacheAlreadySeenWitnessCandidates;\n\nbool witnessScriptsAreDirty = false;\nbool witnessingEnabled = true;\n\nvoid static MuntWitness()\n{\n    LogPrintf(\"Witness thread started\\n\");\n    util::ThreadRename(GLOBAL_APPNAME\"-witness\");\n    \n    // Don't even try witness if we have no wallet (-disablewallet)\n    if (!pactiveWallet)\n        return;\n\n    static bool regTest = Params().IsRegtest();\n    static bool regTestLegacy = Params().IsRegtestLegacy();\n    // Don't use witness loop on regtest\n    if (regTest || regTestLegacy)\n        return;\n    \n    static bool testNet = Params().IsTestnet();\n\n    CChainParams chainparams = Params();\n    try\n    {\n        std::map<boost::uuids::uuid, std::shared_ptr<CReserveKeyOrScript>> reserveKeys;\n        while (true)\n        {\n            if (!testNet)\n            {\n                // Busy-wait for the network to come online so we don't waste time mining\n                // on an obsolete chain. In regtest mode we expect to fly solo.\n                do\n                {\n                    if (pactiveWallet && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) > 0)\n                    {\n                        LOCK(cs_main);\n                        if(!IsInitialBlockDownload())\n                            break;\n                    }\n                    MilliSleep(5000);\n                } while (true);\n            }\n            while (!witnessingEnabled)\n            {\n                MilliSleep(200);\n            }\n            DO_BENCHMARK(\"WIT: MuntWitness\", BCLog::BENCH|BCLog::WITNESS);\n\n            CBlockIndex* pindexTip = nullptr;\n            {\n                LOCK(cs_main);\n                pindexTip = chainActive.Tip();\n            }\n            Consensus::Params consensusParams = chainparams.GetConsensus();\n\n            //We can only start witnessing from phase 3 onward.\n            if (!pindexTip || !pindexTip->pprev || !IsPow2WitnessingActive(pindexTip->nHeight))\n            {\n                MilliSleep(5000);\n                continue;\n            }\n            int nPoW2PhasePrev = GetPoW2Phase(pindexTip->pprev);\n\n            //fixme: (POST-PHASE5)\n            //Ideally instead of just sleeping/busy polling rather wait on a signal that gets triggered only when new blocks come in??\n            MilliSleep(100);\n\n            // Check for stop or if block needs to be rebuilt\n            boost::this_thread::interruption_point();\n\n            static uint256 hashLastAbsentWitnessTip;\n            static uint64_t timeLastAbsentWitnessTip = 0;\n            static uint64_t secondsLastAbsentWitnessTip = 0;\n\n            // If we already have a witnessed block at the tip don't bother looking at any orphans, just patiently wait for next unsigned tip.\n            if (nPoW2PhasePrev < 3 || pindexTip->nVersionPoW2Witness != 0)\n            {\n                timeLastAbsentWitnessTip = 0;\n                secondsLastAbsentWitnessTip = 0;\n                hashLastAbsentWitnessTip.SetNull();\n                continue;\n            }\n\n            // Log absent witness if witness logging enabled.\n            if (LogAcceptCategory(BCLog::WITNESS) || IsArgSet(\"-zmqpubstalledwitness\"))\n            {\n                if (hashLastAbsentWitnessTip == pindexTip->GetBlockHashPoW2())\n                {\n                    uint64_t nSecondsAbsent = (GetTimeMillis() - timeLastAbsentWitnessTip) / 1000;\n                    if (((nSecondsAbsent % 5) == 0) && nSecondsAbsent != secondsLastAbsentWitnessTip)\n                    {\n                        secondsLastAbsentWitnessTip = nSecondsAbsent;\n                        GetMainSignals().StalledWitness(pindexTip, nSecondsAbsent);\n                        LogPrint(BCLog::WITNESS, \"MuntWitness: absent witness at tip [%s] [%d] %d seconds\\n\", hashLastAbsentWitnessTip.ToString(), pindexTip->nHeight, nSecondsAbsent);\n                    }\n                }\n                else\n                {\n                    hashLastAbsentWitnessTip = pindexTip->GetBlockHashPoW2();\n                    timeLastAbsentWitnessTip = GetTimeMillis();\n                    secondsLastAbsentWitnessTip = 0;\n                }\n            }\n\n            // Use a cache to prevent trying the same blocks over and over.\n            // Look for all potential signable blocks at same height as the index tip - don't limit ourselves to just the tip\n            // This is important because otherwise the chain can stall if there is an absent signer for the current tip.\n            std::vector<CBlockIndex*> candidateOrphans;\n            if (cacheAlreadySeenWitnessCandidates.find(pindexTip) == cacheAlreadySeenWitnessCandidates.end())\n            {\n                LogPrint(BCLog::WITNESS, \"MuntWitness: Add witness candidate from chain tip [%s]\\n\", pindexTip->GetBlockHashPoW2().ToString());\n                candidateOrphans.push_back(pindexTip);\n            }\n            if (candidateOrphans.size() == 0)\n            {\n                for (const auto candidateIter : GetTopLevelPoWOrphans(pindexTip->nHeight, *(pindexTip->pprev->phashBlock)))\n                {\n                    if (cacheAlreadySeenWitnessCandidates.find(candidateIter) == cacheAlreadySeenWitnessCandidates.end())\n                    {\n                        LogPrint(BCLog::WITNESS, \"MuntWitness: Add witness candidate from top level pow orphans [%s]\\n\", candidateIter->GetBlockHashPoW2().ToString());\n                        candidateOrphans.push_back(candidateIter);\n                    }\n                }\n                if (cacheAlreadySeenWitnessCandidates.size() > 100000)\n                {\n                    auto eraseEnd = cacheAlreadySeenWitnessCandidates.begin();\n                    std::advance(eraseEnd, cacheAlreadySeenWitnessCandidates.size() - 10);\n                    cacheAlreadySeenWitnessCandidates.erase(cacheAlreadySeenWitnessCandidates.begin(), eraseEnd);\n                }\n            }\n            boost::this_thread::interruption_point();\n\n            if (candidateOrphans.size() > 0)\n            {\n                LOCK2(processBlockCS,cs_main); //cs_main lock for ReadBlockFromDisk and chainActive.Tip()\n                \n                if (chainActive.Tip() != pindexTip)\n                {\n                    continue;\n                }\n\n                \n                for (const auto candidateIter : candidateOrphans)\n                {\n                    boost::this_thread::interruption_point();\n\n                    cacheAlreadySeenWitnessCandidates.insert(candidateIter);\n\n                    //Create new block\n                    std::shared_ptr<CBlock> pWitnessBlock(new CBlock);\n                    if (ReadBlockFromDisk(*pWitnessBlock, candidateIter, chainparams))\n                    {\n                        boost::this_thread::interruption_point();\n                        CGetWitnessInfo witnessInfo;\n\n                        if (!GetWitness(chainActive, chainparams, nullptr, candidateIter->pprev, *pWitnessBlock, witnessInfo))\n                        {\n                            LogPrintf(\"MuntWitness: Invalid candidate witness [%s]\\n\", candidateIter->GetBlockHashPoW2().ToString());\n                            static int64_t nLastErrorHeight = -1;\n\n                            if (nLastErrorHeight == -1 || candidateIter->nHeight - nLastErrorHeight > 10)\n                            {\n                                nLastErrorHeight = candidateIter->nHeight;\n                                continue;\n                            }\n                            nLastErrorHeight = candidateIter->nHeight;\n                            std::string strErrorMessage = strprintf(\"Failed to calculate witness info for candidate block.\\n If this occurs frequently please contact a developer for assistance.\\n height [%d] chain-tip-height [%d]\", candidateIter->nHeight, chainActive.Tip()? chainActive.Tip()->nHeight : 0);\n                            CAlert::Notify(strErrorMessage, true, true);\n                            LogPrintf(\"%s\\n\", strErrorMessage.c_str());\n                            continue;\n                        }\n\n                        // Create all the witness inputs/outputs and additional metadata, add any additional transactions, sign block etc.\n                        boost::this_thread::interruption_point();\n                        bool encounteredError=false;\n                        bool signedBlock=false;\n                        TryPopulateAndSignWitnessBlock(candidateIter, chainparams, consensusParams, witnessInfo, pWitnessBlock, reserveKeys, encounteredError, signedBlock);\n                        \n                        //fixme: (HIGH) If we signed the block consider terminating the loop and purging all other candidates of same height at this point.\n                    }\n                }\n            }\n        }\n    }\n    catch (const boost::thread_interrupted&)\n    {\n        cacheAlreadySeenWitnessCandidates.clear();\n        LogPrintf(\"Witness thread terminated\\n\");\n        throw;\n    }\n    catch (const std::runtime_error &e)\n    {\n        cacheAlreadySeenWitnessCandidates.clear();\n        LogPrintf(\"Witness thread runtime error: %s\\n\", e.what());\n        return;\n    }\n}\n\n#endif\n\n\nvoid StartPoW2WitnessThread(boost::thread_group& threadGroup)\n{\n    #ifdef ENABLE_WALLET\n    threadGroup.create_thread(boost::bind(&util::TraceThread, \"pow2_witness\", &MuntWitness));\n    #endif\n}\n"
  },
  {
    "path": "src/generation/witness.h",
    "content": "// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef GENERATION_WITNESS_H\n#define GENERATION_WITNESS_H\n\n#include <boost/thread/thread.hpp>\n\n//fixme: (POST-PHASE5) This is non-ideal; we should rather use a signal or something for this.\n//! Indicate to the witness thread that it must erase the witness script cache and recalculate it.\nextern bool witnessScriptsAreDirty;\n\nextern bool witnessingEnabled;\n\n//! Run the main witnessing thread; On wallets with no witnessing accounts this will just sleep permanently.\nvoid StartPoW2WitnessThread(boost::thread_group& threadGroup);\n\n#endif\n"
  },
  {
    "path": "src/generation/witnessrewardtemplate.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"witnessrewardtemplate.h\"\n\n#include <numeric>\n\nbool CWitnessRewardTemplate::empty() const\n{\n    return destinations.empty();\n}\n\nCAmount CWitnessRewardTemplate::fixedAmountsSum() const {\n    return std::accumulate(destinations.begin(), destinations.end(), CAmount(0),\n                           [](const CAmount acc, const auto& it){ return acc + it.amount; });\n}\n\ndouble CWitnessRewardTemplate::percentagesSum() const {\n    return std::accumulate(destinations.begin(), destinations.end(), 0.0,\n                           [](const double acc, const auto& it){ return acc + it.percent; });\n}\n\nvoid CWitnessRewardTemplate::validate(const CAmount witnessBlockSubsidy)\n{\n    int numRemainder = std::count_if(destinations.begin(), destinations.end(), [](const CWitnessRewardDestination& dest) { return dest.takesRemainder; });\n    if (numRemainder > 1)\n        throw std::runtime_error(\"Too many remainder destinations in reward template\");\n\n    int numOverflow = std::count_if(destinations.begin(), destinations.end(), [](const CWitnessRewardDestination& dest) { return dest.takesCompoundOverflow; });\n    if (numOverflow > 1)\n        throw std::runtime_error(\"Too many compound_overflow destinations in reward template\");\n\n    std::for_each(destinations.begin(), destinations.end(), [](const CWitnessRewardDestination& dest) {\n        if (dest.percent < 0 || dest.percent > 1.0)\n            throw std::runtime_error(\"Percentage out-of-range [0..100] in reward template\");\n\n        if (dest.type == CWitnessRewardDestination::DestType::Compound && dest.takesCompoundOverflow)\n            throw std::runtime_error(\"\\\"compound_overflow\\\" not allowed on \\\"compound\\\" destination in reward template\");\n    });\n\n    double totalPercent = percentagesSum();\n    if (totalPercent > 1.0)\n        throw std::runtime_error(\"Percentage out-of-range [0..100] in reward template\");\n\n    if (totalPercent < 1.0 && numRemainder == 0)\n        throw std::runtime_error(\"Remainder required in reward template\");\n\n    if (fixedAmountsSum() > witnessBlockSubsidy)\n        throw std::runtime_error(\"Fixed payouts exceed block reward in reward template\");\n}\n"
  },
  {
    "path": "src/generation/witnessrewardtemplate.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WITNESS_REWARD_TEMPLATE_H\n#define WITNESS_REWARD_TEMPLATE_H\n\n#include \"base58.h\"\n#include \"amount.h\"\n#include <vector>\n\nstruct CWitnessRewardDestination {\n    enum class DestType: uint16_t {\n        Compound,\n        Account,\n        Address\n    };\n\n    DestType type;\n    CNativeAddress address;\n    CAmount amount;\n    double percent;\n    bool takesRemainder;\n    bool takesCompoundOverflow;\n\n    CWitnessRewardDestination(): type(DestType::Account), amount(0), percent(0), takesRemainder(false), takesCompoundOverflow(false) {}\n    CWitnessRewardDestination(const DestType _type, const CNativeAddress& _address, const CAmount _amount, const double _percent, const bool _takesRemainder, const bool _takesCompoundOverflow)\n        : type(_type), address(_address), amount(_amount), percent(_percent), takesRemainder(_takesRemainder), takesCompoundOverflow(_takesCompoundOverflow) {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(type);\n        READWRITE(address);\n        READWRITE(amount);\n        READWRITE(percent);\n        READWRITE(takesRemainder);\n        READWRITE(takesCompoundOverflow);\n    }\n};\n\nclass CWitnessRewardTemplate {\npublic:\n    bool empty() const;\n    std::vector<CWitnessRewardDestination> destinations;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITECOMPACTSIZEVECTOR(destinations);\n    }\n\n    CAmount fixedAmountsSum() const;\n    double percentagesSum() const;\n\n    //! Basic sanity checks on the template (like total % < 100 etc), throws if there are issues\n    void validate(const CAmount witnessBlockSubsidy);\n};\n\n#endif\n"
  },
  {
    "path": "src/hash.cpp",
    "content": "// Copyright (c) 2013-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"hash.h\"\n#include \"crypto/common.h\"\n#include \"crypto/hmac_sha512.h\"\n#include \"pubkey.h\"\n\n\ninline uint32_t ROTL32(uint32_t x, int8_t r)\n{\n    return (x << r) | (x >> (32 - r));\n}\n\nunsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash)\n{\n    // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp\n    uint32_t h1 = nHashSeed;\n    if (vDataToHash.size() > 0)\n    {\n        const uint32_t c1 = 0xcc9e2d51;\n        const uint32_t c2 = 0x1b873593;\n\n        const int nblocks = vDataToHash.size() / 4;\n\n        //----------\n        // body\n        const uint8_t* blocks = &vDataToHash[0] + nblocks * 4;\n\n        for (int i = -nblocks; i; i++) {\n            uint32_t k1 = ReadLE32(blocks + i*4);\n\n            k1 *= c1;\n            k1 = ROTL32(k1, 15);\n            k1 *= c2;\n\n            h1 ^= k1;\n            h1 = ROTL32(h1, 13);\n            h1 = h1 * 5 + 0xe6546b64;\n        }\n\n        //----------\n        // tail\n        const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4);\n\n        uint32_t k1 = 0;\n\n        switch (vDataToHash.size() & 3) {\n        case 3:\n            k1 ^= tail[2] << 16;\n        case 2:\n            k1 ^= tail[1] << 8;\n        case 1:\n            k1 ^= tail[0];\n            k1 *= c1;\n            k1 = ROTL32(k1, 15);\n            k1 *= c2;\n            h1 ^= k1;\n        }\n    }\n\n    //----------\n    // finalization\n    h1 ^= vDataToHash.size();\n    h1 ^= h1 >> 16;\n    h1 *= 0x85ebca6b;\n    h1 ^= h1 >> 13;\n    h1 *= 0xc2b2ae35;\n    h1 ^= h1 >> 16;\n\n    return h1;\n}\n\nvoid BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64])\n{\n    unsigned char num[4];\n    num[0] = (nChild >> 24) & 0xFF;\n    num[1] = (nChild >> 16) & 0xFF;\n    num[2] = (nChild >>  8) & 0xFF;\n    num[3] = (nChild >>  0) & 0xFF;\n    CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);\n}\n\n#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))\n\n#define SIPROUND do { \\\n    v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \\\n    v0 = ROTL(v0, 32); \\\n    v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \\\n    v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \\\n    v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \\\n    v2 = ROTL(v2, 32); \\\n} while (0)\n\nCSipHasher::CSipHasher(uint64_t k0, uint64_t k1)\n{\n    v[0] = 0x736f6d6570736575ULL ^ k0;\n    v[1] = 0x646f72616e646f6dULL ^ k1;\n    v[2] = 0x6c7967656e657261ULL ^ k0;\n    v[3] = 0x7465646279746573ULL ^ k1;\n    count = 0;\n    tmp = 0;\n}\n\nCSipHasher& CSipHasher::Write(uint64_t data)\n{\n    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];\n\n    assert(count % 8 == 0);\n\n    v3 ^= data;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= data;\n\n    v[0] = v0;\n    v[1] = v1;\n    v[2] = v2;\n    v[3] = v3;\n\n    count += 8;\n    return *this;\n}\n\nCSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)\n{\n    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];\n    uint64_t t = tmp;\n    int c = count;\n\n    while (size--) {\n        t |= ((uint64_t)(*(data++))) << (8 * (c % 8));\n        c++;\n        if ((c & 7) == 0) {\n            v3 ^= t;\n            SIPROUND;\n            SIPROUND;\n            v0 ^= t;\n            t = 0;\n        }\n    }\n\n    v[0] = v0;\n    v[1] = v1;\n    v[2] = v2;\n    v[3] = v3;\n    count = c;\n    tmp = t;\n\n    return *this;\n}\n\nuint64_t CSipHasher::Finalize() const\n{\n    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];\n\n    uint64_t t = tmp | (((uint64_t)count) << 56);\n\n    v3 ^= t;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= t;\n    v2 ^= 0xFF;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    return v0 ^ v1 ^ v2 ^ v3;\n}\n\nuint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)\n{\n    /* Specialized implementation for efficiency */\n    uint64_t d = val.GetUint64(0);\n\n    uint64_t v0 = 0x736f6d6570736575ULL ^ k0;\n    uint64_t v1 = 0x646f72616e646f6dULL ^ k1;\n    uint64_t v2 = 0x6c7967656e657261ULL ^ k0;\n    uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;\n\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(1);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(2);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(3);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    v3 ^= ((uint64_t)4) << 59;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= ((uint64_t)4) << 59;\n    v2 ^= 0xFF;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    return v0 ^ v1 ^ v2 ^ v3;\n}\n\nuint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)\n{\n    /* Specialized implementation for efficiency */\n    uint64_t d = val.GetUint64(0);\n\n    uint64_t v0 = 0x736f6d6570736575ULL ^ k0;\n    uint64_t v1 = 0x646f72616e646f6dULL ^ k1;\n    uint64_t v2 = 0x6c7967656e657261ULL ^ k0;\n    uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;\n\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(1);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(2);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = val.GetUint64(3);\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    d = (((uint64_t)36) << 56) | extra;\n    v3 ^= d;\n    SIPROUND;\n    SIPROUND;\n    v0 ^= d;\n    v2 ^= 0xFF;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    SIPROUND;\n    return v0 ^ v1 ^ v2 ^ v3;\n}\n"
  },
  {
    "path": "src/hash.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_HASH_H\n#define CORE_HASH_H\n\n#include \"crypto/ripemd160.h\"\n#include \"crypto/sha256.h\"\n#include \"prevector.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n#include \"version.h\"\n\n#include <vector>\n\ntypedef uint256 ChainCode;\n\n/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */\nclass CHash256 {\nprivate:\n    CSHA256 sha;\npublic:\n    static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;\n\n    void Finalize(unsigned char hash[OUTPUT_SIZE]) {\n        unsigned char buf[CSHA256::OUTPUT_SIZE];\n        sha.Finalize(buf);\n        sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);\n    }\n\n    CHash256& Write(const unsigned char *data, size_t len) {\n        sha.Write(data, len);\n        return *this;\n    }\n\n    CHash256& Reset() {\n        sha.Reset();\n        return *this;\n    }\n};\n\n/** A hasher class for Bitcoin's 160-bit hash (SHA-256 + RIPEMD-160). */\nclass CHash160 {\nprivate:\n    CSHA256 sha;\npublic:\n    static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;\n\n    void Finalize(unsigned char hash[OUTPUT_SIZE]) {\n        unsigned char buf[CSHA256::OUTPUT_SIZE];\n        sha.Finalize(buf);\n        CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);\n    }\n\n    CHash160& Write(const unsigned char *data, size_t len) {\n        sha.Write(data, len);\n        return *this;\n    }\n\n    CHash160& Reset() {\n        sha.Reset();\n        return *this;\n    }\n};\n\n/** Compute the 256-bit hash of an object. */\ntemplate<typename T1>\ninline uint256 Hash(const T1 pbegin, const T1 pend)\n{\n    static const unsigned char pblank[1] = {};\n    uint256 result;\n    CHash256().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))\n              .Finalize((unsigned char*)&result);\n    return result;\n}\n\n/** Compute the 256-bit hash of the concatenation of two objects. */\ntemplate<typename T1, typename T2>\ninline uint256 Hash(const T1 p1begin, const T1 p1end,\n                    const T2 p2begin, const T2 p2end) {\n    static const unsigned char pblank[1] = {};\n    uint256 result;\n    CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))\n              .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))\n              .Finalize((unsigned char*)&result);\n    return result;\n}\n\n/** Compute the 256-bit hash of the concatenation of three objects. */\ntemplate<typename T1, typename T2, typename T3>\ninline uint256 Hash(const T1 p1begin, const T1 p1end,\n                    const T2 p2begin, const T2 p2end,\n                    const T3 p3begin, const T3 p3end) {\n    static const unsigned char pblank[1] = {};\n    uint256 result;\n    CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))\n              .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))\n              .Write(p3begin == p3end ? pblank : (const unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0]))\n              .Finalize((unsigned char*)&result);\n    return result;\n}\n\n/** Compute the 160-bit hash an object. */\ntemplate<typename T1>\ninline uint160 Hash160(const T1 pbegin, const T1 pend)\n{\n    static unsigned char pblank[1] = {};\n    uint160 result;\n    CHash160().Write(pbegin == pend ? pblank : (const unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]))\n              .Finalize((unsigned char*)&result);\n    return result;\n}\n\n/** Compute the 160-bit hash of a vector. */\ninline uint160 Hash160(const std::vector<unsigned char>& vch)\n{\n    return Hash160(vch.begin(), vch.end());\n}\n\n/** Compute the 160-bit hash of a vector. */\ntemplate<unsigned int N>\ninline uint160 Hash160(const prevector<N, unsigned char>& vch)\n{\n    return Hash160(vch.begin(), vch.end());\n}\n\n/** A writer stream (for serialization) that computes a 256-bit hash. */\nclass CHashWriter\n{\nprivate:\n    CHash256 ctx;\n\n    const int nType;\n    const int nVersion;\npublic:\n\n    CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}\n\n    int GetType() const { return nType; }\n    int GetVersion() const { return nVersion; }\n\n    void write(const char *pch, size_t size) {\n        ctx.Write((const unsigned char*)pch, size);\n    }\n    \n    void write(Span<const std::byte> dataSpan) {\n        ctx.Write((const unsigned char*)dataSpan.data(), dataSpan.size_bytes());\n    }\n\n    // invalidates the object\n    uint256 GetHash() {\n        uint256 result;\n        ctx.Finalize((unsigned char*)&result);\n        return result;\n    }\n\n    template<typename T>\n    CHashWriter& operator<<(const T& obj) {\n        // Serialize to this stream\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n};\n\n/** Reads data from an underlying stream, while hashing the read data. */\ntemplate<typename Source>\nclass CHashVerifier : public CHashWriter\n{\nprivate:\n    Source* source;\n\npublic:\n    CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}\n\n    void read(char* pch, size_t nSize)\n    {\n        source->read(pch, nSize);\n        this->write(pch, nSize);\n    }\n    \n    void read(Span<std::byte> dataSpan) {\n        source->read(dataSpan);\n        this->write(dataSpan);\n    }\n\n    void peek(char* pch, size_t nSize)\n    {\n        source->peek(pch, nSize);\n    }\n\n    void ignore(size_t nSize)\n    {\n        char data[1024];\n        while (nSize > 0) {\n            size_t now = std::min<size_t>(nSize, 1024);\n            read(data, now);\n            nSize -= now;\n        }\n    }\n\n    template<typename T>\n    CHashVerifier<Source>& operator>>(T& obj)\n    {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n};\n\n/** Compute the 256-bit hash of an object's serialization. */\ntemplate<typename T>\nuint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)\n{\n    CHashWriter ss(nType, nVersion);\n    ss << obj;\n    return ss.GetHash();\n}\n\nunsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);\n\nvoid BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);\n\n/** SipHash-2-4 */\nclass CSipHasher\n{\nprivate:\n    uint64_t v[4];\n    uint64_t tmp;\n    int count;\n\npublic:\n    /** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */\n    CSipHasher(uint64_t k0, uint64_t k1);\n    /** Hash a 64-bit integer worth of data\n     *  It is treated as if this was the little-endian interpretation of 8 bytes.\n     *  This function can only be used when a multiple of 8 bytes have been written so far.\n     */\n    CSipHasher& Write(uint64_t data);\n    /** Hash arbitrary bytes. */\n    CSipHasher& Write(const unsigned char* data, size_t size);\n    /** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */\n    uint64_t Finalize() const;\n};\n\n/** Optimized SipHash-2-4 implementation for uint256.\n *\n *  It is identical to:\n *    SipHasher(k0, k1)\n *      .Write(val.GetUint64(0))\n *      .Write(val.GetUint64(1))\n *      .Write(val.GetUint64(2))\n *      .Write(val.GetUint64(3))\n *      .Finalize()\n */\nuint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);\nuint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);\n\n#endif\n"
  },
  {
    "path": "src/httprpc.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"httprpc.h\"\n\n#include \"base58.h\"\n#include \"chainparams.h\"\n#include \"httpserver.h\"\n#include \"rpc/protocol.h\"\n#include \"rpc/server.h\"\n#include \"random.h\"\n#include \"sync.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"ui_interface.h\"\n#include \"crypto/hmac_sha256.h\"\n#include <stdio.h>\n\n#include <boost/algorithm/string.hpp> // boost::trim\n\n/** WWW-Authenticate to present with 401 Unauthorized response */\nstatic const char* WWW_AUTH_HEADER_DATA = \"Basic realm=\\\"jsonrpc\\\"\";\n\n/* Pre-base64-encoded authentication token */\nstatic std::string strRPCUserColonPass;\n\n\nstatic void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)\n{\n    // Send error reply from json-rpc error object\n    int nStatus = HTTP_INTERNAL_SERVER_ERROR;\n    int code = find_value(objError, \"code\").get_int();\n\n    if (code == RPC_INVALID_REQUEST)\n        nStatus = HTTP_BAD_REQUEST;\n    else if (code == RPC_METHOD_NOT_FOUND)\n        nStatus = HTTP_NOT_FOUND;\n\n    std::string strReply = JSONRPCReply(NullUniValue, objError, id);\n\n    req->WriteHeader(\"Content-Type\", \"application/json\");\n    req->WriteReply(nStatus, strReply);\n}\n\n//This function checks username and password against -rpcauth\n//entries from config file.\nstatic bool multiUserAuthorized(std::string strUserPass)\n{\n    if (strUserPass.find(\":\") == std::string::npos) {\n        return false;\n    }\n    std::string strUser = strUserPass.substr(0, strUserPass.find(\":\"));\n    std::string strPass = strUserPass.substr(strUserPass.find(\":\") + 1);\n\n    if (gArgs.IsArgSet(\"-rpcauth\")) {\n        //Search for multi-user login/pass \"rpcauth\" from config\n        for(std::string strRPCAuth : gArgs.GetArgs(\"-rpcauth\"))\n        {\n            std::vector<std::string> vFields;\n            boost::split(vFields, strRPCAuth, boost::is_any_of(\":$\"));\n            if (vFields.size() != 3) {\n                //Incorrect formatting in config file\n                continue;\n            }\n\n            std::string strName = vFields[0];\n            if (!TimingResistantEqual(strName, strUser)) {\n                continue;\n            }\n\n            std::string strSalt = vFields[1];\n            std::string strHash = vFields[2];\n\n            static const unsigned int KEY_SIZE = 32;\n            unsigned char out[KEY_SIZE];\n\n            CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);\n            std::vector<unsigned char> hexvec(out, out+KEY_SIZE);\n            std::string strHashFromPass = HexStr(hexvec);\n\n            if (TimingResistantEqual(strHashFromPass, strHash)) {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nstatic bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)\n{\n    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called\n        return false;\n    if (strAuth.substr(0, 6) != \"Basic \")\n        return false;\n    std::string strUserPass64 = strAuth.substr(6);\n    boost::trim(strUserPass64);\n    std::string strUserPass = DecodeBase64(strUserPass64);\n\n    if (strUserPass.find(\":\") != std::string::npos)\n        strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(\":\"));\n\n    //Check if authorized under single-user field\n    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {\n        return true;\n    }\n    return multiUserAuthorized(strUserPass);\n}\n\nstatic bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)\n{\n    // JSONRPC handles only POST\n    if (req->GetRequestMethod() != HTTPRequest::POST) {\n        req->WriteReply(HTTP_BAD_METHOD, \"JSONRPC server handles only POST requests\");\n        return false;\n    }\n    // Check authorization\n    std::pair<bool, std::string> authHeader = req->GetHeader(\"authorization\");\n    if (!authHeader.first) {\n        req->WriteHeader(\"WWW-Authenticate\", WWW_AUTH_HEADER_DATA);\n        req->WriteReply(HTTP_UNAUTHORIZED);\n        return false;\n    }\n\n    JSONRPCRequest jreq;\n    if (!RPCAuthorized(authHeader.second, jreq.authUser)) {\n        LogPrintf(\"ThreadRPCServer incorrect password attempt from %s\\n\", req->GetPeer().ToString());\n\n        /* Deter brute-forcing\n           If this results in a DoS the user really\n           shouldn't have their RPC port exposed. */\n        MilliSleep(250);\n\n        req->WriteHeader(\"WWW-Authenticate\", WWW_AUTH_HEADER_DATA);\n        req->WriteReply(HTTP_UNAUTHORIZED);\n        return false;\n    }\n\n    try {\n        // Parse request\n        UniValue valRequest;\n        if (!valRequest.read(req->ReadBody()))\n            throw JSONRPCError(RPC_PARSE_ERROR, \"Parse error\");\n\n        // Set the URI\n        jreq.URI = req->GetURI();\n\n        std::string strReply;\n        // singleton request\n        if (valRequest.isObject()) {\n            jreq.parse(valRequest);\n\n            UniValue result = tableRPC.execute(jreq);\n\n            // Send reply\n            strReply = JSONRPCReply(result, NullUniValue, jreq.id);\n\n        // array of requests\n        } else if (valRequest.isArray())\n            strReply = JSONRPCExecBatch(valRequest.get_array());\n        else\n            throw JSONRPCError(RPC_PARSE_ERROR, \"Top-level object parse error\");\n\n        req->WriteHeader(\"Content-Type\", \"application/json\");\n        req->WriteReply(HTTP_OK, strReply);\n    } catch (const UniValue& objError) {\n        JSONErrorReply(req, objError, jreq.id);\n        return false;\n    } catch (const std::exception& e) {\n        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);\n        return false;\n    }\n    return true;\n}\n\nstatic bool InitRPCAuthentication()\n{\n    if (GetArg(\"-rpcpassword\", \"\") == \"\")\n    {\n        LogPrintf(\"No rpcpassword set - using random cookie authentication\\n\");\n        if (!GenerateAuthCookie(&strRPCUserColonPass)) {\n            uiInterface.ThreadSafeMessageBox(\n                _(\"Error: A fatal internal error occurred, see debug.log for details\"), // Same message as AbortNode\n                \"\", CClientUIInterface::MSG_ERROR);\n            return false;\n        }\n    } else {\n        LogPrintf(\"Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\\n\");\n        strRPCUserColonPass = GetArg(\"-rpcuser\", \"\") + \":\" + GetArg(\"-rpcpassword\", \"\");\n    }\n    return true;\n}\n\nbool StartHTTPRPC()\n{\n    LogPrint(BCLog::RPC, \"Starting HTTP RPC server\\n\");\n    if (!InitRPCAuthentication())\n        return false;\n\n    RegisterHTTPHandler(\"/\", true, HTTPReq_JSONRPC);\n\n    assert(EventBase());\n    return true;\n}\n\nvoid InterruptHTTPRPC()\n{\n    LogPrint(BCLog::RPC, \"Interrupting HTTP RPC server\\n\");\n}\n\nvoid StopHTTPRPC()\n{\n    LogPrint(BCLog::RPC, \"Stopping HTTP RPC server\\n\");\n    UnregisterHTTPHandler(\"/\", true);\n}\n"
  },
  {
    "path": "src/httprpc.h",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_HTTPRPC_H\n#define CORE_HTTPRPC_H\n\n#include <string>\n#include <map>\n\nclass HTTPRequest;\n\n/** Start HTTP RPC subsystem.\n * Precondition; HTTP and RPC has been started.\n */\nbool StartHTTPRPC();\n/** Interrupt HTTP RPC subsystem.\n */\nvoid InterruptHTTPRPC();\n/** Stop HTTP RPC subsystem.\n * Precondition; HTTP and RPC has been stopped.\n */\nvoid StopHTTPRPC();\n\n/** Start HTTP REST subsystem.\n * Precondition; HTTP and RPC has been started.\n */\nbool StartREST();\n/** Interrupt RPC REST subsystem.\n */\nvoid InterruptREST();\n/** Stop HTTP REST subsystem.\n * Precondition; HTTP and RPC has been stopped.\n */\nvoid StopREST();\n\n#endif\n"
  },
  {
    "path": "src/httpserver.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"httpserver.h\"\n\n#include \"chainparamsbase.h\"\n#include \"compat.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/threadnames.h\"\n#include \"appname.h\"\n#include \"netbase.h\"\n#include \"rpc/protocol.h\" // For HTTP status codes\n#include \"sync.h\"\n#include \"ui_interface.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <signal.h>\n#include <future>\n\n#include <event2/event.h>\n#include <event2/http.h>\n#include <event2/thread.h>\n#include <event2/buffer.h>\n#include <event2/util.h>\n#include <event2/keyvalq_struct.h>\n\n#include <deque>\n\n#ifdef EVENT__HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#ifdef _XOPEN_SOURCE_EXTENDED\n#include <arpa/inet.h>\n#endif\n#endif\n\n/** Maximum size of http request (request line + headers) */\nstatic const size_t MAX_HEADERS_SIZE = 8192;\n\n/** HTTP request work item */\nclass HTTPWorkItem : public HTTPClosure\n{\npublic:\n    HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):\n        req(std::move(_req)), path(_path), func(_func)\n    {\n    }\n    void operator()()\n    {\n        func(req.get(), path);\n    }\n\n    std::unique_ptr<HTTPRequest> req;\n\nprivate:\n    std::string path;\n    HTTPRequestHandler func;\n};\n\n/** Simple work queue for distributing work over multiple threads.\n * Work items are simply callable objects.\n */\ntemplate <typename WorkItem>\nclass WorkQueue\n{\nprivate:\n    /** Mutex protects entire object */\n    std::mutex cs;\n    std::condition_variable cond;\n    std::deque<std::unique_ptr<WorkItem>> queue;\n    bool running;\n    size_t maxDepth;\n    int numThreads;\n\n    /** RAII object to keep track of number of running worker threads */\n    class ThreadCounter\n    {\n    public:\n        WorkQueue &wq;\n        ThreadCounter(WorkQueue &w): wq(w)\n        {\n            std::lock_guard<std::mutex> lock(wq.cs);\n            wq.numThreads += 1;\n        }\n        ~ThreadCounter()\n        {\n            std::lock_guard<std::mutex> lock(wq.cs);\n            wq.numThreads -= 1;\n            wq.cond.notify_all();\n        }\n    };\n\npublic:\n    WorkQueue(size_t _maxDepth) : running(true),\n                                 maxDepth(_maxDepth),\n                                 numThreads(0)\n    {\n    }\n    /** Precondition: worker threads have all stopped\n     * (call WaitExit)\n     */\n    ~WorkQueue()\n    {\n    }\n    /** Enqueue a work item */\n    bool Enqueue(WorkItem* item)\n    {\n        std::unique_lock<std::mutex> lock(cs);\n        if (queue.size() >= maxDepth) {\n            return false;\n        }\n        queue.emplace_back(std::unique_ptr<WorkItem>(item));\n        cond.notify_one();\n        return true;\n    }\n    /** Thread function */\n    void Run()\n    {\n        ThreadCounter count(*this);\n        while (true) {\n            std::unique_ptr<WorkItem> i;\n            {\n                std::unique_lock<std::mutex> lock(cs);\n                while (running && queue.empty())\n                    cond.wait(lock);\n                if (!running)\n                    break;\n                i = std::move(queue.front());\n                queue.pop_front();\n            }\n            (*i)();\n        }\n    }\n    /** Interrupt and exit loops */\n    void Interrupt()\n    {\n        std::unique_lock<std::mutex> lock(cs);\n        running = false;\n        cond.notify_all();\n    }\n    /** Wait for worker threads to exit */\n    void WaitExit()\n    {\n        std::unique_lock<std::mutex> lock(cs);\n        while (numThreads > 0)\n            cond.wait(lock);\n    }\n};\n\nstruct HTTPPathHandler\n{\n    HTTPPathHandler() {}\n    HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):\n        prefix(_prefix), exactMatch(_exactMatch), handler(_handler)\n    {\n    }\n    std::string prefix;\n    bool exactMatch;\n    HTTPRequestHandler handler;\n};\n\n/** HTTP module state */\n\n//! libevent event loop\nstatic struct event_base* eventBase = 0;\n//! HTTP server\nstruct evhttp* eventHTTP = 0;\n//! List of subnets to allow RPC connections from\nstatic std::vector<CSubNet> rpc_allow_subnets;\n//! Work queue for handling longer requests off the event loop thread\nstatic WorkQueue<HTTPClosure>* workQueue = 0;\n//! Handlers for (sub)paths\nstd::vector<HTTPPathHandler> pathHandlers;\n//! Bound listening sockets\nstd::vector<evhttp_bound_socket *> boundSockets;\n\n/** Check if a network address is allowed to access the HTTP server */\nstatic bool ClientAllowed(const CNetAddr& netaddr)\n{\n    if (!netaddr.IsValid())\n        return false;\n    for(const CSubNet& subnet : rpc_allow_subnets)\n        if (subnet.Match(netaddr))\n            return true;\n    return false;\n}\n\n/** Initialize ACL list for HTTP server */\nstatic bool InitHTTPAllowList()\n{\n    rpc_allow_subnets.clear();\n    CNetAddr localv4;\n    CNetAddr localv6;\n    LookupHost(\"127.0.0.1\", localv4, false);\n    LookupHost(\"::1\", localv6, false);\n    rpc_allow_subnets.push_back(CSubNet(localv4, 8));      // always allow IPv4 local subnet\n    rpc_allow_subnets.push_back(CSubNet(localv6));         // always allow IPv6 localhost\n    if (gArgs.IsArgSet(\"-rpcallowip\")) {\n        for (const std::string& strAllow : gArgs.GetArgs(\"-rpcallowip\")) {\n            CSubNet subnet;\n            LookupSubNet(strAllow.c_str(), subnet);\n            if (!subnet.IsValid()) {\n                uiInterface.ThreadSafeMessageBox(\n                    strprintf(\"Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).\", strAllow),\n                    \"\", CClientUIInterface::MSG_ERROR);\n                return false;\n            }\n            rpc_allow_subnets.push_back(subnet);\n        }\n    }\n    std::string strAllowed;\n    for (const CSubNet& subnet : rpc_allow_subnets)\n        strAllowed += subnet.ToString() + \" \";\n    LogPrint(BCLog::HTTP, \"Allowing HTTP connections from: %s\\n\", strAllowed);\n    return true;\n}\n\n/** HTTP request method as string - use for logging only */\nstatic std::string RequestMethodString(HTTPRequest::RequestMethod m)\n{\n    switch (m) {\n    case HTTPRequest::GET:\n        return \"GET\";\n        break;\n    case HTTPRequest::POST:\n        return \"POST\";\n        break;\n    case HTTPRequest::HEAD:\n        return \"HEAD\";\n        break;\n    case HTTPRequest::PUT:\n        return \"PUT\";\n        break;\n    case HTTPRequest::UNKNOWN:\n    default:\n        return \"unknown\";\n    }\n}\n\n/** HTTP request callback */\nstatic void http_request_cb(struct evhttp_request* req, void* arg)\n{\n    (unused) arg;\n    std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));\n\n    LogPrint(BCLog::HTTP, \"Received a %s request for %s from %s\\n\",\n             RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());\n\n    // Early address-based allow check\n    if (!ClientAllowed(hreq->GetPeer())) {\n        hreq->WriteReply(HTTP_FORBIDDEN);\n        return;\n    }\n\n    // Early reject unknown HTTP methods\n    if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {\n        hreq->WriteReply(HTTP_BADMETHOD);\n        return;\n    }\n\n    // Find registered handler for prefix\n    std::string strURI = hreq->GetURI();\n    std::string path;\n    std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();\n    std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();\n    for (; i != iend; ++i) {\n        bool match = false;\n        if (i->exactMatch)\n            match = (strURI == i->prefix);\n        else\n            match = (strURI.substr(0, i->prefix.size()) == i->prefix);\n        if (match) {\n            path = strURI.substr(i->prefix.size());\n            break;\n        }\n    }\n\n    // Dispatch to worker thread\n    if (i != iend) {\n        std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(std::move(hreq), path, i->handler));\n        assert(workQueue);\n        if (workQueue->Enqueue(item.get()))\n            item.release(); /* if true, queue took ownership */\n        else {\n            LogPrintf(\"WARNING: request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting\\n\");\n            item->req->WriteReply(HTTP_INTERNAL, \"Work queue depth exceeded\");\n        }\n    } else {\n        hreq->WriteReply(HTTP_NOTFOUND);\n    }\n}\n\n/** Callback to reject HTTP requests after shutdown. */\nstatic void http_reject_request_cb(struct evhttp_request* req, void*)\n{\n    LogPrint(BCLog::HTTP, \"Rejecting request while shutting down\\n\");\n    evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);\n}\n\n/** Event dispatcher thread */\nstatic bool ThreadHTTP(struct event_base* base, struct evhttp* http)\n{\n    (unused) http;\n    util::ThreadRename(GLOBAL_APPNAME\"-http\");\n    LogPrint(BCLog::HTTP, \"Entering http event loop\\n\");\n    event_base_dispatch(base);\n    // Event loop will be interrupted by InterruptHTTPServer()\n    LogPrint(BCLog::HTTP, \"Exited http event loop\\n\");\n    return event_base_got_break(base) == 0;\n}\n\n/** Bind HTTP server to specified addresses */\nstatic bool HTTPBindAddresses(struct evhttp* http)\n{\n    int defaultPort = GetArg(\"-rpcport\", BaseParams().RPCPort());\n    std::vector<std::pair<std::string, uint16_t> > endpoints;\n\n    // Determine what addresses to bind to\n    if (!IsArgSet(\"-rpcallowip\")) { // Default to loopback if not allowing external IPs\n        endpoints.push_back(std::pair(\"::1\", defaultPort));\n        endpoints.push_back(std::pair(\"127.0.0.1\", defaultPort));\n        if (IsArgSet(\"-rpcbind\")) {\n            LogPrintf(\"WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\\n\");\n        }\n    } else if (gArgs.IsArgSet(\"-rpcbind\")) { // Specific bind address\n        for (const std::string& strRPCBind : gArgs.GetArgs(\"-rpcbind\")) {\n            int port = defaultPort;\n            std::string host;\n            SplitHostPort(strRPCBind, port, host);\n            endpoints.push_back(std::pair(host, port));\n        }\n    } else { // No specific bind address specified, bind to any\n        endpoints.push_back(std::pair(\"::\", defaultPort));\n        endpoints.push_back(std::pair(\"0.0.0.0\", defaultPort));\n    }\n\n    // Bind addresses\n    for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {\n        LogPrint(BCLog::HTTP, \"Binding RPC on address %s port %i\\n\", i->first, i->second);\n        evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);\n        if (bind_handle) {\n            boundSockets.push_back(bind_handle);\n        } else {\n            LogPrintf(\"Binding RPC on address %s port %i failed.\\n\", i->first, i->second);\n        }\n    }\n    return !boundSockets.empty();\n}\n\n/** Simple wrapper to set thread name and run work queue */\nstatic void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)\n{\n    util::ThreadRename(GLOBAL_APPNAME\"-httpworker\");\n    queue->Run();\n}\n\n/** libevent event log callback */\nstatic void libevent_log_cb(int severity, const char *msg)\n{\n#ifndef EVENT_LOG_WARN\n// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.\n# define EVENT_LOG_WARN _EVENT_LOG_WARN\n#endif\n    if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category\n        LogPrintf(\"libevent: %s\\n\", msg);\n    else\n        LogPrint(BCLog::LIBEVENT, \"libevent: %s\\n\", msg);\n}\n\nbool InitHTTPServer()\n{\n    struct evhttp* http = 0;\n    struct event_base* base = 0;\n\n    if (!InitHTTPAllowList())\n        return false;\n\n    if (GetBoolArg(\"-rpcssl\", false)) {\n        uiInterface.ThreadSafeMessageBox(\n            \"SSL mode for RPC (-rpcssl) is no longer supported.\",\n            \"\", CClientUIInterface::MSG_ERROR);\n        return false;\n    }\n\n    // Redirect libevent's logging to our own log\n    event_set_log_callback(&libevent_log_cb);\n    // Update libevent's log handling. Returns false if our version of\n    // libevent doesn't support debug logging, in which case we should\n    // clear the BCLog::LIBEVENT flag.\n    if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {\n        logCategories &= ~BCLog::LIBEVENT;\n    }\n\n#ifdef WIN32\n    evthread_use_windows_threads();\n#else\n    evthread_use_pthreads();\n#endif\n\n    base = event_base_new(); // XXX RAII\n    if (!base) {\n        LogPrintf(\"Couldn't create an event_base: exiting\\n\");\n        return false;\n    }\n\n    /* Create a new evhttp object to handle requests. */\n    http = evhttp_new(base); // XXX RAII\n    if (!http) {\n        LogPrintf(\"couldn't create evhttp. Exiting.\\n\");\n        event_base_free(base);\n        return false;\n    }\n\n    evhttp_set_timeout(http, GetArg(\"-rpcservertimeout\", DEFAULT_HTTP_SERVER_TIMEOUT));\n    evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);\n    evhttp_set_max_body_size(http, MAX_SIZE);\n    evhttp_set_gencb(http, http_request_cb, NULL);\n\n    if (!HTTPBindAddresses(http)) {\n        LogPrintf(\"Unable to bind any endpoint for RPC server\\n\");\n        evhttp_free(http);\n        event_base_free(base);\n        return false;\n    }\n\n    LogPrint(BCLog::HTTP, \"Initialized HTTP server\\n\");\n    int workQueueDepth = std::max((long)GetArg(\"-rpcworkqueue\", DEFAULT_HTTP_WORKQUEUE), 1L);\n    LogPrintf(\"HTTP: creating work queue of depth %d\\n\", workQueueDepth);\n\n    workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);\n    eventBase = base;\n    eventHTTP = http;\n    return true;\n}\n\nbool UpdateHTTPServerLogging(bool enable) {\n#if LIBEVENT_VERSION_NUMBER >= 0x02010100\n    if (enable) {\n        event_enable_debug_logging(EVENT_DBG_ALL);\n    } else {\n        event_enable_debug_logging(EVENT_DBG_NONE);\n    }\n    return true;\n#else\n    // Can't update libevent logging if version < 02010100\n    return false;\n#endif\n}\n\nstd::thread threadHTTP;\nstd::future<bool> threadResult;\n\nbool StartHTTPServer()\n{\n    LogPrint(BCLog::HTTP, \"Starting HTTP server\\n\");\n    int rpcThreads = std::max((long)GetArg(\"-rpcthreads\", DEFAULT_HTTP_THREADS), 1L);\n    LogPrintf(\"HTTP: starting %d worker threads\\n\", rpcThreads);\n    std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);\n    threadResult = task.get_future();\n    threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);\n\n    for (int i = 0; i < rpcThreads; i++) {\n        std::thread rpc_worker(HTTPWorkQueueRun, workQueue);\n        rpc_worker.detach();\n    }\n    return true;\n}\n\nvoid InterruptHTTPServer()\n{\n    LogPrint(BCLog::HTTP, \"Interrupting HTTP server\\n\");\n    if (eventHTTP) {\n        // Unlisten sockets\n        for (evhttp_bound_socket *socket : boundSockets) {\n            evhttp_del_accept_socket(eventHTTP, socket);\n        }\n        // Reject requests on current connections\n        evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);\n    }\n    if (workQueue)\n        workQueue->Interrupt();\n}\n\nvoid StopHTTPServer()\n{\n    LogPrint(BCLog::HTTP, \"Stopping HTTP server\\n\");\n    if (workQueue) {\n        LogPrint(BCLog::HTTP, \"Waiting for HTTP worker threads to exit\\n\");\n        workQueue->WaitExit();\n        delete workQueue;\n        workQueue = nullptr;\n    }\n    if (eventBase) {\n        LogPrint(BCLog::HTTP, \"Waiting for HTTP event thread to exit\\n\");\n        // Give event loop a few seconds to exit (to send back last RPC responses), then break it\n        // Before this was solved with event_base_loopexit, but that didn't work as expected in\n        // at least libevent 2.0.21 and always introduced a delay. In libevent\n        // master that appears to be solved, so in the future that solution\n        // could be used again (if desirable).\n        // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990)\n        if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) {\n            LogPrintf(\"HTTP event loop did not exit within allotted time, sending loopbreak\\n\");\n            event_base_loopbreak(eventBase);\n        }\n        threadHTTP.join();\n    }\n    if (eventHTTP) {\n        evhttp_free(eventHTTP);\n        eventHTTP = 0;\n    }\n    if (eventBase) {\n        event_base_free(eventBase);\n        eventBase = 0;\n    }\n    LogPrint(BCLog::HTTP, \"Stopped HTTP server\\n\");\n}\n\nstruct event_base* EventBase()\n{\n    return eventBase;\n}\n\nstatic void httpevent_callback_fn(evutil_socket_t, short, void* data)\n{\n    // Static handler: simply call inner handler\n    HTTPEvent *self = ((HTTPEvent*)data);\n    self->handler();\n    if (self->deleteWhenTriggered)\n        delete self;\n}\n\nHTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):\n    deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)\n{\n    ev = event_new(base, -1, 0, httpevent_callback_fn, this);\n    assert(ev);\n}\nHTTPEvent::~HTTPEvent()\n{\n    event_free(ev);\n}\nvoid HTTPEvent::trigger(struct timeval* tv)\n{\n    if (tv == NULL)\n        event_active(ev, 0, 0); // immediately trigger event in main thread\n    else\n        evtimer_add(ev, tv); // trigger after timeval passed\n}\nHTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),\n                                                       replySent(false)\n{\n}\nHTTPRequest::~HTTPRequest()\n{\n    if (!replySent) {\n        // Keep track of whether reply was sent to avoid request leaks\n        LogPrintf(\"%s: Unhandled request\\n\", __func__);\n        WriteReply(HTTP_INTERNAL, \"Unhandled request\");\n    }\n    // evhttpd cleans up the request, as long as a reply was sent.\n}\n\nstd::pair<bool, std::string> HTTPRequest::GetHeader(const std::string& hdr)\n{\n    const struct evkeyvalq* headers = evhttp_request_get_input_headers(req);\n    assert(headers);\n    const char* val = evhttp_find_header(headers, hdr.c_str());\n    if (val)\n        return std::pair(true, val);\n    else\n        return std::pair(false, \"\");\n}\n\nstd::string HTTPRequest::ReadBody()\n{\n    struct evbuffer* buf = evhttp_request_get_input_buffer(req);\n    if (!buf)\n        return \"\";\n    size_t size = evbuffer_get_length(buf);\n    /** Trivial implementation: if this is ever a performance bottleneck,\n     * internal copying can be avoided in multi-segment buffers by using\n     * evbuffer_peek and an awkward loop. Though in that case, it'd be even\n     * better to not copy into an intermediate string but use a stream\n     * abstraction to consume the evbuffer on the fly in the parsing algorithm.\n     */\n    const char* data = (const char*)evbuffer_pullup(buf, size);\n    if (!data) // returns NULL in case of empty buffer\n        return \"\";\n    std::string rv(data, size);\n    evbuffer_drain(buf, size);\n    return rv;\n}\n\nvoid HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)\n{\n    struct evkeyvalq* headers = evhttp_request_get_output_headers(req);\n    assert(headers);\n    evhttp_add_header(headers, hdr.c_str(), value.c_str());\n}\n\n/** Closure sent to main thread to request a reply to be sent to\n * a HTTP request.\n * Replies must be sent in the main loop in the main http thread,\n * this cannot be done from worker threads.\n */\nvoid HTTPRequest::WriteReply(int nStatus, const std::string& strReply)\n{\n    assert(!replySent && req);\n    // Send event to main http thread to send reply message\n    struct evbuffer* evb = evhttp_request_get_output_buffer(req);\n    assert(evb);\n    evbuffer_add(evb, strReply.data(), strReply.size());\n    HTTPEvent* ev = new HTTPEvent(eventBase, true,\n        std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));\n    ev->trigger(0);\n    replySent = true;\n    req = 0; // transferred back to main thread\n}\n\nCService HTTPRequest::GetPeer()\n{\n    evhttp_connection* con = evhttp_request_get_connection(req);\n    CService peer;\n    if (con) {\n        // evhttp retains ownership over returned address string\n        const char* address = \"\";\n        uint16_t port = 0;\n        evhttp_connection_get_peer(con, (char**)&address, &port);\n        peer = LookupNumeric(address, port);\n    }\n    return peer;\n}\n\nstd::string HTTPRequest::GetURI()\n{\n    return evhttp_request_get_uri(req);\n}\n\nHTTPRequest::RequestMethod HTTPRequest::GetRequestMethod()\n{\n    switch (evhttp_request_get_command(req)) {\n    case EVHTTP_REQ_GET:\n        return GET;\n        break;\n    case EVHTTP_REQ_POST:\n        return POST;\n        break;\n    case EVHTTP_REQ_HEAD:\n        return HEAD;\n        break;\n    case EVHTTP_REQ_PUT:\n        return PUT;\n        break;\n    case EVHTTP_REQ_OPTIONS: case EVHTTP_REQ_TRACE: case EVHTTP_REQ_CONNECT: case EVHTTP_REQ_PATCH: case EVHTTP_REQ_DELETE:\n    default:\n        return UNKNOWN;\n        break;\n    }\n}\n\nvoid RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)\n{\n    LogPrint(BCLog::HTTP, \"Registering HTTP handler for %s (exactmatch %d)\\n\", prefix, exactMatch);\n    pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));\n}\n\nvoid UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)\n{\n    std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();\n    std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();\n    for (; i != iend; ++i)\n        if (i->prefix == prefix && i->exactMatch == exactMatch)\n            break;\n    if (i != iend)\n    {\n        LogPrint(BCLog::HTTP, \"Unregistering HTTP handler for %s (exactmatch %d)\\n\", prefix, exactMatch);\n        pathHandlers.erase(i);\n    }\n}\n\n"
  },
  {
    "path": "src/httpserver.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_HTTPSERVER_H\n#define CORE_HTTPSERVER_H\n\n#include <string>\n#include <stdint.h>\n#include <functional>\n\nstatic const int DEFAULT_HTTP_THREADS=4;\nstatic const int DEFAULT_HTTP_WORKQUEUE=16;\nstatic const int DEFAULT_HTTP_SERVER_TIMEOUT=30;\n\nstruct evhttp_request;\nstruct event_base;\nclass CService;\nclass HTTPRequest;\n\n/** Initialize HTTP server.\n * Call this before RegisterHTTPHandler or EventBase().\n */\nbool InitHTTPServer();\n/** Start HTTP server.\n * This is separate from InitHTTPServer to give users race-condition-free time\n * to register their handlers between InitHTTPServer and StartHTTPServer.\n */\nbool StartHTTPServer();\n/** Interrupt HTTP server threads */\nvoid InterruptHTTPServer();\n/** Stop HTTP server */\nvoid StopHTTPServer();\n\n/** Change logging level for libevent. Removes BCLog::LIBEVENT from logCategories if\n * libevent doesn't support debug logging.*/\nbool UpdateHTTPServerLogging(bool enable);\n\n/** Handler for requests to a certain HTTP path */\ntypedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;\n/** Register handler for prefix.\n * If multiple handlers match a prefix, the first-registered one will\n * be invoked.\n */\nvoid RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler);\n/** Unregister handler for prefix */\nvoid UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);\n\n/** Return evhttp event base. This can be used by submodules to\n * queue timers or custom events.\n */\nstruct event_base* EventBase();\n\n/** In-flight HTTP request.\n * Thin C++ wrapper around evhttp_request.\n */\nclass HTTPRequest\n{\nprivate:\n    struct evhttp_request* req;\n    bool replySent;\n\npublic:\n    HTTPRequest(struct evhttp_request* req);\n    ~HTTPRequest();\n\n    enum RequestMethod {\n        UNKNOWN,\n        GET,\n        POST,\n        HEAD,\n        PUT\n    };\n\n    /** Get requested URI.\n     */\n    std::string GetURI();\n\n    /** Get CService (address:ip) for the origin of the http request.\n     */\n    CService GetPeer();\n\n    /** Get request method.\n     */\n    RequestMethod GetRequestMethod();\n\n    /**\n     * Get the request header specified by hdr, or an empty string.\n     * Return an pair (isPresent,string).\n     */\n    std::pair<bool, std::string> GetHeader(const std::string& hdr);\n\n    /**\n     * Read request body.\n     *\n     * @note As this consumes the underlying buffer, call this only once.\n     * Repeated calls will return an empty string.\n     */\n    std::string ReadBody();\n\n    /**\n     * Write output header.\n     *\n     * @note call this before calling WriteErrorReply or Reply.\n     */\n    void WriteHeader(const std::string& hdr, const std::string& value);\n\n    /**\n     * Write HTTP reply.\n     * nStatus is the HTTP status code to send.\n     * strReply is the body of the reply. Keep it empty to send a standard message.\n     *\n     * @note Can be called only once. As this will give the request back to the\n     * main thread, do not call any other HTTPRequest methods after calling this.\n     */\n    void WriteReply(int nStatus, const std::string& strReply = \"\");\n};\n\n/** Event handler closure.\n */\nclass HTTPClosure\n{\npublic:\n    virtual void operator()() = 0;\n    virtual ~HTTPClosure() {}\n};\n\n/** Event class. This can be used either as an cross-thread trigger or as a timer.\n */\nclass HTTPEvent\n{\npublic:\n    /** Create a new event.\n     * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)\n     * handler is the handler to call when the event is triggered.\n     */\n    HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler);\n    ~HTTPEvent();\n\n    /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after\n     * the given time has elapsed.\n     */\n    void trigger(struct timeval* tv);\n\n    bool deleteWhenTriggered;\n    std::function<void(void)> handler;\nprivate:\n    struct event* ev;\n};\n\n#endif\n"
  },
  {
    "path": "src/indirectmap.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef INDIRECTMAP_H\n#define INDIRECTMAP_H\n\ntemplate <class T>\nstruct DereferencingComparator { bool operator()(const T a, const T b) const { return *a < *b; } };\n\n/* Map whose keys are pointers, but are compared by their dereferenced values.\n *\n * Differs from a plain std::map<const K*, T, DereferencingComparator<K*> > in\n * that methods that take a key for comparison take a K rather than taking a K*\n * (taking a K* would be confusing, since it's the value rather than the address\n * of the object for comparison that matters due to the dereferencing comparator).\n *\n * Objects pointed to by keys must not be modified in any way that changes the\n * result of DereferencingComparator.\n */\ntemplate <class K, class T>\nclass indirectmap {\nprivate:\n    typedef std::map<const K*, T, DereferencingComparator<const K*> > base;\n    base m;\npublic:\n    typedef typename base::iterator iterator;\n    typedef typename base::const_iterator const_iterator;\n    typedef typename base::size_type size_type;\n    typedef typename base::value_type value_type;\n\n    // passthrough (pointer interface)\n    std::pair<iterator, bool> insert(const value_type& value) { return m.insert(value); }\n\n    // pass address (value interface)\n    iterator find(const K& key)                     { return m.find(&key); }\n    const_iterator find(const K& key) const         { return m.find(&key); }\n    iterator lower_bound(const K& key)              { return m.lower_bound(&key); }\n    const_iterator lower_bound(const K& key) const  { return m.lower_bound(&key); }\n    size_type erase(const K& key)                   { return m.erase(&key); }\n    size_type count(const K& key) const             { return m.count(&key); }\n\n    // passthrough\n    bool empty() const              { return m.empty(); }\n    size_type size() const          { return m.size(); }\n    size_type max_size() const      { return m.max_size(); }\n    void clear()                    { m.clear(); }\n    iterator begin()                { return m.begin(); }\n    iterator end()                  { return m.end(); }\n    const_iterator begin() const    { return m.begin(); }\n    const_iterator end() const      { return m.end(); }\n    const_iterator cbegin() const   { return m.cbegin(); }\n    const_iterator cend() const     { return m.cend(); }\n};\n\n#endif\n"
  },
  {
    "path": "src/init.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"init.h\"\n#include <unity/appmanager.h>\n\n#include \"addrman.h\"\n#include \"appname.h\"\n#include \"amount.h\"\n#include \"blockstore.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"checkpoints.h\"\n#include \"compat/sanity.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"validation/validationinterface.h\"\n#include \"validation/versionbitsvalidation.h\"\n#include \"fs.h\"\n#include \"httpserver.h\"\n#include \"httprpc.h\"\n#include \"key.h\"\n#include \"generation/miner.h\"\n#include \"generation/witness.h\"\n#include \"netbase.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"node/context.h\"\n#include \"policy/feerate.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"rpc/server.h\"\n#include \"rpc/register.h\"\n#include \"rpc/blockchain.h\"\n#include \"script/standard.h\"\n#include \"script/sigcache.h\"\n#include \"scheduler.h\"\n#include \"timedata.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"torcontrol.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/threadnames.h\"\n#include \"witnessutil.h\"\n#include \"util/moneystr.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#include \"wallet/walletdb.h\"\n#endif\n#include \"warnings.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <memory>\n\n#ifndef WIN32\n#include <signal.h>\n#include <sys/resource.h>\n#endif\n\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/replace.hpp>\n#include <boost/algorithm/string/split.hpp>\n#include <boost/bind.hpp>\n#include <boost/interprocess/sync/file_lock.hpp>\n#include <boost/thread.hpp>\n#include <openssl/crypto.h>\n\n#if ENABLE_ZMQ\n#include \"zmq/zmqnotificationinterface.h\"\n#endif\n\n#include <compat/sys.h>\n#include <compat/assumptions.h>\n\nbool fFeeEstimatesInitialized = false;\n\n\nstd::unique_ptr<CConnman> g_connman;\nstd::unique_ptr<PeerLogicValidation> peerLogic;\n\n#if ENABLE_ZMQ\nstatic CZMQNotificationInterface* pzmqNotificationInterface = NULL;\n#endif\n\n#ifdef WIN32\n// Win32 LevelDB doesn't use filedescriptors, and the ones used for\n// accessing block files don't count towards the fd_set size limit\n// anyway.\n#define MIN_CORE_FILEDESCRIPTORS 0\n#else\n#define MIN_CORE_FILEDESCRIPTORS 150\n#endif\n\n/** Used to pass flags to the Bind() function */\nenum BindFlags {\n    BF_NONE         = 0,\n    BF_EXPLICIT     = (1U << 0),\n    BF_REPORT_ERROR = (1U << 1),\n    BF_WHITELIST    = (1U << 2),\n};\n\nstatic const char* FEE_ESTIMATES_FILENAME=\"fee_estimates.dat\";\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Shutdown\n//\n\n//\n// Thread management and startup/shutdown:\n//\n// The network-processing threads are all part of a thread group\n// created by AppInit() or the Qt main() function.\n//\n// A clean exit happens when qt or the SIGTERM signal handler call AppLifecycleManager::shutdown()\n// This signals to the shutdown thread that shutdown can commence.\n// The shutdown thread systematically shuts down the application:\n// 1 - Alerts the UI to perform basic pre shutdown preparation (hide UI, show an exit message etc.)\n// 2 - Interrupts the thread groups.\n// 3 - Notifies the UI to disconnect from signals.\n// 4 - Stops all the thread groups, syncs all files to disk etc.\n// 5 - Notifies the App/UI to close themselves (or in the case of the daemon to simply exit).\n\n\nstd::atomic<bool> fDumpMempoolLater(false);\nbool partiallyEraseDatadirOnShutdown=false;\nbool fullyEraseDatadirOnShutdown=false;\n\n/**\n * This is a minimally invasive approach to shutdown on LevelDB read errors from the\n * chainstate, while keeping user interface out of the common library, which is shared\n * between the daemon, UI application, and non-server tools.\n*/\nclass CCoinsViewErrorCatcher : public CCoinsViewBacked\n{\npublic:\n    CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}\n    bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const override\n    {\n        try\n        {\n            return CCoinsViewBacked::GetCoin(outpoint, coin, pOutpointRet);\n        }\n        catch(const std::runtime_error& e)\n        {\n            uiInterface.ThreadSafeMessageBox(_(\"Error reading from database, shutting down.\"), \"\", CClientUIInterface::MSG_ERROR);\n            LogPrintf(\"Error reading from database: %s\\n\", e.what());\n            // Starting the shutdown sequence and returning false to the caller would be\n            // interpreted as 'entry not found' (as opposed to unable to read data), and\n            // could lead to invalid interpretation. Just exit immediately, as we can't\n            // continue anyway, and all writes should be atomic.\n            abort();\n        }\n    }\n    // Writes do not need similar protection, as failure to write is handled by the caller.\n};\n\nstatic CCoinsViewErrorCatcher *pcoinscatcher = NULL;\nstatic std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;\n\nstatic CCoinsViewErrorCatcher *ppow2witcatcher = NULL;\n\nextern void ServerInterrupt();\nvoid CoreInterrupt(boost::thread_group& threadGroup)\n{\n    LogPrintf(\"Core interrupt: commence core interrupt\\n\");\n    PoWGenerateBlocks(false, 0, 0, 0, Params());\n    if (g_connman)\n        g_connman->Interrupt();\n    ServerInterrupt();\n    threadGroup.interrupt_all();\n    LogPrintf(\"Core interrupt: done.\\n\");\n}\n\nextern void ServerShutdown(node::NodeContext& nodeContext);\nvoid CoreShutdown(boost::thread_group& threadGroup, node::NodeContext& nodeContext)\n{\n    LogPrintf(\"Core shutdown: commence core shutdown\\n\");\n    static RecursiveMutex cs_Shutdown;\n\n    TRY_LOCK(cs_Shutdown, lockShutdown);\n    if (!lockShutdown)\n        return;\n\n    /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,\n    /// for example if the data directory was found to be locked.\n    /// Be sure that anything that writes files or flushes caches only does this if the respective\n    /// module was initialized.\n    mempool.AddTransactionsUpdated(1);\n\n    LogPrintf(\"Core shutdown: stop network threads.\\n\");\n    if (g_connman)\n        g_connman->Stop();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n\n\n    LogPrintf(\"Core shutdown: stop remaining worker threads.\\n\");\n    ServerShutdown(nodeContext);\n    threadGroup.join_all();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n\n    LogPrintf(\"Core shutdown: delete network threads.\\n\");\n    MapPort(false);\n    UnregisterValidationInterface(peerLogic.get());\n    peerLogic.reset();\n    g_connman.reset();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n\n    UnregisterNodeSignals(GetNodeSignals());\n    if (fDumpMempoolLater && GetArg(\"-persistmempool\", DEFAULT_PERSIST_MEMPOOL)) {\n        DumpMempool();\n    }\n\n    if (fFeeEstimatesInitialized)\n    {\n        ::feeEstimator.FlushUnconfirmed(::mempool);\n        fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;\n        CAutoFile est_fileout(fsbridge::fopen(est_path, \"wb\"), SER_DISK, CLIENT_VERSION);\n        if (!est_fileout.IsNull())\n            ::feeEstimator.Write(est_fileout);\n        else\n            LogPrintf(\"%s: Failed to write fee estimates to %s\\n\", __func__, est_path.string());\n        fFeeEstimatesInitialized = false;\n    }\n\n\n    LogPrintf(\"Core shutdown: close coin databases.\\n\");\n    {\n        LOCK(cs_main);\n\n        if (!isFullSyncMode() && IsPartialSyncActive())\n            PersistAndPruneForPartialSync();\n        else\n            FlushStateToDisk();\n\n        blockStore.CloseBlockFiles();\n        delete pcoinsTip;\n        pcoinsTip = NULL;\n        delete pcoinscatcher;\n        pcoinscatcher = NULL;\n        delete pcoinsdbview;\n        pcoinsdbview = NULL;\n\n        //Already flushed to disk by FlushStateToDisk, setting to nullptr should trigger deletion.\n        ppow2witTip = nullptr;\n        delete ppow2witcatcher;\n        ppow2witcatcher = NULL;\n        delete ppow2witdbview;\n        ppow2witdbview = NULL;\n\n        delete pblocktree;\n        pblocktree = NULL;\n    }\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n\n\n    #ifdef ENABLE_WALLET\n    LogPrintf(\"Core shutdown: final flush wallets.\\n\");\n    for (CWalletRef pwallet : vpwallets) {\n        pwallet->Flush(true);\n    }\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    #endif\n\n    #if ENABLE_ZMQ\n    LogPrintf(\"Core shutdown: close zmq interfaces.\\n\");\n    if (pzmqNotificationInterface)\n    {\n        UnregisterValidationInterface(pzmqNotificationInterface);\n        delete pzmqNotificationInterface;\n        pzmqNotificationInterface = NULL;\n    }\n    #endif\n\n    UnregisterAllValidationInterfaces();\n    GetMainSignals().UnregisterBackgroundSignalScheduler();\n\n    LogPrintf(\"Core shutdown: unregister validation interfaces.\\n\");\n    #ifndef WIN32\n    try\n    {\n        fs::remove(GetPidFile());\n    }\n    catch (const fs::filesystem_error& e)\n    {\n        LogPrintf(\"%s: Unable to remove pidfile: %s\\n\", __func__, e.what());\n    }\n    #endif\n    UnregisterAllValidationInterfaces();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n\n    #ifdef ENABLE_WALLET\n    LogPrintf(\"Core shutdown: delete wallets.\\n\");\n    for (CWalletRef pwallet : vpwallets)\n    {\n        delete pwallet;\n    }\n    vpwallets.clear();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    #endif\n    FreeParams();\n    globalVerifyHandle.reset();\n    ECC_Stop();\n    LogPrintf(\"Core shutdown: done.\\n\");\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    \n    if (fullyEraseDatadirOnShutdown||partiallyEraseDatadirOnShutdown)\n    {\n        try { fs::remove_all(GetDataDir() / \"autocheckpoints\"); } catch(...){LogPrintf(\"Failed to delete autocheckpoints\\n\");}\n        try { fs::remove(GetDataDir() / \"banlist.dat\"); } catch(...){LogPrintf(\"Failed to delete banlist.dat\\n\");}\n        try { fs::remove(GetDataDir() / \"peers.dat\"); } catch(...){LogPrintf(\"Failed to delete peers.dat\\n\");}\n    }\n    if (fullyEraseDatadirOnShutdown)\n    {\n        try { fs::remove(GetDataDir() / \"mempool.dat\"); } catch(...){LogPrintf(\"Failed to delete mempool.dat\\n\");}\n        try { fs::remove(GetDataDir() / FEE_ESTIMATES_FILENAME); } catch(...){LogPrintf(\"Failed to delete fee estimates\\n\");}\n        try { fs::remove_all(GetDataDir() / \"blocks\"); } catch(...){LogPrintf(\"Failed to delete blocks folder\\n\");}\n        try { fs::remove_all(GetDataDir() / \"chainstate\"); } catch(...){LogPrintf(\"Failed to delete chainstate\\n\");}\n        try { fs::remove_all(GetDataDir() / \"witstate\"); } catch(...){LogPrintf(\"Failed to delete witstate\\n\");}\n        try { fs::remove_all(GetDataDir() / \"database\"); } catch(...){LogPrintf(\"Failed to delete database folder\\n\");}\n        //fixme: Windows\n        // This fails to delete on windows due to db.log still being open at program exit\n        // However with the rest of the data gone db.log is discarded anyway so this is 'okay'\n        // We should try get it working 100% anyway though in future when time allows\n        try { fs::remove(GetDataDir() / \"db.log\"); } catch(...){LogPrintf(\"Failed to delete db.log\\n\");}\n    }\n}\n\n//Signal handlers should be written in a way that does not result in any unwanted side-effects\n//e.g. errno alteration, signal mask alteration, signal disposition change, and other global process attribute changes.\n//Use of non-reentrant functions, e.g., malloc or printf, inside signal handlers is also unsafe.\n//In particular, the POSIX specification and the Linux man page signal(7) requires that all system functions directly or indirectly called from a signal function are async-signal safe and gives\n//list of such async-signal safe system functions (practically the system calls), otherwise it is an undefined behavior. It is suggested to simply set some volatile sig_atomic_t variable in a signal handler, and to test it elsewhere.\nstatic void HandleSIGTERM(int)\n{\n    // We call a sigterm safe 'shutdown' function that does nothing but write to a socket.\n    // The shutdown thread then safely handles the rest from within the already existing shutdown thread.\n    if (AppLifecycleManager::gApp)\n        AppLifecycleManager::gApp->shutdown(true);\n}\n\nstatic void HandleSIGHUP(int)\n{\n    fReopenDebugLog = true;\n}\n\n#ifndef WIN32\nstatic void registerSignalHandler(int signal, void(*handler)(int))\n{\n    struct sigaction sa;\n    sa.sa_handler = handler;\n    sigemptyset(&sa.sa_mask);\n    sa.sa_flags = 0;\n    sigaction(signal, &sa, NULL);\n}\n#endif\n\nbool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {\n    if (!(flags & BF_EXPLICIT) && IsLimited(addr))\n        return false;\n    std::string strError;\n    if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {\n        if (flags & BF_REPORT_ERROR)\n            return InitError(strError);\n        return false;\n    }\n    return true;\n}\n\n//If we want to translate help messages in future we can replace helptr with _ and everything will just work.\n#define helptr(x) std::string(x)\n//If we want to translate error messages in future we can replace helptr with _ and everything will just work.\n#define errortr(x) std::string(x)\n//If we want to translate warning messages in future we can replace helptr with _ and everything will just work.\n#define warningtr(x) std::string(x)\n\nextern std::string HelpMessage(HelpMessageMode mode);\n\nstd::string LicenseInfo()\n{\n    const std::string URL_WEBSITE = \"<https://Munt.org>\";\n\n    //fixme: (FUT) Mention additional libraries, boost etc.\n    //fixme: (FUT) Translate\n    //fixme: (FUT) Add code to ensure translations never strip copyrights\n    return helptr(\"Copyright (C) 2014-2022 The Centure developers\")+ \"\\n\"\n           + helptr(\"Licensed under the GNU Lesser General Public License v3\")+ \"\\n\"\n           + \"\\n\"\n           + helptr(\"This is experimental software.\")+ \"\\n\"\n           + strprintf(helptr(\"Please contribute if you find %s useful. Visit %s for further information about the software.\"), PACKAGE_NAME, URL_WEBSITE)\n           + \"\\n\"\n           + \"\\n\"\n           + strprintf(helptr(\"This product is originally based on a fork of the Bitcoin project. Copyright (C) 2014-2018 The Bitcoin Core Developers.\")) + \"\\n\"\n           + strprintf(helptr(\"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.\"), \"<https://www.openssl.org>\")+ \"\\n\"\n           + strprintf(helptr(\"This product uses a licensed copy of Font Awesome Pro\"))+ \"\\n\"\n           + strprintf(helptr(\"This product includes and uses the Lato font which is licensed under the SIL Open Font License\"))+ \"\\n\"\n           + strprintf(helptr(\"This product makes use of the Qt toolkit which is dynamically linked and licensed under the LGPL\"))+ \"\\n\";\n}\n\nstatic void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)\n{\n    if (initialSync || !pBlockIndex)\n        return;\n\n    std::string strCmd = GetArg(\"-blocknotify\", \"\");\n\n    boost::replace_all(strCmd, \"%s\", pBlockIndex->GetBlockHashPoW2().GetHex());\n    std::thread(runCommand, strCmd).detach();\n}\n\nstatic bool fHaveGenesis = false;\nstatic Mutex cs_GenesisWait;\nstatic std::condition_variable condvar_GenesisWait;\n\nstatic void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)\n{\n    if (pBlockIndex != NULL) {\n        {\n            std::unique_lock<Mutex> lock_GenesisWait(cs_GenesisWait);\n            fHaveGenesis = true;\n        }\n        condvar_GenesisWait.notify_all();\n    }\n}\n\nstruct CImportingNow\n{\n    CImportingNow() {\n        assert(!fImporting);\n        fImporting = true;\n    }\n\n    ~CImportingNow() {\n        assert(fImporting);\n        fImporting = false;\n    }\n};\n\n\n// If we're using -prune with -reindex, then delete block files that will be ignored by the\n// reindex.  Since reindexing works by starting at block file 0 and looping until a blockfile\n// is missing, do the same here to delete any later block files after a gap.  Also delete all\n// rev files since they'll be rewritten by the reindex anyway.  This ensures that vinfoBlockFile\n// is in sync with what's actually on disk by the time we start downloading, so that pruning\n// works correctly.\nstatic void CleanupBlockRevFiles()\n{\n    std::map<std::string, fs::path> mapBlockFiles;\n\n    // Glob all blk?????.dat and rev?????.dat files from the blocks directory.\n    // Remove the rev files immediately and insert the blk file paths into an\n    // ordered map keyed by block file index.\n    LogPrintf(\"Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\\n\");\n    fs::path blocksdir = GetDataDir() / \"blocks\";\n    for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {\n        if (is_regular_file(*it) &&\n            it->path().filename().string().length() == 12 &&\n            it->path().filename().string().substr(8,4) == \".dat\")\n        {\n            if (it->path().filename().string().substr(0,3) == \"blk\")\n                mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();\n            else if (it->path().filename().string().substr(0,3) == \"rev\")\n                remove(it->path());\n        }\n    }\n\n    // Remove all block files that aren't part of a contiguous set starting at\n    // zero by walking the ordered map (keys are block file indices) by\n    // keeping a separate counter.  Once we hit a gap (or if 0 doesn't exist)\n    // start removing block files.\n    int nContigCounter = 0;\n    for(const PAIRTYPE(std::string, fs::path)& item : mapBlockFiles) {\n        if (atoi(item.first) == nContigCounter) {\n            nContigCounter++;\n            continue;\n        }\n        remove(item.second);\n    }\n}\n\nstatic void ThreadImport(std::vector<fs::path> vImportFiles)\n{\n    const CChainParams& chainparams = Params();\n    util::ThreadRename(GLOBAL_APPNAME\"-loadblk\");\n\n    {\n    CImportingNow imp;\n\n    // -reindex\n    if (fReindex) {\n        int nFile = 0;\n        while (true) {\n            FILE* file;\n            CDiskBlockPos pos(nFile, 0);\n            {\n                LOCK(cs_main);\n                if (!blockStore.BlockFileExists(pos))\n                    break; // No block files left to reindex\n                FILE *tmpfile = blockStore.GetBlockFile(pos, true);\n                if (!tmpfile)\n                    break; // This error is logged in OpenBlockFile\n                // dupping here because otherwise the cs_main might be locked for a long time\n                file = fdopen(dup(fileno(tmpfile)), \"rb+\");\n            }\n            LogPrintf(\"Reindexing block file blk%05u.dat...\\n\", (unsigned int)nFile);\n            LoadExternalBlockFile(chainparams, file, &pos);\n            fclose(file);\n            nFile++;\n        }\n        pblocktree->WriteReindexing(false);\n        fReindex = false;\n        LogPrintf(\"Reindexing finished\\n\");\n        // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):\n        InitBlockIndex(chainparams);\n    }\n\n    // hardcoded $DATADIR/bootstrap.dat\n    fs::path pathBootstrap = GetDataDir() / \"bootstrap.dat\";\n    if (fs::exists(pathBootstrap)) {\n        FILE *file = fsbridge::fopen(pathBootstrap, \"rb\");\n        if (file) {\n            fs::path pathBootstrapOld = GetDataDir() / \"bootstrap.dat.old\";\n            LogPrintf(\"Importing bootstrap.dat...\\n\");\n            LoadExternalBlockFile(chainparams, file);\n            fclose(file);\n            RenameOver(pathBootstrap, pathBootstrapOld);\n        } else {\n            LogPrintf(\"Warning: Could not open bootstrap file %s\\n\", pathBootstrap.string());\n        }\n    }\n\n    // -loadblock=\n    for(const fs::path& path : vImportFiles) {\n        FILE *file = fsbridge::fopen(path, \"rb\");\n        if (file) {\n            LogPrintf(\"Importing blocks file %s...\\n\", path.string());\n            LoadExternalBlockFile(chainparams, file);\n            fclose(file);\n        } else {\n            LogPrintf(\"Warning: Could not open blocks file %s\\n\", path.string());\n        }\n    }\n\n    // scan for better chains in the block chain database, that are not yet connected in the active best chain\n    CValidationState state;\n    if (!ActivateBestChain(state, chainparams)) {\n        LogPrintf(\"Failed to connect best block\\n\");\n        LogPrintf(\"shutdown: terminating app due to block connect failiure\");\n        AppLifecycleManager::gApp->shutdown();\n    }\n\n    if (GetBoolArg(\"-stopafterblockimport\", DEFAULT_STOPAFTERBLOCKIMPORT)) {\n        LogPrintf(\"Stopping after block import\\n\");\n        AppLifecycleManager::gApp->shutdown();\n    }\n    } // End scope of CImportingNow\n    if (GetArg(\"-persistmempool\", DEFAULT_PERSIST_MEMPOOL)) {\n        LoadMempool();\n        fDumpMempoolLater = !ShutdownRequested();\n    }\n}\n\n/** Sanity checks\n *  Ensure that Munt is running in a usable environment with all\n *  necessary library support.\n */\nstatic bool InitSanityCheck(void)\n{\n    if(!ECC_InitSanityCheck()) {\n        InitError(\"Elliptic curve cryptography sanity check failure. Aborting.\");\n        return false;\n    }\n\n    if (!glibc_sanity_test() || !glibcxx_sanity_test())\n        return false;\n\n    if (!Random_SanityCheck()) {\n        InitError(\"OS cryptographic RNG sanity check failure. Aborting.\");\n        return false;\n    }\n\n    return true;\n}\n\n// Parameter interaction based on rules\nvoid InitParameterInteraction()\n{\n    // when specifying an explicit binding address, you want to listen on it\n    // even when -connect or -proxy is specified\n    if (IsArgSet(\"-bind\")) {\n        if (SoftSetBoolArg(\"-listen\", true))\n            LogPrintf(\"%s: parameter interaction: -bind set -> setting -listen=1\\n\", __func__);\n    }\n    if (IsArgSet(\"-whitebind\")) {\n        if (SoftSetBoolArg(\"-listen\", true))\n            LogPrintf(\"%s: parameter interaction: -whitebind set -> setting -listen=1\\n\", __func__);\n    }\n\n    if (gArgs.IsArgSet(\"-connect\")) {\n        // when only connecting to trusted nodes, do not seed via DNS, or listen by default\n        if (SoftSetBoolArg(\"-dnsseed\", false))\n            LogPrintf(\"%s: parameter interaction: -connect set -> setting -dnsseed=0\\n\", __func__);\n        if (SoftSetBoolArg(\"-listen\", false))\n            LogPrintf(\"%s: parameter interaction: -connect set -> setting -listen=0\\n\", __func__);\n    }\n\n    if (IsArgSet(\"-proxy\")) {\n        // to protect privacy, do not listen by default if a default proxy server is specified\n        if (SoftSetBoolArg(\"-listen\", false))\n            LogPrintf(\"%s: parameter interaction: -proxy set -> setting -listen=0\\n\", __func__);\n        // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1\n        // to listen locally, so don't rely on this happening through -listen below.\n        if (SoftSetBoolArg(\"-upnp\", false))\n            LogPrintf(\"%s: parameter interaction: -proxy set -> setting -upnp=0\\n\", __func__);\n        // to protect privacy, do not discover addresses by default\n        if (SoftSetBoolArg(\"-discover\", false))\n            LogPrintf(\"%s: parameter interaction: -proxy set -> setting -discover=0\\n\", __func__);\n    }\n\n    if (!GetBoolArg(\"-listen\", DEFAULT_LISTEN)) {\n        // do not map ports or try to retrieve public IP when not listening (pointless)\n        if (SoftSetBoolArg(\"-upnp\", false))\n            LogPrintf(\"%s: parameter interaction: -listen=0 -> setting -upnp=0\\n\", __func__);\n        if (SoftSetBoolArg(\"-discover\", false))\n            LogPrintf(\"%s: parameter interaction: -listen=0 -> setting -discover=0\\n\", __func__);\n        if (SoftSetBoolArg(\"-listenonion\", false))\n            LogPrintf(\"%s: parameter interaction: -listen=0 -> setting -listenonion=0\\n\", __func__);\n    }\n\n    if (IsArgSet(\"-externalip\")) {\n        // if an explicit public IP is specified, do not try to find others\n        if (SoftSetBoolArg(\"-discover\", false))\n            LogPrintf(\"%s: parameter interaction: -externalip set -> setting -discover=0\\n\", __func__);\n    }\n\n    // disable whitelistrelay in blocksonly mode\n    if (GetBoolArg(\"-blocksonly\", DEFAULT_BLOCKSONLY)) {\n        if (SoftSetBoolArg(\"-whitelistrelay\", false))\n            LogPrintf(\"%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\\n\", __func__);\n    }\n\n    // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.\n    if (GetBoolArg(\"-whitelistforcerelay\", DEFAULT_WHITELISTFORCERELAY)) {\n        if (SoftSetBoolArg(\"-whitelistrelay\", true))\n            LogPrintf(\"%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\\n\", __func__);\n    }\n\n    //For raspberry pis etc. we default to keeping logging at a minimum\n    #if defined(__arm__) || defined(__aarch64__)\n    SoftSetBoolArg(\"-minimallogging\", true);\n    #endif\n    gbMinimalLogging = GetBoolArg(\"-minimallogging\", false);\n}\n\nstatic std::string ResolveErrMsg(const char * const optname, const std::string& strBind)\n{\n    return strprintf(errortr(\"Cannot resolve -%s address: '%s'\"), optname, strBind);\n}\n\nvoid InitLogging()\n{\n    fPrintToConsole = GetBoolArg(\"-printtoconsole\", false);\n    fLogTimestamps = GetBoolArg(\"-logtimestamps\", DEFAULT_LOGTIMESTAMPS);\n    fLogTimeMicros = GetBoolArg(\"-logtimemicros\", DEFAULT_LOGTIMEMICROS);\n    fLogIPs = GetBoolArg(\"-logips\", DEFAULT_LOGIPS);\n\n    LogPrintf(\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\");\n    LogPrintf(\"%s version %s\\n\", GLOBAL_APPNAME, FormatFullVersion());\n}\n\nnamespace { // Variables internal to initialization process only\n\nServiceFlags nRelevantServices = NODE_NETWORK;\nint nMaxConnections;\nint nUserMaxConnections;\nint nFD;\nServiceFlags nLocalServices = NODE_NETWORK;\n\n}\n\n[[noreturn]] static void new_handler_terminate()\n{\n    // Rather than throwing std::bad-alloc if allocation fails, terminate\n    // immediately to (try to) avoid chain corruption.\n    // Since LogPrintf may itself allocate memory, set the handler directly\n    // to terminate first.\n    std::set_new_handler(std::terminate);\n    LogPrintf(\"Error: Out of memory. Terminating.\\n\");\n\n    // The log was successful, terminate now.\n    std::terminate();\n};\n\nextern void InitRegisterRPC();\nbool AppInitBasicSetup()\n{\n    // ********************************************************* Step 1: setup\n#ifdef _MSC_VER\n    // Turn off Microsoft heap dump noise\n    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);\n    _CrtSetReportFile(_CRT_WARN, CreateFileA(\"NUL\", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));\n#endif\n#if _MSC_VER >= 1400\n    // Disable confusing \"helpful\" text message on abort, Ctrl-C\n    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n#endif\n#ifdef WIN32\n    // Enable Data Execution Prevention (DEP)\n    // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008\n    // A failure is non-critical and needs no further attention!\n#ifndef PROCESS_DEP_ENABLE\n    // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),\n    // which is not correct. Can be removed, when GCCs winbase.h is fixed!\n#define PROCESS_DEP_ENABLE 0x00000001\n#endif\n    typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);\n    PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA(\"Kernel32.dll\"), \"SetProcessDEPPolicy\");\n    if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);\n#endif\n\n    if (!SetupNetworking())\n        return InitError(\"Initializing networking failed\");\n\n#ifndef WIN32\n    if (!GetBoolArg(\"-sysperms\", false)) {\n        umask(077);\n    }\n\n    // Clean shutdown on SIGTERM\n    registerSignalHandler(SIGTERM, HandleSIGTERM);\n    registerSignalHandler(SIGINT, HandleSIGTERM);\n\n    // Reopen debug.log on SIGHUP\n    registerSignalHandler(SIGHUP, HandleSIGHUP);\n\n    // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly\n    signal(SIGPIPE, SIG_IGN);\n#endif\n\n    std::set_new_handler(new_handler_terminate);\n\n    return true;\n}\n\nbool AppInitParameterInteraction()\n{\n    const CChainParams& chainparams = Params();\n    // ********************************************************* Step 2: parameter interactions\n    // also see: InitParameterInteraction()\n    \n    #ifdef BETA_BUILD\n    if (!chainparams.IsTestNet())\n    {\n        return InitError(errortr(\"Running beta builds on mainnet is dangerous, please don't do this.\"));\n    }\n    #endif\n    \n    // Limit default memory usage on low memory systems, to try and prevent OOM on low spec pi devices and similar.\n    #ifndef PLATFORM_MOBILE\n    if (systemPhysicalMemoryInBytes() <= 1*1024*1024*1024ULL)\n    {\n        if (SoftSetArg(\"-maxconnections\", i64tostr(40)))\n        {\n            InitWarning(strprintf(warningtr(\"Reducing -maxconnections to 40, because of system limitations, this can be overridden by explicitely setting -maxconnections to a larger amount.\")));\n        }\n        if (SoftSetArg(\"-maxmempool\", i64tostr(DEFAULT_MAX_MEMPOOL_SIZE_LOWMEM)))\n        {\n            InitWarning(strprintf(warningtr(\"Reducing -maxmempool to 100, because of system limitations, this can be overridden by explicitely setting -maxmempool to a larger amount.\")));\n        }\n        if (SoftSetArg(\"-dbcache\", i64tostr(100)))\n        {\n            InitWarning(strprintf(warningtr(\"Reducing -dbcache to 200, because of system limitations, this can be overridden by explicitely setting -dbcache to a larger amount.\")));\n        }\n        if (SoftSetArg(\"-rpcthreads\", i64tostr(1)))\n        {\n            InitWarning(strprintf(warningtr(\"Reducing -rpcthreads to 1, because of system limitations, this can be overridden by explicitely setting -rpcthreads to a larger amount.\")));\n        }\n        if (SoftSetBoolArg(\"-reverseheaders\", false))\n        {\n            InitWarning(strprintf(warningtr(\"Disabling reverse header sync, because of system limitations, this can be overridden by explicitely setting -reverseheaders to true.\")));\n        }\n        //if (SoftSetArg(\"-maxreceivebuffer\", DEFAULT_MAXRECEIVEBUFFER_LOWMEM))\n        //{\n            //InitWarning(strprintf(warningtr(\"Lowering receive buffer size from [%d] to [%d], because of system limitations, this can be overridden by explicitely setting -reverseheaders to true.\"), DEFAULT_MAXRECEIVEBUFFER, DEFAULT_MAXRECEIVEBUFFER_LOWMEM));\n        //}   \n    }\n    #endif\n\n    // if using block pruning, then disallow txindex\n    if (GetArg(\"-prune\", 0)) {\n        if (GetBoolArg(\"-txindex\", DEFAULT_TXINDEX))\n            return InitError(errortr(\"Prune mode is incompatible with -txindex.\"));\n    }\n\n    // Make sure enough file descriptors are available\n    int nBind = std::max(\n                (gArgs.IsArgSet(\"-bind\") ? gArgs.GetArgs(\"-bind\").size() : 0) +\n                (gArgs.IsArgSet(\"-whitebind\") ? gArgs.GetArgs(\"-whitebind\").size() : 0), size_t(1));\n    nUserMaxConnections = GetArg(\"-maxconnections\", DEFAULT_MAX_PEER_CONNECTIONS);\n    nMaxConnections = std::max(nUserMaxConnections, 0);\n        \n    // Trim requested connection counts, to fit into system limitations\n    int nSystemMaxConnections = FD_SETSIZE;\n#ifndef WIN32\n    rlimit rlim;\n    int err = getrlimit(RLIMIT_NOFILE, &rlim);\n    if (err) {\n        LogPrintf(\"Could not determine max system file descriptors, assuming %d\", nSystemMaxConnections);\n    }\n    else {\n        nSystemMaxConnections = rlim.rlim_cur;\n    }\n#endif\n\n    nMaxConnections = std::max(std::min(nMaxConnections, (int)(nSystemMaxConnections - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0);\n    nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);\n    if (nFD < MIN_CORE_FILEDESCRIPTORS)\n        return InitError(errortr(\"Not enough file descriptors available.\"));\n    nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);\n\n    if (nMaxConnections < nUserMaxConnections)\n        InitWarning(strprintf(warningtr(\"Reducing -maxconnections from %d to %d, because of system limitations.\"), nUserMaxConnections, nMaxConnections));\n\n    // ********************************************************* Step 3: parameter-to-internal-flags\n    if (gArgs.IsArgSet(\"-debug\")) {\n        // Special-case: if -debug=0/-nodebug is set, turn off debugging messages\n        const std::vector<std::string> categories = gArgs.GetArgs(\"-debug\");\n\n        if (find(categories.begin(), categories.end(), std::string(\"0\")) == categories.end()) {\n            for (const auto& cat : categories) {\n                uint32_t flag = 0;\n                if (!GetLogCategory(&flag, &cat)) {\n                    InitWarning(strprintf(warningtr(\"Unsupported logging category %s=%s.\"), \"-debug\", cat));\n                    continue;\n                }\n                logCategories |= flag;\n            }\n        }\n    }\n\n    // Now remove the logging categories which were explicitly excluded\n    if (gArgs.IsArgSet(\"-debugexclude\")) {\n        for (const std::string& cat : gArgs.GetArgs(\"-debugexclude\")) {\n            uint32_t flag = 0;\n            if (!GetLogCategory(&flag, &cat)) {\n                InitWarning(strprintf(warningtr(\"Unsupported logging category %s=%s.\"), \"-debugexclude\", cat));\n                continue;\n            }\n            logCategories &= ~flag;\n        }\n    }\n\n    // Check for -debugnet\n    if (GetBoolArg(\"-debugnet\", false))\n        InitWarning(warningtr(\"Unsupported argument -debugnet ignored, use -debug=net.\"));\n    // Check for -socks - as this is a privacy risk to continue, exit here\n    if (IsArgSet(\"-socks\"))\n        return InitError(errortr(\"Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.\"));\n    // Check for -tor - as this is a privacy risk to continue, exit here\n    if (GetBoolArg(\"-tor\", false))\n        return InitError(errortr(\"Unsupported argument -tor found, use -onion.\"));\n\n    if (GetBoolArg(\"-benchmark\", false))\n        InitWarning(warningtr(\"Unsupported argument -benchmark ignored, use -debug=bench.\"));\n\n    if (GetBoolArg(\"-whitelistalwaysrelay\", false))\n        InitWarning(warningtr(\"Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.\"));\n\n    if (IsArgSet(\"-blockminsize\"))\n        InitWarning(\"Unsupported argument -blockminsize ignored.\");\n\n    // Checkmempool and checkblockindex default to true in regtest mode\n    int ratio = std::min<int>(std::max<int>(GetArg(\"-checkmempool\", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);\n    if (ratio != 0) {\n        mempool.setSanityCheck(1.0 / ratio);\n    }\n    fCheckBlockIndex = GetBoolArg(\"-checkblockindex\", chainparams.DefaultConsistencyChecks());\n    fCheckpointsEnabled = GetBoolArg(\"-checkpoints\", DEFAULT_CHECKPOINTS_ENABLED);\n    SetFullSyncMode(GetBoolArg(\"-fullsync\", DEFAULT_FULL_SYNC_MODE));\n\n    hashAssumeValid = uint256S(GetArg(\"-assumevalid\", chainparams.GetConsensus().defaultAssumeValid.GetHex()));\n    if (!hashAssumeValid.IsNull())\n        LogPrintf(\"Assuming ancestors of block %s have valid signatures.\\n\", hashAssumeValid.GetHex());\n    else\n        LogPrintf(\"Validating signatures for all blocks.\\n\");\n\n    // mempool limits\n    int64_t nMempoolSizeMax = GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;\n    int64_t nMempoolSizeMin = GetArg(\"-limitdescendantsize\", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;\n    if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)\n        return InitError(strprintf(errortr(\"-maxmempool must be at least %d MB\"), std::ceil(nMempoolSizeMin / 1000000.0)));\n    // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool\n    // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.\n    if (IsArgSet(\"-incrementalrelayfee\"))\n    {\n        CAmount n = 0;\n        if (!ParseMoney(GetArg(\"-incrementalrelayfee\", \"\"), n))\n            return InitError(AmountErrMsg(\"incrementalrelayfee\", GetArg(\"-incrementalrelayfee\", \"\")));\n        incrementalRelayFee = CFeeRate(n);\n    }\n\n    // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency\n    nScriptCheckThreads = GetArg(\"-par\", DEFAULT_SCRIPTCHECK_THREADS);\n    if (nScriptCheckThreads <= 0)\n        nScriptCheckThreads += GetNumCores();\n    if (nScriptCheckThreads <= 1)\n        nScriptCheckThreads = 0;\n    else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)\n        nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;\n\n    // block pruning; get the amount of disk space (in MiB) to allot for block & undo files\n    int64_t nPruneArg = GetArg(\"-prune\", 0);\n    if (nPruneArg < 0) {\n        return InitError(errortr(\"Prune cannot be configured with a negative value.\"));\n    }\n    nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;\n    if (nPruneArg == 1 || (!isFullSyncMode() && GetBoolArg(\"-spv\", DEFAULT_SPV)))\n    {  // manual pruning: -prune=1\n        LogPrintf(\"Block pruning enabled.  Use RPC call pruneblockchain(height) to manually prune block and undo files.\\n\");\n        nPruneTarget = std::numeric_limits<uint64_t>::max();\n        fPruneMode = true;\n    } else if (nPruneTarget) {\n        if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {\n            return InitError(strprintf(errortr(\"Prune configured below the minimum of %d MiB.  Please use a higher number.\"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));\n        }\n        LogPrintf(\"Prune configured to target %uMiB on disk for block and undo files.\\n\", nPruneTarget / 1024 / 1024);\n        fPruneMode = true;\n    }\n\n    InitRegisterRPC();\n\n    nConnectTimeout = GetArg(\"-timeout\", DEFAULT_CONNECT_TIMEOUT);\n    if (nConnectTimeout <= 0)\n        nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;\n\n    // Fee-per-kilobyte amount required for mempool acceptance and relay\n    // If you are mining, be careful setting this:\n    // if you set it to zero then\n    // a transaction spammer can cheaply fill blocks using\n    // 0-fee transactions. It should be set above the real\n    // cost to you of processing a transaction.\n    if (IsArgSet(\"-minrelaytxfee\"))\n    {\n        CAmount n = 0;\n        if (!ParseMoney(GetArg(\"-minrelaytxfee\", \"\"), n)) {\n            return InitError(AmountErrMsg(\"minrelaytxfee\", GetArg(\"-minrelaytxfee\", \"\")));\n        }\n        // High fee check is done afterward in CWallet::ParameterInteraction()\n        ::minRelayTxFee = CFeeRate(n);\n    } else if (incrementalRelayFee > ::minRelayTxFee) {\n        // Allow only setting incrementalRelayFee to control both\n        ::minRelayTxFee = incrementalRelayFee;\n        LogPrintf(\"Increasing minrelaytxfee to %s to match incrementalrelayfee\\n\",::minRelayTxFee.ToString());\n    }\n\n    // Sanity check argument for min fee for including tx in block\n    // TODO: Harmonize which arguments need sanity checking and where that happens\n    if (IsArgSet(\"-blockmintxfee\"))\n    {\n        CAmount n = 0;\n        if (!ParseMoney(GetArg(\"-blockmintxfee\", \"\"), n))\n            return InitError(AmountErrMsg(\"blockmintxfee\", GetArg(\"-blockmintxfee\", \"\")));\n    }\n\n    // Feerate used to define dust.  Shouldn't be changed lightly as old\n    // implementations may inadvertently create non-standard transactions\n    if (IsArgSet(\"-dustrelayfee\"))\n    {\n        CAmount n = 0;\n        if (!ParseMoney(GetArg(\"-dustrelayfee\", \"\"), n) || 0 == n)\n            return InitError(AmountErrMsg(\"dustrelayfee\", GetArg(\"-dustrelayfee\", \"\")));\n        dustRelayFee = CFeeRate(n);\n    }\n\n    fRequireStandard = !GetBoolArg(\"-acceptnonstdtxn\", !chainparams.RequireStandard());\n    if (chainparams.RequireStandard() && !fRequireStandard)\n        return InitError(strprintf(\"acceptnonstdtxn is not currently supported for %s chain\", chainparams.NetworkIDString()));\n    nBytesPerSigOp = GetArg(\"-bytespersigop\", nBytesPerSigOp);\n\n#ifdef ENABLE_WALLET\n    if (!CWallet::ParameterInteraction())\n        return false;\n#endif\n    //Munt - generate private/public key pair for alert or checkpoint system\n    if (IsArgSet(\"-genkeypair\"))\n    {\n        ECC_Start();\n        CKey key;\n        key.MakeNewKey(false);\n\n        CPrivKey vchPrivKey = key.GetPrivKey();\n        printf(\"PrivateKey %s\\n\", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end()).c_str());\n        CPubKey vchPubKey = key.GetPubKey();\n        vchPubKey.Decompress();\n        printf(\"PublicKey %s\\n\", HexStr(vchPubKey.begin(), vchPubKey.end()).c_str());\n        exit(EXIT_SUCCESS);\n    }\n\n\n    fIsBareMultisigStd = GetBoolArg(\"-permitbaremultisig\", DEFAULT_PERMIT_BAREMULTISIG);\n    fAcceptDatacarrier = GetBoolArg(\"-datacarrier\", DEFAULT_ACCEPT_DATACARRIER);\n    nMaxDatacarrierBytes = GetArg(\"-datacarriersize\", nMaxDatacarrierBytes);\n\n    fAlerts = GetBoolArg(\"-alerts\", DEFAULT_ALERTS);\n\n    // Option to startup with mocktime set (used for regression testing):\n    SetMockTime(GetArg(\"-mocktime\", 0)); // SetMockTime(0) is a no-op\n\n    if (GetBoolArg(\"-peerbloomfilters\", DEFAULT_PEERBLOOMFILTERS))\n        nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);\n\n    nMaxTipAge = GetArg(\"-maxtipage\", DEFAULT_MAX_TIP_AGE);\n\n    fEnableReplacement = GetBoolArg(\"-mempoolreplacement\", DEFAULT_ENABLE_REPLACEMENT);\n    if ((!fEnableReplacement) && IsArgSet(\"-mempoolreplacement\")) {\n        // Minimal effort at forwards compatibility\n        std::string strReplacementModeList = GetArg(\"-mempoolreplacement\", \"\");  // default is impossible\n        std::vector<std::string> vstrReplacementModes;\n        boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(\",\"));\n        fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), \"fee\") != vstrReplacementModes.end());\n    }\n\n    if (gArgs.IsArgSet(\"-vbparams\")) {\n        // Allow overriding version bits parameters for testing\n        if (!chainparams.MineBlocksOnDemand()) {\n            return InitError(\"Version bits parameters may only be overridden on regtest.\");\n        }\n        for (const std::string& strDeployment : gArgs.GetArgs(\"-vbparams\")) {\n            std::vector<std::string> vDeploymentParams;\n            boost::split(vDeploymentParams, strDeployment, boost::is_any_of(\":\"));\n            if (vDeploymentParams.size() != 3) {\n                return InitError(\"Version bits parameters malformed, expecting deployment:start:end\");\n            }\n            int64_t nStartTime, nTimeout;\n            if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {\n                return InitError(strprintf(\"Invalid nStartTime (%s)\", vDeploymentParams[1]));\n            }\n            if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {\n                return InitError(strprintf(\"Invalid nTimeout (%s)\", vDeploymentParams[2]));\n            }\n            bool found = false;\n            for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j)\n            {\n                if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) {\n                    UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout);\n                    found = true;\n                    LogPrintf(\"Setting version bits activation parameters for %s to start=%ld, timeout=%ld\\n\", vDeploymentParams[0], nStartTime, nTimeout);\n                    break;\n                }\n            }\n            if (!found) {\n                return InitError(strprintf(\"Invalid deployment (%s)\", vDeploymentParams[0]));\n            }\n        }\n    }\n    return true;\n}\n\nstatic bool LockDataDirectory(bool probeOnly)\n{\n    std::string strDataDir = GetDataDir().string();\n\n    // Make sure only a single Munt process is using the data directory.\n    //fixme: (POST-PHASE5)\n    (unused) probeOnly;\n    /* (MUNT) - we do this elsewhere (MERGE) look into this again.\n    FILE* file = fsbridge::fopen(pathLockFile, \"a\"); // empty lock file; created if it doesn't exist.\n    if (file) fclose(file);\n\n    try {\n        static boost::interprocess::file_lock lock(pathLockFile.string().c_str());\n        if (!lock.try_lock()) {\n            return InitError(strprintf(errortr(\"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\"), strDataDir, errortr(PACKAGE_NAME)));\n        }\n        if (probeOnly) {\n            lock.unlock();\n        }\n    } catch(const boost::interprocess::interprocess_exception& e) {\n        return InitError(strprintf(errortr(\"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\") + \" %s.\", strDataDir, errortr(PACKAGE_NAME), e.what()));\n    }*/\n    return true;\n}\n\nbool AppInitSanityChecks()\n{\n    // ********************************************************* Step 4: sanity checks\n\n    // Initialize elliptic curve code\n    ECC_Start();\n    globalVerifyHandle.reset(new ECCVerifyHandle());\n\n    // Sanity check\n    if (!InitSanityCheck())\n        return InitError(strprintf(errortr(\"Initialization sanity check failed. %s is shutting down.\"), _(PACKAGE_NAME)));\n\n    // Probe the data directory lock to give an early error message, if possible\n    return LockDataDirectory(true);\n}\n\nextern bool InitRPCWarmup();\nextern bool InitTor();\n\nbool AppInitMain(boost::thread_group& threadGroup, node::NodeContext& node)\n{\n    const CChainParams& chainparams = Params();\n    // ********************************************************* Step 4a: application initialization\n    // After daemonization get the data directory lock again and hold on to it until exit\n    // This creates a slight window for a race condition to happen, however this condition is harmless: it\n    // will at most make us exit without printing a message to console.\n    if (!LockDataDirectory(false))\n    {\n        // Detailed error printed inside LockDataDirectory\n        return false;\n    }\n\n    std::string sha256_algo = SHA256AutoDetect();\n    LogPrintf(\"Using the '%s' SHA256 implementation\\n\", sha256_algo);\n    \n    //fixme: (SIGMA) Improve.\n    // Select optimised algorithms for SIGMA\n    selectOptimisedImplementations();\n\n#ifndef WIN32\n    CreatePidFile(GetPidFile(), getpid());\n#endif\n    if (GetBoolArg(\"-shrinkdebugfile\", logCategories == BCLog::NONE))\n    {\n        // Do this first since it both loads a bunch of debug.log into memory,\n        // and because this needs to happen before any other debug.log printing\n        ShrinkDebugFile();\n    }\n\n    if (fPrintToDebugLog)\n        OpenDebugLog();\n\n    if (!fLogTimestamps)\n        LogPrintf(\"Startup time: %s\\n\", FormatISO8601DateTime(GetTime()));\n    LogPrintf(\"Default data directory %s\\n\", GetDefaultDataDir().string());\n    LogPrintf(\"Using data directory %s\\n\", GetDataDir().string());\n    LogPrintf(\"Using config file %s\\n\", GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)).string());\n    LogPrintf(\"Using at most %i automatic connections (%i file descriptors available)\\n\", nMaxConnections, nFD);\n\n    InitSignatureCache();\n\n    LogPrintf(\"Script verification uses %d additional threads\\n\", nScriptCheckThreads);\n    if (nScriptCheckThreads >= 1) {\n        StartScriptCheckWorkerThreads(nScriptCheckThreads);\n    }\n\n    assert(!node.scheduler);\n    node.scheduler = std::make_unique<CScheduler>();\n\n    // Start the lightweight task scheduler thread\n    node.scheduler->m_service_thread = std::thread(&util::TraceThread, \"scheduler\", std::function<void()>([&] { node.scheduler->serviceQueue(); }));\n\n    GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler);\n\n#ifdef ENABLE_WALLET\n    // InitRPCMining is needed here so getblocktemplate in the GUI debug console works properly.\n    InitRPCMining();\n#endif\n\n    /* Start the RPC server already.  It will be started in \"warmup\" mode\n     * and not really process calls already (but it will signify connections\n     * that the server is there and will be ready later).  Warmup mode will\n     * be disabled when initialisation is finished.\n     */\n    if (!InitRPCWarmup())\n        return false;\n\n    int64_t nStart;\n\n#if defined(USE_SSE2)\n    scrypt_detect_sse2();\n#endif\n\n    // ********************************************************* Step 5: verify wallet database integrity\n#ifdef ENABLE_WALLET\n    if (!CWallet::Verify())\n        return false;\n#endif\n\n    #ifdef ENABLE_WALLET\n    StartShadowPoolManagerThread(threadGroup);\n    #endif\n\n    // ********************************************************* Step 6: network initialization\n    // Note that we absolutely cannot open any actual connections\n    // until the very end (\"start node\") as the UTXO/block state\n    // is not yet setup and may end up being set up twice if we\n    // need to reindex later.\n\n    assert(!g_connman);\n    g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));\n    CConnman& connman = *g_connman;\n\n    if (gArgs.IsArgSet(\"-disablenet\"))\n        g_connman->SetNetworkActive(false);\n\n    peerLogic.reset(new PeerLogicValidation(&connman));\n    RegisterValidationInterface(peerLogic.get());\n    RegisterNodeSignals(GetNodeSignals());\n\n    // sanitize comments per BIP-0014, format user agent and check total size\n    std::vector<std::string> uacomments;\n    if (gArgs.IsArgSet(\"-uacomment\"))\n    {\n        for(std::string cmt : gArgs.GetArgs(\"-uacomment\"))\n        {\n            if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))\n                return InitError(strprintf(errortr(\"User Agent comment (%s) contains unsafe characters.\"), cmt));\n            uacomments.push_back(cmt);\n        }\n    }\n\n    //fixme: (UNITY) - HIGH - Sanitize this in some way or handle this differently (e.g. allow unity to set this but not desktop users via command line)\n    strSubVersion = FormatSubVersion(GetArg(\"-clientname\", CLIENT_NAME), CLIENT_VERSION, uacomments);\n    if (strSubVersion.size() > MAX_SUBVERSION_LENGTH)\n    {\n        return InitError(strprintf(errortr(\"Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.\"),\n            strSubVersion.size(), MAX_SUBVERSION_LENGTH));\n    }\n\n    if (gArgs.IsArgSet(\"-onlynet\"))\n    {\n        std::set<enum Network> nets;\n        for(const std::string& snet : gArgs.GetArgs(\"-onlynet\"))\n        {\n            enum Network net = ParseNetwork(snet);\n            if (net == NET_UNROUTABLE)\n                return InitError(strprintf(errortr(\"Unknown network specified in -onlynet: '%s'\"), snet));\n            nets.insert(net);\n        }\n        for (int n = 0; n < NET_MAX; n++)\n        {\n            enum Network net = (enum Network)n;\n            if (!nets.count(net))\n                SetLimited(net);\n        }\n    }\n\n    if (gArgs.IsArgSet(\"-whitelist\"))\n    {\n        for(const std::string& net : gArgs.GetArgs(\"-whitelist\"))\n        {\n            CSubNet subnet;\n            LookupSubNet(net.c_str(), subnet);\n            if (!subnet.IsValid())\n                return InitError(strprintf(errortr(\"Invalid netmask specified in -whitelist: '%s'\"), net));\n            connman.AddWhitelistedRange(subnet);\n        }\n    }\n\n    // Check for host lookup allowed before parsing any network related parameters\n    fNameLookup = GetBoolArg(\"-dns\", DEFAULT_NAME_LOOKUP);\n\n    bool proxyRandomize = GetBoolArg(\"-proxyrandomize\", DEFAULT_PROXYRANDOMIZE);\n    // -proxy sets a proxy for all outgoing network traffic\n    // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default\n    std::string proxyArg = GetArg(\"-proxy\", \"\");\n    SetLimited(NET_TOR);\n    if (proxyArg != \"\" && proxyArg != \"0\")\n    {\n        CService proxyAddr;\n        if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup))\n        {\n            return InitError(strprintf(errortr(\"Invalid -proxy address or hostname: '%s'\"), proxyArg));\n        }\n\n        proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);\n        if (!addrProxy.IsValid())\n            return InitError(strprintf(errortr(\"Invalid -proxy address or hostname: '%s'\"), proxyArg));\n\n        SetProxy(NET_IPV4, addrProxy);\n        SetProxy(NET_IPV6, addrProxy);\n        SetProxy(NET_TOR, addrProxy);\n        SetNameProxy(addrProxy);\n        SetLimited(NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later\n    }\n\n    // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses\n    // -noonion (or -onion=0) disables connecting to .onion entirely\n    // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)\n    std::string onionArg = GetArg(\"-onion\", \"\");\n    if (onionArg != \"\")\n    {\n        // Handle -noonion/-onion=0\n        if (onionArg == \"0\")\n        {\n            SetLimited(NET_TOR); // set onions as unreachable\n        }\n        else\n        {\n            CService onionProxy;\n            if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup))\n            {\n                return InitError(strprintf(errortr(\"Invalid -onion address or hostname: '%s'\"), onionArg));\n            }\n            proxyType addrOnion = proxyType(onionProxy, proxyRandomize);\n            if (!addrOnion.IsValid())\n                return InitError(strprintf(errortr(\"Invalid -onion address or hostname: '%s'\"), onionArg));\n            SetProxy(NET_TOR, addrOnion);\n            SetLimited(NET_TOR, false);\n        }\n    }\n\n    // see Step 2: parameter interactions for more information about these\n    fListen = GetBoolArg(\"-listen\", DEFAULT_LISTEN);\n    fDiscover = GetBoolArg(\"-discover\", true);\n    fRelayTxes = !GetBoolArg(\"-blocksonly\", DEFAULT_BLOCKSONLY);\n\n    //fixme: (FUT) Improve exception handling here\n    try\n    {\n        if (fListen)\n        {\n            bool fBound = false;\n            if (gArgs.IsArgSet(\"-bind\")) {\n                for(const std::string& strBind : gArgs.GetArgs(\"-bind\"))\n                {\n                    CService addrBind;\n                    if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))\n                        return InitError(ResolveErrMsg(\"bind\", strBind));\n                    fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));\n                }\n            }\n            if (gArgs.IsArgSet(\"-whitebind\"))\n            {\n                for(const std::string& strBind : gArgs.GetArgs(\"-whitebind\"))\n                {\n                    CService addrBind;\n                    if (!Lookup(strBind.c_str(), addrBind, 0, false))\n                        return InitError(ResolveErrMsg(\"whitebind\", strBind));\n                    if (addrBind.GetPort() == 0)\n                        return InitError(strprintf(errortr(\"Need to specify a port with -whitebind: '%s'\"), strBind));\n                    fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));\n                }\n            }\n            if (!gArgs.IsArgSet(\"-bind\") && !gArgs.IsArgSet(\"-whitebind\"))\n            {\n                struct in_addr inaddr_any;\n                inaddr_any.s_addr = INADDR_ANY;\n                fBound |= Bind(connman, CService((in6_addr)IN6ADDR_ANY_INIT, GetListenPort()), BF_NONE);\n                fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);\n            }\n            if (!fBound)\n                return InitError(errortr(\"Failed to listen on any port. Use -listen=0 if you want this.\"));\n        }\n    }\n    catch(...)\n    {\n        return InitError(errortr(\"Failed to listen on any port. Use -listen=0 if you want this.\"));\n    }\n\n    if (gArgs.IsArgSet(\"-externalip\"))\n    {\n        for(const std::string& strAddr : gArgs.GetArgs(\"-externalip\"))\n        {\n            CService addrLocal;\n            if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())\n                AddLocal(addrLocal, LOCAL_MANUAL);\n            else\n                return InitError(ResolveErrMsg(\"externalip\", strAddr));\n        }\n    }\n\n#if ENABLE_ZMQ\n    pzmqNotificationInterface = CZMQNotificationInterface::Create();\n\n    if (pzmqNotificationInterface)\n    {\n        RegisterValidationInterface(pzmqNotificationInterface);\n    }\n#endif\n    uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set\n    uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME;\n\n    if (IsArgSet(\"-maxuploadtarget\"))\n    {\n        nMaxOutboundLimit = GetArg(\"-maxuploadtarget\", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;\n    }\n\n    // ********************************************************* Step 7: load block chain\n\n    fReverseHeaders = GetBoolArg(\"-reverseheaders\", true);\n    fReindex = GetBoolArg(\"-reindex\", false);\n    bool fReindexChainState = GetBoolArg(\"-reindex-chainstate\", false);\n\n    fs::create_directories(GetDataDir() / \"blocks\");\n\n    // cache size calculations\n    int64_t nTotalCache = (GetArg(\"-dbcache\", nDefaultDbCache) << 20);\n    nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache\n    nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache\n    int64_t nBlockTreeDBCache = nTotalCache / 8;\n    nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg(\"-txindex\", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);\n    nTotalCache -= nBlockTreeDBCache;\n    int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache\n    nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache\n    nTotalCache -= nCoinDBCache;\n    nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache\n    int64_t nMempoolSizeMax = GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;\n    LogPrintf(\"Cache configuration:\\n\");\n    LogPrintf(\"* Using %.1fMiB for block index database\\n\", nBlockTreeDBCache * (1.0 / 1024 / 1024));\n    LogPrintf(\"* Using %.1fMiB for chain state database\\n\", nCoinDBCache * (1.0 / 1024 / 1024));\n    LogPrintf(\"* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\\n\", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));\n\n    if (fReverseHeaders)\n    {\n        LogPrintf(\"Reverse header sync will temporarily use up to %.1fMiB until initial sync is complete\", sizeof(CBlockHeader) * 1000000.0 / 1024.0 / 1024.0);\n    }\n\n    bool fLoaded = false;\n    while (!fLoaded)\n    {\n        bool fReset = fReindex;\n        std::string strLoadError;\n\n        uiInterface.InitMessage(_(\"Loading block index...\"));\n\n        nStart = GetTimeMillis();\n        bool fullResyncForUpgrade = IsArgSet(\"-resyncforblockindexupgrade\");\n        do\n        {\n            try\n            {\n                static bool upgradeOnceOnly=true;\n                UnloadBlockIndex();\n                loadblockindex:\n                delete pcoinsTip;\n                delete pcoinsdbview;\n                delete pcoinscatcher;\n                delete pblocktree;\n\n                pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);\n                pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);\n                pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);\n                pcoinsTip = new CCoinsViewCache(pcoinscatcher);\n\n                delete ppow2witdbview;\n                delete ppow2witcatcher;\n                ppow2witTip = nullptr;\n\n                ppow2witdbview = new CWitViewDB(nCoinDBCache, false, fReindex || fReindexChainState);\n                ppow2witcatcher = new CCoinsViewErrorCatcher(ppow2witdbview);\n                ppow2witTip = std::shared_ptr<CCoinsViewCache>(new CCoinsViewCache(ppow2witcatcher));\n\n                pcoinsTip->SetSiblingView(ppow2witTip);\n\n\n                if (fReindex)\n                {\n                    pblocktree->WriteReindexing(true);\n                    //If we're reindexing in prune mode, wipe away unusable block files and all undo data files\n                    if (fPruneMode)\n                        CleanupBlockRevFiles();\n                }\n                else\n                {\n                    if (pcoinsdbview->RequiresReindex())\n                    {\n                        fReindex = true;\n                        if (pcoinsdbview->nPreviousVersion < 2)\n                        {\n                            fullResyncForUpgrade = true;\n                            goto fullresyncforupgrade;\n                        }\n                        goto loadblockindex;\n                    }\n                    else\n                    {\n                        // If necessary, upgrade from older database format.\n                        if (!pcoinsdbview->Upgrade())\n                        {\n                            strLoadError = errortr(\"Error upgrading chainstate database\");\n                            break;\n                        }\n                    }\n                }\n                pcoinsdbview->WriteVersion();\n                \n\n                //MUNT - version 2.0 upgrade\n                if (upgradeOnceOnly && pcoinsdbview->nPreviousVersion < pcoinsdbview->nCurrentVersion)\n                {\n                    if (fullResyncForUpgrade)\n                    {\n                        fullresyncforupgrade:\n                        upgradeOnceOnly = false;\n                        uiInterface.InitMessage(_(\"Erasing block index...\"));\n                        UnloadBlockIndex();\n                        fReindex = true;\n                        blockStore.Delete();\n                        goto loadblockindex;\n                    }\n                }\n\n                if (!LoadBlockIndex(chainparams))\n                {\n                    strLoadError = errortr(\"Error loading block database\");\n                    break;\n                }\n\n                // Upgrade\n                if (upgradeOnceOnly && pcoinsdbview->nPreviousVersion < pcoinsdbview->nCurrentVersion)\n                {\n                    upgradeOnceOnly = false;\n                    if (!fullResyncForUpgrade)\n                    {\n                        uiInterface.InitMessage(_(\"Upgrading block index...\"));\n                        if (!UpgradeBlockIndex(chainparams, pcoinsdbview->nPreviousVersion, pcoinsdbview->nCurrentVersion))\n                        {\n                            LogPrintf(\"Error upgrading block database, attempting to wipe index and resync instead.\");\n                            fullResyncForUpgrade = true;\n                        }\n                        else\n                        {\n                            uiInterface.InitMessage(_(\"Reloading block index...\"));\n                            // Flush and reload index\n                            FlushStateToDisk();\n                            UnloadBlockIndex();\n                        }\n                    }\n                    if (fullResyncForUpgrade)\n                    {\n                        uiInterface.InitMessage(_(\"Erasing block index...\"));\n                        UnloadBlockIndex();\n                        fReindex = true;\n                        blockStore.Delete();\n                        goto loadblockindex;\n                    }\n                    goto loadblockindex;\n                }\n\n                // If the loaded chain has a wrong genesis, bail out immediately\n                // (we're likely using a testnet datadir, or the other way around).\n                if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0)\n                    return InitError(_(\"Incorrect or no genesis block found. Wrong datadir for network?\"));\n\n                // Initialize the block index (no-op if non-empty database was already loaded)\n                if (!InitBlockIndex(chainparams))\n                {\n                    strLoadError = errortr(\"Error initializing block database\");\n                    break;\n                }\n\n                // Check for changed -txindex state\n                if (fTxIndex != GetBoolArg(\"-txindex\", DEFAULT_TXINDEX))\n                {\n                    // Immediately force the arg to match the datadir setting, to prevent accidentally having the value get written into the datadir anywhere else in the code\n                    SoftSetBoolArg(\"-txindex\", fTxIndex);\n\n                    strLoadError = errortr(\"You need to rebuild the database using -reindex-chainstate to change -txindex\");\n                    break;\n                }\n\n                // Check for changed -prune state.  What we are concerned about is a user who has pruned blocks\n                // in the past, but is now trying to run unpruned.\n                if (fHavePruned && !fPruneMode)\n                {\n                    // Immediately force the arg to match the datadir setting, to prevent accidentally having the value get written into the datadir anywhere else in the code\n                    fPruneMode = fHavePruned;\n                    strLoadError = errortr(\"You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain\");\n                    break;\n                }\n\n                if (!fReindex && chainActive.Tip() != NULL)\n                {\n                    uiInterface.InitMessage(_(\"Rewinding blocks...\"));\n                    if (!RewindBlockIndex(chainparams))\n                    {\n                        strLoadError = errortr(\"Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain\");\n                        break;\n                    }\n                }\n\n                uiInterface.InitMessage(_(\"Verifying blocks...\"));\n                if (fHavePruned && GetArg(\"-checkblocks\", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP)\n                {\n                    LogPrintf(\"Prune: pruned datadir may not have more than %d blocks; only checking available blocks\", MIN_BLOCKS_TO_KEEP);\n                }\n\n                {\n                    LOCK(cs_main);\n                    CBlockIndex* tip = chainActive.Tip();\n                    RPCNotifyBlockChange(true, tip);\n                    if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60)\n                    {\n                        strLoadError = errortr(\"The block database contains a block which appears to be from the future. \"\n                                \"This may be due to your computer's date and time being set incorrectly. \"\n                                \"Only rebuild the block database if you are sure that your computer's date and time are correct\");\n                        break;\n                    }\n                }\n\n                if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg(\"-checklevel\", DEFAULT_CHECKLEVEL), GetArg(\"-checkblocks\", DEFAULT_CHECKBLOCKS)))\n                {\n                    strLoadError = errortr(\"Corrupted block database detected\");\n                    break;\n                }\n            }\n            catch (const std::exception& e)\n            {\n                LogPrintf(\"%s\\n\", e.what());\n                strLoadError = errortr(\"Error opening block database\");\n                break;\n            }\n\n            fLoaded = true;\n        } while(false);\n\n        if (!fLoaded)\n        {\n            // first suggest a reindex\n            if (!fReset)\n            {\n                auto fRet = uiInterface.ThreadSafeQuestion(\n                    strLoadError + \".\\n\\n\" + errortr(\"Do you want to rebuild the block database now?\"),\n                    strLoadError + \".\\nPlease restart with -reindex or -reindex-chainstate to recover.\",\n                    \"\", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);\n                if (fRet.value_or(false))\n                {\n                    fReindex = true;\n                }\n                else\n                {\n                    LogPrintf(\"Aborted block database rebuild. Exiting.\\n\");\n                    return false;\n                }\n            }\n            else\n            {\n                return InitError(strLoadError);\n            }\n        }\n    }\n\n    LogPrintf(\" block index %15dms\\n\", GetTimeMillis() - nStart);\n\n    fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;\n    CAutoFile est_filein(fsbridge::fopen(est_path, \"rb\"), SER_DISK, CLIENT_VERSION);\n    // Allowed to fail as this file IS missing on first startup.\n    if (!est_filein.IsNull())\n        ::feeEstimator.Read(est_filein);\n    fFeeEstimatesInitialized = true;\n\n    // ********************************************************* Step 8: load wallet\n#ifdef ENABLE_WALLET\n    if (!CWallet::InitLoadWallet())\n        return false;\n#else\n    LogPrintf(\"No wallet support compiled in!\\n\");\n#endif\n    \n    // NB! While ideally we would want to poll for this ahead of calling InitLoadWallet()\n    // Doing so sometimes leads to DBEnv corruption if closing the software really quickly\n    // By only exiting after InitLoadWallet everything is seemingly flushed and avoids this.\n    // In future we should look into better solutions so that we can close faster here.\n    //\n    // As LoadBlockIndex can take several minutes, it's possible the user\n    // requested to kill the GUI during the last operation. If so, exit.\n    // As the program has not fully started yet, Shutdown() is possibly overkill.\n    if (ShutdownRequested())\n    {\n        LogPrintf(\"Shutdown requested. Exiting.\\n\");\n        return false;\n    }\n\n\n    StartPoW2WitnessThread(threadGroup);\n\n    // ********************************************************* Step 9: data directory maintenance\n\n    // if pruning, unset the service bit and perform the initial blockstore prune\n    // after any wallet rescanning has taken place.\n    if (fPruneMode) {\n        LogPrintf(\"Unsetting NODE_NETWORK on prune mode\\n\");\n        nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);\n        if (!fReindex) {\n            uiInterface.InitMessage(_(\"Pruning blockstore...\"));\n            PruneAndFlush();\n        }\n    }\n\n    // Note that setting NODE_SEGSIG is never required: the only downside from not\n    // doing so is that after activation, no upgraded nodes will fetch from you.\n    nLocalServices = ServiceFlags(nLocalServices | NODE_SEGSIG);\n    nRelevantServices = ServiceFlags(nRelevantServices | NODE_SEGSIG);\n\n    // ********************************************************* Step 10: import blocks\n\n    if (!CheckDiskSpace())\n        return false;\n\n    // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.\n    // No locking, as this happens before any background thread is started.\n    if (chainActive.Tip() == NULL) {\n        uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait);\n    } else {\n        fHaveGenesis = true;\n    }\n\n    if (IsArgSet(\"-blocknotify\"))\n        uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);\n\n    std::vector<fs::path> vImportFiles;\n    if (gArgs.IsArgSet(\"-loadblock\"))\n    {\n        for(const std::string& strFile : gArgs.GetArgs(\"-loadblock\"))\n            vImportFiles.push_back(strFile);\n    }\n\n    threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));\n\n    // Wait for genesis block to be processed\n    {\n        WAIT_LOCK(cs_GenesisWait, lock);\n        // We previously could hang here if StartShutdown() is called prior to\n        // ThreadImport getting started, so instead we just wait on a timer to\n        // check ShutdownRequested() regularly.\n        while (!fHaveGenesis && !ShutdownRequested()) {\n            condvar_GenesisWait.wait_for(lock, std::chrono::milliseconds(500));\n        }\n        \n        if (ShutdownRequested())\n        {\n            return false;\n        }\n\n        uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);\n    }\n\n    // ********************************************************* Step 11: start node\n\n    //// debug print\n    LogPrintf(\"mapBlockIndex.size() = %u\\n\",   mapBlockIndex.size());\n    LogPrintf(\"nBestHeight = %d\\n\",                   chainActive.Height());\n    //LogPrintf(\"setKeyPoolExternal.size() = %u\\n\",      pwalletMain ? pwalletMain->setKeyPoolExternal.size() : 0);\n    InitTor();\n\n    Discover();\n\n    // Map ports with UPnP\n    MapPort(GetBoolArg(\"-upnp\", DEFAULT_UPNP));\n\n    std::string strNodeError;\n    CConnman::Options connOptions;\n    connOptions.nLocalServices = nLocalServices;\n    connOptions.nRelevantServices = nRelevantServices;\n    connOptions.nMaxConnections = nMaxConnections;\n    connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);\n    connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;\n    connOptions.nMaxFeeler = 1;\n    connOptions.nBestHeight = chainActive.Height();\n    connOptions.uiInterface = &uiInterface;\n    connOptions.nSendBufferMaxSize = 1000*GetArg(\"-maxsendbuffer\", DEFAULT_MAXSENDBUFFER);\n    connOptions.nReceiveFloodSize = 1000*GetArg(\"-maxreceivebuffer\", DEFAULT_MAXRECEIVEBUFFER);\n\n    connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;\n    connOptions.nMaxOutboundLimit = nMaxOutboundLimit;\n\n    if (gArgs.IsArgSet(\"-seednode\")) {\n        connOptions.vSeedNodes = gArgs.GetArgs(\"-seednode\");\n    }\n\n    if (!connman.Start(*node.scheduler, strNodeError, connOptions))\n        return InitError(strNodeError);\n\n\n    // Generate coins in the background\n    if (GetBoolArg(\"-gen\", DEFAULT_GENERATE))\n    {\n        uint64_t nGenProcLimit = GetArg(\"-genproclimit\", DEFAULT_GENERATE_THREADS);\n        uint64_t nGenArenaProcLimit = GetArg(\"-genarenaproclimit\", DEFAULT_GENERATE_THREADS);\n        if (nGenArenaProcLimit <= 0)\n            nGenArenaProcLimit = nGenProcLimit;\n        uint64_t nGenMemoryLimitKilobytes = GetArg(\"-genmemlimit\", defaultSigmaSettings.arenaSizeKb);\n        \n        if (nGenProcLimit > 0 && nGenMemoryLimitKilobytes > 0)\n        {\n            //fixme: (SIGMA) (DEDUP) - Move this all to a helper function that can share it with RPC (and -gen) etc.\n            #ifdef ENABLE_WALLET\n            if (pactiveWallet)\n            {\n                CAccount* miningAccount = nullptr;\n\n                LOCK2(cs_main, pactiveWallet->cs_wallet);\n                for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n                {\n                    (unused) accountUUID;\n                    if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n                    {\n                        miningAccount = account;\n                        break;\n                    }\n                }\n\n                if (miningAccount)\n                {\n                    std::string readOverrideAddress;\n                    CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(readOverrideAddress);\n                    if (readOverrideAddress.size() == 0)\n                    {\n                        CReserveKeyOrScript* miningAddress = new CReserveKeyOrScript(pactiveWallet, miningAccount, KEYCHAIN_EXTERNAL);\n                        CPubKey pubKey;\n                        if (miningAddress->GetReservedKey(pubKey))\n                        {\n                            CKeyID keyID = pubKey.GetID();\n                            readOverrideAddress = CNativeAddress(keyID).ToString();\n                        }\n                    }\n                    LogPrintf(\"Mine at startup using -gen into mining account\\n\");\n                    PoWGenerateBlocks(true, nGenProcLimit, nGenArenaProcLimit, nGenMemoryLimitKilobytes, chainparams, miningAccount, readOverrideAddress);\n                }\n                else\n                {\n                    LogPrintf(\"Mine at startup using -gen into regular account\\n\");\n                    PoWGenerateBlocks(true, nGenProcLimit, nGenArenaProcLimit, nGenMemoryLimitKilobytes, chainparams);\n                }\n            }\n            else\n            #endif\n            {\n                LogPrintf(\"Mine at startup using -gen into regular account\\n\");\n                PoWGenerateBlocks(true, nGenProcLimit, nGenArenaProcLimit, nGenMemoryLimitKilobytes, chainparams);\n            }\n        }\n    }\n    // ********************************************************* Step 12: finished\n\n    SetRPCWarmupFinished();\n    \n    uiInterface.InitMessage(_(\"Done loading\"));\n\n#ifdef ENABLE_WALLET\n    for (CWalletRef pwallet : vpwallets) {\n        pwallet->postInitProcess(*node.scheduler);\n    }\n#endif\n\n    return !ShutdownRequested();\n}\n"
  },
  {
    "path": "src/init.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_INIT_H\n#define CORE_INIT_H\n\n#include <string>\n\nclass CScheduler;\nclass CWallet;\n\nstatic const bool DEFAULT_PROXYRANDOMIZE = true;\nstatic const bool DEFAULT_REST_ENABLE = false;\nstatic const bool DEFAULT_DISABLE_SAFEMODE = false;\nstatic const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;\nstatic const bool DEFAULT_SPV = false;\n\n//fixme: (PHASE4) comment this out for release\n//#define BETA_BUILD\n\nnamespace boost\n{\n    class thread_group;\n}\n\nnamespace node\n{\n    struct NodeContext;\n}\n\n/** Interrupt core threads */\nvoid CoreInterrupt(boost::thread_group& threadGroup);\n/** Stop core threads */\nvoid CoreShutdown(boost::thread_group& threadGroup, node::NodeContext& nodeContext);\n//!Initialize the logging infrastructure\nvoid InitLogging();\n//!Initialize any app specific hardcoded paramaters here (e.g. the android wallet will set -spv)\n//!This is called after loading the config file\nvoid InitAppSpecificConfigParamaters();\nvoid InitAppSpecificDatadirParamaters();\n//!Parameter interaction: change current parameters depending on various rules\nvoid InitParameterInteraction();\n\n/** Initialize Munt: Basic context setup.\n *  @note This can be done before daemonization.\n *  @pre Parameters should be parsed and config file should be read.\n */\nbool AppInitBasicSetup();\n/**\n * Initialization: parameter interaction.\n * @note This can be done before daemonization.\n * @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.\n */\nbool AppInitParameterInteraction();\n/**\n * Initialization sanity checks: ecc init, sanity checks, dir lock.\n * @note This can be done before daemonization.\n * @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.\n */\nbool AppInitSanityChecks();\n/**\n * Munt main initialization.\n * @note This should only be done after daemonization.\n * @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.\n */\nbool AppInitMain(boost::thread_group& threadGroup, node::NodeContext& node);\n\n/** The help message mode determines what help message to show */\nenum HelpMessageMode {\n    HMM_DAEMON,\n    HMM_UI\n};\n\n/** Help for options shared between UI and daemon (for -help) */\nstd::string HelpMessage(HelpMessageMode mode);\n/** Returns licensing information (for -version) */\nstd::string LicenseInfo();\n\nextern bool partiallyEraseDatadirOnShutdown;\nextern bool fullyEraseDatadirOnShutdown;\n\n#endif\n"
  },
  {
    "path": "src/key.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"key.h\"\n\n#include \"arith_uint256.h\"\n#include \"crypto/common.h\"\n#include \"crypto/hmac_sha512.h\"\n#include \"pubkey.h\"\n#include \"random.h\"\n#include \"appname.h\"\n\n#include <secp256k1.h>\n#include <secp256k1_recovery.h>\n\nstatic secp256k1_context* secp256k1_context_sign = NULL;\n\n/** These functions are taken from the libsecp256k1 distribution and are very ugly. */\nstatic int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {\n    const unsigned char *end = privkey + privkeylen;\n    int lenb = 0;\n    int len = 0;\n    memset(out32, 0, 32);\n    /* sequence header */\n    if (end < privkey+1 || *privkey != 0x30) {\n        return 0;\n    }\n    privkey++;\n    /* sequence length constructor */\n    if (end < privkey+1 || !(*privkey & 0x80)) {\n        return 0;\n    }\n    lenb = *privkey & ~0x80; privkey++;\n    if (lenb < 1 || lenb > 2) {\n        return 0;\n    }\n    if (end < privkey+lenb) {\n        return 0;\n    }\n    /* sequence length */\n    len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);\n    privkey += lenb;\n    if (end < privkey+len) {\n        return 0;\n    }\n    /* sequence element 0: version number (=1) */\n    if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {\n        return 0;\n    }\n    privkey += 3;\n    /* sequence element 1: octet string, up to 32 bytes */\n    if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {\n        return 0;\n    }\n    memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);\n    if (!secp256k1_ec_seckey_verify(ctx, out32)) {\n        memset(out32, 0, 32);\n        return 0;\n    }\n    return 1;\n}\n\nstatic int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {\n    secp256k1_pubkey pubkey;\n    size_t pubkeylen = 0;\n    if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {\n        *privkeylen = 0;\n        return 0;\n    }\n    if (compressed) {\n        static const unsigned char begin[] = {\n            0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20\n        };\n        static const unsigned char middle[] = {\n            0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,\n            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,\n            0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,\n            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,\n            0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,\n            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00\n        };\n        unsigned char *ptr = privkey;\n        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);\n        memcpy(ptr, key32, 32); ptr += 32;\n        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);\n        pubkeylen = 33;\n        secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);\n        ptr += pubkeylen;\n        *privkeylen = ptr - privkey;\n    } else {\n        static const unsigned char begin[] = {\n            0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20\n        };\n        static const unsigned char middle[] = {\n            0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,\n            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,\n            0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,\n            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,\n            0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,\n            0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,\n            0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,\n            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00\n        };\n        unsigned char *ptr = privkey;\n        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);\n        memcpy(ptr, key32, 32); ptr += 32;\n        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);\n        pubkeylen = 65;\n        secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);\n        ptr += pubkeylen;\n        *privkeylen = ptr - privkey;\n    }\n    return 1;\n}\n\nbool CKey::Check(const unsigned char *vch) {\n    return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);\n}\n\nvoid CKey::MakeNewKey(bool fCompressedIn) {\n    do {\n        GetStrongRandBytes(keydata.data(), keydata.size());\n    } while (!Check(keydata.data()));\n    fValid = true;\n    fCompressed = fCompressedIn;\n}\n\nCPrivKey CKey::GetPrivKey() const {\n    assert(fValid);\n    CPrivKey privkey;\n    int ret;\n    size_t privkeylen;\n    privkey.resize(279);\n    privkeylen = 279;\n    ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);\n    assert(ret);\n    privkey.resize(privkeylen);\n    return privkey;\n}\n\nCPubKey CKey::GetPubKey() const {\n    assert(fValid);\n    secp256k1_pubkey pubkey;\n    size_t clen = 65;\n    CPubKey result;\n    int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());\n    assert(ret);\n    secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);\n    assert(result.size() == clen);\n    assert(result.IsValid());\n    return result;\n}\n\nbool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {\n    if (!fValid)\n        return false;\n    vchSig.resize(72);\n    size_t nSigLen = 72;\n    unsigned char extra_entropy[32] = {0};\n    WriteLE32(extra_entropy, test_case);\n    secp256k1_ecdsa_signature sig;\n    int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);\n    assert(ret);\n    secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);\n    vchSig.resize(nSigLen);\n    return true;\n}\n\nbool CKey::VerifyPubKey(const CPubKey& pubkey) const {\n    if (pubkey.IsCompressed() != fCompressed) {\n        return false;\n    }\n    unsigned char rnd[8];\n    std::string str = GLOBAL_APPNAME\" key verification\\n\";\n    GetRandBytes(rnd, sizeof(rnd));\n    uint256 hash;\n    CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin());\n    std::vector<unsigned char> vchSig;\n    Sign(hash, vchSig);\n    return pubkey.Verify(hash, vchSig);\n}\n\nbool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {\n    if (!fValid)\n        return false;\n    vchSig.resize(65);\n    int rec = -1;\n    secp256k1_ecdsa_recoverable_signature sig;\n    int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL);\n    assert(ret);\n    secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig);\n    assert(ret);\n    assert(rec != -1);\n    vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);\n    return true;\n}\n\nbool CKey::Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck) {\n    if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))\n        return false;\n    fCompressed = vchPubKey.IsCompressed();\n    fValid = true;\n\n    if (fSkipCheck)\n        return true;\n\n    return VerifyPubKey(vchPubKey);\n}\n\nbool CKey::SetPrivKey(const CPrivKey& privkey, bool fCompressedIn)\n{\n    if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))\n        return false;\n    fCompressed = fCompressedIn;\n    fValid = true;\n    return true;\n}\n\nbool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {\n    assert(IsValid());\n    assert(IsCompressed());\n    std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);\n    if ((nChild >> 31) == 0) {\n        CPubKey pubkey = GetPubKey();\n        assert(pubkey.begin() + 33 == pubkey.end());\n        BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());\n    } else {\n        assert(begin() + 32 == end());\n        BIP32Hash(cc, nChild, 0, begin(), vout.data());\n    }\n    memcpy(ccChild.begin(), vout.data()+32, 32);\n    memcpy((unsigned char*)keyChild.begin(), begin(), 32);\n    bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());\n    keyChild.fCompressed = true;\n    keyChild.fValid = ret;\n    return ret;\n}\n\nbool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {\n    out.nDepth = nDepth + 1;\n    CKeyID id = key.GetPubKey().GetID();\n    memcpy(&out.vchFingerprint[0], &id, 4);\n    out.nChild = _nChild;\n    return key.Derive(out.key, out.chaincode, _nChild, chaincode);\n}\n\nvoid CExtKey::SetMaster(const std::vector<unsigned char>& hashkey, const unsigned char *seed, unsigned int nSeedLen) {\n    std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);\n    CHMAC_SHA512(&hashkey[0], hashkey.size()).Write(seed, nSeedLen).Finalize(vout.data());\n    key.Set(&vout[0], &vout[32], true);\n    memcpy(chaincode.begin(), &vout[32], 32);\n    nDepth = 0;\n    nChild = 0;\n    memset(vchFingerprint, 0, sizeof(vchFingerprint));\n}\n\nCExtPubKey CExtKey::Neuter() const {\n    CExtPubKey ret;\n    ret.nDepth = nDepth;\n    memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4);\n    ret.nChild = nChild;\n    ret.pubkey = key.GetPubKey();\n    ret.chaincode = chaincode;\n    return ret;\n}\n\nvoid CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {\n    code[0] = nDepth;\n    memcpy(code+1, vchFingerprint, 4);\n    code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;\n    code[7] = (nChild >>  8) & 0xFF; code[8] = (nChild >>  0) & 0xFF;\n    memcpy(code+9, chaincode.begin(), 32);\n    code[41] = 0;\n    assert(key.size() == 32);\n    memcpy(code+42, key.begin(), 32);\n}\n\nvoid CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {\n    nDepth = code[0];\n    memcpy(vchFingerprint, code+1, 4);\n    nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];\n    memcpy(chaincode.begin(), code+9, 32);\n    key.Set(code+42, code+BIP32_EXTKEY_SIZE, true);\n}\n\nbool ECC_InitSanityCheck() {\n    CKey key;\n    key.MakeNewKey(true);\n    CPubKey pubkey = key.GetPubKey();\n    return key.VerifyPubKey(pubkey);\n}\n\nvoid ECC_Start() {\n    assert(secp256k1_context_sign == NULL);\n\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n    assert(ctx != NULL);\n\n    {\n        // Pass in a random blinding seed to the secp256k1 context.\n        std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);\n        GetRandBytes(vseed.data(), 32);\n        bool ret = secp256k1_context_randomize(ctx, vseed.data());\n        assert(ret);\n    }\n\n    secp256k1_context_sign = ctx;\n}\n\nvoid ECC_Stop() {\n    secp256k1_context *ctx = secp256k1_context_sign;\n    secp256k1_context_sign = NULL;\n\n    if (ctx) {\n        secp256k1_context_destroy(ctx);\n    }\n}\n"
  },
  {
    "path": "src/key.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_KEY_H\n#define CORE_KEY_H\n\n#include \"pubkey.h\"\n#include \"serialize.h\"\n#include \"support/allocators/secure.h\"\n#include \"uint256.h\"\n\n#include <stdexcept>\n#include <vector>\n\n\n/**\n * secp256k1:\n * const unsigned int PRIVATE_KEY_SIZE = 279;\n * const unsigned int PUBLIC_KEY_SIZE  = 65;\n * const unsigned int SIGNATURE_SIZE   = 72;\n *\n * see www.keylength.com\n * script supports up to 75 for single byte push\n */\n\n/**\n * secure_allocator is defined in allocators.h\n * CPrivKey is a serialized private key, with all parameters included (279 bytes)\n */\ntypedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;\n\n/** An encapsulated private key. */\nclass CKey\n{\nprivate:\n    //! Whether this private key is valid. We check for correctness when modifying the key\n    //! data, so fValid should always correspond to the actual state.\n    bool fValid;\n\n    //! Whether the public key corresponding to this private key is (to be) compressed.\n    bool fCompressed;\n\n    //! The actual byte data\n    std::vector<unsigned char, secure_allocator<unsigned char> > keydata;\n\n    //! Check whether the 32-byte array pointed to by vch is valid keydata.\n    bool static Check(const unsigned char* vch);\n\npublic:\n    //! Construct an invalid private key.\n    CKey() : fValid(false), fCompressed(false)\n    {\n        // Important: vch must be 32 bytes in length to not break serialization\n        keydata.resize(32);\n    }\n\n    //! Destructor (again necessary because of memlocking).\n    ~CKey()\n    {\n    }\n\n    friend bool operator==(const CKey& a, const CKey& b)\n    {\n        return a.fCompressed == b.fCompressed &&\n            a.size() == b.size() &&\n            memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0;\n    }\n\n    //! Initialize using begin and end iterators to byte data.\n    template <typename T>\n    void Set(const T pbegin, const T pend, bool fCompressedIn)\n    {\n        if (size_t(pend - pbegin) != keydata.size()) {\n            fValid = false;\n        } else if (Check(&pbegin[0])) {\n            memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size());\n            fValid = true;\n            fCompressed = fCompressedIn;\n        } else {\n            fValid = false;\n        }\n    }\n\n    bool SetPrivKey(const CPrivKey& privkey, bool fCompressedIn);\n\n    //! Simple read-only vector-like interface.\n    unsigned int size() const { return (fValid ? keydata.size() : 0); }\n    const unsigned char* begin() const { return keydata.data(); }\n    const unsigned char* end() const { return keydata.data() + size(); }\n\n    //! Check whether this private key is valid.\n    bool IsValid() const { return fValid; }\n\n    //! Check whether the public key corresponding to this private key is (to be) compressed.\n    bool IsCompressed() const { return fCompressed; }\n\n    //! Generate a new private key using a cryptographic PRNG.\n    void MakeNewKey(bool fCompressed);\n\n    /**\n     * Convert the private key to a CPrivKey (serialized OpenSSL private key data).\n     * This is expensive.\n     */\n    CPrivKey GetPrivKey() const;\n\n    /**\n     * Compute the public key from a private key.\n     * This is expensive.\n     */\n    CPubKey GetPubKey() const;\n\n    /**\n     * Create a DER-serialized signature.\n     * The test_case parameter tweaks the deterministic nonce.\n     */\n    bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, uint32_t test_case = 0) const;\n\n    /**\n     * Create a compact signature (65 bytes), which allows reconstructing the used public key.\n     * The format is one header byte, followed by two times 32 bytes for the serialized r and s values.\n     * The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,\n     *                  0x1D = second key with even y, 0x1E = second key with odd y,\n     *                  add 0x04 for compressed keys.\n     */\n    bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const;\n\n    //! Derive BIP32 child key.\n    bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;\n\n    /**\n     * Verify thoroughly whether a private key and a public key match.\n     * This is done using a different mechanism than just regenerating it.\n     */\n    bool VerifyPubKey(const CPubKey& vchPubKey) const;\n\n    //! Load private key and check that public key matches.\n    bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck=false);\n};\n\nstruct CExtKey {\n    unsigned char nDepth;\n    unsigned char vchFingerprint[4];\n    unsigned int nChild;\n    ChainCode chaincode;\n    CKey key;\n\n    const CKey& GetKey() const { return key; };\n    CKey& GetMutableKey() { return key; };\n\n    friend bool operator==(const CExtKey& a, const CExtKey& b)\n    {\n        return a.nDepth == b.nDepth &&\n            memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 &&\n            a.nChild == b.nChild &&\n            a.chaincode == b.chaincode &&\n            a.key == b.key;\n    }\n\n    void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;\n    void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);\n    bool Derive(CExtKey& out, unsigned int nChild) const;\n    CExtPubKey Neuter() const;\n    void SetMaster(const std::vector<unsigned char>& hashkey, const unsigned char* seed, unsigned int nSeedLen);\n    template <typename Stream>\n    void Serialize(Stream& s) const\n    {\n        unsigned int len = BIP32_EXTKEY_SIZE;\n        ::WriteCompactSize(s, len);\n        unsigned char code[BIP32_EXTKEY_SIZE];\n        Encode(code);\n        s.write((const char *)&code[0], len);\n    }\n    template <typename Stream>\n    void Unserialize(Stream& s)\n    {\n        unsigned int len = ::ReadCompactSize(s);\n        unsigned char code[BIP32_EXTKEY_SIZE];\n        s.read((char *)&code[0], len);\n        Decode(code);\n    }\n};\n\n/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */\nvoid ECC_Start(void);\n\n/** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */\nvoid ECC_Stop(void);\n\n/** Check that required EC support is available at runtime. */\nbool ECC_InitSanityCheck(void);\n\n#endif\n"
  },
  {
    "path": "src/keystore.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"keystore.h\"\n\n#include \"key.h\"\n#include \"pubkey.h\"\n#include \"util.h\"\n\nbool CKeyStore::AddKey(const CKey &key) {\n    return AddKeyPubKey(key, key.GetPubKey());\n}\n\nbool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const\n{\n    CKey key;\n    if (!GetKey(address, key)) {\n        LOCK(cs_KeyStore);\n        WatchKeyMap::const_iterator it = mapWatchKeys.find(address);\n        if (it != mapWatchKeys.end()) {\n            vchPubKeyOut = it->second;\n            return true;\n        }\n        return false;\n    }\n    vchPubKeyOut = key.GetPubKey();\n    return true;\n}\n\nbool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)\n{\n    LOCK(cs_KeyStore);\n    mapKeys[pubkey.GetID()] = key;\n    return true;\n}\n\nbool CBasicKeyStore::AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey)\n{\n    LOCK(cs_KeyStore);\n    mapHDKeys[pubkey.GetID()] = HDKeyIndex;\n    return true;\n}\n\nbool CBasicKeyStore::AddCScript(const CScript& redeemScript)\n{\n    if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)\n        return error(\"CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid\", MAX_SCRIPT_ELEMENT_SIZE);\n\n    LOCK(cs_KeyStore);\n    mapScripts[CScriptID(redeemScript)] = redeemScript;\n    return true;\n}\n\nbool CBasicKeyStore::HaveCScript(const CScriptID& hash) const\n{\n    LOCK(cs_KeyStore);\n    return mapScripts.count(hash) > 0;\n}\n\nbool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const\n{\n    LOCK(cs_KeyStore);\n    ScriptMap::const_iterator mi = mapScripts.find(hash);\n    if (mi != mapScripts.end())\n    {\n        redeemScriptOut = (*mi).second;\n        return true;\n    }\n    return false;\n}\n\nstatic bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)\n{\n    //TODO: Use Solver to extract this?\n    CScript::const_iterator pc = dest.begin();\n    opcodetype opcode;\n    std::vector<unsigned char> vch;\n    if (!dest.GetOp(pc, opcode, vch) || vch.size() < 33 || vch.size() > 65)\n        return false;\n    pubKeyOut = CPubKey(vch);\n    if (!pubKeyOut.IsFullyValid())\n        return false;\n    if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))\n        return false;\n    return true;\n}\n\nbool CBasicKeyStore::AddWatchOnly(const CScript &dest)\n{\n    LOCK(cs_KeyStore);\n    setWatchOnly.insert(dest);\n    CPubKey pubKey;\n    if (ExtractPubKey(dest, pubKey))\n        mapWatchKeys[pubKey.GetID()] = pubKey;\n    return true;\n}\n\nbool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)\n{\n    LOCK(cs_KeyStore);\n    setWatchOnly.erase(dest);\n    CPubKey pubKey;\n    if (ExtractPubKey(dest, pubKey))\n        mapWatchKeys.erase(pubKey.GetID());\n    return true;\n}\n\nbool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const\n{\n    LOCK(cs_KeyStore);\n    return setWatchOnly.count(dest) > 0;\n}\n\nbool CBasicKeyStore::HaveWatchOnly() const\n{\n    LOCK(cs_KeyStore);\n    return (!setWatchOnly.empty());\n}\n"
  },
  {
    "path": "src/keystore.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_KEYSTORE_H\n#define CORE_KEYSTORE_H\n\n#include \"key.h\"\n#include \"pubkey.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"sync.h\"\n\n#include \"util.h\"\n\n#include <boost/signals2/signal.hpp>\n\n//temp\n#include \"base58.h\"\n\n/** A virtual base class for key stores */\nclass CKeyStore\n{\nprotected:\n    mutable RecursiveMutex cs_KeyStore;\n\npublic:\n    virtual ~CKeyStore() {}\n\n    //! Add a key to the store.\n    virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;\n    virtual bool AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey) =0;\n    virtual bool AddKey(const CKey &key);\n\n    //! Check whether a key corresponding to a given address is present in the store.\n    virtual bool HaveKey(const CKeyID &address) const =0;\n    virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;\n    virtual bool GetKey(const CKeyID &address, int64_t& HDKeyIndex) const =0;\n    virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;\n    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const =0;\n\n    //! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki\n    virtual bool AddCScript(const CScript& redeemScript) =0;\n    virtual bool HaveCScript(const CScriptID &hash) const =0;\n    virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;\n\n    //! Support for Watch-only addresses\n    virtual bool AddWatchOnly(const CScript &dest) =0;\n    virtual bool RemoveWatchOnly(const CScript &dest) =0;\n    virtual bool HaveWatchOnly(const CScript &dest) const =0;\n    virtual bool HaveWatchOnly() const =0;\n};\n\ntypedef std::map<CKeyID, CKey> KeyMap;\ntypedef std::map<CKeyID, int64_t> KeyMapHD;\ntypedef std::map<CKeyID, CPubKey> WatchKeyMap;\ntypedef std::map<CScriptID, CScript > ScriptMap;\ntypedef std::set<CScript> WatchOnlySet;\n\n/** Basic key store, that keeps keys in an address->secret map */\nclass CBasicKeyStore : public CKeyStore\n{\nprotected:\n    KeyMap mapKeys;\n    KeyMapHD mapHDKeys;\n    WatchKeyMap mapWatchKeys;\n    ScriptMap mapScripts;\n    WatchOnlySet setWatchOnly;\n\npublic:\n    bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);\n    bool AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey);\n    bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;\n    bool HaveKey(const CKeyID &address) const\n    {\n        bool result=false;\n        {\n            LOCK(cs_KeyStore);\n            result = (mapKeys.count(address) > 0);\n        }\n        if (!result)\n        {\n            LOCK(cs_KeyStore);\n            result = (mapHDKeys.count(address) > 0);\n        }\n\n        return result;\n    }\n    void GetKeys(std::set<CKeyID> &setAddress) const\n    {\n        setAddress.clear();\n        {\n            LOCK(cs_KeyStore);\n            KeyMap::const_iterator mi = mapKeys.begin();\n            while (mi != mapKeys.end())\n            {\n                setAddress.insert((*mi).first);\n                mi++;\n            }\n            KeyMapHD::const_iterator mi2 = mapHDKeys.begin();\n            while (mi2 != mapHDKeys.end())\n            {\n                setAddress.insert((*mi2).first);\n                mi2++;\n            }\n        }\n    }\n    bool GetKey(const CKeyID &address, CKey &keyOut) const\n    {\n        {\n            LOCK(cs_KeyStore);\n            KeyMap::const_iterator mi = mapKeys.find(address);\n            if (mi != mapKeys.end())\n            {\n                keyOut = mi->second;\n                return true;\n            }\n        }\n        return false;\n    }\n    bool GetKey(const CKeyID &address, int64_t& HDKeyIndex) const\n    {\n        {\n            LOCK(cs_KeyStore);\n            KeyMapHD::const_iterator mi = mapHDKeys.find(address);\n            if (mi != mapHDKeys.end())\n            {\n                HDKeyIndex = mi->second;\n                return true;\n            }\n        }\n        return false;\n    }\n    bool GetKeyIDWithHighestIndex(CKeyID& HDKeyID) const\n    {\n        int64_t highestIndex=0;\n        {\n            LOCK(cs_KeyStore);\n            if (mapHDKeys.empty())\n                return false;\n            for (const auto& [keyID, keyIndex] : mapHDKeys)\n            {\n                if (keyIndex >= highestIndex)\n                {\n                    highestIndex = keyIndex;\n                    HDKeyID = keyID;\n                }\n            }\n        }\n        return true;\n    }\n    virtual bool AddCScript(const CScript& redeemScript);\n    virtual bool HaveCScript(const CScriptID &hash) const;\n    virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;\n\n    virtual bool AddWatchOnly(const CScript &dest);\n    virtual bool RemoveWatchOnly(const CScript &dest);\n    virtual bool HaveWatchOnly(const CScript &dest) const;\n    virtual bool HaveWatchOnly() const;\n};\n\ntypedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;\ntypedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;\n\n#endif\n"
  },
  {
    "path": "src/leveldb/.appveyor.yml",
    "content": "# Build matrix / environment variables are explained on:\n# https://www.appveyor.com/docs/appveyor-yml/\n# This file can be validated on: https://ci.appveyor.com/tools/validate-yaml\n\nversion: \"{build}\"\n\nenvironment:\n  matrix:\n    # AppVeyor currently has no custom job name feature.\n    # http://help.appveyor.com/discussions/questions/1623-can-i-provide-a-friendly-name-for-jobs\n    - JOB: Visual Studio 2017\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      CMAKE_GENERATOR: Visual Studio 15 2017\n\nplatform:\n  - x86\n  - x64\n\nconfiguration:\n  - RelWithDebInfo\n  - Debug\n\nbuild_script:\n  - git submodule update --init --recursive\n  - mkdir build\n  - cd build\n  - if \"%platform%\"==\"x64\" set CMAKE_GENERATOR=%CMAKE_GENERATOR% Win64\n  - cmake --version\n  - cmake .. -G \"%CMAKE_GENERATOR%\"\n      -DCMAKE_CONFIGURATION_TYPES=\"%CONFIGURATION%\"\n  - cmake --build . --config \"%CONFIGURATION%\"\n  - cd ..\n\ntest_script:\n  - cd build && ctest --verbose --build-config \"%CONFIGURATION%\" && cd ..\n"
  },
  {
    "path": "src/leveldb/.clang-format",
    "content": "# Run manually to reformat a file:\n# clang-format -i --style=file <file>\n# find . -iname '*.cc' -o -iname '*.h' -o -iname '*.h.in' | xargs clang-format -i --style=file\nBasedOnStyle: Google\nDerivePointerAlignment: false\n\n# Public headers are in a different location in the internal Google repository.\n# Order them so that when imported to the authoritative repository they will be\n# in correct alphabetical order.\nIncludeCategories:\n  - Regex:           '^(<|\"(benchmarks|db|helpers)/)'\n    Priority:        1\n  - Regex:           '^\"(leveldb)/'\n    Priority:        2\n  - Regex:           '^(<|\"(issues|port|table|third_party|util)/)'\n    Priority:        3\n  - Regex:           '.*'\n    Priority:        4\n"
  },
  {
    "path": "src/leveldb/.gitignore",
    "content": "# Editors.\n*.sw*\n.vscode\n.DS_Store\n\n# Build directory.\nbuild/\nout/\n"
  },
  {
    "path": "src/leveldb/.travis.yml",
    "content": "# Build matrix / environment variables are explained on:\n# http://about.travis-ci.org/docs/user/build-configuration/\n# This file can be validated on: http://lint.travis-ci.org/\n\nlanguage: cpp\ndist: bionic\nosx_image: xcode10.3\n\ncompiler:\n- gcc\n- clang\nos:\n- linux\n- osx\n\nenv:\n- BUILD_TYPE=Debug\n- BUILD_TYPE=RelWithDebInfo\n\naddons:\n  apt:\n    sources:\n    - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'\n      key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'\n    - sourceline: 'ppa:ubuntu-toolchain-r/test'\n    packages:\n    - clang-9\n    - cmake\n    - gcc-9\n    - g++-9\n    - libgoogle-perftools-dev\n    - libkyotocabinet-dev\n    - libsnappy-dev\n    - libsqlite3-dev\n    - ninja-build\n  homebrew:\n    packages:\n    - cmake\n    - crc32c\n    - gcc@9\n    - gperftools\n    - kyoto-cabinet\n    - llvm@9\n    - ninja\n    - snappy\n    - sqlite3\n    update: true\n\ninstall:\n# The following Homebrew packages aren't linked by default, and need to be\n# prepended to the path explicitly.\n- if [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then\n    export PATH=\"$(brew --prefix llvm)/bin:$PATH\";\n  fi\n# /usr/bin/gcc points to an older compiler on both Linux and macOS.\n- if [ \"$CXX\" = \"g++\" ]; then export CXX=\"g++-9\" CC=\"gcc-9\"; fi\n# /usr/bin/clang points to an older compiler on both Linux and macOS.\n#\n# Homebrew's llvm package doesn't ship a versioned clang++ binary, so the values\n# below don't work on macOS. Fortunately, the path change above makes the\n# default values (clang and clang++) resolve to the correct compiler on macOS.\n- if [ \"$TRAVIS_OS_NAME\" = \"linux\" ]; then\n    if [ \"$CXX\" = \"clang++\" ]; then export CXX=\"clang++-9\" CC=\"clang-9\"; fi;\n  fi\n- echo ${CC}\n- echo ${CXX}\n- ${CXX} --version\n- cmake --version\n\nbefore_script:\n- mkdir -p build && cd build\n- cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE\n    -DCMAKE_INSTALL_PREFIX=$HOME/.local\n- cmake --build .\n- cd ..\n\nscript:\n- cd build && ctest --verbose && cd ..\n- \"if [ -f build/db_bench ] ; then build/db_bench ; fi\"\n- \"if [ -f build/db_bench_sqlite3 ] ; then build/db_bench_sqlite3 ; fi\"\n- \"if [ -f build/db_bench_tree_db ] ; then build/db_bench_tree_db ; fi\"\n- cd build && cmake --build . --target install\n"
  },
  {
    "path": "src/leveldb/AUTHORS",
    "content": "# Names should be added to this file like so:\n# Name or Organization <email address>\n\nGoogle Inc.\n\n# Initial version authors:\nJeffrey Dean <jeff@google.com>\nSanjay Ghemawat <sanjay@google.com>\n\n# Partial list of contributors:\nKevin Regan <kevin.d.regan@gmail.com>\nJohan Bilien <jobi@litl.com>\n"
  },
  {
    "path": "src/leveldb/CMakeLists.txt",
    "content": "# Copyright 2017 The LevelDB Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license that can be\n# found in the LICENSE file. See the AUTHORS file for names of contributors.\n\ncmake_minimum_required(VERSION 3.9)\n# Keep the version below in sync with the one in db.h\nproject(leveldb VERSION 1.22.0 LANGUAGES C CXX)\n\n# This project can use C11, but will gracefully decay down to C89.\nset(CMAKE_C_STANDARD 11)\nset(CMAKE_C_STANDARD_REQUIRED OFF)\nset(CMAKE_C_EXTENSIONS OFF)\n\n# This project requires C++11.\nset(CMAKE_CXX_STANDARD 11)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nif (WIN32)\n  set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_WINDOWS)\n  # TODO(cmumford): Make UNICODE configurable for Windows.\n  add_definitions(-D_UNICODE -DUNICODE)\nelse (WIN32)\n  set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_POSIX)\nendif (WIN32)\n\noption(LEVELDB_BUILD_TESTS \"Build LevelDB's unit tests\" ON)\noption(LEVELDB_BUILD_BENCHMARKS \"Build LevelDB's benchmarks\" ON)\noption(LEVELDB_INSTALL \"Install LevelDB's header and library\" ON)\n\ninclude(TestBigEndian)\ntest_big_endian(LEVELDB_IS_BIG_ENDIAN)\n\ninclude(CheckIncludeFile)\ncheck_include_file(\"unistd.h\" HAVE_UNISTD_H)\n\ninclude(CheckLibraryExists)\ncheck_library_exists(crc32c crc32c_value \"\" HAVE_CRC32C)\ncheck_library_exists(snappy snappy_compress \"\" HAVE_SNAPPY)\ncheck_library_exists(tcmalloc malloc \"\" HAVE_TCMALLOC)\n\ninclude(CheckCXXSymbolExists)\n# Using check_cxx_symbol_exists() instead of check_c_symbol_exists() because\n# we're including the header from C++, and feature detection should use the same\n# compiler language that the project will use later. Principles aside, some\n# versions of do not expose fdatasync() in <unistd.h> in standard C mode\n# (-std=c11), but do expose the function in standard C++ mode (-std=c++11).\ncheck_cxx_symbol_exists(fdatasync \"unistd.h\" HAVE_FDATASYNC)\ncheck_cxx_symbol_exists(F_FULLFSYNC \"fcntl.h\" HAVE_FULLFSYNC)\ncheck_cxx_symbol_exists(O_CLOEXEC \"fcntl.h\" HAVE_O_CLOEXEC)\n\nif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  # Disable C++ exceptions.\n  string(REGEX REPLACE \"/EH[a-z]+\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /EHs-c-\")\n  add_definitions(-D_HAS_EXCEPTIONS=0)\n\n  # Disable RTTI.\n  string(REGEX REPLACE \"/GR\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /GR-\")\nelse(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  # Enable strict prototype warnings for C code in clang and gcc.\n  if(NOT CMAKE_C_FLAGS MATCHES \"-Wstrict-prototypes\")\n    set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wstrict-prototypes\")\n  endif(NOT CMAKE_C_FLAGS MATCHES \"-Wstrict-prototypes\")\n\n  # Disable C++ exceptions.\n  string(REGEX REPLACE \"-fexceptions\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-exceptions\")\n\n  # Disable RTTI.\n  string(REGEX REPLACE \"-frtti\" \"\" CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-rtti\")\nendif(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\n# Test whether -Wthread-safety is available. See\n# https://clang.llvm.org/docs/ThreadSafetyAnalysis.html\ninclude(CheckCXXCompilerFlag)\ncheck_cxx_compiler_flag(-Wthread-safety HAVE_CLANG_THREAD_SAFETY)\n\ninclude(CheckCXXSourceCompiles)\n\n# Test whether C++17 __has_include is available.\ncheck_cxx_source_compiles(\"\n#if defined(__has_include) &&  __has_include(<string>)\n#include <string>\n#endif\nint main() { std::string str; return 0; }\n\" HAVE_CXX17_HAS_INCLUDE)\n\nset(LEVELDB_PUBLIC_INCLUDE_DIR \"include/leveldb\")\nset(LEVELDB_PORT_CONFIG_DIR \"include/port\")\n\nconfigure_file(\n  \"port/port_config.h.in\"\n  \"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h\"\n)\n\ninclude_directories(\n  \"${PROJECT_BINARY_DIR}/include\"\n  \".\"\n)\n\nif(BUILD_SHARED_LIBS)\n  # Only export LEVELDB_EXPORT symbols from the shared library.\n  add_compile_options(-fvisibility=hidden)\nendif(BUILD_SHARED_LIBS)\n\n# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.\ninclude(GNUInstallDirs)\n\nadd_library(leveldb \"\")\ntarget_sources(leveldb\n  PRIVATE\n    \"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h\"\n    \"db/builder.cc\"\n    \"db/builder.h\"\n    \"db/c.cc\"\n    \"db/db_impl.cc\"\n    \"db/db_impl.h\"\n    \"db/db_iter.cc\"\n    \"db/db_iter.h\"\n    \"db/dbformat.cc\"\n    \"db/dbformat.h\"\n    \"db/dumpfile.cc\"\n    \"db/filename.cc\"\n    \"db/filename.h\"\n    \"db/log_format.h\"\n    \"db/log_reader.cc\"\n    \"db/log_reader.h\"\n    \"db/log_writer.cc\"\n    \"db/log_writer.h\"\n    \"db/memtable.cc\"\n    \"db/memtable.h\"\n    \"db/repair.cc\"\n    \"db/skiplist.h\"\n    \"db/snapshot.h\"\n    \"db/table_cache.cc\"\n    \"db/table_cache.h\"\n    \"db/version_edit.cc\"\n    \"db/version_edit.h\"\n    \"db/version_set.cc\"\n    \"db/version_set.h\"\n    \"db/write_batch_internal.h\"\n    \"db/write_batch.cc\"\n    \"port/port_stdcxx.h\"\n    \"port/port.h\"\n    \"port/thread_annotations.h\"\n    \"table/block_builder.cc\"\n    \"table/block_builder.h\"\n    \"table/block.cc\"\n    \"table/block.h\"\n    \"table/filter_block.cc\"\n    \"table/filter_block.h\"\n    \"table/format.cc\"\n    \"table/format.h\"\n    \"table/iterator_wrapper.h\"\n    \"table/iterator.cc\"\n    \"table/merger.cc\"\n    \"table/merger.h\"\n    \"table/table_builder.cc\"\n    \"table/table.cc\"\n    \"table/two_level_iterator.cc\"\n    \"table/two_level_iterator.h\"\n    \"util/arena.cc\"\n    \"util/arena.h\"\n    \"util/bloom.cc\"\n    \"util/cache.cc\"\n    \"util/coding.cc\"\n    \"util/coding.h\"\n    \"util/comparator.cc\"\n    \"util/crc32c.cc\"\n    \"util/crc32c.h\"\n    \"util/env.cc\"\n    \"util/filter_policy.cc\"\n    \"util/hash.cc\"\n    \"util/hash.h\"\n    \"util/logging.cc\"\n    \"util/logging.h\"\n    \"util/mutexlock.h\"\n    \"util/no_destructor.h\"\n    \"util/options.cc\"\n    \"util/random.h\"\n    \"util/status.cc\"\n\n  # Only CMake 3.3+ supports PUBLIC sources in targets exported by \"install\".\n  $<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC>\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h\"\n    \"${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h\"\n)\n\nif (WIN32)\n  target_sources(leveldb\n    PRIVATE\n      \"util/env_windows.cc\"\n      \"util/windows_logger.h\"\n  )\nelse (WIN32)\n  target_sources(leveldb\n    PRIVATE\n      \"util/env_posix.cc\"\n      \"util/posix_logger.h\"\n  )\nendif (WIN32)\n\n# MemEnv is not part of the interface and could be pulled to a separate library.\ntarget_sources(leveldb\n  PRIVATE\n    \"helpers/memenv/memenv.cc\"\n    \"helpers/memenv/memenv.h\"\n)\n\ntarget_include_directories(leveldb\n  PUBLIC\n    $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n)\n\nset_target_properties(leveldb\n  PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})\n\ntarget_compile_definitions(leveldb\n  PRIVATE\n    # Used by include/export.h when building shared libraries.\n    LEVELDB_COMPILE_LIBRARY\n    # Used by port/port.h.\n    ${LEVELDB_PLATFORM_NAME}=1\n)\nif (NOT HAVE_CXX17_HAS_INCLUDE)\n  target_compile_definitions(leveldb\n    PRIVATE\n      LEVELDB_HAS_PORT_CONFIG_H=1\n  )\nendif(NOT HAVE_CXX17_HAS_INCLUDE)\n\nif(BUILD_SHARED_LIBS)\n  target_compile_definitions(leveldb\n    PUBLIC\n      # Used by include/export.h.\n      LEVELDB_SHARED_LIBRARY\n  )\nendif(BUILD_SHARED_LIBS)\n\nif(HAVE_CLANG_THREAD_SAFETY)\n  target_compile_options(leveldb\n    PUBLIC\n      -Werror -Wthread-safety)\nendif(HAVE_CLANG_THREAD_SAFETY)\n\nif(HAVE_CRC32C)\n  target_link_libraries(leveldb crc32c)\nendif(HAVE_CRC32C)\nif(HAVE_SNAPPY)\n  target_link_libraries(leveldb snappy)\nendif(HAVE_SNAPPY)\nif(HAVE_TCMALLOC)\n  target_link_libraries(leveldb tcmalloc)\nendif(HAVE_TCMALLOC)\n\n# Needed by port_stdcxx.h\nfind_package(Threads REQUIRED)\ntarget_link_libraries(leveldb Threads::Threads)\n\nadd_executable(leveldbutil\n  \"db/leveldbutil.cc\"\n)\ntarget_link_libraries(leveldbutil leveldb)\n\nif(LEVELDB_BUILD_TESTS)\n  enable_testing()\n\n  function(leveldb_test test_file)\n    get_filename_component(test_target_name \"${test_file}\" NAME_WE)\n\n    add_executable(\"${test_target_name}\" \"\")\n    target_sources(\"${test_target_name}\"\n      PRIVATE\n        \"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h\"\n        \"util/testharness.cc\"\n        \"util/testharness.h\"\n        \"util/testutil.cc\"\n        \"util/testutil.h\"\n\n        \"${test_file}\"\n    )\n    target_link_libraries(\"${test_target_name}\" leveldb)\n    target_compile_definitions(\"${test_target_name}\"\n      PRIVATE\n        ${LEVELDB_PLATFORM_NAME}=1\n    )\n    if (NOT HAVE_CXX17_HAS_INCLUDE)\n      target_compile_definitions(\"${test_target_name}\"\n        PRIVATE\n          LEVELDB_HAS_PORT_CONFIG_H=1\n      )\n    endif(NOT HAVE_CXX17_HAS_INCLUDE)\n\n    add_test(NAME \"${test_target_name}\" COMMAND \"${test_target_name}\")\n  endfunction(leveldb_test)\n\n  leveldb_test(\"db/c_test.c\")\n  leveldb_test(\"db/fault_injection_test.cc\")\n\n  leveldb_test(\"issues/issue178_test.cc\")\n  leveldb_test(\"issues/issue200_test.cc\")\n  leveldb_test(\"issues/issue320_test.cc\")\n\n  leveldb_test(\"util/env_test.cc\")\n  leveldb_test(\"util/status_test.cc\")\n  leveldb_test(\"util/no_destructor_test.cc\")\n\n  if(NOT BUILD_SHARED_LIBS)\n    leveldb_test(\"db/autocompact_test.cc\")\n    leveldb_test(\"db/corruption_test.cc\")\n    leveldb_test(\"db/db_test.cc\")\n    leveldb_test(\"db/dbformat_test.cc\")\n    leveldb_test(\"db/filename_test.cc\")\n    leveldb_test(\"db/log_test.cc\")\n    leveldb_test(\"db/recovery_test.cc\")\n    leveldb_test(\"db/skiplist_test.cc\")\n    leveldb_test(\"db/version_edit_test.cc\")\n    leveldb_test(\"db/version_set_test.cc\")\n    leveldb_test(\"db/write_batch_test.cc\")\n\n    leveldb_test(\"helpers/memenv/memenv_test.cc\")\n\n    leveldb_test(\"table/filter_block_test.cc\")\n    leveldb_test(\"table/table_test.cc\")\n\n    leveldb_test(\"util/arena_test.cc\")\n    leveldb_test(\"util/bloom_test.cc\")\n    leveldb_test(\"util/cache_test.cc\")\n    leveldb_test(\"util/coding_test.cc\")\n    leveldb_test(\"util/crc32c_test.cc\")\n    leveldb_test(\"util/hash_test.cc\")\n    leveldb_test(\"util/logging_test.cc\")\n\n    # TODO(costan): This test also uses\n    #               \"util/env_{posix|windows}_test_helper.h\"\n    if (WIN32)\n      leveldb_test(\"util/env_windows_test.cc\")\n    else (WIN32)\n      leveldb_test(\"util/env_posix_test.cc\")\n    endif (WIN32)\n  endif(NOT BUILD_SHARED_LIBS)\nendif(LEVELDB_BUILD_TESTS)\n\nif(LEVELDB_BUILD_BENCHMARKS)\n  function(leveldb_benchmark bench_file)\n    get_filename_component(bench_target_name \"${bench_file}\" NAME_WE)\n\n    add_executable(\"${bench_target_name}\" \"\")\n    target_sources(\"${bench_target_name}\"\n      PRIVATE\n        \"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h\"\n        \"util/histogram.cc\"\n        \"util/histogram.h\"\n        \"util/testharness.cc\"\n        \"util/testharness.h\"\n        \"util/testutil.cc\"\n        \"util/testutil.h\"\n\n        \"${bench_file}\"\n    )\n    target_link_libraries(\"${bench_target_name}\" leveldb)\n    target_compile_definitions(\"${bench_target_name}\"\n      PRIVATE\n        ${LEVELDB_PLATFORM_NAME}=1\n    )\n    if (NOT HAVE_CXX17_HAS_INCLUDE)\n      target_compile_definitions(\"${bench_target_name}\"\n        PRIVATE\n          LEVELDB_HAS_PORT_CONFIG_H=1\n      )\n    endif(NOT HAVE_CXX17_HAS_INCLUDE)\n  endfunction(leveldb_benchmark)\n\n  if(NOT BUILD_SHARED_LIBS)\n    leveldb_benchmark(\"benchmarks/db_bench.cc\")\n  endif(NOT BUILD_SHARED_LIBS)\n\n  check_library_exists(sqlite3 sqlite3_open \"\" HAVE_SQLITE3)\n  if(HAVE_SQLITE3)\n    leveldb_benchmark(\"benchmarks/db_bench_sqlite3.cc\")\n    target_link_libraries(db_bench_sqlite3 sqlite3)\n  endif(HAVE_SQLITE3)\n\n  # check_library_exists is insufficient here because the library names have\n  # different manglings when compiled with clang or gcc, at least when installed\n  # with Homebrew on Mac.\n  set(OLD_CMAKE_REQURED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})\n  list(APPEND CMAKE_REQUIRED_LIBRARIES kyotocabinet)\n  check_cxx_source_compiles(\"\n#include <kcpolydb.h>\n\nint main() {\n  kyotocabinet::TreeDB* db = new kyotocabinet::TreeDB();\n  delete db;\n  return 0;\n}\n  \"  HAVE_KYOTOCABINET)\n  set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQURED_LIBRARIES})\n  if(HAVE_KYOTOCABINET)\n    leveldb_benchmark(\"benchmarks/db_bench_tree_db.cc\")\n    target_link_libraries(db_bench_tree_db kyotocabinet)\n  endif(HAVE_KYOTOCABINET)\nendif(LEVELDB_BUILD_BENCHMARKS)\n\nif(LEVELDB_INSTALL)\n  install(TARGETS leveldb\n    EXPORT leveldbTargets\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n  )\n  install(\n    FILES\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h\"\n      \"${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h\"\n    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/leveldb\n  )\n\n  include(CMakePackageConfigHelpers)\n  write_basic_package_version_file(\n      \"${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake\"\n      COMPATIBILITY SameMajorVersion\n  )\n  install(\n    EXPORT leveldbTargets\n    NAMESPACE leveldb::\n    DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/leveldb\"\n  )\n  install(\n    FILES\n      \"cmake/leveldbConfig.cmake\"\n      \"${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake\"\n    DESTINATION \"${CMAKE_INSTALL_LIBDIR}/cmake/leveldb\"\n  )\nendif(LEVELDB_INSTALL)\n"
  },
  {
    "path": "src/leveldb/CONTRIBUTING.md",
    "content": "# Contributing\n\nWe'd love to accept your code patches! However, before we can take them, we\nhave to jump a couple of legal hurdles.\n\n## Contributor License Agreements\n\nPlease fill out either the individual or corporate Contributor License\nAgreement as appropriate.\n\n* If you are an individual writing original source code and you're sure you\nown the intellectual property, then sign an [individual CLA](https://developers.google.com/open-source/cla/individual).\n* If you work for a company that wants to allow you to contribute your work,\nthen sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate).\n\nFollow either of the two links above to access the appropriate CLA and\ninstructions for how to sign and return it.\n\n## Submitting a Patch\n\n1. Sign the contributors license agreement above.\n2. Decide which code you want to submit. A submission should be a set of changes\nthat addresses one issue in the [issue tracker](https://github.com/google/leveldb/issues).\nPlease don't mix more than one logical change per submission, because it makes\nthe history hard to follow. If you want to make a change\n(e.g. add a sample or feature) that doesn't have a corresponding issue in the\nissue tracker, please create one.\n3. **Submitting**: When you are ready to submit, send us a Pull Request. Be\nsure to include the issue number you fixed and the name you used to sign\nthe CLA.\n\n## Writing Code ##\n\nIf your contribution contains code, please make sure that it follows\n[the style guide](http://google.github.io/styleguide/cppguide.html).\nOtherwise we will have to ask you to make changes, and that's no fun for anyone.\n"
  },
  {
    "path": "src/leveldb/LICENSE",
    "content": "Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "src/leveldb/NEWS",
    "content": "Release 1.2 2011-05-16\n----------------------\n\nFixes for larger databases (tested up to one billion 100-byte entries,\ni.e., ~100GB).\n\n(1) Place hard limit on number of level-0 files.  This fixes errors\nof the form \"too many open files\".\n\n(2) Fixed memtable management.  Before the fix, a heavy write burst\ncould cause unbounded memory usage.\n\nA fix for a logging bug where the reader would incorrectly complain\nabout corruption.\n\nAllow public access to WriteBatch contents so that users can easily\nwrap a DB.\n"
  },
  {
    "path": "src/leveldb/README.md",
    "content": "**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.**\n\n[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb)\n[![Build status](https://ci.appveyor.com/api/projects/status/g2j5j4rfkda6eyw5/branch/master?svg=true)](https://ci.appveyor.com/project/pwnall/leveldb)\n\nAuthors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)\n\n# Features\n\n  * Keys and values are arbitrary byte arrays.\n  * Data is stored sorted by key.\n  * Callers can provide a custom comparison function to override the sort order.\n  * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`.\n  * Multiple changes can be made in one atomic batch.\n  * Users can create a transient snapshot to get a consistent view of data.\n  * Forward and backward iteration is supported over the data.\n  * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/).\n  * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.\n\n# Documentation\n\n  [LevelDB library documentation](https://github.com/google/leveldb/blob/master/doc/index.md) is online and bundled with the source code.\n\n# Limitations\n\n  * This is not a SQL database.  It does not have a relational data model, it does not support SQL queries, and it has no support for indexes.\n  * Only a single process (possibly multi-threaded) can access a particular database at a time.\n  * There is no client-server support builtin to the library.  An application that needs such support will have to wrap their own server around the library.\n\n# Building\n\nThis project supports [CMake](https://cmake.org/) out of the box.\n\n### Build for POSIX\n\nQuick start:\n\n```bash\nmkdir -p build && cd build\ncmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .\n```\n\n### Building for Windows\n\nFirst generate the Visual Studio 2017 project/solution files:\n\n```cmd\nmkdir build\ncd build\ncmake -G \"Visual Studio 15\" ..\n```\nThe default default will build for x86. For 64-bit run:\n\n```cmd\ncmake -G \"Visual Studio 15 Win64\" ..\n```\n\nTo compile the Windows solution from the command-line:\n\n```cmd\ndevenv /build Debug leveldb.sln\n```\n\nor open leveldb.sln in Visual Studio and build from within.\n\nPlease see the CMake documentation and `CMakeLists.txt` for more advanced usage.\n\n# Contributing to the leveldb Project\n\nThe leveldb project welcomes contributions. leveldb's primary goal is to be\na reliable and fast key/value store. Changes that are in line with the\nfeatures/limitations outlined above, and meet the requirements below,\nwill be considered.\n\nContribution requirements:\n\n1. **Tested platforms only**. We _generally_ will only accept changes for\n   platforms that are compiled and tested. This means POSIX (for Linux and\n   macOS) or Windows. Very small changes will sometimes be accepted, but\n   consider that more of an exception than the rule.\n\n2. **Stable API**. We strive very hard to maintain a stable API. Changes that\n   require changes for projects using leveldb _might_ be rejected without\n   sufficient benefit to the project.\n\n3. **Tests**: All changes must be accompanied by a new (or changed) test, or\n   a sufficient explanation as to why a new (or changed) test is not required.\n\n4. **Consistent Style**: This project conforms to the\n   [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).\n   To ensure your changes are properly formatted please run:\n\n   ```\n   clang-format -i --style=file <file>\n   ```\n\n## Submitting a Pull Request\n\nBefore any pull request will be accepted the author must first sign a\nContributor License Agreement (CLA) at https://cla.developers.google.com/.\n\nIn order to keep the commit timeline linear\n[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits)\nyour changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase)\non google/leveldb/master. This keeps the commit timeline linear and more easily sync'ed\nwith the internal repository at Google. More information at GitHub's\n[About Git rebase](https://help.github.com/articles/about-git-rebase/) page.\n\n# Performance\n\nHere is a performance report (with explanations) from the run of the\nincluded db_bench program.  The results are somewhat noisy, but should\nbe enough to get a ballpark performance estimate.\n\n## Setup\n\nWe use a database with a million entries.  Each entry has a 16 byte\nkey, and a 100 byte value.  Values used by the benchmark compress to\nabout half their original size.\n\n    LevelDB:    version 1.1\n    Date:       Sun May  1 12:11:26 2011\n    CPU:        4 x Intel(R) Core(TM)2 Quad CPU    Q6600  @ 2.40GHz\n    CPUCache:   4096 KB\n    Keys:       16 bytes each\n    Values:     100 bytes each (50 bytes after compression)\n    Entries:    1000000\n    Raw Size:   110.6 MB (estimated)\n    File Size:  62.9 MB (estimated)\n\n## Write performance\n\nThe \"fill\" benchmarks create a brand new database, in either\nsequential, or random order.  The \"fillsync\" benchmark flushes data\nfrom the operating system to the disk after every operation; the other\nwrite operations leave the data sitting in the operating system buffer\ncache for a while.  The \"overwrite\" benchmark does random writes that\nupdate existing keys in the database.\n\n    fillseq      :       1.765 micros/op;   62.7 MB/s\n    fillsync     :     268.409 micros/op;    0.4 MB/s (10000 ops)\n    fillrandom   :       2.460 micros/op;   45.0 MB/s\n    overwrite    :       2.380 micros/op;   46.5 MB/s\n\nEach \"op\" above corresponds to a write of a single key/value pair.\nI.e., a random write benchmark goes at approximately 400,000 writes per second.\n\nEach \"fillsync\" operation costs much less (0.3 millisecond)\nthan a disk seek (typically 10 milliseconds).  We suspect that this is\nbecause the hard disk itself is buffering the update in its memory and\nresponding before the data has been written to the platter.  This may\nor may not be safe based on whether or not the hard disk has enough\npower to save its memory in the event of a power failure.\n\n## Read performance\n\nWe list the performance of reading sequentially in both the forward\nand reverse direction, and also the performance of a random lookup.\nNote that the database created by the benchmark is quite small.\nTherefore the report characterizes the performance of leveldb when the\nworking set fits in memory.  The cost of reading a piece of data that\nis not present in the operating system buffer cache will be dominated\nby the one or two disk seeks needed to fetch the data from disk.\nWrite performance will be mostly unaffected by whether or not the\nworking set fits in memory.\n\n    readrandom  : 16.677 micros/op;  (approximately 60,000 reads per second)\n    readseq     :  0.476 micros/op;  232.3 MB/s\n    readreverse :  0.724 micros/op;  152.9 MB/s\n\nLevelDB compacts its underlying storage data in the background to\nimprove read performance.  The results listed above were done\nimmediately after a lot of random writes.  The results after\ncompactions (which are usually triggered automatically) are better.\n\n    readrandom  : 11.602 micros/op;  (approximately 85,000 reads per second)\n    readseq     :  0.423 micros/op;  261.8 MB/s\n    readreverse :  0.663 micros/op;  166.9 MB/s\n\nSome of the high cost of reads comes from repeated decompression of blocks\nread from disk.  If we supply enough cache to the leveldb so it can hold the\nuncompressed blocks in memory, the read performance improves again:\n\n    readrandom  : 9.775 micros/op;  (approximately 100,000 reads per second before compaction)\n    readrandom  : 5.215 micros/op;  (approximately 190,000 reads per second after compaction)\n\n## Repository contents\n\nSee [doc/index.md](doc/index.md) for more explanation. See\n[doc/impl.md](doc/impl.md) for a brief overview of the implementation.\n\nThe public interface is in include/leveldb/*.h.  Callers should not include or\nrely on the details of any other header files in this package.  Those\ninternal APIs may be changed without warning.\n\nGuide to header files:\n\n* **include/leveldb/db.h**: Main interface to the DB: Start here.\n\n* **include/leveldb/options.h**: Control over the behavior of an entire database,\nand also control over the behavior of individual reads and writes.\n\n* **include/leveldb/comparator.h**: Abstraction for user-specified comparison function.\nIf you want just bytewise comparison of keys, you can use the default\ncomparator, but clients can write their own comparator implementations if they\nwant custom ordering (e.g. to handle different character encodings, etc.).\n\n* **include/leveldb/iterator.h**: Interface for iterating over data. You can get\nan iterator from a DB object.\n\n* **include/leveldb/write_batch.h**: Interface for atomically applying multiple\nupdates to a database.\n\n* **include/leveldb/slice.h**: A simple module for maintaining a pointer and a\nlength into some other byte array.\n\n* **include/leveldb/status.h**: Status is returned from many of the public interfaces\nand is used to report success and various kinds of errors.\n\n* **include/leveldb/env.h**:\nAbstraction of the OS environment.  A posix implementation of this interface is\nin util/env_posix.cc.\n\n* **include/leveldb/table.h, include/leveldb/table_builder.h**: Lower-level modules that most\nclients probably won't use directly.\n"
  },
  {
    "path": "src/leveldb/TODO",
    "content": "ss\n- Stats\n\ndb\n- Maybe implement DB::BulkDeleteForRange(start_key, end_key)\n  that would blow away files whose ranges are entirely contained\n  within [start_key..end_key]?  For Chrome, deletion of obsolete\n  object stores, etc. can be done in the background anyway, so\n  probably not that important.\n- There have been requests for MultiGet.\n\nAfter a range is completely deleted, what gets rid of the\ncorresponding files if we do no future changes to that range.  Make\nthe conditions for triggering compactions fire in more situations?\n"
  },
  {
    "path": "src/leveldb/benchmarks/db_bench.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/types.h>\n\n#include \"leveldb/cache.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/write_batch.h\"\n#include \"port/port.h\"\n#include \"util/crc32c.h\"\n#include \"util/histogram.h\"\n#include \"util/mutexlock.h\"\n#include \"util/random.h\"\n#include \"util/testutil.h\"\n\n// Comma-separated list of operations to run in the specified order\n//   Actual benchmarks:\n//      fillseq       -- write N values in sequential key order in async mode\n//      fillrandom    -- write N values in random key order in async mode\n//      overwrite     -- overwrite N values in random key order in async mode\n//      fillsync      -- write N/100 values in random key order in sync mode\n//      fill100K      -- write N/1000 100K values in random order in async mode\n//      deleteseq     -- delete N keys in sequential order\n//      deleterandom  -- delete N keys in random order\n//      readseq       -- read N times sequentially\n//      readreverse   -- read N times in reverse order\n//      readrandom    -- read N times in random order\n//      readmissing   -- read N missing keys in random order\n//      readhot       -- read N times in random order from 1% section of DB\n//      seekrandom    -- N random seeks\n//      open          -- cost of opening a DB\n//      crc32c        -- repeated crc32c of 4K of data\n//   Meta operations:\n//      compact     -- Compact the entire DB\n//      stats       -- Print DB stats\n//      sstables    -- Print sstable info\n//      heapprofile -- Dump a heap profile (if supported by this port)\nstatic const char* FLAGS_benchmarks =\n    \"fillseq,\"\n    \"fillsync,\"\n    \"fillrandom,\"\n    \"overwrite,\"\n    \"readrandom,\"\n    \"readrandom,\"  // Extra run to allow previous compactions to quiesce\n    \"readseq,\"\n    \"readreverse,\"\n    \"compact,\"\n    \"readrandom,\"\n    \"readseq,\"\n    \"readreverse,\"\n    \"fill100K,\"\n    \"crc32c,\"\n    \"snappycomp,\"\n    \"snappyuncomp,\";\n\n// Number of key/values to place in database\nstatic int FLAGS_num = 1000000;\n\n// Number of read operations to do.  If negative, do FLAGS_num reads.\nstatic int FLAGS_reads = -1;\n\n// Number of concurrent threads to run.\nstatic int FLAGS_threads = 1;\n\n// Size of each value\nstatic int FLAGS_value_size = 100;\n\n// Arrange to generate values that shrink to this fraction of\n// their original size after compression\nstatic double FLAGS_compression_ratio = 0.5;\n\n// Print histogram of operation timings\nstatic bool FLAGS_histogram = false;\n\n// Number of bytes to buffer in memtable before compacting\n// (initialized to default value by \"main\")\nstatic int FLAGS_write_buffer_size = 0;\n\n// Number of bytes written to each file.\n// (initialized to default value by \"main\")\nstatic int FLAGS_max_file_size = 0;\n\n// Approximate size of user data packed per block (before compression.\n// (initialized to default value by \"main\")\nstatic int FLAGS_block_size = 0;\n\n// Number of bytes to use as a cache of uncompressed data.\n// Negative means use default settings.\nstatic int FLAGS_cache_size = -1;\n\n// Maximum number of files to keep open at the same time (use default if == 0)\nstatic int FLAGS_open_files = 0;\n\n// Bloom filter bits per key.\n// Negative means use default settings.\nstatic int FLAGS_bloom_bits = -1;\n\n// If true, do not destroy the existing database.  If you set this\n// flag and also specify a benchmark that wants a fresh database, that\n// benchmark will fail.\nstatic bool FLAGS_use_existing_db = false;\n\n// If true, reuse existing log/MANIFEST files when re-opening a database.\nstatic bool FLAGS_reuse_logs = false;\n\n// Use the db with the following name.\nstatic const char* FLAGS_db = nullptr;\n\nnamespace leveldb {\n\nnamespace {\nleveldb::Env* g_env = nullptr;\n\n// Helper for quickly generating random data.\nclass RandomGenerator {\n private:\n  std::string data_;\n  int pos_;\n\n public:\n  RandomGenerator() {\n    // We use a limited amount of data over and over again and ensure\n    // that it is larger than the compression window (32KB), and also\n    // large enough to serve all typical value sizes we want to write.\n    Random rnd(301);\n    std::string piece;\n    while (data_.size() < 1048576) {\n      // Add a short fragment that is as compressible as specified\n      // by FLAGS_compression_ratio.\n      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);\n      data_.append(piece);\n    }\n    pos_ = 0;\n  }\n\n  Slice Generate(size_t len) {\n    if (pos_ + len > data_.size()) {\n      pos_ = 0;\n      assert(len < data_.size());\n    }\n    pos_ += len;\n    return Slice(data_.data() + pos_ - len, len);\n  }\n};\n\n#if defined(__linux)\nstatic Slice TrimSpace(Slice s) {\n  size_t start = 0;\n  while (start < s.size() && isspace(s[start])) {\n    start++;\n  }\n  size_t limit = s.size();\n  while (limit > start && isspace(s[limit - 1])) {\n    limit--;\n  }\n  return Slice(s.data() + start, limit - start);\n}\n#endif\n\nstatic void AppendWithSpace(std::string* str, Slice msg) {\n  if (msg.empty()) return;\n  if (!str->empty()) {\n    str->push_back(' ');\n  }\n  str->append(msg.data(), msg.size());\n}\n\nclass Stats {\n private:\n  double start_;\n  double finish_;\n  double seconds_;\n  int done_;\n  int next_report_;\n  int64_t bytes_;\n  double last_op_finish_;\n  Histogram hist_;\n  std::string message_;\n\n public:\n  Stats() { Start(); }\n\n  void Start() {\n    next_report_ = 100;\n    hist_.Clear();\n    done_ = 0;\n    bytes_ = 0;\n    seconds_ = 0;\n    message_.clear();\n    start_ = finish_ = last_op_finish_ = g_env->NowMicros();\n  }\n\n  void Merge(const Stats& other) {\n    hist_.Merge(other.hist_);\n    done_ += other.done_;\n    bytes_ += other.bytes_;\n    seconds_ += other.seconds_;\n    if (other.start_ < start_) start_ = other.start_;\n    if (other.finish_ > finish_) finish_ = other.finish_;\n\n    // Just keep the messages from one thread\n    if (message_.empty()) message_ = other.message_;\n  }\n\n  void Stop() {\n    finish_ = g_env->NowMicros();\n    seconds_ = (finish_ - start_) * 1e-6;\n  }\n\n  void AddMessage(Slice msg) { AppendWithSpace(&message_, msg); }\n\n  void FinishedSingleOp() {\n    if (FLAGS_histogram) {\n      double now = g_env->NowMicros();\n      double micros = now - last_op_finish_;\n      hist_.Add(micros);\n      if (micros > 20000) {\n        fprintf(stderr, \"long op: %.1f micros%30s\\r\", micros, \"\");\n        fflush(stderr);\n      }\n      last_op_finish_ = now;\n    }\n\n    done_++;\n    if (done_ >= next_report_) {\n      if (next_report_ < 1000)\n        next_report_ += 100;\n      else if (next_report_ < 5000)\n        next_report_ += 500;\n      else if (next_report_ < 10000)\n        next_report_ += 1000;\n      else if (next_report_ < 50000)\n        next_report_ += 5000;\n      else if (next_report_ < 100000)\n        next_report_ += 10000;\n      else if (next_report_ < 500000)\n        next_report_ += 50000;\n      else\n        next_report_ += 100000;\n      fprintf(stderr, \"... finished %d ops%30s\\r\", done_, \"\");\n      fflush(stderr);\n    }\n  }\n\n  void AddBytes(int64_t n) { bytes_ += n; }\n\n  void Report(const Slice& name) {\n    // Pretend at least one op was done in case we are running a benchmark\n    // that does not call FinishedSingleOp().\n    if (done_ < 1) done_ = 1;\n\n    std::string extra;\n    if (bytes_ > 0) {\n      // Rate is computed on actual elapsed time, not the sum of per-thread\n      // elapsed times.\n      double elapsed = (finish_ - start_) * 1e-6;\n      char rate[100];\n      snprintf(rate, sizeof(rate), \"%6.1f MB/s\",\n               (bytes_ / 1048576.0) / elapsed);\n      extra = rate;\n    }\n    AppendWithSpace(&extra, message_);\n\n    fprintf(stdout, \"%-12s : %11.3f micros/op;%s%s\\n\", name.ToString().c_str(),\n            seconds_ * 1e6 / done_, (extra.empty() ? \"\" : \" \"), extra.c_str());\n    if (FLAGS_histogram) {\n      fprintf(stdout, \"Microseconds per op:\\n%s\\n\", hist_.ToString().c_str());\n    }\n    fflush(stdout);\n  }\n};\n\n// State shared by all concurrent executions of the same benchmark.\nstruct SharedState {\n  port::Mutex mu;\n  port::CondVar cv GUARDED_BY(mu);\n  int total GUARDED_BY(mu);\n\n  // Each thread goes through the following states:\n  //    (1) initializing\n  //    (2) waiting for others to be initialized\n  //    (3) running\n  //    (4) done\n\n  int num_initialized GUARDED_BY(mu);\n  int num_done GUARDED_BY(mu);\n  bool start GUARDED_BY(mu);\n\n  SharedState(int total)\n      : cv(&mu), total(total), num_initialized(0), num_done(0), start(false) {}\n};\n\n// Per-thread state for concurrent executions of the same benchmark.\nstruct ThreadState {\n  int tid;      // 0..n-1 when running in n threads\n  Random rand;  // Has different seeds for different threads\n  Stats stats;\n  SharedState* shared;\n\n  ThreadState(int index) : tid(index), rand(1000 + index), shared(nullptr) {}\n};\n\n}  // namespace\n\nclass Benchmark {\n private:\n  Cache* cache_;\n  const FilterPolicy* filter_policy_;\n  DB* db_;\n  int num_;\n  int value_size_;\n  int entries_per_batch_;\n  WriteOptions write_options_;\n  int reads_;\n  int heap_counter_;\n\n  void PrintHeader() {\n    const int kKeySize = 16;\n    PrintEnvironment();\n    fprintf(stdout, \"Keys:       %d bytes each\\n\", kKeySize);\n    fprintf(stdout, \"Values:     %d bytes each (%d bytes after compression)\\n\",\n            FLAGS_value_size,\n            static_cast<int>(FLAGS_value_size * FLAGS_compression_ratio + 0.5));\n    fprintf(stdout, \"Entries:    %d\\n\", num_);\n    fprintf(stdout, \"RawSize:    %.1f MB (estimated)\\n\",\n            ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_) /\n             1048576.0));\n    fprintf(stdout, \"FileSize:   %.1f MB (estimated)\\n\",\n            (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /\n             1048576.0));\n    PrintWarnings();\n    fprintf(stdout, \"------------------------------------------------\\n\");\n  }\n\n  void PrintWarnings() {\n#if defined(__GNUC__) && !defined(__OPTIMIZE__)\n    fprintf(\n        stdout,\n        \"WARNING: Optimization is disabled: benchmarks unnecessarily slow\\n\");\n#endif\n#ifndef NDEBUG\n    fprintf(stdout,\n            \"WARNING: Assertions are enabled; benchmarks unnecessarily slow\\n\");\n#endif\n\n    // See if snappy is working by attempting to compress a compressible string\n    const char text[] = \"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\";\n    std::string compressed;\n    if (!port::Snappy_Compress(text, sizeof(text), &compressed)) {\n      fprintf(stdout, \"WARNING: Snappy compression is not enabled\\n\");\n    } else if (compressed.size() >= sizeof(text)) {\n      fprintf(stdout, \"WARNING: Snappy compression is not effective\\n\");\n    }\n  }\n\n  void PrintEnvironment() {\n    fprintf(stderr, \"LevelDB:    version %d.%d\\n\", kMajorVersion,\n            kMinorVersion);\n\n#if defined(__linux)\n    time_t now = time(nullptr);\n    fprintf(stderr, \"Date:       %s\", ctime(&now));  // ctime() adds newline\n\n    FILE* cpuinfo = fopen(\"/proc/cpuinfo\", \"r\");\n    if (cpuinfo != nullptr) {\n      char line[1000];\n      int num_cpus = 0;\n      std::string cpu_type;\n      std::string cache_size;\n      while (fgets(line, sizeof(line), cpuinfo) != nullptr) {\n        const char* sep = strchr(line, ':');\n        if (sep == nullptr) {\n          continue;\n        }\n        Slice key = TrimSpace(Slice(line, sep - 1 - line));\n        Slice val = TrimSpace(Slice(sep + 1));\n        if (key == \"model name\") {\n          ++num_cpus;\n          cpu_type = val.ToString();\n        } else if (key == \"cache size\") {\n          cache_size = val.ToString();\n        }\n      }\n      fclose(cpuinfo);\n      fprintf(stderr, \"CPU:        %d * %s\\n\", num_cpus, cpu_type.c_str());\n      fprintf(stderr, \"CPUCache:   %s\\n\", cache_size.c_str());\n    }\n#endif\n  }\n\n public:\n  Benchmark()\n      : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : nullptr),\n        filter_policy_(FLAGS_bloom_bits >= 0\n                           ? NewBloomFilterPolicy(FLAGS_bloom_bits)\n                           : nullptr),\n        db_(nullptr),\n        num_(FLAGS_num),\n        value_size_(FLAGS_value_size),\n        entries_per_batch_(1),\n        reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),\n        heap_counter_(0) {\n    std::vector<std::string> files;\n    g_env->GetChildren(FLAGS_db, &files);\n    for (size_t i = 0; i < files.size(); i++) {\n      if (Slice(files[i]).starts_with(\"heap-\")) {\n        g_env->DeleteFile(std::string(FLAGS_db) + \"/\" + files[i]);\n      }\n    }\n    if (!FLAGS_use_existing_db) {\n      DestroyDB(FLAGS_db, Options());\n    }\n  }\n\n  ~Benchmark() {\n    delete db_;\n    delete cache_;\n    delete filter_policy_;\n  }\n\n  void Run() {\n    PrintHeader();\n    Open();\n\n    const char* benchmarks = FLAGS_benchmarks;\n    while (benchmarks != nullptr) {\n      const char* sep = strchr(benchmarks, ',');\n      Slice name;\n      if (sep == nullptr) {\n        name = benchmarks;\n        benchmarks = nullptr;\n      } else {\n        name = Slice(benchmarks, sep - benchmarks);\n        benchmarks = sep + 1;\n      }\n\n      // Reset parameters that may be overridden below\n      num_ = FLAGS_num;\n      reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);\n      value_size_ = FLAGS_value_size;\n      entries_per_batch_ = 1;\n      write_options_ = WriteOptions();\n\n      void (Benchmark::*method)(ThreadState*) = nullptr;\n      bool fresh_db = false;\n      int num_threads = FLAGS_threads;\n\n      if (name == Slice(\"open\")) {\n        method = &Benchmark::OpenBench;\n        num_ /= 10000;\n        if (num_ < 1) num_ = 1;\n      } else if (name == Slice(\"fillseq\")) {\n        fresh_db = true;\n        method = &Benchmark::WriteSeq;\n      } else if (name == Slice(\"fillbatch\")) {\n        fresh_db = true;\n        entries_per_batch_ = 1000;\n        method = &Benchmark::WriteSeq;\n      } else if (name == Slice(\"fillrandom\")) {\n        fresh_db = true;\n        method = &Benchmark::WriteRandom;\n      } else if (name == Slice(\"overwrite\")) {\n        fresh_db = false;\n        method = &Benchmark::WriteRandom;\n      } else if (name == Slice(\"fillsync\")) {\n        fresh_db = true;\n        num_ /= 1000;\n        write_options_.sync = true;\n        method = &Benchmark::WriteRandom;\n      } else if (name == Slice(\"fill100K\")) {\n        fresh_db = true;\n        num_ /= 1000;\n        value_size_ = 100 * 1000;\n        method = &Benchmark::WriteRandom;\n      } else if (name == Slice(\"readseq\")) {\n        method = &Benchmark::ReadSequential;\n      } else if (name == Slice(\"readreverse\")) {\n        method = &Benchmark::ReadReverse;\n      } else if (name == Slice(\"readrandom\")) {\n        method = &Benchmark::ReadRandom;\n      } else if (name == Slice(\"readmissing\")) {\n        method = &Benchmark::ReadMissing;\n      } else if (name == Slice(\"seekrandom\")) {\n        method = &Benchmark::SeekRandom;\n      } else if (name == Slice(\"readhot\")) {\n        method = &Benchmark::ReadHot;\n      } else if (name == Slice(\"readrandomsmall\")) {\n        reads_ /= 1000;\n        method = &Benchmark::ReadRandom;\n      } else if (name == Slice(\"deleteseq\")) {\n        method = &Benchmark::DeleteSeq;\n      } else if (name == Slice(\"deleterandom\")) {\n        method = &Benchmark::DeleteRandom;\n      } else if (name == Slice(\"readwhilewriting\")) {\n        num_threads++;  // Add extra thread for writing\n        method = &Benchmark::ReadWhileWriting;\n      } else if (name == Slice(\"compact\")) {\n        method = &Benchmark::Compact;\n      } else if (name == Slice(\"crc32c\")) {\n        method = &Benchmark::Crc32c;\n      } else if (name == Slice(\"snappycomp\")) {\n        method = &Benchmark::SnappyCompress;\n      } else if (name == Slice(\"snappyuncomp\")) {\n        method = &Benchmark::SnappyUncompress;\n      } else if (name == Slice(\"heapprofile\")) {\n        HeapProfile();\n      } else if (name == Slice(\"stats\")) {\n        PrintStats(\"leveldb.stats\");\n      } else if (name == Slice(\"sstables\")) {\n        PrintStats(\"leveldb.sstables\");\n      } else {\n        if (!name.empty()) {  // No error message for empty name\n          fprintf(stderr, \"unknown benchmark '%s'\\n\", name.ToString().c_str());\n        }\n      }\n\n      if (fresh_db) {\n        if (FLAGS_use_existing_db) {\n          fprintf(stdout, \"%-12s : skipped (--use_existing_db is true)\\n\",\n                  name.ToString().c_str());\n          method = nullptr;\n        } else {\n          delete db_;\n          db_ = nullptr;\n          DestroyDB(FLAGS_db, Options());\n          Open();\n        }\n      }\n\n      if (method != nullptr) {\n        RunBenchmark(num_threads, name, method);\n      }\n    }\n  }\n\n private:\n  struct ThreadArg {\n    Benchmark* bm;\n    SharedState* shared;\n    ThreadState* thread;\n    void (Benchmark::*method)(ThreadState*);\n  };\n\n  static void ThreadBody(void* v) {\n    ThreadArg* arg = reinterpret_cast<ThreadArg*>(v);\n    SharedState* shared = arg->shared;\n    ThreadState* thread = arg->thread;\n    {\n      MutexLock l(&shared->mu);\n      shared->num_initialized++;\n      if (shared->num_initialized >= shared->total) {\n        shared->cv.SignalAll();\n      }\n      while (!shared->start) {\n        shared->cv.Wait();\n      }\n    }\n\n    thread->stats.Start();\n    (arg->bm->*(arg->method))(thread);\n    thread->stats.Stop();\n\n    {\n      MutexLock l(&shared->mu);\n      shared->num_done++;\n      if (shared->num_done >= shared->total) {\n        shared->cv.SignalAll();\n      }\n    }\n  }\n\n  void RunBenchmark(int n, Slice name,\n                    void (Benchmark::*method)(ThreadState*)) {\n    SharedState shared(n);\n\n    ThreadArg* arg = new ThreadArg[n];\n    for (int i = 0; i < n; i++) {\n      arg[i].bm = this;\n      arg[i].method = method;\n      arg[i].shared = &shared;\n      arg[i].thread = new ThreadState(i);\n      arg[i].thread->shared = &shared;\n      g_env->StartThread(ThreadBody, &arg[i]);\n    }\n\n    shared.mu.Lock();\n    while (shared.num_initialized < n) {\n      shared.cv.Wait();\n    }\n\n    shared.start = true;\n    shared.cv.SignalAll();\n    while (shared.num_done < n) {\n      shared.cv.Wait();\n    }\n    shared.mu.Unlock();\n\n    for (int i = 1; i < n; i++) {\n      arg[0].thread->stats.Merge(arg[i].thread->stats);\n    }\n    arg[0].thread->stats.Report(name);\n\n    for (int i = 0; i < n; i++) {\n      delete arg[i].thread;\n    }\n    delete[] arg;\n  }\n\n  void Crc32c(ThreadState* thread) {\n    // Checksum about 500MB of data total\n    const int size = 4096;\n    const char* label = \"(4K per op)\";\n    std::string data(size, 'x');\n    int64_t bytes = 0;\n    uint32_t crc = 0;\n    while (bytes < 500 * 1048576) {\n      crc = crc32c::Value(data.data(), size);\n      thread->stats.FinishedSingleOp();\n      bytes += size;\n    }\n    // Print so result is not dead\n    fprintf(stderr, \"... crc=0x%x\\r\", static_cast<unsigned int>(crc));\n\n    thread->stats.AddBytes(bytes);\n    thread->stats.AddMessage(label);\n  }\n\n  void SnappyCompress(ThreadState* thread) {\n    RandomGenerator gen;\n    Slice input = gen.Generate(Options().block_size);\n    int64_t bytes = 0;\n    int64_t produced = 0;\n    bool ok = true;\n    std::string compressed;\n    while (ok && bytes < 1024 * 1048576) {  // Compress 1G\n      ok = port::Snappy_Compress(input.data(), input.size(), &compressed);\n      produced += compressed.size();\n      bytes += input.size();\n      thread->stats.FinishedSingleOp();\n    }\n\n    if (!ok) {\n      thread->stats.AddMessage(\"(snappy failure)\");\n    } else {\n      char buf[100];\n      snprintf(buf, sizeof(buf), \"(output: %.1f%%)\",\n               (produced * 100.0) / bytes);\n      thread->stats.AddMessage(buf);\n      thread->stats.AddBytes(bytes);\n    }\n  }\n\n  void SnappyUncompress(ThreadState* thread) {\n    RandomGenerator gen;\n    Slice input = gen.Generate(Options().block_size);\n    std::string compressed;\n    bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed);\n    int64_t bytes = 0;\n    char* uncompressed = new char[input.size()];\n    while (ok && bytes < 1024 * 1048576) {  // Compress 1G\n      ok = port::Snappy_Uncompress(compressed.data(), compressed.size(),\n                                   uncompressed);\n      bytes += input.size();\n      thread->stats.FinishedSingleOp();\n    }\n    delete[] uncompressed;\n\n    if (!ok) {\n      thread->stats.AddMessage(\"(snappy failure)\");\n    } else {\n      thread->stats.AddBytes(bytes);\n    }\n  }\n\n  void Open() {\n    assert(db_ == nullptr);\n    Options options;\n    options.env = g_env;\n    options.create_if_missing = !FLAGS_use_existing_db;\n    options.block_cache = cache_;\n    options.write_buffer_size = FLAGS_write_buffer_size;\n    options.max_file_size = FLAGS_max_file_size;\n    options.block_size = FLAGS_block_size;\n    options.max_open_files = FLAGS_open_files;\n    options.filter_policy = filter_policy_;\n    options.reuse_logs = FLAGS_reuse_logs;\n    Status s = DB::Open(options, FLAGS_db, &db_);\n    if (!s.ok()) {\n      fprintf(stderr, \"open error: %s\\n\", s.ToString().c_str());\n      exit(1);\n    }\n  }\n\n  void OpenBench(ThreadState* thread) {\n    for (int i = 0; i < num_; i++) {\n      delete db_;\n      Open();\n      thread->stats.FinishedSingleOp();\n    }\n  }\n\n  void WriteSeq(ThreadState* thread) { DoWrite(thread, true); }\n\n  void WriteRandom(ThreadState* thread) { DoWrite(thread, false); }\n\n  void DoWrite(ThreadState* thread, bool seq) {\n    if (num_ != FLAGS_num) {\n      char msg[100];\n      snprintf(msg, sizeof(msg), \"(%d ops)\", num_);\n      thread->stats.AddMessage(msg);\n    }\n\n    RandomGenerator gen;\n    WriteBatch batch;\n    Status s;\n    int64_t bytes = 0;\n    for (int i = 0; i < num_; i += entries_per_batch_) {\n      batch.Clear();\n      for (int j = 0; j < entries_per_batch_; j++) {\n        const int k = seq ? i + j : (thread->rand.Next() % FLAGS_num);\n        char key[100];\n        snprintf(key, sizeof(key), \"%016d\", k);\n        batch.Put(key, gen.Generate(value_size_));\n        bytes += value_size_ + strlen(key);\n        thread->stats.FinishedSingleOp();\n      }\n      s = db_->Write(write_options_, &batch);\n      if (!s.ok()) {\n        fprintf(stderr, \"put error: %s\\n\", s.ToString().c_str());\n        exit(1);\n      }\n    }\n    thread->stats.AddBytes(bytes);\n  }\n\n  void ReadSequential(ThreadState* thread) {\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    int i = 0;\n    int64_t bytes = 0;\n    for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) {\n      bytes += iter->key().size() + iter->value().size();\n      thread->stats.FinishedSingleOp();\n      ++i;\n    }\n    delete iter;\n    thread->stats.AddBytes(bytes);\n  }\n\n  void ReadReverse(ThreadState* thread) {\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    int i = 0;\n    int64_t bytes = 0;\n    for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) {\n      bytes += iter->key().size() + iter->value().size();\n      thread->stats.FinishedSingleOp();\n      ++i;\n    }\n    delete iter;\n    thread->stats.AddBytes(bytes);\n  }\n\n  void ReadRandom(ThreadState* thread) {\n    ReadOptions options;\n    std::string value;\n    int found = 0;\n    for (int i = 0; i < reads_; i++) {\n      char key[100];\n      const int k = thread->rand.Next() % FLAGS_num;\n      snprintf(key, sizeof(key), \"%016d\", k);\n      if (db_->Get(options, key, &value).ok()) {\n        found++;\n      }\n      thread->stats.FinishedSingleOp();\n    }\n    char msg[100];\n    snprintf(msg, sizeof(msg), \"(%d of %d found)\", found, num_);\n    thread->stats.AddMessage(msg);\n  }\n\n  void ReadMissing(ThreadState* thread) {\n    ReadOptions options;\n    std::string value;\n    for (int i = 0; i < reads_; i++) {\n      char key[100];\n      const int k = thread->rand.Next() % FLAGS_num;\n      snprintf(key, sizeof(key), \"%016d.\", k);\n      db_->Get(options, key, &value);\n      thread->stats.FinishedSingleOp();\n    }\n  }\n\n  void ReadHot(ThreadState* thread) {\n    ReadOptions options;\n    std::string value;\n    const int range = (FLAGS_num + 99) / 100;\n    for (int i = 0; i < reads_; i++) {\n      char key[100];\n      const int k = thread->rand.Next() % range;\n      snprintf(key, sizeof(key), \"%016d\", k);\n      db_->Get(options, key, &value);\n      thread->stats.FinishedSingleOp();\n    }\n  }\n\n  void SeekRandom(ThreadState* thread) {\n    ReadOptions options;\n    int found = 0;\n    for (int i = 0; i < reads_; i++) {\n      Iterator* iter = db_->NewIterator(options);\n      char key[100];\n      const int k = thread->rand.Next() % FLAGS_num;\n      snprintf(key, sizeof(key), \"%016d\", k);\n      iter->Seek(key);\n      if (iter->Valid() && iter->key() == key) found++;\n      delete iter;\n      thread->stats.FinishedSingleOp();\n    }\n    char msg[100];\n    snprintf(msg, sizeof(msg), \"(%d of %d found)\", found, num_);\n    thread->stats.AddMessage(msg);\n  }\n\n  void DoDelete(ThreadState* thread, bool seq) {\n    RandomGenerator gen;\n    WriteBatch batch;\n    Status s;\n    for (int i = 0; i < num_; i += entries_per_batch_) {\n      batch.Clear();\n      for (int j = 0; j < entries_per_batch_; j++) {\n        const int k = seq ? i + j : (thread->rand.Next() % FLAGS_num);\n        char key[100];\n        snprintf(key, sizeof(key), \"%016d\", k);\n        batch.Delete(key);\n        thread->stats.FinishedSingleOp();\n      }\n      s = db_->Write(write_options_, &batch);\n      if (!s.ok()) {\n        fprintf(stderr, \"del error: %s\\n\", s.ToString().c_str());\n        exit(1);\n      }\n    }\n  }\n\n  void DeleteSeq(ThreadState* thread) { DoDelete(thread, true); }\n\n  void DeleteRandom(ThreadState* thread) { DoDelete(thread, false); }\n\n  void ReadWhileWriting(ThreadState* thread) {\n    if (thread->tid > 0) {\n      ReadRandom(thread);\n    } else {\n      // Special thread that keeps writing until other threads are done.\n      RandomGenerator gen;\n      while (true) {\n        {\n          MutexLock l(&thread->shared->mu);\n          if (thread->shared->num_done + 1 >= thread->shared->num_initialized) {\n            // Other threads have finished\n            break;\n          }\n        }\n\n        const int k = thread->rand.Next() % FLAGS_num;\n        char key[100];\n        snprintf(key, sizeof(key), \"%016d\", k);\n        Status s = db_->Put(write_options_, key, gen.Generate(value_size_));\n        if (!s.ok()) {\n          fprintf(stderr, \"put error: %s\\n\", s.ToString().c_str());\n          exit(1);\n        }\n      }\n\n      // Do not count any of the preceding work/delay in stats.\n      thread->stats.Start();\n    }\n  }\n\n  void Compact(ThreadState* thread) { db_->CompactRange(nullptr, nullptr); }\n\n  void PrintStats(const char* key) {\n    std::string stats;\n    if (!db_->GetProperty(key, &stats)) {\n      stats = \"(failed)\";\n    }\n    fprintf(stdout, \"\\n%s\\n\", stats.c_str());\n  }\n\n  static void WriteToFile(void* arg, const char* buf, int n) {\n    reinterpret_cast<WritableFile*>(arg)->Append(Slice(buf, n));\n  }\n\n  void HeapProfile() {\n    char fname[100];\n    snprintf(fname, sizeof(fname), \"%s/heap-%04d\", FLAGS_db, ++heap_counter_);\n    WritableFile* file;\n    Status s = g_env->NewWritableFile(fname, &file);\n    if (!s.ok()) {\n      fprintf(stderr, \"%s\\n\", s.ToString().c_str());\n      return;\n    }\n    bool ok = port::GetHeapProfile(WriteToFile, file);\n    delete file;\n    if (!ok) {\n      fprintf(stderr, \"heap profiling not supported\\n\");\n      g_env->DeleteFile(fname);\n    }\n  }\n};\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n  FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;\n  FLAGS_max_file_size = leveldb::Options().max_file_size;\n  FLAGS_block_size = leveldb::Options().block_size;\n  FLAGS_open_files = leveldb::Options().max_open_files;\n  std::string default_db_path;\n\n  for (int i = 1; i < argc; i++) {\n    double d;\n    int n;\n    char junk;\n    if (leveldb::Slice(argv[i]).starts_with(\"--benchmarks=\")) {\n      FLAGS_benchmarks = argv[i] + strlen(\"--benchmarks=\");\n    } else if (sscanf(argv[i], \"--compression_ratio=%lf%c\", &d, &junk) == 1) {\n      FLAGS_compression_ratio = d;\n    } else if (sscanf(argv[i], \"--histogram=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_histogram = n;\n    } else if (sscanf(argv[i], \"--use_existing_db=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_use_existing_db = n;\n    } else if (sscanf(argv[i], \"--reuse_logs=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_reuse_logs = n;\n    } else if (sscanf(argv[i], \"--num=%d%c\", &n, &junk) == 1) {\n      FLAGS_num = n;\n    } else if (sscanf(argv[i], \"--reads=%d%c\", &n, &junk) == 1) {\n      FLAGS_reads = n;\n    } else if (sscanf(argv[i], \"--threads=%d%c\", &n, &junk) == 1) {\n      FLAGS_threads = n;\n    } else if (sscanf(argv[i], \"--value_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_value_size = n;\n    } else if (sscanf(argv[i], \"--write_buffer_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_write_buffer_size = n;\n    } else if (sscanf(argv[i], \"--max_file_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_max_file_size = n;\n    } else if (sscanf(argv[i], \"--block_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_block_size = n;\n    } else if (sscanf(argv[i], \"--cache_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_cache_size = n;\n    } else if (sscanf(argv[i], \"--bloom_bits=%d%c\", &n, &junk) == 1) {\n      FLAGS_bloom_bits = n;\n    } else if (sscanf(argv[i], \"--open_files=%d%c\", &n, &junk) == 1) {\n      FLAGS_open_files = n;\n    } else if (strncmp(argv[i], \"--db=\", 5) == 0) {\n      FLAGS_db = argv[i] + 5;\n    } else {\n      fprintf(stderr, \"Invalid flag '%s'\\n\", argv[i]);\n      exit(1);\n    }\n  }\n\n  leveldb::g_env = leveldb::Env::Default();\n\n  // Choose a location for the test database if none given with --db=<path>\n  if (FLAGS_db == nullptr) {\n    leveldb::g_env->GetTestDirectory(&default_db_path);\n    default_db_path += \"/dbbench\";\n    FLAGS_db = default_db_path.c_str();\n  }\n\n  leveldb::Benchmark benchmark;\n  benchmark.Run();\n  return 0;\n}\n"
  },
  {
    "path": "src/leveldb/benchmarks/db_bench_sqlite3.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <sqlite3.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"util/histogram.h\"\n#include \"util/random.h\"\n#include \"util/testutil.h\"\n\n// Comma-separated list of operations to run in the specified order\n//   Actual benchmarks:\n//\n//   fillseq       -- write N values in sequential key order in async mode\n//   fillseqsync   -- write N/100 values in sequential key order in sync mode\n//   fillseqbatch  -- batch write N values in sequential key order in async mode\n//   fillrandom    -- write N values in random key order in async mode\n//   fillrandsync  -- write N/100 values in random key order in sync mode\n//   fillrandbatch -- batch write N values in sequential key order in async mode\n//   overwrite     -- overwrite N values in random key order in async mode\n//   fillrand100K  -- write N/1000 100K values in random order in async mode\n//   fillseq100K   -- write N/1000 100K values in sequential order in async mode\n//   readseq       -- read N times sequentially\n//   readrandom    -- read N times in random order\n//   readrand100K  -- read N/1000 100K values in sequential order in async mode\nstatic const char* FLAGS_benchmarks =\n    \"fillseq,\"\n    \"fillseqsync,\"\n    \"fillseqbatch,\"\n    \"fillrandom,\"\n    \"fillrandsync,\"\n    \"fillrandbatch,\"\n    \"overwrite,\"\n    \"overwritebatch,\"\n    \"readrandom,\"\n    \"readseq,\"\n    \"fillrand100K,\"\n    \"fillseq100K,\"\n    \"readseq,\"\n    \"readrand100K,\";\n\n// Number of key/values to place in database\nstatic int FLAGS_num = 1000000;\n\n// Number of read operations to do.  If negative, do FLAGS_num reads.\nstatic int FLAGS_reads = -1;\n\n// Size of each value\nstatic int FLAGS_value_size = 100;\n\n// Print histogram of operation timings\nstatic bool FLAGS_histogram = false;\n\n// Arrange to generate values that shrink to this fraction of\n// their original size after compression\nstatic double FLAGS_compression_ratio = 0.5;\n\n// Page size. Default 1 KB.\nstatic int FLAGS_page_size = 1024;\n\n// Number of pages.\n// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB.\nstatic int FLAGS_num_pages = 4096;\n\n// If true, do not destroy the existing database.  If you set this\n// flag and also specify a benchmark that wants a fresh database, that\n// benchmark will fail.\nstatic bool FLAGS_use_existing_db = false;\n\n// If true, we allow batch writes to occur\nstatic bool FLAGS_transaction = true;\n\n// If true, we enable Write-Ahead Logging\nstatic bool FLAGS_WAL_enabled = true;\n\n// Use the db with the following name.\nstatic const char* FLAGS_db = nullptr;\n\ninline static void ExecErrorCheck(int status, char* err_msg) {\n  if (status != SQLITE_OK) {\n    fprintf(stderr, \"SQL error: %s\\n\", err_msg);\n    sqlite3_free(err_msg);\n    exit(1);\n  }\n}\n\ninline static void StepErrorCheck(int status) {\n  if (status != SQLITE_DONE) {\n    fprintf(stderr, \"SQL step error: status = %d\\n\", status);\n    exit(1);\n  }\n}\n\ninline static void ErrorCheck(int status) {\n  if (status != SQLITE_OK) {\n    fprintf(stderr, \"sqlite3 error: status = %d\\n\", status);\n    exit(1);\n  }\n}\n\ninline static void WalCheckpoint(sqlite3* db_) {\n  // Flush all writes to disk\n  if (FLAGS_WAL_enabled) {\n    sqlite3_wal_checkpoint_v2(db_, nullptr, SQLITE_CHECKPOINT_FULL, nullptr,\n                              nullptr);\n  }\n}\n\nnamespace leveldb {\n\n// Helper for quickly generating random data.\nnamespace {\nclass RandomGenerator {\n private:\n  std::string data_;\n  int pos_;\n\n public:\n  RandomGenerator() {\n    // We use a limited amount of data over and over again and ensure\n    // that it is larger than the compression window (32KB), and also\n    // large enough to serve all typical value sizes we want to write.\n    Random rnd(301);\n    std::string piece;\n    while (data_.size() < 1048576) {\n      // Add a short fragment that is as compressible as specified\n      // by FLAGS_compression_ratio.\n      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);\n      data_.append(piece);\n    }\n    pos_ = 0;\n  }\n\n  Slice Generate(int len) {\n    if (pos_ + len > data_.size()) {\n      pos_ = 0;\n      assert(len < data_.size());\n    }\n    pos_ += len;\n    return Slice(data_.data() + pos_ - len, len);\n  }\n};\n\nstatic Slice TrimSpace(Slice s) {\n  int start = 0;\n  while (start < s.size() && isspace(s[start])) {\n    start++;\n  }\n  int limit = s.size();\n  while (limit > start && isspace(s[limit - 1])) {\n    limit--;\n  }\n  return Slice(s.data() + start, limit - start);\n}\n\n}  // namespace\n\nclass Benchmark {\n private:\n  sqlite3* db_;\n  int db_num_;\n  int num_;\n  int reads_;\n  double start_;\n  double last_op_finish_;\n  int64_t bytes_;\n  std::string message_;\n  Histogram hist_;\n  RandomGenerator gen_;\n  Random rand_;\n\n  // State kept for progress messages\n  int done_;\n  int next_report_;  // When to report next\n\n  void PrintHeader() {\n    const int kKeySize = 16;\n    PrintEnvironment();\n    fprintf(stdout, \"Keys:       %d bytes each\\n\", kKeySize);\n    fprintf(stdout, \"Values:     %d bytes each\\n\", FLAGS_value_size);\n    fprintf(stdout, \"Entries:    %d\\n\", num_);\n    fprintf(stdout, \"RawSize:    %.1f MB (estimated)\\n\",\n            ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_) /\n             1048576.0));\n    PrintWarnings();\n    fprintf(stdout, \"------------------------------------------------\\n\");\n  }\n\n  void PrintWarnings() {\n#if defined(__GNUC__) && !defined(__OPTIMIZE__)\n    fprintf(\n        stdout,\n        \"WARNING: Optimization is disabled: benchmarks unnecessarily slow\\n\");\n#endif\n#ifndef NDEBUG\n    fprintf(stdout,\n            \"WARNING: Assertions are enabled; benchmarks unnecessarily slow\\n\");\n#endif\n  }\n\n  void PrintEnvironment() {\n    fprintf(stderr, \"SQLite:     version %s\\n\", SQLITE_VERSION);\n\n#if defined(__linux)\n    time_t now = time(nullptr);\n    fprintf(stderr, \"Date:       %s\", ctime(&now));  // ctime() adds newline\n\n    FILE* cpuinfo = fopen(\"/proc/cpuinfo\", \"r\");\n    if (cpuinfo != nullptr) {\n      char line[1000];\n      int num_cpus = 0;\n      std::string cpu_type;\n      std::string cache_size;\n      while (fgets(line, sizeof(line), cpuinfo) != nullptr) {\n        const char* sep = strchr(line, ':');\n        if (sep == nullptr) {\n          continue;\n        }\n        Slice key = TrimSpace(Slice(line, sep - 1 - line));\n        Slice val = TrimSpace(Slice(sep + 1));\n        if (key == \"model name\") {\n          ++num_cpus;\n          cpu_type = val.ToString();\n        } else if (key == \"cache size\") {\n          cache_size = val.ToString();\n        }\n      }\n      fclose(cpuinfo);\n      fprintf(stderr, \"CPU:        %d * %s\\n\", num_cpus, cpu_type.c_str());\n      fprintf(stderr, \"CPUCache:   %s\\n\", cache_size.c_str());\n    }\n#endif\n  }\n\n  void Start() {\n    start_ = Env::Default()->NowMicros() * 1e-6;\n    bytes_ = 0;\n    message_.clear();\n    last_op_finish_ = start_;\n    hist_.Clear();\n    done_ = 0;\n    next_report_ = 100;\n  }\n\n  void FinishedSingleOp() {\n    if (FLAGS_histogram) {\n      double now = Env::Default()->NowMicros() * 1e-6;\n      double micros = (now - last_op_finish_) * 1e6;\n      hist_.Add(micros);\n      if (micros > 20000) {\n        fprintf(stderr, \"long op: %.1f micros%30s\\r\", micros, \"\");\n        fflush(stderr);\n      }\n      last_op_finish_ = now;\n    }\n\n    done_++;\n    if (done_ >= next_report_) {\n      if (next_report_ < 1000)\n        next_report_ += 100;\n      else if (next_report_ < 5000)\n        next_report_ += 500;\n      else if (next_report_ < 10000)\n        next_report_ += 1000;\n      else if (next_report_ < 50000)\n        next_report_ += 5000;\n      else if (next_report_ < 100000)\n        next_report_ += 10000;\n      else if (next_report_ < 500000)\n        next_report_ += 50000;\n      else\n        next_report_ += 100000;\n      fprintf(stderr, \"... finished %d ops%30s\\r\", done_, \"\");\n      fflush(stderr);\n    }\n  }\n\n  void Stop(const Slice& name) {\n    double finish = Env::Default()->NowMicros() * 1e-6;\n\n    // Pretend at least one op was done in case we are running a benchmark\n    // that does not call FinishedSingleOp().\n    if (done_ < 1) done_ = 1;\n\n    if (bytes_ > 0) {\n      char rate[100];\n      snprintf(rate, sizeof(rate), \"%6.1f MB/s\",\n               (bytes_ / 1048576.0) / (finish - start_));\n      if (!message_.empty()) {\n        message_ = std::string(rate) + \" \" + message_;\n      } else {\n        message_ = rate;\n      }\n    }\n\n    fprintf(stdout, \"%-12s : %11.3f micros/op;%s%s\\n\", name.ToString().c_str(),\n            (finish - start_) * 1e6 / done_, (message_.empty() ? \"\" : \" \"),\n            message_.c_str());\n    if (FLAGS_histogram) {\n      fprintf(stdout, \"Microseconds per op:\\n%s\\n\", hist_.ToString().c_str());\n    }\n    fflush(stdout);\n  }\n\n public:\n  enum Order { SEQUENTIAL, RANDOM };\n  enum DBState { FRESH, EXISTING };\n\n  Benchmark()\n      : db_(nullptr),\n        db_num_(0),\n        num_(FLAGS_num),\n        reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),\n        bytes_(0),\n        rand_(301) {\n    std::vector<std::string> files;\n    std::string test_dir;\n    Env::Default()->GetTestDirectory(&test_dir);\n    Env::Default()->GetChildren(test_dir, &files);\n    if (!FLAGS_use_existing_db) {\n      for (int i = 0; i < files.size(); i++) {\n        if (Slice(files[i]).starts_with(\"dbbench_sqlite3\")) {\n          std::string file_name(test_dir);\n          file_name += \"/\";\n          file_name += files[i];\n          Env::Default()->DeleteFile(file_name.c_str());\n        }\n      }\n    }\n  }\n\n  ~Benchmark() {\n    int status = sqlite3_close(db_);\n    ErrorCheck(status);\n  }\n\n  void Run() {\n    PrintHeader();\n    Open();\n\n    const char* benchmarks = FLAGS_benchmarks;\n    while (benchmarks != nullptr) {\n      const char* sep = strchr(benchmarks, ',');\n      Slice name;\n      if (sep == nullptr) {\n        name = benchmarks;\n        benchmarks = nullptr;\n      } else {\n        name = Slice(benchmarks, sep - benchmarks);\n        benchmarks = sep + 1;\n      }\n\n      bytes_ = 0;\n      Start();\n\n      bool known = true;\n      bool write_sync = false;\n      if (name == Slice(\"fillseq\")) {\n        Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillseqbatch\")) {\n        Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillrandom\")) {\n        Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillrandbatch\")) {\n        Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"overwrite\")) {\n        Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"overwritebatch\")) {\n        Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillrandsync\")) {\n        write_sync = true;\n        Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillseqsync\")) {\n        write_sync = true;\n        Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillrand100K\")) {\n        Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"fillseq100K\")) {\n        Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1);\n        WalCheckpoint(db_);\n      } else if (name == Slice(\"readseq\")) {\n        ReadSequential();\n      } else if (name == Slice(\"readrandom\")) {\n        Read(RANDOM, 1);\n      } else if (name == Slice(\"readrand100K\")) {\n        int n = reads_;\n        reads_ /= 1000;\n        Read(RANDOM, 1);\n        reads_ = n;\n      } else {\n        known = false;\n        if (name != Slice()) {  // No error message for empty name\n          fprintf(stderr, \"unknown benchmark '%s'\\n\", name.ToString().c_str());\n        }\n      }\n      if (known) {\n        Stop(name);\n      }\n    }\n  }\n\n  void Open() {\n    assert(db_ == nullptr);\n\n    int status;\n    char file_name[100];\n    char* err_msg = nullptr;\n    db_num_++;\n\n    // Open database\n    std::string tmp_dir;\n    Env::Default()->GetTestDirectory(&tmp_dir);\n    snprintf(file_name, sizeof(file_name), \"%s/dbbench_sqlite3-%d.db\",\n             tmp_dir.c_str(), db_num_);\n    status = sqlite3_open(file_name, &db_);\n    if (status) {\n      fprintf(stderr, \"open error: %s\\n\", sqlite3_errmsg(db_));\n      exit(1);\n    }\n\n    // Change SQLite cache size\n    char cache_size[100];\n    snprintf(cache_size, sizeof(cache_size), \"PRAGMA cache_size = %d\",\n             FLAGS_num_pages);\n    status = sqlite3_exec(db_, cache_size, nullptr, nullptr, &err_msg);\n    ExecErrorCheck(status, err_msg);\n\n    // FLAGS_page_size is defaulted to 1024\n    if (FLAGS_page_size != 1024) {\n      char page_size[100];\n      snprintf(page_size, sizeof(page_size), \"PRAGMA page_size = %d\",\n               FLAGS_page_size);\n      status = sqlite3_exec(db_, page_size, nullptr, nullptr, &err_msg);\n      ExecErrorCheck(status, err_msg);\n    }\n\n    // Change journal mode to WAL if WAL enabled flag is on\n    if (FLAGS_WAL_enabled) {\n      std::string WAL_stmt = \"PRAGMA journal_mode = WAL\";\n\n      // LevelDB's default cache size is a combined 4 MB\n      std::string WAL_checkpoint = \"PRAGMA wal_autocheckpoint = 4096\";\n      status = sqlite3_exec(db_, WAL_stmt.c_str(), nullptr, nullptr, &err_msg);\n      ExecErrorCheck(status, err_msg);\n      status =\n          sqlite3_exec(db_, WAL_checkpoint.c_str(), nullptr, nullptr, &err_msg);\n      ExecErrorCheck(status, err_msg);\n    }\n\n    // Change locking mode to exclusive and create tables/index for database\n    std::string locking_stmt = \"PRAGMA locking_mode = EXCLUSIVE\";\n    std::string create_stmt =\n        \"CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))\";\n    std::string stmt_array[] = {locking_stmt, create_stmt};\n    int stmt_array_length = sizeof(stmt_array) / sizeof(std::string);\n    for (int i = 0; i < stmt_array_length; i++) {\n      status =\n          sqlite3_exec(db_, stmt_array[i].c_str(), nullptr, nullptr, &err_msg);\n      ExecErrorCheck(status, err_msg);\n    }\n  }\n\n  void Write(bool write_sync, Order order, DBState state, int num_entries,\n             int value_size, int entries_per_batch) {\n    // Create new database if state == FRESH\n    if (state == FRESH) {\n      if (FLAGS_use_existing_db) {\n        message_ = \"skipping (--use_existing_db is true)\";\n        return;\n      }\n      sqlite3_close(db_);\n      db_ = nullptr;\n      Open();\n      Start();\n    }\n\n    if (num_entries != num_) {\n      char msg[100];\n      snprintf(msg, sizeof(msg), \"(%d ops)\", num_entries);\n      message_ = msg;\n    }\n\n    char* err_msg = nullptr;\n    int status;\n\n    sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt;\n    std::string replace_str = \"REPLACE INTO test (key, value) VALUES (?, ?)\";\n    std::string begin_trans_str = \"BEGIN TRANSACTION;\";\n    std::string end_trans_str = \"END TRANSACTION;\";\n\n    // Check for synchronous flag in options\n    std::string sync_stmt =\n        (write_sync) ? \"PRAGMA synchronous = FULL\" : \"PRAGMA synchronous = OFF\";\n    status = sqlite3_exec(db_, sync_stmt.c_str(), nullptr, nullptr, &err_msg);\n    ExecErrorCheck(status, err_msg);\n\n    // Preparing sqlite3 statements\n    status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, &replace_stmt,\n                                nullptr);\n    ErrorCheck(status);\n    status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,\n                                &begin_trans_stmt, nullptr);\n    ErrorCheck(status);\n    status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, &end_trans_stmt,\n                                nullptr);\n    ErrorCheck(status);\n\n    bool transaction = (entries_per_batch > 1);\n    for (int i = 0; i < num_entries; i += entries_per_batch) {\n      // Begin write transaction\n      if (FLAGS_transaction && transaction) {\n        status = sqlite3_step(begin_trans_stmt);\n        StepErrorCheck(status);\n        status = sqlite3_reset(begin_trans_stmt);\n        ErrorCheck(status);\n      }\n\n      // Create and execute SQL statements\n      for (int j = 0; j < entries_per_batch; j++) {\n        const char* value = gen_.Generate(value_size).data();\n\n        // Create values for key-value pair\n        const int k =\n            (order == SEQUENTIAL) ? i + j : (rand_.Next() % num_entries);\n        char key[100];\n        snprintf(key, sizeof(key), \"%016d\", k);\n\n        // Bind KV values into replace_stmt\n        status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC);\n        ErrorCheck(status);\n        status = sqlite3_bind_blob(replace_stmt, 2, value, value_size,\n                                   SQLITE_STATIC);\n        ErrorCheck(status);\n\n        // Execute replace_stmt\n        bytes_ += value_size + strlen(key);\n        status = sqlite3_step(replace_stmt);\n        StepErrorCheck(status);\n\n        // Reset SQLite statement for another use\n        status = sqlite3_clear_bindings(replace_stmt);\n        ErrorCheck(status);\n        status = sqlite3_reset(replace_stmt);\n        ErrorCheck(status);\n\n        FinishedSingleOp();\n      }\n\n      // End write transaction\n      if (FLAGS_transaction && transaction) {\n        status = sqlite3_step(end_trans_stmt);\n        StepErrorCheck(status);\n        status = sqlite3_reset(end_trans_stmt);\n        ErrorCheck(status);\n      }\n    }\n\n    status = sqlite3_finalize(replace_stmt);\n    ErrorCheck(status);\n    status = sqlite3_finalize(begin_trans_stmt);\n    ErrorCheck(status);\n    status = sqlite3_finalize(end_trans_stmt);\n    ErrorCheck(status);\n  }\n\n  void Read(Order order, int entries_per_batch) {\n    int status;\n    sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt;\n\n    std::string read_str = \"SELECT * FROM test WHERE key = ?\";\n    std::string begin_trans_str = \"BEGIN TRANSACTION;\";\n    std::string end_trans_str = \"END TRANSACTION;\";\n\n    // Preparing sqlite3 statements\n    status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,\n                                &begin_trans_stmt, nullptr);\n    ErrorCheck(status);\n    status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, &end_trans_stmt,\n                                nullptr);\n    ErrorCheck(status);\n    status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, nullptr);\n    ErrorCheck(status);\n\n    bool transaction = (entries_per_batch > 1);\n    for (int i = 0; i < reads_; i += entries_per_batch) {\n      // Begin read transaction\n      if (FLAGS_transaction && transaction) {\n        status = sqlite3_step(begin_trans_stmt);\n        StepErrorCheck(status);\n        status = sqlite3_reset(begin_trans_stmt);\n        ErrorCheck(status);\n      }\n\n      // Create and execute SQL statements\n      for (int j = 0; j < entries_per_batch; j++) {\n        // Create key value\n        char key[100];\n        int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_);\n        snprintf(key, sizeof(key), \"%016d\", k);\n\n        // Bind key value into read_stmt\n        status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC);\n        ErrorCheck(status);\n\n        // Execute read statement\n        while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {\n        }\n        StepErrorCheck(status);\n\n        // Reset SQLite statement for another use\n        status = sqlite3_clear_bindings(read_stmt);\n        ErrorCheck(status);\n        status = sqlite3_reset(read_stmt);\n        ErrorCheck(status);\n        FinishedSingleOp();\n      }\n\n      // End read transaction\n      if (FLAGS_transaction && transaction) {\n        status = sqlite3_step(end_trans_stmt);\n        StepErrorCheck(status);\n        status = sqlite3_reset(end_trans_stmt);\n        ErrorCheck(status);\n      }\n    }\n\n    status = sqlite3_finalize(read_stmt);\n    ErrorCheck(status);\n    status = sqlite3_finalize(begin_trans_stmt);\n    ErrorCheck(status);\n    status = sqlite3_finalize(end_trans_stmt);\n    ErrorCheck(status);\n  }\n\n  void ReadSequential() {\n    int status;\n    sqlite3_stmt* pStmt;\n    std::string read_str = \"SELECT * FROM test ORDER BY key\";\n\n    status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, nullptr);\n    ErrorCheck(status);\n    for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) {\n      bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2);\n      FinishedSingleOp();\n    }\n\n    status = sqlite3_finalize(pStmt);\n    ErrorCheck(status);\n  }\n};\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n  std::string default_db_path;\n  for (int i = 1; i < argc; i++) {\n    double d;\n    int n;\n    char junk;\n    if (leveldb::Slice(argv[i]).starts_with(\"--benchmarks=\")) {\n      FLAGS_benchmarks = argv[i] + strlen(\"--benchmarks=\");\n    } else if (sscanf(argv[i], \"--histogram=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_histogram = n;\n    } else if (sscanf(argv[i], \"--compression_ratio=%lf%c\", &d, &junk) == 1) {\n      FLAGS_compression_ratio = d;\n    } else if (sscanf(argv[i], \"--use_existing_db=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_use_existing_db = n;\n    } else if (sscanf(argv[i], \"--num=%d%c\", &n, &junk) == 1) {\n      FLAGS_num = n;\n    } else if (sscanf(argv[i], \"--reads=%d%c\", &n, &junk) == 1) {\n      FLAGS_reads = n;\n    } else if (sscanf(argv[i], \"--value_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_value_size = n;\n    } else if (leveldb::Slice(argv[i]) == leveldb::Slice(\"--no_transaction\")) {\n      FLAGS_transaction = false;\n    } else if (sscanf(argv[i], \"--page_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_page_size = n;\n    } else if (sscanf(argv[i], \"--num_pages=%d%c\", &n, &junk) == 1) {\n      FLAGS_num_pages = n;\n    } else if (sscanf(argv[i], \"--WAL_enabled=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_WAL_enabled = n;\n    } else if (strncmp(argv[i], \"--db=\", 5) == 0) {\n      FLAGS_db = argv[i] + 5;\n    } else {\n      fprintf(stderr, \"Invalid flag '%s'\\n\", argv[i]);\n      exit(1);\n    }\n  }\n\n  // Choose a location for the test database if none given with --db=<path>\n  if (FLAGS_db == nullptr) {\n    leveldb::Env::Default()->GetTestDirectory(&default_db_path);\n    default_db_path += \"/dbbench\";\n    FLAGS_db = default_db_path.c_str();\n  }\n\n  leveldb::Benchmark benchmark;\n  benchmark.Run();\n  return 0;\n}\n"
  },
  {
    "path": "src/leveldb/benchmarks/db_bench_tree_db.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <kcpolydb.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"util/histogram.h\"\n#include \"util/random.h\"\n#include \"util/testutil.h\"\n\n// Comma-separated list of operations to run in the specified order\n//   Actual benchmarks:\n//\n//   fillseq       -- write N values in sequential key order in async mode\n//   fillrandom    -- write N values in random key order in async mode\n//   overwrite     -- overwrite N values in random key order in async mode\n//   fillseqsync   -- write N/100 values in sequential key order in sync mode\n//   fillrandsync  -- write N/100 values in random key order in sync mode\n//   fillrand100K  -- write N/1000 100K values in random order in async mode\n//   fillseq100K   -- write N/1000 100K values in seq order in async mode\n//   readseq       -- read N times sequentially\n//   readseq100K   -- read N/1000 100K values in sequential order in async mode\n//   readrand100K  -- read N/1000 100K values in sequential order in async mode\n//   readrandom    -- read N times in random order\nstatic const char* FLAGS_benchmarks =\n    \"fillseq,\"\n    \"fillseqsync,\"\n    \"fillrandsync,\"\n    \"fillrandom,\"\n    \"overwrite,\"\n    \"readrandom,\"\n    \"readseq,\"\n    \"fillrand100K,\"\n    \"fillseq100K,\"\n    \"readseq100K,\"\n    \"readrand100K,\";\n\n// Number of key/values to place in database\nstatic int FLAGS_num = 1000000;\n\n// Number of read operations to do.  If negative, do FLAGS_num reads.\nstatic int FLAGS_reads = -1;\n\n// Size of each value\nstatic int FLAGS_value_size = 100;\n\n// Arrange to generate values that shrink to this fraction of\n// their original size after compression\nstatic double FLAGS_compression_ratio = 0.5;\n\n// Print histogram of operation timings\nstatic bool FLAGS_histogram = false;\n\n// Cache size. Default 4 MB\nstatic int FLAGS_cache_size = 4194304;\n\n// Page size. Default 1 KB\nstatic int FLAGS_page_size = 1024;\n\n// If true, do not destroy the existing database.  If you set this\n// flag and also specify a benchmark that wants a fresh database, that\n// benchmark will fail.\nstatic bool FLAGS_use_existing_db = false;\n\n// Compression flag. If true, compression is on. If false, compression\n// is off.\nstatic bool FLAGS_compression = true;\n\n// Use the db with the following name.\nstatic const char* FLAGS_db = nullptr;\n\ninline static void DBSynchronize(kyotocabinet::TreeDB* db_) {\n  // Synchronize will flush writes to disk\n  if (!db_->synchronize()) {\n    fprintf(stderr, \"synchronize error: %s\\n\", db_->error().name());\n  }\n}\n\nnamespace leveldb {\n\n// Helper for quickly generating random data.\nnamespace {\nclass RandomGenerator {\n private:\n  std::string data_;\n  int pos_;\n\n public:\n  RandomGenerator() {\n    // We use a limited amount of data over and over again and ensure\n    // that it is larger than the compression window (32KB), and also\n    // large enough to serve all typical value sizes we want to write.\n    Random rnd(301);\n    std::string piece;\n    while (data_.size() < 1048576) {\n      // Add a short fragment that is as compressible as specified\n      // by FLAGS_compression_ratio.\n      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);\n      data_.append(piece);\n    }\n    pos_ = 0;\n  }\n\n  Slice Generate(int len) {\n    if (pos_ + len > data_.size()) {\n      pos_ = 0;\n      assert(len < data_.size());\n    }\n    pos_ += len;\n    return Slice(data_.data() + pos_ - len, len);\n  }\n};\n\nstatic Slice TrimSpace(Slice s) {\n  int start = 0;\n  while (start < s.size() && isspace(s[start])) {\n    start++;\n  }\n  int limit = s.size();\n  while (limit > start && isspace(s[limit - 1])) {\n    limit--;\n  }\n  return Slice(s.data() + start, limit - start);\n}\n\n}  // namespace\n\nclass Benchmark {\n private:\n  kyotocabinet::TreeDB* db_;\n  int db_num_;\n  int num_;\n  int reads_;\n  double start_;\n  double last_op_finish_;\n  int64_t bytes_;\n  std::string message_;\n  Histogram hist_;\n  RandomGenerator gen_;\n  Random rand_;\n  kyotocabinet::LZOCompressor<kyotocabinet::LZO::RAW> comp_;\n\n  // State kept for progress messages\n  int done_;\n  int next_report_;  // When to report next\n\n  void PrintHeader() {\n    const int kKeySize = 16;\n    PrintEnvironment();\n    fprintf(stdout, \"Keys:       %d bytes each\\n\", kKeySize);\n    fprintf(stdout, \"Values:     %d bytes each (%d bytes after compression)\\n\",\n            FLAGS_value_size,\n            static_cast<int>(FLAGS_value_size * FLAGS_compression_ratio + 0.5));\n    fprintf(stdout, \"Entries:    %d\\n\", num_);\n    fprintf(stdout, \"RawSize:    %.1f MB (estimated)\\n\",\n            ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_) /\n             1048576.0));\n    fprintf(stdout, \"FileSize:   %.1f MB (estimated)\\n\",\n            (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /\n             1048576.0));\n    PrintWarnings();\n    fprintf(stdout, \"------------------------------------------------\\n\");\n  }\n\n  void PrintWarnings() {\n#if defined(__GNUC__) && !defined(__OPTIMIZE__)\n    fprintf(\n        stdout,\n        \"WARNING: Optimization is disabled: benchmarks unnecessarily slow\\n\");\n#endif\n#ifndef NDEBUG\n    fprintf(stdout,\n            \"WARNING: Assertions are enabled; benchmarks unnecessarily slow\\n\");\n#endif\n  }\n\n  void PrintEnvironment() {\n    fprintf(stderr, \"Kyoto Cabinet:    version %s, lib ver %d, lib rev %d\\n\",\n            kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV);\n\n#if defined(__linux)\n    time_t now = time(nullptr);\n    fprintf(stderr, \"Date:           %s\", ctime(&now));  // ctime() adds newline\n\n    FILE* cpuinfo = fopen(\"/proc/cpuinfo\", \"r\");\n    if (cpuinfo != nullptr) {\n      char line[1000];\n      int num_cpus = 0;\n      std::string cpu_type;\n      std::string cache_size;\n      while (fgets(line, sizeof(line), cpuinfo) != nullptr) {\n        const char* sep = strchr(line, ':');\n        if (sep == nullptr) {\n          continue;\n        }\n        Slice key = TrimSpace(Slice(line, sep - 1 - line));\n        Slice val = TrimSpace(Slice(sep + 1));\n        if (key == \"model name\") {\n          ++num_cpus;\n          cpu_type = val.ToString();\n        } else if (key == \"cache size\") {\n          cache_size = val.ToString();\n        }\n      }\n      fclose(cpuinfo);\n      fprintf(stderr, \"CPU:            %d * %s\\n\", num_cpus, cpu_type.c_str());\n      fprintf(stderr, \"CPUCache:       %s\\n\", cache_size.c_str());\n    }\n#endif\n  }\n\n  void Start() {\n    start_ = Env::Default()->NowMicros() * 1e-6;\n    bytes_ = 0;\n    message_.clear();\n    last_op_finish_ = start_;\n    hist_.Clear();\n    done_ = 0;\n    next_report_ = 100;\n  }\n\n  void FinishedSingleOp() {\n    if (FLAGS_histogram) {\n      double now = Env::Default()->NowMicros() * 1e-6;\n      double micros = (now - last_op_finish_) * 1e6;\n      hist_.Add(micros);\n      if (micros > 20000) {\n        fprintf(stderr, \"long op: %.1f micros%30s\\r\", micros, \"\");\n        fflush(stderr);\n      }\n      last_op_finish_ = now;\n    }\n\n    done_++;\n    if (done_ >= next_report_) {\n      if (next_report_ < 1000)\n        next_report_ += 100;\n      else if (next_report_ < 5000)\n        next_report_ += 500;\n      else if (next_report_ < 10000)\n        next_report_ += 1000;\n      else if (next_report_ < 50000)\n        next_report_ += 5000;\n      else if (next_report_ < 100000)\n        next_report_ += 10000;\n      else if (next_report_ < 500000)\n        next_report_ += 50000;\n      else\n        next_report_ += 100000;\n      fprintf(stderr, \"... finished %d ops%30s\\r\", done_, \"\");\n      fflush(stderr);\n    }\n  }\n\n  void Stop(const Slice& name) {\n    double finish = Env::Default()->NowMicros() * 1e-6;\n\n    // Pretend at least one op was done in case we are running a benchmark\n    // that does not call FinishedSingleOp().\n    if (done_ < 1) done_ = 1;\n\n    if (bytes_ > 0) {\n      char rate[100];\n      snprintf(rate, sizeof(rate), \"%6.1f MB/s\",\n               (bytes_ / 1048576.0) / (finish - start_));\n      if (!message_.empty()) {\n        message_ = std::string(rate) + \" \" + message_;\n      } else {\n        message_ = rate;\n      }\n    }\n\n    fprintf(stdout, \"%-12s : %11.3f micros/op;%s%s\\n\", name.ToString().c_str(),\n            (finish - start_) * 1e6 / done_, (message_.empty() ? \"\" : \" \"),\n            message_.c_str());\n    if (FLAGS_histogram) {\n      fprintf(stdout, \"Microseconds per op:\\n%s\\n\", hist_.ToString().c_str());\n    }\n    fflush(stdout);\n  }\n\n public:\n  enum Order { SEQUENTIAL, RANDOM };\n  enum DBState { FRESH, EXISTING };\n\n  Benchmark()\n      : db_(nullptr),\n        num_(FLAGS_num),\n        reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),\n        bytes_(0),\n        rand_(301) {\n    std::vector<std::string> files;\n    std::string test_dir;\n    Env::Default()->GetTestDirectory(&test_dir);\n    Env::Default()->GetChildren(test_dir.c_str(), &files);\n    if (!FLAGS_use_existing_db) {\n      for (int i = 0; i < files.size(); i++) {\n        if (Slice(files[i]).starts_with(\"dbbench_polyDB\")) {\n          std::string file_name(test_dir);\n          file_name += \"/\";\n          file_name += files[i];\n          Env::Default()->DeleteFile(file_name.c_str());\n        }\n      }\n    }\n  }\n\n  ~Benchmark() {\n    if (!db_->close()) {\n      fprintf(stderr, \"close error: %s\\n\", db_->error().name());\n    }\n  }\n\n  void Run() {\n    PrintHeader();\n    Open(false);\n\n    const char* benchmarks = FLAGS_benchmarks;\n    while (benchmarks != nullptr) {\n      const char* sep = strchr(benchmarks, ',');\n      Slice name;\n      if (sep == nullptr) {\n        name = benchmarks;\n        benchmarks = nullptr;\n      } else {\n        name = Slice(benchmarks, sep - benchmarks);\n        benchmarks = sep + 1;\n      }\n\n      Start();\n\n      bool known = true;\n      bool write_sync = false;\n      if (name == Slice(\"fillseq\")) {\n        Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"fillrandom\")) {\n        Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"overwrite\")) {\n        Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"fillrandsync\")) {\n        write_sync = true;\n        Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"fillseqsync\")) {\n        write_sync = true;\n        Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"fillrand100K\")) {\n        Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"fillseq100K\")) {\n        Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1);\n        DBSynchronize(db_);\n      } else if (name == Slice(\"readseq\")) {\n        ReadSequential();\n      } else if (name == Slice(\"readrandom\")) {\n        ReadRandom();\n      } else if (name == Slice(\"readrand100K\")) {\n        int n = reads_;\n        reads_ /= 1000;\n        ReadRandom();\n        reads_ = n;\n      } else if (name == Slice(\"readseq100K\")) {\n        int n = reads_;\n        reads_ /= 1000;\n        ReadSequential();\n        reads_ = n;\n      } else {\n        known = false;\n        if (name != Slice()) {  // No error message for empty name\n          fprintf(stderr, \"unknown benchmark '%s'\\n\", name.ToString().c_str());\n        }\n      }\n      if (known) {\n        Stop(name);\n      }\n    }\n  }\n\n private:\n  void Open(bool sync) {\n    assert(db_ == nullptr);\n\n    // Initialize db_\n    db_ = new kyotocabinet::TreeDB();\n    char file_name[100];\n    db_num_++;\n    std::string test_dir;\n    Env::Default()->GetTestDirectory(&test_dir);\n    snprintf(file_name, sizeof(file_name), \"%s/dbbench_polyDB-%d.kct\",\n             test_dir.c_str(), db_num_);\n\n    // Create tuning options and open the database\n    int open_options =\n        kyotocabinet::PolyDB::OWRITER | kyotocabinet::PolyDB::OCREATE;\n    int tune_options =\n        kyotocabinet::TreeDB::TSMALL | kyotocabinet::TreeDB::TLINEAR;\n    if (FLAGS_compression) {\n      tune_options |= kyotocabinet::TreeDB::TCOMPRESS;\n      db_->tune_compressor(&comp_);\n    }\n    db_->tune_options(tune_options);\n    db_->tune_page_cache(FLAGS_cache_size);\n    db_->tune_page(FLAGS_page_size);\n    db_->tune_map(256LL << 20);\n    if (sync) {\n      open_options |= kyotocabinet::PolyDB::OAUTOSYNC;\n    }\n    if (!db_->open(file_name, open_options)) {\n      fprintf(stderr, \"open error: %s\\n\", db_->error().name());\n    }\n  }\n\n  void Write(bool sync, Order order, DBState state, int num_entries,\n             int value_size, int entries_per_batch) {\n    // Create new database if state == FRESH\n    if (state == FRESH) {\n      if (FLAGS_use_existing_db) {\n        message_ = \"skipping (--use_existing_db is true)\";\n        return;\n      }\n      delete db_;\n      db_ = nullptr;\n      Open(sync);\n      Start();  // Do not count time taken to destroy/open\n    }\n\n    if (num_entries != num_) {\n      char msg[100];\n      snprintf(msg, sizeof(msg), \"(%d ops)\", num_entries);\n      message_ = msg;\n    }\n\n    // Write to database\n    for (int i = 0; i < num_entries; i++) {\n      const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries);\n      char key[100];\n      snprintf(key, sizeof(key), \"%016d\", k);\n      bytes_ += value_size + strlen(key);\n      std::string cpp_key = key;\n      if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) {\n        fprintf(stderr, \"set error: %s\\n\", db_->error().name());\n      }\n      FinishedSingleOp();\n    }\n  }\n\n  void ReadSequential() {\n    kyotocabinet::DB::Cursor* cur = db_->cursor();\n    cur->jump();\n    std::string ckey, cvalue;\n    while (cur->get(&ckey, &cvalue, true)) {\n      bytes_ += ckey.size() + cvalue.size();\n      FinishedSingleOp();\n    }\n    delete cur;\n  }\n\n  void ReadRandom() {\n    std::string value;\n    for (int i = 0; i < reads_; i++) {\n      char key[100];\n      const int k = rand_.Next() % reads_;\n      snprintf(key, sizeof(key), \"%016d\", k);\n      db_->get(key, &value);\n      FinishedSingleOp();\n    }\n  }\n};\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n  std::string default_db_path;\n  for (int i = 1; i < argc; i++) {\n    double d;\n    int n;\n    char junk;\n    if (leveldb::Slice(argv[i]).starts_with(\"--benchmarks=\")) {\n      FLAGS_benchmarks = argv[i] + strlen(\"--benchmarks=\");\n    } else if (sscanf(argv[i], \"--compression_ratio=%lf%c\", &d, &junk) == 1) {\n      FLAGS_compression_ratio = d;\n    } else if (sscanf(argv[i], \"--histogram=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_histogram = n;\n    } else if (sscanf(argv[i], \"--num=%d%c\", &n, &junk) == 1) {\n      FLAGS_num = n;\n    } else if (sscanf(argv[i], \"--reads=%d%c\", &n, &junk) == 1) {\n      FLAGS_reads = n;\n    } else if (sscanf(argv[i], \"--value_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_value_size = n;\n    } else if (sscanf(argv[i], \"--cache_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_cache_size = n;\n    } else if (sscanf(argv[i], \"--page_size=%d%c\", &n, &junk) == 1) {\n      FLAGS_page_size = n;\n    } else if (sscanf(argv[i], \"--compression=%d%c\", &n, &junk) == 1 &&\n               (n == 0 || n == 1)) {\n      FLAGS_compression = (n == 1) ? true : false;\n    } else if (strncmp(argv[i], \"--db=\", 5) == 0) {\n      FLAGS_db = argv[i] + 5;\n    } else {\n      fprintf(stderr, \"Invalid flag '%s'\\n\", argv[i]);\n      exit(1);\n    }\n  }\n\n  // Choose a location for the test database if none given with --db=<path>\n  if (FLAGS_db == nullptr) {\n    leveldb::Env::Default()->GetTestDirectory(&default_db_path);\n    default_db_path += \"/dbbench\";\n    FLAGS_db = default_db_path.c_str();\n  }\n\n  leveldb::Benchmark benchmark;\n  benchmark.Run();\n  return 0;\n}\n"
  },
  {
    "path": "src/leveldb/cmake/leveldbConfig.cmake",
    "content": "include(\"${CMAKE_CURRENT_LIST_DIR}/leveldbTargets.cmake\")\n"
  },
  {
    "path": "src/leveldb/db/autocompact_test.cc",
    "content": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/db_impl.h\"\n#include \"leveldb/cache.h\"\n#include \"leveldb/db.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nclass AutoCompactTest {\n public:\n  AutoCompactTest() {\n    dbname_ = test::TmpDir() + \"/autocompact_test\";\n    tiny_cache_ = NewLRUCache(100);\n    options_.block_cache = tiny_cache_;\n    DestroyDB(dbname_, options_);\n    options_.create_if_missing = true;\n    options_.compression = kNoCompression;\n    ASSERT_OK(DB::Open(options_, dbname_, &db_));\n  }\n\n  ~AutoCompactTest() {\n    delete db_;\n    DestroyDB(dbname_, Options());\n    delete tiny_cache_;\n  }\n\n  std::string Key(int i) {\n    char buf[100];\n    snprintf(buf, sizeof(buf), \"key%06d\", i);\n    return std::string(buf);\n  }\n\n  uint64_t Size(const Slice& start, const Slice& limit) {\n    Range r(start, limit);\n    uint64_t size;\n    db_->GetApproximateSizes(&r, 1, &size);\n    return size;\n  }\n\n  void DoReads(int n);\n\n private:\n  std::string dbname_;\n  Cache* tiny_cache_;\n  Options options_;\n  DB* db_;\n};\n\nstatic const int kValueSize = 200 * 1024;\nstatic const int kTotalSize = 100 * 1024 * 1024;\nstatic const int kCount = kTotalSize / kValueSize;\n\n// Read through the first n keys repeatedly and check that they get\n// compacted (verified by checking the size of the key space).\nvoid AutoCompactTest::DoReads(int n) {\n  std::string value(kValueSize, 'x');\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n\n  // Fill database\n  for (int i = 0; i < kCount; i++) {\n    ASSERT_OK(db_->Put(WriteOptions(), Key(i), value));\n  }\n  ASSERT_OK(dbi->TEST_CompactMemTable());\n\n  // Delete everything\n  for (int i = 0; i < kCount; i++) {\n    ASSERT_OK(db_->Delete(WriteOptions(), Key(i)));\n  }\n  ASSERT_OK(dbi->TEST_CompactMemTable());\n\n  // Get initial measurement of the space we will be reading.\n  const int64_t initial_size = Size(Key(0), Key(n));\n  const int64_t initial_other_size = Size(Key(n), Key(kCount));\n\n  // Read until size drops significantly.\n  std::string limit_key = Key(n);\n  for (int read = 0; true; read++) {\n    ASSERT_LT(read, 100) << \"Taking too long to compact\";\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    for (iter->SeekToFirst();\n         iter->Valid() && iter->key().ToString() < limit_key; iter->Next()) {\n      // Drop data\n    }\n    delete iter;\n    // Wait a little bit to allow any triggered compactions to complete.\n    Env::Default()->SleepForMicroseconds(1000000);\n    uint64_t size = Size(Key(0), Key(n));\n    fprintf(stderr, \"iter %3d => %7.3f MB [other %7.3f MB]\\n\", read + 1,\n            size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0);\n    if (size <= initial_size / 10) {\n      break;\n    }\n  }\n\n  // Verify that the size of the key space not touched by the reads\n  // is pretty much unchanged.\n  const int64_t final_other_size = Size(Key(n), Key(kCount));\n  ASSERT_LE(final_other_size, initial_other_size + 1048576);\n  ASSERT_GE(final_other_size, initial_other_size / 5 - 1048576);\n}\n\nTEST(AutoCompactTest, ReadAll) { DoReads(kCount); }\n\nTEST(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); }\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/builder.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/builder.h\"\n\n#include \"db/dbformat.h\"\n#include \"db/filename.h\"\n#include \"db/table_cache.h\"\n#include \"db/version_edit.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/iterator.h\"\n\nnamespace leveldb {\n\nStatus BuildTable(const std::string& dbname, Env* env, const Options& options,\n                  TableCache* table_cache, Iterator* iter, FileMetaData* meta) {\n  Status s;\n  meta->file_size = 0;\n  iter->SeekToFirst();\n\n  std::string fname = TableFileName(dbname, meta->number);\n  if (iter->Valid()) {\n    WritableFile* file;\n    s = env->NewWritableFile(fname, &file);\n    if (!s.ok()) {\n      return s;\n    }\n\n    TableBuilder* builder = new TableBuilder(options, file);\n    meta->smallest.DecodeFrom(iter->key());\n    for (; iter->Valid(); iter->Next()) {\n      Slice key = iter->key();\n      meta->largest.DecodeFrom(key);\n      builder->Add(key, iter->value());\n    }\n\n    // Finish and check for builder errors\n    s = builder->Finish();\n    if (s.ok()) {\n      meta->file_size = builder->FileSize();\n      assert(meta->file_size > 0);\n    }\n    delete builder;\n\n    // Finish and check for file errors\n    if (s.ok()) {\n      s = file->Sync();\n    }\n    if (s.ok()) {\n      s = file->Close();\n    }\n    delete file;\n    file = nullptr;\n\n    if (s.ok()) {\n      // Verify that the table is usable\n      Iterator* it = table_cache->NewIterator(ReadOptions(), meta->number,\n                                              meta->file_size);\n      s = it->status();\n      delete it;\n    }\n  }\n\n  // Check for input iterator errors\n  if (!iter->status().ok()) {\n    s = iter->status();\n  }\n\n  if (s.ok() && meta->file_size > 0) {\n    // Keep it\n  } else {\n    env->DeleteFile(fname);\n  }\n  return s;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/builder.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_BUILDER_H_\n#define STORAGE_LEVELDB_DB_BUILDER_H_\n\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nstruct Options;\nstruct FileMetaData;\n\nclass Env;\nclass Iterator;\nclass TableCache;\nclass VersionEdit;\n\n// Build a Table file from the contents of *iter.  The generated file\n// will be named according to meta->number.  On success, the rest of\n// *meta will be filled with metadata about the generated table.\n// If no data is present in *iter, meta->file_size will be set to\n// zero, and no Table file will be produced.\nStatus BuildTable(const std::string& dbname, Env* env, const Options& options,\n                  TableCache* table_cache, Iterator* iter, FileMetaData* meta);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_BUILDER_H_\n"
  },
  {
    "path": "src/leveldb/db/c.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/c.h\"\n\n#include <cstdint>\n#include <cstdlib>\n\n#include \"leveldb/cache.h\"\n#include \"leveldb/comparator.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/iterator.h\"\n#include \"leveldb/options.h\"\n#include \"leveldb/status.h\"\n#include \"leveldb/write_batch.h\"\n\nusing leveldb::Cache;\nusing leveldb::Comparator;\nusing leveldb::CompressionType;\nusing leveldb::DB;\nusing leveldb::Env;\nusing leveldb::FileLock;\nusing leveldb::FilterPolicy;\nusing leveldb::Iterator;\nusing leveldb::kMajorVersion;\nusing leveldb::kMinorVersion;\nusing leveldb::Logger;\nusing leveldb::NewBloomFilterPolicy;\nusing leveldb::NewLRUCache;\nusing leveldb::Options;\nusing leveldb::RandomAccessFile;\nusing leveldb::Range;\nusing leveldb::ReadOptions;\nusing leveldb::SequentialFile;\nusing leveldb::Slice;\nusing leveldb::Snapshot;\nusing leveldb::Status;\nusing leveldb::WritableFile;\nusing leveldb::WriteBatch;\nusing leveldb::WriteOptions;\n\nextern \"C\" {\n\nstruct leveldb_t {\n  DB* rep;\n};\nstruct leveldb_iterator_t {\n  Iterator* rep;\n};\nstruct leveldb_writebatch_t {\n  WriteBatch rep;\n};\nstruct leveldb_snapshot_t {\n  const Snapshot* rep;\n};\nstruct leveldb_readoptions_t {\n  ReadOptions rep;\n};\nstruct leveldb_writeoptions_t {\n  WriteOptions rep;\n};\nstruct leveldb_options_t {\n  Options rep;\n};\nstruct leveldb_cache_t {\n  Cache* rep;\n};\nstruct leveldb_seqfile_t {\n  SequentialFile* rep;\n};\nstruct leveldb_randomfile_t {\n  RandomAccessFile* rep;\n};\nstruct leveldb_writablefile_t {\n  WritableFile* rep;\n};\nstruct leveldb_logger_t {\n  Logger* rep;\n};\nstruct leveldb_filelock_t {\n  FileLock* rep;\n};\n\nstruct leveldb_comparator_t : public Comparator {\n  ~leveldb_comparator_t() override { (*destructor_)(state_); }\n\n  int Compare(const Slice& a, const Slice& b) const override {\n    return (*compare_)(state_, a.data(), a.size(), b.data(), b.size());\n  }\n\n  const char* Name() const override { return (*name_)(state_); }\n\n  // No-ops since the C binding does not support key shortening methods.\n  void FindShortestSeparator(std::string*, const Slice&) const override {}\n  void FindShortSuccessor(std::string* key) const override {}\n\n  void* state_;\n  void (*destructor_)(void*);\n  int (*compare_)(void*, const char* a, size_t alen, const char* b,\n                  size_t blen);\n  const char* (*name_)(void*);\n};\n\nstruct leveldb_filterpolicy_t : public FilterPolicy {\n  ~leveldb_filterpolicy_t() override { (*destructor_)(state_); }\n\n  const char* Name() const override { return (*name_)(state_); }\n\n  void CreateFilter(const Slice* keys, int n, std::string* dst) const override {\n    std::vector<const char*> key_pointers(n);\n    std::vector<size_t> key_sizes(n);\n    for (int i = 0; i < n; i++) {\n      key_pointers[i] = keys[i].data();\n      key_sizes[i] = keys[i].size();\n    }\n    size_t len;\n    char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len);\n    dst->append(filter, len);\n    free(filter);\n  }\n\n  bool KeyMayMatch(const Slice& key, const Slice& filter) const override {\n    return (*key_match_)(state_, key.data(), key.size(), filter.data(),\n                         filter.size());\n  }\n\n  void* state_;\n  void (*destructor_)(void*);\n  const char* (*name_)(void*);\n  char* (*create_)(void*, const char* const* key_array,\n                   const size_t* key_length_array, int num_keys,\n                   size_t* filter_length);\n  uint8_t (*key_match_)(void*, const char* key, size_t length,\n                        const char* filter, size_t filter_length);\n};\n\nstruct leveldb_env_t {\n  Env* rep;\n  bool is_default;\n};\n\nstatic bool SaveError(char** errptr, const Status& s) {\n  assert(errptr != nullptr);\n  if (s.ok()) {\n    return false;\n  } else if (*errptr == nullptr) {\n    *errptr = strdup(s.ToString().c_str());\n  } else {\n    // TODO(sanjay): Merge with existing error?\n    free(*errptr);\n    *errptr = strdup(s.ToString().c_str());\n  }\n  return true;\n}\n\nstatic char* CopyString(const std::string& str) {\n  char* result = reinterpret_cast<char*>(malloc(sizeof(char) * str.size()));\n  memcpy(result, str.data(), sizeof(char) * str.size());\n  return result;\n}\n\nleveldb_t* leveldb_open(const leveldb_options_t* options, const char* name,\n                        char** errptr) {\n  DB* db;\n  if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) {\n    return nullptr;\n  }\n  leveldb_t* result = new leveldb_t;\n  result->rep = db;\n  return result;\n}\n\nvoid leveldb_close(leveldb_t* db) {\n  delete db->rep;\n  delete db;\n}\n\nvoid leveldb_put(leveldb_t* db, const leveldb_writeoptions_t* options,\n                 const char* key, size_t keylen, const char* val, size_t vallen,\n                 char** errptr) {\n  SaveError(errptr,\n            db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen)));\n}\n\nvoid leveldb_delete(leveldb_t* db, const leveldb_writeoptions_t* options,\n                    const char* key, size_t keylen, char** errptr) {\n  SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen)));\n}\n\nvoid leveldb_write(leveldb_t* db, const leveldb_writeoptions_t* options,\n                   leveldb_writebatch_t* batch, char** errptr) {\n  SaveError(errptr, db->rep->Write(options->rep, &batch->rep));\n}\n\nchar* leveldb_get(leveldb_t* db, const leveldb_readoptions_t* options,\n                  const char* key, size_t keylen, size_t* vallen,\n                  char** errptr) {\n  char* result = nullptr;\n  std::string tmp;\n  Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp);\n  if (s.ok()) {\n    *vallen = tmp.size();\n    result = CopyString(tmp);\n  } else {\n    *vallen = 0;\n    if (!s.IsNotFound()) {\n      SaveError(errptr, s);\n    }\n  }\n  return result;\n}\n\nleveldb_iterator_t* leveldb_create_iterator(\n    leveldb_t* db, const leveldb_readoptions_t* options) {\n  leveldb_iterator_t* result = new leveldb_iterator_t;\n  result->rep = db->rep->NewIterator(options->rep);\n  return result;\n}\n\nconst leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db) {\n  leveldb_snapshot_t* result = new leveldb_snapshot_t;\n  result->rep = db->rep->GetSnapshot();\n  return result;\n}\n\nvoid leveldb_release_snapshot(leveldb_t* db,\n                              const leveldb_snapshot_t* snapshot) {\n  db->rep->ReleaseSnapshot(snapshot->rep);\n  delete snapshot;\n}\n\nchar* leveldb_property_value(leveldb_t* db, const char* propname) {\n  std::string tmp;\n  if (db->rep->GetProperty(Slice(propname), &tmp)) {\n    // We use strdup() since we expect human readable output.\n    return strdup(tmp.c_str());\n  } else {\n    return nullptr;\n  }\n}\n\nvoid leveldb_approximate_sizes(leveldb_t* db, int num_ranges,\n                               const char* const* range_start_key,\n                               const size_t* range_start_key_len,\n                               const char* const* range_limit_key,\n                               const size_t* range_limit_key_len,\n                               uint64_t* sizes) {\n  Range* ranges = new Range[num_ranges];\n  for (int i = 0; i < num_ranges; i++) {\n    ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);\n    ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);\n  }\n  db->rep->GetApproximateSizes(ranges, num_ranges, sizes);\n  delete[] ranges;\n}\n\nvoid leveldb_compact_range(leveldb_t* db, const char* start_key,\n                           size_t start_key_len, const char* limit_key,\n                           size_t limit_key_len) {\n  Slice a, b;\n  db->rep->CompactRange(\n      // Pass null Slice if corresponding \"const char*\" is null\n      (start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr),\n      (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr));\n}\n\nvoid leveldb_destroy_db(const leveldb_options_t* options, const char* name,\n                        char** errptr) {\n  SaveError(errptr, DestroyDB(name, options->rep));\n}\n\nvoid leveldb_repair_db(const leveldb_options_t* options, const char* name,\n                       char** errptr) {\n  SaveError(errptr, RepairDB(name, options->rep));\n}\n\nvoid leveldb_iter_destroy(leveldb_iterator_t* iter) {\n  delete iter->rep;\n  delete iter;\n}\n\nuint8_t leveldb_iter_valid(const leveldb_iterator_t* iter) {\n  return iter->rep->Valid();\n}\n\nvoid leveldb_iter_seek_to_first(leveldb_iterator_t* iter) {\n  iter->rep->SeekToFirst();\n}\n\nvoid leveldb_iter_seek_to_last(leveldb_iterator_t* iter) {\n  iter->rep->SeekToLast();\n}\n\nvoid leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) {\n  iter->rep->Seek(Slice(k, klen));\n}\n\nvoid leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); }\n\nvoid leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); }\n\nconst char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) {\n  Slice s = iter->rep->key();\n  *klen = s.size();\n  return s.data();\n}\n\nconst char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) {\n  Slice s = iter->rep->value();\n  *vlen = s.size();\n  return s.data();\n}\n\nvoid leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) {\n  SaveError(errptr, iter->rep->status());\n}\n\nleveldb_writebatch_t* leveldb_writebatch_create() {\n  return new leveldb_writebatch_t;\n}\n\nvoid leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; }\n\nvoid leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); }\n\nvoid leveldb_writebatch_put(leveldb_writebatch_t* b, const char* key,\n                            size_t klen, const char* val, size_t vlen) {\n  b->rep.Put(Slice(key, klen), Slice(val, vlen));\n}\n\nvoid leveldb_writebatch_delete(leveldb_writebatch_t* b, const char* key,\n                               size_t klen) {\n  b->rep.Delete(Slice(key, klen));\n}\n\nvoid leveldb_writebatch_iterate(const leveldb_writebatch_t* b, void* state,\n                                void (*put)(void*, const char* k, size_t klen,\n                                            const char* v, size_t vlen),\n                                void (*deleted)(void*, const char* k,\n                                                size_t klen)) {\n  class H : public WriteBatch::Handler {\n   public:\n    void* state_;\n    void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen);\n    void (*deleted_)(void*, const char* k, size_t klen);\n    void Put(const Slice& key, const Slice& value) override {\n      (*put_)(state_, key.data(), key.size(), value.data(), value.size());\n    }\n    void Delete(const Slice& key) override {\n      (*deleted_)(state_, key.data(), key.size());\n    }\n  };\n  H handler;\n  handler.state_ = state;\n  handler.put_ = put;\n  handler.deleted_ = deleted;\n  b->rep.Iterate(&handler);\n}\n\nvoid leveldb_writebatch_append(leveldb_writebatch_t* destination,\n                               const leveldb_writebatch_t* source) {\n  destination->rep.Append(source->rep);\n}\n\nleveldb_options_t* leveldb_options_create() { return new leveldb_options_t; }\n\nvoid leveldb_options_destroy(leveldb_options_t* options) { delete options; }\n\nvoid leveldb_options_set_comparator(leveldb_options_t* opt,\n                                    leveldb_comparator_t* cmp) {\n  opt->rep.comparator = cmp;\n}\n\nvoid leveldb_options_set_filter_policy(leveldb_options_t* opt,\n                                       leveldb_filterpolicy_t* policy) {\n  opt->rep.filter_policy = policy;\n}\n\nvoid leveldb_options_set_create_if_missing(leveldb_options_t* opt, uint8_t v) {\n  opt->rep.create_if_missing = v;\n}\n\nvoid leveldb_options_set_error_if_exists(leveldb_options_t* opt, uint8_t v) {\n  opt->rep.error_if_exists = v;\n}\n\nvoid leveldb_options_set_paranoid_checks(leveldb_options_t* opt, uint8_t v) {\n  opt->rep.paranoid_checks = v;\n}\n\nvoid leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) {\n  opt->rep.env = (env ? env->rep : nullptr);\n}\n\nvoid leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) {\n  opt->rep.info_log = (l ? l->rep : nullptr);\n}\n\nvoid leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) {\n  opt->rep.write_buffer_size = s;\n}\n\nvoid leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) {\n  opt->rep.max_open_files = n;\n}\n\nvoid leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) {\n  opt->rep.block_cache = c->rep;\n}\n\nvoid leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) {\n  opt->rep.block_size = s;\n}\n\nvoid leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) {\n  opt->rep.block_restart_interval = n;\n}\n\nvoid leveldb_options_set_max_file_size(leveldb_options_t* opt, size_t s) {\n  opt->rep.max_file_size = s;\n}\n\nvoid leveldb_options_set_compression(leveldb_options_t* opt, int t) {\n  opt->rep.compression = static_cast<CompressionType>(t);\n}\n\nleveldb_comparator_t* leveldb_comparator_create(\n    void* state, void (*destructor)(void*),\n    int (*compare)(void*, const char* a, size_t alen, const char* b,\n                   size_t blen),\n    const char* (*name)(void*)) {\n  leveldb_comparator_t* result = new leveldb_comparator_t;\n  result->state_ = state;\n  result->destructor_ = destructor;\n  result->compare_ = compare;\n  result->name_ = name;\n  return result;\n}\n\nvoid leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; }\n\nleveldb_filterpolicy_t* leveldb_filterpolicy_create(\n    void* state, void (*destructor)(void*),\n    char* (*create_filter)(void*, const char* const* key_array,\n                           const size_t* key_length_array, int num_keys,\n                           size_t* filter_length),\n    uint8_t (*key_may_match)(void*, const char* key, size_t length,\n                             const char* filter, size_t filter_length),\n    const char* (*name)(void*)) {\n  leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t;\n  result->state_ = state;\n  result->destructor_ = destructor;\n  result->create_ = create_filter;\n  result->key_match_ = key_may_match;\n  result->name_ = name;\n  return result;\n}\n\nvoid leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) {\n  delete filter;\n}\n\nleveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) {\n  // Make a leveldb_filterpolicy_t, but override all of its methods so\n  // they delegate to a NewBloomFilterPolicy() instead of user\n  // supplied C functions.\n  struct Wrapper : public leveldb_filterpolicy_t {\n    static void DoNothing(void*) {}\n\n    ~Wrapper() { delete rep_; }\n    const char* Name() const { return rep_->Name(); }\n    void CreateFilter(const Slice* keys, int n, std::string* dst) const {\n      return rep_->CreateFilter(keys, n, dst);\n    }\n    bool KeyMayMatch(const Slice& key, const Slice& filter) const {\n      return rep_->KeyMayMatch(key, filter);\n    }\n\n    const FilterPolicy* rep_;\n  };\n  Wrapper* wrapper = new Wrapper;\n  wrapper->rep_ = NewBloomFilterPolicy(bits_per_key);\n  wrapper->state_ = nullptr;\n  wrapper->destructor_ = &Wrapper::DoNothing;\n  return wrapper;\n}\n\nleveldb_readoptions_t* leveldb_readoptions_create() {\n  return new leveldb_readoptions_t;\n}\n\nvoid leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete opt; }\n\nvoid leveldb_readoptions_set_verify_checksums(leveldb_readoptions_t* opt,\n                                              uint8_t v) {\n  opt->rep.verify_checksums = v;\n}\n\nvoid leveldb_readoptions_set_fill_cache(leveldb_readoptions_t* opt, uint8_t v) {\n  opt->rep.fill_cache = v;\n}\n\nvoid leveldb_readoptions_set_snapshot(leveldb_readoptions_t* opt,\n                                      const leveldb_snapshot_t* snap) {\n  opt->rep.snapshot = (snap ? snap->rep : nullptr);\n}\n\nleveldb_writeoptions_t* leveldb_writeoptions_create() {\n  return new leveldb_writeoptions_t;\n}\n\nvoid leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete opt; }\n\nvoid leveldb_writeoptions_set_sync(leveldb_writeoptions_t* opt, uint8_t v) {\n  opt->rep.sync = v;\n}\n\nleveldb_cache_t* leveldb_cache_create_lru(size_t capacity) {\n  leveldb_cache_t* c = new leveldb_cache_t;\n  c->rep = NewLRUCache(capacity);\n  return c;\n}\n\nvoid leveldb_cache_destroy(leveldb_cache_t* cache) {\n  delete cache->rep;\n  delete cache;\n}\n\nleveldb_env_t* leveldb_create_default_env() {\n  leveldb_env_t* result = new leveldb_env_t;\n  result->rep = Env::Default();\n  result->is_default = true;\n  return result;\n}\n\nvoid leveldb_env_destroy(leveldb_env_t* env) {\n  if (!env->is_default) delete env->rep;\n  delete env;\n}\n\nchar* leveldb_env_get_test_directory(leveldb_env_t* env) {\n  std::string result;\n  if (!env->rep->GetTestDirectory(&result).ok()) {\n    return nullptr;\n  }\n\n  char* buffer = static_cast<char*>(malloc(result.size() + 1));\n  memcpy(buffer, result.data(), result.size());\n  buffer[result.size()] = '\\0';\n  return buffer;\n}\n\nvoid leveldb_free(void* ptr) { free(ptr); }\n\nint leveldb_major_version() { return kMajorVersion; }\n\nint leveldb_minor_version() { return kMinorVersion; }\n\n}  // end extern \"C\"\n"
  },
  {
    "path": "src/leveldb/db/c_test.c",
    "content": "/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n   Use of this source code is governed by a BSD-style license that can be\n   found in the LICENSE file. See the AUTHORS file for names of contributors. */\n\n#include \"leveldb/c.h\"\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nconst char* phase = \"\";\n\nstatic void StartPhase(const char* name) {\n  fprintf(stderr, \"=== Test %s\\n\", name);\n  phase = name;\n}\n\n#define CheckNoError(err)                                               \\\n  if ((err) != NULL) {                                                  \\\n    fprintf(stderr, \"%s:%d: %s: %s\\n\", __FILE__, __LINE__, phase, (err)); \\\n    abort();                                                            \\\n  }\n\n#define CheckCondition(cond)                                            \\\n  if (!(cond)) {                                                        \\\n    fprintf(stderr, \"%s:%d: %s: %s\\n\", __FILE__, __LINE__, phase, #cond); \\\n    abort();                                                            \\\n  }\n\nstatic void CheckEqual(const char* expected, const char* v, size_t n) {\n  if (expected == NULL && v == NULL) {\n    // ok\n  } else if (expected != NULL && v != NULL && n == strlen(expected) &&\n             memcmp(expected, v, n) == 0) {\n    // ok\n    return;\n  } else {\n    fprintf(stderr, \"%s: expected '%s', got '%s'\\n\",\n            phase,\n            (expected ? expected : \"(null)\"),\n            (v ? v : \"(null\"));\n    abort();\n  }\n}\n\nstatic void Free(char** ptr) {\n  if (*ptr) {\n    free(*ptr);\n    *ptr = NULL;\n  }\n}\n\nstatic void CheckGet(\n    leveldb_t* db,\n    const leveldb_readoptions_t* options,\n    const char* key,\n    const char* expected) {\n  char* err = NULL;\n  size_t val_len;\n  char* val;\n  val = leveldb_get(db, options, key, strlen(key), &val_len, &err);\n  CheckNoError(err);\n  CheckEqual(expected, val, val_len);\n  Free(&val);\n}\n\nstatic void CheckIter(leveldb_iterator_t* iter,\n                      const char* key, const char* val) {\n  size_t len;\n  const char* str;\n  str = leveldb_iter_key(iter, &len);\n  CheckEqual(key, str, len);\n  str = leveldb_iter_value(iter, &len);\n  CheckEqual(val, str, len);\n}\n\n// Callback from leveldb_writebatch_iterate()\nstatic void CheckPut(void* ptr,\n                     const char* k, size_t klen,\n                     const char* v, size_t vlen) {\n  int* state = (int*) ptr;\n  CheckCondition(*state < 2);\n  switch (*state) {\n    case 0:\n      CheckEqual(\"bar\", k, klen);\n      CheckEqual(\"b\", v, vlen);\n      break;\n    case 1:\n      CheckEqual(\"box\", k, klen);\n      CheckEqual(\"c\", v, vlen);\n      break;\n  }\n  (*state)++;\n}\n\n// Callback from leveldb_writebatch_iterate()\nstatic void CheckDel(void* ptr, const char* k, size_t klen) {\n  int* state = (int*) ptr;\n  CheckCondition(*state == 2);\n  CheckEqual(\"bar\", k, klen);\n  (*state)++;\n}\n\nstatic void CmpDestroy(void* arg) { }\n\nstatic int CmpCompare(void* arg, const char* a, size_t alen,\n                      const char* b, size_t blen) {\n  int n = (alen < blen) ? alen : blen;\n  int r = memcmp(a, b, n);\n  if (r == 0) {\n    if (alen < blen) r = -1;\n    else if (alen > blen) r = +1;\n  }\n  return r;\n}\n\nstatic const char* CmpName(void* arg) {\n  return \"foo\";\n}\n\n// Custom filter policy\nstatic uint8_t fake_filter_result = 1;\nstatic void FilterDestroy(void* arg) { }\nstatic const char* FilterName(void* arg) {\n  return \"TestFilter\";\n}\nstatic char* FilterCreate(\n    void* arg,\n    const char* const* key_array, const size_t* key_length_array,\n    int num_keys,\n    size_t* filter_length) {\n  *filter_length = 4;\n  char* result = malloc(4);\n  memcpy(result, \"fake\", 4);\n  return result;\n}\nuint8_t FilterKeyMatch(void* arg, const char* key, size_t length,\n                       const char* filter, size_t filter_length) {\n  CheckCondition(filter_length == 4);\n  CheckCondition(memcmp(filter, \"fake\", 4) == 0);\n  return fake_filter_result;\n}\n\nint main(int argc, char** argv) {\n  leveldb_t* db;\n  leveldb_comparator_t* cmp;\n  leveldb_cache_t* cache;\n  leveldb_env_t* env;\n  leveldb_options_t* options;\n  leveldb_readoptions_t* roptions;\n  leveldb_writeoptions_t* woptions;\n  char* dbname;\n  char* err = NULL;\n  int run = -1;\n\n  CheckCondition(leveldb_major_version() >= 1);\n  CheckCondition(leveldb_minor_version() >= 1);\n\n  StartPhase(\"create_objects\");\n  cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);\n  env = leveldb_create_default_env();\n  cache = leveldb_cache_create_lru(100000);\n  dbname = leveldb_env_get_test_directory(env);\n  CheckCondition(dbname != NULL);\n\n  options = leveldb_options_create();\n  leveldb_options_set_comparator(options, cmp);\n  leveldb_options_set_error_if_exists(options, 1);\n  leveldb_options_set_cache(options, cache);\n  leveldb_options_set_env(options, env);\n  leveldb_options_set_info_log(options, NULL);\n  leveldb_options_set_write_buffer_size(options, 100000);\n  leveldb_options_set_paranoid_checks(options, 1);\n  leveldb_options_set_max_open_files(options, 10);\n  leveldb_options_set_block_size(options, 1024);\n  leveldb_options_set_block_restart_interval(options, 8);\n  leveldb_options_set_max_file_size(options, 3 << 20);\n  leveldb_options_set_compression(options, leveldb_no_compression);\n\n  roptions = leveldb_readoptions_create();\n  leveldb_readoptions_set_verify_checksums(roptions, 1);\n  leveldb_readoptions_set_fill_cache(roptions, 0);\n\n  woptions = leveldb_writeoptions_create();\n  leveldb_writeoptions_set_sync(woptions, 1);\n\n  StartPhase(\"destroy\");\n  leveldb_destroy_db(options, dbname, &err);\n  Free(&err);\n\n  StartPhase(\"open_error\");\n  db = leveldb_open(options, dbname, &err);\n  CheckCondition(err != NULL);\n  Free(&err);\n\n  StartPhase(\"leveldb_free\");\n  db = leveldb_open(options, dbname, &err);\n  CheckCondition(err != NULL);\n  leveldb_free(err);\n  err = NULL;\n\n  StartPhase(\"open\");\n  leveldb_options_set_create_if_missing(options, 1);\n  db = leveldb_open(options, dbname, &err);\n  CheckNoError(err);\n  CheckGet(db, roptions, \"foo\", NULL);\n\n  StartPhase(\"put\");\n  leveldb_put(db, woptions, \"foo\", 3, \"hello\", 5, &err);\n  CheckNoError(err);\n  CheckGet(db, roptions, \"foo\", \"hello\");\n\n  StartPhase(\"compactall\");\n  leveldb_compact_range(db, NULL, 0, NULL, 0);\n  CheckGet(db, roptions, \"foo\", \"hello\");\n\n  StartPhase(\"compactrange\");\n  leveldb_compact_range(db, \"a\", 1, \"z\", 1);\n  CheckGet(db, roptions, \"foo\", \"hello\");\n\n  StartPhase(\"writebatch\");\n  {\n    leveldb_writebatch_t* wb = leveldb_writebatch_create();\n    leveldb_writebatch_put(wb, \"foo\", 3, \"a\", 1);\n    leveldb_writebatch_clear(wb);\n    leveldb_writebatch_put(wb, \"bar\", 3, \"b\", 1);\n    leveldb_writebatch_put(wb, \"box\", 3, \"c\", 1);\n\n    leveldb_writebatch_t* wb2 = leveldb_writebatch_create();\n    leveldb_writebatch_delete(wb2, \"bar\", 3);\n    leveldb_writebatch_append(wb, wb2);\n    leveldb_writebatch_destroy(wb2);\n\n    leveldb_write(db, woptions, wb, &err);\n    CheckNoError(err);\n    CheckGet(db, roptions, \"foo\", \"hello\");\n    CheckGet(db, roptions, \"bar\", NULL);\n    CheckGet(db, roptions, \"box\", \"c\");\n\n    int pos = 0;\n    leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel);\n    CheckCondition(pos == 3);\n    leveldb_writebatch_destroy(wb);\n  }\n\n  StartPhase(\"iter\");\n  {\n    leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions);\n    CheckCondition(!leveldb_iter_valid(iter));\n    leveldb_iter_seek_to_first(iter);\n    CheckCondition(leveldb_iter_valid(iter));\n    CheckIter(iter, \"box\", \"c\");\n    leveldb_iter_next(iter);\n    CheckIter(iter, \"foo\", \"hello\");\n    leveldb_iter_prev(iter);\n    CheckIter(iter, \"box\", \"c\");\n    leveldb_iter_prev(iter);\n    CheckCondition(!leveldb_iter_valid(iter));\n    leveldb_iter_seek_to_last(iter);\n    CheckIter(iter, \"foo\", \"hello\");\n    leveldb_iter_seek(iter, \"b\", 1);\n    CheckIter(iter, \"box\", \"c\");\n    leveldb_iter_get_error(iter, &err);\n    CheckNoError(err);\n    leveldb_iter_destroy(iter);\n  }\n\n  StartPhase(\"approximate_sizes\");\n  {\n    int i;\n    int n = 20000;\n    char keybuf[100];\n    char valbuf[100];\n    uint64_t sizes[2];\n    const char* start[2] = { \"a\", \"k00000000000000010000\" };\n    size_t start_len[2] = { 1, 21 };\n    const char* limit[2] = { \"k00000000000000010000\", \"z\" };\n    size_t limit_len[2] = { 21, 1 };\n    leveldb_writeoptions_set_sync(woptions, 0);\n    for (i = 0; i < n; i++) {\n      snprintf(keybuf, sizeof(keybuf), \"k%020d\", i);\n      snprintf(valbuf, sizeof(valbuf), \"v%020d\", i);\n      leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf),\n                  &err);\n      CheckNoError(err);\n    }\n    leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);\n    CheckCondition(sizes[0] > 0);\n    CheckCondition(sizes[1] > 0);\n  }\n\n  StartPhase(\"property\");\n  {\n    char* prop = leveldb_property_value(db, \"nosuchprop\");\n    CheckCondition(prop == NULL);\n    prop = leveldb_property_value(db, \"leveldb.stats\");\n    CheckCondition(prop != NULL);\n    Free(&prop);\n  }\n\n  StartPhase(\"snapshot\");\n  {\n    const leveldb_snapshot_t* snap;\n    snap = leveldb_create_snapshot(db);\n    leveldb_delete(db, woptions, \"foo\", 3, &err);\n    CheckNoError(err);\n    leveldb_readoptions_set_snapshot(roptions, snap);\n    CheckGet(db, roptions, \"foo\", \"hello\");\n    leveldb_readoptions_set_snapshot(roptions, NULL);\n    CheckGet(db, roptions, \"foo\", NULL);\n    leveldb_release_snapshot(db, snap);\n  }\n\n  StartPhase(\"repair\");\n  {\n    leveldb_close(db);\n    leveldb_options_set_create_if_missing(options, 0);\n    leveldb_options_set_error_if_exists(options, 0);\n    leveldb_repair_db(options, dbname, &err);\n    CheckNoError(err);\n    db = leveldb_open(options, dbname, &err);\n    CheckNoError(err);\n    CheckGet(db, roptions, \"foo\", NULL);\n    CheckGet(db, roptions, \"bar\", NULL);\n    CheckGet(db, roptions, \"box\", \"c\");\n    leveldb_options_set_create_if_missing(options, 1);\n    leveldb_options_set_error_if_exists(options, 1);\n  }\n\n  StartPhase(\"filter\");\n  for (run = 0; run < 2; run++) {\n    // First run uses custom filter, second run uses bloom filter\n    CheckNoError(err);\n    leveldb_filterpolicy_t* policy;\n    if (run == 0) {\n      policy = leveldb_filterpolicy_create(\n          NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName);\n    } else {\n      policy = leveldb_filterpolicy_create_bloom(10);\n    }\n\n    // Create new database\n    leveldb_close(db);\n    leveldb_destroy_db(options, dbname, &err);\n    leveldb_options_set_filter_policy(options, policy);\n    db = leveldb_open(options, dbname, &err);\n    CheckNoError(err);\n    leveldb_put(db, woptions, \"foo\", 3, \"foovalue\", 8, &err);\n    CheckNoError(err);\n    leveldb_put(db, woptions, \"bar\", 3, \"barvalue\", 8, &err);\n    CheckNoError(err);\n    leveldb_compact_range(db, NULL, 0, NULL, 0);\n\n    fake_filter_result = 1;\n    CheckGet(db, roptions, \"foo\", \"foovalue\");\n    CheckGet(db, roptions, \"bar\", \"barvalue\");\n    if (phase == 0) {\n      // Must not find value when custom filter returns false\n      fake_filter_result = 0;\n      CheckGet(db, roptions, \"foo\", NULL);\n      CheckGet(db, roptions, \"bar\", NULL);\n      fake_filter_result = 1;\n\n      CheckGet(db, roptions, \"foo\", \"foovalue\");\n      CheckGet(db, roptions, \"bar\", \"barvalue\");\n    }\n    leveldb_options_set_filter_policy(options, NULL);\n    leveldb_filterpolicy_destroy(policy);\n  }\n\n  StartPhase(\"cleanup\");\n  leveldb_close(db);\n  leveldb_options_destroy(options);\n  leveldb_readoptions_destroy(roptions);\n  leveldb_writeoptions_destroy(woptions);\n  leveldb_free(dbname);\n  leveldb_cache_destroy(cache);\n  leveldb_comparator_destroy(cmp);\n  leveldb_env_destroy(env);\n\n  fprintf(stderr, \"PASS\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "src/leveldb/db/corruption_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <sys/types.h>\n\n#include \"db/db_impl.h\"\n#include \"db/filename.h\"\n#include \"db/log_format.h\"\n#include \"db/version_set.h\"\n#include \"leveldb/cache.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/table.h\"\n#include \"leveldb/write_batch.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nstatic const int kValueSize = 1000;\n\nclass CorruptionTest {\n public:\n  CorruptionTest()\n      : db_(nullptr),\n        dbname_(\"/memenv/corruption_test\"),\n        tiny_cache_(NewLRUCache(100)) {\n    options_.env = &env_;\n    options_.block_cache = tiny_cache_;\n    DestroyDB(dbname_, options_);\n\n    options_.create_if_missing = true;\n    Reopen();\n    options_.create_if_missing = false;\n  }\n\n  ~CorruptionTest() {\n    delete db_;\n    delete tiny_cache_;\n  }\n\n  Status TryReopen() {\n    delete db_;\n    db_ = nullptr;\n    return DB::Open(options_, dbname_, &db_);\n  }\n\n  void Reopen() { ASSERT_OK(TryReopen()); }\n\n  void RepairDB() {\n    delete db_;\n    db_ = nullptr;\n    ASSERT_OK(::leveldb::RepairDB(dbname_, options_));\n  }\n\n  void Build(int n) {\n    std::string key_space, value_space;\n    WriteBatch batch;\n    for (int i = 0; i < n; i++) {\n      // if ((i % 100) == 0) fprintf(stderr, \"@ %d of %d\\n\", i, n);\n      Slice key = Key(i, &key_space);\n      batch.Clear();\n      batch.Put(key, Value(i, &value_space));\n      WriteOptions options;\n      // Corrupt() doesn't work without this sync on windows; stat reports 0 for\n      // the file size.\n      if (i == n - 1) {\n        options.sync = true;\n      }\n      ASSERT_OK(db_->Write(options, &batch));\n    }\n  }\n\n  void Check(int min_expected, int max_expected) {\n    int next_expected = 0;\n    int missed = 0;\n    int bad_keys = 0;\n    int bad_values = 0;\n    int correct = 0;\n    std::string value_space;\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n      uint64_t key;\n      Slice in(iter->key());\n      if (in == \"\" || in == \"~\") {\n        // Ignore boundary keys.\n        continue;\n      }\n      if (!ConsumeDecimalNumber(&in, &key) || !in.empty() ||\n          key < next_expected) {\n        bad_keys++;\n        continue;\n      }\n      missed += (key - next_expected);\n      next_expected = key + 1;\n      if (iter->value() != Value(key, &value_space)) {\n        bad_values++;\n      } else {\n        correct++;\n      }\n    }\n    delete iter;\n\n    fprintf(stderr,\n            \"expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\\n\",\n            min_expected, max_expected, correct, bad_keys, bad_values, missed);\n    ASSERT_LE(min_expected, correct);\n    ASSERT_GE(max_expected, correct);\n  }\n\n  void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {\n    // Pick file to corrupt\n    std::vector<std::string> filenames;\n    ASSERT_OK(env_.target()->GetChildren(dbname_, &filenames));\n    uint64_t number;\n    FileType type;\n    std::string fname;\n    int picked_number = -1;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      if (ParseFileName(filenames[i], &number, &type) && type == filetype &&\n          int(number) > picked_number) {  // Pick latest file\n        fname = dbname_ + \"/\" + filenames[i];\n        picked_number = number;\n      }\n    }\n    ASSERT_TRUE(!fname.empty()) << filetype;\n\n    uint64_t file_size;\n    ASSERT_OK(env_.target()->GetFileSize(fname, &file_size));\n\n    if (offset < 0) {\n      // Relative to end of file; make it absolute\n      if (-offset > file_size) {\n        offset = 0;\n      } else {\n        offset = file_size + offset;\n      }\n    }\n    if (offset > file_size) {\n      offset = file_size;\n    }\n    if (offset + bytes_to_corrupt > file_size) {\n      bytes_to_corrupt = file_size - offset;\n    }\n\n    // Do it\n    std::string contents;\n    Status s = ReadFileToString(env_.target(), fname, &contents);\n    ASSERT_TRUE(s.ok()) << s.ToString();\n    for (int i = 0; i < bytes_to_corrupt; i++) {\n      contents[i + offset] ^= 0x80;\n    }\n    s = WriteStringToFile(env_.target(), contents, fname);\n    ASSERT_TRUE(s.ok()) << s.ToString();\n  }\n\n  int Property(const std::string& name) {\n    std::string property;\n    int result;\n    if (db_->GetProperty(name, &property) &&\n        sscanf(property.c_str(), \"%d\", &result) == 1) {\n      return result;\n    } else {\n      return -1;\n    }\n  }\n\n  // Return the ith key\n  Slice Key(int i, std::string* storage) {\n    char buf[100];\n    snprintf(buf, sizeof(buf), \"%016d\", i);\n    storage->assign(buf, strlen(buf));\n    return Slice(*storage);\n  }\n\n  // Return the value to associate with the specified key\n  Slice Value(int k, std::string* storage) {\n    Random r(k);\n    return test::RandomString(&r, kValueSize, storage);\n  }\n\n  test::ErrorEnv env_;\n  Options options_;\n  DB* db_;\n\n private:\n  std::string dbname_;\n  Cache* tiny_cache_;\n};\n\nTEST(CorruptionTest, Recovery) {\n  Build(100);\n  Check(100, 100);\n  Corrupt(kLogFile, 19, 1);  // WriteBatch tag for first record\n  Corrupt(kLogFile, log::kBlockSize + 1000, 1);  // Somewhere in second block\n  Reopen();\n\n  // The 64 records in the first two log blocks are completely lost.\n  Check(36, 36);\n}\n\nTEST(CorruptionTest, RecoverWriteError) {\n  env_.writable_file_error_ = true;\n  Status s = TryReopen();\n  ASSERT_TRUE(!s.ok());\n}\n\nTEST(CorruptionTest, NewFileErrorDuringWrite) {\n  // Do enough writing to force minor compaction\n  env_.writable_file_error_ = true;\n  const int num = 3 + (Options().write_buffer_size / kValueSize);\n  std::string value_storage;\n  Status s;\n  for (int i = 0; s.ok() && i < num; i++) {\n    WriteBatch batch;\n    batch.Put(\"a\", Value(100, &value_storage));\n    s = db_->Write(WriteOptions(), &batch);\n  }\n  ASSERT_TRUE(!s.ok());\n  ASSERT_GE(env_.num_writable_file_errors_, 1);\n  env_.writable_file_error_ = false;\n  Reopen();\n}\n\nTEST(CorruptionTest, TableFile) {\n  Build(100);\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n  dbi->TEST_CompactRange(0, nullptr, nullptr);\n  dbi->TEST_CompactRange(1, nullptr, nullptr);\n\n  Corrupt(kTableFile, 100, 1);\n  Check(90, 99);\n}\n\nTEST(CorruptionTest, TableFileRepair) {\n  options_.block_size = 2 * kValueSize;  // Limit scope of corruption\n  options_.paranoid_checks = true;\n  Reopen();\n  Build(100);\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n  dbi->TEST_CompactRange(0, nullptr, nullptr);\n  dbi->TEST_CompactRange(1, nullptr, nullptr);\n\n  Corrupt(kTableFile, 100, 1);\n  RepairDB();\n  Reopen();\n  Check(95, 99);\n}\n\nTEST(CorruptionTest, TableFileIndexData) {\n  Build(10000);  // Enough to build multiple Tables\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n\n  Corrupt(kTableFile, -2000, 500);\n  Reopen();\n  Check(5000, 9999);\n}\n\nTEST(CorruptionTest, MissingDescriptor) {\n  Build(1000);\n  RepairDB();\n  Reopen();\n  Check(1000, 1000);\n}\n\nTEST(CorruptionTest, SequenceNumberRecovery) {\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v1\"));\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v2\"));\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v3\"));\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v4\"));\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v5\"));\n  RepairDB();\n  Reopen();\n  std::string v;\n  ASSERT_OK(db_->Get(ReadOptions(), \"foo\", &v));\n  ASSERT_EQ(\"v5\", v);\n  // Write something.  If sequence number was not recovered properly,\n  // it will be hidden by an earlier write.\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v6\"));\n  ASSERT_OK(db_->Get(ReadOptions(), \"foo\", &v));\n  ASSERT_EQ(\"v6\", v);\n  Reopen();\n  ASSERT_OK(db_->Get(ReadOptions(), \"foo\", &v));\n  ASSERT_EQ(\"v6\", v);\n}\n\nTEST(CorruptionTest, CorruptedDescriptor) {\n  ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"hello\"));\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n  dbi->TEST_CompactRange(0, nullptr, nullptr);\n\n  Corrupt(kDescriptorFile, 0, 1000);\n  Status s = TryReopen();\n  ASSERT_TRUE(!s.ok());\n\n  RepairDB();\n  Reopen();\n  std::string v;\n  ASSERT_OK(db_->Get(ReadOptions(), \"foo\", &v));\n  ASSERT_EQ(\"hello\", v);\n}\n\nTEST(CorruptionTest, CompactionInputError) {\n  Build(10);\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n  const int last = config::kMaxMemCompactLevel;\n  ASSERT_EQ(1, Property(\"leveldb.num-files-at-level\" + NumberToString(last)));\n\n  Corrupt(kTableFile, 100, 1);\n  Check(5, 9);\n\n  // Force compactions by writing lots of values\n  Build(10000);\n  Check(10000, 10000);\n}\n\nTEST(CorruptionTest, CompactionInputErrorParanoid) {\n  options_.paranoid_checks = true;\n  options_.write_buffer_size = 512 << 10;\n  Reopen();\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n\n  // Make multiple inputs so we need to compact.\n  for (int i = 0; i < 2; i++) {\n    Build(10);\n    dbi->TEST_CompactMemTable();\n    Corrupt(kTableFile, 100, 1);\n    env_.SleepForMicroseconds(100000);\n  }\n  dbi->CompactRange(nullptr, nullptr);\n\n  // Write must fail because of corrupted table\n  std::string tmp1, tmp2;\n  Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2));\n  ASSERT_TRUE(!s.ok()) << \"write did not fail in corrupted paranoid db\";\n}\n\nTEST(CorruptionTest, UnrelatedKeys) {\n  Build(10);\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);\n  dbi->TEST_CompactMemTable();\n  Corrupt(kTableFile, 100, 1);\n\n  std::string tmp1, tmp2;\n  ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));\n  std::string v;\n  ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));\n  ASSERT_EQ(Value(1000, &tmp2).ToString(), v);\n  dbi->TEST_CompactMemTable();\n  ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));\n  ASSERT_EQ(Value(1000, &tmp2).ToString(), v);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/db_impl.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/db_impl.h\"\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include <algorithm>\n#include <atomic>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"db/builder.h\"\n#include \"db/db_iter.h\"\n#include \"db/dbformat.h\"\n#include \"db/filename.h\"\n#include \"db/log_reader.h\"\n#include \"db/log_writer.h\"\n#include \"db/memtable.h\"\n#include \"db/table_cache.h\"\n#include \"db/version_set.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/status.h\"\n#include \"leveldb/table.h\"\n#include \"leveldb/table_builder.h\"\n#include \"port/port.h\"\n#include \"table/block.h\"\n#include \"table/merger.h\"\n#include \"table/two_level_iterator.h\"\n#include \"util/coding.h\"\n#include \"util/logging.h\"\n#include \"util/mutexlock.h\"\n\nnamespace leveldb {\n\nconst int kNumNonTableCacheFiles = 10;\n\n// Information kept for every waiting writer\nstruct DBImpl::Writer {\n  explicit Writer(port::Mutex* mu)\n      : batch(nullptr), sync(false), done(false), cv(mu) {}\n\n  Status status;\n  WriteBatch* batch;\n  bool sync;\n  bool done;\n  port::CondVar cv;\n};\n\nstruct DBImpl::CompactionState {\n  // Files produced by compaction\n  struct Output {\n    uint64_t number;\n    uint64_t file_size;\n    InternalKey smallest, largest;\n  };\n\n  Output* current_output() { return &outputs[outputs.size() - 1]; }\n\n  explicit CompactionState(Compaction* c)\n      : compaction(c),\n        smallest_snapshot(0),\n        outfile(nullptr),\n        builder(nullptr),\n        total_bytes(0) {}\n\n  Compaction* const compaction;\n\n  // Sequence numbers < smallest_snapshot are not significant since we\n  // will never have to service a snapshot below smallest_snapshot.\n  // Therefore if we have seen a sequence number S <= smallest_snapshot,\n  // we can drop all entries for the same key with sequence numbers < S.\n  SequenceNumber smallest_snapshot;\n\n  std::vector<Output> outputs;\n\n  // State kept for output being generated\n  WritableFile* outfile;\n  TableBuilder* builder;\n\n  uint64_t total_bytes;\n};\n\n// Fix user-supplied options to be reasonable\ntemplate <class T, class V>\nstatic void ClipToRange(T* ptr, V minvalue, V maxvalue) {\n  if (static_cast<V>(*ptr) > maxvalue) *ptr = maxvalue;\n  if (static_cast<V>(*ptr) < minvalue) *ptr = minvalue;\n}\nOptions SanitizeOptions(const std::string& dbname,\n                        const InternalKeyComparator* icmp,\n                        const InternalFilterPolicy* ipolicy,\n                        const Options& src) {\n  Options result = src;\n  result.comparator = icmp;\n  result.filter_policy = (src.filter_policy != nullptr) ? ipolicy : nullptr;\n  ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000);\n  ClipToRange(&result.write_buffer_size, 64 << 10, 1 << 30);\n  ClipToRange(&result.max_file_size, 1 << 20, 1 << 30);\n  ClipToRange(&result.block_size, 1 << 10, 4 << 20);\n  if (result.info_log == nullptr) {\n    // Open a log file in the same directory as the db\n    src.env->CreateDir(dbname);  // In case it does not exist\n    src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname));\n    Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log);\n    if (!s.ok()) {\n      // No place suitable for logging\n      result.info_log = nullptr;\n    }\n  }\n  if (result.block_cache == nullptr) {\n    result.block_cache = NewLRUCache(8 << 20);\n  }\n  return result;\n}\n\nstatic int TableCacheSize(const Options& sanitized_options) {\n  // Reserve ten files or so for other uses and give the rest to TableCache.\n  return sanitized_options.max_open_files - kNumNonTableCacheFiles;\n}\n\nDBImpl::DBImpl(const Options& raw_options, const std::string& dbname)\n    : env_(raw_options.env),\n      internal_comparator_(raw_options.comparator),\n      internal_filter_policy_(raw_options.filter_policy),\n      options_(SanitizeOptions(dbname, &internal_comparator_,\n                               &internal_filter_policy_, raw_options)),\n      owns_info_log_(options_.info_log != raw_options.info_log),\n      owns_cache_(options_.block_cache != raw_options.block_cache),\n      dbname_(dbname),\n      table_cache_(new TableCache(dbname_, options_, TableCacheSize(options_))),\n      db_lock_(nullptr),\n      shutting_down_(false),\n      background_work_finished_signal_(&mutex_),\n      mem_(nullptr),\n      imm_(nullptr),\n      has_imm_(false),\n      logfile_(nullptr),\n      logfile_number_(0),\n      log_(nullptr),\n      seed_(0),\n      tmp_batch_(new WriteBatch),\n      background_compaction_scheduled_(false),\n      manual_compaction_(nullptr),\n      versions_(new VersionSet(dbname_, &options_, table_cache_,\n                               &internal_comparator_)) {}\n\nDBImpl::~DBImpl() {\n  // Wait for background work to finish.\n  mutex_.Lock();\n  shutting_down_.store(true, std::memory_order_release);\n  while (background_compaction_scheduled_) {\n    background_work_finished_signal_.Wait();\n  }\n  mutex_.Unlock();\n\n  if (db_lock_ != nullptr) {\n    env_->UnlockFile(db_lock_);\n  }\n\n  delete versions_;\n  if (mem_ != nullptr) mem_->Unref();\n  if (imm_ != nullptr) imm_->Unref();\n  delete tmp_batch_;\n  delete log_;\n  delete logfile_;\n  delete table_cache_;\n\n  if (owns_info_log_) {\n    delete options_.info_log;\n  }\n  if (owns_cache_) {\n    delete options_.block_cache;\n  }\n}\n\nStatus DBImpl::NewDB() {\n  VersionEdit new_db;\n  new_db.SetComparatorName(user_comparator()->Name());\n  new_db.SetLogNumber(0);\n  new_db.SetNextFile(2);\n  new_db.SetLastSequence(0);\n\n  const std::string manifest = DescriptorFileName(dbname_, 1);\n  WritableFile* file;\n  Status s = env_->NewWritableFile(manifest, &file);\n  if (!s.ok()) {\n    return s;\n  }\n  {\n    log::Writer log(file);\n    std::string record;\n    new_db.EncodeTo(&record);\n    s = log.AddRecord(record);\n    if (s.ok()) {\n      s = file->Close();\n    }\n  }\n  delete file;\n  if (s.ok()) {\n    // Make \"CURRENT\" file that points to the new manifest file.\n    s = SetCurrentFile(env_, dbname_, 1);\n  } else {\n    env_->DeleteFile(manifest);\n  }\n  return s;\n}\n\nvoid DBImpl::MaybeIgnoreError(Status* s) const {\n  if (s->ok() || options_.paranoid_checks) {\n    // No change needed\n  } else {\n    Log(options_.info_log, \"Ignoring error %s\", s->ToString().c_str());\n    *s = Status::OK();\n  }\n}\n\nvoid DBImpl::DeleteObsoleteFiles() {\n  mutex_.AssertHeld();\n\n  if (!bg_error_.ok()) {\n    // After a background error, we don't know whether a new version may\n    // or may not have been committed, so we cannot safely garbage collect.\n    return;\n  }\n\n  // Make a set of all of the live files\n  std::set<uint64_t> live = pending_outputs_;\n  versions_->AddLiveFiles(&live);\n\n  std::vector<std::string> filenames;\n  env_->GetChildren(dbname_, &filenames);  // Ignoring errors on purpose\n  uint64_t number;\n  FileType type;\n  std::vector<std::string> files_to_delete;\n  for (std::string& filename : filenames) {\n    if (ParseFileName(filename, &number, &type)) {\n      bool keep = true;\n      switch (type) {\n        case kLogFile:\n          keep = ((number >= versions_->LogNumber()) ||\n                  (number == versions_->PrevLogNumber()));\n          break;\n        case kDescriptorFile:\n          // Keep my manifest file, and any newer incarnations'\n          // (in case there is a race that allows other incarnations)\n          keep = (number >= versions_->ManifestFileNumber());\n          break;\n        case kTableFile:\n          keep = (live.find(number) != live.end());\n          break;\n        case kTempFile:\n          // Any temp files that are currently being written to must\n          // be recorded in pending_outputs_, which is inserted into \"live\"\n          keep = (live.find(number) != live.end());\n          break;\n        case kCurrentFile:\n        case kDBLockFile:\n        case kInfoLogFile:\n          keep = true;\n          break;\n      }\n\n      if (!keep) {\n        files_to_delete.push_back(std::move(filename));\n        if (type == kTableFile) {\n          table_cache_->Evict(number);\n        }\n        Log(options_.info_log, \"Delete type=%d #%lld\\n\", static_cast<int>(type),\n            static_cast<unsigned long long>(number));\n      }\n    }\n  }\n\n  // While deleting all files unblock other threads. All files being deleted\n  // have unique names which will not collide with newly created files and\n  // are therefore safe to delete while allowing other threads to proceed.\n  mutex_.Unlock();\n  for (const std::string& filename : files_to_delete) {\n    env_->DeleteFile(dbname_ + \"/\" + filename);\n  }\n  mutex_.Lock();\n}\n\nStatus DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {\n  mutex_.AssertHeld();\n\n  // Ignore error from CreateDir since the creation of the DB is\n  // committed only when the descriptor is created, and this directory\n  // may already exist from a previous failed creation attempt.\n  env_->CreateDir(dbname_);\n  assert(db_lock_ == nullptr);\n  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);\n  if (!s.ok()) {\n    return s;\n  }\n\n  if (!env_->FileExists(CurrentFileName(dbname_))) {\n    if (options_.create_if_missing) {\n      s = NewDB();\n      if (!s.ok()) {\n        return s;\n      }\n    } else {\n      return Status::InvalidArgument(\n          dbname_, \"does not exist (create_if_missing is false)\");\n    }\n  } else {\n    if (options_.error_if_exists) {\n      return Status::InvalidArgument(dbname_,\n                                     \"exists (error_if_exists is true)\");\n    }\n  }\n\n  s = versions_->Recover(save_manifest);\n  if (!s.ok()) {\n    return s;\n  }\n  SequenceNumber max_sequence(0);\n\n  // Recover from all newer log files than the ones named in the\n  // descriptor (new log files may have been added by the previous\n  // incarnation without registering them in the descriptor).\n  //\n  // Note that PrevLogNumber() is no longer used, but we pay\n  // attention to it in case we are recovering a database\n  // produced by an older version of leveldb.\n  const uint64_t min_log = versions_->LogNumber();\n  const uint64_t prev_log = versions_->PrevLogNumber();\n  std::vector<std::string> filenames;\n  s = env_->GetChildren(dbname_, &filenames);\n  if (!s.ok()) {\n    return s;\n  }\n  std::set<uint64_t> expected;\n  versions_->AddLiveFiles(&expected);\n  uint64_t number;\n  FileType type;\n  std::vector<uint64_t> logs;\n  for (size_t i = 0; i < filenames.size(); i++) {\n    if (ParseFileName(filenames[i], &number, &type)) {\n      expected.erase(number);\n      if (type == kLogFile && ((number >= min_log) || (number == prev_log)))\n        logs.push_back(number);\n    }\n  }\n  if (!expected.empty()) {\n    char buf[50];\n    snprintf(buf, sizeof(buf), \"%d missing files; e.g.\",\n             static_cast<int>(expected.size()));\n    return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));\n  }\n\n  // Recover in the order in which the logs were generated\n  std::sort(logs.begin(), logs.end());\n  for (size_t i = 0; i < logs.size(); i++) {\n    s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit,\n                       &max_sequence);\n    if (!s.ok()) {\n      return s;\n    }\n\n    // The previous incarnation may not have written any MANIFEST\n    // records after allocating this log number.  So we manually\n    // update the file number allocation counter in VersionSet.\n    versions_->MarkFileNumberUsed(logs[i]);\n  }\n\n  if (versions_->LastSequence() < max_sequence) {\n    versions_->SetLastSequence(max_sequence);\n  }\n\n  return Status::OK();\n}\n\nStatus DBImpl::RecoverLogFile(uint64_t log_number, bool last_log,\n                              bool* save_manifest, VersionEdit* edit,\n                              SequenceNumber* max_sequence) {\n  struct LogReporter : public log::Reader::Reporter {\n    Env* env;\n    Logger* info_log;\n    const char* fname;\n    Status* status;  // null if options_.paranoid_checks==false\n    void Corruption(size_t bytes, const Status& s) override {\n      Log(info_log, \"%s%s: dropping %d bytes; %s\",\n          (this->status == nullptr ? \"(ignoring error) \" : \"\"), fname,\n          static_cast<int>(bytes), s.ToString().c_str());\n      if (this->status != nullptr && this->status->ok()) *this->status = s;\n    }\n  };\n\n  mutex_.AssertHeld();\n\n  // Open the log file\n  std::string fname = LogFileName(dbname_, log_number);\n  SequentialFile* file;\n  Status status = env_->NewSequentialFile(fname, &file);\n  if (!status.ok()) {\n    MaybeIgnoreError(&status);\n    return status;\n  }\n\n  // Create the log reader.\n  LogReporter reporter;\n  reporter.env = env_;\n  reporter.info_log = options_.info_log;\n  reporter.fname = fname.c_str();\n  reporter.status = (options_.paranoid_checks ? &status : nullptr);\n  // We intentionally make log::Reader do checksumming even if\n  // paranoid_checks==false so that corruptions cause entire commits\n  // to be skipped instead of propagating bad information (like overly\n  // large sequence numbers).\n  log::Reader reader(file, &reporter, true /*checksum*/, 0 /*initial_offset*/);\n  Log(options_.info_log, \"Recovering log #%llu\",\n      (unsigned long long)log_number);\n\n  // Read all the records and add to a memtable\n  std::string scratch;\n  Slice record;\n  WriteBatch batch;\n  int compactions = 0;\n  MemTable* mem = nullptr;\n  while (reader.ReadRecord(&record, &scratch) && status.ok()) {\n    if (record.size() < 12) {\n      reporter.Corruption(record.size(),\n                          Status::Corruption(\"log record too small\", fname));\n      continue;\n    }\n    WriteBatchInternal::SetContents(&batch, record);\n\n    if (mem == nullptr) {\n      mem = new MemTable(internal_comparator_);\n      mem->Ref();\n    }\n    status = WriteBatchInternal::InsertInto(&batch, mem);\n    MaybeIgnoreError(&status);\n    if (!status.ok()) {\n      break;\n    }\n    const SequenceNumber last_seq = WriteBatchInternal::Sequence(&batch) +\n                                    WriteBatchInternal::Count(&batch) - 1;\n    if (last_seq > *max_sequence) {\n      *max_sequence = last_seq;\n    }\n\n    if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) {\n      compactions++;\n      *save_manifest = true;\n      status = WriteLevel0Table(mem, edit, nullptr);\n      mem->Unref();\n      mem = nullptr;\n      if (!status.ok()) {\n        // Reflect errors immediately so that conditions like full\n        // file-systems cause the DB::Open() to fail.\n        break;\n      }\n    }\n  }\n\n  delete file;\n\n  // See if we should keep reusing the last log file.\n  if (status.ok() && options_.reuse_logs && last_log && compactions == 0) {\n    assert(logfile_ == nullptr);\n    assert(log_ == nullptr);\n    assert(mem_ == nullptr);\n    uint64_t lfile_size;\n    if (env_->GetFileSize(fname, &lfile_size).ok() &&\n        env_->NewAppendableFile(fname, &logfile_).ok()) {\n      Log(options_.info_log, \"Reusing old log %s \\n\", fname.c_str());\n      log_ = new log::Writer(logfile_, lfile_size);\n      logfile_number_ = log_number;\n      if (mem != nullptr) {\n        mem_ = mem;\n        mem = nullptr;\n      } else {\n        // mem can be nullptr if lognum exists but was empty.\n        mem_ = new MemTable(internal_comparator_);\n        mem_->Ref();\n      }\n    }\n  }\n\n  if (mem != nullptr) {\n    // mem did not get reused; compact it.\n    if (status.ok()) {\n      *save_manifest = true;\n      status = WriteLevel0Table(mem, edit, nullptr);\n    }\n    mem->Unref();\n  }\n\n  return status;\n}\n\nStatus DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit,\n                                Version* base) {\n  mutex_.AssertHeld();\n  const uint64_t start_micros = env_->NowMicros();\n  FileMetaData meta;\n  meta.number = versions_->NewFileNumber();\n  pending_outputs_.insert(meta.number);\n  Iterator* iter = mem->NewIterator();\n  Log(options_.info_log, \"Level-0 table #%llu: started\",\n      (unsigned long long)meta.number);\n\n  Status s;\n  {\n    mutex_.Unlock();\n    s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);\n    mutex_.Lock();\n  }\n\n  Log(options_.info_log, \"Level-0 table #%llu: %lld bytes %s\",\n      (unsigned long long)meta.number, (unsigned long long)meta.file_size,\n      s.ToString().c_str());\n  delete iter;\n  pending_outputs_.erase(meta.number);\n\n  // Note that if file_size is zero, the file has been deleted and\n  // should not be added to the manifest.\n  int level = 0;\n  if (s.ok() && meta.file_size > 0) {\n    const Slice min_user_key = meta.smallest.user_key();\n    const Slice max_user_key = meta.largest.user_key();\n    if (base != nullptr) {\n      level = base->PickLevelForMemTableOutput(min_user_key, max_user_key);\n    }\n    edit->AddFile(level, meta.number, meta.file_size, meta.smallest,\n                  meta.largest);\n  }\n\n  CompactionStats stats;\n  stats.micros = env_->NowMicros() - start_micros;\n  stats.bytes_written = meta.file_size;\n  stats_[level].Add(stats);\n  return s;\n}\n\nvoid DBImpl::CompactMemTable() {\n  mutex_.AssertHeld();\n  assert(imm_ != nullptr);\n\n  // Save the contents of the memtable as a new Table\n  VersionEdit edit;\n  Version* base = versions_->current();\n  base->Ref();\n  Status s = WriteLevel0Table(imm_, &edit, base);\n  base->Unref();\n\n  if (s.ok() && shutting_down_.load(std::memory_order_acquire)) {\n    s = Status::IOError(\"Deleting DB during memtable compaction\");\n  }\n\n  // Replace immutable memtable with the generated Table\n  if (s.ok()) {\n    edit.SetPrevLogNumber(0);\n    edit.SetLogNumber(logfile_number_);  // Earlier logs no longer needed\n    s = versions_->LogAndApply(&edit, &mutex_);\n  }\n\n  if (s.ok()) {\n    // Commit to the new state\n    imm_->Unref();\n    imm_ = nullptr;\n    has_imm_.store(false, std::memory_order_release);\n    DeleteObsoleteFiles();\n  } else {\n    RecordBackgroundError(s);\n  }\n}\n\nvoid DBImpl::CompactRange(const Slice* begin, const Slice* end) {\n  int max_level_with_files = 1;\n  {\n    MutexLock l(&mutex_);\n    Version* base = versions_->current();\n    for (int level = 1; level < config::kNumLevels; level++) {\n      if (base->OverlapInLevel(level, begin, end)) {\n        max_level_with_files = level;\n      }\n    }\n  }\n  TEST_CompactMemTable();  // TODO(sanjay): Skip if memtable does not overlap\n  for (int level = 0; level < max_level_with_files; level++) {\n    TEST_CompactRange(level, begin, end);\n  }\n}\n\nvoid DBImpl::TEST_CompactRange(int level, const Slice* begin,\n                               const Slice* end) {\n  assert(level >= 0);\n  assert(level + 1 < config::kNumLevels);\n\n  InternalKey begin_storage, end_storage;\n\n  ManualCompaction manual;\n  manual.level = level;\n  manual.done = false;\n  if (begin == nullptr) {\n    manual.begin = nullptr;\n  } else {\n    begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek);\n    manual.begin = &begin_storage;\n  }\n  if (end == nullptr) {\n    manual.end = nullptr;\n  } else {\n    end_storage = InternalKey(*end, 0, static_cast<ValueType>(0));\n    manual.end = &end_storage;\n  }\n\n  MutexLock l(&mutex_);\n  while (!manual.done && !shutting_down_.load(std::memory_order_acquire) &&\n         bg_error_.ok()) {\n    if (manual_compaction_ == nullptr) {  // Idle\n      manual_compaction_ = &manual;\n      MaybeScheduleCompaction();\n    } else {  // Running either my compaction or another compaction.\n      background_work_finished_signal_.Wait();\n    }\n  }\n  if (manual_compaction_ == &manual) {\n    // Cancel my manual compaction since we aborted early for some reason.\n    manual_compaction_ = nullptr;\n  }\n}\n\nStatus DBImpl::TEST_CompactMemTable() {\n  // nullptr batch means just wait for earlier writes to be done\n  Status s = Write(WriteOptions(), nullptr);\n  if (s.ok()) {\n    // Wait until the compaction completes\n    MutexLock l(&mutex_);\n    while (imm_ != nullptr && bg_error_.ok()) {\n      background_work_finished_signal_.Wait();\n    }\n    if (imm_ != nullptr) {\n      s = bg_error_;\n    }\n  }\n  return s;\n}\n\nvoid DBImpl::RecordBackgroundError(const Status& s) {\n  mutex_.AssertHeld();\n  if (bg_error_.ok()) {\n    bg_error_ = s;\n    background_work_finished_signal_.SignalAll();\n  }\n}\n\nvoid DBImpl::MaybeScheduleCompaction() {\n  mutex_.AssertHeld();\n  if (background_compaction_scheduled_) {\n    // Already scheduled\n  } else if (shutting_down_.load(std::memory_order_acquire)) {\n    // DB is being deleted; no more background compactions\n  } else if (!bg_error_.ok()) {\n    // Already got an error; no more changes\n  } else if (imm_ == nullptr && manual_compaction_ == nullptr &&\n             !versions_->NeedsCompaction()) {\n    // No work to be done\n  } else {\n    background_compaction_scheduled_ = true;\n    env_->Schedule(&DBImpl::BGWork, this);\n  }\n}\n\nvoid DBImpl::BGWork(void* db) {\n  reinterpret_cast<DBImpl*>(db)->BackgroundCall();\n}\n\nvoid DBImpl::BackgroundCall() {\n  MutexLock l(&mutex_);\n  assert(background_compaction_scheduled_);\n  if (shutting_down_.load(std::memory_order_acquire)) {\n    // No more background work when shutting down.\n  } else if (!bg_error_.ok()) {\n    // No more background work after a background error.\n  } else {\n    BackgroundCompaction();\n  }\n\n  background_compaction_scheduled_ = false;\n\n  // Previous compaction may have produced too many files in a level,\n  // so reschedule another compaction if needed.\n  MaybeScheduleCompaction();\n  background_work_finished_signal_.SignalAll();\n}\n\nvoid DBImpl::BackgroundCompaction() {\n  mutex_.AssertHeld();\n\n  if (imm_ != nullptr) {\n    CompactMemTable();\n    return;\n  }\n\n  Compaction* c;\n  bool is_manual = (manual_compaction_ != nullptr);\n  InternalKey manual_end;\n  if (is_manual) {\n    ManualCompaction* m = manual_compaction_;\n    c = versions_->CompactRange(m->level, m->begin, m->end);\n    m->done = (c == nullptr);\n    if (c != nullptr) {\n      manual_end = c->input(0, c->num_input_files(0) - 1)->largest;\n    }\n    Log(options_.info_log,\n        \"Manual compaction at level-%d from %s .. %s; will stop at %s\\n\",\n        m->level, (m->begin ? m->begin->DebugString().c_str() : \"(begin)\"),\n        (m->end ? m->end->DebugString().c_str() : \"(end)\"),\n        (m->done ? \"(end)\" : manual_end.DebugString().c_str()));\n  } else {\n    c = versions_->PickCompaction();\n  }\n\n  Status status;\n  if (c == nullptr) {\n    // Nothing to do\n  } else if (!is_manual && c->IsTrivialMove()) {\n    // Move file to next level\n    assert(c->num_input_files(0) == 1);\n    FileMetaData* f = c->input(0, 0);\n    c->edit()->DeleteFile(c->level(), f->number);\n    c->edit()->AddFile(c->level() + 1, f->number, f->file_size, f->smallest,\n                       f->largest);\n    status = versions_->LogAndApply(c->edit(), &mutex_);\n    if (!status.ok()) {\n      RecordBackgroundError(status);\n    }\n    VersionSet::LevelSummaryStorage tmp;\n    Log(options_.info_log, \"Moved #%lld to level-%d %lld bytes %s: %s\\n\",\n        static_cast<unsigned long long>(f->number), c->level() + 1,\n        static_cast<unsigned long long>(f->file_size),\n        status.ToString().c_str(), versions_->LevelSummary(&tmp));\n  } else {\n    CompactionState* compact = new CompactionState(c);\n    status = DoCompactionWork(compact);\n    if (!status.ok()) {\n      RecordBackgroundError(status);\n    }\n    CleanupCompaction(compact);\n    c->ReleaseInputs();\n    DeleteObsoleteFiles();\n  }\n  delete c;\n\n  if (status.ok()) {\n    // Done\n  } else if (shutting_down_.load(std::memory_order_acquire)) {\n    // Ignore compaction errors found during shutting down\n  } else {\n    Log(options_.info_log, \"Compaction error: %s\", status.ToString().c_str());\n  }\n\n  if (is_manual) {\n    ManualCompaction* m = manual_compaction_;\n    if (!status.ok()) {\n      m->done = true;\n    }\n    if (!m->done) {\n      // We only compacted part of the requested range.  Update *m\n      // to the range that is left to be compacted.\n      m->tmp_storage = manual_end;\n      m->begin = &m->tmp_storage;\n    }\n    manual_compaction_ = nullptr;\n  }\n}\n\nvoid DBImpl::CleanupCompaction(CompactionState* compact) {\n  mutex_.AssertHeld();\n  if (compact->builder != nullptr) {\n    // May happen if we get a shutdown call in the middle of compaction\n    compact->builder->Abandon();\n    delete compact->builder;\n  } else {\n    assert(compact->outfile == nullptr);\n  }\n  delete compact->outfile;\n  for (size_t i = 0; i < compact->outputs.size(); i++) {\n    const CompactionState::Output& out = compact->outputs[i];\n    pending_outputs_.erase(out.number);\n  }\n  delete compact;\n}\n\nStatus DBImpl::OpenCompactionOutputFile(CompactionState* compact) {\n  assert(compact != nullptr);\n  assert(compact->builder == nullptr);\n  uint64_t file_number;\n  {\n    mutex_.Lock();\n    file_number = versions_->NewFileNumber();\n    pending_outputs_.insert(file_number);\n    CompactionState::Output out;\n    out.number = file_number;\n    out.smallest.Clear();\n    out.largest.Clear();\n    compact->outputs.push_back(out);\n    mutex_.Unlock();\n  }\n\n  // Make the output file\n  std::string fname = TableFileName(dbname_, file_number);\n  Status s = env_->NewWritableFile(fname, &compact->outfile);\n  if (s.ok()) {\n    compact->builder = new TableBuilder(options_, compact->outfile);\n  }\n  return s;\n}\n\nStatus DBImpl::FinishCompactionOutputFile(CompactionState* compact,\n                                          Iterator* input) {\n  assert(compact != nullptr);\n  assert(compact->outfile != nullptr);\n  assert(compact->builder != nullptr);\n\n  const uint64_t output_number = compact->current_output()->number;\n  assert(output_number != 0);\n\n  // Check for iterator errors\n  Status s = input->status();\n  const uint64_t current_entries = compact->builder->NumEntries();\n  if (s.ok()) {\n    s = compact->builder->Finish();\n  } else {\n    compact->builder->Abandon();\n  }\n  const uint64_t current_bytes = compact->builder->FileSize();\n  compact->current_output()->file_size = current_bytes;\n  compact->total_bytes += current_bytes;\n  delete compact->builder;\n  compact->builder = nullptr;\n\n  // Finish and check for file errors\n  if (s.ok()) {\n    s = compact->outfile->Sync();\n  }\n  if (s.ok()) {\n    s = compact->outfile->Close();\n  }\n  delete compact->outfile;\n  compact->outfile = nullptr;\n\n  if (s.ok() && current_entries > 0) {\n    // Verify that the table is usable\n    Iterator* iter =\n        table_cache_->NewIterator(ReadOptions(), output_number, current_bytes);\n    s = iter->status();\n    delete iter;\n    if (s.ok()) {\n      Log(options_.info_log, \"Generated table #%llu@%d: %lld keys, %lld bytes\",\n          (unsigned long long)output_number, compact->compaction->level(),\n          (unsigned long long)current_entries,\n          (unsigned long long)current_bytes);\n    }\n  }\n  return s;\n}\n\nStatus DBImpl::InstallCompactionResults(CompactionState* compact) {\n  mutex_.AssertHeld();\n  Log(options_.info_log, \"Compacted %d@%d + %d@%d files => %lld bytes\",\n      compact->compaction->num_input_files(0), compact->compaction->level(),\n      compact->compaction->num_input_files(1), compact->compaction->level() + 1,\n      static_cast<long long>(compact->total_bytes));\n\n  // Add compaction outputs\n  compact->compaction->AddInputDeletions(compact->compaction->edit());\n  const int level = compact->compaction->level();\n  for (size_t i = 0; i < compact->outputs.size(); i++) {\n    const CompactionState::Output& out = compact->outputs[i];\n    compact->compaction->edit()->AddFile(level + 1, out.number, out.file_size,\n                                         out.smallest, out.largest);\n  }\n  return versions_->LogAndApply(compact->compaction->edit(), &mutex_);\n}\n\nStatus DBImpl::DoCompactionWork(CompactionState* compact) {\n  const uint64_t start_micros = env_->NowMicros();\n  int64_t imm_micros = 0;  // Micros spent doing imm_ compactions\n\n  Log(options_.info_log, \"Compacting %d@%d + %d@%d files\",\n      compact->compaction->num_input_files(0), compact->compaction->level(),\n      compact->compaction->num_input_files(1),\n      compact->compaction->level() + 1);\n\n  assert(versions_->NumLevelFiles(compact->compaction->level()) > 0);\n  assert(compact->builder == nullptr);\n  assert(compact->outfile == nullptr);\n  if (snapshots_.empty()) {\n    compact->smallest_snapshot = versions_->LastSequence();\n  } else {\n    compact->smallest_snapshot = snapshots_.oldest()->sequence_number();\n  }\n\n  Iterator* input = versions_->MakeInputIterator(compact->compaction);\n\n  // Release mutex while we're actually doing the compaction work\n  mutex_.Unlock();\n\n  input->SeekToFirst();\n  Status status;\n  ParsedInternalKey ikey;\n  std::string current_user_key;\n  bool has_current_user_key = false;\n  SequenceNumber last_sequence_for_key = kMaxSequenceNumber;\n  while (input->Valid() && !shutting_down_.load(std::memory_order_acquire)) {\n    // Prioritize immutable compaction work\n    if (has_imm_.load(std::memory_order_relaxed)) {\n      const uint64_t imm_start = env_->NowMicros();\n      mutex_.Lock();\n      if (imm_ != nullptr) {\n        CompactMemTable();\n        // Wake up MakeRoomForWrite() if necessary.\n        background_work_finished_signal_.SignalAll();\n      }\n      mutex_.Unlock();\n      imm_micros += (env_->NowMicros() - imm_start);\n    }\n\n    Slice key = input->key();\n    if (compact->compaction->ShouldStopBefore(key) &&\n        compact->builder != nullptr) {\n      status = FinishCompactionOutputFile(compact, input);\n      if (!status.ok()) {\n        break;\n      }\n    }\n\n    // Handle key/value, add to state, etc.\n    bool drop = false;\n    if (!ParseInternalKey(key, &ikey)) {\n      // Do not hide error keys\n      current_user_key.clear();\n      has_current_user_key = false;\n      last_sequence_for_key = kMaxSequenceNumber;\n    } else {\n      if (!has_current_user_key ||\n          user_comparator()->Compare(ikey.user_key, Slice(current_user_key)) !=\n              0) {\n        // First occurrence of this user key\n        current_user_key.assign(ikey.user_key.data(), ikey.user_key.size());\n        has_current_user_key = true;\n        last_sequence_for_key = kMaxSequenceNumber;\n      }\n\n      if (last_sequence_for_key <= compact->smallest_snapshot) {\n        // Hidden by an newer entry for same user key\n        drop = true;  // (A)\n      } else if (ikey.type == kTypeDeletion &&\n                 ikey.sequence <= compact->smallest_snapshot &&\n                 compact->compaction->IsBaseLevelForKey(ikey.user_key)) {\n        // For this user key:\n        // (1) there is no data in higher levels\n        // (2) data in lower levels will have larger sequence numbers\n        // (3) data in layers that are being compacted here and have\n        //     smaller sequence numbers will be dropped in the next\n        //     few iterations of this loop (by rule (A) above).\n        // Therefore this deletion marker is obsolete and can be dropped.\n        drop = true;\n      }\n\n      last_sequence_for_key = ikey.sequence;\n    }\n#if 0\n    Log(options_.info_log,\n        \"  Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, \"\n        \"%d smallest_snapshot: %d\",\n        ikey.user_key.ToString().c_str(),\n        (int)ikey.sequence, ikey.type, kTypeValue, drop,\n        compact->compaction->IsBaseLevelForKey(ikey.user_key),\n        (int)last_sequence_for_key, (int)compact->smallest_snapshot);\n#endif\n\n    if (!drop) {\n      // Open output file if necessary\n      if (compact->builder == nullptr) {\n        status = OpenCompactionOutputFile(compact);\n        if (!status.ok()) {\n          break;\n        }\n      }\n      if (compact->builder->NumEntries() == 0) {\n        compact->current_output()->smallest.DecodeFrom(key);\n      }\n      compact->current_output()->largest.DecodeFrom(key);\n      compact->builder->Add(key, input->value());\n\n      // Close output file if it is big enough\n      if (compact->builder->FileSize() >=\n          compact->compaction->MaxOutputFileSize()) {\n        status = FinishCompactionOutputFile(compact, input);\n        if (!status.ok()) {\n          break;\n        }\n      }\n    }\n\n    input->Next();\n  }\n\n  if (status.ok() && shutting_down_.load(std::memory_order_acquire)) {\n    status = Status::IOError(\"Deleting DB during compaction\");\n  }\n  if (status.ok() && compact->builder != nullptr) {\n    status = FinishCompactionOutputFile(compact, input);\n  }\n  if (status.ok()) {\n    status = input->status();\n  }\n  delete input;\n  input = nullptr;\n\n  CompactionStats stats;\n  stats.micros = env_->NowMicros() - start_micros - imm_micros;\n  for (int which = 0; which < 2; which++) {\n    for (int i = 0; i < compact->compaction->num_input_files(which); i++) {\n      stats.bytes_read += compact->compaction->input(which, i)->file_size;\n    }\n  }\n  for (size_t i = 0; i < compact->outputs.size(); i++) {\n    stats.bytes_written += compact->outputs[i].file_size;\n  }\n\n  mutex_.Lock();\n  stats_[compact->compaction->level() + 1].Add(stats);\n\n  if (status.ok()) {\n    status = InstallCompactionResults(compact);\n  }\n  if (!status.ok()) {\n    RecordBackgroundError(status);\n  }\n  VersionSet::LevelSummaryStorage tmp;\n  Log(options_.info_log, \"compacted to: %s\", versions_->LevelSummary(&tmp));\n  return status;\n}\n\nnamespace {\n\nstruct IterState {\n  port::Mutex* const mu;\n  Version* const version GUARDED_BY(mu);\n  MemTable* const mem GUARDED_BY(mu);\n  MemTable* const imm GUARDED_BY(mu);\n\n  IterState(port::Mutex* mutex, MemTable* mem, MemTable* imm, Version* version)\n      : mu(mutex), version(version), mem(mem), imm(imm) {}\n};\n\nstatic void CleanupIteratorState(void* arg1, void* arg2) {\n  IterState* state = reinterpret_cast<IterState*>(arg1);\n  state->mu->Lock();\n  state->mem->Unref();\n  if (state->imm != nullptr) state->imm->Unref();\n  state->version->Unref();\n  state->mu->Unlock();\n  delete state;\n}\n\n}  // anonymous namespace\n\nIterator* DBImpl::NewInternalIterator(const ReadOptions& options,\n                                      SequenceNumber* latest_snapshot,\n                                      uint32_t* seed) {\n  mutex_.Lock();\n  *latest_snapshot = versions_->LastSequence();\n\n  // Collect together all needed child iterators\n  std::vector<Iterator*> list;\n  list.push_back(mem_->NewIterator());\n  mem_->Ref();\n  if (imm_ != nullptr) {\n    list.push_back(imm_->NewIterator());\n    imm_->Ref();\n  }\n  versions_->current()->AddIterators(options, &list);\n  Iterator* internal_iter =\n      NewMergingIterator(&internal_comparator_, &list[0], list.size());\n  versions_->current()->Ref();\n\n  IterState* cleanup = new IterState(&mutex_, mem_, imm_, versions_->current());\n  internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr);\n\n  *seed = ++seed_;\n  mutex_.Unlock();\n  return internal_iter;\n}\n\nIterator* DBImpl::TEST_NewInternalIterator() {\n  SequenceNumber ignored;\n  uint32_t ignored_seed;\n  return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed);\n}\n\nint64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {\n  MutexLock l(&mutex_);\n  return versions_->MaxNextLevelOverlappingBytes();\n}\n\nStatus DBImpl::Get(const ReadOptions& options, const Slice& key,\n                   std::string* value) {\n  Status s;\n  MutexLock l(&mutex_);\n  SequenceNumber snapshot;\n  if (options.snapshot != nullptr) {\n    snapshot =\n        static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();\n  } else {\n    snapshot = versions_->LastSequence();\n  }\n\n  MemTable* mem = mem_;\n  MemTable* imm = imm_;\n  Version* current = versions_->current();\n  mem->Ref();\n  if (imm != nullptr) imm->Ref();\n  current->Ref();\n\n  bool have_stat_update = false;\n  Version::GetStats stats;\n\n  // Unlock while reading from files and memtables\n  {\n    mutex_.Unlock();\n    // First look in the memtable, then in the immutable memtable (if any).\n    LookupKey lkey(key, snapshot);\n    if (mem->Get(lkey, value, &s)) {\n      // Done\n    } else if (imm != nullptr && imm->Get(lkey, value, &s)) {\n      // Done\n    } else {\n      s = current->Get(options, lkey, value, &stats);\n      have_stat_update = true;\n    }\n    mutex_.Lock();\n  }\n\n  if (have_stat_update && current->UpdateStats(stats)) {\n    MaybeScheduleCompaction();\n  }\n  mem->Unref();\n  if (imm != nullptr) imm->Unref();\n  current->Unref();\n  return s;\n}\n\nIterator* DBImpl::NewIterator(const ReadOptions& options) {\n  SequenceNumber latest_snapshot;\n  uint32_t seed;\n  Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed);\n  return NewDBIterator(this, user_comparator(), iter,\n                       (options.snapshot != nullptr\n                            ? static_cast<const SnapshotImpl*>(options.snapshot)\n                                  ->sequence_number()\n                            : latest_snapshot),\n                       seed);\n}\n\nvoid DBImpl::RecordReadSample(Slice key) {\n  MutexLock l(&mutex_);\n  if (versions_->current()->RecordReadSample(key)) {\n    MaybeScheduleCompaction();\n  }\n}\n\nconst Snapshot* DBImpl::GetSnapshot() {\n  MutexLock l(&mutex_);\n  return snapshots_.New(versions_->LastSequence());\n}\n\nvoid DBImpl::ReleaseSnapshot(const Snapshot* snapshot) {\n  MutexLock l(&mutex_);\n  snapshots_.Delete(static_cast<const SnapshotImpl*>(snapshot));\n}\n\n// Convenience methods\nStatus DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) {\n  return DB::Put(o, key, val);\n}\n\nStatus DBImpl::Delete(const WriteOptions& options, const Slice& key) {\n  return DB::Delete(options, key);\n}\n\nStatus DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {\n  Writer w(&mutex_);\n  w.batch = updates;\n  w.sync = options.sync;\n  w.done = false;\n\n  MutexLock l(&mutex_);\n  writers_.push_back(&w);\n  while (!w.done && &w != writers_.front()) {\n    w.cv.Wait();\n  }\n  if (w.done) {\n    return w.status;\n  }\n\n  // May temporarily unlock and wait.\n  Status status = MakeRoomForWrite(updates == nullptr);\n  uint64_t last_sequence = versions_->LastSequence();\n  Writer* last_writer = &w;\n  if (status.ok() && updates != nullptr) {  // nullptr batch is for compactions\n    WriteBatch* write_batch = BuildBatchGroup(&last_writer);\n    WriteBatchInternal::SetSequence(write_batch, last_sequence + 1);\n    last_sequence += WriteBatchInternal::Count(write_batch);\n\n    // Add to log and apply to memtable.  We can release the lock\n    // during this phase since &w is currently responsible for logging\n    // and protects against concurrent loggers and concurrent writes\n    // into mem_.\n    {\n      mutex_.Unlock();\n      status = log_->AddRecord(WriteBatchInternal::Contents(write_batch));\n      bool sync_error = false;\n      if (status.ok() && options.sync) {\n        status = logfile_->Sync();\n        if (!status.ok()) {\n          sync_error = true;\n        }\n      }\n      if (status.ok()) {\n        status = WriteBatchInternal::InsertInto(write_batch, mem_);\n      }\n      mutex_.Lock();\n      if (sync_error) {\n        // The state of the log file is indeterminate: the log record we\n        // just added may or may not show up when the DB is re-opened.\n        // So we force the DB into a mode where all future writes fail.\n        RecordBackgroundError(status);\n      }\n    }\n    if (write_batch == tmp_batch_) tmp_batch_->Clear();\n\n    versions_->SetLastSequence(last_sequence);\n  }\n\n  while (true) {\n    Writer* ready = writers_.front();\n    writers_.pop_front();\n    if (ready != &w) {\n      ready->status = status;\n      ready->done = true;\n      ready->cv.Signal();\n    }\n    if (ready == last_writer) break;\n  }\n\n  // Notify new head of write queue\n  if (!writers_.empty()) {\n    writers_.front()->cv.Signal();\n  }\n\n  return status;\n}\n\n// REQUIRES: Writer list must be non-empty\n// REQUIRES: First writer must have a non-null batch\nWriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {\n  mutex_.AssertHeld();\n  assert(!writers_.empty());\n  Writer* first = writers_.front();\n  WriteBatch* result = first->batch;\n  assert(result != nullptr);\n\n  size_t size = WriteBatchInternal::ByteSize(first->batch);\n\n  // Allow the group to grow up to a maximum size, but if the\n  // original write is small, limit the growth so we do not slow\n  // down the small write too much.\n  size_t max_size = 1 << 20;\n  if (size <= (128 << 10)) {\n    max_size = size + (128 << 10);\n  }\n\n  *last_writer = first;\n  std::deque<Writer*>::iterator iter = writers_.begin();\n  ++iter;  // Advance past \"first\"\n  for (; iter != writers_.end(); ++iter) {\n    Writer* w = *iter;\n    if (w->sync && !first->sync) {\n      // Do not include a sync write into a batch handled by a non-sync write.\n      break;\n    }\n\n    if (w->batch != nullptr) {\n      size += WriteBatchInternal::ByteSize(w->batch);\n      if (size > max_size) {\n        // Do not make batch too big\n        break;\n      }\n\n      // Append to *result\n      if (result == first->batch) {\n        // Switch to temporary batch instead of disturbing caller's batch\n        result = tmp_batch_;\n        assert(WriteBatchInternal::Count(result) == 0);\n        WriteBatchInternal::Append(result, first->batch);\n      }\n      WriteBatchInternal::Append(result, w->batch);\n    }\n    *last_writer = w;\n  }\n  return result;\n}\n\n// REQUIRES: mutex_ is held\n// REQUIRES: this thread is currently at the front of the writer queue\nStatus DBImpl::MakeRoomForWrite(bool force) {\n  mutex_.AssertHeld();\n  assert(!writers_.empty());\n  bool allow_delay = !force;\n  Status s;\n  while (true) {\n    if (!bg_error_.ok()) {\n      // Yield previous error\n      s = bg_error_;\n      break;\n    } else if (allow_delay && versions_->NumLevelFiles(0) >=\n                                  config::kL0_SlowdownWritesTrigger) {\n      // We are getting close to hitting a hard limit on the number of\n      // L0 files.  Rather than delaying a single write by several\n      // seconds when we hit the hard limit, start delaying each\n      // individual write by 1ms to reduce latency variance.  Also,\n      // this delay hands over some CPU to the compaction thread in\n      // case it is sharing the same core as the writer.\n      mutex_.Unlock();\n      env_->SleepForMicroseconds(1000);\n      allow_delay = false;  // Do not delay a single write more than once\n      mutex_.Lock();\n    } else if (!force &&\n               (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {\n      // There is room in current memtable\n      break;\n    } else if (imm_ != nullptr) {\n      // We have filled up the current memtable, but the previous\n      // one is still being compacted, so we wait.\n      Log(options_.info_log, \"Current memtable full; waiting...\\n\");\n      background_work_finished_signal_.Wait();\n    } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {\n      // There are too many level-0 files.\n      Log(options_.info_log, \"Too many L0 files; waiting...\\n\");\n      background_work_finished_signal_.Wait();\n    } else {\n      // Attempt to switch to a new memtable and trigger compaction of old\n      assert(versions_->PrevLogNumber() == 0);\n      uint64_t new_log_number = versions_->NewFileNumber();\n      WritableFile* lfile = nullptr;\n      s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);\n      if (!s.ok()) {\n        // Avoid chewing through file number space in a tight loop.\n        versions_->ReuseFileNumber(new_log_number);\n        break;\n      }\n      delete log_;\n      delete logfile_;\n      logfile_ = lfile;\n      logfile_number_ = new_log_number;\n      log_ = new log::Writer(lfile);\n      imm_ = mem_;\n      has_imm_.store(true, std::memory_order_release);\n      mem_ = new MemTable(internal_comparator_);\n      mem_->Ref();\n      force = false;  // Do not force another compaction if have room\n      MaybeScheduleCompaction();\n    }\n  }\n  return s;\n}\n\nbool DBImpl::GetProperty(const Slice& property, std::string* value) {\n  value->clear();\n\n  MutexLock l(&mutex_);\n  Slice in = property;\n  Slice prefix(\"leveldb.\");\n  if (!in.starts_with(prefix)) return false;\n  in.remove_prefix(prefix.size());\n\n  if (in.starts_with(\"num-files-at-level\")) {\n    in.remove_prefix(strlen(\"num-files-at-level\"));\n    uint64_t level;\n    bool ok = ConsumeDecimalNumber(&in, &level) && in.empty();\n    if (!ok || level >= config::kNumLevels) {\n      return false;\n    } else {\n      char buf[100];\n      snprintf(buf, sizeof(buf), \"%d\",\n               versions_->NumLevelFiles(static_cast<int>(level)));\n      *value = buf;\n      return true;\n    }\n  } else if (in == \"stats\") {\n    char buf[200];\n    snprintf(buf, sizeof(buf),\n             \"                               Compactions\\n\"\n             \"Level  Files Size(MB) Time(sec) Read(MB) Write(MB)\\n\"\n             \"--------------------------------------------------\\n\");\n    value->append(buf);\n    for (int level = 0; level < config::kNumLevels; level++) {\n      int files = versions_->NumLevelFiles(level);\n      if (stats_[level].micros > 0 || files > 0) {\n        snprintf(buf, sizeof(buf), \"%3d %8d %8.0f %9.0f %8.0f %9.0f\\n\", level,\n                 files, versions_->NumLevelBytes(level) / 1048576.0,\n                 stats_[level].micros / 1e6,\n                 stats_[level].bytes_read / 1048576.0,\n                 stats_[level].bytes_written / 1048576.0);\n        value->append(buf);\n      }\n    }\n    return true;\n  } else if (in == \"sstables\") {\n    *value = versions_->current()->DebugString();\n    return true;\n  } else if (in == \"approximate-memory-usage\") {\n    size_t total_usage = options_.block_cache->TotalCharge();\n    if (mem_) {\n      total_usage += mem_->ApproximateMemoryUsage();\n    }\n    if (imm_) {\n      total_usage += imm_->ApproximateMemoryUsage();\n    }\n    char buf[50];\n    snprintf(buf, sizeof(buf), \"%llu\",\n             static_cast<unsigned long long>(total_usage));\n    value->append(buf);\n    return true;\n  }\n\n  return false;\n}\n\nvoid DBImpl::GetApproximateSizes(const Range* range, int n, uint64_t* sizes) {\n  // TODO(opt): better implementation\n  MutexLock l(&mutex_);\n  Version* v = versions_->current();\n  v->Ref();\n\n  for (int i = 0; i < n; i++) {\n    // Convert user_key into a corresponding internal key.\n    InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek);\n    InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek);\n    uint64_t start = versions_->ApproximateOffsetOf(v, k1);\n    uint64_t limit = versions_->ApproximateOffsetOf(v, k2);\n    sizes[i] = (limit >= start ? limit - start : 0);\n  }\n\n  v->Unref();\n}\n\n// Default implementations of convenience methods that subclasses of DB\n// can call if they wish\nStatus DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) {\n  WriteBatch batch;\n  batch.Put(key, value);\n  return Write(opt, &batch);\n}\n\nStatus DB::Delete(const WriteOptions& opt, const Slice& key) {\n  WriteBatch batch;\n  batch.Delete(key);\n  return Write(opt, &batch);\n}\n\nDB::~DB() = default;\n\nStatus DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {\n  *dbptr = nullptr;\n\n  DBImpl* impl = new DBImpl(options, dbname);\n  impl->mutex_.Lock();\n  VersionEdit edit;\n  // Recover handles create_if_missing, error_if_exists\n  bool save_manifest = false;\n  Status s = impl->Recover(&edit, &save_manifest);\n  if (s.ok() && impl->mem_ == nullptr) {\n    // Create new log and a corresponding memtable.\n    uint64_t new_log_number = impl->versions_->NewFileNumber();\n    WritableFile* lfile;\n    s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),\n                                     &lfile);\n    if (s.ok()) {\n      edit.SetLogNumber(new_log_number);\n      impl->logfile_ = lfile;\n      impl->logfile_number_ = new_log_number;\n      impl->log_ = new log::Writer(lfile);\n      impl->mem_ = new MemTable(impl->internal_comparator_);\n      impl->mem_->Ref();\n    }\n  }\n  if (s.ok() && save_manifest) {\n    edit.SetPrevLogNumber(0);  // No older logs needed after recovery.\n    edit.SetLogNumber(impl->logfile_number_);\n    s = impl->versions_->LogAndApply(&edit, &impl->mutex_);\n  }\n  if (s.ok()) {\n    impl->DeleteObsoleteFiles();\n    impl->MaybeScheduleCompaction();\n  }\n  impl->mutex_.Unlock();\n  if (s.ok()) {\n    assert(impl->mem_ != nullptr);\n    *dbptr = impl;\n  } else {\n    delete impl;\n  }\n  return s;\n}\n\nSnapshot::~Snapshot() = default;\n\nStatus DestroyDB(const std::string& dbname, const Options& options) {\n  Env* env = options.env;\n  std::vector<std::string> filenames;\n  Status result = env->GetChildren(dbname, &filenames);\n  if (!result.ok()) {\n    // Ignore error in case directory does not exist\n    return Status::OK();\n  }\n\n  FileLock* lock;\n  const std::string lockname = LockFileName(dbname);\n  result = env->LockFile(lockname, &lock);\n  if (result.ok()) {\n    uint64_t number;\n    FileType type;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      if (ParseFileName(filenames[i], &number, &type) &&\n          type != kDBLockFile) {  // Lock file will be deleted at end\n        Status del = env->DeleteFile(dbname + \"/\" + filenames[i]);\n        if (result.ok() && !del.ok()) {\n          result = del;\n        }\n      }\n    }\n    env->UnlockFile(lock);  // Ignore error since state is already gone\n    env->DeleteFile(lockname);\n    env->DeleteDir(dbname);  // Ignore error in case dir contains other files\n  }\n  return result;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/db_impl.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_\n#define STORAGE_LEVELDB_DB_DB_IMPL_H_\n\n#include <atomic>\n#include <deque>\n#include <set>\n#include <string>\n\n#include \"db/dbformat.h\"\n#include \"db/log_writer.h\"\n#include \"db/snapshot.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n\nnamespace leveldb {\n\nclass MemTable;\nclass TableCache;\nclass Version;\nclass VersionEdit;\nclass VersionSet;\n\nclass DBImpl : public DB {\n public:\n  DBImpl(const Options& options, const std::string& dbname);\n\n  DBImpl(const DBImpl&) = delete;\n  DBImpl& operator=(const DBImpl&) = delete;\n\n  ~DBImpl() override;\n\n  // Implementations of the DB interface\n  Status Put(const WriteOptions&, const Slice& key,\n             const Slice& value) override;\n  Status Delete(const WriteOptions&, const Slice& key) override;\n  Status Write(const WriteOptions& options, WriteBatch* updates) override;\n  Status Get(const ReadOptions& options, const Slice& key,\n             std::string* value) override;\n  Iterator* NewIterator(const ReadOptions&) override;\n  const Snapshot* GetSnapshot() override;\n  void ReleaseSnapshot(const Snapshot* snapshot) override;\n  bool GetProperty(const Slice& property, std::string* value) override;\n  void GetApproximateSizes(const Range* range, int n, uint64_t* sizes) override;\n  void CompactRange(const Slice* begin, const Slice* end) override;\n\n  // Extra methods (for testing) that are not in the public DB interface\n\n  // Compact any files in the named level that overlap [*begin,*end]\n  void TEST_CompactRange(int level, const Slice* begin, const Slice* end);\n\n  // Force current memtable contents to be compacted.\n  Status TEST_CompactMemTable();\n\n  // Return an internal iterator over the current state of the database.\n  // The keys of this iterator are internal keys (see format.h).\n  // The returned iterator should be deleted when no longer needed.\n  Iterator* TEST_NewInternalIterator();\n\n  // Return the maximum overlapping data (in bytes) at next level for any\n  // file at a level >= 1.\n  int64_t TEST_MaxNextLevelOverlappingBytes();\n\n  // Record a sample of bytes read at the specified internal key.\n  // Samples are taken approximately once every config::kReadBytesPeriod\n  // bytes.\n  void RecordReadSample(Slice key);\n\n private:\n  friend class DB;\n  struct CompactionState;\n  struct Writer;\n\n  // Information for a manual compaction\n  struct ManualCompaction {\n    int level;\n    bool done;\n    const InternalKey* begin;  // null means beginning of key range\n    const InternalKey* end;    // null means end of key range\n    InternalKey tmp_storage;   // Used to keep track of compaction progress\n  };\n\n  // Per level compaction stats.  stats_[level] stores the stats for\n  // compactions that produced data for the specified \"level\".\n  struct CompactionStats {\n    CompactionStats() : micros(0), bytes_read(0), bytes_written(0) {}\n\n    void Add(const CompactionStats& c) {\n      this->micros += c.micros;\n      this->bytes_read += c.bytes_read;\n      this->bytes_written += c.bytes_written;\n    }\n\n    int64_t micros;\n    int64_t bytes_read;\n    int64_t bytes_written;\n  };\n\n  Iterator* NewInternalIterator(const ReadOptions&,\n                                SequenceNumber* latest_snapshot,\n                                uint32_t* seed);\n\n  Status NewDB();\n\n  // Recover the descriptor from persistent storage.  May do a significant\n  // amount of work to recover recently logged updates.  Any changes to\n  // be made to the descriptor are added to *edit.\n  Status Recover(VersionEdit* edit, bool* save_manifest)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  void MaybeIgnoreError(Status* s) const;\n\n  // Delete any unneeded files and stale in-memory entries.\n  void DeleteObsoleteFiles() EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  // Compact the in-memory write buffer to disk.  Switches to a new\n  // log-file/memtable and writes a new descriptor iff successful.\n  // Errors are recorded in bg_error_.\n  void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  Status RecoverLogFile(uint64_t log_number, bool last_log, bool* save_manifest,\n                        VersionEdit* edit, SequenceNumber* max_sequence)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  Status MakeRoomForWrite(bool force /* compact even if there is room? */)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n  WriteBatch* BuildBatchGroup(Writer** last_writer)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  void RecordBackgroundError(const Status& s);\n\n  void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n  static void BGWork(void* db);\n  void BackgroundCall();\n  void BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n  void CleanupCompaction(CompactionState* compact)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n  Status DoCompactionWork(CompactionState* compact)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  Status OpenCompactionOutputFile(CompactionState* compact);\n  Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input);\n  Status InstallCompactionResults(CompactionState* compact)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  const Comparator* user_comparator() const {\n    return internal_comparator_.user_comparator();\n  }\n\n  // Constant after construction\n  Env* const env_;\n  const InternalKeyComparator internal_comparator_;\n  const InternalFilterPolicy internal_filter_policy_;\n  const Options options_;  // options_.comparator == &internal_comparator_\n  const bool owns_info_log_;\n  const bool owns_cache_;\n  const std::string dbname_;\n\n  // table_cache_ provides its own synchronization\n  TableCache* const table_cache_;\n\n  // Lock over the persistent DB state.  Non-null iff successfully acquired.\n  FileLock* db_lock_;\n\n  // State below is protected by mutex_\n  port::Mutex mutex_;\n  std::atomic<bool> shutting_down_;\n  port::CondVar background_work_finished_signal_ GUARDED_BY(mutex_);\n  MemTable* mem_;\n  MemTable* imm_ GUARDED_BY(mutex_);  // Memtable being compacted\n  std::atomic<bool> has_imm_;         // So bg thread can detect non-null imm_\n  WritableFile* logfile_;\n  uint64_t logfile_number_ GUARDED_BY(mutex_);\n  log::Writer* log_;\n  uint32_t seed_ GUARDED_BY(mutex_);  // For sampling.\n\n  // Queue of writers.\n  std::deque<Writer*> writers_ GUARDED_BY(mutex_);\n  WriteBatch* tmp_batch_ GUARDED_BY(mutex_);\n\n  SnapshotList snapshots_ GUARDED_BY(mutex_);\n\n  // Set of table files to protect from deletion because they are\n  // part of ongoing compactions.\n  std::set<uint64_t> pending_outputs_ GUARDED_BY(mutex_);\n\n  // Has a background compaction been scheduled or is running?\n  bool background_compaction_scheduled_ GUARDED_BY(mutex_);\n\n  ManualCompaction* manual_compaction_ GUARDED_BY(mutex_);\n\n  VersionSet* const versions_ GUARDED_BY(mutex_);\n\n  // Have we encountered a background error in paranoid mode?\n  Status bg_error_ GUARDED_BY(mutex_);\n\n  CompactionStats stats_[config::kNumLevels] GUARDED_BY(mutex_);\n};\n\n// Sanitize db options.  The caller should delete result.info_log if\n// it is not equal to src.info_log.\nOptions SanitizeOptions(const std::string& db,\n                        const InternalKeyComparator* icmp,\n                        const InternalFilterPolicy* ipolicy,\n                        const Options& src);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_DB_IMPL_H_\n"
  },
  {
    "path": "src/leveldb/db/db_iter.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/db_iter.h\"\n\n#include \"db/db_impl.h\"\n#include \"db/dbformat.h\"\n#include \"db/filename.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/iterator.h\"\n#include \"port/port.h\"\n#include \"util/logging.h\"\n#include \"util/mutexlock.h\"\n#include \"util/random.h\"\n\nnamespace leveldb {\n\n#if 0\nstatic void DumpInternalIter(Iterator* iter) {\n  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n    ParsedInternalKey k;\n    if (!ParseInternalKey(iter->key(), &k)) {\n      fprintf(stderr, \"Corrupt '%s'\\n\", EscapeString(iter->key()).c_str());\n    } else {\n      fprintf(stderr, \"@ '%s'\\n\", k.DebugString().c_str());\n    }\n  }\n}\n#endif\n\nnamespace {\n\n// Memtables and sstables that make the DB representation contain\n// (userkey,seq,type) => uservalue entries.  DBIter\n// combines multiple entries for the same userkey found in the DB\n// representation into a single entry while accounting for sequence\n// numbers, deletion markers, overwrites, etc.\nclass DBIter : public Iterator {\n public:\n  // Which direction is the iterator currently moving?\n  // (1) When moving forward, the internal iterator is positioned at\n  //     the exact entry that yields this->key(), this->value()\n  // (2) When moving backwards, the internal iterator is positioned\n  //     just before all entries whose user key == this->key().\n  enum Direction { kForward, kReverse };\n\n  DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s,\n         uint32_t seed)\n      : db_(db),\n        user_comparator_(cmp),\n        iter_(iter),\n        sequence_(s),\n        direction_(kForward),\n        valid_(false),\n        rnd_(seed),\n        bytes_until_read_sampling_(RandomCompactionPeriod()) {}\n\n  DBIter(const DBIter&) = delete;\n  DBIter& operator=(const DBIter&) = delete;\n\n  ~DBIter() override { delete iter_; }\n  bool Valid() const override { return valid_; }\n  Slice key() const override {\n    assert(valid_);\n    return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_;\n  }\n  Slice value() const override {\n    assert(valid_);\n    return (direction_ == kForward) ? iter_->value() : saved_value_;\n  }\n  Status status() const override {\n    if (status_.ok()) {\n      return iter_->status();\n    } else {\n      return status_;\n    }\n  }\n\n  void Next() override;\n  void Prev() override;\n  void Seek(const Slice& target) override;\n  void SeekToFirst() override;\n  void SeekToLast() override;\n\n private:\n  void FindNextUserEntry(bool skipping, std::string* skip);\n  void FindPrevUserEntry();\n  bool ParseKey(ParsedInternalKey* key);\n\n  inline void SaveKey(const Slice& k, std::string* dst) {\n    dst->assign(k.data(), k.size());\n  }\n\n  inline void ClearSavedValue() {\n    if (saved_value_.capacity() > 1048576) {\n      std::string empty;\n      swap(empty, saved_value_);\n    } else {\n      saved_value_.clear();\n    }\n  }\n\n  // Picks the number of bytes that can be read until a compaction is scheduled.\n  size_t RandomCompactionPeriod() {\n    return rnd_.Uniform(2 * config::kReadBytesPeriod);\n  }\n\n  DBImpl* db_;\n  const Comparator* const user_comparator_;\n  Iterator* const iter_;\n  SequenceNumber const sequence_;\n  Status status_;\n  std::string saved_key_;    // == current key when direction_==kReverse\n  std::string saved_value_;  // == current raw value when direction_==kReverse\n  Direction direction_;\n  bool valid_;\n  Random rnd_;\n  size_t bytes_until_read_sampling_;\n};\n\ninline bool DBIter::ParseKey(ParsedInternalKey* ikey) {\n  Slice k = iter_->key();\n\n  size_t bytes_read = k.size() + iter_->value().size();\n  while (bytes_until_read_sampling_ < bytes_read) {\n    bytes_until_read_sampling_ += RandomCompactionPeriod();\n    db_->RecordReadSample(k);\n  }\n  assert(bytes_until_read_sampling_ >= bytes_read);\n  bytes_until_read_sampling_ -= bytes_read;\n\n  if (!ParseInternalKey(k, ikey)) {\n    status_ = Status::Corruption(\"corrupted internal key in DBIter\");\n    return false;\n  } else {\n    return true;\n  }\n}\n\nvoid DBIter::Next() {\n  assert(valid_);\n\n  if (direction_ == kReverse) {  // Switch directions?\n    direction_ = kForward;\n    // iter_ is pointing just before the entries for this->key(),\n    // so advance into the range of entries for this->key() and then\n    // use the normal skipping code below.\n    if (!iter_->Valid()) {\n      iter_->SeekToFirst();\n    } else {\n      iter_->Next();\n    }\n    if (!iter_->Valid()) {\n      valid_ = false;\n      saved_key_.clear();\n      return;\n    }\n    // saved_key_ already contains the key to skip past.\n  } else {\n    // Store in saved_key_ the current key so we skip it below.\n    SaveKey(ExtractUserKey(iter_->key()), &saved_key_);\n\n    // iter_ is pointing to current key. We can now safely move to the next to\n    // avoid checking current key.\n    iter_->Next();\n    if (!iter_->Valid()) {\n      valid_ = false;\n      saved_key_.clear();\n      return;\n    }\n  }\n\n  FindNextUserEntry(true, &saved_key_);\n}\n\nvoid DBIter::FindNextUserEntry(bool skipping, std::string* skip) {\n  // Loop until we hit an acceptable entry to yield\n  assert(iter_->Valid());\n  assert(direction_ == kForward);\n  do {\n    ParsedInternalKey ikey;\n    if (ParseKey(&ikey) && ikey.sequence <= sequence_) {\n      switch (ikey.type) {\n        case kTypeDeletion:\n          // Arrange to skip all upcoming entries for this key since\n          // they are hidden by this deletion.\n          SaveKey(ikey.user_key, skip);\n          skipping = true;\n          break;\n        case kTypeValue:\n          if (skipping &&\n              user_comparator_->Compare(ikey.user_key, *skip) <= 0) {\n            // Entry hidden\n          } else {\n            valid_ = true;\n            saved_key_.clear();\n            return;\n          }\n          break;\n      }\n    }\n    iter_->Next();\n  } while (iter_->Valid());\n  saved_key_.clear();\n  valid_ = false;\n}\n\nvoid DBIter::Prev() {\n  assert(valid_);\n\n  if (direction_ == kForward) {  // Switch directions?\n    // iter_ is pointing at the current entry.  Scan backwards until\n    // the key changes so we can use the normal reverse scanning code.\n    assert(iter_->Valid());  // Otherwise valid_ would have been false\n    SaveKey(ExtractUserKey(iter_->key()), &saved_key_);\n    while (true) {\n      iter_->Prev();\n      if (!iter_->Valid()) {\n        valid_ = false;\n        saved_key_.clear();\n        ClearSavedValue();\n        return;\n      }\n      if (user_comparator_->Compare(ExtractUserKey(iter_->key()), saved_key_) <\n          0) {\n        break;\n      }\n    }\n    direction_ = kReverse;\n  }\n\n  FindPrevUserEntry();\n}\n\nvoid DBIter::FindPrevUserEntry() {\n  assert(direction_ == kReverse);\n\n  ValueType value_type = kTypeDeletion;\n  if (iter_->Valid()) {\n    do {\n      ParsedInternalKey ikey;\n      if (ParseKey(&ikey) && ikey.sequence <= sequence_) {\n        if ((value_type != kTypeDeletion) &&\n            user_comparator_->Compare(ikey.user_key, saved_key_) < 0) {\n          // We encountered a non-deleted value in entries for previous keys,\n          break;\n        }\n        value_type = ikey.type;\n        if (value_type == kTypeDeletion) {\n          saved_key_.clear();\n          ClearSavedValue();\n        } else {\n          Slice raw_value = iter_->value();\n          if (saved_value_.capacity() > raw_value.size() + 1048576) {\n            std::string empty;\n            swap(empty, saved_value_);\n          }\n          SaveKey(ExtractUserKey(iter_->key()), &saved_key_);\n          saved_value_.assign(raw_value.data(), raw_value.size());\n        }\n      }\n      iter_->Prev();\n    } while (iter_->Valid());\n  }\n\n  if (value_type == kTypeDeletion) {\n    // End\n    valid_ = false;\n    saved_key_.clear();\n    ClearSavedValue();\n    direction_ = kForward;\n  } else {\n    valid_ = true;\n  }\n}\n\nvoid DBIter::Seek(const Slice& target) {\n  direction_ = kForward;\n  ClearSavedValue();\n  saved_key_.clear();\n  AppendInternalKey(&saved_key_,\n                    ParsedInternalKey(target, sequence_, kValueTypeForSeek));\n  iter_->Seek(saved_key_);\n  if (iter_->Valid()) {\n    FindNextUserEntry(false, &saved_key_ /* temporary storage */);\n  } else {\n    valid_ = false;\n  }\n}\n\nvoid DBIter::SeekToFirst() {\n  direction_ = kForward;\n  ClearSavedValue();\n  iter_->SeekToFirst();\n  if (iter_->Valid()) {\n    FindNextUserEntry(false, &saved_key_ /* temporary storage */);\n  } else {\n    valid_ = false;\n  }\n}\n\nvoid DBIter::SeekToLast() {\n  direction_ = kReverse;\n  ClearSavedValue();\n  iter_->SeekToLast();\n  FindPrevUserEntry();\n}\n\n}  // anonymous namespace\n\nIterator* NewDBIterator(DBImpl* db, const Comparator* user_key_comparator,\n                        Iterator* internal_iter, SequenceNumber sequence,\n                        uint32_t seed) {\n  return new DBIter(db, user_key_comparator, internal_iter, sequence, seed);\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/db_iter.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_\n#define STORAGE_LEVELDB_DB_DB_ITER_H_\n\n#include <stdint.h>\n\n#include \"db/dbformat.h\"\n#include \"leveldb/db.h\"\n\nnamespace leveldb {\n\nclass DBImpl;\n\n// Return a new iterator that converts internal keys (yielded by\n// \"*internal_iter\") that were live at the specified \"sequence\" number\n// into appropriate user keys.\nIterator* NewDBIterator(DBImpl* db, const Comparator* user_key_comparator,\n                        Iterator* internal_iter, SequenceNumber sequence,\n                        uint32_t seed);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_DB_ITER_H_\n"
  },
  {
    "path": "src/leveldb/db/db_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/db.h\"\n\n#include <atomic>\n#include <string>\n\n#include \"db/db_impl.h\"\n#include \"db/filename.h\"\n#include \"db/version_set.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/cache.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/table.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/hash.h\"\n#include \"util/logging.h\"\n#include \"util/mutexlock.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nstatic std::string RandomString(Random* rnd, int len) {\n  std::string r;\n  test::RandomString(rnd, len, &r);\n  return r;\n}\n\nstatic std::string RandomKey(Random* rnd) {\n  int len =\n      (rnd->OneIn(3) ? 1  // Short sometimes to encourage collisions\n                     : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));\n  return test::RandomKey(rnd, len);\n}\n\nnamespace {\nclass AtomicCounter {\n public:\n  AtomicCounter() : count_(0) {}\n  void Increment() { IncrementBy(1); }\n  void IncrementBy(int count) LOCKS_EXCLUDED(mu_) {\n    MutexLock l(&mu_);\n    count_ += count;\n  }\n  int Read() LOCKS_EXCLUDED(mu_) {\n    MutexLock l(&mu_);\n    return count_;\n  }\n  void Reset() LOCKS_EXCLUDED(mu_) {\n    MutexLock l(&mu_);\n    count_ = 0;\n  }\n\n private:\n  port::Mutex mu_;\n  int count_ GUARDED_BY(mu_);\n};\n\nvoid DelayMilliseconds(int millis) {\n  Env::Default()->SleepForMicroseconds(millis * 1000);\n}\n}  // namespace\n\n// Test Env to override default Env behavior for testing.\nclass TestEnv : public EnvWrapper {\n public:\n  explicit TestEnv(Env* base) : EnvWrapper(base), ignore_dot_files_(false) {}\n\n  void SetIgnoreDotFiles(bool ignored) { ignore_dot_files_ = ignored; }\n\n  Status GetChildren(const std::string& dir,\n                     std::vector<std::string>* result) override {\n    Status s = target()->GetChildren(dir, result);\n    if (!s.ok() || !ignore_dot_files_) {\n      return s;\n    }\n\n    std::vector<std::string>::iterator it = result->begin();\n    while (it != result->end()) {\n      if ((*it == \".\") || (*it == \"..\")) {\n        it = result->erase(it);\n      } else {\n        ++it;\n      }\n    }\n\n    return s;\n  }\n\n private:\n  bool ignore_dot_files_;\n};\n\n// Special Env used to delay background operations.\nclass SpecialEnv : public EnvWrapper {\n public:\n  // sstable/log Sync() calls are blocked while this pointer is non-null.\n  std::atomic<bool> delay_data_sync_;\n\n  // sstable/log Sync() calls return an error.\n  std::atomic<bool> data_sync_error_;\n\n  // Simulate no-space errors while this pointer is non-null.\n  std::atomic<bool> no_space_;\n\n  // Simulate non-writable file system while this pointer is non-null.\n  std::atomic<bool> non_writable_;\n\n  // Force sync of manifest files to fail while this pointer is non-null.\n  std::atomic<bool> manifest_sync_error_;\n\n  // Force write to manifest files to fail while this pointer is non-null.\n  std::atomic<bool> manifest_write_error_;\n\n  bool count_random_reads_;\n  AtomicCounter random_read_counter_;\n\n  explicit SpecialEnv(Env* base)\n      : EnvWrapper(base),\n        delay_data_sync_(false),\n        data_sync_error_(false),\n        no_space_(false),\n        non_writable_(false),\n        manifest_sync_error_(false),\n        manifest_write_error_(false),\n        count_random_reads_(false) {}\n\n  Status NewWritableFile(const std::string& f, WritableFile** r) {\n    class DataFile : public WritableFile {\n     private:\n      SpecialEnv* const env_;\n      WritableFile* const base_;\n\n     public:\n      DataFile(SpecialEnv* env, WritableFile* base) : env_(env), base_(base) {}\n      ~DataFile() { delete base_; }\n      Status Append(const Slice& data) {\n        if (env_->no_space_.load(std::memory_order_acquire)) {\n          // Drop writes on the floor\n          return Status::OK();\n        } else {\n          return base_->Append(data);\n        }\n      }\n      Status Close() { return base_->Close(); }\n      Status Flush() { return base_->Flush(); }\n      Status Sync() {\n        if (env_->data_sync_error_.load(std::memory_order_acquire)) {\n          return Status::IOError(\"simulated data sync error\");\n        }\n        while (env_->delay_data_sync_.load(std::memory_order_acquire)) {\n          DelayMilliseconds(100);\n        }\n        return base_->Sync();\n      }\n      std::string GetName() const override { return \"\"; }\n    };\n    class ManifestFile : public WritableFile {\n     private:\n      SpecialEnv* env_;\n      WritableFile* base_;\n\n     public:\n      ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) {}\n      ~ManifestFile() { delete base_; }\n      Status Append(const Slice& data) {\n        if (env_->manifest_write_error_.load(std::memory_order_acquire)) {\n          return Status::IOError(\"simulated writer error\");\n        } else {\n          return base_->Append(data);\n        }\n      }\n      Status Close() { return base_->Close(); }\n      Status Flush() { return base_->Flush(); }\n      Status Sync() {\n        if (env_->manifest_sync_error_.load(std::memory_order_acquire)) {\n          return Status::IOError(\"simulated sync error\");\n        } else {\n          return base_->Sync();\n        }\n      }\n      std::string GetName() const override { return \"\"; }\n    };\n\n    if (non_writable_.load(std::memory_order_acquire)) {\n      return Status::IOError(\"simulated write error\");\n    }\n\n    Status s = target()->NewWritableFile(f, r);\n    if (s.ok()) {\n      if (strstr(f.c_str(), \".ldb\") != nullptr ||\n          strstr(f.c_str(), \".log\") != nullptr) {\n        *r = new DataFile(this, *r);\n      } else if (strstr(f.c_str(), \"MANIFEST\") != nullptr) {\n        *r = new ManifestFile(this, *r);\n      }\n    }\n    return s;\n  }\n\n  Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) {\n    class CountingFile : public RandomAccessFile {\n     private:\n      RandomAccessFile* target_;\n      AtomicCounter* counter_;\n\n     public:\n      CountingFile(RandomAccessFile* target, AtomicCounter* counter)\n          : target_(target), counter_(counter) {}\n      ~CountingFile() override { delete target_; }\n      Status Read(uint64_t offset, size_t n, Slice* result,\n                  char* scratch) const override {\n        counter_->Increment();\n        return target_->Read(offset, n, result, scratch);\n      }\n      std::string GetName() const override { return \"\"; }\n    };\n\n    Status s = target()->NewRandomAccessFile(f, r);\n    if (s.ok() && count_random_reads_) {\n      *r = new CountingFile(*r, &random_read_counter_);\n    }\n    return s;\n  }\n};\n\nclass DBTest {\n public:\n  std::string dbname_;\n  SpecialEnv* env_;\n  DB* db_;\n\n  Options last_options_;\n\n  DBTest() : env_(new SpecialEnv(Env::Default())), option_config_(kDefault) {\n    filter_policy_ = NewBloomFilterPolicy(10);\n    dbname_ = test::TmpDir() + \"/db_test\";\n    DestroyDB(dbname_, Options());\n    db_ = nullptr;\n    Reopen();\n  }\n\n  ~DBTest() {\n    delete db_;\n    DestroyDB(dbname_, Options());\n    delete env_;\n    delete filter_policy_;\n  }\n\n  // Switch to a fresh database with the next option configuration to\n  // test.  Return false if there are no more configurations to test.\n  bool ChangeOptions() {\n    option_config_++;\n    if (option_config_ >= kEnd) {\n      return false;\n    } else {\n      DestroyAndReopen();\n      return true;\n    }\n  }\n\n  // Return the current option configuration.\n  Options CurrentOptions() {\n    Options options;\n    options.reuse_logs = false;\n    switch (option_config_) {\n      case kReuse:\n        options.reuse_logs = true;\n        break;\n      case kFilter:\n        options.filter_policy = filter_policy_;\n        break;\n      case kUncompressed:\n        options.compression = kNoCompression;\n        break;\n      default:\n        break;\n    }\n    return options;\n  }\n\n  DBImpl* dbfull() { return reinterpret_cast<DBImpl*>(db_); }\n\n  void Reopen(Options* options = nullptr) { ASSERT_OK(TryReopen(options)); }\n\n  void Close() {\n    delete db_;\n    db_ = nullptr;\n  }\n\n  void DestroyAndReopen(Options* options = nullptr) {\n    delete db_;\n    db_ = nullptr;\n    DestroyDB(dbname_, Options());\n    ASSERT_OK(TryReopen(options));\n  }\n\n  Status TryReopen(Options* options) {\n    delete db_;\n    db_ = nullptr;\n    Options opts;\n    if (options != nullptr) {\n      opts = *options;\n    } else {\n      opts = CurrentOptions();\n      opts.create_if_missing = true;\n    }\n    last_options_ = opts;\n\n    return DB::Open(opts, dbname_, &db_);\n  }\n\n  Status Put(const std::string& k, const std::string& v) {\n    return db_->Put(WriteOptions(), k, v);\n  }\n\n  Status Delete(const std::string& k) { return db_->Delete(WriteOptions(), k); }\n\n  std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {\n    ReadOptions options;\n    options.snapshot = snapshot;\n    std::string result;\n    Status s = db_->Get(options, k, &result);\n    if (s.IsNotFound()) {\n      result = \"NOT_FOUND\";\n    } else if (!s.ok()) {\n      result = s.ToString();\n    }\n    return result;\n  }\n\n  // Return a string that contains all key,value pairs in order,\n  // formatted like \"(k1->v1)(k2->v2)\".\n  std::string Contents() {\n    std::vector<std::string> forward;\n    std::string result;\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n      std::string s = IterStatus(iter);\n      result.push_back('(');\n      result.append(s);\n      result.push_back(')');\n      forward.push_back(s);\n    }\n\n    // Check reverse iteration results are the reverse of forward results\n    size_t matched = 0;\n    for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {\n      ASSERT_LT(matched, forward.size());\n      ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);\n      matched++;\n    }\n    ASSERT_EQ(matched, forward.size());\n\n    delete iter;\n    return result;\n  }\n\n  std::string AllEntriesFor(const Slice& user_key) {\n    Iterator* iter = dbfull()->TEST_NewInternalIterator();\n    InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);\n    iter->Seek(target.Encode());\n    std::string result;\n    if (!iter->status().ok()) {\n      result = iter->status().ToString();\n    } else {\n      result = \"[ \";\n      bool first = true;\n      while (iter->Valid()) {\n        ParsedInternalKey ikey;\n        if (!ParseInternalKey(iter->key(), &ikey)) {\n          result += \"CORRUPTED\";\n        } else {\n          if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) {\n            break;\n          }\n          if (!first) {\n            result += \", \";\n          }\n          first = false;\n          switch (ikey.type) {\n            case kTypeValue:\n              result += iter->value().ToString();\n              break;\n            case kTypeDeletion:\n              result += \"DEL\";\n              break;\n          }\n        }\n        iter->Next();\n      }\n      if (!first) {\n        result += \" \";\n      }\n      result += \"]\";\n    }\n    delete iter;\n    return result;\n  }\n\n  int NumTableFilesAtLevel(int level) {\n    std::string property;\n    ASSERT_TRUE(db_->GetProperty(\n        \"leveldb.num-files-at-level\" + NumberToString(level), &property));\n    return std::stoi(property);\n  }\n\n  int TotalTableFiles() {\n    int result = 0;\n    for (int level = 0; level < config::kNumLevels; level++) {\n      result += NumTableFilesAtLevel(level);\n    }\n    return result;\n  }\n\n  // Return spread of files per level\n  std::string FilesPerLevel() {\n    std::string result;\n    int last_non_zero_offset = 0;\n    for (int level = 0; level < config::kNumLevels; level++) {\n      int f = NumTableFilesAtLevel(level);\n      char buf[100];\n      snprintf(buf, sizeof(buf), \"%s%d\", (level ? \",\" : \"\"), f);\n      result += buf;\n      if (f > 0) {\n        last_non_zero_offset = result.size();\n      }\n    }\n    result.resize(last_non_zero_offset);\n    return result;\n  }\n\n  int CountFiles() {\n    std::vector<std::string> files;\n    env_->GetChildren(dbname_, &files);\n    return static_cast<int>(files.size());\n  }\n\n  uint64_t Size(const Slice& start, const Slice& limit) {\n    Range r(start, limit);\n    uint64_t size;\n    db_->GetApproximateSizes(&r, 1, &size);\n    return size;\n  }\n\n  void Compact(const Slice& start, const Slice& limit) {\n    db_->CompactRange(&start, &limit);\n  }\n\n  // Do n memtable compactions, each of which produces an sstable\n  // covering the range [small_key,large_key].\n  void MakeTables(int n, const std::string& small_key,\n                  const std::string& large_key) {\n    for (int i = 0; i < n; i++) {\n      Put(small_key, \"begin\");\n      Put(large_key, \"end\");\n      dbfull()->TEST_CompactMemTable();\n    }\n  }\n\n  // Prevent pushing of new sstables into deeper levels by adding\n  // tables that cover a specified range to all levels.\n  void FillLevels(const std::string& smallest, const std::string& largest) {\n    MakeTables(config::kNumLevels, smallest, largest);\n  }\n\n  void DumpFileCounts(const char* label) {\n    fprintf(stderr, \"---\\n%s:\\n\", label);\n    fprintf(\n        stderr, \"maxoverlap: %lld\\n\",\n        static_cast<long long>(dbfull()->TEST_MaxNextLevelOverlappingBytes()));\n    for (int level = 0; level < config::kNumLevels; level++) {\n      int num = NumTableFilesAtLevel(level);\n      if (num > 0) {\n        fprintf(stderr, \"  level %3d : %d files\\n\", level, num);\n      }\n    }\n  }\n\n  std::string DumpSSTableList() {\n    std::string property;\n    db_->GetProperty(\"leveldb.sstables\", &property);\n    return property;\n  }\n\n  std::string IterStatus(Iterator* iter) {\n    std::string result;\n    if (iter->Valid()) {\n      result = iter->key().ToString() + \"->\" + iter->value().ToString();\n    } else {\n      result = \"(invalid)\";\n    }\n    return result;\n  }\n\n  bool DeleteAnSSTFile() {\n    std::vector<std::string> filenames;\n    ASSERT_OK(env_->GetChildren(dbname_, &filenames));\n    uint64_t number;\n    FileType type;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {\n        ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number)));\n        return true;\n      }\n    }\n    return false;\n  }\n\n  // Returns number of files renamed.\n  int RenameLDBToSST() {\n    std::vector<std::string> filenames;\n    ASSERT_OK(env_->GetChildren(dbname_, &filenames));\n    uint64_t number;\n    FileType type;\n    int files_renamed = 0;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {\n        const std::string from = TableFileName(dbname_, number);\n        const std::string to = SSTTableFileName(dbname_, number);\n        ASSERT_OK(env_->RenameFile(from, to));\n        files_renamed++;\n      }\n    }\n    return files_renamed;\n  }\n\n private:\n  // Sequence of option configurations to try\n  enum OptionConfig { kDefault, kReuse, kFilter, kUncompressed, kEnd };\n\n  const FilterPolicy* filter_policy_;\n  int option_config_;\n};\n\nTEST(DBTest, Empty) {\n  do {\n    ASSERT_TRUE(db_ != nullptr);\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, EmptyKey) {\n  do {\n    ASSERT_OK(Put(\"\", \"v1\"));\n    ASSERT_EQ(\"v1\", Get(\"\"));\n    ASSERT_OK(Put(\"\", \"v2\"));\n    ASSERT_EQ(\"v2\", Get(\"\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, EmptyValue) {\n  do {\n    ASSERT_OK(Put(\"key\", \"v1\"));\n    ASSERT_EQ(\"v1\", Get(\"key\"));\n    ASSERT_OK(Put(\"key\", \"\"));\n    ASSERT_EQ(\"\", Get(\"key\"));\n    ASSERT_OK(Put(\"key\", \"v2\"));\n    ASSERT_EQ(\"v2\", Get(\"key\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, ReadWrite) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    ASSERT_OK(Put(\"bar\", \"v2\"));\n    ASSERT_OK(Put(\"foo\", \"v3\"));\n    ASSERT_EQ(\"v3\", Get(\"foo\"));\n    ASSERT_EQ(\"v2\", Get(\"bar\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, PutDeleteGet) {\n  do {\n    ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v1\"));\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    ASSERT_OK(db_->Put(WriteOptions(), \"foo\", \"v2\"));\n    ASSERT_EQ(\"v2\", Get(\"foo\"));\n    ASSERT_OK(db_->Delete(WriteOptions(), \"foo\"));\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetFromImmutableLayer) {\n  do {\n    Options options = CurrentOptions();\n    options.env = env_;\n    options.write_buffer_size = 100000;  // Small write buffer\n    Reopen(&options);\n\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n\n    // Block sync calls.\n    env_->delay_data_sync_.store(true, std::memory_order_release);\n    Put(\"k1\", std::string(100000, 'x'));  // Fill memtable.\n    Put(\"k2\", std::string(100000, 'y'));  // Trigger compaction.\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    // Release sync calls.\n    env_->delay_data_sync_.store(false, std::memory_order_release);\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetFromVersions) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetMemUsage) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    std::string val;\n    ASSERT_TRUE(db_->GetProperty(\"leveldb.approximate-memory-usage\", &val));\n    int mem_usage = std::stoi(val);\n    ASSERT_GT(mem_usage, 0);\n    ASSERT_LT(mem_usage, 5 * 1024 * 1024);\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetSnapshot) {\n  do {\n    // Try with both a short key and a long key\n    for (int i = 0; i < 2; i++) {\n      std::string key = (i == 0) ? std::string(\"foo\") : std::string(200, 'x');\n      ASSERT_OK(Put(key, \"v1\"));\n      const Snapshot* s1 = db_->GetSnapshot();\n      ASSERT_OK(Put(key, \"v2\"));\n      ASSERT_EQ(\"v2\", Get(key));\n      ASSERT_EQ(\"v1\", Get(key, s1));\n      dbfull()->TEST_CompactMemTable();\n      ASSERT_EQ(\"v2\", Get(key));\n      ASSERT_EQ(\"v1\", Get(key, s1));\n      db_->ReleaseSnapshot(s1);\n    }\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetIdenticalSnapshots) {\n  do {\n    // Try with both a short key and a long key\n    for (int i = 0; i < 2; i++) {\n      std::string key = (i == 0) ? std::string(\"foo\") : std::string(200, 'x');\n      ASSERT_OK(Put(key, \"v1\"));\n      const Snapshot* s1 = db_->GetSnapshot();\n      const Snapshot* s2 = db_->GetSnapshot();\n      const Snapshot* s3 = db_->GetSnapshot();\n      ASSERT_OK(Put(key, \"v2\"));\n      ASSERT_EQ(\"v2\", Get(key));\n      ASSERT_EQ(\"v1\", Get(key, s1));\n      ASSERT_EQ(\"v1\", Get(key, s2));\n      ASSERT_EQ(\"v1\", Get(key, s3));\n      db_->ReleaseSnapshot(s1);\n      dbfull()->TEST_CompactMemTable();\n      ASSERT_EQ(\"v2\", Get(key));\n      ASSERT_EQ(\"v1\", Get(key, s2));\n      db_->ReleaseSnapshot(s2);\n      ASSERT_EQ(\"v1\", Get(key, s3));\n      db_->ReleaseSnapshot(s3);\n    }\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, IterateOverEmptySnapshot) {\n  do {\n    const Snapshot* snapshot = db_->GetSnapshot();\n    ReadOptions read_options;\n    read_options.snapshot = snapshot;\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    ASSERT_OK(Put(\"foo\", \"v2\"));\n\n    Iterator* iterator1 = db_->NewIterator(read_options);\n    iterator1->SeekToFirst();\n    ASSERT_TRUE(!iterator1->Valid());\n    delete iterator1;\n\n    dbfull()->TEST_CompactMemTable();\n\n    Iterator* iterator2 = db_->NewIterator(read_options);\n    iterator2->SeekToFirst();\n    ASSERT_TRUE(!iterator2->Valid());\n    delete iterator2;\n\n    db_->ReleaseSnapshot(snapshot);\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetLevel0Ordering) {\n  do {\n    // Check that we process level-0 files in correct order.  The code\n    // below generates two level-0 files where the earlier one comes\n    // before the later one in the level-0 file list since the earlier\n    // one has a smaller \"smallest\" key.\n    ASSERT_OK(Put(\"bar\", \"b\"));\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_OK(Put(\"foo\", \"v2\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"v2\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetOrderedByLevels) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    Compact(\"a\", \"z\");\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    ASSERT_OK(Put(\"foo\", \"v2\"));\n    ASSERT_EQ(\"v2\", Get(\"foo\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"v2\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetPicksCorrectFile) {\n  do {\n    // Arrange to have multiple files in a non-level-0 level.\n    ASSERT_OK(Put(\"a\", \"va\"));\n    Compact(\"a\", \"b\");\n    ASSERT_OK(Put(\"x\", \"vx\"));\n    Compact(\"x\", \"y\");\n    ASSERT_OK(Put(\"f\", \"vf\"));\n    Compact(\"f\", \"g\");\n    ASSERT_EQ(\"va\", Get(\"a\"));\n    ASSERT_EQ(\"vf\", Get(\"f\"));\n    ASSERT_EQ(\"vx\", Get(\"x\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, GetEncountersEmptyLevel) {\n  do {\n    // Arrange for the following to happen:\n    //   * sstable A in level 0\n    //   * nothing in level 1\n    //   * sstable B in level 2\n    // Then do enough Get() calls to arrange for an automatic compaction\n    // of sstable A.  A bug would cause the compaction to be marked as\n    // occurring at level 1 (instead of the correct level 0).\n\n    // Step 1: First place sstables in levels 0 and 2\n    int compaction_count = 0;\n    while (NumTableFilesAtLevel(0) == 0 || NumTableFilesAtLevel(2) == 0) {\n      ASSERT_LE(compaction_count, 100) << \"could not fill levels 0 and 2\";\n      compaction_count++;\n      Put(\"a\", \"begin\");\n      Put(\"z\", \"end\");\n      dbfull()->TEST_CompactMemTable();\n    }\n\n    // Step 2: clear level 1 if necessary.\n    dbfull()->TEST_CompactRange(1, nullptr, nullptr);\n    ASSERT_EQ(NumTableFilesAtLevel(0), 1);\n    ASSERT_EQ(NumTableFilesAtLevel(1), 0);\n    ASSERT_EQ(NumTableFilesAtLevel(2), 1);\n\n    // Step 3: read a bunch of times\n    for (int i = 0; i < 1000; i++) {\n      ASSERT_EQ(\"NOT_FOUND\", Get(\"missing\"));\n    }\n\n    // Step 4: Wait for compaction to finish\n    DelayMilliseconds(1000);\n\n    ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, IterEmpty) {\n  Iterator* iter = db_->NewIterator(ReadOptions());\n\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->Seek(\"foo\");\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  delete iter;\n}\n\nTEST(DBTest, IterSingle) {\n  ASSERT_OK(Put(\"a\", \"va\"));\n  Iterator* iter = db_->NewIterator(ReadOptions());\n\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->Seek(\"\");\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->Seek(\"a\");\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->Seek(\"b\");\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  delete iter;\n}\n\nTEST(DBTest, IterMulti) {\n  ASSERT_OK(Put(\"a\", \"va\"));\n  ASSERT_OK(Put(\"b\", \"vb\"));\n  ASSERT_OK(Put(\"c\", \"vc\"));\n  Iterator* iter = db_->NewIterator(ReadOptions());\n\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->Seek(\"\");\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Seek(\"a\");\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Seek(\"ax\");\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Seek(\"b\");\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Seek(\"z\");\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  // Switch from reverse to forward\n  iter->SeekToLast();\n  iter->Prev();\n  iter->Prev();\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n\n  // Switch from forward to reverse\n  iter->SeekToFirst();\n  iter->Next();\n  iter->Next();\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n\n  // Make sure iter stays at snapshot\n  ASSERT_OK(Put(\"a\", \"va2\"));\n  ASSERT_OK(Put(\"a2\", \"va3\"));\n  ASSERT_OK(Put(\"b\", \"vb2\"));\n  ASSERT_OK(Put(\"c\", \"vc2\"));\n  ASSERT_OK(Delete(\"b\"));\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"b->vb\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  delete iter;\n}\n\nTEST(DBTest, IterSmallAndLargeMix) {\n  ASSERT_OK(Put(\"a\", \"va\"));\n  ASSERT_OK(Put(\"b\", std::string(100000, 'b')));\n  ASSERT_OK(Put(\"c\", \"vc\"));\n  ASSERT_OK(Put(\"d\", std::string(100000, 'd')));\n  ASSERT_OK(Put(\"e\", std::string(100000, 'e')));\n\n  Iterator* iter = db_->NewIterator(ReadOptions());\n\n  iter->SeekToFirst();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"b->\" + std::string(100000, 'b'));\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"d->\" + std::string(100000, 'd'));\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"e->\" + std::string(100000, 'e'));\n  iter->Next();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  iter->SeekToLast();\n  ASSERT_EQ(IterStatus(iter), \"e->\" + std::string(100000, 'e'));\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"d->\" + std::string(100000, 'd'));\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"c->vc\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"b->\" + std::string(100000, 'b'));\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"a->va\");\n  iter->Prev();\n  ASSERT_EQ(IterStatus(iter), \"(invalid)\");\n\n  delete iter;\n}\n\nTEST(DBTest, IterMultiWithDelete) {\n  do {\n    ASSERT_OK(Put(\"a\", \"va\"));\n    ASSERT_OK(Put(\"b\", \"vb\"));\n    ASSERT_OK(Put(\"c\", \"vc\"));\n    ASSERT_OK(Delete(\"b\"));\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"b\"));\n\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    iter->Seek(\"c\");\n    ASSERT_EQ(IterStatus(iter), \"c->vc\");\n    iter->Prev();\n    ASSERT_EQ(IterStatus(iter), \"a->va\");\n    delete iter;\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, Recover) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    ASSERT_OK(Put(\"baz\", \"v5\"));\n\n    Reopen();\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    ASSERT_EQ(\"v5\", Get(\"baz\"));\n    ASSERT_OK(Put(\"bar\", \"v2\"));\n    ASSERT_OK(Put(\"foo\", \"v3\"));\n\n    Reopen();\n    ASSERT_EQ(\"v3\", Get(\"foo\"));\n    ASSERT_OK(Put(\"foo\", \"v4\"));\n    ASSERT_EQ(\"v4\", Get(\"foo\"));\n    ASSERT_EQ(\"v2\", Get(\"bar\"));\n    ASSERT_EQ(\"v5\", Get(\"baz\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, RecoveryWithEmptyLog) {\n  do {\n    ASSERT_OK(Put(\"foo\", \"v1\"));\n    ASSERT_OK(Put(\"foo\", \"v2\"));\n    Reopen();\n    Reopen();\n    ASSERT_OK(Put(\"foo\", \"v3\"));\n    Reopen();\n    ASSERT_EQ(\"v3\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\n// Check that writes done during a memtable compaction are recovered\n// if the database is shutdown during the memtable compaction.\nTEST(DBTest, RecoverDuringMemtableCompaction) {\n  do {\n    Options options = CurrentOptions();\n    options.env = env_;\n    options.write_buffer_size = 1000000;\n    Reopen(&options);\n\n    // Trigger a long memtable compaction and reopen the database during it\n    ASSERT_OK(Put(\"foo\", \"v1\"));                         // Goes to 1st log file\n    ASSERT_OK(Put(\"big1\", std::string(10000000, 'x')));  // Fills memtable\n    ASSERT_OK(Put(\"big2\", std::string(1000, 'y')));      // Triggers compaction\n    ASSERT_OK(Put(\"bar\", \"v2\"));                         // Goes to new log file\n\n    Reopen(&options);\n    ASSERT_EQ(\"v1\", Get(\"foo\"));\n    ASSERT_EQ(\"v2\", Get(\"bar\"));\n    ASSERT_EQ(std::string(10000000, 'x'), Get(\"big1\"));\n    ASSERT_EQ(std::string(1000, 'y'), Get(\"big2\"));\n  } while (ChangeOptions());\n}\n\nstatic std::string Key(int i) {\n  char buf[100];\n  snprintf(buf, sizeof(buf), \"key%06d\", i);\n  return std::string(buf);\n}\n\nTEST(DBTest, MinorCompactionsHappen) {\n  Options options = CurrentOptions();\n  options.write_buffer_size = 10000;\n  Reopen(&options);\n\n  const int N = 500;\n\n  int starting_num_tables = TotalTableFiles();\n  for (int i = 0; i < N; i++) {\n    ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));\n  }\n  int ending_num_tables = TotalTableFiles();\n  ASSERT_GT(ending_num_tables, starting_num_tables);\n\n  for (int i = 0; i < N; i++) {\n    ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));\n  }\n\n  Reopen();\n\n  for (int i = 0; i < N; i++) {\n    ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));\n  }\n}\n\nTEST(DBTest, RecoverWithLargeLog) {\n  {\n    Options options = CurrentOptions();\n    Reopen(&options);\n    ASSERT_OK(Put(\"big1\", std::string(200000, '1')));\n    ASSERT_OK(Put(\"big2\", std::string(200000, '2')));\n    ASSERT_OK(Put(\"small3\", std::string(10, '3')));\n    ASSERT_OK(Put(\"small4\", std::string(10, '4')));\n    ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n  }\n\n  // Make sure that if we re-open with a small write buffer size that\n  // we flush table files in the middle of a large log file.\n  Options options = CurrentOptions();\n  options.write_buffer_size = 100000;\n  Reopen(&options);\n  ASSERT_EQ(NumTableFilesAtLevel(0), 3);\n  ASSERT_EQ(std::string(200000, '1'), Get(\"big1\"));\n  ASSERT_EQ(std::string(200000, '2'), Get(\"big2\"));\n  ASSERT_EQ(std::string(10, '3'), Get(\"small3\"));\n  ASSERT_EQ(std::string(10, '4'), Get(\"small4\"));\n  ASSERT_GT(NumTableFilesAtLevel(0), 1);\n}\n\nTEST(DBTest, CompactionsGenerateMultipleFiles) {\n  Options options = CurrentOptions();\n  options.write_buffer_size = 100000000;  // Large write buffer\n  Reopen(&options);\n\n  Random rnd(301);\n\n  // Write 8MB (80 values, each 100K)\n  ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n  std::vector<std::string> values;\n  for (int i = 0; i < 80; i++) {\n    values.push_back(RandomString(&rnd, 100000));\n    ASSERT_OK(Put(Key(i), values[i]));\n  }\n\n  // Reopening moves updates to level-0\n  Reopen(&options);\n  dbfull()->TEST_CompactRange(0, nullptr, nullptr);\n\n  ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n  ASSERT_GT(NumTableFilesAtLevel(1), 1);\n  for (int i = 0; i < 80; i++) {\n    ASSERT_EQ(Get(Key(i)), values[i]);\n  }\n}\n\nTEST(DBTest, RepeatedWritesToSameKey) {\n  Options options = CurrentOptions();\n  options.env = env_;\n  options.write_buffer_size = 100000;  // Small write buffer\n  Reopen(&options);\n\n  // We must have at most one file per level except for level-0,\n  // which may have up to kL0_StopWritesTrigger files.\n  const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger;\n\n  Random rnd(301);\n  std::string value = RandomString(&rnd, 2 * options.write_buffer_size);\n  for (int i = 0; i < 5 * kMaxFiles; i++) {\n    Put(\"key\", value);\n    ASSERT_LE(TotalTableFiles(), kMaxFiles);\n    fprintf(stderr, \"after %d: %d files\\n\", i + 1, TotalTableFiles());\n  }\n}\n\nTEST(DBTest, SparseMerge) {\n  Options options = CurrentOptions();\n  options.compression = kNoCompression;\n  Reopen(&options);\n\n  FillLevels(\"A\", \"Z\");\n\n  // Suppose there is:\n  //    small amount of data with prefix A\n  //    large amount of data with prefix B\n  //    small amount of data with prefix C\n  // and that recent updates have made small changes to all three prefixes.\n  // Check that we do not do a compaction that merges all of B in one shot.\n  const std::string value(1000, 'x');\n  Put(\"A\", \"va\");\n  // Write approximately 100MB of \"B\" values\n  for (int i = 0; i < 100000; i++) {\n    char key[100];\n    snprintf(key, sizeof(key), \"B%010d\", i);\n    Put(key, value);\n  }\n  Put(\"C\", \"vc\");\n  dbfull()->TEST_CompactMemTable();\n  dbfull()->TEST_CompactRange(0, nullptr, nullptr);\n\n  // Make sparse update\n  Put(\"A\", \"va2\");\n  Put(\"B100\", \"bvalue2\");\n  Put(\"C\", \"vc2\");\n  dbfull()->TEST_CompactMemTable();\n\n  // Compactions should not cause us to create a situation where\n  // a file overlaps too much data at the next level.\n  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);\n  dbfull()->TEST_CompactRange(0, nullptr, nullptr);\n  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);\n  dbfull()->TEST_CompactRange(1, nullptr, nullptr);\n  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20 * 1048576);\n}\n\nstatic bool Between(uint64_t val, uint64_t low, uint64_t high) {\n  bool result = (val >= low) && (val <= high);\n  if (!result) {\n    fprintf(stderr, \"Value %llu is not in range [%llu, %llu]\\n\",\n            (unsigned long long)(val), (unsigned long long)(low),\n            (unsigned long long)(high));\n  }\n  return result;\n}\n\nTEST(DBTest, ApproximateSizes) {\n  do {\n    Options options = CurrentOptions();\n    options.write_buffer_size = 100000000;  // Large write buffer\n    options.compression = kNoCompression;\n    DestroyAndReopen();\n\n    ASSERT_TRUE(Between(Size(\"\", \"xyz\"), 0, 0));\n    Reopen(&options);\n    ASSERT_TRUE(Between(Size(\"\", \"xyz\"), 0, 0));\n\n    // Write 8MB (80 values, each 100K)\n    ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n    const int N = 80;\n    static const int S1 = 100000;\n    static const int S2 = 105000;  // Allow some expansion from metadata\n    Random rnd(301);\n    for (int i = 0; i < N; i++) {\n      ASSERT_OK(Put(Key(i), RandomString(&rnd, S1)));\n    }\n\n    // 0 because GetApproximateSizes() does not account for memtable space\n    ASSERT_TRUE(Between(Size(\"\", Key(50)), 0, 0));\n\n    if (options.reuse_logs) {\n      // Recovery will reuse memtable, and GetApproximateSizes() does not\n      // account for memtable usage;\n      Reopen(&options);\n      ASSERT_TRUE(Between(Size(\"\", Key(50)), 0, 0));\n      continue;\n    }\n\n    // Check sizes across recovery by reopening a few times\n    for (int run = 0; run < 3; run++) {\n      Reopen(&options);\n\n      for (int compact_start = 0; compact_start < N; compact_start += 10) {\n        for (int i = 0; i < N; i += 10) {\n          ASSERT_TRUE(Between(Size(\"\", Key(i)), S1 * i, S2 * i));\n          ASSERT_TRUE(Between(Size(\"\", Key(i) + \".suffix\"), S1 * (i + 1),\n                              S2 * (i + 1)));\n          ASSERT_TRUE(Between(Size(Key(i), Key(i + 10)), S1 * 10, S2 * 10));\n        }\n        ASSERT_TRUE(Between(Size(\"\", Key(50)), S1 * 50, S2 * 50));\n        ASSERT_TRUE(Between(Size(\"\", Key(50) + \".suffix\"), S1 * 50, S2 * 50));\n\n        std::string cstart_str = Key(compact_start);\n        std::string cend_str = Key(compact_start + 9);\n        Slice cstart = cstart_str;\n        Slice cend = cend_str;\n        dbfull()->TEST_CompactRange(0, &cstart, &cend);\n      }\n\n      ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n      ASSERT_GT(NumTableFilesAtLevel(1), 0);\n    }\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {\n  do {\n    Options options = CurrentOptions();\n    options.compression = kNoCompression;\n    Reopen();\n\n    Random rnd(301);\n    std::string big1 = RandomString(&rnd, 100000);\n    ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));\n    ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));\n    ASSERT_OK(Put(Key(2), big1));\n    ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));\n    ASSERT_OK(Put(Key(4), big1));\n    ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));\n    ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));\n    ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));\n\n    if (options.reuse_logs) {\n      // Need to force a memtable compaction since recovery does not do so.\n      ASSERT_OK(dbfull()->TEST_CompactMemTable());\n    }\n\n    // Check sizes across recovery by reopening a few times\n    for (int run = 0; run < 3; run++) {\n      Reopen(&options);\n\n      ASSERT_TRUE(Between(Size(\"\", Key(0)), 0, 0));\n      ASSERT_TRUE(Between(Size(\"\", Key(1)), 10000, 11000));\n      ASSERT_TRUE(Between(Size(\"\", Key(2)), 20000, 21000));\n      ASSERT_TRUE(Between(Size(\"\", Key(3)), 120000, 121000));\n      ASSERT_TRUE(Between(Size(\"\", Key(4)), 130000, 131000));\n      ASSERT_TRUE(Between(Size(\"\", Key(5)), 230000, 231000));\n      ASSERT_TRUE(Between(Size(\"\", Key(6)), 240000, 241000));\n      ASSERT_TRUE(Between(Size(\"\", Key(7)), 540000, 541000));\n      ASSERT_TRUE(Between(Size(\"\", Key(8)), 550000, 560000));\n\n      ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));\n\n      dbfull()->TEST_CompactRange(0, nullptr, nullptr);\n    }\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, IteratorPinsRef) {\n  Put(\"foo\", \"hello\");\n\n  // Get iterator that will yield the current contents of the DB.\n  Iterator* iter = db_->NewIterator(ReadOptions());\n\n  // Write to force compactions\n  Put(\"foo\", \"newvalue1\");\n  for (int i = 0; i < 100; i++) {\n    ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v')));  // 100K values\n  }\n  Put(\"foo\", \"newvalue2\");\n\n  iter->SeekToFirst();\n  ASSERT_TRUE(iter->Valid());\n  ASSERT_EQ(\"foo\", iter->key().ToString());\n  ASSERT_EQ(\"hello\", iter->value().ToString());\n  iter->Next();\n  ASSERT_TRUE(!iter->Valid());\n  delete iter;\n}\n\nTEST(DBTest, Snapshot) {\n  do {\n    Put(\"foo\", \"v1\");\n    const Snapshot* s1 = db_->GetSnapshot();\n    Put(\"foo\", \"v2\");\n    const Snapshot* s2 = db_->GetSnapshot();\n    Put(\"foo\", \"v3\");\n    const Snapshot* s3 = db_->GetSnapshot();\n\n    Put(\"foo\", \"v4\");\n    ASSERT_EQ(\"v1\", Get(\"foo\", s1));\n    ASSERT_EQ(\"v2\", Get(\"foo\", s2));\n    ASSERT_EQ(\"v3\", Get(\"foo\", s3));\n    ASSERT_EQ(\"v4\", Get(\"foo\"));\n\n    db_->ReleaseSnapshot(s3);\n    ASSERT_EQ(\"v1\", Get(\"foo\", s1));\n    ASSERT_EQ(\"v2\", Get(\"foo\", s2));\n    ASSERT_EQ(\"v4\", Get(\"foo\"));\n\n    db_->ReleaseSnapshot(s1);\n    ASSERT_EQ(\"v2\", Get(\"foo\", s2));\n    ASSERT_EQ(\"v4\", Get(\"foo\"));\n\n    db_->ReleaseSnapshot(s2);\n    ASSERT_EQ(\"v4\", Get(\"foo\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, HiddenValuesAreRemoved) {\n  do {\n    Random rnd(301);\n    FillLevels(\"a\", \"z\");\n\n    std::string big = RandomString(&rnd, 50000);\n    Put(\"foo\", big);\n    Put(\"pastfoo\", \"v\");\n    const Snapshot* snapshot = db_->GetSnapshot();\n    Put(\"foo\", \"tiny\");\n    Put(\"pastfoo2\", \"v2\");  // Advance sequence number one more\n\n    ASSERT_OK(dbfull()->TEST_CompactMemTable());\n    ASSERT_GT(NumTableFilesAtLevel(0), 0);\n\n    ASSERT_EQ(big, Get(\"foo\", snapshot));\n    ASSERT_TRUE(Between(Size(\"\", \"pastfoo\"), 50000, 60000));\n    db_->ReleaseSnapshot(snapshot);\n    ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ tiny, \" + big + \" ]\");\n    Slice x(\"x\");\n    dbfull()->TEST_CompactRange(0, nullptr, &x);\n    ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ tiny ]\");\n    ASSERT_EQ(NumTableFilesAtLevel(0), 0);\n    ASSERT_GE(NumTableFilesAtLevel(1), 1);\n    dbfull()->TEST_CompactRange(1, nullptr, &x);\n    ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ tiny ]\");\n\n    ASSERT_TRUE(Between(Size(\"\", \"pastfoo\"), 0, 1000));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, DeletionMarkers1) {\n  Put(\"foo\", \"v1\");\n  ASSERT_OK(dbfull()->TEST_CompactMemTable());\n  const int last = config::kMaxMemCompactLevel;\n  ASSERT_EQ(NumTableFilesAtLevel(last), 1);  // foo => v1 is now in last level\n\n  // Place a table at level last-1 to prevent merging with preceding mutation\n  Put(\"a\", \"begin\");\n  Put(\"z\", \"end\");\n  dbfull()->TEST_CompactMemTable();\n  ASSERT_EQ(NumTableFilesAtLevel(last), 1);\n  ASSERT_EQ(NumTableFilesAtLevel(last - 1), 1);\n\n  Delete(\"foo\");\n  Put(\"foo\", \"v2\");\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ v2, DEL, v1 ]\");\n  ASSERT_OK(dbfull()->TEST_CompactMemTable());  // Moves to level last-2\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ v2, DEL, v1 ]\");\n  Slice z(\"z\");\n  dbfull()->TEST_CompactRange(last - 2, nullptr, &z);\n  // DEL eliminated, but v1 remains because we aren't compacting that level\n  // (DEL can be eliminated because v2 hides v1).\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ v2, v1 ]\");\n  dbfull()->TEST_CompactRange(last - 1, nullptr, nullptr);\n  // Merging last-1 w/ last, so we are the base level for \"foo\", so\n  // DEL is removed.  (as is v1).\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ v2 ]\");\n}\n\nTEST(DBTest, DeletionMarkers2) {\n  Put(\"foo\", \"v1\");\n  ASSERT_OK(dbfull()->TEST_CompactMemTable());\n  const int last = config::kMaxMemCompactLevel;\n  ASSERT_EQ(NumTableFilesAtLevel(last), 1);  // foo => v1 is now in last level\n\n  // Place a table at level last-1 to prevent merging with preceding mutation\n  Put(\"a\", \"begin\");\n  Put(\"z\", \"end\");\n  dbfull()->TEST_CompactMemTable();\n  ASSERT_EQ(NumTableFilesAtLevel(last), 1);\n  ASSERT_EQ(NumTableFilesAtLevel(last - 1), 1);\n\n  Delete(\"foo\");\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ DEL, v1 ]\");\n  ASSERT_OK(dbfull()->TEST_CompactMemTable());  // Moves to level last-2\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ DEL, v1 ]\");\n  dbfull()->TEST_CompactRange(last - 2, nullptr, nullptr);\n  // DEL kept: \"last\" file overlaps\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ DEL, v1 ]\");\n  dbfull()->TEST_CompactRange(last - 1, nullptr, nullptr);\n  // Merging last-1 w/ last, so we are the base level for \"foo\", so\n  // DEL is removed.  (as is v1).\n  ASSERT_EQ(AllEntriesFor(\"foo\"), \"[ ]\");\n}\n\nTEST(DBTest, OverlapInLevel0) {\n  do {\n    ASSERT_EQ(config::kMaxMemCompactLevel, 2) << \"Fix test to match config\";\n\n    // Fill levels 1 and 2 to disable the pushing of new memtables to levels >\n    // 0.\n    ASSERT_OK(Put(\"100\", \"v100\"));\n    ASSERT_OK(Put(\"999\", \"v999\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_OK(Delete(\"100\"));\n    ASSERT_OK(Delete(\"999\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"0,1,1\", FilesPerLevel());\n\n    // Make files spanning the following ranges in level-0:\n    //  files[0]  200 .. 900\n    //  files[1]  300 .. 500\n    // Note that files are sorted by smallest key.\n    ASSERT_OK(Put(\"300\", \"v300\"));\n    ASSERT_OK(Put(\"500\", \"v500\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_OK(Put(\"200\", \"v200\"));\n    ASSERT_OK(Put(\"600\", \"v600\"));\n    ASSERT_OK(Put(\"900\", \"v900\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"2,1,1\", FilesPerLevel());\n\n    // Compact away the placeholder files we created initially\n    dbfull()->TEST_CompactRange(1, nullptr, nullptr);\n    dbfull()->TEST_CompactRange(2, nullptr, nullptr);\n    ASSERT_EQ(\"2\", FilesPerLevel());\n\n    // Do a memtable compaction.  Before bug-fix, the compaction would\n    // not detect the overlap with level-0 files and would incorrectly place\n    // the deletion in a deeper level.\n    ASSERT_OK(Delete(\"600\"));\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"3\", FilesPerLevel());\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"600\"));\n  } while (ChangeOptions());\n}\n\nTEST(DBTest, L0_CompactionBug_Issue44_a) {\n  Reopen();\n  ASSERT_OK(Put(\"b\", \"v\"));\n  Reopen();\n  ASSERT_OK(Delete(\"b\"));\n  ASSERT_OK(Delete(\"a\"));\n  Reopen();\n  ASSERT_OK(Delete(\"a\"));\n  Reopen();\n  ASSERT_OK(Put(\"a\", \"v\"));\n  Reopen();\n  Reopen();\n  ASSERT_EQ(\"(a->v)\", Contents());\n  DelayMilliseconds(1000);  // Wait for compaction to finish\n  ASSERT_EQ(\"(a->v)\", Contents());\n}\n\nTEST(DBTest, L0_CompactionBug_Issue44_b) {\n  Reopen();\n  Put(\"\", \"\");\n  Reopen();\n  Delete(\"e\");\n  Put(\"\", \"\");\n  Reopen();\n  Put(\"c\", \"cv\");\n  Reopen();\n  Put(\"\", \"\");\n  Reopen();\n  Put(\"\", \"\");\n  DelayMilliseconds(1000);  // Wait for compaction to finish\n  Reopen();\n  Put(\"d\", \"dv\");\n  Reopen();\n  Put(\"\", \"\");\n  Reopen();\n  Delete(\"d\");\n  Delete(\"b\");\n  Reopen();\n  ASSERT_EQ(\"(->)(c->cv)\", Contents());\n  DelayMilliseconds(1000);  // Wait for compaction to finish\n  ASSERT_EQ(\"(->)(c->cv)\", Contents());\n}\n\nTEST(DBTest, Fflush_Issue474) {\n  static const int kNum = 100000;\n  Random rnd(test::RandomSeed());\n  for (int i = 0; i < kNum; i++) {\n    fflush(nullptr);\n    ASSERT_OK(Put(RandomKey(&rnd), RandomString(&rnd, 100)));\n  }\n}\n\nTEST(DBTest, ComparatorCheck) {\n  class NewComparator : public Comparator {\n   public:\n    const char* Name() const override { return \"leveldb.NewComparator\"; }\n    int Compare(const Slice& a, const Slice& b) const override {\n      return BytewiseComparator()->Compare(a, b);\n    }\n    void FindShortestSeparator(std::string* s, const Slice& l) const override {\n      BytewiseComparator()->FindShortestSeparator(s, l);\n    }\n    void FindShortSuccessor(std::string* key) const override {\n      BytewiseComparator()->FindShortSuccessor(key);\n    }\n  };\n  NewComparator cmp;\n  Options new_options = CurrentOptions();\n  new_options.comparator = &cmp;\n  Status s = TryReopen(&new_options);\n  ASSERT_TRUE(!s.ok());\n  ASSERT_TRUE(s.ToString().find(\"comparator\") != std::string::npos)\n      << s.ToString();\n}\n\nTEST(DBTest, CustomComparator) {\n  class NumberComparator : public Comparator {\n   public:\n    const char* Name() const override { return \"test.NumberComparator\"; }\n    int Compare(const Slice& a, const Slice& b) const override {\n      return ToNumber(a) - ToNumber(b);\n    }\n    void FindShortestSeparator(std::string* s, const Slice& l) const override {\n      ToNumber(*s);  // Check format\n      ToNumber(l);   // Check format\n    }\n    void FindShortSuccessor(std::string* key) const override {\n      ToNumber(*key);  // Check format\n    }\n\n   private:\n    static int ToNumber(const Slice& x) {\n      // Check that there are no extra characters.\n      ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size() - 1] == ']')\n          << EscapeString(x);\n      int val;\n      char ignored;\n      ASSERT_TRUE(sscanf(x.ToString().c_str(), \"[%i]%c\", &val, &ignored) == 1)\n          << EscapeString(x);\n      return val;\n    }\n  };\n  NumberComparator cmp;\n  Options new_options = CurrentOptions();\n  new_options.create_if_missing = true;\n  new_options.comparator = &cmp;\n  new_options.filter_policy = nullptr;   // Cannot use bloom filters\n  new_options.write_buffer_size = 1000;  // Compact more often\n  DestroyAndReopen(&new_options);\n  ASSERT_OK(Put(\"[10]\", \"ten\"));\n  ASSERT_OK(Put(\"[0x14]\", \"twenty\"));\n  for (int i = 0; i < 2; i++) {\n    ASSERT_EQ(\"ten\", Get(\"[10]\"));\n    ASSERT_EQ(\"ten\", Get(\"[0xa]\"));\n    ASSERT_EQ(\"twenty\", Get(\"[20]\"));\n    ASSERT_EQ(\"twenty\", Get(\"[0x14]\"));\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"[15]\"));\n    ASSERT_EQ(\"NOT_FOUND\", Get(\"[0xf]\"));\n    Compact(\"[0]\", \"[9999]\");\n  }\n\n  for (int run = 0; run < 2; run++) {\n    for (int i = 0; i < 1000; i++) {\n      char buf[100];\n      snprintf(buf, sizeof(buf), \"[%d]\", i * 10);\n      ASSERT_OK(Put(buf, buf));\n    }\n    Compact(\"[0]\", \"[1000000]\");\n  }\n}\n\nTEST(DBTest, ManualCompaction) {\n  ASSERT_EQ(config::kMaxMemCompactLevel, 2)\n      << \"Need to update this test to match kMaxMemCompactLevel\";\n\n  MakeTables(3, \"p\", \"q\");\n  ASSERT_EQ(\"1,1,1\", FilesPerLevel());\n\n  // Compaction range falls before files\n  Compact(\"\", \"c\");\n  ASSERT_EQ(\"1,1,1\", FilesPerLevel());\n\n  // Compaction range falls after files\n  Compact(\"r\", \"z\");\n  ASSERT_EQ(\"1,1,1\", FilesPerLevel());\n\n  // Compaction range overlaps files\n  Compact(\"p1\", \"p9\");\n  ASSERT_EQ(\"0,0,1\", FilesPerLevel());\n\n  // Populate a different range\n  MakeTables(3, \"c\", \"e\");\n  ASSERT_EQ(\"1,1,2\", FilesPerLevel());\n\n  // Compact just the new range\n  Compact(\"b\", \"f\");\n  ASSERT_EQ(\"0,0,2\", FilesPerLevel());\n\n  // Compact all\n  MakeTables(1, \"a\", \"z\");\n  ASSERT_EQ(\"0,1,2\", FilesPerLevel());\n  db_->CompactRange(nullptr, nullptr);\n  ASSERT_EQ(\"0,0,1\", FilesPerLevel());\n}\n\nTEST(DBTest, DBOpen_Options) {\n  std::string dbname = test::TmpDir() + \"/db_options_test\";\n  DestroyDB(dbname, Options());\n\n  // Does not exist, and create_if_missing == false: error\n  DB* db = nullptr;\n  Options opts;\n  opts.create_if_missing = false;\n  Status s = DB::Open(opts, dbname, &db);\n  ASSERT_TRUE(strstr(s.ToString().c_str(), \"does not exist\") != nullptr);\n  ASSERT_TRUE(db == nullptr);\n\n  // Does not exist, and create_if_missing == true: OK\n  opts.create_if_missing = true;\n  s = DB::Open(opts, dbname, &db);\n  ASSERT_OK(s);\n  ASSERT_TRUE(db != nullptr);\n\n  delete db;\n  db = nullptr;\n\n  // Does exist, and error_if_exists == true: error\n  opts.create_if_missing = false;\n  opts.error_if_exists = true;\n  s = DB::Open(opts, dbname, &db);\n  ASSERT_TRUE(strstr(s.ToString().c_str(), \"exists\") != nullptr);\n  ASSERT_TRUE(db == nullptr);\n\n  // Does exist, and error_if_exists == false: OK\n  opts.create_if_missing = true;\n  opts.error_if_exists = false;\n  s = DB::Open(opts, dbname, &db);\n  ASSERT_OK(s);\n  ASSERT_TRUE(db != nullptr);\n\n  delete db;\n  db = nullptr;\n}\n\nTEST(DBTest, DestroyEmptyDir) {\n  std::string dbname = test::TmpDir() + \"/db_empty_dir\";\n  TestEnv env(Env::Default());\n  env.DeleteDir(dbname);\n  ASSERT_TRUE(!env.FileExists(dbname));\n\n  Options opts;\n  opts.env = &env;\n\n  ASSERT_OK(env.CreateDir(dbname));\n  ASSERT_TRUE(env.FileExists(dbname));\n  std::vector<std::string> children;\n  ASSERT_OK(env.GetChildren(dbname, &children));\n  // The stock Env's do not filter out '.' and '..' special files.\n  ASSERT_EQ(2, children.size());\n  ASSERT_OK(DestroyDB(dbname, opts));\n  ASSERT_TRUE(!env.FileExists(dbname));\n\n  // Should also be destroyed if Env is filtering out dot files.\n  env.SetIgnoreDotFiles(true);\n  ASSERT_OK(env.CreateDir(dbname));\n  ASSERT_TRUE(env.FileExists(dbname));\n  ASSERT_OK(env.GetChildren(dbname, &children));\n  ASSERT_EQ(0, children.size());\n  ASSERT_OK(DestroyDB(dbname, opts));\n  ASSERT_TRUE(!env.FileExists(dbname));\n}\n\nTEST(DBTest, DestroyOpenDB) {\n  std::string dbname = test::TmpDir() + \"/open_db_dir\";\n  env_->DeleteDir(dbname);\n  ASSERT_TRUE(!env_->FileExists(dbname));\n\n  Options opts;\n  opts.create_if_missing = true;\n  DB* db = nullptr;\n  ASSERT_OK(DB::Open(opts, dbname, &db));\n  ASSERT_TRUE(db != nullptr);\n\n  // Must fail to destroy an open db.\n  ASSERT_TRUE(env_->FileExists(dbname));\n  ASSERT_TRUE(!DestroyDB(dbname, Options()).ok());\n  ASSERT_TRUE(env_->FileExists(dbname));\n\n  delete db;\n  db = nullptr;\n\n  // Should succeed destroying a closed db.\n  ASSERT_OK(DestroyDB(dbname, Options()));\n  ASSERT_TRUE(!env_->FileExists(dbname));\n}\n\nTEST(DBTest, Locking) {\n  DB* db2 = nullptr;\n  Status s = DB::Open(CurrentOptions(), dbname_, &db2);\n  ASSERT_TRUE(!s.ok()) << \"Locking did not prevent re-opening db\";\n}\n\n// Check that number of files does not grow when we are out of space\nTEST(DBTest, NoSpace) {\n  Options options = CurrentOptions();\n  options.env = env_;\n  Reopen(&options);\n\n  ASSERT_OK(Put(\"foo\", \"v1\"));\n  ASSERT_EQ(\"v1\", Get(\"foo\"));\n  Compact(\"a\", \"z\");\n  const int num_files = CountFiles();\n  // Force out-of-space errors.\n  env_->no_space_.store(true, std::memory_order_release);\n  for (int i = 0; i < 10; i++) {\n    for (int level = 0; level < config::kNumLevels - 1; level++) {\n      dbfull()->TEST_CompactRange(level, nullptr, nullptr);\n    }\n  }\n  env_->no_space_.store(false, std::memory_order_release);\n  ASSERT_LT(CountFiles(), num_files + 3);\n}\n\nTEST(DBTest, NonWritableFileSystem) {\n  Options options = CurrentOptions();\n  options.write_buffer_size = 1000;\n  options.env = env_;\n  Reopen(&options);\n  ASSERT_OK(Put(\"foo\", \"v1\"));\n  // Force errors for new files.\n  env_->non_writable_.store(true, std::memory_order_release);\n  std::string big(100000, 'x');\n  int errors = 0;\n  for (int i = 0; i < 20; i++) {\n    fprintf(stderr, \"iter %d; errors %d\\n\", i, errors);\n    if (!Put(\"foo\", big).ok()) {\n      errors++;\n      DelayMilliseconds(100);\n    }\n  }\n  ASSERT_GT(errors, 0);\n  env_->non_writable_.store(false, std::memory_order_release);\n}\n\nTEST(DBTest, WriteSyncError) {\n  // Check that log sync errors cause the DB to disallow future writes.\n\n  // (a) Cause log sync calls to fail\n  Options options = CurrentOptions();\n  options.env = env_;\n  Reopen(&options);\n  env_->data_sync_error_.store(true, std::memory_order_release);\n\n  // (b) Normal write should succeed\n  WriteOptions w;\n  ASSERT_OK(db_->Put(w, \"k1\", \"v1\"));\n  ASSERT_EQ(\"v1\", Get(\"k1\"));\n\n  // (c) Do a sync write; should fail\n  w.sync = true;\n  ASSERT_TRUE(!db_->Put(w, \"k2\", \"v2\").ok());\n  ASSERT_EQ(\"v1\", Get(\"k1\"));\n  ASSERT_EQ(\"NOT_FOUND\", Get(\"k2\"));\n\n  // (d) make sync behave normally\n  env_->data_sync_error_.store(false, std::memory_order_release);\n\n  // (e) Do a non-sync write; should fail\n  w.sync = false;\n  ASSERT_TRUE(!db_->Put(w, \"k3\", \"v3\").ok());\n  ASSERT_EQ(\"v1\", Get(\"k1\"));\n  ASSERT_EQ(\"NOT_FOUND\", Get(\"k2\"));\n  ASSERT_EQ(\"NOT_FOUND\", Get(\"k3\"));\n}\n\nTEST(DBTest, ManifestWriteError) {\n  // Test for the following problem:\n  // (a) Compaction produces file F\n  // (b) Log record containing F is written to MANIFEST file, but Sync() fails\n  // (c) GC deletes F\n  // (d) After reopening DB, reads fail since deleted F is named in log record\n\n  // We iterate twice.  In the second iteration, everything is the\n  // same except the log record never makes it to the MANIFEST file.\n  for (int iter = 0; iter < 2; iter++) {\n    std::atomic<bool>* error_type = (iter == 0) ? &env_->manifest_sync_error_\n                                                : &env_->manifest_write_error_;\n\n    // Insert foo=>bar mapping\n    Options options = CurrentOptions();\n    options.env = env_;\n    options.create_if_missing = true;\n    options.error_if_exists = false;\n    DestroyAndReopen(&options);\n    ASSERT_OK(Put(\"foo\", \"bar\"));\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n    // Memtable compaction (will succeed)\n    dbfull()->TEST_CompactMemTable();\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n    const int last = config::kMaxMemCompactLevel;\n    ASSERT_EQ(NumTableFilesAtLevel(last), 1);  // foo=>bar is now in last level\n\n    // Merging compaction (will fail)\n    error_type->store(true, std::memory_order_release);\n    dbfull()->TEST_CompactRange(last, nullptr, nullptr);  // Should fail\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n    // Recovery: should not lose data\n    error_type->store(false, std::memory_order_release);\n    Reopen(&options);\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n  }\n}\n\nTEST(DBTest, MissingSSTFile) {\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n  // Dump the memtable to disk.\n  dbfull()->TEST_CompactMemTable();\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n  Close();\n  ASSERT_TRUE(DeleteAnSSTFile());\n  Options options = CurrentOptions();\n  options.paranoid_checks = true;\n  Status s = TryReopen(&options);\n  ASSERT_TRUE(!s.ok());\n  ASSERT_TRUE(s.ToString().find(\"issing\") != std::string::npos) << s.ToString();\n}\n\nTEST(DBTest, StillReadSST) {\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n  // Dump the memtable to disk.\n  dbfull()->TEST_CompactMemTable();\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n  Close();\n  ASSERT_GT(RenameLDBToSST(), 0);\n  Options options = CurrentOptions();\n  options.paranoid_checks = true;\n  Status s = TryReopen(&options);\n  ASSERT_TRUE(s.ok());\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n}\n\nTEST(DBTest, FilesDeletedAfterCompaction) {\n  ASSERT_OK(Put(\"foo\", \"v2\"));\n  Compact(\"a\", \"z\");\n  const int num_files = CountFiles();\n  for (int i = 0; i < 10; i++) {\n    ASSERT_OK(Put(\"foo\", \"v2\"));\n    Compact(\"a\", \"z\");\n  }\n  ASSERT_EQ(CountFiles(), num_files);\n}\n\nTEST(DBTest, BloomFilter) {\n  env_->count_random_reads_ = true;\n  Options options = CurrentOptions();\n  options.env = env_;\n  options.block_cache = NewLRUCache(0);  // Prevent cache hits\n  options.filter_policy = NewBloomFilterPolicy(10);\n  Reopen(&options);\n\n  // Populate multiple layers\n  const int N = 10000;\n  for (int i = 0; i < N; i++) {\n    ASSERT_OK(Put(Key(i), Key(i)));\n  }\n  Compact(\"a\", \"z\");\n  for (int i = 0; i < N; i += 100) {\n    ASSERT_OK(Put(Key(i), Key(i)));\n  }\n  dbfull()->TEST_CompactMemTable();\n\n  // Prevent auto compactions triggered by seeks\n  env_->delay_data_sync_.store(true, std::memory_order_release);\n\n  // Lookup present keys.  Should rarely read from small sstable.\n  env_->random_read_counter_.Reset();\n  for (int i = 0; i < N; i++) {\n    ASSERT_EQ(Key(i), Get(Key(i)));\n  }\n  int reads = env_->random_read_counter_.Read();\n  fprintf(stderr, \"%d present => %d reads\\n\", N, reads);\n  ASSERT_GE(reads, N);\n  ASSERT_LE(reads, N + 2 * N / 100);\n\n  // Lookup present keys.  Should rarely read from either sstable.\n  env_->random_read_counter_.Reset();\n  for (int i = 0; i < N; i++) {\n    ASSERT_EQ(\"NOT_FOUND\", Get(Key(i) + \".missing\"));\n  }\n  reads = env_->random_read_counter_.Read();\n  fprintf(stderr, \"%d missing => %d reads\\n\", N, reads);\n  ASSERT_LE(reads, 3 * N / 100);\n\n  env_->delay_data_sync_.store(false, std::memory_order_release);\n  Close();\n  delete options.block_cache;\n  delete options.filter_policy;\n}\n\n// Multi-threaded test:\nnamespace {\n\nstatic const int kNumThreads = 4;\nstatic const int kTestSeconds = 10;\nstatic const int kNumKeys = 1000;\n\nstruct MTState {\n  DBTest* test;\n  std::atomic<bool> stop;\n  std::atomic<int> counter[kNumThreads];\n  std::atomic<bool> thread_done[kNumThreads];\n};\n\nstruct MTThread {\n  MTState* state;\n  int id;\n};\n\nstatic void MTThreadBody(void* arg) {\n  MTThread* t = reinterpret_cast<MTThread*>(arg);\n  int id = t->id;\n  DB* db = t->state->test->db_;\n  int counter = 0;\n  fprintf(stderr, \"... starting thread %d\\n\", id);\n  Random rnd(1000 + id);\n  std::string value;\n  char valbuf[1500];\n  while (!t->state->stop.load(std::memory_order_acquire)) {\n    t->state->counter[id].store(counter, std::memory_order_release);\n\n    int key = rnd.Uniform(kNumKeys);\n    char keybuf[20];\n    snprintf(keybuf, sizeof(keybuf), \"%016d\", key);\n\n    if (rnd.OneIn(2)) {\n      // Write values of the form <key, my id, counter>.\n      // We add some padding for force compactions.\n      snprintf(valbuf, sizeof(valbuf), \"%d.%d.%-1000d\", key, id,\n               static_cast<int>(counter));\n      ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));\n    } else {\n      // Read a value and verify that it matches the pattern written above.\n      Status s = db->Get(ReadOptions(), Slice(keybuf), &value);\n      if (s.IsNotFound()) {\n        // Key has not yet been written\n      } else {\n        // Check that the writer thread counter is >= the counter in the value\n        ASSERT_OK(s);\n        int k, w, c;\n        ASSERT_EQ(3, sscanf(value.c_str(), \"%d.%d.%d\", &k, &w, &c)) << value;\n        ASSERT_EQ(k, key);\n        ASSERT_GE(w, 0);\n        ASSERT_LT(w, kNumThreads);\n        ASSERT_LE(c, t->state->counter[w].load(std::memory_order_acquire));\n      }\n    }\n    counter++;\n  }\n  t->state->thread_done[id].store(true, std::memory_order_release);\n  fprintf(stderr, \"... stopping thread %d after %d ops\\n\", id, counter);\n}\n\n}  // namespace\n\nTEST(DBTest, MultiThreaded) {\n  do {\n    // Initialize state\n    MTState mt;\n    mt.test = this;\n    mt.stop.store(false, std::memory_order_release);\n    for (int id = 0; id < kNumThreads; id++) {\n      mt.counter[id].store(false, std::memory_order_release);\n      mt.thread_done[id].store(false, std::memory_order_release);\n    }\n\n    // Start threads\n    MTThread thread[kNumThreads];\n    for (int id = 0; id < kNumThreads; id++) {\n      thread[id].state = &mt;\n      thread[id].id = id;\n      env_->StartThread(MTThreadBody, &thread[id]);\n    }\n\n    // Let them run for a while\n    DelayMilliseconds(kTestSeconds * 1000);\n\n    // Stop the threads and wait for them to finish\n    mt.stop.store(true, std::memory_order_release);\n    for (int id = 0; id < kNumThreads; id++) {\n      while (!mt.thread_done[id].load(std::memory_order_acquire)) {\n        DelayMilliseconds(100);\n      }\n    }\n  } while (ChangeOptions());\n}\n\nnamespace {\ntypedef std::map<std::string, std::string> KVMap;\n}\n\nclass ModelDB : public DB {\n public:\n  class ModelSnapshot : public Snapshot {\n   public:\n    KVMap map_;\n  };\n\n  explicit ModelDB(const Options& options) : options_(options) {}\n  ~ModelDB() override = default;\n  Status Put(const WriteOptions& o, const Slice& k, const Slice& v) override {\n    return DB::Put(o, k, v);\n  }\n  Status Delete(const WriteOptions& o, const Slice& key) override {\n    return DB::Delete(o, key);\n  }\n  Status Get(const ReadOptions& options, const Slice& key,\n             std::string* value) override {\n    assert(false);  // Not implemented\n    return Status::NotFound(key);\n  }\n  Iterator* NewIterator(const ReadOptions& options) override {\n    if (options.snapshot == nullptr) {\n      KVMap* saved = new KVMap;\n      *saved = map_;\n      return new ModelIter(saved, true);\n    } else {\n      const KVMap* snapshot_state =\n          &(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);\n      return new ModelIter(snapshot_state, false);\n    }\n  }\n  const Snapshot* GetSnapshot() override {\n    ModelSnapshot* snapshot = new ModelSnapshot;\n    snapshot->map_ = map_;\n    return snapshot;\n  }\n\n  void ReleaseSnapshot(const Snapshot* snapshot) override {\n    delete reinterpret_cast<const ModelSnapshot*>(snapshot);\n  }\n  Status Write(const WriteOptions& options, WriteBatch* batch) override {\n    class Handler : public WriteBatch::Handler {\n     public:\n      KVMap* map_;\n      void Put(const Slice& key, const Slice& value) override {\n        (*map_)[key.ToString()] = value.ToString();\n      }\n      void Delete(const Slice& key) override { map_->erase(key.ToString()); }\n    };\n    Handler handler;\n    handler.map_ = &map_;\n    return batch->Iterate(&handler);\n  }\n\n  bool GetProperty(const Slice& property, std::string* value) override {\n    return false;\n  }\n  void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) override {\n    for (int i = 0; i < n; i++) {\n      sizes[i] = 0;\n    }\n  }\n  void CompactRange(const Slice* start, const Slice* end) override {}\n\n private:\n  class ModelIter : public Iterator {\n   public:\n    ModelIter(const KVMap* map, bool owned)\n        : map_(map), owned_(owned), iter_(map_->end()) {}\n    ~ModelIter() override {\n      if (owned_) delete map_;\n    }\n    bool Valid() const override { return iter_ != map_->end(); }\n    void SeekToFirst() override { iter_ = map_->begin(); }\n    void SeekToLast() override {\n      if (map_->empty()) {\n        iter_ = map_->end();\n      } else {\n        iter_ = map_->find(map_->rbegin()->first);\n      }\n    }\n    void Seek(const Slice& k) override {\n      iter_ = map_->lower_bound(k.ToString());\n    }\n    void Next() override { ++iter_; }\n    void Prev() override { --iter_; }\n    Slice key() const override { return iter_->first; }\n    Slice value() const override { return iter_->second; }\n    Status status() const override { return Status::OK(); }\n\n   private:\n    const KVMap* const map_;\n    const bool owned_;  // Do we own map_\n    KVMap::const_iterator iter_;\n  };\n  const Options options_;\n  KVMap map_;\n};\n\nstatic bool CompareIterators(int step, DB* model, DB* db,\n                             const Snapshot* model_snap,\n                             const Snapshot* db_snap) {\n  ReadOptions options;\n  options.snapshot = model_snap;\n  Iterator* miter = model->NewIterator(options);\n  options.snapshot = db_snap;\n  Iterator* dbiter = db->NewIterator(options);\n  bool ok = true;\n  int count = 0;\n  for (miter->SeekToFirst(), dbiter->SeekToFirst();\n       ok && miter->Valid() && dbiter->Valid(); miter->Next(), dbiter->Next()) {\n    count++;\n    if (miter->key().compare(dbiter->key()) != 0) {\n      fprintf(stderr, \"step %d: Key mismatch: '%s' vs. '%s'\\n\", step,\n              EscapeString(miter->key()).c_str(),\n              EscapeString(dbiter->key()).c_str());\n      ok = false;\n      break;\n    }\n\n    if (miter->value().compare(dbiter->value()) != 0) {\n      fprintf(stderr, \"step %d: Value mismatch for key '%s': '%s' vs. '%s'\\n\",\n              step, EscapeString(miter->key()).c_str(),\n              EscapeString(miter->value()).c_str(),\n              EscapeString(miter->value()).c_str());\n      ok = false;\n    }\n  }\n\n  if (ok) {\n    if (miter->Valid() != dbiter->Valid()) {\n      fprintf(stderr, \"step %d: Mismatch at end of iterators: %d vs. %d\\n\",\n              step, miter->Valid(), dbiter->Valid());\n      ok = false;\n    }\n  }\n  fprintf(stderr, \"%d entries compared: ok=%d\\n\", count, ok);\n  delete miter;\n  delete dbiter;\n  return ok;\n}\n\nTEST(DBTest, Randomized) {\n  Random rnd(test::RandomSeed());\n  do {\n    ModelDB model(CurrentOptions());\n    const int N = 10000;\n    const Snapshot* model_snap = nullptr;\n    const Snapshot* db_snap = nullptr;\n    std::string k, v;\n    for (int step = 0; step < N; step++) {\n      if (step % 100 == 0) {\n        fprintf(stderr, \"Step %d of %d\\n\", step, N);\n      }\n      // TODO(sanjay): Test Get() works\n      int p = rnd.Uniform(100);\n      if (p < 45) {  // Put\n        k = RandomKey(&rnd);\n        v = RandomString(\n            &rnd, rnd.OneIn(20) ? 100 + rnd.Uniform(100) : rnd.Uniform(8));\n        ASSERT_OK(model.Put(WriteOptions(), k, v));\n        ASSERT_OK(db_->Put(WriteOptions(), k, v));\n\n      } else if (p < 90) {  // Delete\n        k = RandomKey(&rnd);\n        ASSERT_OK(model.Delete(WriteOptions(), k));\n        ASSERT_OK(db_->Delete(WriteOptions(), k));\n\n      } else {  // Multi-element batch\n        WriteBatch b;\n        const int num = rnd.Uniform(8);\n        for (int i = 0; i < num; i++) {\n          if (i == 0 || !rnd.OneIn(10)) {\n            k = RandomKey(&rnd);\n          } else {\n            // Periodically re-use the same key from the previous iter, so\n            // we have multiple entries in the write batch for the same key\n          }\n          if (rnd.OneIn(2)) {\n            v = RandomString(&rnd, rnd.Uniform(10));\n            b.Put(k, v);\n          } else {\n            b.Delete(k);\n          }\n        }\n        ASSERT_OK(model.Write(WriteOptions(), &b));\n        ASSERT_OK(db_->Write(WriteOptions(), &b));\n      }\n\n      if ((step % 100) == 0) {\n        ASSERT_TRUE(CompareIterators(step, &model, db_, nullptr, nullptr));\n        ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));\n        // Save a snapshot from each DB this time that we'll use next\n        // time we compare things, to make sure the current state is\n        // preserved with the snapshot\n        if (model_snap != nullptr) model.ReleaseSnapshot(model_snap);\n        if (db_snap != nullptr) db_->ReleaseSnapshot(db_snap);\n\n        Reopen();\n        ASSERT_TRUE(CompareIterators(step, &model, db_, nullptr, nullptr));\n\n        model_snap = model.GetSnapshot();\n        db_snap = db_->GetSnapshot();\n      }\n    }\n    if (model_snap != nullptr) model.ReleaseSnapshot(model_snap);\n    if (db_snap != nullptr) db_->ReleaseSnapshot(db_snap);\n  } while (ChangeOptions());\n}\n\nstd::string MakeKey(unsigned int num) {\n  char buf[30];\n  snprintf(buf, sizeof(buf), \"%016u\", num);\n  return std::string(buf);\n}\n\nvoid BM_LogAndApply(int iters, int num_base_files) {\n  std::string dbname = test::TmpDir() + \"/leveldb_test_benchmark\";\n  DestroyDB(dbname, Options());\n\n  DB* db = nullptr;\n  Options opts;\n  opts.create_if_missing = true;\n  Status s = DB::Open(opts, dbname, &db);\n  ASSERT_OK(s);\n  ASSERT_TRUE(db != nullptr);\n\n  delete db;\n  db = nullptr;\n\n  Env* env = Env::Default();\n\n  port::Mutex mu;\n  MutexLock l(&mu);\n\n  InternalKeyComparator cmp(BytewiseComparator());\n  Options options;\n  VersionSet vset(dbname, &options, nullptr, &cmp);\n  bool save_manifest;\n  ASSERT_OK(vset.Recover(&save_manifest));\n  VersionEdit vbase;\n  uint64_t fnum = 1;\n  for (int i = 0; i < num_base_files; i++) {\n    InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);\n    InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);\n    vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);\n  }\n  ASSERT_OK(vset.LogAndApply(&vbase, &mu));\n\n  uint64_t start_micros = env->NowMicros();\n\n  for (int i = 0; i < iters; i++) {\n    VersionEdit vedit;\n    vedit.DeleteFile(2, fnum);\n    InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);\n    InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);\n    vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);\n    vset.LogAndApply(&vedit, &mu);\n  }\n  uint64_t stop_micros = env->NowMicros();\n  unsigned int us = stop_micros - start_micros;\n  char buf[16];\n  snprintf(buf, sizeof(buf), \"%d\", num_base_files);\n  fprintf(stderr,\n          \"BM_LogAndApply/%-6s   %8d iters : %9u us (%7.0f us / iter)\\n\", buf,\n          iters, us, ((float)us) / iters);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n  if (argc > 1 && std::string(argv[1]) == \"--benchmark\") {\n    leveldb::BM_LogAndApply(1000, 1);\n    leveldb::BM_LogAndApply(1000, 100);\n    leveldb::BM_LogAndApply(1000, 10000);\n    leveldb::BM_LogAndApply(100, 100000);\n    return 0;\n  }\n\n  return leveldb::test::RunAllTests();\n}\n"
  },
  {
    "path": "src/leveldb/db/dbformat.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/dbformat.h\"\n\n#include <stdio.h>\n\n#include <sstream>\n\n#include \"port/port.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nstatic uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {\n  assert(seq <= kMaxSequenceNumber);\n  assert(t <= kValueTypeForSeek);\n  return (seq << 8) | t;\n}\n\nvoid AppendInternalKey(std::string* result, const ParsedInternalKey& key) {\n  result->append(key.user_key.data(), key.user_key.size());\n  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));\n}\n\nstd::string ParsedInternalKey::DebugString() const {\n  std::ostringstream ss;\n  ss << '\\'' << EscapeString(user_key.ToString()) << \"' @ \" << sequence << \" : \"\n     << static_cast<int>(type);\n  return ss.str();\n}\n\nstd::string InternalKey::DebugString() const {\n  ParsedInternalKey parsed;\n  if (ParseInternalKey(rep_, &parsed)) {\n    return parsed.DebugString();\n  }\n  std::ostringstream ss;\n  ss << \"(bad)\" << EscapeString(rep_);\n  return ss.str();\n}\n\nconst char* InternalKeyComparator::Name() const {\n  return \"leveldb.InternalKeyComparator\";\n}\n\nint InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {\n  // Order by:\n  //    increasing user key (according to user-supplied comparator)\n  //    decreasing sequence number\n  //    decreasing type (though sequence# should be enough to disambiguate)\n  int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));\n  if (r == 0) {\n    const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);\n    const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);\n    if (anum > bnum) {\n      r = -1;\n    } else if (anum < bnum) {\n      r = +1;\n    }\n  }\n  return r;\n}\n\nvoid InternalKeyComparator::FindShortestSeparator(std::string* start,\n                                                  const Slice& limit) const {\n  // Attempt to shorten the user portion of the key\n  Slice user_start = ExtractUserKey(*start);\n  Slice user_limit = ExtractUserKey(limit);\n  std::string tmp(user_start.data(), user_start.size());\n  user_comparator_->FindShortestSeparator(&tmp, user_limit);\n  if (tmp.size() < user_start.size() &&\n      user_comparator_->Compare(user_start, tmp) < 0) {\n    // User key has become shorter physically, but larger logically.\n    // Tack on the earliest possible number to the shortened user key.\n    PutFixed64(&tmp,\n               PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));\n    assert(this->Compare(*start, tmp) < 0);\n    assert(this->Compare(tmp, limit) < 0);\n    start->swap(tmp);\n  }\n}\n\nvoid InternalKeyComparator::FindShortSuccessor(std::string* key) const {\n  Slice user_key = ExtractUserKey(*key);\n  std::string tmp(user_key.data(), user_key.size());\n  user_comparator_->FindShortSuccessor(&tmp);\n  if (tmp.size() < user_key.size() &&\n      user_comparator_->Compare(user_key, tmp) < 0) {\n    // User key has become shorter physically, but larger logically.\n    // Tack on the earliest possible number to the shortened user key.\n    PutFixed64(&tmp,\n               PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));\n    assert(this->Compare(*key, tmp) < 0);\n    key->swap(tmp);\n  }\n}\n\nconst char* InternalFilterPolicy::Name() const { return user_policy_->Name(); }\n\nvoid InternalFilterPolicy::CreateFilter(const Slice* keys, int n,\n                                        std::string* dst) const {\n  // We rely on the fact that the code in table.cc does not mind us\n  // adjusting keys[].\n  Slice* mkey = const_cast<Slice*>(keys);\n  for (int i = 0; i < n; i++) {\n    mkey[i] = ExtractUserKey(keys[i]);\n    // TODO(sanjay): Suppress dups?\n  }\n  user_policy_->CreateFilter(keys, n, dst);\n}\n\nbool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const {\n  return user_policy_->KeyMayMatch(ExtractUserKey(key), f);\n}\n\nLookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {\n  size_t usize = user_key.size();\n  size_t needed = usize + 13;  // A conservative estimate\n  char* dst;\n  if (needed <= sizeof(space_)) {\n    dst = space_;\n  } else {\n    dst = new char[needed];\n  }\n  start_ = dst;\n  dst = EncodeVarint32(dst, usize + 8);\n  kstart_ = dst;\n  memcpy(dst, user_key.data(), usize);\n  dst += usize;\n  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));\n  dst += 8;\n  end_ = dst;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/dbformat.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_\n#define STORAGE_LEVELDB_DB_DBFORMAT_H_\n\n#include <cstddef>\n#include <cstdint>\n#include <string>\n\n#include \"leveldb/comparator.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/slice.h\"\n#include \"leveldb/table_builder.h\"\n#include \"util/coding.h\"\n#include \"util/logging.h\"\n\nnamespace leveldb {\n\n// Grouping of constants.  We may want to make some of these\n// parameters set via options.\nnamespace config {\nstatic const int kNumLevels = 7;\n\n// Level-0 compaction is started when we hit this many files.\nstatic const int kL0_CompactionTrigger = 4;\n\n// Soft limit on number of level-0 files.  We slow down writes at this point.\nstatic const int kL0_SlowdownWritesTrigger = 8;\n\n// Maximum number of level-0 files.  We stop writes at this point.\nstatic const int kL0_StopWritesTrigger = 12;\n\n// Maximum level to which a new compacted memtable is pushed if it\n// does not create overlap.  We try to push to level 2 to avoid the\n// relatively expensive level 0=>1 compactions and to avoid some\n// expensive manifest file operations.  We do not push all the way to\n// the largest level since that can generate a lot of wasted disk\n// space if the same key space is being repeatedly overwritten.\nstatic const int kMaxMemCompactLevel = 2;\n\n// Approximate gap in bytes between samples of data read during iteration.\nstatic const int kReadBytesPeriod = 1048576;\n\n}  // namespace config\n\nclass InternalKey;\n\n// Value types encoded as the last component of internal keys.\n// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk\n// data structures.\nenum ValueType { kTypeDeletion = 0x0, kTypeValue = 0x1 };\n// kValueTypeForSeek defines the ValueType that should be passed when\n// constructing a ParsedInternalKey object for seeking to a particular\n// sequence number (since we sort sequence numbers in decreasing order\n// and the value type is embedded as the low 8 bits in the sequence\n// number in internal keys, we need to use the highest-numbered\n// ValueType, not the lowest).\nstatic const ValueType kValueTypeForSeek = kTypeValue;\n\ntypedef uint64_t SequenceNumber;\n\n// We leave eight bits empty at the bottom so a type and sequence#\n// can be packed together into 64-bits.\nstatic const SequenceNumber kMaxSequenceNumber = ((0x1ull << 56) - 1);\n\nstruct ParsedInternalKey {\n  Slice user_key;\n  SequenceNumber sequence;\n  ValueType type;\n\n  ParsedInternalKey() {}  // Intentionally left uninitialized (for speed)\n  ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)\n      : user_key(u), sequence(seq), type(t) {}\n  std::string DebugString() const;\n};\n\n// Return the length of the encoding of \"key\".\ninline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) {\n  return key.user_key.size() + 8;\n}\n\n// Append the serialization of \"key\" to *result.\nvoid AppendInternalKey(std::string* result, const ParsedInternalKey& key);\n\n// Attempt to parse an internal key from \"internal_key\".  On success,\n// stores the parsed data in \"*result\", and returns true.\n//\n// On error, returns false, leaves \"*result\" in an undefined state.\nbool ParseInternalKey(const Slice& internal_key, ParsedInternalKey* result);\n\n// Returns the user key portion of an internal key.\ninline Slice ExtractUserKey(const Slice& internal_key) {\n  assert(internal_key.size() >= 8);\n  return Slice(internal_key.data(), internal_key.size() - 8);\n}\n\n// A comparator for internal keys that uses a specified comparator for\n// the user key portion and breaks ties by decreasing sequence number.\nclass InternalKeyComparator : public Comparator {\n private:\n  const Comparator* user_comparator_;\n\n public:\n  explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) {}\n  const char* Name() const override;\n  int Compare(const Slice& a, const Slice& b) const override;\n  void FindShortestSeparator(std::string* start,\n                             const Slice& limit) const override;\n  void FindShortSuccessor(std::string* key) const override;\n\n  const Comparator* user_comparator() const { return user_comparator_; }\n\n  int Compare(const InternalKey& a, const InternalKey& b) const;\n};\n\n// Filter policy wrapper that converts from internal keys to user keys\nclass InternalFilterPolicy : public FilterPolicy {\n private:\n  const FilterPolicy* const user_policy_;\n\n public:\n  explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) {}\n  const char* Name() const override;\n  void CreateFilter(const Slice* keys, int n, std::string* dst) const override;\n  bool KeyMayMatch(const Slice& key, const Slice& filter) const override;\n};\n\n// Modules in this directory should keep internal keys wrapped inside\n// the following class instead of plain strings so that we do not\n// incorrectly use string comparisons instead of an InternalKeyComparator.\nclass InternalKey {\n private:\n  std::string rep_;\n\n public:\n  InternalKey() {}  // Leave rep_ as empty to indicate it is invalid\n  InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {\n    AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t));\n  }\n\n  bool DecodeFrom(const Slice& s) {\n    rep_.assign(s.data(), s.size());\n    return !rep_.empty();\n  }\n\n  Slice Encode() const {\n    assert(!rep_.empty());\n    return rep_;\n  }\n\n  Slice user_key() const { return ExtractUserKey(rep_); }\n\n  void SetFrom(const ParsedInternalKey& p) {\n    rep_.clear();\n    AppendInternalKey(&rep_, p);\n  }\n\n  void Clear() { rep_.clear(); }\n\n  std::string DebugString() const;\n};\n\ninline int InternalKeyComparator::Compare(const InternalKey& a,\n                                          const InternalKey& b) const {\n  return Compare(a.Encode(), b.Encode());\n}\n\ninline bool ParseInternalKey(const Slice& internal_key,\n                             ParsedInternalKey* result) {\n  const size_t n = internal_key.size();\n  if (n < 8) return false;\n  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);\n  uint8_t c = num & 0xff;\n  result->sequence = num >> 8;\n  result->type = static_cast<ValueType>(c);\n  result->user_key = Slice(internal_key.data(), n - 8);\n  return (c <= static_cast<uint8_t>(kTypeValue));\n}\n\n// A helper class useful for DBImpl::Get()\nclass LookupKey {\n public:\n  // Initialize *this for looking up user_key at a snapshot with\n  // the specified sequence number.\n  LookupKey(const Slice& user_key, SequenceNumber sequence);\n\n  LookupKey(const LookupKey&) = delete;\n  LookupKey& operator=(const LookupKey&) = delete;\n\n  ~LookupKey();\n\n  // Return a key suitable for lookup in a MemTable.\n  Slice memtable_key() const { return Slice(start_, end_ - start_); }\n\n  // Return an internal key (suitable for passing to an internal iterator)\n  Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }\n\n  // Return the user key\n  Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }\n\n private:\n  // We construct a char array of the form:\n  //    klength  varint32               <-- start_\n  //    userkey  char[klength]          <-- kstart_\n  //    tag      uint64\n  //                                    <-- end_\n  // The array is a suitable MemTable key.\n  // The suffix starting with \"userkey\" can be used as an InternalKey.\n  const char* start_;\n  const char* kstart_;\n  const char* end_;\n  char space_[200];  // Avoid allocation for short keys\n};\n\ninline LookupKey::~LookupKey() {\n  if (start_ != space_) delete[] start_;\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_DBFORMAT_H_\n"
  },
  {
    "path": "src/leveldb/db/dbformat_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/dbformat.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nstatic std::string IKey(const std::string& user_key, uint64_t seq,\n                        ValueType vt) {\n  std::string encoded;\n  AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt));\n  return encoded;\n}\n\nstatic std::string Shorten(const std::string& s, const std::string& l) {\n  std::string result = s;\n  InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l);\n  return result;\n}\n\nstatic std::string ShortSuccessor(const std::string& s) {\n  std::string result = s;\n  InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result);\n  return result;\n}\n\nstatic void TestKey(const std::string& key, uint64_t seq, ValueType vt) {\n  std::string encoded = IKey(key, seq, vt);\n\n  Slice in(encoded);\n  ParsedInternalKey decoded(\"\", 0, kTypeValue);\n\n  ASSERT_TRUE(ParseInternalKey(in, &decoded));\n  ASSERT_EQ(key, decoded.user_key.ToString());\n  ASSERT_EQ(seq, decoded.sequence);\n  ASSERT_EQ(vt, decoded.type);\n\n  ASSERT_TRUE(!ParseInternalKey(Slice(\"bar\"), &decoded));\n}\n\nclass FormatTest {};\n\nTEST(FormatTest, InternalKey_EncodeDecode) {\n  const char* keys[] = {\"\", \"k\", \"hello\", \"longggggggggggggggggggggg\"};\n  const uint64_t seq[] = {1,\n                          2,\n                          3,\n                          (1ull << 8) - 1,\n                          1ull << 8,\n                          (1ull << 8) + 1,\n                          (1ull << 16) - 1,\n                          1ull << 16,\n                          (1ull << 16) + 1,\n                          (1ull << 32) - 1,\n                          1ull << 32,\n                          (1ull << 32) + 1};\n  for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) {\n    for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) {\n      TestKey(keys[k], seq[s], kTypeValue);\n      TestKey(\"hello\", 1, kTypeDeletion);\n    }\n  }\n}\n\nTEST(FormatTest, InternalKey_DecodeFromEmpty) {\n  InternalKey internal_key;\n\n  ASSERT_TRUE(!internal_key.DecodeFrom(\"\"));\n}\n\nTEST(FormatTest, InternalKeyShortSeparator) {\n  // When user keys are same\n  ASSERT_EQ(IKey(\"foo\", 100, kTypeValue),\n            Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"foo\", 99, kTypeValue)));\n  ASSERT_EQ(\n      IKey(\"foo\", 100, kTypeValue),\n      Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"foo\", 101, kTypeValue)));\n  ASSERT_EQ(\n      IKey(\"foo\", 100, kTypeValue),\n      Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"foo\", 100, kTypeValue)));\n  ASSERT_EQ(\n      IKey(\"foo\", 100, kTypeValue),\n      Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"foo\", 100, kTypeDeletion)));\n\n  // When user keys are misordered\n  ASSERT_EQ(IKey(\"foo\", 100, kTypeValue),\n            Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"bar\", 99, kTypeValue)));\n\n  // When user keys are different, but correctly ordered\n  ASSERT_EQ(\n      IKey(\"g\", kMaxSequenceNumber, kValueTypeForSeek),\n      Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"hello\", 200, kTypeValue)));\n\n  // When start user key is prefix of limit user key\n  ASSERT_EQ(\n      IKey(\"foo\", 100, kTypeValue),\n      Shorten(IKey(\"foo\", 100, kTypeValue), IKey(\"foobar\", 200, kTypeValue)));\n\n  // When limit user key is prefix of start user key\n  ASSERT_EQ(\n      IKey(\"foobar\", 100, kTypeValue),\n      Shorten(IKey(\"foobar\", 100, kTypeValue), IKey(\"foo\", 200, kTypeValue)));\n}\n\nTEST(FormatTest, InternalKeyShortestSuccessor) {\n  ASSERT_EQ(IKey(\"g\", kMaxSequenceNumber, kValueTypeForSeek),\n            ShortSuccessor(IKey(\"foo\", 100, kTypeValue)));\n  ASSERT_EQ(IKey(\"\\xff\\xff\", 100, kTypeValue),\n            ShortSuccessor(IKey(\"\\xff\\xff\", 100, kTypeValue)));\n}\n\nTEST(FormatTest, ParsedInternalKeyDebugString) {\n  ParsedInternalKey key(\"The \\\"key\\\" in 'single quotes'\", 42, kTypeValue);\n\n  ASSERT_EQ(\"'The \\\"key\\\" in 'single quotes'' @ 42 : 1\", key.DebugString());\n}\n\nTEST(FormatTest, InternalKeyDebugString) {\n  InternalKey key(\"The \\\"key\\\" in 'single quotes'\", 42, kTypeValue);\n  ASSERT_EQ(\"'The \\\"key\\\" in 'single quotes'' @ 42 : 1\", key.DebugString());\n\n  InternalKey invalid_key;\n  ASSERT_EQ(\"(bad)\", invalid_key.DebugString());\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/dumpfile.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/dumpfile.h\"\n\n#include <stdio.h>\n\n#include \"db/dbformat.h\"\n#include \"db/filename.h\"\n#include \"db/log_reader.h\"\n#include \"db/version_edit.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/iterator.h\"\n#include \"leveldb/options.h\"\n#include \"leveldb/status.h\"\n#include \"leveldb/table.h\"\n#include \"leveldb/write_batch.h\"\n#include \"util/logging.h\"\n\nnamespace leveldb {\n\nnamespace {\n\nbool GuessType(const std::string& fname, FileType* type) {\n  size_t pos = fname.rfind('/');\n  std::string basename;\n  if (pos == std::string::npos) {\n    basename = fname;\n  } else {\n    basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);\n  }\n  uint64_t ignored;\n  return ParseFileName(basename, &ignored, type);\n}\n\n// Notified when log reader encounters corruption.\nclass CorruptionReporter : public log::Reader::Reporter {\n public:\n  void Corruption(size_t bytes, const Status& status) override {\n    std::string r = \"corruption: \";\n    AppendNumberTo(&r, bytes);\n    r += \" bytes; \";\n    r += status.ToString();\n    r.push_back('\\n');\n    dst_->Append(r);\n  }\n\n  WritableFile* dst_;\n};\n\n// Print contents of a log file. (*func)() is called on every record.\nStatus PrintLogContents(Env* env, const std::string& fname,\n                        void (*func)(uint64_t, Slice, WritableFile*),\n                        WritableFile* dst) {\n  SequentialFile* file;\n  Status s = env->NewSequentialFile(fname, &file);\n  if (!s.ok()) {\n    return s;\n  }\n  CorruptionReporter reporter;\n  reporter.dst_ = dst;\n  log::Reader reader(file, &reporter, true, 0);\n  Slice record;\n  std::string scratch;\n  while (reader.ReadRecord(&record, &scratch)) {\n    (*func)(reader.LastRecordOffset(), record, dst);\n  }\n  delete file;\n  return Status::OK();\n}\n\n// Called on every item found in a WriteBatch.\nclass WriteBatchItemPrinter : public WriteBatch::Handler {\n public:\n  void Put(const Slice& key, const Slice& value) override {\n    std::string r = \"  put '\";\n    AppendEscapedStringTo(&r, key);\n    r += \"' '\";\n    AppendEscapedStringTo(&r, value);\n    r += \"'\\n\";\n    dst_->Append(r);\n  }\n  void Delete(const Slice& key) override {\n    std::string r = \"  del '\";\n    AppendEscapedStringTo(&r, key);\n    r += \"'\\n\";\n    dst_->Append(r);\n  }\n\n  WritableFile* dst_;\n};\n\n// Called on every log record (each one of which is a WriteBatch)\n// found in a kLogFile.\nstatic void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) {\n  std::string r = \"--- offset \";\n  AppendNumberTo(&r, pos);\n  r += \"; \";\n  if (record.size() < 12) {\n    r += \"log record length \";\n    AppendNumberTo(&r, record.size());\n    r += \" is too small\\n\";\n    dst->Append(r);\n    return;\n  }\n  WriteBatch batch;\n  WriteBatchInternal::SetContents(&batch, record);\n  r += \"sequence \";\n  AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch));\n  r.push_back('\\n');\n  dst->Append(r);\n  WriteBatchItemPrinter batch_item_printer;\n  batch_item_printer.dst_ = dst;\n  Status s = batch.Iterate(&batch_item_printer);\n  if (!s.ok()) {\n    dst->Append(\"  error: \" + s.ToString() + \"\\n\");\n  }\n}\n\nStatus DumpLog(Env* env, const std::string& fname, WritableFile* dst) {\n  return PrintLogContents(env, fname, WriteBatchPrinter, dst);\n}\n\n// Called on every log record (each one of which is a WriteBatch)\n// found in a kDescriptorFile.\nstatic void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) {\n  std::string r = \"--- offset \";\n  AppendNumberTo(&r, pos);\n  r += \"; \";\n  VersionEdit edit;\n  Status s = edit.DecodeFrom(record);\n  if (!s.ok()) {\n    r += s.ToString();\n    r.push_back('\\n');\n  } else {\n    r += edit.DebugString();\n  }\n  dst->Append(r);\n}\n\nStatus DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) {\n  return PrintLogContents(env, fname, VersionEditPrinter, dst);\n}\n\nStatus DumpTable(Env* env, const std::string& fname, WritableFile* dst) {\n  uint64_t file_size;\n  RandomAccessFile* file = nullptr;\n  Table* table = nullptr;\n  Status s = env->GetFileSize(fname, &file_size);\n  if (s.ok()) {\n    s = env->NewRandomAccessFile(fname, &file);\n  }\n  if (s.ok()) {\n    // We use the default comparator, which may or may not match the\n    // comparator used in this database. However this should not cause\n    // problems since we only use Table operations that do not require\n    // any comparisons.  In particular, we do not call Seek or Prev.\n    s = Table::Open(Options(), file, file_size, &table);\n  }\n  if (!s.ok()) {\n    delete table;\n    delete file;\n    return s;\n  }\n\n  ReadOptions ro;\n  ro.fill_cache = false;\n  Iterator* iter = table->NewIterator(ro);\n  std::string r;\n  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n    r.clear();\n    ParsedInternalKey key;\n    if (!ParseInternalKey(iter->key(), &key)) {\n      r = \"badkey '\";\n      AppendEscapedStringTo(&r, iter->key());\n      r += \"' => '\";\n      AppendEscapedStringTo(&r, iter->value());\n      r += \"'\\n\";\n      dst->Append(r);\n    } else {\n      r = \"'\";\n      AppendEscapedStringTo(&r, key.user_key);\n      r += \"' @ \";\n      AppendNumberTo(&r, key.sequence);\n      r += \" : \";\n      if (key.type == kTypeDeletion) {\n        r += \"del\";\n      } else if (key.type == kTypeValue) {\n        r += \"val\";\n      } else {\n        AppendNumberTo(&r, key.type);\n      }\n      r += \" => '\";\n      AppendEscapedStringTo(&r, iter->value());\n      r += \"'\\n\";\n      dst->Append(r);\n    }\n  }\n  s = iter->status();\n  if (!s.ok()) {\n    dst->Append(\"iterator error: \" + s.ToString() + \"\\n\");\n  }\n\n  delete iter;\n  delete table;\n  delete file;\n  return Status::OK();\n}\n\n}  // namespace\n\nStatus DumpFile(Env* env, const std::string& fname, WritableFile* dst) {\n  FileType ftype;\n  if (!GuessType(fname, &ftype)) {\n    return Status::InvalidArgument(fname + \": unknown file type\");\n  }\n  switch (ftype) {\n    case kLogFile:\n      return DumpLog(env, fname, dst);\n    case kDescriptorFile:\n      return DumpDescriptor(env, fname, dst);\n    case kTableFile:\n      return DumpTable(env, fname, dst);\n    default:\n      break;\n  }\n  return Status::InvalidArgument(fname + \": not a dump-able file type\");\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/fault_injection_test.cc",
    "content": "// Copyright 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// This test uses a custom Env to keep track of the state of a filesystem as of\n// the last \"sync\". It then checks for data loss errors by purposely dropping\n// file data (or entire files) not protected by a \"sync\".\n\n#include <map>\n#include <set>\n\n#include \"db/db_impl.h\"\n#include \"db/filename.h\"\n#include \"db/log_format.h\"\n#include \"db/version_set.h\"\n#include \"leveldb/cache.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/table.h\"\n#include \"leveldb/write_batch.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/logging.h\"\n#include \"util/mutexlock.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nstatic const int kValueSize = 1000;\nstatic const int kMaxNumValues = 2000;\nstatic const size_t kNumIterations = 3;\n\nclass FaultInjectionTestEnv;\n\nnamespace {\n\n// Assume a filename, and not a directory name like \"/foo/bar/\"\nstatic std::string GetDirName(const std::string& filename) {\n  size_t found = filename.find_last_of(\"/\\\\\");\n  if (found == std::string::npos) {\n    return \"\";\n  } else {\n    return filename.substr(0, found);\n  }\n}\n\nStatus SyncDir(const std::string& dir) {\n  // As this is a test it isn't required to *actually* sync this directory.\n  return Status::OK();\n}\n\n// A basic file truncation function suitable for this test.\nStatus Truncate(const std::string& filename, uint64_t length) {\n  leveldb::Env* env = leveldb::Env::Default();\n\n  SequentialFile* orig_file;\n  Status s = env->NewSequentialFile(filename, &orig_file);\n  if (!s.ok()) return s;\n\n  char* scratch = new char[length];\n  leveldb::Slice result;\n  s = orig_file->Read(length, &result, scratch);\n  delete orig_file;\n  if (s.ok()) {\n    std::string tmp_name = GetDirName(filename) + \"/truncate.tmp\";\n    WritableFile* tmp_file;\n    s = env->NewWritableFile(tmp_name, &tmp_file);\n    if (s.ok()) {\n      s = tmp_file->Append(result);\n      delete tmp_file;\n      if (s.ok()) {\n        s = env->RenameFile(tmp_name, filename);\n      } else {\n        env->DeleteFile(tmp_name);\n      }\n    }\n  }\n\n  delete[] scratch;\n\n  return s;\n}\n\nstruct FileState {\n  std::string filename_;\n  int64_t pos_;\n  int64_t pos_at_last_sync_;\n  int64_t pos_at_last_flush_;\n\n  FileState(const std::string& filename)\n      : filename_(filename),\n        pos_(-1),\n        pos_at_last_sync_(-1),\n        pos_at_last_flush_(-1) {}\n\n  FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {}\n\n  bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }\n\n  Status DropUnsyncedData() const;\n};\n\n}  // anonymous namespace\n\n// A wrapper around WritableFile which informs another Env whenever this file\n// is written to or sync'ed.\nclass TestWritableFile : public WritableFile {\n public:\n  TestWritableFile(const FileState& state, WritableFile* f,\n                   FaultInjectionTestEnv* env);\n  ~TestWritableFile() override;\n  Status Append(const Slice& data) override;\n  Status Close() override;\n  Status Flush() override;\n  Status Sync() override;\n  std::string GetName() const override { return \"\"; }\n\n private:\n  FileState state_;\n  WritableFile* target_;\n  bool writable_file_opened_;\n  FaultInjectionTestEnv* env_;\n\n  Status SyncParent();\n};\n\nclass FaultInjectionTestEnv : public EnvWrapper {\n public:\n  FaultInjectionTestEnv()\n      : EnvWrapper(Env::Default()), filesystem_active_(true) {}\n  ~FaultInjectionTestEnv() override = default;\n  Status NewWritableFile(const std::string& fname,\n                         WritableFile** result) override;\n  Status NewAppendableFile(const std::string& fname,\n                           WritableFile** result) override;\n  Status DeleteFile(const std::string& f) override;\n  Status RenameFile(const std::string& s, const std::string& t) override;\n\n  void WritableFileClosed(const FileState& state);\n  Status DropUnsyncedFileData();\n  Status DeleteFilesCreatedAfterLastDirSync();\n  void DirWasSynced();\n  bool IsFileCreatedSinceLastDirSync(const std::string& filename);\n  void ResetState();\n  void UntrackFile(const std::string& f);\n  // Setting the filesystem to inactive is the test equivalent to simulating a\n  // system reset. Setting to inactive will freeze our saved filesystem state so\n  // that it will stop being recorded. It can then be reset back to the state at\n  // the time of the reset.\n  bool IsFilesystemActive() LOCKS_EXCLUDED(mutex_) {\n    MutexLock l(&mutex_);\n    return filesystem_active_;\n  }\n  void SetFilesystemActive(bool active) LOCKS_EXCLUDED(mutex_) {\n    MutexLock l(&mutex_);\n    filesystem_active_ = active;\n  }\n\n private:\n  port::Mutex mutex_;\n  std::map<std::string, FileState> db_file_state_ GUARDED_BY(mutex_);\n  std::set<std::string> new_files_since_last_dir_sync_ GUARDED_BY(mutex_);\n  bool filesystem_active_ GUARDED_BY(mutex_);  // Record flushes, syncs, writes\n};\n\nTestWritableFile::TestWritableFile(const FileState& state, WritableFile* f,\n                                   FaultInjectionTestEnv* env)\n    : state_(state), target_(f), writable_file_opened_(true), env_(env) {\n  assert(f != nullptr);\n}\n\nTestWritableFile::~TestWritableFile() {\n  if (writable_file_opened_) {\n    Close();\n  }\n  delete target_;\n}\n\nStatus TestWritableFile::Append(const Slice& data) {\n  Status s = target_->Append(data);\n  if (s.ok() && env_->IsFilesystemActive()) {\n    state_.pos_ += data.size();\n  }\n  return s;\n}\n\nStatus TestWritableFile::Close() {\n  writable_file_opened_ = false;\n  Status s = target_->Close();\n  if (s.ok()) {\n    env_->WritableFileClosed(state_);\n  }\n  return s;\n}\n\nStatus TestWritableFile::Flush() {\n  Status s = target_->Flush();\n  if (s.ok() && env_->IsFilesystemActive()) {\n    state_.pos_at_last_flush_ = state_.pos_;\n  }\n  return s;\n}\n\nStatus TestWritableFile::SyncParent() {\n  Status s = SyncDir(GetDirName(state_.filename_));\n  if (s.ok()) {\n    env_->DirWasSynced();\n  }\n  return s;\n}\n\nStatus TestWritableFile::Sync() {\n  if (!env_->IsFilesystemActive()) {\n    return Status::OK();\n  }\n  // Ensure new files referred to by the manifest are in the filesystem.\n  Status s = target_->Sync();\n  if (s.ok()) {\n    state_.pos_at_last_sync_ = state_.pos_;\n  }\n  if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) {\n    Status ps = SyncParent();\n    if (s.ok() && !ps.ok()) {\n      s = ps;\n    }\n  }\n  return s;\n}\n\nStatus FaultInjectionTestEnv::NewWritableFile(const std::string& fname,\n                                              WritableFile** result) {\n  WritableFile* actual_writable_file;\n  Status s = target()->NewWritableFile(fname, &actual_writable_file);\n  if (s.ok()) {\n    FileState state(fname);\n    state.pos_ = 0;\n    *result = new TestWritableFile(state, actual_writable_file, this);\n    // NewWritableFile doesn't append to files, so if the same file is\n    // opened again then it will be truncated - so forget our saved\n    // state.\n    UntrackFile(fname);\n    MutexLock l(&mutex_);\n    new_files_since_last_dir_sync_.insert(fname);\n  }\n  return s;\n}\n\nStatus FaultInjectionTestEnv::NewAppendableFile(const std::string& fname,\n                                                WritableFile** result) {\n  WritableFile* actual_writable_file;\n  Status s = target()->NewAppendableFile(fname, &actual_writable_file);\n  if (s.ok()) {\n    FileState state(fname);\n    state.pos_ = 0;\n    {\n      MutexLock l(&mutex_);\n      if (db_file_state_.count(fname) == 0) {\n        new_files_since_last_dir_sync_.insert(fname);\n      } else {\n        state = db_file_state_[fname];\n      }\n    }\n    *result = new TestWritableFile(state, actual_writable_file, this);\n  }\n  return s;\n}\n\nStatus FaultInjectionTestEnv::DropUnsyncedFileData() {\n  Status s;\n  MutexLock l(&mutex_);\n  for (const auto& kvp : db_file_state_) {\n    if (!s.ok()) {\n      break;\n    }\n    const FileState& state = kvp.second;\n    if (!state.IsFullySynced()) {\n      s = state.DropUnsyncedData();\n    }\n  }\n  return s;\n}\n\nvoid FaultInjectionTestEnv::DirWasSynced() {\n  MutexLock l(&mutex_);\n  new_files_since_last_dir_sync_.clear();\n}\n\nbool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync(\n    const std::string& filename) {\n  MutexLock l(&mutex_);\n  return new_files_since_last_dir_sync_.find(filename) !=\n         new_files_since_last_dir_sync_.end();\n}\n\nvoid FaultInjectionTestEnv::UntrackFile(const std::string& f) {\n  MutexLock l(&mutex_);\n  db_file_state_.erase(f);\n  new_files_since_last_dir_sync_.erase(f);\n}\n\nStatus FaultInjectionTestEnv::DeleteFile(const std::string& f) {\n  Status s = EnvWrapper::DeleteFile(f);\n  ASSERT_OK(s);\n  if (s.ok()) {\n    UntrackFile(f);\n  }\n  return s;\n}\n\nStatus FaultInjectionTestEnv::RenameFile(const std::string& s,\n                                         const std::string& t) {\n  Status ret = EnvWrapper::RenameFile(s, t);\n\n  if (ret.ok()) {\n    MutexLock l(&mutex_);\n    if (db_file_state_.find(s) != db_file_state_.end()) {\n      db_file_state_[t] = db_file_state_[s];\n      db_file_state_.erase(s);\n    }\n\n    if (new_files_since_last_dir_sync_.erase(s) != 0) {\n      assert(new_files_since_last_dir_sync_.find(t) ==\n             new_files_since_last_dir_sync_.end());\n      new_files_since_last_dir_sync_.insert(t);\n    }\n  }\n\n  return ret;\n}\n\nvoid FaultInjectionTestEnv::ResetState() {\n  // Since we are not destroying the database, the existing files\n  // should keep their recorded synced/flushed state. Therefore\n  // we do not reset db_file_state_ and new_files_since_last_dir_sync_.\n  SetFilesystemActive(true);\n}\n\nStatus FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() {\n  // Because DeleteFile access this container make a copy to avoid deadlock\n  mutex_.Lock();\n  std::set<std::string> new_files(new_files_since_last_dir_sync_.begin(),\n                                  new_files_since_last_dir_sync_.end());\n  mutex_.Unlock();\n  Status status;\n  for (const auto& new_file : new_files) {\n    Status delete_status = DeleteFile(new_file);\n    if (!delete_status.ok() && status.ok()) {\n      status = std::move(delete_status);\n    }\n  }\n  return status;\n}\n\nvoid FaultInjectionTestEnv::WritableFileClosed(const FileState& state) {\n  MutexLock l(&mutex_);\n  db_file_state_[state.filename_] = state;\n}\n\nStatus FileState::DropUnsyncedData() const {\n  int64_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_;\n  return Truncate(filename_, sync_pos);\n}\n\nclass FaultInjectionTest {\n public:\n  enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR };\n  enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES };\n\n  FaultInjectionTestEnv* env_;\n  std::string dbname_;\n  Cache* tiny_cache_;\n  Options options_;\n  DB* db_;\n\n  FaultInjectionTest()\n      : env_(new FaultInjectionTestEnv),\n        tiny_cache_(NewLRUCache(100)),\n        db_(nullptr) {\n    dbname_ = test::TmpDir() + \"/fault_test\";\n    DestroyDB(dbname_, Options());  // Destroy any db from earlier run\n    options_.reuse_logs = true;\n    options_.env = env_;\n    options_.paranoid_checks = true;\n    options_.block_cache = tiny_cache_;\n    options_.create_if_missing = true;\n  }\n\n  ~FaultInjectionTest() {\n    CloseDB();\n    DestroyDB(dbname_, Options());\n    delete tiny_cache_;\n    delete env_;\n  }\n\n  void ReuseLogs(bool reuse) { options_.reuse_logs = reuse; }\n\n  void Build(int start_idx, int num_vals) {\n    std::string key_space, value_space;\n    WriteBatch batch;\n    for (int i = start_idx; i < start_idx + num_vals; i++) {\n      Slice key = Key(i, &key_space);\n      batch.Clear();\n      batch.Put(key, Value(i, &value_space));\n      WriteOptions options;\n      ASSERT_OK(db_->Write(options, &batch));\n    }\n  }\n\n  Status ReadValue(int i, std::string* val) const {\n    std::string key_space, value_space;\n    Slice key = Key(i, &key_space);\n    Value(i, &value_space);\n    ReadOptions options;\n    return db_->Get(options, key, val);\n  }\n\n  Status Verify(int start_idx, int num_vals,\n                ExpectedVerifResult expected) const {\n    std::string val;\n    std::string value_space;\n    Status s;\n    for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) {\n      Value(i, &value_space);\n      s = ReadValue(i, &val);\n      if (expected == VAL_EXPECT_NO_ERROR) {\n        if (s.ok()) {\n          ASSERT_EQ(value_space, val);\n        }\n      } else if (s.ok()) {\n        fprintf(stderr, \"Expected an error at %d, but was OK\\n\", i);\n        s = Status::IOError(dbname_, \"Expected value error:\");\n      } else {\n        s = Status::OK();  // An expected error\n      }\n    }\n    return s;\n  }\n\n  // Return the ith key\n  Slice Key(int i, std::string* storage) const {\n    char buf[100];\n    snprintf(buf, sizeof(buf), \"%016d\", i);\n    storage->assign(buf, strlen(buf));\n    return Slice(*storage);\n  }\n\n  // Return the value to associate with the specified key\n  Slice Value(int k, std::string* storage) const {\n    Random r(k);\n    return test::RandomString(&r, kValueSize, storage);\n  }\n\n  Status OpenDB() {\n    delete db_;\n    db_ = nullptr;\n    env_->ResetState();\n    return DB::Open(options_, dbname_, &db_);\n  }\n\n  void CloseDB() {\n    delete db_;\n    db_ = nullptr;\n  }\n\n  void DeleteAllData() {\n    Iterator* iter = db_->NewIterator(ReadOptions());\n    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n      ASSERT_OK(db_->Delete(WriteOptions(), iter->key()));\n    }\n\n    delete iter;\n  }\n\n  void ResetDBState(ResetMethod reset_method) {\n    switch (reset_method) {\n      case RESET_DROP_UNSYNCED_DATA:\n        ASSERT_OK(env_->DropUnsyncedFileData());\n        break;\n      case RESET_DELETE_UNSYNCED_FILES:\n        ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync());\n        break;\n      default:\n        assert(false);\n    }\n  }\n\n  void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) {\n    DeleteAllData();\n    Build(0, num_pre_sync);\n    db_->CompactRange(nullptr, nullptr);\n    Build(num_pre_sync, num_post_sync);\n  }\n\n  void PartialCompactTestReopenWithFault(ResetMethod reset_method,\n                                         int num_pre_sync, int num_post_sync) {\n    env_->SetFilesystemActive(false);\n    CloseDB();\n    ResetDBState(reset_method);\n    ASSERT_OK(OpenDB());\n    ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR));\n    ASSERT_OK(Verify(num_pre_sync, num_post_sync,\n                     FaultInjectionTest::VAL_EXPECT_ERROR));\n  }\n\n  void NoWriteTestPreFault() {}\n\n  void NoWriteTestReopenWithFault(ResetMethod reset_method) {\n    CloseDB();\n    ResetDBState(reset_method);\n    ASSERT_OK(OpenDB());\n  }\n\n  void DoTest() {\n    Random rnd(0);\n    ASSERT_OK(OpenDB());\n    for (size_t idx = 0; idx < kNumIterations; idx++) {\n      int num_pre_sync = rnd.Uniform(kMaxNumValues);\n      int num_post_sync = rnd.Uniform(kMaxNumValues);\n\n      PartialCompactTestPreFault(num_pre_sync, num_post_sync);\n      PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA, num_pre_sync,\n                                        num_post_sync);\n\n      NoWriteTestPreFault();\n      NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA);\n\n      PartialCompactTestPreFault(num_pre_sync, num_post_sync);\n      // No new files created so we expect all values since no files will be\n      // dropped.\n      PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES,\n                                        num_pre_sync + num_post_sync, 0);\n\n      NoWriteTestPreFault();\n      NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES);\n    }\n  }\n};\n\nTEST(FaultInjectionTest, FaultTestNoLogReuse) {\n  ReuseLogs(false);\n  DoTest();\n}\n\nTEST(FaultInjectionTest, FaultTestWithLogReuse) {\n  ReuseLogs(true);\n  DoTest();\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/filename.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/filename.h\"\n\n#include <ctype.h>\n#include <stdio.h>\n\n#include \"db/dbformat.h\"\n#include \"leveldb/env.h\"\n#include \"util/logging.h\"\n\nnamespace leveldb {\n\n// A utility routine: write \"data\" to the named file and Sync() it.\nStatus WriteStringToFileSync(Env* env, const Slice& data,\n                             const std::string& fname);\n\nstatic std::string MakeFileName(const std::string& dbname, uint64_t number,\n                                const char* suffix) {\n  char buf[100];\n  snprintf(buf, sizeof(buf), \"/%06llu.%s\",\n           static_cast<unsigned long long>(number), suffix);\n  return dbname + buf;\n}\n\nstd::string LogFileName(const std::string& dbname, uint64_t number) {\n  assert(number > 0);\n  return MakeFileName(dbname, number, \"log\");\n}\n\nstd::string TableFileName(const std::string& dbname, uint64_t number) {\n  assert(number > 0);\n  return MakeFileName(dbname, number, \"ldb\");\n}\n\nstd::string SSTTableFileName(const std::string& dbname, uint64_t number) {\n  assert(number > 0);\n  return MakeFileName(dbname, number, \"sst\");\n}\n\nstd::string DescriptorFileName(const std::string& dbname, uint64_t number) {\n  assert(number > 0);\n  char buf[100];\n  snprintf(buf, sizeof(buf), \"/MANIFEST-%06llu\",\n           static_cast<unsigned long long>(number));\n  return dbname + buf;\n}\n\nstd::string CurrentFileName(const std::string& dbname) {\n  return dbname + \"/CURRENT\";\n}\n\nstd::string LockFileName(const std::string& dbname) { return dbname + \"/LOCK\"; }\n\nstd::string TempFileName(const std::string& dbname, uint64_t number) {\n  assert(number > 0);\n  return MakeFileName(dbname, number, \"dbtmp\");\n}\n\nstd::string InfoLogFileName(const std::string& dbname) {\n  return dbname + \"/LOG\";\n}\n\n// Return the name of the old info log file for \"dbname\".\nstd::string OldInfoLogFileName(const std::string& dbname) {\n  return dbname + \"/LOG.old\";\n}\n\n// Owned filenames have the form:\n//    dbname/CURRENT\n//    dbname/LOCK\n//    dbname/LOG\n//    dbname/LOG.old\n//    dbname/MANIFEST-[0-9]+\n//    dbname/[0-9]+.(log|sst|ldb)\nbool ParseFileName(const std::string& filename, uint64_t* number,\n                   FileType* type) {\n  Slice rest(filename);\n  if (rest == \"CURRENT\") {\n    *number = 0;\n    *type = kCurrentFile;\n  } else if (rest == \"LOCK\") {\n    *number = 0;\n    *type = kDBLockFile;\n  } else if (rest == \"LOG\" || rest == \"LOG.old\") {\n    *number = 0;\n    *type = kInfoLogFile;\n  } else if (rest.starts_with(\"MANIFEST-\")) {\n    rest.remove_prefix(strlen(\"MANIFEST-\"));\n    uint64_t num;\n    if (!ConsumeDecimalNumber(&rest, &num)) {\n      return false;\n    }\n    if (!rest.empty()) {\n      return false;\n    }\n    *type = kDescriptorFile;\n    *number = num;\n  } else {\n    // Avoid strtoull() to keep filename format independent of the\n    // current locale\n    uint64_t num;\n    if (!ConsumeDecimalNumber(&rest, &num)) {\n      return false;\n    }\n    Slice suffix = rest;\n    if (suffix == Slice(\".log\")) {\n      *type = kLogFile;\n    } else if (suffix == Slice(\".sst\") || suffix == Slice(\".ldb\")) {\n      *type = kTableFile;\n    } else if (suffix == Slice(\".dbtmp\")) {\n      *type = kTempFile;\n    } else {\n      return false;\n    }\n    *number = num;\n  }\n  return true;\n}\n\nStatus SetCurrentFile(Env* env, const std::string& dbname,\n                      uint64_t descriptor_number) {\n  // Remove leading \"dbname/\" and add newline to manifest file name\n  std::string manifest = DescriptorFileName(dbname, descriptor_number);\n  Slice contents = manifest;\n  assert(contents.starts_with(dbname + \"/\"));\n  contents.remove_prefix(dbname.size() + 1);\n  std::string tmp = TempFileName(dbname, descriptor_number);\n  Status s = WriteStringToFileSync(env, contents.ToString() + \"\\n\", tmp);\n  if (s.ok()) {\n    s = env->RenameFile(tmp, CurrentFileName(dbname));\n  }\n  if (!s.ok()) {\n    env->DeleteFile(tmp);\n  }\n  return s;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/filename.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// File names used by DB code\n\n#ifndef STORAGE_LEVELDB_DB_FILENAME_H_\n#define STORAGE_LEVELDB_DB_FILENAME_H_\n\n#include <stdint.h>\n\n#include <string>\n\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n#include \"port/port.h\"\n\nnamespace leveldb {\n\nclass Env;\n\nenum FileType {\n  kLogFile,\n  kDBLockFile,\n  kTableFile,\n  kDescriptorFile,\n  kCurrentFile,\n  kTempFile,\n  kInfoLogFile  // Either the current one, or an old one\n};\n\n// Return the name of the log file with the specified number\n// in the db named by \"dbname\".  The result will be prefixed with\n// \"dbname\".\nstd::string LogFileName(const std::string& dbname, uint64_t number);\n\n// Return the name of the sstable with the specified number\n// in the db named by \"dbname\".  The result will be prefixed with\n// \"dbname\".\nstd::string TableFileName(const std::string& dbname, uint64_t number);\n\n// Return the legacy file name for an sstable with the specified number\n// in the db named by \"dbname\". The result will be prefixed with\n// \"dbname\".\nstd::string SSTTableFileName(const std::string& dbname, uint64_t number);\n\n// Return the name of the descriptor file for the db named by\n// \"dbname\" and the specified incarnation number.  The result will be\n// prefixed with \"dbname\".\nstd::string DescriptorFileName(const std::string& dbname, uint64_t number);\n\n// Return the name of the current file.  This file contains the name\n// of the current manifest file.  The result will be prefixed with\n// \"dbname\".\nstd::string CurrentFileName(const std::string& dbname);\n\n// Return the name of the lock file for the db named by\n// \"dbname\".  The result will be prefixed with \"dbname\".\nstd::string LockFileName(const std::string& dbname);\n\n// Return the name of a temporary file owned by the db named \"dbname\".\n// The result will be prefixed with \"dbname\".\nstd::string TempFileName(const std::string& dbname, uint64_t number);\n\n// Return the name of the info log file for \"dbname\".\nstd::string InfoLogFileName(const std::string& dbname);\n\n// Return the name of the old info log file for \"dbname\".\nstd::string OldInfoLogFileName(const std::string& dbname);\n\n// If filename is a leveldb file, store the type of the file in *type.\n// The number encoded in the filename is stored in *number.  If the\n// filename was successfully parsed, returns true.  Else return false.\nbool ParseFileName(const std::string& filename, uint64_t* number,\n                   FileType* type);\n\n// Make the CURRENT file point to the descriptor file with the\n// specified number.\nStatus SetCurrentFile(Env* env, const std::string& dbname,\n                      uint64_t descriptor_number);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_FILENAME_H_\n"
  },
  {
    "path": "src/leveldb/db/filename_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/filename.h\"\n\n#include \"db/dbformat.h\"\n#include \"port/port.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass FileNameTest {};\n\nTEST(FileNameTest, Parse) {\n  Slice db;\n  FileType type;\n  uint64_t number;\n\n  // Successful parses\n  static struct {\n    const char* fname;\n    uint64_t number;\n    FileType type;\n  } cases[] = {\n      {\"100.log\", 100, kLogFile},\n      {\"0.log\", 0, kLogFile},\n      {\"0.sst\", 0, kTableFile},\n      {\"0.ldb\", 0, kTableFile},\n      {\"CURRENT\", 0, kCurrentFile},\n      {\"LOCK\", 0, kDBLockFile},\n      {\"MANIFEST-2\", 2, kDescriptorFile},\n      {\"MANIFEST-7\", 7, kDescriptorFile},\n      {\"LOG\", 0, kInfoLogFile},\n      {\"LOG.old\", 0, kInfoLogFile},\n      {\"18446744073709551615.log\", 18446744073709551615ull, kLogFile},\n  };\n  for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {\n    std::string f = cases[i].fname;\n    ASSERT_TRUE(ParseFileName(f, &number, &type)) << f;\n    ASSERT_EQ(cases[i].type, type) << f;\n    ASSERT_EQ(cases[i].number, number) << f;\n  }\n\n  // Errors\n  static const char* errors[] = {\"\",\n                                 \"foo\",\n                                 \"foo-dx-100.log\",\n                                 \".log\",\n                                 \"\",\n                                 \"manifest\",\n                                 \"CURREN\",\n                                 \"CURRENTX\",\n                                 \"MANIFES\",\n                                 \"MANIFEST\",\n                                 \"MANIFEST-\",\n                                 \"XMANIFEST-3\",\n                                 \"MANIFEST-3x\",\n                                 \"LOC\",\n                                 \"LOCKx\",\n                                 \"LO\",\n                                 \"LOGx\",\n                                 \"18446744073709551616.log\",\n                                 \"184467440737095516150.log\",\n                                 \"100\",\n                                 \"100.\",\n                                 \"100.lop\"};\n  for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) {\n    std::string f = errors[i];\n    ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f;\n  }\n}\n\nTEST(FileNameTest, Construction) {\n  uint64_t number;\n  FileType type;\n  std::string fname;\n\n  fname = CurrentFileName(\"foo\");\n  ASSERT_EQ(\"foo/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(0, number);\n  ASSERT_EQ(kCurrentFile, type);\n\n  fname = LockFileName(\"foo\");\n  ASSERT_EQ(\"foo/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(0, number);\n  ASSERT_EQ(kDBLockFile, type);\n\n  fname = LogFileName(\"foo\", 192);\n  ASSERT_EQ(\"foo/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(192, number);\n  ASSERT_EQ(kLogFile, type);\n\n  fname = TableFileName(\"bar\", 200);\n  ASSERT_EQ(\"bar/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(200, number);\n  ASSERT_EQ(kTableFile, type);\n\n  fname = DescriptorFileName(\"bar\", 100);\n  ASSERT_EQ(\"bar/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(100, number);\n  ASSERT_EQ(kDescriptorFile, type);\n\n  fname = TempFileName(\"tmp\", 999);\n  ASSERT_EQ(\"tmp/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(999, number);\n  ASSERT_EQ(kTempFile, type);\n\n  fname = InfoLogFileName(\"foo\");\n  ASSERT_EQ(\"foo/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(0, number);\n  ASSERT_EQ(kInfoLogFile, type);\n\n  fname = OldInfoLogFileName(\"foo\");\n  ASSERT_EQ(\"foo/\", std::string(fname.data(), 4));\n  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));\n  ASSERT_EQ(0, number);\n  ASSERT_EQ(kInfoLogFile, type);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/leveldbutil.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <stdio.h>\n\n#include \"leveldb/dumpfile.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\nnamespace {\n\nclass StdoutPrinter : public WritableFile {\n public:\n  Status Append(const Slice& data) override {\n    fwrite(data.data(), 1, data.size(), stdout);\n    return Status::OK();\n  }\n  Status Close() override { return Status::OK(); }\n  Status Flush() override { return Status::OK(); }\n  Status Sync() override { return Status::OK(); }\n  std::string GetName() const override { return \"[stdout]\"; }\n};\n\nbool HandleDumpCommand(Env* env, char** files, int num) {\n  StdoutPrinter printer;\n  bool ok = true;\n  for (int i = 0; i < num; i++) {\n    Status s = DumpFile(env, files[i], &printer);\n    if (!s.ok()) {\n      fprintf(stderr, \"%s\\n\", s.ToString().c_str());\n      ok = false;\n    }\n  }\n  return ok;\n}\n\n}  // namespace\n}  // namespace leveldb\n\nstatic void Usage() {\n  fprintf(stderr,\n          \"Usage: leveldbutil command...\\n\"\n          \"   dump files...         -- dump contents of specified files\\n\");\n}\n\nint main(int argc, char** argv) {\n  leveldb::Env* env = leveldb::Env::Default();\n  bool ok = true;\n  if (argc < 2) {\n    Usage();\n    ok = false;\n  } else {\n    std::string command = argv[1];\n    if (command == \"dump\") {\n      ok = leveldb::HandleDumpCommand(env, argv + 2, argc - 2);\n    } else {\n      Usage();\n      ok = false;\n    }\n  }\n  return (ok ? 0 : 1);\n}\n"
  },
  {
    "path": "src/leveldb/db/log_format.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Log format information shared by reader and writer.\n// See ../doc/log_format.md for more detail.\n\n#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_\n#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_\n\nnamespace leveldb {\nnamespace log {\n\nenum RecordType {\n  // Zero is reserved for preallocated files\n  kZeroType = 0,\n\n  kFullType = 1,\n\n  // For fragments\n  kFirstType = 2,\n  kMiddleType = 3,\n  kLastType = 4\n};\nstatic const int kMaxRecordType = kLastType;\n\nstatic const int kBlockSize = 32768;\n\n// Header is checksum (4 bytes), length (2 bytes), type (1 byte).\nstatic const int kHeaderSize = 4 + 2 + 1;\n\n}  // namespace log\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_LOG_FORMAT_H_\n"
  },
  {
    "path": "src/leveldb/db/log_reader.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/log_reader.h\"\n\n#include <stdio.h>\n\n#include \"leveldb/env.h\"\n#include \"util/coding.h\"\n#include \"util/crc32c.h\"\n\nnamespace leveldb {\nnamespace log {\n\nReader::Reporter::~Reporter() = default;\n\nReader::Reader(SequentialFile* file, Reporter* reporter, bool checksum,\n               uint64_t initial_offset)\n    : file_(file),\n      reporter_(reporter),\n      checksum_(checksum),\n      backing_store_(new char[kBlockSize]),\n      buffer_(),\n      eof_(false),\n      last_record_offset_(0),\n      end_of_buffer_offset_(0),\n      initial_offset_(initial_offset),\n      resyncing_(initial_offset > 0) {}\n\nReader::~Reader() { delete[] backing_store_; }\n\nbool Reader::SkipToInitialBlock() {\n  const size_t offset_in_block = initial_offset_ % kBlockSize;\n  uint64_t block_start_location = initial_offset_ - offset_in_block;\n\n  // Don't search a block if we'd be in the trailer\n  if (offset_in_block > kBlockSize - 6) {\n    block_start_location += kBlockSize;\n  }\n\n  end_of_buffer_offset_ = block_start_location;\n\n  // Skip to start of first block that can contain the initial record\n  if (block_start_location > 0) {\n    Status skip_status = file_->Skip(block_start_location);\n    if (!skip_status.ok()) {\n      ReportDrop(block_start_location, skip_status);\n      return false;\n    }\n  }\n\n  return true;\n}\n\nbool Reader::ReadRecord(Slice* record, std::string* scratch) {\n  if (last_record_offset_ < initial_offset_) {\n    if (!SkipToInitialBlock()) {\n      return false;\n    }\n  }\n\n  scratch->clear();\n  record->clear();\n  bool in_fragmented_record = false;\n  // Record offset of the logical record that we're reading\n  // 0 is a dummy value to make compilers happy\n  uint64_t prospective_record_offset = 0;\n\n  Slice fragment;\n  while (true) {\n    const unsigned int record_type = ReadPhysicalRecord(&fragment);\n\n    // ReadPhysicalRecord may have only had an empty trailer remaining in its\n    // internal buffer. Calculate the offset of the next physical record now\n    // that it has returned, properly accounting for its header size.\n    uint64_t physical_record_offset =\n        end_of_buffer_offset_ - buffer_.size() - kHeaderSize - fragment.size();\n\n    if (resyncing_) {\n      if (record_type == kMiddleType) {\n        continue;\n      } else if (record_type == kLastType) {\n        resyncing_ = false;\n        continue;\n      } else {\n        resyncing_ = false;\n      }\n    }\n\n    switch (record_type) {\n      case kFullType:\n        if (in_fragmented_record) {\n          // Handle bug in earlier versions of log::Writer where\n          // it could emit an empty kFirstType record at the tail end\n          // of a block followed by a kFullType or kFirstType record\n          // at the beginning of the next block.\n          if (!scratch->empty()) {\n            ReportCorruption(scratch->size(), \"partial record without end(1)\");\n          }\n        }\n        prospective_record_offset = physical_record_offset;\n        scratch->clear();\n        *record = fragment;\n        last_record_offset_ = prospective_record_offset;\n        return true;\n\n      case kFirstType:\n        if (in_fragmented_record) {\n          // Handle bug in earlier versions of log::Writer where\n          // it could emit an empty kFirstType record at the tail end\n          // of a block followed by a kFullType or kFirstType record\n          // at the beginning of the next block.\n          if (!scratch->empty()) {\n            ReportCorruption(scratch->size(), \"partial record without end(2)\");\n          }\n        }\n        prospective_record_offset = physical_record_offset;\n        scratch->assign(fragment.data(), fragment.size());\n        in_fragmented_record = true;\n        break;\n\n      case kMiddleType:\n        if (!in_fragmented_record) {\n          ReportCorruption(fragment.size(),\n                           \"missing start of fragmented record(1)\");\n        } else {\n          scratch->append(fragment.data(), fragment.size());\n        }\n        break;\n\n      case kLastType:\n        if (!in_fragmented_record) {\n          ReportCorruption(fragment.size(),\n                           \"missing start of fragmented record(2)\");\n        } else {\n          scratch->append(fragment.data(), fragment.size());\n          *record = Slice(*scratch);\n          last_record_offset_ = prospective_record_offset;\n          return true;\n        }\n        break;\n\n      case kEof:\n        if (in_fragmented_record) {\n          // This can be caused by the writer dying immediately after\n          // writing a physical record but before completing the next; don't\n          // treat it as a corruption, just ignore the entire logical record.\n          scratch->clear();\n        }\n        return false;\n\n      case kBadRecord:\n        if (in_fragmented_record) {\n          ReportCorruption(scratch->size(), \"error in middle of record\");\n          in_fragmented_record = false;\n          scratch->clear();\n        }\n        break;\n\n      default: {\n        char buf[40];\n        snprintf(buf, sizeof(buf), \"unknown record type %u\", record_type);\n        ReportCorruption(\n            (fragment.size() + (in_fragmented_record ? scratch->size() : 0)),\n            buf);\n        in_fragmented_record = false;\n        scratch->clear();\n        break;\n      }\n    }\n  }\n  return false;\n}\n\nuint64_t Reader::LastRecordOffset() { return last_record_offset_; }\n\nvoid Reader::ReportCorruption(uint64_t bytes, const char* reason) {\n  ReportDrop(bytes, Status::Corruption(reason, file_->GetName()));\n}\n\nvoid Reader::ReportDrop(uint64_t bytes, const Status& reason) {\n  if (reporter_ != nullptr &&\n      end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) {\n    reporter_->Corruption(static_cast<size_t>(bytes), reason);\n  }\n}\n\nunsigned int Reader::ReadPhysicalRecord(Slice* result) {\n  while (true) {\n    if (buffer_.size() < kHeaderSize) {\n      if (!eof_) {\n        // Last read was a full read, so this is a trailer to skip\n        buffer_.clear();\n        Status status = file_->Read(kBlockSize, &buffer_, backing_store_);\n        end_of_buffer_offset_ += buffer_.size();\n        if (!status.ok()) {\n          buffer_.clear();\n          ReportDrop(kBlockSize, status);\n          eof_ = true;\n          return kEof;\n        } else if (buffer_.size() < kBlockSize) {\n          eof_ = true;\n        }\n        continue;\n      } else {\n        // Note that if buffer_ is non-empty, we have a truncated header at the\n        // end of the file, which can be caused by the writer crashing in the\n        // middle of writing the header. Instead of considering this an error,\n        // just report EOF.\n        buffer_.clear();\n        return kEof;\n      }\n    }\n\n    // Parse the header\n    const char* header = buffer_.data();\n    const uint32_t a = static_cast<uint32_t>(header[4]) & 0xff;\n    const uint32_t b = static_cast<uint32_t>(header[5]) & 0xff;\n    const unsigned int type = header[6];\n    const uint32_t length = a | (b << 8);\n    if (kHeaderSize + length > buffer_.size()) {\n      size_t drop_size = buffer_.size();\n      buffer_.clear();\n      if (!eof_) {\n        ReportCorruption(drop_size, \"bad record length\");\n        return kBadRecord;\n      }\n      // If the end of the file has been reached without reading |length| bytes\n      // of payload, assume the writer died in the middle of writing the record.\n      // Don't report a corruption.\n      return kEof;\n    }\n\n    if (type == kZeroType && length == 0) {\n      // Skip zero length record without reporting any drops since\n      // such records are produced by the mmap based writing code in\n      // env_posix.cc that preallocates file regions.\n      buffer_.clear();\n      return kBadRecord;\n    }\n\n    // Check crc\n    if (checksum_) {\n      uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header));\n      uint32_t actual_crc = crc32c::Value(header + 6, 1 + length);\n      if (actual_crc != expected_crc) {\n        // Drop the rest of the buffer since \"length\" itself may have\n        // been corrupted and if we trust it, we could find some\n        // fragment of a real log record that just happens to look\n        // like a valid log record.\n        size_t drop_size = buffer_.size();\n        buffer_.clear();\n        ReportCorruption(drop_size, \"checksum mismatch\");\n        return kBadRecord;\n      }\n    }\n\n    buffer_.remove_prefix(kHeaderSize + length);\n\n    // Skip physical record that started before initial_offset_\n    if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length <\n        initial_offset_) {\n      result->clear();\n      return kBadRecord;\n    }\n\n    *result = Slice(header + kHeaderSize, length);\n    return type;\n  }\n}\n\n}  // namespace log\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/log_reader.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_\n#define STORAGE_LEVELDB_DB_LOG_READER_H_\n\n#include <stdint.h>\n\n#include \"db/log_format.h\"\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nclass SequentialFile;\n\nnamespace log {\n\nclass Reader {\n public:\n  // Interface for reporting errors.\n  class Reporter {\n   public:\n    virtual ~Reporter();\n\n    // Some corruption was detected.  \"size\" is the approximate number\n    // of bytes dropped due to the corruption.\n    virtual void Corruption(size_t bytes, const Status& status) = 0;\n  };\n\n  // Create a reader that will return log records from \"*file\".\n  // \"*file\" must remain live while this Reader is in use.\n  //\n  // If \"reporter\" is non-null, it is notified whenever some data is\n  // dropped due to a detected corruption.  \"*reporter\" must remain\n  // live while this Reader is in use.\n  //\n  // If \"checksum\" is true, verify checksums if available.\n  //\n  // The Reader will start reading at the first record located at physical\n  // position >= initial_offset within the file.\n  Reader(SequentialFile* file, Reporter* reporter, bool checksum,\n         uint64_t initial_offset);\n\n  Reader(const Reader&) = delete;\n  Reader& operator=(const Reader&) = delete;\n\n  ~Reader();\n\n  // Read the next record into *record.  Returns true if read\n  // successfully, false if we hit end of the input.  May use\n  // \"*scratch\" as temporary storage.  The contents filled in *record\n  // will only be valid until the next mutating operation on this\n  // reader or the next mutation to *scratch.\n  bool ReadRecord(Slice* record, std::string* scratch);\n\n  // Returns the physical offset of the last record returned by ReadRecord.\n  //\n  // Undefined before the first call to ReadRecord.\n  uint64_t LastRecordOffset();\n\n private:\n  // Extend record types with the following special values\n  enum {\n    kEof = kMaxRecordType + 1,\n    // Returned whenever we find an invalid physical record.\n    // Currently there are three situations in which this happens:\n    // * The record has an invalid CRC (ReadPhysicalRecord reports a drop)\n    // * The record is a 0-length record (No drop is reported)\n    // * The record is below constructor's initial_offset (No drop is reported)\n    kBadRecord = kMaxRecordType + 2\n  };\n\n  // Skips all blocks that are completely before \"initial_offset_\".\n  //\n  // Returns true on success. Handles reporting.\n  bool SkipToInitialBlock();\n\n  // Return type, or one of the preceding special values\n  unsigned int ReadPhysicalRecord(Slice* result);\n\n  // Reports dropped bytes to the reporter.\n  // buffer_ must be updated to remove the dropped bytes prior to invocation.\n  void ReportCorruption(uint64_t bytes, const char* reason);\n  void ReportDrop(uint64_t bytes, const Status& reason);\n\n  SequentialFile* const file_;\n  Reporter* const reporter_;\n  bool const checksum_;\n  char* const backing_store_;\n  Slice buffer_;\n  bool eof_;  // Last Read() indicated EOF by returning < kBlockSize\n\n  // Offset of the last record returned by ReadRecord.\n  uint64_t last_record_offset_;\n  // Offset of the first location past the end of buffer_.\n  uint64_t end_of_buffer_offset_;\n\n  // Offset at which to start looking for the first record to return\n  uint64_t const initial_offset_;\n\n  // True if we are resynchronizing after a seek (initial_offset_ > 0). In\n  // particular, a run of kMiddleType and kLastType records can be silently\n  // skipped in this mode\n  bool resyncing_;\n};\n\n}  // namespace log\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_LOG_READER_H_\n"
  },
  {
    "path": "src/leveldb/db/log_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/log_reader.h\"\n#include \"db/log_writer.h\"\n#include \"leveldb/env.h\"\n#include \"util/coding.h\"\n#include \"util/crc32c.h\"\n#include \"util/random.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\nnamespace log {\n\n// Construct a string of the specified length made out of the supplied\n// partial string.\nstatic std::string BigString(const std::string& partial_string, size_t n) {\n  std::string result;\n  while (result.size() < n) {\n    result.append(partial_string);\n  }\n  result.resize(n);\n  return result;\n}\n\n// Construct a string from a number\nstatic std::string NumberString(int n) {\n  char buf[50];\n  snprintf(buf, sizeof(buf), \"%d.\", n);\n  return std::string(buf);\n}\n\n// Return a skewed potentially long string\nstatic std::string RandomSkewedString(int i, Random* rnd) {\n  return BigString(NumberString(i), rnd->Skewed(17));\n}\n\nclass LogTest {\n public:\n  LogTest()\n      : reading_(false),\n        writer_(new Writer(&dest_)),\n        reader_(new Reader(&source_, &report_, true /*checksum*/,\n                           0 /*initial_offset*/)) {}\n\n  ~LogTest() {\n    delete writer_;\n    delete reader_;\n  }\n\n  void ReopenForAppend() {\n    delete writer_;\n    writer_ = new Writer(&dest_, dest_.contents_.size());\n  }\n\n  void Write(const std::string& msg) {\n    ASSERT_TRUE(!reading_) << \"Write() after starting to read\";\n    writer_->AddRecord(Slice(msg));\n  }\n\n  size_t WrittenBytes() const { return dest_.contents_.size(); }\n\n  std::string Read() {\n    if (!reading_) {\n      reading_ = true;\n      source_.contents_ = Slice(dest_.contents_);\n    }\n    std::string scratch;\n    Slice record;\n    if (reader_->ReadRecord(&record, &scratch)) {\n      return record.ToString();\n    } else {\n      return \"EOF\";\n    }\n  }\n\n  void IncrementByte(int offset, int delta) {\n    dest_.contents_[offset] += delta;\n  }\n\n  void SetByte(int offset, char new_byte) {\n    dest_.contents_[offset] = new_byte;\n  }\n\n  void ShrinkSize(int bytes) {\n    dest_.contents_.resize(dest_.contents_.size() - bytes);\n  }\n\n  void FixChecksum(int header_offset, int len) {\n    // Compute crc of type/len/data\n    uint32_t crc = crc32c::Value(&dest_.contents_[header_offset + 6], 1 + len);\n    crc = crc32c::Mask(crc);\n    EncodeFixed32(&dest_.contents_[header_offset], crc);\n  }\n\n  void ForceError() { source_.force_error_ = true; }\n\n  size_t DroppedBytes() const { return report_.dropped_bytes_; }\n\n  std::string ReportMessage() const { return report_.message_; }\n\n  // Returns OK iff recorded error message contains \"msg\"\n  std::string MatchError(const std::string& msg) const {\n    if (report_.message_.find(msg) == std::string::npos) {\n      return report_.message_;\n    } else {\n      return \"OK\";\n    }\n  }\n\n  void WriteInitialOffsetLog() {\n    for (int i = 0; i < num_initial_offset_records_; i++) {\n      std::string record(initial_offset_record_sizes_[i],\n                         static_cast<char>('a' + i));\n      Write(record);\n    }\n  }\n\n  void StartReadingAt(uint64_t initial_offset) {\n    delete reader_;\n    reader_ = new Reader(&source_, &report_, true /*checksum*/, initial_offset);\n  }\n\n  void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) {\n    WriteInitialOffsetLog();\n    reading_ = true;\n    source_.contents_ = Slice(dest_.contents_);\n    Reader* offset_reader = new Reader(&source_, &report_, true /*checksum*/,\n                                       WrittenBytes() + offset_past_end);\n    Slice record;\n    std::string scratch;\n    ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch));\n    delete offset_reader;\n  }\n\n  void CheckInitialOffsetRecord(uint64_t initial_offset,\n                                int expected_record_offset) {\n    WriteInitialOffsetLog();\n    reading_ = true;\n    source_.contents_ = Slice(dest_.contents_);\n    Reader* offset_reader =\n        new Reader(&source_, &report_, true /*checksum*/, initial_offset);\n\n    // Read all records from expected_record_offset through the last one.\n    ASSERT_LT(expected_record_offset, num_initial_offset_records_);\n    for (; expected_record_offset < num_initial_offset_records_;\n         ++expected_record_offset) {\n      Slice record;\n      std::string scratch;\n      ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch));\n      ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset],\n                record.size());\n      ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset],\n                offset_reader->LastRecordOffset());\n      ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]);\n    }\n    delete offset_reader;\n  }\n\n private:\n  class StringDest : public WritableFile {\n   public:\n    Status Close() override { return Status::OK(); }\n    Status Flush() override { return Status::OK(); }\n    Status Sync() override { return Status::OK(); }\n    Status Append(const Slice& slice) override {\n      contents_.append(slice.data(), slice.size());\n      return Status::OK();\n    }\n    std::string GetName() const override { return \"\"; }\n\n    std::string contents_;\n  };\n\n  class StringSource : public SequentialFile {\n   public:\n    StringSource() : force_error_(false), returned_partial_(false) {}\n\n    Status Read(size_t n, Slice* result, char* scratch) override {\n      ASSERT_TRUE(!returned_partial_) << \"must not Read() after eof/error\";\n\n      if (force_error_) {\n        force_error_ = false;\n        returned_partial_ = true;\n        return Status::Corruption(\"read error\");\n      }\n\n      if (contents_.size() < n) {\n        n = contents_.size();\n        returned_partial_ = true;\n      }\n      *result = Slice(contents_.data(), n);\n      contents_.remove_prefix(n);\n      return Status::OK();\n    }\n\n    Status Skip(uint64_t n) override {\n      if (n > contents_.size()) {\n        contents_.clear();\n        return Status::NotFound(\"in-memory file skipped past end\");\n      }\n\n      contents_.remove_prefix(n);\n\n      return Status::OK();\n    }\n    std::string GetName() const { return \"\"; }\n\n    Slice contents_;\n    bool force_error_;\n    bool returned_partial_;\n  };\n\n  class ReportCollector : public Reader::Reporter {\n   public:\n    ReportCollector() : dropped_bytes_(0) {}\n    void Corruption(size_t bytes, const Status& status) override {\n      dropped_bytes_ += bytes;\n      message_.append(status.ToString());\n    }\n\n    size_t dropped_bytes_;\n    std::string message_;\n  };\n\n  // Record metadata for testing initial offset functionality\n  static size_t initial_offset_record_sizes_[];\n  static uint64_t initial_offset_last_record_offsets_[];\n  static int num_initial_offset_records_;\n\n  StringDest dest_;\n  StringSource source_;\n  ReportCollector report_;\n  bool reading_;\n  Writer* writer_;\n  Reader* reader_;\n};\n\nsize_t LogTest::initial_offset_record_sizes_[] = {\n    10000,  // Two sizable records in first block\n    10000,\n    2 * log::kBlockSize - 1000,  // Span three blocks\n    1,\n    13716,                          // Consume all but two bytes of block 3.\n    log::kBlockSize - kHeaderSize,  // Consume the entirety of block 4.\n};\n\nuint64_t LogTest::initial_offset_last_record_offsets_[] = {\n    0,\n    kHeaderSize + 10000,\n    2 * (kHeaderSize + 10000),\n    2 * (kHeaderSize + 10000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize,\n    2 * (kHeaderSize + 10000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize +\n        kHeaderSize + 1,\n    3 * log::kBlockSize,\n};\n\n// LogTest::initial_offset_last_record_offsets_ must be defined before this.\nint LogTest::num_initial_offset_records_ =\n    sizeof(LogTest::initial_offset_last_record_offsets_) / sizeof(uint64_t);\n\nTEST(LogTest, Empty) { ASSERT_EQ(\"EOF\", Read()); }\n\nTEST(LogTest, ReadWrite) {\n  Write(\"foo\");\n  Write(\"bar\");\n  Write(\"\");\n  Write(\"xxxx\");\n  ASSERT_EQ(\"foo\", Read());\n  ASSERT_EQ(\"bar\", Read());\n  ASSERT_EQ(\"\", Read());\n  ASSERT_EQ(\"xxxx\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(\"EOF\", Read());  // Make sure reads at eof work\n}\n\nTEST(LogTest, ManyBlocks) {\n  for (int i = 0; i < 100000; i++) {\n    Write(NumberString(i));\n  }\n  for (int i = 0; i < 100000; i++) {\n    ASSERT_EQ(NumberString(i), Read());\n  }\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, Fragmentation) {\n  Write(\"small\");\n  Write(BigString(\"medium\", 50000));\n  Write(BigString(\"large\", 100000));\n  ASSERT_EQ(\"small\", Read());\n  ASSERT_EQ(BigString(\"medium\", 50000), Read());\n  ASSERT_EQ(BigString(\"large\", 100000), Read());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, MarginalTrailer) {\n  // Make a trailer that is exactly the same length as an empty record.\n  const int n = kBlockSize - 2 * kHeaderSize;\n  Write(BigString(\"foo\", n));\n  ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());\n  Write(\"\");\n  Write(\"bar\");\n  ASSERT_EQ(BigString(\"foo\", n), Read());\n  ASSERT_EQ(\"\", Read());\n  ASSERT_EQ(\"bar\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, MarginalTrailer2) {\n  // Make a trailer that is exactly the same length as an empty record.\n  const int n = kBlockSize - 2 * kHeaderSize;\n  Write(BigString(\"foo\", n));\n  ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());\n  Write(\"bar\");\n  ASSERT_EQ(BigString(\"foo\", n), Read());\n  ASSERT_EQ(\"bar\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(0, DroppedBytes());\n  ASSERT_EQ(\"\", ReportMessage());\n}\n\nTEST(LogTest, ShortTrailer) {\n  const int n = kBlockSize - 2 * kHeaderSize + 4;\n  Write(BigString(\"foo\", n));\n  ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());\n  Write(\"\");\n  Write(\"bar\");\n  ASSERT_EQ(BigString(\"foo\", n), Read());\n  ASSERT_EQ(\"\", Read());\n  ASSERT_EQ(\"bar\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, AlignedEof) {\n  const int n = kBlockSize - 2 * kHeaderSize + 4;\n  Write(BigString(\"foo\", n));\n  ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());\n  ASSERT_EQ(BigString(\"foo\", n), Read());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, OpenForAppend) {\n  Write(\"hello\");\n  ReopenForAppend();\n  Write(\"world\");\n  ASSERT_EQ(\"hello\", Read());\n  ASSERT_EQ(\"world\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, RandomRead) {\n  const int N = 500;\n  Random write_rnd(301);\n  for (int i = 0; i < N; i++) {\n    Write(RandomSkewedString(i, &write_rnd));\n  }\n  Random read_rnd(301);\n  for (int i = 0; i < N; i++) {\n    ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read());\n  }\n  ASSERT_EQ(\"EOF\", Read());\n}\n\n// Tests of all the error paths in log_reader.cc follow:\n\nTEST(LogTest, ReadError) {\n  Write(\"foo\");\n  ForceError();\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(kBlockSize, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"read error\"));\n}\n\nTEST(LogTest, BadRecordType) {\n  Write(\"foo\");\n  // Type is stored in header[6]\n  IncrementByte(6, 100);\n  FixChecksum(0, 3);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(3, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"unknown record type\"));\n}\n\nTEST(LogTest, TruncatedTrailingRecordIsIgnored) {\n  Write(\"foo\");\n  ShrinkSize(4);  // Drop all payload as well as a header byte\n  ASSERT_EQ(\"EOF\", Read());\n  // Truncated last record is ignored, not treated as an error.\n  ASSERT_EQ(0, DroppedBytes());\n  ASSERT_EQ(\"\", ReportMessage());\n}\n\nTEST(LogTest, BadLength) {\n  const int kPayloadSize = kBlockSize - kHeaderSize;\n  Write(BigString(\"bar\", kPayloadSize));\n  Write(\"foo\");\n  // Least significant size byte is stored in header[4].\n  IncrementByte(4, 1);\n  ASSERT_EQ(\"foo\", Read());\n  ASSERT_EQ(kBlockSize, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"bad record length\"));\n}\n\nTEST(LogTest, BadLengthAtEndIsIgnored) {\n  Write(\"foo\");\n  ShrinkSize(1);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(0, DroppedBytes());\n  ASSERT_EQ(\"\", ReportMessage());\n}\n\nTEST(LogTest, ChecksumMismatch) {\n  Write(\"foo\");\n  IncrementByte(0, 10);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(10, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"checksum mismatch\"));\n}\n\nTEST(LogTest, UnexpectedMiddleType) {\n  Write(\"foo\");\n  SetByte(6, kMiddleType);\n  FixChecksum(0, 3);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(3, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"missing start\"));\n}\n\nTEST(LogTest, UnexpectedLastType) {\n  Write(\"foo\");\n  SetByte(6, kLastType);\n  FixChecksum(0, 3);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(3, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"missing start\"));\n}\n\nTEST(LogTest, UnexpectedFullType) {\n  Write(\"foo\");\n  Write(\"bar\");\n  SetByte(6, kFirstType);\n  FixChecksum(0, 3);\n  ASSERT_EQ(\"bar\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(3, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"partial record without end\"));\n}\n\nTEST(LogTest, UnexpectedFirstType) {\n  Write(\"foo\");\n  Write(BigString(\"bar\", 100000));\n  SetByte(6, kFirstType);\n  FixChecksum(0, 3);\n  ASSERT_EQ(BigString(\"bar\", 100000), Read());\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(3, DroppedBytes());\n  ASSERT_EQ(\"OK\", MatchError(\"partial record without end\"));\n}\n\nTEST(LogTest, MissingLastIsIgnored) {\n  Write(BigString(\"bar\", kBlockSize));\n  // Remove the LAST block, including header.\n  ShrinkSize(14);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(\"\", ReportMessage());\n  ASSERT_EQ(0, DroppedBytes());\n}\n\nTEST(LogTest, PartialLastIsIgnored) {\n  Write(BigString(\"bar\", kBlockSize));\n  // Cause a bad record length in the LAST block.\n  ShrinkSize(1);\n  ASSERT_EQ(\"EOF\", Read());\n  ASSERT_EQ(\"\", ReportMessage());\n  ASSERT_EQ(0, DroppedBytes());\n}\n\nTEST(LogTest, SkipIntoMultiRecord) {\n  // Consider a fragmented record:\n  //    first(R1), middle(R1), last(R1), first(R2)\n  // If initial_offset points to a record after first(R1) but before first(R2)\n  // incomplete fragment errors are not actual errors, and must be suppressed\n  // until a new first or full record is encountered.\n  Write(BigString(\"foo\", 3 * kBlockSize));\n  Write(\"correct\");\n  StartReadingAt(kBlockSize);\n\n  ASSERT_EQ(\"correct\", Read());\n  ASSERT_EQ(\"\", ReportMessage());\n  ASSERT_EQ(0, DroppedBytes());\n  ASSERT_EQ(\"EOF\", Read());\n}\n\nTEST(LogTest, ErrorJoinsRecords) {\n  // Consider two fragmented records:\n  //    first(R1) last(R1) first(R2) last(R2)\n  // where the middle two fragments disappear.  We do not want\n  // first(R1),last(R2) to get joined and returned as a valid record.\n\n  // Write records that span two blocks\n  Write(BigString(\"foo\", kBlockSize));\n  Write(BigString(\"bar\", kBlockSize));\n  Write(\"correct\");\n\n  // Wipe the middle block\n  for (int offset = kBlockSize; offset < 2 * kBlockSize; offset++) {\n    SetByte(offset, 'x');\n  }\n\n  ASSERT_EQ(\"correct\", Read());\n  ASSERT_EQ(\"EOF\", Read());\n  const size_t dropped = DroppedBytes();\n  ASSERT_LE(dropped, 2 * kBlockSize + 100);\n  ASSERT_GE(dropped, 2 * kBlockSize);\n}\n\nTEST(LogTest, ReadStart) { CheckInitialOffsetRecord(0, 0); }\n\nTEST(LogTest, ReadSecondOneOff) { CheckInitialOffsetRecord(1, 1); }\n\nTEST(LogTest, ReadSecondTenThousand) { CheckInitialOffsetRecord(10000, 1); }\n\nTEST(LogTest, ReadSecondStart) { CheckInitialOffsetRecord(10007, 1); }\n\nTEST(LogTest, ReadThirdOneOff) { CheckInitialOffsetRecord(10008, 2); }\n\nTEST(LogTest, ReadThirdStart) { CheckInitialOffsetRecord(20014, 2); }\n\nTEST(LogTest, ReadFourthOneOff) { CheckInitialOffsetRecord(20015, 3); }\n\nTEST(LogTest, ReadFourthFirstBlockTrailer) {\n  CheckInitialOffsetRecord(log::kBlockSize - 4, 3);\n}\n\nTEST(LogTest, ReadFourthMiddleBlock) {\n  CheckInitialOffsetRecord(log::kBlockSize + 1, 3);\n}\n\nTEST(LogTest, ReadFourthLastBlock) {\n  CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3);\n}\n\nTEST(LogTest, ReadFourthStart) {\n  CheckInitialOffsetRecord(\n      2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize,\n      3);\n}\n\nTEST(LogTest, ReadInitialOffsetIntoBlockPadding) {\n  CheckInitialOffsetRecord(3 * log::kBlockSize - 3, 5);\n}\n\nTEST(LogTest, ReadEnd) { CheckOffsetPastEndReturnsNoRecords(0); }\n\nTEST(LogTest, ReadPastEnd) { CheckOffsetPastEndReturnsNoRecords(5); }\n\n}  // namespace log\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/log_writer.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/log_writer.h\"\n\n#include <stdint.h>\n\n#include \"leveldb/env.h\"\n#include \"util/coding.h\"\n#include \"util/crc32c.h\"\n\nnamespace leveldb {\nnamespace log {\n\nstatic void InitTypeCrc(uint32_t* type_crc) {\n  for (int i = 0; i <= kMaxRecordType; i++) {\n    char t = static_cast<char>(i);\n    type_crc[i] = crc32c::Value(&t, 1);\n  }\n}\n\nWriter::Writer(WritableFile* dest) : dest_(dest), block_offset_(0) {\n  InitTypeCrc(type_crc_);\n}\n\nWriter::Writer(WritableFile* dest, uint64_t dest_length)\n    : dest_(dest), block_offset_(dest_length % kBlockSize) {\n  InitTypeCrc(type_crc_);\n}\n\nWriter::~Writer() = default;\n\nStatus Writer::AddRecord(const Slice& slice) {\n  const char* ptr = slice.data();\n  size_t left = slice.size();\n\n  // Fragment the record if necessary and emit it.  Note that if slice\n  // is empty, we still want to iterate once to emit a single\n  // zero-length record\n  Status s;\n  bool begin = true;\n  do {\n    const int leftover = kBlockSize - block_offset_;\n    assert(leftover >= 0);\n    if (leftover < kHeaderSize) {\n      // Switch to a new block\n      if (leftover > 0) {\n        // Fill the trailer (literal below relies on kHeaderSize being 7)\n        static_assert(kHeaderSize == 7, \"\");\n        dest_->Append(Slice(\"\\x00\\x00\\x00\\x00\\x00\\x00\", leftover));\n      }\n      block_offset_ = 0;\n    }\n\n    // Invariant: we never leave < kHeaderSize bytes in a block.\n    assert(kBlockSize - block_offset_ - kHeaderSize >= 0);\n\n    const size_t avail = kBlockSize - block_offset_ - kHeaderSize;\n    const size_t fragment_length = (left < avail) ? left : avail;\n\n    RecordType type;\n    const bool end = (left == fragment_length);\n    if (begin && end) {\n      type = kFullType;\n    } else if (begin) {\n      type = kFirstType;\n    } else if (end) {\n      type = kLastType;\n    } else {\n      type = kMiddleType;\n    }\n\n    s = EmitPhysicalRecord(type, ptr, fragment_length);\n    ptr += fragment_length;\n    left -= fragment_length;\n    begin = false;\n  } while (s.ok() && left > 0);\n  return s;\n}\n\nStatus Writer::EmitPhysicalRecord(RecordType t, const char* ptr,\n                                  size_t length) {\n  assert(length <= 0xffff);  // Must fit in two bytes\n  assert(block_offset_ + kHeaderSize + length <= kBlockSize);\n\n  // Format the header\n  char buf[kHeaderSize];\n  buf[4] = static_cast<char>(length & 0xff);\n  buf[5] = static_cast<char>(length >> 8);\n  buf[6] = static_cast<char>(t);\n\n  // Compute the crc of the record type and the payload.\n  uint32_t crc = crc32c::Extend(type_crc_[t], ptr, length);\n  crc = crc32c::Mask(crc);  // Adjust for storage\n  EncodeFixed32(buf, crc);\n\n  // Write the header and the payload\n  Status s = dest_->Append(Slice(buf, kHeaderSize));\n  if (s.ok()) {\n    s = dest_->Append(Slice(ptr, length));\n    if (s.ok()) {\n      s = dest_->Flush();\n    }\n  }\n  block_offset_ += kHeaderSize + length;\n  return s;\n}\n\n}  // namespace log\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/log_writer.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_\n#define STORAGE_LEVELDB_DB_LOG_WRITER_H_\n\n#include <stdint.h>\n\n#include \"db/log_format.h\"\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nclass WritableFile;\n\nnamespace log {\n\nclass Writer {\n public:\n  // Create a writer that will append data to \"*dest\".\n  // \"*dest\" must be initially empty.\n  // \"*dest\" must remain live while this Writer is in use.\n  explicit Writer(WritableFile* dest);\n\n  // Create a writer that will append data to \"*dest\".\n  // \"*dest\" must have initial length \"dest_length\".\n  // \"*dest\" must remain live while this Writer is in use.\n  Writer(WritableFile* dest, uint64_t dest_length);\n\n  Writer(const Writer&) = delete;\n  Writer& operator=(const Writer&) = delete;\n\n  ~Writer();\n\n  Status AddRecord(const Slice& slice);\n\n private:\n  Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length);\n\n  WritableFile* dest_;\n  int block_offset_;  // Current offset in block\n\n  // crc32c values for all supported record types.  These are\n  // pre-computed to reduce the overhead of computing the crc of the\n  // record type stored in the header.\n  uint32_t type_crc_[kMaxRecordType + 1];\n};\n\n}  // namespace log\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_LOG_WRITER_H_\n"
  },
  {
    "path": "src/leveldb/db/memtable.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/memtable.h\"\n#include \"db/dbformat.h\"\n#include \"leveldb/comparator.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/iterator.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nstatic Slice GetLengthPrefixedSlice(const char* data) {\n  uint32_t len;\n  const char* p = data;\n  p = GetVarint32Ptr(p, p + 5, &len);  // +5: we assume \"p\" is not corrupted\n  return Slice(p, len);\n}\n\nMemTable::MemTable(const InternalKeyComparator& comparator)\n    : comparator_(comparator), refs_(0), table_(comparator_, &arena_) {}\n\nMemTable::~MemTable() { assert(refs_ == 0); }\n\nsize_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); }\n\nint MemTable::KeyComparator::operator()(const char* aptr,\n                                        const char* bptr) const {\n  // Internal keys are encoded as length-prefixed strings.\n  Slice a = GetLengthPrefixedSlice(aptr);\n  Slice b = GetLengthPrefixedSlice(bptr);\n  return comparator.Compare(a, b);\n}\n\n// Encode a suitable internal key target for \"target\" and return it.\n// Uses *scratch as scratch space, and the returned pointer will point\n// into this scratch space.\nstatic const char* EncodeKey(std::string* scratch, const Slice& target) {\n  scratch->clear();\n  PutVarint32(scratch, target.size());\n  scratch->append(target.data(), target.size());\n  return scratch->data();\n}\n\nclass MemTableIterator : public Iterator {\n public:\n  explicit MemTableIterator(MemTable::Table* table) : iter_(table) {}\n\n  MemTableIterator(const MemTableIterator&) = delete;\n  MemTableIterator& operator=(const MemTableIterator&) = delete;\n\n  ~MemTableIterator() override = default;\n\n  bool Valid() const override { return iter_.Valid(); }\n  void Seek(const Slice& k) override { iter_.Seek(EncodeKey(&tmp_, k)); }\n  void SeekToFirst() override { iter_.SeekToFirst(); }\n  void SeekToLast() override { iter_.SeekToLast(); }\n  void Next() override { iter_.Next(); }\n  void Prev() override { iter_.Prev(); }\n  Slice key() const override { return GetLengthPrefixedSlice(iter_.key()); }\n  Slice value() const override {\n    Slice key_slice = GetLengthPrefixedSlice(iter_.key());\n    return GetLengthPrefixedSlice(key_slice.data() + key_slice.size());\n  }\n\n  Status status() const override { return Status::OK(); }\n\n private:\n  MemTable::Table::Iterator iter_;\n  std::string tmp_;  // For passing to EncodeKey\n};\n\nIterator* MemTable::NewIterator() { return new MemTableIterator(&table_); }\n\nvoid MemTable::Add(SequenceNumber s, ValueType type, const Slice& key,\n                   const Slice& value) {\n  // Format of an entry is concatenation of:\n  //  key_size     : varint32 of internal_key.size()\n  //  key bytes    : char[internal_key.size()]\n  //  value_size   : varint32 of value.size()\n  //  value bytes  : char[value.size()]\n  size_t key_size = key.size();\n  size_t val_size = value.size();\n  size_t internal_key_size = key_size + 8;\n  const size_t encoded_len = VarintLength(internal_key_size) +\n                             internal_key_size + VarintLength(val_size) +\n                             val_size;\n  char* buf = arena_.Allocate(encoded_len);\n  char* p = EncodeVarint32(buf, internal_key_size);\n  memcpy(p, key.data(), key_size);\n  p += key_size;\n  EncodeFixed64(p, (s << 8) | type);\n  p += 8;\n  p = EncodeVarint32(p, val_size);\n  memcpy(p, value.data(), val_size);\n  assert(p + val_size == buf + encoded_len);\n  table_.Insert(buf);\n}\n\nbool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {\n  Slice memkey = key.memtable_key();\n  Table::Iterator iter(&table_);\n  iter.Seek(memkey.data());\n  if (iter.Valid()) {\n    // entry format is:\n    //    klength  varint32\n    //    userkey  char[klength]\n    //    tag      uint64\n    //    vlength  varint32\n    //    value    char[vlength]\n    // Check that it belongs to same user key.  We do not check the\n    // sequence number since the Seek() call above should have skipped\n    // all entries with overly large sequence numbers.\n    const char* entry = iter.key();\n    uint32_t key_length;\n    const char* key_ptr = GetVarint32Ptr(entry, entry + 5, &key_length);\n    if (comparator_.comparator.user_comparator()->Compare(\n            Slice(key_ptr, key_length - 8), key.user_key()) == 0) {\n      // Correct user key\n      const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);\n      switch (static_cast<ValueType>(tag & 0xff)) {\n        case kTypeValue: {\n          Slice v = GetLengthPrefixedSlice(key_ptr + key_length);\n          value->assign(v.data(), v.size());\n          return true;\n        }\n        case kTypeDeletion:\n          *s = Status::NotFound(Slice());\n          return true;\n      }\n    }\n  }\n  return false;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/memtable.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_\n#define STORAGE_LEVELDB_DB_MEMTABLE_H_\n\n#include <string>\n\n#include \"db/dbformat.h\"\n#include \"db/skiplist.h\"\n#include \"leveldb/db.h\"\n#include \"util/arena.h\"\n\nnamespace leveldb {\n\nclass InternalKeyComparator;\nclass MemTableIterator;\n\nclass MemTable {\n public:\n  // MemTables are reference counted.  The initial reference count\n  // is zero and the caller must call Ref() at least once.\n  explicit MemTable(const InternalKeyComparator& comparator);\n\n  MemTable(const MemTable&) = delete;\n  MemTable& operator=(const MemTable&) = delete;\n\n  // Increase reference count.\n  void Ref() { ++refs_; }\n\n  // Drop reference count.  Delete if no more references exist.\n  void Unref() {\n    --refs_;\n    assert(refs_ >= 0);\n    if (refs_ <= 0) {\n      delete this;\n    }\n  }\n\n  // Returns an estimate of the number of bytes of data in use by this\n  // data structure. It is safe to call when MemTable is being modified.\n  size_t ApproximateMemoryUsage();\n\n  // Return an iterator that yields the contents of the memtable.\n  //\n  // The caller must ensure that the underlying MemTable remains live\n  // while the returned iterator is live.  The keys returned by this\n  // iterator are internal keys encoded by AppendInternalKey in the\n  // db/format.{h,cc} module.\n  Iterator* NewIterator();\n\n  // Add an entry into memtable that maps key to value at the\n  // specified sequence number and with the specified type.\n  // Typically value will be empty if type==kTypeDeletion.\n  void Add(SequenceNumber seq, ValueType type, const Slice& key,\n           const Slice& value);\n\n  // If memtable contains a value for key, store it in *value and return true.\n  // If memtable contains a deletion for key, store a NotFound() error\n  // in *status and return true.\n  // Else, return false.\n  bool Get(const LookupKey& key, std::string* value, Status* s);\n\n private:\n  friend class MemTableIterator;\n  friend class MemTableBackwardIterator;\n\n  struct KeyComparator {\n    const InternalKeyComparator comparator;\n    explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) {}\n    int operator()(const char* a, const char* b) const;\n  };\n\n  typedef SkipList<const char*, KeyComparator> Table;\n\n  ~MemTable();  // Private since only Unref() should be used to delete it\n\n  KeyComparator comparator_;\n  int refs_;\n  Arena arena_;\n  Table table_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_MEMTABLE_H_\n"
  },
  {
    "path": "src/leveldb/db/recovery_test.cc",
    "content": "// Copyright (c) 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/db_impl.h\"\n#include \"db/filename.h\"\n#include \"db/version_set.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/write_batch.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nclass RecoveryTest {\n public:\n  RecoveryTest() : env_(Env::Default()), db_(nullptr) {\n    dbname_ = test::TmpDir() + \"/recovery_test\";\n    DestroyDB(dbname_, Options());\n    Open();\n  }\n\n  ~RecoveryTest() {\n    Close();\n    DestroyDB(dbname_, Options());\n  }\n\n  DBImpl* dbfull() const { return reinterpret_cast<DBImpl*>(db_); }\n  Env* env() const { return env_; }\n\n  bool CanAppend() {\n    WritableFile* tmp;\n    Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp);\n    delete tmp;\n    if (s.IsNotSupportedError()) {\n      return false;\n    } else {\n      return true;\n    }\n  }\n\n  void Close() {\n    delete db_;\n    db_ = nullptr;\n  }\n\n  Status OpenWithStatus(Options* options = nullptr) {\n    Close();\n    Options opts;\n    if (options != nullptr) {\n      opts = *options;\n    } else {\n      opts.reuse_logs = true;  // TODO(sanjay): test both ways\n      opts.create_if_missing = true;\n    }\n    if (opts.env == nullptr) {\n      opts.env = env_;\n    }\n    return DB::Open(opts, dbname_, &db_);\n  }\n\n  void Open(Options* options = nullptr) {\n    ASSERT_OK(OpenWithStatus(options));\n    ASSERT_EQ(1, NumLogs());\n  }\n\n  Status Put(const std::string& k, const std::string& v) {\n    return db_->Put(WriteOptions(), k, v);\n  }\n\n  std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {\n    std::string result;\n    Status s = db_->Get(ReadOptions(), k, &result);\n    if (s.IsNotFound()) {\n      result = \"NOT_FOUND\";\n    } else if (!s.ok()) {\n      result = s.ToString();\n    }\n    return result;\n  }\n\n  std::string ManifestFileName() {\n    std::string current;\n    ASSERT_OK(ReadFileToString(env_, CurrentFileName(dbname_), &current));\n    size_t len = current.size();\n    if (len > 0 && current[len - 1] == '\\n') {\n      current.resize(len - 1);\n    }\n    return dbname_ + \"/\" + current;\n  }\n\n  std::string LogName(uint64_t number) { return LogFileName(dbname_, number); }\n\n  size_t DeleteLogFiles() {\n    // Linux allows unlinking open files, but Windows does not.\n    // Closing the db allows for file deletion.\n    Close();\n    std::vector<uint64_t> logs = GetFiles(kLogFile);\n    for (size_t i = 0; i < logs.size(); i++) {\n      ASSERT_OK(env_->DeleteFile(LogName(logs[i]))) << LogName(logs[i]);\n    }\n    return logs.size();\n  }\n\n  void DeleteManifestFile() { ASSERT_OK(env_->DeleteFile(ManifestFileName())); }\n\n  uint64_t FirstLogFile() { return GetFiles(kLogFile)[0]; }\n\n  std::vector<uint64_t> GetFiles(FileType t) {\n    std::vector<std::string> filenames;\n    ASSERT_OK(env_->GetChildren(dbname_, &filenames));\n    std::vector<uint64_t> result;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      uint64_t number;\n      FileType type;\n      if (ParseFileName(filenames[i], &number, &type) && type == t) {\n        result.push_back(number);\n      }\n    }\n    return result;\n  }\n\n  int NumLogs() { return GetFiles(kLogFile).size(); }\n\n  int NumTables() { return GetFiles(kTableFile).size(); }\n\n  uint64_t FileSize(const std::string& fname) {\n    uint64_t result;\n    ASSERT_OK(env_->GetFileSize(fname, &result)) << fname;\n    return result;\n  }\n\n  void CompactMemTable() { dbfull()->TEST_CompactMemTable(); }\n\n  // Directly construct a log file that sets key to val.\n  void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) {\n    std::string fname = LogFileName(dbname_, lognum);\n    WritableFile* file;\n    ASSERT_OK(env_->NewWritableFile(fname, &file));\n    log::Writer writer(file);\n    WriteBatch batch;\n    batch.Put(key, val);\n    WriteBatchInternal::SetSequence(&batch, seq);\n    ASSERT_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch)));\n    ASSERT_OK(file->Flush());\n    delete file;\n  }\n\n private:\n  std::string dbname_;\n  Env* env_;\n  DB* db_;\n};\n\nTEST(RecoveryTest, ManifestReused) {\n  if (!CanAppend()) {\n    fprintf(stderr, \"skipping test because env does not support appending\\n\");\n    return;\n  }\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  Close();\n  std::string old_manifest = ManifestFileName();\n  Open();\n  ASSERT_EQ(old_manifest, ManifestFileName());\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n  Open();\n  ASSERT_EQ(old_manifest, ManifestFileName());\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n}\n\nTEST(RecoveryTest, LargeManifestCompacted) {\n  if (!CanAppend()) {\n    fprintf(stderr, \"skipping test because env does not support appending\\n\");\n    return;\n  }\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  Close();\n  std::string old_manifest = ManifestFileName();\n\n  // Pad with zeroes to make manifest file very big.\n  {\n    uint64_t len = FileSize(old_manifest);\n    WritableFile* file;\n    ASSERT_OK(env()->NewAppendableFile(old_manifest, &file));\n    std::string zeroes(3 * 1048576 - static_cast<size_t>(len), 0);\n    ASSERT_OK(file->Append(zeroes));\n    ASSERT_OK(file->Flush());\n    delete file;\n  }\n\n  Open();\n  std::string new_manifest = ManifestFileName();\n  ASSERT_NE(old_manifest, new_manifest);\n  ASSERT_GT(10000, FileSize(new_manifest));\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n\n  Open();\n  ASSERT_EQ(new_manifest, ManifestFileName());\n  ASSERT_EQ(\"bar\", Get(\"foo\"));\n}\n\nTEST(RecoveryTest, NoLogFiles) {\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  ASSERT_EQ(1, DeleteLogFiles());\n  Open();\n  ASSERT_EQ(\"NOT_FOUND\", Get(\"foo\"));\n  Open();\n  ASSERT_EQ(\"NOT_FOUND\", Get(\"foo\"));\n}\n\nTEST(RecoveryTest, LogFileReuse) {\n  if (!CanAppend()) {\n    fprintf(stderr, \"skipping test because env does not support appending\\n\");\n    return;\n  }\n  for (int i = 0; i < 2; i++) {\n    ASSERT_OK(Put(\"foo\", \"bar\"));\n    if (i == 0) {\n      // Compact to ensure current log is empty\n      CompactMemTable();\n    }\n    Close();\n    ASSERT_EQ(1, NumLogs());\n    uint64_t number = FirstLogFile();\n    if (i == 0) {\n      ASSERT_EQ(0, FileSize(LogName(number)));\n    } else {\n      ASSERT_LT(0, FileSize(LogName(number)));\n    }\n    Open();\n    ASSERT_EQ(1, NumLogs());\n    ASSERT_EQ(number, FirstLogFile()) << \"did not reuse log file\";\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n    Open();\n    ASSERT_EQ(1, NumLogs());\n    ASSERT_EQ(number, FirstLogFile()) << \"did not reuse log file\";\n    ASSERT_EQ(\"bar\", Get(\"foo\"));\n  }\n}\n\nTEST(RecoveryTest, MultipleMemTables) {\n  // Make a large log.\n  const int kNum = 1000;\n  for (int i = 0; i < kNum; i++) {\n    char buf[100];\n    snprintf(buf, sizeof(buf), \"%050d\", i);\n    ASSERT_OK(Put(buf, buf));\n  }\n  ASSERT_EQ(0, NumTables());\n  Close();\n  ASSERT_EQ(0, NumTables());\n  ASSERT_EQ(1, NumLogs());\n  uint64_t old_log_file = FirstLogFile();\n\n  // Force creation of multiple memtables by reducing the write buffer size.\n  Options opt;\n  opt.reuse_logs = true;\n  opt.write_buffer_size = (kNum * 100) / 2;\n  Open(&opt);\n  ASSERT_LE(2, NumTables());\n  ASSERT_EQ(1, NumLogs());\n  ASSERT_NE(old_log_file, FirstLogFile()) << \"must not reuse log\";\n  for (int i = 0; i < kNum; i++) {\n    char buf[100];\n    snprintf(buf, sizeof(buf), \"%050d\", i);\n    ASSERT_EQ(buf, Get(buf));\n  }\n}\n\nTEST(RecoveryTest, MultipleLogFiles) {\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  Close();\n  ASSERT_EQ(1, NumLogs());\n\n  // Make a bunch of uncompacted log files.\n  uint64_t old_log = FirstLogFile();\n  MakeLogFile(old_log + 1, 1000, \"hello\", \"world\");\n  MakeLogFile(old_log + 2, 1001, \"hi\", \"there\");\n  MakeLogFile(old_log + 3, 1002, \"foo\", \"bar2\");\n\n  // Recover and check that all log files were processed.\n  Open();\n  ASSERT_LE(1, NumTables());\n  ASSERT_EQ(1, NumLogs());\n  uint64_t new_log = FirstLogFile();\n  ASSERT_LE(old_log + 3, new_log);\n  ASSERT_EQ(\"bar2\", Get(\"foo\"));\n  ASSERT_EQ(\"world\", Get(\"hello\"));\n  ASSERT_EQ(\"there\", Get(\"hi\"));\n\n  // Test that previous recovery produced recoverable state.\n  Open();\n  ASSERT_LE(1, NumTables());\n  ASSERT_EQ(1, NumLogs());\n  if (CanAppend()) {\n    ASSERT_EQ(new_log, FirstLogFile());\n  }\n  ASSERT_EQ(\"bar2\", Get(\"foo\"));\n  ASSERT_EQ(\"world\", Get(\"hello\"));\n  ASSERT_EQ(\"there\", Get(\"hi\"));\n\n  // Check that introducing an older log file does not cause it to be re-read.\n  Close();\n  MakeLogFile(old_log + 1, 2000, \"hello\", \"stale write\");\n  Open();\n  ASSERT_LE(1, NumTables());\n  ASSERT_EQ(1, NumLogs());\n  if (CanAppend()) {\n    ASSERT_EQ(new_log, FirstLogFile());\n  }\n  ASSERT_EQ(\"bar2\", Get(\"foo\"));\n  ASSERT_EQ(\"world\", Get(\"hello\"));\n  ASSERT_EQ(\"there\", Get(\"hi\"));\n}\n\nTEST(RecoveryTest, ManifestMissing) {\n  ASSERT_OK(Put(\"foo\", \"bar\"));\n  Close();\n  DeleteManifestFile();\n\n  Status status = OpenWithStatus();\n  ASSERT_TRUE(status.IsCorruption());\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/repair.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// We recover the contents of the descriptor from the other files we find.\n// (1) Any log files are first converted to tables\n// (2) We scan every table to compute\n//     (a) smallest/largest for the table\n//     (b) largest sequence number in the table\n// (3) We generate descriptor contents:\n//      - log number is set to zero\n//      - next-file-number is set to 1 + largest file number we found\n//      - last-sequence-number is set to largest sequence# found across\n//        all tables (see 2c)\n//      - compaction pointers are cleared\n//      - every table file is added at level 0\n//\n// Possible optimization 1:\n//   (a) Compute total size and use to pick appropriate max-level M\n//   (b) Sort tables by largest sequence# in the table\n//   (c) For each table: if it overlaps earlier table, place in level-0,\n//       else place in level-M.\n// Possible optimization 2:\n//   Store per-table metadata (smallest, largest, largest-seq#, ...)\n//   in the table's meta section to speed up ScanTable.\n\n#include \"db/builder.h\"\n#include \"db/db_impl.h\"\n#include \"db/dbformat.h\"\n#include \"db/filename.h\"\n#include \"db/log_reader.h\"\n#include \"db/log_writer.h\"\n#include \"db/memtable.h\"\n#include \"db/table_cache.h\"\n#include \"db/version_edit.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/comparator.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\n\nnamespace {\n\nclass Repairer {\n public:\n  Repairer(const std::string& dbname, const Options& options)\n      : dbname_(dbname),\n        env_(options.env),\n        icmp_(options.comparator),\n        ipolicy_(options.filter_policy),\n        options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)),\n        owns_info_log_(options_.info_log != options.info_log),\n        owns_cache_(options_.block_cache != options.block_cache),\n        next_file_number_(1) {\n    // TableCache can be small since we expect each table to be opened once.\n    table_cache_ = new TableCache(dbname_, options_, 10);\n  }\n\n  ~Repairer() {\n    delete table_cache_;\n    if (owns_info_log_) {\n      delete options_.info_log;\n    }\n    if (owns_cache_) {\n      delete options_.block_cache;\n    }\n  }\n\n  Status Run() {\n    Status status = FindFiles();\n    if (status.ok()) {\n      ConvertLogFilesToTables();\n      ExtractMetaData();\n      status = WriteDescriptor();\n    }\n    if (status.ok()) {\n      unsigned long long bytes = 0;\n      for (size_t i = 0; i < tables_.size(); i++) {\n        bytes += tables_[i].meta.file_size;\n      }\n      Log(options_.info_log,\n          \"**** Repaired leveldb %s; \"\n          \"recovered %d files; %llu bytes. \"\n          \"Some data may have been lost. \"\n          \"****\",\n          dbname_.c_str(), static_cast<int>(tables_.size()), bytes);\n    }\n    return status;\n  }\n\n private:\n  struct TableInfo {\n    FileMetaData meta;\n    SequenceNumber max_sequence;\n  };\n\n  Status FindFiles() {\n    std::vector<std::string> filenames;\n    Status status = env_->GetChildren(dbname_, &filenames);\n    if (!status.ok()) {\n      return status;\n    }\n    if (filenames.empty()) {\n      return Status::IOError(dbname_, \"repair found no files\");\n    }\n\n    uint64_t number;\n    FileType type;\n    for (size_t i = 0; i < filenames.size(); i++) {\n      if (ParseFileName(filenames[i], &number, &type)) {\n        if (type == kDescriptorFile) {\n          manifests_.push_back(filenames[i]);\n        } else {\n          if (number + 1 > next_file_number_) {\n            next_file_number_ = number + 1;\n          }\n          if (type == kLogFile) {\n            logs_.push_back(number);\n          } else if (type == kTableFile) {\n            table_numbers_.push_back(number);\n          } else {\n            // Ignore other files\n          }\n        }\n      }\n    }\n    return status;\n  }\n\n  void ConvertLogFilesToTables() {\n    for (size_t i = 0; i < logs_.size(); i++) {\n      std::string logname = LogFileName(dbname_, logs_[i]);\n      Status status = ConvertLogToTable(logs_[i]);\n      if (!status.ok()) {\n        Log(options_.info_log, \"Log #%llu: ignoring conversion error: %s\",\n            (unsigned long long)logs_[i], status.ToString().c_str());\n      }\n      ArchiveFile(logname);\n    }\n  }\n\n  Status ConvertLogToTable(uint64_t log) {\n    struct LogReporter : public log::Reader::Reporter {\n      Env* env;\n      Logger* info_log;\n      uint64_t lognum;\n      void Corruption(size_t bytes, const Status& s) override {\n        // We print error messages for corruption, but continue repairing.\n        Log(info_log, \"Log #%llu: dropping %d bytes; %s\",\n            (unsigned long long)lognum, static_cast<int>(bytes),\n            s.ToString().c_str());\n      }\n    };\n\n    // Open the log file\n    std::string logname = LogFileName(dbname_, log);\n    SequentialFile* lfile;\n    Status status = env_->NewSequentialFile(logname, &lfile);\n    if (!status.ok()) {\n      return status;\n    }\n\n    // Create the log reader.\n    LogReporter reporter;\n    reporter.env = env_;\n    reporter.info_log = options_.info_log;\n    reporter.lognum = log;\n    // We intentionally make log::Reader do checksumming so that\n    // corruptions cause entire commits to be skipped instead of\n    // propagating bad information (like overly large sequence\n    // numbers).\n    log::Reader reader(lfile, &reporter, false /*do not checksum*/,\n                       0 /*initial_offset*/);\n\n    // Read all the records and add to a memtable\n    std::string scratch;\n    Slice record;\n    WriteBatch batch;\n    MemTable* mem = new MemTable(icmp_);\n    mem->Ref();\n    int counter = 0;\n    while (reader.ReadRecord(&record, &scratch)) {\n      if (record.size() < 12) {\n        reporter.Corruption(record.size(),\n                            Status::Corruption(\"log record too small\", logname));\n        continue;\n      }\n      WriteBatchInternal::SetContents(&batch, record);\n      status = WriteBatchInternal::InsertInto(&batch, mem);\n      if (status.ok()) {\n        counter += WriteBatchInternal::Count(&batch);\n      } else {\n        Log(options_.info_log, \"Log #%llu: ignoring %s\",\n            (unsigned long long)log, status.ToString().c_str());\n        status = Status::OK();  // Keep going with rest of file\n      }\n    }\n    delete lfile;\n\n    // Do not record a version edit for this conversion to a Table\n    // since ExtractMetaData() will also generate edits.\n    FileMetaData meta;\n    meta.number = next_file_number_++;\n    Iterator* iter = mem->NewIterator();\n    status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);\n    delete iter;\n    mem->Unref();\n    mem = nullptr;\n    if (status.ok()) {\n      if (meta.file_size > 0) {\n        table_numbers_.push_back(meta.number);\n      }\n    }\n    Log(options_.info_log, \"Log #%llu: %d ops saved to Table #%llu %s\",\n        (unsigned long long)log, counter, (unsigned long long)meta.number,\n        status.ToString().c_str());\n    return status;\n  }\n\n  void ExtractMetaData() {\n    for (size_t i = 0; i < table_numbers_.size(); i++) {\n      ScanTable(table_numbers_[i]);\n    }\n  }\n\n  Iterator* NewTableIterator(const FileMetaData& meta) {\n    // Same as compaction iterators: if paranoid_checks are on, turn\n    // on checksum verification.\n    ReadOptions r;\n    r.verify_checksums = options_.paranoid_checks;\n    return table_cache_->NewIterator(r, meta.number, meta.file_size);\n  }\n\n  void ScanTable(uint64_t number) {\n    TableInfo t;\n    t.meta.number = number;\n    std::string fname = TableFileName(dbname_, number);\n    Status status = env_->GetFileSize(fname, &t.meta.file_size);\n    if (!status.ok()) {\n      // Try alternate file name.\n      fname = SSTTableFileName(dbname_, number);\n      Status s2 = env_->GetFileSize(fname, &t.meta.file_size);\n      if (s2.ok()) {\n        status = Status::OK();\n      }\n    }\n    if (!status.ok()) {\n      ArchiveFile(TableFileName(dbname_, number));\n      ArchiveFile(SSTTableFileName(dbname_, number));\n      Log(options_.info_log, \"Table #%llu: dropped: %s\",\n          (unsigned long long)t.meta.number, status.ToString().c_str());\n      return;\n    }\n\n    // Extract metadata by scanning through table.\n    int counter = 0;\n    Iterator* iter = NewTableIterator(t.meta);\n    bool empty = true;\n    ParsedInternalKey parsed;\n    t.max_sequence = 0;\n    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n      Slice key = iter->key();\n      if (!ParseInternalKey(key, &parsed)) {\n        Log(options_.info_log, \"Table #%llu: unparsable key %s\",\n            (unsigned long long)t.meta.number, EscapeString(key).c_str());\n        continue;\n      }\n\n      counter++;\n      if (empty) {\n        empty = false;\n        t.meta.smallest.DecodeFrom(key);\n      }\n      t.meta.largest.DecodeFrom(key);\n      if (parsed.sequence > t.max_sequence) {\n        t.max_sequence = parsed.sequence;\n      }\n    }\n    if (!iter->status().ok()) {\n      status = iter->status();\n    }\n    delete iter;\n    Log(options_.info_log, \"Table #%llu: %d entries %s\",\n        (unsigned long long)t.meta.number, counter, status.ToString().c_str());\n\n    if (status.ok()) {\n      tables_.push_back(t);\n    } else {\n      RepairTable(fname, t);  // RepairTable archives input file.\n    }\n  }\n\n  void RepairTable(const std::string& src, TableInfo t) {\n    // We will copy src contents to a new table and then rename the\n    // new table over the source.\n\n    // Create builder.\n    std::string copy = TableFileName(dbname_, next_file_number_++);\n    WritableFile* file;\n    Status s = env_->NewWritableFile(copy, &file);\n    if (!s.ok()) {\n      return;\n    }\n    TableBuilder* builder = new TableBuilder(options_, file);\n\n    // Copy data.\n    Iterator* iter = NewTableIterator(t.meta);\n    int counter = 0;\n    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n      builder->Add(iter->key(), iter->value());\n      counter++;\n    }\n    delete iter;\n\n    ArchiveFile(src);\n    if (counter == 0) {\n      builder->Abandon();  // Nothing to save\n    } else {\n      s = builder->Finish();\n      if (s.ok()) {\n        t.meta.file_size = builder->FileSize();\n      }\n    }\n    delete builder;\n    builder = nullptr;\n\n    if (s.ok()) {\n      s = file->Close();\n    }\n    delete file;\n    file = nullptr;\n\n    if (counter > 0 && s.ok()) {\n      std::string orig = TableFileName(dbname_, t.meta.number);\n      s = env_->RenameFile(copy, orig);\n      if (s.ok()) {\n        Log(options_.info_log, \"Table #%llu: %d entries repaired\",\n            (unsigned long long)t.meta.number, counter);\n        tables_.push_back(t);\n      }\n    }\n    if (!s.ok()) {\n      env_->DeleteFile(copy);\n    }\n  }\n\n  Status WriteDescriptor() {\n    std::string tmp = TempFileName(dbname_, 1);\n    WritableFile* file;\n    Status status = env_->NewWritableFile(tmp, &file);\n    if (!status.ok()) {\n      return status;\n    }\n\n    SequenceNumber max_sequence = 0;\n    for (size_t i = 0; i < tables_.size(); i++) {\n      if (max_sequence < tables_[i].max_sequence) {\n        max_sequence = tables_[i].max_sequence;\n      }\n    }\n\n    edit_.SetComparatorName(icmp_.user_comparator()->Name());\n    edit_.SetLogNumber(0);\n    edit_.SetNextFile(next_file_number_);\n    edit_.SetLastSequence(max_sequence);\n\n    for (size_t i = 0; i < tables_.size(); i++) {\n      // TODO(opt): separate out into multiple levels\n      const TableInfo& t = tables_[i];\n      edit_.AddFile(0, t.meta.number, t.meta.file_size, t.meta.smallest,\n                    t.meta.largest);\n    }\n\n    // fprintf(stderr, \"NewDescriptor:\\n%s\\n\", edit_.DebugString().c_str());\n    {\n      log::Writer log(file);\n      std::string record;\n      edit_.EncodeTo(&record);\n      status = log.AddRecord(record);\n    }\n    if (status.ok()) {\n      status = file->Close();\n    }\n    delete file;\n    file = nullptr;\n\n    if (!status.ok()) {\n      env_->DeleteFile(tmp);\n    } else {\n      // Discard older manifests\n      for (size_t i = 0; i < manifests_.size(); i++) {\n        ArchiveFile(dbname_ + \"/\" + manifests_[i]);\n      }\n\n      // Install new manifest\n      status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1));\n      if (status.ok()) {\n        status = SetCurrentFile(env_, dbname_, 1);\n      } else {\n        env_->DeleteFile(tmp);\n      }\n    }\n    return status;\n  }\n\n  void ArchiveFile(const std::string& fname) {\n    // Move into another directory.  E.g., for\n    //    dir/foo\n    // rename to\n    //    dir/lost/foo\n    const char* slash = strrchr(fname.c_str(), '/');\n    std::string new_dir;\n    if (slash != nullptr) {\n      new_dir.assign(fname.data(), slash - fname.data());\n    }\n    new_dir.append(\"/lost\");\n    env_->CreateDir(new_dir);  // Ignore error\n    std::string new_file = new_dir;\n    new_file.append(\"/\");\n    new_file.append((slash == nullptr) ? fname.c_str() : slash + 1);\n    Status s = env_->RenameFile(fname, new_file);\n    Log(options_.info_log, \"Archiving %s: %s\\n\", fname.c_str(),\n        s.ToString().c_str());\n  }\n\n  const std::string dbname_;\n  Env* const env_;\n  InternalKeyComparator const icmp_;\n  InternalFilterPolicy const ipolicy_;\n  const Options options_;\n  bool owns_info_log_;\n  bool owns_cache_;\n  TableCache* table_cache_;\n  VersionEdit edit_;\n\n  std::vector<std::string> manifests_;\n  std::vector<uint64_t> table_numbers_;\n  std::vector<uint64_t> logs_;\n  std::vector<TableInfo> tables_;\n  uint64_t next_file_number_;\n};\n}  // namespace\n\nStatus RepairDB(const std::string& dbname, const Options& options) {\n  Repairer repairer(dbname, options);\n  return repairer.Run();\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/skiplist.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_\n#define STORAGE_LEVELDB_DB_SKIPLIST_H_\n\n// Thread safety\n// -------------\n//\n// Writes require external synchronization, most likely a mutex.\n// Reads require a guarantee that the SkipList will not be destroyed\n// while the read is in progress.  Apart from that, reads progress\n// without any internal locking or synchronization.\n//\n// Invariants:\n//\n// (1) Allocated nodes are never deleted until the SkipList is\n// destroyed.  This is trivially guaranteed by the code since we\n// never delete any skip list nodes.\n//\n// (2) The contents of a Node except for the next/prev pointers are\n// immutable after the Node has been linked into the SkipList.\n// Only Insert() modifies the list, and it is careful to initialize\n// a node and use release-stores to publish the nodes in one or\n// more lists.\n//\n// ... prev vs. next pointer ordering ...\n\n#include <atomic>\n#include <cassert>\n#include <cstdlib>\n\n#include \"util/arena.h\"\n#include \"util/random.h\"\n\nnamespace leveldb {\n\nclass Arena;\n\ntemplate <typename Key, class Comparator>\nclass SkipList {\n private:\n  struct Node;\n\n public:\n  // Create a new SkipList object that will use \"cmp\" for comparing keys,\n  // and will allocate memory using \"*arena\".  Objects allocated in the arena\n  // must remain allocated for the lifetime of the skiplist object.\n  explicit SkipList(Comparator cmp, Arena* arena);\n\n  SkipList(const SkipList&) = delete;\n  SkipList& operator=(const SkipList&) = delete;\n\n  // Insert key into the list.\n  // REQUIRES: nothing that compares equal to key is currently in the list.\n  void Insert(const Key& key);\n\n  // Returns true iff an entry that compares equal to key is in the list.\n  bool Contains(const Key& key) const;\n\n  // Iteration over the contents of a skip list\n  class Iterator {\n   public:\n    // Initialize an iterator over the specified list.\n    // The returned iterator is not valid.\n    explicit Iterator(const SkipList* list);\n\n    // Returns true iff the iterator is positioned at a valid node.\n    bool Valid() const;\n\n    // Returns the key at the current position.\n    // REQUIRES: Valid()\n    const Key& key() const;\n\n    // Advances to the next position.\n    // REQUIRES: Valid()\n    void Next();\n\n    // Advances to the previous position.\n    // REQUIRES: Valid()\n    void Prev();\n\n    // Advance to the first entry with a key >= target\n    void Seek(const Key& target);\n\n    // Position at the first entry in list.\n    // Final state of iterator is Valid() iff list is not empty.\n    void SeekToFirst();\n\n    // Position at the last entry in list.\n    // Final state of iterator is Valid() iff list is not empty.\n    void SeekToLast();\n\n   private:\n    const SkipList* list_;\n    Node* node_;\n    // Intentionally copyable\n  };\n\n private:\n  enum { kMaxHeight = 12 };\n\n  inline int GetMaxHeight() const {\n    return max_height_.load(std::memory_order_relaxed);\n  }\n\n  Node* NewNode(const Key& key, int height);\n  int RandomHeight();\n  bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }\n\n  // Return true if key is greater than the data stored in \"n\"\n  bool KeyIsAfterNode(const Key& key, Node* n) const;\n\n  // Return the earliest node that comes at or after key.\n  // Return nullptr if there is no such node.\n  //\n  // If prev is non-null, fills prev[level] with pointer to previous\n  // node at \"level\" for every level in [0..max_height_-1].\n  Node* FindGreaterOrEqual(const Key& key, Node** prev) const;\n\n  // Return the latest node with a key < key.\n  // Return head_ if there is no such node.\n  Node* FindLessThan(const Key& key) const;\n\n  // Return the last node in the list.\n  // Return head_ if list is empty.\n  Node* FindLast() const;\n\n  // Immutable after construction\n  Comparator const compare_;\n  Arena* const arena_;  // Arena used for allocations of nodes\n\n  Node* const head_;\n\n  // Modified only by Insert().  Read racily by readers, but stale\n  // values are ok.\n  std::atomic<int> max_height_;  // Height of the entire list\n\n  // Read/written only by Insert().\n  Random rnd_;\n};\n\n// Implementation details follow\ntemplate <typename Key, class Comparator>\nstruct SkipList<Key, Comparator>::Node {\n  explicit Node(const Key& k) : key(k) {}\n\n  Key const key;\n\n  // Accessors/mutators for links.  Wrapped in methods so we can\n  // add the appropriate barriers as necessary.\n  Node* Next(int n) {\n    assert(n >= 0);\n    // Use an 'acquire load' so that we observe a fully initialized\n    // version of the returned Node.\n    return next_[n].load(std::memory_order_acquire);\n  }\n  void SetNext(int n, Node* x) {\n    assert(n >= 0);\n    // Use a 'release store' so that anybody who reads through this\n    // pointer observes a fully initialized version of the inserted node.\n    next_[n].store(x, std::memory_order_release);\n  }\n\n  // No-barrier variants that can be safely used in a few locations.\n  Node* NoBarrier_Next(int n) {\n    assert(n >= 0);\n    return next_[n].load(std::memory_order_relaxed);\n  }\n  void NoBarrier_SetNext(int n, Node* x) {\n    assert(n >= 0);\n    next_[n].store(x, std::memory_order_relaxed);\n  }\n\n private:\n  // Array of length equal to the node height.  next_[0] is lowest level link.\n  std::atomic<Node*> next_[1];\n};\n\ntemplate <typename Key, class Comparator>\ntypename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::NewNode(\n    const Key& key, int height) {\n  char* const node_memory = arena_->AllocateAligned(\n      sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1));\n  return new (node_memory) Node(key);\n}\n\ntemplate <typename Key, class Comparator>\ninline SkipList<Key, Comparator>::Iterator::Iterator(const SkipList* list) {\n  list_ = list;\n  node_ = nullptr;\n}\n\ntemplate <typename Key, class Comparator>\ninline bool SkipList<Key, Comparator>::Iterator::Valid() const {\n  return node_ != nullptr;\n}\n\ntemplate <typename Key, class Comparator>\ninline const Key& SkipList<Key, Comparator>::Iterator::key() const {\n  assert(Valid());\n  return node_->key;\n}\n\ntemplate <typename Key, class Comparator>\ninline void SkipList<Key, Comparator>::Iterator::Next() {\n  assert(Valid());\n  node_ = node_->Next(0);\n}\n\ntemplate <typename Key, class Comparator>\ninline void SkipList<Key, Comparator>::Iterator::Prev() {\n  // Instead of using explicit \"prev\" links, we just search for the\n  // last node that falls before key.\n  assert(Valid());\n  node_ = list_->FindLessThan(node_->key);\n  if (node_ == list_->head_) {\n    node_ = nullptr;\n  }\n}\n\ntemplate <typename Key, class Comparator>\ninline void SkipList<Key, Comparator>::Iterator::Seek(const Key& target) {\n  node_ = list_->FindGreaterOrEqual(target, nullptr);\n}\n\ntemplate <typename Key, class Comparator>\ninline void SkipList<Key, Comparator>::Iterator::SeekToFirst() {\n  node_ = list_->head_->Next(0);\n}\n\ntemplate <typename Key, class Comparator>\ninline void SkipList<Key, Comparator>::Iterator::SeekToLast() {\n  node_ = list_->FindLast();\n  if (node_ == list_->head_) {\n    node_ = nullptr;\n  }\n}\n\ntemplate <typename Key, class Comparator>\nint SkipList<Key, Comparator>::RandomHeight() {\n  // Increase height with probability 1 in kBranching\n  static const unsigned int kBranching = 4;\n  int height = 1;\n  while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {\n    height++;\n  }\n  assert(height > 0);\n  assert(height <= kMaxHeight);\n  return height;\n}\n\ntemplate <typename Key, class Comparator>\nbool SkipList<Key, Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {\n  // null n is considered infinite\n  return (n != nullptr) && (compare_(n->key, key) < 0);\n}\n\ntemplate <typename Key, class Comparator>\ntypename SkipList<Key, Comparator>::Node*\nSkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key,\n                                              Node** prev) const {\n  Node* x = head_;\n  int level = GetMaxHeight() - 1;\n  while (true) {\n    Node* next = x->Next(level);\n    if (KeyIsAfterNode(key, next)) {\n      // Keep searching in this list\n      x = next;\n    } else {\n      if (prev != nullptr) prev[level] = x;\n      if (level == 0) {\n        return next;\n      } else {\n        // Switch to next list\n        level--;\n      }\n    }\n  }\n}\n\ntemplate <typename Key, class Comparator>\ntypename SkipList<Key, Comparator>::Node*\nSkipList<Key, Comparator>::FindLessThan(const Key& key) const {\n  Node* x = head_;\n  int level = GetMaxHeight() - 1;\n  while (true) {\n    assert(x == head_ || compare_(x->key, key) < 0);\n    Node* next = x->Next(level);\n    if (next == nullptr || compare_(next->key, key) >= 0) {\n      if (level == 0) {\n        return x;\n      } else {\n        // Switch to next list\n        level--;\n      }\n    } else {\n      x = next;\n    }\n  }\n}\n\ntemplate <typename Key, class Comparator>\ntypename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::FindLast()\n    const {\n  Node* x = head_;\n  int level = GetMaxHeight() - 1;\n  while (true) {\n    Node* next = x->Next(level);\n    if (next == nullptr) {\n      if (level == 0) {\n        return x;\n      } else {\n        // Switch to next list\n        level--;\n      }\n    } else {\n      x = next;\n    }\n  }\n}\n\ntemplate <typename Key, class Comparator>\nSkipList<Key, Comparator>::SkipList(Comparator cmp, Arena* arena)\n    : compare_(cmp),\n      arena_(arena),\n      head_(NewNode(0 /* any key will do */, kMaxHeight)),\n      max_height_(1),\n      rnd_(0xdeadbeef) {\n  for (int i = 0; i < kMaxHeight; i++) {\n    head_->SetNext(i, nullptr);\n  }\n}\n\ntemplate <typename Key, class Comparator>\nvoid SkipList<Key, Comparator>::Insert(const Key& key) {\n  // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()\n  // here since Insert() is externally synchronized.\n  Node* prev[kMaxHeight];\n  Node* x = FindGreaterOrEqual(key, prev);\n\n  // Our data structure does not allow duplicate insertion\n  assert(x == nullptr || !Equal(key, x->key));\n\n  int height = RandomHeight();\n  if (height > GetMaxHeight()) {\n    for (int i = GetMaxHeight(); i < height; i++) {\n      prev[i] = head_;\n    }\n    // It is ok to mutate max_height_ without any synchronization\n    // with concurrent readers.  A concurrent reader that observes\n    // the new value of max_height_ will see either the old value of\n    // new level pointers from head_ (nullptr), or a new value set in\n    // the loop below.  In the former case the reader will\n    // immediately drop to the next level since nullptr sorts after all\n    // keys.  In the latter case the reader will use the new node.\n    max_height_.store(height, std::memory_order_relaxed);\n  }\n\n  x = NewNode(key, height);\n  for (int i = 0; i < height; i++) {\n    // NoBarrier_SetNext() suffices since we will add a barrier when\n    // we publish a pointer to \"x\" in prev[i].\n    x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));\n    prev[i]->SetNext(i, x);\n  }\n}\n\ntemplate <typename Key, class Comparator>\nbool SkipList<Key, Comparator>::Contains(const Key& key) const {\n  Node* x = FindGreaterOrEqual(key, nullptr);\n  if (x != nullptr && Equal(key, x->key)) {\n    return true;\n  } else {\n    return false;\n  }\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_SKIPLIST_H_\n"
  },
  {
    "path": "src/leveldb/db/skiplist_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/skiplist.h\"\n\n#include <atomic>\n#include <set>\n\n#include \"leveldb/env.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/arena.h\"\n#include \"util/hash.h\"\n#include \"util/random.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\ntypedef uint64_t Key;\n\nstruct Comparator {\n  int operator()(const Key& a, const Key& b) const {\n    if (a < b) {\n      return -1;\n    } else if (a > b) {\n      return +1;\n    } else {\n      return 0;\n    }\n  }\n};\n\nclass SkipTest {};\n\nTEST(SkipTest, Empty) {\n  Arena arena;\n  Comparator cmp;\n  SkipList<Key, Comparator> list(cmp, &arena);\n  ASSERT_TRUE(!list.Contains(10));\n\n  SkipList<Key, Comparator>::Iterator iter(&list);\n  ASSERT_TRUE(!iter.Valid());\n  iter.SeekToFirst();\n  ASSERT_TRUE(!iter.Valid());\n  iter.Seek(100);\n  ASSERT_TRUE(!iter.Valid());\n  iter.SeekToLast();\n  ASSERT_TRUE(!iter.Valid());\n}\n\nTEST(SkipTest, InsertAndLookup) {\n  const int N = 2000;\n  const int R = 5000;\n  Random rnd(1000);\n  std::set<Key> keys;\n  Arena arena;\n  Comparator cmp;\n  SkipList<Key, Comparator> list(cmp, &arena);\n  for (int i = 0; i < N; i++) {\n    Key key = rnd.Next() % R;\n    if (keys.insert(key).second) {\n      list.Insert(key);\n    }\n  }\n\n  for (int i = 0; i < R; i++) {\n    if (list.Contains(i)) {\n      ASSERT_EQ(keys.count(i), 1);\n    } else {\n      ASSERT_EQ(keys.count(i), 0);\n    }\n  }\n\n  // Simple iterator tests\n  {\n    SkipList<Key, Comparator>::Iterator iter(&list);\n    ASSERT_TRUE(!iter.Valid());\n\n    iter.Seek(0);\n    ASSERT_TRUE(iter.Valid());\n    ASSERT_EQ(*(keys.begin()), iter.key());\n\n    iter.SeekToFirst();\n    ASSERT_TRUE(iter.Valid());\n    ASSERT_EQ(*(keys.begin()), iter.key());\n\n    iter.SeekToLast();\n    ASSERT_TRUE(iter.Valid());\n    ASSERT_EQ(*(keys.rbegin()), iter.key());\n  }\n\n  // Forward iteration test\n  for (int i = 0; i < R; i++) {\n    SkipList<Key, Comparator>::Iterator iter(&list);\n    iter.Seek(i);\n\n    // Compare against model iterator\n    std::set<Key>::iterator model_iter = keys.lower_bound(i);\n    for (int j = 0; j < 3; j++) {\n      if (model_iter == keys.end()) {\n        ASSERT_TRUE(!iter.Valid());\n        break;\n      } else {\n        ASSERT_TRUE(iter.Valid());\n        ASSERT_EQ(*model_iter, iter.key());\n        ++model_iter;\n        iter.Next();\n      }\n    }\n  }\n\n  // Backward iteration test\n  {\n    SkipList<Key, Comparator>::Iterator iter(&list);\n    iter.SeekToLast();\n\n    // Compare against model iterator\n    for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();\n         model_iter != keys.rend(); ++model_iter) {\n      ASSERT_TRUE(iter.Valid());\n      ASSERT_EQ(*model_iter, iter.key());\n      iter.Prev();\n    }\n    ASSERT_TRUE(!iter.Valid());\n  }\n}\n\n// We want to make sure that with a single writer and multiple\n// concurrent readers (with no synchronization other than when a\n// reader's iterator is created), the reader always observes all the\n// data that was present in the skip list when the iterator was\n// constructed.  Because insertions are happening concurrently, we may\n// also observe new values that were inserted since the iterator was\n// constructed, but we should never miss any values that were present\n// at iterator construction time.\n//\n// We generate multi-part keys:\n//     <key,gen,hash>\n// where:\n//     key is in range [0..K-1]\n//     gen is a generation number for key\n//     hash is hash(key,gen)\n//\n// The insertion code picks a random key, sets gen to be 1 + the last\n// generation number inserted for that key, and sets hash to Hash(key,gen).\n//\n// At the beginning of a read, we snapshot the last inserted\n// generation number for each key.  We then iterate, including random\n// calls to Next() and Seek().  For every key we encounter, we\n// check that it is either expected given the initial snapshot or has\n// been concurrently added since the iterator started.\nclass ConcurrentTest {\n private:\n  static const uint32_t K = 4;\n\n  static uint64_t key(Key key) { return (key >> 40); }\n  static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }\n  static uint64_t hash(Key key) { return key & 0xff; }\n\n  static uint64_t HashNumbers(uint64_t k, uint64_t g) {\n    uint64_t data[2] = {k, g};\n    return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);\n  }\n\n  static Key MakeKey(uint64_t k, uint64_t g) {\n    static_assert(sizeof(Key) == sizeof(uint64_t), \"\");\n    assert(k <= K);  // We sometimes pass K to seek to the end of the skiplist\n    assert(g <= 0xffffffffu);\n    return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));\n  }\n\n  static bool IsValidKey(Key k) {\n    return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);\n  }\n\n  static Key RandomTarget(Random* rnd) {\n    switch (rnd->Next() % 10) {\n      case 0:\n        // Seek to beginning\n        return MakeKey(0, 0);\n      case 1:\n        // Seek to end\n        return MakeKey(K, 0);\n      default:\n        // Seek to middle\n        return MakeKey(rnd->Next() % K, 0);\n    }\n  }\n\n  // Per-key generation\n  struct State {\n    std::atomic<int> generation[K];\n    void Set(int k, int v) {\n      generation[k].store(v, std::memory_order_release);\n    }\n    int Get(int k) { return generation[k].load(std::memory_order_acquire); }\n\n    State() {\n      for (int k = 0; k < K; k++) {\n        Set(k, 0);\n      }\n    }\n  };\n\n  // Current state of the test\n  State current_;\n\n  Arena arena_;\n\n  // SkipList is not protected by mu_.  We just use a single writer\n  // thread to modify it.\n  SkipList<Key, Comparator> list_;\n\n public:\n  ConcurrentTest() : list_(Comparator(), &arena_) {}\n\n  // REQUIRES: External synchronization\n  void WriteStep(Random* rnd) {\n    const uint32_t k = rnd->Next() % K;\n    const intptr_t g = current_.Get(k) + 1;\n    const Key key = MakeKey(k, g);\n    list_.Insert(key);\n    current_.Set(k, g);\n  }\n\n  void ReadStep(Random* rnd) {\n    // Remember the initial committed state of the skiplist.\n    State initial_state;\n    for (int k = 0; k < K; k++) {\n      initial_state.Set(k, current_.Get(k));\n    }\n\n    Key pos = RandomTarget(rnd);\n    SkipList<Key, Comparator>::Iterator iter(&list_);\n    iter.Seek(pos);\n    while (true) {\n      Key current;\n      if (!iter.Valid()) {\n        current = MakeKey(K, 0);\n      } else {\n        current = iter.key();\n        ASSERT_TRUE(IsValidKey(current)) << current;\n      }\n      ASSERT_LE(pos, current) << \"should not go backwards\";\n\n      // Verify that everything in [pos,current) was not present in\n      // initial_state.\n      while (pos < current) {\n        ASSERT_LT(key(pos), K) << pos;\n\n        // Note that generation 0 is never inserted, so it is ok if\n        // <*,0,*> is missing.\n        ASSERT_TRUE((gen(pos) == 0) ||\n                    (gen(pos) > static_cast<Key>(initial_state.Get(key(pos)))))\n            << \"key: \" << key(pos) << \"; gen: \" << gen(pos)\n            << \"; initgen: \" << initial_state.Get(key(pos));\n\n        // Advance to next key in the valid key space\n        if (key(pos) < key(current)) {\n          pos = MakeKey(key(pos) + 1, 0);\n        } else {\n          pos = MakeKey(key(pos), gen(pos) + 1);\n        }\n      }\n\n      if (!iter.Valid()) {\n        break;\n      }\n\n      if (rnd->Next() % 2) {\n        iter.Next();\n        pos = MakeKey(key(pos), gen(pos) + 1);\n      } else {\n        Key new_target = RandomTarget(rnd);\n        if (new_target > pos) {\n          pos = new_target;\n          iter.Seek(new_target);\n        }\n      }\n    }\n  }\n};\nconst uint32_t ConcurrentTest::K;\n\n// Simple test that does single-threaded testing of the ConcurrentTest\n// scaffolding.\nTEST(SkipTest, ConcurrentWithoutThreads) {\n  ConcurrentTest test;\n  Random rnd(test::RandomSeed());\n  for (int i = 0; i < 10000; i++) {\n    test.ReadStep(&rnd);\n    test.WriteStep(&rnd);\n  }\n}\n\nclass TestState {\n public:\n  ConcurrentTest t_;\n  int seed_;\n  std::atomic<bool> quit_flag_;\n\n  enum ReaderState { STARTING, RUNNING, DONE };\n\n  explicit TestState(int s)\n      : seed_(s), quit_flag_(false), state_(STARTING), state_cv_(&mu_) {}\n\n  void Wait(ReaderState s) LOCKS_EXCLUDED(mu_) {\n    mu_.Lock();\n    while (state_ != s) {\n      state_cv_.Wait();\n    }\n    mu_.Unlock();\n  }\n\n  void Change(ReaderState s) LOCKS_EXCLUDED(mu_) {\n    mu_.Lock();\n    state_ = s;\n    state_cv_.Signal();\n    mu_.Unlock();\n  }\n\n private:\n  port::Mutex mu_;\n  ReaderState state_ GUARDED_BY(mu_);\n  port::CondVar state_cv_ GUARDED_BY(mu_);\n};\n\nstatic void ConcurrentReader(void* arg) {\n  TestState* state = reinterpret_cast<TestState*>(arg);\n  Random rnd(state->seed_);\n  int64_t reads = 0;\n  state->Change(TestState::RUNNING);\n  while (!state->quit_flag_.load(std::memory_order_acquire)) {\n    state->t_.ReadStep(&rnd);\n    ++reads;\n  }\n  state->Change(TestState::DONE);\n}\n\nstatic void RunConcurrent(int run) {\n  const int seed = test::RandomSeed() + (run * 100);\n  Random rnd(seed);\n  const int N = 1000;\n  const int kSize = 1000;\n  for (int i = 0; i < N; i++) {\n    if ((i % 100) == 0) {\n      fprintf(stderr, \"Run %d of %d\\n\", i, N);\n    }\n    TestState state(seed + 1);\n    Env::Default()->Schedule(ConcurrentReader, &state);\n    state.Wait(TestState::RUNNING);\n    for (int i = 0; i < kSize; i++) {\n      state.t_.WriteStep(&rnd);\n    }\n    state.quit_flag_.store(true, std::memory_order_release);\n    state.Wait(TestState::DONE);\n  }\n}\n\nTEST(SkipTest, Concurrent1) { RunConcurrent(1); }\nTEST(SkipTest, Concurrent2) { RunConcurrent(2); }\nTEST(SkipTest, Concurrent3) { RunConcurrent(3); }\nTEST(SkipTest, Concurrent4) { RunConcurrent(4); }\nTEST(SkipTest, Concurrent5) { RunConcurrent(5); }\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/snapshot.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_\n#define STORAGE_LEVELDB_DB_SNAPSHOT_H_\n\n#include \"db/dbformat.h\"\n#include \"leveldb/db.h\"\n\nnamespace leveldb {\n\nclass SnapshotList;\n\n// Snapshots are kept in a doubly-linked list in the DB.\n// Each SnapshotImpl corresponds to a particular sequence number.\nclass SnapshotImpl : public Snapshot {\n public:\n  SnapshotImpl(SequenceNumber sequence_number)\n      : sequence_number_(sequence_number) {}\n\n  SequenceNumber sequence_number() const { return sequence_number_; }\n\n private:\n  friend class SnapshotList;\n\n  // SnapshotImpl is kept in a doubly-linked circular list. The SnapshotList\n  // implementation operates on the next/previous fields direcly.\n  SnapshotImpl* prev_;\n  SnapshotImpl* next_;\n\n  const SequenceNumber sequence_number_;\n\n#if !defined(NDEBUG)\n  SnapshotList* list_ = nullptr;\n#endif  // !defined(NDEBUG)\n};\n\nclass SnapshotList {\n public:\n  SnapshotList() : head_(0) {\n    head_.prev_ = &head_;\n    head_.next_ = &head_;\n  }\n\n  bool empty() const { return head_.next_ == &head_; }\n  SnapshotImpl* oldest() const {\n    assert(!empty());\n    return head_.next_;\n  }\n  SnapshotImpl* newest() const {\n    assert(!empty());\n    return head_.prev_;\n  }\n\n  // Creates a SnapshotImpl and appends it to the end of the list.\n  SnapshotImpl* New(SequenceNumber sequence_number) {\n    assert(empty() || newest()->sequence_number_ <= sequence_number);\n\n    SnapshotImpl* snapshot = new SnapshotImpl(sequence_number);\n\n#if !defined(NDEBUG)\n    snapshot->list_ = this;\n#endif  // !defined(NDEBUG)\n    snapshot->next_ = &head_;\n    snapshot->prev_ = head_.prev_;\n    snapshot->prev_->next_ = snapshot;\n    snapshot->next_->prev_ = snapshot;\n    return snapshot;\n  }\n\n  // Removes a SnapshotImpl from this list.\n  //\n  // The snapshot must have been created by calling New() on this list.\n  //\n  // The snapshot pointer should not be const, because its memory is\n  // deallocated. However, that would force us to change DB::ReleaseSnapshot(),\n  // which is in the API, and currently takes a const Snapshot.\n  void Delete(const SnapshotImpl* snapshot) {\n#if !defined(NDEBUG)\n    assert(snapshot->list_ == this);\n#endif  // !defined(NDEBUG)\n    snapshot->prev_->next_ = snapshot->next_;\n    snapshot->next_->prev_ = snapshot->prev_;\n    delete snapshot;\n  }\n\n private:\n  // Dummy head of doubly-linked list of snapshots\n  SnapshotImpl head_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_SNAPSHOT_H_\n"
  },
  {
    "path": "src/leveldb/db/table_cache.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/table_cache.h\"\n\n#include \"db/filename.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/table.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nstruct TableAndFile {\n  RandomAccessFile* file;\n  Table* table;\n};\n\nstatic void DeleteEntry(const Slice& key, void* value) {\n  TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);\n  delete tf->table;\n  delete tf->file;\n  delete tf;\n}\n\nstatic void UnrefEntry(void* arg1, void* arg2) {\n  Cache* cache = reinterpret_cast<Cache*>(arg1);\n  Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);\n  cache->Release(h);\n}\n\nTableCache::TableCache(const std::string& dbname, const Options& options,\n                       int entries)\n    : env_(options.env),\n      dbname_(dbname),\n      options_(options),\n      cache_(NewLRUCache(entries)) {}\n\nTableCache::~TableCache() { delete cache_; }\n\nStatus TableCache::FindTable(uint64_t file_number, uint64_t file_size,\n                             Cache::Handle** handle) {\n  Status s;\n  char buf[sizeof(file_number)];\n  EncodeFixed64(buf, file_number);\n  Slice key(buf, sizeof(buf));\n  *handle = cache_->Lookup(key);\n  if (*handle == nullptr) {\n    std::string fname = TableFileName(dbname_, file_number);\n    RandomAccessFile* file = nullptr;\n    Table* table = nullptr;\n    s = env_->NewRandomAccessFile(fname, &file);\n    if (!s.ok()) {\n      std::string old_fname = SSTTableFileName(dbname_, file_number);\n      if (env_->NewRandomAccessFile(old_fname, &file).ok()) {\n        s = Status::OK();\n      }\n    }\n    if (s.ok()) {\n      s = Table::Open(options_, file, file_size, &table);\n    }\n\n    if (!s.ok()) {\n      assert(table == nullptr);\n      delete file;\n      // We do not cache error results so that if the error is transient,\n      // or somebody repairs the file, we recover automatically.\n    } else {\n      TableAndFile* tf = new TableAndFile;\n      tf->file = file;\n      tf->table = table;\n      *handle = cache_->Insert(key, tf, 1, &DeleteEntry);\n    }\n  }\n  return s;\n}\n\nIterator* TableCache::NewIterator(const ReadOptions& options,\n                                  uint64_t file_number, uint64_t file_size,\n                                  Table** tableptr) {\n  if (tableptr != nullptr) {\n    *tableptr = nullptr;\n  }\n\n  Cache::Handle* handle = nullptr;\n  Status s = FindTable(file_number, file_size, &handle);\n  if (!s.ok()) {\n    return NewErrorIterator(s);\n  }\n\n  Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;\n  Iterator* result = table->NewIterator(options);\n  result->RegisterCleanup(&UnrefEntry, cache_, handle);\n  if (tableptr != nullptr) {\n    *tableptr = table;\n  }\n  return result;\n}\n\nStatus TableCache::Get(const ReadOptions& options, uint64_t file_number,\n                       uint64_t file_size, const Slice& k, void* arg,\n                       void (*handle_result)(void*, const Slice&,\n                                             const Slice&)) {\n  Cache::Handle* handle = nullptr;\n  Status s = FindTable(file_number, file_size, &handle);\n  if (s.ok()) {\n    Table* t = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;\n    s = t->InternalGet(options, k, arg, handle_result);\n    cache_->Release(handle);\n  }\n  return s;\n}\n\nvoid TableCache::Evict(uint64_t file_number) {\n  char buf[sizeof(file_number)];\n  EncodeFixed64(buf, file_number);\n  cache_->Erase(Slice(buf, sizeof(buf)));\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/table_cache.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Thread-safe (provides internal synchronization)\n\n#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_\n#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_\n\n#include <stdint.h>\n\n#include <string>\n\n#include \"db/dbformat.h\"\n#include \"leveldb/cache.h\"\n#include \"leveldb/table.h\"\n#include \"port/port.h\"\n\nnamespace leveldb {\n\nclass Env;\n\nclass TableCache {\n public:\n  TableCache(const std::string& dbname, const Options& options, int entries);\n  ~TableCache();\n\n  // Return an iterator for the specified file number (the corresponding\n  // file length must be exactly \"file_size\" bytes).  If \"tableptr\" is\n  // non-null, also sets \"*tableptr\" to point to the Table object\n  // underlying the returned iterator, or to nullptr if no Table object\n  // underlies the returned iterator.  The returned \"*tableptr\" object is owned\n  // by the cache and should not be deleted, and is valid for as long as the\n  // returned iterator is live.\n  Iterator* NewIterator(const ReadOptions& options, uint64_t file_number,\n                        uint64_t file_size, Table** tableptr = nullptr);\n\n  // If a seek to internal key \"k\" in specified file finds an entry,\n  // call (*handle_result)(arg, found_key, found_value).\n  Status Get(const ReadOptions& options, uint64_t file_number,\n             uint64_t file_size, const Slice& k, void* arg,\n             void (*handle_result)(void*, const Slice&, const Slice&));\n\n  // Evict any entry for the specified file number\n  void Evict(uint64_t file_number);\n\n private:\n  Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**);\n\n  Env* const env_;\n  const std::string dbname_;\n  const Options& options_;\n  Cache* cache_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_TABLE_CACHE_H_\n"
  },
  {
    "path": "src/leveldb/db/version_edit.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/version_edit.h\"\n\n#include \"db/version_set.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\n// Tag numbers for serialized VersionEdit.  These numbers are written to\n// disk and should not be changed.\nenum Tag {\n  kComparator = 1,\n  kLogNumber = 2,\n  kNextFileNumber = 3,\n  kLastSequence = 4,\n  kCompactPointer = 5,\n  kDeletedFile = 6,\n  kNewFile = 7,\n  // 8 was used for large value refs\n  kPrevLogNumber = 9\n};\n\nvoid VersionEdit::Clear() {\n  comparator_.clear();\n  log_number_ = 0;\n  prev_log_number_ = 0;\n  last_sequence_ = 0;\n  next_file_number_ = 0;\n  has_comparator_ = false;\n  has_log_number_ = false;\n  has_prev_log_number_ = false;\n  has_next_file_number_ = false;\n  has_last_sequence_ = false;\n  deleted_files_.clear();\n  new_files_.clear();\n}\n\nvoid VersionEdit::EncodeTo(std::string* dst) const {\n  if (has_comparator_) {\n    PutVarint32(dst, kComparator);\n    PutLengthPrefixedSlice(dst, comparator_);\n  }\n  if (has_log_number_) {\n    PutVarint32(dst, kLogNumber);\n    PutVarint64(dst, log_number_);\n  }\n  if (has_prev_log_number_) {\n    PutVarint32(dst, kPrevLogNumber);\n    PutVarint64(dst, prev_log_number_);\n  }\n  if (has_next_file_number_) {\n    PutVarint32(dst, kNextFileNumber);\n    PutVarint64(dst, next_file_number_);\n  }\n  if (has_last_sequence_) {\n    PutVarint32(dst, kLastSequence);\n    PutVarint64(dst, last_sequence_);\n  }\n\n  for (size_t i = 0; i < compact_pointers_.size(); i++) {\n    PutVarint32(dst, kCompactPointer);\n    PutVarint32(dst, compact_pointers_[i].first);  // level\n    PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode());\n  }\n\n  for (const auto& deleted_file_kvp : deleted_files_) {\n    PutVarint32(dst, kDeletedFile);\n    PutVarint32(dst, deleted_file_kvp.first);   // level\n    PutVarint64(dst, deleted_file_kvp.second);  // file number\n  }\n\n  for (size_t i = 0; i < new_files_.size(); i++) {\n    const FileMetaData& f = new_files_[i].second;\n    PutVarint32(dst, kNewFile);\n    PutVarint32(dst, new_files_[i].first);  // level\n    PutVarint64(dst, f.number);\n    PutVarint64(dst, f.file_size);\n    PutLengthPrefixedSlice(dst, f.smallest.Encode());\n    PutLengthPrefixedSlice(dst, f.largest.Encode());\n  }\n}\n\nstatic bool GetInternalKey(Slice* input, InternalKey* dst) {\n  Slice str;\n  if (GetLengthPrefixedSlice(input, &str)) {\n    return dst->DecodeFrom(str);\n  } else {\n    return false;\n  }\n}\n\nstatic bool GetLevel(Slice* input, int* level) {\n  uint32_t v;\n  if (GetVarint32(input, &v) && v < config::kNumLevels) {\n    *level = v;\n    return true;\n  } else {\n    return false;\n  }\n}\n\nStatus VersionEdit::DecodeFrom(const Slice& src) {\n  Clear();\n  Slice input = src;\n  const char* msg = nullptr;\n  uint32_t tag;\n\n  // Temporary storage for parsing\n  int level;\n  uint64_t number;\n  FileMetaData f;\n  Slice str;\n  InternalKey key;\n\n  while (msg == nullptr && GetVarint32(&input, &tag)) {\n    switch (tag) {\n      case kComparator:\n        if (GetLengthPrefixedSlice(&input, &str)) {\n          comparator_ = str.ToString();\n          has_comparator_ = true;\n        } else {\n          msg = \"comparator name\";\n        }\n        break;\n\n      case kLogNumber:\n        if (GetVarint64(&input, &log_number_)) {\n          has_log_number_ = true;\n        } else {\n          msg = \"log number\";\n        }\n        break;\n\n      case kPrevLogNumber:\n        if (GetVarint64(&input, &prev_log_number_)) {\n          has_prev_log_number_ = true;\n        } else {\n          msg = \"previous log number\";\n        }\n        break;\n\n      case kNextFileNumber:\n        if (GetVarint64(&input, &next_file_number_)) {\n          has_next_file_number_ = true;\n        } else {\n          msg = \"next file number\";\n        }\n        break;\n\n      case kLastSequence:\n        if (GetVarint64(&input, &last_sequence_)) {\n          has_last_sequence_ = true;\n        } else {\n          msg = \"last sequence number\";\n        }\n        break;\n\n      case kCompactPointer:\n        if (GetLevel(&input, &level) && GetInternalKey(&input, &key)) {\n          compact_pointers_.push_back(std::make_pair(level, key));\n        } else {\n          msg = \"compaction pointer\";\n        }\n        break;\n\n      case kDeletedFile:\n        if (GetLevel(&input, &level) && GetVarint64(&input, &number)) {\n          deleted_files_.insert(std::make_pair(level, number));\n        } else {\n          msg = \"deleted file\";\n        }\n        break;\n\n      case kNewFile:\n        if (GetLevel(&input, &level) && GetVarint64(&input, &f.number) &&\n            GetVarint64(&input, &f.file_size) &&\n            GetInternalKey(&input, &f.smallest) &&\n            GetInternalKey(&input, &f.largest)) {\n          new_files_.push_back(std::make_pair(level, f));\n        } else {\n          msg = \"new-file entry\";\n        }\n        break;\n\n      default:\n        msg = \"unknown tag\";\n        break;\n    }\n  }\n\n  if (msg == nullptr && !input.empty()) {\n    msg = \"invalid tag\";\n  }\n\n  Status result;\n  if (msg != nullptr) {\n    result = Status::Corruption(\"VersionEdit\", msg);\n  }\n  return result;\n}\n\nstd::string VersionEdit::DebugString() const {\n  std::string r;\n  r.append(\"VersionEdit {\");\n  if (has_comparator_) {\n    r.append(\"\\n  Comparator: \");\n    r.append(comparator_);\n  }\n  if (has_log_number_) {\n    r.append(\"\\n  LogNumber: \");\n    AppendNumberTo(&r, log_number_);\n  }\n  if (has_prev_log_number_) {\n    r.append(\"\\n  PrevLogNumber: \");\n    AppendNumberTo(&r, prev_log_number_);\n  }\n  if (has_next_file_number_) {\n    r.append(\"\\n  NextFile: \");\n    AppendNumberTo(&r, next_file_number_);\n  }\n  if (has_last_sequence_) {\n    r.append(\"\\n  LastSeq: \");\n    AppendNumberTo(&r, last_sequence_);\n  }\n  for (size_t i = 0; i < compact_pointers_.size(); i++) {\n    r.append(\"\\n  CompactPointer: \");\n    AppendNumberTo(&r, compact_pointers_[i].first);\n    r.append(\" \");\n    r.append(compact_pointers_[i].second.DebugString());\n  }\n  for (const auto& deleted_files_kvp : deleted_files_) {\n    r.append(\"\\n  DeleteFile: \");\n    AppendNumberTo(&r, deleted_files_kvp.first);\n    r.append(\" \");\n    AppendNumberTo(&r, deleted_files_kvp.second);\n  }\n  for (size_t i = 0; i < new_files_.size(); i++) {\n    const FileMetaData& f = new_files_[i].second;\n    r.append(\"\\n  AddFile: \");\n    AppendNumberTo(&r, new_files_[i].first);\n    r.append(\" \");\n    AppendNumberTo(&r, f.number);\n    r.append(\" \");\n    AppendNumberTo(&r, f.file_size);\n    r.append(\" \");\n    r.append(f.smallest.DebugString());\n    r.append(\" .. \");\n    r.append(f.largest.DebugString());\n  }\n  r.append(\"\\n}\\n\");\n  return r;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/version_edit.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_\n#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_\n\n#include <set>\n#include <utility>\n#include <vector>\n\n#include \"db/dbformat.h\"\n\nnamespace leveldb {\n\nclass VersionSet;\n\nstruct FileMetaData {\n  FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) {}\n\n  int refs;\n  int allowed_seeks;  // Seeks allowed until compaction\n  uint64_t number;\n  uint64_t file_size;    // File size in bytes\n  InternalKey smallest;  // Smallest internal key served by table\n  InternalKey largest;   // Largest internal key served by table\n};\n\nclass VersionEdit {\n public:\n  VersionEdit() { Clear(); }\n  ~VersionEdit() = default;\n\n  void Clear();\n\n  void SetComparatorName(const Slice& name) {\n    has_comparator_ = true;\n    comparator_ = name.ToString();\n  }\n  void SetLogNumber(uint64_t num) {\n    has_log_number_ = true;\n    log_number_ = num;\n  }\n  void SetPrevLogNumber(uint64_t num) {\n    has_prev_log_number_ = true;\n    prev_log_number_ = num;\n  }\n  void SetNextFile(uint64_t num) {\n    has_next_file_number_ = true;\n    next_file_number_ = num;\n  }\n  void SetLastSequence(SequenceNumber seq) {\n    has_last_sequence_ = true;\n    last_sequence_ = seq;\n  }\n  void SetCompactPointer(int level, const InternalKey& key) {\n    compact_pointers_.push_back(std::make_pair(level, key));\n  }\n\n  // Add the specified file at the specified number.\n  // REQUIRES: This version has not been saved (see VersionSet::SaveTo)\n  // REQUIRES: \"smallest\" and \"largest\" are smallest and largest keys in file\n  void AddFile(int level, uint64_t file, uint64_t file_size,\n               const InternalKey& smallest, const InternalKey& largest) {\n    FileMetaData f;\n    f.number = file;\n    f.file_size = file_size;\n    f.smallest = smallest;\n    f.largest = largest;\n    new_files_.push_back(std::make_pair(level, f));\n  }\n\n  // Delete the specified \"file\" from the specified \"level\".\n  void DeleteFile(int level, uint64_t file) {\n    deleted_files_.insert(std::make_pair(level, file));\n  }\n\n  void EncodeTo(std::string* dst) const;\n  Status DecodeFrom(const Slice& src);\n\n  std::string DebugString() const;\n\n private:\n  friend class VersionSet;\n\n  typedef std::set<std::pair<int, uint64_t>> DeletedFileSet;\n\n  std::string comparator_;\n  uint64_t log_number_;\n  uint64_t prev_log_number_;\n  uint64_t next_file_number_;\n  SequenceNumber last_sequence_;\n  bool has_comparator_;\n  bool has_log_number_;\n  bool has_prev_log_number_;\n  bool has_next_file_number_;\n  bool has_last_sequence_;\n\n  std::vector<std::pair<int, InternalKey>> compact_pointers_;\n  DeletedFileSet deleted_files_;\n  std::vector<std::pair<int, FileMetaData>> new_files_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_VERSION_EDIT_H_\n"
  },
  {
    "path": "src/leveldb/db/version_edit_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/version_edit.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nstatic void TestEncodeDecode(const VersionEdit& edit) {\n  std::string encoded, encoded2;\n  edit.EncodeTo(&encoded);\n  VersionEdit parsed;\n  Status s = parsed.DecodeFrom(encoded);\n  ASSERT_TRUE(s.ok()) << s.ToString();\n  parsed.EncodeTo(&encoded2);\n  ASSERT_EQ(encoded, encoded2);\n}\n\nclass VersionEditTest {};\n\nTEST(VersionEditTest, EncodeDecode) {\n  static const uint64_t kBig = 1ull << 50;\n\n  VersionEdit edit;\n  for (int i = 0; i < 4; i++) {\n    TestEncodeDecode(edit);\n    edit.AddFile(3, kBig + 300 + i, kBig + 400 + i,\n                 InternalKey(\"foo\", kBig + 500 + i, kTypeValue),\n                 InternalKey(\"zoo\", kBig + 600 + i, kTypeDeletion));\n    edit.DeleteFile(4, kBig + 700 + i);\n    edit.SetCompactPointer(i, InternalKey(\"x\", kBig + 900 + i, kTypeValue));\n  }\n\n  edit.SetComparatorName(\"foo\");\n  edit.SetLogNumber(kBig + 100);\n  edit.SetNextFile(kBig + 200);\n  edit.SetLastSequence(kBig + 1000);\n  TestEncodeDecode(edit);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/version_set.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/version_set.h\"\n\n#include <stdio.h>\n\n#include <algorithm>\n\n#include \"db/filename.h\"\n#include \"db/log_reader.h\"\n#include \"db/log_writer.h\"\n#include \"db/memtable.h\"\n#include \"db/table_cache.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/table_builder.h\"\n#include \"table/merger.h\"\n#include \"table/two_level_iterator.h\"\n#include \"util/coding.h\"\n#include \"util/logging.h\"\n\nnamespace leveldb {\n\nstatic size_t TargetFileSize(const Options* options) {\n  return options->max_file_size;\n}\n\n// Maximum bytes of overlaps in grandparent (i.e., level+2) before we\n// stop building a single file in a level->level+1 compaction.\nstatic int64_t MaxGrandParentOverlapBytes(const Options* options) {\n  return 10 * TargetFileSize(options);\n}\n\n// Maximum number of bytes in all compacted files.  We avoid expanding\n// the lower level file set of a compaction if it would make the\n// total compaction cover more than this many bytes.\nstatic int64_t ExpandedCompactionByteSizeLimit(const Options* options) {\n  return 25 * TargetFileSize(options);\n}\n\nstatic double MaxBytesForLevel(const Options* options, int level) {\n  // Note: the result for level zero is not really used since we set\n  // the level-0 compaction threshold based on number of files.\n\n  // Result for both level-0 and level-1\n  double result = 10. * 1048576.0;\n  while (level > 1) {\n    result *= 10;\n    level--;\n  }\n  return result;\n}\n\nstatic uint64_t MaxFileSizeForLevel(const Options* options, int level) {\n  // We could vary per level to reduce number of files?\n  return TargetFileSize(options);\n}\n\nstatic int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {\n  int64_t sum = 0;\n  for (size_t i = 0; i < files.size(); i++) {\n    sum += files[i]->file_size;\n  }\n  return sum;\n}\n\nVersion::~Version() {\n  assert(refs_ == 0);\n\n  // Remove from linked list\n  prev_->next_ = next_;\n  next_->prev_ = prev_;\n\n  // Drop references to files\n  for (int level = 0; level < config::kNumLevels; level++) {\n    for (size_t i = 0; i < files_[level].size(); i++) {\n      FileMetaData* f = files_[level][i];\n      assert(f->refs > 0);\n      f->refs--;\n      if (f->refs <= 0) {\n        delete f;\n      }\n    }\n  }\n}\n\nint FindFile(const InternalKeyComparator& icmp,\n             const std::vector<FileMetaData*>& files, const Slice& key) {\n  uint32_t left = 0;\n  uint32_t right = files.size();\n  while (left < right) {\n    uint32_t mid = (left + right) / 2;\n    const FileMetaData* f = files[mid];\n    if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {\n      // Key at \"mid.largest\" is < \"target\".  Therefore all\n      // files at or before \"mid\" are uninteresting.\n      left = mid + 1;\n    } else {\n      // Key at \"mid.largest\" is >= \"target\".  Therefore all files\n      // after \"mid\" are uninteresting.\n      right = mid;\n    }\n  }\n  return right;\n}\n\nstatic bool AfterFile(const Comparator* ucmp, const Slice* user_key,\n                      const FileMetaData* f) {\n  // null user_key occurs before all keys and is therefore never after *f\n  return (user_key != nullptr &&\n          ucmp->Compare(*user_key, f->largest.user_key()) > 0);\n}\n\nstatic bool BeforeFile(const Comparator* ucmp, const Slice* user_key,\n                       const FileMetaData* f) {\n  // null user_key occurs after all keys and is therefore never before *f\n  return (user_key != nullptr &&\n          ucmp->Compare(*user_key, f->smallest.user_key()) < 0);\n}\n\nbool SomeFileOverlapsRange(const InternalKeyComparator& icmp,\n                           bool disjoint_sorted_files,\n                           const std::vector<FileMetaData*>& files,\n                           const Slice* smallest_user_key,\n                           const Slice* largest_user_key) {\n  const Comparator* ucmp = icmp.user_comparator();\n  if (!disjoint_sorted_files) {\n    // Need to check against all files\n    for (size_t i = 0; i < files.size(); i++) {\n      const FileMetaData* f = files[i];\n      if (AfterFile(ucmp, smallest_user_key, f) ||\n          BeforeFile(ucmp, largest_user_key, f)) {\n        // No overlap\n      } else {\n        return true;  // Overlap\n      }\n    }\n    return false;\n  }\n\n  // Binary search over file list\n  uint32_t index = 0;\n  if (smallest_user_key != nullptr) {\n    // Find the earliest possible internal key for smallest_user_key\n    InternalKey small_key(*smallest_user_key, kMaxSequenceNumber,\n                          kValueTypeForSeek);\n    index = FindFile(icmp, files, small_key.Encode());\n  }\n\n  if (index >= files.size()) {\n    // beginning of range is after all files, so no overlap.\n    return false;\n  }\n\n  return !BeforeFile(ucmp, largest_user_key, files[index]);\n}\n\n// An internal iterator.  For a given version/level pair, yields\n// information about the files in the level.  For a given entry, key()\n// is the largest key that occurs in the file, and value() is an\n// 16-byte value containing the file number and file size, both\n// encoded using EncodeFixed64.\nclass Version::LevelFileNumIterator : public Iterator {\n public:\n  LevelFileNumIterator(const InternalKeyComparator& icmp,\n                       const std::vector<FileMetaData*>* flist)\n      : icmp_(icmp), flist_(flist), index_(flist->size()) {  // Marks as invalid\n  }\n  bool Valid() const override { return index_ < flist_->size(); }\n  void Seek(const Slice& target) override {\n    index_ = FindFile(icmp_, *flist_, target);\n  }\n  void SeekToFirst() override { index_ = 0; }\n  void SeekToLast() override {\n    index_ = flist_->empty() ? 0 : flist_->size() - 1;\n  }\n  void Next() override {\n    assert(Valid());\n    index_++;\n  }\n  void Prev() override {\n    assert(Valid());\n    if (index_ == 0) {\n      index_ = flist_->size();  // Marks as invalid\n    } else {\n      index_--;\n    }\n  }\n  Slice key() const override {\n    assert(Valid());\n    return (*flist_)[index_]->largest.Encode();\n  }\n  Slice value() const override {\n    assert(Valid());\n    EncodeFixed64(value_buf_, (*flist_)[index_]->number);\n    EncodeFixed64(value_buf_ + 8, (*flist_)[index_]->file_size);\n    return Slice(value_buf_, sizeof(value_buf_));\n  }\n  Status status() const override { return Status::OK(); }\n\n private:\n  const InternalKeyComparator icmp_;\n  const std::vector<FileMetaData*>* const flist_;\n  uint32_t index_;\n\n  // Backing store for value().  Holds the file number and size.\n  mutable char value_buf_[16];\n};\n\nstatic Iterator* GetFileIterator(void* arg, const ReadOptions& options,\n                                 const Slice& file_value) {\n  TableCache* cache = reinterpret_cast<TableCache*>(arg);\n  if (file_value.size() != 16) {\n    return NewErrorIterator(\n        Status::Corruption(\"FileReader invoked with unexpected value\"));\n  } else {\n    return cache->NewIterator(options, DecodeFixed64(file_value.data()),\n                              DecodeFixed64(file_value.data() + 8));\n  }\n}\n\nIterator* Version::NewConcatenatingIterator(const ReadOptions& options,\n                                            int level) const {\n  return NewTwoLevelIterator(\n      new LevelFileNumIterator(vset_->icmp_, &files_[level]), &GetFileIterator,\n      vset_->table_cache_, options);\n}\n\nvoid Version::AddIterators(const ReadOptions& options,\n                           std::vector<Iterator*>* iters) {\n  // Merge all level zero files together since they may overlap\n  for (size_t i = 0; i < files_[0].size(); i++) {\n    iters->push_back(vset_->table_cache_->NewIterator(\n        options, files_[0][i]->number, files_[0][i]->file_size));\n  }\n\n  // For levels > 0, we can use a concatenating iterator that sequentially\n  // walks through the non-overlapping files in the level, opening them\n  // lazily.\n  for (int level = 1; level < config::kNumLevels; level++) {\n    if (!files_[level].empty()) {\n      iters->push_back(NewConcatenatingIterator(options, level));\n    }\n  }\n}\n\n// Callback from TableCache::Get()\nnamespace {\nenum SaverState {\n  kNotFound,\n  kFound,\n  kDeleted,\n  kCorrupt,\n};\nstruct Saver {\n  SaverState state;\n  const Comparator* ucmp;\n  Slice user_key;\n  std::string* value;\n};\n}  // namespace\nstatic void SaveValue(void* arg, const Slice& ikey, const Slice& v) {\n  Saver* s = reinterpret_cast<Saver*>(arg);\n  ParsedInternalKey parsed_key;\n  if (!ParseInternalKey(ikey, &parsed_key)) {\n    s->state = kCorrupt;\n  } else {\n    if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) {\n      s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted;\n      if (s->state == kFound) {\n        s->value->assign(v.data(), v.size());\n      }\n    }\n  }\n}\n\nstatic bool NewestFirst(FileMetaData* a, FileMetaData* b) {\n  return a->number > b->number;\n}\n\nvoid Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,\n                                 bool (*func)(void*, int, FileMetaData*)) {\n  const Comparator* ucmp = vset_->icmp_.user_comparator();\n\n  // Search level-0 in order from newest to oldest.\n  std::vector<FileMetaData*> tmp;\n  tmp.reserve(files_[0].size());\n  for (uint32_t i = 0; i < files_[0].size(); i++) {\n    FileMetaData* f = files_[0][i];\n    if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&\n        ucmp->Compare(user_key, f->largest.user_key()) <= 0) {\n      tmp.push_back(f);\n    }\n  }\n  if (!tmp.empty()) {\n    std::sort(tmp.begin(), tmp.end(), NewestFirst);\n    for (uint32_t i = 0; i < tmp.size(); i++) {\n      if (!(*func)(arg, 0, tmp[i])) {\n        return;\n      }\n    }\n  }\n\n  // Search other levels.\n  for (int level = 1; level < config::kNumLevels; level++) {\n    size_t num_files = files_[level].size();\n    if (num_files == 0) continue;\n\n    // Binary search to find earliest index whose largest key >= internal_key.\n    uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);\n    if (index < num_files) {\n      FileMetaData* f = files_[level][index];\n      if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {\n        // All of \"f\" is past any data for user_key\n      } else {\n        if (!(*func)(arg, level, f)) {\n          return;\n        }\n      }\n    }\n  }\n}\n\nStatus Version::Get(const ReadOptions& options, const LookupKey& k,\n                    std::string* value, GetStats* stats) {\n  stats->seek_file = nullptr;\n  stats->seek_file_level = -1;\n\n  struct State {\n    Saver saver;\n    GetStats* stats;\n    const ReadOptions* options;\n    Slice ikey;\n    FileMetaData* last_file_read;\n    int last_file_read_level;\n\n    VersionSet* vset;\n    Status s;\n    bool found;\n\n    static bool Match(void* arg, int level, FileMetaData* f) {\n      State* state = reinterpret_cast<State*>(arg);\n\n      if (state->stats->seek_file == nullptr &&\n          state->last_file_read != nullptr) {\n        // We have had more than one seek for this read.  Charge the 1st file.\n        state->stats->seek_file = state->last_file_read;\n        state->stats->seek_file_level = state->last_file_read_level;\n      }\n\n      state->last_file_read = f;\n      state->last_file_read_level = level;\n\n      state->s = state->vset->table_cache_->Get(*state->options, f->number,\n                                                f->file_size, state->ikey,\n                                                &state->saver, SaveValue);\n      if (!state->s.ok()) {\n        state->found = true;\n        return false;\n      }\n      switch (state->saver.state) {\n        case kNotFound:\n          return true;  // Keep searching in other files\n        case kFound:\n          state->found = true;\n          return false;\n        case kDeleted:\n          return false;\n        case kCorrupt:\n          state->s =\n              Status::Corruption(\"corrupted key for \", state->saver.user_key);\n          state->found = true;\n          return false;\n      }\n\n      // Not reached. Added to avoid false compilation warnings of\n      // \"control reaches end of non-void function\".\n      return false;\n    }\n  };\n\n  State state;\n  state.found = false;\n  state.stats = stats;\n  state.last_file_read = nullptr;\n  state.last_file_read_level = -1;\n\n  state.options = &options;\n  state.ikey = k.internal_key();\n  state.vset = vset_;\n\n  state.saver.state = kNotFound;\n  state.saver.ucmp = vset_->icmp_.user_comparator();\n  state.saver.user_key = k.user_key();\n  state.saver.value = value;\n\n  ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match);\n\n  return state.found ? state.s : Status::NotFound(Slice());\n}\n\nbool Version::UpdateStats(const GetStats& stats) {\n  FileMetaData* f = stats.seek_file;\n  if (f != nullptr) {\n    f->allowed_seeks--;\n    if (f->allowed_seeks <= 0 && file_to_compact_ == nullptr) {\n      file_to_compact_ = f;\n      file_to_compact_level_ = stats.seek_file_level;\n      return true;\n    }\n  }\n  return false;\n}\n\nbool Version::RecordReadSample(Slice internal_key) {\n  ParsedInternalKey ikey;\n  if (!ParseInternalKey(internal_key, &ikey)) {\n    return false;\n  }\n\n  struct State {\n    GetStats stats;  // Holds first matching file\n    int matches;\n\n    static bool Match(void* arg, int level, FileMetaData* f) {\n      State* state = reinterpret_cast<State*>(arg);\n      state->matches++;\n      if (state->matches == 1) {\n        // Remember first match.\n        state->stats.seek_file = f;\n        state->stats.seek_file_level = level;\n      }\n      // We can stop iterating once we have a second match.\n      return state->matches < 2;\n    }\n  };\n\n  State state;\n  state.matches = 0;\n  ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match);\n\n  // Must have at least two matches since we want to merge across\n  // files. But what if we have a single file that contains many\n  // overwrites and deletions?  Should we have another mechanism for\n  // finding such files?\n  if (state.matches >= 2) {\n    // 1MB cost is about 1 seek (see comment in Builder::Apply).\n    return UpdateStats(state.stats);\n  }\n  return false;\n}\n\nvoid Version::Ref() { ++refs_; }\n\nvoid Version::Unref() {\n  assert(this != &vset_->dummy_versions_);\n  assert(refs_ >= 1);\n  --refs_;\n  if (refs_ == 0) {\n    delete this;\n  }\n}\n\nbool Version::OverlapInLevel(int level, const Slice* smallest_user_key,\n                             const Slice* largest_user_key) {\n  return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level],\n                               smallest_user_key, largest_user_key);\n}\n\nint Version::PickLevelForMemTableOutput(const Slice& smallest_user_key,\n                                        const Slice& largest_user_key) {\n  int level = 0;\n  if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) {\n    // Push to next level if there is no overlap in next level,\n    // and the #bytes overlapping in the level after that are limited.\n    InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek);\n    InternalKey limit(largest_user_key, 0, static_cast<ValueType>(0));\n    std::vector<FileMetaData*> overlaps;\n    while (level < config::kMaxMemCompactLevel) {\n      if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {\n        break;\n      }\n      if (level + 2 < config::kNumLevels) {\n        // Check that file does not overlap too many grandparent bytes.\n        GetOverlappingInputs(level + 2, &start, &limit, &overlaps);\n        const int64_t sum = TotalFileSize(overlaps);\n        if (sum > MaxGrandParentOverlapBytes(vset_->options_)) {\n          break;\n        }\n      }\n      level++;\n    }\n  }\n  return level;\n}\n\n// Store in \"*inputs\" all files in \"level\" that overlap [begin,end]\nvoid Version::GetOverlappingInputs(int level, const InternalKey* begin,\n                                   const InternalKey* end,\n                                   std::vector<FileMetaData*>* inputs) {\n  assert(level >= 0);\n  assert(level < config::kNumLevels);\n  inputs->clear();\n  Slice user_begin, user_end;\n  if (begin != nullptr) {\n    user_begin = begin->user_key();\n  }\n  if (end != nullptr) {\n    user_end = end->user_key();\n  }\n  const Comparator* user_cmp = vset_->icmp_.user_comparator();\n  for (size_t i = 0; i < files_[level].size();) {\n    FileMetaData* f = files_[level][i++];\n    const Slice file_start = f->smallest.user_key();\n    const Slice file_limit = f->largest.user_key();\n    if (begin != nullptr && user_cmp->Compare(file_limit, user_begin) < 0) {\n      // \"f\" is completely before specified range; skip it\n    } else if (end != nullptr && user_cmp->Compare(file_start, user_end) > 0) {\n      // \"f\" is completely after specified range; skip it\n    } else {\n      inputs->push_back(f);\n      if (level == 0) {\n        // Level-0 files may overlap each other.  So check if the newly\n        // added file has expanded the range.  If so, restart search.\n        if (begin != nullptr && user_cmp->Compare(file_start, user_begin) < 0) {\n          user_begin = file_start;\n          inputs->clear();\n          i = 0;\n        } else if (end != nullptr &&\n                   user_cmp->Compare(file_limit, user_end) > 0) {\n          user_end = file_limit;\n          inputs->clear();\n          i = 0;\n        }\n      }\n    }\n  }\n}\n\nstd::string Version::DebugString() const {\n  std::string r;\n  for (int level = 0; level < config::kNumLevels; level++) {\n    // E.g.,\n    //   --- level 1 ---\n    //   17:123['a' .. 'd']\n    //   20:43['e' .. 'g']\n    r.append(\"--- level \");\n    AppendNumberTo(&r, level);\n    r.append(\" ---\\n\");\n    const std::vector<FileMetaData*>& files = files_[level];\n    for (size_t i = 0; i < files.size(); i++) {\n      r.push_back(' ');\n      AppendNumberTo(&r, files[i]->number);\n      r.push_back(':');\n      AppendNumberTo(&r, files[i]->file_size);\n      r.append(\"[\");\n      r.append(files[i]->smallest.DebugString());\n      r.append(\" .. \");\n      r.append(files[i]->largest.DebugString());\n      r.append(\"]\\n\");\n    }\n  }\n  return r;\n}\n\n// A helper class so we can efficiently apply a whole sequence\n// of edits to a particular state without creating intermediate\n// Versions that contain full copies of the intermediate state.\nclass VersionSet::Builder {\n private:\n  // Helper to sort by v->files_[file_number].smallest\n  struct BySmallestKey {\n    const InternalKeyComparator* internal_comparator;\n\n    bool operator()(FileMetaData* f1, FileMetaData* f2) const {\n      int r = internal_comparator->Compare(f1->smallest, f2->smallest);\n      if (r != 0) {\n        return (r < 0);\n      } else {\n        // Break ties by file number\n        return (f1->number < f2->number);\n      }\n    }\n  };\n\n  typedef std::set<FileMetaData*, BySmallestKey> FileSet;\n  struct LevelState {\n    std::set<uint64_t> deleted_files;\n    FileSet* added_files;\n  };\n\n  VersionSet* vset_;\n  Version* base_;\n  LevelState levels_[config::kNumLevels];\n\n public:\n  // Initialize a builder with the files from *base and other info from *vset\n  Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) {\n    base_->Ref();\n    BySmallestKey cmp;\n    cmp.internal_comparator = &vset_->icmp_;\n    for (int level = 0; level < config::kNumLevels; level++) {\n      levels_[level].added_files = new FileSet(cmp);\n    }\n  }\n\n  ~Builder() {\n    for (int level = 0; level < config::kNumLevels; level++) {\n      const FileSet* added = levels_[level].added_files;\n      std::vector<FileMetaData*> to_unref;\n      to_unref.reserve(added->size());\n      for (FileSet::const_iterator it = added->begin(); it != added->end();\n           ++it) {\n        to_unref.push_back(*it);\n      }\n      delete added;\n      for (uint32_t i = 0; i < to_unref.size(); i++) {\n        FileMetaData* f = to_unref[i];\n        f->refs--;\n        if (f->refs <= 0) {\n          delete f;\n        }\n      }\n    }\n    base_->Unref();\n  }\n\n  // Apply all of the edits in *edit to the current state.\n  void Apply(VersionEdit* edit) {\n    // Update compaction pointers\n    for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {\n      const int level = edit->compact_pointers_[i].first;\n      vset_->compact_pointer_[level] =\n          edit->compact_pointers_[i].second.Encode().ToString();\n    }\n\n    // Delete files\n    for (const auto& deleted_file_set_kvp : edit->deleted_files_) {\n      const int level = deleted_file_set_kvp.first;\n      const uint64_t number = deleted_file_set_kvp.second;\n      levels_[level].deleted_files.insert(number);\n    }\n\n    // Add new files\n    for (size_t i = 0; i < edit->new_files_.size(); i++) {\n      const int level = edit->new_files_[i].first;\n      FileMetaData* f = new FileMetaData(edit->new_files_[i].second);\n      f->refs = 1;\n\n      // We arrange to automatically compact this file after\n      // a certain number of seeks.  Let's assume:\n      //   (1) One seek costs 10ms\n      //   (2) Writing or reading 1MB costs 10ms (100MB/s)\n      //   (3) A compaction of 1MB does 25MB of IO:\n      //         1MB read from this level\n      //         10-12MB read from next level (boundaries may be misaligned)\n      //         10-12MB written to next level\n      // This implies that 25 seeks cost the same as the compaction\n      // of 1MB of data.  I.e., one seek costs approximately the\n      // same as the compaction of 40KB of data.  We are a little\n      // conservative and allow approximately one seek for every 16KB\n      // of data before triggering a compaction.\n      f->allowed_seeks = static_cast<int>((f->file_size / 16384U));\n      if (f->allowed_seeks < 100) f->allowed_seeks = 100;\n\n      levels_[level].deleted_files.erase(f->number);\n      levels_[level].added_files->insert(f);\n    }\n  }\n\n  // Save the current state in *v.\n  void SaveTo(Version* v) {\n    BySmallestKey cmp;\n    cmp.internal_comparator = &vset_->icmp_;\n    for (int level = 0; level < config::kNumLevels; level++) {\n      // Merge the set of added files with the set of pre-existing files.\n      // Drop any deleted files.  Store the result in *v.\n      const std::vector<FileMetaData*>& base_files = base_->files_[level];\n      std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();\n      std::vector<FileMetaData*>::const_iterator base_end = base_files.end();\n      const FileSet* added_files = levels_[level].added_files;\n      v->files_[level].reserve(base_files.size() + added_files->size());\n      for (const auto& added_file : *added_files) {\n        // Add all smaller files listed in base_\n        for (std::vector<FileMetaData*>::const_iterator bpos =\n                 std::upper_bound(base_iter, base_end, added_file, cmp);\n             base_iter != bpos; ++base_iter) {\n          MaybeAddFile(v, level, *base_iter);\n        }\n\n        MaybeAddFile(v, level, added_file);\n      }\n\n      // Add remaining base files\n      for (; base_iter != base_end; ++base_iter) {\n        MaybeAddFile(v, level, *base_iter);\n      }\n\n#ifndef NDEBUG\n      // Make sure there is no overlap in levels > 0\n      if (level > 0) {\n        for (uint32_t i = 1; i < v->files_[level].size(); i++) {\n          const InternalKey& prev_end = v->files_[level][i - 1]->largest;\n          const InternalKey& this_begin = v->files_[level][i]->smallest;\n          if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {\n            fprintf(stderr, \"overlapping ranges in same level %s vs. %s\\n\",\n                    prev_end.DebugString().c_str(),\n                    this_begin.DebugString().c_str());\n            abort();\n          }\n        }\n      }\n#endif\n    }\n  }\n\n  void MaybeAddFile(Version* v, int level, FileMetaData* f) {\n    if (levels_[level].deleted_files.count(f->number) > 0) {\n      // File is deleted: do nothing\n    } else {\n      std::vector<FileMetaData*>* files = &v->files_[level];\n      if (level > 0 && !files->empty()) {\n        // Must not overlap\n        assert(vset_->icmp_.Compare((*files)[files->size() - 1]->largest,\n                                    f->smallest) < 0);\n      }\n      f->refs++;\n      files->push_back(f);\n    }\n  }\n};\n\nVersionSet::VersionSet(const std::string& dbname, const Options* options,\n                       TableCache* table_cache,\n                       const InternalKeyComparator* cmp)\n    : env_(options->env),\n      dbname_(dbname),\n      options_(options),\n      table_cache_(table_cache),\n      icmp_(*cmp),\n      next_file_number_(2),\n      manifest_file_number_(0),  // Filled by Recover()\n      last_sequence_(0),\n      log_number_(0),\n      prev_log_number_(0),\n      descriptor_file_(nullptr),\n      descriptor_log_(nullptr),\n      dummy_versions_(this),\n      current_(nullptr) {\n  AppendVersion(new Version(this));\n}\n\nVersionSet::~VersionSet() {\n  current_->Unref();\n  assert(dummy_versions_.next_ == &dummy_versions_);  // List must be empty\n  delete descriptor_log_;\n  delete descriptor_file_;\n}\n\nvoid VersionSet::AppendVersion(Version* v) {\n  // Make \"v\" current\n  assert(v->refs_ == 0);\n  assert(v != current_);\n  if (current_ != nullptr) {\n    current_->Unref();\n  }\n  current_ = v;\n  v->Ref();\n\n  // Append to linked list\n  v->prev_ = dummy_versions_.prev_;\n  v->next_ = &dummy_versions_;\n  v->prev_->next_ = v;\n  v->next_->prev_ = v;\n}\n\nStatus VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {\n  if (edit->has_log_number_) {\n    assert(edit->log_number_ >= log_number_);\n    assert(edit->log_number_ < next_file_number_);\n  } else {\n    edit->SetLogNumber(log_number_);\n  }\n\n  if (!edit->has_prev_log_number_) {\n    edit->SetPrevLogNumber(prev_log_number_);\n  }\n\n  edit->SetNextFile(next_file_number_);\n  edit->SetLastSequence(last_sequence_);\n\n  Version* v = new Version(this);\n  {\n    Builder builder(this, current_);\n    builder.Apply(edit);\n    builder.SaveTo(v);\n  }\n  Finalize(v);\n\n  // Initialize new descriptor log file if necessary by creating\n  // a temporary file that contains a snapshot of the current version.\n  std::string new_manifest_file;\n  Status s;\n  if (descriptor_log_ == nullptr) {\n    // No reason to unlock *mu here since we only hit this path in the\n    // first call to LogAndApply (when opening the database).\n    assert(descriptor_file_ == nullptr);\n    new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);\n    edit->SetNextFile(next_file_number_);\n    s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);\n    if (s.ok()) {\n      descriptor_log_ = new log::Writer(descriptor_file_);\n      s = WriteSnapshot(descriptor_log_);\n    }\n  }\n\n  // Unlock during expensive MANIFEST log write\n  {\n    mu->Unlock();\n\n    // Write new record to MANIFEST log\n    if (s.ok()) {\n      std::string record;\n      edit->EncodeTo(&record);\n      s = descriptor_log_->AddRecord(record);\n      if (s.ok()) {\n        s = descriptor_file_->Sync();\n      }\n      if (!s.ok()) {\n        Log(options_->info_log, \"MANIFEST write: %s\\n\", s.ToString().c_str());\n      }\n    }\n\n    // If we just created a new descriptor file, install it by writing a\n    // new CURRENT file that points to it.\n    if (s.ok() && !new_manifest_file.empty()) {\n      s = SetCurrentFile(env_, dbname_, manifest_file_number_);\n    }\n\n    mu->Lock();\n  }\n\n  // Install the new version\n  if (s.ok()) {\n    AppendVersion(v);\n    log_number_ = edit->log_number_;\n    prev_log_number_ = edit->prev_log_number_;\n  } else {\n    delete v;\n    if (!new_manifest_file.empty()) {\n      delete descriptor_log_;\n      delete descriptor_file_;\n      descriptor_log_ = nullptr;\n      descriptor_file_ = nullptr;\n      env_->DeleteFile(new_manifest_file);\n    }\n  }\n\n  return s;\n}\n\nStatus VersionSet::Recover(bool* save_manifest) {\n  struct LogReporter : public log::Reader::Reporter {\n    Status* status;\n    void Corruption(size_t bytes, const Status& s) override {\n      if (this->status->ok()) *this->status = s;\n    }\n  };\n\n  // Read \"CURRENT\" file, which contains a pointer to the current manifest file\n  std::string current;\n  Status s = ReadFileToString(env_, CurrentFileName(dbname_), &current);\n  if (!s.ok()) {\n    return s;\n  }\n  if (current.empty() || current[current.size() - 1] != '\\n') {\n    return Status::Corruption(\"CURRENT file does not end with newline\");\n  }\n  current.resize(current.size() - 1);\n\n  std::string dscname = dbname_ + \"/\" + current;\n  SequentialFile* file;\n  s = env_->NewSequentialFile(dscname, &file);\n  if (!s.ok()) {\n    if (s.IsNotFound()) {\n      return Status::Corruption(\"CURRENT points to a non-existent file\",\n                                s.ToString());\n    }\n    return s;\n  }\n\n  bool have_log_number = false;\n  bool have_prev_log_number = false;\n  bool have_next_file = false;\n  bool have_last_sequence = false;\n  uint64_t next_file = 0;\n  uint64_t last_sequence = 0;\n  uint64_t log_number = 0;\n  uint64_t prev_log_number = 0;\n  Builder builder(this, current_);\n\n  {\n    LogReporter reporter;\n    reporter.status = &s;\n    log::Reader reader(file, &reporter, true /*checksum*/,\n                       0 /*initial_offset*/);\n    Slice record;\n    std::string scratch;\n    while (reader.ReadRecord(&record, &scratch) && s.ok()) {\n      VersionEdit edit;\n      s = edit.DecodeFrom(record);\n      if (s.ok()) {\n        if (edit.has_comparator_ &&\n            edit.comparator_ != icmp_.user_comparator()->Name()) {\n          s = Status::InvalidArgument(\n              edit.comparator_ + \" does not match existing comparator \",\n              icmp_.user_comparator()->Name());\n        }\n      }\n\n      if (s.ok()) {\n        builder.Apply(&edit);\n      }\n\n      if (edit.has_log_number_) {\n        log_number = edit.log_number_;\n        have_log_number = true;\n      }\n\n      if (edit.has_prev_log_number_) {\n        prev_log_number = edit.prev_log_number_;\n        have_prev_log_number = true;\n      }\n\n      if (edit.has_next_file_number_) {\n        next_file = edit.next_file_number_;\n        have_next_file = true;\n      }\n\n      if (edit.has_last_sequence_) {\n        last_sequence = edit.last_sequence_;\n        have_last_sequence = true;\n      }\n    }\n  }\n  delete file;\n  file = nullptr;\n\n  if (s.ok()) {\n    if (!have_next_file) {\n      s = Status::Corruption(\"no meta-nextfile entry in descriptor\");\n    } else if (!have_log_number) {\n      s = Status::Corruption(\"no meta-lognumber entry in descriptor\");\n    } else if (!have_last_sequence) {\n      s = Status::Corruption(\"no last-sequence-number entry in descriptor\");\n    }\n\n    if (!have_prev_log_number) {\n      prev_log_number = 0;\n    }\n\n    MarkFileNumberUsed(prev_log_number);\n    MarkFileNumberUsed(log_number);\n  }\n\n  if (s.ok()) {\n    Version* v = new Version(this);\n    builder.SaveTo(v);\n    // Install recovered version\n    Finalize(v);\n    AppendVersion(v);\n    manifest_file_number_ = next_file;\n    next_file_number_ = next_file + 1;\n    last_sequence_ = last_sequence;\n    log_number_ = log_number;\n    prev_log_number_ = prev_log_number;\n\n    // See if we can reuse the existing MANIFEST file.\n    if (ReuseManifest(dscname, current)) {\n      // No need to save new manifest\n    } else {\n      *save_manifest = true;\n    }\n  }\n\n  return s;\n}\n\nbool VersionSet::ReuseManifest(const std::string& dscname,\n                               const std::string& dscbase) {\n  if (!options_->reuse_logs) {\n    return false;\n  }\n  FileType manifest_type;\n  uint64_t manifest_number;\n  uint64_t manifest_size;\n  if (!ParseFileName(dscbase, &manifest_number, &manifest_type) ||\n      manifest_type != kDescriptorFile ||\n      !env_->GetFileSize(dscname, &manifest_size).ok() ||\n      // Make new compacted MANIFEST if old one is too big\n      manifest_size >= TargetFileSize(options_)) {\n    return false;\n  }\n\n  assert(descriptor_file_ == nullptr);\n  assert(descriptor_log_ == nullptr);\n  Status r = env_->NewAppendableFile(dscname, &descriptor_file_);\n  if (!r.ok()) {\n    Log(options_->info_log, \"Reuse MANIFEST: %s\\n\", r.ToString().c_str());\n    assert(descriptor_file_ == nullptr);\n    return false;\n  }\n\n  Log(options_->info_log, \"Reusing MANIFEST %s\\n\", dscname.c_str());\n  descriptor_log_ = new log::Writer(descriptor_file_, manifest_size);\n  manifest_file_number_ = manifest_number;\n  return true;\n}\n\nvoid VersionSet::MarkFileNumberUsed(uint64_t number) {\n  if (next_file_number_ <= number) {\n    next_file_number_ = number + 1;\n  }\n}\n\nvoid VersionSet::Finalize(Version* v) {\n  // Precomputed best level for next compaction\n  int best_level = -1;\n  double best_score = -1;\n\n  for (int level = 0; level < config::kNumLevels - 1; level++) {\n    double score;\n    if (level == 0) {\n      // We treat level-0 specially by bounding the number of files\n      // instead of number of bytes for two reasons:\n      //\n      // (1) With larger write-buffer sizes, it is nice not to do too\n      // many level-0 compactions.\n      //\n      // (2) The files in level-0 are merged on every read and\n      // therefore we wish to avoid too many files when the individual\n      // file size is small (perhaps because of a small write-buffer\n      // setting, or very high compression ratios, or lots of\n      // overwrites/deletions).\n      score = v->files_[level].size() /\n              static_cast<double>(config::kL0_CompactionTrigger);\n    } else {\n      // Compute the ratio of current size to size limit.\n      const uint64_t level_bytes = TotalFileSize(v->files_[level]);\n      score =\n          static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level);\n    }\n\n    if (score > best_score) {\n      best_level = level;\n      best_score = score;\n    }\n  }\n\n  v->compaction_level_ = best_level;\n  v->compaction_score_ = best_score;\n}\n\nStatus VersionSet::WriteSnapshot(log::Writer* log) {\n  // TODO: Break up into multiple records to reduce memory usage on recovery?\n\n  // Save metadata\n  VersionEdit edit;\n  edit.SetComparatorName(icmp_.user_comparator()->Name());\n\n  // Save compaction pointers\n  for (int level = 0; level < config::kNumLevels; level++) {\n    if (!compact_pointer_[level].empty()) {\n      InternalKey key;\n      key.DecodeFrom(compact_pointer_[level]);\n      edit.SetCompactPointer(level, key);\n    }\n  }\n\n  // Save files\n  for (int level = 0; level < config::kNumLevels; level++) {\n    const std::vector<FileMetaData*>& files = current_->files_[level];\n    for (size_t i = 0; i < files.size(); i++) {\n      const FileMetaData* f = files[i];\n      edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);\n    }\n  }\n\n  std::string record;\n  edit.EncodeTo(&record);\n  return log->AddRecord(record);\n}\n\nint VersionSet::NumLevelFiles(int level) const {\n  assert(level >= 0);\n  assert(level < config::kNumLevels);\n  return current_->files_[level].size();\n}\n\nconst char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {\n  // Update code if kNumLevels changes\n  static_assert(config::kNumLevels == 7, \"\");\n  snprintf(scratch->buffer, sizeof(scratch->buffer),\n           \"files[ %d %d %d %d %d %d %d ]\", int(current_->files_[0].size()),\n           int(current_->files_[1].size()), int(current_->files_[2].size()),\n           int(current_->files_[3].size()), int(current_->files_[4].size()),\n           int(current_->files_[5].size()), int(current_->files_[6].size()));\n  return scratch->buffer;\n}\n\nuint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {\n  uint64_t result = 0;\n  for (int level = 0; level < config::kNumLevels; level++) {\n    const std::vector<FileMetaData*>& files = v->files_[level];\n    for (size_t i = 0; i < files.size(); i++) {\n      if (icmp_.Compare(files[i]->largest, ikey) <= 0) {\n        // Entire file is before \"ikey\", so just add the file size\n        result += files[i]->file_size;\n      } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {\n        // Entire file is after \"ikey\", so ignore\n        if (level > 0) {\n          // Files other than level 0 are sorted by meta->smallest, so\n          // no further files in this level will contain data for\n          // \"ikey\".\n          break;\n        }\n      } else {\n        // \"ikey\" falls in the range for this table.  Add the\n        // approximate offset of \"ikey\" within the table.\n        Table* tableptr;\n        Iterator* iter = table_cache_->NewIterator(\n            ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);\n        if (tableptr != nullptr) {\n          result += tableptr->ApproximateOffsetOf(ikey.Encode());\n        }\n        delete iter;\n      }\n    }\n  }\n  return result;\n}\n\nvoid VersionSet::AddLiveFiles(std::set<uint64_t>* live) {\n  for (Version* v = dummy_versions_.next_; v != &dummy_versions_;\n       v = v->next_) {\n    for (int level = 0; level < config::kNumLevels; level++) {\n      const std::vector<FileMetaData*>& files = v->files_[level];\n      for (size_t i = 0; i < files.size(); i++) {\n        live->insert(files[i]->number);\n      }\n    }\n  }\n}\n\nint64_t VersionSet::NumLevelBytes(int level) const {\n  assert(level >= 0);\n  assert(level < config::kNumLevels);\n  return TotalFileSize(current_->files_[level]);\n}\n\nint64_t VersionSet::MaxNextLevelOverlappingBytes() {\n  int64_t result = 0;\n  std::vector<FileMetaData*> overlaps;\n  for (int level = 1; level < config::kNumLevels - 1; level++) {\n    for (size_t i = 0; i < current_->files_[level].size(); i++) {\n      const FileMetaData* f = current_->files_[level][i];\n      current_->GetOverlappingInputs(level + 1, &f->smallest, &f->largest,\n                                     &overlaps);\n      const int64_t sum = TotalFileSize(overlaps);\n      if (sum > result) {\n        result = sum;\n      }\n    }\n  }\n  return result;\n}\n\n// Stores the minimal range that covers all entries in inputs in\n// *smallest, *largest.\n// REQUIRES: inputs is not empty\nvoid VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,\n                          InternalKey* smallest, InternalKey* largest) {\n  assert(!inputs.empty());\n  smallest->Clear();\n  largest->Clear();\n  for (size_t i = 0; i < inputs.size(); i++) {\n    FileMetaData* f = inputs[i];\n    if (i == 0) {\n      *smallest = f->smallest;\n      *largest = f->largest;\n    } else {\n      if (icmp_.Compare(f->smallest, *smallest) < 0) {\n        *smallest = f->smallest;\n      }\n      if (icmp_.Compare(f->largest, *largest) > 0) {\n        *largest = f->largest;\n      }\n    }\n  }\n}\n\n// Stores the minimal range that covers all entries in inputs1 and inputs2\n// in *smallest, *largest.\n// REQUIRES: inputs is not empty\nvoid VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,\n                           const std::vector<FileMetaData*>& inputs2,\n                           InternalKey* smallest, InternalKey* largest) {\n  std::vector<FileMetaData*> all = inputs1;\n  all.insert(all.end(), inputs2.begin(), inputs2.end());\n  GetRange(all, smallest, largest);\n}\n\nIterator* VersionSet::MakeInputIterator(Compaction* c) {\n  ReadOptions options;\n  options.verify_checksums = options_->paranoid_checks;\n  options.fill_cache = false;\n\n  // Level-0 files have to be merged together.  For other levels,\n  // we will make a concatenating iterator per level.\n  // TODO(opt): use concatenating iterator for level-0 if there is no overlap\n  const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);\n  Iterator** list = new Iterator*[space];\n  int num = 0;\n  for (int which = 0; which < 2; which++) {\n    if (!c->inputs_[which].empty()) {\n      if (c->level() + which == 0) {\n        const std::vector<FileMetaData*>& files = c->inputs_[which];\n        for (size_t i = 0; i < files.size(); i++) {\n          list[num++] = table_cache_->NewIterator(options, files[i]->number,\n                                                  files[i]->file_size);\n        }\n      } else {\n        // Create concatenating iterator for the files from this level\n        list[num++] = NewTwoLevelIterator(\n            new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),\n            &GetFileIterator, table_cache_, options);\n      }\n    }\n  }\n  assert(num <= space);\n  Iterator* result = NewMergingIterator(&icmp_, list, num);\n  delete[] list;\n  return result;\n}\n\nCompaction* VersionSet::PickCompaction() {\n  Compaction* c;\n  int level;\n\n  // We prefer compactions triggered by too much data in a level over\n  // the compactions triggered by seeks.\n  const bool size_compaction = (current_->compaction_score_ >= 1);\n  const bool seek_compaction = (current_->file_to_compact_ != nullptr);\n  if (size_compaction) {\n    level = current_->compaction_level_;\n    assert(level >= 0);\n    assert(level + 1 < config::kNumLevels);\n    c = new Compaction(options_, level);\n\n    // Pick the first file that comes after compact_pointer_[level]\n    for (size_t i = 0; i < current_->files_[level].size(); i++) {\n      FileMetaData* f = current_->files_[level][i];\n      if (compact_pointer_[level].empty() ||\n          icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) {\n        c->inputs_[0].push_back(f);\n        break;\n      }\n    }\n    if (c->inputs_[0].empty()) {\n      // Wrap-around to the beginning of the key space\n      c->inputs_[0].push_back(current_->files_[level][0]);\n    }\n  } else if (seek_compaction) {\n    level = current_->file_to_compact_level_;\n    c = new Compaction(options_, level);\n    c->inputs_[0].push_back(current_->file_to_compact_);\n  } else {\n    return nullptr;\n  }\n\n  c->input_version_ = current_;\n  c->input_version_->Ref();\n\n  // Files in level 0 may overlap each other, so pick up all overlapping ones\n  if (level == 0) {\n    InternalKey smallest, largest;\n    GetRange(c->inputs_[0], &smallest, &largest);\n    // Note that the next call will discard the file we placed in\n    // c->inputs_[0] earlier and replace it with an overlapping set\n    // which will include the picked file.\n    current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]);\n    assert(!c->inputs_[0].empty());\n  }\n\n  SetupOtherInputs(c);\n\n  return c;\n}\n\n// Finds the largest key in a vector of files. Returns true if files it not\n// empty.\nbool FindLargestKey(const InternalKeyComparator& icmp,\n                    const std::vector<FileMetaData*>& files,\n                    InternalKey* largest_key) {\n  if (files.empty()) {\n    return false;\n  }\n  *largest_key = files[0]->largest;\n  for (size_t i = 1; i < files.size(); ++i) {\n    FileMetaData* f = files[i];\n    if (icmp.Compare(f->largest, *largest_key) > 0) {\n      *largest_key = f->largest;\n    }\n  }\n  return true;\n}\n\n// Finds minimum file b2=(l2, u2) in level file for which l2 > u1 and\n// user_key(l2) = user_key(u1)\nFileMetaData* FindSmallestBoundaryFile(\n    const InternalKeyComparator& icmp,\n    const std::vector<FileMetaData*>& level_files,\n    const InternalKey& largest_key) {\n  const Comparator* user_cmp = icmp.user_comparator();\n  FileMetaData* smallest_boundary_file = nullptr;\n  for (size_t i = 0; i < level_files.size(); ++i) {\n    FileMetaData* f = level_files[i];\n    if (icmp.Compare(f->smallest, largest_key) > 0 &&\n        user_cmp->Compare(f->smallest.user_key(), largest_key.user_key()) ==\n            0) {\n      if (smallest_boundary_file == nullptr ||\n          icmp.Compare(f->smallest, smallest_boundary_file->smallest) < 0) {\n        smallest_boundary_file = f;\n      }\n    }\n  }\n  return smallest_boundary_file;\n}\n\n// Extracts the largest file b1 from |compaction_files| and then searches for a\n// b2 in |level_files| for which user_key(u1) = user_key(l2). If it finds such a\n// file b2 (known as a boundary file) it adds it to |compaction_files| and then\n// searches again using this new upper bound.\n//\n// If there are two blocks, b1=(l1, u1) and b2=(l2, u2) and\n// user_key(u1) = user_key(l2), and if we compact b1 but not b2 then a\n// subsequent get operation will yield an incorrect result because it will\n// return the record from b2 in level i rather than from b1 because it searches\n// level by level for records matching the supplied user key.\n//\n// parameters:\n//   in     level_files:      List of files to search for boundary files.\n//   in/out compaction_files: List of files to extend by adding boundary files.\nvoid AddBoundaryInputs(const InternalKeyComparator& icmp,\n                       const std::vector<FileMetaData*>& level_files,\n                       std::vector<FileMetaData*>* compaction_files) {\n  InternalKey largest_key;\n\n  // Quick return if compaction_files is empty.\n  if (!FindLargestKey(icmp, *compaction_files, &largest_key)) {\n    return;\n  }\n\n  bool continue_searching = true;\n  while (continue_searching) {\n    FileMetaData* smallest_boundary_file =\n        FindSmallestBoundaryFile(icmp, level_files, largest_key);\n\n    // If a boundary file was found advance largest_key, otherwise we're done.\n    if (smallest_boundary_file != NULL) {\n      compaction_files->push_back(smallest_boundary_file);\n      largest_key = smallest_boundary_file->largest;\n    } else {\n      continue_searching = false;\n    }\n  }\n}\n\nvoid VersionSet::SetupOtherInputs(Compaction* c) {\n  const int level = c->level();\n  InternalKey smallest, largest;\n\n  AddBoundaryInputs(icmp_, current_->files_[level], &c->inputs_[0]);\n  GetRange(c->inputs_[0], &smallest, &largest);\n\n  current_->GetOverlappingInputs(level + 1, &smallest, &largest,\n                                 &c->inputs_[1]);\n\n  // Get entire range covered by compaction\n  InternalKey all_start, all_limit;\n  GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);\n\n  // See if we can grow the number of inputs in \"level\" without\n  // changing the number of \"level+1\" files we pick up.\n  if (!c->inputs_[1].empty()) {\n    std::vector<FileMetaData*> expanded0;\n    current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0);\n    AddBoundaryInputs(icmp_, current_->files_[level], &expanded0);\n    const int64_t inputs0_size = TotalFileSize(c->inputs_[0]);\n    const int64_t inputs1_size = TotalFileSize(c->inputs_[1]);\n    const int64_t expanded0_size = TotalFileSize(expanded0);\n    if (expanded0.size() > c->inputs_[0].size() &&\n        inputs1_size + expanded0_size <\n            ExpandedCompactionByteSizeLimit(options_)) {\n      InternalKey new_start, new_limit;\n      GetRange(expanded0, &new_start, &new_limit);\n      std::vector<FileMetaData*> expanded1;\n      current_->GetOverlappingInputs(level + 1, &new_start, &new_limit,\n                                     &expanded1);\n      if (expanded1.size() == c->inputs_[1].size()) {\n        Log(options_->info_log,\n            \"Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\\n\",\n            level, int(c->inputs_[0].size()), int(c->inputs_[1].size()),\n            long(inputs0_size), long(inputs1_size), int(expanded0.size()),\n            int(expanded1.size()), long(expanded0_size), long(inputs1_size));\n        smallest = new_start;\n        largest = new_limit;\n        c->inputs_[0] = expanded0;\n        c->inputs_[1] = expanded1;\n        GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);\n      }\n    }\n  }\n\n  // Compute the set of grandparent files that overlap this compaction\n  // (parent == level+1; grandparent == level+2)\n  if (level + 2 < config::kNumLevels) {\n    current_->GetOverlappingInputs(level + 2, &all_start, &all_limit,\n                                   &c->grandparents_);\n  }\n\n  // Update the place where we will do the next compaction for this level.\n  // We update this immediately instead of waiting for the VersionEdit\n  // to be applied so that if the compaction fails, we will try a different\n  // key range next time.\n  compact_pointer_[level] = largest.Encode().ToString();\n  c->edit_.SetCompactPointer(level, largest);\n}\n\nCompaction* VersionSet::CompactRange(int level, const InternalKey* begin,\n                                     const InternalKey* end) {\n  std::vector<FileMetaData*> inputs;\n  current_->GetOverlappingInputs(level, begin, end, &inputs);\n  if (inputs.empty()) {\n    return nullptr;\n  }\n\n  // Avoid compacting too much in one shot in case the range is large.\n  // But we cannot do this for level-0 since level-0 files can overlap\n  // and we must not pick one file and drop another older file if the\n  // two files overlap.\n  if (level > 0) {\n    const uint64_t limit = MaxFileSizeForLevel(options_, level);\n    uint64_t total = 0;\n    for (size_t i = 0; i < inputs.size(); i++) {\n      uint64_t s = inputs[i]->file_size;\n      total += s;\n      if (total >= limit) {\n        inputs.resize(i + 1);\n        break;\n      }\n    }\n  }\n\n  Compaction* c = new Compaction(options_, level);\n  c->input_version_ = current_;\n  c->input_version_->Ref();\n  c->inputs_[0] = inputs;\n  SetupOtherInputs(c);\n  return c;\n}\n\nCompaction::Compaction(const Options* options, int level)\n    : level_(level),\n      max_output_file_size_(MaxFileSizeForLevel(options, level)),\n      input_version_(nullptr),\n      grandparent_index_(0),\n      seen_key_(false),\n      overlapped_bytes_(0) {\n  for (int i = 0; i < config::kNumLevels; i++) {\n    level_ptrs_[i] = 0;\n  }\n}\n\nCompaction::~Compaction() {\n  if (input_version_ != nullptr) {\n    input_version_->Unref();\n  }\n}\n\nbool Compaction::IsTrivialMove() const {\n  const VersionSet* vset = input_version_->vset_;\n  // Avoid a move if there is lots of overlapping grandparent data.\n  // Otherwise, the move could create a parent file that will require\n  // a very expensive merge later on.\n  return (num_input_files(0) == 1 && num_input_files(1) == 0 &&\n          TotalFileSize(grandparents_) <=\n              MaxGrandParentOverlapBytes(vset->options_));\n}\n\nvoid Compaction::AddInputDeletions(VersionEdit* edit) {\n  for (int which = 0; which < 2; which++) {\n    for (size_t i = 0; i < inputs_[which].size(); i++) {\n      edit->DeleteFile(level_ + which, inputs_[which][i]->number);\n    }\n  }\n}\n\nbool Compaction::IsBaseLevelForKey(const Slice& user_key) {\n  // Maybe use binary search to find right entry instead of linear search?\n  const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator();\n  for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) {\n    const std::vector<FileMetaData*>& files = input_version_->files_[lvl];\n    while (level_ptrs_[lvl] < files.size()) {\n      FileMetaData* f = files[level_ptrs_[lvl]];\n      if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) {\n        // We've advanced far enough\n        if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) {\n          // Key falls in this file's range, so definitely not base level\n          return false;\n        }\n        break;\n      }\n      level_ptrs_[lvl]++;\n    }\n  }\n  return true;\n}\n\nbool Compaction::ShouldStopBefore(const Slice& internal_key) {\n  const VersionSet* vset = input_version_->vset_;\n  // Scan to find earliest grandparent file that contains key.\n  const InternalKeyComparator* icmp = &vset->icmp_;\n  while (grandparent_index_ < grandparents_.size() &&\n         icmp->Compare(internal_key,\n                       grandparents_[grandparent_index_]->largest.Encode()) >\n             0) {\n    if (seen_key_) {\n      overlapped_bytes_ += grandparents_[grandparent_index_]->file_size;\n    }\n    grandparent_index_++;\n  }\n  seen_key_ = true;\n\n  if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) {\n    // Too much overlap for current output; start new output\n    overlapped_bytes_ = 0;\n    return true;\n  } else {\n    return false;\n  }\n}\n\nvoid Compaction::ReleaseInputs() {\n  if (input_version_ != nullptr) {\n    input_version_->Unref();\n    input_version_ = nullptr;\n  }\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/version_set.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// The representation of a DBImpl consists of a set of Versions.  The\n// newest version is called \"current\".  Older versions may be kept\n// around to provide a consistent view to live iterators.\n//\n// Each Version keeps track of a set of Table files per level.  The\n// entire set of versions is maintained in a VersionSet.\n//\n// Version,VersionSet are thread-compatible, but require external\n// synchronization on all accesses.\n\n#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_\n#define STORAGE_LEVELDB_DB_VERSION_SET_H_\n\n#include <map>\n#include <set>\n#include <vector>\n\n#include \"db/dbformat.h\"\n#include \"db/version_edit.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n\nnamespace leveldb {\n\nnamespace log {\nclass Writer;\n}\n\nclass Compaction;\nclass Iterator;\nclass MemTable;\nclass TableBuilder;\nclass TableCache;\nclass Version;\nclass VersionSet;\nclass WritableFile;\n\n// Return the smallest index i such that files[i]->largest >= key.\n// Return files.size() if there is no such file.\n// REQUIRES: \"files\" contains a sorted list of non-overlapping files.\nint FindFile(const InternalKeyComparator& icmp,\n             const std::vector<FileMetaData*>& files, const Slice& key);\n\n// Returns true iff some file in \"files\" overlaps the user key range\n// [*smallest,*largest].\n// smallest==nullptr represents a key smaller than all keys in the DB.\n// largest==nullptr represents a key largest than all keys in the DB.\n// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges\n//           in sorted order.\nbool SomeFileOverlapsRange(const InternalKeyComparator& icmp,\n                           bool disjoint_sorted_files,\n                           const std::vector<FileMetaData*>& files,\n                           const Slice* smallest_user_key,\n                           const Slice* largest_user_key);\n\nclass Version {\n public:\n  // Lookup the value for key.  If found, store it in *val and\n  // return OK.  Else return a non-OK status.  Fills *stats.\n  // REQUIRES: lock is not held\n  struct GetStats {\n    FileMetaData* seek_file;\n    int seek_file_level;\n  };\n\n  // Append to *iters a sequence of iterators that will\n  // yield the contents of this Version when merged together.\n  // REQUIRES: This version has been saved (see VersionSet::SaveTo)\n  void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);\n\n  Status Get(const ReadOptions&, const LookupKey& key, std::string* val,\n             GetStats* stats);\n\n  // Adds \"stats\" into the current state.  Returns true if a new\n  // compaction may need to be triggered, false otherwise.\n  // REQUIRES: lock is held\n  bool UpdateStats(const GetStats& stats);\n\n  // Record a sample of bytes read at the specified internal key.\n  // Samples are taken approximately once every config::kReadBytesPeriod\n  // bytes.  Returns true if a new compaction may need to be triggered.\n  // REQUIRES: lock is held\n  bool RecordReadSample(Slice key);\n\n  // Reference count management (so Versions do not disappear out from\n  // under live iterators)\n  void Ref();\n  void Unref();\n\n  void GetOverlappingInputs(\n      int level,\n      const InternalKey* begin,  // nullptr means before all keys\n      const InternalKey* end,    // nullptr means after all keys\n      std::vector<FileMetaData*>* inputs);\n\n  // Returns true iff some file in the specified level overlaps\n  // some part of [*smallest_user_key,*largest_user_key].\n  // smallest_user_key==nullptr represents a key smaller than all the DB's keys.\n  // largest_user_key==nullptr represents a key largest than all the DB's keys.\n  bool OverlapInLevel(int level, const Slice* smallest_user_key,\n                      const Slice* largest_user_key);\n\n  // Return the level at which we should place a new memtable compaction\n  // result that covers the range [smallest_user_key,largest_user_key].\n  int PickLevelForMemTableOutput(const Slice& smallest_user_key,\n                                 const Slice& largest_user_key);\n\n  int NumFiles(int level) const { return files_[level].size(); }\n\n  // Return a human readable string that describes this version's contents.\n  std::string DebugString() const;\n\n private:\n  friend class Compaction;\n  friend class VersionSet;\n\n  class LevelFileNumIterator;\n\n  explicit Version(VersionSet* vset)\n      : vset_(vset),\n        next_(this),\n        prev_(this),\n        refs_(0),\n        file_to_compact_(nullptr),\n        file_to_compact_level_(-1),\n        compaction_score_(-1),\n        compaction_level_(-1) {}\n\n  Version(const Version&) = delete;\n  Version& operator=(const Version&) = delete;\n\n  ~Version();\n\n  Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;\n\n  // Call func(arg, level, f) for every file that overlaps user_key in\n  // order from newest to oldest.  If an invocation of func returns\n  // false, makes no more calls.\n  //\n  // REQUIRES: user portion of internal_key == user_key.\n  void ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,\n                          bool (*func)(void*, int, FileMetaData*));\n\n  VersionSet* vset_;  // VersionSet to which this Version belongs\n  Version* next_;     // Next version in linked list\n  Version* prev_;     // Previous version in linked list\n  int refs_;          // Number of live refs to this version\n\n  // List of files per level\n  std::vector<FileMetaData*> files_[config::kNumLevels];\n\n  // Next file to compact based on seek stats.\n  FileMetaData* file_to_compact_;\n  int file_to_compact_level_;\n\n  // Level that should be compacted next and its compaction score.\n  // Score < 1 means compaction is not strictly needed.  These fields\n  // are initialized by Finalize().\n  double compaction_score_;\n  int compaction_level_;\n};\n\nclass VersionSet {\n public:\n  VersionSet(const std::string& dbname, const Options* options,\n             TableCache* table_cache, const InternalKeyComparator*);\n  VersionSet(const VersionSet&) = delete;\n  VersionSet& operator=(const VersionSet&) = delete;\n\n  ~VersionSet();\n\n  // Apply *edit to the current version to form a new descriptor that\n  // is both saved to persistent state and installed as the new\n  // current version.  Will release *mu while actually writing to the file.\n  // REQUIRES: *mu is held on entry.\n  // REQUIRES: no other thread concurrently calls LogAndApply()\n  Status LogAndApply(VersionEdit* edit, port::Mutex* mu)\n      EXCLUSIVE_LOCKS_REQUIRED(mu);\n\n  // Recover the last saved descriptor from persistent storage.\n  Status Recover(bool* save_manifest);\n\n  // Return the current version.\n  Version* current() const { return current_; }\n\n  // Return the current manifest file number\n  uint64_t ManifestFileNumber() const { return manifest_file_number_; }\n\n  // Allocate and return a new file number\n  uint64_t NewFileNumber() { return next_file_number_++; }\n\n  // Arrange to reuse \"file_number\" unless a newer file number has\n  // already been allocated.\n  // REQUIRES: \"file_number\" was returned by a call to NewFileNumber().\n  void ReuseFileNumber(uint64_t file_number) {\n    if (next_file_number_ == file_number + 1) {\n      next_file_number_ = file_number;\n    }\n  }\n\n  // Return the number of Table files at the specified level.\n  int NumLevelFiles(int level) const;\n\n  // Return the combined file size of all files at the specified level.\n  int64_t NumLevelBytes(int level) const;\n\n  // Return the last sequence number.\n  uint64_t LastSequence() const { return last_sequence_; }\n\n  // Set the last sequence number to s.\n  void SetLastSequence(uint64_t s) {\n    assert(s >= last_sequence_);\n    last_sequence_ = s;\n  }\n\n  // Mark the specified file number as used.\n  void MarkFileNumberUsed(uint64_t number);\n\n  // Return the current log file number.\n  uint64_t LogNumber() const { return log_number_; }\n\n  // Return the log file number for the log file that is currently\n  // being compacted, or zero if there is no such log file.\n  uint64_t PrevLogNumber() const { return prev_log_number_; }\n\n  // Pick level and inputs for a new compaction.\n  // Returns nullptr if there is no compaction to be done.\n  // Otherwise returns a pointer to a heap-allocated object that\n  // describes the compaction.  Caller should delete the result.\n  Compaction* PickCompaction();\n\n  // Return a compaction object for compacting the range [begin,end] in\n  // the specified level.  Returns nullptr if there is nothing in that\n  // level that overlaps the specified range.  Caller should delete\n  // the result.\n  Compaction* CompactRange(int level, const InternalKey* begin,\n                           const InternalKey* end);\n\n  // Return the maximum overlapping data (in bytes) at next level for any\n  // file at a level >= 1.\n  int64_t MaxNextLevelOverlappingBytes();\n\n  // Create an iterator that reads over the compaction inputs for \"*c\".\n  // The caller should delete the iterator when no longer needed.\n  Iterator* MakeInputIterator(Compaction* c);\n\n  // Returns true iff some level needs a compaction.\n  bool NeedsCompaction() const {\n    Version* v = current_;\n    return (v->compaction_score_ >= 1) || (v->file_to_compact_ != nullptr);\n  }\n\n  // Add all files listed in any live version to *live.\n  // May also mutate some internal state.\n  void AddLiveFiles(std::set<uint64_t>* live);\n\n  // Return the approximate offset in the database of the data for\n  // \"key\" as of version \"v\".\n  uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key);\n\n  // Return a human-readable short (single-line) summary of the number\n  // of files per level.  Uses *scratch as backing store.\n  struct LevelSummaryStorage {\n    char buffer[100];\n  };\n  const char* LevelSummary(LevelSummaryStorage* scratch) const;\n\n private:\n  class Builder;\n\n  friend class Compaction;\n  friend class Version;\n\n  bool ReuseManifest(const std::string& dscname, const std::string& dscbase);\n\n  void Finalize(Version* v);\n\n  void GetRange(const std::vector<FileMetaData*>& inputs, InternalKey* smallest,\n                InternalKey* largest);\n\n  void GetRange2(const std::vector<FileMetaData*>& inputs1,\n                 const std::vector<FileMetaData*>& inputs2,\n                 InternalKey* smallest, InternalKey* largest);\n\n  void SetupOtherInputs(Compaction* c);\n\n  // Save current contents to *log\n  Status WriteSnapshot(log::Writer* log);\n\n  void AppendVersion(Version* v);\n\n  Env* const env_;\n  const std::string dbname_;\n  const Options* const options_;\n  TableCache* const table_cache_;\n  const InternalKeyComparator icmp_;\n  uint64_t next_file_number_;\n  uint64_t manifest_file_number_;\n  uint64_t last_sequence_;\n  uint64_t log_number_;\n  uint64_t prev_log_number_;  // 0 or backing store for memtable being compacted\n\n  // Opened lazily\n  WritableFile* descriptor_file_;\n  log::Writer* descriptor_log_;\n  Version dummy_versions_;  // Head of circular doubly-linked list of versions.\n  Version* current_;        // == dummy_versions_.prev_\n\n  // Per-level key at which the next compaction at that level should start.\n  // Either an empty string, or a valid InternalKey.\n  std::string compact_pointer_[config::kNumLevels];\n};\n\n// A Compaction encapsulates information about a compaction.\nclass Compaction {\n public:\n  ~Compaction();\n\n  // Return the level that is being compacted.  Inputs from \"level\"\n  // and \"level+1\" will be merged to produce a set of \"level+1\" files.\n  int level() const { return level_; }\n\n  // Return the object that holds the edits to the descriptor done\n  // by this compaction.\n  VersionEdit* edit() { return &edit_; }\n\n  // \"which\" must be either 0 or 1\n  int num_input_files(int which) const { return inputs_[which].size(); }\n\n  // Return the ith input file at \"level()+which\" (\"which\" must be 0 or 1).\n  FileMetaData* input(int which, int i) const { return inputs_[which][i]; }\n\n  // Maximum size of files to build during this compaction.\n  uint64_t MaxOutputFileSize() const { return max_output_file_size_; }\n\n  // Is this a trivial compaction that can be implemented by just\n  // moving a single input file to the next level (no merging or splitting)\n  bool IsTrivialMove() const;\n\n  // Add all inputs to this compaction as delete operations to *edit.\n  void AddInputDeletions(VersionEdit* edit);\n\n  // Returns true if the information we have available guarantees that\n  // the compaction is producing data in \"level+1\" for which no data exists\n  // in levels greater than \"level+1\".\n  bool IsBaseLevelForKey(const Slice& user_key);\n\n  // Returns true iff we should stop building the current output\n  // before processing \"internal_key\".\n  bool ShouldStopBefore(const Slice& internal_key);\n\n  // Release the input version for the compaction, once the compaction\n  // is successful.\n  void ReleaseInputs();\n\n private:\n  friend class Version;\n  friend class VersionSet;\n\n  Compaction(const Options* options, int level);\n\n  int level_;\n  uint64_t max_output_file_size_;\n  Version* input_version_;\n  VersionEdit edit_;\n\n  // Each compaction reads inputs from \"level_\" and \"level_+1\"\n  std::vector<FileMetaData*> inputs_[2];  // The two sets of inputs\n\n  // State used to check for number of overlapping grandparent files\n  // (parent == level_ + 1, grandparent == level_ + 2)\n  std::vector<FileMetaData*> grandparents_;\n  size_t grandparent_index_;  // Index in grandparent_starts_\n  bool seen_key_;             // Some output key has been seen\n  int64_t overlapped_bytes_;  // Bytes of overlap between current output\n                              // and grandparent files\n\n  // State for implementing IsBaseLevelForKey\n\n  // level_ptrs_ holds indices into input_version_->levels_: our state\n  // is that we are positioned at one of the file ranges for each\n  // higher level than the ones involved in this compaction (i.e. for\n  // all L >= level_ + 2).\n  size_t level_ptrs_[config::kNumLevels];\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_VERSION_SET_H_\n"
  },
  {
    "path": "src/leveldb/db/version_set_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"db/version_set.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nclass FindFileTest {\n public:\n  FindFileTest() : disjoint_sorted_files_(true) {}\n\n  ~FindFileTest() {\n    for (int i = 0; i < files_.size(); i++) {\n      delete files_[i];\n    }\n  }\n\n  void Add(const char* smallest, const char* largest,\n           SequenceNumber smallest_seq = 100,\n           SequenceNumber largest_seq = 100) {\n    FileMetaData* f = new FileMetaData;\n    f->number = files_.size() + 1;\n    f->smallest = InternalKey(smallest, smallest_seq, kTypeValue);\n    f->largest = InternalKey(largest, largest_seq, kTypeValue);\n    files_.push_back(f);\n  }\n\n  int Find(const char* key) {\n    InternalKey target(key, 100, kTypeValue);\n    InternalKeyComparator cmp(BytewiseComparator());\n    return FindFile(cmp, files_, target.Encode());\n  }\n\n  bool Overlaps(const char* smallest, const char* largest) {\n    InternalKeyComparator cmp(BytewiseComparator());\n    Slice s(smallest != nullptr ? smallest : \"\");\n    Slice l(largest != nullptr ? largest : \"\");\n    return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_,\n                                 (smallest != nullptr ? &s : nullptr),\n                                 (largest != nullptr ? &l : nullptr));\n  }\n\n  bool disjoint_sorted_files_;\n\n private:\n  std::vector<FileMetaData*> files_;\n};\n\nTEST(FindFileTest, Empty) {\n  ASSERT_EQ(0, Find(\"foo\"));\n  ASSERT_TRUE(!Overlaps(\"a\", \"z\"));\n  ASSERT_TRUE(!Overlaps(nullptr, \"z\"));\n  ASSERT_TRUE(!Overlaps(\"a\", nullptr));\n  ASSERT_TRUE(!Overlaps(nullptr, nullptr));\n}\n\nTEST(FindFileTest, Single) {\n  Add(\"p\", \"q\");\n  ASSERT_EQ(0, Find(\"a\"));\n  ASSERT_EQ(0, Find(\"p\"));\n  ASSERT_EQ(0, Find(\"p1\"));\n  ASSERT_EQ(0, Find(\"q\"));\n  ASSERT_EQ(1, Find(\"q1\"));\n  ASSERT_EQ(1, Find(\"z\"));\n\n  ASSERT_TRUE(!Overlaps(\"a\", \"b\"));\n  ASSERT_TRUE(!Overlaps(\"z1\", \"z2\"));\n  ASSERT_TRUE(Overlaps(\"a\", \"p\"));\n  ASSERT_TRUE(Overlaps(\"a\", \"q\"));\n  ASSERT_TRUE(Overlaps(\"a\", \"z\"));\n  ASSERT_TRUE(Overlaps(\"p\", \"p1\"));\n  ASSERT_TRUE(Overlaps(\"p\", \"q\"));\n  ASSERT_TRUE(Overlaps(\"p\", \"z\"));\n  ASSERT_TRUE(Overlaps(\"p1\", \"p2\"));\n  ASSERT_TRUE(Overlaps(\"p1\", \"z\"));\n  ASSERT_TRUE(Overlaps(\"q\", \"q\"));\n  ASSERT_TRUE(Overlaps(\"q\", \"q1\"));\n\n  ASSERT_TRUE(!Overlaps(nullptr, \"j\"));\n  ASSERT_TRUE(!Overlaps(\"r\", nullptr));\n  ASSERT_TRUE(Overlaps(nullptr, \"p\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"p1\"));\n  ASSERT_TRUE(Overlaps(\"q\", nullptr));\n  ASSERT_TRUE(Overlaps(nullptr, nullptr));\n}\n\nTEST(FindFileTest, Multiple) {\n  Add(\"150\", \"200\");\n  Add(\"200\", \"250\");\n  Add(\"300\", \"350\");\n  Add(\"400\", \"450\");\n  ASSERT_EQ(0, Find(\"100\"));\n  ASSERT_EQ(0, Find(\"150\"));\n  ASSERT_EQ(0, Find(\"151\"));\n  ASSERT_EQ(0, Find(\"199\"));\n  ASSERT_EQ(0, Find(\"200\"));\n  ASSERT_EQ(1, Find(\"201\"));\n  ASSERT_EQ(1, Find(\"249\"));\n  ASSERT_EQ(1, Find(\"250\"));\n  ASSERT_EQ(2, Find(\"251\"));\n  ASSERT_EQ(2, Find(\"299\"));\n  ASSERT_EQ(2, Find(\"300\"));\n  ASSERT_EQ(2, Find(\"349\"));\n  ASSERT_EQ(2, Find(\"350\"));\n  ASSERT_EQ(3, Find(\"351\"));\n  ASSERT_EQ(3, Find(\"400\"));\n  ASSERT_EQ(3, Find(\"450\"));\n  ASSERT_EQ(4, Find(\"451\"));\n\n  ASSERT_TRUE(!Overlaps(\"100\", \"149\"));\n  ASSERT_TRUE(!Overlaps(\"251\", \"299\"));\n  ASSERT_TRUE(!Overlaps(\"451\", \"500\"));\n  ASSERT_TRUE(!Overlaps(\"351\", \"399\"));\n\n  ASSERT_TRUE(Overlaps(\"100\", \"150\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"200\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"300\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"400\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"500\"));\n  ASSERT_TRUE(Overlaps(\"375\", \"400\"));\n  ASSERT_TRUE(Overlaps(\"450\", \"450\"));\n  ASSERT_TRUE(Overlaps(\"450\", \"500\"));\n}\n\nTEST(FindFileTest, MultipleNullBoundaries) {\n  Add(\"150\", \"200\");\n  Add(\"200\", \"250\");\n  Add(\"300\", \"350\");\n  Add(\"400\", \"450\");\n  ASSERT_TRUE(!Overlaps(nullptr, \"149\"));\n  ASSERT_TRUE(!Overlaps(\"451\", nullptr));\n  ASSERT_TRUE(Overlaps(nullptr, nullptr));\n  ASSERT_TRUE(Overlaps(nullptr, \"150\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"199\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"200\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"201\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"400\"));\n  ASSERT_TRUE(Overlaps(nullptr, \"800\"));\n  ASSERT_TRUE(Overlaps(\"100\", nullptr));\n  ASSERT_TRUE(Overlaps(\"200\", nullptr));\n  ASSERT_TRUE(Overlaps(\"449\", nullptr));\n  ASSERT_TRUE(Overlaps(\"450\", nullptr));\n}\n\nTEST(FindFileTest, OverlapSequenceChecks) {\n  Add(\"200\", \"200\", 5000, 3000);\n  ASSERT_TRUE(!Overlaps(\"199\", \"199\"));\n  ASSERT_TRUE(!Overlaps(\"201\", \"300\"));\n  ASSERT_TRUE(Overlaps(\"200\", \"200\"));\n  ASSERT_TRUE(Overlaps(\"190\", \"200\"));\n  ASSERT_TRUE(Overlaps(\"200\", \"210\"));\n}\n\nTEST(FindFileTest, OverlappingFiles) {\n  Add(\"150\", \"600\");\n  Add(\"400\", \"500\");\n  disjoint_sorted_files_ = false;\n  ASSERT_TRUE(!Overlaps(\"100\", \"149\"));\n  ASSERT_TRUE(!Overlaps(\"601\", \"700\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"150\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"200\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"300\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"400\"));\n  ASSERT_TRUE(Overlaps(\"100\", \"500\"));\n  ASSERT_TRUE(Overlaps(\"375\", \"400\"));\n  ASSERT_TRUE(Overlaps(\"450\", \"450\"));\n  ASSERT_TRUE(Overlaps(\"450\", \"500\"));\n  ASSERT_TRUE(Overlaps(\"450\", \"700\"));\n  ASSERT_TRUE(Overlaps(\"600\", \"700\"));\n}\n\nvoid AddBoundaryInputs(const InternalKeyComparator& icmp,\n                       const std::vector<FileMetaData*>& level_files,\n                       std::vector<FileMetaData*>* compaction_files);\n\nclass AddBoundaryInputsTest {\n public:\n  std::vector<FileMetaData*> level_files_;\n  std::vector<FileMetaData*> compaction_files_;\n  std::vector<FileMetaData*> all_files_;\n  InternalKeyComparator icmp_;\n\n  AddBoundaryInputsTest() : icmp_(BytewiseComparator()) {}\n\n  ~AddBoundaryInputsTest() {\n    for (size_t i = 0; i < all_files_.size(); ++i) {\n      delete all_files_[i];\n    }\n    all_files_.clear();\n  }\n\n  FileMetaData* CreateFileMetaData(uint64_t number, InternalKey smallest,\n                                   InternalKey largest) {\n    FileMetaData* f = new FileMetaData();\n    f->number = number;\n    f->smallest = smallest;\n    f->largest = largest;\n    all_files_.push_back(f);\n    return f;\n  }\n};\n\nTEST(AddBoundaryInputsTest, TestEmptyFileSets) {\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_TRUE(compaction_files_.empty());\n  ASSERT_TRUE(level_files_.empty());\n}\n\nTEST(AddBoundaryInputsTest, TestEmptyLevelFiles) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 1, kTypeValue)));\n  compaction_files_.push_back(f1);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_EQ(1, compaction_files_.size());\n  ASSERT_EQ(f1, compaction_files_[0]);\n  ASSERT_TRUE(level_files_.empty());\n}\n\nTEST(AddBoundaryInputsTest, TestEmptyCompactionFiles) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 1, kTypeValue)));\n  level_files_.push_back(f1);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_TRUE(compaction_files_.empty());\n  ASSERT_EQ(1, level_files_.size());\n  ASSERT_EQ(f1, level_files_[0]);\n}\n\nTEST(AddBoundaryInputsTest, TestNoBoundaryFiles) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 1, kTypeValue)));\n  FileMetaData* f2 =\n      CreateFileMetaData(1, InternalKey(\"200\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"200\", 1, kTypeValue)));\n  FileMetaData* f3 =\n      CreateFileMetaData(1, InternalKey(\"300\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"300\", 1, kTypeValue)));\n\n  level_files_.push_back(f3);\n  level_files_.push_back(f2);\n  level_files_.push_back(f1);\n  compaction_files_.push_back(f2);\n  compaction_files_.push_back(f3);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_EQ(2, compaction_files_.size());\n}\n\nTEST(AddBoundaryInputsTest, TestOneBoundaryFiles) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 3, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 2, kTypeValue)));\n  FileMetaData* f2 =\n      CreateFileMetaData(1, InternalKey(\"100\", 1, kTypeValue),\n                         InternalKey(InternalKey(\"200\", 3, kTypeValue)));\n  FileMetaData* f3 =\n      CreateFileMetaData(1, InternalKey(\"300\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"300\", 1, kTypeValue)));\n\n  level_files_.push_back(f3);\n  level_files_.push_back(f2);\n  level_files_.push_back(f1);\n  compaction_files_.push_back(f1);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_EQ(2, compaction_files_.size());\n  ASSERT_EQ(f1, compaction_files_[0]);\n  ASSERT_EQ(f2, compaction_files_[1]);\n}\n\nTEST(AddBoundaryInputsTest, TestTwoBoundaryFiles) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 6, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 5, kTypeValue)));\n  FileMetaData* f2 =\n      CreateFileMetaData(1, InternalKey(\"100\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"300\", 1, kTypeValue)));\n  FileMetaData* f3 =\n      CreateFileMetaData(1, InternalKey(\"100\", 4, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 3, kTypeValue)));\n\n  level_files_.push_back(f2);\n  level_files_.push_back(f3);\n  level_files_.push_back(f1);\n  compaction_files_.push_back(f1);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_EQ(3, compaction_files_.size());\n  ASSERT_EQ(f1, compaction_files_[0]);\n  ASSERT_EQ(f3, compaction_files_[1]);\n  ASSERT_EQ(f2, compaction_files_[2]);\n}\n\nTEST(AddBoundaryInputsTest, TestDisjoinFilePointers) {\n  FileMetaData* f1 =\n      CreateFileMetaData(1, InternalKey(\"100\", 6, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 5, kTypeValue)));\n  FileMetaData* f2 =\n      CreateFileMetaData(1, InternalKey(\"100\", 6, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 5, kTypeValue)));\n  FileMetaData* f3 =\n      CreateFileMetaData(1, InternalKey(\"100\", 2, kTypeValue),\n                         InternalKey(InternalKey(\"300\", 1, kTypeValue)));\n  FileMetaData* f4 =\n      CreateFileMetaData(1, InternalKey(\"100\", 4, kTypeValue),\n                         InternalKey(InternalKey(\"100\", 3, kTypeValue)));\n\n  level_files_.push_back(f2);\n  level_files_.push_back(f3);\n  level_files_.push_back(f4);\n\n  compaction_files_.push_back(f1);\n\n  AddBoundaryInputs(icmp_, level_files_, &compaction_files_);\n  ASSERT_EQ(3, compaction_files_.size());\n  ASSERT_EQ(f1, compaction_files_[0]);\n  ASSERT_EQ(f4, compaction_files_[1]);\n  ASSERT_EQ(f3, compaction_files_[2]);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/db/write_batch.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// WriteBatch::rep_ :=\n//    sequence: fixed64\n//    count: fixed32\n//    data: record[count]\n// record :=\n//    kTypeValue varstring varstring         |\n//    kTypeDeletion varstring\n// varstring :=\n//    len: varint32\n//    data: uint8[len]\n\n#include \"leveldb/write_batch.h\"\n\n#include \"db/dbformat.h\"\n#include \"db/memtable.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/db.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\n// WriteBatch header has an 8-byte sequence number followed by a 4-byte count.\nstatic const size_t kHeader = 12;\n\nWriteBatch::WriteBatch() { Clear(); }\n\nWriteBatch::~WriteBatch() = default;\n\nWriteBatch::Handler::~Handler() = default;\n\nvoid WriteBatch::Clear() {\n  rep_.clear();\n  rep_.resize(kHeader);\n}\n\nsize_t WriteBatch::ApproximateSize() const { return rep_.size(); }\n\nStatus WriteBatch::Iterate(Handler* handler) const {\n  Slice input(rep_);\n  if (input.size() < kHeader) {\n    return Status::Corruption(\"malformed WriteBatch (too small)\");\n  }\n\n  input.remove_prefix(kHeader);\n  Slice key, value;\n  int found = 0;\n  while (!input.empty()) {\n    found++;\n    char tag = input[0];\n    input.remove_prefix(1);\n    switch (tag) {\n      case kTypeValue:\n        if (GetLengthPrefixedSlice(&input, &key) &&\n            GetLengthPrefixedSlice(&input, &value)) {\n          handler->Put(key, value);\n        } else {\n          return Status::Corruption(\"bad WriteBatch Put\");\n        }\n        break;\n      case kTypeDeletion:\n        if (GetLengthPrefixedSlice(&input, &key)) {\n          handler->Delete(key);\n        } else {\n          return Status::Corruption(\"bad WriteBatch Delete\");\n        }\n        break;\n      default:\n        return Status::Corruption(\"unknown WriteBatch tag\");\n    }\n  }\n  if (found != WriteBatchInternal::Count(this)) {\n    return Status::Corruption(\"WriteBatch has wrong count\");\n  } else {\n    return Status::OK();\n  }\n}\n\nint WriteBatchInternal::Count(const WriteBatch* b) {\n  return DecodeFixed32(b->rep_.data() + 8);\n}\n\nvoid WriteBatchInternal::SetCount(WriteBatch* b, int n) {\n  EncodeFixed32(&b->rep_[8], n);\n}\n\nSequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {\n  return SequenceNumber(DecodeFixed64(b->rep_.data()));\n}\n\nvoid WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) {\n  EncodeFixed64(&b->rep_[0], seq);\n}\n\nvoid WriteBatch::Put(const Slice& key, const Slice& value) {\n  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);\n  rep_.push_back(static_cast<char>(kTypeValue));\n  PutLengthPrefixedSlice(&rep_, key);\n  PutLengthPrefixedSlice(&rep_, value);\n}\n\nvoid WriteBatch::Delete(const Slice& key) {\n  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);\n  rep_.push_back(static_cast<char>(kTypeDeletion));\n  PutLengthPrefixedSlice(&rep_, key);\n}\n\nvoid WriteBatch::Append(const WriteBatch& source) {\n  WriteBatchInternal::Append(this, &source);\n}\n\nnamespace {\nclass MemTableInserter : public WriteBatch::Handler {\n public:\n  SequenceNumber sequence_;\n  MemTable* mem_;\n\n  void Put(const Slice& key, const Slice& value) override {\n    mem_->Add(sequence_, kTypeValue, key, value);\n    sequence_++;\n  }\n  void Delete(const Slice& key) override {\n    mem_->Add(sequence_, kTypeDeletion, key, Slice());\n    sequence_++;\n  }\n};\n}  // namespace\n\nStatus WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* memtable) {\n  MemTableInserter inserter;\n  inserter.sequence_ = WriteBatchInternal::Sequence(b);\n  inserter.mem_ = memtable;\n  return b->Iterate(&inserter);\n}\n\nvoid WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {\n  assert(contents.size() >= kHeader);\n  b->rep_.assign(contents.data(), contents.size());\n}\n\nvoid WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {\n  SetCount(dst, Count(dst) + Count(src));\n  assert(src->rep_.size() >= kHeader);\n  dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/db/write_batch_internal.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_\n#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_\n\n#include \"db/dbformat.h\"\n#include \"leveldb/write_batch.h\"\n\nnamespace leveldb {\n\nclass MemTable;\n\n// WriteBatchInternal provides static methods for manipulating a\n// WriteBatch that we don't want in the public WriteBatch interface.\nclass WriteBatchInternal {\n public:\n  // Return the number of entries in the batch.\n  static int Count(const WriteBatch* batch);\n\n  // Set the count for the number of entries in the batch.\n  static void SetCount(WriteBatch* batch, int n);\n\n  // Return the sequence number for the start of this batch.\n  static SequenceNumber Sequence(const WriteBatch* batch);\n\n  // Store the specified number as the sequence number for the start of\n  // this batch.\n  static void SetSequence(WriteBatch* batch, SequenceNumber seq);\n\n  static Slice Contents(const WriteBatch* batch) { return Slice(batch->rep_); }\n\n  static size_t ByteSize(const WriteBatch* batch) { return batch->rep_.size(); }\n\n  static void SetContents(WriteBatch* batch, const Slice& contents);\n\n  static Status InsertInto(const WriteBatch* batch, MemTable* memtable);\n\n  static void Append(WriteBatch* dst, const WriteBatch* src);\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_\n"
  },
  {
    "path": "src/leveldb/db/write_batch_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/db.h\"\n\n#include \"db/memtable.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/env.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nstatic std::string PrintContents(WriteBatch* b) {\n  InternalKeyComparator cmp(BytewiseComparator());\n  MemTable* mem = new MemTable(cmp);\n  mem->Ref();\n  std::string state;\n  Status s = WriteBatchInternal::InsertInto(b, mem);\n  int count = 0;\n  Iterator* iter = mem->NewIterator();\n  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n    ParsedInternalKey ikey;\n    ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey));\n    switch (ikey.type) {\n      case kTypeValue:\n        state.append(\"Put(\");\n        state.append(ikey.user_key.ToString());\n        state.append(\", \");\n        state.append(iter->value().ToString());\n        state.append(\")\");\n        count++;\n        break;\n      case kTypeDeletion:\n        state.append(\"Delete(\");\n        state.append(ikey.user_key.ToString());\n        state.append(\")\");\n        count++;\n        break;\n    }\n    state.append(\"@\");\n    state.append(NumberToString(ikey.sequence));\n  }\n  delete iter;\n  if (!s.ok()) {\n    state.append(\"ParseError()\");\n  } else if (count != WriteBatchInternal::Count(b)) {\n    state.append(\"CountMismatch()\");\n  }\n  mem->Unref();\n  return state;\n}\n\nclass WriteBatchTest {};\n\nTEST(WriteBatchTest, Empty) {\n  WriteBatch batch;\n  ASSERT_EQ(\"\", PrintContents(&batch));\n  ASSERT_EQ(0, WriteBatchInternal::Count(&batch));\n}\n\nTEST(WriteBatchTest, Multiple) {\n  WriteBatch batch;\n  batch.Put(Slice(\"foo\"), Slice(\"bar\"));\n  batch.Delete(Slice(\"box\"));\n  batch.Put(Slice(\"baz\"), Slice(\"boo\"));\n  WriteBatchInternal::SetSequence(&batch, 100);\n  ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch));\n  ASSERT_EQ(3, WriteBatchInternal::Count(&batch));\n  ASSERT_EQ(\n      \"Put(baz, boo)@102\"\n      \"Delete(box)@101\"\n      \"Put(foo, bar)@100\",\n      PrintContents(&batch));\n}\n\nTEST(WriteBatchTest, Corruption) {\n  WriteBatch batch;\n  batch.Put(Slice(\"foo\"), Slice(\"bar\"));\n  batch.Delete(Slice(\"box\"));\n  WriteBatchInternal::SetSequence(&batch, 200);\n  Slice contents = WriteBatchInternal::Contents(&batch);\n  WriteBatchInternal::SetContents(&batch,\n                                  Slice(contents.data(), contents.size() - 1));\n  ASSERT_EQ(\n      \"Put(foo, bar)@200\"\n      \"ParseError()\",\n      PrintContents(&batch));\n}\n\nTEST(WriteBatchTest, Append) {\n  WriteBatch b1, b2;\n  WriteBatchInternal::SetSequence(&b1, 200);\n  WriteBatchInternal::SetSequence(&b2, 300);\n  b1.Append(b2);\n  ASSERT_EQ(\"\", PrintContents(&b1));\n  b2.Put(\"a\", \"va\");\n  b1.Append(b2);\n  ASSERT_EQ(\"Put(a, va)@200\", PrintContents(&b1));\n  b2.Clear();\n  b2.Put(\"b\", \"vb\");\n  b1.Append(b2);\n  ASSERT_EQ(\n      \"Put(a, va)@200\"\n      \"Put(b, vb)@201\",\n      PrintContents(&b1));\n  b2.Delete(\"foo\");\n  b1.Append(b2);\n  ASSERT_EQ(\n      \"Put(a, va)@200\"\n      \"Put(b, vb)@202\"\n      \"Put(b, vb)@201\"\n      \"Delete(foo)@203\",\n      PrintContents(&b1));\n}\n\nTEST(WriteBatchTest, ApproximateSize) {\n  WriteBatch batch;\n  size_t empty_size = batch.ApproximateSize();\n\n  batch.Put(Slice(\"foo\"), Slice(\"bar\"));\n  size_t one_key_size = batch.ApproximateSize();\n  ASSERT_LT(empty_size, one_key_size);\n\n  batch.Put(Slice(\"baz\"), Slice(\"boo\"));\n  size_t two_keys_size = batch.ApproximateSize();\n  ASSERT_LT(one_key_size, two_keys_size);\n\n  batch.Delete(Slice(\"box\"));\n  size_t post_delete_size = batch.ApproximateSize();\n  ASSERT_LT(two_keys_size, post_delete_size);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/doc/benchmark.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<title>LevelDB Benchmarks</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<style>\nbody {\n  font-family:Helvetica,sans-serif;\n  padding:20px;\n}\n\nh2 {\n  padding-top:30px;\n}\n\ntable.bn {\n  width:800px;\n  border-collapse:collapse;\n  border:0;\n  padding:0;\n}\n\ntable.bnbase {\n  width:650px;\n}\n\ntable.bn td {\n  padding:2px 0;\n}\n\ntable.bn td.c1 {\n  font-weight:bold;\n  width:150px;\n}\n\ntable.bn td.c1 div.e {\n  float:right;\n  font-weight:normal;\n}\n\ntable.bn td.c2 {\n  width:150px;\n  text-align:right;\n  padding:2px;\n}\n\ntable.bn td.c3 {\n  width:350px;\n}\n\ntable.bn td.c4 {\n  width:150px;\n  font-size:small;\n  padding-left:4px;\n}\n\n/* chart bars */\ndiv.bldb {\n  background-color:#0255df;\n}\n\ndiv.bkct {\n  background-color:#df5555;\n}\n\ndiv.bsql {\n  background-color:#aadf55;\n}\n\n.code {\n  font-family:monospace;\n  font-size:large;\n}\n\n.todo {\n  color: red;\n}\n\n</style>\n</head>\n<body>\n<h1>LevelDB Benchmarks</h1>\n<p>Google, July 2011</p>\n<hr>\n\n<p>In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against <a href=\"http://www.sqlite.org/\">SQLite3</a> (version 3.7.6.3) and <a href=\"http://fallabs.com/kyotocabinet/spex.html\">Kyoto Cabinet's</a> (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.</p>\n\n<p>Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.</p>\n\n<h4>Benchmark Source Code</h4>\n<p>We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's <span class=\"code\">db_bench</span>. The code for each of the benchmarks resides here:</p>\n<ul>\n\t<li> <b>LevelDB:</b> <a href=\"https://github.com/google/leveldb/blob/master/benchmarks/db_bench.cc\">benchmarks/db_bench.cc</a>.</li>\n\t<li> <b>SQLite:</b> <a href=\"https://github.com/google/leveldb/blob/master/benchmarks/db_bench_sqlite3.cc\">benchmarks/db_bench_sqlite3.cc</a>.</li>\n\t<li> <b>Kyoto TreeDB:</b> <a href=\"https://github.com/google/leveldb/blob/master/benchmarks/db_bench_tree_db.cc\">benchmarks/db_bench_tree_db.cc</a>.</li>\n</ul>\n\n<h4>Custom Build Specifications</h4>\n<ul>\n<li>LevelDB: LevelDB was compiled with the <a href=\"http://code.google.com/p/google-perftools\">tcmalloc</a> library and the <a href=\"http://code.google.com/p/snappy/\">Snappy</a> compression library (revision 33).  Assertions were disabled.</li>\n<li>TreeDB: TreeDB was compiled using the <a href=\"http://www.oberhumer.com/opensource/lzo/\">LZO</a> compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.</li>\n<li>SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive.  We also enabled SQLite's <a href=\"http://www.sqlite.org/draft/wal.html\">write-ahead logging</a>.</li>\n</ul>\n\n<h2>1. Baseline Performance</h2>\n<p>This section gives the baseline performance of all the\ndatabases.  Following sections show how performance changes as various\nparameters are varied.  For the baseline:</p>\n<ul>\n\t<li> Each database is allowed 4 MB of cache memory.</li>\n        <li> Databases are opened in <em>asynchronous</em> write mode.\n             (LevelDB's sync option, TreeDB's OAUTOSYNC option, and\n             SQLite3's synchronous options are all turned off).  I.e.,\n             every write is pushed to the operating system, but the\n             benchmark does not wait for the write to reach the disk.</li>\n\t<li> Keys are 16 bytes each.</li>\n        <li> Value are 100 bytes each (with enough redundancy so that\n             a simple compressor shrinks them to 50% of their original\n             size).</li>\n\t<li> Sequential reads/writes traverse the key space in increasing order.</li>\n\t<li> Random reads/writes traverse the key space in random order.</li>\n</ul>\n\n<h3>A. Sequential Reads</h3>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">4,030,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">1,010,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:95px\">&nbsp;</div></td>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">383,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:33px\">&nbsp;</div></td>\n</table>\n<h3>B. Random Reads</h3>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">129,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:298px\">&nbsp;</div></td>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">151,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:350px\">&nbsp;</div></td>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">134,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:310px\">&nbsp;</div></td>\n</table>\n<h3>C. Sequential Writes</h3>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">779,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">342,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:154px\">&nbsp;</div></td>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">48,600 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:22px\">&nbsp;</div></td>\n</table>\n<h3>D. Random Writes</h3>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">164,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">88,500 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:188px\">&nbsp;</div></td>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">9,860 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:21px\">&nbsp;</div></td>\n</table>\n\n<p>LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.</p>\n\n<h2>2. Write Performance under Different Configurations</h2>\n<h3>A. Large Values </h3>\n<p>For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.</p>\n<h4>Sequential Writes</h4>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">1,100 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:234px\">&nbsp;</div></td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">1,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:224px\">&nbsp;</div></td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">1,600 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:350px\">&nbsp;</div></td></tr>\n</table>\n<h4>Random Writes</h4>\n<table class=\"bn bnbase\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">480 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:105px\">&nbsp;</div></td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">1,100 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:240px\">&nbsp;</div></td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">1,600 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:350px\">&nbsp;</div></td></tr>\n</table>\n<p>LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file.\nWith larger values, LevelDB's per-operation efficiency is swamped by the\ncost of extra copies of large values.</p>\n<h3>B. Batch Writes</h3>\n<p>A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.</p>\n<h4>Sequential Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">840,000 entries/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.08x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">124,000 entries/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:52px\">&nbsp;</div></td>\n    <td class=\"c4\">(2.55x baseline)</td></tr>\n</table>\n<h4>Random Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">221,000 entries/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.35x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">22,000 entries/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:34px\">&nbsp;</div></td>\n    <td class=\"c4\">(2.23x baseline)</td></tr>\n</table>\n\n<p>Because of the way LevelDB persistent storage is organized, batches of\nrandom writes are not much slower (only a factor of 4x) than batches\nof sequential writes.</p>\n\n<h3>C. Synchronous Writes</h3>\n<p>In the following benchmark, we enable the synchronous writing modes\nof all of the databases.  Since this change significantly slows down the\nbenchmark, we stop after 10,000 writes. For synchronous write tests, we've\ndisabled hard drive write-caching (using `hdparm -W 0 [device]`).</p>\n<ul>\n    <li>For LevelDB, we set WriteOptions.sync = true.</li>\n    <li>In TreeDB, we enabled TreeDB's OAUTOSYNC option.</li>\n    <li>For SQLite3, we set \"PRAGMA synchronous = FULL\".</li>\n</ul>\n<h4>Sequential Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">100 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.003x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">7 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:27px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.0004x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">88 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:315px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.002x baseline)</td></tr>\n</table>\n<h4>Random Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">100 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.015x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">8 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:29px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.001x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">88 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:314px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.009x baseline)</td></tr>\n</table>\n\n<p>Also see the <code>ext4</code> performance numbers below\nsince synchronous writes behave significantly differently\non <code>ext3</code> and <code>ext4</code>.</p>\n\n<h3>D. Turning Compression Off</h3>\n\n<p>In the baseline measurements, LevelDB and TreeDB were using\nlight-weight compression\n(<a href=\"http://code.google.com/p/snappy/\">Snappy</a> for LevelDB,\nand <a href=\"http://www.oberhumer.com/opensource/lzo/\">LZO</a> for\nTreeDB). SQLite3, by default does not use compression.  The\nexperiments below show what happens when compression is disabled in\nall of the databases (the SQLite3 numbers are just a copy of\nits baseline measurements):</p>\n\n<h4>Sequential Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">594,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.76x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">485,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:239px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.42x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">48,600 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:29px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.00x baseline)</td></tr>\n</table>\n<h4>Random Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">135,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:296px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.82x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">159,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.80x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">9,860 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:22px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.00x baseline)</td></tr>\n</table>\n\n<p>LevelDB's write performance is better with compression than without\nsince compression decreases the amount of data that has to be written\nto disk.  Therefore LevelDB users can leave compression enabled in\nmost scenarios without having worry about a tradeoff between space\nusage and performance.  TreeDB's performance on the other hand is\nbetter without compression than with compression.  Presumably this is\nbecause TreeDB's compression library (LZO) is more expensive than\nLevelDB's compression library (Snappy).<p>\n\n<h3>E. Using More Memory</h3>\n<p>We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).</p>\n<h4>Sequential Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">812,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.04x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">321,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:138px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.94x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">48,500 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:21px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.00x baseline)</td></tr>\n</table>\n<h4>Random Writes</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">355,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(2.16x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">284,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:280px\">&nbsp;</div></td>\n    <td class=\"c4\">(3.21x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">9,670 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:10px\">&nbsp;</div></td>\n    <td class=\"c4\">(0.98x baseline)</td></tr>\n</table>\n\n<p>SQLite's performance does not change substantially when compared to\nthe baseline, but the random write performance for both LevelDB and\nTreeDB increases significantly.  LevelDB's performance improves\nbecause a larger write buffer reduces the need to merge sorted files\n(since it creates a smaller number of larger sorted files).  TreeDB's\nperformance goes up because the entire database is available in memory\nfor fast in-place updates.</p>\n\n  <h2>3. Read Performance under Different Configurations</h2>\n<h3>A. Larger Caches</h3>\n<p>We increased the overall memory usage to 128 MB for each database.\nFor LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB\nto LevelDB's cache. The other databases don't differentiate between a\nwrite buffer and a cache, so we simply set their cache size to 128\nMB.</p>\n<h4>Sequential Reads</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">5,210,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.29x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">1,070,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:72px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.06x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">609,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:41px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.59x baseline)</td></tr>\n</table>\n\n<h4>Random Reads</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">190,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:144px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.47x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">463,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(3.07x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">186,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:141px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.39x baseline)</td></tr>\n</table>\n\n<p>As expected, the read performance of all of the databases increases\nwhen the caches are enlarged.  In particular, TreeDB seems to make\nvery effective use of a cache that is large enough to hold the entire\ndatabase.</p>\n\n<h3>B. No Compression Reads </h3>\n<p>For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.</p>\n<h4>Sequential Reads</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">4,880,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.21x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">1,230,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:88px\">&nbsp;</div></td>\n    <td class=\"c4\">(3.60x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">383,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:27px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.00x baseline)</td></tr>\n</table>\n<h4>Random Reads</h4>\n<table class=\"bn\">\n<tr><td class=\"c1\">LevelDB</td>\n    <td class=\"c2\">149,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bldb\" style=\"width:300px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.16x baseline)</td></tr>\n<tr><td class=\"c1\">Kyoto TreeDB</td>\n    <td class=\"c2\">175,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bkct\" style=\"width:350px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.16x baseline)</td></tr>\n<tr><td class=\"c1\">SQLite3</td>\n    <td class=\"c2\">134,000 ops/sec</td>\n    <td class=\"c3\"><div class=\"bsql\" style=\"width:268px\">&nbsp;</div></td>\n    <td class=\"c4\">(1.00x baseline)</td></tr>\n</table>\n\n<p>Performance of both LevelDB and TreeDB improves a small amount when\ncompression is disabled.  Note however that under different workloads,\nperformance may very well be better with compression if it allows more\nof the working set to fit in memory.</p>\n\n<h2>Note about Ext4 Filesystems</h2>\n<p>The preceding numbers are for an ext3 file system. Synchronous writes are much slower under <a href=\"http://en.wikipedia.org/wiki/Ext4\">ext4</a> (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of <span class=\"code\">fsync</span> / <span class=\"code\">msync</span> calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues <span class=\"code\">fsync</span> calls when switching to a new file.</p>\n\n<h2>Acknowledgements</h2>\n<p>Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.</p>\n</body>\n</html>\n"
  },
  {
    "path": "src/leveldb/doc/impl.md",
    "content": "## Files\n\nThe implementation of leveldb is similar in spirit to the representation of a\nsingle [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html).\nHowever the organization of the files that make up the representation is\nsomewhat different and is explained below.\n\nEach database is represented by a set of files stored in a directory. There are\nseveral different types of files as documented below:\n\n### Log files\n\nA log file (*.log) stores a sequence of recent updates. Each update is appended\nto the current log file. When the log file reaches a pre-determined size\n(approximately 4MB by default), it is converted to a sorted table (see below)\nand a new log file is created for future updates.\n\nA copy of the current log file is kept in an in-memory structure (the\n`memtable`). This copy is consulted on every read so that read operations\nreflect all logged updates.\n\n## Sorted tables\n\nA sorted table (*.ldb) stores a sequence of entries sorted by key. Each entry is\neither a value for the key, or a deletion marker for the key. (Deletion markers\nare kept around to hide obsolete values present in older sorted tables).\n\nThe set of sorted tables are organized into a sequence of levels. The sorted\ntable generated from a log file is placed in a special **young** level (also\ncalled level-0). When the number of young files exceeds a certain threshold\n(currently four), all of the young files are merged together with all of the\noverlapping level-1 files to produce a sequence of new level-1 files (we create\na new level-1 file for every 2MB of data.)\n\nFiles in the young level may contain overlapping keys. However files in other\nlevels have distinct non-overlapping key ranges. Consider level number L where\nL >= 1. When the combined size of files in level-L exceeds (10^L) MB (i.e., 10MB\nfor level-1, 100MB for level-2, ...), one file in level-L, and all of the\noverlapping files in level-(L+1) are merged to form a set of new files for\nlevel-(L+1). These merges have the effect of gradually migrating new updates\nfrom the young level to the largest level using only bulk reads and writes\n(i.e., minimizing expensive seeks).\n\n### Manifest\n\nA MANIFEST file lists the set of sorted tables that make up each level, the\ncorresponding key ranges, and other important metadata. A new MANIFEST file\n(with a new number embedded in the file name) is created whenever the database\nis reopened. The MANIFEST file is formatted as a log, and changes made to the\nserving state (as files are added or removed) are appended to this log.\n\n### Current\n\nCURRENT is a simple text file that contains the name of the latest MANIFEST\nfile.\n\n### Info logs\n\nInformational messages are printed to files named LOG and LOG.old.\n\n### Others\n\nOther files used for miscellaneous purposes may also be present (LOCK, *.dbtmp).\n\n## Level 0\n\nWhen the log file grows above a certain size (4MB by default):\nCreate a brand new memtable and log file and direct future updates here.\n\nIn the background:\n\n1. Write the contents of the previous memtable to an sstable.\n2. Discard the memtable.\n3. Delete the old log file and the old memtable.\n4. Add the new sstable to the young (level-0) level.\n\n## Compactions\n\nWhen the size of level L exceeds its limit, we compact it in a background\nthread. The compaction picks a file from level L and all overlapping files from\nthe next level L+1. Note that if a level-L file overlaps only part of a\nlevel-(L+1) file, the entire file at level-(L+1) is used as an input to the\ncompaction and will be discarded after the compaction.  Aside: because level-0\nis special (files in it may overlap each other), we treat compactions from\nlevel-0 to level-1 specially: a level-0 compaction may pick more than one\nlevel-0 file in case some of these files overlap each other.\n\nA compaction merges the contents of the picked files to produce a sequence of\nlevel-(L+1) files. We switch to producing a new level-(L+1) file after the\ncurrent output file has reached the target file size (2MB). We also switch to a\nnew output file when the key range of the current output file has grown enough\nto overlap more than ten level-(L+2) files.  This last rule ensures that a later\ncompaction of a level-(L+1) file will not pick up too much data from\nlevel-(L+2).\n\nThe old files are discarded and the new files are added to the serving state.\n\nCompactions for a particular level rotate through the key space. In more detail,\nfor each level L, we remember the ending key of the last compaction at level L.\nThe next compaction for level L will pick the first file that starts after this\nkey (wrapping around to the beginning of the key space if there is no such\nfile).\n\nCompactions drop overwritten values. They also drop deletion markers if there\nare no higher numbered levels that contain a file whose range overlaps the\ncurrent key.\n\n### Timing\n\nLevel-0 compactions will read up to four 1MB files from level-0, and at worst\nall the level-1 files (10MB). I.e., we will read 14MB and write 14MB.\n\nOther than the special level-0 compactions, we will pick one 2MB file from level\nL. In the worst case, this will overlap ~ 12 files from level L+1 (10 because\nlevel-(L+1) is ten times the size of level-L, and another two at the boundaries\nsince the file ranges at level-L will usually not be aligned with the file\nranges at level-L+1). The compaction will therefore read 26MB and write 26MB.\nAssuming a disk IO rate of 100MB/s (ballpark range for modern drives), the worst\ncompaction cost will be approximately 0.5 second.\n\nIf we throttle the background writing to something small, say 10% of the full\n100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at\n10MB/s, we might build up lots of level-0 files (~50 to hold the 5*10MB). This\nmay significantly increase the cost of reads due to the overhead of merging more\nfiles together on every read.\n\nSolution 1: To reduce this problem, we might want to increase the log switching\nthreshold when the number of level-0 files is large. Though the downside is that\nthe larger this threshold, the more memory we will need to hold the\ncorresponding memtable.\n\nSolution 2: We might want to decrease write rate artificially when the number of\nlevel-0 files goes up.\n\nSolution 3: We work on reducing the cost of very wide merges. Perhaps most of\nthe level-0 files will have their blocks sitting uncompressed in the cache and\nwe will only need to worry about the O(N) complexity in the merging iterator.\n\n### Number of files\n\nInstead of always making 2MB files, we could make larger files for larger levels\nto reduce the total file count, though at the expense of more bursty\ncompactions.  Alternatively, we could shard the set of files into multiple\ndirectories.\n\nAn experiment on an ext3 filesystem on Feb 04, 2011 shows the following timings\nto do 100K file opens in directories with varying number of files:\n\n\n| Files in directory | Microseconds to open a file |\n|-------------------:|----------------------------:|\n|               1000 |                           9 |\n|              10000 |                          10 |\n|             100000 |                          16 |\n\nSo maybe even the sharding is not necessary on modern filesystems?\n\n## Recovery\n\n* Read CURRENT to find name of the latest committed MANIFEST\n* Read the named MANIFEST file\n* Clean up stale files\n* We could open all sstables here, but it is probably better to be lazy...\n* Convert log chunk to a new level-0 sstable\n* Start directing new writes to a new log file with recovered sequence#\n\n## Garbage collection of files\n\n`DeleteObsoleteFiles()` is called at the end of every compaction and at the end\nof recovery. It finds the names of all files in the database. It deletes all log\nfiles that are not the current log file. It deletes all table files that are not\nreferenced from some level and are not the output of an active compaction.\n"
  },
  {
    "path": "src/leveldb/doc/index.md",
    "content": "leveldb\n=======\n\n_Jeff Dean, Sanjay Ghemawat_\n\nThe leveldb library provides a persistent key value store. Keys and values are\narbitrary byte arrays.  The keys are ordered within the key value store\naccording to a user-specified comparator function.\n\n## Opening A Database\n\nA leveldb database has a name which corresponds to a file system directory. All\nof the contents of database are stored in this directory. The following example\nshows how to open a database, creating it if necessary:\n\n```c++\n#include <cassert>\n#include \"leveldb/db.h\"\n\nleveldb::DB* db;\nleveldb::Options options;\noptions.create_if_missing = true;\nleveldb::Status status = leveldb::DB::Open(options, \"/tmp/testdb\", &db);\nassert(status.ok());\n...\n```\n\nIf you want to raise an error if the database already exists, add the following\nline before the `leveldb::DB::Open` call:\n\n```c++\noptions.error_if_exists = true;\n```\n\n## Status\n\nYou may have noticed the `leveldb::Status` type above. Values of this type are\nreturned by most functions in leveldb that may encounter an error. You can check\nif such a result is ok, and also print an associated error message:\n\n```c++\nleveldb::Status s = ...;\nif (!s.ok()) cerr << s.ToString() << endl;\n```\n\n## Closing A Database\n\nWhen you are done with a database, just delete the database object. Example:\n\n```c++\n... open the db as described above ...\n... do something with db ...\ndelete db;\n```\n\n## Reads And Writes\n\nThe database provides Put, Delete, and Get methods to modify/query the database.\nFor example, the following code moves the value stored under key1 to key2.\n\n```c++\nstd::string value;\nleveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);\nif (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);\nif (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);\n```\n\n## Atomic Updates\n\nNote that if the process dies after the Put of key2 but before the delete of\nkey1, the same value may be left stored under multiple keys. Such problems can\nbe avoided by using the `WriteBatch` class to atomically apply a set of updates:\n\n```c++\n#include \"leveldb/write_batch.h\"\n...\nstd::string value;\nleveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);\nif (s.ok()) {\n  leveldb::WriteBatch batch;\n  batch.Delete(key1);\n  batch.Put(key2, value);\n  s = db->Write(leveldb::WriteOptions(), &batch);\n}\n```\n\nThe `WriteBatch` holds a sequence of edits to be made to the database, and these\nedits within the batch are applied in order. Note that we called Delete before\nPut so that if key1 is identical to key2, we do not end up erroneously dropping\nthe value entirely.\n\nApart from its atomicity benefits, `WriteBatch` may also be used to speed up\nbulk updates by placing lots of individual mutations into the same batch.\n\n## Synchronous Writes\n\nBy default, each write to leveldb is asynchronous: it returns after pushing the\nwrite from the process into the operating system. The transfer from operating\nsystem memory to the underlying persistent storage happens asynchronously. The\nsync flag can be turned on for a particular write to make the write operation\nnot return until the data being written has been pushed all the way to\npersistent storage. (On Posix systems, this is implemented by calling either\n`fsync(...)` or `fdatasync(...)` or `msync(..., MS_SYNC)` before the write\noperation returns.)\n\n```c++\nleveldb::WriteOptions write_options;\nwrite_options.sync = true;\ndb->Put(write_options, ...);\n```\n\nAsynchronous writes are often more than a thousand times as fast as synchronous\nwrites. The downside of asynchronous writes is that a crash of the machine may\ncause the last few updates to be lost. Note that a crash of just the writing\nprocess (i.e., not a reboot) will not cause any loss since even when sync is\nfalse, an update is pushed from the process memory into the operating system\nbefore it is considered done.\n\nAsynchronous writes can often be used safely. For example, when loading a large\namount of data into the database you can handle lost updates by restarting the\nbulk load after a crash. A hybrid scheme is also possible where every Nth write\nis synchronous, and in the event of a crash, the bulk load is restarted just\nafter the last synchronous write finished by the previous run. (The synchronous\nwrite can update a marker that describes where to restart on a crash.)\n\n`WriteBatch` provides an alternative to asynchronous writes. Multiple updates\nmay be placed in the same WriteBatch and applied together using a synchronous\nwrite (i.e., `write_options.sync` is set to true). The extra cost of the\nsynchronous write will be amortized across all of the writes in the batch.\n\n## Concurrency\n\nA database may only be opened by one process at a time. The leveldb\nimplementation acquires a lock from the operating system to prevent misuse.\nWithin a single process, the same `leveldb::DB` object may be safely shared by\nmultiple concurrent threads. I.e., different threads may write into or fetch\niterators or call Get on the same database without any external synchronization\n(the leveldb implementation will automatically do the required synchronization).\nHowever other objects (like Iterator and `WriteBatch`) may require external\nsynchronization. If two threads share such an object, they must protect access\nto it using their own locking protocol. More details are available in the public\nheader files.\n\n## Iteration\n\nThe following example demonstrates how to print all key,value pairs in a\ndatabase.\n\n```c++\nleveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());\nfor (it->SeekToFirst(); it->Valid(); it->Next()) {\n  cout << it->key().ToString() << \": \"  << it->value().ToString() << endl;\n}\nassert(it->status().ok());  // Check for any errors found during the scan\ndelete it;\n```\n\nThe following variation shows how to process just the keys in the range\n[start,limit):\n\n```c++\nfor (it->Seek(start);\n   it->Valid() && it->key().ToString() < limit;\n   it->Next()) {\n  ...\n}\n```\n\nYou can also process entries in reverse order. (Caveat: reverse iteration may be\nsomewhat slower than forward iteration.)\n\n```c++\nfor (it->SeekToLast(); it->Valid(); it->Prev()) {\n  ...\n}\n```\n\n## Snapshots\n\nSnapshots provide consistent read-only views over the entire state of the\nkey-value store.  `ReadOptions::snapshot` may be non-NULL to indicate that a\nread should operate on a particular version of the DB state. If\n`ReadOptions::snapshot` is NULL, the read will operate on an implicit snapshot\nof the current state.\n\nSnapshots are created by the `DB::GetSnapshot()` method:\n\n```c++\nleveldb::ReadOptions options;\noptions.snapshot = db->GetSnapshot();\n... apply some updates to db ...\nleveldb::Iterator* iter = db->NewIterator(options);\n... read using iter to view the state when the snapshot was created ...\ndelete iter;\ndb->ReleaseSnapshot(options.snapshot);\n```\n\nNote that when a snapshot is no longer needed, it should be released using the\n`DB::ReleaseSnapshot` interface. This allows the implementation to get rid of\nstate that was being maintained just to support reading as of that snapshot.\n\n## Slice\n\nThe return value of the `it->key()` and `it->value()` calls above are instances\nof the `leveldb::Slice` type. Slice is a simple structure that contains a length\nand a pointer to an external byte array. Returning a Slice is a cheaper\nalternative to returning a `std::string` since we do not need to copy\npotentially large keys and values. In addition, leveldb methods do not return\nnull-terminated C-style strings since leveldb keys and values are allowed to\ncontain `'\\0'` bytes.\n\nC++ strings and null-terminated C-style strings can be easily converted to a\nSlice:\n\n```c++\nleveldb::Slice s1 = \"hello\";\n\nstd::string str(\"world\");\nleveldb::Slice s2 = str;\n```\n\nA Slice can be easily converted back to a C++ string:\n\n```c++\nstd::string str = s1.ToString();\nassert(str == std::string(\"hello\"));\n```\n\nBe careful when using Slices since it is up to the caller to ensure that the\nexternal byte array into which the Slice points remains live while the Slice is\nin use. For example, the following is buggy:\n\n```c++\nleveldb::Slice slice;\nif (...) {\n  std::string str = ...;\n  slice = str;\n}\nUse(slice);\n```\n\nWhen the if statement goes out of scope, str will be destroyed and the backing\nstorage for slice will disappear.\n\n## Comparators\n\nThe preceding examples used the default ordering function for key, which orders\nbytes lexicographically. You can however supply a custom comparator when opening\na database.  For example, suppose each database key consists of two numbers and\nwe should sort by the first number, breaking ties by the second number. First,\ndefine a proper subclass of `leveldb::Comparator` that expresses these rules:\n\n```c++\nclass TwoPartComparator : public leveldb::Comparator {\n public:\n  // Three-way comparison function:\n  //   if a < b: negative result\n  //   if a > b: positive result\n  //   else: zero result\n  int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {\n    int a1, a2, b1, b2;\n    ParseKey(a, &a1, &a2);\n    ParseKey(b, &b1, &b2);\n    if (a1 < b1) return -1;\n    if (a1 > b1) return +1;\n    if (a2 < b2) return -1;\n    if (a2 > b2) return +1;\n    return 0;\n  }\n\n  // Ignore the following methods for now:\n  const char* Name() const { return \"TwoPartComparator\"; }\n  void FindShortestSeparator(std::string*, const leveldb::Slice&) const {}\n  void FindShortSuccessor(std::string*) const {}\n};\n```\n\nNow create a database using this custom comparator:\n\n```c++\nTwoPartComparator cmp;\nleveldb::DB* db;\nleveldb::Options options;\noptions.create_if_missing = true;\noptions.comparator = &cmp;\nleveldb::Status status = leveldb::DB::Open(options, \"/tmp/testdb\", &db);\n...\n```\n\n### Backwards compatibility\n\nThe result of the comparator's Name method is attached to the database when it\nis created, and is checked on every subsequent database open. If the name\nchanges, the `leveldb::DB::Open` call will fail. Therefore, change the name if\nand only if the new key format and comparison function are incompatible with\nexisting databases, and it is ok to discard the contents of all existing\ndatabases.\n\nYou can however still gradually evolve your key format over time with a little\nbit of pre-planning. For example, you could store a version number at the end of\neach key (one byte should suffice for most uses). When you wish to switch to a\nnew key format (e.g., adding an optional third part to the keys processed by\n`TwoPartComparator`), (a) keep the same comparator name (b) increment the\nversion number for new keys (c) change the comparator function so it uses the\nversion numbers found in the keys to decide how to interpret them.\n\n## Performance\n\nPerformance can be tuned by changing the default values of the types defined in\n`include/options.h`.\n\n### Block size\n\nleveldb groups adjacent keys together into the same block and such a block is\nthe unit of transfer to and from persistent storage. The default block size is\napproximately 4096 uncompressed bytes.  Applications that mostly do bulk scans\nover the contents of the database may wish to increase this size. Applications\nthat do a lot of point reads of small values may wish to switch to a smaller\nblock size if performance measurements indicate an improvement. There isn't much\nbenefit in using blocks smaller than one kilobyte, or larger than a few\nmegabytes. Also note that compression will be more effective with larger block\nsizes.\n\n### Compression\n\nEach block is individually compressed before being written to persistent\nstorage. Compression is on by default since the default compression method is\nvery fast, and is automatically disabled for uncompressible data. In rare cases,\napplications may want to disable compression entirely, but should only do so if\nbenchmarks show a performance improvement:\n\n```c++\nleveldb::Options options;\noptions.compression = leveldb::kNoCompression;\n... leveldb::DB::Open(options, name, ...) ....\n```\n\n### Cache\n\nThe contents of the database are stored in a set of files in the filesystem and\neach file stores a sequence of compressed blocks. If options.block_cache is\nnon-NULL, it is used to cache frequently used uncompressed block contents.\n\n```c++\n#include \"leveldb/cache.h\"\n\nleveldb::Options options;\noptions.block_cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache\nleveldb::DB* db;\nleveldb::DB::Open(options, name, &db);\n... use the db ...\ndelete db\ndelete options.block_cache;\n```\n\nNote that the cache holds uncompressed data, and therefore it should be sized\naccording to application level data sizes, without any reduction from\ncompression. (Caching of compressed blocks is left to the operating system\nbuffer cache, or any custom Env implementation provided by the client.)\n\nWhen performing a bulk read, the application may wish to disable caching so that\nthe data processed by the bulk read does not end up displacing most of the\ncached contents. A per-iterator option can be used to achieve this:\n\n```c++\nleveldb::ReadOptions options;\noptions.fill_cache = false;\nleveldb::Iterator* it = db->NewIterator(options);\nfor (it->SeekToFirst(); it->Valid(); it->Next()) {\n  ...\n}\n```\n\n### Key Layout\n\nNote that the unit of disk transfer and caching is a block. Adjacent keys\n(according to the database sort order) will usually be placed in the same block.\nTherefore the application can improve its performance by placing keys that are\naccessed together near each other and placing infrequently used keys in a\nseparate region of the key space.\n\nFor example, suppose we are implementing a simple file system on top of leveldb.\nThe types of entries we might wish to store are:\n\n    filename -> permission-bits, length, list of file_block_ids\n    file_block_id -> data\n\nWe might want to prefix filename keys with one letter (say '/') and the\n`file_block_id` keys with a different letter (say '0') so that scans over just\nthe metadata do not force us to fetch and cache bulky file contents.\n\n### Filters\n\nBecause of the way leveldb data is organized on disk, a single `Get()` call may\ninvolve multiple reads from disk. The optional FilterPolicy mechanism can be\nused to reduce the number of disk reads substantially.\n\n```c++\nleveldb::Options options;\noptions.filter_policy = NewBloomFilterPolicy(10);\nleveldb::DB* db;\nleveldb::DB::Open(options, \"/tmp/testdb\", &db);\n... use the database ...\ndelete db;\ndelete options.filter_policy;\n```\n\nThe preceding code associates a Bloom filter based filtering policy with the\ndatabase.  Bloom filter based filtering relies on keeping some number of bits of\ndata in memory per key (in this case 10 bits per key since that is the argument\nwe passed to `NewBloomFilterPolicy`). This filter will reduce the number of\nunnecessary disk reads needed for Get() calls by a factor of approximately\na 100. Increasing the bits per key will lead to a larger reduction at the cost\nof more memory usage. We recommend that applications whose working set does not\nfit in memory and that do a lot of random reads set a filter policy.\n\nIf you are using a custom comparator, you should ensure that the filter policy\nyou are using is compatible with your comparator. For example, consider a\ncomparator that ignores trailing spaces when comparing keys.\n`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the\napplication should provide a custom filter policy that also ignores trailing\nspaces. For example:\n\n```c++\nclass CustomFilterPolicy : public leveldb::FilterPolicy {\n private:\n  FilterPolicy* builtin_policy_;\n\n public:\n  CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {}\n  ~CustomFilterPolicy() { delete builtin_policy_; }\n\n  const char* Name() const { return \"IgnoreTrailingSpacesFilter\"; }\n\n  void CreateFilter(const Slice* keys, int n, std::string* dst) const {\n    // Use builtin bloom filter code after removing trailing spaces\n    std::vector<Slice> trimmed(n);\n    for (int i = 0; i < n; i++) {\n      trimmed[i] = RemoveTrailingSpaces(keys[i]);\n    }\n    return builtin_policy_->CreateFilter(&trimmed[i], n, dst);\n  }\n};\n```\n\nAdvanced applications may provide a filter policy that does not use a bloom\nfilter but uses some other mechanism for summarizing a set of keys. See\n`leveldb/filter_policy.h` for detail.\n\n## Checksums\n\nleveldb associates checksums with all data it stores in the file system. There\nare two separate controls provided over how aggressively these checksums are\nverified:\n\n`ReadOptions::verify_checksums` may be set to true to force checksum\nverification of all data that is read from the file system on behalf of a\nparticular read.  By default, no such verification is done.\n\n`Options::paranoid_checks` may be set to true before opening a database to make\nthe database implementation raise an error as soon as it detects an internal\ncorruption. Depending on which portion of the database has been corrupted, the\nerror may be raised when the database is opened, or later by another database\noperation. By default, paranoid checking is off so that the database can be used\neven if parts of its persistent storage have been corrupted.\n\nIf a database is corrupted (perhaps it cannot be opened when paranoid checking\nis turned on), the `leveldb::RepairDB` function may be used to recover as much\nof the data as possible\n\n## Approximate Sizes\n\nThe `GetApproximateSizes` method can used to get the approximate number of bytes\nof file system space used by one or more key ranges.\n\n```c++\nleveldb::Range ranges[2];\nranges[0] = leveldb::Range(\"a\", \"c\");\nranges[1] = leveldb::Range(\"x\", \"z\");\nuint64_t sizes[2];\nleveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);\n```\n\nThe preceding call will set `sizes[0]` to the approximate number of bytes of\nfile system space used by the key range `[a..c)` and `sizes[1]` to the\napproximate number of bytes used by the key range `[x..z)`.\n\n## Environment\n\nAll file operations (and other operating system calls) issued by the leveldb\nimplementation are routed through a `leveldb::Env` object. Sophisticated clients\nmay wish to provide their own Env implementation to get better control.\nFor example, an application may introduce artificial delays in the file IO\npaths to limit the impact of leveldb on other activities in the system.\n\n```c++\nclass SlowEnv : public leveldb::Env {\n  ... implementation of the Env interface ...\n};\n\nSlowEnv env;\nleveldb::Options options;\noptions.env = &env;\nStatus s = leveldb::DB::Open(options, ...);\n```\n\n## Porting\n\nleveldb may be ported to a new platform by providing platform specific\nimplementations of the types/methods/functions exported by\n`leveldb/port/port.h`.  See `leveldb/port/port_example.h` for more details.\n\nIn addition, the new platform may need a new default `leveldb::Env`\nimplementation.  See `leveldb/util/env_posix.h` for an example.\n\n## Other Information\n\nDetails about the leveldb implementation may be found in the following\ndocuments:\n\n1. [Implementation notes](impl.md)\n2. [Format of an immutable Table file](table_format.md)\n3. [Format of a log file](log_format.md)\n"
  },
  {
    "path": "src/leveldb/doc/log_format.md",
    "content": "leveldb Log format\n==================\nThe log file contents are a sequence of 32KB blocks.  The only exception is that\nthe tail of the file may contain a partial block.\n\nEach block consists of a sequence of records:\n\n    block := record* trailer?\n    record :=\n      checksum: uint32     // crc32c of type and data[] ; little-endian\n      length: uint16       // little-endian\n      type: uint8          // One of FULL, FIRST, MIDDLE, LAST\n      data: uint8[length]\n\nA record never starts within the last six bytes of a block (since it won't fit).\nAny leftover bytes here form the trailer, which must consist entirely of zero\nbytes and must be skipped by readers.\n\nAside: if exactly seven bytes are left in the current block, and a new non-zero\nlength record is added, the writer must emit a FIRST record (which contains zero\nbytes of user data) to fill up the trailing seven bytes of the block and then\nemit all of the user data in subsequent blocks.\n\nMore types may be added in the future.  Some Readers may skip record types they\ndo not understand, others may report that some data was skipped.\n\n    FULL == 1\n    FIRST == 2\n    MIDDLE == 3\n    LAST == 4\n\nThe FULL record contains the contents of an entire user record.\n\nFIRST, MIDDLE, LAST are types used for user records that have been split into\nmultiple fragments (typically because of block boundaries).  FIRST is the type\nof the first fragment of a user record, LAST is the type of the last fragment of\na user record, and MIDDLE is the type of all interior fragments of a user\nrecord.\n\nExample: consider a sequence of user records:\n\n    A: length 1000\n    B: length 97270\n    C: length 8000\n\n**A** will be stored as a FULL record in the first block.\n\n**B** will be split into three fragments: first fragment occupies the rest of\nthe first block, second fragment occupies the entirety of the second block, and\nthe third fragment occupies a prefix of the third block.  This will leave six\nbytes free in the third block, which will be left empty as the trailer.\n\n**C** will be stored as a FULL record in the fourth block.\n\n----\n\n## Some benefits over the recordio format:\n\n1. We do not need any heuristics for resyncing - just go to next block boundary\n   and scan.  If there is a corruption, skip to the next block.  As a\n   side-benefit, we do not get confused when part of the contents of one log\n   file are embedded as a record inside another log file.\n\n2. Splitting at approximate boundaries (e.g., for mapreduce) is simple: find the\n   next block boundary and skip records until we hit a FULL or FIRST record.\n\n3. We do not need extra buffering for large records.\n\n## Some downsides compared to recordio format:\n\n1. No packing of tiny records.  This could be fixed by adding a new record type,\n   so it is a shortcoming of the current implementation, not necessarily the\n   format.\n\n2. No compression.  Again, this could be fixed by adding new record types.\n"
  },
  {
    "path": "src/leveldb/doc/table_format.md",
    "content": "leveldb File format\n===================\n\n    <beginning_of_file>\n    [data block 1]\n    [data block 2]\n    ...\n    [data block N]\n    [meta block 1]\n    ...\n    [meta block K]\n    [metaindex block]\n    [index block]\n    [Footer]        (fixed size; starts at file_size - sizeof(Footer))\n    <end_of_file>\n\nThe file contains internal pointers.  Each such pointer is called\na BlockHandle and contains the following information:\n\n    offset:   varint64\n    size:     varint64\n\nSee [varints](https://developers.google.com/protocol-buffers/docs/encoding#varints)\nfor an explanation of varint64 format.\n\n1.  The sequence of key/value pairs in the file are stored in sorted\norder and partitioned into a sequence of data blocks.  These blocks\ncome one after another at the beginning of the file.  Each data block\nis formatted according to the code in `block_builder.cc`, and then\noptionally compressed.\n\n2. After the data blocks we store a bunch of meta blocks.  The\nsupported meta block types are described below.  More meta block types\nmay be added in the future.  Each meta block is again formatted using\n`block_builder.cc` and then optionally compressed.\n\n3. A \"metaindex\" block.  It contains one entry for every other meta\nblock where the key is the name of the meta block and the value is a\nBlockHandle pointing to that meta block.\n\n4. An \"index\" block.  This block contains one entry per data block,\nwhere the key is a string >= last key in that data block and before\nthe first key in the successive data block.  The value is the\nBlockHandle for the data block.\n\n5. At the very end of the file is a fixed length footer that contains\nthe BlockHandle of the metaindex and index blocks as well as a magic number.\n\n        metaindex_handle: char[p];     // Block handle for metaindex\n        index_handle:     char[q];     // Block handle for index\n        padding:          char[40-p-q];// zeroed bytes to make fixed length\n                                       // (40==2*BlockHandle::kMaxEncodedLength)\n        magic:            fixed64;     // == 0xdb4775248b80fb57 (little-endian)\n\n## \"filter\" Meta Block\n\nIf a `FilterPolicy` was specified when the database was opened, a\nfilter block is stored in each table.  The \"metaindex\" block contains\nan entry that maps from `filter.<N>` to the BlockHandle for the filter\nblock where `<N>` is the string returned by the filter policy's\n`Name()` method.\n\nThe filter block stores a sequence of filters, where filter i contains\nthe output of `FilterPolicy::CreateFilter()` on all keys that are stored\nin a block whose file offset falls within the range\n\n    [ i*base ... (i+1)*base-1 ]\n\nCurrently, \"base\" is 2KB.  So for example, if blocks X and Y start in\nthe range `[ 0KB .. 2KB-1 ]`, all of the keys in X and Y will be\nconverted to a filter by calling `FilterPolicy::CreateFilter()`, and the\nresulting filter will be stored as the first filter in the filter\nblock.\n\nThe filter block is formatted as follows:\n\n    [filter 0]\n    [filter 1]\n    [filter 2]\n    ...\n    [filter N-1]\n\n    [offset of filter 0]                  : 4 bytes\n    [offset of filter 1]                  : 4 bytes\n    [offset of filter 2]                  : 4 bytes\n    ...\n    [offset of filter N-1]                : 4 bytes\n\n    [offset of beginning of offset array] : 4 bytes\n    lg(base)                              : 1 byte\n\nThe offset array at the end of the filter block allows efficient\nmapping from a data block offset to the corresponding filter.\n\n## \"stats\" Meta Block\n\nThis meta block contains a bunch of stats.  The key is the name\nof the statistic.  The value contains the statistic.\n\nTODO(postrelease): record following stats.\n\n    data size\n    index size\n    key size (uncompressed)\n    value size (uncompressed)\n    number of entries\n    number of data blocks\n"
  },
  {
    "path": "src/leveldb/helpers/memenv/memenv.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"helpers/memenv/memenv.h\"\n\n#include <string.h>\n\n#include <limits>\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"leveldb/env.h\"\n#include \"leveldb/status.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/mutexlock.h\"\n\nnamespace leveldb {\n\nnamespace {\n\nclass FileState {\n public:\n  // FileStates are reference counted. The initial reference count is zero\n  // and the caller must call Ref() at least once.\n  FileState() : refs_(0), size_(0) {}\n\n  // No copying allowed.\n  FileState(const FileState&) = delete;\n  FileState& operator=(const FileState&) = delete;\n\n  // Increase the reference count.\n  void Ref() {\n    MutexLock lock(&refs_mutex_);\n    ++refs_;\n  }\n\n  // Decrease the reference count. Delete if this is the last reference.\n  void Unref() {\n    bool do_delete = false;\n\n    {\n      MutexLock lock(&refs_mutex_);\n      --refs_;\n      assert(refs_ >= 0);\n      if (refs_ <= 0) {\n        do_delete = true;\n      }\n    }\n\n    if (do_delete) {\n      delete this;\n    }\n  }\n\n  uint64_t Size() const {\n    MutexLock lock(&blocks_mutex_);\n    return size_;\n  }\n\n  void Truncate() {\n    MutexLock lock(&blocks_mutex_);\n    for (char*& block : blocks_) {\n      delete[] block;\n    }\n    blocks_.clear();\n    size_ = 0;\n  }\n\n  Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {\n    MutexLock lock(&blocks_mutex_);\n    if (offset > size_) {\n      return Status::IOError(\"Offset greater than file size.\");\n    }\n    const uint64_t available = size_ - offset;\n    if (n > available) {\n      n = static_cast<size_t>(available);\n    }\n    if (n == 0) {\n      *result = Slice();\n      return Status::OK();\n    }\n\n    assert(offset / kBlockSize <= std::numeric_limits<size_t>::max());\n    size_t block = static_cast<size_t>(offset / kBlockSize);\n    size_t block_offset = offset % kBlockSize;\n    size_t bytes_to_copy = n;\n    char* dst = scratch;\n\n    while (bytes_to_copy > 0) {\n      size_t avail = kBlockSize - block_offset;\n      if (avail > bytes_to_copy) {\n        avail = bytes_to_copy;\n      }\n      memcpy(dst, blocks_[block] + block_offset, avail);\n\n      bytes_to_copy -= avail;\n      dst += avail;\n      block++;\n      block_offset = 0;\n    }\n\n    *result = Slice(scratch, n);\n    return Status::OK();\n  }\n\n  Status Append(const Slice& data) {\n    const char* src = data.data();\n    size_t src_len = data.size();\n\n    MutexLock lock(&blocks_mutex_);\n    while (src_len > 0) {\n      size_t avail;\n      size_t offset = size_ % kBlockSize;\n\n      if (offset != 0) {\n        // There is some room in the last block.\n        avail = kBlockSize - offset;\n      } else {\n        // No room in the last block; push new one.\n        blocks_.push_back(new char[kBlockSize]);\n        avail = kBlockSize;\n      }\n\n      if (avail > src_len) {\n        avail = src_len;\n      }\n      memcpy(blocks_.back() + offset, src, avail);\n      src_len -= avail;\n      src += avail;\n      size_ += avail;\n    }\n\n    return Status::OK();\n  }\n\n private:\n  enum { kBlockSize = 8 * 1024 };\n\n  // Private since only Unref() should be used to delete it.\n  ~FileState() { Truncate(); }\n\n  port::Mutex refs_mutex_;\n  int refs_ GUARDED_BY(refs_mutex_);\n\n  mutable port::Mutex blocks_mutex_;\n  std::vector<char*> blocks_ GUARDED_BY(blocks_mutex_);\n  uint64_t size_ GUARDED_BY(blocks_mutex_);\n};\n\nclass SequentialFileImpl : public SequentialFile {\n public:\n  explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {\n    file_->Ref();\n  }\n\n  ~SequentialFileImpl() override { file_->Unref(); }\n\n  Status Read(size_t n, Slice* result, char* scratch) override {\n    Status s = file_->Read(pos_, n, result, scratch);\n    if (s.ok()) {\n      pos_ += result->size();\n    }\n    return s;\n  }\n\n  Status Skip(uint64_t n) override {\n    if (pos_ > file_->Size()) {\n      return Status::IOError(\"pos_ > file_->Size()\");\n    }\n    const uint64_t available = file_->Size() - pos_;\n    if (n > available) {\n      n = available;\n    }\n    pos_ += n;\n    return Status::OK();\n  }\n\n  virtual std::string GetName() const override { return \"[memenv]\"; }\n private:\n  FileState* file_;\n  uint64_t pos_;\n};\n\nclass RandomAccessFileImpl : public RandomAccessFile {\n public:\n  explicit RandomAccessFileImpl(FileState* file) : file_(file) { file_->Ref(); }\n\n  ~RandomAccessFileImpl() override { file_->Unref(); }\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    return file_->Read(offset, n, result, scratch);\n  }\n\n  virtual std::string GetName() const override { return \"[memenv]\"; }\n private:\n  FileState* file_;\n};\n\nclass WritableFileImpl : public WritableFile {\n public:\n  WritableFileImpl(FileState* file) : file_(file) { file_->Ref(); }\n\n  ~WritableFileImpl() override { file_->Unref(); }\n\n  Status Append(const Slice& data) override { return file_->Append(data); }\n\n  Status Close() override { return Status::OK(); }\n  Status Flush() override { return Status::OK(); }\n  Status Sync() override { return Status::OK(); }\n\n  virtual std::string GetName() const override { return \"[memenv]\"; }\n private:\n  FileState* file_;\n};\n\nclass NoOpLogger : public Logger {\n public:\n  void Logv(const char* format, va_list ap) override {}\n};\n\nclass InMemoryEnv : public EnvWrapper {\n public:\n  explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) {}\n\n  ~InMemoryEnv() override {\n    for (const auto& kvp : file_map_) {\n      kvp.second->Unref();\n    }\n  }\n\n  // Partial implementation of the Env interface.\n  Status NewSequentialFile(const std::string& fname,\n                           SequentialFile** result) override {\n    MutexLock lock(&mutex_);\n    if (file_map_.find(fname) == file_map_.end()) {\n      *result = nullptr;\n      return Status::IOError(fname, \"File not found\");\n    }\n\n    *result = new SequentialFileImpl(file_map_[fname]);\n    return Status::OK();\n  }\n\n  Status NewRandomAccessFile(const std::string& fname,\n                             RandomAccessFile** result) override {\n    MutexLock lock(&mutex_);\n    if (file_map_.find(fname) == file_map_.end()) {\n      *result = nullptr;\n      return Status::IOError(fname, \"File not found\");\n    }\n\n    *result = new RandomAccessFileImpl(file_map_[fname]);\n    return Status::OK();\n  }\n\n  Status NewWritableFile(const std::string& fname,\n                         WritableFile** result) override {\n    MutexLock lock(&mutex_);\n    FileSystem::iterator it = file_map_.find(fname);\n\n    FileState* file;\n    if (it == file_map_.end()) {\n      // File is not currently open.\n      file = new FileState();\n      file->Ref();\n      file_map_[fname] = file;\n    } else {\n      file = it->second;\n      file->Truncate();\n    }\n\n    *result = new WritableFileImpl(file);\n    return Status::OK();\n  }\n\n  Status NewAppendableFile(const std::string& fname,\n                           WritableFile** result) override {\n    MutexLock lock(&mutex_);\n    FileState** sptr = &file_map_[fname];\n    FileState* file = *sptr;\n    if (file == nullptr) {\n      file = new FileState();\n      file->Ref();\n    }\n    *result = new WritableFileImpl(file);\n    return Status::OK();\n  }\n\n  bool FileExists(const std::string& fname) override {\n    MutexLock lock(&mutex_);\n    return file_map_.find(fname) != file_map_.end();\n  }\n\n  Status GetChildren(const std::string& dir,\n                     std::vector<std::string>* result) override {\n    MutexLock lock(&mutex_);\n    result->clear();\n\n    for (const auto& kvp : file_map_) {\n      const std::string& filename = kvp.first;\n\n      if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&\n          Slice(filename).starts_with(Slice(dir))) {\n        result->push_back(filename.substr(dir.size() + 1));\n      }\n    }\n\n    return Status::OK();\n  }\n\n  void DeleteFileInternal(const std::string& fname)\n      EXCLUSIVE_LOCKS_REQUIRED(mutex_) {\n    if (file_map_.find(fname) == file_map_.end()) {\n      return;\n    }\n\n    file_map_[fname]->Unref();\n    file_map_.erase(fname);\n  }\n\n  Status DeleteFile(const std::string& fname) override {\n    MutexLock lock(&mutex_);\n    if (file_map_.find(fname) == file_map_.end()) {\n      return Status::IOError(fname, \"File not found\");\n    }\n\n    DeleteFileInternal(fname);\n    return Status::OK();\n  }\n\n  Status CreateDir(const std::string& dirname) override { return Status::OK(); }\n\n  Status DeleteDir(const std::string& dirname) override { return Status::OK(); }\n\n  Status GetFileSize(const std::string& fname, uint64_t* file_size) override {\n    MutexLock lock(&mutex_);\n    if (file_map_.find(fname) == file_map_.end()) {\n      return Status::IOError(fname, \"File not found\");\n    }\n\n    *file_size = file_map_[fname]->Size();\n    return Status::OK();\n  }\n\n  Status RenameFile(const std::string& src,\n                    const std::string& target) override {\n    MutexLock lock(&mutex_);\n    if (file_map_.find(src) == file_map_.end()) {\n      return Status::IOError(src, \"File not found\");\n    }\n\n    DeleteFileInternal(target);\n    file_map_[target] = file_map_[src];\n    file_map_.erase(src);\n    return Status::OK();\n  }\n\n  Status LockFile(const std::string& fname, FileLock** lock) override {\n    *lock = new FileLock;\n    return Status::OK();\n  }\n\n  Status UnlockFile(FileLock* lock) override {\n    delete lock;\n    return Status::OK();\n  }\n\n  Status GetTestDirectory(std::string* path) override {\n    *path = \"/test\";\n    return Status::OK();\n  }\n\n  Status NewLogger(const std::string& fname, Logger** result) override {\n    *result = new NoOpLogger;\n    return Status::OK();\n  }\n\n private:\n  // Map from filenames to FileState objects, representing a simple file system.\n  typedef std::map<std::string, FileState*> FileSystem;\n\n  port::Mutex mutex_;\n  FileSystem file_map_ GUARDED_BY(mutex_);\n};\n\n}  // namespace\n\nEnv* NewMemEnv(Env* base_env) { return new InMemoryEnv(base_env); }\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/helpers/memenv/memenv.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_\n#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_\n\n#include \"leveldb/export.h\"\n\nnamespace leveldb {\n\nclass Env;\n\n// Returns a new environment that stores its data in memory and delegates\n// all non-file-storage tasks to base_env. The caller must delete the result\n// when it is no longer needed.\n// *base_env must remain live while the result is in use.\nLEVELDB_EXPORT Env* NewMemEnv(Env* base_env);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_\n"
  },
  {
    "path": "src/leveldb/helpers/memenv/memenv_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"helpers/memenv/memenv.h\"\n\n#include <string>\n#include <vector>\n\n#include \"db/db_impl.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass MemEnvTest {\n public:\n  MemEnvTest() : env_(NewMemEnv(Env::Default())) {}\n  ~MemEnvTest() { delete env_; }\n\n  Env* env_;\n};\n\nTEST(MemEnvTest, Basics) {\n  uint64_t file_size;\n  WritableFile* writable_file;\n  std::vector<std::string> children;\n\n  ASSERT_OK(env_->CreateDir(\"/dir\"));\n\n  // Check that the directory is empty.\n  ASSERT_TRUE(!env_->FileExists(\"/dir/non_existent\"));\n  ASSERT_TRUE(!env_->GetFileSize(\"/dir/non_existent\", &file_size).ok());\n  ASSERT_OK(env_->GetChildren(\"/dir\", &children));\n  ASSERT_EQ(0, children.size());\n\n  // Create a file.\n  ASSERT_OK(env_->NewWritableFile(\"/dir/f\", &writable_file));\n  ASSERT_OK(env_->GetFileSize(\"/dir/f\", &file_size));\n  ASSERT_EQ(0, file_size);\n  delete writable_file;\n\n  // Check that the file exists.\n  ASSERT_TRUE(env_->FileExists(\"/dir/f\"));\n  ASSERT_OK(env_->GetFileSize(\"/dir/f\", &file_size));\n  ASSERT_EQ(0, file_size);\n  ASSERT_OK(env_->GetChildren(\"/dir\", &children));\n  ASSERT_EQ(1, children.size());\n  ASSERT_EQ(\"f\", children[0]);\n\n  // Write to the file.\n  ASSERT_OK(env_->NewWritableFile(\"/dir/f\", &writable_file));\n  ASSERT_OK(writable_file->Append(\"abc\"));\n  delete writable_file;\n\n  // Check that append works.\n  ASSERT_OK(env_->NewAppendableFile(\"/dir/f\", &writable_file));\n  ASSERT_OK(env_->GetFileSize(\"/dir/f\", &file_size));\n  ASSERT_EQ(3, file_size);\n  ASSERT_OK(writable_file->Append(\"hello\"));\n  delete writable_file;\n\n  // Check for expected size.\n  ASSERT_OK(env_->GetFileSize(\"/dir/f\", &file_size));\n  ASSERT_EQ(8, file_size);\n\n  // Check that renaming works.\n  ASSERT_TRUE(!env_->RenameFile(\"/dir/non_existent\", \"/dir/g\").ok());\n  ASSERT_OK(env_->RenameFile(\"/dir/f\", \"/dir/g\"));\n  ASSERT_TRUE(!env_->FileExists(\"/dir/f\"));\n  ASSERT_TRUE(env_->FileExists(\"/dir/g\"));\n  ASSERT_OK(env_->GetFileSize(\"/dir/g\", &file_size));\n  ASSERT_EQ(8, file_size);\n\n  // Check that opening non-existent file fails.\n  SequentialFile* seq_file;\n  RandomAccessFile* rand_file;\n  ASSERT_TRUE(!env_->NewSequentialFile(\"/dir/non_existent\", &seq_file).ok());\n  ASSERT_TRUE(!seq_file);\n  ASSERT_TRUE(!env_->NewRandomAccessFile(\"/dir/non_existent\", &rand_file).ok());\n  ASSERT_TRUE(!rand_file);\n\n  // Check that deleting works.\n  ASSERT_TRUE(!env_->DeleteFile(\"/dir/non_existent\").ok());\n  ASSERT_OK(env_->DeleteFile(\"/dir/g\"));\n  ASSERT_TRUE(!env_->FileExists(\"/dir/g\"));\n  ASSERT_OK(env_->GetChildren(\"/dir\", &children));\n  ASSERT_EQ(0, children.size());\n  ASSERT_OK(env_->DeleteDir(\"/dir\"));\n}\n\nTEST(MemEnvTest, ReadWrite) {\n  WritableFile* writable_file;\n  SequentialFile* seq_file;\n  RandomAccessFile* rand_file;\n  Slice result;\n  char scratch[100];\n\n  ASSERT_OK(env_->CreateDir(\"/dir\"));\n\n  ASSERT_OK(env_->NewWritableFile(\"/dir/f\", &writable_file));\n  ASSERT_OK(writable_file->Append(\"hello \"));\n  ASSERT_OK(writable_file->Append(\"world\"));\n  delete writable_file;\n\n  // Read sequentially.\n  ASSERT_OK(env_->NewSequentialFile(\"/dir/f\", &seq_file));\n  ASSERT_OK(seq_file->Read(5, &result, scratch));  // Read \"hello\".\n  ASSERT_EQ(0, result.compare(\"hello\"));\n  ASSERT_OK(seq_file->Skip(1));\n  ASSERT_OK(seq_file->Read(1000, &result, scratch));  // Read \"world\".\n  ASSERT_EQ(0, result.compare(\"world\"));\n  ASSERT_OK(seq_file->Read(1000, &result, scratch));  // Try reading past EOF.\n  ASSERT_EQ(0, result.size());\n  ASSERT_OK(seq_file->Skip(100));  // Try to skip past end of file.\n  ASSERT_OK(seq_file->Read(1000, &result, scratch));\n  ASSERT_EQ(0, result.size());\n  delete seq_file;\n\n  // Random reads.\n  ASSERT_OK(env_->NewRandomAccessFile(\"/dir/f\", &rand_file));\n  ASSERT_OK(rand_file->Read(6, 5, &result, scratch));  // Read \"world\".\n  ASSERT_EQ(0, result.compare(\"world\"));\n  ASSERT_OK(rand_file->Read(0, 5, &result, scratch));  // Read \"hello\".\n  ASSERT_EQ(0, result.compare(\"hello\"));\n  ASSERT_OK(rand_file->Read(10, 100, &result, scratch));  // Read \"d\".\n  ASSERT_EQ(0, result.compare(\"d\"));\n\n  // Too high offset.\n  ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok());\n  delete rand_file;\n}\n\nTEST(MemEnvTest, Locks) {\n  FileLock* lock;\n\n  // These are no-ops, but we test they return success.\n  ASSERT_OK(env_->LockFile(\"some file\", &lock));\n  ASSERT_OK(env_->UnlockFile(lock));\n}\n\nTEST(MemEnvTest, Misc) {\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  ASSERT_TRUE(!test_dir.empty());\n\n  WritableFile* writable_file;\n  ASSERT_OK(env_->NewWritableFile(\"/a/b\", &writable_file));\n\n  // These are no-ops, but we test they return success.\n  ASSERT_OK(writable_file->Sync());\n  ASSERT_OK(writable_file->Flush());\n  ASSERT_OK(writable_file->Close());\n  delete writable_file;\n}\n\nTEST(MemEnvTest, LargeWrite) {\n  const size_t kWriteSize = 300 * 1024;\n  char* scratch = new char[kWriteSize * 2];\n\n  std::string write_data;\n  for (size_t i = 0; i < kWriteSize; ++i) {\n    write_data.append(1, static_cast<char>(i));\n  }\n\n  WritableFile* writable_file;\n  ASSERT_OK(env_->NewWritableFile(\"/dir/f\", &writable_file));\n  ASSERT_OK(writable_file->Append(\"foo\"));\n  ASSERT_OK(writable_file->Append(write_data));\n  delete writable_file;\n\n  SequentialFile* seq_file;\n  Slice result;\n  ASSERT_OK(env_->NewSequentialFile(\"/dir/f\", &seq_file));\n  ASSERT_OK(seq_file->Read(3, &result, scratch));  // Read \"foo\".\n  ASSERT_EQ(0, result.compare(\"foo\"));\n\n  size_t read = 0;\n  std::string read_data;\n  while (read < kWriteSize) {\n    ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch));\n    read_data.append(result.data(), result.size());\n    read += result.size();\n  }\n  ASSERT_TRUE(write_data == read_data);\n  delete seq_file;\n  delete[] scratch;\n}\n\nTEST(MemEnvTest, OverwriteOpenFile) {\n  const char kWrite1Data[] = \"Write #1 data\";\n  const size_t kFileDataLen = sizeof(kWrite1Data) - 1;\n  const std::string kTestFileName = test::TmpDir() + \"/leveldb-TestFile.dat\";\n\n  ASSERT_OK(WriteStringToFile(env_, kWrite1Data, kTestFileName));\n\n  RandomAccessFile* rand_file;\n  ASSERT_OK(env_->NewRandomAccessFile(kTestFileName, &rand_file));\n\n  const char kWrite2Data[] = \"Write #2 data\";\n  ASSERT_OK(WriteStringToFile(env_, kWrite2Data, kTestFileName));\n\n  // Verify that overwriting an open file will result in the new file data\n  // being read from files opened before the write.\n  Slice result;\n  char scratch[kFileDataLen];\n  ASSERT_OK(rand_file->Read(0, kFileDataLen, &result, scratch));\n  ASSERT_EQ(0, result.compare(kWrite2Data));\n\n  delete rand_file;\n}\n\nTEST(MemEnvTest, DBTest) {\n  Options options;\n  options.create_if_missing = true;\n  options.env = env_;\n  DB* db;\n\n  const Slice keys[] = {Slice(\"aaa\"), Slice(\"bbb\"), Slice(\"ccc\")};\n  const Slice vals[] = {Slice(\"foo\"), Slice(\"bar\"), Slice(\"baz\")};\n\n  ASSERT_OK(DB::Open(options, \"/dir/db\", &db));\n  for (size_t i = 0; i < 3; ++i) {\n    ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i]));\n  }\n\n  for (size_t i = 0; i < 3; ++i) {\n    std::string res;\n    ASSERT_OK(db->Get(ReadOptions(), keys[i], &res));\n    ASSERT_TRUE(res == vals[i]);\n  }\n\n  Iterator* iterator = db->NewIterator(ReadOptions());\n  iterator->SeekToFirst();\n  for (size_t i = 0; i < 3; ++i) {\n    ASSERT_TRUE(iterator->Valid());\n    ASSERT_TRUE(keys[i] == iterator->key());\n    ASSERT_TRUE(vals[i] == iterator->value());\n    iterator->Next();\n  }\n  ASSERT_TRUE(!iterator->Valid());\n  delete iterator;\n\n  DBImpl* dbi = reinterpret_cast<DBImpl*>(db);\n  ASSERT_OK(dbi->TEST_CompactMemTable());\n\n  for (size_t i = 0; i < 3; ++i) {\n    std::string res;\n    ASSERT_OK(db->Get(ReadOptions(), keys[i], &res));\n    ASSERT_TRUE(res == vals[i]);\n  }\n\n  delete db;\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/include/leveldb/c.h",
    "content": "/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n  Use of this source code is governed by a BSD-style license that can be\n  found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n  C bindings for leveldb.  May be useful as a stable ABI that can be\n  used by programs that keep leveldb in a shared library, or for\n  a JNI api.\n\n  Does not support:\n  . getters for the option types\n  . custom comparators that implement key shortening\n  . custom iter, db, env, cache implementations using just the C bindings\n\n  Some conventions:\n\n  (1) We expose just opaque struct pointers and functions to clients.\n  This allows us to change internal representations without having to\n  recompile clients.\n\n  (2) For simplicity, there is no equivalent to the Slice type.  Instead,\n  the caller has to pass the pointer and length as separate\n  arguments.\n\n  (3) Errors are represented by a null-terminated c string.  NULL\n  means no error.  All operations that can raise an error are passed\n  a \"char** errptr\" as the last argument.  One of the following must\n  be true on entry:\n     *errptr == NULL\n     *errptr points to a malloc()ed null-terminated error message\n       (On Windows, *errptr must have been malloc()-ed by this library.)\n  On success, a leveldb routine leaves *errptr unchanged.\n  On failure, leveldb frees the old value of *errptr and\n  set *errptr to a malloc()ed error message.\n\n  (4) Bools have the type uint8_t (0 == false; rest == true)\n\n  (5) All of the pointer arguments must be non-NULL.\n*/\n\n#ifndef STORAGE_LEVELDB_INCLUDE_C_H_\n#define STORAGE_LEVELDB_INCLUDE_C_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdarg.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"leveldb/export.h\"\n\n/* Exported types */\n\ntypedef struct leveldb_t leveldb_t;\ntypedef struct leveldb_cache_t leveldb_cache_t;\ntypedef struct leveldb_comparator_t leveldb_comparator_t;\ntypedef struct leveldb_env_t leveldb_env_t;\ntypedef struct leveldb_filelock_t leveldb_filelock_t;\ntypedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t;\ntypedef struct leveldb_iterator_t leveldb_iterator_t;\ntypedef struct leveldb_logger_t leveldb_logger_t;\ntypedef struct leveldb_options_t leveldb_options_t;\ntypedef struct leveldb_randomfile_t leveldb_randomfile_t;\ntypedef struct leveldb_readoptions_t leveldb_readoptions_t;\ntypedef struct leveldb_seqfile_t leveldb_seqfile_t;\ntypedef struct leveldb_snapshot_t leveldb_snapshot_t;\ntypedef struct leveldb_writablefile_t leveldb_writablefile_t;\ntypedef struct leveldb_writebatch_t leveldb_writebatch_t;\ntypedef struct leveldb_writeoptions_t leveldb_writeoptions_t;\n\n/* DB operations */\n\nLEVELDB_EXPORT leveldb_t* leveldb_open(const leveldb_options_t* options,\n                                       const char* name, char** errptr);\n\nLEVELDB_EXPORT void leveldb_close(leveldb_t* db);\n\nLEVELDB_EXPORT void leveldb_put(leveldb_t* db,\n                                const leveldb_writeoptions_t* options,\n                                const char* key, size_t keylen, const char* val,\n                                size_t vallen, char** errptr);\n\nLEVELDB_EXPORT void leveldb_delete(leveldb_t* db,\n                                   const leveldb_writeoptions_t* options,\n                                   const char* key, size_t keylen,\n                                   char** errptr);\n\nLEVELDB_EXPORT void leveldb_write(leveldb_t* db,\n                                  const leveldb_writeoptions_t* options,\n                                  leveldb_writebatch_t* batch, char** errptr);\n\n/* Returns NULL if not found.  A malloc()ed array otherwise.\n   Stores the length of the array in *vallen. */\nLEVELDB_EXPORT char* leveldb_get(leveldb_t* db,\n                                 const leveldb_readoptions_t* options,\n                                 const char* key, size_t keylen, size_t* vallen,\n                                 char** errptr);\n\nLEVELDB_EXPORT leveldb_iterator_t* leveldb_create_iterator(\n    leveldb_t* db, const leveldb_readoptions_t* options);\n\nLEVELDB_EXPORT const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db);\n\nLEVELDB_EXPORT void leveldb_release_snapshot(\n    leveldb_t* db, const leveldb_snapshot_t* snapshot);\n\n/* Returns NULL if property name is unknown.\n   Else returns a pointer to a malloc()-ed null-terminated value. */\nLEVELDB_EXPORT char* leveldb_property_value(leveldb_t* db,\n                                            const char* propname);\n\nLEVELDB_EXPORT void leveldb_approximate_sizes(\n    leveldb_t* db, int num_ranges, const char* const* range_start_key,\n    const size_t* range_start_key_len, const char* const* range_limit_key,\n    const size_t* range_limit_key_len, uint64_t* sizes);\n\nLEVELDB_EXPORT void leveldb_compact_range(leveldb_t* db, const char* start_key,\n                                          size_t start_key_len,\n                                          const char* limit_key,\n                                          size_t limit_key_len);\n\n/* Management operations */\n\nLEVELDB_EXPORT void leveldb_destroy_db(const leveldb_options_t* options,\n                                       const char* name, char** errptr);\n\nLEVELDB_EXPORT void leveldb_repair_db(const leveldb_options_t* options,\n                                      const char* name, char** errptr);\n\n/* Iterator */\n\nLEVELDB_EXPORT void leveldb_iter_destroy(leveldb_iterator_t*);\nLEVELDB_EXPORT uint8_t leveldb_iter_valid(const leveldb_iterator_t*);\nLEVELDB_EXPORT void leveldb_iter_seek_to_first(leveldb_iterator_t*);\nLEVELDB_EXPORT void leveldb_iter_seek_to_last(leveldb_iterator_t*);\nLEVELDB_EXPORT void leveldb_iter_seek(leveldb_iterator_t*, const char* k,\n                                      size_t klen);\nLEVELDB_EXPORT void leveldb_iter_next(leveldb_iterator_t*);\nLEVELDB_EXPORT void leveldb_iter_prev(leveldb_iterator_t*);\nLEVELDB_EXPORT const char* leveldb_iter_key(const leveldb_iterator_t*,\n                                            size_t* klen);\nLEVELDB_EXPORT const char* leveldb_iter_value(const leveldb_iterator_t*,\n                                              size_t* vlen);\nLEVELDB_EXPORT void leveldb_iter_get_error(const leveldb_iterator_t*,\n                                           char** errptr);\n\n/* Write batch */\n\nLEVELDB_EXPORT leveldb_writebatch_t* leveldb_writebatch_create(void);\nLEVELDB_EXPORT void leveldb_writebatch_destroy(leveldb_writebatch_t*);\nLEVELDB_EXPORT void leveldb_writebatch_clear(leveldb_writebatch_t*);\nLEVELDB_EXPORT void leveldb_writebatch_put(leveldb_writebatch_t*,\n                                           const char* key, size_t klen,\n                                           const char* val, size_t vlen);\nLEVELDB_EXPORT void leveldb_writebatch_delete(leveldb_writebatch_t*,\n                                              const char* key, size_t klen);\nLEVELDB_EXPORT void leveldb_writebatch_iterate(\n    const leveldb_writebatch_t*, void* state,\n    void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen),\n    void (*deleted)(void*, const char* k, size_t klen));\nLEVELDB_EXPORT void leveldb_writebatch_append(\n    leveldb_writebatch_t* destination, const leveldb_writebatch_t* source);\n\n/* Options */\n\nLEVELDB_EXPORT leveldb_options_t* leveldb_options_create(void);\nLEVELDB_EXPORT void leveldb_options_destroy(leveldb_options_t*);\nLEVELDB_EXPORT void leveldb_options_set_comparator(leveldb_options_t*,\n                                                   leveldb_comparator_t*);\nLEVELDB_EXPORT void leveldb_options_set_filter_policy(leveldb_options_t*,\n                                                      leveldb_filterpolicy_t*);\nLEVELDB_EXPORT void leveldb_options_set_create_if_missing(leveldb_options_t*,\n                                                          uint8_t);\nLEVELDB_EXPORT void leveldb_options_set_error_if_exists(leveldb_options_t*,\n                                                        uint8_t);\nLEVELDB_EXPORT void leveldb_options_set_paranoid_checks(leveldb_options_t*,\n                                                        uint8_t);\nLEVELDB_EXPORT void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*);\nLEVELDB_EXPORT void leveldb_options_set_info_log(leveldb_options_t*,\n                                                 leveldb_logger_t*);\nLEVELDB_EXPORT void leveldb_options_set_write_buffer_size(leveldb_options_t*,\n                                                          size_t);\nLEVELDB_EXPORT void leveldb_options_set_max_open_files(leveldb_options_t*, int);\nLEVELDB_EXPORT void leveldb_options_set_cache(leveldb_options_t*,\n                                              leveldb_cache_t*);\nLEVELDB_EXPORT void leveldb_options_set_block_size(leveldb_options_t*, size_t);\nLEVELDB_EXPORT void leveldb_options_set_block_restart_interval(\n    leveldb_options_t*, int);\nLEVELDB_EXPORT void leveldb_options_set_max_file_size(leveldb_options_t*,\n                                                      size_t);\n\nenum { leveldb_no_compression = 0, leveldb_snappy_compression = 1 };\nLEVELDB_EXPORT void leveldb_options_set_compression(leveldb_options_t*, int);\n\n/* Comparator */\n\nLEVELDB_EXPORT leveldb_comparator_t* leveldb_comparator_create(\n    void* state, void (*destructor)(void*),\n    int (*compare)(void*, const char* a, size_t alen, const char* b,\n                   size_t blen),\n    const char* (*name)(void*));\nLEVELDB_EXPORT void leveldb_comparator_destroy(leveldb_comparator_t*);\n\n/* Filter policy */\n\nLEVELDB_EXPORT leveldb_filterpolicy_t* leveldb_filterpolicy_create(\n    void* state, void (*destructor)(void*),\n    char* (*create_filter)(void*, const char* const* key_array,\n                           const size_t* key_length_array, int num_keys,\n                           size_t* filter_length),\n    uint8_t (*key_may_match)(void*, const char* key, size_t length,\n                             const char* filter, size_t filter_length),\n    const char* (*name)(void*));\nLEVELDB_EXPORT void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*);\n\nLEVELDB_EXPORT leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(\n    int bits_per_key);\n\n/* Read options */\n\nLEVELDB_EXPORT leveldb_readoptions_t* leveldb_readoptions_create(void);\nLEVELDB_EXPORT void leveldb_readoptions_destroy(leveldb_readoptions_t*);\nLEVELDB_EXPORT void leveldb_readoptions_set_verify_checksums(\n    leveldb_readoptions_t*, uint8_t);\nLEVELDB_EXPORT void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t*,\n                                                       uint8_t);\nLEVELDB_EXPORT void leveldb_readoptions_set_snapshot(leveldb_readoptions_t*,\n                                                     const leveldb_snapshot_t*);\n\n/* Write options */\n\nLEVELDB_EXPORT leveldb_writeoptions_t* leveldb_writeoptions_create(void);\nLEVELDB_EXPORT void leveldb_writeoptions_destroy(leveldb_writeoptions_t*);\nLEVELDB_EXPORT void leveldb_writeoptions_set_sync(leveldb_writeoptions_t*,\n                                                  uint8_t);\n\n/* Cache */\n\nLEVELDB_EXPORT leveldb_cache_t* leveldb_cache_create_lru(size_t capacity);\nLEVELDB_EXPORT void leveldb_cache_destroy(leveldb_cache_t* cache);\n\n/* Env */\n\nLEVELDB_EXPORT leveldb_env_t* leveldb_create_default_env(void);\nLEVELDB_EXPORT void leveldb_env_destroy(leveldb_env_t*);\n\n/* If not NULL, the returned buffer must be released using leveldb_free(). */\nLEVELDB_EXPORT char* leveldb_env_get_test_directory(leveldb_env_t*);\n\n/* Utility */\n\n/* Calls free(ptr).\n   REQUIRES: ptr was malloc()-ed and returned by one of the routines\n   in this file.  Note that in certain cases (typically on Windows), you\n   may need to call this routine instead of free(ptr) to dispose of\n   malloc()-ed memory returned by this library. */\nLEVELDB_EXPORT void leveldb_free(void* ptr);\n\n/* Return the major version number for this release. */\nLEVELDB_EXPORT int leveldb_major_version(void);\n\n/* Return the minor version number for this release. */\nLEVELDB_EXPORT int leveldb_minor_version(void);\n\n#ifdef __cplusplus\n} /* end extern \"C\" */\n#endif\n\n#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */\n"
  },
  {
    "path": "src/leveldb/include/leveldb/cache.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// A Cache is an interface that maps keys to values.  It has internal\n// synchronization and may be safely accessed concurrently from\n// multiple threads.  It may automatically evict entries to make room\n// for new entries.  Values have a specified charge against the cache\n// capacity.  For example, a cache where the values are variable\n// length strings, may use the length of the string as the charge for\n// the string.\n//\n// A builtin cache implementation with a least-recently-used eviction\n// policy is provided.  Clients may use their own implementations if\n// they want something more sophisticated (like scan-resistance, a\n// custom eviction policy, variable cache sizing, etc.)\n\n#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_\n#define STORAGE_LEVELDB_INCLUDE_CACHE_H_\n\n#include <stdint.h>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/slice.h\"\n\nnamespace leveldb {\n\nclass LEVELDB_EXPORT Cache;\n\n// Create a new cache with a fixed size capacity.  This implementation\n// of Cache uses a least-recently-used eviction policy.\nLEVELDB_EXPORT Cache* NewLRUCache(size_t capacity);\n\nclass LEVELDB_EXPORT Cache {\n public:\n  Cache() = default;\n\n  Cache(const Cache&) = delete;\n  Cache& operator=(const Cache&) = delete;\n\n  // Destroys all existing entries by calling the \"deleter\"\n  // function that was passed to the constructor.\n  virtual ~Cache();\n\n  // Opaque handle to an entry stored in the cache.\n  struct Handle {};\n\n  // Insert a mapping from key->value into the cache and assign it\n  // the specified charge against the total cache capacity.\n  //\n  // Returns a handle that corresponds to the mapping.  The caller\n  // must call this->Release(handle) when the returned mapping is no\n  // longer needed.\n  //\n  // When the inserted entry is no longer needed, the key and\n  // value will be passed to \"deleter\".\n  virtual Handle* Insert(const Slice& key, void* value, size_t charge,\n                         void (*deleter)(const Slice& key, void* value)) = 0;\n\n  // If the cache has no mapping for \"key\", returns nullptr.\n  //\n  // Else return a handle that corresponds to the mapping.  The caller\n  // must call this->Release(handle) when the returned mapping is no\n  // longer needed.\n  virtual Handle* Lookup(const Slice& key) = 0;\n\n  // Release a mapping returned by a previous Lookup().\n  // REQUIRES: handle must not have been released yet.\n  // REQUIRES: handle must have been returned by a method on *this.\n  virtual void Release(Handle* handle) = 0;\n\n  // Return the value encapsulated in a handle returned by a\n  // successful Lookup().\n  // REQUIRES: handle must not have been released yet.\n  // REQUIRES: handle must have been returned by a method on *this.\n  virtual void* Value(Handle* handle) = 0;\n\n  // If the cache contains entry for key, erase it.  Note that the\n  // underlying entry will be kept around until all existing handles\n  // to it have been released.\n  virtual void Erase(const Slice& key) = 0;\n\n  // Return a new numeric id.  May be used by multiple clients who are\n  // sharing the same cache to partition the key space.  Typically the\n  // client will allocate a new id at startup and prepend the id to\n  // its cache keys.\n  virtual uint64_t NewId() = 0;\n\n  // Remove all cache entries that are not actively in use.  Memory-constrained\n  // applications may wish to call this method to reduce memory usage.\n  // Default implementation of Prune() does nothing.  Subclasses are strongly\n  // encouraged to override the default implementation.  A future release of\n  // leveldb may change Prune() to a pure abstract method.\n  virtual void Prune() {}\n\n  // Return an estimate of the combined charges of all elements stored in the\n  // cache.\n  virtual size_t TotalCharge() const = 0;\n\n private:\n  void LRU_Remove(Handle* e);\n  void LRU_Append(Handle* e);\n  void Unref(Handle* e);\n\n  struct Rep;\n  Rep* rep_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_CACHE_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/comparator.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_\n#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_\n\n#include <string>\n\n#include \"leveldb/export.h\"\n\nnamespace leveldb {\n\nclass Slice;\n\n// A Comparator object provides a total order across slices that are\n// used as keys in an sstable or a database.  A Comparator implementation\n// must be thread-safe since leveldb may invoke its methods concurrently\n// from multiple threads.\nclass LEVELDB_EXPORT Comparator {\n public:\n  virtual ~Comparator();\n\n  // Three-way comparison.  Returns value:\n  //   < 0 iff \"a\" < \"b\",\n  //   == 0 iff \"a\" == \"b\",\n  //   > 0 iff \"a\" > \"b\"\n  virtual int Compare(const Slice& a, const Slice& b) const = 0;\n\n  // The name of the comparator.  Used to check for comparator\n  // mismatches (i.e., a DB created with one comparator is\n  // accessed using a different comparator.\n  //\n  // The client of this package should switch to a new name whenever\n  // the comparator implementation changes in a way that will cause\n  // the relative ordering of any two keys to change.\n  //\n  // Names starting with \"leveldb.\" are reserved and should not be used\n  // by any clients of this package.\n  virtual const char* Name() const = 0;\n\n  // Advanced functions: these are used to reduce the space requirements\n  // for internal data structures like index blocks.\n\n  // If *start < limit, changes *start to a short string in [start,limit).\n  // Simple comparator implementations may return with *start unchanged,\n  // i.e., an implementation of this method that does nothing is correct.\n  virtual void FindShortestSeparator(std::string* start,\n                                     const Slice& limit) const = 0;\n\n  // Changes *key to a short string >= *key.\n  // Simple comparator implementations may return with *key unchanged,\n  // i.e., an implementation of this method that does nothing is correct.\n  virtual void FindShortSuccessor(std::string* key) const = 0;\n};\n\n// Return a builtin comparator that uses lexicographic byte-wise\n// ordering.  The result remains the property of this module and\n// must not be deleted.\nLEVELDB_EXPORT const Comparator* BytewiseComparator();\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/db.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_\n#define STORAGE_LEVELDB_INCLUDE_DB_H_\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/iterator.h\"\n#include \"leveldb/options.h\"\n\nnamespace leveldb {\n\n// Update CMakeLists.txt if you change these\nstatic const int kMajorVersion = 1;\nstatic const int kMinorVersion = 22;\n\nstruct Options;\nstruct ReadOptions;\nstruct WriteOptions;\nclass WriteBatch;\n\n// Abstract handle to particular state of a DB.\n// A Snapshot is an immutable object and can therefore be safely\n// accessed from multiple threads without any external synchronization.\nclass LEVELDB_EXPORT Snapshot {\n protected:\n  virtual ~Snapshot();\n};\n\n// A range of keys\nstruct LEVELDB_EXPORT Range {\n  Range() = default;\n  Range(const Slice& s, const Slice& l) : start(s), limit(l) {}\n\n  Slice start;  // Included in the range\n  Slice limit;  // Not included in the range\n};\n\n// A DB is a persistent ordered map from keys to values.\n// A DB is safe for concurrent access from multiple threads without\n// any external synchronization.\nclass LEVELDB_EXPORT DB {\n public:\n  // Open the database with the specified \"name\".\n  // Stores a pointer to a heap-allocated database in *dbptr and returns\n  // OK on success.\n  // Stores nullptr in *dbptr and returns a non-OK status on error.\n  // Caller should delete *dbptr when it is no longer needed.\n  static Status Open(const Options& options, const std::string& name,\n                     DB** dbptr);\n\n  DB() = default;\n\n  DB(const DB&) = delete;\n  DB& operator=(const DB&) = delete;\n\n  virtual ~DB();\n\n  // Set the database entry for \"key\" to \"value\".  Returns OK on success,\n  // and a non-OK status on error.\n  // Note: consider setting options.sync = true.\n  virtual Status Put(const WriteOptions& options, const Slice& key,\n                     const Slice& value) = 0;\n\n  // Remove the database entry (if any) for \"key\".  Returns OK on\n  // success, and a non-OK status on error.  It is not an error if \"key\"\n  // did not exist in the database.\n  // Note: consider setting options.sync = true.\n  virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;\n\n  // Apply the specified updates to the database.\n  // Returns OK on success, non-OK on failure.\n  // Note: consider setting options.sync = true.\n  virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;\n\n  // If the database contains an entry for \"key\" store the\n  // corresponding value in *value and return OK.\n  //\n  // If there is no entry for \"key\" leave *value unchanged and return\n  // a status for which Status::IsNotFound() returns true.\n  //\n  // May return some other Status on an error.\n  virtual Status Get(const ReadOptions& options, const Slice& key,\n                     std::string* value) = 0;\n\n  // Return a heap-allocated iterator over the contents of the database.\n  // The result of NewIterator() is initially invalid (caller must\n  // call one of the Seek methods on the iterator before using it).\n  //\n  // Caller should delete the iterator when it is no longer needed.\n  // The returned iterator should be deleted before this db is deleted.\n  virtual Iterator* NewIterator(const ReadOptions& options) = 0;\n\n  // Return a handle to the current DB state.  Iterators created with\n  // this handle will all observe a stable snapshot of the current DB\n  // state.  The caller must call ReleaseSnapshot(result) when the\n  // snapshot is no longer needed.\n  virtual const Snapshot* GetSnapshot() = 0;\n\n  // Release a previously acquired snapshot.  The caller must not\n  // use \"snapshot\" after this call.\n  virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;\n\n  // DB implementations can export properties about their state\n  // via this method.  If \"property\" is a valid property understood by this\n  // DB implementation, fills \"*value\" with its current value and returns\n  // true.  Otherwise returns false.\n  //\n  //\n  // Valid property names include:\n  //\n  //  \"leveldb.num-files-at-level<N>\" - return the number of files at level <N>,\n  //     where <N> is an ASCII representation of a level number (e.g. \"0\").\n  //  \"leveldb.stats\" - returns a multi-line string that describes statistics\n  //     about the internal operation of the DB.\n  //  \"leveldb.sstables\" - returns a multi-line string that describes all\n  //     of the sstables that make up the db contents.\n  //  \"leveldb.approximate-memory-usage\" - returns the approximate number of\n  //     bytes of memory in use by the DB.\n  virtual bool GetProperty(const Slice& property, std::string* value) = 0;\n\n  // For each i in [0,n-1], store in \"sizes[i]\", the approximate\n  // file system space used by keys in \"[range[i].start .. range[i].limit)\".\n  //\n  // Note that the returned sizes measure file system space usage, so\n  // if the user data compresses by a factor of ten, the returned\n  // sizes will be one-tenth the size of the corresponding user data size.\n  //\n  // The results may not include the sizes of recently written data.\n  virtual void GetApproximateSizes(const Range* range, int n,\n                                   uint64_t* sizes) = 0;\n\n  // Compact the underlying storage for the key range [*begin,*end].\n  // In particular, deleted and overwritten versions are discarded,\n  // and the data is rearranged to reduce the cost of operations\n  // needed to access the data.  This operation should typically only\n  // be invoked by users who understand the underlying implementation.\n  //\n  // begin==nullptr is treated as a key before all keys in the database.\n  // end==nullptr is treated as a key after all keys in the database.\n  // Therefore the following call will compact the entire database:\n  //    db->CompactRange(nullptr, nullptr);\n  virtual void CompactRange(const Slice* begin, const Slice* end) = 0;\n};\n\n// Destroy the contents of the specified database.\n// Be very careful using this method.\n//\n// Note: For backwards compatibility, if DestroyDB is unable to list the\n// database files, Status::OK() will still be returned masking this failure.\nLEVELDB_EXPORT Status DestroyDB(const std::string& name,\n                                const Options& options);\n\n// If a DB cannot be opened, you may attempt to call this method to\n// resurrect as much of the contents of the database as possible.\n// Some data may be lost, so be careful when calling this function\n// on a database that contains important information.\nLEVELDB_EXPORT Status RepairDB(const std::string& dbname,\n                               const Options& options);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_DB_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/dumpfile.h",
    "content": "// Copyright (c) 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_\n#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_\n\n#include <string>\n\n#include \"leveldb/env.h\"\n#include \"leveldb/export.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\n// Dump the contents of the file named by fname in text format to\n// *dst.  Makes a sequence of dst->Append() calls; each call is passed\n// the newline-terminated text corresponding to a single item found\n// in the file.\n//\n// Returns a non-OK result if fname does not name a leveldb storage\n// file, or if the file cannot be read.\nLEVELDB_EXPORT Status DumpFile(Env* env, const std::string& fname,\n                               WritableFile* dst);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/env.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// An Env is an interface used by the leveldb implementation to access\n// operating system functionality like the filesystem etc.  Callers\n// may wish to provide a custom Env object when opening a database to\n// get fine gain control; e.g., to rate limit file system operations.\n//\n// All Env implementations are safe for concurrent access from\n// multiple threads without any external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_\n#define STORAGE_LEVELDB_INCLUDE_ENV_H_\n\n#include <stdarg.h>\n#include <stdint.h>\n\n#include <string>\n#include <vector>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/status.h\"\n\n#if defined(_WIN32)\n// The leveldb::Env class below contains a DeleteFile method.\n// At the same time, <windows.h>, a fairly popular header\n// file for Windows applications, defines a DeleteFile macro.\n//\n// Without any intervention on our part, the result of this\n// unfortunate coincidence is that the name of the\n// leveldb::Env::DeleteFile method seen by the compiler depends on\n// whether <windows.h> was included before or after the LevelDB\n// headers.\n//\n// To avoid headaches, we undefined DeleteFile (if defined) and\n// redefine it at the bottom of this file. This way <windows.h>\n// can be included before this file (or not at all) and the\n// exported method will always be leveldb::Env::DeleteFile.\n#if defined(DeleteFile)\n#undef DeleteFile\n#define LEVELDB_DELETEFILE_UNDEFINED\n#endif  // defined(DeleteFile)\n#endif  // defined(_WIN32)\n\nnamespace leveldb {\n\nclass FileLock;\nclass Logger;\nclass RandomAccessFile;\nclass SequentialFile;\nclass Slice;\nclass WritableFile;\n\nclass LEVELDB_EXPORT Env {\n public:\n  Env() = default;\n\n  Env(const Env&) = delete;\n  Env& operator=(const Env&) = delete;\n\n  virtual ~Env();\n\n  // Return a default environment suitable for the current operating\n  // system.  Sophisticated users may wish to provide their own Env\n  // implementation instead of relying on this default environment.\n  //\n  // The result of Default() belongs to leveldb and must never be deleted.\n  static Env* Default();\n\n  // Create an object that sequentially reads the file with the specified name.\n  // On success, stores a pointer to the new file in *result and returns OK.\n  // On failure stores nullptr in *result and returns non-OK.  If the file does\n  // not exist, returns a non-OK status.  Implementations should return a\n  // NotFound status when the file does not exist.\n  //\n  // The returned file will only be accessed by one thread at a time.\n  virtual Status NewSequentialFile(const std::string& fname,\n                                   SequentialFile** result) = 0;\n\n  // Create an object supporting random-access reads from the file with the\n  // specified name.  On success, stores a pointer to the new file in\n  // *result and returns OK.  On failure stores nullptr in *result and\n  // returns non-OK.  If the file does not exist, returns a non-OK\n  // status.  Implementations should return a NotFound status when the file does\n  // not exist.\n  //\n  // The returned file may be concurrently accessed by multiple threads.\n  virtual Status NewRandomAccessFile(const std::string& fname,\n                                     RandomAccessFile** result) = 0;\n\n  // Create an object that writes to a new file with the specified\n  // name.  Deletes any existing file with the same name and creates a\n  // new file.  On success, stores a pointer to the new file in\n  // *result and returns OK.  On failure stores nullptr in *result and\n  // returns non-OK.\n  //\n  // The returned file will only be accessed by one thread at a time.\n  virtual Status NewWritableFile(const std::string& fname,\n                                 WritableFile** result) = 0;\n\n  // Create an object that either appends to an existing file, or\n  // writes to a new file (if the file does not exist to begin with).\n  // On success, stores a pointer to the new file in *result and\n  // returns OK.  On failure stores nullptr in *result and returns\n  // non-OK.\n  //\n  // The returned file will only be accessed by one thread at a time.\n  //\n  // May return an IsNotSupportedError error if this Env does\n  // not allow appending to an existing file.  Users of Env (including\n  // the leveldb implementation) must be prepared to deal with\n  // an Env that does not support appending.\n  virtual Status NewAppendableFile(const std::string& fname,\n                                   WritableFile** result);\n\n  // Returns true iff the named file exists.\n  virtual bool FileExists(const std::string& fname) = 0;\n\n  // Store in *result the names of the children of the specified directory.\n  // The names are relative to \"dir\".\n  // Original contents of *results are dropped.\n  virtual Status GetChildren(const std::string& dir,\n                             std::vector<std::string>* result) = 0;\n\n  // Delete the named file.\n  virtual Status DeleteFile(const std::string& fname) = 0;\n\n  // Create the specified directory.\n  virtual Status CreateDir(const std::string& dirname) = 0;\n\n  // Delete the specified directory.\n  virtual Status DeleteDir(const std::string& dirname) = 0;\n\n  // Store the size of fname in *file_size.\n  virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0;\n\n  // Rename file src to target.\n  virtual Status RenameFile(const std::string& src,\n                            const std::string& target) = 0;\n\n  // Lock the specified file.  Used to prevent concurrent access to\n  // the same db by multiple processes.  On failure, stores nullptr in\n  // *lock and returns non-OK.\n  //\n  // On success, stores a pointer to the object that represents the\n  // acquired lock in *lock and returns OK.  The caller should call\n  // UnlockFile(*lock) to release the lock.  If the process exits,\n  // the lock will be automatically released.\n  //\n  // If somebody else already holds the lock, finishes immediately\n  // with a failure.  I.e., this call does not wait for existing locks\n  // to go away.\n  //\n  // May create the named file if it does not already exist.\n  virtual Status LockFile(const std::string& fname, FileLock** lock) = 0;\n\n  // Release the lock acquired by a previous successful call to LockFile.\n  // REQUIRES: lock was returned by a successful LockFile() call\n  // REQUIRES: lock has not already been unlocked.\n  virtual Status UnlockFile(FileLock* lock) = 0;\n\n  // Arrange to run \"(*function)(arg)\" once in a background thread.\n  //\n  // \"function\" may run in an unspecified thread.  Multiple functions\n  // added to the same Env may run concurrently in different threads.\n  // I.e., the caller may not assume that background work items are\n  // serialized.\n  virtual void Schedule(void (*function)(void* arg), void* arg) = 0;\n\n  // Start a new thread, invoking \"function(arg)\" within the new thread.\n  // When \"function(arg)\" returns, the thread will be destroyed.\n  virtual void StartThread(void (*function)(void* arg), void* arg) = 0;\n\n  // *path is set to a temporary directory that can be used for testing. It may\n  // or may not have just been created. The directory may or may not differ\n  // between runs of the same process, but subsequent calls will return the\n  // same directory.\n  virtual Status GetTestDirectory(std::string* path) = 0;\n\n  // Create and return a log file for storing informational messages.\n  virtual Status NewLogger(const std::string& fname, Logger** result) = 0;\n\n  // Returns the number of micro-seconds since some fixed point in time. Only\n  // useful for computing deltas of time.\n  virtual uint64_t NowMicros() = 0;\n\n  // Sleep/delay the thread for the prescribed number of micro-seconds.\n  virtual void SleepForMicroseconds(int micros) = 0;\n};\n\n// A file abstraction for reading sequentially through a file\nclass LEVELDB_EXPORT SequentialFile {\n public:\n  SequentialFile() = default;\n\n  SequentialFile(const SequentialFile&) = delete;\n  SequentialFile& operator=(const SequentialFile&) = delete;\n\n  virtual ~SequentialFile();\n\n  // Read up to \"n\" bytes from the file.  \"scratch[0..n-1]\" may be\n  // written by this routine.  Sets \"*result\" to the data that was\n  // read (including if fewer than \"n\" bytes were successfully read).\n  // May set \"*result\" to point at data in \"scratch[0..n-1]\", so\n  // \"scratch[0..n-1]\" must be live when \"*result\" is used.\n  // If an error was encountered, returns a non-OK status.\n  //\n  // REQUIRES: External synchronization\n  virtual Status Read(size_t n, Slice* result, char* scratch) = 0;\n\n  // Skip \"n\" bytes from the file. This is guaranteed to be no\n  // slower that reading the same data, but may be faster.\n  //\n  // If end of file is reached, skipping will stop at the end of the\n  // file, and Skip will return OK.\n  //\n  // REQUIRES: External synchronization\n  virtual Status Skip(uint64_t n) = 0;\n\n  // Get a name for the file, only for error reporting\n  virtual std::string GetName() const = 0;\n};\n\n// A file abstraction for randomly reading the contents of a file.\nclass LEVELDB_EXPORT RandomAccessFile {\n public:\n  RandomAccessFile() = default;\n\n  RandomAccessFile(const RandomAccessFile&) = delete;\n  RandomAccessFile& operator=(const RandomAccessFile&) = delete;\n\n  virtual ~RandomAccessFile();\n\n  // Read up to \"n\" bytes from the file starting at \"offset\".\n  // \"scratch[0..n-1]\" may be written by this routine.  Sets \"*result\"\n  // to the data that was read (including if fewer than \"n\" bytes were\n  // successfully read).  May set \"*result\" to point at data in\n  // \"scratch[0..n-1]\", so \"scratch[0..n-1]\" must be live when\n  // \"*result\" is used.  If an error was encountered, returns a non-OK\n  // status.\n  //\n  // Safe for concurrent use by multiple threads.\n  virtual Status Read(uint64_t offset, size_t n, Slice* result,\n                      char* scratch) const = 0;\n\n  // Get a name for the file, only for error reporting\n  virtual std::string GetName() const = 0;\n};\n\n// A file abstraction for sequential writing.  The implementation\n// must provide buffering since callers may append small fragments\n// at a time to the file.\nclass LEVELDB_EXPORT WritableFile {\n public:\n  WritableFile() = default;\n\n  WritableFile(const WritableFile&) = delete;\n  WritableFile& operator=(const WritableFile&) = delete;\n\n  virtual ~WritableFile();\n\n  virtual Status Append(const Slice& data) = 0;\n  virtual Status Close() = 0;\n  virtual Status Flush() = 0;\n  virtual Status Sync() = 0;\n\n  // Get a name for the file, only for error reporting\n  virtual std::string GetName() const = 0;\n};\n\n// An interface for writing log messages.\nclass LEVELDB_EXPORT Logger {\n public:\n  Logger() = default;\n\n  Logger(const Logger&) = delete;\n  Logger& operator=(const Logger&) = delete;\n\n  virtual ~Logger();\n\n  // Write an entry to the log file with the specified format.\n  virtual void Logv(const char* format, va_list ap) = 0;\n};\n\n// Identifies a locked file.\nclass LEVELDB_EXPORT FileLock {\n public:\n  FileLock() = default;\n\n  FileLock(const FileLock&) = delete;\n  FileLock& operator=(const FileLock&) = delete;\n\n  virtual ~FileLock();\n};\n\n// Log the specified data to *info_log if info_log is non-null.\nvoid Log(Logger* info_log, const char* format, ...)\n#if defined(__GNUC__) || defined(__clang__)\n    __attribute__((__format__(__printf__, 2, 3)))\n#endif\n    ;\n\n// A utility routine: write \"data\" to the named file.\nLEVELDB_EXPORT Status WriteStringToFile(Env* env, const Slice& data,\n                                        const std::string& fname);\n\n// A utility routine: read contents of named file into *data\nLEVELDB_EXPORT Status ReadFileToString(Env* env, const std::string& fname,\n                                       std::string* data);\n\n// An implementation of Env that forwards all calls to another Env.\n// May be useful to clients who wish to override just part of the\n// functionality of another Env.\nclass LEVELDB_EXPORT EnvWrapper : public Env {\n public:\n  // Initialize an EnvWrapper that delegates all calls to *t.\n  explicit EnvWrapper(Env* t) : target_(t) {}\n  virtual ~EnvWrapper();\n\n  // Return the target to which this Env forwards all calls.\n  Env* target() const { return target_; }\n\n  // The following text is boilerplate that forwards all methods to target().\n  Status NewSequentialFile(const std::string& f, SequentialFile** r) override {\n    return target_->NewSequentialFile(f, r);\n  }\n  Status NewRandomAccessFile(const std::string& f,\n                             RandomAccessFile** r) override {\n    return target_->NewRandomAccessFile(f, r);\n  }\n  Status NewWritableFile(const std::string& f, WritableFile** r) override {\n    return target_->NewWritableFile(f, r);\n  }\n  Status NewAppendableFile(const std::string& f, WritableFile** r) override {\n    return target_->NewAppendableFile(f, r);\n  }\n  bool FileExists(const std::string& f) override {\n    return target_->FileExists(f);\n  }\n  Status GetChildren(const std::string& dir,\n                     std::vector<std::string>* r) override {\n    return target_->GetChildren(dir, r);\n  }\n  Status DeleteFile(const std::string& f) override {\n    return target_->DeleteFile(f);\n  }\n  Status CreateDir(const std::string& d) override {\n    return target_->CreateDir(d);\n  }\n  Status DeleteDir(const std::string& d) override {\n    return target_->DeleteDir(d);\n  }\n  Status GetFileSize(const std::string& f, uint64_t* s) override {\n    return target_->GetFileSize(f, s);\n  }\n  Status RenameFile(const std::string& s, const std::string& t) override {\n    return target_->RenameFile(s, t);\n  }\n  Status LockFile(const std::string& f, FileLock** l) override {\n    return target_->LockFile(f, l);\n  }\n  Status UnlockFile(FileLock* l) override { return target_->UnlockFile(l); }\n  void Schedule(void (*f)(void*), void* a) override {\n    return target_->Schedule(f, a);\n  }\n  void StartThread(void (*f)(void*), void* a) override {\n    return target_->StartThread(f, a);\n  }\n  Status GetTestDirectory(std::string* path) override {\n    return target_->GetTestDirectory(path);\n  }\n  Status NewLogger(const std::string& fname, Logger** result) override {\n    return target_->NewLogger(fname, result);\n  }\n  uint64_t NowMicros() override { return target_->NowMicros(); }\n  void SleepForMicroseconds(int micros) override {\n    target_->SleepForMicroseconds(micros);\n  }\n\n private:\n  Env* target_;\n};\n\n}  // namespace leveldb\n\n// Redefine DeleteFile if necessary.\n#if defined(_WIN32) && defined(LEVELDB_DELETEFILE_UNDEFINED)\n#if defined(UNICODE)\n#define DeleteFile DeleteFileW\n#else\n#define DeleteFile DeleteFileA\n#endif  // defined(UNICODE)\n#endif  // defined(_WIN32) && defined(LEVELDB_DELETEFILE_UNDEFINED)\n\n#endif  // STORAGE_LEVELDB_INCLUDE_ENV_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/export.h",
    "content": "// Copyright (c) 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_EXPORT_H_\n#define STORAGE_LEVELDB_INCLUDE_EXPORT_H_\n\n#if !defined(LEVELDB_EXPORT)\n\n#if defined(LEVELDB_SHARED_LIBRARY)\n#if defined(_WIN32)\n\n#if defined(LEVELDB_COMPILE_LIBRARY)\n#define LEVELDB_EXPORT __declspec(dllexport)\n#else\n#define LEVELDB_EXPORT __declspec(dllimport)\n#endif  // defined(LEVELDB_COMPILE_LIBRARY)\n\n#else  // defined(_WIN32)\n#if defined(LEVELDB_COMPILE_LIBRARY)\n#define LEVELDB_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define LEVELDB_EXPORT\n#endif\n#endif  // defined(_WIN32)\n\n#else  // defined(LEVELDB_SHARED_LIBRARY)\n#define LEVELDB_EXPORT\n#endif\n\n#endif  // !defined(LEVELDB_EXPORT)\n\n#endif  // STORAGE_LEVELDB_INCLUDE_EXPORT_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/filter_policy.h",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// A database can be configured with a custom FilterPolicy object.\n// This object is responsible for creating a small filter from a set\n// of keys.  These filters are stored in leveldb and are consulted\n// automatically by leveldb to decide whether or not to read some\n// information from disk. In many cases, a filter can cut down the\n// number of disk seeks form a handful to a single disk seek per\n// DB::Get() call.\n//\n// Most people will want to use the builtin bloom filter support (see\n// NewBloomFilterPolicy() below).\n\n#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_\n#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_\n\n#include <string>\n\n#include \"leveldb/export.h\"\n\nnamespace leveldb {\n\nclass Slice;\n\nclass LEVELDB_EXPORT FilterPolicy {\n public:\n  virtual ~FilterPolicy();\n\n  // Return the name of this policy.  Note that if the filter encoding\n  // changes in an incompatible way, the name returned by this method\n  // must be changed.  Otherwise, old incompatible filters may be\n  // passed to methods of this type.\n  virtual const char* Name() const = 0;\n\n  // keys[0,n-1] contains a list of keys (potentially with duplicates)\n  // that are ordered according to the user supplied comparator.\n  // Append a filter that summarizes keys[0,n-1] to *dst.\n  //\n  // Warning: do not change the initial contents of *dst.  Instead,\n  // append the newly constructed filter to *dst.\n  virtual void CreateFilter(const Slice* keys, int n,\n                            std::string* dst) const = 0;\n\n  // \"filter\" contains the data appended by a preceding call to\n  // CreateFilter() on this class.  This method must return true if\n  // the key was in the list of keys passed to CreateFilter().\n  // This method may return true or false if the key was not on the\n  // list, but it should aim to return false with a high probability.\n  virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0;\n};\n\n// Return a new filter policy that uses a bloom filter with approximately\n// the specified number of bits per key.  A good value for bits_per_key\n// is 10, which yields a filter with ~ 1% false positive rate.\n//\n// Callers must delete the result after any database that is using the\n// result has been closed.\n//\n// Note: if you are using a custom comparator that ignores some parts\n// of the keys being compared, you must not use NewBloomFilterPolicy()\n// and must provide your own FilterPolicy that also ignores the\n// corresponding parts of the keys.  For example, if the comparator\n// ignores trailing spaces, it would be incorrect to use a\n// FilterPolicy (like NewBloomFilterPolicy) that does not ignore\n// trailing spaces in keys.\nLEVELDB_EXPORT const FilterPolicy* NewBloomFilterPolicy(int bits_per_key);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/iterator.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// An iterator yields a sequence of key/value pairs from a source.\n// The following class defines the interface.  Multiple implementations\n// are provided by this library.  In particular, iterators are provided\n// to access the contents of a Table or a DB.\n//\n// Multiple threads can invoke const methods on an Iterator without\n// external synchronization, but if any of the threads may call a\n// non-const method, all threads accessing the same Iterator must use\n// external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_\n#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_\n\n#include \"leveldb/export.h\"\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nclass LEVELDB_EXPORT Iterator {\n public:\n  Iterator();\n\n  Iterator(const Iterator&) = delete;\n  Iterator& operator=(const Iterator&) = delete;\n\n  virtual ~Iterator();\n\n  // An iterator is either positioned at a key/value pair, or\n  // not valid.  This method returns true iff the iterator is valid.\n  virtual bool Valid() const = 0;\n\n  // Position at the first key in the source.  The iterator is Valid()\n  // after this call iff the source is not empty.\n  virtual void SeekToFirst() = 0;\n\n  // Position at the last key in the source.  The iterator is\n  // Valid() after this call iff the source is not empty.\n  virtual void SeekToLast() = 0;\n\n  // Position at the first key in the source that is at or past target.\n  // The iterator is Valid() after this call iff the source contains\n  // an entry that comes at or past target.\n  virtual void Seek(const Slice& target) = 0;\n\n  // Moves to the next entry in the source.  After this call, Valid() is\n  // true iff the iterator was not positioned at the last entry in the source.\n  // REQUIRES: Valid()\n  virtual void Next() = 0;\n\n  // Moves to the previous entry in the source.  After this call, Valid() is\n  // true iff the iterator was not positioned at the first entry in source.\n  // REQUIRES: Valid()\n  virtual void Prev() = 0;\n\n  // Return the key for the current entry.  The underlying storage for\n  // the returned slice is valid only until the next modification of\n  // the iterator.\n  // REQUIRES: Valid()\n  virtual Slice key() const = 0;\n\n  // Return the value for the current entry.  The underlying storage for\n  // the returned slice is valid only until the next modification of\n  // the iterator.\n  // REQUIRES: Valid()\n  virtual Slice value() const = 0;\n\n  // If an error has occurred, return it.  Else return an ok status.\n  virtual Status status() const = 0;\n\n  // Clients are allowed to register function/arg1/arg2 triples that\n  // will be invoked when this iterator is destroyed.\n  //\n  // Note that unlike all of the preceding methods, this method is\n  // not abstract and therefore clients should not override it.\n  using CleanupFunction = void (*)(void* arg1, void* arg2);\n  void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2);\n\n private:\n  // Cleanup functions are stored in a single-linked list.\n  // The list's head node is inlined in the iterator.\n  struct CleanupNode {\n    // True if the node is not used. Only head nodes might be unused.\n    bool IsEmpty() const { return function == nullptr; }\n    // Invokes the cleanup function.\n    void Run() {\n      assert(function != nullptr);\n      (*function)(arg1, arg2);\n    }\n\n    // The head node is used if the function pointer is not null.\n    CleanupFunction function;\n    void* arg1;\n    void* arg2;\n    CleanupNode* next;\n  };\n  CleanupNode cleanup_head_;\n};\n\n// Return an empty iterator (yields nothing).\nLEVELDB_EXPORT Iterator* NewEmptyIterator();\n\n// Return an empty iterator with the specified status.\nLEVELDB_EXPORT Iterator* NewErrorIterator(const Status& status);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/options.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_\n#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_\n\n#include <stddef.h>\n\n#include \"leveldb/export.h\"\n\nnamespace leveldb {\n\nclass Cache;\nclass Comparator;\nclass Env;\nclass FilterPolicy;\nclass Logger;\nclass Snapshot;\n\n// DB contents are stored in a set of blocks, each of which holds a\n// sequence of key,value pairs.  Each block may be compressed before\n// being stored in a file.  The following enum describes which\n// compression method (if any) is used to compress a block.\nenum CompressionType {\n  // NOTE: do not change the values of existing entries, as these are\n  // part of the persistent format on disk.\n  kNoCompression = 0x0,\n  kSnappyCompression = 0x1\n};\n\n// Options to control the behavior of a database (passed to DB::Open)\nstruct LEVELDB_EXPORT Options {\n  // Create an Options object with default values for all fields.\n  Options();\n\n  // -------------------\n  // Parameters that affect behavior\n\n  // Comparator used to define the order of keys in the table.\n  // Default: a comparator that uses lexicographic byte-wise ordering\n  //\n  // REQUIRES: The client must ensure that the comparator supplied\n  // here has the same name and orders keys *exactly* the same as the\n  // comparator provided to previous open calls on the same DB.\n  const Comparator* comparator;\n\n  // If true, the database will be created if it is missing.\n  bool create_if_missing = false;\n\n  // If true, an error is raised if the database already exists.\n  bool error_if_exists = false;\n\n  // If true, the implementation will do aggressive checking of the\n  // data it is processing and will stop early if it detects any\n  // errors.  This may have unforeseen ramifications: for example, a\n  // corruption of one DB entry may cause a large number of entries to\n  // become unreadable or for the entire DB to become unopenable.\n  bool paranoid_checks = false;\n\n  // Use the specified object to interact with the environment,\n  // e.g. to read/write files, schedule background work, etc.\n  // Default: Env::Default()\n  Env* env;\n\n  // Any internal progress/error information generated by the db will\n  // be written to info_log if it is non-null, or to a file stored\n  // in the same directory as the DB contents if info_log is null.\n  Logger* info_log = nullptr;\n\n  // -------------------\n  // Parameters that affect performance\n\n  // Amount of data to build up in memory (backed by an unsorted log\n  // on disk) before converting to a sorted on-disk file.\n  //\n  // Larger values increase performance, especially during bulk loads.\n  // Up to two write buffers may be held in memory at the same time,\n  // so you may wish to adjust this parameter to control memory usage.\n  // Also, a larger write buffer will result in a longer recovery time\n  // the next time the database is opened.\n  size_t write_buffer_size = 4 * 1024 * 1024;\n\n  // Number of open files that can be used by the DB.  You may need to\n  // increase this if your database has a large working set (budget\n  // one open file per 2MB of working set).\n  int max_open_files = 1000;\n\n  // Control over blocks (user data is stored in a set of blocks, and\n  // a block is the unit of reading from disk).\n\n  // If non-null, use the specified cache for blocks.\n  // If null, leveldb will automatically create and use an 8MB internal cache.\n  Cache* block_cache = nullptr;\n\n  // Approximate size of user data packed per block.  Note that the\n  // block size specified here corresponds to uncompressed data.  The\n  // actual size of the unit read from disk may be smaller if\n  // compression is enabled.  This parameter can be changed dynamically.\n  size_t block_size = 4 * 1024;\n\n  // Number of keys between restart points for delta encoding of keys.\n  // This parameter can be changed dynamically.  Most clients should\n  // leave this parameter alone.\n  int block_restart_interval = 16;\n\n  // Leveldb will write up to this amount of bytes to a file before\n  // switching to a new one.\n  // Most clients should leave this parameter alone.  However if your\n  // filesystem is more efficient with larger files, you could\n  // consider increasing the value.  The downside will be longer\n  // compactions and hence longer latency/performance hiccups.\n  // Another reason to increase this parameter might be when you are\n  // initially populating a large database.\n  size_t max_file_size = 2 * 1024 * 1024;\n\n  // Compress blocks using the specified compression algorithm.  This\n  // parameter can be changed dynamically.\n  //\n  // Default: kSnappyCompression, which gives lightweight but fast\n  // compression.\n  //\n  // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:\n  //    ~200-500MB/s compression\n  //    ~400-800MB/s decompression\n  // Note that these speeds are significantly faster than most\n  // persistent storage speeds, and therefore it is typically never\n  // worth switching to kNoCompression.  Even if the input data is\n  // incompressible, the kSnappyCompression implementation will\n  // efficiently detect that and will switch to uncompressed mode.\n  CompressionType compression = kSnappyCompression;\n\n  // EXPERIMENTAL: If true, append to existing MANIFEST and log files\n  // when a database is opened.  This can significantly speed up open.\n  //\n  // Default: currently false, but may become true later.\n  bool reuse_logs = false;\n\n  // If non-null, use the specified filter policy to reduce disk reads.\n  // Many applications will benefit from passing the result of\n  // NewBloomFilterPolicy() here.\n  const FilterPolicy* filter_policy = nullptr;\n};\n\n// Options that control read operations\nstruct LEVELDB_EXPORT ReadOptions {\n  ReadOptions() = default;\n\n  // If true, all data read from underlying storage will be\n  // verified against corresponding checksums.\n  bool verify_checksums = false;\n\n  // Should the data read for this iteration be cached in memory?\n  // Callers may wish to set this field to false for bulk scans.\n  bool fill_cache = true;\n\n  // If \"snapshot\" is non-null, read as of the supplied snapshot\n  // (which must belong to the DB that is being read and which must\n  // not have been released).  If \"snapshot\" is null, use an implicit\n  // snapshot of the state at the beginning of this read operation.\n  const Snapshot* snapshot = nullptr;\n};\n\n// Options that control write operations\nstruct LEVELDB_EXPORT WriteOptions {\n  WriteOptions() = default;\n\n  // If true, the write will be flushed from the operating system\n  // buffer cache (by calling WritableFile::Sync()) before the write\n  // is considered complete.  If this flag is true, writes will be\n  // slower.\n  //\n  // If this flag is false, and the machine crashes, some recent\n  // writes may be lost.  Note that if it is just the process that\n  // crashes (i.e., the machine does not reboot), no writes will be\n  // lost even if sync==false.\n  //\n  // In other words, a DB write with sync==false has similar\n  // crash semantics as the \"write()\" system call.  A DB write\n  // with sync==true has similar crash semantics to a \"write()\"\n  // system call followed by \"fsync()\".\n  bool sync = false;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/slice.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Slice is a simple structure containing a pointer into some external\n// storage and a size.  The user of a Slice must ensure that the slice\n// is not used after the corresponding external storage has been\n// deallocated.\n//\n// Multiple threads can invoke const methods on a Slice without\n// external synchronization, but if any of the threads may call a\n// non-const method, all threads accessing the same Slice must use\n// external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_\n#define STORAGE_LEVELDB_INCLUDE_SLICE_H_\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n\n#include <string>\n\n#include \"leveldb/export.h\"\n\nnamespace leveldb {\n\nclass LEVELDB_EXPORT Slice {\n public:\n  // Create an empty slice.\n  Slice() : data_(\"\"), size_(0) {}\n\n  // Create a slice that refers to d[0,n-1].\n  Slice(const char* d, size_t n) : data_(d), size_(n) {}\n\n  // Create a slice that refers to the contents of \"s\"\n  Slice(const std::string& s) : data_(s.data()), size_(s.size()) {}\n\n  // Create a slice that refers to s[0,strlen(s)-1]\n  Slice(const char* s) : data_(s), size_(strlen(s)) {}\n\n  // Intentionally copyable.\n  Slice(const Slice&) = default;\n  Slice& operator=(const Slice&) = default;\n\n  // Return a pointer to the beginning of the referenced data\n  const char* data() const { return data_; }\n\n  // Return the length (in bytes) of the referenced data\n  size_t size() const { return size_; }\n\n  // Return true iff the length of the referenced data is zero\n  bool empty() const { return size_ == 0; }\n\n  // Return the ith byte in the referenced data.\n  // REQUIRES: n < size()\n  char operator[](size_t n) const {\n    assert(n < size());\n    return data_[n];\n  }\n\n  // Change this slice to refer to an empty array\n  void clear() {\n    data_ = \"\";\n    size_ = 0;\n  }\n\n  // Drop the first \"n\" bytes from this slice.\n  void remove_prefix(size_t n) {\n    assert(n <= size());\n    data_ += n;\n    size_ -= n;\n  }\n\n  // Return a string that contains the copy of the referenced data.\n  std::string ToString() const { return std::string(data_, size_); }\n\n  // Three-way comparison.  Returns value:\n  //   <  0 iff \"*this\" <  \"b\",\n  //   == 0 iff \"*this\" == \"b\",\n  //   >  0 iff \"*this\" >  \"b\"\n  int compare(const Slice& b) const;\n\n  // Return true iff \"x\" is a prefix of \"*this\"\n  bool starts_with(const Slice& x) const {\n    return ((size_ >= x.size_) && (memcmp(data_, x.data_, x.size_) == 0));\n  }\n\n private:\n  const char* data_;\n  size_t size_;\n};\n\ninline bool operator==(const Slice& x, const Slice& y) {\n  return ((x.size() == y.size()) &&\n          (memcmp(x.data(), y.data(), x.size()) == 0));\n}\n\ninline bool operator!=(const Slice& x, const Slice& y) { return !(x == y); }\n\ninline int Slice::compare(const Slice& b) const {\n  const size_t min_len = (size_ < b.size_) ? size_ : b.size_;\n  int r = memcmp(data_, b.data_, min_len);\n  if (r == 0) {\n    if (size_ < b.size_)\n      r = -1;\n    else if (size_ > b.size_)\n      r = +1;\n  }\n  return r;\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_SLICE_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/status.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// A Status encapsulates the result of an operation.  It may indicate success,\n// or it may indicate an error with an associated error message.\n//\n// Multiple threads can invoke const methods on a Status without\n// external synchronization, but if any of the threads may call a\n// non-const method, all threads accessing the same Status must use\n// external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_\n#define STORAGE_LEVELDB_INCLUDE_STATUS_H_\n\n#include <algorithm>\n#include <string>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/slice.h\"\n\nnamespace leveldb {\n\nclass LEVELDB_EXPORT Status {\n public:\n  // Create a success status.\n  Status() noexcept : state_(nullptr) {}\n  ~Status() { delete[] state_; }\n\n  Status(const Status& rhs);\n  Status& operator=(const Status& rhs);\n\n  Status(Status&& rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; }\n  Status& operator=(Status&& rhs) noexcept;\n\n  // Return a success status.\n  static Status OK() { return Status(); }\n\n  // Return error status of an appropriate type.\n  static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {\n    return Status(kNotFound, msg, msg2);\n  }\n  static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {\n    return Status(kCorruption, msg, msg2);\n  }\n  static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {\n    return Status(kNotSupported, msg, msg2);\n  }\n  static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {\n    return Status(kInvalidArgument, msg, msg2);\n  }\n  static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {\n    return Status(kIOError, msg, msg2);\n  }\n\n  // Returns true iff the status indicates success.\n  bool ok() const { return (state_ == nullptr); }\n\n  // Returns true iff the status indicates a NotFound error.\n  bool IsNotFound() const { return code() == kNotFound; }\n\n  // Returns true iff the status indicates a Corruption error.\n  bool IsCorruption() const { return code() == kCorruption; }\n\n  // Returns true iff the status indicates an IOError.\n  bool IsIOError() const { return code() == kIOError; }\n\n  // Returns true iff the status indicates a NotSupportedError.\n  bool IsNotSupportedError() const { return code() == kNotSupported; }\n\n  // Returns true iff the status indicates an InvalidArgument.\n  bool IsInvalidArgument() const { return code() == kInvalidArgument; }\n\n  // Return a string representation of this status suitable for printing.\n  // Returns the string \"OK\" for success.\n  std::string ToString() const;\n\n private:\n  enum Code {\n    kOk = 0,\n    kNotFound = 1,\n    kCorruption = 2,\n    kNotSupported = 3,\n    kInvalidArgument = 4,\n    kIOError = 5\n  };\n\n  Code code() const {\n    return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);\n  }\n\n  Status(Code code, const Slice& msg, const Slice& msg2);\n  static const char* CopyState(const char* s);\n\n  // OK status has a null state_.  Otherwise, state_ is a new[] array\n  // of the following form:\n  //    state_[0..3] == length of message\n  //    state_[4]    == code\n  //    state_[5..]  == message\n  const char* state_;\n};\n\ninline Status::Status(const Status& rhs) {\n  state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);\n}\ninline Status& Status::operator=(const Status& rhs) {\n  // The following condition catches both aliasing (when this == &rhs),\n  // and the common case where both rhs and *this are ok.\n  if (state_ != rhs.state_) {\n    delete[] state_;\n    state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);\n  }\n  return *this;\n}\ninline Status& Status::operator=(Status&& rhs) noexcept {\n  std::swap(state_, rhs.state_);\n  return *this;\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_STATUS_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/table.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_\n#define STORAGE_LEVELDB_INCLUDE_TABLE_H_\n\n#include <stdint.h>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/iterator.h\"\n\nnamespace leveldb {\n\nclass Block;\nclass BlockHandle;\nclass Footer;\nstruct Options;\nclass RandomAccessFile;\nstruct ReadOptions;\nclass TableCache;\n\n// A Table is a sorted map from strings to strings.  Tables are\n// immutable and persistent.  A Table may be safely accessed from\n// multiple threads without external synchronization.\nclass LEVELDB_EXPORT Table {\n public:\n  // Attempt to open the table that is stored in bytes [0..file_size)\n  // of \"file\", and read the metadata entries necessary to allow\n  // retrieving data from the table.\n  //\n  // If successful, returns ok and sets \"*table\" to the newly opened\n  // table.  The client should delete \"*table\" when no longer needed.\n  // If there was an error while initializing the table, sets \"*table\"\n  // to nullptr and returns a non-ok status.  Does not take ownership of\n  // \"*source\", but the client must ensure that \"source\" remains live\n  // for the duration of the returned table's lifetime.\n  //\n  // *file must remain live while this Table is in use.\n  static Status Open(const Options& options, RandomAccessFile* file,\n                     uint64_t file_size, Table** table);\n\n  Table(const Table&) = delete;\n  Table& operator=(const Table&) = delete;\n\n  ~Table();\n\n  // Returns a new iterator over the table contents.\n  // The result of NewIterator() is initially invalid (caller must\n  // call one of the Seek methods on the iterator before using it).\n  Iterator* NewIterator(const ReadOptions&) const;\n\n  // Given a key, return an approximate byte offset in the file where\n  // the data for that key begins (or would begin if the key were\n  // present in the file).  The returned value is in terms of file\n  // bytes, and so includes effects like compression of the underlying data.\n  // E.g., the approximate offset of the last key in the table will\n  // be close to the file length.\n  uint64_t ApproximateOffsetOf(const Slice& key) const;\n\n private:\n  friend class TableCache;\n  struct Rep;\n\n  static Iterator* BlockReader(void*, const ReadOptions&, const Slice&);\n\n  explicit Table(Rep* rep) : rep_(rep) {}\n\n  // Calls (*handle_result)(arg, ...) with the entry found after a call\n  // to Seek(key).  May not make such a call if filter policy says\n  // that key is not present.\n  Status InternalGet(const ReadOptions&, const Slice& key, void* arg,\n                     void (*handle_result)(void* arg, const Slice& k,\n                                           const Slice& v));\n\n  void ReadMeta(const Footer& footer);\n  void ReadFilter(const Slice& filter_handle_value);\n\n  Rep* const rep_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/table_builder.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// TableBuilder provides the interface used to build a Table\n// (an immutable and sorted map from keys to values).\n//\n// Multiple threads can invoke const methods on a TableBuilder without\n// external synchronization, but if any of the threads may call a\n// non-const method, all threads accessing the same TableBuilder must use\n// external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_\n#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_\n\n#include <stdint.h>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/options.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nclass BlockBuilder;\nclass BlockHandle;\nclass WritableFile;\n\nclass LEVELDB_EXPORT TableBuilder {\n public:\n  // Create a builder that will store the contents of the table it is\n  // building in *file.  Does not close the file.  It is up to the\n  // caller to close the file after calling Finish().\n  TableBuilder(const Options& options, WritableFile* file);\n\n  TableBuilder(const TableBuilder&) = delete;\n  TableBuilder& operator=(const TableBuilder&) = delete;\n\n  // REQUIRES: Either Finish() or Abandon() has been called.\n  ~TableBuilder();\n\n  // Change the options used by this builder.  Note: only some of the\n  // option fields can be changed after construction.  If a field is\n  // not allowed to change dynamically and its value in the structure\n  // passed to the constructor is different from its value in the\n  // structure passed to this method, this method will return an error\n  // without changing any fields.\n  Status ChangeOptions(const Options& options);\n\n  // Add key,value to the table being constructed.\n  // REQUIRES: key is after any previously added key according to comparator.\n  // REQUIRES: Finish(), Abandon() have not been called\n  void Add(const Slice& key, const Slice& value);\n\n  // Advanced operation: flush any buffered key/value pairs to file.\n  // Can be used to ensure that two adjacent entries never live in\n  // the same data block.  Most clients should not need to use this method.\n  // REQUIRES: Finish(), Abandon() have not been called\n  void Flush();\n\n  // Return non-ok iff some error has been detected.\n  Status status() const;\n\n  // Finish building the table.  Stops using the file passed to the\n  // constructor after this function returns.\n  // REQUIRES: Finish(), Abandon() have not been called\n  Status Finish();\n\n  // Indicate that the contents of this builder should be abandoned.  Stops\n  // using the file passed to the constructor after this function returns.\n  // If the caller is not going to call Finish(), it must call Abandon()\n  // before destroying this builder.\n  // REQUIRES: Finish(), Abandon() have not been called\n  void Abandon();\n\n  // Number of calls to Add() so far.\n  uint64_t NumEntries() const;\n\n  // Size of the file generated so far.  If invoked after a successful\n  // Finish() call, returns the size of the final generated file.\n  uint64_t FileSize() const;\n\n private:\n  bool ok() const { return status().ok(); }\n  void WriteBlock(BlockBuilder* block, BlockHandle* handle);\n  void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle);\n\n  struct Rep;\n  Rep* rep_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_\n"
  },
  {
    "path": "src/leveldb/include/leveldb/write_batch.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// WriteBatch holds a collection of updates to apply atomically to a DB.\n//\n// The updates are applied in the order in which they are added\n// to the WriteBatch.  For example, the value of \"key\" will be \"v3\"\n// after the following batch is written:\n//\n//    batch.Put(\"key\", \"v1\");\n//    batch.Delete(\"key\");\n//    batch.Put(\"key\", \"v2\");\n//    batch.Put(\"key\", \"v3\");\n//\n// Multiple threads can invoke const methods on a WriteBatch without\n// external synchronization, but if any of the threads may call a\n// non-const method, all threads accessing the same WriteBatch must use\n// external synchronization.\n\n#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_\n#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_\n\n#include <string>\n\n#include \"leveldb/export.h\"\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\n\nclass Slice;\n\nclass LEVELDB_EXPORT WriteBatch {\n public:\n  class LEVELDB_EXPORT Handler {\n   public:\n    virtual ~Handler();\n    virtual void Put(const Slice& key, const Slice& value) = 0;\n    virtual void Delete(const Slice& key) = 0;\n  };\n\n  WriteBatch();\n\n  // Intentionally copyable.\n  WriteBatch(const WriteBatch&) = default;\n  WriteBatch& operator=(const WriteBatch&) = default;\n\n  ~WriteBatch();\n\n  // Store the mapping \"key->value\" in the database.\n  void Put(const Slice& key, const Slice& value);\n\n  // If the database contains a mapping for \"key\", erase it.  Else do nothing.\n  void Delete(const Slice& key);\n\n  // Clear all updates buffered in this batch.\n  void Clear();\n\n  // The size of the database changes caused by this batch.\n  //\n  // This number is tied to implementation details, and may change across\n  // releases. It is intended for LevelDB usage metrics.\n  size_t ApproximateSize() const;\n\n  // Copies the operations in \"source\" to this batch.\n  //\n  // This runs in O(source size) time. However, the constant factor is better\n  // than calling Iterate() over the source batch with a Handler that replicates\n  // the operations into this batch.\n  void Append(const WriteBatch& source);\n\n  // Support for iterating over the contents of a batch.\n  Status Iterate(Handler* handler) const;\n\n private:\n  friend class WriteBatchInternal;\n\n  std::string rep_;  // See comment in write_batch.cc for the format of rep_\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_\n"
  },
  {
    "path": "src/leveldb/issues/issue178_test.cc",
    "content": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// Test for issue 178: a manual compaction causes deleted data to reappear.\n#include <cstdlib>\n#include <iostream>\n#include <sstream>\n\n#include \"leveldb/db.h\"\n#include \"leveldb/write_batch.h\"\n#include \"util/testharness.h\"\n\nnamespace {\n\nconst int kNumKeys = 1100000;\n\nstd::string Key1(int i) {\n  char buf[100];\n  snprintf(buf, sizeof(buf), \"my_key_%d\", i);\n  return buf;\n}\n\nstd::string Key2(int i) { return Key1(i) + \"_xxx\"; }\n\nclass Issue178 {};\n\nTEST(Issue178, Test) {\n  // Get rid of any state from an old run.\n  std::string dbpath = leveldb::test::TmpDir() + \"/leveldb_cbug_test\";\n  DestroyDB(dbpath, leveldb::Options());\n\n  // Open database.  Disable compression since it affects the creation\n  // of layers and the code below is trying to test against a very\n  // specific scenario.\n  leveldb::DB* db;\n  leveldb::Options db_options;\n  db_options.create_if_missing = true;\n  db_options.compression = leveldb::kNoCompression;\n  ASSERT_OK(leveldb::DB::Open(db_options, dbpath, &db));\n\n  // create first key range\n  leveldb::WriteBatch batch;\n  for (size_t i = 0; i < kNumKeys; i++) {\n    batch.Put(Key1(i), \"value for range 1 key\");\n  }\n  ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch));\n\n  // create second key range\n  batch.Clear();\n  for (size_t i = 0; i < kNumKeys; i++) {\n    batch.Put(Key2(i), \"value for range 2 key\");\n  }\n  ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch));\n\n  // delete second key range\n  batch.Clear();\n  for (size_t i = 0; i < kNumKeys; i++) {\n    batch.Delete(Key2(i));\n  }\n  ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch));\n\n  // compact database\n  std::string start_key = Key1(0);\n  std::string end_key = Key1(kNumKeys - 1);\n  leveldb::Slice least(start_key.data(), start_key.size());\n  leveldb::Slice greatest(end_key.data(), end_key.size());\n\n  // commenting out the line below causes the example to work correctly\n  db->CompactRange(&least, &greatest);\n\n  // count the keys\n  leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions());\n  size_t num_keys = 0;\n  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {\n    num_keys++;\n  }\n  delete iter;\n  ASSERT_EQ(kNumKeys, num_keys) << \"Bad number of keys\";\n\n  // close database\n  delete db;\n  DestroyDB(dbpath, leveldb::Options());\n}\n\n}  // anonymous namespace\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/issues/issue200_test.cc",
    "content": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// Test for issue 200: when iterator switches direction from backward\n// to forward, the current key can be yielded unexpectedly if a new\n// mutation has been added just before the current key.\n\n#include \"leveldb/db.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass Issue200 {};\n\nTEST(Issue200, Test) {\n  // Get rid of any state from an old run.\n  std::string dbpath = test::TmpDir() + \"/leveldb_issue200_test\";\n  DestroyDB(dbpath, Options());\n\n  DB* db;\n  Options options;\n  options.create_if_missing = true;\n  ASSERT_OK(DB::Open(options, dbpath, &db));\n\n  WriteOptions write_options;\n  ASSERT_OK(db->Put(write_options, \"1\", \"b\"));\n  ASSERT_OK(db->Put(write_options, \"2\", \"c\"));\n  ASSERT_OK(db->Put(write_options, \"3\", \"d\"));\n  ASSERT_OK(db->Put(write_options, \"4\", \"e\"));\n  ASSERT_OK(db->Put(write_options, \"5\", \"f\"));\n\n  ReadOptions read_options;\n  Iterator* iter = db->NewIterator(read_options);\n\n  // Add an element that should not be reflected in the iterator.\n  ASSERT_OK(db->Put(write_options, \"25\", \"cd\"));\n\n  iter->Seek(\"5\");\n  ASSERT_EQ(iter->key().ToString(), \"5\");\n  iter->Prev();\n  ASSERT_EQ(iter->key().ToString(), \"4\");\n  iter->Prev();\n  ASSERT_EQ(iter->key().ToString(), \"3\");\n  iter->Next();\n  ASSERT_EQ(iter->key().ToString(), \"4\");\n  iter->Next();\n  ASSERT_EQ(iter->key().ToString(), \"5\");\n\n  delete iter;\n  delete db;\n  DestroyDB(dbpath, options);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/issues/issue320_test.cc",
    "content": "// Copyright (c) 2019 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <cstdint>\n#include <cstdlib>\n#include <iostream>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"leveldb/db.h\"\n#include \"leveldb/write_batch.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nnamespace {\n\n// Creates a random number in the range of [0, max).\nint GenerateRandomNumber(int max) { return std::rand() % max; }\n\nstd::string CreateRandomString(int32_t index) {\n  static const size_t len = 1024;\n  char bytes[len];\n  size_t i = 0;\n  while (i < 8) {\n    bytes[i] = 'a' + ((index >> (4 * i)) & 0xf);\n    ++i;\n  }\n  while (i < sizeof(bytes)) {\n    bytes[i] = 'a' + GenerateRandomNumber(26);\n    ++i;\n  }\n  return std::string(bytes, sizeof(bytes));\n}\n\n}  // namespace\n\nclass Issue320 {};\n\nTEST(Issue320, Test) {\n  std::srand(0);\n\n  bool delete_before_put = false;\n  bool keep_snapshots = true;\n\n  std::vector<std::unique_ptr<std::pair<std::string, std::string>>> test_map(\n      10000);\n  std::vector<Snapshot const*> snapshots(100, nullptr);\n\n  DB* db;\n  Options options;\n  options.create_if_missing = true;\n\n  std::string dbpath = test::TmpDir() + \"/leveldb_issue320_test\";\n  ASSERT_OK(DB::Open(options, dbpath, &db));\n\n  uint32_t target_size = 10000;\n  uint32_t num_items = 0;\n  uint32_t count = 0;\n  std::string key;\n  std::string value, old_value;\n\n  WriteOptions writeOptions;\n  ReadOptions readOptions;\n  while (count < 200000) {\n    if ((++count % 1000) == 0) {\n      std::cout << \"count: \" << count << std::endl;\n    }\n\n    int index = GenerateRandomNumber(test_map.size());\n    WriteBatch batch;\n\n    if (test_map[index] == nullptr) {\n      num_items++;\n      test_map[index].reset(new std::pair<std::string, std::string>(\n          CreateRandomString(index), CreateRandomString(index)));\n      batch.Put(test_map[index]->first, test_map[index]->second);\n    } else {\n      ASSERT_OK(db->Get(readOptions, test_map[index]->first, &old_value));\n      if (old_value != test_map[index]->second) {\n        std::cout << \"ERROR incorrect value returned by Get\" << std::endl;\n        std::cout << \"  count=\" << count << std::endl;\n        std::cout << \"  old value=\" << old_value << std::endl;\n        std::cout << \"  test_map[index]->second=\" << test_map[index]->second\n                  << std::endl;\n        std::cout << \"  test_map[index]->first=\" << test_map[index]->first\n                  << std::endl;\n        std::cout << \"  index=\" << index << std::endl;\n        ASSERT_EQ(old_value, test_map[index]->second);\n      }\n\n      if (num_items >= target_size && GenerateRandomNumber(100) > 30) {\n        batch.Delete(test_map[index]->first);\n        test_map[index] = nullptr;\n        --num_items;\n      } else {\n        test_map[index]->second = CreateRandomString(index);\n        if (delete_before_put) batch.Delete(test_map[index]->first);\n        batch.Put(test_map[index]->first, test_map[index]->second);\n      }\n    }\n\n    ASSERT_OK(db->Write(writeOptions, &batch));\n\n    if (keep_snapshots && GenerateRandomNumber(10) == 0) {\n      int i = GenerateRandomNumber(snapshots.size());\n      if (snapshots[i] != nullptr) {\n        db->ReleaseSnapshot(snapshots[i]);\n      }\n      snapshots[i] = db->GetSnapshot();\n    }\n  }\n\n  for (Snapshot const* snapshot : snapshots) {\n    if (snapshot) {\n      db->ReleaseSnapshot(snapshot);\n    }\n  }\n\n  delete db;\n  DestroyDB(dbpath, options);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/port/README.md",
    "content": "This directory contains interfaces and implementations that isolate the\nrest of the package from platform details.\n\nCode in the rest of the package includes \"port.h\" from this directory.\n\"port.h\" in turn includes a platform specific \"port_<platform>.h\" file\nthat provides the platform specific implementation.\n\nSee port_stdcxx.h for an example of what must be provided in a platform\nspecific header file.\n\n"
  },
  {
    "path": "src/leveldb/port/port.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_PORT_PORT_H_\n#define STORAGE_LEVELDB_PORT_PORT_H_\n\n#include <string.h>\n\n// Include the appropriate platform specific file below.  If you are\n// porting to a new platform, see \"port_example.h\" for documentation\n// of what the new port_<platform>.h file must provide.\n#if defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_WINDOWS)\n#include \"port/port_stdcxx.h\"\n#elif defined(LEVELDB_PLATFORM_CHROMIUM)\n#include \"port/port_chromium.h\"\n#endif\n\n#endif  // STORAGE_LEVELDB_PORT_PORT_H_\n"
  },
  {
    "path": "src/leveldb/port/port_config.h.in",
    "content": "// Copyright 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_PORT_PORT_CONFIG_H_\n#define STORAGE_LEVELDB_PORT_PORT_CONFIG_H_\n\n// Define to 1 if you have a definition for fdatasync() in <unistd.h>.\n#if !defined(HAVE_FDATASYNC)\n#cmakedefine01 HAVE_FDATASYNC\n#endif  // !defined(HAVE_FDATASYNC)\n\n// Define to 1 if you have a definition for F_FULLFSYNC in <fcntl.h>.\n#if !defined(HAVE_FULLFSYNC)\n#cmakedefine01 HAVE_FULLFSYNC\n#endif  // !defined(HAVE_FULLFSYNC)\n\n// Define to 1 if you have a definition for O_CLOEXEC in <fcntl.h>.\n#if !defined(HAVE_O_CLOEXEC)\n#cmakedefine01 HAVE_O_CLOEXEC\n#endif  // !defined(HAVE_O_CLOEXEC)\n\n// Define to 1 if you have Google CRC32C.\n#if !defined(HAVE_CRC32C)\n#cmakedefine01 HAVE_CRC32C\n#endif  // !defined(HAVE_CRC32C)\n\n// Define to 1 if you have Google Snappy.\n#if !defined(HAVE_SNAPPY)\n#cmakedefine01 HAVE_SNAPPY\n#endif  // !defined(HAVE_SNAPPY)\n\n// Define to 1 if your processor stores words with the most significant byte\n// first (like Motorola and SPARC, unlike Intel and VAX).\n#if !defined(LEVELDB_IS_BIG_ENDIAN)\n#cmakedefine01 LEVELDB_IS_BIG_ENDIAN\n#endif  // !defined(LEVELDB_IS_BIG_ENDIAN)\n\n#endif  // STORAGE_LEVELDB_PORT_PORT_CONFIG_H_"
  },
  {
    "path": "src/leveldb/port/port_example.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// This file contains the specification, but not the implementations,\n// of the types/operations/etc. that should be defined by a platform\n// specific port_<platform>.h file.  Use this file as a reference for\n// how to port this package to a new platform.\n\n#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_\n#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_\n\n#include \"port/thread_annotations.h\"\n\nnamespace leveldb {\nnamespace port {\n\n// TODO(jorlow): Many of these belong more in the environment class rather than\n//               here. We should try moving them and see if it affects perf.\n\n// The following boolean constant must be true on a little-endian machine\n// and false otherwise.\nstatic const bool kLittleEndian = true /* or some other expression */;\n\n// ------------------ Threading -------------------\n\n// A Mutex represents an exclusive lock.\nclass LOCKABLE Mutex {\n public:\n  Mutex();\n  ~Mutex();\n\n  // Lock the mutex.  Waits until other lockers have exited.\n  // Will deadlock if the mutex is already locked by this thread.\n  void Lock() EXCLUSIVE_LOCK_FUNCTION();\n\n  // Unlock the mutex.\n  // REQUIRES: This mutex was locked by this thread.\n  void Unlock() UNLOCK_FUNCTION();\n\n  // Optionally crash if this thread does not hold this mutex.\n  // The implementation must be fast, especially if NDEBUG is\n  // defined.  The implementation is allowed to skip all checks.\n  void AssertHeld() ASSERT_EXCLUSIVE_LOCK();\n};\n\nclass CondVar {\n public:\n  explicit CondVar(Mutex* mu);\n  ~CondVar();\n\n  // Atomically release *mu and block on this condition variable until\n  // either a call to SignalAll(), or a call to Signal() that picks\n  // this thread to wakeup.\n  // REQUIRES: this thread holds *mu\n  void Wait();\n\n  // If there are some threads waiting, wake up at least one of them.\n  void Signal();\n\n  // Wake up all waiting threads.\n  void SignallAll();\n};\n\n// ------------------ Compression -------------------\n\n// Store the snappy compression of \"input[0,input_length-1]\" in *output.\n// Returns false if snappy is not supported by this port.\nbool Snappy_Compress(const char* input, size_t input_length,\n                     std::string* output);\n\n// If input[0,input_length-1] looks like a valid snappy compressed\n// buffer, store the size of the uncompressed data in *result and\n// return true.  Else return false.\nbool Snappy_GetUncompressedLength(const char* input, size_t length,\n                                  size_t* result);\n\n// Attempt to snappy uncompress input[0,input_length-1] into *output.\n// Returns true if successful, false if the input is invalid lightweight\n// compressed data.\n//\n// REQUIRES: at least the first \"n\" bytes of output[] must be writable\n// where \"n\" is the result of a successful call to\n// Snappy_GetUncompressedLength.\nbool Snappy_Uncompress(const char* input_data, size_t input_length,\n                       char* output);\n\n// ------------------ Miscellaneous -------------------\n\n// If heap profiling is not supported, returns false.\n// Else repeatedly calls (*func)(arg, data, n) and then returns true.\n// The concatenation of all \"data[0,n-1]\" fragments is the heap profile.\nbool GetHeapProfile(void (*func)(void*, const char*, int), void* arg);\n\n// Extend the CRC to include the first n bytes of buf.\n//\n// Returns zero if the CRC cannot be extended using acceleration, else returns\n// the newly extended CRC value (which may also be zero).\nuint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size);\n\n}  // namespace port\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_\n"
  },
  {
    "path": "src/leveldb/port/port_stdcxx.h",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_PORT_PORT_STDCXX_H_\n#define STORAGE_LEVELDB_PORT_PORT_STDCXX_H_\n\n// port/port_config.h availability is automatically detected via __has_include\n// in newer compilers. If LEVELDB_HAS_PORT_CONFIG_H is defined, it overrides the\n// configuration detection.\n#if defined(LEVELDB_HAS_PORT_CONFIG_H)\n\n#if LEVELDB_HAS_PORT_CONFIG_H\n#include \"port/port_config.h\"\n#endif  // LEVELDB_HAS_PORT_CONFIG_H\n\n#elif defined(__has_include)\n\n#if __has_include(\"port/port_config.h\")\n#include \"port/port_config.h\"\n#endif  // __has_include(\"port/port_config.h\")\n\n#endif  // defined(LEVELDB_HAS_PORT_CONFIG_H)\n\n#if HAVE_CRC32C\n#include <crc32c/crc32c.h>\n#endif  // HAVE_CRC32C\n#if HAVE_SNAPPY\n#include <snappy.h>\n#endif  // HAVE_SNAPPY\n\n#include <cassert>\n#include <condition_variable>  // NOLINT\n#include <cstddef>\n#include <cstdint>\n#include <mutex>  // NOLINT\n#include <string>\n\n#include \"port/thread_annotations.h\"\n\nnamespace leveldb {\nnamespace port {\n\nstatic const bool kLittleEndian = !LEVELDB_IS_BIG_ENDIAN;\n\nclass CondVar;\n\n// Thinly wraps std::mutex.\nclass LOCKABLE Mutex {\n public:\n  Mutex() = default;\n  ~Mutex() = default;\n\n  Mutex(const Mutex&) = delete;\n  Mutex& operator=(const Mutex&) = delete;\n\n  void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu_.lock(); }\n  void Unlock() UNLOCK_FUNCTION() { mu_.unlock(); }\n  void AssertHeld() ASSERT_EXCLUSIVE_LOCK() {}\n\n private:\n  friend class CondVar;\n  std::mutex mu_;\n};\n\n// Thinly wraps std::condition_variable.\nclass CondVar {\n public:\n  explicit CondVar(Mutex* mu) : mu_(mu) { assert(mu != nullptr); }\n  ~CondVar() = default;\n\n  CondVar(const CondVar&) = delete;\n  CondVar& operator=(const CondVar&) = delete;\n\n  void Wait() {\n    std::unique_lock<std::mutex> lock(mu_->mu_, std::adopt_lock);\n    cv_.wait(lock);\n    lock.release();\n  }\n  void Signal() { cv_.notify_one(); }\n  void SignalAll() { cv_.notify_all(); }\n\n private:\n  std::condition_variable cv_;\n  Mutex* const mu_;\n};\n\ninline bool Snappy_Compress(const char* input, size_t length,\n                            std::string* output) {\n#if HAVE_SNAPPY\n  output->resize(snappy::MaxCompressedLength(length));\n  size_t outlen;\n  snappy::RawCompress(input, length, &(*output)[0], &outlen);\n  output->resize(outlen);\n  return true;\n#else\n  // Silence compiler warnings about unused arguments.\n  (void)input;\n  (void)length;\n  (void)output;\n#endif  // HAVE_SNAPPY\n\n  return false;\n}\n\ninline bool Snappy_GetUncompressedLength(const char* input, size_t length,\n                                         size_t* result) {\n#if HAVE_SNAPPY\n  return snappy::GetUncompressedLength(input, length, result);\n#else\n  // Silence compiler warnings about unused arguments.\n  (void)input;\n  (void)length;\n  (void)result;\n  return false;\n#endif  // HAVE_SNAPPY\n}\n\ninline bool Snappy_Uncompress(const char* input, size_t length, char* output) {\n#if HAVE_SNAPPY\n  return snappy::RawUncompress(input, length, output);\n#else\n  // Silence compiler warnings about unused arguments.\n  (void)input;\n  (void)length;\n  (void)output;\n  return false;\n#endif  // HAVE_SNAPPY\n}\n\ninline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {\n  // Silence compiler warnings about unused arguments.\n  (void)func;\n  (void)arg;\n  return false;\n}\n\ninline uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) {\n#if HAVE_CRC32C\n  return ::crc32c::Extend(crc, reinterpret_cast<const uint8_t*>(buf), size);\n#else\n  // Silence compiler warnings about unused arguments.\n  (void)crc;\n  (void)buf;\n  (void)size;\n  return 0;\n#endif  // HAVE_CRC32C\n}\n\n}  // namespace port\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_PORT_PORT_STDCXX_H_\n"
  },
  {
    "path": "src/leveldb/port/thread_annotations.h",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_\n#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_\n\n// Use Clang's thread safety analysis annotations when available. In other\n// environments, the macros receive empty definitions.\n// Usage documentation: https://clang.llvm.org/docs/ThreadSafetyAnalysis.html\n\n#if !defined(THREAD_ANNOTATION_ATTRIBUTE__)\n\n#if defined(__clang__)\n\n#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))\n#else\n#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op\n#endif\n\n#endif  // !defined(THREAD_ANNOTATION_ATTRIBUTE__)\n\n#ifndef GUARDED_BY\n#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))\n#endif\n\n#ifndef PT_GUARDED_BY\n#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))\n#endif\n\n#ifndef ACQUIRED_AFTER\n#define ACQUIRED_AFTER(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))\n#endif\n\n#ifndef ACQUIRED_BEFORE\n#define ACQUIRED_BEFORE(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))\n#endif\n\n#ifndef EXCLUSIVE_LOCKS_REQUIRED\n#define EXCLUSIVE_LOCKS_REQUIRED(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))\n#endif\n\n#ifndef SHARED_LOCKS_REQUIRED\n#define SHARED_LOCKS_REQUIRED(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))\n#endif\n\n#ifndef LOCKS_EXCLUDED\n#define LOCKS_EXCLUDED(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))\n#endif\n\n#ifndef LOCK_RETURNED\n#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))\n#endif\n\n#ifndef LOCKABLE\n#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)\n#endif\n\n#ifndef SCOPED_LOCKABLE\n#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)\n#endif\n\n#ifndef EXCLUSIVE_LOCK_FUNCTION\n#define EXCLUSIVE_LOCK_FUNCTION(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))\n#endif\n\n#ifndef SHARED_LOCK_FUNCTION\n#define SHARED_LOCK_FUNCTION(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))\n#endif\n\n#ifndef EXCLUSIVE_TRYLOCK_FUNCTION\n#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))\n#endif\n\n#ifndef SHARED_TRYLOCK_FUNCTION\n#define SHARED_TRYLOCK_FUNCTION(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))\n#endif\n\n#ifndef UNLOCK_FUNCTION\n#define UNLOCK_FUNCTION(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))\n#endif\n\n#ifndef NO_THREAD_SAFETY_ANALYSIS\n#define NO_THREAD_SAFETY_ANALYSIS \\\n  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)\n#endif\n\n#ifndef ASSERT_EXCLUSIVE_LOCK\n#define ASSERT_EXCLUSIVE_LOCK(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))\n#endif\n\n#ifndef ASSERT_SHARED_LOCK\n#define ASSERT_SHARED_LOCK(...) \\\n  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))\n#endif\n\n#endif  // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_\n"
  },
  {
    "path": "src/leveldb/table/block.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Decodes the blocks generated by block_builder.cc.\n\n#include \"table/block.h\"\n\n#include <algorithm>\n#include <cstdint>\n#include <vector>\n\n#include \"leveldb/comparator.h\"\n#include \"table/format.h\"\n#include \"util/coding.h\"\n#include \"util/logging.h\"\n\nnamespace leveldb {\n\ninline uint32_t Block::NumRestarts() const {\n  assert(size_ >= sizeof(uint32_t));\n  return DecodeFixed32(data_ + size_ - sizeof(uint32_t));\n}\n\nBlock::Block(const BlockContents& contents)\n    : data_(contents.data.data()),\n      size_(contents.data.size()),\n      owned_(contents.heap_allocated) {\n  if (size_ < sizeof(uint32_t)) {\n    size_ = 0;  // Error marker\n  } else {\n    size_t max_restarts_allowed = (size_ - sizeof(uint32_t)) / sizeof(uint32_t);\n    if (NumRestarts() > max_restarts_allowed) {\n      // The size is too small for NumRestarts()\n      size_ = 0;\n    } else {\n      restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);\n    }\n  }\n}\n\nBlock::~Block() {\n  if (owned_) {\n    delete[] data_;\n  }\n}\n\n// Helper routine: decode the next block entry starting at \"p\",\n// storing the number of shared key bytes, non_shared key bytes,\n// and the length of the value in \"*shared\", \"*non_shared\", and\n// \"*value_length\", respectively.  Will not dereference past \"limit\".\n//\n// If any errors are detected, returns nullptr.  Otherwise, returns a\n// pointer to the key delta (just past the three decoded values).\nstatic inline const char* DecodeEntry(const char* p, const char* limit,\n                                      uint32_t* shared, uint32_t* non_shared,\n                                      uint32_t* value_length) {\n  if (limit - p < 3) return nullptr;\n  *shared = reinterpret_cast<const uint8_t*>(p)[0];\n  *non_shared = reinterpret_cast<const uint8_t*>(p)[1];\n  *value_length = reinterpret_cast<const uint8_t*>(p)[2];\n  if ((*shared | *non_shared | *value_length) < 128) {\n    // Fast path: all three values are encoded in one byte each\n    p += 3;\n  } else {\n    if ((p = GetVarint32Ptr(p, limit, shared)) == nullptr) return nullptr;\n    if ((p = GetVarint32Ptr(p, limit, non_shared)) == nullptr) return nullptr;\n    if ((p = GetVarint32Ptr(p, limit, value_length)) == nullptr) return nullptr;\n  }\n\n  if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {\n    return nullptr;\n  }\n  return p;\n}\n\nclass Block::Iter : public Iterator {\n private:\n  const Comparator* const comparator_;\n  const char* const data_;       // underlying block contents\n  uint32_t const restarts_;      // Offset of restart array (list of fixed32)\n  uint32_t const num_restarts_;  // Number of uint32_t entries in restart array\n\n  // current_ is offset in data_ of current entry.  >= restarts_ if !Valid\n  uint32_t current_;\n  uint32_t restart_index_;  // Index of restart block in which current_ falls\n  std::string key_;\n  Slice value_;\n  Status status_;\n\n  inline int Compare(const Slice& a, const Slice& b) const {\n    return comparator_->Compare(a, b);\n  }\n\n  // Return the offset in data_ just past the end of the current entry.\n  inline uint32_t NextEntryOffset() const {\n    return (value_.data() + value_.size()) - data_;\n  }\n\n  uint32_t GetRestartPoint(uint32_t index) {\n    assert(index < num_restarts_);\n    return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));\n  }\n\n  void SeekToRestartPoint(uint32_t index) {\n    key_.clear();\n    restart_index_ = index;\n    // current_ will be fixed by ParseNextKey();\n\n    // ParseNextKey() starts at the end of value_, so set value_ accordingly\n    uint32_t offset = GetRestartPoint(index);\n    value_ = Slice(data_ + offset, 0);\n  }\n\n public:\n  Iter(const Comparator* comparator, const char* data, uint32_t restarts,\n       uint32_t num_restarts)\n      : comparator_(comparator),\n        data_(data),\n        restarts_(restarts),\n        num_restarts_(num_restarts),\n        current_(restarts_),\n        restart_index_(num_restarts_) {\n    assert(num_restarts_ > 0);\n  }\n\n  bool Valid() const override { return current_ < restarts_; }\n  Status status() const override { return status_; }\n  Slice key() const override {\n    assert(Valid());\n    return key_;\n  }\n  Slice value() const override {\n    assert(Valid());\n    return value_;\n  }\n\n  void Next() override {\n    assert(Valid());\n    ParseNextKey();\n  }\n\n  void Prev() override {\n    assert(Valid());\n\n    // Scan backwards to a restart point before current_\n    const uint32_t original = current_;\n    while (GetRestartPoint(restart_index_) >= original) {\n      if (restart_index_ == 0) {\n        // No more entries\n        current_ = restarts_;\n        restart_index_ = num_restarts_;\n        return;\n      }\n      restart_index_--;\n    }\n\n    SeekToRestartPoint(restart_index_);\n    do {\n      // Loop until end of current entry hits the start of original entry\n    } while (ParseNextKey() && NextEntryOffset() < original);\n  }\n\n  void Seek(const Slice& target) override {\n    // Binary search in restart array to find the last restart point\n    // with a key < target\n    uint32_t left = 0;\n    uint32_t right = num_restarts_ - 1;\n    while (left < right) {\n      uint32_t mid = (left + right + 1) / 2;\n      uint32_t region_offset = GetRestartPoint(mid);\n      uint32_t shared, non_shared, value_length;\n      const char* key_ptr =\n          DecodeEntry(data_ + region_offset, data_ + restarts_, &shared,\n                      &non_shared, &value_length);\n      if (key_ptr == nullptr || (shared != 0)) {\n        CorruptionError();\n        return;\n      }\n      Slice mid_key(key_ptr, non_shared);\n      if (Compare(mid_key, target) < 0) {\n        // Key at \"mid\" is smaller than \"target\".  Therefore all\n        // blocks before \"mid\" are uninteresting.\n        left = mid;\n      } else {\n        // Key at \"mid\" is >= \"target\".  Therefore all blocks at or\n        // after \"mid\" are uninteresting.\n        right = mid - 1;\n      }\n    }\n\n    // Linear search (within restart block) for first key >= target\n    SeekToRestartPoint(left);\n    while (true) {\n      if (!ParseNextKey()) {\n        return;\n      }\n      if (Compare(key_, target) >= 0) {\n        return;\n      }\n    }\n  }\n\n  void SeekToFirst() override {\n    SeekToRestartPoint(0);\n    ParseNextKey();\n  }\n\n  void SeekToLast() override {\n    SeekToRestartPoint(num_restarts_ - 1);\n    while (ParseNextKey() && NextEntryOffset() < restarts_) {\n      // Keep skipping\n    }\n  }\n\n private:\n  void CorruptionError() {\n    current_ = restarts_;\n    restart_index_ = num_restarts_;\n    status_ = Status::Corruption(\"bad entry in block\");\n    key_.clear();\n    value_.clear();\n  }\n\n  bool ParseNextKey() {\n    current_ = NextEntryOffset();\n    const char* p = data_ + current_;\n    const char* limit = data_ + restarts_;  // Restarts come right after data\n    if (p >= limit) {\n      // No more entries to return.  Mark as invalid.\n      current_ = restarts_;\n      restart_index_ = num_restarts_;\n      return false;\n    }\n\n    // Decode next entry\n    uint32_t shared, non_shared, value_length;\n    p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);\n    if (p == nullptr || key_.size() < shared) {\n      CorruptionError();\n      return false;\n    } else {\n      key_.resize(shared);\n      key_.append(p, non_shared);\n      value_ = Slice(p + non_shared, value_length);\n      while (restart_index_ + 1 < num_restarts_ &&\n             GetRestartPoint(restart_index_ + 1) < current_) {\n        ++restart_index_;\n      }\n      return true;\n    }\n  }\n};\n\nIterator* Block::NewIterator(const Comparator* comparator) {\n  if (size_ < sizeof(uint32_t)) {\n    return NewErrorIterator(Status::Corruption(\"bad block contents\"));\n  }\n  const uint32_t num_restarts = NumRestarts();\n  if (num_restarts == 0) {\n    return NewEmptyIterator();\n  } else {\n    return new Iter(comparator, data_, restart_offset_, num_restarts);\n  }\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/block.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_\n#define STORAGE_LEVELDB_TABLE_BLOCK_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"leveldb/iterator.h\"\n\nnamespace leveldb {\n\nstruct BlockContents;\nclass Comparator;\n\nclass Block {\n public:\n  // Initialize the block with the specified contents.\n  explicit Block(const BlockContents& contents);\n\n  Block(const Block&) = delete;\n  Block& operator=(const Block&) = delete;\n\n  ~Block();\n\n  size_t size() const { return size_; }\n  Iterator* NewIterator(const Comparator* comparator);\n\n private:\n  class Iter;\n\n  uint32_t NumRestarts() const;\n\n  const char* data_;\n  size_t size_;\n  uint32_t restart_offset_;  // Offset in data_ of restart array\n  bool owned_;               // Block owns data_[]\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_BLOCK_H_\n"
  },
  {
    "path": "src/leveldb/table/block_builder.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// BlockBuilder generates blocks where keys are prefix-compressed:\n//\n// When we store a key, we drop the prefix shared with the previous\n// string.  This helps reduce the space requirement significantly.\n// Furthermore, once every K keys, we do not apply the prefix\n// compression and store the entire key.  We call this a \"restart\n// point\".  The tail end of the block stores the offsets of all of the\n// restart points, and can be used to do a binary search when looking\n// for a particular key.  Values are stored as-is (without compression)\n// immediately following the corresponding key.\n//\n// An entry for a particular key-value pair has the form:\n//     shared_bytes: varint32\n//     unshared_bytes: varint32\n//     value_length: varint32\n//     key_delta: char[unshared_bytes]\n//     value: char[value_length]\n// shared_bytes == 0 for restart points.\n//\n// The trailer of the block has the form:\n//     restarts: uint32[num_restarts]\n//     num_restarts: uint32\n// restarts[i] contains the offset within the block of the ith restart point.\n\n#include \"table/block_builder.h\"\n\n#include <assert.h>\n\n#include <algorithm>\n\n#include \"leveldb/comparator.h\"\n#include \"leveldb/options.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nBlockBuilder::BlockBuilder(const Options* options)\n    : options_(options), restarts_(), counter_(0), finished_(false) {\n  assert(options->block_restart_interval >= 1);\n  restarts_.push_back(0);  // First restart point is at offset 0\n}\n\nvoid BlockBuilder::Reset() {\n  buffer_.clear();\n  restarts_.clear();\n  restarts_.push_back(0);  // First restart point is at offset 0\n  counter_ = 0;\n  finished_ = false;\n  last_key_.clear();\n}\n\nsize_t BlockBuilder::CurrentSizeEstimate() const {\n  return (buffer_.size() +                       // Raw data buffer\n          restarts_.size() * sizeof(uint32_t) +  // Restart array\n          sizeof(uint32_t));                     // Restart array length\n}\n\nSlice BlockBuilder::Finish() {\n  // Append restart array\n  for (size_t i = 0; i < restarts_.size(); i++) {\n    PutFixed32(&buffer_, restarts_[i]);\n  }\n  PutFixed32(&buffer_, restarts_.size());\n  finished_ = true;\n  return Slice(buffer_);\n}\n\nvoid BlockBuilder::Add(const Slice& key, const Slice& value) {\n  Slice last_key_piece(last_key_);\n  assert(!finished_);\n  assert(counter_ <= options_->block_restart_interval);\n  assert(buffer_.empty()  // No values yet?\n         || options_->comparator->Compare(key, last_key_piece) > 0);\n  size_t shared = 0;\n  if (counter_ < options_->block_restart_interval) {\n    // See how much sharing to do with previous string\n    const size_t min_length = std::min(last_key_piece.size(), key.size());\n    while ((shared < min_length) && (last_key_piece[shared] == key[shared])) {\n      shared++;\n    }\n  } else {\n    // Restart compression\n    restarts_.push_back(buffer_.size());\n    counter_ = 0;\n  }\n  const size_t non_shared = key.size() - shared;\n\n  // Add \"<shared><non_shared><value_size>\" to buffer_\n  PutVarint32(&buffer_, shared);\n  PutVarint32(&buffer_, non_shared);\n  PutVarint32(&buffer_, value.size());\n\n  // Add string delta to buffer_ followed by value\n  buffer_.append(key.data() + shared, non_shared);\n  buffer_.append(value.data(), value.size());\n\n  // Update state\n  last_key_.resize(shared);\n  last_key_.append(key.data() + shared, non_shared);\n  assert(Slice(last_key_) == key);\n  counter_++;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/block_builder.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_\n#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_\n\n#include <stdint.h>\n\n#include <vector>\n\n#include \"leveldb/slice.h\"\n\nnamespace leveldb {\n\nstruct Options;\n\nclass BlockBuilder {\n public:\n  explicit BlockBuilder(const Options* options);\n\n  BlockBuilder(const BlockBuilder&) = delete;\n  BlockBuilder& operator=(const BlockBuilder&) = delete;\n\n  // Reset the contents as if the BlockBuilder was just constructed.\n  void Reset();\n\n  // REQUIRES: Finish() has not been called since the last call to Reset().\n  // REQUIRES: key is larger than any previously added key\n  void Add(const Slice& key, const Slice& value);\n\n  // Finish building the block and return a slice that refers to the\n  // block contents.  The returned slice will remain valid for the\n  // lifetime of this builder or until Reset() is called.\n  Slice Finish();\n\n  // Returns an estimate of the current (uncompressed) size of the block\n  // we are building.\n  size_t CurrentSizeEstimate() const;\n\n  // Return true iff no entries have been added since the last Reset()\n  bool empty() const { return buffer_.empty(); }\n\n private:\n  const Options* options_;\n  std::string buffer_;              // Destination buffer\n  std::vector<uint32_t> restarts_;  // Restart points\n  int counter_;                     // Number of entries emitted since restart\n  bool finished_;                   // Has Finish() been called?\n  std::string last_key_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_\n"
  },
  {
    "path": "src/leveldb/table/filter_block.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"table/filter_block.h\"\n\n#include \"leveldb/filter_policy.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\n// See doc/table_format.md for an explanation of the filter block format.\n\n// Generate new filter every 2KB of data\nstatic const size_t kFilterBaseLg = 11;\nstatic const size_t kFilterBase = 1 << kFilterBaseLg;\n\nFilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy)\n    : policy_(policy) {}\n\nvoid FilterBlockBuilder::StartBlock(uint64_t block_offset) {\n  uint64_t filter_index = (block_offset / kFilterBase);\n  assert(filter_index >= filter_offsets_.size());\n  while (filter_index > filter_offsets_.size()) {\n    GenerateFilter();\n  }\n}\n\nvoid FilterBlockBuilder::AddKey(const Slice& key) {\n  Slice k = key;\n  start_.push_back(keys_.size());\n  keys_.append(k.data(), k.size());\n}\n\nSlice FilterBlockBuilder::Finish() {\n  if (!start_.empty()) {\n    GenerateFilter();\n  }\n\n  // Append array of per-filter offsets\n  const uint32_t array_offset = result_.size();\n  for (size_t i = 0; i < filter_offsets_.size(); i++) {\n    PutFixed32(&result_, filter_offsets_[i]);\n  }\n\n  PutFixed32(&result_, array_offset);\n  result_.push_back(kFilterBaseLg);  // Save encoding parameter in result\n  return Slice(result_);\n}\n\nvoid FilterBlockBuilder::GenerateFilter() {\n  const size_t num_keys = start_.size();\n  if (num_keys == 0) {\n    // Fast path if there are no keys for this filter\n    filter_offsets_.push_back(result_.size());\n    return;\n  }\n\n  // Make list of keys from flattened key structure\n  start_.push_back(keys_.size());  // Simplify length computation\n  tmp_keys_.resize(num_keys);\n  for (size_t i = 0; i < num_keys; i++) {\n    const char* base = keys_.data() + start_[i];\n    size_t length = start_[i + 1] - start_[i];\n    tmp_keys_[i] = Slice(base, length);\n  }\n\n  // Generate filter for current set of keys and append to result_.\n  filter_offsets_.push_back(result_.size());\n  policy_->CreateFilter(&tmp_keys_[0], static_cast<int>(num_keys), &result_);\n\n  tmp_keys_.clear();\n  keys_.clear();\n  start_.clear();\n}\n\nFilterBlockReader::FilterBlockReader(const FilterPolicy* policy,\n                                     const Slice& contents)\n    : policy_(policy), data_(nullptr), offset_(nullptr), num_(0), base_lg_(0) {\n  size_t n = contents.size();\n  if (n < 5) return;  // 1 byte for base_lg_ and 4 for start of offset array\n  base_lg_ = contents[n - 1];\n  uint32_t last_word = DecodeFixed32(contents.data() + n - 5);\n  if (last_word > n - 5) return;\n  data_ = contents.data();\n  offset_ = data_ + last_word;\n  num_ = (n - 5 - last_word) / 4;\n}\n\nbool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {\n  uint64_t index = block_offset >> base_lg_;\n  if (index < num_) {\n    uint32_t start = DecodeFixed32(offset_ + index * 4);\n    uint32_t limit = DecodeFixed32(offset_ + index * 4 + 4);\n    if (start <= limit && limit <= static_cast<size_t>(offset_ - data_)) {\n      Slice filter = Slice(data_ + start, limit - start);\n      return policy_->KeyMayMatch(key, filter);\n    } else if (start == limit) {\n      // Empty filters do not match any keys\n      return false;\n    }\n  }\n  return true;  // Errors are treated as potential matches\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/filter_block.h",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// A filter block is stored near the end of a Table file.  It contains\n// filters (e.g., bloom filters) for all data blocks in the table combined\n// into a single filter block.\n\n#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_\n#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include <string>\n#include <vector>\n\n#include \"leveldb/slice.h\"\n#include \"util/hash.h\"\n\nnamespace leveldb {\n\nclass FilterPolicy;\n\n// A FilterBlockBuilder is used to construct all of the filters for a\n// particular Table.  It generates a single string which is stored as\n// a special block in the Table.\n//\n// The sequence of calls to FilterBlockBuilder must match the regexp:\n//      (StartBlock AddKey*)* Finish\nclass FilterBlockBuilder {\n public:\n  explicit FilterBlockBuilder(const FilterPolicy*);\n\n  FilterBlockBuilder(const FilterBlockBuilder&) = delete;\n  FilterBlockBuilder& operator=(const FilterBlockBuilder&) = delete;\n\n  void StartBlock(uint64_t block_offset);\n  void AddKey(const Slice& key);\n  Slice Finish();\n\n private:\n  void GenerateFilter();\n\n  const FilterPolicy* policy_;\n  std::string keys_;             // Flattened key contents\n  std::vector<size_t> start_;    // Starting index in keys_ of each key\n  std::string result_;           // Filter data computed so far\n  std::vector<Slice> tmp_keys_;  // policy_->CreateFilter() argument\n  std::vector<uint32_t> filter_offsets_;\n};\n\nclass FilterBlockReader {\n public:\n  // REQUIRES: \"contents\" and *policy must stay live while *this is live.\n  FilterBlockReader(const FilterPolicy* policy, const Slice& contents);\n  bool KeyMayMatch(uint64_t block_offset, const Slice& key);\n\n private:\n  const FilterPolicy* policy_;\n  const char* data_;    // Pointer to filter data (at block-start)\n  const char* offset_;  // Pointer to beginning of offset array (at block-end)\n  size_t num_;          // Number of entries in offset array\n  size_t base_lg_;      // Encoding parameter (see kFilterBaseLg in .cc file)\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_\n"
  },
  {
    "path": "src/leveldb/table/filter_block_test.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"table/filter_block.h\"\n\n#include \"leveldb/filter_policy.h\"\n#include \"util/coding.h\"\n#include \"util/hash.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\n// For testing: emit an array with one hash value per key\nclass TestHashFilter : public FilterPolicy {\n public:\n  const char* Name() const override { return \"TestHashFilter\"; }\n\n  void CreateFilter(const Slice* keys, int n, std::string* dst) const override {\n    for (int i = 0; i < n; i++) {\n      uint32_t h = Hash(keys[i].data(), keys[i].size(), 1);\n      PutFixed32(dst, h);\n    }\n  }\n\n  bool KeyMayMatch(const Slice& key, const Slice& filter) const override {\n    uint32_t h = Hash(key.data(), key.size(), 1);\n    for (size_t i = 0; i + 4 <= filter.size(); i += 4) {\n      if (h == DecodeFixed32(filter.data() + i)) {\n        return true;\n      }\n    }\n    return false;\n  }\n};\n\nclass FilterBlockTest {\n public:\n  TestHashFilter policy_;\n};\n\nTEST(FilterBlockTest, EmptyBuilder) {\n  FilterBlockBuilder builder(&policy_);\n  Slice block = builder.Finish();\n  ASSERT_EQ(\"\\\\x00\\\\x00\\\\x00\\\\x00\\\\x0b\", EscapeString(block));\n  FilterBlockReader reader(&policy_, block);\n  ASSERT_TRUE(reader.KeyMayMatch(0, \"foo\"));\n  ASSERT_TRUE(reader.KeyMayMatch(100000, \"foo\"));\n}\n\nTEST(FilterBlockTest, SingleChunk) {\n  FilterBlockBuilder builder(&policy_);\n  builder.StartBlock(100);\n  builder.AddKey(\"foo\");\n  builder.AddKey(\"bar\");\n  builder.AddKey(\"box\");\n  builder.StartBlock(200);\n  builder.AddKey(\"box\");\n  builder.StartBlock(300);\n  builder.AddKey(\"hello\");\n  Slice block = builder.Finish();\n  FilterBlockReader reader(&policy_, block);\n  ASSERT_TRUE(reader.KeyMayMatch(100, \"foo\"));\n  ASSERT_TRUE(reader.KeyMayMatch(100, \"bar\"));\n  ASSERT_TRUE(reader.KeyMayMatch(100, \"box\"));\n  ASSERT_TRUE(reader.KeyMayMatch(100, \"hello\"));\n  ASSERT_TRUE(reader.KeyMayMatch(100, \"foo\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(100, \"missing\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(100, \"other\"));\n}\n\nTEST(FilterBlockTest, MultiChunk) {\n  FilterBlockBuilder builder(&policy_);\n\n  // First filter\n  builder.StartBlock(0);\n  builder.AddKey(\"foo\");\n  builder.StartBlock(2000);\n  builder.AddKey(\"bar\");\n\n  // Second filter\n  builder.StartBlock(3100);\n  builder.AddKey(\"box\");\n\n  // Third filter is empty\n\n  // Last filter\n  builder.StartBlock(9000);\n  builder.AddKey(\"box\");\n  builder.AddKey(\"hello\");\n\n  Slice block = builder.Finish();\n  FilterBlockReader reader(&policy_, block);\n\n  // Check first filter\n  ASSERT_TRUE(reader.KeyMayMatch(0, \"foo\"));\n  ASSERT_TRUE(reader.KeyMayMatch(2000, \"bar\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(0, \"box\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(0, \"hello\"));\n\n  // Check second filter\n  ASSERT_TRUE(reader.KeyMayMatch(3100, \"box\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(3100, \"foo\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(3100, \"bar\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(3100, \"hello\"));\n\n  // Check third filter (empty)\n  ASSERT_TRUE(!reader.KeyMayMatch(4100, \"foo\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(4100, \"bar\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(4100, \"box\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(4100, \"hello\"));\n\n  // Check last filter\n  ASSERT_TRUE(reader.KeyMayMatch(9000, \"box\"));\n  ASSERT_TRUE(reader.KeyMayMatch(9000, \"hello\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(9000, \"foo\"));\n  ASSERT_TRUE(!reader.KeyMayMatch(9000, \"bar\"));\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/table/format.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"table/format.h\"\n\n#include \"leveldb/env.h\"\n#include \"port/port.h\"\n#include \"table/block.h\"\n#include \"util/coding.h\"\n#include \"util/crc32c.h\"\n\nnamespace leveldb {\n\nvoid BlockHandle::EncodeTo(std::string* dst) const {\n  // Sanity check that all fields have been set\n  assert(offset_ != ~static_cast<uint64_t>(0));\n  assert(size_ != ~static_cast<uint64_t>(0));\n  PutVarint64(dst, offset_);\n  PutVarint64(dst, size_);\n}\n\nStatus BlockHandle::DecodeFrom(Slice* input) {\n  if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) {\n    return Status::OK();\n  } else {\n    return Status::Corruption(\"bad block handle\");\n  }\n}\n\nvoid Footer::EncodeTo(std::string* dst) const {\n  const size_t original_size = dst->size();\n  metaindex_handle_.EncodeTo(dst);\n  index_handle_.EncodeTo(dst);\n  dst->resize(2 * BlockHandle::kMaxEncodedLength);  // Padding\n  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));\n  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));\n  assert(dst->size() == original_size + kEncodedLength);\n  (void)original_size;  // Disable unused variable warning.\n}\n\nStatus Footer::DecodeFrom(Slice* input) {\n  const char* magic_ptr = input->data() + kEncodedLength - 8;\n  const uint32_t magic_lo = DecodeFixed32(magic_ptr);\n  const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4);\n  const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |\n                          (static_cast<uint64_t>(magic_lo)));\n  if (magic != kTableMagicNumber) {\n    return Status::Corruption(\"not an sstable (bad magic number)\");\n  }\n\n  Status result = metaindex_handle_.DecodeFrom(input);\n  if (result.ok()) {\n    result = index_handle_.DecodeFrom(input);\n  }\n  if (result.ok()) {\n    // We skip over any leftover data (just padding for now) in \"input\"\n    const char* end = magic_ptr + 8;\n    *input = Slice(end, input->data() + input->size() - end);\n  }\n  return result;\n}\n\nStatus ReadBlock(RandomAccessFile* file, const ReadOptions& options,\n                 const BlockHandle& handle, BlockContents* result) {\n  result->data = Slice();\n  result->cachable = false;\n  result->heap_allocated = false;\n\n  // Read the block contents as well as the type/crc footer.\n  // See table_builder.cc for the code that built this structure.\n  size_t n = static_cast<size_t>(handle.size());\n  char* buf = new char[n + kBlockTrailerSize];\n  Slice contents;\n  Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);\n  if (!s.ok()) {\n    delete[] buf;\n    return s;\n  }\n  if (contents.size() != n + kBlockTrailerSize) {\n    delete[] buf;\n    return Status::Corruption(\"truncated block read\", file->GetName());\n  }\n\n  // Check the crc of the type and the block contents\n  const char* data = contents.data();  // Pointer to where Read put the data\n  if (options.verify_checksums) {\n    const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));\n    const uint32_t actual = crc32c::Value(data, n + 1);\n    if (actual != crc) {\n      delete[] buf;\n      s = Status::Corruption(\"block checksum mismatch\", file->GetName());\n      return s;\n    }\n  }\n\n  switch (data[n]) {\n    case kNoCompression:\n      if (data != buf) {\n        // File implementation gave us pointer to some other data.\n        // Use it directly under the assumption that it will be live\n        // while the file is open.\n        delete[] buf;\n        result->data = Slice(data, n);\n        result->heap_allocated = false;\n        result->cachable = false;  // Do not double-cache\n      } else {\n        result->data = Slice(buf, n);\n        result->heap_allocated = true;\n        result->cachable = true;\n      }\n\n      // Ok\n      break;\n    case kSnappyCompression: {\n      size_t ulength = 0;\n      if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) {\n        delete[] buf;\n        return Status::Corruption(\"corrupted compressed block contents\", file->GetName());\n      }\n      char* ubuf = new char[ulength];\n      if (!port::Snappy_Uncompress(data, n, ubuf)) {\n        delete[] buf;\n        delete[] ubuf;\n        return Status::Corruption(\"corrupted compressed block contents\", file->GetName());\n      }\n      delete[] buf;\n      result->data = Slice(ubuf, ulength);\n      result->heap_allocated = true;\n      result->cachable = true;\n      break;\n    }\n    default:\n      delete[] buf;\n      return Status::Corruption(\"bad block type\", file->GetName());\n  }\n\n  return Status::OK();\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/format.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_\n#define STORAGE_LEVELDB_TABLE_FORMAT_H_\n\n#include <stdint.h>\n\n#include <string>\n\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n#include \"leveldb/table_builder.h\"\n\nnamespace leveldb {\n\nclass Block;\nclass RandomAccessFile;\nstruct ReadOptions;\n\n// BlockHandle is a pointer to the extent of a file that stores a data\n// block or a meta block.\nclass BlockHandle {\n public:\n  // Maximum encoding length of a BlockHandle\n  enum { kMaxEncodedLength = 10 + 10 };\n\n  BlockHandle();\n\n  // The offset of the block in the file.\n  uint64_t offset() const { return offset_; }\n  void set_offset(uint64_t offset) { offset_ = offset; }\n\n  // The size of the stored block\n  uint64_t size() const { return size_; }\n  void set_size(uint64_t size) { size_ = size; }\n\n  void EncodeTo(std::string* dst) const;\n  Status DecodeFrom(Slice* input);\n\n private:\n  uint64_t offset_;\n  uint64_t size_;\n};\n\n// Footer encapsulates the fixed information stored at the tail\n// end of every table file.\nclass Footer {\n public:\n  // Encoded length of a Footer.  Note that the serialization of a\n  // Footer will always occupy exactly this many bytes.  It consists\n  // of two block handles and a magic number.\n  enum { kEncodedLength = 2 * BlockHandle::kMaxEncodedLength + 8 };\n\n  Footer() = default;\n\n  // The block handle for the metaindex block of the table\n  const BlockHandle& metaindex_handle() const { return metaindex_handle_; }\n  void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; }\n\n  // The block handle for the index block of the table\n  const BlockHandle& index_handle() const { return index_handle_; }\n  void set_index_handle(const BlockHandle& h) { index_handle_ = h; }\n\n  void EncodeTo(std::string* dst) const;\n  Status DecodeFrom(Slice* input);\n\n private:\n  BlockHandle metaindex_handle_;\n  BlockHandle index_handle_;\n};\n\n// kTableMagicNumber was picked by running\n//    echo http://code.google.com/p/leveldb/ | sha1sum\n// and taking the leading 64 bits.\nstatic const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull;\n\n// 1-byte type + 32-bit crc\nstatic const size_t kBlockTrailerSize = 5;\n\nstruct BlockContents {\n  Slice data;           // Actual contents of data\n  bool cachable;        // True iff data can be cached\n  bool heap_allocated;  // True iff caller should delete[] data.data()\n};\n\n// Read the block identified by \"handle\" from \"file\".  On failure\n// return non-OK.  On success fill *result and return OK.\nStatus ReadBlock(RandomAccessFile* file, const ReadOptions& options,\n                 const BlockHandle& handle, BlockContents* result);\n\n// Implementation details follow.  Clients should ignore,\n\ninline BlockHandle::BlockHandle()\n    : offset_(~static_cast<uint64_t>(0)), size_(~static_cast<uint64_t>(0)) {}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_FORMAT_H_\n"
  },
  {
    "path": "src/leveldb/table/iterator.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/iterator.h\"\n\nnamespace leveldb {\n\nIterator::Iterator() {\n  cleanup_head_.function = nullptr;\n  cleanup_head_.next = nullptr;\n}\n\nIterator::~Iterator() {\n  if (!cleanup_head_.IsEmpty()) {\n    cleanup_head_.Run();\n    for (CleanupNode* node = cleanup_head_.next; node != nullptr;) {\n      node->Run();\n      CleanupNode* next_node = node->next;\n      delete node;\n      node = next_node;\n    }\n  }\n}\n\nvoid Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) {\n  assert(func != nullptr);\n  CleanupNode* node;\n  if (cleanup_head_.IsEmpty()) {\n    node = &cleanup_head_;\n  } else {\n    node = new CleanupNode();\n    node->next = cleanup_head_.next;\n    cleanup_head_.next = node;\n  }\n  node->function = func;\n  node->arg1 = arg1;\n  node->arg2 = arg2;\n}\n\nnamespace {\n\nclass EmptyIterator : public Iterator {\n public:\n  EmptyIterator(const Status& s) : status_(s) {}\n  ~EmptyIterator() override = default;\n\n  bool Valid() const override { return false; }\n  void Seek(const Slice& target) override {}\n  void SeekToFirst() override {}\n  void SeekToLast() override {}\n  void Next() override { assert(false); }\n  void Prev() override { assert(false); }\n  Slice key() const override {\n    assert(false);\n    return Slice();\n  }\n  Slice value() const override {\n    assert(false);\n    return Slice();\n  }\n  Status status() const override { return status_; }\n\n private:\n  Status status_;\n};\n\n}  // anonymous namespace\n\nIterator* NewEmptyIterator() { return new EmptyIterator(Status::OK()); }\n\nIterator* NewErrorIterator(const Status& status) {\n  return new EmptyIterator(status);\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/iterator_wrapper.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_\n#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_\n\n#include \"leveldb/iterator.h\"\n#include \"leveldb/slice.h\"\n\nnamespace leveldb {\n\n// A internal wrapper class with an interface similar to Iterator that\n// caches the valid() and key() results for an underlying iterator.\n// This can help avoid virtual function calls and also gives better\n// cache locality.\nclass IteratorWrapper {\n public:\n  IteratorWrapper() : iter_(nullptr), valid_(false) {}\n  explicit IteratorWrapper(Iterator* iter) : iter_(nullptr) { Set(iter); }\n  ~IteratorWrapper() { delete iter_; }\n  Iterator* iter() const { return iter_; }\n\n  // Takes ownership of \"iter\" and will delete it when destroyed, or\n  // when Set() is invoked again.\n  void Set(Iterator* iter) {\n    delete iter_;\n    iter_ = iter;\n    if (iter_ == nullptr) {\n      valid_ = false;\n    } else {\n      Update();\n    }\n  }\n\n  // Iterator interface methods\n  bool Valid() const { return valid_; }\n  Slice key() const {\n    assert(Valid());\n    return key_;\n  }\n  Slice value() const {\n    assert(Valid());\n    return iter_->value();\n  }\n  // Methods below require iter() != nullptr\n  Status status() const {\n    assert(iter_);\n    return iter_->status();\n  }\n  void Next() {\n    assert(iter_);\n    iter_->Next();\n    Update();\n  }\n  void Prev() {\n    assert(iter_);\n    iter_->Prev();\n    Update();\n  }\n  void Seek(const Slice& k) {\n    assert(iter_);\n    iter_->Seek(k);\n    Update();\n  }\n  void SeekToFirst() {\n    assert(iter_);\n    iter_->SeekToFirst();\n    Update();\n  }\n  void SeekToLast() {\n    assert(iter_);\n    iter_->SeekToLast();\n    Update();\n  }\n\n private:\n  void Update() {\n    valid_ = iter_->Valid();\n    if (valid_) {\n      key_ = iter_->key();\n    }\n  }\n\n  Iterator* iter_;\n  bool valid_;\n  Slice key_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_\n"
  },
  {
    "path": "src/leveldb/table/merger.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"table/merger.h\"\n\n#include \"leveldb/comparator.h\"\n#include \"leveldb/iterator.h\"\n#include \"table/iterator_wrapper.h\"\n\nnamespace leveldb {\n\nnamespace {\nclass MergingIterator : public Iterator {\n public:\n  MergingIterator(const Comparator* comparator, Iterator** children, int n)\n      : comparator_(comparator),\n        children_(new IteratorWrapper[n]),\n        n_(n),\n        current_(nullptr),\n        direction_(kForward) {\n    for (int i = 0; i < n; i++) {\n      children_[i].Set(children[i]);\n    }\n  }\n\n  ~MergingIterator() override { delete[] children_; }\n\n  bool Valid() const override { return (current_ != nullptr); }\n\n  void SeekToFirst() override {\n    for (int i = 0; i < n_; i++) {\n      children_[i].SeekToFirst();\n    }\n    FindSmallest();\n    direction_ = kForward;\n  }\n\n  void SeekToLast() override {\n    for (int i = 0; i < n_; i++) {\n      children_[i].SeekToLast();\n    }\n    FindLargest();\n    direction_ = kReverse;\n  }\n\n  void Seek(const Slice& target) override {\n    for (int i = 0; i < n_; i++) {\n      children_[i].Seek(target);\n    }\n    FindSmallest();\n    direction_ = kForward;\n  }\n\n  void Next() override {\n    assert(Valid());\n\n    // Ensure that all children are positioned after key().\n    // If we are moving in the forward direction, it is already\n    // true for all of the non-current_ children since current_ is\n    // the smallest child and key() == current_->key().  Otherwise,\n    // we explicitly position the non-current_ children.\n    if (direction_ != kForward) {\n      for (int i = 0; i < n_; i++) {\n        IteratorWrapper* child = &children_[i];\n        if (child != current_) {\n          child->Seek(key());\n          if (child->Valid() &&\n              comparator_->Compare(key(), child->key()) == 0) {\n            child->Next();\n          }\n        }\n      }\n      direction_ = kForward;\n    }\n\n    current_->Next();\n    FindSmallest();\n  }\n\n  void Prev() override {\n    assert(Valid());\n\n    // Ensure that all children are positioned before key().\n    // If we are moving in the reverse direction, it is already\n    // true for all of the non-current_ children since current_ is\n    // the largest child and key() == current_->key().  Otherwise,\n    // we explicitly position the non-current_ children.\n    if (direction_ != kReverse) {\n      for (int i = 0; i < n_; i++) {\n        IteratorWrapper* child = &children_[i];\n        if (child != current_) {\n          child->Seek(key());\n          if (child->Valid()) {\n            // Child is at first entry >= key().  Step back one to be < key()\n            child->Prev();\n          } else {\n            // Child has no entries >= key().  Position at last entry.\n            child->SeekToLast();\n          }\n        }\n      }\n      direction_ = kReverse;\n    }\n\n    current_->Prev();\n    FindLargest();\n  }\n\n  Slice key() const override {\n    assert(Valid());\n    return current_->key();\n  }\n\n  Slice value() const override {\n    assert(Valid());\n    return current_->value();\n  }\n\n  Status status() const override {\n    Status status;\n    for (int i = 0; i < n_; i++) {\n      status = children_[i].status();\n      if (!status.ok()) {\n        break;\n      }\n    }\n    return status;\n  }\n\n private:\n  // Which direction is the iterator moving?\n  enum Direction { kForward, kReverse };\n\n  void FindSmallest();\n  void FindLargest();\n\n  // We might want to use a heap in case there are lots of children.\n  // For now we use a simple array since we expect a very small number\n  // of children in leveldb.\n  const Comparator* comparator_;\n  IteratorWrapper* children_;\n  int n_;\n  IteratorWrapper* current_;\n  Direction direction_;\n};\n\nvoid MergingIterator::FindSmallest() {\n  IteratorWrapper* smallest = nullptr;\n  for (int i = 0; i < n_; i++) {\n    IteratorWrapper* child = &children_[i];\n    if (child->Valid()) {\n      if (smallest == nullptr) {\n        smallest = child;\n      } else if (comparator_->Compare(child->key(), smallest->key()) < 0) {\n        smallest = child;\n      }\n    }\n  }\n  current_ = smallest;\n}\n\nvoid MergingIterator::FindLargest() {\n  IteratorWrapper* largest = nullptr;\n  for (int i = n_ - 1; i >= 0; i--) {\n    IteratorWrapper* child = &children_[i];\n    if (child->Valid()) {\n      if (largest == nullptr) {\n        largest = child;\n      } else if (comparator_->Compare(child->key(), largest->key()) > 0) {\n        largest = child;\n      }\n    }\n  }\n  current_ = largest;\n}\n}  // namespace\n\nIterator* NewMergingIterator(const Comparator* comparator, Iterator** children,\n                             int n) {\n  assert(n >= 0);\n  if (n == 0) {\n    return NewEmptyIterator();\n  } else if (n == 1) {\n    return children[0];\n  } else {\n    return new MergingIterator(comparator, children, n);\n  }\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/merger.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_\n#define STORAGE_LEVELDB_TABLE_MERGER_H_\n\nnamespace leveldb {\n\nclass Comparator;\nclass Iterator;\n\n// Return an iterator that provided the union of the data in\n// children[0,n-1].  Takes ownership of the child iterators and\n// will delete them when the result iterator is deleted.\n//\n// The result does no duplicate suppression.  I.e., if a particular\n// key is present in K child iterators, it will be yielded K times.\n//\n// REQUIRES: n >= 0\nIterator* NewMergingIterator(const Comparator* comparator, Iterator** children,\n                             int n);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_MERGER_H_\n"
  },
  {
    "path": "src/leveldb/table/table.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/table.h\"\n\n#include \"leveldb/cache.h\"\n#include \"leveldb/comparator.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/options.h\"\n#include \"table/block.h\"\n#include \"table/filter_block.h\"\n#include \"table/format.h\"\n#include \"table/two_level_iterator.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nstruct Table::Rep {\n  ~Rep() {\n    delete filter;\n    delete[] filter_data;\n    delete index_block;\n  }\n\n  Options options;\n  Status status;\n  RandomAccessFile* file;\n  uint64_t cache_id;\n  FilterBlockReader* filter;\n  const char* filter_data;\n\n  BlockHandle metaindex_handle;  // Handle to metaindex_block: saved from footer\n  Block* index_block;\n};\n\nStatus Table::Open(const Options& options, RandomAccessFile* file,\n                   uint64_t size, Table** table) {\n  *table = nullptr;\n  if (size < Footer::kEncodedLength) {\n    return Status::Corruption(\"file is too short to be an sstable\");\n  }\n\n  char footer_space[Footer::kEncodedLength];\n  Slice footer_input;\n  Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,\n                        &footer_input, footer_space);\n  if (!s.ok()) return s;\n\n  Footer footer;\n  s = footer.DecodeFrom(&footer_input);\n  if (!s.ok()) return s;\n\n  // Read the index block\n  BlockContents index_block_contents;\n  if (s.ok()) {\n    ReadOptions opt;\n    if (options.paranoid_checks) {\n      opt.verify_checksums = true;\n    }\n    s = ReadBlock(file, opt, footer.index_handle(), &index_block_contents);\n  }\n\n  if (s.ok()) {\n    // We've successfully read the footer and the index block: we're\n    // ready to serve requests.\n    Block* index_block = new Block(index_block_contents);\n    Rep* rep = new Table::Rep;\n    rep->options = options;\n    rep->file = file;\n    rep->metaindex_handle = footer.metaindex_handle();\n    rep->index_block = index_block;\n    rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);\n    rep->filter_data = nullptr;\n    rep->filter = nullptr;\n    *table = new Table(rep);\n    (*table)->ReadMeta(footer);\n  }\n\n  return s;\n}\n\nvoid Table::ReadMeta(const Footer& footer) {\n  if (rep_->options.filter_policy == nullptr) {\n    return;  // Do not need any metadata\n  }\n\n  // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates\n  // it is an empty block.\n  ReadOptions opt;\n  if (rep_->options.paranoid_checks) {\n    opt.verify_checksums = true;\n  }\n  BlockContents contents;\n  if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {\n    // Do not propagate errors since meta info is not needed for operation\n    return;\n  }\n  Block* meta = new Block(contents);\n\n  Iterator* iter = meta->NewIterator(BytewiseComparator());\n  std::string key = \"filter.\";\n  key.append(rep_->options.filter_policy->Name());\n  iter->Seek(key);\n  if (iter->Valid() && iter->key() == Slice(key)) {\n    ReadFilter(iter->value());\n  }\n  delete iter;\n  delete meta;\n}\n\nvoid Table::ReadFilter(const Slice& filter_handle_value) {\n  Slice v = filter_handle_value;\n  BlockHandle filter_handle;\n  if (!filter_handle.DecodeFrom(&v).ok()) {\n    return;\n  }\n\n  // We might want to unify with ReadBlock() if we start\n  // requiring checksum verification in Table::Open.\n  ReadOptions opt;\n  if (rep_->options.paranoid_checks) {\n    opt.verify_checksums = true;\n  }\n  BlockContents block;\n  if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {\n    return;\n  }\n  if (block.heap_allocated) {\n    rep_->filter_data = block.data.data();  // Will need to delete later\n  }\n  rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data);\n}\n\nTable::~Table() { delete rep_; }\n\nstatic void DeleteBlock(void* arg, void* ignored) {\n  delete reinterpret_cast<Block*>(arg);\n}\n\nstatic void DeleteCachedBlock(const Slice& key, void* value) {\n  Block* block = reinterpret_cast<Block*>(value);\n  delete block;\n}\n\nstatic void ReleaseBlock(void* arg, void* h) {\n  Cache* cache = reinterpret_cast<Cache*>(arg);\n  Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);\n  cache->Release(handle);\n}\n\n// Convert an index iterator value (i.e., an encoded BlockHandle)\n// into an iterator over the contents of the corresponding block.\nIterator* Table::BlockReader(void* arg, const ReadOptions& options,\n                             const Slice& index_value) {\n  Table* table = reinterpret_cast<Table*>(arg);\n  Cache* block_cache = table->rep_->options.block_cache;\n  Block* block = nullptr;\n  Cache::Handle* cache_handle = nullptr;\n\n  BlockHandle handle;\n  Slice input = index_value;\n  Status s = handle.DecodeFrom(&input);\n  // We intentionally allow extra stuff in index_value so that we\n  // can add more features in the future.\n\n  if (s.ok()) {\n    BlockContents contents;\n    if (block_cache != nullptr) {\n      char cache_key_buffer[16];\n      EncodeFixed64(cache_key_buffer, table->rep_->cache_id);\n      EncodeFixed64(cache_key_buffer + 8, handle.offset());\n      Slice key(cache_key_buffer, sizeof(cache_key_buffer));\n      cache_handle = block_cache->Lookup(key);\n      if (cache_handle != nullptr) {\n        block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));\n      } else {\n        s = ReadBlock(table->rep_->file, options, handle, &contents);\n        if (s.ok()) {\n          block = new Block(contents);\n          if (contents.cachable && options.fill_cache) {\n            cache_handle = block_cache->Insert(key, block, block->size(),\n                                               &DeleteCachedBlock);\n          }\n        }\n      }\n    } else {\n      s = ReadBlock(table->rep_->file, options, handle, &contents);\n      if (s.ok()) {\n        block = new Block(contents);\n      }\n    }\n  }\n\n  Iterator* iter;\n  if (block != nullptr) {\n    iter = block->NewIterator(table->rep_->options.comparator);\n    if (cache_handle == nullptr) {\n      iter->RegisterCleanup(&DeleteBlock, block, nullptr);\n    } else {\n      iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);\n    }\n  } else {\n    iter = NewErrorIterator(s);\n  }\n  return iter;\n}\n\nIterator* Table::NewIterator(const ReadOptions& options) const {\n  return NewTwoLevelIterator(\n      rep_->index_block->NewIterator(rep_->options.comparator),\n      &Table::BlockReader, const_cast<Table*>(this), options);\n}\n\nStatus Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg,\n                          void (*handle_result)(void*, const Slice&,\n                                                const Slice&)) {\n  Status s;\n  Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator);\n  iiter->Seek(k);\n  if (iiter->Valid()) {\n    Slice handle_value = iiter->value();\n    FilterBlockReader* filter = rep_->filter;\n    BlockHandle handle;\n    if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() &&\n        !filter->KeyMayMatch(handle.offset(), k)) {\n      // Not found\n    } else {\n      Iterator* block_iter = BlockReader(this, options, iiter->value());\n      block_iter->Seek(k);\n      if (block_iter->Valid()) {\n        (*handle_result)(arg, block_iter->key(), block_iter->value());\n      }\n      s = block_iter->status();\n      delete block_iter;\n    }\n  }\n  if (s.ok()) {\n    s = iiter->status();\n  }\n  delete iiter;\n  return s;\n}\n\nuint64_t Table::ApproximateOffsetOf(const Slice& key) const {\n  Iterator* index_iter =\n      rep_->index_block->NewIterator(rep_->options.comparator);\n  index_iter->Seek(key);\n  uint64_t result;\n  if (index_iter->Valid()) {\n    BlockHandle handle;\n    Slice input = index_iter->value();\n    Status s = handle.DecodeFrom(&input);\n    if (s.ok()) {\n      result = handle.offset();\n    } else {\n      // Strange: we can't decode the block handle in the index block.\n      // We'll just return the offset of the metaindex block, which is\n      // close to the whole file size for this case.\n      result = rep_->metaindex_handle.offset();\n    }\n  } else {\n    // key is past the last key in the file.  Approximate the offset\n    // by returning the offset of the metaindex block (which is\n    // right near the end of the file).\n    result = rep_->metaindex_handle.offset();\n  }\n  delete index_iter;\n  return result;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/table_builder.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/table_builder.h\"\n\n#include <assert.h>\n\n#include \"leveldb/comparator.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/filter_policy.h\"\n#include \"leveldb/options.h\"\n#include \"table/block_builder.h\"\n#include \"table/filter_block.h\"\n#include \"table/format.h\"\n#include \"util/coding.h\"\n#include \"util/crc32c.h\"\n\nnamespace leveldb {\n\nstruct TableBuilder::Rep {\n  Rep(const Options& opt, WritableFile* f)\n      : options(opt),\n        index_block_options(opt),\n        file(f),\n        offset(0),\n        data_block(&options),\n        index_block(&index_block_options),\n        num_entries(0),\n        closed(false),\n        filter_block(opt.filter_policy == nullptr\n                         ? nullptr\n                         : new FilterBlockBuilder(opt.filter_policy)),\n        pending_index_entry(false) {\n    index_block_options.block_restart_interval = 1;\n  }\n\n  Options options;\n  Options index_block_options;\n  WritableFile* file;\n  uint64_t offset;\n  Status status;\n  BlockBuilder data_block;\n  BlockBuilder index_block;\n  std::string last_key;\n  int64_t num_entries;\n  bool closed;  // Either Finish() or Abandon() has been called.\n  FilterBlockBuilder* filter_block;\n\n  // We do not emit the index entry for a block until we have seen the\n  // first key for the next data block.  This allows us to use shorter\n  // keys in the index block.  For example, consider a block boundary\n  // between the keys \"the quick brown fox\" and \"the who\".  We can use\n  // \"the r\" as the key for the index block entry since it is >= all\n  // entries in the first block and < all entries in subsequent\n  // blocks.\n  //\n  // Invariant: r->pending_index_entry is true only if data_block is empty.\n  bool pending_index_entry;\n  BlockHandle pending_handle;  // Handle to add to index block\n\n  std::string compressed_output;\n};\n\nTableBuilder::TableBuilder(const Options& options, WritableFile* file)\n    : rep_(new Rep(options, file)) {\n  if (rep_->filter_block != nullptr) {\n    rep_->filter_block->StartBlock(0);\n  }\n}\n\nTableBuilder::~TableBuilder() {\n  assert(rep_->closed);  // Catch errors where caller forgot to call Finish()\n  delete rep_->filter_block;\n  delete rep_;\n}\n\nStatus TableBuilder::ChangeOptions(const Options& options) {\n  // Note: if more fields are added to Options, update\n  // this function to catch changes that should not be allowed to\n  // change in the middle of building a Table.\n  if (options.comparator != rep_->options.comparator) {\n    return Status::InvalidArgument(\"changing comparator while building table\");\n  }\n\n  // Note that any live BlockBuilders point to rep_->options and therefore\n  // will automatically pick up the updated options.\n  rep_->options = options;\n  rep_->index_block_options = options;\n  rep_->index_block_options.block_restart_interval = 1;\n  return Status::OK();\n}\n\nvoid TableBuilder::Add(const Slice& key, const Slice& value) {\n  Rep* r = rep_;\n  assert(!r->closed);\n  if (!ok()) return;\n  if (r->num_entries > 0) {\n    assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0);\n  }\n\n  if (r->pending_index_entry) {\n    assert(r->data_block.empty());\n    r->options.comparator->FindShortestSeparator(&r->last_key, key);\n    std::string handle_encoding;\n    r->pending_handle.EncodeTo(&handle_encoding);\n    r->index_block.Add(r->last_key, Slice(handle_encoding));\n    r->pending_index_entry = false;\n  }\n\n  if (r->filter_block != nullptr) {\n    r->filter_block->AddKey(key);\n  }\n\n  r->last_key.assign(key.data(), key.size());\n  r->num_entries++;\n  r->data_block.Add(key, value);\n\n  const size_t estimated_block_size = r->data_block.CurrentSizeEstimate();\n  if (estimated_block_size >= r->options.block_size) {\n    Flush();\n  }\n}\n\nvoid TableBuilder::Flush() {\n  Rep* r = rep_;\n  assert(!r->closed);\n  if (!ok()) return;\n  if (r->data_block.empty()) return;\n  assert(!r->pending_index_entry);\n  WriteBlock(&r->data_block, &r->pending_handle);\n  if (ok()) {\n    r->pending_index_entry = true;\n    r->status = r->file->Flush();\n  }\n  if (r->filter_block != nullptr) {\n    r->filter_block->StartBlock(r->offset);\n  }\n}\n\nvoid TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) {\n  // File format contains a sequence of blocks where each block has:\n  //    block_data: uint8[n]\n  //    type: uint8\n  //    crc: uint32\n  assert(ok());\n  Rep* r = rep_;\n  Slice raw = block->Finish();\n\n  Slice block_contents;\n  CompressionType type = r->options.compression;\n  // TODO(postrelease): Support more compression options: zlib?\n  switch (type) {\n    case kNoCompression:\n      block_contents = raw;\n      break;\n\n    case kSnappyCompression: {\n      std::string* compressed = &r->compressed_output;\n      if (port::Snappy_Compress(raw.data(), raw.size(), compressed) &&\n          compressed->size() < raw.size() - (raw.size() / 8u)) {\n        block_contents = *compressed;\n      } else {\n        // Snappy not supported, or compressed less than 12.5%, so just\n        // store uncompressed form\n        block_contents = raw;\n        type = kNoCompression;\n      }\n      break;\n    }\n  }\n  WriteRawBlock(block_contents, type, handle);\n  r->compressed_output.clear();\n  block->Reset();\n}\n\nvoid TableBuilder::WriteRawBlock(const Slice& block_contents,\n                                 CompressionType type, BlockHandle* handle) {\n  Rep* r = rep_;\n  handle->set_offset(r->offset);\n  handle->set_size(block_contents.size());\n  r->status = r->file->Append(block_contents);\n  if (r->status.ok()) {\n    char trailer[kBlockTrailerSize];\n    trailer[0] = type;\n    uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size());\n    crc = crc32c::Extend(crc, trailer, 1);  // Extend crc to cover block type\n    EncodeFixed32(trailer + 1, crc32c::Mask(crc));\n    r->status = r->file->Append(Slice(trailer, kBlockTrailerSize));\n    if (r->status.ok()) {\n      r->offset += block_contents.size() + kBlockTrailerSize;\n    }\n  }\n}\n\nStatus TableBuilder::status() const { return rep_->status; }\n\nStatus TableBuilder::Finish() {\n  Rep* r = rep_;\n  Flush();\n  assert(!r->closed);\n  r->closed = true;\n\n  BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle;\n\n  // Write filter block\n  if (ok() && r->filter_block != nullptr) {\n    WriteRawBlock(r->filter_block->Finish(), kNoCompression,\n                  &filter_block_handle);\n  }\n\n  // Write metaindex block\n  if (ok()) {\n    BlockBuilder meta_index_block(&r->options);\n    if (r->filter_block != nullptr) {\n      // Add mapping from \"filter.Name\" to location of filter data\n      std::string key = \"filter.\";\n      key.append(r->options.filter_policy->Name());\n      std::string handle_encoding;\n      filter_block_handle.EncodeTo(&handle_encoding);\n      meta_index_block.Add(key, handle_encoding);\n    }\n\n    // TODO(postrelease): Add stats and other meta blocks\n    WriteBlock(&meta_index_block, &metaindex_block_handle);\n  }\n\n  // Write index block\n  if (ok()) {\n    if (r->pending_index_entry) {\n      r->options.comparator->FindShortSuccessor(&r->last_key);\n      std::string handle_encoding;\n      r->pending_handle.EncodeTo(&handle_encoding);\n      r->index_block.Add(r->last_key, Slice(handle_encoding));\n      r->pending_index_entry = false;\n    }\n    WriteBlock(&r->index_block, &index_block_handle);\n  }\n\n  // Write footer\n  if (ok()) {\n    Footer footer;\n    footer.set_metaindex_handle(metaindex_block_handle);\n    footer.set_index_handle(index_block_handle);\n    std::string footer_encoding;\n    footer.EncodeTo(&footer_encoding);\n    r->status = r->file->Append(footer_encoding);\n    if (r->status.ok()) {\n      r->offset += footer_encoding.size();\n    }\n  }\n  return r->status;\n}\n\nvoid TableBuilder::Abandon() {\n  Rep* r = rep_;\n  assert(!r->closed);\n  r->closed = true;\n}\n\nuint64_t TableBuilder::NumEntries() const { return rep_->num_entries; }\n\nuint64_t TableBuilder::FileSize() const { return rep_->offset; }\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/table_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/table.h\"\n\n#include <map>\n#include <string>\n\n#include \"db/dbformat.h\"\n#include \"db/memtable.h\"\n#include \"db/write_batch_internal.h\"\n#include \"leveldb/db.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/iterator.h\"\n#include \"leveldb/table_builder.h\"\n#include \"table/block.h\"\n#include \"table/block_builder.h\"\n#include \"table/format.h\"\n#include \"util/random.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\n// Return reverse of \"key\".\n// Used to test non-lexicographic comparators.\nstatic std::string Reverse(const Slice& key) {\n  std::string str(key.ToString());\n  std::string rev(\"\");\n  for (std::string::reverse_iterator rit = str.rbegin(); rit != str.rend();\n       ++rit) {\n    rev.push_back(*rit);\n  }\n  return rev;\n}\n\nnamespace {\nclass ReverseKeyComparator : public Comparator {\n public:\n  const char* Name() const override {\n    return \"leveldb.ReverseBytewiseComparator\";\n  }\n\n  int Compare(const Slice& a, const Slice& b) const override {\n    return BytewiseComparator()->Compare(Reverse(a), Reverse(b));\n  }\n\n  void FindShortestSeparator(std::string* start,\n                             const Slice& limit) const override {\n    std::string s = Reverse(*start);\n    std::string l = Reverse(limit);\n    BytewiseComparator()->FindShortestSeparator(&s, l);\n    *start = Reverse(s);\n  }\n\n  void FindShortSuccessor(std::string* key) const override {\n    std::string s = Reverse(*key);\n    BytewiseComparator()->FindShortSuccessor(&s);\n    *key = Reverse(s);\n  }\n};\n}  // namespace\nstatic ReverseKeyComparator reverse_key_comparator;\n\nstatic void Increment(const Comparator* cmp, std::string* key) {\n  if (cmp == BytewiseComparator()) {\n    key->push_back('\\0');\n  } else {\n    assert(cmp == &reverse_key_comparator);\n    std::string rev = Reverse(*key);\n    rev.push_back('\\0');\n    *key = Reverse(rev);\n  }\n}\n\n// An STL comparator that uses a Comparator\nnamespace {\nstruct STLLessThan {\n  const Comparator* cmp;\n\n  STLLessThan() : cmp(BytewiseComparator()) {}\n  STLLessThan(const Comparator* c) : cmp(c) {}\n  bool operator()(const std::string& a, const std::string& b) const {\n    return cmp->Compare(Slice(a), Slice(b)) < 0;\n  }\n};\n}  // namespace\n\nclass StringSink : public WritableFile {\n public:\n  ~StringSink() override = default;\n\n  const std::string& contents() const { return contents_; }\n\n  Status Close() override { return Status::OK(); }\n  Status Flush() override { return Status::OK(); }\n  Status Sync() override { return Status::OK(); }\n\n  Status Append(const Slice& data) override {\n    contents_.append(data.data(), data.size());\n    return Status::OK();\n  }\n\n  std::string GetName() const override { return \"\"; }\n private:\n  std::string contents_;\n};\n\nclass StringSource : public RandomAccessFile {\n public:\n  StringSource(const Slice& contents)\n      : contents_(contents.data(), contents.size()) {}\n\n  ~StringSource() override = default;\n\n  uint64_t Size() const { return contents_.size(); }\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    if (offset >= contents_.size()) {\n      return Status::InvalidArgument(\"invalid Read offset\");\n    }\n    if (offset + n > contents_.size()) {\n      n = contents_.size() - offset;\n    }\n    memcpy(scratch, &contents_[offset], n);\n    *result = Slice(scratch, n);\n    return Status::OK();\n  }\n\n  std::string GetName() const { return \"\"; }\n private:\n  std::string contents_;\n};\n\ntypedef std::map<std::string, std::string, STLLessThan> KVMap;\n\n// Helper class for tests to unify the interface between\n// BlockBuilder/TableBuilder and Block/Table.\nclass Constructor {\n public:\n  explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) {}\n  virtual ~Constructor() = default;\n\n  void Add(const std::string& key, const Slice& value) {\n    data_[key] = value.ToString();\n  }\n\n  // Finish constructing the data structure with all the keys that have\n  // been added so far.  Returns the keys in sorted order in \"*keys\"\n  // and stores the key/value pairs in \"*kvmap\"\n  void Finish(const Options& options, std::vector<std::string>* keys,\n              KVMap* kvmap) {\n    *kvmap = data_;\n    keys->clear();\n    for (const auto& kvp : data_) {\n      keys->push_back(kvp.first);\n    }\n    data_.clear();\n    Status s = FinishImpl(options, *kvmap);\n    ASSERT_TRUE(s.ok()) << s.ToString();\n  }\n\n  // Construct the data structure from the data in \"data\"\n  virtual Status FinishImpl(const Options& options, const KVMap& data) = 0;\n\n  virtual Iterator* NewIterator() const = 0;\n\n  const KVMap& data() const { return data_; }\n\n  virtual DB* db() const { return nullptr; }  // Overridden in DBConstructor\n\n private:\n  KVMap data_;\n};\n\nclass BlockConstructor : public Constructor {\n public:\n  explicit BlockConstructor(const Comparator* cmp)\n      : Constructor(cmp), comparator_(cmp), block_(nullptr) {}\n  ~BlockConstructor() override { delete block_; }\n  Status FinishImpl(const Options& options, const KVMap& data) override {\n    delete block_;\n    block_ = nullptr;\n    BlockBuilder builder(&options);\n\n    for (const auto& kvp : data) {\n      builder.Add(kvp.first, kvp.second);\n    }\n    // Open the block\n    data_ = builder.Finish().ToString();\n    BlockContents contents;\n    contents.data = data_;\n    contents.cachable = false;\n    contents.heap_allocated = false;\n    block_ = new Block(contents);\n    return Status::OK();\n  }\n  Iterator* NewIterator() const override {\n    return block_->NewIterator(comparator_);\n  }\n\n private:\n  const Comparator* const comparator_;\n  std::string data_;\n  Block* block_;\n\n  BlockConstructor();\n};\n\nclass TableConstructor : public Constructor {\n public:\n  TableConstructor(const Comparator* cmp)\n      : Constructor(cmp), source_(nullptr), table_(nullptr) {}\n  ~TableConstructor() override { Reset(); }\n  Status FinishImpl(const Options& options, const KVMap& data) override {\n    Reset();\n    StringSink sink;\n    TableBuilder builder(options, &sink);\n\n    for (const auto& kvp : data) {\n      builder.Add(kvp.first, kvp.second);\n      ASSERT_TRUE(builder.status().ok());\n    }\n    Status s = builder.Finish();\n    ASSERT_TRUE(s.ok()) << s.ToString();\n\n    ASSERT_EQ(sink.contents().size(), builder.FileSize());\n\n    // Open the table\n    source_ = new StringSource(sink.contents());\n    Options table_options;\n    table_options.comparator = options.comparator;\n    return Table::Open(table_options, source_, sink.contents().size(), &table_);\n  }\n\n  Iterator* NewIterator() const override {\n    return table_->NewIterator(ReadOptions());\n  }\n\n  uint64_t ApproximateOffsetOf(const Slice& key) const {\n    return table_->ApproximateOffsetOf(key);\n  }\n\n private:\n  void Reset() {\n    delete table_;\n    delete source_;\n    table_ = nullptr;\n    source_ = nullptr;\n  }\n\n  StringSource* source_;\n  Table* table_;\n\n  TableConstructor();\n};\n\n// A helper class that converts internal format keys into user keys\nclass KeyConvertingIterator : public Iterator {\n public:\n  explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) {}\n\n  KeyConvertingIterator(const KeyConvertingIterator&) = delete;\n  KeyConvertingIterator& operator=(const KeyConvertingIterator&) = delete;\n\n  ~KeyConvertingIterator() override { delete iter_; }\n\n  bool Valid() const override { return iter_->Valid(); }\n  void Seek(const Slice& target) override {\n    ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue);\n    std::string encoded;\n    AppendInternalKey(&encoded, ikey);\n    iter_->Seek(encoded);\n  }\n  void SeekToFirst() override { iter_->SeekToFirst(); }\n  void SeekToLast() override { iter_->SeekToLast(); }\n  void Next() override { iter_->Next(); }\n  void Prev() override { iter_->Prev(); }\n\n  Slice key() const override {\n    assert(Valid());\n    ParsedInternalKey key;\n    if (!ParseInternalKey(iter_->key(), &key)) {\n      status_ = Status::Corruption(\"malformed internal key\");\n      return Slice(\"corrupted key\");\n    }\n    return key.user_key;\n  }\n\n  Slice value() const override { return iter_->value(); }\n  Status status() const override {\n    return status_.ok() ? iter_->status() : status_;\n  }\n\n private:\n  mutable Status status_;\n  Iterator* iter_;\n};\n\nclass MemTableConstructor : public Constructor {\n public:\n  explicit MemTableConstructor(const Comparator* cmp)\n      : Constructor(cmp), internal_comparator_(cmp) {\n    memtable_ = new MemTable(internal_comparator_);\n    memtable_->Ref();\n  }\n  ~MemTableConstructor() override { memtable_->Unref(); }\n  Status FinishImpl(const Options& options, const KVMap& data) override {\n    memtable_->Unref();\n    memtable_ = new MemTable(internal_comparator_);\n    memtable_->Ref();\n    int seq = 1;\n    for (const auto& kvp : data) {\n      memtable_->Add(seq, kTypeValue, kvp.first, kvp.second);\n      seq++;\n    }\n    return Status::OK();\n  }\n  Iterator* NewIterator() const override {\n    return new KeyConvertingIterator(memtable_->NewIterator());\n  }\n\n private:\n  const InternalKeyComparator internal_comparator_;\n  MemTable* memtable_;\n};\n\nclass DBConstructor : public Constructor {\n public:\n  explicit DBConstructor(const Comparator* cmp)\n      : Constructor(cmp), comparator_(cmp) {\n    db_ = nullptr;\n    NewDB();\n  }\n  ~DBConstructor() override { delete db_; }\n  Status FinishImpl(const Options& options, const KVMap& data) override {\n    delete db_;\n    db_ = nullptr;\n    NewDB();\n    for (const auto& kvp : data) {\n      WriteBatch batch;\n      batch.Put(kvp.first, kvp.second);\n      ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok());\n    }\n    return Status::OK();\n  }\n  Iterator* NewIterator() const override {\n    return db_->NewIterator(ReadOptions());\n  }\n\n  DB* db() const override { return db_; }\n\n private:\n  void NewDB() {\n    std::string name = test::TmpDir() + \"/table_testdb\";\n\n    Options options;\n    options.comparator = comparator_;\n    Status status = DestroyDB(name, options);\n    ASSERT_TRUE(status.ok()) << status.ToString();\n\n    options.create_if_missing = true;\n    options.error_if_exists = true;\n    options.write_buffer_size = 10000;  // Something small to force merging\n    status = DB::Open(options, name, &db_);\n    ASSERT_TRUE(status.ok()) << status.ToString();\n  }\n\n  const Comparator* const comparator_;\n  DB* db_;\n};\n\nenum TestType { TABLE_TEST, BLOCK_TEST, MEMTABLE_TEST, DB_TEST };\n\nstruct TestArgs {\n  TestType type;\n  bool reverse_compare;\n  int restart_interval;\n};\n\nstatic const TestArgs kTestArgList[] = {\n    {TABLE_TEST, false, 16},\n    {TABLE_TEST, false, 1},\n    {TABLE_TEST, false, 1024},\n    {TABLE_TEST, true, 16},\n    {TABLE_TEST, true, 1},\n    {TABLE_TEST, true, 1024},\n\n    {BLOCK_TEST, false, 16},\n    {BLOCK_TEST, false, 1},\n    {BLOCK_TEST, false, 1024},\n    {BLOCK_TEST, true, 16},\n    {BLOCK_TEST, true, 1},\n    {BLOCK_TEST, true, 1024},\n\n    // Restart interval does not matter for memtables\n    {MEMTABLE_TEST, false, 16},\n    {MEMTABLE_TEST, true, 16},\n\n    // Do not bother with restart interval variations for DB\n    {DB_TEST, false, 16},\n    {DB_TEST, true, 16},\n};\nstatic const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]);\n\nclass Harness {\n public:\n  Harness() : constructor_(nullptr) {}\n\n  void Init(const TestArgs& args) {\n    delete constructor_;\n    constructor_ = nullptr;\n    options_ = Options();\n\n    options_.block_restart_interval = args.restart_interval;\n    // Use shorter block size for tests to exercise block boundary\n    // conditions more.\n    options_.block_size = 256;\n    if (args.reverse_compare) {\n      options_.comparator = &reverse_key_comparator;\n    }\n    switch (args.type) {\n      case TABLE_TEST:\n        constructor_ = new TableConstructor(options_.comparator);\n        break;\n      case BLOCK_TEST:\n        constructor_ = new BlockConstructor(options_.comparator);\n        break;\n      case MEMTABLE_TEST:\n        constructor_ = new MemTableConstructor(options_.comparator);\n        break;\n      case DB_TEST:\n        constructor_ = new DBConstructor(options_.comparator);\n        break;\n    }\n  }\n\n  ~Harness() { delete constructor_; }\n\n  void Add(const std::string& key, const std::string& value) {\n    constructor_->Add(key, value);\n  }\n\n  void Test(Random* rnd) {\n    std::vector<std::string> keys;\n    KVMap data;\n    constructor_->Finish(options_, &keys, &data);\n\n    TestForwardScan(keys, data);\n    TestBackwardScan(keys, data);\n    TestRandomAccess(rnd, keys, data);\n  }\n\n  void TestForwardScan(const std::vector<std::string>& keys,\n                       const KVMap& data) {\n    Iterator* iter = constructor_->NewIterator();\n    ASSERT_TRUE(!iter->Valid());\n    iter->SeekToFirst();\n    for (KVMap::const_iterator model_iter = data.begin();\n         model_iter != data.end(); ++model_iter) {\n      ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n      iter->Next();\n    }\n    ASSERT_TRUE(!iter->Valid());\n    delete iter;\n  }\n\n  void TestBackwardScan(const std::vector<std::string>& keys,\n                        const KVMap& data) {\n    Iterator* iter = constructor_->NewIterator();\n    ASSERT_TRUE(!iter->Valid());\n    iter->SeekToLast();\n    for (KVMap::const_reverse_iterator model_iter = data.rbegin();\n         model_iter != data.rend(); ++model_iter) {\n      ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n      iter->Prev();\n    }\n    ASSERT_TRUE(!iter->Valid());\n    delete iter;\n  }\n\n  void TestRandomAccess(Random* rnd, const std::vector<std::string>& keys,\n                        const KVMap& data) {\n    static const bool kVerbose = false;\n    Iterator* iter = constructor_->NewIterator();\n    ASSERT_TRUE(!iter->Valid());\n    KVMap::const_iterator model_iter = data.begin();\n    if (kVerbose) fprintf(stderr, \"---\\n\");\n    for (int i = 0; i < 200; i++) {\n      const int toss = rnd->Uniform(5);\n      switch (toss) {\n        case 0: {\n          if (iter->Valid()) {\n            if (kVerbose) fprintf(stderr, \"Next\\n\");\n            iter->Next();\n            ++model_iter;\n            ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n          }\n          break;\n        }\n\n        case 1: {\n          if (kVerbose) fprintf(stderr, \"SeekToFirst\\n\");\n          iter->SeekToFirst();\n          model_iter = data.begin();\n          ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n          break;\n        }\n\n        case 2: {\n          std::string key = PickRandomKey(rnd, keys);\n          model_iter = data.lower_bound(key);\n          if (kVerbose)\n            fprintf(stderr, \"Seek '%s'\\n\", EscapeString(key).c_str());\n          iter->Seek(Slice(key));\n          ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n          break;\n        }\n\n        case 3: {\n          if (iter->Valid()) {\n            if (kVerbose) fprintf(stderr, \"Prev\\n\");\n            iter->Prev();\n            if (model_iter == data.begin()) {\n              model_iter = data.end();  // Wrap around to invalid value\n            } else {\n              --model_iter;\n            }\n            ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n          }\n          break;\n        }\n\n        case 4: {\n          if (kVerbose) fprintf(stderr, \"SeekToLast\\n\");\n          iter->SeekToLast();\n          if (keys.empty()) {\n            model_iter = data.end();\n          } else {\n            std::string last = data.rbegin()->first;\n            model_iter = data.lower_bound(last);\n          }\n          ASSERT_EQ(ToString(data, model_iter), ToString(iter));\n          break;\n        }\n      }\n    }\n    delete iter;\n  }\n\n  std::string ToString(const KVMap& data, const KVMap::const_iterator& it) {\n    if (it == data.end()) {\n      return \"END\";\n    } else {\n      return \"'\" + it->first + \"->\" + it->second + \"'\";\n    }\n  }\n\n  std::string ToString(const KVMap& data,\n                       const KVMap::const_reverse_iterator& it) {\n    if (it == data.rend()) {\n      return \"END\";\n    } else {\n      return \"'\" + it->first + \"->\" + it->second + \"'\";\n    }\n  }\n\n  std::string ToString(const Iterator* it) {\n    if (!it->Valid()) {\n      return \"END\";\n    } else {\n      return \"'\" + it->key().ToString() + \"->\" + it->value().ToString() + \"'\";\n    }\n  }\n\n  std::string PickRandomKey(Random* rnd, const std::vector<std::string>& keys) {\n    if (keys.empty()) {\n      return \"foo\";\n    } else {\n      const int index = rnd->Uniform(keys.size());\n      std::string result = keys[index];\n      switch (rnd->Uniform(3)) {\n        case 0:\n          // Return an existing key\n          break;\n        case 1: {\n          // Attempt to return something smaller than an existing key\n          if (!result.empty() && result[result.size() - 1] > '\\0') {\n            result[result.size() - 1]--;\n          }\n          break;\n        }\n        case 2: {\n          // Return something larger than an existing key\n          Increment(options_.comparator, &result);\n          break;\n        }\n      }\n      return result;\n    }\n  }\n\n  // Returns nullptr if not running against a DB\n  DB* db() const { return constructor_->db(); }\n\n private:\n  Options options_;\n  Constructor* constructor_;\n};\n\n// Test empty table/block.\nTEST(Harness, Empty) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 1);\n    Test(&rnd);\n  }\n}\n\n// Special test for a block with no restart entries.  The C++ leveldb\n// code never generates such blocks, but the Java version of leveldb\n// seems to.\nTEST(Harness, ZeroRestartPointsInBlock) {\n  char data[sizeof(uint32_t)];\n  memset(data, 0, sizeof(data));\n  BlockContents contents;\n  contents.data = Slice(data, sizeof(data));\n  contents.cachable = false;\n  contents.heap_allocated = false;\n  Block block(contents);\n  Iterator* iter = block.NewIterator(BytewiseComparator());\n  iter->SeekToFirst();\n  ASSERT_TRUE(!iter->Valid());\n  iter->SeekToLast();\n  ASSERT_TRUE(!iter->Valid());\n  iter->Seek(\"foo\");\n  ASSERT_TRUE(!iter->Valid());\n  delete iter;\n}\n\n// Test the empty key\nTEST(Harness, SimpleEmptyKey) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 1);\n    Add(\"\", \"v\");\n    Test(&rnd);\n  }\n}\n\nTEST(Harness, SimpleSingle) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 2);\n    Add(\"abc\", \"v\");\n    Test(&rnd);\n  }\n}\n\nTEST(Harness, SimpleMulti) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 3);\n    Add(\"abc\", \"v\");\n    Add(\"abcd\", \"v\");\n    Add(\"ac\", \"v2\");\n    Test(&rnd);\n  }\n}\n\nTEST(Harness, SimpleSpecialKey) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 4);\n    Add(\"\\xff\\xff\", \"v3\");\n    Test(&rnd);\n  }\n}\n\nTEST(Harness, Randomized) {\n  for (int i = 0; i < kNumTestArgs; i++) {\n    Init(kTestArgList[i]);\n    Random rnd(test::RandomSeed() + 5);\n    for (int num_entries = 0; num_entries < 2000;\n         num_entries += (num_entries < 50 ? 1 : 200)) {\n      if ((num_entries % 10) == 0) {\n        fprintf(stderr, \"case %d of %d: num_entries = %d\\n\", (i + 1),\n                int(kNumTestArgs), num_entries);\n      }\n      for (int e = 0; e < num_entries; e++) {\n        std::string v;\n        Add(test::RandomKey(&rnd, rnd.Skewed(4)),\n            test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());\n      }\n      Test(&rnd);\n    }\n  }\n}\n\nTEST(Harness, RandomizedLongDB) {\n  Random rnd(test::RandomSeed());\n  TestArgs args = {DB_TEST, false, 16};\n  Init(args);\n  int num_entries = 100000;\n  for (int e = 0; e < num_entries; e++) {\n    std::string v;\n    Add(test::RandomKey(&rnd, rnd.Skewed(4)),\n        test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());\n  }\n  Test(&rnd);\n\n  // We must have created enough data to force merging\n  int files = 0;\n  for (int level = 0; level < config::kNumLevels; level++) {\n    std::string value;\n    char name[100];\n    snprintf(name, sizeof(name), \"leveldb.num-files-at-level%d\", level);\n    ASSERT_TRUE(db()->GetProperty(name, &value));\n    files += atoi(value.c_str());\n  }\n  ASSERT_GT(files, 0);\n}\n\nclass MemTableTest {};\n\nTEST(MemTableTest, Simple) {\n  InternalKeyComparator cmp(BytewiseComparator());\n  MemTable* memtable = new MemTable(cmp);\n  memtable->Ref();\n  WriteBatch batch;\n  WriteBatchInternal::SetSequence(&batch, 100);\n  batch.Put(std::string(\"k1\"), std::string(\"v1\"));\n  batch.Put(std::string(\"k2\"), std::string(\"v2\"));\n  batch.Put(std::string(\"k3\"), std::string(\"v3\"));\n  batch.Put(std::string(\"largekey\"), std::string(\"vlarge\"));\n  ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok());\n\n  Iterator* iter = memtable->NewIterator();\n  iter->SeekToFirst();\n  while (iter->Valid()) {\n    fprintf(stderr, \"key: '%s' -> '%s'\\n\", iter->key().ToString().c_str(),\n            iter->value().ToString().c_str());\n    iter->Next();\n  }\n\n  delete iter;\n  memtable->Unref();\n}\n\nstatic bool Between(uint64_t val, uint64_t low, uint64_t high) {\n  bool result = (val >= low) && (val <= high);\n  if (!result) {\n    fprintf(stderr, \"Value %llu is not in range [%llu, %llu]\\n\",\n            (unsigned long long)(val), (unsigned long long)(low),\n            (unsigned long long)(high));\n  }\n  return result;\n}\n\nclass TableTest {};\n\nTEST(TableTest, ApproximateOffsetOfPlain) {\n  TableConstructor c(BytewiseComparator());\n  c.Add(\"k01\", \"hello\");\n  c.Add(\"k02\", \"hello2\");\n  c.Add(\"k03\", std::string(10000, 'x'));\n  c.Add(\"k04\", std::string(200000, 'x'));\n  c.Add(\"k05\", std::string(300000, 'x'));\n  c.Add(\"k06\", \"hello3\");\n  c.Add(\"k07\", std::string(100000, 'x'));\n  std::vector<std::string> keys;\n  KVMap kvmap;\n  Options options;\n  options.block_size = 1024;\n  options.compression = kNoCompression;\n  c.Finish(options, &keys, &kvmap);\n\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"abc\"), 0, 0));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k01\"), 0, 0));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k01a\"), 0, 0));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k02\"), 0, 0));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k03\"), 0, 0));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k04\"), 10000, 11000));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k04a\"), 210000, 211000));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k05\"), 210000, 211000));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k06\"), 510000, 511000));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k07\"), 510000, 511000));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"xyz\"), 610000, 612000));\n}\n\nstatic bool SnappyCompressionSupported() {\n  std::string out;\n  Slice in = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";\n  return port::Snappy_Compress(in.data(), in.size(), &out);\n}\n\nTEST(TableTest, ApproximateOffsetOfCompressed) {\n  if (!SnappyCompressionSupported()) {\n    fprintf(stderr, \"skipping compression tests\\n\");\n    return;\n  }\n\n  Random rnd(301);\n  TableConstructor c(BytewiseComparator());\n  std::string tmp;\n  c.Add(\"k01\", \"hello\");\n  c.Add(\"k02\", test::CompressibleString(&rnd, 0.25, 10000, &tmp));\n  c.Add(\"k03\", \"hello3\");\n  c.Add(\"k04\", test::CompressibleString(&rnd, 0.25, 10000, &tmp));\n  std::vector<std::string> keys;\n  KVMap kvmap;\n  Options options;\n  options.block_size = 1024;\n  options.compression = kSnappyCompression;\n  c.Finish(options, &keys, &kvmap);\n\n  // Expected upper and lower bounds of space used by compressible strings.\n  static const int kSlop = 1000;  // Compressor effectiveness varies.\n  const int expected = 2500;      // 10000 * compression ratio (0.25)\n  const int min_z = expected - kSlop;\n  const int max_z = expected + kSlop;\n\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"abc\"), 0, kSlop));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k01\"), 0, kSlop));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k02\"), 0, kSlop));\n  // Have now emitted a large compressible string, so adjust expected offset.\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k03\"), min_z, max_z));\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"k04\"), min_z, max_z));\n  // Have now emitted two large compressible strings, so adjust expected offset.\n  ASSERT_TRUE(Between(c.ApproximateOffsetOf(\"xyz\"), 2 * min_z, 2 * max_z));\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/table/two_level_iterator.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"table/two_level_iterator.h\"\n\n#include \"leveldb/table.h\"\n#include \"table/block.h\"\n#include \"table/format.h\"\n#include \"table/iterator_wrapper.h\"\n\nnamespace leveldb {\n\nnamespace {\n\ntypedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);\n\nclass TwoLevelIterator : public Iterator {\n public:\n  TwoLevelIterator(Iterator* index_iter, BlockFunction block_function,\n                   void* arg, const ReadOptions& options);\n\n  ~TwoLevelIterator() override;\n\n  void Seek(const Slice& target) override;\n  void SeekToFirst() override;\n  void SeekToLast() override;\n  void Next() override;\n  void Prev() override;\n\n  bool Valid() const override { return data_iter_.Valid(); }\n  Slice key() const override {\n    assert(Valid());\n    return data_iter_.key();\n  }\n  Slice value() const override {\n    assert(Valid());\n    return data_iter_.value();\n  }\n  Status status() const override {\n    // It'd be nice if status() returned a const Status& instead of a Status\n    if (!index_iter_.status().ok()) {\n      return index_iter_.status();\n    } else if (data_iter_.iter() != nullptr && !data_iter_.status().ok()) {\n      return data_iter_.status();\n    } else {\n      return status_;\n    }\n  }\n\n private:\n  void SaveError(const Status& s) {\n    if (status_.ok() && !s.ok()) status_ = s;\n  }\n  void SkipEmptyDataBlocksForward();\n  void SkipEmptyDataBlocksBackward();\n  void SetDataIterator(Iterator* data_iter);\n  void InitDataBlock();\n\n  BlockFunction block_function_;\n  void* arg_;\n  const ReadOptions options_;\n  Status status_;\n  IteratorWrapper index_iter_;\n  IteratorWrapper data_iter_;  // May be nullptr\n  // If data_iter_ is non-null, then \"data_block_handle_\" holds the\n  // \"index_value\" passed to block_function_ to create the data_iter_.\n  std::string data_block_handle_;\n};\n\nTwoLevelIterator::TwoLevelIterator(Iterator* index_iter,\n                                   BlockFunction block_function, void* arg,\n                                   const ReadOptions& options)\n    : block_function_(block_function),\n      arg_(arg),\n      options_(options),\n      index_iter_(index_iter),\n      data_iter_(nullptr) {}\n\nTwoLevelIterator::~TwoLevelIterator() = default;\n\nvoid TwoLevelIterator::Seek(const Slice& target) {\n  index_iter_.Seek(target);\n  InitDataBlock();\n  if (data_iter_.iter() != nullptr) data_iter_.Seek(target);\n  SkipEmptyDataBlocksForward();\n}\n\nvoid TwoLevelIterator::SeekToFirst() {\n  index_iter_.SeekToFirst();\n  InitDataBlock();\n  if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst();\n  SkipEmptyDataBlocksForward();\n}\n\nvoid TwoLevelIterator::SeekToLast() {\n  index_iter_.SeekToLast();\n  InitDataBlock();\n  if (data_iter_.iter() != nullptr) data_iter_.SeekToLast();\n  SkipEmptyDataBlocksBackward();\n}\n\nvoid TwoLevelIterator::Next() {\n  assert(Valid());\n  data_iter_.Next();\n  SkipEmptyDataBlocksForward();\n}\n\nvoid TwoLevelIterator::Prev() {\n  assert(Valid());\n  data_iter_.Prev();\n  SkipEmptyDataBlocksBackward();\n}\n\nvoid TwoLevelIterator::SkipEmptyDataBlocksForward() {\n  while (data_iter_.iter() == nullptr || !data_iter_.Valid()) {\n    // Move to next block\n    if (!index_iter_.Valid()) {\n      SetDataIterator(nullptr);\n      return;\n    }\n    index_iter_.Next();\n    InitDataBlock();\n    if (data_iter_.iter() != nullptr) data_iter_.SeekToFirst();\n  }\n}\n\nvoid TwoLevelIterator::SkipEmptyDataBlocksBackward() {\n  while (data_iter_.iter() == nullptr || !data_iter_.Valid()) {\n    // Move to next block\n    if (!index_iter_.Valid()) {\n      SetDataIterator(nullptr);\n      return;\n    }\n    index_iter_.Prev();\n    InitDataBlock();\n    if (data_iter_.iter() != nullptr) data_iter_.SeekToLast();\n  }\n}\n\nvoid TwoLevelIterator::SetDataIterator(Iterator* data_iter) {\n  if (data_iter_.iter() != nullptr) SaveError(data_iter_.status());\n  data_iter_.Set(data_iter);\n}\n\nvoid TwoLevelIterator::InitDataBlock() {\n  if (!index_iter_.Valid()) {\n    SetDataIterator(nullptr);\n  } else {\n    Slice handle = index_iter_.value();\n    if (data_iter_.iter() != nullptr &&\n        handle.compare(data_block_handle_) == 0) {\n      // data_iter_ is already constructed with this iterator, so\n      // no need to change anything\n    } else {\n      Iterator* iter = (*block_function_)(arg_, options_, handle);\n      data_block_handle_.assign(handle.data(), handle.size());\n      SetDataIterator(iter);\n    }\n  }\n}\n\n}  // namespace\n\nIterator* NewTwoLevelIterator(Iterator* index_iter,\n                              BlockFunction block_function, void* arg,\n                              const ReadOptions& options) {\n  return new TwoLevelIterator(index_iter, block_function, arg, options);\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/table/two_level_iterator.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_\n#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_\n\n#include \"leveldb/iterator.h\"\n\nnamespace leveldb {\n\nstruct ReadOptions;\n\n// Return a new two level iterator.  A two-level iterator contains an\n// index iterator whose values point to a sequence of blocks where\n// each block is itself a sequence of key,value pairs.  The returned\n// two-level iterator yields the concatenation of all key/value pairs\n// in the sequence of blocks.  Takes ownership of \"index_iter\" and\n// will delete it when no longer needed.\n//\n// Uses a supplied function to convert an index_iter value into\n// an iterator over the contents of the corresponding block.\nIterator* NewTwoLevelIterator(\n    Iterator* index_iter,\n    Iterator* (*block_function)(void* arg, const ReadOptions& options,\n                                const Slice& index_value),\n    void* arg, const ReadOptions& options);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_\n"
  },
  {
    "path": "src/leveldb/util/arena.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/arena.h\"\n\nnamespace leveldb {\n\nstatic const int kBlockSize = 4096;\n\nArena::Arena()\n    : alloc_ptr_(nullptr), alloc_bytes_remaining_(0), memory_usage_(0) {}\n\nArena::~Arena() {\n  for (size_t i = 0; i < blocks_.size(); i++) {\n    delete[] blocks_[i];\n  }\n}\n\nchar* Arena::AllocateFallback(size_t bytes) {\n  if (bytes > kBlockSize / 4) {\n    // Object is more than a quarter of our block size.  Allocate it separately\n    // to avoid wasting too much space in leftover bytes.\n    char* result = AllocateNewBlock(bytes);\n    return result;\n  }\n\n  // We waste the remaining space in the current block.\n  alloc_ptr_ = AllocateNewBlock(kBlockSize);\n  alloc_bytes_remaining_ = kBlockSize;\n\n  char* result = alloc_ptr_;\n  alloc_ptr_ += bytes;\n  alloc_bytes_remaining_ -= bytes;\n  return result;\n}\n\nchar* Arena::AllocateAligned(size_t bytes) {\n  const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8;\n  static_assert((align & (align - 1)) == 0,\n                \"Pointer size should be a power of 2\");\n  size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align - 1);\n  size_t slop = (current_mod == 0 ? 0 : align - current_mod);\n  size_t needed = bytes + slop;\n  char* result;\n  if (needed <= alloc_bytes_remaining_) {\n    result = alloc_ptr_ + slop;\n    alloc_ptr_ += needed;\n    alloc_bytes_remaining_ -= needed;\n  } else {\n    // AllocateFallback always returned aligned memory\n    result = AllocateFallback(bytes);\n  }\n  assert((reinterpret_cast<uintptr_t>(result) & (align - 1)) == 0);\n  return result;\n}\n\nchar* Arena::AllocateNewBlock(size_t block_bytes) {\n  char* result = new char[block_bytes];\n  blocks_.push_back(result);\n  memory_usage_.fetch_add(block_bytes + sizeof(char*),\n                          std::memory_order_relaxed);\n  return result;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/arena.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_\n#define STORAGE_LEVELDB_UTIL_ARENA_H_\n\n#include <atomic>\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\nnamespace leveldb {\n\nclass Arena {\n public:\n  Arena();\n\n  Arena(const Arena&) = delete;\n  Arena& operator=(const Arena&) = delete;\n\n  ~Arena();\n\n  // Return a pointer to a newly allocated memory block of \"bytes\" bytes.\n  char* Allocate(size_t bytes);\n\n  // Allocate memory with the normal alignment guarantees provided by malloc.\n  char* AllocateAligned(size_t bytes);\n\n  // Returns an estimate of the total memory usage of data allocated\n  // by the arena.\n  size_t MemoryUsage() const {\n    return memory_usage_.load(std::memory_order_relaxed);\n  }\n\n private:\n  char* AllocateFallback(size_t bytes);\n  char* AllocateNewBlock(size_t block_bytes);\n\n  // Allocation state\n  char* alloc_ptr_;\n  size_t alloc_bytes_remaining_;\n\n  // Array of new[] allocated memory blocks\n  std::vector<char*> blocks_;\n\n  // Total memory usage of the arena.\n  //\n  // TODO(costan): This member is accessed via atomics, but the others are\n  //               accessed without any locking. Is this OK?\n  std::atomic<size_t> memory_usage_;\n};\n\ninline char* Arena::Allocate(size_t bytes) {\n  // The semantics of what to return are a bit messy if we allow\n  // 0-byte allocations, so we disallow them here (we don't need\n  // them for our internal use).\n  assert(bytes > 0);\n  if (bytes <= alloc_bytes_remaining_) {\n    char* result = alloc_ptr_;\n    alloc_ptr_ += bytes;\n    alloc_bytes_remaining_ -= bytes;\n    return result;\n  }\n  return AllocateFallback(bytes);\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_ARENA_H_\n"
  },
  {
    "path": "src/leveldb/util/arena_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/arena.h\"\n\n#include \"util/random.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass ArenaTest {};\n\nTEST(ArenaTest, Empty) { Arena arena; }\n\nTEST(ArenaTest, Simple) {\n  std::vector<std::pair<size_t, char*>> allocated;\n  Arena arena;\n  const int N = 100000;\n  size_t bytes = 0;\n  Random rnd(301);\n  for (int i = 0; i < N; i++) {\n    size_t s;\n    if (i % (N / 10) == 0) {\n      s = i;\n    } else {\n      s = rnd.OneIn(4000)\n              ? rnd.Uniform(6000)\n              : (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));\n    }\n    if (s == 0) {\n      // Our arena disallows size 0 allocations.\n      s = 1;\n    }\n    char* r;\n    if (rnd.OneIn(10)) {\n      r = arena.AllocateAligned(s);\n    } else {\n      r = arena.Allocate(s);\n    }\n\n    for (size_t b = 0; b < s; b++) {\n      // Fill the \"i\"th allocation with a known bit pattern\n      r[b] = i % 256;\n    }\n    bytes += s;\n    allocated.push_back(std::make_pair(s, r));\n    ASSERT_GE(arena.MemoryUsage(), bytes);\n    if (i > N / 10) {\n      ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);\n    }\n  }\n  for (size_t i = 0; i < allocated.size(); i++) {\n    size_t num_bytes = allocated[i].first;\n    const char* p = allocated[i].second;\n    for (size_t b = 0; b < num_bytes; b++) {\n      // Check the \"i\"th allocation for the known bit pattern\n      ASSERT_EQ(int(p[b]) & 0xff, i % 256);\n    }\n  }\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/bloom.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/filter_policy.h\"\n\n#include \"leveldb/slice.h\"\n#include \"util/hash.h\"\n\nnamespace leveldb {\n\nnamespace {\nstatic uint32_t BloomHash(const Slice& key) {\n  return Hash(key.data(), key.size(), 0xbc9f1d34);\n}\n\nclass BloomFilterPolicy : public FilterPolicy {\n public:\n  explicit BloomFilterPolicy(int bits_per_key) : bits_per_key_(bits_per_key) {\n    // We intentionally round down to reduce probing cost a little bit\n    k_ = static_cast<size_t>(bits_per_key * 0.69);  // 0.69 =~ ln(2)\n    if (k_ < 1) k_ = 1;\n    if (k_ > 30) k_ = 30;\n  }\n\n  const char* Name() const override { return \"leveldb.BuiltinBloomFilter2\"; }\n\n  void CreateFilter(const Slice* keys, int n, std::string* dst) const override {\n    // Compute bloom filter size (in both bits and bytes)\n    size_t bits = n * bits_per_key_;\n\n    // For small n, we can see a very high false positive rate.  Fix it\n    // by enforcing a minimum bloom filter length.\n    if (bits < 64) bits = 64;\n\n    size_t bytes = (bits + 7) / 8;\n    bits = bytes * 8;\n\n    const size_t init_size = dst->size();\n    dst->resize(init_size + bytes, 0);\n    dst->push_back(static_cast<char>(k_));  // Remember # of probes in filter\n    char* array = &(*dst)[init_size];\n    for (int i = 0; i < n; i++) {\n      // Use double-hashing to generate a sequence of hash values.\n      // See analysis in [Kirsch,Mitzenmacher 2006].\n      uint32_t h = BloomHash(keys[i]);\n      const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits\n      for (size_t j = 0; j < k_; j++) {\n        const uint32_t bitpos = h % bits;\n        array[bitpos / 8] |= (1 << (bitpos % 8));\n        h += delta;\n      }\n    }\n  }\n\n  bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const override {\n    const size_t len = bloom_filter.size();\n    if (len < 2) return false;\n\n    const char* array = bloom_filter.data();\n    const size_t bits = (len - 1) * 8;\n\n    // Use the encoded k so that we can read filters generated by\n    // bloom filters created using different parameters.\n    const size_t k = array[len - 1];\n    if (k > 30) {\n      // Reserved for potentially new encodings for short bloom filters.\n      // Consider it a match.\n      return true;\n    }\n\n    uint32_t h = BloomHash(key);\n    const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits\n    for (size_t j = 0; j < k; j++) {\n      const uint32_t bitpos = h % bits;\n      if ((array[bitpos / 8] & (1 << (bitpos % 8))) == 0) return false;\n      h += delta;\n    }\n    return true;\n  }\n\n private:\n  size_t bits_per_key_;\n  size_t k_;\n};\n}  // namespace\n\nconst FilterPolicy* NewBloomFilterPolicy(int bits_per_key) {\n  return new BloomFilterPolicy(bits_per_key);\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/bloom_test.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/filter_policy.h\"\n\n#include \"util/coding.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nstatic const int kVerbose = 1;\n\nstatic Slice Key(int i, char* buffer) {\n  EncodeFixed32(buffer, i);\n  return Slice(buffer, sizeof(uint32_t));\n}\n\nclass BloomTest {\n public:\n  BloomTest() : policy_(NewBloomFilterPolicy(10)) {}\n\n  ~BloomTest() { delete policy_; }\n\n  void Reset() {\n    keys_.clear();\n    filter_.clear();\n  }\n\n  void Add(const Slice& s) { keys_.push_back(s.ToString()); }\n\n  void Build() {\n    std::vector<Slice> key_slices;\n    for (size_t i = 0; i < keys_.size(); i++) {\n      key_slices.push_back(Slice(keys_[i]));\n    }\n    filter_.clear();\n    policy_->CreateFilter(&key_slices[0], static_cast<int>(key_slices.size()),\n                          &filter_);\n    keys_.clear();\n    if (kVerbose >= 2) DumpFilter();\n  }\n\n  size_t FilterSize() const { return filter_.size(); }\n\n  void DumpFilter() {\n    fprintf(stderr, \"F(\");\n    for (size_t i = 0; i + 1 < filter_.size(); i++) {\n      const unsigned int c = static_cast<unsigned int>(filter_[i]);\n      for (int j = 0; j < 8; j++) {\n        fprintf(stderr, \"%c\", (c & (1 << j)) ? '1' : '.');\n      }\n    }\n    fprintf(stderr, \")\\n\");\n  }\n\n  bool Matches(const Slice& s) {\n    if (!keys_.empty()) {\n      Build();\n    }\n    return policy_->KeyMayMatch(s, filter_);\n  }\n\n  double FalsePositiveRate() {\n    char buffer[sizeof(int)];\n    int result = 0;\n    for (int i = 0; i < 10000; i++) {\n      if (Matches(Key(i + 1000000000, buffer))) {\n        result++;\n      }\n    }\n    return result / 10000.0;\n  }\n\n private:\n  const FilterPolicy* policy_;\n  std::string filter_;\n  std::vector<std::string> keys_;\n};\n\nTEST(BloomTest, EmptyFilter) {\n  ASSERT_TRUE(!Matches(\"hello\"));\n  ASSERT_TRUE(!Matches(\"world\"));\n}\n\nTEST(BloomTest, Small) {\n  Add(\"hello\");\n  Add(\"world\");\n  ASSERT_TRUE(Matches(\"hello\"));\n  ASSERT_TRUE(Matches(\"world\"));\n  ASSERT_TRUE(!Matches(\"x\"));\n  ASSERT_TRUE(!Matches(\"foo\"));\n}\n\nstatic int NextLength(int length) {\n  if (length < 10) {\n    length += 1;\n  } else if (length < 100) {\n    length += 10;\n  } else if (length < 1000) {\n    length += 100;\n  } else {\n    length += 1000;\n  }\n  return length;\n}\n\nTEST(BloomTest, VaryingLengths) {\n  char buffer[sizeof(int)];\n\n  // Count number of filters that significantly exceed the false positive rate\n  int mediocre_filters = 0;\n  int good_filters = 0;\n\n  for (int length = 1; length <= 10000; length = NextLength(length)) {\n    Reset();\n    for (int i = 0; i < length; i++) {\n      Add(Key(i, buffer));\n    }\n    Build();\n\n    ASSERT_LE(FilterSize(), static_cast<size_t>((length * 10 / 8) + 40))\n        << length;\n\n    // All added keys must match\n    for (int i = 0; i < length; i++) {\n      ASSERT_TRUE(Matches(Key(i, buffer)))\n          << \"Length \" << length << \"; key \" << i;\n    }\n\n    // Check false positive rate\n    double rate = FalsePositiveRate();\n    if (kVerbose >= 1) {\n      fprintf(stderr, \"False positives: %5.2f%% @ length = %6d ; bytes = %6d\\n\",\n              rate * 100.0, length, static_cast<int>(FilterSize()));\n    }\n    ASSERT_LE(rate, 0.02);  // Must not be over 2%\n    if (rate > 0.0125)\n      mediocre_filters++;  // Allowed, but not too often\n    else\n      good_filters++;\n  }\n  if (kVerbose >= 1) {\n    fprintf(stderr, \"Filters: %d good, %d mediocre\\n\", good_filters,\n            mediocre_filters);\n  }\n  ASSERT_LE(mediocre_filters, good_filters / 5);\n}\n\n// Different bits-per-byte\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/cache.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"leveldb/cache.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/hash.h\"\n#include \"util/mutexlock.h\"\n\nnamespace leveldb {\n\nCache::~Cache() {}\n\nnamespace {\n\n// LRU cache implementation\n//\n// Cache entries have an \"in_cache\" boolean indicating whether the cache has a\n// reference on the entry.  The only ways that this can become false without the\n// entry being passed to its \"deleter\" are via Erase(), via Insert() when\n// an element with a duplicate key is inserted, or on destruction of the cache.\n//\n// The cache keeps two linked lists of items in the cache.  All items in the\n// cache are in one list or the other, and never both.  Items still referenced\n// by clients but erased from the cache are in neither list.  The lists are:\n// - in-use:  contains the items currently referenced by clients, in no\n//   particular order.  (This list is used for invariant checking.  If we\n//   removed the check, elements that would otherwise be on this list could be\n//   left as disconnected singleton lists.)\n// - LRU:  contains the items not currently referenced by clients, in LRU order\n// Elements are moved between these lists by the Ref() and Unref() methods,\n// when they detect an element in the cache acquiring or losing its only\n// external reference.\n\n// An entry is a variable length heap-allocated structure.  Entries\n// are kept in a circular doubly linked list ordered by access time.\nstruct LRUHandle {\n  void* value;\n  void (*deleter)(const Slice&, void* value);\n  LRUHandle* next_hash;\n  LRUHandle* next;\n  LRUHandle* prev;\n  size_t charge;  // TODO(opt): Only allow uint32_t?\n  size_t key_length;\n  bool in_cache;     // Whether entry is in the cache.\n  uint32_t refs;     // References, including cache reference, if present.\n  uint32_t hash;     // Hash of key(); used for fast sharding and comparisons\n  char key_data[1];  // Beginning of key\n\n  Slice key() const {\n    // next_ is only equal to this if the LRU handle is the list head of an\n    // empty list. List heads never have meaningful keys.\n    assert(next != this);\n\n    return Slice(key_data, key_length);\n  }\n};\n\n// We provide our own simple hash table since it removes a whole bunch\n// of porting hacks and is also faster than some of the built-in hash\n// table implementations in some of the compiler/runtime combinations\n// we have tested.  E.g., readrandom speeds up by ~5% over the g++\n// 4.4.3's builtin hashtable.\nclass HandleTable {\n public:\n  HandleTable() : length_(0), elems_(0), list_(nullptr) { Resize(); }\n  ~HandleTable() { delete[] list_; }\n\n  LRUHandle* Lookup(const Slice& key, uint32_t hash) {\n    return *FindPointer(key, hash);\n  }\n\n  LRUHandle* Insert(LRUHandle* h) {\n    LRUHandle** ptr = FindPointer(h->key(), h->hash);\n    LRUHandle* old = *ptr;\n    h->next_hash = (old == nullptr ? nullptr : old->next_hash);\n    *ptr = h;\n    if (old == nullptr) {\n      ++elems_;\n      if (elems_ > length_) {\n        // Since each cache entry is fairly large, we aim for a small\n        // average linked list length (<= 1).\n        Resize();\n      }\n    }\n    return old;\n  }\n\n  LRUHandle* Remove(const Slice& key, uint32_t hash) {\n    LRUHandle** ptr = FindPointer(key, hash);\n    LRUHandle* result = *ptr;\n    if (result != nullptr) {\n      *ptr = result->next_hash;\n      --elems_;\n    }\n    return result;\n  }\n\n private:\n  // The table consists of an array of buckets where each bucket is\n  // a linked list of cache entries that hash into the bucket.\n  uint32_t length_;\n  uint32_t elems_;\n  LRUHandle** list_;\n\n  // Return a pointer to slot that points to a cache entry that\n  // matches key/hash.  If there is no such cache entry, return a\n  // pointer to the trailing slot in the corresponding linked list.\n  LRUHandle** FindPointer(const Slice& key, uint32_t hash) {\n    LRUHandle** ptr = &list_[hash & (length_ - 1)];\n    while (*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key())) {\n      ptr = &(*ptr)->next_hash;\n    }\n    return ptr;\n  }\n\n  void Resize() {\n    uint32_t new_length = 4;\n    while (new_length < elems_) {\n      new_length *= 2;\n    }\n    LRUHandle** new_list = new LRUHandle*[new_length];\n    memset(new_list, 0, sizeof(new_list[0]) * new_length);\n    uint32_t count = 0;\n    for (uint32_t i = 0; i < length_; i++) {\n      LRUHandle* h = list_[i];\n      while (h != nullptr) {\n        LRUHandle* next = h->next_hash;\n        uint32_t hash = h->hash;\n        LRUHandle** ptr = &new_list[hash & (new_length - 1)];\n        h->next_hash = *ptr;\n        *ptr = h;\n        h = next;\n        count++;\n      }\n    }\n    assert(elems_ == count);\n    delete[] list_;\n    list_ = new_list;\n    length_ = new_length;\n  }\n};\n\n// A single shard of sharded cache.\nclass LRUCache {\n public:\n  LRUCache();\n  ~LRUCache();\n\n  // Separate from constructor so caller can easily make an array of LRUCache\n  void SetCapacity(size_t capacity) { capacity_ = capacity; }\n\n  // Like Cache methods, but with an extra \"hash\" parameter.\n  Cache::Handle* Insert(const Slice& key, uint32_t hash, void* value,\n                        size_t charge,\n                        void (*deleter)(const Slice& key, void* value));\n  Cache::Handle* Lookup(const Slice& key, uint32_t hash);\n  void Release(Cache::Handle* handle);\n  void Erase(const Slice& key, uint32_t hash);\n  void Prune();\n  size_t TotalCharge() const {\n    MutexLock l(&mutex_);\n    return usage_;\n  }\n\n private:\n  void LRU_Remove(LRUHandle* e);\n  void LRU_Append(LRUHandle* list, LRUHandle* e);\n  void Ref(LRUHandle* e);\n  void Unref(LRUHandle* e);\n  bool FinishErase(LRUHandle* e) EXCLUSIVE_LOCKS_REQUIRED(mutex_);\n\n  // Initialized before use.\n  size_t capacity_;\n\n  // mutex_ protects the following state.\n  mutable port::Mutex mutex_;\n  size_t usage_ GUARDED_BY(mutex_);\n\n  // Dummy head of LRU list.\n  // lru.prev is newest entry, lru.next is oldest entry.\n  // Entries have refs==1 and in_cache==true.\n  LRUHandle lru_ GUARDED_BY(mutex_);\n\n  // Dummy head of in-use list.\n  // Entries are in use by clients, and have refs >= 2 and in_cache==true.\n  LRUHandle in_use_ GUARDED_BY(mutex_);\n\n  HandleTable table_ GUARDED_BY(mutex_);\n};\n\nLRUCache::LRUCache() : capacity_(0), usage_(0) {\n  // Make empty circular linked lists.\n  lru_.next = &lru_;\n  lru_.prev = &lru_;\n  in_use_.next = &in_use_;\n  in_use_.prev = &in_use_;\n}\n\nLRUCache::~LRUCache() {\n  assert(in_use_.next == &in_use_);  // Error if caller has an unreleased handle\n  for (LRUHandle* e = lru_.next; e != &lru_;) {\n    LRUHandle* next = e->next;\n    assert(e->in_cache);\n    e->in_cache = false;\n    assert(e->refs == 1);  // Invariant of lru_ list.\n    Unref(e);\n    e = next;\n  }\n}\n\nvoid LRUCache::Ref(LRUHandle* e) {\n  if (e->refs == 1 && e->in_cache) {  // If on lru_ list, move to in_use_ list.\n    LRU_Remove(e);\n    LRU_Append(&in_use_, e);\n  }\n  e->refs++;\n}\n\nvoid LRUCache::Unref(LRUHandle* e) {\n  assert(e->refs > 0);\n  e->refs--;\n  if (e->refs == 0) {  // Deallocate.\n    assert(!e->in_cache);\n    (*e->deleter)(e->key(), e->value);\n    free(e);\n  } else if (e->in_cache && e->refs == 1) {\n    // No longer in use; move to lru_ list.\n    LRU_Remove(e);\n    LRU_Append(&lru_, e);\n  }\n}\n\nvoid LRUCache::LRU_Remove(LRUHandle* e) {\n  e->next->prev = e->prev;\n  e->prev->next = e->next;\n}\n\nvoid LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) {\n  // Make \"e\" newest entry by inserting just before *list\n  e->next = list;\n  e->prev = list->prev;\n  e->prev->next = e;\n  e->next->prev = e;\n}\n\nCache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {\n  MutexLock l(&mutex_);\n  LRUHandle* e = table_.Lookup(key, hash);\n  if (e != nullptr) {\n    Ref(e);\n  }\n  return reinterpret_cast<Cache::Handle*>(e);\n}\n\nvoid LRUCache::Release(Cache::Handle* handle) {\n  MutexLock l(&mutex_);\n  Unref(reinterpret_cast<LRUHandle*>(handle));\n}\n\nCache::Handle* LRUCache::Insert(const Slice& key, uint32_t hash, void* value,\n                                size_t charge,\n                                void (*deleter)(const Slice& key,\n                                                void* value)) {\n  MutexLock l(&mutex_);\n\n  LRUHandle* e =\n      reinterpret_cast<LRUHandle*>(malloc(sizeof(LRUHandle) - 1 + key.size()));\n  e->value = value;\n  e->deleter = deleter;\n  e->charge = charge;\n  e->key_length = key.size();\n  e->hash = hash;\n  e->in_cache = false;\n  e->refs = 1;  // for the returned handle.\n  memcpy(e->key_data, key.data(), key.size());\n\n  if (capacity_ > 0) {\n    e->refs++;  // for the cache's reference.\n    e->in_cache = true;\n    LRU_Append(&in_use_, e);\n    usage_ += charge;\n    FinishErase(table_.Insert(e));\n  } else {  // don't cache. (capacity_==0 is supported and turns off caching.)\n    // next is read by key() in an assert, so it must be initialized\n    e->next = nullptr;\n  }\n  while (usage_ > capacity_ && lru_.next != &lru_) {\n    LRUHandle* old = lru_.next;\n    assert(old->refs == 1);\n    bool erased = FinishErase(table_.Remove(old->key(), old->hash));\n    if (!erased) {  // to avoid unused variable when compiled NDEBUG\n      assert(erased);\n    }\n  }\n\n  return reinterpret_cast<Cache::Handle*>(e);\n}\n\n// If e != nullptr, finish removing *e from the cache; it has already been\n// removed from the hash table.  Return whether e != nullptr.\nbool LRUCache::FinishErase(LRUHandle* e) {\n  if (e != nullptr) {\n    assert(e->in_cache);\n    LRU_Remove(e);\n    e->in_cache = false;\n    usage_ -= e->charge;\n    Unref(e);\n  }\n  return e != nullptr;\n}\n\nvoid LRUCache::Erase(const Slice& key, uint32_t hash) {\n  MutexLock l(&mutex_);\n  FinishErase(table_.Remove(key, hash));\n}\n\nvoid LRUCache::Prune() {\n  MutexLock l(&mutex_);\n  while (lru_.next != &lru_) {\n    LRUHandle* e = lru_.next;\n    assert(e->refs == 1);\n    bool erased = FinishErase(table_.Remove(e->key(), e->hash));\n    if (!erased) {  // to avoid unused variable when compiled NDEBUG\n      assert(erased);\n    }\n  }\n}\n\nstatic const int kNumShardBits = 4;\nstatic const int kNumShards = 1 << kNumShardBits;\n\nclass ShardedLRUCache : public Cache {\n private:\n  LRUCache shard_[kNumShards];\n  port::Mutex id_mutex_;\n  uint64_t last_id_;\n\n  static inline uint32_t HashSlice(const Slice& s) {\n    return Hash(s.data(), s.size(), 0);\n  }\n\n  static uint32_t Shard(uint32_t hash) { return hash >> (32 - kNumShardBits); }\n\n public:\n  explicit ShardedLRUCache(size_t capacity) : last_id_(0) {\n    const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;\n    for (int s = 0; s < kNumShards; s++) {\n      shard_[s].SetCapacity(per_shard);\n    }\n  }\n  ~ShardedLRUCache() override {}\n  Handle* Insert(const Slice& key, void* value, size_t charge,\n                 void (*deleter)(const Slice& key, void* value)) override {\n    const uint32_t hash = HashSlice(key);\n    return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);\n  }\n  Handle* Lookup(const Slice& key) override {\n    const uint32_t hash = HashSlice(key);\n    return shard_[Shard(hash)].Lookup(key, hash);\n  }\n  void Release(Handle* handle) override {\n    LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);\n    shard_[Shard(h->hash)].Release(handle);\n  }\n  void Erase(const Slice& key) override {\n    const uint32_t hash = HashSlice(key);\n    shard_[Shard(hash)].Erase(key, hash);\n  }\n  void* Value(Handle* handle) override {\n    return reinterpret_cast<LRUHandle*>(handle)->value;\n  }\n  uint64_t NewId() override {\n    MutexLock l(&id_mutex_);\n    return ++(last_id_);\n  }\n  void Prune() override {\n    for (int s = 0; s < kNumShards; s++) {\n      shard_[s].Prune();\n    }\n  }\n  size_t TotalCharge() const override {\n    size_t total = 0;\n    for (int s = 0; s < kNumShards; s++) {\n      total += shard_[s].TotalCharge();\n    }\n    return total;\n  }\n};\n\n}  // end anonymous namespace\n\nCache* NewLRUCache(size_t capacity) { return new ShardedLRUCache(capacity); }\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/cache_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/cache.h\"\n\n#include <vector>\n#include \"util/coding.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\n// Conversions between numeric keys/values and the types expected by Cache.\nstatic std::string EncodeKey(int k) {\n  std::string result;\n  PutFixed32(&result, k);\n  return result;\n}\nstatic int DecodeKey(const Slice& k) {\n  assert(k.size() == 4);\n  return DecodeFixed32(k.data());\n}\nstatic void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); }\nstatic int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); }\n\nclass CacheTest {\n public:\n  static void Deleter(const Slice& key, void* v) {\n    current_->deleted_keys_.push_back(DecodeKey(key));\n    current_->deleted_values_.push_back(DecodeValue(v));\n  }\n\n  static const int kCacheSize = 1000;\n  std::vector<int> deleted_keys_;\n  std::vector<int> deleted_values_;\n  Cache* cache_;\n\n  CacheTest() : cache_(NewLRUCache(kCacheSize)) { current_ = this; }\n\n  ~CacheTest() { delete cache_; }\n\n  int Lookup(int key) {\n    Cache::Handle* handle = cache_->Lookup(EncodeKey(key));\n    const int r = (handle == nullptr) ? -1 : DecodeValue(cache_->Value(handle));\n    if (handle != nullptr) {\n      cache_->Release(handle);\n    }\n    return r;\n  }\n\n  void Insert(int key, int value, int charge = 1) {\n    cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge,\n                                   &CacheTest::Deleter));\n  }\n\n  Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) {\n    return cache_->Insert(EncodeKey(key), EncodeValue(value), charge,\n                          &CacheTest::Deleter);\n  }\n\n  void Erase(int key) { cache_->Erase(EncodeKey(key)); }\n\n  static CacheTest* current_;\n};\nCacheTest* CacheTest::current_;\n\nTEST(CacheTest, HitAndMiss) {\n  ASSERT_EQ(-1, Lookup(100));\n\n  Insert(100, 101);\n  ASSERT_EQ(101, Lookup(100));\n  ASSERT_EQ(-1, Lookup(200));\n  ASSERT_EQ(-1, Lookup(300));\n\n  Insert(200, 201);\n  ASSERT_EQ(101, Lookup(100));\n  ASSERT_EQ(201, Lookup(200));\n  ASSERT_EQ(-1, Lookup(300));\n\n  Insert(100, 102);\n  ASSERT_EQ(102, Lookup(100));\n  ASSERT_EQ(201, Lookup(200));\n  ASSERT_EQ(-1, Lookup(300));\n\n  ASSERT_EQ(1, deleted_keys_.size());\n  ASSERT_EQ(100, deleted_keys_[0]);\n  ASSERT_EQ(101, deleted_values_[0]);\n}\n\nTEST(CacheTest, Erase) {\n  Erase(200);\n  ASSERT_EQ(0, deleted_keys_.size());\n\n  Insert(100, 101);\n  Insert(200, 201);\n  Erase(100);\n  ASSERT_EQ(-1, Lookup(100));\n  ASSERT_EQ(201, Lookup(200));\n  ASSERT_EQ(1, deleted_keys_.size());\n  ASSERT_EQ(100, deleted_keys_[0]);\n  ASSERT_EQ(101, deleted_values_[0]);\n\n  Erase(100);\n  ASSERT_EQ(-1, Lookup(100));\n  ASSERT_EQ(201, Lookup(200));\n  ASSERT_EQ(1, deleted_keys_.size());\n}\n\nTEST(CacheTest, EntriesArePinned) {\n  Insert(100, 101);\n  Cache::Handle* h1 = cache_->Lookup(EncodeKey(100));\n  ASSERT_EQ(101, DecodeValue(cache_->Value(h1)));\n\n  Insert(100, 102);\n  Cache::Handle* h2 = cache_->Lookup(EncodeKey(100));\n  ASSERT_EQ(102, DecodeValue(cache_->Value(h2)));\n  ASSERT_EQ(0, deleted_keys_.size());\n\n  cache_->Release(h1);\n  ASSERT_EQ(1, deleted_keys_.size());\n  ASSERT_EQ(100, deleted_keys_[0]);\n  ASSERT_EQ(101, deleted_values_[0]);\n\n  Erase(100);\n  ASSERT_EQ(-1, Lookup(100));\n  ASSERT_EQ(1, deleted_keys_.size());\n\n  cache_->Release(h2);\n  ASSERT_EQ(2, deleted_keys_.size());\n  ASSERT_EQ(100, deleted_keys_[1]);\n  ASSERT_EQ(102, deleted_values_[1]);\n}\n\nTEST(CacheTest, EvictionPolicy) {\n  Insert(100, 101);\n  Insert(200, 201);\n  Insert(300, 301);\n  Cache::Handle* h = cache_->Lookup(EncodeKey(300));\n\n  // Frequently used entry must be kept around,\n  // as must things that are still in use.\n  for (int i = 0; i < kCacheSize + 100; i++) {\n    Insert(1000 + i, 2000 + i);\n    ASSERT_EQ(2000 + i, Lookup(1000 + i));\n    ASSERT_EQ(101, Lookup(100));\n  }\n  ASSERT_EQ(101, Lookup(100));\n  ASSERT_EQ(-1, Lookup(200));\n  ASSERT_EQ(301, Lookup(300));\n  cache_->Release(h);\n}\n\nTEST(CacheTest, UseExceedsCacheSize) {\n  // Overfill the cache, keeping handles on all inserted entries.\n  std::vector<Cache::Handle*> h;\n  for (int i = 0; i < kCacheSize + 100; i++) {\n    h.push_back(InsertAndReturnHandle(1000 + i, 2000 + i));\n  }\n\n  // Check that all the entries can be found in the cache.\n  for (int i = 0; i < h.size(); i++) {\n    ASSERT_EQ(2000 + i, Lookup(1000 + i));\n  }\n\n  for (int i = 0; i < h.size(); i++) {\n    cache_->Release(h[i]);\n  }\n}\n\nTEST(CacheTest, HeavyEntries) {\n  // Add a bunch of light and heavy entries and then count the combined\n  // size of items still in the cache, which must be approximately the\n  // same as the total capacity.\n  const int kLight = 1;\n  const int kHeavy = 10;\n  int added = 0;\n  int index = 0;\n  while (added < 2 * kCacheSize) {\n    const int weight = (index & 1) ? kLight : kHeavy;\n    Insert(index, 1000 + index, weight);\n    added += weight;\n    index++;\n  }\n\n  int cached_weight = 0;\n  for (int i = 0; i < index; i++) {\n    const int weight = (i & 1 ? kLight : kHeavy);\n    int r = Lookup(i);\n    if (r >= 0) {\n      cached_weight += weight;\n      ASSERT_EQ(1000 + i, r);\n    }\n  }\n  ASSERT_LE(cached_weight, kCacheSize + kCacheSize / 10);\n}\n\nTEST(CacheTest, NewId) {\n  uint64_t a = cache_->NewId();\n  uint64_t b = cache_->NewId();\n  ASSERT_NE(a, b);\n}\n\nTEST(CacheTest, Prune) {\n  Insert(1, 100);\n  Insert(2, 200);\n\n  Cache::Handle* handle = cache_->Lookup(EncodeKey(1));\n  ASSERT_TRUE(handle);\n  cache_->Prune();\n  cache_->Release(handle);\n\n  ASSERT_EQ(100, Lookup(1));\n  ASSERT_EQ(-1, Lookup(2));\n}\n\nTEST(CacheTest, ZeroSizeCache) {\n  delete cache_;\n  cache_ = NewLRUCache(0);\n\n  Insert(1, 100);\n  ASSERT_EQ(-1, Lookup(1));\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/coding.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/coding.h\"\n\nnamespace leveldb {\n\nvoid PutFixed32(std::string* dst, uint32_t value) {\n  char buf[sizeof(value)];\n  EncodeFixed32(buf, value);\n  dst->append(buf, sizeof(buf));\n}\n\nvoid PutFixed64(std::string* dst, uint64_t value) {\n  char buf[sizeof(value)];\n  EncodeFixed64(buf, value);\n  dst->append(buf, sizeof(buf));\n}\n\nchar* EncodeVarint32(char* dst, uint32_t v) {\n  // Operate on characters as unsigneds\n  uint8_t* ptr = reinterpret_cast<uint8_t*>(dst);\n  static const int B = 128;\n  if (v < (1 << 7)) {\n    *(ptr++) = v;\n  } else if (v < (1 << 14)) {\n    *(ptr++) = v | B;\n    *(ptr++) = v >> 7;\n  } else if (v < (1 << 21)) {\n    *(ptr++) = v | B;\n    *(ptr++) = (v >> 7) | B;\n    *(ptr++) = v >> 14;\n  } else if (v < (1 << 28)) {\n    *(ptr++) = v | B;\n    *(ptr++) = (v >> 7) | B;\n    *(ptr++) = (v >> 14) | B;\n    *(ptr++) = v >> 21;\n  } else {\n    *(ptr++) = v | B;\n    *(ptr++) = (v >> 7) | B;\n    *(ptr++) = (v >> 14) | B;\n    *(ptr++) = (v >> 21) | B;\n    *(ptr++) = v >> 28;\n  }\n  return reinterpret_cast<char*>(ptr);\n}\n\nvoid PutVarint32(std::string* dst, uint32_t v) {\n  char buf[5];\n  char* ptr = EncodeVarint32(buf, v);\n  dst->append(buf, ptr - buf);\n}\n\nchar* EncodeVarint64(char* dst, uint64_t v) {\n  static const int B = 128;\n  uint8_t* ptr = reinterpret_cast<uint8_t*>(dst);\n  while (v >= B) {\n    *(ptr++) = v | B;\n    v >>= 7;\n  }\n  *(ptr++) = static_cast<uint8_t>(v);\n  return reinterpret_cast<char*>(ptr);\n}\n\nvoid PutVarint64(std::string* dst, uint64_t v) {\n  char buf[10];\n  char* ptr = EncodeVarint64(buf, v);\n  dst->append(buf, ptr - buf);\n}\n\nvoid PutLengthPrefixedSlice(std::string* dst, const Slice& value) {\n  PutVarint32(dst, value.size());\n  dst->append(value.data(), value.size());\n}\n\nint VarintLength(uint64_t v) {\n  int len = 1;\n  while (v >= 128) {\n    v >>= 7;\n    len++;\n  }\n  return len;\n}\n\nconst char* GetVarint32PtrFallback(const char* p, const char* limit,\n                                   uint32_t* value) {\n  uint32_t result = 0;\n  for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) {\n    uint32_t byte = *(reinterpret_cast<const uint8_t*>(p));\n    p++;\n    if (byte & 128) {\n      // More bytes are present\n      result |= ((byte & 127) << shift);\n    } else {\n      result |= (byte << shift);\n      *value = result;\n      return reinterpret_cast<const char*>(p);\n    }\n  }\n  return nullptr;\n}\n\nbool GetVarint32(Slice* input, uint32_t* value) {\n  const char* p = input->data();\n  const char* limit = p + input->size();\n  const char* q = GetVarint32Ptr(p, limit, value);\n  if (q == nullptr) {\n    return false;\n  } else {\n    *input = Slice(q, limit - q);\n    return true;\n  }\n}\n\nconst char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) {\n  uint64_t result = 0;\n  for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) {\n    uint64_t byte = *(reinterpret_cast<const uint8_t*>(p));\n    p++;\n    if (byte & 128) {\n      // More bytes are present\n      result |= ((byte & 127) << shift);\n    } else {\n      result |= (byte << shift);\n      *value = result;\n      return reinterpret_cast<const char*>(p);\n    }\n  }\n  return nullptr;\n}\n\nbool GetVarint64(Slice* input, uint64_t* value) {\n  const char* p = input->data();\n  const char* limit = p + input->size();\n  const char* q = GetVarint64Ptr(p, limit, value);\n  if (q == nullptr) {\n    return false;\n  } else {\n    *input = Slice(q, limit - q);\n    return true;\n  }\n}\n\nconst char* GetLengthPrefixedSlice(const char* p, const char* limit,\n                                   Slice* result) {\n  uint32_t len;\n  p = GetVarint32Ptr(p, limit, &len);\n  if (p == nullptr) return nullptr;\n  if (p + len > limit) return nullptr;\n  *result = Slice(p, len);\n  return p + len;\n}\n\nbool GetLengthPrefixedSlice(Slice* input, Slice* result) {\n  uint32_t len;\n  if (GetVarint32(input, &len) && input->size() >= len) {\n    *result = Slice(input->data(), len);\n    input->remove_prefix(len);\n    return true;\n  } else {\n    return false;\n  }\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/coding.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Endian-neutral encoding:\n// * Fixed-length numbers are encoded with least-significant byte first\n// * In addition we support variable length \"varint\" encoding\n// * Strings are encoded prefixed by their length in varint format\n\n#ifndef STORAGE_LEVELDB_UTIL_CODING_H_\n#define STORAGE_LEVELDB_UTIL_CODING_H_\n\n#include <cstdint>\n#include <cstring>\n#include <string>\n\n#include \"leveldb/slice.h\"\n#include \"port/port.h\"\n\nnamespace leveldb {\n\n// Standard Put... routines append to a string\nvoid PutFixed32(std::string* dst, uint32_t value);\nvoid PutFixed64(std::string* dst, uint64_t value);\nvoid PutVarint32(std::string* dst, uint32_t value);\nvoid PutVarint64(std::string* dst, uint64_t value);\nvoid PutLengthPrefixedSlice(std::string* dst, const Slice& value);\n\n// Standard Get... routines parse a value from the beginning of a Slice\n// and advance the slice past the parsed value.\nbool GetVarint32(Slice* input, uint32_t* value);\nbool GetVarint64(Slice* input, uint64_t* value);\nbool GetLengthPrefixedSlice(Slice* input, Slice* result);\n\n// Pointer-based variants of GetVarint...  These either store a value\n// in *v and return a pointer just past the parsed value, or return\n// nullptr on error.  These routines only look at bytes in the range\n// [p..limit-1]\nconst char* GetVarint32Ptr(const char* p, const char* limit, uint32_t* v);\nconst char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* v);\n\n// Returns the length of the varint32 or varint64 encoding of \"v\"\nint VarintLength(uint64_t v);\n\n// Lower-level versions of Put... that write directly into a character buffer\n// and return a pointer just past the last byte written.\n// REQUIRES: dst has enough space for the value being written\nchar* EncodeVarint32(char* dst, uint32_t value);\nchar* EncodeVarint64(char* dst, uint64_t value);\n\n// TODO(costan): Remove port::kLittleEndian and the fast paths based on\n//               std::memcpy when clang learns to optimize the generic code, as\n//               described in https://bugs.llvm.org/show_bug.cgi?id=41761\n//\n// The platform-independent code in DecodeFixed{32,64}() gets optimized to mov\n// on x86 and ldr on ARM64, by both clang and gcc. However, only gcc optimizes\n// the platform-independent code in EncodeFixed{32,64}() to mov / str.\n\n// Lower-level versions of Put... that write directly into a character buffer\n// REQUIRES: dst has enough space for the value being written\n\ninline void EncodeFixed32(char* dst, uint32_t value) {\n  uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);\n\n  if (port::kLittleEndian) {\n    // Fast path for little-endian CPUs. All major compilers optimize this to a\n    // single mov (x86_64) / str (ARM) instruction.\n    std::memcpy(buffer, &value, sizeof(uint32_t));\n    return;\n  }\n\n  // Platform-independent code.\n  // Currently, only gcc optimizes this to a single mov / str instruction.\n  buffer[0] = static_cast<uint8_t>(value);\n  buffer[1] = static_cast<uint8_t>(value >> 8);\n  buffer[2] = static_cast<uint8_t>(value >> 16);\n  buffer[3] = static_cast<uint8_t>(value >> 24);\n}\n\ninline void EncodeFixed64(char* dst, uint64_t value) {\n  uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);\n\n  if (port::kLittleEndian) {\n    // Fast path for little-endian CPUs. All major compilers optimize this to a\n    // single mov (x86_64) / str (ARM) instruction.\n    std::memcpy(buffer, &value, sizeof(uint64_t));\n    return;\n  }\n\n  // Platform-independent code.\n  // Currently, only gcc optimizes this to a single mov / str instruction.\n  buffer[0] = static_cast<uint8_t>(value);\n  buffer[1] = static_cast<uint8_t>(value >> 8);\n  buffer[2] = static_cast<uint8_t>(value >> 16);\n  buffer[3] = static_cast<uint8_t>(value >> 24);\n  buffer[4] = static_cast<uint8_t>(value >> 32);\n  buffer[5] = static_cast<uint8_t>(value >> 40);\n  buffer[6] = static_cast<uint8_t>(value >> 48);\n  buffer[7] = static_cast<uint8_t>(value >> 56);\n}\n\n// Lower-level versions of Get... that read directly from a character buffer\n// without any bounds checking.\n\ninline uint32_t DecodeFixed32(const char* ptr) {\n  const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);\n\n  if (port::kLittleEndian) {\n    // Fast path for little-endian CPUs. All major compilers optimize this to a\n    // single mov (x86_64) / ldr (ARM) instruction.\n    uint32_t result;\n    std::memcpy(&result, buffer, sizeof(uint32_t));\n    return result;\n  }\n\n  // Platform-independent code.\n  // Clang and gcc optimize this to a single mov / ldr instruction.\n  return (static_cast<uint32_t>(buffer[0])) |\n         (static_cast<uint32_t>(buffer[1]) << 8) |\n         (static_cast<uint32_t>(buffer[2]) << 16) |\n         (static_cast<uint32_t>(buffer[3]) << 24);\n}\n\ninline uint64_t DecodeFixed64(const char* ptr) {\n  const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);\n\n  if (port::kLittleEndian) {\n    // Fast path for little-endian CPUs. All major compilers optimize this to a\n    // single mov (x86_64) / ldr (ARM) instruction.\n    uint64_t result;\n    std::memcpy(&result, buffer, sizeof(uint64_t));\n    return result;\n  }\n\n  // Platform-independent code.\n  // Clang and gcc optimize this to a single mov / ldr instruction.\n  return (static_cast<uint64_t>(buffer[0])) |\n         (static_cast<uint64_t>(buffer[1]) << 8) |\n         (static_cast<uint64_t>(buffer[2]) << 16) |\n         (static_cast<uint64_t>(buffer[3]) << 24) |\n         (static_cast<uint64_t>(buffer[4]) << 32) |\n         (static_cast<uint64_t>(buffer[5]) << 40) |\n         (static_cast<uint64_t>(buffer[6]) << 48) |\n         (static_cast<uint64_t>(buffer[7]) << 56);\n}\n\n// Internal routine for use by fallback path of GetVarint32Ptr\nconst char* GetVarint32PtrFallback(const char* p, const char* limit,\n                                   uint32_t* value);\ninline const char* GetVarint32Ptr(const char* p, const char* limit,\n                                  uint32_t* value) {\n  if (p < limit) {\n    uint32_t result = *(reinterpret_cast<const uint8_t*>(p));\n    if ((result & 128) == 0) {\n      *value = result;\n      return p + 1;\n    }\n  }\n  return GetVarint32PtrFallback(p, limit, value);\n}\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_CODING_H_\n"
  },
  {
    "path": "src/leveldb/util/coding_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <vector>\n\n#include \"util/coding.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass Coding {};\n\nTEST(Coding, Fixed32) {\n  std::string s;\n  for (uint32_t v = 0; v < 100000; v++) {\n    PutFixed32(&s, v);\n  }\n\n  const char* p = s.data();\n  for (uint32_t v = 0; v < 100000; v++) {\n    uint32_t actual = DecodeFixed32(p);\n    ASSERT_EQ(v, actual);\n    p += sizeof(uint32_t);\n  }\n}\n\nTEST(Coding, Fixed64) {\n  std::string s;\n  for (int power = 0; power <= 63; power++) {\n    uint64_t v = static_cast<uint64_t>(1) << power;\n    PutFixed64(&s, v - 1);\n    PutFixed64(&s, v + 0);\n    PutFixed64(&s, v + 1);\n  }\n\n  const char* p = s.data();\n  for (int power = 0; power <= 63; power++) {\n    uint64_t v = static_cast<uint64_t>(1) << power;\n    uint64_t actual;\n    actual = DecodeFixed64(p);\n    ASSERT_EQ(v - 1, actual);\n    p += sizeof(uint64_t);\n\n    actual = DecodeFixed64(p);\n    ASSERT_EQ(v + 0, actual);\n    p += sizeof(uint64_t);\n\n    actual = DecodeFixed64(p);\n    ASSERT_EQ(v + 1, actual);\n    p += sizeof(uint64_t);\n  }\n}\n\n// Test that encoding routines generate little-endian encodings\nTEST(Coding, EncodingOutput) {\n  std::string dst;\n  PutFixed32(&dst, 0x04030201);\n  ASSERT_EQ(4, dst.size());\n  ASSERT_EQ(0x01, static_cast<int>(dst[0]));\n  ASSERT_EQ(0x02, static_cast<int>(dst[1]));\n  ASSERT_EQ(0x03, static_cast<int>(dst[2]));\n  ASSERT_EQ(0x04, static_cast<int>(dst[3]));\n\n  dst.clear();\n  PutFixed64(&dst, 0x0807060504030201ull);\n  ASSERT_EQ(8, dst.size());\n  ASSERT_EQ(0x01, static_cast<int>(dst[0]));\n  ASSERT_EQ(0x02, static_cast<int>(dst[1]));\n  ASSERT_EQ(0x03, static_cast<int>(dst[2]));\n  ASSERT_EQ(0x04, static_cast<int>(dst[3]));\n  ASSERT_EQ(0x05, static_cast<int>(dst[4]));\n  ASSERT_EQ(0x06, static_cast<int>(dst[5]));\n  ASSERT_EQ(0x07, static_cast<int>(dst[6]));\n  ASSERT_EQ(0x08, static_cast<int>(dst[7]));\n}\n\nTEST(Coding, Varint32) {\n  std::string s;\n  for (uint32_t i = 0; i < (32 * 32); i++) {\n    uint32_t v = (i / 32) << (i % 32);\n    PutVarint32(&s, v);\n  }\n\n  const char* p = s.data();\n  const char* limit = p + s.size();\n  for (uint32_t i = 0; i < (32 * 32); i++) {\n    uint32_t expected = (i / 32) << (i % 32);\n    uint32_t actual;\n    const char* start = p;\n    p = GetVarint32Ptr(p, limit, &actual);\n    ASSERT_TRUE(p != nullptr);\n    ASSERT_EQ(expected, actual);\n    ASSERT_EQ(VarintLength(actual), p - start);\n  }\n  ASSERT_EQ(p, s.data() + s.size());\n}\n\nTEST(Coding, Varint64) {\n  // Construct the list of values to check\n  std::vector<uint64_t> values;\n  // Some special values\n  values.push_back(0);\n  values.push_back(100);\n  values.push_back(~static_cast<uint64_t>(0));\n  values.push_back(~static_cast<uint64_t>(0) - 1);\n  for (uint32_t k = 0; k < 64; k++) {\n    // Test values near powers of two\n    const uint64_t power = 1ull << k;\n    values.push_back(power);\n    values.push_back(power - 1);\n    values.push_back(power + 1);\n  }\n\n  std::string s;\n  for (size_t i = 0; i < values.size(); i++) {\n    PutVarint64(&s, values[i]);\n  }\n\n  const char* p = s.data();\n  const char* limit = p + s.size();\n  for (size_t i = 0; i < values.size(); i++) {\n    ASSERT_TRUE(p < limit);\n    uint64_t actual;\n    const char* start = p;\n    p = GetVarint64Ptr(p, limit, &actual);\n    ASSERT_TRUE(p != nullptr);\n    ASSERT_EQ(values[i], actual);\n    ASSERT_EQ(VarintLength(actual), p - start);\n  }\n  ASSERT_EQ(p, limit);\n}\n\nTEST(Coding, Varint32Overflow) {\n  uint32_t result;\n  std::string input(\"\\x81\\x82\\x83\\x84\\x85\\x11\");\n  ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(),\n                             &result) == nullptr);\n}\n\nTEST(Coding, Varint32Truncation) {\n  uint32_t large_value = (1u << 31) + 100;\n  std::string s;\n  PutVarint32(&s, large_value);\n  uint32_t result;\n  for (size_t len = 0; len < s.size() - 1; len++) {\n    ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == nullptr);\n  }\n  ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) !=\n              nullptr);\n  ASSERT_EQ(large_value, result);\n}\n\nTEST(Coding, Varint64Overflow) {\n  uint64_t result;\n  std::string input(\"\\x81\\x82\\x83\\x84\\x85\\x81\\x82\\x83\\x84\\x85\\x11\");\n  ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(),\n                             &result) == nullptr);\n}\n\nTEST(Coding, Varint64Truncation) {\n  uint64_t large_value = (1ull << 63) + 100ull;\n  std::string s;\n  PutVarint64(&s, large_value);\n  uint64_t result;\n  for (size_t len = 0; len < s.size() - 1; len++) {\n    ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == nullptr);\n  }\n  ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) !=\n              nullptr);\n  ASSERT_EQ(large_value, result);\n}\n\nTEST(Coding, Strings) {\n  std::string s;\n  PutLengthPrefixedSlice(&s, Slice(\"\"));\n  PutLengthPrefixedSlice(&s, Slice(\"foo\"));\n  PutLengthPrefixedSlice(&s, Slice(\"bar\"));\n  PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x')));\n\n  Slice input(s);\n  Slice v;\n  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));\n  ASSERT_EQ(\"\", v.ToString());\n  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));\n  ASSERT_EQ(\"foo\", v.ToString());\n  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));\n  ASSERT_EQ(\"bar\", v.ToString());\n  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));\n  ASSERT_EQ(std::string(200, 'x'), v.ToString());\n  ASSERT_EQ(\"\", input.ToString());\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/comparator.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/comparator.h\"\n\n#include <algorithm>\n#include <cstdint>\n#include <string>\n#include <type_traits>\n\n#include \"leveldb/slice.h\"\n#include \"util/logging.h\"\n#include \"util/no_destructor.h\"\n\nnamespace leveldb {\n\nComparator::~Comparator() = default;\n\nnamespace {\nclass BytewiseComparatorImpl : public Comparator {\n public:\n  BytewiseComparatorImpl() = default;\n\n  const char* Name() const override { return \"leveldb.BytewiseComparator\"; }\n\n  int Compare(const Slice& a, const Slice& b) const override {\n    return a.compare(b);\n  }\n\n  void FindShortestSeparator(std::string* start,\n                             const Slice& limit) const override {\n    // Find length of common prefix\n    size_t min_length = std::min(start->size(), limit.size());\n    size_t diff_index = 0;\n    while ((diff_index < min_length) &&\n           ((*start)[diff_index] == limit[diff_index])) {\n      diff_index++;\n    }\n\n    if (diff_index >= min_length) {\n      // Do not shorten if one string is a prefix of the other\n    } else {\n      uint8_t diff_byte = static_cast<uint8_t>((*start)[diff_index]);\n      if (diff_byte < static_cast<uint8_t>(0xff) &&\n          diff_byte + 1 < static_cast<uint8_t>(limit[diff_index])) {\n        (*start)[diff_index]++;\n        start->resize(diff_index + 1);\n        assert(Compare(*start, limit) < 0);\n      }\n    }\n  }\n\n  void FindShortSuccessor(std::string* key) const override {\n    // Find first character that can be incremented\n    size_t n = key->size();\n    for (size_t i = 0; i < n; i++) {\n      const uint8_t byte = (*key)[i];\n      if (byte != static_cast<uint8_t>(0xff)) {\n        (*key)[i] = byte + 1;\n        key->resize(i + 1);\n        return;\n      }\n    }\n    // *key is a run of 0xffs.  Leave it alone.\n  }\n};\n}  // namespace\n\nconst Comparator* BytewiseComparator() {\n  static NoDestructor<BytewiseComparatorImpl> singleton;\n  return singleton.get();\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/crc32c.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// A portable implementation of crc32c.\n\n#include \"util/crc32c.h\"\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"port/port.h\"\n#include \"util/coding.h\"\n\nnamespace leveldb {\nnamespace crc32c {\n\nnamespace {\n\nconst uint32_t kByteExtensionTable[256] = {\n    0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,\n    0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,\n    0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,\n    0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,\n    0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,\n    0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,\n    0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,\n    0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,\n    0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,\n    0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,\n    0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,\n    0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,\n    0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,\n    0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,\n    0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,\n    0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,\n    0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,\n    0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,\n    0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,\n    0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,\n    0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,\n    0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,\n    0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,\n    0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,\n    0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,\n    0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,\n    0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,\n    0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,\n    0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,\n    0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,\n    0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,\n    0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,\n    0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,\n    0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,\n    0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,\n    0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,\n    0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,\n    0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,\n    0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,\n    0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,\n    0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,\n    0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,\n    0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351};\n\nconst uint32_t kStrideExtensionTable0[256] = {\n    0x00000000, 0x30d23865, 0x61a470ca, 0x517648af, 0xc348e194, 0xf39ad9f1,\n    0xa2ec915e, 0x923ea93b, 0x837db5d9, 0xb3af8dbc, 0xe2d9c513, 0xd20bfd76,\n    0x4035544d, 0x70e76c28, 0x21912487, 0x11431ce2, 0x03171d43, 0x33c52526,\n    0x62b36d89, 0x526155ec, 0xc05ffcd7, 0xf08dc4b2, 0xa1fb8c1d, 0x9129b478,\n    0x806aa89a, 0xb0b890ff, 0xe1ced850, 0xd11ce035, 0x4322490e, 0x73f0716b,\n    0x228639c4, 0x125401a1, 0x062e3a86, 0x36fc02e3, 0x678a4a4c, 0x57587229,\n    0xc566db12, 0xf5b4e377, 0xa4c2abd8, 0x941093bd, 0x85538f5f, 0xb581b73a,\n    0xe4f7ff95, 0xd425c7f0, 0x461b6ecb, 0x76c956ae, 0x27bf1e01, 0x176d2664,\n    0x053927c5, 0x35eb1fa0, 0x649d570f, 0x544f6f6a, 0xc671c651, 0xf6a3fe34,\n    0xa7d5b69b, 0x97078efe, 0x8644921c, 0xb696aa79, 0xe7e0e2d6, 0xd732dab3,\n    0x450c7388, 0x75de4bed, 0x24a80342, 0x147a3b27, 0x0c5c750c, 0x3c8e4d69,\n    0x6df805c6, 0x5d2a3da3, 0xcf149498, 0xffc6acfd, 0xaeb0e452, 0x9e62dc37,\n    0x8f21c0d5, 0xbff3f8b0, 0xee85b01f, 0xde57887a, 0x4c692141, 0x7cbb1924,\n    0x2dcd518b, 0x1d1f69ee, 0x0f4b684f, 0x3f99502a, 0x6eef1885, 0x5e3d20e0,\n    0xcc0389db, 0xfcd1b1be, 0xada7f911, 0x9d75c174, 0x8c36dd96, 0xbce4e5f3,\n    0xed92ad5c, 0xdd409539, 0x4f7e3c02, 0x7fac0467, 0x2eda4cc8, 0x1e0874ad,\n    0x0a724f8a, 0x3aa077ef, 0x6bd63f40, 0x5b040725, 0xc93aae1e, 0xf9e8967b,\n    0xa89eded4, 0x984ce6b1, 0x890ffa53, 0xb9ddc236, 0xe8ab8a99, 0xd879b2fc,\n    0x4a471bc7, 0x7a9523a2, 0x2be36b0d, 0x1b315368, 0x096552c9, 0x39b76aac,\n    0x68c12203, 0x58131a66, 0xca2db35d, 0xfaff8b38, 0xab89c397, 0x9b5bfbf2,\n    0x8a18e710, 0xbacadf75, 0xebbc97da, 0xdb6eafbf, 0x49500684, 0x79823ee1,\n    0x28f4764e, 0x18264e2b, 0x18b8ea18, 0x286ad27d, 0x791c9ad2, 0x49cea2b7,\n    0xdbf00b8c, 0xeb2233e9, 0xba547b46, 0x8a864323, 0x9bc55fc1, 0xab1767a4,\n    0xfa612f0b, 0xcab3176e, 0x588dbe55, 0x685f8630, 0x3929ce9f, 0x09fbf6fa,\n    0x1baff75b, 0x2b7dcf3e, 0x7a0b8791, 0x4ad9bff4, 0xd8e716cf, 0xe8352eaa,\n    0xb9436605, 0x89915e60, 0x98d24282, 0xa8007ae7, 0xf9763248, 0xc9a40a2d,\n    0x5b9aa316, 0x6b489b73, 0x3a3ed3dc, 0x0aecebb9, 0x1e96d09e, 0x2e44e8fb,\n    0x7f32a054, 0x4fe09831, 0xddde310a, 0xed0c096f, 0xbc7a41c0, 0x8ca879a5,\n    0x9deb6547, 0xad395d22, 0xfc4f158d, 0xcc9d2de8, 0x5ea384d3, 0x6e71bcb6,\n    0x3f07f419, 0x0fd5cc7c, 0x1d81cddd, 0x2d53f5b8, 0x7c25bd17, 0x4cf78572,\n    0xdec92c49, 0xee1b142c, 0xbf6d5c83, 0x8fbf64e6, 0x9efc7804, 0xae2e4061,\n    0xff5808ce, 0xcf8a30ab, 0x5db49990, 0x6d66a1f5, 0x3c10e95a, 0x0cc2d13f,\n    0x14e49f14, 0x2436a771, 0x7540efde, 0x4592d7bb, 0xd7ac7e80, 0xe77e46e5,\n    0xb6080e4a, 0x86da362f, 0x97992acd, 0xa74b12a8, 0xf63d5a07, 0xc6ef6262,\n    0x54d1cb59, 0x6403f33c, 0x3575bb93, 0x05a783f6, 0x17f38257, 0x2721ba32,\n    0x7657f29d, 0x4685caf8, 0xd4bb63c3, 0xe4695ba6, 0xb51f1309, 0x85cd2b6c,\n    0x948e378e, 0xa45c0feb, 0xf52a4744, 0xc5f87f21, 0x57c6d61a, 0x6714ee7f,\n    0x3662a6d0, 0x06b09eb5, 0x12caa592, 0x22189df7, 0x736ed558, 0x43bced3d,\n    0xd1824406, 0xe1507c63, 0xb02634cc, 0x80f40ca9, 0x91b7104b, 0xa165282e,\n    0xf0136081, 0xc0c158e4, 0x52fff1df, 0x622dc9ba, 0x335b8115, 0x0389b970,\n    0x11ddb8d1, 0x210f80b4, 0x7079c81b, 0x40abf07e, 0xd2955945, 0xe2476120,\n    0xb331298f, 0x83e311ea, 0x92a00d08, 0xa272356d, 0xf3047dc2, 0xc3d645a7,\n    0x51e8ec9c, 0x613ad4f9, 0x304c9c56, 0x009ea433};\n\nconst uint32_t kStrideExtensionTable1[256] = {\n    0x00000000, 0x54075546, 0xa80eaa8c, 0xfc09ffca, 0x55f123e9, 0x01f676af,\n    0xfdff8965, 0xa9f8dc23, 0xabe247d2, 0xffe51294, 0x03eced5e, 0x57ebb818,\n    0xfe13643b, 0xaa14317d, 0x561dceb7, 0x021a9bf1, 0x5228f955, 0x062fac13,\n    0xfa2653d9, 0xae21069f, 0x07d9dabc, 0x53de8ffa, 0xafd77030, 0xfbd02576,\n    0xf9cabe87, 0xadcdebc1, 0x51c4140b, 0x05c3414d, 0xac3b9d6e, 0xf83cc828,\n    0x043537e2, 0x503262a4, 0xa451f2aa, 0xf056a7ec, 0x0c5f5826, 0x58580d60,\n    0xf1a0d143, 0xa5a78405, 0x59ae7bcf, 0x0da92e89, 0x0fb3b578, 0x5bb4e03e,\n    0xa7bd1ff4, 0xf3ba4ab2, 0x5a429691, 0x0e45c3d7, 0xf24c3c1d, 0xa64b695b,\n    0xf6790bff, 0xa27e5eb9, 0x5e77a173, 0x0a70f435, 0xa3882816, 0xf78f7d50,\n    0x0b86829a, 0x5f81d7dc, 0x5d9b4c2d, 0x099c196b, 0xf595e6a1, 0xa192b3e7,\n    0x086a6fc4, 0x5c6d3a82, 0xa064c548, 0xf463900e, 0x4d4f93a5, 0x1948c6e3,\n    0xe5413929, 0xb1466c6f, 0x18beb04c, 0x4cb9e50a, 0xb0b01ac0, 0xe4b74f86,\n    0xe6add477, 0xb2aa8131, 0x4ea37efb, 0x1aa42bbd, 0xb35cf79e, 0xe75ba2d8,\n    0x1b525d12, 0x4f550854, 0x1f676af0, 0x4b603fb6, 0xb769c07c, 0xe36e953a,\n    0x4a964919, 0x1e911c5f, 0xe298e395, 0xb69fb6d3, 0xb4852d22, 0xe0827864,\n    0x1c8b87ae, 0x488cd2e8, 0xe1740ecb, 0xb5735b8d, 0x497aa447, 0x1d7df101,\n    0xe91e610f, 0xbd193449, 0x4110cb83, 0x15179ec5, 0xbcef42e6, 0xe8e817a0,\n    0x14e1e86a, 0x40e6bd2c, 0x42fc26dd, 0x16fb739b, 0xeaf28c51, 0xbef5d917,\n    0x170d0534, 0x430a5072, 0xbf03afb8, 0xeb04fafe, 0xbb36985a, 0xef31cd1c,\n    0x133832d6, 0x473f6790, 0xeec7bbb3, 0xbac0eef5, 0x46c9113f, 0x12ce4479,\n    0x10d4df88, 0x44d38ace, 0xb8da7504, 0xecdd2042, 0x4525fc61, 0x1122a927,\n    0xed2b56ed, 0xb92c03ab, 0x9a9f274a, 0xce98720c, 0x32918dc6, 0x6696d880,\n    0xcf6e04a3, 0x9b6951e5, 0x6760ae2f, 0x3367fb69, 0x317d6098, 0x657a35de,\n    0x9973ca14, 0xcd749f52, 0x648c4371, 0x308b1637, 0xcc82e9fd, 0x9885bcbb,\n    0xc8b7de1f, 0x9cb08b59, 0x60b97493, 0x34be21d5, 0x9d46fdf6, 0xc941a8b0,\n    0x3548577a, 0x614f023c, 0x635599cd, 0x3752cc8b, 0xcb5b3341, 0x9f5c6607,\n    0x36a4ba24, 0x62a3ef62, 0x9eaa10a8, 0xcaad45ee, 0x3eced5e0, 0x6ac980a6,\n    0x96c07f6c, 0xc2c72a2a, 0x6b3ff609, 0x3f38a34f, 0xc3315c85, 0x973609c3,\n    0x952c9232, 0xc12bc774, 0x3d2238be, 0x69256df8, 0xc0ddb1db, 0x94dae49d,\n    0x68d31b57, 0x3cd44e11, 0x6ce62cb5, 0x38e179f3, 0xc4e88639, 0x90efd37f,\n    0x39170f5c, 0x6d105a1a, 0x9119a5d0, 0xc51ef096, 0xc7046b67, 0x93033e21,\n    0x6f0ac1eb, 0x3b0d94ad, 0x92f5488e, 0xc6f21dc8, 0x3afbe202, 0x6efcb744,\n    0xd7d0b4ef, 0x83d7e1a9, 0x7fde1e63, 0x2bd94b25, 0x82219706, 0xd626c240,\n    0x2a2f3d8a, 0x7e2868cc, 0x7c32f33d, 0x2835a67b, 0xd43c59b1, 0x803b0cf7,\n    0x29c3d0d4, 0x7dc48592, 0x81cd7a58, 0xd5ca2f1e, 0x85f84dba, 0xd1ff18fc,\n    0x2df6e736, 0x79f1b270, 0xd0096e53, 0x840e3b15, 0x7807c4df, 0x2c009199,\n    0x2e1a0a68, 0x7a1d5f2e, 0x8614a0e4, 0xd213f5a2, 0x7beb2981, 0x2fec7cc7,\n    0xd3e5830d, 0x87e2d64b, 0x73814645, 0x27861303, 0xdb8fecc9, 0x8f88b98f,\n    0x267065ac, 0x727730ea, 0x8e7ecf20, 0xda799a66, 0xd8630197, 0x8c6454d1,\n    0x706dab1b, 0x246afe5d, 0x8d92227e, 0xd9957738, 0x259c88f2, 0x719bddb4,\n    0x21a9bf10, 0x75aeea56, 0x89a7159c, 0xdda040da, 0x74589cf9, 0x205fc9bf,\n    0xdc563675, 0x88516333, 0x8a4bf8c2, 0xde4cad84, 0x2245524e, 0x76420708,\n    0xdfbadb2b, 0x8bbd8e6d, 0x77b471a7, 0x23b324e1};\n\nconst uint32_t kStrideExtensionTable2[256] = {\n    0x00000000, 0x678efd01, 0xcf1dfa02, 0xa8930703, 0x9bd782f5, 0xfc597ff4,\n    0x54ca78f7, 0x334485f6, 0x3243731b, 0x55cd8e1a, 0xfd5e8919, 0x9ad07418,\n    0xa994f1ee, 0xce1a0cef, 0x66890bec, 0x0107f6ed, 0x6486e636, 0x03081b37,\n    0xab9b1c34, 0xcc15e135, 0xff5164c3, 0x98df99c2, 0x304c9ec1, 0x57c263c0,\n    0x56c5952d, 0x314b682c, 0x99d86f2f, 0xfe56922e, 0xcd1217d8, 0xaa9cead9,\n    0x020fedda, 0x658110db, 0xc90dcc6c, 0xae83316d, 0x0610366e, 0x619ecb6f,\n    0x52da4e99, 0x3554b398, 0x9dc7b49b, 0xfa49499a, 0xfb4ebf77, 0x9cc04276,\n    0x34534575, 0x53ddb874, 0x60993d82, 0x0717c083, 0xaf84c780, 0xc80a3a81,\n    0xad8b2a5a, 0xca05d75b, 0x6296d058, 0x05182d59, 0x365ca8af, 0x51d255ae,\n    0xf94152ad, 0x9ecfafac, 0x9fc85941, 0xf846a440, 0x50d5a343, 0x375b5e42,\n    0x041fdbb4, 0x639126b5, 0xcb0221b6, 0xac8cdcb7, 0x97f7ee29, 0xf0791328,\n    0x58ea142b, 0x3f64e92a, 0x0c206cdc, 0x6bae91dd, 0xc33d96de, 0xa4b36bdf,\n    0xa5b49d32, 0xc23a6033, 0x6aa96730, 0x0d279a31, 0x3e631fc7, 0x59ede2c6,\n    0xf17ee5c5, 0x96f018c4, 0xf371081f, 0x94fff51e, 0x3c6cf21d, 0x5be20f1c,\n    0x68a68aea, 0x0f2877eb, 0xa7bb70e8, 0xc0358de9, 0xc1327b04, 0xa6bc8605,\n    0x0e2f8106, 0x69a17c07, 0x5ae5f9f1, 0x3d6b04f0, 0x95f803f3, 0xf276fef2,\n    0x5efa2245, 0x3974df44, 0x91e7d847, 0xf6692546, 0xc52da0b0, 0xa2a35db1,\n    0x0a305ab2, 0x6dbea7b3, 0x6cb9515e, 0x0b37ac5f, 0xa3a4ab5c, 0xc42a565d,\n    0xf76ed3ab, 0x90e02eaa, 0x387329a9, 0x5ffdd4a8, 0x3a7cc473, 0x5df23972,\n    0xf5613e71, 0x92efc370, 0xa1ab4686, 0xc625bb87, 0x6eb6bc84, 0x09384185,\n    0x083fb768, 0x6fb14a69, 0xc7224d6a, 0xa0acb06b, 0x93e8359d, 0xf466c89c,\n    0x5cf5cf9f, 0x3b7b329e, 0x2a03aaa3, 0x4d8d57a2, 0xe51e50a1, 0x8290ada0,\n    0xb1d42856, 0xd65ad557, 0x7ec9d254, 0x19472f55, 0x1840d9b8, 0x7fce24b9,\n    0xd75d23ba, 0xb0d3debb, 0x83975b4d, 0xe419a64c, 0x4c8aa14f, 0x2b045c4e,\n    0x4e854c95, 0x290bb194, 0x8198b697, 0xe6164b96, 0xd552ce60, 0xb2dc3361,\n    0x1a4f3462, 0x7dc1c963, 0x7cc63f8e, 0x1b48c28f, 0xb3dbc58c, 0xd455388d,\n    0xe711bd7b, 0x809f407a, 0x280c4779, 0x4f82ba78, 0xe30e66cf, 0x84809bce,\n    0x2c139ccd, 0x4b9d61cc, 0x78d9e43a, 0x1f57193b, 0xb7c41e38, 0xd04ae339,\n    0xd14d15d4, 0xb6c3e8d5, 0x1e50efd6, 0x79de12d7, 0x4a9a9721, 0x2d146a20,\n    0x85876d23, 0xe2099022, 0x878880f9, 0xe0067df8, 0x48957afb, 0x2f1b87fa,\n    0x1c5f020c, 0x7bd1ff0d, 0xd342f80e, 0xb4cc050f, 0xb5cbf3e2, 0xd2450ee3,\n    0x7ad609e0, 0x1d58f4e1, 0x2e1c7117, 0x49928c16, 0xe1018b15, 0x868f7614,\n    0xbdf4448a, 0xda7ab98b, 0x72e9be88, 0x15674389, 0x2623c67f, 0x41ad3b7e,\n    0xe93e3c7d, 0x8eb0c17c, 0x8fb73791, 0xe839ca90, 0x40aacd93, 0x27243092,\n    0x1460b564, 0x73ee4865, 0xdb7d4f66, 0xbcf3b267, 0xd972a2bc, 0xbefc5fbd,\n    0x166f58be, 0x71e1a5bf, 0x42a52049, 0x252bdd48, 0x8db8da4b, 0xea36274a,\n    0xeb31d1a7, 0x8cbf2ca6, 0x242c2ba5, 0x43a2d6a4, 0x70e65352, 0x1768ae53,\n    0xbffba950, 0xd8755451, 0x74f988e6, 0x137775e7, 0xbbe472e4, 0xdc6a8fe5,\n    0xef2e0a13, 0x88a0f712, 0x2033f011, 0x47bd0d10, 0x46bafbfd, 0x213406fc,\n    0x89a701ff, 0xee29fcfe, 0xdd6d7908, 0xbae38409, 0x1270830a, 0x75fe7e0b,\n    0x107f6ed0, 0x77f193d1, 0xdf6294d2, 0xb8ec69d3, 0x8ba8ec25, 0xec261124,\n    0x44b51627, 0x233beb26, 0x223c1dcb, 0x45b2e0ca, 0xed21e7c9, 0x8aaf1ac8,\n    0xb9eb9f3e, 0xde65623f, 0x76f6653c, 0x1178983d};\n\nconst uint32_t kStrideExtensionTable3[256] = {\n    0x00000000, 0xf20c0dfe, 0xe1f46d0d, 0x13f860f3, 0xc604aceb, 0x3408a115,\n    0x27f0c1e6, 0xd5fccc18, 0x89e52f27, 0x7be922d9, 0x6811422a, 0x9a1d4fd4,\n    0x4fe183cc, 0xbded8e32, 0xae15eec1, 0x5c19e33f, 0x162628bf, 0xe42a2541,\n    0xf7d245b2, 0x05de484c, 0xd0228454, 0x222e89aa, 0x31d6e959, 0xc3dae4a7,\n    0x9fc30798, 0x6dcf0a66, 0x7e376a95, 0x8c3b676b, 0x59c7ab73, 0xabcba68d,\n    0xb833c67e, 0x4a3fcb80, 0x2c4c517e, 0xde405c80, 0xcdb83c73, 0x3fb4318d,\n    0xea48fd95, 0x1844f06b, 0x0bbc9098, 0xf9b09d66, 0xa5a97e59, 0x57a573a7,\n    0x445d1354, 0xb6511eaa, 0x63add2b2, 0x91a1df4c, 0x8259bfbf, 0x7055b241,\n    0x3a6a79c1, 0xc866743f, 0xdb9e14cc, 0x29921932, 0xfc6ed52a, 0x0e62d8d4,\n    0x1d9ab827, 0xef96b5d9, 0xb38f56e6, 0x41835b18, 0x527b3beb, 0xa0773615,\n    0x758bfa0d, 0x8787f7f3, 0x947f9700, 0x66739afe, 0x5898a2fc, 0xaa94af02,\n    0xb96ccff1, 0x4b60c20f, 0x9e9c0e17, 0x6c9003e9, 0x7f68631a, 0x8d646ee4,\n    0xd17d8ddb, 0x23718025, 0x3089e0d6, 0xc285ed28, 0x17792130, 0xe5752cce,\n    0xf68d4c3d, 0x048141c3, 0x4ebe8a43, 0xbcb287bd, 0xaf4ae74e, 0x5d46eab0,\n    0x88ba26a8, 0x7ab62b56, 0x694e4ba5, 0x9b42465b, 0xc75ba564, 0x3557a89a,\n    0x26afc869, 0xd4a3c597, 0x015f098f, 0xf3530471, 0xe0ab6482, 0x12a7697c,\n    0x74d4f382, 0x86d8fe7c, 0x95209e8f, 0x672c9371, 0xb2d05f69, 0x40dc5297,\n    0x53243264, 0xa1283f9a, 0xfd31dca5, 0x0f3dd15b, 0x1cc5b1a8, 0xeec9bc56,\n    0x3b35704e, 0xc9397db0, 0xdac11d43, 0x28cd10bd, 0x62f2db3d, 0x90fed6c3,\n    0x8306b630, 0x710abbce, 0xa4f677d6, 0x56fa7a28, 0x45021adb, 0xb70e1725,\n    0xeb17f41a, 0x191bf9e4, 0x0ae39917, 0xf8ef94e9, 0x2d1358f1, 0xdf1f550f,\n    0xcce735fc, 0x3eeb3802, 0xb13145f8, 0x433d4806, 0x50c528f5, 0xa2c9250b,\n    0x7735e913, 0x8539e4ed, 0x96c1841e, 0x64cd89e0, 0x38d46adf, 0xcad86721,\n    0xd92007d2, 0x2b2c0a2c, 0xfed0c634, 0x0cdccbca, 0x1f24ab39, 0xed28a6c7,\n    0xa7176d47, 0x551b60b9, 0x46e3004a, 0xb4ef0db4, 0x6113c1ac, 0x931fcc52,\n    0x80e7aca1, 0x72eba15f, 0x2ef24260, 0xdcfe4f9e, 0xcf062f6d, 0x3d0a2293,\n    0xe8f6ee8b, 0x1afae375, 0x09028386, 0xfb0e8e78, 0x9d7d1486, 0x6f711978,\n    0x7c89798b, 0x8e857475, 0x5b79b86d, 0xa975b593, 0xba8dd560, 0x4881d89e,\n    0x14983ba1, 0xe694365f, 0xf56c56ac, 0x07605b52, 0xd29c974a, 0x20909ab4,\n    0x3368fa47, 0xc164f7b9, 0x8b5b3c39, 0x795731c7, 0x6aaf5134, 0x98a35cca,\n    0x4d5f90d2, 0xbf539d2c, 0xacabfddf, 0x5ea7f021, 0x02be131e, 0xf0b21ee0,\n    0xe34a7e13, 0x114673ed, 0xc4babff5, 0x36b6b20b, 0x254ed2f8, 0xd742df06,\n    0xe9a9e704, 0x1ba5eafa, 0x085d8a09, 0xfa5187f7, 0x2fad4bef, 0xdda14611,\n    0xce5926e2, 0x3c552b1c, 0x604cc823, 0x9240c5dd, 0x81b8a52e, 0x73b4a8d0,\n    0xa64864c8, 0x54446936, 0x47bc09c5, 0xb5b0043b, 0xff8fcfbb, 0x0d83c245,\n    0x1e7ba2b6, 0xec77af48, 0x398b6350, 0xcb876eae, 0xd87f0e5d, 0x2a7303a3,\n    0x766ae09c, 0x8466ed62, 0x979e8d91, 0x6592806f, 0xb06e4c77, 0x42624189,\n    0x519a217a, 0xa3962c84, 0xc5e5b67a, 0x37e9bb84, 0x2411db77, 0xd61dd689,\n    0x03e11a91, 0xf1ed176f, 0xe215779c, 0x10197a62, 0x4c00995d, 0xbe0c94a3,\n    0xadf4f450, 0x5ff8f9ae, 0x8a0435b6, 0x78083848, 0x6bf058bb, 0x99fc5545,\n    0xd3c39ec5, 0x21cf933b, 0x3237f3c8, 0xc03bfe36, 0x15c7322e, 0xe7cb3fd0,\n    0xf4335f23, 0x063f52dd, 0x5a26b1e2, 0xa82abc1c, 0xbbd2dcef, 0x49ded111,\n    0x9c221d09, 0x6e2e10f7, 0x7dd67004, 0x8fda7dfa};\n\n// CRCs are pre- and post- conditioned by xoring with all ones.\nstatic constexpr const uint32_t kCRC32Xor = static_cast<uint32_t>(0xffffffffU);\n\n// Reads a little-endian 32-bit integer from a 32-bit-aligned buffer.\ninline uint32_t ReadUint32LE(const uint8_t* buffer) {\n  return DecodeFixed32(reinterpret_cast<const char*>(buffer));\n}\n\n// Returns the smallest address >= the given address that is aligned to N bytes.\n//\n// N must be a power of two.\ntemplate <int N>\nconstexpr inline const uint8_t* RoundUp(const uint8_t* pointer) {\n  return reinterpret_cast<uint8_t*>(\n      (reinterpret_cast<uintptr_t>(pointer) + (N - 1)) &\n      ~static_cast<uintptr_t>(N - 1));\n}\n\n}  // namespace\n\n// Determine if the CPU running this program can accelerate the CRC32C\n// calculation.\nstatic bool CanAccelerateCRC32C() {\n  // port::AcceleretedCRC32C returns zero when unable to accelerate.\n  static const char kTestCRCBuffer[] = \"TestCRCBuffer\";\n  static const char kBufSize = sizeof(kTestCRCBuffer) - 1;\n  static const uint32_t kTestCRCValue = 0xdcbc59fa;\n\n  return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue;\n}\n\nuint32_t Extend(uint32_t crc, const char* data, size_t n) {\n  static bool accelerate = CanAccelerateCRC32C();\n  if (accelerate) {\n    return port::AcceleratedCRC32C(crc, data, n);\n  }\n\n  const uint8_t* p = reinterpret_cast<const uint8_t*>(data);\n  const uint8_t* e = p + n;\n  uint32_t l = crc ^ kCRC32Xor;\n\n// Process one byte at a time.\n#define STEP1                              \\\n  do {                                     \\\n    int c = (l & 0xff) ^ *p++;             \\\n    l = kByteExtensionTable[c] ^ (l >> 8); \\\n  } while (0)\n\n// Process one of the 4 strides of 4-byte data.\n#define STEP4(s)                                                               \\\n  do {                                                                         \\\n    crc##s = ReadUint32LE(p + s * 4) ^ kStrideExtensionTable3[crc##s & 0xff] ^ \\\n             kStrideExtensionTable2[(crc##s >> 8) & 0xff] ^                    \\\n             kStrideExtensionTable1[(crc##s >> 16) & 0xff] ^                   \\\n             kStrideExtensionTable0[crc##s >> 24];                             \\\n  } while (0)\n\n// Process a 16-byte swath of 4 strides, each of which has 4 bytes of data.\n#define STEP16 \\\n  do {         \\\n    STEP4(0);  \\\n    STEP4(1);  \\\n    STEP4(2);  \\\n    STEP4(3);  \\\n    p += 16;   \\\n  } while (0)\n\n// Process 4 bytes that were already loaded into a word.\n#define STEP4W(w)                                   \\\n  do {                                              \\\n    w ^= l;                                         \\\n    for (size_t i = 0; i < 4; ++i) {                \\\n      w = (w >> 8) ^ kByteExtensionTable[w & 0xff]; \\\n    }                                               \\\n    l = w;                                          \\\n  } while (0)\n\n  // Point x at first 4-byte aligned byte in the buffer. This might be past the\n  // end of the buffer.\n  const uint8_t* x = RoundUp<4>(p);\n  if (x <= e) {\n    // Process bytes p is 4-byte aligned.\n    while (p != x) {\n      STEP1;\n    }\n  }\n\n  if ((e - p) >= 16) {\n    // Load a 16-byte swath into the stride partial results.\n    uint32_t crc0 = ReadUint32LE(p + 0 * 4) ^ l;\n    uint32_t crc1 = ReadUint32LE(p + 1 * 4);\n    uint32_t crc2 = ReadUint32LE(p + 2 * 4);\n    uint32_t crc3 = ReadUint32LE(p + 3 * 4);\n    p += 16;\n\n    // It is possible to get better speeds (at least on x86) by interleaving\n    // prefetching 256 bytes ahead with processing 64 bytes at a time. See the\n    // portable implementation in https://github.com/google/crc32c/.\n\n    // Process one 16-byte swath at a time.\n    while ((e - p) >= 16) {\n      STEP16;\n    }\n\n    // Advance one word at a time as far as possible.\n    while ((e - p) >= 4) {\n      STEP4(0);\n      uint32_t tmp = crc0;\n      crc0 = crc1;\n      crc1 = crc2;\n      crc2 = crc3;\n      crc3 = tmp;\n      p += 4;\n    }\n\n    // Combine the 4 partial stride results.\n    l = 0;\n    STEP4W(crc0);\n    STEP4W(crc1);\n    STEP4W(crc2);\n    STEP4W(crc3);\n  }\n\n  // Process the last few bytes.\n  while (p != e) {\n    STEP1;\n  }\n#undef STEP4W\n#undef STEP16\n#undef STEP4\n#undef STEP1\n  return l ^ kCRC32Xor;\n}\n\n}  // namespace crc32c\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/crc32c.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_\n#define STORAGE_LEVELDB_UTIL_CRC32C_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\nnamespace leveldb {\nnamespace crc32c {\n\n// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the\n// crc32c of some string A.  Extend() is often used to maintain the\n// crc32c of a stream of data.\nuint32_t Extend(uint32_t init_crc, const char* data, size_t n);\n\n// Return the crc32c of data[0,n-1]\ninline uint32_t Value(const char* data, size_t n) { return Extend(0, data, n); }\n\nstatic const uint32_t kMaskDelta = 0xa282ead8ul;\n\n// Return a masked representation of crc.\n//\n// Motivation: it is problematic to compute the CRC of a string that\n// contains embedded CRCs.  Therefore we recommend that CRCs stored\n// somewhere (e.g., in files) should be masked before being stored.\ninline uint32_t Mask(uint32_t crc) {\n  // Rotate right by 15 bits and add a constant.\n  return ((crc >> 15) | (crc << 17)) + kMaskDelta;\n}\n\n// Return the crc whose masked representation is masked_crc.\ninline uint32_t Unmask(uint32_t masked_crc) {\n  uint32_t rot = masked_crc - kMaskDelta;\n  return ((rot >> 17) | (rot << 15));\n}\n\n}  // namespace crc32c\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_CRC32C_H_\n"
  },
  {
    "path": "src/leveldb/util/crc32c_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/crc32c.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\nnamespace crc32c {\n\nclass CRC {};\n\nTEST(CRC, StandardResults) {\n  // From rfc3720 section B.4.\n  char buf[32];\n\n  memset(buf, 0, sizeof(buf));\n  ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf)));\n\n  memset(buf, 0xff, sizeof(buf));\n  ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf)));\n\n  for (int i = 0; i < 32; i++) {\n    buf[i] = i;\n  }\n  ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf)));\n\n  for (int i = 0; i < 32; i++) {\n    buf[i] = 31 - i;\n  }\n  ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf)));\n\n  uint8_t data[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n  ASSERT_EQ(0xd9963a56, Value(reinterpret_cast<char*>(data), sizeof(data)));\n}\n\nTEST(CRC, Values) { ASSERT_NE(Value(\"a\", 1), Value(\"foo\", 3)); }\n\nTEST(CRC, Extend) {\n  ASSERT_EQ(Value(\"hello world\", 11), Extend(Value(\"hello \", 6), \"world\", 5));\n}\n\nTEST(CRC, Mask) {\n  uint32_t crc = Value(\"foo\", 3);\n  ASSERT_NE(crc, Mask(crc));\n  ASSERT_NE(crc, Mask(Mask(crc)));\n  ASSERT_EQ(crc, Unmask(Mask(crc)));\n  ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc)))));\n}\n\n}  // namespace crc32c\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/env.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\n\nEnv::~Env() = default;\n\nStatus Env::NewAppendableFile(const std::string& fname, WritableFile** result) {\n  return Status::NotSupported(\"NewAppendableFile\", fname);\n}\n\nSequentialFile::~SequentialFile() = default;\n\nRandomAccessFile::~RandomAccessFile() = default;\n\nWritableFile::~WritableFile() = default;\n\nLogger::~Logger() = default;\n\nFileLock::~FileLock() = default;\n\nvoid Log(Logger* info_log, const char* format, ...) {\n  if (info_log != nullptr) {\n    va_list ap;\n    va_start(ap, format);\n    info_log->Logv(format, ap);\n    va_end(ap);\n  }\n}\n\nstatic Status DoWriteStringToFile(Env* env, const Slice& data,\n                                  const std::string& fname, bool should_sync) {\n  WritableFile* file;\n  Status s = env->NewWritableFile(fname, &file);\n  if (!s.ok()) {\n    return s;\n  }\n  s = file->Append(data);\n  if (s.ok() && should_sync) {\n    s = file->Sync();\n  }\n  if (s.ok()) {\n    s = file->Close();\n  }\n  delete file;  // Will auto-close if we did not close above\n  if (!s.ok()) {\n    env->DeleteFile(fname);\n  }\n  return s;\n}\n\nStatus WriteStringToFile(Env* env, const Slice& data,\n                         const std::string& fname) {\n  return DoWriteStringToFile(env, data, fname, false);\n}\n\nStatus WriteStringToFileSync(Env* env, const Slice& data,\n                             const std::string& fname) {\n  return DoWriteStringToFile(env, data, fname, true);\n}\n\nStatus ReadFileToString(Env* env, const std::string& fname, std::string* data) {\n  data->clear();\n  SequentialFile* file;\n  Status s = env->NewSequentialFile(fname, &file);\n  if (!s.ok()) {\n    return s;\n  }\n  static const int kBufferSize = 8192;\n  char* space = new char[kBufferSize];\n  while (true) {\n    Slice fragment;\n    s = file->Read(kBufferSize, &fragment, space);\n    if (!s.ok()) {\n      break;\n    }\n    data->append(fragment.data(), fragment.size());\n    if (fragment.empty()) {\n      break;\n    }\n  }\n  delete[] space;\n  delete file;\n  return s;\n}\n\nEnvWrapper::~EnvWrapper() {}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/env_posix.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <dirent.h>\n#include <fcntl.h>\n#include <pthread.h>\n#include <sys/mman.h>\n#include <sys/resource.h>\n#include <sys/stat.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <atomic>\n#include <cerrno>\n#include <cstddef>\n#include <cstdint>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <limits>\n#include <queue>\n#include <set>\n#include <string>\n#include <thread>\n#include <type_traits>\n#include <utility>\n\n#include \"leveldb/env.h\"\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/env_posix_test_helper.h\"\n#include \"util/posix_logger.h\"\n\nnamespace leveldb {\n\nnamespace {\n\n// Set by EnvPosixTestHelper::SetReadOnlyMMapLimit() and MaxOpenFiles().\nint g_open_read_only_file_limit = -1;\n\n// Up to 4096 mmap regions for 64-bit binaries; none for 32-bit.\nconstexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;\n\n// Can be set using EnvPosixTestHelper::SetReadOnlyMMapLimit().\nint g_mmap_limit = kDefaultMmapLimit;\n\n// Common flags defined for all posix open operations\n#if defined(HAVE_O_CLOEXEC)\nconstexpr const int kOpenBaseFlags = O_CLOEXEC;\n#else\nconstexpr const int kOpenBaseFlags = 0;\n#endif  // defined(HAVE_O_CLOEXEC)\n\nconstexpr const size_t kWritableFileBufferSize = 65536;\n\nStatus PosixError(const std::string& context, int error_number) {\n  if (error_number == ENOENT) {\n    return Status::NotFound(context, std::strerror(error_number));\n  } else {\n    return Status::IOError(context, std::strerror(error_number));\n  }\n}\n\n// Helper class to limit resource usage to avoid exhaustion.\n// Currently used to limit read-only file descriptors and mmap file usage\n// so that we do not run out of file descriptors or virtual memory, or run into\n// kernel performance problems for very large databases.\nclass Limiter {\n public:\n  // Limit maximum number of resources to |max_acquires|.\n  Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}\n\n  Limiter(const Limiter&) = delete;\n  Limiter operator=(const Limiter&) = delete;\n\n  // If another resource is available, acquire it and return true.\n  // Else return false.\n  bool Acquire() {\n    int old_acquires_allowed =\n        acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);\n\n    if (old_acquires_allowed > 0) return true;\n\n    acquires_allowed_.fetch_add(1, std::memory_order_relaxed);\n    return false;\n  }\n\n  // Release a resource acquired by a previous call to Acquire() that returned\n  // true.\n  void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); }\n\n private:\n  // The number of available resources.\n  //\n  // This is a counter and is not tied to the invariants of any other class, so\n  // it can be operated on safely using std::memory_order_relaxed.\n  std::atomic<int> acquires_allowed_;\n};\n\n// Implements sequential read access in a file using read().\n//\n// Instances of this class are thread-friendly but not thread-safe, as required\n// by the SequentialFile API.\nclass PosixSequentialFile final : public SequentialFile {\n public:\n  PosixSequentialFile(std::string filename, int fd)\n      : fd_(fd), filename_(filename) {}\n  ~PosixSequentialFile() override { close(fd_); }\n\n  Status Read(size_t n, Slice* result, char* scratch) override {\n    Status status;\n    while (true) {\n      ::ssize_t read_size = ::read(fd_, scratch, n);\n      if (read_size < 0) {  // Read error.\n        if (errno == EINTR) {\n          continue;  // Retry\n        }\n        status = PosixError(filename_, errno);\n        break;\n      }\n      *result = Slice(scratch, read_size);\n      break;\n    }\n    return status;\n  }\n\n  Status Skip(uint64_t n) override {\n    if (::lseek(fd_, n, SEEK_CUR) == static_cast<off_t>(-1)) {\n      return PosixError(filename_, errno);\n    }\n    return Status::OK();\n  }\n\n  virtual std::string GetName() const override { return filename_; }\n\n private:\n  const int fd_;\n  const std::string filename_;\n};\n\n// Implements random read access in a file using pread().\n//\n// Instances of this class are thread-safe, as required by the RandomAccessFile\n// API. Instances are immutable and Read() only calls thread-safe library\n// functions.\nclass PosixRandomAccessFile final : public RandomAccessFile {\n public:\n  // The new instance takes ownership of |fd|. |fd_limiter| must outlive this\n  // instance, and will be used to determine if .\n  PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter)\n      : has_permanent_fd_(fd_limiter->Acquire()),\n        fd_(has_permanent_fd_ ? fd : -1),\n        fd_limiter_(fd_limiter),\n        filename_(std::move(filename)) {\n    if (!has_permanent_fd_) {\n      assert(fd_ == -1);\n      ::close(fd);  // The file will be opened on every read.\n    }\n  }\n\n  ~PosixRandomAccessFile() override {\n    if (has_permanent_fd_) {\n      assert(fd_ != -1);\n      ::close(fd_);\n      fd_limiter_->Release();\n    }\n  }\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    int fd = fd_;\n    if (!has_permanent_fd_) {\n      fd = ::open(filename_.c_str(), O_RDONLY | kOpenBaseFlags);\n      if (fd < 0) {\n        return PosixError(filename_, errno);\n      }\n    }\n\n    assert(fd != -1);\n\n    Status status;\n    ssize_t read_size = ::pread(fd, scratch, n, static_cast<off_t>(offset));\n    *result = Slice(scratch, (read_size < 0) ? 0 : read_size);\n    if (read_size < 0) {\n      // An error: return a non-ok status.\n      status = PosixError(filename_, errno);\n    }\n    if (!has_permanent_fd_) {\n      // Close the temporary file descriptor opened earlier.\n      assert(fd != fd_);\n      ::close(fd);\n    }\n    return status;\n  }\n\n  virtual std::string GetName() const override { return filename_; }\n\n private:\n  const bool has_permanent_fd_;  // If false, the file is opened on every read.\n  const int fd_;                 // -1 if has_permanent_fd_ is false.\n  Limiter* const fd_limiter_;\n  const std::string filename_;\n};\n\n// Implements random read access in a file using mmap().\n//\n// Instances of this class are thread-safe, as required by the RandomAccessFile\n// API. Instances are immutable and Read() only calls thread-safe library\n// functions.\nclass PosixMmapReadableFile final : public RandomAccessFile {\n public:\n  // mmap_base[0, length-1] points to the memory-mapped contents of the file. It\n  // must be the result of a successful call to mmap(). This instances takes\n  // over the ownership of the region.\n  //\n  // |mmap_limiter| must outlive this instance. The caller must have already\n  // aquired the right to use one mmap region, which will be released when this\n  // instance is destroyed.\n  PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length,\n                        Limiter* mmap_limiter)\n      : mmap_base_(mmap_base),\n        length_(length),\n        mmap_limiter_(mmap_limiter),\n        filename_(std::move(filename)) {}\n\n  ~PosixMmapReadableFile() override {\n    ::munmap(static_cast<void*>(mmap_base_), length_);\n    mmap_limiter_->Release();\n  }\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    if (offset + n > length_) {\n      *result = Slice();\n      return PosixError(filename_, EINVAL);\n    }\n\n    *result = Slice(mmap_base_ + offset, n);\n    return Status::OK();\n  }\n\n  virtual std::string GetName() const override { return filename_; }\n\n private:\n  char* const mmap_base_;\n  const size_t length_;\n  Limiter* const mmap_limiter_;\n  const std::string filename_;\n};\n\nclass PosixWritableFile final : public WritableFile {\n public:\n  PosixWritableFile(std::string filename, int fd)\n      : pos_(0),\n        fd_(fd),\n        is_manifest_(IsManifest(filename)),\n        filename_(std::move(filename)),\n        dirname_(Dirname(filename_)) {}\n\n  ~PosixWritableFile() override {\n    if (fd_ >= 0) {\n      // Ignoring any potential errors\n      Close();\n    }\n  }\n\n  Status Append(const Slice& data) override {\n    size_t write_size = data.size();\n    const char* write_data = data.data();\n\n    // Fit as much as possible into buffer.\n    size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);\n    std::memcpy(buf_ + pos_, write_data, copy_size);\n    write_data += copy_size;\n    write_size -= copy_size;\n    pos_ += copy_size;\n    if (write_size == 0) {\n      return Status::OK();\n    }\n\n    // Can't fit in buffer, so need to do at least one write.\n    Status status = FlushBuffer();\n    if (!status.ok()) {\n      return status;\n    }\n\n    // Small writes go to buffer, large writes are written directly.\n    if (write_size < kWritableFileBufferSize) {\n      std::memcpy(buf_, write_data, write_size);\n      pos_ = write_size;\n      return Status::OK();\n    }\n    return WriteUnbuffered(write_data, write_size);\n  }\n\n  Status Close() override {\n    Status status = FlushBuffer();\n    const int close_result = ::close(fd_);\n    if (close_result < 0 && status.ok()) {\n      status = PosixError(filename_, errno);\n    }\n    fd_ = -1;\n    return status;\n  }\n\n  Status Flush() override { return FlushBuffer(); }\n\n  Status Sync() override {\n    // Ensure new files referred to by the manifest are in the filesystem.\n    //\n    // This needs to happen before the manifest file is flushed to disk, to\n    // avoid crashing in a state where the manifest refers to files that are not\n    // yet on disk.\n    Status status = SyncDirIfManifest();\n    if (!status.ok()) {\n      return status;\n    }\n\n    status = FlushBuffer();\n    if (!status.ok()) {\n      return status;\n    }\n\n    return SyncFd(fd_, filename_, false);\n  }\n\n private:\n  Status FlushBuffer() {\n    Status status = WriteUnbuffered(buf_, pos_);\n    pos_ = 0;\n    return status;\n  }\n\n  Status WriteUnbuffered(const char* data, size_t size) {\n    while (size > 0) {\n      ssize_t write_result = ::write(fd_, data, size);\n      if (write_result < 0) {\n        if (errno == EINTR) {\n          continue;  // Retry\n        }\n        return PosixError(filename_, errno);\n      }\n      data += write_result;\n      size -= write_result;\n    }\n    return Status::OK();\n  }\n\n  Status SyncDirIfManifest() {\n    Status status;\n    if (!is_manifest_) {\n      return status;\n    }\n\n    int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);\n    if (fd < 0) {\n      status = PosixError(dirname_, errno);\n    } else {\n      status = SyncFd(fd, dirname_, true);\n      ::close(fd);\n    }\n    return status;\n  }\n\n  // Ensures that all the caches associated with the given file descriptor's\n  // data are flushed all the way to durable media, and can withstand power\n  // failures.\n  //\n  // The path argument is only used to populate the description string in the\n  // returned Status if an error occurs.\n  static Status SyncFd(int fd, const std::string& fd_path, bool syncing_dir) {\n#if HAVE_FULLFSYNC\n    // On macOS and iOS, fsync() doesn't guarantee durability past power\n    // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some\n    // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to\n    // fsync().\n    if (::fcntl(fd, F_FULLFSYNC) == 0) {\n      return Status::OK();\n    }\n#endif  // HAVE_FULLFSYNC\n\n#if HAVE_FDATASYNC\n    bool sync_success = ::fdatasync(fd) == 0;\n#else\n    bool sync_success = ::fsync(fd) == 0;\n#endif  // HAVE_FDATASYNC\n\n    if (sync_success) {\n      return Status::OK();\n    }\n    // Do not crash if filesystem can't fsync directories\n    // (see https://github.com/bitcoin/bitcoin/pull/10000)\n    if (syncing_dir && errno == EINVAL) {\n      return Status::OK();\n    }\n    return PosixError(fd_path, errno);\n  }\n\n  // Returns the directory name in a path pointing to a file.\n  //\n  // Returns \".\" if the path does not contain any directory separator.\n  static std::string Dirname(const std::string& filename) {\n    std::string::size_type separator_pos = filename.rfind('/');\n    if (separator_pos == std::string::npos) {\n      return std::string(\".\");\n    }\n    // The filename component should not contain a path separator. If it does,\n    // the splitting was done incorrectly.\n    assert(filename.find('/', separator_pos + 1) == std::string::npos);\n\n    return filename.substr(0, separator_pos);\n  }\n\n  // Extracts the file name from a path pointing to a file.\n  //\n  // The returned Slice points to |filename|'s data buffer, so it is only valid\n  // while |filename| is alive and unchanged.\n  static Slice Basename(const std::string& filename) {\n    std::string::size_type separator_pos = filename.rfind('/');\n    if (separator_pos == std::string::npos) {\n      return Slice(filename);\n    }\n    // The filename component should not contain a path separator. If it does,\n    // the splitting was done incorrectly.\n    assert(filename.find('/', separator_pos + 1) == std::string::npos);\n\n    return Slice(filename.data() + separator_pos + 1,\n                 filename.length() - separator_pos - 1);\n  }\n\n  // True if the given file is a manifest file.\n  static bool IsManifest(const std::string& filename) {\n    return Basename(filename).starts_with(\"MANIFEST\");\n  }\n\n  virtual std::string GetName() const override { return filename_; }\n\n  // buf_[0, pos_ - 1] contains data to be written to fd_.\n  char buf_[kWritableFileBufferSize];\n  size_t pos_;\n  int fd_;\n\n  const bool is_manifest_;  // True if the file's name starts with MANIFEST.\n  const std::string filename_;\n  const std::string dirname_;  // The directory of filename_.\n};\n\nint LockOrUnlock(int fd, bool lock) {\n  errno = 0;\n  struct ::flock file_lock_info;\n  std::memset(&file_lock_info, 0, sizeof(file_lock_info));\n  file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);\n  file_lock_info.l_whence = SEEK_SET;\n  file_lock_info.l_start = 0;\n  file_lock_info.l_len = 0;  // Lock/unlock entire file.\n  return ::fcntl(fd, F_SETLK, &file_lock_info);\n}\n\n// Instances are thread-safe because they are immutable.\nclass PosixFileLock : public FileLock {\n public:\n  PosixFileLock(int fd, std::string filename)\n      : fd_(fd), filename_(std::move(filename)) {}\n\n  int fd() const { return fd_; }\n  const std::string& filename() const { return filename_; }\n\n private:\n  const int fd_;\n  const std::string filename_;\n};\n\n// Tracks the files locked by PosixEnv::LockFile().\n//\n// We maintain a separate set instead of relying on fcntl(F_SETLK) because\n// fcntl(F_SETLK) does not provide any protection against multiple uses from the\n// same process.\n//\n// Instances are thread-safe because all member data is guarded by a mutex.\nclass PosixLockTable {\n public:\n  bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {\n    mu_.Lock();\n    bool succeeded = locked_files_.insert(fname).second;\n    mu_.Unlock();\n    return succeeded;\n  }\n  void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {\n    mu_.Lock();\n    locked_files_.erase(fname);\n    mu_.Unlock();\n  }\n\n private:\n  port::Mutex mu_;\n  std::set<std::string> locked_files_ GUARDED_BY(mu_);\n};\n\nclass PosixEnv : public Env {\n public:\n  PosixEnv();\n  ~PosixEnv() override {\n    static const char msg[] =\n        \"PosixEnv singleton destroyed. Unsupported behavior!\\n\";\n    std::fwrite(msg, 1, sizeof(msg), stderr);\n    std::abort();\n  }\n\n  Status NewSequentialFile(const std::string& filename,\n                           SequentialFile** result) override {\n    int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);\n    if (fd < 0) {\n      *result = nullptr;\n      return PosixError(filename, errno);\n    }\n\n    *result = new PosixSequentialFile(filename, fd);\n    return Status::OK();\n  }\n\n  Status NewRandomAccessFile(const std::string& filename,\n                             RandomAccessFile** result) override {\n    *result = nullptr;\n    int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);\n    if (fd < 0) {\n      return PosixError(filename, errno);\n    }\n\n    if (!mmap_limiter_.Acquire()) {\n      *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_);\n      return Status::OK();\n    }\n\n    uint64_t file_size;\n    Status status = GetFileSize(filename, &file_size);\n    if (status.ok()) {\n      void* mmap_base =\n          ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);\n      if (mmap_base != MAP_FAILED) {\n        *result = new PosixMmapReadableFile(filename,\n                                            reinterpret_cast<char*>(mmap_base),\n                                            file_size, &mmap_limiter_);\n      } else {\n        status = PosixError(filename, errno);\n      }\n    }\n    ::close(fd);\n    if (!status.ok()) {\n      mmap_limiter_.Release();\n    }\n    return status;\n  }\n\n  Status NewWritableFile(const std::string& filename,\n                         WritableFile** result) override {\n    int fd = ::open(filename.c_str(),\n                    O_TRUNC | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);\n    if (fd < 0) {\n      *result = nullptr;\n      return PosixError(filename, errno);\n    }\n\n    *result = new PosixWritableFile(filename, fd);\n    return Status::OK();\n  }\n\n  Status NewAppendableFile(const std::string& filename,\n                           WritableFile** result) override {\n    int fd = ::open(filename.c_str(),\n                    O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);\n    if (fd < 0) {\n      *result = nullptr;\n      return PosixError(filename, errno);\n    }\n\n    *result = new PosixWritableFile(filename, fd);\n    return Status::OK();\n  }\n\n  bool FileExists(const std::string& filename) override {\n    return ::access(filename.c_str(), F_OK) == 0;\n  }\n\n  Status GetChildren(const std::string& directory_path,\n                     std::vector<std::string>* result) override {\n    result->clear();\n    ::DIR* dir = ::opendir(directory_path.c_str());\n    if (dir == nullptr) {\n      return PosixError(directory_path, errno);\n    }\n    struct ::dirent* entry;\n    while ((entry = ::readdir(dir)) != nullptr) {\n      result->emplace_back(entry->d_name);\n    }\n    ::closedir(dir);\n    return Status::OK();\n  }\n\n  Status DeleteFile(const std::string& filename) override {\n    if (::unlink(filename.c_str()) != 0) {\n      return PosixError(filename, errno);\n    }\n    return Status::OK();\n  }\n\n  Status CreateDir(const std::string& dirname) override {\n    if (::mkdir(dirname.c_str(), 0755) != 0) {\n      return PosixError(dirname, errno);\n    }\n    return Status::OK();\n  }\n\n  Status DeleteDir(const std::string& dirname) override {\n    if (::rmdir(dirname.c_str()) != 0) {\n      return PosixError(dirname, errno);\n    }\n    return Status::OK();\n  }\n\n  Status GetFileSize(const std::string& filename, uint64_t* size) override {\n    struct ::stat file_stat;\n    if (::stat(filename.c_str(), &file_stat) != 0) {\n      *size = 0;\n      return PosixError(filename, errno);\n    }\n    *size = file_stat.st_size;\n    return Status::OK();\n  }\n\n  Status RenameFile(const std::string& from, const std::string& to) override {\n    if (std::rename(from.c_str(), to.c_str()) != 0) {\n      return PosixError(from, errno);\n    }\n    return Status::OK();\n  }\n\n  Status LockFile(const std::string& filename, FileLock** lock) override {\n    *lock = nullptr;\n\n    int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | kOpenBaseFlags, 0644);\n    if (fd < 0) {\n      return PosixError(filename, errno);\n    }\n\n    if (!locks_.Insert(filename)) {\n      ::close(fd);\n      return Status::IOError(\"lock \" + filename, \"already held by process\");\n    }\n\n    if (LockOrUnlock(fd, true) == -1) {\n      int lock_errno = errno;\n      ::close(fd);\n      locks_.Remove(filename);\n      return PosixError(\"lock \" + filename, lock_errno);\n    }\n\n    *lock = new PosixFileLock(fd, filename);\n    return Status::OK();\n  }\n\n  Status UnlockFile(FileLock* lock) override {\n    PosixFileLock* posix_file_lock = static_cast<PosixFileLock*>(lock);\n    if (LockOrUnlock(posix_file_lock->fd(), false) == -1) {\n      return PosixError(\"unlock \" + posix_file_lock->filename(), errno);\n    }\n    locks_.Remove(posix_file_lock->filename());\n    ::close(posix_file_lock->fd());\n    delete posix_file_lock;\n    return Status::OK();\n  }\n\n  void Schedule(void (*background_work_function)(void* background_work_arg),\n                void* background_work_arg) override;\n\n  void StartThread(void (*thread_main)(void* thread_main_arg),\n                   void* thread_main_arg) override {\n    std::thread new_thread(thread_main, thread_main_arg);\n    new_thread.detach();\n  }\n\n  Status GetTestDirectory(std::string* result) override {\n    const char* env = std::getenv(\"TEST_TMPDIR\");\n    if (env && env[0] != '\\0') {\n      *result = env;\n    } else {\n      char buf[100];\n      std::snprintf(buf, sizeof(buf), \"/tmp/leveldbtest-%d\",\n                    static_cast<int>(::geteuid()));\n      *result = buf;\n    }\n\n    // The CreateDir status is ignored because the directory may already exist.\n    CreateDir(*result);\n\n    return Status::OK();\n  }\n\n  Status NewLogger(const std::string& filename, Logger** result) override {\n    int fd = ::open(filename.c_str(),\n                    O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);\n    if (fd < 0) {\n      *result = nullptr;\n      return PosixError(filename, errno);\n    }\n\n    std::FILE* fp = ::fdopen(fd, \"w\");\n    if (fp == nullptr) {\n      ::close(fd);\n      *result = nullptr;\n      return PosixError(filename, errno);\n    } else {\n      *result = new PosixLogger(fp);\n      return Status::OK();\n    }\n  }\n\n  uint64_t NowMicros() override {\n    static constexpr uint64_t kUsecondsPerSecond = 1000000;\n    struct ::timeval tv;\n    ::gettimeofday(&tv, nullptr);\n    return static_cast<uint64_t>(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec;\n  }\n\n  void SleepForMicroseconds(int micros) override {\n    std::this_thread::sleep_for(std::chrono::microseconds(micros));\n  }\n\n private:\n  void BackgroundThreadMain();\n\n  static void BackgroundThreadEntryPoint(PosixEnv* env) {\n    env->BackgroundThreadMain();\n  }\n\n  // Stores the work item data in a Schedule() call.\n  //\n  // Instances are constructed on the thread calling Schedule() and used on the\n  // background thread.\n  //\n  // This structure is thread-safe beacuse it is immutable.\n  struct BackgroundWorkItem {\n    explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)\n        : function(function), arg(arg) {}\n\n    void (*const function)(void*);\n    void* const arg;\n  };\n\n  port::Mutex background_work_mutex_;\n  port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);\n  bool started_background_thread_ GUARDED_BY(background_work_mutex_);\n\n  std::queue<BackgroundWorkItem> background_work_queue_\n      GUARDED_BY(background_work_mutex_);\n\n  PosixLockTable locks_;  // Thread-safe.\n  Limiter mmap_limiter_;  // Thread-safe.\n  Limiter fd_limiter_;    // Thread-safe.\n};\n\n// Return the maximum number of concurrent mmaps.\nint MaxMmaps() { return g_mmap_limit; }\n\n// Return the maximum number of read-only files to keep open.\nint MaxOpenFiles() {\n  if (g_open_read_only_file_limit >= 0) {\n    return g_open_read_only_file_limit;\n  }\n  struct ::rlimit rlim;\n  if (::getrlimit(RLIMIT_NOFILE, &rlim)) {\n    // getrlimit failed, fallback to hard-coded default.\n    g_open_read_only_file_limit = 50;\n  } else if (rlim.rlim_cur == RLIM_INFINITY) {\n    g_open_read_only_file_limit = std::numeric_limits<int>::max();\n  } else {\n    // Allow use of 20% of available file descriptors for read-only files.\n    g_open_read_only_file_limit = rlim.rlim_cur / 5;\n  }\n  return g_open_read_only_file_limit;\n}\n\n}  // namespace\n\nPosixEnv::PosixEnv()\n    : background_work_cv_(&background_work_mutex_),\n      started_background_thread_(false),\n      mmap_limiter_(MaxMmaps()),\n      fd_limiter_(MaxOpenFiles()) {}\n\nvoid PosixEnv::Schedule(\n    void (*background_work_function)(void* background_work_arg),\n    void* background_work_arg) {\n  background_work_mutex_.Lock();\n\n  // Start the background thread, if we haven't done so already.\n  if (!started_background_thread_) {\n    started_background_thread_ = true;\n    std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);\n    background_thread.detach();\n  }\n\n  // If the queue is empty, the background thread may be waiting for work.\n  if (background_work_queue_.empty()) {\n    background_work_cv_.Signal();\n  }\n\n  background_work_queue_.emplace(background_work_function, background_work_arg);\n  background_work_mutex_.Unlock();\n}\n\nvoid PosixEnv::BackgroundThreadMain() {\n  while (true) {\n    background_work_mutex_.Lock();\n\n    // Wait until there is work to be done.\n    while (background_work_queue_.empty()) {\n      background_work_cv_.Wait();\n    }\n\n    assert(!background_work_queue_.empty());\n    auto background_work_function = background_work_queue_.front().function;\n    void* background_work_arg = background_work_queue_.front().arg;\n    background_work_queue_.pop();\n\n    background_work_mutex_.Unlock();\n    background_work_function(background_work_arg);\n  }\n}\n\nnamespace {\n\n// Wraps an Env instance whose destructor is never created.\n//\n// Intended usage:\n//   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;\n//   void ConfigurePosixEnv(int param) {\n//     PlatformSingletonEnv::AssertEnvNotInitialized();\n//     // set global configuration flags.\n//   }\n//   Env* Env::Default() {\n//     static PlatformSingletonEnv default_env;\n//     return default_env.env();\n//   }\ntemplate <typename EnvType>\nclass SingletonEnv {\n public:\n  SingletonEnv() {\n#if !defined(NDEBUG)\n    env_initialized_.store(true, std::memory_order::memory_order_relaxed);\n#endif  // !defined(NDEBUG)\n    static_assert(sizeof(env_storage_) >= sizeof(EnvType),\n                  \"env_storage_ will not fit the Env\");\n    static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),\n                  \"env_storage_ does not meet the Env's alignment needs\");\n    new (&env_storage_) EnvType();\n  }\n  ~SingletonEnv() = default;\n\n  SingletonEnv(const SingletonEnv&) = delete;\n  SingletonEnv& operator=(const SingletonEnv&) = delete;\n\n  Env* env() { return reinterpret_cast<Env*>(&env_storage_); }\n\n  static void AssertEnvNotInitialized() {\n#if !defined(NDEBUG)\n    assert(!env_initialized_.load(std::memory_order::memory_order_relaxed));\n#endif  // !defined(NDEBUG)\n  }\n\n private:\n  typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type\n      env_storage_;\n#if !defined(NDEBUG)\n  static std::atomic<bool> env_initialized_;\n#endif  // !defined(NDEBUG)\n};\n\n#if !defined(NDEBUG)\ntemplate <typename EnvType>\nstd::atomic<bool> SingletonEnv<EnvType>::env_initialized_;\n#endif  // !defined(NDEBUG)\n\nusing PosixDefaultEnv = SingletonEnv<PosixEnv>;\n\n}  // namespace\n\nvoid EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {\n  PosixDefaultEnv::AssertEnvNotInitialized();\n  g_open_read_only_file_limit = limit;\n}\n\nvoid EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {\n  PosixDefaultEnv::AssertEnvNotInitialized();\n  g_mmap_limit = limit;\n}\n\nEnv* Env::Default() {\n  static PosixDefaultEnv env_container;\n  return env_container.env();\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/env_posix_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <sys/resource.h>\n#include <sys/wait.h>\n#include <unistd.h>\n\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <string>\n#include <unordered_set>\n#include <vector>\n\n#include \"leveldb/env.h\"\n#include \"port/port.h\"\n#include \"util/env_posix_test_helper.h\"\n#include \"util/testharness.h\"\n\n#if HAVE_O_CLOEXEC\n\nnamespace {\n\n// Exit codes for the helper process spawned by TestCloseOnExec* tests.\n// Useful for debugging test failures.\nconstexpr int kTextCloseOnExecHelperExecFailedCode = 61;\nconstexpr int kTextCloseOnExecHelperDup2FailedCode = 62;\nconstexpr int kTextCloseOnExecHelperFoundOpenFdCode = 63;\n\n// Global set by main() and read in TestCloseOnExec.\n//\n// The argv[0] value is stored in a std::vector instead of a std::string because\n// std::string does not return a mutable pointer to its buffer until C++17.\n//\n// The vector stores the string pointed to by argv[0], plus the trailing null.\nstd::vector<char>* GetArgvZero() {\n  static std::vector<char> program_name;\n  return &program_name;\n}\n\n// Command-line switch used to run this test as the CloseOnExecSwitch helper.\nstatic const char kTestCloseOnExecSwitch[] = \"--test-close-on-exec-helper\";\n\n// Executed in a separate process by TestCloseOnExec* tests.\n//\n// main() delegates to this function when the test executable is launched with\n// a special command-line switch. TestCloseOnExec* tests fork()+exec() the test\n// executable and pass the special command-line switch.\n//\n\n// main() delegates to this function when the test executable is launched with\n// a special command-line switch. TestCloseOnExec* tests fork()+exec() the test\n// executable and pass the special command-line switch.\n//\n// When main() delegates to this function, the process probes whether a given\n// file descriptor is open, and communicates the result via its exit code.\nint TestCloseOnExecHelperMain(char* pid_arg) {\n  int fd = std::atoi(pid_arg);\n  // When given the same file descriptor twice, dup2() returns -1 if the\n  // file descriptor is closed, or the given file descriptor if it is open.\n  if (::dup2(fd, fd) == fd) {\n    std::fprintf(stderr, \"Unexpected open fd %d\\n\", fd);\n    return kTextCloseOnExecHelperFoundOpenFdCode;\n  }\n  // Double-check that dup2() is saying the file descriptor is closed.\n  if (errno != EBADF) {\n    std::fprintf(stderr, \"Unexpected errno after calling dup2 on fd %d: %s\\n\",\n                 fd, std::strerror(errno));\n    return kTextCloseOnExecHelperDup2FailedCode;\n  }\n  return 0;\n}\n\n// File descriptors are small non-negative integers.\n//\n// Returns void so the implementation can use ASSERT_EQ.\nvoid GetMaxFileDescriptor(int* result_fd) {\n  // Get the maximum file descriptor number.\n  ::rlimit fd_rlimit;\n  ASSERT_EQ(0, ::getrlimit(RLIMIT_NOFILE, &fd_rlimit));\n  *result_fd = fd_rlimit.rlim_cur;\n}\n\n// Iterates through all possible FDs and returns the currently open ones.\n//\n// Returns void so the implementation can use ASSERT_EQ.\nvoid GetOpenFileDescriptors(std::unordered_set<int>* open_fds) {\n  int max_fd = 0;\n  GetMaxFileDescriptor(&max_fd);\n\n  for (int fd = 0; fd < max_fd; ++fd) {\n    if (::dup2(fd, fd) != fd) {\n      // When given the same file descriptor twice, dup2() returns -1 if the\n      // file descriptor is closed, or the given file descriptor if it is open.\n      //\n      // Double-check that dup2() is saying the fd is closed.\n      ASSERT_EQ(EBADF, errno)\n          << \"dup2() should set errno to EBADF on closed file descriptors\";\n      continue;\n    }\n    open_fds->insert(fd);\n  }\n}\n\n// Finds an FD open since a previous call to GetOpenFileDescriptors().\n//\n// |baseline_open_fds| is the result of a previous GetOpenFileDescriptors()\n// call. Assumes that exactly one FD was opened since that call.\n//\n// Returns void so the implementation can use ASSERT_EQ.\nvoid GetNewlyOpenedFileDescriptor(\n    const std::unordered_set<int>& baseline_open_fds, int* result_fd) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n  for (int fd : baseline_open_fds) {\n    ASSERT_EQ(1, open_fds.count(fd))\n        << \"Previously opened file descriptor was closed during test setup\";\n    open_fds.erase(fd);\n  }\n  ASSERT_EQ(1, open_fds.size())\n      << \"Expected exactly one newly opened file descriptor during test setup\";\n  *result_fd = *open_fds.begin();\n}\n\n// Check that a fork()+exec()-ed child process does not have an extra open FD.\nvoid CheckCloseOnExecDoesNotLeakFDs(\n    const std::unordered_set<int>& baseline_open_fds) {\n  // Prepare the argument list for the child process.\n  // execv() wants mutable buffers.\n  char switch_buffer[sizeof(kTestCloseOnExecSwitch)];\n  std::memcpy(switch_buffer, kTestCloseOnExecSwitch,\n              sizeof(kTestCloseOnExecSwitch));\n\n  int probed_fd;\n  GetNewlyOpenedFileDescriptor(baseline_open_fds, &probed_fd);\n  std::string fd_string = std::to_string(probed_fd);\n  std::vector<char> fd_buffer(fd_string.begin(), fd_string.end());\n  fd_buffer.emplace_back('\\0');\n\n  // The helper process is launched with the command below.\n  //      env_posix_tests --test-close-on-exec-helper 3\n  char* child_argv[] = {GetArgvZero()->data(), switch_buffer, fd_buffer.data(),\n                        nullptr};\n\n  constexpr int kForkInChildProcessReturnValue = 0;\n  int child_pid = fork();\n  if (child_pid == kForkInChildProcessReturnValue) {\n    ::execv(child_argv[0], child_argv);\n    std::fprintf(stderr, \"Error spawning child process: %s\\n\", strerror(errno));\n    std::exit(kTextCloseOnExecHelperExecFailedCode);\n  }\n\n  int child_status = 0;\n  ASSERT_EQ(child_pid, ::waitpid(child_pid, &child_status, 0));\n  ASSERT_TRUE(WIFEXITED(child_status))\n      << \"The helper process did not exit with an exit code\";\n  ASSERT_EQ(0, WEXITSTATUS(child_status))\n      << \"The helper process encountered an error\";\n}\n\n}  // namespace\n\n#endif  // HAVE_O_CLOEXEC\n\nnamespace leveldb {\n\nstatic const int kReadOnlyFileLimit = 4;\nstatic const int kMMapLimit = 4;\n\nclass EnvPosixTest {\n public:\n  static void SetFileLimits(int read_only_file_limit, int mmap_limit) {\n    EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit);\n    EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit);\n  }\n\n  EnvPosixTest() : env_(Env::Default()) {}\n\n  Env* env_;\n};\n\nTEST(EnvPosixTest, TestOpenOnRead) {\n  // Write some test data to a single file that will be opened |n| times.\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string test_file = test_dir + \"/open_on_read.txt\";\n\n  FILE* f = fopen(test_file.c_str(), \"we\");\n  ASSERT_TRUE(f != nullptr);\n  const char kFileData[] = \"abcdefghijklmnopqrstuvwxyz\";\n  fputs(kFileData, f);\n  fclose(f);\n\n  // Open test file some number above the sum of the two limits to force\n  // open-on-read behavior of POSIX Env leveldb::RandomAccessFile.\n  const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5;\n  leveldb::RandomAccessFile* files[kNumFiles] = {0};\n  for (int i = 0; i < kNumFiles; i++) {\n    ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i]));\n  }\n  char scratch;\n  Slice read_result;\n  for (int i = 0; i < kNumFiles; i++) {\n    ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch));\n    ASSERT_EQ(kFileData[i], read_result[0]);\n  }\n  for (int i = 0; i < kNumFiles; i++) {\n    delete files[i];\n  }\n  ASSERT_OK(env_->DeleteFile(test_file));\n}\n\n#if HAVE_O_CLOEXEC\n\nTEST(EnvPosixTest, TestCloseOnExecSequentialFile) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_sequential.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  leveldb::SequentialFile* file = nullptr;\n  ASSERT_OK(env_->NewSequentialFile(file_path, &file));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  delete file;\n\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\nTEST(EnvPosixTest, TestCloseOnExecRandomAccessFile) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_random_access.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  // Exhaust the RandomAccessFile mmap limit. This way, the test\n  // RandomAccessFile instance below is backed by a file descriptor, not by an\n  // mmap region.\n  leveldb::RandomAccessFile* mmapped_files[kReadOnlyFileLimit] = {nullptr};\n  for (int i = 0; i < kReadOnlyFileLimit; i++) {\n    ASSERT_OK(env_->NewRandomAccessFile(file_path, &mmapped_files[i]));\n  }\n\n  leveldb::RandomAccessFile* file = nullptr;\n  ASSERT_OK(env_->NewRandomAccessFile(file_path, &file));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  delete file;\n\n  for (int i = 0; i < kReadOnlyFileLimit; i++) {\n    delete mmapped_files[i];\n  }\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\nTEST(EnvPosixTest, TestCloseOnExecWritableFile) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_writable.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  leveldb::WritableFile* file = nullptr;\n  ASSERT_OK(env_->NewWritableFile(file_path, &file));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  delete file;\n\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\nTEST(EnvPosixTest, TestCloseOnExecAppendableFile) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_appendable.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  leveldb::WritableFile* file = nullptr;\n  ASSERT_OK(env_->NewAppendableFile(file_path, &file));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  delete file;\n\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\nTEST(EnvPosixTest, TestCloseOnExecLockFile) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_lock.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  leveldb::FileLock* lock = nullptr;\n  ASSERT_OK(env_->LockFile(file_path, &lock));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  ASSERT_OK(env_->UnlockFile(lock));\n\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\nTEST(EnvPosixTest, TestCloseOnExecLogger) {\n  std::unordered_set<int> open_fds;\n  GetOpenFileDescriptors(&open_fds);\n\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string file_path = test_dir + \"/close_on_exec_logger.txt\";\n  ASSERT_OK(WriteStringToFile(env_, \"0123456789\", file_path));\n\n  leveldb::Logger* file = nullptr;\n  ASSERT_OK(env_->NewLogger(file_path, &file));\n  CheckCloseOnExecDoesNotLeakFDs(open_fds);\n  delete file;\n\n  ASSERT_OK(env_->DeleteFile(file_path));\n}\n\n#endif  // HAVE_O_CLOEXEC\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n#if HAVE_O_CLOEXEC\n  // Check if we're invoked as a helper program, or as the test suite.\n  for (int i = 1; i < argc; ++i) {\n    if (!std::strcmp(argv[i], kTestCloseOnExecSwitch)) {\n      return TestCloseOnExecHelperMain(argv[i + 1]);\n    }\n  }\n\n  // Save argv[0] early, because googletest may modify argv.\n  GetArgvZero()->assign(argv[0], argv[0] + std::strlen(argv[0]) + 1);\n#endif  // HAVE_O_CLOEXEC\n\n  // All tests currently run with the same read-only file limits.\n  leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit,\n                                       leveldb::kMMapLimit);\n  return leveldb::test::RunAllTests();\n}\n"
  },
  {
    "path": "src/leveldb/util/env_posix_test_helper.h",
    "content": "// Copyright 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_\n#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_\n\nnamespace leveldb {\n\nclass EnvPosixTest;\n\n// A helper for the POSIX Env to facilitate testing.\nclass EnvPosixTestHelper {\n private:\n  friend class EnvPosixTest;\n\n  // Set the maximum number of read-only files that will be opened.\n  // Must be called before creating an Env.\n  static void SetReadOnlyFDLimit(int limit);\n\n  // Set the maximum number of read-only files that will be mapped via mmap.\n  // Must be called before creating an Env.\n  static void SetReadOnlyMMapLimit(int limit);\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_\n"
  },
  {
    "path": "src/leveldb/util/env_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/env.h\"\n\n#include <algorithm>\n\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/mutexlock.h\"\n#include \"util/testharness.h\"\n#include \"util/testutil.h\"\n\nnamespace leveldb {\n\nstatic const int kDelayMicros = 100000;\n\nclass EnvTest {\n public:\n  EnvTest() : env_(Env::Default()) {}\n\n  Env* env_;\n};\n\nTEST(EnvTest, ReadWrite) {\n  Random rnd(test::RandomSeed());\n\n  // Get file to use for testing.\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string test_file_name = test_dir + \"/open_on_read.txt\";\n  WritableFile* writable_file;\n  ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file));\n\n  // Fill a file with data generated via a sequence of randomly sized writes.\n  static const size_t kDataSize = 10 * 1048576;\n  std::string data;\n  while (data.size() < kDataSize) {\n    int len = rnd.Skewed(18);  // Up to 2^18 - 1, but typically much smaller\n    std::string r;\n    test::RandomString(&rnd, len, &r);\n    ASSERT_OK(writable_file->Append(r));\n    data += r;\n    if (rnd.OneIn(10)) {\n      ASSERT_OK(writable_file->Flush());\n    }\n  }\n  ASSERT_OK(writable_file->Sync());\n  ASSERT_OK(writable_file->Close());\n  delete writable_file;\n\n  // Read all data using a sequence of randomly sized reads.\n  SequentialFile* sequential_file;\n  ASSERT_OK(env_->NewSequentialFile(test_file_name, &sequential_file));\n  std::string read_result;\n  std::string scratch;\n  while (read_result.size() < data.size()) {\n    int len = std::min<int>(rnd.Skewed(18), data.size() - read_result.size());\n    scratch.resize(std::max(len, 1));  // at least 1 so &scratch[0] is legal\n    Slice read;\n    ASSERT_OK(sequential_file->Read(len, &read, &scratch[0]));\n    if (len > 0) {\n      ASSERT_GT(read.size(), 0);\n    }\n    ASSERT_LE(read.size(), len);\n    read_result.append(read.data(), read.size());\n  }\n  ASSERT_EQ(read_result, data);\n  delete sequential_file;\n}\n\nTEST(EnvTest, RunImmediately) {\n  struct RunState {\n    port::Mutex mu;\n    port::CondVar cvar{&mu};\n    bool called = false;\n\n    static void Run(void* arg) {\n      RunState* state = reinterpret_cast<RunState*>(arg);\n      MutexLock l(&state->mu);\n      ASSERT_EQ(state->called, false);\n      state->called = true;\n      state->cvar.Signal();\n    }\n  };\n\n  RunState state;\n  env_->Schedule(&RunState::Run, &state);\n\n  MutexLock l(&state.mu);\n  while (!state.called) {\n    state.cvar.Wait();\n  }\n}\n\nTEST(EnvTest, RunMany) {\n  struct RunState {\n    port::Mutex mu;\n    port::CondVar cvar{&mu};\n    int last_id = 0;\n  };\n\n  struct Callback {\n    RunState* state_;  // Pointer to shared state.\n    const int id_;  // Order# for the execution of this callback.\n\n    Callback(RunState* s, int id) : state_(s), id_(id) {}\n\n    static void Run(void* arg) {\n      Callback* callback = reinterpret_cast<Callback*>(arg);\n      RunState* state = callback->state_;\n\n      MutexLock l(&state->mu);\n      ASSERT_EQ(state->last_id, callback->id_ - 1);\n      state->last_id = callback->id_;\n      state->cvar.Signal();\n    }\n  };\n\n  RunState state;\n  Callback callback1(&state, 1);\n  Callback callback2(&state, 2);\n  Callback callback3(&state, 3);\n  Callback callback4(&state, 4);\n  env_->Schedule(&Callback::Run, &callback1);\n  env_->Schedule(&Callback::Run, &callback2);\n  env_->Schedule(&Callback::Run, &callback3);\n  env_->Schedule(&Callback::Run, &callback4);\n\n  MutexLock l(&state.mu);\n  while (state.last_id != 4) {\n    state.cvar.Wait();\n  }\n}\n\nstruct State {\n  port::Mutex mu;\n  port::CondVar cvar{&mu};\n\n  int val GUARDED_BY(mu);\n  int num_running GUARDED_BY(mu);\n\n  State(int val, int num_running) : val(val), num_running(num_running) {}\n};\n\nstatic void ThreadBody(void* arg) {\n  State* s = reinterpret_cast<State*>(arg);\n  s->mu.Lock();\n  s->val += 1;\n  s->num_running -= 1;\n  s->cvar.Signal();\n  s->mu.Unlock();\n}\n\nTEST(EnvTest, StartThread) {\n  State state(0, 3);\n  for (int i = 0; i < 3; i++) {\n    env_->StartThread(&ThreadBody, &state);\n  }\n\n  MutexLock l(&state.mu);\n  while (state.num_running != 0) {\n    state.cvar.Wait();\n  }\n  ASSERT_EQ(state.val, 3);\n}\n\nTEST(EnvTest, TestOpenNonExistentFile) {\n  // Write some test data to a single file that will be opened |n| times.\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n\n  std::string non_existent_file = test_dir + \"/non_existent_file\";\n  ASSERT_TRUE(!env_->FileExists(non_existent_file));\n\n  RandomAccessFile* random_access_file;\n  Status status =\n      env_->NewRandomAccessFile(non_existent_file, &random_access_file);\n  ASSERT_TRUE(status.IsNotFound());\n\n  SequentialFile* sequential_file;\n  status = env_->NewSequentialFile(non_existent_file, &sequential_file);\n  ASSERT_TRUE(status.IsNotFound());\n}\n\nTEST(EnvTest, ReopenWritableFile) {\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string test_file_name = test_dir + \"/reopen_writable_file.txt\";\n  env_->DeleteFile(test_file_name);\n\n  WritableFile* writable_file;\n  ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file));\n  std::string data(\"hello world!\");\n  ASSERT_OK(writable_file->Append(data));\n  ASSERT_OK(writable_file->Close());\n  delete writable_file;\n\n  ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file));\n  data = \"42\";\n  ASSERT_OK(writable_file->Append(data));\n  ASSERT_OK(writable_file->Close());\n  delete writable_file;\n\n  ASSERT_OK(ReadFileToString(env_, test_file_name, &data));\n  ASSERT_EQ(std::string(\"42\"), data);\n  env_->DeleteFile(test_file_name);\n}\n\nTEST(EnvTest, ReopenAppendableFile) {\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string test_file_name = test_dir + \"/reopen_appendable_file.txt\";\n  env_->DeleteFile(test_file_name);\n\n  WritableFile* appendable_file;\n  ASSERT_OK(env_->NewAppendableFile(test_file_name, &appendable_file));\n  std::string data(\"hello world!\");\n  ASSERT_OK(appendable_file->Append(data));\n  ASSERT_OK(appendable_file->Close());\n  delete appendable_file;\n\n  ASSERT_OK(env_->NewAppendableFile(test_file_name, &appendable_file));\n  data = \"42\";\n  ASSERT_OK(appendable_file->Append(data));\n  ASSERT_OK(appendable_file->Close());\n  delete appendable_file;\n\n  ASSERT_OK(ReadFileToString(env_, test_file_name, &data));\n  ASSERT_EQ(std::string(\"hello world!42\"), data);\n  env_->DeleteFile(test_file_name);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/env_windows.cc",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n// Prevent Windows headers from defining min/max macros and instead\n// use STL.\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif  // ifndef NOMINMAX\n#include <windows.h>\n\n#include <algorithm>\n#include <atomic>\n#include <chrono>\n#include <condition_variable>\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n#include <memory>\n#include <mutex>\n#include <queue>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"leveldb/env.h\"\n#include \"leveldb/slice.h\"\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n#include \"util/env_windows_test_helper.h\"\n#include \"util/logging.h\"\n#include \"util/mutexlock.h\"\n#include \"util/windows_logger.h\"\n\n#if defined(DeleteFile)\n#undef DeleteFile\n#endif  // defined(DeleteFile)\n\nnamespace leveldb {\n\nnamespace {\n\nconstexpr const size_t kWritableFileBufferSize = 65536;\n\n// Up to 1000 mmaps for 64-bit binaries; none for 32-bit.\nconstexpr int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0;\n\n// Can be set by by EnvWindowsTestHelper::SetReadOnlyMMapLimit().\nint g_mmap_limit = kDefaultMmapLimit;\n\nstd::string GetWindowsErrorMessage(DWORD error_code) {\n  std::string message;\n  char* error_text = nullptr;\n  // Use MBCS version of FormatMessage to match return value.\n  size_t error_text_size = ::FormatMessageA(\n      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |\n          FORMAT_MESSAGE_IGNORE_INSERTS,\n      nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n      reinterpret_cast<char*>(&error_text), 0, nullptr);\n  if (!error_text) {\n    return message;\n  }\n  message.assign(error_text, error_text_size);\n  ::LocalFree(error_text);\n  return message;\n}\n\nStatus WindowsError(const std::string& context, DWORD error_code) {\n  if (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND)\n    return Status::NotFound(context, GetWindowsErrorMessage(error_code));\n  return Status::IOError(context, GetWindowsErrorMessage(error_code));\n}\n\nclass ScopedHandle {\n public:\n  ScopedHandle(HANDLE handle) : handle_(handle) {}\n  ScopedHandle(const ScopedHandle&) = delete;\n  ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}\n  ~ScopedHandle() { Close(); }\n\n  ScopedHandle& operator=(const ScopedHandle&) = delete;\n\n  ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {\n    if (this != &rhs) handle_ = rhs.Release();\n    return *this;\n  }\n\n  bool Close() {\n    if (!is_valid()) {\n      return true;\n    }\n    HANDLE h = handle_;\n    handle_ = INVALID_HANDLE_VALUE;\n    return ::CloseHandle(h);\n  }\n\n  bool is_valid() const {\n    return handle_ != INVALID_HANDLE_VALUE && handle_ != nullptr;\n  }\n\n  HANDLE get() const { return handle_; }\n\n  HANDLE Release() {\n    HANDLE h = handle_;\n    handle_ = INVALID_HANDLE_VALUE;\n    return h;\n  }\n\n private:\n  HANDLE handle_;\n};\n\n// Helper class to limit resource usage to avoid exhaustion.\n// Currently used to limit read-only file descriptors and mmap file usage\n// so that we do not run out of file descriptors or virtual memory, or run into\n// kernel performance problems for very large databases.\nclass Limiter {\n public:\n  // Limit maximum number of resources to |max_acquires|.\n  Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}\n\n  Limiter(const Limiter&) = delete;\n  Limiter operator=(const Limiter&) = delete;\n\n  // If another resource is available, acquire it and return true.\n  // Else return false.\n  bool Acquire() {\n    int old_acquires_allowed =\n        acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);\n\n    if (old_acquires_allowed > 0) return true;\n\n    acquires_allowed_.fetch_add(1, std::memory_order_relaxed);\n    return false;\n  }\n\n  // Release a resource acquired by a previous call to Acquire() that returned\n  // true.\n  void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); }\n\n private:\n  // The number of available resources.\n  //\n  // This is a counter and is not tied to the invariants of any other class, so\n  // it can be operated on safely using std::memory_order_relaxed.\n  std::atomic<int> acquires_allowed_;\n};\n\nclass WindowsSequentialFile : public SequentialFile {\n public:\n  WindowsSequentialFile(std::string filename, ScopedHandle handle)\n      : handle_(std::move(handle)), filename_(std::move(filename)) {}\n  ~WindowsSequentialFile() override {}\n\n  Status Read(size_t n, Slice* result, char* scratch) override {\n    DWORD bytes_read;\n    // DWORD is 32-bit, but size_t could technically be larger. However leveldb\n    // files are limited to leveldb::Options::max_file_size which is clamped to\n    // 1<<30 or 1 GiB.\n    assert(n <= std::numeric_limits<DWORD>::max());\n    if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,\n                    nullptr)) {\n      return WindowsError(filename_, ::GetLastError());\n    }\n\n    *result = Slice(scratch, bytes_read);\n    return Status::OK();\n  }\n\n  Status Skip(uint64_t n) override {\n    LARGE_INTEGER distance;\n    distance.QuadPart = n;\n    if (!::SetFilePointerEx(handle_.get(), distance, nullptr, FILE_CURRENT)) {\n      return WindowsError(filename_, ::GetLastError());\n    }\n    return Status::OK();\n  }\n\n  std::string GetName() const override { return filename_; }\n\n private:\n  const ScopedHandle handle_;\n  const std::string filename_;\n};\n\nclass WindowsRandomAccessFile : public RandomAccessFile {\n public:\n  WindowsRandomAccessFile(std::string filename, ScopedHandle handle)\n      : handle_(std::move(handle)), filename_(std::move(filename)) {}\n\n  ~WindowsRandomAccessFile() override = default;\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    DWORD bytes_read = 0;\n    OVERLAPPED overlapped = {0};\n\n    overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);\n    overlapped.Offset = static_cast<DWORD>(offset);\n    if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,\n                    &overlapped)) {\n      DWORD error_code = ::GetLastError();\n      if (error_code != ERROR_HANDLE_EOF) {\n        *result = Slice(scratch, 0);\n        return Status::IOError(filename_, GetWindowsErrorMessage(error_code));\n      }\n    }\n\n    *result = Slice(scratch, bytes_read);\n    return Status::OK();\n  }\n\n  std::string GetName() const override { return filename_; }\n\n private:\n  const ScopedHandle handle_;\n  const std::string filename_;\n};\n\nclass WindowsMmapReadableFile : public RandomAccessFile {\n public:\n  // base[0,length-1] contains the mmapped contents of the file.\n  WindowsMmapReadableFile(std::string filename, char* mmap_base, size_t length,\n                          Limiter* mmap_limiter)\n      : mmap_base_(mmap_base),\n        length_(length),\n        mmap_limiter_(mmap_limiter),\n        filename_(std::move(filename)) {}\n\n  ~WindowsMmapReadableFile() override {\n    ::UnmapViewOfFile(mmap_base_);\n    mmap_limiter_->Release();\n  }\n\n  Status Read(uint64_t offset, size_t n, Slice* result,\n              char* scratch) const override {\n    if (offset + n > length_) {\n      *result = Slice();\n      return WindowsError(filename_, ERROR_INVALID_PARAMETER);\n    }\n\n    *result = Slice(mmap_base_ + offset, n);\n    return Status::OK();\n  }\n\n  std::string GetName() const override { return filename_; }\n\n private:\n  char* const mmap_base_;\n  const size_t length_;\n  Limiter* const mmap_limiter_;\n  const std::string filename_;\n};\n\nclass WindowsWritableFile : public WritableFile {\n public:\n  WindowsWritableFile(std::string filename, ScopedHandle handle)\n      : pos_(0), handle_(std::move(handle)), filename_(std::move(filename)) {}\n\n  ~WindowsWritableFile() override = default;\n\n  Status Append(const Slice& data) override {\n    size_t write_size = data.size();\n    const char* write_data = data.data();\n\n    // Fit as much as possible into buffer.\n    size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);\n    std::memcpy(buf_ + pos_, write_data, copy_size);\n    write_data += copy_size;\n    write_size -= copy_size;\n    pos_ += copy_size;\n    if (write_size == 0) {\n      return Status::OK();\n    }\n\n    // Can't fit in buffer, so need to do at least one write.\n    Status status = FlushBuffer();\n    if (!status.ok()) {\n      return status;\n    }\n\n    // Small writes go to buffer, large writes are written directly.\n    if (write_size < kWritableFileBufferSize) {\n      std::memcpy(buf_, write_data, write_size);\n      pos_ = write_size;\n      return Status::OK();\n    }\n    return WriteUnbuffered(write_data, write_size);\n  }\n\n  Status Close() override {\n    Status status = FlushBuffer();\n    if (!handle_.Close() && status.ok()) {\n      status = WindowsError(filename_, ::GetLastError());\n    }\n    return status;\n  }\n\n  Status Flush() override { return FlushBuffer(); }\n\n  Status Sync() override {\n    // On Windows no need to sync parent directory. Its metadata will be updated\n    // via the creation of the new file, without an explicit sync.\n\n    Status status = FlushBuffer();\n    if (!status.ok()) {\n      return status;\n    }\n\n    if (!::FlushFileBuffers(handle_.get())) {\n      return Status::IOError(filename_,\n                             GetWindowsErrorMessage(::GetLastError()));\n    }\n    return Status::OK();\n  }\n\n  std::string GetName() const override { return filename_; }\n\n private:\n  Status FlushBuffer() {\n    Status status = WriteUnbuffered(buf_, pos_);\n    pos_ = 0;\n    return status;\n  }\n\n  Status WriteUnbuffered(const char* data, size_t size) {\n    DWORD bytes_written;\n    if (!::WriteFile(handle_.get(), data, static_cast<DWORD>(size),\n                     &bytes_written, nullptr)) {\n      return Status::IOError(filename_,\n                             GetWindowsErrorMessage(::GetLastError()));\n    }\n    return Status::OK();\n  }\n\n  // buf_[0, pos_-1] contains data to be written to handle_.\n  char buf_[kWritableFileBufferSize];\n  size_t pos_;\n\n  ScopedHandle handle_;\n  const std::string filename_;\n};\n\n// Lock or unlock the entire file as specified by |lock|. Returns true\n// when successful, false upon failure. Caller should call ::GetLastError()\n// to determine cause of failure\nbool LockOrUnlock(HANDLE handle, bool lock) {\n  if (lock) {\n    return ::LockFile(handle,\n                      /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,\n                      /*nNumberOfBytesToLockLow=*/MAXDWORD,\n                      /*nNumberOfBytesToLockHigh=*/MAXDWORD);\n  } else {\n    return ::UnlockFile(handle,\n                        /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,\n                        /*nNumberOfBytesToLockLow=*/MAXDWORD,\n                        /*nNumberOfBytesToLockHigh=*/MAXDWORD);\n  }\n}\n\nclass WindowsFileLock : public FileLock {\n public:\n  WindowsFileLock(ScopedHandle handle, std::string filename)\n      : handle_(std::move(handle)), filename_(std::move(filename)) {}\n\n  const ScopedHandle& handle() const { return handle_; }\n  const std::string& filename() const { return filename_; }\n\n private:\n  const ScopedHandle handle_;\n  const std::string filename_;\n};\n\nclass WindowsEnv : public Env {\n public:\n  WindowsEnv();\n  ~WindowsEnv() override {\n    static const char msg[] =\n        \"WindowsEnv singleton destroyed. Unsupported behavior!\\n\";\n    std::fwrite(msg, 1, sizeof(msg), stderr);\n    std::abort();\n  }\n\n  Status NewSequentialFile(const std::string& filename,\n                           SequentialFile** result) override {\n    *result = nullptr;\n    DWORD desired_access = GENERIC_READ;\n    DWORD share_mode = FILE_SHARE_READ;\n    auto wFilename = toUtf16(filename);\n    ScopedHandle handle = ::CreateFileW(\n        wFilename.c_str(), desired_access, share_mode,\n        /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,\n        /*hTemplateFile=*/nullptr);\n    if (!handle.is_valid()) {\n      return WindowsError(filename, ::GetLastError());\n    }\n\n    *result = new WindowsSequentialFile(filename, std::move(handle));\n    return Status::OK();\n  }\n\n  Status NewRandomAccessFile(const std::string& filename,\n                             RandomAccessFile** result) override {\n    *result = nullptr;\n    DWORD desired_access = GENERIC_READ;\n    DWORD share_mode = FILE_SHARE_READ;\n    auto wFilename = toUtf16(filename);\n    ScopedHandle handle =\n        ::CreateFileW(wFilename.c_str(), desired_access, share_mode,\n                      /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING,\n                      FILE_ATTRIBUTE_READONLY,\n                      /*hTemplateFile=*/nullptr);\n    if (!handle.is_valid()) {\n      return WindowsError(filename, ::GetLastError());\n    }\n    if (!mmap_limiter_.Acquire()) {\n      *result = new WindowsRandomAccessFile(filename, std::move(handle));\n      return Status::OK();\n    }\n\n    LARGE_INTEGER file_size;\n    Status status;\n    if (!::GetFileSizeEx(handle.get(), &file_size)) {\n      mmap_limiter_.Release();\n      return WindowsError(filename, ::GetLastError());\n    }\n\n    ScopedHandle mapping =\n        ::CreateFileMappingW(handle.get(),\n                             /*security attributes=*/nullptr, PAGE_READONLY,\n                             /*dwMaximumSizeHigh=*/0,\n                             /*dwMaximumSizeLow=*/0,\n                             /*lpName=*/nullptr);\n    if (mapping.is_valid()) {\n      void* mmap_base = ::MapViewOfFile(mapping.get(), FILE_MAP_READ,\n                                        /*dwFileOffsetHigh=*/0,\n                                        /*dwFileOffsetLow=*/0,\n                                        /*dwNumberOfBytesToMap=*/0);\n      if (mmap_base) {\n        *result = new WindowsMmapReadableFile(\n            filename, reinterpret_cast<char*>(mmap_base),\n            static_cast<size_t>(file_size.QuadPart), &mmap_limiter_);\n        return Status::OK();\n      }\n    }\n    mmap_limiter_.Release();\n    return WindowsError(filename, ::GetLastError());\n  }\n\n  Status NewWritableFile(const std::string& filename,\n                         WritableFile** result) override {\n    DWORD desired_access = GENERIC_WRITE;\n    DWORD share_mode = 0;  // Exclusive access.\n    auto wFilename = toUtf16(filename);\n    ScopedHandle handle = ::CreateFileW(\n        wFilename.c_str(), desired_access, share_mode,\n        /*lpSecurityAttributes=*/nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,\n        /*hTemplateFile=*/nullptr);\n    if (!handle.is_valid()) {\n      *result = nullptr;\n      return WindowsError(filename, ::GetLastError());\n    }\n\n    *result = new WindowsWritableFile(filename, std::move(handle));\n    return Status::OK();\n  }\n\n  Status NewAppendableFile(const std::string& filename,\n                           WritableFile** result) override {\n    DWORD desired_access = FILE_APPEND_DATA;\n    DWORD share_mode = 0;  // Exclusive access.\n    auto wFilename = toUtf16(filename);\n    ScopedHandle handle = ::CreateFileW(\n        wFilename.c_str(), desired_access, share_mode,\n        /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,\n        /*hTemplateFile=*/nullptr);\n    if (!handle.is_valid()) {\n      *result = nullptr;\n      return WindowsError(filename, ::GetLastError());\n    }\n\n    *result = new WindowsWritableFile(filename, std::move(handle));\n    return Status::OK();\n  }\n\n  bool FileExists(const std::string& filename) override {\n    auto wFilename = toUtf16(filename);\n    return GetFileAttributesW(wFilename.c_str()) != INVALID_FILE_ATTRIBUTES;\n  }\n\n  Status GetChildren(const std::string& directory_path,\n                     std::vector<std::string>* result) override {\n    const std::string find_pattern = directory_path + \"\\\\*\";\n    WIN32_FIND_DATAW find_data;\n    auto wFind_pattern = toUtf16(find_pattern);\n    HANDLE dir_handle = ::FindFirstFileW(wFind_pattern.c_str(), &find_data);\n    if (dir_handle == INVALID_HANDLE_VALUE) {\n      DWORD last_error = ::GetLastError();\n      if (last_error == ERROR_FILE_NOT_FOUND) {\n        return Status::OK();\n      }\n      return WindowsError(directory_path, last_error);\n    }\n    do {\n      char base_name[_MAX_FNAME];\n      char ext[_MAX_EXT];\n\n      auto find_data_filename = toUtf8(find_data.cFileName);\n      if (!_splitpath_s(find_data_filename.c_str(), nullptr, 0, nullptr, 0,\n                        base_name, ARRAYSIZE(base_name), ext, ARRAYSIZE(ext))) {\n        result->emplace_back(std::string(base_name) + ext);\n      }\n    } while (::FindNextFileW(dir_handle, &find_data));\n    DWORD last_error = ::GetLastError();\n    ::FindClose(dir_handle);\n    if (last_error != ERROR_NO_MORE_FILES) {\n      return WindowsError(directory_path, last_error);\n    }\n    return Status::OK();\n  }\n\n  Status DeleteFile(const std::string& filename) override {\n    auto wFilename = toUtf16(filename);\n    if (!::DeleteFileW(wFilename.c_str())) {\n      return WindowsError(filename, ::GetLastError());\n    }\n    return Status::OK();\n  }\n\n  Status CreateDir(const std::string& dirname) override {\n    auto wDirname = toUtf16(dirname);\n    if (!::CreateDirectoryW(wDirname.c_str(), nullptr)) {\n      return WindowsError(dirname, ::GetLastError());\n    }\n    return Status::OK();\n  }\n\n  Status DeleteDir(const std::string& dirname) override {\n    auto wDirname = toUtf16(dirname);\n    if (!::RemoveDirectoryW(wDirname.c_str())) {\n      return WindowsError(dirname, ::GetLastError());\n    }\n    return Status::OK();\n  }\n\n  Status GetFileSize(const std::string& filename, uint64_t* size) override {\n    WIN32_FILE_ATTRIBUTE_DATA file_attributes;\n    auto wFilename = toUtf16(filename);\n    if (!::GetFileAttributesExW(wFilename.c_str(), GetFileExInfoStandard,\n                                &file_attributes)) {\n      return WindowsError(filename, ::GetLastError());\n    }\n    ULARGE_INTEGER file_size;\n    file_size.HighPart = file_attributes.nFileSizeHigh;\n    file_size.LowPart = file_attributes.nFileSizeLow;\n    *size = file_size.QuadPart;\n    return Status::OK();\n  }\n\n  Status RenameFile(const std::string& from, const std::string& to) override {\n    // Try a simple move first. It will only succeed when |to| doesn't already\n    // exist.\n    auto wFrom = toUtf16(from);\n    auto wTo = toUtf16(to);\n    if (::MoveFileW(wFrom.c_str(), wTo.c_str())) {\n      return Status::OK();\n    }\n    DWORD move_error = ::GetLastError();\n\n    // Try the full-blown replace if the move fails, as ReplaceFile will only\n    // succeed when |to| does exist. When writing to a network share, we may not\n    // be able to change the ACLs. Ignore ACL errors then\n    // (REPLACEFILE_IGNORE_MERGE_ERRORS).\n    if (::ReplaceFileW(wTo.c_str(), wFrom.c_str(), /*lpBackupFileName=*/nullptr,\n                       REPLACEFILE_IGNORE_MERGE_ERRORS,\n                       /*lpExclude=*/nullptr, /*lpReserved=*/nullptr)) {\n      return Status::OK();\n    }\n    DWORD replace_error = ::GetLastError();\n    // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that\n    // |to| does not exist. In this case, the more relevant error comes from the\n    // call to MoveFile.\n    if (replace_error == ERROR_FILE_NOT_FOUND ||\n        replace_error == ERROR_PATH_NOT_FOUND) {\n      return WindowsError(from, move_error);\n    } else {\n      return WindowsError(from, replace_error);\n    }\n  }\n\n  Status LockFile(const std::string& filename, FileLock** lock) override {\n    *lock = nullptr;\n    Status result;\n    auto wFilename = toUtf16(filename);\n    ScopedHandle handle = ::CreateFileW(\n        wFilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,\n        /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,\n        nullptr);\n    if (!handle.is_valid()) {\n      result = WindowsError(filename, ::GetLastError());\n    } else if (!LockOrUnlock(handle.get(), true)) {\n      result = WindowsError(\"lock \" + filename, ::GetLastError());\n    } else {\n      *lock = new WindowsFileLock(std::move(handle), filename);\n    }\n    return result;\n  }\n\n  Status UnlockFile(FileLock* lock) override {\n    WindowsFileLock* windows_file_lock =\n        reinterpret_cast<WindowsFileLock*>(lock);\n    if (!LockOrUnlock(windows_file_lock->handle().get(), false)) {\n      return WindowsError(\"unlock \" + windows_file_lock->filename(),\n                          ::GetLastError());\n    }\n    delete windows_file_lock;\n    return Status::OK();\n  }\n\n  void Schedule(void (*background_work_function)(void* background_work_arg),\n                void* background_work_arg) override;\n\n  void StartThread(void (*thread_main)(void* thread_main_arg),\n                   void* thread_main_arg) override {\n    std::thread new_thread(thread_main, thread_main_arg);\n    new_thread.detach();\n  }\n\n  Status GetTestDirectory(std::string* result) override {\n    const char* env = getenv(\"TEST_TMPDIR\");\n    if (env && env[0] != '\\0') {\n      *result = env;\n      return Status::OK();\n    }\n\n    wchar_t wtmp_path[MAX_PATH];\n    if (!GetTempPathW(ARRAYSIZE(wtmp_path), wtmp_path)) {\n      return WindowsError(\"GetTempPath\", ::GetLastError());\n    }\n    std::string tmp_path = toUtf8(std::wstring(wtmp_path));\n    std::stringstream ss;\n    ss << tmp_path << \"leveldbtest-\" << std::this_thread::get_id();\n    *result = ss.str();\n\n    // Directory may already exist\n    CreateDir(*result);\n    return Status::OK();\n  }\n\n  Status NewLogger(const std::string& filename, Logger** result) override {\n    auto wFilename = toUtf16(filename);\n    std::FILE* fp = _wfopen(wFilename.c_str(), L\"w\");\n    if (fp == nullptr) {\n      *result = nullptr;\n      return WindowsError(filename, ::GetLastError());\n    } else {\n      *result = new WindowsLogger(fp);\n      return Status::OK();\n    }\n  }\n\n  uint64_t NowMicros() override {\n    // GetSystemTimeAsFileTime typically has a resolution of 10-20 msec.\n    // TODO(cmumford): Switch to GetSystemTimePreciseAsFileTime which is\n    // available in Windows 8 and later.\n    FILETIME ft;\n    ::GetSystemTimeAsFileTime(&ft);\n    // Each tick represents a 100-nanosecond intervals since January 1, 1601\n    // (UTC).\n    uint64_t num_ticks =\n        (static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;\n    return num_ticks / 10;\n  }\n\n  void SleepForMicroseconds(int micros) override {\n    std::this_thread::sleep_for(std::chrono::microseconds(micros));\n  }\n\n private:\n  void BackgroundThreadMain();\n\n  static void BackgroundThreadEntryPoint(WindowsEnv* env) {\n    env->BackgroundThreadMain();\n  }\n\n  // Stores the work item data in a Schedule() call.\n  //\n  // Instances are constructed on the thread calling Schedule() and used on the\n  // background thread.\n  //\n  // This structure is thread-safe beacuse it is immutable.\n  struct BackgroundWorkItem {\n    explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)\n        : function(function), arg(arg) {}\n\n    void (*const function)(void*);\n    void* const arg;\n  };\n\n  port::Mutex background_work_mutex_;\n  port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);\n  bool started_background_thread_ GUARDED_BY(background_work_mutex_);\n\n  std::queue<BackgroundWorkItem> background_work_queue_\n      GUARDED_BY(background_work_mutex_);\n\n  Limiter mmap_limiter_;  // Thread-safe.\n\n  // Converts a Windows wide multi-byte UTF-16 string to a UTF-8 string.\n  // See http://utf8everywhere.org/#windows\n  std::string toUtf8(const std::wstring& wstr) {\n    if (wstr.empty()) return std::string();\n    int size_needed = WideCharToMultiByte(\n        CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);\n    std::string strTo(size_needed, 0);\n    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0],\n                        size_needed, NULL, NULL);\n    return strTo;\n  }\n\n  // Converts a UTF-8 string to a Windows UTF-16 multi-byte wide character\n  // string.\n  // See http://utf8everywhere.org/#windows\n  std::wstring toUtf16(const std::string& str) {\n    if (str.empty()) return std::wstring();\n    int size_needed =\n        MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);\n    std::wstring strTo(size_needed, 0);\n    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &strTo[0],\n                        size_needed);\n    return strTo;\n  }\n};\n\n// Return the maximum number of concurrent mmaps.\nint MaxMmaps() { return g_mmap_limit; }\n\nWindowsEnv::WindowsEnv()\n    : background_work_cv_(&background_work_mutex_),\n      started_background_thread_(false),\n      mmap_limiter_(MaxMmaps()) {}\n\nvoid WindowsEnv::Schedule(\n    void (*background_work_function)(void* background_work_arg),\n    void* background_work_arg) {\n  background_work_mutex_.Lock();\n\n  // Start the background thread, if we haven't done so already.\n  if (!started_background_thread_) {\n    started_background_thread_ = true;\n    std::thread background_thread(WindowsEnv::BackgroundThreadEntryPoint, this);\n    background_thread.detach();\n  }\n\n  // If the queue is empty, the background thread may be waiting for work.\n  if (background_work_queue_.empty()) {\n    background_work_cv_.Signal();\n  }\n\n  background_work_queue_.emplace(background_work_function, background_work_arg);\n  background_work_mutex_.Unlock();\n}\n\nvoid WindowsEnv::BackgroundThreadMain() {\n  while (true) {\n    background_work_mutex_.Lock();\n\n    // Wait until there is work to be done.\n    while (background_work_queue_.empty()) {\n      background_work_cv_.Wait();\n    }\n\n    assert(!background_work_queue_.empty());\n    auto background_work_function = background_work_queue_.front().function;\n    void* background_work_arg = background_work_queue_.front().arg;\n    background_work_queue_.pop();\n\n    background_work_mutex_.Unlock();\n    background_work_function(background_work_arg);\n  }\n}\n\n// Wraps an Env instance whose destructor is never created.\n//\n// Intended usage:\n//   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;\n//   void ConfigurePosixEnv(int param) {\n//     PlatformSingletonEnv::AssertEnvNotInitialized();\n//     // set global configuration flags.\n//   }\n//   Env* Env::Default() {\n//     static PlatformSingletonEnv default_env;\n//     return default_env.env();\n//   }\ntemplate <typename EnvType>\nclass SingletonEnv {\n public:\n  SingletonEnv() {\n#if !defined(NDEBUG)\n    env_initialized_.store(true, std::memory_order::memory_order_relaxed);\n#endif  // !defined(NDEBUG)\n    static_assert(sizeof(env_storage_) >= sizeof(EnvType),\n                  \"env_storage_ will not fit the Env\");\n    static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),\n                  \"env_storage_ does not meet the Env's alignment needs\");\n    new (&env_storage_) EnvType();\n  }\n  ~SingletonEnv() = default;\n\n  SingletonEnv(const SingletonEnv&) = delete;\n  SingletonEnv& operator=(const SingletonEnv&) = delete;\n\n  Env* env() { return reinterpret_cast<Env*>(&env_storage_); }\n\n  static void AssertEnvNotInitialized() {\n#if !defined(NDEBUG)\n    assert(!env_initialized_.load(std::memory_order::memory_order_relaxed));\n#endif  // !defined(NDEBUG)\n  }\n\n private:\n  typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type\n      env_storage_;\n#if !defined(NDEBUG)\n  static std::atomic<bool> env_initialized_;\n#endif  // !defined(NDEBUG)\n};\n\n#if !defined(NDEBUG)\ntemplate <typename EnvType>\nstd::atomic<bool> SingletonEnv<EnvType>::env_initialized_;\n#endif  // !defined(NDEBUG)\n\nusing WindowsDefaultEnv = SingletonEnv<WindowsEnv>;\n\n}  // namespace\n\nvoid EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {\n  WindowsDefaultEnv::AssertEnvNotInitialized();\n  g_mmap_limit = limit;\n}\n\nEnv* Env::Default() {\n  static WindowsDefaultEnv env_container;\n  return env_container.env();\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/env_windows_test.cc",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/env.h\"\n\n#include \"port/port.h\"\n#include \"util/env_windows_test_helper.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nstatic const int kMMapLimit = 4;\n\nclass EnvWindowsTest {\n public:\n  static void SetFileLimits(int mmap_limit) {\n    EnvWindowsTestHelper::SetReadOnlyMMapLimit(mmap_limit);\n  }\n\n  EnvWindowsTest() : env_(Env::Default()) {}\n\n  Env* env_;\n};\n\nTEST(EnvWindowsTest, TestOpenOnRead) {\n  // Write some test data to a single file that will be opened |n| times.\n  std::string test_dir;\n  ASSERT_OK(env_->GetTestDirectory(&test_dir));\n  std::string test_file = test_dir + \"/open_on_read.txt\";\n\n  FILE* f = fopen(test_file.c_str(), \"w\");\n  ASSERT_TRUE(f != nullptr);\n  const char kFileData[] = \"abcdefghijklmnopqrstuvwxyz\";\n  fputs(kFileData, f);\n  fclose(f);\n\n  // Open test file some number above the sum of the two limits to force\n  // leveldb::WindowsEnv to switch from mapping the file into memory\n  // to basic file reading.\n  const int kNumFiles = kMMapLimit + 5;\n  leveldb::RandomAccessFile* files[kNumFiles] = {0};\n  for (int i = 0; i < kNumFiles; i++) {\n    ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i]));\n  }\n  char scratch;\n  Slice read_result;\n  for (int i = 0; i < kNumFiles; i++) {\n    ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch));\n    ASSERT_EQ(kFileData[i], read_result[0]);\n  }\n  for (int i = 0; i < kNumFiles; i++) {\n    delete files[i];\n  }\n  ASSERT_OK(env_->DeleteFile(test_file));\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) {\n  // All tests currently run with the same read-only file limits.\n  leveldb::EnvWindowsTest::SetFileLimits(leveldb::kMMapLimit);\n  return leveldb::test::RunAllTests();\n}\n"
  },
  {
    "path": "src/leveldb/util/env_windows_test_helper.h",
    "content": "// Copyright 2018 (c) The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_\n#define STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_\n\nnamespace leveldb {\n\nclass EnvWindowsTest;\n\n// A helper for the Windows Env to facilitate testing.\nclass EnvWindowsTestHelper {\n private:\n  friend class CorruptionTest;\n  friend class EnvWindowsTest;\n\n  // Set the maximum number of read-only files that will be mapped via mmap.\n  // Must be called before creating an Env.\n  static void SetReadOnlyMMapLimit(int limit);\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_ENV_WINDOWS_TEST_HELPER_H_\n"
  },
  {
    "path": "src/leveldb/util/filter_policy.cc",
    "content": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/filter_policy.h\"\n\nnamespace leveldb {\n\nFilterPolicy::~FilterPolicy() {}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/hash.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/hash.h\"\n\n#include <string.h>\n\n#include \"util/coding.h\"\n\n// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through\n// between switch labels. The real definition should be provided externally.\n// This one is a fallback version for unsupported compilers.\n#ifndef FALLTHROUGH_INTENDED\n#define FALLTHROUGH_INTENDED \\\n  do {                       \\\n  } while (0)\n#endif\n\nnamespace leveldb {\n\nuint32_t Hash(const char* data, size_t n, uint32_t seed) {\n  // Similar to murmur hash\n  const uint32_t m = 0xc6a4a793;\n  const uint32_t r = 24;\n  const char* limit = data + n;\n  uint32_t h = seed ^ (n * m);\n\n  // Pick up four bytes at a time\n  while (data + 4 <= limit) {\n    uint32_t w = DecodeFixed32(data);\n    data += 4;\n    h += w;\n    h *= m;\n    h ^= (h >> 16);\n  }\n\n  // Pick up remaining bytes\n  switch (limit - data) {\n    case 3:\n      h += static_cast<uint8_t>(data[2]) << 16;\n      FALLTHROUGH_INTENDED;\n    case 2:\n      h += static_cast<uint8_t>(data[1]) << 8;\n      FALLTHROUGH_INTENDED;\n    case 1:\n      h += static_cast<uint8_t>(data[0]);\n      h *= m;\n      h ^= (h >> r);\n      break;\n  }\n  return h;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/hash.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Simple hash function used for internal data structures\n\n#ifndef STORAGE_LEVELDB_UTIL_HASH_H_\n#define STORAGE_LEVELDB_UTIL_HASH_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\nnamespace leveldb {\n\nuint32_t Hash(const char* data, size_t n, uint32_t seed);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_HASH_H_\n"
  },
  {
    "path": "src/leveldb/util/hash_test.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/hash.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass HASH {};\n\nTEST(HASH, SignedUnsignedIssue) {\n  const uint8_t data1[1] = {0x62};\n  const uint8_t data2[2] = {0xc3, 0x97};\n  const uint8_t data3[3] = {0xe2, 0x99, 0xa5};\n  const uint8_t data4[4] = {0xe1, 0x80, 0xb9, 0x32};\n  const uint8_t data5[48] = {\n      0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n      0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  };\n\n  ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34);\n  ASSERT_EQ(\n      Hash(reinterpret_cast<const char*>(data1), sizeof(data1), 0xbc9f1d34),\n      0xef1345c4);\n  ASSERT_EQ(\n      Hash(reinterpret_cast<const char*>(data2), sizeof(data2), 0xbc9f1d34),\n      0x5b663814);\n  ASSERT_EQ(\n      Hash(reinterpret_cast<const char*>(data3), sizeof(data3), 0xbc9f1d34),\n      0x323c078f);\n  ASSERT_EQ(\n      Hash(reinterpret_cast<const char*>(data4), sizeof(data4), 0xbc9f1d34),\n      0xed21633a);\n  ASSERT_EQ(\n      Hash(reinterpret_cast<const char*>(data5), sizeof(data5), 0x12345678),\n      0xf333dabb);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/histogram.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/histogram.h\"\n\n#include <math.h>\n#include <stdio.h>\n\n#include \"port/port.h\"\n\nnamespace leveldb {\n\nconst double Histogram::kBucketLimit[kNumBuckets] = {\n    1,\n    2,\n    3,\n    4,\n    5,\n    6,\n    7,\n    8,\n    9,\n    10,\n    12,\n    14,\n    16,\n    18,\n    20,\n    25,\n    30,\n    35,\n    40,\n    45,\n    50,\n    60,\n    70,\n    80,\n    90,\n    100,\n    120,\n    140,\n    160,\n    180,\n    200,\n    250,\n    300,\n    350,\n    400,\n    450,\n    500,\n    600,\n    700,\n    800,\n    900,\n    1000,\n    1200,\n    1400,\n    1600,\n    1800,\n    2000,\n    2500,\n    3000,\n    3500,\n    4000,\n    4500,\n    5000,\n    6000,\n    7000,\n    8000,\n    9000,\n    10000,\n    12000,\n    14000,\n    16000,\n    18000,\n    20000,\n    25000,\n    30000,\n    35000,\n    40000,\n    45000,\n    50000,\n    60000,\n    70000,\n    80000,\n    90000,\n    100000,\n    120000,\n    140000,\n    160000,\n    180000,\n    200000,\n    250000,\n    300000,\n    350000,\n    400000,\n    450000,\n    500000,\n    600000,\n    700000,\n    800000,\n    900000,\n    1000000,\n    1200000,\n    1400000,\n    1600000,\n    1800000,\n    2000000,\n    2500000,\n    3000000,\n    3500000,\n    4000000,\n    4500000,\n    5000000,\n    6000000,\n    7000000,\n    8000000,\n    9000000,\n    10000000,\n    12000000,\n    14000000,\n    16000000,\n    18000000,\n    20000000,\n    25000000,\n    30000000,\n    35000000,\n    40000000,\n    45000000,\n    50000000,\n    60000000,\n    70000000,\n    80000000,\n    90000000,\n    100000000,\n    120000000,\n    140000000,\n    160000000,\n    180000000,\n    200000000,\n    250000000,\n    300000000,\n    350000000,\n    400000000,\n    450000000,\n    500000000,\n    600000000,\n    700000000,\n    800000000,\n    900000000,\n    1000000000,\n    1200000000,\n    1400000000,\n    1600000000,\n    1800000000,\n    2000000000,\n    2500000000.0,\n    3000000000.0,\n    3500000000.0,\n    4000000000.0,\n    4500000000.0,\n    5000000000.0,\n    6000000000.0,\n    7000000000.0,\n    8000000000.0,\n    9000000000.0,\n    1e200,\n};\n\nvoid Histogram::Clear() {\n  min_ = kBucketLimit[kNumBuckets - 1];\n  max_ = 0;\n  num_ = 0;\n  sum_ = 0;\n  sum_squares_ = 0;\n  for (int i = 0; i < kNumBuckets; i++) {\n    buckets_[i] = 0;\n  }\n}\n\nvoid Histogram::Add(double value) {\n  // Linear search is fast enough for our usage in db_bench\n  int b = 0;\n  while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) {\n    b++;\n  }\n  buckets_[b] += 1.0;\n  if (min_ > value) min_ = value;\n  if (max_ < value) max_ = value;\n  num_++;\n  sum_ += value;\n  sum_squares_ += (value * value);\n}\n\nvoid Histogram::Merge(const Histogram& other) {\n  if (other.min_ < min_) min_ = other.min_;\n  if (other.max_ > max_) max_ = other.max_;\n  num_ += other.num_;\n  sum_ += other.sum_;\n  sum_squares_ += other.sum_squares_;\n  for (int b = 0; b < kNumBuckets; b++) {\n    buckets_[b] += other.buckets_[b];\n  }\n}\n\ndouble Histogram::Median() const { return Percentile(50.0); }\n\ndouble Histogram::Percentile(double p) const {\n  double threshold = num_ * (p / 100.0);\n  double sum = 0;\n  for (int b = 0; b < kNumBuckets; b++) {\n    sum += buckets_[b];\n    if (sum >= threshold) {\n      // Scale linearly within this bucket\n      double left_point = (b == 0) ? 0 : kBucketLimit[b - 1];\n      double right_point = kBucketLimit[b];\n      double left_sum = sum - buckets_[b];\n      double right_sum = sum;\n      double pos = (threshold - left_sum) / (right_sum - left_sum);\n      double r = left_point + (right_point - left_point) * pos;\n      if (r < min_) r = min_;\n      if (r > max_) r = max_;\n      return r;\n    }\n  }\n  return max_;\n}\n\ndouble Histogram::Average() const {\n  if (num_ == 0.0) return 0;\n  return sum_ / num_;\n}\n\ndouble Histogram::StandardDeviation() const {\n  if (num_ == 0.0) return 0;\n  double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_);\n  return sqrt(variance);\n}\n\nstd::string Histogram::ToString() const {\n  std::string r;\n  char buf[200];\n  snprintf(buf, sizeof(buf), \"Count: %.0f  Average: %.4f  StdDev: %.2f\\n\", num_,\n           Average(), StandardDeviation());\n  r.append(buf);\n  snprintf(buf, sizeof(buf), \"Min: %.4f  Median: %.4f  Max: %.4f\\n\",\n           (num_ == 0.0 ? 0.0 : min_), Median(), max_);\n  r.append(buf);\n  r.append(\"------------------------------------------------------\\n\");\n  const double mult = 100.0 / num_;\n  double sum = 0;\n  for (int b = 0; b < kNumBuckets; b++) {\n    if (buckets_[b] <= 0.0) continue;\n    sum += buckets_[b];\n    snprintf(buf, sizeof(buf), \"[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% \",\n             ((b == 0) ? 0.0 : kBucketLimit[b - 1]),  // left\n             kBucketLimit[b],                         // right\n             buckets_[b],                             // count\n             mult * buckets_[b],                      // percentage\n             mult * sum);                             // cumulative percentage\n    r.append(buf);\n\n    // Add hash marks based on percentage; 20 marks for 100%.\n    int marks = static_cast<int>(20 * (buckets_[b] / num_) + 0.5);\n    r.append(marks, '#');\n    r.push_back('\\n');\n  }\n  return r;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/histogram.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_\n#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_\n\n#include <string>\n\nnamespace leveldb {\n\nclass Histogram {\n public:\n  Histogram() {}\n  ~Histogram() {}\n\n  void Clear();\n  void Add(double value);\n  void Merge(const Histogram& other);\n\n  std::string ToString() const;\n\n private:\n  enum { kNumBuckets = 154 };\n\n  double Median() const;\n  double Percentile(double p) const;\n  double Average() const;\n  double StandardDeviation() const;\n\n  static const double kBucketLimit[kNumBuckets];\n\n  double min_;\n  double max_;\n  double num_;\n  double sum_;\n  double sum_squares_;\n\n  double buckets_[kNumBuckets];\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_\n"
  },
  {
    "path": "src/leveldb/util/logging.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/logging.h\"\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <limits>\n\n#include \"leveldb/env.h\"\n#include \"leveldb/slice.h\"\n\nnamespace leveldb {\n\nvoid AppendNumberTo(std::string* str, uint64_t num) {\n  char buf[30];\n  snprintf(buf, sizeof(buf), \"%llu\", (unsigned long long)num);\n  str->append(buf);\n}\n\nvoid AppendEscapedStringTo(std::string* str, const Slice& value) {\n  for (size_t i = 0; i < value.size(); i++) {\n    char c = value[i];\n    if (c >= ' ' && c <= '~') {\n      str->push_back(c);\n    } else {\n      char buf[10];\n      snprintf(buf, sizeof(buf), \"\\\\x%02x\",\n               static_cast<unsigned int>(c) & 0xff);\n      str->append(buf);\n    }\n  }\n}\n\nstd::string NumberToString(uint64_t num) {\n  std::string r;\n  AppendNumberTo(&r, num);\n  return r;\n}\n\nstd::string EscapeString(const Slice& value) {\n  std::string r;\n  AppendEscapedStringTo(&r, value);\n  return r;\n}\n\nbool ConsumeDecimalNumber(Slice* in, uint64_t* val) {\n  // Constants that will be optimized away.\n  constexpr const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max();\n  constexpr const char kLastDigitOfMaxUint64 =\n      '0' + static_cast<char>(kMaxUint64 % 10);\n\n  uint64_t value = 0;\n\n  // reinterpret_cast-ing from char* to uint8_t* to avoid signedness.\n  const uint8_t* start = reinterpret_cast<const uint8_t*>(in->data());\n\n  const uint8_t* end = start + in->size();\n  const uint8_t* current = start;\n  for (; current != end; ++current) {\n    const uint8_t ch = *current;\n    if (ch < '0' || ch > '9') break;\n\n    // Overflow check.\n    // kMaxUint64 / 10 is also constant and will be optimized away.\n    if (value > kMaxUint64 / 10 ||\n        (value == kMaxUint64 / 10 && ch > kLastDigitOfMaxUint64)) {\n      return false;\n    }\n\n    value = (value * 10) + (ch - '0');\n  }\n\n  *val = value;\n  const size_t digits_consumed = current - start;\n  in->remove_prefix(digits_consumed);\n  return digits_consumed != 0;\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/logging.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Must not be included from any .h files to avoid polluting the namespace\n// with macros.\n\n#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_\n#define STORAGE_LEVELDB_UTIL_LOGGING_H_\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include <string>\n\n#include \"port/port.h\"\n\nnamespace leveldb {\n\nclass Slice;\nclass WritableFile;\n\n// Append a human-readable printout of \"num\" to *str\nvoid AppendNumberTo(std::string* str, uint64_t num);\n\n// Append a human-readable printout of \"value\" to *str.\n// Escapes any non-printable characters found in \"value\".\nvoid AppendEscapedStringTo(std::string* str, const Slice& value);\n\n// Return a human-readable printout of \"num\"\nstd::string NumberToString(uint64_t num);\n\n// Return a human-readable version of \"value\".\n// Escapes any non-printable characters found in \"value\".\nstd::string EscapeString(const Slice& value);\n\n// Parse a human-readable number from \"*in\" into *value.  On success,\n// advances \"*in\" past the consumed number and sets \"*val\" to the\n// numeric value.  Otherwise, returns false and leaves *in in an\n// unspecified state.\nbool ConsumeDecimalNumber(Slice* in, uint64_t* val);\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_LOGGING_H_\n"
  },
  {
    "path": "src/leveldb/util/logging_test.cc",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <limits>\n#include <string>\n\n#include \"leveldb/slice.h\"\n#include \"util/logging.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nclass Logging {};\n\nTEST(Logging, NumberToString) {\n  ASSERT_EQ(\"0\", NumberToString(0));\n  ASSERT_EQ(\"1\", NumberToString(1));\n  ASSERT_EQ(\"9\", NumberToString(9));\n\n  ASSERT_EQ(\"10\", NumberToString(10));\n  ASSERT_EQ(\"11\", NumberToString(11));\n  ASSERT_EQ(\"19\", NumberToString(19));\n  ASSERT_EQ(\"99\", NumberToString(99));\n\n  ASSERT_EQ(\"100\", NumberToString(100));\n  ASSERT_EQ(\"109\", NumberToString(109));\n  ASSERT_EQ(\"190\", NumberToString(190));\n  ASSERT_EQ(\"123\", NumberToString(123));\n  ASSERT_EQ(\"12345678\", NumberToString(12345678));\n\n  static_assert(std::numeric_limits<uint64_t>::max() == 18446744073709551615U,\n                \"Test consistency check\");\n  ASSERT_EQ(\"18446744073709551000\", NumberToString(18446744073709551000U));\n  ASSERT_EQ(\"18446744073709551600\", NumberToString(18446744073709551600U));\n  ASSERT_EQ(\"18446744073709551610\", NumberToString(18446744073709551610U));\n  ASSERT_EQ(\"18446744073709551614\", NumberToString(18446744073709551614U));\n  ASSERT_EQ(\"18446744073709551615\", NumberToString(18446744073709551615U));\n}\n\nvoid ConsumeDecimalNumberRoundtripTest(uint64_t number,\n                                       const std::string& padding = \"\") {\n  std::string decimal_number = NumberToString(number);\n  std::string input_string = decimal_number + padding;\n  Slice input(input_string);\n  Slice output = input;\n  uint64_t result;\n  ASSERT_TRUE(ConsumeDecimalNumber(&output, &result));\n  ASSERT_EQ(number, result);\n  ASSERT_EQ(decimal_number.size(), output.data() - input.data());\n  ASSERT_EQ(padding.size(), output.size());\n}\n\nTEST(Logging, ConsumeDecimalNumberRoundtrip) {\n  ConsumeDecimalNumberRoundtripTest(0);\n  ConsumeDecimalNumberRoundtripTest(1);\n  ConsumeDecimalNumberRoundtripTest(9);\n\n  ConsumeDecimalNumberRoundtripTest(10);\n  ConsumeDecimalNumberRoundtripTest(11);\n  ConsumeDecimalNumberRoundtripTest(19);\n  ConsumeDecimalNumberRoundtripTest(99);\n\n  ConsumeDecimalNumberRoundtripTest(100);\n  ConsumeDecimalNumberRoundtripTest(109);\n  ConsumeDecimalNumberRoundtripTest(190);\n  ConsumeDecimalNumberRoundtripTest(123);\n  ASSERT_EQ(\"12345678\", NumberToString(12345678));\n\n  for (uint64_t i = 0; i < 100; ++i) {\n    uint64_t large_number = std::numeric_limits<uint64_t>::max() - i;\n    ConsumeDecimalNumberRoundtripTest(large_number);\n  }\n}\n\nTEST(Logging, ConsumeDecimalNumberRoundtripWithPadding) {\n  ConsumeDecimalNumberRoundtripTest(0, \" \");\n  ConsumeDecimalNumberRoundtripTest(1, \"abc\");\n  ConsumeDecimalNumberRoundtripTest(9, \"x\");\n\n  ConsumeDecimalNumberRoundtripTest(10, \"_\");\n  ConsumeDecimalNumberRoundtripTest(11, std::string(\"\\0\\0\\0\", 3));\n  ConsumeDecimalNumberRoundtripTest(19, \"abc\");\n  ConsumeDecimalNumberRoundtripTest(99, \"padding\");\n\n  ConsumeDecimalNumberRoundtripTest(100, \" \");\n\n  for (uint64_t i = 0; i < 100; ++i) {\n    uint64_t large_number = std::numeric_limits<uint64_t>::max() - i;\n    ConsumeDecimalNumberRoundtripTest(large_number, \"pad\");\n  }\n}\n\nvoid ConsumeDecimalNumberOverflowTest(const std::string& input_string) {\n  Slice input(input_string);\n  Slice output = input;\n  uint64_t result;\n  ASSERT_EQ(false, ConsumeDecimalNumber(&output, &result));\n}\n\nTEST(Logging, ConsumeDecimalNumberOverflow) {\n  static_assert(std::numeric_limits<uint64_t>::max() == 18446744073709551615U,\n                \"Test consistency check\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551616\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551617\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551618\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551619\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551620\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551621\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551622\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551623\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551624\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551625\");\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551626\");\n\n  ConsumeDecimalNumberOverflowTest(\"18446744073709551700\");\n\n  ConsumeDecimalNumberOverflowTest(\"99999999999999999999\");\n}\n\nvoid ConsumeDecimalNumberNoDigitsTest(const std::string& input_string) {\n  Slice input(input_string);\n  Slice output = input;\n  uint64_t result;\n  ASSERT_EQ(false, ConsumeDecimalNumber(&output, &result));\n  ASSERT_EQ(input.data(), output.data());\n  ASSERT_EQ(input.size(), output.size());\n}\n\nTEST(Logging, ConsumeDecimalNumberNoDigits) {\n  ConsumeDecimalNumberNoDigitsTest(\"\");\n  ConsumeDecimalNumberNoDigitsTest(\" \");\n  ConsumeDecimalNumberNoDigitsTest(\"a\");\n  ConsumeDecimalNumberNoDigitsTest(\" 123\");\n  ConsumeDecimalNumberNoDigitsTest(\"a123\");\n  ConsumeDecimalNumberNoDigitsTest(std::string(\"\\000123\", 4));\n  ConsumeDecimalNumberNoDigitsTest(std::string(\"\\177123\", 4));\n  ConsumeDecimalNumberNoDigitsTest(std::string(\"\\377123\", 4));\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/mutexlock.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_\n#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_\n\n#include \"port/port.h\"\n#include \"port/thread_annotations.h\"\n\nnamespace leveldb {\n\n// Helper class that locks a mutex on construction and unlocks the mutex when\n// the destructor of the MutexLock object is invoked.\n//\n// Typical usage:\n//\n//   void MyClass::MyMethod() {\n//     MutexLock l(&mu_);       // mu_ is an instance variable\n//     ... some complex code, possibly with multiple return paths ...\n//   }\n\nclass SCOPED_LOCKABLE MutexLock {\n public:\n  explicit MutexLock(port::Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {\n    this->mu_->Lock();\n  }\n  ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }\n\n  MutexLock(const MutexLock&) = delete;\n  MutexLock& operator=(const MutexLock&) = delete;\n\n private:\n  port::Mutex* const mu_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_\n"
  },
  {
    "path": "src/leveldb/util/no_destructor.h",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_\n#define STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_\n\n#include <type_traits>\n#include <utility>\n\nnamespace leveldb {\n\n// Wraps an instance whose destructor is never called.\n//\n// This is intended for use with function-level static variables.\ntemplate <typename InstanceType>\nclass NoDestructor {\n public:\n  template <typename... ConstructorArgTypes>\n  explicit NoDestructor(ConstructorArgTypes&&... constructor_args) {\n    static_assert(sizeof(instance_storage_) >= sizeof(InstanceType),\n                  \"instance_storage_ is not large enough to hold the instance\");\n    static_assert(\n        alignof(decltype(instance_storage_)) >= alignof(InstanceType),\n        \"instance_storage_ does not meet the instance's alignment requirement\");\n    new (&instance_storage_)\n        InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...);\n  }\n\n  ~NoDestructor() = default;\n\n  NoDestructor(const NoDestructor&) = delete;\n  NoDestructor& operator=(const NoDestructor&) = delete;\n\n  InstanceType* get() {\n    return reinterpret_cast<InstanceType*>(&instance_storage_);\n  }\n\n private:\n  typename std::aligned_storage<sizeof(InstanceType),\n                                alignof(InstanceType)>::type instance_storage_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_\n"
  },
  {
    "path": "src/leveldb/util/no_destructor_test.cc",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <cstdint>\n#include <cstdlib>\n#include <utility>\n\n#include \"util/no_destructor.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nnamespace {\n\nstruct DoNotDestruct {\n public:\n  DoNotDestruct(uint32_t a, uint64_t b) : a(a), b(b) {}\n  ~DoNotDestruct() { std::abort(); }\n\n  // Used to check constructor argument forwarding.\n  uint32_t a;\n  uint64_t b;\n};\n\nconstexpr const uint32_t kGoldenA = 0xdeadbeef;\nconstexpr const uint64_t kGoldenB = 0xaabbccddeeffaabb;\n\n}  // namespace\n\nclass NoDestructorTest {};\n\nTEST(NoDestructorTest, StackInstance) {\n  NoDestructor<DoNotDestruct> instance(kGoldenA, kGoldenB);\n  ASSERT_EQ(kGoldenA, instance.get()->a);\n  ASSERT_EQ(kGoldenB, instance.get()->b);\n}\n\nTEST(NoDestructorTest, StaticInstance) {\n  static NoDestructor<DoNotDestruct> instance(kGoldenA, kGoldenB);\n  ASSERT_EQ(kGoldenA, instance.get()->a);\n  ASSERT_EQ(kGoldenB, instance.get()->b);\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/options.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/options.h\"\n\n#include \"leveldb/comparator.h\"\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\n\nOptions::Options() : comparator(BytewiseComparator()), env(Env::Default()) {}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/posix_logger.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Logger implementation that can be shared by all environments\n// where enough posix functionality is available.\n\n#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_\n#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_\n\n#include <sys/time.h>\n\n#include <cassert>\n#include <cstdarg>\n#include <cstdio>\n#include <ctime>\n#include <sstream>\n#include <thread>\n\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\n\nclass PosixLogger final : public Logger {\n public:\n  // Creates a logger that writes to the given file.\n  //\n  // The PosixLogger instance takes ownership of the file handle.\n  explicit PosixLogger(std::FILE* fp) : fp_(fp) { assert(fp != nullptr); }\n\n  ~PosixLogger() override { std::fclose(fp_); }\n\n  void Logv(const char* format, va_list arguments) override {\n    // Record the time as close to the Logv() call as possible.\n    struct ::timeval now_timeval;\n    ::gettimeofday(&now_timeval, nullptr);\n    const std::time_t now_seconds = now_timeval.tv_sec;\n    struct std::tm now_components;\n    ::localtime_r(&now_seconds, &now_components);\n\n    // Record the thread ID.\n    constexpr const int kMaxThreadIdSize = 32;\n    std::ostringstream thread_stream;\n    thread_stream << std::this_thread::get_id();\n    std::string thread_id = thread_stream.str();\n    if (thread_id.size() > kMaxThreadIdSize) {\n      thread_id.resize(kMaxThreadIdSize);\n    }\n\n    // We first attempt to print into a stack-allocated buffer. If this attempt\n    // fails, we make a second attempt with a dynamically allocated buffer.\n    constexpr const int kStackBufferSize = 512;\n    char stack_buffer[kStackBufferSize];\n    static_assert(sizeof(stack_buffer) == static_cast<size_t>(kStackBufferSize),\n                  \"sizeof(char) is expected to be 1 in C++\");\n\n    int dynamic_buffer_size = 0;  // Computed in the first iteration.\n    for (int iteration = 0; iteration < 2; ++iteration) {\n      const int buffer_size =\n          (iteration == 0) ? kStackBufferSize : dynamic_buffer_size;\n      char* const buffer =\n          (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size];\n\n      // Print the header into the buffer.\n      int buffer_offset = snprintf(\n          buffer, buffer_size, \"%04d/%02d/%02d-%02d:%02d:%02d.%06d %s \",\n          now_components.tm_year + 1900, now_components.tm_mon + 1,\n          now_components.tm_mday, now_components.tm_hour, now_components.tm_min,\n          now_components.tm_sec, static_cast<int>(now_timeval.tv_usec),\n          thread_id.c_str());\n\n      // The header can be at most 28 characters (10 date + 15 time +\n      // 3 delimiters) plus the thread ID, which should fit comfortably into the\n      // static buffer.\n      assert(buffer_offset <= 28 + kMaxThreadIdSize);\n      static_assert(28 + kMaxThreadIdSize < kStackBufferSize,\n                    \"stack-allocated buffer may not fit the message header\");\n      assert(buffer_offset < buffer_size);\n\n      // Print the message into the buffer.\n      std::va_list arguments_copy;\n      va_copy(arguments_copy, arguments);\n      buffer_offset +=\n          std::vsnprintf(buffer + buffer_offset, buffer_size - buffer_offset,\n                         format, arguments_copy);\n      va_end(arguments_copy);\n\n      // The code below may append a newline at the end of the buffer, which\n      // requires an extra character.\n      if (buffer_offset >= buffer_size - 1) {\n        // The message did not fit into the buffer.\n        if (iteration == 0) {\n          // Re-run the loop and use a dynamically-allocated buffer. The buffer\n          // will be large enough for the log message, an extra newline and a\n          // null terminator.\n          dynamic_buffer_size = buffer_offset + 2;\n          continue;\n        }\n\n        // The dynamically-allocated buffer was incorrectly sized. This should\n        // not happen, assuming a correct implementation of (v)snprintf. Fail\n        // in tests, recover by truncating the log message in production.\n        assert(false);\n        buffer_offset = buffer_size - 1;\n      }\n\n      // Add a newline if necessary.\n      if (buffer[buffer_offset - 1] != '\\n') {\n        buffer[buffer_offset] = '\\n';\n        ++buffer_offset;\n      }\n\n      assert(buffer_offset <= buffer_size);\n      std::fwrite(buffer, 1, buffer_offset, fp_);\n      std::fflush(fp_);\n\n      if (iteration != 0) {\n        delete[] buffer;\n      }\n      break;\n    }\n  }\n\n private:\n  std::FILE* const fp_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_\n"
  },
  {
    "path": "src/leveldb/util/random.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_\n#define STORAGE_LEVELDB_UTIL_RANDOM_H_\n\n#include <stdint.h>\n\nnamespace leveldb {\n\n// A very simple random number generator.  Not especially good at\n// generating truly random bits, but good enough for our needs in this\n// package.\nclass Random {\n private:\n  uint32_t seed_;\n\n public:\n  explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) {\n    // Avoid bad seeds.\n    if (seed_ == 0 || seed_ == 2147483647L) {\n      seed_ = 1;\n    }\n  }\n  uint32_t Next() {\n    static const uint32_t M = 2147483647L;  // 2^31-1\n    static const uint64_t A = 16807;        // bits 14, 8, 7, 5, 2, 1, 0\n    // We are computing\n    //       seed_ = (seed_ * A) % M,    where M = 2^31-1\n    //\n    // seed_ must not be zero or M, or else all subsequent computed values\n    // will be zero or M respectively.  For all other values, seed_ will end\n    // up cycling through every number in [1,M-1]\n    uint64_t product = seed_ * A;\n\n    // Compute (product % M) using the fact that ((x << 31) % M) == x.\n    seed_ = static_cast<uint32_t>((product >> 31) + (product & M));\n    // The first reduction may overflow by 1 bit, so we may need to\n    // repeat.  mod == M is not possible; using > allows the faster\n    // sign-bit-based test.\n    if (seed_ > M) {\n      seed_ -= M;\n    }\n    return seed_;\n  }\n  // Returns a uniformly distributed value in the range [0..n-1]\n  // REQUIRES: n > 0\n  uint32_t Uniform(int n) { return Next() % n; }\n\n  // Randomly returns true ~\"1/n\" of the time, and false otherwise.\n  // REQUIRES: n > 0\n  bool OneIn(int n) { return (Next() % n) == 0; }\n\n  // Skewed: pick \"base\" uniformly from range [0,max_log] and then\n  // return \"base\" random bits.  The effect is to pick a number in the\n  // range [0,2^max_log-1] with exponential bias towards smaller numbers.\n  uint32_t Skewed(int max_log) { return Uniform(1 << Uniform(max_log + 1)); }\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_RANDOM_H_\n"
  },
  {
    "path": "src/leveldb/util/status.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"leveldb/status.h\"\n\n#include <stdio.h>\n\n#include \"port/port.h\"\n\nnamespace leveldb {\n\nconst char* Status::CopyState(const char* state) {\n  uint32_t size;\n  memcpy(&size, state, sizeof(size));\n  char* result = new char[size + 5];\n  memcpy(result, state, size + 5);\n  return result;\n}\n\nStatus::Status(Code code, const Slice& msg, const Slice& msg2) {\n  assert(code != kOk);\n  const uint32_t len1 = static_cast<uint32_t>(msg.size());\n  const uint32_t len2 = static_cast<uint32_t>(msg2.size());\n  const uint32_t size = len1 + (len2 ? (2 + len2) : 0);\n  char* result = new char[size + 5];\n  memcpy(result, &size, sizeof(size));\n  result[4] = static_cast<char>(code);\n  memcpy(result + 5, msg.data(), len1);\n  if (len2) {\n    result[5 + len1] = ':';\n    result[6 + len1] = ' ';\n    memcpy(result + 7 + len1, msg2.data(), len2);\n  }\n  state_ = result;\n}\n\nstd::string Status::ToString() const {\n  if (state_ == nullptr) {\n    return \"OK\";\n  } else {\n    char tmp[30];\n    const char* type;\n    switch (code()) {\n      case kOk:\n        type = \"OK\";\n        break;\n      case kNotFound:\n        type = \"NotFound: \";\n        break;\n      case kCorruption:\n        type = \"Corruption: \";\n        break;\n      case kNotSupported:\n        type = \"Not implemented: \";\n        break;\n      case kInvalidArgument:\n        type = \"Invalid argument: \";\n        break;\n      case kIOError:\n        type = \"IO error: \";\n        break;\n      default:\n        snprintf(tmp, sizeof(tmp),\n                 \"Unknown code(%d): \", static_cast<int>(code()));\n        type = tmp;\n        break;\n    }\n    std::string result(type);\n    uint32_t length;\n    memcpy(&length, state_, sizeof(length));\n    result.append(state_ + 5, length);\n    return result;\n  }\n}\n\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/status_test.cc",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include <utility>\n\n#include \"leveldb/slice.h\"\n#include \"leveldb/status.h\"\n#include \"util/testharness.h\"\n\nnamespace leveldb {\n\nTEST(Status, MoveConstructor) {\n  {\n    Status ok = Status::OK();\n    Status ok2 = std::move(ok);\n\n    ASSERT_TRUE(ok2.ok());\n  }\n\n  {\n    Status status = Status::NotFound(\"custom NotFound status message\");\n    Status status2 = std::move(status);\n\n    ASSERT_TRUE(status2.IsNotFound());\n    ASSERT_EQ(\"NotFound: custom NotFound status message\", status2.ToString());\n  }\n\n  {\n    Status self_moved = Status::IOError(\"custom IOError status message\");\n\n    // Needed to bypass compiler warning about explicit move-assignment.\n    Status& self_moved_reference = self_moved;\n    self_moved_reference = std::move(self_moved);\n  }\n}\n\n}  // namespace leveldb\n\nint main(int argc, char** argv) { return leveldb::test::RunAllTests(); }\n"
  },
  {
    "path": "src/leveldb/util/testharness.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/testharness.h\"\n\n#include <stdlib.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include <string>\n#include <vector>\n\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\nnamespace test {\n\nnamespace {\nstruct Test {\n  const char* base;\n  const char* name;\n  void (*func)();\n};\nstd::vector<Test>* tests;\n}  // namespace\n\nbool RegisterTest(const char* base, const char* name, void (*func)()) {\n  if (tests == nullptr) {\n    tests = new std::vector<Test>;\n  }\n  Test t;\n  t.base = base;\n  t.name = name;\n  t.func = func;\n  tests->push_back(t);\n  return true;\n}\n\nint RunAllTests() {\n  const char* matcher = getenv(\"LEVELDB_TESTS\");\n\n  int num = 0;\n  if (tests != nullptr) {\n    for (size_t i = 0; i < tests->size(); i++) {\n      const Test& t = (*tests)[i];\n      if (matcher != nullptr) {\n        std::string name = t.base;\n        name.push_back('.');\n        name.append(t.name);\n        if (strstr(name.c_str(), matcher) == nullptr) {\n          continue;\n        }\n      }\n      fprintf(stderr, \"==== Test %s.%s\\n\", t.base, t.name);\n      (*t.func)();\n      ++num;\n    }\n  }\n  fprintf(stderr, \"==== PASSED %d tests\\n\", num);\n  return 0;\n}\n\nstd::string TmpDir() {\n  std::string dir;\n  Status s = Env::Default()->GetTestDirectory(&dir);\n  ASSERT_TRUE(s.ok()) << s.ToString();\n  return dir;\n}\n\nint RandomSeed() {\n  const char* env = getenv(\"TEST_RANDOM_SEED\");\n  int result = (env != nullptr ? atoi(env) : 301);\n  if (result <= 0) {\n    result = 301;\n  }\n  return result;\n}\n\n}  // namespace test\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/testharness.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_\n#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <sstream>\n\n#include \"leveldb/status.h\"\n\nnamespace leveldb {\nnamespace test {\n\n// Run some of the tests registered by the TEST() macro.  If the\n// environment variable \"LEVELDB_TESTS\" is not set, runs all tests.\n// Otherwise, runs only the tests whose name contains the value of\n// \"LEVELDB_TESTS\" as a substring.  E.g., suppose the tests are:\n//    TEST(Foo, Hello) { ... }\n//    TEST(Foo, World) { ... }\n// LEVELDB_TESTS=Hello will run the first test\n// LEVELDB_TESTS=o     will run both tests\n// LEVELDB_TESTS=Junk  will run no tests\n//\n// Returns 0 if all tests pass.\n// Dies or returns a non-zero value if some test fails.\nint RunAllTests();\n\n// Return the directory to use for temporary storage.\nstd::string TmpDir();\n\n// Return a randomization seed for this run.  Typically returns the\n// same number on repeated invocations of this binary, but automated\n// runs may be able to vary the seed.\nint RandomSeed();\n\n// An instance of Tester is allocated to hold temporary state during\n// the execution of an assertion.\nclass Tester {\n private:\n  bool ok_;\n  const char* fname_;\n  int line_;\n  std::stringstream ss_;\n\n public:\n  Tester(const char* f, int l) : ok_(true), fname_(f), line_(l) {}\n\n  ~Tester() {\n    if (!ok_) {\n      fprintf(stderr, \"%s:%d:%s\\n\", fname_, line_, ss_.str().c_str());\n      exit(1);\n    }\n  }\n\n  Tester& Is(bool b, const char* msg) {\n    if (!b) {\n      ss_ << \" Assertion failure \" << msg;\n      ok_ = false;\n    }\n    return *this;\n  }\n\n  Tester& IsOk(const Status& s) {\n    if (!s.ok()) {\n      ss_ << \" \" << s.ToString();\n      ok_ = false;\n    }\n    return *this;\n  }\n\n#define BINARY_OP(name, op)                          \\\n  template <class X, class Y>                        \\\n  Tester& name(const X& x, const Y& y) {             \\\n    if (!(x op y)) {                                 \\\n      ss_ << \" failed: \" << x << (\" \" #op \" \") << y; \\\n      ok_ = false;                                   \\\n    }                                                \\\n    return *this;                                    \\\n  }\n\n  BINARY_OP(IsEq, ==)\n  BINARY_OP(IsNe, !=)\n  BINARY_OP(IsGe, >=)\n  BINARY_OP(IsGt, >)\n  BINARY_OP(IsLe, <=)\n  BINARY_OP(IsLt, <)\n#undef BINARY_OP\n\n  // Attach the specified value to the error message if an error has occurred\n  template <class V>\n  Tester& operator<<(const V& value) {\n    if (!ok_) {\n      ss_ << \" \" << value;\n    }\n    return *this;\n  }\n};\n\n#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c)\n#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s))\n#define ASSERT_EQ(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a), (b))\n#define ASSERT_NE(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a), (b))\n#define ASSERT_GE(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a), (b))\n#define ASSERT_GT(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a), (b))\n#define ASSERT_LE(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a), (b))\n#define ASSERT_LT(a, b) \\\n  ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a), (b))\n\n#define TCONCAT(a, b) TCONCAT1(a, b)\n#define TCONCAT1(a, b) a##b\n\n#define TEST(base, name)                                              \\\n  class TCONCAT(_Test_, name) : public base {                         \\\n   public:                                                            \\\n    void _Run();                                                      \\\n    static void _RunIt() {                                            \\\n      TCONCAT(_Test_, name) t;                                        \\\n      t._Run();                                                       \\\n    }                                                                 \\\n  };                                                                  \\\n  bool TCONCAT(_Test_ignored_, name) = ::leveldb::test::RegisterTest( \\\n      #base, #name, &TCONCAT(_Test_, name)::_RunIt);                  \\\n  void TCONCAT(_Test_, name)::_Run()\n\n// Register the specified test.  Typically not used directly, but\n// invoked via the macro expansion of TEST.\nbool RegisterTest(const char* base, const char* name, void (*func)());\n\n}  // namespace test\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_\n"
  },
  {
    "path": "src/leveldb/util/testutil.cc",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#include \"util/testutil.h\"\n\n#include \"util/random.h\"\n\nnamespace leveldb {\nnamespace test {\n\nSlice RandomString(Random* rnd, int len, std::string* dst) {\n  dst->resize(len);\n  for (int i = 0; i < len; i++) {\n    (*dst)[i] = static_cast<char>(' ' + rnd->Uniform(95));  // ' ' .. '~'\n  }\n  return Slice(*dst);\n}\n\nstd::string RandomKey(Random* rnd, int len) {\n  // Make sure to generate a wide variety of characters so we\n  // test the boundary conditions for short-key optimizations.\n  static const char kTestChars[] = {'\\0', '\\1', 'a',    'b',    'c',\n                                    'd',  'e',  '\\xfd', '\\xfe', '\\xff'};\n  std::string result;\n  for (int i = 0; i < len; i++) {\n    result += kTestChars[rnd->Uniform(sizeof(kTestChars))];\n  }\n  return result;\n}\n\nSlice CompressibleString(Random* rnd, double compressed_fraction, size_t len,\n                         std::string* dst) {\n  int raw = static_cast<int>(len * compressed_fraction);\n  if (raw < 1) raw = 1;\n  std::string raw_data;\n  RandomString(rnd, raw, &raw_data);\n\n  // Duplicate the random data until we have filled \"len\" bytes\n  dst->clear();\n  while (dst->size() < len) {\n    dst->append(raw_data);\n  }\n  dst->resize(len);\n  return Slice(*dst);\n}\n\n}  // namespace test\n}  // namespace leveldb\n"
  },
  {
    "path": "src/leveldb/util/testutil.h",
    "content": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n\n#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_\n#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_\n\n#include \"helpers/memenv/memenv.h\"\n#include \"leveldb/env.h\"\n#include \"leveldb/slice.h\"\n#include \"util/random.h\"\n\nnamespace leveldb {\nnamespace test {\n\n// Store in *dst a random string of length \"len\" and return a Slice that\n// references the generated data.\nSlice RandomString(Random* rnd, int len, std::string* dst);\n\n// Return a random key with the specified length that may contain interesting\n// characters (e.g. \\x00, \\xff, etc.).\nstd::string RandomKey(Random* rnd, int len);\n\n// Store in *dst a string of length \"len\" that will compress to\n// \"N*compressed_fraction\" bytes and return a Slice that references\n// the generated data.\nSlice CompressibleString(Random* rnd, double compressed_fraction, size_t len,\n                         std::string* dst);\n\n// A wrapper that allows injection of errors.\nclass ErrorEnv : public EnvWrapper {\n public:\n  bool writable_file_error_;\n  int num_writable_file_errors_;\n\n  ErrorEnv()\n      : EnvWrapper(NewMemEnv(Env::Default())),\n        writable_file_error_(false),\n        num_writable_file_errors_(0) {}\n  ~ErrorEnv() override { delete target(); }\n\n  Status NewWritableFile(const std::string& fname,\n                         WritableFile** result) override {\n    if (writable_file_error_) {\n      ++num_writable_file_errors_;\n      *result = nullptr;\n      return Status::IOError(fname, \"fake error\");\n    }\n    return target()->NewWritableFile(fname, result);\n  }\n\n  Status NewAppendableFile(const std::string& fname,\n                           WritableFile** result) override {\n    if (writable_file_error_) {\n      ++num_writable_file_errors_;\n      *result = nullptr;\n      return Status::IOError(fname, \"fake error\");\n    }\n    return target()->NewAppendableFile(fname, result);\n  }\n};\n\n}  // namespace test\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_TESTUTIL_H_\n"
  },
  {
    "path": "src/leveldb/util/windows_logger.h",
    "content": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file. See the AUTHORS file for names of contributors.\n//\n// Logger implementation for the Windows platform.\n\n#ifndef STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_\n#define STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_\n\n#include <cassert>\n#include <cstdarg>\n#include <cstdio>\n#include <ctime>\n#include <sstream>\n#include <thread>\n\n#include \"leveldb/env.h\"\n\nnamespace leveldb {\n\nclass WindowsLogger final : public Logger {\n public:\n  // Creates a logger that writes to the given file.\n  //\n  // The PosixLogger instance takes ownership of the file handle.\n  explicit WindowsLogger(std::FILE* fp) : fp_(fp) { assert(fp != nullptr); }\n\n  ~WindowsLogger() override { std::fclose(fp_); }\n\n  void Logv(const char* format, va_list arguments) override {\n    // Record the time as close to the Logv() call as possible.\n    SYSTEMTIME now_components;\n    ::GetLocalTime(&now_components);\n\n    // Record the thread ID.\n    constexpr const int kMaxThreadIdSize = 32;\n    std::ostringstream thread_stream;\n    thread_stream << std::this_thread::get_id();\n    std::string thread_id = thread_stream.str();\n    if (thread_id.size() > kMaxThreadIdSize) {\n      thread_id.resize(kMaxThreadIdSize);\n    }\n\n    // We first attempt to print into a stack-allocated buffer. If this attempt\n    // fails, we make a second attempt with a dynamically allocated buffer.\n    constexpr const int kStackBufferSize = 512;\n    char stack_buffer[kStackBufferSize];\n    static_assert(sizeof(stack_buffer) == static_cast<size_t>(kStackBufferSize),\n                  \"sizeof(char) is expected to be 1 in C++\");\n\n    int dynamic_buffer_size = 0;  // Computed in the first iteration.\n    for (int iteration = 0; iteration < 2; ++iteration) {\n      const int buffer_size =\n          (iteration == 0) ? kStackBufferSize : dynamic_buffer_size;\n      char* const buffer =\n          (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size];\n\n      // Print the header into the buffer.\n      int buffer_offset = snprintf(\n          buffer, buffer_size, \"%04d/%02d/%02d-%02d:%02d:%02d.%06d %s \",\n          now_components.wYear, now_components.wMonth, now_components.wDay,\n          now_components.wHour, now_components.wMinute, now_components.wSecond,\n          static_cast<int>(now_components.wMilliseconds * 1000),\n          thread_id.c_str());\n\n      // The header can be at most 28 characters (10 date + 15 time +\n      // 3 delimiters) plus the thread ID, which should fit comfortably into the\n      // static buffer.\n      assert(buffer_offset <= 28 + kMaxThreadIdSize);\n      static_assert(28 + kMaxThreadIdSize < kStackBufferSize,\n                    \"stack-allocated buffer may not fit the message header\");\n      assert(buffer_offset < buffer_size);\n\n      // Print the message into the buffer.\n      std::va_list arguments_copy;\n      va_copy(arguments_copy, arguments);\n      buffer_offset +=\n          std::vsnprintf(buffer + buffer_offset, buffer_size - buffer_offset,\n                         format, arguments_copy);\n      va_end(arguments_copy);\n\n      // The code below may append a newline at the end of the buffer, which\n      // requires an extra character.\n      if (buffer_offset >= buffer_size - 1) {\n        // The message did not fit into the buffer.\n        if (iteration == 0) {\n          // Re-run the loop and use a dynamically-allocated buffer. The buffer\n          // will be large enough for the log message, an extra newline and a\n          // null terminator.\n          dynamic_buffer_size = buffer_offset + 2;\n          continue;\n        }\n\n        // The dynamically-allocated buffer was incorrectly sized. This should\n        // not happen, assuming a correct implementation of (v)snprintf. Fail\n        // in tests, recover by truncating the log message in production.\n        assert(false);\n        buffer_offset = buffer_size - 1;\n      }\n\n      // Add a newline if necessary.\n      if (buffer[buffer_offset - 1] != '\\n') {\n        buffer[buffer_offset] = '\\n';\n        ++buffer_offset;\n      }\n\n      assert(buffer_offset <= buffer_size);\n      std::fwrite(buffer, 1, buffer_offset, fp_);\n      std::fflush(fp_);\n\n      if (iteration != 0) {\n        delete[] buffer;\n      }\n      break;\n    }\n  }\n\n private:\n  std::FILE* const fp_;\n};\n\n}  // namespace leveldb\n\n#endif  // STORAGE_LEVELDB_UTIL_WINDOWS_LOGGER_H_\n"
  },
  {
    "path": "src/limitedmap.h",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef LIMITEDMAP_H\n#define LIMITEDMAP_H\n\n#include <assert.h>\n#include <map>\n\n/** STL-like map container that only keeps the N elements with the highest value. */\ntemplate <typename K, typename V>\nclass limitedmap\n{\npublic:\n    typedef K key_type;\n    typedef V mapped_type;\n    typedef std::pair<const key_type, mapped_type> value_type;\n    typedef typename std::map<K, V>::const_iterator const_iterator;\n    typedef typename std::map<K, V>::size_type size_type;\n\nprotected:\n    std::map<K, V> map;\n    typedef typename std::map<K, V>::iterator iterator;\n    std::multimap<V, iterator> rmap;\n    typedef typename std::multimap<V, iterator>::iterator rmap_iterator;\n    size_type nMaxSize;\n\npublic:\n    limitedmap(size_type nMaxSizeIn)\n    {\n        assert(nMaxSizeIn > 0);\n        nMaxSize = nMaxSizeIn;\n    }\n    const_iterator begin() const { return map.begin(); }\n    const_iterator end() const { return map.end(); }\n    size_type size() const { return map.size(); }\n    bool empty() const { return map.empty(); }\n    const_iterator find(const key_type& k) const { return map.find(k); }\n    size_type count(const key_type& k) const { return map.count(k); }\n    void insert(const value_type& x)\n    {\n        std::pair<iterator, bool> ret = map.insert(x);\n        if (ret.second) {\n            if (map.size() > nMaxSize) {\n                map.erase(rmap.begin()->second);\n                rmap.erase(rmap.begin());\n            }\n            rmap.insert(std::pair(x.second, ret.first));\n        }\n    }\n    void erase(const key_type& k)\n    {\n        iterator itTarget = map.find(k);\n        if (itTarget == map.end())\n            return;\n        std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second);\n        for (rmap_iterator it = itPair.first; it != itPair.second; ++it)\n            if (it->second == itTarget) {\n                rmap.erase(it);\n                map.erase(itTarget);\n                return;\n            }\n        // Shouldn't ever get here\n        assert(0);\n    }\n    void update(const_iterator itIn, const mapped_type& v)\n    {\n        // Using map::erase() with empty range instead of map::find() to get a non-const iterator,\n        // since it is a constant time operation in C++11. For more details, see\n        // https://stackoverflow.com/questions/765148/how-to-remove-constness-of-const-iterator\n        iterator itTarget = map.erase(itIn, itIn);\n\n        if (itTarget == map.end())\n            return;\n        std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second);\n        for (rmap_iterator it = itPair.first; it != itPair.second; ++it)\n            if (it->second == itTarget) {\n                rmap.erase(it);\n                itTarget->second = v;\n                rmap.insert(std::pair(v, itTarget));\n                return;\n            }\n        // Shouldn't ever get here\n        assert(0);\n    }\n    size_type max_size() const { return nMaxSize; }\n    size_type max_size(size_type s)\n    {\n        assert(s > 0);\n        while (map.size() > s) {\n            map.erase(rmap.begin()->second);\n            rmap.erase(rmap.begin());\n        }\n        nMaxSize = s;\n        return nMaxSize;\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/llvm-cpumodel-hack.cpp",
    "content": "//===-- cpu_model.c - Support for __cpu_model builtin  ------------*- C -*-===//\n//\n// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.\n// See https://llvm.org/LICENSE.txt for license information.\n// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n//\n//===----------------------------------------------------------------------===//\n//\n//  This file is based on LLVM's lib/Support/Host.cpp.\n//  It implements the operating system Host concept and builtin\n//  __cpu_model for the compiler_rt library, for x86 only.\n//\n//===----------------------------------------------------------------------===//\n\n#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) ||           \\\n     defined(_M_X64)) &&                                                       \\\n    (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER))\n\n#include <assert.h>\n\n#define bool int\n#define true 1\n#define false 0\n\n#ifdef _MSC_VER\n#include <intrin.h>\n#endif\n\n#ifndef __has_attribute\n#define __has_attribute(attr) 0\n#endif\n\nenum VendorSignatures {\n  SIG_INTEL = 0x756e6547, // Genu\n  SIG_AMD = 0x68747541,   // Auth\n};\n\nenum ProcessorVendors {\n  VENDOR_INTEL = 1,\n  VENDOR_AMD,\n  VENDOR_OTHER,\n  VENDOR_MAX\n};\n\nenum ProcessorTypes {\n  INTEL_BONNELL = 1,\n  INTEL_CORE2,\n  INTEL_COREI7,\n  AMDFAM10H,\n  AMDFAM15H,\n  INTEL_SILVERMONT,\n  INTEL_KNL,\n  AMD_BTVER1,\n  AMD_BTVER2,\n  AMDFAM17H,\n  INTEL_KNM,\n  INTEL_GOLDMONT,\n  INTEL_GOLDMONT_PLUS,\n  INTEL_TREMONT,\n  CPU_TYPE_MAX\n};\n\nenum ProcessorSubtypes {\n  INTEL_COREI7_NEHALEM = 1,\n  INTEL_COREI7_WESTMERE,\n  INTEL_COREI7_SANDYBRIDGE,\n  AMDFAM10H_BARCELONA,\n  AMDFAM10H_SHANGHAI,\n  AMDFAM10H_ISTANBUL,\n  AMDFAM15H_BDVER1,\n  AMDFAM15H_BDVER2,\n  AMDFAM15H_BDVER3,\n  AMDFAM15H_BDVER4,\n  AMDFAM17H_ZNVER1,\n  INTEL_COREI7_IVYBRIDGE,\n  INTEL_COREI7_HASWELL,\n  INTEL_COREI7_BROADWELL,\n  INTEL_COREI7_SKYLAKE,\n  INTEL_COREI7_SKYLAKE_AVX512,\n  INTEL_COREI7_CANNONLAKE,\n  INTEL_COREI7_ICELAKE_CLIENT,\n  INTEL_COREI7_ICELAKE_SERVER,\n  AMDFAM17H_ZNVER2,\n  INTEL_COREI7_CASCADELAKE,\n  CPU_SUBTYPE_MAX\n};\n\nenum ProcessorFeatures {\n  FEATURE_CMOV = 0,\n  FEATURE_MMX,\n  FEATURE_POPCNT,\n  FEATURE_SSE,\n  FEATURE_SSE2,\n  FEATURE_SSE3,\n  FEATURE_SSSE3,\n  FEATURE_SSE4_1,\n  FEATURE_SSE4_2,\n  FEATURE_AVX,\n  FEATURE_AVX2,\n  FEATURE_SSE4_A,\n  FEATURE_FMA4,\n  FEATURE_XOP,\n  FEATURE_FMA,\n  FEATURE_AVX512F,\n  FEATURE_BMI,\n  FEATURE_BMI2,\n  FEATURE_AES,\n  FEATURE_PCLMUL,\n  FEATURE_AVX512VL,\n  FEATURE_AVX512BW,\n  FEATURE_AVX512DQ,\n  FEATURE_AVX512CD,\n  FEATURE_AVX512ER,\n  FEATURE_AVX512PF,\n  FEATURE_AVX512VBMI,\n  FEATURE_AVX512IFMA,\n  FEATURE_AVX5124VNNIW,\n  FEATURE_AVX5124FMAPS,\n  FEATURE_AVX512VPOPCNTDQ,\n  FEATURE_AVX512VBMI2,\n  FEATURE_GFNI,\n  FEATURE_VPCLMULQDQ,\n  FEATURE_AVX512VNNI,\n  FEATURE_AVX512BITALG,\n  FEATURE_AVX512BF16\n};\n\n// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).\n// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID\n// support. Consequently, for i386, the presence of CPUID is checked first\n// via the corresponding eflags bit.\nstatic bool isCpuIdSupported() {\n#if defined(__GNUC__) || defined(__clang__)\n#if defined(__i386__)\n  int __cpuid_supported;\n  __asm__(\"  pushfl\\n\"\n          \"  popl   %%eax\\n\"\n          \"  movl   %%eax,%%ecx\\n\"\n          \"  xorl   $0x00200000,%%eax\\n\"\n          \"  pushl  %%eax\\n\"\n          \"  popfl\\n\"\n          \"  pushfl\\n\"\n          \"  popl   %%eax\\n\"\n          \"  movl   $0,%0\\n\"\n          \"  cmpl   %%eax,%%ecx\\n\"\n          \"  je     1f\\n\"\n          \"  movl   $1,%0\\n\"\n          \"1:\"\n          : \"=r\"(__cpuid_supported)\n          :\n          : \"eax\", \"ecx\");\n  if (!__cpuid_supported)\n    return false;\n#endif\n  return true;\n#endif\n  return true;\n}\n\n// This code is copied from lib/Support/Host.cpp.\n// Changes to either file should be mirrored in the other.\n\n/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in\n/// the specified arguments.  If we can't run cpuid on the host, return true.\nstatic bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,\n                               unsigned *rECX, unsigned *rEDX) {\n#if defined(__GNUC__) || defined(__clang__)\n#if defined(__x86_64__)\n  // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.\n  // FIXME: should we save this for Clang?\n  __asm__(\"movq\\t%%rbx, %%rsi\\n\\t\"\n          \"cpuid\\n\\t\"\n          \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n          : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n          : \"a\"(value));\n  return false;\n#elif defined(__i386__)\n  __asm__(\"movl\\t%%ebx, %%esi\\n\\t\"\n          \"cpuid\\n\\t\"\n          \"xchgl\\t%%ebx, %%esi\\n\\t\"\n          : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n          : \"a\"(value));\n  return false;\n#else\n  return true;\n#endif\n#elif defined(_MSC_VER)\n  // The MSVC intrinsic is portable across x86 and x64.\n  int registers[4];\n  __cpuid(registers, value);\n  *rEAX = registers[0];\n  *rEBX = registers[1];\n  *rECX = registers[2];\n  *rEDX = registers[3];\n  return false;\n#else\n  return true;\n#endif\n}\n\n/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return\n/// the 4 values in the specified arguments.  If we can't run cpuid on the host,\n/// return true.\nstatic bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,\n                                 unsigned *rEAX, unsigned *rEBX, unsigned *rECX,\n                                 unsigned *rEDX) {\n#if defined(__GNUC__) || defined(__clang__)\n#if defined(__x86_64__)\n  // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.\n  // FIXME: should we save this for Clang?\n  __asm__(\"movq\\t%%rbx, %%rsi\\n\\t\"\n          \"cpuid\\n\\t\"\n          \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n          : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n          : \"a\"(value), \"c\"(subleaf));\n  return false;\n#elif defined(__i386__)\n  __asm__(\"movl\\t%%ebx, %%esi\\n\\t\"\n          \"cpuid\\n\\t\"\n          \"xchgl\\t%%ebx, %%esi\\n\\t\"\n          : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n          : \"a\"(value), \"c\"(subleaf));\n  return false;\n#else\n  return true;\n#endif\n#elif defined(_MSC_VER)\n  int registers[4];\n  __cpuidex(registers, value, subleaf);\n  *rEAX = registers[0];\n  *rEBX = registers[1];\n  *rECX = registers[2];\n  *rEDX = registers[3];\n  return false;\n#else\n  return true;\n#endif\n}\n\n// Read control register 0 (XCR0). Used to detect features such as AVX.\nstatic bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {\n#if defined(__GNUC__) || defined(__clang__)\n  // Check xgetbv; this uses a .byte sequence instead of the instruction\n  // directly because older assemblers do not include support for xgetbv and\n  // there is no easy way to conditionally compile based on the assembler used.\n  __asm__(\".byte 0x0f, 0x01, 0xd0\" : \"=a\"(*rEAX), \"=d\"(*rEDX) : \"c\"(0));\n  return false;\n#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)\n  unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);\n  *rEAX = Result;\n  *rEDX = Result >> 32;\n  return false;\n#else\n  return true;\n#endif\n}\n\nstatic void detectX86FamilyModel(unsigned EAX, unsigned *Family,\n                                 unsigned *Model) {\n  *Family = (EAX >> 8) & 0xf; // Bits 8 - 11\n  *Model = (EAX >> 4) & 0xf;  // Bits 4 - 7\n  if (*Family == 6 || *Family == 0xf) {\n    if (*Family == 0xf)\n      // Examine extended family ID if family ID is F.\n      *Family += (EAX >> 20) & 0xff; // Bits 20 - 27\n    // Examine extended model ID if family ID is 6 or F.\n    *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19\n  }\n}\n\nstatic void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,\n                                            unsigned Brand_id,\n                                            unsigned Features,\n                                            unsigned Features2, unsigned *Type,\n                                            unsigned *Subtype) {\n  if (Brand_id != 0)\n    return;\n  switch (Family) {\n  case 6:\n    switch (Model) {\n    case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile\n               // processor, Intel Core 2 Quad processor, Intel Core 2 Quad\n               // mobile processor, Intel Core 2 Extreme processor, Intel\n               // Pentium Dual-Core processor, Intel Xeon processor, model\n               // 0Fh. All processors are manufactured using the 65 nm process.\n    case 0x16: // Intel Celeron processor model 16h. All processors are\n               // manufactured using the 65 nm process\n    case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model\n               // 17h. All processors are manufactured using the 45 nm process.\n               //\n               // 45nm: Penryn , Wolfdale, Yorkfield (XE)\n    case 0x1d: // Intel Xeon processor MP. All processors are manufactured using\n               // the 45 nm process.\n      *Type = INTEL_CORE2; // \"penryn\"\n      break;\n    case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All\n               // processors are manufactured using the 45 nm process.\n    case 0x1e: // Intel(R) Core(TM) i7 CPU         870  @ 2.93GHz.\n               // As found in a Summer 2010 model iMac.\n    case 0x1f:\n    case 0x2e:              // Nehalem EX\n      *Type = INTEL_COREI7; // \"nehalem\"\n      *Subtype = INTEL_COREI7_NEHALEM;\n      break;\n    case 0x25: // Intel Core i7, laptop version.\n    case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All\n               // processors are manufactured using the 32 nm process.\n    case 0x2f: // Westmere EX\n      *Type = INTEL_COREI7; // \"westmere\"\n      *Subtype = INTEL_COREI7_WESTMERE;\n      break;\n    case 0x2a: // Intel Core i7 processor. All processors are manufactured\n               // using the 32 nm process.\n    case 0x2d:\n      *Type = INTEL_COREI7; //\"sandybridge\"\n      *Subtype = INTEL_COREI7_SANDYBRIDGE;\n      break;\n    case 0x3a:\n    case 0x3e:              // Ivy Bridge EP\n      *Type = INTEL_COREI7; // \"ivybridge\"\n      *Subtype = INTEL_COREI7_IVYBRIDGE;\n      break;\n\n    // Haswell:\n    case 0x3c:\n    case 0x3f:\n    case 0x45:\n    case 0x46:\n      *Type = INTEL_COREI7; // \"haswell\"\n      *Subtype = INTEL_COREI7_HASWELL;\n      break;\n\n    // Broadwell:\n    case 0x3d:\n    case 0x47:\n    case 0x4f:\n    case 0x56:\n      *Type = INTEL_COREI7; // \"broadwell\"\n      *Subtype = INTEL_COREI7_BROADWELL;\n      break;\n\n    // Skylake:\n    case 0x4e:              // Skylake mobile\n    case 0x5e:              // Skylake desktop\n    case 0x8e:              // Kaby Lake mobile\n    case 0x9e:              // Kaby Lake desktop\n      *Type = INTEL_COREI7; // \"skylake\"\n      *Subtype = INTEL_COREI7_SKYLAKE;\n      break;\n\n    // Skylake Xeon:\n    case 0x55:\n      *Type = INTEL_COREI7;\n      if (Features2 & (1 << (FEATURE_AVX512VNNI - 32)))\n        *Subtype = INTEL_COREI7_CASCADELAKE; // \"cascadelake\"\n      else\n        *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // \"skylake-avx512\"\n      break;\n\n    // Cannonlake:\n    case 0x66:\n      *Type = INTEL_COREI7;\n      *Subtype = INTEL_COREI7_CANNONLAKE; // \"cannonlake\"\n      break;\n\n    // Icelake:\n    case 0x7d:\n    case 0x7e:\n      *Type = INTEL_COREI7;\n      *Subtype = INTEL_COREI7_ICELAKE_CLIENT; // \"icelake-client\"\n      break;\n\n    // Icelake Xeon:\n    case 0x6a:\n    case 0x6c:\n      *Type = INTEL_COREI7;\n      *Subtype = INTEL_COREI7_ICELAKE_SERVER; // \"icelake-server\"\n      break;\n\n    case 0x1c: // Most 45 nm Intel Atom processors\n    case 0x26: // 45 nm Atom Lincroft\n    case 0x27: // 32 nm Atom Medfield\n    case 0x35: // 32 nm Atom Midview\n    case 0x36: // 32 nm Atom Midview\n      *Type = INTEL_BONNELL;\n      break; // \"bonnell\"\n\n    // Atom Silvermont codes from the Intel software optimization guide.\n    case 0x37:\n    case 0x4a:\n    case 0x4d:\n    case 0x5a:\n    case 0x5d:\n    case 0x4c: // really airmont\n      *Type = INTEL_SILVERMONT;\n      break; // \"silvermont\"\n    // Goldmont:\n    case 0x5c: // Apollo Lake\n    case 0x5f: // Denverton\n      *Type = INTEL_GOLDMONT;\n      break; // \"goldmont\"\n    case 0x7a:\n      *Type = INTEL_GOLDMONT_PLUS;\n      break;\n    case 0x86:\n      *Type = INTEL_TREMONT;\n      break;\n\n    case 0x57:\n      *Type = INTEL_KNL; // knl\n      break;\n\n    case 0x85:\n      *Type = INTEL_KNM; // knm\n      break;\n\n    default: // Unknown family 6 CPU.\n      break;\n    }\n    break;\n  default:\n    break; // Unknown.\n  }\n}\n\nstatic void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,\n                                          unsigned Features, unsigned Features2,\n                                          unsigned *Type, unsigned *Subtype) {\n  // FIXME: this poorly matches the generated SubtargetFeatureKV table.  There\n  // appears to be no way to generate the wide variety of AMD-specific targets\n  // from the information returned from CPUID.\n  switch (Family) {\n  case 16:\n    *Type = AMDFAM10H; // \"amdfam10\"\n    switch (Model) {\n    case 2:\n      *Subtype = AMDFAM10H_BARCELONA;\n      break;\n    case 4:\n      *Subtype = AMDFAM10H_SHANGHAI;\n      break;\n    case 8:\n      *Subtype = AMDFAM10H_ISTANBUL;\n      break;\n    }\n    break;\n  case 20:\n    *Type = AMD_BTVER1;\n    break; // \"btver1\";\n  case 21:\n    *Type = AMDFAM15H;\n    if (Model >= 0x60 && Model <= 0x7f) {\n      *Subtype = AMDFAM15H_BDVER4;\n      break; // \"bdver4\"; 60h-7Fh: Excavator\n    }\n    if (Model >= 0x30 && Model <= 0x3f) {\n      *Subtype = AMDFAM15H_BDVER3;\n      break; // \"bdver3\"; 30h-3Fh: Steamroller\n    }\n    if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {\n      *Subtype = AMDFAM15H_BDVER2;\n      break; // \"bdver2\"; 02h, 10h-1Fh: Piledriver\n    }\n    if (Model <= 0x0f) {\n      *Subtype = AMDFAM15H_BDVER1;\n      break; // \"bdver1\"; 00h-0Fh: Bulldozer\n    }\n    break;\n  case 22:\n    *Type = AMD_BTVER2;\n    break; // \"btver2\"\n  case 23:\n    *Type = AMDFAM17H;\n    if (Model >= 0x30 && Model <= 0x3f) {\n      *Subtype = AMDFAM17H_ZNVER2;\n      break; // \"znver2\"; 30h-3fh: Zen2\n    }\n    if (Model <= 0x0f) {\n      *Subtype = AMDFAM17H_ZNVER1;\n      break; // \"znver1\"; 00h-0Fh: Zen1\n    }\n    break;\n  default:\n    break; // \"generic\"\n  }\n}\n\nstatic void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,\n                                 unsigned *FeaturesOut,\n                                 unsigned *Features2Out) {\n  unsigned Features = 0;\n  unsigned Features2 = 0;\n  unsigned EAX, EBX;\n\n#define setFeature(F)                                                          \\\n  do {                                                                         \\\n    if (F < 32)                                                                \\\n      Features |= 1U << (F & 0x1f);                                            \\\n    else if (F < 64)                                                           \\\n      Features2 |= 1U << ((F - 32) & 0x1f);                                    \\\n  } while (0)\n\n  if ((EDX >> 15) & 1)\n    setFeature(FEATURE_CMOV);\n  if ((EDX >> 23) & 1)\n    setFeature(FEATURE_MMX);\n  if ((EDX >> 25) & 1)\n    setFeature(FEATURE_SSE);\n  if ((EDX >> 26) & 1)\n    setFeature(FEATURE_SSE2);\n\n  if ((ECX >> 0) & 1)\n    setFeature(FEATURE_SSE3);\n  if ((ECX >> 1) & 1)\n    setFeature(FEATURE_PCLMUL);\n  if ((ECX >> 9) & 1)\n    setFeature(FEATURE_SSSE3);\n  if ((ECX >> 12) & 1)\n    setFeature(FEATURE_FMA);\n  if ((ECX >> 19) & 1)\n    setFeature(FEATURE_SSE4_1);\n  if ((ECX >> 20) & 1)\n    setFeature(FEATURE_SSE4_2);\n  if ((ECX >> 23) & 1)\n    setFeature(FEATURE_POPCNT);\n  if ((ECX >> 25) & 1)\n    setFeature(FEATURE_AES);\n\n  // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV\n  // indicates that the AVX registers will be saved and restored on context\n  // switch, then we have full AVX support.\n  const unsigned AVXBits = (1 << 27) | (1 << 28);\n  bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&\n                ((EAX & 0x6) == 0x6);\n  bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);\n\n  if (HasAVX)\n    setFeature(FEATURE_AVX);\n\n  bool HasLeaf7 =\n      MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);\n\n  if (HasLeaf7 && ((EBX >> 3) & 1))\n    setFeature(FEATURE_BMI);\n  if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)\n    setFeature(FEATURE_AVX2);\n  if (HasLeaf7 && ((EBX >> 8) & 1))\n    setFeature(FEATURE_BMI2);\n  if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512F);\n  if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512DQ);\n  if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512IFMA);\n  if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512PF);\n  if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512ER);\n  if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512CD);\n  if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512BW);\n  if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512VL);\n\n  if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512VBMI);\n  if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512VBMI2);\n  if (HasLeaf7 && ((ECX >> 8) & 1))\n    setFeature(FEATURE_GFNI);\n  if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX)\n    setFeature(FEATURE_VPCLMULQDQ);\n  if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512VNNI);\n  if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512BITALG);\n  if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512VPOPCNTDQ);\n\n  if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX5124VNNIW);\n  if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX5124FMAPS);\n\n  bool HasLeaf7Subleaf1 =\n      MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);\n  if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save)\n    setFeature(FEATURE_AVX512BF16);\n\n  unsigned MaxExtLevel;\n  getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);\n\n  bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&\n                     !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);\n  if (HasExtLeaf1 && ((ECX >> 6) & 1))\n    setFeature(FEATURE_SSE4_A);\n  if (HasExtLeaf1 && ((ECX >> 11) & 1))\n    setFeature(FEATURE_XOP);\n  if (HasExtLeaf1 && ((ECX >> 16) & 1))\n    setFeature(FEATURE_FMA4);\n\n  *FeaturesOut = Features;\n  *Features2Out = Features2;\n#undef setFeature\n}\n\n#if defined(HAVE_INIT_PRIORITY)\n#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))\n#elif __has_attribute(__constructor__)\n#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))\n#else\n// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that\n// this runs during initialization.\n#define CONSTRUCTOR_ATTRIBUTE\n#endif\n\n#ifndef _WIN32\n__attribute__((visibility(\"hidden\")))\n#endif\nint __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;\n\n#ifndef _WIN32\n__attribute__((visibility(\"hidden\")))\n#endif\nstruct __processor_model {\n  unsigned int __cpu_vendor;\n  unsigned int __cpu_type;\n  unsigned int __cpu_subtype;\n  unsigned int __cpu_features[1];\n} __cpu_model = {0, 0, 0, {0}};\n\n#ifndef _WIN32\n__attribute__((visibility(\"hidden\")))\n#endif\nunsigned int __cpu_features2;\n\n// A constructor function that is sets __cpu_model and __cpu_features2 with\n// the right values.  This needs to run only once.  This constructor is\n// given the highest priority and it should run before constructors without\n// the priority set.  However, it still runs after ifunc initializers and\n// needs to be called explicitly there.\n\nint CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {\n  unsigned EAX, EBX, ECX, EDX;\n  unsigned MaxLeaf = 5;\n  unsigned Vendor;\n  unsigned Model, Family, Brand_id;\n  unsigned Features = 0;\n  unsigned Features2 = 0;\n\n  // This function needs to run just once.\n  if (__cpu_model.__cpu_vendor)\n    return 0;\n\n  if (!isCpuIdSupported())\n    return -1;\n\n  // Assume cpuid insn present. Run in level 0 to get vendor id.\n  if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {\n    __cpu_model.__cpu_vendor = VENDOR_OTHER;\n    return -1;\n  }\n  getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);\n  detectX86FamilyModel(EAX, &Family, &Model);\n  Brand_id = EBX & 0xff;\n\n  // Find available features.\n  getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2);\n  __cpu_model.__cpu_features[0] = Features;\n  __cpu_features2 = Features2;\n\n  if (Vendor == SIG_INTEL) {\n    // Get CPU type.\n    getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features,\n                                    Features2, &(__cpu_model.__cpu_type),\n                                    &(__cpu_model.__cpu_subtype));\n    __cpu_model.__cpu_vendor = VENDOR_INTEL;\n  } else if (Vendor == SIG_AMD) {\n    // Get CPU type.\n    getAMDProcessorTypeAndSubtype(Family, Model, Features, Features2,\n                                  &(__cpu_model.__cpu_type),\n                                  &(__cpu_model.__cpu_subtype));\n    __cpu_model.__cpu_vendor = VENDOR_AMD;\n  } else\n    __cpu_model.__cpu_vendor = VENDOR_OTHER;\n\n  assert(__cpu_model.__cpu_vendor < VENDOR_MAX);\n  assert(__cpu_model.__cpu_type < CPU_TYPE_MAX);\n  assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);\n\n  return 0;\n}\n\n#endif\n\n"
  },
  {
    "path": "src/logging.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <fs.h>\n#include <logging.h>\n#include <util/threadnames.h>\n#include <util/time.h>\n\n#include <algorithm>\n#include <array>\n#include <mutex>\n\n\n"
  },
  {
    "path": "src/logging.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_LOGGING_H\n#define BITCOIN_LOGGING_H\n\n#include <fs.h>\n#include <tinyformat.h>\n#include <threadsafety.h>\n\n#include <atomic>\n#include <cstdint>\n#include <functional>\n#include <list>\n#include <mutex>\n#include <string>\n#include <vector>\n\nextern std::atomic<uint32_t> logCategories;\n\nstruct CLogCategoryActive\n{\n    std::string category;\n    bool active;\n};\n\nnamespace BCLog {\n    enum LogFlags : uint32_t {\n        NONE        = 0,\n        ALERT       = (1 <<  0),\n        NET         = (1 <<  1),\n        TOR         = (1 <<  2),\n        MEMPOOL     = (1 <<  3),\n        HTTP        = (1 <<  4),\n        BENCH       = (1 <<  5),\n        ZMQ         = (1 <<  6),\n        DB          = (1 <<  7),\n        RPC         = (1 <<  8),\n        ESTIMATEFEE = (1 <<  9),\n        ADDRMAN     = (1 << 10),\n        SELECTCOINS = (1 << 11),\n        REINDEX     = (1 << 12),\n        CMPCTBLOCK  = (1 << 13),\n        RAND        = (1 << 14),\n        PRUNE       = (1 << 15),\n        PROXY       = (1 << 16),\n        MEMPOOLREJ  = (1 << 17),\n        LIBEVENT    = (1 << 18),\n        COINDB      = (1 << 19),\n        QT          = (1 << 20),\n        LEVELDB     = (1 << 21),\n        DELTA       = (1 << 22),\n        WITNESS     = (1 << 23),\n        IO          = (1 << 24),\n        WALLET      = (1 << 25),\n        LOCK        = (1 << 26),\n        VALIDATION  = (1 << 27),\n        ALL         = ~(uint32_t)0,\n    };\n}\n\n/** Return true if log accepts specified category */\nstatic inline bool LogAcceptCategory(uint32_t category)\n{\n    return (logCategories.load(std::memory_order_relaxed) & category) != 0;\n}\n\n/** Returns a string with the log categories. */\nstd::string ListLogCategories();\n\n/** Returns a vector of the active log categories. */\nstd::vector<CLogCategoryActive> ListActiveLogCategories();\n\n/** Return true if str parses as a log category and set the flags in f */\nbool GetLogCategory(uint32_t *f, const std::string *str);\n\n/** Send a string to the log output */\nint LogPrintStr(const std::string &str);\n\n/** Get format string from VA_ARGS for error reporting */\ntemplate<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, [[maybe_unused]] const Args&... args) { return fmt; }\n\ntemplate<typename... Args>\nbool error(const char* fmt, const Args&... args)\n{\n    LogPrintStr(\"ERROR: \" + tfm::format(fmt, args...) + \"\\n\");\n    return false;\n}\n\n#define LogPrintf(...) do { \\\n    std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \\\n    try { \\\n        _log_msg_ = tfm::format(__VA_ARGS__); \\\n    } catch (tinyformat::format_error &fmterr) { \\\n        /* Original format string will have newline so don't add one here */ \\\n        _log_msg_ = \"Error \\\"\" + std::string(fmterr.what()) + \"\\\" while formatting log message: \" + FormatStringFromLogArgs(__VA_ARGS__); \\\n    } \\\n    LogPrintStr(_log_msg_); \\\n} while(0)\n\n// Use a macro instead of a function for conditional logging to prevent\n// evaluating arguments when logging for the category is not enabled.\n#define LogPrint(category, ...)              \\\n    do {                                     \\\n        if (LogAcceptCategory((category))) { \\\n            LogPrintf(__VA_ARGS__);          \\\n        }                                    \\\n    } while (0)\n\n#endif // BITCOIN_LOGGING_H\n"
  },
  {
    "path": "src/memusage.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef MEMUSAGE_H\n#define MEMUSAGE_H\n\n#include \"indirectmap.h\"\n\n#include <stdlib.h>\n\n#include <map>\n#include <set>\n#include <vector>\n#include <unordered_map>\n#include <unordered_set>\n\n\n\nnamespace memusage\n{\n\n/** Compute the total memory used by allocating alloc bytes. */\nstatic size_t MallocUsage(size_t alloc);\n\n/** Dynamic memory usage for built-in types is zero. */\nstatic inline size_t DynamicUsage([[maybe_unused]] const int8_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const uint8_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const int16_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const uint16_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const int32_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const uint32_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const int64_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const uint64_t& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const float& v) { return 0; }\nstatic inline size_t DynamicUsage([[maybe_unused]] const double& v) { return 0; }\ntemplate<typename X> static inline size_t DynamicUsage([[maybe_unused]] X * const &v) { return 0; }\ntemplate<typename X> static inline size_t DynamicUsage([[maybe_unused]] const X * const &v) { return 0; }\n\n/** Compute the memory used for dynamically allocated but owned data structures.\n *  For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >)\n *  will compute the memory used for the vector<int>'s, but not for the ints inside.\n *  This is for efficiency reasons, as these functions are intended to be fast. If\n *  application data structures require more accurate inner accounting, they should\n *  iterate themselves, or use more efficient caching + updating on modification.\n */\n\nstatic inline size_t MallocUsage(size_t alloc)\n{\n    // Measured on libc6 2.19 on Linux.\n    if (alloc == 0) {\n        return 0;\n    } else if (sizeof(void*) == 8) {\n        return ((alloc + 31) >> 4) << 4;\n    } else if (sizeof(void*) == 4) {\n        return ((alloc + 15) >> 3) << 3;\n    } else {\n        assert(0);\n    }\n}\n\n// STL data structures\n\ntemplate<typename X>\nstruct stl_tree_node\n{\nprivate:\n    int color;\n    void* parent;\n    void* left;\n    void* right;\n    X x;\n};\n\nstruct stl_shared_counter\n{\n    /* Various platforms use different sized counters here.\n     * Conservatively assume that they won't be larger than size_t. */\n    void* class_type;\n    size_t use_count;\n    size_t weak_count;\n};\n\ntemplate<typename X>\nstatic inline size_t DynamicUsage(const std::vector<X>& v)\n{\n    return MallocUsage(v.capacity() * sizeof(X));\n}\n\ntemplate<unsigned int N, typename X, typename S, typename D>\nstatic inline size_t DynamicUsage(const prevector<N, X, S, D>& v)\n{\n    return MallocUsage(v.allocated_memory());\n}\n\ntemplate<typename X, typename Y>\nstatic inline size_t DynamicUsage(const std::set<X, Y>& s)\n{\n    return MallocUsage(sizeof(stl_tree_node<X>)) * s.size();\n}\n\ntemplate<typename X, typename Y>\nstatic inline size_t IncrementalDynamicUsage([[maybe_unused]] const std::set<X, Y>& s)\n{\n    return MallocUsage(sizeof(stl_tree_node<X>));\n}\n\ntemplate<typename X, typename Y, typename Z>\nstatic inline size_t DynamicUsage(const std::map<X, Y, Z>& m)\n{\n    return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >)) * m.size();\n}\n\ntemplate<typename X, typename Y, typename Z>\nstatic inline size_t IncrementalDynamicUsage(const std::map<X, Y, Z>& m)\n{\n    return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >));\n}\n\n// indirectmap has underlying map with pointer as key\n\ntemplate<typename X, typename Y>\nstatic inline size_t DynamicUsage(const indirectmap<X, Y>& m)\n{\n    return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >)) * m.size();\n}\n\ntemplate<typename X, typename Y>\nstatic inline size_t IncrementalDynamicUsage(const indirectmap<X, Y>& m)\n{\n    return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >));\n}\n\ntemplate<typename X>\nstatic inline size_t DynamicUsage(const std::unique_ptr<X>& p)\n{\n    return p ? MallocUsage(sizeof(X)) : 0;\n}\n\ntemplate<typename X>\nstatic inline size_t DynamicUsage(const std::shared_ptr<X>& p)\n{\n    // A shared_ptr can either use a single continuous memory block for both\n    // the counter and the storage (when using std::make_shared), or separate.\n    // We can't observe the difference, however, so assume the worst.\n    return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0;\n}\n\ntemplate<typename X>\nstruct unordered_node : private X\n{\nprivate:\n    void* ptr;\n};\n\ntemplate<typename X, typename Y>\nstatic inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)\n{\n    return MallocUsage(sizeof(unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());\n}\n\ntemplate<typename X, typename Y, typename Z>\nstatic inline size_t DynamicUsage(const std::unordered_map<X, Y, Z>& m)\n{\n    return MallocUsage(sizeof(unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "src/merkleblock.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"merkleblock.h\"\n\n#include \"hash.h\"\n#include \"consensus/consensus.h\"\n#include \"util/strencodings.h\"\n\nCMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)\n{\n    header = block.GetBlockHeader();\n\n    std::vector<bool> vMatch;\n    std::vector<uint256> vHashes;\n\n    vMatch.reserve(block.vtx.size());\n    vHashes.reserve(block.vtx.size());\n\n    for (unsigned int i = 0; i < block.vtx.size(); i++)\n    {\n        const uint256& hash = block.vtx[i]->GetHash();\n        if (txids.count(hash))\n            vMatch.push_back(true);\n        else\n            vMatch.push_back(false);\n        vHashes.push_back(hash);\n    }\n\n    txn = CPartialMerkleTree(vHashes, vMatch);\n}\n\nuint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {\n    if (height == 0) {\n        // hash at height 0 is the txids themself\n        return vTxid[pos];\n    } else {\n        // calculate left hash\n        uint256 left = CalcHash(height-1, pos*2, vTxid), right;\n        // calculate right hash if not beyond the end of the array - copy left hash otherwise\n        if (pos*2+1 < CalcTreeWidth(height-1))\n            right = CalcHash(height-1, pos*2+1, vTxid);\n        else\n            right = left;\n        // combine subhashes\n        return Hash(BEGIN(left), END(left), BEGIN(right), END(right));\n    }\n}\n\nvoid CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) {\n    // determine whether this node is the parent of at least one matched txid\n    bool fParentOfMatch = false;\n    for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)\n        fParentOfMatch |= vMatch[p];\n    // store as flag bit\n    vBits.push_back(fParentOfMatch);\n    if (height==0 || !fParentOfMatch) {\n        // if at height 0, or nothing interesting below, store hash and stop\n        vHash.push_back(CalcHash(height, pos, vTxid));\n    } else {\n        // otherwise, don't store any hash, but descend into the subtrees\n        TraverseAndBuild(height-1, pos*2, vTxid, vMatch);\n        if (pos*2+1 < CalcTreeWidth(height-1))\n            TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);\n    }\n}\n\nuint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {\n    if (nBitsUsed >= vBits.size()) {\n        // overflowed the bits array - failure\n        fBad = true;\n        return uint256();\n    }\n    bool fParentOfMatch = vBits[nBitsUsed++];\n    if (height==0 || !fParentOfMatch) {\n        // if at height 0, or nothing interesting below, use stored hash and do not descend\n        if (nHashUsed >= vHash.size()) {\n            // overflowed the hash array - failure\n            fBad = true;\n            return uint256();\n        }\n        const uint256 &hash = vHash[nHashUsed++];\n        if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid\n            vMatch.push_back(hash);\n            vnIndex.push_back(pos);\n        }\n        return hash;\n    } else {\n        // otherwise, descend into the subtrees to extract matched txids and hashes\n        uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;\n        if (pos*2+1 < CalcTreeWidth(height-1)) {\n            right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);\n            if (right == left) {\n                // The left and right branches should never be identical, as the transaction\n                // hashes covered by them must each be unique.\n                fBad = true;\n            }\n        } else {\n            right = left;\n        }\n        // and combine them before returning\n        return Hash(BEGIN(left), END(left), BEGIN(right), END(right));\n    }\n}\n\nCPartialMerkleTree::CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {\n    // reset state\n    vBits.clear();\n    vHash.clear();\n\n    // calculate height of tree\n    int nHeight = 0;\n    while (CalcTreeWidth(nHeight) > 1)\n        nHeight++;\n\n    // traverse the partial tree\n    TraverseAndBuild(nHeight, 0, vTxid, vMatch);\n}\n\nCPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}\n\nuint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex) {\n    vMatch.clear();\n    // An empty set will not work\n    if (nTransactions == 0)\n        return uint256();\n    // check for excessively high numbers of transactions\n    if (nTransactions > MAX_BLOCK_BASE_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction\n        return uint256();\n    // there can never be more hashes provided than one for every txid\n    if (vHash.size() > nTransactions)\n        return uint256();\n    // there must be at least one bit per node in the partial tree, and at least one node per hash\n    if (vBits.size() < vHash.size())\n        return uint256();\n    // calculate height of tree\n    int nHeight = 0;\n    while (CalcTreeWidth(nHeight) > 1)\n        nHeight++;\n    // traverse the partial tree\n    unsigned int nBitsUsed = 0, nHashUsed = 0;\n    uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);\n    // verify that no problems occurred during the tree traversal\n    if (fBad)\n        return uint256();\n    // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)\n    if ((nBitsUsed+7)/8 != (vBits.size()+7)/8)\n        return uint256();\n    // verify that all hashes were consumed\n    if (nHashUsed != vHash.size())\n        return uint256();\n    return hashMerkleRoot;\n}\n"
  },
  {
    "path": "src/merkleblock.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef MERKLEBLOCK_H\n#define MERKLEBLOCK_H\n\n#include \"serialize.h\"\n#include \"uint256.h\"\n#include \"primitives/block.h\"\n#include \"bloom.h\"\n\n#include <vector>\n\n/** Data structure that represents a partial merkle tree.\n *\n * It represents a subset of the txid's of a known block, in a way that\n * allows recovery of the list of txid's and the merkle root, in an\n * authenticated way.\n *\n * The encoding works as follows: we traverse the tree in depth-first order,\n * storing a bit for each traversed node, signifying whether the node is the\n * parent of at least one matched leaf txid (or a matched txid itself). In\n * case we are at the leaf level, or this bit is 0, its merkle node hash is\n * stored, and its children are not explored further. Otherwise, no hash is\n * stored, but we recurse into both (or the only) child branch. During\n * decoding, the same depth-first traversal is performed, consuming bits and\n * hashes as they written during encoding.\n *\n * The serialization is fixed and provides a hard guarantee about the\n * encoded size:\n *\n *   SIZE <= 10 + ceil(32.25*N)\n *\n * Where N represents the number of leaf nodes of the partial tree. N itself\n * is bounded by:\n *\n *   N <= total_transactions\n *   N <= 1 + matched_transactions*tree_height\n *\n * The serialization format:\n *  - uint32     total_transactions (4 bytes)\n *  - varint     number of hashes   (1-3 bytes)\n *  - uint256[]  hashes in depth-first order (<= 32*N bytes)\n *  - varint     number of bytes of flag bits (1-3 bytes)\n *  - byte[]     flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)\n * The size constraints follow from this.\n */\nclass CPartialMerkleTree\n{\nprotected:\n    /** the total number of transactions in the block */\n    unsigned int nTransactions;\n\n    /** node-is-parent-of-matched-txid bits */\n    std::vector<bool> vBits;\n\n    /** txids and internal hashes */\n    std::vector<uint256> vHash;\n\n    /** flag set when encountering invalid data */\n    bool fBad;\n\n    /** helper function to efficiently calculate the number of nodes at given height in the merkle tree */\n    unsigned int CalcTreeWidth(int height) {\n        return (nTransactions+(1 << height)-1) >> height;\n    }\n\n    /** calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) */\n    uint256 CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid);\n\n    /** recursive function that traverses tree nodes, storing the data as bits and hashes */\n    void TraverseAndBuild(int height, unsigned int pos, const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);\n\n    /**\n     * recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.\n     * it returns the hash of the respective node and its respective index.\n     */\n    uint256 TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);\n\npublic:\n\n    /** serialization implementation */\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(nTransactions);\n        READWRITECOMPACTSIZEVECTOR(vHash);\n        std::vector<unsigned char> vBytes;\n        if (ser_action.ForRead()) {\n            READWRITECOMPACTSIZEVECTOR(vBytes);\n            CPartialMerkleTree &us = *(const_cast<CPartialMerkleTree*>(this));\n            us.vBits.resize(vBytes.size() * 8);\n            for (unsigned int p = 0; p < us.vBits.size(); p++)\n                us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0;\n            us.fBad = false;\n        } else {\n            vBytes.resize((vBits.size()+7)/8);\n            for (unsigned int p = 0; p < vBits.size(); p++)\n                vBytes[p / 8] |= vBits[p] << (p % 8);\n            READWRITECOMPACTSIZEVECTOR(vBytes);\n        }\n    }\n\n    /** Construct a partial merkle tree from a list of transaction ids, and a mask that selects a subset of them */\n    CPartialMerkleTree(const std::vector<uint256> &vTxid, const std::vector<bool> &vMatch);\n\n    CPartialMerkleTree();\n\n    /**\n     * extract the matching txid's represented by this partial merkle tree\n     * and their respective indices within the partial tree.\n     * returns the merkle root, or 0 in case of failure\n     */\n    uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);\n};\n\n\n/**\n * Used to relay blocks as header + vector<merkle branch>\n * to filtered nodes.\n */\nclass CMerkleBlock\n{\npublic:\n    /** Public only for unit testing */\n    CBlockHeader header;\n    CPartialMerkleTree txn;\n\npublic:\n    /** Public only for unit testing and relay testing (not relayed) */\n    std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;\n\n    // Create from a CBlock, matching the txids in the set\n    CMerkleBlock(const CBlock& block, const std::set<uint256>& txids);\n\n    CMerkleBlock() {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(header);\n        READWRITE(txn);\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/net.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"net.h\"\n\n#include \"addrman.h\"\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"consensus/consensus.h\"\n#include \"crypto/common.h\"\n#include \"crypto/sha256.h\"\n#include \"hash.h\"\n#include \"primitives/transaction.h\"\n#include \"scheduler.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n#include \"util/thread.h\"\n\n#include <boost/thread.hpp>\n\n#ifdef WIN32\n#include <string.h>\n#else\n#include <fcntl.h>\n#endif\n\n#ifdef USE_UPNP\n#include <miniupnpc/miniupnpc.h>\n#include <miniupnpc/miniwget.h>\n#include <miniupnpc/upnpcommands.h>\n#include <miniupnpc/upnperrors.h>\n#endif\n\n\n#include <math.h>\n\n// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)\n#define DUMP_ADDRESSES_INTERVAL 900\n\n// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.\n#define FEELER_SLEEP_WINDOW 1\n\n#if !defined(HAVE_MSG_NOSIGNAL)\n#define MSG_NOSIGNAL 0\n#endif\n\n// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0\n#if !defined(HAVE_MSG_DONTWAIT)\n#define MSG_DONTWAIT 0\n#endif\n\n// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.\n// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.\n#ifdef WIN32\n#ifndef PROTECTION_LEVEL_UNRESTRICTED\n#define PROTECTION_LEVEL_UNRESTRICTED 10\n#endif\n#ifndef IPV6_PROTECTION_LEVEL\n#define IPV6_PROTECTION_LEVEL 23\n#endif\n#endif\n\nconst static std::string NET_MESSAGE_COMMAND_OTHER = \"*other*\";\n\nstatic const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256(\"netgroup\")[0:8]\nstatic const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256(\"localhostnonce\")[0:8]\n//\n// Global state variables\n//\nbool fDiscover = true;\nbool fListen = true;\nbool fRelayTxes = true;\nRecursiveMutex cs_mapLocalHost;\nstd::map<CNetAddr, LocalServiceInfo> mapLocalHost;\nstatic bool vfLimited[NET_MAX] = {};\nstd::string strSubVersion;\n\nlimitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);\n\n// Signals for message handling\nstatic CNodeSignals g_signals;\nCNodeSignals& GetNodeSignals() { return g_signals; }\n\nvoid CConnman::AddOneShot(const std::string& strDest)\n{\n    LOCK(cs_vOneShots);\n    vOneShots.push_back(strDest);\n}\n\nunsigned short GetListenPort()\n{\n    return (unsigned short)(GetArg(\"-port\", Params().GetDefaultPort()));\n}\n\n// find 'best' local address for a particular peer\nbool GetLocal(CService& addr, const CNetAddr *paddrPeer)\n{\n    if (!fListen)\n        return false;\n\n    int nBestScore = -1;\n    int nBestReachability = -1;\n    {\n        LOCK(cs_mapLocalHost);\n        for (std::map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)\n        {\n            int nScore = (*it).second.nScore;\n            int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);\n            if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore))\n            {\n                addr = CService((*it).first, (*it).second.nPort);\n                nBestReachability = nReachability;\n                nBestScore = nScore;\n            }\n        }\n    }\n    return nBestScore >= 0;\n}\n\n//! Convert the pnSeeds6 array into usable address objects.\nstatic std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn)\n{\n    // It'll only connect to one or two seed nodes because once it connects,\n    // it'll get a pile of addresses with newer timestamps.\n    // Seed nodes are given a random 'last seen time' of between one and two\n    // weeks ago.\n    const int64_t nOneWeek = 7*24*60*60;\n    std::vector<CAddress> vSeedsOut;\n    vSeedsOut.reserve(vSeedsIn.size());\n    for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i)\n    {\n        struct in6_addr ip;\n        memcpy(&ip, i->addr, sizeof(ip));\n        CAddress addr(CService(ip, i->port), NODE_NETWORK);\n        addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;\n        vSeedsOut.push_back(addr);\n    }\n    return vSeedsOut;\n}\n\n// get best local address for a particular peer as a CAddress\n// Otherwise, return the unroutable 0.0.0.0 but filled in with\n// the normal parameters, since the IP may be changed to a useful\n// one by discovery.\nCAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)\n{\n    CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);\n    CService addr;\n    if (GetLocal(addr, paddrPeer))\n    {\n        ret = CAddress(addr, nLocalServices);\n    }\n    ret.nTime = GetAdjustedTime();\n    return ret;\n}\n\nstatic int GetnScore(const CService& addr)\n{\n    LOCK(cs_mapLocalHost);\n    if (mapLocalHost.count(addr) == LOCAL_NONE)\n        return 0;\n    return mapLocalHost[addr].nScore;\n}\n\n// Is our peer's addrLocal potentially useful as an external IP source?\nbool IsPeerAddrLocalGood(CNode *pnode)\n{\n    CService addrLocal = pnode->GetAddrLocal();\n    return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&\n           !IsLimited(addrLocal.GetNetwork());\n}\n\n// pushes our own address to a peer\nvoid AdvertiseLocal(CNode *pnode)\n{\n    if (fListen && pnode->fSuccessfullyConnected)\n    {\n        CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());\n        // If discovery is enabled, sometimes give our peer the address it\n        // tells us that it sees us as in case it has a better idea of our\n        // address than we do.\n        if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||\n             GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))\n        {\n            addrLocal.SetIP(pnode->GetAddrLocal());\n        }\n        if (addrLocal.IsRoutable())\n        {\n            LogPrint(BCLog::NET, \"AdvertiseLocal: advertising address %s\\n\", addrLocal.ToString());\n            FastRandomContext insecure_rand;\n            pnode->PushAddress(addrLocal, insecure_rand);\n        }\n    }\n}\n\n// learn a new local address\nbool AddLocal(const CService& addr, int nScore)\n{\n    if (!addr.IsRoutable())\n        return false;\n\n    if (!fDiscover && nScore < LOCAL_MANUAL)\n        return false;\n\n    if (IsLimited(addr))\n        return false;\n\n    LogPrintf(\"AddLocal(%s,%i)\\n\", addr.ToString(), nScore);\n\n    {\n        LOCK(cs_mapLocalHost);\n        bool fAlready = mapLocalHost.count(addr) > 0;\n        LocalServiceInfo &info = mapLocalHost[addr];\n        if (!fAlready || nScore >= info.nScore) {\n            info.nScore = nScore + (fAlready ? 1 : 0);\n            info.nPort = addr.GetPort();\n        }\n    }\n\n    return true;\n}\n\nbool AddLocal(const CNetAddr &addr, int nScore)\n{\n    return AddLocal(CService(addr, GetListenPort()), nScore);\n}\n\nbool RemoveLocal(const CService& addr)\n{\n    LOCK(cs_mapLocalHost);\n    LogPrintf(\"RemoveLocal(%s)\\n\", addr.ToString());\n    mapLocalHost.erase(addr);\n    return true;\n}\n\n/** Make a particular network entirely off-limits (no automatic connects to it) */\nvoid SetLimited(enum Network net, bool fLimited)\n{\n    if (net == NET_UNROUTABLE)\n        return;\n    LOCK(cs_mapLocalHost);\n    vfLimited[net] = fLimited;\n}\n\nbool IsLimited(enum Network net)\n{\n    LOCK(cs_mapLocalHost);\n    return vfLimited[net];\n}\n\nbool IsLimited(const CNetAddr &addr)\n{\n    return IsLimited(addr.GetNetwork());\n}\n\n/** vote for a local address */\nbool SeenLocal(const CService& addr)\n{\n    {\n        LOCK(cs_mapLocalHost);\n        if (mapLocalHost.count(addr) == 0)\n            return false;\n        mapLocalHost[addr].nScore++;\n    }\n    return true;\n}\n\n\n/** check whether a given address is potentially local */\nbool IsLocal(const CService& addr)\n{\n    LOCK(cs_mapLocalHost);\n    return mapLocalHost.count(addr) > 0;\n}\n\n/** check whether a given network is one we can probably connect to */\nbool IsReachable(enum Network net)\n{\n    LOCK(cs_mapLocalHost);\n    return !vfLimited[net];\n}\n\n/** check whether a given address is in a network we can probably connect to */\nbool IsReachable(const CNetAddr& addr)\n{\n    enum Network net = addr.GetNetwork();\n    return IsReachable(net);\n}\n\n\nCNode* CConnman::FindNode(const CNetAddr& ip)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes)\n        if ((CNetAddr)pnode->addr == ip)\n            return (pnode);\n    return NULL;\n}\n\nCNode* CConnman::FindNode(const CSubNet& subNet)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes)\n    if (subNet.Match((CNetAddr)pnode->addr))\n        return (pnode);\n    return NULL;\n}\n\nCNode* CConnman::FindNode(const std::string& addrName)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes) {\n        if (pnode->GetAddrName() == addrName) {\n            return (pnode);\n        }\n    }\n    return NULL;\n}\n\nCNode* CConnman::FindNode(const CService& addr)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes)\n        if ((CService)pnode->addr == addr)\n            return (pnode);\n    return NULL;\n}\n\nbool CConnman::CheckIncomingNonce(uint64_t nonce)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes) {\n        if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce)\n            return false;\n    }\n    return true;\n}\n\n/** Get the bind address for a socket as CAddress */\nstatic CAddress GetBindAddress(socket_t& sock)\n{\n    CAddress addr_bind;\n    try {\n        addr_bind.SetSockAddr(sock.local_endpoint());\n    }\n    catch (boost::system::error_code& ec) {\n        LogPrint(BCLog::NET, \"Warning: getsockname failed\\n\");\n    }\n    return addr_bind;\n}\n\nCNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)\n{\n    if (pszDest == NULL) {\n        if (IsLocal(addrConnect))\n            return NULL;\n\n        // Look for an existing connection\n        CNode* pnode = FindNode((CService)addrConnect);\n        if (pnode)\n        {\n            LogPrintf(\"Failed to open new connection, already connected\\n\");\n            return NULL;\n        }\n    }\n\n    /// debug print\n    LogPrint(BCLog::NET, \"trying connection %s lastseen=%.1fhrs\\n\",\n        pszDest ? pszDest : addrConnect.ToString(),\n        pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);\n\n    // Connect\n    socket_t socket(get_io_context());\n    bool proxyConnectionFailed = false;\n    if (pszDest ? ConnectSocketByName(addrConnect, socket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :\n                  ConnectSocket(addrConnect, socket, nConnectTimeout, &proxyConnectionFailed))\n    {\n        if (pszDest && addrConnect.IsValid()) {\n            // It is possible that we already have a connection to the IP/port pszDest resolved to.\n            // In that case, drop the connection that was just created, and return the existing CNode instead.\n            // Also store the name we used to connect in that CNode, so that future FindNode() calls to that\n            // name catch this early.\n            LOCK(cs_vNodes);\n            CNode* pnode = FindNode((CService)addrConnect);\n            if (pnode)\n            {\n                pnode->MaybeSetAddrName(std::string(pszDest));\n                try {\n                    socket.close();\n                }\n                catch (const boost::system::error_code& ec) {\n                    LogPrint(BCLog::NET, \"ConnectNode close error: %s\\n\", ec.message());\n                }\n                LogPrintf(\"Failed to open new connection, already connected\\n\");\n                return NULL;\n            }\n        }\n\n        addrman.Attempt(addrConnect, fCountFailure);\n\n        // Add node\n        NodeId id = GetNewNodeId();\n        uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();\n        CAddress addr_bind = GetBindAddress(socket);\n        CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), std::move(socket), addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : \"\", false);\n        pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);\n        pnode->AddRef();\n\n        return pnode;\n    } else if (!proxyConnectionFailed) {\n        // If connecting to the node failed, and failure is not caused by a problem connecting to\n        // the proxy, mark this as an attempt.\n        addrman.Attempt(addrConnect, fCountFailure);\n    }\n\n    return NULL;\n}\n\nvoid CConnman::DumpBanlist()\n{\n    SweepBanned(); // clean unused entries (if bantime has expired)\n\n    if (!BannedSetIsDirty())\n        return;\n\n    int64_t nStart = GetTimeMillis();\n\n    CBanDB bandb;\n    banmap_t banmap;\n    GetBanned(banmap);\n    if (bandb.Write(banmap)) {\n        SetBannedSetDirty(false);\n    }\n\n    LogPrint(BCLog::NET, \"Flushed %d banned node ips/subnets to banlist.dat  %dms\\n\",\n        banmap.size(), GetTimeMillis() - nStart);\n}\n\nvoid CNode::CloseSocketDisconnect()\n{\n    fDisconnect = true;\n    LogPrint(BCLog::NET, \"disconnecting peer=%d\\n\", id);\n    try {\n        hSocket.close();\n        inactivityTimer.cancel();\n    }\n    catch(const boost::system::system_error& ec) {\n        LogPrint(BCLog::NET, \"disconnecting peer=%d socket close: %s\\n\", id, ec.what());\n    }\n}\n\nvoid CConnman::ClearBanned()\n{\n    {\n        LOCK(cs_setBanned);\n        setBanned.clear();\n        setBannedIsDirty = true;\n    }\n    DumpBanlist(); //store banlist to disk\n    if(clientInterface)\n        clientInterface->BannedListChanged();\n}\n\nbool CConnman::IsBanned(CNetAddr ip)\n{\n    bool fResult = false;\n    {\n        LOCK(cs_setBanned);\n        for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++)\n        {\n            CSubNet subNet = (*it).first;\n            CBanEntry banEntry = (*it).second;\n\n            if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil)\n                fResult = true;\n        }\n    }\n    return fResult;\n}\n\nbool CConnman::IsBanned(CSubNet subnet)\n{\n    bool fResult = false;\n    {\n        LOCK(cs_setBanned);\n        banmap_t::iterator i = setBanned.find(subnet);\n        if (i != setBanned.end())\n        {\n            CBanEntry banEntry = (*i).second;\n            if (GetTime() < banEntry.nBanUntil)\n                fResult = true;\n        }\n    }\n    return fResult;\n}\n\nvoid CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {\n    CSubNet subNet(addr);\n    Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);\n}\n\nvoid CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {\n    CBanEntry banEntry(GetTime());\n    banEntry.banReason = banReason;\n    if (bantimeoffset <= 0)\n    {\n        bantimeoffset = GetArg(\"-bantime\", DEFAULT_MISBEHAVING_BANTIME);\n        sinceUnixEpoch = false;\n    }\n    banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;\n\n    {\n        LOCK(cs_setBanned);\n        if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {\n            setBanned[subNet] = banEntry;\n            setBannedIsDirty = true;\n        }\n        else\n            return;\n    }\n    if(clientInterface)\n        clientInterface->BannedListChanged();\n    {\n        LOCK(cs_vNodes);\n        for(CNode* pnode : vNodes) {\n            if (subNet.Match((CNetAddr)pnode->addr))\n                pnode->fDisconnect = true;\n        }\n    }\n    if(banReason == BanReasonManuallyAdded)\n        DumpBanlist(); //store banlist to disk immediately if user requested ban\n}\n\nbool CConnman::Unban(const CNetAddr &addr) {\n    CSubNet subNet(addr);\n    return Unban(subNet);\n}\n\nbool CConnman::Unban(const CSubNet &subNet) {\n    {\n        LOCK(cs_setBanned);\n        if (!setBanned.erase(subNet))\n            return false;\n        setBannedIsDirty = true;\n    }\n    if(clientInterface)\n        clientInterface->BannedListChanged();\n    DumpBanlist(); //store banlist to disk immediately\n    return true;\n}\n\nvoid CConnman::GetBanned(banmap_t &banMap)\n{\n    LOCK(cs_setBanned);\n    // Sweep the banlist so expired bans are not returned\n    SweepBanned();\n    banMap = setBanned; //create a thread safe copy\n}\n\nvoid CConnman::SetBanned(const banmap_t &banMap)\n{\n    LOCK(cs_setBanned);\n    setBanned = banMap;\n    setBannedIsDirty = true;\n}\n\nvoid CConnman::SweepBanned()\n{\n    int64_t now = GetTime();\n\n    LOCK(cs_setBanned);\n    banmap_t::iterator it = setBanned.begin();\n    while(it != setBanned.end())\n    {\n        CSubNet subNet = (*it).first;\n        CBanEntry banEntry = (*it).second;\n        if(now > banEntry.nBanUntil)\n        {\n            setBanned.erase(it++);\n            setBannedIsDirty = true;\n            LogPrint(BCLog::NET, \"%s: Removed banned node ip/subnet from banlist.dat: %s\\n\", __func__, subNet.ToString());\n        }\n        else\n            ++it;\n    }\n}\n\nbool CConnman::BannedSetIsDirty()\n{\n    LOCK(cs_setBanned);\n    return setBannedIsDirty;\n}\n\nvoid CConnman::SetBannedSetDirty(bool dirty)\n{\n    LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag\n    setBannedIsDirty = dirty;\n}\n\n\nbool CConnman::IsWhitelistedRange(const CNetAddr &addr) {\n    LOCK(cs_vWhitelistedRange);\n    for(const CSubNet& subnet : vWhitelistedRange) {\n        if (subnet.Match(addr))\n            return true;\n    }\n    return false;\n}\n\nvoid CConnman::AddWhitelistedRange(const CSubNet &subnet) {\n    LOCK(cs_vWhitelistedRange);\n    vWhitelistedRange.push_back(subnet);\n}\n\n\nstd::string CNode::GetAddrName() const {\n    LOCK(cs_addrName);\n    return addrName;\n}\n\nvoid CNode::MaybeSetAddrName(const std::string& addrNameIn) {\n    LOCK(cs_addrName);\n    if (addrName.empty()) {\n        addrName = addrNameIn;\n    }\n}\n\nCService CNode::GetAddrLocal() const {\n    LOCK(cs_addrLocal);\n    return addrLocal;\n}\n\nvoid CNode::SetAddrLocal(const CService& addrLocalIn) {\n    LOCK(cs_addrLocal);\n    if (addrLocal.IsValid()) {\n        error(\"Addr local already set for node: %i. Refusing to change from %s to %s\", id, addrLocal.ToString(), addrLocalIn.ToString());\n    } else {\n        addrLocal = addrLocalIn;\n    }\n}\n\n#undef X\n#define X(name) stats.name = name\nvoid CNode::copyStats(CNodeStats &stats)\n{\n    stats.nodeid = this->GetId();\n    X(nServices);\n    X(addr);\n    X(addrBind);\n    {\n        X(fRelayTxes);\n    }\n    X(nLastSend);\n    X(nLastRecv);\n    X(nTimeConnected);\n    X(nTimeOffset);\n    stats.addrName = GetAddrName();\n    X(nVersion);\n    {\n        LOCK(cs_SubVer);\n        X(cleanSubVer);\n    }\n    X(fInbound);\n    X(fAddnode);\n    X(nStartingHeight);\n    {\n        LOCK(cs_vSend);\n        X(mapSendBytesPerMsgCmd);\n        X(nSendBytes);\n    }\n    {\n        LOCK(cs_vRecv);\n        X(mapRecvBytesPerMsgCmd);\n        X(nRecvBytes);\n    }\n    X(fWhitelisted);\n\n    // It is common for nodes with good ping times to suddenly become lagged,\n    // due to a new block arriving or other large transfer.\n    // Merely reporting pingtime might fool the caller into thinking the node was still responsive,\n    // since pingtime does not update until the ping is complete, which might take a while.\n    // So, if a ping is taking an unusually long time in flight,\n    // the caller can immediately detect that this is happening.\n    int64_t nPingUsecWait = 0;\n    if ((0 != nPingNonceSent) && (0 != nPingUsecStart)) {\n        nPingUsecWait = GetTimeMicros() - nPingUsecStart;\n    }\n\n    // Raw ping time is in microseconds, but show it to user as whole seconds (Munt users should be well used to small numbers with many decimal places by now :)\n    stats.dPingTime = (((double)nPingUsecTime) / 1e6);\n    stats.dMinPing  = (((double)nMinPingUsecTime) / 1e6);\n    stats.dPingWait = (((double)nPingUsecWait) / 1e6);\n\n    // Leave string empty if addrLocal invalid (not filled in yet)\n    CService addrLocalUnlocked = GetAddrLocal();\n    stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : \"\";\n}\n#undef X\n\nbool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete)\n{\n    complete = false;\n    int64_t nTimeMicros = GetTimeMicros();\n    LOCK(cs_vRecv);\n    nLastRecv = nTimeMicros / 1000000;\n    nRecvBytes += nBytes;\n    while (nBytes > 0) {\n\n        // get current incomplete message, or create a new one\n        if (vRecvMsg.empty() ||\n            vRecvMsg.back().complete())\n            vRecvMsg.push_back(CNetMessage(Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION));\n\n        CNetMessage& msg = vRecvMsg.back();\n\n        // absorb network data\n        int handled;\n        if (!msg.in_data)\n            handled = msg.readHeader(pch, nBytes);\n        else\n            handled = msg.readData(pch, nBytes);\n\n        if (handled < 0)\n            return false;\n\n        if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {\n            LogPrint(BCLog::NET, \"Oversized message from peer=%i, disconnecting\\n\", GetId());\n            return false;\n        }\n\n        pch += handled;\n        nBytes -= handled;\n\n        if (msg.complete()) {\n\n            //store received bytes per message command\n            //to prevent a memory DOS, only allow valid commands\n            mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand);\n            if (i == mapRecvBytesPerMsgCmd.end())\n                i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);\n            assert(i != mapRecvBytesPerMsgCmd.end());\n            i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;\n\n            msg.nTime = nTimeMicros;\n            complete = true;\n        }\n    }\n\n    return true;\n}\n\nvoid CNode::SetSendVersion(int nVersionIn)\n{\n    // Send version may only be changed in the version message, and\n    // only one version message is allowed per session. We can therefore\n    // treat this value as const and even atomic as long as it's only used\n    // once a version message has been successfully processed. Any attempt to\n    // set this twice is an error.\n    if (nSendVersion != 0) {\n        error(\"Send version already set for node: %i. Refusing to change from %i to %i\", id, nSendVersion, nVersionIn);\n    } else {\n        nSendVersion = nVersionIn;\n    }\n}\n\nint CNode::GetSendVersion() const\n{\n    // The send version should always be explicitly set to\n    // INIT_PROTO_VERSION rather than using this value until SetSendVersion\n    // has been called.\n    if (nSendVersion == 0) {\n        error(\"Requesting unset send version for node: %i. Using %i\", id, INIT_PROTO_VERSION);\n        return INIT_PROTO_VERSION;\n    }\n    return nSendVersion;\n}\n\n\nint CNetMessage::readHeader(const char *pch, unsigned int nBytes)\n{\n    // copy data to temporary parsing buffer\n    unsigned int nRemaining = 24 - nHdrPos;\n    unsigned int nCopy = std::min(nRemaining, nBytes);\n\n    memcpy(&hdrbuf[nHdrPos], pch, nCopy);\n    nHdrPos += nCopy;\n\n    // if header incomplete, exit\n    if (nHdrPos < 24)\n        return nCopy;\n\n    // deserialize to CMessageHeader\n    try {\n        hdrbuf >> hdr;\n    }\n    catch (const std::exception&) {\n        return -1;\n    }\n\n    // reject messages larger than MAX_SIZE\n    if (hdr.nMessageSize > MAX_SIZE)\n        return -1;\n\n    // switch state to reading message data\n    in_data = true;\n\n    return nCopy;\n}\n\nint CNetMessage::readData(const char *pch, unsigned int nBytes)\n{\n    unsigned int nRemaining = hdr.nMessageSize - nDataPos;\n    unsigned int nCopy = std::min(nRemaining, nBytes);\n\n    if (vRecv.size() < nDataPos + nCopy) {\n        // Allocate up to 256 KiB ahead, but never more than the total message size.\n        vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));\n    }\n\n    hasher.Write((const unsigned char*)pch, nCopy);\n    memcpy(&vRecv[nDataPos], pch, nCopy);\n    nDataPos += nCopy;\n\n    return nCopy;\n}\n\nconst uint256& CNetMessage::GetMessageHash() const\n{\n    assert(complete());\n    if (data_hash.IsNull())\n        hasher.Finalize(data_hash.begin());\n    return data_hash;\n}\n\nstruct NodeEvictionCandidate\n{\n    NodeId id;\n    int64_t nTimeConnected;\n    int64_t nMinPingUsecTime;\n    int64_t nLastBlockTime;\n    int64_t nLastTXTime;\n    bool fRelevantServices;\n    bool fRelayTxes;\n    CAddress addr;\n    uint64_t nKeyedNetGroup;\n};\n\nstatic bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)\n{\n    return a.nMinPingUsecTime > b.nMinPingUsecTime;\n}\n\nstatic bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)\n{\n    return a.nTimeConnected > b.nTimeConnected;\n}\n\nstatic bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {\n    return a.nKeyedNetGroup < b.nKeyedNetGroup;\n}\n\nstatic bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)\n{\n    // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.\n    if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;\n    if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;\n    return a.nTimeConnected > b.nTimeConnected;\n}\n\nstatic bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)\n{\n    // There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.\n    if (a.nLastTXTime != b.nLastTXTime) return a.nLastTXTime < b.nLastTXTime;\n    if (a.fRelayTxes != b.fRelayTxes) return b.fRelayTxes;\n    return a.nTimeConnected > b.nTimeConnected;\n}\n\n/** Try to find a connection to evict when the node is full.\n *  Extreme care must be taken to avoid opening the node to attacker\n *   triggered network partitioning.\n *  The strategy used here is to protect a small number of peers\n *   for each of several distinct characteristics which are difficult\n *   to forge.  In order to partition a node the attacker must be\n *   simultaneously better at all of them than honest peers.\n */\nbool CConnman::AttemptToEvictConnection()\n{\n    std::vector<NodeEvictionCandidate> vEvictionCandidates;\n    {\n        LOCK(cs_vNodes);\n\n        for(CNode *node : vNodes) {\n            if (node->fWhitelisted)\n                continue;\n            if (!node->fInbound)\n                continue;\n            if (node->fDisconnect)\n                continue;\n            NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,\n                                               node->nLastBlockTime, node->nLastTXTime,\n                                               (node->nServices & nRelevantServices) == nRelevantServices,\n                                               node->fRelayTxes, node->addr, node->nKeyedNetGroup};\n            vEvictionCandidates.push_back(candidate);\n        }\n    }\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Protect connections with certain characteristics\n\n    // Deterministically select 4 peers to protect by netgroup.\n    // An attacker cannot predict which netgroups will be protected\n    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed);\n    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Protect the 8 nodes with the lowest minimum ping time.\n    // An attacker cannot manipulate this metric without physically moving nodes closer to the target.\n    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);\n    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Protect 4 nodes that most recently sent us transactions.\n    // An attacker cannot manipulate this metric without performing useful work.\n    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);\n    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Protect 4 nodes that most recently sent us blocks.\n    // An attacker cannot manipulate this metric without performing useful work.\n    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);\n    vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Protect the half of the remaining nodes which have been connected the longest.\n    // This replicates the non-eviction implicit behavior, and precludes attacks that start later.\n    std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);\n    vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());\n\n    if (vEvictionCandidates.empty()) return false;\n\n    // Identify the network group with the most connections and youngest member.\n    // (vEvictionCandidates is already sorted by reverse connect time)\n    uint64_t naMostConnections;\n    unsigned int nMostConnections = 0;\n    int64_t nMostConnectionsTime = 0;\n    std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;\n    for(const NodeEvictionCandidate &node : vEvictionCandidates) {\n        mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);\n        int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;\n        size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();\n\n        if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {\n            nMostConnections = groupsize;\n            nMostConnectionsTime = grouptime;\n            naMostConnections = node.nKeyedNetGroup;\n        }\n    }\n\n    // Reduce to the network group with the most connections\n    vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);\n\n    // Disconnect from the network group with the most connections\n    NodeId evicted = vEvictionCandidates.front().id;\n    LOCK(cs_vNodes);\n    for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {\n        if ((*it)->GetId() == evicted) {\n            (*it)->fDisconnect = true;\n            return true;\n        }\n    }\n    return false;\n}\n\n\n\nvoid CConnman::NodeDisconnectAndDeleter()\n{\n    const int INTERVAL_SEC = 1;\n\n    disconnectAndDeleterTimer.expires_from_now(boost::posix_time::seconds(INTERVAL_SEC));\n    disconnectAndDeleterTimer.async_wait([this](const boost::system::error_code& ec) {\n        if (ec)\n            return;\n\n        //\n        // Disconnect nodes\n        //\n        {\n            LOCK(cs_vNodes);\n            // Disconnect unused nodes\n            std::vector<CNode*> vNodesCopy = vNodes;\n            for(CNode* pnode : vNodesCopy)\n            {\n                if (pnode->fDisconnect)\n                {\n                    // remove from vNodes\n                    vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());\n\n                    // release outbound grant (if any)\n                    pnode->grantOutbound.Release();\n\n                    // close socket and cleanup\n                    pnode->CloseSocketDisconnect();\n\n                    // hold in disconnected pool until all refs are released\n                    pnode->Release();\n                    vNodesDisconnected.push_back(pnode);\n                }\n            }\n        }\n        {\n            // Delete disconnected nodes\n            std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;\n            for(CNode* pnode : vNodesDisconnectedCopy)\n            {\n                // wait until threads are done using it\n                if (pnode->GetRefCount() <= 0) {\n                    bool fDelete = false;\n                    {\n                        TRY_LOCK(pnode->cs_inventory, lockInv);\n                        if (lockInv) {\n                            TRY_LOCK(pnode->cs_vSend, lockSend);\n                            if (lockSend) {\n                                fDelete = true;\n                            }\n                        }\n                    }\n                    if (fDelete) {\n                        vNodesDisconnected.remove(pnode);\n                        DeleteNode(pnode);\n                    }\n                }\n            }\n        }\n\n        NodeDisconnectAndDeleter();\n    });\n}\n\nvoid CConnman::NumConnectionsNotifier()\n{\n    const int INTERVAL_SEC = 1;\n    static unsigned int nPrevNodeCount = 0;\n\n    connectionsNotifierTimer.expires_from_now(boost::posix_time::seconds(INTERVAL_SEC));\n    connectionsNotifierTimer.async_wait([this](const boost::system::error_code& ec) {\n        if (ec)\n            return;\n\n        size_t vNodesSize;\n        {\n            LOCK(cs_vNodes);\n            vNodesSize = vNodes.size();\n        }\n        if(vNodesSize != nPrevNodeCount) {\n            nPrevNodeCount = vNodesSize;\n            if(clientInterface)\n                clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount);\n        }\n\n        NumConnectionsNotifier();\n    });\n}\n\nvoid CConnman::NodeInactivityChecker(CNode* pnode)\n{\n    pnode->AddRef();\n\n    const int INTERVAL_SEC = 1;\n\n    pnode->inactivityTimer.expires_from_now(boost::posix_time::seconds(INTERVAL_SEC));\n    pnode->inactivityTimer.async_wait([this, pnode](const boost::system::error_code& ec) {\n\n        if (!ec) {\n            int64_t nTime = GetTimeSeconds();\n            if (nTime - pnode->nTimeConnected > 60)\n            {\n                if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)\n                {\n                    LogPrint(BCLog::NET, \"socket no message in first 60 seconds, %d %d from %d\\n\", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());\n                    pnode->fDisconnect = true;\n                }\n                else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)\n                {\n                    LogPrintf(\"socket sending timeout: %is\\n\", nTime - pnode->nLastSend);\n                    pnode->fDisconnect = true;\n                }\n                else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))\n                {\n                    LogPrintf(\"socket receive timeout: %is\\n\", nTime - pnode->nLastRecv);\n                    pnode->fDisconnect = true;\n                }\n                else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())\n                {\n                    LogPrintf(\"ping timeout: %fs\\n\", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));\n                    pnode->fDisconnect = true;\n                }\n                else if (!pnode->fSuccessfullyConnected)\n                {\n                    LogPrintf(\"version handshake timeout from %d\\n\", pnode->GetId());\n                    pnode->fDisconnect = true;\n                }\n            }\n            if (!pnode->fDisconnect)\n                NodeInactivityChecker(pnode);\n        }\n        else if (ec == boost::asio::error::operation_aborted)\n        {\n            LogPrint(BCLog::NET, \"inactivity timer for %d aborted\\n\", pnode->GetId());\n        }\n        else\n        {\n            LogPrint(BCLog::NET, \"inactivity timer for %d failed [%s]\\n\", pnode->GetId(), ec.message().c_str());\n        }\n        pnode->Release();\n    });\n}\n\nvoid CConnman::ResumeReceive(CNode* pnode)\n{\n    // Implement the following logic:\n    // * If there is (too much) data to send halt receiving and first drain the write buffer.\n    //   This avoids needlessly queueing received data, if the remote peer is not themselves\n    //   receiving data. This means properly utilizing TCP flow control signalling.\n    // * Otherwise, if there is space left in the receive buffer handle incoming data.\n    // * Hand off all complete messages to the processor, to be handled without\n    //   blocking here.\n\n    if (interruptNet)\n        return;\n\n    if (pnode->fPauseRecv)\n        return;\n\n    pnode->AddRef();\n\n    pnode->hSocket.async_receive(boost::asio::mutable_buffer(pnode->pchBuf, sizeof(pnode->pchBuf)),\n                                 [this,pnode] (const boost::system::error_code& ec, std::size_t bytes_transferred) {\n        if (!ec) {\n            bool msgcomplete = false;\n            if (!pnode->ReceiveMsgBytes(pnode->pchBuf, bytes_transferred, msgcomplete)) {\n                pnode->fDisconnect = true;\n            }\n            else {\n                RecordBytesRecv(bytes_transferred);\n                if (msgcomplete) {\n                    size_t nSizeAdded = 0;\n                    auto it(pnode->vRecvMsg.begin());\n                    for (; it != pnode->vRecvMsg.end(); ++it) {\n                        if (!it->complete())\n                            break;\n                        nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;\n                    }\n                    {\n                        LOCK(pnode->cs_vProcessMsg);\n                        pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);\n                        pnode->nProcessQueueSize += nSizeAdded;\n                        pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;\n                    }\n                    WakeMessageHandler();\n                }\n                this->ResumeReceive(pnode);\n            }\n        }\n        else {\n            if (boost::asio::error::eof == ec) {\n                // socket closed gracefully\n                if (!pnode->fDisconnect) {\n                    LogPrint(BCLog::NET, \"socket closed\\n\");\n                }\n            }\n            else {\n                if (!pnode->fDisconnect)\n                    LogPrintf(\"socket recv error %s\\n\", ec.message());\n            }\n            pnode->fDisconnect = true;\n        }\n\n        pnode->Release();\n    });\n}\n\nvoid CConnman::ThreadSocketHandler()\n{\n    NodeDisconnectAndDeleter();\n    NumConnectionsNotifier();\n\n    while (!interruptNet) {\n        get_io_context().run();\n        if (!interruptNet.sleep_for(std::chrono::milliseconds(50)))\n            return;\n        get_io_context().restart();\n    }\n}\n\nvoid CConnman::WakeMessageHandler()\n{\n    {\n        std::lock_guard<std::mutex> lock(mutexMsgProc);\n        fMsgProcWake = true;\n    }\n    condMsgProc.notify_one();\n}\n\n\n\n\n\n\n#ifdef USE_UPNP\nstatic void ThreadMapPort()\n{\n    std::string port = strprintf(\"%u\", GetListenPort());\n    const char * multicastif = 0;\n    const char * minissdpdpath = 0;\n    struct UPNPDev * devlist = 0;\n    char lanaddr[64];\n\n#ifndef UPNPDISCOVER_SUCCESS\n    /* miniupnpc 1.5 */\n    devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);\n#elif MINIUPNPC_API_VERSION < 14\n    /* miniupnpc 1.6 */\n    int error = 0;\n    devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);\n#else\n    /* miniupnpc 1.9.20150730 */\n    int error = 0;\n    devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);\n#endif\n\n    struct UPNPUrls urls;\n    struct IGDdatas data;\n    int r;\n\n    r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));\n    if (r == 1)\n    {\n        if (fDiscover) {\n            char externalIPAddress[40];\n            r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);\n            if(r != UPNPCOMMAND_SUCCESS)\n                LogPrintf(\"UPnP: GetExternalIPAddress() returned %d\\n\", r);\n            else\n            {\n                if(externalIPAddress[0])\n                {\n                    CNetAddr resolved;\n                    if(LookupHost(externalIPAddress, resolved, false)) {\n                        LogPrintf(\"UPnP: ExternalIPAddress = %s\\n\", resolved.ToString().c_str());\n                        AddLocal(resolved, LOCAL_UPNP);\n                    }\n                }\n                else\n                    LogPrintf(\"UPnP: GetExternalIPAddress failed.\\n\");\n            }\n        }\n\n        std::string strDesc = GLOBAL_APPNAME \" \" + FormatFullVersion();\n\n        try {\n            while (true) {\n#ifndef UPNPDISCOVER_SUCCESS\n                /* miniupnpc 1.5 */\n                r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,\n                                    port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), \"TCP\", 0);\n#else\n                /* miniupnpc 1.6 */\n                r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,\n                                    port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), \"TCP\", 0, \"0\");\n#endif\n\n                if(r!=UPNPCOMMAND_SUCCESS)\n                    LogPrintf(\"AddPortMapping(%s, %s, %s) failed with code %d (%s)\\n\",\n                        port, port, lanaddr, r, strupnperror(r));\n                else\n                    LogPrintf(\"UPnP Port Mapping successful.\\n\");\n\n                MilliSleep(20*60*1000); // Refresh every 20 minutes\n            }\n        }\n        catch (const boost::thread_interrupted&)\n        {\n            r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), \"TCP\", 0);\n            LogPrintf(\"UPNP_DeletePortMapping() returned: %d\\n\", r);\n            freeUPNPDevlist(devlist); devlist = 0;\n            FreeUPNPUrls(&urls);\n            throw;\n        }\n    } else {\n        LogPrintf(\"No valid UPnP IGDs found\\n\");\n        freeUPNPDevlist(devlist); devlist = 0;\n        if (r != 0)\n            FreeUPNPUrls(&urls);\n    }\n}\n\nvoid MapPort(bool fUseUPnP)\n{\n    static boost::thread* upnp_thread = NULL;\n\n    if (fUseUPnP)\n    {\n        if (upnp_thread) {\n            upnp_thread->interrupt();\n            upnp_thread->join();\n            delete upnp_thread;\n        }\n        upnp_thread = new boost::thread(&util::TraceThread, \"upnp\", std::function<void()>(&ThreadMapPort));\n    }\n    else if (upnp_thread) {\n        upnp_thread->interrupt();\n        upnp_thread->join();\n        delete upnp_thread;\n        upnp_thread = NULL;\n    }\n}\n\n#else\nvoid MapPort(bool)\n{\n    // Intentionally left blank.\n}\n#endif\n\n\n\n\n\n\nstatic std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredServiceBits)\n{\n    //use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK)\n    if (!data.supportsServiceBitsFiltering || *requiredServiceBits == NODE_NETWORK) {\n        *requiredServiceBits = NODE_NETWORK;\n        return data.host;\n    }\n\n    // See chainparams.cpp, most dnsseeds only support one or two possible servicebits hostnames\n    return strprintf(\"x%x.%s\", *requiredServiceBits, data.host);\n}\n\n\nvoid CConnman::ThreadDNSAddressSeed()\n{\n    // goal: only query DNS seeds if address need is acute\n    // Avoiding DNS seeds when we don't need them improves user privacy by\n    //  creating fewer identifying DNS requests, reduces trust by giving seeds\n    //  less influence on the network topology, and reduces traffic to the seeds.\n    if ((addrman.size() > 0) &&\n        (!GetBoolArg(\"-forcednsseed\", DEFAULT_FORCEDNSSEED))) {\n        if (!interruptNet.sleep_for(std::chrono::seconds(11)))\n            return;\n\n        LOCK(cs_vNodes);\n        int nRelevant = 0;\n        for (auto pnode : vNodes) {\n            nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);\n        }\n        if (nRelevant >= 2) {\n            LogPrintf(\"P2P peers available. Skipped DNS seeding.\\n\");\n            return;\n        }\n    }\n\n    const std::vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();\n    int found = 0;\n\n    LogPrintf(\"Loading addresses from DNS seeds (could take a while)\\n\");\n\n    for(const CDNSSeedData &seed : vSeeds) {\n        if (interruptNet) {\n            return;\n        }\n        if (HaveNameProxy()) {\n            AddOneShot(seed.host);\n        } else {\n            std::vector<CNetAddr> vIPs;\n            std::vector<CAddress> vAdd;\n            ServiceFlags requiredServiceBits = nRelevantServices;\n            if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))\n            {\n                for(const CNetAddr& ip : vIPs)\n                {\n                    int nOneDay = 24*3600;\n                    CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);\n                    addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old\n                    vAdd.push_back(addr);\n                    found++;\n                }\n            }\n            if (interruptNet) {\n                return;\n            }\n            // TODO: The seed name resolve may fail, yielding an IP of [::], which results in\n            // addrman assigning the same source to results from different seeds.\n            // This should switch to a hard-coded stable dummy IP for each seed name, so that the\n            // resolve is not required at all.\n            if (!vIPs.empty()) {\n                CService seedSource;\n                Lookup(seed.name.c_str(), seedSource, 0, true);\n                addrman.Add(vAdd, seedSource);\n            }\n        }\n    }\n\n    LogPrintf(\"%d addresses found from DNS seeds\\n\", found);\n}\n\n\n\n\n\n\n\n\n\n\n\n\nvoid CConnman::DumpAddresses()\n{\n    int64_t nStart = GetTimeMillis();\n\n    CAddrDB adb;\n    adb.Write(addrman);\n\n    LogPrint(BCLog::NET, \"Flushed %d addresses to peers.dat  %dms\\n\",\n           addrman.size(), GetTimeMillis() - nStart);\n}\n\nvoid CConnman::DumpData()\n{\n    DumpAddresses();\n    DumpBanlist();\n}\n\nvoid CConnman::ProcessOneShot()\n{\n    std::string strDest;\n    {\n        LOCK(cs_vOneShots);\n        if (vOneShots.empty())\n            return;\n        strDest = vOneShots.front();\n        vOneShots.pop_front();\n    }\n    CAddress addr;\n    CSemaphoreGrant grant(*semOutbound, true);\n    if (grant) {\n        if (!OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true))\n            AddOneShot(strDest);\n    }\n}\n\nvoid CConnman::ThreadOpenConnections()\n{\n    // Connect to specific addresses\n    if (gArgs.IsArgSet(\"-connect\") && gArgs.GetArgs(\"-connect\").size() > 0)\n    {\n        for (int64_t nLoop = 0;; nLoop++)\n        {\n            ProcessOneShot();\n            for(const std::string& strAddr : gArgs.GetArgs(\"-connect\"))\n            {\n                CAddress addr(CService(), NODE_NONE);\n                OpenNetworkConnection(addr, false, NULL, strAddr.c_str());\n                for (int i = 0; i < 10 && i < nLoop; i++)\n                {\n                    if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))\n                        return;\n                }\n            }\n            if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))\n                return;\n        }\n    }\n\n    // Initiate network connections\n    int64_t nStart = GetTime();\n\n    // Minimum time before next feeler connection (in microseconds).\n    int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);\n    while (!interruptNet)\n    {\n        ProcessOneShot();\n\n        if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))\n            return;\n\n        CSemaphoreGrant grant(*semOutbound);\n        if (interruptNet)\n            return;\n\n        // Add seed nodes if DNS seeds are all down (an infrastructure attack?).\n        if (addrman.size() == 0 && (GetTime() - nStart > 60)) {\n            static bool done = false;\n            if (!done) {\n                LogPrintf(\"Adding fixed seed nodes as DNS doesn't seem to be available.\\n\");\n                CNetAddr local;\n                LookupHost(\"127.0.0.1\", local, false);\n                addrman.Add(convertSeed6(Params().FixedSeeds()), local);\n                done = true;\n            }\n        }\n\n        //\n        // Choose an address to connect to based on most recently seen\n        //\n        CAddress addrConnect;\n\n        // Only connect out to one peer per network group (/16 for IPv4).\n        // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.\n        int nOutbound = 0;\n        int nOutboundRelevant = 0;\n        std::set<std::vector<unsigned char> > setConnected;\n        {\n            LOCK(cs_vNodes);\n            for(CNode* pnode : vNodes) {\n                if (!pnode->fInbound && !pnode->fAddnode) {\n\n                    // Count the peers that have all relevant services\n                    if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) {\n                        nOutboundRelevant++;\n                    }\n                    // Netgroups for inbound and addnode peers are not excluded because our goal here\n                    // is to not use multiple of our limited outbound slots on a single netgroup\n                    // but inbound and addnode peers do not use our outbound slots.  Inbound peers\n                    // also have the added issue that they're attacker controlled and could be used\n                    // to prevent us from connecting to particular hosts if we used them here.\n                    setConnected.insert(pnode->addr.GetGroup());\n                    nOutbound++;\n                }\n            }\n        }\n\n        // Feeler Connections\n        //\n        // Design goals:\n        //  * Increase the number of connectable addresses in the tried table.\n        //\n        // Method:\n        //  * Choose a random address from new and attempt to connect to it if we can connect\n        //    successfully it is added to tried.\n        //  * Start attempting feeler connections only after node finishes making outbound\n        //    connections.\n        //  * Only make a feeler connection once every few minutes.\n        //\n        bool fFeeler = false;\n        if (nOutbound >= nMaxOutbound) {\n            int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).\n            if (nTime > nNextFeeler) {\n                nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);\n                fFeeler = true;\n            } else {\n                continue;\n            }\n        }\n\n        int64_t nANow = GetAdjustedTime();\n        int nTries = 0;\n        while (!interruptNet)\n        {\n            CAddrInfo addr = addrman.Select(fFeeler);\n\n            // if we selected an invalid address, restart\n            if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))\n                break;\n\n            // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,\n            // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates\n            // already-connected network ranges, ...) before trying new addrman addresses.\n            nTries++;\n            if (nTries > 100)\n                break;\n\n            if (IsLimited(addr))\n                continue;\n\n            // only connect to full nodes\n            if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)\n                continue;\n\n            // only consider very recently tried nodes after 30 failed attempts\n            if (nANow - addr.nLastTry < 600 && nTries < 30)\n                continue;\n\n            // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up.\n            ServiceFlags nRequiredServices = nRelevantServices;\n            if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) {\n                nRequiredServices = REQUIRED_SERVICES;\n            }\n\n            if ((addr.nServices & nRequiredServices) != nRequiredServices) {\n                continue;\n            }\n\n            // do not allow non-default ports, unless after 50 invalid addresses selected already\n            if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50)\n                continue;\n\n            addrConnect = addr;\n\n            // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services\n            if (nOutboundRelevant >= (nMaxOutbound >> 1)) {\n                addrConnect.nServices = REQUIRED_SERVICES;\n            } else {\n                addrConnect.nServices = nRequiredServices;\n            }\n            break;\n        }\n\n        if (addrConnect.IsValid()) {\n\n            if (fFeeler) {\n                // Add small amount of random noise before connection to avoid synchronization.\n                int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);\n                if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))\n                    return;\n                LogPrint(BCLog::NET, \"Making feeler connection to %s\\n\", addrConnect.ToString());\n            }\n\n            OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler);\n        }\n    }\n}\n\nstd::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()\n{\n    std::vector<AddedNodeInfo> ret;\n\n    std::list<std::string> lAddresses(0);\n    {\n        LOCK(cs_vAddedNodes);\n        ret.reserve(vAddedNodes.size());\n        for(const std::string& strAddNode : vAddedNodes)\n            lAddresses.push_back(strAddNode);\n    }\n\n\n    // Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService\n    std::map<CService, bool> mapConnected;\n    std::map<std::string, std::pair<bool, CService>> mapConnectedByName;\n    {\n        LOCK(cs_vNodes);\n        for (const CNode* pnode : vNodes) {\n            if (pnode->addr.IsValid()) {\n                mapConnected[pnode->addr] = pnode->fInbound;\n            }\n            std::string addrName = pnode->GetAddrName();\n            if (!addrName.empty()) {\n                mapConnectedByName[std::move(addrName)] = std::pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));\n            }\n        }\n    }\n\n    for(const std::string& strAddNode : lAddresses) {\n        CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort()));\n        if (service.IsValid()) {\n            // strAddNode is an IP:port\n            auto it = mapConnected.find(service);\n            if (it != mapConnected.end()) {\n                ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});\n            } else {\n                ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});\n            }\n        } else {\n            // strAddNode is a name\n            auto it = mapConnectedByName.find(strAddNode);\n            if (it != mapConnectedByName.end()) {\n                ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});\n            } else {\n                ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});\n            }\n        }\n    }\n\n    return ret;\n}\n\nvoid CConnman::ThreadOpenAddedConnections()\n{\n    {\n        LOCK(cs_vAddedNodes);\n        if (gArgs.IsArgSet(\"-addnode\"))\n            vAddedNodes = gArgs.GetArgs(\"-addnode\");\n    }\n\n    while (true)\n    {\n        CSemaphoreGrant grant(*semAddnode);\n        std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();\n        bool tried = false;\n        for (const AddedNodeInfo& info : vInfo) {\n            if (!info.fConnected) {\n                if (!grant.TryAcquire()) {\n                    // If we've used up our semaphore and need a new one, lets not wait here since while we are waiting\n                    // the addednodeinfo state might change.\n                    break;\n                }\n                // If strAddedNode is an IP/port, decode it immediately, so\n                // OpenNetworkConnection can detect existing connections to that IP/port.\n                tried = true;\n                CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort()));\n                OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true);\n                if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))\n                    return;\n            }\n        }\n        // Retry every 60 seconds if a connection was attempted, otherwise two seconds\n        if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)))\n            return;\n    }\n}\n\n// if successful, this moves the passed grant to the constructed node\nbool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode)\n{\n    //\n    // Initiate outbound network connection\n    //\n    if (interruptNet) {\n        return false;\n    }\n    if (!fNetworkActive) {\n        return false;\n    }\n    if (!pszDest) {\n        if (IsLocal(addrConnect) ||\n            FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) ||\n            FindNode(addrConnect.ToStringIPPort()))\n            return false;\n    } else if (FindNode(std::string(pszDest)))\n        return false;\n\n    CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);\n\n    if (!pnode)\n        return false;\n    if (grantOutbound)\n        grantOutbound->MoveTo(pnode->grantOutbound);\n    if (fOneShot)\n        pnode->fOneShot = true;\n    if (fFeeler)\n        pnode->fFeeler = true;\n    if (fAddnode)\n        pnode->fAddnode = true;\n\n    GetNodeSignals().InitializeNode(pnode, *this);\n    {\n        LOCK(cs_vNodes);\n        vNodes.push_back(pnode);\n    }\n\n    return true;\n}\n\nvoid CConnman::ThreadMessageHandler()\n{\n    while (!flagInterruptMsgProc)\n    {\n        std::vector<CNode*> vNodesCopy;\n        {\n            LOCK(cs_vNodes);\n            vNodesCopy = vNodes;\n            for(CNode* pnode : vNodesCopy) {\n                pnode->AddRef();\n            }\n        }\n\n        bool fMoreWork = false;\n\n        for(CNode* pnode : vNodesCopy)\n        {\n            if (pnode->fDisconnect)\n                continue;\n\n            // Receive messages\n            bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc);\n            fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);\n            if (flagInterruptMsgProc)\n                return;\n\n            // Send messages\n            {\n                LOCK(pnode->cs_sendProcessing);\n                GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);\n            }\n            if (flagInterruptMsgProc)\n                return;\n        }\n\n        {\n            LOCK(cs_vNodes);\n            for(CNode* pnode : vNodesCopy)\n                pnode->Release();\n        }\n\n        std::unique_lock<std::mutex> lock(mutexMsgProc);\n        if (!fMoreWork) {\n            condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100), [this] { return fMsgProcWake; });\n        }\n        fMsgProcWake = false;\n    }\n}\n\nvoid CConnman::AcceptIncoming(ListenSocket& listener)\n{\n    listener.acceptor.async_accept(listener.peer, listener.peerEndpoint,\n                                   [this, &listener](const boost::system::error_code& ec) {\n        // this handler runs in io_context.run() thread!\n\n        if (ec) {\n            LogPrintf(\"socket error acceptor failed: %s\\n\", ec.message());\n            return;\n        }\n\n        CAddress addr;\n        addr.SetSockAddr(listener.peerEndpoint);\n\n        bool connection_ok = true;\n\n        if (!fNetworkActive) {\n            LogPrintf(\"connection from %s dropped: not accepting new connections\\n\", addr.ToString());\n            connection_ok = false;\n        }\n\n        bool whitelisted = listener.whitelisted || IsWhitelistedRange(addr);\n        if (connection_ok && IsBanned(addr) && !whitelisted)\n        {\n            LogPrintf(\"connection from %s dropped (banned)\\n\", addr.ToString());\n            connection_ok = false;\n        }\n\n        if (connection_ok)\n        {\n            int nInbound = 0;\n            int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);\n            {\n                LOCK(cs_vNodes);\n                for(CNode* pnode : vNodes)\n                        if (pnode->fInbound)\n                        nInbound++;\n            }\n            if (nInbound >= nMaxInbound)\n            {\n                if (!AttemptToEvictConnection()) {\n                    // No connection to evict, disconnect the new connection\n                    LogPrint(BCLog::NET, \"failed to find an eviction candidate - connection from %s dropped (full)\\n\", addr.ToString());\n                    connection_ok = false;\n                }\n            }\n        }\n\n        if (connection_ok) {\n            // According to the internet TCP_NODELAY is not carried into accepted sockets\n            // on all platforms.  Set it again here just to be sure.\n            listener.peer.set_option(boost::asio::ip::tcp::no_delay(true));\n\n            NodeId id = GetNewNodeId();\n            uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();\n            CAddress addr_bind = GetBindAddress(listener.peer);\n\n            CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), std::move(listener.peer), addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, \"\", true);\n            pnode->AddRef();\n            pnode->fWhitelisted = whitelisted;\n            GetNodeSignals().InitializeNode(pnode, *this);\n\n            LogPrint(BCLog::NET, \"connection from %s accepted\\n\", addr.ToString());\n\n            {\n                LOCK(cs_vNodes);\n                vNodes.push_back(pnode);\n            }\n        }\n        else {\n            try {\n                listener.peer.close();\n            }\n            catch (const boost::system::error_code& ec) {\n                LogPrint(BCLog::NET, \"connection from  %s closed: %s\\n\", addr.ToString(), ec.message());\n            }\n        }\n\n        // re-run for another incoming connection\n        this->AcceptIncoming(listener);\n    });\n}\n\nbool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)\n{\n    try {\n        boost::asio::ip::tcp::endpoint endpoint(addrBind.GetSockAddr());\n\n        boost::asio::ip::tcp::acceptor acceptor(get_io_context());\n        acceptor.open(endpoint.protocol());\n        acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));\n        // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option\n        // and enable it by default or not. Try to enable it, if possible.\n#ifdef IPV6_V6ONLY\n        if (endpoint.protocol()==boost::asio::ip::tcp::v6()) {\n            acceptor.set_option(boost::asio::ip::v6_only(true));\n        }\n#endif\n        acceptor.set_option(boost::asio::ip::tcp::no_delay(true));\n        acceptor.bind(endpoint);\n        acceptor.listen(SOMAXCONN);\n\n        // There is no equivalent for this in Boost.Asio\n        //#ifdef WIN32\n        //        int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;\n        //        setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));\n        //#endif\n\n        vhListenSocket.push_back(ListenSocket(std::move(acceptor), fWhitelisted));\n        ListenSocket& listener = vhListenSocket.back();\n        AcceptIncoming(listener);\n    }\n    catch(boost::system::error_code& ec) {\n        LogPrintf(\"Listening connections on [%s] failed (%s)\\n\", addrBind.ToString(), ec.message());\n        vhListenSocket.pop_back();\n        return false;\n    }\n\n    if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)\n        AddLocal(addrBind, LOCAL_BIND);\n\n    return true;\n}\n\nvoid Discover()\n{\n    if (!fDiscover)\n        return;\n\n#ifdef WIN32\n    // Get local host IP\n    char pszHostName[256] = \"\";\n    if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)\n    {\n        std::vector<CNetAddr> vaddr;\n        if (LookupHost(pszHostName, vaddr, 0, true))\n        {\n            for (const CNetAddr &addr : vaddr)\n            {\n                if (AddLocal(addr, LOCAL_IF))\n                    LogPrintf(\"%s: %s - %s\\n\", __func__, pszHostName, addr.ToString());\n            }\n        }\n    }\n#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)\n    // Get local host ip\n    struct ifaddrs* myaddrs;\n    if (getifaddrs(&myaddrs) == 0)\n    {\n        for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)\n        {\n            if (ifa->ifa_addr == NULL) continue;\n            if ((ifa->ifa_flags & IFF_UP) == 0) continue;\n            if (strcmp(ifa->ifa_name, \"lo\") == 0) continue;\n            if (strcmp(ifa->ifa_name, \"lo0\") == 0) continue;\n            if (ifa->ifa_addr->sa_family == AF_INET)\n            {\n                struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);\n                CNetAddr addr(s4->sin_addr);\n                if (AddLocal(addr, LOCAL_IF))\n                    LogPrintf(\"%s: IPv4 %s: %s\\n\", __func__, ifa->ifa_name, addr.ToString());\n            }\n            else if (ifa->ifa_addr->sa_family == AF_INET6)\n            {\n                struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);\n                CNetAddr addr(s6->sin6_addr);\n                if (AddLocal(addr, LOCAL_IF))\n                    LogPrintf(\"%s: IPv6 %s: %s\\n\", __func__, ifa->ifa_name, addr.ToString());\n            }\n        }\n        freeifaddrs(myaddrs);\n    }\n#else\n    //fixme: (UNITY) (ANDROID) - Any point in implementing this?\n#endif\n}\n\nvoid CConnman::SetNetworkActive(bool active)\n{\n    LogPrint(BCLog::NET, \"SetNetworkActive: %s\\n\", active);\n\n    if (!active) {\n        fNetworkActive = false;\n\n        LOCK(cs_vNodes);\n        // Close sockets to all nodes\n        for(CNode* pnode : vNodes) {\n            pnode->fDisconnect = true;\n        }\n    } else {\n        fNetworkActive = true;\n    }\n\n    uiInterface.NotifyNetworkActiveChanged(fNetworkActive);\n}\n\nCConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In),\n    disconnectAndDeleterTimer(get_io_context()), connectionsNotifierTimer(get_io_context())\n{\n    fNetworkActive = true;\n    setBannedIsDirty = false;\n    fAddressesInitialized = false;\n    nLastNodeId = 0;\n    nSendBufferMaxSize = 0;\n    nReceiveFloodSize = 0;\n    semOutbound = NULL;\n    semAddnode = NULL;\n    nMaxConnections = 0;\n    nMaxOutbound = 0;\n    nMaxAddnode = 0;\n    nBestHeight = 0;\n    clientInterface = NULL;\n    flagInterruptMsgProc = false;\n}\n\nNodeId CConnman::GetNewNodeId()\n{\n    return nLastNodeId.fetch_add(1, std::memory_order_relaxed);\n}\n\nbool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options connOptions)\n{\n    nTotalBytesRecv = 0;\n    nTotalBytesSent = 0;\n    nMaxOutboundTotalBytesSentInCycle = 0;\n    nMaxOutboundCycleStartTime = 0;\n\n    nRelevantServices = connOptions.nRelevantServices;\n    nLocalServices = connOptions.nLocalServices;\n    nMaxConnections = connOptions.nMaxConnections;\n    nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections);\n    nMaxAddnode = connOptions.nMaxAddnode;\n    nMaxFeeler = connOptions.nMaxFeeler;\n\n    nSendBufferMaxSize = connOptions.nSendBufferMaxSize;\n    nReceiveFloodSize = connOptions.nReceiveFloodSize;\n\n    nMaxOutboundLimit = connOptions.nMaxOutboundLimit;\n    nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;\n\n    SetBestHeight(connOptions.nBestHeight);\n\n    for (const auto& strDest : connOptions.vSeedNodes) {\n        AddOneShot(strDest);\n    }\n\n    clientInterface = connOptions.uiInterface;\n    if (clientInterface) {\n        clientInterface->InitMessage(_(\"Loading P2P addresses...\"));\n    }\n    // Load addresses from peers.dat\n    int64_t nStart = GetTimeMillis();\n    {\n        CAddrDB adb;\n        if (adb.Read(addrman))\n            LogPrintf(\"Loaded %i addresses from peers.dat  %dms\\n\", addrman.size(), GetTimeMillis() - nStart);\n        else {\n            addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it\n            LogPrintf(\"Invalid or missing peers.dat; recreating\\n\");\n            DumpAddresses();\n        }\n    }\n    if (clientInterface)\n        clientInterface->InitMessage(_(\"Loading banlist...\"));\n    // Load addresses from banlist.dat\n    nStart = GetTimeMillis();\n    CBanDB bandb;\n    banmap_t banmap;\n    if (bandb.Read(banmap)) {\n        SetBanned(banmap); // thread save setter\n        SetBannedSetDirty(false); // no need to write down, just read data\n        SweepBanned(); // sweep out unused entries\n\n        LogPrint(BCLog::NET, \"Loaded %d banned node ips/subnets from banlist.dat  %dms\\n\",\n            banmap.size(), GetTimeMillis() - nStart);\n    } else {\n        LogPrintf(\"Invalid or missing banlist.dat; recreating\\n\");\n        SetBannedSetDirty(true); // force write\n        DumpBanlist();\n    }\n\n    uiInterface.InitMessage(_(\"Starting network threads...\"));\n\n    fAddressesInitialized = true;\n\n    if (semOutbound == NULL) {\n        // initialize semaphore\n        semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));\n    }\n    if (semAddnode == NULL) {\n        // initialize semaphore\n        semAddnode = new CSemaphore(nMaxAddnode);\n    }\n\n    //\n    // Start threads\n    //\n    InterruptSocks5(false);\n    interruptNet.reset();\n    flagInterruptMsgProc = false;\n\n    {\n        std::unique_lock<std::mutex> lock(mutexMsgProc);\n        fMsgProcWake = false;\n    }\n\n    // Send and receive from sockets, accept connections\n    threadSocketHandler = std::thread(&util::TraceThread, \"net\", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this)));\n\n    if (!GetBoolArg(\"-dnsseed\", true))\n        LogPrintf(\"DNS seeding disabled\\n\");\n    else\n        threadDNSAddressSeed = std::thread(&util::TraceThread, \"dnsseed\", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));\n\n    // Initiate outbound connections from -addnode\n    threadOpenAddedConnections = std::thread(&util::TraceThread, \"addcon\", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));\n\n    // Initiate outbound connections unless connect=0\n    if (!gArgs.IsArgSet(\"-connect\") || gArgs.GetArgs(\"-connect\").size() != 1 || gArgs.GetArgs(\"-connect\")[0] != \"0\")\n        threadOpenConnections = std::thread(&util::TraceThread, \"opencon\", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));\n\n    // Process messages\n    threadMessageHandler = std::thread(&util::TraceThread, \"msghand\", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));\n\n    // Dump network addresses\n    scheduler.scheduleEvery([this] { CConnman::DumpData(); }, std::chrono::seconds(DUMP_ADDRESSES_INTERVAL));\n\n    return true;\n}\n\nclass CNetCleanup\n{\npublic:\n    CNetCleanup() {}\n\n    ~CNetCleanup()\n    {\n#ifdef WIN32\n        // Shutdown Windows Sockets\n        WSACleanup();\n#endif\n    }\n}\ninstance_of_cnetcleanup;\n\nvoid CConnman::Interrupt()\n{\n    LogPrint(BCLog::NET, \"CConnman::Interrupt\\n\");\n\n    {\n        std::lock_guard<std::mutex> lock(mutexMsgProc);\n        flagInterruptMsgProc = true;\n    }\n    condMsgProc.notify_all();\n\n    interruptNet();\n    get_io_context().stop();\n    InterruptSocks5(true);\n\n    if (semOutbound) {\n        for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) {\n            semOutbound->post();\n        }\n    }\n\n    if (semAddnode) {\n        for (int i=0; i<nMaxAddnode; i++) {\n            semAddnode->post();\n        }\n    }\n}\n\nvoid CConnman::Stop()\n{\n    LogPrint(BCLog::NET, \"CConnman::Stop\\n\");\n\n    if (threadMessageHandler.joinable())\n        threadMessageHandler.join();\n    if (threadOpenConnections.joinable())\n        threadOpenConnections.join();\n    if (threadOpenAddedConnections.joinable())\n        threadOpenAddedConnections.join();\n    if (threadDNSAddressSeed.joinable())\n        threadDNSAddressSeed.join();\n    if (threadSocketHandler.joinable())\n        threadSocketHandler.join();\n\n    if (fAddressesInitialized)\n    {\n        DumpData();\n        fAddressesInitialized = false;\n    }\n\n    LogPrint(BCLog::NET, \"closing all sockets\\n\");\n    for (CNode* pnode : vNodes) {\n        pnode->CloseSocketDisconnect();\n    }\n    for(CNode *pnode : vNodes) {\n        DeleteNode(pnode);\n    }\n    vNodes.clear();\n    for(CNode *pnode : vNodesDisconnected) {\n        DeleteNode(pnode);\n    }\n    vNodesDisconnected.clear();\n\n    for (ListenSocket& ls : vhListenSocket) {\n        try {\n            ls.acceptor.close();\n        }\n        catch (const boost::system::system_error& ec) {\n            LogPrint(BCLog::NET, \"close listening socket: %s\\n\", ec.what());\n        }\n    }\n    vhListenSocket.clear();\n\n    // clean up some globals (to help leak detection)\n    delete semOutbound;\n    semOutbound = NULL;\n    delete semAddnode;\n    semAddnode = NULL;\n\n    hasBeenStopped = true;\n}\n\nvoid CConnman::DeleteNode(CNode* pnode)\n{\n    assert(pnode);\n    bool fUpdateConnectionTime = false;\n    GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime);\n    if(fUpdateConnectionTime)\n        addrman.Connected(pnode->addr);\n    delete pnode;\n}\n\nCConnman::~CConnman()\n{\n    assert(hasBeenStopped);\n}\n\nsize_t CConnman::GetAddressCount() const\n{\n    return addrman.size();\n}\n\nvoid CConnman::SetServices(const CService &addr, ServiceFlags nServices)\n{\n    addrman.SetServices(addr, nServices);\n}\n\nvoid CConnman::MarkAddressGood(const CAddress& addr)\n{\n    addrman.Good(addr);\n}\n\nvoid CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)\n{\n    addrman.Add(vAddr, addrFrom, nTimePenalty);\n}\n\nstd::vector<CAddress> CConnman::GetAddresses()\n{\n    return addrman.GetAddr();\n}\n\nbool CConnman::AddNode(const std::string& strNode)\n{\n    LOCK(cs_vAddedNodes);\n    for(std::vector<std::string>::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {\n        if (strNode == *it)\n            return false;\n    }\n\n    vAddedNodes.push_back(strNode);\n    return true;\n}\n\nbool CConnman::RemoveAddedNode(const std::string& strNode)\n{\n    LOCK(cs_vAddedNodes);\n    for(std::vector<std::string>::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {\n        if (strNode == *it) {\n            vAddedNodes.erase(it);\n            return true;\n        }\n    }\n    return false;\n}\n\nsize_t CConnman::GetNodeCount(NumConnections flags)\n{\n    LOCK(cs_vNodes);\n    if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total\n        return vNodes.size();\n\n    int nNum = 0;\n    for(std::vector<CNode*>::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it)\n        if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))\n            nNum++;\n\n    return nNum;\n}\n\nvoid CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)\n{\n    vstats.clear();\n    LOCK(cs_vNodes);\n    vstats.reserve(vNodes.size());\n    for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) {\n        CNode* pnode = *it;\n        vstats.emplace_back();\n        pnode->copyStats(vstats.back());\n    }\n}\n\nbool CConnman::DisconnectNode(const std::string& strNode)\n{\n    LOCK(cs_vNodes);\n    if (CNode* pnode = FindNode(strNode)) {\n        pnode->fDisconnect = true;\n        return true;\n    }\n    return false;\n}\nbool CConnman::DisconnectNode(NodeId id)\n{\n    LOCK(cs_vNodes);\n    for(CNode* pnode : vNodes) {\n        if (id == pnode->GetId()) {\n            pnode->fDisconnect = true;\n            return true;\n        }\n    }\n    return false;\n}\n\nvoid CConnman::RecordBytesRecv(uint64_t bytes)\n{\n    LOCK(cs_totalBytesRecv);\n    nTotalBytesRecv += bytes;\n}\n\nvoid CConnman::RecordBytesSent(uint64_t bytes)\n{\n    LOCK(cs_totalBytesSent);\n    nTotalBytesSent += bytes;\n\n    uint64_t now = GetTime();\n    if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now)\n    {\n        // timeframe expired, reset cycle\n        nMaxOutboundCycleStartTime = now;\n        nMaxOutboundTotalBytesSentInCycle = 0;\n    }\n\n    // TODO, exclude whitebind peers\n    nMaxOutboundTotalBytesSentInCycle += bytes;\n}\n\nvoid CConnman::SetMaxOutboundTarget(uint64_t limit)\n{\n    LOCK(cs_totalBytesSent);\n    nMaxOutboundLimit = limit;\n}\n\nuint64_t CConnman::GetMaxOutboundTarget()\n{\n    LOCK(cs_totalBytesSent);\n    return nMaxOutboundLimit;\n}\n\nuint64_t CConnman::GetMaxOutboundTimeframe()\n{\n    LOCK(cs_totalBytesSent);\n    return nMaxOutboundTimeframe;\n}\n\nuint64_t CConnman::GetMaxOutboundTimeLeftInCycle()\n{\n    LOCK(cs_totalBytesSent);\n    if (nMaxOutboundLimit == 0)\n        return 0;\n\n    if (nMaxOutboundCycleStartTime == 0)\n        return nMaxOutboundTimeframe;\n\n    uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe;\n    uint64_t now = GetTime();\n    return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime();\n}\n\nvoid CConnman::SetMaxOutboundTimeframe(uint64_t timeframe)\n{\n    LOCK(cs_totalBytesSent);\n    if (nMaxOutboundTimeframe != timeframe)\n    {\n        // reset measure-cycle in case of changing\n        // the timeframe\n        nMaxOutboundCycleStartTime = GetTime();\n    }\n    nMaxOutboundTimeframe = timeframe;\n}\n\nbool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)\n{\n    LOCK(cs_totalBytesSent);\n    if (nMaxOutboundLimit == 0)\n        return false;\n\n    if (historicalBlockServingLimit)\n    {\n        // keep a large enough buffer to at least relay each block once\n        uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();\n        uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_SIZE;\n        if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)\n            return true;\n    }\n    else if (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit)\n        return true;\n\n    return false;\n}\n\nuint64_t CConnman::GetOutboundTargetBytesLeft()\n{\n    LOCK(cs_totalBytesSent);\n    if (nMaxOutboundLimit == 0)\n        return 0;\n\n    return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;\n}\n\nuint64_t CConnman::GetTotalBytesRecv()\n{\n    LOCK(cs_totalBytesRecv);\n    return nTotalBytesRecv;\n}\n\nuint64_t CConnman::GetTotalBytesSent()\n{\n    LOCK(cs_totalBytesSent);\n    return nTotalBytesSent;\n}\n\nServiceFlags CConnman::GetLocalServices() const\n{\n    return nLocalServices;\n}\n\nvoid CConnman::SetBestHeight(int height)\n{\n    nBestHeight.store(height, std::memory_order_release);\n}\n\nint CConnman::GetBestHeight() const\n{\n    return nBestHeight.load(std::memory_order_acquire);\n}\n\nunsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }\nunsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }\n\nCNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, socket_t hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) :\n    hSocket(std::move(hSocketIn)),\n    nTimeConnected(GetTimeSeconds()),\n    addr(addrIn),\n    addrBind(addrBindIn),\n    fInbound(fInboundIn),\n    nKeyedNetGroup(nKeyedNetGroupIn),\n    addrKnown(5000, 0.001),\n    filterInventoryKnown(50000, 0.000001),\n    id(idIn),\n    nLocalHostNonce(nLocalHostNonceIn),\n    nLocalServices(nLocalServicesIn),\n    nMyStartingHeight(nMyStartingHeightIn),\n    nSendVersion(0),\n    inactivityTimer(get_io_context())\n{\n    nServices = NODE_NONE;\n    nServicesExpected = NODE_NONE;\n    nRecvVersion = INIT_PROTO_VERSION;\n    nLastSend = 0;\n    nLastRecv = 0;\n    nSendBytes = 0;\n    fResumeSendActive = false;\n    nRecvBytes = 0;\n    nTimeOffset = 0;\n    addrName = addrNameIn == \"\" ? addr.ToStringIPPort() : addrNameIn;\n    nVersion = 0;\n    strSubVer = \"\";\n    fWhitelisted = false;\n    fOneShot = false;\n    fAddnode = false;\n    fClient = false; // set by version message\n    fFeeler = false;\n    fSuccessfullyConnected = false;\n    fDisconnect = false;\n    nRefCount = 0;\n    nSendSize = 0;\n    hashContinue = uint256();\n    nStartingHeight = -1;\n    filterInventoryKnown.reset();\n    fSendMempool = false;\n    fGetAddr = false;\n    nNextLocalAddrSend = 0;\n    nNextAddrSend = 0;\n    nNextInvSend = 0;\n    fRelayTxes = false;\n    fSentAddr = false;\n    timeLastMempoolReq = 0;\n    nLastBlockTime = 0;\n    nLastTXTime = 0;\n    nPingNonceSent = 0;\n    nPingUsecStart = 0;\n    nPingUsecTime = 0;\n    fPingQueued = false;\n    hashCheckpointKnown = uint256();\n    nMinPingUsecTime = std::numeric_limits<int64_t>::max();\n    minFeeFilter = 0;\n    lastSentFeeFilter = 0;\n    nextSendTimeFeeFilter = 0;\n    fPauseRecv = false;\n    fPauseSend = false;\n    nProcessQueueSize = 0;\n\n    for(const std::string &msg : getAllNetMessageTypes())\n        mapRecvBytesPerMsgCmd[msg] = 0;\n    mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;\n\n    if (fLogIPs) {\n        LogPrint(BCLog::NET, \"Added connection to %s peer=%d\\n\", addrName, id);\n    } else {\n        LogPrint(BCLog::NET, \"Added connection peer=%d\\n\", id);\n    }\n}\n\nCNode::~CNode()\n{\n}\n\nvoid CNode::AskFor(const CInv& inv)\n{\n    if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ)\n        return;\n    // a peer may not have multiple non-responded queue positions for a single inv item\n    if (!setAskFor.insert(inv.hash).second)\n        return;\n\n    // We're using mapAskFor as a priority queue,\n    // the key is the earliest time the request can be sent\n    int64_t nRequestTime;\n    limitedmap<uint256, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv.hash);\n    if (it != mapAlreadyAskedFor.end())\n        nRequestTime = it->second;\n    else\n        nRequestTime = 0;\n    LogPrint(BCLog::NET, \"askfor %s  %d (%s) peer=%d\\n\", inv.ToString(), nRequestTime, FormatISO8601DateTime(nRequestTime/1000000), id);\n\n    // Make sure not to reuse time indexes to keep things in the same order\n    int64_t nNow = GetTimeMicros() - 1000000;\n    static int64_t nLastTime;\n    ++nLastTime;\n    nNow = std::max(nNow, nLastTime);\n    nLastTime = nNow;\n\n    // Each retry is 2 minutes after the last\n    nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);\n    if (it != mapAlreadyAskedFor.end())\n        mapAlreadyAskedFor.update(it, nRequestTime);\n    else\n        mapAlreadyAskedFor.insert(std::pair(inv.hash, nRequestTime));\n    mapAskFor.insert(std::pair(nRequestTime, inv));\n}\n\nbool CConnman::NodeFullyConnected(const CNode* pnode)\n{\n    return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;\n}\n\nvoid CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)\n{\n    size_t nMessageSize = msg.data.size();\n    size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE;\n    LogPrint(BCLog::NET, \"sending %s (%d bytes) peer=%d\\n\",  SanitizeString(msg.command.c_str()), nMessageSize, pnode->GetId());\n\n    std::vector<unsigned char> serializedHeader;\n    serializedHeader.reserve(CMessageHeader::HEADER_SIZE);\n    uint256 hash = Hash(msg.data.data(), msg.data.data() + nMessageSize);\n    CMessageHeader hdr(Params().MessageStart(), msg.command.c_str(), nMessageSize);\n    memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);\n\n    CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr};\n\n    {\n        LOCK(pnode->cs_vSend);\n\n        //log total amount of bytes per command\n        pnode->mapSendBytesPerMsgCmd[msg.command] += nTotalSize;\n        pnode->nSendSize += nTotalSize;\n\n        if (pnode->nSendSize > nSendBufferMaxSize)\n            pnode->fPauseSend = true;\n        pnode->vSendMsg.push_back(std::move(serializedHeader));\n        if (nMessageSize)\n            pnode->vSendMsg.push_back(std::move(msg.data));\n\n        if (!pnode->fResumeSendActive) {\n            pnode->fResumeSendActive = true;\n            pnode->AddRef();\n            boost::asio::post(get_io_context(), [this, pnode]() {\n                this->ResumeSend(pnode);\n                pnode->Release();\n            });\n        }\n    }\n}\n\nvoid CConnman::ResumeSend(CNode *pnode)\n{\n    LOCK(pnode->cs_vSend);\n\n    if (pnode->vSendMsg.empty()) {\n        pnode->fResumeSendActive = false;\n        return;\n    }\n\n    // buffer to hold and own the message data, Asio buffers don't take ownership\n    using BufferHolder = std::shared_ptr<std::vector<unsigned char> >;\n    auto bufferHolder = BufferHolder(new std::vector<unsigned char>(std::move(pnode->vSendMsg.front())));\n    pnode->vSendMsg.pop_front();\n    boost::asio::const_buffer buffer = boost::asio::buffer(reinterpret_cast<const char*>(bufferHolder->data()), bufferHolder->size());\n\n    pnode->AddRef();\n    boost::asio::async_write(pnode->hSocket, buffer,\n                             [this, pnode, bufferHolder](const boost::system::error_code& ec, std::size_t bytes_transferred) {\n        if (ec) {\n            LogPrint(BCLog::NET, \"socket send error %s\\n\", ec.message());\n            pnode->fDisconnect = true;\n            pnode->Release();\n            return;\n        }\n\n        RecordBytesSent(bytes_transferred);\n\n        LOCK(pnode->cs_vSend);\n\n        pnode->nLastSend = GetTimeSeconds();\n        pnode->nSendBytes += bytes_transferred;\n\n        pnode->nSendSize -= bytes_transferred;\n        pnode->fPauseSend = pnode->nSendSize > nSendBufferMaxSize;\n\n        this->ResumeSend(pnode);\n        pnode->Release();\n    });\n}\n\nbool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)\n{\n    CNode* found = nullptr;\n    LOCK(cs_vNodes);\n    for (auto&& pnode : vNodes) {\n        if(pnode->GetId() == id) {\n            found = pnode;\n            break;\n        }\n    }\n    return found != nullptr && NodeFullyConnected(found) && func(found);\n}\n\nint64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {\n    return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);\n}\n\nCSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const\n{\n    return CSipHasher(nSeed0, nSeed1).Write(id);\n}\n\nuint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const\n{\n    std::vector<unsigned char> vchNetGroup(ad.GetGroup());\n\n    return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();\n}\n"
  },
  {
    "path": "src/net.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_NET_H\n#define CORE_NET_H\n\n#include \"addrdb.h\"\n#include \"addrman.h\"\n#include \"amount.h\"\n#include \"bloom.h\"\n#include \"compat.h\"\n#include \"hash.h\"\n#include \"limitedmap.h\"\n#include \"netaddress.h\"\n#include \"policy/feerate.h\"\n#include \"protocol.h\"\n#include \"random.h\"\n#include \"streams.h\"\n#include \"sync.h\"\n#include \"uint256.h\"\n#include \"threadinterrupt.h\"\n#include \"netbase.h\"\n\n#include \"unity/signals.h\"\n\n#include <atomic>\n#include <deque>\n#include <stdint.h>\n#include <thread>\n#include <memory>\n#include <condition_variable>\n\n#ifndef WIN32\n#include <arpa/inet.h>\n#endif\n\n#include <boost/signals2/signal.hpp>\n\nclass CScheduler;\nclass CNode;\n\nnamespace boost {\n    class thread_group;\n} // namespace boost\n\n/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */\nstatic const int PING_INTERVAL = 2 * 60;\n/** Time after which to disconnect, after waiting for a ping response (or inactivity). */\nstatic const int TIMEOUT_INTERVAL = 20 * 60;\n/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/\nstatic const int FEELER_INTERVAL = 120;\n/** The maximum number of entries in an 'inv' protocol message */\nstatic const unsigned int MAX_INV_SZ = 50000;\n/** The maximum number of mempool entries in the 'inv' message send to new connecting peer */\nstatic const unsigned int MAX_SEND_INIT_MEMPOOL = 20;\n/** The maximum number of new addresses to accumulate before announcing. */\nstatic const unsigned int MAX_ADDR_TO_SEND = 1000;\n/** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */\nstatic const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;\n/** Maximum length of strSubVer in `version` message */\nstatic const unsigned int MAX_SUBVERSION_LENGTH = 256;\n/** Maximum number of automatic outgoing nodes */\nstatic const int MAX_OUTBOUND_CONNECTIONS = 8;\n/** Maximum number of addnode outgoing nodes */\nstatic const int MAX_ADDNODE_CONNECTIONS = 8;\n/** -listen default */\nstatic const bool DEFAULT_LISTEN = true;\n/** -upnp default */\n#ifdef USE_UPNP\nstatic const bool DEFAULT_UPNP = USE_UPNP;\n#else\nstatic const bool DEFAULT_UPNP = false;\n#endif\n/** The maximum number of entries in mapAskFor */\nstatic const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;\n/** The maximum number of entries in setAskFor (larger due to getdata latency)*/\nstatic const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;\n/** The maximum number of peer connections to maintain. */\nstatic const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;\n/** The default for -maxuploadtarget. 0 = Unlimited */\nstatic const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;\n/** The default timeframe for -maxuploadtarget. 1 day. */\nstatic const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24;\n/** Default for blocks only*/\nstatic const bool DEFAULT_BLOCKSONLY = false;\n\nstatic const bool DEFAULT_FORCEDNSSEED = false;\nstatic const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;\nstatic const size_t DEFAULT_MAXSENDBUFFER    = 1 * 1000;\nstatic const size_t DEFAULT_MAXRECEIVEBUFFER_LOWMEM = 1 * 1000;\n\nstatic const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;\n\n// NOTE: When adjusting this, update rpcnet:setban's help (\"24h\")\nstatic const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24;  // Default 24-hour ban\n\ntypedef int64_t NodeId;\n\nstruct AddedNodeInfo\n{\n    std::string strAddedNode;\n    CService resolvedAddress;\n    bool fConnected;\n    bool fInbound;\n};\n\nclass CTransaction;\nclass CNodeStats;\nclass CClientUIInterface;\n\nstruct CSerializedNetMsg\n{\n    CSerializedNetMsg() = default;\n    CSerializedNetMsg(CSerializedNetMsg&&) = default;\n    CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;\n    // No copying, only moves.\n    CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;\n    CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;\n\n    std::vector<unsigned char> data;\n    std::string command;\n};\n\n\nclass CConnman\n{\npublic:\n\n    enum NumConnections {\n        CONNECTIONS_NONE = 0,\n        CONNECTIONS_IN = (1U << 0),\n        CONNECTIONS_OUT = (1U << 1),\n        CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),\n    };\n\n    struct Options\n    {\n        ServiceFlags nLocalServices = NODE_NONE;\n        ServiceFlags nRelevantServices = NODE_NONE;\n        int nMaxConnections = 0;\n        int nMaxOutbound = 0;\n        int nMaxAddnode = 0;\n        int nMaxFeeler = 0;\n        int nBestHeight = 0;\n        CClientUIInterface* uiInterface = nullptr;\n        unsigned int nSendBufferMaxSize = 0;\n        unsigned int nReceiveFloodSize = 0;\n        uint64_t nMaxOutboundTimeframe = 0;\n        uint64_t nMaxOutboundLimit = 0;\n        std::vector<std::string> vSeedNodes;\n    };\n    CConnman(uint64_t seed0, uint64_t seed1);\n    ~CConnman();\n    bool Start(CScheduler& scheduler, std::string& strNodeError, Options options);\n    void Stop();\n    void Interrupt();\n    bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);\n    bool GetNetworkActive() const { return fNetworkActive; };\n    void SetNetworkActive(bool active);\n    bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);\n    bool CheckIncomingNonce(uint64_t nonce);\n\n    bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);\n\n    void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);\n\n    template<typename Callable>\n    void ForEachNode(Callable&& func)\n    {\n        LOCK(cs_vNodes);\n        for (auto&& node : vNodes) {\n            if (NodeFullyConnected(node))\n                func(node);\n        }\n    };\n\n    template<typename Callable>\n    void ForEachNode(Callable&& func) const\n    {\n        LOCK(cs_vNodes);\n        for (auto&& node : vNodes) {\n            if (NodeFullyConnected(node))\n                func(node);\n        }\n    };\n\n    template<typename Callable, typename CallableAfter>\n    void ForEachNodeThen(Callable&& pre, CallableAfter&& post)\n    {\n        LOCK(cs_vNodes);\n        for (auto&& node : vNodes) {\n            if (NodeFullyConnected(node))\n                pre(node);\n        }\n        post();\n    };\n\n    template<typename Callable, typename CallableAfter>\n    void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const\n    {\n        LOCK(cs_vNodes);\n        for (auto&& node : vNodes) {\n            if (NodeFullyConnected(node))\n                pre(node);\n        }\n        post();\n    };\n\n    // Addrman functions\n    size_t GetAddressCount() const;\n    void SetServices(const CService &addr, ServiceFlags nServices);\n    void MarkAddressGood(const CAddress& addr);\n    void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);\n    std::vector<CAddress> GetAddresses();\n\n    // Denial-of-service detection/prevention\n    // The idea is to detect peers that are behaving\n    // badly and disconnect/ban them, but do it in a\n    // one-coding-mistake-won't-shatter-the-entire-network\n    // way.\n    // IMPORTANT:  There should be nothing I can give a\n    // node that it will forward on that will make that\n    // node's peers drop it. If there is, an attacker\n    // can isolate a node and/or try to split the network.\n    // Dropping a node for sending stuff that is invalid\n    // now but might be valid in a later version is also\n    // dangerous, because it can cause a network split\n    // between nodes running old code and nodes running\n    // new code.\n    void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);\n    void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);\n    void ClearBanned();\n    bool IsBanned(CNetAddr ip);\n    bool IsBanned(CSubNet subnet);\n    bool Unban(const CNetAddr &ip);\n    bool Unban(const CSubNet &ip);\n    void GetBanned(banmap_t &banmap);\n    void SetBanned(const banmap_t &banmap);\n\n    bool AddNode(const std::string& node);\n    bool RemoveAddedNode(const std::string& node);\n    std::vector<AddedNodeInfo> GetAddedNodeInfo();\n\n    size_t GetNodeCount(NumConnections num);\n    void GetNodeStats(std::vector<CNodeStats>& vstats);\n    bool DisconnectNode(const std::string& node);\n    bool DisconnectNode(NodeId id);\n\n    unsigned int GetSendBufferSize() const;\n\n    void AddWhitelistedRange(const CSubNet &subnet);\n\n    ServiceFlags GetLocalServices() const;\n\n    //!set the max outbound target in bytes\n    void SetMaxOutboundTarget(uint64_t limit);\n    uint64_t GetMaxOutboundTarget();\n\n    //!set the timeframe for the max outbound target\n    void SetMaxOutboundTimeframe(uint64_t timeframe);\n    uint64_t GetMaxOutboundTimeframe();\n\n    //!check if the outbound target is reached\n    // if param historicalBlockServingLimit is set true, the function will\n    // response true if the limit for serving historical blocks has been reached\n    bool OutboundTargetReached(bool historicalBlockServingLimit);\n\n    //!response the bytes left in the current max outbound cycle\n    // in case of no limit, it will always response 0\n    uint64_t GetOutboundTargetBytesLeft();\n\n    //!response the time in second left in the current max outbound cycle\n    // in case of no limit, it will always response 0\n    uint64_t GetMaxOutboundTimeLeftInCycle();\n\n    uint64_t GetTotalBytesRecv();\n    uint64_t GetTotalBytesSent();\n\n    void SetBestHeight(int height);\n    int GetBestHeight() const;\n\n    /** Get a unique deterministic randomizer. */\n    CSipHasher GetDeterministicRandomizer(uint64_t id) const;\n\n    unsigned int GetReceiveFloodSize() const;\n\n    void WakeMessageHandler();\n\n    void ResumeReceive(CNode* pnode);\n    void NodeInactivityChecker(CNode* pnode);\n\nprivate:\n    struct ListenSocket {\n        boost::asio::ip::tcp::acceptor acceptor;\n        bool whitelisted;\n        boost::asio::ip::tcp::endpoint peerEndpoint;\n        boost::asio::ip::tcp::socket peer;\n\n        ListenSocket(boost::asio::ip::tcp::acceptor acceptor_, bool whitelisted_) :\n            acceptor(std::move(acceptor_)), whitelisted(whitelisted_),\n            peer(get_io_context())\n        {}\n    };\n    void AcceptIncoming(ListenSocket& listener);\n\n    void ThreadOpenAddedConnections();\n    void AddOneShot(const std::string& strDest);\n    void ProcessOneShot();\n    void NodeDisconnectAndDeleter();\n    void NumConnectionsNotifier();\n    void ThreadOpenConnections();\n    void ThreadMessageHandler();\n    void AcceptConnection(const ListenSocket& hListenSocket);\n    void ThreadSocketHandler();\n    void ThreadDNSAddressSeed();\n\n    uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;\n\n    CNode* FindNode(const CNetAddr& ip);\n    CNode* FindNode(const CSubNet& subNet);\n    CNode* FindNode(const std::string& addrName);\n    CNode* FindNode(const CService& addr);\n\n    bool AttemptToEvictConnection();\n    CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure);\n    bool IsWhitelistedRange(const CNetAddr &addr);\n\n    void DeleteNode(CNode* pnode);\n\n    NodeId GetNewNodeId();\n\n    void ResumeSend(CNode *pnode);\n    //!check is the banlist has unwritten changes\n    bool BannedSetIsDirty();\n    //!set the \"dirty\" flag for the banlist\n    void SetBannedSetDirty(bool dirty=true);\n    //!clean unused entries (if bantime has expired)\n    void SweepBanned();\n    void DumpAddresses();\n    void DumpData();\n    void DumpBanlist();\n\n    // Network stats\n    void RecordBytesRecv(uint64_t bytes);\n    void RecordBytesSent(uint64_t bytes);\n\n    // Whether the node should be passed out in ForEach* callbacks\n    static bool NodeFullyConnected(const CNode* pnode);\n\n    // Network usage totals\n    RecursiveMutex cs_totalBytesRecv;\n    RecursiveMutex cs_totalBytesSent;\n    uint64_t nTotalBytesRecv;\n    uint64_t nTotalBytesSent;\n\n    // outbound limit & stats\n    uint64_t nMaxOutboundTotalBytesSentInCycle;\n    uint64_t nMaxOutboundCycleStartTime;\n    uint64_t nMaxOutboundLimit;\n    uint64_t nMaxOutboundTimeframe;\n\n    // Whitelisted ranges. Any node connecting from these is automatically\n    // whitelisted (as well as those connecting to whitelisted binds).\n    std::vector<CSubNet> vWhitelistedRange;\n    RecursiveMutex cs_vWhitelistedRange;\n\n    unsigned int nSendBufferMaxSize;\n    unsigned int nReceiveFloodSize;\n\n    std::list<ListenSocket> vhListenSocket;\n    std::atomic<bool> fNetworkActive;\n    banmap_t setBanned;\n    RecursiveMutex cs_setBanned;\n    bool setBannedIsDirty;\n    bool fAddressesInitialized;\n    CAddrMan addrman;\n    std::deque<std::string> vOneShots;\n    RecursiveMutex cs_vOneShots;\n    std::vector<std::string> vAddedNodes;\n    RecursiveMutex cs_vAddedNodes;\n    std::vector<CNode*> vNodes;\n    std::list<CNode*> vNodesDisconnected;\n    mutable RecursiveMutex cs_vNodes;\n    std::atomic<NodeId> nLastNodeId;\n\n    /** Services this instance offers */\n    ServiceFlags nLocalServices;\n\n    /** Services this instance cares about */\n    ServiceFlags nRelevantServices;\n\n    CSemaphore *semOutbound;\n    CSemaphore *semAddnode;\n    int nMaxConnections;\n    int nMaxOutbound;\n    int nMaxAddnode;\n    int nMaxFeeler;\n    std::atomic<int> nBestHeight;\n    CClientUIInterface* clientInterface;\n\n    /** SipHasher seeds for deterministic randomness */\n    const uint64_t nSeed0, nSeed1;\n\n    /** flag for waking the message processor. */\n    bool fMsgProcWake;\n\n    /** flag to check that Stop has been called on us */\n    bool hasBeenStopped = false;\n\n    std::condition_variable condMsgProc;\n    std::mutex mutexMsgProc;\n    std::atomic<bool> flagInterruptMsgProc;\n\n    CThreadInterrupt interruptNet;\n\n    std::thread threadDNSAddressSeed;\n    std::thread threadSocketHandler;\n    std::thread threadOpenAddedConnections;\n    std::thread threadOpenConnections;\n    std::thread threadMessageHandler;\n\n    boost::asio::deadline_timer disconnectAndDeleterTimer;\n    boost::asio::deadline_timer connectionsNotifierTimer;\n};\nextern std::unique_ptr<CConnman> g_connman;\nvoid Discover();\nvoid MapPort(bool fUseUPnP);\nunsigned short GetListenPort();\nbool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);\n\n// Signals for message handling\nstruct CNodeSignals\n{\n    boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), BooleanAndAllReturnValues> ProcessMessages;\n    boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), BooleanAndAllReturnValues> SendMessages;\n    boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode;\n    boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;\n};\n\n\nCNodeSignals& GetNodeSignals();\n\n\nenum\n{\n    LOCAL_NONE,   // unknown\n    LOCAL_IF,     // address a local interface listens on\n    LOCAL_BIND,   // address explicit bound to\n    LOCAL_UPNP,   // address reported by UPnP\n    LOCAL_MANUAL, // address explicitly specified (-externalip=)\n\n    LOCAL_MAX\n};\n\nbool IsPeerAddrLocalGood(CNode *pnode);\nvoid AdvertiseLocal(CNode *pnode);\nvoid SetLimited(enum Network net, bool fLimited = true);\nbool IsLimited(enum Network net);\nbool IsLimited(const CNetAddr& addr);\nbool AddLocal(const CService& addr, int nScore = LOCAL_NONE);\nbool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);\nbool RemoveLocal(const CService& addr);\nbool SeenLocal(const CService& addr);\nbool IsLocal(const CService& addr);\nbool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);\nbool IsReachable(enum Network net);\nbool IsReachable(const CNetAddr &addr);\nCAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);\n\n\nextern bool fDiscover;\nextern bool fListen;\nextern bool fRelayTxes;\n\nextern limitedmap<uint256, int64_t> mapAlreadyAskedFor;\n\n/** Subversion as sent to the P2P network in `version` messages */\nextern std::string strSubVersion;\n\nstruct LocalServiceInfo {\n    int nScore;\n    int nPort;\n};\n\nextern RecursiveMutex cs_mapLocalHost;\nextern std::map<CNetAddr, LocalServiceInfo> mapLocalHost;\ntypedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes\n\nclass CNodeStats\n{\npublic:\n    NodeId nodeid;\n    ServiceFlags nServices;\n    bool fRelayTxes;\n    int64_t nLastSend;\n    int64_t nLastRecv;\n    int64_t nTimeConnected;\n    int64_t nTimeOffset;\n    std::string addrName;\n    int nVersion;\n    std::string cleanSubVer;\n    bool fInbound;\n    bool fAddnode;\n    int nStartingHeight;\n    uint64_t nSendBytes;\n    mapMsgCmdSize mapSendBytesPerMsgCmd;\n    uint64_t nRecvBytes;\n    mapMsgCmdSize mapRecvBytesPerMsgCmd;\n    bool fWhitelisted;\n    double dPingTime;\n    double dPingWait;\n    double dMinPing;\n    // Our address, as reported by the peer\n    std::string addrLocal;\n    // Address of this peer\n    CAddress addr;\n    // Bind address of our side of the connection\n    CAddress addrBind;\n};\n\n\n\n\nclass CNetMessage {\nprivate:\n    mutable CHash256 hasher;\n    mutable uint256 data_hash;\npublic:\n    bool in_data;                   // parsing header (false) or data (true)\n\n    CDataStream hdrbuf;             // partially received header\n    CMessageHeader hdr;             // complete header\n    unsigned int nHdrPos;\n\n    CDataStream vRecv;              // received message data\n    unsigned int nDataPos;\n\n    int64_t nTime;                  // time (in microseconds) of message receipt.\n\n    CNetMessage(const CMessageHeader::MessageStartChars& pchMessageStartIn, int nTypeIn, int nVersionIn) : hdrbuf(nTypeIn, nVersionIn), hdr(pchMessageStartIn), vRecv(nTypeIn, nVersionIn) {\n        hdrbuf.resize(24);\n        in_data = false;\n        nHdrPos = 0;\n        nDataPos = 0;\n        nTime = 0;\n    }\n\n    bool complete() const\n    {\n        if (!in_data)\n            return false;\n        return (hdr.nMessageSize == nDataPos);\n    }\n\n    const uint256& GetMessageHash() const;\n\n    void SetVersion(int nVersionIn)\n    {\n        hdrbuf.SetVersion(nVersionIn);\n        vRecv.SetVersion(nVersionIn);\n    }\n\n    int readHeader(const char *pch, unsigned int nBytes);\n    int readData(const char *pch, unsigned int nBytes);\n};\n\n\n/** Information about a peer */\nclass CNode\n{\n    friend class CConnman;\npublic:\n    // socket\n    std::atomic<ServiceFlags> nServices;\n    ServiceFlags nServicesExpected;\n    socket_t hSocket;\n    size_t nSendSize; // total size of all vSendMsg entries\n    uint64_t nSendBytes;\n    std::deque<std::vector<unsigned char>> vSendMsg;\n    RecursiveMutex cs_vSend;\n    bool fResumeSendActive;\n    RecursiveMutex cs_vRecv;\n\n    RecursiveMutex cs_vProcessMsg;\n    std::list<CNetMessage> vProcessMsg;\n    size_t nProcessQueueSize;\n\n    RecursiveMutex cs_sendProcessing;\n\n    std::deque<CInv> vRecvGetData;\n    uint64_t nRecvBytes;\n    std::atomic<int> nRecvVersion;\n\n    std::atomic<int64_t> nLastSend;\n    std::atomic<int64_t> nLastRecv;\n    const int64_t nTimeConnected;\n    std::atomic<int64_t> nTimeOffset;\n    // Address of this peer\n    const CAddress addr;\n    // Bind address of our side of the connection\n    const CAddress addrBind;\n    std::atomic<int> nVersion;\n    // strSubVer is whatever byte array we read from the wire. However, this field is intended\n    // to be printed out, displayed to humans in various forms and so on. So we sanitize it and\n    // store the sanitized version in cleanSubVer. The original should be used when dealing with\n    // the network or wire types and the cleaned string used when displayed or logged.\n    std::string strSubVer, cleanSubVer;\n    RecursiveMutex cs_SubVer; // used for both cleanSubVer and strSubVer\n    bool fWhitelisted; // This peer can bypass DoS banning.\n    bool fFeeler; // If true this node is being used as a short lived feeler.\n    bool fOneShot;\n    bool fAddnode;\n    bool fClient;\n    const bool fInbound;\n    std::atomic_bool fSuccessfullyConnected;\n    std::atomic_bool fDisconnect;\n    // We use fRelayTxes to avoid relaying tx invs before receiving the peer's version message\n    // The peer may tell us in its version message that we should not relay tx invs\n    bool fRelayTxes;\n    bool fSentAddr;\n    CSemaphoreGrant grantOutbound;\n    std::atomic<int> nRefCount;\n\n    const uint64_t nKeyedNetGroup;\n    std::atomic_bool fPauseRecv;\n    std::atomic_bool fPauseSend;\nprotected:\n\n    mapMsgCmdSize mapSendBytesPerMsgCmd;\n    mapMsgCmdSize mapRecvBytesPerMsgCmd;\n\npublic:\n    uint256 hashContinue;\n    std::atomic<int> nStartingHeight;\n\n    // flood relay\n    std::vector<CAddress> vAddrToSend;\n    CRollingBloomFilter addrKnown;\n    bool fGetAddr;\n    std::set<uint256> setKnown;\n    uint256 hashCheckpointKnown;\n    uint256 hashInvalidateKnown;\n    int64_t nNextAddrSend;\n    int64_t nNextLocalAddrSend;\n\n    // inventory based relay\n    CRollingBloomFilter filterInventoryKnown;\n    // Set of transaction ids we still have to announce.\n    // They are sorted by the mempool before relay, so the order is not important.\n    std::set<uint256> setInventoryTxToSend;\n    // List of block ids we still have announce.\n    // There is no final sorting before sending, as they are always sent immediately\n    // and in the order requested.\n    std::vector<uint256> vInventoryBlockToSend;\n    RecursiveMutex cs_inventory;\n    std::set<uint256> setAskFor;\n    std::multimap<int64_t, CInv> mapAskFor;\n    int64_t nNextInvSend;\n    // Used for headers announcements - unfiltered blocks to relay\n    // Also protected by cs_inventory\n    std::vector<uint256> vBlockHashesToAnnounce;\n    // Used for BIP35 mempool sending, also protected by cs_inventory\n    bool fSendMempool;\n\n    // Last time a \"MEMPOOL\" request was serviced.\n    std::atomic<int64_t> timeLastMempoolReq;\n\n    // Block and TXN accept times\n    std::atomic<int64_t> nLastBlockTime;\n    std::atomic<int64_t> nLastTXTime;\n\n    // Ping time measurement:\n    // The pong reply we're expecting, or 0 if no pong expected.\n    std::atomic<uint64_t> nPingNonceSent;\n    // Time (in usec) the last ping was sent, or 0 if no ping was ever sent.\n    std::atomic<int64_t> nPingUsecStart;\n    // Last measured round-trip time.\n    std::atomic<int64_t> nPingUsecTime;\n    // Best measured round-trip time.\n    std::atomic<int64_t> nMinPingUsecTime;\n    // Whether a ping is requested.\n    std::atomic<bool> fPingQueued;\n    // Minimum fee rate with which to filter inv's to this node\n    CAmount minFeeFilter;\n    RecursiveMutex cs_feeFilter;\n    CAmount lastSentFeeFilter;\n    int64_t nextSendTimeFeeFilter;\n\n    CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, socket_t hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = \"\", bool fInboundIn = false);\n    ~CNode();\n\nprivate:\n    CNode(const CNode&);\n    void operator=(const CNode&);\n    const NodeId id;\n\n\n    const uint64_t nLocalHostNonce;\n    // Services offered to this peer\n    const ServiceFlags nLocalServices;\n    const int nMyStartingHeight;\n    int nSendVersion;\n    std::list<CNetMessage> vRecvMsg;  // Used only by SocketHandler thread\n\n    mutable RecursiveMutex cs_addrName;\n    std::string addrName;\n\n    // Our address, as reported by the peer\n    CService addrLocal;\n    mutable RecursiveMutex cs_addrLocal;\n\n    bool fSendInProgress;\n\n    // typical socket buffer is 8K-64K\n    char pchBuf[0x10000];\n\n    boost::asio::deadline_timer inactivityTimer;\n\npublic:\n\n    NodeId GetId() const {\n        return id;\n    }\n\n    uint64_t GetLocalNonce() const {\n        return nLocalHostNonce;\n    }\n\n    int GetMyStartingHeight() const {\n        return nMyStartingHeight;\n    }\n\n    int GetRefCount() const\n    {\n        assert(nRefCount >= 0);\n        return nRefCount;\n    }\n\n    bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);\n\n    void SetRecvVersion(int nVersionIn)\n    {\n        nRecvVersion = nVersionIn;\n    }\n    int GetRecvVersion() const\n    {\n        return nRecvVersion;\n    }\n    void SetSendVersion(int nVersionIn);\n    int GetSendVersion() const;\n\n    CService GetAddrLocal() const;\n    //! May not be called more than once\n    void SetAddrLocal(const CService& addrLocalIn);\n\n    CNode* AddRef()\n    {\n        nRefCount++;\n        return this;\n    }\n\n    void Release()\n    {\n        nRefCount--;\n    }\n\n\n\n    void AddAddressKnown(const CAddress& _addr)\n    {\n        addrKnown.insert(_addr.GetKey());\n    }\n\n    void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)\n    {\n        // Known checking here is only to save space from duplicates.\n        // SendMessages will filter it again for knowns that were added\n        // after addresses were pushed.\n        if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {\n            if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {\n                vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;\n            } else {\n                vAddrToSend.push_back(_addr);\n            }\n        }\n    }\n\n\n    void AddInventoryKnown(const CInv& inv)\n    {\n        {\n            LOCK(cs_inventory);\n            filterInventoryKnown.insert(inv.hash);\n        }\n    }\n\n    void PushInventory(const CInv& inv)\n    {\n        LOCK(cs_inventory);\n        if (inv.type == MSG_TX) {\n            if (!filterInventoryKnown.contains(inv.hash)) {\n                setInventoryTxToSend.insert(inv.hash);\n            }\n        } else if (inv.type == MSG_BLOCK) {\n            vInventoryBlockToSend.push_back(inv.hash);\n        }\n    }\n\n    void PushBlockHash(const uint256 &hash)\n    {\n        LOCK(cs_inventory);\n        vBlockHashesToAnnounce.push_back(hash);\n    }\n\n    void AskFor(const CInv& inv);\n\n    void CloseSocketDisconnect();\n\n    void copyStats(CNodeStats &stats);\n\n    ServiceFlags GetLocalServices() const\n    {\n        return nLocalServices;\n    }\n\n    std::string GetAddrName() const;\n    //! Sets the addrName only if it was not previously set\n    void MaybeSetAddrName(const std::string& addrNameIn);\n};\n\n\n\n\n\n/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */\nint64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);\n\n#endif\n"
  },
  {
    "path": "src/net_processing.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"net_processing.h\"\n\n#include \"addrman.h\"\n#include \"arith_uint256.h\"\n#include \"blockencodings.h\"\n#include \"chainparams.h\"\n#include \"consensus/validation.h\"\n#include \"hash.h\"\n#include \"init.h\"\n#include \"validation/validation.h\"\n#include \"merkleblock.h\"\n#include \"net.h\"\n#include \"netmessagemaker.h\"\n#include \"netbase.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"random.h\"\n#include \"tinyformat.h\"\n#include \"txmempool.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"witnessutil.h\"\n#include \"util/moneystr.h\"\n#include \"util/strencodings.h\"\n#include \"validation/validationinterface.h\"\n\n#include \"alert.h\"\n#include \"checkpoints.h\"\n\n#include <boost/foreach.hpp>\n\n#include <algorithm>\n\n#if defined(NDEBUG)\n# error \"Cannot be compiled without assertions.\"\n#endif\n\nstatic std::atomic<bool> fPreventBlockDownloadDuringHeaderSync(false);\n\nstd::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block\n\nstruct IteratorComparator\n{\n    template<typename I>\n    bool operator()(const I& a, const I& b) const\n    {\n        return &(*a) < &(*b);\n    }\n};\n\nstruct COrphanTx\n{\n    // When modifying, adapt the copy of this definition in tests/DoS_tests.\n    CTransactionRef tx;\n    NodeId fromPeer;\n    int64_t nTimeExpire;\n};\nstd::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);\nstd::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main);\nvoid EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);\n\nstatic size_t vExtraTxnForCompactIt = 0;\nstatic std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(cs_main);\n\nstatic const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256(\"main address relay\")[0:8]\n\n// Internal stuff\nnamespace\n{\n    /** Number of nodes with fSyncStarted. */\n    int nSyncStarted = 0;\n\n    /** Number of nodes with fRHeaderSyncStarted. */\n    int nRHeaderSyncStarted = 0;\n\n    /** Number of nodes with fPartialSyncStarted. */\n    int nPartialSyncStarted = 0;\n\n    /**\n     * Sources of received blocks, saved to be able to send them reject\n     * messages or ban them when processing happens afterwards. Protected by\n     * cs_main.\n     * Set mapBlockSource[hash].second to false if the node should not be\n     * punished if the block is invalid.\n     */\n    std::map<uint256, std::pair<NodeId, bool>> mapBlockSource;\n\n    /**\n     * Filter for transactions that were recently rejected by\n     * AcceptToMemoryPool. These are not rerequested until the chain tip\n     * changes, at which point the entire filter is reset. Protected by\n     * cs_main.\n     *\n     * Without this filter we'd be re-requesting txs from each of our peers,\n     * increasing bandwidth consumption considerably. For instance, with 100\n     * peers, half of which relay a tx we don't accept, that might be a 50x\n     * bandwidth increase. A flooding attacker attempting to roll-over the\n     * filter using minimum-sized, 60byte, transactions might manage to send\n     * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a\n     * two minute window to send invs to us.\n     *\n     * Decreasing the false positive rate is fairly cheap, so we pick one in a\n     * million to make it highly unlikely for users to have issues with this\n     * filter.\n     *\n     * Memory used: 1.3 MB\n     */\n    std::unique_ptr<CRollingBloomFilter> recentRejects;\n    uint256 hashRecentRejectsChainTip;\n\n    /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */\n    struct QueuedBlock {\n        uint256 hash;\n        const CBlockIndex* pindex;                               //!< Optional.\n        bool fValidatedHeaders;                                  //!< Whether this block has validated headers at the time of request.\n        std::unique_ptr<PartiallyDownloadedBlock> partialBlock;  //!< Optional, used for CMPCTBLOCK downloads\n        bool priorityRequest;                                    //!< Whether its a priority download\n    };\n    std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;\n\n    /** Stack of nodes which we have set to announce using compact blocks */\n    std::list<NodeId> lNodesAnnouncingHeaderAndIDs;\n\n    /** Number of preferable block download peers. */\n    int nPreferredDownload = 0;\n\n    /** Number of peers from which we're downloading blocks. */\n    int nPeersWithValidatedDownloads = 0;\n\n    /** Relay map, protected by cs_main. */\n    typedef std::map<uint256, CTransactionRef> MapRelay;\n    MapRelay mapRelay;\n    /** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */\n    std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;\n\n    /** Headers received through RHEADERS and checkpoint verified. */\n    std::vector<CBlockHeader> vReverseHeaders;\n\n    /** Maximum starting height seen on any peer. */\n    int nMaxStartingHeight = 0;\n\n    struct PriorityBlockRequest\n    {\n        const CBlockIndex* pindex;\n        bool downloaded;\n        PriorityDownloadCallback_t callback;\n    };\n\n    std::list<PriorityBlockRequest> blocksToDownloadFirst;\n} // anon namespace\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Registration of network node signals.\n//\n\nnamespace\n{\n\nstruct CBlockReject\n{\n    unsigned char chRejectCode;\n    std::string strRejectReason;\n    uint256 hashBlock;\n};\n\n/**\n * Maintain validation-specific state about nodes, protected by cs_main, instead\n * by CNode's own locks. This simplifies asynchronous operation, where\n * processing of incoming data is done after the ProcessMessage call returns,\n * and we're no longer holding the node's locks.\n */\nstruct CNodeState\n{\n    //! The peer's address\n    const CService address;\n    //! Whether we have a fully established connection.\n    bool fCurrentlyConnected;\n    //! Accumulated misbehaviour score for this peer.\n    int nMisbehavior;\n    //! Whether this peer should be disconnected and banned (unless whitelisted).\n    bool fShouldBan;\n    //! String name of this peer (debugging/logging purposes).\n    const std::string name;\n    //! List of asynchronously-determined block rejections to notify this peer about.\n    std::vector<CBlockReject> rejects;\n    //! The best known block we know this peer has announced.\n    const CBlockIndex *pindexBestKnownBlock;\n    //! The hash of the last unknown block this peer has announced.\n    uint256 hashLastUnknownBlock;\n    //! The last full block we both have.\n    const CBlockIndex *pindexLastCommonBlock;\n    //! The best header we have sent our peer.\n    const CBlockIndex *pindexBestHeaderSent;\n    //! Length of current-streak of unconnecting headers announcements\n    int nUnconnectingHeaders;\n    //! Whether we've started (forward) headers synchronization with this peer.\n    bool fSyncStarted;\n    //! Whether we've started reverse headers synchronization with this peer.\n    bool fRHeadersSyncStarted;\n    //! Whether we've started partial headers synchronization with this peer.\n    bool fPartialSyncStarted;\n    //! When to potentially disconnect peer for stalling headers download\n    int64_t nHeadersSyncTimeout;\n    //! When to potentially disconnect peer for stalling partial headers download\n    int64_t nPartialHeadersSyncTimeout;\n    //! Since when we're stalling block download progress (in microseconds), or 0.\n    int64_t nStallingSince;\n    std::list<QueuedBlock> vBlocksInFlight;\n    //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.\n    int64_t nDownloadingSince;\n    int nBlocksInFlight;\n    int nBlocksInFlightValidHeaders;\n    //! Whether we consider this a preferred download peer.\n    bool fPreferredDownload;\n    //! Whether this peer wants invs or headers (when possible) for block announcements.\n    bool fPreferHeaders;\n    //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.\n    bool fPreferHeaderAndIDs;\n    /**\n      * Whether this peer will send us cmpctblocks if we request them.\n      * This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion,\n      * but is used as a flag to \"lock in\" the version of compact blocks (fWantsCmpctWitness) we send.\n      */\n    bool fProvidesHeaderAndIDs;\n    //! Whether this peer can give us segregated signature data\n    bool fHaveSegregatedSignatures;\n    //! Whether this peer wants witnesses in cmpctblocks/blocktxns\n    bool fWantsCmpctWitness;\n    /**\n     * If we've announced NODE_SEGSIG to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns,\n     * otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.\n     */\n    bool fSupportsDesiredCmpctVersion;\n\n    CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn)\n    {\n        fCurrentlyConnected = false;\n        nMisbehavior = 0;\n        fShouldBan = false;\n        pindexBestKnownBlock = NULL;\n        hashLastUnknownBlock.SetNull();\n        pindexLastCommonBlock = NULL;\n        pindexBestHeaderSent = NULL;\n        nUnconnectingHeaders = 0;\n        fSyncStarted = false;\n        fRHeadersSyncStarted = false;\n        fPartialSyncStarted = false;\n        nHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n        nPartialHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n        nStallingSince = 0;\n        nDownloadingSince = 0;\n        nBlocksInFlight = 0;\n        nBlocksInFlightValidHeaders = 0;\n        fPreferredDownload = false;\n        fPreferHeaders = false;\n        fPreferHeaderAndIDs = false;\n        fProvidesHeaderAndIDs = false;\n        fHaveSegregatedSignatures = false;\n        fWantsCmpctWitness = false;\n        fSupportsDesiredCmpctVersion = false;\n    }\n};\n\n/** Map maintaining per-node state. Requires cs_main. */\nstd::map<NodeId, CNodeState> mapNodeState;\n\n// Requires cs_main.\nCNodeState *State(NodeId pnode)\n{\n    std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);\n    if (it == mapNodeState.end())\n        return NULL;\n    return &it->second;\n}\n\nvoid UpdatePreferredDownload(CNode* node, CNodeState* state)\n{\n    nPreferredDownload -= state->fPreferredDownload;\n\n    // Whether this node should be marked as a preferred download node.\n    state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;\n\n    nPreferredDownload += state->fPreferredDownload;\n}\n\nvoid PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)\n{\n    ServiceFlags nLocalNodeServices = pnode->GetLocalServices();\n    uint64_t nonce = pnode->GetLocalNonce();\n    int nNodeStartingHeight = pnode->GetMyStartingHeight();\n    NodeId nodeid = pnode->GetId();\n    CAddress addr = pnode->addr;\n\n    CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));\n    CAddress addrMe = CAddress(CService(), nLocalNodeServices);\n\n    connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,\n            nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));\n\n    if (fLogIPs)\n    {\n        LogPrint(BCLog::NET, \"send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\\n\", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);\n    }\n    else\n    {\n        LogPrint(BCLog::NET, \"send version message: version %d, blocks=%d, us=%s, peer=%d\\n\", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid);\n    }\n}\n\nvoid InitializeNode(CNode *pnode, CConnman& connman)\n{\n    CAddress addr = pnode->addr;\n    std::string addrName = pnode->GetAddrName();\n    NodeId nodeid = pnode->GetId();\n    {\n        LOCK(cs_main);\n        mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));\n    }\n    if(!pnode->fInbound)\n        PushNodeVersion(pnode, connman, GetTime());\n    connman.ResumeReceive(pnode);\n    boost::asio::post(get_io_context(), [pnode, &connman]()\n    {\n        connman.NodeInactivityChecker(pnode);\n    });\n}\n\nvoid FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime)\n{\n    fUpdateConnectionTime = false;\n    LOCK(cs_main);\n    CNodeState *state = State(nodeid);\n\n    if (state->fSyncStarted)\n        nSyncStarted--;\n\n    if (state->fRHeadersSyncStarted)\n        nRHeaderSyncStarted--;\n\n    if (state->fPartialSyncStarted)\n        nPartialSyncStarted--;\n\n    if (state->nMisbehavior == 0 && state->fCurrentlyConnected)\n    {\n        fUpdateConnectionTime = true;\n    }\n\n    for(const QueuedBlock& entry : state->vBlocksInFlight)\n    {\n        mapBlocksInFlight.erase(entry.hash);\n    }\n    EraseOrphansFor(nodeid);\n    nPreferredDownload -= state->fPreferredDownload;\n    nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);\n    assert(nPeersWithValidatedDownloads >= 0);\n\n    mapNodeState.erase(nodeid);\n\n    if (mapNodeState.empty())\n    {\n        // Do a consistency check after the last peer is removed.\n        assert(mapBlocksInFlight.empty());\n        assert(nPreferredDownload == 0);\n        assert(nPeersWithValidatedDownloads == 0);\n    }\n    LogPrint(BCLog::NET, \"Cleared nodestate for peer=%d\\n\", nodeid);\n}\n\n// Requires cs_main.\n// Returns a MarkBlockAsReceivedResult struct to indicating whether we requested this block and if it was via the priority request queue\n// Also used if a block was /not/ received and timed out or started with another peer\nstruct MarkBlockAsReceivedResult\n{\n    bool fRequested;\n    bool fPriorityRequest;\n };\nMarkBlockAsReceivedResult MarkBlockAsReceived(const uint256& hash)\n{\n    std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);\n    if (itInFlight != mapBlocksInFlight.end())\n    {\n        CNodeState *state = State(itInFlight->second.first);\n        state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;\n        if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders)\n        {\n            // Last validated block on the queue was received.\n            nPeersWithValidatedDownloads--;\n        }\n        if (state->vBlocksInFlight.begin() == itInFlight->second.second)\n        {\n            // First block on the queue was received, update the start download time for the next one\n            state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros());\n        }\n        bool priorityRequest = itInFlight->second.second->priorityRequest;\n        state->nBlocksInFlight--;\n        state->nStallingSince = 0;\n        if (priorityRequest)\n        {\n            // mark as downloaded\n            auto it = std::find_if(blocksToDownloadFirst.begin(), blocksToDownloadFirst.end(),  [&itInFlight](const PriorityBlockRequest &r) { return r.pindex == itInFlight->second.second->pindex; });\n            if (it != blocksToDownloadFirst.end())\n            {\n                (*it).downloaded = true;\n            }\n        }\n        state->vBlocksInFlight.erase(itInFlight->second.second);\n        mapBlocksInFlight.erase(itInFlight);\n\n        return {true, priorityRequest};\n    }\n    return {false, false};\n}\n\n// Requires cs_main.\n// returns false, still setting pit, if the block was already in flight from the same peer\n// pit will only be valid as long as the same cs_main lock is being held\nbool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const CBlockIndex* pindex = nullptr, std::list<QueuedBlock>::iterator** pit = nullptr, bool priorityRequest = false) {\n    CNodeState *state = State(nodeid);\n    assert(state != NULL);\n\n    // Short-circuit most stuff in case its from the same node\n    std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);\n    if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid)\n    {\n        if (pit)\n            *pit = &itInFlight->second.second;\n        return false;\n    }\n\n    // Make sure it's not listed somewhere already.\n    MarkBlockAsReceived(hash);\n\n    std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),\n            {hash, pindex, pindex != nullptr, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool) : nullptr), priorityRequest});\n    state->nBlocksInFlight++;\n    state->nBlocksInFlightValidHeaders += it->fValidatedHeaders;\n    if (state->nBlocksInFlight == 1)\n    {\n        // We're starting a block download (batch) from this peer.\n        state->nDownloadingSince = GetTimeMicros();\n    }\n    if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL)\n    {\n        nPeersWithValidatedDownloads++;\n    }\n    itInFlight = mapBlocksInFlight.insert(std::pair(hash, std::pair(nodeid, it))).first;\n    if (pit)\n        *pit = &itInFlight->second.second;\n    return true;\n}\n\n/** Check whether the last unknown block a peer advertised is not yet known. */\nvoid ProcessBlockAvailability(NodeId nodeid)\n{\n    CNodeState *state = State(nodeid);\n    assert(state != NULL);\n\n    if (!state->hashLastUnknownBlock.IsNull())\n    {\n        BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);\n        if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0)\n        {\n            if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork || itOld->second->nHeight >= state->pindexBestKnownBlock->nHeight)\n                state->pindexBestKnownBlock = itOld->second;\n            state->hashLastUnknownBlock.SetNull();\n        }\n    }\n}\n\n/** Update tracking information about which blocks a peer is assumed to have. */\nvoid UpdateBlockAvailability(NodeId nodeid, const uint256 &hash)\n{\n    CNodeState *state = State(nodeid);\n    assert(state != NULL);\n\n    ProcessBlockAvailability(nodeid);\n\n    BlockMap::iterator it = mapBlockIndex.find(hash);\n    if (it != mapBlockIndex.end() && it->second->nChainWork > 0)\n    {\n        // An actually better block was announced.\n        if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork || it->second->nHeight >= state->pindexBestKnownBlock->nHeight)\n            state->pindexBestKnownBlock = it->second;\n    }\n    else\n    {\n        // An unknown block was announced; just assume that the latest one is the best one.\n        state->hashLastUnknownBlock = hash;\n    }\n}\n\nvoid MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman)\n{\n    //fixme: (POST-PHASE5)\n    return;\n    #if 0\n    AssertLockHeld(cs_main);\n    CNodeState* nodestate = State(nodeid);\n    if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion)\n    {\n        // Never ask from peers who can't provide witnesses.\n        return;\n    }\n    if (nodestate->fProvidesHeaderAndIDs)\n    {\n        for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++)\n        {\n            if (*it == nodeid)\n            {\n                lNodesAnnouncingHeaderAndIDs.erase(it);\n                lNodesAnnouncingHeaderAndIDs.push_back(nodeid);\n                return;\n            }\n        }\n        connman.ForNode(nodeid, [&connman](CNode* pfrom){\n            bool fAnnounceUsingCMPCTBLOCK = false;\n            uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_SEGSIG) ? 2 : 1;\n            if (lNodesAnnouncingHeaderAndIDs.size() >= 3)\n            {\n                // As per BIP152, we only get 3 of our peers to announce\n                // blocks using compact encodings.\n                connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){\n                    connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));\n                    return true;\n                });\n                lNodesAnnouncingHeaderAndIDs.pop_front();\n            }\n            fAnnounceUsingCMPCTBLOCK = true;\n            connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));\n            lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());\n            return true;\n        });\n    }\n    #endif\n}\n\n// Requires cs_main\nbool CanDirectFetch(const Consensus::Params &consensusParams)\n{\n    return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;\n}\n\n// Requires cs_main\nbool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex)\n{\n    if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))\n        return true;\n    if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))\n        return true;\n    return false;\n}\n\n/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has\n *  at most count entries.\n *  returns true if priority downloads where used\n */\nbool FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams)\n{\n    if (count == 0)\n        return false;\n\n    vBlocks.reserve(vBlocks.size() + count);\n    CNodeState *state = State(nodeid);\n    assert(state != NULL);\n\n    // Make sure pindexBestKnownBlock is up to date, we'll need it.\n    ProcessBlockAvailability(nodeid);\n\n    if (!blocksToDownloadFirst.empty())\n    {\n        for (const PriorityBlockRequest &r: blocksToDownloadFirst)\n        {\n            if (r.downloaded) continue;\n            if (r.pindex && state->pindexBestKnownBlock != nullptr && state->pindexBestKnownBlock->nHeight >= r.pindex->nHeight && !mapBlocksInFlight.count(r.pindex->GetBlockHashPoW2()))\n            {\n                vBlocks.push_back(r.pindex);\n                if (vBlocks.size() == count)\n                {\n                    break;\n                }\n            }\n        }\n        return true;\n    }\n\n    if (!isFullSyncMode())\n    {\n        return false;\n    }\n\n    bool headerTipStillOld = !partialChain.Tip() || partialChain.Tip()->GetBlockTime() < GetAdjustedTime() - HEADERS_RECENT_FOR_BLOCKDOWNLOAD;\n    if (fPreventBlockDownloadDuringHeaderSync && headerTipStillOld)\n    {\n        return false;\n    }\n\n    if (state->pindexBestKnownBlock == NULL || (state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork && state->pindexBestKnownBlock->nHeight < chainActive.Tip()->nHeight) || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork))\n    {\n        // This peer has nothing interesting.\n        return false;\n    }\n\n    if (state->pindexLastCommonBlock == NULL)\n    {\n        // Bootstrap quickly by guessing a parent of our best tip is the forking point.\n        // Guessing wrong in either direction is not a problem.\n        state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())];\n    }\n\n    // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor\n    // of its current tip anymore. Go back enough to fix that.\n    state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);\n    if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)\n    {\n        if (state->pindexBestKnownBlock->nHeight >= chainActive.Tip()->nHeight)\n        {\n            const CBlockIndex* pIndex = state->pindexBestKnownBlock;\n            if (!pIndex->IsValid(BLOCK_VALID_TREE))\n                return false;\n            if (!State(nodeid)->fHaveSegregatedSignatures && IsSegSigEnabled(pIndex->pprev))\n                return false;\n            if (pIndex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pIndex))\n            {\n                return false;\n            }\n            else if (mapBlocksInFlight.count(pIndex->GetBlockHashPoW2()) == 0)\n            {\n                vBlocks.push_back(state->pindexBestKnownBlock);\n            }\n        }\n        return false;\n    }\n\n    std::vector<const CBlockIndex*> vToFetch;\n    const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;\n    // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last\n    // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to\n    // download that next block if the window were 1 larger.\n    int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;\n    int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);\n    NodeId waitingfor = -1;\n    while (pindexWalk->nHeight < nMaxHeight)\n    {\n        // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards\n        // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive\n        // as iterating over ~100 CBlockIndex* entries anyway.\n        int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));\n        vToFetch.resize(nToFetch);\n        pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);\n        vToFetch[nToFetch - 1] = pindexWalk;\n        for (unsigned int i = nToFetch - 1; i > 0; i--)\n        {\n            vToFetch[i - 1] = vToFetch[i]->pprev;\n        }\n\n        // Iterate over those blocks in vToFetch (in forward direction), adding the ones that\n        // are not yet downloaded and not in flight to vBlocks. In the mean time, update\n        // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's\n        // already part of our chain (and therefore don't need it even if pruned).\n        for(const CBlockIndex* pindex : vToFetch)\n        {\n            if (!pindex->IsValid(BLOCK_VALID_TREE))\n            {\n                // We consider the chain that this peer is on invalid.\n                return false;\n            }\n            if (!State(nodeid)->fHaveSegregatedSignatures && IsSegSigEnabled(pindex->pprev))\n            {\n                // We wouldn't download this block or its descendants from this peer.\n                return false;\n            }\n            if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex))\n            {\n                if (pindex->nChainTx)\n                    state->pindexLastCommonBlock = pindex;\n            }\n            else if (mapBlocksInFlight.count(pindex->GetBlockHashPoW2()) == 0)\n            {\n                // The block is not already downloaded, and not yet in flight.\n                if (pindex->nHeight > nWindowEnd)\n                {\n                    // We reached the end of the window.\n                    if (vBlocks.size() == 0 && waitingfor != nodeid)\n                    {\n                        // We aren't able to fetch anything, but we would be if the download window was one larger.\n                        nodeStaller = waitingfor;\n                    }\n                    return false;\n                }\n                vBlocks.push_back(pindex);\n                if (vBlocks.size() == count)\n                {\n                    return false;\n                }\n            }\n            else if (waitingfor == -1)\n            {\n                // This is the first already-in-flight block.\n                waitingfor = mapBlocksInFlight[pindex->GetBlockHashPoW2()].first;\n            }\n        }\n    }\n    return false;\n}\n\nvoid NotifyHeaderProgress(CConnman& connman, bool partialProgressed)\n{\n    int currentCount = 0;\n    int headerTipHeight = 0;\n    int64_t headerTipTime = 0;\n\n    if (partialProgressed)\n    {\n        LOCK(cs_main);\n        if (pindexBestPartial)\n        {\n            currentCount = pindexBestPartial->nHeight;\n            headerTipHeight = pindexBestPartial->nHeight;\n            headerTipTime = pindexBestPartial->GetBlockTime();\n        }\n    }\n    else // headers not due to partial sync progress, ie. headers have changed normal progress\n    {\n        currentCount = vReverseHeaders.size();\n        LOCK(cs_main);\n        if (pindexBestHeader)\n        {\n            currentCount += pindexBestHeader->nHeight;\n            headerTipHeight = pindexBestHeader->nHeight;\n            headerTipTime = pindexBestHeader->GetBlockTime();\n        }\n    }\n\n    uiInterface.NotifyHeaderProgress(currentCount, GetProbableHeight(), headerTipHeight, headerTipTime);\n}\n\n} // anon namespace\n\nint GetProbableHeight()\n{\n    LOCK(cs_main);\n\n    int probableHeight = nMaxStartingHeight;\n    probableHeight = std::max(probableHeight, Checkpoints::LastCheckPointHeight());\n    if (g_connman)\n        probableHeight = std::max(probableHeight, g_connman->GetBestHeight());\n    if (pindexBestHeader)\n        probableHeight = std::max(probableHeight, pindexBestHeader->nHeight);\n    if (pindexBestPartial)\n        probableHeight = std::max(probableHeight, pindexBestPartial->nHeight);\n    return probableHeight;\n}\n\nbool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)\n{\n    LOCK(cs_main);\n    CNodeState *state = State(nodeid);\n    if (state == NULL)\n        return false;\n    stats.nMisbehavior = state->nMisbehavior;\n    stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;\n    stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;\n    for(const QueuedBlock& queue : state->vBlocksInFlight)\n    {\n        if (queue.pindex)\n            stats.vHeightInFlight.push_back(queue.pindex->nHeight);\n    }\n    return true;\n}\n\nvoid RegisterNodeSignals(CNodeSignals& nodeSignals)\n{\n    nodeSignals.ProcessMessages.connect(&ProcessMessages);\n    nodeSignals.SendMessages.connect(&SendMessages);\n    nodeSignals.InitializeNode.connect(&InitializeNode);\n    nodeSignals.FinalizeNode.connect(&FinalizeNode);\n}\n\nvoid UnregisterNodeSignals(CNodeSignals& nodeSignals)\n{\n    nodeSignals.ProcessMessages.disconnect(&ProcessMessages);\n    nodeSignals.SendMessages.disconnect(&SendMessages);\n    nodeSignals.InitializeNode.disconnect(&InitializeNode);\n    nodeSignals.FinalizeNode.disconnect(&FinalizeNode);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// mapOrphanTransactions\n//\n\nstatic void AddToCompactExtraTransactions(const CTransactionRef& tx)\n{\n    size_t max_extra_txn = GetArg(\"-blockreconstructionextratxn\", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);\n    if (max_extra_txn <= 0)\n        return;\n    if (!vExtraTxnForCompact.size())\n        vExtraTxnForCompact.resize(max_extra_txn);\n    vExtraTxnForCompact[vExtraTxnForCompactIt] = std::pair(tx->GetWitnessHash(), tx);\n    vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn;\n}\n\nbool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)\n{\n    const uint256& hash = tx->GetHash();\n    if (mapOrphanTransactions.count(hash))\n        return false;\n\n    // Ignore big transactions, to avoid a\n    // send-big-orphans memory exhaustion attack. If a peer has a legitimate\n    // large transaction with a missing parent then we assume\n    // it will rebroadcast it later, after the parent transaction(s)\n    // have been mined or received.\n    // 100 orphans, each of which is at most 99,999 bytes big is\n    // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):\n    unsigned int sz = GetTransactionWeight(*tx);\n    if (sz >= MAX_STANDARD_TX_WEIGHT)\n    {\n        LogPrint(BCLog::MEMPOOL, \"ignoring large orphan tx (size: %u, hash: %s)\\n\", sz, hash.ToString());\n        return false;\n    }\n\n    auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME});\n    assert(ret.second);\n    for(const CTxIn& txin : tx->vin)\n    {\n        mapOrphanTransactionsByPrev[txin.GetPrevOut()].insert(ret.first);\n    }\n\n    AddToCompactExtraTransactions(tx);\n\n    LogPrint(BCLog::MEMPOOL, \"stored orphan tx %s (mapsz %u outsz %u)\\n\", hash.ToString(),\n             mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());\n    return true;\n}\n\nint static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)\n{\n    std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);\n    if (it == mapOrphanTransactions.end())\n        return 0;\n    for(const CTxIn& txin : it->second.tx->vin)\n    {\n        auto itPrev = mapOrphanTransactionsByPrev.find(txin.GetPrevOut());\n        if (itPrev == mapOrphanTransactionsByPrev.end())\n            continue;\n        itPrev->second.erase(it);\n        if (itPrev->second.empty())\n            mapOrphanTransactionsByPrev.erase(itPrev);\n    }\n    mapOrphanTransactions.erase(it);\n    return 1;\n}\n\nvoid EraseOrphansFor(NodeId peer)\n{\n    int nErased = 0;\n    std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();\n    while (iter != mapOrphanTransactions.end())\n    {\n        std::map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid\n        if (maybeErase->second.fromPeer == peer)\n        {\n            nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());\n        }\n    }\n    if (nErased > 0) LogPrint(BCLog::MEMPOOL, \"Erased %d orphan tx from peer=%d\\n\", nErased, peer);\n}\n\n\nunsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)\n{\n    unsigned int nEvicted = 0;\n    static int64_t nNextSweep;\n    int64_t nNow = GetTime();\n    if (nNextSweep <= nNow)\n    {\n        // Sweep out expired orphan pool entries:\n        int nErased = 0;\n        int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;\n        std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();\n        while (iter != mapOrphanTransactions.end())\n        {\n            std::map<uint256, COrphanTx>::iterator maybeErase = iter++;\n            if (maybeErase->second.nTimeExpire <= nNow)\n            {\n                nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());\n            }\n            else\n            {\n                nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);\n            }\n        }\n        // Sweep again 5 minutes after the next entry that expires in order to batch the linear scan.\n        nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;\n        if (nErased > 0) LogPrint(BCLog::MEMPOOL, \"Erased %d orphan tx due to expiration\\n\", nErased);\n    }\n    while (mapOrphanTransactions.size() > nMaxOrphans)\n    {\n        // Evict a random orphan:\n        uint256 randomhash = GetRandHash();\n        std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);\n        if (it == mapOrphanTransactions.end())\n            it = mapOrphanTransactions.begin();\n        EraseOrphanTx(it->first);\n        ++nEvicted;\n    }\n    return nEvicted;\n}\n\n// Requires cs_main.\nvoid Misbehaving(NodeId pnode, int howmuch)\n{\n    if (howmuch == 0)\n        return;\n\n    CNodeState *state = State(pnode);\n    if (state == NULL)\n        return;\n\n    state->nMisbehavior += howmuch;\n    int banscore = GetArg(\"-banscore\", DEFAULT_BANSCORE_THRESHOLD);\n    if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)\n    {\n        LogPrintf(\"%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED\\n\", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);\n        state->fShouldBan = true;\n    } else\n        LogPrintf(\"%s: %s peer=%d (%d -> %d)\\n\", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);\n}\n\n\n\n\n\n\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// blockchain -> download logic notification\n//\n\nPeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn)\n{\n    // Initialize global variables that cannot be constructed at startup.\n    recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));\n}\n\nvoid PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted)\n{\n    LOCK(cs_main);\n\n    std::vector<uint256> vOrphanErase;\n\n    for (const CTransactionRef& ptx : pblock->vtx)\n    {\n        const CTransaction& tx = *ptx;\n\n        // Which orphan pool entries must we evict?\n        for (const auto& txin : tx.vin)\n        {\n            auto itByPrev = mapOrphanTransactionsByPrev.find(txin.GetPrevOut());\n            if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;\n            for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi)\n            {\n                const CTransaction& orphanTx = *(*mi)->second.tx;\n                const uint256& orphanHash = orphanTx.GetHash();\n                vOrphanErase.push_back(orphanHash);\n            }\n        }\n    }\n\n    // Erase orphan transactions include or precluded by this block\n    if (vOrphanErase.size())\n    {\n        int nErased = 0;\n        for(uint256 &orphanHash : vOrphanErase)\n        {\n            nErased += EraseOrphanTx(orphanHash);\n        }\n        LogPrint(BCLog::MEMPOOL, \"Erased %d orphan tx included or conflicted by block\\n\", nErased);\n    }\n}\n\n// All of the following cache a recent block, and are protected by cs_most_recent_block\nstatic RecursiveMutex cs_most_recent_block;\n\nstatic std::shared_ptr<const CBlock> most_recent_block_pow;\nstatic std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block_pow;\nstatic uint256 most_recent_block_hash_pow;\n\nstatic std::shared_ptr<const CBlock> most_recent_block_pow2;\nstatic std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block_pow2;\nstatic uint256 most_recent_block_hash_pow2;\n\nstatic bool fWitnessesPresentInMostRecentCompactBlock;\n\nvoid PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock)\n{\n    std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true);\n    const CNetMsgMaker msgMaker(PROTOCOL_VERSION);\n\n    LOCK(cs_main);\n\n    static int nHighestFastAnnounce = 0;\n    // < and not <= as we want to also announce competing PoW orphans in the case of an absent witness.\n    if (pindex->nHeight < nHighestFastAnnounce)\n        return;\n    nHighestFastAnnounce = pindex->nHeight;\n\n    bool fWitnessEnabled = IsSegSigEnabled(pindex->pprev);\n\n    uint256 hashBlock;\n\n    if (pblock->nVersionPoW2Witness > 0)\n    {\n        hashBlock = pblock->GetHashPoW2();\n        {\n            LOCK(cs_most_recent_block);\n            most_recent_block_hash_pow2 = hashBlock;\n            most_recent_block_pow2 = pblock;\n            most_recent_compact_block_pow2 = pcmpctblock;\n            fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;\n        }\n    }\n    else\n    {\n        hashBlock = pblock->GetHashLegacy();\n        {\n            LOCK(cs_most_recent_block);\n            most_recent_block_hash_pow = hashBlock;\n            most_recent_block_pow = pblock;\n            most_recent_compact_block_pow = pcmpctblock;\n            fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;\n        }\n    }\n\n\n    connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode)\n    {\n        // TODO: Avoid the repeated-serialization here\n        if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)\n            return;\n        ProcessBlockAvailability(pnode->GetId());\n        CNodeState &state = *State(pnode->GetId());\n        // If the peer has, or we announced to them the previous block already,\n        // but we don't think they have this one, go ahead and announce it\n        if ( !PeerHasHeader(&state, pindex) /*&& PeerHasHeader(&state, pindex->pprev)*/ )\n        {\n            if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness))\n            {\n                LogPrint(BCLog::NET, \"%s fast-announce sending header-and-ids %s to peer=%d\\n\", \"PeerLogicValidation::NewPoWValidBlock\", hashBlock.ToString(), pnode->GetId());\n                connman->PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));\n                state.pindexBestHeaderSent = pindex;\n            }\n            else\n            {\n                std::vector<CBlock> vHeaders;\n                vHeaders.push_back(pindex->GetBlockHeader());\n                LogPrint(BCLog::NET, \"%s fast-announce sending header %s to peer=%d\\n\", \"PeerLogicValidation::NewPoWValidBlock\", hashBlock.ToString(), pnode->GetId());\n                connman->PushMessage(pnode, (msgMaker).Make(NetMsgType::HEADERS, COMPACTSIZEVECTOR(vHeaders)));\n            }\n        }\n    });\n}\n\nvoid PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)\n{\n    const int nNewHeight = pindexNew->nHeight;\n    connman->SetBestHeight(nNewHeight);\n\n    if (!fInitialDownload)\n    {\n        // Find the hashes of all blocks that weren't previously in the best chain.\n        std::vector<uint256> vHashes;\n        const CBlockIndex *pindexToAnnounce = pindexNew;\n        while (pindexToAnnounce != pindexFork)\n        {\n            vHashes.push_back(pindexToAnnounce->GetBlockHashPoW2());\n            pindexToAnnounce = pindexToAnnounce->pprev;\n            if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE)\n            {\n                // Limit announcements in case of a huge reorganization.\n                // Rely on the peer's synchronization mechanism in that case.\n                break;\n            }\n        }\n        // Relay inventory, but don't relay old inventory during initial block download.\n        connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode)\n        {\n            if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0))\n            {\n                BOOST_REVERSE_FOREACH(const uint256& hash, vHashes)\n                {\n                    pnode->PushBlockHash(hash);\n                }\n            }\n        });\n        connman->WakeMessageHandler();\n    }\n\n    nTimeBestReceived = GetTime();\n}\n\nvoid PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state)\n{\n    LOCK(cs_main);\n\n    const uint256 hash = block.GetHashPoW2();\n\n    std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);\n\n    int nDoS = 0;\n    if (state.IsInvalid(nDoS))\n    {\n        // Don't send reject message with code 0 or an internal reject code.\n        if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL)\n        {\n            CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};\n            State(it->second.first)->rejects.push_back(reject);\n            if (nDoS > 0 && it->second.second)\n                Misbehaving(it->second.first, nDoS);\n        }\n    }\n    // Check that:\n    // 1. The block is valid\n    // 2. We're not in initial block download\n    // 3. This is currently the best block we're aware of. We haven't updated\n    //    the tip yet so we have no way to check this directly here. Instead we\n    //    just check that there are currently no other blocks in flight.\n    else if (state.IsValid() && !IsInitialBlockDownload() && mapBlocksInFlight.count(hash) == mapBlocksInFlight.size())\n    {\n        if (it != mapBlockSource.end())\n        {\n            MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman);\n        }\n    }\n    if (it != mapBlockSource.end())\n        mapBlockSource.erase(it);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Messages\n//\n\n\nbool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)\n{\n    switch (inv.type)\n    {\n        case MSG_TX:\n        case MSG_WITNESS_TX:\n            {\n                assert(recentRejects);\n                if (chainActive.Tip()->GetBlockHashPoW2() != hashRecentRejectsChainTip)\n                {\n                    // If the chain tip has changed previously rejected transactions\n                    // might be now valid, e.g. due to a nLockTime'd tx becoming valid,\n                    // or a double-spend. Reset the rejects filter and give those\n                    // txs a second chance.\n                    hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHashPoW2();\n                    recentRejects->reset();\n                }\n\n                return recentRejects->contains(inv.hash) ||\n                    mempool.exists(inv.hash) ||\n                    mapOrphanTransactions.count(inv.hash) ||\n                    pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1\n                    pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));\n            }\n        case MSG_BLOCK:\n        case MSG_WITNESS_BLOCK:\n            return mapBlockIndex.count(inv.hash);\n    }\n    // Don't know what it is, just say we already got one\n    return true;\n}\n\nstatic void RelayTransaction(const CTransaction& tx, CConnman& connman)\n{\n    CInv inv(MSG_TX, tx.GetHash());\n    connman.ForEachNode([&inv](CNode* pnode)\n    {\n        pnode->PushInventory(inv);\n    });\n}\n\nstatic void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)\n{\n    unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)\n\n    // Relay to a limited number of other nodes\n    // Use deterministic randomness to send to the same nodes for 24 hours\n    // at a time so the addrKnowns of the chosen nodes prevent repeats\n    uint64_t hashAddr = addr.GetHash();\n    const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));\n    FastRandomContext insecure_rand;\n\n    std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};\n    assert(nRelayNodes <= best.size());\n\n    auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode)\n    {\n        if (pnode->nVersion >= CADDR_TIME_VERSION)\n        {\n            uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();\n            for (unsigned int i = 0; i < nRelayNodes; i++)\n            {\n                 if (hashKey > best[i].first)\n                 {\n                     std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);\n                     best[i] = std::pair(hashKey, pnode);\n                     break;\n                 }\n            }\n        }\n    };\n\n    auto pushfunc = [&addr, &best, nRelayNodes, &insecure_rand]\n    {\n        for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++)\n        {\n            best[i].second->PushAddress(addr, insecure_rand);\n        }\n    };\n\n    connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));\n}\n\nvoid static ProcessGetData(CNode* pfrom, const CChainParams& params, CConnman& connman, const std::atomic<bool>& interruptMsgProc)\n{\n    std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();\n    std::vector<CInv> vNotFound;\n    const CNetMsgMaker msgMaker(pfrom->GetSendVersion());\n    const Consensus::Params& consensusParams = params.GetConsensus();\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n    while (it != pfrom->vRecvGetData.end())\n    {\n        // Don't bother if send buffer is too full to respond anyway\n        if (pfrom->fPauseSend)\n            break;\n\n        const CInv &inv = *it;\n        {\n            if (interruptMsgProc)\n                return;\n\n            it++;\n\n            if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)\n            {\n                bool send = false;\n                BlockMap::iterator mi = mapBlockIndex.find(inv.hash);\n                std::shared_ptr<const CBlock> a_recent_block;\n                std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;\n                bool fWitnessesPresentInARecentCompactBlock;\n                {\n                    LOCK(cs_most_recent_block);\n\n                    a_recent_block = most_recent_block_pow2;\n                    a_recent_compact_block = most_recent_compact_block_pow2;\n                    fWitnessesPresentInARecentCompactBlock = fWitnessesPresentInMostRecentCompactBlock;\n                }\n                if (mi != mapBlockIndex.end())\n                {\n                    if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) &&\n                            mi->second->IsValid(BLOCK_VALID_TREE))\n                    {\n                        // If we have the block and all of its parents, but have not yet validated it,\n                        // we might be in the middle of connecting it (ie in the unlock of cs_main\n                        // before ActivateBestChain but after AcceptBlock).\n                        // In this case, we need to run ActivateBestChain prior to checking the relay\n                        // conditions below.\n                        CValidationState dummy;\n                        ActivateBestChain(dummy, Params(), a_recent_block);\n                    }\n                    // If it is part of the chain or a competing PoW tip orphan then we want to send it.\n                    if (chainActive.Contains(mi->second) || mi->second->nHeight >= chainActive.Tip()->nHeight)\n                    {\n                        send = true;\n                    }\n                    else\n                    {\n                        static const int nOneMonth = 30 * 24 * 60 * 60;\n                        // To prevent fingerprinting attacks, only send blocks outside of the active\n                        // chain if they are valid, and no more than a month older (both in time, and in\n                        // best equivalent proof of work) than the best header chain we know about.\n                        send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) &&\n                            (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&\n                            (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth);\n                        if (!send)\n                            LogPrintf(\"%s: ignoring request from peer=%i for old block that isn't in the main chain\\n\", __func__, pfrom->GetId());\n                    }\n                }\n                // disconnect node in case we have reached the outbound limit for serving historical blocks\n                // never disconnect whitelisted nodes\n                static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical\n                if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)\n                {\n                    LogPrint(BCLog::NET, \"historical block serving limit reached, disconnect peer=%d\\n\", pfrom->GetId());\n\n                    //disconnect node\n                    pfrom->fDisconnect = true;\n                    send = false;\n                }\n                // Pruned nodes may have deleted the block, so check whether\n                // it's available before trying to send.\n                if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))\n                {\n                    std::shared_ptr<const CBlock> pblock;\n\n                    if (a_recent_block && a_recent_block->GetHashPoW2() == (*mi).second->GetBlockHashPoW2())\n                    {\n                        pblock = a_recent_block;\n                    }\n                    else\n                    {\n                        // Send block from disk\n                        std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();\n                        if (!ReadBlockFromDisk(*pblockRead, (*mi).second, params))\n                            assert(!\"cannot load pow2 block from disk\");\n                        pblock = pblockRead;\n                    }\n\n                    if (inv.type == MSG_BLOCK)\n                    {\n                        connman.PushMessage(pfrom, (msgMaker).Make(SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES, NetMsgType::BLOCK, *pblock));\n                    }\n                    else if (inv.type == MSG_WITNESS_BLOCK)\n                    {\n                        connman.PushMessage(pfrom, (msgMaker).Make(NetMsgType::BLOCK, *pblock));\n                    }\n                    else if (inv.type == MSG_FILTERED_BLOCK)\n                    {\n                        //fixme: (PHASE5) We can remove this mesage.\n                        // no response\n                    }\n                    else if (inv.type == MSG_CMPCT_BLOCK)\n                    {\n                        // If a peer is asking for old blocks, we're almost guaranteed\n                        // they won't have a useful mempool to match against a compact block,\n                        // and we don't feel like constructing the object for them, so\n                        // instead we respond with the full, non-compact block.\n                        bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;\n                        int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES;\n                        if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH)\n                        {\n                            if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHashPoW2() == mi->second->GetBlockHashPoW2())\n                            {\n                                connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));\n                            }\n                            else\n                            {\n                                CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);\n                                connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));\n                            }\n                        }\n                        else\n                        {\n                            connman.PushMessage(pfrom, (msgMaker).Make(nSendFlags, NetMsgType::BLOCK, *pblock));\n                        }\n                    }\n\n                    // Trigger the peer node to send a getblocks request for the next batch of inventory\n                    if (inv.hash == pfrom->hashContinue)\n                    {\n                        // Bypass PushInventory, this must send even if redundant,\n                        // and we want it right after the last block so they don't\n                        // wait for other stuff first.\n                        std::vector<CInv> vInv;\n                        vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHashPoW2()));\n                        connman.PushMessage(pfrom, (msgMaker).Make(NetMsgType::INV, COMPACTSIZEVECTOR(vInv)));\n                        pfrom->hashContinue.SetNull();\n                    }\n                }\n            }\n            else if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)\n            {\n                // Send stream from relay memory\n                bool push = false;\n                auto mi = mapRelay.find(inv.hash);\n                int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES : 0);\n                if (mi != mapRelay.end())\n                {\n                    connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));\n                    push = true;\n                }\n                else if (pfrom->timeLastMempoolReq)\n                {\n                    auto txinfo = mempool.info(inv.hash);\n                    // To protect privacy, do not answer getdata using the mempool when\n                    // that TX couldn't have been INVed in reply to a MEMPOOL request.\n                    if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq)\n                    {\n                        connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));\n                        push = true;\n                    }\n                }\n                if (!push)\n                {\n                    vNotFound.push_back(inv);\n                }\n            }\n\n            if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)\n                break;\n        }\n    }\n\n    pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);\n\n    if (!vNotFound.empty())\n    {\n        // Let the peer know that we didn't find what it asked for, so it doesn't\n        // have to wait around forever. Currently only SPV clients actually care\n        // about this message: it's needed when they are recursively walking the\n        // dependencies of relevant unconfirmed transactions. SPV clients want to\n        // do that because they want to know about (and store and rebroadcast and\n        // risk analyze) the dependencies of transactions relevant to them, without\n        // having to download the entire memory pool.\n        connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, COMPACTSIZEVECTOR(vNotFound)));\n    }\n}\n\nstatic uint32_t GetFetchFlags(CNode* pfrom)\n{\n    uint32_t nFetchFlags = 0;\n    if ((pfrom->GetLocalServices() & NODE_SEGSIG) && State(pfrom->GetId())->fHaveSegregatedSignatures)\n    {\n        nFetchFlags |= MSG_WITNESS_FLAG;\n    }\n    return nFetchFlags;\n}\n\ninline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman)\n{\n    BlockTransactions resp(req);\n    for (size_t i = 0; i < req.indexes.size(); i++)\n    {\n        if (req.indexes[i] >= block.vtx.size())\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 100);\n            LogPrintf(\"Peer %d sent us a getblocktxn with out-of-bounds tx indices\", pfrom->GetId());\n            return;\n        }\n        resp.txn[i] = block.vtx[req.indexes[i]];\n    }\n    LOCK(cs_main);\n    const CNetMsgMaker msgMaker(pfrom->GetSendVersion());\n    int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES;\n    connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));\n}\n\nextern void UnityReportError(const std::string &str);\n\nstatic void ProcessPriorityRequests()\n{\n    LOCK(cs_main);\n    while (!blocksToDownloadFirst.empty())\n    {\n        const PriorityBlockRequest &r = *blocksToDownloadFirst.begin();\n\n        // make sure we process blocks in order\n        if (!r.downloaded)\n        {\n            break;\n        }\n\n        if (r.pindex->nStatus & BLOCK_HAVE_DATA)\n        {\n            CBlock loadBlock;\n            if (!ReadBlockFromDisk(loadBlock, r.pindex, Params()))\n            {\n                if (fSPV)\n                {\n                    pactiveWallet->ResetSPV();\n                    UnityReportError(std::string(__func__) + \"Can't read block from disk\");\n                    return;\n                }\n                else\n                {\n                    throw std::runtime_error(std::string(__func__) + \"Can't read block from disk\");\n                }\n            }\n            auto currentBlock = std::make_shared<const CBlock>(loadBlock);\n\n            r.callback(currentBlock, r.pindex);\n\n            LogPrint(BCLog::NET, \"processed priority block request (%s) height=%d\\n\", r.pindex->GetBlockHashPoW2().ToString(), r.pindex->nHeight);\n\n            blocksToDownloadFirst.pop_front();\n        }\n        else\n        {\n            if (fSPV && pactiveWallet)\n            {\n                pactiveWallet->ResetSPV();\n                UnityReportError(std::string(__func__) + \"Can't read block from disk\");\n                return;\n            }\n            else\n            {\n                throw std::runtime_error(std::string(__func__) + strprintf(\" No data for downloaded block [%s], block index inconsistency.\", r.pindex->GetBlockHashPoW2().ToString()));\n            }\n        }\n    }\n}\n\nstatic void SendMempool(CNode* pto, unsigned int maxEntries = std::numeric_limits<int>::max())\n{\n    auto vtxinfo = mempool.infoAll();\n\n    // limit to maxEntries by random selection\n    // there is intentionally no prefered treatment for \"own\" tx, they will be send eventually on another random selection\n    while (vtxinfo.size() > maxEntries)\n    {\n        vtxinfo.erase(vtxinfo.begin() + GetRandInt(vtxinfo.size()));\n    }\n\n    for (const auto& txinfo : vtxinfo)\n    {\n        const uint256& hash = txinfo.tx->GetHash();\n        CInv inv(MSG_TX, hash);\n        pto->PushInventory(inv);\n    }\n}\n\nbool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, const std::atomic<bool>& interruptMsgProc)\n{\n    LogPrint(BCLog::NET, \"received: %s (%u bytes) peer=%d\\n\", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());\n    if (IsArgSet(\"-dropmessagestest\") && GetRand(GetArg(\"-dropmessagestest\", 0)) == 0)\n    {\n        LogPrintf(\"dropmessagestest DROPPING RECV MESSAGE\\n\");\n        return true;\n    }\n\n    if (IsArgSet(\"-dropsyncheaderstest\"))\n    {\n        // rig artificially unresponsive peer\n        LOCK(cs_main);\n        CNodeState *nodestate = State(pfrom->GetId());\n\n        if (GetRand(GetArg(\"-dropsyncheaderstest\", 0)) == 0 // select random\n            && (strCommand == NetMsgType::HEADERS || strCommand == NetMsgType::RHEADERS) // header messages\n            && vRecv.size() > 1000 // which are large (ie. not an announcement but most likely a response to a header request)\n            && (nodestate->fPartialSyncStarted || nodestate->fSyncStarted || nodestate->fRHeadersSyncStarted) ) // when syncing\n        {\n            LogPrintf(\"dropsyncheaderstest DROPPED A HEADER for node %d\\n\", pfrom->GetId());\n            return true;\n        }\n    }\n\n    if (!(pfrom->GetLocalServices() & NODE_BLOOM) && (strCommand == NetMsgType::FILTERLOAD || strCommand == NetMsgType::FILTERADD))\n    {\n        if (pfrom->nVersion >= NO_BLOOM_VERSION)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 100);\n            return false;\n        }\n        else\n        {\n            pfrom->fDisconnect = true;\n            return false;\n        }\n    }\n\n    if (strCommand == NetMsgType::REJECT)\n    {\n        if (LogAcceptCategory(BCLog::NET))\n        {\n            try\n            {\n                std::string strMsg; unsigned char ccode; std::string strReason;\n                vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);\n\n                std::ostringstream ss;\n                ss << strMsg << \" code \" << itostr(ccode) << \": \" << strReason;\n\n                if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)\n                {\n                    uint256 hash;\n                    vRecv >> hash;\n                    ss << \": hash \" << hash.ToString();\n                }\n                LogPrint(BCLog::NET, \"Reject %s\\n\", SanitizeString(ss.str()));\n            } catch (const std::ios_base::failure&)\n            {\n                // Avoid feedback loops by preventing reject messages from triggering a new reject message.\n                LogPrint(BCLog::NET, \"Unparseable reject message received\\n\");\n            }\n        }\n    }\n\n    else if (strCommand == NetMsgType::VERSION)\n    {\n        // Each connection can only send one version message\n        if (pfrom->nVersion != 0)\n        {\n            connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string(\"Duplicate version message\")));\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 1);\n            return false;\n        }\n\n        int64_t nTime;\n        CAddress addrMe;\n        CAddress addrFrom;\n        uint64_t nNonce = 1;\n        uint64_t nServiceInt;\n        ServiceFlags nServices;\n        int nVersion;\n        int nSendVersion;\n        std::string strSubVer;\n        std::string cleanSubVer;\n        int nStartingHeight = -1;\n        bool fRelay = true;\n\n        vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;\n        nSendVersion = std::min(nVersion, PROTOCOL_VERSION);\n        nServices = ServiceFlags(nServiceInt);\n        if (!pfrom->fInbound)\n        {\n            connman.SetServices(pfrom->addr, nServices);\n        }\n        if (pfrom->nServicesExpected & ~nServices)\n        {\n            LogPrint(BCLog::NET, \"peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\\n\", pfrom->GetId(), nServices, pfrom->nServicesExpected);\n            connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,\n                               strprintf(\"Expected to offer services %08x\", pfrom->nServicesExpected)));\n            pfrom->fDisconnect = true;\n            return false;\n        }\n\n\n        // disconnect from peers older than this proto version\n        if (nVersion < MIN_PEER_PROTO_VERSION)\n        {\n            if (!gbMinimalLogging)\n                LogPrintf(\"peer=%d using obsolete version %i; disconnecting\\n\", pfrom->GetId(), nVersion);\n            connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf(\"Version must be %d or greater\", MIN_PEER_PROTO_VERSION)));\n            pfrom->fDisconnect = true;\n            return false;\n        }\n\n        if (nVersion == 10300)\n            nVersion = 300;\n        if (!vRecv.empty())\n            vRecv >> addrFrom >> nNonce;\n        if (!vRecv.empty())\n        {\n            vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);\n            cleanSubVer = SanitizeString(strSubVer);\n        }\n        if (!vRecv.empty())\n        {\n            vRecv >> nStartingHeight;\n        }\n        if (!vRecv.empty())\n            vRecv >> fRelay;\n        // Disconnect if we connected to ourself\n        if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))\n        {\n            LogPrintf(\"connected to self at %s, disconnecting\\n\", pfrom->addr.ToString());\n            pfrom->fDisconnect = true;\n            return true;\n        }\n\n        if (pfrom->fInbound && addrMe.IsRoutable())\n        {\n            SeenLocal(addrMe);\n        }\n\n        // Be shy and don't send version until we hear\n        if (pfrom->fInbound)\n            PushNodeVersion(pfrom, connman, GetAdjustedTime());\n\n        connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));\n\n        pfrom->nServices = nServices;\n        pfrom->SetAddrLocal(addrMe);\n        {\n            LOCK(pfrom->cs_SubVer);\n            pfrom->strSubVer = strSubVer;\n            pfrom->cleanSubVer = cleanSubVer;\n        }\n        pfrom->nStartingHeight = nStartingHeight;\n        if (nStartingHeight > nMaxStartingHeight)\n            nMaxStartingHeight = nStartingHeight;\n        pfrom->fClient = !(nServices & NODE_NETWORK);\n        {\n            pfrom->fRelayTxes = fRelay;\n        }\n\n        // Change version\n        pfrom->SetSendVersion(nSendVersion);\n        pfrom->nVersion = nVersion;\n\n        if((nServices & NODE_SEGSIG))\n        {\n            LOCK(cs_main);\n            State(pfrom->GetId())->fHaveSegregatedSignatures = true;\n        }\n\n        // Potentially mark this peer as a preferred download peer.\n        {\n            LOCK(cs_main);\n            UpdatePreferredDownload(pfrom, State(pfrom->GetId()));\n        }\n\n        if (!pfrom->fInbound)\n        {\n            // Advertise our address\n            if (fListen && !IsInitialBlockDownload())\n            {\n                CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());\n                FastRandomContext insecure_rand;\n                if (addr.IsRoutable())\n                {\n                    LogPrint(BCLog::NET, \"ProcessMessages: advertising address %s\\n\", addr.ToString());\n                    pfrom->PushAddress(addr, insecure_rand);\n                }\n                else if (IsPeerAddrLocalGood(pfrom))\n                {\n                    addr.SetIP(addrMe);\n                    LogPrint(BCLog::NET, \"ProcessMessages: advertising address %s\\n\", addr.ToString());\n                    pfrom->PushAddress(addr, insecure_rand);\n                }\n            }\n\n            // Get recent addresses\n            if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)\n            {\n                connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));\n                pfrom->fGetAddr = true;\n            }\n            connman.MarkAddressGood(pfrom->addr);\n        }\n\n        std::string remoteAddr;\n        if (fLogIPs)\n            remoteAddr = \", peeraddr=\" + pfrom->addr.ToString();\n\n        LogPrintf(\"receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\\n\",\n                  cleanSubVer, pfrom->nVersion,\n                  pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(),\n                  remoteAddr);\n\n        int64_t nTimeOffset = nTime - GetTime();\n        pfrom->nTimeOffset = nTimeOffset;\n        AddTimeData(pfrom->addr, nTimeOffset);\n\n        // Feeler connections exist only to verify if address is online.\n        if (pfrom->fFeeler)\n        {\n            assert(!pfrom->fInbound);\n            pfrom->fDisconnect = true;\n        }\n\n        // Relay alerts\n        {\n            LOCK(cs_mapAlerts);\n            for (const auto& [alertHash, alert] : mapAlerts)\n            {\n                (unused) alertHash;\n                alert.RelayTo(pfrom);\n            }\n        }\n\n        // Trigger mempool to be send when synced. This way transaction that were created recently but perhaps not reached the network\n        // yet due to connectity issues (which can easily happen on mobile devices) are broadcasted to all new peers.\n        // Under normal circumstances the whole mempool will be sent, however under peak conditions at most MAX_SEND_INIT_MEMPOOL randomly selected\n        // entries are sent.\n        if (IsChainNearPresent() || IsPartialNearPresent())\n            SendMempool(pfrom, MAX_SEND_INIT_MEMPOOL);\n\n        // Disconnect any peers that are not yet synced beyond the last checkpoint height\n        // They will only slow the sync down\n        if (IsInitialBlockDownload())\n        {\n            if (pfrom->nStartingHeight < Checkpoints::LastCheckPointHeight() && Checkpoints::LastCheckPointHeight() != 0)\n            {\n                LOCK(cs_main);\n                pfrom->fDisconnect = true;\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n\n    else if (fAlerts && strCommand == NetMsgType::ALERT)\n    {\n        CAlert alert;\n        vRecv >> alert;\n\n        uint256 alertHash = alert.GetHash();\n        if (pfrom->setKnown.count(alertHash) == 0)\n        {\n            if (alert.ProcessAlert(chainparams.AlertKey()))\n            {\n                // Relay\n                pfrom->setKnown.insert(alertHash);\n                {\n                    g_connman->ForEachNode([alert](CNode* pnode)\n                    {\n                        alert.RelayTo(pnode);\n                    });\n                }\n            }\n            else\n            {\n                // Small DoS penalty so peers that send us lots of\n                // duplicate/expired/invalid-signature/whatever alerts\n                // eventually get banned.\n                // This isn't a Misbehaving(100) (immediate ban) because the\n                // peer might be an older or different implementation with\n                // a different signature key, etc.\n                Misbehaving(pfrom->GetId(), 10);\n            }\n        }\n    }\n    \n    else if (pfrom->nVersion == 0)\n    {\n        // Must have a version message before anything else\n        LOCK(cs_main);\n        Misbehaving(pfrom->GetId(), 1);\n        return false;\n    }\n\n    // At this point, the outgoing message serialization version can't change.\n    const CNetMsgMaker msgMaker(pfrom->GetSendVersion());\n\n    if (strCommand == NetMsgType::VERACK)\n    {\n        pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));\n\n        if (!pfrom->fInbound)\n        {\n            // Mark this node as currently connected, so we update its timestamp later.\n            LOCK(cs_main);\n            State(pfrom->GetId())->fCurrentlyConnected = true;\n        }\n\n        if (pfrom->nVersion >= SENDHEADERS_VERSION)\n        {\n            // Tell our peer we prefer to receive headers rather than inv's\n            // We send this to non-NODE NETWORK peers as well, because even\n            // non-NODE NETWORK peers can announce blocks (such as pruning\n            // nodes)\n            connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));\n        }\n        //fixme: (POST-PHASE5)\n        #if 0\n        if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION)\n        {\n            // Tell our peer we are willing to provide version 1 or 2 cmpctblocks\n            // However, we do not request new block announcements using\n            // cmpctblock messages.\n            // We send this to non-NODE NETWORK peers as well, because\n            // they may wish to request compact blocks from us\n            bool fAnnounceUsingCMPCTBLOCK = false;\n            uint64_t nCMPCTBLOCKVersion = 2;\n            if (pfrom->GetLocalServices() & NODE_SEGSIG)\n                connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));\n            nCMPCTBLOCKVersion = 1;\n            connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));\n        }\n        #endif\n        pfrom->fSuccessfullyConnected = true;\n    }\n\n    else if (!pfrom->fSuccessfullyConnected)\n    {\n        // Must have a verack message before anything else\n        LOCK(cs_main);\n        Misbehaving(pfrom->GetId(), 1);\n        return false;\n    }\n\n    else if (strCommand == NetMsgType::ADDR)\n    {\n        std::vector<CAddress> vAddr;\n        vRecv >> COMPACTSIZEVECTOR(vAddr);\n\n        // Don't want addr from older versions unless seeding\n        if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)\n            return true;\n        if (vAddr.size() > 1000)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 20);\n            return error(\"message addr size() = %u\", vAddr.size());\n        }\n\n        // Store the new addresses\n        std::vector<CAddress> vAddrOk;\n        int64_t nNow = GetAdjustedTime();\n        int64_t nSince = nNow - 10 * 60;\n        for(CAddress& addr : vAddr)\n        {\n            if (interruptMsgProc)\n                return true;\n\n            if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)\n                continue;\n\n            if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)\n                addr.nTime = nNow - 5 * 24 * 60 * 60;\n            pfrom->AddAddressKnown(addr);\n            bool fReachable = IsReachable(addr);\n            if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())\n            {\n                // Relay to a limited number of other nodes\n                RelayAddress(addr, fReachable, connman);\n            }\n            // Do not store addresses outside our network\n            if (fReachable)\n                vAddrOk.push_back(addr);\n        }\n        connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);\n        if (vAddr.size() < 1000)\n            pfrom->fGetAddr = false;\n        if (pfrom->fOneShot)\n            pfrom->fDisconnect = true;\n    }\n\n    else if (strCommand == NetMsgType::SENDHEADERS)\n    {\n        LOCK(cs_main);\n        State(pfrom->GetId())->fPreferHeaders = true;\n    }\n\n    else if (strCommand == NetMsgType::SENDCMPCT)\n    {\n        //fixme: (POST-PHASE5)\n        #if 0\n        bool fAnnounceUsingCMPCTBLOCK = false;\n        uint64_t nCMPCTBLOCKVersion = 0;\n        vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;\n        if (nCMPCTBLOCKVersion == 1 || ((pfrom->GetLocalServices() & NODE_SEGSIG) && nCMPCTBLOCKVersion == 2))\n        {\n            LOCK(cs_main);\n            // fProvidesHeaderAndIDs is used to \"lock in\" version of compact blocks we send (fWantsCmpctWitness)\n            if (!State(pfrom->GetId())->fProvidesHeaderAndIDs)\n            {\n                State(pfrom->GetId())->fProvidesHeaderAndIDs = true;\n                State(pfrom->GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2;\n            }\n            if (State(pfrom->GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces\n                State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;\n            if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion)\n            {\n                if (pfrom->GetLocalServices() & NODE_SEGSIG)\n                    State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2);\n                else\n                    State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);\n            }\n        }\n        #endif\n    }\n\n\n    else if (strCommand == NetMsgType::INV)\n    {\n        std::vector<CInv> vInv;\n        vRecv >> COMPACTSIZEVECTOR(vInv);\n        if (vInv.size() > MAX_INV_SZ)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 20);\n            return error(\"message inv size() = %u\", vInv.size());\n        }\n\n        bool fBlocksOnly = !fRelayTxes;\n\n        // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true\n        if (pfrom->fWhitelisted && GetBoolArg(\"-whitelistrelay\", DEFAULT_WHITELISTRELAY))\n            fBlocksOnly = false;\n\n        LOCK(cs_main);\n\n        uint32_t nFetchFlags = GetFetchFlags(pfrom);\n\n        for (CInv &inv : vInv)\n        {\n            if (interruptMsgProc)\n                return true;\n\n            bool fAlreadyHave = AlreadyHave(inv);\n            LogPrint(BCLog::NET, \"got inv: %s  %s peer=%d\\n\", inv.ToString(), fAlreadyHave ? \"have\" : \"new\", pfrom->GetId());\n\n            if (inv.type == MSG_TX)\n            {\n                inv.type |= nFetchFlags;\n            }\n\n            if (inv.type == MSG_BLOCK)\n            {\n                UpdateBlockAvailability(pfrom->GetId(), inv.hash);\n                if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash) && !IsInitialBlockDownload())\n                {\n                    // We used to request the full block here, but since headers-announcements are now the\n                    // primary method of announcement on the network, and since, in the case that a node\n                    // fell back to inv we probably have a reorg which we should get the headers for first,\n                    // we now only provide a getheaders response here. When we receive the headers, we will\n                    // then ask for the blocks we need.\n                    connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocatorPoW2(pindexBestHeader), inv.hash));\n                    LogPrint(BCLog::NET, \"getheaders (%d) %s to peer=%d\\n\", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());\n                }\n            }\n            else\n            {\n                pfrom->AddInventoryKnown(inv);\n                if (fBlocksOnly)\n                {\n                    LogPrint(BCLog::NET, \"transaction (%s) inv sent in violation of protocol peer=%d\\n\", inv.hash.ToString(), pfrom->GetId());\n                }\n                else if (!fAlreadyHave && !fImporting && !fReindex && (!IsInitialBlockDownload() || IsPartialSyncActive()))\n                {\n                    pfrom->AskFor(inv);\n                }\n            }\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::GETDATA)\n    {\n        std::vector<CInv> vInv;\n        vRecv >> COMPACTSIZEVECTOR(vInv);\n        if (vInv.size() > MAX_INV_SZ)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 20);\n            return error(\"message getdata size() = %u\", vInv.size());\n        }\n\n        LogPrint(BCLog::NET, \"received getdata (%u invsz) peer=%d\\n\", vInv.size(), pfrom->GetId());\n\n        if (vInv.size() > 0)\n        {\n            LogPrint(BCLog::NET, \"received getdata for: %s peer=%d\\n\", vInv[0].ToString(), pfrom->GetId());\n        }\n\n        pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());\n        ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);\n    }\n\n\n    else if (strCommand == NetMsgType::GETBLOCKS)\n    {\n        CBlockLocator locator;\n        uint256 hashStop;\n        vRecv >> locator >> hashStop;\n\n        // We might have announced the currently-being-connected tip using a\n        // compact block, which resulted in the peer sending a getblocks\n        // request, which we would otherwise respond to without the new block.\n        // To avoid this situation we simply verify that we are on our best\n        // known chain now. This is super overkill, but we handle it better\n        // for getheaders requests, and there are no known nodes which support\n        // compact blocks but still use getblocks to request blocks.\n        {\n            std::shared_ptr<const CBlock> a_recent_block;\n            {\n                LOCK(cs_most_recent_block);\n                a_recent_block = most_recent_block_pow2;\n            }\n            CValidationState dummy;\n            ActivateBestChain(dummy, Params(), a_recent_block);\n        }\n\n        LOCK(cs_main);\n\n        // Find the last block the caller has in the main chain\n        const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);\n\n        // Send the rest of the chain\n        if (pindex)\n            pindex = chainActive.Next(pindex);\n        int nLimit = 500;\n        LogPrint(BCLog::NET, \"getblocks %d to %s limit %d from peer=%d\\n\", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? \"end\" : hashStop.ToString(), nLimit, pfrom->GetId());\n        for (; pindex; pindex = chainActive.Next(pindex))\n        {\n            if (pindex->GetBlockHashPoW2() == hashStop || pindex->GetBlockHashLegacy() == hashStop)\n            {\n                LogPrint(BCLog::NET, \"  getblocks stopping at %d %s\\n\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n                break;\n            }\n            // If pruning, don't inv blocks unless we have on disk and are likely to still have\n            // for some reasonable time window (1 hour) that block relay might require.\n            const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing;\n            if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave))\n            {\n                LogPrint(BCLog::NET, \" getblocks stopping, pruned or too old block at %d %s\\n\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n                break;\n            }\n            pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHashPoW2()));\n\n            if (--nLimit <= 0)\n            {\n                // When this block is requested, we'll send an inv that'll\n                // trigger the peer to getblocks the next batch of inventory.\n                LogPrint(BCLog::NET, \"  getblocks stopping at limit %d %s\\n\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n                pfrom->hashContinue = pindex->GetBlockHashPoW2();\n                break;\n            }\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::GETBLOCKTXN)\n    {\n        BlockTransactionsRequest req;\n        vRecv >> req;\n\n        std::shared_ptr<const CBlock> recent_block;\n        {\n            LOCK(cs_most_recent_block);\n            if (most_recent_block_hash_pow2 == req.blockhash)\n                recent_block = most_recent_block_pow2;\n            // Unlock cs_most_recent_block to avoid cs_main lock inversion\n        }\n        if (recent_block)\n        {\n            SendBlockTransactions(*recent_block, req, pfrom, connman);\n            return true;\n        }\n\n        LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n        BlockMap::iterator it = mapBlockIndex.find(req.blockhash);\n        if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA))\n        {\n            LogPrintf(\"Peer %d sent us a getblocktxn for a block we don't have\", pfrom->GetId());\n            return true;\n        }\n\n        if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH)\n        {\n            // If an older block is requested (should never happen in practice,\n            // but can happen in tests) send a block response instead of a\n            // blocktxn response. Sending a full block response instead of a\n            // small blocktxn response is preferable in the case where a peer\n            // might maliciously send lots of getblocktxn requests to trigger\n            // expensive disk reads, because it will require the peer to\n            // actually receive all the data read from disk over the network.\n            LogPrint(BCLog::NET, \"Peer %d sent us a getblocktxn for a block > %i deep\", pfrom->GetId(), MAX_BLOCKTXN_DEPTH);\n            CInv inv;\n            inv.type = State(pfrom->GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK;\n            inv.hash = req.blockhash;\n            pfrom->vRecvGetData.push_back(inv);\n            ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);\n            return true;\n        }\n\n        CBlock block;\n        bool ret = ReadBlockFromDisk(block, it->second, chainparams);\n\n        //fixme: (POST-PHASE5) (HIGH) (NETWORK) \n        //We were getting an assert here at some point so assert disable and error handling placed instead.\n        //We should look into this again.\n        //assert(ret);\n        if (ret)\n        {\n            SendBlockTransactions(block, req, pfrom, connman);\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::GETHEADERS)\n    {\n        CBlockLocator locator;\n        uint256 hashStop;\n        vRecv >> locator >> hashStop;\n\n        LOCK(cs_main);\n        static bool fRegTest = Params().IsRegtest();\n        static bool fRegTestLegacy = Params().IsRegtestLegacy();\n        if (IsInitialBlockDownload() && !pfrom->fWhitelisted && !fRegTest && !fRegTestLegacy)\n        {\n            LogPrint(BCLog::NET, \"Ignoring getheaders from peer=%d because node is in initial block download\\n\", pfrom->GetId());\n            return true;\n        }\n\n        CNodeState *nodestate = State(pfrom->GetId());\n        const CBlockIndex* pindex = NULL;\n        if (locator.IsNull())\n        {\n            // If locator is null, return the hashStop block\n            BlockMap::iterator mi = mapBlockIndex.find(hashStop);\n            if (mi == mapBlockIndex.end())\n                return true;\n            pindex = (*mi).second;\n        }\n        else\n        {\n            // Find the last block the caller has in the main chain\n            pindex = FindForkInGlobalIndex(chainActive, locator);\n            if (pindex)\n                pindex = chainActive.Next(pindex);\n        }\n\n        // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end\n        std::vector<CBlock> vHeaders;\n        int nLimit = MAX_HEADERS_RESULTS;\n        LogPrint(BCLog::NET, \"getheaders %d to %s from peer=%d\\n\", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? \"end\" : hashStop.ToString(), pfrom->GetId());\n        for (; pindex; pindex = chainActive.Next(pindex))\n        {\n            vHeaders.push_back(pindex->GetBlockHeader());\n            if (--nLimit <= 0 || pindex->GetBlockHashPoW2() == hashStop)\n                break;\n        }\n        // pindex can be NULL either if we sent chainActive.Tip() OR\n        // if our peer has chainActive.Tip() (and thus we are sending an empty\n        // headers message). In both cases it's safe to update\n        // pindexBestHeaderSent to be our tip.\n        //\n        // It is important that we simply reset the BestHeaderSent value here,\n        // and not max(BestHeaderSent, newHeaderSent). We might have announced\n        // the currently-being-connected tip using a compact block, which\n        // resulted in the peer sending a headers request, which we respond to\n        // without the new block. By resetting the BestHeaderSent, we ensure we\n        // will re-announce the new block via headers (or compact blocks again)\n        // in the SendMessages logic.\n        nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();\n        connman.PushMessage(pfrom, (msgMaker).Make(NetMsgType::HEADERS, COMPACTSIZEVECTOR(vHeaders)));\n    }\n\n\n    else if (strCommand == NetMsgType::GETRHEADERS)\n    {\n        uint32_t height, num;\n        vRecv >> height >> num;\n\n        LOCK(cs_main);\n        if (IsInitialBlockDownload() && !pfrom->fWhitelisted && !IsArgSet(\"-regtest\"))\n        {\n            LogPrint(BCLog::NET, \"Ignoring getrheaders from peer=%d because node is in initial block download\\n\", pfrom->GetId());\n            return true;\n        }\n\n        if ((int)height > chainActive.Height())\n        {\n            LogPrint(BCLog::NET, \"getrheaders from peer=%d is requesting an unknown height=%ud\\n\", pfrom->GetId(), height);\n\n            // Misbehaving peer, it should know that all blocks before latest checkpoint are present.\n            // That it how it should decide to start requesting reverse headers in the first place.\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 100);\n            return true;\n        }\n\n        if (num > height)\n        {\n            LogPrint(BCLog::NET, \"getrheaders from peer=%d is requesting blocks before genesis\\n\", pfrom->GetId());\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 100);\n            return true;\n        }\n\n        unsigned int nLimit = std::min(num, MAX_RHEADERS_RESULTS);\n        std::vector<CBlockHeader> vHeaders;\n        vHeaders.reserve(nLimit);\n        LogPrint(BCLog::NET, \"getrheaders height %d num=%d from peer=%d\\n\", height, num, pfrom->GetId());\n\n        for (unsigned int i = height; i > height - nLimit; i--)\n        {\n            vHeaders.push_back(chainActive[i]->GetBlockHeader());\n        }\n\n        connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::RHEADERS, height, COMPACTSIZEVECTOR(vHeaders)));\n    }\n\n    else if (strCommand == NetMsgType::TX)\n    {\n        // Stop processing the transaction early if\n        // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off\n        if (!fRelayTxes && (!pfrom->fWhitelisted || !GetBoolArg(\"-whitelistrelay\", DEFAULT_WHITELISTRELAY)))\n        {\n            LogPrint(BCLog::NET, \"transaction sent in violation of protocol peer=%d\\n\", pfrom->GetId());\n            return true;\n        }\n\n        std::deque<COutPoint> vWorkQueue;\n        std::vector<uint256> vEraseQueue;\n        CTransactionRef ptx;\n        vRecv >> ptx;\n        const CTransaction& tx = *ptx;\n\n        CInv inv(MSG_TX, tx.GetHash());\n        pfrom->AddInventoryKnown(inv);\n\n        LOCK(cs_main);\n\n        bool fMissingInputs = false;\n        CValidationState state;\n\n        pfrom->setAskFor.erase(inv.hash);\n        mapAlreadyAskedFor.erase(inv.hash);\n\n        std::list<CTransactionRef> lRemovedTxn;\n\n        if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs, &lRemovedTxn))\n        {\n            mempool.check(pcoinsTip);\n            RelayTransaction(tx, connman);\n            for (unsigned int i = 0; i < tx.vout.size(); i++)\n            {\n                vWorkQueue.emplace_back(inv.hash, i);\n            }\n\n            pfrom->nLastTXTime = GetTime();\n\n            LogPrint(BCLog::MEMPOOL, \"AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\\n\",\n                pfrom->GetId(),\n                tx.GetHash().ToString(),\n                mempool.size(), mempool.DynamicMemoryUsage() / 1000);\n\n            // Recursively process any orphan transactions that depended on this one\n            std::set<NodeId> setMisbehaving;\n            while (!vWorkQueue.empty())\n            {\n                auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());\n                vWorkQueue.pop_front();\n                if (itByPrev == mapOrphanTransactionsByPrev.end())\n                    continue;\n                for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi)\n                {\n                    const CTransactionRef& porphanTx = (*mi)->second.tx;\n                    const CTransaction& orphanTx = *porphanTx;\n                    const uint256& orphanHash = orphanTx.GetHash();\n                    NodeId fromPeer = (*mi)->second.fromPeer;\n                    bool fMissingInputs2 = false;\n                    // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan\n                    // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get\n                    // anyone relaying LegitTxX banned)\n                    CValidationState stateDummy;\n\n\n                    if (setMisbehaving.count(fromPeer))\n                        continue;\n                    if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2, &lRemovedTxn))\n                    {\n                        LogPrint(BCLog::MEMPOOL, \"   accepted orphan tx %s\\n\", orphanHash.ToString());\n                        RelayTransaction(orphanTx, connman);\n                        for (unsigned int i = 0; i < orphanTx.vout.size(); i++)\n                        {\n                            vWorkQueue.emplace_back(orphanHash, i);\n                        }\n                        vEraseQueue.push_back(orphanHash);\n                    }\n                    else if (!fMissingInputs2)\n                    {\n                        int nDos = 0;\n                        if (stateDummy.IsInvalid(nDos) && nDos > 0)\n                        {\n                            // Punish peer that gave us an invalid orphan tx\n                            Misbehaving(fromPeer, nDos);\n                            setMisbehaving.insert(fromPeer);\n                            LogPrint(BCLog::MEMPOOL, \"   invalid orphan tx %s\\n\", orphanHash.ToString());\n                        }\n                        // Has inputs but not accepted to mempool\n                        // Probably non-standard or insufficient fee\n                        LogPrint(BCLog::MEMPOOL, \"   removed orphan tx %s\\n\", orphanHash.ToString());\n                        vEraseQueue.push_back(orphanHash);\n                        if (!orphanTx.HasSegregatedSignatures() && !stateDummy.CorruptionPossible())\n                        {\n                            // Do not use rejection cache for witness transactions or\n                            // witness-stripped transactions, as they can have been malleated.\n                            // See https://github.com/bitcoin/bitcoin/issues/8279 for details.\n                            assert(recentRejects);\n                            recentRejects->insert(orphanHash);\n                        }\n                    }\n                    mempool.check(pcoinsTip);\n                }\n            }\n\n            for(uint256 hash : vEraseQueue)\n                EraseOrphanTx(hash);\n        }\n        else if (fMissingInputs)\n        {\n            bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected\n            for(const CTxIn& txin : tx.vin)\n            {\n                uint256 txHash;\n                if (GetTxHash(txin.GetPrevOut(), txHash) && recentRejects->contains(txHash))\n                {\n                    fRejectedParents = true;\n                    break;\n                }\n            }\n            if (!fRejectedParents)\n            {\n                uint32_t nFetchFlags = GetFetchFlags(pfrom);\n                for(const CTxIn& txin : tx.vin)\n                {\n                    uint256 txHash;\n                    if (GetTxHash(txin.GetPrevOut(), txHash))\n                    {\n                        CInv _inv(MSG_TX | nFetchFlags, txHash);\n                        pfrom->AddInventoryKnown(_inv);\n                        if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);\n                    }\n                }\n                AddOrphanTx(ptx, pfrom->GetId());\n\n                // DoS prevention: do not allow mapOrphanTransactions to grow unbounded\n                unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg(\"-maxorphantx\", DEFAULT_MAX_ORPHAN_TRANSACTIONS));\n                unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);\n                if (nEvicted > 0)\n                {\n                    LogPrint(BCLog::MEMPOOL, \"mapOrphan overflow, removed %u tx\\n\", nEvicted);\n                }\n            }\n            else\n            {\n                LogPrint(BCLog::MEMPOOL, \"not keeping orphan with rejected parents %s\\n\",tx.GetHash().ToString());\n                // We will continue to reject this tx since it has rejected\n                // parents so avoid re-requesting it from other peers.\n                recentRejects->insert(tx.GetHash());\n            }\n        }\n        else\n        {\n            if (!tx.HasSegregatedSignatures() && !state.CorruptionPossible())\n            {\n                // Do not use rejection cache for witness transactions or\n                // witness-stripped transactions, as they can have been malleated.\n                // See https://github.com/bitcoin/bitcoin/issues/8279 for details.\n                assert(recentRejects);\n                recentRejects->insert(tx.GetHash());\n                if (RecursiveDynamicUsage(*ptx) < 100000)\n                {\n                    AddToCompactExtraTransactions(ptx);\n                }\n            }\n            else if (tx.HasSegregatedSignatures() && RecursiveDynamicUsage(*ptx) < 100000)\n            {\n                AddToCompactExtraTransactions(ptx);\n            }\n\n            if (pfrom->fWhitelisted && GetBoolArg(\"-whitelistforcerelay\", DEFAULT_WHITELISTFORCERELAY))\n            {\n                // Always relay transactions received from whitelisted peers, even\n                // if they were already in the mempool or rejected from it due\n                // to policy, allowing the node to function as a gateway for\n                // nodes hidden behind it.\n                //\n                // Never relay transactions that we would assign a non-zero DoS\n                // score for, as we expect peers to do the same with us in that\n                // case.\n                int nDoS = 0;\n                if (!state.IsInvalid(nDoS) || nDoS == 0)\n                {\n                    LogPrintf(\"Force relaying tx %s from whitelisted peer=%d\\n\", tx.GetHash().ToString(), pfrom->GetId());\n                    RelayTransaction(tx, connman);\n                }\n                else\n                {\n                    LogPrintf(\"Not relaying invalid transaction %s from whitelisted peer=%d (%s)\\n\", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state));\n                }\n            }\n        }\n\n        for (const CTransactionRef& removedTx : lRemovedTxn)\n        {\n            AddToCompactExtraTransactions(removedTx);\n        }\n\n        int nDoS = 0;\n        if (state.IsInvalid(nDoS))\n        {\n            LogPrint(BCLog::MEMPOOLREJ, \"%s from peer=%d was not accepted: %s\\n\", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state));\n            // Never send AcceptToMemoryPool's internal codes over P2P\n            if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL)\n            {\n                connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),\n                                   state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));\n            }\n            if (nDoS > 0)\n            {\n                Misbehaving(pfrom->GetId(), nDoS);\n            }\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing\n    {\n        CBlockHeaderAndShortTxIDs cmpctblock;\n        vRecv >> cmpctblock;\n\n        {\n            LOCK(cs_main);\n\n            if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end())\n            {\n                // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers\n                if (!IsInitialBlockDownload())\n                    connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocatorPoW2(pindexBestHeader), uint256()));\n                return true;\n            }\n        }\n\n        const CBlockIndex *pindex = NULL;\n        CValidationState state;\n        if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex))\n        {\n            int nDoS;\n            if (state.IsInvalid(nDoS))\n            {\n                if (nDoS > 0)\n                {\n                    LOCK(cs_main);\n                    Misbehaving(pfrom->GetId(), nDoS);\n                }\n                LogPrintf(\"Peer %d sent us invalid header via cmpctblock\\n\", pfrom->GetId());\n                return true;\n            }\n            return false;\n        }\n\n        // When we succeed in decoding a block's txids from a cmpctblock\n        // message we typically jump to the BLOCKTXN handling code, with a\n        // dummy (empty) BLOCKTXN message, to re-use the logic there in\n        // completing processing of the putative block (without cs_main).\n        bool fProcessBLOCKTXN = false;\n        CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);\n\n        // If we end up treating this as a plain headers message, call that as well\n        // without cs_main.\n        bool fRevertToHeaderProcessing = false;\n        CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);\n\n        // Keep a CBlock for \"optimistic\" compactblock reconstructions (see\n        // below)\n        std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n        bool fBlockReconstructed = false;\n\n        {\n            LOCK(cs_main);\n            // If AcceptBlockHeader returned true, it set pindex\n            assert(pindex);\n            UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHashPoW2());\n\n            std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHashPoW2());\n            bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();\n\n            if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here\n                return true;\n\n            if ((pindex->nChainWork <= chainActive.Tip()->nChainWork && pindex->nHeight != chainActive.Tip()->nHeight) || // We know something better\n                    pindex->nTx != 0) // We had this block at some point, but pruned it\n            {\n                if (fAlreadyInFlight)\n                {\n                    // We requested this block for some reason, but our mempool will probably be useless\n                    // so we just grab the block via normal getdata\n                    std::vector<CInv> vInv(1);\n                    vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHashPoW2());\n                    connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vInv)));\n                }\n                return true;\n            }\n\n            // If we're not close to tip yet, give up and let parallel block fetch work its magic\n            if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))\n                return true;\n\n            CNodeState *nodestate = State(pfrom->GetId());\n\n            // Don't bother trying to process compact blocks from v1 peers after segsig activates.\n            if (IsSegSigEnabled(pindex->pprev) && !nodestate->fSupportsDesiredCmpctVersion)\n                return true;\n\n            // We want to be a bit conservative just to be extra careful about DoS\n            // possibilities in compact block processing...\n            if (pindex->nHeight <= chainActive.Height() + 2)\n            {\n                if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||\n                    (fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId()))\n                {\n                    std::list<QueuedBlock>::iterator* queuedBlockIt = NULL;\n                    if (!MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHashPoW2(), pindex, &queuedBlockIt))\n                    {\n                        if (!(*queuedBlockIt)->partialBlock)\n                        {\n                            (*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&mempool));\n                        }\n                        else\n                        {\n                            // The block was already in flight using compact blocks from the same peer\n                            LogPrint(BCLog::NET, \"Peer sent us compact block we were already syncing!\\n\");\n                            return true;\n                        }\n                    }\n\n                    PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;\n                    ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);\n                    if (status == READ_STATUS_INVALID)\n                    {\n                        MarkBlockAsReceived(pindex->GetBlockHashPoW2()); // Reset in-flight state in case of whitelist\n                        Misbehaving(pfrom->GetId(), 100);\n                        LogPrintf(\"Peer %d sent us invalid compact block\\n\", pfrom->GetId());\n                        return true;\n                    }\n                    else if (status == READ_STATUS_FAILED)\n                    {\n                        // Duplicate txindexes, the block is now in-flight, so just request it\n                        std::vector<CInv> vInv(1);\n                        vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHashPoW2());\n                        connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vInv)));\n                        return true;\n                    }\n\n                    BlockTransactionsRequest req;\n                    for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++)\n                    {\n                        if (!partialBlock.IsTxAvailable(i))\n                            req.indexes.push_back(i);\n                    }\n                    if (req.indexes.empty())\n                    {\n                        // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)\n                        BlockTransactions txn;\n                        txn.blockhash = cmpctblock.header.GetHashPoW2();\n                        blockTxnMsg << txn;\n                        fProcessBLOCKTXN = true;\n                    }\n                    else\n                    {\n                        req.blockhash = pindex->GetBlockHashPoW2();\n                        connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));\n                    }\n                }\n                else\n                {\n                    // This block is either already in flight from a different\n                    // peer, or this peer has too many blocks outstanding to\n                    // download from.\n                    // Optimistically try to reconstruct anyway since we might be\n                    // able to without any round trips.\n                    PartiallyDownloadedBlock tempBlock(&mempool);\n                    ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);\n                    if (status != READ_STATUS_OK)\n                    {\n                        // TODO: don't ignore failures\n                        return true;\n                    }\n                    std::vector<CTransactionRef> dummy;\n                    status = tempBlock.FillBlock(*pblock, dummy);\n                    if (status == READ_STATUS_OK)\n                    {\n                        fBlockReconstructed = true;\n                    }\n                }\n            }\n            else\n            {\n                if (fAlreadyInFlight)\n                {\n                    // We requested this block, but its far into the future, so our\n                    // mempool will probably be useless - request the block normally\n                    std::vector<CInv> vInv(1);\n                    vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHashPoW2());\n                    connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vInv)));\n                    return true;\n                }\n                else\n                {\n                    // If this was an announce-cmpctblock, we want the same treatment as a header message\n                    // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)\n                    std::vector<CBlock> headers;\n                    headers.push_back(cmpctblock.header);\n                    vHeadersMsg << COMPACTSIZEVECTOR(headers);\n                    fRevertToHeaderProcessing = true;\n                }\n            }\n        }\n\n        if (fProcessBLOCKTXN)\n            return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc);\n\n        if (fRevertToHeaderProcessing)\n            return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc);\n\n        if (fBlockReconstructed)\n        {\n            // If we got here, we were able to optimistically reconstruct a\n            // block that is in flight from some other peer.\n            {\n                LOCK(cs_main);\n                mapBlockSource.emplace(pblock->GetHashPoW2(), std::pair(pfrom->GetId(), false));\n            }\n            bool fNewBlock = false;\n            ProcessNewBlock(chainparams, pblock, true, &fNewBlock, false, true);\n            if (fNewBlock)\n                pfrom->nLastBlockTime = GetTime();\n\n            LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()\n            if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS))\n            {\n                // Clear download state for this block, which is in\n                // process from some other peer.  We do this after calling\n                // ProcessNewBlock so that a malleated cmpctblock announcement\n                // can't be used to interfere with block relay.\n                MarkBlockAsReceived(pblock->GetHashPoW2());\n            }\n        }\n\n    }\n\n    else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing\n    {\n        BlockTransactions resp;\n        vRecv >> resp;\n\n        std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n        bool fBlockRead = false;\n        {\n            LOCK(cs_main);\n\n            std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash);\n            if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock || it->second.first != pfrom->GetId())\n            {\n                LogPrint(BCLog::NET, \"Peer %d sent us block transactions for block we weren't expecting\\n\", pfrom->GetId());\n                return true;\n            }\n\n            PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;\n            ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);\n            if (status == READ_STATUS_INVALID)\n            {\n                MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist\n                Misbehaving(pfrom->GetId(), 100);\n                LogPrintf(\"Peer %d sent us invalid compact block/non-matching block transactions\\n\", pfrom->GetId());\n                return true;\n            }\n            else if (status == READ_STATUS_FAILED)\n            {\n                // Might have collided, fall back to getdata now :(\n                std::vector<CInv> invs;\n                invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));\n                connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(invs)));\n            }\n            else\n            {\n                // Block is either okay, or possibly we received\n                // READ_STATUS_CHECKBLOCK_FAILED.\n                // Note that CheckBlock can only fail for one of a few reasons:\n                // 1. bad-proof-of-work (impossible here, because we've already\n                //    accepted the header)\n                // 2. merkleroot doesn't match the transactions given (already\n                //    caught in FillBlock with READ_STATUS_FAILED, so\n                //    impossible here)\n                // 3. the block is otherwise invalid (eg invalid coinbase,\n                //    block is too big, too many legacy sigops, etc).\n                // So if CheckBlock failed, #3 is the only possibility.\n                // Under BIP 152, we don't DoS-ban unless proof of work is\n                // invalid (we don't require all the stateless checks to have\n                // been run).  This is handled below, so just treat this as\n                // though the block was successfully read, and rely on the\n                // handling in ProcessNewBlock to ensure the block index is\n                // updated, reject messages go out, etc.\n                MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer\n                fBlockRead = true;\n                // mapBlockSource is only used for sending reject messages and DoS scores,\n                // so the race between here and cs_main in ProcessNewBlock is fine.\n                // BIP 152 permits peers to relay compact blocks after validating\n                // the header only; we should not punish peers if the block turns\n                // out to be invalid.\n                mapBlockSource.emplace(resp.blockhash, std::pair(pfrom->GetId(), false));\n            }\n        } // Don't hold cs_main when we call into ProcessNewBlock\n        if (fBlockRead)\n        {\n            bool fNewBlock = false;\n            // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,\n            // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)\n            ProcessNewBlock(chainparams, pblock, true, &fNewBlock, false, true);\n            if (fNewBlock)\n                pfrom->nLastBlockTime = GetTime();\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing\n    {\n        std::vector<CBlockHeader> headers;\n\n        // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.\n        unsigned int nCount = ReadCompactSize(vRecv);\n        if (nCount > MAX_HEADERS_RESULTS)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 20);\n            return error(\"headers message size = %u\", nCount);\n        }\n        headers.resize(nCount);\n        for (unsigned int n = 0; n < nCount; n++)\n        {\n            vRecv >> headers[n];\n            ReadCompactSize(vRecv); // ignore tx count; assume it is 0.\n        }\n\n        if (nCount == 0)\n        {\n            // Nothing interesting. Stop asking this peers for more headers.\n            return true;\n        }\n\n        const CBlockIndex *pindexLast = NULL;\n        {\n            LOCK(cs_main);\n            CNodeState *nodestate = State(pfrom->GetId());\n\n            // If this looks like it could be a block announcement (nCount <\n            // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that\n            // don't connect:\n            // - Send a getheaders message in response to try to connect the chain, but only if header sync is near present.\n            // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that\n            //   don't connect before giving DoS points\n            // - Once a headers message is received that is valid and does connect,\n            //   nUnconnectingHeaders gets reset back to 0.\n            if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE)\n            {\n                nodestate->nUnconnectingHeaders++;\n                CBlockIndex* pindex = pindexBestPartial && pindexBestPartial->nHeight > pindexBestHeader->nHeight\n                        ? pindexBestPartial\n                        : pindexBestHeader;\n                CChain& chain = pindex == pindexBestHeader ? chainActive : partialChain;\n\n                bool headerSyncNearPresent = pindex && GetAdjustedTime() - pindex->GetBlockTime() < 24 * 3600;\n                if (headerSyncNearPresent)\n                {\n                    connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chain.GetLocatorPoW2(pindex), uint256()));\n                    LogPrint(BCLog::NET, \"received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\\n\",\n                            headers[0].GetHashPoW2().ToString(),\n                            headers[0].hashPrevBlock.ToString(),\n                            pindex->nHeight,\n                            pfrom->GetId(), nodestate->nUnconnectingHeaders);\n                }\n\n                // Set hashLastUnknownBlock for this peer, so that if we\n                // eventually get the headers - even from a different peer -\n                // we can use this peer to download.\n                UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHashPoW2());\n\n                if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0)\n                {\n                    Misbehaving(pfrom->GetId(), 20);\n                }\n                return true;\n            }\n\n            // verify that the received headers are continuous, ie. connect\n            uint256 hashLastBlock;\n            for (const CBlockHeader& header : headers)\n            {\n                if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock)\n                {\n                    Misbehaving(pfrom->GetId(), 20);\n                    return error(\"non-continuous headers sequence\");\n                }\n                hashLastBlock = header.GetHashPoW2();\n            }\n\n            // reset header request/response timeout\n            if (nodestate->fPartialSyncStarted)\n                nodestate->nPartialHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n            else if (nodestate->fSyncStarted || nodestate->fRHeadersSyncStarted)\n                nodestate->nHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n        }\n\n\n        CValidationState state;\n        if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast))\n        {\n            int nDoS;\n            if (state.IsInvalid(nDoS))\n            {\n                if (nDoS > 0)\n                {\n                    LOCK(cs_main);\n                    Misbehaving(pfrom->GetId(), nDoS);\n                }\n                return error(\"invalid header received\");\n            }\n            return false;\n        }\n\n        bool notifyAsPartialProgress = isFullSyncMode()\n                ? !chainActive.FindFork(mapBlockIndex.find(headers[0].hashPrevBlock)->second)\n                : true;\n        NotifyHeaderProgress(connman, notifyAsPartialProgress);\n\n        {\n            LOCK(cs_main);\n            CNodeState *nodestate = State(pfrom->GetId());\n            if (nodestate->nUnconnectingHeaders > 0)\n            {\n                LogPrint(BCLog::NET, \"peer=%d: resetting nUnconnectingHeaders (%d -> 0)\\n\", pfrom->GetId(), nodestate->nUnconnectingHeaders);\n            }\n            nodestate->nUnconnectingHeaders = 0;\n\n            assert(pindexLast);\n            UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHashPoW2());\n\n            if (nCount == MAX_HEADERS_RESULTS)\n            {\n                // Headers message had its maximum size; the peer may have more headers.\n\n                // When not in any header sync state bail out and don't ask for more headers\n                if (!nodestate->fSyncStarted && !nodestate->fRHeadersSyncStarted && !nodestate->fPartialSyncStarted)\n                    return true;\n\n                // If there is reverse header sync in progress stop this slow forward header sync,\n                // it is severly slowing down progress. Reverse header sync will go in lock step\n                // with forward header sync. The peer connection is appreciated however and so\n                // the fSyncStarted is reset so header download might start again later from this peer.\n                if (nodestate->fSyncStarted && nRHeaderSyncStarted > 0)\n                {\n                    nodestate->fSyncStarted = false;\n                    nSyncStarted--;\n                    LogPrintf(\"Giving up forward full header sync in favor of reverse headers, peer=%d\\n\", pfrom->GetId());\n                    return true;\n                }\n\n                // If full header sync is active but partial sync is not catched up yet, give up the full header\n                // sync as it will slow down the partial sync (this is a safeguard and should not happen during normal\n                // operation as full header sync is only started when partial sync is near present\n                if (nodestate->fSyncStarted && IsPartialSyncActive() && !IsPartialNearPresent(BLOCK_PARTIAL_TRANSACTIONS))\n                {\n                    nodestate->fSyncStarted = false;\n                    nSyncStarted--;\n                    LogPrintf(\"Giving up forward full header sync to prevent slowing down partial sync, peer=%d\\n\", pfrom->GetId());\n                    return true;\n                }\n\n                // Partial sync got deactivated after the partial header sync was started on this node\n                if (nodestate->fPartialSyncStarted && !IsPartialSyncActive())\n                {\n                    nodestate->fPartialSyncStarted = false;\n                    nPartialSyncStarted--;\n                    LogPrintf(\"Giving up forward partial header sync, peer=%d\\n\", pfrom->GetId());\n                    return true;\n                }\n\n                LogPrint(BCLog::NET, \"more getheaders (%d) to end to peer=%d (startheight:%d)\\n\", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);\n                LOCK(cs_main);\n                bool connectsToPartial = IsPartialSyncActive() && partialChain.FindFork(pindexLast);\n                const CChain& chain = connectsToPartial ? partialChain : chainActive;\n                CBlockLocator locator = chain.GetLocatorPoW2(pindexLast);\n                connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, locator, uint256()));\n\n                // set new header request/response timeout\n                int64_t timeout = GetTimeMicros() + HEADERS_DOWNLOAD_RESPONSE_TIMEOUT;\n                if (nodestate->fPartialSyncStarted)\n                    nodestate->nPartialHeadersSyncTimeout = timeout;\n                else if (nodestate->fSyncStarted || nodestate->fRHeadersSyncStarted)\n                    nodestate->nHeadersSyncTimeout = timeout;\n            }\n\n            bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());\n            // If this set of headers is valid and ends in a block with at least as\n            // much work as our tip, download as much as possible.\n            if (!IsPartialSyncActive() && fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork)\n            {\n                std::vector<const CBlockIndex*> vToFetch;\n                const CBlockIndex *pindexWalk = pindexLast;\n                // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.\n                while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER)\n                {\n                    if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&\n                            !mapBlocksInFlight.count(pindexWalk->GetBlockHashPoW2()) &&\n                            (!IsSegSigEnabled(pindexWalk->pprev) || State(pfrom->GetId())->fHaveSegregatedSignatures))\n                    {\n                        // We don't have this block, and it's not yet in flight.\n                        vToFetch.push_back(pindexWalk);\n                    }\n                    pindexWalk = pindexWalk->pprev;\n                }\n                // If pindexWalk still isn't on our main chain, we're looking at a\n                // very large reorg at a time we think we're close to caught up to\n                // the main chain -- this shouldn't really happen.  Bail out on the\n                // direct fetch and rely on parallel download instead.\n                if (!chainActive.Contains(pindexWalk))\n                {\n                    LogPrint(BCLog::NET, \"Large reorg, won't direct fetch to %s (%d)\\n\",\n                            pindexLast->GetBlockHashPoW2().ToString(),\n                            pindexLast->nHeight);\n                }\n                else\n                {\n                    // Do not request blocks if autorequest is disabled\n                    if (!isFullSyncMode())\n                    {\n                        return true;\n                    }\n                    std::vector<CInv> vGetData;\n                    // Download as much as possible, from earliest to latest.\n                    BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch)\n                    {\n                        if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER)\n                        {\n                            // Can't download any more from this peer\n                            break;\n                        }\n                        uint32_t nFetchFlags = GetFetchFlags(pfrom);\n                        vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHashPoW2()));\n                        MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHashPoW2(), pindex);\n                        LogPrint(BCLog::NET, \"Requesting block %s from  peer=%d\\n\",\n                                pindex->GetBlockHashPoW2().ToString(), pfrom->GetId());\n                    }\n                    if (vGetData.size() > 1)\n                    {\n                        LogPrint(BCLog::NET, \"Downloading blocks toward %s (%d) via headers direct fetch\\n\",\n                                pindexLast->GetBlockHashPoW2().ToString(), pindexLast->nHeight);\n                    }\n                    if (vGetData.size() > 0)\n                    {\n                        if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN))\n                        {\n                            // In any case, we want to download using a compact block, not a regular one\n                            vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);\n                        }\n                        connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vGetData)));\n                    }\n                }\n            }\n        }\n    }\n\n    else if (fReverseHeaders && strCommand == NetMsgType::RHEADERS && !fImporting && !fReindex) // Ignore headers received while importing\n    {\n        LogPrint(BCLog::NET, \"Received reverse headers peer=%d\\n\", pfrom->GetId());\n\n        std::vector<CBlockHeader> headers;\n\n        uint32_t height;\n        vRecv >> height;\n\n        // Get number of headers and check against maximum allowed\n        unsigned int nCount = ReadCompactSize(vRecv);\n        if (nCount > MAX_RHEADERS_RESULTS)\n        {\n            LOCK(cs_main);\n            Misbehaving(pfrom->GetId(), 20);\n            return error(\"rheaders message size = %u\", nCount);\n        }\n\n        // Nothing interesting. Stop asking this peers for more headers.\n        if (nCount == 0)\n        {\n            return true;\n        }\n\n        int nRHeadersConnected = 0;\n        const int lastCheckPointHeight = Checkpoints::LastCheckPointHeight();\n        for (unsigned int n = 0; n < nCount; n++)\n        {\n            CBlockHeader header;\n            vRecv >> header;\n\n            uint256 hash = header.GetHashPoW2();\n            unsigned int expectedHeight = lastCheckPointHeight - vReverseHeaders.size();\n\n            // verify that the header connects\n            if (vReverseHeaders.size()>0 && vReverseHeaders.back().hashPrevBlock != hash)\n            {\n                LogPrint(BCLog::NET, \"Received reverse header does not connect, peer=%d\\n\", pfrom->GetId());\n\n                // if one or more headers have already connected to vReverseHeaders but this header\n                // does not connect then the peer tries to trick us\n                if (nRHeadersConnected>0)\n                {\n                    Misbehaving(pfrom->GetId(), 100);\n                    return error(\"non-continuous reverse headers sequence\");\n                }\n\n                // if it \"just\" doesn't connect there could be incoming rheaders from multiple peers\n                // just ignore these ones, new ones will be requested\n                break;\n            }\n\n            // if a checkpoint exists at the expected height verify it\n            auto it = chainparams.Checkpoints().find(expectedHeight);\n            if (it!=chainparams.Checkpoints().end())\n            {\n                if (hash != it->second.hash)\n                {\n                    LOCK(cs_main);\n                    Misbehaving(pfrom->GetId(), 100);\n                    return error(\"rheaders from %d mismatch checkpoint\", pfrom->GetId());\n                }\n                else\n                {\n                    LogPrint(BCLog::NET, \"Reverse headers passed checkpoint %d, peer=%d\\n\", expectedHeight, pfrom->GetId());\n                }\n            }\n\n            // never process more then lastCheckPointHeight\n            if ((int)vReverseHeaders.size()<lastCheckPointHeight)\n            {\n                // Try to limit the growth of vReverseHeaders\n                if (vReverseHeaders.size() == 0)\n                {\n                    vReverseHeaders.reserve(lastCheckPointHeight + 1000);\n                }\n                vReverseHeaders.push_back(header);\n            }\n\n            nRHeadersConnected++;\n\n        }\n\n        LogPrint(BCLog::NET, \"Processed %d connected reverse headers peer=%d, total %d\\n\", nRHeadersConnected, pfrom->GetId(), vReverseHeaders.size());\n\n        int headerHeight = pindexBestHeader ? pindexBestHeader->nHeight : 0;\n        int headerGap = lastCheckPointHeight - headerHeight - (int)vReverseHeaders.size();\n\n        if (headerGap <= 0)\n        {\n            LogPrintf(\"%s\", \"Reverse headers complete, connecting to tip\\n\");\n\n            std::reverse(std::begin(vReverseHeaders), std::end(vReverseHeaders));\n            CValidationState state;\n            const CBlockIndex *pindexLast = NULL;\n            // ProcessNewBlockHeaders is skipping PoW checking here as passing checkpoint verification\n            // is a stronger validation already. Skipping the PoW check saves a huge amount of CPU time,\n            // each PoW check takes 0.39ms (timed on 1st gen i7).\n            if (!ProcessNewBlockHeaders(vReverseHeaders, state, chainparams, &pindexLast, true))\n            {\n                int nDoS;\n                if (state.IsInvalid(nDoS))\n                {\n                    // If processing the reverse headers fails there is something very wrong as\n                    // all headers have connecting sha hashes and passed the checkpoints.\n                    // Consider aborting here.\n                    vReverseHeaders.clear();\n                    vReverseHeaders.shrink_to_fit();\n                    \n                    //fixme: We need to look into why this is happening so regularly, but in meantime work around it by disabling\n                    // Fall back to regular headers\n                    fReverseHeaders = false;\n\n                    // Blame peer latest reverse headers came from\n                    LOCK(cs_main);\n                    Misbehaving(pfrom->GetId(), 100);\n                    return error(\"Something went very wrong when putting reverse headers into chain, blaming peer=%d!\", pfrom->GetId());\n                }\n                return false;\n            }\n\n            LOCK(cs_main);\n            CNodeState *nodestate = State(pfrom->GetId());\n            if (nodestate->fRHeadersSyncStarted)\n            {\n                nodestate->fRHeadersSyncStarted = false;\n                nRHeaderSyncStarted--;\n            }\n\n            LogPrintf(\"Header height after reverse header sync %s\\n\", pindexBestHeader->nHeight);\n\n            // Reverse headers are only requested from peers that have at least up to the last checkpoint\n            // so we can update the block availability of the current reverse header peer even if\n            // it is not the same as the reverse header peer initally started with\n            UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHashPoW2());\n\n            vReverseHeaders.clear();\n            vReverseHeaders.shrink_to_fit();\n        }\n\n        if (nRHeadersConnected > 0)\n            NotifyHeaderProgress(connman, false);\n\n        // request more reverse headers if there is still a gap between the chain tip and the reverse headers\n        if (headerGap > 0)\n        {\n            LogPrint(BCLog::NET, \"more reverse getrheaders (%d) to peer=%d (startheight:%d)\\n\",\n                     lastCheckPointHeight-(int)vReverseHeaders.size(), pfrom->GetId(), pfrom->nStartingHeight);\n            connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETRHEADERS,\n                                                     uint32_t(lastCheckPointHeight-vReverseHeaders.size()),\n                                                     uint32_t(std::min((unsigned int)headerGap, MAX_RHEADERS_RESULTS))));\n        }\n\n        return true;\n    }\n\n    else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing\n    {\n        std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n        vRecv >> *pblock;\n\n        LogPrint(BCLog::NET, \"received block %s peer=%d\\n\", pblock->GetHashPoW2().ToString(), pfrom->GetId());\n\n        // Process all blocks from whitelisted peers, even if not requested,\n        // unless we're still syncing with the network.\n        // Such an unrequested block may still be processed, subject to the\n        // conditions in AcceptBlock().\n        bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();\n        bool fAssumePOWGood = false;\n        MarkBlockAsReceivedResult result;\n        const uint256 hash(pblock->GetHashPoW2());\n        {\n            LOCK(cs_main);\n            // Also always process if we requested the block explicitly, as we may\n            // need it even though it is not a candidate for a new best tip.\n            result = MarkBlockAsReceived(hash);\n            forceProcessing |= result.fRequested;\n            // mapBlockSource is only used for sending reject messages and DoS scores,\n            // so the race between here and cs_main in ProcessNewBlock is fine.\n            mapBlockSource.emplace(hash, std::pair(pfrom->GetId(), true));\n\n            // Blocks we already know of that pass BLOCK_VALID_TREE don't need PoW checked again (it would checkout fine)\n            auto mi = mapBlockIndex.find(hash);\n            if (mi!=mapBlockIndex.end())\n            {\n                fAssumePOWGood = mi->second->IsValid(BLOCK_VALID_TREE);\n            }\n        }\n        bool fNewBlock = false;\n        ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock, fAssumePOWGood, !result.fPriorityRequest);\n        if (fNewBlock)\n            pfrom->nLastBlockTime = GetTime();\n    }\n\n\n    else if (strCommand == NetMsgType::GETADDR)\n    {\n        // This asymmetric behavior for inbound and outbound connections was introduced\n        // to prevent a fingerprinting attack: an attacker can send specific fake addresses\n        // to users' AddrMan and later request them by sending getaddr messages.\n        // Making nodes which are behind NAT and can only make outgoing connections ignore\n        // the getaddr message mitigates the attack.\n        if (!pfrom->fInbound)\n        {\n            LogPrint(BCLog::NET, \"Ignoring \\\"getaddr\\\" from outbound connection. peer=%d\\n\", pfrom->GetId());\n            return true;\n        }\n\n        // Only send one GetAddr response per connection to reduce resource waste\n        //  and discourage addr stamping of INV announcements.\n        if (pfrom->fSentAddr)\n        {\n            LogPrint(BCLog::NET, \"Ignoring repeated \\\"getaddr\\\". peer=%d\\n\", pfrom->GetId());\n            return true;\n        }\n        pfrom->fSentAddr = true;\n\n        pfrom->vAddrToSend.clear();\n        std::vector<CAddress> vAddr = connman.GetAddresses();\n        FastRandomContext insecure_rand;\n        for(const CAddress &addr : vAddr)\n            pfrom->PushAddress(addr, insecure_rand);\n    }\n\n\n    else if (strCommand == NetMsgType::MEMPOOL)\n    {\n        if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)\n        {\n            LogPrint(BCLog::NET, \"mempool request with bloom filters disabled, disconnect peer=%d\\n\", pfrom->GetId());\n            pfrom->fDisconnect = true;\n            return true;\n        }\n\n        if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)\n        {\n            LogPrint(BCLog::NET, \"mempool request with bandwidth limit reached, disconnect peer=%d\\n\", pfrom->GetId());\n            pfrom->fDisconnect = true;\n            return true;\n        }\n\n        LOCK(pfrom->cs_inventory);\n        pfrom->fSendMempool = true;\n    }\n\n\n    else if (strCommand == NetMsgType::PING)\n    {\n        if (pfrom->nVersion > BIP0031_VERSION)\n        {\n            uint64_t nonce = 0;\n            vRecv >> nonce;\n            // Echo the message back with the nonce. This allows for two useful features:\n            //\n            // 1) A remote node can quickly check if the connection is operational\n            // 2) Remote nodes can measure the latency of the network thread. If this node\n            //    is overloaded it won't respond to pings quickly and the remote node can\n            //    avoid sending us more work, like chain download requests.\n            //\n            // The nonce stops the remote getting confused between different pings: without\n            // it, if the remote node sends a ping once per second and this node takes 5\n            // seconds to respond to each, the 5th ping the remote sends would appear to\n            // return very quickly.\n            connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::PONG)\n    {\n        int64_t pingUsecEnd = nTimeReceived;\n        uint64_t nonce = 0;\n        size_t nAvail = vRecv.in_avail();\n        bool bPingFinished = false;\n        std::string sProblem;\n\n        if (nAvail >= sizeof(nonce))\n        {\n            vRecv >> nonce;\n\n            // Only process pong message if there is an outstanding ping (old ping without nonce should never pong)\n            if (pfrom->nPingNonceSent != 0)\n            {\n                if (nonce == pfrom->nPingNonceSent)\n                {\n                    // Matching pong received, this ping is no longer outstanding\n                    bPingFinished = true;\n                    int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;\n                    if (pingUsecTime > 0)\n                    {\n                        // Successful ping time measurement, replace previous\n                        pfrom->nPingUsecTime = pingUsecTime;\n                        pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);\n                    }\n                    else\n                    {\n                        // This should never happen\n                        sProblem = \"Timing mishap\";\n                    }\n                }\n                else\n                {\n                    // Nonce mismatches are normal when pings are overlapping\n                    sProblem = \"Nonce mismatch\";\n                    if (nonce == 0)\n                    {\n                        // This is most likely a bug in another implementation somewhere; cancel this ping\n                        bPingFinished = true;\n                        sProblem = \"Nonce zero\";\n                    }\n                }\n            }\n            else\n            {\n                sProblem = \"Unsolicited pong without ping\";\n            }\n        }\n        else\n        {\n            // This is most likely a bug in another implementation somewhere; cancel this ping\n            bPingFinished = true;\n            sProblem = \"Short payload\";\n        }\n\n        if (!(sProblem.empty()))\n        {\n            LogPrint(BCLog::NET, \"pong peer=%d: %s, %x expected, %x received, %u bytes\\n\",\n                pfrom->GetId(),\n                sProblem,\n                pfrom->nPingNonceSent,\n                nonce,\n                nAvail);\n        }\n        if (bPingFinished)\n        {\n            pfrom->nPingNonceSent = 0;\n        }\n    }\n\n\n    else if (strCommand == NetMsgType::FILTERLOAD)\n    {\n        //fixme: (PHASE5) Remove.\n        //Do nothing for now, bloom filters deprecated.\n    }\n\n\n    else if (strCommand == NetMsgType::FILTERADD)\n    {\n        //fixme: (PHASE5) Remove.\n        //Do nothing for now, bloom filters deprecated.\n    }\n\n\n    else if (strCommand == NetMsgType::FILTERCLEAR)\n    {\n        //fixme: (PHASE5) Remove.\n        //Do nothing for now, bloom filters deprecated.\n    }\n\n    else if (strCommand == NetMsgType::FEEFILTER)\n    {\n        CAmount newFeeFilter = 0;\n        vRecv >> newFeeFilter;\n        if (MoneyRange(newFeeFilter))\n        {\n            {\n                LOCK(pfrom->cs_feeFilter);\n                pfrom->minFeeFilter = newFeeFilter;\n            }\n            LogPrint(BCLog::NET, \"received: feefilter of %s from peer=%d\\n\", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());\n        }\n    }\n\n    else if (strCommand == NetMsgType::NOTFOUND)\n    {\n        // We do not care about the NOTFOUND message, but logging an Unknown Command\n        // message would be undesirable as we transmit it ourselves.\n    }\n\n    else\n    {\n        // Ignore unknown commands for extensibility\n        LogPrint(BCLog::NET, \"Unknown command \\\"%s\\\" from peer=%d\\n\", SanitizeString(strCommand), pfrom->GetId());\n    }\n\n\n\n    return true;\n}\n\nstatic bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman& connman)\n{\n    AssertLockHeld(cs_main);\n    CNodeState &state = *State(pnode->GetId());\n\n    for(const CBlockReject& reject : state.rejects)\n    {\n        connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));\n    }\n    state.rejects.clear();\n\n    if (state.fShouldBan)\n    {\n        state.fShouldBan = false;\n        if (pnode->fWhitelisted)\n        {\n            LogPrintf(\"Warning: not punishing whitelisted peer %s!\\n\", pnode->addr.ToString());\n        }\n        else if (pnode->fAddnode)\n        {\n            LogPrintf(\"Warning: not punishing addnoded peer %s!\\n\", pnode->addr.ToString());\n        }\n        else\n        {\n            pnode->fDisconnect = true;\n            if (pnode->addr.IsLocal())\n            {\n                LogPrintf(\"Warning: not banning local peer %s!\\n\", pnode->addr.ToString());\n            }\n            else\n            {\n                connman.Ban(pnode->addr, BanReasonNodeMisbehaving);\n            }\n        }\n        return true;\n    }\n    return false;\n}\n\nbool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interruptMsgProc)\n{\n    const CChainParams& chainparams = Params();\n    //\n    // Message format\n    //  (4) message start\n    //  (12) command\n    //  (4) size\n    //  (4) checksum\n    //  (x) data\n    //\n    bool fMoreWork = false;\n\n    if (!pfrom->vRecvGetData.empty())\n        ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);\n\n    if (pfrom->fDisconnect)\n        return false;\n\n    // this maintains the order of responses\n    if (!pfrom->vRecvGetData.empty()) return true;\n\n    // Don't bother if send buffer is too full to respond anyway\n    if (pfrom->fPauseSend)\n        return false;\n\n    std::list<CNetMessage> msgs;\n    {\n        LOCK(pfrom->cs_vProcessMsg);\n        if (pfrom->vProcessMsg.empty())\n            return false;\n        // Just take one message\n        msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());\n        pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;\n        bool prev_fPauseRecv = pfrom->fPauseRecv;\n        pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize();\n        if (!pfrom->fPauseRecv && prev_fPauseRecv)\n        {\n            connman.ResumeReceive(pfrom);\n        }\n        fMoreWork = !pfrom->vProcessMsg.empty();\n    }\n    CNetMessage& msg(msgs.front());\n\n    msg.SetVersion(pfrom->GetRecvVersion());\n    // Scan for message start\n    if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0)\n    {\n        LogPrintf(\"PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\\n\", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());\n        pfrom->fDisconnect = true;\n        return false;\n    }\n\n    // Read header\n    CMessageHeader& hdr = msg.hdr;\n    if (!hdr.IsValid(chainparams.MessageStart()))\n    {\n        LogPrintf(\"PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\\n\", SanitizeString(hdr.GetCommand()), pfrom->GetId());\n        return fMoreWork;\n    }\n    std::string strCommand = hdr.GetCommand();\n\n    // Message size\n    unsigned int nMessageSize = hdr.nMessageSize;\n\n    // Checksum\n    CDataStream& vRecv = msg.vRecv;\n    const uint256& hash = msg.GetMessageHash();\n    if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)\n    {\n        LogPrintf(\"%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\\n\", __func__,\n           SanitizeString(strCommand), nMessageSize,\n           HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),\n           HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));\n        return fMoreWork;\n    }\n\n    // Process message\n    bool fRet = false;\n    try\n    {\n        fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc);\n        if (interruptMsgProc)\n            return false;\n        if (!pfrom->vRecvGetData.empty())\n            fMoreWork = true;\n    }\n    catch (const std::ios_base::failure& e)\n    {\n        connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string(\"error parsing message\")));\n        if (strstr(e.what(), \"end of data\"))\n        {\n            // Allow exceptions from under-length message on vRecv\n            LogPrintf(\"%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\\n\", __func__, SanitizeString(strCommand), nMessageSize, e.what());\n        }\n        else if (strstr(e.what(), \"size too large\"))\n        {\n            // Allow exceptions from over-long size\n            LogPrintf(\"%s(%s, %u bytes): Exception '%s' caught\\n\", __func__, SanitizeString(strCommand), nMessageSize, e.what());\n        }\n        else if (strstr(e.what(), \"non-canonical ReadCompactSize()\"))\n        {\n            // Allow exceptions from non-canonical encoding\n            LogPrintf(\"%s(%s, %u bytes): Exception '%s' caught\\n\", __func__, SanitizeString(strCommand), nMessageSize, e.what());\n        }\n        else\n        {\n            PrintExceptionContinue(&e, \"ProcessMessages()\");\n        }\n    }\n    catch (const std::exception& e)\n    {\n        PrintExceptionContinue(&e, \"ProcessMessages()\");\n    }\n    catch (...)\n    {\n        PrintExceptionContinue(NULL, \"ProcessMessages()\");\n    }\n\n    if (!fRet)\n    {\n        if (!gbMinimalLogging || strCommand != NetMsgType::VERSION)\n            LogPrintf(\"%s(%s, %u bytes) FAILED peer=%d\\n\", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());\n    }\n\n    // msg might have fullfilled priority request(s), deliver it\n    ProcessPriorityRequests();\n\n    LOCK(cs_main);\n    SendRejectsAndCheckIfBanned(pfrom, connman);\n\n    return fMoreWork;\n}\n\nclass CompareInvMempoolOrder\n{\n    CTxMemPool *mp;\npublic:\n    CompareInvMempoolOrder(CTxMemPool *_mempool)\n    {\n        mp = _mempool;\n    }\n\n    bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)\n    {\n        /* As std::make_heap produces a max-heap, we want the entries with the\n         * fewest ancestors/highest fee to sort later. */\n        return mp->CompareDepthAndScore(*b, *a);\n    }\n};\n\nbool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interruptMsgProc)\n{\n    const Consensus::Params& consensusParams = Params().GetConsensus();\n    {\n        // Don't send anything until the version handshake is complete\n        if (!pto->fSuccessfullyConnected || pto->fDisconnect)\n            return true;\n\n        // If we get here, the outgoing message serialization version is set and can't change.\n        const CNetMsgMaker msgMaker(pto->GetSendVersion());\n\n        //\n        // Message: ping\n        //\n        bool pingSend = false;\n        if (pto->fPingQueued)\n        {\n            // RPC ping request by user\n            pingSend = true;\n        }\n        if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros())\n        {\n            // Ping automatically sent as a latency probe & keepalive.\n            pingSend = true;\n        }\n        if (pingSend)\n        {\n            uint64_t nonce = 0;\n            while (nonce == 0)\n            {\n                GetRandBytes((unsigned char*)&nonce, sizeof(nonce));\n            }\n            pto->fPingQueued = false;\n            pto->nPingUsecStart = GetTimeMicros();\n            if (pto->nVersion > BIP0031_VERSION)\n            {\n                pto->nPingNonceSent = nonce;\n                connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));\n            }\n            else\n            {\n                // Peer is too old to support ping command with nonce, pong will never arrive.\n                pto->nPingNonceSent = 0;\n                connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING));\n            }\n        }\n\n        TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState()\n        if (!lockMain)\n            return true;\n\n        if (SendRejectsAndCheckIfBanned(pto, connman))\n            return true;\n        CNodeState &state = *State(pto->GetId());\n\n        // Address refresh broadcast\n        int64_t nNow = GetTimeMicros();\n        if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow)\n        {\n            AdvertiseLocal(pto);\n            pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);\n        }\n\n        //\n        // Message: addr\n        //\n        if (pto->nNextAddrSend < nNow)\n        {\n            pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);\n            std::vector<CAddress> vAddr;\n            vAddr.reserve(pto->vAddrToSend.size());\n            for(const CAddress& addr : pto->vAddrToSend)\n            {\n                if (!pto->addrKnown.contains(addr.GetKey()))\n                {\n                    pto->addrKnown.insert(addr.GetKey());\n                    vAddr.push_back(addr);\n                    // receiver rejects addr messages larger than 1000\n                    if (vAddr.size() >= 1000)\n                    {\n                        connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, COMPACTSIZEVECTOR(vAddr)));\n                        vAddr.clear();\n                    }\n                }\n            }\n            pto->vAddrToSend.clear();\n            if (!vAddr.empty())\n                connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, COMPACTSIZEVECTOR(vAddr)));\n            // we only send the big addr message once\n            if (pto->vAddrToSend.capacity() > 40)\n                pto->vAddrToSend.shrink_to_fit();\n        }\n\n        // Reset partial header sync (occurs when partial sync is deactivated)\n        if (!IsPartialSyncActive() && state.fPartialSyncStarted)\n        {\n            state.fPartialSyncStarted = false;\n            nPartialSyncStarted--;\n        }\n\n        // Start sync\n        if (pindexBestHeader == NULL)\n            pindexBestHeader = chainActive.Tip();\n\n        // Download if this is a nice peer, or we have no nice peers and this one might do.\n        // Don't download from peers that are behind a lot and have not even made it to the last checkpoint\n        bool fFetch =    pto->nStartingHeight >= Checkpoints::LastCheckPointHeight()\n                      && (state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot));\n\n        // Partial header sync\n        if (fFetch && !state.fPartialSyncStarted && nPartialSyncStarted == 0 && IsPartialSyncActive() &&  !pto->fClient && !fImporting && !fReindex)\n        {\n            state.fPartialSyncStarted = true;\n            nPartialSyncStarted++;\n\n            // set header request/response timeout, but not when chain near present as there might not be new headers to expect\n            if (!IsPartialNearPresent())\n                state.nPartialHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_RESPONSE_TIMEOUT;\n\n            connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, partialChain.GetLocatorPoW2(pindexBestPartial), uint256()));\n        }\n\n        // Full header sync\n        if (   isFullSyncMode()\n            && ((!IsPartialSyncActive() || IsPartialNearPresent(BLOCK_PARTIAL_TRANSACTIONS))\n            && !state.fSyncStarted && !state.fRHeadersSyncStarted\n            && !pto->fClient && !fImporting && !fReindex))\n        {\n            int lastCheckPointHeight = Checkpoints::LastCheckPointHeight();\n            // Reverse header sync if possible\n            if (fReverseHeaders && pto->nVersion >= REVERSEHEADERS_VERSION && nRHeaderSyncStarted == 0 && fFetch\n                    && pto->nStartingHeight > lastCheckPointHeight\n                    && pindexBestHeader->nHeight < lastCheckPointHeight - (int)vReverseHeaders.size())\n            {\n\n                state.fRHeadersSyncStarted = true;\n                nRHeaderSyncStarted++;\n\n                // set header request/response timeout, always as for reverse headers sure to expect a response\n                if (pindexBestHeader->GetBlockTime() < GetAdjustedTime() - 24 * 60 * 60)\n                    state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_RESPONSE_TIMEOUT;\n\n                LogPrintf(\"initial reverse getrheaders (%d) to peer=%d (startheight:%d)\\n\", lastCheckPointHeight - vReverseHeaders.size(),\n                         pto->GetId(), pto->nStartingHeight);\n\n                int headerGap = lastCheckPointHeight - pindexBestHeader->nHeight - (int)vReverseHeaders.size();\n\n                connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETRHEADERS,\n                                                       uint32_t(lastCheckPointHeight-vReverseHeaders.size()),\n                                                       uint32_t(std::min((unsigned int)headerGap, MAX_RHEADERS_RESULTS))));\n            }\n            // fallback to old (forward) header sync\n            // Only actively request headers from a single peer, unless we're close to today.\n            else if ((nRHeaderSyncStarted == 0 && nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60)\n            {\n                state.fSyncStarted = true;\n\n                // set header request/response timeout, but not when close to today (headers will be requested from all peers so a single one not\n                // giving a response is ok)\n                if (pindexBestHeader->GetBlockTime() < GetAdjustedTime() - 24 * 60 * 60)\n                    state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_RESPONSE_TIMEOUT;\n\n                nSyncStarted++;\n                const CBlockIndex *pindexStart = pindexBestHeader;\n                /* If possible, start at the block preceding the currently\n                   best known header.  This ensures that we always get a\n                   non-empty list of headers back as long as the peer\n                   is up-to-date.  With a non-empty response, we can initialise\n                   the peer's known best block.  This wouldn't be possible\n                   if we requested starting at pindexBestHeader and\n                   got back an empty response.  */\n                if (pindexStart->pprev)\n                    pindexStart = pindexStart->pprev;\n                LogPrintf(\"initial getheaders (%d) to peer=%d (startheight:%d)\\n\", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);\n                connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocatorPoW2(pindexStart), uint256()));\n            }\n        }\n\n        // Resend wallet transactions that haven't gotten in a block yet\n        // Except during reindex, importing and IBD, when old wallet\n        // transactions become unconfirmed and spams other nodes.\n        if (!fReindex && !fImporting && !IsInitialBlockDownload())\n        {\n            GetMainSignals().Broadcast(nTimeBestReceived, &connman);\n        }\n\n        //\n        // Try sending block announcements via headers\n        //\n        {\n            // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our\n            // list of block hashes we're relaying, and our peer wants\n            // headers announcements, then find the first header\n            // not yet known to our peer but would connect, and send.\n            // If no header would connect, or if we have too many\n            // blocks, or if the peer doesn't want headers, just\n            // add all to the inv queue.\n            LOCK(pto->cs_inventory);\n            std::vector<CBlock> vHeaders;\n            bool fRevertToInv = ((!state.fPreferHeaders &&\n                                 (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||\n                                pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);\n            const CBlockIndex *pBestIndex = NULL; // last header queued for delivery\n            ProcessBlockAvailability(pto->GetId()); // ensure pindexBestKnownBlock is up-to-date\n\n            if (!fRevertToInv)\n            {\n                bool fFoundStartingHeader = false;\n                // Try to find first header that our peer doesn't have, and\n                // then send all headers past that one.  If we come across any\n                // headers that aren't on chainActive, give up.\n                for(const uint256 &hash : pto->vBlockHashesToAnnounce)\n                {\n                    BlockMap::iterator mi = mapBlockIndex.find(hash);\n                    assert(mi != mapBlockIndex.end());\n                    const CBlockIndex *pindex = mi->second;\n                    if (chainActive[pindex->nHeight] != pindex)\n                    {\n                        // Bail out if we reorged away from this block\n                        fRevertToInv = true;\n                        break;\n                    }\n                    if (pBestIndex != NULL && pindex->pprev != pBestIndex)\n                    {\n                        // This means that the list of blocks to announce don't\n                        // connect to each other.\n                        // This shouldn't really be possible to hit during\n                        // regular operation (because reorgs should take us to\n                        // a chain that has some block not on the prior chain,\n                        // which should be caught by the prior check), but one\n                        // way this could happen is by using invalidateblock /\n                        // reconsiderblock repeatedly on the tip, causing it to\n                        // be added multiple times to vBlockHashesToAnnounce.\n                        // Robustly deal with this rare situation by reverting\n                        // to an inv.\n                        fRevertToInv = true;\n                        break;\n                    }\n                    pBestIndex = pindex;\n                    if (fFoundStartingHeader)\n                    {\n                        // add this to the headers message\n                        vHeaders.push_back(pindex->GetBlockHeader());\n                    }\n                    else if (PeerHasHeader(&state, pindex))\n                    {\n                        continue; // keep looking for the first new block\n                    }\n                    else if (pindex->pprev == NULL || PeerHasHeader(&state, pindex->pprev))\n                    {\n                        // Peer doesn't have this header but they do have the prior one.\n                        // Start sending headers.\n                        fFoundStartingHeader = true;\n                        vHeaders.push_back(pindex->GetBlockHeader());\n                    }\n                    else\n                    {\n                        // Peer doesn't have this header or the prior one -- nothing will\n                        // connect, so bail out.\n                        fRevertToInv = true;\n                        break;\n                    }\n                }\n            }\n            if (!fRevertToInv && !vHeaders.empty())\n            {\n                if (vHeaders.size() == 1 && state.fPreferHeaderAndIDs)\n                {\n                    // We only send up to 1 block as header-and-ids, as otherwise\n                    // probably means we're doing an initial-ish-sync or they're slow\n                    LogPrint(BCLog::NET, \"%s sending header-and-ids %s to peer=%d\\n\", __func__,\n                            vHeaders.front().GetHashPoW2().ToString(), pto->GetId());\n\n                    int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES;\n\n                    bool fGotBlockFromCache = false;\n                    {\n                        LOCK(cs_most_recent_block);\n                        if (most_recent_block_hash_pow == pBestIndex->GetBlockHashLegacy())\n                        {\n                            if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)\n                            {\n                                connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block_pow));\n                            }\n                            else\n                            {\n                                CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block_pow, state.fWantsCmpctWitness);\n                                connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));\n                            }\n                            fGotBlockFromCache = true;\n                        }\n                        else if (most_recent_block_hash_pow2 == pBestIndex->GetBlockHashPoW2())\n                        {\n                            if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)\n                            {\n                                connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block_pow2));\n                            }\n                            else\n                            {\n                                CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block_pow2, state.fWantsCmpctWitness);\n                                connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));\n                            }\n                            fGotBlockFromCache = true;\n                        }\n                    }\n                    if (!fGotBlockFromCache)\n                    {\n                        CBlock block;\n                        bool ret = ReadBlockFromDisk(block, pBestIndex, Params());\n                        assert(ret);\n                        CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);\n                        connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));\n                    }\n                    state.pindexBestHeaderSent = pBestIndex;\n                }\n                else if (state.fPreferHeaders)\n                {\n                    if (vHeaders.size() > 1)\n                    {\n                        LogPrint(BCLog::NET, \"%s: %u headers, range (%s, %s), to peer=%d\\n\", __func__,\n                                vHeaders.size(),\n                                vHeaders.front().GetHashLegacy().ToString(),\n                                vHeaders.back().GetHashLegacy().ToString(), pto->GetId());\n                    }\n                    else\n                    {\n                        LogPrint(BCLog::NET, \"%s: sending header %s to peer=%d\\n\", __func__,\n                                vHeaders.front().GetHashLegacy().ToString(), pto->GetId());\n                    }\n                    connman.PushMessage(pto, (msgMaker).Make(NetMsgType::HEADERS, COMPACTSIZEVECTOR(vHeaders)));\n                    state.pindexBestHeaderSent = pBestIndex;\n                }\n                else\n                {\n                    fRevertToInv = true;\n                }\n            }\n            if (fRevertToInv)\n            {\n                // If falling back to using an inv, just try to inv the tip.\n                // The last entry in vBlockHashesToAnnounce was our tip at some point\n                // in the past.\n                if (!pto->vBlockHashesToAnnounce.empty())\n                {\n                    const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();\n                    BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce);\n                    assert(mi != mapBlockIndex.end());\n                    const CBlockIndex *pindex = mi->second;\n\n                    // Warn if we're announcing a block that is not on the main chain.\n                    // This should be very rare and could be optimized out.\n                    // Just log for now.\n                    if (chainActive[pindex->nHeight] != pindex)\n                    {\n                        LogPrint(BCLog::NET, \"Announcing block %s not on main chain (tip=%s)\\n\",\n                            hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHashPoW2().ToString());\n                    }\n\n                    // If the peer's chain has this block, don't inv it back.\n                    if (!PeerHasHeader(&state, pindex))\n                    {\n                        pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce));\n                        LogPrint(BCLog::NET, \"%s: sending inv peer=%d hash=%s\\n\", __func__,\n                            pto->GetId(), hashToAnnounce.ToString());\n                    }\n                }\n            }\n            pto->vBlockHashesToAnnounce.clear();\n        }\n\n        //\n        // Message: inventory\n        //\n        std::vector<CInv> vInv;\n        {\n            LOCK(pto->cs_inventory);\n            vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));\n\n            // Add blocks\n            for(const uint256& hash : pto->vInventoryBlockToSend)\n            {\n                vInv.push_back(CInv(MSG_BLOCK, hash));\n                if (vInv.size() == MAX_INV_SZ)\n                {\n                    connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, COMPACTSIZEVECTOR(vInv)));\n                    vInv.clear();\n                }\n            }\n            pto->vInventoryBlockToSend.clear();\n\n            // Check whether periodic sends should happen\n            bool fSendTrickle = pto->fWhitelisted || IsPartialSyncActive();\n            if (pto->nNextInvSend < nNow)\n            {\n                fSendTrickle = true;\n                // Use half the delay for outbound peers, as there is less privacy concern for them.\n                pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);\n            }\n\n            // Time to send but the peer has requested we not relay transactions.\n            if (fSendTrickle)\n            {\n                if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();\n            }\n\n            // Respond to BIP35 mempool requests\n            if (fSendTrickle && pto->fSendMempool)\n            {\n                pto->fSendMempool = false;\n                SendMempool(pto);\n                pto->timeLastMempoolReq = GetTime();\n            }\n\n            // Determine transactions to relay\n            if (fSendTrickle)\n            {\n                // Produce a vector with all candidates for sending\n                std::vector<std::set<uint256>::iterator> vInvTx;\n                vInvTx.reserve(pto->setInventoryTxToSend.size());\n                for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++)\n                {\n                    vInvTx.push_back(it);\n                }\n                CAmount filterrate = 0;\n                {\n                    LOCK(pto->cs_feeFilter);\n                    filterrate = pto->minFeeFilter;\n                }\n                // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.\n                // A heap is used so that not all items need sorting if only a few are being sent.\n                CompareInvMempoolOrder compareInvMempoolOrder(&mempool);\n                std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);\n                // No reason to drain out at many times the network's capacity,\n                // especially since we have many peers and some will draw much shorter delays.\n                unsigned int nRelayedTransactions = 0;\n                LOCK(mempool.cs);\n                while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX)\n                {\n                    // Fetch the top element from the heap\n                    std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);\n                    std::set<uint256>::iterator it = vInvTx.back();\n                    vInvTx.pop_back();\n                    uint256 hash = *it;\n                    // Remove it from the to-be-sent set\n                    pto->setInventoryTxToSend.erase(it);\n                    // Check if not in the filter already\n                    if (pto->filterInventoryKnown.contains(hash))\n                    {\n                        continue;\n                    }\n                    // Not in the mempool anymore? don't bother sending it.\n                    auto txinfo = mempool.info(hash);\n                    if (!txinfo.tx)\n                    {\n                        continue;\n                    }\n                    // the feeperkb != 0 is a hack to ensure that entries going into the mempool\n                    // while in pure partial sync are always send out\n                    if (   (filterrate && txinfo.feeRate.GetFeePerK() < filterrate)\n                        && txinfo.feeRate.GetFeePerK() != 0)\n                    {\n                        continue;\n                    }\n                    // Send\n                    vInv.push_back(CInv(MSG_TX, hash));\n                    nRelayedTransactions++;\n                    {\n                        // Expire old relay messages\n                        while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)\n                        {\n                            mapRelay.erase(vRelayExpiration.front().second);\n                            vRelayExpiration.pop_front();\n                        }\n\n                        auto ret = mapRelay.insert(std::pair(hash, std::move(txinfo.tx)));\n                        if (ret.second)\n                        {\n                            vRelayExpiration.push_back(std::pair(nNow + 15 * 60 * 1000000, ret.first));\n                        }\n                    }\n                    if (vInv.size() == MAX_INV_SZ)\n                    {\n                        connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, COMPACTSIZEVECTOR(vInv)));\n                        vInv.clear();\n                    }\n                    pto->filterInventoryKnown.insert(hash);\n                }\n            }\n        }\n        if (!vInv.empty())\n            connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, COMPACTSIZEVECTOR(vInv)));\n\n        // Detect whether we're stalling\n        nNow = GetTimeMicros();\n        if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT)\n        {\n            // Stalling only triggers when the block download window cannot move. During normal steady state,\n            // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection\n            // should only happen during initial block download.\n            LogPrintf(\"Peer=%d is stalling block download, disconnecting\\n\", pto->GetId());\n            pto->fDisconnect = true;\n            return true;\n        }\n        // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval\n        // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.\n        // We compensate for other peers to prevent killing off peers due to our own downstream link\n        // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes\n        // to unreasonably increase our timeout.\n        if (state.vBlocksInFlight.size() > 0)\n        {\n            QueuedBlock &queuedBlock = state.vBlocksInFlight.front();\n            int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0);\n            int nTimeInterval = consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads);\n            //Allow at least 20 seconds for e.g testnet (which has fast block intervals)\n            if (nNow > state.nDownloadingSince + std::max(20000000, nTimeInterval))\n            {\n                LogPrintf(\"Timeout downloading block %s from peer=%d, disconnecting\\n\", queuedBlock.hash.ToString(), pto->GetId());\n                pto->fDisconnect = true;\n                return true;\n            }\n        }\n\n        // Check partial sync header request/response timeout\n        if (state.fPartialSyncStarted && state.nPartialHeadersSyncTimeout < std::numeric_limits<int64_t>::max() && nNow > state.nPartialHeadersSyncTimeout)\n        {\n            LogPrintf(\"Timeout downloading headers from peer=%d, disconnecting\\n\", pto->GetId());\n            pto->fDisconnect = true;\n            state.nPartialHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n            return true;\n        }\n\n        // Check normal sync header request/response timeout\n        if ((state.fSyncStarted || state.fRHeadersSyncStarted) && state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max() && nNow > state.nHeadersSyncTimeout)\n        {\n            LogPrintf(\"Timeout downloading headers from peer=%d, disconnecting\\n\", pto->GetId());\n            pto->fDisconnect = true;\n            state.nHeadersSyncTimeout = std::numeric_limits<int64_t>::max();\n            return true;\n        }\n\n        //\n        // Message: getdata (blocks)\n        //\n        std::vector<CInv> vGetData;\n        if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER)\n        {\n            std::vector<const CBlockIndex*> vToDownload;\n            NodeId staller = -1;\n            bool priorityRequest = FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);\n            for (const CBlockIndex *pindex : vToDownload)\n            {\n                uint32_t nFetchFlags = GetFetchFlags(pto);\n                vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHashPoW2()));\n                MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHashPoW2(), pindex, NULL, priorityRequest);\n                LogPrint(BCLog::NET, \"Requesting%s block %s (%d) peer=%d\\n\", (priorityRequest ? \" (priority)\" : \" \"), pindex->GetBlockHashPoW2().ToString(),\n                    pindex->nHeight, pto->GetId());\n            }\n            if (state.nBlocksInFlight == 0 && staller != -1)\n            {\n                if (State(staller)->nStallingSince == 0)\n                {\n                    State(staller)->nStallingSince = nNow;\n                    LogPrint(BCLog::NET, \"Stall started peer=%d\\n\", staller);\n                }\n            }\n        }\n\n        //\n        // Message: getdata (non-blocks)\n        //\n        while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)\n        {\n            const CInv& inv = (*pto->mapAskFor.begin()).second;\n            if (!AlreadyHave(inv))\n            {\n                LogPrint(BCLog::NET, \"Requesting %s peer=%d\\n\", inv.ToString(), pto->GetId());\n                vGetData.push_back(inv);\n                if (vGetData.size() >= 1000)\n                {\n                    connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vGetData)));\n                    vGetData.clear();\n                }\n            }\n            else\n            {\n                //If we're not going to ask, don't expect a response.\n                pto->setAskFor.erase(inv.hash);\n            }\n            pto->mapAskFor.erase(pto->mapAskFor.begin());\n        }\n        if (!vGetData.empty())\n            connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, COMPACTSIZEVECTOR(vGetData)));\n\n        //\n        // Message: feefilter\n        //\n        // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay\n        if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg(\"-feefilter\", DEFAULT_FEEFILTER) &&\n            !(pto->fWhitelisted && GetBoolArg(\"-whitelistforcerelay\", DEFAULT_WHITELISTFORCERELAY)))\n        {\n            CAmount currentFilter = mempool.GetMinFee(GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();\n            int64_t timeNow = GetTimeMicros();\n            if (timeNow > pto->nextSendTimeFeeFilter)\n            {\n                static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE);\n                static FeeFilterRounder filterRounder(default_feerate);\n                CAmount filterToSend = filterRounder.round(currentFilter);\n                // We always have a fee filter of at least minRelayTxFee\n                filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());\n                if (filterToSend != pto->lastSentFeeFilter)\n                {\n                    connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));\n                    pto->lastSentFeeFilter = filterToSend;\n                }\n                pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);\n            }\n            // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY\n            // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.\n            else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&\n                     (currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3))\n            {\n                pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;\n            }\n        }\n    }\n    return true;\n}\n\nvoid AddPriorityDownload(const std::vector<const CBlockIndex*>& blocksToDownload, const PriorityDownloadCallback_t& callback)\n{\n    LOCK(cs_main);\n    for (const CBlockIndex* pindex: blocksToDownload)\n    {\n        bool downloaded = pindex->nStatus & BLOCK_HAVE_DATA;\n        blocksToDownloadFirst.push_back({pindex, downloaded, callback});\n    }\n}\n\nvoid CancelPriorityDownload(const CBlockIndex *index, const PriorityDownloadCallback_t& callback)\n{\n    LOCK(cs_main);\n    blocksToDownloadFirst.remove_if([&index](const PriorityBlockRequest& request){ return request.pindex == index; });\n}\n\nvoid CancelAllPriorityDownloads()\n{\n    LOCK(cs_main);\n    blocksToDownloadFirst.clear();\n}\n\nvoid PreventBlockDownloadDuringHeaderSync(bool state)\n{\n    fPreventBlockDownloadDuringHeaderSync = state;\n}\n\nsize_t CountPriorityDownloads()\n{\n    LOCK(cs_main);\n    return blocksToDownloadFirst.size();\n}\n\nclass CNetProcessingCleanup\n{\npublic:\n    CNetProcessingCleanup() {}\n    ~CNetProcessingCleanup()\n    {\n        // orphan transactions\n        mapOrphanTransactions.clear();\n        mapOrphanTransactionsByPrev.clear();\n    }\n} instance_of_cnetprocessingcleanup;\n"
  },
  {
    "path": "src/net_processing.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef NET_PROCESSING_H\n#define NET_PROCESSING_H\n\n#include \"net.h\"\n#include \"validation/validationinterface.h\"\n\n/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */\nstatic const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;\n/** Expiration time for orphan transactions in seconds */\nstatic const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;\n/** Minimum time between orphan transactions expire time checks in seconds */\nstatic const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;\n/** Default number of orphan+recently-replaced txn to keep around for block reconstruction */\nstatic const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;\n/** Timeout for the header request/response cycle during synchronisation\n * This time can and should be quite tight as we want to quickly drop peers that are not very responsive\n * Because of the tight timeout care shuld be taken that only \"external\" time is measured, ie.\n * the timeout should be reset as soon as an incoming header is known to be the response, not after fully processing\n * it which might take considerable time on some platforms. The timeout should be set again as soon as a new header\n * request message is pushed out.\n */\n#define HEADERS_DOWNLOAD_RESPONSE_TIMEOUT (Params().IsRegtestLegacy() ? 700 * 1000000 : 7 * 1000000) // 7 seconds\n\n/** When most recent header is newer, then block download is allowed when using SPV\n * (and automatic block requests is enabled). */\nstatic constexpr int64_t HEADERS_RECENT_FOR_BLOCKDOWNLOAD = 24 * 3600; // a day\n\n/** Register with a network node to receive its signals */\nvoid RegisterNodeSignals(CNodeSignals& nodeSignals);\n/** Unregister a network node */\nvoid UnregisterNodeSignals(CNodeSignals& nodeSignals);\n\nclass PeerLogicValidation : public CValidationInterface {\nprivate:\n    CConnman* connman;\n\npublic:\n    PeerLogicValidation(CConnman* connmanIn);\n\n    void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;\n    void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;\n    void BlockChecked(const CBlock& block, const CValidationState& state) override;\n    void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;\n};\n\nstruct CNodeStateStats {\n    int nMisbehavior;\n    int nSyncHeight;\n    int nCommonHeight;\n    std::vector<int> vHeightInFlight;\n};\n\n/** Get statistics from node state */\nbool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);\n/** Increase a node's misbehavior score. */\nvoid Misbehaving(NodeId nodeid, int howmuch);\n\n/** Process protocol messages received from a given node */\nbool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& interrupt);\n/**\n * Send queued protocol messages to be sent to a give node.\n *\n * @param[in]   pto             The node which we are sending messages to.\n * @param[in]   connman         The connection manager for that node.\n * @param[in]   interrupt       Interrupt condition for processing threads\n * @return                      True if there is more work to be done\n */\nbool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interrupt);\n\nvoid PreventBlockDownloadDuringHeaderSync(bool state);\n\n/**\n * Prioritize a block for downloading\n * Blocks requested with priority will be downloaded and processed first\n * Priority requests are delivered in requested order\n * Downloaded blocks will not trigger ActivateBestChain\n */\ntypedef std::function<void(const std::shared_ptr<const CBlock>, const CBlockIndex*)> PriorityDownloadCallback_t;\nvoid AddPriorityDownload(const std::vector<const CBlockIndex*>& blocksToDownload, const PriorityDownloadCallback_t& callback);\nvoid CancelPriorityDownload(const CBlockIndex* index, const PriorityDownloadCallback_t& callback);\nvoid CancelAllPriorityDownloads();\nsize_t CountPriorityDownloads();\n\nint GetProbableHeight();\n\n#endif\n"
  },
  {
    "path": "src/netaddress.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifdef HAVE_CONFIG_H\n#include \"config/build-config.h\"\n#endif\n\n#include \"netaddress.h\"\n#include \"hash.h\"\n#include \"util/strencodings.h\"\n#include \"tinyformat.h\"\n#include \"netbase.h\"\n#include \"util.h\"\n\nstatic const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };\nstatic const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};\n\nvoid CNetAddr::Init()\n{\n    memset(ip, 0, sizeof(ip));\n    scopeId = 0;\n}\n\nvoid CNetAddr::SetIP(const CNetAddr& ipIn)\n{\n    memcpy(ip, ipIn.ip, sizeof(ip));\n}\n\nvoid CNetAddr::SetRaw(Network network, const uint8_t *ip_in)\n{\n    switch(network)\n    {\n        case NET_IPV4:\n            memcpy(ip, pchIPv4, 12);\n            memcpy(ip+12, ip_in, 4);\n            break;\n        case NET_IPV6:\n            memcpy(ip, ip_in, 16);\n            break;\n        default:\n            assert(!\"invalid network\");\n    }\n}\n\nbool CNetAddr::SetSpecial(const std::string &strName)\n{\n    if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == \".onion\") {\n        std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());\n        if (vchAddr.size() != 16-sizeof(pchOnionCat))\n            return false;\n        memcpy(ip, pchOnionCat, sizeof(pchOnionCat));\n        for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)\n            ip[i + sizeof(pchOnionCat)] = vchAddr[i];\n        return true;\n    }\n    return false;\n}\n\nCNetAddr::CNetAddr()\n{\n    Init();\n}\n\nCNetAddr::CNetAddr(const boost::asio::ip::address& addr)\n{\n    if (addr.is_v4()) {\n        SetRaw(NET_IPV4, addr.to_v4().to_bytes().data());\n    }\n    else if (addr.is_v6()) {\n        auto addr_v6 = addr.to_v6();\n        SetRaw(NET_IPV6, addr_v6.to_bytes().data());\n        scopeId = addr_v6.scope_id();\n    }\n}\n\nCNetAddr::CNetAddr(const struct in_addr& ipv4Addr)\n{\n    SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);\n}\n\nCNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)\n{\n    SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr);\n    scopeId = scope;\n}\n\nunsigned int CNetAddr::GetByte(int n) const\n{\n    return ip[15-n];\n}\n\nbool CNetAddr::IsIPv4() const\n{\n    return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);\n}\n\nbool CNetAddr::IsIPv6() const\n{\n    return (!IsIPv4() && !IsTor());\n}\n\nbool CNetAddr::IsRFC1918() const\n{\n    return IsIPv4() && (\n        GetByte(3) == 10 ||\n        (GetByte(3) == 192 && GetByte(2) == 168) ||\n        (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));\n}\n\nbool CNetAddr::IsRFC2544() const\n{\n    return IsIPv4() && GetByte(3) == 198 && (GetByte(2) == 18 || GetByte(2) == 19);\n}\n\nbool CNetAddr::IsRFC3927() const\n{\n    return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);\n}\n\nbool CNetAddr::IsRFC6598() const\n{\n    return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && GetByte(2) <= 127;\n}\n\nbool CNetAddr::IsRFC5737() const\n{\n    return IsIPv4() && ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||\n        (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||\n        (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));\n}\n\nbool CNetAddr::IsRFC3849() const\n{\n    return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8;\n}\n\nbool CNetAddr::IsRFC3964() const\n{\n    return (GetByte(15) == 0x20 && GetByte(14) == 0x02);\n}\n\nbool CNetAddr::IsRFC6052() const\n{\n    static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};\n    return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);\n}\n\nbool CNetAddr::IsRFC4380() const\n{\n    return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0);\n}\n\nbool CNetAddr::IsRFC4862() const\n{\n    static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};\n    return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);\n}\n\nbool CNetAddr::IsRFC4193() const\n{\n    return ((GetByte(15) & 0xFE) == 0xFC);\n}\n\nbool CNetAddr::IsRFC6145() const\n{\n    static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};\n    return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);\n}\n\nbool CNetAddr::IsRFC4843() const\n{\n    return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);\n}\n\nbool CNetAddr::IsTor() const\n{\n    return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);\n}\n\nbool CNetAddr::IsLocal() const\n{\n    // IPv4 loopback\n   if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))\n       return true;\n\n   // IPv6 loopback (::1/128)\n   static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};\n   if (memcmp(ip, pchLocal, 16) == 0)\n       return true;\n\n   return false;\n}\n\nbool CNetAddr::IsValid() const\n{\n    // Cleanup 3-byte shifted addresses caused by garbage in size field\n    // of addr messages from versions before 0.2.9 checksum.\n    // Two consecutive addr messages look like this:\n    // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...\n    // so if the first length field is garbled, it reads the second batch\n    // of addr misaligned by 3 bytes.\n    if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0)\n        return false;\n\n    // unspecified IPv6 address (::/128)\n    unsigned char ipNone6[16] = {};\n    if (memcmp(ip, ipNone6, 16) == 0)\n        return false;\n\n    // documentation IPv6 address\n    if (IsRFC3849())\n        return false;\n\n    if (IsIPv4())\n    {\n        // INADDR_NONE\n        uint32_t ipNone = INADDR_NONE;\n        if (memcmp(ip+12, &ipNone, 4) == 0)\n            return false;\n\n        // 0\n        ipNone = 0;\n        if (memcmp(ip+12, &ipNone, 4) == 0)\n            return false;\n    }\n\n    return true;\n}\n\nbool CNetAddr::IsRoutable() const\n{\n    return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());\n}\n\nenum Network CNetAddr::GetNetwork() const\n{\n    if (!IsRoutable())\n        return NET_UNROUTABLE;\n\n    if (IsIPv4())\n        return NET_IPV4;\n\n    if (IsTor())\n        return NET_TOR;\n\n    return NET_IPV6;\n}\n\nstd::string CNetAddr::ToStringIP() const\n{\n    if (IsTor())\n        return EncodeBase32(&ip[6], 10) + \".onion\";\n\n    try {\n        boost::asio::ip::tcp::resolver resolver(get_io_context());\n        auto endpoints = resolver.resolve(GetAddress().to_string(), \"\", boost::asio::ip::tcp::resolver::flags::numeric_host);\n        return endpoints.begin()->host_name();\n    }\n    catch (const boost::system::error_code& ec) {\n    }\n\n    if (IsIPv4())\n        return strprintf(\"%u.%u.%u.%u\", GetByte(3), GetByte(2), GetByte(1), GetByte(0));\n    else\n        return strprintf(\"%x:%x:%x:%x:%x:%x:%x:%x\",\n                         GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12),\n                         GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8),\n                         GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4),\n                         GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0));\n}\n\nstd::string CNetAddr::ToString() const\n{\n    return ToStringIP();\n}\n\nstd::string CNetAddr::HostnameLookup() const\n{\n    if (IsTor())\n        return \"\";\n\n    try {\n        boost::asio::ip::tcp::resolver resolver(get_io_context());\n        boost::asio::ip::tcp::endpoint ep;\n        ep.address(GetAddress());\n        auto endpoints = resolver.resolve(ep);\n        return endpoints.begin()->host_name();\n    }\n    catch (const boost::system::error_code& ec) {\n    }\n\n    return \"\";\n}\n\nbool operator==(const CNetAddr& a, const CNetAddr& b)\n{\n    return (memcmp(a.ip, b.ip, 16) == 0);\n}\n\nbool operator!=(const CNetAddr& a, const CNetAddr& b)\n{\n    return (memcmp(a.ip, b.ip, 16) != 0);\n}\n\nbool operator<(const CNetAddr& a, const CNetAddr& b)\n{\n    return (memcmp(a.ip, b.ip, 16) < 0);\n}\n\nboost::asio::ip::address CNetAddr::GetAddress() const\n{\n    if (IsIPv4())\n        return GetInAddr();\n    else\n        return GetIn6Addr();\n}\n\nboost::asio::ip::address_v4 CNetAddr::GetInAddr() const\n{\n    boost::asio::ip::address_v4::bytes_type bytes;\n    memcpy(bytes.data(), (const unsigned char*)ip+12, 4);\n    return boost::asio::ip::address_v4(bytes);\n}\n\nboost::asio::ip::address_v6 CNetAddr::GetIn6Addr() const\n{\n    boost::asio::ip::address_v6::bytes_type bytes;\n    memcpy(bytes.data(), (const unsigned char*)ip, 16);\n    return boost::asio::ip::address_v6(bytes, scopeId);\n}\n\nbool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const\n{\n    if (!IsIPv4())\n        return false;\n    memcpy(pipv4Addr, ip+12, 4);\n    return true;\n}\n\nbool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const\n{\n    memcpy(pipv6Addr, ip, 16);\n    return true;\n}\n\n// get canonical identifier of an address' group\n// no two connections will be attempted to addresses with the same group\nstd::vector<unsigned char> CNetAddr::GetGroup() const\n{\n    std::vector<unsigned char> vchRet;\n    int nClass = NET_IPV6;\n    int nStartByte = 0;\n    int nBits = 16;\n\n    // all local addresses belong to the same group\n    if (IsLocal())\n    {\n        nClass = 255;\n        nBits = 0;\n    }\n\n    // all unroutable addresses belong to the same group\n    if (!IsRoutable())\n    {\n        nClass = NET_UNROUTABLE;\n        nBits = 0;\n    }\n    // for IPv4 addresses, '1' + the 16 higher-order bits of the IP\n    // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix\n    else if (IsIPv4() || IsRFC6145() || IsRFC6052())\n    {\n        nClass = NET_IPV4;\n        nStartByte = 12;\n    }\n    // for 6to4 tunnelled addresses, use the encapsulated IPv4 address\n    else if (IsRFC3964())\n    {\n        nClass = NET_IPV4;\n        nStartByte = 2;\n    }\n    // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address\n    else if (IsRFC4380())\n    {\n        vchRet.push_back(NET_IPV4);\n        vchRet.push_back(GetByte(3) ^ 0xFF);\n        vchRet.push_back(GetByte(2) ^ 0xFF);\n        return vchRet;\n    }\n    else if (IsTor())\n    {\n        nClass = NET_TOR;\n        nStartByte = 6;\n        nBits = 4;\n    }\n    // for he.net, use /36 groups\n    else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)\n        nBits = 36;\n    // for the rest of the IPv6 network, use /32 groups\n    else\n        nBits = 32;\n\n    vchRet.push_back(nClass);\n    while (nBits >= 8)\n    {\n        vchRet.push_back(GetByte(15 - nStartByte));\n        nStartByte++;\n        nBits -= 8;\n    }\n    if (nBits > 0)\n        vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));\n\n    return vchRet;\n}\n\nuint64_t CNetAddr::GetHash() const\n{\n    uint256 hash = Hash(&ip[0], &ip[16]);\n    uint64_t nRet;\n    memcpy(&nRet, &hash, sizeof(nRet));\n    return nRet;\n}\n\n// private extensions to enum Network, only returned by GetExtNetwork,\n// and only used in GetReachabilityFrom\nstatic const int NET_UNKNOWN = NET_MAX + 0;\nstatic const int NET_TEREDO  = NET_MAX + 1;\nint static GetExtNetwork(const CNetAddr *addr)\n{\n    if (addr == NULL)\n        return NET_UNKNOWN;\n    if (addr->IsRFC4380())\n        return NET_TEREDO;\n    return addr->GetNetwork();\n}\n\n/** Calculates a metric for how reachable (*this) is from a given partner */\nint CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const\n{\n    enum Reachability {\n        REACH_UNREACHABLE,\n        REACH_DEFAULT,\n        REACH_TEREDO,\n        REACH_IPV6_WEAK,\n        REACH_IPV4,\n        REACH_IPV6_STRONG,\n        REACH_PRIVATE\n    };\n\n    if (!IsRoutable())\n        return REACH_UNREACHABLE;\n\n    int ourNet = GetExtNetwork(this);\n    int theirNet = GetExtNetwork(paddrPartner);\n    bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();\n\n    switch(theirNet) {\n    case NET_IPV4:\n        switch(ourNet) {\n        default:       return REACH_DEFAULT;\n        case NET_IPV4: return REACH_IPV4;\n        }\n    case NET_IPV6:\n        switch(ourNet) {\n        default:         return REACH_DEFAULT;\n        case NET_TEREDO: return REACH_TEREDO;\n        case NET_IPV4:   return REACH_IPV4;\n        case NET_IPV6:   return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled\n        }\n    case NET_TOR:\n        switch(ourNet) {\n        default:         return REACH_DEFAULT;\n        case NET_IPV4:   return REACH_IPV4; // Tor users can connect to IPv4 as well\n        case NET_TOR:    return REACH_PRIVATE;\n        }\n    case NET_TEREDO:\n        switch(ourNet) {\n        default:          return REACH_DEFAULT;\n        case NET_TEREDO:  return REACH_TEREDO;\n        case NET_IPV6:    return REACH_IPV6_WEAK;\n        case NET_IPV4:    return REACH_IPV4;\n        }\n    case NET_UNKNOWN:\n    case NET_UNROUTABLE:\n    default:\n        switch(ourNet) {\n        default:          return REACH_DEFAULT;\n        case NET_TEREDO:  return REACH_TEREDO;\n        case NET_IPV6:    return REACH_IPV6_WEAK;\n        case NET_IPV4:    return REACH_IPV4;\n        case NET_TOR:     return REACH_PRIVATE; // either from Tor, or don't care about our address\n        }\n    }\n}\n\nvoid CService::Init()\n{\n    port = 0;\n}\n\nCService::CService()\n{\n    Init();\n}\n\nCService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)\n{\n}\n\nCService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn)\n{\n}\n\nCService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)\n{\n}\n\nCService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))\n{\n    assert(addr.sin_family == AF_INET);\n}\n\nCService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))\n{\n   assert(addr.sin6_family == AF_INET6);\n}\n\nCService::CService(const boost::asio::ip::tcp::endpoint& endpoint) : CNetAddr(endpoint.address()), port(endpoint.port())\n{\n}\n\nbool CService::SetSockAddr(const boost::asio::ip::tcp::endpoint& endpoint)\n{\n    auto protocol = endpoint.protocol();\n    if (protocol == boost::asio::ip::tcp::v4() || protocol == boost::asio::ip::tcp::v6()) {\n        *this = CService(endpoint);\n    }\n    return true;\n}\n\nunsigned short CService::GetPort() const\n{\n    return port;\n}\n\nbool operator==(const CService& a, const CService& b)\n{\n    return (CNetAddr)a == (CNetAddr)b && a.port == b.port;\n}\n\nbool operator!=(const CService& a, const CService& b)\n{\n    return (CNetAddr)a != (CNetAddr)b || a.port != b.port;\n}\n\nbool operator<(const CService& a, const CService& b)\n{\n    return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port);\n}\n\nboost::asio::ip::tcp::endpoint CService::GetSockAddr() const\n{\n    boost::asio::ip::tcp::endpoint endpoint(GetAddress(), port);\n    return endpoint;\n}\n\nbool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const\n{\n    if (IsIPv4()) {\n        if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))\n            return false;\n        *addrlen = sizeof(struct sockaddr_in);\n        struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;\n        memset(paddrin, 0, *addrlen);\n        if (!GetInAddr(&paddrin->sin_addr))\n            return false;\n        paddrin->sin_family = AF_INET;\n        paddrin->sin_port = htons(port);\n        return true;\n    }\n    if (IsIPv6()) {\n        if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))\n            return false;\n        *addrlen = sizeof(struct sockaddr_in6);\n        struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;\n        memset(paddrin6, 0, *addrlen);\n        if (!GetIn6Addr(&paddrin6->sin6_addr))\n            return false;\n        paddrin6->sin6_scope_id = scopeId;\n        paddrin6->sin6_family = AF_INET6;\n        paddrin6->sin6_port = htons(port);\n        return true;\n    }\n    return false;\n}\n\nstd::vector<unsigned char> CService::GetKey() const\n{\n     std::vector<unsigned char> vKey;\n     vKey.resize(18);\n     memcpy(&vKey[0], ip, 16);\n     vKey[16] = port / 0x100;\n     vKey[17] = port & 0x0FF;\n     return vKey;\n}\n\nstd::string CService::ToStringPort() const\n{\n    return strprintf(\"%u\", port);\n}\n\nstd::string CService::ToStringIPPort() const\n{\n    if (IsIPv4() || IsTor()) {\n        return ToStringIP() + \":\" + ToStringPort();\n    } else {\n        return \"[\" + ToStringIP() + \"]:\" + ToStringPort();\n    }\n}\n\nstd::string CService::ToString() const\n{\n    return ToStringIPPort();\n}\n\nvoid CService::SetPort(unsigned short portIn)\n{\n    port = portIn;\n}\n\nCSubNet::CSubNet():\n    valid(false)\n{\n    memset(netmask, 0, sizeof(netmask));\n}\n\nCSubNet::CSubNet(const CNetAddr &addr, int32_t mask)\n{\n    valid = true;\n    network = addr;\n    // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address\n    memset(netmask, 255, sizeof(netmask));\n\n    // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n\n    const int astartofs = network.IsIPv4() ? 12 : 0;\n\n    int32_t n = mask;\n    if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address\n    {\n        n += astartofs*8;\n        // Clear bits [n..127]\n        for (; n < 128; ++n)\n            netmask[n>>3] &= ~(1<<(7-(n&7)));\n    } else\n        valid = false;\n\n    // Normalize network according to netmask\n    for(int x=0; x<16; ++x)\n        network.ip[x] &= netmask[x];\n}\n\nCSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask)\n{\n    valid = true;\n    network = addr;\n    // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address\n    memset(netmask, 255, sizeof(netmask));\n\n    // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n\n    const int astartofs = network.IsIPv4() ? 12 : 0;\n\n    for(int x=astartofs; x<16; ++x)\n        netmask[x] = mask.ip[x];\n\n    // Normalize network according to netmask\n    for(int x=0; x<16; ++x)\n        network.ip[x] &= netmask[x];\n}\n\nCSubNet::CSubNet(const CNetAddr &addr):\n    valid(addr.IsValid())\n{\n    memset(netmask, 255, sizeof(netmask));\n    network = addr;\n}\n\nbool CSubNet::Match(const CNetAddr &addr) const\n{\n    if (!valid || !addr.IsValid())\n        return false;\n    for(int x=0; x<16; ++x)\n        if ((addr.ip[x] & netmask[x]) != network.ip[x])\n            return false;\n    return true;\n}\n\nstatic inline int NetmaskBits(uint8_t x)\n{\n    switch(x) {\n    case 0x00: return 0; break;\n    case 0x80: return 1; break;\n    case 0xc0: return 2; break;\n    case 0xe0: return 3; break;\n    case 0xf0: return 4; break;\n    case 0xf8: return 5; break;\n    case 0xfc: return 6; break;\n    case 0xfe: return 7; break;\n    case 0xff: return 8; break;\n    default: return -1; break;\n    }\n}\n\nstd::string CSubNet::ToString() const\n{\n    /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */\n    int cidr = 0;\n    bool valid_cidr = true;\n    int n = network.IsIPv4() ? 12 : 0;\n    for (; n < 16 && netmask[n] == 0xff; ++n)\n        cidr += 8;\n    if (n < 16) {\n        int bits = NetmaskBits(netmask[n]);\n        if (bits < 0)\n            valid_cidr = false;\n        else\n            cidr += bits;\n        ++n;\n    }\n    for (; n < 16 && valid_cidr; ++n)\n        if (netmask[n] != 0x00)\n            valid_cidr = false;\n\n    /* Format output */\n    std::string strNetmask;\n    if (valid_cidr) {\n        strNetmask = strprintf(\"%u\", cidr);\n    } else {\n        if (network.IsIPv4())\n            strNetmask = strprintf(\"%u.%u.%u.%u\", netmask[12], netmask[13], netmask[14], netmask[15]);\n        else\n            strNetmask = strprintf(\"%x:%x:%x:%x:%x:%x:%x:%x\",\n                             netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],\n                             netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],\n                             netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],\n                             netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);\n    }\n\n    return network.ToString() + \"/\" + strNetmask;\n}\n\nbool CSubNet::IsValid() const\n{\n    return valid;\n}\n\nbool operator==(const CSubNet& a, const CSubNet& b)\n{\n    return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);\n}\n\nbool operator!=(const CSubNet& a, const CSubNet& b)\n{\n    return !(a==b);\n}\n\nbool operator<(const CSubNet& a, const CSubNet& b)\n{\n    return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));\n}\n"
  },
  {
    "path": "src/netaddress.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef NETADDRESS_H\n#define NETADDRESS_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"compat.h\"\n#include \"serialize.h\"\n\n#include <stdint.h>\n#include <string>\n#include <vector>\n\n// fixme: (BOOST) - Workaround for boost on macOS (when using newer clang) build issue (not detecting string_view properly)\n// Remove this when addressed by Boost's ASIO config.\n// https://www.boost.org/doc/libs/1_67_0/boost/asio/detail/config.hpp\n// Standard library support for std::string_view.\n#define BOOST_ASIO_HAS_STD_STRING_VIEW 1\n#define BOOST_ASIO_DISABLE_STD_STRING_VIEW 1\n#include <boost/asio.hpp>\n\nenum Network\n{\n    NET_UNROUTABLE = 0,\n    NET_IPV4,\n    NET_IPV6,\n    NET_TOR,\n\n    NET_MAX,\n};\n\n/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */\nclass CNetAddr\n{\n    protected:\n        unsigned char ip[16]; // in network byte order\n        uint32_t scopeId; // for scoped/link-local ipv6 addresses\n\n    public:\n        CNetAddr();\n        CNetAddr(const struct in_addr& ipv4Addr);\n        CNetAddr(const boost::asio::ip::address& addr);\n        void Init();\n        void SetIP(const CNetAddr& ip);\n\n        /**\n         * Set raw IPv4 or IPv6 address (in network byte order)\n         * @note Only NET_IPV4 and NET_IPV6 are allowed for network.\n         */\n        void SetRaw(Network network, const uint8_t *data);\n\n        bool SetSpecial(const std::string &strName); // for Tor addresses\n        bool IsIPv4() const;    // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)\n        bool IsIPv6() const;    // IPv6 address (not mapped IPv4, not Tor)\n        bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)\n        bool IsRFC2544() const; // IPv4 inter-network communications (192.18.0.0/15)\n        bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10)\n        bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24)\n        bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)\n        bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)\n        bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)\n        bool IsRFC4193() const; // IPv6 unique local (FC00::/7)\n        bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)\n        bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)\n        bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)\n        bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)\n        bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)\n        bool IsTor() const;\n        bool IsLocal() const;\n        bool IsRoutable() const;\n        bool IsValid() const;\n        enum Network GetNetwork() const;\n        std::string ToString() const;\n        std::string ToStringIP() const;\n        std::string HostnameLookup() const;\n        unsigned int GetByte(int n) const;\n        uint64_t GetHash() const;\n        bool GetInAddr(struct in_addr* pipv4Addr) const;\n        boost::asio::ip::address GetAddress() const;\n        boost::asio::ip::address_v4 GetInAddr() const;\n        boost::asio::ip::address_v6 GetIn6Addr() const;\n        std::vector<unsigned char> GetGroup() const;\n        int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;\n\n        CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);\n        bool GetIn6Addr(struct in6_addr* pipv6Addr) const;\n\n        friend bool operator==(const CNetAddr& a, const CNetAddr& b);\n        friend bool operator!=(const CNetAddr& a, const CNetAddr& b);\n        friend bool operator<(const CNetAddr& a, const CNetAddr& b);\n\n        ADD_SERIALIZE_METHODS;\n\n        template <typename Stream, typename Operation>\n        inline void SerializationOp(Stream& s, Operation ser_action) {\n            READWRITE(FLATDATA(ip));\n        }\n\n        friend class CSubNet;\n};\n\nclass CSubNet\n{\n    protected:\n        /// Network (base) address\n        CNetAddr network;\n        /// Netmask, in network byte order\n        uint8_t netmask[16];\n        /// Is this value valid? (only used to signal parse errors)\n        bool valid;\n\n    public:\n        CSubNet();\n        CSubNet(const CNetAddr &addr, int32_t mask);\n        CSubNet(const CNetAddr &addr, const CNetAddr &mask);\n\n        //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)\n        explicit CSubNet(const CNetAddr &addr);\n\n        bool Match(const CNetAddr &addr) const;\n\n        std::string ToString() const;\n        bool IsValid() const;\n\n        friend bool operator==(const CSubNet& a, const CSubNet& b);\n        friend bool operator!=(const CSubNet& a, const CSubNet& b);\n        friend bool operator<(const CSubNet& a, const CSubNet& b);\n\n        ADD_SERIALIZE_METHODS;\n\n        template <typename Stream, typename Operation>\n        inline void SerializationOp(Stream& s, Operation ser_action) {\n            READWRITE(network);\n            READWRITE(FLATDATA(netmask));\n            READWRITE(FLATDATA(valid));\n        }\n};\n\n/** A combination of a network address (CNetAddr) and a (TCP) port */\nclass CService : public CNetAddr\n{\n    protected:\n        unsigned short port; // host order\n\n    public:\n        CService();\n        CService(const CNetAddr& ip, unsigned short port);\n        CService(const struct in_addr& ipv4Addr, unsigned short port);\n        CService(const struct sockaddr_in& addr);\n        CService(const boost::asio::ip::tcp::endpoint& endpoint);\n        void Init();\n        void SetPort(unsigned short portIn);\n        unsigned short GetPort() const;\n        bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;\n        boost::asio::ip::tcp::endpoint GetSockAddr() const;\n        bool SetSockAddr(const boost::asio::ip::tcp::endpoint& endpoint);\n        friend bool operator==(const CService& a, const CService& b);\n        friend bool operator!=(const CService& a, const CService& b);\n        friend bool operator<(const CService& a, const CService& b);\n        std::vector<unsigned char> GetKey() const;\n        std::string ToString() const;\n        std::string ToStringPort() const;\n        std::string ToStringIPPort() const;\n\n        CService(const struct in6_addr& ipv6Addr, unsigned short port);\n        CService(const struct sockaddr_in6& addr);\n\n        ADD_SERIALIZE_METHODS;\n\n        template <typename Stream, typename Operation>\n        inline void SerializationOp(Stream& s, Operation ser_action) {\n            READWRITE(FLATDATA(ip));\n            unsigned short portN = htons(port);\n            READWRITE(FLATDATA(portN));\n            if (ser_action.ForRead())\n                 port = ntohs(portN);\n        }\n};\n\n#endif\n"
  },
  {
    "path": "src/netbase.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifdef HAVE_CONFIG_H\n#include \"config/build-config.h\"\n#endif\n\n#include \"netbase.h\"\n\n#include \"hash.h\"\n#include \"sync.h\"\n#include \"uint256.h\"\n#include \"random.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#include <atomic>\n\n#ifndef WIN32\n#include <fcntl.h>\n#endif\n\n#include <boost/algorithm/string/case_conv.hpp> // for to_lower()\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and ends_with()\n\nusing namespace boost::asio::ip;\n\n#if !defined(HAVE_MSG_NOSIGNAL)\n#define MSG_NOSIGNAL 0\n#endif\n\n// Settings\nstatic proxyType proxyInfo[NET_MAX];\nstatic proxyType nameProxy;\nstatic RecursiveMutex cs_proxyInfos;\nint nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;\nbool fNameLookup = DEFAULT_NAME_LOOKUP;\n\n// Need ample time for negotiation for very slow proxies such as Tor (milliseconds)\nstatic const int SOCKS5_RECV_TIMEOUT = 20 * 1000;\nstatic std::atomic<bool> interruptSocks5Recv(false);\n\nstatic boost::asio::io_context _io_context;\n\nboost::asio::io_context& get_io_context() {\n    return _io_context;\n}\n\nenum Network ParseNetwork(std::string net) {\n    boost::to_lower(net);\n    if (net == \"ipv4\") return NET_IPV4;\n    if (net == \"ipv6\") return NET_IPV6;\n    if (net == \"tor\" || net == \"onion\")  return NET_TOR;\n    return NET_UNROUTABLE;\n}\n\nstd::string GetNetworkName(enum Network net) {\n    switch(net)\n    {\n    case NET_IPV4: return \"ipv4\";\n    case NET_IPV6: return \"ipv6\";\n    case NET_TOR: return \"onion\";\n    default: return \"\";\n    }\n}\n\nvoid SplitHostPort(std::string in, int &portOut, std::string &hostOut) {\n    size_t colon = in.find_last_of(':');\n    // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator\n    bool fHaveColon = colon != in.npos;\n    bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe\n    bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);\n    if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {\n        int32_t n;\n        if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {\n            in = in.substr(0, colon);\n            portOut = n;\n        }\n    }\n    if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')\n        hostOut = in.substr(1, in.size()-2);\n    else\n        hostOut = in;\n}\n\nbool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)\n{\n    vIP.clear();\n\n    {\n        CNetAddr addr;\n        if (addr.SetSpecial(std::string(pszName))) {\n            vIP.push_back(addr);\n            return true;\n        }\n    }\n\n    try {\n        tcp::resolver resolver(get_io_context());\n        auto endpoints =\n                resolver.resolve(pszName,\n                                 \"\",\n                                 fAllowLookup ?\n                                     tcp::resolver::flags::address_configured\n                                   : tcp::resolver::flags::numeric_host);\n\n        for (auto it = endpoints.begin(); it != endpoints.end() && (nMaxSolutions==0 || vIP.size()<nMaxSolutions); it++) {\n            vIP.push_back(it->endpoint().address());\n        }\n    }\n    catch (const boost::system::system_error& err) {\n        LogPrint(BCLog::NET, \"LookupIntern for %s failed: %s\\n\", pszName, err.what());\n        return false;\n    }\n\n    return true;\n}\n\nbool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)\n{\n    std::string strHost(pszName);\n    if (strHost.empty())\n        return false;\n    if (boost::algorithm::starts_with(strHost, \"[\") && boost::algorithm::ends_with(strHost, \"]\"))\n    {\n        strHost = strHost.substr(1, strHost.size() - 2);\n    }\n\n    return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);\n}\n\nbool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup)\n{\n    std::vector<CNetAddr> vIP;\n    LookupHost(pszName, vIP, 1, fAllowLookup);\n    if(vIP.empty())\n        return false;\n    addr = vIP.front();\n    return true;\n}\n\nbool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)\n{\n    if (pszName[0] == 0)\n        return false;\n    int port = portDefault;\n    std::string hostname = \"\";\n    SplitHostPort(std::string(pszName), port, hostname);\n\n    std::vector<CNetAddr> vIP;\n    bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);\n    if (!fRet)\n        return false;\n    vAddr.resize(vIP.size());\n    for (unsigned int i = 0; i < vIP.size(); i++)\n        vAddr[i] = CService(vIP[i], port);\n    return true;\n}\n\nbool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)\n{\n    std::vector<CService> vService;\n    bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1);\n    if (!fRet)\n        return false;\n    addr = vService[0];\n    return true;\n}\n\nCService LookupNumeric(const char *pszName, int portDefault)\n{\n    CService addr;\n    // \"1.2:345\" will fail to resolve the ip, but will still set the port.\n    // If the ip fails to resolve, re-init the result.\n    if(!Lookup(pszName, addr, portDefault, false))\n        addr = CService();\n    return addr;\n}\n\nenum class IntrRecvError {\n    OK,\n    Timeout,\n    Disconnected,\n    NetworkError,\n    Interrupted\n};\n\n/**\n * Read bytes from socket. This will either read the full number of bytes requested\n * or return False on error or timeout.\n * This function can be interrupted by calling InterruptSocks5()\n *\n * @param data Buffer to receive into\n * @param len  Length of data to receive\n * @param timeout  Timeout in milliseconds for receive operation\n *\n * @note This function requires that hSocket is in non-blocking mode.\n */\nstatic IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)\n{\n    int64_t curTime = GetTimeMillis();\n    int64_t endTime = curTime + timeout;\n    // Maximum time to wait in one select call. It will take up until this time (in millis)\n    // to break off in case of an interruption.\n    const int64_t maxWait = 1000;\n    while (len > 0 && curTime < endTime) {\n        ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first\n        if (ret > 0) {\n            len -= ret;\n            data += ret;\n        } else if (ret == 0) { // Unexpected disconnection\n            return IntrRecvError::Disconnected;\n        } else { // Other error or blocking\n            int nErr = WSAGetLastError();\n            if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {\n                struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));\n                fd_set fdset;\n                FD_ZERO(&fdset);\n                FD_SET(hSocket, &fdset);\n                int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);\n                if (nRet == SOCKET_ERROR) {\n                    return IntrRecvError::NetworkError;\n                }\n            } else {\n                return IntrRecvError::NetworkError;\n            }\n        }\n        if (interruptSocks5Recv)\n            return IntrRecvError::Interrupted;\n        curTime = GetTimeMillis();\n    }\n    return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;\n}\n\nstruct ProxyCredentials\n{\n    std::string username;\n    std::string password;\n};\n\nstd::string Socks5ErrorString(int err)\n{\n    switch(err) {\n        case 0x01: return \"general failure\";\n        case 0x02: return \"connection not allowed\";\n        case 0x03: return \"network unreachable\";\n        case 0x04: return \"host unreachable\";\n        case 0x05: return \"connection refused\";\n        case 0x06: return \"TTL expired\";\n        case 0x07: return \"protocol error\";\n        case 0x08: return \"address type not supported\";\n        default:   return \"unknown\";\n    }\n}\n\n/** Connect using SOCKS5 (as described in RFC1928) */\nstatic bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)\n{\n    IntrRecvError recvr;\n    LogPrint(BCLog::NET, \"SOCKS5 connecting %s\\n\", strDest);\n    if (strDest.size() > 255) {\n        CloseSocket(hSocket);\n        return error(\"Hostname too long\");\n    }\n    // Accepted authentication methods\n    std::vector<uint8_t> vSocks5Init;\n    vSocks5Init.push_back(0x05);\n    if (auth) {\n        vSocks5Init.push_back(0x02); // # METHODS\n        vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED\n        vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)\n    } else {\n        vSocks5Init.push_back(0x01); // # METHODS\n        vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED\n    }\n    ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);\n    if (ret != (ssize_t)vSocks5Init.size()) {\n        CloseSocket(hSocket);\n        return error(\"Error sending to proxy\");\n    }\n    char pchRet1[2];\n    if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {\n        CloseSocket(hSocket);\n        LogPrintf(\"Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\\n\", strDest, port);\n        return false;\n    }\n    if (pchRet1[0] != 0x05) {\n        CloseSocket(hSocket);\n        return error(\"Proxy failed to initialize\");\n    }\n    if (pchRet1[1] == 0x02 && auth) {\n        // Perform username/password authentication (as described in RFC1929)\n        std::vector<uint8_t> vAuth;\n        vAuth.push_back(0x01);\n        if (auth->username.size() > 255 || auth->password.size() > 255)\n            return error(\"Proxy username or password too long\");\n        vAuth.push_back(auth->username.size());\n        vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());\n        vAuth.push_back(auth->password.size());\n        vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());\n        ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);\n        if (ret != (ssize_t)vAuth.size()) {\n            CloseSocket(hSocket);\n            return error(\"Error sending authentication to proxy\");\n        }\n        LogPrint(BCLog::PROXY, \"SOCKS5 sending proxy authentication %s:%s\\n\", auth->username, auth->password);\n        char pchRetA[2];\n        if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {\n            CloseSocket(hSocket);\n            return error(\"Error reading proxy authentication response\");\n        }\n        if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {\n            CloseSocket(hSocket);\n            return error(\"Proxy authentication unsuccessful\");\n        }\n    } else if (pchRet1[1] == 0x00) {\n        // Perform no authentication\n    } else {\n        CloseSocket(hSocket);\n        return error(\"Proxy requested wrong authentication method %02x\", pchRet1[1]);\n    }\n    std::vector<uint8_t> vSocks5;\n    vSocks5.push_back(0x05); // VER protocol version\n    vSocks5.push_back(0x01); // CMD CONNECT\n    vSocks5.push_back(0x00); // RSV Reserved\n    vSocks5.push_back(0x03); // ATYP DOMAINNAME\n    vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function\n    vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());\n    vSocks5.push_back((port >> 8) & 0xFF);\n    vSocks5.push_back((port >> 0) & 0xFF);\n    ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);\n    if (ret != (ssize_t)vSocks5.size()) {\n        CloseSocket(hSocket);\n        return error(\"Error sending to proxy\");\n    }\n    char pchRet2[4];\n    if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {\n        CloseSocket(hSocket);\n        if (recvr == IntrRecvError::Timeout) {\n            /* If a timeout happens here, this effectively means we timed out while connecting\n             * to the remote node. This is very common for Tor, so do not print an\n             * error message. */\n            return false;\n        } else {\n            return error(\"Error while reading proxy response\");\n        }\n    }\n    if (pchRet2[0] != 0x05) {\n        CloseSocket(hSocket);\n        return error(\"Proxy failed to accept request\");\n    }\n    if (pchRet2[1] != 0x00) {\n        // Failures to connect to a peer that are not proxy errors\n        CloseSocket(hSocket);\n        LogPrintf(\"Socks5() connect to %s:%d failed: %s\\n\", strDest, port, Socks5ErrorString(pchRet2[1]));\n        return false;\n    }\n    if (pchRet2[2] != 0x00) {\n        CloseSocket(hSocket);\n        return error(\"Error: malformed proxy response\");\n    }\n    char pchRet3[256];\n    switch (pchRet2[3])\n    {\n        case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;\n        case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;\n        case 0x03:\n        {\n            recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);\n            if (recvr != IntrRecvError::OK) {\n                CloseSocket(hSocket);\n                return error(\"Error reading from proxy\");\n            }\n            int nRecv = pchRet3[0];\n            recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);\n            break;\n        }\n        default: CloseSocket(hSocket); return error(\"Error: malformed proxy response\");\n    }\n    if (recvr != IntrRecvError::OK) {\n        CloseSocket(hSocket);\n        return error(\"Error reading from proxy\");\n    }\n    if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {\n        CloseSocket(hSocket);\n        return error(\"Error reading from proxy\");\n    }\n    LogPrint(BCLog::NET, \"SOCKS5 connected %s\\n\", strDest);\n    return true;\n}\n\nbool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)\n{\n    hSocketRet = INVALID_SOCKET;\n\n    struct sockaddr_storage sockaddr;\n    socklen_t len = sizeof(sockaddr);\n    if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {\n        LogPrintf(\"Cannot connect to %s: unsupported network\\n\", addrConnect.ToString());\n        return false;\n    }\n\n    SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);\n    if (hSocket == INVALID_SOCKET)\n        return false;\n\n#ifdef SO_NOSIGPIPE\n    int set = 1;\n    // Different way of disabling SIGPIPE on BSD\n    setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));\n#endif\n\n    //Disable Nagle's algorithm\n    SetSocketNoDelay(hSocket);\n\n    // Set to non-blocking\n    if (!SetSocketNonBlocking(hSocket, true))\n        return error(\"ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\\n\", NetworkErrorString(WSAGetLastError()));\n\n    if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)\n    {\n        int nErr = WSAGetLastError();\n        // WSAEINVAL is here because some legacy version of winsock uses it\n        if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)\n        {\n            struct timeval timeout = MillisToTimeval(nTimeout);\n            fd_set fdset;\n            FD_ZERO(&fdset);\n            FD_SET(hSocket, &fdset);\n            int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);\n            if (nRet == 0)\n            {\n                LogPrint(BCLog::NET, \"connection to %s timeout\\n\", addrConnect.ToString());\n                CloseSocket(hSocket);\n                return false;\n            }\n            if (nRet == SOCKET_ERROR)\n            {\n                LogPrintf(\"select() for %s failed: %s\\n\", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));\n                CloseSocket(hSocket);\n                return false;\n            }\n            socklen_t nRetSize = sizeof(nRet);\n#ifdef WIN32\n            if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)\n#else\n            if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)\n#endif\n            {\n                LogPrintf(\"getsockopt() for %s failed: %s\\n\", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));\n                CloseSocket(hSocket);\n                return false;\n            }\n            if (nRet != 0)\n            {\n                LogPrintf(\"connect() to %s failed after select(): %s\\n\", addrConnect.ToString(), NetworkErrorString(nRet));\n                CloseSocket(hSocket);\n                return false;\n            }\n        }\n#ifdef WIN32\n        else if (WSAGetLastError() != WSAEISCONN)\n#else\n        else\n#endif\n        {\n            LogPrintf(\"connect() to %s failed: %s\\n\", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));\n            CloseSocket(hSocket);\n            return false;\n        }\n    }\n\n    hSocketRet = hSocket;\n    return true;\n}\n\nbool SetProxy(enum Network net, const proxyType &addrProxy) {\n    assert(net >= 0 && net < NET_MAX);\n    if (!addrProxy.IsValid())\n        return false;\n    LOCK(cs_proxyInfos);\n    proxyInfo[net] = addrProxy;\n    return true;\n}\n\nbool GetProxy(enum Network net, proxyType &proxyInfoOut) {\n    assert(net >= 0 && net < NET_MAX);\n    LOCK(cs_proxyInfos);\n    if (!proxyInfo[net].IsValid())\n        return false;\n    proxyInfoOut = proxyInfo[net];\n    return true;\n}\n\nbool SetNameProxy(const proxyType &addrProxy) {\n    if (!addrProxy.IsValid())\n        return false;\n    LOCK(cs_proxyInfos);\n    nameProxy = addrProxy;\n    return true;\n}\n\nbool GetNameProxy(proxyType &nameProxyOut) {\n    LOCK(cs_proxyInfos);\n    if(!nameProxy.IsValid())\n        return false;\n    nameProxyOut = nameProxy;\n    return true;\n}\n\nbool HaveNameProxy() {\n    LOCK(cs_proxyInfos);\n    return nameProxy.IsValid();\n}\n\nbool IsProxy(const CNetAddr &addr) {\n    LOCK(cs_proxyInfos);\n    for (int i = 0; i < NET_MAX; i++) {\n        if (addr == (CNetAddr)proxyInfo[i].proxy)\n            return true;\n    }\n    return false;\n}\n\nstatic bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, socket_t& socketRet, int nTimeout, bool *outProxyConnectionFailed)\n{\n    SOCKET hSocket = INVALID_SOCKET;\n    // first connect to proxy server\n    if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) {\n        if (outProxyConnectionFailed)\n            *outProxyConnectionFailed = true;\n        return false;\n    }\n    // do socks negotiation\n    if (proxy.randomize_credentials) {\n        ProxyCredentials random_auth;\n        static std::atomic_int counter;\n        random_auth.username = random_auth.password = strprintf(\"%i\", counter++);\n        if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))\n            return false;\n    } else {\n        if (!Socks5(strDest, (unsigned short)port, 0, hSocket))\n            return false;\n    }\n\n    auto protocol = proxy.proxy.GetAddress().is_v4() ? boost::asio::ip::tcp::v4() : boost::asio::ip::tcp::v6();\n    socketRet.assign(protocol, hSocket);\n    return true;\n}\n\nbool static ConnectSocketDirectly(const CService &addrConnect, socket_t& socketRet, int nTimeout)\n{\n    socket_t socket(get_io_context());\n\n    std::future<void> future = socket.async_connect(addrConnect.GetSockAddr(), boost::asio::use_future);\n    std::future_status status = future.wait_for(std::chrono::milliseconds(nTimeout));\n    if (status == std::future_status::timeout) {\n        LogPrint(BCLog::NET, \"connection to %s timeout\\n\", addrConnect.ToString());\n        return false;\n    }\n    else {\n        try {\n            future.get();\n            LogPrint(BCLog::NET, \"connected to %s\\n\", addrConnect.ToString());\n            socket.set_option(boost::asio::ip::tcp::no_delay(true));\n        }\n        catch (const boost::system::system_error& err) {\n            LogPrint(BCLog::NET, \"connection to %s failed: %s\\n\", addrConnect.ToString(), err.what());\n            return false;\n        }\n    }\n\n    socketRet = std::move(socket);\n    return true;\n}\n\nbool ConnectSocket(const CService &addrDest, socket_t& socketRet, int nTimeout, bool *outProxyConnectionFailed)\n{\n    proxyType proxy;\n    if (outProxyConnectionFailed)\n        *outProxyConnectionFailed = false;\n\n    if (GetProxy(addrDest.GetNetwork(), proxy))\n        return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), socketRet, nTimeout, outProxyConnectionFailed);\n    else // no proxy needed (none set for target network)\n        return ConnectSocketDirectly(addrDest, socketRet, nTimeout);\n}\n\nbool ConnectSocketByName(CService &addr, socket_t& socketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)\n{\n    std::string strDest;\n    int port = portDefault;\n\n    if (outProxyConnectionFailed)\n        *outProxyConnectionFailed = false;\n\n    SplitHostPort(std::string(pszDest), port, strDest);\n\n    proxyType proxy;\n    GetNameProxy(proxy);\n\n    std::vector<CService> addrResolved;\n    if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {\n        if (addrResolved.size() > 0) {\n            addr = addrResolved[GetRand(addrResolved.size())];\n            return ConnectSocket(addr, socketRet, nTimeout);\n        }\n    }\n\n    addr = CService();\n\n    if (!HaveNameProxy())\n        return false;\n    return ConnectThroughProxy(proxy, strDest, port, socketRet, nTimeout, outProxyConnectionFailed);\n}\n\nbool LookupSubNet(const char* pszName, CSubNet& ret)\n{\n    std::string strSubnet(pszName);\n    size_t slash = strSubnet.find_last_of('/');\n    std::vector<CNetAddr> vIP;\n\n    std::string strAddress = strSubnet.substr(0, slash);\n    if (LookupHost(strAddress.c_str(), vIP, 1, false))\n    {\n        CNetAddr network = vIP[0];\n        if (slash != strSubnet.npos)\n        {\n            std::string strNetmask = strSubnet.substr(slash + 1);\n            int32_t n;\n            // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n\n            if (ParseInt32(strNetmask, &n)) { // If valid number, assume /24 syntax\n                ret = CSubNet(network, n);\n                return ret.IsValid();\n            }\n            else // If not a valid number, try full netmask syntax\n            {\n                // Never allow lookup for netmask\n                if (LookupHost(strNetmask.c_str(), vIP, 1, false)) {\n                    ret = CSubNet(network, vIP[0]);\n                    return ret.IsValid();\n                }\n            }\n        }\n        else\n        {\n            ret = CSubNet(network);\n            return ret.IsValid();\n        }\n    }\n    return false;\n}\n\n#ifdef WIN32\nstd::string NetworkErrorString(int err)\n{\n    char buf[256];\n    buf[0] = 0;\n    if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,\n            NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n            buf, sizeof(buf), NULL))\n    {\n        return strprintf(\"%s (%d)\", buf, err);\n    }\n    else\n    {\n        return strprintf(\"Unknown error (%d)\", err);\n    }\n}\n#else\nstd::string NetworkErrorString(int err)\n{\n    char buf[256];\n    buf[0] = 0;\n    /* Too bad there are two incompatible implementations of the\n     * thread-safe strerror. */\n    const char *s;\n#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */\n    s = strerror_r(err, buf, sizeof(buf));\n#else /* POSIX variant always returns message in buffer */\n    s = buf;\n    if (strerror_r(err, buf, sizeof(buf)))\n        buf[0] = 0;\n#endif\n    return strprintf(\"%s (%d)\", s, err);\n}\n#endif\n\nbool CloseSocket(SOCKET& hSocket)\n{\n    if (hSocket == INVALID_SOCKET)\n        return false;\n#ifdef WIN32\n    int ret = closesocket(hSocket);\n#else\n    int ret = close(hSocket);\n#endif\n    hSocket = INVALID_SOCKET;\n    return ret != SOCKET_ERROR;\n}\n\nbool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)\n{\n    if (fNonBlocking) {\n#ifdef WIN32\n        u_long nOne = 1;\n        if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {\n#else\n        int fFlags = fcntl(hSocket, F_GETFL, 0);\n        if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {\n#endif\n            CloseSocket(hSocket);\n            return false;\n        }\n    } else {\n#ifdef WIN32\n        u_long nZero = 0;\n        if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {\n#else\n        int fFlags = fcntl(hSocket, F_GETFL, 0);\n        if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {\n#endif\n            CloseSocket(hSocket);\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool SetSocketNoDelay(SOCKET& hSocket)\n{\n    int set = 1;\n    int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));\n    return rc == 0;\n}\n\nvoid InterruptSocks5(bool interrupt)\n{\n    interruptSocks5Recv = interrupt;\n}\n"
  },
  {
    "path": "src/netbase.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef NETBASE_H\n#define NETBASE_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"compat.h\"\n#include \"netaddress.h\"\n#include \"serialize.h\"\n\n#include <stdint.h>\n#include <string>\n#include <vector>\n\n// fixme: (BOOST) - Workaround for boost on macOS (when using newer clang) build issue (not detecting string_view properly)\n// Remove this when addressed by Boost's ASIO config.\n// https://www.boost.org/doc/libs/1_67_0/boost/asio/detail/config.hpp\n// Standard library support for std::string_view.\n#define BOOST_ASIO_HAS_STD_STRING_VIEW 1\n#define BOOST_ASIO_DISABLE_STD_STRING_VIEW 1\n#include <boost/asio.hpp>\n\nextern int nConnectTimeout;\nextern bool fNameLookup;\n\n//! -timeout default\nstatic const int DEFAULT_CONNECT_TIMEOUT = 5000;\n//! -dns default\nstatic const int DEFAULT_NAME_LOOKUP = true;\n\nclass proxyType\n{\npublic:\n    proxyType(): randomize_credentials(false) {}\n    proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}\n\n    bool IsValid() const { return proxy.IsValid(); }\n\n    CService proxy;\n    bool randomize_credentials;\n};\n\ntypedef boost::asio::ip::tcp::socket socket_t;\n\nenum Network ParseNetwork(std::string net);\nstd::string GetNetworkName(enum Network net);\nvoid SplitHostPort(std::string in, int &portOut, std::string &hostOut);\nbool SetProxy(enum Network net, const proxyType &addrProxy);\nbool GetProxy(enum Network net, proxyType &proxyInfoOut);\nbool IsProxy(const CNetAddr &addr);\nbool SetNameProxy(const proxyType &addrProxy);\nbool HaveNameProxy();\nbool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup);\nbool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup);\nbool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup);\nbool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);\nCService LookupNumeric(const char *pszName, int portDefault = 0);\nbool LookupSubNet(const char *pszName, CSubNet& subnet);\nbool ConnectSocket(const CService &addr, socket_t& socketRet, int nTimeout, bool *outProxyConnectionFailed = 0);\nbool ConnectSocketByName(CService &addr, socket_t& socketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = 0);\n/** Return readable error string for a network error code */\nstd::string NetworkErrorString(int err);\n/** Close socket and set hSocket to INVALID_SOCKET */\nbool CloseSocket(SOCKET& hSocket);\n/** Disable or enable blocking-mode for a socket */\nbool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking);\n/** Set the TCP_NODELAY flag on a socket */\nbool SetSocketNoDelay(SOCKET& hSocket);\n/**\n * Convert milliseconds to a struct timeval for e.g. select.\n */\nstruct timeval MillisToTimeval(int64_t nTimeout);\nvoid InterruptSocks5(bool interrupt);\n\nboost::asio::io_context& get_io_context();\n\n#endif\n"
  },
  {
    "path": "src/netmessagemaker.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef NETMESSAGEMAKER_H\n#define NETMESSAGEMAKER_H\n\n#include \"net.h\"\n#include \"serialize.h\"\n\nclass CNetMsgMaker\n{\npublic:\n    CNetMsgMaker(int nVersionIn, int nExtraFlagsIn = 0) : nVersion(nVersionIn), nExtraFlags(nExtraFlagsIn){}\n\n    template <typename... Args>\n    CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const\n    {\n        CSerializedNetMsg msg;\n        msg.command = std::move(sCommand);\n        CVectorWriter{ SER_NETWORK, nFlags | nVersion | nExtraFlags, msg.data, 0, std::forward<Args>(args)... };\n        return msg;\n    }\n\n    template <typename... Args>\n    CSerializedNetMsg Make(std::string sCommand, Args&&... args) const\n    {\n        return Make(0, std::move(sCommand), std::forward<Args>(args)...);\n    }\n\nprivate:\n    const int nVersion;\n    const int nExtraFlags;\n};\n\n#endif\n"
  },
  {
    "path": "src/node/context.cpp",
    "content": "// Copyright (c) 2019-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"context.h\"\n\nnamespace node {\nNodeContext::NodeContext() {}\nNodeContext::~NodeContext() {}\n} // namespace node\n"
  },
  {
    "path": "src/node/context.h",
    "content": "// Copyright (c) 2019-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_NODE_CONTEXT_H\n#define CORE_NODE_CONTEXT_H\n\n#include \"scheduler.h\"\n\n\nnamespace node {\n//! NodeContext struct containing references to chain state and connection\n//! state.\n//!\n//! This is used by init, rpc, and test code to pass object references around\n//! without needing to declare the same variables and parameters repeatedly, or\n//! to use globals. More variables could be added to this struct (particularly\n//! references to validation objects) to eliminate use of globals\n//! and make code more modular and testable. The struct isn't intended to have\n//! any member functions. It should just be a collection of references that can\n//! be used without pulling in unwanted dependencies or functionality.\nstruct NodeContext {\n    std::unique_ptr<CScheduler> scheduler;\n\n    //! Declare default constructor and destructor that are not inline, so code\n    //! instantiating the NodeContext struct doesn't need to #include class\n    //! definitions for all the unique_ptr members.\n    NodeContext();\n    ~NodeContext();\n};\n} // namespace node\n\n#endif // BITCOIN_NODE_CONTEXT_H\n"
  },
  {
    "path": "src/noui.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n#include \"noui.h\"\n\n#include \"ui_interface.h\"\n#include \"util.h\"\n\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n\n#include <cstdio>\n#include <stdint.h>\n#include <string>\n\n#include <boost/bind/bind.hpp> \nusing namespace boost::placeholders;\n\nstatic bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)\n{\n    bool fSecure = style & CClientUIInterface::SECURE;\n    style &= ~CClientUIInterface::SECURE;\n\n    std::string strCaption;\n    // Check for usage of predefined caption\n    switch (style) {\n    case CClientUIInterface::MSG_ERROR:\n        strCaption += _(\"Error\");\n        break;\n    case CClientUIInterface::MSG_WARNING:\n        strCaption += _(\"Warning\");\n        break;\n    case CClientUIInterface::MSG_INFORMATION:\n        strCaption += _(\"Information\");\n        break;\n    default:\n        strCaption += caption; // Use supplied caption (can be empty)\n    }\n\n    if (!fSecure)\n        LogPrintf(\"%s: %s\\n\", strCaption, message);\n    fprintf(stderr, \"%s: %s\\n\", strCaption.c_str(), message.c_str());\n    return false;\n}\n\nstatic bool noui_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)\n{\n    return noui_ThreadSafeMessageBox(message, caption, style);\n}\n\nstatic void noui_InitMessage(const std::string& message)\n{\n    LogPrintf(\"init message: %s\\n\", message);\n}\n\n#ifdef ENABLE_WALLET\nstatic void NotifyRequestUnlockS(CWallet* wallet, std::string reason)\n{\n    SecureString passwd = GetArg(\"-unlockpasswd\", \"\").c_str();\n    if (!passwd.empty())\n    {\n        if (!wallet->Unlock(passwd))\n        {\n            fprintf(stderr, \"Wallet requested unlock but -unlockpasswd was invalid - please unlock via RPC or in the case of an upgrade temporarily set -unlockpasswd in \" GLOBAL_APPNAME \".conf: reason [%s]\\n\", reason.c_str());\n            return;\n        }\n    }\n    fprintf(stderr, \"Wallet requested unlock but could not unlock - please unlock via RPC or in the case of an upgrade temporarily set -unlockpasswd in \" GLOBAL_APPNAME \".conf: reason [%s]\\n\", reason.c_str());\n}\n\nstatic void NotifyRequestUnlockWithCallbackS(CWallet* wallet, std::string reason, std::function<void (void)> successCallback)\n{\n    SecureString passwd = GetArg(\"-unlockpasswd\", \"\").c_str();\n    if (!passwd.empty())\n    {\n        if (!wallet->Unlock(passwd))\n        {\n            fprintf(stderr, \"Wallet requested unlock but -unlockpasswd was invalid - please unlock via RPC or in the case of an upgrade temporarily set -unlockpasswd in \" GLOBAL_APPNAME \".conf: reason for request [%s]\\n\", reason.c_str());\n            return;\n        }\n    }\n    else\n    {\n        fprintf(stderr, \"Wallet requested unlock but could not unlock - please unlock via RPC or in the case of an upgrade temporarily set -unlockpasswd in \" GLOBAL_APPNAME \".conf: reason for request [%s]\\n\", reason.c_str());\n        return;\n    }\n    successCallback();\n}\n#endif\n\nvoid noui_connect()\n{\n    // Connect daemon signal handlers\n    uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);\n    uiInterface.ThreadSafeQuestion.connect(noui_ThreadSafeQuestion);\n    uiInterface.InitMessage.connect(noui_InitMessage);\n\n    #ifdef ENABLE_WALLET\n    uiInterface.RequestUnlock.connect(boost::bind(NotifyRequestUnlockS, _1, _2));\n    uiInterface.RequestUnlockWithCallback.connect(boost::bind(NotifyRequestUnlockWithCallbackS, _1, _2, _3));\n    #endif\n}\n"
  },
  {
    "path": "src/noui.h",
    "content": "// Copyright (c) 2013-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_NOUI_H\n#define CORE_NOUI_H\n\nextern void noui_connect();\n\n#endif\n"
  },
  {
    "path": "src/obj/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "src/obj-test/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "src/policy/feerate.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"appname.h\"\n#include \"feerate.h\"\n\n#include \"tinyformat.h\"\n\nconst std::string CURRENCY_UNIT = GLOBAL_COIN_CODE;\n\nCFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)\n{\n    assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));\n    int64_t nSize = int64_t(nBytes_);\n\n    if (nSize > 0)\n        nSatoshisPerK = nFeePaid * 1000 / nSize;\n    else\n        nSatoshisPerK = 0;\n}\n\nCAmount CFeeRate::GetFee(size_t nBytes_) const\n{\n    assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));\n    int64_t nSize = int64_t(nBytes_);\n\n    CAmount nFee = nSatoshisPerK * nSize / 1000;\n\n    if (nFee == 0 && nSize != 0) {\n        if (nSatoshisPerK > 0)\n            nFee = CAmount(1);\n        if (nSatoshisPerK < 0)\n            nFee = CAmount(-1);\n    }\n\n    return nFee;\n}\n\nstd::string CFeeRate::ToString() const\n{\n    return strprintf(\"%d.%08d %s/kB\", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);\n}\n"
  },
  {
    "path": "src/policy/feerate.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef POLICY_FEERATE_H\n#define POLICY_FEERATE_H\n\n#include \"amount.h\"\n#include \"serialize.h\"\n\n#include <string>\n\nextern const std::string CURRENCY_UNIT;\n\n/**\n * Fee rate in satoshis per kilobyte: CAmount / kB\n */\nclass CFeeRate\n{\nprivate:\n    CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes\npublic:\n    /** Fee rate of 0 satoshis per kB */\n    CFeeRate() : nSatoshisPerK(0) { }\n    explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }\n    /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/\n    CFeeRate(const CAmount& nFeePaid, size_t nBytes);\n    CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }\n    /**\n     * Return the fee in satoshis for the given size in bytes.\n     */\n    CAmount GetFee(size_t nBytes) const;\n    /**\n     * Return the fee in satoshis for a size of 1000 bytes\n     */\n    CAmount GetFeePerK() const { return GetFee(1000); }\n    friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }\n    friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }\n    friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }\n    friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }\n    friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }\n    CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }\n    std::string ToString() const;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(nSatoshisPerK);\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/policy/fees.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n\n#include \"amount.h\"\n#include \"clientversion.h\"\n#include \"primitives/transaction.h\"\n#include \"random.h\"\n#include \"streams.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n\nstatic constexpr double INF_FEERATE = 1e99;\n\n/**\n * We will instantiate an instance of this class to track transactions that were\n * included in a block. We will lump transactions into a bucket according to their\n * approximate feerate and then track how long it took for those txs to be included in a block\n *\n * The tracking of unconfirmed (mempool) transactions is completely independent of the\n * historical tracking of transactions that have been confirmed in a block.\n */\nclass TxConfirmStats\n{\nprivate:\n    //Define the buckets we will group transactions into\n    const std::vector<double>& buckets;              // The upper-bound of the range for the bucket (inclusive)\n    const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket\n\n    // For each bucket X:\n    // Count the total # of txs in each bucket\n    // Track the historical moving average of this total over blocks\n    std::vector<double> txCtAvg;\n\n    // Count the total # of txs confirmed within Y blocks in each bucket\n    // Track the historical moving average of theses totals over blocks\n    std::vector<std::vector<double>> confAvg; // confAvg[Y][X]\n\n    // Track moving avg of txs which have been evicted from the mempool\n    // after failing to be confirmed within Y blocks\n    std::vector<std::vector<double>> failAvg; // failAvg[Y][X]\n\n    // Sum the total feerate of all tx's in each bucket\n    // Track the historical moving average of this total over blocks\n    std::vector<double> avg;\n\n    // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X\n    // Combine the total value with the tx counts to calculate the avg feerate per bucket\n\n    double decay;\n\n    // Resolution (# of blocks) with which confirmations are tracked\n    unsigned int scale;\n\n    // Mempool counts of outstanding transactions\n    // For each bucket X, track the number of transactions in the mempool\n    // that are unconfirmed for each possible confirmation value Y\n    std::vector<std::vector<int> > unconfTxs;  //unconfTxs[Y][X]\n    // transactions still unconfirmed after GetMaxConfirms for each bucket\n    std::vector<int> oldUnconfTxs;\n\n    void resizeInMemoryCounters(size_t newbuckets);\n\npublic:\n    /**\n     * Create new TxConfirmStats. This is called by BlockPolicyEstimator's\n     * constructor with default values.\n     * @param defaultBuckets contains the upper limits for the bucket boundaries\n     * @param maxConfirms max number of confirms to track\n     * @param decay how much to decay the historical moving average per block\n     */\n    TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,\n                   unsigned int maxPeriods, double decay, unsigned int scale);\n\n    /** Roll the circular buffer for unconfirmed txs*/\n    void ClearCurrent(unsigned int nBlockHeight);\n\n    /**\n     * Record a new transaction data point in the current block stats\n     * @param blocksToConfirm the number of blocks it took this transaction to confirm\n     * @param val the feerate of the transaction\n     * @warning blocksToConfirm is 1-based and has to be >= 1\n     */\n    void Record(int blocksToConfirm, double val);\n\n    /** Record a new transaction entering the mempool*/\n    unsigned int NewTx(unsigned int nBlockHeight, double val);\n\n    /** Remove a transaction from mempool tracking stats*/\n    void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,\n                  unsigned int bucketIndex, bool inBlock);\n\n    /** Update our estimates by decaying our historical moving average and updating\n        with the data gathered from the current block */\n    void UpdateMovingAverages();\n\n    /**\n     * Calculate a feerate estimate.  Find the lowest value bucket (or range of buckets\n     * to make sure we have enough data points) whose transactions still have sufficient likelihood\n     * of being confirmed within the target number of confirmations\n     * @param confTarget target number of confirmations\n     * @param sufficientTxVal required average number of transactions per block in a bucket range\n     * @param minSuccess the success probability we require\n     * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR\n     *        return the highest feerate such that all lower values fail minSuccess\n     * @param nBlockHeight the current block height\n     */\n    double EstimateMedianVal(int confTarget, double sufficientTxVal,\n                             double minSuccess, bool requireGreater, unsigned int nBlockHeight,\n                             EstimationResult *result = nullptr) const;\n\n    /** Return the max number of confirms we're tracking */\n    unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }\n\n    /** Write state of estimation data to a file*/\n    void Write(CAutoFile& fileout) const;\n\n    /**\n     * Read saved state of estimation data from a file and replace all internal data structures and\n     * variables with this state.\n     */\n    void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);\n};\n\n\nTxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,\n                                const std::map<double, unsigned int>& defaultBucketMap,\n                               unsigned int maxPeriods, double _decay, unsigned int _scale)\n    : buckets(defaultBuckets), bucketMap(defaultBucketMap)\n{\n    decay = _decay;\n    scale = _scale;\n    confAvg.resize(maxPeriods);\n    for (unsigned int i = 0; i < maxPeriods; i++) {\n        confAvg[i].resize(buckets.size());\n    }\n    failAvg.resize(maxPeriods);\n    for (unsigned int i = 0; i < maxPeriods; i++) {\n        failAvg[i].resize(buckets.size());\n    }\n\n    txCtAvg.resize(buckets.size());\n    avg.resize(buckets.size());\n\n    resizeInMemoryCounters(buckets.size());\n}\n\nvoid TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {\n    // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.\n    unconfTxs.resize(GetMaxConfirms());\n    for (unsigned int i = 0; i < unconfTxs.size(); i++) {\n        unconfTxs[i].resize(newbuckets);\n    }\n    oldUnconfTxs.resize(newbuckets);\n}\n\n// Roll the unconfirmed txs circular buffer\nvoid TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)\n{\n    for (unsigned int j = 0; j < buckets.size(); j++) {\n        oldUnconfTxs[j] += unconfTxs[nBlockHeight%unconfTxs.size()][j];\n        unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;\n    }\n}\n\n\nvoid TxConfirmStats::Record(int blocksToConfirm, double val)\n{\n    // blocksToConfirm is 1-based\n    if (blocksToConfirm < 1)\n        return;\n    int periodsToConfirm = (blocksToConfirm + scale - 1)/scale;\n    unsigned int bucketindex = bucketMap.lower_bound(val)->second;\n    for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {\n        confAvg[i - 1][bucketindex]++;\n    }\n    txCtAvg[bucketindex]++;\n    avg[bucketindex] += val;\n}\n\nvoid TxConfirmStats::UpdateMovingAverages()\n{\n    for (unsigned int j = 0; j < buckets.size(); j++) {\n        for (unsigned int i = 0; i < confAvg.size(); i++)\n            confAvg[i][j] = confAvg[i][j] * decay;\n        for (unsigned int i = 0; i < failAvg.size(); i++)\n            failAvg[i][j] = failAvg[i][j] * decay;\n        avg[j] = avg[j] * decay;\n        txCtAvg[j] = txCtAvg[j] * decay;\n    }\n}\n\n// returns -1 on error conditions\ndouble TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,\n                                         double successBreakPoint, bool requireGreater,\n                                         unsigned int nBlockHeight, EstimationResult *result) const\n{\n    // Counters for a bucket (or range of buckets)\n    double nConf = 0; // Number of tx's confirmed within the confTarget\n    double totalNum = 0; // Total number of tx's that were ever confirmed\n    int extraNum = 0;  // Number of tx's still in mempool for confTarget or longer\n    double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget\n    int periodTarget = (confTarget + scale - 1)/scale;\n\n    int maxbucketindex = buckets.size() - 1;\n\n    // requireGreater means we are looking for the lowest feerate such that all higher\n    // values pass, so we start at maxbucketindex (highest feerate) and look at successively\n    // smaller buckets until we reach failure.  Otherwise, we are looking for the highest\n    // feerate such that all lower values fail, and we go in the opposite direction.\n    unsigned int startbucket = requireGreater ? maxbucketindex : 0;\n    int step = requireGreater ? -1 : 1;\n\n    // We'll combine buckets until we have enough samples.\n    // The near and far variables will define the range we've combined\n    // The best variables are the last range we saw which still had a high\n    // enough confirmation rate to count as success.\n    // The cur variables are the current range we're counting.\n    unsigned int curNearBucket = startbucket;\n    unsigned int bestNearBucket = startbucket;\n    unsigned int curFarBucket = startbucket;\n    unsigned int bestFarBucket = startbucket;\n\n    bool foundAnswer = false;\n    unsigned int bins = unconfTxs.size();\n    bool newBucketRange = true;\n    bool passing = true;\n    EstimatorBucket passBucket;\n    EstimatorBucket failBucket;\n\n    // Start counting from highest(default) or lowest feerate transactions\n    for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {\n        if (newBucketRange) {\n            curNearBucket = bucket;\n            newBucketRange = false;\n        }\n        curFarBucket = bucket;\n        nConf += confAvg[periodTarget - 1][bucket];\n        totalNum += txCtAvg[bucket];\n        failNum += failAvg[periodTarget - 1][bucket];\n        for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)\n            extraNum += unconfTxs[(nBlockHeight - confct)%bins][bucket];\n        extraNum += oldUnconfTxs[bucket];\n        // If we have enough transaction data points in this range of buckets,\n        // we can test for success\n        // (Only count the confirmed data points, so that each confirmation count\n        // will be looking at the same amount of data and same bucket breaks)\n        if (totalNum >= sufficientTxVal / (1 - decay)) {\n            double curPct = nConf / (totalNum + failNum + extraNum);\n\n            // Check to see if we are no longer getting confirmed at the success rate\n            if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint)) {\n                if (passing) {\n                    // First time we hit a failure record the failed bucket\n                    unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);\n                    unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);\n                    failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;\n                    failBucket.end = buckets[failMaxBucket];\n                    failBucket.withinTarget = nConf;\n                    failBucket.totalConfirmed = totalNum;\n                    failBucket.inMempool = extraNum;\n                    failBucket.leftMempool = failNum;\n                    passing = false;\n                }\n                continue;\n            }\n            // Otherwise update the cumulative stats, and the bucket variables\n            // and reset the counters\n            else {\n                failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing\n                foundAnswer = true;\n                passing = true;\n                passBucket.withinTarget = nConf;\n                nConf = 0;\n                passBucket.totalConfirmed = totalNum;\n                totalNum = 0;\n                passBucket.inMempool = extraNum;\n                passBucket.leftMempool = failNum;\n                failNum = 0;\n                extraNum = 0;\n                bestNearBucket = curNearBucket;\n                bestFarBucket = curFarBucket;\n                newBucketRange = true;\n            }\n        }\n    }\n\n    double median = -1;\n    double txSum = 0;\n\n    // Calculate the \"average\" feerate of the best bucket range that met success conditions\n    // Find the bucket with the median transaction and then report the average feerate from that bucket\n    // This is a compromise between finding the median which we can't since we don't save all tx's\n    // and reporting the average which is less accurate\n    unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);\n    unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);\n    for (unsigned int j = minBucket; j <= maxBucket; j++) {\n        txSum += txCtAvg[j];\n    }\n    if (foundAnswer && txSum != 0) {\n        txSum = txSum / 2;\n        for (unsigned int j = minBucket; j <= maxBucket; j++) {\n            if (txCtAvg[j] < txSum)\n                txSum -= txCtAvg[j];\n            else { // we're in the right bucket\n                median = avg[j] / txCtAvg[j];\n                break;\n            }\n        }\n\n        passBucket.start = minBucket ? buckets[minBucket-1] : 0;\n        passBucket.end = buckets[maxBucket];\n    }\n\n    // If we were passing until we reached last few buckets with insufficient data, then report those as failed\n    if (passing && !newBucketRange) {\n        unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);\n        unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);\n        failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;\n        failBucket.end = buckets[failMaxBucket];\n        failBucket.withinTarget = nConf;\n        failBucket.totalConfirmed = totalNum;\n        failBucket.inMempool = extraNum;\n        failBucket.leftMempool = failNum;\n    }\n\n    LogPrint(BCLog::ESTIMATEFEE, \"FeeEst: %d %s%.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\\n\",\n             confTarget, requireGreater ? \">\" : \"<\", 100.0 * successBreakPoint, decay,\n             median, passBucket.start, passBucket.end,\n             100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool),\n             passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,\n             failBucket.start, failBucket.end,\n             100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool),\n             failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);\n\n\n    if (result) {\n        result->pass = passBucket;\n        result->fail = failBucket;\n        result->decay = decay;\n        result->scale = scale;\n    }\n    return median;\n}\n\nvoid TxConfirmStats::Write(CAutoFile& fileout) const\n{\n    fileout << decay;\n    fileout << scale;\n    fileout << COMPACTSIZEVECTOR(avg);\n    fileout << COMPACTSIZEVECTOR(txCtAvg);\n    fileout << COMPACTSIZEVECTOR(confAvg);\n    fileout << COMPACTSIZEVECTOR(failAvg);\n}\n\nvoid TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)\n{\n    // Read data file and do some very basic sanity checking\n    // buckets and bucketMap are not updated yet, so don't access them\n    // If there is a read failure, we'll just discard this entire object anyway\n    size_t maxConfirms, maxPeriods;\n\n    // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor\n    if (nFileVersion >= 149900) {\n        filein >> decay;\n        if (decay <= 0 || decay >= 1) {\n            throw std::runtime_error(\"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)\");\n        }\n        filein >> scale;\n    }\n\n    filein >> COMPACTSIZEVECTOR(avg);\n    if (avg.size() != numBuckets) {\n        throw std::runtime_error(\"Corrupt estimates file. Mismatch in feerate average bucket count\");\n    }\n    filein >> COMPACTSIZEVECTOR(txCtAvg);\n    if (txCtAvg.size() != numBuckets) {\n        throw std::runtime_error(\"Corrupt estimates file. Mismatch in tx count bucket count\");\n    }\n    filein >> COMPACTSIZEVECTOR(confAvg);\n    maxPeriods = confAvg.size();\n    maxConfirms = scale * maxPeriods;\n\n    if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week\n        throw std::runtime_error(\"Corrupt estimates file.  Must maintain estimates for between 1 and 1008 (one week) confirms\");\n    }\n    for (unsigned int i = 0; i < maxPeriods; i++) {\n        if (confAvg[i].size() != numBuckets) {\n            throw std::runtime_error(\"Corrupt estimates file. Mismatch in feerate conf average bucket count\");\n        }\n    }\n\n    if (nFileVersion >= 149900) {\n        filein >> COMPACTSIZEVECTOR(failAvg);\n        if (maxPeriods != failAvg.size()) {\n            throw std::runtime_error(\"Corrupt estimates file. Mismatch in confirms tracked for failures\");\n        }\n        for (unsigned int i = 0; i < maxPeriods; i++) {\n            if (failAvg[i].size() != numBuckets) {\n                throw std::runtime_error(\"Corrupt estimates file. Mismatch in one of failure average bucket counts\");\n            }\n        }\n    } else {\n        failAvg.resize(confAvg.size());\n        for (unsigned int i = 0; i < failAvg.size(); i++) {\n            failAvg[i].resize(numBuckets);\n        }\n    }\n\n    // Resize the current block variables which aren't stored in the data file\n    // to match the number of confirms and buckets\n    resizeInMemoryCounters(numBuckets);\n\n    LogPrint(BCLog::ESTIMATEFEE, \"Reading estimates: %u buckets counting confirms up to %u blocks\\n\",\n             numBuckets, maxConfirms);\n}\n\nunsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)\n{\n    unsigned int bucketindex = bucketMap.lower_bound(val)->second;\n    unsigned int blockIndex = nBlockHeight % unconfTxs.size();\n    unconfTxs[blockIndex][bucketindex]++;\n    return bucketindex;\n}\n\nvoid TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)\n{\n    //nBestSeenHeight is not updated yet for the new block\n    int blocksAgo = nBestSeenHeight - entryHeight;\n    if (nBestSeenHeight == 0)  // the BlockPolicyEstimator hasn't seen any blocks yet\n        blocksAgo = 0;\n    if (blocksAgo < 0) {\n        LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy error, blocks ago is negative for mempool tx\\n\");\n        return;  //This can't happen because we call this with our best seen height, no entries can have higher\n    }\n\n    if (blocksAgo >= (int)unconfTxs.size()) {\n        if (oldUnconfTxs[bucketindex] > 0) {\n            oldUnconfTxs[bucketindex]--;\n        } else {\n            LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\\n\",\n                     bucketindex);\n        }\n    }\n    else {\n        unsigned int blockIndex = entryHeight % unconfTxs.size();\n        if (unconfTxs[blockIndex][bucketindex] > 0) {\n            unconfTxs[blockIndex][bucketindex]--;\n        } else {\n            LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\\n\",\n                     blockIndex, bucketindex);\n        }\n    }\n    if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period\n        unsigned int periodsAgo = blocksAgo / scale;\n        for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {\n            failAvg[i][bucketindex]++;\n        }\n    }\n}\n\n// This function is called from CTxMemPool::removeUnchecked to ensure\n// txs removed from the mempool for any reason are no longer\n// tracked. Txs that were part of a block have already been removed in\n// processBlockTx to ensure they are never double tracked, but it is\n// of no harm to try to remove them again.\nbool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)\n{\n    LOCK(cs_feeEstimator);\n    std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);\n    if (pos != mapMemPoolTxs.end()) {\n        feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);\n        shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);\n        longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);\n        mapMemPoolTxs.erase(hash);\n        return true;\n    } else {\n        return false;\n    }\n}\n\nCBlockPolicyEstimator::CBlockPolicyEstimator()\n    : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)\n{\n    static_assert(MIN_BUCKET_FEERATE > 0, \"Min feerate must be nonzero\");\n    size_t bucketIndex = 0;\n    for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {\n        buckets.push_back(bucketBoundary);\n        bucketMap[bucketBoundary] = bucketIndex;\n    }\n    buckets.push_back(INF_FEERATE);\n    bucketMap[INF_FEERATE] = bucketIndex;\n    assert(bucketMap.size() == buckets.size());\n\n    feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);\n    shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);\n    longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);\n}\n\nCBlockPolicyEstimator::~CBlockPolicyEstimator()\n{\n    delete feeStats;\n    delete shortStats;\n    delete longStats;\n}\n\nvoid CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)\n{\n    LOCK(cs_feeEstimator);\n    unsigned int txHeight = entry.GetHeight();\n    uint256 hash = entry.GetTx().GetHash();\n    if (mapMemPoolTxs.count(hash)) {\n        LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy error mempool tx %s already being tracked\\n\",\n                 hash.ToString().c_str());\n\treturn;\n    }\n\n    if (txHeight != nBestSeenHeight) {\n        // Ignore side chains and re-orgs; assuming they are random they don't\n        // affect the estimate.  We'll potentially double count transactions in 1-block reorgs.\n        // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip().\n        // It will be synced next time a block is processed.\n        return;\n    }\n\n    // Only want to be updating estimates when our blockchain is synced,\n    // otherwise we'll miscalculate how many blocks its taking to get included.\n    if (!validFeeEstimate) {\n        untrackedTxs++;\n        return;\n    }\n    trackedTxs++;\n\n    // Feerates are stored and reported as NLG-per-kb:\n    CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());\n\n    mapMemPoolTxs[hash].blockHeight = txHeight;\n    unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());\n    mapMemPoolTxs[hash].bucketIndex = bucketIndex;\n    unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());\n    assert(bucketIndex == bucketIndex2);\n    unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());\n    assert(bucketIndex == bucketIndex3);\n}\n\nbool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)\n{\n    if (!removeTx(entry->GetTx().GetHash(), true)) {\n        // This transaction wasn't being tracked for fee estimation\n        return false;\n    }\n\n    // How many blocks did it take for miners to include this transaction?\n    // blocksToConfirm is 1-based, so a transaction included in the earliest\n    // possible block has confirmation count of 1\n    int blocksToConfirm = nBlockHeight - entry->GetHeight();\n    if (blocksToConfirm <= 0) {\n        // This can't happen because we don't process transactions from a block with a height\n        // lower than our greatest seen height\n        LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy error Transaction had negative blocksToConfirm\\n\");\n        return false;\n    }\n\n    // Feerates are stored and reported as NLG-per-kb:\n    CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());\n\n    feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());\n    shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());\n    longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());\n    return true;\n}\n\nvoid CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,\n                                         std::vector<const CTxMemPoolEntry*>& entries)\n{\n    LOCK(cs_feeEstimator);\n    if (nBlockHeight <= nBestSeenHeight) {\n        // Ignore side chains and re-orgs; assuming they are random\n        // they don't affect the estimate.\n        // And if an attacker can re-org the chain at will, then\n        // you've got much bigger problems than \"attacker can influence\n        // transaction fees.\"\n        return;\n    }\n\n    // Must update nBestSeenHeight in sync with ClearCurrent so that\n    // calls to removeTx (via processBlockTx) correctly calculate age\n    // of unconfirmed txs to remove from tracking.\n    nBestSeenHeight = nBlockHeight;\n\n    // Update unconfirmed circular buffer\n    feeStats->ClearCurrent(nBlockHeight);\n    shortStats->ClearCurrent(nBlockHeight);\n    longStats->ClearCurrent(nBlockHeight);\n\n    // Decay all exponential averages\n    feeStats->UpdateMovingAverages();\n    shortStats->UpdateMovingAverages();\n    longStats->UpdateMovingAverages();\n\n    unsigned int countedTxs = 0;\n    // Update averages with data points from current block\n    for (const auto& entry : entries) {\n        if (processBlockTx(nBlockHeight, entry))\n            countedTxs++;\n    }\n\n    if (firstRecordedHeight == 0 && countedTxs > 0) {\n        firstRecordedHeight = nBestSeenHeight;\n        LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy first recorded height %u\\n\", firstRecordedHeight);\n    }\n\n\n    LogPrint(BCLog::ESTIMATEFEE, \"Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\\n\",\n             countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),\n             MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? \"historical\" : \"current\");\n\n    trackedTxs = 0;\n    untrackedTxs = 0;\n}\n\nCFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const\n{\n    // It's not possible to get reasonable estimates for confTarget of 1\n    if (confTarget <= 1)\n        return CFeeRate(0);\n\n    return estimateRawFee(confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);\n}\n\nCFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const\n{\n    TxConfirmStats* stats;\n    double sufficientTxs = SUFFICIENT_FEETXS;\n    switch (horizon) {\n    case FeeEstimateHorizon::SHORT_HALFLIFE: {\n        stats = shortStats;\n        sufficientTxs = SUFFICIENT_TXS_SHORT;\n        break;\n    }\n    case FeeEstimateHorizon::MED_HALFLIFE: {\n        stats = feeStats;\n        break;\n    }\n    case FeeEstimateHorizon::LONG_HALFLIFE: {\n        stats = longStats;\n        break;\n    }\n    default: {\n        return CFeeRate(0);\n    }\n    }\n\n    LOCK(cs_feeEstimator);\n    // Return failure if trying to analyze a target we're not tracking\n    if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())\n        return CFeeRate(0);\n    if (successThreshold > 1)\n        return CFeeRate(0);\n\n    double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, true, nBestSeenHeight, result);\n\n    if (median < 0)\n        return CFeeRate(0);\n\n    return CFeeRate(median);\n}\n\nunsigned int CBlockPolicyEstimator::BlockSpan() const\n{\n    if (firstRecordedHeight == 0) return 0;\n    assert(nBestSeenHeight >= firstRecordedHeight);\n\n    return nBestSeenHeight - firstRecordedHeight;\n}\n\nunsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const\n{\n    if (historicalFirst == 0) return 0;\n    assert(historicalBest >= historicalFirst);\n\n    if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;\n\n    return historicalBest - historicalFirst;\n}\n\nunsigned int CBlockPolicyEstimator::MaxUsableEstimate() const\n{\n    // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate\n    return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);\n}\n\n/** Return a fee estimate at the required successThreshold from the shortest\n * time horizon which tracks confirmations up to the desired target.  If\n * checkShorterHorizon is requested, also allow short time horizon estimates\n * for a lower target to reduce the given answer */\ndouble CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon) const\n{\n    double estimate = -1;\n    if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {\n        // Find estimate from shortest time horizon possible\n        if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon\n            estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight);\n        }\n        else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon\n            estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);\n        }\n        else { // long horizon\n            estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);\n        }\n        if (checkShorterHorizon) {\n            // If a lower confTarget from a more recent horizon returns a lower answer use it.\n            if (confTarget > feeStats->GetMaxConfirms()) {\n                double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight);\n                if (medMax > 0 && (estimate == -1 || medMax < estimate))\n                    estimate = medMax;\n            }\n            if (confTarget > shortStats->GetMaxConfirms()) {\n                double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight);\n                if (shortMax > 0 && (estimate == -1 || shortMax < estimate))\n                    estimate = shortMax;\n            }\n        }\n    }\n    return estimate;\n}\n\n/** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met\n * at 2 * target for any longer time horizons.\n */\ndouble CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget) const\n{\n    double estimate = -1;\n    if (doubleTarget <= shortStats->GetMaxConfirms()) {\n        estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight);\n    }\n    if (doubleTarget <= feeStats->GetMaxConfirms()) {\n        double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight);\n        if (longEstimate > estimate) {\n            estimate = longEstimate;\n        }\n    }\n    return estimate;\n}\n\n/** estimateSmartFee returns the max of the feerates calculated with a 60%\n * threshold required at target / 2, an 85% threshold required at target and a\n * 95% threshold required at 2 * target.  Each calculation is performed at the\n * shortest time horizon which tracks the required target.  Conservative\n * estimates, however, required the 95% threshold at 2 * target be met for any\n * longer time horizons also.\n */\nCFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool, bool conservative) const\n{\n    if (answerFoundAtTarget)\n        *answerFoundAtTarget = confTarget;\n\n    double median = -1;\n    {\n        LOCK(cs_feeEstimator);\n\n        // Return failure if trying to analyze a target we're not tracking\n        if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())\n            return CFeeRate(0);\n\n        // It's not possible to get reasonable estimates for confTarget of 1\n        if (confTarget == 1)\n            confTarget = 2;\n\n        unsigned int maxUsableEstimate = MaxUsableEstimate();\n        if (maxUsableEstimate <= 1)\n            return CFeeRate(0);\n\n        if ((unsigned int)confTarget > maxUsableEstimate) {\n            confTarget = maxUsableEstimate;\n        }\n\n        assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints\n\n        /** true is passed to estimateCombined fee for target/2 and target so\n         * that we check the max confirms for shorter time horizons as well.\n         * This is necessary to preserve monotonically increasing estimates.\n         * For non-conservative estimates we do the same thing for 2*target, but\n         * for conservative estimates we want to skip these shorter horizons\n         * checks for 2*target because we are taking the max over all time\n         * horizons so we already have monotonically increasing estimates and\n         * the purpose of conservative estimates is not to let short term\n         * fluctuations lower our estimates by too much.\n         */\n        double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true);\n        double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true);\n        double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative);\n        median = halfEst;\n        if (actualEst > median) {\n            median = actualEst;\n        }\n        if (doubleEst > median) {\n            median = doubleEst;\n        }\n\n        if (conservative || median == -1) {\n            double consEst =  estimateConservativeFee(2 * confTarget);\n            if (consEst > median) {\n                median = consEst;\n            }\n        }\n    } // Must unlock cs_feeEstimator before taking mempool locks\n\n    if (answerFoundAtTarget)\n        *answerFoundAtTarget = confTarget;\n\n    // If mempool is limiting txs , return at least the min feerate from the mempool\n    CAmount minPoolFee = pool.GetMinFee(GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();\n    if (minPoolFee > 0 && minPoolFee > median)\n        return CFeeRate(minPoolFee);\n\n    if (median < 0)\n        return CFeeRate(0);\n\n    return CFeeRate(median);\n}\n\n\nbool CBlockPolicyEstimator::Write(CAutoFile& fileout) const\n{\n    try {\n        LOCK(cs_feeEstimator);\n        fileout << 149900; // version required to read: 0.14.99 or later\n        fileout << CLIENT_VERSION; // version that wrote the file\n        fileout << nBestSeenHeight;\n        if (BlockSpan() > HistoricalBlockSpan()/2) {\n            fileout << firstRecordedHeight << nBestSeenHeight;\n        }\n        else {\n            fileout << historicalFirst << historicalBest;\n        }\n        fileout << COMPACTSIZEVECTOR(buckets);\n        feeStats->Write(fileout);\n        shortStats->Write(fileout);\n        longStats->Write(fileout);\n    }\n    catch (const std::exception&) {\n        LogPrintf(\"CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\\n\");\n        return false;\n    }\n    return true;\n}\n\nbool CBlockPolicyEstimator::Read(CAutoFile& filein)\n{\n    try {\n        LOCK(cs_feeEstimator);\n        int nVersionRequired, nVersionThatWrote;\n        filein >> nVersionRequired >> nVersionThatWrote;\n        if (nVersionRequired > CLIENT_VERSION)\n            return error(\"CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file\", nVersionRequired);\n\n        // Read fee estimates file into temporary variables so existing data\n        // structures aren't corrupted if there is an exception.\n        unsigned int nFileBestSeenHeight;\n        filein >> nFileBestSeenHeight;\n\n        if (nVersionThatWrote < 149900) {\n            // Read the old fee estimates file for temporary use, but then discard.  Will start collecting data from scratch.\n            // decay is stored before buckets in old versions, so pre-read decay and pass into TxConfirmStats constructor\n            double tempDecay;\n            filein >> tempDecay;\n            if (tempDecay <= 0 || tempDecay >= 1)\n                throw std::runtime_error(\"Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)\");\n\n            std::vector<double> tempBuckets;\n            filein >> COMPACTSIZEVECTOR(tempBuckets);\n            size_t tempNum = tempBuckets.size();\n            if (tempNum <= 1 || tempNum > 1000)\n                throw std::runtime_error(\"Corrupt estimates file. Must have between 2 and 1000 feerate buckets\");\n\n            std::map<double, unsigned int> tempMap;\n\n            std::unique_ptr<TxConfirmStats> tempFeeStats(new TxConfirmStats(tempBuckets, tempMap, MED_BLOCK_PERIODS, tempDecay, 1));\n            tempFeeStats->Read(filein, nVersionThatWrote, tempNum);\n            // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.\n\n            tempMap.clear();\n            for (unsigned int i = 0; i < tempBuckets.size(); i++) {\n                tempMap[tempBuckets[i]] = i;\n            }\n        }\n        else { // nVersionThatWrote >= 149900\n            unsigned int nFileHistoricalFirst, nFileHistoricalBest;\n            filein >> nFileHistoricalFirst >> nFileHistoricalBest;\n            if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {\n                throw std::runtime_error(\"Corrupt estimates file. Historical block range for estimates is invalid\");\n            }\n            std::vector<double> fileBuckets;\n            filein >> COMPACTSIZEVECTOR(fileBuckets);\n            size_t numBuckets = fileBuckets.size();\n            if (numBuckets <= 1 || numBuckets > 1000)\n                throw std::runtime_error(\"Corrupt estimates file. Must have between 2 and 1000 feerate buckets\");\n\n            std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));\n            std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));\n            std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));\n            fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);\n            fileShortStats->Read(filein, nVersionThatWrote, numBuckets);\n            fileLongStats->Read(filein, nVersionThatWrote, numBuckets);\n\n            // Fee estimates file parsed correctly\n            // Copy buckets from file and refresh our bucketmap\n            buckets = fileBuckets;\n            bucketMap.clear();\n            for (unsigned int i = 0; i < buckets.size(); i++) {\n                bucketMap[buckets[i]] = i;\n            }\n\n            // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap\n            delete feeStats;\n            delete shortStats;\n            delete longStats;\n            feeStats = fileFeeStats.release();\n            shortStats = fileShortStats.release();\n            longStats = fileLongStats.release();\n\n            nBestSeenHeight = nFileBestSeenHeight;\n            historicalFirst = nFileHistoricalFirst;\n            historicalBest = nFileHistoricalBest;\n        }\n    }\n    catch (const std::exception& e) {\n        LogPrintf(\"CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\\n\",e.what());\n        return false;\n    }\n    return true;\n}\n\nvoid CBlockPolicyEstimator::FlushUnconfirmed(CTxMemPool& pool) {\n    int64_t startclear = GetTimeMicros();\n    std::vector<uint256> txids;\n    pool.queryHashes(txids);\n    LOCK(cs_feeEstimator);\n    for (auto& txid : txids) {\n        removeTx(txid, false);\n    }\n    int64_t endclear = GetTimeMicros();\n    LogPrint(BCLog::ESTIMATEFEE, \"Recorded %u unconfirmed txs from mempool in %gs\\n\",txids.size(), (endclear - startclear)*0.000001);\n}\n\nFeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)\n{\n    CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);\n    feeset.insert(0);\n    for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {\n        feeset.insert(bucketBoundary);\n    }\n}\n\nCAmount FeeFilterRounder::round(CAmount currentMinFee)\n{\n    std::set<double>::iterator it = feeset.lower_bound(currentMinFee);\n    if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {\n        it--;\n    }\n    return *it;\n}\n"
  },
  {
    "path": "src/policy/fees.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#ifndef POLICYESTIMATOR_H\n#define POLICYESTIMATOR_H\n\n#include \"amount.h\"\n#include \"feerate.h\"\n#include \"uint256.h\"\n#include \"random.h\"\n#include \"sync.h\"\n\n#include <map>\n#include <string>\n#include <vector>\n\nclass CAutoFile;\nclass CFeeRate;\nclass CTxMemPoolEntry;\nclass CTxMemPool;\nclass TxConfirmStats;\n\n/** \\class CBlockPolicyEstimator\n * The BlockPolicyEstimator is used for estimating the feerate needed\n * for a transaction to be included in a block within a certain number of\n * blocks.\n *\n * At a high level the algorithm works by grouping transactions into buckets\n * based on having similar feerates and then tracking how long it\n * takes transactions in the various buckets to be mined.  It operates under\n * the assumption that in general transactions of higher feerate will be\n * included in blocks before transactions of lower feerate.   So for\n * example if you wanted to know what feerate you should put on a transaction to\n * be included in a block within the next 5 blocks, you would start by looking\n * at the bucket with the highest feerate transactions and verifying that a\n * sufficiently high percentage of them were confirmed within 5 blocks and\n * then you would look at the next highest feerate bucket, and so on, stopping at\n * the last bucket to pass the test.   The average feerate of transactions in this\n * bucket will give you an indication of the lowest feerate you can put on a\n * transaction and still have a sufficiently high chance of being confirmed\n * within your desired 5 blocks.\n *\n * Here is a brief description of the implementation:\n * When a transaction enters the mempool, we track the height of the block chain\n * at entry.  All further calculations are conducted only on this set of \"seen\"\n * transactions. Whenever a block comes in, we count the number of transactions\n * in each bucket and the total amount of feerate paid in each bucket. Then we\n * calculate how many blocks Y it took each transaction to be mined.  We convert\n * from a number of blocks to a number of periods Y' each encompassing \"scale\"\n * blocks.  This is is tracked in 3 different data sets each up to a maximum\n * number of periods. Within each data set we have an array of counters in each\n * feerate bucket and we increment all the counters from Y' up to max periods\n * representing that a tx was successfully confirmed in less than or equal to\n * that many periods. We want to save a history of this information, so at any\n * time we have a counter of the total number of transactions that happened in a\n * given feerate bucket and the total number that were confirmed in each of the\n * periods or less for any bucket.  We save this history by keeping an\n * exponentially decaying moving average of each one of these stats.  This is\n * done for a different decay in each of the 3 data sets to keep relevant data\n * from different time horizons.  Furthermore we also keep track of the number\n * unmined (in mempool or left mempool without being included in a block)\n * transactions in each bucket and for how many blocks they have been\n * outstanding and use both of these numbers to increase the number of transactions\n * we've seen in that feerate bucket when calculating an estimate for any number\n * of confirmations below the number of blocks they've been outstanding.\n */\n\n/* Identifier for each of the 3 different TxConfirmStats which will track\n * history over different time horizons. */\nenum FeeEstimateHorizon {\n    SHORT_HALFLIFE = 0,\n    MED_HALFLIFE = 1,\n    LONG_HALFLIFE = 2\n};\n\n/* Used to return detailed information about a feerate bucket */\nstruct EstimatorBucket\n{\n    double start = -1;\n    double end = -1;\n    double withinTarget = 0;\n    double totalConfirmed = 0;\n    double inMempool = 0;\n    double leftMempool = 0;\n};\n\n/* Used to return detailed information about a fee estimate calculation */\nstruct EstimationResult\n{\n    EstimatorBucket pass;\n    EstimatorBucket fail;\n    double decay;\n    unsigned int scale;\n};\n\n/**\n *  We want to be able to estimate feerates that are needed on tx's to be included in\n * a certain number of blocks.  Every time a block is added to the best chain, this class records\n * stats on the transactions included in that block\n */\nclass CBlockPolicyEstimator\n{\nprivate:\n    /** Track confirm delays up to 12 blocks for short horizon */\n    static constexpr unsigned int SHORT_BLOCK_PERIODS = 12;\n    static constexpr unsigned int SHORT_SCALE = 1;\n    /** Track confirm delays up to 48 blocks for medium horizon */\n    static constexpr unsigned int MED_BLOCK_PERIODS = 24;\n    static constexpr unsigned int MED_SCALE = 2;\n    /** Track confirm delays up to 1008 blocks for long horizon */\n    static constexpr unsigned int LONG_BLOCK_PERIODS = 42;\n    static constexpr unsigned int LONG_SCALE = 24;\n    /** Historical estimates that are older than this aren't valid */\n    static const unsigned int OLDEST_ESTIMATE_HISTORY = 6 * 1008;\n\n    /** Decay of .962 is a half-life of 18 blocks or about 3 hours */\n    static constexpr double SHORT_DECAY = .962;\n    /** Decay of .998 is a half-life of 144 blocks or about 1 day */\n    static constexpr double MED_DECAY = .9952;\n    /** Decay of .9995 is a half-life of 1008 blocks or about 1 week */\n    static constexpr double LONG_DECAY = .99931;\n\n    /** Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks*/\n    static constexpr double HALF_SUCCESS_PCT = .6;\n    /** Require greater than 85% of X feerate transactions to be confirmed within Y blocks*/\n    static constexpr double SUCCESS_PCT = .85;\n    /** Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks*/\n    static constexpr double DOUBLE_SUCCESS_PCT = .95;\n\n    /** Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance */\n    static constexpr double SUFFICIENT_FEETXS = 0.1;\n    /** Require an avg of 0.5 tx when using short decay since there are fewer blocks considered*/\n    static constexpr double SUFFICIENT_TXS_SHORT = 0.5;\n\n    /** Minimum and Maximum values for tracking feerates\n     * The MIN_BUCKET_FEERATE should just be set to the lowest reasonable feerate we\n     * might ever want to track.  Historically this has been 1000 since it was\n     * inheriting DEFAULT_MIN_RELAY_TX_FEE and changing it is disruptive as it\n     * invalidates old estimates files. So leave it at 1000 unless it becomes\n     * necessary to lower it, and then lower it substantially.\n     */\n    static constexpr double MIN_BUCKET_FEERATE = 1000;\n    static constexpr double MAX_BUCKET_FEERATE = 1e7;\n\n    /** Spacing of FeeRate buckets\n     * We have to lump transactions into buckets based on feerate, but we want to be able\n     * to give accurate estimates over a large range of potential feerates\n     * Therefore it makes sense to exponentially space the buckets\n     */\n    static constexpr double FEE_SPACING = 1.05;\n\npublic:\n    /** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */\n    CBlockPolicyEstimator();\n    ~CBlockPolicyEstimator();\n\n    /** Process all the transactions that have been included in a block */\n    void processBlock(unsigned int nBlockHeight,\n                      std::vector<const CTxMemPoolEntry*>& entries);\n\n    /** Process a transaction accepted to the mempool*/\n    void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate);\n\n    /** Remove a transaction from the mempool tracking stats*/\n    bool removeTx(uint256 hash, bool inBlock);\n\n    /** DEPRECATED. Return a feerate estimate */\n    CFeeRate estimateFee(int confTarget) const;\n\n    /** Estimate feerate needed to get be included in a block within confTarget\n     *  blocks. If no answer can be given at confTarget, return an estimate at\n     *  the closest target where one can be given.  'conservative' estimates are\n     *  valid over longer time horizons also.\n     */\n    CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool, bool conservative = true) const;\n\n    /** Return a specific fee estimate calculation with a given success\n     * threshold and time horizon, and optionally return detailed data about\n     * calculation\n     */\n    CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result = nullptr) const;\n\n    /** Write estimation data to a file */\n    bool Write(CAutoFile& fileout) const;\n\n    /** Read estimation data from a file */\n    bool Read(CAutoFile& filein);\n\n    /** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */\n    void FlushUnconfirmed(CTxMemPool& pool);\n\nprivate:\n    unsigned int nBestSeenHeight;\n    unsigned int firstRecordedHeight;\n    unsigned int historicalFirst;\n    unsigned int historicalBest;\n\n    struct TxStatsInfo\n    {\n        unsigned int blockHeight;\n        unsigned int bucketIndex;\n        TxStatsInfo() : blockHeight(0), bucketIndex(0) {}\n    };\n\n    // map of txids to information about that transaction\n    std::map<uint256, TxStatsInfo> mapMemPoolTxs;\n\n    /** Classes to track historical data on transaction confirmations */\n    TxConfirmStats* feeStats;\n    TxConfirmStats* shortStats;\n    TxConfirmStats* longStats;\n\n    unsigned int trackedTxs;\n    unsigned int untrackedTxs;\n\n    std::vector<double> buckets;              // The upper-bound of the range for the bucket (inclusive)\n    std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket\n\n    mutable RecursiveMutex cs_feeEstimator;\n\n    /** Process a transaction confirmed in a block*/\n    bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);\n\n    /** Helper for estimateSmartFee */\n    double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon) const;\n    /** Helper for estimateSmartFee */\n    double estimateConservativeFee(unsigned int doubleTarget) const;\n    /** Number of blocks of data recorded while fee estimates have been running */\n    unsigned int BlockSpan() const;\n    /** Number of blocks of recorded fee estimate data represented in saved data file */\n    unsigned int HistoricalBlockSpan() const;\n    /** Calculation of highest target that reasonable estimate can be provided for */\n    unsigned int MaxUsableEstimate() const;\n};\n\nclass FeeFilterRounder\n{\nprivate:\n    static constexpr double MAX_FILTER_FEERATE = 1e7;\n    /** FEE_FILTER_SPACING is just used to provide some quantization of fee\n     * filter results.  Historically it reused FEE_SPACING, but it is completely\n     * unrelated, and was made a separate constant so the two concepts are not\n     * tied together */\n    static constexpr double FEE_FILTER_SPACING = 1.1;\n\npublic:\n    /** Create new FeeFilterRounder */\n    FeeFilterRounder(const CFeeRate& minIncrementalFee);\n\n    /** Quantize a minimum fee for privacy purpose before broadcast **/\n    CAmount round(CAmount currentMinFee);\n\nprivate:\n    std::set<double> feeset;\n    FastRandomContext insecure_rand;\n};\n\n#endif\n"
  },
  {
    "path": "src/policy/policy.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic\n\n#include \"policy/policy.h\"\n\n#include \"validation/validation.h\"\n#include \"coins.h\"\n#include \"tinyformat.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n//fixme: (PHASE5) - we can remove these includes\n#include \"witnessutil.h\"\n\nCAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)\n{\n    /*\n    // \"Dust\" is defined in terms of dustRelayFee,\n    // which has units satoshis-per-kilobyte.\n    // If you'd pay more than 1/3 in fees\n    // to spend something, then we consider it dust.\n    */\n    // Munt: IsDust() detection disabled, allows any valid dust to be relayed.\n    // The fees imposed on each dust txo is considered sufficient spam deterrant. \n    return 0;\n}\n\nbool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)\n{\n    //fixme: (POST-PHASE5) (LOW) - reconsider dust policy.\n    //return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));\n    return false;\n}\n\n/**\n    * Check transaction inputs to mitigate two\n    * potential denial-of-service attacks:\n    * \n    * 1. scriptSigs with extra data stuffed into them,\n    *    not consumed by scriptPubKey (or P2SH script)\n    * 2. P2SH scripts with a crazy number of expensive\n    *    CHECKSIG/CHECKMULTISIG operations\n    *\n    * Why bother? To avoid denial-of-service attacks; an attacker\n    * can submit a standard HASH... OP_EQUAL transaction,\n    * which will get accepted into blocks. The redemption\n    * script can be anything; an attacker could use a very\n    * expensive-to-check-upon-redemption script like:\n    *   DUP CHECKSIG DROP ... repeated 100 times... OP_1\n    */\nbool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool segsigEnabled)\n{\n    std::vector<std::vector<unsigned char> > vSolutions;\n    if (!Solver(scriptPubKey, whichType, vSolutions))\n        return false;\n\n    if (whichType == TX_MULTISIG)\n    {\n        unsigned char m = vSolutions.front()[0];\n        unsigned char n = vSolutions.back()[0];\n        // Support up to x-of-3 multisig txns as standard\n        if (n < 1 || n > 3)\n            return false;\n        if (m < 1 || m > n)\n            return false;\n    }\n    else if (whichType == TX_NULL_DATA && (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))\n    {\n          return false;\n    }\n\n    return whichType != TX_NONSTANDARD;\n}\n\nbool IsStandardTx(const CTransaction& tx, std::string& reason, int nPoW2Version, const bool segsigEnabled)\n{\n    if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < CTransaction::SEGSIG_ACTIVATION_VERSION) {\n        reason = \"version\";\n        return false;\n    }\n\n    // Extremely large transactions with lots of inputs can cost the network\n    // almost as much to process as they cost the sender in fees, because\n    // computing signature hashes is O(ninputs*txsize). Limiting transactions\n    // to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.\n    unsigned int sz = GetTransactionWeight(tx);\n    if (sz >= MAX_STANDARD_TX_WEIGHT)\n    {\n        reason = \"tx-size\";\n        return false;\n    }\n\n    if (!IsOldTransactionVersion(tx.nVersion))\n    {\n        if (tx.flags[HasExtraFlags] != 0)\n        {\n            reason = \"tx-has-extraflags\";\n        }\n        //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look into this post release\n        if (tx.flags[HasLockTime] != 0)\n        {\n            reason = \"tx-has-locktime\";\n        }\n    }\n\n    for(const CTxIn& txin : tx.vin)\n    {\n        // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed\n        // keys (remember the 520 byte limit on redeemScript size). That works\n        // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627\n        // bytes of scriptSig, which we round off to 1650 bytes for some minor\n        // future-proofing. That's also enough to spend a 20-of-20\n        // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not\n        // considered standard.\n        if (txin.scriptSig.size() > 1650)\n        {\n            reason = \"scriptsig-size\";\n            return false;\n        }\n        if (!txin.scriptSig.IsPushOnly())\n        {\n            reason = \"scriptsig-not-pushonly\";\n            return false;\n        }\n        if (txin.GetType() != CTxInType::CURRENT_TX_IN_TYPE)\n        {\n            reason = \"unsupported-ctxin-type\";\n        }\n        //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look into this post release\n        if (txin.FlagIsSet(HasLock) != 0)\n        {\n            reason = \"txin-has-lock\";\n        }\n    }\n\n    unsigned int nDataOut = 0;\n    txnouttype whichType;\n    for(const CTxOut& txout : tx.vout)\n    {\n        switch (txout.GetType())\n        {\n            case CTxOutType::ScriptLegacyOutput:\n            {\n                if (!::IsStandard(txout.output.scriptPubKey, whichType, segsigEnabled))\n                {\n                    reason = \"scriptpubkey\";\n                    return false;\n                }\n                break;\n            }\n            case CTxOutType::StandardKeyHashOutput:\n                break;\n            case CTxOutType::PoW2WitnessOutput:\n                break;\n            default:\n            {\n                reason = \"unsupported-ctxout-type\";\n            }\n        }\n\n        if (whichType == TX_NULL_DATA)\n        {\n            nDataOut++;\n        }\n        else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd))\n        {\n            reason = \"bare-multisig\";\n            return false;\n        }\n        else if (IsDust(txout, ::dustRelayFee))\n        {\n            reason = \"dust\";\n            return false;\n        }\n    }\n\n    // only one OP_RETURN txout is permitted\n    if (nDataOut > 1)\n    {\n        reason = \"multi-op-return\";\n        return false;\n    }\n\n    return true;\n}\n\n//fixme: (PHASE5) de-dupe\ntypedef std::vector<unsigned char> valtype;\nstatic CScript PushAll(const std::vector<valtype>& values)\n{\n    CScript result;\n    for(const valtype& v : values) {\n        if (v.size() == 0) {\n            result << OP_0;\n        } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {\n            result << CScript::EncodeOP_N(v[0]);\n        } else {\n            result << v;\n        }\n    }\n    return result;\n}\n\nbool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)\n{\n    if (tx.IsCoinBase())\n        return true; // Coinbases don't use vin normally\n\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n    {\n        const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].GetPrevOut()).out;\n\n        std::vector<std::vector<unsigned char> > vSolutions;\n        txnouttype whichType;\n        // get the scriptPubKey corresponding to this input:\n        if (prev.GetType() <= CTxOutType::ScriptLegacyOutput)\n        {\n            const CScript& prevScript = prev.output.scriptPubKey;\n            if (!Solver(prevScript, whichType, vSolutions))\n                return false;\n\n            if (whichType == TX_SCRIPTHASH)\n            {\n                std::vector<std::vector<unsigned char> > stack;\n                // convert the scriptSig into a stack, so we can inspect the redeemScript\n                if (IsOldTransactionVersion(tx.nVersion))\n                {\n                    if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1))\n                        return false;\n                }\n                else\n                {\n                    if (tx.vin[i].scriptSig.size() != 0)\n                        return false;\n                    CScript scriptSigTemp = PushAll(tx.vin[i].segregatedSignatureData.stack);\n                    if (!EvalScript(stack, scriptSigTemp, SCRIPT_VERIFY_NONE, BaseSignatureChecker(CKeyID(), CKeyID()), IsOldTransactionVersion(tx.nVersion) ? SCRIPT_V1 : SCRIPT_V2))\n                        return false;\n                }\n                if (stack.empty())\n                    return false;\n                CScript subscript(stack.back().begin(), stack.back().end());\n                if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS)\n                {\n                    return false;\n                }\n            }\n        }\n    }\n\n    return true;\n}\n\nbool IsSegregatedSignatureDataStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)\n{\n    //fixme: (PHASE5) - Look into any other restrictions we may want to add here.\n    // Don't think there is anything - but check again against bitcoin equivalent (IsWitnessStandard) to be sure\n    \n    // Old transaction format  has no segregated signature data\n    if (IsOldTransactionVersion(tx.nVersion))\n    {\n        if (tx.HasSegregatedSignatures())\n            return false;\n        return true;\n    }\n\n    static const unsigned int MAX_STANDARD_SEGREGATED_SIGNATURE_STACK_ITEMS = 100;\n    static const unsigned int MAX_STANDARD_SEGREGATED_SIGNATURE_STACK_ITEM_SIZE = 80;\n\n    for (uint64_t i=0; i<tx.vin.size(); ++i)\n    {\n        size_t sizeSegregatedSignatureStack = tx.vin[i].segregatedSignatureData.stack.size();\n        if (sizeSegregatedSignatureStack > MAX_STANDARD_SEGREGATED_SIGNATURE_STACK_ITEMS)\n            return false;\n\n        for (unsigned int j = 0; j < sizeSegregatedSignatureStack; j++)\n        {\n            if (tx.vin[i].segregatedSignatureData.stack[j].size() > MAX_STANDARD_SEGREGATED_SIGNATURE_STACK_ITEM_SIZE)\n                return false;\n        }\n    }\n    \n    return true;\n}\n\nCFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);\nCFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);\nunsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;\n\nint64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)\n{\n    return (std::max(nWeight, nSigOpCost * nBytesPerSigOp));\n}\n\nint64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)\n{\n    return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);\n}\n\nconst uint64_t STANDARD_COINBASE_INPUT_SIZE_DISCOUNT = 60;\nconst uint64_t STANDARD_COINBASE_SIGOP_COST_DISCOUNT = 1;   \nint64_t GetVirtualTransactionSizeDiscounted(int64_t nWeight, uint64_t numCoinbaseInputs, int64_t nSigOpCost)\n{\n    uint64_t coinbaseInputsToDiscount=(numCoinbaseInputs>2?numCoinbaseInputs-2:numCoinbaseInputs);\n    uint64_t weightDiscount = STANDARD_COINBASE_INPUT_SIZE_DISCOUNT * coinbaseInputsToDiscount;\n    uint64_t sigOpCostDiscount = STANDARD_COINBASE_SIGOP_COST_DISCOUNT * coinbaseInputsToDiscount;\n    uint64_t discountedWeight = (uint64_t)nWeight>weightDiscount?(uint64_t)nWeight-weightDiscount:(uint64_t)nWeight;\n    uint64_t discountedSigOps = (uint64_t)nSigOpCost>sigOpCostDiscount?(uint64_t)nSigOpCost-sigOpCostDiscount:(uint64_t)nSigOpCost;\n    \n    return (std::max(discountedWeight, discountedSigOps * nBytesPerSigOp));\n}\n\n\nint64_t GetVirtualTransactionSizeDiscounted(const CTransaction& tx, uint64_t numCoinbaseInputs, int64_t nSigOpCost)\n{\n    uint64_t nTxWeight = GetTransactionWeight(tx);    \n    return GetVirtualTransactionSizeDiscounted(nTxWeight, numCoinbaseInputs, nSigOpCost);\n}\n"
  },
  {
    "path": "src/policy/policy.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef POLICY_POLICY_H\n#define POLICY_POLICY_H\n\n#include \"consensus/consensus.h\"\n#include \"feerate.h\"\n#include \"script/interpreter.h\"\n#include \"script/standard.h\"\n\n#include <string>\n\nclass CCoinsViewCache;\nclass CTxOut;\n\n/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/\nstatic const unsigned int DEFAULT_BLOCK_MAX_SIZE = 250000;\n/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/\nstatic const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;\n/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/\nstatic const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;\n/** The maximum weight for transactions we're willing to relay/mine */\nstatic const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;\n/** Maximum number of signature check operations in an IsStandard() P2SH script */\nstatic const unsigned int MAX_P2SH_SIGOPS = 15;\n/** The maximum number of sigops we're willing to relay/mine in a single tx */\nstatic const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;\n/** Default for -maxmempool, maximum megabytes of mempool memory usage */\nstatic const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;\nstatic const unsigned int DEFAULT_MAX_MEMPOOL_SIZE_LOWMEM = 50;\n/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/\nstatic const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;\n/** Default for -bytespersigop */\nstatic const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;\n\n/** Min feerate for defining dust. Historically this has been the same as the\n * minRelayTxFee, however changing the dust limit changes which transactions are\n * standard and should be done with care and ideally rarely. It makes sense to\n * only increase the dust limit after prior releases were already not creating\n * outputs below the new threshold */\nstatic const unsigned int DUST_RELAY_TX_FEE = 1000;\n/**\n * Standard script verification flags that standard transactions will comply\n * with. However scripts violating these flags may still be present in valid\n * blocks and we must accept those blocks.\n */\nstatic const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |\n                                                         SCRIPT_VERIFY_DERSIG |\n                                                         SCRIPT_VERIFY_STRICTENC |\n                                                         SCRIPT_VERIFY_MINIMALDATA |\n                                                         SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |\n                                                         SCRIPT_VERIFY_CLEANSTACK |\n                                                         SCRIPT_VERIFY_MINIMALIF |\n                                                         SCRIPT_VERIFY_NULLFAIL |\n                                                         SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |\n                                                         SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |\n                                                         SCRIPT_VERIFY_LOW_S\n                                                         ;\n\n/** For convenience, standard but not mandatory verify flags. */\nstatic const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;\n\n/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */\nstatic const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |\n                                                           LOCKTIME_MEDIAN_TIME_PAST;\n\nCAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);\n\nbool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);\n\nbool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool segsigEnabled = false);\n    /**\n     * Check for standard transaction types\n     * @return True if all outputs (scriptPubKeys) use only standard transaction forms\n     */\nbool IsStandardTx(const CTransaction& tx, std::string& reason, int nPoW2Version, const bool segsigEnabled = false);\n    /**\n     * Check for standard transaction types\n     * @param[in] mapInputs    Map of previous transactions that have outputs we're spending\n     * @return True if all inputs (scriptSigs) use only standard transaction forms\n     */\nbool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);\n\nbool IsSegregatedSignatureDataStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);\n\nextern CFeeRate incrementalRelayFee;\nextern CFeeRate dustRelayFee;\nextern unsigned int nBytesPerSigOp;\n\n/** Compute the virtual transaction size (weight reinterpreted as bytes). */\nint64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost);\nint64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0);\nint64_t GetVirtualTransactionSizeDiscounted(int64_t nWeight, uint64_t numCoinbaseInputs, int64_t nSigOpCost);\nint64_t GetVirtualTransactionSizeDiscounted(const CTransaction& tx, uint64_t numCoinbaseInputs, int64_t nSigOpCost=0);\n\n#endif\n"
  },
  {
    "path": "src/policy/rbf.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"policy/rbf.h\"\n\n//fixme: (PHASE5) we can make this the only behaviour and remove the previous behaviour.\nstatic bool SignalsOptInRBFSegSig(const CTransaction &tx)\n{\n    for(const CTxIn &txin : tx.vin)\n    {\n        if (txin.FlagIsSet(CTxInFlags::OptInRBF))\n        {\n            return true;\n        }\n    }\n    return false;\n}\n\nbool SignalsOptInRBF(const CTransaction &tx)\n{\n    if (!IsOldTransactionVersion(tx.nVersion))\n        return SignalsOptInRBFSegSig(tx);\n\n    for(const CTxIn &txin : tx.vin)\n    {\n        if (txin.GetSequence(tx.nVersion) < std::numeric_limits<unsigned int>::max()-1)\n        {\n            return true;\n        }\n    }\n    return false;\n}\n\nRBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool)\n{\n    AssertLockHeld(pool.cs);\n\n    CTxMemPool::setEntries setAncestors;\n\n    // First check the transaction itself.\n    if (SignalsOptInRBF(tx))\n    {\n        return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125;\n    }\n\n    // If this transaction is not in our mempool, then we can't be sure\n    // we will know about all its inputs.\n    if (!pool.exists(tx.GetHash()))\n    {\n        return RBF_TRANSACTIONSTATE_UNKNOWN;\n    }\n\n    // If all the inputs have nSequence >= maxint-1, it still might be\n    // signaled for RBF if any unconfirmed parents have signaled.\n    uint64_t noLimit = std::numeric_limits<uint64_t>::max();\n    std::string dummy;\n    CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());\n    pool.CalculateMemPoolAncestors(entry, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);\n\n    for(CTxMemPool::txiter it : setAncestors)\n    {\n        if (SignalsOptInRBF(it->GetTx()))\n        {\n            return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125;\n        }\n    }\n    return RBF_TRANSACTIONSTATE_FINAL;\n}\n"
  },
  {
    "path": "src/policy/rbf.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef POLICY_RBF_H\n#define POLICY_RBF_H\n\n#include \"txmempool.h\"\n\nstatic const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;\n\nenum RBFTransactionState {\n    RBF_TRANSACTIONSTATE_UNKNOWN,\n    RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125,\n    RBF_TRANSACTIONSTATE_FINAL\n};\n\n// Check whether the sequence numbers on this transaction are signaling\n// opt-in to replace-by-fee, according to BIP 125\nbool SignalsOptInRBF(const CTransaction &tx);\n\n// Determine whether an in-mempool transaction is signaling opt-in to RBF\n// according to BIP 125\n// This involves checking sequence numbers of the transaction, as well\n// as the sequence numbers of all in-mempool ancestors.\nRBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool);\n\n#endif\n"
  },
  {
    "path": "src/pow/diff.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef POW_DIFF_H\n#define POW_DIFF_H\n\n#include <consensus/params.h>\n#include \"diff_common.h\"\n\nunsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)\n{\n    return GetNextWorkRequired(pindexLast, pblock, params.nPowTargetSpacing, UintToArith256(params.powLimit).GetCompact());\n}\n\n\n#endif\n\n"
  },
  {
    "path": "src/pow/diff_common.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n#include \"diff_common.h\"\n#include \"diff_delta.h\"\n#include \"diff_old.h\"\n#include \"../../chainparams.h\"\n\nunsigned int GetNextWorkRequired(const CBlockIndex* indexLast, const CBlockHeader* block, unsigned int nPowTargetSpacing, unsigned int nPowLimit)\n{\n    if (Params().GetConsensus().fPowNoRetargeting)\n        return indexLast->nBits;\n\n    static int nDeltaSwitchoverBlock = DIFF_SWITCHOVER(10, 250000);\n    static int nOldDiffSwitchoverBlock = DIFF_SWITCHOVER(0, 1831778);\n\n    if ((indexLast->nHeight+1) >= nOldDiffSwitchoverBlock)\n    {\n        // Delta can't handle a target spacing of 1 - so we just assume a static diff for testnets where target spacing is 1.\n        if (nPowTargetSpacing>1 && (indexLast->nHeight+1) >= nDeltaSwitchoverBlock)\n        {\n            return GetNextWorkRequired_DELTA(indexLast, block, nPowTargetSpacing, nPowLimit, nDeltaSwitchoverBlock);\n        }\n        else\n        {\n            return 524287999;\n        }\n    }\n    return diff_old(indexLast->nHeight+1, nPowLimit);\n}\n"
  },
  {
    "path": "src/pow/diff_common.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n\n#ifndef POW_DIFF_COMMON_H\n#define POW_DIFF_COMMON_H\n\n#include <consensus/params.h>\n#include <arith_uint256.h>\n#include <chain.h>\n#include <sync.h>\n#include <util.h>\n#include <stdint.h>\n\n#define BLOCK_TIME(block) block->nTime\n#define INDEX_TIME(block) block->GetBlockTime()\n#define BIGINT_MULTIPLY(x, y) x * y\n#define BIGINT_DIVIDE(x, y) x / y\n\n#define DIFF_SWITCHOVER(TEST, MAIN) (Params().IsTestnet() ? TEST :  MAIN)\nextern unsigned int GetNextWorkRequired(const CBlockIndex* indexLast, const CBlockHeader* block, unsigned int nPowTargetSpacing, unsigned int nPowLimit);\n\n#endif\n"
  },
  {
    "path": "src/pow/diff_delta.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Frank (dt_cdog@yahoo.com) and Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// This file contains Delta, the Munt Difficulty Re-adjustment algorithm developed by Frank (dt_cdog@yahoo.com) with various enhancements by Malcolm MacLeod (mmacleod@gmx.com)\n// The core algorithm works by taking time measurements of four periods (last block; short window; medium window; long window) and then apply a weighting to them.\n// This allows the algorithm to react to short term fluctuations while still taking long term block targets into account, which helps prevent it from overreacting.\n//\n// In addition to the core algorithm several extra rules are then applied in certain situations (e.g. multiple quick blocks) to enhance the behaviour.\n\n#include \"diff_common.h\"\n#include \"diff_delta.h\"\n#include \"chainparams.h\"\n#include <stdint.h>\n\nunsigned int GetNextWorkRequired_DELTA (const CBlockIndex* pindexLast, const CBlockHeader* block, int nPowTargetSpacing, unsigned int nPowLimit, unsigned int nFirstDeltaBlock)\n{\n    // These two variables are not used in the calculation at all, but only for logging when -debug is set, to prevent logging the same calculation repeatedly.\n    static int64_t nPrevHeight     = 0;\n    static int64_t nPrevDifficulty = 0;\n    static bool debugLogging = LogAcceptCategory(BCLog::DELTA);\n\n    std::string sLogInfo;\n    \n    //uint32_t nDeltaVersion=3;\n\n    // The spacing we want our blocks to come in at.\n    int64_t nRetargetTimespan      = nPowTargetSpacing;\n\n    // The minimum difficulty that is allowed, this is set on a per algorithm basis.\n    const unsigned int nProofOfWorkLimit = nPowLimit;\n\n    // How many blocks to use to calculate each of the four algo specific time windows (last block; short window; middle window; long window)\n    const unsigned int nLastBlock           =   1;\n    const unsigned int nShortFrame          =   3;\n    const unsigned int nMiddleFrame         =  24;\n    const unsigned int nLongFrame           = 576;\n\n\n    // Weighting to use for each of the four algo specific time windows.\n    const int64_t nLBWeight        =  64;\n    const int64_t nShortWeight     =  8;\n    int64_t nMiddleWeight          =  2;\n    int64_t nLongWeight            =  1;\n\n    // Minimum threshold for the short window, if it exceeds these thresholds then favour a larger swing in difficulty.\n    const int64_t nQBFrame         = nShortFrame + 1;\n\n    // Any block with a time lower than nBadTimeLimit is considered to have a 'bad' time, the time is replaced with the value of nBadTimeReplace.\n    const int64_t nBadTimeLimit    = 0;\n    const int64_t nBadTimeReplace  = nRetargetTimespan / 10;\n\n    // Used for 'exception 1' (see code below), if block is lower than 'nLowTimeLimit' then prevent the algorithm from decreasing difficulty any further.\n    // If block is lower than 'nFloorTimeLimit' then impose a minor increase in difficulty.\n    // This helps to prevent the algorithm from generating and giving away too many sudden/easy 'quick blocks' after a long block or two have occured, and instead forces things to be recovered more gently over time without intefering with other desirable properties of the algorithm.\n    const int64_t nLowTimeLimit    = nRetargetTimespan * 90 / PERCENT_FACTOR;\n    const int64_t nFloorTimeLimit  = nRetargetTimespan * 65 / PERCENT_FACTOR;\n\n    // Used for 'exception 2' (see code below), if a block has taken longer than nLongTimeLimit we perform a difficulty reduction, which increases over time based on nLongTimeStep\n    // NB!!! nLongTimeLimit MUST ALWAYS EXCEED THE THE MAXIMUM DRIFT ALLOWED (IN BOTH THE POSITIVE AND NEGATIVE DIRECTION)\n    // SO AT LEAST DRIFT X2 OR MORE - OR ELSE CLIENTS CAN FORCE LOW DIFFICULTY BLOCKS BY MESSING WITH THE BLOCK TIMES.\n    const int64_t nDrift   = 60; //Drift in seconds\n    int64_t nLongTimeLimit = (3 * nDrift);\n    int64_t nLongTimeStep  = nDrift;\n\n    // Limit adjustment amount to try prevent jumping too far in either direction.\n    // min 75% of default time; 33.3% difficulty increase\n    unsigned int nMinimumAdjustLimit = (unsigned int)nRetargetTimespan * 75 / PERCENT_FACTOR;\n    // max 150% of default time; 33.3% difficuly decrease\n    unsigned int nMaximumAdjustLimit = (unsigned int)nRetargetTimespan * 150 / PERCENT_FACTOR;\n\n    // Variables used in calculation\n    int64_t nQBTimespan            = 0;\n\n    int64_t nWeightedSum           = 0;\n    int64_t nWeightedDiv           = 0;\n    int64_t nWeightedTimespan      = 0;\n\n    const CBlockIndex* pindexFirst = pindexLast;\n\n    // Genesis block\n    if (pindexLast == NULL)\n        return nProofOfWorkLimit;\n\n    // -- Use a fixed difficulty until we have enough blocks to work with\n    if (pindexLast->nHeight <= nQBFrame)\n        return nProofOfWorkLimit;\n\n    // -- Calculate timespan for last block window\n    int64_t nLBTimespan = 0;\n    {\n        int64_t nLBTimespanPoW = 0;\n        pindexFirst = pindexLast->pprev;\n        nLBTimespanPoW = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();\n        nLBTimespan = pindexLast->GetBlockTimePoW2Witness() - pindexFirst->GetBlockTimePoW2Witness();\n\n        // Prevent bad/negative block times - switch them for a fixed time.\n        if (nLBTimespan <= nBadTimeLimit)\n            nLBTimespan = nBadTimeReplace;\n        \n        // If last block was 'long block' with difficulty adjustment, treat it as a faster block at the lower difficulty\n        if (nLBTimespanPoW > (nLongTimeLimit + nLongTimeStep))\n        {\n            nLBTimespanPoW = (nLBTimespanPoW-nLongTimeLimit)%nLongTimeStep;\n            nLBTimespan = std::min(nLBTimespan, nLBTimespanPoW);\n        }\n    }\n\n\n    // -- Calculate timespan for short window\n    int64_t nShortTimespan = 0;\n    {\n        int64_t nDeltaTimespan = 0;\n        int64_t nDeltaTimespanPoW = 0;\n        pindexFirst = pindexLast;\n        for (unsigned int i = 1; pindexFirst != NULL && i <= nQBFrame; i++)\n        {\n            nDeltaTimespanPoW = pindexFirst->GetBlockTime() - pindexFirst->pprev->GetBlockTime();\n            nDeltaTimespan = pindexFirst->GetBlockTimePoW2Witness() - pindexFirst->pprev->GetBlockTimePoW2Witness();\n\n            // Prevent bad/negative block times - switch them for a fixed time.\n            if (nDeltaTimespan <= nBadTimeLimit)\n                nDeltaTimespan = nBadTimeReplace;\n            \n            // If last block was 'long block' with difficulty adjustment, treat it as a faster block at the lower difficulty\n            if (nDeltaTimespanPoW > (nLongTimeLimit + nLongTimeStep))\n            {\n                nDeltaTimespanPoW = (nDeltaTimespanPoW-nLongTimeLimit)%nLongTimeStep;\n                nDeltaTimespan = std::min(nDeltaTimespan, nDeltaTimespanPoW);\n            }\n\n            if (i<= nShortFrame)\n                nShortTimespan += nDeltaTimespan;\n            nQBTimespan += nDeltaTimespan;\n            pindexFirst = pindexFirst->pprev;\n        }\n    }\n\n    // -- Calculate time interval for middle window\n    int64_t nMiddleTimespan = 0;\n    {\n        int64_t nDeltaTimespan = 0;\n        int64_t nDeltaTimespanPoW = 0;\n        if (pindexLast->nHeight - (int)nFirstDeltaBlock <= (int)nMiddleFrame)\n        {\n            nMiddleWeight = nMiddleTimespan = 0;\n        }\n        else\n        {\n            pindexFirst = pindexLast;\n            for (unsigned int i = 1; pindexFirst != NULL && i <= nMiddleFrame; i++)\n            {\n                nDeltaTimespan = pindexFirst->GetBlockTimePoW2Witness() - pindexFirst->pprev->GetBlockTimePoW2Witness();\n\n                // Prevent bad/negative block times - switch them for a fixed time.\n                if (nDeltaTimespan <= nBadTimeLimit)\n                    nDeltaTimespan = nBadTimeReplace;\n                \n                // If last block was 'long block' with difficulty adjustment, treat it as a faster block at the lower difficulty\n                if (nDeltaTimespanPoW > (nLongTimeLimit + nLongTimeStep))\n                {\n                    nDeltaTimespanPoW = (nDeltaTimespanPoW-nLongTimeLimit)%nLongTimeStep;\n                    nDeltaTimespan = std::min(nDeltaTimespan, nDeltaTimespanPoW);\n                }\n\n                nMiddleTimespan += nDeltaTimespan;\n                pindexFirst = pindexFirst->pprev;\n            }\n        }\n    }\n\n\n    // -- Calculate timespan for long window\n    int64_t nLongTimespan = 0;\n    {\n        // NB! No need to worry about single negative block times as it has no significant influence over this many blocks.\n        if ((int)pindexLast->nHeight - (int)nFirstDeltaBlock <= (int)nLongFrame)\n        {\n            nLongWeight = nLongTimespan = 0;\n        }\n        else\n        {\n            pindexFirst = pindexLast;\n            for (unsigned int i = 1; pindexFirst != NULL && i <= nLongFrame; i++)\n            {\n                pindexFirst = pindexFirst->pprev;\n            }\n            nLongTimespan = pindexLast->GetBlockTimePoW2Witness() - pindexFirst->GetBlockTimePoW2Witness();\n        }\n    }\n\n    // -- Combine all the timespans and weights to get a weighted timespan\n    nWeightedSum      = (nLBTimespan * nLBWeight) + (nShortTimespan * nShortWeight);\n    nWeightedSum     += (nMiddleTimespan * nMiddleWeight) + (nLongTimespan * nLongWeight);\n    nWeightedDiv      = (nLastBlock * nLBWeight) + (nShortFrame * nShortWeight);\n    nWeightedDiv     += (nMiddleFrame * nMiddleWeight) + (nLongFrame * nLongWeight);\n    nWeightedTimespan = nWeightedSum / nWeightedDiv;\n\n    // If we are close to target time then reduce the adjustment limits to smooth things off a little bit more.\n    {\n        if (std::abs(nLBTimespan - nRetargetTimespan) < nRetargetTimespan * 20 / PERCENT_FACTOR)\n        {\n            // 90% of target\n            // 11.11111111111111% difficulty increase\n            // 10% difficulty decrease.\n            nMinimumAdjustLimit = (unsigned int)nRetargetTimespan * 90 / PERCENT_FACTOR;\n            nMaximumAdjustLimit = (unsigned int)nRetargetTimespan * 110 / PERCENT_FACTOR;\n        }\n        else if (std::abs(nLBTimespan - nRetargetTimespan) < nRetargetTimespan * 30 / PERCENT_FACTOR)\n        {\n            // 80% of target - 25% difficulty increase/decrease maximum.\n            nMinimumAdjustLimit = (unsigned int)nRetargetTimespan * 80 / PERCENT_FACTOR;\n            nMaximumAdjustLimit = (unsigned int)nRetargetTimespan * 120 / PERCENT_FACTOR;\n        }\n    }\n\n    // -- Apply the adjustment limits\n    {\n        // min\n        if (nWeightedTimespan < nMinimumAdjustLimit)\n            nWeightedTimespan = nMinimumAdjustLimit;\n        // max\n        if (nWeightedTimespan > nMaximumAdjustLimit)\n            nWeightedTimespan = nMaximumAdjustLimit;\n    }\n\n\n\n    // -- Finally calculate and set the new difficulty.\n    arith_uint256 bnNew;\n    bnNew.SetCompact(pindexLast->nBits);\n    bnNew =  bnNew * arith_uint256(nWeightedTimespan);\n    bnNew = bnNew / arith_uint256(nRetargetTimespan);\n\n\n    // Now that we have the difficulty we run a last few 'special purpose' exception rules which have the ability to override the calculation:\n    // Exception 1 - Never adjust difficulty downward (human view) if previous block generation was already faster than what we wanted.\n    {\n        nLBTimespan = pindexLast->GetBlockTimePoW2Witness() - pindexLast->pprev->GetBlockTimePoW2Witness();\n        \n        arith_uint256 bnComp;\n        bnComp.SetCompact(pindexLast->nBits);\n        if (nLBTimespan > 0 && nLBTimespan < nLowTimeLimit && (bnNew > bnComp))\n        {\n            // If it is this low then we actually give it a slight nudge upwards - 5%\n            if (nLBTimespan < nFloorTimeLimit)\n            {\n                bnNew.SetCompact(pindexLast->nBits);\n                bnNew = bnNew * arith_uint256(95);\n                bnNew = bnNew / arith_uint256(PERCENT_FACTOR);\n                if (debugLogging && (nPrevHeight != pindexLast->nHeight) )\n                    sLogInfo +=  strprintf(\"<DELTA> Last block time [%ld] was far below target but adjustment still downward, forcing difficulty up by 5%% instead\\n\", nLBTimespan);\n            }\n            else\n            {\n                bnNew.SetCompact(pindexLast->nBits);\n                if (debugLogging && (nPrevHeight != pindexLast->nHeight) )\n                    sLogInfo += strprintf(\"<DELTA> Last block time [%ld] below target but adjustment still downward, blocking downward adjustment\\n\", nLBTimespan);\n            }\n        }\n    }\n\n    // Exception 2 - Reduce difficulty if current block generation time has already exceeded maximum time limit. (NB! nLongTimeLimit must exceed maximum possible drift in both positive and negative direction)\n    {\n        int64_t lastBlockTime=pindexLast->GetBlockTimePoW2Witness();\n        if ((block->nTime - lastBlockTime) > nLongTimeLimit)\n        {\n            // Fixed reduction for each missed step. 10% pre-SIGMA, 30% after SIGMA, 10% delta V3\n            int32_t nDeltaDropPerStep=110;\n            int64_t nNumMissedSteps = ((block->nTime - lastBlockTime - nLongTimeLimit) / nLongTimeStep) + 1;\n            for(int i=0;i < nNumMissedSteps; ++i)\n            {\n                bnNew = bnNew * arith_uint256(nDeltaDropPerStep);\n                bnNew = bnNew / arith_uint256(PERCENT_FACTOR);\n            }\n\n            if (debugLogging && (nPrevHeight != pindexLast->nHeight ||  bnNew.GetCompact() != nPrevDifficulty) )\n                sLogInfo +=  strprintf(\"<DELTA> Maximum block time hit - dropping difficulty %08x %s\\n\", bnNew.GetCompact(), bnNew.ToString().c_str());\n        }\n    }\n\n    // Exception 3 - Difficulty should never go below (human view) the starting difficulty, so if it has we force it back to the limit.    \n    {\n        arith_uint256 bnComp;\n        if (block->nTime > 1571320800)\n        {\n            const unsigned int newProofOfWorkLimit = UintToArith256(uint256S(\"0x003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\")).GetCompact();\n            bnComp.SetCompact(newProofOfWorkLimit);\n            if (bnNew > bnComp)\n                bnNew.SetCompact(newProofOfWorkLimit);\n        }\n        else\n        {\n            bnComp.SetCompact(nProofOfWorkLimit);\n            if (bnNew > bnComp)\n                bnNew.SetCompact(nProofOfWorkLimit);\n        }\n    }\n\n    if (debugLogging)\n    {\n        if (nPrevHeight != pindexLast->nHeight ||  bnNew.GetCompact() != nPrevDifficulty)\n        {\n            static RecursiveMutex logCS;\n            LOCK(logCS);\n            LogPrintf(\"<DELTA> Height= %d\\n\" , pindexLast->nHeight);\n            LogPrintf(\"%s\" , sLogInfo.c_str());\n            LogPrintf(\"<DELTA> nTargetTimespan = %ld nActualTimespan = %ld nWeightedTimespan = %ld \\n\", nRetargetTimespan, nLBTimespan, nWeightedTimespan);\n            LogPrintf(\"<DELTA> nShortTimespan/nShortFrame = %ld nMiddleTimespan/nMiddleFrame = %ld nLongTimespan/nLongFrame = %ld \\n\", nShortTimespan/nShortFrame, nMiddleTimespan/nMiddleFrame, nLongTimespan/nLongFrame);\n            LogPrintf(\"<DELTA> Before: %08x %s\\n\", pindexLast->nBits, arith_uint256().SetCompact(pindexLast->nBits).ToString().c_str());\n            LogPrintf(\"<DELTA> After:  %08x %s\\n\", bnNew.GetCompact(), bnNew.ToString().c_str());\n            LogPrintf(\"<DELTA> Rough change percentage (human view): %lf%%\\n\", -( ( (bnNew.getdouble() - arith_uint256().SetCompact(pindexLast->nBits).getdouble()) / arith_uint256().SetCompact(pindexLast->nBits).getdouble()) * 100) );\n        }\n        nPrevHeight = pindexLast->nHeight;\n        nPrevDifficulty = bnNew.GetCompact();\n    }\n\n    // Difficulty is returned in compact form.\n    return bnNew.GetCompact();\n}\n"
  },
  {
    "path": "src/pow/diff_delta.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// This file contains Delta, the Munt Difficulty Re-adjustment algorithm developed by Frank (dt_cdog@yahoo.com) with various enhancements by Malcolm MacLeod (mmacleod@gmx.com)\n// The core algorithm works by taking time measurements of four periods (last block; short window; medium window; long window) and then apply a weighting to them.\n// This allows the algorithm to react to short term fluctuations while still taking long term block targets into account, which helps prevent it from overreacting.\n//\n// In addition to the core algorithm several extra rules are then applied in certain situations (e.g. multiple quick blocks) to enhance the behaviour.\n\n\n#ifndef POW_DIFF_DELTA_H\n#define POW_DIFF_DELTA_H\n\n#define PERCENT_FACTOR 100\nextern unsigned int GetNextWorkRequired_DELTA (const CBlockIndex* pindexLast, const CBlockHeader* block, int nPowTargetSpacing, unsigned int nPowLimit, unsigned int nFirstDeltaBlock);\n\n#endif\n"
  },
  {
    "path": "src/pow/diff_old.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// This file replaces the old Difficulty Re-adjustment algorithms\n// It returns a ZERO DIFF when out of range, which can be catched as\n// error after the call (resulting diff > params.powLimit)\n\n#include <stdint.h>\n#include \"diff_common.h\"\n\nconst int32_t nMaxHeight = 1831778;\nconst int32_t nDiffArraySize = nMaxHeight + 1;\nconst int32_t udiff[nDiffArraySize] = {\n #include \"../data/static_diff_data.cpp\"\n};\n\n\nunsigned int diff_old(int nHeight, unsigned int nPowLimit)\n{\n    unsigned int nRet;\n\n    if ((nHeight < 0) || (nHeight > nMaxHeight))\n    {\n        LogPrintf(\"DIFF_old: block height out of range (%d)\\n\", nHeight);\n        return 0;\n    }\n    nRet = (unsigned int)udiff[nHeight];\n\n    static bool fDebug = LogAcceptCategory(BCLog::DELTA);\n    if (fDebug)\n    {\n        static RecursiveMutex logCS;\n        LOCK(logCS);\n        LogPrintf(\"<STATICDIFF> Height=%d Diff=%08x\\n\", nHeight, nRet);\n    }\n\n    return nRet;\n}\n"
  },
  {
    "path": "src/pow/diff_old.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n//\n// This file replaces the old Difficulty Re-adjustment algorithms\n// It returns a ZERO DIFF when out of range, which can be catched as\n// error after the call (resulting diff > params.powLimit)\n\n#ifndef POW_DIFF_OLD_H\n#define POW_DIFF_OLD_H\n\nextern unsigned int diff_old(int nHeight, unsigned int nPowLimit);\n\n#endif\n"
  },
  {
    "path": "src/pow/pow.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"pow.h\"\n\n#include \"arith_uint256.h\"\n#include \"chain.h\"\n#include \"primitives/block.h\"\n#include \"uint256.h\"\n#include \"crypto/hash/sigma/sigma.h\"\n#include \"random.h\"\n#include <thread>\n\n#include \"chainparams.h\"\n#include <validation/validation.h> //For VALIDATION_MOBILE\n\nuint64_t verifyFactor=200;\n\nbool CheckProofOfWork(const CBlock* block, const Consensus::Params& params)\n{    \n    bool fNegative;\n    bool fOverflow;\n    arith_uint256 bnTarget;\n\n    bnTarget.SetCompact(block->nBits, &fNegative, &fOverflow);\n\n    static bool fRegTest = Params().IsRegtest();\n    static bool fRegTestLegacy = Params().IsRegtestLegacy();\n    if (!(fRegTest||fRegTestLegacy) && block->nTime > 1571320800)\n    {\n        uint256 newProofOfWorkLimit = uint256S(\"0x003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n        // Check range\n        if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(newProofOfWorkLimit))\n            return false;\n    }\n    else\n    {\n        // Check range\n        if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))\n            return false;\n    }\n\n    //fixme: (SIGMA) - Post activation we can simplify this.\n    // Check proof of work matches claimed amount\n    if (block->nTime > defaultSigmaSettings.activationDate)\n    {\n        #ifdef VALIDATION_MOBILE\n            //fixme: (SIGMA) (PHASE5) (HIGH) Remove/improve this once we have witness-header-sync; this is a temporary measure to keep SPV performance adequate on low power devices for now.\n            // Benchmarking on 6 core mobile device showed roughly double performance when using 2 threads instead of 1\n            // when further increasing the number of threads (3 and 4) performance stayed roughly the same though at the cost of\n            // higher cpu and energy consumption and overall app/device responsiveness.\n            // As such the number of threads is limited to 2 (if reported by the OS). Further research and benchmarking on a wider range of devices\n            // would be needed to create a solution that gets the most out of a wide range of OS and devices. This might not be worth it though\n            // as for mobile/SPV the witness-header-sync will probably completely skip the pow check in the future.\n            uint32_t numVerifyThreads = std::min(defaultSigmaSettings.numVerifyThreads, (uint64_t)std::max(1, std::min(2, (int)std::thread::hardware_concurrency())));\n            static sigma_verify_context verify(defaultSigmaSettings, numVerifyThreads);\n            static RecursiveMutex csPOW;\n            LOCK(csPOW);\n\n            int verifyLevel = GetRand(verifyFactor);\n            if (verifyLevel == 0)\n            {\n                return verify.verifyHeader<1>(*block);\n            }\n            else if (verifyLevel == 1)\n            {\n                return verify.verifyHeader<2>(*block);\n            }\n            else\n            {\n                return true;\n            }\n        #else\n            static sigma_verify_context verify(defaultSigmaSettings,std::min(defaultSigmaSettings.numVerifyThreads, (uint64_t)std::thread::hardware_concurrency()));\n            static RecursiveMutex csPOW;\n            LOCK(csPOW);\n\n            // Testnet optimisation - only verify last 5 days worth of blocks\n            if (Params().IsOfficialTestnetV1() && (block->nTime < GetTime() - 86400*5))\n            {\n                return true;\n            }\n            //fixme: (SIGMA) - Detect faster machines and disable this optimisation for them, this will further increase network security.\n            // We speed up verification by doing a half verify 40% of the time instead of a full verify\n            // As a half verify has a 50% chance of detecting a 'half valid' hash an attacker has only a 20% chance of a node accepting his header without banning him\n            // This should provide a ~20% speed up for slow machines\n            int verifyLevel = GetRand(100);\n            if (verifyLevel < 20)\n            {\n                return verify.verifyHeader<1>(*block);\n            }\n            else if (verifyLevel < 40)\n            {\n                return verify.verifyHeader<2>(*block);\n            }\n            return verify.verifyHeader<0>(*block);\n        #endif\n    }\n    else\n    {\n        if (UintToArith256(block->GetPoWHash()) > bnTarget)\n            return false;\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/pow/pow.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef POW_POW_H\n#define POW_POW_H\n\n#include \"consensus/params.h\"\n#include \"crypto/hash/sigma/sigma.h\"\n\n#include <stdint.h>\n\nclass CBlock;\nclass CBlockIndex;\nclass uint256;\n\n/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */\nbool CheckProofOfWork(const CBlock* block, const Consensus::Params& params);\n\nextern uint64_t verifyFactor;\n\n#endif\n"
  },
  {
    "path": "src/prevector.h",
    "content": "// Copyright (c) 2015-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_PREVECTOR_H\n#define CORE_PREVECTOR_H\n\n#include <assert.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#include <algorithm>\n#include <cstddef>\n#include <type_traits>\n#include <utility>\n\n/** Implements a drop-in replacement for std::vector<T> which stores up to N\n *  elements directly (without heap allocation). The types Size and Diff are\n *  used to store element counts, and can be any unsigned + signed type.\n *\n *  Storage layout is either:\n *  - Direct allocation:\n *    - Size _size: the number of used elements (between 0 and N)\n *    - T direct[N]: an array of N elements of type T\n *      (only the first _size are initialized).\n *  - Indirect allocation:\n *    - Size _size: the number of used elements plus N + 1\n *    - Size capacity: the number of allocated elements\n *    - T* indirect: a pointer to an array of capacity elements of type T\n *      (only the first _size are initialized).\n *\n *  The data type T must be movable by memmove/realloc(). Once we switch to C++,\n *  move constructors can be used instead.\n */\ntemplate<unsigned int N, typename T, typename Size = uint32_t, typename Diff = int32_t>\nclass prevector {\npublic:\n    typedef Size size_type;\n    typedef Diff difference_type;\n    typedef T value_type;\n    typedef value_type& reference;\n    typedef const value_type& const_reference;\n    typedef value_type* pointer;\n    typedef const value_type* const_pointer;\n\n    class iterator {\n        T* ptr;\n    public:\n        typedef Diff difference_type;\n        typedef T value_type;\n        typedef T* pointer;\n        typedef T& reference;\n        typedef std::random_access_iterator_tag iterator_category;\n        iterator(T* ptr_) : ptr(ptr_) {}\n        T& operator*() const { return *ptr; }\n        T* operator->() const { return ptr; }\n        T& operator[](size_type pos) { return ptr[pos]; }\n        const T& operator[](size_type pos) const { return ptr[pos]; }\n        iterator& operator++() { ptr++; return *this; }\n        iterator& operator--() { ptr--; return *this; }\n        iterator operator++(int) { iterator copy(*this); ++(*this); return copy; }\n        iterator operator--(int) { iterator copy(*this); --(*this); return copy; }\n        difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); }\n        iterator operator+(size_type n) { return iterator(ptr + n); }\n        iterator& operator+=(size_type n) { ptr += n; return *this; }\n        iterator operator-(size_type n) { return iterator(ptr - n); }\n        iterator& operator-=(size_type n) { ptr -= n; return *this; }\n        bool operator==(iterator x) const { return ptr == x.ptr; }\n        bool operator!=(iterator x) const { return ptr != x.ptr; }\n        bool operator>=(iterator x) const { return ptr >= x.ptr; }\n        bool operator<=(iterator x) const { return ptr <= x.ptr; }\n        bool operator>(iterator x) const { return ptr > x.ptr; }\n        bool operator<(iterator x) const { return ptr < x.ptr; }\n    };\n\n    class reverse_iterator {\n        T* ptr;\n    public:\n        typedef Diff difference_type;\n        typedef T value_type;\n        typedef T* pointer;\n        typedef T& reference;\n        typedef std::bidirectional_iterator_tag iterator_category;\n        reverse_iterator(T* ptr_) : ptr(ptr_) {}\n        T& operator*() { return *ptr; }\n        const T& operator*() const { return *ptr; }\n        T* operator->() { return ptr; }\n        const T* operator->() const { return ptr; }\n        reverse_iterator& operator--() { ptr++; return *this; }\n        reverse_iterator& operator++() { ptr--; return *this; }\n        reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; }\n        reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; }\n        bool operator==(reverse_iterator x) const { return ptr == x.ptr; }\n        bool operator!=(reverse_iterator x) const { return ptr != x.ptr; }\n    };\n\n    class const_iterator {\n        const T* ptr;\n    public:\n        typedef Diff difference_type;\n        typedef const T value_type;\n        typedef const T* pointer;\n        typedef const T& reference;\n        typedef std::random_access_iterator_tag iterator_category;\n        const_iterator(const T* ptr_) : ptr(ptr_) {}\n        const_iterator(iterator x) : ptr(&(*x)) {}\n        const T& operator*() const { return *ptr; }\n        const T* operator->() const { return ptr; }\n        const T& operator[](size_type pos) const { return ptr[pos]; }\n        const_iterator& operator++() { ptr++; return *this; }\n        const_iterator& operator--() { ptr--; return *this; }\n        const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; }\n        const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; }\n        difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); }\n        const_iterator operator+(size_type n) { return const_iterator(ptr + n); }\n        const_iterator& operator+=(size_type n) { ptr += n; return *this; }\n        const_iterator operator-(size_type n) { return const_iterator(ptr - n); }\n        const_iterator& operator-=(size_type n) { ptr -= n; return *this; }\n        bool operator==(const_iterator x) const { return ptr == x.ptr; }\n        bool operator!=(const_iterator x) const { return ptr != x.ptr; }\n        bool operator>=(const_iterator x) const { return ptr >= x.ptr; }\n        bool operator<=(const_iterator x) const { return ptr <= x.ptr; }\n        bool operator>(const_iterator x) const { return ptr > x.ptr; }\n        bool operator<(const_iterator x) const { return ptr < x.ptr; }\n    };\n\n    class const_reverse_iterator {\n        const T* ptr;\n    public:\n        typedef Diff difference_type;\n        typedef const T value_type;\n        typedef const T* pointer;\n        typedef const T& reference;\n        typedef std::bidirectional_iterator_tag iterator_category;\n        const_reverse_iterator(const T* ptr_) : ptr(ptr_) {}\n        const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}\n        const T& operator*() const { return *ptr; }\n        const T* operator->() const { return ptr; }\n        const_reverse_iterator& operator--() { ptr++; return *this; }\n        const_reverse_iterator& operator++() { ptr--; return *this; }\n        const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; }\n        const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; }\n        bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; }\n        bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; }\n    };\n\nprivate:\n#pragma pack(push, 1)\n    union direct_or_indirect {\n        char direct[sizeof(T) * N];\n        struct {\n            char* indirect;\n            size_type capacity;\n        } indirect_contents;\n    };\n#pragma pack(pop)\n    alignas(char*) direct_or_indirect _union = {};\n    size_type _size = 0;\n\n    static_assert(alignof(char*) % alignof(size_type) == 0 && sizeof(char*) % alignof(size_type) == 0, \"size_type cannot have more restrictive alignment requirement than pointer\");\n    static_assert(alignof(char*) % alignof(T) == 0, \"value_type T cannot have more restrictive alignment requirement than pointer\");\n\n    T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }\n    const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }\n    T* indirect_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.indirect_contents.indirect) + pos; }\n    const T* indirect_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.indirect_contents.indirect) + pos; }\n    bool is_direct() const { return _size <= N; }\n\n    void change_capacity(size_type new_capacity) {\n        if (new_capacity <= N) {\n            if (!is_direct()) {\n                T* indirect = indirect_ptr(0);\n                T* src = indirect;\n                T* dst = direct_ptr(0);\n                memcpy(dst, src, size() * sizeof(T));\n                free(indirect);\n                _size -= N + 1;\n            }\n        } else {\n            if (!is_direct()) {\n                /* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert\n                    success. These should instead use an allocator or new/delete so that handlers\n                    are called as necessary, but performance would be slightly degraded by doing so. */\n                _union.indirect_contents.indirect = static_cast<char*>(realloc(_union.indirect_contents.indirect, ((size_t)sizeof(T)) * new_capacity));\n                assert(_union.indirect_contents.indirect);\n                _union.indirect_contents.capacity = new_capacity;\n            } else {\n                char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));\n                assert(new_indirect);\n                T* src = direct_ptr(0);\n                T* dst = reinterpret_cast<T*>(new_indirect);\n                memcpy(dst, src, size() * sizeof(T));\n                _union.indirect_contents.indirect = new_indirect;\n                _union.indirect_contents.capacity = new_capacity;\n                _size += N + 1;\n            }\n        }\n    }\n\n    T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }\n    const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }\n\n    void fill(T* dst, ptrdiff_t count, const T& value = T{}) {\n        std::fill_n(dst, count, value);\n    }\n\n    template<typename InputIterator>\n    void fill(T* dst, InputIterator first, InputIterator last) {\n        while (first != last) {\n            new(static_cast<void*>(dst)) T(*first);\n            ++dst;\n            ++first;\n        }\n    }\n\npublic:\n    void assign(size_type n, const T& val) {\n        clear();\n        if (capacity() < n) {\n            change_capacity(n);\n        }\n        _size += n;\n        fill(item_ptr(0), n, val);\n    }\n\n    template<typename InputIterator>\n    void assign(InputIterator first, InputIterator last) {\n        size_type n = last - first;\n        clear();\n        if (capacity() < n) {\n            change_capacity(n);\n        }\n        _size += n;\n        fill(item_ptr(0), first, last);\n    }\n\n    prevector() {}\n\n    explicit prevector(size_type n) {\n        resize(n);\n    }\n\n    explicit prevector(size_type n, const T& val) {\n        change_capacity(n);\n        _size += n;\n        fill(item_ptr(0), n, val);\n    }\n\n    template<typename InputIterator>\n    prevector(InputIterator first, InputIterator last) {\n        size_type n = last - first;\n        change_capacity(n);\n        _size += n;\n        fill(item_ptr(0), first, last);\n    }\n\n    prevector(const prevector<N, T, Size, Diff>& other) {\n        size_type n = other.size();\n        change_capacity(n);\n        _size += n;\n        fill(item_ptr(0), other.begin(),  other.end());\n    }\n\n    prevector(prevector<N, T, Size, Diff>&& other) {\n        swap(other);\n    }\n\n    prevector& operator=(const prevector<N, T, Size, Diff>& other) {\n        if (&other == this) {\n            return *this;\n        }\n        assign(other.begin(), other.end());\n        return *this;\n    }\n\n    prevector& operator=(prevector<N, T, Size, Diff>&& other) {\n        swap(other);\n        return *this;\n    }\n\n    size_type size() const {\n        return is_direct() ? _size : _size - N - 1;\n    }\n\n    bool empty() const {\n        return size() == 0;\n    }\n\n    iterator begin() { return iterator(item_ptr(0)); }\n    const_iterator begin() const { return const_iterator(item_ptr(0)); }\n    iterator end() { return iterator(item_ptr(size())); }\n    const_iterator end() const { return const_iterator(item_ptr(size())); }\n\n    reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); }\n    const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); }\n    reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); }\n    const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); }\n\n    size_t capacity() const {\n        if (is_direct()) {\n            return N;\n        } else {\n            return _union.indirect_contents.capacity;\n        }\n    }\n\n    T& operator[](size_type pos) {\n        return *item_ptr(pos);\n    }\n\n    const T& operator[](size_type pos) const {\n        return *item_ptr(pos);\n    }\n\n    void resize(size_type new_size) {\n        size_type cur_size = size();\n        if (cur_size == new_size) {\n            return;\n        }\n        if (cur_size > new_size) {\n            erase(item_ptr(new_size), end());\n            return;\n        }\n        if (new_size > capacity()) {\n            change_capacity(new_size);\n        }\n        ptrdiff_t increase = new_size - cur_size;\n        fill(item_ptr(cur_size), increase);\n        _size += increase;\n    }\n\n    void reserve(size_type new_capacity) {\n        if (new_capacity > capacity()) {\n            change_capacity(new_capacity);\n        }\n    }\n\n    void shrink_to_fit() {\n        change_capacity(size());\n    }\n\n    void clear() {\n        resize(0);\n    }\n\n    iterator insert(iterator pos, const T& value) {\n        size_type p = pos - begin();\n        size_type new_size = size() + 1;\n        if (capacity() < new_size) {\n            change_capacity(new_size + (new_size >> 1));\n        }\n        T* ptr = item_ptr(p);\n        memmove(ptr + 1, ptr, (size() - p) * sizeof(T));\n        _size++;\n        new(static_cast<void*>(ptr)) T(value);\n        return iterator(ptr);\n    }\n\n    void insert(iterator pos, size_type count, const T& value) {\n        size_type p = pos - begin();\n        size_type new_size = size() + count;\n        if (capacity() < new_size) {\n            change_capacity(new_size + (new_size >> 1));\n        }\n        T* ptr = item_ptr(p);\n        memmove(ptr + count, ptr, (size() - p) * sizeof(T));\n        _size += count;\n        fill(item_ptr(p), count, value);\n    }\n\n    template<typename InputIterator>\n    void insert(iterator pos, InputIterator first, InputIterator last) {\n        size_type p = pos - begin();\n        difference_type count = last - first;\n        size_type new_size = size() + count;\n        if (capacity() < new_size) {\n            change_capacity(new_size + (new_size >> 1));\n        }\n        T* ptr = item_ptr(p);\n        memmove(ptr + count, ptr, (size() - p) * sizeof(T));\n        _size += count;\n        fill(ptr, first, last);\n    }\n\n    inline void resize_uninitialized(size_type new_size) {\n        // resize_uninitialized changes the size of the prevector but does not initialize it.\n        // If size < new_size, the added elements must be initialized explicitly.\n        if (capacity() < new_size) {\n            change_capacity(new_size);\n            _size += new_size - size();\n            return;\n        }\n        if (new_size < size()) {\n            erase(item_ptr(new_size), end());\n        } else {\n            _size += new_size - size();\n        }\n    }\n\n    iterator erase(iterator pos) {\n        return erase(pos, pos + 1);\n    }\n\n    iterator erase(iterator first, iterator last) {\n        // Erase is not allowed to the change the object's capacity. That means\n        // that when starting with an indirectly allocated prevector with\n        // size and capacity > N, the result may be a still indirectly allocated\n        // prevector with size <= N and capacity > N. A shrink_to_fit() call is\n        // necessary to switch to the (more efficient) directly allocated\n        // representation (with capacity N and size <= N).\n        iterator p = first;\n        char* endp = (char*)&(*end());\n        if (!std::is_trivially_destructible<T>::value) {\n            while (p != last) {\n                (*p).~T();\n                _size--;\n                ++p;\n            }\n        } else {\n            _size -= last - p;\n        }\n        memmove(&(*first), &(*last), endp - ((char*)(&(*last))));\n        return first;\n    }\n\n    template<typename... Args>\n    void emplace_back(Args&&... args) {\n        size_type new_size = size() + 1;\n        if (capacity() < new_size) {\n            change_capacity(new_size + (new_size >> 1));\n        }\n        new(item_ptr(size())) T(std::forward<Args>(args)...);\n        _size++;\n    }\n\n    void push_back(const T& value) {\n        emplace_back(value);\n    }\n\n    void pop_back() {\n        erase(end() - 1, end());\n    }\n\n    T& front() {\n        return *item_ptr(0);\n    }\n\n    const T& front() const {\n        return *item_ptr(0);\n    }\n\n    T& back() {\n        return *item_ptr(size() - 1);\n    }\n\n    const T& back() const {\n        return *item_ptr(size() - 1);\n    }\n\n    void swap(prevector<N, T, Size, Diff>& other) {\n        std::swap(_union, other._union);\n        std::swap(_size, other._size);\n    }\n\n    ~prevector() {\n        if (!std::is_trivially_destructible<T>::value) {\n            clear();\n        }\n        if (!is_direct()) {\n            free(_union.indirect_contents.indirect);\n            _union.indirect_contents.indirect = nullptr;\n        }\n    }\n\n    bool operator==(const prevector<N, T, Size, Diff>& other) const {\n        if (other.size() != size()) {\n            return false;\n        }\n        const_iterator b1 = begin();\n        const_iterator b2 = other.begin();\n        const_iterator e1 = end();\n        while (b1 != e1) {\n            if ((*b1) != (*b2)) {\n                return false;\n            }\n            ++b1;\n            ++b2;\n        }\n        return true;\n    }\n\n    bool operator!=(const prevector<N, T, Size, Diff>& other) const {\n        return !(*this == other);\n    }\n\n    bool operator<(const prevector<N, T, Size, Diff>& other) const {\n        if (size() < other.size()) {\n            return true;\n        }\n        if (size() > other.size()) {\n            return false;\n        }\n        const_iterator b1 = begin();\n        const_iterator b2 = other.begin();\n        const_iterator e1 = end();\n        while (b1 != e1) {\n            if ((*b1) < (*b2)) {\n                return true;\n            }\n            if ((*b2) < (*b1)) {\n                return false;\n            }\n            ++b1;\n            ++b2;\n        }\n        return false;\n    }\n\n    size_t allocated_memory() const {\n        if (is_direct()) {\n            return 0;\n        } else {\n            return ((size_t)(sizeof(T))) * _union.indirect_contents.capacity;\n        }\n    }\n\n    value_type* data() {\n        return item_ptr(0);\n    }\n\n    const value_type* data() const {\n        return item_ptr(0);\n    }\n};\n\n#endif // CORE_PREVECTOR_H\n"
  },
  {
    "path": "src/primitives/block.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"primitives/block.h\"\n\n#include \"hash.h\"\n#include \"tinyformat.h\"\n#include \"util/strencodings.h\"\n#include \"crypto/common.h\"\n#include <chainparams.h>\n\nuint256 CBlockHeader::GetHashLegacy() const\n{\n    //if (!cachedHash.IsNull())\n        //return cachedHash;\n\n    //cachedHash = SerializeHash(*this);\n    //return cachedHash;\n    return SerializeHash(*this, SER_GETHASH, SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS);\n}\n\nuint256 CBlockHeader::GetHashPoW2(bool force) const\n{\n    if (force)\n        assert(nVersionPoW2Witness != 0 || nTimePoW2Witness != 0);\n\n    if (nVersionPoW2Witness == 0 || nTimePoW2Witness == 0)\n        return SerializeHash(*this, SER_GETHASH, SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS);\n\n    return SerializeHash(*this, SER_GETHASH, SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS_SIG);\n}\n\nuint256 CBlock::GetPoWHash() const\n{\n    //if (!cachedPOWHash.IsNull())\n        //return cachedPOWHash;\n\n    uint256 hashRet;\n\n    static bool fRegTest = Params().IsRegtest();\n    static bool fRegTestLegacy = Params().IsRegtestLegacy();\n    //CBSU - maybe use a static functor or something here instead of having the branch \n    if (fRegTestLegacy)\n    {\n        arith_uint256 thash;\n        arith_uint256 fhash;\n        hash_sha256(BEGIN(nVersion), 80, thash);\n        hash_sha256(BEGIN(thash), 32, fhash);\n        hashRet = ArithToUint256(fhash);\n    }\n    else\n    {\n        //CBSU - maybe use a static functor or something here instead of having the branch \n        static bool hashCity = (fRegTest) ? true : ( (Params().IsTestnet()) ? ( GetArg(\"-testnet\", \"\")[0] == 'C' ? true : false ) : false);\n        if (hashCity)\n        {\n            arith_uint256 thash;\n            hash_city(BEGIN(nVersion), thash);\n            hashRet = ArithToUint256(thash);\n        }\n        else\n        {\n            char scratchpad[SCRYPT_SCRATCHPAD_SIZE];\n            scrypt_1024_1_1_256_sp(BEGIN(nVersion), BEGIN(hashRet), scratchpad);\n        }\n    }\n    //cachedPOWHash = ArithToUint256(thash);\n    //return cachedPOWHash;\n    return hashRet;\n}\n\nstd::string CBlock::ToString() const\n{\n    std::stringstream s;\n    //fixme: (SIGMA)\n    s << strprintf(\"CBlock(hashlegacy=%s, hashpow2=%s, powhash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\\n\",\n        GetHashLegacy().ToString(),\n        GetHashPoW2().ToString(),\n        GetPoWHash().ToString().c_str(),\n        nVersion,\n        hashPrevBlock.ToString(),\n        hashMerkleRoot.ToString(),\n        nTime, nBits, nNonce,\n        vtx.size());\n    for (unsigned int i = 0; i < vtx.size(); i++)\n    {\n        s << \"  \" << vtx[i]->ToString() << \"\\n\";\n    }\n    return s.str();\n}\n\nint64_t GetBlockWeight(const CBlock& block)\n{\n    // segsig: block weight = block size, including the size of the segregated signatures - no complicated segwit weighting shenanigans necessary.\n    return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);\n}\n"
  },
  {
    "path": "src/primitives/block.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef PRIMITIVES_BLOCK_H\n#define PRIMITIVES_BLOCK_H\n\n#include \"primitives/transaction.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n#include \"arith_uint256.h\"\n#include \"util/strencodings.h\"\n#include \"util.h\"\n#include <crypto/hash/hash.h>\n\n#define SERIALIZE_BLOCK_HEADER_NO_WITNESS_DELTA    0x10000000\n#define SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS     0x20000000\n#define SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS_SIG 0x40000000\n\ninline double GetHumanDifficultyFromBits(uint64_t nBits)\n{\n    int nShift = (nBits >> 24) & 0xff;\n\n    double dDiff =(double)0x0000ffff / (double)(nBits & 0x00ffffff);\n\n    while (nShift < 29)\n    {\n        dDiff *= 256.0;\n        nShift++;\n    }\n    while (nShift > 29)\n    {\n        dDiff /= 256.0;\n        nShift--;\n    }\n\n    // SIGMA - We multiply by 1'000'000'000 to get a better human readable difficulty.\n    // Otherwise the SIGMA difficulty will always be fractional and look strange.\n    return dDiff * 1000000000;\n}\n\n/** Nodes collect new transactions into a block, hash them into a hash tree,\n * and scan through nonce values to make the block's hash satisfy proof-of-work\n * requirements.  When they solve the proof-of-work, they broadcast the block\n * to everyone and the block is added to the block chain.  The first transaction\n * in the block is a special one that creates a new coin owned by the creator\n * of the block.\n */\nclass CBlockHeader\n{\npublic:\n    // PoW2 Witness header\n    int32_t nVersionPoW2Witness;\n    uint32_t nTimePoW2Witness;\n    uint256 hashMerkleRootPoW2Witness;\n    //fixme: (POST-PHASE5) Optimisation - this is always 65 bits, we should use a fixed size data structure.\n    std::vector<unsigned char> witnessHeaderPoW2Sig;\n    \n    // Changes in the witness UTXO that this block causes\n    std::vector<unsigned char> witnessUTXODelta;\n\n\n    // PoW header\n    int32_t nVersion;\n    uint256 hashPrevBlock;\n    uint256 hashMerkleRoot;\n    uint32_t nTime;\n    uint32_t nBits;\n\n    //fixme: (SIGMA) - Ensure this works on both big and little endian - if not we might have to drop the struct and just use bit manipulation instead.\n    union\n    {\n        struct\n        {\n            uint16_t nPreNonce;\n            uint16_t nPostNonce;\n        };\n        uint32_t nNonce;\n    };\n\n    CBlockHeader()\n    {\n        SetNull();\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        //fixme: (PHASE5) Remove support for legacy nodes - no longer need this once phase4 is locked in.\n        if (!(s.GetVersion() & SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS))\n        {\n            READWRITE(nVersionPoW2Witness);\n            READWRITE(nTimePoW2Witness);\n            READWRITE(hashMerkleRootPoW2Witness);\n        }\n\n        READWRITE(this->nVersion);\n        READWRITE(hashPrevBlock);\n        READWRITE(hashMerkleRoot);\n        READWRITE(nTime);\n        READWRITE(nBits);\n        READWRITE(nNonce);\n\n        //fixme: (PHASE5) Remove support for legacy nodes - no longer need this once phase4 is locked in.\n        if (nVersionPoW2Witness != 0)\n        {\n            if (!(s.GetVersion() & SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS))\n            {\n                if (!(s.GetVersion() & SERIALIZE_BLOCK_HEADER_NO_POW2_WITNESS_SIG))\n                {\n                    if (ser_action.ForRead())\n                        witnessHeaderPoW2Sig.resize(65);\n                    else\n                        assert(witnessHeaderPoW2Sig.size() == 65);\n                    READWRITENOSIZEVECTOR(witnessHeaderPoW2Sig);\n                }\n                \n                if (!(s.GetVersion() & SERIALIZE_BLOCK_HEADER_NO_WITNESS_DELTA))\n                {\n                    if( (s.GetType() == SER_DISK) || \n                        ((s.GetType() == SER_NETWORK) && (s.GetVersion() % 80000 >= WITNESS_SYNC_VERSION)) ||\n                        ((s.GetType() == SER_GETHASH) && (witnessUTXODelta.size() > 0)) )\n                    {\n                        //fixme: (WITNESS_SYNC) - If size is frequently above 200 then switch to varint instead\n                        READWRITECOMPACTSIZEVECTOR(witnessUTXODelta);\n                    }\n                }\n            }\n        }\n    }\n\n    void SetNull()\n    {\n        nVersion = 0;\n        hashPrevBlock.SetNull();\n        hashMerkleRoot.SetNull();\n        nTime = 0;\n        nBits = 0;\n        nNonce = 0;\n\n        nVersionPoW2Witness = 0;\n        nTimePoW2Witness = 0;\n        hashMerkleRootPoW2Witness.SetNull();\n        witnessHeaderPoW2Sig.clear();\n        witnessUTXODelta.clear();\n    }\n\n    bool IsNull() const\n    {\n        return (nBits == 0);\n    }\n\n    //fixme: (POST-PHASE5) SBSU - this gives speed boost\n    //but causes issues for mining\n    //Disabled out of concern it may cause issues for others as well\n    //re-enable once carefully looking into the below assertion.\n    //Munt-daemon: main.cpp:2341: bool ConnectBlock(const CBlock&, CValidationState&, CBlockIndex*, CCoinsViewCache&, const CChainParams&, bool): Assertion `hashPrevBlock == view.GetBestBlock()' failed.\n    //mutable uint256 cachedHash;\n    uint256 GetHashLegacy() const;\n\n    uint256 GetHashPoW2(bool force=false) const;\n\n    int64_t GetBlockTime() const\n    {\n        return (int64_t)nTime;\n    }\n};\n\n\nclass CBlock : public CBlockHeader\n{\npublic:\n    // network and disk\n    std::vector<CTransactionRef> vtx;\n\n    // memory only\n    mutable bool fChecked;\n    mutable bool fPOWChecked;\n\n    CBlock()\n    {\n        SetNull();\n    }\n\n    CBlock(const CBlockHeader &header)\n    {\n        SetNull();\n        *((CBlockHeader*)this) = header;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(*(CBlockHeader*)this);\n        READWRITECOMPACTSIZEVECTOR(vtx);\n    }\n\n    void SetNull()\n    {\n        CBlockHeader::SetNull();\n        vtx.clear();\n        fChecked = false;\n        fPOWChecked = false;\n        //cachedHash = uint256();\n        //cachedPOWHash = uint256();\n    }\n\n    //mutable uint256 cachedPOWHash;\n    uint256 GetPoWHash() const;\n\n    CBlockHeader GetBlockHeader() const\n    {\n        CBlockHeader block;\n        block.nVersion       = nVersion;\n        block.hashPrevBlock  = hashPrevBlock;\n        block.hashMerkleRoot = hashMerkleRoot;\n        block.nTime          = nTime;\n        block.nBits          = nBits;\n        block.nNonce         = nNonce;\n        block.nVersionPoW2Witness = nVersionPoW2Witness;\n        block.nTimePoW2Witness = nTimePoW2Witness;\n        block.hashMerkleRootPoW2Witness = hashMerkleRootPoW2Witness;\n        block.witnessHeaderPoW2Sig = witnessHeaderPoW2Sig;\n        block.witnessUTXODelta = witnessUTXODelta;\n        return block;\n    }\n\n    std::string ToString() const;\n};\n\n/** Describes a place in the block chain to another node such that if the\n * other node doesn't have the same branch, it can find a recent common trunk.\n * The further back it is, the further before the fork it may be.\n */\nstruct CBlockLocator\n{\n    std::vector<uint256> vHave;\n\n    CBlockLocator() {}\n\n    CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        int nVersion = s.GetVersion();\n        if (!(s.GetType() & SER_GETHASH))\n            READWRITE(nVersion);\n        READWRITECOMPACTSIZEVECTOR(vHave);\n    }\n\n    void SetNull()\n    {\n        vHave.clear();\n    }\n\n    bool IsNull() const\n    {\n        return vHave.empty();\n    }\n};\n\n/** Compute the consensus-critical block weight (see BIP 141). */\nint64_t GetBlockWeight(const CBlock& tx);\n\n#endif\n"
  },
  {
    "path": "src/primitives/transaction.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"primitives/transaction.h\"\n\n#include \"hash.h\"\n#include \"tinyformat.h\"\n#include \"util/strencodings.h\"\n\nuint256 COutPoint::getBucketHash() const\n{\n    if (isHash)\n    {\n        return hash;\n    }\n    else\n    {\n        return prevBlock.getHash();\n    }\n}\n\nuint256 COutPoint::getTransactionHash() const\n{\n    assert(isHash);\n    return hash;\n}\n\nstd::string COutPoint::ToString() const\n{\n    if (isHash)\n        return strprintf(\"COutPoint(hash=%s, out_index=%u)\", hash.ToString().substr(0,10), n);\n    else\n        return strprintf(\"COutPoint(tx_height=%u, tx_index=%u, out_index=%u)\", prevBlock.blockNumber, prevBlock.transactionIndex, n);\n}\n\nCTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn, uint8_t nFlagsIn)\n{\n    prevout = prevoutIn;\n    scriptSig = scriptSigIn;\n    nSequence = nSequenceIn;\n    nTypeAndFlags = CURRENT_TYPE | nFlagsIn;\n    if (!prevout.isHash)\n        SetFlag(CTxInFlags::IndexBasedOutpoint);\n}\n\nCTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn, uint8_t nFlagsIn)\n{\n    prevout = COutPoint(hashPrevTx, nOut);\n    scriptSig = scriptSigIn;\n    nSequence = nSequenceIn;\n    nTypeAndFlags = CURRENT_TYPE | nFlagsIn;\n}\n\nstd::string CTxIn::ToString() const\n{\n    std::string str;\n    str += \"CTxIn(\";\n    str += prevout.ToString();\n    if (prevout.IsNull())\n        str += strprintf(\", coinbase %s\", HexStr(scriptSig));\n    else\n        str += strprintf(\", scriptSig=%s\", HexStr(scriptSig).substr(0, 24));\n        \n    if (FlagIsSet(CTxInFlags::HasRelativeLock))\n    {\n        str += strprintf(\", relativeLockSequence=%u\", nSequence);\n    }\n    else if (FlagIsSet(CTxInFlags::HasAbsoluteLock))\n    {\n        str += strprintf(\", absoluteLockSequence=%u\", nSequence);\n    }\n    //fixme: (PHASE5) - Other sequence behaviours we should log?\n    //else if(...)\n    //{\n    //}\n    //fixme: (PHASE5) - we can remove the below\n    else\n    {\n        if (nSequence != SEQUENCE_FINAL)\n            str += strprintf(\", nSequence=%u\", nSequence);\n    }\n    str += \")\";\n    return str;\n}\n\nCTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)\n{\n    //NB! Important otherwise we fail to initialise some member variables.\n    //CBSU - possibly initialise only those variables instead of double assigning nValue and nType\n    SetNull();\n\n    nValue = nValueIn;\n    SetType(CTxOutType::ScriptLegacyOutput);\n    output.scriptPubKey = scriptPubKeyIn;\n}\n\nCTxOut::CTxOut(const CAmount& nValueIn, CTxOutPoW2Witness witnessDetails)\n{\n    //NB! Important otherwise we fail to initialise some member variables.\n    //CBSU - possibly initialise only those variables instead of double assigning nValue and nType\n    SetNull();\n\n    nValue = nValueIn;\n    SetType(CTxOutType::PoW2WitnessOutput);\n    output.witnessDetails = witnessDetails;\n}\n\nCTxOut::CTxOut(const CAmount& nValueIn, CTxOutStandardKeyHash standardKeyHash)\n{\n    //NB! Important otherwise we fail to initialise some member variables.\n    //CBSU - possibly initialise only those variables instead of double assigning nValue and nType\n    SetNull();\n\n    nValue = nValueIn;\n    SetType(CTxOutType::StandardKeyHashOutput);\n    output.standardKeyHash = standardKeyHash;\n}\n\nstd::string CTxOut::ToString() const\n{\n    return strprintf(\"CTxOut(nValue=%d.%08d, type=%s, data=%s)\", nValue / COIN, nValue % COIN, GetTypeAsString(), output.GetHex().substr(0, 30));\n}\n\n//fixme: (PHASE5) restore CURRENT_VERSION behaviour here.\n//CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), flags(0), extraFlags(0) {}\nCMutableTransaction::CMutableTransaction(int32_t nVersion_) : nVersion(nVersion_), nLockTime(0), flags(0), extraFlags(0) {}\nCMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), flags(tx.flags), extraFlags(tx.extraFlags) {}\n\nuint256 CMutableTransaction::GetHash() const\n{\n    if (!IsOldTransactionVersion(nVersion))\n        return SerializeHash(*this, SER_GETHASH, 0);\n    else\n        return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES);\n}\n\nuint256 CTransaction::ComputeHash() const\n{\n    if (!IsOldTransactionVersion(nVersion))\n        return SerializeHash(*this, SER_GETHASH, 0);\n    else\n        return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES);\n}\n\nuint256 CTransaction::GetWitnessHash() const\n{\n    if (nVersion < 3)\n    {\n        if (!HasSegregatedSignatures()) {\n            return GetHash();\n        }\n    }\n    return SerializeHash(*this, SER_GETHASH, 0);\n}\n\n/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */\n//fixme: (PHASE5) restore CURRENT_VERSION behaviour here.\n//CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), flags(0), extraFlags(0), hash() {}\nCTransaction::CTransaction(int32_t nVersion_) : nVersion(nVersion_), vin(), vout(), nLockTime(0), flags(0), extraFlags(0), hash() {}\nCTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), flags(tx.flags), extraFlags(tx.extraFlags), hash(ComputeHash()) {}\nCTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), flags(tx.flags), extraFlags(tx.extraFlags), hash(ComputeHash()) {}\n\nCAmount CTransaction::GetValueOut() const\n{\n    CAmount nValueOut = 0;\n    for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)\n    {\n        if (it->nValue > 0)\n        {\n            nValueOut += it->nValue;\n            if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))\n                throw std::runtime_error(std::string(__func__) + \": value out of range\");\n        }\n    }\n    return nValueOut;\n}\n\nunsigned int CTransaction::GetTotalSize() const\n{\n    return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);\n}\n\nstd::string CTransaction::ToString() const\n{\n    std::string str;\n    str += strprintf(\"CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\\n\",\n        GetHash().ToString().substr(0,10),\n        nVersion,\n        vin.size(),\n        vout.size(),\n        nLockTime);\n    for (unsigned int i = 0; i < vin.size(); i++)\n        str += \"    \" + vin[i].ToString() + \"\\n\";\n    for (unsigned int i = 0; i < vin.size(); i++)\n        str += \"    \" + vin[i].segregatedSignatureData.ToString() + \"\\n\";\n    for (unsigned int i = 0; i < vout.size(); i++)\n        str += \"    \" + vout[i].ToString() + \"\\n\";\n    return str;\n}\n\nint64_t GetTransactionWeight(const CTransaction& tx)\n{\n    // segsig: transaction weight = transaction size, including the size of the segregated signatures - no complicated segwit weighting shenanigans necessary.\n    return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);\n}\n"
  },
  {
    "path": "src/primitives/transaction.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef PRIMITIVES_TRANSACTION_H\n#define PRIMITIVES_TRANSACTION_H\n\n#include \"amount.h\"\n#include \"script/script.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n\n//Munt\n#include \"pubkey.h\"\n#include \"streams.h\"\n#include \"util/strencodings.h\"\n#include <new> // Required for placement 'new'.\n#include <bitset>\n\n\nstatic const int SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES = 0x40000000;\n\ninline bool IsOldTransactionVersion(const unsigned int nVersion)\n{\n    return (nVersion < 5) || (nVersion == 536870912);\n}\n\nstruct CBlockPosition\n{\n    uint64_t blockNumber; // Position of block on blockchain that contains our transaction.\n    uint64_t transactionIndex; // Position of transaction within the block.\n    CBlockPosition(uint64_t blockNumber_, uint64_t transactionIndex_) : blockNumber(blockNumber_), transactionIndex(transactionIndex_) {}\n\n    uint256 getHash() const\n    {\n        std::vector<unsigned char> serData;\n        {\n            CVectorWriter serializedBlockPosition(SER_NETWORK, INIT_PROTO_VERSION, serData, 0);\n            serializedBlockPosition << blockNumber;\n            serializedBlockPosition << transactionIndex;\n        }\n        std::string sHex = HexStr(serData);\n        return Hash(sHex.begin(), sHex.end());\n    }\n\n    friend bool operator<(const CBlockPosition& a, const CBlockPosition& b)\n    {\n        if (a.blockNumber != b.blockNumber)\n        {\n            return a.blockNumber < b.blockNumber;\n        }\n        else\n        {\n            return a.transactionIndex < b.transactionIndex;\n        }\n    }\n\n    friend bool operator==(const CBlockPosition& a, const CBlockPosition& b)\n    {\n        return (a.blockNumber == b.blockNumber && a.transactionIndex == b.transactionIndex);\n    }\n};\n\n\n// Represented in class as 3 bits.\n// Maximum of 8 values\nenum CTxInType : uint8_t\n{\n    CURRENT_TX_IN_TYPE = 0,\n    FUTURE_TX_IN_TYPE2 = 1,\n    FUTURE_TX_IN_TYPE3 = 2,\n    FUTURE_TX_IN_TYPE4 = 3,\n    FUTURE_TX_IN_TYPE5 = 4,\n    FUTURE_TX_IN_TYPE6 = 5,\n    FUTURE_TX_IN_TYPE7 = 6,\n    FUTURE_TX_IN_TYPE8 = 7\n};\n\n//fixme: (PHASE4) (MOBILE) (SPV) (SEGSIG) Ensure IndexBasedOutpoint working on mobile SPV wallets\n//fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n// Only 5 bits available for TxInFlags.\n// The are used as bit flags so only 5 values possible each with an on/off state.\n// All 5 values are currently in use.\nenum CTxInFlags : uint8_t\n{\n    // The actual flag values\n    IndexBasedOutpoint = 1,                                                         // Outpoint is an index instead of a hash.\n    OptInRBF = 2,                                                                   // CTxIn allows RBF.\n    HasAbsoluteLock = 4,                                                            // CTxIn uses \"absolute\" locktime.\n    HasTimeBasedRelativeLock = 8,                                                   // CTxIn uses time based \"relative\" locktime.\n    HasBlockBasedRelativeLock = 16,                                                 // CTxIn uses block based \"relative\" locktime.\n    // Below are mask/setting helpers\n    None = 0,\n    HasRelativeLock = HasTimeBasedRelativeLock | HasBlockBasedRelativeLock,\n    HasLock = HasRelativeLock | HasAbsoluteLock\n};\n\n#define UINT31_MAX 2147483647\n\n/** An outpoint - a combination of a transaction hash and an index n into its vout */\nclass COutPoint\n{\nprivate:\n     //fixme: (POST-PHASE5) (MED) - We can reduce memory consumption here by using something like prevector for hash cases.\n    // Outpoint either uses hash or 'block position' never both.\n    union\n    {\n        uint256 hash;\n        CBlockPosition prevBlock;\n    };\npublic:\n    uint32_t isHash: 1; // Set to 0 when using prevBlock, 1 when using hash.\n    uint32_t n : 31;\n\n    COutPoint()\n    : hash(uint256())\n    , isHash(1)\n    , n(UINT31_MAX)\n    {\n    }\n    COutPoint(const uint256& hashIn, uint32_t nIn)\n    :\n    hash(hashIn)\n    , isHash(1)\n    , n(nIn)\n    {\n    }\n    COutPoint(const uint64_t blockNumber, const uint64_t transactionIndex, uint32_t nIn)\n    : prevBlock(blockNumber, transactionIndex)\n    , isHash(0)\n    , n(nIn)\n    {\n    }\n\n    uint64_t getTransactionBlockNumber() const\n    {\n        assert(!isHash);\n        return prevBlock.blockNumber;\n    }\n    \n    uint64_t getTransactionIndex() const\n    {\n        assert(!isHash);\n        return prevBlock.transactionIndex;\n    }\n\n    // Hash suitable for bucketized containers such as std::unordered_map, do NOT assume this is the transaction hash!\n    uint256 getBucketHash() const;\n\n    // Transaction hash only for isHash outpoints\n    uint256 getTransactionHash() const;\n\n    void setHash(uint256 hash_)\n    {\n        hash = hash_;\n        isHash = 1;\n    }\n\n    template <typename Stream> inline void ReadFromStream(Stream& s, CTxInType nType, CTxInFlags nFlags, int nTransactionVersion)\n    {\n        // Future, if we ever make use of future input types e.g. FUTURE_TX_IN_TYPE2 then we must make use of them here\n        (void) nType;\n        CSerActionUnserialize ser_action;\n\n        if (IsOldTransactionVersion(nTransactionVersion))\n        {\n            isHash = 1;\n            STRREAD(hash);\n            uint32_t n_;\n            STRREAD(n_);\n            n = n_;\n        }\n        else\n        {\n            if ((nFlags & CTxInFlags::IndexBasedOutpoint) == 0)\n            {\n                isHash = 1;\n                STRREAD(hash);\n            }\n            else\n            {\n                isHash = 0;\n                STRREAD(VARINT(prevBlock.blockNumber));\n                STRREAD(VARINT(prevBlock.transactionIndex));\n            }\n            uint32_t n_ = 0;\n            STRREAD(VARINT(n_));\n            n = n_;\n        }\n    }\n\n    template <typename Stream> inline void WriteToStream(Stream& s, CTxInType nType, CTxInFlags nFlags, int nTransactionVersion) const\n    {\n        // Future, if we ever make use of future input types e.g. FUTURE_TX_IN_TYPE2 then we must make use of them here\n        (void) nType;\n        CSerActionSerialize ser_action;\n\n        if (IsOldTransactionVersion(nTransactionVersion))\n        {\n            STRWRITE(hash);\n            uint32_t nTemp = (n == UINT31_MAX ? std::numeric_limits<uint32_t>::max() : (uint32_t)n);\n            STRWRITE(nTemp);\n        }\n        else\n        {\n            if ((nFlags & CTxInFlags::IndexBasedOutpoint) == 0)\n            {\n                STRWRITE(hash);\n            }\n            else\n            {\n                STRWRITE(VARINT(prevBlock.blockNumber));\n                STRWRITE(VARINT(prevBlock.transactionIndex));\n            }\n            uint32_t n_ = n;\n            STRWRITE(VARINT(n_));\n        }\n    }\n\n    void SetNull() { hash.SetNull(); n = UINT31_MAX; }\n    bool IsNull() const { return (hash.IsNull() && n == UINT31_MAX); }\n\n    friend bool operator<(const COutPoint& a, const COutPoint& b)\n    {\n        if (a.isHash == b.isHash)\n        {\n            if (a.isHash)\n            {\n                if (a.hash == b.hash)\n                {\n                    return a.n < b.n;\n                }\n                else\n                {\n                    return a.hash < b.hash;\n                }\n            }\n            else\n            {\n                if (a.prevBlock == b.prevBlock)\n                {\n                    return a.n < b.n;\n                }\n                else\n                {\n                    return a.prevBlock < b.prevBlock;\n                }\n            }\n        }\n        else\n        {\n            return a.isHash < b.isHash;\n        }\n    }\n\n    friend bool operator==(const COutPoint& a, const COutPoint& b)\n    {\n        return (a.isHash == b.isHash && ((a.isHash && a.hash == b.hash) || (!a.isHash && a.prevBlock == b.prevBlock)) && a.n == b.n);\n    }\n\n    friend bool operator!=(const COutPoint& a, const COutPoint& b)\n    {\n        return !(a == b);\n    }\n\n    std::string ToString() const;\n};\n\n/** An input of a transaction.  It contains the location of the previous\n * transaction's output that it claims and a signature that matches the\n * output's public key.\n */\nclass CTxIn\n{\npublic:\n    static const uint8_t CURRENT_TYPE=0;\n    // First 3 bits are type, last 5 bits are flags.\n    mutable uint8_t nTypeAndFlags;\n    //fixme: (POST-PHASE5) gcc - future - In an ideal world we would just have nType be of type 'CTxOutType' - however GCC spits out unavoidable warnings when using an enum as part of a bitfield, so we use these getter/setter methods to work around it.\n    CTxInType GetType() const\n    {\n        return (CTxInType) ( (nTypeAndFlags & 0b11100000) >> 5 );\n    }\n    CTxInFlags GetFlags() const\n    {\n        return (CTxInFlags) ( nTypeAndFlags & 0b00011111 );\n    }\n    bool FlagIsSet(CTxInFlags flag) const\n    {\n        return (GetFlags() & flag) != 0;\n    }\n    void SetFlag(CTxInFlags flag) const\n    {\n        nTypeAndFlags |= flag;\n        if (!FlagIsSet(CTxInFlags::HasRelativeLock))\n        {\n            nSequence = 0;\n        }\n    }\n    void UnsetFlag(CTxInFlags flag) const\n    {\n        nTypeAndFlags &= ~flag;\n        if (!FlagIsSet(CTxInFlags::HasRelativeLock))\n        {\n            nSequence = 0;\n        }\n    }\n    uint32_t GetSequence(int nTransactionVersion) const\n    {\n        if (IsOldTransactionVersion(nTransactionVersion) || FlagIsSet(CTxInFlags::HasRelativeLock))\n            return nSequence;\n        return 0;\n    }\n    void SetSequence(uint32_t nSequence_, int nTransactionVersion, CTxInFlags sequenceType)\n    {\n        if (IsOldTransactionVersion(nTransactionVersion))\n        {\n            nSequence = nSequence_;\n        }\n        else\n        {\n            SetFlag(sequenceType);\n            if (FlagIsSet(CTxInFlags::HasRelativeLock))\n            {\n                nSequence = nSequence_;\n            }\n        }\n    }\n    const COutPoint& GetPrevOut() const { return prevout; };\n    void SetPrevOut(const COutPoint& prevout_)\n    {\n        prevout = prevout_;\n        if (!prevout.isHash)\n            SetFlag(CTxInFlags::IndexBasedOutpoint);\n    }\n    void SetPrevOutNull()\n    {\n        prevout.SetNull();\n    }\n    CScript scriptSig;\nprivate:\n    COutPoint prevout;\n    mutable uint32_t nSequence;\npublic:\n    CSegregatedSignatureData segregatedSignatureData; //! Only serialized through CTransaction\n\n    /* Setting nSequence to this value for every input in a transaction\n     * disables nLockTime. */\n    static const uint32_t SEQUENCE_FINAL = 0xffffffff;\n\n    /* Below flags apply in the context of BIP 68*/\n    /* If this flag set, CTxIn::nSequence is NOT interpreted as a\n     * relative lock-time. */\n    static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);\n\n    /* If CTxIn::nSequence encodes a relative lock-time and this flag\n     * is set, the relative lock-time has units of 512 seconds,\n     * otherwise it specifies blocks with a granularity of 1. */\n    static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);\n\n    /* If CTxIn::nSequence encodes a relative lock-time, this mask is\n     * applied to extract that lock-time from the sequence field. */\n    static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;\n\n    /* In order to use the same number of bits to encode roughly the\n     * same wall-clock duration, and because blocks are naturally\n     * limited to occur every 150s on average, the minimum granularity\n     * for time-based relative lock-time is fixed at 128 seconds.\n     * Converting from CTxIn::nSequence to seconds is performed by\n     * multiplying by 128 = 2^7, or equivalently shifting up by\n     * 7 bits. */\n    static const int SEQUENCE_LOCKTIME_GRANULARITY = 7;\n\n    CTxIn()\n    {\n        nSequence = SEQUENCE_FINAL;\n        nTypeAndFlags = CURRENT_TYPE;\n    }\n\n    explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn, uint8_t nFlagsIn);\n    CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn, uint8_t nFlagsIn);\n\n    template <typename Stream> inline void ReadFromStream(Stream& s, int nTransactionVersion)\n    {\n        CSerActionUnserialize ser_action;\n\n        //2.0 onwards we have versioning for CTxIn\n        if (!IsOldTransactionVersion(nTransactionVersion))\n        {\n            STRREAD(nTypeAndFlags);\n\n            prevout.ReadFromStream(s, GetType(), GetFlags(), nTransactionVersion);\n            //scriptSig is no longer used - everything goes in segregatedSignatureData.\n            if (FlagIsSet(CTxInFlags::HasRelativeLock))\n            {\n                s >> VARINT(nSequence);\n            }\n        }\n        else\n        {\n            prevout.ReadFromStream(s, GetType(), GetFlags(), nTransactionVersion);\n            STRREAD(*(CScriptBase*)(&scriptSig));\n            STRREAD(nSequence);\n        }\n    }\n    template <typename Stream> inline void WriteToStream(Stream& s, int nTransactionVersion) const\n    {\n        CSerActionSerialize ser_action;\n\n        if (!IsOldTransactionVersion(nTransactionVersion))\n        {\n            //if (nSequence != SEQUENCE_FINAL)\n                //nTypeAndFlags |= HasSequenceNumberMask;\n            STRWRITE(nTypeAndFlags);\n\n            prevout.WriteToStream(s, GetType(), GetFlags(), nTransactionVersion);\n\n            if (FlagIsSet(CTxInFlags::HasRelativeLock))\n            {\n                s << VARINT(nSequence);\n            }\n        }\n        else\n        {\n            prevout.WriteToStream(s, GetType(), GetFlags(), nTransactionVersion);\n            STRWRITE(*(CScriptBase*)(&scriptSig));\n            STRWRITE(nSequence);\n        }\n    }\n\n    friend bool operator==(const CTxIn& a, const CTxIn& b)\n    {\n        return (a.prevout   == b.prevout &&\n                a.scriptSig == b.scriptSig &&\n                a.nSequence == b.nSequence);\n    }\n\n    friend bool operator!=(const CTxIn& a, const CTxIn& b)\n    {\n        return !(a == b);\n    }\n\n    std::string ToString() const;\n};\n\nenum CTxOutType : uint8_t\n{\n    //General purpose output types start from 0 counting upward\n    ScriptLegacyOutput = 0,\n\n    //Specific/fixed purpose output types start from max counting backwards\n    PoW2WitnessOutput = 31,\n    StandardKeyHashOutput = 30\n};\n\n\nclass CTxOutPoW2Witness\n{\npublic:\n    CKeyID spendingKeyID;\n    CKeyID witnessKeyID;\n    uint64_t lockFromBlock;\n    uint64_t lockUntilBlock;\n    uint64_t failCount;\n    uint64_t actionNonce;\n\n    CTxOutPoW2Witness() {clear();}\n\n    void clear()\n    {\n        spendingKeyID.SetNull();\n        witnessKeyID.SetNull();\n        lockFromBlock = 0;\n        lockUntilBlock = 0;\n        failCount = 0;\n        actionNonce = 0;\n    }\n\n    bool operator==(const CTxOutPoW2Witness& compare) const\n    {\n        return spendingKeyID == compare.spendingKeyID &&\n               witnessKeyID == compare.witnessKeyID &&\n               lockFromBlock == compare.lockFromBlock &&\n               lockUntilBlock == compare.lockUntilBlock &&\n               failCount == compare.failCount &&\n               actionNonce == compare.actionNonce;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(spendingKeyID);\n        READWRITE(witnessKeyID);\n        READWRITE(lockFromBlock);\n        READWRITE(lockUntilBlock);\n        READWRITE(VARINT(failCount));\n        READWRITE(VARINT(actionNonce));\n    }\n    \n    //fixme: (PHASE5) remove\n    //NB! Don't serialise this or use this for compares\n    //We use this only inside witness bundle calculations where we need to know the input type without looking it up again\n    CTxOutType nType;\n};\n\nclass CTxOutStandardKeyHash\n{\npublic:\n    CKeyID keyID;\n\n    CTxOutStandardKeyHash(const CKeyID  keyID_) : keyID(keyID_) {}\n    CTxOutStandardKeyHash() { clear(); }\n\n    void clear()\n    {\n        keyID.SetNull();\n    }\n\n    bool operator==(const CTxOutStandardKeyHash& compare) const\n    {\n        return keyID == compare.keyID;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(keyID);\n    }\n};\n\n/** An output of a transaction.  It contains the public key that the next input\n * must be able to sign with to claim it.\n */\nclass CTxOut\n{\npublic:\n    //fixme: (POST-PHASE5) gcc - future - In an ideal world we would just have nType be of type 'CTxOutType' - however GCC spits out unavoidable warnings when using an enum as part of a bitfield, so we use these getter/setter methods to work around it.\n    CTxOutType GetType() const\n    {\n        return (CTxOutType)output.nType;\n    }\n    std::string GetTypeAsString() const\n    {\n        switch(CTxOutType(output.nType))\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                return \"SCRIPT\";\n            case CTxOutType::PoW2WitnessOutput:\n                return \"POW2WITNESS\";\n            case CTxOutType::StandardKeyHashOutput:\n                return \"STANDARDKEYHASH\";\n        }\n        return \"\";\n    }\n    void SetType(CTxOutType nType_)\n    {\n        output.DeleteOutput();\n        output.nType = nType_;\n        output.AllocOutput();\n    }\n\n    CAmount nValue;\n\n    //Size of CTxOut in memory is very important - so we use a union here to try minimise the space taken.\n    struct output\n    {\n        uint8_t nType: 5;\n        mutable uint8_t nValueBase: 3;\n        union\n        {\n            CScript scriptPubKey;\n            CTxOutPoW2Witness witnessDetails;\n            CTxOutStandardKeyHash standardKeyHash;\n        };\n        output()\n        {\n            new(&scriptPubKey) CScript();\n            nType = 0;\n        }\n        ~output()\n        {\n        }\n\n        void DeleteOutput()\n        {\n            switch(nType)\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                {\n                    scriptPubKey.clear();\n                    scriptPubKey.~CScript(); break;\n                }\n                case CTxOutType::PoW2WitnessOutput:\n                {\n                    witnessDetails.clear();\n                    witnessDetails.~CTxOutPoW2Witness(); break;\n                }\n                case CTxOutType::StandardKeyHashOutput:\n                {\n                    standardKeyHash.clear();\n                    standardKeyHash.~CTxOutStandardKeyHash(); break;\n                }\n            }\n        }\n\n        void AllocOutput()\n        {\n            switch(nType)\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                    new(&scriptPubKey) CScript(); break;\n                case CTxOutType::PoW2WitnessOutput:\n                    new(&witnessDetails) CTxOutPoW2Witness(); break;\n                case CTxOutType::StandardKeyHashOutput:\n                    new(&standardKeyHash) CTxOutStandardKeyHash(); break;\n            }\n        }\n\n        template <typename Stream> inline void WriteToStream(Stream& s) const\n        {\n            static CSerActionSerialize ser_action;\n            switch(nType)\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                    STRWRITE(*(CScriptBase*)(&scriptPubKey)); break;\n                case CTxOutType::PoW2WitnessOutput:\n                    STRWRITE(witnessDetails); break;\n                case CTxOutType::StandardKeyHashOutput:\n                    STRWRITE(standardKeyHash); break;\n            }\n        }\n\n        template <typename Stream> inline void ReadFromStream(Stream& s)\n        {\n            static CSerActionUnserialize ser_action;\n            switch(nType)\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                    STRREAD(*(CScriptBase*)(&scriptPubKey)); break;\n                case CTxOutType::PoW2WitnessOutput:\n                    STRREAD(witnessDetails); break;\n                case CTxOutType::StandardKeyHashOutput:\n                    STRREAD(standardKeyHash); break;\n            }\n        }\n\n        std::string GetHex() const\n        {\n            std::vector<unsigned char> serData;\n            {\n                CVectorWriter serialisedWitnessHeaderInfoStream(SER_NETWORK, INIT_PROTO_VERSION, serData, 0);\n                const_cast<output*>(this)->WriteToStream(serialisedWitnessHeaderInfoStream);\n            }\n            return HexStr(serData);\n        }\n\n        uint256 GetHash() const\n        {\n            std::string sHex = GetHex();\n            return Hash(sHex.begin(), sHex.end());\n        }\n\n        bool operator==(const output& compare) const\n        {\n            if (nType != compare.nType)\n                return false;\n\n            switch(CTxOutType(nType))\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                    return scriptPubKey == compare.scriptPubKey;\n                case CTxOutType::PoW2WitnessOutput:\n                    return witnessDetails == compare.witnessDetails;\n                case CTxOutType::StandardKeyHashOutput:\n                    return standardKeyHash == compare.standardKeyHash;\n            }\n            return false;\n        }\n    } output;\n\n\n    bool IsUnspendable() const\n    {\n        if (GetType() <= CTxOutType::ScriptLegacyOutput)\n            return output.scriptPubKey.IsUnspendable();\n        return false;\n    }\n\n    virtual ~CTxOut()\n    {\n        output.DeleteOutput();\n    }\n\n    CTxOut operator=(const CTxOut& copyFrom)\n    {\n        SetType(CTxOutType(copyFrom.output.nType));\n        output.nValueBase = copyFrom.output.nValueBase;\n        nValue = copyFrom.nValue;\n        switch(CTxOutType(output.nType))\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                output.scriptPubKey = copyFrom.output.scriptPubKey; break;\n            case CTxOutType::PoW2WitnessOutput:\n                output.witnessDetails = copyFrom.output.witnessDetails; break;\n            case CTxOutType::StandardKeyHashOutput:\n                output.standardKeyHash = copyFrom.output.standardKeyHash; break;\n        }\n        return *this;\n    }\n\n    CTxOut(const CTxOut& copyFrom)\n    {\n        SetType(CTxOutType(copyFrom.output.nType));\n        nValue = copyFrom.nValue;\n        output.nValueBase = copyFrom.output.nValueBase;\n        switch(CTxOutType(output.nType))\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                output.scriptPubKey = copyFrom.output.scriptPubKey; break;\n            case CTxOutType::PoW2WitnessOutput:\n                output.witnessDetails = copyFrom.output.witnessDetails; break;\n            case CTxOutType::StandardKeyHashOutput:\n                output.standardKeyHash = copyFrom.output.standardKeyHash; break;\n        }\n    }\n\n    CTxOut(CTxOut&& copyFrom)\n    {\n        SetType(CTxOutType(copyFrom.output.nType));\n        nValue = copyFrom.nValue;\n        output.nValueBase = copyFrom.output.nValueBase;\n        switch(CTxOutType(output.nType))\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                output.scriptPubKey = copyFrom.output.scriptPubKey; break;\n            case CTxOutType::PoW2WitnessOutput:\n                output.witnessDetails = copyFrom.output.witnessDetails; break;\n            case CTxOutType::StandardKeyHashOutput:\n                output.standardKeyHash = copyFrom.output.standardKeyHash; break;\n        }\n    }\n\n    CTxOut& operator=(CTxOut&& copyFrom)\n    {\n        SetType(CTxOutType(copyFrom.output.nType));\n        nValue = copyFrom.nValue;\n        output.nValueBase = copyFrom.output.nValueBase;\n        switch(CTxOutType(output.nType))\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                output.scriptPubKey = copyFrom.output.scriptPubKey; break;\n            case CTxOutType::PoW2WitnessOutput:\n                output.witnessDetails = copyFrom.output.witnessDetails; break;\n            case CTxOutType::StandardKeyHashOutput:\n                output.standardKeyHash = copyFrom.output.standardKeyHash; break;\n        }\n        return *this;\n    }\n\n    CTxOut()\n    {\n        SetNull();\n    }\n\n    CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);\n    CTxOut(const CAmount& nValueIn, CTxOutPoW2Witness witnessDetails);\n    CTxOut(const CAmount& nValueIn, CTxOutStandardKeyHash standardKeyHash);\n\n    template <typename Stream> void WriteToStream(Stream& s, int32_t nTransactionVersion) const\n    {\n        static CSerActionSerialize ser_action;\n        if (IsOldTransactionVersion(nTransactionVersion))\n        {\n            assert(output.nType == CTxOutType::ScriptLegacyOutput);\n\n            // Old transaction format.\n            STRWRITE(nValue);\n        }\n        else\n        {\n            CAmount nValueWrite = nValue;\n\n            output.nValueBase = 0; // 8 decimal precision.\n            //fixme: (POST-PHASE5) Is there some 'trick' to calculate this faster without so much branching?\n            if (nValue % 1000000000000 == 0)    { output.nValueBase = 7; } // 4 significant digit precision\n            else if (nValue % 10000000000 == 0) { output.nValueBase = 6; } // 2 significant digit precision\n            else if (nValue % 100000000 == 0)   { output.nValueBase = 5; } // 1 significant digit precision\n            else if (nValue % 10000000 == 0)    { output.nValueBase = 4; } // 1 decimal precision\n            else if (nValue % 1000000 == 0)     { output.nValueBase = 3; } // 2 decimal precision\n            else if (nValue % 10000 == 0)       { output.nValueBase = 2; } // 4 decimal precision\n            else if (nValue % 100 == 0)         { output.nValueBase = 1; } // 6 decimal precision\n\n            // Adjust nValueWrite to the new base.\n            switch (output.nValueBase)\n            {\n                case 7: nValueWrite /= 1000000000000; break;\n                case 6: nValueWrite /= 10000000000; break;\n                case 5: nValueWrite /= 100000000; break;\n                case 4: nValueWrite /= 10000000; break;\n                case 3: nValueWrite /= 1000000; break;\n                case 2: nValueWrite /= 10000; break;\n                case 1: nValueWrite /= 100; break;\n            }\n\n            uint8_t nTypeAndValueBase = 0;\n            nTypeAndValueBase = output.nType;\n            nTypeAndValueBase <<= 3;\n            nTypeAndValueBase |= output.nValueBase;\n            STRWRITE(nTypeAndValueBase);\n            STRWRITE(VARINT(nValueWrite));\n        }\n        output.WriteToStream(s);\n    }\n\n    template <typename Stream> void ReadFromStream(Stream& s, int32_t nTransactionVersion)\n    {\n        static CSerActionUnserialize ser_action;\n        if (IsOldTransactionVersion(nTransactionVersion))\n        {\n            assert(output.nType == CTxOutType::ScriptLegacyOutput);\n            output.nValueBase = 0;\n            STRREAD(nValue);\n        }\n        else // Read in the new transaction format value, which is specified in a format that is much more compact in most circumstances.\n        {\n            uint8_t nTypeAndValueBase;\n            STRREAD(nTypeAndValueBase);\n            output.nValueBase = (nTypeAndValueBase & 0b00000111);\n            SetType(CTxOutType((nTypeAndValueBase & 0b11111000) >> 3));\n\n            STRREAD(VARINT(nValue)); // Compacted value is stored as a varint.\n            switch(output.nValueBase) // Which further needs to be multiplied by base to get the full int64 value.\n            {\n                case 0: break;                          // 8 decimal precision  (0.00000008, 87654321.12345678 etc.)\n                case 1: nValue *= 100; break;           // 6 decimal precision  (0.00000600, 87654321.12345600 etc.)\n                case 2: nValue *= 10000; break;         // 4 decimal precision  (0.00040000, 87654321.12340000 etc.)\n                case 3: nValue *= 1000000; break;       // 2 decimal precision  (0.02000000, 87654321.12000000 etc.)\n                case 4: nValue *= 10000000; break;      // 1 decimal precision  (0.10000000, 87654321.10000000 etc.)\n                case 5: nValue *= 100000000; break;     // 1 significant digit precision (1.00000000, 87654321.00000000 etc.)\n                case 6: nValue *= 10000000000; break;   // 3 significant digit precision (200.00000000, 876543200.00000000 etc.)\n                case 7: nValue *= 1000000000000; break; // 5 significant digit precision (40000.00000000, 876540000.00000000 etc.)\n            };\n        }\n        output.ReadFromStream(s);\n    }\n\n    // trigger serializers used for witness bundle serializing to use the new format\n    static const int32_t NEW_FORMAT_VERSION = 5;\n\n    template <typename Stream> void Serialize(Stream& s) const\n    {\n        WriteToStream(s, CTxOut::NEW_FORMAT_VERSION);\n    }\n\n    void SetNull()\n    {\n        SetType(ScriptLegacyOutput);\n        output.nValueBase = 0;\n        nValue = -1;\n        switch(output.nType)\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                output.scriptPubKey.clear(); break;\n            case CTxOutType::PoW2WitnessOutput:\n                output.witnessDetails.clear(); break;\n            case CTxOutType::StandardKeyHashOutput:\n                output.standardKeyHash.clear(); break;\n        }\n    }\n\n    bool IsNull() const\n    {\n        return (nValue == -1);\n    }\n\n    friend bool operator==(const CTxOut& a, const CTxOut& b)\n    {\n        return (a.nValue == b.nValue &&\n                a.output == b.output);\n    }\n\n    friend bool operator!=(const CTxOut& a, const CTxOut& b)\n    {\n        return !(a == b);\n    }\n\n    std::string ToString() const;\n};\n\nstruct CMutableTransaction;\n\n/**\n * Basic transaction serialization format:\n * - int32_t nVersion\n * - std::vector<CTxIn> vin\n * - std::vector<CTxOut> vout\n * - uint32_t nLockTime\n *\n * Extended transaction serialization format:\n * - int32_t nVersion\n * - unsigned char dummy = 0x00\n * - unsigned char flags (!= 0)\n * - std::vector<CTxIn> vin\n * - std::vector<CTxOut> vout\n * - if (flags & 1):\n *   - CTxWitness wit;\n * - uint32_t nLockTime\n */\ntemplate<typename Stream, typename TxType>\ninline void UnserializeTransactionOld(TxType& tx, Stream& s)\n{\n    s >> tx.nVersion;\n    tx.vin.clear();\n    tx.vout.clear();\n\n    /* Try to read the vin. */\n    {\n        uint64_t nSize = 0;\n        s >> COMPACTSIZE(nSize);\n        tx.vin.resize(nSize);\n        for (auto& in : tx.vin)\n        {\n            in.ReadFromStream(s, tx.nVersion);\n        }\n    }\n\n    /* We read a non-empty vin. Assume a normal vout follows. */\n    {\n        uint64_t nSize = 0;\n        s >> COMPACTSIZE(nSize);\n        tx.vout.resize(nSize);\n        for (auto& out : tx.vout)\n        {\n            out.ReadFromStream(s, tx.nVersion);\n        }\n    }\n    s >> tx.nLockTime;\n}\n\ntemplate<typename Stream, typename TxType>\ninline void SerializeTransactionOld(const TxType& tx, Stream& s)\n{\n    s << tx.nVersion;\n    s << COMPACTSIZE(tx.vin.size());\n    for (const auto& in : tx.vin)\n    {\n        in.WriteToStream(s, tx.nVersion);\n    }\n    s << COMPACTSIZE(tx.vout.size());\n    for (const auto& out : tx.vout)\n    {\n        out.WriteToStream(s, tx.nVersion);\n    }\n    s << tx.nLockTime;\n}\n\n//New transaction format:\n//Version number: CVarInt [1 byte] (but forward compat for larger sizes)\n//Flags: bitset [1 byte] (7 bytes used, 8th byte signals ExtraFlags)  {Current flags are for 1/2/3 input transactions, 1/2/3 output transactions and locktime}\n//ExtraFlags: bitset [1 byte] (but never currently present, only there for forwards compat)\n//Input count: CVarInt [0-9 byte] (only present in the event that input count flags are all unset)\n//Vector of inputs\n//Output count: CVarInt [0-9 byte] (only present in the event that output count flags are all unset)\n//Vector of outputs\n//Vector of witnesses (no size)\n//Lock time: CVarInt [0-9 byte] (only present if locktime flag is set)\n\n//>90% of transactions involve either 1/2/3 inputs or 1/2/3 outputs.\nenum TransactionFlags : uint8_t\n{\n    HasOneInput,\n    HasTwoInputs,\n    HasThreeInputs,\n    HasOneOutput,\n    HasTwoOutputs,\n    HasThreeOutputs,\n    HasLockTime,\n    HasExtraFlags\n};\n\ntemplate<typename Stream, typename TxType> inline void SerializeTransaction(const TxType& tx, Stream& s) {\n    if (IsOldTransactionVersion(tx.nVersion))\n        return SerializeTransactionOld(tx, s);\n\n    // Setup flags\n    switch(tx.vin.size())\n    {\n        case 1:\n            tx.flags.set(HasOneInput, true).set(HasTwoInputs, false).set(HasThreeInputs, false); break;\n        case 2:\n            tx.flags.set(HasOneInput, false).set(HasTwoInputs, true).set(HasThreeInputs, false); break;\n        case 3:\n            tx.flags.set(HasOneInput, false).set(HasTwoInputs, false).set(HasThreeInputs, true); break;\n        default:\n            tx.flags.set(HasOneInput, false).set(HasTwoInputs, false).set(HasThreeInputs, false);\n    }\n    switch(tx.vout.size())\n    {\n        case 1:\n            tx.flags.set(HasOneOutput, true).set(HasTwoOutputs, false).set(HasThreeOutputs, false); break;\n        case 2:\n            tx.flags.set(HasOneOutput, false).set(HasTwoOutputs, true).set(HasThreeOutputs, false); break;\n        case 3:\n            tx.flags.set(HasOneOutput, false).set(HasTwoOutputs, false).set(HasThreeOutputs, true); break;\n        default:\n            tx.flags.set(HasOneOutput, false).set(HasTwoOutputs, false).set(HasThreeOutputs, false);\n    }\n    tx.flags.set(HasLockTime, false);\n    if (tx.nLockTime > 0)\n    {\n        tx.flags.set(HasLockTime, true);\n    }\n\n    //Serialization begins.\n    //Version\n    s << VARINT(tx.nVersion);\n\n    //Flags + (opt) ExtraFlags\n    s << static_cast<uint8_t>(tx.flags.to_ulong());\n    if(tx.flags[HasExtraFlags])\n        s << static_cast<uint8_t>(tx.extraFlags.to_ulong());\n\n    //(opt) Input count + Inputs\n    if ( !(tx.flags[HasOneInput] || tx.flags[HasTwoInputs] || tx.flags[HasThreeInputs]) )\n        s << VARINT(tx.vin.size());\n    for (const auto& in : tx.vin)\n    {\n        in.WriteToStream(s, tx.nVersion);\n    }\n\n    //(opt) Output count + Outputs\n    if (!tx.flags[HasOneOutput] && !tx.flags[HasTwoOutputs] && !tx.flags[HasThreeOutputs])\n    {\n        s << VARINT(tx.vout.size());\n    }\n    for (const auto& out : tx.vout)\n    {\n        out.WriteToStream(s, tx.nVersion);\n    }\n\n    //Witness data\n    if (!(s.GetVersion() & SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES)) {\n        for (size_t i = 0; i < tx.vin.size(); i++)\n        {\n            s << VARINTVECTOR(tx.vin[i].segregatedSignatureData.stack);\n        }\n    }\n\n    // (opt) lock time\n    if (tx.flags[HasLockTime])\n    {\n        s << VARINT(tx.nLockTime);\n    }\n}\n\n\ntemplate<typename Stream, typename TxType>\ninline void UnserializeTransaction(TxType& tx, Stream& s) {\n    CSerActionUnserialize ser_action;\n\n    //Version\n    STRPEEK(tx.nVersion);\n    if (IsOldTransactionVersion(tx.nVersion))\n    {\n        UnserializeTransactionOld(tx, s);\n        return;\n    }\n    tx.nVersion = ReadVarInt<Stream, int32_t>(s);\n\n    //Flags + (opt) ExtraFlags\n    tx.flags.reset();\n    tx.extraFlags.reset();\n    unsigned char cFlags, cExtraFlags;\n    s >> cFlags;\n    tx.flags = std::bitset<8>(cFlags);\n    if (tx.flags[HasExtraFlags])\n    {\n        s >> cExtraFlags;\n        tx.extraFlags = std::bitset<8>(cExtraFlags);\n    }\n\n    //(opt) Input count + Inputs\n    tx.vin.clear();\n    if (tx.flags[HasOneInput])\n    {\n        tx.vin.resize(1);\n    }\n    else if (tx.flags[HasTwoInputs])\n    {\n        tx.vin.resize(2);\n    }\n    else if (tx.flags[HasThreeInputs])\n    {\n        tx.vin.resize(3);\n    }\n    else\n    {\n        int nSize = 0;\n        s >> VARINT(nSize);\n        tx.vin.resize(nSize);\n    }\n    for (auto & txIn : tx.vin)\n    {\n        txIn.ReadFromStream(s, tx.nVersion);\n    }\n\n    //(opt) Output count + Outputs\n    tx.vout.clear();\n    if (tx.flags[HasOneOutput])\n    {\n        tx.vout.resize(1);\n    }\n    else if (tx.flags[HasTwoOutputs])\n    {\n        tx.vout.resize(2);\n    }\n    else if (tx.flags[HasThreeOutputs])\n    {\n        tx.vout.resize(3);\n    }\n    else\n    {\n        uint64_t nSize = 0;\n        s >> VARINT(nSize);\n        tx.vout.resize(nSize);\n    }\n    for (auto & txOut : tx.vout)\n    {\n        txOut.ReadFromStream(s, tx.nVersion);\n    }\n\n    if (!(s.GetVersion() & SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES)) {\n        for (size_t i = 0; i < tx.vin.size(); i++) {\n            s >> VARINTVECTOR(tx.vin[i].segregatedSignatureData.stack);\n        }\n    }\n\n    // (opt) lock time\n    if (tx.flags[HasLockTime])\n    {\n        tx.nLockTime = ReadVarInt<Stream, uint32_t>(s);\n    }\n    else\n    {\n        tx.nLockTime = 0;\n    }\n}\n\nstruct CWitnessBundles;\ntypedef std::shared_ptr<const CWitnessBundles> CWitnessBundlesRef;\n\n//fixme: regtest; when we update all tests to segsig in future we can remove this\n#define CURRENT_TX_VERSION_POW2 (Params().IsRegtestLegacy()) ? 1 : CTransaction::SEGSIG_ACTIVATION_VERSION\n\n/** The basic transaction that is broadcasted on the network and contained in\n * blocks.  A transaction can contain multiple inputs and outputs.\n */\nclass CTransaction\n{\npublic:\n    // Default transaction version.\n    static const int32_t CURRENT_VERSION=5;\n\n    // Changing the default transaction version requires a two step process: first\n    // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date\n    // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and\n    // MAX_STANDARD_VERSION will be equal.\n    static const int32_t MAX_STANDARD_VERSION=5;\n    static const int32_t SEGSIG_ACTIVATION_VERSION=5;\n\n    // The local variables are made const to prevent unintended modification\n    // without updating the cached hash value. However, CTransaction is not\n    // actually immutable; deserialization and assignment are implemented,\n    // and bypass the constness. This is safe, as they update the entire\n    // structure, including the hash.\n    const int32_t nVersion;\n    const std::vector<CTxIn> vin;\n    const std::vector<CTxOut> vout;\n    const uint32_t nLockTime;\n    mutable std::bitset<8> flags;\n    mutable std::bitset<8> extraFlags;//Currently unused but present for forwards compat.\n\n    mutable CWitnessBundlesRef witnessBundles; // optional, memory only\n\nprivate:\n    /** Memory only. */\n    const uint256 hash;\n\n    uint256 ComputeHash() const;\n\npublic:\n    /** Construct a CTransaction that qualifies as IsNull() */\n    CTransaction(int32_t nVersion_);\n\n    /** Convert a CMutableTransaction into a CTransaction. */\n    CTransaction(const CMutableTransaction &tx);\n    CTransaction(CMutableTransaction &&tx);\n\n    template <typename Stream>\n    inline void Serialize(Stream& s) const {\n        SerializeTransaction(*this, s);\n    }\n\n    /** This deserializing constructor is provided instead of an Unserialize method.\n     *  Unserialize is not possible, since it would require overwriting const fields. */\n    template <typename Stream>\n    CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}\n\n    bool IsNull() const {\n        return vin.empty() && vout.empty();\n    }\n\n    const uint256& GetHash() const {\n        return hash;\n    }\n\n    // Compute a hash that includes both transaction and witness data\n    uint256 GetWitnessHash() const;\n\n    // Return sum of txouts.\n    CAmount GetValueOut() const;\n    // GetValueIn() is a method on CCoinsViewCache, because\n    // inputs must be known to compute value in.\n\n    /**\n     * Get the total transaction size in bytes, including witness data.\n     * \"Total Size\" defined in BIP141 and BIP144.\n     * @return Total transaction size in bytes\n     */\n    unsigned int GetTotalSize() const;\n\n    bool IsCoinBase() const\n    {\n        return (vin.size() == 1 && vin[0].GetPrevOut().IsNull()) || IsPoW2WitnessCoinBase();\n    }\n\n    //fixme: (PHASE5) Not sure if necessary or overkill, check second vin is a witness transaction, doing so will be expensive, I suspect we don't need to do it.\n    bool IsPoW2WitnessCoinBase() const\n    {\n        return (vin.size() == 2 && vin[0].GetPrevOut().IsNull());\n    }\n\n    friend bool operator==(const CTransaction& a, const CTransaction& b)\n    {\n        return a.hash == b.hash;\n    }\n\n    friend bool operator!=(const CTransaction& a, const CTransaction& b)\n    {\n        return a.hash != b.hash;\n    }\n\n    std::string ToString() const;\n\n    bool HasSegregatedSignatures() const\n    {\n        for (size_t i = 0; i < vin.size(); i++)\n        {\n            if (!vin[i].segregatedSignatureData.IsNull()) \n                return true;\n        }\n        return false;\n    }\n};\n\n/** A mutable version of CTransaction. */\nstruct CMutableTransaction\n{\n    int32_t nVersion;\n    std::vector<CTxIn> vin;\n    std::vector<CTxOut> vout;\n    uint32_t nLockTime;\n    mutable std::bitset<8> flags;\n    mutable std::bitset<8> extraFlags;//Currently unused but present for forwards compat.\n\n    CMutableTransaction(int32_t nVersion_);\n    CMutableTransaction(const CTransaction& tx);\n\n    template <typename Stream>\n    inline void Serialize(Stream& s) const {\n        SerializeTransaction(*this, s);\n    }\n\n\n    template <typename Stream>\n    inline void Unserialize(Stream& s) {\n        UnserializeTransaction(*this, s);\n    }\n\n    template <typename Stream>\n    CMutableTransaction(deserialize_type, Stream& s) {\n        Unserialize(s);\n    }\n\n    /** Compute the hash of this CMutableTransaction. This is computed on the\n     * fly, as opposed to GetHash() in CTransaction, which uses a cached result.\n     */\n    uint256 GetHash() const;\n\n    friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)\n    {\n        return a.GetHash() == b.GetHash();\n    }\n\n    //fixme: (PHASE5) - We can possibly improve this test by testing transaction version instead.\n    bool HasSegregatedSignatures() const\n    {\n        for (size_t i = 0; i < vin.size(); i++)\n        {\n            if (!vin[i].segregatedSignatureData.IsNull())\n                return true;\n        }\n        return false;\n    }\n};\n\ntypedef std::shared_ptr<const CTransaction> CTransactionRef;\nstatic inline CTransactionRef MakeTransactionRef(int32_t nVersion_) { return std::make_shared<const CTransaction>(nVersion_); }\ntemplate <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }\n\nint64_t GetTransactionWeight(const CTransaction &tx);\n\n#endif\n"
  },
  {
    "path": "src/protocol.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"protocol.h\"\n\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#ifndef WIN32\n# include <arpa/inet.h>\n#endif\n\nnamespace NetMsgType {\nconst char *VERSION=\"version\";\nconst char *VERACK=\"verack\";\nconst char *ADDR=\"addr\";\nconst char *INV=\"inv\";\nconst char *GETDATA=\"getdata\";\nconst char *MERKLEBLOCK=\"merkleblock\";\nconst char *GETBLOCKS=\"getblocks\";\nconst char *GETHEADERS=\"getheaders\";\nconst char *GETRHEADERS=\"getrheaders\";\nconst char *TX=\"tx\";\nconst char *HEADERS=\"headers\";\nconst char *RHEADERS=\"rheaders\";\nconst char *BLOCK=\"block\";\nconst char *GETADDR=\"getaddr\";\nconst char *MEMPOOL=\"mempool\";\nconst char *PING=\"ping\";\nconst char *PONG=\"pong\";\nconst char *ALERT=\"alert\";\nconst char *NOTFOUND=\"notfound\";\nconst char *FILTERLOAD=\"filterload\";\nconst char *FILTERADD=\"filteradd\";\nconst char *FILTERCLEAR=\"filterclear\";\nconst char *REJECT=\"reject\";\nconst char *SENDHEADERS=\"sendheaders\";\nconst char *FEEFILTER=\"feefilter\";\nconst char *SENDCMPCT=\"sendcmpct\";\nconst char *CMPCTBLOCK=\"cmpctblock\";\nconst char *GETBLOCKTXN=\"getblocktxn\";\nconst char *BLOCKTXN=\"blocktxn\";\n};\n\n/** All known message types. Keep this in the same order as the list of\n * messages above and in protocol.h.\n */\nconst static std::string allNetMessageTypes[] = {\n    NetMsgType::VERSION,\n    NetMsgType::VERACK,\n    NetMsgType::ADDR,\n    NetMsgType::INV,\n    NetMsgType::GETDATA,\n    NetMsgType::MERKLEBLOCK,\n    NetMsgType::GETBLOCKS,\n    NetMsgType::GETHEADERS,\n    NetMsgType::GETRHEADERS,\n    NetMsgType::TX,\n    NetMsgType::HEADERS,\n    NetMsgType::RHEADERS,\n    NetMsgType::BLOCK,\n    NetMsgType::GETADDR,\n    NetMsgType::MEMPOOL,\n    NetMsgType::PING,\n    NetMsgType::PONG,\n    NetMsgType::ALERT,\n    NetMsgType::NOTFOUND,\n    NetMsgType::FILTERLOAD,\n    NetMsgType::FILTERADD,\n    NetMsgType::FILTERCLEAR,\n    NetMsgType::REJECT,\n    NetMsgType::SENDHEADERS,\n    NetMsgType::FEEFILTER,\n    NetMsgType::SENDCMPCT,\n    NetMsgType::CMPCTBLOCK,\n    NetMsgType::GETBLOCKTXN,\n    NetMsgType::BLOCKTXN,\n};\nconst static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));\n\nCMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)\n{\n    memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);\n    memset(pchCommand, 0, sizeof(pchCommand));\n    nMessageSize = -1;\n    memset(pchChecksum, 0, CHECKSUM_SIZE);\n}\n\nCMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn)\n{\n    memcpy(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE);\n    memset(pchCommand, 0, sizeof(pchCommand));\n    strncpy(pchCommand, pszCommand, COMMAND_SIZE);\n    nMessageSize = nMessageSizeIn;\n    memset(pchChecksum, 0, CHECKSUM_SIZE);\n}\n\nstd::string CMessageHeader::GetCommand() const\n{\n    return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE));\n}\n\nbool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const\n{\n    // Check start string\n    if (memcmp(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE) != 0)\n        return false;\n\n    // Check the command string for errors\n    for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)\n    {\n        if (*p1 == 0)\n        {\n            // Must be all zeros after the first zero\n            for (; p1 < pchCommand + COMMAND_SIZE; p1++)\n                if (*p1 != 0)\n                    return false;\n        }\n        else if (*p1 < ' ' || *p1 > 0x7E)\n            return false;\n    }\n\n    // Message size\n    if (nMessageSize > MAX_SIZE)\n    {\n        LogPrintf(\"CMessageHeader::IsValid(): (%s, %u bytes) nMessageSize > MAX_SIZE\\n\", GetCommand(), nMessageSize);\n        return false;\n    }\n\n    return true;\n}\n\n\n\nCAddress::CAddress() : CService()\n{\n    Init();\n}\n\nCAddress::CAddress(CService ipIn, ServiceFlags nServicesIn) : CService(ipIn)\n{\n    Init();\n    nServices = nServicesIn;\n}\n\nvoid CAddress::Init()\n{\n    nServices = NODE_NONE;\n    nTime = 100000000;\n}\n\nCInv::CInv()\n{\n    type = 0;\n    hash.SetNull();\n}\n\nCInv::CInv(int typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {}\n\nbool operator<(const CInv& a, const CInv& b)\n{\n    return (a.type < b.type || (a.type == b.type && a.hash < b.hash));\n}\n\nstd::string CInv::GetCommand() const\n{\n    std::string cmd;\n    if (type & MSG_WITNESS_FLAG)\n        cmd.append(\"witness-\");\n    int masked = type & MSG_TYPE_MASK;\n    switch (masked)\n    {\n    case MSG_TX:             return cmd.append(NetMsgType::TX);\n    case MSG_BLOCK:          return cmd.append(NetMsgType::BLOCK);\n    case MSG_FILTERED_BLOCK: return cmd.append(NetMsgType::MERKLEBLOCK);\n    case MSG_CMPCT_BLOCK:    return cmd.append(NetMsgType::CMPCTBLOCK);\n    default:\n        throw std::out_of_range(strprintf(\"CInv::GetCommand(): type=%d unknown type\", type));\n    }\n}\n\nstd::string CInv::ToString() const\n{\n    try {\n        return strprintf(\"%s %s\", GetCommand(), hash.ToString());\n    } catch(const std::out_of_range &) {\n        return strprintf(\"0x%08x %s\", type, hash.ToString());\n    }\n}\n\nconst std::vector<std::string> &getAllNetMessageTypes()\n{\n    return allNetMessageTypesVec;\n}\n"
  },
  {
    "path": "src/protocol.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef __cplusplus\n#error This header can only be compiled as C++.\n#endif\n\n#ifndef CORE_PROTOCOL_H\n#define CORE_PROTOCOL_H\n\n#include \"netaddress.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n#include \"version.h\"\n\n#include <stdint.h>\n#include <string>\n\n/** Message header.\n * (4) message start.\n * (12) command.\n * (4) size.\n * (4) checksum.\n */\nclass CMessageHeader\n{\npublic:\n    enum {\n        MESSAGE_START_SIZE = 4,\n        COMMAND_SIZE = 12,\n        MESSAGE_SIZE_SIZE = 4,\n        CHECKSUM_SIZE = 4,\n\n        MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,\n        CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,\n        HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE\n    };\n    typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];\n\n    CMessageHeader(const MessageStartChars& pchMessageStartIn);\n    CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);\n\n    std::string GetCommand() const;\n    bool IsValid(const MessageStartChars& messageStart) const;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(FLATDATA(pchMessageStart));\n        READWRITE(FLATDATA(pchCommand));\n        READWRITE(nMessageSize);\n        READWRITE(FLATDATA(pchChecksum));\n    }\n\n    char pchMessageStart[MESSAGE_START_SIZE];\n    char pchCommand[COMMAND_SIZE];\n    uint32_t nMessageSize;\n    uint8_t pchChecksum[CHECKSUM_SIZE];\n};\n\n/**\n * p2p protocol message types. When adding new message types, don't forget\n * to update allNetMessageTypes in protocol.cpp.\n */\nnamespace NetMsgType {\n\n/**\n * The version message provides information about the transmitting node to the\n * receiving node at the beginning of a connection.\n * @see https://Munt.org/en/developer-reference#version\n */\nextern const char *VERSION;\n/**\n * The verack message acknowledges a previously-received version message,\n * informing the connecting node that it can begin to send other messages.\n * @see https://Munt.org/en/developer-reference#verack\n */\nextern const char *VERACK;\n/**\n * The addr (IP address) message relays connection information for peers on the\n * network.\n * @see https://Munt.org/en/developer-reference#addr\n */\nextern const char *ADDR;\n/**\n * The inv message (inventory message) transmits one or more inventories of\n * objects known to the transmitting peer.\n * @see https://Munt.org/en/developer-reference#inv\n */\nextern const char *INV;\n/**\n * The getdata message requests one or more data objects from another node.\n * @see https://Munt.org/en/developer-reference#getdata\n */\nextern const char *GETDATA;\n/**\n * The merkleblock message is a reply to a getdata message which requested a\n * block using the inventory type MSG_MERKLEBLOCK.\n * @since protocol version 70001 as described by BIP37.\n * @see https://Munt.org/en/developer-reference#merkleblock\n */\nextern const char *MERKLEBLOCK;\n/**\n * The getblocks message requests an inv message that provides block header\n * hashes starting from a particular point in the block chain.\n * @see https://Munt.org/en/developer-reference#getblocks\n */\nextern const char *GETBLOCKS;\n/**\n * The getheaders message requests a headers message that provides block\n * headers starting from a particular point in the block chain.\n * @since protocol version 31800.\n * @see https://Munt.org/en/developer-reference#getheaders\n */\nextern const char *GETHEADERS;\n/**\n * The getrheaders message requests a rheaders message that provides block\n * headers in reversed order starting from a particular point in the block chain.\n * @since protocol version 70016.\n * @see https://Munt.org/en/developer-reference#getrheaders\n */\nextern const char *GETRHEADERS;\n/**\n * The tx message transmits a single transaction.\n * @see https://Munt.org/en/developer-reference#tx\n */\nextern const char *TX;\n/**\n * The headers message sends one or more block headers to a node which\n * previously requested certain headers with a getheaders message.\n * @since protocol version 31800.\n * @see https://Munt.org/en/developer-reference#headers\n */\nextern const char *HEADERS;\n/**\n * The rheaders message sends one or more block headers in reverse order to a node which\n * previously requested certain headers with a getrheaders message.\n * @since protocol version 70016.\n * @see https://Munt.org/en/developer-reference#headers\n */\nextern const char *RHEADERS;\n/**\n * The block message transmits a single serialized block.\n * @see https://Munt.org/en/developer-reference#block\n */\nextern const char *BLOCK;\n/**\n * The getaddr message requests an addr message from the receiving node,\n * preferably one with lots of IP addresses of other receiving nodes.\n * @see https://Munt.org/en/developer-reference#getaddr\n */\nextern const char *GETADDR;\n/**\n * The mempool message requests the TXIDs of transactions that the receiving\n * node has verified as valid but which have not yet appeared in a block.\n * @since protocol version 60002.\n * @see https://Munt.org/en/developer-reference#mempool\n */\nextern const char *MEMPOOL;\n/**\n * The ping message is sent periodically to help confirm that the receiving\n * peer is still connected.\n * @see https://Munt.org/en/developer-reference#ping\n */\nextern const char *PING;\n/**\n * The pong message replies to a ping message, proving to the pinging node that\n * the ponging node is still alive.\n * @since protocol version 60001 as described by BIP31.\n * @see https://Munt.org/en/developer-reference#pong\n */\nextern const char *PONG;\n /**\n * The alert message warns nodes of problems that may affect them or the rest\n * of the network.\n * @since protocol version 311.\n * @see https://Munt.org/en/developer-reference#alert\n */\nextern const char *ALERT;\n\n/**\n * The notfound message is a reply to a getdata message which requested an\n * object the receiving node does not have available for relay.\n * @ince protocol version 70001.\n * @see https://Munt.org/en/developer-reference#notfound\n */\nextern const char *NOTFOUND;\n/**\n * The filterload message tells the receiving peer to filter all relayed\n * transactions and requested merkle blocks through the provided filter.\n * @since protocol version 70001 as described by BIP37.\n *   Only available with service bit NODE_BLOOM since protocol version\n *   70011 as described by BIP111.\n * @see https://Munt.org/en/developer-reference#filterload\n */\nextern const char *FILTERLOAD;\n/**\n * The filteradd message tells the receiving peer to add a single element to a\n * previously-set bloom filter, such as a new public key.\n * @since protocol version 70001 as described by BIP37.\n *   Only available with service bit NODE_BLOOM since protocol version\n *   70011 as described by BIP111.\n * @see https://Munt.org/en/developer-reference#filteradd\n */\nextern const char *FILTERADD;\n/**\n * The filterclear message tells the receiving peer to remove a previously-set\n * bloom filter.\n * @since protocol version 70001 as described by BIP37.\n *   Only available with service bit NODE_BLOOM since protocol version\n *   70011 as described by BIP111.\n * @see https://Munt.org/en/developer-reference#filterclear\n */\nextern const char *FILTERCLEAR;\n/**\n * The reject message informs the receiving node that one of its previous\n * messages has been rejected.\n * @since protocol version 70002 as described by BIP61.\n * @see https://Munt.org/en/developer-reference#reject\n */\nextern const char *REJECT;\n/**\n * Indicates that a node prefers to receive new block announcements via a\n * \"headers\" message rather than an \"inv\".\n * @since protocol version 70012 as described by BIP130.\n * @see https://Munt.org/en/developer-reference#sendheaders\n */\nextern const char *SENDHEADERS;\n/**\n * The feefilter message tells the receiving peer not to inv us any txs\n * which do not meet the specified min fee rate.\n * @since protocol version 70013 as described by BIP133\n */\nextern const char *FEEFILTER;\n/**\n * Contains a 1-byte bool and 8-byte LE version number.\n * Indicates that a node is willing to provide blocks via \"cmpctblock\" messages.\n * May indicate that a node prefers to receive new block announcements via a\n * \"cmpctblock\" message rather than an \"inv\", depending on message contents.\n * @since protocol version 70014 as described by BIP 152\n */\nextern const char *SENDCMPCT;\n/**\n * Contains a CBlockHeaderAndShortTxIDs object - providing a header and\n * list of \"short txids\".\n * @since protocol version 70014 as described by BIP 152\n */\nextern const char *CMPCTBLOCK;\n/**\n * Contains a BlockTransactionsRequest\n * Peer should respond with \"blocktxn\" message.\n * @since protocol version 70014 as described by BIP 152\n */\nextern const char *GETBLOCKTXN;\n/**\n * Contains a BlockTransactions.\n * Sent in response to a \"getblocktxn\" message.\n * @since protocol version 70014 as described by BIP 152\n */\nextern const char *BLOCKTXN;\n};\n\n/* Get a vector of all valid message types (see above) */\nconst std::vector<std::string> &getAllNetMessageTypes();\n\n/** nServices flags */\nenum ServiceFlags : uint64_t {\n    // Nothing\n    NODE_NONE = 0,\n    // NODE_NETWORK means that the node is capable of serving the block chain. It is currently\n    // set by all core nodes, and is unset by SPV clients or other peers that just want\n    // network services but don't provide them.\n    NODE_NETWORK = (1 << 0),\n    // NODE_GETUTXO means the node is capable of responding to the getutxo protocol request.\n    // Core does not support this but external clients can.\n    // See BIP 64 for details on how this is implemented.\n    NODE_GETUTXO = (1 << 1),\n    // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.\n    // Core nodes used to support this by default, without advertising this bit,\n    // but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)\n    NODE_BLOOM = (1 << 2),\n    // NODE_SEGSIG indicates that a node can be asked for blocks and transactions including witness data.\n    NODE_SEGSIG = (1 << 3),\n    // NODE_XTHIN means the node supports Xtreme Thinblocks\n    // If this is turned off then the node will not service nor make xthin requests\n    NODE_XTHIN = (1 << 4),\n\n    // Bits 24-31 are reserved for temporary experiments. Just pick a bit that\n    // isn't getting used, or one not being used much, and notify the\n    // development mailing list. Remember that service bits are just\n    // unauthenticated advertisements, so your code must be robust against\n    // collisions and other cases where nodes may be advertising a service they\n    // do not actually support. Other service bits should be allocated via the\n    // BIP process.\n};\n\n/** A CService with information about it as peer */\nclass CAddress : public CService\n{\npublic:\n    CAddress();\n    explicit CAddress(CService ipIn, ServiceFlags nServicesIn);\n\n    void Init();\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        if (ser_action.ForRead())\n            Init();\n        int nVersion = s.GetVersion();\n        if (s.GetType() & SER_DISK)\n            READWRITE(nVersion);\n        if ((s.GetType() & SER_DISK) ||\n            (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH)))\n            READWRITE(nTime);\n        uint64_t nServicesInt = nServices;\n        READWRITE(nServicesInt);\n        nServices = (ServiceFlags)nServicesInt;\n        READWRITE(*(CService*)this);\n    }\n\n    // TODO: make private (improves encapsulation)\npublic:\n    ServiceFlags nServices;\n\n    // disk and network only\n    unsigned int nTime;\n};\n\n/** getdata message type flags */\nconst uint32_t MSG_WITNESS_FLAG = 1 << 30;\nconst uint32_t MSG_TYPE_MASK    = 0xffffffff >> 2;\n\n/** getdata / inv message types.\n * These numbers are defined by the protocol. When adding a new value, be sure\n * to mention it in the respective BIP.\n */\nenum GetDataMsg\n{\n    UNDEFINED = 0,\n    MSG_TX = 1,\n    MSG_BLOCK = 2,\n    // The following can only occur in getdata. Invs always use TX or BLOCK.\n    MSG_FILTERED_BLOCK = 3,  //!< Defined in BIP37\n    MSG_CMPCT_BLOCK = 4,     //!< Defined in BIP152\n    MSG_WITNESS_BLOCK = MSG_BLOCK | MSG_WITNESS_FLAG, //!< Defined in BIP144\n    MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG,       //!< Defined in BIP144\n    MSG_FILTERED_WITNESS_BLOCK = MSG_FILTERED_BLOCK | MSG_WITNESS_FLAG,\n};\n\n/** inv message data */\nclass CInv\n{\npublic:\n    CInv();\n    CInv(int typeIn, const uint256& hashIn);\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        READWRITE(type);\n        READWRITE(hash);\n    }\n\n    friend bool operator<(const CInv& a, const CInv& b);\n\n    std::string GetCommand() const;\n    std::string ToString() const;\n\n    // TODO: make private (improves encapsulation)\npublic:\n    int type;\n    uint256 hash;\n};\n\n#endif\n"
  },
  {
    "path": "src/pubkey.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"pubkey.h\"\n\n#include <secp256k1.h>\n#include <secp256k1_recovery.h>\n\nnamespace\n{\n/* Global secp256k1_context object used for verification. */\nsecp256k1_context* secp256k1_context_verify = NULL;\n}\n\n/** This function is taken from the libsecp256k1 distribution and implements\n *  DER parsing for ECDSA signatures, while supporting an arbitrary subset of\n *  format violations.\n *\n *  Supported violations include negative integers, excessive padding, garbage\n *  at the end, and overly long length descriptors. This is safe to use in\n *  Munt because since the activation of BIP66, signatures are verified to be\n *  strict DER before being passed to this module, and we know it supports all\n *  violations present in the blockchain before that point.\n */\nstatic int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {\n    size_t rpos, rlen, spos, slen;\n    size_t pos = 0;\n    size_t lenbyte;\n    unsigned char tmpsig[64] = {0};\n    int overflow = 0;\n\n    /* Hack to initialize sig with a correctly-parsed but invalid signature. */\n    secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n\n    /* Sequence tag byte */\n    if (pos == inputlen || input[pos] != 0x30) {\n        return 0;\n    }\n    pos++;\n\n    /* Sequence length bytes */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        pos += lenbyte;\n    }\n\n    /* Integer tag byte for R */\n    if (pos == inputlen || input[pos] != 0x02) {\n        return 0;\n    }\n    pos++;\n\n    /* Integer length for R */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        while (lenbyte > 0 && input[pos] == 0) {\n            pos++;\n            lenbyte--;\n        }\n        if (lenbyte >= sizeof(size_t)) {\n            return 0;\n        }\n        rlen = 0;\n        while (lenbyte > 0) {\n            rlen = (rlen << 8) + input[pos];\n            pos++;\n            lenbyte--;\n        }\n    } else {\n        rlen = lenbyte;\n    }\n    if (rlen > inputlen - pos) {\n        return 0;\n    }\n    rpos = pos;\n    pos += rlen;\n\n    /* Integer tag byte for S */\n    if (pos == inputlen || input[pos] != 0x02) {\n        return 0;\n    }\n    pos++;\n\n    /* Integer length for S */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        while (lenbyte > 0 && input[pos] == 0) {\n            pos++;\n            lenbyte--;\n        }\n        if (lenbyte >= sizeof(size_t)) {\n            return 0;\n        }\n        slen = 0;\n        while (lenbyte > 0) {\n            slen = (slen << 8) + input[pos];\n            pos++;\n            lenbyte--;\n        }\n    } else {\n        slen = lenbyte;\n    }\n    if (slen > inputlen - pos) {\n        return 0;\n    }\n    spos = pos;\n    pos += slen;\n\n    /* Ignore leading zeroes in R */\n    while (rlen > 0 && input[rpos] == 0) {\n        rlen--;\n        rpos++;\n    }\n    /* Copy R value */\n    if (rlen > 32) {\n        overflow = 1;\n    } else {\n        memcpy(tmpsig + 32 - rlen, input + rpos, rlen);\n    }\n\n    /* Ignore leading zeroes in S */\n    while (slen > 0 && input[spos] == 0) {\n        slen--;\n        spos++;\n    }\n    /* Copy S value */\n    if (slen > 32) {\n        overflow = 1;\n    } else {\n        memcpy(tmpsig + 64 - slen, input + spos, slen);\n    }\n\n    if (!overflow) {\n        overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n    }\n    if (overflow) {\n        /* Overwrite the result again with a correctly-parsed but invalid\n           signature if parsing failed. */\n        memset(tmpsig, 0, 64);\n        secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n    }\n    return 1;\n}\n\nbool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {\n    if (!IsValid())\n        return false;\n    secp256k1_pubkey pubkey;\n    secp256k1_ecdsa_signature sig;\n    if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {\n        return false;\n    }\n    if (vchSig.size() == 0) {\n        return false;\n    }\n    if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {\n        return false;\n    }\n    /* libsecp256k1's ECDSA verification requires lower-S signatures, which have\n     * not historically been enforced in Munt, so normalize them first. */\n    secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);\n    return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);\n}\n\nbool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {\n    if (vchSig.size() != 65)\n        return false;\n    int recid = (vchSig[0] - 27) & 3;\n    bool fComp = ((vchSig[0] - 27) & 4) != 0;\n    secp256k1_pubkey pubkey;\n    secp256k1_ecdsa_recoverable_signature sig;\n    if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {\n        return false;\n    }\n    if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {\n        return false;\n    }\n    unsigned char pub[65];\n    size_t publen = 65;\n    secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);\n    Set(pub, pub + publen);\n    return true;\n}\n\nbool CPubKey::IsFullyValid() const {\n    if (!IsValid())\n        return false;\n    secp256k1_pubkey pubkey;\n    return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size());\n}\n\nbool CPubKey::Decompress() {\n    if (!IsValid())\n        return false;\n    secp256k1_pubkey pubkey;\n    if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {\n        return false;\n    }\n    unsigned char pub[65];\n    size_t publen = 65;\n    secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);\n    Set(pub, pub + publen);\n    return true;\n}\n\nbool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {\n    assert(IsValid());\n    assert((nChild >> 31) == 0);\n    assert(begin() + 33 == end());\n    unsigned char out[64];\n    BIP32Hash(cc, nChild, *begin(), begin()+1, out);\n    memcpy(ccChild.begin(), out+32, 32);\n    secp256k1_pubkey pubkey;\n    if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {\n        return false;\n    }\n    if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {\n        return false;\n    }\n    unsigned char pub[33];\n    size_t publen = 33;\n    secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);\n    pubkeyChild.Set(pub, pub + publen);\n    return true;\n}\n\nvoid CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {\n    code[0] = nDepth;\n    memcpy(code+1, vchFingerprint, 4);\n    code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;\n    code[7] = (nChild >>  8) & 0xFF; code[8] = (nChild >>  0) & 0xFF;\n    memcpy(code+9, chaincode.begin(), 32);\n    assert(pubkey.size() == 33);\n    memcpy(code+41, pubkey.begin(), 33);\n}\n\nvoid CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {\n    nDepth = code[0];\n    memcpy(vchFingerprint, code+1, 4);\n    nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];\n    memcpy(chaincode.begin(), code+9, 32);\n    pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE);\n}\n\nbool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {\n    out.nDepth = nDepth + 1;\n    CKeyID id = pubkey.GetID();\n    memcpy(&out.vchFingerprint[0], &id, 4);\n    out.nChild = _nChild;\n    return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);\n}\n\n/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {\n    secp256k1_ecdsa_signature sig;\n    if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {\n        return false;\n    }\n    return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));\n}\n\n/* static */ int ECCVerifyHandle::refcount = 0;\n\nECCVerifyHandle::ECCVerifyHandle()\n{\n    if (refcount == 0) {\n        assert(secp256k1_context_verify == NULL);\n        secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);\n        assert(secp256k1_context_verify != NULL);\n    }\n    refcount++;\n}\n\nECCVerifyHandle::~ECCVerifyHandle()\n{\n    refcount--;\n    if (refcount == 0) {\n        assert(secp256k1_context_verify != NULL);\n        secp256k1_context_destroy(secp256k1_context_verify);\n        secp256k1_context_verify = NULL;\n    }\n}\n"
  },
  {
    "path": "src/pubkey.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n#ifndef CORE_PUBKEY_H\n#define CORE_PUBKEY_H\n\n#include \"hash.h\"\n#include \"serialize.h\"\n#include \"uint256.h\"\n\n#include <stdexcept>\n#include <vector>\n\n/**\n * secp256k1:\n * const unsigned int PRIVATE_KEY_SIZE = 279;\n * const unsigned int PUBLIC_KEY_SIZE  = 65;\n * const unsigned int SIGNATURE_SIZE   = 72;\n *\n * see www.keylength.com\n * script supports up to 75 for single byte push\n */\n\nconst unsigned int BIP32_EXTKEY_SIZE = 74;\n\n/** A reference to a CKey: the Hash160 of its serialized public key */\nclass CKeyID : public uint160\n{\npublic:\n    CKeyID() : uint160() {}\n    CKeyID(const uint160& in) : uint160(in) {}\n};\n\ntypedef uint256 ChainCode;\n\n/** An encapsulated public key. */\nclass CPubKey\n{\nprivate:\n\n    /**\n     * Just store the serialized data.\n     * Its length can very cheaply be computed from the first byte.\n     */\n    unsigned char vch[65];\n\n    //! Compute the length of a pubkey with a given first byte.\n    unsigned int static GetLen(unsigned char chHeader)\n    {\n        if (chHeader == 2 || chHeader == 3)\n            return 33;\n        if (chHeader == 4 || chHeader == 6 || chHeader == 7)\n            return 65;\n        return 0;\n    }\n\n    //! Set this key data to be invalid\n    void Invalidate()\n    {\n        vch[0] = 0xFF;\n    }\n\npublic:\n    //! Construct an invalid public key.\n    CPubKey()\n    {\n        Invalidate();\n    }\n\n    //! Initialize a public key using begin/end iterators to byte data.\n    template <typename T>\n    void Set(const T pbegin, const T pend)\n    {\n        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);\n        if (len && len == (pend - pbegin))\n            memcpy(vch, (unsigned char*)&pbegin[0], len);\n        else\n            Invalidate();\n    }\n\n    //! Construct a public key using begin/end iterators to byte data.\n    template <typename T>\n    CPubKey(const T pbegin, const T pend)\n    {\n        Set(pbegin, pend);\n    }\n\n    //! Construct a public key from a byte vector.\n    CPubKey(const std::vector<unsigned char>& _vch)\n    {\n        Set(_vch.begin(), _vch.end());\n    }\n\n    //! Simple read-only vector-like interface to the pubkey data.\n    unsigned int size() const { return GetLen(vch[0]); }\n    const unsigned char* begin() const { return vch; }\n    const unsigned char* end() const { return vch + size(); }\n    const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }\n\n    //! Comparator implementation.\n    friend bool operator==(const CPubKey& a, const CPubKey& b)\n    {\n        return a.vch[0] == b.vch[0] &&\n               memcmp(a.vch, b.vch, a.size()) == 0;\n    }\n    friend bool operator!=(const CPubKey& a, const CPubKey& b)\n    {\n        return !(a == b);\n    }\n    friend bool operator<(const CPubKey& a, const CPubKey& b)\n    {\n        return a.vch[0] < b.vch[0] ||\n               (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);\n    }\n\n    //! Implement serialization, as if this was a byte vector.\n    template <typename Stream>\n    void Serialize(Stream& s) const\n    {\n        unsigned int len = size();\n        ::WriteCompactSize(s, len);\n        s.write((char*)vch, len);\n    }\n    template <typename Stream>\n    void Unserialize(Stream& s)\n    {\n        unsigned int len = ::ReadCompactSize(s);\n        if (len <= 65) {\n            s.read((char*)vch, len);\n        } else {\n            // invalid pubkey, skip available data\n            char dummy;\n            while (len--)\n                s.read(&dummy, 1);\n            Invalidate();\n        }\n    }\n\n    //! Get the KeyID of this public key (hash of its serialization)\n    CKeyID GetID() const\n    {\n        return CKeyID(Hash160(vch, vch + size()));\n    }\n\n    //! Get the 256-bit hash of this public key.\n    uint256 GetHash() const\n    {\n        return Hash(vch, vch + size());\n    }\n\n    /*\n     * Check syntactic correctness.\n     *\n     * Note that this is consensus critical as CheckSig() calls it!\n     */\n    bool IsValid() const\n    {\n        return size() > 0;\n    }\n\n    //! fully validate whether this is a valid public key (more expensive than IsValid())\n    bool IsFullyValid() const;\n\n    //! Check whether this is a compressed public key.\n    bool IsCompressed() const\n    {\n        return size() == 33;\n    }\n\n    /**\n     * Verify a DER signature (~72 bytes).\n     * If this public key is not fully valid, the return value will be false.\n     */\n    bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;\n\n    /**\n     * Check whether a signature is normalized (lower-S).\n     */\n    static bool CheckLowS(const std::vector<unsigned char>& vchSig);\n\n    //! Recover a public key from a compact signature.\n    bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);\n\n    //! Turn this public key into an uncompressed public key.\n    bool Decompress();\n\n    //! Derive BIP32 child pubkey.\n    bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;\n};\n\nstruct CExtPubKey {\n    unsigned char nDepth;\n    unsigned char vchFingerprint[4];\n    unsigned int nChild;\n    ChainCode chaincode;\n    CPubKey pubkey;\n\n    const CPubKey& GetKey() const { return pubkey; };\n    CPubKey& GetMutableKey() { return pubkey; };\n\n    friend bool operator==(const CExtPubKey &a, const CExtPubKey &b)\n    {\n        return a.nDepth == b.nDepth &&\n            memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 &&\n            a.nChild == b.nChild &&\n            a.chaincode == b.chaincode &&\n            a.pubkey == b.pubkey;\n    }\n\n    void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;\n    void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);\n    bool Derive(CExtPubKey& out, unsigned int nChild) const;\n\n    void Serialize(CSizeComputer& s) const\n    {\n        // Optimized implementation for ::GetSerializeSize that avoids copying.\n        s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int)\n    }\n    template <typename Stream>\n    void Serialize(Stream& s) const\n    {\n        unsigned int len = BIP32_EXTKEY_SIZE;\n        ::WriteCompactSize(s, len);\n        unsigned char code[BIP32_EXTKEY_SIZE];\n        Encode(code);\n        s.write((const char *)&code[0], len);\n    }\n    template <typename Stream>\n    void Unserialize(Stream& s)\n    {\n        unsigned int len = ::ReadCompactSize(s);\n        unsigned char code[BIP32_EXTKEY_SIZE];\n        if (len != BIP32_EXTKEY_SIZE)\n            throw std::runtime_error(\"Invalid extended key size\\n\");\n        s.read((char *)&code[0], len);\n        Decode(code);\n    }\n};\n\n/** Users of this module must hold an ECCVerifyHandle. The constructor and\n *  destructor of these are not allowed to run in parallel, though. */\nclass ECCVerifyHandle\n{\n    static int refcount;\n\npublic:\n    ECCVerifyHandle();\n    ~ECCVerifyHandle();\n};\n\n#endif\n"
  },
  {
    "path": "src/random.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"random.h\"\n\n#include \"crypto/sha512.h\"\n#include \"support/cleanse.h\"\n#ifdef WIN32\n#include \"compat.h\" // for Windows API\n#include <wincrypt.h>\n#endif\n#include \"util.h\"             // for LogPrint()\n#include \"util/strencodings.h\" // for GetTime()\n\n#include <stdlib.h>\n#include <limits>\n#include <chrono>\n#include <thread>\n\n#ifndef WIN32\n#include <sys/time.h>\n#endif\n\n#ifdef HAVE_SYS_GETRANDOM\n#include <sys/syscall.h>\n#include <linux/random.h>\n#endif\n#ifdef HAVE_GETENTROPY\n#include <unistd.h>\n#endif\n#ifdef HAVE_SYSCTL_ARND\n#include <sys/sysctl.h>\n#endif\n\n#include <mutex>\n\n#include <openssl/err.h>\n#include <openssl/rand.h>\n\nstatic void RandFailure()\n{\n    LogPrintf(\"Failed to read randomness, aborting\\n\");\n    abort();\n}\n\nstatic inline int64_t GetPerformanceCounter()\n{\n    // Read the hardware time stamp counter when available.\n    // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.\n#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))\n    return __rdtsc();\n#elif !defined(_MSC_VER) && defined(__i386__)\n    uint64_t r = 0;\n    __asm__ volatile (\"rdtsc\" : \"=A\"(r)); // Constrain the r variable to the eax:edx pair.\n    return r;\n#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))\n    uint64_t r1 = 0, r2 = 0;\n    __asm__ volatile (\"rdtsc\" : \"=a\"(r1), \"=d\"(r2)); // Constrain r1 to rax and r2 to rdx.\n    return (r2 << 32) | r1;\n#else\n    // Fall back to using C++11 clock (usually microsecond or nanosecond precision)\n    return std::chrono::high_resolution_clock::now().time_since_epoch().count();\n#endif\n}\n\nvoid RandAddSeed()\n{\n    // Seed with CPU performance counter\n    int64_t nCounter = GetPerformanceCounter();\n    RAND_add(&nCounter, sizeof(nCounter), 1.5);\n    memory_cleanse((void*)&nCounter, sizeof(nCounter));\n}\n\nstatic void RandAddSeedPerfmon()\n{\n    RandAddSeed();\n\n#ifdef WIN32\n    // Don't need this on Linux, OpenSSL automatically uses /dev/urandom\n    // Seed with the entire set of perfmon data\n\n    // This can take up to 2 seconds, so only do it every 10 minutes\n    static int64_t nLastPerfmon;\n    if (GetTime() < nLastPerfmon + 10 * 60)\n        return;\n    nLastPerfmon = GetTime();\n\n    std::vector<unsigned char> vData(250000, 0);\n    long ret = 0;\n    unsigned long nSize = 0;\n    const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data\n    while (true) {\n        nSize = vData.size();\n        ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, \"Global\", NULL, NULL, vData.data(), &nSize);\n        if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)\n            break;\n        vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially\n    }\n    RegCloseKey(HKEY_PERFORMANCE_DATA);\n    if (ret == ERROR_SUCCESS) {\n        RAND_add(vData.data(), nSize, nSize / 100.0);\n        memory_cleanse(vData.data(), nSize);\n        LogPrint(BCLog::RAND, \"%s: %lu bytes\\n\", __func__, nSize);\n    } else {\n        static bool warned = false; // Warn only once\n        if (!warned) {\n            LogPrintf(\"%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\\n\", __func__, ret);\n            warned = true;\n        }\n    }\n#endif\n}\n\n#ifndef WIN32\n/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most\n * compatible way to get cryptographic randomness on UNIX-ish platforms.\n */\nvoid GetDevURandom(unsigned char *ent32)\n{\n    int f = open(\"/dev/urandom\", O_RDONLY);\n    if (f == -1) {\n        RandFailure();\n    }\n    int have = 0;\n    do {\n        ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);\n        if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {\n            RandFailure();\n        }\n        have += n;\n    } while (have < NUM_OS_RANDOM_BYTES);\n    close(f);\n}\n#endif\n\n/** Get 32 bytes of system entropy. */\nvoid GetOSRand(unsigned char *ent32)\n{\n#if defined(WIN32)\n    HCRYPTPROV hProvider;\n    int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);\n    if (!ret) {\n        RandFailure();\n    }\n    ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);\n    if (!ret) {\n        RandFailure();\n    }\n    CryptReleaseContext(hProvider, 0);\n#elif defined(HAVE_SYS_GETRANDOM)\n    /* Linux. From the getrandom(2) man page:\n     * \"If the urandom source has been initialized, reads of up to 256 bytes\n     * will always return as many bytes as requested and will not be\n     * interrupted by signals.\"\n     */\n    int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);\n    if (rv != NUM_OS_RANDOM_BYTES) {\n        if (rv < 0 && errno == ENOSYS) {\n            /* Fallback for kernel <3.17: the return value will be -1 and errno\n             * ENOSYS if the syscall is not available, in that case fall back\n             * to /dev/urandom.\n             */\n            GetDevURandom(ent32);\n        } else {\n            RandFailure();\n        }\n    }\n#elif defined(HAVE_GETENTROPY)\n    /* On OpenBSD this can return up to 256 bytes of entropy, will return an\n     * error if more are requested.\n     * The call cannot return less than the requested number of bytes.\n     */\n    if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {\n        RandFailure();\n    }\n#elif defined(HAVE_SYSCTL_ARND)\n    /* FreeBSD and similar. It is possible for the call to return less\n     * bytes than requested, so need to read in a loop.\n     */\n    static const int name[2] = {CTL_KERN, KERN_ARND};\n    int have = 0;\n    do {\n        size_t len = NUM_OS_RANDOM_BYTES - have;\n        if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, NULL, 0) != 0) {\n            RandFailure();\n        }\n        have += len;\n    } while (have < NUM_OS_RANDOM_BYTES);\n#else\n    /* Fall back to /dev/urandom if there is no specific method implemented to\n     * get system entropy for this OS.\n     */\n    GetDevURandom(ent32);\n#endif\n}\n\nvoid GetRandBytes(unsigned char* buf, int num)\n{\n    if (RAND_bytes(buf, num) != 1) {\n        RandFailure();\n    }\n}\n\nstatic void AddDataToRng(void* data, size_t len);\n\nvoid RandAddSeedSleep()\n{\n    int64_t nPerfCounter1 = GetPerformanceCounter();\n    std::this_thread::sleep_for(std::chrono::milliseconds(1));\n    int64_t nPerfCounter2 = GetPerformanceCounter();\n\n    // Combine with and update state\n    AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1));\n    AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2));\n\n    memory_cleanse(&nPerfCounter1, sizeof(nPerfCounter1));\n    memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));\n}\n\n\nstatic std::mutex cs_rng_state;\nstatic unsigned char rng_state[32] = {0};\nstatic uint64_t rng_counter = 0;\n\nstatic void AddDataToRng(void* data, size_t len) {\n    CSHA512 hasher;\n    hasher.Write((const unsigned char*)&len, sizeof(len));\n    hasher.Write((const unsigned char*)data, len);\n    unsigned char buf[64];\n    {\n        std::unique_lock<std::mutex> lock(cs_rng_state);\n        hasher.Write(rng_state, sizeof(rng_state));\n        hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));\n        ++rng_counter;\n        hasher.Finalize(buf);\n        memcpy(rng_state, buf + 32, 32);\n    }\n    memory_cleanse(buf, 64);\n}\n\nvoid GetStrongRandBytes(unsigned char* out, int num)\n{\n    assert(num <= 32);\n    CSHA512 hasher;\n    unsigned char buf[64];\n\n    // First source: OpenSSL's RNG\n    RandAddSeedPerfmon();\n    GetRandBytes(buf, 32);\n    hasher.Write(buf, 32);\n\n    // Second source: OS RNG\n    GetOSRand(buf);\n    hasher.Write(buf, 32);\n\n    // Combine with and update state\n    {\n        std::unique_lock<std::mutex> lock(cs_rng_state);\n        hasher.Write(rng_state, sizeof(rng_state));\n        hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));\n        ++rng_counter;\n        hasher.Finalize(buf);\n        memcpy(rng_state, buf + 32, 32);\n    }\n\n    // Produce output\n    memcpy(out, buf, num);\n    memory_cleanse(buf, 64);\n}\n\nuint64_t GetRand(uint64_t nMax)\n{\n    if (nMax == 0)\n        return 0;\n\n    // The range of the random source must be a multiple of the modulus\n    // to give every possible output value an equal possibility\n    uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;\n    uint64_t nRand = 0;\n    do {\n        GetRandBytes((unsigned char*)&nRand, sizeof(nRand));\n    } while (nRand >= nRange);\n    return (nRand % nMax);\n}\n\nint GetRandInt(int nMax)\n{\n    return GetRand(nMax);\n}\n\nuint256 GetRandHash()\n{\n    uint256 hash;\n    GetRandBytes((unsigned char*)&hash, sizeof(hash));\n    return hash;\n}\n\nvoid FastRandomContext::RandomSeed()\n{\n    uint256 seed = GetRandHash();\n    rng.SetKey(seed.begin(), 32);\n    requires_seed = false;\n}\n\nuint256 FastRandomContext::rand256()\n{\n    if (bytebuf_size < 32) {\n        FillByteBuffer();\n    }\n    uint256 ret;\n    memcpy(ret.begin(), bytebuf + 64 - bytebuf_size, 32);\n    bytebuf_size -= 32;\n    return ret;\n}\n\nstd::vector<unsigned char> FastRandomContext::randbytes(size_t len)\n{\n    std::vector<unsigned char> ret(len);\n    if (len > 0) {\n        rng.Keystream(ret.data(), len);\n    }\n    return ret;\n}\n\nFastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0)\n{\n    rng.SetKey(seed.begin(), 32);\n}\n\nbool Random_SanityCheck()\n{\n    uint64_t start = GetPerformanceCounter();\n\n    /* This does not measure the quality of randomness, but it does test that\n     * OSRandom() overwrites all 32 bytes of the output given a maximum\n     * number of tries.\n     */\n    static const ssize_t MAX_TRIES = 1024;\n    uint8_t data[NUM_OS_RANDOM_BYTES];\n    bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */\n    int num_overwritten;\n    int tries = 0;\n    /* Loop until all bytes have been overwritten at least once, or max number tries reached */\n    do {\n        memset(data, 0, NUM_OS_RANDOM_BYTES);\n        GetOSRand(data);\n        for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {\n            overwritten[x] |= (data[x] != 0);\n        }\n\n        num_overwritten = 0;\n        for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {\n            if (overwritten[x]) {\n                num_overwritten += 1;\n            }\n        }\n\n        tries += 1;\n    } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);\n    if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */\n\n    // Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.\n    std::this_thread::sleep_for(std::chrono::milliseconds(1));\n    uint64_t stop = GetPerformanceCounter();\n    if (stop == start) return false;\n\n    // We called GetPerformanceCounter. Use it as entropy.\n    RAND_add((const unsigned char*)&start, sizeof(start), 1);\n    RAND_add((const unsigned char*)&stop, sizeof(stop), 1);\n\n    return true;\n}\n\nFastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)\n{\n    if (!fDeterministic) {\n        return;\n    }\n    uint256 seed;\n    rng.SetKey(seed.begin(), 32);\n}\n"
  },
  {
    "path": "src/random.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef RANDOM_H\n#define RANDOM_H\n\n#include \"crypto/chacha20.h\"\n#include \"crypto/common.h\"\n#include \"uint256.h\"\n\n#include <stdint.h>\n\n/* Seed OpenSSL PRNG with additional entropy data */\nvoid RandAddSeed();\n\n/**\n * Functions to gather random data via the OpenSSL PRNG\n */\nvoid GetRandBytes(unsigned char* buf, int num);\nuint64_t GetRand(uint64_t nMax);\nint GetRandInt(int nMax);\nuint256 GetRandHash();\n\n/**\n * Add a little bit of randomness to the output of GetStrongRangBytes.\n * This sleeps for a millisecond, so should only be called when there is\n * no other work to be done.\n */\nvoid RandAddSeedSleep();\n\n/**\n * Function to gather random data from multiple sources, failing whenever any\n * of those source fail to provide a result.\n */\nvoid GetStrongRandBytes(unsigned char* buf, int num);\n\n/**\n * Fast randomness source. This is seeded once with secure random data, but\n * is completely deterministic and insecure after that.\n * This class is not thread-safe.\n */\nclass FastRandomContext {\nprivate:\n    bool requires_seed;\n    ChaCha20 rng;\n\n    unsigned char bytebuf[64];\n    int bytebuf_size;\n\n    uint64_t bitbuf;\n    int bitbuf_size;\n\n    void RandomSeed();\n\n    void FillByteBuffer()\n    {\n        if (requires_seed) {\n            RandomSeed();\n        }\n        rng.Keystream(bytebuf, sizeof(bytebuf));\n        bytebuf_size = sizeof(bytebuf);\n    }\n\n    void FillBitBuffer()\n    {\n        bitbuf = rand64();\n        bitbuf_size = 64;\n    }\n\npublic:\n    explicit FastRandomContext(bool fDeterministic = false);\n\n    /** Initialize with explicit seed (only for testing) */\n    explicit FastRandomContext(const uint256& seed);\n\n    /** Generate a random 64-bit integer. */\n    uint64_t rand64()\n    {\n        if (bytebuf_size < 8) FillByteBuffer();\n        uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);\n        bytebuf_size -= 8;\n        return ret;\n    }\n\n    /** Generate a random (bits)-bit integer. */\n    uint64_t randbits(int bits) {\n        if (bits == 0) {\n            return 0;\n        } else if (bits > 32) {\n            return rand64() >> (64 - bits);\n        } else {\n            if (bitbuf_size < bits) FillBitBuffer();\n            uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));\n            bitbuf >>= bits;\n            bitbuf_size -= bits;\n            return ret;\n        }\n    }\n\n    /** Generate a random integer in the range [0..range). */\n    uint64_t randrange(uint64_t range)\n    {\n        --range;\n        int bits = CountBits(range);\n        while (true) {\n            uint64_t ret = randbits(bits);\n            if (ret <= range) return ret;\n        }\n    }\n\n    /** Generate random bytes. */\n    std::vector<unsigned char> randbytes(size_t len);\n\n    /** Generate a random 32-bit integer. */\n    uint32_t rand32() { return randbits(32); }\n\n    /** generate a random uint256. */\n    uint256 rand256();\n\n    /** Generate a random boolean. */\n    bool randbool() { return randbits(1); }\n};\n\n/* Number of random bytes returned by GetOSRand.\n * When changing this constant make sure to change all call sites, and make\n * sure that the underlying OS APIs for all platforms support the number.\n * (many cap out at 256 bytes).\n */\nstatic const ssize_t NUM_OS_RANDOM_BYTES = 32;\n\n/** Get 32 bytes of system entropy. Do not use this in application code: use\n * GetStrongRandBytes instead.\n */\nvoid GetOSRand(unsigned char *ent32);\n\n/** Check that OS randomness is available and returning the requested number\n * of bytes.\n */\nbool Random_SanityCheck();\n\n#endif\n"
  },
  {
    "path": "src/randomenv.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif\n\n#include <randomenv.h>\n\n#include <clientversion.h>\n#include <compat/cpuid.h>\n#include <crypto/sha512.h>\n#include <support/cleanse.h>\n#include <util/time.h> // for GetTime()\n#ifdef WIN32\n#include <compat.h> // for Windows API\n#endif\n\n#include <algorithm>\n#include <atomic>\n#include <chrono>\n#include <climits>\n#include <thread>\n#include <vector>\n\n#include <stdint.h>\n#include <string.h>\n#ifndef WIN32\n#include <sys/types.h> // must go before a number of other headers\n#include <fcntl.h>\n#include <netinet/in.h>\n#include <sys/resource.h>\n#include <sys/socket.h>\n#include <sys/stat.h>\n#include <sys/time.h>\n#include <sys/utsname.h>\n#include <unistd.h>\n#endif\n#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS\n#include <ifaddrs.h>\n#endif\n#if HAVE_SYSCTL\n#include <sys/sysctl.h>\n#if HAVE_VM_VM_PARAM_H\n#include <vm/vm_param.h>\n#endif\n#if HAVE_SYS_RESOURCES_H\n#include <sys/resources.h>\n#endif\n#if HAVE_SYS_VMMETER_H\n#include <sys/vmmeter.h>\n#endif\n#endif\n#if defined(HAVE_STRONG_GETAUXVAL)\n#include <sys/auxv.h>\n#endif\n\n//! Necessary on some platforms\nextern char** environ;\n\nnamespace {\n\nvoid RandAddSeedPerfmon(CSHA512& hasher)\n{\n#ifdef WIN32\n    // Seed with the entire set of perfmon data\n\n    // This can take up to 2 seconds, so only do it every 10 minutes.\n    // Initialize last_perfmon to 0 seconds, we don't skip the first call.\n    static std::atomic<std::chrono::seconds> last_perfmon{0s};\n    auto last_time = last_perfmon.load();\n    auto current_time = GetTime<std::chrono::seconds>();\n    if (current_time < last_time + std::chrono::minutes{10}) return;\n    last_perfmon = current_time;\n\n    std::vector<unsigned char> vData(250000, 0);\n    long ret = 0;\n    unsigned long nSize = 0;\n    const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data\n    while (true) {\n        nSize = vData.size();\n        ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, \"Global\", nullptr, nullptr, vData.data(), &nSize);\n        if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)\n            break;\n        vData.resize(std::min((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially\n    }\n    RegCloseKey(HKEY_PERFORMANCE_DATA);\n    if (ret == ERROR_SUCCESS) {\n        hasher.Write(vData.data(), nSize);\n        memory_cleanse(vData.data(), nSize);\n    } else {\n        // Performance data is only a best-effort attempt at improving the\n        // situation when the OS randomness (and other sources) aren't\n        // adequate. As a result, failure to read it is isn't considered critical,\n        // so we don't call RandFailure().\n        // TODO: Add logging when the logger is made functional before global\n        // constructors have been invoked.\n    }\n#endif\n}\n\n/** Helper to easily feed data into a CSHA512.\n *\n * Note that this does not serialize the passed object (like stream.h's << operators do).\n * Its raw memory representation is used directly.\n */\ntemplate<typename T>\nCSHA512& operator<<(CSHA512& hasher, const T& data) {\n    static_assert(!std::is_same<typename std::decay<T>::type, char*>::value, \"Calling operator<<(CSHA512, char*) is probably not what you want\");\n    static_assert(!std::is_same<typename std::decay<T>::type, unsigned char*>::value, \"Calling operator<<(CSHA512, unsigned char*) is probably not what you want\");\n    static_assert(!std::is_same<typename std::decay<T>::type, const char*>::value, \"Calling operator<<(CSHA512, const char*) is probably not what you want\");\n    static_assert(!std::is_same<typename std::decay<T>::type, const unsigned char*>::value, \"Calling operator<<(CSHA512, const unsigned char*) is probably not what you want\");\n    hasher.Write((const unsigned char*)&data, sizeof(data));\n    return hasher;\n}\n\n#ifndef WIN32\nvoid AddSockaddr(CSHA512& hasher, const struct sockaddr *addr)\n{\n    if (addr == nullptr) return;\n    switch (addr->sa_family) {\n    case AF_INET:\n        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));\n        break;\n    case AF_INET6:\n        hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));\n        break;\n    default:\n        hasher.Write((const unsigned char*)&addr->sa_family, sizeof(addr->sa_family));\n    }\n}\n\nvoid AddFile(CSHA512& hasher, const char *path)\n{\n    struct stat sb = {};\n    int f = open(path, O_RDONLY);\n    size_t total = 0;\n    if (f != -1) {\n        unsigned char fbuf[4096];\n        int n;\n        hasher.Write((const unsigned char*)&f, sizeof(f));\n        if (fstat(f, &sb) == 0) hasher << sb;\n        do {\n            n = read(f, fbuf, sizeof(fbuf));\n            if (n > 0) hasher.Write(fbuf, n);\n            total += n;\n            /* not bothering with EINTR handling. */\n        } while (n == sizeof(fbuf) && total < 1048576); // Read only the first 1 Mbyte\n        close(f);\n    }\n}\n\nvoid AddPath(CSHA512& hasher, const char *path)\n{\n    struct stat sb = {};\n    if (stat(path, &sb) == 0) {\n        hasher.Write((const unsigned char*)path, strlen(path) + 1);\n        hasher << sb;\n    }\n}\n#endif\n\n#if HAVE_SYSCTL\ntemplate<int... S>\nvoid AddSysctl(CSHA512& hasher)\n{\n    int CTL[sizeof...(S)] = {S...};\n    unsigned char buffer[65536];\n    size_t siz = 65536;\n    int ret = sysctl(CTL, sizeof...(S), buffer, &siz, nullptr, 0);\n    if (ret == 0 || (ret == -1 && errno == ENOMEM)) {\n        hasher << sizeof(CTL);\n        hasher.Write((const unsigned char*)CTL, sizeof(CTL));\n        if (siz > sizeof(buffer)) siz = sizeof(buffer);\n        hasher << siz;\n        hasher.Write(buffer, siz);\n    }\n}\n#endif\n\n#ifdef HAVE_GETCPUID\nvoid inline AddCPUID(CSHA512& hasher, uint32_t leaf, uint32_t subleaf, uint32_t& ax, uint32_t& bx, uint32_t& cx, uint32_t& dx)\n{\n    GetCPUID(leaf, subleaf, ax, bx, cx, dx);\n    hasher << leaf << subleaf << ax << bx << cx << dx;\n}\n\nvoid AddAllCPUID(CSHA512& hasher)\n{\n    uint32_t ax, bx, cx, dx;\n    // Iterate over all standard leaves\n    AddCPUID(hasher, 0, 0, ax, bx, cx, dx); // Returns max leaf in ax\n    uint32_t max = ax;\n    for (uint32_t leaf = 1; leaf <= max && leaf <= 0xFF; ++leaf) {\n        uint32_t maxsub = 0;\n        for (uint32_t subleaf = 0; subleaf <= 0xFF; ++subleaf) {\n            AddCPUID(hasher, leaf, subleaf, ax, bx, cx, dx);\n            // Iterate subleafs for leaf values 4, 7, 11, 13\n            if (leaf == 4) {\n                if ((ax & 0x1f) == 0) break;\n            } else if (leaf == 7) {\n                if (subleaf == 0) maxsub = ax;\n                if (subleaf == maxsub) break;\n            } else if (leaf == 11) {\n                if ((cx & 0xff00) == 0) break;\n            } else if (leaf == 13) {\n                if (ax == 0 && bx == 0 && cx == 0 && dx == 0) break;\n            } else {\n                // For any other leaf, stop after subleaf 0.\n                break;\n            }\n        }\n    }\n    // Iterate over all extended leaves\n    AddCPUID(hasher, 0x80000000, 0, ax, bx, cx, dx); // Returns max extended leaf in ax\n    uint32_t ext_max = ax;\n    for (uint32_t leaf = 0x80000001; leaf <= ext_max && leaf <= 0x800000FF; ++leaf) {\n        AddCPUID(hasher, leaf, 0, ax, bx, cx, dx);\n    }\n}\n#endif\n} // namespace\n\nvoid RandAddDynamicEnv(CSHA512& hasher)\n{\n    RandAddSeedPerfmon(hasher);\n\n    // Various clocks\n#ifdef WIN32\n    FILETIME ftime;\n    GetSystemTimeAsFileTime(&ftime);\n    hasher << ftime;\n#else\n    struct timespec ts = {};\n#    ifdef CLOCK_MONOTONIC\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n    hasher << ts;\n#    endif\n#    ifdef CLOCK_REALTIME\n    clock_gettime(CLOCK_REALTIME, &ts);\n    hasher << ts;\n#    endif\n#    ifdef CLOCK_BOOTTIME\n    clock_gettime(CLOCK_BOOTTIME, &ts);\n    hasher << ts;\n#    endif\n    // gettimeofday is available on all UNIX systems, but only has microsecond precision.\n    struct timeval tv = {};\n    gettimeofday(&tv, nullptr);\n    hasher << tv;\n#endif\n    // Probably redundant, but also use all the clocks C++11 provides:\n    hasher << std::chrono::system_clock::now().time_since_epoch().count();\n    hasher << std::chrono::steady_clock::now().time_since_epoch().count();\n    hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();\n\n#ifndef WIN32\n    // Current resource usage.\n    struct rusage usage = {};\n    if (getrusage(RUSAGE_SELF, &usage) == 0) hasher << usage;\n#endif\n\n#ifdef __linux__\n    AddFile(hasher, \"/proc/diskstats\");\n    AddFile(hasher, \"/proc/vmstat\");\n    AddFile(hasher, \"/proc/schedstat\");\n    AddFile(hasher, \"/proc/zoneinfo\");\n    AddFile(hasher, \"/proc/meminfo\");\n    AddFile(hasher, \"/proc/softirqs\");\n    AddFile(hasher, \"/proc/stat\");\n    AddFile(hasher, \"/proc/self/schedstat\");\n    AddFile(hasher, \"/proc/self/status\");\n#endif\n\n#if HAVE_SYSCTL\n#  ifdef CTL_KERN\n#    if defined(KERN_PROC) && defined(KERN_PROC_ALL)\n    AddSysctl<CTL_KERN, KERN_PROC, KERN_PROC_ALL>(hasher);\n#    endif\n#  endif\n#  ifdef CTL_HW\n#    ifdef HW_DISKSTATS\n    AddSysctl<CTL_HW, HW_DISKSTATS>(hasher);\n#    endif\n#  endif\n#  ifdef CTL_VM\n#    ifdef VM_LOADAVG\n    AddSysctl<CTL_VM, VM_LOADAVG>(hasher);\n#    endif\n#    ifdef VM_TOTAL\n    AddSysctl<CTL_VM, VM_TOTAL>(hasher);\n#    endif\n#    ifdef VM_METER\n    AddSysctl<CTL_VM, VM_METER>(hasher);\n#    endif\n#  endif\n#endif\n\n    // Stack and heap location\n    void* addr = malloc(4097);\n    hasher << &addr << addr;\n    free(addr);\n}\n\nvoid RandAddStaticEnv(CSHA512& hasher)\n{\n    // Some compile-time static properties\n    hasher << (CHAR_MIN < 0) << sizeof(void*) << sizeof(long) << sizeof(int);\n#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)\n    hasher << __GNUC__ << __GNUC_MINOR__ << __GNUC_PATCHLEVEL__;\n#endif\n#ifdef _MSC_VER\n    hasher << _MSC_VER;\n#endif\n    hasher << __cplusplus;\n#ifdef _XOPEN_VERSION\n    hasher << _XOPEN_VERSION;\n#endif\n#ifdef __VERSION__\n    const char* COMPILER_VERSION = __VERSION__;\n    hasher.Write((const unsigned char*)COMPILER_VERSION, strlen(COMPILER_VERSION) + 1);\n#endif\n\n    // Bitcoin client version\n    hasher << CLIENT_VERSION;\n\n#if defined(HAVE_STRONG_GETAUXVAL)\n    // Information available through getauxval()\n#  ifdef AT_HWCAP\n    hasher << getauxval(AT_HWCAP);\n#  endif\n#  ifdef AT_HWCAP2\n    hasher << getauxval(AT_HWCAP2);\n#  endif\n#  ifdef AT_RANDOM\n    const unsigned char* random_aux = (const unsigned char*)getauxval(AT_RANDOM);\n    if (random_aux) hasher.Write(random_aux, 16);\n#  endif\n#  ifdef AT_PLATFORM\n    const char* platform_str = (const char*)getauxval(AT_PLATFORM);\n    if (platform_str) hasher.Write((const unsigned char*)platform_str, strlen(platform_str) + 1);\n#  endif\n#  ifdef AT_EXECFN\n    const char* exec_str = (const char*)getauxval(AT_EXECFN);\n    if (exec_str) hasher.Write((const unsigned char*)exec_str, strlen(exec_str) + 1);\n#  endif\n#endif // HAVE_STRONG_GETAUXVAL\n\n#ifdef HAVE_GETCPUID\n    AddAllCPUID(hasher);\n#endif\n\n    // Memory locations\n    hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;\n\n    // Hostname\n    char hname[256];\n    if (gethostname(hname, 256) == 0) {\n        hasher.Write((const unsigned char*)hname, strnlen(hname, 256));\n    }\n\n#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS\n    // Network interfaces\n    struct ifaddrs *ifad = NULL;\n    getifaddrs(&ifad);\n    struct ifaddrs *ifit = ifad;\n    while (ifit != NULL) {\n        hasher.Write((const unsigned char*)&ifit, sizeof(ifit));\n        hasher.Write((const unsigned char*)ifit->ifa_name, strlen(ifit->ifa_name) + 1);\n        hasher.Write((const unsigned char*)&ifit->ifa_flags, sizeof(ifit->ifa_flags));\n        AddSockaddr(hasher, ifit->ifa_addr);\n        AddSockaddr(hasher, ifit->ifa_netmask);\n        AddSockaddr(hasher, ifit->ifa_dstaddr);\n        ifit = ifit->ifa_next;\n    }\n    freeifaddrs(ifad);\n#endif\n\n#ifndef WIN32\n    // UNIX kernel information\n    struct utsname name;\n    if (uname(&name) != -1) {\n        hasher.Write((const unsigned char*)&name.sysname, strlen(name.sysname) + 1);\n        hasher.Write((const unsigned char*)&name.nodename, strlen(name.nodename) + 1);\n        hasher.Write((const unsigned char*)&name.release, strlen(name.release) + 1);\n        hasher.Write((const unsigned char*)&name.version, strlen(name.version) + 1);\n        hasher.Write((const unsigned char*)&name.machine, strlen(name.machine) + 1);\n    }\n\n    /* Path and filesystem provided data */\n    AddPath(hasher, \"/\");\n    AddPath(hasher, \".\");\n    AddPath(hasher, \"/tmp\");\n    AddPath(hasher, \"/home\");\n    AddPath(hasher, \"/proc\");\n#ifdef __linux__\n    AddFile(hasher, \"/proc/cmdline\");\n    AddFile(hasher, \"/proc/cpuinfo\");\n    AddFile(hasher, \"/proc/version\");\n#endif\n    AddFile(hasher, \"/etc/passwd\");\n    AddFile(hasher, \"/etc/group\");\n    AddFile(hasher, \"/etc/hosts\");\n    AddFile(hasher, \"/etc/resolv.conf\");\n    AddFile(hasher, \"/etc/timezone\");\n    AddFile(hasher, \"/etc/localtime\");\n#endif\n\n    // For MacOS/BSDs, gather data through sysctl instead of /proc. Not all of these\n    // will exist on every system.\n#if HAVE_SYSCTL\n#  ifdef CTL_HW\n#    ifdef HW_MACHINE\n    AddSysctl<CTL_HW, HW_MACHINE>(hasher);\n#    endif\n#    ifdef HW_MODEL\n    AddSysctl<CTL_HW, HW_MODEL>(hasher);\n#    endif\n#    ifdef HW_NCPU\n    AddSysctl<CTL_HW, HW_NCPU>(hasher);\n#    endif\n#    ifdef HW_PHYSMEM\n    AddSysctl<CTL_HW, HW_PHYSMEM>(hasher);\n#    endif\n#    ifdef HW_USERMEM\n    AddSysctl<CTL_HW, HW_USERMEM>(hasher);\n#    endif\n#    ifdef HW_MACHINE_ARCH\n    AddSysctl<CTL_HW, HW_MACHINE_ARCH>(hasher);\n#    endif\n#    ifdef HW_REALMEM\n    AddSysctl<CTL_HW, HW_REALMEM>(hasher);\n#    endif\n#    ifdef HW_CPU_FREQ\n    AddSysctl<CTL_HW, HW_CPU_FREQ>(hasher);\n#    endif\n#    ifdef HW_BUS_FREQ\n    AddSysctl<CTL_HW, HW_BUS_FREQ>(hasher);\n#    endif\n#    ifdef HW_CACHELINE\n    AddSysctl<CTL_HW, HW_CACHELINE>(hasher);\n#    endif\n#  endif\n#  ifdef CTL_KERN\n#    ifdef KERN_BOOTFILE\n     AddSysctl<CTL_KERN, KERN_BOOTFILE>(hasher);\n#    endif\n#    ifdef KERN_BOOTTIME\n     AddSysctl<CTL_KERN, KERN_BOOTTIME>(hasher);\n#    endif\n#    ifdef KERN_CLOCKRATE\n     AddSysctl<CTL_KERN, KERN_CLOCKRATE>(hasher);\n#    endif\n#    ifdef KERN_HOSTID\n     AddSysctl<CTL_KERN, KERN_HOSTID>(hasher);\n#    endif\n#    ifdef KERN_HOSTUUID\n     AddSysctl<CTL_KERN, KERN_HOSTUUID>(hasher);\n#    endif\n#    ifdef KERN_HOSTNAME\n     AddSysctl<CTL_KERN, KERN_HOSTNAME>(hasher);\n#    endif\n#    ifdef KERN_OSRELDATE\n     AddSysctl<CTL_KERN, KERN_OSRELDATE>(hasher);\n#    endif\n#    ifdef KERN_OSRELEASE\n     AddSysctl<CTL_KERN, KERN_OSRELEASE>(hasher);\n#    endif\n#    ifdef KERN_OSREV\n     AddSysctl<CTL_KERN, KERN_OSREV>(hasher);\n#    endif\n#    ifdef KERN_OSTYPE\n     AddSysctl<CTL_KERN, KERN_OSTYPE>(hasher);\n#    endif\n#    ifdef KERN_POSIX1\n     AddSysctl<CTL_KERN, KERN_OSREV>(hasher);\n#    endif\n#    ifdef KERN_VERSION\n     AddSysctl<CTL_KERN, KERN_VERSION>(hasher);\n#    endif\n#  endif\n#endif\n\n    // Env variables\n    if (environ) {\n        for (size_t i = 0; environ[i]; ++i) {\n            hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));\n        }\n    }\n\n    // Process, thread, user, session, group, ... ids.\n#ifdef WIN32\n    hasher << GetCurrentProcessId() << GetCurrentThreadId();\n#else\n    hasher << getpid() << getppid() << getsid(0) << getpgid(0) << getuid() << geteuid() << getgid() << getegid();\n#endif\n    hasher << std::this_thread::get_id();\n}\n"
  },
  {
    "path": "src/randomenv.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_RANDOMENV_H\n#define CORE_RANDOMENV_H\n\n#include <crypto/sha512.h>\n\n/** Gather non-cryptographic environment data that changes over time. */\nvoid RandAddDynamicEnv(CSHA512& hasher);\n\n/** Gather non-cryptographic environment data that does not change over time. */\nvoid RandAddStaticEnv(CSHA512& hasher);\n\n#endif // CORE_RANDOMENV_H\n"
  },
  {
    "path": "src/rest.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"core_io.h\"\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"validation/validation.h\"\n#include \"httpserver.h\"\n#include \"httprpc.h\"\n#include \"rpc/blockchain.h\"\n#include \"rpc/server.h\"\n#include \"streams.h\"\n#include \"sync.h\"\n#include \"txmempool.h\"\n#include \"util/strencodings.h\"\n#include \"version.h\"\n\n#include <boost/algorithm/string.hpp>\n\n#include <univalue.h>\n\nstatic const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once\n\nenum RetFormat {\n    RF_UNDEF,\n    RF_BINARY,\n    RF_HEX,\n    RF_JSON,\n};\n\nstatic const struct {\n    enum RetFormat rf;\n    const char* name;\n} rf_names[] = {\n      {RF_UNDEF, \"\"},\n      {RF_BINARY, \"bin\"},\n      {RF_HEX, \"hex\"},\n      {RF_JSON, \"json\"},\n};\n\nstruct CCoin {\n    uint32_t fSegSig : 1;\n    uint32_t nHeight : 31;\n    CTxOut out;\n\n    ADD_SERIALIZE_METHODS;\n\n    CCoin() : nHeight(0) {}\n    CCoin(Coin&& in) : fSegSig(in.fSegSig), nHeight(in.nHeight), out(std::move(in.out)) {}\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        uint32_t nTxVerDummy = 0;\n        READWRITE(nTxVerDummy);\n        uint32_t nHeight_ = nHeight;\n        nHeight_ |= (fSegSig << 31);\n        READWRITE(nHeight_);\n        nHeight = (nHeight_   & (0b01111111111111111111111111111111));\n        fSegSig = ( (nHeight_ & (0b10000000000000000000000000000000)) > 0);\n        if (ser_action.ForRead())\n        {\n            out.ReadFromStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n        }\n        else\n        {\n            out.WriteToStream(s, (fSegSig ? CTransaction::SEGSIG_ACTIVATION_VERSION : CTransaction::SEGSIG_ACTIVATION_VERSION-1));\n        }\n    }\n};\n\nstatic bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)\n{\n    req->WriteHeader(\"Content-Type\", \"text/plain\");\n    req->WriteReply(status, message + \"\\r\\n\");\n    return false;\n}\n\nstatic enum RetFormat ParseDataFormat(std::string& param, const std::string& strReq)\n{\n    const std::string::size_type pos = strReq.rfind('.');\n    if (pos == std::string::npos)\n    {\n        param = strReq;\n        return rf_names[0].rf;\n    }\n\n    param = strReq.substr(0, pos);\n    const std::string suff(strReq, pos + 1);\n\n    for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)\n        if (suff == rf_names[i].name)\n            return rf_names[i].rf;\n\n    /* If no suffix is found, return original string.  */\n    param = strReq;\n    return rf_names[0].rf;\n}\n\nstatic std::string AvailableDataFormatsString()\n{\n    std::string formats = \"\";\n    for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)\n        if (strlen(rf_names[i].name) > 0) {\n            formats.append(\".\");\n            formats.append(rf_names[i].name);\n            formats.append(\", \");\n        }\n\n    if (formats.length() > 0)\n        return formats.substr(0, formats.length() - 2);\n\n    return formats;\n}\n\nstatic bool ParseHashStr(const std::string& strReq, uint256& v)\n{\n    if (!IsHex(strReq) || (strReq.size() != 64))\n        return false;\n\n    v.SetHex(strReq);\n    return true;\n}\n\nstatic bool CheckWarmup(HTTPRequest* req)\n{\n    std::string statusmessage;\n    if (RPCIsInWarmup(&statusmessage))\n         return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, \"Service temporarily unavailable: \" + statusmessage);\n    return true;\n}\n\nstatic bool rest_headers(HTTPRequest* req,\n                         const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string param;\n    const RetFormat rf = ParseDataFormat(param, strURIPart);\n    std::vector<std::string> path;\n    boost::split(path, param, boost::is_any_of(\"/\"));\n\n    if (path.size() != 2)\n        return RESTERR(req, HTTP_BAD_REQUEST, \"No header count specified. Use /rest/headers/<count>/<hash>.<ext>.\");\n\n    long count = strtol(path[0].c_str(), NULL, 10);\n    if (count < 1 || count > 2000)\n        return RESTERR(req, HTTP_BAD_REQUEST, \"Header count out of range: \" + path[0]);\n\n    std::string hashStr = path[1];\n    uint256 hash;\n    if (!ParseHashStr(hashStr, hash))\n        return RESTERR(req, HTTP_BAD_REQUEST, \"Invalid hash: \" + hashStr);\n\n    std::vector<const CBlockIndex *> headers;\n    headers.reserve(count);\n    {\n        LOCK(cs_main);\n        BlockMap::const_iterator it = mapBlockIndex.find(hash);\n        const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL;\n        while (pindex != NULL && chainActive.Contains(pindex)) {\n            headers.push_back(pindex);\n            if (headers.size() == (unsigned long)count)\n                break;\n            pindex = chainActive.Next(pindex);\n        }\n    }\n\n    CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);\n    for(const CBlockIndex *pindex : headers) {\n        ssHeader << pindex->GetBlockHeader();\n    }\n\n    switch (rf)\n    {\n        case RF_BINARY: {\n            std::string binaryHeader = ssHeader.str();\n            req->WriteHeader(\"Content-Type\", \"application/octet-stream\");\n            req->WriteReply(HTTP_OK, binaryHeader);\n            return true;\n        }\n\n        case RF_HEX: {\n            std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"text/plain\");\n            req->WriteReply(HTTP_OK, strHex);\n            return true;\n        }\n        case RF_JSON: {\n            UniValue jsonHeaders(UniValue::VARR);\n            for(const CBlockIndex *pindex : headers) {\n                jsonHeaders.push_back(blockheaderToJSON(pindex));\n            }\n            std::string strJSON = jsonHeaders.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n        case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: .bin, .hex)\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_block(HTTPRequest* req,\n                       const std::string& strURIPart,\n                       bool showTxDetails)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string hashStr;\n    const RetFormat rf = ParseDataFormat(hashStr, strURIPart);\n\n    uint256 hash;\n    if (!ParseHashStr(hashStr, hash))\n        return RESTERR(req, HTTP_BAD_REQUEST, \"Invalid hash: \" + hashStr);\n\n    CBlock block;\n    CBlockIndex* pblockindex = NULL;\n    {\n        if (mapBlockIndex.count(hash) == 0)\n            return RESTERR(req, HTTP_NOT_FOUND, hashStr + \" not found\");\n\n        pblockindex = mapBlockIndex[hash];\n        if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)\n            return RESTERR(req, HTTP_NOT_FOUND, hashStr + \" not available (pruned data)\");\n        {\n            LOCK(cs_main); // Required for ReadBlockFromDisk.\n            if (!ReadBlockFromDisk(block, pblockindex, Params()))\n                return RESTERR(req, HTTP_NOT_FOUND, hashStr + \" not found\");\n        }\n    }\n\n    CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());\n    ssBlock << block;\n\n    switch (rf)\n    {\n        case RF_BINARY: {\n            std::string binaryBlock = ssBlock.str();\n            req->WriteHeader(\"Content-Type\", \"application/octet-stream\");\n            req->WriteReply(HTTP_OK, binaryBlock);\n            return true;\n        }\n\n        case RF_HEX: {\n            std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"text/plain\");\n            req->WriteReply(HTTP_OK, strHex);\n            return true;\n        }\n\n        case RF_JSON: {\n            UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);\n            std::string strJSON = objBlock.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n\n        case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: \" + AvailableDataFormatsString() + \")\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)\n{\n    return rest_block(req, strURIPart, true);\n}\n\nstatic bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPart)\n{\n    return rest_block(req, strURIPart, false);\n}\n\n// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp\nUniValue getblockchaininfo(const JSONRPCRequest& request);\n\nstatic bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string param;\n    const RetFormat rf = ParseDataFormat(param, strURIPart);\n\n    switch (rf)\n    {\n        case RF_JSON: {\n            JSONRPCRequest jsonRequest;\n            jsonRequest.params = UniValue(UniValue::VARR);\n            UniValue chainInfoObject = getblockchaininfo(jsonRequest);\n            std::string strJSON = chainInfoObject.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n        case RF_UNDEF: case RF_BINARY: case RF_HEX:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: json)\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string param;\n    const RetFormat rf = ParseDataFormat(param, strURIPart);\n\n        switch (rf) {\n        case RF_JSON: {\n            UniValue mempoolInfoObject = mempoolInfoToJSON();\n\n            std::string strJSON = mempoolInfoObject.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n        case RF_BINARY: case RF_HEX: case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: json)\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string param;\n    const RetFormat rf = ParseDataFormat(param, strURIPart);\n\n    switch (rf)\n    {\n        case RF_JSON: {\n            UniValue mempoolObject = mempoolToJSON(true);\n\n            std::string strJSON = mempoolObject.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n        case RF_BINARY: case RF_HEX: case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: json)\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_tx(HTTPRequest* req, const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string hashStr;\n    const RetFormat rf = ParseDataFormat(hashStr, strURIPart);\n\n    uint256 hash;\n    if (!ParseHashStr(hashStr, hash))\n        return RESTERR(req, HTTP_BAD_REQUEST, \"Invalid hash: \" + hashStr);\n\n    CTransactionRef tx;\n    uint256 hashBlock = uint256();\n    if (!GetTransaction(hash, tx, Params(), hashBlock, true))\n        return RESTERR(req, HTTP_NOT_FOUND, hashStr + \" not found\");\n\n    CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());\n    ssTx << tx;\n\n    switch (rf)\n    {\n        case RF_BINARY: {\n            std::string binaryTx = ssTx.str();\n            req->WriteHeader(\"Content-Type\", \"application/octet-stream\");\n            req->WriteReply(HTTP_OK, binaryTx);\n            return true;\n        }\n\n        case RF_HEX: {\n            std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"text/plain\");\n            req->WriteReply(HTTP_OK, strHex);\n            return true;\n        }\n\n        case RF_JSON: {\n            UniValue objTx(UniValue::VOBJ);\n            TxToUniv(*tx, hashBlock, objTx);\n            std::string strJSON = objTx.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n\n        case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: \" + AvailableDataFormatsString() + \")\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)\n{\n    if (!CheckWarmup(req))\n        return false;\n    std::string param;\n    const RetFormat rf = ParseDataFormat(param, strURIPart);\n\n    std::vector<std::string> uriParts;\n    if (param.length() > 1)\n    {\n        std::string strUriParams = param.substr(1);\n        boost::split(uriParts, strUriParams, boost::is_any_of(\"/\"));\n    }\n\n    // throw exception in case of a empty request\n    std::string strRequestMutable = req->ReadBody();\n    if (strRequestMutable.length() == 0 && uriParts.size() == 0)\n        return RESTERR(req, HTTP_BAD_REQUEST, \"Error: empty request\");\n\n    bool fInputParsed = false;\n    bool fCheckMemPool = false;\n    std::vector<COutPoint> vOutPoints;\n\n    // parse/deserialize input\n    // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...\n\n    if (uriParts.size() > 0)\n    {\n\n        //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)\n        if (uriParts.size() > 0 && uriParts[0] == \"checkmempool\")\n            fCheckMemPool = true;\n\n        for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)\n        {\n            uint256 txid;\n            int32_t nOutput;\n            std::string strTxid = uriParts[i].substr(0, uriParts[i].find(\"-\"));\n            std::string strOutput = uriParts[i].substr(uriParts[i].find(\"-\")+1);\n\n            if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))\n                return RESTERR(req, HTTP_BAD_REQUEST, \"Parse error\");\n\n            txid.SetHex(strTxid);\n            vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));\n        }\n\n        if (vOutPoints.size() > 0)\n            fInputParsed = true;\n        else\n            return RESTERR(req, HTTP_BAD_REQUEST, \"Error: empty request\");\n    }\n\n    switch (rf)\n    {\n        case RF_HEX: {\n            // convert hex to bin, continue then with bin part\n            std::vector<unsigned char> strRequestV = ParseHex(strRequestMutable);\n            strRequestMutable.assign(strRequestV.begin(), strRequestV.end());\n        }\n\n        case RF_BINARY: {\n            try {\n                //deserialize only if user sent a request\n                if (strRequestMutable.size() > 0)\n                {\n                    if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA\n                        return RESTERR(req, HTTP_BAD_REQUEST, \"Combination of URI scheme inputs and raw post data is not allowed\");\n\n                    CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);\n                    oss << strRequestMutable;\n                    oss >> fCheckMemPool;\n                    //fixme: (PHASE4POSTREL) (SEGSIG)\n                    int nSize = 0;\n                    oss >> COMPACTSIZE(nSize);\n                    for (int i=0; i<nSize; ++i)\n                    {\n                        COutPoint outpoint;\n                        //fixme: (PHASE4POSTREL) (SEGSIG)\n                        outpoint.WriteToStream(oss, (CTxInType)0, (CTxInFlags)0, 1);\n                        vOutPoints.push_back(outpoint);\n                    }\n                }\n            } catch (const std::ios_base::failure& e) {\n                // abort in case of unreadable binary data\n                return RESTERR(req, HTTP_BAD_REQUEST, \"Parse error\");\n            }\n            break;\n        }\n\n        case RF_JSON: {\n            if (!fInputParsed)\n                return RESTERR(req, HTTP_BAD_REQUEST, \"Error: empty request\");\n            break;\n        }\n\n        case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: \" + AvailableDataFormatsString() + \")\");\n        }\n    }\n\n    // limit max outpoints\n    if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)\n        return RESTERR(req, HTTP_BAD_REQUEST, strprintf(\"Error: max outpoints exceeded (max: %d, tried: %d)\", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));\n\n    // check spentness and form a bitmap (as well as a JSON capable human-readable string representation)\n    std::vector<unsigned char> bitmap;\n    std::vector<CCoin> outs;\n    std::string bitmapStringRepresentation;\n    std::vector<bool> hits;\n    bitmap.resize((vOutPoints.size() + 7) / 8);\n    {\n        LOCK2(cs_main, mempool.cs);\n\n        CCoinsView viewDummy;\n        CCoinsViewCache view(&viewDummy);\n\n        CCoinsViewCache& viewChain = *pcoinsTip;\n        CCoinsViewMemPool viewMempool(&viewChain, mempool);\n\n        if (fCheckMemPool)\n            view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool\n\n        for (size_t i = 0; i < vOutPoints.size(); i++) {\n            bool hit = false;\n            Coin coin;\n            if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {\n                hit = true;\n                outs.emplace_back(std::move(coin));\n            }\n\n            hits.push_back(hit);\n            bitmapStringRepresentation.append(hit ? \"1\" : \"0\"); // form a binary string representation (human-readable for json output)\n            bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);\n        }\n    }\n\n    switch (rf)\n    {\n        case RF_BINARY: {\n            // serialize data\n            // use exact same output as mentioned in Bip64\n            CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);\n            ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHashPoW2() << COMPACTSIZEVECTOR(bitmap) << COMPACTSIZEVECTOR(outs);\n            std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();\n\n            req->WriteHeader(\"Content-Type\", \"application/octet-stream\");\n            req->WriteReply(HTTP_OK, ssGetUTXOResponseString);\n            return true;\n        }\n\n        case RF_HEX: {\n            CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);\n            ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHashPoW2() << COMPACTSIZEVECTOR(bitmap) << COMPACTSIZEVECTOR(outs);\n            std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + \"\\n\";\n\n            req->WriteHeader(\"Content-Type\", \"text/plain\");\n            req->WriteReply(HTTP_OK, strHex);\n            return true;\n        }\n\n        case RF_JSON: {\n            UniValue objGetUTXOResponse(UniValue::VOBJ);\n\n            // pack in some essentials\n            // use more or less the same output as mentioned in Bip64\n            objGetUTXOResponse.pushKV(\"chainHeight\", chainActive.Height());\n            objGetUTXOResponse.pushKV(\"chaintipHash\", chainActive.Tip()->GetBlockHashPoW2().GetHex());\n            objGetUTXOResponse.pushKV(\"bitmap\", bitmapStringRepresentation);\n\n            UniValue utxos(UniValue::VARR);\n            for (const CCoin& coin : outs) {\n                UniValue utxo(UniValue::VOBJ);\n                utxo.pushKV(\"height\", (int32_t)coin.nHeight);\n                utxo.pushKV(\"value\", ValueFromAmount(coin.out.nValue));\n\n                //fixme: (PHASE4POSTREL) (SEGSIG)\n                if (coin.out.GetType() <= CTxOutType::ScriptLegacyOutput)\n                {\n                    // include the script in a json output\n                    UniValue o(UniValue::VOBJ);\n                    ScriptPubKeyToUniv(coin.out.output.scriptPubKey, o, true);\n                    utxo.pushKV(\"scriptPubKey\", o);\n                    utxos.push_back(utxo);\n                }\n            }\n            objGetUTXOResponse.pushKV(\"utxos\", utxos);\n\n            // return json string\n            std::string strJSON = objGetUTXOResponse.write() + \"\\n\";\n            req->WriteHeader(\"Content-Type\", \"application/json\");\n            req->WriteReply(HTTP_OK, strJSON);\n            return true;\n        }\n        case RF_UNDEF:\n        default: {\n            return RESTERR(req, HTTP_NOT_FOUND, \"output format not found (available: \" + AvailableDataFormatsString() + \")\");\n        }\n    }\n\n    // not reached\n    return true; // continue to process further HTTP reqs on this cxn\n}\n\nstatic const struct {\n    const char* prefix;\n    bool (*handler)(HTTPRequest* req, const std::string& strReq);\n} uri_prefixes[] = {\n      {\"/rest/tx/\", rest_tx},\n      {\"/rest/block/notxdetails/\", rest_block_notxdetails},\n      {\"/rest/block/\", rest_block_extended},\n      {\"/rest/chaininfo\", rest_chaininfo},\n      {\"/rest/mempool/info\", rest_mempool_info},\n      {\"/rest/mempool/contents\", rest_mempool_contents},\n      {\"/rest/headers/\", rest_headers},\n      {\"/rest/getutxos\", rest_getutxos},\n};\n\nbool StartREST()\n{\n    for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)\n        RegisterHTTPHandler(uri_prefixes[i].prefix, false, uri_prefixes[i].handler);\n    return true;\n}\n\nvoid InterruptREST()\n{\n}\n\nvoid StopREST()\n{\n    for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)\n        UnregisterHTTPHandler(uri_prefixes[i].prefix, false);\n}\n"
  },
  {
    "path": "src/reverse_iterator.h",
    "content": "// Taken from https://gist.github.com/arvidsson/7231973\n\n#ifndef CORE_REVERSE_ITERATOR_H\n#define CORE_REVERSE_ITERATOR_H\n\n/**\n * Template used for reverse iteration in C++11 range-based for loops.\n *\n *   std::vector<int> v = {1, 2, 3, 4, 5};\n *   for (auto x : reverse_iterate(v))\n *       std::cout << x << \" \";\n */\n\ntemplate <typename T>\nclass reverse_range\n{\n    T &m_x;\n\npublic:\n    explicit reverse_range(T &x) : m_x(x) {}\n\n    auto begin() const -> decltype(this->m_x.rbegin())\n    {\n        return m_x.rbegin();\n    }\n\n    auto end() const -> decltype(this->m_x.rend())\n    {\n        return m_x.rend();\n    }\n};\n\ntemplate <typename T>\nreverse_range<T> reverse_iterate(T &x)\n{\n    return reverse_range<T>(x);\n}\n\n#endif // CORE_REVERSE_ITERATOR_H\n"
  },
  {
    "path": "src/reverselock.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef REVERSELOCK_H\n#define REVERSELOCK_H\n\n/**\n * An RAII-style reverse lock. Unlocks on construction and locks on destruction.\n */\ntemplate<typename Lock>\nclass reverse_lock\n{\npublic:\n\n    explicit reverse_lock(Lock& _lock) : lock(_lock) {\n        _lock.unlock();\n        _lock.swap(templock);\n    }\n\n    ~reverse_lock() {\n        templock.lock();\n        templock.swap(lock);\n    }\n\nprivate:\n    reverse_lock(reverse_lock const&);\n    reverse_lock& operator=(reverse_lock const&);\n\n    Lock& lock;\n    Lock templock;\n};\n\n#endif\n"
  },
  {
    "path": "src/rpc/accounts.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"appname.h\"\n#include <rpc/accounts.h>\n#include \"generation/generation.h\"\n#include \"generation/miner.h\"\n#include \"generation/witness.h\"\n#include <rpc/server.h>\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include <consensus/consensus.h>\n#include <consensus/validation.h>\n#include <boost/assign/list_of.hpp>\n\n#include \"init.h\"\n#include \"unity/appmanager.h\"\n#include \"witnessutil.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/rpcwallet.h>\n#include \"wallet/wallet.h\"\n#include \"wallet/coincontrol.h\"\n#include \"wallet/witness_operations.h\"\n#endif\n\n#include <numeric>\n#include <boost/accumulators/accumulators.hpp>\n#include <boost/accumulators/statistics/stats.hpp>\n#include <boost/accumulators/statistics/median.hpp>\n#include <boost/accumulators/statistics/mean.hpp>\n#include <boost/accumulators/statistics/min.hpp>\n#include <boost/accumulators/statistics/max.hpp>\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and ends_with()\n#include <boost/algorithm/string/split.hpp>\n\n#include \"txdb.h\"\n#include \"coins.h\"\n#include \"blockfilter.h\"\n#include \"primitives/transaction.h\"\n\n#include \"util/moneystr.h\"\n\n#include \"net.h\"\n\n\n#ifdef ENABLE_WALLET\n\nstatic UniValue gethashps(const JSONRPCRequest& request)\n{\n    if (request.fHelp)\n        throw std::runtime_error(\n            \"gethashps\\n\"\n            \"\\nReturns the estimated hashes per second that this computer is mining at.\\n\");\n\n    double dHashPerSecLog = dHashesPerSec;\n    std::string sHashPerSecLogLabel = \" h\";\n    selectLargesHashUnit(dHashPerSecLog, sHashPerSecLogLabel);\n    \n    double dRollingHashPerSecLog = dRollingHashesPerSec;\n    std::string sRollingHashPerSecLogLabel = \" h\";\n    selectLargesHashUnit(dRollingHashPerSecLog, sRollingHashPerSecLogLabel);\n    \n    double dBestHashPerSecLog = dBestHashesPerSec;\n    std::string sBestHashPerSecLogLabel = \" h\";\n    selectLargesHashUnit(dBestHashPerSecLog, sBestHashPerSecLogLabel);\n    \n    UniValue rec(UniValue::VOBJ);\n    rec.pushKV(\"last_reported\",   strprintf(\"%lf %s\", dHashPerSecLog, sHashPerSecLogLabel));\n    rec.pushKV(\"rolling_average\", strprintf(\"%lf %s\", dRollingHashPerSecLog, sRollingHashPerSecLogLabel));\n    rec.pushKV(\"best_reported\",   strprintf(\"%lf %s\", dBestHashPerSecLog, sBestHashPerSecLogLabel));\n    rec.pushKV(\"arena_setup\",     strprintf(\"%lf s\", nArenaSetupTime/1000.0));\n\n    return rec;\n    return strprintf(\"%lf %s/s (best %lf %s/s)\", dHashPerSecLog, sHashPerSecLogLabel, dBestHashPerSecLog, sBestHashPerSecLogLabel);\n}\n\nstatic UniValue sethashlimit(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"sethashlimit  ( limit )\\n\"\n            \"\\nSet the maximum number of hashes to calculate per second when mining.\\n\"\n            \"\\nThis mainly exists for testing purposes but can also be used to limit CPU usage a little.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. limit     (numeric) The number of hashes to allow per second, or -1 to remove limit.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"sethashlimit 500000\", \"\")\n            + HelpExampleRpc(\"sethashlimit 500000\", \"\"));\n\n    RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));\n\n    nHashThrottle = request.params[0].get_int();\n\n    LogPrintf(\"<DELTA> hash throttle %ld\\n\", nHashThrottle);\n\n    return strprintf(\"Throttling hash: %d\", nHashThrottle);\n}\n\nCBlockIndex* GetIndexFromSpecifier(std::string sTipHash)\n{\n    CBlockIndex* pIndex = nullptr;\n    int32_t nTipHeight;\n    if (ParseInt32(sTipHash, &nTipHeight))\n    {\n        pIndex = chainActive[nTipHeight];\n        if (!pIndex)\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found.\");\n    }\n    else\n    {\n        if (sTipHash == \"tip\" || sTipHash.empty())\n        {\n            pIndex = chainActive.Tip();\n            if (!pIndex)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Chain has no tip.\");\n        }\n        else if(boost::starts_with(sTipHash, \"tip~\"))\n        {\n            int nReverseHeight;\n            if (!ParseInt32(sTipHash.substr(4,std::string::npos), &nReverseHeight))\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid block specifier.\");\n            pIndex = chainActive.Tip();\n            if (!pIndex)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Chain has no tip.\");\n            while(pIndex && nReverseHeight>0)\n            {\n                pIndex = pIndex->pprev;\n                --nReverseHeight;\n            }\n            if (!pIndex)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid block specifier, chain does not go back that far.\");\n        }\n        else\n        {\n            uint256 hash(uint256S(sTipHash));\n            if (mapBlockIndex.count(hash) == 0)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found.\");\n            pIndex = mapBlockIndex[hash];\n        }\n    }\n    return pIndex;\n}\n\nstatic UniValue getwitnessinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 3)\n        throw std::runtime_error(\n            \"getwitnessinfo \\\"block_specifier\\\" verbose mine_only\\n\"\n            \"\\nReturns witness related network info for a given block.\"\n            \"\\nWhen verbose is enabled returns additional statistics.\\n\"\n            \"\\nNB! Note that this command effectively winds back a copy of the chain to a specified point in time in order to obtain detailed information\\n\"\n            \"\\nTherefore the further back in time you go the slower it becomes, trying to get information on the entire chain via this command by repeatedly calling it for every block is therefore incredibly inefficient\\n\"\n            \"\\nIf you need to do this it is recommended that you make use of the range specifier '-' in a single call; which will be exponentially faster than making multiple calls.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"block_specifier\\\"       (string, optional, default=tip) The block_specifier for which to display witness information, if empty or 'tip' the tip of the current chain is used.\\n\"\n            \"\\nSpecifier can be the hash of the block; an absolute height in the blockchain or a tip~# specifier to iterate backwards from tip; for which to return witness details\\n\"\n            \"\\nSpecifier can also be a range comprising of two instances of any of the above seperated by a dash '-' which will return an array of witness info for the entire range.\\n\"\n            \"2. verbose                  (boolean, optional, default=false) Display additional verbose information.\\n\"\n            \"3. mine_only                (boolean, optional, default=false) In verbose display only show account info for accounts belonging to this wallet.\\n\"\n            \"\\nResult:\\n\"\n            \"[{\\n\"\n            \"     \\\"pow2_phase\\\": n                                  (number) The number of the currently active pow2_phase.\\n\"\n            \"     \\\"number_of_witnesses_raw\\\": n                     (number) The total number of funded witness addresses in existence on the network.\\n\"\n            \"     \\\"number_of_witnesses_total\\\": n                   (number) The total number of funded witness addresses in existence on the network which pass basic restrictions to witness like minimum weight.\\n\"\n            \"     \\\"number_of_witnesses_eligible\\\": n                (number) The total number of witness addresses on the network which were considered eligible candidates to witness for this block.\\n\"\n            \"     \\\"total_witness_weight_raw\\\": n                    (number) The total weight of all witness addresses that were part of \\\"number_of_witnesses_total\\\".\\n\"\n            \"     \\\"total_witness_weight_eligible_raw\\\": n,          (number) The total weight of all witness addresses that were part of \\\"number_of_witnesses_eligible\\\".\\n\"\n            \"     \\\"total_witness_weight_eligible_adjusted\\\": n,     (number) The adjusted weight (after applying maximum weight restrictions) of all witness addresses that were part of \\\"number_of_witnesses_eligible\\\".\\n\"\n            \"     \\\"selected_witness_address\\\": address              (string) The address of the witness that has been selected for the current chain tip.\\n\"\n            \"     \\\"witness_statistics\\\": {\\n\"\n            \"         \\\"weight\\\": {                                  Weight statistics based on all witness addresses\\n\"\n            \"             \\\"largest\\\": n                             (number) The largest single address weight on the network.\\n\"\n            \"             \\\"smallest\\\": n                            (number) The smallest single address weight on the network.\\n\"\n            \"             \\\"mean\\\": n                                (number) The mean weight of all witness addresses.\\n\"\n            \"             \\\"median\\\": n                              (number) The median weight of all witness addresses.\\n\"\n            \"         }\\n\"\n            \"         \\\"amount\\\": {                                  Amount statistics based on all witness addresses\\n\"\n            \"             \\\"largest\\\": n                             (number) The largest single address amount on the network.\\n\"\n            \"             \\\"smallest\\\": n                            (number) The smallest single address amount on the network.\\n\"\n            \"             \\\"mean\\\": n                                (number) The mean amount of all witness addresses.\\n\"\n            \"             \\\"median\\\": n                              (number) The median amount of all witness addresses.\\n\"\n            \"         }\\n\"\n            \"         \\\"lock_period\\\": {                             Lock period statistics based on all witness addresses\\n\"\n            \"             \\\"largest\\\": n                             (number) The largest single address lock_period on the network.\\n\"\n            \"             \\\"smallest\\\": n                            (number) The smallest single address lock_period on the network.\\n\"\n            \"             \\\"mean\\\": n                                (number) The mean lock_period of all witness addresses.\\n\"\n            \"             \\\"median\\\": n                              (number) The median lock_period of all witness addresses.\\n\"\n            \"         }\\n\"\n            \"         \\\"age\\\": {                                     Age statistics based on all witness addresses (age is how long an address has existed since it last performed an operation of some kind)\\n\"\n            \"             \\\"largest\\\": n                             (number) The oldest address on the network.\\n\"\n            \"             \\\"smallest\\\": n                            (number) The more recent address on the network.\\n\"\n            \"             \\\"mean\\\": n                                (number) The mean age of all witness addresses.\\n\"\n            \"             \\\"median\\\": n                              (number) The median age of all witness addresses.\\n\"\n            \"         }\\n\"\n            \"     }\\n\"\n            \"     \\\"witness_address_list\\\": [                        List of all witness addresses on the network, with address specific information\\n\"\n            \"         {\\n\"\n            \"             \\\"type\\\": address_type                     (string) The type of address output used to create the address. Either SCRIPT or POW2WITNESS depending on whether SegSig was activated at the time of creation or not.\\n\"\n            \"             \\\"address\\\": address                       (string) The address of the witness that has been selected for the current chain tip.\\n\"\n            \"             \\\"age\\\": n                                 (number) The age of the address (how long since it was last active in any way)\\n\"\n            \"             \\\"amount\\\": n                              (number) The amount that is locked in the address.\\n\"\n            \"             \\\"raw_weight\\\": n                          (number) The raw weight of the address before any adjustments.\\n\"\n            \"             \\\"adjusted_weight\\\": n                     (number) The weight after 1% limit is applied\\n\"\n            \"             \\\"adjusted_weight_final\\\": n               (number) The weight considered by the witness algorithm after all adjustments are applied.\\n\"\n            \"             \\\"expected_witness_period\\\": n             (number) The period that the network will allow this address to go without witnessing before it expires.\\n\"\n            \"             \\\"estimated_witness_period\\\": n            (number) The average period in which this address should earn a reward over time\\n\"\n            \"             \\\"last_active_block\\\": n                   (number) The last block in which this address was active.\\n\"\n            \"             \\\"lock_from_block\\\": n                     (number) The block where this address was originally locked.\\n\"\n            \"             \\\"lock_until_block\\\": n                    (number) The block that this address will remain locked until.\\n\"\n            \"             \\\"lock_period\\\": n                         (number) The complete length in time that this address will be locked for\\n\"\n            \"             \\\"lock_period_expired\\\": n                 (boolean)true if the lock has expired (funds can be withdrawed)\\n\"\n            \"             \\\"eligible_to_witness\\\": n                 (number) true if the address is eligible to witness.\\n\"\n            \"             \\\"expired_from_inactivity\\\": n             (number) true if the network has expired (kicked off) this address due to it failing to witness in the expected period\\n\"\n            //\"             \\\"fail_count\\\": n                          (number) Internal accounting for how many times this address has been renewed; Note it increases in a non-linear fashion but decreases by 1 for every valid witnessing operation.\\n\"\n            //\"             \\\"action_nonce\\\": n                        (number) Internal count of how many actions this address has been involved in since creation; Used to ensure address transaction uniqueness across operations.\\n\"\n            \"             \\\"ismine_accountname\\\": n                  (string) If the address belongs to an account in this wallet, the name of the account.\\n\"\n            \"         }\\n\"\n            \"         ...\\n\"\n            \"     ]\\n\"\n            \"}]\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nBasic witness info for current chain tip\\n\"\n            + HelpExampleCli(\"getwitnessinfo tip false\", \"\")\n            + \"\\nExtended witness info for the block two blocks before tip\\n\"\n            + HelpExampleCli(\"getwitnessinfo tip~2 true\", \"\")\n            + \"\\nExtended witness info for block 400000\\n\"\n            + HelpExampleCli(\"getwitnessinfo 400000 true\", \"\")\n            + \"\\nExtended witness info for block with hash 8383d8e9999ade8ad0c9f84e7816afec3b9e4855341f678bb0fdc3af46ee6f31\\n\"\n            + HelpExampleCli(\"getwitnessinfo \\\"8383d8e9999ade8ad0c9f84e7816afec3b9e4855341f678bb0fdc3af46ee6f31\\\" true\", \"\"));\n\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n    #else\n    LOCK(cs_main);\n    #endif\n\n    CBlockIndex* pTipIndexStart = nullptr;\n    CBlockIndex* pTipIndexEnd = nullptr;\n    bool fVerbose = false;\n    bool showMineOnly = false;\n    if (request.params.size() > 0)\n    {\n        std::string sTipSpecifier = request.params[0].get_str();\n        int nRangeCount = std::count(sTipSpecifier.begin(), sTipSpecifier.end(), '-');\n        if (nRangeCount > 1)\n        {\n            throw std::runtime_error(\"Cannot have more than one range (-) in block specifier\");\n        }\n        else if (nRangeCount == 1)\n        {\n            std::vector<std::string> rangeSpecifiers;\n            boost::algorithm::split(rangeSpecifiers, sTipSpecifier, boost::is_any_of(\"-\"));\n            pTipIndexStart = GetIndexFromSpecifier(rangeSpecifiers[0]);\n            pTipIndexEnd = GetIndexFromSpecifier(rangeSpecifiers[1]);\n            if (pTipIndexStart == pTipIndexEnd)\n            {\n                throw std::runtime_error(\"End and start of range are identical\");\n            }\n        }\n        else\n        {\n            pTipIndexEnd = pTipIndexStart = GetIndexFromSpecifier(sTipSpecifier);\n        }\n    }\n    else\n    {\n        pTipIndexEnd = pTipIndexStart = chainActive.Tip();\n    }\n\n    if (!pTipIndexStart || (uint64_t)pTipIndexStart->nHeight < Params().GetConsensus().pow2Phase5FirstBlockHeight)\n        throw std::runtime_error(\"Requests block(s) from before phase 5 activation.\");\n    if (!pTipIndexEnd || (uint64_t)pTipIndexEnd->nHeight < Params().GetConsensus().pow2Phase5FirstBlockHeight)\n        throw std::runtime_error(\"Requests block(s) from before phase 5 activation.\");\n    \n    if (pTipIndexStart->nHeight < pTipIndexEnd->nHeight)\n    {\n        std::swap(pTipIndexStart, pTipIndexEnd);\n    }\n\n    if (request.params.size() >= 2)\n        fVerbose = request.params[1].get_bool();\n\n    if (request.params.size() > 2)\n        showMineOnly = request.params[2].get_bool();\n\n    UniValue witnessInfoForBlocks(UniValue::VOBJ);\n    \n    CBlockIndex* pTipIndex_ = nullptr;\n    //fixme: (PHASE5) - Fix this to only do a shallow clone of whats needed (need to fix recursive cloning mess first)\n    CCloneChain tempChain(chainActive, GetPow2ValidationCloneHeight(chainActive, pTipIndexEnd, 10), pTipIndexStart, pTipIndex_);\n    if (!pTipIndex_)\n            throw std::runtime_error(\"Could not locate a valid PoW² chain that contains this block as tip.\");\n    CCoinsViewCache viewNew(pcoinsTip);\n        \n    while (pTipIndex_ && (pTipIndex_->nHeight >= pTipIndexEnd->nHeight))\n    {\n        int64_t nTotalWeightAll = 0;\n        int64_t nNumWitnessAddressesAll = 0;\n        int64_t nPow2Phase = 1;\n        std::string sWitnessAddress;\n        UniValue jsonAllWitnessAddresses(UniValue::VARR);\n        boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::median(boost::accumulators::with_p_square_quantile), boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max> > witnessWeightStats;\n        boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::median(boost::accumulators::with_p_square_quantile), boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max> > witnessAmountStats;\n        boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::median(boost::accumulators::with_p_square_quantile), boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max> > lockPeriodWeightStats;\n        boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::median(boost::accumulators::with_p_square_quantile), boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max> > ageStats;\n\n        CValidationState state;\n        if (!ForceActivateChain(pTipIndex_, nullptr, state, Params(), tempChain, viewNew))\n            throw std::runtime_error(\"Could not locate a valid PoW² chain that contains this block as tip.\");\n        if (!state.IsValid())\n            throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n\n        if (IsPow2Phase5Active(pTipIndex_, Params(), tempChain, &viewNew))\n            nPow2Phase = 5;\n        else if (IsPow2Phase4Active(pTipIndex_))\n            nPow2Phase = 4;\n        else if (IsPow2Phase3Active(pTipIndex_?pTipIndex_->nHeight:0))\n            nPow2Phase = 3;\n        else if (IsPow2Phase2Active(pTipIndex_))\n            nPow2Phase = 2;\n\n        CGetWitnessInfo witInfo;\n\n        if (nPow2Phase >= 2)\n        {\n            CBlock block;\n            {\n                LOCK(cs_main);// cs_main lock required for ReadBlockFromDisk\n                if (!ReadBlockFromDisk(block, pTipIndex_, Params()))\n                    throw std::runtime_error(\"Could not load block to obtain PoW² information.\");\n            }\n\n            if (!GetWitnessInfo(tempChain, Params(), &viewNew, pTipIndex_->pprev, block, witInfo, pTipIndex_->nHeight))\n                throw std::runtime_error(\"Could not enumerate all PoW² witness information for block.\");\n\n            if (!GetPow2NetworkWeight(pTipIndex_, Params(), nNumWitnessAddressesAll, nTotalWeightAll, tempChain, &viewNew))\n                throw std::runtime_error(\"Block does not form part of a valid PoW² chain.\");\n\n            if (nPow2Phase >= 3)\n            {\n                if (!GetWitnessHelper(block.GetHashLegacy(), witInfo, pTipIndex_->nHeight))\n                    throw std::runtime_error(\"Could not select a valid PoW² witness for block.\");\n\n                CTxDestination selectedWitnessAddress;\n                if (!ExtractDestination(witInfo.selectedWitnessTransaction, selectedWitnessAddress))\n                    throw std::runtime_error(\"Could not extract PoW² witness for block.\");\n\n                sWitnessAddress = CNativeAddress(selectedWitnessAddress).ToString();\n            }\n        }\n\n        if (fVerbose)\n        {\n            for (auto& iter : witInfo.allWitnessCoins)\n            {\n                bool fEligible = false;\n                uint64_t nAdjustedWeight = 0;\n                {\n                    auto poolIter = witInfo.witnessSelectionPoolFiltered.begin();\n                    while (poolIter != witInfo.witnessSelectionPoolFiltered.end())\n                    {\n                        if (poolIter->outpoint == iter.first)\n                        {\n                            if (poolIter->coin.out == iter.second.out)\n                            {\n                                nAdjustedWeight = poolIter->nWeight;\n                                fEligible = true;\n                                break;\n                            }\n                        }\n                        ++poolIter;\n                    }\n                }\n                bool fExpired = false;\n                {\n                    auto poolIter = witInfo.witnessSelectionPoolUnfiltered.begin();\n                    while (poolIter != witInfo.witnessSelectionPoolUnfiltered.end())\n                    {\n                        if (poolIter->outpoint == iter.first)\n                        {\n                            if (poolIter->coin.out == iter.second.out)\n                            {\n                                if (witnessHasExpired(poolIter->nAge, poolIter->nWeight, witInfo.nTotalWeightRaw))\n                                {\n                                    fExpired = true;\n                                }\n                                break;\n                            }\n                        }\n                        ++poolIter;\n                    }\n                }\n        \n                CTxDestination address;\n                if (!ExtractDestination(iter.second.out, address))\n                    throw std::runtime_error(\"Could not extract PoW² witness for block.\");\n                \n                uint64_t nFailCount=0;\n                uint64_t nActionNonce=0;\n                if (iter.second.out.GetType() == PoW2WitnessOutput)\n                {\n                    CTxOutPoW2Witness witnessDetails;\n                    if (!GetPow2WitnessOutput(iter.second.out, witnessDetails))\n                        throw std::runtime_error(\"Could not extract PoW² witness details for block.\");\n                    nFailCount = witnessDetails.failCount;\n                    nActionNonce = witnessDetails.actionNonce;\n                }\n\n                uint64_t nLastActiveBlock = iter.second.nHeight;\n                uint64_t nLockFromBlock = 0;\n                uint64_t nLockUntilBlock = 0;\n                uint64_t nLockPeriodInBlocks = GetPoW2LockLengthInBlocksFromOutput(iter.second.out, iter.second.nHeight, nLockFromBlock, nLockUntilBlock);\n                uint64_t nRawWeight = GetPoW2RawWeightForAmount(iter.second.out.nValue, pTipIndex_->nHeight, nLockPeriodInBlocks);\n                uint64_t nAge = pTipIndex_->nHeight - nLastActiveBlock;\n                CAmount nValue = iter.second.out.nValue;\n\n                bool fLockPeriodExpired = (GetPoW2RemainingLockLengthInBlocks(nLockUntilBlock, pTipIndex_->nHeight) == 0);\n\n                std::string strAddress = CNativeAddress(address).ToString();\n                #ifdef ENABLE_WALLET\n                std::string accountName = accountNameForAddress(*pwallet, address);\n                #endif\n\n                UniValue rec(UniValue::VOBJ);\n                rec.pushKV(\"type\", iter.second.out.GetTypeAsString());\n                rec.pushKV(\"address\", strAddress);\n                rec.pushKV(\"age\", nAge);\n                rec.pushKV(\"amount\", ValueFromAmount(nValue));\n                rec.pushKV(\"raw_weight\", nRawWeight);\n                rec.pushKV(\"adjusted_weight\", std::min(nRawWeight, witInfo.nMaxIndividualWeight));\n                rec.pushKV(\"adjusted_weight_final\", nAdjustedWeight);\n                rec.pushKV(\"expected_witness_period\", expectedWitnessBlockPeriod(nRawWeight, witInfo.nTotalWeightRaw));\n                rec.pushKV(\"estimated_witness_period\", estimatedWitnessBlockPeriod(nRawWeight, witInfo.nTotalWeightRaw));\n                rec.pushKV(\"last_active_block\", nLastActiveBlock);\n                rec.pushKV(\"lock_from_block\", nLockFromBlock);\n                rec.pushKV(\"lock_until_block\", nLockUntilBlock);\n                rec.pushKV(\"lock_period\", nLockPeriodInBlocks);\n                rec.pushKV(\"lock_period_expired\", fLockPeriodExpired);\n                rec.pushKV(\"eligible_to_witness\", fEligible);\n                rec.pushKV(\"expired_from_inactivity\", fExpired);\n                rec.pushKV(\"fail_count\", nFailCount);\n                rec.pushKV(\"action_nonce\", nActionNonce);\n                #ifdef ENABLE_WALLET\n                rec.pushKV(\"ismine_accountname\", accountName);\n                #else\n                rec.pushKV(\"ismine_accountname\", \"\");\n                #endif\n\n                witnessWeightStats(nRawWeight);\n                lockPeriodWeightStats(nLockPeriodInBlocks);\n                witnessAmountStats(nValue);\n                ageStats(nAge);\n\n                #ifdef ENABLE_WALLET\n                if (showMineOnly && accountName.empty())\n                    continue;\n                #endif\n\n                jsonAllWitnessAddresses.push_back(rec);\n            }\n        }\n\n        UniValue witnessInfoForBlock(UniValue::VARR);\n        UniValue rec(UniValue::VOBJ);\n        rec.pushKV(\"pow2_phase\", nPow2Phase);\n        rec.pushKV(\"number_of_witnesses_raw\", (uint64_t)nNumWitnessAddressesAll);\n        rec.pushKV(\"number_of_witnesses_total\", (uint64_t)witInfo.witnessSelectionPoolUnfiltered.size());\n        rec.pushKV(\"number_of_witnesses_eligible\", (uint64_t)witInfo.witnessSelectionPoolFiltered.size());\n        rec.pushKV(\"total_witness_weight_raw\", (uint64_t)witInfo.nTotalWeightRaw);\n        rec.pushKV(\"total_witness_weight_eligible_raw\", (uint64_t)witInfo.nTotalWeightEligibleRaw);\n        rec.pushKV(\"total_witness_weight_eligible_adjusted\", (uint64_t)witInfo.nTotalWeightEligibleAdjusted);\n        rec.pushKV(\"selected_witness_address\", sWitnessAddress);\n        rec.pushKV(\"selected_witness_index\", (uint64_t)witInfo.selectedWitnessIndex);\n        if (fVerbose)\n        {\n            UniValue averages(UniValue::VOBJ);\n            {\n                if (boost::accumulators::count(witnessWeightStats) > 0)\n                {\n                    UniValue weight(UniValue::VOBJ);\n                    weight.pushKV(\"largest\", boost::accumulators::max(witnessWeightStats));\n                    weight.pushKV(\"smallest\", boost::accumulators::min(witnessWeightStats));\n                    weight.pushKV(\"mean\", boost::accumulators::mean(witnessWeightStats));\n                    weight.pushKV(\"median\", boost::accumulators::median(witnessWeightStats));\n                    averages.pushKV(\"weight\", weight);\n                }\n            }\n            {\n                if (boost::accumulators::count(witnessAmountStats) > 0)\n                {\n                    UniValue amount(UniValue::VOBJ);\n                    amount.pushKV(\"largest\", ValueFromAmount(boost::accumulators::max(witnessAmountStats)));\n                    amount.pushKV(\"smallest\", ValueFromAmount(boost::accumulators::min(witnessAmountStats)));\n                    amount.pushKV(\"mean\", ValueFromAmount(boost::accumulators::mean(witnessAmountStats)));\n                    amount.pushKV(\"median\", ValueFromAmount(boost::accumulators::median(witnessAmountStats)));\n                    averages.pushKV(\"amount\", amount);\n                }\n            }\n            {\n                if (boost::accumulators::count(lockPeriodWeightStats) > 0)\n                {\n                    UniValue lockPeriod(UniValue::VOBJ);\n                    lockPeriod.pushKV(\"largest\", boost::accumulators::max(lockPeriodWeightStats));\n                    lockPeriod.pushKV(\"smallest\", boost::accumulators::min(lockPeriodWeightStats));\n                    lockPeriod.pushKV(\"mean\", boost::accumulators::mean(lockPeriodWeightStats));\n                    lockPeriod.pushKV(\"median\", boost::accumulators::median(lockPeriodWeightStats));\n                    averages.pushKV(\"lock_period\", lockPeriod);\n                }\n            }\n            {\n                if (boost::accumulators::count(ageStats) > 0)\n                {\n                    UniValue age(UniValue::VOBJ);\n                    age.pushKV(\"largest\", boost::accumulators::max(ageStats));\n                    age.pushKV(\"smallest\", boost::accumulators::min(ageStats));\n                    age.pushKV(\"mean\", boost::accumulators::mean(ageStats));\n                    age.pushKV(\"median\", boost::accumulators::median(ageStats));\n                    averages.pushKV(\"age\", age);\n                }\n            }\n            rec.pushKV(\"witness_statistics\", averages);\n            rec.pushKV(\"witness_address_list\", jsonAllWitnessAddresses);\n        }\n        witnessInfoForBlock.push_back(rec);\n        if (pTipIndexStart == pTipIndexEnd)\n        {\n            return witnessInfoForBlock;\n        }\n        witnessInfoForBlocks.pushKV(pTipIndex_->GetBlockHashPoW2().ToString(), witnessInfoForBlock);\n        pTipIndex_ = pTipIndex_->pprev;\n    }\n    return witnessInfoForBlocks;\n}\n\nstatic UniValue getwitnessutxo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getwitnessutxo \\\"block_specifier\\\"\\n\"\n            \"\\nReturns witness utxo for a given block.\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"block_specifier\\\"       (string, optional, default=tip) The block_specifier for which to display witness information, if empty or 'tip' the tip of the current chain is used.\\n\"\n            );\n\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n    #else\n    LOCK(cs_main);\n    #endif\n\n    CBlockIndex* pTipIndexStart = nullptr;\n    std::string sTipSpecifier = request.params[0].get_str();\n    pTipIndexStart = GetIndexFromSpecifier(sTipSpecifier);\n\n    if (!pTipIndexStart || (uint64_t)pTipIndexStart->nHeight < Params().GetConsensus().pow2Phase5FirstBlockHeight)\n        throw std::runtime_error(\"Requests block(s) from before phase 5 activation.\");\n    \n    CBlockIndex* pTipIndex_ = nullptr;\n    //fixme: (PHASE5) - Fix this to only do a shallow clone of whats needed (need to fix recursive cloning mess first)\n    CCloneChain tempChain(chainActive, GetPow2ValidationCloneHeight(chainActive, pTipIndexStart, 10), pTipIndexStart, pTipIndex_);\n    if (!pTipIndex_)\n            throw std::runtime_error(\"Could not locate a valid PoW² chain that contains this block as tip.\");\n    CCoinsViewCache viewNew(pcoinsTip);\n        \n    UniValue witnessUTXO(UniValue::VARR);\n    CBlock block;\n    {\n        LOCK(cs_main);// cs_main lock required for ReadBlockFromDisk\n        if (!ReadBlockFromDisk(block, pTipIndex_, Params()))\n            throw std::runtime_error(\"Could not load block to obtain PoW² information.\");\n    }\n    \n    std::map<COutPoint, Coin> allWitnessCoinsIndexBased;\n    // Fetch all unspent witness outputs for the chain in which -block- acts as the tip.\n    if (!getAllUnspentWitnessCoins(tempChain, Params(), pTipIndex_->pprev, allWitnessCoinsIndexBased, &block, &viewNew, true))\n        throw std::runtime_error(\"Could not retrieve utxo for block.\");\n\n    SimplifiedWitnessUTXOSet witnessUTXOset = GenerateSimplifiedWitnessUTXOSetFromUTXOSet(allWitnessCoinsIndexBased);\n    \n    CGetWitnessInfo witInfoSimplified;\n    if (!GetWitnessFromSimplifiedUTXO(witnessUTXOset, pTipIndex_, witInfoSimplified))\n        throw std::runtime_error(\"Could not enumerate all simplified PoW² witness information for block.\");\n    \n    CGetWitnessInfo witnessInfo;\n    if (!GetWitness(tempChain, Params(), &viewNew, pTipIndex_->pprev, block, witnessInfo))\n        throw std::runtime_error(\"Could not enumerate all PoW² witness information for block.\");\n    \n    assert(witInfoSimplified.selectedWitnessIndex == witnessInfo.selectedWitnessIndex);\n    if ((uint64_t)pTipIndex_->nHeight >= Params().GetConsensus().pow2WitnessSyncHeight)\n    {\n        assert(witInfoSimplified.selectedWitnessOutpoint == witnessInfo.selectedWitnessOutpoint);\n    }\n    assert(witInfoSimplified.selectedWitnessBlockHeight == witnessInfo.selectedWitnessBlockHeight);\n    assert(witInfoSimplified.nTotalWeightRaw == witnessInfo.nTotalWeightRaw);\n    assert(witInfoSimplified.nTotalWeightEligibleRaw == witnessInfo.nTotalWeightEligibleRaw);\n    assert(witInfoSimplified.nTotalWeightEligibleAdjusted == witnessInfo.nTotalWeightEligibleAdjusted);\n    assert(witInfoSimplified.nMaxIndividualWeight == witnessInfo.nMaxIndividualWeight);    \n    \n    for (const auto& item : witnessUTXOset.witnessCandidates)\n    {\n        UniValue rec(UniValue::VOBJ);   \n        rec.pushKV(\"block_number\", (uint64_t)item.blockNumber);\n        rec.pushKV(\"transaction_index\", (uint64_t)item.transactionIndex);\n        rec.pushKV(\"transaction_output_index\", (uint64_t)item.transactionOutputIndex);\n        rec.pushKV(\"transaction_lock_until_block\", (uint64_t)item.lockUntilBlock);\n        rec.pushKV(\"transaction_lock_from_block\", (uint64_t)item.lockFromBlock);\n        rec.pushKV(\"value\", (uint64_t)item.nValue);\n        rec.pushKV(\"witnessPubKeyID\", item.witnessPubKeyID.ToString());\n        witnessUTXO.push_back(rec);\n    }\n    return witnessUTXO;\n}\n\nstatic UniValue disablewitnessing(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0) {\n        throw std::runtime_error(\n            \"disablewitnessing\\n\"\n            \"\\nStops all witnessing activity, call \\\"enablewitnessing\\\" to start witnessing again.\\n\"\n        );\n    }\n\n    witnessingEnabled = false;\n    return true;\n}\n\nstatic UniValue enablewitnessing(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0) {\n        throw std::runtime_error(\n            \"enablewitnessing\\n\"\n            \"\\nStarts all witnessing activity, call \\\"disablewitnessing\\\" to stop witnessing again.\\n\"\n        );\n    }\n\n    witnessingEnabled = true;\n    return true;\n}\n\nstatic UniValue dumpfiltercheckpoints(const JSONRPCRequest& request)\n{\n     if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"dumpfiltercheckpoints \\\"filename\\\"\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpfiltercheckpoints\", \"\"));\n\n    std::ofstream file;\n    boost::filesystem::path filepath = request.params[0].get_str();\n    filepath = boost::filesystem::absolute(filepath);\n    file.open(filepath.string().c_str());\n    if (!file.is_open())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot open wallet dump file\");\n\n    LogPrintf(\"Dumping filter checkpoints:\\n\");\n    int nStart = Params().IsTestnet() ? 0 : 250000;//Earliest possible recovery phrase (before this we didn't use phrases)\n    int nInterval1 = 500;\n    int nInterval2 = 100;\n    int nCrossOver = Params().IsTestnet() ? 200000 : 500000;\n    if (chainActive.Tip() != NULL)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet); // cs_main required for ReadBlockFromDisk.\n\n        std::vector<unsigned char> allFilters;\n        allFilters.reserve(3000000);\n        int nMaxHeight = chainActive.Height();\n        int nInterval = nInterval1;\n\n        unsigned int nTotalElements = 0;\n        unsigned int nTotalIntervals = 0;\n        for (int i=nStart; i+nInterval < nMaxHeight;)\n        {\n            if (i >= nCrossOver)\n                nInterval = nInterval2;\n\n            RangedCPBlockFilter filter(chainActive[i-1], chainActive[i+nInterval-1]);\n            const std::vector<unsigned char>& filterData = filter.GetEncodedFilter();\n            {\n                std::vector<unsigned char> filterSizeVector;\n                CVectorWriter sizeWriter(0, 0, filterSizeVector, 0);\n                WriteCompactSize(sizeWriter, filterData.size());\n                std::copy(filterSizeVector.cbegin(), filterSizeVector.cend(), std::back_inserter(allFilters));\n            }\n            std::copy(filterData.cbegin(), filterData.cend(), std::back_inserter(allFilters));\n\n            i += nInterval;\n\n            nTotalElements += filter.GetFilter().NumElements();\n            nTotalIntervals++;\n        }\n        LogPrintf(\"size: %d elements: %u intervals: %u\\n\", allFilters.size(), nTotalElements, nTotalIntervals);\n        file.write((const char*)&allFilters[0], allFilters.size());\n    }\n\n    file.close();\n    return true;\n}\n\nstatic UniValue dumpdiffarray(const JSONRPCRequest& request)\n{\n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"dumpdiffarray  \\\"height\\\" \\\"filename\\\"\\n\"\n            \"\\nDump code for a c++ array containing 'height' integers, where each integer represents the difficulty (nBits) of a block.\\n\"\n            \"\\nThis mainly exists for testing and development purposes, and can be used to help verify that your client has not been tampered with.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. height     (numeric) The number of blocks to add to the array.\\n\"\n            \"2. filename   (string) Where to write the data, file will be overwritten.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpdiffarray 1260000\", \"\"));\n\n    RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});\n    \n    std::ofstream file;\n    boost::filesystem::path filepath = request.params[1].get_str();\n    filepath = boost::filesystem::absolute(filepath);\n    file.open(filepath.string().c_str(), std::ios::out|std::ios::trunc);\n    if (!file.is_open())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot open target file\");\n\n    std::string reverseOutBuffer;\n    std::string scratchBuffer;\n    unsigned int nNumToOutput = request.params[0].get_int();\n    reverseOutBuffer.reserve(16*nNumToOutput);\n\n    CBlockIndex* pBlock = chainActive.Tip();\n    while(pBlock->pprev && (unsigned int)pBlock->nHeight > nNumToOutput)\n        pBlock = pBlock->pprev;\n\n    int count=1;\n    while(pBlock)\n    {\n        scratchBuffer = itostr(pBlock->nBits);\n        std::reverse(scratchBuffer.begin(), scratchBuffer.end());\n        if (count!= 1)\n            reverseOutBuffer += \" ,\";\n        reverseOutBuffer += scratchBuffer;\n        if (count%10 == 0)\n            reverseOutBuffer += \"        \\n\";\n        pBlock = pBlock->pprev;\n        count=count+1;\n    }\n\n    std::reverse(reverseOutBuffer.begin(), reverseOutBuffer.end());\n\n    file.write(&reverseOutBuffer[0], reverseOutBuffer.size());\n    file.close();\n\n    return reverseOutBuffer;\n}\n\n\nstatic UniValue dumpblockgaps(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"dumpblockgaps  start_height count\\n\"\n            \"\\nDump the block gaps for the last n blocks.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. start_height     (numeric) Where to start dumping from, counting backwards from chaintip.\\n\"\n            \"2. count           (numeric) The number of blocks to dump the block gaps of - going backwards from the start_height.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpblockgaps 50\", \"\"));\n\n    RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));\n\n    int nStart = request.params[0].get_int();\n    int nNumToOutput = request.params[1].get_int();\n\n    CBlockIndex* pBlock = chainActive.Tip();\n\n    UniValue jsonGaps(UniValue::VARR);\n\n    typedef boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::median(boost::accumulators::with_p_square_quantile), boost::accumulators::tag::mean, boost::accumulators::tag::min, boost::accumulators::tag::max>> StatCollection;\n    StatCollection gapStatsPoW;\n    StatCollection gapStatsWitness;\n\n    while(pBlock && pBlock->pprev && --nStart>0)\n    {\n        pBlock = pBlock->pprev;\n    }\n\n    while(pBlock && pBlock->pprev && --nNumToOutput>0)\n    {\n        int64_t gapPoW = std::abs((int64_t)pBlock->nTime - (int64_t)pBlock->pprev->nTime);\n        int64_t gapWitness = std::abs((int64_t)(pBlock->nTimePoW2Witness>0?pBlock->nTimePoW2Witness:pBlock->nTime) - (int64_t)(pBlock->pprev->nTimePoW2Witness>0?pBlock->pprev->nTimePoW2Witness:pBlock->pprev->nTime));\n        pBlock = pBlock->pprev;\n        if (gapPoW > 6000)\n        {\n            continue;\n        }\n        UniValue rec(UniValue::VOBJ);\n        UniValue arr(UniValue::VARR);\n        arr.push_back(gapWitness);\n        arr.push_back(gapPoW);\n        rec.pushKV(itostr(pBlock->nHeight), arr);\n        jsonGaps.push_back(rec);\n        gapStatsPoW(gapPoW);\n        gapStatsWitness(gapWitness);\n    }\n\n    {\n        UniValue rec(UniValue::VOBJ);\n        UniValue arr(UniValue::VARR);\n        arr.push_back(boost::accumulators::max(gapStatsWitness));\n        arr.push_back(boost::accumulators::max(gapStatsPoW));\n        rec.pushKV(\"max\", arr);\n        jsonGaps.push_back(rec);\n    }\n    {\n        UniValue rec(UniValue::VOBJ);\n        UniValue arr(UniValue::VARR);\n        arr.push_back(boost::accumulators::min(gapStatsWitness));\n        arr.push_back(boost::accumulators::min(gapStatsPoW));\n        rec.pushKV(\"min\", arr);\n        jsonGaps.push_back(rec);\n    }\n    {\n        UniValue rec(UniValue::VOBJ);\n        UniValue arr(UniValue::VARR);\n        arr.push_back(boost::accumulators::mean(gapStatsWitness));\n        arr.push_back(boost::accumulators::mean(gapStatsPoW));\n        rec.pushKV(\"mean\", arr);\n        jsonGaps.push_back(rec);\n    }\n    {\n        UniValue rec(UniValue::VOBJ);\n        UniValue arr(UniValue::VARR);\n        arr.push_back(boost::accumulators::median(gapStatsWitness));\n        arr.push_back(boost::accumulators::median(gapStatsPoW));\n        rec.pushKV(\"median\", arr);\n        jsonGaps.push_back(rec);\n    }\n    return jsonGaps;\n}\n\n\nstatic UniValue dumptransactionstats(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"dumptransactionstats start_height count\\n\"\n            \"\\nDump the transaction stats for the last n blocks.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. start_height     (numeric) Where to start dumping from, counting backwards from chaintip.\\n\"\n            \"2. count           (numeric) The number of blocks to dump the block gaps of - going backwards from the start_height.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpblockgaps 50\", \"\"));\n\n    RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));\n\n    int nStart = request.params[0].get_int();\n    int nNumToOutput = request.params[1].get_int();\n\n    CBlockIndex* pBlock = chainActive.Tip();\n\n    UniValue jsonGaps(UniValue::VARR);\n\n    while(pBlock && pBlock->pprev && --nStart>0)\n    {\n        pBlock = pBlock->pprev;\n    }\n\n    int count = 0;\n    std::map<int64_t, int64_t> inputCount;\n    std::map<int64_t, int64_t> outputCount;\n    inputCount[1]=outputCount[1]=0;\n    inputCount[2]=outputCount[2]=0;\n    inputCount[3]=outputCount[3]=0;\n    inputCount[4]=outputCount[4]=0;\n    inputCount[5]=outputCount[5]=0;\n    inputCount[6]=outputCount[6]=0;\n    inputCount[7]=outputCount[7]=0;\n\n    while(pBlock && pBlock->pprev && --nNumToOutput>0)\n    {\n        CBlock block;\n        LOCK(cs_main);// cs_main lock required for ReadBlockFromDisk\n        if (ReadBlockFromDisk(block, pBlock, Params()))\n        {\n            for (auto transaction : block.vtx)\n            {\n                ++count;\n                if (transaction->vin.size() >=7)\n                {\n                    ++inputCount[7];\n                }\n                else\n                {\n                    ++inputCount[transaction->vin.size()];\n                }\n                if (transaction->vout.size() >=7)\n                {\n                    ++outputCount[7];\n                }\n                else\n                {\n                    ++outputCount[transaction->vout.size()];\n                }\n            }\n        }\n        pBlock = pBlock->pprev;\n    }\n\n    jsonGaps.push_back(\"count:\");\n    jsonGaps.push_back(count);\n    jsonGaps.push_back(\"1:\");\n    jsonGaps.push_back(inputCount[1]);\n    jsonGaps.push_back(outputCount[1]);\n    jsonGaps.push_back(\"2:\");\n    jsonGaps.push_back(inputCount[2]);\n    jsonGaps.push_back(outputCount[2]);\n    jsonGaps.push_back(\"3:\");\n    jsonGaps.push_back(inputCount[3]);\n    jsonGaps.push_back(outputCount[3]);\n    jsonGaps.push_back(\"4:\");\n    jsonGaps.push_back(inputCount[4]);\n    jsonGaps.push_back(outputCount[4]);\n    jsonGaps.push_back(\"5:\");\n    jsonGaps.push_back(inputCount[5]);\n    jsonGaps.push_back(outputCount[5]);\n    jsonGaps.push_back(\"6:\");\n    jsonGaps.push_back(inputCount[6]);\n    jsonGaps.push_back(outputCount[6]);\n    jsonGaps.push_back(\"n:\");\n    jsonGaps.push_back(inputCount[7]);\n    jsonGaps.push_back(outputCount[7]);\n\n\n    return jsonGaps;\n}\n\n\nstatic UniValue changeaccountname(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"changeaccountname \\\"account\\\" \\\"name\\\"\\n\"\n            \"\\nChange the name of an account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"         (string) The UUID or unique label of the account.\\n\"\n            \"2. \\\"name\\\"           (string) The new label for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the final label for the account. Note this may be different from the given label in the case of duplicates.\\n\"\n            \"\\nActive account is used as the default for all commands that take an optional account argument.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"changeaccountname \\\"My witness account\\\" \\\"Charity donations\\\"\", \"\")\n            + HelpExampleRpc(\"changeaccountname \\\"My witness account\\\" \\\"Charity donations\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* account = AccountFromValue(pwallet, request.params[0], false);\n    std::string label = request.params[1].get_str();\n\n    pwallet->changeAccountName(account, label);\n\n    return account->getLabel();\n}\n\n#define MINIMUM_VALUABLE_AMOUNT 1000000000\nstatic UniValue deleteaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"deleteaccount \\\"account\\\" \\\"force\\\"\\n\"\n            \"\\nDelete an account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"        (string) The UUID or unique label of the account.\\n\"\n            \"2. \\\"force\\\"          (string) Specify string force to force deletion of a non-empty account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"deleteaccount \\\"My account\\\"\", \"\")\n            + HelpExampleRpc(\"deleteaccount \\\"My account\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* account = AccountFromValue(pwallet, request.params[0], false);\n\n    bool forcePurge = false;\n    if (account->IsWitnessOnly() || account->IsReadOnly())\n        forcePurge = true;\n    if (request.params.size() == 1 || request.params[1].get_str() != \"force\")\n    {\n        CAmount balance = pwallet->GetBalanceForDepth(0, account, true, true);\n        if (account->IsWitnessOnly())\n        {\n            balance = pwallet->GetBalanceForDepth(0, account, false, true);\n        }\n        if (balance > MINIMUM_VALUABLE_AMOUNT && !account->IsReadOnly())\n        {\n            throw std::runtime_error(strprintf(\"Account not empty, please first empty your account before trying to delete it [balance: %s]\", FormatMoney(balance)));\n        }\n    }\n\n    CWalletDB walletdb(*pwallet->dbw);\n    pwallet->deleteAccount(walletdb, account, forcePurge);\n    return true;\n}\n\n\nstatic UniValue restoreaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"restoreaccount \\\"account\\\"\\n\"\n            \"\\nRestore an account that has previously been deleted. Note account must still be in wallet does not work on purged accounts.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"        (string) The UUID or unique label of the account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"restoreaccount \\\"My account\\\"\", \"\")\n            + HelpExampleRpc(\"restoreaccount \\\"My account\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* restoreAccount;\n    try\n    {\n        restoreAccount = AccountFromValue(pwallet, request.params[0], false);\n    }\n    catch(...)\n    {\n        restoreAccount = AccountFromValue(pwallet, UniValue(request.params[0].get_str() + \" [Deleted]\"), false);\n    }\n\n    std::string name = restoreAccount->getLabel();\n    if (name.find(_(\"[Deleted]\")) != std::string::npos)\n    {\n        name = name.replace(name.find(_(\"[Deleted]\")), _(\"[Deleted]\").length(), _(\"[Restored]\"));\n    }\n\n    // Add the account, don't let it steal focus (this can create issues on e.g. mobile wallets where the UI/Unity lib expects a single account to always be the active one)\n    static_cast<CExtWallet*>(pactiveWallet)->addAccount(restoreAccount, name, false);\n\n    return true;\n}\n\n\n\nstatic UniValue rpccreateaccounthelper(CWallet* pwallet, std::string accountName, std::string accountType, bool bMakeActive=true)\n{\n    CAccount* account = CreateAccountHelper(pwallet, accountName, accountType, bMakeActive);\n\n    if (!account)\n        throw std::runtime_error(\"Unable to create account.\");\n\n    return getUUIDAsString(account->getUUID());\n}\n\nstatic UniValue createaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() == 0 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"createaccount \\\"name\\\" \\\"type\\\"\\n\"\n            \"Create an account, for HD accounts the currently active seed will be used to create the account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"name\\\"       (string) Specify the label for the account.\\n\"\n            \"2. \\\"type\\\"       (string, optional) Type of account to create (HD; Mobile; Legacy; Witness)\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"createaccount \\\"My new account\\\"\", \"\")\n            + HelpExampleRpc(\"createaccount \\\"My new account\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n\n    std::string accountType = \"HD\";\n    if (request.params.size() > 1)\n    {\n        accountType = request.params[1].get_str();\n        if (accountType != \"HD\" && accountType != \"Mobile\" && accountType != \"Legacy\" && accountType != \"Witness\")\n            throw std::runtime_error(\"Invalid account type\");\n    }\n\n    return rpccreateaccounthelper(pwallet, request.params[0].get_str(), accountType);\n}\n\n\nstatic UniValue createwitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"createwitnessaccount \\\"name\\\"\\n\"\n            \"Create an account, the currently active seed will be used to create the account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"name\\\"       (string) Specify the label for the account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"createwitnessaccount \\\"My 3y savings\\\"\", \"\")\n            + HelpExampleRpc(\"createwitnessaccount \\\"My 3y savings\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    if (GetPoW2Phase(chainActive.Tip()) < 2)\n        throw std::runtime_error(\"Cannot create witness accounts before phase 2 activates.\");\n\n    return rpccreateaccounthelper(pwallet, request.params[0].get_str(), \"Witness\", false);\n}\n\nstatic UniValue createminingaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"createminingaccount \\\"name\\\"\\n\"\n            \"Create an account, the currently active seed will be used to create the account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"name\\\"       (string) Specify the label for the account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"createminingaccount \\\"My 3y savings\\\"\", \"\")\n            + HelpExampleRpc(\"createminingaccount \\\"My 3y savings\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    \n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused) accountUUID;\n        if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n        {\n            throw std::runtime_error(\"Wallet already contains a mining account\");\n        }\n    }\n\n    return rpccreateaccounthelper(pwallet, request.params[0].get_str(), \"Mining\", false);\n}\n\n\nstatic UniValue setminingrewardaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1 )\n        throw std::runtime_error(\n            \"setminingrewardaddress \\\"reward_address\\\"\\n\"\n            \"\\nSet an output address into which mining rewards from a mining account will be paid.\\n\"\n            \"\\nWhen set `reward_address` overrides the default address that would otherwise be assigned by the wallet.\\n\"\n            \"\\nPass \\\"\\\" as the reward_address to restore default behaviour of using a wallet allocated address.\\n\"\n            \"\\nIt is necessary to manually call `setgenerate` again before changes made by this command will take effect.\\n\"\n            \"1. \\\"reward_address\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setminingrewardaddress \\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"\", \"\")\n            + HelpExampleRpc(\"setminingrewardaddress \\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"\", \"\"));\n\n    bool haveMiningAccount = false;\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused) accountUUID;\n        if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n        {\n            haveMiningAccount = true;\n            break;\n        }\n    }\n    if (!haveMiningAccount)\n    {\n        throw std::runtime_error(\"Wallet does not contain a mining account. First create a mining account using `createminingaccount` before using this command.\");\n    }\n    \n    std::string strWriteOverrideAddress = request.params[0].get_str();\n    if (!strWriteOverrideAddress.empty())\n    {\n        CNativeAddress address(strWriteOverrideAddress);\n        if (!address.IsValid())\n        {\n            throw std::runtime_error(\"Invalid mining address.\");\n        }\n    }\n    return CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString(strWriteOverrideAddress);\n}\n\nstatic UniValue getminingrewardaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0 )\n        throw std::runtime_error(\n            \"getminingrewardaddress\\n\"\n            \"\\nGet the output address into which `setgenerate`, `-gen` or the mining UI will pay the output of generated blocks.\\n\"\n            \"\\nIf `getminingrewardaddress` has been called then the address set by this will be returned.\\n\"\n            \"\\nOtherwise the default mining account address will be returned.\\n\"\n            \"\\nIf there is no mining account then an error will be returned.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"address\\\":\\\"address\\\", (string) The address if one is found. \\n\"\n            \"     \\\"is_default\\\",        (boolean) true if the address is from the mining account, false if it is one that has been manually set via `setminingrewardaddress`\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getminingrewardaddress\", \"\")\n            + HelpExampleRpc(\"getminingrewardaddress\", \"\"));\n        \n    bool haveMiningAccount = false;\n    CAccount* miningAccount = nullptr;\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused) accountUUID;\n        if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n        {\n            haveMiningAccount = true;\n            miningAccount = account;\n            break;\n        }\n    }\n    if (!haveMiningAccount)\n    {\n        throw std::runtime_error(\"Wallet does not contain a mining account. First create a mining account using `createminingaccount` before using this command.\");\n    }\n\n    std::string strMiningAddress;\n    CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(strMiningAddress);\n    UniValue result(UniValue::VOBJ);\n    if (strMiningAddress.size() == 0)\n    {\n        CReserveKeyOrScript* miningAddress = new CReserveKeyOrScript(pactiveWallet, miningAccount, KEYCHAIN_EXTERNAL);\n        CPubKey pubKey;\n        if (miningAddress->GetReservedKey(pubKey))\n        {\n            CKeyID keyID = pubKey.GetID();\n            strMiningAddress = CNativeAddress(keyID).ToString();\n        }\n        result.pushKV(\"address\",strMiningAddress);\n        result.pushKV(\"is_default\", true);\n    }\n    else\n    {\n        result.pushKV(\"address\",strMiningAddress);\n        result.pushKV(\"is_default\", false);\n    }\n    \n    return result;\n}\n\nstatic witnessOutputsInfoVector getCurrentOutputsForWitnessAddress(CNativeAddress& searchAddress)\n{\n    std::map<COutPoint, Coin> allWitnessCoins;\n    if (!getAllUnspentWitnessCoins(chainActive, Params(), chainActive.Tip(), allWitnessCoins))\n        throw std::runtime_error(\"Failed to enumerate all witness coins.\");\n\n    witnessOutputsInfoVector matchedOutputs;\n    for (const auto& [outpoint, coin] : allWitnessCoins)\n    {\n        CTxDestination compareDestination;\n        bool fValidAddress = ExtractDestination(coin.out, compareDestination);\n\n        if (fValidAddress && (CNativeAddress(compareDestination) == searchAddress))\n        {\n            matchedOutputs.push_back(std::tuple(coin.out, coin.nHeight, coin.nTxIndex, outpoint));\n        }\n    }\n    return matchedOutputs;\n}\n\n//! Given a string specifier, calculate a lock length in blocks to match it. e.g. 1d -> 576; 5b -> 5; 1m -> 17280\n//! Returns 0 if specifier is invalid.\nstatic uint64_t GetLockPeriodInBlocksFromFormattedStringSpecifier(std::string formattedLockPeriodSpecifier)\n{\n    uint64_t lockPeriodInBlocks = 0;\n    int nMultiplier = 1;\n    if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"y\"))\n    {\n        nMultiplier = 365 * DailyBlocksTarget();\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"m\"))\n    {\n        nMultiplier = 30 * DailyBlocksTarget();\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"w\"))\n    {\n        nMultiplier = 7 * DailyBlocksTarget();\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"d\"))\n    {\n        nMultiplier = DailyBlocksTarget();\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"b\"))\n    {\n        nMultiplier = 1;\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    if (!ParseUInt64(formattedLockPeriodSpecifier, &lockPeriodInBlocks))\n        return 0;\n    lockPeriodInBlocks *=  nMultiplier;\n    return lockPeriodInBlocks;\n}\n\nstatic UniValue fundwitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 4 || request.params.size() > 5)\n        throw std::runtime_error(\n            \"fundwitnessaccount \\\"funding_account\\\" \\\"witness_account\\\" \\\"amount\\\" \\\"time\\\" \\\"force_multiple\\\" \\n\"\n            \"Lock \\\"amount\\\" \" GLOBAL_COIN_CODE \" in \\\"witness_account\\\" for time period \\\"time\\\" using funds from \\\"funding_account\\\"\\n\"\n            \"NB! Though it is possible to fund a witness account that already has a balance, this can cause UI issues and is not strictly supported.\\n\"\n            \"It is highly recommended to rather use 'extendwitnessaccount' in this case which behaves more like what most people would expect.\\n\"\n            \"By default this command will fail if an account already contains an existing funded address.\\n\"\n            \"Note that this command is not currently calendar aware, it performs simplistic conversion i.e. 1 month is 30 days. This may change in future.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"funding_account\\\"      (string, required) The unique UUID or label for the account from which money will be removed. Use \\\"\\\" for the active account or \\\"*\\\" for all accounts to be considered.\\n\"\n            \"2. \\\"witness_account\\\"      (string, required) The unique UUID or label for the witness account that will hold the locked funds.\\n\"\n            \"3. \\\"amount\\\"               (string, required) The amount of \" GLOBAL_COIN_CODE \" to hold locked in the witness account. Minimum amount of 5000 \" GLOBAL_COIN_CODE \" is allowed.\\n\"\n            \"4. \\\"time\\\"                 (string, required) The time period for which the funds should be locked in the witness account. Minimum of 1 month and a maximum of 3 years. By default this is interpreted as blocks e.g. \\\"1000\\\", suffix with \\\"y\\\", \\\"m\\\", \\\"w\\\", \\\"d\\\", \\\"b\\\" to specifically work in years, months, weeks, days or blocks.\\n\"\n            \"5. force_multiple         (boolean, optional, default=false) Allow funding an account that already contains a valid witness address. \\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",   (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n   (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nTake 10000\" GLOBAL_COIN_CODE \" out of \\\"mysavingsaccount\\\" and lock in \\\"mywitnessaccount\\\" for 2 years.\\n\"\n            + HelpExampleCli(\"fundwitnessaccount \\\"mysavingsaccount\\\" \\\"mywitnessaccount\\\" \\\"10000\\\" \\\"2y\\\"\", \"\")\n            + \"\\nTake 10000\" GLOBAL_COIN_CODE \" out of \\\"mysavingsaccount\\\" and lock in \\\"mywitnessaccount\\\" for 2 months.\\n\"\n            + HelpExampleCli(\"fundwitnessaccount \\\"mysavingsaccount\\\" \\\"mywitnessaccount\\\" \\\"10000\\\" \\\"2m\\\"\", \"\")\n            + \"\\nTake 10000\" GLOBAL_COIN_CODE \" out of \\\"mysavingsaccount\\\" and lock in \\\"mywitnessaccount\\\" for 100 days.\\n\"\n            + HelpExampleCli(\"fundwitnessaccount \\\"mysavingsaccount\\\" \\\"mywitnessaccount\\\" \\\"10000\\\" \\\"100d\\\"\", \"\")\n            + HelpExampleRpc(\"fundwitnessaccount \\\"mysavingsaccount\\\" \\\"mywitnessaccount\\\" \\\"10000\\\" \\\"2y\\\"\", \"\"));\n\n    int nPoW2TipPhase = GetPoW2Phase(chainActive.Tip());\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (nPoW2TipPhase < 2)\n        throw std::runtime_error(\"Cannot fund witness accounts before phase 2 activates.\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], true);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* targetWitnessAccount = AccountFromValue(pwallet, request.params[1], true);\n    if (!targetWitnessAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate witness account [%s].\",  request.params[1].get_str()));\n\n    bool fAllowMultiple = false;\n    if (request.params.size() >= 5)\n        fAllowMultiple = request.params[4].get_bool();\n\n    // arg3 - amount\n    CAmount nAmount =  AmountFromValue(request.params[2]);\n\n    // arg4 - lock period.\n    // Calculate lock period based on suffix (if one is present) otherwise leave as is.\n    std::string formattedLockPeriodSpecifier = request.params[3].getValStr();\n    uint64_t nLockPeriodInBlocks = GetLockPeriodInBlocksFromFormattedStringSpecifier(formattedLockPeriodSpecifier);\n\n    try {\n        std::string txid;\n        CAmount fee;\n        fundwitnessaccount(pwallet, fundingAccount, targetWitnessAccount, nAmount, nLockPeriodInBlocks, fAllowMultiple, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstatic UniValue extendwitnessaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 4)\n        throw std::runtime_error(\n            \"extendwitnessaddress \\\"funding_account\\\" \\\"witness_address\\\" \\\"amount\\\" \\\"time\\\" \\n\"\n            \"Change the currently locked amount and time period for \\\"witness_address\\\" to match the new \\\"amount\\\" and time period \\\"time\\\"\\n\"\n            \"Note the new amount must be ≥ the old amount, and the new time period must exceed the remaining lock period that is currently set on the account\\n\"\n            \"\\\"funding_account\\\" is the account from which the locked funds will be claimed.\\n\"\n            \"\\\"time\\\" may be a minimum of 1 month and a maximum of 3 years.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"funding_account\\\"  (string, required) The unique UUID or label for the account from which money will be removed.\\n\"\n            \"2. \\\"witness_address\\\"  (string, required) The \" GLOBAL_APPNAME \" address for the witness key.\\n\"\n            \"3. \\\"amount\\\"           (string, required) The amount of \" GLOBAL_COIN_CODE \" to hold locked in the witness account. Minimum amount of 5000 \" GLOBAL_COIN_CODE \" is allowed.\\n\"\n            \"4. \\\"time\\\"             (string, required) The time period for which the funds should be locked in the witness account. By default this is interpreted as blocks e.g. \\\"1000\\\", suffix with \\\"y\\\", \\\"m\\\", \\\"w\\\", \\\"d\\\", \\\"b\\\" to specifically work in years, months, weeks, days or blocks.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",   (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n   (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"extendwitnessaddress \\\"My account\\\" \\\"2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\\\" \\\"50000\\\" \\\"2y\\\"\", \"\")\n            + HelpExampleRpc(\"extendwitnessaddress \\\"My account\\\" \\\"2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\\\" \\\"50000\\\" \\\"2y\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' address.\n    CNativeAddress witnessAddress(request.params[1].get_str());\n    bool isValid = witnessAddress.IsValidWitness(Params());\n\n    if (!isValid)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Not a valid witness address [%s].\", request.params[1].get_str()));\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAddress(witnessAddress);\n    if (unspentWitnessOutputs.size() == 0)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Address does not contain any witness outputs [%s].\", request.params[1].get_str()));\n\n    // arg3 - amount\n    CAmount requestedAmount =  AmountFromValue(request.params[2]);\n    if (requestedAmount < (gMinimumWitnessAmount*COIN))\n        throw JSONRPCError(RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n\n    // arg4 - lock period.\n    // Calculate lock period based on suffix (if one is present) otherwise leave as is.\n    std::string formattedLockPeriodSpecifier = request.params[3].getValStr();\n    uint64_t requestedLockPeriodInBlocks = GetLockPeriodInBlocksFromFormattedStringSpecifier(formattedLockPeriodSpecifier);\n    if (requestedLockPeriodInBlocks == 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid number passed for lock period.\");\n\n    try {\n        std::string txid;\n        CAmount fee;\n        extendwitnessaddresshelper(fundingAccount, unspentWitnessOutputs, pwallet, requestedAmount, requestedLockPeriodInBlocks, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstatic UniValue calculatewitnessweight(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"calculatewitnessweight \\\"amount\\\" \\\"time\\\" \\n\"\n            \"calculate what the witness weight would be for a given \\\"amount\\\" and time period \\\"time\\\"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"amount\\\"          (string, required) The amount of \" GLOBAL_COIN_CODE \" to hold locked in the witness account.\\n\"\n            \"2. \\\"time\\\"            (string, required) The time period for which the funds should be locked in the witness account. By default this is interpreted as blocks e.g. \\\"1000\\\", suffix with \\\"y\\\", \\\"m\\\", \\\"w\\\", \\\"d\\\", \\\"b\\\" to specifically work in years, months, weeks, days or blocks.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",  (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n  (string) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"calculateholdingweight \\\"120\\\" \\\"2y\\\"\", \"\")\n            + HelpExampleRpc(\"calculateholdingweight \\\"120\\\" \\\"2y\\\"\", \"\"));\n\n    // arg1 - amount\n    CAmount requestedAmount =  AmountFromValue(request.params[0]);\n\n    // arg2 - lock period.\n    // Calculate lock period based on suffix (if one is present) otherwise leave as is.\n    std::string formattedLockPeriodSpecifier = request.params[1].getValStr();\n    uint64_t requestedLockPeriodInBlocks = GetLockPeriodInBlocksFromFormattedStringSpecifier(formattedLockPeriodSpecifier);\n    if (requestedLockPeriodInBlocks == 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid number passed for lock period.\");\n\n    UniValue result(UniValue::VOBJ);\n    uint64_t rawWeight = GetPoW2RawWeightForAmount(requestedAmount, chainActive.Height(), requestedLockPeriodInBlocks);\n    result.pushKV(\"raw_weight\", rawWeight);\n\n    CGetWitnessInfo witnessInfo = GetWitnessInfoWrapper();\n    uint64_t networkWeight = witnessInfo.nTotalWeightEligibleRaw;\n    result.pushKV(\"adjusted_weight\", adjustedWeightForAmount(requestedAmount, chainActive.Height(), requestedLockPeriodInBlocks, networkWeight));\n\n    const auto optimalAmounts = optimalWitnessDistribution(requestedAmount, requestedLockPeriodInBlocks, networkWeight);    \n    uint64_t optimalWeight=0;\n    for (const auto& partAmount : optimalAmounts)\n    {\n        optimalWeight += GetPoW2RawWeightForAmount(partAmount,  chainActive.Height(), requestedLockPeriodInBlocks);\n    }\n    result.pushKV(\"optimal_parts\", (uint64_t)optimalAmounts.size());\n    result.pushKV(\"optimal_weight\", (uint64_t)optimalWeight);\n\n    return result;\n}\n\nstatic UniValue extendwitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 4)\n        throw std::runtime_error(\n            \"extendwitnessaccount \\\"funding_account\\\" \\\"witness_account\\\" \\\"amount\\\" \\\"time\\\" \\n\"\n            \"Change the currently locked amount and time period for \\\"witness_account\\\" to match the new \\\"amount\\\" ant time period \\\"time\\\"\\n\"\n            \"Note the new amount must be ≥ the old amount, and the new time period must exceed the remaining lock period that is currently set on the account\\n\"\n            \"\\\"funding_account\\\" is the account from which the locked funds will be claimed.\\n\"\n            \"\\\"time\\\" may be a minimum of 1 month and a maximum of 3 years.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"funding_account\\\" (string, required) The unique UUID or label for the account from which money will be removed.\\n\"\n            \"2. \\\"witness_account\\\" (string, required) The unique UUID or label for the witness account that will hold the locked funds.\\n\"\n            \"3. \\\"amount\\\"          (string, required) The amount of \" GLOBAL_COIN_CODE \" to hold locked in the witness account. Minimum amount of 5000 \" GLOBAL_COIN_CODE \" is allowed.\\n\"\n            \"4. \\\"time\\\"            (string, required) The time period for which the funds should be locked in the witness account. By default this is interpreted as blocks e.g. \\\"1000\\\", suffix with \\\"y\\\", \\\"m\\\", \\\"w\\\", \\\"d\\\", \\\"b\\\" to specifically work in years, months, weeks, days or blocks.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",  (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n  (string) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"extendwitnessaccount \\\"My account\\\" \\\"My witness account\\\" \\\"50000\\\" \\\"2y\\\"\", \"\")\n            + HelpExampleRpc(\"extendwitnessaccount \\\"My account\\\" \\\"My witness account\\\" \\\"50000\\\" \\\"2y\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* witnessAccount = AccountFromValue(pwallet, request.params[1], false);\n    if (!witnessAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate witness account [%s].\",  request.params[1].get_str()));\n\n    // arg3 - amount\n    CAmount requestedAmount =  AmountFromValue(request.params[2]);\n    if (requestedAmount < (gMinimumWitnessAmount*COIN))\n        throw JSONRPCError(RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n\n    // arg4 - lock period.\n    // Calculate lock period based on suffix (if one is present) otherwise leave as is.\n    std::string formattedLockPeriodSpecifier = request.params[3].getValStr();\n    uint64_t requestedLockPeriodInBlocks = GetLockPeriodInBlocksFromFormattedStringSpecifier(formattedLockPeriodSpecifier);\n    if (requestedLockPeriodInBlocks == 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid number passed for lock period.\");\n\n    try {\n        std::string txid;\n        CAmount fee;\n        extendwitnessaccount(pwallet, fundingAccount, witnessAccount, requestedAmount, requestedLockPeriodInBlocks, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstatic UniValue getactiveaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getactiveaccount \\n\"\n            \"\\nReturn the UUID for the currently active account.\\n\"\n            \"\\nActive account is used as the default for all commands that take an optional account argument.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getactiveaccount\", \"\")\n            + HelpExampleRpc(\"getactiveaccount\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    if (!pwallet->activeAccount)\n        throw std::runtime_error(\"No account active\");\n\n    return getUUIDAsString(pwallet->activeAccount->getUUID());\n}\n\nstatic UniValue getreadonlyaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getreadonlyaccount \\\"account\\\" \\n\"\n            \"\\nGet the public key of an HD account, this can be used to import the account as a read only account in another wallet.\\n\"\n            \"1. \\\"account\\\"        (required) The unique UUID or label for the account .\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the public key as an encoded string, that can be used with the \\\"importreadonlyaccount\\\" command.\\n\"\n            \"\\nNB! it is important to be careful with and protect access to this public key as if it is compromised it can compromise security of your entire wallet, in cases where one or more child private keys are also compromised.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getreadonlyaccount \\\"My account\\\"\", \"\")\n            + HelpExampleRpc(\"getreadonlyaccount \\\"My account\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* account = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!account->IsHD())\n        throw std::runtime_error(\"Can only be used on a HD account.\");\n\n    CAccountHD* accountHD = dynamic_cast<CAccountHD*>(account);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    return accountHD->GetAccountMasterPubKeyEncoded().c_str();\n}\n\nstatic UniValue importreadonlyaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"importreadonlyaccount \\\"name\\\" \\\"encodedkey\\\" \\n\"\n            \"\\nImport a read only account from an \\\"encodedkey\\\" which has been obtained by using \\\"getreadonlyaccount\\\"\\n\"\n            \"1. \\\"name\\\"       (string) Name to assign to the new account.\\n\"\n            \"2. \\\"encodedkey\\\" (string) Encoded string containing the extended public key for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID of the new account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"importreadonlyaccount \\\"Watch account\\\" \\\"dd3tNdQ8A4KqYvYVvXzGEU7ChdNye9RdTixnLSFqpQHG-2Rakbbkn7GDUTdD6wtSd5KV5PnCFgQt3FPc8eYkMonRM\\\"\", \"\")\n            + HelpExampleRpc(\"importreadonlyaccount \\\"Watch account\\\" \\\"dd3tNdQ8A4KqYvYVvXzGEU7ChdNye9RdTixnLSFqpQHG-2Rakbbkn7GDUTdD6wtSd5KV5PnCFgQt3FPc8eYkMonRM\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    CAccount* account = pwallet->CreateReadOnlyAccount(request.params[0].get_str().c_str(), request.params[1].get_str().c_str());\n\n    if (!account)\n        throw std::runtime_error(\"Unable to create account.\");\n\n    //fixme: (PHASE5) Use a timestamp here\n    // Whenever a key is imported, we need to scan the whole chain - do so now\n    pwallet->nTimeFirstKey = 1;\n    ResetSPVStartRescanThread();\n\n    return getUUIDAsString(account->getUUID());\n}\n\n\n\nstatic UniValue importlinkedaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"importlinkedaccount \\\"name\\\" \\\"encoded_key_uri\\\" \\n\"\n            \"\\nImport a linked account from an \\\"encoded_key_uri\\\"\\n\"\n            \"1. \\\"name\\\"       (string) Name to assign to the new account.\\n\"\n            \"2. \\\"encoded_key_uri\\\" (string) Encoded string containing the extended public key for the account, you can get one of these using 'getlinkedaccount'.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID of the new account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"importlinkedaccount \\\"Linked account\\\" \\\"\" GLOBAL_APP_URIPREFIX \"sync:2JQWMRUmrVym8Ak8TdeLhveAXkA1a5fb9fWzQUZkhd8G-3tS68yeav8TRJqhf5NEsa44tLRyjRouZQCcwcQ4Q5CSe:3mM4jYg7L4FhLC;TNhC2TDsD2L2PW7ri7ysn9YTfoQfpWT1K3\\\"\", \"\")\n            + HelpExampleRpc(\"importlinkedaccount \\\"Linked account\\\" \\\"\" GLOBAL_APP_URIPREFIX \"sync:2JQWMRUmrVym8Ak8TdeLhveAXkA1a5fb9fWzQUZkhd8G-3tS68yeav8TRJqhf5NEsa44tLRyjRouZQCcwcQ4Q5CSe:3mM4jYg7L4FhLC;TNhC2TDsD2L2PW7ri7ysn9YTfoQfpWT1K3\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    CEncodedSecretKeyExt<CExtKey> linkedKey;\n    if (!linkedKey.fromURIString(request.params[1].get_str().c_str()))\n    {\n        return false;\n    }\n    CAccount* account =  pwallet->CreateSeedlessHDAccount(request.params[0].get_str().c_str(), linkedKey.getKeyRaw(), AccountState::Normal, AccountType::Mobi);\n\n    if (!account)\n        throw std::runtime_error(\"Unable to create account.\");\n\n    ResetSPVStartRescanThread();\n\n    return getUUIDAsString(account->getUUID());\n}\n\n\nstatic UniValue getlinkedaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getlinkedaccount \\\"account\\\" \\n\"\n            \"\\nExport an \\\"encoded_key_uri\\\" for an account, import into another wallet using 'importlinkedaccount'\\n\"\n            \"1. \\\"account\\\"       (string) Name to assign to the new account.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the encoded_key_uri of the account\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getlinkedaccount \\\"Linked account\\\" \\\"\", \"\")\n            + HelpExampleRpc(\"getlinkedaccount \\\"Linked account\\\" \\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n    \n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n    \n    if (!forAccount->IsHD())\n        throw std::runtime_error(\"Not a HD account\");\n\n    std::string encodedURI = GLOBAL_APP_URIPREFIX \"sync:\" + CEncodedSecretKeyExt<CExtKey>(*(static_cast<CAccountHD*>(forAccount)->GetAccountMasterPrivKey())).SetCreationTime(i64tostr(forAccount->getEarliestPossibleCreationTime())).ToURIString();\n\n    return encodedURI;\n}\n\n\n\nstatic UniValue getactiveseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getactiveseed \\n\"\n            \"\\nReturn the UUID for the currently active account.\\n\"\n            \"\\nActive account is used as the default for all commands that take an optional account argument.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getactiveseed\", \"\")\n            + HelpExampleRpc(\"getactiveseed\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    if (!pwallet->activeSeed)\n        throw std::runtime_error(\"No seed active\");\n\n    return getUUIDAsString(pwallet->activeSeed->getUUID());\n}\n\nstatic UniValue setactiveaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"setactiveaccount \\n\"\n            \"\\nSet the currently active account based on name or uuid.\\n\"\n            \"1. \\\"account\\\"        (string, required) The unique UUID or label for the account or \\\"\\\" for the active account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setactiveaccount \\\"My account\\\"\", \"\")\n            + HelpExampleRpc(\"setactiveaccount \\\"My account\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* account = AccountFromValue(pwallet, request.params[0], false);\n\n    CWalletDB walletdb(*pwallet->dbw);\n    pwallet->setActiveAccount(walletdb, account);\n    return getUUIDAsString(account->getUUID());\n}\n\nstatic UniValue getaccountbalances(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getaccountbalances ( min_conf include_watchonly )\\n\"\n            \"Returns a list of balances for all accounts in the wallet.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. minconf           (numeric, optional, default=1) Only include transactions confirmed at least this many times.\\n\"\n            \"2. include_watchonly (boolean, optional, default=false) Also include balance in watch-only addresses (see 'importaddress')\\n\"\n            \"\\nResult:\\n\"\n            \"amount              (numeric) The total amount in \" + CURRENCY_UNIT + \" received for this account.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nThe total amount in the wallet\\n\"\n            + HelpExampleCli(\"getaccountbalances\", \"\") +\n            \"\\nThe total amount in the wallet at least 5 blocks confirmed\\n\"\n            + HelpExampleCli(\"getaccountbalances\", \"6\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"getaccountbalances\", \"6\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    int nMinDepth = 1;\n    if (request.params.size() > 0)\n        nMinDepth = request.params[0].get_int();\n\n    bool includeWatchOnly = false;\n    if (request.params.size() > 1)\n        includeWatchOnly = request.params[1].get_bool();\n\n    UniValue allAccounts(UniValue::VARR);\n\n    //NB! - Intermediate AccountFromValue step is required in order to handle default account semantics.\n    for (const auto& [accountUUID, account] : pwallet->mapAccounts)\n    {\n        UniValue rec(UniValue::VOBJ);\n        rec.pushKV(\"UUID\", getUUIDAsString(accountUUID));\n        rec.pushKV(\"label\",account->getLabel());\n        CAmount balance = pwallet->GetBalanceForDepth(nMinDepth, account, false, true);\n        if (includeWatchOnly)\n            balance += pwallet->GetWatchOnlyBalance(nMinDepth, account, true);\n        rec.pushKV(\"balance\", ValueFromAmount(balance));\n        allAccounts.push_back(rec);\n    }\n\n    return allAccounts;\n}\n\nstatic CHDSeed* SeedFromValue(CWallet* pwallet, const UniValue& value, bool useDefaultIfEmpty)\n{\n    std::string strSeedUUID = value.get_str();\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    if (strSeedUUID.empty())\n    {\n        if (!useDefaultIfEmpty || !pwallet->getActiveSeed())\n        {\n            throw std::runtime_error(\"No seed identifier passed, and no active seed selected, please select an active seed or pass a valid identifier.\");\n        }\n        return pwallet->getActiveSeed();\n    }\n\n    boost::uuids::uuid seedUUID = getUUIDFromString(strSeedUUID);\n\n    CHDSeed* foundSeed = NULL;\n    if (pwallet->mapSeeds.find(seedUUID) != pwallet->mapSeeds.end())\n    {\n        foundSeed = pwallet->mapSeeds[seedUUID];\n    }\n\n    if (!foundSeed)\n        throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, \"Not a valid seed UUID.\");\n\n    return foundSeed;\n}\n\nstatic UniValue setactiveseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"setactiveseed \\n\"\n            \"\\nSet the currently active seed by UUID.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setactiveseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\")\n            + HelpExampleRpc(\"setactiveseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CHDSeed* seed = SeedFromValue(pwallet, request.params[0], false);\n\n    CWalletDB walletdb(*pwallet->dbw);\n    pwallet->setActiveSeed(walletdb, seed);\n    return getUUIDAsString(seed->getUUID());\n}\n\n\nstatic UniValue createseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"createseed \\n\"\n            \"\\nCreate a new seed using random entropy.\\n\"\n            \"1. \\\"type\\\"       (string, optional default=BIP44) Type of seed to create (BIP44; BIP44NH; BIP44E; BIP32; BIP32L)\\n\"\n            \"\\nThe default is correct in almost all cases, only experts should work with the other types\\n\"\n            \"\\nBIP44 - This is the standard \" GLOBAL_APPNAME \" seed type that should be used in almost all cases.\\n\"\n            \"\\nBIP44NH - (No Hardening) This is the same as above, however with weakened security required for \\\"read only\\\" (watch) seed capability, use this only if you understand the implications and if you want to share your seed with another read only wallet.\\n\"\n            \"\\nBIP44E - This is a modified BIP44 with a different hash value, required for compatibility with some external wallets (e.g. Coinomi).\\n\"\n            \"\\nBIP32 - Older HD standard that was used by our mobile wallets before 1.6.0, use this to import/recover old mobile recovery phrases.\\n\"\n            \"\\nBIP32L - (Legacy) Even older HD standard that was used by our first android wallets, use this to import/recover very old mobile recovery phrases.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID of the new seed.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"createseed\", \"\")\n            + HelpExampleRpc(\"createseed\", \"\"));\n\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    CHDSeed::SeedType seedType = CHDSeed::CHDSeed::BIP44;\n    if (request.params.size() > 0)\n    {\n        seedType = SeedTypeFromString(request.params[0].get_str());\n    }\n\n    CHDSeed* newSeed = pwallet->GenerateHDSeed(seedType);\n\n    if(!newSeed)\n        throw std::runtime_error(\"Failed to generate seed\");\n\n    return getUUIDAsString(newSeed->getUUID());\n}\n\n\nstatic UniValue deleteseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"deleteseed \\\"seed\\\" should_purge_accounts \\n\" \n            \"\\nDelete a HD seed.\\n\"\n            \"1. \\\"seed\\\"                (string, required) The unique UUID for the seed that we want mnemonics of, or \\\"\\\" for the active seed.\\n\"\n            \"2. should_purge_accounts     (boolean, optional, default=false) Permanently purge from the wallet, all accounts associated with the seed, as opposed to simply marking them as deleted which places them in a hidden but still accessible state.\"\n            \"\\nResult:\\n\"\n            \"\\ntrue on success.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"deleteseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\")\n            + HelpExampleRpc(\"deleteseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\"));\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CHDSeed* seed = SeedFromValue(pwallet, request.params[0], true);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    bool shouldPurgeAccounts = false;\n    if (request.params.size() > 1)\n        shouldPurgeAccounts = request.params[1].get_bool();\n\n    CWalletDB walletdb(*pwallet->dbw);\n    pwallet->DeleteSeed(walletdb, seed, shouldPurgeAccounts);\n\n    return true;\n}\n\nstatic UniValue importseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)\n        throw std::runtime_error(\n            \"importseed \\\"mnemonic_or_pubkey\\\" \\\"type\\\" is_read_only \\n\"\n            \"\\nSet the currently active seed by UUID.\\n\"\n            \"1. \\\"mnemonic_or_pubkey\\\"       (string) Specify the BIP44 mnemonic that will be used to generate the seed.\\n\"\n            \"2. \\\"type\\\"       (string, optional default=BIP44) Type of seed to create (BIP44; BIP44NH; BIP44E; BIP32; BIP32L)\\n\"\n            \"\\nThe default is correct in almost all cases, only experts should work with the other types\\n\"\n            \"\\nBIP44 - This is the standard \" GLOBAL_APPNAME \" seed type that should be used in almost all cases.\\n\"\n            \"\\nBIP44NH - (No Hardening) This is the same as above, however with weakened security required for \\\"read only\\\" (watch) seed capability, use this only if you understand the implications and if you want to share your seed with another read only wallet.\\n\"\n            \"\\nBIP44E - This is a modified BIP44 with a different hash value, required for compatibility with some external wallets (e.g. Coinomi).\\n\"\n            \"\\nBIP32 - Older HD standard that was used by our mobile wallets before 1.6.0, use this to import/recover old mobile recovery phrases.\\n\"\n            \"\\nBIP32L - (Legacy) Even older HD standard that was used by our first android wallets, use this to import/recover very old mobile recovery phrases.\\n\"\n            \"\\nIn the case of read only seeds a pubkey rather than a mnemonic is required.\\n\"\n            \"3. is_read_only      (boolean, optional, default=false) Account is a 'read only account' - type argument will be ignored and always set to BIP44NH in this case. Wallet will be rescanned for transactions.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID of the new seed.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"importseed \\\"green cliff good ghost orange charge cancel blue group interest walk yellow\\\"\", \"\")\n            + HelpExampleRpc(\"importseed \\\"green cliff good ghost orange charge cancel blue group interest walk yellow\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    CHDSeed::SeedType seedType = CHDSeed::CHDSeed::BIP44;\n    if (request.params.size() > 1)\n    {\n        seedType = SeedTypeFromString(request.params[1].get_str());\n    }\n\n    bool fReadOnly = false;\n    if (request.params.size() > 2)\n        fReadOnly = request.params[2].get_bool();\n\n    CHDSeed* newSeed = NULL;\n    if (fReadOnly)\n    {\n        SecureString pubkeyString = request.params[0].get_str().c_str();\n        newSeed = pwallet->ImportHDSeedFromPubkey(pubkeyString);\n    }\n    else\n    {\n        SecureString mnemonic = request.params[0].get_str().c_str();\n        newSeed = pwallet->ImportHDSeed(mnemonic, seedType);\n    }\n\n    //fixme: (POST-PHASE5) Use a timestamp here\n    // Whenever a key is imported, we need to scan the whole chain - do so now\n    pwallet->nTimeFirstKey = 1;\n    ResetSPVStartRescanThread();\n\n    return getUUIDAsString(newSeed->getUUID());\n}\n\nstatic UniValue listallaccounts(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 2)\n        throw std::runtime_error(\n            \"listaccounts \\\"seed\\\" \\\"state\\\"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"seed\\\"        (string, optional) The unique UUID for the seed that we want accounts of.\\n\"\n            \"2. \\\"state\\\"       (string, optional, default=Normal) The state of account to list, options are: Normal, Deleted, Shadow, ShadowChild. \\\"*\\\" or \\\"\\\" to list all account states.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID and label for all wallet accounts.\\n\"\n            \"\\nNote UUID is guaranteed to be unique while label is not.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listaccounts \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\")\n            + HelpExampleRpc(\"listaccounts \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\"));\n\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    std::string sStateSearch = \"*\";\n\n    CHDSeed* forSeed = NULL;\n    if (request.params.size() > 0 && request.params[0].get_str() != \"*\")\n        forSeed = SeedFromValue(pwallet, request.params[0], true);\n    if (request.params.size() > 1)\n        sStateSearch = request.params[1].get_str();\n    if (sStateSearch.empty())\n        sStateSearch = \"*\";\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    UniValue allAccounts(UniValue::VARR);\n\n    for (const auto& accountPair : pwallet->mapAccounts)\n    {\n        if (sStateSearch != \"*\" && sStateSearch != GetAccountStateString(accountPair.second->m_State))\n            continue;\n\n        if (!accountPair.second->IsHD())\n        {\n            if (!forSeed)\n            {\n                UniValue rec(UniValue::VOBJ);\n                rec.pushKV(\"UUID\", getUUIDAsString(accountPair.first));\n                rec.pushKV(\"label\", accountPair.second->getLabel());\n                rec.pushKV(\"state\", GetAccountStateString(accountPair.second->m_State));\n                rec.pushKV(\"type\", GetAccountTypeString(accountPair.second->m_Type));\n                rec.pushKV(\"HD_type\", \"legacy\");\n                allAccounts.push_back(rec);\n            }\n            continue;\n        }\n        if (accountPair.second->m_State == AccountState::Shadow && !(sStateSearch == \"Shadow\"||sStateSearch == \"ShadowChild\"||sStateSearch == \"*\"))\n            continue;\n        if (forSeed && ((CAccountHD*)accountPair.second)->getSeedUUID() != forSeed->getUUID())\n            continue;\n\n        UniValue rec(UniValue::VOBJ);\n        rec.pushKV(\"UUID\", getUUIDAsString(accountPair.first));\n        rec.pushKV(\"label\", accountPair.second->getLabel());\n        rec.pushKV(\"state\", GetAccountStateString(accountPair.second->m_State));\n        rec.pushKV(\"type\", GetAccountTypeString(accountPair.second->m_Type));\n        rec.pushKV(\"HD_type\", \"HD\");\n        rec.pushKV(\"HDindex\", (uint64_t) dynamic_cast<CAccountHD*>(accountPair.second)->getIndex());\n\n        allAccounts.push_back(rec);\n    }\n\n    return allAccounts;\n}\n\nstatic UniValue getmnemonicfromseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getmnemonicfromseed \\\"seed\\\" \\n\"\n            \"\\nGet the mnemonic of a HD seed.\\n\"\n            \"1. \\\"seed\\\"        (string, required) The unique UUID for the seed that we want mnemonics of, or \\\"\\\" for the active seed.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the mnemonic as a string.\\n\"\n            \"\\nNote it is important to ensure that nobody gets access to this mnemonic or all funds in accounts made from the seed can be compromised.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmnemonicfromseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\")\n            + HelpExampleRpc(\"getmnemonicfromseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\"));\n\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CHDSeed* seed = SeedFromValue(pwallet, request.params[0], true);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    return seed->getMnemonic().c_str();\n}\n\nstatic UniValue getreadonlyseed(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getreadonlyseed \\\"seed\\\" \\n\"\n            \"\\nGet the public key of an HD seed, this can be used to import the seed as a read only seed in another wallet.\\n\"\n            \"1. \\\"seed\\\"        (string, required) The unique UUID for the seed that we want the public key of, or \\\"\\\" for the active seed.\\n\"\n            \"\\nNote the seed must be a 'non hardened' BIP44NH seed and not a regular seed.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the public key as a string.\\n\"\n            \"\\nNote it is important to be careful with and protect access to this public key as if it is compromised it can weaken security in cases where private keys are also compromised.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getreadonlyseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\")\n            + HelpExampleRpc(\"getreadonlyseed \\\"827f0000-0300-0000-0000-000000000000\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CHDSeed* seed = SeedFromValue(pwallet, request.params[0], true);\n\n    if (seed->m_type != CHDSeed::SeedType::BIP44NoHardening)\n        throw std::runtime_error(\"Can only use command with a non-hardened BIP44 seed\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    return seed->getPubkey().c_str();\n}\n\nstatic UniValue listseeds(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"listseeds \\n\"\n            \"\\nReturn the UUID for all wallet seeds.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listseeds\", \"\")\n            + HelpExampleRpc(\"listseeds\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    UniValue AllSeeds(UniValue::VARR);\n\n    for (const auto& seedPair : pwallet->mapSeeds)\n    {\n        UniValue rec(UniValue::VOBJ);\n        rec.pushKV(\"UUID\", getUUIDAsString(seedPair.first));\n        rec.pushKV(\"type\", StringFromSeedType(seedPair.second));\n        if (seedPair.second->IsReadOnly())\n            rec.pushKV(\"readonly\", \"true\");\n        AllSeeds.push_back(rec);\n    }\n\n    return AllSeeds;\n}\n\nstatic UniValue rotatewitnessaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"rotatewitnessaddress \\\"funding_account\\\" \\\"witness_address\\\" \\n\"\n            \"\\nChange the \\\"witnessing key\\\" of a witness account, the wallet needs to be unlocked to do this, the \\\"spending key\\\" will remain unchanged. \\n\"\n            \"1. \\\"funding_account\\\"  (string, required) The unique UUID or label for the account from which money will be removed to pay for the transaction fee.\\n\"\n            \"2. \\\"witness_address\\\"  (string, required) The \" GLOBAL_APPNAME \" address for the witness key.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",   (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n   (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"rotatewitnessaddress \\\"My account\\\" 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\")\n            + HelpExampleRpc(\"rotatewitnessaddress \\\"My account\\\" 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' address.\n    CNativeAddress witnessAddress(request.params[1].get_str());\n    bool isValid = witnessAddress.IsValidWitness(Params());\n\n    if (!isValid)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Not a valid witness address [%s].\", request.params[1].get_str()));\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAddress(witnessAddress);\n    if (unspentWitnessOutputs.size() == 0)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Address does not contain any witness outputs [%s].\", request.params[1].get_str()));\n\n    try {\n        std::string txid;\n        CAmount fee;\n        rotatewitnessaddresshelper(fundingAccount, unspentWitnessOutputs, pwallet, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\n\n                                    \n                    \nstatic UniValue repairwitnessaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"repairwitnessaddress \\\"witness_address\\\" \\n\"\n            \"\\nRepair a witness address if the witness key is only available when wallet is unlocked. Make the witness key always available\\n\"\n            \"1. \\\"witness_address\\\"  (string, required) The \" GLOBAL_APPNAME \" address for the witness key.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"success\\\",    (boolean) True if all keys are present and in correct form, false otherwise.\\n\"\n            \"     \\\"info\\\",       (string)  Information on the error.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"repairwitnessaddress 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\")\n            + HelpExampleRpc(\"repairwitnessaddress 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    UniValue result(UniValue::VOBJ);\n    // NB! Wallet should be locked for this test\n    if (!pwallet->IsCrypted())\n    {\n        result.pushKV(\"success\", false);\n        result.pushKV(\"info\", \"repairwitnessaddress can only be used on encrypted wallets\");\n        return result;\n    }\n    if (pwallet->IsLocked())\n    {\n        result.pushKV(\"success\", false);\n        result.pushKV(\"info\", \"repairwitnessaddress can only be used on unlocked wallets\");\n        return result;\n    }\n\n    // arg1 - 'to' address.\n    CNativeAddress witnessAddress(request.params[0].get_str());\n    bool isValid = witnessAddress.IsValidWitness(Params());\n\n    if (!isValid)\n    {\n        result.pushKV(\"success\", false);\n        result.pushKV(\"info\", \"Not a valid witness address\");\n        return result;\n    }\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAddress(witnessAddress);\n    if (unspentWitnessOutputs.size() == 0)\n    {\n        result.pushKV(\"success\", false);\n        result.pushKV(\"info\", \"Not an active witness address\");\n        return result;\n    }\n\n    // Find the account\n    const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] = unspentWitnessOutputs[0];\n    (unused) currentWitnessHeight;\n    (unused) currentWitnessOutpoint;\n    (unused) currentWitnessTxIndex;\n    CAccount* witnessAccount = pwallet->FindBestWitnessAccountForTransaction(currentWitnessTxOut);\n    if (!witnessAccount)\n    {\n        result.pushKV(\"success\", false);\n        result.pushKV(\"info\", \"Unable to determine account for witness address.\");\n        return result;\n    }\n\n    // Get the current witness details\n    if (currentWitnessTxOut.GetType() != CTxOutType::PoW2WitnessOutput)\n        throw std::runtime_error(\"Cannot extract witness output from legacy script output\");\n    CTxOutPoW2Witness currentWitnessDetails;\n    GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails);\n\n    CPubKey witnessPubKey;\n    if (!witnessAccount->GetPubKey(currentWitnessDetails.witnessKeyID, witnessPubKey))\n    {\n        result.pushKV(\"validity\", true);\n        result.pushKV(\"info\", \"Unable to retrieve public witness key\");\n        return result;\n    }\n    CKey witnessPrivKey;\n    if (!witnessAccount->GetKey(currentWitnessDetails.witnessKeyID, witnessPrivKey))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Unable to generate witness signing key.\");\n        return result;\n    }\n    \n    if (!pwallet->AddKeyPubKey(witnessPrivKey, witnessPrivKey.GetPubKey(), *witnessAccount, KEYCHAIN_WITNESS))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Failed to mark witnessing key for encrypted usage\");\n    }\n\n    result.pushKV(\"validity\", true);\n    result.pushKV(\"info\", \"\");\n    return result;\n}\n\nstatic UniValue verifywitnessaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"verifywitnessaddress \\\"witness_address\\\" \\n\"\n            \"\\nVerify that a witness address is in good working order. Wallet must have both public keys, witness key must be available to sign in an unencrypted form so that wallet can witness while locked.\\n\"\n            \"1. \\\"witness_address\\\"  (string, required) The \" GLOBAL_APPNAME \" address for the witness key.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"validity\\\",   (boolean) True if all keys are present and in correct form, false otherwise.\\n\"\n            \"     \\\"info\\\",       (string)  Information on the error.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"rotatewitnessaddress \\\"My account\\\" 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\")\n            + HelpExampleRpc(\"rotatewitnessaddress \\\"My account\\\" 2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    UniValue result(UniValue::VOBJ);\n    // NB! Wallet should be locked for this test\n    if (!pwallet->IsCrypted())\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"verifywitnessaddress can only be used on encrypted wallets\");\n        return result;\n    }\n    if (!pwallet->IsLocked())\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"verifywitnessaddress can only be used on locked wallets\");\n        return result;\n    }\n\n    // arg1 - 'to' address.\n    CNativeAddress witnessAddress(request.params[0].get_str());\n    bool isValid = witnessAddress.IsValidWitness(Params());\n\n    if (!isValid)\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Not a valid witness address\");\n        return result;\n    }\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAddress(witnessAddress);\n    if (unspentWitnessOutputs.size() == 0)\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Not an active witness address\");\n        return result;\n    }\n\n    // Find the account\n    const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] = unspentWitnessOutputs[0];\n    (unused) currentWitnessHeight;\n    (unused) currentWitnessOutpoint;\n    (unused) currentWitnessTxIndex;\n    CAccount* witnessAccount = pwallet->FindBestWitnessAccountForTransaction(currentWitnessTxOut);\n    if (!witnessAccount)\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Unable to determine account for witness address.\");\n        return result;\n    }\n\n    // Get the current witness details\n    if (currentWitnessTxOut.GetType() != CTxOutType::PoW2WitnessOutput)\n        throw std::runtime_error(\"Cannot extract witness output from legacy script output\");\n    CTxOutPoW2Witness currentWitnessDetails;\n    GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails);\n\n    CPubKey pubKey;\n    if (!witnessAccount->GetPubKey(currentWitnessDetails.witnessKeyID, pubKey))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Unable to retrieve public witness key\");\n        return result;\n    }\n    if (!witnessAccount->GetPubKey(currentWitnessDetails.spendingKeyID, pubKey))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Unable to retrieve public spending key\");\n        return result;\n    }\n\n    CKey privKey;\n    if (!witnessAccount->GetKey(currentWitnessDetails.witnessKeyID, privKey))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Able to retrieve witness signing key; this should not be possible as key should be encrypted.\");\n        return result;\n    }\n    if (witnessAccount->GetKey(currentWitnessDetails.spendingKeyID, privKey))\n    {\n        result.pushKV(\"validity\", false);\n        result.pushKV(\"info\", \"Unable to retrieve spending signing key; key may be incorrectly encrypted.\");\n        return result;\n    }\n\n    result.pushKV(\"validity\", true);\n    result.pushKV(\"info\", \"\");\n    return result;\n}\n\n\nstatic UniValue resetdatadirfull(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() != 0)\n    {\n        throw std::runtime_error(\"resetdatadirfull does not take arguments\\n\");\n    }\n\n    LogPrintf(\"Full datadir wipe requested.\\n\");\n    // Immediately disable what we can so this is cleaner.\n    if (g_connman)\n    {\n        g_connman->SetNetworkActive(false);\n    }\n    witnessingEnabled = false;\n    fullyEraseDatadirOnShutdown=true;\n    \n    // Event loop will exit after current HTTP requests have been handled, so\n    // this reply will get back to the client.\n    LogPrintf(\"shutdown: terminating app for full datadir wipe\");\n    AppLifecycleManager::gApp->shutdown();\n    return \"Stopping application and fully resetting data directory (excluding wallet)\";\n}\n\nstatic UniValue resetdatadirpartial(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() != 0)\n    {\n        throw std::runtime_error(\"resetdatadirpartial does not take arguments\\n\");\n    }\n\n    LogPrintf(\"Partial datadir wipe requested.\\n\");\n    // Immediately disable what we can so this is cleaner.\n    if (g_connman)\n    {\n        g_connman->SetNetworkActive(false);\n    }\n    witnessingEnabled = false;\n    partiallyEraseDatadirOnShutdown=true;\n    \n    LogPrintf(\"shutdown: terminating app for partial datadir wipe\");\n    // Event loop will exit after current HTTP requests have been handled, so\n    // this reply will get back to the client.\n    AppLifecycleManager::gApp->shutdown();\n    return \"Stopping application and partially resetting data directory (excluding wallet)\";\n}\n\nstatic UniValue resetconfig(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() != 0)\n    {\n        throw std::runtime_error(\"resetconfig does not take arguments\\n\");\n    }\n\n    LogPrintf(\"Config wipe requested.\\n\");\n\n    std::vector<std::string> asKeep;    \n    {\n        fs::ifstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n        if (!streamConfig.good())\n            throw std::runtime_error(\"No config file to reset\\n\");\n\n        std::string configLine;\n        while (!streamConfig.eof())\n        {\n            std::getline(streamConfig, configLine);\n            if (boost::starts_with(configLine, \"rpc\") && !boost::starts_with(configLine, \"rpcthreads\"))\n            {\n                asKeep.push_back(configLine);\n            }\n        }\n    }\n    \n    fs::ofstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n    if (!streamConfig.good())\n        throw std::runtime_error(\"No config file to reset\\n\");\n    \n    for (const auto& keepLine : asKeep)\n    {\n        streamConfig << keepLine << \"\\n\";\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue resetconfig_pi_lowmem(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() != 0)\n    {\n        throw std::runtime_error(\"resetconfig_pi_lowmem does not take arguments\\n\");\n    }\n\n    LogPrintf(\"Config wipe requested.\\n\");\n\n    std::vector<std::string> asKeep;    \n    {\n        fs::ifstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n        if (!streamConfig.good())\n            throw std::runtime_error(\"No config file to reset\\n\");\n\n        std::string configLine;\n        while (!streamConfig.eof())\n        {\n            std::getline(streamConfig, configLine);\n            if (boost::starts_with(configLine, \"rpc\") && !boost::starts_with(configLine, \"rpcthreads\"))\n            {\n                asKeep.push_back(configLine);\n            }\n        }\n    }\n    \n    fs::ofstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n    if (!streamConfig.good())\n        throw std::runtime_error(\"No config file to reset\\n\");\n    \n    for (const auto& keepLine : asKeep)\n    {\n        streamConfig << keepLine << \"\\n\";\n    }\n    streamConfig << \"maxconnections=10\\n\";\n    streamConfig << \"maxmempool=50\\n\";\n    streamConfig << \"dbcache=50\\n\";\n    streamConfig << \"rpcthreads=1\\n\";\n    streamConfig << \"par=1\\n\";\n    streamConfig << \"reverseheaders=false\\n\";\n\n    return NullUniValue;\n}\n\nstatic UniValue resetconfig_pi_medmem(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() != 0)\n    {\n        throw std::runtime_error(\"resetconfig_pi_medmem does not take arguments\\n\");\n    }\n\n    LogPrintf(\"Config wipe requested.\\n\");\n\n    std::vector<std::string> asKeep;    \n    {\n        fs::ifstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n        if (!streamConfig.good())\n            throw std::runtime_error(\"No config file to reset\\n\");\n\n        std::string configLine;\n        while (!streamConfig.eof())\n        {\n            std::getline(streamConfig, configLine);\n            if (boost::starts_with(configLine, \"rpc\") && !boost::starts_with(configLine, \"rpcthreads\"))\n            {\n                asKeep.push_back(configLine);\n            }\n        }\n    }\n    \n    fs::ofstream streamConfig(GetConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME)));\n    if (!streamConfig.good())\n        throw std::runtime_error(\"No config file to reset\\n\");\n    \n    for (const auto& keepLine : asKeep)\n    {\n        streamConfig << keepLine << \"\\n\";\n    }\n    streamConfig << \"maxmempool=100\\n\";\n    streamConfig << \"dbcache=200\\n\";\n    streamConfig << \"rpcthreads=1\\n\";\n    streamConfig << \"reverseheaders=false\\n\";\n\n    return NullUniValue;\n}\n\nstatic UniValue getlastblocks(const JSONRPCRequest& request)\n{\n    // NB! Delibritely return no help, we don't want this command to be listed in the help.\n    if (request.fHelp) throw std::runtime_error(\"\");\n    if (request.params.size() > 1)\n    {\n        throw std::runtime_error(\n            \"\\nRenew an expired witness account. \\n\"\n            \"1. \\\"num_blocks\\\"        (optional) How many blocks to go back from the tip; default 30\\n\");\n    }\n\n    uint64_t numBlocks = 30;\n    if (request.params.size() > 0)\n        numBlocks = request.params[0].get_int();\n        \n    LogPrintf(\"getlastblocks requested.\\n\");\n    UniValue result(UniValue::VOBJ);    \n    if ((uint64_t)chainActive.Tip()->nHeight > numBlocks)\n    {\n        CBlockIndex* pIndex = chainActive.Tip();\n        for (uint64_t i=0;i<numBlocks;++i)\n        {\n            result.pushKV(pIndex->GetBlockHashPoW2().ToString(),pIndex->nHeight);\n            pIndex = pIndex->pprev;\n        }\n    }\n    \n    return result;\n}\n\nstatic UniValue rotatewitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"rotatewitnessaccount \\\"funding_account\\\" \\\"witness_account\\\" \\n\"\n            \"\\nChange the \\\"witnessing key\\\" of a witness account, the wallet needs to be unlocked to do this, the \\\"spending key\\\" will remain unchanged. \\n\"\n            \"1. \\\"funding_account\\\"  (string, required) The unique UUID or label for the account from which money will be removed to pay for the transaction fee.\\n\"\n            \"2. \\\"witness_account\\\"  (string, required) The unique UUID or label for the witness account that will hold the locked funds.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\":\\\"txid\\\",   (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\":n   (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"rotatewitnessaddress \\\"My account\\\" \\\"My witness account\\\"\", \"\")\n            + HelpExampleRpc(\"rotatewitnessaddress \\\"My account\\\" \\\"My witness account\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* witnessAccount = AccountFromValue(pwallet, request.params[1], false);\n    if (!witnessAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate witness account [%s].\",  request.params[1].get_str()));\n\n    try {\n        std::string txid;\n        CAmount fee;\n        rotatewitnessaccount(pwallet, fundingAccount, witnessAccount, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n\n}\n\nstatic UniValue renewwitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"renewwitnessaccount \\\"funding_account\\\" \\\"witness_account\\\" \\n\"\n            \"\\nRenew an expired witness account. \\n\"\n            \"1. \\\"funding_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\",                (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\"           (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"renewwitnessaccount \\\"My account\\\" \\\"My witness account\\\"\", \"\")\n            + HelpExampleRpc(\"renewwitnessaccount \\\"My account\\\" \\\"My witness account\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* witnessAccount = AccountFromValue(pwallet, request.params[1], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Cannot split a witness-only account as spend key is required to do this.\");\n    }\n\n    //fixme: (PHASE5) - Share common code with GUI::requestRenewWitness\n    std::string strError;\n    CMutableTransaction tx(CURRENT_TX_VERSION_POW2);\n    CReserveKeyOrScript changeReserveKey(pactiveWallet, fundingAccount, KEYCHAIN_EXTERNAL);\n    CAmount transactionFee;\n    if (!pactiveWallet->PrepareRenewWitnessAccountTransaction(fundingAccount, witnessAccount, changeReserveKey, tx, transactionFee, strError, nullptr, nullptr))\n    {\n        throw std::runtime_error(strprintf(\"Failed to create renew transaction [%s]\", strError.c_str()));\n    }\n\n    \n    uint256 finalTransactionHash;\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        if (!pactiveWallet->SignAndSubmitTransaction(changeReserveKey, tx, strError, &finalTransactionHash, SignType::Spend))\n        {\n            LogPrintf(\"Failed to sign renew transaction [%s]\\n\", strError.c_str());\n            throw std::runtime_error(strprintf(\"Failed to sign renew transaction [%s]\", strError.c_str()));\n        }\n    }\n\n    // Clear the failed flag in UI, and remove the 'renew' button for immediate user feedback.\n    witnessAccount->SetWarningState(AccountStatus::WitnessPending);\n    static_cast<const CExtWallet*>(pactiveWallet)->NotifyAccountWarningChanged(pactiveWallet, witnessAccount);\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(finalTransactionHash.GetHex(), ValueFromAmount(transactionFee));\n    return result;\n}\n\nstatic UniValue splitwitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 3)\n        throw std::runtime_error(\n            \"splitwitnessaccount \\\"funding_account\\\" \\\"witness_account\\\" \\\"amounts\\\" \\n\"\n            \"\\nSplit a witness address into two seperate witness addresses, all details of the addresses remain identical other than a reduction in amounts.\\n\"\n            \"\\nThis is useful in the event that an account has exceeded 1 percent of the network weight. \\n\"\n            \"1. \\\"funding_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"3. \\\"amounts\\\"                (string, required) A json object with amounts for the new addresses\\n\"\n            \"    {\\n\"\n            \"      \\\"amount\\\"              (numeric) The amount that should go in each new account\\n\"\n            \"      ,...\\n\"\n            \"    }\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\",                (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\"           (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"splitwitnessaccount \\\"My account\\\" \\\"My witness account\\\"  \\\"[10000, 5000, 5000]\\\"\", \"\")\n            + HelpExampleRpc(\"splitwitnessaccount \\\"My account\\\" \\\"My witness account\\\"  \\\"[10000, 5000, 5000]\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* witnessAccount = AccountFromValue(pwallet, request.params[1], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[1].get_str()));\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Cannot split a witness-only account as spend key is required to do this.\");\n    }\n\n    // arg3 - 'split' paramaters\n    std::vector<UniValue> splitInto = request.params[2].getValues();\n    if (splitInto.size() < 2)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Split command requires at least two outputs\");\n\n    std::vector<CAmount> splitAmounts;\n    for (const auto& unparsedSplitAmount : splitInto)\n    {\n        CAmount splitValue = AmountFromValue(unparsedSplitAmount);\n        splitAmounts.emplace_back(splitValue);\n    }\n\n    try {\n        std::string txid;\n        CAmount fee;\n        redistributewitnessaccount(pwallet, fundingAccount, witnessAccount, splitAmounts, &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstatic UniValue mergewitnessaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"mergewitnessaccount \\\"funding_account\\\" \\\"witness_account\\\"\\n\"\n            \"\\nMerge multiple witness addresses into a single one.\\n\"\n            \"\\nAddresses must share identical characteristics other than \\\"amount\\\" and therefore this will usually only work on addresses that were created via \\\"splitwitnessaccount\\\".\\n\"\n            \"\\nThis is useful in the event that the network weight has risen significantly and an account that was previously split could now earn better as a single account. \\n\"\n            \"1. \\\"funding_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"txid\\\",                (string) The txid of the created transaction\\n\"\n            \"     \\\"fee_amount\\\"           (number) The fee that was paid.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"mergewitnessaccount \\\"My account\\\" \\\"My witness account\\\"\", \"\")\n            + HelpExampleRpc(\"mergewitnessaccount \\\"My account\\\" \\\"My witness account\\\"\", \"\"));\n\n    // Basic sanity checks.\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // arg1 - 'from' account.\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    // arg2 - 'to' account.\n    CAccount* witnessAccount = AccountFromValue(pwallet, request.params[1], false);\n    if (!fundingAccount)\n        throw std::runtime_error(strprintf(\"Unable to locate funding account [%s].\",  request.params[0].get_str()));\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Cannot split a witness-only account as spend key is required to do this.\");\n    }\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(witnessAccount);\n    if (unspentWitnessOutputs.size() == 0)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Account does not contain any witness outputs [%s].\", request.params[1].get_str()));\n\n    if (unspentWitnessOutputs.size() == 1)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Account only contains one witness output at least two are required to merge [%s].\", request.params[1].get_str()));\n\n    CAmount totalAmount = std::accumulate(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), CAmount(0), [](const CAmount acc, const auto& it){\n        const CTxOut& txOut = std::get<0>(it);\n        return acc + txOut.nValue;\n    });\n\n    try {\n        std::string txid;\n        CAmount fee;\n        redistributewitnessaccount(pwallet, fundingAccount, witnessAccount, std::vector({totalAmount}), &txid, &fee);\n        UniValue result(UniValue::VOBJ);\n        result.pushKV(\"txid\", txid);\n        result.pushKV(\"fee_amount\", ValueFromAmount(fee));\n        return result;\n    }\n    catch (witness_error& e) {\n        throw JSONRPCError(e.code(), e.what());\n    }\n    catch (std::runtime_error& e) {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstatic UniValue setwitnesscompound(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"setwitnesscompound \\\"witness_account\\\" \\\"amount\\\"\\n\"\n            \"\\nSet whether a witness account should compound or not.\\n\"\n            \"\\nCompounding is controlled as follows:\\n\"\n            \"\\n    1) When set to 0 no compounding will be done, all rewards will be sent to the non-compound output set by \\\"setwitnessgeneration\\\" or a key in the account if \\\"setwitnessgeneration\\\" has not been called.\\n\"\n            \"\\n    2) When set to a positive number \\\"n\\\", earnings up until \\\"n\\\" will be compounded, and the remainder will be sent to the non-compound output (as describe in 1).\\n\"\n            \"\\n    3) When set to a negative number \\\"n\\\", \\\"n\\\" will be deducted and sent to a non-compound output (as described in 1) and the remainder will be compounded.\\n\"\n            \"\\nIn all cases it is important to remember the following:\\n\"\n            \"\\n    4) Transaction fees and not just the witness reward can be compounded, so compounding amount should be set considering possible transaction fees as well and not just the block reward.\\n\"\n            \"\\n    5) A maximum of \" GLOBAL_MAXIMUM_WITNESS_COMPOUND \" \" GLOBAL_COIN_CODE \" can be compounded, regardless of whether a block contains more fees. In the event that there are additional fees to distribute after applying the compounding settings, the settings will be ignored for the additional fees and paid to a non-compound output (as described in 1)\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"witness_account\\\"            (string) The UUID or unique label of the account.\\n\"\n            \"2. amount                        (numeric or string, required) The amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"account_uuid\\\",            (string) The UUID of the account that has been modified.\\n\"\n            \"     \\\"amount\\\"                   (string) The amount that has been set.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setwitnesscompound \\\"My witness account\\\" 5\", \"\")\n            + HelpExampleRpc(\"setwitnesscompound \\\"My witness account\\\" 10\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    CAmount amount = AmountFromValue(request.params[1], true);\n\n    CWalletDB walletdb(*pwallet->dbw);\n    forAccount->setCompounding(amount, &walletdb);\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(getUUIDAsString(forAccount->getUUID()), ValueFromAmount(forAccount->getCompounding()));\n    return result;\n}\n\nstatic UniValue getwitnesscompound(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getwitnesscompound \\\"witness_account\\\"\\n\"\n            \"\\nGet the current compound setting for an account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"witness_account\\\"        (string) The UUID or unique label of the account.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the current amount set for the account.\\n\"\n            \"\\nCompounding is controlled as follows:\\n\"\n            \"\\n    1) When set to 0 no compounding will be done, all rewards will be sent to the non-compound output set by \\\"setwitnessgeneration\\\" or a key in the account if \\\"setwitnessgeneration\\\" has not been called.\\n\"\n            \"\\n    2) When set to a positive number \\\"n\\\", earnings up until \\\"n\\\" will be compounded, and the remainder will be sent to the non-compound output (as describe in 1).\\n\"\n            \"\\n    3) When set to a negative number \\\"n\\\", \\\"n\\\" will be deducted and sent to a non-compound output (as described in 1) and the remainder will be compounded.\\n\"\n            \"\\nIn all cases it is important to remember the following:\\n\"\n            \"\\n    4) Transaction fees and not just the witness reward can be compounded, so while the witness reward is 20 \" GLOBAL_COIN_CODE \" compounding amount should be set considering possible transaction fees as well.\\n\"\n            \"\\n    5) A maximum of 40 \" GLOBAL_COIN_CODE \" can be compounded, regardless of whether a block contains more fees. In the event that there are additional fees to distribute after applying the compounding settings, the settings will be ignored for the additional fees and paid to a non-compound output (as described in 1)\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getwitnesscompound \\\"My witness account\\\"\", \"\")\n            + HelpExampleRpc(\"getwitnesscompound \\\"My witness account\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    return ValueFromAmount(forAccount->getCompounding());\n}\n\nstatic UniValue setwitnessrewardaddress(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2 )\n        throw std::runtime_error(\n            \"setwitnessrewardaddress \\\"witness_account\\\" \\\"destination\\\"\\n\"\n            \"\\nSet the output address into which all non-compound witness earnings will be paid.\\n\"\n            \"\\nSee \\\"setwitnesscompound\\\" for how to control compounding and additional information.\\n\"\n            \"1. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"destination\\\"           (required) An address. Set empty string to reset the reward script.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"account_uuid\\\",        (string) The UUID of the account that has been modified.\\n\"\n            \"     \\\"amount\\\"               (string) The amount that has been set.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setwitnessrewardscript \\\"my witness account\\\" \\\"Vb5YMjiTA9BUYi9zPToKg3wAAdrpHNp1V2hSBVHpgLMm9sPojhnX\\\"\", \"\")\n            + HelpExampleRpc(\"setwitnessrewardscript \\\"my witness account\\\" \\\"Vb5YMjiTA9BUYi9zPToKg3wAAdrpHNp1V2hSBVHpgLMm9sPojhnX\\\"\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    CScript scriptForNonCompoundPayments;\n    CNativeAddress address(request.params[1].get_str());\n    if (address.IsValid()) {\n        scriptForNonCompoundPayments = GetScriptForDestination(address.Get());\n    }\n\n    CWalletDB walletdb(*pwallet->dbw);\n    forAccount->setNonCompoundRewardScript(scriptForNonCompoundPayments, &walletdb);\n\n    witnessScriptsAreDirty = true;\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(getUUIDAsString(forAccount->getUUID()), HexStr(forAccount->getNonCompoundRewardScript()));\n    return result;\n}\n\nstatic UniValue setwitnessrewardscript(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 3 )\n        throw std::runtime_error(\n            \"setwitnessrewardscript \\\"witness_account\\\" \\\"destination\\\" force_pubkey \\n\"\n            \"\\nSet the output key into which all non-compound witness earnings will be paid.\\n\"\n            \"\\nSee \\\"setwitnesscompound\\\" for how to control compounding and additional information.\\n\"\n            \"1. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"destination\\\"           (required) An address or hex encoded script or public key. Set empty string to reset the reward script.\\n\"\n            \"3. force_pubkey              (boolean, optional, default=false) Cause command to fail if an invalid pubkey is passed, without this the pubkey may be imported as a script.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"account_uuid\\\",        (string) The UUID of the account that has been modified.\\n\"\n            \"     \\\"amount\\\"               (string) The amount that has been set.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setwitnessrewardscript \\\"my witness account\\\" \\\"Vb5YMjiTA9BUYi9zPToKg3wAAdrpHNp1V2hSBVHpgLMm9sPojhnX\\\"\", \"\")\n            + HelpExampleRpc(\"setwitnessrewardscript \\\"my witness account\\\" \\\"Vb5YMjiTA9BUYi9zPToKg3wAAdrpHNp1V2hSBVHpgLMm9sPojhnX\\\"\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n\n    bool forcePubKey = false;\n    if (request.params.size() > 2)\n        forcePubKey = request.params[2].get_bool();\n\n    std::string pubKeyOrScript = request.params[1].get_str();\n\n    CScript scriptForNonCompoundPayments;\n\n    CNativeAddress address(pubKeyOrScript);\n    if (address.IsValid()) {\n        scriptForNonCompoundPayments = GetScriptForDestination(address.Get());\n    }\n    else if (!pubKeyOrScript.empty()) {\n        if (!IsHex(pubKeyOrScript))\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Data is neither hex encoded nor a valid address\");\n\n        // Try public key first.\n        std::vector<unsigned char> data(ParseHex(pubKeyOrScript));\n        CPubKey pubKey(data.begin(), data.end());\n        if (pubKey.IsFullyValid())\n        {\n            scriptForNonCompoundPayments = CScript() << ToByteVector(pubKey) << OP_CHECKSIG;\n        }\n        else\n        {\n            if (forcePubKey)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Not a valid hex encoded public key\");\n\n            // Not a public key so treat it as a script.\n            scriptForNonCompoundPayments = CScript(data.begin(), data.end());\n            if (!scriptForNonCompoundPayments.HasValidOps())\n            {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Data is hex encoded, but not a valid pubkey or script\");\n            }\n        }\n    }\n\n    CWalletDB walletdb(*pwallet->dbw);\n    forAccount->setNonCompoundRewardScript(scriptForNonCompoundPayments, &walletdb);\n\n    witnessScriptsAreDirty = true;\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(getUUIDAsString(forAccount->getUUID()), HexStr(forAccount->getNonCompoundRewardScript()));\n    return result;\n}\n\nstatic UniValue getwitnessrewardscript(const JSONRPCRequest& request)\n{\n     #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getwitnessrewardscript \\\"witness_account\\\" \\n\"\n            \"\\nGet the output key into which all non-compound witness earnings will be paid.\\n\"\n            \"\\nSee \\\"getwitnesscompound\\\" for how to control compounding and additional information.\\n\"\n            \"1. \\\"witness_account\\\"    (required) The unique UUID or label for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"     \\\"account_uuid\\\",    (string) The UUID of the account that has been modified.\\n\"\n            \"     \\\"hex_script\\\"       (string) Hex encoded script that has been set.\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"setwitnessrewardscript \\\"my witness account\\\"\", \"\")\n            + HelpExampleRpc(\"setwitnessrewardscript \\\"my witness account\\\"\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    UniValue result(UniValue::VOBJ);\n    if (!forAccount->hasNonCompoundRewardScript())\n    {\n        result.pushKV(getUUIDAsString(forAccount->getUUID()), \"\");\n    }\n    else\n    {\n        result.pushKV(getUUIDAsString(forAccount->getUUID()), HexStr(forAccount->getNonCompoundRewardScript()));\n    }\n    return result;\n}\n\nstatic UniValue setwitnessrewardtemplate(const JSONRPCRequest& request)\n{\n#ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n#else\n    LOCK(cs_main);\n#endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"setwitnessrewardtemplate \\\"witness_account\\\" [[\\\"destination1\\\" (,\\\"amount\\\") (,\\\"percentage%\\\") (,\\\"remainder\\\") (,\\\"compound_overflow\\\")], [\\\"destination2\\\" ...], ...]\\n\"\n            \"\\nSet the template to control where witness earnings are paid. Multiple destinations can be specified, compounding or not each receiving a fixed\\n\"\n            \"amount and/or a percentage of the witness amounts earned.\\n\"\n            \"1. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"2. \\\"destinationX\\\"           (required) an address or one of the special keywords, \\\"account\\\" or \\\"compound\\\"\\n\"\n            \"                                         \\\"compound\\\", compounds back into \\\"witness_account\\\"\\n\"\n            \"                                         \\\"account\\\" pays out to \\\"witness_account\\\" without compounding (ie. spendable payout)\\n\"\n            \"3. amount                     (string, optional) Fixed amount for this destination.\\n\"\n            \"4. percentage                 (string, optional) Percentage of remaining non-fixed amount for this destination (postfixed with % symbol).\\n\"\n            \"4. remainder                  (string, optional) The remainder marked destination receives any amount still remaining after distributing fixed and percentage amounts.\\n\"\n            \"5. compound_overflow          (string, optional) The compound_overflow marked destination receives any excess compound.\\n\"\n            \"\\nResult:\\n\"\n            \"(string) The UUID of the account that has been modified.\\n\"\n            \"\\nRemarks:\\n\"\n            \"If a reward template is set on the account it overrides the witness-compound setting (see \\\"setwitnesscompound\\\").\\n\"\n            \"For each entry the destination has to be the first element. The order of the following elements is arbitrary. When multiple entries have remainder, compound or compound_overflow set \"\n            \"behaviour is undefined (only one can receive the remainder). When using percentages it is recommended to also use a remainder, instead of giving multiple \"\n            \"entries that total 100%. Because percentages are floating point specifying a total of 100% can lead to rounding errors and over specification.\\n\"\n            \"If a reward script is set (see \\\"setwitnessrewardscript\\\") that is used as the \\\"account\\\" destination.\\n\"\n            \"When resulting compound exceeds the allowed amount without a \\\"compound_overflow\\\" in the template, the overflow will go to the remainder (which cannot be on the \\\"compound\\\" destination in this case).\\n\"\n            \"\\nDistribution of rewards:\\n\"\n            \"1. All fixed amounts are distributed (including compound)\\n\"\n            \"2. Percentages of the remaining amount are distributed.\\n\"\n            \"3. Any remaining amount goes to the remainder destination.\\n\"\n            \"4. If the compound amount resulting from above calculation exceeds the maximum allowed compound amount, then the maximum will be compounded and any excess amount will go to compound_overflow.\\n\"\n            \"\\nExamples:\\n\"\n            \"Assuming there is 90 \" GLOBAL_COIN_CODE \" witness reward to divide, then in the example below the fixed amount to divide is 40 (10 + 30), leaving 50 for percentage splits. Only 40% (20 \" GLOBAL_COIN_CODE \") is specified (5% + 5% + 30%), leaving 30 \" GLOBAL_COIN_CODE \" as remainder.\\n\"\n            \"So the distribution is: 2.5 \" GLOBAL_COIN_CODE \" to TRVQzTaFGt1cQcDdgAJGwnzFfFgUbR1PnF, 40 non-compounding to the witness account, 2.5 \" GLOBAL_COIN_CODE \" to TBb5KJ3jnq7Xk5uwWV7dAyRmSEgfvszevo (compound overflow = 0) and 45 is compounded into the witness.\\n\"\n            + HelpExampleCli(\"setwitnessrewardtemplate \\\"my witness account\\\" '[[\\\"TRVQzTaFGt1cQcDdgAJGwnzFfFgUbR1PnF\\\", \\\"5%\\\"], [\\\"account\\\", \\\"10\\\", \\\"remainder\\\"],[\\\"TBb5KJ3jnq7Xk5uwWV7dAyRmSEgfvszevo\\\", \\\"5%\\\", \\\"compound_overflow\\\"], [\\\"compound\\\", \\\"30\\\", \\\"30%\\\"]]'\", \"\")\n            + HelpExampleRpc(\"setwitnessrewardtemplate \\\"my witness account\\\" '[[\\\"TRVQzTaFGt1cQcDdgAJGwnzFfFgUbR1PnF\\\", \\\"5%\\\"], [\\\"account\\\", \\\"10\\\", \\\"remainder\\\"],[\\\"TBb5KJ3jnq7Xk5uwWV7dAyRmSEgfvszevo\\\", \\\"5%\\\", \\\"compound_overflow\\\"], [\\\"compound\\\", \\\"30\\\", \\\"30%\\\"]]'\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    const std::vector<UniValue>& destinations = request.params[1].get_array().getValues();\n\n    CWitnessRewardTemplate rewardTemplate;\n\n    for (const UniValue& dst: destinations) {\n        const std::vector<UniValue>& dstArr = dst.get_array().getValues();\n        if (dstArr.size() < 2)\n            throw JSONRPCError(RPC_INVALID_PARAMS, \"Need destination and at least one quantity specifier\");\n\n        CWitnessRewardDestination rewardDestination;\n\n        std::string destSpec = dstArr[0].getValStr();\n        if (destSpec == \"compound\") {\n            rewardDestination.type = CWitnessRewardDestination::DestType::Compound;\n        }\n        else if (destSpec == \"account\") {\n            rewardDestination.type = CWitnessRewardDestination::DestType::Account;\n        }\n        else {\n            rewardDestination.type = CWitnessRewardDestination::DestType::Address;\n            rewardDestination.address = CNativeAddress(destSpec);\n        }\n\n        for (auto it = ++dstArr.begin(); it != dstArr.end(); it++) {\n            std::string qtySpec = it->getValStr();\n            if (qtySpec == \"remainder\") {\n                rewardDestination.takesRemainder = true;\n            }\n            else if (qtySpec == \"compound_overflow\") {\n                rewardDestination.takesCompoundOverflow = true;\n            }\n            else if (qtySpec.size() > 0 && qtySpec[qtySpec.size() - 1] == '%') {\n                rewardDestination.percent = std::stod(qtySpec.substr(0, qtySpec.size() - 1)) / 100.0;\n            }\n            else {\n                rewardDestination.amount = AmountFromValue(*it);\n            }\n        }\n\n        rewardTemplate.destinations.push_back(rewardDestination);\n    }\n\n    rewardTemplate.validate(GetBlockSubsidy(chainActive.Height()).witness);\n\n    CWalletDB walletdb(*pwallet->dbw);\n    forAccount->setRewardTemplate(rewardTemplate, &walletdb);\n\n    UniValue result(getUUIDAsString(forAccount->getUUID()));\n    return result;\n}\n\nstatic UniValue getwitnessrewardtemplate(const JSONRPCRequest& request)\n{\n#ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n#else\n    LOCK(cs_main);\n#endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getwitnessrewardtemplate \\\"witness_account\\\" \\n\"\n            \"\\nGet the template how witness earnings will be paid..\\n\"\n            \"\\nSee \\\"setwitnessrewardtemplate\\\" for additional information.\\n\"\n            \"1. \\\"witness_account\\\"    (required) The unique UUID or label for the account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getwitnessrewardtemplate \\\"my witness account\\\"\", \"\")\n            + HelpExampleRpc(\"getwitnessrewardtemplate \\\"my witness account\\\"\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(strprintf(\"Specified account is not a witness account [%s].\",  request.params[0].get_str()));\n\n    UniValue result(UniValue::VOBJ);\n    if (!forAccount->hasRewardTemplate())\n    {\n        result.pushKV(getUUIDAsString(forAccount->getUUID()), \"\");\n    }\n    else\n    {\n        CWitnessRewardTemplate rewardTemplate = forAccount->getRewardTemplate();\n        UniValue templateArray(UniValue::VARR);\n        for (const CWitnessRewardDestination& dest: rewardTemplate.destinations) {\n            UniValue destArray(UniValue::VARR);\n            std::string destStr;\n\n            switch (dest.type) {\n            case CWitnessRewardDestination::DestType::Address:\n                destStr = dest.address.ToString();\n                break;\n            case CWitnessRewardDestination::DestType::Compound:\n                destStr = \"compound\";\n                break;\n            case CWitnessRewardDestination::DestType::Account:\n                destStr = \"account\";\n                break;\n            }\n            destArray.push_back(destStr);\n\n            if (dest.amount > 0)\n                destArray.push_back(ValueFromAmount(dest.amount));\n\n            if (dest.percent > 0.0)\n                destArray.push_back(strprintf(\"%.2f%%\", 100.0 * dest.percent));\n\n            if (dest.takesRemainder)\n                destArray.push_back(\"remainder\");\n\n            if (dest.takesCompoundOverflow)\n                destArray.push_back(\"compound_overflow\");\n\n            templateArray.push_back(destArray);\n        }\n\n        result.pushKV(getUUIDAsString(forAccount->getUUID()), templateArray);\n    }\n    return result;\n}\n\nstatic UniValue getwitnessaccountkeys(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getwitnessaccountkeys \\\"witness_account\\\" \\n\"\n            \"\\nGet the witness keys of an HD account, this can be used to import the account as a witness only account in another wallet via the \\\"importwitnesskeys\\\" command.\\n\"\n            \"\\nA single account can theoretically contain multiple keys, if it has been split \\\"splitwitnessaccount\\\", this will include all of them \\n\"\n            \"1. \\\"witness_account\\\"        (required) The unique UUID or label for the account.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the private witness keys as an encoded string, that can be used with the \\\"importwitnesskeys\\\" command.\\n\"\n            \"\\nNB! The exported private key is only the \\\"witnessing\\\" key and not the \\\"spending\\\" key for the witness account.\\n\"\n            \"\\nIf the \\\"witness\\\" key is compromised your funds will remain completely safe however the attacker will be able to use the key to claim your earnings.\\n\"\n            \"\\nIf you believe your key is or may have been compromised use \\\"rotatewitnessaccount\\\" to rotate to a new witness key.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getwitnessaccountkeys \\\"My witness account\\\"\", \"\")\n            + HelpExampleRpc(\"getwitnessaccountkeys \\\"My witness account\\\"\", \"\"));\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[0], false);\n\n    if (!forAccount)\n        throw std::runtime_error(\"Invalid account name or UUID\");\n\n    if (!forAccount->IsPoW2Witness())\n        throw std::runtime_error(\"Can only be used on a witness account.\");\n\n    if (!chainActive.Tip())\n        throw std::runtime_error(\"Wait for chain to synchronise before using command.\");\n\n    if (!IsPow2WitnessingActive(chainActive.Tip()->nHeight))\n        throw std::runtime_error(\"Wait for witnessing to activate before using this command.\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::map<COutPoint, Coin> allWitnessCoins;\n    if (!getAllUnspentWitnessCoins(chainActive, Params(), chainActive.Tip(), allWitnessCoins))\n        throw std::runtime_error(\"Failed to enumerate all witness coins.\");\n\n    std::string linkUrl = witnessKeysLinkUrlForAccount(pwallet, forAccount);\n\n    if (linkUrl.empty())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Witness account has no active keys.\");\n\n    return linkUrl;\n}\n\nstatic UniValue getwitnessaddresskeys(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getwitnessaddresskeys \\\"witness_address\\\" \\n\"\n            \"\\nGet the witness key of an HD address, this can be used to import the account as a witness only account in another wallet via the \\\"importwitnesskeys\\\" command.\\n\"\n            \"1. \\\"witness_address\\\"        (required) The \" GLOBAL_APPNAME \" address for the witness key.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the private witness key as an encoded string, that can be used with the \\\"importwitnesskeys\\\" command.\\n\"\n            \"\\nNB! The exported private key is only the \\\"witnessing\\\" key and not the \\\"spending\\\" key for the witness account.\\n\"\n            \"\\nIf the \\\"witness\\\" key is compromised your funds will remain completely safe however the attacker will be able to use the key to claim your earnings.\\n\"\n            \"\\nIf you believe your key is or may have been compromised use \\\"rotatewitnessaccount\\\" to rotate to a new witness key.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getwitnessaddresskeys \\\"2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\\\"\", \"\")\n            + HelpExampleRpc(\"getwitnessaddresskeys \\\"2ZnFwkJyYeEftAoQDe7PC96t2Y7XMmKdNtekRdtx32GNQRJztULieFRFwQoQqN\\\"\", \"\"));\n\n    CNativeAddress forAddress(request.params[0].get_str());\n    bool isValid = forAddress.IsValidWitness(Params());\n\n    if (!isValid)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Not a valid witness address.\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::string witnessAccountKeys = \"\";\n    for (const auto& [accountUUID, forAccount] : pwallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        CPoW2WitnessDestination dest = boost::get<CPoW2WitnessDestination>(forAddress.Get());\n        if (forAccount->HaveKey(dest.witnessKey))\n        {\n            CKey witnessPrivKey;\n            if (!forAccount->GetKey(dest.witnessKey, witnessPrivKey))\n            {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Unable to retrieve key for witness address.\");\n            }\n            //fixme: (PHASE5) - to be 100% correct we should export the creation time of the actual key (where available) and not getEarliestPossibleCreationTime - however getEarliestPossibleCreationTime will do for now.\n            witnessAccountKeys += CEncodedSecretKey(witnessPrivKey).ToString() + strprintf(\"#%s\", forAccount->getEarliestPossibleCreationTime());\n            break;\n        }\n    }\n    if (witnessAccountKeys.empty())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Witness account has no active keys.\");\n\n    // FIXME: only unique keys in here using the earliest time for each (so need to introduce a map for this)\n    witnessAccountKeys = GLOBAL_APP_URIPREFIX\"://witnesskeys?keys=\" + witnessAccountKeys;\n    return witnessAccountKeys;\n}\n\nstatic UniValue importwitnesskeys(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"importwitnesskeys \\\"account_name\\\" \\\"encoded_key_url\\\" \\\"create_account\\\" \\n\"\n            \"\\nAdd keys imported from an \\\"encoded_key_url\\\" which has been obtained by using \\\"getwitnessaddresskeys\\\" or \\\"getwitnessaccountkeys\\\" \\n\"\n            \"\\nUses an existing account if \\\"create_account\\\" is false, otherwise creates a new one. \\n\"\n            \"1. \\\"account_name\\\"            (string) name/label of the new account.\\n\"\n            \"2. \\\"encoded_key_url\\\"         (string) Encoded string containing the extended public key for the account.\\n\"\n            \"3. \\\"create_account\\\"          (boolean, optional, default=false) Encoded string containing the extended public key for the account.\\n\"\n            \"4. \\\"rescan\\\"                  (boolean, optional, default=true) Perform a rescan for account transactions.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn the UUID of account.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"importwitnesskeys \\\"my witness account\\\" \\\"\" GLOBAL_APP_URIPREFIX \"://witnesskeys?keys=Vd69eLAZ2r76C47xB3pDLa9Fx4Li8Xt5AHgzjJDuLbkP8eqUjToC#1529049773\\\"\", \"\")\n            + HelpExampleRpc(\"importwitnesskeys \\\"my witness account\\\" \\\"\" GLOBAL_APP_URIPREFIX \"://witnesskeys?keys=Vd69eLAZ2r76C47xB3pDLa9Fx4Li8Xt5AHgzjJDuLbkP8eqUjToC#1529049773\\\"\", \"\"));\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    bool shouldCreateAccount = false;\n    if (request.params.size() > 2)\n        shouldCreateAccount = request.params[2].get_bool();\n    \n    bool shouldRescan = true;\n    if (request.params.size() > 3)\n        shouldRescan = request.params[3].get_bool();\n\n    const auto& keysAndBirthDates = pwallet->ParseWitnessKeyURL(request.params[1].get_str().c_str());\n    if (keysAndBirthDates.empty())\n        throw std::runtime_error(\"Invalid encoded key URL\");\n\n    CAccount* account = nullptr;\n    if (!shouldCreateAccount)\n    {\n        account = AccountFromValue(pwallet, request.params[0], false);\n        if (!account)\n            throw std::runtime_error(\"Invalid account name or UUID\");\n        if (account->m_Type != WitnessOnlyWitnessAccount)\n            throw std::runtime_error(\"Account is not a witness-only account\");\n\n        if (!pwallet->ImportKeysIntoWitnessOnlyWitnessAccount(account, keysAndBirthDates, shouldRescan))\n            throw std::runtime_error(\"Failed to import keys into account\");\n    }\n    else\n    {\n        std::string requestedAccountName = request.params[0].get_str();\n        account = pwallet->CreateWitnessOnlyWitnessAccount(requestedAccountName, keysAndBirthDates, shouldRescan);\n        if (!account)\n            throw std::runtime_error(\"Failed to create witness-only witness account\");\n    }\n\n    //NB! No need to trigger a rescan CreateWitnessOnlyWitnessAccount already did this.\n\n    return getUUIDAsString(account->getUUID());\n}\n\n\nstatic const CRPCCommand commandsFull[] =\n{ //  category                   name                               actor (function)                 okSafeMode\n  //  ---------------------      ------------------------           -----------------------          ----------\n    { \"generating\",              \"gethashps\",                       &gethashps,                      true,    {} },\n    { \"generating\",              \"sethashlimit\",                    &sethashlimit,                   true,    {\"limit\"} },\n    { \"generating\",              \"createminingaccount\",             &createminingaccount,            true,    {\"name\"} },\n    { \"generating\",              \"setminingrewardaddress\",          &setminingrewardaddress,         true,    {\"reward_address\"} },\n    { \"generating\",              \"getminingrewardaddress\",          &getminingrewardaddress,         true,    {\"\"} },\n\n    //fixme: (PHASE5) Many of these belong in accounts category as well.\n    //We should consider allowing multiple categories for commands, so its easier for people to discover commands under specific topics they are interested in.\n    { \"witness\",                 \"createwitnessaccount\",            &createwitnessaccount,           true,    {\"name\"} },\n    { \"witness\",                 \"calculatewitnessweight\",          &calculatewitnessweight,         true,    { \"amount\", \"time\" } },\n    { \"witness\",                 \"extendwitnessaccount\",            &extendwitnessaccount,           true,    {\"funding_account\", \"witness_account\", \"amount\", \"time\" } },\n    { \"witness\",                 \"extendwitnessaddress\",            &extendwitnessaddress,           true,    {\"funding_account\", \"witness_address\", \"amount\", \"time\" } },\n    { \"witness\",                 \"fundwitnessaccount\",              &fundwitnessaccount,             true,    {\"funding_account\", \"witness_account\", \"amount\", \"time\", \"force_multiple\" } },\n    { \"witness\",                 \"getwitnessaccountkeys\",           &getwitnessaccountkeys,          true,    {\"witness_account\"} },\n    { \"witness\",                 \"getwitnessaddresskeys\",           &getwitnessaddresskeys,          true,    {\"witness_address\"} },\n    { \"witness\",                 \"getwitnesscompound\",              &getwitnesscompound,             true,    {\"witness_account\"} },\n    { \"witness\",                 \"getwitnessinfo\",                  &getwitnessinfo,                 true,    {\"block_specifier\", \"verbose\", \"mine_only\"} },\n    { \"witness\",                 \"getwitnessutxo\",                  &getwitnessutxo,                 true,    {\"block_specifier\"} },\n    { \"witness\",                 \"getwitnessrewardscript\",          &getwitnessrewardscript,         true,    {\"witness_account\"} },\n    { \"witness\",                 \"importwitnesskeys\",               &importwitnesskeys,              true,    {\"account_name\", \"encoded_key_url\", \"create_account\"} },\n    { \"witness\",                 \"mergewitnessaccount\",             &mergewitnessaccount,            true,    {\"funding_account\", \"witness_account\"} },\n    { \"witness\",                 \"rotatewitnessaddress\",            &rotatewitnessaddress,           true,    {\"funding_account\", \"witness_address\"} },\n    { \"witness\",                 \"rotatewitnessaccount\",            &rotatewitnessaccount,           true,    {\"funding_account\", \"witness_account\"} },\n    { \"witness\",                 \"renewwitnessaccount\",             &renewwitnessaccount,            true,    {\"funding_account\", \"witness_account\"} },\n    { \"witness\",                 \"setwitnesscompound\",              &setwitnesscompound,             true,    {\"witness_account\", \"amount\"} },\n    { \"witness\",                 \"setwitnessrewardscript\",          &setwitnessrewardscript,         true,    {\"witness_account\", \"pubkey_or_script\", \"force_pubkey\"} },\n    { \"witness\",                 \"setwitnessrewardaddress\",         &setwitnessrewardaddress,         true,   {\"witness_account\", \"pubkey_or_script\"} },\n    { \"witness\",                 \"setwitnessrewardtemplate\",        &setwitnessrewardtemplate,       true,    {\"witness_account\", \"reward_template\"} },\n    { \"witness\",                 \"getwitnessrewardtemplate\",        &getwitnessrewardtemplate,       true,    {\"witness_account\" } },\n    { \"witness\",                 \"splitwitnessaccount\",             &splitwitnessaccount,            true,    {\"funding_account\", \"witness_account\", \"amounts\"} },\n    { \"witness\",                 \"enablewitnessing\",                &enablewitnessing,               true,    {} },\n    { \"witness\",                 \"disablewitnessing\",               &disablewitnessing,              true,    {} },\n    { \"witness\",                 \"repairwitnessaddress\",            &repairwitnessaddress,           true,    {\"witness_address\" } },\n    \n\n    { \"developer\",               \"dumpblockgaps\",                   &dumpblockgaps,                  true,    {\"start_height\", \"count\"} },\n    { \"developer\",               \"dumpfiltercheckpoints\",           &dumpfiltercheckpoints,          true,    {} },\n    { \"developer\",               \"dumptransactionstats\",            &dumptransactionstats,           true,    {\"start_height\", \"count\"} },\n    { \"developer\",               \"dumpdiffarray\",                   &dumpdiffarray,                  true,    {\"height\"} },\n    { \"developer\",               \"verifywitnessaddress\",            &verifywitnessaddress,           true,    {\"witness_address\" } },\n    \n    { \"accounts\",                \"createaccount\",                   &createaccount,                  true,    {\"name\", \"type\"} },\n    { \"accounts\",                \"deleteaccount\",                   &deleteaccount,                  true,    {\"account\", \"force\"} },\n    { \"accounts\",                \"restoreaccount\",                  &restoreaccount,                 true,    {\"account\"} },\n    { \"accounts\",                \"getreadonlyaccount\",              &getreadonlyaccount,             true,    {\"account\"} },\n    { \"accounts\",                \"importreadonlyaccount\",           &importreadonlyaccount,          true,    {\"name\", \"encoded_key\"} },\n    { \"accounts\",                \"getlinkedaccount\",                &getlinkedaccount,               true,    {\"account\"} },\n    { \"accounts\",                \"importlinkedaccount\",             &importlinkedaccount,            true,    {\"name\", \"encoded_key_uri\"} },\n    { \"accounts\",                \"setactiveaccount\",                &setactiveaccount,               true,    {\"account\"} },\n\n    { \"mnemonics\",               \"createseed\",                      &createseed,                     true,    {\"type\"} },\n    { \"mnemonics\",               \"deleteseed\",                      &deleteseed,                     true,    {\"seed\", \"should_purge_accounts\"} },\n    { \"mnemonics\",               \"getreadonlyseed\",                 &getreadonlyseed,                true,    {\"seed\"} },\n    { \"mnemonics\",               \"setactiveseed\",                   &setactiveseed,                  true,    {\"seed\"} },\n    { \"mnemonics\",               \"importseed\",                      &importseed,                     true,    {\"mnemonic_or_pubkey\", \"type\", \"is_read_only\"} },\n};\n\nstatic const CRPCCommand commandsSPV[] =\n{ //  category                   name                               actor (function)                 okSafeMode\n  //  ---------------------      ------------------------           -----------------------          ----------\n    \n    { \"support\",                 \"resetdatadirpartial\",             &resetdatadirpartial,            true,    {\"\"} },\n    { \"support\",                 \"resetdatadirfull\",                &resetdatadirfull,               true,    {\"\"} },\n    { \"support\",                 \"resetconfig\",                     &resetconfig,                    true,    {\"\"} },\n    { \"support\",                 \"resetconfig_pi_lowmem\",           &resetconfig_pi_lowmem,          true,    {\"\"} },\n    { \"support\",                 \"resetconfig_pi_medmem\",           &resetconfig_pi_medmem,          true,    {\"\"} },\n    { \"support\",                 \"getlastblocks\",                   &getlastblocks,                  true,    {\"num_blocks\"} },\n\n    { \"accounts\",                \"changeaccountname\",               &changeaccountname,              true,    {\"account\", \"name\"} },\n    { \"accounts\",                \"getactiveaccount\",                &getactiveaccount,               true,    {} },\n    { \"accounts\",                \"listaccounts\",                    &listallaccounts,                true,    {\"seed\", \"state\"} },\n    { \"accounts\",                \"getaccountbalances\",              &getaccountbalances,             false,   {\"min_conf\", \"include_watchonly\"} },\n\n    { \"mnemonics\",               \"getactiveseed\",                   &getactiveseed,                  true,    {} },\n    { \"mnemonics\",               \"getmnemonicfromseed\",             &getmnemonicfromseed,            true,    {\"seed\"} },\n    { \"mnemonics\",               \"listseeds\",                       &listseeds,                      true,    {} },\n};\n\nvoid RegisterMuntRPCCommands(CRPCTable &t)\n{\n    if (!GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commandsFull); vcidx++)\n            t.appendCommand(commandsFull[vcidx].name, &commandsFull[vcidx]);\n    }\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commandsSPV); vcidx++)\n        t.appendCommand(commandsSPV[vcidx].name, &commandsSPV[vcidx]);\n}\n\n#endif\n\n\n"
  },
  {
    "path": "src/rpc/accounts.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef RPC_ACCOUNTS_H\n#define RPC_ACCOUNTS_H\n\n#include <univalue.h>\n\n// Get the hash per second that we are mining at.\nUniValue gethashps(const UniValue& params, bool fHelp);\n\n// Set the maximum hash per second to allow when mining.\nUniValue sethashlimit(const UniValue& params, bool fHelp);\n\n// Dump c++ code for old_diff.h that can be used to verify that the code has not been tampered with.\nUniValue dumpdiffarray(const UniValue& params, bool fHelp);\n\n#endif\n"
  },
  {
    "path": "src/rpc/blockchain.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"rpc/blockchain.h\"\n\n#include \"appname.h\"\n#include \"amount.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"checkpoints.h\"\n#include \"coins.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"validation/versionbitsvalidation.h\"\n#include \"core_io.h\"\n#include <net_processing.h>\n#include \"policy/feerate.h\"\n#include \"policy/policy.h\"\n#include \"primitives/transaction.h\"\n#include \"rpc/server.h\"\n#include \"streams.h\"\n#include \"sync.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"hash.h\"\n#include \"versionbits.h\"\n#include \"undo.h\"\n#include \"blockstore.h\"\n\n#include <stdint.h>\n\n#include <univalue.h>\n\n#include <mutex>\n#include <condition_variable>\n\n#include <boost/thread.hpp>\n\nstruct CUpdatedBlock\n{\n    uint256 hash;\n    int height;\n};\n\nstatic std::mutex cs_blockchange;\nstatic std::condition_variable cond_blockchange;\nstatic CUpdatedBlock latestblock;\n\nextern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);\n\ndouble GetDifficulty(const CBlockIndex* blockindex)\n{\n    if (blockindex == NULL)\n    {\n        if (chainActive.Tip() == NULL)\n            return 1.0;\n        else\n            blockindex = chainActive.Tip();\n    }\n\n    return GetHumanDifficultyFromBits(blockindex->nBits);\n}\n\nUniValue blockheaderToJSON(const CBlockIndex* blockindex)\n{\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"hash\", blockindex->GetBlockHashPoW2().GetHex());\n    int confirmations = -1;\n    // Only report confirmations if the block is on the main chain\n    if (chainActive.Contains(blockindex))\n        confirmations = chainActive.Height() - blockindex->nHeight + 1;\n    result.pushKV(\"confirmations\", confirmations);\n    result.pushKV(\"validated\", ((blockindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS));\n    result.pushKV(\"height\", blockindex->nHeight);\n    result.pushKV(\"version\", blockindex->nVersion);\n    result.pushKV(\"versionHex\", strprintf(\"%08x\", blockindex->nVersion));\n    result.pushKV(\"merkleroot\", blockindex->hashMerkleRoot.GetHex());\n    result.pushKV(\"time\", (int64_t)blockindex->GetBlockTimePoW2Witness());\n    result.pushKV(\"mediantime\", (int64_t)blockindex->GetMedianTimePast());\n    result.pushKV(\"witness_version\", blockindex->nVersionPoW2Witness);\n    result.pushKV(\"witness_versionHex\", strprintf(\"%08x\", blockindex->nVersionPoW2Witness));\n    result.pushKV(\"pow_time\", (int64_t)blockindex->nTime);\n    result.pushKV(\"witness_time\", (int64_t)blockindex->nTimePoW2Witness);\n    result.pushKV(\"witness_merkleroot\", blockindex->hashMerkleRootPoW2Witness.GetHex());\n    result.pushKV(\"witness_signature\", HexStr(blockindex->witnessHeaderPoW2Sig.begin(), blockindex->witnessHeaderPoW2Sig.end()));\n    result.pushKV(\"witness_utxo_delta\", HexStr(blockindex->witnessUTXODelta.begin(), blockindex->witnessUTXODelta.end()));\n    result.pushKV(\"nonce\", (uint64_t)blockindex->nNonce);\n    result.pushKV(\"pre_nonce\", (uint64_t)blockindex->nPreNonce);\n    result.pushKV(\"post_nonce\", (uint64_t)blockindex->nPostNonce);\n    result.pushKV(\"bits\", strprintf(\"%08x\", blockindex->nBits));\n    result.pushKV(\"difficulty\", GetDifficulty(blockindex));\n    result.pushKV(\"chainwork\", blockindex->nChainWork.GetHex());\n\n    if (blockindex->pprev)\n        result.pushKV(\"previousblockhash\", blockindex->pprev->GetBlockHashPoW2().GetHex());\n    CBlockIndex *pnext = chainActive.Next(blockindex);\n    if (pnext)\n        result.pushKV(\"nextblockhash\", pnext->GetBlockHashPoW2().GetHex());\n    return result;\n}\n\nUniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)\n{\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"hash\", block.GetHashPoW2().GetHex());\n    if (blockindex)\n    {\n        int confirmations = -1;\n        // Only report confirmations if the block is on the main chain\n        if (chainActive.Contains(blockindex))\n            confirmations = chainActive.Height() - blockindex->nHeight + 1;\n        result.pushKV(\"confirmations\", confirmations);\n    }\n    result.pushKV(\"strippedsize\", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES));\n    if (blockindex)\n    {\n        result.pushKV(\"validated\", (blockindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS);\n    }\n    result.pushKV(\"size\", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION));\n    result.pushKV(\"weight\", (int)::GetBlockWeight(block));\n    if (blockindex)\n    {\n        result.pushKV(\"height\", blockindex->nHeight);\n    }\n    result.pushKV(\"version\", block.nVersion);\n    result.pushKV(\"versionHex\", strprintf(\"%08x\", block.nVersion));\n    result.pushKV(\"merkleroot\", block.hashMerkleRoot.GetHex());\n    result.pushKV(\"witness_version\", block.nVersionPoW2Witness);\n    result.pushKV(\"witness_versionHex\", strprintf(\"%08x\", block.nVersionPoW2Witness));\n    result.pushKV(\"witness_time\", (int64_t)block.nTimePoW2Witness);\n    result.pushKV(\"pow_time\", (int64_t)block.nTime);\n    result.pushKV(\"witness_merkleroot\", block.hashMerkleRootPoW2Witness.GetHex());\n    result.pushKV(\"witness_signature\", HexStr(block.witnessHeaderPoW2Sig.begin(), block.witnessHeaderPoW2Sig.end()));\n    result.pushKV(\"witness_utxo_delta\", HexStr(block.witnessUTXODelta.begin(), block.witnessUTXODelta.end()));\n    UniValue txs(UniValue::VARR);\n    for(const auto& tx : block.vtx)\n    {\n        if(txDetails)\n        {\n            UniValue objTx(UniValue::VOBJ);\n            TxToUniv(*tx, uint256(), objTx);\n            txs.push_back(objTx);\n        }\n        else\n            txs.push_back(tx->GetHash().GetHex());\n    }\n    result.pushKV(\"tx\", txs);\n    if (blockindex)\n    {\n        result.pushKV(\"time\", (int64_t)blockindex->GetBlockTimePoW2Witness());\n        result.pushKV(\"mediantime\", (int64_t)blockindex->GetMedianTimePast());\n    }\n    result.pushKV(\"nonce\", (uint64_t)block.nNonce);\n    result.pushKV(\"pre_nonce\", (uint64_t)block.nPreNonce);\n    result.pushKV(\"post_nonce\", (uint64_t)block.nPostNonce);\n    result.pushKV(\"bits\", strprintf(\"%08x\", block.nBits));\n    if (blockindex)\n    {\n        result.pushKV(\"difficulty\", GetDifficulty(blockindex));\n        result.pushKV(\"chainwork\", blockindex->nChainWork.GetHex());\n    }\n\n    if (blockindex)\n    {\n        if (blockindex->pprev)\n            result.pushKV(\"previousblockhash\", blockindex->pprev->GetBlockHashPoW2().GetHex());\n        CBlockIndex *pnext = chainActive.Next(blockindex);\n        if (pnext)\n            result.pushKV(\"nextblockhash\", pnext->GetBlockHashPoW2().GetHex());\n    }\n    return result;\n}\n\nstatic UniValue getblockcount(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getblockcount\\n\"\n            \"\\nReturns the number of blocks in the longest blockchain.\\n\"\n            \"\\nResult:\\n\"\n            \"n    (numeric) The current block count\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getblockcount\", \"\")\n            + HelpExampleRpc(\"getblockcount\", \"\")\n        );\n\n    LOCK(cs_main);\n    return chainActive.Height();\n}\n\nstatic UniValue getbestblockhash(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getbestblockhash\\n\"\n            \"\\nReturns the hash of the best (tip) block in the longest blockchain.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"hex\\\"      (string) the block hash hex encoded\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getbestblockhash\", \"\")\n            + HelpExampleRpc(\"getbestblockhash\", \"\")\n        );\n\n    LOCK(cs_main);\n    return chainActive.Tip()->GetBlockHashPoW2().GetHex();\n}\n\nvoid RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)\n{\n    if(pindex) {\n        std::lock_guard<std::mutex> lock(cs_blockchange);\n        latestblock.hash = pindex->GetBlockHashPoW2();\n        latestblock.height = pindex->nHeight;\n    }\n    cond_blockchange.notify_all();\n}\n\nstatic UniValue waitfornewblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"waitfornewblock (timeout)\\n\"\n            \"\\nWaits for a specific new block and returns useful info about it.\\n\"\n            \"\\nReturns the current block on timeout or exit.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\\n\"\n            \"\\nResult:\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"hash\\\" : {       (string) The blockhash\\n\"\n            \"  \\\"height\\\" : {     (int) Block height\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"waitfornewblock\", \"1000\")\n            + HelpExampleRpc(\"waitfornewblock\", \"1000\")\n        );\n    int timeout = 0;\n    if (request.params.size() > 0)\n        timeout = request.params[0].get_int();\n\n    CUpdatedBlock block;\n    {\n        std::unique_lock<std::mutex> lock(cs_blockchange);\n        block = latestblock;\n        if(timeout)\n            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });\n        else\n            cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });\n        block = latestblock;\n    }\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"hash\", block.hash.GetHex());\n    ret.pushKV(\"height\", block.height);\n    return ret;\n}\n\nstatic UniValue waitforblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"waitforblock <blockhash> (timeout)\\n\"\n            \"\\nWaits for a specific new block and returns useful info about it.\\n\"\n            \"\\nReturns the current block on timeout or exit.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\" (required, string) Block hash to wait for.\\n\"\n            \"2. timeout       (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\\n\"\n            \"\\nResult:\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"hash\\\" : {       (string) The blockhash\\n\"\n            \"  \\\"height\\\" : {     (int) Block height\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"waitforblock\", \"\\\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\\\", 1000\")\n            + HelpExampleRpc(\"waitforblock\", \"\\\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\\\", 1000\")\n        );\n    int timeout = 0;\n\n    uint256 hash = uint256S(request.params[0].get_str());\n\n    if (request.params.size() > 1)\n        timeout = request.params[1].get_int();\n\n    CUpdatedBlock block;\n    {\n        std::unique_lock<std::mutex> lock(cs_blockchange);\n        if(timeout)\n            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});\n        else\n            cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });\n        block = latestblock;\n    }\n\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"hash\", block.hash.GetHex());\n    ret.pushKV(\"height\", block.height);\n    return ret;\n}\n\nstatic UniValue waitforblockheight(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"waitforblockheight <height> (timeout)\\n\"\n            \"\\nWaits for (at least) block height and returns the height and hash\\n\"\n            \"of the current tip.\\n\"\n            \"\\nReturns the current block on timeout or exit.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. height  (required, int) Block height to wait for (int)\\n\"\n            \"2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\\n\"\n            \"\\nResult:\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"hash\\\" : {       (string) The blockhash\\n\"\n            \"  \\\"height\\\" : {     (int) Block height\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"waitforblockheight\", \"\\\"100\\\", 1000\")\n            + HelpExampleRpc(\"waitforblockheight\", \"\\\"100\\\", 1000\")\n        );\n    int timeout = 0;\n\n    int height = request.params[0].get_int();\n\n    if (request.params.size() > 1)\n        timeout = request.params[1].get_int();\n\n    CUpdatedBlock block;\n    {\n        std::unique_lock<std::mutex> lock(cs_blockchange);\n        if(timeout)\n            cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});\n        else\n            cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });\n        block = latestblock;\n    }\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"hash\", block.hash.GetHex());\n    ret.pushKV(\"height\", block.height);\n    return ret;\n}\n\nstatic UniValue getdifficulty(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getdifficulty\\n\"\n            \"\\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\\n\"\n            \"\\nResult:\\n\"\n            \"n.nnn       (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getdifficulty\", \"\")\n            + HelpExampleRpc(\"getdifficulty\", \"\")\n        );\n\n    LOCK(cs_main);\n    return GetDifficulty();\n}\n\nstatic std::string EntryDescriptionString()\n{\n    return \"    \\\"size\\\" : n,             (numeric) virtual transaction size.\\n\"\n           \"    \\\"fee\\\" : n,              (numeric) transaction fee in \" + CURRENCY_UNIT + \"\\n\"\n           \"    \\\"modifiedfee\\\" : n,      (numeric) transaction fee with fee deltas used for mining priority\\n\"\n           \"    \\\"time\\\" : n,             (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\\n\"\n           \"    \\\"height\\\" : n,           (numeric) block height when transaction entered pool\\n\"\n           \"    \\\"descendantcount\\\" : n,  (numeric) number of in-mempool descendant transactions (including this one)\\n\"\n           \"    \\\"descendantsize\\\" : n,   (numeric) virtual transaction size of in-mempool descendants (including this one)\\n\"\n           \"    \\\"descendantfees\\\" : n,   (numeric) modified fees (see above) of in-mempool descendants (including this one)\\n\"\n           \"    \\\"ancestorcount\\\" : n,    (numeric) number of in-mempool ancestor transactions (including this one)\\n\"\n           \"    \\\"ancestorsize\\\" : n,     (numeric) virtual transaction size of in-mempool ancestors (including this one)\\n\"\n           \"    \\\"ancestorfees\\\" : n,     (numeric) modified fees (see above) of in-mempool ancestors (including this one)\\n\"\n           \"    \\\"depends\\\" : [           (array) unconfirmed transactions used as inputs for this transaction\\n\"\n           \"        \\\"transactionid\\\",    (string) parent transaction id\\n\"\n           \"       ... ]\\n\";\n}\n\nstatic void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)\n{\n    AssertLockHeld(mempool.cs);\n\n    info.pushKV(\"size\", (int)e.GetTxSize());\n    info.pushKV(\"fee\", ValueFromAmount(e.GetFee()));\n    info.pushKV(\"modifiedfee\", ValueFromAmount(e.GetModifiedFee()));\n    info.pushKV(\"time\", e.GetTime());\n    info.pushKV(\"height\", (int)e.GetHeight());\n    info.pushKV(\"descendantcount\", e.GetCountWithDescendants());\n    info.pushKV(\"descendantsize\", e.GetSizeWithDescendants());\n    info.pushKV(\"descendantfees\", e.GetModFeesWithDescendants());\n    info.pushKV(\"ancestorcount\", e.GetCountWithAncestors());\n    info.pushKV(\"ancestorsize\", e.GetSizeWithAncestors());\n    info.pushKV(\"ancestorfees\", e.GetModFeesWithAncestors());\n    const CTransaction& tx = e.GetTx();\n    std::set<std::string> setDepends;\n    for(const CTxIn& txin : tx.vin)\n    {\n        if (txin.GetPrevOut().isHash && mempool.exists(txin.GetPrevOut().getTransactionHash()))\n            setDepends.insert(txin.GetPrevOut().getTransactionHash().ToString());\n    }\n\n    UniValue depends(UniValue::VARR);\n    for(const std::string& dep : setDepends)\n    {\n        depends.push_back(dep);\n    }\n\n    info.pushKV(\"depends\", depends);\n}\n\nUniValue mempoolToJSON(bool fVerbose)\n{\n    if (fVerbose)\n    {\n        LOCK(mempool.cs);\n        UniValue o(UniValue::VOBJ);\n        for(const CTxMemPoolEntry& e : mempool.mapTx)\n        {\n            const uint256& hash = e.GetTx().GetHash();\n            UniValue info(UniValue::VOBJ);\n            entryToJSON(info, e);\n            o.pushKV(hash.ToString(), info);\n        }\n        return o;\n    }\n    else\n    {\n        std::vector<uint256> vtxid;\n        mempool.queryHashes(vtxid);\n\n        UniValue a(UniValue::VARR);\n        for(const uint256& hash : vtxid)\n        {\n            a.push_back(hash.ToString());\n        }\n\n        return a;\n    }\n}\n\nstatic UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"syncwithvalidationinterfacequeue \\n\"\n            \"Waits for the validation interface queue to catch up on everything that was there when we entered this function.\\n\"\n            + HelpExampleCli(\"syncwithvalidationinterfacequeue\",\"\")\n            + HelpExampleRpc(\"syncwithvalidationinterfacequeue\",\"\")\n        );\n    \n    SyncWithValidationInterfaceQueue();\n    return NullUniValue;\n}\n\nstatic UniValue getrawmempool(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getrawmempool ( verbose )\\n\"\n            \"\\nReturns all transaction ids in memory pool as a json array of string transaction ids.\\n\"\n            \"\\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\\n\"\n            \"\\nResult: (for verbose = false):\\n\"\n            \"[                     (json array of string)\\n\"\n            \"  \\\"transactionid\\\"     (string) The transaction id\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nResult: (for verbose = true):\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"transactionid\\\" : {       (json object)\\n\"\n            + EntryDescriptionString()\n            + \"  }, ...\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getrawmempool\", \"true\")\n            + HelpExampleRpc(\"getrawmempool\", \"true\")\n        );\n\n    bool fVerbose = false;\n    if (request.params.size() > 0)\n        fVerbose = request.params[0].get_bool();\n\n    return mempoolToJSON(fVerbose);\n}\n\nstatic UniValue getmempoolancestors(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {\n        throw std::runtime_error(\n            \"getmempoolancestors txid (verbose)\\n\"\n            \"\\nIf txid is in the mempool, returns all in-mempool ancestors.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"                 (string, required) The transaction id (must be in mempool)\\n\"\n            \"2. verbose                  (boolean, optional, default=false) True for a json object, false for array of transaction ids\\n\"\n            \"\\nResult (for verbose=false):\\n\"\n            \"[                       (json array of strings)\\n\"\n            \"  \\\"transactionid\\\"           (string) The transaction id of an in-mempool ancestor transaction\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nResult (for verbose=true):\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"transactionid\\\" : {       (json object)\\n\"\n            + EntryDescriptionString()\n            + \"  }, ...\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmempoolancestors\", \"\\\"mytxid\\\"\")\n            + HelpExampleRpc(\"getmempoolancestors\", \"\\\"mytxid\\\"\")\n            );\n    }\n\n    bool fVerbose = false;\n    if (request.params.size() > 1)\n        fVerbose = request.params[1].get_bool();\n\n    uint256 hash = ParseHashV(request.params[0], \"parameter 1\");\n\n    LOCK(mempool.cs);\n\n    CTxMemPool::txiter it = mempool.mapTx.find(hash);\n    if (it == mempool.mapTx.end()) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction not in mempool\");\n    }\n\n    CTxMemPool::setEntries setAncestors;\n    uint64_t noLimit = std::numeric_limits<uint64_t>::max();\n    std::string dummy;\n    mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);\n\n    if (!fVerbose) {\n        UniValue o(UniValue::VARR);\n        for(CTxMemPool::txiter ancestorIt : setAncestors) {\n            o.push_back(ancestorIt->GetTx().GetHash().ToString());\n        }\n\n        return o;\n    } else {\n        UniValue o(UniValue::VOBJ);\n        for(CTxMemPool::txiter ancestorIt : setAncestors) {\n            const CTxMemPoolEntry &e = *ancestorIt;\n            const uint256& _hash = e.GetTx().GetHash();\n            UniValue info(UniValue::VOBJ);\n            entryToJSON(info, e);\n            o.pushKV(_hash.ToString(), info);\n        }\n        return o;\n    }\n}\n\nstatic UniValue getmempooldescendants(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {\n        throw std::runtime_error(\n            \"getmempooldescendants txid (verbose)\\n\"\n            \"\\nIf txid is in the mempool, returns all in-mempool descendants.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"                 (string, required) The transaction id (must be in mempool)\\n\"\n            \"2. verbose                  (boolean, optional, default=false) True for a json object, false for array of transaction ids\\n\"\n            \"\\nResult (for verbose=false):\\n\"\n            \"[                       (json array of strings)\\n\"\n            \"  \\\"transactionid\\\"           (string) The transaction id of an in-mempool descendant transaction\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nResult (for verbose=true):\\n\"\n            \"{                           (json object)\\n\"\n            \"  \\\"transactionid\\\" : {       (json object)\\n\"\n            + EntryDescriptionString()\n            + \"  }, ...\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmempooldescendants\", \"\\\"mytxid\\\"\")\n            + HelpExampleRpc(\"getmempooldescendants\", \"\\\"mytxid\\\"\")\n            );\n    }\n\n    bool fVerbose = false;\n    if (request.params.size() > 1)\n        fVerbose = request.params[1].get_bool();\n\n    uint256 hash = ParseHashV(request.params[0], \"parameter 1\");\n\n    LOCK(mempool.cs);\n\n    CTxMemPool::txiter it = mempool.mapTx.find(hash);\n    if (it == mempool.mapTx.end()) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction not in mempool\");\n    }\n\n    CTxMemPool::setEntries setDescendants;\n    mempool.CalculateDescendants(it, setDescendants);\n    // CTxMemPool::CalculateDescendants will include the given tx\n    setDescendants.erase(it);\n\n    if (!fVerbose) {\n        UniValue o(UniValue::VARR);\n        for(CTxMemPool::txiter descendantIt : setDescendants) {\n            o.push_back(descendantIt->GetTx().GetHash().ToString());\n        }\n\n        return o;\n    } else {\n        UniValue o(UniValue::VOBJ);\n        for(CTxMemPool::txiter descendantIt : setDescendants) {\n            const CTxMemPoolEntry &e = *descendantIt;\n            const uint256& _hash = e.GetTx().GetHash();\n            UniValue info(UniValue::VOBJ);\n            entryToJSON(info, e);\n            o.pushKV(_hash.ToString(), info);\n        }\n        return o;\n    }\n}\n\nstatic UniValue getmempoolentry(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1) {\n        throw std::runtime_error(\n            \"getmempoolentry txid\\n\"\n            \"\\nReturns mempool data for given transaction\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"                   (string, required) The transaction id (must be in mempool)\\n\"\n            \"\\nResult:\\n\"\n            \"{                           (json object)\\n\"\n            + EntryDescriptionString()\n            + \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmempoolentry\", \"\\\"mytxid\\\"\")\n            + HelpExampleRpc(\"getmempoolentry\", \"\\\"mytxid\\\"\")\n        );\n    }\n\n    uint256 hash = ParseHashV(request.params[0], \"parameter 1\");\n\n    LOCK(mempool.cs);\n\n    CTxMemPool::txiter it = mempool.mapTx.find(hash);\n    if (it == mempool.mapTx.end()) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction not in mempool\");\n    }\n\n    const CTxMemPoolEntry &e = *it;\n    UniValue info(UniValue::VOBJ);\n    entryToJSON(info, e);\n    return info;\n}\n\nstatic UniValue getblockhash(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getblockhash height\\n\"\n            \"\\nReturns hash of block in best-block-chain at height provided.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. height         (numeric, required) The height index\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"hash\\\"         (string) The block hash\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getblockhash\", \"1000\")\n            + HelpExampleRpc(\"getblockhash\", \"1000\")\n        );\n\n    LOCK(cs_main);\n\n    int nHeight = request.params[0].get_int();\n    if (nHeight < 0 || nHeight > chainActive.Height())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Block height out of range\");\n\n    CBlockIndex* pblockindex = chainActive[nHeight];\n    return pblockindex->GetBlockHashPoW2().GetHex();\n}\n\nstatic UniValue getblockheader(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getblockheader \\\"hash\\\" ( verbose )\\n\"\n            \"\\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\\n\"\n            \"If verbose is true, returns an Object with information about blockheader <hash>.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"hash\\\"          (string, required) The block hash\\n\"\n            \"2. verbose           (boolean, optional, default=true) true for a json object, false for the hex encoded data\\n\"\n            \"\\nResult (for verbose = true):\\n\"\n            \"{\\n\"\n            \"  \\\"hash\\\" : \\\"hash\\\",     (string) the block hash (same as provided)\\n\"\n            \"  \\\"confirmations\\\" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain\\n\"\n            \"  \\\"validated\\\" : n,       (boolean) True if the block has been validated\\n\"\n            \"  \\\"height\\\" : n,          (numeric) The block height or index\\n\"\n            \"  \\\"version\\\" : n,         (numeric) The block version\\n\"\n            \"  \\\"versionHex\\\" : \\\"00000000\\\", (string) The block version formatted in hexadecimal\\n\"\n            \"  \\\"merkleroot\\\" : \\\"xxxx\\\", (string) The merkle root\\n\"\n            \"  \\\"time\\\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"mediantime\\\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"nonce\\\" : n,           (numeric) The nonce\\n\"\n            \"  \\\"bits\\\" : \\\"1d00ffff\\\", (string) The bits\\n\"\n            \"  \\\"difficulty\\\" : x.xxx,  (numeric) The difficulty\\n\"\n            \"  \\\"chainwork\\\" : \\\"0000...1f3\\\"     (string) Expected number of hashes required to produce the current chain (in hex)\\n\"\n            \"  \\\"previousblockhash\\\" : \\\"hash\\\",  (string) The hash of the previous block\\n\"\n            \"  \\\"nextblockhash\\\" : \\\"hash\\\",      (string) The hash of the next block\\n\"\n            \"}\\n\"\n            \"\\nResult (for verbose=false):\\n\"\n            \"\\\"data\\\"             (string) A string that is serialized, hex-encoded data for block 'hash'.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getblockheader\", \"\\\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\\\"\")\n            + HelpExampleRpc(\"getblockheader\", \"\\\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\\\"\")\n        );\n\n    LOCK(cs_main);\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n\n    bool fVerbose = true;\n    if (request.params.size() > 1)\n        fVerbose = request.params[1].get_bool();\n\n    if (mapBlockIndex.count(hash) == 0)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n\n    CBlockIndex* pblockindex = mapBlockIndex[hash];\n\n    if (!fVerbose)\n    {\n        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);\n        ssBlock << pblockindex->GetBlockHeader();\n        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());\n        return strHex;\n    }\n\n    return blockheaderToJSON(pblockindex);\n}\n\nstatic UniValue getblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getblock \\\"blockhash\\\" ( verbosity ) \\n\"\n            \"\\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\\n\"\n            \"If verbosity is 1, returns an Object with information about block <hash>.\\n\"\n            \"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\"          (string, required) The block hash\\n\"\n            \"2. verbosity              (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\\n\"\n            \"\\nResult (for verbosity = 0):\\n\"\n            \"\\\"data\\\"             (string) A string that is serialized, hex-encoded data for block 'hash'.\\n\"\n            \"\\nResult (for verbosity = 1):\\n\"\n            \"{\\n\"\n            \"  \\\"hash\\\" : \\\"hash\\\",     (string) the block hash (same as provided)\\n\"\n            \"  \\\"confirmations\\\" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain\\n\"\n            \"  \\\"size\\\" : n,            (numeric) The block size\\n\"\n            \"  \\\"strippedsize\\\" : n,    (numeric) The block size excluding segregated signature data\\n\"\n            \"  \\\"weight\\\" : n           (numeric) The block weight as defined in BIP 141\\n\"\n            \"  \\\"height\\\" : n,          (numeric) The block height or index\\n\"\n            \"  \\\"version\\\" : n,         (numeric) The block version\\n\"\n            \"  \\\"versionHex\\\" : \\\"00000000\\\", (string) The block version formatted in hexadecimal\\n\"\n            \"  \\\"merkleroot\\\" : \\\"xxxx\\\", (string) The merkle root\\n\"\n            \"  \\\"tx\\\" : [               (array of string) The transaction ids\\n\"\n            \"     \\\"transactionid\\\"     (string) The transaction id\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"time\\\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"mediantime\\\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"nonce\\\" : n,           (numeric) The nonce\\n\"\n            \"  \\\"bits\\\" : \\\"1d00ffff\\\", (string) The bits\\n\"\n            \"  \\\"difficulty\\\" : x.xxx,  (numeric) The difficulty\\n\"\n            \"  \\\"chainwork\\\" : \\\"xxxx\\\",  (string) Expected number of hashes required to produce the chain up to this block (in hex)\\n\"\n            \"  \\\"previousblockhash\\\" : \\\"hash\\\",  (string) The hash of the previous block\\n\"\n            \"  \\\"nextblockhash\\\" : \\\"hash\\\"       (string) The hash of the next block\\n\"\n            \"}\\n\"\n            \"\\nResult (for verbosity = 2):\\n\"\n            \"{\\n\"\n            \"  ...,                     Same output as verbosity = 1.\\n\"\n            \"  \\\"tx\\\" : [               (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \\\"tx\\\" result.\\n\"\n            \"         ,...\\n\"\n            \"  ],\\n\"\n            \"  ,...                     Same output as verbosity = 1.\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getblock\", \"\\\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\\\"\")\n            + HelpExampleRpc(\"getblock\", \"\\\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\\\"\")\n        );\n\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n\n    int verbosity = 1;\n    if (request.params.size() > 1) {\n        if(request.params[1].isNum())\n            verbosity = request.params[1].get_int();\n        else\n            verbosity = request.params[1].get_bool() ? 1 : 0;\n    }\n\n    if (mapBlockIndex.count(hash) == 0)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n\n    CBlock block;\n    CBlockIndex* pblockindex = mapBlockIndex[hash];\n\n    if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)\n        throw JSONRPCError(RPC_MISC_ERROR, \"Block not available (pruned data)\");\n\n    if (!ReadBlockFromDisk(block, pblockindex, Params()))\n        // Block not found on disk. This could be because we have the block\n        // header in our index but don't have the block (for example if a\n        // non-whitelisted node sends us an unrequested long chain of valid\n        // blocks, we add the headers to our index, but don't accept the\n        // block).\n        throw JSONRPCError(RPC_MISC_ERROR, \"Block not found on disk\");\n\n    if (verbosity <= 0)\n    {\n        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());\n        ssBlock << block;\n        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());\n        return strHex;\n    }\n\n    return blockToJSON(block, pblockindex, verbosity >= 2);\n}\n\n\nstatic UniValue decodeblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"decodeblock \\\"blockhex\\\"\\n\"\n            \"\\nDecode a block from hex and print the result.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhex\\\"          (string, required) The block hash\\n\"\n            \"{\\n\"\n            \"  \\\"hash\\\" : \\\"hash\\\",     (string) the block hash (same as provided)\\n\"\n            \"  \\\"confirmations\\\" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain\\n\"\n            \"  \\\"size\\\" : n,            (numeric) The block size\\n\"\n            \"  \\\"strippedsize\\\" : n,    (numeric) The block size excluding segregated signature data\\n\"\n            \"  \\\"weight\\\" : n           (numeric) The block weight as defined in BIP 141\\n\"\n            \"  \\\"height\\\" : n,          (numeric) The block height or index\\n\"\n            \"  \\\"version\\\" : n,         (numeric) The block version\\n\"\n            \"  \\\"versionHex\\\" : \\\"00000000\\\", (string) The block version formatted in hexadecimal\\n\"\n            \"  \\\"merkleroot\\\" : \\\"xxxx\\\", (string) The merkle root\\n\"\n            \"  \\\"tx\\\" : [               (array of string) The transaction ids\\n\"\n            \"     \\\"transactionid\\\"     (string) The transaction id\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"time\\\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"mediantime\\\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"nonce\\\" : n,           (numeric) The nonce\\n\"\n            \"  \\\"bits\\\" : \\\"1d00ffff\\\", (string) The bits\\n\"\n            \"  \\\"difficulty\\\" : x.xxx,  (numeric) The difficulty\\n\"\n            \"  \\\"chainwork\\\" : \\\"xxxx\\\",  (string) Expected number of hashes required to produce the chain up to this block (in hex)\\n\"\n            \"  \\\"previousblockhash\\\" : \\\"hash\\\",  (string) The hash of the previous block\\n\"\n            \"  \\\"nextblockhash\\\" : \\\"hash\\\"       (string) The hash of the next block\\n\"\n            \"}\\n\"\n        );\n\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n    std::string strHex = request.params[0].get_str();\n\n    std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();\n    CBlock& block = *blockptr;\n    if (!DecodeHexBlk(block, request.params[0].get_str())) {\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"Block decode failed\");\n    }\n\n    return blockToJSON(block, nullptr, true);\n}\n\nstruct CCoinsStats\n{\n    int nHeight;\n    uint256 hashBlock;\n    uint64_t nTransactions;\n    uint64_t nTransactionOutputs;\n    uint64_t nBogoSize;\n    uint256 hashSerialized;\n    uint64_t nDiskSize;\n    CAmount nTotalAmount;\n    std::map<int, int> nTypeCount;\n\n    CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nBogoSize(0), nDiskSize(0), nTotalAmount(0) {}\n};\n\nstatic void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)\n{\n    assert(!outputs.empty());\n    ss << hash;\n    ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase);\n    stats.nTransactions++;\n    for (const auto output : outputs)\n    {\n        ss << VARINT(output.first + 1);\n        ss << output.second.out.GetType();\n        switch (output.second.out.GetType())\n        {\n            case CTxOutType::ScriptLegacyOutput:\n                ss << *(const CScriptBase*)(&output.second.out.output.scriptPubKey);\n                break;\n            case CTxOutType::StandardKeyHashOutput:\n                ss << output.second.out.output.standardKeyHash;\n                break;\n            case CTxOutType::PoW2WitnessOutput:\n                ss << output.second.out.output.witnessDetails;\n                break;\n        }\n        ss << VARINT(output.second.out.nValue);\n        uint64_t nScriptSize=0;\n        {\n            std::vector<CTxDestination> addresses;\n            switch (output.second.out.GetType())\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                    txnouttype whichType;\n                    int nRequired;\n                    ExtractDestinations(output.second.out.output.scriptPubKey, whichType, addresses, nRequired);\n                    stats.nTypeCount[whichType]++;\n                    nScriptSize = output.second.out.output.scriptPubKey.size();\n                    break;\n                case CTxOutType::StandardKeyHashOutput:\n                    //fixme: (PHASE5) Handle 'nBogoSize' here\n                    stats.nTypeCount[TX_STANDARD_PUBKEY_HASH]++;\n                    break;\n                case CTxOutType::PoW2WitnessOutput:\n                    //fixme: (PHASE5) Handle 'nBogoSize' here\n                    stats.nTypeCount[TX_STANDARD_WITNESS]++;\n                    break;\n            }\n        }\n\n        stats.nTransactionOutputs++;\n        stats.nTotalAmount += output.second.out.nValue;\n        stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +\n                           2 /* scriptPubKey len */ + nScriptSize /* scriptPubKey */;\n    }\n    ss << VARINT(0);\n}\n\n//! Calculate statistics about the unspent transaction output set\nstatic bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)\n{\n    std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());\n\n    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);\n    stats.hashBlock = pcursor->GetBestBlock();\n    {\n        LOCK(cs_main);\n        stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;\n    }\n    ss << stats.hashBlock;\n    uint256 prevkey;\n    std::map<uint32_t, Coin> outputs;\n    while (pcursor->Valid())\n    {\n        boost::this_thread::interruption_point();\n        COutPoint key;\n        uint256 txHash;\n        Coin coin;\n        if (pcursor->GetKey(key) && pcursor->GetValue(coin) && GetTxHash(key, txHash))\n        {\n            if (!outputs.empty() && txHash != prevkey)\n            {\n                ApplyStats(stats, ss, prevkey, outputs);\n                outputs.clear();\n            }\n            prevkey = txHash;\n            outputs[key.n] = std::move(coin);\n        }\n        else\n        {\n            return error(\"%s: unable to read value\", __func__);\n        }\n        pcursor->Next();\n    }\n    if (!outputs.empty()) {\n        ApplyStats(stats, ss, prevkey, outputs);\n    }\n    stats.hashSerialized = ss.GetHash();\n    stats.nDiskSize = view->EstimateSize();\n    return true;\n}\n\nstatic UniValue pruneblockchain(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"pruneblockchain\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"height\\\"       (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\\n\"\n            \"                  to prune blocks whose block time is at least 2 hours older than the provided timestamp.\\n\"\n            \"\\nResult:\\n\"\n            \"n    (numeric) Height of the last block pruned.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"pruneblockchain\", \"1000\")\n            + HelpExampleRpc(\"pruneblockchain\", \"1000\"));\n\n    if (!fPruneMode)\n        throw JSONRPCError(RPC_MISC_ERROR, \"Cannot prune blocks because node is not in prune mode.\");\n\n    LOCK(cs_main);\n\n    int heightParam = request.params[0].get_int();\n    if (heightParam < 0)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Negative block height.\");\n\n    // Height value more than a billion is too high to be a block height, and\n    // too low to be a block time (corresponds to timestamp from Sep 2001).\n    if (heightParam > 1000000000) {\n        // Add a 2 hour buffer to include blocks which might have had old timestamps\n        CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW);\n        if (!pindex) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Could not find block with at least the specified timestamp.\");\n        }\n        heightParam = pindex->nHeight;\n    }\n\n    unsigned int height = (unsigned int) heightParam;\n    unsigned int chainHeight = (unsigned int) chainActive.Height();\n    if (chainHeight < Params().PruneAfterHeight())\n        throw JSONRPCError(RPC_MISC_ERROR, \"Blockchain is too short for pruning.\");\n    else if (height > chainHeight)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Blockchain is shorter than the attempted prune height.\");\n    else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {\n        LogPrint(BCLog::RPC, \"Attempt to prune blocks close to the tip.  Retaining the minimum number of blocks.\");\n        height = chainHeight - MIN_BLOCKS_TO_KEEP;\n    }\n\n    PruneBlockFilesManual(height);\n    return uint64_t(height);\n}\n\nstatic UniValue gettxoutsetinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"gettxoutsetinfo\\n\"\n            \"\\nReturns statistics about the unspent transaction output set.\\n\"\n            \"Note this call may take some time.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"height\\\":n,                    (numeric) The current block height (index)\\n\"\n            \"  \\\"bestblock\\\": \\\"hex\\\",            (string) the best block hash hex\\n\"\n            \"  \\\"transactions\\\": n,             (numeric) The number of transactions\\n\"\n            \"  \\\"txouts\\\": n,                   (numeric) The number of output transactions\\n\"\n            \"  \\\"bogosize\\\": n,                 (numeric) A meaningless metric for UTXO set size\\n\"\n            \"  \\\"hash_serialized_2\\\": \\\"hash\\\",   (string) The serialized hash\\n\"\n            \"  \\\"disk_size\\\": n,                (numeric) The estimated size of the chainstate on disk\\n\"\n            \"  \\\"total_amount\\\": x.xxx          (numeric) The total amount\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"gettxoutsetinfo\", \"\")\n            + HelpExampleRpc(\"gettxoutsetinfo\", \"\")\n        );\n\n    UniValue ret(UniValue::VOBJ);\n\n    CCoinsStats stats;\n    FlushStateToDisk();\n    if (GetUTXOStats(pcoinsdbview, stats))\n    {\n        ret.pushKV(\"height\", (int64_t)stats.nHeight);\n        ret.pushKV(\"bestblock\", stats.hashBlock.GetHex());\n        ret.pushKV(\"transactions\", (int64_t)stats.nTransactions);\n        ret.pushKV(\"txouts\", (int64_t)stats.nTransactionOutputs);\n        ret.pushKV(\"bogosize\", (int64_t)stats.nBogoSize);\n        ret.pushKV(\"hash_serialized_2\", stats.hashSerialized.GetHex());\n        ret.pushKV(\"disk_size\", stats.nDiskSize);\n        ret.pushKV(\"total_amount\", ValueFromAmount(stats.nTotalAmount));\n        for (auto& item : stats.nTypeCount)\n        {\n            ret.pushKV(GetTxnOutputType((txnouttype)item.first), item.second);\n        }\n    }\n    else\n    {\n        throw JSONRPCError(RPC_INTERNAL_ERROR, \"Unable to read UTXO set\");\n    }\n    return ret;\n}\n\nstatic UniValue gettxout(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)\n        throw std::runtime_error(\n            \"gettxout \\\"txid\\\" n ( include_mempool )\\n\"\n            \"\\nReturns details about an unspent transaction output.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"       (string, required) The transaction id\\n\"\n            \"2. n              (numeric, required) vout number\\n\"\n            \"3. include_mempool  (boolean, optional) Whether to include the mempool\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"bestblock\\\" : \\\"hash\\\",    (string) the block hash\\n\"\n            \"  \\\"confirmations\\\" : n,       (numeric) The number of confirmations\\n\"\n            \"  \\\"value\\\" : x.xxx,           (numeric) The transaction value in \" + CURRENCY_UNIT + \"\\n\"\n            \"  \\\"scriptPubKey\\\" : {         (json object)\\n\"\n            \"     \\\"asm\\\" : \\\"code\\\",       (string) \\n\"\n            \"     \\\"hex\\\" : \\\"hex\\\",        (string) \\n\"\n            \"     \\\"reqSigs\\\" : n,          (numeric) Number of required signatures\\n\"\n            \"     \\\"type\\\" : \\\"pubkeyhash\\\", (string) The type, eg pubkeyhash\\n\"\n            \"     \\\"addresses\\\" : [          (array of string) array of \" GLOBAL_APPNAME \" addresses\\n\"\n            \"        \\\"address\\\"     (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"        ,...\\n\"\n            \"     ]\\n\"\n            \"  },\\n\"\n            \"  \\\"version\\\" : n,            (numeric) The version\\n\"\n            \"  \\\"coinbase\\\" : true|false   (boolean) Coinbase or not\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            \"\\nGet unspent transactions\\n\"\n            + HelpExampleCli(\"listunspent\", \"\") +\n            \"\\nView the details\\n\"\n            + HelpExampleCli(\"gettxout\", \"\\\"txid\\\" 1\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"gettxout\", \"\\\"txid\\\", 1\")\n        );\n\n    LOCK(cs_main);\n\n    UniValue ret(UniValue::VOBJ);\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n    int n = request.params[1].get_int();\n    COutPoint out(hash, n);\n    bool fMempool = true;\n    if (request.params.size() > 2)\n        fMempool = request.params[2].get_bool();\n\n    Coin coin;\n    if (fMempool) {\n        LOCK(mempool.cs);\n        CCoinsViewMemPool view(pcoinsTip, mempool);\n        if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { // TODO: filtering spent coins should be done by the CCoinsViewMemPool\n            return NullUniValue;\n        }\n    } else {\n        if (!pcoinsTip->GetCoin(out, coin)) {\n            return NullUniValue;\n        }\n    }\n\n    BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());\n    CBlockIndex *pindex = it->second;\n    ret.pushKV(\"bestblock\", pindex->GetBlockHashPoW2().GetHex());\n    if (coin.nHeight == MEMPOOL_HEIGHT) {\n        ret.pushKV(\"confirmations\", 0);\n    } else {\n        ret.pushKV(\"confirmations\", (int64_t)(pindex->nHeight - coin.nHeight + 1));\n    }\n    ret.pushKV(\"value\", ValueFromAmount(coin.out.nValue));\n    UniValue o(UniValue::VOBJ);\n    switch (coin.out.GetType())\n    {\n        case CTxOutType::ScriptLegacyOutput:\n        {\n            ScriptPubKeyToUniv(coin.out.output.scriptPubKey, o, true);\n            ret.pushKV(\"scriptPubKey\", o);\n            break;\n        }\n        case CTxOutType::StandardKeyHashOutput:\n        {\n            PoW2WitnessToUniv(coin.out, o, true);\n            ret.pushKV(\"PoW²-witness\", o);\n            break;\n        }\n        case CTxOutType::PoW2WitnessOutput:\n        {\n            StandardKeyHashToUniv(coin.out, o, true);\n            ret.pushKV(\"standard-key-hash\", o);\n            break;\n        }\n    }\n    ret.pushKV(\"coinbase\", (bool)coin.fCoinBase);\n\n    return ret;\n}\n\nstatic UniValue verifychain(const JSONRPCRequest& request)\n{\n    int nCheckLevel = GetArg(\"-checklevel\", DEFAULT_CHECKLEVEL);\n    int nCheckDepth = GetArg(\"-checkblocks\", DEFAULT_CHECKBLOCKS);\n    if (request.fHelp || request.params.size() > 2)\n        throw std::runtime_error(\n            \"verifychain ( check_level num_blocks )\\n\"\n            \"\\nVerifies blockchain database.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. check_level  (numeric, optional, 0-4, default=\" + strprintf(\"%d\", nCheckLevel) + \") How thorough the block verification is.\\n\"\n            \"2. num_blocks   (numeric, optional, default=\" + strprintf(\"%d\", nCheckDepth) + \", 0=all) The number of blocks to check.\\n\"\n            \"\\nResult:\\n\"\n            \"true|false       (boolean) Verified or not\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"verifychain\", \"\")\n            + HelpExampleRpc(\"verifychain\", \"\")\n        );\n\n    LOCK(cs_main);\n\n    if (request.params.size() > 0)\n        nCheckLevel = request.params[0].get_int();\n    if (request.params.size() > 1)\n        nCheckDepth = request.params[1].get_int();\n\n    return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);\n}\n\n/** Implementation of IsSuperMajority with better feedback */\nstatic UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)\n{\n    UniValue rv(UniValue::VOBJ);\n    bool activated = false;\n    switch(version)\n    {\n        case 2:\n            activated = pindex->nHeight >= consensusParams.BIP34Height;\n            break;\n        case 3:\n            activated = pindex->nHeight >= consensusParams.BIP66Height;\n            break;\n        case 4:\n            activated = pindex->nHeight >= consensusParams.BIP65Height;\n            break;\n    }\n    rv.pushKV(\"status\", activated);\n    return rv;\n}\n\nstatic UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)\n{\n    UniValue rv(UniValue::VOBJ);\n    rv.pushKV(\"id\", name);\n    rv.pushKV(\"version\", version);\n    rv.pushKV(\"reject\", SoftForkMajorityDesc(version, pindex, consensusParams));\n    return rv;\n}\n\nstatic UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id)\n{\n    UniValue rv(UniValue::VOBJ);\n    const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id);\n    switch (thresholdState) {\n    case THRESHOLD_DEFINED: rv.pushKV(\"status\", \"defined\"); break;\n    case THRESHOLD_STARTED: rv.pushKV(\"status\", \"started\"); break;\n    case THRESHOLD_LOCKED_IN: rv.pushKV(\"status\", \"locked_in\"); break;\n    case THRESHOLD_ACTIVE: rv.pushKV(\"status\", \"active\"); break;\n    case THRESHOLD_FAILED: rv.pushKV(\"status\", \"failed\"); break;\n    }\n    if (THRESHOLD_STARTED == thresholdState)\n    {\n        rv.pushKV(\"bit\", consensusParams.vDeployments[id].bit);\n    }\n    rv.pushKV(\"startTime\", consensusParams.vDeployments[id].nStartTime);\n    rv.pushKV(\"timeout\", consensusParams.vDeployments[id].nTimeout);\n    rv.pushKV(\"since\", VersionBitsTipStateSinceHeight(consensusParams, id));\n    if (THRESHOLD_STARTED == thresholdState)\n    {\n        UniValue statsUV(UniValue::VOBJ);\n        BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id);\n        statsUV.pushKV(\"period\", statsStruct.period);\n        statsUV.pushKV(\"threshold\", statsStruct.threshold);\n        statsUV.pushKV(\"elapsed\", statsStruct.elapsed);\n        statsUV.pushKV(\"count\", statsStruct.count);\n        statsUV.pushKV(\"possible\", statsStruct.possible);\n        rv.pushKV(\"statistics\", statsUV);\n    }\n    return rv;\n}\n\nstatic void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)\n{\n    // Deployments with timeout value of 0 are hidden.\n    // A timeout value of 0 guarantees a softfork will never be activated.\n    // This is used when softfork codes are merged without specifying the deployment schedule.\n    if (consensusParams.vDeployments[id].nTimeout > 0)\n        bip9_softforks.pushKV(name, BIP9SoftForkDesc(consensusParams, id));\n}\n\nUniValue getblockchaininfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getblockchaininfo\\n\"\n            \"Returns an object containing various state info regarding blockchain processing.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"chain\\\": \\\"xxxx\\\",        (string) current network name as defined in BIP70 (main, test, regtest)\\n\"\n            \"  \\\"blocks\\\": xxxxxx,         (numeric) the current number of blocks processed in the server\\n\"\n            \"  \\\"headers\\\": xxxxxx,        (numeric) the current number of headers we have validated\\n\"\n            \"  \\\"bestblockhash\\\": \\\"...\\\", (string) the hash of the currently best block\\n\"\n            \"  \\\"difficulty\\\": xxxxxx,     (numeric) the current difficulty\\n\"\n            \"  \\\"mediantime\\\": xxxxxx,     (numeric) median time for the current best block\\n\"\n            \"  \\\"verificationprogress\\\": xxxx, (numeric) estimate of verification progress [0..1]\\n\"\n            \"  \\\"initialblockdownload\\\": xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode.\\n\"\n            \"  \\\"chainwork\\\": \\\"xxxx\\\"     (string) total amount of work in active chain, in hexadecimal\\n\"\n            \"  \\\"pruned\\\": xx,             (boolean) if the blocks are subject to pruning\\n\"\n            \"  \\\"pruneheight\\\": xxxxxx,    (numeric) lowest-height complete block stored\\n\"\n            \"  \\\"automatic_pruning\\\": xx,      (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\\n\"\n            \"  \\\"prune_target_size\\\": xxxxxx,  (numeric) the target size used by pruning (only present if automatic pruning is enabled)\\n\"\n            \"  \\\"softforks\\\": [            (array) status of softforks in progress\\n\"\n            \"     {\\n\"\n            \"        \\\"id\\\": \\\"xxxx\\\",        (string) name of softfork\\n\"\n            \"        \\\"version\\\": xx,         (numeric) block version\\n\"\n            \"        \\\"reject\\\": {            (object) progress toward rejecting pre-softfork blocks\\n\"\n            \"           \\\"status\\\": xx,       (boolean) true if threshold reached\\n\"\n            \"        },\\n\"\n            \"     }, ...\\n\"\n            \"  ],\\n\"\n            \"  \\\"bip9_softforks\\\": {          (object) status of BIP9 softforks in progress\\n\"\n            \"     \\\"xxxx\\\" : {                (string) name of the softfork\\n\"\n            \"        \\\"status\\\": \\\"xxxx\\\",    (string) one of \\\"defined\\\", \\\"started\\\", \\\"locked_in\\\", \\\"active\\\", \\\"failed\\\"\\n\"\n            \"        \\\"bit\\\": xx,             (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \\\"started\\\" status)\\n\"\n            \"        \\\"startTime\\\": xx,       (numeric) the minimum median time past of a block at which the bit gains its meaning\\n\"\n            \"        \\\"timeout\\\": xx,         (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\\n\"\n            \"        \\\"since\\\": xx,           (numeric) height of the first block to which the status applies\\n\"\n            \"        \\\"statistics\\\": {        (object) numeric statistics about BIP9 signalling for a softfork (only for \\\"started\\\" status)\\n\"\n            \"           \\\"period\\\": xx,       (numeric) the length in blocks of the BIP9 signalling period \\n\"\n            \"           \\\"threshold\\\": xx,    (numeric) the number of blocks with the version bit set required to activate the feature \\n\"\n            \"           \\\"elapsed\\\": xx,      (numeric) the number of blocks elapsed since the beginning of the current period \\n\"\n            \"           \\\"count\\\": xx,        (numeric) the number of blocks with the version bit set in the current period \\n\"\n            \"           \\\"possible\\\": xx      (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \\n\"\n            \"        }\\n\"\n            \"     }\\n\"\n            \"  }\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getblockchaininfo\", \"\")\n            + HelpExampleRpc(\"getblockchaininfo\", \"\")\n        );\n\n    LOCK(cs_main);\n\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"chain\",                 Params().NetworkIDString());\n    obj.pushKV(\"blocks\",                (int)chainActive.Height());\n    obj.pushKV(\"headers\",               pindexBestHeader ? pindexBestHeader->nHeight : -1);\n    obj.pushKV(\"bestblockhash\",         chainActive.Tip()->GetBlockHashPoW2().GetHex());\n    obj.pushKV(\"difficulty\",            (double)GetDifficulty());\n    obj.pushKV(\"mediantime\",            (int64_t)chainActive.Tip()->GetMedianTimePast());\n    obj.pushKV(\"verificationprogress\",  GuessVerificationProgress(chainActive.Tip()));\n    obj.pushKV(\"initialblockdownload\",  IsInitialBlockDownload());\n    obj.pushKV(\"chainwork\",             chainActive.Tip()->nChainWork.GetHex());\n    obj.pushKV(\"pruned\",                fPruneMode);\n\n    const Consensus::Params& consensusParams = Params().GetConsensus();\n    CBlockIndex* tip = chainActive.Tip();\n    UniValue softforks(UniValue::VARR);\n    UniValue bip9_softforks(UniValue::VOBJ);\n    softforks.push_back(SoftForkDesc(\"bip34\", 2, tip, consensusParams));\n    softforks.push_back(SoftForkDesc(\"bip66\", 3, tip, consensusParams));\n    softforks.push_back(SoftForkDesc(\"bip65\", 4, tip, consensusParams));\n    BIP9SoftForkDescPushBack(bip9_softforks, \"csv\", consensusParams, Consensus::DEPLOYMENT_CSV);\n    obj.pushKV(\"softforks\",             softforks);\n    obj.pushKV(\"bip9_softforks\", bip9_softforks);\n\n    if (fPruneMode)\n    {\n        CBlockIndex *block = chainActive.Tip();\n        while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))\n            block = block->pprev;\n\n        obj.pushKV(\"pruneheight\",        block->nHeight);\n        // if 0, execution bypasses the whole if block.\n        bool automatic_pruning = (gArgs.GetArg(\"-prune\", 0) != 1);\n        obj.pushKV(\"automatic_pruning\",  automatic_pruning);\n        if (automatic_pruning) {\n            obj.pushKV(\"prune_target_size\",  nPruneTarget);\n        }\n    }\n    return obj;\n}\n\n/** Comparison function for sorting the getchaintips heads.  */\nstruct CompareBlocksByHeight\n{\n    bool operator()(const CBlockIndex* a, const CBlockIndex* b) const\n    {\n        /* Make sure that unequal blocks with the same height do not compare\n           equal. Use the pointers themselves to make a distinction. */\n\n        if (a->nHeight != b->nHeight)\n          return (a->nHeight > b->nHeight);\n\n        return a < b;\n    }\n};\n\nstatic UniValue getchaintips(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getchaintips\\n\"\n            \"Return information about all known tips in the block tree,\"\n            \" including the main chain as well as orphaned branches.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"height\\\": xxxx,         (numeric) height of the chain tip\\n\"\n            \"    \\\"hash\\\": \\\"xxxx\\\",         (string) block hash of the tip\\n\"\n            \"    \\\"branchlen\\\": 0          (numeric) zero for main chain\\n\"\n            \"    \\\"status\\\": \\\"active\\\"      (string) \\\"active\\\" for the main chain\\n\"\n            \"  },\\n\"\n            \"  {\\n\"\n            \"    \\\"height\\\": xxxx,\\n\"\n            \"    \\\"hash\\\": \\\"xxxx\\\",\\n\"\n            \"    \\\"branchlen\\\": 1          (numeric) length of branch connecting the tip to the main chain\\n\"\n            \"    \\\"status\\\": \\\"xxxx\\\"        (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\\n\"\n            \"  }\\n\"\n            \"]\\n\"\n            \"Possible values for status:\\n\"\n            \"1.  \\\"invalid\\\"               This branch contains at least one invalid block\\n\"\n            \"2.  \\\"headers-only\\\"          Not all blocks for this branch are available, but the headers are valid\\n\"\n            \"3.  \\\"valid-headers\\\"         All blocks are available for this branch, but they were never fully validated\\n\"\n            \"4.  \\\"valid-fork\\\"            This branch is not part of the active chain, but is fully validated\\n\"\n            \"5.  \\\"active\\\"                This is the tip of the active main chain, which is certainly valid\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getchaintips\", \"\")\n            + HelpExampleRpc(\"getchaintips\", \"\")\n        );\n\n    LOCK(cs_main);\n\n    /*\n     * Idea:  the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.\n     * Algorithm:\n     *  - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.\n     *  - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.\n     *  - add chainActive.Tip()\n     */\n    std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;\n    std::set<const CBlockIndex*> setOrphans;\n    std::set<const CBlockIndex*> setPrevs;\n\n    for(const PAIRTYPE(const uint256, CBlockIndex*)& item : mapBlockIndex)\n    {\n        if (!chainActive.Contains(item.second)) {\n            setOrphans.insert(item.second);\n            setPrevs.insert(item.second->pprev);\n        }\n    }\n\n    for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it)\n    {\n        if (setPrevs.erase(*it) == 0) {\n            setTips.insert(*it);\n        }\n    }\n\n    // Always report the currently active tip.\n    setTips.insert(chainActive.Tip());\n\n    /* Construct the output array.  */\n    UniValue res(UniValue::VARR);\n    for(const CBlockIndex* block : setTips)\n    {\n        UniValue obj(UniValue::VOBJ);\n        obj.pushKV(\"height\", block->nHeight);\n        obj.pushKV(\"hash\", block->phashBlock->GetHex());\n\n        const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;\n        obj.pushKV(\"branchlen\", branchLen);\n\n        std::string status;\n        if (chainActive.Contains(block)) {\n            // This block is part of the currently active chain.\n            status = \"active\";\n        } else if (block->nStatus & BLOCK_FAILED_MASK) {\n            // This block or one of its ancestors is invalid.\n            status = \"invalid\";\n        } else if (block->nChainTx == 0) {\n            // This block cannot be connected because full block data for it or one of its parents is missing.\n            status = \"headers-only\";\n        } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {\n            // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.\n            status = \"valid-fork\";\n        } else if (block->IsValid(BLOCK_VALID_TREE)) {\n            // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.\n            status = \"valid-headers\";\n        } else {\n            // No clue.\n            status = \"unknown\";\n        }\n        obj.pushKV(\"status\", status);\n\n        res.push_back(obj);\n    }\n\n    return res;\n}\n\nextern std::atomic_bool fDumpMempoolLater;\nUniValue mempoolInfoToJSON()\n{\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"loaded\", fDumpMempoolLater);\n    ret.pushKV(\"size\", (int64_t) mempool.size());\n    ret.pushKV(\"bytes\", (int64_t) mempool.GetTotalTxSize());\n    ret.pushKV(\"usage\", (int64_t) mempool.DynamicMemoryUsage());\n    size_t maxmempool = GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;\n    ret.pushKV(\"maxmempool\", (int64_t) maxmempool);\n    ret.pushKV(\"mempoolminfee\", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK()));\n\n    return ret;\n}\n\nstatic UniValue getmempoolinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getmempoolinfo\\n\"\n            \"\\nReturns details on the active state of the TX memory pool.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"loaded\\\": xxxxx              (boolean) True if the mempool is fully loaded\\n\"\n            \"  \\\"size\\\": xxxxx,               (numeric) Current tx count\\n\"\n            \"  \\\"bytes\\\": xxxxx,              (numeric) Sum of all virtual transaction sizes.\\n\"\n            \"  \\\"usage\\\": xxxxx,              (numeric) Total memory usage for the mempool\\n\"\n            \"  \\\"maxmempool\\\": xxxxx,         (numeric) Maximum memory usage for the mempool\\n\"\n            \"  \\\"mempoolminfee\\\": xxxxx       (numeric) Minimum feerate (\" + CURRENCY_UNIT + \" per KB) for tx to be accepted\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmempoolinfo\", \"\")\n            + HelpExampleRpc(\"getmempoolinfo\", \"\")\n        );\n\n    return mempoolInfoToJSON();\n}\n\nstatic UniValue emptymempool(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"emptymempool\\n\"\n            \"\\nErase all transactions currently in the mempool, force mempool to empty.\\n\"\n        );\n\n    EmptyMempool(mempool);\n    return NullUniValue;\n}\n\nstatic UniValue preciousblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"preciousblock \\\"blockhash\\\"\\n\"\n            \"\\nTreats a block as if it were received before others with the same work.\\n\"\n            \"\\nA later preciousblock call can override the effect of an earlier one.\\n\"\n            \"\\nThe effects of preciousblock are not retained across restarts.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\"   (string, required) the hash of the block to mark as precious\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"preciousblock\", \"\\\"blockhash\\\"\")\n            + HelpExampleRpc(\"preciousblock\", \"\\\"blockhash\\\"\")\n        );\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n    CBlockIndex* pblockindex;\n\n    {\n        LOCK(cs_main);\n        if (mapBlockIndex.count(hash) == 0)\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n\n        pblockindex = mapBlockIndex[hash];\n    }\n\n    CValidationState state;\n    PreciousBlock(state, Params(), pblockindex);\n\n    if (!state.IsValid()) {\n        throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue invalidateblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"invalidateblock \\\"blockhash\\\"\\n\"\n            \"\\nPermanently marks a block as invalid, as if it violated a consensus rule.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\"   (string, required) the hash of the block to mark as invalid\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"invalidateblock\", \"\\\"blockhash\\\"\")\n            + HelpExampleRpc(\"invalidateblock\", \"\\\"blockhash\\\"\")\n        );\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n    CValidationState state;\n\n    {\n        LOCK(cs_main);\n        if (mapBlockIndex.count(hash) == 0)\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n\n        CBlockIndex* pblockindex = mapBlockIndex[hash];\n        InvalidateBlock(state, Params(), pblockindex);\n    }\n\n    if (state.IsValid()) {\n        ActivateBestChain(state, Params());\n    }\n\n    if (!state.IsValid()) {\n        throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue invalidateblocksatheight(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"invalidateblocksatheight \\\"height\\\"\\n\"\n            \"\\nPermanently marks all block candidates at a given height as invalid, as if it violated a consensus rule.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"block_height\\\"   (integet, required) the hash of the block to mark as invalid\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"invalidateblocksatheight\", \"\\\"300000\\\"\")\n            + HelpExampleRpc(\"invalidateblocksatheight\", \"\\\"300000\\\"\")\n        );\n\n    uint64_t nHeight = request.params[0].get_int();\n    \n    CValidationState state;\n    {\n        LOCK(cs_main);\n        while ((uint64_t)chainActive.Height() >= nHeight)\n        {\n            {\n                LOCK(cs_main);\n                if (!InvalidateBlock(state, Params(), chainActive[nHeight]))\n                    throw JSONRPCError(RPC_DATABASE_ERROR, \"failed to invalidate block\");\n            }\n            \n            if (state.IsValid())\n            {\n                ActivateBestChain(state, Params());\n            }\n            \n            if (!state.IsValid())\n            {\n                throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n            }\n        }\n    }\n    return NullUniValue;\n}\n\nstatic UniValue invalidateunwitnessedblocksatheight(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"invalidateunwitnessedblocksatheight \\\"height\\\"\\n\"\n            \"\\nPermanently marks all block candidates at a given height as invalid, as if it violated a consensus rule.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"block_height\\\"   (integet, required) the hash of the block to mark as invalid\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"invalidateunwitnessedblocksatheight\", \"\\\"300000\\\"\")\n            + HelpExampleRpc(\"invalidateunwitnessedblocksatheight\", \"\\\"300000\\\"\")\n        );\n\n    uint64_t nHeight = request.params[0].get_int();\n    \n    CValidationState state;\n    {\n        LOCK(cs_main);\n        while ((uint64_t)chainActive.Height() >= nHeight)\n        {\n            if (chainActive[nHeight]->nTimePoW2Witness > 0)\n                break;\n\n            {\n                LOCK(cs_main);\n                if (!InvalidateBlock(state, Params(), chainActive[nHeight]))\n                    throw JSONRPCError(RPC_DATABASE_ERROR, \"failed to invalidate block\");\n            }\n            \n            if (state.IsValid())\n            {\n                ActivateBestChain(state, Params());\n            }\n            \n            if (!state.IsValid())\n            {\n                throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n            }\n        }\n    }\n    return NullUniValue;\n}\n\nstatic UniValue reconsiderblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"reconsiderblock \\\"blockhash\\\"\\n\"\n            \"\\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\\n\"\n            \"This can be used to undo the effects of invalidateblock.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\"   (string, required) the hash of the block to reconsider\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"reconsiderblock\", \"\\\"blockhash\\\"\")\n            + HelpExampleRpc(\"reconsiderblock\", \"\\\"blockhash\\\"\")\n        );\n\n    std::string strHash = request.params[0].get_str();\n    uint256 hash(uint256S(strHash));\n\n    {\n        LOCK(cs_main);\n        if (mapBlockIndex.count(hash) == 0)\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n\n        CBlockIndex* pblockindex = mapBlockIndex[hash];\n        ResetBlockFailureFlags(pblockindex);\n    }\n\n    CValidationState state;\n    ActivateBestChain(state, Params());\n\n    if (!state.IsValid()) {\n        throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue getchaintxstats(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getchaintxstats ( num_blocks block_hash )\\n\"\n            \"\\nCompute statistics about the total number and rate of transactions in the chain.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. num_blocks     (numeric, optional) Size of the window in number of blocks (default: one month).\\n\"\n            \"2. \\\"block_hash\\\"   (string, optional) The hash of the block that ends the window.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"time\\\": xxxxx,        (numeric) The timestamp for the statistics in UNIX format.\\n\"\n            \"  \\\"txcount\\\": xxxxx,     (numeric) The total number of transactions in the chain up to that point.\\n\"\n            \"  \\\"txrate\\\": x.xx,       (numeric) The average rate of transactions per second in the window.\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getchaintxstats\", \"\")\n            + HelpExampleRpc(\"getchaintxstats\", \"2016\")\n        );\n\n    const CBlockIndex* pindex;\n    int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month\n\n    if (request.params.size() > 0 && !request.params[0].isNull()) {\n        blockcount = request.params[0].get_int();\n    }\n\n    bool havehash = request.params.size() > 1 && !request.params[1].isNull();\n    uint256 hash;\n    if (havehash) {\n        hash = uint256S(request.params[1].get_str());\n    }\n\n    {\n        LOCK(cs_main);\n        if (havehash) {\n            auto it = mapBlockIndex.find(hash);\n            if (it == mapBlockIndex.end()) {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n            }\n            pindex = it->second;\n            if (!chainActive.Contains(pindex)) {\n                throw JSONRPCError(RPC_INVALID_PARAMETER, \"Block is not in main chain\");\n            }\n        } else {\n            pindex = chainActive.Tip();\n        }\n    }\n\n    if (blockcount < 1 || blockcount >= pindex->nHeight) {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid block count: should be between 1 and the block's height\");\n    }\n\n    const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);\n    int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();\n    int nTxDiff = pindex->nChainTx - pindexPast->nChainTx;\n\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"time\", (int64_t)pindex->GetBlockTimePoW2Witness());\n    ret.pushKV(\"txcount\", (int64_t)pindex->nChainTx);\n    ret.pushKV(\"txrate\", ((double)nTxDiff) / nTimeDiff);\n\n    return ret;\n}\n\ntemplate<typename T>\nstatic T CalculateTruncatedMedian(std::vector<T>& scores)\n{\n    size_t size = scores.size();\n    if (size == 0) {\n        return 0;\n    }\n\n    std::sort(scores.begin(), scores.end());\n    if (size % 2 == 0) {\n        return (scores[size / 2 - 1] + scores[size / 2]) / 2;\n    } else {\n        return scores[size / 2];\n    }\n}\n\nstatic constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;\nvoid CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)\n{\n    if (scores.empty()) {\n        return;\n    }\n\n    std::sort(scores.begin(), scores.end());\n\n    // 10th, 25th, 50th, 75th, and 90th percentile weight units.\n    const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {\n        total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0\n    };\n\n    int64_t next_percentile_index = 0;\n    int64_t cumulative_weight = 0;\n    for (const auto& element : scores) {\n        cumulative_weight += element.second;\n        while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {\n            result[next_percentile_index] = element.first;\n            ++next_percentile_index;\n        }\n    }\n\n    // Fill any remaining percentiles with the last value.\n    for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {\n        result[i] = scores.back().first;\n    }\n}\n\ntemplate<typename T>\nstatic inline bool SetHasKeys(const std::set<T>& set) {return false;}\ntemplate<typename T, typename Tk, typename... Args>\nstatic inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)\n{\n    return (set.count(key) != 0) || SetHasKeys(set, args...);\n}\n\n// outpoint (needed for the utxo index) + nHeight + fCoinBase\nstatic constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);\n\nstatic CBlock GetBlockChecked(const CBlockIndex* pblockindex)\n{\n    CBlock block;\n    /*if (IsBlockPruned(pblockindex)) {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Block not available (pruned data)\");\n    }*/\n\n    if (!ReadBlockFromDisk(block, pblockindex, Params())) {\n        // Block not found on disk. This could be because we have the block\n        // header in our index but don't have the block (for example if a\n        // non-whitelisted node sends us an unrequested long chain of valid\n        // blocks, we add the headers to our index, but don't accept the\n        // block).\n        throw JSONRPCError(RPC_MISC_ERROR, \"Block not found on disk\");\n    }\n\n    return block;\n}\n\nstatic CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex)\n{\n    CBlockUndo blockUndo;\n    /*if (IsBlockPruned(pblockindex)) {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Undo data not available (pruned data)\");\n    }*/\n\n    if (!blockStore.UndoReadFromDisk(blockUndo, pblockindex->GetUndoPos(),pblockindex->pprev->GetBlockHashPoW2())) {\n        throw JSONRPCError(RPC_MISC_ERROR, \"Can't read undo data from disk\");\n    }\n\n    return blockUndo;\n}\n\nstatic UniValue getblockstats(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getblockstats \\\"hash_or_height\\\" \\\"stats\\\"\\n\"\n            \"\\nCompute per block statistics for a given window. All amounts are in satoshis.\\n\"\n        );\n    #if 0\n    RPCHelpMan{\"getblockstats \",\n                \"\\nCompute per block statistics for a given window. All amounts are in satoshis.\\n\"\n                \"It won't work for some heights with pruning.\\n\",\n                {\n                    {\"hash_or_height\", RPCArg::Type::NUM, RPCArg::Optional::NO, \"The block hash or height of the target block\", \"\", {\"\", \"string or numeric\"}},\n                    {\"stats\", RPCArg::Type::ARR, /* default */ \"all values\", \"Values to plot (see result below)\",\n                        {\n                            {\"height\", RPCArg::Type::STR, RPCArg::Optional::OMITTED, \"Selected statistic\"},\n                            {\"time\", RPCArg::Type::STR, RPCArg::Optional::OMITTED, \"Selected statistic\"},\n                        },\n                        \"stats\"},\n                },\n                RPCResult{\n            RPCResult::Type::OBJ, \"\", \"\",\n            {\n                {RPCResult::Type::NUM, \"avgfee\", \"Average fee in the block\"},\n                {RPCResult::Type::NUM, \"avgfeerate\", \"Average feerate (in satoshis per virtual byte)\"},\n                {RPCResult::Type::NUM, \"avgtxsize\", \"Average transaction size\"},\n                {RPCResult::Type::STR_HEX, \"blockhash\", \"The block hash (to check for potential reorgs)\"},\n                {RPCResult::Type::ARR_FIXED, \"feerate_percentiles\", \"Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)\",\n                {\n                    {RPCResult::Type::NUM, \"10th_percentile_feerate\", \"The 10th percentile feerate\"},\n                    {RPCResult::Type::NUM, \"25th_percentile_feerate\", \"The 25th percentile feerate\"},\n                    {RPCResult::Type::NUM, \"50th_percentile_feerate\", \"The 50th percentile feerate\"},\n                    {RPCResult::Type::NUM, \"75th_percentile_feerate\", \"The 75th percentile feerate\"},\n                    {RPCResult::Type::NUM, \"90th_percentile_feerate\", \"The 90th percentile feerate\"},\n                }},\n                {RPCResult::Type::NUM, \"height\", \"The height of the block\"},\n                {RPCResult::Type::NUM, \"ins\", \"The number of inputs (excluding coinbase)\"},\n                {RPCResult::Type::NUM, \"maxfee\", \"Maximum fee in the block\"},\n                {RPCResult::Type::NUM, \"maxfeerate\", \"Maximum feerate (in satoshis per virtual byte)\"},\n                {RPCResult::Type::NUM, \"maxtxsize\", \"Maximum transaction size\"},\n                {RPCResult::Type::NUM, \"medianfee\", \"Truncated median fee in the block\"},\n                {RPCResult::Type::NUM, \"mediantime\", \"The block median time past\"},\n                {RPCResult::Type::NUM, \"mediantxsize\", \"Truncated median transaction size\"},\n                {RPCResult::Type::NUM, \"minfee\", \"Minimum fee in the block\"},\n                {RPCResult::Type::NUM, \"minfeerate\", \"Minimum feerate (in satoshis per virtual byte)\"},\n                {RPCResult::Type::NUM, \"mintxsize\", \"Minimum transaction size\"},\n                {RPCResult::Type::NUM, \"outs\", \"The number of outputs\"},\n                {RPCResult::Type::NUM, \"subsidy\", \"The block subsidy\"},\n                {RPCResult::Type::NUM, \"swtotal_size\", \"Total size of all segwit transactions\"},\n                {RPCResult::Type::NUM, \"swtotal_weight\", \"Total weight of all segwit transactions divided by segwit scale factor (4)\"},\n                {RPCResult::Type::NUM, \"swtxs\", \"The number of segwit transactions\"},\n                {RPCResult::Type::NUM, \"time\", \"The block time\"},\n                {RPCResult::Type::NUM, \"total_out\", \"Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])\"},\n                {RPCResult::Type::NUM, \"total_size\", \"Total size of all non-coinbase transactions\"},\n                {RPCResult::Type::NUM, \"total_weight\", \"Total weight of all non-coinbase transactions divided by segwit scale factor (4)\"},\n                {RPCResult::Type::NUM, \"totalfee\", \"The fee total\"},\n                {RPCResult::Type::NUM, \"txs\", \"The number of transactions (excluding coinbase)\"},\n                {RPCResult::Type::NUM, \"utxo_increase\", \"The increase/decrease in the number of unspent outputs\"},\n                {RPCResult::Type::NUM, \"utxo_size_inc\", \"The increase/decrease in size for the utxo index (not discounting op_return and similar)\"},\n            }},\n                RPCExamples{\n                    HelpExampleCli(\"getblockstats\", \"1000 '[\\\"minfeerate\\\",\\\"avgfeerate\\\"]'\")\n            + HelpExampleRpc(\"getblockstats\", \"1000 '[\\\"minfeerate\\\",\\\"avgfeerate\\\"]'\")\n                },\n    }.Check(request);\n    #endif\n\n    LOCK(cs_main);\n\n    CBlockIndex* pindex;\n    if (request.params[0].isNum()) {\n        const int height = request.params[0].get_int();\n        const int current_tip = chainActive.Height();\n        if (height < 0) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Target block height %d is negative\", height));\n        }\n        if (height > current_tip) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Target block height %d after current tip %d\", height, current_tip));\n        }\n\n        pindex = chainActive[height];\n    } else {\n        const uint256 hash(ParseHashV(request.params[0], \"hash_or_height\"));\n        auto findIter = mapBlockIndex.find(hash);\n        if (findIter == mapBlockIndex.end()) {\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n        }\n        pindex = findIter->second;\n        if (!chainActive.Contains(pindex)) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Block is not in chain %s\", Params().NetworkIDString()));\n        }\n    }\n\n    if (pindex == nullptr)\n    {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid index\"));\n    }\n\n    std::set<std::string> stats;\n    if (!request.params[1].isNull()) {\n        const UniValue stats_univalue = request.params[1].get_array();\n        for (unsigned int i = 0; i < stats_univalue.size(); i++) {\n            const std::string stat = stats_univalue[i].get_str();\n            stats.insert(stat);\n        }\n    }\n\n    const CBlock block = GetBlockChecked(pindex);\n    const CBlockUndo blockUndo = GetUndoChecked(pindex);\n\n    const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)\n    const bool do_mediantxsize = do_all || stats.count(\"mediantxsize\") != 0;\n    const bool do_medianfee = do_all || stats.count(\"medianfee\") != 0;\n    const bool do_feerate_percentiles = do_all || stats.count(\"feerate_percentiles\") != 0;\n    const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||\n        SetHasKeys(stats, \"utxo_size_inc\", \"totalfee\", \"avgfee\", \"avgfeerate\", \"minfee\", \"maxfee\", \"minfeerate\", \"maxfeerate\");\n    const bool loop_outputs = do_all || loop_inputs || stats.count(\"total_out\");\n    const bool do_calculate_size = do_mediantxsize ||\n        SetHasKeys(stats, \"total_size\", \"avgtxsize\", \"mintxsize\", \"maxtxsize\", \"swtotal_size\");\n    const bool do_calculate_weight = do_all || SetHasKeys(stats, \"total_weight\", \"avgfeerate\", \"swtotal_weight\", \"avgfeerate\", \"feerate_percentiles\", \"minfeerate\", \"maxfeerate\");\n    const bool do_calculate_sw = do_all || SetHasKeys(stats, \"swtxs\", \"swtotal_size\", \"swtotal_weight\");\n\n    CAmount maxfee = 0;\n    CAmount maxfeerate = 0;\n    CAmount minfee = MAX_MONEY;\n    CAmount minfeerate = MAX_MONEY;\n    CAmount total_out = 0;\n    CAmount totalfee = 0;\n    int64_t inputs = 0;\n    int64_t maxtxsize = 0;\n    int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;\n    int64_t outputs = 0;\n    int64_t swtotal_size = 0;\n    int64_t swtotal_weight = 0;\n    int64_t swtxs = 0;\n    int64_t total_size = 0;\n    int64_t total_weight = 0;\n    int64_t utxo_size_inc = 0;\n    std::vector<CAmount> fee_array;\n    std::vector<std::pair<CAmount, int64_t>> feerate_array;\n    std::vector<int64_t> txsize_array;\n\n    for (size_t i = 0; i < block.vtx.size(); ++i) {\n        const auto& tx = block.vtx.at(i);\n        outputs += tx->vout.size();\n\n        CAmount tx_total_out = 0;\n        if (loop_outputs) {\n            for (const CTxOut& out : tx->vout) {\n                tx_total_out += out.nValue;\n                utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;\n            }\n        }\n\n        if (tx->IsCoinBase()) {\n            continue;\n        }\n\n        inputs += tx->vin.size(); // Don't count coinbase's fake input\n        total_out += tx_total_out; // Don't count coinbase reward\n\n        int64_t tx_size = 0;\n        if (do_calculate_size) {\n\n            tx_size = tx->GetTotalSize();\n            if (do_mediantxsize) {\n                txsize_array.push_back(tx_size);\n            }\n            maxtxsize = std::max(maxtxsize, tx_size);\n            mintxsize = std::min(mintxsize, tx_size);\n            total_size += tx_size;\n        }\n\n        int64_t weight = 0;\n        if (do_calculate_weight) {\n            weight = GetTransactionWeight(*tx);\n            total_weight += weight;\n        }\n\n        if (do_calculate_sw && tx->HasSegregatedSignatures()) {\n            ++swtxs;\n            swtotal_size += tx_size;\n            swtotal_weight += weight;\n        }\n\n        if (loop_inputs) {\n            CAmount tx_total_in = 0;\n            const auto& txundo = blockUndo.vtxundo.at(i - 1);\n            for (const Coin& coin: txundo.vprevout) {\n                const CTxOut& prevoutput = coin.out;\n\n                tx_total_in += prevoutput.nValue;\n                utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;\n            }\n\n            CAmount txfee = tx_total_in - tx_total_out;\n            if(!MoneyRange(txfee))\n            {\n                throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid fee\"));\n            }\n            \n            if (do_medianfee) {\n                fee_array.push_back(txfee);\n            }\n            maxfee = std::max(maxfee, txfee);\n            minfee = std::min(minfee, txfee);\n            totalfee += txfee;\n\n            // New feerate uses satoshis per virtual byte instead of per serialized byte\n            CAmount feerate = weight ? (txfee) / weight : 0;\n            if (do_feerate_percentiles) {\n                feerate_array.emplace_back(std::make_pair(feerate, weight));\n            }\n            maxfeerate = std::max(maxfeerate, feerate);\n            minfeerate = std::min(minfeerate, feerate);\n        }\n    }\n\n    CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };\n    CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);\n\n    UniValue feerates_res(UniValue::VARR);\n    for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {\n        feerates_res.push_back(feerate_percentiles[i]);\n    }\n\n    UniValue ret_all(UniValue::VOBJ);\n    ret_all.pushKV(\"avgfee\", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);\n    ret_all.pushKV(\"avgfeerate\", total_weight ? (totalfee) / total_weight : 0); // Unit: sat/vbyte\n    ret_all.pushKV(\"avgtxsize\", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);\n    ret_all.pushKV(\"blockhash\", pindex->GetBlockHashPoW2().GetHex());\n    ret_all.pushKV(\"feerate_percentiles\", feerates_res);\n    ret_all.pushKV(\"height\", (int64_t)pindex->nHeight);\n    ret_all.pushKV(\"ins\", inputs);\n    ret_all.pushKV(\"maxfee\", maxfee);\n    ret_all.pushKV(\"maxfeerate\", maxfeerate);\n    ret_all.pushKV(\"maxtxsize\", maxtxsize);\n    ret_all.pushKV(\"medianfee\", CalculateTruncatedMedian(fee_array));\n    ret_all.pushKV(\"mediantime\", pindex->GetMedianTimePast());\n    ret_all.pushKV(\"mediantxsize\", CalculateTruncatedMedian(txsize_array));\n    ret_all.pushKV(\"minfee\", (minfee == MAX_MONEY) ? 0 : minfee);\n    ret_all.pushKV(\"minfeerate\", (minfeerate == MAX_MONEY) ? 0 : minfeerate);\n    ret_all.pushKV(\"mintxsize\", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);\n    ret_all.pushKV(\"outs\", outputs);\n    ret_all.pushKV(\"subsidy\", GetBlockSubsidy(pindex->nHeight).total);\n    ret_all.pushKV(\"subsidy_mining\", GetBlockSubsidy(pindex->nHeight).mining);\n    ret_all.pushKV(\"subsidy_witness\", GetBlockSubsidy(pindex->nHeight).witness);\n    ret_all.pushKV(\"subsidy_dev\", GetBlockSubsidy(pindex->nHeight).dev);\n    ret_all.pushKV(\"swtotal_size\", swtotal_size);\n    ret_all.pushKV(\"swtotal_weight\", swtotal_weight);\n    ret_all.pushKV(\"swtxs\", swtxs);\n    ret_all.pushKV(\"time\", pindex->GetBlockTimePoW2Witness());\n    ret_all.pushKV(\"total_out\", total_out);\n    ret_all.pushKV(\"total_size\", total_size);\n    ret_all.pushKV(\"total_weight\", total_weight);\n    ret_all.pushKV(\"totalfee\", totalfee);\n    ret_all.pushKV(\"txs\", (int64_t)block.vtx.size());\n    ret_all.pushKV(\"utxo_increase\", outputs - inputs);\n    ret_all.pushKV(\"utxo_size_inc\", utxo_size_inc);\n\n    if (do_all) {\n        return ret_all;\n    }\n\n    UniValue ret(UniValue::VOBJ);\n    for (const std::string& stat : stats) {\n        const UniValue& value = ret_all[stat];\n        if (value.isNull()) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid selected statistic %s\", stat));\n        }\n        ret.pushKV(stat, value);\n    }\n    return ret;\n}\n\nstatic const CRPCCommand commands[] =\n{ //  category              name                      actor (function)         okSafe argNames\n  //  --------------------- ------------------------  -----------------------  ------ ----------\n    { \"blockchain\",         \"getblockchaininfo\",      &getblockchaininfo,      true,  {} },\n    { \"blockchain\",         \"getblockstats\",          &getblockstats,          true,  {\"hash_or_height\", \"stats\"} },\n    { \"blockchain\",         \"getchaintxstats\",        &getchaintxstats,        true,  {\"num_blocks\", \"block_hash\"} },\n    { \"blockchain\",         \"getbestblockhash\",       &getbestblockhash,       true,  {} },\n    { \"blockchain\",         \"getblockcount\",          &getblockcount,          true,  {} },\n    { \"blockchain\",         \"getblock\",               &getblock,               true,  {\"blockhash\",\"verbosity|verbose\"} },\n    { \"blockchain\",         \"decodeblock\",            &decodeblock,            true,  {\"blockhex\"} },\n    { \"blockchain\",         \"getblockhash\",           &getblockhash,           true,  {\"height\"} },\n    { \"blockchain\",         \"getblockheader\",         &getblockheader,         true,  {\"blockhash\",\"verbose\"} },\n    { \"blockchain\",         \"getchaintips\",           &getchaintips,           true,  {} },\n    { \"blockchain\",         \"getdifficulty\",          &getdifficulty,          true,  {} },\n    { \"blockchain\",         \"emptymempool\",           &emptymempool,           true,  {} },\n    { \"blockchain\",         \"getmempoolancestors\",    &getmempoolancestors,    true,  {\"txid\",\"verbose\"} },\n    { \"blockchain\",         \"getmempooldescendants\",  &getmempooldescendants,  true,  {\"txid\",\"verbose\"} },\n    { \"blockchain\",         \"getmempoolentry\",        &getmempoolentry,        true,  {\"txid\"} },\n    { \"blockchain\",         \"getmempoolinfo\",         &getmempoolinfo,         true,  {} },\n    { \"blockchain\",         \"getrawmempool\",          &getrawmempool,          true,  {\"verbose\"} },\n    { \"blockchain\",         \"gettxout\",               &gettxout,               true,  {\"txid\",\"n\",\"include_mempool\"} },\n    { \"blockchain\",         \"gettxoutsetinfo\",        &gettxoutsetinfo,        true,  {} },\n    { \"blockchain\",         \"pruneblockchain\",        &pruneblockchain,        true,  {\"height\"} },\n    { \"blockchain\",         \"verifychain\",            &verifychain,            true,  {\"check_level\",\"num_blocks\"} },\n\n    { \"blockchain\",         \"preciousblock\",          &preciousblock,          true,  {\"blockhash\"} },\n\n    /* Not shown in help */\n    { \"hidden\",             \"invalidateblock\",         &invalidateblock,         true,  {\"blockhash\"} },\n    { \"hidden\",             \"invalidateblocksatheight\",&invalidateblocksatheight,true,  {\"block_height\"} },\n    { \"hidden\",             \"invalidateunwitnessedblocksatheight\",&invalidateunwitnessedblocksatheight,true,  {\"block_height\"} },            \n    { \"hidden\",             \"reconsiderblock\",         &reconsiderblock,         true,  {\"blockhash\"} },\n    { \"hidden\",             \"waitfornewblock\",         &waitfornewblock,         true,  {\"timeout\"} },\n    { \"hidden\",             \"waitforblock\",            &waitforblock,            true,  {\"blockhash\",\"timeout\"} },\n    { \"hidden\",             \"waitforblockheight\",      &waitforblockheight,      true,  {\"height\",\"timeout\"} },\n    { \"hidden\",     \"syncwithvalidationinterfacequeue\", &syncwithvalidationinterfacequeue,          true,  {} },\n};\n\nvoid RegisterBlockchainRPCCommands(CRPCTable &t)\n{\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)\n        t.appendCommand(commands[vcidx].name, &commands[vcidx]);\n}\n"
  },
  {
    "path": "src/rpc/blockchain.h",
    "content": "// Copyright (c) 2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef RPC_BLOCKCHAIN_H\n#define RPC_BLOCKCHAIN_H\n\nclass CBlock;\nclass CBlockIndex;\nclass CScript;\nclass CTransaction;\nclass uint256;\nclass UniValue;\n\n/**\n * Get the difficulty of the net wrt to the given block index, or the chain tip if\n * not provided.\n *\n * @return A floating point number that is a multiple of the main net minimum\n * difficulty (4295032833 hashes).\n */\ndouble GetDifficulty(const CBlockIndex* blockindex = nullptr);\n\n/** Callback for when block tip changed. */\nvoid RPCNotifyBlockChange(bool ibd, const CBlockIndex *);\n\n/** Block description to JSON */\nUniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);\n\n/** Mempool information to JSON */\nUniValue mempoolInfoToJSON();\n\n/** Mempool to JSON */\nUniValue mempoolToJSON(bool fVerbose = false);\n\n/** Block header to JSON */\nUniValue blockheaderToJSON(const CBlockIndex* blockindex);\n\n#endif\n\n"
  },
  {
    "path": "src/rpc/client.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"rpc/client.h\"\n#include \"rpc/protocol.h\"\n#include \"util.h\"\n\n#include <set>\n#include <stdint.h>\n\n#include <univalue.h>\n\nclass CRPCConvertParam\n{\npublic:\n    std::string methodName; //!< method whose params want conversion\n    int paramIdx;           //!< 0-based idx of param to convert\n    std::string paramName;  //!< parameter name\n};\n\n/**\n * Specify a (method, idx, name) here if the argument is a non-string RPC\n * argument and needs to be converted from JSON.\n *\n * @note Parameter indexes start from 0.\n */\nstatic const CRPCConvertParam vRPCConvertParams[] =\n{\n    { \"setmocktime\", 0, \"timestamp\" },\n    { \"generate\", 0, \"num_blocks\" },\n    { \"generate\", 1, \"max_tries\" },\n    { \"generatetoaddress\", 0, \"num_blocks\" },\n    { \"generatetoaddress\", 2, \"max_tries\" },\n    { \"getnetworkhashps\", 0, \"num_blocks\" },\n    { \"getnetworkhashps\", 1, \"height\" },\n    { \"sendtoaddress\", 1, \"amount\" },\n    { \"sendtoaddress\", 4, \"subtract_fee_from_amount\" },\n    { \"settxfee\", 0, \"amount\" },\n    { \"getreceivedbyaddress\", 1, \"min_conf\" },\n    { \"getreceivedbyaccount\", 1, \"min_conf\" },\n    { \"listreceivedbyaddress\", 0, \"min_conf\" },\n    { \"listreceivedbyaddress\", 1, \"include_empty\" },\n    { \"listreceivedbyaddress\", 2, \"include_watchonly\" },\n    { \"listreceivedbyaccount\", 0, \"min_conf\" },\n    { \"listreceivedbyaccount\", 1, \"include_empty\" },\n    { \"listreceivedbyaccount\", 2, \"include_watchonly\" },\n    { \"getbalance\", 1, \"min_conf\" },\n    { \"getbalance\", 2, \"include_watchonly\" },\n    { \"getaccountbalances\", 0, \"min_conf\" },\n    { \"getaccountbalances\", 1, \"include_watchonly\" },\n    { \"getblockhash\", 0, \"height\" },\n    { \"invalidateblocksatheight\", 0, \"block_height\" },\n    { \"waitforblockheight\", 0, \"height\" },\n    { \"waitforblockheight\", 1, \"timeout\" },\n    { \"waitforblock\", 1, \"timeout\" },\n    { \"waitfornewblock\", 0, \"timeout\" },\n    { \"move\", 2, \"amount\" },\n    { \"move\", 3, \"min_conf\" },\n    { \"defrag\", 2, \"min_input_amount\" },\n    { \"defrag\", 3, \"max_input_amount\" },\n    { \"defrag\", 4, \"max_input_quantity\" },\n    { \"defrag\", 5, \"min_conf\" },\n    { \"sendfrom\", 2, \"amount\" },\n    { \"sendfrom\", 3, \"min_conf\" },\n    { \"listtransactions\", 1, \"count\" },\n    { \"listtransactions\", 2, \"skip\" },\n    { \"listtransactions\", 3, \"include_watchonly\" },\n    { \"walletpassphrase\", 1, \"timeout\" },\n    { \"getblocktemplate\", 0, \"template_request\" },\n    { \"listsinceblock\", 1, \"target_confirmations\" },\n    { \"listsinceblock\", 2, \"include_watchonly\" },\n    { \"sendmany\", 1, \"amounts\" },\n    { \"sendmany\", 2, \"min_conf\" },\n    { \"sendmany\", 4, \"subtract_fee_from\" },\n    { \"addmultisigaddress\", 0, \"num_required\" },\n    { \"addmultisigaddress\", 1, \"keys\" },\n    { \"createmultisig\", 0, \"num_required\" },\n    { \"createmultisig\", 1, \"keys\" },\n    { \"listunspent\", 0, \"min_conf\" },\n    { \"listunspent\", 1, \"max_conf\" },\n    { \"listunspent\", 2, \"addresses\" },\n    { \"listunspent\", 4, \"query_options\" },\n    { \"listunspentforaccount\", 1, \"min_conf\" },\n    { \"listunspentforaccount\", 2, \"max_conf\" },\n    { \"listunspentforaccount\", 3, \"addresses\" },\n    { \"listunspentforaccount\", 5, \"query_options\" },\n    { \"getblock\", 1, \"verbosity\" },\n    { \"getblockheader\", 1, \"verbose\" },\n    { \"getchaintxstats\", 0, \"num_blocks\" },\n    { \"gettransaction\", 1, \"include_watchonly\" },\n    { \"getrawtransaction\", 1, \"verbose\" },\n    { \"createrawtransaction\", 0, \"inputs\" },\n    { \"createrawtransaction\", 1, \"outputs\" },\n    { \"createrawtransaction\", 2, \"lock_time\" },\n    { \"createrawtransaction\", 3, \"opt_in_to_rbf\" },\n    { \"signrawtransaction\", 1, \"prev_txs\" },\n    { \"signrawtransaction\", 2, \"priv_keys\" },\n    { \"sendrawtransaction\", 1, \"allow_high_fees\" },\n    { \"fundrawtransaction\", 2, \"options\" },\n    { \"gettxout\", 1, \"n\" },\n    { \"gettxout\", 2, \"include_mempool\" },\n    { \"gettxoutproof\", 0, \"txids\" },\n    { \"lockunspent\", 0, \"unlock\" },\n    { \"lockunspent\", 1, \"transactions\" },\n    { \"importprivkey\", 2, \"rescan\" },\n    { \"importaddress\", 2, \"rescan\" },\n    { \"importaddress\", 3, \"p2sh\" },\n    { \"importpubkey\", 2, \"rescan\" },\n    { \"importmulti\", 1, \"requests\" },\n    { \"importmulti\", 2, \"options\" },\n    { \"verifychain\", 0, \"check_level\" },\n    { \"verifychain\", 1, \"num_blocks\" },\n    { \"getblockstats\", 0, \"hash_or_height\" },\n    { \"getblockstats\", 1, \"stats\" },\n    { \"pruneblockchain\", 0, \"height\" },\n    { \"keypoolrefill\", 0, \"new_size\" },\n    { \"getrawmempool\", 0, \"verbose\" },\n    { \"estimatefee\", 0, \"num_blocks\" },\n    { \"estimatesmartfee\", 0, \"num_blocks\" },\n    { \"estimaterawfee\", 0, \"num_blocks\" },\n    { \"estimaterawfee\", 1, \"threshold\" },\n    { \"estimaterawfee\", 2, \"horizon\" },\n    { \"prioritisetransaction\", 1, \"dummy\" },\n    { \"prioritisetransaction\", 2, \"fee_delta\" },\n    { \"setban\", 2, \"ban_time\" },\n    { \"setban\", 3, \"absolute\" },\n    { \"setnetworkactive\", 0, \"state\" },\n    { \"getmempoolancestors\", 1, \"verbose\" },\n    { \"getmempooldescendants\", 1, \"verbose\" },\n    { \"bumpfee\", 1, \"options\" },\n    { \"logging\", 0, \"include\" },\n    { \"logging\", 1, \"exclude\" },\n    { \"disconnectnode\", 1, \"node_id\" },\n    // Echo with conversion (For testing only)\n    { \"echojson\", 0, \"arg0\" },\n    { \"echojson\", 1, \"arg1\" },\n    { \"echojson\", 2, \"arg2\" },\n    { \"echojson\", 3, \"arg3\" },\n    { \"echojson\", 4, \"arg4\" },\n    { \"echojson\", 5, \"arg5\" },\n    { \"echojson\", 6, \"arg6\" },\n    { \"echojson\", 7, \"arg7\" },\n    { \"echojson\", 8, \"arg8\" },\n    { \"echojson\", 9, \"arg9\" },\n    { \"setgenerate\", 0, \"generate\" },\n    { \"setgenerate\", 1, \"gen_proc_limit\" },\n    { \"setgenerate\", 2, \"gen_arena_proc_limit\" },\n    { \"deleteseed\", 1, \"should_purge_accounts\" },\n    { \"importseed\", 2, \"is_read_only\" },\n    { \"importwitnesskeys\", 2, \"create_account\" },\n    { \"importwitnesskeys\", 3, \"rescan\" },\n    { \"splitwitnessaccount\", 2, \"amounts\" },\n    { \"setwitnesscompound\", 1, \"amount\" },\n    { \"getwitnessinfo\", 1, \"verbose\" },\n    { \"getwitnessinfo\", 2, \"mine_only\" },\n    { \"fundwitnessaccount\", 4, \"force_multiple\" },\n    { \"setwitnessrewardscript\", 2, \"force_pubkey\" },\n    { \"setwitnessrewardtemplate\", 1, \"reward_template\" },\n    { \"sethashlimit\", 0, \"limit\" },\n    { \"getlastblocks\", 0, \"num_blocks\" },\n    { \"dumpdiffarray\", 0, \"height\" },\n    { \"dumpblockgaps\", 0, \"start_height\" },\n    { \"dumpblockgaps\", 1, \"count\" },\n    { \"dumptransactionstats\", 0, \"start_height\" },\n    { \"dumptransactionstats\", 1, \"count\" },\n    { \"sendtoaddressfromaccount\", 2, \"amount\" },\n    { \"sendtoaddressfromaccount\", 5, \"subtract_fee_from_amount\" },\n};\n\nclass CRPCConvertTable\n{\nprivate:\n    std::set<std::pair<std::string, int>> members;\n    std::set<std::pair<std::string, std::string>> membersByName;\n\npublic:\n    CRPCConvertTable();\n\n    bool convert(const std::string& method, int idx) {\n        return (members.count(std::pair(method, idx)) > 0);\n    }\n    bool convert(const std::string& method, const std::string& name) {\n        return (membersByName.count(std::pair(method, name)) > 0);\n    }\n};\n\nCRPCConvertTable::CRPCConvertTable()\n{\n    const unsigned int n_elem =\n        (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));\n\n    for (unsigned int i = 0; i < n_elem; i++) {\n        members.insert(std::pair(vRPCConvertParams[i].methodName,\n                                      vRPCConvertParams[i].paramIdx));\n        membersByName.insert(std::pair(vRPCConvertParams[i].methodName,\n                                            vRPCConvertParams[i].paramName));\n    }\n}\n\nstatic CRPCConvertTable rpcCvtTable;\n\n/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)\n * as well as objects and arrays.\n */\nUniValue ParseNonRFCJSONValue(const std::string& strVal)\n{\n    UniValue jVal;\n    if (!jVal.read(std::string(\"[\")+strVal+std::string(\"]\")) ||\n        !jVal.isArray() || jVal.size()!=1)\n        throw std::runtime_error(std::string(\"Error parsing JSON:\")+strVal);\n    return jVal[0];\n}\n\nUniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)\n{\n    UniValue params(UniValue::VARR);\n\n    for (unsigned int idx = 0; idx < strParams.size(); idx++) {\n        const std::string& strVal = strParams[idx];\n\n        if (!rpcCvtTable.convert(strMethod, idx)) {\n            // insert string value directly\n            params.push_back(strVal);\n        } else {\n            // parse string as JSON, insert bool/number/object/etc. value\n            params.push_back(ParseNonRFCJSONValue(strVal));\n        }\n    }\n\n    return params;\n}\n\nUniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)\n{\n    UniValue params(UniValue::VOBJ);\n\n    for (const std::string &s: strParams) {\n        size_t pos = s.find(\"=\");\n        if (pos == std::string::npos) {\n            throw(std::runtime_error(\"No '=' in named argument '\"+s+\"', this needs to be present for every argument (even if it is empty)\"));\n        }\n\n        std::string name = s.substr(0, pos);\n        std::string value = s.substr(pos+1);\n\n        if (!rpcCvtTable.convert(strMethod, name)) {\n            // insert string value directly\n            params.pushKV(name, value);\n        } else {\n            // parse string as JSON, insert bool/number/object/etc. value\n            params.pushKV(name, ParseNonRFCJSONValue(value));\n        }\n    }\n\n    return params;\n}\n"
  },
  {
    "path": "src/rpc/client.h",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef RPCCLIENT_H\n#define RPCCLIENT_H\n\n#include <univalue.h>\n\n/** Convert positional arguments to command-specific RPC representation */\nUniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);\n\n/** Convert named arguments to command-specific RPC representation */\nUniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<std::string>& strParams);\n\n/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)\n * as well as objects and arrays.\n */\nUniValue ParseNonRFCJSONValue(const std::string& strVal);\n\n#endif\n"
  },
  {
    "path": "src/rpc/mining.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"base58.h\"\n#include \"amount.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/params.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"validation/validationinterface.h\"\n#include \"validation/versionbitsvalidation.h\"\n#include \"core_io.h\"\n#include \"init.h\"\n#include \"versionbits.h\"\n#include \"generation/miner.h\"\n#include \"net.h\"\n#include \"policy/fees.h\"\n#include \"pow/pow.h\"\n#include \"rpc/blockchain.h\"\n#include \"rpc/server.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"arith_uint256.h\"\n#include \"warnings.h\"\n#include \"witnessutil.h\"\n#include <compat/sys.h>\n\n#include <memory>\n#include <stdint.h>\n\n#include <univalue.h>\n#ifdef ENABLE_WALLET\n#include \"wallet/account.h\"\n#include \"wallet/wallet.h\"\n#include \"wallet/rpcwallet.h\"\n#endif\n#include \"generation/generation.h\"\n#include \"script/script.h\"\n#include <rpc/accounts.h>\n#include <validation/witnessvalidation.h>\n\n#include <boost/algorithm/string/predicate.hpp> // for ends_with()\n#include <boost/uuid/uuid.hpp>\n\n/**\n * Return average network hashes per second based on the last 'lookup' blocks,\n * or from the last difficulty change if 'lookup' is nonpositive.\n * If 'height' is nonnegative, compute the estimate at the time when a given block was found.\n */\nstatic UniValue GetNetworkHashPS(uint32_t lookup, int height)\n{\n    CBlockIndex *pb = chainActive.Tip();\n\n    if (height >= 0 && height < chainActive.Height())\n        pb = chainActive[height];\n\n    if (pb == NULL || !pb->nHeight)\n        return 0;\n\n    // If lookup is larger than chain, then set it to chain length.\n    if (lookup > (uint32_t)pb->nHeight)\n        lookup = (uint32_t)pb->nHeight;\n    \n    bool sigmaActive=false;\n    if (pb->nTime >= defaultSigmaSettings.activationDate)\n    {\n        sigmaActive = true;\n    }\n        \n\n    CBlockIndex *pb0 = pb;\n    int64_t minTime = pb0->GetBlockTime();\n    int64_t maxTime = minTime;\n    uint64_t count = 0;\n    arith_uint256 workDiff = 0;\n    for (uint32_t i = 0; i < lookup; i++)\n    {\n        if (sigmaActive && pb0->pprev->nTime < defaultSigmaSettings.activationDate)\n            break;\n        workDiff += GetBlockProof(*pb0);\n        count++;\n        pb0 = pb0->pprev;\n        int64_t time = pb0->GetBlockTime();\n        minTime = std::min(time, minTime);\n        maxTime = std::max(time, maxTime);\n    }\n\n    // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.\n    if (minTime == maxTime)\n        return 0;\n\n\n    int64_t timeDiff = maxTime - minTime;\n\n    if (sigmaActive)\n    {\n        // SIGMA: Not 100% clear that this is the best we can do or if we can approximate a better estimate, this seems to be a reasonable approximation for now.\n        // What we report to the user as 'hashes' are actually 'half hashes' (see sigma_bench to understand the distinction)\n        // So to match up we have to try approximate half hashes here as well instead of hashes.\n        // We can achieve this by squaring the individual chain works.\n        workDiff = workDiff/count;\n        workDiff = workDiff*workDiff;\n        workDiff *= count;\n    }\n    return (workDiff.getdouble() / timeDiff);\n}\n\nstatic UniValue getnetworkhashps(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getnetworkhashps ( nblocks height )\\n\"\n            \"\\nReturns the estimated network hashes per second based on the last n blocks.\\n\"\n            \"Pass in [blocks] to override # of blocks.\\n\"\n            \"Pass in [height] to estimate the network speed at the time when a certain block was found.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. nblocks     (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\\n\"\n            \"2. height      (numeric, optional, default=-1) To estimate at the time of the given height.\\n\"\n            \"\\nResult:\\n\"\n            \"x             (numeric) Hashes per second estimated\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getnetworkhashps\", \"\")\n            + HelpExampleRpc(\"getnetworkhashps\", \"\")\n       );\n\n    LOCK(cs_main);\n    int64_t lookup = request.params.size() > 0 ? request.params[0].get_int() : 120;\n    if (lookup < 0)\n        lookup = 120;\n\n    return GetNetworkHashPS(lookup, request.params.size() > 1 ? request.params[1].get_int() : -1);\n}\n\nextern void TryPopulateAndSignWitnessBlock(CBlockIndex* candidateIter, CChainParams& chainparams, Consensus::Params& consensusParams, CGetWitnessInfo witnessInfo, std::shared_ptr<CBlock> pWitnessBlock, std::map<boost::uuids::uuid, std::shared_ptr<CReserveKeyOrScript>>& reserveKeys, bool& encounteredError, bool& signedBlock);\n\nstatic UniValue generateBlocks(std::shared_ptr<CReserveKeyOrScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)\n{\n    static const int nInnerLoopCount = 0x10000;\n    int nHeightEnd = 0;\n    int nHeight = 0;\n\n    std::map<boost::uuids::uuid, std::shared_ptr<CReserveKeyOrScript>> reservedKeys;\n    \n    {   // Don't keep cs_main locked\n        LOCK(cs_main);\n        nHeight = chainActive.Height();\n        nHeightEnd = nHeight+nGenerate;\n    }\n    unsigned int nExtraNonce = 0;\n    UniValue blockHashes(UniValue::VARR);\n    while (nHeight < nHeightEnd)\n    {\n        std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(chainActive.Tip(), coinbaseScript));\n        if (!pblocktemplate.get())\n            throw JSONRPCError(RPC_INTERNAL_ERROR, \"Couldn't create new block\");\n        CBlock *pblock = &pblocktemplate->block;\n        {\n            LOCK(cs_main);\n            IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);\n        }\n        while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock, Params().GetConsensus())) {\n            ++pblock->nNonce;\n            --nMaxTries;\n        }\n        if (nMaxTries == 0) {\n            break;\n        }\n        if (pblock->nNonce == nInnerLoopCount) {\n            continue;\n        }\n\n        CChainParams chainparams = Params();\n        Consensus::Params consensus = chainparams.GetConsensus();\n        CGetWitnessInfo witnessInfo;\n        if (Params().IsRegtest())\n        {\n            if (!GetWitness(chainActive, chainparams, nullptr, chainActive.Tip(), *pblock, witnessInfo))\n            {\n                throw JSONRPCError(RPC_INTERNAL_ERROR, \"Unable to get witness for block\");\n            }\n        }\n            \n        std::shared_ptr<CBlock> shared_pblock = std::make_shared<CBlock>(*pblock);\n        if (!ProcessNewBlock(Params(), shared_pblock, true, NULL, false, true))\n            throw JSONRPCError(RPC_INTERNAL_ERROR, \"ProcessNewBlock, PoW block not accepted\");\n        \n        // Perform witnessing\n        if (Params().IsRegtest())\n        {   \n            bool encounteredError=false;\n            bool signedBlock=false;\n            TryPopulateAndSignWitnessBlock(chainActive.Tip(), chainparams, consensus, witnessInfo, shared_pblock, reservedKeys, encounteredError, signedBlock);\n            if (encounteredError || !signedBlock)\n                throw JSONRPCError(RPC_INTERNAL_ERROR, \"Unable to witness block\");\n            \n            if (!ProcessNewBlock(Params(), shared_pblock, true, NULL, false, true))\n                throw JSONRPCError(RPC_INTERNAL_ERROR, \"ProcessNewBlock, witness block not accepted\");\n        }\n        \n        ++nHeight;\n        blockHashes.push_back(pblock->GetHashLegacy().GetHex());\n\n        //mark script as important because it was used at least for one coinbase output if the script came from the wallet\n        if (keepScript)\n        {\n            coinbaseScript->KeepScript();\n        }\n    }\n    return blockHashes;\n}\n\nvoid InitRPCMining()\n{\n}\n\nvoid ShutdownRPCMining()\n{\n}\n\nstatic UniValue getgenerate(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getgenerate\\n\"\n            \"\\nReturn if the server is set to generate coins or not. The default is false.\\n\"\n            \"It is set with the command line argument -gen (or \" + std::string(DEFAULT_CONF_FILENAME) + \" setting gen)\\n\"\n            \"It can also be set with the setgenerate call.\\n\"\n            \"\\nResult\\n\"\n            \"true|false      (boolean) If the server is set to generate coins or not\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getgenerate\", \"\")\n            + HelpExampleRpc(\"getgenerate\", \"\")\n        );\n\n    LOCK(cs_main);\n    return PoWGenerationIsActive();\n}\n\nstatic UniValue generate(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)\n        throw std::runtime_error(\n            \"generate num_blocks ( max_tries )\\n\"\n            \"\\ngenerate up to n blocks immediately (before the RPC call returns)\\n\"\n            \"\\nArguments:\\n\"\n            \"1. nblocks      (numeric, required) How many blocks are generated immediately.\\n\"\n            \"2. maxtries     (numeric, optional) How many iterations to try (default = 1000000).\\n\"\n            \"3. account      (string, optional) The UUID or unique label of the account.\\n\"\n            \"\\nResult:\\n\"\n            \"[ blockhashes ]     (array) hashes of blocks generated\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nGenerate 11 blocks\\n\"\n            + HelpExampleCli(\"generate\", \"11\")\n        );\n\n    if (!Params().IsRegtest())\n        throw std::runtime_error(\"generate command only for regtest; for mainnet/testnet use setgenerate\");\n\n    int nGenerate = request.params[0].get_int();\n    uint64_t nMaxTries = 1000000;\n    if (request.params.size() > 1) {\n        nMaxTries = request.params[1].get_int();\n    }\n\n    CAccount* forAccount = nullptr;\n\n#ifdef ENABLE_WALLET\n    if (request.params.size() > 2)\n        forAccount = AccountFromValue(pactiveWallet, request.params[2], false);\n    else {\n        if (!pactiveWallet->activeAccount)\n            throw std::runtime_error(\"No active account selected, first select an active account.\");\n        forAccount = pactiveWallet->activeAccount;\n    }\n\n    if (forAccount->IsPoW2Witness())\n        throw std::runtime_error(\"Witness account selected, first select a regular account as the active account or specifiy a regular account.\");\n#endif\n\n    std::shared_ptr<CReserveKeyOrScript> coinbaseScript;\n    GetMainSignals().ScriptForMining(coinbaseScript, forAccount);\n\n    // If the keypool is exhausted, no script is returned at all.  Catch this.\n    if (!coinbaseScript)\n        throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n\n    //throw an error if no script was provided\n    if (coinbaseScript->reserveScript.empty())\n        throw JSONRPCError(RPC_INTERNAL_ERROR, \"No coinbase script available; a wallet is required\");\n\n    return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);\n}\n\nstatic UniValue setgenerate(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n    \n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 5)\n        throw std::runtime_error(\n            \"setgenerate generate ( gen_proc_limit )\\n\"\n            \"\\nSet 'generate' true or false to turn generation on or off.\\n\"\n            \"Generation is limited to 'gen_proc_limit' processors, -1 is unlimited.\\n\"\n            \"Arena setup is limited to 'gen_arena_proc_limit' processors, -1 is unlimited, takes the value of 'gen_proc_limit' if not explicitely set.\\n\"\n            \"See the getgenerate call for the current setting.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. generate             (boolean, required) Set to true to turn on generation, off to turn off.\\n\"\n            \"2. gen_proc_limit       (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\\n\"\n            \"3. gen_arena_proc_limit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\\n\"\n            \"4. gen_memory_limit     (string, optional) How much system memory to use, specify a letter G/M/K/B to determine size e.g. 524288K (Kilobytes), 512M (Megabytes), 3G (Gigabytes).\\n\"\n            \"5. account              (string, optional) The UUID or unique label of the account.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nSet the generation on with a limit of one processor\\n\"\n            + HelpExampleCli(\"setgenerate\", \"true 1\") +\n            \"\\nCheck the setting\\n\"\n            + HelpExampleCli(\"getgenerate\", \"\") +\n            \"\\nTurn off generation\\n\"\n            + HelpExampleCli(\"setgenerate\", \"false\") +\n            \"\\nUsing json rpc\\n\"\n            + HelpExampleRpc(\"setgenerate\", \"true, 1\")\n        );\n\n    if (Params().MineBlocksOnDemand())\n        throw JSONRPCError(RPC_METHOD_NOT_FOUND, \"Use the generate method instead of setgenerate on this network\");\n\n    #ifdef ENABLE_WALLET\n    if (!pwallet)\n    {\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n    }\n    \n    bool fGenerate = true;\n    if (request.params.size() > 0)\n    {\n        fGenerate = request.params[0].get_bool();\n    }\n    \n    int nGenProcLimit = GetArg(\"-genproclimit\", DEFAULT_GENERATE_THREADS);\n    if (request.params.size() > 1)\n    {\n        nGenProcLimit = request.params[1].get_int();\n        if (nGenProcLimit == 0)\n        {\n            fGenerate = false;\n        }\n    }\n    \n    int nGenArenaProcLimit = GetArg(\"-genarenaproclimit\", DEFAULT_GENERATE_THREADS);\n    if (request.params.size() > 2)\n    {\n        nGenArenaProcLimit = request.params[2].get_int();\n        if (nGenArenaProcLimit == 0)\n        {\n            fGenerate = false;\n        }\n    }\n    \n    if (!fGenerate)\n    {\n        std::thread([=]\n        {\n            PoWStopGeneration();\n        }).detach();\n        return \"Block generation disabled.\";\n    }\n\n    \n    CAccount* forAccount = nullptr;\n    if (request.params.size() > 4 && request.params[4].get_str().length()>0)\n    {\n        forAccount = AccountFromValue(pactiveWallet, request.params[4], false);\n        if (forAccount && forAccount->IsPoW2Witness())\n        {\n            throw std::runtime_error(\"Witness account selected, first select a regular account as the active account or specify a regular account.\");\n        }\n    }\n    \n    std::string overrideAccountAddress;\n    if (!forAccount)\n    {\n        for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n        {\n            (unused) accountUUID;\n            if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n            {\n                forAccount = account;\n                break;\n            }\n        }\n        CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(overrideAccountAddress);\n    }\n    \n    if (!forAccount)\n    {\n        throw std::runtime_error(\"No mining account present in wallet. Create a mining account using `createminingaccount` or pass an explicit target account to yout `setgenerate` call.\");\n    }\n\n    // Try to avoid swap by never using more than sysmem-1gb or on machines with only 1gb of memory sysmem-512mb.\n    uint64_t systemMemory = systemPhysicalMemoryInBytes();\n    if (systemMemory > 1 * 1024 * 1024 * 1024)\n    {\n        systemMemory -= 1 * 1024 * 1024 * 1024;\n    }\n    else if (systemMemory > 512 * 1024 * 1024)\n    {\n        systemMemory -= 512 * 1024 * 1024;\n    }\n    else if (systemMemory > 256 * 1024 * 1024)\n    {\n        systemMemory -= 256 * 1024 * 1024;\n    }\n    else if (systemMemory > 128 * 1024 * 1024)\n    {\n        systemMemory -= 128 * 1024 * 1024;\n    }\n\n    // Allow user to override default memory selection.\n    uint64_t nGenMemoryLimitBytes = std::min(systemMemory, defaultSigmaSettings.arenaSizeKb*1024);\n    if (request.params.size() > 3)\n    {\n        std::string sMemLimit = request.params[3].get_str();\n        nGenMemoryLimitBytes = GetMemLimitInBytesFromFormattedStringSpecifier(sMemLimit);\n    }\n    \n    // Normalise for SIGMA arena expectations (arena size must be a multiple of 16mb)\n    normaliseBufferSize(nGenMemoryLimitBytes);\n    \n    SoftSetArg(\"-genproclimit\", itostr(nGenProcLimit));\n    SoftSetArg(\"-genarenaproclimit\", itostr(nGenArenaProcLimit));\n    SoftSetArg(\"-genmemlimit\", i64tostr(nGenMemoryLimitBytes/1024));\n    std::thread([=]\n    {\n        try\n        {\n            PoWGenerateBlocks(true, nGenProcLimit, nGenArenaProcLimit, nGenMemoryLimitBytes/1024, Params(), forAccount, overrideAccountAddress);\n        }\n        catch(...)\n        {\n        }\n    }).detach();\n    \n    if (overrideAccountAddress.length() > 0)\n    {\n        return strprintf(\"Block generation enabled into account [%s] using target address [%s], thread limit: [%d threads], memory: [%d Mb].\", pwallet->mapAccountLabels[forAccount->getUUID()], overrideAccountAddress ,nGenProcLimit, nGenMemoryLimitBytes/1024/1024);\n    }\n    else\n    {\n        return strprintf(\"Block generation enabled into account [%s], thread limit: [%d threads], memory: [%d Mb].\", pwallet->mapAccountLabels[forAccount->getUUID()] ,nGenProcLimit, nGenMemoryLimitBytes/1024/1024);\n    }\n    #else\n    throw std::runtime_error(\"Cannot use command without an active wallet\");\n    return nullptr;\n    #endif\n}\n\nstatic UniValue generatetoaddress(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)\n        throw std::runtime_error(\n            \"generatetoaddress num_blocks address (max_tries)\\n\"\n            \"\\nGenerate blocks immediately to a specified address (before the RPC call returns)\\n\"\n            \"\\nArguments:\\n\"\n            \"1. nblocks      (numeric, required) How many blocks are generated immediately.\\n\"\n            \"2. address      (string, required) The address to send the newly generated \" GLOBAL_APPNAME \" to.\\n\"\n            \"3. maxtries     (numeric, optional) How many iterations to try (default = 1000000).\\n\"\n            \"\\nResult:\\n\"\n            \"[ blockhashes ]     (array) hashes of blocks generated\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nGenerate 11 blocks to myaddress\\n\"\n            + HelpExampleCli(\"generatetoaddress\", \"11 \\\"myaddress\\\"\")\n        );\n\n    if (!Params().IsRegtest() && !Params().IsRegtestLegacy())\n        throw std::runtime_error(\"generatetoaddress command only for regtest; for mainnet/testnet use setgenerate\");\n\n    int nGenerate = request.params[0].get_int();\n    uint64_t nMaxTries = 1000000;\n    if (request.params.size() > 2) {\n        nMaxTries = request.params[2].get_int();\n    }\n\n    CNativeAddress address(request.params[1].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Error: Invalid address\");\n\n    std::shared_ptr<CReserveKeyOrScript> coinbaseScript = std::make_shared<CReserveKeyOrScript>();\n    coinbaseScript->reserveScript = GetScriptForDestination(address.Get());\n\n    return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);\n}\n\nstatic UniValue getmininginfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getmininginfo\\n\"\n            \"\\nReturns a json object containing information about block generation.\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"blocks\\\": nnn,             (numeric) The current block\\n\"\n            \"  \\\"currentblocksize\\\": nnn,   (numeric) The last block size\\n\"\n            \"  \\\"currentblockweight\\\": nnn, (numeric) The last block weight\\n\"\n            \"  \\\"currentblocktx\\\": nnn,     (numeric) The last block transaction\\n\"\n            \"  \\\"difficulty\\\": xxx.xxxxx    (numeric) The current difficulty\\n\"\n            \"  \\\"errors\\\": \\\"...\\\"            (string) Current errors\\n\"\n            \"  \\\"networkhashps\\\": nnn,      (numeric) The network hashes per second\\n\"\n            \"  \\\"generate\\\": true|false     (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\\n\"\n            \"  \\\"genproclimit\\\": n          (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\\n\"\n            \"  \\\"genmemlimit\\\": n           (numeric) The memory limit for generation; In Kilobytes. (see getgenerate or setgenerate calls)\\n\"\n            \"  \\\"pooledtx\\\": n              (numeric) The size of the mempool\\n\"\n            \"  \\\"chain\\\": \\\"xxxx\\\",           (string) current network name as defined in BIP70 (main, test, regtest)\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmininginfo\", \"\")\n            + HelpExampleRpc(\"getmininginfo\", \"\")\n        );\n\n\n    LOCK(cs_main);\n\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"blocks\",                           (int)chainActive.Height());\n    obj.pushKV(\"currentblocksize\",                 (uint64_t)nLastBlockSize);\n    obj.pushKV(\"currentblockweight\",               (uint64_t)nLastBlockWeight);\n    obj.pushKV(\"currentblocktx\",                   (uint64_t)nLastBlockTx);\n    obj.pushKV(\"difficulty\",                       (double)GetDifficulty());\n    obj.pushKV(\"errors\",                           GetWarnings(\"statusbar\"));\n    obj.pushKV(\"genproclimit\",                     (int)GetArg(\"-genproclimit\", DEFAULT_GENERATE_THREADS));\n    obj.pushKV(\"genmemlimit\",                      (uint64_t)GetArg(\"-genmemlimit\", DEFAULT_GENERATE_THREADS));\n    obj.pushKV(\"networkhashps\",                    getnetworkhashps(request));\n    obj.pushKV(\"pooledtx\",                         (uint64_t)mempool.size());\n    obj.pushKV(\"chain\",                            Params().NetworkIDString());\n    obj.pushKV(\"selected_shavite_implementation\",  selectedAlgorithmName(gSelShavite));\n    obj.pushKV(\"selected_argon_implementation\",    selectedAlgorithmName(gSelArgon));\n    obj.pushKV(\"selected_echo_implementation\",     selectedAlgorithmName(gSelEcho));\n    return obj;\n}\n\n\n// NOTE: Unlike wallet RPC (which use NLG values), mining RPCs follow GBT (BIP 22) in using satoshi amounts\nstatic UniValue prioritisetransaction(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 3)\n        throw std::runtime_error(\n            \"prioritisetransaction <txid> <dummy_value> <fee_delta>\\n\"\n            \"Accepts the transaction into generated blocks at a higher (or lower) priority\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"         (string, required) The transaction id.\\n\"\n            \"2. dummy_value    (numeric, optional) API-Compatibility for previous API. Must be zero or null.\\n\"\n            \"                  DEPRECATED. For forward compatibility use named arguments and omit this parameter.\\n\"\n            \"3. fee_delta      (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\\n\"\n            \"                  The fee is not actually paid, only the algorithm for selecting transactions into a block\\n\"\n            \"                  considers the transaction as it would have paid a higher (or lower) fee.\\n\"\n            \"\\nResult:\\n\"\n            \"true              (boolean) Returns true\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"prioritisetransaction\", \"\\\"txid\\\" 0.0 10000\")\n            + HelpExampleRpc(\"prioritisetransaction\", \"\\\"txid\\\", 0.0, 10000\")\n        );\n\n    LOCK(cs_main);\n\n    uint256 hash = ParseHashStr(request.params[0].get_str(), \"txid\");\n    CAmount nAmount = request.params[2].get_int64();\n\n    if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Priority is no longer supported, dummy argument to prioritisetransaction must be 0.\");\n    }\n\n    mempool.PrioritiseTransaction(hash, nAmount);\n    return true;\n}\n\n\n// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller\nstatic UniValue BIP22ValidationResult(const CValidationState& state)\n{\n    if (state.IsValid())\n        return NullUniValue;\n\n    std::string strRejectReason = state.GetRejectReason();\n    if (state.IsError())\n        throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason);\n    if (state.IsInvalid())\n    {\n        if (strRejectReason.empty())\n            return \"rejected\";\n        return strRejectReason;\n    }\n    // Should be impossible\n    return \"valid?\";\n}\n\nclass submitblock_StateCatcher : public CValidationInterface\n{\npublic:\n    uint256 hash;\n    bool found;\n    CValidationState state;\n\n    submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}\n\nprotected:\n    void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {\n        if (block.GetHashPoW2() != hash)\n            return;\n        found = true;\n        state = stateIn;\n    }\n};\n\nstatic UniValue submitblock(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {\n        throw std::runtime_error(\n            \"submitblock \\\"hexdata\\\" ( \\\"jsonparametersobject\\\" )\\n\"\n            \"\\nAttempts to submit new block to network.\\n\"\n            \"The 'jsonparametersobject' parameter is currently ignored.\\n\"\n            \"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\\n\"\n\n            \"\\nArguments\\n\"\n            \"1. \\\"hexdata\\\"        (string, required) the hex-encoded block data to submit\\n\"\n            \"2. \\\"parameters\\\"     (string, optional) object of optional parameters\\n\"\n            \"    {\\n\"\n            \"      \\\"workid\\\" : \\\"id\\\"    (string, optional) if the server provided a workid, it MUST be included with submissions\\n\"\n            \"    }\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"submitblock\", \"\\\"mydata\\\"\")\n            + HelpExampleRpc(\"submitblock\", \"\\\"mydata\\\"\")\n        );\n    }\n\n    std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();\n    CBlock& block = *blockptr;\n    if (!DecodeHexBlk(block, request.params[0].get_str())) {\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"Block decode failed\");\n    }\n\n    if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"Block does not start with a coinbase\");\n    }\n\n    uint256 hash = block.GetHashPoW2();\n    bool fBlockPresent = false;\n    {\n        LOCK(cs_main);\n        BlockMap::iterator mi = mapBlockIndex.find(hash);\n        if (mi != mapBlockIndex.end()) {\n            CBlockIndex *pindex = mi->second;\n            if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {\n                return \"duplicate\";\n            }\n            if (pindex->nStatus & BLOCK_FAILED_MASK) {\n                return \"duplicate-invalid\";\n            }\n            // Otherwise, we might only have the header - process the block before returning\n            fBlockPresent = true;\n        }\n    }\n\n    submitblock_StateCatcher sc(block.GetHashPoW2());\n    RegisterValidationInterface(&sc);\n    bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL, false, true);\n    UnregisterValidationInterface(&sc);\n\n\n    if (fBlockPresent) {\n        if (fAccepted && !sc.found) {\n            return \"duplicate-inconclusive\";\n        }\n        return \"duplicate\";\n    }\n    if (!fAccepted)\n        return \"invalid\";\n    if (!sc.found) {\n        return \"inconclusive\";\n    }\n    return BIP22ValidationResult(sc.state);\n}\n\nstatic UniValue submitheader(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n    {\n        throw std::runtime_error(\n            \"submitheader \\\"hexdata\\\"\\n\"\n            \"\\nAttempts to submit new header to network.\\n\"\n            \"\\nArguments\\n\"\n            \"1. \\\"hexdata\\\"        (string, required) the hex-encoded block data to submit\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"submitblock\", \"\\\"mydata\\\"\")\n            + HelpExampleRpc(\"submitblock\", \"\\\"mydata\\\"\")\n        );\n    }\n\n    std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();\n    CBlock& block = *blockptr;\n    if (!DecodeHexBlk(block, request.params[0].get_str()+\"00\"))\n    {\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"Header decode failed\");\n    }\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"hash\", block.GetHashPoW2().ToString());\n\n    const CBlockIndex *pindex = NULL;\n    CValidationState state;\n    if (!ProcessNewBlockHeaders( {block.GetBlockHeader()}, state, Params(), &pindex))\n    {\n        result.pushKV(\"status\", \"failed\");        \n    }\n    else\n    {\n        result.pushKV(\"status\", \"success\");\n    }\n    return result;\n}\n\nstatic UniValue estimatefee(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"estimatefee num_blocks\\n\"\n            \"\\nDEPRECATED. Please use estimatesmartfee for more intelligent estimates.\"\n            \"\\nEstimates the approximate fee per kilobyte needed for a transaction to begin\\n\"\n            \"confirmation within num_blocks blocks. Uses virtual transaction size of transaction\\n\"\n            \"as defined in BIP 141 (witness data is discounted).\\n\"\n            \"\\nArguments:\\n\"\n            \"1. num_blocks  (numeric, required)\\n\"\n            \"\\nResult:\\n\"\n            \"n              (numeric) estimated fee-per-kilobyte\\n\"\n            \"\\n\"\n            \"A negative value is returned if not enough transactions and blocks\\n\"\n            \"have been observed to make an estimate.\\n\"\n            \"-1 is always returned for num_blocks == 1 as it is impossible to calculate\\n\"\n            \"a fee that is high enough to get reliably included in the next block.\\n\"\n            \"\\nExample:\\n\"\n            + HelpExampleCli(\"estimatefee\", \"6\")\n            );\n\n    RPCTypeCheck(request.params, {UniValue::VNUM});\n\n    int nBlocks = request.params[0].get_int();\n    if (nBlocks < 1)\n        nBlocks = 1;\n\n    CFeeRate feeRate = ::feeEstimator.estimateFee(nBlocks);\n    if (feeRate == CFeeRate(0))\n        return -1.0;\n\n    return ValueFromAmount(feeRate.GetFeePerK());\n}\n\n/* Used to determine type of fee estimation requested */\nenum class FeeEstimateMode {\n    UNSET,        //!< Use default settings based on other criteria\n    ECONOMICAL,   //!< Force estimateSmartFee to use non-conservative estimates\n    CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates\n};\n\nbool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode)\n{\n    static const std::map<std::string, FeeEstimateMode> fee_modes = {\n        {\"UNSET\", FeeEstimateMode::UNSET},\n        {\"ECONOMICAL\", FeeEstimateMode::ECONOMICAL},\n        {\"CONSERVATIVE\", FeeEstimateMode::CONSERVATIVE},\n    };\n    auto mode = fee_modes.find(mode_string);\n\n    if (mode == fee_modes.end()) return false;\n\n    fee_estimate_mode = mode->second;\n    return true;\n}\n\n\n\n\nstatic UniValue estimatesmartfee(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"estimatesmartfee num_blocks (conservative)\\n\"\n            \"\\nEstimates the approximate fee per kilobyte needed for a transaction to begin\\n\"\n            \"confirmation within num_blocks blocks if possible and return the number of blocks\\n\"\n            \"for which the estimate is valid. Uses virtual transaction size as defined\\n\"\n            \"in BIP 141 (witness data is discounted).\\n\"\n            \"\\nArguments:\\n\"\n            \"1. num_blocks    (numeric)\\n\"\n            \"2. conservative  (String, optional) Whether to return a more conservative estimate which\\n\"\n            \"                 also satisfies a longer history. A conservative estimate potentially returns a higher\\n\"\n            \"                 feerate and is more likely to be sufficient for the desired target, but is not as\\n\"\n            \"                 responsive to short term drops in the prevailing fee market\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"feerate\\\" : x.x,     (numeric) estimate fee-per-kilobyte (in \" GLOBAL_COIN_CODE \")\\n\"\n            \"  \\\"blocks\\\" : n         (numeric) block number where estimate was found\\n\"\n            \"}\\n\"\n            \"\\n\"\n            \"A negative value is returned if not enough transactions and blocks\\n\"\n            \"have been observed to make an estimate for any number of blocks.\\n\"\n            \"However it will not return a value below the mempool reject fee.\\n\"\n            \"\\nExample:\\n\"\n            + HelpExampleCli(\"estimatesmartfee\", \"6\")\n            );\n\n   \n    RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});\n    RPCTypeCheckArgument(request.params[0], UniValue::VNUM);\n    //unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);\n    //unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);\n    bool conservative = true;\n    if (!request.params[1].isNull())\n    {\n        FeeEstimateMode fee_mode;\n        if (!FeeModeFromString(request.params[1].get_str(), fee_mode))\n        {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid estimate_mode parameter\");\n        }\n        if (fee_mode == FeeEstimateMode::ECONOMICAL)\n            conservative = false;\n    }\n\n    UniValue result(UniValue::VOBJ);\n    UniValue errors(UniValue::VARR);\n    //FeeCalculation feeCalc;\n    int answerFound;\n    //CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative);\n    CFeeRate feeRate = ::feeEstimator.estimateSmartFee(request.params[0].get_int(), &answerFound, ::mempool, conservative);\n    if (feeRate.GetFeePerK() != 0)\n    {\n        result.pushKV(\"feerate\", ValueFromAmount(feeRate.GetFeePerK()));\n    }\n    else\n    {\n        errors.push_back(\"Insufficient data or no feerate found\");\n        result.pushKV(\"errors\", errors);\n    }\n    result.pushKV(\"blocks\", answerFound);\n    return result;\n}\n\nstatic UniValue estimaterawfee(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1|| request.params.size() > 3)\n        throw std::runtime_error(\n            \"estimaterawfee num_blocks (threshold horizon)\\n\"\n            \"\\nWARNING: This interface is unstable and may disappear or change!\\n\"\n            \"\\nWARNING: This is an advanced API call that is tightly coupled to the specific\\n\"\n            \"         implementation of fee estimation. The parameters it can be called with\\n\"\n            \"         and the results it returns will change if the internal implementation changes.\\n\"\n            \"\\nEstimates the approximate fee per kilobyte needed for a transaction to begin\\n\"\n            \"confirmation within num_blocks blocks if possible. Uses virtual transaction size as defined\\n\"\n            \"in BIP 141 (witness data is discounted).\\n\"\n            \"\\nArguments:\\n\"\n            \"1. num_blocks  (numeric)\\n\"\n            \"2. threshold   (numeric, optional) The proportion of transactions in a given feerate range that must have been\\n\"\n            \"               confirmed within num_blocks in order to consider those feerates as high enough and proceed to check\\n\"\n            \"               lower buckets.  Default: 0.95\\n\"\n            \"3. horizon     (numeric, optional) How long a history of estimates to consider. 0=short, 1=medium, 2=long.\\n\"\n            \"               Default: 1\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"feerate\\\" : x.x,        (numeric) estimate fee-per-kilobyte (in \" GLOBAL_COIN_CODE \")\\n\"\n            \"  \\\"decay\\\" : x.x,          (numeric) exponential decay (per block) for historical moving average of confirmation data\\n\"\n            \"  \\\"scale\\\" : x,            (numeric) The resolution of confirmation targets at this time horizon\\n\"\n            \"  \\\"pass\\\" : {              (json object) information about the lowest range of feerates to succeed in meeting the threshold\\n\"\n            \"      \\\"startrange\\\" : x.x,     (numeric) start of feerate range\\n\"\n            \"      \\\"endrange\\\" : x.x,       (numeric) end of feerate range\\n\"\n            \"      \\\"withintarget\\\" : x.x,   (numeric) number of txs over history horizon in the feerate range that were confirmed within target\\n\"\n            \"      \\\"totalconfirmed\\\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\\n\"\n            \"      \\\"inmempool\\\" : x.x,      (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\\n\"\n            \"      \\\"leftmempool\\\" : x.x,    (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\\n\"\n            \"  }\\n\"\n            \"  \\\"fail\\\" : { ... }        (json object) information about the highest range of feerates to fail to meet the threshold\\n\"\n            \"}\\n\"\n            \"\\n\"\n            \"A negative feerate is returned if no answer can be given.\\n\"\n            \"\\nExample:\\n\"\n            + HelpExampleCli(\"estimaterawfee\", \"6 0.9 1\")\n            );\n\n    RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);\n    RPCTypeCheckArgument(request.params[0], UniValue::VNUM);\n    int nBlocks = request.params[0].get_int();\n    double threshold = 0.95;\n    if (!request.params[1].isNull())\n        threshold = request.params[1].get_real();\n    FeeEstimateHorizon horizon = FeeEstimateHorizon::MED_HALFLIFE;\n    if (!request.params[2].isNull()) {\n        int horizonInt = request.params[2].get_int();\n        if (horizonInt < 0 || horizonInt > 2) {\n            throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid horizon for fee estimates\");\n        } else {\n            horizon = (FeeEstimateHorizon)horizonInt;\n        }\n    }\n    UniValue result(UniValue::VOBJ);\n    CFeeRate feeRate;\n    EstimationResult buckets;\n    feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);\n\n    result.pushKV(\"feerate\", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()));\n    result.pushKV(\"decay\", buckets.decay);\n    result.pushKV(\"scale\", (int)buckets.scale);\n    UniValue passbucket(UniValue::VOBJ);\n    passbucket.pushKV(\"startrange\", round(buckets.pass.start));\n    passbucket.pushKV(\"endrange\", round(buckets.pass.end));\n    passbucket.pushKV(\"withintarget\", round(buckets.pass.withinTarget * 100.0) / 100.0);\n    passbucket.pushKV(\"totalconfirmed\", round(buckets.pass.totalConfirmed * 100.0) / 100.0);\n    passbucket.pushKV(\"inmempool\", round(buckets.pass.inMempool * 100.0) / 100.0);\n    passbucket.pushKV(\"leftmempool\", round(buckets.pass.leftMempool * 100.0) / 100.0);\n    result.pushKV(\"pass\", passbucket);\n    UniValue failbucket(UniValue::VOBJ);\n    failbucket.pushKV(\"startrange\", round(buckets.fail.start));\n    failbucket.pushKV(\"endrange\", round(buckets.fail.end));\n    failbucket.pushKV(\"withintarget\", round(buckets.fail.withinTarget * 100.0) / 100.0);\n    failbucket.pushKV(\"totalconfirmed\", round(buckets.fail.totalConfirmed * 100.0) / 100.0);\n    failbucket.pushKV(\"inmempool\", round(buckets.fail.inMempool * 100.0) / 100.0);\n    failbucket.pushKV(\"leftmempool\", round(buckets.fail.leftMempool * 100.0) / 100.0);\n    result.pushKV(\"fail\", failbucket);\n    return result;\n}\n\nstatic const CRPCCommand commandsFull[] =\n{ //  category              name                      actor (function)         okSafeMode\n  //  --------------------- ------------------------  -----------------------  ----------\n    { \"block_generation\",   \"getnetworkhashps\",       &getnetworkhashps,       true,  {\"num_blocks\",\"height\"} },\n    { \"block_generation\",   \"getmininginfo\",          &getmininginfo,          true,  {} },\n    { \"block_generation\",   \"prioritisetransaction\",  &prioritisetransaction,  true,  {\"txid\",\"dummy_value\",\"fee_delta\"} },\n\n    { \"generating\",         \"generate\",               &generate,               true,  {\"num_blocks\",\"max_tries\"} },\n    { \"generating\",         \"generatetoaddress\",      &generatetoaddress,      true,  {\"num_blocks\",\"address\",\"max_tries\"} },\n    { \"generating\",         \"getgenerate\",            &getgenerate,            true,  {}  },\n    { \"generating\",         \"setgenerate\",            &setgenerate,            true,  {\"generate\", \"gen_proc_limit\", \"gen_memory_limit\"}  },\n};\n\nstatic const CRPCCommand commandsSPV[] =\n{ //  category              name                      actor (function)         okSafeMode\n  //  --------------------- ------------------------  -----------------------  ----------\n    { \"block_generation\",   \"submitblock\",            &submitblock,            true,  {\"hexdata\",\"parameters\"} },\n    { \"block_generation\",   \"submitheader\",           &submitheader,           true,  {\"hexdata\"} },\n\n    { \"util\",               \"estimatefee\",            &estimatefee,            true,  {\"num_blocks\"} },\n    { \"util\",               \"estimatesmartfee\",       &estimatesmartfee,       true,  {\"num_blocks\", \"conservative\"} },\n\n    { \"hidden\",             \"estimaterawfee\",         &estimaterawfee,         true,  {\"num_blocks\", \"threshold\", \"horizon\"} },\n};\n\nvoid RegisterMiningRPCCommands(CRPCTable &t)\n{\n    if (!GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commandsFull); vcidx++)\n            t.appendCommand(commandsFull[vcidx].name, &commandsFull[vcidx]);\n    }\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commandsSPV); vcidx++)\n        t.appendCommand(commandsSPV[vcidx].name, &commandsSPV[vcidx]);\n}\n"
  },
  {
    "path": "src/rpc/misc.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"base58.h\"\n#include \"chain.h\"\n#include \"clientversion.h\"\n#include \"init.h\"\n#include \"validation/validation.h\"\n#include \"httpserver.h\"\n#include \"net.h\"\n#include \"netbase.h\"\n#include \"rpc/blockchain.h\"\n#include \"rpc/server.h\"\n#include \"timedata.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/rpcwallet.h\"\n#include \"wallet/wallet.h\"\n#include \"wallet/walletdb.h\"\n#endif\n#include \"wallet/account.h\"\n#include \"warnings.h\"\n\n#include <stdint.h>\n#ifdef HAVE_MALLOC_INFO\n#include <malloc.h>\n#endif\n\n#include <univalue.h>\n\n/**\n * @note Do not add or change anything in the information returned by this\n * method. `getinfo` exists for backwards-compatibility only. It combines\n * information from wildly different sources in the program, which is a mess,\n * and is thus planned to be deprecated eventually.\n *\n * Based on the source of the information, new information should be added to:\n * - `getblockchaininfo`,\n * - `getnetworkinfo` or\n * - `getwalletinfo`\n *\n * Or alternatively, create a specific query method for the information.\n **/\nstatic UniValue getinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getinfo\\n\"\n            \"\\nDEPRECATED. Returns an object containing various state info.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"version\\\": xxxxx,           (numeric) the server version\\n\"\n            \"  \\\"protocolversion\\\": xxxxx,   (numeric) the protocol version\\n\"\n            \"  \\\"walletversion\\\": xxxxx,     (numeric) the wallet version\\n\"\n            \"  \\\"balance\\\": xxxxxxx,         (numeric) the total \" GLOBAL_APPNAME \" balance of the wallet\\n\"\n            \"  \\\"blocks\\\": xxxxxx,           (numeric) the current number of blocks processed in the server\\n\"\n            \"  \\\"timeoffset\\\": xxxxx,        (numeric) the time offset\\n\"\n            \"  \\\"connections\\\": xxxxx,       (numeric) the number of connections\\n\"\n            \"  \\\"proxy\\\": \\\"host:port\\\",     (string, optional) the proxy used by the server\\n\"\n            \"  \\\"difficulty\\\": xxxxxx,       (numeric) the current difficulty\\n\"\n            \"  \\\"testnet\\\": true|false,      (boolean) if the server is using testnet or not\\n\"\n            \"  \\\"keypoololdest\\\": xxxxxx,    (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\\n\"\n            \"  \\\"keypoolsize\\\": xxxx,        (numeric) how many new keys are pre-generated\\n\"\n            \"  \\\"unlocked_until\\\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\\n\"\n            \"  \\\"paytxfee\\\": x.xxxx,         (numeric) the transaction fee set in \" + CURRENCY_UNIT + \"/kB\\n\"\n            \"  \\\"relayfee\\\": x.xxxx,         (numeric) minimum relay fee for transactions in \" + CURRENCY_UNIT + \"/kB\\n\"\n            \"  \\\"errors\\\": \\\"...\\\"           (string) any error messages\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getinfo\", \"\")\n            + HelpExampleRpc(\"getinfo\", \"\")\n        );\n\n#ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n#else\n    LOCK(cs_main);\n#endif\n\n    proxyType proxy;\n    GetProxy(NET_IPV4, proxy);\n\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"version\", CLIENT_VERSION);\n    obj.pushKV(\"protocolversion\", PROTOCOL_VERSION);\n#ifdef ENABLE_WALLET\n    if (pwallet) {\n        obj.pushKV(\"walletversion\", pwallet->GetVersion());\n        obj.pushKV(\"balance\",       ValueFromAmount(pwallet->GetBalance(nullptr, true, false, true)));\n    }\n#endif\n    obj.pushKV(\"blocks\",        (int)chainActive.Height());\n    obj.pushKV(\"timeoffset\",    GetTimeOffset());\n    if(g_connman)\n        obj.pushKV(\"connections\",   (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));\n    obj.pushKV(\"proxy\",         (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()));\n    obj.pushKV(\"difficulty\",    (double)GetDifficulty());\n    obj.pushKV(\"testnet\",       Params().NetworkIDString() == CBaseChainParams::TESTNET);\n#ifdef ENABLE_WALLET\n    if (pwallet) {\n        obj.pushKV(\"keypoololdest\", pwallet->GetOldestKeyPoolTime());\n        //fixme: (FUT) (BIP44)\n        {\n            LOCK(pwallet->activeAccount->cs_keypool);\n            obj.pushKV(\"keypoolsize\",   (int)pwallet->activeAccount->GetKeyPoolSize());\n        }\n    }\n    if (pwallet && pwallet->IsCrypted()) {\n        obj.pushKV(\"unlocked_until\", pwallet->nRelockTime);\n    }\n    obj.pushKV(\"mininput\",      ValueFromAmount(0));\n    obj.pushKV(\"paytxfee\",      ValueFromAmount(payTxFee.GetFeePerK()));\n#endif\n    obj.pushKV(\"relayfee\",      ValueFromAmount(::minRelayTxFee.GetFeePerK()));\n    obj.pushKV(\"errors\",        GetWarnings(\"statusbar\"));\n    return obj;\n}\n\n#ifdef ENABLE_WALLET\nclass DescribeAddressVisitor : public boost::static_visitor<UniValue>\n{\npublic:\n    CWallet * const pwallet;\n\n    DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}\n\n    UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }\n\n    UniValue operator()(const CPoW2WitnessDestination &dest) const {\n        UniValue obj(UniValue::VOBJ);\n        CPubKey vchPubKey;\n        obj.pushKV(\"isscript\", false);\n        if (pwallet)\n        {\n            if (pwallet->GetPubKey(dest.spendingKey, vchPubKey))\n            {\n                obj.pushKV(\"spendingpubkey\", HexStr(vchPubKey));\n            }\n            CKey privKey;\n            bool ismine = pwallet->GetKey(dest.spendingKey, privKey);\n            obj.pushKV(\"spendingprivkey_isavailable\", ismine?\"true\":\"false\");\n        }\n        obj.pushKV(\"spendingpubkeyhash\", dest.spendingKey.GetHex());\n        if (pwallet)\n        {\n            if (pwallet->GetPubKey(dest.witnessKey, vchPubKey))\n            {\n                obj.pushKV(\"witnesspubkey\", HexStr(vchPubKey));\n            }\n            CKey privKey;\n            bool ismine = pwallet->GetKey(dest.witnessKey, privKey);\n            obj.pushKV(\"witnessprivkey_isavailable\", ismine?\"true\":\"false\");\n        }\n        obj.pushKV(\"witnesspubkeyhash\", dest.witnessKey.GetHex());\n        return obj;\n    }\n\n    UniValue operator()(const CKeyID &keyID) const {\n        UniValue obj(UniValue::VOBJ);\n        CPubKey vchPubKey;\n        obj.pushKV(\"isscript\", false);\n        if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {\n            obj.pushKV(\"pubkey\", HexStr(vchPubKey));\n            obj.pushKV(\"iscompressed\", vchPubKey.IsCompressed());\n        }\n        return obj;\n    }\n\n    UniValue operator()(const CScriptID &scriptID) const {\n        UniValue obj(UniValue::VOBJ);\n        CScript subscript;\n        obj.pushKV(\"isscript\", true);\n        if (pwallet && pwallet->GetCScript(scriptID, subscript)) {\n            std::vector<CTxDestination> addresses;\n            txnouttype whichType;\n            int nRequired;\n            ExtractDestinations(subscript, whichType, addresses, nRequired);\n            obj.pushKV(\"script\", GetTxnOutputType(whichType));\n            obj.pushKV(\"hex\", HexStr(subscript.begin(), subscript.end()));\n            UniValue a(UniValue::VARR);\n            for(const CTxDestination& addr : addresses)\n                a.push_back(CNativeAddress(addr).ToString());\n            obj.pushKV(\"addresses\", a);\n            if (whichType == TX_MULTISIG)\n                obj.pushKV(\"sigsrequired\", nRequired);\n        }\n        return obj;\n    }\n};\n#endif\n\nUniValue validateaddress(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"validateaddress \\\"address\\\"\\n\"\n            \"\\nReturn information about the given \" GLOBAL_APPNAME \" address.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"     (string, required) The \" GLOBAL_APPNAME \" address to validate\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"isvalid\\\" : true|false,       (boolean) If the address is valid or not. If not, this is the only property returned.\\n\"\n            \"  \\\"address\\\" : \\\"address\\\", (string) The \" GLOBAL_APPNAME \" address validated\\n\"\n            \"  \\\"scriptPubKey\\\" : \\\"hex\\\",       (string) The hex encoded scriptPubKey generated by the address\\n\"\n            \"  \\\"ismine\\\" : true|false,        (boolean) If the address is yours or not\\n\"\n            \"  \\\"iswatchonly\\\" : true|false,   (boolean) If the address is watchonly\\n\"\n            \"  \\\"isscript\\\" : true|false,      (boolean) If the key is a script\\n\"\n            \"  \\\"pubkey\\\" : \\\"publickeyhex\\\",    (string) The hex value of the raw public key\\n\"\n            \"  \\\"iscompressed\\\" : true|false,  (boolean) If the address is compressed\\n\"\n            \"  \\\"account\\\" : \\\"account\\\"         (string) The account associated with the address, \\n\"\n            \"  \\\"accountlabel\\\" : \\\"accountlabel\\\" (string) Label of the account associated with the address, \\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"validateaddress\", \"\\\"GPSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\\\"\")\n            + HelpExampleRpc(\"validateaddress\", \"\\\"GPSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\\\"\")\n        );\n\n#ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n#else\n    LOCK(cs_main);\n#endif\n\n    CNativeAddress address(request.params[0].get_str());\n    bool isValid = address.IsValid();\n\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"isvalid\", isValid);\n    if (isValid)\n    {\n        CTxDestination dest = address.Get();\n        std::string currentAddress = address.ToString();\n        ret.pushKV(\"address\", currentAddress);\n\n        //fixme: (PHASE5) Add some segsig specific output here.\n        CScript scriptPubKey = GetScriptForDestination(dest);\n        ret.pushKV(\"scriptPubKey\", HexStr(scriptPubKey.begin(), scriptPubKey.end()));\n\n#ifdef ENABLE_WALLET\n        if (pwallet)\n        {\n            isminetype mine = IsMine(*pwallet, dest);\n            ret.pushKV(\"ismine\", (mine & ISMINE_SPENDABLE) ? true : false);\n            ret.pushKV(\"iswatchonly\", (mine & ISMINE_WATCH_ONLY) ? true: false);\n            UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);\n            ret.pushKVs(detail);\n            for (const auto& accountIter : pwallet->mapAccounts)\n            {\n                if (IsMine(*accountIter.second, dest) > ISMINE_WATCH_ONLY )\n                {\n                    ret.pushKV(\"account\", getUUIDAsString(accountIter.second->getUUID()));\n                    ret.pushKV(\"accountlabel\", accountIter.second->getLabel());\n                }\n            }\n        }\n#endif\n    }\n    return ret;\n}\n\nstatic UniValue getaddress(const JSONRPCRequest& request)\n{\n    LOCK(cs_main);\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getaddress \\\"pubkey_or_script\\\" \\n\"\n            \"\\nGet the address of a pubkey or script\\n\"\n            \"\\nTo get the pubkey of an address use 'validateaddress'\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"pubkey_or_script\\\"       (required) An hex encoded script or public key.\\n\"\n            \"\\nResult:\\n\"\n            \"\\nReturn an array of addresses on success\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getaddress \\\"Vd69eLAZ2r76C47xB3pDLa9Fx4Li8Xt5AHgzjJDuLbkP8eqUjToC\\\"\", \"\")\n            + HelpExampleRpc(\"getaddress \\\"Vd69eLAZ2r76C47xB3pDLa9Fx4Li8Xt5AHgzjJDuLbkP8eqUjToC\\\"\", \"\"));\n\n    std::string pubKeyOrScript = request.params[0].get_str();\n    if (!IsHex(pubKeyOrScript))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Data is not hex encoded\");\n\n    UniValue result(UniValue::VARR);\n\n    // Try public key first.\n    std::vector<unsigned char> data(ParseHex(pubKeyOrScript));\n    CPubKey pubKey(data.begin(), data.end());\n    if (pubKey.IsFullyValid())\n    {\n        result.push_back(CNativeAddress(pubKey.GetID()).ToString());\n    }\n    else\n    {\n        // Not a public key so treat it as a script.\n        CScript scriptPubKey(data.begin(), data.end());\n        std::vector<CTxDestination> addresses;\n\n        int nRequired;\n        txnouttype type;\n        if (ExtractDestinations(scriptPubKey, type, addresses, nRequired))\n        {\n            for(const CTxDestination& addr : addresses)\n            {\n                result.push_back(CNativeAddress(addr).ToString());\n            }\n        }\n        //fixme: (PHASE5) Check that this handles p2sh correctly (handle ExtractDestinations failiure - look at decodescript to get an idea of what needs to be done)\n    }\n\n    return result;\n}\n\n// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around\nclass CWallet;\n\n/**\n * Used by addmultisigaddress / createmultisig:\n */\nCScript _createmultisig_redeemScript(CAccount* const forAccount, const UniValue& params)\n{\n    int nRequired = params[0].get_int();\n    const UniValue& keys = params[1].get_array();\n\n    // Gather public keys\n    if (nRequired < 1) { throw std::runtime_error(\"a multisignature address must require at least one key to redeem\"); }\n    if ((int)keys.size() < nRequired) { throw std::runtime_error(strprintf(\"not enough keys supplied (got %u keys, but need at least %d to redeem)\", keys.size(), nRequired)); }\n    if (keys.size() > 16) { throw std::runtime_error(\"Number of addresses involved in the multisignature address creation > 16\\nReduce the number\"); }\n    \n    std::vector<CPubKey> pubkeys;\n    pubkeys.resize(keys.size());\n    for (unsigned int i = 0; i < keys.size(); i++)\n    {\n        const std::string& ks = keys[i].get_str();\n        #ifdef ENABLE_WALLET\n        CNativeAddress address(ks);\n        if (forAccount && address.IsValid())\n        {\n            // Case 1: Munt address and we have full public key:\n            CKeyID keyID;\n            CPubKey vchPubKey;\n            if (!address.GetKeyID(keyID)) { throw std::runtime_error(strprintf(\"%s does not refer to a key\",ks)); }\n            if (!forAccount->GetPubKey(keyID, vchPubKey)){ throw std::runtime_error(strprintf(\"no full public key for address %s\",ks)); }\n            if (!vchPubKey.IsFullyValid()) { throw std::runtime_error(\" Invalid public key: \"+ks); }\n            pubkeys[i] = vchPubKey;\n        }\n        else\n        #endif\n        {\n            // Case 2: hex public key\n            bool validPublicKey=false;\n            if (IsHex(ks))\n            {\n                CPubKey vchPubKey(ParseHex(ks));\n                if (vchPubKey.IsFullyValid())\n                {\n                    validPublicKey = true;\n                    pubkeys[i] = vchPubKey;\n                }\n            }\n            if (!validPublicKey)\n            {\n                throw std::runtime_error(\" Invalid public key: \"+ks);\n            }\n        }\n    }\n    CScript result = GetScriptForMultisig(nRequired, pubkeys);\n\n    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)\n    { \n        throw std::runtime_error(strprintf(\"redeemScript exceeds size limit: %d > %d\", result.size(), MAX_SCRIPT_ELEMENT_SIZE));\n    }\n\n    return result;\n}\n\nUniValue createmultisig(const JSONRPCRequest& request)\n{\n#ifdef ENABLE_WALLET\n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n#endif\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)\n    {\n        std::string msg = \"createmultisig num_required [\\\"key\\\",...]\\n\"\n            \"\\nCreates a multi-signature address with n signature of m keys required.\\n\"\n            \"It returns a json object with the address and redeemScript.\\n\"\n\n            \"\\nArguments:\\n\"\n            \"1. num_required   (numeric, required) The number of required signatures out of the n keys or addresses.\\n\"\n            \"2. \\\"keys\\\"       (string, required) A json array of keys which are \" GLOBAL_APPNAME \" addresses or hex-encoded public keys\\n\"\n            \"     [\\n\"\n            \"       \\\"key\\\"    (string) \" GLOBAL_APPNAME \" address or hex-encoded public key\\n\"\n            \"       ,...\\n\"\n            \"     ]\\n\"\n\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"address\\\":\\\"multisigaddress\\\",  (string) The value of the new multisig address.\\n\"\n            \"  \\\"redeemScript\\\":\\\"script\\\"       (string) The string value of the hex-encoded redemption script.\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            \"\\nCreate a multisig address from 2 addresses\\n\"\n            + HelpExampleCli(\"createmultisig\", \"2 \\\"[\\\\\\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\\\\\",\\\\\\\"G71sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\\\\\"]\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"createmultisig\", \"2, \\\"[\\\\\\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\\\\\",\\\\\\\"G71sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\\\\\"]\\\"\")\n        ;\n        throw std::runtime_error(msg);\n    }\n\n    // Construct using pay-to-script-hash:\n    #ifdef ENABLE_WALLET\n    CScript inner = _createmultisig_redeemScript(pwallet->activeAccount, request.params);\n    #else\n    CScript inner = _createmultisig_redeemScript(nullptr, request.params);\n    #endif\n    CScriptID innerID(inner);\n    CNativeAddress address(innerID);\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"address\", address.ToString());\n    result.pushKV(\"redeemScript\", HexStr(inner.begin(), inner.end()));\n\n    return result;\n}\n\nUniValue verifymessage(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 3)\n        throw std::runtime_error(\n            \"verifymessage \\\"address\\\" \\\"signature\\\" \\\"message\\\"\\n\"\n            \"\\nVerify a signed message\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"         (string, required) The \" GLOBAL_APPNAME \" address to use for the signature.\\n\"\n            \"2. \\\"signature\\\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\\n\"\n            \"3. \\\"message\\\"         (string, required) The message that was signed.\\n\"\n            \"\\nResult:\\n\"\n            \"true|false   (boolean) If the signature is verified or not.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nUnlock the wallet for 30 seconds\\n\"\n            + HelpExampleCli(\"walletpassphrase\", \"\\\"mypassphrase\\\" 30\") +\n            \"\\nCreate the signature\\n\"\n            + HelpExampleCli(\"signmessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" \\\"my message\\\"\") +\n            \"\\nVerify the signature\\n\"\n            + HelpExampleCli(\"verifymessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" \\\"signature\\\" \\\"my message\\\"\") +\n            \"\\nAs json rpc\\n\"\n            + HelpExampleRpc(\"verifymessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\", \\\"signature\\\", \\\"my message\\\"\")\n        );\n\n    LOCK(cs_main);\n\n    std::string strAddress  = request.params[0].get_str();\n    std::string strSign     = request.params[1].get_str();\n    std::string strMessage  = request.params[2].get_str();\n\n    CNativeAddress addr(strAddress);\n    if (!addr.IsValid())\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid address\");\n\n    CKeyID keyID;\n    if (!addr.GetKeyID(keyID))\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Address does not refer to key\");\n\n    bool fInvalid = false;\n    std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);\n\n    if (fInvalid)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Malformed base64 encoding\");\n\n    CHashWriter ss(SER_GETHASH, 0);\n    ss << strMessageMagic;\n    ss << strMessage;\n\n    CPubKey pubkey;\n    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))\n        return false;\n\n    return (pubkey.GetID() == keyID);\n}\n\nUniValue signmessagewithprivkey(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"signmessagewithprivkey \\\"privkey\\\" \\\"message\\\"\\n\"\n            \"\\nSign a message with the private key of an address\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"privkey\\\"         (string, required) The private key to sign the message with.\\n\"\n            \"2. \\\"message\\\"         (string, required) The message to create a signature of.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"signature\\\"          (string) The signature of the message encoded in base 64\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nCreate the signature\\n\"\n            + HelpExampleCli(\"signmessagewithprivkey\", \"\\\"privkey\\\" \\\"my message\\\"\") +\n            \"\\nVerify the signature\\n\"\n            + HelpExampleCli(\"verifymessage\", \"\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" \\\"signature\\\" \\\"my message\\\"\") +\n            \"\\nAs json rpc\\n\"\n            + HelpExampleRpc(\"signmessagewithprivkey\", \"\\\"privkey\\\", \\\"my message\\\"\")\n        );\n\n    std::string strPrivkey = request.params[0].get_str();\n    std::string strMessage = request.params[1].get_str();\n\n    CEncodedSecretKey vchSecret;\n    bool fGood = vchSecret.SetString(strPrivkey);\n    if (!fGood)\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid private key\");\n    CKey key = vchSecret.GetKey();\n    if (!key.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Private key outside allowed range\");\n\n    CHashWriter ss(SER_GETHASH, 0);\n    ss << strMessageMagic;\n    ss << strMessage;\n\n    std::vector<unsigned char> vchSig;\n    if (!key.SignCompact(ss.GetHash(), vchSig))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Sign failed\");\n\n    return EncodeBase64(&vchSig[0], vchSig.size());\n}\n\nUniValue forcesigseg(const JSONRPCRequest& request)\n{\n if (request.fHelp)\n        throw std::runtime_error(\"force program to perform an illegal operation and trigger a sigseg, useful to test debugging features\");\n  ++*(int*)0;\n  return NullUniValue;\n}\n\n\nUniValue setmocktime(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"setmocktime timestamp\\n\"\n            \"\\nSet the local time to given timestamp (-regtest only)\\n\"\n            \"\\nArguments:\\n\"\n            \"1. timestamp  (integer, required) Unix seconds-since-epoch timestamp\\n\"\n            \"   Pass 0 to go back to using the system time.\"\n        );\n\n    if (!Params().MineBlocksOnDemand())\n        throw std::runtime_error(\"setmocktime for regression testing (-regtest mode) only\");\n\n    // For now, don't change mocktime if we're in the middle of validation, as\n    // this could have an effect on mempool time-based eviction, as well as\n    // IsCurrentForFeeEstimation() and IsInitialBlockDownload().\n    // TODO: figure out the right way to synchronize around mocktime, and\n    // ensure all call sites of GetTime() are accessing this safely.\n    LOCK(cs_main);\n\n    RPCTypeCheck(request.params, {UniValue::VNUM});\n    SetMockTime(request.params[0].get_int64());\n\n    return NullUniValue;\n}\n\nstatic UniValue RPCLockedMemoryInfo()\n{\n    LockedPool::Stats stats = LockedPoolManager::Instance().stats();\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"used\", uint64_t(stats.used));\n    obj.pushKV(\"free\", uint64_t(stats.free));\n    obj.pushKV(\"total\", uint64_t(stats.total));\n    obj.pushKV(\"locked\", uint64_t(stats.locked));\n    obj.pushKV(\"chunks_used\", uint64_t(stats.chunks_used));\n    obj.pushKV(\"chunks_free\", uint64_t(stats.chunks_free));\n    return obj;\n}\n\n#ifdef HAVE_MALLOC_INFO\nstatic std::string RPCMallocInfo()\n{\n    char *ptr = nullptr;\n    size_t size = 0;\n    FILE *f = open_memstream(&ptr, &size);\n    if (f) {\n        malloc_info(0, f);\n        fclose(f);\n        if (ptr) {\n            std::string rv(ptr, size);\n            free(ptr);\n            return rv;\n        }\n    }\n    return \"\";\n}\n#endif\n\nUniValue getmemoryinfo(const JSONRPCRequest& request)\n{\n    /* Please, avoid using the word \"pool\" here in the RPC interface or help,\n     * as users will undoubtedly confuse it with the other \"memory pool\"\n     */\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getmemoryinfo (\\\"mode\\\")\\n\"\n            \"Returns an object containing information about memory usage.\\n\"\n            \"Arguments:\\n\"\n            \"1. \\\"mode\\\" determines what kind of information is returned. This argument is optional, the default mode is \\\"stats\\\".\\n\"\n            \"  - \\\"stats\\\" returns general statistics about memory usage in the daemon.\\n\"\n            \"  - \\\"mallocinfo\\\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+).\\n\"\n            \"\\nResult (mode \\\"stats\\\"):\\n\"\n            \"{\\n\"\n            \"  \\\"locked\\\": {               (json object) Information about locked memory manager\\n\"\n            \"    \\\"used\\\": xxxxx,          (numeric) Number of bytes used\\n\"\n            \"    \\\"free\\\": xxxxx,          (numeric) Number of bytes available in current arenas\\n\"\n            \"    \\\"total\\\": xxxxxxx,       (numeric) Total number of bytes managed\\n\"\n            \"    \\\"locked\\\": xxxxxx,       (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk.\\n\"\n            \"    \\\"chunks_used\\\": xxxxx,   (numeric) Number allocated chunks\\n\"\n            \"    \\\"chunks_free\\\": xxxxx,   (numeric) Number unused chunks\\n\"\n            \"  }\\n\"\n            \"}\\n\"\n            \"\\nResult (mode \\\"mallocinfo\\\"):\\n\"\n            \"\\\"<malloc version=\\\"1\\\">...\\\"\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getmemoryinfo\", \"\")\n            + HelpExampleRpc(\"getmemoryinfo\", \"\")\n        );\n\n    std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? \"stats\" : request.params[0].get_str();\n    if (mode == \"stats\") {\n        UniValue obj(UniValue::VOBJ);\n        obj.pushKV(\"locked\", RPCLockedMemoryInfo());\n        return obj;\n    } else if (mode == \"mallocinfo\") {\n#ifdef HAVE_MALLOC_INFO\n        return RPCMallocInfo();\n#else\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"mallocinfo is only available when compiled with glibc 2.10+\");\n#endif\n    } else {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"unknown mode \" + mode);\n    }\n}\n\nuint32_t getCategoryMask(UniValue cats) {\n    cats = cats.get_array();\n    uint32_t mask = 0;\n    for (unsigned int i = 0; i < cats.size(); ++i) {\n        uint32_t flag = 0;\n        std::string cat = cats[i].get_str();\n        if (!GetLogCategory(&flag, &cat)) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"unknown logging category \" + cat);\n        }\n        mask |= flag;\n    }\n    return mask;\n}\n\nUniValue logging(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 2) {\n        throw std::runtime_error(\n            \"logging [include,...] <exclude>\\n\"\n            \"Gets and sets the logging configuration.\\n\"\n            \"When called without an argument, returns the list of categories that are currently being debug logged.\\n\"\n            \"When called with arguments, adds or removes categories from debug logging.\\n\"\n            \"The valid logging categories are: \" + ListLogCategories() + \"\\n\"\n            \"libevent logging is configured on startup and cannot be modified by this RPC during runtime.\"\n            \"Arguments:\\n\"\n            \"1. \\\"include\\\" (array of strings) add debug logging for these categories.\\n\"\n            \"2. \\\"exclude\\\" (array of strings) remove debug logging for these categories.\\n\"\n            \"\\nResult: <categories>  (string): a list of the logging categories that are active.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"logging\", \"\\\"[\\\\\\\"all\\\\\\\"]\\\" \\\"[\\\\\\\"http\\\\\\\"]\\\"\")\n            + HelpExampleRpc(\"logging\", \"[\\\"all\\\"], \\\"[libevent]\\\"\")\n        );\n    }\n\n    uint32_t originalLogCategories = logCategories;\n    if (request.params.size() > 0 && request.params[0].isArray()) {\n        logCategories |= getCategoryMask(request.params[0]);\n    }\n\n    if (request.params.size() > 1 && request.params[1].isArray()) {\n        logCategories &= ~getCategoryMask(request.params[1]);\n    }\n\n    // Update libevent logging if BCLog::LIBEVENT has changed.\n    // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,\n    // in which case we should clear the BCLog::LIBEVENT flag.\n    // Throw an error if the user has explicitly asked to change only the libevent\n    // flag and it failed.\n    uint32_t changedLogCategories = originalLogCategories ^ logCategories;\n    if (changedLogCategories & BCLog::LIBEVENT) {\n        if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {\n            logCategories &= ~BCLog::LIBEVENT;\n            if (changedLogCategories == BCLog::LIBEVENT) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"libevent logging cannot be updated when using libevent before v2.1.1.\");\n            }\n        }\n    }\n\n    UniValue result(UniValue::VOBJ);\n    std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();\n    for (const auto& logCatActive : vLogCatActive) {\n        result.pushKV(logCatActive.category, logCatActive.active);\n    }\n\n    return result;\n}\n\nUniValue echo(const JSONRPCRequest& request)\n{\n    if (request.fHelp)\n        throw std::runtime_error(\n            \"echo|echojson \\\"message\\\" ...\\n\"\n            \"\\nSimply echo back the input arguments. This command is for testing.\\n\"\n            \"\\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in\"\n            GLOBAL_APPNAME \"-cli and the GUI. There is no server-side difference.\"\n        );\n\n    return request.params;\n}\n\nstatic const CRPCCommand commands[] =\n{ //  category              name                      actor (function)         okSafeMode\n  //  --------------------- ------------------------  -----------------------  ----------\n    { \"control\",            \"getinfo\",                &getinfo,                true,  {} }, /* uses wallet if enabled */\n    { \"control\",            \"getmemoryinfo\",          &getmemoryinfo,          true,  {\"mode\"} },\n\n    { \"util\",               \"getaddress\",             &getaddress,             true,  {\"pubkey_or_script\"} },\n    { \"util\",               \"validateaddress\",        &validateaddress,        true,  {\"address\"} }, /* uses wallet if enabled */\n    { \"util\",               \"createmultisig\",         &createmultisig,         true,  {\"num_required\",\"keys\"} },\n    { \"util\",               \"verifymessage\",          &verifymessage,          true,  {\"address\",\"signature\",\"message\"} },\n    { \"util\",               \"signmessagewithprivkey\", &signmessagewithprivkey, true,  {\"privkey\",\"message\"} },\n\n    /* Not shown in help */\n    { \"hidden\",             \"setmocktime\",            &setmocktime,            true,  {\"timestamp\"}},\n    { \"hidden\",             \"forcesigseg\",            &forcesigseg,      true,  {}},\n    { \"hidden\",             \"echo\",                   &echo,                   true,  {\"arg0\",\"arg1\",\"arg2\",\"arg3\",\"arg4\",\"arg5\",\"arg6\",\"arg7\",\"arg8\",\"arg9\"}},\n    { \"hidden\",             \"echojson\",               &echo,                   true,  {\"arg0\",\"arg1\",\"arg2\",\"arg3\",\"arg4\",\"arg5\",\"arg6\",\"arg7\",\"arg8\",\"arg9\"}},\n    { \"hidden\",             \"logging\",                &logging,                true,  {\"include\", \"exclude\"}},\n};\n\nvoid RegisterMiscRPCCommands(CRPCTable &t)\n{\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)\n        t.appendCommand(commands[vcidx].name, &commands[vcidx]);\n}\n"
  },
  {
    "path": "src/rpc/netrpc.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"rpc/server.h\"\n\n#include \"appname.h\"\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"netbase.h\"\n#include \"policy/policy.h\"\n#include \"protocol.h\"\n#include \"sync.h\"\n#include \"timedata.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"version.h\"\n#include \"warnings.h\"\n\n\n\n#include <univalue.h>\n\n\nstatic UniValue getconnectioncount(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getconnectioncount\\n\"\n            \"\\nReturns the number of connections to other nodes.\\n\"\n            \"\\nResult:\\n\"\n            \"n          (numeric) The connection count\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getconnectioncount\", \"\")\n            + HelpExampleRpc(\"getconnectioncount\", \"\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);\n}\n\nstatic UniValue ping(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"ping\\n\"\n            \"\\nRequests that a ping be sent to all other nodes, to measure ping time.\\n\"\n            \"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\\n\"\n            \"Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"ping\", \"\")\n            + HelpExampleRpc(\"ping\", \"\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    // Request that each node send a ping during next message processing pass\n    g_connman->ForEachNode([](CNode* pnode) {\n        pnode->fPingQueued = true;\n    });\n    return NullUniValue;\n}\n\nstatic UniValue getpeerinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getpeerinfo\\n\"\n            \"\\nReturns data about each connected network node as a json array of objects.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"id\\\": n,                   (numeric) Peer index\\n\"\n            \"    \\\"addr\\\":\\\"host:port\\\",      (string) The ip address and port of the peer\\n\"\n            \"    \\\"addrbind\\\":\\\"ip:port\\\",    (string) Bind address of the connection to the peer\\n\"\n            \"    \\\"addrlocal\\\":\\\"ip:port\\\",   (string) Local address as reported by the peer\\n\"\n            \"    \\\"services\\\":\\\"xxxxxxxxxxxxxxxx\\\",   (string) The services offered\\n\"\n            \"    \\\"relaytxes\\\":true|false,    (boolean) Whether peer has asked us to relay transactions to it\\n\"\n            \"    \\\"lastsend\\\": ttt,           (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\\n\"\n            \"    \\\"lastrecv\\\": ttt,           (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\\n\"\n            \"    \\\"bytessent\\\": n,            (numeric) The total bytes sent\\n\"\n            \"    \\\"bytesrecv\\\": n,            (numeric) The total bytes received\\n\"\n            \"    \\\"conntime\\\": ttt,           (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"    \\\"timeoffset\\\": ttt,         (numeric) The time offset in seconds\\n\"\n            \"    \\\"pingtime\\\": n,             (numeric) ping time (if available)\\n\"\n            \"    \\\"minping\\\": n,              (numeric) minimum observed ping time (if any at all)\\n\"\n            \"    \\\"pingwait\\\": n,             (numeric) ping wait (if non-zero)\\n\"\n            \"    \\\"version\\\": v,              (numeric) The peer version, such as 7001\\n\"\n            \"    \\\"subver\\\": \\\"/Satoshi:0.8.5/\\\",  (string) The string version\\n\"\n            \"    \\\"inbound\\\": true|false,     (boolean) Inbound (true) or Outbound (false)\\n\"\n            \"    \\\"addnode\\\": true|false,     (boolean) Whether connection was due to addnode and is using an addnode slot\\n\"\n            \"    \\\"startingheight\\\": n,       (numeric) The starting height (block) of the peer\\n\"\n            \"    \\\"banscore\\\": n,             (numeric) The ban score\\n\"\n            \"    \\\"synced_headers\\\": n,       (numeric) The last header we have in common with this peer\\n\"\n            \"    \\\"synced_blocks\\\": n,        (numeric) The last block we have in common with this peer\\n\"\n            \"    \\\"inflight\\\": [\\n\"\n            \"       n,                        (numeric) The heights of blocks we're currently asking from this peer\\n\"\n            \"       ...\\n\"\n            \"    ],\\n\"\n            \"    \\\"whitelisted\\\": true|false, (boolean) Whether the peer is whitelisted\\n\"\n            \"    \\\"bytessent_per_msg\\\": {\\n\"\n            \"       \\\"addr\\\": n,              (numeric) The total bytes sent aggregated by message type\\n\"\n            \"       ...\\n\"\n            \"    },\\n\"\n            \"    \\\"bytesrecv_per_msg\\\": {\\n\"\n            \"       \\\"addr\\\": n,              (numeric) The total bytes received aggregated by message type\\n\"\n            \"       ...\\n\"\n            \"    }\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getpeerinfo\", \"\")\n            + HelpExampleRpc(\"getpeerinfo\", \"\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    std::vector<CNodeStats> vstats;\n    g_connman->GetNodeStats(vstats);\n\n    UniValue ret(UniValue::VARR);\n\n    for(const CNodeStats& stats : vstats) {\n        UniValue obj(UniValue::VOBJ);\n        CNodeStateStats statestats;\n        bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);\n        obj.pushKV(\"id\", stats.nodeid);\n        obj.pushKV(\"addr\", stats.addrName);\n        if (!(stats.addrLocal.empty()))\n            obj.pushKV(\"addrlocal\", stats.addrLocal);\n        if (stats.addrBind.IsValid())\n            obj.pushKV(\"addrbind\", stats.addrBind.ToString());\n        obj.pushKV(\"services\", strprintf(\"%016x\", stats.nServices));\n        obj.pushKV(\"relaytxes\", stats.fRelayTxes);\n        obj.pushKV(\"lastsend\", stats.nLastSend);\n        obj.pushKV(\"lastrecv\", stats.nLastRecv);\n        obj.pushKV(\"bytessent\", stats.nSendBytes);\n        obj.pushKV(\"bytesrecv\", stats.nRecvBytes);\n        obj.pushKV(\"conntime\", stats.nTimeConnected);\n        obj.pushKV(\"timeoffset\", stats.nTimeOffset);\n        if (stats.dPingTime > 0.0)\n            obj.pushKV(\"pingtime\", stats.dPingTime);\n        if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)\n            obj.pushKV(\"minping\", stats.dMinPing);\n        if (stats.dPingWait > 0.0)\n            obj.pushKV(\"pingwait\", stats.dPingWait);\n        obj.pushKV(\"version\", stats.nVersion);\n        // Use the sanitized form of subver here, to avoid tricksy remote peers from\n        // corrupting or modifying the JSON output by putting special characters in\n        // their ver message.\n        obj.pushKV(\"subver\", stats.cleanSubVer);\n        obj.pushKV(\"inbound\", stats.fInbound);\n        obj.pushKV(\"addnode\", stats.fAddnode);\n        obj.pushKV(\"startingheight\", stats.nStartingHeight);\n        if (fStateStats) {\n            obj.pushKV(\"banscore\", statestats.nMisbehavior);\n            obj.pushKV(\"synced_headers\", statestats.nSyncHeight);\n            obj.pushKV(\"synced_blocks\", statestats.nCommonHeight);\n            UniValue heights(UniValue::VARR);\n            for(int height : statestats.vHeightInFlight) {\n                heights.push_back(height);\n            }\n            obj.pushKV(\"inflight\", heights);\n        }\n        obj.pushKV(\"whitelisted\", stats.fWhitelisted);\n\n        UniValue sendPerMsgCmd(UniValue::VOBJ);\n        for(const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {\n            if (i.second > 0)\n                sendPerMsgCmd.pushKV(i.first, i.second);\n        }\n        obj.pushKV(\"bytessent_per_msg\", sendPerMsgCmd);\n\n        UniValue recvPerMsgCmd(UniValue::VOBJ);\n        for(const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) {\n            if (i.second > 0)\n                recvPerMsgCmd.pushKV(i.first, i.second);\n        }\n        obj.pushKV(\"bytesrecv_per_msg\", recvPerMsgCmd);\n\n        ret.push_back(obj);\n    }\n\n    return ret;\n}\n\nstatic UniValue addnode(const JSONRPCRequest& request)\n{\n    std::string strCommand;\n    if (request.params.size() == 2)\n        strCommand = request.params[1].get_str();\n    if (request.fHelp || request.params.size() != 2 ||\n        (strCommand != \"onetry\" && strCommand != \"add\" && strCommand != \"remove\"))\n        throw std::runtime_error(\n            \"addnode \\\"node\\\" \\\"add|remove|onetry\\\"\\n\"\n            \"\\nAttempts add or remove a node from the addnode list.\\n\"\n            \"Or try a connection to a node once.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"node\\\"     (string, required) The node (see getpeerinfo for nodes)\\n\"\n            \"2. \\\"command\\\"  (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"addnode\", \"\\\"192.168.0.6:9231\\\" \\\"onetry\\\"\")\n            + HelpExampleRpc(\"addnode\", \"\\\"192.168.0.6:9231\\\", \\\"onetry\\\"\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    std::string strNode = request.params[0].get_str();\n\n    if (strCommand == \"onetry\")\n    {\n        CAddress addr;\n        g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());\n        return NullUniValue;\n    }\n\n    if (strCommand == \"add\")\n    {\n        if(!g_connman->AddNode(strNode))\n            throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, \"Error: Node already added\");\n    }\n    else if(strCommand == \"remove\")\n    {\n        if(!g_connman->RemoveAddedNode(strNode))\n            throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, \"Error: Node has not been added.\");\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue disconnectnode(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3)\n        throw std::runtime_error(\n            \"disconnectnode \\\"[address]\\\" [node_id]\\n\"\n            \"\\nImmediately disconnects from the specified peer node.\\n\"\n            \"\\nStrictly one out of 'address' and 'node_id' can be provided to identify the node.\\n\"\n            \"\\nTo disconnect by node_id, either set 'address' to the empty string, or call using the named 'node_id' argument only.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"     (string, optional) The IP address/port of the node\\n\"\n            \"2. \\\"node_id\\\"      (number, optional) The node ID (see getpeerinfo for node IDs)\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"disconnectnode\", \"\\\"192.168.0.6:8333\\\"\")\n            + HelpExampleCli(\"disconnectnode\", \"\\\"\\\" 1\")\n            + HelpExampleRpc(\"disconnectnode\", \"\\\"192.168.0.6:8333\\\"\")\n            + HelpExampleRpc(\"disconnectnode\", \"\\\"\\\", 1\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    bool success;\n    const UniValue &address_arg = request.params[0];\n    const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1];\n\n    if (!address_arg.isNull() && id_arg.isNull()) {\n        /* handle disconnect-by-address */\n        success = g_connman->DisconnectNode(address_arg.get_str());\n    } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {\n        /* handle disconnect-by-id */\n        NodeId nodeid = (NodeId) id_arg.get_int64();\n        success = g_connman->DisconnectNode(nodeid);\n    } else {\n        throw JSONRPCError(RPC_INVALID_PARAMS, \"Only one of address and nodeid should be provided.\");\n    }\n\n    if (!success) {\n        throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, \"Node not found in connected nodes\");\n    }\n\n    return NullUniValue;\n}\n\nstatic UniValue getaddednodeinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getaddednodeinfo ( \\\"node\\\" )\\n\"\n            \"\\nReturns information about the given added node, or all added nodes\\n\"\n            \"(note that onetry addnodes are not listed here)\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"node\\\"   (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"addednode\\\" : \\\"192.168.0.201\\\",   (string) The node ip address or name (as provided to addnode)\\n\"\n            \"    \\\"connected\\\" : true|false,          (boolean) If connected\\n\"\n            \"    \\\"addresses\\\" : [                    (list of objects) Only when connected = true\\n\"\n            \"       {\\n\"\n            \"         \\\"address\\\" : \\\"192.168.0.201:9231\\\",  (string) The \" GLOBAL_APPNAME \" server IP and port we're connected to\\n\"\n            \"         \\\"connected\\\" : \\\"outbound\\\"           (string) connection, inbound or outbound\\n\"\n            \"       }\\n\"\n            \"     ]\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getaddednodeinfo\", \"true\")\n            + HelpExampleCli(\"getaddednodeinfo\", \"true \\\"192.168.0.201\\\"\")\n            + HelpExampleRpc(\"getaddednodeinfo\", \"true, \\\"192.168.0.201\\\"\")\n        );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();\n\n    if (request.params.size() == 1) {\n        bool found = false;\n        for (const AddedNodeInfo& info : vInfo) {\n            if (info.strAddedNode == request.params[0].get_str()) {\n                vInfo.assign(1, info);\n                found = true;\n                break;\n            }\n        }\n        if (!found) {\n            throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, \"Error: Node has not been added.\");\n        }\n    }\n\n    UniValue ret(UniValue::VARR);\n\n    for (const AddedNodeInfo& info : vInfo) {\n        UniValue obj(UniValue::VOBJ);\n        obj.pushKV(\"addednode\", info.strAddedNode);\n        obj.pushKV(\"connected\", info.fConnected);\n        UniValue addresses(UniValue::VARR);\n        if (info.fConnected) {\n            UniValue address(UniValue::VOBJ);\n            address.pushKV(\"address\", info.resolvedAddress.ToString());\n            address.pushKV(\"connected\", info.fInbound ? \"inbound\" : \"outbound\");\n            addresses.push_back(address);\n        }\n        obj.pushKV(\"addresses\", addresses);\n        ret.push_back(obj);\n    }\n\n    return ret;\n}\n\nstatic UniValue getnettotals(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"getnettotals\\n\"\n            \"\\nReturns information about network traffic, including bytes in, bytes out,\\n\"\n            \"and current time.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"totalbytesrecv\\\": n,   (numeric) Total bytes received\\n\"\n            \"  \\\"totalbytessent\\\": n,   (numeric) Total bytes sent\\n\"\n            \"  \\\"timemillis\\\": t,       (numeric) Current UNIX time in milliseconds\\n\"\n            \"  \\\"uploadtarget\\\":\\n\"\n            \"  {\\n\"\n            \"    \\\"timeframe\\\": n,                         (numeric) Length of the measuring timeframe in seconds\\n\"\n            \"    \\\"target\\\": n,                            (numeric) Target in bytes\\n\"\n            \"    \\\"target_reached\\\": true|false,           (boolean) True if target is reached\\n\"\n            \"    \\\"serve_historical_blocks\\\": true|false,  (boolean) True if serving historical blocks\\n\"\n            \"    \\\"bytes_left_in_cycle\\\": t,               (numeric) Bytes left in current time cycle\\n\"\n            \"    \\\"time_left_in_cycle\\\": t                 (numeric) Seconds left in current time cycle\\n\"\n            \"  }\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getnettotals\", \"\")\n            + HelpExampleRpc(\"getnettotals\", \"\")\n       );\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"totalbytesrecv\", g_connman->GetTotalBytesRecv());\n    obj.pushKV(\"totalbytessent\", g_connman->GetTotalBytesSent());\n    obj.pushKV(\"timemillis\", GetTimeMillis());\n\n    UniValue outboundLimit(UniValue::VOBJ);\n    outboundLimit.pushKV(\"timeframe\", g_connman->GetMaxOutboundTimeframe());\n    outboundLimit.pushKV(\"target\", g_connman->GetMaxOutboundTarget());\n    outboundLimit.pushKV(\"target_reached\", g_connman->OutboundTargetReached(false));\n    outboundLimit.pushKV(\"serve_historical_blocks\", !g_connman->OutboundTargetReached(true));\n    outboundLimit.pushKV(\"bytes_left_in_cycle\", g_connman->GetOutboundTargetBytesLeft());\n    outboundLimit.pushKV(\"time_left_in_cycle\", g_connman->GetMaxOutboundTimeLeftInCycle());\n    obj.pushKV(\"uploadtarget\", outboundLimit);\n    return obj;\n}\n\nstatic UniValue GetNetworksInfo()\n{\n    UniValue networks(UniValue::VARR);\n    for(int n=0; n<NET_MAX; ++n)\n    {\n        enum Network network = static_cast<enum Network>(n);\n        if(network == NET_UNROUTABLE)\n            continue;\n        proxyType proxy;\n        UniValue obj(UniValue::VOBJ);\n        GetProxy(network, proxy);\n        obj.pushKV(\"name\", GetNetworkName(network));\n        obj.pushKV(\"limited\", IsLimited(network));\n        obj.pushKV(\"reachable\", IsReachable(network));\n        obj.pushKV(\"proxy\", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string());\n        obj.pushKV(\"proxy_randomize_credentials\", proxy.randomize_credentials);\n        networks.push_back(obj);\n    }\n    return networks;\n}\n\nstatic UniValue getnetworkinfo(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getnetworkinfo\\n\"\n            \"Returns an object containing various state info regarding P2P networking.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"version\\\": xxxxx,                      (numeric) the server version\\n\"\n            \"  \\\"subversion\\\": \\\"/Satoshi:x.x.x/\\\",     (string) the server subversion string\\n\"\n            \"  \\\"protocolversion\\\": xxxxx,              (numeric) the protocol version\\n\"\n            \"  \\\"localservices\\\": \\\"xxxxxxxxxxxxxxxx\\\", (string) the services we offer to the network\\n\"\n            \"  \\\"localrelay\\\": true|false,              (bool) true if transaction relay is requested from peers\\n\"\n            \"  \\\"timeoffset\\\": xxxxx,                   (numeric) the time offset\\n\"\n            \"  \\\"connections\\\": xxxxx,                  (numeric) the number of connections\\n\"\n            \"  \\\"networkactive\\\": true|false,           (bool) whether p2p networking is enabled\\n\"\n            \"  \\\"networks\\\": [                          (array) information per network\\n\"\n            \"  {\\n\"\n            \"    \\\"name\\\": \\\"xxx\\\",                     (string) network (ipv4, ipv6 or onion)\\n\"\n            \"    \\\"limited\\\": true|false,               (boolean) is the network limited using -onlynet?\\n\"\n            \"    \\\"reachable\\\": true|false,             (boolean) is the network reachable?\\n\"\n            \"    \\\"proxy\\\": \\\"host:port\\\"               (string) the proxy that is used for this network, or empty if none\\n\"\n            \"    \\\"proxy_randomize_credentials\\\": true|false,  (string) Whether randomized credentials are used\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"relayfee\\\": x.xxxxxxxx,                (numeric) minimum relay fee for transactions in \" + CURRENCY_UNIT + \"/kB\\n\"\n            \"  \\\"incrementalfee\\\": x.xxxxxxxx,          (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in \" + CURRENCY_UNIT + \"/kB\\n\"\n            \"  \\\"localaddresses\\\": [                    (array) list of local addresses\\n\"\n            \"  {\\n\"\n            \"    \\\"address\\\": \\\"xxxx\\\",                 (string) network address\\n\"\n            \"    \\\"port\\\": xxx,                         (numeric) network port\\n\"\n            \"    \\\"score\\\": xxx                         (numeric) relative score\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"  ]\\n\"\n            \"  \\\"warnings\\\": \\\"...\\\"                    (string) any network warnings\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getnetworkinfo\", \"\")\n            + HelpExampleRpc(\"getnetworkinfo\", \"\")\n        );\n\n    LOCK(cs_main);\n    UniValue obj(UniValue::VOBJ);\n    obj.pushKV(\"version\",       CLIENT_VERSION);\n    obj.pushKV(\"subversion\",    strSubVersion);\n    obj.pushKV(\"protocolversion\",PROTOCOL_VERSION);\n    if(g_connman)\n        obj.pushKV(\"localservices\", strprintf(\"%016x\", g_connman->GetLocalServices()));\n    obj.pushKV(\"localrelay\",     fRelayTxes);\n    obj.pushKV(\"timeoffset\",    GetTimeOffset());\n    if (g_connman) {\n        obj.pushKV(\"networkactive\", g_connman->GetNetworkActive());\n        obj.pushKV(\"connections\",   (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));\n    }\n    obj.pushKV(\"networks\",      GetNetworksInfo());\n    obj.pushKV(\"relayfee\",      ValueFromAmount(::minRelayTxFee.GetFeePerK()));\n    obj.pushKV(\"incrementalfee\", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));\n    UniValue localAddresses(UniValue::VARR);\n    {\n        LOCK(cs_mapLocalHost);\n        for(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item : mapLocalHost)\n        {\n            UniValue rec(UniValue::VOBJ);\n            rec.pushKV(\"address\", item.first.ToString());\n            rec.pushKV(\"port\", item.second.nPort);\n            rec.pushKV(\"score\", item.second.nScore);\n            localAddresses.push_back(rec);\n        }\n    }\n    obj.pushKV(\"localaddresses\", localAddresses);\n    obj.pushKV(\"warnings\",       GetWarnings(\"statusbar\"));\n    return obj;\n}\n\nstatic UniValue setban(const JSONRPCRequest& request)\n{\n    std::string strCommand;\n    if (request.params.size() >= 2)\n        strCommand = request.params[1].get_str();\n    if (request.fHelp || request.params.size() < 2 ||\n        (strCommand != \"add\" && strCommand != \"remove\"))\n        throw std::runtime_error(\n                            \"setban \\\"subnet\\\" \\\"add|remove\\\" (ban_time) (absolute)\\n\"\n                            \"\\nAttempts add or remove a IP/Subnet from the banned list.\\n\"\n                            \"\\nArguments:\\n\"\n                            \"1. \\\"subnet\\\"       (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\\n\"\n                            \"2. \\\"command\\\"      (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\\n\"\n                            \"3. \\\"ban_time\\\"     (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\\n\"\n                            \"4. \\\"absolute\\\"     (boolean, optional) If set, the ban_time must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\\n\"\n                            \"\\nExamples:\\n\"\n                            + HelpExampleCli(\"setban\", \"\\\"192.168.0.6\\\" \\\"add\\\" 86400\")\n                            + HelpExampleCli(\"setban\", \"\\\"192.168.0.0/24\\\" \\\"add\\\"\")\n                            + HelpExampleRpc(\"setban\", \"\\\"192.168.0.6\\\", \\\"add\\\", 86400\")\n                            );\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    CSubNet subNet;\n    CNetAddr netAddr;\n    bool isSubnet = false;\n\n    if (request.params[0].get_str().find(\"/\") != std::string::npos)\n        isSubnet = true;\n\n    if (!isSubnet) {\n        CNetAddr resolved;\n        LookupHost(request.params[0].get_str().c_str(), resolved, false);\n        netAddr = resolved;\n    }\n    else\n        LookupSubNet(request.params[0].get_str().c_str(), subNet);\n\n    if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )\n        throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, \"Error: Invalid IP/Subnet\");\n\n    if (strCommand == \"add\")\n    {\n        if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))\n            throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, \"Error: IP/Subnet already banned\");\n\n        int64_t banTime = 0; //use standard bantime if not specified\n        if (request.params.size() >= 3 && !request.params[2].isNull())\n            banTime = request.params[2].get_int64();\n\n        bool absolute = false;\n        if (request.params.size() == 4 && request.params[3].isTrue())\n            absolute = true;\n\n        isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);\n    }\n    else if(strCommand == \"remove\")\n    {\n        if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))\n            throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, \"Error: Unban failed. Requested address/subnet was not previously banned.\");\n    }\n    return NullUniValue;\n}\n\nstatic UniValue listbanned(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n                            \"listbanned\\n\"\n                            \"\\nList all banned IPs/Subnets.\\n\"\n                            \"\\nExamples:\\n\"\n                            + HelpExampleCli(\"listbanned\", \"\")\n                            + HelpExampleRpc(\"listbanned\", \"\")\n                            );\n\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    banmap_t banMap;\n    g_connman->GetBanned(banMap);\n\n    UniValue bannedAddresses(UniValue::VARR);\n    for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)\n    {\n        CBanEntry banEntry = (*it).second;\n        UniValue rec(UniValue::VOBJ);\n        rec.pushKV(\"address\", (*it).first.ToString());\n        rec.pushKV(\"banned_until\", banEntry.nBanUntil);\n        rec.pushKV(\"ban_created\", banEntry.nCreateTime);\n        rec.pushKV(\"ban_reason\", banEntry.banReasonToString());\n\n        bannedAddresses.push_back(rec);\n    }\n\n    return bannedAddresses;\n}\n\nstatic UniValue clearbanned(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n                            \"clearbanned\\n\"\n                            \"\\nClear all banned IPs.\\n\"\n                            \"\\nExamples:\\n\"\n                            + HelpExampleCli(\"clearbanned\", \"\")\n                            + HelpExampleRpc(\"clearbanned\", \"\")\n                            );\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    g_connman->ClearBanned();\n\n    return NullUniValue;\n}\n\nstatic UniValue setnetworkactive(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1) {\n        throw std::runtime_error(\n            \"setnetworkactive true|false\\n\"\n            \"\\nDisable/enable all p2p network activity.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"state\\\"        (boolean, required) true to enable networking, false to disable\\n\"\n        );\n    }\n\n    if (!g_connman) {\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n    }\n\n    g_connman->SetNetworkActive(request.params[0].get_bool());\n\n    return g_connman->GetNetworkActive();\n}\n\nstatic UniValue disablenetwork(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0) {\n        throw std::runtime_error(\n            \"disablenetwork\\n\"\n            \"\\nStops all p2p network activity, call \\\"enablenetwork\\\" to start p2p activity again.\\n\"\n        );\n    }\n\n    if (!g_connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\"); }\n\n    g_connman->SetNetworkActive(false);\n    return !g_connman->GetNetworkActive();\n}\n\nstatic UniValue enablenetwork(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 0) {\n        throw std::runtime_error(\n            \"enablenetwork\\n\"\n            \"\\nStarts all p2p network activity, call \\\"disablenetwork\\\" to stop p2p activity again.\\n\"\n        );\n    }\n\n    if (!g_connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\"); }\n\n    g_connman->SetNetworkActive(true);\n    return g_connman->GetNetworkActive();\n}\n\nstatic const CRPCCommand commands[] =\n{ //  category              name                      actor (function)         okSafeMode\n  //  --------------------- ------------------------  -----------------------  ----------\n    { \"network\",            \"getconnectioncount\",     &getconnectioncount,     true,  {} },\n    { \"network\",            \"ping\",                   &ping,                   true,  {} },\n    { \"network\",            \"getpeerinfo\",            &getpeerinfo,            true,  {} },\n    { \"network\",            \"addnode\",                &addnode,                true,  {\"node\",\"command\"} },\n    { \"network\",            \"disconnectnode\",         &disconnectnode,         true,  {\"address\", \"node_id\"} },\n    { \"network\",            \"getaddednodeinfo\",       &getaddednodeinfo,       true,  {\"node\"} },\n    { \"network\",            \"getnettotals\",           &getnettotals,           true,  {} },\n    { \"network\",            \"getnetworkinfo\",         &getnetworkinfo,         true,  {} },\n    { \"network\",            \"setban\",                 &setban,                 true,  {\"subnet\", \"command\", \"ban_time\", \"absolute\"} },\n    { \"network\",            \"listbanned\",             &listbanned,             true,  {} },\n    { \"network\",            \"clearbanned\",            &clearbanned,            true,  {} },\n    { \"network\",            \"setnetworkactive\",       &setnetworkactive,       true,  {\"state\"} },\n    { \"network\",            \"disablenetwork\",         &disablenetwork,         true,  {} },\n    { \"network\",            \"enablenetwork\",          &enablenetwork,          true,  {} },\n};\n\nvoid RegisterNetRPCCommands(CRPCTable &t)\n{\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)\n        t.appendCommand(commands[vcidx].name, &commands[vcidx]);\n}\n"
  },
  {
    "path": "src/rpc/protocol.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"rpc/protocol.h\"\n\n#include \"random.h\"\n#include \"tinyformat.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"util/time.h\"\n#include \"version.h\"\n\n#include <stdint.h>\n#include <fstream>\n\n/**\n * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,\n * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were\n * unspecified (HTTP errors and contents of 'error').\n * \n * 1.0 spec: http://json-rpc.org/wiki/specification\n * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html\n */\n\nUniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)\n{\n    UniValue request(UniValue::VOBJ);\n    request.pushKV(\"method\", strMethod);\n    request.pushKV(\"params\", params);\n    request.pushKV(\"id\", id);\n    return request;\n}\n\nUniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)\n{\n    UniValue reply(UniValue::VOBJ);\n    if (!error.isNull())\n        reply.pushKV(\"result\", NullUniValue);\n    else\n        reply.pushKV(\"result\", result);\n    reply.pushKV(\"error\", error);\n    reply.pushKV(\"id\", id);\n    return reply;\n}\n\nstd::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)\n{\n    UniValue reply = JSONRPCReplyObj(result, error, id);\n    return reply.write() + \"\\n\";\n}\n\nUniValue JSONRPCError(int code, const std::string& message)\n{\n    UniValue error(UniValue::VOBJ);\n    error.pushKV(\"code\", code);\n    error.pushKV(\"message\", message);\n    return error;\n}\n\n/** Username used when cookie authentication is in use (arbitrary, only for\n * recognizability in debugging/logging purposes)\n */\nstatic const std::string COOKIEAUTH_USER = \"__cookie__\";\n/** Default name for auth cookie file */\nstatic const std::string COOKIEAUTH_FILE = \".cookie\";\n\nfs::path GetAuthCookieFile()\n{\n    fs::path path(GetArg(\"-rpccookiefile\", COOKIEAUTH_FILE));\n    if (!path.is_complete()) path = GetDataDir() / path;\n    return path;\n}\n\nbool GenerateAuthCookie(std::string *cookie_out)\n{\n    const size_t COOKIE_SIZE = 32;\n    unsigned char rand_pwd[COOKIE_SIZE];\n    GetRandBytes(rand_pwd, COOKIE_SIZE);\n    std::string cookie = COOKIEAUTH_USER + \":\" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);\n\n    /** the umask determines what permissions are used to create this file -\n     * these are set to 077 in init.cpp unless overridden with -sysperms.\n     */\n    std::ofstream file;\n    fs::path filepath = GetAuthCookieFile();\n    file.open(filepath.string().c_str());\n    if (!file.is_open()) {\n        LogPrintf(\"Unable to open cookie authentication file %s for writing\\n\", filepath.string());\n        return false;\n    }\n    file << cookie;\n    file.close();\n    LogPrintf(\"Generated RPC authentication cookie %s\\n\", filepath.string());\n\n    if (cookie_out)\n        *cookie_out = cookie;\n    return true;\n}\n\nbool GetAuthCookie(std::string *cookie_out)\n{\n    std::ifstream file;\n    std::string cookie;\n    fs::path filepath = GetAuthCookieFile();\n    file.open(filepath.string().c_str());\n    if (!file.is_open())\n        return false;\n    std::getline(file, cookie);\n    file.close();\n\n    if (cookie_out)\n        *cookie_out = cookie;\n    return true;\n}\n\nvoid DeleteAuthCookie()\n{\n    try {\n        fs::remove(GetAuthCookieFile());\n    } catch (const fs::filesystem_error& e) {\n        LogPrintf(\"%s: Unable to remove random auth cookie file: %s\\n\", __func__, e.what());\n    }\n}\n\n"
  },
  {
    "path": "src/rpc/protocol.h",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef RPCPROTOCOL_H\n#define RPCPROTOCOL_H\n\n#include \"fs.h\"\n\n#include <list>\n#include <map>\n#include <stdint.h>\n#include <string>\n\n#include <univalue.h>\n\n//! HTTP status codes\nenum HTTPStatusCode\n{\n    HTTP_OK                    = 200,\n    HTTP_BAD_REQUEST           = 400,\n    HTTP_UNAUTHORIZED          = 401,\n    HTTP_FORBIDDEN             = 403,\n    HTTP_NOT_FOUND             = 404,\n    HTTP_BAD_METHOD            = 405,\n    HTTP_INTERNAL_SERVER_ERROR = 500,\n    HTTP_SERVICE_UNAVAILABLE   = 503,\n};\n\n//! Munt RPC error codes\nenum RPCErrorCode\n{\n    //! Standard JSON-RPC 2.0 errors\n    // RPC_INVALID_REQUEST is internally mapped to HTTP_BAD_REQUEST (400).\n    // It should not be used for application-layer errors.\n    RPC_INVALID_REQUEST  = -32600,\n    // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404).\n    // It should not be used for application-layer errors.\n    RPC_METHOD_NOT_FOUND = -32601,\n    RPC_INVALID_PARAMS   = -32602,\n    // RPC_INTERNAL_ERROR should only be used for genuine errors in Munt-daemon\n    // (for example datadir corruption).\n    RPC_INTERNAL_ERROR   = -32603,\n    RPC_PARSE_ERROR      = -32700,\n\n    //! General application defined errors\n    RPC_MISC_ERROR                  = -1,  //!< std::exception thrown in command handling\n    RPC_FORBIDDEN_BY_SAFE_MODE      = -2,  //!< Server is in safe mode, and command is not allowed in safe mode\n    RPC_TYPE_ERROR                  = -3,  //!< Unexpected type was passed as parameter\n    RPC_INVALID_ADDRESS_OR_KEY      = -5,  //!< Invalid address or key\n    RPC_OUT_OF_MEMORY               = -7,  //!< Ran out of memory during operation\n    RPC_INVALID_PARAMETER           = -8,  //!< Invalid, missing or duplicate parameter\n    RPC_DATABASE_ERROR              = -20, //!< Database error\n    RPC_DESERIALIZATION_ERROR       = -22, //!< Error parsing or validating structure in raw format\n    RPC_VERIFY_ERROR                = -25, //!< General error during transaction or block submission\n    RPC_VERIFY_REJECTED             = -26, //!< Transaction or block was rejected by network rules\n    RPC_VERIFY_ALREADY_IN_CHAIN     = -27, //!< Transaction already in chain\n    RPC_IN_WARMUP                   = -28, //!< Client still warming up\n\n    //! Aliases for backward compatibility\n    RPC_TRANSACTION_ERROR           = RPC_VERIFY_ERROR,\n    RPC_TRANSACTION_REJECTED        = RPC_VERIFY_REJECTED,\n    RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,\n\n    //! P2P client errors\n    RPC_CLIENT_NOT_CONNECTED        = -9,  //!< Munt is not connected\n    RPC_CLIENT_IN_INITIAL_DOWNLOAD  = -10, //!< Still downloading initial blocks\n    RPC_CLIENT_NODE_ALREADY_ADDED   = -23, //!< Node is already added\n    RPC_CLIENT_NODE_NOT_ADDED       = -24, //!< Node has not been added before\n    RPC_CLIENT_NODE_NOT_CONNECTED   = -29, //!< Node to disconnect not found in connected nodes\n    RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet\n    RPC_CLIENT_P2P_DISABLED         = -31, //!< No valid connection manager instance found\n\n    //! Wallet errors\n    RPC_WALLET_ERROR                = -4,  //!< Unspecified problem with wallet (key not found etc.)\n    RPC_WALLET_INSUFFICIENT_FUNDS   = -6,  //!< Not enough funds in wallet or account\n    RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name\n    RPC_WALLET_KEYPOOL_RAN_OUT      = -12, //!< Keypool ran out, call keypoolrefill first\n    RPC_WALLET_UNLOCK_NEEDED        = -13, //!< Enter the wallet passphrase with walletpassphrase first\n    RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect\n    RPC_WALLET_WRONG_ENC_STATE      = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)\n    RPC_WALLET_ENCRYPTION_FAILED    = -16, //!< Failed to encrypt the wallet\n    RPC_WALLET_ALREADY_UNLOCKED     = -17, //!< Wallet is already unlocked\n};\n\nUniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);\nUniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);\nstd::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);\nUniValue JSONRPCError(int code, const std::string& message);\n\n/** Get name of RPC authentication cookie file */\nfs::path GetAuthCookieFile();\n/** Generate a new RPC authentication cookie and write it to disk */\nbool GenerateAuthCookie(std::string *cookie_out);\n/** Read the RPC authentication cookie from disk */\nbool GetAuthCookie(std::string *cookie_out);\n/** Delete RPC authentication cookie from disk */\nvoid DeleteAuthCookie();\n\n#endif\n"
  },
  {
    "path": "src/rpc/rawtransaction.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"base58.h\"\n#include \"chain.h\"\n#include \"coins.h\"\n#include \"consensus/validation.h\"\n#include \"core_io.h\"\n#include \"init.h\"\n#include \"keystore.h\"\n#include \"merkleblock.h\"\n#include \"net.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"primitives/transaction.h\"\n#include \"rpc/server.h\"\n#include \"script/script.h\"\n#include \"script/script_error.h\"\n#include \"script/sign.h\"\n#include \"script/standard.h\"\n#include \"txmempool.h\"\n#include \"uint256.h\"\n#include \"util/strencodings.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/rpcwallet.h\"\n#include \"wallet/wallet.h\"\n#endif\n\n#include <stdint.h>\n\n#include <univalue.h>\n\n//fixme: (PHASE5) - We can remove this include\n#include \"witnessutil.h\"\n#include \"validation/validation.h\"\n\n\nvoid TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)\n{\n    // Call into TxToUniv() in Munt-common to decode the transaction hex.\n    //\n    // Blockchain contextual information (confirmations and blocktime) is not\n    // available to code in Munt-common, so we query them here and push the\n    // data into the returned UniValue.\n    TxToUniv(tx, uint256(), entry);\n\n    if (!hashBlock.IsNull()) {\n        entry.pushKV(\"blockhash\", hashBlock.GetHex());\n        BlockMap::iterator mi = mapBlockIndex.find(hashBlock);\n        if (mi != mapBlockIndex.end() && (*mi).second) {\n            CBlockIndex* pindex = (*mi).second;\n            if (chainActive.Contains(pindex)) {\n                entry.pushKV(\"confirmations\", 1 + chainActive.Height() - pindex->nHeight);\n                entry.pushKV(\"time\", pindex->GetBlockTimePoW2Witness());\n                entry.pushKV(\"blocktime\", pindex->GetBlockTimePoW2Witness());\n            }\n            else\n                entry.pushKV(\"confirmations\", 0);\n        }\n    }\n}\n\nUniValue getrawtransaction(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getrawtransaction \\\"txid\\\" ( verbose )\\n\"\n\n            \"\\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\\n\"\n            \"enabled, it also works for blockchain transactions.\\n\"\n            \"DEPRECATED: for now, it also works for transactions with unspent outputs.\\n\"\n\n            \"\\nReturn the raw transaction data.\\n\"\n            \"\\nIf verbose is 'true', returns an Object with information about 'txid'.\\n\"\n            \"If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\\n\"\n\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"      (string, required) The transaction id\\n\"\n            \"2. verbose       (bool, optional, default=false) If false, return a string, otherwise return a json object\\n\"\n\n            \"\\nResult (if verbose is not set or set to false):\\n\"\n            \"\\\"data\\\"      (string) The serialized, hex-encoded data for 'txid'\\n\"\n\n            \"\\nResult (if verbose is set to true):\\n\"\n            \"{\\n\"\n            \"  \\\"hex\\\" : \\\"data\\\",                 (string) The serialized, hex-encoded data for 'txid'\\n\"\n            \"  \\\"txid\\\" : \\\"id\\\",                  (string) The transaction id (same as provided)\\n\"\n            \"  \\\"hash\\\" : \\\"id\\\",                  (string) The transaction hash\\n\"\n            \"  \\\"size\\\" : n,                       (numeric) The serialized transaction size\\n\"\n            \"  \\\"vsize\\\" : n,                      (numeric) The virtual transaction size\\n\"\n            \"  \\\"version\\\" : n,                    (numeric) The version\\n\"\n            \"  \\\"locktime\\\" : ttt,                 (numeric) The lock time\\n\"\n            \"  \\\"vin\\\" : [                         (array of json objects)\\n\"\n            \"     {\\n\"\n            \"       \\\"prevout_type\\\" : \\\"type\\\",   (string) How we reference the prevout, either 'hash' or 'index'\\n\"\n            \"       \\\"txid\\\": \\\"id\\\",              (string) The transaction id\\n\"\n            \"       \\\"tx_height\\\": \\\"id\\\",         (string) The height of the block containing the input\\n\"\n            \"       \\\"tx_index\\\": \\\"id\\\",          (string) The index of the transaction within the containing block\\n\"\n            \"       \\\"vout\\\": n,                   (numeric) \\n\"\n            \"       \\\"scriptSig\\\": {               (json object) The script\\n\"\n            \"         \\\"asm\\\": \\\"asm\\\",            (string) asm\\n\"\n            \"         \\\"hex\\\": \\\"hex\\\"             (string) hex\\n\"\n            \"       },\\n\"\n            \"       \\\"sequence\\\": n                (numeric) The script sequence number\\n\"\n            \"       \\\"txin_sig_data\\\": [\\\"hex\\\", ...] (array of string) hex-encoded segregated signature data (if any)\\n\"\n            \"     }\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"vout\\\" : [                        (array of json objects)\\n\"\n            \"     {\\n\"\n            \"       \\\"value\\\" : x.xxx,             (numeric) The value in \" + CURRENCY_UNIT + \"\\n\"\n            \"       \\\"n\\\" : n,                     (numeric) index\\n\"\n            \"       \\\"scriptPubKey\\\" : {           (json object)\\n\"\n            \"         \\\"asm\\\" : \\\"asm\\\",           (string) the asm\\n\"\n            \"         \\\"hex\\\" : \\\"hex\\\",           (string) the hex\\n\"\n            \"         \\\"reqSigs\\\" : n,             (numeric) The required sigs\\n\"\n            \"         \\\"type\\\" : \\\"pubkeyhash\\\",   (string) The type, eg 'pubkeyhash'\\n\"\n            \"         \\\"addresses\\\" : [            (json array of string)\\n\"\n            \"           \\\"address\\\"                (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"           ,...\\n\"\n            \"         ]\\n\"\n            \"       }\\n\"\n            \"     }\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"blockhash\\\" : \\\"hash\\\",           (string) the block hash\\n\"\n            \"  \\\"confirmations\\\" : n,              (numeric) The confirmations\\n\"\n            \"  \\\"time\\\" : ttt,                     (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"  \\\"blocktime\\\" : ttt                 (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getrawtransaction\", \"\\\"mytxid\\\"\")\n            + HelpExampleCli(\"getrawtransaction\", \"\\\"mytxid\\\" true\")\n            + HelpExampleRpc(\"getrawtransaction\", \"\\\"mytxid\\\", true\")\n        );\n\n    LOCK(cs_main);\n\n    uint256 hash = ParseHashV(request.params[0], \"parameter 1\");\n\n    // Accept either a bool (true) or a num (>=1) to indicate verbose output.\n    bool fVerbose = false;\n    if (request.params.size() > 1) {\n        if (request.params[1].isNum()) {\n            if (request.params[1].get_int() != 0) {\n                fVerbose = true;\n            }\n        }\n        else if(request.params[1].isBool()) {\n            if(request.params[1].isTrue()) {\n                fVerbose = true;\n            }\n        }\n        else {\n            throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid type provided. Verbose parameter must be a boolean.\");\n        }\n    }\n\n    CTransactionRef tx;\n    uint256 hashBlock;\n    if (!GetTransaction(hash, tx, Params(), hashBlock, true))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? \"No such mempool or blockchain transaction\"\n            : \"No such mempool transaction. Use -txindex to enable blockchain transaction queries\") +\n            \". Use gettransaction for wallet transactions.\");\n\n    std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());\n\n    if (!fVerbose)\n        return strHex;\n\n    UniValue result(UniValue::VOBJ);\n    TxToJSON(*tx, hashBlock, result);\n    return result;\n}\n\nUniValue gettxoutproof(const JSONRPCRequest& request)\n{\n    if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))\n        throw std::runtime_error(\n            \"gettxoutproof [\\\"txid\\\",...] ( blockhash )\\n\"\n            \"\\nReturns a hex-encoded proof that \\\"txid\\\" was included in a block.\\n\"\n            \"\\nNOTE: By default this function only works sometimes. This is when there is an\\n\"\n            \"unspent output in the utxo for this transaction. To make it always work,\\n\"\n            \"you need to maintain a transaction index, using the -txindex command line option or\\n\"\n            \"specify the block in which the transaction is included manually (by blockhash).\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txids\\\"       (string) A json array of txids to filter\\n\"\n            \"    [\\n\"\n            \"      \\\"txid\\\"     (string) A transaction hash\\n\"\n            \"      ,...\\n\"\n            \"    ]\\n\"\n            \"2. \\\"blockhash\\\"   (string, optional) If specified, looks for txid in the block with this hash\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"data\\\"           (string) A string that is a serialized, hex-encoded data for the proof.\\n\"\n        );\n\n    std::set<uint256> setTxids;\n    uint256 oneTxid;\n    UniValue txids = request.params[0].get_array();\n    for (unsigned int idx = 0; idx < txids.size(); idx++) {\n        const UniValue& txid = txids[idx];\n        if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))\n            throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid txid \")+txid.get_str());\n        uint256 hash(uint256S(txid.get_str()));\n        if (setTxids.count(hash))\n            throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid parameter, duplicated txid: \")+txid.get_str());\n       setTxids.insert(hash);\n       oneTxid = hash;\n    }\n\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n    CBlockIndex* pblockindex = NULL;\n\n    uint256 hashBlock;\n    if (request.params.size() > 1)\n    {\n        hashBlock = uint256S(request.params[1].get_str());\n        if (!mapBlockIndex.count(hashBlock))\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found\");\n        pblockindex = mapBlockIndex[hashBlock];\n    } else {\n        const Coin& coin = AccessByTxid(*pcoinsTip, oneTxid);\n        if (!coin.IsSpent() && coin.nHeight > 0 && coin.nHeight <= chainActive.Height()) {\n            pblockindex = chainActive[coin.nHeight];\n        }\n    }\n\n    if (pblockindex == NULL)\n    {\n        CTransactionRef tx;\n        if (!GetTransaction(oneTxid, tx, Params(), hashBlock, false) || hashBlock.IsNull())\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction not yet in block\");\n        if (!mapBlockIndex.count(hashBlock))\n            throw JSONRPCError(RPC_INTERNAL_ERROR, \"Transaction index corrupt\");\n        pblockindex = mapBlockIndex[hashBlock];\n    }\n\n    CBlock block;\n    if(!ReadBlockFromDisk(block, pblockindex, Params()))\n        throw JSONRPCError(RPC_INTERNAL_ERROR, \"Can't read block from disk\");\n\n    unsigned int ntxFound = 0;\n    for (const auto& tx : block.vtx)\n        if (setTxids.count(tx->GetHash()))\n            ntxFound++;\n    if (ntxFound != setTxids.size())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"(Not all) transactions not found in specified block\");\n\n    CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES);\n    CMerkleBlock mb(block, setTxids);\n    ssMB << mb;\n    std::string strHex = HexStr(ssMB.begin(), ssMB.end());\n    return strHex;\n}\n\nUniValue verifytxoutproof(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"verifytxoutproof \\\"proof\\\"\\n\"\n            \"\\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\\n\"\n            \"and throwing an RPC error if the block is not in our best chain\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"proof\\\"    (string, required) The hex-encoded proof generated by gettxoutproof\\n\"\n            \"\\nResult:\\n\"\n            \"[\\\"txid\\\"]      (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\\n\"\n        );\n\n    CDataStream ssMB(ParseHexV(request.params[0], \"proof\"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES);\n    CMerkleBlock merkleBlock;\n    ssMB >> merkleBlock;\n\n    UniValue res(UniValue::VARR);\n\n    std::vector<uint256> vMatch;\n    std::vector<unsigned int> vIndex;\n    if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)\n        return res;\n\n    LOCK(cs_main);\n\n    if (!mapBlockIndex.count(merkleBlock.header.GetHashPoW2()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHashPoW2()]))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found in chain\");\n\n    for(const uint256& hash : vMatch)\n        res.push_back(hash.GetHex());\n    return res;\n}\n\nUniValue createrawtransaction(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"createrawtransaction [{\\\"txid\\\":\\\"id\\\",\\\"vout\\\":n},...] {\\\"address\\\":amount,\\\"data\\\":\\\"hex\\\",...} ( lock_time ) ( opt_in_to_rbf )\\n\"\n            \"\\nCreate a transaction spending the given inputs and creating new outputs.\\n\"\n            \"Outputs can be addresses or data.\\n\"\n            \"Returns hex-encoded raw transaction.\\n\"\n            \"Note that the transaction's inputs are not signed, and\\n\"\n            \"it is not stored in the wallet or transmitted to the network.\\n\"\n\n            \"\\nArguments:\\n\"\n            \"1. \\\"inputs\\\"                (array, required) A json array of json objects\\n\"\n            \"     [\\n\"\n            \"       {\\n\"\n            \"         \\\"txid\\\":\\\"id\\\",      (string, required) The transaction id\\n\"\n            \"         \\\"vout\\\":n,         (numeric, required) The output number\\n\"\n            \"         \\\"sequence\\\":n      (numeric, optional) The sequence number\\n\"\n            \"       } \\n\"\n            \"       ,...\\n\"\n            \"     ]\\n\"\n            \"2. \\\"outputs\\\"               (object, required) a json object with outputs\\n\"\n            \"    {\\n\"\n            \"      \\\"address\\\": x.xxx,    (numeric or string, required) The key is the \" GLOBAL_APPNAME \" address, the numeric value (can be string) is the \" + CURRENCY_UNIT + \" amount\\n\"\n            \"      \\\"data\\\": \\\"hex\\\"        (string, required) The key is \\\"data\\\", the value is hex encoded data\\n\"\n            \"      ,...\\n\"\n            \"    }\\n\"\n            \"3. lock_time               (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\\n\"\n            \"4. opt_in_to_rbf           (boolean, optional, default=false) Allow this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"transaction\\\"              (string) hex string of the transaction\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"createrawtransaction\", \"\\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"myid\\\\\\\",\\\\\\\"vout\\\\\\\":0}]\\\" \\\"{\\\\\\\"address\\\\\\\":0.01}\\\"\")\n            + HelpExampleCli(\"createrawtransaction\", \"\\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"myid\\\\\\\",\\\\\\\"vout\\\\\\\":0}]\\\" \\\"{\\\\\\\"data\\\\\\\":\\\\\\\"00010203\\\\\\\"}\\\"\")\n            + HelpExampleRpc(\"createrawtransaction\", \"\\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"myid\\\\\\\",\\\\\\\"vout\\\\\\\":0}]\\\", \\\"{\\\\\\\"address\\\\\\\":0.01}\\\"\")\n            + HelpExampleRpc(\"createrawtransaction\", \"\\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"myid\\\\\\\",\\\\\\\"vout\\\\\\\":0}]\\\", \\\"{\\\\\\\"data\\\\\\\":\\\\\\\"00010203\\\\\\\"}\\\"\")\n        );\n\n    RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM}, true);\n    if (request.params[0].isNull() || request.params[1].isNull())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, arguments 1 and 2 must be non-null\");\n\n    UniValue inputs = request.params[0].get_array();\n    UniValue sendTo = request.params[1].get_obj();\n\n    CMutableTransaction rawTx(CURRENT_TX_VERSION_POW2);\n\n    if (request.params.size() > 2 && !request.params[2].isNull())\n    {\n        int64_t nLockTime = request.params[2].get_int64();\n        if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, locktime out of range\");\n        rawTx.nLockTime = nLockTime;\n    }\n\n    bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false;\n\n    for (unsigned int idx = 0; idx < inputs.size(); idx++)\n    {\n        const UniValue& input = inputs[idx];\n        const UniValue& o = input.get_obj();\n\n        uint256 txid = ParseHashO(o, \"txid\");\n\n        const UniValue& vout_v = find_value(o, \"vout\");\n        if (!vout_v.isNum())\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, missing vout key\");\n        int nOutput = vout_v.get_int();\n        if (nOutput < 0)\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, vout must be positive\");\n\n        uint32_t nSequence = 0;\n        uint8_t nFlags = 0;\n        if (IsOldTransactionVersion(rawTx.nVersion))\n        {\n            if (rbfOptIn)\n            {\n                nSequence = MAX_BIP125_RBF_SEQUENCE;\n            }\n            else if (rawTx.nLockTime)\n            {\n                nSequence = std::numeric_limits<uint32_t>::max() - 1;\n            }\n            else\n            {\n                nSequence = std::numeric_limits<uint32_t>::max();\n            }\n        }\n        else\n        {\n            if (rbfOptIn)\n                nFlags |= CTxInFlags::OptInRBF;\n            //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n            //if (rawTx.nLockTime)\n                //nFlags |= CTxInFlags::HasTimeBasedRelativeLock;\n        }\n\n        // set the sequence number if passed in the parameters object\n        const UniValue& sequenceObj = find_value(o, \"sequence\");\n        if (sequenceObj.isNum())\n        {\n            int64_t seqNr64 = sequenceObj.get_int64();\n            if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max())\n            {\n                throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, sequence number is out of range\");\n            }\n            else\n            {\n                nSequence = (uint32_t)seqNr64;\n            }\n        }\n\n        CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence, nFlags);\n\n        rawTx.vin.push_back(in);\n    }\n\n    std::set<CNativeAddress> setAddress;\n    std::vector<std::string> addrList = sendTo.getKeys();\n    for(const std::string& name_ : addrList)\n    {\n        if (name_ == \"data\")\n        {\n            std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),\"Data\");\n\n            CTxOut out(0, CScript() << OP_RETURN << data);\n            rawTx.vout.push_back(out);\n        }\n        else\n        {\n            CNativeAddress address(name_);\n            if (!address.IsValid())\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(\"Invalid \" GLOBAL_APPNAME \" address: \")+name_);\n\n            if (setAddress.count(address))\n                throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid parameter, duplicated address: \")+name_);\n            setAddress.insert(address);\n\n            if (!IsOldTransactionVersion(rawTx.nVersion))\n            {\n                CKeyID keyID;\n                address.GetKeyID(keyID);\n                CTxOutStandardKeyHash keyHashForDestination(keyID);\n                CAmount nAmount = AmountFromValue(sendTo[name_]);\n                CTxOut out(nAmount, keyHashForDestination);\n                rawTx.vout.push_back(out);\n            }\n            else\n            {\n                CScript scriptPubKey = GetScriptForDestination(address.Get());\n                CAmount nAmount = AmountFromValue(sendTo[name_]);\n                CTxOut out(nAmount, scriptPubKey);\n                rawTx.vout.push_back(out);\n            }\n        }\n    }\n\n    if (request.params.size() > 3 && rbfOptIn != SignalsOptInRBF(rawTx))\n    {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter combination: Sequence number(s) contradict optintorbf option\");\n    }\n\n    return EncodeHexTx(rawTx);\n}\n\nUniValue decoderawtransaction(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"decoderawtransaction \\\"hexstring\\\"\\n\"\n            \"\\nReturn a JSON object representing the serialized, hex-encoded transaction.\\n\"\n\n            \"\\nArguments:\\n\"\n            \"1. \\\"hexstring\\\"      (string, required) The transaction hex string\\n\"\n\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"txid\\\" : \\\"id\\\",        (string) The transaction id\\n\"\n            \"  \\\"hash\\\" : \\\"id\\\",        (string) The transaction hash (differs from txid for segsig transactions)\\n\"\n            \"  \\\"size\\\" : n,             (numeric) The transaction size\\n\"\n            \"  \\\"vsize\\\" : n,            (numeric) The virtual transaction size (differs from size for segsig transactions)\\n\"\n            \"  \\\"version\\\" : n,          (numeric) The version\\n\"\n            \"  \\\"locktime\\\" : ttt,       (numeric) The lock time\\n\"\n            \"  \\\"vin\\\" : [               (array of json objects)\\n\"\n            \"     {\\n\"\n            \"       \\\"txid\\\": \\\"id\\\",    (string) The transaction id\\n\"\n            \"       \\\"vout\\\": n,         (numeric) The output number\\n\"\n            \"       \\\"scriptSig\\\": {     (json object) The script\\n\"\n            \"         \\\"asm\\\": \\\"asm\\\",  (string) asm\\n\"\n            \"         \\\"hex\\\": \\\"hex\\\"   (string) hex\\n\"\n            \"       },\\n\"\n            \"       \\\"txin_sig_data\\\": [\\\"hex\\\", ...] (array of string) hex-encoded segregated signature data (if any)\\n\"\n            \"       \\\"sequence\\\": n     (numeric) The script sequence number\\n\"\n            \"     }\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"vout\\\" : [             (array of json objects)\\n\"\n            \"     {\\n\"\n            \"       \\\"value\\\" : x.xxx,            (numeric) The value in \" + CURRENCY_UNIT + \"\\n\"\n            \"       \\\"n\\\" : n,                    (numeric) index\\n\"\n            \"       \\\"scriptPubKey\\\" : {          (json object)\\n\"\n            \"         \\\"asm\\\" : \\\"asm\\\",          (string) the asm\\n\"\n            \"         \\\"hex\\\" : \\\"hex\\\",          (string) the hex\\n\"\n            \"         \\\"reqSigs\\\" : n,            (numeric) The required sigs\\n\"\n            \"         \\\"type\\\" : \\\"pubkeyhash\\\",  (string) The type, eg 'pubkeyhash'\\n\"\n            \"         \\\"addresses\\\" : [           (json array of string)\\n\"\n            \"           \\\"G2tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\\\"   (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"           ,...\\n\"\n            \"         ]\\n\"\n            \"       }\\n\"\n            \"     }\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"decoderawtransaction\", \"\\\"hexstring\\\"\")\n            + HelpExampleRpc(\"decoderawtransaction\", \"\\\"hexstring\\\"\")\n        );\n\n    LOCK(cs_main);\n    RPCTypeCheck(request.params, {UniValue::VSTR});\n\n    CMutableTransaction mtx(CURRENT_TX_VERSION_POW2);\n\n    if (!DecodeHexTx(mtx, request.params[0].get_str(), true))\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"TX decode failed\");\n\n    UniValue result(UniValue::VOBJ);\n    TxToUniv(CTransaction(std::move(mtx)), uint256(), result);\n\n    return result;\n}\n\nUniValue decodescript(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"decodescript \\\"hexstring\\\"\\n\"\n            \"\\nDecode a hex-encoded script.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"hexstring\\\"     (string) the hex encoded script\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"asm\\\":\\\"asm\\\",   (string) Script public key\\n\"\n            \"  \\\"hex\\\":\\\"hex\\\",   (string) hex encoded public key\\n\"\n            \"  \\\"type\\\":\\\"type\\\", (string) The output type\\n\"\n            \"  \\\"reqSigs\\\": n,    (numeric) The required signatures\\n\"\n            \"  \\\"addresses\\\": [   (json array of string)\\n\"\n            \"     \\\"address\\\"     (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"     ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"p2sh\\\",\\\"address\\\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"decodescript\", \"\\\"hexstring\\\"\")\n            + HelpExampleRpc(\"decodescript\", \"\\\"hexstring\\\"\")\n        );\n\n    RPCTypeCheck(request.params, {UniValue::VSTR});\n\n    UniValue r(UniValue::VOBJ);\n    CScript script;\n    if (request.params[0].get_str().size() > 0){\n        std::vector<unsigned char> scriptData(ParseHexV(request.params[0], \"argument\"));\n        script = CScript(scriptData.begin(), scriptData.end());\n    } else {\n        // Empty scripts are valid\n    }\n    \n    CTxOutPoW2Witness phase3WitnessInfo;\n    if (script.ExtractPoW2WitnessFromScript(phase3WitnessInfo))\n    {\n        r.pushKV(\"type\", \"pow2_phase3_witness\");\n        r.pushKV(\"witness_address\", CNativeAddress(CPoW2WitnessDestination(phase3WitnessInfo.spendingKeyID, phase3WitnessInfo.witnessKeyID)).ToString());\n        r.pushKV(\"spending_key_address\", CNativeAddress(phase3WitnessInfo.spendingKeyID).ToString());\n        r.pushKV(\"witness_key_address\", CNativeAddress(phase3WitnessInfo.witnessKeyID).ToString());\n        r.pushKV(\"lock_from_block\", i64tostr(phase3WitnessInfo.lockFromBlock));\n        r.pushKV(\"lock_until_block\", i64tostr(phase3WitnessInfo.lockUntilBlock));\n        r.pushKV(\"fail_count\", i64tostr(phase3WitnessInfo.failCount));\n        r.pushKV(\"action_nonce\", i64tostr(phase3WitnessInfo.actionNonce));\n        return r;\n    }\n    \n    ScriptPubKeyToUniv(script, r, false);\n\n    UniValue type;\n    type = find_value(r, \"type\");\n\n    if (type.isStr() && type.get_str() != \"scripthash\") {\n        // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,\n        // don't return the address for a P2SH of the P2SH.\n        r.pushKV(\"p2sh\", CNativeAddress(CScriptID(script)).ToString());\n    }\n\n    return r;\n}\n\n/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */\nstatic void TxInErrorToJSON(const uint64_t nTransactionVersion, const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)\n{\n    UniValue entry(UniValue::VOBJ);\n    uint256 txHash;\n    if (GetTxHash(txin.GetPrevOut(), txHash))\n        entry.pushKV(\"txid\", txHash.ToString());\n    entry.pushKV(\"vout\", (uint64_t)txin.GetPrevOut().n);\n    UniValue sigData(UniValue::VARR);\n    for (unsigned int i = 0; i < txin.segregatedSignatureData.stack.size(); i++) {\n        sigData.push_back(HexStr(txin.segregatedSignatureData.stack[i].begin(), txin.segregatedSignatureData.stack[i].end()));\n    }\n    entry.pushKV(\"sig_data\", sigData);\n    entry.pushKV(\"scriptSig\", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));\n    entry.pushKV(\"sequence\", (uint64_t)txin.GetSequence(nTransactionVersion));\n    entry.pushKV(\"error\", strMessage);\n    vErrorsRet.push_back(entry);\n}\n\nUniValue signrawtransaction(const JSONRPCRequest& request)\n{\n#ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n#endif\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"signrawtransaction \\\"hexstring\\\" ( [{\\\"txid\\\":\\\"id\\\",\\\"vout\\\":n,\\\"scriptPubKey\\\":\\\"hex\\\",\\\"redeemScript\\\":\\\"hex\\\"},...] [\\\"privatekey1\\\",...] sighashtype )\\n\"\n            \"\\nSign inputs for raw transaction (serialized, hex-encoded).\\n\"\n            \"The second optional argument (may be null) is an array of previous transaction outputs that\\n\"\n            \"this transaction depends on but may not yet be in the block chain.\\n\"\n            \"The third optional argument (may be null) is an array of base58-encoded private\\n\"\n            \"keys that, if given, will be the only keys used to sign the transaction.\\n\"\n#ifdef ENABLE_WALLET\n            + HelpRequiringPassphrase(pwallet) + \"\\n\"\n#endif\n\n            \"\\nArguments:\\n\"\n            \"1. \\\"hexstring\\\"     (string, required) The transaction hex string\\n\"\n            \"2. \\\"prev_txs\\\"      (string, optional) An json array of previous dependent transaction outputs\\n\"\n            \"     [               (json array of json objects, or 'null' if none provided)\\n\"\n            \"       {\\n\"\n            \"         \\\"txid\\\":\\\"id\\\",             (string, required) The transaction id\\n\"\n            \"         \\\"vout\\\":n,                  (numeric, required) The output number\\n\"\n            \"         \\\"scriptPubKey\\\": \\\"hex\\\",   (string, required) script key\\n\"\n            \"         \\\"redeemScript\\\": \\\"hex\\\",   (string, required for P2SH or P2WSH) redeem script\\n\"\n            \"         \\\"amount\\\": value            (numeric, required) The amount spent\\n\"\n            \"       }\\n\"\n            \"       ,...\\n\"\n            \"    ]\\n\"\n            \"3. \\\"priv_keys\\\"     (string, optional) A json array of base58-encoded private keys for signing\\n\"\n            \"    [                  (json array of strings, or 'null' if none provided)\\n\"\n            \"      \\\"privatekey\\\"   (string) private key in base58-encoding\\n\"\n            \"      ,...\\n\"\n            \"    ]\\n\"\n            \"4. \\\"sighashtype\\\"     (string, optional, default=ALL) The signature hash type. Must be one of\\n\"\n            \"       \\\"ALL\\\"\\n\"\n            \"       \\\"NONE\\\"\\n\"\n            \"       \\\"SINGLE\\\"\\n\"\n            \"       \\\"ALL|ANYONECANPAY\\\"\\n\"\n            \"       \\\"NONE|ANYONECANPAY\\\"\\n\"\n            \"       \\\"SINGLE|ANYONECANPAY\\\"\\n\"\n            \"5. \\\"signtype\\\"     (string, optional, default=Spend) The type of signing operation to do (Spend or Witness) - only significant for witness addess transactions.\\n\"\n            \"       \\\"Spend\\\"\\n\"\n            \"       \\\"Witness\\\"\\n\"\n\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"hex\\\" : \\\"value\\\",           (string) The hex-encoded raw transaction with signature(s)\\n\"\n            \"  \\\"complete\\\" : true|false,   (boolean) If the transaction has a complete set of signatures\\n\"\n            \"  \\\"errors\\\" : [                 (json array of objects) Script verification errors (if there are any)\\n\"\n            \"    {\\n\"\n            \"      \\\"txid\\\" : \\\"hash\\\",           (string) The hash of the referenced, previous transaction\\n\"\n            \"      \\\"vout\\\" : n,                (numeric) The index of the output to spent and used as input\\n\"\n            \"      \\\"scriptSig\\\" : \\\"hex\\\",       (string) The hex-encoded signature script\\n\"\n            \"      \\\"sequence\\\" : n,            (numeric) Script sequence number\\n\"\n            \"      \\\"error\\\" : \\\"text\\\"           (string) Verification or signing error related to the input\\n\"\n            \"    }\\n\"\n            \"    ,...\\n\"\n            \"  ]\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"signrawtransaction\", \"\\\"myhex\\\"\")\n            + HelpExampleRpc(\"signrawtransaction\", \"\\\"myhex\\\"\")\n        );\n\n#ifdef ENABLE_WALLET\n    LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n#else\n    LOCK(cs_main);\n#endif\n    RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);\n\n    std::vector<unsigned char> txData(ParseHexV(request.params[0], \"argument 1\"));\n    CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);\n    std::vector<CMutableTransaction> txVariants;\n    while (!ssData.empty()) {\n        try {\n            CMutableTransaction tx(CURRENT_TX_VERSION_POW2);\n            ssData >> tx;\n            txVariants.push_back(tx);\n        }\n        catch (const std::exception&) {\n            throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"TX decode failed\");\n        }\n    }\n\n    if (txVariants.empty())\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"Missing transaction\");\n\n    // mergedTx will end up with all the signatures; it\n    // starts as a clone of the rawtx:\n    CMutableTransaction mergedTx(txVariants[0]);\n\n    // Fetch previous transactions (inputs):\n    CCoinsView viewDummy;\n    CCoinsViewCache view(&viewDummy);\n    {\n        LOCK(mempool.cs);\n        CCoinsViewCache &viewChain = *pcoinsTip;\n        CCoinsViewMemPool viewMempool(&viewChain, mempool);\n        view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view\n\n        for(const CTxIn& txin : mergedTx.vin) {\n            view.AccessCoin(txin.GetPrevOut()); // Load entries from viewChain into view; can fail.\n        }\n\n        view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long\n    }\n\n    bool fGivenKeys = false;\n    CBasicKeyStore tempKeystore;\n    if (request.params.size() > 2 && !request.params[2].isNull()) {\n        fGivenKeys = true;\n        UniValue keys = request.params[2].get_array();\n        for (unsigned int idx = 0; idx < keys.size(); idx++) {\n            UniValue k = keys[idx];\n            CEncodedSecretKey vchSecret;\n            bool fGood = vchSecret.SetString(k.get_str());\n            if (!fGood)\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid private key\");\n            CKey key = vchSecret.GetKey();\n            if (!key.IsValid())\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Private key outside allowed range\");\n            tempKeystore.AddKey(key);\n        }\n    }\n#ifdef ENABLE_WALLET\n    else if (pwallet) {\n        EnsureWalletIsUnlocked(pwallet);\n    }\n#endif\n\n    // Add previous txouts given in the RPC call:\n    if (request.params.size() > 1 && !request.params[1].isNull()) {\n        UniValue prevTxs = request.params[1].get_array();\n        for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {\n            const UniValue& p = prevTxs[idx];\n            if (!p.isObject())\n                throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"expected object with {\\\"txid'\\\",\\\"vout\\\",\\\"scriptPubKey\\\"}\");\n\n            UniValue prevOut = p.get_obj();\n\n            RPCTypeCheckObj(prevOut,\n                {\n                    {\"txid\", UniValueType(UniValue::VSTR)},\n                    {\"vout\", UniValueType(UniValue::VNUM)},\n                    {\"scriptPubKey\", UniValueType(UniValue::VSTR)},\n                });\n\n            uint256 txid = ParseHashO(prevOut, \"txid\");\n\n            int nOut = find_value(prevOut, \"vout\").get_int();\n            if (nOut < 0)\n                throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"vout must be positive\");\n\n            COutPoint out(txid, nOut);\n            std::vector<unsigned char> pkData(ParseHexO(prevOut, \"scriptPubKey\"));\n            CScript scriptPubKey(pkData.begin(), pkData.end());\n\n            {\n                const Coin& coin = view.AccessCoin(out);\n                if (!coin.IsSpent() && coin.out.output.nType == ScriptLegacyOutput && coin.out.output.scriptPubKey != scriptPubKey)\n                {\n                    std::string err(\"Previous output scriptPubKey mismatch:\\n\");\n                    err = err + ScriptToAsmStr(coin.out.output.scriptPubKey) + \"\\nvs:\\n\" + ScriptToAsmStr(scriptPubKey);\n                    throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);\n                }\n                Coin newcoin;\n                newcoin.out.output.scriptPubKey = scriptPubKey;\n                newcoin.out.nValue = 0;\n                if (prevOut.exists(\"amount\")) {\n                    newcoin.out.nValue = AmountFromValue(find_value(prevOut, \"amount\"));\n                }\n                newcoin.nHeight = 1;\n                view.AddCoin(out, std::move(newcoin), true);\n            }\n\n            // if redeemScript given and not using the local wallet (private keys\n            // given), add redeemScript to the tempKeystore so it can be signed:\n            if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() ))\n            {\n                RPCTypeCheckObj(prevOut,\n                    {\n                        {\"txid\", UniValueType(UniValue::VSTR)},\n                        {\"vout\", UniValueType(UniValue::VNUM)},\n                        {\"scriptPubKey\", UniValueType(UniValue::VSTR)},\n                        {\"redeemScript\", UniValueType(UniValue::VSTR)},\n                    });\n                UniValue v = find_value(prevOut, \"redeemScript\");\n                if (!v.isNull()) {\n                    std::vector<unsigned char> rsData(ParseHexV(v, \"redeemScript\"));\n                    CScript redeemScript(rsData.begin(), rsData.end());\n                    tempKeystore.AddCScript(redeemScript);\n                }\n            }\n        }\n    }\n\n#ifdef ENABLE_WALLET\n    std::vector<CKeyStore*> accountsToTry;\n    if (fGivenKeys || !pwallet || !pwallet->activeAccount)\n    {\n        accountsToTry.push_back(&tempKeystore);\n    }\n    else\n    {\n        for (const auto& accountPair : pactiveWallet->mapAccounts)\n        {\n            accountsToTry.push_back(accountPair.second);\n        }\n    }\n#else\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&tempKeystore);\n#endif\n\n    int nHashType = SIGHASH_ALL;\n    if (request.params.size() > 3 && !request.params[3].isNull()) {\n        static std::map<std::string, int> mapSigHashValues = {\n            {std::string(\"ALL\"), int(SIGHASH_ALL)},\n            {std::string(\"ALL|ANYONECANPAY\"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},\n            {std::string(\"NONE\"), int(SIGHASH_NONE)},\n            {std::string(\"NONE|ANYONECANPAY\"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},\n            {std::string(\"SINGLE\"), int(SIGHASH_SINGLE)},\n            {std::string(\"SINGLE|ANYONECANPAY\"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},\n        };\n        std::string strHashType = request.params[3].get_str();\n        if (mapSigHashValues.count(strHashType))\n            nHashType = mapSigHashValues[strHashType];\n        else\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid sighash param\");\n    }\n\n    SignType signType = Spend;\n\n    if (request.params.size() > 4 && !request.params[4].isNull()) {\n        std::string strHashType = request.params[3].get_str();\n        if (strHashType == \"Witness\" || strHashType == \"witness\" || strHashType == \"WITNESS\")\n            signType = Witness;\n        else if (strHashType == \"Spend\" || strHashType == \"spend\" || strHashType == \"SPEND\")\n            signType = Spend;\n        else\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Unknown sign type\");\n    }\n\n    bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);\n\n    // Script verification errors\n    UniValue vErrors(UniValue::VARR);\n\n    // Use CTransaction for the constant parts of the\n    // transaction to avoid rehashing.\n    const CTransaction txConst(mergedTx);\n    // Sign what we can:\n    for (unsigned int i = 0; i < mergedTx.vin.size(); i++)\n    {\n        CTxIn& txin = mergedTx.vin[i];\n        const Coin& coin = view.AccessCoin(txin.GetPrevOut());\n        if (coin.IsSpent()) {\n            TxInErrorToJSON(mergedTx.nVersion, txin, vErrors, \"Input not found or already spent\");\n            continue;\n        }\n        \n        const CAmount& amount = coin.out.nValue;\n\n        CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(coin.out, signType);\n\n        SignatureData sigdata;\n        // Only sign SIGHASH_SINGLE if there's a corresponding output:\n        if (!fHashSingle || (i < mergedTx.vout.size()))\n            ProduceSignature(MutableTransactionSignatureCreator(signingKeyID, accountsToTry, &mergedTx, i, amount, nHashType), coin.out, sigdata, signType, mergedTx.nVersion);\n\n        switch (coin.out.output.nType)\n        {\n            case ScriptLegacyOutput:\n            {\n                const CScript& prevPubKey = coin.out.output.scriptPubKey;\n                // ... and merge in other signatures:\n                for(const CMutableTransaction& txv : txVariants)\n                {\n                    if (txv.vin.size() > i)\n                    {\n                        sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(signingKeyID, CKeyID(), &txConst, i, amount), sigdata, DataFromTransaction(txv, i), IsOldTransactionVersion(mergedTx.nVersion) ? SIGVERSION_BASE : SIGVERSION_SEGSIG);\n                    }\n                }\n                \n                UpdateTransaction(mergedTx, i, sigdata);\n\n                ScriptError serror = SCRIPT_ERR_OK;\n                if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.segregatedSignatureData, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(signingKeyID, CKeyID(), &txConst, i, amount), IsOldTransactionVersion(mergedTx.nVersion) ? SCRIPT_V1 : SCRIPT_V2, &serror)) {\n                    TxInErrorToJSON(mergedTx.nVersion, txin, vErrors, ScriptErrorString(serror));\n                }\n                break;\n            }\n            case PoW2WitnessOutput:\n            {\n                if (!SignSignature(accountsToTry, coin.out, mergedTx, i, amount, nHashType, SignType::Spend))\n                {\n                    throw JSONRPCError(RPC_INVALID_PARAMETER, \"Failed to sign witness output\");\n                }\n                break;\n            }\n            case StandardKeyHashOutput:\n            {\n                if (!SignSignature(accountsToTry, coin.out, mergedTx, i, amount, nHashType, SignType::Spend))\n                {\n                    throw JSONRPCError(RPC_INVALID_PARAMETER, \"Failed to sign keyhash output\");\n                }\n            }\n        }\n\n        \n    }\n    bool fComplete = vErrors.empty();\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"hex\", EncodeHexTx(mergedTx));\n    result.pushKV(\"complete\", fComplete);\n    if (!vErrors.empty()) {\n        result.pushKV(\"errors\", vErrors);\n    }\n\n    return result;\n}\n\nUniValue sendrawtransaction(const JSONRPCRequest& request)\n{\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"sendrawtransaction \\\"hexstring\\\" ( allow_high_fees )\\n\"\n            \"\\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\\n\"\n            \"\\nAlso see createrawtransaction and signrawtransaction calls.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"hexstring\\\"    (string, required) The hex string of the raw transaction)\\n\"\n            \"2. allow_high_fees    (boolean, optional, default=false) Allow high fees\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"hex\\\"             (string) The transaction hash in hex\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nCreate a transaction\\n\"\n            + HelpExampleCli(\"createrawtransaction\", \"\\\"[{\\\\\\\"txid\\\\\\\" : \\\\\\\"mytxid\\\\\\\",\\\\\\\"vout\\\\\\\":0}]\\\" \\\"{\\\\\\\"myaddress\\\\\\\":0.01}\\\"\") +\n            \"Sign the transaction, and get back the hex\\n\"\n            + HelpExampleCli(\"signrawtransaction\", \"\\\"myhex\\\"\") +\n            \"\\nSend the transaction (signed hex)\\n\"\n            + HelpExampleCli(\"sendrawtransaction\", \"\\\"signedhex\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"sendrawtransaction\", \"\\\"signedhex\\\"\")\n        );\n\n    LOCK(cs_main);\n    RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});\n\n    // parse hex string from parameter\n    CMutableTransaction mtx(CURRENT_TX_VERSION_POW2);\n    if (!DecodeHexTx(mtx, request.params[0].get_str()))\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"TX decode failed\");\n    CTransactionRef tx(MakeTransactionRef(std::move(mtx)));\n    const uint256& hashTx = tx->GetHash();\n\n    CAmount nMaxRawTxFee = maxTxFee;\n    if (request.params.size() > 1 && request.params[1].get_bool())\n        nMaxRawTxFee = 0;\n\n    CCoinsViewCache &view = *pcoinsTip;\n    bool fHaveChain = false;\n    for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {\n        const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));\n        fHaveChain = !existingCoin.IsSpent();\n    }\n    bool fHaveMempool = mempool.exists(hashTx);\n    if (!fHaveMempool && !fHaveChain) {\n        // push to local node and sync with wallets\n        CValidationState state;\n        bool fMissingInputs;\n        bool fLimitFree = true;\n        if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, NULL, false, nMaxRawTxFee)) {\n            if (state.IsInvalid()) {\n                throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf(\"%i: %s\", state.GetRejectCode(), state.GetRejectReason()));\n            } else {\n                if (fMissingInputs) {\n                    throw JSONRPCError(RPC_TRANSACTION_ERROR, \"Missing inputs\");\n                }\n                throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());\n            }\n        }\n    } else if (fHaveChain) {\n        throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, \"transaction already in block chain\");\n    }\n    if(!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    CInv inv(MSG_TX, hashTx);\n    g_connman->ForEachNode([&inv](CNode* pnode)\n    {\n        pnode->PushInventory(inv);\n    });\n    return hashTx.GetHex();\n}\n\nstatic const CRPCCommand commands[] =\n{ //  category              name                      actor (function)         okSafeMode\n  //  --------------------- ------------------------  -----------------------  ----------\n    { \"rawtransactions\",    \"getrawtransaction\",      &getrawtransaction,      true,  {\"txid\",\"verbose\"} },\n    { \"rawtransactions\",    \"createrawtransaction\",   &createrawtransaction,   true,  {\"inputs\",\"outputs\",\"locktime\",\"opt_in_to_rbf\"} },\n    { \"rawtransactions\",    \"decoderawtransaction\",   &decoderawtransaction,   true,  {\"hexstring\"} },\n    { \"rawtransactions\",    \"decodescript\",           &decodescript,           true,  {\"hexstring\"} },\n    { \"rawtransactions\",    \"sendrawtransaction\",     &sendrawtransaction,     false, {\"hexstring\",\"allow_high_fees\"} },\n    { \"rawtransactions\",    \"signrawtransaction\",     &signrawtransaction,     false, {\"hexstring\",\"prev_txs\",\"priv_keys\",\"sighashtype\"} }, /* uses wallet if enabled */\n\n    { \"blockchain\",         \"gettxoutproof\",          &gettxoutproof,          true,  {\"txids\", \"blockhash\"} },\n    { \"blockchain\",         \"verifytxoutproof\",       &verifytxoutproof,       true,  {\"proof\"} },\n};\n\nvoid RegisterRawTransactionRPCCommands(CRPCTable &t)\n{\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)\n        t.appendCommand(commands[vcidx].name, &commands[vcidx]);\n}\n"
  },
  {
    "path": "src/rpc/register.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef RPCREGISTER_H\n#define RPCREGISTER_H\n\n/** These are in one header file to avoid creating tons of single-function\n * headers for everything under src/rpc/ */\nclass CRPCTable;\n\n/** Register block chain RPC commands */\nvoid RegisterBlockchainRPCCommands(CRPCTable &tableRPC);\n/** Register P2P networking RPC commands */\nvoid RegisterNetRPCCommands(CRPCTable &tableRPC);\n/** Register miscellaneous RPC commands */\nvoid RegisterMiscRPCCommands(CRPCTable &tableRPC);\n/** Register mining RPC commands */\nvoid RegisterMiningRPCCommands(CRPCTable &tableRPC);\n/** Register raw transaction RPC commands */\nvoid RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);\n\n\n#ifdef ENABLE_WALLET\n/** Register Munt RPC commands */\nvoid RegisterMuntRPCCommands(CRPCTable &tableRPC);\n#endif\n\nstatic inline void RegisterAllCoreRPCCommands(CRPCTable &t)\n{\n    RegisterBlockchainRPCCommands(t);\n    RegisterNetRPCCommands(t);\n    RegisterMiscRPCCommands(t);\n    RegisterMiningRPCCommands(t);\n    RegisterRawTransactionRPCCommands(t);\n    #ifdef ENABLE_WALLET\n    RegisterMuntRPCCommands(t);\n    #endif\n}\n\n#endif\n"
  },
  {
    "path": "src/rpc/server.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"rpc/server.h\"\n\n#include \"appname.h\"\n#include \"base58.h\"\n#include \"fs.h\"\n#include \"init.h\"\n#include \"random.h\"\n#include \"sync.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#include <unity/appmanager.h>\n\n#include <univalue.h>\n\n#include <boost/bind.hpp>\n\n#include <boost/signals2/signal.hpp>\n#include <boost/algorithm/string/case_conv.hpp> // for to_upper()\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/split.hpp>\n\n#include <memory> // for unique_ptr\n#include <unordered_map>\n\nstatic bool fRPCRunning = false;\nstatic bool fRPCInWarmup = true;\nstatic std::string rpcWarmupStatus(\"RPC server started\");\nstatic RecursiveMutex cs_rpcWarmup;\n\n\nstatic struct CRPCSignals\n{\n    boost::signals2::signal<void ()> Started;\n    boost::signals2::signal<void ()> Stopped;\n    boost::signals2::signal<void (const CRPCCommand&)> PreCommand;\n} g_rpcSignals;\n\nvoid RPCServer::OnStarted(std::function<void ()> slot)\n{\n    g_rpcSignals.Started.connect(slot);\n}\n\nvoid RPCServer::OnStopped(std::function<void ()> slot)\n{\n    g_rpcSignals.Stopped.connect(slot);\n}\n\nvoid RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)\n{\n    g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));\n}\n\nvoid RPCTypeCheck(const UniValue& params,\n                  const std::list<UniValue::VType>& typesExpected,\n                  bool fAllowNull)\n{\n    unsigned int i = 0;\n    for(UniValue::VType t : typesExpected)\n    {\n        if (params.size() <= i)\n            break;\n\n        const UniValue& v = params[i];\n        if (!(fAllowNull && v.isNull())) {\n            RPCTypeCheckArgument(v, t);\n        }\n        i++;\n    }\n}\n\nvoid RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)\n{\n    if (value.type() != typeExpected) {\n        throw JSONRPCError(RPC_TYPE_ERROR, strprintf(\"Expected type %s, got %s\", uvTypeName(typeExpected), uvTypeName(value.type())));\n    }\n}\n\nvoid RPCTypeCheckObj(const UniValue& o,\n    const std::map<std::string, UniValueType>& typesExpected,\n    bool fAllowNull,\n    bool fStrict)\n{\n    for (const auto& t : typesExpected) {\n        const UniValue& v = find_value(o, t.first);\n        if (!fAllowNull && v.isNull())\n            throw JSONRPCError(RPC_TYPE_ERROR, strprintf(\"Missing %s\", t.first));\n\n        if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {\n            std::string err = strprintf(\"Expected type %s for %s, got %s\",\n                uvTypeName(t.second.type), t.first, uvTypeName(v.type()));\n            throw JSONRPCError(RPC_TYPE_ERROR, err);\n        }\n    }\n\n    if (fStrict)\n    {\n        for(const std::string& k : o.getKeys())\n        {\n            if (typesExpected.count(k) == 0)\n            {\n                std::string err = strprintf(\"Unexpected key %s\", k);\n                throw JSONRPCError(RPC_TYPE_ERROR, err);\n            }\n        }\n    }\n}\n\nCAmount AmountFromValue(const UniValue& value, bool allowNegative)\n{\n    if (!value.isNum() && !value.isStr())\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Amount is not a number or string\");\n    CAmount amount;\n    if (!ParseFixedPoint(value.getValStr(), 8, &amount))\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount\");\n    if (!allowNegative && !MoneyRange(amount))\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Amount out of range\");\n    return amount;\n}\n\nUniValue ValueFromAmount(const CAmount& amount)\n{\n    bool sign = amount < 0;\n    int64_t n_abs = (sign ? -amount : amount);\n    int64_t quotient = n_abs / COIN;\n    int64_t remainder = n_abs % COIN;\n    return UniValue(UniValue::VNUM,\n            strprintf(\"%s%d.%08d\", sign ? \"-\" : \"\", quotient, remainder));\n}\n\nuint256 ParseHashV(const UniValue& v, std::string strName)\n{\n    std::string strHex;\n    if (v.isStr())\n        strHex = v.get_str();\n    if (!IsHex(strHex)) // Note: IsHex(\"\") is false\n        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+\" must be hexadecimal string (not '\"+strHex+\"')\");\n    if (64 != strHex.length())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"%s must be of length %d (not %d)\", strName, 64, strHex.length()));\n    uint256 result;\n    result.SetHex(strHex);\n    return result;\n}\nuint256 ParseHashO(const UniValue& o, std::string strKey)\n{\n    return ParseHashV(find_value(o, strKey), strKey);\n}\nstd::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)\n{\n    std::string strHex;\n    if (v.isStr())\n        strHex = v.get_str();\n    if (!IsHex(strHex))\n        throw JSONRPCError(RPC_INVALID_PARAMETER, strName+\" must be hexadecimal string (not '\"+strHex+\"')\");\n    return ParseHex(strHex);\n}\nstd::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)\n{\n    return ParseHexV(find_value(o, strKey), strKey);\n}\n\n/**\n * Note: This interface may still be subject to change.\n */\n\nstd::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const\n{\n    std::string strRet;\n    std::string category;\n    std::set<rpcfn_type> setDone;\n    std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;\n\n    for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)\n        vCommands.push_back(std::pair(mi->second->category + mi->first, mi->second));\n    sort(vCommands.begin(), vCommands.end());\n\n    JSONRPCRequest jreq(helpreq);\n    jreq.fHelp = true;\n    jreq.params = UniValue();\n\n    for(const PAIRTYPE(std::string, const CRPCCommand*)& command : vCommands)\n    {\n        const CRPCCommand *pcmd = command.second;\n        std::string strMethod = pcmd->name;\n        if ((strCommand != \"\" || pcmd->category == \"hidden\" || pcmd->category == \"support\") && strMethod != strCommand)\n            continue;\n        jreq.strMethod = strMethod;\n        try\n        {\n            rpcfn_type pfn = pcmd->actor;\n            if (setDone.insert(pfn).second)\n                (*pfn)(jreq);\n        }\n        catch (const std::exception& e)\n        {\n            // Help text is returned in an exception\n            std::string strHelp = std::string(e.what());\n            if (strCommand == \"\")\n            {\n                if (strHelp.find('\\n') != std::string::npos)\n                    strHelp = strHelp.substr(0, strHelp.find('\\n'));\n\n                if (category != pcmd->category)\n                {\n                    if (!category.empty())\n                        strRet += \"\\n\";\n                    category = pcmd->category;\n                    std::string firstLetter = category.substr(0,1);\n                    boost::to_upper(firstLetter);\n                    strRet += \"== \" + firstLetter + category.substr(1) + \" ==\\n\";\n                }\n            }\n            strRet += strHelp + \"\\n\";\n        }\n    }\n    if (strRet == \"\")\n        strRet = strprintf(\"help: unknown command: %s\\n\", strCommand);\n    strRet = strRet.substr(0,strRet.size()-1);\n    return strRet;\n}\n\nstatic UniValue help(const JSONRPCRequest& jsonRequest)\n{\n    if (jsonRequest.fHelp || jsonRequest.params.size() > 1)\n        throw std::runtime_error(\n            \"help ( \\\"command\\\" )\\n\"\n            \"\\nList all commands, or get help for a specified command.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"command\\\"     (string, optional) The command to get help on\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"text\\\"     (string) The help text\\n\"\n        );\n\n    std::string strCommand;\n    if (jsonRequest.params.size() > 0)\n        strCommand = jsonRequest.params[0].get_str();\n\n    return tableRPC.help(strCommand, jsonRequest);\n}\n\n\nstatic UniValue stop(const JSONRPCRequest& jsonRequest)\n{\n    // Accept the deprecated and ignored 'detach' boolean argument\n    // Also accept the hidden 'wait' integer argument (milliseconds)\n    // For instance, 'stop 1000' makes the call wait 1 second before returning\n    // to the client (intended for testing)\n    if (jsonRequest.fHelp || jsonRequest.params.size() > 1)\n        throw std::runtime_error(\n            \"stop\\n\"\n            \"\\nStop \" GLOBAL_APPNAME \" server.\");\n    // Event loop will exit after current HTTP requests have been handled, so\n    // this reply will get back to the client.\n    LogPrintf(\"shutdown: 'stop' called via RPC, terminating app\");\n    AppLifecycleManager::gApp->shutdown();\n    if (jsonRequest.params[0].isNum()) {\n        MilliSleep(jsonRequest.params[0].get_int());\n    }\n    return GLOBAL_APPNAME\" server stopping\";\n}\n\nstatic UniValue uptime(const JSONRPCRequest& jsonRequest)\n{\n    if (jsonRequest.fHelp || jsonRequest.params.size() > 1)\n        throw std::runtime_error(\n            \"uptime\\n\"\n            \"\\nReturns the total uptime of the server (in seconds).\");\n\n    return GetTime() - GetStartupTime();\n}\n\n/**\n * Call Table\n */\nstatic const CRPCCommand vRPCCommands[] =\n{ //  category              name                      actor (function)         okSafe argNames\n  //  --------------------- ------------------------  -----------------------  ------ ----------\n    /* Overall control/query calls */\n    { \"control\",            \"help\",                   &help,                   true,  {\"command\"}  },\n    { \"control\",            \"stop\",                   &stop,                   true,  {\"wait\"}  },\n    { \"control\",            \"uptime\",                 &uptime,                 true,  {\"\"}  },\n};\n\nCRPCTable::CRPCTable()\n{\n    unsigned int vcidx;\n    for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)\n    {\n        const CRPCCommand *pcmd;\n\n        pcmd = &vRPCCommands[vcidx];\n        mapCommands[pcmd->name] = pcmd;\n    }\n}\n\nconst CRPCCommand *CRPCTable::operator[](const std::string &name) const\n{\n    std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);\n    if (it == mapCommands.end())\n        return NULL;\n    return (*it).second;\n}\n\nbool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)\n{\n    if (IsRPCRunning())\n        return false;\n\n    // don't allow overwriting for now\n    std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);\n    if (it != mapCommands.end())\n        return false;\n\n    mapCommands[name] = pcmd;\n    return true;\n}\n\nbool StartRPC()\n{\n    LogPrint(BCLog::RPC, \"Starting RPC\\n\");\n    fRPCRunning = true;\n    g_rpcSignals.Started();\n    return true;\n}\n\nvoid InterruptRPC()\n{\n    LogPrint(BCLog::RPC, \"Interrupting RPC\\n\");\n    // Interrupt e.g. running longpolls\n    fRPCRunning = false;\n}\n\nvoid StopRPC()\n{\n    LogPrint(BCLog::RPC, \"Stopping RPC\\n\");\n    DeleteAuthCookie();\n    g_rpcSignals.Stopped();\n}\n\nbool IsRPCRunning()\n{\n    return fRPCRunning;\n}\n\nvoid SetRPCWarmupStatus(const std::string& newStatus)\n{\n    LOCK(cs_rpcWarmup);\n    rpcWarmupStatus = newStatus;\n}\n\nvoid SetRPCWarmupFinished()\n{\n    LOCK(cs_rpcWarmup);\n    assert(fRPCInWarmup);\n    fRPCInWarmup = false;\n}\n\nbool RPCIsInWarmup(std::string *outStatus)\n{\n    LOCK(cs_rpcWarmup);\n    if (outStatus)\n        *outStatus = rpcWarmupStatus;\n    return fRPCInWarmup;\n}\n\nvoid JSONRPCRequest::parse(const UniValue& valRequest)\n{\n    // Parse request\n    if (!valRequest.isObject())\n        throw JSONRPCError(RPC_INVALID_REQUEST, \"Invalid Request object\");\n    const UniValue& request = valRequest.get_obj();\n\n    // Parse id now so errors from here on will have the id\n    id = find_value(request, \"id\");\n\n    // Parse method\n    UniValue valMethod = find_value(request, \"method\");\n    if (valMethod.isNull())\n        throw JSONRPCError(RPC_INVALID_REQUEST, \"Missing method\");\n    if (!valMethod.isStr())\n        throw JSONRPCError(RPC_INVALID_REQUEST, \"Method must be a string\");\n    strMethod = valMethod.get_str();\n    LogPrint(BCLog::RPC, \"ThreadRPCServer method=%s\\n\", SanitizeString(strMethod));\n\n    // Parse params\n    UniValue valParams = find_value(request, \"params\");\n    if (valParams.isArray() || valParams.isObject())\n        params = valParams;\n    else if (valParams.isNull())\n        params = UniValue(UniValue::VARR);\n    else\n        throw JSONRPCError(RPC_INVALID_REQUEST, \"Params must be an array or object\");\n}\n\nstatic UniValue JSONRPCExecOne(const UniValue& req)\n{\n    UniValue rpc_result(UniValue::VOBJ);\n\n    JSONRPCRequest jreq;\n    try {\n        jreq.parse(req);\n\n        UniValue result = tableRPC.execute(jreq);\n        rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);\n    }\n    catch (const UniValue& objError)\n    {\n        rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);\n    }\n    catch (const std::exception& e)\n    {\n        rpc_result = JSONRPCReplyObj(NullUniValue,\n                                     JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);\n    }\n\n    return rpc_result;\n}\n\nstd::string JSONRPCExecBatch(const UniValue& vReq)\n{\n    UniValue ret(UniValue::VARR);\n    for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)\n        ret.push_back(JSONRPCExecOne(vReq[reqIdx]));\n\n    return ret.write() + \"\\n\";\n}\n\n/**\n * Process named arguments into a vector of positional arguments, based on the\n * passed-in specification for the RPC call's arguments.\n */\nstatic inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)\n{\n    JSONRPCRequest out = in;\n    out.params = UniValue(UniValue::VARR);\n    // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if\n    // there is an unknown one.\n    const std::vector<std::string>& keys = in.params.getKeys();\n    const std::vector<UniValue>& values = in.params.getValues();\n    std::unordered_map<std::string, const UniValue*> argsIn;\n    for (size_t i=0; i<keys.size(); ++i) {\n        argsIn[keys[i]] = &values[i];\n    }\n    // Process expected parameters.\n    int hole = 0;\n    for (const std::string &argNamePattern: argNames) {\n        std::vector<std::string> vargNames;\n        boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of(\"|\"));\n        auto fr = argsIn.end();\n        for (const std::string & argName : vargNames) {\n            fr = argsIn.find(argName);\n            if (fr != argsIn.end()) {\n                break;\n            }\n        }\n        if (fr != argsIn.end()) {\n            for (int i = 0; i < hole; ++i) {\n                // Fill hole between specified parameters with JSON nulls,\n                // but not at the end (for backwards compatibility with calls\n                // that act based on number of specified parameters).\n                out.params.push_back(UniValue());\n            }\n            hole = 0;\n            out.params.push_back(*fr->second);\n            argsIn.erase(fr);\n        } else {\n            hole += 1;\n        }\n    }\n    // If there are still arguments in the argsIn map, this is an error.\n    if (!argsIn.empty()) {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Unknown named parameter \" + argsIn.begin()->first);\n    }\n    // Return request with named arguments transformed to positional arguments\n    return out;\n}\n\nUniValue CRPCTable::execute(const JSONRPCRequest &request) const\n{\n    // Return immediately if in warmup\n    {\n        LOCK(cs_rpcWarmup);\n        if (fRPCInWarmup)\n            throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);\n    }\n\n    // Find method\n    const CRPCCommand *pcmd = tableRPC[request.strMethod];\n    if (!pcmd)\n        throw JSONRPCError(RPC_METHOD_NOT_FOUND, \"Method not found\");\n\n    g_rpcSignals.PreCommand(*pcmd);\n\n    try\n    {\n        // Execute, convert arguments to array if necessary\n        if (request.params.isObject()) {\n            return pcmd->actor(transformNamedArguments(request, pcmd->argNames));\n        } else {\n            return pcmd->actor(request);\n        }\n    }\n    catch (const std::exception& e)\n    {\n        throw JSONRPCError(RPC_MISC_ERROR, e.what());\n    }\n}\n\nstd::vector<std::string> CRPCTable::listCommands() const\n{\n    std::vector<std::string> commandList;\n    for (const auto& [commandName, command] : mapCommands)\n    {\n        if (command->category != \"hidden\")\n        {\n            commandList.push_back(commandName);\n        }\n    }\n    return commandList;\n}\n\nstd::string HelpExampleCli(const std::string& methodname, const std::string& args)\n{\n    return \"> \" GLOBAL_APPNAME \"-cli \" + methodname + \" \" + args + \"\\n\";\n}\n\nstd::string HelpExampleRpc(const std::string& methodname, const std::string& args)\n{\n    return \"> curl --user myusername --data-binary '{\\\"jsonrpc\\\": \\\"1.0\\\", \\\"id\\\":\\\"curltest\\\", \"\n        \"\\\"method\\\": \\\"\" + methodname + \"\\\", \\\"params\\\": [\" + args + \"] }' -H 'content-type: text/plain;' http://127.0.0.1:9232/\\n\";\n}\n\nint RPCSerializationFlags()\n{\n    int flag = 0;\n    return flag;\n}\n\nCRPCTable tableRPC;\n"
  },
  {
    "path": "src/rpc/server.h",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef RPCSERVER_H\n#define RPCSERVER_H\n\n#include \"amount.h\"\n#include \"rpc/protocol.h\"\n#include \"uint256.h\"\n\n#include <list>\n#include <map>\n#include <stdint.h>\n#include <string>\n\n#include <univalue.h>\n\nstatic const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;\n\nclass CRPCCommand;\n\nnamespace RPCServer\n{\n    void OnStarted(std::function<void ()> slot);\n    void OnStopped(std::function<void ()> slot);\n    void OnPreCommand(std::function<void (const CRPCCommand&)> slot);\n}\n\nclass CBlockIndex;\nclass CNetAddr;\n\n/** Wrapper for UniValue::VType, which includes typeAny:\n * Used to denote don't care type. Only used by RPCTypeCheckObj */\nstruct UniValueType {\n    UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}\n    UniValueType() : typeAny(true) {}\n    bool typeAny;\n    UniValue::VType type;\n};\n\nclass JSONRPCRequest\n{\npublic:\n    UniValue id;\n    std::string strMethod;\n    UniValue params;\n    bool fHelp;\n    std::string URI;\n    std::string authUser;\n\n    JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}\n    void parse(const UniValue& valRequest);\n};\n\n/** Query whether RPC is running */\nbool IsRPCRunning();\n\n/**\n * Set the RPC warmup status.  When this is done, all RPC calls will error out\n * immediately with RPC_IN_WARMUP.\n */\nvoid SetRPCWarmupStatus(const std::string& newStatus);\n/* Mark warmup as done.  RPC calls will be processed from now on.  */\nvoid SetRPCWarmupFinished();\n\n/* returns the current warmup state.  */\nbool RPCIsInWarmup(std::string *outStatus);\n\n/**\n * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that\n * the right number of arguments are passed, just that any passed are the correct type.\n */\nvoid RPCTypeCheck(const UniValue& params,\n                  const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);\n\n/**\n * Type-check one argument; throws JSONRPCError if wrong type given.\n */\nvoid RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);\n\n/*\n  Check for expected keys/value types in an Object.\n*/\nvoid RPCTypeCheckObj(const UniValue& o,\n    const std::map<std::string, UniValueType>& typesExpected,\n    bool fAllowNull = false,\n    bool fStrict = false);\n\ntypedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);\n\nclass CRPCCommand\n{\npublic:\n    std::string category;\n    std::string name;\n    rpcfn_type actor;\n    bool okSafeMode;\n    std::vector<std::string> argNames;\n};\n\n/**\n * Bitcoin RPC command dispatcher.\n */\nclass CRPCTable\n{\nprivate:\n    std::map<std::string, const CRPCCommand*> mapCommands;\npublic:\n    CRPCTable();\n    const CRPCCommand* operator[](const std::string& name) const;\n    std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;\n\n    /**\n     * Execute a method.\n     * @param request The JSONRPCRequest to execute\n     * @returns Result of the call.\n     * @throws an exception (UniValue) when an error happens.\n     */\n    UniValue execute(const JSONRPCRequest &request) const;\n\n    /**\n    * Returns a list of registered commands\n    * @returns List of registered commands.\n    */\n    std::vector<std::string> listCommands() const;\n\n\n    /**\n     * Appends a CRPCCommand to the dispatch table.\n     * Returns false if RPC server is already running (dump concurrency protection).\n     * Commands cannot be overwritten (returns false).\n     */\n    bool appendCommand(const std::string& name, const CRPCCommand* pcmd);\n};\n\nextern CRPCTable tableRPC;\n\n/**\n * Utilities: convert hex-encoded Values\n * (throws error if not hex).\n */\nextern uint256 ParseHashV(const UniValue& v, std::string strName);\nextern uint256 ParseHashO(const UniValue& o, std::string strKey);\nextern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);\nextern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);\n\nextern void InitRPCMining();\nextern void ShutdownRPCMining();\n\nextern CAmount AmountFromValue(const UniValue& value, bool allowNegative = false);\nextern UniValue ValueFromAmount(const CAmount& amount);\nextern std::string HelpExampleCli(const std::string& methodname, const std::string& args);\nextern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);\n\nbool StartRPC();\nvoid InterruptRPC();\nvoid StopRPC();\nstd::string JSONRPCExecBatch(const UniValue& vReq);\n\n// Retrieves any serialization flags requested in command line argument\nint RPCSerializationFlags();\n\n#endif\n"
  },
  {
    "path": "src/scheduler.cpp",
    "content": "// Copyright (c) 2015-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"scheduler.h\"\n\n#include <random.h>\n#include <util/syscall_sandbox.h>\n#include <util/time.h>\n\n#include <assert.h>\n#include <functional>\n#include <utility>\n\nCScheduler::CScheduler()\n{\n}\n\nCScheduler::~CScheduler()\n{\n    assert(nThreadsServicingQueue == 0);\n    if (stopWhenEmpty) assert(taskQueue.empty());\n}\n\nvoid CScheduler::stop()\n{\n    WITH_LOCK(newTaskMutex, stopRequested = true);\n    newTaskScheduled.notify_all();\n    if (m_service_thread.joinable()) m_service_thread.join();\n}\n\nvoid CScheduler::serviceQueue()\n{\n    SetSyscallSandboxPolicy(SyscallSandboxPolicy::SCHEDULER);\n    WAIT_LOCK(newTaskMutex, lock);\n    ++nThreadsServicingQueue;\n\n    // newTaskMutex is locked throughout this loop EXCEPT\n    // when the thread is waiting or when the user's function\n    // is called.\n    while (!shouldStop()) {\n        try {\n            while (!shouldStop() && taskQueue.empty()) {\n                // Wait until there is something to do.\n                newTaskScheduled.wait(lock);\n            }\n\n            // Wait until either there is a new task, or until\n            // the time of the first item on the queue:\n\n            while (!shouldStop() && !taskQueue.empty()) {\n                std::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first;\n                if (newTaskScheduled.wait_until(lock, timeToWaitFor) == std::cv_status::timeout) {\n                    break; // Exit loop after timeout, it means we reached the time of the event\n                }\n            }\n\n            // If there are multiple threads, the queue can empty while we're waiting (another\n            // thread may service the task we were waiting on).\n            if (shouldStop() || taskQueue.empty())\n                continue;\n\n            Function f = taskQueue.begin()->second;\n            taskQueue.erase(taskQueue.begin());\n\n            {\n                // Unlock before calling f, so it can reschedule itself or another task\n                // without deadlocking:\n                REVERSE_LOCK(lock);\n                f();\n            }\n        } catch (...) {\n            --nThreadsServicingQueue;\n            throw;\n        }\n    }\n    --nThreadsServicingQueue;\n    newTaskScheduled.notify_one();\n}\n\nvoid CScheduler::schedule(CScheduler::Function f, std::chrono::system_clock::time_point t)\n{\n    {\n        LOCK(newTaskMutex);\n        taskQueue.insert(std::make_pair(t, f));\n    }\n    newTaskScheduled.notify_one();\n}\n\nvoid CScheduler::MockForward(std::chrono::seconds delta_seconds)\n{\n    assert(delta_seconds > 0s && delta_seconds <= 1h);\n\n    {\n        LOCK(newTaskMutex);\n\n        // use temp_queue to maintain updated schedule\n        std::multimap<std::chrono::system_clock::time_point, Function> temp_queue;\n\n        for (const auto& element : taskQueue) {\n            temp_queue.emplace_hint(temp_queue.cend(), element.first - delta_seconds, element.second);\n        }\n\n        // point taskQueue to temp_queue\n        taskQueue = std::move(temp_queue);\n    }\n\n    // notify that the taskQueue needs to be processed\n    newTaskScheduled.notify_one();\n}\n\nstatic void Repeat(CScheduler& s, CScheduler::Function f, std::chrono::milliseconds delta)\n{\n    f();\n    s.scheduleFromNow([=, &s] { Repeat(s, f, delta); }, delta);\n}\n\nvoid CScheduler::scheduleEvery(CScheduler::Function f, std::chrono::milliseconds delta)\n{\n    scheduleFromNow([=] { Repeat(*this, f, delta); }, delta);\n}\n\nsize_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point& first,\n                                std::chrono::system_clock::time_point& last) const\n{\n    LOCK(newTaskMutex);\n    size_t result = taskQueue.size();\n    if (!taskQueue.empty()) {\n        first = taskQueue.begin()->first;\n        last = taskQueue.rbegin()->first;\n    }\n    return result;\n}\n\nbool CScheduler::AreThreadsServicingQueue() const\n{\n    LOCK(newTaskMutex);\n    return nThreadsServicingQueue;\n}\n\n\nvoid SingleThreadedSchedulerClient::MaybeScheduleProcessQueue()\n{\n    {\n        LOCK(m_callbacks_mutex);\n        // Try to avoid scheduling too many copies here, but if we\n        // accidentally have two ProcessQueue's scheduled at once its\n        // not a big deal.\n        if (m_are_callbacks_running) return;\n        if (m_callbacks_pending.empty()) return;\n    }\n    m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this), std::chrono::system_clock::now());\n}\n\nvoid SingleThreadedSchedulerClient::ProcessQueue()\n{\n    std::function<void()> callback;\n    {\n        LOCK(m_callbacks_mutex);\n        if (m_are_callbacks_running) return;\n        if (m_callbacks_pending.empty()) return;\n        m_are_callbacks_running = true;\n\n        callback = std::move(m_callbacks_pending.front());\n        m_callbacks_pending.pop_front();\n    }\n\n    // RAII the setting of fCallbacksRunning and calling MaybeScheduleProcessQueue\n    // to ensure both happen safely even if callback() throws.\n    struct RAIICallbacksRunning {\n        SingleThreadedSchedulerClient* instance;\n        explicit RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}\n        ~RAIICallbacksRunning()\n        {\n            {\n                LOCK(instance->m_callbacks_mutex);\n                instance->m_are_callbacks_running = false;\n            }\n            instance->MaybeScheduleProcessQueue();\n        }\n    } raiicallbacksrunning(this);\n\n    callback();\n}\n\nvoid SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void()> func)\n{\n    assert(m_pscheduler);\n\n    {\n        LOCK(m_callbacks_mutex);\n        m_callbacks_pending.emplace_back(std::move(func));\n    }\n    MaybeScheduleProcessQueue();\n}\n\nvoid SingleThreadedSchedulerClient::EmptyQueue()\n{\n    assert(!m_pscheduler->AreThreadsServicingQueue());\n    bool should_continue = true;\n    while (should_continue) {\n        ProcessQueue();\n        LOCK(m_callbacks_mutex);\n        should_continue = !m_callbacks_pending.empty();\n    }\n}\n\nsize_t SingleThreadedSchedulerClient::CallbacksPending()\n{\n    LOCK(m_callbacks_mutex);\n    return m_callbacks_pending.size();\n}\n"
  },
  {
    "path": "src/scheduler.h",
    "content": "// Copyright (c) 2015-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SCHEDULER_H\n#define SCHEDULER_H\n\n#include <condition_variable>\n#include <functional>\n#include <list>\n#include <map>\n#include <thread>\n\n#include <sync.h>\n\n/**\n * Simple class for background tasks that should be run\n * periodically or once \"after a while\"\n *\n * Usage:\n *\n * CScheduler* s = new CScheduler();\n * s->scheduleFromNow(doSomething, std::chrono::milliseconds{11}); // Assuming a: void doSomething() { }\n * s->scheduleFromNow([=] { this->func(argument); }, std::chrono::milliseconds{3});\n * std::thread* t = new std::thread([&] { s->serviceQueue(); });\n *\n * ... then at program shutdown, make sure to call stop() to clean up the thread(s) running serviceQueue:\n * s->stop();\n * t->join();\n * delete t;\n * delete s; // Must be done after thread is interrupted/joined.\n */\nclass CScheduler\n{\npublic:\n    CScheduler();\n    ~CScheduler();\n\n    std::thread m_service_thread;\n\n    typedef std::function<void()> Function;\n\n    /** Call func at/after time t */\n    void schedule(Function f, std::chrono::system_clock::time_point t);\n\n    /** Call f once after the delta has passed */\n    void scheduleFromNow(Function f, std::chrono::milliseconds delta)\n    {\n        schedule(std::move(f), std::chrono::system_clock::now() + delta);\n    }\n\n    /**\n     * Repeat f until the scheduler is stopped. First run is after delta has passed once.\n     *\n     * The timing is not exact: Every time f is finished, it is rescheduled to run again after delta. If you need more\n     * accurate scheduling, don't use this method.\n     */\n    void scheduleEvery(Function f, std::chrono::milliseconds delta);\n\n    /**\n     * Mock the scheduler to fast forward in time.\n     * Iterates through items on taskQueue and reschedules them\n     * to be delta_seconds sooner.\n     */\n    void MockForward(std::chrono::seconds delta_seconds);\n\n    /**\n     * Services the queue 'forever'. Should be run in a thread.\n     */\n    void serviceQueue();\n\n    /** Tell any threads running serviceQueue to stop as soon as the current task is done */\n    void stop();\n\n    /** Tell any threads running serviceQueue to stop when there is no work left to be done */\n    void StopWhenDrained()\n    {\n        WITH_LOCK(newTaskMutex, stopWhenEmpty = true);\n        newTaskScheduled.notify_all();\n        if (m_service_thread.joinable()) m_service_thread.join();\n    }\n\n    /**\n     * Returns number of tasks waiting to be serviced,\n     * and first and last task times\n     */\n    size_t getQueueInfo(std::chrono::system_clock::time_point& first,\n                        std::chrono::system_clock::time_point& last) const;\n\n    /** Returns true if there are threads actively running in serviceQueue() */\n    bool AreThreadsServicingQueue() const;\n\nprivate:\n    mutable Mutex newTaskMutex;\n    std::condition_variable newTaskScheduled;\n    std::multimap<std::chrono::system_clock::time_point, Function> taskQueue GUARDED_BY(newTaskMutex);\n    int nThreadsServicingQueue GUARDED_BY(newTaskMutex){0};\n    bool stopRequested GUARDED_BY(newTaskMutex){false};\n    bool stopWhenEmpty GUARDED_BY(newTaskMutex){false};\n    bool shouldStop() const EXCLUSIVE_LOCKS_REQUIRED(newTaskMutex) { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }\n};\n\n/**\n * Class used by CScheduler clients which may schedule multiple jobs\n * which are required to be run serially. Jobs may not be run on the\n * same thread, but no two jobs will be executed\n * at the same time and memory will be release-acquire consistent\n * (the scheduler will internally do an acquire before invoking a callback\n * as well as a release at the end). In practice this means that a callback\n * B() will be able to observe all of the effects of callback A() which executed\n * before it.\n */\nclass SingleThreadedSchedulerClient\n{\nprivate:\n    CScheduler* m_pscheduler;\n\n    Mutex m_callbacks_mutex;\n    std::list<std::function<void()>> m_callbacks_pending GUARDED_BY(m_callbacks_mutex);\n    bool m_are_callbacks_running GUARDED_BY(m_callbacks_mutex) = false;\n\n    void MaybeScheduleProcessQueue();\n    void ProcessQueue();\n\npublic:\n    explicit SingleThreadedSchedulerClient(CScheduler* pschedulerIn) : m_pscheduler(pschedulerIn) {}\n\n    /**\n     * Add a callback to be executed. Callbacks are executed serially\n     * and memory is release-acquire consistent between callback executions.\n     * Practically, this means that callbacks can behave as if they are executed\n     * in order by a single thread.\n     */\n    void AddToProcessQueue(std::function<void()> func);\n\n    /**\n     * Processes all remaining queue members on the calling thread, blocking until queue is empty\n     * Must be called after the CScheduler has no remaining processing threads!\n     */\n    void EmptyQueue();\n\n    size_t CallbacksPending();\n};\n\n#endif\n"
  },
  {
    "path": "src/script/consensus.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"script/consensus.h\"\n\n#include \"primitives/transaction.h\"\n#include \"pubkey.h\"\n#include \"script/interpreter.h\"\n#include \"version.h\"\n#include \"validation/validation.h\"\n\nnamespace {\n\n/** A class that deserializes a single CTransaction one time. */\nclass TxInputStream\n{\npublic:\n    TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) :\n    m_type(nTypeIn),\n    m_version(nVersionIn),\n    m_data(txTo),\n    m_remaining(txToLen)\n    {}\n   \n    void read(Span<std::byte> dst)\n    {\n        if (dst.size() > m_remaining) {\n            throw std::ios_base::failure(std::string(__func__) + \": end of data\");\n        }\n\n        if (dst.data() == nullptr) {\n            throw std::ios_base::failure(std::string(__func__) + \": bad destination buffer\");\n        }\n\n        if (m_data == nullptr) {\n            throw std::ios_base::failure(std::string(__func__) + \": bad source buffer\");\n        }\n\n        memcpy(dst.data(), m_data, dst.size());\n        m_remaining -= dst.size();\n        m_data += dst.size();\n    }\n    \n    void read(char* pch, size_t nSize)\n    {\n        if (nSize > m_remaining)\n            throw std::ios_base::failure(std::string(__func__) + \": end of data\");\n\n        if (pch == NULL)\n            throw std::ios_base::failure(std::string(__func__) + \": bad destination buffer\");\n\n        if (m_data == NULL)\n            throw std::ios_base::failure(std::string(__func__) + \": bad source buffer\");\n\n        memcpy(pch, m_data, nSize);\n        m_remaining -= nSize;\n        m_data += nSize;\n    }\n\n    void peek(char* pch, size_t nSize)\n    {\n        if (nSize > m_remaining)\n            throw std::ios_base::failure(std::string(__func__) + \": end of data\");\n\n        if (pch == NULL)\n            throw std::ios_base::failure(std::string(__func__) + \": bad destination buffer\");\n\n        if (m_data == NULL)\n            throw std::ios_base::failure(std::string(__func__) + \": bad source buffer\");\n\n        memcpy(pch, m_data, nSize);\n    }\n\n    void ignore(size_t nSize)\n    {\n        m_remaining -= nSize;\n        m_data += nSize;\n    }\n\n    template<typename T>\n    TxInputStream& operator>>(T& obj)\n    {\n        ::Unserialize(*this, obj);\n        return *this;\n    }\n\n    int GetVersion() const { return m_version; }\n    int GetType() const { return m_type; }\nprivate:\n    const int m_type;\n    const int m_version;\n    const unsigned char* m_data;\n    size_t m_remaining;\n};\n\ninline int set_error(scriptconsensus_error* ret, scriptconsensus_error serror)\n{\n    if (ret)\n        *ret = serror;\n    return 0;\n}\n\nstruct ECCryptoClosure\n{\n    ECCVerifyHandle handle;\n};\n\nECCryptoClosure instance_of_eccryptoclosure;\n}\n\n/** Check that all specified flags are part of the libconsensus interface. */\nstatic bool verify_flags(unsigned int flags)\n{\n    return (flags & ~(SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_ALL)) == 0;\n}\n\nstatic int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount, const unsigned char *txTo, unsigned int txToLen, unsigned int nIn, unsigned int flags, scriptconsensus_error* err)\n{\n    if (!verify_flags(flags)) {\n        return SCRIPT_CONSENSUS_ERR_INVALID_FLAGS;\n    }\n    try {\n        TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);\n        CTransaction tx(deserialize, stream);\n        if (nIn >= tx.vin.size())\n            return set_error(err, SCRIPT_CONSENSUS_ERR_TX_INDEX);\n        if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen)\n            return set_error(err, SCRIPT_CONSENSUS_ERR_TX_SIZE_MISMATCH);\n\n        // Regardless of the verification result, the tx did not error.\n        set_error(err, SCRIPT_CONSENSUS_ERR_OK);\n\n        PrecomputedTransactionData txdata(tx);\n        \n        // NB! We create the signature checker with NULL ID's\n        // This is fine because the script check itself pulls the correct keys from the stack and checks them\n        CKeyID nullKeyID;\n        ScriptVersion scriptversion = (tx.vin[nIn].segregatedSignatureData.IsNull()) ? SCRIPT_V1 : SCRIPT_V2;\n        return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].segregatedSignatureData, flags, TransactionSignatureChecker(nullKeyID, nullKeyID, &tx, nIn, amount, txdata), scriptversion, NULL);\n    } catch (const std::exception&) {\n        return set_error(err, SCRIPT_CONSENSUS_ERR_TX_DESERIALIZE); // Error deserializing\n    }\n}\n\nint script_consensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,\n                                    const unsigned char *txTo        , unsigned int txToLen,\n                                    unsigned int nIn, unsigned int flags, scriptconsensus_error* err)\n{\n    CAmount am(amount);\n    return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);\n}\n\n\nint script_consensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,\n                                   const unsigned char *txTo        , unsigned int txToLen,\n                                   unsigned int nIn, unsigned int flags, scriptconsensus_error* err)\n{\n    if (flags & SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_WITNESS) {\n        return set_error(err, SCRIPT_CONSENSUS_ERR_AMOUNT_REQUIRED);\n    }\n\n    CAmount am(0);\n    return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);\n}\n\nunsigned int script_consensus_version()\n{\n    // Just use the API version for now\n    return SCRIPTCONSENSUS_API_VER;\n}\n"
  },
  {
    "path": "src/script/consensus.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SCRIPT_CONSENSUS_H\n#define SCRIPT_CONSENSUS_H\n\n#include <stdint.h>\n\n#if defined(BUILD_INTERNAL) && defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n  #if defined(_WIN32)\n    #if defined(DLL_EXPORT)\n      #if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT)\n        #define EXPORT_SYMBOL __declspec(dllexport)\n      #else\n        #define EXPORT_SYMBOL\n      #endif\n    #endif\n  #elif defined(HAVE_FUNC_ATTRIBUTE_VISIBILITY)\n    #define EXPORT_SYMBOL __attribute__ ((visibility (\"default\")))\n  #endif\n#elif defined(MSC_VER) && !defined(STATIC_LIBSCRIPTCONSENSUS)\n  #define EXPORT_SYMBOL __declspec(dllimport)\n#endif\n\n#ifndef EXPORT_SYMBOL\n  #define EXPORT_SYMBOL\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define SCRIPTCONSENSUS_API_VER 1\n\ntypedef enum script_consensus_error_t\n{\n    SCRIPT_CONSENSUS_ERR_OK = 0,\n    SCRIPT_CONSENSUS_ERR_TX_INDEX,\n    SCRIPT_CONSENSUS_ERR_TX_SIZE_MISMATCH,\n    SCRIPT_CONSENSUS_ERR_TX_DESERIALIZE,\n    SCRIPT_CONSENSUS_ERR_AMOUNT_REQUIRED,\n    SCRIPT_CONSENSUS_ERR_INVALID_FLAGS,\n} scriptconsensus_error;\n\n\n/** Script verification flags */\nenum\n{\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_NONE                = 0,\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_P2SH                = (1U << 0), // evaluate P2SH (BIP16) subscripts\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_DERSIG              = (1U << 2), // enforce strict DER (BIP66) compliance\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 8), // enable CHECKLOCKTIMEVERIFY (BIP65)\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 9), // enable CHECKSEQUENCEVERIFY (BIP112)\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_WITNESS             = (1U << 13), // enable WITNESS (BIP141)\n    SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_ALL                 = SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_P2SH | SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_DERSIG |\n                                                               SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY |\n                                                               SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_WITNESS\n};\n\n/// Returns 1 if the input nIn of the serialized transaction pointed to by\n/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under\n/// the additional constraints specified by flags.\n/// If not NULL, err will contain an error/success code for the operation\nEXPORT_SYMBOL int script_consensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,\n                                                 const unsigned char *txTo        , unsigned int txToLen,\n                                                 unsigned int nIn, unsigned int flags, scriptconsensus_error* err);\n\nEXPORT_SYMBOL int script_consensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,\n                                    const unsigned char *txTo        , unsigned int txToLen,\n                                    unsigned int nIn, unsigned int flags, scriptconsensus_error* err);\n\nEXPORT_SYMBOL unsigned int script_consensus_version();\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#undef EXPORT_SYMBOL\n\n#endif\n"
  },
  {
    "path": "src/script/interpreter.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"interpreter.h\"\n\n#include \"primitives/transaction.h\"\n#include \"crypto/ripemd160.h\"\n#include \"crypto/sha1.h\"\n#include \"crypto/sha256.h\"\n#include \"pubkey.h\"\n#include \"script/script.h\"\n#include \"uint256.h\"\n#include <util.h>\n#include \"chainparams.h\"\n\ntypedef std::vector<unsigned char> valtype;\n\nnamespace {\n\ninline bool set_success(ScriptError* ret)\n{\n    if (ret)\n        *ret = SCRIPT_ERR_OK;\n    return true;\n}\n\ninline bool set_error(ScriptError* ret, const ScriptError serror)\n{\n    if (ret)\n        *ret = serror;\n    return false;\n}\n\n} // anon namespace\n\nstatic bool CastToBool(const valtype& vch)\n{\n    for (unsigned int i = 0; i < vch.size(); i++)\n    {\n        if (vch[i] != 0)\n        {\n            // Can be negative zero\n            if (i == vch.size()-1 && vch[i] == 0x80)\n                return false;\n            return true;\n        }\n    }\n    return false;\n}\n\n/**\n * Script is a stack machine (like Forth) that evaluates a predicate\n * returning a bool indicating valid or not.  There are no loops.\n */\n#define stacktop(i)  (stack.at(stack.size()+(i)))\n#define altstacktop(i)  (altstack.at(altstack.size()+(i)))\nstatic inline void popstack(std::vector<valtype>& stack)\n{\n    if (stack.empty())\n        throw std::runtime_error(\"popstack(): stack empty\");\n    stack.pop_back();\n}\n\nbool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {\n    if (vchPubKey.size() < 33) {\n        //  Non-canonical public key: too short\n        return false;\n    }\n    if (vchPubKey[0] == 0x04) {\n        if (vchPubKey.size() != 65) {\n            //  Non-canonical public key: invalid length for uncompressed key\n            return false;\n        }\n    } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {\n        if (vchPubKey.size() != 33) {\n            //  Non-canonical public key: invalid length for compressed key\n            return false;\n        }\n    } else {\n        //  Non-canonical public key: neither compressed nor uncompressed\n        return false;\n    }\n    return true;\n}\n\n/**\n * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>\n * Where R and S are not negative (their first byte has its highest bit not set), and not\n * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,\n * in which case a single 0 byte is necessary and even required).\n * \n * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623\n *\n * This function is consensus-critical since BIP66.\n */\nbool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {\n    // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]\n    // * total-length: 1-byte length descriptor of everything that follows,\n    //   excluding the sighash byte.\n    // * R-length: 1-byte length descriptor of the R value that follows.\n    // * R: arbitrary-length big-endian encoded R value. It must use the shortest\n    //   possible encoding for a positive integers (which means no null bytes at\n    //   the start, except a single one when the next byte has its highest bit set).\n    // * S-length: 1-byte length descriptor of the S value that follows.\n    // * S: arbitrary-length big-endian encoded S value. The same rules apply.\n    // * sighash: 1-byte value indicating what data is hashed (not part of the DER\n    //   signature)\n\n    // Minimum and maximum size constraints.\n    if (sig.size() < 9) return false;\n    if (sig.size() > 73) return false;\n\n    // A signature is of type 0x30 (compound).\n    if (sig[0] != 0x30) return false;\n\n    // Make sure the length covers the entire signature.\n    if (sig[1] != sig.size() - 3) return false;\n\n    // Extract the length of the R element.\n    unsigned int lenR = sig[3];\n\n    // Make sure the length of the S element is still inside the signature.\n    if (5 + lenR >= sig.size()) return false;\n\n    // Extract the length of the S element.\n    unsigned int lenS = sig[5 + lenR];\n\n    // Verify that the length of the signature matches the sum of the length\n    // of the elements.\n    if ((size_t)(lenR + lenS + 7) != sig.size()) return false;\n \n    // Check whether the R element is an integer.\n    if (sig[2] != 0x02) return false;\n\n    // Zero-length integers are not allowed for R.\n    if (lenR == 0) return false;\n\n    // Negative numbers are not allowed for R.\n    if (sig[4] & 0x80) return false;\n\n    // Null bytes at the start of R are not allowed, unless R would\n    // otherwise be interpreted as a negative number.\n    if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;\n\n    // Check whether the S element is an integer.\n    if (sig[lenR + 4] != 0x02) return false;\n\n    // Zero-length integers are not allowed for S.\n    if (lenS == 0) return false;\n\n    // Negative numbers are not allowed for S.\n    if (sig[lenR + 6] & 0x80) return false;\n\n    // Null bytes at the start of S are not allowed, unless S would otherwise be\n    // interpreted as a negative number.\n    if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;\n\n    return true;\n}\n\nbool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {\n    if (!IsValidSignatureEncoding(vchSig)) {\n        return set_error(serror, SCRIPT_ERR_SIG_DER);\n    }\n    std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);\n    if (!CPubKey::CheckLowS(vchSigCopy)) {\n        return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);\n    }\n    return true;\n}\n\nbool static IsDefinedHashtypeSignature(const valtype &vchSig) {\n    if (vchSig.size() == 0) {\n        return false;\n    }\n    unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));\n    if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)\n        return false;\n\n    return true;\n}\n\nbool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {\n    // Empty signature. Not strictly DER encoded, but allowed to provide a\n    // compact way to provide an invalid signature for use with CHECK(MULTI)SIG\n    if (vchSig.size() == 0) {\n        return true;\n    }\n    if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) {\n        return set_error(serror, SCRIPT_ERR_SIG_DER);\n    } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {\n        // serror is set\n        return false;\n    } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {\n        return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);\n    }\n    return true;\n}\n\nbool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {\n    if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {\n        return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);\n    }\n    \n    return true;\n}\n\nbool static CheckMinimalPush(const valtype& data, opcodetype opcode) {\n    if (data.size() == 0) {\n        // Could have used OP_0.\n        return opcode == OP_0;\n    } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {\n        // Could have used OP_1 .. OP_16.\n        return opcode == OP_1 + (data[0] - 1);\n    } else if (data.size() == 1 && data[0] == 0x81) {\n        // Could have used OP_1NEGATE.\n        return opcode == OP_1NEGATE;\n    } else if (data.size() <= 75) {\n        // Could have used a direct push (opcode indicating number of bytes pushed + those bytes).\n        return opcode == data.size();\n    } else if (data.size() <= 255) {\n        // Could have used OP_PUSHDATA.\n        return opcode == OP_PUSHDATA1;\n    } else if (data.size() <= 65535) {\n        // Could have used OP_PUSHDATA2.\n        return opcode == OP_PUSHDATA2;\n    }\n    return true;\n}\n\nbool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptVersion scriptversion, ScriptError* serror)\n{\n    SigVersion sigversion = (scriptversion == SCRIPT_V1) ? SIGVERSION_BASE : SIGVERSION_SEGSIG;\n    \n    static const CScriptNum bnZero(0);\n    static const CScriptNum bnOne(1);\n    // static const CScriptNum bnFalse(0);\n    // static const CScriptNum bnTrue(1);\n    static const valtype vchFalse(0);\n    // static const valtype vchZero(0);\n    static const valtype vchTrue(1, 1);\n\n    CScript::const_iterator pc = script.begin();\n    CScript::const_iterator pend = script.end();\n    CScript::const_iterator pbegincodehash = script.begin();\n    opcodetype opcode;\n    valtype vchPushValue;\n    std::vector<bool> vfExec;\n    std::vector<valtype> altstack;\n    set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);\n    if (script.size() > MAX_SCRIPT_SIZE)\n        return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);\n    int nOpCount = 0;\n    bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;\n\n    try\n    {\n        while (pc < pend)\n        {\n            bool fExec = !count(vfExec.begin(), vfExec.end(), false);\n\n            //\n            // Read instruction\n            //\n            if (!script.GetOp(pc, opcode, vchPushValue))\n                return set_error(serror, SCRIPT_ERR_BAD_OPCODE);\n            if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)\n                return set_error(serror, SCRIPT_ERR_PUSH_SIZE);\n\n            // Note how OP_RESERVED does not count towards the opcode limit.\n            if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)\n                return set_error(serror, SCRIPT_ERR_OP_COUNT);\n\n            if (opcode == OP_CAT ||\n                opcode == OP_SUBSTR ||\n                opcode == OP_LEFT ||\n                opcode == OP_RIGHT ||\n                opcode == OP_INVERT ||\n                opcode == OP_AND ||\n                opcode == OP_OR ||\n                opcode == OP_XOR ||\n                opcode == OP_2MUL ||\n                opcode == OP_2DIV ||\n                opcode == OP_MUL ||\n                opcode == OP_DIV ||\n                opcode == OP_MOD ||\n                opcode == OP_LSHIFT ||\n                opcode == OP_RSHIFT)\n                return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.\n\n            if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {\n                if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {\n                    return set_error(serror, SCRIPT_ERR_MINIMALDATA);\n                }\n                stack.push_back(vchPushValue);\n            } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))\n            switch (opcode)\n            {\n                //\n                // Push value\n                //\n                case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8:\n                case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16:\n                {\n                    // ( -- value)\n                    CScriptNum bn((int)opcode - (int)(OP_1 - 1));\n                    stack.push_back(bn.getvch());\n                    // The result of these opcodes should always be the minimal way to push the data\n                    // they push, so no need for a CheckMinimalPush here.\n                }\n                break;\n\n                //\n                // Control\n                //\n                case OP_NOP:\n                    break;\n\n                case OP_CHECKLOCKTIMEVERIFY:\n                {\n                    if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {\n                        // not enabled; treat as a NOP2\n                        if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {\n                            return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);\n                        }\n                        break;\n                    }\n\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n\n                    // Note that elsewhere numeric opcodes are limited to\n                    // operands in the range -2**31+1 to 2**31-1, however it is\n                    // legal for opcodes to produce results exceeding that\n                    // range. This limitation is implemented by CScriptNum's\n                    // default 4-byte limit.\n                    //\n                    // If we kept to that limit we'd have a year 2038 problem,\n                    // even though the nLockTime field in transactions\n                    // themselves is uint32 which only becomes meaningless\n                    // after the year 2106.\n                    //\n                    // Thus as a special case we tell CScriptNum to accept up\n                    // to 5-byte bignums, which are good until 2**39-1, well\n                    // beyond the 2**32-1 limit of the nLockTime field itself.\n                    const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);\n\n                    // In the rare event that the argument may be < 0 due to\n                    // some arithmetic being done first, you can always use\n                    // 0 MAX CHECKLOCKTIMEVERIFY.\n                    if (nLockTime < 0)\n                        return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);\n\n                    // Actually compare the specified lock time with the transaction.\n                    if (!checker.CheckLockTime(nLockTime))\n                        return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);\n\n                    break;\n                }\n\n                case OP_CHECKSEQUENCEVERIFY:\n                {\n                    if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {\n                        // not enabled; treat as a NOP3\n                        if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {\n                            return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);\n                        }\n                        break;\n                    }\n\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n\n                    // nSequence, like nLockTime, is a 32-bit unsigned integer\n                    // field. See the comment in CHECKLOCKTIMEVERIFY regarding\n                    // 5-byte numeric operands.\n                    const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);\n\n                    // In the rare event that the argument may be < 0 due to\n                    // some arithmetic being done first, you can always use\n                    // 0 MAX CHECKSEQUENCEVERIFY.\n                    if (nSequence < 0)\n                        return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);\n\n                    // For V1 compatibility only\n                    // To provide for future soft-fork extensibility, if the operand has the disabled lock-time flag set, CHECKSEQUENCEVERIFY behaves as a NOP.\n                    if (scriptversion == SCRIPT_V1 && ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0))\n                    {\n                        break;\n                    }\n                    // For V2 the sequence number is always assigned meaning                    \n\n                    // Compare the specified sequence number with the input.\n                    if (!checker.CheckSequence(nSequence))\n                        return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);\n\n                    break;\n                }\n\n                case OP_NOP1: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:\n                {\n                    if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)\n                        return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);\n                }\n                break;\n\n                case OP_IF:\n                case OP_NOTIF:\n                {\n                    // <expression> if [statements] [else [statements]] endif\n                    bool fValue = false;\n                    if (fExec)\n                    {\n                        if (stack.size() < 1)\n                            return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);\n                        valtype& vch = stacktop(-1);\n                        if (sigversion == SIGVERSION_SEGSIG && (flags & SCRIPT_VERIFY_MINIMALIF))\n                        {\n                            if (vch.size() > 1)\n                                return set_error(serror, SCRIPT_ERR_MINIMALIF);\n                            if (vch.size() == 1 && vch[0] != 1)\n                                return set_error(serror, SCRIPT_ERR_MINIMALIF);\n                        }\n                        fValue = CastToBool(vch);\n                        if (opcode == OP_NOTIF)\n                            fValue = !fValue;\n                        popstack(stack);\n                    }\n                    vfExec.push_back(fValue);\n                }\n                break;\n\n                case OP_ELSE:\n                {\n                    if (vfExec.empty())\n                        return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);\n                    vfExec.back() = !vfExec.back();\n                }\n                break;\n\n                case OP_ENDIF:\n                {\n                    if (vfExec.empty())\n                        return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);\n                    vfExec.pop_back();\n                }\n                break;\n\n                case OP_VERIFY:\n                {\n                    // (true -- ) or\n                    // (false -- false) and return\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    bool fValue = CastToBool(stacktop(-1));\n                    if (fValue)\n                        popstack(stack);\n                    else\n                        return set_error(serror, SCRIPT_ERR_VERIFY);\n                }\n                break;\n\n                case OP_RETURN:\n                {\n                    return set_error(serror, SCRIPT_ERR_OP_RETURN);\n                }\n                break;\n\n\n                //\n                // Stack ops\n                //\n                case OP_TOALTSTACK:\n                {\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    altstack.push_back(stacktop(-1));\n                    popstack(stack);\n                }\n                break;\n\n                case OP_FROMALTSTACK:\n                {\n                    if (altstack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION);\n                    stack.push_back(altstacktop(-1));\n                    popstack(altstack);\n                }\n                break;\n\n                case OP_2DROP:\n                {\n                    // (x1 x2 -- )\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    popstack(stack);\n                    popstack(stack);\n                }\n                break;\n\n                case OP_2DUP:\n                {\n                    // (x1 x2 -- x1 x2 x1 x2)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch1 = stacktop(-2);\n                    valtype vch2 = stacktop(-1);\n                    stack.push_back(vch1);\n                    stack.push_back(vch2);\n                }\n                break;\n\n                case OP_3DUP:\n                {\n                    // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)\n                    if (stack.size() < 3)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch1 = stacktop(-3);\n                    valtype vch2 = stacktop(-2);\n                    valtype vch3 = stacktop(-1);\n                    stack.push_back(vch1);\n                    stack.push_back(vch2);\n                    stack.push_back(vch3);\n                }\n                break;\n\n                case OP_2OVER:\n                {\n                    // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)\n                    if (stack.size() < 4)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch1 = stacktop(-4);\n                    valtype vch2 = stacktop(-3);\n                    stack.push_back(vch1);\n                    stack.push_back(vch2);\n                }\n                break;\n\n                case OP_2ROT:\n                {\n                    // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)\n                    if (stack.size() < 6)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch1 = stacktop(-6);\n                    valtype vch2 = stacktop(-5);\n                    stack.erase(stack.end()-6, stack.end()-4);\n                    stack.push_back(vch1);\n                    stack.push_back(vch2);\n                }\n                break;\n\n                case OP_2SWAP:\n                {\n                    // (x1 x2 x3 x4 -- x3 x4 x1 x2)\n                    if (stack.size() < 4)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    swap(stacktop(-4), stacktop(-2));\n                    swap(stacktop(-3), stacktop(-1));\n                }\n                break;\n\n                case OP_IFDUP:\n                {\n                    // (x - 0 | x x)\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch = stacktop(-1);\n                    if (CastToBool(vch))\n                        stack.push_back(vch);\n                }\n                break;\n\n                case OP_DEPTH:\n                {\n                    // -- stacksize\n                    CScriptNum bn(stack.size());\n                    stack.push_back(bn.getvch());\n                }\n                break;\n\n                case OP_DROP:\n                {\n                    // (x -- )\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    popstack(stack);\n                }\n                break;\n\n                case OP_DUP:\n                {\n                    // (x -- x x)\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch = stacktop(-1);\n                    stack.push_back(vch);\n                }\n                break;\n\n                case OP_NIP:\n                {\n                    // (x1 x2 -- x2)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    stack.erase(stack.end() - 2);\n                }\n                break;\n\n                case OP_OVER:\n                {\n                    // (x1 x2 -- x1 x2 x1)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch = stacktop(-2);\n                    stack.push_back(vch);\n                }\n                break;\n\n                case OP_PICK:\n                case OP_ROLL:\n                {\n                    // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)\n                    // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();\n                    popstack(stack);\n                    if (n < 0 || n >= (int)stack.size())\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch = stacktop(-n-1);\n                    if (opcode == OP_ROLL)\n                        stack.erase(stack.end()-n-1);\n                    stack.push_back(vch);\n                }\n                break;\n\n                case OP_ROT:\n                {\n                    // (x1 x2 x3 -- x2 x3 x1)\n                    //  x2 x1 x3  after first swap\n                    //  x2 x3 x1  after second swap\n                    if (stack.size() < 3)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    swap(stacktop(-3), stacktop(-2));\n                    swap(stacktop(-2), stacktop(-1));\n                }\n                break;\n\n                case OP_SWAP:\n                {\n                    // (x1 x2 -- x2 x1)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    swap(stacktop(-2), stacktop(-1));\n                }\n                break;\n\n                case OP_TUCK:\n                {\n                    // (x1 x2 -- x2 x1 x2)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype vch = stacktop(-1);\n                    stack.insert(stack.end()-2, vch);\n                }\n                break;\n\n\n                case OP_SIZE:\n                {\n                    // (in -- in size)\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    CScriptNum bn(stacktop(-1).size());\n                    stack.push_back(bn.getvch());\n                }\n                break;\n\n\n                //\n                // Bitwise logic\n                //\n                case OP_EQUAL:\n                case OP_EQUALVERIFY:\n                //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL\n                {\n                    // (x1 x2 - bool)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype& vch1 = stacktop(-2);\n                    valtype& vch2 = stacktop(-1);\n                    bool fEqual = (vch1 == vch2);\n                    // OP_NOTEQUAL is disabled because it would be too easy to say\n                    // something like n != 1 and have some wiseguy pass in 1 with extra\n                    // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)\n                    //if (opcode == OP_NOTEQUAL)\n                    //    fEqual = !fEqual;\n                    popstack(stack);\n                    popstack(stack);\n                    stack.push_back(fEqual ? vchTrue : vchFalse);\n                    if (opcode == OP_EQUALVERIFY)\n                    {\n                        if (fEqual)\n                            popstack(stack);\n                        else\n                            return set_error(serror, SCRIPT_ERR_EQUALVERIFY);\n                    }\n                }\n                break;\n\n\n                //\n                // Numeric\n                //\n                case OP_1ADD:\n                case OP_1SUB:\n                case OP_NEGATE:\n                case OP_ABS:\n                case OP_NOT:\n                case OP_0NOTEQUAL:\n                {\n                    // (in -- out)\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    CScriptNum bn(stacktop(-1), fRequireMinimal);\n                    switch (opcode)\n                    {\n                        case OP_1ADD:       bn += bnOne; break;\n                        case OP_1SUB:       bn -= bnOne; break;\n                        case OP_NEGATE:     bn = -bn; break;\n                        case OP_ABS:        if (bn < bnZero) bn = -bn; break;\n                        case OP_NOT:        bn = (bn == bnZero); break;\n                        case OP_0NOTEQUAL:  bn = (bn != bnZero); break;\n                        case OP_FALSE: case OP_PUSHDATA1: case OP_PUSHDATA2: case OP_PUSHDATA4: case OP_1NEGATE: case OP_RESERVED: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: case OP_NOP:case OP_VER: case OP_IF: case OP_NOTIF: case OP_VERIF: case OP_ELSE: case OP_ENDIF: case OP_VERIFY: case OP_RETURN: case OP_TOALTSTACK: case OP_FROMALTSTACK: case OP_2DROP: case OP_2DUP: case OP_3DUP: case OP_2OVER: case OP_2ROT: case OP_2SWAP: case OP_IFDUP: case OP_DEPTH: case OP_DROP: case OP_DUP: case OP_NIP: case OP_OVER: case OP_PICK: case OP_ROLL: case OP_ROT: case OP_SWAP: case OP_TUCK: case OP_CAT: case OP_SUBSTR: case OP_LEFT: case OP_RIGHT: case OP_SIZE: case OP_INVERT: case OP_AND: case OP_OR: case OP_XOR: case OP_EQUAL: case OP_EQUALVERIFY: case OP_RESERVED1: case OP_RESERVED2: case OP_2MUL: case OP_2DIV: case OP_MUL: case OP_DIV: case OP_MOD: case OP_LSHIFT: case OP_RSHIFT: case OP_SMALLINTEGER: case OP_PUBKEYS: case OP_PUBKEYHASH: case OP_PUBKEY: case OP_INVALIDOPCODE: case OP_VERNOTIF: case OP_ADD: case OP_SUB: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: case OP_WITHIN: case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: case OP_CODESEPARATOR: case OP_CHECKSIG: case OP_CHECKSIGVERIFY: case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: case OP_NOP1: case OP_CHECKLOCKTIMEVERIFY: case OP_CHECKSEQUENCEVERIFY:  case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:\n                        default:            assert(!\"invalid opcode\"); break;\n                    }\n                    popstack(stack);\n                    stack.push_back(bn.getvch());\n                }\n                break;\n\n                case OP_ADD:\n                case OP_SUB:\n                case OP_BOOLAND:\n                case OP_BOOLOR:\n                case OP_NUMEQUAL:\n                case OP_NUMEQUALVERIFY:\n                case OP_NUMNOTEQUAL:\n                case OP_LESSTHAN:\n                case OP_GREATERTHAN:\n                case OP_LESSTHANOREQUAL:\n                case OP_GREATERTHANOREQUAL:\n                case OP_MIN:\n                case OP_MAX:\n                {\n                    // (x1 x2 -- out)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    CScriptNum bn1(stacktop(-2), fRequireMinimal);\n                    CScriptNum bn2(stacktop(-1), fRequireMinimal);\n                    CScriptNum bn(0);\n                    switch (opcode)\n                    {\n                        case OP_ADD:\n                            bn = bn1 + bn2;\n                            break;\n\n                        case OP_SUB:\n                            bn = bn1 - bn2;\n                            break;\n\n                        case OP_BOOLAND:             bn = (bn1 != bnZero && bn2 != bnZero); break;\n                        case OP_BOOLOR:              bn = (bn1 != bnZero || bn2 != bnZero); break;\n                        case OP_NUMEQUAL:            bn = (bn1 == bn2); break;\n                        case OP_NUMEQUALVERIFY:      bn = (bn1 == bn2); break;\n                        case OP_NUMNOTEQUAL:         bn = (bn1 != bn2); break;\n                        case OP_LESSTHAN:            bn = (bn1 < bn2); break;\n                        case OP_GREATERTHAN:         bn = (bn1 > bn2); break;\n                        case OP_LESSTHANOREQUAL:     bn = (bn1 <= bn2); break;\n                        case OP_GREATERTHANOREQUAL:  bn = (bn1 >= bn2); break;\n                        case OP_MIN:                 bn = (bn1 < bn2 ? bn1 : bn2); break;\n                        case OP_MAX:                 bn = (bn1 > bn2 ? bn1 : bn2); break;\n                        case OP_0: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: case OP_PUSHDATA2: case OP_PUSHDATA4: case OP_1NEGATE: case OP_RESERVED: case OP_NOP: case OP_VER: case OP_IF: case OP_NOTIF: case OP_VERIF: case OP_VERNOTIF: case OP_ELSE: case OP_ENDIF: case OP_VERIFY: case OP_RETURN: case OP_TOALTSTACK: case OP_PUSHDATA1: case OP_3DUP: case OP_2OVER: case OP_2ROT: case OP_2SWAP: case OP_IFDUP: case OP_DEPTH: case OP_DROP: case OP_DUP: case OP_NIP: case OP_OVER: case OP_PICK: case OP_ROLL: case OP_ROT: case OP_SWAP: case OP_TUCK: case OP_CAT: case OP_SUBSTR: case OP_LEFT: case OP_RIGHT: case OP_SIZE: case OP_INVERT: case OP_AND: case OP_OR: case OP_XOR: case OP_EQUAL: case OP_EQUALVERIFY: case OP_RESERVED1: case OP_RESERVED2: case OP_1ADD: case OP_1SUB: case OP_2MUL: case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: case OP_MUL: case OP_DIV: case OP_MOD: case OP_LSHIFT: case OP_FROMALTSTACK: case OP_2DROP: case OP_2DUP: case OP_WITHIN: case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_CODESEPARATOR: case OP_CHECKSIG: case OP_CHECKSIGVERIFY: case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: case OP_RSHIFT: case OP_HASH160: case OP_HASH256: case OP_SMALLINTEGER: case OP_PUBKEYS: case OP_PUBKEYHASH: case OP_PUBKEY: case OP_INVALIDOPCODE:\n                        default:                     assert(!\"invalid opcode\"); break;\n                    }\n                    popstack(stack);\n                    popstack(stack);\n                    stack.push_back(bn.getvch());\n\n                    if (opcode == OP_NUMEQUALVERIFY)\n                    {\n                        if (CastToBool(stacktop(-1)))\n                            popstack(stack);\n                        else\n                            return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY);\n                    }\n                }\n                break;\n\n                case OP_WITHIN:\n                {\n                    // (x min max -- out)\n                    if (stack.size() < 3)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    CScriptNum bn1(stacktop(-3), fRequireMinimal);\n                    CScriptNum bn2(stacktop(-2), fRequireMinimal);\n                    CScriptNum bn3(stacktop(-1), fRequireMinimal);\n                    bool fValue = (bn2 <= bn1 && bn1 < bn3);\n                    popstack(stack);\n                    popstack(stack);\n                    popstack(stack);\n                    stack.push_back(fValue ? vchTrue : vchFalse);\n                }\n                break;\n\n\n                //\n                // Crypto\n                //\n                case OP_RIPEMD160:\n                case OP_SHA1:\n                case OP_SHA256:\n                case OP_HASH160:\n                case OP_HASH256:\n                {\n                    // (in -- hash)\n                    if (stack.size() < 1)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    valtype& vch = stacktop(-1);\n                    valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);\n                    if (opcode == OP_RIPEMD160)\n                        CRIPEMD160().Write(vch.data(), vch.size()).Finalize(vchHash.data());\n                    else if (opcode == OP_SHA1)\n                        CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data());\n                    else if (opcode == OP_SHA256)\n                        CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data());\n                    else if (opcode == OP_HASH160)\n                        CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data());\n                    else if (opcode == OP_HASH256)\n                        CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data());\n                    popstack(stack);\n                    stack.push_back(vchHash);\n                }\n                break;\n\n                case OP_CODESEPARATOR:\n                {\n                    // Hash starts after the code separator\n                    pbegincodehash = pc;\n                }\n                break;\n\n                case OP_CHECKSIG:\n                case OP_CHECKSIGVERIFY:\n                {\n                    // (sig pubkey -- bool)\n                    if (stack.size() < 2)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n\n                    valtype& vchSig    = stacktop(-2);\n                    valtype& vchPubKey = stacktop(-1);\n\n                    // Subset of script starting at the most recent codeseparator\n                    CScript scriptCode(pbegincodehash, pend);\n\n                    // Drop the signature in pre-segsig scripts but not segsig scripts\n                    if (sigversion == SIGVERSION_BASE)\n                    {\n                        scriptCode.FindAndDelete(CScript(vchSig));\n                    }\n\n                    //fixme: (PHASE5) (SEGSIG) (DERSIG) - We don't check the signature encoding here as with segsig signatures are COMPACT encoded\n                    //And further signatures are 'seperated' from the transaction for transaction ID etc.\n                    //HOWEVER, we should still triple check that no compact encoding mutability is possible and introduce a check for the COMPACT encoded signature anyway if theres anything that needs checking.\n                    if (sigversion == SIGVERSION_BASE)\n                    {\n                        if (!CheckSignatureEncoding(vchSig, flags, serror))\n                        {\n                            //serror is set\n                            return false;\n                        }\n                    }\n                    if (!CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror))\n                    {\n                        //serror is set\n                        return false;\n                    }\n                    bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);\n\n                    if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())\n                        return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);\n\n                    popstack(stack);\n                    popstack(stack);\n                    stack.push_back(fSuccess ? vchTrue : vchFalse);\n                    if (opcode == OP_CHECKSIGVERIFY)\n                    {\n                        if (fSuccess)\n                            popstack(stack);\n                        else\n                            return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY);\n                    }\n                }\n                break;\n\n                case OP_CHECKMULTISIG:\n                case OP_CHECKMULTISIGVERIFY:\n                {\n                    // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)\n\n                    int i = 1;\n                    if ((int)stack.size() < i)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n\n                    int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();\n                    if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG)\n                        return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);\n                    nOpCount += nKeysCount;\n                    if (nOpCount > MAX_OPS_PER_SCRIPT)\n                        return set_error(serror, SCRIPT_ERR_OP_COUNT);\n                    int ikey = ++i;\n                    // ikey2 is the position of last non-signature item in the stack. Top stack item = 1.\n                    // With SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if operation fails.\n                    int ikey2 = nKeysCount + 2;\n                    i += nKeysCount;\n                    if ((int)stack.size() < i)\n                        return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n\n                    int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();\n                    if (nSigsCount < 0 || nSigsCount > nKeysCount)\n                        return set_error(serror, SCRIPT_ERR_SIG_COUNT);\n                    int isig = ++i;\n                    i += nSigsCount;\n                    \n                    if (sigversion == SIGVERSION_SEGSIG)\n                    {\n                        if ((int)stack.size() < i-1)\n                            return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    }\n                    else\n                    {\n                        if ((int)stack.size() < i)\n                            return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                    }\n\n                    // Subset of script starting at the most recent codeseparator\n                    CScript scriptCode(pbegincodehash, pend);\n\n                    // Drop the signature in pre-segsig scripts but not segsig scripts\n                    if (sigversion == SIGVERSION_BASE)\n                    {\n                        for (int k = 0; k < nSigsCount; k++)\n                        {\n                            valtype& vchSig = stacktop(-isig-k);\n                            scriptCode.FindAndDelete(CScript(vchSig));\n                        }\n                    }\n\n                    bool fSuccess = true;\n                    while (fSuccess && nSigsCount > 0)\n                    {\n                        const valtype& vchSig = stacktop(-isig);\n                        const valtype& vchPubKey = stacktop(-ikey);\n\n                        // Note how this makes the exact order of pubkey/signature evaluation\n                        // distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.\n                        // See the script_(in)valid tests for details.\n                        //fixme: (PHASE5) (SEGSIG) (DERSIG) - We don't check the signature encoding here as with segsig signatures are COMPACT encoded\n                        //And further signatures are 'seperated' from the transaction for transaction ID etc.\n                        //HOWEVER, we should still triple check that no compact encoding mutability is possible and introduce a check for the COMPACT encoded signature anyway if theres anything that needs checking.\n                        if (sigversion == SIGVERSION_BASE)\n                        {\n                            if (!CheckSignatureEncoding(vchSig, flags, serror))\n                            {\n                                // serror is set\n                                return false;\n                            }\n                        }\n                        if (!CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror))\n                        {\n                            // serror is set\n                            return false;\n                        }\n\n                        // Check signature\n                        bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);\n\n                        if (fOk) {\n                            isig++;\n                            nSigsCount--;\n                        }\n                        ikey++;\n                        nKeysCount--;\n\n                        // If there are more signatures left than keys left,\n                        // then too many signatures have failed. Exit early,\n                        // without checking any further signatures.\n                        if (nSigsCount > nKeysCount)\n                            fSuccess = false;\n                    }\n\n                    // Clean up stack of actual arguments\n                    while (i-- > 1) {\n                        // If the operation failed, we require that all signatures must be empty vector\n                        if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size())\n                            return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);\n                        if (ikey2 > 0)\n                            ikey2--;\n                        popstack(stack);\n                    }\n\n                    if (sigversion == SIGVERSION_BASE)\n                    {\n                        // A bug causes CHECKMULTISIG to consume one extra argument\n                        // whose contents were not checked in any way.\n                        //\n                        // Unfortunately this is a potential source of mutability,\n                        // so optionally verify it is exactly equal to zero prior\n                        // to removing it from the stack.\n                        if (stack.size() < 1)\n                            return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);\n                        popstack(stack);\n                    }\n\n                    stack.push_back(fSuccess ? vchTrue : vchFalse);\n\n                    if (opcode == OP_CHECKMULTISIGVERIFY)\n                    {\n                        if (fSuccess)\n                            popstack(stack);\n                        else\n                            return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY);\n                    }\n                }\n                break;\n\n                case OP_FALSE: case OP_PUSHDATA1: case OP_PUSHDATA2: case OP_PUSHDATA4: case OP_RESERVED: case OP_VER: case OP_VERIF: case OP_VERNOTIF: case OP_CAT: case OP_SUBSTR: case OP_LEFT: case OP_RIGHT: case OP_INVERT: case OP_AND: case OP_OR: case OP_XOR: case OP_RESERVED1: case OP_RESERVED2: case OP_2MUL: case OP_2DIV: case OP_MUL: case OP_DIV: case OP_LSHIFT: case OP_RSHIFT: case OP_SMALLINTEGER: case OP_PUBKEYS: case OP_PUBKEYHASH: case OP_PUBKEY: case OP_INVALIDOPCODE: case OP_MOD:\n                default:\n                    return set_error(serror, SCRIPT_ERR_BAD_OPCODE);\n            }\n\n            // Size limits\n            if (stack.size() + altstack.size() > MAX_STACK_SIZE)\n                return set_error(serror, SCRIPT_ERR_STACK_SIZE);\n        }\n    }\n    catch (...)\n    {\n        return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);\n    }\n\n    if (!vfExec.empty())\n        return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);\n\n    return set_success(serror);\n}\n\nnamespace {\n\n/**\n * Wrapper that serializes like CTransaction, but with the modifications\n *  required for the signature hash done in-place\n */\nclass CTransactionSignatureSerializer {\nprivate:\n    const CTransaction& txTo;  //!< reference to the spending transaction (the one being serialized)\n    const CScript& scriptCode; //!< output script being consumed\n    const unsigned int nIn;    //!< input index of txTo being signed\n    const bool fAnyoneCanPay;  //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set\n    const bool fHashSingle;    //!< whether the hashtype is SIGHASH_SINGLE\n    const bool fHashNone;      //!< whether the hashtype is SIGHASH_NONE\n\npublic:\n    CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :\n        txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),\n        fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),\n        fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),\n        fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}\n\n    /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */\n    template<typename S>\n    void SerializeScriptCode(S &s) const {\n        CScript::const_iterator it = scriptCode.begin();\n        CScript::const_iterator itBegin = it;\n        opcodetype opcode;\n        unsigned int nCodeSeparators = 0;\n        while (scriptCode.GetOp(it, opcode)) {\n            if (opcode == OP_CODESEPARATOR)\n                nCodeSeparators++;\n        }\n        ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators);\n        it = itBegin;\n        while (scriptCode.GetOp(it, opcode)) {\n            if (opcode == OP_CODESEPARATOR) {\n                s.write((char*)&itBegin[0], it-itBegin-1);\n                itBegin = it;\n            }\n        }\n        if (itBegin != scriptCode.end())\n            s.write((char*)&itBegin[0], it-itBegin);\n    }\n\n    /** Serialize an input of txTo */\n    template<typename S>\n    void SerializeInput(S &s, unsigned int nInput) const {\n        // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized\n        if (fAnyoneCanPay)\n            nInput = nIn;\n        // Serialize the prevout\n        txTo.vin[nInput].GetPrevOut().WriteToStream(s, txTo.vin[nInput].GetType(), txTo.vin[nInput].GetFlags(), txTo.nVersion);\n        // Serialize the script\n        if (nInput != nIn)\n            // Blank out other inputs' signatures\n            ::Serialize(s, CScriptBase());\n        else\n            SerializeScriptCode(s);\n        if (!IsOldTransactionVersion(txTo.nVersion))\n        {\n            if (nInput != nIn && (fHashSingle || fHashNone))\n            {\n                // let the others update at will\n                ::Serialize(s, (int)0);\n            }\n            else\n            {\n                s << txTo.vin[nInput].nTypeAndFlags;\n                s << txTo.vin[nInput].GetSequence(txTo.nVersion);\n            }\n        }\n        else\n        {\n            // Serialize the nSequence\n            if (nInput != nIn && (fHashSingle || fHashNone))\n                // let the others update at will\n                ::Serialize(s, (int)0);\n            else\n                ::Serialize(s, txTo.vin[nInput].GetSequence(txTo.nVersion));\n        }\n    }\n\n    /** Serialize an output of txTo */\n    template<typename S>\n    void SerializeOutput(S &s, unsigned int nOutput) const {\n        if (fHashSingle && nOutput != nIn)\n            // Do not lock-in the txout payee at other indices as txin\n            CTxOut().WriteToStream(s, txTo.nVersion);\n        else\n            txTo.vout[nOutput].WriteToStream(s, txTo.nVersion);\n    }\n\n    /** Serialize txTo */\n    template<typename S>\n    void Serialize(S &s) const {\n        // Serialize nVersion\n        ::Serialize(s, txTo.nVersion);\n        // Serialize vin\n        unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();\n        ::WriteCompactSize(s, nInputs);\n        for (unsigned int nInput = 0; nInput < nInputs; nInput++)\n             SerializeInput(s, nInput);\n        // Serialize vout\n        unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size());\n        ::WriteCompactSize(s, nOutputs);\n        for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++)\n             SerializeOutput(s, nOutput);\n        // Serialize nLockTime\n        ::Serialize(s, txTo.nLockTime);\n    }\n};\n\nuint256 GetPrevoutHash(const CTransaction& txTo)\n{\n    CHashWriter ss(SER_GETHASH, 0);\n    for (const auto& txin : txTo.vin)\n    {\n        txin.GetPrevOut().WriteToStream(ss, txin.GetType(), txin.GetFlags(), txTo.nVersion);\n    }\n    return ss.GetHash();\n}\n\nuint256 GetSequenceHash(const CTransaction& txTo) {\n    CHashWriter ss(SER_GETHASH, 0);\n    for (const auto& txin : txTo.vin) {\n        if (!IsOldTransactionVersion(txTo.nVersion))\n            ss << txin.nTypeAndFlags;\n        ss << txin.GetSequence(txTo.nVersion);\n    }\n    return ss.GetHash();\n}\n\nuint256 GetOutputsHash(const CTransaction& txTo) {\n    CHashWriter ss(SER_GETHASH, 0);\n    for (const auto& txout : txTo.vout) {\n        txout.WriteToStream(ss, txTo.nVersion);\n    }\n    return ss.GetHash();\n}\n\n} // anon namespace\n\nPrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)\n{\n    hashPrevouts = GetPrevoutHash(txTo);\n    hashSequence = GetSequenceHash(txTo);\n    hashOutputs = GetOutputsHash(txTo);\n}\n\nuint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)\n{\n    if (sigversion == SIGVERSION_SEGSIG)\n    {\n        uint256 hashPrevouts;\n        uint256 hashSequence;\n        uint256 hashOutputs;\n\n        if (!(nHashType & SIGHASH_ANYONECANPAY)) {\n            hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);\n        }\n\n        if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {\n            hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);\n        }\n\n\n        if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {\n            hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);\n        } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {\n            CHashWriter ss(SER_GETHASH, 0);\n            txTo.vout[nIn].WriteToStream(ss, txTo.nVersion);\n            hashOutputs = ss.GetHash();\n        }\n\n        CHashWriter ss(SER_GETHASH, 0);\n        // Version\n        ss << txTo.nVersion;\n        // Input prevouts/nSequence (none/all, depending on flags)\n        ss << hashPrevouts;\n        ss << hashSequence;\n        // The input being signed (replacing the scriptSig with scriptCode + amount)\n        // The prevout may already be contained in hashPrevout, and the nSequence\n        // may already be contain in hashSequence.\n        txTo.vin[nIn].GetPrevOut().WriteToStream(ss, txTo.vin[nIn].GetType(), txTo.vin[nIn].GetFlags(), txTo.nVersion);\n        ss << static_cast<const CScriptBase&>(scriptCode);\n        ss << amount;\n\n        if (!IsOldTransactionVersion(txTo.nVersion))\n            ss << txTo.vin[nIn].nTypeAndFlags;\n        ss << txTo.vin[nIn].GetSequence(txTo.nVersion);\n        // Outputs (none/one/all, depending on flags)\n        ss << hashOutputs;\n        // Locktime\n        ss << txTo.nLockTime;\n        // Sighash type\n        ss << nHashType;\n\n        return ss.GetHash();\n    }\n\n    static const uint256 one(uint256S(\"0000000000000000000000000000000000000000000000000000000000000001\"));\n    if (nIn >= txTo.vin.size()) {\n        //  nIn out of range\n        return one;\n    }\n\n    // Check for invalid use of SIGHASH_SINGLE\n    if ((nHashType & 0x1f) == SIGHASH_SINGLE) {\n        if (nIn >= txTo.vout.size()) {\n            //  nOut out of range\n            return one;\n        }\n    }\n\n    // Wrapper to serialize only the necessary parts of the transaction being signed\n    CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);\n\n    // Serialize and hash\n    CHashWriter ss(SER_GETHASH, 0);\n    ss << txTmp << nHashType;\n    return ss.GetHash();\n}\n\nbool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const\n{\n    return pubkey.Verify(sighash, vchSig);\n}\n\nbool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const\n{\n    // Hash type is one byte tacked on to the end of the signature\n    std::vector<unsigned char> vchSig(vchSigIn);\n    if (vchSig.empty())\n        return false;\n    int nHashType = vchSig.back();\n    vchSig.pop_back();\n\n    uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);\n\n    if (sigversion == SIGVERSION_SEGSIG)\n    {\n        CPubKey pubkey;\n\n        // Recover the public key from the signature (this also verifies the signature)\n        if (!pubkey.RecoverCompact(sighash, vchSig))\n            return false;\n        // Ensure the public key is valid\n        if (!pubkey.IsValid())\n            return false;\n        // Ensure that the recovered pubkey is the correct one for the address in question\n        if (signatureKeyID == CKeyID())\n        {\n            if (CPubKey(vchPubKey).GetID() != pubkey.GetID())\n            {\n                return false;\n            }\n        }\n        else if (signatureKeyID != pubkey.GetID())\n        {\n            return false;\n        }\n        //NB! We don't need to verify the signature - the compact recovery already included verification\n    }\n    else\n    {\n        CPubKey pubkey = CPubKey(vchPubKey);\n        // Ensure the public key is valid\n        if (!pubkey.IsValid())\n            return false;\n        // Verify the signature is valid for the provided public key\n        if (!VerifySignature(vchSig, pubkey, sighash))\n            return false;\n    }\n\n    return true;\n}\n\nbool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const\n{\n    // There are two kinds of nLockTime: lock-by-blockheight\n    // and lock-by-blocktime, distinguished by whether\n    // nLockTime < LOCKTIME_THRESHOLD.\n    //\n    // We want to compare apples to apples, so fail the script\n    // unless the type of nLockTime being tested is the same as\n    // the nLockTime in the transaction.\n    if (!(txTo->nLockTime <  LOCKTIME_THRESHOLD && nLockTime <  LOCKTIME_THRESHOLD))\n        return false;\n    if (!(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD))\n        return false;\n\n    // Now that we know we're comparing apples-to-apples, the\n    // comparison is a simple numeric one.\n    if (nLockTime > (int64_t)txTo->nLockTime)\n        return false;\n\n    // Finally the nLockTime feature can be disabled and thus\n    // CHECKLOCKTIMEVERIFY bypassed if every txin has been\n    // finalized by setting nSequence to maxint. The\n    // transaction would be allowed into the blockchain, making\n    // the opcode ineffective.\n    //\n    // Testing if this vin is not final is sufficient to\n    // prevent this condition. Alternatively we could test all\n    // inputs, but testing just this input minimizes the data\n    // required to prove correct CHECKLOCKTIMEVERIFY execution.\n    \n    if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].GetSequence(txTo->nVersion))\n        return false;\n\n    return true;\n}\n\nbool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const\n{\n    // Fail if the transaction's version number is not set high\n    // enough to trigger BIP 68 rules.\n    if (static_cast<uint32_t>(txTo->nVersion) < 2)\n        return false;\n\n    if (IsOldTransactionVersion(txTo->nVersion))\n    {\n        // Relative lock times are supported by comparing the passed\n        // in operand to the sequence number of the input.\n        const int64_t txToSequence = (int64_t)txTo->vin[nIn].GetSequence(txTo->nVersion);\n    \n        // Sequence numbers with their most significant bit set are not\n        // consensus constrained. Testing that the transaction's sequence\n        // number do not have this bit set prevents using this property\n        // to get around a CHECKSEQUENCEVERIFY check.\n        if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG)\n            return false;\n        \n        // Mask off any bits that do not have consensus-enforced meaning\n        // before doing the integer comparisons\n        const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;\n        const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;\n        const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;\n        \n        // There are two kinds of nSequence: lock-by-blockheight\n        // and lock-by-blocktime, distinguished by whether\n        // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.\n        //\n        // We want to compare apples to apples, so fail the script\n        // unless the type of nSequenceMasked being tested is the same as\n        // the nSequenceMasked in the transaction.\n        if (!(txToSequenceMasked <  CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG))\n            return false;\n        if (!(txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG))\n            return false;\n\n        // Now that we know we're comparing apples-to-apples, the\n        // comparison is a simple numeric one.\n        if (nSequenceMasked > txToSequenceMasked)\n            return false;\n    }\n    else\n    {\n        const int64_t txToSequence = (int64_t)txTo->vin[nIn].GetSequence(txTo->nVersion);\n\n        // Ensure we can't get around a CHECKSEQUENCEVERIFY check by having no 'sequence number' at all\n        if (!txTo->vin[nIn].FlagIsSet(CTxInFlags::HasRelativeLock))\n            return false;\n        \n        // There are two kinds of nSequence: lock-by-blockheight\n        // and lock-by-blocktime\n        // Ensure we compare the same type\n        const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;\n        const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;\n        if (txTo->vin[nIn].FlagIsSet(CTxInFlags::HasTimeBasedRelativeLock) && nSequenceMasked <  CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)\n        {               \n            return false;\n        }\n        else if (txTo->vin[nIn].FlagIsSet(CTxInFlags::HasBlockBasedRelativeLock) && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)\n        {\n            return false;\n        }\n        else\n        {\n            return false;\n        }\n        \n        // Now that we know we're comparing apples-to-apples, the\n        // comparison is a simple numeric one.\n        if (nSequenceMasked > txToSequence)\n                return false;\n    }\n    \n    return true;\n}\n\n//fixme: (PHASE5) de-dupe\nstatic CScript PushAll(const std::vector<valtype>& values)\n{\n    CScript result;\n    for(const valtype& v : values) {\n        if (v.size() == 0) {\n            result << OP_0;\n        } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {\n            result << CScript::EncodeOP_N(v[0]);\n        } else {\n            result << v;\n        }\n    }\n    return result;\n}\n\nbool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CSegregatedSignatureData* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptVersion scriptversion, ScriptError* serror)\n{\n    static const CSegregatedSignatureData emptyWitness;\n    if (witness == NULL)\n    {\n        witness = &emptyWitness;\n    }\n\n    set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);\n\n    if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly())\n    {\n        return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);\n    }\n\n    std::vector<std::vector<unsigned char> > stack, stackCopy;\n    if (scriptSig.size() == 0 && witness)\n    {\n        CScript scriptSigTemp = PushAll(witness->stack);\n        if (!EvalScript(stack, scriptSigTemp, flags, checker, scriptversion, serror))\n            // serror is set\n            return false;\n    }\n    else\n    {\n        if (!EvalScript(stack, scriptSig, flags, checker, scriptversion, serror))\n            // serror is set\n            return false;\n    }\n\n    if (flags & SCRIPT_VERIFY_P2SH)\n            stackCopy = stack;\n    if (!EvalScript(stack, scriptPubKey, flags, checker, scriptversion, serror))\n    {\n        // serror is set\n        return false;\n    }\n\n    if (stack.empty())\n        return set_error(serror, SCRIPT_ERR_EVAL_FALSE);\n    if (!CastToBool(stack.back()))\n        return set_error(serror, SCRIPT_ERR_EVAL_FALSE);\n\n    // Additional validation for spend-to-script-hash transactions:\n    if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())\n    {\n        // scriptSig must be literals-only or validation fails\n        if (!scriptSig.IsPushOnly())\n            return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);\n\n        // Restore stack.\n        swap(stack, stackCopy);\n\n        // stack cannot be empty here, because if it was the\n        // P2SH  HASH <> EQUAL  scriptPubKey would be evaluated with\n        // an empty stack and the EvalScript above would return false.\n        assert(!stack.empty());\n\n        const valtype& pubKeySerialized = stack.back();\n        CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());\n        popstack(stack);\n\n        if (!EvalScript(stack, pubKey2, flags, checker, scriptversion, serror))\n            // serror is set\n            return false;\n        if (stack.empty())\n            return set_error(serror, SCRIPT_ERR_EVAL_FALSE);\n        if (!CastToBool(stack.back()))\n            return set_error(serror, SCRIPT_ERR_EVAL_FALSE);\n    }\n\n    // The CLEANSTACK check is only performed after potential P2SH evaluation,\n    // as the non-P2SH evaluation of a P2SH script will obviously not result in\n    // a clean stack (the P2SH inputs remain).\n    if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0)\n    {\n        // Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK\n        // would be possible, which is not a softfork (and P2SH should be one).\n        assert((flags & SCRIPT_VERIFY_P2SH) != 0);\n        if (stack.size() != 1)\n        {\n            return set_error(serror, SCRIPT_ERR_CLEANSTACK);\n        }\n    }\n\n    return set_success(serror);\n}\n\n"
  },
  {
    "path": "src/script/interpreter.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_INTERPRETER_H\n#define SCRIPT_INTERPRETER_H\n\n#include \"script_error.h\"\n#include \"primitives/transaction.h\"\n\n#include <vector>\n#include <stdint.h>\n#include <string>\n#include \"coins.h\"\n\nclass CPubKey;\nclass CScript;\nclass CTransaction;\nclass uint256;\n\n/** Signature hash types/flags */\nenum\n{\n    SIGHASH_ALL = 1,\n    SIGHASH_NONE = 2,\n    SIGHASH_SINGLE = 3,\n    SIGHASH_ANYONECANPAY = 0x80,\n};\n\n/** Script verification flags */\nenum\n{\n    SCRIPT_VERIFY_NONE      = 0,\n\n    // Evaluate P2SH subscripts (softfork safe, BIP16).\n    SCRIPT_VERIFY_P2SH      = (1U << 0),\n\n    // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.\n    // Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.\n    // (softfork safe, but not used or intended as a consensus rule).\n    SCRIPT_VERIFY_STRICTENC = (1U << 1),\n\n    // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)\n    SCRIPT_VERIFY_DERSIG    = (1U << 2),\n\n    // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure\n    // (softfork safe, BIP62 rule 5).\n    SCRIPT_VERIFY_LOW_S     = (1U << 3),\n\n    // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).\n    SCRIPT_VERIFY_SIGPUSHONLY = (1U << 4),\n\n    // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct\n    // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating\n    // any other push causes the script to fail (BIP62 rule 3).\n    // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).\n    // (softfork safe)\n    SCRIPT_VERIFY_MINIMALDATA = (1U << 5),\n\n    // Discourage use of NOPs reserved for upgrades (NOP1-10)\n    //\n    // Provided so that nodes can avoid accepting or mining transactions\n    // containing executed NOP's whose meaning may change after a soft-fork,\n    // thus rendering the script invalid; with this flag set executing\n    // discouraged NOPs fails the script. This verification flag will never be\n    // a mandatory flag applied to scripts in a block. NOPs that are not\n    // executed, e.g.  within an unexecuted IF ENDIF block, are *not* rejected.\n    SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS  = (1U << 6),\n\n    // Require that only a single stack element remains after evaluation. This changes the success criterion from\n    // \"At least one stack element must remain, and when interpreted as a boolean, it must be true\" to\n    // \"Exactly one stack element must remain, and when interpreted as a boolean, it must be true\".\n    // (softfork safe, BIP62 rule 6)\n    // Note: CLEANSTACK should never be used without P2SH or WITNESS.\n    SCRIPT_VERIFY_CLEANSTACK = (1U << 7),\n\n    // Verify CHECKLOCKTIMEVERIFY\n    //\n    // See BIP65 for details.\n    SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 8),\n\n    // support CHECKSEQUENCEVERIFY opcode\n    //\n    // See BIP112 for details\n    SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 9),\n\n    // Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector\n    //\n    SCRIPT_VERIFY_MINIMALIF = (1U << 10),\n\n    // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed\n    //\n    SCRIPT_VERIFY_NULLFAIL = (1U << 11),\n};\n\nbool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);\n\nstruct PrecomputedTransactionData\n{\n    uint256 hashPrevouts, hashSequence, hashOutputs;\n\n    PrecomputedTransactionData(const CTransaction& tx);\n};\n\nenum SigVersion\n{\n    SIGVERSION_BASE = 0,\n    SIGVERSION_SEGSIG = 1\n};\n\nenum ScriptVersion\n{\n    SCRIPT_V1, // V1 (bitcoin) transaction format\n    SCRIPT_V2  // Munt V2 transaction format (SegSig)\n};\n\nuint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);\n\nclass BaseSignatureChecker\n{\npublic:\n    //fixme: (PHASE5) Temporary placed here - move back to TransactionSignatureChecker after phase 4 activation.\n    const CKeyID signatureKeyID;\n    const CKeyID spendingKeyID;\n    BaseSignatureChecker(const CKeyID signatureKeyID_, const CKeyID spendingKeyID_) : signatureKeyID(signatureKeyID_), spendingKeyID(spendingKeyID_) {}\n\n    virtual bool CheckSig([[maybe_unused]] const std::vector<unsigned char>& scriptSig, [[maybe_unused]] const std::vector<unsigned char>& vchPubKey, [[maybe_unused]] const CScript& scriptCode, [[maybe_unused]] SigVersion sigversion) const\n    {\n        return false;\n    }\n\n    virtual bool CheckLockTime([[maybe_unused]] const CScriptNum& nLockTime) const\n    {\n         return false;\n    }\n\n    virtual bool CheckSequence([[maybe_unused]] const CScriptNum& nSequence) const\n    {\n         return false;\n    }\n\n    virtual ~BaseSignatureChecker() {}\n};\n\nclass TransactionSignatureChecker : public BaseSignatureChecker\n{\nprivate:\n    const CTransaction* txTo;\n    unsigned int nIn;\n    const CAmount amount;\n    const PrecomputedTransactionData* txdata;\n\nprotected:\n    virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;\n\npublic:\n    TransactionSignatureChecker(const CKeyID signatureKeyID_, const CKeyID spendingKeyID_, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : BaseSignatureChecker(signatureKeyID_, spendingKeyID_), txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}\n    TransactionSignatureChecker(const CKeyID signatureKeyID_, const CKeyID spendingKeyID_, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : BaseSignatureChecker(signatureKeyID_, spendingKeyID_), txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}\n    bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;\n    bool CheckLockTime(const CScriptNum& nLockTime) const;\n    bool CheckSequence(const CScriptNum& nSequence) const;\n};\n\nclass MutableTransactionSignatureChecker : public TransactionSignatureChecker\n{\nprivate:\n    const CTransaction txTo;\n\npublic:\n    MutableTransactionSignatureChecker(CKeyID signingKeyID, CKeyID spendingKeyID, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : TransactionSignatureChecker(signingKeyID, spendingKeyID, &txTo, nInIn, amountIn), txTo(*txToIn) {}\n};\n\nbool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptVersion scriptversion, ScriptError* error = NULL);\nbool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CSegregatedSignatureData* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptVersion scriptversion, ScriptError* serror = NULL);\n\n#endif\n"
  },
  {
    "path": "src/script/ismine.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"ismine.h\"\n\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"script/sign.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/wallet.h>\n\n\n\n\ntypedef std::vector<unsigned char> valtype;\n\nunsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)\n{\n    unsigned int nResult = 0;\n    for(const valtype& pubkey : pubkeys)\n    {\n        CKeyID keyID = CPubKey(pubkey).GetID();\n        if (keystore.HaveKey(keyID))\n            ++nResult;\n    }\n    return nResult;\n}\n\nunsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& wallet)\n{\n    unsigned int nResult = 0;\n    for (const auto& accountPair : wallet.mapAccounts)\n        nResult += HaveKeys(pubkeys, *accountPair.second);\n    return nResult;\n}\n\nisminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion sigversion)\n{\n    bool isInvalid = false;\n    return IsMine(keystore, scriptPubKey, isInvalid, sigversion);\n}\n\nisminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion sigversion)\n{\n    bool isInvalid = false;\n    return IsMine(keystore, dest, isInvalid, sigversion);\n}\n\nisminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& isInvalid, SigVersion sigversion)\n{\n    if (dest.type() == typeid(CPoW2WitnessDestination))\n    {\n        const CPoW2WitnessDestination* witnessDetails = boost::get<CPoW2WitnessDestination>(&dest);\n        return IsMine(keystore, *witnessDetails);\n    }\n    else\n    {\n        CScript script = GetScriptForDestination(dest);\n        return IsMine(keystore, script, isInvalid, sigversion);\n    }\n}\n\nisminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)\n{\n    std::vector<valtype> vSolutions;\n    txnouttype whichType;\n    if (!Solver(scriptPubKey, whichType, vSolutions)) {\n        if (keystore.HaveWatchOnly(scriptPubKey))\n            return ISMINE_WATCH_UNSOLVABLE;\n        return ISMINE_NO;\n    }\n\n    CKeyID keyID;\n    switch (whichType)\n    {\n        case TX_NONSTANDARD:\n        case TX_NULL_DATA:\n            break;\n        case TX_PUBKEY:\n            keyID = CPubKey(vSolutions[0]).GetID();\n            if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) {\n                isInvalid = true;\n                return ISMINE_NO;\n            }\n            if (keystore.HaveKey(keyID))\n                return ISMINE_SPENDABLE;\n            break;\n        case TX_PUBKEYHASH:\n            keyID = CKeyID(uint160(vSolutions[0]));\n            if (sigversion != SIGVERSION_BASE) {\n                CPubKey pubkey;\n                if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {\n                    isInvalid = true;\n                    return ISMINE_NO;\n                }\n            }\n            if (keystore.HaveKey(keyID))\n                return ISMINE_SPENDABLE;\n            break;\n        case TX_SCRIPTHASH:\n        {\n            CScriptID scriptID = CScriptID(uint160(vSolutions[0]));\n            CScript subscript;\n            if (keystore.GetCScript(scriptID, subscript)) {\n                isminetype ret = IsMine(keystore, subscript, isInvalid);\n                if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))\n                    return ret;\n            }\n            break;\n        }\n\n        case TX_MULTISIG:\n        {\n            // Only consider transactions \"mine\" if we own ALL the\n            // keys involved. Multi-signature transactions that are\n            // partially owned (somebody else has a key that can spend\n            // them) enable spend-out-from-under-you attacks, especially\n            // in shared-wallet situations.\n            std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);\n            if (sigversion != SIGVERSION_BASE) {\n                for (size_t i = 0; i < keys.size(); i++) {\n                    if (keys[i].size() != 33) {\n                        isInvalid = true;\n                        return ISMINE_NO;\n                    }\n                }\n            }\n            if (HaveKeys(keys, keystore) == keys.size())\n                return ISMINE_SPENDABLE;\n            break;\n        }\n        case TX_STANDARD_WITNESS:\n        case TX_STANDARD_PUBKEY_HASH:\n            assert(0);\n            break;\n    }\n\n    //fixme: (FUT) (WATCH_ONLY) (MED)\n    /*if (keystore.HaveWatchOnly(scriptPubKey)) {\n        // TODO: This could be optimized some by doing some work after the above solver\n        SignatureData sigs;\n        return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;\n    }*/\n    return ISMINE_NO;\n}\n\n\nisminetype IsMine(const CKeyStore& keystore, const CPoW2WitnessDestination& witnessDetails)\n{\n    if (keystore.HaveKey(witnessDetails.spendingKey))\n        return ISMINE_SPENDABLE;\n    if (keystore.HaveKey(witnessDetails.witnessKey))\n        return ISMINE_WITNESS;\n    return ISMINE_NO;\n}\n\nisminetype IsMine(const CKeyStore& keystore, const CTxOutPoW2Witness& witnessDetails)\n{\n    if (keystore.HaveKey(witnessDetails.spendingKeyID))\n        return ISMINE_SPENDABLE;\n    if (keystore.HaveKey(witnessDetails.witnessKeyID))\n        return ISMINE_WITNESS;\n    return ISMINE_NO;\n}\n\nisminetype IsMine(const CKeyStore& keystore, const CTxOutStandardKeyHash& standardKeyHash)\n{\n    if (keystore.HaveKey(standardKeyHash.keyID))\n        return ISMINE_SPENDABLE;\n    return ISMINE_NO;\n}\n\nisminetype IsMine(const CKeyStore &keystore, const CTxOut& txout)\n{\n    switch (txout.GetType())\n    {\n        case CTxOutType::ScriptLegacyOutput:\n            return IsMine(keystore, txout.output.scriptPubKey);\n        case CTxOutType::PoW2WitnessOutput:\n            return IsMine(keystore, txout.output.witnessDetails);\n        case CTxOutType::StandardKeyHashOutput:\n            return IsMine(keystore, txout.output.standardKeyHash);\n    }\n    return ISMINE_NO;\n}\n\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CTxOut& txout, uint64_t time)\n{\n    switch (txout.GetType())\n    {\n        case CTxOutType::ScriptLegacyOutput:\n            return RemoveAddressFromKeypoolIfIsMine(keystore, txout.output.scriptPubKey, time);\n        case CTxOutType::PoW2WitnessOutput:\n        {\n            bool haveSpendingKey = keystore.HaveKey(txout.output.witnessDetails.spendingKeyID);\n            bool haveWitnessKey = keystore.HaveKey(txout.output.witnessDetails.witnessKeyID);\n\n            if (haveSpendingKey)\n                keystore.MarkKeyUsed(txout.output.witnessDetails.spendingKeyID, time);\n            if (haveWitnessKey)\n                keystore.MarkKeyUsed(txout.output.witnessDetails.witnessKeyID, time);\n\n            if (haveSpendingKey)\n                return ISMINE_SPENDABLE;\n            if (haveWitnessKey)\n                return ISMINE_WITNESS;\n            break;\n        }\n        case CTxOutType::StandardKeyHashOutput:\n        {\n            if (keystore.HaveKey(txout.output.standardKeyHash.keyID))\n            {\n                keystore.MarkKeyUsed(txout.output.standardKeyHash.keyID, time);\n                return ISMINE_SPENDABLE;\n            }\n            break;\n        }\n    }\n    return ISMINE_NO;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CScript& scriptPubKey, uint64_t time, SigVersion sigversion)\n{\n    bool isInvalid = false;\n    return RemoveAddressFromKeypoolIfIsMine(keystore, scriptPubKey, time, isInvalid, sigversion);\n}\n\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CScript& scriptPubKey, uint64_t time, bool& isInvalid, SigVersion sigversion)\n{\n    std::vector<valtype> vSolutions;\n    txnouttype whichType;\n    if (!Solver(scriptPubKey, whichType, vSolutions)) {\n        if (keystore.HaveWatchOnly(scriptPubKey))\n            return ISMINE_WATCH_UNSOLVABLE;\n        return ISMINE_NO;\n    }\n\n    CKeyID keyID;\n    switch (whichType)\n    {\n        case TX_NONSTANDARD:\n        case TX_NULL_DATA:\n            break;\n        case TX_PUBKEY:\n            keyID = CPubKey(vSolutions[0]).GetID();\n            if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) {\n                isInvalid = true;\n                return ISMINE_NO;\n            }\n            if (keystore.HaveKey(keyID))\n            {\n                keystore.MarkKeyUsed(keyID, time);\n                return ISMINE_SPENDABLE;\n            }\n            break;\n        case TX_PUBKEYHASH:\n            keyID = CKeyID(uint160(vSolutions[0]));\n            if (sigversion != SIGVERSION_BASE) {\n                CPubKey pubkey;\n                if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {\n                    isInvalid = true;\n                    return ISMINE_NO;\n                }\n            }\n            if (keystore.HaveKey(keyID))\n            {\n                keystore.MarkKeyUsed(keyID, time);\n                return ISMINE_SPENDABLE;\n            }\n            break;\n        case TX_SCRIPTHASH:\n        {\n            CScriptID scriptID = CScriptID(uint160(vSolutions[0]));\n            CScript subscript;\n            if (keystore.GetCScript(scriptID, subscript)) {\n                isminetype ret = RemoveAddressFromKeypoolIfIsMine(keystore, subscript, time, isInvalid);\n                if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))\n                    return ret;\n            }\n            break;\n        }\n\n        case TX_MULTISIG:\n        {\n            // Only consider transactions \"mine\" if we own ALL the\n            // keys involved. Multi-signature transactions that are\n            // partially owned (somebody else has a key that can spend\n            // them) enable spend-out-from-under-you attacks, especially\n            // in shared-wallet situations.\n            std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);\n            if (sigversion != SIGVERSION_BASE) {\n                for (size_t i = 0; i < keys.size(); i++) {\n                    if (keys[i].size() != 33) {\n                        isInvalid = true;\n                        return ISMINE_NO;\n                    }\n                }\n            }\n            if (HaveKeys(keys, keystore) == keys.size())\n            {\n                for (auto& key : keys)\n                {\n                    keystore.MarkKeyUsed(CPubKey(key).GetID(), time);\n                }\n                return ISMINE_SPENDABLE;\n            }\n            break;\n        }\n        case TX_STANDARD_WITNESS:\n        case TX_STANDARD_PUBKEY_HASH:\n            assert(0);\n            break;\n    }\n    /*\n     //fixme: (FUT) (WATCH_ONLY) (MED)\n      if (keystore.HaveWatchOnly(scriptPubKey)) {\n        // TODO: This could be optimized some by doing some work after the above solver\n        SignatureData sigs;\n        return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;\n    }*/\n    return ISMINE_NO;\n}\n#endif\n"
  },
  {
    "path": "src/script/ismine.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_ISMINE_H\n#define SCRIPT_ISMINE_H\n\n#include \"script/standard.h\"\n\n#include <stdint.h>\n\nclass CKeyStore;\nclass CScript;\nclass CWallet;\n\n/** IsMine() return codes */\nenum isminetype : uint_fast8_t\n{\n    ISMINE_NO = 0,\n    //! Indicates that we don't know how to create a scriptSig that would solve this if we were given the appropriate private keys\n    ISMINE_WATCH_UNSOLVABLE = 1,\n    //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys\n    ISMINE_WATCH_SOLVABLE = 2,\n    ISMINE_WATCH_ONLY = ISMINE_WATCH_SOLVABLE | ISMINE_WATCH_UNSOLVABLE,\n    //fixme: (PHASE5) - We should assign a different value to ISMINE_WITNESS than ISMINE_SPENDABLE\n    //However this will require carefully going through every case in the code that deals with \"ISMINE_\" values to ensure its handled right.\n    ISMINE_WITNESS = 4,\n    ISMINE_SPENDABLE = 4,\n    ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE\n};\n/** used for bitflags of isminetype */\ntypedef uint8_t isminefilter;\n\n/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion\n * and return a ISMINE_NO immediately, as an invalid script should never be considered as \"mine\". This is needed as\n * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed\n * keys in SIGVERSION_SEGSIG script, but could also be used in similar cases in the future\n */\nisminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SIGVERSION_BASE);\nisminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SIGVERSION_BASE);\nisminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SIGVERSION_BASE);\nisminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SIGVERSION_BASE);\nisminetype IsMine(const CKeyStore& keystore, const CTxOut& txout);\nisminetype IsMine(const CKeyStore& keystore, const CPoW2WitnessDestination& witnessDetails);\nisminetype IsMine(const CKeyStore& keystore, const CTxOutPoW2Witness& witnessDetails);\nisminetype IsMine(const CKeyStore& keystore, const CTxOutStandardKeyHash& standardKeyHash);\n\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CScript& scriptPubKey, uint64_t time, bool& isInvalid, SigVersion = SIGVERSION_BASE);\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CScript& scriptPubKey, uint64_t time, SigVersion = SIGVERSION_BASE);\nisminetype RemoveAddressFromKeypoolIfIsMine(CWallet& keystore, const CTxOut& txout, uint64_t time);\n\n#endif\n"
  },
  {
    "path": "src/script/script.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"script.h\"\n#include \"alert.h\"\n#include <util.h>\n\n#include \"tinyformat.h\"\n#include \"util/strencodings.h\"\n\n//Munt\n#include <primitives/transaction.h>\n\nconst char* GetOpName(opcodetype opcode)\n{\n    switch (opcode)\n    {\n    // push value\n    case OP_0                      : return \"0\";\n    case OP_PUSHDATA1              : return \"OP_PUSHDATA1\";\n    case OP_PUSHDATA2              : return \"OP_PUSHDATA2\";\n    case OP_PUSHDATA4              : return \"OP_PUSHDATA4\";\n    case OP_1NEGATE                : return \"-1\";\n    case OP_RESERVED               : return \"OP_RESERVED\";\n    case OP_1                      : return \"1\";\n    case OP_2                      : return \"2\";\n    case OP_3                      : return \"3\";\n    case OP_4                      : return \"4\";\n    case OP_5                      : return \"5\";\n    case OP_6                      : return \"6\";\n    case OP_7                      : return \"7\";\n    case OP_8                      : return \"8\";\n    case OP_9                      : return \"9\";\n    case OP_10                     : return \"10\";\n    case OP_11                     : return \"11\";\n    case OP_12                     : return \"12\";\n    case OP_13                     : return \"13\";\n    case OP_14                     : return \"14\";\n    case OP_15                     : return \"15\";\n    case OP_16                     : return \"16\";\n\n    // control\n    case OP_NOP                    : return \"OP_NOP\";\n    case OP_VER                    : return \"OP_VER\";\n    case OP_IF                     : return \"OP_IF\";\n    case OP_NOTIF                  : return \"OP_NOTIF\";\n    case OP_VERIF                  : return \"OP_VERIF\";\n    case OP_VERNOTIF               : return \"OP_VERNOTIF\";\n    case OP_ELSE                   : return \"OP_ELSE\";\n    case OP_ENDIF                  : return \"OP_ENDIF\";\n    case OP_VERIFY                 : return \"OP_VERIFY\";\n    case OP_RETURN                 : return \"OP_RETURN\";\n\n    // stack ops\n    case OP_TOALTSTACK             : return \"OP_TOALTSTACK\";\n    case OP_FROMALTSTACK           : return \"OP_FROMALTSTACK\";\n    case OP_2DROP                  : return \"OP_2DROP\";\n    case OP_2DUP                   : return \"OP_2DUP\";\n    case OP_3DUP                   : return \"OP_3DUP\";\n    case OP_2OVER                  : return \"OP_2OVER\";\n    case OP_2ROT                   : return \"OP_2ROT\";\n    case OP_2SWAP                  : return \"OP_2SWAP\";\n    case OP_IFDUP                  : return \"OP_IFDUP\";\n    case OP_DEPTH                  : return \"OP_DEPTH\";\n    case OP_DROP                   : return \"OP_DROP\";\n    case OP_DUP                    : return \"OP_DUP\";\n    case OP_NIP                    : return \"OP_NIP\";\n    case OP_OVER                   : return \"OP_OVER\";\n    case OP_PICK                   : return \"OP_PICK\";\n    case OP_ROLL                   : return \"OP_ROLL\";\n    case OP_ROT                    : return \"OP_ROT\";\n    case OP_SWAP                   : return \"OP_SWAP\";\n    case OP_TUCK                   : return \"OP_TUCK\";\n\n    // splice ops\n    case OP_CAT                    : return \"OP_CAT\";\n    case OP_SUBSTR                 : return \"OP_SUBSTR\";\n    case OP_LEFT                   : return \"OP_LEFT\";\n    case OP_RIGHT                  : return \"OP_RIGHT\";\n    case OP_SIZE                   : return \"OP_SIZE\";\n\n    // bit logic\n    case OP_INVERT                 : return \"OP_INVERT\";\n    case OP_AND                    : return \"OP_AND\";\n    case OP_OR                     : return \"OP_OR\";\n    case OP_XOR                    : return \"OP_XOR\";\n    case OP_EQUAL                  : return \"OP_EQUAL\";\n    case OP_EQUALVERIFY            : return \"OP_EQUALVERIFY\";\n    case OP_RESERVED1              : return \"OP_RESERVED1\";\n    case OP_RESERVED2              : return \"OP_RESERVED2\";\n\n    // numeric\n    case OP_1ADD                   : return \"OP_1ADD\";\n    case OP_1SUB                   : return \"OP_1SUB\";\n    case OP_2MUL                   : return \"OP_2MUL\";\n    case OP_2DIV                   : return \"OP_2DIV\";\n    case OP_NEGATE                 : return \"OP_NEGATE\";\n    case OP_ABS                    : return \"OP_ABS\";\n    case OP_NOT                    : return \"OP_NOT\";\n    case OP_0NOTEQUAL              : return \"OP_0NOTEQUAL\";\n    case OP_ADD                    : return \"OP_ADD\";\n    case OP_SUB                    : return \"OP_SUB\";\n    case OP_MUL                    : return \"OP_MUL\";\n    case OP_DIV                    : return \"OP_DIV\";\n    case OP_MOD                    : return \"OP_MOD\";\n    case OP_LSHIFT                 : return \"OP_LSHIFT\";\n    case OP_RSHIFT                 : return \"OP_RSHIFT\";\n    case OP_BOOLAND                : return \"OP_BOOLAND\";\n    case OP_BOOLOR                 : return \"OP_BOOLOR\";\n    case OP_NUMEQUAL               : return \"OP_NUMEQUAL\";\n    case OP_NUMEQUALVERIFY         : return \"OP_NUMEQUALVERIFY\";\n    case OP_NUMNOTEQUAL            : return \"OP_NUMNOTEQUAL\";\n    case OP_LESSTHAN               : return \"OP_LESSTHAN\";\n    case OP_GREATERTHAN            : return \"OP_GREATERTHAN\";\n    case OP_LESSTHANOREQUAL        : return \"OP_LESSTHANOREQUAL\";\n    case OP_GREATERTHANOREQUAL     : return \"OP_GREATERTHANOREQUAL\";\n    case OP_MIN                    : return \"OP_MIN\";\n    case OP_MAX                    : return \"OP_MAX\";\n    case OP_WITHIN                 : return \"OP_WITHIN\";\n\n    // crypto\n    case OP_RIPEMD160              : return \"OP_RIPEMD160\";\n    case OP_SHA1                   : return \"OP_SHA1\";\n    case OP_SHA256                 : return \"OP_SHA256\";\n    case OP_HASH160                : return \"OP_HASH160\";\n    case OP_HASH256                : return \"OP_HASH256\";\n    case OP_CODESEPARATOR          : return \"OP_CODESEPARATOR\";\n    case OP_CHECKSIG               : return \"OP_CHECKSIG\";\n    case OP_CHECKSIGVERIFY         : return \"OP_CHECKSIGVERIFY\";\n    case OP_CHECKMULTISIG          : return \"OP_CHECKMULTISIG\";\n    case OP_CHECKMULTISIGVERIFY    : return \"OP_CHECKMULTISIGVERIFY\";\n\n    // expansion\n    case OP_NOP1                   : return \"OP_NOP1\";\n    case OP_CHECKLOCKTIMEVERIFY    : return \"OP_CHECKLOCKTIMEVERIFY\";\n    case OP_CHECKSEQUENCEVERIFY    : return \"OP_CHECKSEQUENCEVERIFY\";\n    case OP_NOP4                   : return \"OP_NOP4\";\n    case OP_NOP5                   : return \"OP_NOP5\";\n    case OP_NOP6                   : return \"OP_NOP6\";\n    case OP_NOP7                   : return \"OP_NOP7\";\n    case OP_NOP8                   : return \"OP_NOP8\";\n    case OP_NOP9                   : return \"OP_NOP9\";\n    case OP_NOP10                  : return \"OP_NOP10\";\n\n    case OP_INVALIDOPCODE          : return \"OP_INVALIDOPCODE\";\n\n    // Note:\n    //  The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum\n    //  as kind of implementation hack, they are *NOT* real opcodes.  If found in real\n    //  Script, just let the default: case deal with them.\n    case OP_SMALLINTEGER: case OP_PUBKEYS: case OP_PUBKEYHASH:\n\n    default:\n        return \"OP_UNKNOWN\";\n    }\n}\n\nunsigned int CScript::GetSigOpCount(bool fAccurate) const\n{\n    unsigned int n = 0;\n    const_iterator pc = begin();\n    opcodetype lastOpcode = OP_INVALIDOPCODE;\n    while (pc < end())\n    {\n        opcodetype opcode;\n        if (!GetOp(pc, opcode))\n            break;\n        if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)\n            n++;\n        else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)\n        {\n            if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)\n                n += DecodeOP_N(lastOpcode);\n            else\n                n += MAX_PUBKEYS_PER_MULTISIG;\n        }\n        lastOpcode = opcode;\n    }\n    return n;\n}\n\nunsigned int CScript::GetSigOpCount(const CScript& scriptSig) const\n{\n    if (!IsPayToScriptHash())\n        return GetSigOpCount(true);\n\n    // This is a pay-to-script-hash scriptPubKey;\n    // get the last item that the scriptSig\n    // pushes onto the stack:\n    const_iterator pc = scriptSig.begin();\n    std::vector<unsigned char> vData;\n    while (pc < scriptSig.end())\n    {\n        opcodetype opcode;\n        if (!scriptSig.GetOp(pc, opcode, vData))\n            return 0;\n        if (opcode > OP_16)\n            return 0;\n    }\n\n    /// ... and return its opcount:\n    CScript subscript(vData.begin(), vData.end());\n    return subscript.GetSigOpCount(true);\n}\n\nbool CScript::IsPayToPubkeyHash(CKeyID &hash) const\n{\n    if (this->size() == 25 && (*this)[0] == OP_DUP && (*this)[1] == OP_HASH160\n        && (*this)[2] == 20 && (*this)[23] == OP_EQUALVERIFY\n        && (*this)[24] == OP_CHECKSIG) {\n        memcpy(hash.begin(), &(*this)[3], 20);\n        return true;\n    }\n    return false;\n}\n\nbool CScript::IsPayToScriptHash() const\n{\n    // Extra-fast test for pay-to-script-hash CScripts:\n    return (this->size() == 23 &&\n            (*this)[0] == OP_HASH160 &&\n            (*this)[1] == 0x14 &&\n            (*this)[22] == OP_EQUAL);\n}\n\n//OP_0 [1 byte] 72 [1 byte] hash [20 byte] hash [20 byte] uint64_t [8 byte] uint64_t [8 byte] uint64_t [8 byte] uint64_t [8 byte] (74 bytes)\nbool CScript::ExtractPoW2WitnessFromScript(CTxOutPoW2Witness& witness) const\n{\n    if (this->size() != 74)\n    {\n        return false;\n    }\n\n    CScript::const_iterator it = begin();\n\n    opcodetype opcode;\n    std::vector<unsigned char> item;\n    if (!GetOp(it, opcode, item) || opcode != OP_0)\n    {\n        return false;\n    }\n\n    if (!GetOp(it, opcode, item) || opcode != (unsigned char)72)\n    {\n        return false;\n    }\n\n    std::vector<unsigned char> vchSpendingKey( begin()+2, begin()+22 );\n    witness.spendingKeyID = CKeyID(uint160(vchSpendingKey));\n\n    std::vector<unsigned char> vchWitnessKey( begin()+22, begin()+42 );\n    witness.witnessKeyID = CKeyID(uint160(vchWitnessKey));\n\n    std::vector<unsigned char> vchLockFromBlock( begin()+42, begin()+50 );\n    witness.lockFromBlock = CScriptUInt64( vchLockFromBlock ).nNumber;\n\n    std::vector<unsigned char> vchLockUntilBlock( begin()+50, begin()+58 );\n    witness.lockUntilBlock = CScriptUInt64( vchLockUntilBlock ).nNumber;\n\n    std::vector<unsigned char> vchFailCount( begin()+58, begin()+66 );\n    witness.failCount = CScriptUInt64( vchFailCount ).nNumber;\n\n    std::vector<unsigned char> vchActionNonce( begin()+66, begin()+74 );\n    witness.actionNonce = CScriptUInt64( vchActionNonce ).nNumber;\n\n    return true;\n}\n\n\nbool CScript::IsPushOnly(const_iterator pc) const\n{\n    while (pc < end())\n    {\n        opcodetype opcode;\n        if (!GetOp(pc, opcode))\n            return false;\n        // Note that IsPushOnly() *does* consider OP_RESERVED to be a\n        // push-type opcode, however execution of OP_RESERVED fails, so\n        // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to\n        // the P2SH special validation code being executed.\n        if (opcode > OP_16)\n            return false;\n    }\n    return true;\n}\n\nbool CScript::IsPushOnly() const\n{\n    return this->IsPushOnly(begin());\n}\n\nstd::string CSegregatedSignatureData::ToString() const\n{\n    std::string ret = \"CSegregatedSignatureData(\";\n    for (unsigned int i = 0; i < stack.size(); i++) {\n        if (i) {\n            ret += \", \";\n        }\n        ret += HexStr(stack[i]);\n    }\n    return ret + \")\";\n}\n\nbool CScript::HasValidOps() const\n{\n    CScript::const_iterator it = begin();\n    while (it < end()) {\n        opcodetype opcode;\n        std::vector<unsigned char> item;\n        if (!GetOp(it, opcode, item) || opcode > MAX_OPCODE || item.size() > MAX_SCRIPT_ELEMENT_SIZE) {\n            return false;\n        }\n    }\n    return true;\n}\n"
  },
  {
    "path": "src/script/script.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_SCRIPT_H\n#define SCRIPT_SCRIPT_H\n\n#include \"crypto/common.h\"\n#include \"prevector.h\"\n\n#include <assert.h>\n#include <climits>\n#include <limits>\n#include <stdexcept>\n#include <stdint.h>\n#include <string.h>\n#include <string>\n#include <vector>\n\n//Munt\nclass CTxOutPoW2Witness;\nclass CKeyID;\n\n// Maximum number of bytes pushable to the stack\nstatic const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;\n\n// Maximum number of non-push operations per script\nstatic const int MAX_OPS_PER_SCRIPT = 201;\n\n// Maximum number of public keys per multisig\nstatic const int MAX_PUBKEYS_PER_MULTISIG = 20;\n\n// Maximum script length in bytes\nstatic const int MAX_SCRIPT_SIZE = 10000;\n\n// Maximum number of values on script interpreter stack\nstatic const int MAX_STACK_SIZE = 1000;\n\n// Threshold for nLockTime: below this value it is interpreted as block number,\n// otherwise as UNIX timestamp.\nstatic const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov  5 00:53:20 1985 UTC\n\ntemplate <typename T>\nstd::vector<unsigned char> ToByteVector(const T& in)\n{\n    return std::vector<unsigned char>(in.begin(), in.end());\n}\n\n/** Script opcodes */\nenum opcodetype\n{\n    // push value\n    OP_0 = 0x00,\n    OP_FALSE = OP_0,\n    OP_PUSHDATA1 = 0x4c,\n    OP_PUSHDATA2 = 0x4d,\n    OP_PUSHDATA4 = 0x4e,\n    OP_1NEGATE = 0x4f,\n    OP_RESERVED = 0x50,\n    OP_1 = 0x51,\n    OP_TRUE=OP_1,\n    OP_2 = 0x52,\n    OP_3 = 0x53,\n    OP_4 = 0x54,\n    OP_5 = 0x55,\n    OP_6 = 0x56,\n    OP_7 = 0x57,\n    OP_8 = 0x58,\n    OP_9 = 0x59,\n    OP_10 = 0x5a,\n    OP_11 = 0x5b,\n    OP_12 = 0x5c,\n    OP_13 = 0x5d,\n    OP_14 = 0x5e,\n    OP_15 = 0x5f,\n    OP_16 = 0x60,\n\n    // control\n    OP_NOP = 0x61,\n    OP_VER = 0x62,\n    OP_IF = 0x63,\n    OP_NOTIF = 0x64,\n    OP_VERIF = 0x65,\n    OP_VERNOTIF = 0x66,\n    OP_ELSE = 0x67,\n    OP_ENDIF = 0x68,\n    OP_VERIFY = 0x69,\n    OP_RETURN = 0x6a,\n\n    // stack ops\n    OP_TOALTSTACK = 0x6b,\n    OP_FROMALTSTACK = 0x6c,\n    OP_2DROP = 0x6d,\n    OP_2DUP = 0x6e,\n    OP_3DUP = 0x6f,\n    OP_2OVER = 0x70,\n    OP_2ROT = 0x71,\n    OP_2SWAP = 0x72,\n    OP_IFDUP = 0x73,\n    OP_DEPTH = 0x74,\n    OP_DROP = 0x75,\n    OP_DUP = 0x76,\n    OP_NIP = 0x77,\n    OP_OVER = 0x78,\n    OP_PICK = 0x79,\n    OP_ROLL = 0x7a,\n    OP_ROT = 0x7b,\n    OP_SWAP = 0x7c,\n    OP_TUCK = 0x7d,\n\n    // splice ops\n    OP_CAT = 0x7e,\n    OP_SUBSTR = 0x7f,\n    OP_LEFT = 0x80,\n    OP_RIGHT = 0x81,\n    OP_SIZE = 0x82,\n\n    // bit logic\n    OP_INVERT = 0x83,\n    OP_AND = 0x84,\n    OP_OR = 0x85,\n    OP_XOR = 0x86,\n    OP_EQUAL = 0x87,\n    OP_EQUALVERIFY = 0x88,\n    OP_RESERVED1 = 0x89,\n    OP_RESERVED2 = 0x8a,\n\n    // numeric\n    OP_1ADD = 0x8b,\n    OP_1SUB = 0x8c,\n    OP_2MUL = 0x8d,\n    OP_2DIV = 0x8e,\n    OP_NEGATE = 0x8f,\n    OP_ABS = 0x90,\n    OP_NOT = 0x91,\n    OP_0NOTEQUAL = 0x92,\n\n    OP_ADD = 0x93,\n    OP_SUB = 0x94,\n    OP_MUL = 0x95,\n    OP_DIV = 0x96,\n    OP_MOD = 0x97,\n    OP_LSHIFT = 0x98,\n    OP_RSHIFT = 0x99,\n\n    OP_BOOLAND = 0x9a,\n    OP_BOOLOR = 0x9b,\n    OP_NUMEQUAL = 0x9c,\n    OP_NUMEQUALVERIFY = 0x9d,\n    OP_NUMNOTEQUAL = 0x9e,\n    OP_LESSTHAN = 0x9f,\n    OP_GREATERTHAN = 0xa0,\n    OP_LESSTHANOREQUAL = 0xa1,\n    OP_GREATERTHANOREQUAL = 0xa2,\n    OP_MIN = 0xa3,\n    OP_MAX = 0xa4,\n\n    OP_WITHIN = 0xa5,\n\n    // crypto\n    OP_RIPEMD160 = 0xa6,\n    OP_SHA1 = 0xa7,\n    OP_SHA256 = 0xa8,\n    OP_HASH160 = 0xa9,\n    OP_HASH256 = 0xaa,\n    OP_CODESEPARATOR = 0xab,\n    OP_CHECKSIG = 0xac,\n    OP_CHECKSIGVERIFY = 0xad,\n    OP_CHECKMULTISIG = 0xae,\n    OP_CHECKMULTISIGVERIFY = 0xaf,\n\n    // expansion\n    OP_NOP1 = 0xb0,\n    OP_CHECKLOCKTIMEVERIFY = 0xb1,\n    OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,\n    OP_CHECKSEQUENCEVERIFY = 0xb2,\n    OP_NOP3 = OP_CHECKSEQUENCEVERIFY,\n    OP_NOP4 = 0xb3,\n    OP_NOP5 = 0xb4,\n    OP_NOP6 = 0xb5,\n    OP_NOP7 = 0xb6,\n    OP_NOP8 = 0xb7,\n    OP_NOP9 = 0xb8,\n    OP_NOP10 = 0xb9,\n\n\n    // template matching params\n    OP_SMALLINTEGER = 0xfa,\n    OP_PUBKEYS = 0xfb,\n    OP_PUBKEYHASH = 0xfd,\n    OP_PUBKEY = 0xfe,\n\n    OP_INVALIDOPCODE = 0xff,\n};\n\n// Maximum value that an opcode can be\nstatic const unsigned int MAX_OPCODE = OP_NOP10;\n\nconst char* GetOpName(opcodetype opcode);\n\nclass scriptnum_error : public std::runtime_error\n{\npublic:\n    explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}\n};\n\n//fixme: (PHASE5) We can remove this class\nclass CScriptUInt64\n{\n    public:\n        CScriptUInt64(uint64_t nNumber_)\n        {\n            nNumber = nNumber_;\n\n            vchNumber.resize(8);\n            for (auto iter = vchNumber.begin(); iter != vchNumber.end(); ++iter)\n            {\n                *iter = (nNumber_ & 0xff);\n                nNumber_ >>= 8;\n            }\n        }\n        CScriptUInt64(std::vector<unsigned char> vchNumber_)\n        {\n            assert(vchNumber_.size() == 8);\n            nNumber = 0;\n\n            for (unsigned int idx = 0; idx < vchNumber_.size(); ++idx)\n            {\n                nNumber |= ((uint64_t)(vchNumber_[idx]) << 8*idx);\n            }\n        }\n\n        std::vector<unsigned char> vchNumber;\n        uint64_t nNumber;\n};\n\nclass CScriptNum\n{\n/**\n * Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.\n * The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],\n * but results may overflow (and are valid as long as they are not used in a subsequent\n * numeric operation). CScriptNum enforces those semantics by storing results as\n * an int64 and allowing out-of-range values to be returned as a vector of bytes but\n * throwing an exception if arithmetic is done or the result is interpreted as an integer.\n */\npublic:\n\n    explicit CScriptNum(const int64_t& n)\n    {\n        m_value = n;\n    }\n\n    static const size_t nDefaultMaxNumSize = 4;\n\n    explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal,\n                        const size_t nMaxNumSize = nDefaultMaxNumSize)\n    {\n        if (vch.size() > nMaxNumSize) {\n            throw scriptnum_error(\"script number overflow\");\n        }\n        if (fRequireMinimal && vch.size() > 0) {\n            // Check that the number is encoded with the minimum possible\n            // number of bytes.\n            //\n            // If the most-significant-byte - excluding the sign bit - is zero\n            // then we're not minimal. Note how this test also rejects the\n            // negative-zero encoding, 0x80.\n            if ((vch.back() & 0x7f) == 0) {\n                // One exception: if there's more than one byte and the most\n                // significant bit of the second-most-significant-byte is set\n                // it would conflict with the sign bit. An example of this case\n                // is +-255, which encode to 0xff00 and 0xff80 respectively.\n                // (big-endian).\n                if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {\n                    throw scriptnum_error(\"non-minimally encoded script number\");\n                }\n            }\n        }\n        m_value = set_vch(vch);\n    }\n\n    inline bool operator==(const int64_t& rhs) const    { return m_value == rhs; }\n    inline bool operator!=(const int64_t& rhs) const    { return m_value != rhs; }\n    inline bool operator<=(const int64_t& rhs) const    { return m_value <= rhs; }\n    inline bool operator< (const int64_t& rhs) const    { return m_value <  rhs; }\n    inline bool operator>=(const int64_t& rhs) const    { return m_value >= rhs; }\n    inline bool operator> (const int64_t& rhs) const    { return m_value >  rhs; }\n\n    inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }\n    inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }\n    inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }\n    inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }\n    inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }\n    inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }\n\n    inline CScriptNum operator+(   const int64_t& rhs)    const { return CScriptNum(m_value + rhs);}\n    inline CScriptNum operator-(   const int64_t& rhs)    const { return CScriptNum(m_value - rhs);}\n    inline CScriptNum operator+(   const CScriptNum& rhs) const { return operator+(rhs.m_value);   }\n    inline CScriptNum operator-(   const CScriptNum& rhs) const { return operator-(rhs.m_value);   }\n\n    inline CScriptNum& operator+=( const CScriptNum& rhs)       { return operator+=(rhs.m_value);  }\n    inline CScriptNum& operator-=( const CScriptNum& rhs)       { return operator-=(rhs.m_value);  }\n\n    inline CScriptNum operator&(   const int64_t& rhs)    const { return CScriptNum(m_value & rhs);}\n    inline CScriptNum operator&(   const CScriptNum& rhs) const { return operator&(rhs.m_value);   }\n\n    inline CScriptNum& operator&=( const CScriptNum& rhs)       { return operator&=(rhs.m_value);  }\n\n    inline CScriptNum operator-()                         const\n    {\n        assert(m_value != std::numeric_limits<int64_t>::min());\n        return CScriptNum(-m_value);\n    }\n\n    inline CScriptNum& operator=( const int64_t& rhs)\n    {\n        m_value = rhs;\n        return *this;\n    }\n\n    inline CScriptNum& operator+=( const int64_t& rhs)\n    {\n        assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||\n                           (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));\n        m_value += rhs;\n        return *this;\n    }\n\n    inline CScriptNum& operator-=( const int64_t& rhs)\n    {\n        assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||\n                           (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));\n        m_value -= rhs;\n        return *this;\n    }\n\n    inline CScriptNum& operator&=( const int64_t& rhs)\n    {\n        m_value &= rhs;\n        return *this;\n    }\n\n    int getint() const\n    {\n        if (m_value > std::numeric_limits<int>::max())\n            return std::numeric_limits<int>::max();\n        else if (m_value < std::numeric_limits<int>::min())\n            return std::numeric_limits<int>::min();\n        return m_value;\n    }\n\n    std::vector<unsigned char> getvch() const\n    {\n        return serialize(m_value);\n    }\n\n    static std::vector<unsigned char> serialize(const int64_t& value)\n    {\n        if(value == 0)\n            return std::vector<unsigned char>();\n\n        std::vector<unsigned char> result;\n        const bool neg = value < 0;\n        uint64_t absvalue = neg ? -value : value;\n\n        while(absvalue)\n        {\n            result.push_back(absvalue & 0xff);\n            absvalue >>= 8;\n        }\n\n//    - If the most significant byte is >= 0x80 and the value is positive, push a\n//    new zero-byte to make the significant byte < 0x80 again.\n\n//    - If the most significant byte is >= 0x80 and the value is negative, push a\n//    new 0x80 byte that will be popped off when converting to an integral.\n\n//    - If the most significant byte is < 0x80 and the value is negative, add\n//    0x80 to it, since it will be subtracted and interpreted as a negative when\n//    converting to an integral.\n\n        if (result.back() & 0x80)\n            result.push_back(neg ? 0x80 : 0);\n        else if (neg)\n            result.back() |= 0x80;\n\n        return result;\n    }\n\nprivate:\n    static int64_t set_vch(const std::vector<unsigned char>& vch)\n    {\n      if (vch.empty())\n          return 0;\n\n      int64_t result = 0;\n      for (size_t i = 0; i != vch.size(); ++i)\n          result |= static_cast<int64_t>(vch[i]) << 8*i;\n\n      // If the input vector's most significant byte is 0x80, remove it from\n      // the result's msb and return a negative.\n      if (vch.back() & 0x80)\n          return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));\n\n      return result;\n    }\n\n    int64_t m_value;\n};\n\ntypedef prevector<28, unsigned char> CScriptBase;\n\n/** Serialized script, used inside transaction inputs and outputs */\nclass CScript : public CScriptBase\n{\nprotected:\n    CScript& push_int64(int64_t n)\n    {\n        if (n == -1 || (n >= 1 && n <= 16))\n        {\n            push_back(n + (OP_1 - 1));\n        }\n        else if (n == 0)\n        {\n            push_back(OP_0);\n        }\n        else\n        {\n            *this << CScriptNum::serialize(n);\n        }\n        return *this;\n    }\npublic:\n    CScript() { }\n    CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { }\n    CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { }\n    CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { }\n\n    CScript& operator+=(const CScript& b)\n    {\n        insert(end(), b.begin(), b.end());\n        return *this;\n    }\n\n    friend CScript operator+(const CScript& a, const CScript& b)\n    {\n        CScript ret = a;\n        ret += b;\n        return ret;\n    }\n\n    CScript(int64_t b)        { operator<<(b); }\n\n    explicit CScript(opcodetype b)     { operator<<(b); }\n    explicit CScript(const CScriptNum& b) { operator<<(b); }\n    explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }\n\n\n    CScript& operator<<(int64_t b) { return push_int64(b); }\n\n    CScript& operator<<(opcodetype opcode)\n    {\n        if (opcode < 0 || opcode > 0xff)\n            throw std::runtime_error(\"CScript::operator<<(): invalid opcode\");\n        insert(end(), (unsigned char)opcode);\n        return *this;\n    }\n\n    CScript& operator<<(const CScriptNum& b)\n    {\n        *this << b.getvch();\n        return *this;\n    }\n\n    CScript& operator<<(const std::vector<unsigned char>& b)\n    {\n        if (b.size() < OP_PUSHDATA1)\n        {\n            insert(end(), (unsigned char)b.size());\n        }\n        else if (b.size() <= 0xff)\n        {\n            insert(end(), OP_PUSHDATA1);\n            insert(end(), (unsigned char)b.size());\n        }\n        else if (b.size() <= 0xffff)\n        {\n            insert(end(), OP_PUSHDATA2);\n            uint8_t _data[2];\n            WriteLE16(_data, b.size());\n            insert(end(), _data, _data + sizeof(_data));\n        }\n        else\n        {\n            insert(end(), OP_PUSHDATA4);\n            uint8_t _data[4];\n            WriteLE32(_data, b.size());\n            insert(end(), _data, _data + sizeof(_data));\n        }\n        insert(end(), b.begin(), b.end());\n        return *this;\n    }\n\n    CScript& operator<<([[maybe_unused]]const CScript& b)\n    {\n        // I'm not sure if this should push the script or concatenate scripts.\n        // If there's ever a use for pushing a script onto a script, delete this member fn\n        assert(!\"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!\");\n        return *this;\n    }\n\n    CScript& operator<<(const CScriptUInt64& b)\n    {\n        insert(end(), b.vchNumber.begin(), b.vchNumber.end());\n        return *this;\n    }\n\n\n    bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)\n    {\n         // Wrapper so it can be called with either iterator or const_iterator\n         const_iterator pc2 = pc;\n         bool fRet = GetOp2(pc2, opcodeRet, &vchRet);\n         pc = begin() + (pc2 - begin());\n         return fRet;\n    }\n\n    bool GetOp(iterator& pc, opcodetype& opcodeRet)\n    {\n         const_iterator pc2 = pc;\n         bool fRet = GetOp2(pc2, opcodeRet, NULL);\n         pc = begin() + (pc2 - begin());\n         return fRet;\n    }\n\n    bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const\n    {\n        return GetOp2(pc, opcodeRet, &vchRet);\n    }\n\n    bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const\n    {\n        return GetOp2(pc, opcodeRet, NULL);\n    }\n\n    bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const\n    {\n        opcodeRet = OP_INVALIDOPCODE;\n        if (pvchRet)\n            pvchRet->clear();\n        if (pc >= end())\n            return false;\n\n        // Read instruction\n        if (end() - pc < 1)\n            return false;\n        unsigned int opcode = *pc++;\n\n        // Immediate operand\n        if (opcode <= OP_PUSHDATA4)\n        {\n            unsigned int nSize = 0;\n            if (opcode < OP_PUSHDATA1)\n            {\n                nSize = opcode;\n            }\n            else if (opcode == OP_PUSHDATA1)\n            {\n                if (end() - pc < 1)\n                    return false;\n                nSize = *pc++;\n            }\n            else if (opcode == OP_PUSHDATA2)\n            {\n                if (end() - pc < 2)\n                    return false;\n                nSize = ReadLE16(&pc[0]);\n                pc += 2;\n            }\n            else if (opcode == OP_PUSHDATA4)\n            {\n                if (end() - pc < 4)\n                    return false;\n                nSize = ReadLE32(&pc[0]);\n                pc += 4;\n            }\n            if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize)\n                return false;\n            if (pvchRet)\n                pvchRet->assign(pc, pc + nSize);\n            pc += nSize;\n        }\n\n        opcodeRet = (opcodetype)opcode;\n        return true;\n    }\n\n    /** Encode/decode small integers: */\n    static int DecodeOP_N(opcodetype opcode)\n    {\n        if (opcode == OP_0)\n            return 0;\n        assert(opcode >= OP_1 && opcode <= OP_16);\n        return (int)opcode - (int)(OP_1 - 1);\n    }\n    static opcodetype EncodeOP_N(int n)\n    {\n        assert(n >= 0 && n <= 16);\n        if (n == 0)\n            return OP_0;\n        return (opcodetype)(OP_1+n-1);\n    }\n\n    int FindAndDelete(const CScript& b)\n    {\n        int nFound = 0;\n        if (b.empty())\n            return nFound;\n        CScript result;\n        iterator pc = begin(), pc2 = begin();\n        opcodetype opcode;\n        do\n        {\n            result.insert(result.end(), pc2, pc);\n            while (static_cast<size_t>(end() - pc) >= b.size() && std::equal(b.begin(), b.end(), pc))\n            {\n                pc = pc + b.size();\n                ++nFound;\n            }\n            pc2 = pc;\n        }\n        while (GetOp(pc, opcode));\n\n        if (nFound > 0) {\n            result.insert(result.end(), pc2, end());\n            *this = result;\n        }\n\n        return nFound;\n    }\n    int Find(opcodetype op) const\n    {\n        int nFound = 0;\n        opcodetype opcode;\n        for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)\n            if (opcode == op)\n                ++nFound;\n        return nFound;\n    }\n\n    /**\n     * Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs\n     * as 20 sigops. With pay-to-script-hash, that changed:\n     * CHECKMULTISIGs serialized in scriptSigs are\n     * counted more accurately, assuming they are of the form\n     *  ... OP_N CHECKMULTISIG ...\n     */\n    unsigned int GetSigOpCount(bool fAccurate) const;\n\n    /**\n     * Accurately count sigOps, including sigOps in\n     * pay-to-script-hash transactions:\n     */\n    unsigned int GetSigOpCount(const CScript& scriptSig) const;\n\n    bool IsPayToPubkeyHash(CKeyID &hash) const;\n    bool IsPayToScriptHash() const;\n\n    bool ExtractPoW2WitnessFromScript(CTxOutPoW2Witness& witness) const;\n\n    /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */\n    bool IsPushOnly(const_iterator pc) const;\n    bool IsPushOnly() const;\n\n    /** Check if the script contains valid OP_CODES */\n    bool HasValidOps() const;\n\n    /**\n     * Returns whether the script is guaranteed to fail at execution,\n     * regardless of the initial stack. This allows outputs to be pruned\n     * instantly when entering the UTXO set.\n     */\n    bool IsUnspendable() const\n    {\n        return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE);\n    }\n\n    void clear()\n    {\n        // The default std::vector::clear() does not release memory.\n        CScriptBase().swap(*this);\n    }\n};\n\nstruct CSegregatedSignatureData\n{\n    // Note that this encodes the data elements being pushed, rather than\n    // encoding them as a CScript that pushes them.\n    std::vector<std::vector<unsigned char> > stack;\n\n    // Some compilers complain without a default constructor\n    CSegregatedSignatureData() { }\n\n    bool IsNull() const { return stack.empty(); }\n\n    void SetNull() { stack.clear(); stack.shrink_to_fit(); }\n\n    std::string ToString() const;\n};\n\nclass CReserveScript\n{\npublic:\n    CScript reserveScript;\n    virtual void KeepScript() {}\n    virtual void keepScriptOnDestroy() {}\n    CReserveScript() {}\n    CReserveScript(CScript& reserveScript_) {reserveScript = reserveScript_;}\n    virtual ~CReserveScript() {}\n};\n\n#endif\n"
  },
  {
    "path": "src/script/script_error.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"script_error.h\"\n\nconst char* ScriptErrorString(const ScriptError serror)\n{\n    switch (serror)\n    {\n        case SCRIPT_ERR_OK:\n            return \"No error\";\n        case SCRIPT_ERR_EVAL_FALSE:\n            return \"Script evaluated without error but finished with a false/empty top stack element\";\n        case SCRIPT_ERR_VERIFY:\n            return \"Script failed an OP_VERIFY operation\";\n        case SCRIPT_ERR_EQUALVERIFY:\n            return \"Script failed an OP_EQUALVERIFY operation\";\n        case SCRIPT_ERR_CHECKMULTISIGVERIFY:\n            return \"Script failed an OP_CHECKMULTISIGVERIFY operation\";\n        case SCRIPT_ERR_CHECKSIGVERIFY:\n            return \"Script failed an OP_CHECKSIGVERIFY operation\";\n        case SCRIPT_ERR_NUMEQUALVERIFY:\n            return \"Script failed an OP_NUMEQUALVERIFY operation\";\n        case SCRIPT_ERR_SCRIPT_SIZE:\n            return \"Script is too big\";\n        case SCRIPT_ERR_PUSH_SIZE:\n            return \"Push value size limit exceeded\";\n        case SCRIPT_ERR_OP_COUNT:\n            return \"Operation limit exceeded\";\n        case SCRIPT_ERR_STACK_SIZE:\n            return \"Stack size limit exceeded\";\n        case SCRIPT_ERR_SIG_COUNT:\n            return \"Signature count negative or greater than pubkey count\";\n        case SCRIPT_ERR_PUBKEY_COUNT:\n            return \"Pubkey count negative or limit exceeded\";\n        case SCRIPT_ERR_BAD_OPCODE:\n            return \"Opcode missing or not understood\";\n        case SCRIPT_ERR_DISABLED_OPCODE:\n            return \"Attempted to use a disabled opcode\";\n        case SCRIPT_ERR_INVALID_STACK_OPERATION:\n            return \"Operation not valid with the current stack size\";\n        case SCRIPT_ERR_INVALID_ALTSTACK_OPERATION:\n            return \"Operation not valid with the current altstack size\";\n        case SCRIPT_ERR_OP_RETURN:\n            return \"OP_RETURN was encountered\";\n        case SCRIPT_ERR_UNBALANCED_CONDITIONAL:\n            return \"Invalid OP_IF construction\";\n        case SCRIPT_ERR_NEGATIVE_LOCKTIME:\n            return \"Negative locktime\";\n        case SCRIPT_ERR_UNSATISFIED_LOCKTIME:\n            return \"Locktime requirement not satisfied\";\n        case SCRIPT_ERR_SIG_HASHTYPE:\n            return \"Signature hash type missing or not understood\";\n        case SCRIPT_ERR_SIG_DER:\n            return \"Non-canonical DER signature\";\n        case SCRIPT_ERR_MINIMALDATA:\n            return \"Data push larger than necessary\";\n        case SCRIPT_ERR_SIG_PUSHONLY:\n            return \"Only non-push operators allowed in signatures\";\n        case SCRIPT_ERR_SIG_HIGH_S:\n            return \"Non-canonical signature: S value is unnecessarily high\";\n        case SCRIPT_ERR_MINIMALIF:\n            return \"OP_IF/NOTIF argument must be minimal\";\n        case SCRIPT_ERR_SIG_NULLFAIL:\n            return \"Signature must be zero for failed CHECK(MULTI)SIG operation\";\n        case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS:\n            return \"NOPx reserved for soft-fork upgrades\";\n        case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM:\n            return \"Witness version reserved for soft-fork upgrades\";\n        case SCRIPT_ERR_PUBKEYTYPE:\n            return \"Public key is neither compressed or uncompressed\";\n        case SCRIPT_ERR_SEGSIG_PUBKEYTYPE:\n            return \"Using non-compressed keys in segsig\";\n        case SCRIPT_ERR_CLEANSTACK:\n        case SCRIPT_ERR_UNKNOWN_ERROR:\n        case SCRIPT_ERR_ERROR_COUNT:\n        default: break;\n    }\n    return \"unknown error\";\n}\n"
  },
  {
    "path": "src/script/script_error.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SCRIPT_SCRIPT_ERROR_H\n#define SCRIPT_SCRIPT_ERROR_H\n\ntypedef enum ScriptError_t\n{\n    SCRIPT_ERR_OK = 0,\n    SCRIPT_ERR_UNKNOWN_ERROR,\n    SCRIPT_ERR_EVAL_FALSE,\n    SCRIPT_ERR_OP_RETURN,\n\n    /* Max sizes */\n    SCRIPT_ERR_SCRIPT_SIZE,\n    SCRIPT_ERR_PUSH_SIZE,\n    SCRIPT_ERR_OP_COUNT,\n    SCRIPT_ERR_STACK_SIZE,\n    SCRIPT_ERR_SIG_COUNT,\n    SCRIPT_ERR_PUBKEY_COUNT,\n\n    /* Failed verify operations */\n    SCRIPT_ERR_VERIFY,\n    SCRIPT_ERR_EQUALVERIFY,\n    SCRIPT_ERR_CHECKMULTISIGVERIFY,\n    SCRIPT_ERR_CHECKSIGVERIFY,\n    SCRIPT_ERR_NUMEQUALVERIFY,\n\n    /* Logical/Format/Canonical errors */\n    SCRIPT_ERR_BAD_OPCODE,\n    SCRIPT_ERR_DISABLED_OPCODE,\n    SCRIPT_ERR_INVALID_STACK_OPERATION,\n    SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,\n    SCRIPT_ERR_UNBALANCED_CONDITIONAL,\n\n    /* CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY */\n    SCRIPT_ERR_NEGATIVE_LOCKTIME,\n    SCRIPT_ERR_UNSATISFIED_LOCKTIME,\n\n    /* Malleability */\n    SCRIPT_ERR_SIG_HASHTYPE,\n    SCRIPT_ERR_SIG_DER,\n    SCRIPT_ERR_MINIMALDATA,\n    SCRIPT_ERR_SIG_PUSHONLY,\n    SCRIPT_ERR_SIG_HIGH_S,\n    SCRIPT_ERR_PUBKEYTYPE,\n    SCRIPT_ERR_CLEANSTACK,\n    SCRIPT_ERR_MINIMALIF,\n    SCRIPT_ERR_SIG_NULLFAIL,\n\n    /* softfork safeness */\n    SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,\n    SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,\n\n    /* segregated witness */\n    SCRIPT_ERR_SEGSIG_PUBKEYTYPE,\n\n    SCRIPT_ERR_ERROR_COUNT\n} ScriptError;\n\n#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT\n\nconst char* ScriptErrorString(const ScriptError error);\n\n#endif\n"
  },
  {
    "path": "src/script/sigcache.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"sigcache.h\"\n\n#include \"memusage.h\"\n#include \"pubkey.h\"\n#include \"random.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n\n#include \"cuckoocache.h\"\n#include <boost/thread.hpp>\n\nnamespace {\n/**\n * Valid signature cache, to avoid doing expensive ECDSA signature checking\n * twice for every transaction (once when accepted into memory pool, and\n * again when accepted into the block chain)\n */\nclass CSignatureCache\n{\nprivate:\n     //! Entries are SHA256(nonce || signature hash || public key || signature):\n    uint256 nonce;\n    typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;\n    map_type setValid;\n    boost::shared_mutex cs_sigcache;\n\npublic:\n    CSignatureCache()\n    {\n        GetRandBytes(nonce.begin(), 32);\n    }\n\n    void\n    ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)\n    {\n        CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());\n    }\n\n    bool\n    Get(const uint256& entry, const bool erase)\n    {\n        boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);\n        return setValid.contains(entry, erase);\n    }\n\n    void Set(uint256& entry)\n    {\n        boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);\n        setValid.insert(entry);\n    }\n    uint32_t setup_bytes(size_t n)\n    {\n        return setValid.setup_bytes(n);\n    }\n};\n\n/* In previous versions of this code, signatureCache was a local static variable\n * in CachingTransactionSignatureChecker::VerifySignature.  We initialize\n * signatureCache outside of VerifySignature to avoid the atomic operation per\n * call overhead associated with local static variables even though\n * signatureCache could be made local to VerifySignature.\n*/\nstatic CSignatureCache signatureCache;\n}\n\n// To be called once in AppInitMain/BasicTestingSetup to initialize the\n// signatureCache.\nvoid InitSignatureCache()\n{\n    // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,\n    // setup_bytes creates the minimum possible cache (2 elements).\n    size_t nMaxCacheSize = std::min(std::max((int64_t)0, GetArg(\"-maxsigcachesize\", DEFAULT_MAX_SIG_CACHE_SIZE)), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);\n    size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);\n    LogPrintf(\"Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\\n\",\n            (nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems);\n}\n\nbool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const\n{\n    uint256 entry;\n    signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey);\n    if (signatureCache.Get(entry, !store))\n        return true;\n    if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))\n        return false;\n    if (store)\n        signatureCache.Set(entry);\n    return true;\n}\n"
  },
  {
    "path": "src/script/sigcache.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_SIGCACHE_H\n#define SCRIPT_SIGCACHE_H\n\n#include \"script/interpreter.h\"\n\n#include <vector>\n\n// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit\n// systems). Due to how we count cache size, actual memory usage is slightly\n// more (~32.25 MB)\nstatic const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;\n// Maximum sig cache size allowed\nstatic const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;\n\nclass CPubKey;\n\n/**\n * We're hashing a nonce into the entries themselves, so we don't need extra\n * blinding in the set hash computation.\n *\n * This may exhibit platform endian dependent behavior but because these are\n * nonced hashes (random) and this state is only ever used locally it is safe.\n * All that matters is local consistency.\n */\nclass SignatureCacheHasher\n{\npublic:\n    template <uint8_t hash_select>\n    uint32_t operator()(const uint256& key) const\n    {\n        static_assert(hash_select <8, \"SignatureCacheHasher only has 8 hashes available.\");\n        uint32_t u;\n        std::memcpy(&u, key.begin()+4*hash_select, 4);\n        return u;\n    }\n};\n\nclass CachingTransactionSignatureChecker : public TransactionSignatureChecker\n{\nprivate:\n    bool store;\n\npublic:\n    CachingTransactionSignatureChecker(CKeyID signingKeyID, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(signingKeyID, spendingKeyID, txToIn, nInIn, amountIn, txdataIn), store(storeIn) {}\n\n    bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;\n};\n\nvoid InitSignatureCache();\n\n#endif\n"
  },
  {
    "path": "src/script/sign.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"script/sign.h\"\n\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"policy/policy.h\"\n#include \"primitives/transaction.h\"\n#include \"script/standard.h\"\n#include \"uint256.h\"\n#include \"validation/validation.h\"\n\n\n\ntypedef std::vector<unsigned char> valtype;\n\nTransactionSignatureCreator::TransactionSignatureCreator(CKeyID signingKeyID, const std::vector<CKeyStore*>& accountsToTryIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(accountsToTryIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(signingKeyID, CKeyID(), txTo, nIn, amountIn) {}\n\nbool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const\n{\n    CKey key;\n    bool gotKey = false;\n    for (const auto& forAccount : accountsToTry)\n    {\n        if (forAccount->GetKey(address, key))\n        {\n            gotKey = true;\n            break;\n        }\n    }\n    if (!gotKey)\n    {\n        LogPrintf(\"Error: TransactionSignatureCreator::CreateSig failed-no-key [accountsToTry.size()==%d]\\n\", accountsToTry.size());\n        return false;\n    }\n\n\n    uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);\n    if (sigversion == SIGVERSION_SEGSIG)\n    {\n        //fixme: (PHASE5) (SEGSIG) Lots of unit tests for this. (test also old style transactions)\n        if (!key.SignCompact(hash, vchSig))\n        {\n            LogPrintf(\"Error: TransactionSignatureCreator::CreateSig: failed-sign-compact\\n\");\n            return false;\n        }\n    }\n    else\n    {\n        if (!key.Sign(hash, vchSig))\n            return false;\n    }\n    vchSig.push_back((unsigned char)nHashType);\n    return true;\n}\n\nstatic bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)\n{\n    std::vector<unsigned char> vchSig;\n    if (!creator.CreateSig(vchSig, address, scriptCode, sigversion))\n        return false;\n    ret.push_back(vchSig);\n    return true;\n}\n\nstatic bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)\n{\n    int nSigned = 0;\n    int nRequired = multisigdata.front()[0];\n    for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)\n    {\n        const valtype& pubkey = multisigdata[i];\n        CKeyID keyID = CPubKey(pubkey).GetID();\n        if (Sign1(keyID, creator, scriptCode, ret, sigversion))\n            ++nSigned;\n    }\n    return nSigned==nRequired;\n}\n\n/**\n * Sign scriptPubKey using signature made with creator.\n * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),\n * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.\n * Returns false if scriptPubKey could not be completely satisfied.\n */\nstatic bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,\n                     std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignType type)\n{\n    CScript scriptRet;\n    uint160 h160;\n    ret.clear();\n\n    std::vector<valtype> vSolutions;\n    if (!Solver(scriptPubKey, whichTypeRet, vSolutions))\n        return false;\n\n    CKeyID keyID;\n    switch (whichTypeRet)\n    {\n    case TX_NONSTANDARD:\n    case TX_NULL_DATA:\n        return false;\n    case TX_PUBKEY:\n        keyID = CPubKey(vSolutions[0]).GetID();\n        return Sign1(keyID, creator, scriptPubKey, ret, sigversion);\n    case TX_PUBKEYHASH:\n        keyID = CKeyID(uint160(vSolutions[0]));\n        if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion))\n            return false;\n        else\n        {\n            CPubKey vch;\n            for (const auto& forAccount : creator.accounts())\n            {\n                if (forAccount->GetPubKey(keyID, vch))\n                {\n                    ret.push_back(ToByteVector(vch));\n                    break;\n                }\n            }\n        }\n        return true;\n    case TX_SCRIPTHASH:\n        for (const auto& forAccount : creator.accounts())\n        {\n            if (forAccount->GetCScript(uint160(vSolutions[0]), scriptRet))\n            {\n                ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));\n                return true;\n            }\n        }\n        return false;\n\n    case TX_MULTISIG:\n        if (sigversion == SIGVERSION_BASE)\n        {\n            ret.push_back(valtype()); // workaround CHECKMULTISIG bug\n        }\n        return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));\n    case TX_STANDARD_WITNESS:\n    case TX_STANDARD_PUBKEY_HASH:\n        assert(0);\n        return false;\n        \n    default:\n        return false;\n    }\n}\n\nstatic bool SignStep(const BaseSignatureCreator& creator, const CTxOutPoW2Witness& pow2Witness, std::vector<valtype>& ret, SigVersion sigversion, SignType type)\n{\n    CScript scriptRet;\n    uint160 h160;\n    ret.clear();\n\n    //As we have no segregated signature data to sign we instead sign a standard placeholder.\n    //Note that the witness itself contains a nonce to avoid ever signing identical data\n    std::vector<unsigned char> sSignatureDataPlaceholder = {'p','o','w','2','w','i','t','n','e','s','s'};\n    CScript scriptSignatureDataPlaceholder(sSignatureDataPlaceholder.begin(), sSignatureDataPlaceholder.end());\n\n    switch(type)\n    {\n        case Spend:\n        {\n            if (!Sign1(pow2Witness.witnessKeyID, creator, scriptSignatureDataPlaceholder, ret, SIGVERSION_SEGSIG))\n                return false;\n            if (!Sign1(pow2Witness.spendingKeyID, creator, scriptSignatureDataPlaceholder, ret, SIGVERSION_SEGSIG))\n                return false;\n            return true;\n        }\n        case Witness:\n        {\n            if (!Sign1(pow2Witness.witnessKeyID, creator, scriptSignatureDataPlaceholder, ret, SIGVERSION_SEGSIG))\n                return false;\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic bool SignStep(const BaseSignatureCreator& creator, const CTxOutStandardKeyHash& standardKeyHash, std::vector<valtype>& ret, SigVersion sigversion, SignType type)\n{\n    CScript scriptRet;\n    uint160 h160;\n    ret.clear();\n\n    //As we have no segregated signature data to sign we instead sign a standard placeholder.\n    std::vector<unsigned char> sSignatureDataPlaceholder = {'k','e','y','h','a','s','h'};\n    CScript scriptSignatureDataPlaceholder(sSignatureDataPlaceholder.begin(), sSignatureDataPlaceholder.end());\n\n    if (!Sign1(standardKeyHash.keyID, creator, scriptSignatureDataPlaceholder, ret, SIGVERSION_SEGSIG))\n        return false;\n    return true;\n}\n\n//fixme: (PHASE5) de-dupe\nstatic CScript PushAll(const std::vector<valtype>& values)\n{\n    CScript result;\n    for(const valtype& v : values) {\n        if (v.size() == 0) {\n            result << OP_0;\n        } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {\n            result << CScript::EncodeOP_N(v[0]);\n        } else {\n            result << v;\n        }\n    }\n    return result;\n}\n\nclass CSigningKeysVisitor : public boost::static_visitor<void> {\npublic:\n    std::vector<CKeyID> vKeys;\n    SignType type;\n    CSigningKeysVisitor(SignType type_) : type(type_) {}\n\n    void Process(const CTxDestination& dest)\n    {\n        boost::apply_visitor(*this, dest);\n    }\n\n    void operator()(const CKeyID &keyId)\n    {\n        vKeys.push_back(keyId);\n    }\n\n    void operator()(const CScriptID &scriptId)\n    {\n        //fixme: (FUT) (WATCH_ONLY) (MED)\n    }\n\n    void operator()(const CPoW2WitnessDestination &dest) {\n        //fixme: (FUT) (Look into possibility of stacked signing.)\n        if (type == SignType::Witness)\n            vKeys.push_back(dest.witnessKey);\n        else if (type == SignType::Spend)\n            vKeys.push_back(dest.spendingKey);\n    }\n\n    void operator()(const CNoDestination &none) {}\n};\n\nCKeyID ExtractSigningPubkeyFromTxOutput(const CTxOut& txOut, SignType type)\n{\n    switch(txOut.GetType())\n    {\n        case ScriptLegacyOutput:\n        {\n            CTxDestination dest;\n            if (!ExtractDestination(txOut.output.scriptPubKey, dest))\n                return CKeyID();\n\n            CSigningKeysVisitor getSigningKeys(type);\n            getSigningKeys.Process(dest);\n            //NB! This looks weird, but with multisig we get the signatures later when evaluating the script, so actually this is correct.\n            if (getSigningKeys.vKeys.size() != 1)\n                return CKeyID();\n            return getSigningKeys.vKeys[0];\n        }\n        case PoW2WitnessOutput:\n        {\n            //fixme: (FUT) (Look into possibility of stacked signing.)\n            if (type == SignType::Spend)\n                return txOut.output.witnessDetails.spendingKeyID;\n            else if(type == SignType::Witness)\n                return txOut.output.witnessDetails.witnessKeyID;\n            return CKeyID();\n        }\n        case StandardKeyHashOutput:\n            return txOut.output.standardKeyHash.keyID;\n    }\n    return CKeyID();\n}\n\nbool ProduceSignature(const BaseSignatureCreator& creator, const CTxOut& fromOutput, SignatureData& sigdata, SignType type, uint64_t nVersion)\n{\n    SigVersion sigversion = IsOldTransactionVersion(nVersion) ? SIGVERSION_BASE : SIGVERSION_SEGSIG;\n    if (fromOutput.GetType() <= CTxOutType::ScriptLegacyOutput)\n    {\n        CScript script = fromOutput.output.scriptPubKey;\n        std::vector<valtype> result;\n        txnouttype whichType;\n        bool solved = SignStep(creator, script, result, whichType, sigversion, type);\n        CScript subscript;\n        sigdata.segregatedSignatureData.stack.clear();\n\n        if (solved && whichType == TX_SCRIPTHASH)\n        {\n            // Solver returns the subscript that needs to be evaluated;\n            // the final scriptSig is the signatures from that\n            // and then the serialized subscript:\n            script = subscript = CScript(result[0].begin(), result[0].end());\n            solved = solved && SignStep(creator, script, result, whichType, sigversion, type) && whichType != TX_SCRIPTHASH;\n            result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));\n        }\n        if (sigversion == SIGVERSION_BASE)\n        {\n            sigdata.scriptSig = PushAll(result);\n        }\n        else\n        {\n            sigdata.segregatedSignatureData.stack = result;\n        }\n        // Test solution\n        return solved;\n    }\n    else if (fromOutput.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        std::vector<valtype> result;\n        bool solved = SignStep(creator, fromOutput.output.witnessDetails, result, sigversion, type);\n        sigdata.segregatedSignatureData.stack = result;\n\n        return solved;\n    }\n    else if (fromOutput.GetType() == CTxOutType::StandardKeyHashOutput)\n    {\n        std::vector<valtype> result;\n        bool solved = SignStep(creator, fromOutput.output.standardKeyHash, result, sigversion, type);\n        sigdata.segregatedSignatureData.stack = result;\n\n        return solved;\n    }\n    else\n    {\n        assert(0);\n    }\n    return false;\n}\n\nSignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)\n{\n    SignatureData data;\n    assert(tx.vin.size() > nIn);\n    data.scriptSig = tx.vin[nIn].scriptSig;\n    data.segregatedSignatureData = tx.vin[nIn].segregatedSignatureData;\n    return data;\n}\n\nvoid UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)\n{\n    assert(tx.vin.size() > nIn);\n    tx.vin[nIn].scriptSig = data.scriptSig;\n    tx.vin[nIn].segregatedSignatureData = data.segregatedSignatureData;\n}\n\nbool SignSignature(const std::vector<CKeyStore*>& accountsToTry, const CTxOut& fromOutput, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignType type)\n{\n    assert(nIn < txTo.vin.size());\n\n    CTransaction txToConst(txTo);\n    CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(fromOutput, SignType::Spend);\n    TransactionSignatureCreator creator(signingKeyID, accountsToTry, &txToConst, nIn, amount, nHashType);\n\n    SignatureData sigdata;\n    bool ret = ProduceSignature(creator, fromOutput, sigdata, type, txToConst.nVersion);\n    UpdateTransaction(txTo, nIn, sigdata);\n    return ret;\n}\n\nbool SignSignature(const std::vector<CKeyStore*>& accountsToTry, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignType type)\n{\n    assert(nIn < txTo.vin.size());\n    CTxIn& txin = txTo.vin[nIn];\n    assert(txin.GetPrevOut().n < txFrom.vout.size());\n    const CTxOut& txout = txFrom.vout[txin.GetPrevOut().n];\n\n    return SignSignature(accountsToTry, txout, txTo, nIn, txout.nValue, nHashType, type);\n}\n\nstatic std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,\n                               const std::vector<valtype>& vSolutions,\n                               const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)\n{\n    // Combine all the signatures we've got:\n    std::set<valtype> allsigs;\n    for(const valtype& v : sigs1)\n    {\n        if (!v.empty())\n            allsigs.insert(v);\n    }\n    for(const valtype& v : sigs2)\n    {\n        if (!v.empty())\n            allsigs.insert(v);\n    }\n\n    // Build a map of pubkey -> signature by matching sigs to pubkeys:\n    assert(vSolutions.size() > 1);\n    unsigned int nSigsRequired = vSolutions.front()[0];\n    unsigned int nPubKeys = vSolutions.size()-2;\n    std::map<valtype, valtype> sigs;\n    for(const valtype& sig : allsigs)\n    {\n        for (unsigned int i = 0; i < nPubKeys; i++)\n        {\n            const valtype& pubkey = vSolutions[i+1];\n            if (sigs.count(pubkey))\n                continue; // Already got a sig for this pubkey\n\n            if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))\n            {\n                sigs[pubkey] = sig;\n                break;\n            }\n        }\n    }\n    // Now build a merged CScript:\n    unsigned int nSigsHave = 0;\n    std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround\n    for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)\n    {\n        if (sigs.count(vSolutions[i+1]))\n        {\n            result.push_back(sigs[vSolutions[i+1]]);\n            ++nSigsHave;\n        }\n    }\n    // Fill any missing with OP_0:\n    for (unsigned int i = nSigsHave; i < nSigsRequired; i++)\n        result.push_back(valtype());\n\n    return result;\n}\n\nnamespace\n{\nstruct Stacks\n{\n    std::vector<valtype> script;\n    std::vector<valtype> segregatedSignatureData;\n\n    Stacks() {}\n    explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_), segregatedSignatureData() {}\n    explicit Stacks(const SignatureData& data) : segregatedSignatureData(data.segregatedSignatureData.stack) {\n        ScriptVersion scriptversion = (data.segregatedSignatureData.IsNull()) ? SCRIPT_V1 : SCRIPT_V2;\n        EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(CKeyID(), CKeyID()), scriptversion);\n    }\n\n    SignatureData Output() const {\n        SignatureData result;\n        result.scriptSig = PushAll(script);\n        result.segregatedSignatureData.stack = segregatedSignatureData;\n        return result;\n    }\n};\n}\n\nstatic Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,\n                                 const txnouttype txType, const std::vector<valtype>& vSolutions,\n                                 Stacks sigs1, Stacks sigs2, SigVersion sigversion)\n{\n    switch (txType)\n    {\n    case TX_NONSTANDARD:\n    case TX_NULL_DATA:\n        // Don't know anything about this, assume bigger one is correct:\n        if (sigs1.script.size() >= sigs2.script.size())\n            return sigs1;\n        return sigs2;\n    case TX_PUBKEY:\n    case TX_PUBKEYHASH:\n        // Signatures are bigger than placeholders or empty scripts:\n        if (sigversion == SIGVERSION_BASE)\n        {\n            if (sigs1.script.empty() || sigs1.script[0].empty())\n                return sigs2;\n        }\n        else\n        {\n            if (sigs1.segregatedSignatureData.empty() || sigs1.segregatedSignatureData[0].empty())\n                return sigs2;\n        }\n        return sigs1;\n    case TX_SCRIPTHASH:\n        if (sigversion == SIGVERSION_BASE)\n        {\n            if (sigs1.script.empty() || sigs1.script.back().empty())\n                return sigs2;\n            else if (sigs2.script.empty() || sigs2.script.back().empty())\n                return sigs1;\n            else\n            {\n                // Recur to combine:\n                valtype spk = sigs1.script.back();\n                CScript pubKey2(spk.begin(), spk.end());\n\n                txnouttype txType2;\n                std::vector<std::vector<unsigned char> > vSolutions2;\n                Solver(pubKey2, txType2, vSolutions2);\n                sigs1.script.pop_back();\n                sigs2.script.pop_back();\n                Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);\n                result.script.push_back(spk);\n                return result;\n            }\n        }\n        else\n        {\n            if (sigs1.segregatedSignatureData.empty() || sigs1.segregatedSignatureData.back().empty())\n                return sigs2;\n            else if (sigs2.segregatedSignatureData.empty() || sigs2.segregatedSignatureData.back().empty())\n                return sigs1;\n            else\n            {\n                // Recur to combine:\n                valtype spk = sigs1.segregatedSignatureData.back();\n                CScript pubKey2(spk.begin(), spk.end());\n\n                txnouttype txType2;\n                std::vector<std::vector<unsigned char> > vSolutions2;\n                Solver(pubKey2, txType2, vSolutions2);\n                sigs1.segregatedSignatureData.pop_back();\n                sigs2.segregatedSignatureData.pop_back();\n                Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);\n                result.segregatedSignatureData.push_back(spk);\n                return result;\n            }\n        }\n    case TX_MULTISIG:\n        if (sigversion == SIGVERSION_BASE)\n        {\n            return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));\n        }\n        else\n        {\n            return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.segregatedSignatureData, sigs2.segregatedSignatureData, sigversion));\n        }\n    case TX_STANDARD_WITNESS:\n    case TX_STANDARD_PUBKEY_HASH:\n        assert(0);\n        return Stacks();\n    default:\n        return Stacks();\n    }\n}\n\nSignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,\n                          const SignatureData& scriptSig1, const SignatureData& scriptSig2, SigVersion sigversion)\n{\n    txnouttype txType;\n    std::vector<std::vector<unsigned char> > vSolutions;\n    Solver(scriptPubKey, txType, vSolutions);\n\n    return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), sigversion).Output();\n}\n\nnamespace {\n/** Dummy signature checker which accepts all signatures. */\nclass DummySignatureChecker : public BaseSignatureChecker\n{\npublic:\n    DummySignatureChecker() : BaseSignatureChecker(CKeyID(), CKeyID()) {}\n\n    bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const\n    {\n        return true;\n    }\n};\nconst DummySignatureChecker dummyChecker;\n}\n\nconst BaseSignatureChecker& DummySignatureCreator::Checker() const\n{\n    return dummyChecker;\n}\n\nbool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const\n{\n    // Create a dummy signature that is a valid DER-encoding\n    vchSig.assign(72, '\\000');\n    vchSig[0] = 0x30;\n    vchSig[1] = 69;\n    vchSig[2] = 0x02;\n    vchSig[3] = 33;\n    vchSig[4] = 0x01;\n    vchSig[4 + 33] = 0x02;\n    vchSig[5 + 33] = 32;\n    vchSig[6 + 33] = 0x01;\n    vchSig[6 + 33 + 32] = SIGHASH_ALL;\n    return true;\n}\n"
  },
  {
    "path": "src/script/sign.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_SIGN_H\n#define SCRIPT_SIGN_H\n\n#include \"script/interpreter.h\"\n\nclass CKeyID;\nclass CKeyStore;\nclass CScript;\nclass CTransaction;\n\nstruct CMutableTransaction;\n\n/** Virtual base class for signature creators. */\nclass BaseSignatureCreator {\nprotected:\n    std::vector<CKeyStore*> accountsToTry;\n\npublic:\n    BaseSignatureCreator(const std::vector<CKeyStore*>& accountsToTryIn) : accountsToTry(accountsToTryIn) {}\n    const std::vector<CKeyStore*>& accounts() const { return accountsToTry; };\n    virtual ~BaseSignatureCreator() {}\n    virtual const BaseSignatureChecker& Checker() const =0;\n\n    /** Create a singular (non-script) signature. */\n    virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;\n};\n\n/** A signature creator for transactions. */\nclass TransactionSignatureCreator : public BaseSignatureCreator {\n    const CTransaction* txTo;\n    unsigned int nIn;\n    int nHashType;\n    CAmount amount;\n    const TransactionSignatureChecker checker;\n\npublic:\n    TransactionSignatureCreator(CKeyID signingKeyID, const std::vector<CKeyStore*>& accountsToTryIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);\n    const BaseSignatureChecker& Checker() const { return checker; }\n    bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;\n};\n\nclass MutableTransactionSignatureCreator : public TransactionSignatureCreator {\n    CTransaction tx;\n\npublic:\n    MutableTransactionSignatureCreator(CKeyID signingKeyID, const std::vector<CKeyStore*>& accountsToTryIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : TransactionSignatureCreator(signingKeyID, accountsToTryIn, &tx, nInIn, amountIn, nHashTypeIn), tx(*txToIn) {}\n};\n\n/** A signature creator that just produces 72-byte empty signatures. */\nclass DummySignatureCreator : public BaseSignatureCreator {\npublic:\n    DummySignatureCreator(const std::vector<CKeyStore*>& accountsToTryIn) : BaseSignatureCreator(accountsToTryIn) {}\n    const BaseSignatureChecker& Checker() const;\n    bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;\n};\n\nstruct SignatureData {\n    CScript scriptSig;\n    CSegregatedSignatureData segregatedSignatureData;\n\n    SignatureData() {}\n    explicit SignatureData(const CScript& script) : scriptSig(script) {}\n};\n\nenum SignType\n{\n    Spend,\n    Witness\n};\n\n/** Get the CKeyID of the pubkey for the key that should be used to sign an output */\nCKeyID ExtractSigningPubkeyFromTxOutput(const CTxOut& txOut, SignType type);\n\n/** Produce a script signature using a generic signature creator. */\nbool ProduceSignature(const BaseSignatureCreator& creator, const CTxOut& fromOutput, SignatureData& sigdata, SignType type, uint64_t nVersion);\n\n/** Produce a script signature for a transaction. */\nbool SignSignature(const std::vector<CKeyStore*>& accountsToTry, const CTxOut& fromOutput, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignType type);\nbool SignSignature(const std::vector<CKeyStore*>& accountsToTry, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignType type);\n\n/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */\nSignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2, SigVersion sigversion);\n\n/** Extract signature data from a transaction, and insert it. */\nSignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);\nvoid UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);\n\n#endif\n"
  },
  {
    "path": "src/script/standard.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"script/standard.h\"\n\n#include \"pubkey.h\"\n#include \"script/script.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n\n\ntypedef std::vector<unsigned char> valtype;\n\nbool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;\nunsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;\n\nCScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}\n\nconst char* GetTxnOutputType(txnouttype t)\n{\n    // Outside of switch statement to avoid compiler warnings on some compilers\n    switch (t)\n    {\n        case TX_NONSTANDARD: return \"nonstandard\";\n        case TX_PUBKEY: return \"pubkey\";\n        case TX_PUBKEYHASH: return \"pubkeyhash\";\n        case TX_SCRIPTHASH: return \"scripthash\";\n        case TX_MULTISIG: return \"multisig\";\n        case TX_NULL_DATA: return \"nulldata\";\n        case TX_STANDARD_PUBKEY_HASH: return \"keyhash_standard\";\n        case TX_STANDARD_WITNESS: return \"pow2_witness_standard\";\n    }\n    return NULL;\n}\n\n/**\n * Return public keys or hashes from scriptPubKey, for 'standard' transaction types.\n */\nbool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)\n{\n    // Templates\n    static std::multimap<txnouttype, CScript> mTemplates;\n    if (mTemplates.empty())\n    {\n        // Standard tx, sender provides pubkey, receiver adds signature\n        mTemplates.insert(std::pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));\n\n        // Munt address tx, sender provides hash of pubkey, receiver provides signature and pubkey\n        mTemplates.insert(std::pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));\n\n        // Sender provides N pubkeys, receivers provides M signatures\n        mTemplates.insert(std::pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));\n    }\n\n    vSolutionsRet.clear();\n\n    // Shortcut for pay-to-script-hash, which are more constrained than the other types:\n    // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL\n    if (scriptPubKey.IsPayToScriptHash())\n    {\n        typeRet = TX_SCRIPTHASH;\n        std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);\n        vSolutionsRet.push_back(hashBytes);\n        return true;\n    }\n\n    // Provably prunable, data-carrying output\n    //\n    // So long as script passes the IsUnspendable() test and all but the first\n    // byte passes the IsPushOnly() test we don't care what exactly is in the\n    // script.\n    if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {\n        typeRet = TX_NULL_DATA;\n        return true;\n    }\n\n    // Scan templates\n    const CScript& script1 = scriptPubKey;\n    for(const PAIRTYPE(txnouttype, CScript)& tplate : mTemplates)\n    {\n        const CScript& script2 = tplate.second;\n        vSolutionsRet.clear();\n\n        opcodetype opcode1, opcode2;\n        std::vector<unsigned char> vch1, vch2;\n\n        // Compare\n        CScript::const_iterator pc1 = script1.begin();\n        CScript::const_iterator pc2 = script2.begin();\n        while (true)\n        {\n            if (pc1 == script1.end() && pc2 == script2.end())\n            {\n                // Found a match\n                typeRet = tplate.first;\n                if (typeRet == TX_MULTISIG)\n                {\n                    // Additional checks for TX_MULTISIG:\n                    unsigned char m = vSolutionsRet.front()[0];\n                    unsigned char n = vSolutionsRet.back()[0];\n                    if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)\n                        return false;\n                }\n                return true;\n            }\n            if (!script1.GetOp(pc1, opcode1, vch1))\n                break;\n            if (!script2.GetOp(pc2, opcode2, vch2))\n                break;\n\n            // Template matching opcodes:\n            if (opcode2 == OP_PUBKEYS)\n            {\n                while (vch1.size() >= 33 && vch1.size() <= 65)\n                {\n                    vSolutionsRet.push_back(vch1);\n                    if (!script1.GetOp(pc1, opcode1, vch1))\n                        break;\n                }\n                if (!script2.GetOp(pc2, opcode2, vch2))\n                    break;\n                // Normal situation is to fall through\n                // to other if/else statements\n            }\n\n            if (opcode2 == OP_PUBKEY)\n            {\n                if (vch1.size() < 33 || vch1.size() > 65)\n                    break;\n                vSolutionsRet.push_back(vch1);\n            }\n            else if (opcode2 == OP_PUBKEYHASH)\n            {\n                if (vch1.size() != sizeof(uint160))\n                    break;\n                vSolutionsRet.push_back(vch1);\n            }\n            else if (opcode2 == OP_SMALLINTEGER)\n            {   // Single-byte small integer pushed onto vSolutions\n                if (opcode1 == OP_0 ||\n                    (opcode1 >= OP_1 && opcode1 <= OP_16))\n                {\n                    char n = (char)CScript::DecodeOP_N(opcode1);\n                    vSolutionsRet.push_back(valtype(1, n));\n                }\n                else\n                    break;\n            }\n            else if (opcode1 != opcode2 || vch1 != vch2)\n            {\n                // Others must match exactly\n                break;\n            }\n        }\n    }\n\n    vSolutionsRet.clear();\n    typeRet = TX_NONSTANDARD;\n    return false;\n}\n\nbool ExtractDestination(const CTxOut& out, CTxDestination& addressRet)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        addressRet = CPoW2WitnessDestination(out.output.witnessDetails.spendingKeyID, out.output.witnessDetails.witnessKeyID);\n        return true;\n    }\n    else if (out.GetType() == CTxOutType::StandardKeyHashOutput)\n    {\n        addressRet = out.output.standardKeyHash.keyID;\n        return true;\n    }\n\n    return ExtractDestination(out.output.scriptPubKey, addressRet);\n}\n\nbool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)\n{\n    std::vector<valtype> vSolutions;\n    txnouttype whichType;\n    if (!Solver(scriptPubKey, whichType, vSolutions))\n        return false;\n\n    if (whichType == TX_PUBKEY)\n    {\n        CPubKey pubKey(vSolutions[0]);\n        if (!pubKey.IsValid())\n            return false;\n\n        addressRet = pubKey.GetID();\n        return true;\n    }\n    else if (whichType == TX_PUBKEYHASH)\n    {\n        addressRet = CKeyID(uint160(vSolutions[0]));\n        return true;\n    }\n    else if (whichType == TX_SCRIPTHASH)\n    {\n        addressRet = CScriptID(uint160(vSolutions[0]));\n        return true;\n    }\n    // Multisig txns have more than one address...\n    return false;\n}\n\nbool ExtractDestinations(const CTxOut& out, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        nRequiredRet = 1;\n        typeRet = TX_STANDARD_WITNESS;\n        addressRet.push_back(CPoW2WitnessDestination(out.output.witnessDetails.spendingKeyID, out.output.witnessDetails.witnessKeyID));\n        return true;\n    }\n    else if (out.GetType() == CTxOutType::StandardKeyHashOutput)\n    {\n        nRequiredRet = 1;\n        typeRet = TX_STANDARD_PUBKEY_HASH;\n        addressRet.push_back(out.output.standardKeyHash.keyID);\n        return true;\n    }\n    return ExtractDestinations(out.output.scriptPubKey, typeRet, addressRet, nRequiredRet);\n}\n\nbool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)\n{\n    addressRet.clear();\n    typeRet = TX_NONSTANDARD;\n    std::vector<valtype> vSolutions;\n    if (!Solver(scriptPubKey, typeRet, vSolutions))\n        return false;\n    if (typeRet == TX_NULL_DATA){\n        // This is data, not addresses\n        return false;\n    }\n\n    if (typeRet == TX_MULTISIG)\n    {\n        nRequiredRet = vSolutions.front()[0];\n        for (unsigned int i = 1; i < vSolutions.size()-1; i++)\n        {\n            CPubKey pubKey(vSolutions[i]);\n            if (!pubKey.IsValid())\n                continue;\n\n            CTxDestination address = pubKey.GetID();\n            addressRet.push_back(address);\n        }\n\n        if (addressRet.empty())\n            return false;\n    }\n    else\n    {\n        nRequiredRet = 1;\n        CTxDestination address;\n        if (!ExtractDestination(scriptPubKey, address))\n           return false;\n        addressRet.push_back(address);\n    }\n\n    return true;\n}\n\nnamespace\n{\nclass CScriptVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    CScript *script;\npublic:\n    CScriptVisitor(CScript *scriptin) { script = scriptin; }\n\n    bool operator()(const CNoDestination &dest) const {\n        script->clear();\n        return false;\n    }\n\n    bool operator()(const CKeyID &keyID) const {\n        script->clear();\n        *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;\n        return true;\n    }\n\n    bool operator()(const CScriptID &scriptID) const {\n        script->clear();\n        *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;\n        return true;\n    }\n\n    //OP_0 [1 byte] 72 [1 byte] hash [20 byte] hash [20 byte] uint64_t [8 byte] uint64_t [8 byte] uint64_t [8 byte] uint64_t [8 byte] (74 bytes)\n    bool operator()(const CPoW2WitnessDestination& destinationPoW2Witness) const {\n        script->clear();\n        *script << OP_0;\n        script->insert(script->end(), (unsigned char)72);\n        script->insert(script->end(), destinationPoW2Witness.spendingKey.begin(), destinationPoW2Witness.spendingKey.end());\n        script->insert(script->end(), destinationPoW2Witness.witnessKey.begin(), destinationPoW2Witness.witnessKey.end());\n        *script << CScriptUInt64(destinationPoW2Witness.lockFromBlock) << CScriptUInt64(destinationPoW2Witness.lockUntilBlock) << CScriptUInt64(destinationPoW2Witness.failCount) << CScriptUInt64(destinationPoW2Witness.actionNonce);\n\n        return true;\n    }\n};\n}\n\n\n\nCScript GetScriptForDestination(const CTxDestination& dest)\n{\n    CScript script;\n\n    boost::apply_visitor(CScriptVisitor(&script), dest);\n    return script;\n}\n\n\nCScript GetScriptForRawPubKey(const CPubKey& pubKey)\n{\n    return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;\n}\n\nCScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)\n{\n    CScript script;\n\n    script << CScript::EncodeOP_N(nRequired);\n    for(const CPubKey& key : keys)\n        script << ToByteVector(key);\n    script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;\n    return script;\n}\n\nCScript GetScriptForWitness(const CScript& redeemscript)\n{\n    CScript ret;\n\n    txnouttype typ;\n    std::vector<std::vector<unsigned char> > vSolutions;\n    if (Solver(redeemscript, typ, vSolutions)) {\n        if (typ == TX_PUBKEY) {\n            unsigned char h160[20];\n            CHash160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160);\n            ret << OP_0 << std::vector<unsigned char>(&h160[0], &h160[20]);\n            return ret;\n        } else if (typ == TX_PUBKEYHASH) {\n           ret << OP_0 << vSolutions[0];\n           return ret;\n        }\n    }\n    uint256 hash;\n    CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin());\n    ret << OP_0 << ToByteVector(hash);\n    return ret;\n}\n"
  },
  {
    "path": "src/script/standard.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SCRIPT_STANDARD_H\n#define SCRIPT_STANDARD_H\n\n#include \"script/interpreter.h\"\n#include \"uint256.h\"\n#include \"pubkey.h\"\n\n#include <boost/variant.hpp>\n\n#include <stdint.h>\n\nstatic const bool DEFAULT_ACCEPT_DATACARRIER = true;\n\nclass CKeyID;\nclass CScript;\n\n/** A reference to a CScript: the Hash160 of its serialization (see script.h) */\nclass CScriptID : public uint160\n{\npublic:\n    CScriptID() : uint160() {}\n    CScriptID(const CScript& in);\n    CScriptID(const uint160& in) : uint160(in) {}\n};\n\nstatic const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)\nextern bool fAcceptDatacarrier;\nextern unsigned nMaxDatacarrierBytes;\n\n/**\n * Mandatory script verification flags that all new blocks must comply with for\n * them to be valid. (but old blocks may not comply with) Currently just P2SH,\n * but in the future other flags may be added, such as a soft-fork to enforce\n * strict DER encoding.\n * \n * Failing one of these tests may trigger a DoS ban - see CheckInputs() for\n * details.\n */\nstatic const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;\n\nenum txnouttype\n{\n    TX_NONSTANDARD,\n    // 'standard' transaction types:\n    TX_PUBKEY,\n    TX_PUBKEYHASH,\n    TX_SCRIPTHASH,\n    TX_MULTISIG,\n    TX_NULL_DATA,\n    // NB! Not actual script types, just workarounds for other transaction types in stat geneation\n    TX_STANDARD_PUBKEY_HASH,\n    TX_STANDARD_WITNESS,\n};\n\nclass CNoDestination {\npublic:\n    friend bool operator==([[maybe_unused]] const CNoDestination &a, [[maybe_unused]] const CNoDestination &b) { return true; }\n    friend bool operator<([[maybe_unused]] const CNoDestination &a, [[maybe_unused]] const CNoDestination &b) { return true; }\n};\n\nclass CPoW2WitnessDestination{\npublic:\n    //Double check this.\n    CPoW2WitnessDestination(const CKeyID& spendingKeyIn, const CKeyID& witnessKeyIn) : spendingKey(spendingKeyIn), witnessKey(witnessKeyIn), lockFromBlock(0), lockUntilBlock(0), failCount(0) {}\n    CPoW2WitnessDestination() : spendingKey(CKeyID()), witnessKey(CKeyID()), lockFromBlock(0), lockUntilBlock(0), failCount(0), actionNonce(0) {}\n\n    CKeyID spendingKey;\n    CKeyID witnessKey;\n    uint64_t lockFromBlock;\n    uint64_t lockUntilBlock;\n    uint64_t failCount;\n    uint64_t actionNonce;\n\n    //fixme: (PHASE5) NB! This compares only on keys, it doesn't consider other variables\n    // We should somehow make this more explicit to prevent accidental usage by code that expects better\n    // e.g. Should these comparators consider the lock block or not?\n    // e.g. Should these return = if the witnessKey is different but spending key is the same? Depends where exactly this is called from...\n    // Current behaviour is probably fine, but make explicit that this is the case\n    friend bool operator==(const CPoW2WitnessDestination &a, const CPoW2WitnessDestination &b) { return a.spendingKey == b.spendingKey && a.witnessKey == b.witnessKey; }\n    friend bool operator<(const CPoW2WitnessDestination &a, const CPoW2WitnessDestination &b) { return a.spendingKey < b.spendingKey || (a.spendingKey == b.spendingKey && a.witnessKey < b.witnessKey); }\n\n    ADD_SERIALIZE_METHODS\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(spendingKey);\n        READWRITE(witnessKey);\n        READWRITE(lockFromBlock);\n        READWRITE(lockUntilBlock);\n        READWRITE(VARINT(failCount));\n        READWRITE(VARINT(actionNonce));\n    }\n};\n\n/** \n * A txout script template with a specific destination. It is either:\n *  * CNoDestination: no destination set\n *  * CKeyID: TX_PUBKEYHASH destination\n *  * CScriptID: TX_SCRIPTHASH destination\n *  A CTxDestination is the internal data type encoded in a CNativeAddress\n */\ntypedef boost::variant<CNoDestination, CKeyID, CScriptID, CPoW2WitnessDestination> CTxDestination;\n\nconst char* GetTxnOutputType(txnouttype t);\n\nbool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);\nbool ExtractDestination(const CTxOut& out, CTxDestination& addressRet);\nbool ExtractDestinations(const CTxOut& out, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);\nbool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);\nbool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);\n\nCScript GetScriptForDestination(const CTxDestination& dest);\nCScript GetScriptForRawPubKey(const CPubKey& pubkey);\nCScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);\nCScript GetScriptForWitness(const CScript& redeemscript);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/.gitignore",
    "content": "bench_inv\nbench_ecdh\nbench_sign\nbench_verify\nbench_schnorr_verify\nbench_recover\nbench_internal\ntests\nexhaustive_tests\ngen_context\n*.exe\n*.so\n*.a\n!.gitignore\n\nMakefile\nconfigure\n.libs/\nMakefile.in\naclocal.m4\nautom4te.cache/\nconfig.log\nconfig.status\n*.tar.gz\n*.la\nlibtool\n.deps/\n.dirstamp\n*.lo\n*.o\n*~\nsrc/libsecp256k1-config.h\nsrc/libsecp256k1-config.h.in\nsrc/ecmult_static_context.h\nbuild-aux/config.guess\nbuild-aux/config.sub\nbuild-aux/depcomp\nbuild-aux/install-sh\nbuild-aux/ltmain.sh\nbuild-aux/m4/libtool.m4\nbuild-aux/m4/lt~obsolete.m4\nbuild-aux/m4/ltoptions.m4\nbuild-aux/m4/ltsugar.m4\nbuild-aux/m4/ltversion.m4\nbuild-aux/missing\nbuild-aux/compile\nbuild-aux/test-driver\nsrc/stamp-h1\nlibsecp256k1.pc\n"
  },
  {
    "path": "src/secp256k1/.travis.yml",
    "content": "language: c\nsudo: false\naddons:\n  apt:\n    packages: libgmp-dev\ncompiler:\n  - clang\n  - gcc\ncache:\n  directories:\n  - src/java/guava/\nenv:\n  global:\n    - FIELD=auto  BIGNUM=auto  SCALAR=auto  ENDOMORPHISM=no  STATICPRECOMPUTATION=yes  ASM=no  BUILD=check  EXTRAFLAGS=  HOST=  ECDH=no  RECOVERY=no  EXPERIMENTAL=no\n    - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar\n  matrix:\n    - SCALAR=32bit    RECOVERY=yes\n    - SCALAR=32bit    FIELD=32bit       ECDH=yes  EXPERIMENTAL=yes\n    - SCALAR=64bit\n    - FIELD=64bit     RECOVERY=yes\n    - FIELD=64bit     ENDOMORPHISM=yes\n    - FIELD=64bit     ENDOMORPHISM=yes  ECDH=yes EXPERIMENTAL=yes\n    - FIELD=64bit                       ASM=x86_64\n    - FIELD=64bit     ENDOMORPHISM=yes  ASM=x86_64\n    - FIELD=32bit     ENDOMORPHISM=yes\n    - BIGNUM=no\n    - BIGNUM=no       ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes\n    - BIGNUM=no       STATICPRECOMPUTATION=no\n    - BUILD=distcheck\n    - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC\n    - EXTRAFLAGS=CFLAGS=-O0\n    - BUILD=check-java ECDH=yes EXPERIMENTAL=yes\nmatrix:\n  fast_finish: true\n  include:\n    - compiler: clang\n      env: HOST=i686-linux-gnu ENDOMORPHISM=yes\n      addons:\n        apt:\n          packages:\n            - gcc-multilib\n            - libgmp-dev:i386\n    - compiler: clang\n      env: HOST=i686-linux-gnu\n      addons:\n        apt:\n          packages:\n            - gcc-multilib\n    - compiler: gcc\n      env: HOST=i686-linux-gnu ENDOMORPHISM=yes\n      addons:\n        apt:\n          packages:\n            - gcc-multilib\n    - compiler: gcc\n      env: HOST=i686-linux-gnu\n      addons:\n        apt:\n          packages:\n            - gcc-multilib\n            - libgmp-dev:i386\nbefore_install: mkdir -p `dirname $GUAVA_JAR`\ninstall: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi\nbefore_script: ./autogen.sh\nscript:\n - if [ -n \"$HOST\" ]; then export USE_HOST=\"--host=$HOST\"; fi\n - if [ \"x$HOST\" = \"xi686-linux-gnu\" ]; then export CC=\"$CC -m32\"; fi\n - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD\nos: linux\n"
  },
  {
    "path": "src/secp256k1/COPYING",
    "content": "Copyright (c) 2013 Pieter Wuille\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "src/secp256k1/Makefile.am",
    "content": "ACLOCAL_AMFLAGS = -I build-aux/m4\n\nlib_LTLIBRARIES = libsecp256k1.la\nif USE_JNI\nJNI_LIB = libsecp256k1_jni.la\nnoinst_LTLIBRARIES = $(JNI_LIB)\nelse\nJNI_LIB =\nendif\ninclude_HEADERS = include/secp256k1.h\nnoinst_HEADERS =\nnoinst_HEADERS += src/scalar.h\nnoinst_HEADERS += src/scalar_4x64.h\nnoinst_HEADERS += src/scalar_8x32.h\nnoinst_HEADERS += src/scalar_low.h\nnoinst_HEADERS += src/scalar_impl.h\nnoinst_HEADERS += src/scalar_4x64_impl.h\nnoinst_HEADERS += src/scalar_8x32_impl.h\nnoinst_HEADERS += src/scalar_low_impl.h\nnoinst_HEADERS += src/group.h\nnoinst_HEADERS += src/group_impl.h\nnoinst_HEADERS += src/num_gmp.h\nnoinst_HEADERS += src/num_gmp_impl.h\nnoinst_HEADERS += src/ecdsa.h\nnoinst_HEADERS += src/ecdsa_impl.h\nnoinst_HEADERS += src/eckey.h\nnoinst_HEADERS += src/eckey_impl.h\nnoinst_HEADERS += src/ecmult.h\nnoinst_HEADERS += src/ecmult_impl.h\nnoinst_HEADERS += src/ecmult_const.h\nnoinst_HEADERS += src/ecmult_const_impl.h\nnoinst_HEADERS += src/ecmult_gen.h\nnoinst_HEADERS += src/ecmult_gen_impl.h\nnoinst_HEADERS += src/num.h\nnoinst_HEADERS += src/num_impl.h\nnoinst_HEADERS += src/field_10x26.h\nnoinst_HEADERS += src/field_10x26_impl.h\nnoinst_HEADERS += src/field_5x52.h\nnoinst_HEADERS += src/field_5x52_impl.h\nnoinst_HEADERS += src/field_5x52_int128_impl.h\nnoinst_HEADERS += src/field_5x52_asm_impl.h\nnoinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h\nnoinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h\nnoinst_HEADERS += src/util.h\nnoinst_HEADERS += src/testrand.h\nnoinst_HEADERS += src/testrand_impl.h\nnoinst_HEADERS += src/hash.h\nnoinst_HEADERS += src/hash_impl.h\nnoinst_HEADERS += src/field.h\nnoinst_HEADERS += src/field_impl.h\nnoinst_HEADERS += src/bench.h\nnoinst_HEADERS += contrib/lax_der_parsing.h\nnoinst_HEADERS += contrib/lax_der_parsing.c\nnoinst_HEADERS += contrib/lax_der_privatekey_parsing.h\nnoinst_HEADERS += contrib/lax_der_privatekey_parsing.c\n\nif USE_EXTERNAL_ASM\nCOMMON_LIB = libsecp256k1_common.la\nnoinst_LTLIBRARIES = $(COMMON_LIB)\nelse\nCOMMON_LIB =\nendif\n\npkgconfigdir = $(libdir)/pkgconfig\npkgconfig_DATA = libsecp256k1.pc\n\nif USE_EXTERNAL_ASM\nif USE_ASM_ARM\nlibsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s\nendif\nendif\n\nlibsecp256k1_la_SOURCES = src/secp256k1.c\nlibsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)\nlibsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)\n\nlibsecp256k1_jni_la_SOURCES  = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c\nlibsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)\n\nnoinst_PROGRAMS =\nif USE_BENCHMARK\nnoinst_PROGRAMS += bench_verify bench_sign bench_internal\nbench_verify_SOURCES = src/bench_verify.c\nbench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)\nbench_sign_SOURCES = src/bench_sign.c\nbench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)\nbench_internal_SOURCES = src/bench_internal.c\nbench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)\nbench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)\nendif\n\nTESTS =\nif USE_TESTS\nnoinst_PROGRAMS += tests\ntests_SOURCES = src/tests.c\ntests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)\nif !ENABLE_COVERAGE\ntests_CPPFLAGS += -DVERIFY\nendif\ntests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)\ntests_LDFLAGS = -static\nTESTS += tests\nendif\n\nif USE_EXHAUSTIVE_TESTS\nnoinst_PROGRAMS += exhaustive_tests\nexhaustive_tests_SOURCES = src/tests_exhaustive.c\nexhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)\nif !ENABLE_COVERAGE\nexhaustive_tests_CPPFLAGS += -DVERIFY\nendif\nexhaustive_tests_LDADD = $(SECP_LIBS)\nexhaustive_tests_LDFLAGS = -static\nTESTS += exhaustive_tests\nendif\n\nJAVAROOT=src/java\nJAVAORG=org/bitcoin\nJAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar\nCLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)\nJAVA_FILES= \\\n  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \\\n  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \\\n  $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \\\n  $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java\n\nif USE_JNI\n\n$(JAVA_GUAVA):\n\t@echo Guava is missing. Fetch it via: \\\n\twget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)\n\t@false\n\n.stamp-java: $(JAVA_FILES)\n\t@echo   Compiling $^\n\t$(AM_V_at)$(CLASSPATH_ENV) javac $^\n\t@touch $@\n\nif USE_TESTS\n\ncheck-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java\n\t$(AM_V_at)java -Djava.library.path=\"./:./src:./src/.libs:.libs/\" -cp \"$(JAVA_GUAVA):$(JAVAROOT)\" $(JAVAORG)/NativeSecp256k1Test\n\nendif\nendif\n\nif USE_ECMULT_STATIC_PRECOMPUTATION\nCPPFLAGS_FOR_BUILD =-I$(top_srcdir)\nCFLAGS_FOR_BUILD = -Wall -Wextra -Wno-unused-function\n\ngen_context_OBJECTS = gen_context.o\ngen_context_BIN = gen_context$(BUILD_EXEEXT)\ngen_%.o: src/gen_%.c\n\t$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@\n\n$(gen_context_BIN): $(gen_context_OBJECTS)\n\t$(CC_FOR_BUILD) $^ -o $@\n\n$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h\n$(tests_OBJECTS): src/ecmult_static_context.h\n$(bench_internal_OBJECTS): src/ecmult_static_context.h\n\nsrc/ecmult_static_context.h: $(gen_context_BIN)\n\t./$(gen_context_BIN)\n\nCLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java\nendif\n\nEXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)\n\nif ENABLE_MODULE_ECDH\ninclude src/modules/ecdh/Makefile.am.include\nendif\n\nif ENABLE_MODULE_RECOVERY\ninclude src/modules/recovery/Makefile.am.include\nendif\n"
  },
  {
    "path": "src/secp256k1/README.md",
    "content": "libsecp256k1\n============\n\n[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)\n\nOptimized C library for EC operations on curve secp256k1.\n\nThis library is a work in progress and is being used to research best practices. Use at your own risk.\n\nFeatures:\n* secp256k1 ECDSA signing/verification and key generation.\n* Adding/multiplying private/public keys.\n* Serialization/parsing of private keys, public keys, signatures.\n* Constant time, constant memory access signing and pubkey generation.\n* Derandomized DSA (via RFC6979 or with a caller provided function.)\n* Very efficient implementation.\n\nImplementation details\n----------------------\n\n* General\n  * No runtime heap allocation.\n  * Extensive testing infrastructure.\n  * Structured to facilitate review and analysis.\n  * Intended to be portable to any system with a C89 compiler and uint64_t support.\n  * Expose only higher level interfaces to minimize the API surface and improve application security. (\"Be difficult to use insecurely.\")\n* Field operations\n  * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).\n    * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).\n    * Using 10 26-bit limbs.\n  * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).\n* Scalar operations\n  * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.\n    * Using 4 64-bit limbs (relying on __int128 support in the compiler).\n    * Using 8 32-bit limbs.\n* Group operations\n  * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).\n  * Use addition between points in Jacobian and affine coordinates where possible.\n  * Use a unified addition/doubling formula where necessary to avoid data-dependent branches.\n  * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.\n* Point multiplication for verification (a*P + b*G).\n  * Use wNAF notation for point multiplicands.\n  * Use a much larger window for multiples of G, using precomputed multiples.\n  * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.\n  * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.\n* Point multiplication for signing\n  * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.\n  * Access the table with branch-free conditional moves so memory access is uniform.\n  * No data-dependent branches\n  * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.\n\nBuild steps\n-----------\n\nlibsecp256k1 is built using autotools:\n\n    $ ./autogen.sh\n    $ ./configure\n    $ make\n    $ ./tests\n    $ sudo make install  # optional\n"
  },
  {
    "path": "src/secp256k1/TODO",
    "content": "* Unit tests for fieldelem/groupelem, including ones intended to\n  trigger fieldelem's boundary cases.\n* Complete constant-time operations for signing/keygen\n"
  },
  {
    "path": "src/secp256k1/autogen.sh",
    "content": "#!/bin/sh\nset -e\nautoreconf -if --warnings=all\n"
  },
  {
    "path": "src/secp256k1/build-aux/m4/ax_jni_include_dir.m4",
    "content": "# ===========================================================================\n#    http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_JNI_INCLUDE_DIR\n#\n# DESCRIPTION\n#\n#   AX_JNI_INCLUDE_DIR finds include directories needed for compiling\n#   programs using the JNI interface.\n#\n#   JNI include directories are usually in the Java distribution. This is\n#   deduced from the value of $JAVA_HOME, $JAVAC, or the path to \"javac\", in\n#   that order. When this macro completes, a list of directories is left in\n#   the variable JNI_INCLUDE_DIRS.\n#\n#   Example usage follows:\n#\n#     AX_JNI_INCLUDE_DIR\n#\n#     for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS\n#     do\n#             CPPFLAGS=\"$CPPFLAGS -I$JNI_INCLUDE_DIR\"\n#     done\n#\n#   If you want to force a specific compiler:\n#\n#   - at the configure.in level, set JAVAC=yourcompiler before calling\n#   AX_JNI_INCLUDE_DIR\n#\n#   - at the configure level, setenv JAVAC\n#\n#   Note: This macro can work with the autoconf M4 macros for Java programs.\n#   This particular macro is not part of the original set of macros.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Don Anderson <dda@sleepycat.com>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved. This file is offered as-is, without any\n#   warranty.\n\n#serial 10\n\nAU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])\nAC_DEFUN([AX_JNI_INCLUDE_DIR],[\n\nJNI_INCLUDE_DIRS=\"\"\n\nif test \"x$JAVA_HOME\" != x; then\n\t_JTOPDIR=\"$JAVA_HOME\"\nelse\n\tif test \"x$JAVAC\" = x; then\n\t\tJAVAC=javac\n\tfi\n\tAC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])\n\tif test \"x$_ACJNI_JAVAC\" = xno; then\n\t\tAC_MSG_WARN([cannot find JDK; try setting \\$JAVAC or \\$JAVA_HOME])\n\tfi\n\t_ACJNI_FOLLOW_SYMLINKS(\"$_ACJNI_JAVAC\")\n\t_JTOPDIR=`echo \"$_ACJNI_FOLLOWED\" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`\nfi\n\ncase \"$host_os\" in\n        darwin*)        _JTOPDIR=`echo \"$_JTOPDIR\" | sed -e 's:/[[^/]]*$::'`\n                        _JINC=\"$_JTOPDIR/Headers\";;\n        *)              _JINC=\"$_JTOPDIR/include\";;\nesac\n_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])\n_AS_ECHO_LOG([_JINC=$_JINC])\n\n# On Mac OS X 10.6.4, jni.h is a symlink:\n# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h\n# -> ../../CurrentJDK/Headers/jni.h.\n\nAC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,\n[\nif test -f \"$_JINC/jni.h\"; then\n  ac_cv_jni_header_path=\"$_JINC\"\n  JNI_INCLUDE_DIRS=\"$JNI_INCLUDE_DIRS $ac_cv_jni_header_path\"\nelse\n  _JTOPDIR=`echo \"$_JTOPDIR\" | sed -e 's:/[[^/]]*$::'`\n  if test -f \"$_JTOPDIR/include/jni.h\"; then\n    ac_cv_jni_header_path=\"$_JTOPDIR/include\"\n    JNI_INCLUDE_DIRS=\"$JNI_INCLUDE_DIRS $ac_cv_jni_header_path\"\n  else\n    ac_cv_jni_header_path=none\n  fi\nfi\n])\n\n\n\n# get the likely subdirectories for system specific java includes\ncase \"$host_os\" in\nbsdi*)          _JNI_INC_SUBDIRS=\"bsdos\";;\ndarwin*)        _JNI_INC_SUBDIRS=\"darwin\";;\nfreebsd*)       _JNI_INC_SUBDIRS=\"freebsd\";;\nlinux*)         _JNI_INC_SUBDIRS=\"linux genunix\";;\nosf*)           _JNI_INC_SUBDIRS=\"alpha\";;\nsolaris*)       _JNI_INC_SUBDIRS=\"solaris\";;\nmingw*)\t\t_JNI_INC_SUBDIRS=\"win32\";;\ncygwin*)\t_JNI_INC_SUBDIRS=\"win32\";;\n*)              _JNI_INC_SUBDIRS=\"genunix\";;\nesac\n\nif test \"x$ac_cv_jni_header_path\" != \"xnone\"; then\n  # add any subdirectories that are present\n  for JINCSUBDIR in $_JNI_INC_SUBDIRS\n  do\n      if test -d \"$_JTOPDIR/include/$JINCSUBDIR\"; then\n           JNI_INCLUDE_DIRS=\"$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR\"\n      fi\n  done\nfi\n])\n\n# _ACJNI_FOLLOW_SYMLINKS <path>\n# Follows symbolic links on <path>,\n# finally setting variable _ACJNI_FOLLOWED\n# ----------------------------------------\nAC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[\n# find the include directory relative to the javac executable\n_cur=\"$1\"\nwhile ls -ld \"$_cur\" 2>/dev/null | grep \" -> \" >/dev/null; do\n        AC_MSG_CHECKING([symlink for $_cur])\n        _slink=`ls -ld \"$_cur\" | sed 's/.* -> //'`\n        case \"$_slink\" in\n        /*) _cur=\"$_slink\";;\n        # 'X' avoids triggering unwanted echo options.\n        *) _cur=`echo \"X$_cur\" | sed -e 's/^X//' -e 's:[[^/]]*$::'`\"$_slink\";;\n        esac\n        AC_MSG_RESULT([$_cur])\ndone\n_ACJNI_FOLLOWED=\"$_cur\"\n])# _ACJNI\n"
  },
  {
    "path": "src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4",
    "content": "# ===========================================================================\n#   http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_PROG_CC_FOR_BUILD\n#\n# DESCRIPTION\n#\n#   This macro searches for a C compiler that generates native executables,\n#   that is a C compiler that surely is not a cross-compiler. This can be\n#   useful if you have to generate source code at compile-time like for\n#   example GCC does.\n#\n#   The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything\n#   needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD).\n#   The value of these variables can be overridden by the user by specifying\n#   a compiler with an environment variable (like you do for standard CC).\n#\n#   It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object\n#   file extensions for the build platform, and GCC_FOR_BUILD to `yes' if\n#   the compiler we found is GCC. All these variables but GCC_FOR_BUILD are\n#   substituted in the Makefile.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved. This file is offered as-is, without any\n#   warranty.\n\n#serial 8\n\nAU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD])\nAC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl\nAC_REQUIRE([AC_PROG_CC])dnl\nAC_REQUIRE([AC_PROG_CPP])dnl\nAC_REQUIRE([AC_EXEEXT])dnl\nAC_REQUIRE([AC_CANONICAL_HOST])dnl\n\ndnl Use the standard macros, but make them use other variable names\ndnl\npushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl\npushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl\npushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl\npushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl\npushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl\npushdef([ac_cv_exeext], ac_cv_build_exeext)dnl\npushdef([ac_cv_objext], ac_cv_build_objext)dnl\npushdef([ac_exeext], ac_build_exeext)dnl\npushdef([ac_objext], ac_build_objext)dnl\npushdef([CC], CC_FOR_BUILD)dnl\npushdef([CPP], CPP_FOR_BUILD)dnl\npushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl\npushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl\npushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl\npushdef([host], build)dnl\npushdef([host_alias], build_alias)dnl\npushdef([host_cpu], build_cpu)dnl\npushdef([host_vendor], build_vendor)dnl\npushdef([host_os], build_os)dnl\npushdef([ac_cv_host], ac_cv_build)dnl\npushdef([ac_cv_host_alias], ac_cv_build_alias)dnl\npushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl\npushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl\npushdef([ac_cv_host_os], ac_cv_build_os)dnl\npushdef([ac_cpp], ac_build_cpp)dnl\npushdef([ac_compile], ac_build_compile)dnl\npushdef([ac_link], ac_build_link)dnl\n\nsave_cross_compiling=$cross_compiling\nsave_ac_tool_prefix=$ac_tool_prefix\ncross_compiling=no\nac_tool_prefix=\n\nAC_PROG_CC\nAC_PROG_CPP\nAC_EXEEXT\n\nac_tool_prefix=$save_ac_tool_prefix\ncross_compiling=$save_cross_compiling\n\ndnl Restore the old definitions\ndnl\npopdef([ac_link])dnl\npopdef([ac_compile])dnl\npopdef([ac_cpp])dnl\npopdef([ac_cv_host_os])dnl\npopdef([ac_cv_host_vendor])dnl\npopdef([ac_cv_host_cpu])dnl\npopdef([ac_cv_host_alias])dnl\npopdef([ac_cv_host])dnl\npopdef([host_os])dnl\npopdef([host_vendor])dnl\npopdef([host_cpu])dnl\npopdef([host_alias])dnl\npopdef([host])dnl\npopdef([LDFLAGS])dnl\npopdef([CPPFLAGS])dnl\npopdef([CFLAGS])dnl\npopdef([CPP])dnl\npopdef([CC])dnl\npopdef([ac_objext])dnl\npopdef([ac_exeext])dnl\npopdef([ac_cv_objext])dnl\npopdef([ac_cv_exeext])dnl\npopdef([ac_cv_prog_cc_g])dnl\npopdef([ac_cv_prog_cc_cross])dnl\npopdef([ac_cv_prog_cc_works])dnl\npopdef([ac_cv_prog_gcc])dnl\npopdef([ac_cv_prog_CPP])dnl\n\ndnl Finally, set Makefile variables\ndnl\nBUILD_EXEEXT=$ac_build_exeext\nBUILD_OBJEXT=$ac_build_objext\nAC_SUBST(BUILD_EXEEXT)dnl\nAC_SUBST(BUILD_OBJEXT)dnl\nAC_SUBST([CFLAGS_FOR_BUILD])dnl\nAC_SUBST([CPPFLAGS_FOR_BUILD])dnl\nAC_SUBST([LDFLAGS_FOR_BUILD])dnl\n])\n"
  },
  {
    "path": "src/secp256k1/build-aux/m4/bitcoin_secp.m4",
    "content": "dnl libsecp25k1 helper checks\nAC_DEFUN([SECP_INT128_CHECK],[\nhas_int128=$ac_cv_type___int128\n])\n\ndnl escape \"$0x\" below using the m4 quadrigaph @S|@, and escape it again with a \\ for the shell.\nAC_DEFUN([SECP_64BIT_ASM_CHECK],[\nAC_MSG_CHECKING(for x86_64 assembly availability)\nAC_COMPILE_IFELSE([AC_LANG_PROGRAM([[\n  #include <stdint.h>]],[[\n  uint64_t a = 11, tmp;\n  __asm__ __volatile__(\"movq \\@S|@0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");\n  ]])],[has_64bit_asm=yes],[has_64bit_asm=no])\nAC_MSG_RESULT([$has_64bit_asm])\n])\n\ndnl\nAC_DEFUN([SECP_OPENSSL_CHECK],[\n  has_libcrypto=no\n  m4_ifdef([PKG_CHECK_MODULES],[\n    PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])\n    if test x\"$has_libcrypto\" = x\"yes\"; then\n      TEMP_LIBS=\"$LIBS\"\n      LIBS=\"$LIBS $CRYPTO_LIBS\"\n      AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no])\n      LIBS=\"$TEMP_LIBS\"\n    fi\n  ])\n  if test x$has_libcrypto = xno; then\n    AC_CHECK_HEADER(openssl/crypto.h,[\n      AC_CHECK_LIB(crypto, main,[\n        has_libcrypto=yes\n        CRYPTO_LIBS=-lcrypto\n        AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])\n      ])\n    ])\n    LIBS=\n  fi\nif test x\"$has_libcrypto\" = x\"yes\" && test x\"$has_openssl_ec\" = x; then\n  AC_MSG_CHECKING(for EC functions in libcrypto)\n  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[\n    #include <openssl/ec.h>\n    #include <openssl/ecdsa.h>\n    #include <openssl/obj_mac.h>]],[[\n    EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);\n    ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);\n    ECDSA_verify(0, NULL, 0, NULL, 0, eckey);\n    EC_KEY_free(eckey);\n    ECDSA_SIG *sig_openssl;\n    sig_openssl = ECDSA_SIG_new();\n    (void)sig_openssl->r;\n    ECDSA_SIG_free(sig_openssl);\n  ]])],[has_openssl_ec=yes],[has_openssl_ec=no])\n  AC_MSG_RESULT([$has_openssl_ec])\nfi\n])\n\ndnl\nAC_DEFUN([SECP_GMP_CHECK],[\nif test x\"$has_gmp\" != x\"yes\"; then\n  CPPFLAGS_TEMP=\"$CPPFLAGS\"\n  CPPFLAGS=\"$GMP_CPPFLAGS $CPPFLAGS\"\n  LIBS_TEMP=\"$LIBS\"\n  LIBS=\"$GMP_LIBS $LIBS\"\n  AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS=\"$GMP_LIBS -lgmp\"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])\n  CPPFLAGS=\"$CPPFLAGS_TEMP\"\n  LIBS=\"$LIBS_TEMP\"\nfi\n])\n"
  },
  {
    "path": "src/secp256k1/configure.ac",
    "content": "AC_PREREQ([2.60])\nAC_INIT([libsecp256k1],[0.1])\nAC_CONFIG_AUX_DIR([build-aux])\nAC_CONFIG_MACRO_DIR([build-aux/m4])\nAC_CANONICAL_HOST\nAH_TOP([#ifndef LIBSECP256K1_CONFIG_H])\nAH_TOP([#define LIBSECP256K1_CONFIG_H])\nAH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])\nAM_INIT_AUTOMAKE([foreign subdir-objects])\nLT_INIT\n\n\ndnl make the compilation flags quiet unless V=1 is used\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\n\nPKG_PROG_PKG_CONFIG\n\nAC_PATH_TOOL(AR, ar)\nAC_PATH_TOOL(RANLIB, ranlib)\nAC_PATH_TOOL(STRIP, strip)\nAX_PROG_CC_FOR_BUILD\n\nif test \"x$CFLAGS\" = \"x\"; then\n  CFLAGS=\"-g\"\nfi\n\nAM_PROG_CC_C_O\n\nAC_PROG_CC_C89\nif test x\"$ac_cv_prog_cc_c89\" = x\"no\"; then\n  AC_MSG_ERROR([c89 compiler support required])\nfi\nAM_PROG_AS\n\ncase $host_os in\n  *darwin*)\n     if  test x$cross_compiling != xyes; then\n       AC_PATH_PROG([BREW],brew,)\n       if test x$BREW != x; then\n         dnl These Homebrew packages may be keg-only, meaning that they won't be found\n         dnl in expected paths because they may conflict with system files. Ask\n         dnl Homebrew where each one is located, then adjust paths accordingly.\n\n         openssl_prefix=`$BREW --prefix openssl 2>/dev/null`\n         gmp_prefix=`$BREW --prefix gmp 2>/dev/null`\n         if test x$openssl_prefix != x; then\n           PKG_CONFIG_PATH=\"$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH\"\n           export PKG_CONFIG_PATH\n         fi\n         if test x$gmp_prefix != x; then\n           GMP_CPPFLAGS=\"-I$gmp_prefix/include\"\n           GMP_LIBS=\"-L$gmp_prefix/lib\"\n         fi\n       else\n         AC_PATH_PROG([PORT],port,)\n         dnl if homebrew isn't installed and macports is, add the macports default paths\n         dnl as a last resort.\n         if test x$PORT != x; then\n           CPPFLAGS=\"$CPPFLAGS -isystem /opt/local/include\"\n           LDFLAGS=\"$LDFLAGS -L/opt/local/lib\"\n         fi\n       fi\n     fi\n   ;;\nesac\n\nCFLAGS=\"$CFLAGS -W\"\n\nwarn_CFLAGS=\"-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings\"\nsaved_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS $warn_CFLAGS\"\nAC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])\nAC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],\n    [ AC_MSG_RESULT([yes]) ],\n    [ AC_MSG_RESULT([no])\n      CFLAGS=\"$saved_CFLAGS\"\n    ])\n\nsaved_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS -fvisibility=hidden\"\nAC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])\nAC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],\n    [ AC_MSG_RESULT([yes]) ],\n    [ AC_MSG_RESULT([no])\n      CFLAGS=\"$saved_CFLAGS\"\n    ])\n\nAC_ARG_ENABLE(benchmark,\n    AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),\n    [use_benchmark=$enableval],\n    [use_benchmark=no])\n\nAC_ARG_ENABLE(coverage,\n    AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),\n    [enable_coverage=$enableval],\n    [enable_coverage=no])\n\nAC_ARG_ENABLE(tests,\n    AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),\n    [use_tests=$enableval],\n    [use_tests=yes])\n\nAC_ARG_ENABLE(openssl_tests,\n    AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),\n    [enable_openssl_tests=$enableval],\n    [enable_openssl_tests=auto])\n\nAC_ARG_ENABLE(experimental,\n    AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),\n    [use_experimental=$enableval],\n    [use_experimental=no])\n\nAC_ARG_ENABLE(exhaustive_tests,\n    AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),\n    [use_exhaustive_tests=$enableval],\n    [use_exhaustive_tests=yes])\n\nAC_ARG_ENABLE(endomorphism,\n    AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),\n    [use_endomorphism=$enableval],\n    [use_endomorphism=no])\n\nAC_ARG_ENABLE(ecmult_static_precomputation,\n    AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),\n    [use_ecmult_static_precomputation=$enableval],\n    [use_ecmult_static_precomputation=auto])\n\nAC_ARG_ENABLE(module_ecdh,\n    AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),\n    [enable_module_ecdh=$enableval],\n    [enable_module_ecdh=no])\n\nAC_ARG_ENABLE(module_recovery,\n    AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),\n    [enable_module_recovery=$enableval],\n    [enable_module_recovery=no])\n\nAC_ARG_ENABLE(jni,\n    AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),\n    [use_jni=$enableval],\n    [use_jni=auto])\n\nAC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],\n[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])\n\nAC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],\n[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])\n\nAC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],\n[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])\n\nAC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]\n[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])\n\nAC_CHECK_TYPES([__int128])\n\nAC_MSG_CHECKING([for __builtin_expect])\nAC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],\n    [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],\n    [ AC_MSG_RESULT([no])\n    ])\n\nif test x\"$enable_coverage\" = x\"yes\"; then\n    AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])\n    CFLAGS=\"$CFLAGS -O0 --coverage\"\n    LDFLAGS=\"--coverage\"\nelse\n    CFLAGS=\"$CFLAGS -O3\"\nfi\n\nif test x\"$use_ecmult_static_precomputation\" != x\"no\"; then\n  save_cross_compiling=$cross_compiling\n  cross_compiling=no\n  TEMP_CC=\"$CC\"\n  CC=\"$CC_FOR_BUILD\"\n  AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])\n  AC_RUN_IFELSE(\n    [AC_LANG_PROGRAM([], [return 0])],\n    [working_native_cc=yes],\n    [working_native_cc=no],[dnl])\n  CC=\"$TEMP_CC\"\n  cross_compiling=$save_cross_compiling\n\n  if test x\"$working_native_cc\" = x\"no\"; then\n    set_precomp=no\n    if test x\"$use_ecmult_static_precomputation\" = x\"yes\";  then\n      AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])\n    else\n      AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])\n    fi\n  else\n    AC_MSG_RESULT([ok])\n    set_precomp=yes\n  fi\nelse\n  set_precomp=no\nfi\n\nif test x\"$req_asm\" = x\"auto\"; then\n  SECP_64BIT_ASM_CHECK\n  if test x\"$has_64bit_asm\" = x\"yes\"; then\n    set_asm=x86_64\n  fi\n  if test x\"$set_asm\" = x; then\n    set_asm=no\n  fi\nelse\n  set_asm=$req_asm\n  case $set_asm in\n  x86_64)\n    SECP_64BIT_ASM_CHECK\n    if test x\"$has_64bit_asm\" != x\"yes\"; then\n      AC_MSG_ERROR([x86_64 assembly optimization requested but not available])\n    fi\n    ;;\n  arm)\n    ;;\n  no)\n    ;;\n  *)\n    AC_MSG_ERROR([invalid assembly optimization selection])\n    ;;\n  esac\nfi\n\nif test x\"$req_field\" = x\"auto\"; then\n  if test x\"set_asm\" = x\"x86_64\"; then\n    set_field=64bit\n  fi\n  if test x\"$set_field\" = x; then\n    SECP_INT128_CHECK\n    if test x\"$has_int128\" = x\"yes\"; then\n      set_field=64bit\n    fi\n  fi\n  if test x\"$set_field\" = x; then\n    set_field=32bit\n  fi\nelse\n  set_field=$req_field\n  case $set_field in\n  64bit)\n    if test x\"$set_asm\" != x\"x86_64\"; then\n      SECP_INT128_CHECK\n      if test x\"$has_int128\" != x\"yes\"; then\n        AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])\n      fi\n    fi\n    ;;\n  32bit)\n    ;;\n  *)\n    AC_MSG_ERROR([invalid field implementation selection])\n    ;;\n  esac\nfi\n\nif test x\"$req_scalar\" = x\"auto\"; then\n  SECP_INT128_CHECK\n  if test x\"$has_int128\" = x\"yes\"; then\n    set_scalar=64bit\n  fi\n  if test x\"$set_scalar\" = x; then\n    set_scalar=32bit\n  fi\nelse\n  set_scalar=$req_scalar\n  case $set_scalar in\n  64bit)\n    SECP_INT128_CHECK\n    if test x\"$has_int128\" != x\"yes\"; then\n      AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])\n    fi\n    ;;\n  32bit)\n    ;;\n  *)\n    AC_MSG_ERROR([invalid scalar implementation selected])\n    ;;\n  esac\nfi\n\nif test x\"$req_bignum\" = x\"auto\"; then\n  SECP_GMP_CHECK\n  if test x\"$has_gmp\" = x\"yes\"; then\n    set_bignum=gmp\n  fi\n\n  if test x\"$set_bignum\" = x; then\n    set_bignum=no\n  fi\nelse\n  set_bignum=$req_bignum\n  case $set_bignum in\n  gmp)\n    SECP_GMP_CHECK\n    if test x\"$has_gmp\" != x\"yes\"; then\n      AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])\n    fi\n    ;;\n  no)\n    ;;\n  *)\n    AC_MSG_ERROR([invalid bignum implementation selection])\n    ;;\n  esac\nfi\n\n# select assembly optimization\nuse_external_asm=no\n\ncase $set_asm in\nx86_64)\n  AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])\n  ;;\narm)\n  use_external_asm=yes\n  ;;\nno)\n  ;;\n*)\n  AC_MSG_ERROR([invalid assembly optimizations])\n  ;;\nesac\n\n# select field implementation\ncase $set_field in\n64bit)\n  AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])\n  ;;\n32bit)\n  AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])\n  ;;\n*)\n  AC_MSG_ERROR([invalid field implementation])\n  ;;\nesac\n\n# select bignum implementation\ncase $set_bignum in\ngmp)\n  AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])\n  AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])\n  AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])\n  AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])\n  ;;\nno)\n  AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])\n  AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])\n  AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])\n  ;;\n*)\n  AC_MSG_ERROR([invalid bignum implementation])\n  ;;\nesac\n\n#select scalar implementation\ncase $set_scalar in\n64bit)\n  AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])\n  ;;\n32bit)\n  AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])\n  ;;\n*)\n  AC_MSG_ERROR([invalid scalar implementation])\n  ;;\nesac\n\nif test x\"$use_tests\" = x\"yes\"; then\n  SECP_OPENSSL_CHECK\n  if test x\"$has_openssl_ec\" = x\"yes\"; then\n    if test x\"$enable_openssl_tests\" != x\"no\"; then\n      AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])\n      SECP_TEST_INCLUDES=\"$SSL_CFLAGS $CRYPTO_CFLAGS\"\n      SECP_TEST_LIBS=\"$CRYPTO_LIBS\"\n\n      case $host in\n      *mingw*)\n        SECP_TEST_LIBS=\"$SECP_TEST_LIBS -lgdi32\"\n        ;;\n      esac\n    fi\n  else\n    if test x\"$enable_openssl_tests\" = x\"yes\"; then\n      AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])\n    fi\n  fi\nelse\n  if test x\"$enable_openssl_tests\" = x\"yes\"; then\n    AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])\n  fi\nfi\n\nif test x\"$use_jni\" != x\"no\"; then\n  AX_JNI_INCLUDE_DIR\n  have_jni_dependencies=yes\n  if test x\"$enable_module_ecdh\" = x\"no\"; then\n    have_jni_dependencies=no\n  fi\n  if test \"x$JNI_INCLUDE_DIRS\" = \"x\"; then\n    have_jni_dependencies=no\n  fi\n  if test \"x$have_jni_dependencies\" = \"xno\"; then\n    if test x\"$use_jni\" = x\"yes\"; then\n      AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])\n    fi\n    AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])\n    use_jni=no\n  else\n    use_jni=yes\n    for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do\n      JNI_INCLUDES=\"$JNI_INCLUDES -I$JNI_INCLUDE_DIR\"\n    done\n  fi\nfi\n\nif test x\"$set_bignum\" = x\"gmp\"; then\n  SECP_LIBS=\"$SECP_LIBS $GMP_LIBS\"\n  SECP_INCLUDES=\"$SECP_INCLUDES $GMP_CPPFLAGS\"\nfi\n\nif test x\"$use_endomorphism\" = x\"yes\"; then\n  AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])\nfi\n\nif test x\"$set_precomp\" = x\"yes\"; then\n  AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])\nfi\n\nif test x\"$enable_module_ecdh\" = x\"yes\"; then\n  AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])\nfi\n\nif test x\"$enable_module_recovery\" = x\"yes\"; then\n  AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])\nfi\n\nAC_C_BIGENDIAN()\n\nif test x\"$use_external_asm\" = x\"yes\"; then\n  AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])\nfi\n\nAC_MSG_NOTICE([Using static precomputation: $set_precomp])\nAC_MSG_NOTICE([Using assembly optimizations: $set_asm])\nAC_MSG_NOTICE([Using field implementation: $set_field])\nAC_MSG_NOTICE([Using bignum implementation: $set_bignum])\nAC_MSG_NOTICE([Using scalar implementation: $set_scalar])\nAC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])\nAC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])\nAC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])\nAC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])\nAC_MSG_NOTICE([Using jni: $use_jni])\n\nif test x\"$enable_experimental\" = x\"yes\"; then\n  AC_MSG_NOTICE([******])\n  AC_MSG_NOTICE([WARNING: experimental build])\n  AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])\n  AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])\n  AC_MSG_NOTICE([******])\nelse\n  if test x\"$enable_module_ecdh\" = x\"yes\"; then\n    AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])\n  fi\n  if test x\"$set_asm\" = x\"arm\"; then\n    AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])\n  fi\nfi\n\nAC_CONFIG_HEADERS([src/libsecp256k1-config.h])\nAC_CONFIG_FILES([Makefile libsecp256k1.pc])\nAC_SUBST(JNI_INCLUDES)\nAC_SUBST(SECP_INCLUDES)\nAC_SUBST(SECP_LIBS)\nAC_SUBST(SECP_TEST_LIBS)\nAC_SUBST(SECP_TEST_INCLUDES)\nAM_CONDITIONAL([ENABLE_COVERAGE], [test x\"$enable_coverage\" = x\"yes\"])\nAM_CONDITIONAL([USE_TESTS], [test x\"$use_tests\" != x\"no\"])\nAM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x\"$use_exhaustive_tests\" != x\"no\"])\nAM_CONDITIONAL([USE_BENCHMARK], [test x\"$use_benchmark\" = x\"yes\"])\nAM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x\"$set_precomp\" = x\"yes\"])\nAM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x\"$enable_module_ecdh\" = x\"yes\"])\nAM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x\"$enable_module_recovery\" = x\"yes\"])\nAM_CONDITIONAL([USE_JNI], [test x\"$use_jni\" == x\"yes\"])\nAM_CONDITIONAL([USE_EXTERNAL_ASM], [test x\"$use_external_asm\" = x\"yes\"])\nAM_CONDITIONAL([USE_ASM_ARM], [test x\"$set_asm\" = x\"arm\"])\n\ndnl make sure nothing new is exported so that we don't break the cache\nPKGCONFIG_PATH_TEMP=\"$PKG_CONFIG_PATH\"\nunset PKG_CONFIG_PATH\nPKG_CONFIG_PATH=\"$PKGCONFIG_PATH_TEMP\"\n\nAC_OUTPUT\n"
  },
  {
    "path": "src/secp256k1/contrib/lax_der_parsing.c",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include <string.h>\n#include <secp256k1.h>\n\n#include \"lax_der_parsing.h\"\n\nint ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {\n    size_t rpos, rlen, spos, slen;\n    size_t pos = 0;\n    size_t lenbyte;\n    unsigned char tmpsig[64] = {0};\n    int overflow = 0;\n\n    /* Hack to initialize sig with a correctly-parsed but invalid signature. */\n    secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n\n    /* Sequence tag byte */\n    if (pos == inputlen || input[pos] != 0x30) {\n        return 0;\n    }\n    pos++;\n\n    /* Sequence length bytes */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        pos += lenbyte;\n    }\n\n    /* Integer tag byte for R */\n    if (pos == inputlen || input[pos] != 0x02) {\n        return 0;\n    }\n    pos++;\n\n    /* Integer length for R */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        while (lenbyte > 0 && input[pos] == 0) {\n            pos++;\n            lenbyte--;\n        }\n        if (lenbyte >= sizeof(size_t)) {\n            return 0;\n        }\n        rlen = 0;\n        while (lenbyte > 0) {\n            rlen = (rlen << 8) + input[pos];\n            pos++;\n            lenbyte--;\n        }\n    } else {\n        rlen = lenbyte;\n    }\n    if (rlen > inputlen - pos) {\n        return 0;\n    }\n    rpos = pos;\n    pos += rlen;\n\n    /* Integer tag byte for S */\n    if (pos == inputlen || input[pos] != 0x02) {\n        return 0;\n    }\n    pos++;\n\n    /* Integer length for S */\n    if (pos == inputlen) {\n        return 0;\n    }\n    lenbyte = input[pos++];\n    if (lenbyte & 0x80) {\n        lenbyte -= 0x80;\n        if (pos + lenbyte > inputlen) {\n            return 0;\n        }\n        while (lenbyte > 0 && input[pos] == 0) {\n            pos++;\n            lenbyte--;\n        }\n        if (lenbyte >= sizeof(size_t)) {\n            return 0;\n        }\n        slen = 0;\n        while (lenbyte > 0) {\n            slen = (slen << 8) + input[pos];\n            pos++;\n            lenbyte--;\n        }\n    } else {\n        slen = lenbyte;\n    }\n    if (slen > inputlen - pos) {\n        return 0;\n    }\n    spos = pos;\n    pos += slen;\n\n    /* Ignore leading zeroes in R */\n    while (rlen > 0 && input[rpos] == 0) {\n        rlen--;\n        rpos++;\n    }\n    /* Copy R value */\n    if (rlen > 32) {\n        overflow = 1;\n    } else {\n        memcpy(tmpsig + 32 - rlen, input + rpos, rlen);\n    }\n\n    /* Ignore leading zeroes in S */\n    while (slen > 0 && input[spos] == 0) {\n        slen--;\n        spos++;\n    }\n    /* Copy S value */\n    if (slen > 32) {\n        overflow = 1;\n    } else {\n        memcpy(tmpsig + 64 - slen, input + spos, slen);\n    }\n\n    if (!overflow) {\n        overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n    }\n    if (overflow) {\n        memset(tmpsig, 0, 64);\n        secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);\n    }\n    return 1;\n}\n\n"
  },
  {
    "path": "src/secp256k1/contrib/lax_der_parsing.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n/****\n * Please do not link this file directly. It is not part of the libsecp256k1\n * project and does not promise any stability in its API, functionality or\n * presence. Projects which use this code should instead copy this header\n * and its accompanying .c file directly into their codebase.\n ****/\n\n/* This file defines a function that parses DER with various errors and\n * violations. This is not a part of the library itself, because the allowed\n * violations are chosen arbitrarily and do not follow or establish any\n * standard.\n *\n * In many places it matters that different implementations do not only accept\n * the same set of valid signatures, but also reject the same set of signatures.\n * The only means to accomplish that is by strictly obeying a standard, and not\n * accepting anything else.\n *\n * Nonetheless, sometimes there is a need for compatibility with systems that\n * use signatures which do not strictly obey DER. The snippet below shows how\n * certain violations are easily supported. You may need to adapt it.\n *\n * Do not use this for new systems. Use well-defined DER or compact signatures\n * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and\n * secp256k1_ecdsa_signature_parse_compact).\n *\n * The supported violations are:\n * - All numbers are parsed as nonnegative integers, even though X.609-0207\n *   section 8.3.3 specifies that integers are always encoded as two's\n *   complement.\n * - Integers can have length 0, even though section 8.3.1 says they can't.\n * - Integers with overly long padding are accepted, violation section\n *   8.3.2.\n * - 127-byte long length descriptors are accepted, even though section\n *   8.1.3.5.c says that they are not.\n * - Trailing garbage data inside or after the signature is ignored.\n * - The length descriptor of the sequence is ignored.\n *\n * Compared to for example OpenSSL, many violations are NOT supported:\n * - Using overly long tag descriptors for the sequence or integers inside,\n *   violating section 8.1.2.2.\n * - Encoding primitive integers as constructed values, violating section\n *   8.3.1.\n */\n\n#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_\n#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_\n\n#include <secp256k1.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/** Parse a signature in \"lax DER\" format\n *\n *  Returns: 1 when the signature could be parsed, 0 otherwise.\n *  Args: ctx:      a secp256k1 context object\n *  Out:  sig:      a pointer to a signature object\n *  In:   input:    a pointer to the signature to be parsed\n *        inputlen: the length of the array pointed to be input\n *\n *  This function will accept any valid DER encoded signature, even if the\n *  encoded numbers are out of range. In addition, it will accept signatures\n *  which violate the DER spec in various ways. Its purpose is to allow\n *  validation of the Bitcoin blockchain, which includes non-DER signatures\n *  from before the network rules were updated to enforce DER. Note that\n *  the set of supported violations is a strict subset of what OpenSSL will\n *  accept.\n *\n *  After the call, sig will always be initialized. If parsing failed or the\n *  encoded numbers are out of range, signature validation with it is\n *  guaranteed to fail for every message and public key.\n */\nint ecdsa_signature_parse_der_lax(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature* sig,\n    const unsigned char *input,\n    size_t inputlen\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/contrib/lax_der_privatekey_parsing.c",
    "content": "/**********************************************************************\n * Copyright (c) 2014, 2015 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include <string.h>\n#include <secp256k1.h>\n\n#include \"lax_der_privatekey_parsing.h\"\n\nint ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {\n    const unsigned char *end = privkey + privkeylen;\n    int lenb = 0;\n    int len = 0;\n    memset(out32, 0, 32);\n    /* sequence header */\n    if (end < privkey+1 || *privkey != 0x30) {\n        return 0;\n    }\n    privkey++;\n    /* sequence length constructor */\n    if (end < privkey+1 || !(*privkey & 0x80)) {\n        return 0;\n    }\n    lenb = *privkey & ~0x80; privkey++;\n    if (lenb < 1 || lenb > 2) {\n        return 0;\n    }\n    if (end < privkey+lenb) {\n        return 0;\n    }\n    /* sequence length */\n    len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);\n    privkey += lenb;\n    if (end < privkey+len) {\n        return 0;\n    }\n    /* sequence element 0: version number (=1) */\n    if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {\n        return 0;\n    }\n    privkey += 3;\n    /* sequence element 1: octet string, up to 32 bytes */\n    if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {\n        return 0;\n    }\n    memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);\n    if (!secp256k1_ec_seckey_verify(ctx, out32)) {\n        memset(out32, 0, 32);\n        return 0;\n    }\n    return 1;\n}\n\nint ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {\n    secp256k1_pubkey pubkey;\n    size_t pubkeylen = 0;\n    if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {\n        *privkeylen = 0;\n        return 0;\n    }\n    if (compressed) {\n        static const unsigned char begin[] = {\n            0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20\n        };\n        static const unsigned char middle[] = {\n            0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,\n            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,\n            0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,\n            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,\n            0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,\n            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00\n        };\n        unsigned char *ptr = privkey;\n        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);\n        memcpy(ptr, key32, 32); ptr += 32;\n        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);\n        pubkeylen = 33;\n        secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);\n        ptr += pubkeylen;\n        *privkeylen = ptr - privkey;\n    } else {\n        static const unsigned char begin[] = {\n            0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20\n        };\n        static const unsigned char middle[] = {\n            0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,\n            0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,\n            0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,\n            0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,\n            0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,\n            0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,\n            0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,\n            0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00\n        };\n        unsigned char *ptr = privkey;\n        memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);\n        memcpy(ptr, key32, 32); ptr += 32;\n        memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);\n        pubkeylen = 65;\n        secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);\n        ptr += pubkeylen;\n        *privkeylen = ptr - privkey;\n    }\n    return 1;\n}\n"
  },
  {
    "path": "src/secp256k1/contrib/lax_der_privatekey_parsing.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014, 2015 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n/****\n * Please do not link this file directly. It is not part of the libsecp256k1\n * project and does not promise any stability in its API, functionality or\n * presence. Projects which use this code should instead copy this header\n * and its accompanying .c file directly into their codebase.\n ****/\n\n/* This file contains code snippets that parse DER private keys with\n * various errors and violations.  This is not a part of the library\n * itself, because the allowed violations are chosen arbitrarily and\n * do not follow or establish any standard.\n *\n * It also contains code to serialize private keys in a compatible\n * manner.\n *\n * These functions are meant for compatibility with applications\n * that require BER encoded keys. When working with secp256k1-specific\n * code, the simple 32-byte private keys normally used by the\n * library are sufficient.\n */\n\n#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_\n#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_\n\n#include <secp256k1.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/** Export a private key in DER format.\n *\n *  Returns: 1 if the private key was valid.\n *  Args: ctx:        pointer to a context object, initialized for signing (cannot\n *                    be NULL)\n *  Out: privkey:     pointer to an array for storing the private key in BER.\n *                    Should have space for 279 bytes, and cannot be NULL.\n *       privkeylen:  Pointer to an int where the length of the private key in\n *                    privkey will be stored.\n *  In:  seckey:      pointer to a 32-byte secret key to export.\n *       compressed:  1 if the key should be exported in\n *                    compressed format, 0 otherwise\n *\n *  This function is purely meant for compatibility with applications that\n *  require BER encoded keys. When working with secp256k1-specific code, the\n *  simple 32-byte private keys are sufficient.\n *\n *  Note that this function does not guarantee correct DER output. It is\n *  guaranteed to be parsable by secp256k1_ec_privkey_import_der\n */\nSECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(\n    const secp256k1_context* ctx,\n    unsigned char *privkey,\n    size_t *privkeylen,\n    const unsigned char *seckey,\n    int compressed\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Import a private key in DER format.\n * Returns: 1 if a private key was extracted.\n * Args: ctx:        pointer to a context object (cannot be NULL).\n * Out:  seckey:     pointer to a 32-byte array for storing the private key.\n *                   (cannot be NULL).\n * In:   privkey:    pointer to a private key in DER format (cannot be NULL).\n *       privkeylen: length of the DER private key pointed to be privkey.\n *\n * This function will accept more than just strict DER, and even allow some BER\n * violations. The public key stored inside the DER-encoded private key is not\n * verified for correctness, nor are the curve parameters. Use this function\n * only if you know in advance it is supposed to contain a secp256k1 private\n * key.\n */\nSECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(\n    const secp256k1_context* ctx,\n    unsigned char *seckey,\n    const unsigned char *privkey,\n    size_t privkeylen\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/include/secp256k1.h",
    "content": "#ifndef _SECP256K1_\n# define _SECP256K1_\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n#include <stddef.h>\n\n/* These rules specify the order of arguments in API calls:\n *\n * 1. Context pointers go first, followed by output arguments, combined\n *    output/input arguments, and finally input-only arguments.\n * 2. Array lengths always immediately the follow the argument whose length\n *    they describe, even if this violates rule 1.\n * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated\n *    later go first. This means: signatures, public nonces, private nonces,\n *    messages, public keys, secret keys, tweaks.\n * 4. Arguments that are not data pointers go last, from more complex to less\n *    complex: function pointers, algorithm names, messages, void pointers,\n *    counts, flags, booleans.\n * 5. Opaque data pointers follow the function pointer they are to be passed to.\n */\n\n/** Opaque data structure that holds context information (precomputed tables etc.).\n *\n *  The purpose of context structures is to cache large precomputed data tables\n *  that are expensive to construct, and also to maintain the randomization data\n *  for blinding.\n *\n *  Do not create a new context object for each operation, as construction is\n *  far slower than all other API calls (~100 times slower than an ECDSA\n *  verification).\n *\n *  A constructed context can safely be used from multiple threads\n *  simultaneously, but API call that take a non-const pointer to a context\n *  need exclusive access to it. In particular this is the case for\n *  secp256k1_context_destroy and secp256k1_context_randomize.\n *\n *  Regarding randomization, either do it once at creation time (in which case\n *  you do not need any locking for the other calls), or use a read-write lock.\n */\ntypedef struct secp256k1_context_struct secp256k1_context;\n\n/** Opaque data structure that holds a parsed and valid public key.\n *\n *  The exact representation of data inside is implementation defined and not\n *  guaranteed to be portable between different platforms or versions. It is\n *  however guaranteed to be 64 bytes in size, and can be safely copied/moved.\n *  If you need to convert to a format suitable for storage, transmission, or\n *  comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.\n */\ntypedef struct {\n    unsigned char data[64];\n} secp256k1_pubkey;\n\n/** Opaque data structured that holds a parsed ECDSA signature.\n *\n *  The exact representation of data inside is implementation defined and not\n *  guaranteed to be portable between different platforms or versions. It is\n *  however guaranteed to be 64 bytes in size, and can be safely copied/moved.\n *  If you need to convert to a format suitable for storage, transmission, or\n *  comparison, use the secp256k1_ecdsa_signature_serialize_* and\n *  secp256k1_ecdsa_signature_serialize_* functions.\n */\ntypedef struct {\n    unsigned char data[64];\n} secp256k1_ecdsa_signature;\n\n/** A pointer to a function to deterministically generate a nonce.\n *\n * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.\n * Out:     nonce32:   pointer to a 32-byte array to be filled by the function.\n * In:      msg32:     the 32-byte message hash being verified (will not be NULL)\n *          key32:     pointer to a 32-byte secret key (will not be NULL)\n *          algo16:    pointer to a 16-byte array describing the signature\n *                     algorithm (will be NULL for ECDSA for compatibility).\n *          data:      Arbitrary data pointer that is passed through.\n *          attempt:   how many iterations we have tried to find a nonce.\n *                     This will almost always be 0, but different attempt values\n *                     are required to result in a different nonce.\n *\n * Except for test cases, this function should compute some cryptographic hash of\n * the message, the algorithm, the key and the attempt.\n */\ntypedef int (*secp256k1_nonce_function)(\n    unsigned char *nonce32,\n    const unsigned char *msg32,\n    const unsigned char *key32,\n    const unsigned char *algo16,\n    void *data,\n    unsigned int attempt\n);\n\n# if !defined(SECP256K1_GNUC_PREREQ)\n#  if defined(__GNUC__)&&defined(__GNUC_MINOR__)\n#   define SECP256K1_GNUC_PREREQ(_maj,_min) \\\n ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))\n#  else\n#   define SECP256K1_GNUC_PREREQ(_maj,_min) 0\n#  endif\n# endif\n\n# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )\n#  if SECP256K1_GNUC_PREREQ(2,7)\n#   define SECP256K1_INLINE __inline__\n#  elif (defined(_MSC_VER))\n#   define SECP256K1_INLINE __inline\n#  else\n#   define SECP256K1_INLINE\n#  endif\n# else\n#  define SECP256K1_INLINE inline\n# endif\n\n#ifndef SECP256K1_API\n# if defined(_WIN32)\n#  ifdef SECP256K1_BUILD\n#   define SECP256K1_API __declspec(dllexport)\n#  else\n#   define SECP256K1_API\n#  endif\n# elif defined(__GNUC__) && defined(SECP256K1_BUILD)\n#  define SECP256K1_API __attribute__ ((visibility (\"default\")))\n# else\n#  define SECP256K1_API\n# endif\n#endif\n\n/**Warning attributes\n  * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out\n  * some paranoid null checks. */\n# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)\n#  define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))\n# else\n#  define SECP256K1_WARN_UNUSED_RESULT\n# endif\n# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)\n#  define SECP256K1_ARG_NONNULL(_x)  __attribute__ ((__nonnull__(_x)))\n# else\n#  define SECP256K1_ARG_NONNULL(_x)\n# endif\n\n/** All flags' lower 8 bits indicate what they're for. Do not use directly. */\n#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)\n#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)\n#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)\n/** The higher bits contain the actual data. Do not use directly. */\n#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)\n#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)\n#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)\n\n/** Flags to pass to secp256k1_context_create. */\n#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)\n#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)\n#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)\n\n/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */\n#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)\n#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)\n\n/** Create a secp256k1 context object.\n *\n *  Returns: a newly created context object.\n *  In:      flags: which parts of the context to initialize.\n *\n *  See also secp256k1_context_randomize.\n */\nSECP256K1_API secp256k1_context* secp256k1_context_create(\n    unsigned int flags\n) SECP256K1_WARN_UNUSED_RESULT;\n\n/** Copies a secp256k1 context object.\n *\n *  Returns: a newly created context object.\n *  Args:    ctx: an existing context to copy (cannot be NULL)\n */\nSECP256K1_API secp256k1_context* secp256k1_context_clone(\n    const secp256k1_context* ctx\n) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;\n\n/** Destroy a secp256k1 context object.\n *\n *  The context pointer may not be used afterwards.\n *  Args:   ctx: an existing context to destroy (cannot be NULL)\n */\nSECP256K1_API void secp256k1_context_destroy(\n    secp256k1_context* ctx\n);\n\n/** Set a callback function to be called when an illegal argument is passed to\n *  an API call. It will only trigger for violations that are mentioned\n *  explicitly in the header.\n *\n *  The philosophy is that these shouldn't be dealt with through a\n *  specific return value, as calling code should not have branches to deal with\n *  the case that this code itself is broken.\n *\n *  On the other hand, during debug stage, one would want to be informed about\n *  such mistakes, and the default (crashing) may be inadvisable.\n *  When this callback is triggered, the API function called is guaranteed not\n *  to cause a crash, though its return value and output arguments are\n *  undefined.\n *\n *  Args: ctx:  an existing context object (cannot be NULL)\n *  In:   fun:  a pointer to a function to call when an illegal argument is\n *              passed to the API, taking a message and an opaque pointer\n *              (NULL restores a default handler that calls abort).\n *        data: the opaque pointer to pass to fun above.\n */\nSECP256K1_API void secp256k1_context_set_illegal_callback(\n    secp256k1_context* ctx,\n    void (*fun)(const char* message, void* data),\n    const void* data\n) SECP256K1_ARG_NONNULL(1);\n\n/** Set a callback function to be called when an internal consistency check\n *  fails. The default is crashing.\n *\n *  This can only trigger in case of a hardware failure, miscompilation,\n *  memory corruption, serious bug in the library, or other error would can\n *  otherwise result in undefined behaviour. It will not trigger due to mere\n *  incorrect usage of the API (see secp256k1_context_set_illegal_callback\n *  for that). After this callback returns, anything may happen, including\n *  crashing.\n *\n *  Args: ctx:  an existing context object (cannot be NULL)\n *  In:   fun:  a pointer to a function to call when an internal error occurs,\n *              taking a message and an opaque pointer (NULL restores a default\n *              handler that calls abort).\n *        data: the opaque pointer to pass to fun above.\n */\nSECP256K1_API void secp256k1_context_set_error_callback(\n    secp256k1_context* ctx,\n    void (*fun)(const char* message, void* data),\n    const void* data\n) SECP256K1_ARG_NONNULL(1);\n\n/** Parse a variable-length public key into the pubkey object.\n *\n *  Returns: 1 if the public key was fully valid.\n *           0 if the public key could not be parsed or is invalid.\n *  Args: ctx:      a secp256k1 context object.\n *  Out:  pubkey:   pointer to a pubkey object. If 1 is returned, it is set to a\n *                  parsed version of input. If not, its value is undefined.\n *  In:   input:    pointer to a serialized public key\n *        inputlen: length of the array pointed to by input\n *\n *  This function supports parsing compressed (33 bytes, header byte 0x02 or\n *  0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header\n *  byte 0x06 or 0x07) format public keys.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey* pubkey,\n    const unsigned char *input,\n    size_t inputlen\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Serialize a pubkey object into a serialized byte sequence.\n *\n *  Returns: 1 always.\n *  Args:   ctx:        a secp256k1 context object.\n *  Out:    output:     a pointer to a 65-byte (if compressed==0) or 33-byte (if\n *                      compressed==1) byte array to place the serialized key\n *                      in.\n *  In/Out: outputlen:  a pointer to an integer which is initially set to the\n *                      size of output, and is overwritten with the written\n *                      size.\n *  In:     pubkey:     a pointer to a secp256k1_pubkey containing an\n *                      initialized public key.\n *          flags:      SECP256K1_EC_COMPRESSED if serialization should be in\n *                      compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.\n */\nSECP256K1_API int secp256k1_ec_pubkey_serialize(\n    const secp256k1_context* ctx,\n    unsigned char *output,\n    size_t *outputlen,\n    const secp256k1_pubkey* pubkey,\n    unsigned int flags\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Parse an ECDSA signature in compact (64 bytes) format.\n *\n *  Returns: 1 when the signature could be parsed, 0 otherwise.\n *  Args: ctx:      a secp256k1 context object\n *  Out:  sig:      a pointer to a signature object\n *  In:   input64:  a pointer to the 64-byte array to parse\n *\n *  The signature must consist of a 32-byte big endian R value, followed by a\n *  32-byte big endian S value. If R or S fall outside of [0..order-1], the\n *  encoding is invalid. R and S with value 0 are allowed in the encoding.\n *\n *  After the call, sig will always be initialized. If parsing failed or R or\n *  S are zero, the resulting sig value is guaranteed to fail validation for any\n *  message and public key.\n */\nSECP256K1_API int secp256k1_ecdsa_signature_parse_compact(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature* sig,\n    const unsigned char *input64\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Parse a DER ECDSA signature.\n *\n *  Returns: 1 when the signature could be parsed, 0 otherwise.\n *  Args: ctx:      a secp256k1 context object\n *  Out:  sig:      a pointer to a signature object\n *  In:   input:    a pointer to the signature to be parsed\n *        inputlen: the length of the array pointed to be input\n *\n *  This function will accept any valid DER encoded signature, even if the\n *  encoded numbers are out of range.\n *\n *  After the call, sig will always be initialized. If parsing failed or the\n *  encoded numbers are out of range, signature validation with it is\n *  guaranteed to fail for every message and public key.\n */\nSECP256K1_API int secp256k1_ecdsa_signature_parse_der(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature* sig,\n    const unsigned char *input,\n    size_t inputlen\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Serialize an ECDSA signature in DER format.\n *\n *  Returns: 1 if enough space was available to serialize, 0 otherwise\n *  Args:   ctx:       a secp256k1 context object\n *  Out:    output:    a pointer to an array to store the DER serialization\n *  In/Out: outputlen: a pointer to a length integer. Initially, this integer\n *                     should be set to the length of output. After the call\n *                     it will be set to the length of the serialization (even\n *                     if 0 was returned).\n *  In:     sig:       a pointer to an initialized signature object\n */\nSECP256K1_API int secp256k1_ecdsa_signature_serialize_der(\n    const secp256k1_context* ctx,\n    unsigned char *output,\n    size_t *outputlen,\n    const secp256k1_ecdsa_signature* sig\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Serialize an ECDSA signature in compact (64 byte) format.\n *\n *  Returns: 1\n *  Args:   ctx:       a secp256k1 context object\n *  Out:    output64:  a pointer to a 64-byte array to store the compact serialization\n *  In:     sig:       a pointer to an initialized signature object\n *\n *  See secp256k1_ecdsa_signature_parse_compact for details about the encoding.\n */\nSECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(\n    const secp256k1_context* ctx,\n    unsigned char *output64,\n    const secp256k1_ecdsa_signature* sig\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Verify an ECDSA signature.\n *\n *  Returns: 1: correct signature\n *           0: incorrect or unparseable signature\n *  Args:    ctx:       a secp256k1 context object, initialized for verification.\n *  In:      sig:       the signature being verified (cannot be NULL)\n *           msg32:     the 32-byte message hash being verified (cannot be NULL)\n *           pubkey:    pointer to an initialized public key to verify with (cannot be NULL)\n *\n * To avoid accepting malleable signatures, only ECDSA signatures in lower-S\n * form are accepted.\n *\n * If you need to accept ECDSA signatures from sources that do not obey this\n * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to\n * validation, but be aware that doing so results in malleable signatures.\n *\n * For details, see the comments for that function.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(\n    const secp256k1_context* ctx,\n    const secp256k1_ecdsa_signature *sig,\n    const unsigned char *msg32,\n    const secp256k1_pubkey *pubkey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Convert a signature to a normalized lower-S form.\n *\n *  Returns: 1 if sigin was not normalized, 0 if it already was.\n *  Args: ctx:    a secp256k1 context object\n *  Out:  sigout: a pointer to a signature to fill with the normalized form,\n *                or copy if the input was already normalized. (can be NULL if\n *                you're only interested in whether the input was already\n *                normalized).\n *  In:   sigin:  a pointer to a signature to check/normalize (cannot be NULL,\n *                can be identical to sigout)\n *\n *  With ECDSA a third-party can forge a second distinct signature of the same\n *  message, given a single initial signature, but without knowing the key. This\n *  is done by negating the S value modulo the order of the curve, 'flipping'\n *  the sign of the random point R which is not included in the signature.\n *\n *  Forgery of the same message isn't universally problematic, but in systems\n *  where message malleability or uniqueness of signatures is important this can\n *  cause issues. This forgery can be blocked by all verifiers forcing signers\n *  to use a normalized form.\n *\n *  The lower-S form reduces the size of signatures slightly on average when\n *  variable length encodings (such as DER) are used and is cheap to verify,\n *  making it a good choice. Security of always using lower-S is assured because\n *  anyone can trivially modify a signature after the fact to enforce this\n *  property anyway.\n *\n *  The lower S value is always between 0x1 and\n *  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,\n *  inclusive.\n *\n *  No other forms of ECDSA malleability are known and none seem likely, but\n *  there is no formal proof that ECDSA, even with this additional restriction,\n *  is free of other malleability. Commonly used serialization schemes will also\n *  accept various non-unique encodings, so care should be taken when this\n *  property is required for an application.\n *\n *  The secp256k1_ecdsa_sign function will by default create signatures in the\n *  lower-S form, and secp256k1_ecdsa_verify will not accept others. In case\n *  signatures come from a system that cannot enforce this property,\n *  secp256k1_ecdsa_signature_normalize must be called before verification.\n */\nSECP256K1_API int secp256k1_ecdsa_signature_normalize(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature *sigout,\n    const secp256k1_ecdsa_signature *sigin\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);\n\n/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.\n * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of\n * extra entropy.\n */\nSECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;\n\n/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */\nSECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;\n\n/** Create an ECDSA signature.\n *\n *  Returns: 1: signature created\n *           0: the nonce generation function failed, or the private key was invalid.\n *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)\n *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)\n *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)\n *           seckey: pointer to a 32-byte secret key (cannot be NULL)\n *           noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used\n *           ndata:  pointer to arbitrary data used by the nonce generation function (can be NULL)\n *\n * The created signature is always in lower-S form. See\n * secp256k1_ecdsa_signature_normalize for more details.\n */\nSECP256K1_API int secp256k1_ecdsa_sign(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature *sig,\n    const unsigned char *msg32,\n    const unsigned char *seckey,\n    secp256k1_nonce_function noncefp,\n    const void *ndata\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Verify an ECDSA secret key.\n *\n *  Returns: 1: secret key is valid\n *           0: secret key is invalid\n *  Args:    ctx: pointer to a context object (cannot be NULL)\n *  In:      seckey: pointer to a 32-byte secret key (cannot be NULL)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(\n    const secp256k1_context* ctx,\n    const unsigned char *seckey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);\n\n/** Compute the public key for a secret key.\n *\n *  Returns: 1: secret was valid, public key stores\n *           0: secret was invalid, try again\n *  Args:   ctx:        pointer to a context object, initialized for signing (cannot be NULL)\n *  Out:    pubkey:     pointer to the created public key (cannot be NULL)\n *  In:     seckey:     pointer to a 32-byte private key (cannot be NULL)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *pubkey,\n    const unsigned char *seckey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Negates a private key in place.\n *\n *  Returns: 1 always\n *  Args:   ctx:        pointer to a context object\n *  In/Out: pubkey:     pointer to the public key to be negated (cannot be NULL)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(\n    const secp256k1_context* ctx,\n    unsigned char *seckey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);\n\n/** Negates a public key in place.\n *\n *  Returns: 1 always\n *  Args:   ctx:        pointer to a context object\n *  In/Out: pubkey:     pointer to the public key to be negated (cannot be NULL)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *pubkey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);\n\n/** Tweak a private key by adding tweak to it.\n * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for\n *          uniformly random 32-byte arrays, or if the resulting private key\n *          would be invalid (only when the tweak is the complement of the\n *          private key). 1 otherwise.\n * Args:    ctx:    pointer to a context object (cannot be NULL).\n * In/Out:  seckey: pointer to a 32-byte private key.\n * In:      tweak:  pointer to a 32-byte tweak.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(\n    const secp256k1_context* ctx,\n    unsigned char *seckey,\n    const unsigned char *tweak\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Tweak a public key by adding tweak times the generator to it.\n * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for\n *          uniformly random 32-byte arrays, or if the resulting public key\n *          would be invalid (only when the tweak is the complement of the\n *          corresponding private key). 1 otherwise.\n * Args:    ctx:    pointer to a context object initialized for validation\n *                  (cannot be NULL).\n * In/Out:  pubkey: pointer to a public key object.\n * In:      tweak:  pointer to a 32-byte tweak.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *pubkey,\n    const unsigned char *tweak\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Tweak a private key by multiplying it by a tweak.\n * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for\n *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.\n * Args:   ctx:    pointer to a context object (cannot be NULL).\n * In/Out: seckey: pointer to a 32-byte private key.\n * In:     tweak:  pointer to a 32-byte tweak.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(\n    const secp256k1_context* ctx,\n    unsigned char *seckey,\n    const unsigned char *tweak\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Tweak a public key by multiplying it by a tweak value.\n * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for\n *          uniformly random 32-byte arrays, or equal to zero. 1 otherwise.\n * Args:    ctx:    pointer to a context object initialized for validation\n *                 (cannot be NULL).\n * In/Out:  pubkey: pointer to a public key obkect.\n * In:      tweak:  pointer to a 32-byte tweak.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *pubkey,\n    const unsigned char *tweak\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Updates the context randomization to protect against side-channel leakage.\n *  Returns: 1: randomization successfully updated\n *           0: error\n *  Args:    ctx:       pointer to a context object (cannot be NULL)\n *  In:      seed32:    pointer to a 32-byte random seed (NULL resets to initial state)\n *\n * While secp256k1 code is written to be constant-time no matter what secret\n * values are, it's possible that a future compiler may output code which isn't,\n * and also that the CPU may not emit the same radio frequencies or draw the same\n * amount power for all values.\n *\n * This function provides a seed which is combined into the blinding value: that\n * blinding value is added before each multiplication (and removed afterwards) so\n * that it does not affect function results, but shields against attacks which\n * rely on any input-dependent behaviour.\n *\n * You should call this after secp256k1_context_create or\n * secp256k1_context_clone, and may call this repeatedly afterwards.\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(\n    secp256k1_context* ctx,\n    const unsigned char *seed32\n) SECP256K1_ARG_NONNULL(1);\n\n/** Add a number of public keys together.\n *  Returns: 1: the sum of the public keys is valid.\n *           0: the sum of the public keys is not valid.\n *  Args:   ctx:        pointer to a context object\n *  Out:    out:        pointer to a public key object for placing the resulting public key\n *                      (cannot be NULL)\n *  In:     ins:        pointer to array of pointers to public keys (cannot be NULL)\n *          n:          the number of public keys to add together (must be at least 1)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *out,\n    const secp256k1_pubkey * const * ins,\n    size_t n\n) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/include/secp256k1_ecdh.h",
    "content": "#ifndef _SECP256K1_ECDH_\n# define _SECP256K1_ECDH_\n\n# include \"secp256k1.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/** Compute an EC Diffie-Hellman secret in constant time\n *  Returns: 1: exponentiation was successful\n *           0: scalar was invalid (zero or overflow)\n *  Args:    ctx:        pointer to a context object (cannot be NULL)\n *  Out:     result:     a 32-byte array which will be populated by an ECDH\n *                       secret computed from the point and scalar\n *  In:      pubkey:     a pointer to a secp256k1_pubkey containing an\n *                       initialized public key\n *           privkey:    a 32-byte scalar with which to multiply the point\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(\n  const secp256k1_context* ctx,\n  unsigned char *result,\n  const secp256k1_pubkey *pubkey,\n  const unsigned char *privkey\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/include/secp256k1_recovery.h",
    "content": "#ifndef _SECP256K1_RECOVERY_\n# define _SECP256K1_RECOVERY_\n\n# include \"secp256k1.h\"\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n/** Opaque data structured that holds a parsed ECDSA signature,\n *  supporting pubkey recovery.\n *\n *  The exact representation of data inside is implementation defined and not\n *  guaranteed to be portable between different platforms or versions. It is\n *  however guaranteed to be 65 bytes in size, and can be safely copied/moved.\n *  If you need to convert to a format suitable for storage or transmission, use\n *  the secp256k1_ecdsa_signature_serialize_* and\n *  secp256k1_ecdsa_signature_parse_* functions.\n *\n *  Furthermore, it is guaranteed that identical signatures (including their\n *  recoverability) will have identical representation, so they can be\n *  memcmp'ed.\n */\ntypedef struct {\n    unsigned char data[65];\n} secp256k1_ecdsa_recoverable_signature;\n\n/** Parse a compact ECDSA signature (64 bytes + recovery id).\n *\n *  Returns: 1 when the signature could be parsed, 0 otherwise\n *  Args: ctx:     a secp256k1 context object\n *  Out:  sig:     a pointer to a signature object\n *  In:   input64: a pointer to a 64-byte compact signature\n *        recid:   the recovery id (0, 1, 2 or 3)\n */\nSECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_recoverable_signature* sig,\n    const unsigned char *input64,\n    int recid\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Convert a recoverable signature into a normal signature.\n *\n *  Returns: 1\n *  Out: sig:    a pointer to a normal signature (cannot be NULL).\n *  In:  sigin:  a pointer to a recoverable signature (cannot be NULL).\n */\nSECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_signature* sig,\n    const secp256k1_ecdsa_recoverable_signature* sigin\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);\n\n/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).\n *\n *  Returns: 1\n *  Args: ctx:      a secp256k1 context object\n *  Out:  output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)\n *        recid:    a pointer to an integer to hold the recovery id (can be NULL).\n *  In:   sig:      a pointer to an initialized signature object (cannot be NULL)\n */\nSECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(\n    const secp256k1_context* ctx,\n    unsigned char *output64,\n    int *recid,\n    const secp256k1_ecdsa_recoverable_signature* sig\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Create a recoverable ECDSA signature.\n *\n *  Returns: 1: signature created\n *           0: the nonce generation function failed, or the private key was invalid.\n *  Args:    ctx:    pointer to a context object, initialized for signing (cannot be NULL)\n *  Out:     sig:    pointer to an array where the signature will be placed (cannot be NULL)\n *  In:      msg32:  the 32-byte message hash being signed (cannot be NULL)\n *           seckey: pointer to a 32-byte secret key (cannot be NULL)\n *           noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used\n *           ndata:  pointer to arbitrary data used by the nonce generation function (can be NULL)\n */\nSECP256K1_API int secp256k1_ecdsa_sign_recoverable(\n    const secp256k1_context* ctx,\n    secp256k1_ecdsa_recoverable_signature *sig,\n    const unsigned char *msg32,\n    const unsigned char *seckey,\n    secp256k1_nonce_function noncefp,\n    const void *ndata\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n/** Recover an ECDSA public key from a signature.\n *\n *  Returns: 1: public key successfully recovered (which guarantees a correct signature).\n *           0: otherwise.\n *  Args:    ctx:        pointer to a context object, initialized for verification (cannot be NULL)\n *  Out:     pubkey:     pointer to the recovered public key (cannot be NULL)\n *  In:      sig:        pointer to initialized signature that supports pubkey recovery (cannot be NULL)\n *           msg32:      the 32-byte message hash assumed to be signed (cannot be NULL)\n */\nSECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(\n    const secp256k1_context* ctx,\n    secp256k1_pubkey *pubkey,\n    const secp256k1_ecdsa_recoverable_signature *sig,\n    const unsigned char *msg32\n) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/libsecp256k1.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libsecp256k1\nDescription: Optimized C library for EC operations on curve secp256k1\nURL: https://github.com/bitcoin-core/secp256k1\nVersion: @PACKAGE_VERSION@\nCflags: -I${includedir}\nLibs.private: @SECP_LIBS@\nLibs: -L${libdir} -lsecp256k1\n\n"
  },
  {
    "path": "src/secp256k1/obj/.gitignore",
    "content": ""
  },
  {
    "path": "src/secp256k1/sage/group_prover.sage",
    "content": "# This code supports verifying group implementations which have branches\n# or conditional statements (like cmovs), by allowing each execution path\n# to independently set assumptions on input or intermediary variables.\n#\n# The general approach is:\n# * A constraint is a tuple of two sets of of symbolic expressions:\n#   the first of which are required to evaluate to zero, the second of which\n#   are required to evaluate to nonzero.\n#   - A constraint is said to be conflicting if any of its nonzero expressions\n#     is in the ideal with basis the zero expressions (in other words: when the\n#     zero expressions imply that one of the nonzero expressions are zero).\n# * There is a list of laws that describe the intended behaviour, including\n#   laws for addition and doubling. Each law is called with the symbolic point\n#   coordinates as arguments, and returns:\n#   - A constraint describing the assumptions under which it is applicable,\n#     called \"assumeLaw\"\n#   - A constraint describing the requirements of the law, called \"require\"\n# * Implementations are transliterated into functions that operate as well on\n#   algebraic input points, and are called once per combination of branches\n#   exectured. Each execution returns:\n#   - A constraint describing the assumptions this implementation requires\n#     (such as Z1=1), called \"assumeFormula\"\n#   - A constraint describing the assumptions this specific branch requires,\n#     but which is by construction guaranteed to cover the entire space by\n#     merging the results from all branches, called \"assumeBranch\"\n#   - The result of the computation\n# * All combinations of laws with implementation branches are tried, and:\n#   - If the combination of assumeLaw, assumeFormula, and assumeBranch results\n#     in a conflict, it means this law does not apply to this branch, and it is\n#     skipped.\n#   - For others, we try to prove the require constraints hold, assuming the\n#     information in assumeLaw + assumeFormula + assumeBranch, and if this does\n#     not succeed, we fail.\n#     + To prove an expression is zero, we check whether it belongs to the\n#       ideal with the assumed zero expressions as basis. This test is exact.\n#     + To prove an expression is nonzero, we check whether each of its\n#       factors is contained in the set of nonzero assumptions' factors.\n#       This test is not exact, so various combinations of original and\n#       reduced expressions' factors are tried.\n#   - If we succeed, we print out the assumptions from assumeFormula that\n#     weren't implied by assumeLaw already. Those from assumeBranch are skipped,\n#     as we assume that all constraints in it are complementary with each other.\n#\n# Based on the sage verification scripts used in the Explicit-Formulas Database\n# by Tanja Lange and others, see http://hyperelliptic.org/EFD\n\nclass fastfrac:\n  \"\"\"Fractions over rings.\"\"\"\n\n  def __init__(self,R,top,bot=1):\n    \"\"\"Construct a fractional, given a ring, a numerator, and denominator.\"\"\"\n    self.R = R\n    if parent(top) == ZZ or parent(top) == R:\n      self.top = R(top)\n      self.bot = R(bot)\n    elif top.__class__ == fastfrac:\n      self.top = top.top\n      self.bot = top.bot * bot\n    else:\n      self.top = R(numerator(top))\n      self.bot = R(denominator(top)) * bot\n\n  def iszero(self,I):\n    \"\"\"Return whether this fraction is zero given an ideal.\"\"\"\n    return self.top in I and self.bot not in I\n\n  def reduce(self,assumeZero):\n    zero = self.R.ideal(map(numerator, assumeZero))\n    return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))\n\n  def __add__(self,other):\n    \"\"\"Add two fractions.\"\"\"\n    if parent(other) == ZZ:\n      return fastfrac(self.R,self.top + self.bot * other,self.bot)\n    if other.__class__ == fastfrac:\n      return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)\n    return NotImplemented\n\n  def __sub__(self,other):\n    \"\"\"Subtract two fractions.\"\"\"\n    if parent(other) == ZZ:\n      return fastfrac(self.R,self.top - self.bot * other,self.bot)\n    if other.__class__ == fastfrac:\n      return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)\n    return NotImplemented\n\n  def __neg__(self):\n    \"\"\"Return the negation of a fraction.\"\"\"\n    return fastfrac(self.R,-self.top,self.bot)\n\n  def __mul__(self,other):\n    \"\"\"Multiply two fractions.\"\"\"\n    if parent(other) == ZZ:\n      return fastfrac(self.R,self.top * other,self.bot)\n    if other.__class__ == fastfrac:\n      return fastfrac(self.R,self.top * other.top,self.bot * other.bot)\n    return NotImplemented\n\n  def __rmul__(self,other):\n    \"\"\"Multiply something else with a fraction.\"\"\"\n    return self.__mul__(other)\n\n  def __div__(self,other):\n    \"\"\"Divide two fractions.\"\"\"\n    if parent(other) == ZZ:\n      return fastfrac(self.R,self.top,self.bot * other)\n    if other.__class__ == fastfrac:\n      return fastfrac(self.R,self.top * other.bot,self.bot * other.top)\n    return NotImplemented\n\n  def __pow__(self,other):\n    \"\"\"Compute a power of a fraction.\"\"\"\n    if parent(other) == ZZ:\n      if other < 0:\n        # Negative powers require flipping top and bottom\n        return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))\n      else:\n        return fastfrac(self.R,self.top ^ other,self.bot ^ other)\n    return NotImplemented\n\n  def __str__(self):\n    return \"fastfrac((\" + str(self.top) + \") / (\" + str(self.bot) + \"))\"\n  def __repr__(self):\n    return \"%s\" % self\n\n  def numerator(self):\n    return self.top\n\nclass constraints:\n  \"\"\"A set of constraints, consisting of zero and nonzero expressions.\n\n  Constraints can either be used to express knowledge or a requirement.\n\n  Both the fields zero and nonzero are maps from expressions to description\n  strings. The expressions that are the keys in zero are required to be zero,\n  and the expressions that are the keys in nonzero are required to be nonzero.\n\n  Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in\n  nonzero could be multiplied into a single key. This is often much less\n  efficient to work with though, so we keep them separate inside the\n  constraints. This allows higher-level code to do fast checks on the individual\n  nonzero elements, or combine them if needed for stronger checks.\n\n  We can't multiply the different zero elements, as it would suffice for one of\n  the factors to be zero, instead of all of them. Instead, the zero elements are\n  typically combined into an ideal first.\n  \"\"\"\n\n  def __init__(self, **kwargs):\n    if 'zero' in kwargs:\n      self.zero = dict(kwargs['zero'])\n    else:\n      self.zero = dict()\n    if 'nonzero' in kwargs:\n      self.nonzero = dict(kwargs['nonzero'])\n    else:\n      self.nonzero = dict()\n\n  def negate(self):\n    return constraints(zero=self.nonzero, nonzero=self.zero)\n\n  def __add__(self, other):\n    zero = self.zero.copy()\n    zero.update(other.zero)\n    nonzero = self.nonzero.copy()\n    nonzero.update(other.nonzero)\n    return constraints(zero=zero, nonzero=nonzero)\n\n  def __str__(self):\n    return \"constraints(zero=%s,nonzero=%s)\" % (self.zero, self.nonzero)\n\n  def __repr__(self):\n    return \"%s\" % self\n\n\ndef conflicts(R, con):\n  \"\"\"Check whether any of the passed non-zero assumptions is implied by the zero assumptions\"\"\"\n  zero = R.ideal(map(numerator, con.zero))\n  if 1 in zero:\n    return True\n  # First a cheap check whether any of the individual nonzero terms conflict on\n  # their own.\n  for nonzero in con.nonzero:\n    if nonzero.iszero(zero):\n      return True\n  # It can be the case that entries in the nonzero set do not individually\n  # conflict with the zero set, but their combination does. For example, knowing\n  # that either x or y is zero is equivalent to having x*y in the zero set.\n  # Having x or y individually in the nonzero set is not a conflict, but both\n  # simultaneously is, so that is the right thing to check for.\n  if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):\n    return True\n  return False\n\n\ndef get_nonzero_set(R, assume):\n  \"\"\"Calculate a simple set of nonzero expressions\"\"\"\n  zero = R.ideal(map(numerator, assume.zero))\n  nonzero = set()\n  for nz in map(numerator, assume.nonzero):\n    for (f,n) in nz.factor():\n      nonzero.add(f)\n    rnz = zero.reduce(nz)\n    for (f,n) in rnz.factor():\n      nonzero.add(f)\n  return nonzero\n\n\ndef prove_nonzero(R, exprs, assume):\n  \"\"\"Check whether an expression is provably nonzero, given assumptions\"\"\"\n  zero = R.ideal(map(numerator, assume.zero))\n  nonzero = get_nonzero_set(R, assume)\n  expl = set()\n  ok = True\n  for expr in exprs:\n    if numerator(expr) in zero:\n      return (False, [exprs[expr]])\n  allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)\n  for (f, n) in allexprs.factor():\n    if f not in nonzero:\n      ok = False\n  if ok:\n    return (True, None)\n  ok = True\n  for (f, n) in zero.reduce(numerator(allexprs)).factor():\n    if f not in nonzero:\n      ok = False\n  if ok:\n    return (True, None)\n  ok = True\n  for expr in exprs:\n    for (f,n) in numerator(expr).factor():\n      if f not in nonzero:\n        ok = False\n  if ok:\n    return (True, None)\n  ok = True\n  for expr in exprs:\n    for (f,n) in zero.reduce(numerator(expr)).factor():\n      if f not in nonzero:\n        expl.add(exprs[expr])\n  if expl:\n    return (False, list(expl))\n  else:\n    return (True, None)\n\n\ndef prove_zero(R, exprs, assume):\n  \"\"\"Check whether all of the passed expressions are provably zero, given assumptions\"\"\"\n  r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)\n  if not r:\n    return (False, map(lambda x: \"Possibly zero denominator: %s\" % x, e))\n  zero = R.ideal(map(numerator, assume.zero))\n  nonzero = prod(x for x in assume.nonzero)\n  expl = []\n  for expr in exprs:\n    if not expr.iszero(zero):\n      expl.append(exprs[expr])\n  if not expl:\n    return (True, None)\n  return (False, expl)\n\n\ndef describe_extra(R, assume, assumeExtra):\n  \"\"\"Describe what assumptions are added, given existing assumptions\"\"\"\n  zerox = assume.zero.copy()\n  zerox.update(assumeExtra.zero)\n  zero = R.ideal(map(numerator, assume.zero))\n  zeroextra = R.ideal(map(numerator, zerox))\n  nonzero = get_nonzero_set(R, assume)\n  ret = set()\n  # Iterate over the extra zero expressions\n  for base in assumeExtra.zero:\n    if base not in zero:\n      add = []\n      for (f, n) in numerator(base).factor():\n        if f not in nonzero:\n          add += [\"%s\" % f]\n      if add:\n        ret.add((\" * \".join(add)) + \" = 0 [%s]\" % assumeExtra.zero[base])\n  # Iterate over the extra nonzero expressions\n  for nz in assumeExtra.nonzero:\n    nzr = zeroextra.reduce(numerator(nz))\n    if nzr not in zeroextra:\n      for (f,n) in nzr.factor():\n        if zeroextra.reduce(f) not in nonzero:\n          ret.add(\"%s != 0\" % zeroextra.reduce(f))\n  return \", \".join(x for x in ret)\n\n\ndef check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):\n  \"\"\"Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions\"\"\"\n  assume = assumeLaw + assumeAssert + assumeBranch\n\n  if conflicts(R, assume):\n    # This formula does not apply\n    return None\n\n  describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)\n\n  ok, msg = prove_zero(R, require.zero, assume)\n  if not ok:\n    return \"FAIL, %s fails (assuming %s)\" % (str(msg), describe)\n\n  res, expl = prove_nonzero(R, require.nonzero, assume)\n  if not res:\n    return \"FAIL, %s fails (assuming %s)\" % (str(expl), describe)\n\n  if describe != \"\":\n    return \"OK (assuming %s)\" % describe\n  else:\n    return \"OK\"\n\n\ndef concrete_verify(c):\n  for k in c.zero:\n    if k != 0:\n      return (False, c.zero[k])\n  for k in c.nonzero:\n    if k == 0:\n      return (False, c.nonzero[k])\n  return (True, None)\n"
  },
  {
    "path": "src/secp256k1/sage/secp256k1.sage",
    "content": "# Test libsecp256k1' group operation implementations using prover.sage\n\nimport sys\n\nload(\"group_prover.sage\")\nload(\"weierstrass_prover.sage\")\n\ndef formula_secp256k1_gej_double_var(a):\n  \"\"\"libsecp256k1's secp256k1_gej_double_var, used by various addition functions\"\"\"\n  rz = a.Z * a.Y\n  rz = rz * 2\n  t1 = a.X^2\n  t1 = t1 * 3\n  t2 = t1^2\n  t3 = a.Y^2\n  t3 = t3 * 2\n  t4 = t3^2\n  t4 = t4 * 2\n  t3 = t3 * a.X\n  rx = t3\n  rx = rx * 4\n  rx = -rx\n  rx = rx + t2\n  t2 = -t2\n  t3 = t3 * 6\n  t3 = t3 + t2\n  ry = t1 * t3\n  t2 = -t4\n  ry = ry + t2\n  return jacobianpoint(rx, ry, rz)\n\ndef formula_secp256k1_gej_add_var(branch, a, b):\n  \"\"\"libsecp256k1's secp256k1_gej_add_var\"\"\"\n  if branch == 0:\n    return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)\n  if branch == 1:\n    return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)\n  z22 = b.Z^2\n  z12 = a.Z^2\n  u1 = a.X * z22\n  u2 = b.X * z12\n  s1 = a.Y * z22\n  s1 = s1 * b.Z\n  s2 = b.Y * z12\n  s2 = s2 * a.Z\n  h = -u1\n  h = h + u2\n  i = -s1\n  i = i + s2\n  if branch == 2:\n    r = formula_secp256k1_gej_double_var(a)\n    return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)\n  if branch == 3:\n    return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())\n  i2 = i^2\n  h2 = h^2\n  h3 = h2 * h\n  h = h * b.Z\n  rz = a.Z * h\n  t = u1 * h2\n  rx = t\n  rx = rx * 2\n  rx = rx + h3\n  rx = -rx\n  rx = rx + i2\n  ry = -rx\n  ry = ry + t\n  ry = ry * i\n  h3 = h3 * s1\n  h3 = -h3\n  ry = ry + h3\n  return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))\n\ndef formula_secp256k1_gej_add_ge_var(branch, a, b):\n  \"\"\"libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1\"\"\"\n  if branch == 0:\n    return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b)\n  if branch == 1:\n    return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)\n  z12 = a.Z^2\n  u1 = a.X\n  u2 = b.X * z12\n  s1 = a.Y\n  s2 = b.Y * z12\n  s2 = s2 * a.Z\n  h = -u1\n  h = h + u2\n  i = -s1\n  i = i + s2\n  if (branch == 2):\n    r = formula_secp256k1_gej_double_var(a)\n    return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)\n  if (branch == 3):\n    return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())\n  i2 = i^2\n  h2 = h^2\n  h3 = h * h2\n  rz = a.Z * h\n  t = u1 * h2\n  rx = t\n  rx = rx * 2\n  rx = rx + h3\n  rx = -rx\n  rx = rx + i2\n  ry = -rx\n  ry = ry + t\n  ry = ry * i\n  h3 = h3 * s1\n  h3 = -h3\n  ry = ry + h3\n  return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))\n\ndef formula_secp256k1_gej_add_zinv_var(branch, a, b):\n  \"\"\"libsecp256k1's secp256k1_gej_add_zinv_var\"\"\"\n  bzinv = b.Z^(-1)\n  if branch == 0:\n    return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)\n  if branch == 1:\n    bzinv2 = bzinv^2\n    bzinv3 = bzinv2 * bzinv\n    rx = b.X * bzinv2\n    ry = b.Y * bzinv3\n    rz = 1\n    return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))\n  azz = a.Z * bzinv\n  z12 = azz^2\n  u1 = a.X\n  u2 = b.X * z12\n  s1 = a.Y\n  s2 = b.Y * z12\n  s2 = s2 * azz\n  h = -u1\n  h = h + u2\n  i = -s1\n  i = i + s2\n  if branch == 2:\n    r = formula_secp256k1_gej_double_var(a)\n    return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)\n  if branch == 3:\n    return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())\n  i2 = i^2\n  h2 = h^2\n  h3 = h * h2\n  rz = a.Z\n  rz = rz * h\n  t = u1 * h2\n  rx = t\n  rx = rx * 2\n  rx = rx + h3\n  rx = -rx\n  rx = rx + i2\n  ry = -rx\n  ry = ry + t\n  ry = ry * i\n  h3 = h3 * s1\n  h3 = -h3\n  ry = ry + h3\n  return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))\n\ndef formula_secp256k1_gej_add_ge(branch, a, b):\n  \"\"\"libsecp256k1's secp256k1_gej_add_ge\"\"\"\n  zeroes = {}\n  nonzeroes = {}\n  a_infinity = False\n  if (branch & 4) != 0:\n    nonzeroes.update({a.Infinity : 'a_infinite'})\n    a_infinity = True\n  else:\n    zeroes.update({a.Infinity : 'a_finite'})\n  zz = a.Z^2\n  u1 = a.X\n  u2 = b.X * zz\n  s1 = a.Y\n  s2 = b.Y * zz\n  s2 = s2 * a.Z\n  t = u1\n  t = t + u2\n  m = s1\n  m = m + s2\n  rr = t^2\n  m_alt = -u2\n  tt = u1 * m_alt\n  rr = rr + tt\n  degenerate = (branch & 3) == 3\n  if (branch & 1) != 0:\n    zeroes.update({m : 'm_zero'})\n  else:\n    nonzeroes.update({m : 'm_nonzero'})\n  if (branch & 2) != 0:\n    zeroes.update({rr : 'rr_zero'})\n  else:\n    nonzeroes.update({rr : 'rr_nonzero'})\n  rr_alt = s1\n  rr_alt = rr_alt * 2\n  m_alt = m_alt + u1\n  if not degenerate:\n    rr_alt = rr\n    m_alt = m\n  n = m_alt^2\n  q = n * t\n  n = n^2\n  if degenerate:\n    n = m\n  t = rr_alt^2\n  rz = a.Z * m_alt\n  infinity = False\n  if (branch & 8) != 0:\n    if not a_infinity:\n      infinity = True\n    zeroes.update({rz : 'r.z=0'})\n  else:\n    nonzeroes.update({rz : 'r.z!=0'})\n  rz = rz * 2\n  q = -q\n  t = t + q\n  rx = t\n  t = t * 2\n  t = t + q\n  t = t * rr_alt\n  t = t + n\n  ry = -t\n  rx = rx * 4\n  ry = ry * 4\n  if a_infinity:\n    rx = b.X\n    ry = b.Y\n    rz = 1\n  if infinity:\n    return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())\n  return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))\n\ndef formula_secp256k1_gej_add_ge_old(branch, a, b):\n  \"\"\"libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx\"\"\"\n  a_infinity = (branch & 1) != 0\n  zero = {}\n  nonzero = {}\n  if a_infinity:\n    nonzero.update({a.Infinity : 'a_infinite'})\n  else:\n    zero.update({a.Infinity : 'a_finite'})\n  zz = a.Z^2\n  u1 = a.X\n  u2 = b.X * zz\n  s1 = a.Y\n  s2 = b.Y * zz\n  s2 = s2 * a.Z\n  z = a.Z\n  t = u1\n  t = t + u2\n  m = s1\n  m = m + s2\n  n = m^2\n  q = n * t\n  n = n^2\n  rr = t^2\n  t = u1 * u2\n  t = -t\n  rr = rr + t\n  t = rr^2\n  rz = m * z\n  infinity = False\n  if (branch & 2) != 0:\n    if not a_infinity:\n      infinity = True\n    else:\n      return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())\n    zero.update({rz : 'r.z=0'})\n  else:\n    nonzero.update({rz : 'r.z!=0'})\n  rz = rz * (0 if a_infinity else 2)\n  rx = t\n  q = -q\n  rx = rx + q\n  q = q * 3\n  t = t * 2\n  t = t + q\n  t = t * rr\n  t = t + n\n  ry = -t\n  rx = rx * (0 if a_infinity else 4)\n  ry = ry * (0 if a_infinity else 4)\n  t = b.X\n  t = t * (1 if a_infinity else 0)\n  rx = rx + t\n  t = b.Y\n  t = t * (1 if a_infinity else 0)\n  ry = ry + t\n  t = (1 if a_infinity else 0)\n  rz = rz + t\n  if infinity:\n    return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())\n  return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))\n\nif __name__ == \"__main__\":\n  check_symbolic_jacobian_weierstrass(\"secp256k1_gej_add_var\", 0, 7, 5, formula_secp256k1_gej_add_var)\n  check_symbolic_jacobian_weierstrass(\"secp256k1_gej_add_ge_var\", 0, 7, 5, formula_secp256k1_gej_add_ge_var)\n  check_symbolic_jacobian_weierstrass(\"secp256k1_gej_add_zinv_var\", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)\n  check_symbolic_jacobian_weierstrass(\"secp256k1_gej_add_ge\", 0, 7, 16, formula_secp256k1_gej_add_ge)\n  check_symbolic_jacobian_weierstrass(\"secp256k1_gej_add_ge_old [should fail]\", 0, 7, 4, formula_secp256k1_gej_add_ge_old)\n\n  if len(sys.argv) >= 2 and sys.argv[1] == \"--exhaustive\":\n    check_exhaustive_jacobian_weierstrass(\"secp256k1_gej_add_var\", 0, 7, 5, formula_secp256k1_gej_add_var, 43)\n    check_exhaustive_jacobian_weierstrass(\"secp256k1_gej_add_ge_var\", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)\n    check_exhaustive_jacobian_weierstrass(\"secp256k1_gej_add_zinv_var\", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)\n    check_exhaustive_jacobian_weierstrass(\"secp256k1_gej_add_ge\", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)\n    check_exhaustive_jacobian_weierstrass(\"secp256k1_gej_add_ge_old [should fail]\", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)\n"
  },
  {
    "path": "src/secp256k1/sage/weierstrass_prover.sage",
    "content": "# Prover implementation for Weierstrass curves of the form\n# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws\n# operating on affine and Jacobian coordinates, including the point at infinity\n# represented by a 4th variable in coordinates.\n\nload(\"group_prover.sage\")\n\n\nclass affinepoint:\n  def __init__(self, x, y, infinity=0):\n    self.x = x\n    self.y = y\n    self.infinity = infinity\n  def __str__(self):\n    return \"affinepoint(x=%s,y=%s,inf=%s)\" % (self.x, self.y, self.infinity)\n\n\nclass jacobianpoint:\n  def __init__(self, x, y, z, infinity=0):\n    self.X = x\n    self.Y = y\n    self.Z = z\n    self.Infinity = infinity\n  def __str__(self):\n    return \"jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)\" % (self.X, self.Y, self.Z, self.Infinity)\n\n\ndef point_at_infinity():\n  return jacobianpoint(1, 1, 1, 1)\n\n\ndef negate(p):\n  if p.__class__ == affinepoint:\n    return affinepoint(p.x, -p.y)\n  if p.__class__ == jacobianpoint:\n    return jacobianpoint(p.X, -p.Y, p.Z)\n  assert(False)\n\n\ndef on_weierstrass_curve(A, B, p):\n  \"\"\"Return a set of zero-expressions for an affine point to be on the curve\"\"\"\n  return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})\n\n\ndef tangential_to_weierstrass_curve(A, B, p12, p3):\n  \"\"\"Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)\"\"\"\n  return constraints(zero={\n    (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'\n  })\n\n\ndef colinear(p1, p2, p3):\n  \"\"\"Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear\"\"\"\n  return constraints(zero={\n    (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',\n    (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',\n    (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'\n  })\n\n\ndef good_affine_point(p):\n  return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})\n\n\ndef good_jacobian_point(p):\n  return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})\n\n\ndef good_point(p):\n  return constraints(nonzero={p.Z^6 : 'nonzero_X'})\n\n\ndef finite(p, *affine_fns):\n  con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})\n  if p.Z != 0:\n    return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)\n  else:\n    return con\n\ndef infinite(p):\n  return constraints(nonzero={p.Infinity : 'infinite_point'})\n\n\ndef law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):\n  \"\"\"Check whether the passed set of coordinates is a valid Jacobian add, given assumptions\"\"\"\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               on_weierstrass_curve(A, B, pa) +\n               on_weierstrass_curve(A, B, pb) +\n               finite(pA) +\n               finite(pB) +\n               constraints(nonzero={pa.x - pb.x : 'different_x'}))\n  require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +\n             colinear(pa, pb, negate(pc))))\n  return (assumeLaw, require)\n\n\ndef law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):\n  \"\"\"Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions\"\"\"\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               on_weierstrass_curve(A, B, pa) +\n               on_weierstrass_curve(A, B, pb) +\n               finite(pA) +\n               finite(pB) +\n               constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))\n  require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +\n             tangential_to_weierstrass_curve(A, B, pa, negate(pc))))\n  return (assumeLaw, require)\n\n\ndef law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               on_weierstrass_curve(A, B, pa) +\n               on_weierstrass_curve(A, B, pb) +\n               finite(pA) +\n               finite(pB) +\n               constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))\n  require = infinite(pC)\n  return (assumeLaw, require)\n\n\ndef law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               on_weierstrass_curve(A, B, pb) +\n               infinite(pA) +\n               finite(pB))\n  require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))\n  return (assumeLaw, require)\n\n\ndef law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               on_weierstrass_curve(A, B, pa) +\n               infinite(pB) +\n               finite(pA))\n  require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))\n  return (assumeLaw, require)\n\n\ndef law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):\n  assumeLaw = (good_affine_point(pa) +\n               good_affine_point(pb) +\n               good_jacobian_point(pA) +\n               good_jacobian_point(pB) +\n               infinite(pA) +\n               infinite(pB))\n  require = infinite(pC)\n  return (assumeLaw, require)\n\n\nlaws_jacobian_weierstrass = {\n  'add': law_jacobian_weierstrass_add,\n  'double': law_jacobian_weierstrass_double,\n  'add_opposite': law_jacobian_weierstrass_add_opposites,\n  'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,\n  'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,\n  'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab\n}\n\n\ndef check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):\n  \"\"\"Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field\"\"\"\n  F = Integers(p)\n  print \"Formula %s on Z%i:\" % (name, p)\n  points = []\n  for x in xrange(0, p):\n    for y in xrange(0, p):\n      point = affinepoint(F(x), F(y))\n      r, e = concrete_verify(on_weierstrass_curve(A, B, point))\n      if r:\n        points.append(point)\n\n  for za in xrange(1, p):\n    for zb in xrange(1, p):\n      for pa in points:\n        for pb in points:\n          for ia in xrange(2):\n            for ib in xrange(2):\n              pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)\n              pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)\n              for branch in xrange(0, branches):\n                assumeAssert, assumeBranch, pC = formula(branch, pA, pB)\n                pC.X = F(pC.X)\n                pC.Y = F(pC.Y)\n                pC.Z = F(pC.Z)\n                pC.Infinity = F(pC.Infinity)\n                r, e = concrete_verify(assumeAssert + assumeBranch)\n                if r:\n                  match = False\n                  for key in laws_jacobian_weierstrass:\n                    assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)\n                    r, e = concrete_verify(assumeLaw)\n                    if r:\n                      if match:\n                        print \"  multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)\" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)\n                      else:\n                        match = True\n                      r, e = concrete_verify(require)\n                      if not r:\n                        print \"  failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s\" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)\n  print\n\n\ndef check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):\n  assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)\n  return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)\n\ndef check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):\n  \"\"\"Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically\"\"\"\n  R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')\n  lift = lambda x: fastfrac(R,x)\n  ax = lift(ax)\n  ay = lift(ay)\n  Az = lift(Az)\n  bx = lift(bx)\n  by = lift(by)\n  Bz = lift(Bz)\n  Ai = lift(Ai)\n  Bi = lift(Bi)\n\n  pa = affinepoint(ax, ay, Ai)\n  pb = affinepoint(bx, by, Bi)\n  pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)\n  pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)\n\n  res = {}\n\n  for key in laws_jacobian_weierstrass:\n    res[key] = []\n\n  print (\"Formula \" + name + \":\")\n  count = 0\n  for branch in xrange(branches):\n    assumeFormula, assumeBranch, pC = formula(branch, pA, pB)\n    pC.X = lift(pC.X)\n    pC.Y = lift(pC.Y)\n    pC.Z = lift(pC.Z)\n    pC.Infinity = lift(pC.Infinity)\n\n    for key in laws_jacobian_weierstrass:\n      res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))\n\n  for key in res:\n    print \"  %s:\" % key\n    val = res[key]\n    for x in val:\n      if x[0] is not None:\n        print \"    branch %i: %s\" % (x[1], x[0])\n\n  print\n"
  },
  {
    "path": "src/secp256k1/src/asm/field_10x26_arm.s",
    "content": "@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:\n/**********************************************************************\n * Copyright (c) 2014 Wladimir J. van der Laan                        *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n/*\nARM implementation of field_10x26 inner loops.\n\nNote:\n\n- To avoid unnecessary loads and make use of available registers, two\n  'passes' have every time been interleaved, with the odd passes accumulating c' and d' \n  which will be added to c and d respectively in the the even passes\n\n*/\n\n\t.syntax unified\n\t.arch armv7-a\n\t@ eabi attributes - see readelf -A\n\t.eabi_attribute 8, 1  @ Tag_ARM_ISA_use = yes\n\t.eabi_attribute 9, 0  @ Tag_Thumb_ISA_use = no\n\t.eabi_attribute 10, 0 @ Tag_FP_arch = none\n\t.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte\n\t.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP\n\t.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed\n\t.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6\n\t.text\n\n\t@ Field constants\n\t.set field_R0, 0x3d10\n\t.set field_R1, 0x400\n\t.set field_not_M, 0xfc000000\t@ ~M = ~0x3ffffff\n\n\t.align\t2\n\t.global secp256k1_fe_mul_inner\n\t.type\tsecp256k1_fe_mul_inner, %function\n\t@ Arguments:\n\t@  r0  r      Restrict: can overlap with a, not with b\n\t@  r1  a\n\t@  r2  b\n\t@ Stack (total 4+10*4 = 44)\n\t@  sp + #0        saved 'r' pointer\n\t@  sp + #4 + 4*X  t0,t1,t2,t3,t4,t5,t6,t7,u8,t9\nsecp256k1_fe_mul_inner:\n\tstmfd\tsp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}\n\tsub\tsp, sp, #48\t\t\t@ frame=44 + alignment\n\tstr     r0, [sp, #0]\t\t\t@ save result address, we need it only at the end\n\n\t/******************************************\n\t * Main computation code.\n\t ******************************************\n\n\tAllocation:\n\t    r0,r14,r7,r8   scratch\n\t    r1       a (pointer)\n\t    r2       b (pointer)\n\t    r3:r4    c\n\t    r5:r6    d\n\t    r11:r12  c'\n\t    r9:r10   d'\n\n\tNote: do not write to r[] here, it may overlap with a[]\n\t*/\n\n\t/* A - interleaved with B */\n\tldr\tr7, [r1, #0*4]\t\t\t@ a[0]\n\tldr\tr8, [r2, #9*4]\t\t\t@ b[9]\n\tldr\tr0, [r1, #1*4]\t\t\t@ a[1]\n\tumull\tr5, r6, r7, r8\t\t\t@ d = a[0] * b[9]\n\tldr\tr14, [r2, #8*4]\t\t\t@ b[8]\n\tumull\tr9, r10, r0, r8\t\t\t@ d' = a[1] * b[9]\n\tldr\tr7, [r1, #2*4]\t\t\t@ a[2]\n\tumlal\tr5, r6, r0, r14\t\t\t@ d += a[1] * b[8]\n\tldr\tr8, [r2, #7*4] \t\t\t@ b[7]\n\tumlal\tr9, r10, r7, r14\t\t@ d' += a[2] * b[8]\n\tldr\tr0, [r1, #3*4]   \t\t@ a[3]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[2] * b[7]\n\tldr\tr14, [r2, #6*4]   \t\t@ b[6]\n\tumlal\tr9, r10, r0, r8  \t\t@ d' += a[3] * b[7]\n\tldr\tr7, [r1, #4*4]   \t\t@ a[4]\n\tumlal\tr5, r6, r0, r14   \t\t@ d += a[3] * b[6]\n\tldr\tr8, [r2, #5*4]   \t\t@ b[5]\n\tumlal\tr9, r10, r7, r14  \t\t@ d' += a[4] * b[6]\n\tldr\tr0, [r1, #5*4]   \t\t@ a[5]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[4] * b[5]\n\tldr\tr14, [r2, #4*4]   \t\t@ b[4]\n\tumlal\tr9, r10, r0, r8  \t\t@ d' += a[5] * b[5]\n\tldr\tr7, [r1, #6*4]   \t\t@ a[6]\n\tumlal\tr5, r6, r0, r14   \t\t@ d += a[5] * b[4]\n\tldr\tr8, [r2, #3*4]   \t\t@ b[3]\n\tumlal\tr9, r10, r7, r14  \t\t@ d' += a[6] * b[4]\n\tldr\tr0, [r1, #7*4]   \t\t@ a[7]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[6] * b[3]\n\tldr\tr14, [r2, #2*4]   \t\t@ b[2]\n\tumlal\tr9, r10, r0, r8  \t\t@ d' += a[7] * b[3]\n\tldr\tr7, [r1, #8*4]   \t\t@ a[8]\n\tumlal\tr5, r6, r0, r14   \t\t@ d += a[7] * b[2]\n\tldr\tr8, [r2, #1*4]   \t\t@ b[1]\n\tumlal\tr9, r10, r7, r14  \t\t@ d' += a[8] * b[2]\n\tldr\tr0, [r1, #9*4]   \t\t@ a[9]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[8] * b[1]\n\tldr\tr14, [r2, #0*4]   \t\t@ b[0]\n\tumlal\tr9, r10, r0, r8  \t\t@ d' += a[9] * b[1]\n\tldr\tr7, [r1, #0*4]   \t\t@ a[0]\n\tumlal\tr5, r6, r0, r14   \t\t@ d += a[9] * b[0]\n\t@ r7,r14 used in B\n\n\tbic\tr0, r5, field_not_M \t\t@ t9 = d & M\n\tstr     r0, [sp, #4 + 4*9]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26 \n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\n\t/* B */\n\tumull\tr3, r4, r7, r14   \t\t@ c = a[0] * b[0]\n\tadds\tr5, r5, r9       \t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u0 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u0 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t0 = c & M\n\tstr\tr14, [sp, #4 + 0*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u0 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* C - interleaved with D */\n\tldr\tr7, [r1, #0*4]   \t\t@ a[0]\n\tldr\tr8, [r2, #2*4]   \t\t@ b[2]\n\tldr\tr14, [r2, #1*4]   \t\t@ b[1]\n\tumull\tr11, r12, r7, r8   \t\t@ c' = a[0] * b[2]\n\tldr\tr0, [r1, #1*4]   \t\t@ a[1]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[0] * b[1]\n\tldr\tr8, [r2, #0*4]   \t\t@ b[0]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[1] * b[1]\n\tldr\tr7, [r1, #2*4]   \t\t@ a[2]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[1] * b[0]\n\tldr\tr14, [r2, #9*4]   \t\t@ b[9]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[2] * b[0]\n\tldr\tr0, [r1, #3*4]   \t\t@ a[3]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[2] * b[9]\n\tldr\tr8, [r2, #8*4]   \t\t@ b[8]\n\tumull\tr9, r10, r0, r14   \t\t@ d' = a[3] * b[9]\n\tldr\tr7, [r1, #4*4]   \t\t@ a[4]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[3] * b[8]\n\tldr\tr14, [r2, #7*4]   \t\t@ b[7]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[4] * b[8]\n\tldr\tr0, [r1, #5*4]   \t\t@ a[5]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[4] * b[7]\n\tldr\tr8, [r2, #6*4]   \t\t@ b[6]\n\tumlal\tr9, r10, r0, r14   \t\t@ d' += a[5] * b[7]\n\tldr\tr7, [r1, #6*4]   \t\t@ a[6]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[5] * b[6]\n\tldr\tr14, [r2, #5*4]   \t\t@ b[5]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[6] * b[6]\n\tldr\tr0, [r1, #7*4]   \t\t@ a[7]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[6] * b[5]\n\tldr\tr8, [r2, #4*4]   \t\t@ b[4]\n\tumlal\tr9, r10, r0, r14   \t\t@ d' += a[7] * b[5]\n\tldr\tr7, [r1, #8*4]   \t\t@ a[8]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[7] * b[4]\n\tldr\tr14, [r2, #3*4]   \t\t@ b[3]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[8] * b[4]\n\tldr\tr0, [r1, #9*4]   \t\t@ a[9]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[8] * b[3]\n\tldr\tr8, [r2, #2*4]   \t\t@ b[2]\n\tumlal\tr9, r10, r0, r14   \t\t@ d' += a[9] * b[3]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[9] * b[2]\n\n\tbic\tr0, r5, field_not_M \t\t@ u1 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u1 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t1 = c & M\n\tstr\tr14, [sp, #4 + 1*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u1 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* D */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u2 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u2 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t2 = c & M\n\tstr\tr14, [sp, #4 + 2*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u2 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* E - interleaved with F */\n\tldr\tr7, [r1, #0*4]   \t\t@ a[0]\n\tldr\tr8, [r2, #4*4]   \t\t@ b[4]\n\tumull\tr11, r12, r7, r8   \t\t@ c' = a[0] * b[4]\n\tldr\tr8, [r2, #3*4]   \t\t@ b[3]\n\tumlal   r3, r4, r7, r8   \t\t@ c += a[0] * b[3]\n\tldr\tr7, [r1, #1*4]   \t\t@ a[1]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[1] * b[3]\n\tldr\tr8, [r2, #2*4]   \t\t@ b[2]\n\tumlal   r3, r4, r7, r8   \t\t@ c += a[1] * b[2]\n\tldr\tr7, [r1, #2*4]   \t\t@ a[2]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[2] * b[2]\n\tldr\tr8, [r2, #1*4]   \t\t@ b[1]\n\tumlal   r3, r4, r7, r8   \t\t@ c += a[2] * b[1]\n\tldr\tr7, [r1, #3*4]   \t\t@ a[3]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[3] * b[1]\n\tldr\tr8, [r2, #0*4]   \t\t@ b[0]\n\tumlal   r3, r4, r7, r8   \t\t@ c += a[3] * b[0]\n\tldr\tr7, [r1, #4*4]   \t\t@ a[4]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[4] * b[0]\n\tldr\tr8, [r2, #9*4]   \t\t@ b[9]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[4] * b[9]\n\tldr\tr7, [r1, #5*4]   \t\t@ a[5]\n\tumull\tr9, r10, r7, r8   \t\t@ d' = a[5] * b[9]\n\tldr\tr8, [r2, #8*4]   \t\t@ b[8]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[5] * b[8]\n\tldr\tr7, [r1, #6*4]   \t\t@ a[6]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[6] * b[8]\n\tldr\tr8, [r2, #7*4]   \t\t@ b[7]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[6] * b[7]\n\tldr\tr7, [r1, #7*4]   \t\t@ a[7]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[7] * b[7]\n\tldr\tr8, [r2, #6*4]   \t\t@ b[6]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[7] * b[6]\n\tldr\tr7, [r1, #8*4]   \t\t@ a[8]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[8] * b[6]\n\tldr\tr8, [r2, #5*4]   \t\t@ b[5]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[8] * b[5]\n\tldr\tr7, [r1, #9*4]   \t\t@ a[9]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[9] * b[5]\n\tldr\tr8, [r2, #4*4]   \t\t@ b[4]\n\tumlal\tr5, r6, r7, r8   \t\t@ d += a[9] * b[4]\n\n\tbic\tr0, r5, field_not_M \t\t@ u3 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u3 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t3 = c & M\n\tstr\tr14, [sp, #4 + 3*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u3 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* F */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u4 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u4 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t4 = c & M\n\tstr\tr14, [sp, #4 + 4*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u4 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* G - interleaved with H */\n\tldr\tr7, [r1, #0*4]   \t\t@ a[0]\n\tldr\tr8, [r2, #6*4]   \t\t@ b[6]\n\tldr\tr14, [r2, #5*4]   \t\t@ b[5]\n\tumull\tr11, r12, r7, r8   \t\t@ c' = a[0] * b[6]\n\tldr\tr0, [r1, #1*4]   \t\t@ a[1]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[0] * b[5]\n\tldr\tr8, [r2, #4*4]   \t\t@ b[4]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[1] * b[5]\n\tldr\tr7, [r1, #2*4]   \t\t@ a[2]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[1] * b[4]\n\tldr\tr14, [r2, #3*4]   \t\t@ b[3]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[2] * b[4]\n\tldr\tr0, [r1, #3*4]   \t\t@ a[3]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[2] * b[3]\n\tldr\tr8, [r2, #2*4]   \t\t@ b[2]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[3] * b[3]\n\tldr\tr7, [r1, #4*4]   \t\t@ a[4]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[3] * b[2]\n\tldr\tr14, [r2, #1*4]   \t\t@ b[1]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[4] * b[2]\n\tldr\tr0, [r1, #5*4]   \t\t@ a[5]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[4] * b[1]\n\tldr\tr8, [r2, #0*4]   \t\t@ b[0]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[5] * b[1]\n\tldr\tr7, [r1, #6*4]   \t\t@ a[6]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[5] * b[0]\n\tldr\tr14, [r2, #9*4]   \t\t@ b[9]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[6] * b[0]\n\tldr\tr0, [r1, #7*4]   \t\t@ a[7]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[6] * b[9]\n\tldr\tr8, [r2, #8*4]   \t\t@ b[8]\n\tumull\tr9, r10, r0, r14   \t\t@ d' = a[7] * b[9]\n\tldr\tr7, [r1, #8*4]   \t\t@ a[8]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[7] * b[8]\n\tldr\tr14, [r2, #7*4]   \t\t@ b[7]\n\tumlal\tr9, r10, r7, r8   \t\t@ d' += a[8] * b[8]\n\tldr\tr0, [r1, #9*4]   \t\t@ a[9]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[8] * b[7]\n\tldr\tr8, [r2, #6*4]   \t\t@ b[6]\n\tumlal\tr9, r10, r0, r14   \t\t@ d' += a[9] * b[7]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[9] * b[6]\n\n\tbic\tr0, r5, field_not_M \t\t@ u5 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u5 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t5 = c & M\n\tstr\tr14, [sp, #4 + 5*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u5 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* H */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u6 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u6 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t6 = c & M\n\tstr\tr14, [sp, #4 + 6*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u6 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* I - interleaved with J */\n\tldr\tr8, [r2, #8*4]   \t\t@ b[8]\n\tldr\tr7, [r1, #0*4]   \t\t@ a[0]\n\tldr\tr14, [r2, #7*4]   \t\t@ b[7]\n\tumull   r11, r12, r7, r8   \t\t@ c' = a[0] * b[8]\n\tldr\tr0, [r1, #1*4]   \t\t@ a[1]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[0] * b[7]\n\tldr\tr8, [r2, #6*4]   \t\t@ b[6]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[1] * b[7]\n\tldr\tr7, [r1, #2*4]   \t\t@ a[2]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[1] * b[6]\n\tldr\tr14, [r2, #5*4]   \t\t@ b[5]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[2] * b[6]\n\tldr\tr0, [r1, #3*4]   \t\t@ a[3]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[2] * b[5]\n\tldr\tr8, [r2, #4*4]   \t\t@ b[4]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[3] * b[5]\n\tldr\tr7, [r1, #4*4]   \t\t@ a[4]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[3] * b[4]\n\tldr\tr14, [r2, #3*4]   \t\t@ b[3]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[4] * b[4]\n\tldr\tr0, [r1, #5*4]   \t\t@ a[5]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[4] * b[3]\n\tldr\tr8, [r2, #2*4]   \t\t@ b[2]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[5] * b[3]\n\tldr\tr7, [r1, #6*4]   \t\t@ a[6]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[5] * b[2]\n\tldr\tr14, [r2, #1*4]   \t\t@ b[1]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[6] * b[2]\n\tldr\tr0, [r1, #7*4]   \t\t@ a[7]\n\tumlal   r3, r4, r7, r14   \t\t@ c += a[6] * b[1]\n\tldr\tr8, [r2, #0*4]   \t\t@ b[0]\n\tumlal   r11, r12, r0, r14   \t\t@ c' += a[7] * b[1]\n\tldr\tr7, [r1, #8*4]   \t\t@ a[8]\n\tumlal   r3, r4, r0, r8   \t\t@ c += a[7] * b[0]\n\tldr\tr14, [r2, #9*4]   \t\t@ b[9]\n\tumlal   r11, r12, r7, r8   \t\t@ c' += a[8] * b[0]\n\tldr\tr0, [r1, #9*4]   \t\t@ a[9]\n\tumlal\tr5, r6, r7, r14   \t\t@ d += a[8] * b[9]\n\tldr\tr8, [r2, #8*4]   \t\t@ b[8]\n\tumull\tr9, r10, r0, r14  \t\t@ d' = a[9] * b[9]\n\tumlal\tr5, r6, r0, r8   \t\t@ d += a[9] * b[8]\n\n\tbic\tr0, r5, field_not_M \t\t@ u7 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u7 * R0\n\tumlal   r3, r4, r0, r14\n\n\tbic\tr14, r3, field_not_M \t\t@ t7 = c & M\n\tstr\tr14, [sp, #4 + 7*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u7 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* J */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u8 = d & M\n\tstr\tr0, [sp, #4 + 8*4]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u8 * R0\n\tumlal   r3, r4, r0, r14\n\n\t/******************************************\n\t * compute and write back result\n\t ******************************************\n\tAllocation:\n\t    r0    r\n\t    r3:r4 c\n\t    r5:r6 d\n\t    r7    t0\n\t    r8    t1\n\t    r9    t2\n\t    r11   u8\n\t    r12   t9\n\t    r1,r2,r10,r14 scratch\n\n\tNote: do not read from a[] after here, it may overlap with r[]\n\t*/\n\tldr\tr0, [sp, #0]\n\tadd\tr1, sp, #4 + 3*4\t\t@ r[3..7] = t3..7, r11=u8, r12=t9\n\tldmia\tr1, {r2,r7,r8,r9,r10,r11,r12}\n\tadd\tr1, r0, #3*4\n\tstmia\tr1, {r2,r7,r8,r9,r10}\n\n\tbic\tr2, r3, field_not_M \t\t@ r[8] = c & M\n\tstr\tr2, [r0, #8*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u8 * R1\n\tumlal   r3, r4, r11, r14\n\tmovw    r14, field_R0\t\t\t@ c += d * R0\n\tumlal   r3, r4, r5, r14\n\tadds\tr3, r3, r12\t\t\t@ c += t9\n\tadc\tr4, r4, #0\n\n\tadd\tr1, sp, #4 + 0*4\t\t@ r7,r8,r9 = t0,t1,t2\n\tldmia\tr1, {r7,r8,r9}\n\n\tubfx\tr2, r3, #0, #22     \t\t@ r[9] = c & (M >> 4)\n\tstr\tr2, [r0, #9*4]\n\tmov\tr3, r3, lsr #22     \t\t@ c >>= 22\n\torr\tr3, r3, r4, asl #10\n\tmov     r4, r4, lsr #22\n\tmovw    r14, field_R1 << 4   \t\t@ c += d * (R1 << 4)\n\tumlal   r3, r4, r5, r14\n\n\tmovw    r14, field_R0 >> 4   \t\t@ d = c * (R0 >> 4) + t0 (64x64 multiply+add)\n\tumull\tr5, r6, r3, r14\t\t\t@ d = c.lo * (R0 >> 4)\n\tadds\tr5, r5, r7\t    \t\t@ d.lo += t0\n\tmla\tr6, r14, r4, r6\t\t\t@ d.hi += c.hi * (R0 >> 4)\n\tadc\tr6, r6, 0\t     \t\t@ d.hi += carry\n\n\tbic\tr2, r5, field_not_M \t\t@ r[0] = d & M\n\tstr\tr2, [r0, #0*4]\n\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\t\n\tmovw    r14, field_R1 >> 4   \t\t@ d += c * (R1 >> 4) + t1 (64x64 multiply+add)\n\tumull\tr1, r2, r3, r14       \t\t@ tmp = c.lo * (R1 >> 4)\n\tadds\tr5, r5, r8\t    \t\t@ d.lo += t1\n\tadc\tr6, r6, #0\t    \t\t@ d.hi += carry\n\tadds\tr5, r5, r1\t    \t\t@ d.lo += tmp.lo\n\tmla\tr2, r14, r4, r2      \t\t@ tmp.hi += c.hi * (R1 >> 4)\n\tadc\tr6, r6, r2\t   \t\t@ d.hi += carry + tmp.hi\n\n\tbic\tr2, r5, field_not_M \t\t@ r[1] = d & M\n\tstr\tr2, [r0, #1*4]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26 (ignore hi)\n\torr\tr5, r5, r6, asl #6\n\n\tadd\tr5, r5, r9\t  \t\t@ d += t2\n\tstr\tr5, [r0, #2*4]      \t\t@ r[2] = d\n\n\tadd\tsp, sp, #48\n\tldmfd\tsp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n\t.size\tsecp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner\n\n\t.align\t2\n\t.global secp256k1_fe_sqr_inner\n\t.type\tsecp256k1_fe_sqr_inner, %function\n\t@ Arguments:\n\t@  r0  r\t Can overlap with a\n\t@  r1  a\n\t@ Stack (total 4+10*4 = 44)\n\t@  sp + #0        saved 'r' pointer\n\t@  sp + #4 + 4*X  t0,t1,t2,t3,t4,t5,t6,t7,u8,t9\nsecp256k1_fe_sqr_inner:\n\tstmfd\tsp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}\n\tsub\tsp, sp, #48\t\t\t@ frame=44 + alignment\n\tstr     r0, [sp, #0]\t\t\t@ save result address, we need it only at the end\n\t/******************************************\n\t * Main computation code.\n\t ******************************************\n\n\tAllocation:\n\t    r0,r14,r2,r7,r8   scratch\n\t    r1       a (pointer)\n\t    r3:r4    c\n\t    r5:r6    d\n\t    r11:r12  c'\n\t    r9:r10   d'\n\n\tNote: do not write to r[] here, it may overlap with a[]\n\t*/\n\t/* A interleaved with B */\n\tldr\tr0, [r1, #1*4]\t\t\t@ a[1]*2\n\tldr\tr7, [r1, #0*4]\t\t\t@ a[0]\n\tmov\tr0, r0, asl #1\n\tldr\tr14, [r1, #9*4]\t\t\t@ a[9]\n\tumull\tr3, r4, r7, r7\t\t\t@ c = a[0] * a[0]\n\tldr\tr8, [r1, #8*4]\t\t\t@ a[8]\n\tmov\tr7, r7, asl #1\n\tumull\tr5, r6, r7, r14\t\t\t@ d = a[0]*2 * a[9]\n\tldr\tr7, [r1, #2*4]\t\t\t@ a[2]*2\n\tumull\tr9, r10, r0, r14\t\t@ d' = a[1]*2 * a[9]\n\tldr\tr14, [r1, #7*4]\t\t\t@ a[7]\n\tumlal\tr5, r6, r0, r8\t\t\t@ d += a[1]*2 * a[8]\n\tmov\tr7, r7, asl #1\n\tldr\tr0, [r1, #3*4]\t\t\t@ a[3]*2\n\tumlal\tr9, r10, r7, r8\t\t\t@ d' += a[2]*2 * a[8]\n\tldr\tr8, [r1, #6*4]\t\t\t@ a[6]\n\tumlal\tr5, r6, r7, r14\t\t\t@ d += a[2]*2 * a[7]\n\tmov\tr0, r0, asl #1\n\tldr\tr7, [r1, #4*4]\t\t\t@ a[4]*2\n\tumlal\tr9, r10, r0, r14\t\t@ d' += a[3]*2 * a[7]\n\tldr\tr14, [r1, #5*4]\t\t\t@ a[5]\n\tmov\tr7, r7, asl #1\n\tumlal\tr5, r6, r0, r8\t\t\t@ d += a[3]*2 * a[6]\n\tumlal\tr9, r10, r7, r8\t\t\t@ d' += a[4]*2 * a[6]\n\tumlal\tr5, r6, r7, r14\t\t\t@ d += a[4]*2 * a[5]\n\tumlal\tr9, r10, r14, r14\t\t@ d' += a[5] * a[5]\n\n\tbic\tr0, r5, field_not_M \t\t@ t9 = d & M\n\tstr     r0, [sp, #4 + 9*4]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26 \n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\n\t/* B */\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u0 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u0 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t0 = c & M\n\tstr\tr14, [sp, #4 + 0*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u0 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* C interleaved with D */\n\tldr\tr0, [r1, #0*4]\t\t\t@ a[0]*2\n\tldr\tr14, [r1, #1*4]\t\t\t@ a[1]\n\tmov\tr0, r0, asl #1\n\tldr\tr8, [r1, #2*4]\t\t\t@ a[2]\n\tumlal\tr3, r4, r0, r14\t\t\t@ c += a[0]*2 * a[1]\n\tmov\tr7, r8, asl #1                  @ a[2]*2\n\tumull\tr11, r12, r14, r14\t\t@ c' = a[1] * a[1]\n\tldr\tr14, [r1, #9*4]\t\t\t@ a[9]\n\tumlal\tr11, r12, r0, r8\t\t@ c' += a[0]*2 * a[2]\n\tldr\tr0, [r1, #3*4]\t\t\t@ a[3]*2\n\tldr\tr8, [r1, #8*4]\t\t\t@ a[8]\n\tumlal\tr5, r6, r7, r14\t\t\t@ d += a[2]*2 * a[9]\n\tmov\tr0, r0, asl #1\n\tldr\tr7, [r1, #4*4]\t\t\t@ a[4]*2\n\tumull\tr9, r10, r0, r14\t\t@ d' = a[3]*2 * a[9]\n\tldr\tr14, [r1, #7*4]\t\t\t@ a[7]\n\tumlal\tr5, r6, r0, r8\t\t\t@ d += a[3]*2 * a[8]\n\tmov\tr7, r7, asl #1\n\tldr\tr0, [r1, #5*4]\t\t\t@ a[5]*2\n\tumlal\tr9, r10, r7, r8\t\t\t@ d' += a[4]*2 * a[8]\n\tldr\tr8, [r1, #6*4]\t\t\t@ a[6]\n\tmov\tr0, r0, asl #1\n\tumlal\tr5, r6, r7, r14\t\t\t@ d += a[4]*2 * a[7]\n\tumlal\tr9, r10, r0, r14\t\t@ d' += a[5]*2 * a[7]\n\tumlal\tr5, r6, r0, r8\t\t\t@ d += a[5]*2 * a[6]\n\tumlal\tr9, r10, r8, r8\t\t\t@ d' += a[6] * a[6]\n\n\tbic\tr0, r5, field_not_M \t\t@ u1 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u1 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t1 = c & M\n\tstr\tr14, [sp, #4 + 1*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u1 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* D */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u2 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u2 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t2 = c & M\n\tstr\tr14, [sp, #4 + 2*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u2 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* E interleaved with F */\n\tldr\tr7, [r1, #0*4]\t\t\t@ a[0]*2\n\tldr\tr0, [r1, #1*4]\t\t\t@ a[1]*2\n\tldr\tr14, [r1, #2*4]\t\t\t@ a[2]\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #3*4]\t\t\t@ a[3]\n\tldr\tr2, [r1, #4*4]\n\tumlal\tr3, r4, r7, r8\t\t\t@ c += a[0]*2 * a[3]\n\tmov\tr0, r0, asl #1\n\tumull\tr11, r12, r7, r2\t\t@ c' = a[0]*2 * a[4]\n\tmov\tr2, r2, asl #1\t\t\t@ a[4]*2\n\tumlal\tr11, r12, r0, r8\t\t@ c' += a[1]*2 * a[3]\n\tldr\tr8, [r1, #9*4]\t\t\t@ a[9]\n\tumlal\tr3, r4, r0, r14\t\t\t@ c += a[1]*2 * a[2]\n\tldr\tr0, [r1, #5*4]\t\t\t@ a[5]*2\n\tumlal\tr11, r12, r14, r14\t\t@ c' += a[2] * a[2]\n\tldr\tr14, [r1, #8*4]\t\t\t@ a[8]\n\tmov\tr0, r0, asl #1\n\tumlal\tr5, r6, r2, r8\t\t\t@ d += a[4]*2 * a[9]\n\tldr\tr7, [r1, #6*4]\t\t\t@ a[6]*2\n\tumull\tr9, r10, r0, r8\t\t\t@ d' = a[5]*2 * a[9]\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #7*4]\t\t\t@ a[7]\n\tumlal\tr5, r6, r0, r14\t\t\t@ d += a[5]*2 * a[8]\n\tumlal\tr9, r10, r7, r14\t\t@ d' += a[6]*2 * a[8]\n\tumlal\tr5, r6, r7, r8\t\t\t@ d += a[6]*2 * a[7]\n\tumlal\tr9, r10, r8, r8\t\t\t@ d' += a[7] * a[7]\n\n\tbic\tr0, r5, field_not_M \t\t@ u3 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u3 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t3 = c & M\n\tstr\tr14, [sp, #4 + 3*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u3 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* F */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u4 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u4 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t4 = c & M\n\tstr\tr14, [sp, #4 + 4*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u4 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* G interleaved with H */\n\tldr\tr7, [r1, #0*4]\t\t\t@ a[0]*2\n\tldr\tr0, [r1, #1*4]\t\t\t@ a[1]*2\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #5*4]\t\t\t@ a[5]\n\tldr\tr2, [r1, #6*4]\t\t\t@ a[6]\n\tumlal\tr3, r4, r7, r8\t\t\t@ c += a[0]*2 * a[5]\n\tldr\tr14, [r1, #4*4]\t\t\t@ a[4]\n\tmov\tr0, r0, asl #1\n\tumull\tr11, r12, r7, r2\t\t@ c' = a[0]*2 * a[6]\n\tldr\tr7, [r1, #2*4]\t\t\t@ a[2]*2\n\tumlal\tr11, r12, r0, r8\t\t@ c' += a[1]*2 * a[5]\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #3*4]\t\t\t@ a[3]\n\tumlal\tr3, r4, r0, r14\t\t\t@ c += a[1]*2 * a[4]\n\tmov\tr0, r2, asl #1\t\t\t@ a[6]*2\n\tumlal\tr11, r12, r7, r14\t\t@ c' += a[2]*2 * a[4]\n\tldr\tr14, [r1, #9*4]\t\t\t@ a[9]\n\tumlal\tr3, r4, r7, r8\t\t\t@ c += a[2]*2 * a[3]\n\tldr\tr7, [r1, #7*4]\t\t\t@ a[7]*2\n\tumlal\tr11, r12, r8, r8\t\t@ c' += a[3] * a[3]\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #8*4]\t\t\t@ a[8]\n\tumlal\tr5, r6, r0, r14\t\t\t@ d += a[6]*2 * a[9]\n\tumull\tr9, r10, r7, r14\t\t@ d' = a[7]*2 * a[9]\n\tumlal\tr5, r6, r7, r8\t\t\t@ d += a[7]*2 * a[8]\n\tumlal\tr9, r10, r8, r8\t\t\t@ d' += a[8] * a[8]\n\n\tbic\tr0, r5, field_not_M \t\t@ u5 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u5 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t5 = c & M\n\tstr\tr14, [sp, #4 + 5*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u5 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* H */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tadds\tr5, r5, r9\t\t\t@ d += d'\n\tadc\tr6, r6, r10\n\n\tbic\tr0, r5, field_not_M \t\t@ u6 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u6 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t6 = c & M\n\tstr\tr14, [sp, #4 + 6*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u6 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* I interleaved with J */\n\tldr\tr7, [r1, #0*4]\t\t\t@ a[0]*2\n\tldr\tr0, [r1, #1*4]\t\t\t@ a[1]*2\n\tmov\tr7, r7, asl #1\n\tldr\tr8, [r1, #7*4]\t\t\t@ a[7]\n\tldr\tr2, [r1, #8*4]\t\t\t@ a[8]\n\tumlal\tr3, r4, r7, r8\t\t\t@ c += a[0]*2 * a[7]\n\tldr\tr14, [r1, #6*4]\t\t\t@ a[6]\n\tmov\tr0, r0, asl #1\n\tumull\tr11, r12, r7, r2\t\t@ c' = a[0]*2 * a[8]\n\tldr\tr7, [r1, #2*4]\t\t\t@ a[2]*2\n\tumlal\tr11, r12, r0, r8\t\t@ c' += a[1]*2 * a[7]\n\tldr\tr8, [r1, #5*4]\t\t\t@ a[5]\n\tumlal\tr3, r4, r0, r14\t\t\t@ c += a[1]*2 * a[6]\n\tldr\tr0, [r1, #3*4]\t\t\t@ a[3]*2\n\tmov\tr7, r7, asl #1\n\tumlal\tr11, r12, r7, r14\t\t@ c' += a[2]*2 * a[6]\n\tldr\tr14, [r1, #4*4]\t\t\t@ a[4]\n\tmov\tr0, r0, asl #1\n\tumlal\tr3, r4, r7, r8\t\t\t@ c += a[2]*2 * a[5]\n\tmov\tr2, r2, asl #1\t\t\t@ a[8]*2\n\tumlal\tr11, r12, r0, r8\t\t@ c' += a[3]*2 * a[5]\n\tumlal\tr3, r4, r0, r14\t\t\t@ c += a[3]*2 * a[4]\n\tumlal\tr11, r12, r14, r14\t\t@ c' += a[4] * a[4]\n\tldr\tr8, [r1, #9*4]\t\t\t@ a[9]\n\tumlal\tr5, r6, r2, r8\t\t\t@ d += a[8]*2 * a[9]\n\t@ r8 will be used in J\n\n\tbic\tr0, r5, field_not_M \t\t@ u7 = d & M\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u7 * R0\n\tumlal   r3, r4, r0, r14\n\tbic\tr14, r3, field_not_M \t\t@ t7 = c & M\n\tstr\tr14, [sp, #4 + 7*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u7 * R1\n\tumlal   r3, r4, r0, r14\n\n\t/* J */\n\tadds\tr3, r3, r11\t\t\t@ c += c'\n\tadc\tr4, r4, r12\n\tumlal\tr5, r6, r8, r8\t\t\t@ d += a[9] * a[9]\n\n\tbic\tr0, r5, field_not_M \t\t@ u8 = d & M\n\tstr\tr0, [sp, #4 + 8*4]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\tmovw    r14, field_R0\t\t\t@ c += u8 * R0\n\tumlal   r3, r4, r0, r14\n\n\t/******************************************\n\t * compute and write back result\n\t ******************************************\n\tAllocation:\n\t    r0    r\n\t    r3:r4 c\n\t    r5:r6 d\n\t    r7    t0\n\t    r8    t1\n\t    r9    t2\n\t    r11   u8\n\t    r12   t9\n\t    r1,r2,r10,r14 scratch\n\n\tNote: do not read from a[] after here, it may overlap with r[]\n\t*/\n\tldr\tr0, [sp, #0]\n\tadd\tr1, sp, #4 + 3*4\t\t@ r[3..7] = t3..7, r11=u8, r12=t9\n\tldmia\tr1, {r2,r7,r8,r9,r10,r11,r12}\n\tadd\tr1, r0, #3*4\n\tstmia\tr1, {r2,r7,r8,r9,r10}\n\n\tbic\tr2, r3, field_not_M \t\t@ r[8] = c & M\n\tstr\tr2, [r0, #8*4]\n\tmov\tr3, r3, lsr #26     \t\t@ c >>= 26\n\torr\tr3, r3, r4, asl #6\n\tmov     r4, r4, lsr #26\n\tmov     r14, field_R1\t\t\t@ c += u8 * R1\n\tumlal   r3, r4, r11, r14\n\tmovw    r14, field_R0\t\t\t@ c += d * R0\n\tumlal   r3, r4, r5, r14\n\tadds\tr3, r3, r12\t\t\t@ c += t9\n\tadc\tr4, r4, #0\n\n\tadd\tr1, sp, #4 + 0*4\t\t@ r7,r8,r9 = t0,t1,t2\n\tldmia\tr1, {r7,r8,r9}\n\n\tubfx\tr2, r3, #0, #22     \t\t@ r[9] = c & (M >> 4)\n\tstr\tr2, [r0, #9*4]\n\tmov\tr3, r3, lsr #22     \t\t@ c >>= 22\n\torr\tr3, r3, r4, asl #10\n\tmov     r4, r4, lsr #22\n\tmovw    r14, field_R1 << 4   \t\t@ c += d * (R1 << 4)\n\tumlal   r3, r4, r5, r14\n\n\tmovw    r14, field_R0 >> 4   \t\t@ d = c * (R0 >> 4) + t0 (64x64 multiply+add)\n\tumull\tr5, r6, r3, r14\t\t\t@ d = c.lo * (R0 >> 4)\n\tadds\tr5, r5, r7\t    \t\t@ d.lo += t0\n\tmla\tr6, r14, r4, r6\t\t\t@ d.hi += c.hi * (R0 >> 4)\n\tadc\tr6, r6, 0\t     \t\t@ d.hi += carry\n\n\tbic\tr2, r5, field_not_M \t\t@ r[0] = d & M\n\tstr\tr2, [r0, #0*4]\n\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26\n\torr\tr5, r5, r6, asl #6\n\tmov     r6, r6, lsr #26\n\t\n\tmovw    r14, field_R1 >> 4   \t\t@ d += c * (R1 >> 4) + t1 (64x64 multiply+add)\n\tumull\tr1, r2, r3, r14       \t\t@ tmp = c.lo * (R1 >> 4)\n\tadds\tr5, r5, r8\t    \t\t@ d.lo += t1\n\tadc\tr6, r6, #0\t    \t\t@ d.hi += carry\n\tadds\tr5, r5, r1\t    \t\t@ d.lo += tmp.lo\n\tmla\tr2, r14, r4, r2      \t\t@ tmp.hi += c.hi * (R1 >> 4)\n\tadc\tr6, r6, r2\t   \t\t@ d.hi += carry + tmp.hi\n\n\tbic\tr2, r5, field_not_M \t\t@ r[1] = d & M\n\tstr\tr2, [r0, #1*4]\n\tmov\tr5, r5, lsr #26     \t\t@ d >>= 26 (ignore hi)\n\torr\tr5, r5, r6, asl #6\n\n\tadd\tr5, r5, r9\t  \t\t@ d += t2\n\tstr\tr5, [r0, #2*4]      \t\t@ r[2] = d\n\n\tadd\tsp, sp, #48\n\tldmfd\tsp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n\t.size\tsecp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner\n\n"
  },
  {
    "path": "src/secp256k1/src/basic-config.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_BASIC_CONFIG_\n#define _SECP256K1_BASIC_CONFIG_\n\n#ifdef USE_BASIC_CONFIG\n\n#undef USE_ASM_X86_64\n#undef USE_ENDOMORPHISM\n#undef USE_FIELD_10X26\n#undef USE_FIELD_5X52\n#undef USE_FIELD_INV_BUILTIN\n#undef USE_FIELD_INV_NUM\n#undef USE_NUM_GMP\n#undef USE_NUM_NONE\n#undef USE_SCALAR_4X64\n#undef USE_SCALAR_8X32\n#undef USE_SCALAR_INV_BUILTIN\n#undef USE_SCALAR_INV_NUM\n\n#define USE_NUM_NONE 1\n#define USE_FIELD_INV_BUILTIN 1\n#define USE_SCALAR_INV_BUILTIN 1\n#define USE_FIELD_10X26 1\n#define USE_SCALAR_8X32 1\n\n#endif // USE_BASIC_CONFIG\n#endif // _SECP256K1_BASIC_CONFIG_\n"
  },
  {
    "path": "src/secp256k1/src/bench.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_BENCH_H_\n#define _SECP256K1_BENCH_H_\n\n#include <stdio.h>\n#include <math.h>\n#include \"sys/time.h\"\n\nstatic double gettimedouble(void) {\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return tv.tv_usec * 0.000001 + tv.tv_sec;\n}\n\nvoid print_number(double x) {\n    double y = x;\n    int c = 0;\n    if (y < 0.0) {\n        y = -y;\n    }\n    while (y > 0 && y < 100.0) {\n        y *= 10.0;\n        c++;\n    }\n    printf(\"%.*f\", c, x);\n}\n\nvoid run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {\n    int i;\n    double min = HUGE_VAL;\n    double sum = 0.0;\n    double max = 0.0;\n    for (i = 0; i < count; i++) {\n        double begin, total;\n        if (setup != NULL) {\n            setup(data);\n        }\n        begin = gettimedouble();\n        benchmark(data);\n        total = gettimedouble() - begin;\n        if (teardown != NULL) {\n            teardown(data);\n        }\n        if (total < min) {\n            min = total;\n        }\n        if (total > max) {\n            max = total;\n        }\n        sum += total;\n    }\n    printf(\"%s: min \", name);\n    print_number(min * 1000000.0 / iter);\n    printf(\"us / avg \");\n    print_number((sum / count) * 1000000.0 / iter);\n    printf(\"us / max \");\n    print_number(max * 1000000.0 / iter);\n    printf(\"us\\n\");\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/bench_ecdh.c",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra                  *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include <string.h>\n\n#include \"include/secp256k1.h\"\n#include \"include/secp256k1_ecdh.h\"\n#include \"util.h\"\n#include \"bench.h\"\n\ntypedef struct {\n    secp256k1_context *ctx;\n    secp256k1_pubkey point;\n    unsigned char scalar[32];\n} bench_ecdh_t;\n\nstatic void bench_ecdh_setup(void* arg) {\n    int i;\n    bench_ecdh_t *data = (bench_ecdh_t*)arg;\n    const unsigned char point[] = {\n        0x03,\n        0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,\n        0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,\n        0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,\n        0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f\n    };\n\n    /* create a context with no capabilities */\n    data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);\n    for (i = 0; i < 32; i++) {\n        data->scalar[i] = i + 1;\n    }\n    CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);\n}\n\nstatic void bench_ecdh(void* arg) {\n    int i;\n    unsigned char res[32];\n    bench_ecdh_t *data = (bench_ecdh_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);\n    }\n}\n\nint main(void) {\n    bench_ecdh_t data;\n\n    run_benchmark(\"ecdh\", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/bench_internal.c",
    "content": "/**********************************************************************\n * Copyright (c) 2014-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n#include <stdio.h>\n\n#include \"include/secp256k1.h\"\n\n#include \"util.h\"\n#include \"hash_impl.h\"\n#include \"num_impl.h\"\n#include \"field_impl.h\"\n#include \"group_impl.h\"\n#include \"scalar_impl.h\"\n#include \"ecmult_const_impl.h\"\n#include \"ecmult_impl.h\"\n#include \"bench.h\"\n#include \"secp256k1.c\"\n\ntypedef struct {\n    secp256k1_scalar scalar_x, scalar_y;\n    secp256k1_fe fe_x, fe_y;\n    secp256k1_ge ge_x, ge_y;\n    secp256k1_gej gej_x, gej_y;\n    unsigned char data[64];\n    int wnaf[256];\n} bench_inv_t;\n\nvoid bench_setup(void* arg) {\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    static const unsigned char init_x[32] = {\n        0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,\n        0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,\n        0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,\n        0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83\n    };\n\n    static const unsigned char init_y[32] = {\n        0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,\n        0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,\n        0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,\n        0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3\n    };\n\n    secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);\n    secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);\n    secp256k1_fe_set_b32(&data->fe_x, init_x);\n    secp256k1_fe_set_b32(&data->fe_y, init_y);\n    CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));\n    CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));\n    secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);\n    secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);\n    memcpy(data->data, init_x, 32);\n    memcpy(data->data + 32, init_y, 32);\n}\n\nvoid bench_scalar_add(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000000; i++) {\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\nvoid bench_scalar_negate(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000000; i++) {\n        secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);\n    }\n}\n\nvoid bench_scalar_sqr(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);\n    }\n}\n\nvoid bench_scalar_mul(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\n#ifdef USE_ENDOMORPHISM\nvoid bench_scalar_split(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_scalar l, r;\n        secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x);\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n#endif\n\nvoid bench_scalar_inverse(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000; i++) {\n        secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\nvoid bench_scalar_inverse_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000; i++) {\n        secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\nvoid bench_field_normalize(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000000; i++) {\n        secp256k1_fe_normalize(&data->fe_x);\n    }\n}\n\nvoid bench_field_normalize_weak(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 2000000; i++) {\n        secp256k1_fe_normalize_weak(&data->fe_x);\n    }\n}\n\nvoid bench_field_mul(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);\n    }\n}\n\nvoid bench_field_sqr(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_fe_sqr(&data->fe_x, &data->fe_x);\n    }\n}\n\nvoid bench_field_inverse(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_fe_inv(&data->fe_x, &data->fe_x);\n        secp256k1_fe_add(&data->fe_x, &data->fe_y);\n    }\n}\n\nvoid bench_field_inverse_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);\n        secp256k1_fe_add(&data->fe_x, &data->fe_y);\n    }\n}\n\nvoid bench_field_sqrt(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);\n        secp256k1_fe_add(&data->fe_x, &data->fe_y);\n    }\n}\n\nvoid bench_group_double_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);\n    }\n}\n\nvoid bench_group_add_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);\n    }\n}\n\nvoid bench_group_add_affine(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);\n    }\n}\n\nvoid bench_group_add_affine_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);\n    }\n}\n\nvoid bench_group_jacobi_var(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_gej_has_quad_y_var(&data->gej_x);\n    }\n}\n\nvoid bench_ecmult_wnaf(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\nvoid bench_wnaf_const(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A);\n        secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);\n    }\n}\n\n\nvoid bench_sha256(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n    secp256k1_sha256_t sha;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_sha256_initialize(&sha);\n        secp256k1_sha256_write(&sha, data->data, 32);\n        secp256k1_sha256_finalize(&sha, data->data);\n    }\n}\n\nvoid bench_hmac_sha256(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n    secp256k1_hmac_sha256_t hmac;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);\n        secp256k1_hmac_sha256_write(&hmac, data->data, 32);\n        secp256k1_hmac_sha256_finalize(&hmac, data->data);\n    }\n}\n\nvoid bench_rfc6979_hmac_sha256(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n    secp256k1_rfc6979_hmac_sha256_t rng;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);\n    }\n}\n\nvoid bench_context_verify(void* arg) {\n    int i;\n    (unused)arg;\n    for (i = 0; i < 20; i++) {\n        secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));\n    }\n}\n\nvoid bench_context_sign(void* arg) {\n    int i;\n    (unused)arg;\n    for (i = 0; i < 200; i++) {\n        secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));\n    }\n}\n\n#ifndef USE_NUM_NONE\nvoid bench_num_jacobi(void* arg) {\n    int i;\n    bench_inv_t *data = (bench_inv_t*)arg;\n    secp256k1_num nx, norder;\n\n    secp256k1_scalar_get_num(&nx, &data->scalar_x);\n    secp256k1_scalar_order_get_num(&norder);\n    secp256k1_scalar_get_num(&norder, &data->scalar_y);\n\n    for (i = 0; i < 200000; i++) {\n        secp256k1_num_jacobi(&nx, &norder);\n    }\n}\n#endif\n\nint have_flag(int argc, char** argv, char *flag) {\n    char** argm = argv + argc;\n    argv++;\n    if (argv == argm) {\n        return 1;\n    }\n    while (argv != NULL && argv != argm) {\n        if (strcmp(*argv, flag) == 0) {\n            return 1;\n        }\n        argv++;\n    }\n    return 0;\n}\n\nint main(int argc, char **argv) {\n    bench_inv_t data;\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"add\")) run_benchmark(\"scalar_add\", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"negate\")) run_benchmark(\"scalar_negate\", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"sqr\")) run_benchmark(\"scalar_sqr\", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"mul\")) run_benchmark(\"scalar_mul\", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);\n#ifdef USE_ENDOMORPHISM\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"split\")) run_benchmark(\"scalar_split\", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);\n#endif\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"inverse\")) run_benchmark(\"scalar_inverse\", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);\n    if (have_flag(argc, argv, \"scalar\") || have_flag(argc, argv, \"inverse\")) run_benchmark(\"scalar_inverse_var\", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);\n\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"normalize\")) run_benchmark(\"field_normalize\", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"normalize\")) run_benchmark(\"field_normalize_weak\", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"sqr\")) run_benchmark(\"field_sqr\", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"mul\")) run_benchmark(\"field_mul\", bench_field_mul, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"inverse\")) run_benchmark(\"field_inverse\", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"inverse\")) run_benchmark(\"field_inverse_var\", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);\n    if (have_flag(argc, argv, \"field\") || have_flag(argc, argv, \"sqrt\")) run_benchmark(\"field_sqrt\", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);\n\n    if (have_flag(argc, argv, \"group\") || have_flag(argc, argv, \"double\")) run_benchmark(\"group_double_var\", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"group\") || have_flag(argc, argv, \"add\")) run_benchmark(\"group_add_var\", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"group\") || have_flag(argc, argv, \"add\")) run_benchmark(\"group_add_affine\", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"group\") || have_flag(argc, argv, \"add\")) run_benchmark(\"group_add_affine_var\", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);\n    if (have_flag(argc, argv, \"group\") || have_flag(argc, argv, \"jacobi\")) run_benchmark(\"group_jacobi_var\", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);\n\n    if (have_flag(argc, argv, \"ecmult\") || have_flag(argc, argv, \"wnaf\")) run_benchmark(\"wnaf_const\", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);\n    if (have_flag(argc, argv, \"ecmult\") || have_flag(argc, argv, \"wnaf\")) run_benchmark(\"ecmult_wnaf\", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);\n\n    if (have_flag(argc, argv, \"hash\") || have_flag(argc, argv, \"sha256\")) run_benchmark(\"hash_sha256\", bench_sha256, bench_setup, NULL, &data, 10, 20000);\n    if (have_flag(argc, argv, \"hash\") || have_flag(argc, argv, \"hmac\")) run_benchmark(\"hash_hmac_sha256\", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);\n    if (have_flag(argc, argv, \"hash\") || have_flag(argc, argv, \"rng6979\")) run_benchmark(\"hash_rfc6979_hmac_sha256\", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000);\n\n    if (have_flag(argc, argv, \"context\") || have_flag(argc, argv, \"verify\")) run_benchmark(\"context_verify\", bench_context_verify, bench_setup, NULL, &data, 10, 20);\n    if (have_flag(argc, argv, \"context\") || have_flag(argc, argv, \"sign\")) run_benchmark(\"context_sign\", bench_context_sign, bench_setup, NULL, &data, 10, 200);\n\n#ifndef USE_NUM_NONE\n    if (have_flag(argc, argv, \"num\") || have_flag(argc, argv, \"jacobi\")) run_benchmark(\"num_jacobi\", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);\n#endif\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/bench_recover.c",
    "content": "/**********************************************************************\n * Copyright (c) 2014-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include \"include/secp256k1.h\"\n#include \"include/secp256k1_recovery.h\"\n#include \"util.h\"\n#include \"bench.h\"\n\ntypedef struct {\n    secp256k1_context *ctx;\n    unsigned char msg[32];\n    unsigned char sig[64];\n} bench_recover_t;\n\nvoid bench_recover(void* arg) {\n    int i;\n    bench_recover_t *data = (bench_recover_t*)arg;\n    secp256k1_pubkey pubkey;\n    unsigned char pubkeyc[33];\n\n    for (i = 0; i < 20000; i++) {\n        int j;\n        size_t pubkeylen = 33;\n        secp256k1_ecdsa_recoverable_signature sig;\n        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));\n        CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg));\n        CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));\n        for (j = 0; j < 32; j++) {\n            data->sig[j + 32] = data->msg[j];    /* Move former message to S. */\n            data->msg[j] = data->sig[j];         /* Move former R to message. */\n            data->sig[j] = pubkeyc[j + 1];       /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */\n        }\n    }\n}\n\nvoid bench_recover_setup(void* arg) {\n    int i;\n    bench_recover_t *data = (bench_recover_t*)arg;\n\n    for (i = 0; i < 32; i++) {\n        data->msg[i] = 1 + i;\n    }\n    for (i = 0; i < 64; i++) {\n        data->sig[i] = 65 + i;\n    }\n}\n\nint main(void) {\n    bench_recover_t data;\n\n    data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);\n\n    run_benchmark(\"ecdsa_recover\", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);\n\n    secp256k1_context_destroy(data.ctx);\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/bench_sign.c",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include \"include/secp256k1.h\"\n#include \"util.h\"\n#include \"bench.h\"\n\ntypedef struct {\n    secp256k1_context* ctx;\n    unsigned char msg[32];\n    unsigned char key[32];\n} bench_sign_t;\n\nstatic void bench_sign_setup(void* arg) {\n    int i;\n    bench_sign_t *data = (bench_sign_t*)arg;\n\n    for (i = 0; i < 32; i++) {\n        data->msg[i] = i + 1;\n    }\n    for (i = 0; i < 32; i++) {\n        data->key[i] = i + 65;\n    }\n}\n\nstatic void bench_sign(void* arg) {\n    int i;\n    bench_sign_t *data = (bench_sign_t*)arg;\n\n    unsigned char sig[74];\n    for (i = 0; i < 20000; i++) {\n        size_t siglen = 74;\n        int j;\n        secp256k1_ecdsa_signature signature;\n        CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL));\n        CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature));\n        for (j = 0; j < 32; j++) {\n            data->msg[j] = sig[j];\n            data->key[j] = sig[j + 32];\n        }\n    }\n}\n\nint main(void) {\n    bench_sign_t data;\n\n    data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n\n    run_benchmark(\"ecdsa_sign\", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);\n\n    secp256k1_context_destroy(data.ctx);\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/bench_verify.c",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"include/secp256k1.h\"\n#include \"util.h\"\n#include \"bench.h\"\n\n#ifdef ENABLE_OPENSSL_TESTS\n#include <openssl/bn.h>\n#include <openssl/ecdsa.h>\n#include <openssl/obj_mac.h>\n#endif\n\ntypedef struct {\n    secp256k1_context *ctx;\n    unsigned char msg[32];\n    unsigned char key[32];\n    unsigned char sig[72];\n    size_t siglen;\n    unsigned char pubkey[33];\n    size_t pubkeylen;\n#ifdef ENABLE_OPENSSL_TESTS\n    EC_GROUP* ec_group;\n#endif\n} benchmark_verify_t;\n\nstatic void benchmark_verify(void* arg) {\n    int i;\n    benchmark_verify_t* data = (benchmark_verify_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        secp256k1_pubkey pubkey;\n        secp256k1_ecdsa_signature sig;\n        data->sig[data->siglen - 1] ^= (i & 0xFF);\n        data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);\n        data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);\n        CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);\n        CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);\n        CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0));\n        data->sig[data->siglen - 1] ^= (i & 0xFF);\n        data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);\n        data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);\n    }\n}\n\n#ifdef ENABLE_OPENSSL_TESTS\nstatic void benchmark_verify_openssl(void* arg) {\n    int i;\n    benchmark_verify_t* data = (benchmark_verify_t*)arg;\n\n    for (i = 0; i < 20000; i++) {\n        data->sig[data->siglen - 1] ^= (i & 0xFF);\n        data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);\n        data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);\n        {\n            EC_KEY *pkey = EC_KEY_new();\n            const unsigned char *pubkey = &data->pubkey[0];\n            int result;\n\n            CHECK(pkey != NULL);\n            result = EC_KEY_set_group(pkey, data->ec_group);\n            CHECK(result);\n            result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;\n            CHECK(result);\n            result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);\n            CHECK(result);\n            EC_KEY_free(pkey);\n        }\n        data->sig[data->siglen - 1] ^= (i & 0xFF);\n        data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);\n        data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);\n    }\n}\n#endif\n\nint main(void) {\n    int i;\n    secp256k1_pubkey pubkey;\n    secp256k1_ecdsa_signature sig;\n    benchmark_verify_t data;\n\n    data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n\n    for (i = 0; i < 32; i++) {\n        data.msg[i] = 1 + i;\n    }\n    for (i = 0; i < 32; i++) {\n        data.key[i] = 33 + i;\n    }\n    data.siglen = 72;\n    CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL));\n    CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));\n    CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));\n    data.pubkeylen = 33;\n    CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);\n\n    run_benchmark(\"ecdsa_verify\", benchmark_verify, NULL, NULL, &data, 10, 20000);\n#ifdef ENABLE_OPENSSL_TESTS\n    data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);\n    run_benchmark(\"ecdsa_verify_openssl\", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);\n    EC_GROUP_free(data.ec_group);\n#endif\n\n    secp256k1_context_destroy(data.ctx);\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/ecdsa.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECDSA_\n#define _SECP256K1_ECDSA_\n\n#include <stddef.h>\n\n#include \"scalar.h\"\n#include \"group.h\"\n#include \"ecmult.h\"\n\nstatic int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size);\nstatic int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s);\nstatic int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);\nstatic int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecdsa_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n\n#ifndef _SECP256K1_ECDSA_IMPL_H_\n#define _SECP256K1_ECDSA_IMPL_H_\n\n#include \"scalar.h\"\n#include \"field.h\"\n#include \"group.h\"\n#include \"ecmult.h\"\n#include \"ecmult_gen.h\"\n#include \"ecdsa.h\"\n\n/** Group order for secp256k1 defined as 'n' in \"Standards for Efficient Cryptography\" (SEC2) 2.7.1\n *  sage: for t in xrange(1023, -1, -1):\n *     ..   p = 2**256 - 2**32 - t\n *     ..   if p.is_prime():\n *     ..     print '%x'%p\n *     ..     break\n *   'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'\n *  sage: a = 0\n *  sage: b = 7\n *  sage: F = FiniteField (p)\n *  sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())\n *   'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'\n */\nstatic const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(\n    0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,\n    0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL\n);\n\n/** Difference between field and order, values 'p' and 'n' values defined in\n *  \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.\n *  sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\n *  sage: a = 0\n *  sage: b = 7\n *  sage: F = FiniteField (p)\n *  sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())\n *   '14551231950b75fc4402da1722fc9baee'\n */\nstatic const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(\n    0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL\n);\n\nstatic int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {\n    int lenleft, b1;\n    size_t ret = 0;\n    if (*sigp >= sigend) {\n        return -1;\n    }\n    b1 = *((*sigp)++);\n    if (b1 == 0xFF) {\n        /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */\n        return -1;\n    }\n    if ((b1 & 0x80) == 0) {\n        /* X.690-0207 8.1.3.4 short form length octets */\n        return b1;\n    }\n    if (b1 == 0x80) {\n        /* Indefinite length is not allowed in DER. */\n        return -1;\n    }\n    /* X.690-207 8.1.3.5 long form length octets */\n    lenleft = b1 & 0x7F;\n    if (lenleft > sigend - *sigp) {\n        return -1;\n    }\n    if (**sigp == 0) {\n        /* Not the shortest possible length encoding. */\n        return -1;\n    }\n    if ((size_t)lenleft > sizeof(size_t)) {\n        /* The resulting length would exceed the range of a size_t, so\n         * certainly longer than the passed array size.\n         */\n        return -1;\n    }\n    while (lenleft > 0) {\n        if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {\n        }\n        ret = (ret << 8) | **sigp;\n        if (ret + lenleft > (size_t)(sigend - *sigp)) {\n            /* Result exceeds the length of the passed array. */\n            return -1;\n        }\n        (*sigp)++;\n        lenleft--;\n    }\n    if (ret < 128) {\n        /* Not the shortest possible length encoding. */\n        return -1;\n    }\n    return ret;\n}\n\nstatic int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {\n    int overflow = 0;\n    unsigned char ra[32] = {0};\n    int rlen;\n\n    if (*sig == sigend || **sig != 0x02) {\n        /* Not a primitive integer (X.690-0207 8.3.1). */\n        return 0;\n    }\n    (*sig)++;\n    rlen = secp256k1_der_read_len(sig, sigend);\n    if (rlen <= 0 || (*sig) + rlen > sigend) {\n        /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1).  */\n        return 0;\n    }\n    if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) {\n        /* Excessive 0x00 padding. */\n        return 0;\n    }\n    if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) {\n        /* Excessive 0xFF padding. */\n        return 0;\n    }\n    if ((**sig & 0x80) == 0x80) {\n        /* Negative. */\n        overflow = 1;\n    }\n    while (rlen > 0 && **sig == 0) {\n        /* Skip leading zero bytes */\n        rlen--;\n        (*sig)++;\n    }\n    if (rlen > 32) {\n        overflow = 1;\n    }\n    if (!overflow) {\n        memcpy(ra + 32 - rlen, *sig, rlen);\n        secp256k1_scalar_set_b32(r, ra, &overflow);\n    }\n    if (overflow) {\n        secp256k1_scalar_set_int(r, 0);\n    }\n    (*sig) += rlen;\n    return 1;\n}\n\nstatic int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {\n    const unsigned char *sigend = sig + size;\n    int rlen;\n    if (sig == sigend || *(sig++) != 0x30) {\n        /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */\n        return 0;\n    }\n    rlen = secp256k1_der_read_len(&sig, sigend);\n    if (rlen < 0 || sig + rlen > sigend) {\n        /* Tuple exceeds bounds */\n        return 0;\n    }\n    if (sig + rlen != sigend) {\n        /* Garbage after tuple. */\n        return 0;\n    }\n\n    if (!secp256k1_der_parse_integer(rr, &sig, sigend)) {\n        return 0;\n    }\n    if (!secp256k1_der_parse_integer(rs, &sig, sigend)) {\n        return 0;\n    }\n\n    if (sig != sigend) {\n        /* Trailing garbage inside tuple. */\n        return 0;\n    }\n\n    return 1;\n}\n\nstatic int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) {\n    unsigned char r[33] = {0}, s[33] = {0};\n    unsigned char *rp = r, *sp = s;\n    size_t lenR = 33, lenS = 33;\n    secp256k1_scalar_get_b32(&r[1], ar);\n    secp256k1_scalar_get_b32(&s[1], as);\n    while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }\n    while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }\n    if (*size < 6+lenS+lenR) {\n        *size = 6 + lenS + lenR;\n        return 0;\n    }\n    *size = 6 + lenS + lenR;\n    sig[0] = 0x30;\n    sig[1] = 4 + lenS + lenR;\n    sig[2] = 0x02;\n    sig[3] = lenR;\n    memcpy(sig+4, rp, lenR);\n    sig[4+lenR] = 0x02;\n    sig[5+lenR] = lenS;\n    memcpy(sig+lenR+6, sp, lenS);\n    return 1;\n}\n\nstatic int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {\n    unsigned char c[32];\n    secp256k1_scalar sn, u1, u2;\n#if !defined(EXHAUSTIVE_TEST_ORDER)\n    secp256k1_fe xr;\n#endif\n    secp256k1_gej pubkeyj;\n    secp256k1_gej pr;\n\n    if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {\n        return 0;\n    }\n\n    secp256k1_scalar_inverse_var(&sn, sigs);\n    secp256k1_scalar_mul(&u1, &sn, message);\n    secp256k1_scalar_mul(&u2, &sn, sigr);\n    secp256k1_gej_set_ge(&pubkeyj, pubkey);\n    secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1);\n    if (secp256k1_gej_is_infinity(&pr)) {\n        return 0;\n    }\n\n#if defined(EXHAUSTIVE_TEST_ORDER)\n{\n    secp256k1_scalar computed_r;\n    secp256k1_ge pr_ge;\n    secp256k1_ge_set_gej(&pr_ge, &pr);\n    secp256k1_fe_normalize(&pr_ge.x);\n\n    secp256k1_fe_get_b32(c, &pr_ge.x);\n    secp256k1_scalar_set_b32(&computed_r, c, NULL);\n    return secp256k1_scalar_eq(sigr, &computed_r);\n}\n#else\n    secp256k1_scalar_get_b32(c, sigr);\n    secp256k1_fe_set_b32(&xr, c);\n\n    /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)\n     *  in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),\n     *  compute the remainder modulo n, and compare it to xr. However:\n     *\n     *        xr == X(pr) mod n\n     *    <=> exists h. (xr + h * n < p && xr + h * n == X(pr))\n     *    [Since 2 * n > p, h can only be 0 or 1]\n     *    <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))\n     *    [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]\n     *    <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)\n     *    [Multiplying both sides of the equations by pr.z^2 mod p]\n     *    <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x)\n     *\n     *  Thus, we can avoid the inversion, but we have to check both cases separately.\n     *  secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.\n     */\n    if (secp256k1_gej_eq_x_var(&xr, &pr)) {\n        /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */\n        return 1;\n    }\n    if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {\n        /* xr + n >= p, so we can skip testing the second case. */\n        return 0;\n    }\n    secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);\n    if (secp256k1_gej_eq_x_var(&xr, &pr)) {\n        /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */\n        return 1;\n    }\n    return 0;\n#endif\n}\n\nstatic int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {\n    unsigned char b[32];\n    secp256k1_gej rp;\n    secp256k1_ge r;\n    secp256k1_scalar n;\n    int overflow = 0;\n\n    secp256k1_ecmult_gen(ctx, &rp, nonce);\n    secp256k1_ge_set_gej(&r, &rp);\n    secp256k1_fe_normalize(&r.x);\n    secp256k1_fe_normalize(&r.y);\n    secp256k1_fe_get_b32(b, &r.x);\n    secp256k1_scalar_set_b32(sigr, b, &overflow);\n    /* These two conditions should be checked before calling */\n    VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));\n    VERIFY_CHECK(overflow == 0);\n\n    if (recid) {\n        /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log\n         * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.\n         */\n        *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);\n    }\n    secp256k1_scalar_mul(&n, sigr, seckey);\n    secp256k1_scalar_add(&n, &n, message);\n    secp256k1_scalar_inverse(sigs, nonce);\n    secp256k1_scalar_mul(sigs, sigs, &n);\n    secp256k1_scalar_clear(&n);\n    secp256k1_gej_clear(&rp);\n    secp256k1_ge_clear(&r);\n    if (secp256k1_scalar_is_zero(sigs)) {\n        return 0;\n    }\n    if (secp256k1_scalar_is_high(sigs)) {\n        secp256k1_scalar_negate(sigs, sigs);\n        if (recid) {\n            *recid ^= 1;\n        }\n    }\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/eckey.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECKEY_\n#define _SECP256K1_ECKEY_\n\n#include <stddef.h>\n\n#include \"group.h\"\n#include \"scalar.h\"\n#include \"ecmult.h\"\n#include \"ecmult_gen.h\"\n\nstatic int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);\nstatic int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);\n\nstatic int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);\nstatic int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);\nstatic int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);\nstatic int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/eckey_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECKEY_IMPL_H_\n#define _SECP256K1_ECKEY_IMPL_H_\n\n#include \"eckey.h\"\n\n#include \"scalar.h\"\n#include \"field.h\"\n#include \"group.h\"\n#include \"ecmult_gen.h\"\n\nstatic int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {\n    if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {\n        secp256k1_fe x;\n        return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);\n    } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {\n        secp256k1_fe x, y;\n        if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {\n            return 0;\n        }\n        secp256k1_ge_set_xy(elem, &x, &y);\n        if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {\n            return 0;\n        }\n        return secp256k1_ge_is_valid_var(elem);\n    } else {\n        return 0;\n    }\n}\n\nstatic int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {\n    if (secp256k1_ge_is_infinity(elem)) {\n        return 0;\n    }\n    secp256k1_fe_normalize_var(&elem->x);\n    secp256k1_fe_normalize_var(&elem->y);\n    secp256k1_fe_get_b32(&pub[1], &elem->x);\n    if (compressed) {\n        *size = 33;\n        pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);\n    } else {\n        *size = 65;\n        pub[0] = 0x04;\n        secp256k1_fe_get_b32(&pub[33], &elem->y);\n    }\n    return 1;\n}\n\nstatic int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {\n    secp256k1_scalar_add(key, key, tweak);\n    if (secp256k1_scalar_is_zero(key)) {\n        return 0;\n    }\n    return 1;\n}\n\nstatic int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {\n    secp256k1_gej pt;\n    secp256k1_scalar one;\n    secp256k1_gej_set_ge(&pt, key);\n    secp256k1_scalar_set_int(&one, 1);\n    secp256k1_ecmult(ctx, &pt, &pt, &one, tweak);\n\n    if (secp256k1_gej_is_infinity(&pt)) {\n        return 0;\n    }\n    secp256k1_ge_set_gej(key, &pt);\n    return 1;\n}\n\nstatic int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {\n    if (secp256k1_scalar_is_zero(tweak)) {\n        return 0;\n    }\n\n    secp256k1_scalar_mul(key, key, tweak);\n    return 1;\n}\n\nstatic int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {\n    secp256k1_scalar zero;\n    secp256k1_gej pt;\n    if (secp256k1_scalar_is_zero(tweak)) {\n        return 0;\n    }\n\n    secp256k1_scalar_set_int(&zero, 0);\n    secp256k1_gej_set_ge(&pt, key);\n    secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero);\n    secp256k1_ge_set_gej(key, &pt);\n    return 1;\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_\n#define _SECP256K1_ECMULT_\n\n#include \"num.h\"\n#include \"group.h\"\n\ntypedef struct {\n    /* For accelerating the computation of a*P + b*G: */\n    secp256k1_ge_storage (*pre_g)[];    /* odd multiples of the generator */\n#ifdef USE_ENDOMORPHISM\n    secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */\n#endif\n} secp256k1_ecmult_context;\n\nstatic void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);\nstatic void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);\nstatic void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,\n                                           const secp256k1_ecmult_context *src, const secp256k1_callback *cb);\nstatic void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);\nstatic int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);\n\n/** Double multiply: R = na*A + ng*G */\nstatic void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult_const.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_CONST_\n#define _SECP256K1_ECMULT_CONST_\n\n#include \"scalar.h\"\n#include \"group.h\"\n\nstatic void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult_const_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra                  *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_CONST_IMPL_\n#define _SECP256K1_ECMULT_CONST_IMPL_\n\n#include \"scalar.h\"\n#include \"group.h\"\n#include \"ecmult_const.h\"\n#include \"ecmult_impl.h\"\n\n#ifdef USE_ENDOMORPHISM\n    #define WNAF_BITS 128\n#else\n    #define WNAF_BITS 256\n#endif\n#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w))\n\n/* This is like `ECMULT_TABLE_GET_GE` but is constant time */\n#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \\\n    int m; \\\n    int abs_n = (n) * (((n) > 0) * 2 - 1); \\\n    int idx_n = abs_n / 2; \\\n    secp256k1_fe neg_y; \\\n    VERIFY_CHECK(((n) & 1) == 1); \\\n    VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \\\n    VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \\\n    VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \\\n    VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \\\n    for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \\\n        /* This loop is used to avoid secret data in array indices. See\n         * the comment in ecmult_gen_impl.h for rationale. */ \\\n        secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \\\n        secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \\\n    } \\\n    (r)->infinity = 0; \\\n    secp256k1_fe_negate(&neg_y, &(r)->y, 1); \\\n    secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \\\n} while(0)\n\n\n/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)\n *  with the following guarantees:\n *  - each wnaf[i] an odd integer between -(1 << w) and (1 << w)\n *  - each wnaf[i] is nonzero\n *  - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w\n *\n *  Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar\n *  Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)\n *  CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003\n *\n *  Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335\n */\nstatic int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {\n    int global_sign;\n    int skew = 0;\n    int word = 0;\n\n    /* 1 2 3 */\n    int u_last;\n    int u;\n\n    int flip;\n    int bit;\n    secp256k1_scalar neg_s;\n    int not_neg_one;\n    /* Note that we cannot handle even numbers by negating them to be odd, as is\n     * done in other implementations, since if our scalars were specified to have\n     * width < 256 for performance reasons, their negations would have width 256\n     * and we'd lose any performance benefit. Instead, we use a technique from\n     * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)\n     * or 2 (for odd) to the number we are encoding, returning a skew value indicating\n     * this, and having the caller compensate after doing the multiplication. */\n\n    /* Negative numbers will be negated to keep their bit representation below the maximum width */\n    flip = secp256k1_scalar_is_high(&s);\n    /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */\n    bit = flip ^ !secp256k1_scalar_is_even(&s);\n    /* We check for negative one, since adding 2 to it will cause an overflow */\n    secp256k1_scalar_negate(&neg_s, &s);\n    not_neg_one = !secp256k1_scalar_is_one(&neg_s);\n    secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);\n    /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects\n     * that we added two to it and flipped it. In fact for -1 these operations are\n     * identical. We only flipped, but since skewing is required (in the sense that\n     * the skew must be 1 or 2, never zero) and flipping is not, we need to change\n     * our flags to claim that we only skewed. */\n    global_sign = secp256k1_scalar_cond_negate(&s, flip);\n    global_sign *= not_neg_one * 2 - 1;\n    skew = 1 << bit;\n\n    /* 4 */\n    u_last = secp256k1_scalar_shr_int(&s, w);\n    while (word * w < WNAF_BITS) {\n        int sign;\n        int even;\n\n        /* 4.1 4.4 */\n        u = secp256k1_scalar_shr_int(&s, w);\n        /* 4.2 */\n        even = ((u & 1) == 0);\n        sign = 2 * (u_last > 0) - 1;\n        u += sign * even;\n        u_last -= sign * even * (1 << w);\n\n        /* 4.3, adapted for global sign change */\n        wnaf[word++] = u_last * global_sign;\n\n        u_last = u;\n    }\n    wnaf[word] = u * global_sign;\n\n    VERIFY_CHECK(secp256k1_scalar_is_zero(&s));\n    VERIFY_CHECK(word == WNAF_SIZE(w));\n    return skew;\n}\n\n\nstatic void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {\n    secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];\n    secp256k1_ge tmpa;\n    secp256k1_fe Z;\n\n    int skew_1;\n    int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];\n#ifdef USE_ENDOMORPHISM\n    secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];\n    int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];\n    int skew_lam;\n    secp256k1_scalar q_1, q_lam;\n#endif\n\n    int i;\n    secp256k1_scalar sc = *scalar;\n\n    /* build wnaf representation for q. */\n#ifdef USE_ENDOMORPHISM\n    /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */\n    secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);\n    skew_1   = secp256k1_wnaf_const(wnaf_1,   q_1,   WINDOW_A - 1);\n    skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);\n#else\n    skew_1   = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);\n#endif\n\n    /* Calculate odd multiples of a.\n     * All multiples are brought to the same Z 'denominator', which is stored\n     * in Z. Due to secp256k1' isomorphism we can do all operations pretending\n     * that the Z coordinate was 1, use affine addition formulae, and correct\n     * the Z coordinate of the result once at the end.\n     */\n    secp256k1_gej_set_ge(r, a);\n    secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);\n    for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {\n        secp256k1_fe_normalize_weak(&pre_a[i].y);\n    }\n#ifdef USE_ENDOMORPHISM\n    for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {\n        secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);\n    }\n#endif\n\n    /* first loop iteration (separated out so we can directly set r, rather\n     * than having it start at infinity, get doubled several times, then have\n     * its new value added to it) */\n    i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];\n    VERIFY_CHECK(i != 0);\n    ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);\n    secp256k1_gej_set_ge(r, &tmpa);\n#ifdef USE_ENDOMORPHISM\n    i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];\n    VERIFY_CHECK(i != 0);\n    ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);\n    secp256k1_gej_add_ge(r, r, &tmpa);\n#endif\n    /* remaining loop iterations */\n    for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {\n        int n;\n        int j;\n        for (j = 0; j < WINDOW_A - 1; ++j) {\n            secp256k1_gej_double_nonzero(r, r, NULL);\n        }\n\n        n = wnaf_1[i];\n        ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);\n        VERIFY_CHECK(n != 0);\n        secp256k1_gej_add_ge(r, r, &tmpa);\n#ifdef USE_ENDOMORPHISM\n        n = wnaf_lam[i];\n        ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);\n        VERIFY_CHECK(n != 0);\n        secp256k1_gej_add_ge(r, r, &tmpa);\n#endif\n    }\n\n    secp256k1_fe_mul(&r->z, &r->z, &Z);\n\n    {\n        /* Correct for wNAF skew */\n        secp256k1_ge correction = *a;\n        secp256k1_ge_storage correction_1_stor;\n#ifdef USE_ENDOMORPHISM\n        secp256k1_ge_storage correction_lam_stor;\n#endif\n        secp256k1_ge_storage a2_stor;\n        secp256k1_gej tmpj;\n        secp256k1_gej_set_ge(&tmpj, &correction);\n        secp256k1_gej_double_var(&tmpj, &tmpj, NULL);\n        secp256k1_ge_set_gej(&correction, &tmpj);\n        secp256k1_ge_to_storage(&correction_1_stor, a);\n#ifdef USE_ENDOMORPHISM\n        secp256k1_ge_to_storage(&correction_lam_stor, a);\n#endif\n        secp256k1_ge_to_storage(&a2_stor, &correction);\n\n        /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */\n        secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);\n#ifdef USE_ENDOMORPHISM\n        secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);\n#endif\n\n        /* Apply the correction */\n        secp256k1_ge_from_storage(&correction, &correction_1_stor);\n        secp256k1_ge_neg(&correction, &correction);\n        secp256k1_gej_add_ge(r, r, &correction);\n\n#ifdef USE_ENDOMORPHISM\n        secp256k1_ge_from_storage(&correction, &correction_lam_stor);\n        secp256k1_ge_neg(&correction, &correction);\n        secp256k1_ge_mul_lambda(&correction, &correction);\n        secp256k1_gej_add_ge(r, r, &correction);\n#endif\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult_gen.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_GEN_\n#define _SECP256K1_ECMULT_GEN_\n\n#include \"scalar.h\"\n#include \"group.h\"\n\ntypedef struct {\n    /* For accelerating the computation of a*G:\n     * To harden against timing attacks, use the following mechanism:\n     * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.\n     * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where:\n     *   * U_i = U * 2^i (for i=0..62)\n     *   * U_i = U * (1-2^63) (for i=63)\n     *   where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0.\n     * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is\n     * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).\n     * None of the resulting prec group elements have a known scalar, and neither do any of\n     * the intermediate sums while computing a*G.\n     */\n    secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */\n    secp256k1_scalar blind;\n    secp256k1_gej initial;\n} secp256k1_ecmult_gen_context;\n\nstatic void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);\nstatic void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);\nstatic void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,\n                                               const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);\nstatic void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);\nstatic int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);\n\n/** Multiply with the generator: R = a*G */\nstatic void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);\n\nstatic void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult_gen_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell      *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_\n#define _SECP256K1_ECMULT_GEN_IMPL_H_\n\n#include \"scalar.h\"\n#include \"group.h\"\n#include \"ecmult_gen.h\"\n#include \"hash_impl.h\"\n#ifdef USE_ECMULT_STATIC_PRECOMPUTATION\n#include \"ecmult_static_context.h\"\n#endif\nstatic void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {\n    ctx->prec = NULL;\n}\n\nstatic void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {\n#ifndef USE_ECMULT_STATIC_PRECOMPUTATION\n    secp256k1_ge prec[1024];\n    secp256k1_gej gj;\n    secp256k1_gej nums_gej;\n    int i, j;\n#endif\n\n    if (ctx->prec != NULL) {\n        return;\n    }\n#ifndef USE_ECMULT_STATIC_PRECOMPUTATION\n    ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));\n\n    /* get the generator */\n    secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);\n\n    /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */\n    {\n        static const unsigned char nums_b32[33] = \"The scalar for this x is unknown\";\n        secp256k1_fe nums_x;\n        secp256k1_ge nums_ge;\n        int r;\n        r = secp256k1_fe_set_b32(&nums_x, nums_b32);\n        (void)r;\n        VERIFY_CHECK(r);\n        r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);\n        (void)r;\n        VERIFY_CHECK(r);\n        secp256k1_gej_set_ge(&nums_gej, &nums_ge);\n        /* Add G to make the bits in x uniformly distributed. */\n        secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);\n    }\n\n    /* compute prec. */\n    {\n        secp256k1_gej precj[1024]; /* Jacobian versions of prec. */\n        secp256k1_gej gbase;\n        secp256k1_gej numsbase;\n        gbase = gj; /* 16^j * G */\n        numsbase = nums_gej; /* 2^j * nums. */\n        for (j = 0; j < 64; j++) {\n            /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */\n            precj[j*16] = numsbase;\n            for (i = 1; i < 16; i++) {\n                secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL);\n            }\n            /* Multiply gbase by 16. */\n            for (i = 0; i < 4; i++) {\n                secp256k1_gej_double_var(&gbase, &gbase, NULL);\n            }\n            /* Multiply numbase by 2. */\n            secp256k1_gej_double_var(&numsbase, &numsbase, NULL);\n            if (j == 62) {\n                /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */\n                secp256k1_gej_neg(&numsbase, &numsbase);\n                secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);\n            }\n        }\n        secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);\n    }\n    for (j = 0; j < 64; j++) {\n        for (i = 0; i < 16; i++) {\n            secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);\n        }\n    }\n#else\n    (void)cb;\n    ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;\n#endif\n    secp256k1_ecmult_gen_blind(ctx, NULL);\n}\n\nstatic int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) {\n    return ctx->prec != NULL;\n}\n\nstatic void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,\n                                               const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {\n    if (src->prec == NULL) {\n        dst->prec = NULL;\n    } else {\n#ifndef USE_ECMULT_STATIC_PRECOMPUTATION\n        dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));\n        memcpy(dst->prec, src->prec, sizeof(*dst->prec));\n#else\n        (void)cb;\n        dst->prec = src->prec;\n#endif\n        dst->initial = src->initial;\n        dst->blind = src->blind;\n    }\n}\n\nstatic void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {\n#ifndef USE_ECMULT_STATIC_PRECOMPUTATION\n    free(ctx->prec);\n#endif\n    secp256k1_scalar_clear(&ctx->blind);\n    secp256k1_gej_clear(&ctx->initial);\n    ctx->prec = NULL;\n}\n\nstatic void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {\n    secp256k1_ge add;\n    secp256k1_ge_storage adds;\n    secp256k1_scalar gnb;\n    int bits;\n    int i, j;\n    memset(&adds, 0, sizeof(adds));\n    *r = ctx->initial;\n    /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */\n    secp256k1_scalar_add(&gnb, gn, &ctx->blind);\n    add.infinity = 0;\n    for (j = 0; j < 64; j++) {\n        bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4);\n        for (i = 0; i < 16; i++) {\n            /** This uses a conditional move to avoid any secret data in array indexes.\n             *   _Any_ use of secret indexes has been demonstrated to result in timing\n             *   sidechannels, even when the cache-line access patterns are uniform.\n             *  See also:\n             *   \"A word of warning\", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe\n             *    (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and\n             *   \"Cache Attacks and Countermeasures: the Case of AES\", RSA 2006,\n             *    by Dag Arne Osvik, Adi Shamir, and Eran Tromer\n             *    (http://www.tau.ac.il/~tromer/papers/cache.pdf)\n             */\n            secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits);\n        }\n        secp256k1_ge_from_storage(&add, &adds);\n        secp256k1_gej_add_ge(r, r, &add);\n    }\n    bits = 0;\n    secp256k1_ge_clear(&add);\n    secp256k1_scalar_clear(&gnb);\n}\n\n/* Setup blinding values for secp256k1_ecmult_gen. */\nstatic void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {\n    secp256k1_scalar b;\n    secp256k1_gej gb;\n    secp256k1_fe s;\n    unsigned char nonce32[32];\n    secp256k1_rfc6979_hmac_sha256_t rng;\n    int retry;\n    unsigned char keydata[64] = {0};\n    if (seed32 == NULL) {\n        /* When seed is NULL, reset the initial point and blinding value. */\n        secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);\n        secp256k1_gej_neg(&ctx->initial, &ctx->initial);\n        secp256k1_scalar_set_int(&ctx->blind, 1);\n    }\n    /* The prior blinding value (if not reset) is chained forward by including it in the hash. */\n    secp256k1_scalar_get_b32(nonce32, &ctx->blind);\n    /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,\n     *   and guards against weak or adversarial seeds.  This is a simpler and safer interface than\n     *   asking the caller for blinding values directly and expecting them to retry on failure.\n     */\n    memcpy(keydata, nonce32, 32);\n    if (seed32 != NULL) {\n        memcpy(keydata + 32, seed32, 32);\n    }\n    secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);\n    memset(keydata, 0, sizeof(keydata));\n    /* Retry for out of range results to achieve uniformity. */\n    do {\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);\n        retry = !secp256k1_fe_set_b32(&s, nonce32);\n        retry |= secp256k1_fe_is_zero(&s);\n    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */\n    /* Randomize the projection to defend against multiplier sidechannels. */\n    secp256k1_gej_rescale(&ctx->initial, &s);\n    secp256k1_fe_clear(&s);\n    do {\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);\n        secp256k1_scalar_set_b32(&b, nonce32, &retry);\n        /* A blinding value of 0 works, but would undermine the projection hardening. */\n        retry |= secp256k1_scalar_is_zero(&b);\n    } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */\n    secp256k1_rfc6979_hmac_sha256_finalize(&rng);\n    memset(nonce32, 0, 32);\n    secp256k1_ecmult_gen(ctx, &gb, &b);\n    secp256k1_scalar_negate(&b, &b);\n    ctx->blind = b;\n    ctx->initial = gb;\n    secp256k1_scalar_clear(&b);\n    secp256k1_gej_clear(&gb);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/ecmult_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_ECMULT_IMPL_H_\n#define _SECP256K1_ECMULT_IMPL_H_\n\n#include <string.h>\n\n#include \"group.h\"\n#include \"scalar.h\"\n#include \"ecmult.h\"\n\n#if defined(EXHAUSTIVE_TEST_ORDER)\n/* We need to lower these values for exhaustive tests because\n * the tables cannot have infinities in them (this breaks the\n * affine-isomorphism stuff which tracks z-ratios) */\n#  if EXHAUSTIVE_TEST_ORDER > 128\n#    define WINDOW_A 5\n#    define WINDOW_G 8\n#  elif EXHAUSTIVE_TEST_ORDER > 8\n#    define WINDOW_A 4\n#    define WINDOW_G 4\n#  else\n#    define WINDOW_A 2\n#    define WINDOW_G 2\n#  endif\n#else\n/* optimal for 128-bit and 256-bit exponents. */\n#define WINDOW_A 5\n/** larger numbers may result in slightly better performance, at the cost of\n    exponentially larger precomputed tables. */\n#ifdef USE_ENDOMORPHISM\n/** Two tables for window size 15: 1.375 MiB. */\n#define WINDOW_G 15\n#else\n/** One table for window size 16: 1.375 MiB. */\n#define WINDOW_G 16\n#endif\n#endif\n\n/** The number of entries a table with precomputed multiples needs to have. */\n#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))\n\n/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain\n *  the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will\n *  contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.\n *  Prej's Z values are undefined, except for the last value.\n */\nstatic void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {\n    secp256k1_gej d;\n    secp256k1_ge a_ge, d_ge;\n    int i;\n\n    VERIFY_CHECK(!a->infinity);\n\n    secp256k1_gej_double_var(&d, a, NULL);\n\n    /*\n     * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate\n     * of 'd', and scale the 1P starting value's x/y coordinates without changing its z.\n     */\n    d_ge.x = d.x;\n    d_ge.y = d.y;\n    d_ge.infinity = 0;\n\n    secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);\n    prej[0].x = a_ge.x;\n    prej[0].y = a_ge.y;\n    prej[0].z = a->z;\n    prej[0].infinity = 0;\n\n    zr[0] = d.z;\n    for (i = 1; i < n; i++) {\n        secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);\n    }\n\n    /*\n     * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only\n     * the final point's z coordinate is actually used though, so just update that.\n     */\n    secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);\n}\n\n/** Fill a table 'pre' with precomputed odd multiples of a.\n *\n *  There are two versions of this function:\n *  - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its\n *    resulting point set to a single constant Z denominator, stores the X and Y\n *    coordinates as ge_storage points in pre, and stores the global Z in rz.\n *    It only operates on tables sized for WINDOW_A wnaf multiples.\n *  - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its\n *    resulting point set to actually affine points, and stores those in pre.\n *    It operates on tables of any size, but uses heap-allocated temporaries.\n *\n *  To compute a*P + b*G, we compute a table for P using the first function,\n *  and for G using the second (which requires an inverse, but it only needs to\n *  happen once).\n */\nstatic void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {\n    secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];\n    secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];\n\n    /* Compute the odd multiples in Jacobian form. */\n    secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);\n    /* Bring them to the same Z denominator. */\n    secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);\n}\n\nstatic void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) {\n    secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n);\n    secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n);\n    secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n);\n    int i;\n\n    /* Compute the odd multiples in Jacobian form. */\n    secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);\n    /* Convert them in batch to affine coordinates. */\n    secp256k1_ge_set_table_gej_var(prea, prej, zr, n);\n    /* Convert them to compact storage form. */\n    for (i = 0; i < n; i++) {\n        secp256k1_ge_to_storage(&pre[i], &prea[i]);\n    }\n\n    free(prea);\n    free(prej);\n    free(zr);\n}\n\n/** The following two macro retrieves a particular odd multiple from a table\n *  of precomputed multiples. */\n#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \\\n    VERIFY_CHECK(((n) & 1) == 1); \\\n    VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \\\n    VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \\\n    if ((n) > 0) { \\\n        *(r) = (pre)[((n)-1)/2]; \\\n    } else { \\\n        secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \\\n    } \\\n} while(0)\n\n#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \\\n    VERIFY_CHECK(((n) & 1) == 1); \\\n    VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \\\n    VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \\\n    if ((n) > 0) { \\\n        secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \\\n    } else { \\\n        secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \\\n        secp256k1_ge_neg((r), (r)); \\\n    } \\\n} while(0)\n\nstatic void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) {\n    ctx->pre_g = NULL;\n#ifdef USE_ENDOMORPHISM\n    ctx->pre_g_128 = NULL;\n#endif\n}\n\nstatic void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {\n    secp256k1_gej gj;\n\n    if (ctx->pre_g != NULL) {\n        return;\n    }\n\n    /* get the generator */\n    secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);\n\n    ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));\n\n    /* precompute the tables with odd multiples */\n    secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);\n\n#ifdef USE_ENDOMORPHISM\n    {\n        secp256k1_gej g_128j;\n        int i;\n\n        ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));\n\n        /* calculate 2^128*generator */\n        g_128j = gj;\n        for (i = 0; i < 128; i++) {\n            secp256k1_gej_double_var(&g_128j, &g_128j, NULL);\n        }\n        secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb);\n    }\n#endif\n}\n\nstatic void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,\n                                           const secp256k1_ecmult_context *src, const secp256k1_callback *cb) {\n    if (src->pre_g == NULL) {\n        dst->pre_g = NULL;\n    } else {\n        size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);\n        dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);\n        memcpy(dst->pre_g, src->pre_g, size);\n    }\n#ifdef USE_ENDOMORPHISM\n    if (src->pre_g_128 == NULL) {\n        dst->pre_g_128 = NULL;\n    } else {\n        size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G);\n        dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);\n        memcpy(dst->pre_g_128, src->pre_g_128, size);\n    }\n#endif\n}\n\nstatic int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) {\n    return ctx->pre_g != NULL;\n}\n\nstatic void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {\n    free(ctx->pre_g);\n#ifdef USE_ENDOMORPHISM\n    free(ctx->pre_g_128);\n#endif\n    secp256k1_ecmult_context_init(ctx);\n}\n\n/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),\n *  with the following guarantees:\n *  - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)\n *  - two non-zero entries in wnaf are separated by at least w-1 zeroes.\n *  - the number of set values in wnaf is returned. This number is at most 256, and at most one more\n *    than the number of bits in the (absolute value) of the input.\n */\nstatic int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) {\n    secp256k1_scalar s = *a;\n    int last_set_bit = -1;\n    int bit = 0;\n    int sign = 1;\n    int carry = 0;\n\n    VERIFY_CHECK(wnaf != NULL);\n    VERIFY_CHECK(0 <= len && len <= 256);\n    VERIFY_CHECK(a != NULL);\n    VERIFY_CHECK(2 <= w && w <= 31);\n\n    memset(wnaf, 0, len * sizeof(wnaf[0]));\n\n    if (secp256k1_scalar_get_bits(&s, 255, 1)) {\n        secp256k1_scalar_negate(&s, &s);\n        sign = -1;\n    }\n\n    while (bit < len) {\n        int now;\n        int word;\n        if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {\n            bit++;\n            continue;\n        }\n\n        now = w;\n        if (now > len - bit) {\n            now = len - bit;\n        }\n\n        word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry;\n\n        carry = (word >> (w-1)) & 1;\n        word -= carry << w;\n\n        wnaf[bit] = sign * word;\n        last_set_bit = bit;\n\n        bit += now;\n    }\n#ifdef VERIFY\n    CHECK(carry == 0);\n    while (bit < 256) {\n        CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);\n    } \n#endif\n    return last_set_bit + 1;\n}\n\nstatic void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {\n    secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];\n    secp256k1_ge tmpa;\n    secp256k1_fe Z;\n#ifdef USE_ENDOMORPHISM\n    secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];\n    secp256k1_scalar na_1, na_lam;\n    /* Splitted G factors. */\n    secp256k1_scalar ng_1, ng_128;\n    int wnaf_na_1[130];\n    int wnaf_na_lam[130];\n    int bits_na_1;\n    int bits_na_lam;\n    int wnaf_ng_1[129];\n    int bits_ng_1;\n    int wnaf_ng_128[129];\n    int bits_ng_128;\n#else\n    int wnaf_na[256];\n    int bits_na;\n    int wnaf_ng[256];\n    int bits_ng;\n#endif\n    int i;\n    int bits;\n\n#ifdef USE_ENDOMORPHISM\n    /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */\n    secp256k1_scalar_split_lambda(&na_1, &na_lam, na);\n\n    /* build wnaf representation for na_1 and na_lam. */\n    bits_na_1   = secp256k1_ecmult_wnaf(wnaf_na_1,   130, &na_1,   WINDOW_A);\n    bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A);\n    VERIFY_CHECK(bits_na_1 <= 130);\n    VERIFY_CHECK(bits_na_lam <= 130);\n    bits = bits_na_1;\n    if (bits_na_lam > bits) {\n        bits = bits_na_lam;\n    }\n#else\n    /* build wnaf representation for na. */\n    bits_na     = secp256k1_ecmult_wnaf(wnaf_na,     256, na,      WINDOW_A);\n    bits = bits_na;\n#endif\n\n    /* Calculate odd multiples of a.\n     * All multiples are brought to the same Z 'denominator', which is stored\n     * in Z. Due to secp256k1' isomorphism we can do all operations pretending\n     * that the Z coordinate was 1, use affine addition formulae, and correct\n     * the Z coordinate of the result once at the end.\n     * The exception is the precomputed G table points, which are actually\n     * affine. Compared to the base used for other points, they have a Z ratio\n     * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same\n     * isomorphism to efficiently add with a known Z inverse.\n     */\n    secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a);\n\n#ifdef USE_ENDOMORPHISM\n    for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {\n        secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);\n    }\n\n    /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */\n    secp256k1_scalar_split_128(&ng_1, &ng_128, ng);\n\n    /* Build wnaf representation for ng_1 and ng_128 */\n    bits_ng_1   = secp256k1_ecmult_wnaf(wnaf_ng_1,   129, &ng_1,   WINDOW_G);\n    bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);\n    if (bits_ng_1 > bits) {\n        bits = bits_ng_1;\n    }\n    if (bits_ng_128 > bits) {\n        bits = bits_ng_128;\n    }\n#else\n    bits_ng     = secp256k1_ecmult_wnaf(wnaf_ng,     256, ng,      WINDOW_G);\n    if (bits_ng > bits) {\n        bits = bits_ng;\n    }\n#endif\n\n    secp256k1_gej_set_infinity(r);\n\n    for (i = bits - 1; i >= 0; i--) {\n        int n;\n        secp256k1_gej_double_var(r, r, NULL);\n#ifdef USE_ENDOMORPHISM\n        if (i < bits_na_1 && (n = wnaf_na_1[i])) {\n            ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);\n            secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);\n        }\n        if (i < bits_na_lam && (n = wnaf_na_lam[i])) {\n            ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);\n            secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);\n        }\n        if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {\n            ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);\n            secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);\n        }\n        if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {\n            ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G);\n            secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);\n        }\n#else\n        if (i < bits_na && (n = wnaf_na[i])) {\n            ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);\n            secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);\n        }\n        if (i < bits_ng && (n = wnaf_ng[i])) {\n            ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);\n            secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);\n        }\n#endif\n    }\n\n    if (!r->infinity) {\n        secp256k1_fe_mul(&r->z, &r->z, &Z);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_\n#define _SECP256K1_FIELD_\n\n/** Field element module.\n *\n *  Field elements can be represented in several ways, but code accessing\n *  it (and implementations) need to take certain properties into account:\n *  - Each field element can be normalized or not.\n *  - Each field element has a magnitude, which represents how far away\n *    its representation is away from normalization. Normalized elements\n *    always have a magnitude of 1, but a magnitude of 1 doesn't imply\n *    normality.\n */\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#if defined(USE_FIELD_10X26)\n#include \"field_10x26.h\"\n#elif defined(USE_FIELD_5X52)\n#include \"field_5x52.h\"\n#else\n#error \"Please select field implementation\"\n#endif\n\n#include \"util.h\"\n\n/** Normalize a field element. */\nstatic void secp256k1_fe_normalize(secp256k1_fe *r);\n\n/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */\nstatic void secp256k1_fe_normalize_weak(secp256k1_fe *r);\n\n/** Normalize a field element, without constant-time guarantee. */\nstatic void secp256k1_fe_normalize_var(secp256k1_fe *r);\n\n/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field\n *  implementation may optionally normalize the input, but this should not be relied upon. */\nstatic int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r);\n\n/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field\n *  implementation may optionally normalize the input, but this should not be relied upon. */\nstatic int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);\n\n/** Set a field element equal to a small integer. Resulting field element is normalized. */\nstatic void secp256k1_fe_set_int(secp256k1_fe *r, int a);\n\n/** Sets a field element equal to zero, initializing all fields. */\nstatic void secp256k1_fe_clear(secp256k1_fe *a);\n\n/** Verify whether a field element is zero. Requires the input to be normalized. */\nstatic int secp256k1_fe_is_zero(const secp256k1_fe *a);\n\n/** Check the \"oddness\" of a field element. Requires the input to be normalized. */\nstatic int secp256k1_fe_is_odd(const secp256k1_fe *a);\n\n/** Compare two field elements. Requires magnitude-1 inputs. */\nstatic int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);\n\n/** Same as secp256k1_fe_equal, but may be variable time. */\nstatic int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);\n\n/** Compare two field elements. Requires both inputs to be normalized */\nstatic int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);\n\n/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */\nstatic int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);\n\n/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */\nstatic void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);\n\n/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input\n *  as an argument. The magnitude of the output is one higher. */\nstatic void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);\n\n/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that\n *  small integer. */\nstatic void secp256k1_fe_mul_int(secp256k1_fe *r, int a);\n\n/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */\nstatic void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);\n\n/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.\n *  The output magnitude is 1 (but not guaranteed to be normalized). */\nstatic void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);\n\n/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.\n *  The output magnitude is 1 (but not guaranteed to be normalized). */\nstatic void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);\n\n/** If a has a square root, it is computed in r and 1 is returned. If a does not\n *  have a square root, the root of its negation is computed and 0 is returned.\n *  The input's magnitude can be at most 8. The output magnitude is 1 (but not\n *  guaranteed to be normalized). The result in r will always be a square\n *  itself. */\nstatic int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);\n\n/** Checks whether a field element is a quadratic residue. */\nstatic int secp256k1_fe_is_quad_var(const secp256k1_fe *a);\n\n/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be\n *  at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */\nstatic void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);\n\n/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */\nstatic void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);\n\n/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be\n *  at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and\n *  outputs must not overlap in memory. */\nstatic void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len);\n\n/** Convert a field element to the storage type. */\nstatic void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);\n\n/** Convert a field element back from the storage type. */\nstatic void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);\n\n/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */\nstatic void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);\n\n/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */\nstatic void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_10x26.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_REPR_\n#define _SECP256K1_FIELD_REPR_\n\n#include <stdint.h>\n\ntypedef struct {\n    /* X = sum(i=0..9, elem[i]*2^26) mod n */\n    uint32_t n[10];\n#ifdef VERIFY\n    int magnitude;\n    int normalized;\n#endif\n} secp256k1_fe;\n\n/* Unpacks a constant into a overlapping multi-limbed FE element. */\n#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \\\n    (d0) & 0x3FFFFFFUL, \\\n    (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \\\n    (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \\\n    (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \\\n    (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \\\n    (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \\\n    (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \\\n    (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \\\n    (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \\\n    (((uint32_t)d7) >> 10) \\\n}\n\n#ifdef VERIFY\n#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}\n#else\n#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}\n#endif\n\ntypedef struct {\n    uint32_t n[8];\n} secp256k1_fe_storage;\n\n#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}\n#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_10x26_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_REPR_IMPL_H_\n#define _SECP256K1_FIELD_REPR_IMPL_H_\n\n#include \"util.h\"\n#include \"num.h\"\n#include \"field.h\"\n\n#ifdef VERIFY\nstatic void secp256k1_fe_verify(const secp256k1_fe *a) {\n    const uint32_t *d = a->n;\n    int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;\n    r &= (d[0] <= 0x3FFFFFFUL * m);\n    r &= (d[1] <= 0x3FFFFFFUL * m);\n    r &= (d[2] <= 0x3FFFFFFUL * m);\n    r &= (d[3] <= 0x3FFFFFFUL * m);\n    r &= (d[4] <= 0x3FFFFFFUL * m);\n    r &= (d[5] <= 0x3FFFFFFUL * m);\n    r &= (d[6] <= 0x3FFFFFFUL * m);\n    r &= (d[7] <= 0x3FFFFFFUL * m);\n    r &= (d[8] <= 0x3FFFFFFUL * m);\n    r &= (d[9] <= 0x03FFFFFUL * m);\n    r &= (a->magnitude >= 0);\n    r &= (a->magnitude <= 32);\n    if (a->normalized) {\n        r &= (a->magnitude <= 1);\n        if (r && (d[9] == 0x03FFFFFUL)) {\n            uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2];\n            if (mid == 0x3FFFFFFUL) {\n                r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);\n            }\n        }\n    }\n    VERIFY_CHECK(r == 1);\n}\n#endif\n\nstatic void secp256k1_fe_normalize(secp256k1_fe *r) {\n    uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],\n             t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];\n\n    /* Reduce t9 at the start so there will be at most a single carry from the first pass */\n    uint32_t m;\n    uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x3D1UL; t1 += (x << 6);\n    t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL;\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8;\n\n    /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t9 >> 23 == 0);\n\n    /* At most a single final reduction is needed; check if the value is >= the field characteristic */\n    x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL)\n        & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));\n\n    /* Apply the final reduction (for constant-time behaviour, we do it always) */\n    t0 += x * 0x3D1UL; t1 += (x << 6);\n    t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL;\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL;\n\n    /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */\n    VERIFY_CHECK(t9 >> 22 == x);\n\n    /* Mask off the possible multiple of 2^256 from the final reduction */\n    t9 &= 0x03FFFFFUL;\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n    r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_normalize_weak(secp256k1_fe *r) {\n    uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],\n             t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];\n\n    /* Reduce t9 at the start so there will be at most a single carry from the first pass */\n    uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x3D1UL; t1 += (x << 6);\n    t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL;\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL;\n\n    /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t9 >> 23 == 0);\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n    r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_normalize_var(secp256k1_fe *r) {\n    uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],\n             t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];\n\n    /* Reduce t9 at the start so there will be at most a single carry from the first pass */\n    uint32_t m;\n    uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x3D1UL; t1 += (x << 6);\n    t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL;\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8;\n\n    /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t9 >> 23 == 0);\n\n    /* At most a single final reduction is needed; check if the value is >= the field characteristic */\n    x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL)\n        & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));\n\n    if (x) {\n        t0 += 0x3D1UL; t1 += (x << 6);\n        t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL;\n        t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL;\n        t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL;\n        t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL;\n        t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL;\n        t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL;\n        t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL;\n        t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL;\n        t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL;\n\n        /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */\n        VERIFY_CHECK(t9 >> 22 == x);\n\n        /* Mask off the possible multiple of 2^256 from the final reduction */\n        t9 &= 0x03FFFFFUL;\n    }\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n    r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {\n    uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],\n             t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];\n\n    /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */\n    uint32_t z0, z1;\n\n    /* Reduce t9 at the start so there will be at most a single carry from the first pass */\n    uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x3D1UL; t1 += (x << 6);\n    t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0  = t0; z1  = t0 ^ 0x3D0UL;\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8;\n                                         z0 |= t9; z1 &= t9 ^ 0x3C00000UL;\n\n    /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t9 >> 23 == 0);\n\n    return (z0 == 0) | (z1 == 0x3FFFFFFUL);\n}\n\nstatic int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {\n    uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;\n    uint32_t z0, z1;\n    uint32_t x;\n\n    t0 = r->n[0];\n    t9 = r->n[9];\n\n    /* Reduce t9 at the start so there will be at most a single carry from the first pass */\n    x = t9 >> 22;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x3D1UL;\n\n    /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */\n    z0 = t0 & 0x3FFFFFFUL;\n    z1 = z0 ^ 0x3D0UL;\n\n    /* Fast return path should catch the majority of cases */\n    if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) {\n        return 0;\n    }\n\n    t1 = r->n[1];\n    t2 = r->n[2];\n    t3 = r->n[3];\n    t4 = r->n[4];\n    t5 = r->n[5];\n    t6 = r->n[6];\n    t7 = r->n[7];\n    t8 = r->n[8];\n\n    t9 &= 0x03FFFFFUL;\n    t1 += (x << 6);\n\n    t1 += (t0 >> 26);\n    t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL;\n    t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2;\n    t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3;\n    t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4;\n    t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5;\n    t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6;\n    t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7;\n    t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8;\n                                         z0 |= t9; z1 &= t9 ^ 0x3C00000UL;\n\n    /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t9 >> 23 == 0);\n\n    return (z0 == 0) | (z1 == 0x3FFFFFFUL);\n}\n\nSECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {\n    r->n[0] = a;\n    r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {\n    const uint32_t *t = a->n;\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;\n}\n\nSECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    return a->n[0] & 1;\n}\n\nSECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {\n    int i;\n#ifdef VERIFY\n    a->magnitude = 0;\n    a->normalized = 1;\n#endif\n    for (i=0; i<10; i++) {\n        a->n[i] = 0;\n    }\n}\n\nstatic int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {\n    int i;\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    VERIFY_CHECK(b->normalized);\n    secp256k1_fe_verify(a);\n    secp256k1_fe_verify(b);\n#endif\n    for (i = 9; i >= 0; i--) {\n        if (a->n[i] > b->n[i]) {\n            return 1;\n        }\n        if (a->n[i] < b->n[i]) {\n            return -1;\n        }\n    }\n    return 0;\n}\n\nstatic int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {\n    r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);\n    r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);\n    r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);\n    r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18);\n    r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24);\n    r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22);\n    r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20);\n    r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);\n    r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);\n    r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);\n\n    if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {\n        return 0;\n    }\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n    return 1;\n}\n\n/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */\nstatic void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    r[0] = (a->n[9] >> 14) & 0xff;\n    r[1] = (a->n[9] >> 6) & 0xff;\n    r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);\n    r[3] = (a->n[8] >> 16) & 0xff;\n    r[4] = (a->n[8] >> 8) & 0xff;\n    r[5] = a->n[8] & 0xff;\n    r[6] = (a->n[7] >> 18) & 0xff;\n    r[7] = (a->n[7] >> 10) & 0xff;\n    r[8] = (a->n[7] >> 2) & 0xff;\n    r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f);\n    r[10] = (a->n[6] >> 12) & 0xff;\n    r[11] = (a->n[6] >> 4) & 0xff;\n    r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf);\n    r[13] = (a->n[5] >> 14) & 0xff;\n    r[14] = (a->n[5] >> 6) & 0xff;\n    r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3);\n    r[16] = (a->n[4] >> 16) & 0xff;\n    r[17] = (a->n[4] >> 8) & 0xff;\n    r[18] = a->n[4] & 0xff;\n    r[19] = (a->n[3] >> 18) & 0xff;\n    r[20] = (a->n[3] >> 10) & 0xff;\n    r[21] = (a->n[3] >> 2) & 0xff;\n    r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f);\n    r[23] = (a->n[2] >> 12) & 0xff;\n    r[24] = (a->n[2] >> 4) & 0xff;\n    r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf);\n    r[26] = (a->n[1] >> 14) & 0xff;\n    r[27] = (a->n[1] >> 6) & 0xff;\n    r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3);\n    r[29] = (a->n[0] >> 16) & 0xff;\n    r[30] = (a->n[0] >> 8) & 0xff;\n    r[31] = a->n[0] & 0xff;\n}\n\nSECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= m);\n    secp256k1_fe_verify(a);\n#endif\n    r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];\n    r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];\n    r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2];\n    r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3];\n    r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4];\n    r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5];\n    r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6];\n    r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7];\n    r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8];\n    r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];\n#ifdef VERIFY\n    r->magnitude = m + 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {\n    r->n[0] *= a;\n    r->n[1] *= a;\n    r->n[2] *= a;\n    r->n[3] *= a;\n    r->n[4] *= a;\n    r->n[5] *= a;\n    r->n[6] *= a;\n    r->n[7] *= a;\n    r->n[8] *= a;\n    r->n[9] *= a;\n#ifdef VERIFY\n    r->magnitude *= a;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    secp256k1_fe_verify(a);\n#endif\n    r->n[0] += a->n[0];\n    r->n[1] += a->n[1];\n    r->n[2] += a->n[2];\n    r->n[3] += a->n[3];\n    r->n[4] += a->n[4];\n    r->n[5] += a->n[5];\n    r->n[6] += a->n[6];\n    r->n[7] += a->n[7];\n    r->n[8] += a->n[8];\n    r->n[9] += a->n[9];\n#ifdef VERIFY\n    r->magnitude += a->magnitude;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\n#if defined(USE_EXTERNAL_ASM)\n\n/* External assembler implementation */\nvoid secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);\nvoid secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);\n\n#else\n\n#ifdef VERIFY\n#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)\n#else\n#define VERIFY_BITS(x, n) do { } while(0)\n#endif\n\nSECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {\n    uint64_t c, d;\n    uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8;\n    uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7;\n    const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;\n\n    VERIFY_BITS(a[0], 30);\n    VERIFY_BITS(a[1], 30);\n    VERIFY_BITS(a[2], 30);\n    VERIFY_BITS(a[3], 30);\n    VERIFY_BITS(a[4], 30);\n    VERIFY_BITS(a[5], 30);\n    VERIFY_BITS(a[6], 30);\n    VERIFY_BITS(a[7], 30);\n    VERIFY_BITS(a[8], 30);\n    VERIFY_BITS(a[9], 26);\n    VERIFY_BITS(b[0], 30);\n    VERIFY_BITS(b[1], 30);\n    VERIFY_BITS(b[2], 30);\n    VERIFY_BITS(b[3], 30);\n    VERIFY_BITS(b[4], 30);\n    VERIFY_BITS(b[5], 30);\n    VERIFY_BITS(b[6], 30);\n    VERIFY_BITS(b[7], 30);\n    VERIFY_BITS(b[8], 30);\n    VERIFY_BITS(b[9], 26);\n\n    /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.\n     *  px is a shorthand for sum(a[i]*b[x-i], i=0..x).\n     *  Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].\n     */\n\n    d  = (uint64_t)a[0] * b[9]\n       + (uint64_t)a[1] * b[8]\n       + (uint64_t)a[2] * b[7]\n       + (uint64_t)a[3] * b[6]\n       + (uint64_t)a[4] * b[5]\n       + (uint64_t)a[5] * b[4]\n       + (uint64_t)a[6] * b[3]\n       + (uint64_t)a[7] * b[2]\n       + (uint64_t)a[8] * b[1]\n       + (uint64_t)a[9] * b[0];\n    /* VERIFY_BITS(d, 64); */\n    /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */\n    t9 = d & M; d >>= 26;\n    VERIFY_BITS(t9, 26);\n    VERIFY_BITS(d, 38);\n    /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */\n\n    c  = (uint64_t)a[0] * b[0];\n    VERIFY_BITS(c, 60);\n    /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */\n    d += (uint64_t)a[1] * b[9]\n       + (uint64_t)a[2] * b[8]\n       + (uint64_t)a[3] * b[7]\n       + (uint64_t)a[4] * b[6]\n       + (uint64_t)a[5] * b[5]\n       + (uint64_t)a[6] * b[4]\n       + (uint64_t)a[7] * b[3]\n       + (uint64_t)a[8] * b[2]\n       + (uint64_t)a[9] * b[1];\n    VERIFY_BITS(d, 63);\n    /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    u0 = d & M; d >>= 26; c += u0 * R0;\n    VERIFY_BITS(u0, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 61);\n    /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    t0 = c & M; c >>= 26; c += u0 * R1;\n    VERIFY_BITS(t0, 26);\n    VERIFY_BITS(c, 37);\n    /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n\n    c += (uint64_t)a[0] * b[1]\n       + (uint64_t)a[1] * b[0];\n    VERIFY_BITS(c, 62);\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    d += (uint64_t)a[2] * b[9]\n       + (uint64_t)a[3] * b[8]\n       + (uint64_t)a[4] * b[7]\n       + (uint64_t)a[5] * b[6]\n       + (uint64_t)a[6] * b[5]\n       + (uint64_t)a[7] * b[4]\n       + (uint64_t)a[8] * b[3]\n       + (uint64_t)a[9] * b[2];\n    VERIFY_BITS(d, 63);\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    u1 = d & M; d >>= 26; c += u1 * R0;\n    VERIFY_BITS(u1, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 63);\n    /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    t1 = c & M; c >>= 26; c += u1 * R1;\n    VERIFY_BITS(t1, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n\n    c += (uint64_t)a[0] * b[2]\n       + (uint64_t)a[1] * b[1]\n       + (uint64_t)a[2] * b[0];\n    VERIFY_BITS(c, 62);\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    d += (uint64_t)a[3] * b[9]\n       + (uint64_t)a[4] * b[8]\n       + (uint64_t)a[5] * b[7]\n       + (uint64_t)a[6] * b[6]\n       + (uint64_t)a[7] * b[5]\n       + (uint64_t)a[8] * b[4]\n       + (uint64_t)a[9] * b[3];\n    VERIFY_BITS(d, 63);\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    u2 = d & M; d >>= 26; c += u2 * R0;\n    VERIFY_BITS(u2, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 63);\n    /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    t2 = c & M; c >>= 26; c += u2 * R1;\n    VERIFY_BITS(t2, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[3]\n       + (uint64_t)a[1] * b[2]\n       + (uint64_t)a[2] * b[1]\n       + (uint64_t)a[3] * b[0];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    d += (uint64_t)a[4] * b[9]\n       + (uint64_t)a[5] * b[8]\n       + (uint64_t)a[6] * b[7]\n       + (uint64_t)a[7] * b[6]\n       + (uint64_t)a[8] * b[5]\n       + (uint64_t)a[9] * b[4];\n    VERIFY_BITS(d, 63);\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    u3 = d & M; d >>= 26; c += u3 * R0;\n    VERIFY_BITS(u3, 26);\n    VERIFY_BITS(d, 37);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    t3 = c & M; c >>= 26; c += u3 * R1;\n    VERIFY_BITS(t3, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[4]\n       + (uint64_t)a[1] * b[3]\n       + (uint64_t)a[2] * b[2]\n       + (uint64_t)a[3] * b[1]\n       + (uint64_t)a[4] * b[0];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[5] * b[9]\n       + (uint64_t)a[6] * b[8]\n       + (uint64_t)a[7] * b[7]\n       + (uint64_t)a[8] * b[6]\n       + (uint64_t)a[9] * b[5];\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    u4 = d & M; d >>= 26; c += u4 * R0;\n    VERIFY_BITS(u4, 26);\n    VERIFY_BITS(d, 36);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    t4 = c & M; c >>= 26; c += u4 * R1;\n    VERIFY_BITS(t4, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[5]\n       + (uint64_t)a[1] * b[4]\n       + (uint64_t)a[2] * b[3]\n       + (uint64_t)a[3] * b[2]\n       + (uint64_t)a[4] * b[1]\n       + (uint64_t)a[5] * b[0];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[6] * b[9]\n       + (uint64_t)a[7] * b[8]\n       + (uint64_t)a[8] * b[7]\n       + (uint64_t)a[9] * b[6];\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    u5 = d & M; d >>= 26; c += u5 * R0;\n    VERIFY_BITS(u5, 26);\n    VERIFY_BITS(d, 36);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    t5 = c & M; c >>= 26; c += u5 * R1;\n    VERIFY_BITS(t5, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[6]\n       + (uint64_t)a[1] * b[5]\n       + (uint64_t)a[2] * b[4]\n       + (uint64_t)a[3] * b[3]\n       + (uint64_t)a[4] * b[2]\n       + (uint64_t)a[5] * b[1]\n       + (uint64_t)a[6] * b[0];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[7] * b[9]\n       + (uint64_t)a[8] * b[8]\n       + (uint64_t)a[9] * b[7];\n    VERIFY_BITS(d, 61);\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    u6 = d & M; d >>= 26; c += u6 * R0;\n    VERIFY_BITS(u6, 26);\n    VERIFY_BITS(d, 35);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    t6 = c & M; c >>= 26; c += u6 * R1;\n    VERIFY_BITS(t6, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[7]\n       + (uint64_t)a[1] * b[6]\n       + (uint64_t)a[2] * b[5]\n       + (uint64_t)a[3] * b[4]\n       + (uint64_t)a[4] * b[3]\n       + (uint64_t)a[5] * b[2]\n       + (uint64_t)a[6] * b[1]\n       + (uint64_t)a[7] * b[0];\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x8000007C00000007ULL);\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[8] * b[9]\n       + (uint64_t)a[9] * b[8];\n    VERIFY_BITS(d, 58);\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    u7 = d & M; d >>= 26; c += u7 * R0;\n    VERIFY_BITS(u7, 26);\n    VERIFY_BITS(d, 32);\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL);\n    /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    t7 = c & M; c >>= 26; c += u7 * R1;\n    VERIFY_BITS(t7, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)a[0] * b[8]\n       + (uint64_t)a[1] * b[7]\n       + (uint64_t)a[2] * b[6]\n       + (uint64_t)a[3] * b[5]\n       + (uint64_t)a[4] * b[4]\n       + (uint64_t)a[5] * b[3]\n       + (uint64_t)a[6] * b[2]\n       + (uint64_t)a[7] * b[1]\n       + (uint64_t)a[8] * b[0];\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x9000007B80000008ULL);\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[9] * b[9];\n    VERIFY_BITS(d, 57);\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    u8 = d & M; d >>= 26; c += u8 * R0;\n    VERIFY_BITS(u8, 26);\n    VERIFY_BITS(d, 31);\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    r[3] = t3;\n    VERIFY_BITS(r[3], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[4] = t4;\n    VERIFY_BITS(r[4], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[5] = t5;\n    VERIFY_BITS(r[5], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[6] = t6;\n    VERIFY_BITS(r[6], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[7] = t7;\n    VERIFY_BITS(r[7], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    r[8] = c & M; c >>= 26; c += u8 * R1;\n    VERIFY_BITS(r[8], 26);\n    VERIFY_BITS(c, 39);\n    /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c   += d * R0 + t9;\n    VERIFY_BITS(c, 45);\n    /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4);\n    VERIFY_BITS(r[9], 22);\n    VERIFY_BITS(c, 46);\n    /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    d    = c * (R0 >> 4) + t0;\n    VERIFY_BITS(d, 56);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[0] = d & M; d >>= 26;\n    VERIFY_BITS(r[0], 26);\n    VERIFY_BITS(d, 30);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d   += c * (R1 >> 4) + t1;\n    VERIFY_BITS(d, 53);\n    VERIFY_CHECK(d <= 0x10000003FFFFBFULL);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[1] = d & M; d >>= 26;\n    VERIFY_BITS(r[1], 26);\n    VERIFY_BITS(d, 27);\n    VERIFY_CHECK(d <= 0x4000000ULL);\n    /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d   += t2;\n    VERIFY_BITS(d, 27);\n    /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[2] = d;\n    VERIFY_BITS(r[2], 27);\n    /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n}\n\nSECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) {\n    uint64_t c, d;\n    uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8;\n    uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7;\n    const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL;\n\n    VERIFY_BITS(a[0], 30);\n    VERIFY_BITS(a[1], 30);\n    VERIFY_BITS(a[2], 30);\n    VERIFY_BITS(a[3], 30);\n    VERIFY_BITS(a[4], 30);\n    VERIFY_BITS(a[5], 30);\n    VERIFY_BITS(a[6], 30);\n    VERIFY_BITS(a[7], 30);\n    VERIFY_BITS(a[8], 30);\n    VERIFY_BITS(a[9], 26);\n\n    /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.\n     *  px is a shorthand for sum(a[i]*a[x-i], i=0..x).\n     *  Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].\n     */\n\n    d  = (uint64_t)(a[0]*2) * a[9]\n       + (uint64_t)(a[1]*2) * a[8]\n       + (uint64_t)(a[2]*2) * a[7]\n       + (uint64_t)(a[3]*2) * a[6]\n       + (uint64_t)(a[4]*2) * a[5];\n    /* VERIFY_BITS(d, 64); */\n    /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */\n    t9 = d & M; d >>= 26;\n    VERIFY_BITS(t9, 26);\n    VERIFY_BITS(d, 38);\n    /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */\n\n    c  = (uint64_t)a[0] * a[0];\n    VERIFY_BITS(c, 60);\n    /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */\n    d += (uint64_t)(a[1]*2) * a[9]\n       + (uint64_t)(a[2]*2) * a[8]\n       + (uint64_t)(a[3]*2) * a[7]\n       + (uint64_t)(a[4]*2) * a[6]\n       + (uint64_t)a[5] * a[5];\n    VERIFY_BITS(d, 63);\n    /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    u0 = d & M; d >>= 26; c += u0 * R0;\n    VERIFY_BITS(u0, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 61);\n    /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    t0 = c & M; c >>= 26; c += u0 * R1;\n    VERIFY_BITS(t0, 26);\n    VERIFY_BITS(c, 37);\n    /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[1];\n    VERIFY_BITS(c, 62);\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    d += (uint64_t)(a[2]*2) * a[9]\n       + (uint64_t)(a[3]*2) * a[8]\n       + (uint64_t)(a[4]*2) * a[7]\n       + (uint64_t)(a[5]*2) * a[6];\n    VERIFY_BITS(d, 63);\n    /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    u1 = d & M; d >>= 26; c += u1 * R0;\n    VERIFY_BITS(u1, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 63);\n    /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    t1 = c & M; c >>= 26; c += u1 * R1;\n    VERIFY_BITS(t1, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[2]\n       + (uint64_t)a[1] * a[1];\n    VERIFY_BITS(c, 62);\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    d += (uint64_t)(a[3]*2) * a[9]\n       + (uint64_t)(a[4]*2) * a[8]\n       + (uint64_t)(a[5]*2) * a[7]\n       + (uint64_t)a[6] * a[6];\n    VERIFY_BITS(d, 63);\n    /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    u2 = d & M; d >>= 26; c += u2 * R0;\n    VERIFY_BITS(u2, 26);\n    VERIFY_BITS(d, 37);\n    VERIFY_BITS(c, 63);\n    /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    t2 = c & M; c >>= 26; c += u2 * R1;\n    VERIFY_BITS(t2, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[3]\n       + (uint64_t)(a[1]*2) * a[2];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    d += (uint64_t)(a[4]*2) * a[9]\n       + (uint64_t)(a[5]*2) * a[8]\n       + (uint64_t)(a[6]*2) * a[7];\n    VERIFY_BITS(d, 63);\n    /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    u3 = d & M; d >>= 26; c += u3 * R0;\n    VERIFY_BITS(u3, 26);\n    VERIFY_BITS(d, 37);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    t3 = c & M; c >>= 26; c += u3 * R1;\n    VERIFY_BITS(t3, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[4]\n       + (uint64_t)(a[1]*2) * a[3]\n       + (uint64_t)a[2] * a[2];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    d += (uint64_t)(a[5]*2) * a[9]\n       + (uint64_t)(a[6]*2) * a[8]\n       + (uint64_t)a[7] * a[7];\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    u4 = d & M; d >>= 26; c += u4 * R0;\n    VERIFY_BITS(u4, 26);\n    VERIFY_BITS(d, 36);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    t4 = c & M; c >>= 26; c += u4 * R1;\n    VERIFY_BITS(t4, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[5]\n       + (uint64_t)(a[1]*2) * a[4]\n       + (uint64_t)(a[2]*2) * a[3];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)(a[6]*2) * a[9]\n       + (uint64_t)(a[7]*2) * a[8];\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    u5 = d & M; d >>= 26; c += u5 * R0;\n    VERIFY_BITS(u5, 26);\n    VERIFY_BITS(d, 36);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    t5 = c & M; c >>= 26; c += u5 * R1;\n    VERIFY_BITS(t5, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[6]\n       + (uint64_t)(a[1]*2) * a[5]\n       + (uint64_t)(a[2]*2) * a[4]\n       + (uint64_t)a[3] * a[3];\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)(a[7]*2) * a[9]\n       + (uint64_t)a[8] * a[8];\n    VERIFY_BITS(d, 61);\n    /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    u6 = d & M; d >>= 26; c += u6 * R0;\n    VERIFY_BITS(u6, 26);\n    VERIFY_BITS(d, 35);\n    /* VERIFY_BITS(c, 64); */\n    /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    t6 = c & M; c >>= 26; c += u6 * R1;\n    VERIFY_BITS(t6, 26);\n    VERIFY_BITS(c, 39);\n    /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[7]\n       + (uint64_t)(a[1]*2) * a[6]\n       + (uint64_t)(a[2]*2) * a[5]\n       + (uint64_t)(a[3]*2) * a[4];\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x8000007C00000007ULL);\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)(a[8]*2) * a[9];\n    VERIFY_BITS(d, 58);\n    /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    u7 = d & M; d >>= 26; c += u7 * R0;\n    VERIFY_BITS(u7, 26);\n    VERIFY_BITS(d, 32);\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL);\n    /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    t7 = c & M; c >>= 26; c += u7 * R1;\n    VERIFY_BITS(t7, 26);\n    VERIFY_BITS(c, 38);\n    /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    c += (uint64_t)(a[0]*2) * a[8]\n       + (uint64_t)(a[1]*2) * a[7]\n       + (uint64_t)(a[2]*2) * a[6]\n       + (uint64_t)(a[3]*2) * a[5]\n       + (uint64_t)a[4] * a[4];\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x9000007B80000008ULL);\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint64_t)a[9] * a[9];\n    VERIFY_BITS(d, 57);\n    /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    u8 = d & M; d >>= 26; c += u8 * R0;\n    VERIFY_BITS(u8, 26);\n    VERIFY_BITS(d, 31);\n    /* VERIFY_BITS(c, 64); */\n    VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    r[3] = t3;\n    VERIFY_BITS(r[3], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[4] = t4;\n    VERIFY_BITS(r[4], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[5] = t5;\n    VERIFY_BITS(r[5], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[6] = t6;\n    VERIFY_BITS(r[6], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[7] = t7;\n    VERIFY_BITS(r[7], 26);\n    /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    r[8] = c & M; c >>= 26; c += u8 * R1;\n    VERIFY_BITS(r[8], 26);\n    VERIFY_BITS(c, 39);\n    /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c   += d * R0 + t9;\n    VERIFY_BITS(c, 45);\n    /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4);\n    VERIFY_BITS(r[9], 22);\n    VERIFY_BITS(c, 46);\n    /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    d    = c * (R0 >> 4) + t0;\n    VERIFY_BITS(d, 56);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[0] = d & M; d >>= 26;\n    VERIFY_BITS(r[0], 26);\n    VERIFY_BITS(d, 30);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d   += c * (R1 >> 4) + t1;\n    VERIFY_BITS(d, 53);\n    VERIFY_CHECK(d <= 0x10000003FFFFBFULL);\n    /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[1] = d & M; d >>= 26;\n    VERIFY_BITS(r[1], 26);\n    VERIFY_BITS(d, 27);\n    VERIFY_CHECK(d <= 0x4000000ULL);\n    /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    d   += t2;\n    VERIFY_BITS(d, 27);\n    /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[2] = d;\n    VERIFY_BITS(r[2], 27);\n    /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n}\n#endif\n\nstatic void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= 8);\n    VERIFY_CHECK(b->magnitude <= 8);\n    secp256k1_fe_verify(a);\n    secp256k1_fe_verify(b);\n    VERIFY_CHECK(r != b);\n#endif\n    secp256k1_fe_mul_inner(r->n, a->n, b->n);\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= 8);\n    secp256k1_fe_verify(a);\n#endif\n    secp256k1_fe_sqr_inner(r->n, a->n);\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {\n    uint32_t mask0, mask1;\n    mask0 = flag + ~((uint32_t)0);\n    mask1 = ~mask0;\n    r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);\n    r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);\n    r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);\n    r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);\n    r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);\n    r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1);\n    r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1);\n    r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);\n    r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);\n    r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);\n#ifdef VERIFY\n    if (a->magnitude > r->magnitude) {\n        r->magnitude = a->magnitude;\n    }\n    r->normalized &= a->normalized;\n#endif\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {\n    uint32_t mask0, mask1;\n    mask0 = flag + ~((uint32_t)0);\n    mask1 = ~mask0;\n    r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);\n    r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);\n    r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);\n    r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);\n    r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);\n    r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1);\n    r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1);\n    r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);\n}\n\nstatic void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n#endif\n    r->n[0] = a->n[0] | a->n[1] << 26;\n    r->n[1] = a->n[1] >> 6 | a->n[2] << 20;\n    r->n[2] = a->n[2] >> 12 | a->n[3] << 14;\n    r->n[3] = a->n[3] >> 18 | a->n[4] << 8;\n    r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28;\n    r->n[5] = a->n[6] >> 4 | a->n[7] << 22;\n    r->n[6] = a->n[7] >> 10 | a->n[8] << 16;\n    r->n[7] = a->n[8] >> 16 | a->n[9] << 10;\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {\n    r->n[0] = a->n[0] & 0x3FFFFFFUL;\n    r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);\n    r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);\n    r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL);\n    r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL);\n    r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL;\n    r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL);\n    r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);\n    r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);\n    r->n[9] = a->n[7] >> 10;\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_5x52.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_REPR_\n#define _SECP256K1_FIELD_REPR_\n\n#include <stdint.h>\n\ntypedef struct {\n    /* X = sum(i=0..4, elem[i]*2^52) mod n */\n    uint64_t n[5];\n#ifdef VERIFY\n    int magnitude;\n    int normalized;\n#endif\n} secp256k1_fe;\n\n/* Unpacks a constant into a overlapping multi-limbed FE element. */\n#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \\\n    (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \\\n    ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \\\n    ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \\\n    ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \\\n    ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \\\n}\n\n#ifdef VERIFY\n#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}\n#else\n#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}\n#endif\n\ntypedef struct {\n    uint64_t n[4];\n} secp256k1_fe_storage;\n\n#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \\\n    (d0) | (((uint64_t)(d1)) << 32), \\\n    (d2) | (((uint64_t)(d3)) << 32), \\\n    (d4) | (((uint64_t)(d5)) << 32), \\\n    (d6) | (((uint64_t)(d7)) << 32) \\\n}}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_5x52_asm_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille               *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n/**\n * Changelog:\n * - March 2013, Diederik Huys:    original version\n * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm\n * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly\n */\n\n#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_\n#define _SECP256K1_FIELD_INNER5X52_IMPL_H_\n\n/* It is desirable to be able to build Munt with -fno-omit-frame-pointer (for tools like ASAN) but the code in this file won't compile without frame pointers.\n * So we force frame pointers to be on for this file only.\n */\n#if !defined(__clang__)\n#pragma GCC push_options\n#pragma GCC optimize \"O3,omit-frame-pointer\"\n#endif\n\nSECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {\n/**\n * Registers: rdx:rax = multiplication accumulator\n *            r9:r8   = c\n *            r15:rcx = d\n *            r10-r14 = a0-a4\n *            rbx     = b\n *            rdi     = r\n *            rsi     = a / t?\n */\n  uint64_t tmp1, tmp2, tmp3;\n__asm__ __volatile__(\n    \"movq 0(%%rsi),%%r10\\n\"\n    \"movq 8(%%rsi),%%r11\\n\"\n    \"movq 16(%%rsi),%%r12\\n\"\n    \"movq 24(%%rsi),%%r13\\n\"\n    \"movq 32(%%rsi),%%r14\\n\"\n\n    /* d += a3 * b0 */\n    \"movq 0(%%rbx),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"movq %%rax,%%rcx\\n\"\n    \"movq %%rdx,%%r15\\n\"\n    /* d += a2 * b1 */\n    \"movq 8(%%rbx),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a1 * b2 */\n    \"movq 16(%%rbx),%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d = a0 * b3 */\n    \"movq 24(%%rbx),%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* c = a4 * b4 */\n    \"movq 32(%%rbx),%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"movq %%rax,%%r8\\n\"\n    \"movq %%rdx,%%r9\\n\"\n    /* d += (c & M) * R */\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* c >>= 52 (%%r8 only) */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    /* t3 (tmp1) = d & M */\n    \"movq %%rcx,%%rsi\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rsi\\n\"\n    \"movq %%rsi,%q1\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%r15,%%rcx\\n\"\n    \"xorq %%r15,%%r15\\n\"\n    /* d += a4 * b0 */\n    \"movq 0(%%rbx),%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a3 * b1 */\n    \"movq 8(%%rbx),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a2 * b2 */\n    \"movq 16(%%rbx),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a1 * b3 */\n    \"movq 24(%%rbx),%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a0 * b4 */\n    \"movq 32(%%rbx),%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += c * R */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* t4 = d & M (%%rsi) */\n    \"movq %%rcx,%%rsi\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rsi\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%r15,%%rcx\\n\"\n    \"xorq %%r15,%%r15\\n\"\n    /* tx = t4 >> 48 (tmp3) */\n    \"movq %%rsi,%%rax\\n\"\n    \"shrq $48,%%rax\\n\"\n    \"movq %%rax,%q3\\n\"\n    /* t4 &= (M >> 4) (tmp2) */\n    \"movq $0xffffffffffff,%%rax\\n\"\n    \"andq %%rax,%%rsi\\n\"\n    \"movq %%rsi,%q2\\n\"\n    /* c = a0 * b0 */\n    \"movq 0(%%rbx),%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"movq %%rax,%%r8\\n\"\n    \"movq %%rdx,%%r9\\n\"\n    /* d += a4 * b1 */\n    \"movq 8(%%rbx),%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a3 * b2 */\n    \"movq 16(%%rbx),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a2 * b3 */\n    \"movq 24(%%rbx),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a1 * b4 */\n    \"movq 32(%%rbx),%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* u0 = d & M (%%rsi) */\n    \"movq %%rcx,%%rsi\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rsi\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%r15,%%rcx\\n\"\n    \"xorq %%r15,%%r15\\n\"\n    /* u0 = (u0 << 4) | tx (%%rsi) */\n    \"shlq $4,%%rsi\\n\"\n    \"movq %q3,%%rax\\n\"\n    \"orq %%rax,%%rsi\\n\"\n    /* c += u0 * (R >> 4) */\n    \"movq $0x1000003d1,%%rax\\n\"\n    \"mulq %%rsi\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* r[0] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq %%rax,0(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* c += a1 * b0 */\n    \"movq 0(%%rbx),%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* c += a0 * b1 */\n    \"movq 8(%%rbx),%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d += a4 * b2 */\n    \"movq 16(%%rbx),%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a3 * b3 */\n    \"movq 24(%%rbx),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a2 * b4 */\n    \"movq 32(%%rbx),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* c += (d & M) * R */\n    \"movq %%rcx,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%r15,%%rcx\\n\"\n    \"xorq %%r15,%%r15\\n\"\n    /* r[1] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq %%rax,8(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* c += a2 * b0 */\n    \"movq 0(%%rbx),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* c += a1 * b1 */\n    \"movq 8(%%rbx),%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* c += a0 * b2 (last use of %%r10 = a0) */\n    \"movq 16(%%rbx),%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */\n    \"movq %q2,%%rsi\\n\"\n    \"movq %q1,%%r10\\n\"\n    /* d += a4 * b3 */\n    \"movq 24(%%rbx),%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* d += a3 * b4 */\n    \"movq 32(%%rbx),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rcx\\n\"\n    \"adcq %%rdx,%%r15\\n\"\n    /* c += (d & M) * R */\n    \"movq %%rcx,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d >>= 52 (%%rcx only) */\n    \"shrdq $52,%%r15,%%rcx\\n\"\n    /* r[2] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq %%rax,16(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* c += t3 */\n    \"addq %%r10,%%r8\\n\"\n    /* c += d * R */\n    \"movq %%rcx,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* r[3] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0xfffffffffffff,%%rdx\\n\"\n    \"andq %%rdx,%%rax\\n\"\n    \"movq %%rax,24(%%rdi)\\n\"\n    /* c >>= 52 (%%r8 only) */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    /* c += t4 (%%r8 only) */\n    \"addq %%rsi,%%r8\\n\"\n    /* r[4] = c */\n    \"movq %%r8,32(%%rdi)\\n\"\n: \"+S\"(a), \"=m\"(tmp1), \"=m\"(tmp2), \"=m\"(tmp3)\n: \"b\"(b), \"D\"(r)\n: \"%rax\", \"%rcx\", \"%rdx\", \"%r8\", \"%r9\", \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r14\", \"%r15\", \"cc\", \"memory\"\n);\n}\n\nSECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {\n/**\n * Registers: rdx:rax = multiplication accumulator\n *            r9:r8   = c\n *            rcx:rbx = d\n *            r10-r14 = a0-a4\n *            r15     = M (0xfffffffffffff)\n *            rdi     = r\n *            rsi     = a / t?\n */\n  uint64_t tmp1, tmp2, tmp3;\n__asm__ __volatile__(\n    \"movq 0(%%rsi),%%r10\\n\"\n    \"movq 8(%%rsi),%%r11\\n\"\n    \"movq 16(%%rsi),%%r12\\n\"\n    \"movq 24(%%rsi),%%r13\\n\"\n    \"movq 32(%%rsi),%%r14\\n\"\n    \"movq $0xfffffffffffff,%%r15\\n\"\n\n    /* d = (a0*2) * a3 */\n    \"leaq (%%r10,%%r10,1),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"movq %%rax,%%rbx\\n\"\n    \"movq %%rdx,%%rcx\\n\"\n    /* d += (a1*2) * a2 */\n    \"leaq (%%r11,%%r11,1),%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* c = a4 * a4 */\n    \"movq %%r14,%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"movq %%rax,%%r8\\n\"\n    \"movq %%rdx,%%r9\\n\"\n    /* d += (c & M) * R */\n    \"andq %%r15,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* c >>= 52 (%%r8 only) */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    /* t3 (tmp1) = d & M */\n    \"movq %%rbx,%%rsi\\n\"\n    \"andq %%r15,%%rsi\\n\"\n    \"movq %%rsi,%q1\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%rcx,%%rbx\\n\"\n    \"xorq %%rcx,%%rcx\\n\"\n    /* a4 *= 2 */\n    \"addq %%r14,%%r14\\n\"\n    /* d += a0 * a4 */\n    \"movq %%r10,%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* d+= (a1*2) * a3 */\n    \"leaq (%%r11,%%r11,1),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* d += a2 * a2 */\n    \"movq %%r12,%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* d += c * R */\n    \"movq %%r8,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* t4 = d & M (%%rsi) */\n    \"movq %%rbx,%%rsi\\n\"\n    \"andq %%r15,%%rsi\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%rcx,%%rbx\\n\"\n    \"xorq %%rcx,%%rcx\\n\"\n    /* tx = t4 >> 48 (tmp3) */\n    \"movq %%rsi,%%rax\\n\"\n    \"shrq $48,%%rax\\n\"\n    \"movq %%rax,%q3\\n\"\n    /* t4 &= (M >> 4) (tmp2) */\n    \"movq $0xffffffffffff,%%rax\\n\"\n    \"andq %%rax,%%rsi\\n\"\n    \"movq %%rsi,%q2\\n\"\n    /* c = a0 * a0 */\n    \"movq %%r10,%%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"movq %%rax,%%r8\\n\"\n    \"movq %%rdx,%%r9\\n\"\n    /* d += a1 * a4 */\n    \"movq %%r11,%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* d += (a2*2) * a3 */\n    \"leaq (%%r12,%%r12,1),%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* u0 = d & M (%%rsi) */\n    \"movq %%rbx,%%rsi\\n\"\n    \"andq %%r15,%%rsi\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%rcx,%%rbx\\n\"\n    \"xorq %%rcx,%%rcx\\n\"\n    /* u0 = (u0 << 4) | tx (%%rsi) */\n    \"shlq $4,%%rsi\\n\"\n    \"movq %q3,%%rax\\n\"\n    \"orq %%rax,%%rsi\\n\"\n    /* c += u0 * (R >> 4) */\n    \"movq $0x1000003d1,%%rax\\n\"\n    \"mulq %%rsi\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* r[0] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq %%rax,0(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* a0 *= 2 */\n    \"addq %%r10,%%r10\\n\"\n    /* c += a0 * a1 */\n    \"movq %%r10,%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d += a2 * a4 */\n    \"movq %%r12,%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* d += a3 * a3 */\n    \"movq %%r13,%%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* c += (d & M) * R */\n    \"movq %%rbx,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d >>= 52 */\n    \"shrdq $52,%%rcx,%%rbx\\n\"\n    \"xorq %%rcx,%%rcx\\n\"\n    /* r[1] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq %%rax,8(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* c += a0 * a2 (last use of %%r10) */\n    \"movq %%r10,%%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */\n    \"movq %q2,%%rsi\\n\"\n    \"movq %q1,%%r10\\n\"\n    /* c += a1 * a1 */\n    \"movq %%r11,%%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d += a3 * a4 */\n    \"movq %%r13,%%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax,%%rbx\\n\"\n    \"adcq %%rdx,%%rcx\\n\"\n    /* c += (d & M) * R */\n    \"movq %%rbx,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* d >>= 52 (%%rbx only) */\n    \"shrdq $52,%%rcx,%%rbx\\n\"\n    /* r[2] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq %%rax,16(%%rdi)\\n\"\n    /* c >>= 52 */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    \"xorq %%r9,%%r9\\n\"\n    /* c += t3 */\n    \"addq %%r10,%%r8\\n\"\n    /* c += d * R */\n    \"movq %%rbx,%%rax\\n\"\n    \"movq $0x1000003d10,%%rdx\\n\"\n    \"mulq %%rdx\\n\"\n    \"addq %%rax,%%r8\\n\"\n    \"adcq %%rdx,%%r9\\n\"\n    /* r[3] = c & M */\n    \"movq %%r8,%%rax\\n\"\n    \"andq %%r15,%%rax\\n\"\n    \"movq %%rax,24(%%rdi)\\n\"\n    /* c >>= 52 (%%r8 only) */\n    \"shrdq $52,%%r9,%%r8\\n\"\n    /* c += t4 (%%r8 only) */\n    \"addq %%rsi,%%r8\\n\"\n    /* r[4] = c */\n    \"movq %%r8,32(%%rdi)\\n\"\n: \"+S\"(a), \"=m\"(tmp1), \"=m\"(tmp2), \"=m\"(tmp3)\n: \"D\"(r)\n: \"%rax\", \"%rbx\", \"%rcx\", \"%rdx\", \"%r8\", \"%r9\", \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r14\", \"%r15\", \"cc\", \"memory\"\n);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_5x52_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_REPR_IMPL_H_\n#define _SECP256K1_FIELD_REPR_IMPL_H_\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include \"util.h\"\n#include \"num.h\"\n#include \"field.h\"\n\n#if defined(USE_ASM_X86_64)\n#include \"field_5x52_asm_impl.h\"\n#else\n#include \"field_5x52_int128_impl.h\"\n#endif\n\n/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,\n *  represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,\n *  each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element\n *  is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations\n *  accept any input with magnitude at most M, and have different rules for propagating magnitude to their\n *  output.\n */\n\n#ifdef VERIFY\nstatic void secp256k1_fe_verify(const secp256k1_fe *a) {\n    const uint64_t *d = a->n;\n    int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;\n   /* secp256k1 'p' value defined in \"Standards for Efficient Cryptography\" (SEC2) 2.7.1. */\n    r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);\n    r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);\n    r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);\n    r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m);\n    r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m);\n    r &= (a->magnitude >= 0);\n    r &= (a->magnitude <= 2048);\n    if (a->normalized) {\n        r &= (a->magnitude <= 1);\n        if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {\n            r &= (d[0] < 0xFFFFEFFFFFC2FULL);\n        }\n    }\n    VERIFY_CHECK(r == 1);\n}\n#endif\n\nstatic void secp256k1_fe_normalize(secp256k1_fe *r) {\n    uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];\n\n    /* Reduce t4 at the start so there will be at most a single carry from the first pass */\n    uint64_t m;\n    uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x1000003D1ULL;\n    t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;\n\n    /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t4 >> 49 == 0);\n\n    /* At most a single final reduction is needed; check if the value is >= the field characteristic */\n    x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)\n        & (t0 >= 0xFFFFEFFFFFC2FULL));\n\n    /* Apply the final reduction (for constant-time behaviour, we do it always) */\n    t0 += x * 0x1000003D1ULL;\n    t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;\n\n    /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */\n    VERIFY_CHECK(t4 >> 48 == x);\n\n    /* Mask off the possible multiple of 2^256 from the final reduction */\n    t4 &= 0x0FFFFFFFFFFFFULL;\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_normalize_weak(secp256k1_fe *r) {\n    uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];\n\n    /* Reduce t4 at the start so there will be at most a single carry from the first pass */\n    uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x1000003D1ULL;\n    t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;\n\n    /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t4 >> 49 == 0);\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_normalize_var(secp256k1_fe *r) {\n    uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];\n\n    /* Reduce t4 at the start so there will be at most a single carry from the first pass */\n    uint64_t m;\n    uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x1000003D1ULL;\n    t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;\n\n    /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t4 >> 49 == 0);\n\n    /* At most a single final reduction is needed; check if the value is >= the field characteristic */\n    x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)\n        & (t0 >= 0xFFFFEFFFFFC2FULL));\n\n    if (x) {\n        t0 += 0x1000003D1ULL;\n        t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;\n        t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;\n        t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;\n        t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;\n\n        /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */\n        VERIFY_CHECK(t4 >> 48 == x);\n\n        /* Mask off the possible multiple of 2^256 from the final reduction */\n        t4 &= 0x0FFFFFFFFFFFFULL;\n    }\n\n    r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;\n\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {\n    uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];\n\n    /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */\n    uint64_t z0, z1;\n\n    /* Reduce t4 at the start so there will be at most a single carry from the first pass */\n    uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x1000003D1ULL;\n    t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0  = t0; z1  = t0 ^ 0x1000003D0ULL;\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;\n                                                z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;\n\n    /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t4 >> 49 == 0);\n\n    return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);\n}\n\nstatic int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {\n    uint64_t t0, t1, t2, t3, t4;\n    uint64_t z0, z1;\n    uint64_t x;\n\n    t0 = r->n[0];\n    t4 = r->n[4];\n\n    /* Reduce t4 at the start so there will be at most a single carry from the first pass */\n    x = t4 >> 48;\n\n    /* The first pass ensures the magnitude is 1, ... */\n    t0 += x * 0x1000003D1ULL;\n\n    /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */\n    z0 = t0 & 0xFFFFFFFFFFFFFULL;\n    z1 = z0 ^ 0x1000003D0ULL;\n\n    /* Fast return path should catch the majority of cases */\n    if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) {\n        return 0;\n    }\n\n    t1 = r->n[1];\n    t2 = r->n[2];\n    t3 = r->n[3];\n\n    t4 &= 0x0FFFFFFFFFFFFULL;\n\n    t1 += (t0 >> 52);\n    t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;\n    t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;\n    t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;\n                                                z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;\n\n    /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */\n    VERIFY_CHECK(t4 >> 49 == 0);\n\n    return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);\n}\n\nSECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {\n    r->n[0] = a;\n    r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {\n    const uint64_t *t = a->n;\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;\n}\n\nSECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    return a->n[0] & 1;\n}\n\nSECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {\n    int i;\n#ifdef VERIFY\n    a->magnitude = 0;\n    a->normalized = 1;\n#endif\n    for (i=0; i<5; i++) {\n        a->n[i] = 0;\n    }\n}\n\nstatic int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {\n    int i;\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    VERIFY_CHECK(b->normalized);\n    secp256k1_fe_verify(a);\n    secp256k1_fe_verify(b);\n#endif\n    for (i = 4; i >= 0; i--) {\n        if (a->n[i] > b->n[i]) {\n            return 1;\n        }\n        if (a->n[i] < b->n[i]) {\n            return -1;\n        }\n    }\n    return 0;\n}\n\nstatic int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {\n    r->n[0] = (uint64_t)a[31]\n            | ((uint64_t)a[30] << 8)\n            | ((uint64_t)a[29] << 16)\n            | ((uint64_t)a[28] << 24)\n            | ((uint64_t)a[27] << 32)\n            | ((uint64_t)a[26] << 40)\n            | ((uint64_t)(a[25] & 0xF)  << 48);\n    r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)\n            | ((uint64_t)a[24] << 4)\n            | ((uint64_t)a[23] << 12)\n            | ((uint64_t)a[22] << 20)\n            | ((uint64_t)a[21] << 28)\n            | ((uint64_t)a[20] << 36)\n            | ((uint64_t)a[19] << 44);\n    r->n[2] = (uint64_t)a[18]\n            | ((uint64_t)a[17] << 8)\n            | ((uint64_t)a[16] << 16)\n            | ((uint64_t)a[15] << 24)\n            | ((uint64_t)a[14] << 32)\n            | ((uint64_t)a[13] << 40)\n            | ((uint64_t)(a[12] & 0xF) << 48);\n    r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)\n            | ((uint64_t)a[11] << 4)\n            | ((uint64_t)a[10] << 12)\n            | ((uint64_t)a[9]  << 20)\n            | ((uint64_t)a[8]  << 28)\n            | ((uint64_t)a[7]  << 36)\n            | ((uint64_t)a[6]  << 44);\n    r->n[4] = (uint64_t)a[5]\n            | ((uint64_t)a[4] << 8)\n            | ((uint64_t)a[3] << 16)\n            | ((uint64_t)a[2] << 24)\n            | ((uint64_t)a[1] << 32)\n            | ((uint64_t)a[0] << 40);\n    if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {\n        return 0;\n    }\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n    secp256k1_fe_verify(r);\n#endif\n    return 1;\n}\n\n/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */\nstatic void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n    secp256k1_fe_verify(a);\n#endif\n    r[0] = (a->n[4] >> 40) & 0xFF;\n    r[1] = (a->n[4] >> 32) & 0xFF;\n    r[2] = (a->n[4] >> 24) & 0xFF;\n    r[3] = (a->n[4] >> 16) & 0xFF;\n    r[4] = (a->n[4] >> 8) & 0xFF;\n    r[5] = a->n[4] & 0xFF;\n    r[6] = (a->n[3] >> 44) & 0xFF;\n    r[7] = (a->n[3] >> 36) & 0xFF;\n    r[8] = (a->n[3] >> 28) & 0xFF;\n    r[9] = (a->n[3] >> 20) & 0xFF;\n    r[10] = (a->n[3] >> 12) & 0xFF;\n    r[11] = (a->n[3] >> 4) & 0xFF;\n    r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);\n    r[13] = (a->n[2] >> 40) & 0xFF;\n    r[14] = (a->n[2] >> 32) & 0xFF;\n    r[15] = (a->n[2] >> 24) & 0xFF;\n    r[16] = (a->n[2] >> 16) & 0xFF;\n    r[17] = (a->n[2] >> 8) & 0xFF;\n    r[18] = a->n[2] & 0xFF;\n    r[19] = (a->n[1] >> 44) & 0xFF;\n    r[20] = (a->n[1] >> 36) & 0xFF;\n    r[21] = (a->n[1] >> 28) & 0xFF;\n    r[22] = (a->n[1] >> 20) & 0xFF;\n    r[23] = (a->n[1] >> 12) & 0xFF;\n    r[24] = (a->n[1] >> 4) & 0xFF;\n    r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);\n    r[26] = (a->n[0] >> 40) & 0xFF;\n    r[27] = (a->n[0] >> 32) & 0xFF;\n    r[28] = (a->n[0] >> 24) & 0xFF;\n    r[29] = (a->n[0] >> 16) & 0xFF;\n    r[30] = (a->n[0] >> 8) & 0xFF;\n    r[31] = a->n[0] & 0xFF;\n}\n\nSECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= m);\n    secp256k1_fe_verify(a);\n#endif\n    r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];\n    r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];\n    r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];\n    r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];\n    r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];\n#ifdef VERIFY\n    r->magnitude = m + 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {\n    r->n[0] *= a;\n    r->n[1] *= a;\n    r->n[2] *= a;\n    r->n[3] *= a;\n    r->n[4] *= a;\n#ifdef VERIFY\n    r->magnitude *= a;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nSECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    secp256k1_fe_verify(a);\n#endif\n    r->n[0] += a->n[0];\n    r->n[1] += a->n[1];\n    r->n[2] += a->n[2];\n    r->n[3] += a->n[3];\n    r->n[4] += a->n[4];\n#ifdef VERIFY\n    r->magnitude += a->magnitude;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= 8);\n    VERIFY_CHECK(b->magnitude <= 8);\n    secp256k1_fe_verify(a);\n    secp256k1_fe_verify(b);\n    VERIFY_CHECK(r != b);\n#endif\n    secp256k1_fe_mul_inner(r->n, a->n, b->n);\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->magnitude <= 8);\n    secp256k1_fe_verify(a);\n#endif\n    secp256k1_fe_sqr_inner(r->n, a->n);\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 0;\n    secp256k1_fe_verify(r);\n#endif\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {\n    uint64_t mask0, mask1;\n    mask0 = flag + ~((uint64_t)0);\n    mask1 = ~mask0;\n    r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);\n    r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);\n    r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);\n    r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);\n    r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);\n#ifdef VERIFY\n    if (a->magnitude > r->magnitude) {\n        r->magnitude = a->magnitude;\n    }\n    r->normalized &= a->normalized;\n#endif\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {\n    uint64_t mask0, mask1;\n    mask0 = flag + ~((uint64_t)0);\n    mask1 = ~mask0;\n    r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);\n    r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);\n    r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);\n    r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);\n}\n\nstatic void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {\n#ifdef VERIFY\n    VERIFY_CHECK(a->normalized);\n#endif\n    r->n[0] = a->n[0] | a->n[1] << 52;\n    r->n[1] = a->n[1] >> 12 | a->n[2] << 40;\n    r->n[2] = a->n[2] >> 24 | a->n[3] << 28;\n    r->n[3] = a->n[3] >> 36 | a->n[4] << 16;\n}\n\nstatic SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {\n    r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;\n    r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);\n    r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);\n    r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);\n    r->n[4] = a->n[3] >> 16;\n#ifdef VERIFY\n    r->magnitude = 1;\n    r->normalized = 1;\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_5x52_int128_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_\n#define _SECP256K1_FIELD_INNER5X52_IMPL_H_\n\n#include <stdint.h>\n\n#ifdef VERIFY\n#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)\n#else\n#define VERIFY_BITS(x, n) do { } while(0)\n#endif\n\nSECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {\n    uint128_t c, d;\n    uint64_t t3, t4, tx, u0;\n    uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];\n    const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;\n\n    VERIFY_BITS(a[0], 56);\n    VERIFY_BITS(a[1], 56);\n    VERIFY_BITS(a[2], 56);\n    VERIFY_BITS(a[3], 56);\n    VERIFY_BITS(a[4], 52);\n    VERIFY_BITS(b[0], 56);\n    VERIFY_BITS(b[1], 56);\n    VERIFY_BITS(b[2], 56);\n    VERIFY_BITS(b[3], 56);\n    VERIFY_BITS(b[4], 52);\n    VERIFY_CHECK(r != b);\n\n    /*  [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.\n     *  px is a shorthand for sum(a[i]*b[x-i], i=0..x).\n     *  Note that [x 0 0 0 0 0] = [x*R].\n     */\n\n    d  = (uint128_t)a0 * b[3]\n       + (uint128_t)a1 * b[2]\n       + (uint128_t)a2 * b[1]\n       + (uint128_t)a3 * b[0];\n    VERIFY_BITS(d, 114);\n    /* [d 0 0 0] = [p3 0 0 0] */\n    c  = (uint128_t)a4 * b[4];\n    VERIFY_BITS(c, 112);\n    /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n    d += (c & M) * R; c >>= 52;\n    VERIFY_BITS(d, 115);\n    VERIFY_BITS(c, 60);\n    /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n    t3 = d & M; d >>= 52;\n    VERIFY_BITS(t3, 52);\n    VERIFY_BITS(d, 63);\n    /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n\n    d += (uint128_t)a0 * b[4]\n       + (uint128_t)a1 * b[3]\n       + (uint128_t)a2 * b[2]\n       + (uint128_t)a3 * b[1]\n       + (uint128_t)a4 * b[0];\n    VERIFY_BITS(d, 115);\n    /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    d += c * R;\n    VERIFY_BITS(d, 116);\n    /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    t4 = d & M; d >>= 52;\n    VERIFY_BITS(t4, 52);\n    VERIFY_BITS(d, 64);\n    /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    tx = (t4 >> 48); t4 &= (M >> 4);\n    VERIFY_BITS(tx, 4);\n    VERIFY_BITS(t4, 48);\n    /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n\n    c  = (uint128_t)a0 * b[0];\n    VERIFY_BITS(c, 112);\n    /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */\n    d += (uint128_t)a1 * b[4]\n       + (uint128_t)a2 * b[3]\n       + (uint128_t)a3 * b[2]\n       + (uint128_t)a4 * b[1];\n    VERIFY_BITS(d, 115);\n    /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    u0 = d & M; d >>= 52;\n    VERIFY_BITS(u0, 52);\n    VERIFY_BITS(d, 63);\n    /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    u0 = (u0 << 4) | tx;\n    VERIFY_BITS(u0, 56);\n    /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    c += (uint128_t)u0 * (R >> 4);\n    VERIFY_BITS(c, 115);\n    /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    r[0] = c & M; c >>= 52;\n    VERIFY_BITS(r[0], 52);\n    VERIFY_BITS(c, 61);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */\n\n    c += (uint128_t)a0 * b[1]\n       + (uint128_t)a1 * b[0];\n    VERIFY_BITS(c, 114);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */\n    d += (uint128_t)a2 * b[4]\n       + (uint128_t)a3 * b[3]\n       + (uint128_t)a4 * b[2];\n    VERIFY_BITS(d, 114);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n    c += (d & M) * R; d >>= 52;\n    VERIFY_BITS(c, 115);\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n    r[1] = c & M; c >>= 52;\n    VERIFY_BITS(r[1], 52);\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n\n    c += (uint128_t)a0 * b[2]\n       + (uint128_t)a1 * b[1]\n       + (uint128_t)a2 * b[0];\n    VERIFY_BITS(c, 114);\n    /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint128_t)a3 * b[4]\n       + (uint128_t)a4 * b[3];\n    VERIFY_BITS(d, 114);\n    /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c += (d & M) * R; d >>= 52;\n    VERIFY_BITS(c, 115);\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[2] = c & M; c >>= 52;\n    VERIFY_BITS(r[2], 52);\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c   += d * R + t3;\n    VERIFY_BITS(c, 100);\n    /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[3] = c & M; c >>= 52;\n    VERIFY_BITS(r[3], 52);\n    VERIFY_BITS(c, 48);\n    /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c   += t4;\n    VERIFY_BITS(c, 49);\n    /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[4] = c;\n    VERIFY_BITS(r[4], 49);\n    /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n}\n\nSECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {\n    uint128_t c, d;\n    uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];\n    int64_t t3, t4, tx, u0;\n    const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;\n\n    VERIFY_BITS(a[0], 56);\n    VERIFY_BITS(a[1], 56);\n    VERIFY_BITS(a[2], 56);\n    VERIFY_BITS(a[3], 56);\n    VERIFY_BITS(a[4], 52);\n\n    /**  [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.\n     *  px is a shorthand for sum(a[i]*a[x-i], i=0..x).\n     *  Note that [x 0 0 0 0 0] = [x*R].\n     */\n\n    d  = (uint128_t)(a0*2) * a3\n       + (uint128_t)(a1*2) * a2;\n    VERIFY_BITS(d, 114);\n    /* [d 0 0 0] = [p3 0 0 0] */\n    c  = (uint128_t)a4 * a4;\n    VERIFY_BITS(c, 112);\n    /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n    d += (c & M) * R; c >>= 52;\n    VERIFY_BITS(d, 115);\n    VERIFY_BITS(c, 60);\n    /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n    t3 = d & M; d >>= 52;\n    VERIFY_BITS(t3, 52);\n    VERIFY_BITS(d, 63);\n    /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */\n\n    a4 *= 2;\n    d += (uint128_t)a0 * a4\n       + (uint128_t)(a1*2) * a3\n       + (uint128_t)a2 * a2;\n    VERIFY_BITS(d, 115);\n    /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    d += c * R;\n    VERIFY_BITS(d, 116);\n    /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    t4 = d & M; d >>= 52;\n    VERIFY_BITS(t4, 52);\n    VERIFY_BITS(d, 64);\n    /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n    tx = (t4 >> 48); t4 &= (M >> 4);\n    VERIFY_BITS(tx, 4);\n    VERIFY_BITS(t4, 48);\n    /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */\n\n    c  = (uint128_t)a0 * a0;\n    VERIFY_BITS(c, 112);\n    /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */\n    d += (uint128_t)a1 * a4\n       + (uint128_t)(a2*2) * a3;\n    VERIFY_BITS(d, 114);\n    /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    u0 = d & M; d >>= 52;\n    VERIFY_BITS(u0, 52);\n    VERIFY_BITS(d, 62);\n    /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    u0 = (u0 << 4) | tx;\n    VERIFY_BITS(u0, 56);\n    /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    c += (uint128_t)u0 * (R >> 4);\n    VERIFY_BITS(c, 113);\n    /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */\n    r[0] = c & M; c >>= 52;\n    VERIFY_BITS(r[0], 52);\n    VERIFY_BITS(c, 61);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */\n\n    a0 *= 2;\n    c += (uint128_t)a0 * a1;\n    VERIFY_BITS(c, 114);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */\n    d += (uint128_t)a2 * a4\n       + (uint128_t)a3 * a3;\n    VERIFY_BITS(d, 114);\n    /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n    c += (d & M) * R; d >>= 52;\n    VERIFY_BITS(c, 115);\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n    r[1] = c & M; c >>= 52;\n    VERIFY_BITS(r[1], 52);\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */\n\n    c += (uint128_t)a0 * a2\n       + (uint128_t)a1 * a1;\n    VERIFY_BITS(c, 114);\n    /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */\n    d += (uint128_t)a3 * a4;\n    VERIFY_BITS(d, 114);\n    /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c += (d & M) * R; d >>= 52;\n    VERIFY_BITS(c, 115);\n    VERIFY_BITS(d, 62);\n    /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[2] = c & M; c >>= 52;\n    VERIFY_BITS(r[2], 52);\n    VERIFY_BITS(c, 63);\n    /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n\n    c   += d * R + t3;\n    VERIFY_BITS(c, 100);\n    /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[3] = c & M; c >>= 52;\n    VERIFY_BITS(r[3], 52);\n    VERIFY_BITS(c, 48);\n    /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    c   += t4;\n    VERIFY_BITS(c, 49);\n    /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n    r[4] = c;\n    VERIFY_BITS(r[4], 49);\n    /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/field_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_FIELD_IMPL_H_\n#define _SECP256K1_FIELD_IMPL_H_\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include \"util.h\"\n\n#if defined(USE_FIELD_10X26)\n#include \"field_10x26_impl.h\"\n#elif defined(USE_FIELD_5X52)\n#include \"field_5x52_impl.h\"\n#else\n#error \"Please select field implementation\"\n#endif\n\nSECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {\n    secp256k1_fe na;\n    secp256k1_fe_negate(&na, a, 1);\n    secp256k1_fe_add(&na, b);\n    return secp256k1_fe_normalizes_to_zero(&na);\n}\n\nSECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {\n    secp256k1_fe na;\n    secp256k1_fe_negate(&na, a, 1);\n    secp256k1_fe_add(&na, b);\n    return secp256k1_fe_normalizes_to_zero_var(&na);\n}\n\nstatic int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {\n    /** Given that p is congruent to 3 mod 4, we can compute the square root of\n     *  a mod p as the (p+1)/4'th power of a.\n     *\n     *  As (p+1)/4 is an even number, it will have the same result for a and for\n     *  (-a). Only one of these two numbers actually has a square root however,\n     *  so we test at the end by squaring and comparing to the input.\n     *  Also because (p+1)/4 is an even number, the computed square root is\n     *  itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).\n     */\n    secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;\n    int j;\n\n    /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in\n     *  { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:\n     *  1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]\n     */\n\n    secp256k1_fe_sqr(&x2, a);\n    secp256k1_fe_mul(&x2, &x2, a);\n\n    secp256k1_fe_sqr(&x3, &x2);\n    secp256k1_fe_mul(&x3, &x3, a);\n\n    x6 = x3;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x6, &x6);\n    }\n    secp256k1_fe_mul(&x6, &x6, &x3);\n\n    x9 = x6;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x9, &x9);\n    }\n    secp256k1_fe_mul(&x9, &x9, &x3);\n\n    x11 = x9;\n    for (j=0; j<2; j++) {\n        secp256k1_fe_sqr(&x11, &x11);\n    }\n    secp256k1_fe_mul(&x11, &x11, &x2);\n\n    x22 = x11;\n    for (j=0; j<11; j++) {\n        secp256k1_fe_sqr(&x22, &x22);\n    }\n    secp256k1_fe_mul(&x22, &x22, &x11);\n\n    x44 = x22;\n    for (j=0; j<22; j++) {\n        secp256k1_fe_sqr(&x44, &x44);\n    }\n    secp256k1_fe_mul(&x44, &x44, &x22);\n\n    x88 = x44;\n    for (j=0; j<44; j++) {\n        secp256k1_fe_sqr(&x88, &x88);\n    }\n    secp256k1_fe_mul(&x88, &x88, &x44);\n\n    x176 = x88;\n    for (j=0; j<88; j++) {\n        secp256k1_fe_sqr(&x176, &x176);\n    }\n    secp256k1_fe_mul(&x176, &x176, &x88);\n\n    x220 = x176;\n    for (j=0; j<44; j++) {\n        secp256k1_fe_sqr(&x220, &x220);\n    }\n    secp256k1_fe_mul(&x220, &x220, &x44);\n\n    x223 = x220;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x223, &x223);\n    }\n    secp256k1_fe_mul(&x223, &x223, &x3);\n\n    /* The final result is then assembled using a sliding window over the blocks. */\n\n    t1 = x223;\n    for (j=0; j<23; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(&t1, &t1, &x22);\n    for (j=0; j<6; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(&t1, &t1, &x2);\n    secp256k1_fe_sqr(&t1, &t1);\n    secp256k1_fe_sqr(r, &t1);\n\n    /* Check that a square root was actually calculated */\n\n    secp256k1_fe_sqr(&t1, r);\n    return secp256k1_fe_equal(&t1, a);\n}\n\nstatic void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {\n    secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;\n    int j;\n\n    /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in\n     *  { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:\n     *  [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]\n     */\n\n    secp256k1_fe_sqr(&x2, a);\n    secp256k1_fe_mul(&x2, &x2, a);\n\n    secp256k1_fe_sqr(&x3, &x2);\n    secp256k1_fe_mul(&x3, &x3, a);\n\n    x6 = x3;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x6, &x6);\n    }\n    secp256k1_fe_mul(&x6, &x6, &x3);\n\n    x9 = x6;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x9, &x9);\n    }\n    secp256k1_fe_mul(&x9, &x9, &x3);\n\n    x11 = x9;\n    for (j=0; j<2; j++) {\n        secp256k1_fe_sqr(&x11, &x11);\n    }\n    secp256k1_fe_mul(&x11, &x11, &x2);\n\n    x22 = x11;\n    for (j=0; j<11; j++) {\n        secp256k1_fe_sqr(&x22, &x22);\n    }\n    secp256k1_fe_mul(&x22, &x22, &x11);\n\n    x44 = x22;\n    for (j=0; j<22; j++) {\n        secp256k1_fe_sqr(&x44, &x44);\n    }\n    secp256k1_fe_mul(&x44, &x44, &x22);\n\n    x88 = x44;\n    for (j=0; j<44; j++) {\n        secp256k1_fe_sqr(&x88, &x88);\n    }\n    secp256k1_fe_mul(&x88, &x88, &x44);\n\n    x176 = x88;\n    for (j=0; j<88; j++) {\n        secp256k1_fe_sqr(&x176, &x176);\n    }\n    secp256k1_fe_mul(&x176, &x176, &x88);\n\n    x220 = x176;\n    for (j=0; j<44; j++) {\n        secp256k1_fe_sqr(&x220, &x220);\n    }\n    secp256k1_fe_mul(&x220, &x220, &x44);\n\n    x223 = x220;\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&x223, &x223);\n    }\n    secp256k1_fe_mul(&x223, &x223, &x3);\n\n    /* The final result is then assembled using a sliding window over the blocks. */\n\n    t1 = x223;\n    for (j=0; j<23; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(&t1, &t1, &x22);\n    for (j=0; j<5; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(&t1, &t1, a);\n    for (j=0; j<3; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(&t1, &t1, &x2);\n    for (j=0; j<2; j++) {\n        secp256k1_fe_sqr(&t1, &t1);\n    }\n    secp256k1_fe_mul(r, a, &t1);\n}\n\nstatic void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {\n#if defined(USE_FIELD_INV_BUILTIN)\n    secp256k1_fe_inv(r, a);\n#elif defined(USE_FIELD_INV_NUM)\n    secp256k1_num n, m;\n    static const secp256k1_fe negone = SECP256K1_FE_CONST(\n        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,\n        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL\n    );\n    /* secp256k1 field prime, value p defined in \"Standards for Efficient Cryptography\" (SEC2) 2.7.1. */\n    static const unsigned char prime[32] = {\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F\n    };\n    unsigned char b[32];\n    int res;\n    secp256k1_fe c = *a;\n    secp256k1_fe_normalize_var(&c);\n    secp256k1_fe_get_b32(b, &c);\n    secp256k1_num_set_bin(&n, b, 32);\n    secp256k1_num_set_bin(&m, prime, 32);\n    secp256k1_num_mod_inverse(&n, &n, &m);\n    secp256k1_num_get_bin(b, 32, &n);\n    res = secp256k1_fe_set_b32(r, b);\n    (void)res;\n    VERIFY_CHECK(res);\n    /* Verify the result is the (unique) valid inverse using non-GMP code. */\n    secp256k1_fe_mul(&c, &c, r);\n    secp256k1_fe_add(&c, &negone);\n    CHECK(secp256k1_fe_normalizes_to_zero_var(&c));\n#else\n#error \"Please select field inverse implementation\"\n#endif\n}\n\nstatic void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) {\n    secp256k1_fe u;\n    size_t i;\n    if (len < 1) {\n        return;\n    }\n\n    VERIFY_CHECK((r + len <= a) || (a + len <= r));\n\n    r[0] = a[0];\n\n    i = 0;\n    while (++i < len) {\n        secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]);\n    }\n\n    secp256k1_fe_inv_var(&u, &r[--i]);\n\n    while (i > 0) {\n        size_t j = i--;\n        secp256k1_fe_mul(&r[j], &r[i], &u);\n        secp256k1_fe_mul(&u, &u, &a[j]);\n    }\n\n    r[0] = u;\n}\n\nstatic int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {\n#ifndef USE_NUM_NONE\n    unsigned char b[32];\n    secp256k1_num n;\n    secp256k1_num m;\n    /* secp256k1 field prime, value p defined in \"Standards for Efficient Cryptography\" (SEC2) 2.7.1. */\n    static const unsigned char prime[32] = {\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F\n    };\n\n    secp256k1_fe c = *a;\n    secp256k1_fe_normalize_var(&c);\n    secp256k1_fe_get_b32(b, &c);\n    secp256k1_num_set_bin(&n, b, 32);\n    secp256k1_num_set_bin(&m, prime, 32);\n    return secp256k1_num_jacobi(&n, &m) >= 0;\n#else\n    secp256k1_fe r;\n    return secp256k1_fe_sqrt(&r, a);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/gen_context.c",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields           *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#define USE_BASIC_CONFIG 1\n\n#include \"basic-config.h\"\n#include \"include/secp256k1.h\"\n#include \"field_impl.h\"\n#include \"scalar_impl.h\"\n#include \"group_impl.h\"\n#include \"ecmult_gen_impl.h\"\n\nstatic void default_error_callback_fn(const char* str, void* data) {\n    (void)data;\n    fprintf(stderr, \"[libsecp256k1] internal consistency check failed: %s\\n\", str);\n    abort();\n}\n\nstatic const secp256k1_callback default_error_callback = {\n    default_error_callback_fn,\n    NULL\n};\n\nint main(int argc, char **argv) {\n    secp256k1_ecmult_gen_context ctx;\n    int inner;\n    int outer;\n    FILE* fp;\n\n    (void)argc;\n    (void)argv;\n\n    fp = fopen(\"src/ecmult_static_context.h\",\"w\");\n    if (fp == NULL) {\n        fprintf(stderr, \"Could not open src/ecmult_static_context.h for writing!\\n\");\n        return -1;\n    }\n\n    fprintf(fp, \"#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\\n\");\n    fprintf(fp, \"#define _SECP256K1_ECMULT_STATIC_CONTEXT_\\n\");\n    fprintf(fp, \"#include \\\"group.h\\\"\\n\");\n    fprintf(fp, \"#define SC SECP256K1_GE_STORAGE_CONST\\n\");\n    fprintf(fp, \"static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\\n\");\n\n    secp256k1_ecmult_gen_context_init(&ctx);\n    secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);\n    for(outer = 0; outer != 64; outer++) {\n        fprintf(fp,\"{\\n\");\n        for(inner = 0; inner != 16; inner++) {\n            fprintf(fp,\"    SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)\", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner]));\n            if (inner != 15) {\n                fprintf(fp,\",\\n\");\n            } else {\n                fprintf(fp,\"\\n\");\n            }\n        }\n        if (outer != 63) {\n            fprintf(fp,\"},\\n\");\n        } else {\n            fprintf(fp,\"}\\n\");\n        }\n    }\n    fprintf(fp,\"};\\n\");\n    secp256k1_ecmult_gen_context_clear(&ctx);\n\n    fprintf(fp, \"#undef SC\\n\");\n    fprintf(fp, \"#endif\\n\");\n    fclose(fp);\n\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/group.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_GROUP_\n#define _SECP256K1_GROUP_\n\n#include \"num.h\"\n#include \"field.h\"\n\n/** A group element of the secp256k1 curve, in affine coordinates. */\ntypedef struct {\n    secp256k1_fe x;\n    secp256k1_fe y;\n    int infinity; /* whether this represents the point at infinity */\n} secp256k1_ge;\n\n#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}\n#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}\n\n/** A group element of the secp256k1 curve, in jacobian coordinates. */\ntypedef struct {\n    secp256k1_fe x; /* actual X: x/z^2 */\n    secp256k1_fe y; /* actual Y: y/z^3 */\n    secp256k1_fe z;\n    int infinity; /* whether this represents the point at infinity */\n} secp256k1_gej;\n\n#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0}\n#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}\n\ntypedef struct {\n    secp256k1_fe_storage x;\n    secp256k1_fe_storage y;\n} secp256k1_ge_storage;\n\n#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))}\n\n#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y)\n\n/** Set a group element equal to the point with given X and Y coordinates */\nstatic void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);\n\n/** Set a group element (affine) equal to the point with the given X coordinate\n *  and a Y coordinate that is a quadratic residue modulo p. The return value\n *  is true iff a coordinate with the given X coordinate exists.\n */\nstatic int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);\n\n/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness\n *  for Y. Return value indicates whether the result is valid. */\nstatic int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);\n\n/** Check whether a group element is the point at infinity. */\nstatic int secp256k1_ge_is_infinity(const secp256k1_ge *a);\n\n/** Check whether a group element is valid (i.e., on the curve). */\nstatic int secp256k1_ge_is_valid_var(const secp256k1_ge *a);\n\nstatic void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);\n\n/** Set a group element equal to another which is given in jacobian coordinates */\nstatic void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);\n\n/** Set a batch of group elements equal to the inputs given in jacobian coordinates */\nstatic void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);\n\n/** Set a batch of group elements equal to the inputs given in jacobian\n *  coordinates (with known z-ratios). zr must contain the known z-ratios such\n *  that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */\nstatic void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);\n\n/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to\n *  the same global z \"denominator\". zr must contain the known z-ratios such\n *  that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y\n *  coordinates of the result are stored in r, the common z coordinate is\n *  stored in globalz. */\nstatic void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);\n\n/** Set a group element (jacobian) equal to the point at infinity. */\nstatic void secp256k1_gej_set_infinity(secp256k1_gej *r);\n\n/** Set a group element (jacobian) equal to another which is given in affine coordinates. */\nstatic void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);\n\n/** Compare the X coordinate of a group element (jacobian). */\nstatic int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);\n\n/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */\nstatic void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);\n\n/** Check whether a group element is the point at infinity. */\nstatic int secp256k1_gej_is_infinity(const secp256k1_gej *a);\n\n/** Check whether a group element's y coordinate is a quadratic residue. */\nstatic int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);\n\n/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).\n * a may not be zero. Constant time. */\nstatic void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);\n\n/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */\nstatic void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);\n\n/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */\nstatic void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);\n\n/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */\nstatic void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b);\n\n/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient\n    than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time\n    guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */\nstatic void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);\n\n/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */\nstatic void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);\n\n#ifdef USE_ENDOMORPHISM\n/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */\nstatic void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);\n#endif\n\n/** Clear a secp256k1_gej to prevent leaking sensitive information. */\nstatic void secp256k1_gej_clear(secp256k1_gej *r);\n\n/** Clear a secp256k1_ge to prevent leaking sensitive information. */\nstatic void secp256k1_ge_clear(secp256k1_ge *r);\n\n/** Convert a group element to the storage type. */\nstatic void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a);\n\n/** Convert a group element back from the storage type. */\nstatic void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);\n\n/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */\nstatic void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);\n\n/** Rescale a jacobian point by b which must be non-zero. Constant-time. */\nstatic void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/group_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_GROUP_IMPL_H_\n#define _SECP256K1_GROUP_IMPL_H_\n\n#include \"num.h\"\n#include \"field.h\"\n#include \"group.h\"\n\n/* These points can be generated in sage as follows:\n *\n * 0. Setup a worksheet with the following parameters.\n *   b = 4  # whatever CURVE_B will be set to\n *   F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)\n *   C = EllipticCurve ([F (0), F (b)])\n *\n * 1. Determine all the small orders available to you. (If there are\n *    no satisfactory ones, go back and change b.)\n *   print C.order().factor(limit=1000)\n *\n * 2. Choose an order as one of the prime factors listed in the above step.\n *    (You can also multiply some to get a composite order, though the\n *    tests will crash trying to invert scalars during signing.) We take a\n *    random point and scale it to drop its order to the desired value.\n *    There is some probability this won't work; just try again.\n *   order = 199\n *   P = C.random_point()\n *   P = (int(P.order()) / int(order)) * P\n *   assert(P.order() == order)\n *\n * 3. Print the values. You'll need to use a vim macro or something to\n *    split the hex output into 4-byte chunks.\n *   print \"%x %x\" % P.xy()\n */\n#if defined(EXHAUSTIVE_TEST_ORDER)\n#  if EXHAUSTIVE_TEST_ORDER == 199\nconst secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(\n    0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,\n    0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,\n    0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,\n    0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED\n);\n\nconst int CURVE_B = 4;\n#  elif EXHAUSTIVE_TEST_ORDER == 13\nconst secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(\n    0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,\n    0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,\n    0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,\n    0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac\n);\nconst int CURVE_B = 2;\n#  else\n#    error No known generator for the specified exhaustive test group order.\n#  endif\n#else\n/** Generator for secp256k1, value 'g' defined in\n *  \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.\n */\nstatic const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(\n    0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\n    0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\n    0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\n    0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\n);\n\nconst int CURVE_B = 7;\n#endif\n\nstatic void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {\n    secp256k1_fe zi2;\n    secp256k1_fe zi3;\n    secp256k1_fe_sqr(&zi2, zi);\n    secp256k1_fe_mul(&zi3, &zi2, zi);\n    secp256k1_fe_mul(&r->x, &a->x, &zi2);\n    secp256k1_fe_mul(&r->y, &a->y, &zi3);\n    r->infinity = a->infinity;\n}\n\nstatic void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {\n    r->infinity = 0;\n    r->x = *x;\n    r->y = *y;\n}\n\nstatic int secp256k1_ge_is_infinity(const secp256k1_ge *a) {\n    return a->infinity;\n}\n\nstatic void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {\n    *r = *a;\n    secp256k1_fe_normalize_weak(&r->y);\n    secp256k1_fe_negate(&r->y, &r->y, 1);\n}\n\nstatic void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {\n    secp256k1_fe z2, z3;\n    r->infinity = a->infinity;\n    secp256k1_fe_inv(&a->z, &a->z);\n    secp256k1_fe_sqr(&z2, &a->z);\n    secp256k1_fe_mul(&z3, &a->z, &z2);\n    secp256k1_fe_mul(&a->x, &a->x, &z2);\n    secp256k1_fe_mul(&a->y, &a->y, &z3);\n    secp256k1_fe_set_int(&a->z, 1);\n    r->x = a->x;\n    r->y = a->y;\n}\n\nstatic void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {\n    secp256k1_fe z2, z3;\n    r->infinity = a->infinity;\n    if (a->infinity) {\n        return;\n    }\n    secp256k1_fe_inv_var(&a->z, &a->z);\n    secp256k1_fe_sqr(&z2, &a->z);\n    secp256k1_fe_mul(&z3, &a->z, &z2);\n    secp256k1_fe_mul(&a->x, &a->x, &z2);\n    secp256k1_fe_mul(&a->y, &a->y, &z3);\n    secp256k1_fe_set_int(&a->z, 1);\n    r->x = a->x;\n    r->y = a->y;\n}\n\nstatic void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {\n    secp256k1_fe *az;\n    secp256k1_fe *azi;\n    size_t i;\n    size_t count = 0;\n    az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);\n    for (i = 0; i < len; i++) {\n        if (!a[i].infinity) {\n            az[count++] = a[i].z;\n        }\n    }\n\n    azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);\n    secp256k1_fe_inv_all_var(azi, az, count);\n    free(az);\n\n    count = 0;\n    for (i = 0; i < len; i++) {\n        r[i].infinity = a[i].infinity;\n        if (!a[i].infinity) {\n            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);\n        }\n    }\n    free(azi);\n}\n\nstatic void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {\n    size_t i = len - 1;\n    secp256k1_fe zi;\n\n    if (len > 0) {\n        /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */\n        secp256k1_fe_inv(&zi, &a[i].z);\n        secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);\n\n        /* Work out way backwards, using the z-ratios to scale the x/y values. */\n        while (i > 0) {\n            secp256k1_fe_mul(&zi, &zi, &zr[i]);\n            i--;\n            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);\n        }\n    }\n}\n\nstatic void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {\n    size_t i = len - 1;\n    secp256k1_fe zs;\n\n    if (len > 0) {\n        /* The z of the final point gives us the \"global Z\" for the table. */\n        r[i].x = a[i].x;\n        r[i].y = a[i].y;\n        *globalz = a[i].z;\n        r[i].infinity = 0;\n        zs = zr[i];\n\n        /* Work our way backwards, using the z-ratios to scale the x/y values. */\n        while (i > 0) {\n            if (i != len - 1) {\n                secp256k1_fe_mul(&zs, &zs, &zr[i]);\n            }\n            i--;\n            secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);\n        }\n    }\n}\n\nstatic void secp256k1_gej_set_infinity(secp256k1_gej *r) {\n    r->infinity = 1;\n    secp256k1_fe_clear(&r->x);\n    secp256k1_fe_clear(&r->y);\n    secp256k1_fe_clear(&r->z);\n}\n\nstatic void secp256k1_gej_clear(secp256k1_gej *r) {\n    r->infinity = 0;\n    secp256k1_fe_clear(&r->x);\n    secp256k1_fe_clear(&r->y);\n    secp256k1_fe_clear(&r->z);\n}\n\nstatic void secp256k1_ge_clear(secp256k1_ge *r) {\n    r->infinity = 0;\n    secp256k1_fe_clear(&r->x);\n    secp256k1_fe_clear(&r->y);\n}\n\nstatic int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {\n    secp256k1_fe x2, x3, c;\n    r->x = *x;\n    secp256k1_fe_sqr(&x2, x);\n    secp256k1_fe_mul(&x3, x, &x2);\n    r->infinity = 0;\n    secp256k1_fe_set_int(&c, CURVE_B);\n    secp256k1_fe_add(&c, &x3);\n    return secp256k1_fe_sqrt(&r->y, &c);\n}\n\nstatic int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {\n    if (!secp256k1_ge_set_xquad(r, x)) {\n        return 0;\n    }\n    secp256k1_fe_normalize_var(&r->y);\n    if (secp256k1_fe_is_odd(&r->y) != odd) {\n        secp256k1_fe_negate(&r->y, &r->y, 1);\n    }\n    return 1;\n\n}\n\nstatic void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {\n   r->infinity = a->infinity;\n   r->x = a->x;\n   r->y = a->y;\n   secp256k1_fe_set_int(&r->z, 1);\n}\n\nstatic int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {\n    secp256k1_fe r, r2;\n    VERIFY_CHECK(!a->infinity);\n    secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);\n    r2 = a->x; secp256k1_fe_normalize_weak(&r2);\n    return secp256k1_fe_equal_var(&r, &r2);\n}\n\nstatic void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {\n    r->infinity = a->infinity;\n    r->x = a->x;\n    r->y = a->y;\n    r->z = a->z;\n    secp256k1_fe_normalize_weak(&r->y);\n    secp256k1_fe_negate(&r->y, &r->y, 1);\n}\n\nstatic int secp256k1_gej_is_infinity(const secp256k1_gej *a) {\n    return a->infinity;\n}\n\nstatic int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {\n    secp256k1_fe y2, x3, z2, z6;\n    if (a->infinity) {\n        return 0;\n    }\n    /** y^2 = x^3 + 7\n     *  (Y/Z^3)^2 = (X/Z^2)^3 + 7\n     *  Y^2 / Z^6 = X^3 / Z^6 + 7\n     *  Y^2 = X^3 + 7*Z^6\n     */\n    secp256k1_fe_sqr(&y2, &a->y);\n    secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);\n    secp256k1_fe_sqr(&z2, &a->z);\n    secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);\n    secp256k1_fe_mul_int(&z6, CURVE_B);\n    secp256k1_fe_add(&x3, &z6);\n    secp256k1_fe_normalize_weak(&x3);\n    return secp256k1_fe_equal_var(&y2, &x3);\n}\n\nstatic int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {\n    secp256k1_fe y2, x3, c;\n    if (a->infinity) {\n        return 0;\n    }\n    /* y^2 = x^3 + 7 */\n    secp256k1_fe_sqr(&y2, &a->y);\n    secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);\n    secp256k1_fe_set_int(&c, CURVE_B);\n    secp256k1_fe_add(&x3, &c);\n    secp256k1_fe_normalize_weak(&x3);\n    return secp256k1_fe_equal_var(&y2, &x3);\n}\n\nstatic void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {\n    /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.\n     *\n     * Note that there is an implementation described at\n     *     https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l\n     * which trades a multiply for a square, but in practice this is actually slower,\n     * mainly because it requires more normalizations.\n     */\n    secp256k1_fe t1,t2,t3,t4;\n    /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,\n     *  Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have\n     *  y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.\n     *\n     *  Having said this, if this function receives a point on a sextic twist, e.g. by\n     *  a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,\n     *  since -6 does have a cube root mod p. For this point, this function will not set\n     *  the infinity flag even though the point doubles to infinity, and the result\n     *  point will be gibberish (z = 0 but infinity = 0).\n     */\n    r->infinity = a->infinity;\n    if (r->infinity) {\n        if (rzr != NULL) {\n            secp256k1_fe_set_int(rzr, 1);\n        }\n        return;\n    }\n\n    if (rzr != NULL) {\n        *rzr = a->y;\n        secp256k1_fe_normalize_weak(rzr);\n        secp256k1_fe_mul_int(rzr, 2);\n    }\n\n    secp256k1_fe_mul(&r->z, &a->z, &a->y);\n    secp256k1_fe_mul_int(&r->z, 2);       /* Z' = 2*Y*Z (2) */\n    secp256k1_fe_sqr(&t1, &a->x);\n    secp256k1_fe_mul_int(&t1, 3);         /* T1 = 3*X^2 (3) */\n    secp256k1_fe_sqr(&t2, &t1);           /* T2 = 9*X^4 (1) */\n    secp256k1_fe_sqr(&t3, &a->y);\n    secp256k1_fe_mul_int(&t3, 2);         /* T3 = 2*Y^2 (2) */\n    secp256k1_fe_sqr(&t4, &t3);\n    secp256k1_fe_mul_int(&t4, 2);         /* T4 = 8*Y^4 (2) */\n    secp256k1_fe_mul(&t3, &t3, &a->x);    /* T3 = 2*X*Y^2 (1) */\n    r->x = t3;\n    secp256k1_fe_mul_int(&r->x, 4);       /* X' = 8*X*Y^2 (4) */\n    secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */\n    secp256k1_fe_add(&r->x, &t2);         /* X' = 9*X^4 - 8*X*Y^2 (6) */\n    secp256k1_fe_negate(&t2, &t2, 1);     /* T2 = -9*X^4 (2) */\n    secp256k1_fe_mul_int(&t3, 6);         /* T3 = 12*X*Y^2 (6) */\n    secp256k1_fe_add(&t3, &t2);           /* T3 = 12*X*Y^2 - 9*X^4 (8) */\n    secp256k1_fe_mul(&r->y, &t1, &t3);    /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */\n    secp256k1_fe_negate(&t2, &t4, 2);     /* T2 = -8*Y^4 (3) */\n    secp256k1_fe_add(&r->y, &t2);         /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */\n}\n\nstatic SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {\n    VERIFY_CHECK(!secp256k1_gej_is_infinity(a));\n    secp256k1_gej_double_var(r, a, rzr);\n}\n\nstatic void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {\n    /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */\n    secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;\n\n    if (a->infinity) {\n        VERIFY_CHECK(rzr == NULL);\n        *r = *b;\n        return;\n    }\n\n    if (b->infinity) {\n        if (rzr != NULL) {\n            secp256k1_fe_set_int(rzr, 1);\n        }\n        *r = *a;\n        return;\n    }\n\n    r->infinity = 0;\n    secp256k1_fe_sqr(&z22, &b->z);\n    secp256k1_fe_sqr(&z12, &a->z);\n    secp256k1_fe_mul(&u1, &a->x, &z22);\n    secp256k1_fe_mul(&u2, &b->x, &z12);\n    secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);\n    secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);\n    secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);\n    secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);\n    if (secp256k1_fe_normalizes_to_zero_var(&h)) {\n        if (secp256k1_fe_normalizes_to_zero_var(&i)) {\n            secp256k1_gej_double_var(r, a, rzr);\n        } else {\n            if (rzr != NULL) {\n                secp256k1_fe_set_int(rzr, 0);\n            }\n            r->infinity = 1;\n        }\n        return;\n    }\n    secp256k1_fe_sqr(&i2, &i);\n    secp256k1_fe_sqr(&h2, &h);\n    secp256k1_fe_mul(&h3, &h, &h2);\n    secp256k1_fe_mul(&h, &h, &b->z);\n    if (rzr != NULL) {\n        *rzr = h;\n    }\n    secp256k1_fe_mul(&r->z, &a->z, &h);\n    secp256k1_fe_mul(&t, &u1, &h2);\n    r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);\n    secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);\n    secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);\n    secp256k1_fe_add(&r->y, &h3);\n}\n\nstatic void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {\n    /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */\n    secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;\n    if (a->infinity) {\n        VERIFY_CHECK(rzr == NULL);\n        secp256k1_gej_set_ge(r, b);\n        return;\n    }\n    if (b->infinity) {\n        if (rzr != NULL) {\n            secp256k1_fe_set_int(rzr, 1);\n        }\n        *r = *a;\n        return;\n    }\n    r->infinity = 0;\n\n    secp256k1_fe_sqr(&z12, &a->z);\n    u1 = a->x; secp256k1_fe_normalize_weak(&u1);\n    secp256k1_fe_mul(&u2, &b->x, &z12);\n    s1 = a->y; secp256k1_fe_normalize_weak(&s1);\n    secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);\n    secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);\n    secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);\n    if (secp256k1_fe_normalizes_to_zero_var(&h)) {\n        if (secp256k1_fe_normalizes_to_zero_var(&i)) {\n            secp256k1_gej_double_var(r, a, rzr);\n        } else {\n            if (rzr != NULL) {\n                secp256k1_fe_set_int(rzr, 0);\n            }\n            r->infinity = 1;\n        }\n        return;\n    }\n    secp256k1_fe_sqr(&i2, &i);\n    secp256k1_fe_sqr(&h2, &h);\n    secp256k1_fe_mul(&h3, &h, &h2);\n    if (rzr != NULL) {\n        *rzr = h;\n    }\n    secp256k1_fe_mul(&r->z, &a->z, &h);\n    secp256k1_fe_mul(&t, &u1, &h2);\n    r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);\n    secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);\n    secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);\n    secp256k1_fe_add(&r->y, &h3);\n}\n\nstatic void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {\n    /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */\n    secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;\n\n    if (b->infinity) {\n        *r = *a;\n        return;\n    }\n    if (a->infinity) {\n        secp256k1_fe bzinv2, bzinv3;\n        r->infinity = b->infinity;\n        secp256k1_fe_sqr(&bzinv2, bzinv);\n        secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv);\n        secp256k1_fe_mul(&r->x, &b->x, &bzinv2);\n        secp256k1_fe_mul(&r->y, &b->y, &bzinv3);\n        secp256k1_fe_set_int(&r->z, 1);\n        return;\n    }\n    r->infinity = 0;\n\n    /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to\n     *  secp256k1's isomorphism we can multiply the Z coordinates on both sides\n     *  by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1).\n     *  This means that (rx,ry,rz) can be calculated as\n     *  (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz.\n     *  The variable az below holds the modified Z coordinate for a, which is used\n     *  for the computation of rx and ry, but not for rz.\n     */\n    secp256k1_fe_mul(&az, &a->z, bzinv);\n\n    secp256k1_fe_sqr(&z12, &az);\n    u1 = a->x; secp256k1_fe_normalize_weak(&u1);\n    secp256k1_fe_mul(&u2, &b->x, &z12);\n    s1 = a->y; secp256k1_fe_normalize_weak(&s1);\n    secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);\n    secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);\n    secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);\n    if (secp256k1_fe_normalizes_to_zero_var(&h)) {\n        if (secp256k1_fe_normalizes_to_zero_var(&i)) {\n            secp256k1_gej_double_var(r, a, NULL);\n        } else {\n            r->infinity = 1;\n        }\n        return;\n    }\n    secp256k1_fe_sqr(&i2, &i);\n    secp256k1_fe_sqr(&h2, &h);\n    secp256k1_fe_mul(&h3, &h, &h2);\n    r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);\n    secp256k1_fe_mul(&t, &u1, &h2);\n    r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);\n    secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);\n    secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);\n    secp256k1_fe_add(&r->y, &h3);\n}\n\n\nstatic void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {\n    /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */\n    static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);\n    secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;\n    secp256k1_fe m_alt, rr_alt;\n    int infinity, degenerate;\n    VERIFY_CHECK(!b->infinity);\n    VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);\n\n    /** In:\n     *    Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.\n     *    In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.\n     *  we find as solution for a unified addition/doubling formula:\n     *    lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation.\n     *    x3 = lambda^2 - (x1 + x2)\n     *    2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2).\n     *\n     *  Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives:\n     *    U1 = X1*Z2^2, U2 = X2*Z1^2\n     *    S1 = Y1*Z2^3, S2 = Y2*Z1^3\n     *    Z = Z1*Z2\n     *    T = U1+U2\n     *    M = S1+S2\n     *    Q = T*M^2\n     *    R = T^2-U1*U2\n     *    X3 = 4*(R^2-Q)\n     *    Y3 = 4*(R*(3*Q-2*R^2)-M^4)\n     *    Z3 = 2*M*Z\n     *  (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)\n     *\n     *  This formula has the benefit of being the same for both addition\n     *  of distinct points and doubling. However, it breaks down in the\n     *  case that either point is infinity, or that y1 = -y2. We handle\n     *  these cases in the following ways:\n     *\n     *    - If b is infinity we simply bail by means of a VERIFY_CHECK.\n     *\n     *    - If a is infinity, we detect this, and at the end of the\n     *      computation replace the result (which will be meaningless,\n     *      but we compute to be constant-time) with b.x : b.y : 1.\n     *\n     *    - If a = -b, we have y1 = -y2, which is a degenerate case.\n     *      But here the answer is infinity, so we simply set the\n     *      infinity flag of the result, overriding the computed values\n     *      without even needing to cmov.\n     *\n     *    - If y1 = -y2 but x1 != x2, which does occur thanks to certain\n     *      properties of our curve (specifically, 1 has nontrivial cube\n     *      roots in our field, and the curve equation has no x coefficient)\n     *      then the answer is not infinity but also not given by the above\n     *      equation. In this case, we cmov in place an alternate expression\n     *      for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these\n     *      expressions for lambda are defined, they are equal, and can be\n     *      obtained from each other by multiplication by (y1 + y2)/(y1 + y2)\n     *      then substitution of x^3 + 7 for y^2 (using the curve equation).\n     *      For all pairs of nonzero points (a, b) at least one is defined,\n     *      so this covers everything.\n     */\n\n    secp256k1_fe_sqr(&zz, &a->z);                       /* z = Z1^2 */\n    u1 = a->x; secp256k1_fe_normalize_weak(&u1);        /* u1 = U1 = X1*Z2^2 (1) */\n    secp256k1_fe_mul(&u2, &b->x, &zz);                  /* u2 = U2 = X2*Z1^2 (1) */\n    s1 = a->y; secp256k1_fe_normalize_weak(&s1);        /* s1 = S1 = Y1*Z2^3 (1) */\n    secp256k1_fe_mul(&s2, &b->y, &zz);                  /* s2 = Y2*Z1^2 (1) */\n    secp256k1_fe_mul(&s2, &s2, &a->z);                  /* s2 = S2 = Y2*Z1^3 (1) */\n    t = u1; secp256k1_fe_add(&t, &u2);                  /* t = T = U1+U2 (2) */\n    m = s1; secp256k1_fe_add(&m, &s2);                  /* m = M = S1+S2 (2) */\n    secp256k1_fe_sqr(&rr, &t);                          /* rr = T^2 (1) */\n    secp256k1_fe_negate(&m_alt, &u2, 1);                /* Malt = -X2*Z1^2 */\n    secp256k1_fe_mul(&tt, &u1, &m_alt);                 /* tt = -U1*U2 (2) */\n    secp256k1_fe_add(&rr, &tt);                         /* rr = R = T^2-U1*U2 (3) */\n    /** If lambda = R/M = 0/0 we have a problem (except in the \"trivial\"\n     *  case that Z = z1z2 = 0, and this is special-cased later on). */\n    degenerate = secp256k1_fe_normalizes_to_zero(&m) &\n                 secp256k1_fe_normalizes_to_zero(&rr);\n    /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.\n     * This means either x1 == beta*x2 or beta*x1 == x2, where beta is\n     * a nontrivial cube root of one. In either case, an alternate\n     * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),\n     * so we set R/M equal to this. */\n    rr_alt = s1;\n    secp256k1_fe_mul_int(&rr_alt, 2);       /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */\n    secp256k1_fe_add(&m_alt, &u1);          /* Malt = X1*Z2^2 - X2*Z1^2 */\n\n    secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);\n    secp256k1_fe_cmov(&m_alt, &m, !degenerate);\n    /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.\n     * From here on out Ralt and Malt represent the numerator\n     * and denominator of lambda; R and M represent the explicit\n     * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */\n    secp256k1_fe_sqr(&n, &m_alt);                       /* n = Malt^2 (1) */\n    secp256k1_fe_mul(&q, &n, &t);                       /* q = Q = T*Malt^2 (1) */\n    /* These two lines use the observation that either M == Malt or M == 0,\n     * so M^3 * Malt is either Malt^4 (which is computed by squaring), or\n     * zero (which is \"computed\" by cmov). So the cost is one squaring\n     * versus two multiplications. */\n    secp256k1_fe_sqr(&n, &n);\n    secp256k1_fe_cmov(&n, &m, degenerate);              /* n = M^3 * Malt (2) */\n    secp256k1_fe_sqr(&t, &rr_alt);                      /* t = Ralt^2 (1) */\n    secp256k1_fe_mul(&r->z, &a->z, &m_alt);             /* r->z = Malt*Z (1) */\n    infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);\n    secp256k1_fe_mul_int(&r->z, 2);                     /* r->z = Z3 = 2*Malt*Z (2) */\n    secp256k1_fe_negate(&q, &q, 1);                     /* q = -Q (2) */\n    secp256k1_fe_add(&t, &q);                           /* t = Ralt^2-Q (3) */\n    secp256k1_fe_normalize_weak(&t);\n    r->x = t;                                           /* r->x = Ralt^2-Q (1) */\n    secp256k1_fe_mul_int(&t, 2);                        /* t = 2*x3 (2) */\n    secp256k1_fe_add(&t, &q);                           /* t = 2*x3 - Q: (4) */\n    secp256k1_fe_mul(&t, &t, &rr_alt);                  /* t = Ralt*(2*x3 - Q) (1) */\n    secp256k1_fe_add(&t, &n);                           /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */\n    secp256k1_fe_negate(&r->y, &t, 3);                  /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */\n    secp256k1_fe_normalize_weak(&r->y);\n    secp256k1_fe_mul_int(&r->x, 4);                     /* r->x = X3 = 4*(Ralt^2-Q) */\n    secp256k1_fe_mul_int(&r->y, 4);                     /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */\n\n    /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */\n    secp256k1_fe_cmov(&r->x, &b->x, a->infinity);\n    secp256k1_fe_cmov(&r->y, &b->y, a->infinity);\n    secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);\n    r->infinity = infinity;\n}\n\nstatic void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {\n    /* Operations: 4 mul, 1 sqr */\n    secp256k1_fe zz;\n    VERIFY_CHECK(!secp256k1_fe_is_zero(s));\n    secp256k1_fe_sqr(&zz, s);\n    secp256k1_fe_mul(&r->x, &r->x, &zz);                /* r->x *= s^2 */\n    secp256k1_fe_mul(&r->y, &r->y, &zz);\n    secp256k1_fe_mul(&r->y, &r->y, s);                  /* r->y *= s^3 */\n    secp256k1_fe_mul(&r->z, &r->z, s);                  /* r->z *= s   */\n}\n\nstatic void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {\n    secp256k1_fe x, y;\n    VERIFY_CHECK(!a->infinity);\n    x = a->x;\n    secp256k1_fe_normalize(&x);\n    y = a->y;\n    secp256k1_fe_normalize(&y);\n    secp256k1_fe_to_storage(&r->x, &x);\n    secp256k1_fe_to_storage(&r->y, &y);\n}\n\nstatic void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) {\n    secp256k1_fe_from_storage(&r->x, &a->x);\n    secp256k1_fe_from_storage(&r->y, &a->y);\n    r->infinity = 0;\n}\n\nstatic SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {\n    secp256k1_fe_storage_cmov(&r->x, &a->x, flag);\n    secp256k1_fe_storage_cmov(&r->y, &a->y, flag);\n}\n\n#ifdef USE_ENDOMORPHISM\nstatic void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {\n    static const secp256k1_fe beta = SECP256K1_FE_CONST(\n        0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,\n        0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul\n    );\n    *r = *a;\n    secp256k1_fe_mul(&r->x, &r->x, &beta);\n}\n#endif\n\nstatic int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {\n    secp256k1_fe yz;\n\n    if (a->infinity) {\n        return 0;\n    }\n\n    /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as\n     * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z\n       is */\n    secp256k1_fe_mul(&yz, &a->y, &a->z);\n    return secp256k1_fe_is_quad_var(&yz);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/hash.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_HASH_\n#define _SECP256K1_HASH_\n\n#include <stdlib.h>\n#include <stdint.h>\n\ntypedef struct {\n    uint32_t s[8];\n    uint32_t buf[16]; /* In big endian */\n    size_t bytes;\n} secp256k1_sha256_t;\n\nstatic void secp256k1_sha256_initialize(secp256k1_sha256_t *hash);\nstatic void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size);\nstatic void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32);\n\ntypedef struct {\n    secp256k1_sha256_t inner, outer;\n} secp256k1_hmac_sha256_t;\n\nstatic void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size);\nstatic void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size);\nstatic void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32);\n\ntypedef struct {\n    unsigned char v[32];\n    unsigned char k[32];\n    int retry;\n} secp256k1_rfc6979_hmac_sha256_t;\n\nstatic void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);\nstatic void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);\nstatic void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/hash_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_HASH_IMPL_H_\n#define _SECP256K1_HASH_IMPL_H_\n\n#include \"hash.h\"\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))\n#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))\n#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10))\n#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7))\n#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3))\n#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10))\n\n#define Round(a,b,c,d,e,f,g,h,k,w) do { \\\n    uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \\\n    uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \\\n    (d) += t1; \\\n    (h) = t1 + t2; \\\n} while(0)\n\n#ifdef WORDS_BIGENDIAN\n#define BE32(x) (x)\n#else\n#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))\n#endif\n\nstatic void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {\n    hash->s[0] = 0x6a09e667ul;\n    hash->s[1] = 0xbb67ae85ul;\n    hash->s[2] = 0x3c6ef372ul;\n    hash->s[3] = 0xa54ff53aul;\n    hash->s[4] = 0x510e527ful;\n    hash->s[5] = 0x9b05688cul;\n    hash->s[6] = 0x1f83d9abul;\n    hash->s[7] = 0x5be0cd19ul;\n    hash->bytes = 0;\n}\n\n/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */\nstatic void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {\n    uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n    uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;\n\n    Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));\n    Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));\n    Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));\n    Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));\n    Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));\n    Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));\n    Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));\n    Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));\n    Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));\n    Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));\n    Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));\n    Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));\n    Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));\n    Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));\n    Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));\n    Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));\n\n    Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));\n\n    Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));\n\n    Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));\n    Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));\n    Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));\n    Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));\n    Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));\n    Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));\n    Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));\n    Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));\n    Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));\n    Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));\n    Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));\n    Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));\n    Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));\n    Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));\n    Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));\n    Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));\n\n    s[0] += a;\n    s[1] += b;\n    s[2] += c;\n    s[3] += d;\n    s[4] += e;\n    s[5] += f;\n    s[6] += g;\n    s[7] += h;\n}\n\nstatic void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {\n    size_t bufsize = hash->bytes & 0x3F;\n    hash->bytes += len;\n    while (bufsize + len >= 64) {\n        /* Fill the buffer, and process it. */\n        memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);\n        data += 64 - bufsize;\n        len -= 64 - bufsize;\n        secp256k1_sha256_transform(hash->s, hash->buf);\n        bufsize = 0;\n    }\n    if (len) {\n        /* Fill the buffer with what remains. */\n        memcpy(((unsigned char*)hash->buf) + bufsize, data, len);\n    }\n}\n\nstatic void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) {\n    static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n    uint32_t sizedesc[2];\n    uint32_t out[8];\n    int i = 0;\n    sizedesc[0] = BE32(hash->bytes >> 29);\n    sizedesc[1] = BE32(hash->bytes << 3);\n    secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));\n    secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);\n    for (i = 0; i < 8; i++) {\n        out[i] = BE32(hash->s[i]);\n        hash->s[i] = 0;\n    }\n    memcpy(out32, (const unsigned char*)out, 32);\n}\n\nstatic void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {\n    int n;\n    unsigned char rkey[64];\n    if (keylen <= 64) {\n        memcpy(rkey, key, keylen);\n        memset(rkey + keylen, 0, 64 - keylen);\n    } else {\n        secp256k1_sha256_t sha256;\n        secp256k1_sha256_initialize(&sha256);\n        secp256k1_sha256_write(&sha256, key, keylen);\n        secp256k1_sha256_finalize(&sha256, rkey);\n        memset(rkey + 32, 0, 32);\n    }\n\n    secp256k1_sha256_initialize(&hash->outer);\n    for (n = 0; n < 64; n++) {\n        rkey[n] ^= 0x5c;\n    }\n    secp256k1_sha256_write(&hash->outer, rkey, 64);\n\n    secp256k1_sha256_initialize(&hash->inner);\n    for (n = 0; n < 64; n++) {\n        rkey[n] ^= 0x5c ^ 0x36;\n    }\n    secp256k1_sha256_write(&hash->inner, rkey, 64);\n    memset(rkey, 0, 64);\n}\n\nstatic void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) {\n    secp256k1_sha256_write(&hash->inner, data, size);\n}\n\nstatic void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) {\n    unsigned char temp[32];\n    secp256k1_sha256_finalize(&hash->inner, temp);\n    secp256k1_sha256_write(&hash->outer, temp, 32);\n    memset(temp, 0, 32);\n    secp256k1_sha256_finalize(&hash->outer, out32);\n}\n\n\nstatic void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {\n    secp256k1_hmac_sha256_t hmac;\n    static const unsigned char zero[1] = {0x00};\n    static const unsigned char one[1] = {0x01};\n\n    memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */\n    memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */\n\n    /* RFC6979 3.2.d. */\n    secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n    secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n    secp256k1_hmac_sha256_write(&hmac, zero, 1);\n    secp256k1_hmac_sha256_write(&hmac, key, keylen);\n    secp256k1_hmac_sha256_finalize(&hmac, rng->k);\n    secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n    secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n    secp256k1_hmac_sha256_finalize(&hmac, rng->v);\n\n    /* RFC6979 3.2.f. */\n    secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n    secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n    secp256k1_hmac_sha256_write(&hmac, one, 1);\n    secp256k1_hmac_sha256_write(&hmac, key, keylen);\n    secp256k1_hmac_sha256_finalize(&hmac, rng->k);\n    secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n    secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n    secp256k1_hmac_sha256_finalize(&hmac, rng->v);\n    rng->retry = 0;\n}\n\nstatic void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) {\n    /* RFC6979 3.2.h. */\n    static const unsigned char zero[1] = {0x00};\n    if (rng->retry) {\n        secp256k1_hmac_sha256_t hmac;\n        secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n        secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n        secp256k1_hmac_sha256_write(&hmac, zero, 1);\n        secp256k1_hmac_sha256_finalize(&hmac, rng->k);\n        secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n        secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n        secp256k1_hmac_sha256_finalize(&hmac, rng->v);\n    }\n\n    while (outlen > 0) {\n        secp256k1_hmac_sha256_t hmac;\n        int now = outlen;\n        secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);\n        secp256k1_hmac_sha256_write(&hmac, rng->v, 32);\n        secp256k1_hmac_sha256_finalize(&hmac, rng->v);\n        if (now > 32) {\n            now = 32;\n        }\n        memcpy(out, rng->v, now);\n        out += now;\n        outlen -= now;\n    }\n\n    rng->retry = 1;\n}\n\nstatic void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) {\n    memset(rng->k, 0, 32);\n    memset(rng->v, 0, 32);\n    rng->retry = 0;\n}\n\n#undef BE32\n#undef Round\n#undef sigma1\n#undef sigma0\n#undef Sigma1\n#undef Sigma0\n#undef Maj\n#undef Ch\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java",
    "content": "/*\n * Copyright 2013 Google Inc.\n * Copyright 2014-2016 the libsecp256k1 contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.bitcoin;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport java.math.BigInteger;\nimport com.google.common.base.Preconditions;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport static org.bitcoin.NativeSecp256k1Util.*;\n\n/**\n * <p>This class holds native methods to handle ECDSA verification.</p>\n *\n * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>\n *\n * <p>To build secp256k1 for use with bitcoinj, run\n * `./configure --enable-jni --enable-experimental --enable-module-ecdh`\n * and `make` then copy `.libs/libsecp256k1.so` to your system library path\n * or point the JVM to the folder containing it with -Djava.library.path\n * </p>\n */\npublic class NativeSecp256k1 {\n\n    private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();\n    private static final Lock r = rwl.readLock();\n    private static final Lock w = rwl.writeLock();\n    private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();\n    /**\n     * Verifies the given secp256k1 signature in native code.\n     * Calling when enabled == false is undefined (probably library not loaded)\n     *\n     * @param data The data which was signed, must be exactly 32 bytes\n     * @param signature The signature\n     * @param pub The public key which did the signing\n     */\n    public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{\n        Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < 520) {\n            byteBuff = ByteBuffer.allocateDirect(520);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(data);\n        byteBuff.put(signature);\n        byteBuff.put(pub);\n\n        byte[][] retByteArray;\n\n        r.lock();\n        try {\n          return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;\n        } finally {\n          r.unlock();\n        }\n    }\n\n    /**\n     * libsecp256k1 Create an ECDSA signature.\n     *\n     * @param data Message hash, 32 bytes\n     * @param key Secret key, 32 bytes\n     *\n     * Return values\n     * @param sig byte array of signature\n     */\n    public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{\n        Preconditions.checkArgument(data.length == 32 && sec.length <= 32);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < 32 + 32) {\n            byteBuff = ByteBuffer.allocateDirect(32 + 32);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(data);\n        byteBuff.put(sec);\n\n        byte[][] retByteArray;\n\n        r.lock();\n        try {\n          retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());\n        } finally {\n          r.unlock();\n        }\n\n        byte[] sigArr = retByteArray[0];\n        int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(sigArr.length, sigLen, \"Got bad signature length.\");\n\n        return retVal == 0 ? new byte[0] : sigArr;\n    }\n\n    /**\n     * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid\n     *\n     * @param seckey ECDSA Secret key, 32 bytes\n     */\n    public static boolean secKeyVerify(byte[] seckey) {\n        Preconditions.checkArgument(seckey.length == 32);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < seckey.length) {\n            byteBuff = ByteBuffer.allocateDirect(seckey.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(seckey);\n\n        r.lock();\n        try {\n          return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;\n        } finally {\n          r.unlock();\n        }\n    }\n\n\n    /**\n     * libsecp256k1 Compute Pubkey - computes public key from secret key\n     *\n     * @param seckey ECDSA Secret key, 32 bytes\n     *\n     * Return values\n     * @param pubkey ECDSA Public key, 33 or 65 bytes\n     */\n    //TODO add a 'compressed' arg\n    public static byte[] computePubkey(byte[] seckey) throws AssertFailException{\n        Preconditions.checkArgument(seckey.length == 32);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < seckey.length) {\n            byteBuff = ByteBuffer.allocateDirect(seckey.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(seckey);\n\n        byte[][] retByteArray;\n\n        r.lock();\n        try {\n          retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());\n        } finally {\n          r.unlock();\n        }\n\n        byte[] pubArr = retByteArray[0];\n        int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(pubArr.length, pubLen, \"Got bad pubkey length.\");\n\n        return retVal == 0 ? new byte[0]: pubArr;\n    }\n\n    /**\n     * libsecp256k1 Cleanup - This destroys the secp256k1 context object\n     * This should be called at the end of the program for proper cleanup of the context.\n     */\n    public static synchronized void cleanup() {\n        w.lock();\n        try {\n          secp256k1_destroy_context(Secp256k1Context.getContext());\n        } finally {\n          w.unlock();\n        }\n    }\n\n    public static long cloneContext() {\n       r.lock();\n       try {\n        return secp256k1_ctx_clone(Secp256k1Context.getContext());\n       } finally { r.unlock(); }\n    }\n\n    /**\n     * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it\n     *\n     * @param tweak some bytes to tweak with\n     * @param seckey 32-byte seckey\n     */\n    public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{\n        Preconditions.checkArgument(privkey.length == 32);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {\n            byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(privkey);\n        byteBuff.put(tweak);\n\n        byte[][] retByteArray;\n        r.lock();\n        try {\n          retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());\n        } finally {\n          r.unlock();\n        }\n\n        byte[] privArr = retByteArray[0];\n\n        int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(privArr.length, privLen, \"Got bad pubkey length.\");\n\n        assertEquals(retVal, 1, \"Failed return value check.\");\n\n        return privArr;\n    }\n\n    /**\n     * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it\n     *\n     * @param tweak some bytes to tweak with\n     * @param seckey 32-byte seckey\n     */\n    public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{\n        Preconditions.checkArgument(privkey.length == 32);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {\n            byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(privkey);\n        byteBuff.put(tweak);\n\n        byte[][] retByteArray;\n        r.lock();\n        try {\n          retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());\n        } finally {\n          r.unlock();\n        }\n\n        byte[] privArr = retByteArray[0];\n\n        int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(privArr.length, privLen, \"Got bad pubkey length.\");\n\n        assertEquals(retVal, 1, \"Failed return value check.\");\n\n        return privArr;\n    }\n\n    /**\n     * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it\n     *\n     * @param tweak some bytes to tweak with\n     * @param pubkey 32-byte seckey\n     */\n    public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{\n        Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {\n            byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(pubkey);\n        byteBuff.put(tweak);\n\n        byte[][] retByteArray;\n        r.lock();\n        try {\n          retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);\n        } finally {\n          r.unlock();\n        }\n\n        byte[] pubArr = retByteArray[0];\n\n        int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(pubArr.length, pubLen, \"Got bad pubkey length.\");\n\n        assertEquals(retVal, 1, \"Failed return value check.\");\n\n        return pubArr;\n    }\n\n    /**\n     * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it\n     *\n     * @param tweak some bytes to tweak with\n     * @param pubkey 32-byte seckey\n     */\n    public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{\n        Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {\n            byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(pubkey);\n        byteBuff.put(tweak);\n\n        byte[][] retByteArray;\n        r.lock();\n        try {\n          retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);\n        } finally {\n          r.unlock();\n        }\n\n        byte[] pubArr = retByteArray[0];\n\n        int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;\n        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n\n        assertEquals(pubArr.length, pubLen, \"Got bad pubkey length.\");\n\n        assertEquals(retVal, 1, \"Failed return value check.\");\n\n        return pubArr;\n    }\n\n    /**\n     * libsecp256k1 create ECDH secret - constant time ECDH calculation\n     *\n     * @param seckey byte array of secret key used in exponentiaion\n     * @param pubkey byte array of public key used in exponentiaion\n     */\n    public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{\n        Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {\n            byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(seckey);\n        byteBuff.put(pubkey);\n\n        byte[][] retByteArray;\n        r.lock();\n        try {\n          retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);\n        } finally {\n          r.unlock();\n        }\n\n        byte[] resArr = retByteArray[0];\n        int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();\n\n        assertEquals(resArr.length, 32, \"Got bad result length.\");\n        assertEquals(retVal, 1, \"Failed return value check.\");\n\n        return resArr;\n    }\n\n    /**\n     * libsecp256k1 randomize - updates the context randomization\n     *\n     * @param seed 32-byte random seed\n     */\n    public static synchronized boolean randomize(byte[] seed) throws AssertFailException{\n        Preconditions.checkArgument(seed.length == 32 || seed == null);\n\n        ByteBuffer byteBuff = nativeECDSABuffer.get();\n        if (byteBuff == null || byteBuff.capacity() < seed.length) {\n            byteBuff = ByteBuffer.allocateDirect(seed.length);\n            byteBuff.order(ByteOrder.nativeOrder());\n            nativeECDSABuffer.set(byteBuff);\n        }\n        byteBuff.rewind();\n        byteBuff.put(seed);\n\n        w.lock();\n        try {\n          return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;\n        } finally {\n          w.unlock();\n        }\n    }\n\n    private static native long secp256k1_ctx_clone(long context);\n\n    private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);\n\n    private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);\n\n    private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);\n\n    private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);\n\n    private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);\n\n    private static native void secp256k1_destroy_context(long context);\n\n    private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);\n\n    private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);\n\n    private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);\n\n    private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);\n\n    private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);\n\n    private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);\n\n}\n"
  },
  {
    "path": "src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java",
    "content": "package org.bitcoin;\n\nimport com.google.common.io.BaseEncoding;\nimport java.util.Arrays;\nimport java.math.BigInteger;\nimport javax.xml.bind.DatatypeConverter;\nimport static org.bitcoin.NativeSecp256k1Util.*;\n\n/**\n * This class holds test cases defined for testing this library.\n */\npublic class NativeSecp256k1Test {\n\n    //TODO improve comments/add more tests\n    /**\n      * This tests verify() for a valid signature\n      */\n    public static void testVerifyPos() throws AssertFailException{\n        boolean result = false;\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90\".toLowerCase()); //sha256hash of \"testing\"\n        byte[] sig = BaseEncoding.base16().lowerCase().decode(\"3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589\".toLowerCase());\n        byte[] pub = BaseEncoding.base16().lowerCase().decode(\"040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40\".toLowerCase());\n\n        result = NativeSecp256k1.verify( data, sig, pub);\n        assertEquals( result, true , \"testVerifyPos\");\n    }\n\n    /**\n      * This tests verify() for a non-valid signature\n      */\n    public static void testVerifyNeg() throws AssertFailException{\n        boolean result = false;\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91\".toLowerCase()); //sha256hash of \"testing\"\n        byte[] sig = BaseEncoding.base16().lowerCase().decode(\"3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589\".toLowerCase());\n        byte[] pub = BaseEncoding.base16().lowerCase().decode(\"040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40\".toLowerCase());\n\n        result = NativeSecp256k1.verify( data, sig, pub);\n        //System.out.println(\" TEST \" + new BigInteger(1, resultbytes).toString(16));\n        assertEquals( result, false , \"testVerifyNeg\");\n    }\n\n    /**\n      * This tests secret key verify() for a valid secretkey\n      */\n    public static void testSecKeyVerifyPos() throws AssertFailException{\n        boolean result = false;\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n\n        result = NativeSecp256k1.secKeyVerify( sec );\n        //System.out.println(\" TEST \" + new BigInteger(1, resultbytes).toString(16));\n        assertEquals( result, true , \"testSecKeyVerifyPos\");\n    }\n\n    /**\n      * This tests secret key verify() for a invalid secretkey\n      */\n    public static void testSecKeyVerifyNeg() throws AssertFailException{\n        boolean result = false;\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\".toLowerCase());\n\n        result = NativeSecp256k1.secKeyVerify( sec );\n        //System.out.println(\" TEST \" + new BigInteger(1, resultbytes).toString(16));\n        assertEquals( result, false , \"testSecKeyVerifyNeg\");\n    }\n\n    /**\n      * This tests public key create() for a valid secretkey\n      */\n    public static void testPubKeyCreatePos() throws AssertFailException{\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n\n        byte[] resultArr = NativeSecp256k1.computePubkey( sec);\n        String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( pubkeyString , \"04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6\" , \"testPubKeyCreatePos\");\n    }\n\n    /**\n      * This tests public key create() for a invalid secretkey\n      */\n    public static void testPubKeyCreateNeg() throws AssertFailException{\n       byte[] sec = BaseEncoding.base16().lowerCase().decode(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\".toLowerCase());\n\n       byte[] resultArr = NativeSecp256k1.computePubkey( sec);\n       String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n       assertEquals( pubkeyString, \"\" , \"testPubKeyCreateNeg\");\n    }\n\n    /**\n      * This tests sign() for a valid secretkey\n      */\n    public static void testSignPos() throws AssertFailException{\n\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90\".toLowerCase()); //sha256hash of \"testing\"\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n\n        byte[] resultArr = NativeSecp256k1.sign(data, sec);\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString, \"30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9\" , \"testSignPos\");\n    }\n\n    /**\n      * This tests sign() for a invalid secretkey\n      */\n    public static void testSignNeg() throws AssertFailException{\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90\".toLowerCase()); //sha256hash of \"testing\"\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\".toLowerCase());\n\n        byte[] resultArr = NativeSecp256k1.sign(data, sec);\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString, \"\" , \"testSignNeg\");\n    }\n\n    /**\n      * This tests private key tweak-add\n      */\n    public static void testPrivKeyTweakAdd_1() throws AssertFailException {\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3\".toLowerCase()); //sha256hash of \"tweak\"\n\n        byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString , \"A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3\" , \"testPrivKeyAdd_1\");\n    }\n\n    /**\n      * This tests private key tweak-mul\n      */\n    public static void testPrivKeyTweakMul_1() throws AssertFailException {\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3\".toLowerCase()); //sha256hash of \"tweak\"\n\n        byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString , \"97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC\" , \"testPrivKeyMul_1\");\n    }\n\n    /**\n      * This tests private key tweak-add uncompressed\n      */\n    public static void testPrivKeyTweakAdd_2() throws AssertFailException {\n        byte[] pub = BaseEncoding.base16().lowerCase().decode(\"040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40\".toLowerCase());\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3\".toLowerCase()); //sha256hash of \"tweak\"\n\n        byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString , \"0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF\" , \"testPrivKeyAdd_2\");\n    }\n\n    /**\n      * This tests private key tweak-mul uncompressed\n      */\n    public static void testPrivKeyTweakMul_2() throws AssertFailException {\n        byte[] pub = BaseEncoding.base16().lowerCase().decode(\"040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40\".toLowerCase());\n        byte[] data = BaseEncoding.base16().lowerCase().decode(\"3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3\".toLowerCase()); //sha256hash of \"tweak\"\n\n        byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );\n        String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( sigString , \"04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589\" , \"testPrivKeyMul_2\");\n    }\n\n    /**\n      * This tests seed randomization\n      */\n    public static void testRandomize() throws AssertFailException {\n        byte[] seed = BaseEncoding.base16().lowerCase().decode(\"A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11\".toLowerCase()); //sha256hash of \"random\"\n        boolean result = NativeSecp256k1.randomize(seed);\n        assertEquals( result, true, \"testRandomize\");\n    }\n\n    public static void testCreateECDHSecret() throws AssertFailException{\n\n        byte[] sec = BaseEncoding.base16().lowerCase().decode(\"67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530\".toLowerCase());\n        byte[] pub = BaseEncoding.base16().lowerCase().decode(\"040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40\".toLowerCase());\n\n        byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);\n        String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);\n        assertEquals( ecdhString, \"2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043\" , \"testCreateECDHSecret\");\n    }\n\n    public static void main(String[] args) throws AssertFailException{\n\n\n        System.out.println(\"\\n libsecp256k1 enabled: \" + Secp256k1Context.isEnabled() + \"\\n\");\n\n        assertEquals( Secp256k1Context.isEnabled(), true, \"isEnabled\" );\n\n        //Test verify() success/fail\n        testVerifyPos();\n        testVerifyNeg();\n\n        //Test secKeyVerify() success/fail\n        testSecKeyVerifyPos();\n        testSecKeyVerifyNeg();\n\n        //Test computePubkey() success/fail\n        testPubKeyCreatePos();\n        testPubKeyCreateNeg();\n\n        //Test sign() success/fail\n        testSignPos();\n        testSignNeg();\n\n        //Test privKeyTweakAdd() 1\n        testPrivKeyTweakAdd_1();\n\n        //Test privKeyTweakMul() 2\n        testPrivKeyTweakMul_1();\n\n        //Test privKeyTweakAdd() 3\n        testPrivKeyTweakAdd_2();\n\n        //Test privKeyTweakMul() 4\n        testPrivKeyTweakMul_2();\n\n        //Test randomize()\n        testRandomize();\n\n        //Test ECDH\n        testCreateECDHSecret();\n\n        NativeSecp256k1.cleanup();\n\n        System.out.println(\" All tests passed.\" );\n\n    }\n}\n"
  },
  {
    "path": "src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java",
    "content": "/*\n * Copyright 2014-2016 the libsecp256k1 contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.bitcoin;\n\npublic class NativeSecp256k1Util{\n\n    public static void assertEquals( int val, int val2, String message ) throws AssertFailException{\n      if( val != val2 )\n        throw new AssertFailException(\"FAIL: \" + message);\n    }\n\n    public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{\n      if( val != val2 )\n        throw new AssertFailException(\"FAIL: \" + message);\n      else\n        System.out.println(\"PASS: \" + message);\n    }\n\n    public static void assertEquals( String val, String val2, String message ) throws AssertFailException{\n      if( !val.equals(val2) )\n        throw new AssertFailException(\"FAIL: \" + message);\n      else\n        System.out.println(\"PASS: \" + message);\n    }\n\n    public static class AssertFailException extends Exception {\n      public AssertFailException(String message) {\n        super( message );\n      }\n    }\n}\n"
  },
  {
    "path": "src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java",
    "content": "/*\n * Copyright 2014-2016 the libsecp256k1 contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.bitcoin;\n\n/**\n * This class holds the context reference used in native methods \n * to handle ECDSA operations.\n */\npublic class Secp256k1Context {\n  private static final boolean enabled; //true if the library is loaded\n  private static final long context; //ref to pointer to context obj\n\n  static { //static initializer\n      boolean isEnabled = true;\n      long contextRef = -1;\n      try {\n          System.loadLibrary(\"secp256k1\");\n          contextRef = secp256k1_init_context();\n      } catch (UnsatisfiedLinkError e) {\n          System.out.println(\"UnsatisfiedLinkError: \" + e.toString());\n          isEnabled = false;\n      }\n      enabled = isEnabled;\n      context = contextRef;\n  }\n\n  public static boolean isEnabled() {\n     return enabled;\n  }\n\n  public static long getContext() {\n     if(!enabled) return -1; //sanity check\n     return context;\n  }\n\n  private static native long secp256k1_init_context();\n}\n"
  },
  {
    "path": "src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c",
    "content": "#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include \"org_bitcoin_NativeSecp256k1.h\"\n#include \"include/secp256k1.h\"\n#include \"include/secp256k1_ecdh.h\"\n#include \"include/secp256k1_recovery.h\"\n\n\nSECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone\n  (JNIEnv* env, jclass classObject, jlong ctx_l)\n{\n  const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n\n  jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);\n\n  (void)classObject;(void)env;\n\n  return ctx_clone_l;\n\n}\n\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n\n  const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n\n  (void)classObject;\n\n  return secp256k1_context_randomize(ctx, seed);\n\n}\n\nSECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context\n  (JNIEnv* env, jclass classObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n\n  secp256k1_context_destroy(ctx);\n\n  (void)classObject;(void)env;\n}\n\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n\n  unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* sigdata = {  (unsigned char*) (data + 32) };\n  const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };\n\n  secp256k1_ecdsa_signature sig;\n  secp256k1_pubkey pubkey;\n\n  int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);\n\n  if( ret ) {\n    ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);\n\n    if( ret ) {\n      ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);\n    }\n  }\n\n  (void)classObject;\n\n  return ret;\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  unsigned char* secKey = (unsigned char*) (data + 32);\n\n  jobjectArray retArray;\n  jbyteArray sigArray, intsByteArray;\n  unsigned char intsarray[2];\n\n  secp256k1_ecdsa_signature sig[72];\n\n  int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );\n\n  unsigned char outputSer[72];\n  size_t outputLen = 72;\n\n  if( ret ) {\n    int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;\n  }\n\n  intsarray[0] = outputLen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  sigArray = (*env)->NewByteArray(env, outputLen);\n  (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);\n  (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n\n  (void)classObject;\n\n  return secp256k1_ec_seckey_verify(ctx, secKey);\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n\n  secp256k1_pubkey pubkey;\n\n  jobjectArray retArray;\n  jbyteArray pubkeyArray, intsByteArray;\n  unsigned char intsarray[2];\n\n  int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);\n\n  unsigned char outputSer[65];\n  size_t outputLen = 65;\n\n  if( ret ) {\n    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;\n  }\n\n  intsarray[0] = outputLen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  pubkeyArray = (*env)->NewByteArray(env, outputLen);\n  (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);\n  (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* tweak = (unsigned char*) (privkey + 32);\n\n  jobjectArray retArray;\n  jbyteArray privArray, intsByteArray;\n  unsigned char intsarray[2];\n\n  int privkeylen = 32;\n\n  int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);\n\n  intsarray[0] = privkeylen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  privArray = (*env)->NewByteArray(env, privkeylen);\n  (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);\n  (*env)->SetObjectArrayElement(env, retArray, 0, privArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* tweak = (unsigned char*) (privkey + 32);\n\n  jobjectArray retArray;\n  jbyteArray privArray, intsByteArray;\n  unsigned char intsarray[2];\n\n  int privkeylen = 32;\n\n  int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);\n\n  intsarray[0] = privkeylen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  privArray = (*env)->NewByteArray(env, privkeylen);\n  (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);\n  (*env)->SetObjectArrayElement(env, retArray, 0, privArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n/*  secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/\n  unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* tweak = (unsigned char*) (pkey + publen);\n\n  jobjectArray retArray;\n  jbyteArray pubArray, intsByteArray;\n  unsigned char intsarray[2];\n  unsigned char outputSer[65];\n  size_t outputLen = 65;\n\n  secp256k1_pubkey pubkey;\n  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);\n\n  if( ret ) {\n    ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);\n  }\n\n  if( ret ) {\n    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;\n  }\n\n  intsarray[0] = outputLen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  pubArray = (*env)->NewByteArray(env, outputLen);\n  (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);\n  (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* tweak = (unsigned char*) (pkey + publen);\n\n  jobjectArray retArray;\n  jbyteArray pubArray, intsByteArray;\n  unsigned char intsarray[2];\n  unsigned char outputSer[65];\n  size_t outputLen = 65;\n\n  secp256k1_pubkey pubkey;\n  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);\n\n  if ( ret ) {\n    ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);\n  }\n\n  if( ret ) {\n    int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;\n  }\n\n  intsarray[0] = outputLen;\n  intsarray[1] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  pubArray = (*env)->NewByteArray(env, outputLen);\n  (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);\n  (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 2);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n\nSECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine\n  (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)\n{\n  (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;\n\n  return 0;\n}\n\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)\n{\n  secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;\n  const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);\n  const unsigned char* pubdata = (const unsigned char*) (secdata + 32);\n\n  jobjectArray retArray;\n  jbyteArray outArray, intsByteArray;\n  unsigned char intsarray[1];\n  secp256k1_pubkey pubkey;\n  unsigned char nonce_res[32];\n  size_t outputLen = 32;\n\n  int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);\n\n  if (ret) {\n    ret = secp256k1_ecdh(\n      ctx,\n      nonce_res,\n      &pubkey,\n      secdata\n    );\n  }\n\n  intsarray[0] = ret;\n\n  retArray = (*env)->NewObjectArray(env, 2,\n    (*env)->FindClass(env, \"[B\"),\n    (*env)->NewByteArray(env, 1));\n\n  outArray = (*env)->NewByteArray(env, outputLen);\n  (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);\n  (*env)->SetObjectArrayElement(env, retArray, 0, outArray);\n\n  intsByteArray = (*env)->NewByteArray(env, 1);\n  (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);\n  (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);\n\n  (void)classObject;\n\n  return retArray;\n}\n"
  },
  {
    "path": "src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n#include \"include/secp256k1.h\"\n/* Header for class org_bitcoin_NativeSecp256k1 */\n\n#ifndef _Included_org_bitcoin_NativeSecp256k1\n#define _Included_org_bitcoin_NativeSecp256k1\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ctx_clone\n * Signature: (J)J\n */\nSECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone\n  (JNIEnv *, jclass, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_context_randomize\n * Signature: (Ljava/nio/ByteBuffer;J)I\n */\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_privkey_tweak_add\n * Signature: (Ljava/nio/ByteBuffer;J)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_privkey_tweak_mul\n * Signature: (Ljava/nio/ByteBuffer;J)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_pubkey_tweak_add\n * Signature: (Ljava/nio/ByteBuffer;JI)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add\n  (JNIEnv *, jclass, jobject, jlong, jint);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_pubkey_tweak_mul\n * Signature: (Ljava/nio/ByteBuffer;JI)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul\n  (JNIEnv *, jclass, jobject, jlong, jint);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_destroy_context\n * Signature: (J)V\n */\nSECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context\n  (JNIEnv *, jclass, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ecdsa_verify\n * Signature: (Ljava/nio/ByteBuffer;JII)I\n */\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify\n  (JNIEnv *, jclass, jobject, jlong, jint, jint);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ecdsa_sign\n * Signature: (Ljava/nio/ByteBuffer;J)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ec_seckey_verify\n * Signature: (Ljava/nio/ByteBuffer;J)I\n */\nSECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ec_pubkey_create\n * Signature: (Ljava/nio/ByteBuffer;J)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create\n  (JNIEnv *, jclass, jobject, jlong);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ec_pubkey_parse\n * Signature: (Ljava/nio/ByteBuffer;JI)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse\n  (JNIEnv *, jclass, jobject, jlong, jint);\n\n/*\n * Class:     org_bitcoin_NativeSecp256k1\n * Method:    secp256k1_ecdh\n * Signature: (Ljava/nio/ByteBuffer;JI)[[B\n */\nSECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh\n  (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);\n\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c",
    "content": "#include <stdlib.h>\n#include <stdint.h>\n#include \"org_bitcoin_Secp256k1Context.h\"\n#include \"include/secp256k1.h\"\n\nSECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context\n  (JNIEnv* env, jclass classObject)\n{\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n\n  (void)classObject;(void)env;\n\n  return (uintptr_t)ctx;\n}\n\n"
  },
  {
    "path": "src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n#include \"include/secp256k1.h\"\n/* Header for class org_bitcoin_Secp256k1Context */\n\n#ifndef _Included_org_bitcoin_Secp256k1Context\n#define _Included_org_bitcoin_Secp256k1Context\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_bitcoin_Secp256k1Context\n * Method:    secp256k1_init_context\n * Signature: ()J\n */\nSECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context\n  (JNIEnv *, jclass);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/modules/ecdh/Makefile.am.include",
    "content": "include_HEADERS += include/secp256k1_ecdh.h\nnoinst_HEADERS += src/modules/ecdh/main_impl.h\nnoinst_HEADERS += src/modules/ecdh/tests_impl.h\nif USE_BENCHMARK\nnoinst_PROGRAMS += bench_ecdh\nbench_ecdh_SOURCES = src/bench_ecdh.c\nbench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)\nendif\n"
  },
  {
    "path": "src/secp256k1/src/modules/ecdh/main_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_MODULE_ECDH_MAIN_\n#define _SECP256K1_MODULE_ECDH_MAIN_\n\n#include \"include/secp256k1_ecdh.h\"\n#include \"ecmult_const_impl.h\"\n\nint secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {\n    int ret = 0;\n    int overflow = 0;\n    secp256k1_gej res;\n    secp256k1_ge pt;\n    secp256k1_scalar s;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(result != NULL);\n    ARG_CHECK(point != NULL);\n    ARG_CHECK(scalar != NULL);\n\n    secp256k1_pubkey_load(ctx, &pt, point);\n    secp256k1_scalar_set_b32(&s, scalar, &overflow);\n    if (overflow || secp256k1_scalar_is_zero(&s)) {\n        ret = 0;\n    } else {\n        unsigned char x[32];\n        unsigned char y[1];\n        secp256k1_sha256_t sha;\n\n        secp256k1_ecmult_const(&res, &pt, &s);\n        secp256k1_ge_set_gej(&pt, &res);\n        /* Compute a hash of the point in compressed form\n         * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not\n         * expect its output to be secret and has a timing sidechannel. */\n        secp256k1_fe_normalize(&pt.x);\n        secp256k1_fe_normalize(&pt.y);\n        secp256k1_fe_get_b32(x, &pt.x);\n        y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);\n\n        secp256k1_sha256_initialize(&sha);\n        secp256k1_sha256_write(&sha, y, sizeof(y));\n        secp256k1_sha256_write(&sha, x, sizeof(x));\n        secp256k1_sha256_finalize(&sha, result);\n        ret = 1;\n    }\n\n    secp256k1_scalar_clear(&s);\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/modules/ecdh/tests_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_MODULE_ECDH_TESTS_\n#define _SECP256K1_MODULE_ECDH_TESTS_\n\nvoid test_ecdh_api(void) {\n    /* Setup context that just counts errors */\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n    secp256k1_pubkey point;\n    unsigned char res[32];\n    unsigned char s_one[32] = { 0 };\n    int32_t ecount = 0;\n    s_one[31] = 1;\n\n    secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);\n    CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);\n\n    /* Check all NULLs are detected */\n    CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);\n    CHECK(ecount == 0);\n    CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);\n    CHECK(ecount == 3);\n\n    /* Cleanup */\n    secp256k1_context_destroy(tctx);\n}\n\nvoid test_ecdh_generator_basepoint(void) {\n    unsigned char s_one[32] = { 0 };\n    secp256k1_pubkey point[2];\n    int i;\n\n    s_one[31] = 1;\n    /* Check against pubkey creation when the basepoint is the generator */\n    for (i = 0; i < 100; ++i) {\n        secp256k1_sha256_t sha;\n        unsigned char s_b32[32];\n        unsigned char output_ecdh[32];\n        unsigned char output_ser[32];\n        unsigned char point_ser[33];\n        size_t point_ser_len = sizeof(point_ser);\n        secp256k1_scalar s;\n\n        random_scalar_order(&s);\n        secp256k1_scalar_get_b32(s_b32, &s);\n\n        /* compute using ECDH function */\n        CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);\n        CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);\n        /* compute \"explicitly\" */\n        CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);\n        CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);\n        CHECK(point_ser_len == sizeof(point_ser));\n        secp256k1_sha256_initialize(&sha);\n        secp256k1_sha256_write(&sha, point_ser, point_ser_len);\n        secp256k1_sha256_finalize(&sha, output_ser);\n        /* compare */\n        CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);\n    }\n}\n\nvoid test_bad_scalar(void) {\n    unsigned char s_zero[32] = { 0 };\n    unsigned char s_overflow[32] = {\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n        0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n        0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41\n    };\n    unsigned char s_rand[32] = { 0 };\n    unsigned char output[32];\n    secp256k1_scalar rand;\n    secp256k1_pubkey point;\n\n    /* Create random point */\n    random_scalar_order(&rand);\n    secp256k1_scalar_get_b32(s_rand, &rand);\n    CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);\n\n    /* Try to multiply it by bad values */\n    CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);\n    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);\n    /* ...and a good one */\n    s_overflow[31] -= 1;\n    CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);\n}\n\nvoid run_ecdh_tests(void) {\n    test_ecdh_api();\n    test_ecdh_generator_basepoint();\n    test_bad_scalar();\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/modules/recovery/Makefile.am.include",
    "content": "include_HEADERS += include/secp256k1_recovery.h\nnoinst_HEADERS += src/modules/recovery/main_impl.h\nnoinst_HEADERS += src/modules/recovery/tests_impl.h\nif USE_BENCHMARK\nnoinst_PROGRAMS += bench_recover\nbench_recover_SOURCES = src/bench_recover.c\nbench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)\nendif\n"
  },
  {
    "path": "src/secp256k1/src/modules/recovery/main_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_\n#define _SECP256K1_MODULE_RECOVERY_MAIN_\n\n#include \"include/secp256k1_recovery.h\"\n\nstatic void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) {\n    (void)ctx;\n    if (sizeof(secp256k1_scalar) == 32) {\n        /* When the secp256k1_scalar type is exactly 32 byte, use its\n         * representation inside secp256k1_ecdsa_signature, as conversion is very fast.\n         * Note that secp256k1_ecdsa_signature_save must use the same representation. */\n        memcpy(r, &sig->data[0], 32);\n        memcpy(s, &sig->data[32], 32);\n    } else {\n        secp256k1_scalar_set_b32(r, &sig->data[0], NULL);\n        secp256k1_scalar_set_b32(s, &sig->data[32], NULL);\n    }\n    *recid = sig->data[64];\n}\n\nstatic void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) {\n    if (sizeof(secp256k1_scalar) == 32) {\n        memcpy(&sig->data[0], r, 32);\n        memcpy(&sig->data[32], s, 32);\n    } else {\n        secp256k1_scalar_get_b32(&sig->data[0], r);\n        secp256k1_scalar_get_b32(&sig->data[32], s);\n    }\n    sig->data[64] = recid;\n}\n\nint secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) {\n    secp256k1_scalar r, s;\n    int ret = 1;\n    int overflow = 0;\n\n    (void)ctx;\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(input64 != NULL);\n    ARG_CHECK(recid >= 0 && recid <= 3);\n\n    secp256k1_scalar_set_b32(&r, &input64[0], &overflow);\n    ret &= !overflow;\n    secp256k1_scalar_set_b32(&s, &input64[32], &overflow);\n    ret &= !overflow;\n    if (ret) {\n        secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid);\n    } else {\n        memset(sig, 0, sizeof(*sig));\n    }\n    return ret;\n}\n\nint secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) {\n    secp256k1_scalar r, s;\n\n    (void)ctx;\n    ARG_CHECK(output64 != NULL);\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(recid != NULL);\n\n    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);\n    secp256k1_scalar_get_b32(&output64[0], &r);\n    secp256k1_scalar_get_b32(&output64[32], &s);\n    return 1;\n}\n\nint secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) {\n    secp256k1_scalar r, s;\n    int recid;\n\n    (void)ctx;\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(sigin != NULL);\n\n    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin);\n    secp256k1_ecdsa_signature_save(sig, &r, &s);\n    return 1;\n}\n\nstatic int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {\n    unsigned char brx[32];\n    secp256k1_fe fx;\n    secp256k1_ge x;\n    secp256k1_gej xj;\n    secp256k1_scalar rn, u1, u2;\n    secp256k1_gej qj;\n    int r;\n\n    if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {\n        return 0;\n    }\n\n    secp256k1_scalar_get_b32(brx, sigr);\n    r = secp256k1_fe_set_b32(&fx, brx);\n    (void)r;\n    VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */\n    if (recid & 2) {\n        if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {\n            return 0;\n        }\n        secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);\n    }\n    if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {\n        return 0;\n    }\n    secp256k1_gej_set_ge(&xj, &x);\n    secp256k1_scalar_inverse_var(&rn, sigr);\n    secp256k1_scalar_mul(&u1, &rn, message);\n    secp256k1_scalar_negate(&u1, &u1);\n    secp256k1_scalar_mul(&u2, &rn, sigs);\n    secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);\n    secp256k1_ge_set_gej_var(pubkey, &qj);\n    return !secp256k1_gej_is_infinity(&qj);\n}\n\nint secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {\n    secp256k1_scalar r, s;\n    secp256k1_scalar sec, non, msg;\n    int recid;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));\n    ARG_CHECK(msg32 != NULL);\n    ARG_CHECK(signature != NULL);\n    ARG_CHECK(seckey != NULL);\n    if (noncefp == NULL) {\n        noncefp = secp256k1_nonce_function_default;\n    }\n\n    secp256k1_scalar_set_b32(&sec, seckey, &overflow);\n    /* Fail if the secret key is invalid. */\n    if (!overflow && !secp256k1_scalar_is_zero(&sec)) {\n        unsigned char nonce32[32];\n        unsigned int count = 0;\n        secp256k1_scalar_set_b32(&msg, msg32, NULL);\n        while (1) {\n            ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);\n            if (!ret) {\n                break;\n            }\n            secp256k1_scalar_set_b32(&non, nonce32, &overflow);\n            if (!secp256k1_scalar_is_zero(&non) && !overflow) {\n                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {\n                    break;\n                }\n            }\n            count++;\n        }\n        memset(nonce32, 0, 32);\n        secp256k1_scalar_clear(&msg);\n        secp256k1_scalar_clear(&non);\n        secp256k1_scalar_clear(&sec);\n    }\n    if (ret) {\n        secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);\n    } else {\n        memset(signature, 0, sizeof(*signature));\n    }\n    return ret;\n}\n\nint secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) {\n    secp256k1_ge q;\n    secp256k1_scalar r, s;\n    secp256k1_scalar m;\n    int recid;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));\n    ARG_CHECK(msg32 != NULL);\n    ARG_CHECK(signature != NULL);\n    ARG_CHECK(pubkey != NULL);\n\n    secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);\n    VERIFY_CHECK(recid >= 0 && recid < 4);  /* should have been caught in parse_compact */\n    secp256k1_scalar_set_b32(&m, msg32, NULL);\n    if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {\n        secp256k1_pubkey_save(pubkey, &q);\n        return 1;\n    } else {\n        memset(pubkey, 0, sizeof(*pubkey));\n        return 0;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/modules/recovery/tests_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_\n#define _SECP256K1_MODULE_RECOVERY_TESTS_\n\nstatic int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {\n    (void) msg32;\n    (void) key32;\n    (void) algo16;\n    (void) data;\n\n    /* On the first run, return 0 to force a second run */\n    if (counter == 0) {\n        memset(nonce32, 0, 32);\n        return 1;\n    }\n    /* On the second run, return an overflow to force a third run */\n    if (counter == 1) {\n        memset(nonce32, 0xff, 32);\n        return 1;\n    }\n    /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */\n    memset(nonce32, 1, 32);\n    return secp256k1_rand_bits(1);\n}\n\nvoid test_ecdsa_recovery_api(void) {\n    /* Setup contexts that just count errors */\n    secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n    secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);\n    secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n    secp256k1_pubkey pubkey;\n    secp256k1_pubkey recpubkey;\n    secp256k1_ecdsa_signature normal_sig;\n    secp256k1_ecdsa_recoverable_signature recsig;\n    unsigned char privkey[32] = { 1 };\n    unsigned char message[32] = { 2 };\n    int32_t ecount = 0;\n    int recid = 0;\n    unsigned char sig[74];\n    unsigned char zero_privkey[32] = { 0 };\n    unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };\n\n    secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);\n\n    /* Construct and verify corresponding public key. */\n    CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);\n\n    /* Check bad contexts and NULLs for signing */\n    ecount = 0;\n    CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);\n    CHECK(ecount == 4);\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);\n    CHECK(ecount == 5);\n    /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */\n    secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);\n    CHECK(ecount == 5);\n    /* These will all fail, but not in ARG_CHECK way */\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);\n    /* This one will succeed. */\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);\n    CHECK(ecount == 5);\n\n    /* Check signing with a goofy nonce function */\n\n    /* Check bad contexts and NULLs for recovery */\n    ecount = 0;\n    CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);\n    CHECK(ecount == 4);\n    CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);\n    CHECK(ecount == 5);\n\n    /* Check NULLs for conversion */\n    CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);\n    ecount = 0;\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);\n\n    /* Check NULLs for de/serialization */\n    CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);\n    ecount = 0;\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);\n\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);\n    CHECK(ecount == 4);\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);\n    CHECK(ecount == 5);\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);\n    CHECK(ecount == 6);\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);\n    CHECK(ecount == 7);\n    /* overflow in signature will fail but not affect ecount */\n    memcpy(sig, over_privkey, 32);\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);\n    CHECK(ecount == 7);\n\n    /* cleanup */\n    secp256k1_context_destroy(none);\n    secp256k1_context_destroy(sign);\n    secp256k1_context_destroy(vrfy);\n    secp256k1_context_destroy(both);\n}\n\nvoid test_ecdsa_recovery_end_to_end(void) {\n    unsigned char extra[32] = {0x00};\n    unsigned char privkey[32];\n    unsigned char message[32];\n    secp256k1_ecdsa_signature signature[5];\n    secp256k1_ecdsa_recoverable_signature rsignature[5];\n    unsigned char sig[74];\n    secp256k1_pubkey pubkey;\n    secp256k1_pubkey recpubkey;\n    int recid = 0;\n\n    /* Generate a random key and message. */\n    {\n        secp256k1_scalar msg, key;\n        random_scalar_order_test(&msg);\n        random_scalar_order_test(&key);\n        secp256k1_scalar_get_b32(privkey, &key);\n        secp256k1_scalar_get_b32(message, &msg);\n    }\n\n    /* Construct and verify corresponding public key. */\n    CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);\n\n    /* Serialize/parse compact and verify/recover. */\n    extra[0] = 0;\n    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);\n    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);\n    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);\n    extra[31] = 1;\n    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);\n    extra[31] = 0;\n    extra[0] = 1;\n    CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);\n    CHECK(memcmp(&signature[4], &signature[0], 64) == 0);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);\n    memset(&rsignature[4], 0, sizeof(rsignature[4]));\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);\n    /* Parse compact (with recovery id) and recover. */\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);\n    CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);\n    CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);\n    /* Serialize/destroy/parse signature and verify again. */\n    CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);\n    sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);\n    CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);\n    /* Recover again */\n    CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||\n          memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);\n}\n\n/* Tests several edge cases. */\nvoid test_ecdsa_recovery_edge_cases(void) {\n    const unsigned char msg32[32] = {\n        'T', 'h', 'i', 's', ' ', 'i', 's', ' ',\n        'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',\n        'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',\n        's', 's', 'a', 'g', 'e', '.', '.', '.'\n    };\n    const unsigned char sig64[64] = {\n        /* Generated by signing the above message with nonce 'This is the nonce we will use...'\n         * and secret key 0 (which is not valid), resulting in recid 0. */\n        0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,\n        0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,\n        0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,\n        0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,\n        0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,\n        0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,\n        0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,\n        0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57\n    };\n    secp256k1_pubkey pubkey;\n    /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */\n    const unsigned char sigb64[64] = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n    };\n    secp256k1_pubkey pubkeyb;\n    secp256k1_ecdsa_recoverable_signature rsig;\n    secp256k1_ecdsa_signature sig;\n    int recid;\n\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));\n    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));\n    CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));\n    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));\n    CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));\n    CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));\n\n    for (recid = 0; recid < 4; recid++) {\n        int i;\n        int recid2;\n        /* (4,4) encoded in DER. */\n        unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};\n        unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};\n        unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};\n        unsigned char sigbderalt1[39] = {\n            0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,\n        };\n        unsigned char sigbderalt2[39] = {\n            0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n        };\n        unsigned char sigbderalt3[40] = {\n            0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,\n        };\n        unsigned char sigbderalt4[40] = {\n            0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n        };\n        /* (order + r,4) encoded in DER. */\n        unsigned char sigbderlong[40] = {\n            0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,\n            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n            0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,\n            0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,\n            0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04\n        };\n        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);\n        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);\n        for (recid2 = 0; recid2 < 4; recid2++) {\n            secp256k1_pubkey pubkey2b;\n            CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);\n            CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);\n            /* Verifying with (order + r,4) should always fail. */\n            CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);\n            CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);\n        }\n        /* DER parsing tests. */\n        /* Zero length r/s. */\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);\n        /* Leading zeros. */\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);\n        sigbderalt3[4] = 1;\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);\n        sigbderalt4[7] = 1;\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);\n        /* Damage signature. */\n        sigbder[7]++;\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);\n        sigbder[7]--;\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);\n        for(i = 0; i < 8; i++) {\n            int c;\n            unsigned char orig = sigbder[i];\n            /*Try every single-byte change.*/\n            for (c = 0; c < 256; c++) {\n                if (c == orig ) {\n                    continue;\n                }\n                sigbder[i] = c;\n                CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);\n            }\n            sigbder[i] = orig;\n        }\n    }\n\n    /* Test r/s equal to zero */\n    {\n        /* (1,1) encoded in DER. */\n        unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};\n        unsigned char sigc64[64] = {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        };\n        secp256k1_pubkey pubkeyc;\n        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);\n        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);\n        sigcder[4] = 0;\n        sigc64[31] = 0;\n        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);\n        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);\n        sigcder[4] = 1;\n        sigcder[7] = 0;\n        sigc64[31] = 1;\n        sigc64[63] = 0;\n        CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);\n        CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);\n    }\n}\n\nvoid run_recovery_tests(void) {\n    int i;\n    for (i = 0; i < count; i++) {\n        test_ecdsa_recovery_api();\n    }\n    for (i = 0; i < 64*count; i++) {\n        test_ecdsa_recovery_end_to_end();\n    }\n    test_ecdsa_recovery_edge_cases();\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/num.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_NUM_\n#define _SECP256K1_NUM_\n\n#ifndef USE_NUM_NONE\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#if defined(USE_NUM_GMP)\n#include \"num_gmp.h\"\n#else\n#error \"Please select num implementation\"\n#endif\n\n/** Copy a number. */\nstatic void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a);\n\n/** Convert a number's absolute value to a binary big-endian string.\n *  There must be enough place. */\nstatic void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a);\n\n/** Set a number to the value of a binary big-endian string. */\nstatic void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen);\n\n/** Compute a modular inverse. The input must be less than the modulus. */\nstatic void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);\n\n/** Compute the jacobi symbol (a|b). b must be positive and odd. */\nstatic int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);\n\n/** Compare the absolute value of two numbers. */\nstatic int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);\n\n/** Test whether two number are equal (including sign). */\nstatic int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b);\n\n/** Add two (signed) numbers. */\nstatic void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);\n\n/** Subtract two (signed) numbers. */\nstatic void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);\n\n/** Multiply two (signed) numbers. */\nstatic void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);\n\n/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,\n    even if r was negative. */\nstatic void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m);\n\n/** Right-shift the passed number by bits bits. */\nstatic void secp256k1_num_shift(secp256k1_num *r, int bits);\n\n/** Check whether a number is zero. */\nstatic int secp256k1_num_is_zero(const secp256k1_num *a);\n\n/** Check whether a number is one. */\nstatic int secp256k1_num_is_one(const secp256k1_num *a);\n\n/** Check whether a number is strictly negative. */\nstatic int secp256k1_num_is_neg(const secp256k1_num *a);\n\n/** Change a number's sign. */\nstatic void secp256k1_num_negate(secp256k1_num *r);\n\n#endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/num_gmp.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_NUM_REPR_\n#define _SECP256K1_NUM_REPR_\n\n#include <gmp.h>\n\n#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS)\n\ntypedef struct {\n    mp_limb_t data[2*NUM_LIMBS];\n    int neg;\n    int limbs;\n} secp256k1_num;\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/num_gmp_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_NUM_REPR_IMPL_H_\n#define _SECP256K1_NUM_REPR_IMPL_H_\n\n#include <string.h>\n#include <stdlib.h>\n#include <gmp.h>\n\n#include \"util.h\"\n#include \"num.h\"\n\n#ifdef VERIFY\nstatic void secp256k1_num_sanity(const secp256k1_num *a) {\n    VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));\n}\n#else\n#define secp256k1_num_sanity(a) do { } while(0)\n#endif\n\nstatic void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) {\n    *r = *a;\n}\n\nstatic void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) {\n    unsigned char tmp[65];\n    int len = 0;\n    int shift = 0;\n    if (a->limbs>1 || a->data[0] != 0) {\n        len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);\n    }\n    while (shift < len && tmp[shift] == 0) shift++;\n    VERIFY_CHECK(len-shift <= (int)rlen);\n    memset(r, 0, rlen - len + shift);\n    if (len > shift) {\n        memcpy(r + rlen - len + shift, tmp + shift, len - shift);\n    }\n    memset(tmp, 0, sizeof(tmp));\n}\n\nstatic void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) {\n    int len;\n    VERIFY_CHECK(alen > 0);\n    VERIFY_CHECK(alen <= 64);\n    len = mpn_set_str(r->data, a, alen, 256);\n    if (len == 0) {\n        r->data[0] = 0;\n        len = 1;\n    }\n    VERIFY_CHECK(len <= NUM_LIMBS*2);\n    r->limbs = len;\n    r->neg = 0;\n    while (r->limbs > 1 && r->data[r->limbs-1]==0) {\n        r->limbs--;\n    }\n}\n\nstatic void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {\n    mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);\n    r->limbs = a->limbs;\n    if (c != 0) {\n        VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);\n        r->data[r->limbs++] = c;\n    }\n}\n\nstatic void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {\n    mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);\n    (void)c;\n    VERIFY_CHECK(c == 0);\n    r->limbs = a->limbs;\n    while (r->limbs > 1 && r->data[r->limbs-1]==0) {\n        r->limbs--;\n    }\n}\n\nstatic void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) {\n    secp256k1_num_sanity(r);\n    secp256k1_num_sanity(m);\n\n    if (r->limbs >= m->limbs) {\n        mp_limb_t t[2*NUM_LIMBS];\n        mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);\n        memset(t, 0, sizeof(t));\n        r->limbs = m->limbs;\n        while (r->limbs > 1 && r->data[r->limbs-1]==0) {\n            r->limbs--;\n        }\n    }\n\n    if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {\n        secp256k1_num_sub_abs(r, m, r);\n        r->neg = 0;\n    }\n}\n\nstatic void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) {\n    int i;\n    mp_limb_t g[NUM_LIMBS+1];\n    mp_limb_t u[NUM_LIMBS+1];\n    mp_limb_t v[NUM_LIMBS+1];\n    mp_size_t sn;\n    mp_size_t gn;\n    secp256k1_num_sanity(a);\n    secp256k1_num_sanity(m);\n\n    /** mpn_gcdext computes: (G,S) = gcdext(U,V), where\n     *  * G = gcd(U,V)\n     *  * G = U*S + V*T\n     *  * U has equal or more limbs than V, and V has no padding\n     *  If we set U to be (a padded version of) a, and V = m:\n     *    G = a*S + m*T\n     *    G = a*S mod m\n     *  Assuming G=1:\n     *    S = 1/a mod m\n     */\n    VERIFY_CHECK(m->limbs <= NUM_LIMBS);\n    VERIFY_CHECK(m->data[m->limbs-1] != 0);\n    for (i = 0; i < m->limbs; i++) {\n        u[i] = (i < a->limbs) ? a->data[i] : 0;\n        v[i] = m->data[i];\n    }\n    sn = NUM_LIMBS+1;\n    gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);\n    (void)gn;\n    VERIFY_CHECK(gn == 1);\n    VERIFY_CHECK(g[0] == 1);\n    r->neg = a->neg ^ m->neg;\n    if (sn < 0) {\n        mpn_sub(r->data, m->data, m->limbs, r->data, -sn);\n        r->limbs = m->limbs;\n        while (r->limbs > 1 && r->data[r->limbs-1]==0) {\n            r->limbs--;\n        }\n    } else {\n        r->limbs = sn;\n    }\n    memset(g, 0, sizeof(g));\n    memset(u, 0, sizeof(u));\n    memset(v, 0, sizeof(v));\n}\n\nstatic int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {\n    int ret;\n    mpz_t ga, gb;\n    secp256k1_num_sanity(a);\n    secp256k1_num_sanity(b);\n    VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));\n\n    mpz_inits(ga, gb, NULL);\n\n    mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);\n    mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);\n    if (a->neg) {\n        mpz_neg(ga, ga);\n    }\n\n    ret = mpz_jacobi(ga, gb);\n\n    mpz_clears(ga, gb, NULL);\n\n    return ret;\n}\n\nstatic int secp256k1_num_is_one(const secp256k1_num *a) {\n    return (a->limbs == 1 && a->data[0] == 1);\n}\n\nstatic int secp256k1_num_is_zero(const secp256k1_num *a) {\n    return (a->limbs == 1 && a->data[0] == 0);\n}\n\nstatic int secp256k1_num_is_neg(const secp256k1_num *a) {\n    return (a->limbs > 1 || a->data[0] != 0) && a->neg;\n}\n\nstatic int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) {\n    if (a->limbs > b->limbs) {\n        return 1;\n    }\n    if (a->limbs < b->limbs) {\n        return -1;\n    }\n    return mpn_cmp(a->data, b->data, a->limbs);\n}\n\nstatic int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) {\n    if (a->limbs > b->limbs) {\n        return 0;\n    }\n    if (a->limbs < b->limbs) {\n        return 0;\n    }\n    if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) {\n        return 0;\n    }\n    return mpn_cmp(a->data, b->data, a->limbs) == 0;\n}\n\nstatic void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) {\n    if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */\n        r->neg = a->neg;\n        if (a->limbs >= b->limbs) {\n            secp256k1_num_add_abs(r, a, b);\n        } else {\n            secp256k1_num_add_abs(r, b, a);\n        }\n    } else {\n        if (secp256k1_num_cmp(a, b) > 0) {\n            r->neg = a->neg;\n            secp256k1_num_sub_abs(r, a, b);\n        } else {\n            r->neg = b->neg ^ bneg;\n            secp256k1_num_sub_abs(r, b, a);\n        }\n    }\n}\n\nstatic void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {\n    secp256k1_num_sanity(a);\n    secp256k1_num_sanity(b);\n    secp256k1_num_subadd(r, a, b, 0);\n}\n\nstatic void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {\n    secp256k1_num_sanity(a);\n    secp256k1_num_sanity(b);\n    secp256k1_num_subadd(r, a, b, 1);\n}\n\nstatic void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {\n    mp_limb_t tmp[2*NUM_LIMBS+1];\n    secp256k1_num_sanity(a);\n    secp256k1_num_sanity(b);\n\n    VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);\n    if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {\n        r->limbs = 1;\n        r->neg = 0;\n        r->data[0] = 0;\n        return;\n    }\n    if (a->limbs >= b->limbs) {\n        mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);\n    } else {\n        mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);\n    }\n    r->limbs = a->limbs + b->limbs;\n    if (r->limbs > 1 && tmp[r->limbs - 1]==0) {\n        r->limbs--;\n    }\n    VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS);\n    mpn_copyi(r->data, tmp, r->limbs);\n    r->neg = a->neg ^ b->neg;\n    memset(tmp, 0, sizeof(tmp));\n}\n\nstatic void secp256k1_num_shift(secp256k1_num *r, int bits) {\n    if (bits % GMP_NUMB_BITS) {\n        /* Shift within limbs. */\n        mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);\n    }\n    if (bits >= GMP_NUMB_BITS) {\n        int i;\n        /* Shift full limbs. */\n        for (i = 0; i < r->limbs; i++) {\n            int index = i + (bits / GMP_NUMB_BITS);\n            if (index < r->limbs && index < 2*NUM_LIMBS) {\n                r->data[i] = r->data[index];\n            } else {\n                r->data[i] = 0;\n            }\n        }\n    }\n    while (r->limbs>1 && r->data[r->limbs-1]==0) {\n        r->limbs--;\n    }\n}\n\nstatic void secp256k1_num_negate(secp256k1_num *r) {\n    r->neg ^= 1;\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/num_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_NUM_IMPL_H_\n#define _SECP256K1_NUM_IMPL_H_\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include \"num.h\"\n\n#if defined(USE_NUM_GMP)\n#include \"num_gmp_impl.h\"\n#elif defined(USE_NUM_NONE)\n/* Nothing. */\n#else\n#error \"Please select num implementation\"\n#endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_\n#define _SECP256K1_SCALAR_\n\n#include \"num.h\"\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#if defined(EXHAUSTIVE_TEST_ORDER)\n#include \"scalar_low.h\"\n#elif defined(USE_SCALAR_4X64)\n#include \"scalar_4x64.h\"\n#elif defined(USE_SCALAR_8X32)\n#include \"scalar_8x32.h\"\n#else\n#error \"Please select scalar implementation\"\n#endif\n\n/** Clear a scalar to prevent the leak of sensitive data. */\nstatic void secp256k1_scalar_clear(secp256k1_scalar *r);\n\n/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */\nstatic unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count);\n\n/** Access bits from a scalar. Not constant time. */\nstatic unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);\n\n/** Set a scalar from a big endian byte array. */\nstatic void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow);\n\n/** Set a scalar to an unsigned integer. */\nstatic void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v);\n\n/** Convert a scalar to a byte array. */\nstatic void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a);\n\n/** Add two scalars together (modulo the group order). Returns whether it overflowed. */\nstatic int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);\n\n/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */\nstatic void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag);\n\n/** Multiply two scalars (modulo the group order). */\nstatic void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);\n\n/** Shift a scalar right by some amount strictly between 0 and 16, returning\n *  the low bits that were shifted off */\nstatic int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);\n\n/** Compute the square of a scalar (modulo the group order). */\nstatic void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a);\n\n/** Compute the inverse of a scalar (modulo the group order). */\nstatic void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);\n\n/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */\nstatic void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a);\n\n/** Compute the complement of a scalar (modulo the group order). */\nstatic void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a);\n\n/** Check whether a scalar equals zero. */\nstatic int secp256k1_scalar_is_zero(const secp256k1_scalar *a);\n\n/** Check whether a scalar equals one. */\nstatic int secp256k1_scalar_is_one(const secp256k1_scalar *a);\n\n/** Check whether a scalar, considered as an nonnegative integer, is even. */\nstatic int secp256k1_scalar_is_even(const secp256k1_scalar *a);\n\n/** Check whether a scalar is higher than the group order divided by 2. */\nstatic int secp256k1_scalar_is_high(const secp256k1_scalar *a);\n\n/** Conditionally negate a number, in constant time.\n * Returns -1 if the number was negated, 1 otherwise */\nstatic int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag);\n\n#ifndef USE_NUM_NONE\n/** Convert a scalar to a number. */\nstatic void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a);\n\n/** Get the order of the group as a number. */\nstatic void secp256k1_scalar_order_get_num(secp256k1_num *r);\n#endif\n\n/** Compare two scalars. */\nstatic int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b);\n\n#ifdef USE_ENDOMORPHISM\n/** Find r1 and r2 such that r1+r2*2^128 = a. */\nstatic void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);\n/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */\nstatic void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a);\n#endif\n\n/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */\nstatic void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_4x64.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_\n#define _SECP256K1_SCALAR_REPR_\n\n#include <stdint.h>\n\n/** A scalar modulo the group order of the secp256k1 curve. */\ntypedef struct {\n    uint64_t d[4];\n} secp256k1_scalar;\n\n#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_4x64_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_\n#define _SECP256K1_SCALAR_REPR_IMPL_H_\n\n/* Limbs of the secp256k1 order. */\n#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)\n#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL)\n#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL)\n#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)\n\n/* Limbs of 2^256 minus the secp256k1 order. */\n#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1)\n#define SECP256K1_N_C_1 (~SECP256K1_N_1)\n#define SECP256K1_N_C_2 (1)\n\n/* Limbs of half the secp256k1 order. */\n#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL)\n#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL)\n#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL)\n#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL)\n\nSECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {\n    r->d[0] = 0;\n    r->d[1] = 0;\n    r->d[2] = 0;\n    r->d[3] = 0;\n}\n\nSECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {\n    r->d[0] = v;\n    r->d[1] = 0;\n    r->d[2] = 0;\n    r->d[3] = 0;\n}\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);\n    return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);\n}\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    VERIFY_CHECK(count < 32);\n    VERIFY_CHECK(offset + count <= 256);\n    if ((offset + count - 1) >> 6 == offset >> 6) {\n        return secp256k1_scalar_get_bits(a, offset, count);\n    } else {\n        VERIFY_CHECK((offset >> 6) + 1 < 4);\n        return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1);\n    }\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) {\n    int yes = 0;\n    int no = 0;\n    no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */\n    no |= (a->d[2] < SECP256K1_N_2);\n    yes |= (a->d[2] > SECP256K1_N_2) & ~no;\n    no |= (a->d[1] < SECP256K1_N_1);\n    yes |= (a->d[1] > SECP256K1_N_1) & ~no;\n    yes |= (a->d[0] >= SECP256K1_N_0) & ~no;\n    return yes;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) {\n    uint128_t t;\n    VERIFY_CHECK(overflow <= 1);\n    t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;\n    r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1;\n    r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2;\n    r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint64_t)r->d[3];\n    r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;\n    return overflow;\n}\n\nstatic int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    int overflow;\n    uint128_t t = (uint128_t)a->d[0] + b->d[0];\n    r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)a->d[1] + b->d[1];\n    r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)a->d[2] + b->d[2];\n    r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)a->d[3] + b->d[3];\n    r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    overflow = t + secp256k1_scalar_check_overflow(r);\n    VERIFY_CHECK(overflow == 0 || overflow == 1);\n    secp256k1_scalar_reduce(r, overflow);\n    return overflow;\n}\n\nstatic void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {\n    uint128_t t;\n    VERIFY_CHECK(bit < 256);\n    bit += ((uint32_t) flag - 1) & 0x100;  /* forcing (bit >> 6) > 3 makes this a noop */\n    t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));\n    r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));\n    r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));\n    r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;\n    t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));\n    r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;\n#ifdef VERIFY\n    VERIFY_CHECK((t >> 64) == 0);\n    VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);\n#endif\n}\n\nstatic void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {\n    int over;\n    r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;\n    r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;\n    r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56;\n    r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56;\n    over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));\n    if (overflow) {\n        *overflow = over;\n    }\n}\n\nstatic void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {\n    bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3];\n    bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2];\n    bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1];\n    bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {\n    return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0;\n}\n\nstatic void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);\n    uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1;\n    r->d[0] = t & nonzero; t >>= 64;\n    t += (uint128_t)(~a->d[1]) + SECP256K1_N_1;\n    r->d[1] = t & nonzero; t >>= 64;\n    t += (uint128_t)(~a->d[2]) + SECP256K1_N_2;\n    r->d[2] = t & nonzero; t >>= 64;\n    t += (uint128_t)(~a->d[3]) + SECP256K1_N_3;\n    r->d[3] = t & nonzero;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {\n    return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0;\n}\n\nstatic int secp256k1_scalar_is_high(const secp256k1_scalar *a) {\n    int yes = 0;\n    int no = 0;\n    no |= (a->d[3] < SECP256K1_N_H_3);\n    yes |= (a->d[3] > SECP256K1_N_H_3) & ~no;\n    no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */\n    no |= (a->d[1] < SECP256K1_N_H_1) & ~yes;\n    yes |= (a->d[1] > SECP256K1_N_H_1) & ~no;\n    yes |= (a->d[0] > SECP256K1_N_H_0) & ~no;\n    return yes;\n}\n\nstatic int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {\n    /* If we are flag = 0, mask = 00...00 and this is a no-op;\n     * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */\n    uint64_t mask = !flag - 1;\n    uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;\n    uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);\n    r->d[0] = t & nonzero; t >>= 64;\n    t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);\n    r->d[1] = t & nonzero; t >>= 64;\n    t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);\n    r->d[2] = t & nonzero; t >>= 64;\n    t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);\n    r->d[3] = t & nonzero;\n    return 2 * (mask == 0) - 1;\n}\n\n/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */\n\n/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define muladd(a,b) { \\\n    uint64_t tl, th; \\\n    { \\\n        uint128_t t = (uint128_t)a * b; \\\n        th = t >> 64;         /* at most 0xFFFFFFFFFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    c0 += tl;                 /* overflow is handled on the next line */ \\\n    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFFFFFFFFFF */ \\\n    c1 += th;                 /* overflow is handled on the next line */ \\\n    c2 += (c1 < th) ? 1 : 0;  /* never overflows by contract (verified in the next line) */ \\\n    VERIFY_CHECK((c1 >= th) || (c2 != 0)); \\\n}\n\n/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */\n#define muladd_fast(a,b) { \\\n    uint64_t tl, th; \\\n    { \\\n        uint128_t t = (uint128_t)a * b; \\\n        th = t >> 64;         /* at most 0xFFFFFFFFFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    c0 += tl;                 /* overflow is handled on the next line */ \\\n    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFFFFFFFFFF */ \\\n    c1 += th;                 /* never overflows by contract (verified in the next line) */ \\\n    VERIFY_CHECK(c1 >= th); \\\n}\n\n/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define muladd2(a,b) { \\\n    uint64_t tl, th, th2, tl2; \\\n    { \\\n        uint128_t t = (uint128_t)a * b; \\\n        th = t >> 64;               /* at most 0xFFFFFFFFFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    th2 = th + th;                  /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \\\n    c2 += (th2 < th) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((th2 >= th) || (c2 != 0)); \\\n    tl2 = tl + tl;                  /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \\\n    th2 += (tl2 < tl) ? 1 : 0;      /* at most 0xFFFFFFFFFFFFFFFF */ \\\n    c0 += tl2;                      /* overflow is handled on the next line */ \\\n    th2 += (c0 < tl2) ? 1 : 0;      /* second overflow is handled on the next line */ \\\n    c2 += (c0 < tl2) & (th2 == 0);  /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \\\n    c1 += th2;                      /* overflow is handled on the next line */ \\\n    c2 += (c1 < th2) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \\\n}\n\n/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define sumadd(a) { \\\n    unsigned int over; \\\n    c0 += (a);                  /* overflow is handled on the next line */ \\\n    over = (c0 < (a)) ? 1 : 0; \\\n    c1 += over;                 /* overflow is handled on the next line */ \\\n    c2 += (c1 < over) ? 1 : 0;  /* never overflows by contract */ \\\n}\n\n/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */\n#define sumadd_fast(a) { \\\n    c0 += (a);                 /* overflow is handled on the next line */ \\\n    c1 += (c0 < (a)) ? 1 : 0;  /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \\\n    VERIFY_CHECK(c2 == 0); \\\n}\n\n/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */\n#define extract(n) { \\\n    (n) = c0; \\\n    c0 = c1; \\\n    c1 = c2; \\\n    c2 = 0; \\\n}\n\n/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */\n#define extract_fast(n) { \\\n    (n) = c0; \\\n    c0 = c1; \\\n    c1 = 0; \\\n    VERIFY_CHECK(c2 == 0); \\\n}\n\nstatic void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) {\n#ifdef USE_ASM_X86_64\n    /* Reduce 512 bits into 385. */\n    uint64_t m0, m1, m2, m3, m4, m5, m6;\n    uint64_t p0, p1, p2, p3, p4;\n    uint64_t c;\n\n    __asm__ __volatile__(\n    /* Preload. */\n    \"movq 32(%%rsi), %%r11\\n\"\n    \"movq 40(%%rsi), %%r12\\n\"\n    \"movq 48(%%rsi), %%r13\\n\"\n    \"movq 56(%%rsi), %%r14\\n\"\n    /* Initialize r8,r9,r10 */\n    \"movq 0(%%rsi), %%r8\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9) += n0 * c0 */\n    \"movq %8, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    /* extract m0 */\n    \"movq %%r8, %q0\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10) += l1 */\n    \"addq 8(%%rsi), %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r9,r10,r8) += n1 * c0 */\n    \"movq %8, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += n0 * c1 */\n    \"movq %9, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* extract m1 */\n    \"movq %%r9, %q1\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r10,r8,r9) += l2 */\n    \"addq 16(%%rsi), %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += n2 * c0 */\n    \"movq %8, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += n1 * c1 */\n    \"movq %9, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += n0 */\n    \"addq %%r11, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* extract m2 */\n    \"movq %%r10, %q2\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9,r10) += l3 */\n    \"addq 24(%%rsi), %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += n3 * c0 */\n    \"movq %8, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += n2 * c1 */\n    \"movq %9, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += n1 */\n    \"addq %%r12, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* extract m3 */\n    \"movq %%r8, %q3\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10,r8) += n3 * c1 */\n    \"movq %9, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += n2 */\n    \"addq %%r13, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* extract m4 */\n    \"movq %%r9, %q4\\n\"\n    /* (r10,r8) += n3 */\n    \"addq %%r14, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* extract m5 */\n    \"movq %%r10, %q5\\n\"\n    /* extract m6 */\n    \"movq %%r8, %q6\\n\"\n    : \"=g\"(m0), \"=g\"(m1), \"=g\"(m2), \"=g\"(m3), \"=g\"(m4), \"=g\"(m5), \"=g\"(m6)\n    : \"S\"(l), \"n\"(SECP256K1_N_C_0), \"n\"(SECP256K1_N_C_1)\n    : \"rax\", \"rdx\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r13\", \"r14\", \"cc\");\n\n    /* Reduce 385 bits into 258. */\n    __asm__ __volatile__(\n    /* Preload */\n    \"movq %q9, %%r11\\n\"\n    \"movq %q10, %%r12\\n\"\n    \"movq %q11, %%r13\\n\"\n    /* Initialize (r8,r9,r10) */\n    \"movq %q5, %%r8\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9) += m4 * c0 */\n    \"movq %12, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    /* extract p0 */\n    \"movq %%r8, %q0\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10) += m1 */\n    \"addq %q6, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r9,r10,r8) += m5 * c0 */\n    \"movq %12, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += m4 * c1 */\n    \"movq %13, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* extract p1 */\n    \"movq %%r9, %q1\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r10,r8,r9) += m2 */\n    \"addq %q7, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += m6 * c0 */\n    \"movq %12, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += m5 * c1 */\n    \"movq %13, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += m4 */\n    \"addq %%r11, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* extract p2 */\n    \"movq %%r10, %q2\\n\"\n    /* (r8,r9) += m3 */\n    \"addq %q8, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r8,r9) += m6 * c1 */\n    \"movq %13, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    /* (r8,r9) += m5 */\n    \"addq %%r12, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* extract p3 */\n    \"movq %%r8, %q3\\n\"\n    /* (r9) += m6 */\n    \"addq %%r13, %%r9\\n\"\n    /* extract p4 */\n    \"movq %%r9, %q4\\n\"\n    : \"=&g\"(p0), \"=&g\"(p1), \"=&g\"(p2), \"=g\"(p3), \"=g\"(p4)\n    : \"g\"(m0), \"g\"(m1), \"g\"(m2), \"g\"(m3), \"g\"(m4), \"g\"(m5), \"g\"(m6), \"n\"(SECP256K1_N_C_0), \"n\"(SECP256K1_N_C_1)\n    : \"rax\", \"rdx\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r13\", \"cc\");\n\n    /* Reduce 258 bits into 256. */\n    __asm__ __volatile__(\n    /* Preload */\n    \"movq %q5, %%r10\\n\"\n    /* (rax,rdx) = p4 * c0 */\n    \"movq %7, %%rax\\n\"\n    \"mulq %%r10\\n\"\n    /* (rax,rdx) += p0 */\n    \"addq %q1, %%rax\\n\"\n    \"adcq $0, %%rdx\\n\"\n    /* extract r0 */\n    \"movq %%rax, 0(%q6)\\n\"\n    /* Move to (r8,r9) */\n    \"movq %%rdx, %%r8\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r8,r9) += p1 */\n    \"addq %q2, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r8,r9) += p4 * c1 */\n    \"movq %8, %%rax\\n\"\n    \"mulq %%r10\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    /* Extract r1 */\n    \"movq %%r8, 8(%q6)\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r8) += p4 */\n    \"addq %%r10, %%r9\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r8) += p2 */\n    \"addq %q3, %%r9\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* Extract r2 */\n    \"movq %%r9, 16(%q6)\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r8,r9) += p3 */\n    \"addq %q4, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* Extract r3 */\n    \"movq %%r8, 24(%q6)\\n\"\n    /* Extract c */\n    \"movq %%r9, %q0\\n\"\n    : \"=g\"(c)\n    : \"g\"(p0), \"g\"(p1), \"g\"(p2), \"g\"(p3), \"g\"(p4), \"D\"(r), \"n\"(SECP256K1_N_C_0), \"n\"(SECP256K1_N_C_1)\n    : \"rax\", \"rdx\", \"r8\", \"r9\", \"r10\", \"cc\", \"memory\");\n#else\n    uint128_t c;\n    uint64_t c0, c1, c2;\n    uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7];\n    uint64_t m0, m1, m2, m3, m4, m5;\n    uint32_t m6;\n    uint64_t p0, p1, p2, p3;\n    uint32_t p4;\n\n    /* Reduce 512 bits into 385. */\n    /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */\n    c0 = l[0]; c1 = 0; c2 = 0;\n    muladd_fast(n0, SECP256K1_N_C_0);\n    extract_fast(m0);\n    sumadd_fast(l[1]);\n    muladd(n1, SECP256K1_N_C_0);\n    muladd(n0, SECP256K1_N_C_1);\n    extract(m1);\n    sumadd(l[2]);\n    muladd(n2, SECP256K1_N_C_0);\n    muladd(n1, SECP256K1_N_C_1);\n    sumadd(n0);\n    extract(m2);\n    sumadd(l[3]);\n    muladd(n3, SECP256K1_N_C_0);\n    muladd(n2, SECP256K1_N_C_1);\n    sumadd(n1);\n    extract(m3);\n    muladd(n3, SECP256K1_N_C_1);\n    sumadd(n2);\n    extract(m4);\n    sumadd_fast(n3);\n    extract_fast(m5);\n    VERIFY_CHECK(c0 <= 1);\n    m6 = c0;\n\n    /* Reduce 385 bits into 258. */\n    /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */\n    c0 = m0; c1 = 0; c2 = 0;\n    muladd_fast(m4, SECP256K1_N_C_0);\n    extract_fast(p0);\n    sumadd_fast(m1);\n    muladd(m5, SECP256K1_N_C_0);\n    muladd(m4, SECP256K1_N_C_1);\n    extract(p1);\n    sumadd(m2);\n    muladd(m6, SECP256K1_N_C_0);\n    muladd(m5, SECP256K1_N_C_1);\n    sumadd(m4);\n    extract(p2);\n    sumadd_fast(m3);\n    muladd_fast(m6, SECP256K1_N_C_1);\n    sumadd_fast(m5);\n    extract_fast(p3);\n    p4 = c0 + m6;\n    VERIFY_CHECK(p4 <= 2);\n\n    /* Reduce 258 bits into 256. */\n    /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */\n    c = p0 + (uint128_t)SECP256K1_N_C_0 * p4;\n    r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;\n    c += p1 + (uint128_t)SECP256K1_N_C_1 * p4;\n    r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;\n    c += p2 + (uint128_t)p4;\n    r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;\n    c += p3;\n    r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;\n#endif\n\n    /* Final reduction of r. */\n    secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));\n}\n\nstatic void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) {\n#ifdef USE_ASM_X86_64\n    const uint64_t *pb = b->d;\n    __asm__ __volatile__(\n    /* Preload */\n    \"movq 0(%%rdi), %%r15\\n\"\n    \"movq 8(%%rdi), %%rbx\\n\"\n    \"movq 16(%%rdi), %%rcx\\n\"\n    \"movq 0(%%rdx), %%r11\\n\"\n    \"movq 8(%%rdx), %%r12\\n\"\n    \"movq 16(%%rdx), %%r13\\n\"\n    \"movq 24(%%rdx), %%r14\\n\"\n    /* (rax,rdx) = a0 * b0 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    /* Extract l0 */\n    \"movq %%rax, 0(%%rsi)\\n\"\n    /* (r8,r9,r10) = (rdx) */\n    \"movq %%rdx, %%r8\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9,r10) += a0 * b1 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += a1 * b0 */\n    \"movq %%rbx, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* Extract l1 */\n    \"movq %%r8, 8(%%rsi)\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10,r8) += a0 * b2 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += a1 * b1 */\n    \"movq %%rbx, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += a2 * b0 */\n    \"movq %%rcx, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* Extract l2 */\n    \"movq %%r9, 16(%%rsi)\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r10,r8,r9) += a0 * b3 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* Preload a3 */\n    \"movq 24(%%rdi), %%r15\\n\"\n    /* (r10,r8,r9) += a1 * b2 */\n    \"movq %%rbx, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += a2 * b1 */\n    \"movq %%rcx, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += a3 * b0 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* Extract l3 */\n    \"movq %%r10, 24(%%rsi)\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9,r10) += a1 * b3 */\n    \"movq %%rbx, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += a2 * b2 */\n    \"movq %%rcx, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += a3 * b1 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* Extract l4 */\n    \"movq %%r8, 32(%%rsi)\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10,r8) += a2 * b3 */\n    \"movq %%rcx, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += a3 * b2 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* Extract l5 */\n    \"movq %%r9, 40(%%rsi)\\n\"\n    /* (r10,r8) += a3 * b3 */\n    \"movq %%r15, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    /* Extract l6 */\n    \"movq %%r10, 48(%%rsi)\\n\"\n    /* Extract l7 */\n    \"movq %%r8, 56(%%rsi)\\n\"\n    : \"+d\"(pb)\n    : \"S\"(l), \"D\"(a->d)\n    : \"rax\", \"rbx\", \"rcx\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r13\", \"r14\", \"r15\", \"cc\", \"memory\");\n#else\n    /* 160 bit accumulator. */\n    uint64_t c0 = 0, c1 = 0;\n    uint32_t c2 = 0;\n\n    /* l[0..7] = a[0..3] * b[0..3]. */\n    muladd_fast(a->d[0], b->d[0]);\n    extract_fast(l[0]);\n    muladd(a->d[0], b->d[1]);\n    muladd(a->d[1], b->d[0]);\n    extract(l[1]);\n    muladd(a->d[0], b->d[2]);\n    muladd(a->d[1], b->d[1]);\n    muladd(a->d[2], b->d[0]);\n    extract(l[2]);\n    muladd(a->d[0], b->d[3]);\n    muladd(a->d[1], b->d[2]);\n    muladd(a->d[2], b->d[1]);\n    muladd(a->d[3], b->d[0]);\n    extract(l[3]);\n    muladd(a->d[1], b->d[3]);\n    muladd(a->d[2], b->d[2]);\n    muladd(a->d[3], b->d[1]);\n    extract(l[4]);\n    muladd(a->d[2], b->d[3]);\n    muladd(a->d[3], b->d[2]);\n    extract(l[5]);\n    muladd_fast(a->d[3], b->d[3]);\n    extract_fast(l[6]);\n    VERIFY_CHECK(c1 == 0);\n    l[7] = c0;\n#endif\n}\n\nstatic void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) {\n#ifdef USE_ASM_X86_64\n    __asm__ __volatile__(\n    /* Preload */\n    \"movq 0(%%rdi), %%r11\\n\"\n    \"movq 8(%%rdi), %%r12\\n\"\n    \"movq 16(%%rdi), %%r13\\n\"\n    \"movq 24(%%rdi), %%r14\\n\"\n    /* (rax,rdx) = a0 * a0 */\n    \"movq %%r11, %%rax\\n\"\n    \"mulq %%r11\\n\"\n    /* Extract l0 */\n    \"movq %%rax, 0(%%rsi)\\n\"\n    /* (r8,r9,r10) = (rdx,0) */\n    \"movq %%rdx, %%r8\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9,r10) += 2 * a0 * a1 */\n    \"movq %%r11, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* Extract l1 */\n    \"movq %%r8, 8(%%rsi)\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10,r8) += 2 * a0 * a2 */\n    \"movq %%r11, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* (r9,r10,r8) += a1 * a1 */\n    \"movq %%r12, %%rax\\n\"\n    \"mulq %%r12\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* Extract l2 */\n    \"movq %%r9, 16(%%rsi)\\n\"\n    \"xorq %%r9, %%r9\\n\"\n    /* (r10,r8,r9) += 2 * a0 * a3 */\n    \"movq %%r11, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* (r10,r8,r9) += 2 * a1 * a2 */\n    \"movq %%r12, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    \"adcq $0, %%r9\\n\"\n    /* Extract l3 */\n    \"movq %%r10, 24(%%rsi)\\n\"\n    \"xorq %%r10, %%r10\\n\"\n    /* (r8,r9,r10) += 2 * a1 * a3 */\n    \"movq %%r12, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* (r8,r9,r10) += a2 * a2 */\n    \"movq %%r13, %%rax\\n\"\n    \"mulq %%r13\\n\"\n    \"addq %%rax, %%r8\\n\"\n    \"adcq %%rdx, %%r9\\n\"\n    \"adcq $0, %%r10\\n\"\n    /* Extract l4 */\n    \"movq %%r8, 32(%%rsi)\\n\"\n    \"xorq %%r8, %%r8\\n\"\n    /* (r9,r10,r8) += 2 * a2 * a3 */\n    \"movq %%r13, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    \"addq %%rax, %%r9\\n\"\n    \"adcq %%rdx, %%r10\\n\"\n    \"adcq $0, %%r8\\n\"\n    /* Extract l5 */\n    \"movq %%r9, 40(%%rsi)\\n\"\n    /* (r10,r8) += a3 * a3 */\n    \"movq %%r14, %%rax\\n\"\n    \"mulq %%r14\\n\"\n    \"addq %%rax, %%r10\\n\"\n    \"adcq %%rdx, %%r8\\n\"\n    /* Extract l6 */\n    \"movq %%r10, 48(%%rsi)\\n\"\n    /* Extract l7 */\n    \"movq %%r8, 56(%%rsi)\\n\"\n    :\n    : \"S\"(l), \"D\"(a->d)\n    : \"rax\", \"rdx\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r13\", \"r14\", \"cc\", \"memory\");\n#else\n    /* 160 bit accumulator. */\n    uint64_t c0 = 0, c1 = 0;\n    uint32_t c2 = 0;\n\n    /* l[0..7] = a[0..3] * b[0..3]. */\n    muladd_fast(a->d[0], a->d[0]);\n    extract_fast(l[0]);\n    muladd2(a->d[0], a->d[1]);\n    extract(l[1]);\n    muladd2(a->d[0], a->d[2]);\n    muladd(a->d[1], a->d[1]);\n    extract(l[2]);\n    muladd2(a->d[0], a->d[3]);\n    muladd2(a->d[1], a->d[2]);\n    extract(l[3]);\n    muladd2(a->d[1], a->d[3]);\n    muladd(a->d[2], a->d[2]);\n    extract(l[4]);\n    muladd2(a->d[2], a->d[3]);\n    extract(l[5]);\n    muladd_fast(a->d[3], a->d[3]);\n    extract_fast(l[6]);\n    VERIFY_CHECK(c1 == 0);\n    l[7] = c0;\n#endif\n}\n\n#undef sumadd\n#undef sumadd_fast\n#undef muladd\n#undef muladd_fast\n#undef muladd2\n#undef extract\n#undef extract_fast\n\nstatic void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    uint64_t l[8];\n    secp256k1_scalar_mul_512(l, a, b);\n    secp256k1_scalar_reduce_512(r, l);\n}\n\nstatic int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {\n    int ret;\n    VERIFY_CHECK(n > 0);\n    VERIFY_CHECK(n < 16);\n    ret = r->d[0] & ((1 << n) - 1);\n    r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n));\n    r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n));\n    r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n));\n    r->d[3] = (r->d[3] >> n);\n    return ret;\n}\n\nstatic void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    uint64_t l[8];\n    secp256k1_scalar_sqr_512(l, a);\n    secp256k1_scalar_reduce_512(r, l);\n}\n\n#ifdef USE_ENDOMORPHISM\nstatic void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {\n    r1->d[0] = a->d[0];\n    r1->d[1] = a->d[1];\n    r1->d[2] = 0;\n    r1->d[3] = 0;\n    r2->d[0] = a->d[2];\n    r2->d[1] = a->d[3];\n    r2->d[2] = 0;\n    r2->d[3] = 0;\n}\n#endif\n\nSECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;\n}\n\nSECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) {\n    uint64_t l[8];\n    unsigned int shiftlimbs;\n    unsigned int shiftlow;\n    unsigned int shifthigh;\n    VERIFY_CHECK(shift >= 256);\n    secp256k1_scalar_mul_512(l, a, b);\n    shiftlimbs = shift >> 6;\n    shiftlow = shift & 0x3F;\n    shifthigh = 64 - shiftlow;\n    r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;\n    secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_8x32.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_\n#define _SECP256K1_SCALAR_REPR_\n\n#include <stdint.h>\n\n/** A scalar modulo the group order of the secp256k1 curve. */\ntypedef struct {\n    uint32_t d[8];\n} secp256k1_scalar;\n\n#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_8x32_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_\n#define _SECP256K1_SCALAR_REPR_IMPL_H_\n\n/* Limbs of the secp256k1 order. */\n#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)\n#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL)\n#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL)\n#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL)\n#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL)\n#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL)\n#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL)\n#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL)\n\n/* Limbs of 2^256 minus the secp256k1 order. */\n#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1)\n#define SECP256K1_N_C_1 (~SECP256K1_N_1)\n#define SECP256K1_N_C_2 (~SECP256K1_N_2)\n#define SECP256K1_N_C_3 (~SECP256K1_N_3)\n#define SECP256K1_N_C_4 (1)\n\n/* Limbs of half the secp256k1 order. */\n#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL)\n#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL)\n#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL)\n#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL)\n#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL)\n#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL)\n#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL)\n#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL)\n\nSECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {\n    r->d[0] = 0;\n    r->d[1] = 0;\n    r->d[2] = 0;\n    r->d[3] = 0;\n    r->d[4] = 0;\n    r->d[5] = 0;\n    r->d[6] = 0;\n    r->d[7] = 0;\n}\n\nSECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {\n    r->d[0] = v;\n    r->d[1] = 0;\n    r->d[2] = 0;\n    r->d[3] = 0;\n    r->d[4] = 0;\n    r->d[5] = 0;\n    r->d[6] = 0;\n    r->d[7] = 0;\n}\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);\n    return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);\n}\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    VERIFY_CHECK(count < 32);\n    VERIFY_CHECK(offset + count <= 256);\n    if ((offset + count - 1) >> 5 == offset >> 5) {\n        return secp256k1_scalar_get_bits(a, offset, count);\n    } else {\n        VERIFY_CHECK((offset >> 5) + 1 < 8);\n        return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1);\n    }\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) {\n    int yes = 0;\n    int no = 0;\n    no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */\n    no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */\n    no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */\n    no |= (a->d[4] < SECP256K1_N_4);\n    yes |= (a->d[4] > SECP256K1_N_4) & ~no;\n    no |= (a->d[3] < SECP256K1_N_3) & ~yes;\n    yes |= (a->d[3] > SECP256K1_N_3) & ~no;\n    no |= (a->d[2] < SECP256K1_N_2) & ~yes;\n    yes |= (a->d[2] > SECP256K1_N_2) & ~no;\n    no |= (a->d[1] < SECP256K1_N_1) & ~yes;\n    yes |= (a->d[1] > SECP256K1_N_1) & ~no;\n    yes |= (a->d[0] >= SECP256K1_N_0) & ~no;\n    return yes;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) {\n    uint64_t t;\n    VERIFY_CHECK(overflow <= 1);\n    t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;\n    r->d[0] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1;\n    r->d[1] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2;\n    r->d[2] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3;\n    r->d[3] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4;\n    r->d[4] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[5];\n    r->d[5] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[6];\n    r->d[6] = t & 0xFFFFFFFFUL; t >>= 32;\n    t += (uint64_t)r->d[7];\n    r->d[7] = t & 0xFFFFFFFFUL;\n    return overflow;\n}\n\nstatic int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    int overflow;\n    uint64_t t = (uint64_t)a->d[0] + b->d[0];\n    r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[1] + b->d[1];\n    r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[2] + b->d[2];\n    r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[3] + b->d[3];\n    r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[4] + b->d[4];\n    r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[5] + b->d[5];\n    r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[6] + b->d[6];\n    r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)a->d[7] + b->d[7];\n    r->d[7] = t & 0xFFFFFFFFULL; t >>= 32;\n    overflow = t + secp256k1_scalar_check_overflow(r);\n    VERIFY_CHECK(overflow == 0 || overflow == 1);\n    secp256k1_scalar_reduce(r, overflow);\n    return overflow;\n}\n\nstatic void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {\n    uint64_t t;\n    VERIFY_CHECK(bit < 256);\n    bit += ((uint32_t) flag - 1) & 0x100;  /* forcing (bit >> 5) > 7 makes this a noop */\n    t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));\n    r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));\n    r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F));\n    r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F));\n    r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F));\n    r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F));\n    r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F));\n    r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;\n    t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));\n    r->d[7] = t & 0xFFFFFFFFULL;\n#ifdef VERIFY\n    VERIFY_CHECK((t >> 32) == 0);\n    VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);\n#endif\n}\n\nstatic void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {\n    int over;\n    r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;\n    r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;\n    r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;\n    r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24;\n    r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24;\n    r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;\n    r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;\n    r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;\n    over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));\n    if (overflow) {\n        *overflow = over;\n    }\n}\n\nstatic void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {\n    bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];\n    bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];\n    bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];\n    bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4];\n    bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3];\n    bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2];\n    bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1];\n    bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {\n    return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;\n}\n\nstatic void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0);\n    uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1;\n    r->d[0] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[1]) + SECP256K1_N_1;\n    r->d[1] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[2]) + SECP256K1_N_2;\n    r->d[2] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[3]) + SECP256K1_N_3;\n    r->d[3] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[4]) + SECP256K1_N_4;\n    r->d[4] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[5]) + SECP256K1_N_5;\n    r->d[5] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[6]) + SECP256K1_N_6;\n    r->d[6] = t & nonzero; t >>= 32;\n    t += (uint64_t)(~a->d[7]) + SECP256K1_N_7;\n    r->d[7] = t & nonzero;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {\n    return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;\n}\n\nstatic int secp256k1_scalar_is_high(const secp256k1_scalar *a) {\n    int yes = 0;\n    int no = 0;\n    no |= (a->d[7] < SECP256K1_N_H_7);\n    yes |= (a->d[7] > SECP256K1_N_H_7) & ~no;\n    no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */\n    no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */\n    no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */\n    no |= (a->d[3] < SECP256K1_N_H_3) & ~yes;\n    yes |= (a->d[3] > SECP256K1_N_H_3) & ~no;\n    no |= (a->d[2] < SECP256K1_N_H_2) & ~yes;\n    yes |= (a->d[2] > SECP256K1_N_H_2) & ~no;\n    no |= (a->d[1] < SECP256K1_N_H_1) & ~yes;\n    yes |= (a->d[1] > SECP256K1_N_H_1) & ~no;\n    yes |= (a->d[0] > SECP256K1_N_H_0) & ~no;\n    return yes;\n}\n\nstatic int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {\n    /* If we are flag = 0, mask = 00...00 and this is a no-op;\n     * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */\n    uint32_t mask = !flag - 1;\n    uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);\n    uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);\n    r->d[0] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);\n    r->d[1] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);\n    r->d[2] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);\n    r->d[3] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask);\n    r->d[4] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask);\n    r->d[5] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask);\n    r->d[6] = t & nonzero; t >>= 32;\n    t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask);\n    r->d[7] = t & nonzero;\n    return 2 * (mask == 0) - 1;\n}\n\n\n/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */\n\n/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define muladd(a,b) { \\\n    uint32_t tl, th; \\\n    { \\\n        uint64_t t = (uint64_t)a * b; \\\n        th = t >> 32;         /* at most 0xFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    c0 += tl;                 /* overflow is handled on the next line */ \\\n    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFF */ \\\n    c1 += th;                 /* overflow is handled on the next line */ \\\n    c2 += (c1 < th) ? 1 : 0;  /* never overflows by contract (verified in the next line) */ \\\n    VERIFY_CHECK((c1 >= th) || (c2 != 0)); \\\n}\n\n/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */\n#define muladd_fast(a,b) { \\\n    uint32_t tl, th; \\\n    { \\\n        uint64_t t = (uint64_t)a * b; \\\n        th = t >> 32;         /* at most 0xFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    c0 += tl;                 /* overflow is handled on the next line */ \\\n    th += (c0 < tl) ? 1 : 0;  /* at most 0xFFFFFFFF */ \\\n    c1 += th;                 /* never overflows by contract (verified in the next line) */ \\\n    VERIFY_CHECK(c1 >= th); \\\n}\n\n/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define muladd2(a,b) { \\\n    uint32_t tl, th, th2, tl2; \\\n    { \\\n        uint64_t t = (uint64_t)a * b; \\\n        th = t >> 32;               /* at most 0xFFFFFFFE */ \\\n        tl = t; \\\n    } \\\n    th2 = th + th;                  /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \\\n    c2 += (th2 < th) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((th2 >= th) || (c2 != 0)); \\\n    tl2 = tl + tl;                  /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \\\n    th2 += (tl2 < tl) ? 1 : 0;      /* at most 0xFFFFFFFF */ \\\n    c0 += tl2;                      /* overflow is handled on the next line */ \\\n    th2 += (c0 < tl2) ? 1 : 0;      /* second overflow is handled on the next line */ \\\n    c2 += (c0 < tl2) & (th2 == 0);  /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \\\n    c1 += th2;                      /* overflow is handled on the next line */ \\\n    c2 += (c1 < th2) ? 1 : 0;       /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \\\n}\n\n/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */\n#define sumadd(a) { \\\n    unsigned int over; \\\n    c0 += (a);                  /* overflow is handled on the next line */ \\\n    over = (c0 < (a)) ? 1 : 0; \\\n    c1 += over;                 /* overflow is handled on the next line */ \\\n    c2 += (c1 < over) ? 1 : 0;  /* never overflows by contract */ \\\n}\n\n/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */\n#define sumadd_fast(a) { \\\n    c0 += (a);                 /* overflow is handled on the next line */ \\\n    c1 += (c0 < (a)) ? 1 : 0;  /* never overflows by contract (verified the next line) */ \\\n    VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \\\n    VERIFY_CHECK(c2 == 0); \\\n}\n\n/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */\n#define extract(n) { \\\n    (n) = c0; \\\n    c0 = c1; \\\n    c1 = c2; \\\n    c2 = 0; \\\n}\n\n/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */\n#define extract_fast(n) { \\\n    (n) = c0; \\\n    c0 = c1; \\\n    c1 = 0; \\\n    VERIFY_CHECK(c2 == 0); \\\n}\n\nstatic void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) {\n    uint64_t c;\n    uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15];\n    uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12;\n    uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8;\n\n    /* 96 bit accumulator. */\n    uint32_t c0, c1, c2;\n\n    /* Reduce 512 bits into 385. */\n    /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */\n    c0 = l[0]; c1 = 0; c2 = 0;\n    muladd_fast(n0, SECP256K1_N_C_0);\n    extract_fast(m0);\n    sumadd_fast(l[1]);\n    muladd(n1, SECP256K1_N_C_0);\n    muladd(n0, SECP256K1_N_C_1);\n    extract(m1);\n    sumadd(l[2]);\n    muladd(n2, SECP256K1_N_C_0);\n    muladd(n1, SECP256K1_N_C_1);\n    muladd(n0, SECP256K1_N_C_2);\n    extract(m2);\n    sumadd(l[3]);\n    muladd(n3, SECP256K1_N_C_0);\n    muladd(n2, SECP256K1_N_C_1);\n    muladd(n1, SECP256K1_N_C_2);\n    muladd(n0, SECP256K1_N_C_3);\n    extract(m3);\n    sumadd(l[4]);\n    muladd(n4, SECP256K1_N_C_0);\n    muladd(n3, SECP256K1_N_C_1);\n    muladd(n2, SECP256K1_N_C_2);\n    muladd(n1, SECP256K1_N_C_3);\n    sumadd(n0);\n    extract(m4);\n    sumadd(l[5]);\n    muladd(n5, SECP256K1_N_C_0);\n    muladd(n4, SECP256K1_N_C_1);\n    muladd(n3, SECP256K1_N_C_2);\n    muladd(n2, SECP256K1_N_C_3);\n    sumadd(n1);\n    extract(m5);\n    sumadd(l[6]);\n    muladd(n6, SECP256K1_N_C_0);\n    muladd(n5, SECP256K1_N_C_1);\n    muladd(n4, SECP256K1_N_C_2);\n    muladd(n3, SECP256K1_N_C_3);\n    sumadd(n2);\n    extract(m6);\n    sumadd(l[7]);\n    muladd(n7, SECP256K1_N_C_0);\n    muladd(n6, SECP256K1_N_C_1);\n    muladd(n5, SECP256K1_N_C_2);\n    muladd(n4, SECP256K1_N_C_3);\n    sumadd(n3);\n    extract(m7);\n    muladd(n7, SECP256K1_N_C_1);\n    muladd(n6, SECP256K1_N_C_2);\n    muladd(n5, SECP256K1_N_C_3);\n    sumadd(n4);\n    extract(m8);\n    muladd(n7, SECP256K1_N_C_2);\n    muladd(n6, SECP256K1_N_C_3);\n    sumadd(n5);\n    extract(m9);\n    muladd(n7, SECP256K1_N_C_3);\n    sumadd(n6);\n    extract(m10);\n    sumadd_fast(n7);\n    extract_fast(m11);\n    VERIFY_CHECK(c0 <= 1);\n    m12 = c0;\n\n    /* Reduce 385 bits into 258. */\n    /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */\n    c0 = m0; c1 = 0; c2 = 0;\n    muladd_fast(m8, SECP256K1_N_C_0);\n    extract_fast(p0);\n    sumadd_fast(m1);\n    muladd(m9, SECP256K1_N_C_0);\n    muladd(m8, SECP256K1_N_C_1);\n    extract(p1);\n    sumadd(m2);\n    muladd(m10, SECP256K1_N_C_0);\n    muladd(m9, SECP256K1_N_C_1);\n    muladd(m8, SECP256K1_N_C_2);\n    extract(p2);\n    sumadd(m3);\n    muladd(m11, SECP256K1_N_C_0);\n    muladd(m10, SECP256K1_N_C_1);\n    muladd(m9, SECP256K1_N_C_2);\n    muladd(m8, SECP256K1_N_C_3);\n    extract(p3);\n    sumadd(m4);\n    muladd(m12, SECP256K1_N_C_0);\n    muladd(m11, SECP256K1_N_C_1);\n    muladd(m10, SECP256K1_N_C_2);\n    muladd(m9, SECP256K1_N_C_3);\n    sumadd(m8);\n    extract(p4);\n    sumadd(m5);\n    muladd(m12, SECP256K1_N_C_1);\n    muladd(m11, SECP256K1_N_C_2);\n    muladd(m10, SECP256K1_N_C_3);\n    sumadd(m9);\n    extract(p5);\n    sumadd(m6);\n    muladd(m12, SECP256K1_N_C_2);\n    muladd(m11, SECP256K1_N_C_3);\n    sumadd(m10);\n    extract(p6);\n    sumadd_fast(m7);\n    muladd_fast(m12, SECP256K1_N_C_3);\n    sumadd_fast(m11);\n    extract_fast(p7);\n    p8 = c0 + m12;\n    VERIFY_CHECK(p8 <= 2);\n\n    /* Reduce 258 bits into 256. */\n    /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */\n    c = p0 + (uint64_t)SECP256K1_N_C_0 * p8;\n    r->d[0] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p1 + (uint64_t)SECP256K1_N_C_1 * p8;\n    r->d[1] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p2 + (uint64_t)SECP256K1_N_C_2 * p8;\n    r->d[2] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p3 + (uint64_t)SECP256K1_N_C_3 * p8;\n    r->d[3] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p4 + (uint64_t)p8;\n    r->d[4] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p5;\n    r->d[5] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p6;\n    r->d[6] = c & 0xFFFFFFFFUL; c >>= 32;\n    c += p7;\n    r->d[7] = c & 0xFFFFFFFFUL; c >>= 32;\n\n    /* Final reduction of r. */\n    secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));\n}\n\nstatic void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    /* 96 bit accumulator. */\n    uint32_t c0 = 0, c1 = 0, c2 = 0;\n\n    /* l[0..15] = a[0..7] * b[0..7]. */\n    muladd_fast(a->d[0], b->d[0]);\n    extract_fast(l[0]);\n    muladd(a->d[0], b->d[1]);\n    muladd(a->d[1], b->d[0]);\n    extract(l[1]);\n    muladd(a->d[0], b->d[2]);\n    muladd(a->d[1], b->d[1]);\n    muladd(a->d[2], b->d[0]);\n    extract(l[2]);\n    muladd(a->d[0], b->d[3]);\n    muladd(a->d[1], b->d[2]);\n    muladd(a->d[2], b->d[1]);\n    muladd(a->d[3], b->d[0]);\n    extract(l[3]);\n    muladd(a->d[0], b->d[4]);\n    muladd(a->d[1], b->d[3]);\n    muladd(a->d[2], b->d[2]);\n    muladd(a->d[3], b->d[1]);\n    muladd(a->d[4], b->d[0]);\n    extract(l[4]);\n    muladd(a->d[0], b->d[5]);\n    muladd(a->d[1], b->d[4]);\n    muladd(a->d[2], b->d[3]);\n    muladd(a->d[3], b->d[2]);\n    muladd(a->d[4], b->d[1]);\n    muladd(a->d[5], b->d[0]);\n    extract(l[5]);\n    muladd(a->d[0], b->d[6]);\n    muladd(a->d[1], b->d[5]);\n    muladd(a->d[2], b->d[4]);\n    muladd(a->d[3], b->d[3]);\n    muladd(a->d[4], b->d[2]);\n    muladd(a->d[5], b->d[1]);\n    muladd(a->d[6], b->d[0]);\n    extract(l[6]);\n    muladd(a->d[0], b->d[7]);\n    muladd(a->d[1], b->d[6]);\n    muladd(a->d[2], b->d[5]);\n    muladd(a->d[3], b->d[4]);\n    muladd(a->d[4], b->d[3]);\n    muladd(a->d[5], b->d[2]);\n    muladd(a->d[6], b->d[1]);\n    muladd(a->d[7], b->d[0]);\n    extract(l[7]);\n    muladd(a->d[1], b->d[7]);\n    muladd(a->d[2], b->d[6]);\n    muladd(a->d[3], b->d[5]);\n    muladd(a->d[4], b->d[4]);\n    muladd(a->d[5], b->d[3]);\n    muladd(a->d[6], b->d[2]);\n    muladd(a->d[7], b->d[1]);\n    extract(l[8]);\n    muladd(a->d[2], b->d[7]);\n    muladd(a->d[3], b->d[6]);\n    muladd(a->d[4], b->d[5]);\n    muladd(a->d[5], b->d[4]);\n    muladd(a->d[6], b->d[3]);\n    muladd(a->d[7], b->d[2]);\n    extract(l[9]);\n    muladd(a->d[3], b->d[7]);\n    muladd(a->d[4], b->d[6]);\n    muladd(a->d[5], b->d[5]);\n    muladd(a->d[6], b->d[4]);\n    muladd(a->d[7], b->d[3]);\n    extract(l[10]);\n    muladd(a->d[4], b->d[7]);\n    muladd(a->d[5], b->d[6]);\n    muladd(a->d[6], b->d[5]);\n    muladd(a->d[7], b->d[4]);\n    extract(l[11]);\n    muladd(a->d[5], b->d[7]);\n    muladd(a->d[6], b->d[6]);\n    muladd(a->d[7], b->d[5]);\n    extract(l[12]);\n    muladd(a->d[6], b->d[7]);\n    muladd(a->d[7], b->d[6]);\n    extract(l[13]);\n    muladd_fast(a->d[7], b->d[7]);\n    extract_fast(l[14]);\n    VERIFY_CHECK(c1 == 0);\n    l[15] = c0;\n}\n\nstatic void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) {\n    /* 96 bit accumulator. */\n    uint32_t c0 = 0, c1 = 0, c2 = 0;\n\n    /* l[0..15] = a[0..7]^2. */\n    muladd_fast(a->d[0], a->d[0]);\n    extract_fast(l[0]);\n    muladd2(a->d[0], a->d[1]);\n    extract(l[1]);\n    muladd2(a->d[0], a->d[2]);\n    muladd(a->d[1], a->d[1]);\n    extract(l[2]);\n    muladd2(a->d[0], a->d[3]);\n    muladd2(a->d[1], a->d[2]);\n    extract(l[3]);\n    muladd2(a->d[0], a->d[4]);\n    muladd2(a->d[1], a->d[3]);\n    muladd(a->d[2], a->d[2]);\n    extract(l[4]);\n    muladd2(a->d[0], a->d[5]);\n    muladd2(a->d[1], a->d[4]);\n    muladd2(a->d[2], a->d[3]);\n    extract(l[5]);\n    muladd2(a->d[0], a->d[6]);\n    muladd2(a->d[1], a->d[5]);\n    muladd2(a->d[2], a->d[4]);\n    muladd(a->d[3], a->d[3]);\n    extract(l[6]);\n    muladd2(a->d[0], a->d[7]);\n    muladd2(a->d[1], a->d[6]);\n    muladd2(a->d[2], a->d[5]);\n    muladd2(a->d[3], a->d[4]);\n    extract(l[7]);\n    muladd2(a->d[1], a->d[7]);\n    muladd2(a->d[2], a->d[6]);\n    muladd2(a->d[3], a->d[5]);\n    muladd(a->d[4], a->d[4]);\n    extract(l[8]);\n    muladd2(a->d[2], a->d[7]);\n    muladd2(a->d[3], a->d[6]);\n    muladd2(a->d[4], a->d[5]);\n    extract(l[9]);\n    muladd2(a->d[3], a->d[7]);\n    muladd2(a->d[4], a->d[6]);\n    muladd(a->d[5], a->d[5]);\n    extract(l[10]);\n    muladd2(a->d[4], a->d[7]);\n    muladd2(a->d[5], a->d[6]);\n    extract(l[11]);\n    muladd2(a->d[5], a->d[7]);\n    muladd(a->d[6], a->d[6]);\n    extract(l[12]);\n    muladd2(a->d[6], a->d[7]);\n    extract(l[13]);\n    muladd_fast(a->d[7], a->d[7]);\n    extract_fast(l[14]);\n    VERIFY_CHECK(c1 == 0);\n    l[15] = c0;\n}\n\n#undef sumadd\n#undef sumadd_fast\n#undef muladd\n#undef muladd_fast\n#undef muladd2\n#undef extract\n#undef extract_fast\n\nstatic void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    uint32_t l[16];\n    secp256k1_scalar_mul_512(l, a, b);\n    secp256k1_scalar_reduce_512(r, l);\n}\n\nstatic int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {\n    int ret;\n    VERIFY_CHECK(n > 0);\n    VERIFY_CHECK(n < 16);\n    ret = r->d[0] & ((1 << n) - 1);\n    r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n));\n    r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n));\n    r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n));\n    r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n));\n    r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n));\n    r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n));\n    r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n));\n    r->d[7] = (r->d[7] >> n);\n    return ret;\n}\n\nstatic void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    uint32_t l[16];\n    secp256k1_scalar_sqr_512(l, a);\n    secp256k1_scalar_reduce_512(r, l);\n}\n\n#ifdef USE_ENDOMORPHISM\nstatic void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {\n    r1->d[0] = a->d[0];\n    r1->d[1] = a->d[1];\n    r1->d[2] = a->d[2];\n    r1->d[3] = a->d[3];\n    r1->d[4] = 0;\n    r1->d[5] = 0;\n    r1->d[6] = 0;\n    r1->d[7] = 0;\n    r2->d[0] = a->d[4];\n    r2->d[1] = a->d[5];\n    r2->d[2] = a->d[6];\n    r2->d[3] = a->d[7];\n    r2->d[4] = 0;\n    r2->d[5] = 0;\n    r2->d[6] = 0;\n    r2->d[7] = 0;\n}\n#endif\n\nSECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;\n}\n\nSECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) {\n    uint32_t l[16];\n    unsigned int shiftlimbs;\n    unsigned int shiftlow;\n    unsigned int shifthigh;\n    VERIFY_CHECK(shift >= 256);\n    secp256k1_scalar_mul_512(l, a, b);\n    shiftlimbs = shift >> 5;\n    shiftlow = shift & 0x1F;\n    shifthigh = 32 - shiftlow;\n    r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;\n    r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow)  : 0;\n    secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2014 Pieter Wuille                                   *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_IMPL_H_\n#define _SECP256K1_SCALAR_IMPL_H_\n\n#include \"group.h\"\n#include \"scalar.h\"\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#if defined(EXHAUSTIVE_TEST_ORDER)\n#include \"scalar_low_impl.h\"\n#elif defined(USE_SCALAR_4X64)\n#include \"scalar_4x64_impl.h\"\n#elif defined(USE_SCALAR_8X32)\n#include \"scalar_8x32_impl.h\"\n#else\n#error \"Please select scalar implementation\"\n#endif\n\n#ifndef USE_NUM_NONE\nstatic void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) {\n    unsigned char c[32];\n    secp256k1_scalar_get_b32(c, a);\n    secp256k1_num_set_bin(r, c, 32);\n}\n\n/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */\nstatic void secp256k1_scalar_order_get_num(secp256k1_num *r) {\n#if defined(EXHAUSTIVE_TEST_ORDER)\n    static const unsigned char order[32] = {\n        0,0,0,0,0,0,0,0,\n        0,0,0,0,0,0,0,0,\n        0,0,0,0,0,0,0,0,\n        0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER\n    };\n#else\n    static const unsigned char order[32] = {\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,\n        0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,\n        0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41\n    };\n#endif\n    secp256k1_num_set_bin(r, order, 32);\n}\n#endif\n\nstatic void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {\n#if defined(EXHAUSTIVE_TEST_ORDER)\n    int i;\n    *r = 0;\n    for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)\n        if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)\n            *r = i;\n    /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus\n     * have a composite group order; fix it in exhaustive_tests.c). */\n    VERIFY_CHECK(*r != 0);\n}\n#else\n    secp256k1_scalar *t;\n    int i;\n    /* First compute xN as x ^ (2^N - 1) for some values of N,\n     * and uM as x ^ M for some values of M. */\n    secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126;\n    secp256k1_scalar u2, u5, u9, u11, u13;\n\n    secp256k1_scalar_sqr(&u2, x);\n    secp256k1_scalar_mul(&x2, &u2,  x);\n    secp256k1_scalar_mul(&u5, &u2, &x2);\n    secp256k1_scalar_mul(&x3, &u5,  &u2);\n    secp256k1_scalar_mul(&u9, &x3, &u2);\n    secp256k1_scalar_mul(&u11, &u9, &u2);\n    secp256k1_scalar_mul(&u13, &u11, &u2);\n\n    secp256k1_scalar_sqr(&x6, &u13);\n    secp256k1_scalar_sqr(&x6, &x6);\n    secp256k1_scalar_mul(&x6, &x6, &u11);\n\n    secp256k1_scalar_sqr(&x8, &x6);\n    secp256k1_scalar_sqr(&x8, &x8);\n    secp256k1_scalar_mul(&x8, &x8,  &x2);\n\n    secp256k1_scalar_sqr(&x14, &x8);\n    for (i = 0; i < 5; i++) {\n        secp256k1_scalar_sqr(&x14, &x14);\n    }\n    secp256k1_scalar_mul(&x14, &x14, &x6);\n\n    secp256k1_scalar_sqr(&x28, &x14);\n    for (i = 0; i < 13; i++) {\n        secp256k1_scalar_sqr(&x28, &x28);\n    }\n    secp256k1_scalar_mul(&x28, &x28, &x14);\n\n    secp256k1_scalar_sqr(&x56, &x28);\n    for (i = 0; i < 27; i++) {\n        secp256k1_scalar_sqr(&x56, &x56);\n    }\n    secp256k1_scalar_mul(&x56, &x56, &x28);\n\n    secp256k1_scalar_sqr(&x112, &x56);\n    for (i = 0; i < 55; i++) {\n        secp256k1_scalar_sqr(&x112, &x112);\n    }\n    secp256k1_scalar_mul(&x112, &x112, &x56);\n\n    secp256k1_scalar_sqr(&x126, &x112);\n    for (i = 0; i < 13; i++) {\n        secp256k1_scalar_sqr(&x126, &x126);\n    }\n    secp256k1_scalar_mul(&x126, &x126, &x14);\n\n    /* Then accumulate the final result (t starts at x126). */\n    t = &x126;\n    for (i = 0; i < 3; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u5); /* 101 */\n    for (i = 0; i < 4; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 4; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u5); /* 101 */\n    for (i = 0; i < 5; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u11); /* 1011 */\n    for (i = 0; i < 4; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u11); /* 1011 */\n    for (i = 0; i < 4; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 5; i++) { /* 00 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 6; i++) { /* 00 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u13); /* 1101 */\n    for (i = 0; i < 4; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u5); /* 101 */\n    for (i = 0; i < 3; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 5; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u9); /* 1001 */\n    for (i = 0; i < 6; i++) { /* 000 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u5); /* 101 */\n    for (i = 0; i < 10; i++) { /* 0000000 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 4; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x3); /* 111 */\n    for (i = 0; i < 9; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x8); /* 11111111 */\n    for (i = 0; i < 5; i++) { /* 0 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u9); /* 1001 */\n    for (i = 0; i < 6; i++) { /* 00 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u11); /* 1011 */\n    for (i = 0; i < 4; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u13); /* 1101 */\n    for (i = 0; i < 5; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &x2); /* 11 */\n    for (i = 0; i < 6; i++) { /* 00 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u13); /* 1101 */\n    for (i = 0; i < 10; i++) { /* 000000 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u13); /* 1101 */\n    for (i = 0; i < 4; i++) {\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, &u9); /* 1001 */\n    for (i = 0; i < 6; i++) { /* 00000 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(t, t, x); /* 1 */\n    for (i = 0; i < 8; i++) { /* 00 */\n        secp256k1_scalar_sqr(t, t);\n    }\n    secp256k1_scalar_mul(r, t, &x6); /* 111111 */\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {\n    return !(a->d[0] & 1);\n}\n#endif\n\nstatic void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {\n#if defined(USE_SCALAR_INV_BUILTIN)\n    secp256k1_scalar_inverse(r, x);\n#elif defined(USE_SCALAR_INV_NUM)\n    unsigned char b[32];\n    secp256k1_num n, m;\n    secp256k1_scalar t = *x;\n    secp256k1_scalar_get_b32(b, &t);\n    secp256k1_num_set_bin(&n, b, 32);\n    secp256k1_scalar_order_get_num(&m);\n    secp256k1_num_mod_inverse(&n, &n, &m);\n    secp256k1_num_get_bin(b, 32, &n);\n    secp256k1_scalar_set_b32(r, b, NULL);\n    /* Verify that the inverse was computed correctly, without GMP code. */\n    secp256k1_scalar_mul(&t, &t, r);\n    CHECK(secp256k1_scalar_is_one(&t));\n#else\n#error \"Please select scalar inverse implementation\"\n#endif\n}\n\n#ifdef USE_ENDOMORPHISM\n#if defined(EXHAUSTIVE_TEST_ORDER)\n/**\n * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the\n * full case we don't bother making k1 and k2 be small, we just want them to be\n * nontrivial to get full test coverage for the exhaustive tests. We therefore\n * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.\n */\nstatic void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {\n    *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;\n    *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;\n}\n#else\n/**\n * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where\n * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,\n *            0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}\n *\n * \"Guide to Elliptic Curve Cryptography\" (Hankerson, Menezes, Vanstone) gives an algorithm\n * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1\n * and k2 have a small size.\n * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:\n *\n * - a1 =      {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}\n * - b1 =     -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}\n * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}\n * - b2 =      {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}\n *\n * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives\n * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and\n * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.\n *\n * g1, g2 are precomputed constants used to replace division with a rounded multiplication\n * when decomposing the scalar for an endomorphism-based point multiplication.\n *\n * The possibility of using precomputed estimates is mentioned in \"Guide to Elliptic Curve\n * Cryptography\" (Hankerson, Menezes, Vanstone) in section 3.5.\n *\n * The derivation is described in the paper \"Efficient Software Implementation of Public-Key\n * Cryptography on Sensor Networks Using the MSP430X Microcontroller\" (Gouvea, Oliveira, Lopez),\n * Section 4.3 (here we use a somewhat higher-precision estimate):\n * d = a1*b2 - b1*a2\n * g1 = round((2^272)*b2/d)\n * g2 = round((2^272)*b1/d)\n *\n * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found\n * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').\n *\n * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order).\n */\n\nstatic void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {\n    secp256k1_scalar c1, c2;\n    static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST(\n        0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL,\n        0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL\n    );\n    static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST(\n        0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,\n        0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL\n    );\n    static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST(\n        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,\n        0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL\n    );\n    static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST(\n        0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL,\n        0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL\n    );\n    static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST(\n        0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL,\n        0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL\n    );\n    VERIFY_CHECK(r1 != a);\n    VERIFY_CHECK(r2 != a);\n    /* these _var calls are constant time since the shift amount is constant */\n    secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272);\n    secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272);\n    secp256k1_scalar_mul(&c1, &c1, &minus_b1);\n    secp256k1_scalar_mul(&c2, &c2, &minus_b2);\n    secp256k1_scalar_add(r2, &c1, &c2);\n    secp256k1_scalar_mul(r1, r2, &minus_lambda);\n    secp256k1_scalar_add(r1, r1, a);\n}\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_low.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_\n#define _SECP256K1_SCALAR_REPR_\n\n#include <stdint.h>\n\n/** A scalar modulo the group order of the secp256k1 curve. */\ntypedef uint32_t secp256k1_scalar;\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/scalar_low_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2015 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_\n#define _SECP256K1_SCALAR_REPR_IMPL_H_\n\n#include \"scalar.h\"\n\n#include <string.h>\n\nSECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {\n    return !(*a & 1);\n}\n\nSECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }\nSECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    if (offset < 32)\n        return ((*a >> offset) & ((((uint32_t)1) << count) - 1));\n    else\n        return 0;\n}\n\nSECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {\n    return secp256k1_scalar_get_bits(a, offset, count);\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }\n\nstatic int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;\n    return *r < *b;\n}\n\nstatic void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {\n    if (flag && bit < 32)\n        *r += (1 << bit);\n#ifdef VERIFY\n    VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);\n#endif\n}\n\nstatic void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {\n    const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;\n    int i;\n    *r = 0;\n    for (i = 0; i < 32; i++) {\n       *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;\n    }\n    /* just deny overflow, it basically always happens */\n    if (overflow) *overflow = 0;\n}\n\nstatic void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {\n    memset(bin, 0, 32);\n    bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {\n    return *a == 0;\n}\n\nstatic void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    if (*a == 0) {\n        *r = 0;\n    } else {\n        *r = EXHAUSTIVE_TEST_ORDER - *a;\n    }\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {\n    return *a == 1;\n}\n\nstatic int secp256k1_scalar_is_high(const secp256k1_scalar *a) {\n    return *a > EXHAUSTIVE_TEST_ORDER / 2;\n}\n\nstatic int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {\n    if (flag) secp256k1_scalar_negate(r, r);\n    return flag ? -1 : 1;\n}\n\nstatic void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;\n}\n\nstatic int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {\n    int ret;\n    VERIFY_CHECK(n > 0);\n    VERIFY_CHECK(n < 16);\n    ret = *r & ((1 << n) - 1);\n    *r >>= n;\n    return ret;\n}\n\nstatic void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {\n    *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;\n}\n\nstatic void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {\n    *r1 = *a;\n    *r2 = 0;\n}\n\nSECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {\n    return *a == *b;\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/secp256k1.c",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#include \"include/secp256k1.h\"\n\n#include \"util.h\"\n#include \"num_impl.h\"\n#include \"field_impl.h\"\n#include \"scalar_impl.h\"\n#include \"group_impl.h\"\n#include \"ecmult_impl.h\"\n#include \"ecmult_const_impl.h\"\n#include \"ecmult_gen_impl.h\"\n#include \"ecdsa_impl.h\"\n#include \"eckey_impl.h\"\n#include \"hash_impl.h\"\n\n#define ARG_CHECK(cond) do { \\\n    if (EXPECT(!(cond), 0)) { \\\n        secp256k1_callback_call(&ctx->illegal_callback, #cond); \\\n        return 0; \\\n    } \\\n} while(0)\n\nstatic void default_illegal_callback_fn(const char* str, void* data) {\n    (void)data;\n    fprintf(stderr, \"[libsecp256k1] illegal argument: %s\\n\", str);\n    abort();\n}\n\nstatic const secp256k1_callback default_illegal_callback = {\n    default_illegal_callback_fn,\n    NULL\n};\n\nstatic void default_error_callback_fn(const char* str, void* data) {\n    (void)data;\n    fprintf(stderr, \"[libsecp256k1] internal consistency check failed: %s\\n\", str);\n    abort();\n}\n\nstatic const secp256k1_callback default_error_callback = {\n    default_error_callback_fn,\n    NULL\n};\n\n\nstruct secp256k1_context_struct {\n    secp256k1_ecmult_context ecmult_ctx;\n    secp256k1_ecmult_gen_context ecmult_gen_ctx;\n    secp256k1_callback illegal_callback;\n    secp256k1_callback error_callback;\n};\n\nsecp256k1_context* secp256k1_context_create(unsigned int flags) {\n    secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));\n    ret->illegal_callback = default_illegal_callback;\n    ret->error_callback = default_error_callback;\n\n    if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {\n            secp256k1_callback_call(&ret->illegal_callback,\n                                    \"Invalid flags\");\n            free(ret);\n            return NULL;\n    }\n\n    secp256k1_ecmult_context_init(&ret->ecmult_ctx);\n    secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);\n\n    if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {\n        secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);\n    }\n    if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {\n        secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);\n    }\n\n    return ret;\n}\n\nsecp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {\n    secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context));\n    ret->illegal_callback = ctx->illegal_callback;\n    ret->error_callback = ctx->error_callback;\n    secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback);\n    secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback);\n    return ret;\n}\n\nvoid secp256k1_context_destroy(secp256k1_context* ctx) {\n    if (ctx != NULL) {\n        secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);\n        secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);\n\n        free(ctx);\n    }\n}\n\nvoid secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {\n    if (fun == NULL) {\n        fun = default_illegal_callback_fn;\n    }\n    ctx->illegal_callback.fn = fun;\n    ctx->illegal_callback.data = data;\n}\n\nvoid secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {\n    if (fun == NULL) {\n        fun = default_error_callback_fn;\n    }\n    ctx->error_callback.fn = fun;\n    ctx->error_callback.data = data;\n}\n\nstatic int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {\n    if (sizeof(secp256k1_ge_storage) == 64) {\n        /* When the secp256k1_ge_storage type is exactly 64 byte, use its\n         * representation inside secp256k1_pubkey, as conversion is very fast.\n         * Note that secp256k1_pubkey_save must use the same representation. */\n        secp256k1_ge_storage s;\n        memcpy(&s, &pubkey->data[0], 64);\n        secp256k1_ge_from_storage(ge, &s);\n    } else {\n        /* Otherwise, fall back to 32-byte big endian for X and Y. */\n        secp256k1_fe x, y;\n        secp256k1_fe_set_b32(&x, pubkey->data);\n        secp256k1_fe_set_b32(&y, pubkey->data + 32);\n        secp256k1_ge_set_xy(ge, &x, &y);\n    }\n    ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));\n    return 1;\n}\n\nstatic void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {\n    if (sizeof(secp256k1_ge_storage) == 64) {\n        secp256k1_ge_storage s;\n        secp256k1_ge_to_storage(&s, ge);\n        memcpy(&pubkey->data[0], &s, 64);\n    } else {\n        VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));\n        secp256k1_fe_normalize_var(&ge->x);\n        secp256k1_fe_normalize_var(&ge->y);\n        secp256k1_fe_get_b32(pubkey->data, &ge->x);\n        secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);\n    }\n}\n\nint secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {\n    secp256k1_ge Q;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(pubkey != NULL);\n    memset(pubkey, 0, sizeof(*pubkey));\n    ARG_CHECK(input != NULL);\n    if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) {\n        return 0;\n    }\n    secp256k1_pubkey_save(pubkey, &Q);\n    secp256k1_ge_clear(&Q);\n    return 1;\n}\n\nint secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) {\n    secp256k1_ge Q;\n    size_t len;\n    int ret = 0;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(outputlen != NULL);\n    ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));\n    len = *outputlen;\n    *outputlen = 0;\n    ARG_CHECK(output != NULL);\n    memset(output, 0, len);\n    ARG_CHECK(pubkey != NULL);\n    ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);\n    if (secp256k1_pubkey_load(ctx, &Q, pubkey)) {\n        ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION);\n        if (ret) {\n            *outputlen = len;\n        }\n    }\n    return ret;\n}\n\nstatic void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) {\n    (void)ctx;\n    if (sizeof(secp256k1_scalar) == 32) {\n        /* When the secp256k1_scalar type is exactly 32 byte, use its\n         * representation inside secp256k1_ecdsa_signature, as conversion is very fast.\n         * Note that secp256k1_ecdsa_signature_save must use the same representation. */\n        memcpy(r, &sig->data[0], 32);\n        memcpy(s, &sig->data[32], 32);\n    } else {\n        secp256k1_scalar_set_b32(r, &sig->data[0], NULL);\n        secp256k1_scalar_set_b32(s, &sig->data[32], NULL);\n    }\n}\n\nstatic void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) {\n    if (sizeof(secp256k1_scalar) == 32) {\n        memcpy(&sig->data[0], r, 32);\n        memcpy(&sig->data[32], s, 32);\n    } else {\n        secp256k1_scalar_get_b32(&sig->data[0], r);\n        secp256k1_scalar_get_b32(&sig->data[32], s);\n    }\n}\n\nint secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {\n    secp256k1_scalar r, s;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(input != NULL);\n\n    if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {\n        secp256k1_ecdsa_signature_save(sig, &r, &s);\n        return 1;\n    } else {\n        memset(sig, 0, sizeof(*sig));\n        return 0;\n    }\n}\n\nint secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) {\n    secp256k1_scalar r, s;\n    int ret = 1;\n    int overflow = 0;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(input64 != NULL);\n\n    secp256k1_scalar_set_b32(&r, &input64[0], &overflow);\n    ret &= !overflow;\n    secp256k1_scalar_set_b32(&s, &input64[32], &overflow);\n    ret &= !overflow;\n    if (ret) {\n        secp256k1_ecdsa_signature_save(sig, &r, &s);\n    } else {\n        memset(sig, 0, sizeof(*sig));\n    }\n    return ret;\n}\n\nint secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {\n    secp256k1_scalar r, s;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(output != NULL);\n    ARG_CHECK(outputlen != NULL);\n    ARG_CHECK(sig != NULL);\n\n    secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);\n    return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);\n}\n\nint secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {\n    secp256k1_scalar r, s;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(output64 != NULL);\n    ARG_CHECK(sig != NULL);\n\n    secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);\n    secp256k1_scalar_get_b32(&output64[0], &r);\n    secp256k1_scalar_get_b32(&output64[32], &s);\n    return 1;\n}\n\nint secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) {\n    secp256k1_scalar r, s;\n    int ret = 0;\n\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(sigin != NULL);\n\n    secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin);\n    ret = secp256k1_scalar_is_high(&s);\n    if (sigout != NULL) {\n        if (ret) {\n            secp256k1_scalar_negate(&s, &s);\n        }\n        secp256k1_ecdsa_signature_save(sigout, &r, &s);\n    }\n\n    return ret;\n}\n\nint secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) {\n    secp256k1_ge q;\n    secp256k1_scalar r, s;\n    secp256k1_scalar m;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));\n    ARG_CHECK(msg32 != NULL);\n    ARG_CHECK(sig != NULL);\n    ARG_CHECK(pubkey != NULL);\n\n    secp256k1_scalar_set_b32(&m, msg32, NULL);\n    secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);\n    return (!secp256k1_scalar_is_high(&s) &&\n            secp256k1_pubkey_load(ctx, &q, pubkey) &&\n            secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));\n}\n\nstatic int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {\n   unsigned char keydata[112];\n   int keylen = 64;\n   secp256k1_rfc6979_hmac_sha256_t rng;\n   unsigned int i;\n   /* We feed a byte array to the PRNG as input, consisting of:\n    * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.\n    * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.\n    * - optionally 16 extra bytes with the algorithm name.\n    * Because the arguments have distinct fixed lengths it is not possible for\n    *  different argument mixtures to emulate each other and result in the same\n    *  nonces.\n    */\n   memcpy(keydata, key32, 32);\n   memcpy(keydata + 32, msg32, 32);\n   if (data != NULL) {\n       memcpy(keydata + 64, data, 32);\n       keylen = 96;\n   }\n   if (algo16 != NULL) {\n       memcpy(keydata + keylen, algo16, 16);\n       keylen += 16;\n   }\n   secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen);\n   memset(keydata, 0, sizeof(keydata));\n   for (i = 0; i <= counter; i++) {\n       secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);\n   }\n   secp256k1_rfc6979_hmac_sha256_finalize(&rng);\n   return 1;\n}\n\nconst secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;\nconst secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;\n\nint secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {\n    secp256k1_scalar r, s;\n    secp256k1_scalar sec, non, msg;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));\n    ARG_CHECK(msg32 != NULL);\n    ARG_CHECK(signature != NULL);\n    ARG_CHECK(seckey != NULL);\n    if (noncefp == NULL) {\n        noncefp = secp256k1_nonce_function_default;\n    }\n\n    secp256k1_scalar_set_b32(&sec, seckey, &overflow);\n    /* Fail if the secret key is invalid. */\n    if (!overflow && !secp256k1_scalar_is_zero(&sec)) {\n        unsigned char nonce32[32];\n        unsigned int count = 0;\n        secp256k1_scalar_set_b32(&msg, msg32, NULL);\n        while (1) {\n            ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);\n            if (!ret) {\n                break;\n            }\n            secp256k1_scalar_set_b32(&non, nonce32, &overflow);\n            if (!overflow && !secp256k1_scalar_is_zero(&non)) {\n                if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) {\n                    break;\n                }\n            }\n            count++;\n        }\n        memset(nonce32, 0, 32);\n        secp256k1_scalar_clear(&msg);\n        secp256k1_scalar_clear(&non);\n        secp256k1_scalar_clear(&sec);\n    }\n    if (ret) {\n        secp256k1_ecdsa_signature_save(signature, &r, &s);\n    } else {\n        memset(signature, 0, sizeof(*signature));\n    }\n    return ret;\n}\n\nint secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) {\n    secp256k1_scalar sec;\n    int ret;\n    int overflow;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(seckey != NULL);\n\n    secp256k1_scalar_set_b32(&sec, seckey, &overflow);\n    ret = !overflow && !secp256k1_scalar_is_zero(&sec);\n    secp256k1_scalar_clear(&sec);\n    return ret;\n}\n\nint secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) {\n    secp256k1_gej pj;\n    secp256k1_ge p;\n    secp256k1_scalar sec;\n    int overflow;\n    int ret = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(pubkey != NULL);\n    memset(pubkey, 0, sizeof(*pubkey));\n    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));\n    ARG_CHECK(seckey != NULL);\n\n    secp256k1_scalar_set_b32(&sec, seckey, &overflow);\n    ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec));\n    if (ret) {\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);\n        secp256k1_ge_set_gej(&p, &pj);\n        secp256k1_pubkey_save(pubkey, &p);\n    }\n    secp256k1_scalar_clear(&sec);\n    return ret;\n}\n\nint secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {\n    secp256k1_scalar sec;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(seckey != NULL);\n\n    secp256k1_scalar_set_b32(&sec, seckey, NULL);\n    secp256k1_scalar_negate(&sec, &sec);\n    secp256k1_scalar_get_b32(seckey, &sec);\n\n    return 1;\n}\n\nint secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {\n    int ret = 0;\n    secp256k1_ge p;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(pubkey != NULL);\n\n    ret = secp256k1_pubkey_load(ctx, &p, pubkey);\n    memset(pubkey, 0, sizeof(*pubkey));\n    if (ret) {\n        secp256k1_ge_neg(&p, &p);\n        secp256k1_pubkey_save(pubkey, &p);\n    }\n    return ret;\n}\n\nint secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {\n    secp256k1_scalar term;\n    secp256k1_scalar sec;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(seckey != NULL);\n    ARG_CHECK(tweak != NULL);\n\n    secp256k1_scalar_set_b32(&term, tweak, &overflow);\n    secp256k1_scalar_set_b32(&sec, seckey, NULL);\n\n    ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term);\n    memset(seckey, 0, 32);\n    if (ret) {\n        secp256k1_scalar_get_b32(seckey, &sec);\n    }\n\n    secp256k1_scalar_clear(&sec);\n    secp256k1_scalar_clear(&term);\n    return ret;\n}\n\nint secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {\n    secp256k1_ge p;\n    secp256k1_scalar term;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));\n    ARG_CHECK(pubkey != NULL);\n    ARG_CHECK(tweak != NULL);\n\n    secp256k1_scalar_set_b32(&term, tweak, &overflow);\n    ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);\n    memset(pubkey, 0, sizeof(*pubkey));\n    if (ret) {\n        if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) {\n            secp256k1_pubkey_save(pubkey, &p);\n        } else {\n            ret = 0;\n        }\n    }\n\n    return ret;\n}\n\nint secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {\n    secp256k1_scalar factor;\n    secp256k1_scalar sec;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(seckey != NULL);\n    ARG_CHECK(tweak != NULL);\n\n    secp256k1_scalar_set_b32(&factor, tweak, &overflow);\n    secp256k1_scalar_set_b32(&sec, seckey, NULL);\n    ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor);\n    memset(seckey, 0, 32);\n    if (ret) {\n        secp256k1_scalar_get_b32(seckey, &sec);\n    }\n\n    secp256k1_scalar_clear(&sec);\n    secp256k1_scalar_clear(&factor);\n    return ret;\n}\n\nint secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) {\n    secp256k1_ge p;\n    secp256k1_scalar factor;\n    int ret = 0;\n    int overflow = 0;\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));\n    ARG_CHECK(pubkey != NULL);\n    ARG_CHECK(tweak != NULL);\n\n    secp256k1_scalar_set_b32(&factor, tweak, &overflow);\n    ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey);\n    memset(pubkey, 0, sizeof(*pubkey));\n    if (ret) {\n        if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) {\n            secp256k1_pubkey_save(pubkey, &p);\n        } else {\n            ret = 0;\n        }\n    }\n\n    return ret;\n}\n\nint secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {\n    VERIFY_CHECK(ctx != NULL);\n    ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));\n    secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);\n    return 1;\n}\n\nint secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) {\n    size_t i;\n    secp256k1_gej Qj;\n    secp256k1_ge Q;\n\n    ARG_CHECK(pubnonce != NULL);\n    memset(pubnonce, 0, sizeof(*pubnonce));\n    ARG_CHECK(n >= 1);\n    ARG_CHECK(pubnonces != NULL);\n\n    secp256k1_gej_set_infinity(&Qj);\n\n    for (i = 0; i < n; i++) {\n        secp256k1_pubkey_load(ctx, &Q, pubnonces[i]);\n        secp256k1_gej_add_ge(&Qj, &Qj, &Q);\n    }\n    if (secp256k1_gej_is_infinity(&Qj)) {\n        return 0;\n    }\n    secp256k1_ge_set_gej(&Q, &Qj);\n    secp256k1_pubkey_save(pubnonce, &Q);\n    return 1;\n}\n\n#ifdef ENABLE_MODULE_ECDH\n# include \"modules/ecdh/main_impl.h\"\n#endif\n\n#ifdef ENABLE_MODULE_RECOVERY\n# include \"modules/recovery/main_impl.h\"\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/testrand.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_TESTRAND_H_\n#define _SECP256K1_TESTRAND_H_\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n/* A non-cryptographic RNG used only for test infrastructure. */\n\n/** Seed the pseudorandom number generator for testing. */\nSECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16);\n\n/** Generate a pseudorandom number in the range [0..2**32-1]. */\nstatic uint32_t secp256k1_rand32(void);\n\n/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or\n *  more. */\nstatic uint32_t secp256k1_rand_bits(int bits);\n\n/** Generate a pseudorandom number in the range [0..range-1]. */\nstatic uint32_t secp256k1_rand_int(uint32_t range);\n\n/** Generate a pseudorandom 32-byte array. */\nstatic void secp256k1_rand256(unsigned char *b32);\n\n/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */\nstatic void secp256k1_rand256_test(unsigned char *b32);\n\n/** Generate pseudorandom bytes with long sequences of zero and one bits. */\nstatic void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/testrand_impl.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013-2015 Pieter Wuille                              *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_TESTRAND_IMPL_H_\n#define _SECP256K1_TESTRAND_IMPL_H_\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"testrand.h\"\n#include \"hash.h\"\n\nstatic secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng;\nstatic uint32_t secp256k1_test_rng_precomputed[8];\nstatic int secp256k1_test_rng_precomputed_used = 8;\nstatic uint64_t secp256k1_test_rng_integer;\nstatic int secp256k1_test_rng_integer_bits_left = 0;\n\nSECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) {\n    secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16);\n}\n\nSECP256K1_INLINE static uint32_t secp256k1_rand32(void) {\n    if (secp256k1_test_rng_precomputed_used == 8) {\n        secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed));\n        secp256k1_test_rng_precomputed_used = 0;\n    }\n    return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++];\n}\n\nstatic uint32_t secp256k1_rand_bits(int bits) {\n    uint32_t ret;\n    if (secp256k1_test_rng_integer_bits_left < bits) {\n        secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left);\n        secp256k1_test_rng_integer_bits_left += 32;\n    }\n    ret = secp256k1_test_rng_integer;\n    secp256k1_test_rng_integer >>= bits;\n    secp256k1_test_rng_integer_bits_left -= bits;\n    ret &= ((~((uint32_t)0)) >> (32 - bits));\n    return ret;\n}\n\nstatic uint32_t secp256k1_rand_int(uint32_t range) {\n    /* We want a uniform integer between 0 and range-1, inclusive.\n     * B is the smallest number such that range <= 2**B.\n     * two mechanisms implemented here:\n     * - generate B bits numbers until one below range is found, and return it\n     * - find the largest multiple M of range that is <= 2**(B+A), generate B+A\n     *   bits numbers until one below M is found, and return it modulo range\n     * The second mechanism consumes A more bits of entropy in every iteration,\n     * but may need fewer iterations due to M being closer to 2**(B+A) then\n     * range is to 2**B. The array below (indexed by B) contains a 0 when the\n     * first mechanism is to be used, and the number A otherwise.\n     */\n    static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0};\n    uint32_t trange, mult;\n    int bits = 0;\n    if (range <= 1) {\n        return 0;\n    }\n    trange = range - 1;\n    while (trange > 0) {\n        trange >>= 1;\n        bits++;\n    }\n    if (addbits[bits]) {\n        bits = bits + addbits[bits];\n        mult = ((~((uint32_t)0)) >> (32 - bits)) / range;\n        trange = range * mult;\n    } else {\n        trange = range;\n        mult = 1;\n    }\n    while(1) {\n        uint32_t x = secp256k1_rand_bits(bits);\n        if (x < trange) {\n            return (mult == 1) ? x : (x % range);\n        }\n    }\n}\n\nstatic void secp256k1_rand256(unsigned char *b32) {\n    secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32);\n}\n\nstatic void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) {\n    size_t bits = 0;\n    memset(bytes, 0, len);\n    while (bits < len * 8) {\n        int now;\n        uint32_t val;\n        now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31;\n        val = secp256k1_rand_bits(1);\n        while (now > 0 && bits < len * 8) {\n            bytes[bits / 8] |= val << (bits % 8);\n            now--;\n            bits++;\n        }\n    }\n}\n\nstatic void secp256k1_rand256_test(unsigned char *b32) {\n    secp256k1_rand_bytes_test(b32, 32);\n}\n\n#endif\n"
  },
  {
    "path": "src/secp256k1/src/tests.c",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell      *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <time.h>\n\n#include \"secp256k1.c\"\n#include \"include/secp256k1.h\"\n#include \"testrand_impl.h\"\n\n#ifdef ENABLE_OPENSSL_TESTS\n#include \"openssl/bn.h\"\n#include \"openssl/ec.h\"\n#include \"openssl/ecdsa.h\"\n#include \"openssl/obj_mac.h\"\n#endif\n\n#include \"contrib/lax_der_parsing.c\"\n#include \"contrib/lax_der_privatekey_parsing.c\"\n\n#if !defined(VG_CHECK)\n# if defined(VALGRIND)\n#  include <valgrind/memcheck.h>\n#  define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))\n#  define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))\n# else\n#  define VG_UNDEF(x,y)\n#  define VG_CHECK(x,y)\n# endif\n#endif\n\nstatic int count = 64;\nstatic secp256k1_context *ctx = NULL;\n\nstatic void counting_illegal_callback_fn(const char* str, void* data) {\n    /* Dummy callback function that just counts. */\n    int32_t *p;\n    (void)str;\n    p = data;\n    (*p)++;\n}\n\nstatic void uncounting_illegal_callback_fn(const char* str, void* data) {\n    /* Dummy callback function that just counts (backwards). */\n    int32_t *p;\n    (void)str;\n    p = data;\n    (*p)--;\n}\n\nvoid random_field_element_test(secp256k1_fe *fe) {\n    do {\n        unsigned char b32[32];\n        secp256k1_rand256_test(b32);\n        if (secp256k1_fe_set_b32(fe, b32)) {\n            break;\n        }\n    } while(1);\n}\n\nvoid random_field_element_magnitude(secp256k1_fe *fe) {\n    secp256k1_fe zero;\n    int n = secp256k1_rand_int(9);\n    secp256k1_fe_normalize(fe);\n    if (n == 0) {\n        return;\n    }\n    secp256k1_fe_clear(&zero);\n    secp256k1_fe_negate(&zero, &zero, 0);\n    secp256k1_fe_mul_int(&zero, n - 1);\n    secp256k1_fe_add(fe, &zero);\n    VERIFY_CHECK(fe->magnitude == n);\n}\n\nvoid random_group_element_test(secp256k1_ge *ge) {\n    secp256k1_fe fe;\n    do {\n        random_field_element_test(&fe);\n        if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) {\n            secp256k1_fe_normalize(&ge->y);\n            break;\n        }\n    } while(1);\n}\n\nvoid random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) {\n    secp256k1_fe z2, z3;\n    do {\n        random_field_element_test(&gej->z);\n        if (!secp256k1_fe_is_zero(&gej->z)) {\n            break;\n        }\n    } while(1);\n    secp256k1_fe_sqr(&z2, &gej->z);\n    secp256k1_fe_mul(&z3, &z2, &gej->z);\n    secp256k1_fe_mul(&gej->x, &ge->x, &z2);\n    secp256k1_fe_mul(&gej->y, &ge->y, &z3);\n    gej->infinity = ge->infinity;\n}\n\nvoid random_scalar_order_test(secp256k1_scalar *num) {\n    do {\n        unsigned char b32[32];\n        int overflow = 0;\n        secp256k1_rand256_test(b32);\n        secp256k1_scalar_set_b32(num, b32, &overflow);\n        if (overflow || secp256k1_scalar_is_zero(num)) {\n            continue;\n        }\n        break;\n    } while(1);\n}\n\nvoid random_scalar_order(secp256k1_scalar *num) {\n    do {\n        unsigned char b32[32];\n        int overflow = 0;\n        secp256k1_rand256(b32);\n        secp256k1_scalar_set_b32(num, b32, &overflow);\n        if (overflow || secp256k1_scalar_is_zero(num)) {\n            continue;\n        }\n        break;\n    } while(1);\n}\n\nvoid run_context_tests(void) {\n    secp256k1_pubkey pubkey;\n    secp256k1_pubkey zero_pubkey;\n    secp256k1_ecdsa_signature sig;\n    unsigned char ctmp[32];\n    int32_t ecount;\n    int32_t ecount2;\n    secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n    secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);\n    secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n\n    secp256k1_gej pubj;\n    secp256k1_ge pub;\n    secp256k1_scalar msg, key, nonce;\n    secp256k1_scalar sigr, sigs;\n\n    memset(&zero_pubkey, 0, sizeof(zero_pubkey));\n\n    ecount = 0;\n    ecount2 = 10;\n    secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);\n    secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);\n    secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL);\n    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);\n\n    /*** clone and destroy all of them to make sure cloning was complete ***/\n    {\n        secp256k1_context *ctx_tmp;\n\n        ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp);\n        ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp);\n        ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp);\n        ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp);\n    }\n\n    /* Verify that the error callback makes it across the clone. */\n    CHECK(vrfy->error_callback.fn != sign->error_callback.fn);\n    /* And that it resets back to default. */\n    secp256k1_context_set_error_callback(sign, NULL, NULL);\n    CHECK(vrfy->error_callback.fn == sign->error_callback.fn);\n\n    /*** attempt to use them ***/\n    random_scalar_order_test(&msg);\n    random_scalar_order_test(&key);\n    secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key);\n    secp256k1_ge_set_gej(&pub, &pubj);\n\n    /* Verify context-type checking illegal-argument errors. */\n    memset(ctmp, 1, 32);\n    CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0);\n    CHECK(ecount == 1);\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0);\n    CHECK(ecount == 2);\n    VG_UNDEF(&sig, sizeof(sig));\n    CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1);\n    VG_CHECK(&sig, sizeof(sig));\n    CHECK(ecount2 == 10);\n    CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0);\n    CHECK(ecount2 == 11);\n    CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0);\n    CHECK(ecount2 == 12);\n    CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);\n    CHECK(ecount2 == 13);\n    CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);\n    CHECK(ecount == 2);\n    CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);\n    CHECK(ecount2 == 14);\n    CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);\n    CHECK(ecount == 3);\n    CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);\n    CHECK(ecount == 4);\n    CHECK(secp256k1_context_randomize(sign, NULL) == 1);\n    CHECK(ecount2 == 14);\n    secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);\n    secp256k1_context_set_illegal_callback(sign, NULL, NULL);\n\n    /* This shouldn't leak memory, due to already-set tests. */\n    secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL);\n    secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL);\n\n    /* obtain a working nonce */\n    do {\n        random_scalar_order_test(&nonce);\n    } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));\n\n    /* try signing */\n    CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));\n    CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));\n\n    /* try verifying */\n    CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg));\n    CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg));\n\n    /* cleanup */\n    secp256k1_context_destroy(none);\n    secp256k1_context_destroy(sign);\n    secp256k1_context_destroy(vrfy);\n    secp256k1_context_destroy(both);\n    /* Defined as no-op. */\n    secp256k1_context_destroy(NULL);\n}\n\n/***** HASH TESTS *****/\n\nvoid run_sha256_tests(void) {\n    static const char *inputs[8] = {\n        \"\", \"abc\", \"message digest\", \"secure hash algorithm\", \"SHA256 is considered to be safe\",\n        \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n        \"For this sample, this 63-byte string will be used as input data\",\n        \"This is exactly 64 bytes long, not counting the terminating byte\"\n    };\n    static const unsigned char outputs[8][32] = {\n        {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},\n        {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},\n        {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},\n        {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d},\n        {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},\n        {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},\n        {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},\n        {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}\n    };\n    int i;\n    for (i = 0; i < 8; i++) {\n        unsigned char out[32];\n        secp256k1_sha256_t hasher;\n        secp256k1_sha256_initialize(&hasher);\n        secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));\n        secp256k1_sha256_finalize(&hasher, out);\n        CHECK(memcmp(out, outputs[i], 32) == 0);\n        if (strlen(inputs[i]) > 0) {\n            int split = secp256k1_rand_int(strlen(inputs[i]));\n            secp256k1_sha256_initialize(&hasher);\n            secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);\n            secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);\n            secp256k1_sha256_finalize(&hasher, out);\n            CHECK(memcmp(out, outputs[i], 32) == 0);\n        }\n    }\n}\n\nvoid run_hmac_sha256_tests(void) {\n    static const char *keys[6] = {\n        \"\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\",\n        \"\\x4a\\x65\\x66\\x65\",\n        \"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\",\n        \"\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\",\n        \"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\",\n        \"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\"\n    };\n    static const char *inputs[6] = {\n        \"\\x48\\x69\\x20\\x54\\x68\\x65\\x72\\x65\",\n        \"\\x77\\x68\\x61\\x74\\x20\\x64\\x6f\\x20\\x79\\x61\\x20\\x77\\x61\\x6e\\x74\\x20\\x66\\x6f\\x72\\x20\\x6e\\x6f\\x74\\x68\\x69\\x6e\\x67\\x3f\",\n        \"\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\",\n        \"\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\",\n        \"\\x54\\x65\\x73\\x74\\x20\\x55\\x73\\x69\\x6e\\x67\\x20\\x4c\\x61\\x72\\x67\\x65\\x72\\x20\\x54\\x68\\x61\\x6e\\x20\\x42\\x6c\\x6f\\x63\\x6b\\x2d\\x53\\x69\\x7a\\x65\\x20\\x4b\\x65\\x79\\x20\\x2d\\x20\\x48\\x61\\x73\\x68\\x20\\x4b\\x65\\x79\\x20\\x46\\x69\\x72\\x73\\x74\",\n        \"\\x54\\x68\\x69\\x73\\x20\\x69\\x73\\x20\\x61\\x20\\x74\\x65\\x73\\x74\\x20\\x75\\x73\\x69\\x6e\\x67\\x20\\x61\\x20\\x6c\\x61\\x72\\x67\\x65\\x72\\x20\\x74\\x68\\x61\\x6e\\x20\\x62\\x6c\\x6f\\x63\\x6b\\x2d\\x73\\x69\\x7a\\x65\\x20\\x6b\\x65\\x79\\x20\\x61\\x6e\\x64\\x20\\x61\\x20\\x6c\\x61\\x72\\x67\\x65\\x72\\x20\\x74\\x68\\x61\\x6e\\x20\\x62\\x6c\\x6f\\x63\\x6b\\x2d\\x73\\x69\\x7a\\x65\\x20\\x64\\x61\\x74\\x61\\x2e\\x20\\x54\\x68\\x65\\x20\\x6b\\x65\\x79\\x20\\x6e\\x65\\x65\\x64\\x73\\x20\\x74\\x6f\\x20\\x62\\x65\\x20\\x68\\x61\\x73\\x68\\x65\\x64\\x20\\x62\\x65\\x66\\x6f\\x72\\x65\\x20\\x62\\x65\\x69\\x6e\\x67\\x20\\x75\\x73\\x65\\x64\\x20\\x62\\x79\\x20\\x74\\x68\\x65\\x20\\x48\\x4d\\x41\\x43\\x20\\x61\\x6c\\x67\\x6f\\x72\\x69\\x74\\x68\\x6d\\x2e\"\n    };\n    static const unsigned char outputs[6][32] = {\n        {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7},\n        {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43},\n        {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe},\n        {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b},\n        {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54},\n        {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2}\n    };\n    int i;\n    for (i = 0; i < 6; i++) {\n        secp256k1_hmac_sha256_t hasher;\n        unsigned char out[32];\n        secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));\n        secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));\n        secp256k1_hmac_sha256_finalize(&hasher, out);\n        CHECK(memcmp(out, outputs[i], 32) == 0);\n        if (strlen(inputs[i]) > 0) {\n            int split = secp256k1_rand_int(strlen(inputs[i]));\n            secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));\n            secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);\n            secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);\n            secp256k1_hmac_sha256_finalize(&hasher, out);\n            CHECK(memcmp(out, outputs[i], 32) == 0);\n        }\n    }\n}\n\nvoid run_rfc6979_hmac_sha256_tests(void) {\n    static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0};\n    static const unsigned char out1[3][32] = {\n        {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb},\n        {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a},\n        {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e}\n    };\n\n    static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};\n    static const unsigned char out2[3][32] = {\n        {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95},\n        {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9},\n        {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94}\n    };\n\n    secp256k1_rfc6979_hmac_sha256_t rng;\n    unsigned char out[32];\n    int i;\n\n    secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64);\n    for (i = 0; i < 3; i++) {\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);\n        CHECK(memcmp(out, out1[i], 32) == 0);\n    }\n    secp256k1_rfc6979_hmac_sha256_finalize(&rng);\n\n    secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65);\n    for (i = 0; i < 3; i++) {\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);\n        CHECK(memcmp(out, out1[i], 32) != 0);\n    }\n    secp256k1_rfc6979_hmac_sha256_finalize(&rng);\n\n    secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64);\n    for (i = 0; i < 3; i++) {\n        secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);\n        CHECK(memcmp(out, out2[i], 32) == 0);\n    }\n    secp256k1_rfc6979_hmac_sha256_finalize(&rng);\n}\n\n/***** RANDOM TESTS *****/\n\nvoid test_rand_bits(int rand32, int bits) {\n    /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to\n     * get a false negative chance below once in a billion */\n    static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316};\n    /* We try multiplying the results with various odd numbers, which shouldn't\n     * influence the uniform distribution modulo a power of 2. */\n    static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011};\n    /* We only select up to 6 bits from the output to analyse */\n    unsigned int usebits = bits > 6 ? 6 : bits;\n    unsigned int maxshift = bits - usebits;\n    /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit\n       number, track all observed outcomes, one per bit in a uint64_t. */\n    uint64_t x[6][27] = {{0}};\n    unsigned int i, shift, m;\n    /* Multiply the output of all rand calls with the odd number m, which\n       should not change the uniformity of its distribution. */\n    for (i = 0; i < rounds[usebits]; i++) {\n        uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits));\n        CHECK((((uint64_t)r) >> bits) == 0);\n        for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) {\n            uint32_t rm = r * mults[m];\n            for (shift = 0; shift <= maxshift; shift++) {\n                x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1)));\n            }\n        }\n    }\n    for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) {\n        for (shift = 0; shift <= maxshift; shift++) {\n            /* Test that the lower usebits bits of x[shift] are 1 */\n            CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0);\n        }\n    }\n}\n\n/* Subrange must be a whole divisor of range, and at most 64 */\nvoid test_rand_int(uint32_t range, uint32_t subrange) {\n    /* (1-1/subrange)^rounds < 1/10^9 */\n    int rounds = (subrange * 2073) / 100;\n    int i;\n    uint64_t x = 0;\n    CHECK((range % subrange) == 0);\n    for (i = 0; i < rounds; i++) {\n        uint32_t r = secp256k1_rand_int(range);\n        CHECK(r < range);\n        r = r % subrange;\n        x |= (((uint64_t)1) << r);\n    }\n    /* Test that the lower subrange bits of x are 1. */\n    CHECK(((~x) << (64 - subrange)) == 0);\n}\n\nvoid run_rand_bits(void) {\n    size_t b;\n    test_rand_bits(1, 32);\n    for (b = 1; b <= 32; b++) {\n        test_rand_bits(0, b);\n    }\n}\n\nvoid run_rand_int(void) {\n    static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432};\n    static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64};\n    unsigned int m, s;\n    for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) {\n        for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) {\n            test_rand_int(ms[m] * ss[s], ss[s]);\n        }\n    }\n}\n\n/***** NUM TESTS *****/\n\n#ifndef USE_NUM_NONE\nvoid random_num_negate(secp256k1_num *num) {\n    if (secp256k1_rand_bits(1)) {\n        secp256k1_num_negate(num);\n    }\n}\n\nvoid random_num_order_test(secp256k1_num *num) {\n    secp256k1_scalar sc;\n    random_scalar_order_test(&sc);\n    secp256k1_scalar_get_num(num, &sc);\n}\n\nvoid random_num_order(secp256k1_num *num) {\n    secp256k1_scalar sc;\n    random_scalar_order(&sc);\n    secp256k1_scalar_get_num(num, &sc);\n}\n\nvoid test_num_negate(void) {\n    secp256k1_num n1;\n    secp256k1_num n2;\n    random_num_order_test(&n1); /* n1 = R */\n    random_num_negate(&n1);\n    secp256k1_num_copy(&n2, &n1); /* n2 = R */\n    secp256k1_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */\n    CHECK(secp256k1_num_is_zero(&n1));\n    secp256k1_num_copy(&n1, &n2); /* n1 = R */\n    secp256k1_num_negate(&n1); /* n1 = -R */\n    CHECK(!secp256k1_num_is_zero(&n1));\n    secp256k1_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */\n    CHECK(secp256k1_num_is_zero(&n1));\n    secp256k1_num_copy(&n1, &n2); /* n1 = R */\n    secp256k1_num_negate(&n1); /* n1 = -R */\n    CHECK(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2));\n    secp256k1_num_negate(&n1); /* n1 = R */\n    CHECK(secp256k1_num_eq(&n1, &n2));\n}\n\nvoid test_num_add_sub(void) {\n    int i;\n    secp256k1_scalar s;\n    secp256k1_num n1;\n    secp256k1_num n2;\n    secp256k1_num n1p2, n2p1, n1m2, n2m1;\n    random_num_order_test(&n1); /* n1 = R1 */\n    if (secp256k1_rand_bits(1)) {\n        random_num_negate(&n1);\n    }\n    random_num_order_test(&n2); /* n2 = R2 */\n    if (secp256k1_rand_bits(1)) {\n        random_num_negate(&n2);\n    }\n    secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */\n    secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */\n    secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */\n    secp256k1_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */\n    CHECK(secp256k1_num_eq(&n1p2, &n2p1));\n    CHECK(!secp256k1_num_eq(&n1p2, &n1m2));\n    secp256k1_num_negate(&n2m1); /* n2m1 = -R2 + R1 */\n    CHECK(secp256k1_num_eq(&n2m1, &n1m2));\n    CHECK(!secp256k1_num_eq(&n2m1, &n1));\n    secp256k1_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */\n    CHECK(secp256k1_num_eq(&n2m1, &n1));\n    CHECK(!secp256k1_num_eq(&n2p1, &n1));\n    secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */\n    CHECK(secp256k1_num_eq(&n2p1, &n1));\n\n    /* check is_one */\n    secp256k1_scalar_set_int(&s, 1);\n    secp256k1_scalar_get_num(&n1, &s);\n    CHECK(secp256k1_num_is_one(&n1));\n    /* check that 2^n + 1 is never 1 */\n    secp256k1_scalar_get_num(&n2, &s);\n    for (i = 0; i < 250; ++i) {\n        secp256k1_num_add(&n1, &n1, &n1);    /* n1 *= 2 */\n        secp256k1_num_add(&n1p2, &n1, &n2);  /* n1p2 = n1 + 1 */\n        CHECK(!secp256k1_num_is_one(&n1p2));\n    }\n}\n\nvoid test_num_mod(void) {\n    int i;\n    secp256k1_scalar s;\n    secp256k1_num order, n;\n\n    /* check that 0 mod anything is 0 */\n    random_scalar_order_test(&s);\n    secp256k1_scalar_get_num(&order, &s);\n    secp256k1_scalar_set_int(&s, 0);\n    secp256k1_scalar_get_num(&n, &s);\n    secp256k1_num_mod(&n, &order);\n    CHECK(secp256k1_num_is_zero(&n));\n\n    /* check that anything mod 1 is 0 */\n    secp256k1_scalar_set_int(&s, 1);\n    secp256k1_scalar_get_num(&order, &s);\n    secp256k1_scalar_get_num(&n, &s);\n    secp256k1_num_mod(&n, &order);\n    CHECK(secp256k1_num_is_zero(&n));\n\n    /* check that increasing the number past 2^256 does not break this */\n    random_scalar_order_test(&s);\n    secp256k1_scalar_get_num(&n, &s);\n    /* multiply by 2^8, which'll test this case with high probability */\n    for (i = 0; i < 8; ++i) {\n        secp256k1_num_add(&n, &n, &n);\n    }\n    secp256k1_num_mod(&n, &order);\n    CHECK(secp256k1_num_is_zero(&n));\n}\n\nvoid test_num_jacobi(void) {\n    secp256k1_scalar sqr;\n    secp256k1_scalar small;\n    secp256k1_scalar five;  /* five is not a quadratic residue */\n    secp256k1_num order, n;\n    int i;\n    /* squares mod 5 are 1, 4 */\n    const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 };\n\n    /* check some small values with 5 as the order */\n    secp256k1_scalar_set_int(&five, 5);\n    secp256k1_scalar_get_num(&order, &five);\n    for (i = 0; i < 10; ++i) {\n        secp256k1_scalar_set_int(&small, i);\n        secp256k1_scalar_get_num(&n, &small);\n        CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]);\n    }\n\n    /** test large values with 5 as group order */\n    secp256k1_scalar_get_num(&order, &five);\n    /* we first need a scalar which is not a multiple of 5 */\n    do {\n        secp256k1_num fiven;\n        random_scalar_order_test(&sqr);\n        secp256k1_scalar_get_num(&fiven, &five);\n        secp256k1_scalar_get_num(&n, &sqr);\n        secp256k1_num_mod(&n, &fiven);\n    } while (secp256k1_num_is_zero(&n));\n    /* next force it to be a residue. 2 is a nonresidue mod 5 so we can\n     * just multiply by two, i.e. add the number to itself */\n    if (secp256k1_num_jacobi(&n, &order) == -1) {\n        secp256k1_num_add(&n, &n, &n);\n    }\n\n    /* test residue */\n    CHECK(secp256k1_num_jacobi(&n, &order) == 1);\n    /* test nonresidue */\n    secp256k1_num_add(&n, &n, &n);\n    CHECK(secp256k1_num_jacobi(&n, &order) == -1);\n\n    /** test with secp group order as order */\n    secp256k1_scalar_order_get_num(&order);\n    random_scalar_order_test(&sqr);\n    secp256k1_scalar_sqr(&sqr, &sqr);\n    /* test residue */\n    secp256k1_scalar_get_num(&n, &sqr);\n    CHECK(secp256k1_num_jacobi(&n, &order) == 1);\n    /* test nonresidue */\n    secp256k1_scalar_mul(&sqr, &sqr, &five);\n    secp256k1_scalar_get_num(&n, &sqr);\n    CHECK(secp256k1_num_jacobi(&n, &order) == -1);\n    /* test multiple of the order*/\n    CHECK(secp256k1_num_jacobi(&order, &order) == 0);\n\n    /* check one less than the order */\n    secp256k1_scalar_set_int(&small, 1);\n    secp256k1_scalar_get_num(&n, &small);\n    secp256k1_num_sub(&n, &order, &n);\n    CHECK(secp256k1_num_jacobi(&n, &order) == 1);  /* sage confirms this is 1 */\n}\n\nvoid run_num_smalltests(void) {\n    int i;\n    for (i = 0; i < 100*count; i++) {\n        test_num_negate();\n        test_num_add_sub();\n        test_num_mod();\n        test_num_jacobi();\n    }\n}\n#endif\n\n/***** SCALAR TESTS *****/\n\nvoid scalar_test(void) {\n    secp256k1_scalar s;\n    secp256k1_scalar s1;\n    secp256k1_scalar s2;\n#ifndef USE_NUM_NONE\n    secp256k1_num snum, s1num, s2num;\n    secp256k1_num order, half_order;\n#endif\n    unsigned char c[32];\n\n    /* Set 's' to a random scalar, with value 'snum'. */\n    random_scalar_order_test(&s);\n\n    /* Set 's1' to a random scalar, with value 's1num'. */\n    random_scalar_order_test(&s1);\n\n    /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */\n    random_scalar_order_test(&s2);\n    secp256k1_scalar_get_b32(c, &s2);\n\n#ifndef USE_NUM_NONE\n    secp256k1_scalar_get_num(&snum, &s);\n    secp256k1_scalar_get_num(&s1num, &s1);\n    secp256k1_scalar_get_num(&s2num, &s2);\n\n    secp256k1_scalar_order_get_num(&order);\n    half_order = order;\n    secp256k1_num_shift(&half_order, 1);\n#endif\n\n    {\n        int i;\n        /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */\n        secp256k1_scalar n;\n        secp256k1_scalar_set_int(&n, 0);\n        for (i = 0; i < 256; i += 4) {\n            secp256k1_scalar t;\n            int j;\n            secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));\n            for (j = 0; j < 4; j++) {\n                secp256k1_scalar_add(&n, &n, &n);\n            }\n            secp256k1_scalar_add(&n, &n, &t);\n        }\n        CHECK(secp256k1_scalar_eq(&n, &s));\n    }\n\n    {\n        /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */\n        secp256k1_scalar n;\n        int i = 0;\n        secp256k1_scalar_set_int(&n, 0);\n        while (i < 256) {\n            secp256k1_scalar t;\n            int j;\n            int now = secp256k1_rand_int(15) + 1;\n            if (now + i > 256) {\n                now = 256 - i;\n            }\n            secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now));\n            for (j = 0; j < now; j++) {\n                secp256k1_scalar_add(&n, &n, &n);\n            }\n            secp256k1_scalar_add(&n, &n, &t);\n            i += now;\n        }\n        CHECK(secp256k1_scalar_eq(&n, &s));\n    }\n\n#ifndef USE_NUM_NONE\n    {\n        /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */\n        secp256k1_num rnum;\n        secp256k1_num r2num;\n        secp256k1_scalar r;\n        secp256k1_num_add(&rnum, &snum, &s2num);\n        secp256k1_num_mod(&rnum, &order);\n        secp256k1_scalar_add(&r, &s, &s2);\n        secp256k1_scalar_get_num(&r2num, &r);\n        CHECK(secp256k1_num_eq(&rnum, &r2num));\n    }\n\n    {\n        /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */\n        secp256k1_scalar r;\n        secp256k1_num r2num;\n        secp256k1_num rnum;\n        secp256k1_num_mul(&rnum, &snum, &s2num);\n        secp256k1_num_mod(&rnum, &order);\n        secp256k1_scalar_mul(&r, &s, &s2);\n        secp256k1_scalar_get_num(&r2num, &r);\n        CHECK(secp256k1_num_eq(&rnum, &r2num));\n        /* The result can only be zero if at least one of the factors was zero. */\n        CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2)));\n        /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */\n        CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2)));\n        CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s)));\n    }\n\n    {\n        secp256k1_scalar neg;\n        secp256k1_num negnum;\n        secp256k1_num negnum2;\n        /* Check that comparison with zero matches comparison with zero on the number. */\n        CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));\n        /* Check that comparison with the half order is equal to testing for high scalar. */\n        CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0));\n        secp256k1_scalar_negate(&neg, &s);\n        secp256k1_num_sub(&negnum, &order, &snum);\n        secp256k1_num_mod(&negnum, &order);\n        /* Check that comparison with the half order is equal to testing for high scalar after negation. */\n        CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0));\n        /* Negating should change the high property, unless the value was already zero. */\n        CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s));\n        secp256k1_scalar_get_num(&negnum2, &neg);\n        /* Negating a scalar should be equal to (order - n) mod order on the number. */\n        CHECK(secp256k1_num_eq(&negnum, &negnum2));\n        secp256k1_scalar_add(&neg, &neg, &s);\n        /* Adding a number to its negation should result in zero. */\n        CHECK(secp256k1_scalar_is_zero(&neg));\n        secp256k1_scalar_negate(&neg, &neg);\n        /* Negating zero should still result in zero. */\n        CHECK(secp256k1_scalar_is_zero(&neg));\n    }\n\n    {\n        /* Test secp256k1_scalar_mul_shift_var. */\n        secp256k1_scalar r;\n        secp256k1_num one;\n        secp256k1_num rnum;\n        secp256k1_num rnum2;\n        unsigned char cone[1] = {0x01};\n        unsigned int shift = 256 + secp256k1_rand_int(257);\n        secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift);\n        secp256k1_num_mul(&rnum, &s1num, &s2num);\n        secp256k1_num_shift(&rnum, shift - 1);\n        secp256k1_num_set_bin(&one, cone, 1);\n        secp256k1_num_add(&rnum, &rnum, &one);\n        secp256k1_num_shift(&rnum, 1);\n        secp256k1_scalar_get_num(&rnum2, &r);\n        CHECK(secp256k1_num_eq(&rnum, &rnum2));\n    }\n\n    {\n        /* test secp256k1_scalar_shr_int */\n        secp256k1_scalar r;\n        int i;\n        random_scalar_order_test(&r);\n        for (i = 0; i < 100; ++i) {\n            int low;\n            int shift = 1 + secp256k1_rand_int(15);\n            int expected = r.d[0] % (1 << shift);\n            low = secp256k1_scalar_shr_int(&r, shift);\n            CHECK(expected == low);\n        }\n    }\n#endif\n\n    {\n        /* Test that scalar inverses are equal to the inverse of their number modulo the order. */\n        if (!secp256k1_scalar_is_zero(&s)) {\n            secp256k1_scalar inv;\n#ifndef USE_NUM_NONE\n            secp256k1_num invnum;\n            secp256k1_num invnum2;\n#endif\n            secp256k1_scalar_inverse(&inv, &s);\n#ifndef USE_NUM_NONE\n            secp256k1_num_mod_inverse(&invnum, &snum, &order);\n            secp256k1_scalar_get_num(&invnum2, &inv);\n            CHECK(secp256k1_num_eq(&invnum, &invnum2));\n#endif\n            secp256k1_scalar_mul(&inv, &inv, &s);\n            /* Multiplying a scalar with its inverse must result in one. */\n            CHECK(secp256k1_scalar_is_one(&inv));\n            secp256k1_scalar_inverse(&inv, &inv);\n            /* Inverting one must result in one. */\n            CHECK(secp256k1_scalar_is_one(&inv));\n#ifndef USE_NUM_NONE\n            secp256k1_scalar_get_num(&invnum, &inv);\n            CHECK(secp256k1_num_is_one(&invnum));\n#endif\n        }\n    }\n\n    {\n        /* Test commutativity of add. */\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar_add(&r1, &s1, &s2);\n        secp256k1_scalar_add(&r2, &s2, &s1);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar b;\n        int i;\n        /* Test add_bit. */\n        int bit = secp256k1_rand_bits(8);\n        secp256k1_scalar_set_int(&b, 1);\n        CHECK(secp256k1_scalar_is_one(&b));\n        for (i = 0; i < bit; i++) {\n            secp256k1_scalar_add(&b, &b, &b);\n        }\n        r1 = s1;\n        r2 = s1;\n        if (!secp256k1_scalar_add(&r1, &r1, &b)) {\n            /* No overflow happened. */\n            secp256k1_scalar_cadd_bit(&r2, bit, 1);\n            CHECK(secp256k1_scalar_eq(&r1, &r2));\n            /* cadd is a noop when flag is zero */\n            secp256k1_scalar_cadd_bit(&r2, bit, 0);\n            CHECK(secp256k1_scalar_eq(&r1, &r2));\n        }\n    }\n\n    {\n        /* Test commutativity of mul. */\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar_mul(&r1, &s1, &s2);\n        secp256k1_scalar_mul(&r2, &s2, &s1);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        /* Test associativity of add. */\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar_add(&r1, &s1, &s2);\n        secp256k1_scalar_add(&r1, &r1, &s);\n        secp256k1_scalar_add(&r2, &s2, &s);\n        secp256k1_scalar_add(&r2, &s1, &r2);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        /* Test associativity of mul. */\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar_mul(&r1, &s1, &s2);\n        secp256k1_scalar_mul(&r1, &r1, &s);\n        secp256k1_scalar_mul(&r2, &s2, &s);\n        secp256k1_scalar_mul(&r2, &s1, &r2);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        /* Test distributitivity of mul over add. */\n        secp256k1_scalar r1, r2, t;\n        secp256k1_scalar_add(&r1, &s1, &s2);\n        secp256k1_scalar_mul(&r1, &r1, &s);\n        secp256k1_scalar_mul(&r2, &s1, &s);\n        secp256k1_scalar_mul(&t, &s2, &s);\n        secp256k1_scalar_add(&r2, &r2, &t);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        /* Test square. */\n        secp256k1_scalar r1, r2;\n        secp256k1_scalar_sqr(&r1, &s1);\n        secp256k1_scalar_mul(&r2, &s1, &s1);\n        CHECK(secp256k1_scalar_eq(&r1, &r2));\n    }\n\n    {\n        /* Test multiplicative identity. */\n        secp256k1_scalar r1, v1;\n        secp256k1_scalar_set_int(&v1,1);\n        secp256k1_scalar_mul(&r1, &s1, &v1);\n        CHECK(secp256k1_scalar_eq(&r1, &s1));\n    }\n\n    {\n        /* Test additive identity. */\n        secp256k1_scalar r1, v0;\n        secp256k1_scalar_set_int(&v0,0);\n        secp256k1_scalar_add(&r1, &s1, &v0);\n        CHECK(secp256k1_scalar_eq(&r1, &s1));\n    }\n\n    {\n        /* Test zero product property. */\n        secp256k1_scalar r1, v0;\n        secp256k1_scalar_set_int(&v0,0);\n        secp256k1_scalar_mul(&r1, &s1, &v0);\n        CHECK(secp256k1_scalar_eq(&r1, &v0));\n    }\n\n}\n\nvoid run_scalar_tests(void) {\n    int i;\n    for (i = 0; i < 128 * count; i++) {\n        scalar_test();\n    }\n\n    {\n        /* (-1)+1 should be zero. */\n        secp256k1_scalar s, o;\n        secp256k1_scalar_set_int(&s, 1);\n        CHECK(secp256k1_scalar_is_one(&s));\n        secp256k1_scalar_negate(&o, &s);\n        secp256k1_scalar_add(&o, &o, &s);\n        CHECK(secp256k1_scalar_is_zero(&o));\n        secp256k1_scalar_negate(&o, &o);\n        CHECK(secp256k1_scalar_is_zero(&o));\n    }\n\n#ifndef USE_NUM_NONE\n    {\n        /* A scalar with value of the curve order should be 0. */\n        secp256k1_num order;\n        secp256k1_scalar zero;\n        unsigned char bin[32];\n        int overflow = 0;\n        secp256k1_scalar_order_get_num(&order);\n        secp256k1_num_get_bin(bin, 32, &order);\n        secp256k1_scalar_set_b32(&zero, bin, &overflow);\n        CHECK(overflow == 1);\n        CHECK(secp256k1_scalar_is_zero(&zero));\n    }\n#endif\n\n    {\n        /* Does check_overflow check catch all ones? */\n        static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST(\n            0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,\n            0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL\n        );\n        CHECK(secp256k1_scalar_check_overflow(&overflowed));\n    }\n\n    {\n        /* Static test vectors.\n         * These were reduced from ~10^12 random vectors based on comparison-decision\n         *  and edge-case coverage on 32-bit and 64-bit implementations.\n         * The responses were generated with Sage 5.9.\n         */\n        secp256k1_scalar x;\n        secp256k1_scalar y;\n        secp256k1_scalar z;\n        secp256k1_scalar zz;\n        secp256k1_scalar one;\n        secp256k1_scalar r1;\n        secp256k1_scalar r2;\n#if defined(USE_SCALAR_INV_NUM)\n        secp256k1_scalar zzv;\n#endif\n        int overflow;\n        unsigned char chal[33][2][32] = {\n            {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,\n              0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}},\n            {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n             {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,\n              0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}},\n            {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00},\n             {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,\n              0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0,\n              0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,\n              0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,\n              0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f,\n              0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f,\n              0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,\n              0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},\n             {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n              0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff,\n              0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,\n              0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00,\n              0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0},\n             {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},\n            {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff,\n              0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},\n            {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f},\n             {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,\n              0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff,\n              0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,\n              0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff},\n             {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}},\n            {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff,\n              0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,\n              0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f,\n              0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}},\n            {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00},\n             {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}},\n            {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00,\n              0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n             {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}},\n            {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,\n              0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00,\n              0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00},\n             {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},\n             {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80,\n              0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,\n              0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}},\n            {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff,\n              0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,\n              0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n              0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n              0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n             {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0,\n              0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,\n              0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}},\n            {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n              0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n              0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00,\n              0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,\n              0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n             {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},\n            {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,\n              0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}},\n            {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00},\n             {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,\n              0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,\n              0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}},\n            {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01,\n              0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},\n             {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n              0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80,\n              0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8,\n              0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80},\n             {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00,\n              0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f,\n              0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}},\n            {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00,\n              0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83,\n              0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80,\n              0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0},\n             {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,\n              0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}},\n            {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,\n              0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,\n              0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03},\n             {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,\n              0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,\n              0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}}\n        };\n        unsigned char res[33][2][32] = {\n            {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,\n              0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,\n              0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,\n              0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35},\n             {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d,\n              0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c,\n              0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49,\n              0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}},\n            {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22,\n              0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c,\n              0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f,\n              0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8},\n             {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77,\n              0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4,\n              0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59,\n              0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}},\n            {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef,\n              0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab,\n              0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55,\n              0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c},\n             {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96,\n              0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f,\n              0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12,\n              0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}},\n            {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c,\n              0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf,\n              0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9,\n              0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48},\n             {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42,\n              0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5,\n              0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c,\n              0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}},\n            {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb,\n              0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74,\n              0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6,\n              0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63},\n             {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3,\n              0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99,\n              0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58,\n              0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}},\n            {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b,\n              0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7,\n              0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f,\n              0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0},\n             {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d,\n              0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d,\n              0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9,\n              0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}},\n            {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7,\n              0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70,\n              0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06,\n              0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e},\n             {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9,\n              0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79,\n              0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e,\n              0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}},\n            {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb,\n              0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5,\n              0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a,\n              0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe},\n             {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48,\n              0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e,\n              0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc,\n              0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}},\n            {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b,\n              0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0,\n              0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53,\n              0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8},\n             {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c,\n              0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01,\n              0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f,\n              0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}},\n            {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7,\n              0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c,\n              0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92,\n              0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30},\n             {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62,\n              0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e,\n              0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb,\n              0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}},\n            {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25,\n              0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d,\n              0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0,\n              0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13},\n             {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60,\n              0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00,\n              0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4,\n              0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}},\n            {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31,\n              0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4,\n              0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88,\n              0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa},\n             {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57,\n              0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38,\n              0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51,\n              0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}},\n            {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c,\n              0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f,\n              0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2,\n              0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4},\n             {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01,\n              0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4,\n              0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86,\n              0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}},\n            {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5,\n              0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51,\n              0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3,\n              0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62},\n             {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c,\n              0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91,\n              0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c,\n              0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}},\n            {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e,\n              0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56,\n              0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58,\n              0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4},\n             {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41,\n              0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7,\n              0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92,\n              0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}},\n            {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec,\n              0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19,\n              0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3,\n              0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4},\n             {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87,\n              0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a,\n              0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92,\n              0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}},\n            {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64,\n              0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3,\n              0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f,\n              0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33},\n             {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c,\n              0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d,\n              0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea,\n              0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}},\n            {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7,\n              0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a,\n              0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae,\n              0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe},\n             {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc,\n              0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39,\n              0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14,\n              0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}},\n            {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23,\n              0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d,\n              0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2,\n              0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16},\n             {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c,\n              0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84,\n              0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0,\n              0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}},\n            {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb,\n              0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94,\n              0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b,\n              0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e},\n             {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54,\n              0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00,\n              0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb,\n              0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},\n            {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,\n              0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,\n              0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,\n              0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92},\n             {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,\n              0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,\n              0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,\n              0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}},\n            {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0,\n              0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b,\n              0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94,\n              0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8},\n             {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26,\n              0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d,\n              0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a,\n              0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}},\n            {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n              0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,\n              0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd},\n             {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1,\n              0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0,\n              0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59,\n              0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}},\n            {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n              0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n              0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40},\n             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},\n            {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39,\n              0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea,\n              0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf,\n              0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae},\n             {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b,\n              0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb,\n              0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6,\n              0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}},\n            {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a,\n              0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f,\n              0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9,\n              0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56},\n             {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93,\n              0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07,\n              0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71,\n              0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}},\n            {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87,\n              0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9,\n              0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55,\n              0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73},\n             {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d,\n              0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86,\n              0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb,\n              0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}},\n            {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2,\n              0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7,\n              0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41,\n              0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7},\n             {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06,\n              0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04,\n              0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08,\n              0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}},\n            {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2,\n              0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b,\n              0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40,\n              0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68},\n             {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e,\n              0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a,\n              0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b,\n              0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}},\n            {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67,\n              0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f,\n              0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a,\n              0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51},\n             {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,\n              0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,\n              0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,\n              0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}},\n            {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,\n              0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,\n              0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,\n              0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5},\n             {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,\n              0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,\n              0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,\n              0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}\n        };\n        secp256k1_scalar_set_int(&one, 1);\n        for (i = 0; i < 33; i++) {\n            secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);\n            CHECK(!overflow);\n            secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);\n            CHECK(!overflow);\n            secp256k1_scalar_set_b32(&r1, res[i][0], &overflow);\n            CHECK(!overflow);\n            secp256k1_scalar_set_b32(&r2, res[i][1], &overflow);\n            CHECK(!overflow);\n            secp256k1_scalar_mul(&z, &x, &y);\n            CHECK(!secp256k1_scalar_check_overflow(&z));\n            CHECK(secp256k1_scalar_eq(&r1, &z));\n            if (!secp256k1_scalar_is_zero(&y)) {\n                secp256k1_scalar_inverse(&zz, &y);\n                CHECK(!secp256k1_scalar_check_overflow(&zz));\n#if defined(USE_SCALAR_INV_NUM)\n                secp256k1_scalar_inverse_var(&zzv, &y);\n                CHECK(secp256k1_scalar_eq(&zzv, &zz));\n#endif\n                secp256k1_scalar_mul(&z, &z, &zz);\n                CHECK(!secp256k1_scalar_check_overflow(&z));\n                CHECK(secp256k1_scalar_eq(&x, &z));\n                secp256k1_scalar_mul(&zz, &zz, &y);\n                CHECK(!secp256k1_scalar_check_overflow(&zz));\n                CHECK(secp256k1_scalar_eq(&one, &zz));\n            }\n            secp256k1_scalar_mul(&z, &x, &x);\n            CHECK(!secp256k1_scalar_check_overflow(&z));\n            secp256k1_scalar_sqr(&zz, &x);\n            CHECK(!secp256k1_scalar_check_overflow(&zz));\n            CHECK(secp256k1_scalar_eq(&zz, &z));\n            CHECK(secp256k1_scalar_eq(&r2, &zz));\n        }\n    }\n}\n\n/***** FIELD TESTS *****/\n\nvoid random_fe(secp256k1_fe *x) {\n    unsigned char bin[32];\n    do {\n        secp256k1_rand256(bin);\n        if (secp256k1_fe_set_b32(x, bin)) {\n            return;\n        }\n    } while(1);\n}\n\nvoid random_fe_test(secp256k1_fe *x) {\n    unsigned char bin[32];\n    do {\n        secp256k1_rand256_test(bin);\n        if (secp256k1_fe_set_b32(x, bin)) {\n            return;\n        }\n    } while(1);\n}\n\nvoid random_fe_non_zero(secp256k1_fe *nz) {\n    int tries = 10;\n    while (--tries >= 0) {\n        random_fe(nz);\n        secp256k1_fe_normalize(nz);\n        if (!secp256k1_fe_is_zero(nz)) {\n            break;\n        }\n    }\n    /* Infinitesimal probability of spurious failure here */\n    CHECK(tries >= 0);\n}\n\nvoid random_fe_non_square(secp256k1_fe *ns) {\n    secp256k1_fe r;\n    random_fe_non_zero(ns);\n    if (secp256k1_fe_sqrt(&r, ns)) {\n        secp256k1_fe_negate(ns, ns, 1);\n    }\n}\n\nint check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {\n    secp256k1_fe an = *a;\n    secp256k1_fe bn = *b;\n    secp256k1_fe_normalize_weak(&an);\n    secp256k1_fe_normalize_var(&bn);\n    return secp256k1_fe_equal_var(&an, &bn);\n}\n\nint check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) {\n    secp256k1_fe x;\n    secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);\n    secp256k1_fe_mul(&x, a, ai);\n    return check_fe_equal(&x, &one);\n}\n\nvoid run_field_convert(void) {\n    static const unsigned char b32[32] = {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n        0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n        0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40\n    };\n    static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST(\n        0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,\n        0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL\n    );\n    static const secp256k1_fe fe = SECP256K1_FE_CONST(\n        0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL,\n        0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL\n    );\n    secp256k1_fe fe2;\n    unsigned char b322[32];\n    secp256k1_fe_storage fes2;\n    /* Check conversions to fe. */\n    CHECK(secp256k1_fe_set_b32(&fe2, b32));\n    CHECK(secp256k1_fe_equal_var(&fe, &fe2));\n    secp256k1_fe_from_storage(&fe2, &fes);\n    CHECK(secp256k1_fe_equal_var(&fe, &fe2));\n    /* Check conversion from fe. */\n    secp256k1_fe_get_b32(b322, &fe);\n    CHECK(memcmp(b322, b32, 32) == 0);\n    secp256k1_fe_to_storage(&fes2, &fe);\n    CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0);\n}\n\nint fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) {\n    secp256k1_fe t = *b;\n#ifdef VERIFY\n    t.magnitude = a->magnitude;\n    t.normalized = a->normalized;\n#endif\n    return memcmp(a, &t, sizeof(secp256k1_fe));\n}\n\nvoid run_field_misc(void) {\n    secp256k1_fe x;\n    secp256k1_fe y;\n    secp256k1_fe z;\n    secp256k1_fe q;\n    secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);\n    int i, j;\n    for (i = 0; i < 5*count; i++) {\n        secp256k1_fe_storage xs, ys, zs;\n        random_fe(&x);\n        random_fe_non_zero(&y);\n        /* Test the fe equality and comparison operations. */\n        CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);\n        CHECK(secp256k1_fe_equal_var(&x, &x));\n        z = x;\n        secp256k1_fe_add(&z,&y);\n        /* Test fe conditional move; z is not normalized here. */\n        q = x;\n        secp256k1_fe_cmov(&x, &z, 0);\n        VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude);\n        secp256k1_fe_cmov(&x, &x, 1);\n        CHECK(fe_memcmp(&x, &z) != 0);\n        CHECK(fe_memcmp(&x, &q) == 0);\n        secp256k1_fe_cmov(&q, &z, 1);\n        VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude);\n        CHECK(fe_memcmp(&q, &z) == 0);\n        secp256k1_fe_normalize_var(&x);\n        secp256k1_fe_normalize_var(&z);\n        CHECK(!secp256k1_fe_equal_var(&x, &z));\n        secp256k1_fe_normalize_var(&q);\n        secp256k1_fe_cmov(&q, &z, (i&1));\n        VERIFY_CHECK(q.normalized && q.magnitude == 1);\n        for (j = 0; j < 6; j++) {\n            secp256k1_fe_negate(&z, &z, j+1);\n            secp256k1_fe_normalize_var(&q);\n            secp256k1_fe_cmov(&q, &z, (j&1));\n            VERIFY_CHECK(!q.normalized && q.magnitude == (j+2));\n        }\n        secp256k1_fe_normalize_var(&z);\n        /* Test storage conversion and conditional moves. */\n        secp256k1_fe_to_storage(&xs, &x);\n        secp256k1_fe_to_storage(&ys, &y);\n        secp256k1_fe_to_storage(&zs, &z);\n        secp256k1_fe_storage_cmov(&zs, &xs, 0);\n        secp256k1_fe_storage_cmov(&zs, &zs, 1);\n        CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0);\n        secp256k1_fe_storage_cmov(&ys, &xs, 1);\n        CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0);\n        secp256k1_fe_from_storage(&x, &xs);\n        secp256k1_fe_from_storage(&y, &ys);\n        secp256k1_fe_from_storage(&z, &zs);\n        /* Test that mul_int, mul, and add agree. */\n        secp256k1_fe_add(&y, &x);\n        secp256k1_fe_add(&y, &x);\n        z = x;\n        secp256k1_fe_mul_int(&z, 3);\n        CHECK(check_fe_equal(&y, &z));\n        secp256k1_fe_add(&y, &x);\n        secp256k1_fe_add(&z, &x);\n        CHECK(check_fe_equal(&z, &y));\n        z = x;\n        secp256k1_fe_mul_int(&z, 5);\n        secp256k1_fe_mul(&q, &x, &fe5);\n        CHECK(check_fe_equal(&z, &q));\n        secp256k1_fe_negate(&x, &x, 1);\n        secp256k1_fe_add(&z, &x);\n        secp256k1_fe_add(&q, &x);\n        CHECK(check_fe_equal(&y, &z));\n        CHECK(check_fe_equal(&q, &y));\n    }\n}\n\nvoid run_field_inv(void) {\n    secp256k1_fe x, xi, xii;\n    int i;\n    for (i = 0; i < 10*count; i++) {\n        random_fe_non_zero(&x);\n        secp256k1_fe_inv(&xi, &x);\n        CHECK(check_fe_inverse(&x, &xi));\n        secp256k1_fe_inv(&xii, &xi);\n        CHECK(check_fe_equal(&x, &xii));\n    }\n}\n\nvoid run_field_inv_var(void) {\n    secp256k1_fe x, xi, xii;\n    int i;\n    for (i = 0; i < 10*count; i++) {\n        random_fe_non_zero(&x);\n        secp256k1_fe_inv_var(&xi, &x);\n        CHECK(check_fe_inverse(&x, &xi));\n        secp256k1_fe_inv_var(&xii, &xi);\n        CHECK(check_fe_equal(&x, &xii));\n    }\n}\n\nvoid run_field_inv_all_var(void) {\n    secp256k1_fe x[16], xi[16], xii[16];\n    int i;\n    /* Check it's safe to call for 0 elements */\n    secp256k1_fe_inv_all_var(xi, x, 0);\n    for (i = 0; i < count; i++) {\n        size_t j;\n        size_t len = secp256k1_rand_int(15) + 1;\n        for (j = 0; j < len; j++) {\n            random_fe_non_zero(&x[j]);\n        }\n        secp256k1_fe_inv_all_var(xi, x, len);\n        for (j = 0; j < len; j++) {\n            CHECK(check_fe_inverse(&x[j], &xi[j]));\n        }\n        secp256k1_fe_inv_all_var(xii, xi, len);\n        for (j = 0; j < len; j++) {\n            CHECK(check_fe_equal(&x[j], &xii[j]));\n        }\n    }\n}\n\nvoid run_sqr(void) {\n    secp256k1_fe x, s;\n\n    {\n        int i;\n        secp256k1_fe_set_int(&x, 1);\n        secp256k1_fe_negate(&x, &x, 1);\n\n        for (i = 1; i <= 512; ++i) {\n            secp256k1_fe_mul_int(&x, 2);\n            secp256k1_fe_normalize(&x);\n            secp256k1_fe_sqr(&s, &x);\n        }\n    }\n}\n\nvoid test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {\n    secp256k1_fe r1, r2;\n    int v = secp256k1_fe_sqrt(&r1, a);\n    CHECK((v == 0) == (k == NULL));\n\n    if (k != NULL) {\n        /* Check that the returned root is +/- the given known answer */\n        secp256k1_fe_negate(&r2, &r1, 1);\n        secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k);\n        secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2);\n        CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2));\n    }\n}\n\nvoid run_sqrt(void) {\n    secp256k1_fe ns, x, s, t;\n    int i;\n\n    /* Check sqrt(0) is 0 */\n    secp256k1_fe_set_int(&x, 0);\n    secp256k1_fe_sqr(&s, &x);\n    test_sqrt(&s, &x);\n\n    /* Check sqrt of small squares (and their negatives) */\n    for (i = 1; i <= 100; i++) {\n        secp256k1_fe_set_int(&x, i);\n        secp256k1_fe_sqr(&s, &x);\n        test_sqrt(&s, &x);\n        secp256k1_fe_negate(&t, &s, 1);\n        test_sqrt(&t, NULL);\n    }\n\n    /* Consistency checks for large random values */\n    for (i = 0; i < 10; i++) {\n        int j;\n        random_fe_non_square(&ns);\n        for (j = 0; j < count; j++) {\n            random_fe(&x);\n            secp256k1_fe_sqr(&s, &x);\n            test_sqrt(&s, &x);\n            secp256k1_fe_negate(&t, &s, 1);\n            test_sqrt(&t, NULL);\n            secp256k1_fe_mul(&t, &s, &ns);\n            test_sqrt(&t, NULL);\n        }\n    }\n}\n\n/***** GROUP TESTS *****/\n\nvoid ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {\n    CHECK(a->infinity == b->infinity);\n    if (a->infinity) {\n        return;\n    }\n    CHECK(secp256k1_fe_equal_var(&a->x, &b->x));\n    CHECK(secp256k1_fe_equal_var(&a->y, &b->y));\n}\n\n/* This compares jacobian points including their Z, not just their geometric meaning. */\nint gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) {\n    secp256k1_gej a2;\n    secp256k1_gej b2;\n    int ret = 1;\n    ret &= a->infinity == b->infinity;\n    if (ret && !a->infinity) {\n        a2 = *a;\n        b2 = *b;\n        secp256k1_fe_normalize(&a2.x);\n        secp256k1_fe_normalize(&a2.y);\n        secp256k1_fe_normalize(&a2.z);\n        secp256k1_fe_normalize(&b2.x);\n        secp256k1_fe_normalize(&b2.y);\n        secp256k1_fe_normalize(&b2.z);\n        ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0;\n        ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0;\n        ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0;\n    }\n    return ret;\n}\n\nvoid ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {\n    secp256k1_fe z2s;\n    secp256k1_fe u1, u2, s1, s2;\n    CHECK(a->infinity == b->infinity);\n    if (a->infinity) {\n        return;\n    }\n    /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */\n    secp256k1_fe_sqr(&z2s, &b->z);\n    secp256k1_fe_mul(&u1, &a->x, &z2s);\n    u2 = b->x; secp256k1_fe_normalize_weak(&u2);\n    secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);\n    s2 = b->y; secp256k1_fe_normalize_weak(&s2);\n    CHECK(secp256k1_fe_equal_var(&u1, &u2));\n    CHECK(secp256k1_fe_equal_var(&s1, &s2));\n}\n\nvoid test_ge(void) {\n    int i, i1;\n#ifdef USE_ENDOMORPHISM\n    int runs = 6;\n#else\n    int runs = 4;\n#endif\n    /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4).\n     * The second in each pair of identical points uses a random Z coordinate in the Jacobian form.\n     * All magnitudes are randomized.\n     * All 17*17 combinations of points are added to each other, using all applicable methods.\n     *\n     * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well.\n     */\n    secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));\n    secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));\n    secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));\n    secp256k1_fe zf;\n    secp256k1_fe zfi2, zfi3;\n\n    secp256k1_gej_set_infinity(&gej[0]);\n    secp256k1_ge_clear(&ge[0]);\n    secp256k1_ge_set_gej_var(&ge[0], &gej[0]);\n    for (i = 0; i < runs; i++) {\n        int j;\n        secp256k1_ge g;\n        random_group_element_test(&g);\n#ifdef USE_ENDOMORPHISM\n        if (i >= runs - 2) {\n            secp256k1_ge_mul_lambda(&g, &ge[1]);\n        }\n        if (i >= runs - 1) {\n            secp256k1_ge_mul_lambda(&g, &g);\n        }\n#endif\n        ge[1 + 4 * i] = g;\n        ge[2 + 4 * i] = g;\n        secp256k1_ge_neg(&ge[3 + 4 * i], &g);\n        secp256k1_ge_neg(&ge[4 + 4 * i], &g);\n        secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]);\n        random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]);\n        secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]);\n        random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]);\n        for (j = 0; j < 4; j++) {\n            random_field_element_magnitude(&ge[1 + j + 4 * i].x);\n            random_field_element_magnitude(&ge[1 + j + 4 * i].y);\n            random_field_element_magnitude(&gej[1 + j + 4 * i].x);\n            random_field_element_magnitude(&gej[1 + j + 4 * i].y);\n            random_field_element_magnitude(&gej[1 + j + 4 * i].z);\n        }\n    }\n\n    /* Compute z inverses. */\n    {\n        secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));\n        for (i = 0; i < 4 * runs + 1; i++) {\n            if (i == 0) {\n                /* The point at infinity does not have a meaningful z inverse. Any should do. */\n                do {\n                    random_field_element_test(&zs[i]);\n                } while(secp256k1_fe_is_zero(&zs[i]));\n            } else {\n                zs[i] = gej[i].z;\n            }\n        }\n        secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1);\n        free(zs);\n    }\n\n    /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */\n    do {\n        random_field_element_test(&zf);\n    } while(secp256k1_fe_is_zero(&zf));\n    random_field_element_magnitude(&zf);\n    secp256k1_fe_inv_var(&zfi3, &zf);\n    secp256k1_fe_sqr(&zfi2, &zfi3);\n    secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);\n\n    for (i1 = 0; i1 < 1 + 4 * runs; i1++) {\n        int i2;\n        for (i2 = 0; i2 < 1 + 4 * runs; i2++) {\n            /* Compute reference result using gej + gej (var). */\n            secp256k1_gej refj, resj;\n            secp256k1_ge ref;\n            secp256k1_fe zr;\n            secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr);\n            /* Check Z ratio. */\n            if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) {\n                secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z);\n                CHECK(secp256k1_fe_equal_var(&zrz, &refj.z));\n            }\n            secp256k1_ge_set_gej_var(&ref, &refj);\n\n            /* Test gej + ge with Z ratio result (var). */\n            secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr);\n            ge_equals_gej(&ref, &resj);\n            if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) {\n                secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z);\n                CHECK(secp256k1_fe_equal_var(&zrz, &resj.z));\n            }\n\n            /* Test gej + ge (var, with additional Z factor). */\n            {\n                secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */\n                secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2);\n                secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3);\n                random_field_element_magnitude(&ge2_zfi.x);\n                random_field_element_magnitude(&ge2_zfi.y);\n                secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf);\n                ge_equals_gej(&ref, &resj);\n            }\n\n            /* Test gej + ge (const). */\n            if (i2 != 0) {\n                /* secp256k1_gej_add_ge does not support its second argument being infinity. */\n                secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]);\n                ge_equals_gej(&ref, &resj);\n            }\n\n            /* Test doubling (var). */\n            if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) {\n                secp256k1_fe zr2;\n                /* Normal doubling with Z ratio result. */\n                secp256k1_gej_double_var(&resj, &gej[i1], &zr2);\n                ge_equals_gej(&ref, &resj);\n                /* Check Z ratio. */\n                secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z);\n                CHECK(secp256k1_fe_equal_var(&zr2, &resj.z));\n                /* Normal doubling. */\n                secp256k1_gej_double_var(&resj, &gej[i2], NULL);\n                ge_equals_gej(&ref, &resj);\n            }\n\n            /* Test adding opposites. */\n            if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) {\n                CHECK(secp256k1_ge_is_infinity(&ref));\n            }\n\n            /* Test adding infinity. */\n            if (i1 == 0) {\n                CHECK(secp256k1_ge_is_infinity(&ge[i1]));\n                CHECK(secp256k1_gej_is_infinity(&gej[i1]));\n                ge_equals_gej(&ref, &gej[i2]);\n            }\n            if (i2 == 0) {\n                CHECK(secp256k1_ge_is_infinity(&ge[i2]));\n                CHECK(secp256k1_gej_is_infinity(&gej[i2]));\n                ge_equals_gej(&ref, &gej[i1]);\n            }\n        }\n    }\n\n    /* Test adding all points together in random order equals infinity. */\n    {\n        secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;\n        secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));\n        for (i = 0; i < 4 * runs + 1; i++) {\n            gej_shuffled[i] = gej[i];\n        }\n        for (i = 0; i < 4 * runs + 1; i++) {\n            int swap = i + secp256k1_rand_int(4 * runs + 1 - i);\n            if (swap != i) {\n                secp256k1_gej t = gej_shuffled[i];\n                gej_shuffled[i] = gej_shuffled[swap];\n                gej_shuffled[swap] = t;\n            }\n        }\n        for (i = 0; i < 4 * runs + 1; i++) {\n            secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL);\n        }\n        CHECK(secp256k1_gej_is_infinity(&sum));\n        free(gej_shuffled);\n    }\n\n    /* Test batch gej -> ge conversion with and without known z ratios. */\n    {\n        secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));\n        secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));\n        secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));\n        for (i = 0; i < 4 * runs + 1; i++) {\n            /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */\n            if (i < 4 * runs) {\n                secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);\n            }\n        }\n        secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1);\n        secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback);\n        for (i = 0; i < 4 * runs + 1; i++) {\n            secp256k1_fe s;\n            random_fe_non_zero(&s);\n            secp256k1_gej_rescale(&gej[i], &s);\n            ge_equals_gej(&ge_set_table[i], &gej[i]);\n            ge_equals_gej(&ge_set_all[i], &gej[i]);\n        }\n        free(ge_set_table);\n        free(ge_set_all);\n        free(zr);\n    }\n\n    free(ge);\n    free(gej);\n    free(zinv);\n}\n\nvoid test_add_neg_y_diff_x(void) {\n    /* The point of this test is to check that we can add two points\n     * whose y-coordinates are negatives of each other but whose x\n     * coordinates differ. If the x-coordinates were the same, these\n     * points would be negatives of each other and their sum is\n     * infinity. This is cool because it \"covers up\" any degeneracy\n     * in the addition algorithm that would cause the xy coordinates\n     * of the sum to be wrong (since infinity has no xy coordinates).\n     * HOWEVER, if the x-coordinates are different, infinity is the\n     * wrong answer, and such degeneracies are exposed. This is the\n     * root of https://github.com/bitcoin-core/secp256k1/issues/257\n     * which this test is a regression test for.\n     *\n     * These points were generated in sage as\n     * # secp256k1 params\n     * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)\n     * C = EllipticCurve ([F (0), F (7)])\n     * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)\n     * N = FiniteField(G.order())\n     *\n     * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F)\n     * x = polygen(N)\n     * lam  = (1 - x^3).roots()[1][0]\n     *\n     * # random \"bad pair\"\n     * P = C.random_element()\n     * Q = -int(lam) * P\n     * print \"    P: %x %x\" % P.xy()\n     * print \"    Q: %x %x\" % Q.xy()\n     * print \"P + Q: %x %x\" % (P + Q).xy()\n     */\n    secp256k1_gej aj = SECP256K1_GEJ_CONST(\n        0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30,\n        0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb,\n        0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8,\n        0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d\n    );\n    secp256k1_gej bj = SECP256K1_GEJ_CONST(\n        0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86,\n        0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7,\n        0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57,\n        0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2\n    );\n    secp256k1_gej sumj = SECP256K1_GEJ_CONST(\n        0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027,\n        0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a,\n        0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08,\n        0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe\n    );\n    secp256k1_ge b;\n    secp256k1_gej resj;\n    secp256k1_ge res;\n    secp256k1_ge_set_gej(&b, &bj);\n\n    secp256k1_gej_add_var(&resj, &aj, &bj, NULL);\n    secp256k1_ge_set_gej(&res, &resj);\n    ge_equals_gej(&res, &sumj);\n\n    secp256k1_gej_add_ge(&resj, &aj, &b);\n    secp256k1_ge_set_gej(&res, &resj);\n    ge_equals_gej(&res, &sumj);\n\n    secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL);\n    secp256k1_ge_set_gej(&res, &resj);\n    ge_equals_gej(&res, &sumj);\n}\n\nvoid run_ge(void) {\n    int i;\n    for (i = 0; i < count * 32; i++) {\n        test_ge();\n    }\n    test_add_neg_y_diff_x();\n}\n\nvoid test_ec_combine(void) {\n    secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);\n    secp256k1_pubkey data[6];\n    const secp256k1_pubkey* d[6];\n    secp256k1_pubkey sd;\n    secp256k1_pubkey sd2;\n    secp256k1_gej Qj;\n    secp256k1_ge Q;\n    int i;\n    for (i = 1; i <= 6; i++) {\n        secp256k1_scalar s;\n        random_scalar_order_test(&s);\n        secp256k1_scalar_add(&sum, &sum, &s);\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s);\n        secp256k1_ge_set_gej(&Q, &Qj);\n        secp256k1_pubkey_save(&data[i - 1], &Q);\n        d[i - 1] = &data[i - 1];\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum);\n        secp256k1_ge_set_gej(&Q, &Qj);\n        secp256k1_pubkey_save(&sd, &Q);\n        CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1);\n        CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0);\n    }\n}\n\nvoid run_ec_combine(void) {\n    int i;\n    for (i = 0; i < count * 8; i++) {\n         test_ec_combine();\n    }\n}\n\nvoid test_group_decompress(const secp256k1_fe* x) {\n    /* The input itself, normalized. */\n    secp256k1_fe fex = *x;\n    secp256k1_fe fez;\n    /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */\n    secp256k1_ge ge_quad, ge_even, ge_odd;\n    secp256k1_gej gej_quad;\n    /* Return values of the above calls. */\n    int res_quad, res_even, res_odd;\n\n    secp256k1_fe_normalize_var(&fex);\n\n    res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex);\n    res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);\n    res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);\n\n    CHECK(res_quad == res_even);\n    CHECK(res_quad == res_odd);\n\n    if (res_quad) {\n        secp256k1_fe_normalize_var(&ge_quad.x);\n        secp256k1_fe_normalize_var(&ge_odd.x);\n        secp256k1_fe_normalize_var(&ge_even.x);\n        secp256k1_fe_normalize_var(&ge_quad.y);\n        secp256k1_fe_normalize_var(&ge_odd.y);\n        secp256k1_fe_normalize_var(&ge_even.y);\n\n        /* No infinity allowed. */\n        CHECK(!ge_quad.infinity);\n        CHECK(!ge_even.infinity);\n        CHECK(!ge_odd.infinity);\n\n        /* Check that the x coordinates check out. */\n        CHECK(secp256k1_fe_equal_var(&ge_quad.x, x));\n        CHECK(secp256k1_fe_equal_var(&ge_even.x, x));\n        CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));\n\n        /* Check that the Y coordinate result in ge_quad is a square. */\n        CHECK(secp256k1_fe_is_quad_var(&ge_quad.y));\n\n        /* Check odd/even Y in ge_odd, ge_even. */\n        CHECK(secp256k1_fe_is_odd(&ge_odd.y));\n        CHECK(!secp256k1_fe_is_odd(&ge_even.y));\n\n        /* Check secp256k1_gej_has_quad_y_var. */\n        secp256k1_gej_set_ge(&gej_quad, &ge_quad);\n        CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));\n        do {\n            random_fe_test(&fez);\n        } while (secp256k1_fe_is_zero(&fez));\n        secp256k1_gej_rescale(&gej_quad, &fez);\n        CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));\n        secp256k1_gej_neg(&gej_quad, &gej_quad);\n        CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));\n        do {\n            random_fe_test(&fez);\n        } while (secp256k1_fe_is_zero(&fez));\n        secp256k1_gej_rescale(&gej_quad, &fez);\n        CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));\n        secp256k1_gej_neg(&gej_quad, &gej_quad);\n        CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));\n    }\n}\n\nvoid run_group_decompress(void) {\n    int i;\n    for (i = 0; i < count * 4; i++) {\n        secp256k1_fe fe;\n        random_fe_test(&fe);\n        test_group_decompress(&fe);\n    }\n}\n\n/***** ECMULT TESTS *****/\n\nvoid run_ecmult_chain(void) {\n    /* random starting point A (on the curve) */\n    secp256k1_gej a = SECP256K1_GEJ_CONST(\n        0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3,\n        0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004,\n        0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f,\n        0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f\n    );\n    /* two random initial factors xn and gn */\n    secp256k1_scalar xn = SECP256K1_SCALAR_CONST(\n        0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c,\n        0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407\n    );\n    secp256k1_scalar gn = SECP256K1_SCALAR_CONST(\n        0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9,\n        0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de\n    );\n    /* two small multipliers to be applied to xn and gn in every iteration: */\n    static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337);\n    static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113);\n    /* accumulators with the resulting coefficients to A and G */\n    secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);\n    secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);\n    /* actual points */\n    secp256k1_gej x;\n    secp256k1_gej x2;\n    int i;\n\n    /* the point being computed */\n    x = a;\n    for (i = 0; i < 200*count; i++) {\n        /* in each iteration, compute X = xn*X + gn*G; */\n        secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn);\n        /* also compute ae and ge: the actual accumulated factors for A and G */\n        /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */\n        secp256k1_scalar_mul(&ae, &ae, &xn);\n        secp256k1_scalar_mul(&ge, &ge, &xn);\n        secp256k1_scalar_add(&ge, &ge, &gn);\n        /* modify xn and gn */\n        secp256k1_scalar_mul(&xn, &xn, &xf);\n        secp256k1_scalar_mul(&gn, &gn, &gf);\n\n        /* verify */\n        if (i == 19999) {\n            /* expected result after 19999 iterations */\n            secp256k1_gej rp = SECP256K1_GEJ_CONST(\n                0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE,\n                0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830,\n                0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D,\n                0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88\n            );\n\n            secp256k1_gej_neg(&rp, &rp);\n            secp256k1_gej_add_var(&rp, &rp, &x, NULL);\n            CHECK(secp256k1_gej_is_infinity(&rp));\n        }\n    }\n    /* redo the computation, but directly with the resulting ae and ge coefficients: */\n    secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge);\n    secp256k1_gej_neg(&x2, &x2);\n    secp256k1_gej_add_var(&x2, &x2, &x, NULL);\n    CHECK(secp256k1_gej_is_infinity(&x2));\n}\n\nvoid test_point_times_order(const secp256k1_gej *point) {\n    /* X * (point + G) + (order-X) * (pointer + G) = 0 */\n    secp256k1_scalar x;\n    secp256k1_scalar nx;\n    secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);\n    secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);\n    secp256k1_gej res1, res2;\n    secp256k1_ge res3;\n    unsigned char pub[65];\n    size_t psize = 65;\n    random_scalar_order_test(&x);\n    secp256k1_scalar_negate(&nx, &x);\n    secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */\n    secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */\n    secp256k1_gej_add_var(&res1, &res1, &res2, NULL);\n    CHECK(secp256k1_gej_is_infinity(&res1));\n    CHECK(secp256k1_gej_is_valid_var(&res1) == 0);\n    secp256k1_ge_set_gej(&res3, &res1);\n    CHECK(secp256k1_ge_is_infinity(&res3));\n    CHECK(secp256k1_ge_is_valid_var(&res3) == 0);\n    CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0);\n    psize = 65;\n    CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0);\n    /* check zero/one edge cases */\n    secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero);\n    secp256k1_ge_set_gej(&res3, &res1);\n    CHECK(secp256k1_ge_is_infinity(&res3));\n    secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero);\n    secp256k1_ge_set_gej(&res3, &res1);\n    ge_equals_gej(&res3, point);\n    secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one);\n    secp256k1_ge_set_gej(&res3, &res1);\n    ge_equals_ge(&res3, &secp256k1_ge_const_g);\n}\n\nvoid run_point_times_order(void) {\n    int i;\n    secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2);\n    static const secp256k1_fe xr = SECP256K1_FE_CONST(\n        0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C,\n        0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45\n    );\n    for (i = 0; i < 500; i++) {\n        secp256k1_ge p;\n        if (secp256k1_ge_set_xo_var(&p, &x, 1)) {\n            secp256k1_gej j;\n            CHECK(secp256k1_ge_is_valid_var(&p));\n            secp256k1_gej_set_ge(&j, &p);\n            CHECK(secp256k1_gej_is_valid_var(&j));\n            test_point_times_order(&j);\n        }\n        secp256k1_fe_sqr(&x, &x);\n    }\n    secp256k1_fe_normalize_var(&x);\n    CHECK(secp256k1_fe_equal_var(&x, &xr));\n}\n\nvoid ecmult_const_random_mult(void) {\n    /* random starting point A (on the curve) */\n    secp256k1_ge a = SECP256K1_GE_CONST(\n        0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b,\n        0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a,\n        0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c,\n        0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d\n    );\n    /* random initial factor xn */\n    secp256k1_scalar xn = SECP256K1_SCALAR_CONST(\n        0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327,\n        0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b\n    );\n    /* expected xn * A (from sage) */\n    secp256k1_ge expected_b = SECP256K1_GE_CONST(\n        0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd,\n        0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786,\n        0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f,\n        0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956\n    );\n    secp256k1_gej b;\n    secp256k1_ecmult_const(&b, &a, &xn);\n\n    CHECK(secp256k1_ge_is_valid_var(&a));\n    ge_equals_gej(&expected_b, &b);\n}\n\nvoid ecmult_const_commutativity(void) {\n    secp256k1_scalar a;\n    secp256k1_scalar b;\n    secp256k1_gej res1;\n    secp256k1_gej res2;\n    secp256k1_ge mid1;\n    secp256k1_ge mid2;\n    random_scalar_order_test(&a);\n    random_scalar_order_test(&b);\n\n    secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);\n    secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);\n    secp256k1_ge_set_gej(&mid1, &res1);\n    secp256k1_ge_set_gej(&mid2, &res2);\n    secp256k1_ecmult_const(&res1, &mid1, &b);\n    secp256k1_ecmult_const(&res2, &mid2, &a);\n    secp256k1_ge_set_gej(&mid1, &res1);\n    secp256k1_ge_set_gej(&mid2, &res2);\n    ge_equals_ge(&mid1, &mid2);\n}\n\nvoid ecmult_const_mult_zero_one(void) {\n    secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);\n    secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);\n    secp256k1_scalar negone;\n    secp256k1_gej res1;\n    secp256k1_ge res2;\n    secp256k1_ge point;\n    secp256k1_scalar_negate(&negone, &one);\n\n    random_group_element_test(&point);\n    secp256k1_ecmult_const(&res1, &point, &zero);\n    secp256k1_ge_set_gej(&res2, &res1);\n    CHECK(secp256k1_ge_is_infinity(&res2));\n    secp256k1_ecmult_const(&res1, &point, &one);\n    secp256k1_ge_set_gej(&res2, &res1);\n    ge_equals_ge(&res2, &point);\n    secp256k1_ecmult_const(&res1, &point, &negone);\n    secp256k1_gej_neg(&res1, &res1);\n    secp256k1_ge_set_gej(&res2, &res1);\n    ge_equals_ge(&res2, &point);\n}\n\nvoid ecmult_const_chain_multiply(void) {\n    /* Check known result (randomly generated test problem from sage) */\n    const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST(\n        0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d,\n        0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b\n    );\n    const secp256k1_gej expected_point = SECP256K1_GEJ_CONST(\n        0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd,\n        0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f,\n        0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196,\n        0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435\n    );\n    secp256k1_gej point;\n    secp256k1_ge res;\n    int i;\n\n    secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g);\n    for (i = 0; i < 100; ++i) {\n        secp256k1_ge tmp;\n        secp256k1_ge_set_gej(&tmp, &point);\n        secp256k1_ecmult_const(&point, &tmp, &scalar);\n    }\n    secp256k1_ge_set_gej(&res, &point);\n    ge_equals_gej(&res, &expected_point);\n}\n\nvoid run_ecmult_const_tests(void) {\n    ecmult_const_mult_zero_one();\n    ecmult_const_random_mult();\n    ecmult_const_commutativity();\n    ecmult_const_chain_multiply();\n}\n\nvoid test_wnaf(const secp256k1_scalar *number, int w) {\n    secp256k1_scalar x, two, t;\n    int wnaf[256];\n    int zeroes = -1;\n    int i;\n    int bits;\n    secp256k1_scalar_set_int(&x, 0);\n    secp256k1_scalar_set_int(&two, 2);\n    bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w);\n    CHECK(bits <= 256);\n    for (i = bits-1; i >= 0; i--) {\n        int v = wnaf[i];\n        secp256k1_scalar_mul(&x, &x, &two);\n        if (v) {\n            CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */\n            zeroes=0;\n            CHECK((v & 1) == 1); /* check non-zero elements are odd */\n            CHECK(v <= (1 << (w-1)) - 1); /* check range below */\n            CHECK(v >= -(1 << (w-1)) - 1); /* check range above */\n        } else {\n            CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */\n            zeroes++;\n        }\n        if (v >= 0) {\n            secp256k1_scalar_set_int(&t, v);\n        } else {\n            secp256k1_scalar_set_int(&t, -v);\n            secp256k1_scalar_negate(&t, &t);\n        }\n        secp256k1_scalar_add(&x, &x, &t);\n    }\n    CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */\n}\n\nvoid test_constant_wnaf_negate(const secp256k1_scalar *number) {\n    secp256k1_scalar neg1 = *number;\n    secp256k1_scalar neg2 = *number;\n    int sign1 = 1;\n    int sign2 = 1;\n\n    if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) {\n        secp256k1_scalar_negate(&neg1, &neg1);\n        sign1 = -1;\n    }\n    sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2));\n    CHECK(sign1 == sign2);\n    CHECK(secp256k1_scalar_eq(&neg1, &neg2));\n}\n\nvoid test_constant_wnaf(const secp256k1_scalar *number, int w) {\n    secp256k1_scalar x, shift;\n    int wnaf[256] = {0};\n    int i;\n    int skew;\n    secp256k1_scalar num = *number;\n\n    secp256k1_scalar_set_int(&x, 0);\n    secp256k1_scalar_set_int(&shift, 1 << w);\n    /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */\n#ifdef USE_ENDOMORPHISM\n    for (i = 0; i < 16; ++i) {\n        secp256k1_scalar_shr_int(&num, 8);\n    }\n#endif\n    skew = secp256k1_wnaf_const(wnaf, num, w);\n\n    for (i = WNAF_SIZE(w); i >= 0; --i) {\n        secp256k1_scalar t;\n        int v = wnaf[i];\n        CHECK(v != 0); /* check nonzero */\n        CHECK(v & 1);  /* check parity */\n        CHECK(v > -(1 << w)); /* check range above */\n        CHECK(v < (1 << w));  /* check range below */\n\n        secp256k1_scalar_mul(&x, &x, &shift);\n        if (v >= 0) {\n            secp256k1_scalar_set_int(&t, v);\n        } else {\n            secp256k1_scalar_set_int(&t, -v);\n            secp256k1_scalar_negate(&t, &t);\n        }\n        secp256k1_scalar_add(&x, &x, &t);\n    }\n    /* Skew num because when encoding numbers as odd we use an offset */\n    secp256k1_scalar_cadd_bit(&num, skew == 2, 1);\n    CHECK(secp256k1_scalar_eq(&x, &num));\n}\n\nvoid run_wnaf(void) {\n    int i;\n    secp256k1_scalar n = {{0}};\n\n    /* Sanity check: 1 and 2 are the smallest odd and even numbers and should\n     *               have easier-to-diagnose failure modes  */\n    n.d[0] = 1;\n    test_constant_wnaf(&n, 4);\n    n.d[0] = 2;\n    test_constant_wnaf(&n, 4);\n    /* Random tests */\n    for (i = 0; i < count; i++) {\n        random_scalar_order(&n);\n        test_wnaf(&n, 4+(i%10));\n        test_constant_wnaf_negate(&n);\n        test_constant_wnaf(&n, 4 + (i % 10));\n    }\n    secp256k1_scalar_set_int(&n, 0);\n    CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1);\n    CHECK(secp256k1_scalar_is_zero(&n));\n    CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1);\n    CHECK(secp256k1_scalar_is_zero(&n));\n}\n\nvoid test_ecmult_constants(void) {\n    /* Test ecmult_gen() for [0..36) and [order-36..0). */\n    secp256k1_scalar x;\n    secp256k1_gej r;\n    secp256k1_ge ng;\n    int i;\n    int j;\n    secp256k1_ge_neg(&ng, &secp256k1_ge_const_g);\n    for (i = 0; i < 36; i++ ) {\n        secp256k1_scalar_set_int(&x, i);\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x);\n        for (j = 0; j < i; j++) {\n            if (j == i - 1) {\n                ge_equals_gej(&secp256k1_ge_const_g, &r);\n            }\n            secp256k1_gej_add_ge(&r, &r, &ng);\n        }\n        CHECK(secp256k1_gej_is_infinity(&r));\n    }\n    for (i = 1; i <= 36; i++ ) {\n        secp256k1_scalar_set_int(&x, i);\n        secp256k1_scalar_negate(&x, &x);\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x);\n        for (j = 0; j < i; j++) {\n            if (j == i - 1) {\n                ge_equals_gej(&ng, &r);\n            }\n            secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g);\n        }\n        CHECK(secp256k1_gej_is_infinity(&r));\n    }\n}\n\nvoid run_ecmult_constants(void) {\n    test_ecmult_constants();\n}\n\nvoid test_ecmult_gen_blind(void) {\n    /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */\n    secp256k1_scalar key;\n    secp256k1_scalar b;\n    unsigned char seed32[32];\n    secp256k1_gej pgej;\n    secp256k1_gej pgej2;\n    secp256k1_gej i;\n    secp256k1_ge pge;\n    random_scalar_order_test(&key);\n    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key);\n    secp256k1_rand256(seed32);\n    b = ctx->ecmult_gen_ctx.blind;\n    i = ctx->ecmult_gen_ctx.initial;\n    secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);\n    CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));\n    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key);\n    CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));\n    CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial));\n    secp256k1_ge_set_gej(&pge, &pgej);\n    ge_equals_gej(&pge, &pgej2);\n}\n\nvoid test_ecmult_gen_blind_reset(void) {\n    /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */\n    secp256k1_scalar b;\n    secp256k1_gej initial;\n    secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);\n    b = ctx->ecmult_gen_ctx.blind;\n    initial = ctx->ecmult_gen_ctx.initial;\n    secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0);\n    CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind));\n    CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial));\n}\n\nvoid run_ecmult_gen_blind(void) {\n    int i;\n    test_ecmult_gen_blind_reset();\n    for (i = 0; i < 10; i++) {\n        test_ecmult_gen_blind();\n    }\n}\n\n#ifdef USE_ENDOMORPHISM\n/***** ENDOMORPHISH TESTS *****/\nvoid test_scalar_split(void) {\n    secp256k1_scalar full;\n    secp256k1_scalar s1, slam;\n    const unsigned char zero[32] = {0};\n    unsigned char tmp[32];\n\n    random_scalar_order_test(&full);\n    secp256k1_scalar_split_lambda(&s1, &slam, &full);\n\n    /* check that both are <= 128 bits in size */\n    if (secp256k1_scalar_is_high(&s1)) {\n        secp256k1_scalar_negate(&s1, &s1);\n    }\n    if (secp256k1_scalar_is_high(&slam)) {\n        secp256k1_scalar_negate(&slam, &slam);\n    }\n\n    secp256k1_scalar_get_b32(tmp, &s1);\n    CHECK(memcmp(zero, tmp, 16) == 0);\n    secp256k1_scalar_get_b32(tmp, &slam);\n    CHECK(memcmp(zero, tmp, 16) == 0);\n}\n\nvoid run_endomorphism_tests(void) {\n    test_scalar_split();\n}\n#endif\n\nvoid ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) {\n    unsigned char pubkeyc[65];\n    secp256k1_pubkey pubkey;\n    secp256k1_ge ge;\n    size_t pubkeyclen;\n    int32_t ecount;\n    ecount = 0;\n    secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);\n    for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) {\n        /* Smaller sizes are tested exhaustively elsewhere. */\n        int32_t i;\n        memcpy(&pubkeyc[1], input, 64);\n        VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen);\n        for (i = 0; i < 256; i++) {\n            /* Try all type bytes. */\n            int xpass;\n            int ypass;\n            int ysign;\n            pubkeyc[0] = i;\n            /* What sign does this point have? */\n            ysign = (input[63] & 1) + 2;\n            /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */\n            xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2);\n            /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */\n            ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) &&\n                ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65));\n            if (xpass || ypass) {\n                /* These cases must parse. */\n                unsigned char pubkeyo[65];\n                size_t outl;\n                memset(&pubkey, 0, sizeof(pubkey));\n                VG_UNDEF(&pubkey, sizeof(pubkey));\n                ecount = 0;\n                CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);\n                VG_CHECK(&pubkey, sizeof(pubkey));\n                outl = 65;\n                VG_UNDEF(pubkeyo, 65);\n                CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1);\n                VG_CHECK(pubkeyo, outl);\n                CHECK(outl == 33);\n                CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0);\n                CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0]));\n                if (ypass) {\n                    /* This test isn't always done because we decode with alternative signs, so the y won't match. */\n                    CHECK(pubkeyo[0] == ysign);\n                    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);\n                    memset(&pubkey, 0, sizeof(pubkey));\n                    VG_UNDEF(&pubkey, sizeof(pubkey));\n                    secp256k1_pubkey_save(&pubkey, &ge);\n                    VG_CHECK(&pubkey, sizeof(pubkey));\n                    outl = 65;\n                    VG_UNDEF(pubkeyo, 65);\n                    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);\n                    VG_CHECK(pubkeyo, outl);\n                    CHECK(outl == 65);\n                    CHECK(pubkeyo[0] == 4);\n                    CHECK(memcmp(&pubkeyo[1], input, 64) == 0);\n                }\n                CHECK(ecount == 0);\n            } else {\n                /* These cases must fail to parse. */\n                memset(&pubkey, 0xfe, sizeof(pubkey));\n                ecount = 0;\n                VG_UNDEF(&pubkey, sizeof(pubkey));\n                CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0);\n                VG_CHECK(&pubkey, sizeof(pubkey));\n                CHECK(ecount == 0);\n                CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n                CHECK(ecount == 1);\n            }\n        }\n    }\n    secp256k1_context_set_illegal_callback(ctx, NULL, NULL);\n}\n\nvoid run_ec_pubkey_parse_test(void) {\n#define SECP256K1_EC_PARSE_TEST_NVALID (12)\n    const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = {\n        {\n            /* Point with leading and trailing zeros in x and y serialization. */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83,\n            0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00\n        },\n        {\n            /* Point with x equal to a 3rd root of unity.*/\n            0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9,\n            0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee,\n            0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,\n            0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,\n        },\n        {\n            /* Point with largest x. (1/2) */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c,\n            0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e,\n            0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d,\n        },\n        {\n            /* Point with largest x. (2/2) */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c,\n            0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1,\n            0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2,\n        },\n        {\n            /* Point with smallest x. (1/2) */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,\n            0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,\n        },\n        {\n            /* Point with smallest x. (2/2) */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb,\n            0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41,\n        },\n        {\n            /* Point with largest y. (1/3) */\n            0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,\n            0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,\n        },\n        {\n            /* Point with largest y. (2/3) */\n            0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,\n            0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,\n        },\n        {\n            /* Point with largest y. (3/3) */\n            0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,\n            0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,\n        },\n        {\n            /* Point with smallest y. (1/3) */\n            0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,\n            0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        },\n        {\n            /* Point with smallest y. (2/3) */\n            0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,\n            0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        },\n        {\n            /* Point with smallest y. (3/3) */\n            0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,\n            0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01\n        }\n    };\n#define SECP256K1_EC_PARSE_TEST_NXVALID (4)\n    const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = {\n        {\n            /* Valid if y overflow ignored (y = 1 mod p). (1/3) */\n            0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6,\n            0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,\n        },\n        {\n            /* Valid if y overflow ignored (y = 1 mod p). (2/3) */\n            0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c,\n            0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,\n        },\n        {\n            /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/\n            0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc,\n            0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,\n        },\n        {\n            /* x on curve, y is from y^2 = x^3 + 8. */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03\n        }\n    };\n#define SECP256K1_EC_PARSE_TEST_NINVALID (7)\n    const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = {\n        {\n            /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */\n            0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c,\n            0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        },\n        {\n            /* Valid if x overflow ignored (x = 1 mod p). */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,\n            0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14,\n            0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee,\n        },\n        {\n            /* Valid if x overflow ignored (x = 1 mod p). */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30,\n            0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb,\n            0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41,\n        },\n        {\n            /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,\n            0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f,\n            0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28,\n        },\n        {\n            /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e,\n            0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0,\n            0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07,\n        },\n        {\n            /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d,\n            0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc,\n        },\n        {\n            /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2,\n            0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53\n        }\n    };\n    const unsigned char pubkeyc[66] = {\n        /* Serialization of G. */\n        0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B,\n        0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17,\n        0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08,\n        0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4,\n        0xB8, 0x00\n    };\n    unsigned char sout[65];\n    unsigned char shortkey[2];\n    secp256k1_ge ge;\n    secp256k1_pubkey pubkey;\n    size_t len;\n    int32_t i;\n    int32_t ecount;\n    int32_t ecount2;\n    ecount = 0;\n    /* Nothing should be reading this far into pubkeyc. */\n    VG_UNDEF(&pubkeyc[65], 1);\n    secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);\n    /* Zero length claimed, fail, zeroize, no illegal arg error. */\n    memset(&pubkey, 0xfe, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(shortkey, 2);\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 0);\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n    CHECK(ecount == 1);\n    /* Length one claimed, fail, zeroize, no illegal arg error. */\n    for (i = 0; i < 256 ; i++) {\n        memset(&pubkey, 0xfe, sizeof(pubkey));\n        ecount = 0;\n        shortkey[0] = i;\n        VG_UNDEF(&shortkey[1], 1);\n        VG_UNDEF(&pubkey, sizeof(pubkey));\n        CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0);\n        VG_CHECK(&pubkey, sizeof(pubkey));\n        CHECK(ecount == 0);\n        CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n        CHECK(ecount == 1);\n    }\n    /* Length two claimed, fail, zeroize, no illegal arg error. */\n    for (i = 0; i < 65536 ; i++) {\n        memset(&pubkey, 0xfe, sizeof(pubkey));\n        ecount = 0;\n        shortkey[0] = i & 255;\n        shortkey[1] = i >> 8;\n        VG_UNDEF(&pubkey, sizeof(pubkey));\n        CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0);\n        VG_CHECK(&pubkey, sizeof(pubkey));\n        CHECK(ecount == 0);\n        CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n        CHECK(ecount == 1);\n    }\n    memset(&pubkey, 0xfe, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 0);\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n    CHECK(ecount == 1);\n    /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */\n    CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0);\n    CHECK(ecount == 2);\n    /* NULL input string. Illegal arg and zeroize output. */\n    memset(&pubkey, 0xfe, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 1);\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n    CHECK(ecount == 2);\n    /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */\n    memset(&pubkey, 0xfe, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 0);\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n    CHECK(ecount == 1);\n    /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */\n    memset(&pubkey, 0xfe, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 0);\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0);\n    CHECK(ecount == 1);\n    /* Valid parse. */\n    memset(&pubkey, 0, sizeof(pubkey));\n    ecount = 0;\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(ecount == 0);\n    VG_UNDEF(&ge, sizeof(ge));\n    CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1);\n    VG_CHECK(&ge.x, sizeof(ge.x));\n    VG_CHECK(&ge.y, sizeof(ge.y));\n    VG_CHECK(&ge.infinity, sizeof(ge.infinity));\n    ge_equals_ge(&secp256k1_ge_const_g, &ge);\n    CHECK(ecount == 0);\n    /* secp256k1_ec_pubkey_serialize illegal args. */\n    ecount = 0;\n    len = 65;\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);\n    CHECK(ecount == 1);\n    CHECK(len == 0);\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0);\n    CHECK(ecount == 2);\n    len = 65;\n    VG_UNDEF(sout, 65);\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0);\n    VG_CHECK(sout, 65);\n    CHECK(ecount == 3);\n    CHECK(len == 0);\n    len = 65;\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0);\n    CHECK(ecount == 4);\n    CHECK(len == 0);\n    len = 65;\n    VG_UNDEF(sout, 65);\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);\n    VG_CHECK(sout, 65);\n    CHECK(ecount == 4);\n    CHECK(len == 65);\n    /* Multiple illegal args. Should still set arg error only once. */\n    ecount = 0;\n    ecount2 = 11;\n    CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);\n    CHECK(ecount == 1);\n    /* Does the illegal arg callback actually change the behavior? */\n    secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2);\n    CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0);\n    CHECK(ecount == 1);\n    CHECK(ecount2 == 10);\n    secp256k1_context_set_illegal_callback(ctx, NULL, NULL);\n    /* Try a bunch of prefabbed points with all possible encodings. */\n    for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) {\n        ec_pubkey_parse_pointtest(valid[i], 1, 1);\n    }\n    for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) {\n        ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0);\n    }\n    for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) {\n        ec_pubkey_parse_pointtest(invalid[i], 0, 0);\n    }\n}\n\nvoid run_eckey_edge_case_test(void) {\n    const unsigned char orderc[32] = {\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n        0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n        0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41\n    };\n    const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00};\n    unsigned char ctmp[33];\n    unsigned char ctmp2[33];\n    secp256k1_pubkey pubkey;\n    secp256k1_pubkey pubkey2;\n    secp256k1_pubkey pubkey_one;\n    secp256k1_pubkey pubkey_negone;\n    const secp256k1_pubkey *pubkeys[3];\n    size_t len;\n    int32_t ecount;\n    /* Group order is too large, reject. */\n    CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0);\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    /* Maximum value is too large, reject. */\n    memset(ctmp, 255, 32);\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);\n    memset(&pubkey, 1, sizeof(pubkey));\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    /* Zero is too small, reject. */\n    memset(ctmp, 0, 32);\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);\n    memset(&pubkey, 1, sizeof(pubkey));\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    /* One must be accepted. */\n    ctmp[31] = 0x01;\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);\n    memset(&pubkey, 0, sizeof(pubkey));\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);\n    pubkey_one = pubkey;\n    /* Group order + 1 is too large, reject. */\n    memcpy(ctmp, orderc, 32);\n    ctmp[31] = 0x42;\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);\n    memset(&pubkey, 1, sizeof(pubkey));\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    /* -1 must be accepted. */\n    ctmp[31] = 0x40;\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);\n    memset(&pubkey, 0, sizeof(pubkey));\n    VG_UNDEF(&pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);\n    VG_CHECK(&pubkey, sizeof(pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);\n    pubkey_negone = pubkey;\n    /* Tweak of zero leaves the value changed. */\n    memset(ctmp2, 0, 32);\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);\n    CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);\n    memcpy(&pubkey2, &pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);\n    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);\n    /* Multiply tweak of zero zeroizes the output. */\n    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);\n    CHECK(memcmp(zeros, ctmp, 32) == 0);\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);\n    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);\n    memcpy(&pubkey, &pubkey2, sizeof(pubkey));\n    /* Overflowing key tweak zeroizes. */\n    memcpy(ctmp, orderc, 32);\n    ctmp[31] = 0x40;\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);\n    CHECK(memcmp(zeros, ctmp, 32) == 0);\n    memcpy(ctmp, orderc, 32);\n    ctmp[31] = 0x40;\n    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0);\n    CHECK(memcmp(zeros, ctmp, 32) == 0);\n    memcpy(ctmp, orderc, 32);\n    ctmp[31] = 0x40;\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);\n    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);\n    memcpy(&pubkey, &pubkey2, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);\n    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);\n    memcpy(&pubkey, &pubkey2, sizeof(pubkey));\n    /* Private key tweaks results in a key of zero. */\n    ctmp2[31] = 1;\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);\n    CHECK(memcmp(zeros, ctmp2, 32) == 0);\n    ctmp2[31] = 1;\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);\n    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);\n    memcpy(&pubkey, &pubkey2, sizeof(pubkey));\n    /* Tweak computation wraps and results in a key of 1. */\n    ctmp2[31] = 2;\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1);\n    CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);\n    ctmp2[31] = 2;\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);\n    ctmp2[31] = 1;\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1);\n    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);\n    /* Tweak mul * 2 = 1+1. */\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);\n    ctmp2[31] = 2;\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1);\n    CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);\n    /* Test argument errors. */\n    ecount = 0;\n    secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);\n    CHECK(ecount == 0);\n    /* Zeroize pubkey on parse error. */\n    memset(&pubkey, 0, 32);\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);\n    CHECK(ecount == 1);\n    CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);\n    memcpy(&pubkey, &pubkey2, sizeof(pubkey));\n    memset(&pubkey2, 0, 32);\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0);\n    CHECK(ecount == 2);\n    CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0);\n    /* Plain argument errors. */\n    ecount = 0;\n    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1);\n    CHECK(ecount == 0);\n    CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0);\n    CHECK(ecount == 1);\n    ecount = 0;\n    memset(ctmp2, 0, 32);\n    ctmp2[31] = 4;\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0);\n    CHECK(ecount == 2);\n    ecount = 0;\n    memset(ctmp2, 0, 32);\n    ctmp2[31] = 4;\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0);\n    CHECK(ecount == 2);\n    ecount = 0;\n    memset(ctmp2, 0, 32);\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0);\n    CHECK(ecount == 2);\n    ecount = 0;\n    memset(ctmp2, 0, 32);\n    ctmp2[31] = 1;\n    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0);\n    CHECK(ecount == 2);\n    ecount = 0;\n    CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);\n    CHECK(ecount == 1);\n    memset(&pubkey, 1, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);\n    CHECK(ecount == 2);\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    /* secp256k1_ec_pubkey_combine tests. */\n    ecount = 0;\n    pubkeys[0] = &pubkey_one;\n    VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *));\n    VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *));\n    VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *));\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    CHECK(ecount == 1);\n    CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0);\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    CHECK(ecount == 2);\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    CHECK(ecount == 3);\n    pubkeys[0] = &pubkey_negone;\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);\n    CHECK(ecount == 3);\n    len = 33;\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1);\n    CHECK(memcmp(ctmp, ctmp2, 33) == 0);\n    /* Result is infinity. */\n    pubkeys[0] = &pubkey_one;\n    pubkeys[1] = &pubkey_negone;\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0);\n    CHECK(ecount == 3);\n    /* Passes through infinity but comes out one. */\n    pubkeys[2] = &pubkey_one;\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);\n    CHECK(ecount == 3);\n    len = 33;\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);\n    CHECK(memcmp(ctmp, ctmp2, 33) == 0);\n    /* Adds to two. */\n    pubkeys[1] = &pubkey_one;\n    memset(&pubkey, 255, sizeof(secp256k1_pubkey));\n    VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1);\n    VG_CHECK(&pubkey, sizeof(secp256k1_pubkey));\n    CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);\n    CHECK(ecount == 3);\n    secp256k1_context_set_illegal_callback(ctx, NULL, NULL);\n}\n\nvoid random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {\n    secp256k1_scalar nonce;\n    do {\n        random_scalar_order_test(&nonce);\n    } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid));\n}\n\nvoid test_ecdsa_sign_verify(void) {\n    secp256k1_gej pubj;\n    secp256k1_ge pub;\n    secp256k1_scalar one;\n    secp256k1_scalar msg, key;\n    secp256k1_scalar sigr, sigs;\n    int recid;\n    int getrec;\n    random_scalar_order_test(&msg);\n    random_scalar_order_test(&key);\n    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);\n    secp256k1_ge_set_gej(&pub, &pubj);\n    getrec = secp256k1_rand_bits(1);\n    random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL);\n    if (getrec) {\n        CHECK(recid >= 0 && recid < 4);\n    }\n    CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));\n    secp256k1_scalar_set_int(&one, 1);\n    secp256k1_scalar_add(&msg, &msg, &one);\n    CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));\n}\n\nvoid run_ecdsa_sign_verify(void) {\n    int i;\n    for (i = 0; i < 10*count; i++) {\n        test_ecdsa_sign_verify();\n    }\n}\n\n/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */\nstatic int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {\n    (void)msg32;\n    (void)key32;\n    (void)algo16;\n    memcpy(nonce32, data, 32);\n    return (counter == 0);\n}\n\nstatic int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {\n   /* Dummy nonce generator that has a fatal error on the first counter value. */\n   if (counter == 0) {\n       return 0;\n   }\n   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1);\n}\n\nstatic int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {\n   /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */\n   if (counter < 3) {\n       memset(nonce32, counter==0 ? 0 : 255, 32);\n       if (counter == 2) {\n           nonce32[31]--;\n       }\n       return 1;\n   }\n   if (counter < 5) {\n       static const unsigned char order[] = {\n           0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n           0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,\n           0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,\n           0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41\n       };\n       memcpy(nonce32, order, 32);\n       if (counter == 4) {\n           nonce32[31]++;\n       }\n       return 1;\n   }\n   /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */\n   /* If someone does fine a case where it retries for secp256k1, we'd like to know. */\n   if (counter > 5) {\n       return 0;\n   }\n   return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5);\n}\n\nint is_empty_signature(const secp256k1_ecdsa_signature *sig) {\n    static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0};\n    return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0;\n}\n\nvoid test_ecdsa_end_to_end(void) {\n    unsigned char extra[32] = {0x00};\n    unsigned char privkey[32];\n    unsigned char message[32];\n    unsigned char privkey2[32];\n    secp256k1_ecdsa_signature signature[6];\n    secp256k1_scalar r, s;\n    unsigned char sig[74];\n    size_t siglen = 74;\n    unsigned char pubkeyc[65];\n    size_t pubkeyclen = 65;\n    secp256k1_pubkey pubkey;\n    secp256k1_pubkey pubkey_tmp;\n    unsigned char seckey[300];\n    size_t seckeylen = 300;\n\n    /* Generate a random key and message. */\n    {\n        secp256k1_scalar msg, key;\n        random_scalar_order_test(&msg);\n        random_scalar_order_test(&key);\n        secp256k1_scalar_get_b32(privkey, &key);\n        secp256k1_scalar_get_b32(message, &msg);\n    }\n\n    /* Construct and verify corresponding public key. */\n    CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);\n    CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);\n\n    /* Verify exporting and importing public key. */\n    CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));\n    memset(&pubkey, 0, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);\n\n    /* Verify negation changes the key and changes it back */\n    memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey));\n    CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);\n    CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0);\n    CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);\n    CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0);\n\n    /* Verify private key import and export. */\n    CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));\n    CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);\n    CHECK(memcmp(privkey, privkey2, 32) == 0);\n\n    /* Optionally tweak the keys using addition. */\n    if (secp256k1_rand_int(3) == 0) {\n        int ret1;\n        int ret2;\n        unsigned char rnd[32];\n        secp256k1_pubkey pubkey2;\n        secp256k1_rand256_test(rnd);\n        ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd);\n        ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);\n        CHECK(ret1 == ret2);\n        if (ret1 == 0) {\n            return;\n        }\n        CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);\n        CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);\n    }\n\n    /* Optionally tweak the keys using multiplication. */\n    if (secp256k1_rand_int(3) == 0) {\n        int ret1;\n        int ret2;\n        unsigned char rnd[32];\n        secp256k1_pubkey pubkey2;\n        secp256k1_rand256_test(rnd);\n        ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd);\n        ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);\n        CHECK(ret1 == ret2);\n        if (ret1 == 0) {\n            return;\n        }\n        CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);\n        CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);\n    }\n\n    /* Sign. */\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1);\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1);\n    extra[31] = 1;\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1);\n    extra[31] = 0;\n    extra[0] = 1;\n    CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1);\n    CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0);\n    CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0);\n    CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0);\n    CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0);\n    CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0);\n    CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0);\n    CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0);\n    /* Verify. */\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1);\n    /* Test lower-S form, malleate, verify and fail, test again, malleate again */\n    CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0]));\n    secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]);\n    secp256k1_scalar_negate(&s, &s);\n    secp256k1_ecdsa_signature_save(&signature[5], &r, &s);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0);\n    CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));\n    CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));\n    CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));\n    CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5]));\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);\n    secp256k1_scalar_negate(&s, &s);\n    secp256k1_ecdsa_signature_save(&signature[5], &r, &s);\n    CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5]));\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1);\n    CHECK(memcmp(&signature[5], &signature[0], 64) == 0);\n\n    /* Serialize/parse DER and verify again */\n    CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);\n    memset(&signature[0], 0, sizeof(signature[0]));\n    CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1);\n    CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1);\n    /* Serialize/destroy/parse DER and verify again. */\n    siglen = 74;\n    CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);\n    sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255);\n    CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||\n          secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0);\n}\n\nvoid test_random_pubkeys(void) {\n    secp256k1_ge elem;\n    secp256k1_ge elem2;\n    unsigned char in[65];\n    /* Generate some randomly sized pubkeys. */\n    size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33;\n    if (secp256k1_rand_bits(2) == 0) {\n        len = secp256k1_rand_bits(6);\n    }\n    if (len == 65) {\n      in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7);\n    } else {\n      in[0] = secp256k1_rand_bits(1) ? 2 : 3;\n    }\n    if (secp256k1_rand_bits(3) == 0) {\n        in[0] = secp256k1_rand_bits(8);\n    }\n    if (len > 1) {\n        secp256k1_rand256(&in[1]);\n    }\n    if (len > 33) {\n        secp256k1_rand256(&in[33]);\n    }\n    if (secp256k1_eckey_pubkey_parse(&elem, in, len)) {\n        unsigned char out[65];\n        unsigned char firstb;\n        int res;\n        size_t size = len;\n        firstb = in[0];\n        /* If the pubkey can be parsed, it should round-trip... */\n        CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33));\n        CHECK(size == len);\n        CHECK(memcmp(&in[1], &out[1], len-1) == 0);\n        /* ... except for the type of hybrid inputs. */\n        if ((in[0] != 6) && (in[0] != 7)) {\n            CHECK(in[0] == out[0]);\n        }\n        size = 65;\n        CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0));\n        CHECK(size == 65);\n        CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size));\n        ge_equals_ge(&elem,&elem2);\n        /* Check that the X9.62 hybrid type is checked. */\n        in[0] = secp256k1_rand_bits(1) ? 6 : 7;\n        res = secp256k1_eckey_pubkey_parse(&elem2, in, size);\n        if (firstb == 2 || firstb == 3) {\n            if (in[0] == firstb + 4) {\n              CHECK(res);\n            } else {\n              CHECK(!res);\n            }\n        }\n        if (res) {\n            ge_equals_ge(&elem,&elem2);\n            CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0));\n            CHECK(memcmp(&in[1], &out[1], 64) == 0);\n        }\n    }\n}\n\nvoid run_random_pubkeys(void) {\n    int i;\n    for (i = 0; i < 10*count; i++) {\n        test_random_pubkeys();\n    }\n}\n\nvoid run_ecdsa_end_to_end(void) {\n    int i;\n    for (i = 0; i < 64*count; i++) {\n        test_ecdsa_end_to_end();\n    }\n}\n\nint test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {\n    static const unsigned char zeroes[32] = {0};\n#ifdef ENABLE_OPENSSL_TESTS\n    static const unsigned char max_scalar[32] = {\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n        0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n        0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40\n    };\n#endif\n\n    int ret = 0;\n\n    secp256k1_ecdsa_signature sig_der;\n    unsigned char roundtrip_der[2048];\n    unsigned char compact_der[64];\n    size_t len_der = 2048;\n    int parsed_der = 0, valid_der = 0, roundtrips_der = 0;\n\n    secp256k1_ecdsa_signature sig_der_lax;\n    unsigned char roundtrip_der_lax[2048];\n    unsigned char compact_der_lax[64];\n    size_t len_der_lax = 2048;\n    int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0;\n\n#ifdef ENABLE_OPENSSL_TESTS\n    ECDSA_SIG *sig_openssl;\n    const unsigned char *sigptr;\n    unsigned char roundtrip_openssl[2048];\n    int len_openssl = 2048;\n    int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0;\n#endif\n\n    parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen);\n    if (parsed_der) {\n        ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0;\n        valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0);\n    }\n    if (valid_der) {\n        ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1;\n        roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0;\n    }\n\n    parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen);\n    if (parsed_der_lax) {\n        ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10;\n        valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0);\n    }\n    if (valid_der_lax) {\n        ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11;\n        roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0;\n    }\n\n    if (certainly_der) {\n        ret |= (!parsed_der) << 2;\n    }\n    if (certainly_not_der) {\n        ret |= (parsed_der) << 17;\n    }\n    if (valid_der) {\n        ret |= (!roundtrips_der) << 3;\n    }\n\n    if (valid_der) {\n        ret |= (!roundtrips_der_lax) << 12;\n        ret |= (len_der != len_der_lax) << 13;\n        ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14;\n    }\n    ret |= (roundtrips_der != roundtrips_der_lax) << 15;\n    if (parsed_der) {\n        ret |= (!parsed_der_lax) << 16;\n    }\n\n#ifdef ENABLE_OPENSSL_TESTS\n    sig_openssl = ECDSA_SIG_new();\n    sigptr = sig;\n    parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL);\n    if (parsed_openssl) {\n        valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256;\n        if (valid_openssl) {\n            unsigned char tmp[32] = {0};\n            BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r));\n            valid_openssl = memcmp(tmp, max_scalar, 32) < 0;\n        }\n        if (valid_openssl) {\n            unsigned char tmp[32] = {0};\n            BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s));\n            valid_openssl = memcmp(tmp, max_scalar, 32) < 0;\n        }\n    }\n    len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL);\n    if (len_openssl <= 2048) {\n        unsigned char *ptr = roundtrip_openssl;\n        CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl);\n        roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0);\n    } else {\n        len_openssl = 0;\n    }\n    ECDSA_SIG_free(sig_openssl);\n\n    ret |= (parsed_der && !parsed_openssl) << 4;\n    ret |= (valid_der && !valid_openssl) << 5;\n    ret |= (roundtrips_openssl && !parsed_der) << 6;\n    ret |= (roundtrips_der != roundtrips_openssl) << 7;\n    if (roundtrips_openssl) {\n        ret |= (len_der != (size_t)len_openssl) << 8;\n        ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9;\n    }\n#endif\n    return ret;\n}\n\nstatic void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {\n    size_t i;\n    for (i = 0; i < ptrlen; i++) {\n        int shift = ptrlen - 1 - i;\n        if (shift >= 4) {\n            ptr[i] = 0;\n        } else {\n            ptr[i] = (val >> shift) & 0xFF;\n        }\n    }\n}\n\nstatic void damage_array(unsigned char *sig, size_t *len) {\n    int pos;\n    int action = secp256k1_rand_bits(3);\n    if (action < 1 && *len > 3) {\n        /* Delete a byte. */\n        pos = secp256k1_rand_int(*len);\n        memmove(sig + pos, sig + pos + 1, *len - pos - 1);\n        (*len)--;\n        return;\n    } else if (action < 2 && *len < 2048) {\n        /* Insert a byte. */\n        pos = secp256k1_rand_int(1 + *len);\n        memmove(sig + pos + 1, sig + pos, *len - pos);\n        sig[pos] = secp256k1_rand_bits(8);\n        (*len)++;\n        return;\n    } else if (action < 4) {\n        /* Modify a byte. */\n        sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255);\n        return;\n    } else { /* action < 8 */\n        /* Modify a bit. */\n        sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3);\n        return;\n    }\n}\n\nstatic void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) {\n    int der;\n    int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2];\n    size_t tlen, elen, glen;\n    int indet;\n    int n;\n\n    *len = 0;\n    der = secp256k1_rand_bits(2) == 0;\n    *certainly_der = der;\n    *certainly_not_der = 0;\n    indet = der ? 0 : secp256k1_rand_int(10) == 0;\n\n    for (n = 0; n < 2; n++) {\n        /* We generate two classes of numbers: nlow==1 \"low\" ones (up to 32 bytes), nlow==0 \"high\" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */\n        nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0);\n        /* The length of the number in bytes (the first byte of which will always be nonzero) */\n        nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8;\n        CHECK(nlen[n] <= 232);\n        /* The top bit of the number. */\n        nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1));\n        /* The top byte of the number (after the potential hardcoded 16 0xFF characters for \"high\" 32 bytes numbers) */\n        nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127));\n        /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */\n        nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8);\n        if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) {\n            *certainly_not_der = 1;\n        }\n        CHECK(nlen[n] + nzlen[n] <= 300);\n        /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */\n        nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2);\n        if (!der) {\n            /* nlenlen[n] max 127 bytes */\n            int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256;\n            nlenlen[n] += add;\n            if (add != 0) {\n                *certainly_not_der = 1;\n            }\n        }\n        CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427);\n    }\n\n    /* The total length of the data to go, so far */\n    tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1];\n    CHECK(tlen <= 856);\n\n    /* The length of the garbage inside the tuple. */\n    elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8;\n    if (elen != 0) {\n        *certainly_not_der = 1;\n    }\n    tlen += elen;\n    CHECK(tlen <= 980);\n\n    /* The length of the garbage after the end of the tuple. */\n    glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8;\n    if (glen != 0) {\n        *certainly_not_der = 1;\n    }\n    CHECK(tlen + glen <= 990);\n\n    /* Write the tuple header. */\n    sig[(*len)++] = 0x30;\n    if (indet) {\n        /* Indeterminate length */\n        sig[(*len)++] = 0x80;\n        *certainly_not_der = 1;\n    } else {\n        int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2);\n        if (!der) {\n            int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256;\n            tlenlen += add;\n            if (add != 0) {\n                *certainly_not_der = 1;\n            }\n        }\n        if (tlenlen == 0) {\n            /* Short length notation */\n            sig[(*len)++] = tlen;\n        } else {\n            /* Long length notation */\n            sig[(*len)++] = 128 + tlenlen;\n            assign_big_endian(sig + *len, tlenlen, tlen);\n            *len += tlenlen;\n        }\n        tlen += tlenlen;\n    }\n    tlen += 2;\n    CHECK(tlen + glen <= 1119);\n\n    for (n = 0; n < 2; n++) {\n        /* Write the integer header. */\n        sig[(*len)++] = 0x02;\n        if (nlenlen[n] == 0) {\n            /* Short length notation */\n            sig[(*len)++] = nlen[n] + nzlen[n];\n        } else {\n            /* Long length notation. */\n            sig[(*len)++] = 128 + nlenlen[n];\n            assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]);\n            *len += nlenlen[n];\n        }\n        /* Write zero padding */\n        while (nzlen[n] > 0) {\n            sig[(*len)++] = 0x00;\n            nzlen[n]--;\n        }\n        if (nlen[n] == 32 && !nlow[n]) {\n            /* Special extra 16 0xFF bytes in \"high\" 32-byte numbers */\n            int i;\n            for (i = 0; i < 16; i++) {\n                sig[(*len)++] = 0xFF;\n            }\n            nlen[n] -= 16;\n        }\n        /* Write first byte of number */\n        if (nlen[n] > 0) {\n            sig[(*len)++] = nhbyte[n];\n            nlen[n]--;\n        }\n        /* Generate remaining random bytes of number */\n        secp256k1_rand_bytes_test(sig + *len, nlen[n]);\n        *len += nlen[n];\n        nlen[n] = 0;\n    }\n\n    /* Generate random garbage inside tuple. */\n    secp256k1_rand_bytes_test(sig + *len, elen);\n    *len += elen;\n\n    /* Generate end-of-contents bytes. */\n    if (indet) {\n        sig[(*len)++] = 0;\n        sig[(*len)++] = 0;\n        tlen += 2;\n    }\n    CHECK(tlen + glen <= 1121);\n\n    /* Generate random garbage outside tuple. */\n    secp256k1_rand_bytes_test(sig + *len, glen);\n    *len += glen;\n    tlen += glen;\n    CHECK(tlen <= 1121);\n    CHECK(tlen == *len);\n}\n\nvoid run_ecdsa_der_parse(void) {\n    int i,j;\n    for (i = 0; i < 200 * count; i++) {\n        unsigned char buffer[2048];\n        size_t buflen = 0;\n        int certainly_der = 0;\n        int certainly_not_der = 0;\n        random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);\n        CHECK(buflen <= 2048);\n        for (j = 0; j < 16; j++) {\n            int ret = 0;\n            if (j > 0) {\n                damage_array(buffer, &buflen);\n                /* We don't know anything anymore about the DERness of the result */\n                certainly_der = 0;\n                certainly_not_der = 0;\n            }\n            ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der);\n            if (ret != 0) {\n                size_t k;\n                fprintf(stderr, \"Failure %x on \", ret);\n                for (k = 0; k < buflen; k++) {\n                    fprintf(stderr, \"%02x \", buffer[k]);\n                }\n                fprintf(stderr, \"\\n\");\n            }\n            CHECK(ret == 0);\n        }\n    }\n}\n\n/* Tests several edge cases. */\nvoid test_ecdsa_edge_cases(void) {\n    int t;\n    secp256k1_ecdsa_signature sig;\n\n    /* Test the case where ECDSA recomputes a point that is infinity. */\n    {\n        secp256k1_gej keyj;\n        secp256k1_ge key;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 1);\n        secp256k1_scalar_negate(&ss, &ss);\n        secp256k1_scalar_inverse(&ss, &ss);\n        secp256k1_scalar_set_int(&sr, 1);\n        secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);\n        secp256k1_ge_set_gej(&key, &keyj);\n        msg = ss;\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n    }\n\n    /* Verify signature with r of zero fails. */\n    {\n        const unsigned char pubkey_mods_zero[33] = {\n            0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,\n            0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,\n            0x41\n        };\n        secp256k1_ge key;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 1);\n        secp256k1_scalar_set_int(&msg, 0);\n        secp256k1_scalar_set_int(&sr, 0);\n        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33));\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n    }\n\n    /* Verify signature with s of zero fails. */\n    {\n        const unsigned char pubkey[33] = {\n            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x01\n        };\n        secp256k1_ge key;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 0);\n        secp256k1_scalar_set_int(&msg, 0);\n        secp256k1_scalar_set_int(&sr, 1);\n        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n    }\n\n    /* Verify signature with message 0 passes. */\n    {\n        const unsigned char pubkey[33] = {\n            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x02\n        };\n        const unsigned char pubkey2[33] = {\n            0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0,\n            0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41,\n            0x43\n        };\n        secp256k1_ge key;\n        secp256k1_ge key2;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 2);\n        secp256k1_scalar_set_int(&msg, 0);\n        secp256k1_scalar_set_int(&sr, 2);\n        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));\n        CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);\n        secp256k1_scalar_negate(&ss, &ss);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);\n        secp256k1_scalar_set_int(&ss, 1);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);\n    }\n\n    /* Verify signature with message 1 passes. */\n    {\n        const unsigned char pubkey[33] = {\n            0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22,\n            0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05,\n            0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c,\n            0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76,\n            0x25\n        };\n        const unsigned char pubkey2[33] = {\n            0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40,\n            0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae,\n            0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f,\n            0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10,\n            0x62\n        };\n        const unsigned char csr[32] = {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,\n            0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb\n        };\n        secp256k1_ge key;\n        secp256k1_ge key2;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 1);\n        secp256k1_scalar_set_int(&msg, 1);\n        secp256k1_scalar_set_b32(&sr, csr, NULL);\n        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));\n        CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33));\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);\n        secp256k1_scalar_negate(&ss, &ss);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1);\n        secp256k1_scalar_set_int(&ss, 2);\n        secp256k1_scalar_inverse_var(&ss, &ss);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0);\n    }\n\n    /* Verify signature with message -1 passes. */\n    {\n        const unsigned char pubkey[33] = {\n            0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0,\n            0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52,\n            0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27,\n            0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20,\n            0xf1\n        };\n        const unsigned char csr[32] = {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n            0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4,\n            0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee\n        };\n        secp256k1_ge key;\n        secp256k1_scalar msg;\n        secp256k1_scalar sr, ss;\n        secp256k1_scalar_set_int(&ss, 1);\n        secp256k1_scalar_set_int(&msg, 1);\n        secp256k1_scalar_negate(&msg, &msg);\n        secp256k1_scalar_set_b32(&sr, csr, NULL);\n        CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33));\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        secp256k1_scalar_negate(&ss, &ss);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1);\n        secp256k1_scalar_set_int(&ss, 3);\n        secp256k1_scalar_inverse_var(&ss, &ss);\n        CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);\n    }\n\n    /* Signature where s would be zero. */\n    {\n        secp256k1_pubkey pubkey;\n        size_t siglen;\n        int32_t ecount;\n        unsigned char signature[72];\n        static const unsigned char nonce[32] = {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        };\n        static const unsigned char nonce2[32] = {\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\n            0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,\n            0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,\n            0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40\n        };\n        const unsigned char key[32] = {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n        };\n        unsigned char msg[32] = {\n            0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53,\n            0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7,\n            0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,\n            0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,\n        };\n        ecount = 0;\n        secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0);\n        msg[31] = 0xaa;\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1);\n        CHECK(ecount == 0);\n        CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0);\n        CHECK(ecount == 1);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0);\n        CHECK(ecount == 2);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0);\n        CHECK(ecount == 3);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1);\n        CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1);\n        CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0);\n        CHECK(ecount == 4);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0);\n        CHECK(ecount == 5);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0);\n        CHECK(ecount == 6);\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1);\n        CHECK(ecount == 6);\n        CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0);\n        CHECK(ecount == 7);\n        /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */\n        CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0);\n        CHECK(ecount == 8);\n        siglen = 72;\n        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0);\n        CHECK(ecount == 9);\n        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0);\n        CHECK(ecount == 10);\n        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0);\n        CHECK(ecount == 11);\n        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);\n        CHECK(ecount == 11);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0);\n        CHECK(ecount == 12);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0);\n        CHECK(ecount == 13);\n        CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1);\n        CHECK(ecount == 13);\n        siglen = 10;\n        /* Too little room for a signature does not fail via ARGCHECK. */\n        CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);\n        CHECK(ecount == 13);\n        ecount = 0;\n        CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0);\n        CHECK(ecount == 1);\n        CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0);\n        CHECK(ecount == 2);\n        CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0);\n        CHECK(ecount == 3);\n        CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1);\n        CHECK(ecount == 3);\n        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0);\n        CHECK(ecount == 4);\n        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0);\n        CHECK(ecount == 5);\n        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1);\n        CHECK(ecount == 5);\n        memset(signature, 255, 64);\n        CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0);\n        CHECK(ecount == 5);\n        secp256k1_context_set_illegal_callback(ctx, NULL, NULL);\n    }\n\n    /* Nonce function corner cases. */\n    for (t = 0; t < 2; t++) {\n        static const unsigned char zero[32] = {0x00};\n        int i;\n        unsigned char key[32];\n        unsigned char msg[32];\n        secp256k1_ecdsa_signature sig2;\n        secp256k1_scalar sr[512], ss;\n        const unsigned char *extra;\n        extra = t == 0 ? NULL : zero;\n        memset(msg, 0, 32);\n        msg[31] = 1;\n        /* High key results in signature failure. */\n        memset(key, 0xFF, 32);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);\n        CHECK(is_empty_signature(&sig));\n        /* Zero key results in signature failure. */\n        memset(key, 0, 32);\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0);\n        CHECK(is_empty_signature(&sig));\n        /* Nonce function failure results in signature failure. */\n        key[31] = 1;\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0);\n        CHECK(is_empty_signature(&sig));\n        /* The retry loop successfully makes its way to the first good value. */\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1);\n        CHECK(!is_empty_signature(&sig));\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1);\n        CHECK(!is_empty_signature(&sig2));\n        CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);\n        /* The default nonce function is deterministic. */\n        CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);\n        CHECK(!is_empty_signature(&sig2));\n        CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);\n        /* The default nonce function changes output with different messages. */\n        for(i = 0; i < 256; i++) {\n            int j;\n            msg[0] = i;\n            CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);\n            CHECK(!is_empty_signature(&sig2));\n            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);\n            for (j = 0; j < i; j++) {\n                CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));\n            }\n        }\n        msg[0] = 0;\n        msg[31] = 2;\n        /* The default nonce function changes output with different keys. */\n        for(i = 256; i < 512; i++) {\n            int j;\n            key[0] = i - 256;\n            CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1);\n            CHECK(!is_empty_signature(&sig2));\n            secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2);\n            for (j = 0; j < i; j++) {\n                CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));\n            }\n        }\n        key[0] = 0;\n    }\n\n    {\n        /* Check that optional nonce arguments do not have equivalent effect. */\n        const unsigned char zeros[32] = {0};\n        unsigned char nonce[32];\n        unsigned char nonce2[32];\n        unsigned char nonce3[32];\n        unsigned char nonce4[32];\n        VG_UNDEF(nonce,32);\n        VG_UNDEF(nonce2,32);\n        VG_UNDEF(nonce3,32);\n        VG_UNDEF(nonce4,32);\n        CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1);\n        VG_CHECK(nonce,32);\n        CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1);\n        VG_CHECK(nonce2,32);\n        CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1);\n        VG_CHECK(nonce3,32);\n        CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1);\n        VG_CHECK(nonce4,32);\n        CHECK(memcmp(nonce, nonce2, 32) != 0);\n        CHECK(memcmp(nonce, nonce3, 32) != 0);\n        CHECK(memcmp(nonce, nonce4, 32) != 0);\n        CHECK(memcmp(nonce2, nonce3, 32) != 0);\n        CHECK(memcmp(nonce2, nonce4, 32) != 0);\n        CHECK(memcmp(nonce3, nonce4, 32) != 0);\n    }\n\n\n    /* Privkey export where pubkey is the point at infinity. */\n    {\n        unsigned char privkey[300];\n        unsigned char seckey[32] = {\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,\n            0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,\n            0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,\n        };\n        size_t outlen = 300;\n        CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));\n        outlen = 300;\n        CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));\n    }\n}\n\nvoid run_ecdsa_edge_cases(void) {\n    test_ecdsa_edge_cases();\n}\n\n#ifdef ENABLE_OPENSSL_TESTS\nEC_KEY *get_openssl_key(const unsigned char *key32) {\n    unsigned char privkey[300];\n    size_t privkeylen;\n    const unsigned char* pbegin = privkey;\n    int compr = secp256k1_rand_bits(1);\n    EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);\n    CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr));\n    CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));\n    CHECK(EC_KEY_check_key(ec_key));\n    return ec_key;\n}\n\nvoid test_ecdsa_openssl(void) {\n    secp256k1_gej qj;\n    secp256k1_ge q;\n    secp256k1_scalar sigr, sigs;\n    secp256k1_scalar one;\n    secp256k1_scalar msg2;\n    secp256k1_scalar key, msg;\n    EC_KEY *ec_key;\n    unsigned int sigsize = 80;\n    size_t secp_sigsize = 80;\n    unsigned char message[32];\n    unsigned char signature[80];\n    unsigned char key32[32];\n    secp256k1_rand256_test(message);\n    secp256k1_scalar_set_b32(&msg, message, NULL);\n    random_scalar_order_test(&key);\n    secp256k1_scalar_get_b32(key32, &key);\n    secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key);\n    secp256k1_ge_set_gej(&q, &qj);\n    ec_key = get_openssl_key(key32);\n    CHECK(ec_key != NULL);\n    CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));\n    CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize));\n    CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg));\n    secp256k1_scalar_set_int(&one, 1);\n    secp256k1_scalar_add(&msg2, &msg, &one);\n    CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2));\n\n    random_sign(&sigr, &sigs, &key, &msg, NULL);\n    CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs));\n    CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1);\n\n    EC_KEY_free(ec_key);\n}\n\nvoid run_ecdsa_openssl(void) {\n    int i;\n    for (i = 0; i < 10*count; i++) {\n        test_ecdsa_openssl();\n    }\n}\n#endif\n\n#ifdef ENABLE_MODULE_ECDH\n# include \"modules/ecdh/tests_impl.h\"\n#endif\n\n#ifdef ENABLE_MODULE_RECOVERY\n# include \"modules/recovery/tests_impl.h\"\n#endif\n\nint main(int argc, char **argv) {\n    unsigned char seed16[16] = {0};\n    unsigned char run32[32] = {0};\n    /* find iteration count */\n    if (argc > 1) {\n        count = strtol(argv[1], NULL, 0);\n    }\n\n    /* find random seed */\n    if (argc > 2) {\n        int pos = 0;\n        const char* ch = argv[2];\n        while (pos < 16 && ch[0] != 0 && ch[1] != 0) {\n            unsigned short sh;\n            if (sscanf(ch, \"%2hx\", &sh)) {\n                seed16[pos] = sh;\n            } else {\n                break;\n            }\n            ch += 2;\n            pos++;\n        }\n    } else {\n        FILE *frand = fopen(\"/dev/urandom\", \"r\");\n        if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) {\n            uint64_t t = time(NULL) * (uint64_t)1337;\n            seed16[0] ^= t;\n            seed16[1] ^= t >> 8;\n            seed16[2] ^= t >> 16;\n            seed16[3] ^= t >> 24;\n            seed16[4] ^= t >> 32;\n            seed16[5] ^= t >> 40;\n            seed16[6] ^= t >> 48;\n            seed16[7] ^= t >> 56;\n        }\n        fclose(frand);\n    }\n    secp256k1_rand_seed(seed16);\n\n    printf(\"test count = %i\\n\", count);\n    printf(\"random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\\n\", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]);\n\n    /* initialize */\n    run_context_tests();\n    ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n    if (secp256k1_rand_bits(1)) {\n        secp256k1_rand256(run32);\n        CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL));\n    }\n\n    run_rand_bits();\n    run_rand_int();\n\n    run_sha256_tests();\n    run_hmac_sha256_tests();\n    run_rfc6979_hmac_sha256_tests();\n\n#ifndef USE_NUM_NONE\n    /* num tests */\n    run_num_smalltests();\n#endif\n\n    /* scalar tests */\n    run_scalar_tests();\n\n    /* field tests */\n    run_field_inv();\n    run_field_inv_var();\n    run_field_inv_all_var();\n    run_field_misc();\n    run_field_convert();\n    run_sqr();\n    run_sqrt();\n\n    /* group tests */\n    run_ge();\n    run_group_decompress();\n\n    /* ecmult tests */\n    run_wnaf();\n    run_point_times_order();\n    run_ecmult_chain();\n    run_ecmult_constants();\n    run_ecmult_gen_blind();\n    run_ecmult_const_tests();\n    run_ec_combine();\n\n    /* endomorphism tests */\n#ifdef USE_ENDOMORPHISM\n    run_endomorphism_tests();\n#endif\n\n    /* EC point parser test */\n    run_ec_pubkey_parse_test();\n\n    /* EC key edge cases */\n    run_eckey_edge_case_test();\n\n#ifdef ENABLE_MODULE_ECDH\n    /* ecdh tests */\n    run_ecdh_tests();\n#endif\n\n    /* ecdsa tests */\n    run_random_pubkeys();\n    run_ecdsa_der_parse();\n    run_ecdsa_sign_verify();\n    run_ecdsa_end_to_end();\n    run_ecdsa_edge_cases();\n#ifdef ENABLE_OPENSSL_TESTS\n    run_ecdsa_openssl();\n#endif\n\n#ifdef ENABLE_MODULE_RECOVERY\n    /* ECDSA pubkey recovery tests */\n    run_recovery_tests();\n#endif\n\n    secp256k1_rand256(run32);\n    printf(\"random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\\n\", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);\n\n    /* shutdown */\n    secp256k1_context_destroy(ctx);\n\n    printf(\"no problems found\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "src/secp256k1/src/tests_exhaustive.c",
    "content": "/***********************************************************************\n * Copyright (c) 2016 Andrew Poelstra                                 *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <time.h>\n\n#undef USE_ECMULT_STATIC_PRECOMPUTATION\n\n#ifndef EXHAUSTIVE_TEST_ORDER\n/* see group_impl.h for allowable values */\n#define EXHAUSTIVE_TEST_ORDER 13\n#define EXHAUSTIVE_TEST_LAMBDA 9   /* cube root of 1 mod 13 */\n#endif\n\n#include \"include/secp256k1.h\"\n#include \"group.h\"\n#include \"secp256k1.c\"\n#include \"testrand_impl.h\"\n\n#ifdef ENABLE_MODULE_RECOVERY\n#include \"src/modules/recovery/main_impl.h\"\n#include \"include/secp256k1_recovery.h\"\n#endif\n\n/** stolen from tests.c */\nvoid ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {\n    CHECK(a->infinity == b->infinity);\n    if (a->infinity) {\n        return;\n    }\n    CHECK(secp256k1_fe_equal_var(&a->x, &b->x));\n    CHECK(secp256k1_fe_equal_var(&a->y, &b->y));\n}\n\nvoid ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {\n    secp256k1_fe z2s;\n    secp256k1_fe u1, u2, s1, s2;\n    CHECK(a->infinity == b->infinity);\n    if (a->infinity) {\n        return;\n    }\n    /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */\n    secp256k1_fe_sqr(&z2s, &b->z);\n    secp256k1_fe_mul(&u1, &a->x, &z2s);\n    u2 = b->x; secp256k1_fe_normalize_weak(&u2);\n    secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);\n    s2 = b->y; secp256k1_fe_normalize_weak(&s2);\n    CHECK(secp256k1_fe_equal_var(&u1, &u2));\n    CHECK(secp256k1_fe_equal_var(&s1, &s2));\n}\n\nvoid random_fe(secp256k1_fe *x) {\n    unsigned char bin[32];\n    do {\n        secp256k1_rand256(bin);\n        if (secp256k1_fe_set_b32(x, bin)) {\n            return;\n        }\n    } while(1);\n}\n/** END stolen from tests.c */\n\nint secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,\n                                      const unsigned char *key32, const unsigned char *algo16,\n                                      void *data, unsigned int attempt) {\n    secp256k1_scalar s;\n    int *idata = data;\n    (void)msg32;\n    (void)key32;\n    (void)algo16;\n    /* Some nonces cannot be used because they'd cause s and/or r to be zero.\n     * The signing function has retry logic here that just re-calls the nonce\n     * function with an increased `attempt`. So if attempt > 0 this means we\n     * need to change the nonce to avoid an infinite loop. */\n    if (attempt > 0) {\n        *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER;\n    }\n    secp256k1_scalar_set_int(&s, *idata);\n    secp256k1_scalar_get_b32(nonce32, &s);\n    return 1;\n}\n\n#ifdef USE_ENDOMORPHISM\nvoid test_exhaustive_endomorphism(const secp256k1_ge *group, int order) {\n    int i;\n    for (i = 0; i < order; i++) {\n        secp256k1_ge res;\n        secp256k1_ge_mul_lambda(&res, &group[i]);\n        ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);\n    }\n}\n#endif\n\nvoid test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {\n    int i, j;\n\n    /* Sanity-check (and check infinity functions) */\n    CHECK(secp256k1_ge_is_infinity(&group[0]));\n    CHECK(secp256k1_gej_is_infinity(&groupj[0]));\n    for (i = 1; i < order; i++) {\n        CHECK(!secp256k1_ge_is_infinity(&group[i]));\n        CHECK(!secp256k1_gej_is_infinity(&groupj[i]));\n    }\n\n    /* Check all addition formulae */\n    for (j = 0; j < order; j++) {\n        secp256k1_fe fe_inv;\n        secp256k1_fe_inv(&fe_inv, &groupj[j].z);\n        for (i = 0; i < order; i++) {\n            secp256k1_ge zless_gej;\n            secp256k1_gej tmp;\n            /* add_var */\n            secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);\n            ge_equals_gej(&group[(i + j) % order], &tmp);\n            /* add_ge */\n            if (j > 0) {\n                secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);\n                ge_equals_gej(&group[(i + j) % order], &tmp);\n            }\n            /* add_ge_var */\n            secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);\n            ge_equals_gej(&group[(i + j) % order], &tmp);\n            /* add_zinv_var */\n            zless_gej.infinity = groupj[j].infinity;\n            zless_gej.x = groupj[j].x;\n            zless_gej.y = groupj[j].y;\n            secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);\n            ge_equals_gej(&group[(i + j) % order], &tmp);\n        }\n    }\n\n    /* Check doubling */\n    for (i = 0; i < order; i++) {\n        secp256k1_gej tmp;\n        if (i > 0) {\n            secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL);\n            ge_equals_gej(&group[(2 * i) % order], &tmp);\n        }\n        secp256k1_gej_double_var(&tmp, &groupj[i], NULL);\n        ge_equals_gej(&group[(2 * i) % order], &tmp);\n    }\n\n    /* Check negation */\n    for (i = 1; i < order; i++) {\n        secp256k1_ge tmp;\n        secp256k1_gej tmpj;\n        secp256k1_ge_neg(&tmp, &group[i]);\n        ge_equals_ge(&group[order - i], &tmp);\n        secp256k1_gej_neg(&tmpj, &groupj[i]);\n        ge_equals_gej(&group[order - i], &tmpj);\n    }\n}\n\nvoid test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) {\n    int i, j, r_log;\n    for (r_log = 1; r_log < order; r_log++) {\n        for (j = 0; j < order; j++) {\n            for (i = 0; i < order; i++) {\n                secp256k1_gej tmp;\n                secp256k1_scalar na, ng;\n                secp256k1_scalar_set_int(&na, i);\n                secp256k1_scalar_set_int(&ng, j);\n\n                secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng);\n                ge_equals_gej(&group[(i * r_log + j) % order], &tmp);\n\n                if (i > 0) {\n                    secp256k1_ecmult_const(&tmp, &group[i], &ng);\n                    ge_equals_gej(&group[(i * j) % order], &tmp);\n                }\n            }\n        }\n    }\n}\n\nvoid r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {\n    secp256k1_fe x;\n    unsigned char x_bin[32];\n    k %= EXHAUSTIVE_TEST_ORDER;\n    x = group[k].x;\n    secp256k1_fe_normalize(&x);\n    secp256k1_fe_get_b32(x_bin, &x);\n    secp256k1_scalar_set_b32(r, x_bin, NULL);\n}\n\nvoid test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {\n    int s, r, msg, key;\n    for (s = 1; s < order; s++) {\n        for (r = 1; r < order; r++) {\n            for (msg = 1; msg < order; msg++) {\n                for (key = 1; key < order; key++) {\n                    secp256k1_ge nonconst_ge;\n                    secp256k1_ecdsa_signature sig;\n                    secp256k1_pubkey pk;\n                    secp256k1_scalar sk_s, msg_s, r_s, s_s;\n                    secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;\n                    int k, should_verify;\n                    unsigned char msg32[32];\n\n                    secp256k1_scalar_set_int(&s_s, s);\n                    secp256k1_scalar_set_int(&r_s, r);\n                    secp256k1_scalar_set_int(&msg_s, msg);\n                    secp256k1_scalar_set_int(&sk_s, key);\n\n                    /* Verify by hand */\n                    /* Run through every k value that gives us this r and check that *one* works.\n                     * Note there could be none, there could be multiple, ECDSA is weird. */\n                    should_verify = 0;\n                    for (k = 0; k < order; k++) {\n                        secp256k1_scalar check_x_s;\n                        r_from_k(&check_x_s, group, k);\n                        if (r_s == check_x_s) {\n                            secp256k1_scalar_set_int(&s_times_k_s, k);\n                            secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);\n                            secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);\n                            secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);\n                            should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);\n                        }\n                    }\n                    /* nb we have a \"high s\" rule */\n                    should_verify &= !secp256k1_scalar_is_high(&s_s);\n\n                    /* Verify by calling verify */\n                    secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s);\n                    memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));\n                    secp256k1_pubkey_save(&pk, &nonconst_ge);\n                    secp256k1_scalar_get_b32(msg32, &msg_s);\n                    CHECK(should_verify ==\n                          secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));\n                }\n            }\n        }\n    }\n}\n\nvoid test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {\n    int i, j, k;\n\n    /* Loop */\n    for (i = 1; i < order; i++) {  /* message */\n        for (j = 1; j < order; j++) {  /* key */\n            for (k = 1; k < order; k++) {  /* nonce */\n                const int starting_k = k;\n                secp256k1_ecdsa_signature sig;\n                secp256k1_scalar sk, msg, r, s, expected_r;\n                unsigned char sk32[32], msg32[32];\n                secp256k1_scalar_set_int(&msg, i);\n                secp256k1_scalar_set_int(&sk, j);\n                secp256k1_scalar_get_b32(sk32, &sk);\n                secp256k1_scalar_get_b32(msg32, &msg);\n\n                secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k);\n\n                secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);\n                /* Note that we compute expected_r *after* signing -- this is important\n                 * because our nonce-computing function function might change k during\n                 * signing. */\n                r_from_k(&expected_r, group, k);\n                CHECK(r == expected_r);\n                CHECK((k * s) % order == (i + r * j) % order ||\n                      (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);\n\n                /* Overflow means we've tried every possible nonce */\n                if (k < starting_k) {\n                    break;\n                }\n            }\n        }\n    }\n\n    /* We would like to verify zero-knowledge here by counting how often every\n     * possible (s, r) tuple appears, but because the group order is larger\n     * than the field order, when coercing the x-values to scalar values, some\n     * appear more often than others, so we are actually not zero-knowledge.\n     * (This effect also appears in the real code, but the difference is on the\n     * order of 1/2^128th the field order, so the deviation is not useful to a\n     * computationally bounded attacker.)\n     */\n}\n\n#ifdef ENABLE_MODULE_RECOVERY\nvoid test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {\n    int i, j, k;\n\n    /* Loop */\n    for (i = 1; i < order; i++) {  /* message */\n        for (j = 1; j < order; j++) {  /* key */\n            for (k = 1; k < order; k++) {  /* nonce */\n                const int starting_k = k;\n                secp256k1_fe r_dot_y_normalized;\n                secp256k1_ecdsa_recoverable_signature rsig;\n                secp256k1_ecdsa_signature sig;\n                secp256k1_scalar sk, msg, r, s, expected_r;\n                unsigned char sk32[32], msg32[32];\n                int expected_recid;\n                int recid;\n                secp256k1_scalar_set_int(&msg, i);\n                secp256k1_scalar_set_int(&sk, j);\n                secp256k1_scalar_get_b32(sk32, &sk);\n                secp256k1_scalar_get_b32(msg32, &msg);\n\n                secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);\n\n                /* Check directly */\n                secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);\n                r_from_k(&expected_r, group, k);\n                CHECK(r == expected_r);\n                CHECK((k * s) % order == (i + r * j) % order ||\n                      (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);\n                /* In computing the recid, there is an overflow condition that is disabled in\n                 * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value\n                 * will exceed the group order, and our signing code always holds out for r\n                 * values that don't overflow, so with a proper overflow check the tests would\n                 * loop indefinitely. */\n                r_dot_y_normalized = group[k].y;\n                secp256k1_fe_normalize(&r_dot_y_normalized);\n                /* Also the recovery id is flipped depending if we hit the low-s branch */\n                if ((k * s) % order == (i + r * j) % order) {\n                    expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0;\n                } else {\n                    expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1;\n                }\n                CHECK(recid == expected_recid);\n\n                /* Convert to a standard sig then check */\n                secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);\n                secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);\n                /* Note that we compute expected_r *after* signing -- this is important\n                 * because our nonce-computing function function might change k during\n                 * signing. */\n                r_from_k(&expected_r, group, k);\n                CHECK(r == expected_r);\n                CHECK((k * s) % order == (i + r * j) % order ||\n                      (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);\n\n                /* Overflow means we've tried every possible nonce */\n                if (k < starting_k) {\n                    break;\n                }\n            }\n        }\n    }\n}\n\nvoid test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {\n    /* This is essentially a copy of test_exhaustive_verify, with recovery added */\n    int s, r, msg, key;\n    for (s = 1; s < order; s++) {\n        for (r = 1; r < order; r++) {\n            for (msg = 1; msg < order; msg++) {\n                for (key = 1; key < order; key++) {\n                    secp256k1_ge nonconst_ge;\n                    secp256k1_ecdsa_recoverable_signature rsig;\n                    secp256k1_ecdsa_signature sig;\n                    secp256k1_pubkey pk;\n                    secp256k1_scalar sk_s, msg_s, r_s, s_s;\n                    secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;\n                    int recid = 0;\n                    int k, should_verify;\n                    unsigned char msg32[32];\n\n                    secp256k1_scalar_set_int(&s_s, s);\n                    secp256k1_scalar_set_int(&r_s, r);\n                    secp256k1_scalar_set_int(&msg_s, msg);\n                    secp256k1_scalar_set_int(&sk_s, key);\n                    secp256k1_scalar_get_b32(msg32, &msg_s);\n\n                    /* Verify by hand */\n                    /* Run through every k value that gives us this r and check that *one* works.\n                     * Note there could be none, there could be multiple, ECDSA is weird. */\n                    should_verify = 0;\n                    for (k = 0; k < order; k++) {\n                        secp256k1_scalar check_x_s;\n                        r_from_k(&check_x_s, group, k);\n                        if (r_s == check_x_s) {\n                            secp256k1_scalar_set_int(&s_times_k_s, k);\n                            secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);\n                            secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);\n                            secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);\n                            should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);\n                        }\n                    }\n                    /* nb we have a \"high s\" rule */\n                    should_verify &= !secp256k1_scalar_is_high(&s_s);\n\n                    /* We would like to try recovering the pubkey and checking that it matches,\n                     * but pubkey recovery is impossible in the exhaustive tests (the reason\n                     * being that there are 12 nonzero r values, 12 nonzero points, and no\n                     * overlap between the sets, so there are no valid signatures). */\n\n                    /* Verify by converting to a standard signature and calling verify */\n                    secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);\n                    secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);\n                    memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));\n                    secp256k1_pubkey_save(&pk, &nonconst_ge);\n                    CHECK(should_verify ==\n                          secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));\n                }\n            }\n        }\n    }\n}\n#endif\n\nint main(void) {\n    int i;\n    secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];\n    secp256k1_ge group[EXHAUSTIVE_TEST_ORDER];\n\n    /* Build context */\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);\n\n    /* TODO set z = 1, then do num_tests runs with random z values */\n\n    /* Generate the entire group */\n    secp256k1_gej_set_infinity(&groupj[0]);\n    secp256k1_ge_set_gej(&group[0], &groupj[0]);\n    for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {\n        /* Set a different random z-value for each Jacobian point */\n        secp256k1_fe z;\n        random_fe(&z);\n\n        secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g);\n        secp256k1_ge_set_gej(&group[i], &groupj[i]);\n        secp256k1_gej_rescale(&groupj[i], &z);\n\n        /* Verify against ecmult_gen */\n        {\n            secp256k1_scalar scalar_i;\n            secp256k1_gej generatedj;\n            secp256k1_ge generated;\n\n            secp256k1_scalar_set_int(&scalar_i, i);\n            secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i);\n            secp256k1_ge_set_gej(&generated, &generatedj);\n\n            CHECK(group[i].infinity == 0);\n            CHECK(generated.infinity == 0);\n            CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x));\n            CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y));\n        }\n    }\n\n    /* Run the tests */\n#ifdef USE_ENDOMORPHISM\n    test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER);\n#endif\n    test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER);\n    test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER);\n    test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);\n    test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);\n\n#ifdef ENABLE_MODULE_RECOVERY\n    test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);\n    test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);\n#endif\n\n    secp256k1_context_destroy(ctx);\n    return 0;\n}\n\n"
  },
  {
    "path": "src/secp256k1/src/util.h",
    "content": "/**********************************************************************\n * Copyright (c) 2013, 2014 Pieter Wuille                             *\n * Distributed under the MIT software license, see the accompanying   *\n * file COPYING or http://www.opensource.org/licenses/mit-license.php.*\n **********************************************************************/\n\n#ifndef _SECP256K1_UTIL_H_\n#define _SECP256K1_UTIL_H_\n\n#if defined HAVE_CONFIG_H\n#include \"libsecp256k1-config.h\"\n#endif\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdio.h>\n\ntypedef struct {\n    void (*fn)(const char *text, void* data);\n    const void* data;\n} secp256k1_callback;\n\nstatic SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) {\n    cb->fn(text, (void*)cb->data);\n}\n\n#ifdef DETERMINISTIC\n#define TEST_FAILURE(msg) do { \\\n    fprintf(stderr, \"%s\\n\", msg); \\\n    abort(); \\\n} while(0);\n#else\n#define TEST_FAILURE(msg) do { \\\n    fprintf(stderr, \"%s:%d: %s\\n\", __FILE__, __LINE__, msg); \\\n    abort(); \\\n} while(0)\n#endif\n\n#ifdef HAVE_BUILTIN_EXPECT\n#define EXPECT(x,c) __builtin_expect((x),(c))\n#else\n#define EXPECT(x,c) (x)\n#endif\n\n#ifdef DETERMINISTIC\n#define CHECK(cond) do { \\\n    if (EXPECT(!(cond), 0)) { \\\n        TEST_FAILURE(\"test condition failed\"); \\\n    } \\\n} while(0)\n#else\n#define CHECK(cond) do { \\\n    if (EXPECT(!(cond), 0)) { \\\n        TEST_FAILURE(\"test condition failed: \" #cond); \\\n    } \\\n} while(0)\n#endif\n\n/* Like assert(), but when VERIFY is defined, and side-effect safe. */\n#if defined(COVERAGE)\n#define VERIFY_CHECK(check)\n#define VERIFY_SETUP(stmt)\n#elif defined(VERIFY)\n#define VERIFY_CHECK CHECK\n#define VERIFY_SETUP(stmt) do { stmt; } while(0)\n#else\n#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)\n#define VERIFY_SETUP(stmt)\n#endif\n\nstatic SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {\n    void *ret = malloc(size);\n    if (ret == NULL) {\n        secp256k1_callback_call(cb, \"Out of memory\");\n    }\n    return ret;\n}\n\n/* Macro for restrict, when available and not in a VERIFY build. */\n#if defined(SECP256K1_BUILD) && defined(VERIFY)\n# define SECP256K1_RESTRICT\n#else\n# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )\n#  if SECP256K1_GNUC_PREREQ(3,0)\n#   define SECP256K1_RESTRICT __restrict__\n#  elif (defined(_MSC_VER) && _MSC_VER >= 1400)\n#   define SECP256K1_RESTRICT __restrict\n#  else\n#   define SECP256K1_RESTRICT\n#  endif\n# else\n#  define SECP256K1_RESTRICT restrict\n# endif\n#endif\n\n#if defined(_WIN32)\n# define I64FORMAT \"I64d\"\n# define I64uFORMAT \"I64u\"\n#else\n# define I64FORMAT \"lld\"\n# define I64uFORMAT \"llu\"\n#endif\n\n#if defined(HAVE___INT128)\n# if defined(__GNUC__)\n#  define SECP256K1_GNUC_EXT __extension__\n# else\n#  define SECP256K1_GNUC_EXT\n# endif\nSECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;\n#endif\n\n#endif\n"
  },
  {
    "path": "src/serialize.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_SERIALIZE_H\n#define CORE_SERIALIZE_H\n\n#include \"compat/endian.h\"\n\n#include <algorithm>\n#include <assert.h>\n#include <ios>\n#include <limits>\n#include <map>\n#include <memory>\n#include <set>\n#include <stdint.h>\n#include <string>\n#include <string.h>\n#include <utility>\n#include <vector>\n#include <type_traits>\n\n#include <prevector.h>\n#include \"support/allocators/secure.h\"\n#include <span.h>\n\n/**\n * The maximum size of a serialized object in bytes or number of elements\n * (for eg vectors) when the size is encoded as CompactSize.\n */\nstatic constexpr uint64_t MAX_SIZE = 0x02000000;\n\n/** Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */\nstatic const unsigned int MAX_VECTOR_ALLOCATE = 5000000;\n\n/**\n * Dummy data type to identify deserializing constructors.\n *\n * By convention, a constructor of a type T with signature\n *\n *   template <typename Stream> T::T(deserialize_type, Stream& s)\n *\n * is a deserializing constructor, which builds the type by\n * deserializing it from s. If T contains const fields, this\n * is likely the only way to do so.\n */\nstruct deserialize_type {};\nconstexpr deserialize_type deserialize {};\n\n/**\n * Used to bypass the rule against non-const reference to temporary\n * where it makes sense with wrappers such as CFlatData or CTxDB\n */\ntemplate<typename T>\ninline T& REF(const T& val)\n{\n    return const_cast<T&>(val);\n}\n\n/**\n * Used to acquire a non-const pointer \"this\" to generate bodies\n * of const serialization operations from a template\n */\ntemplate<typename T>\ninline T* NCONST_PTR(const T* val)\n{\n    return const_cast<T*>(val);\n}\n\n/*\n * Lowest-level serialization and conversion.\n */\ntemplate<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)\n{\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)\n{\n    obj = htole16(obj);\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj)\n{\n    obj = htobe16(obj);\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)\n{\n    obj = htole32(obj);\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)\n{\n    obj = htobe32(obj);\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)\n{\n    obj = htole64(obj);\n    s.write(AsBytes(Span{&obj, 1}));\n}\ntemplate<typename Stream> inline uint8_t ser_readdata8(Stream &s)\n{\n    uint8_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return obj;\n}\ntemplate<typename Stream> inline uint16_t ser_readdata16(Stream &s)\n{\n    uint16_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return le16toh(obj);\n}\ntemplate<typename Stream> inline uint16_t ser_readdata16be(Stream &s)\n{\n    uint16_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return be16toh(obj);\n}\ntemplate<typename Stream> inline uint32_t ser_readdata32(Stream &s)\n{\n    uint32_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return le32toh(obj);\n}\ntemplate<typename Stream> inline uint32_t ser_readdata32be(Stream &s)\n{\n    uint32_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return be32toh(obj);\n}\ntemplate<typename Stream> inline uint64_t ser_readdata64(Stream &s)\n{\n    uint64_t obj;\n    s.read(AsWritableBytes(Span{&obj, 1}));\n    return le64toh(obj);\n}\ninline uint64_t ser_double_to_uint64(double x)\n{\n    union { double x; uint64_t y; } tmp;\n    tmp.x = x;\n    return tmp.y;\n}\ninline uint32_t ser_float_to_uint32(float x)\n{\n    union { float x; uint32_t y; } tmp;\n    tmp.x = x;\n    return tmp.y;\n}\ninline double ser_uint64_to_double(uint64_t y)\n{\n    union { double x; uint64_t y; } tmp;\n    tmp.y = y;\n    return tmp.x;\n}\ninline float ser_uint32_to_float(uint32_t y)\n{\n    union { float x; uint32_t y; } tmp;\n    tmp.y = y;\n    return tmp.x;\n}\n\n\n/////////////////////////////////////////////////////////////////\n//\n// Templates for serializing to anything that looks like a stream,\n// i.e. anything that supports .read(Span<std::byte>) and .write(Span<const std::byte>)\n//\n\nclass CSizeComputer;\n\nenum\n{\n    // primary actions\n    SER_NETWORK         = (1 << 0),\n    SER_DISK            = (1 << 1),\n    SER_GETHASH         = (1 << 2),\n};\n\n#define READWRITE(obj)      (::SerReadWrite(s, (obj), ser_action))\n#define READWRITEMANY(...)  (::SerReadWriteMany(s, ser_action, __VA_ARGS__))\n#define STRWRITE(obj)       (::SerWrite(s, (obj), ser_action))\n#define STRREAD(obj)        (::SerRead(s, (obj), ser_action))\n\n#define STRPEEK(obj)       (::SerPeek(s, (obj), ser_action))\n#define STRSKIP(obj)       (::SerSkip(s, (obj), ser_action))\n\n\n/** \n * Implement three methods for serializable objects. These are actually wrappers over\n * \"SerializationOp\" template, which implements the body of each class' serialization\n * code. Adding \"ADD_SERIALIZE_METHODS\" in the body of the class causes these wrappers to be\n * added as members. \n */\n#define ADD_SERIALIZE_METHODS                                         \\\n    template<typename Stream>                                         \\\n    void Serialize(Stream& s) const {                                 \\\n        NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize());  \\\n    }                                                                 \\\n    template<typename Stream>                                         \\\n    void Unserialize(Stream& s) {                                     \\\n        SerializationOp(s, CSerActionUnserialize());                  \\\n    }\n\ntemplate<typename Stream> inline void Serialize(Stream& s, char a    ) { ser_writedata8(s, a); } // TODO Get rid of bare char\ntemplate<typename Stream> inline void Serialize(Stream& s, int8_t a  ) { ser_writedata8(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); }\ntemplate<typename Stream> inline void Serialize(Stream& s, float a   ) { ser_writedata32(s, ser_float_to_uint32(a)); }\ntemplate<typename Stream> inline void Serialize(Stream& s, double a  ) { ser_writedata64(s, ser_double_to_uint64(a)); }\n\ntemplate<typename Stream> inline void Unserialize(Stream& s, char& a    ) { a = ser_readdata8(s); } // TODO Get rid of bare char\ntemplate<typename Stream> inline void Unserialize(Stream& s, int8_t& a  ) { a = ser_readdata8(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, float& a   ) { a = ser_uint32_to_float(ser_readdata32(s)); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, double& a  ) { a = ser_uint64_to_double(ser_readdata64(s)); }\n\ntemplate<typename Stream> inline void Serialize(Stream& s, bool a)    { char f=a; ser_writedata8(s, f); }\ntemplate<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; }\n\n\n\n\n\n\n/**\n * Compact Size\n * size <  253        -- 1 byte\n * size <= USHRT_MAX  -- 3 bytes  (253 + 2 bytes)\n * size <= UINT_MAX   -- 5 bytes  (254 + 4 bytes)\n * size >  UINT_MAX   -- 9 bytes  (255 + 8 bytes)\n */\ninline unsigned int GetSizeOfCompactSize(uint64_t nSize)\n{\n    if (nSize < 253)             return sizeof(unsigned char);\n    else if (nSize <= std::numeric_limits<uint16_t>::max()) return sizeof(unsigned char) + sizeof(uint16_t);\n    else if (nSize <= std::numeric_limits<unsigned int>::max())  return sizeof(unsigned char) + sizeof(unsigned int);\n    else                         return sizeof(unsigned char) + sizeof(uint64_t);\n}\n\ninline void WriteCompactSize(CSizeComputer& os, uint64_t nSize);\n\ntemplate<typename Stream>\nvoid WriteCompactSize(Stream& os, uint64_t nSize)\n{\n    if (nSize < 253)\n    {\n        ser_writedata8(os, nSize);\n    }\n    else if (nSize <= std::numeric_limits<uint16_t>::max())\n    {\n        ser_writedata8(os, 253);\n        ser_writedata16(os, nSize);\n    }\n    else if (nSize <= std::numeric_limits<unsigned int>::max())\n    {\n        ser_writedata8(os, 254);\n        ser_writedata32(os, nSize);\n    }\n    else\n    {\n        ser_writedata8(os, 255);\n        ser_writedata64(os, nSize);\n    }\n    return;\n}\n\n/**\n * Decode a CompactSize-encoded variable-length integer.\n *\n * As these are primarily used to encode the size of vector-like serializations, by default a range\n * check is performed. When used as a generic number encoding, range_check should be set to false.\n */\ntemplate<typename Stream>\nuint64_t ReadCompactSize(Stream& is, bool range_check = true)\n{\n    uint8_t chSize = ser_readdata8(is);\n    uint64_t nSizeRet = 0;\n    if (chSize < 253)\n    {\n        nSizeRet = chSize;\n    }\n    else if (chSize == 253)\n    {\n        nSizeRet = ser_readdata16(is);\n        if (nSizeRet < 253)\n            throw std::ios_base::failure(\"non-canonical ReadCompactSize()\");\n    }\n    else if (chSize == 254)\n    {\n        nSizeRet = ser_readdata32(is);\n        if (nSizeRet < 0x10000u)\n            throw std::ios_base::failure(\"non-canonical ReadCompactSize()\");\n    }\n    else\n    {\n        nSizeRet = ser_readdata64(is);\n        if (nSizeRet < 0x100000000ULL)\n            throw std::ios_base::failure(\"non-canonical ReadCompactSize()\");\n    }\n    if (range_check && nSizeRet > MAX_SIZE) {\n        throw std::ios_base::failure(\"ReadCompactSize(): size too large\");\n    }\n    return nSizeRet;\n}\n\n/**\n * Variable-length integers: bytes are a MSB base-128 encoding of the number.\n * The high bit in each byte signifies whether another digit follows. To make\n * sure the encoding is one-to-one, one is subtracted from all but the last digit.\n * Thus, the byte sequence a[] with length len, where all but the last byte\n * has bit 128 set, encodes the number:\n *\n *  (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1))\n *\n * Properties:\n * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes)\n * * Every integer has exactly one encoding\n * * Encoding does not depend on size of original integer type\n * * No redundancy: every (infinite) byte sequence corresponds to a list\n *   of encoded integers.\n *\n * 0:         [0x00]  256:        [0x81 0x00]\n * 1:         [0x01]  16383:      [0xFE 0x7F]\n * 127:       [0x7F]  16384:      [0xFF 0x00]\n * 128:  [0x80 0x00]  16511:      [0xFF 0x7F]\n * 255:  [0x80 0x7F]  65535: [0x82 0xFE 0x7F]\n * 2^32:           [0x8E 0xFE 0xFE 0xFF 0x00]\n */\n\ntemplate<typename I>\ninline unsigned int GetSizeOfVarInt(I n)\n{\n    int nRet = 0;\n    while(true) {\n        nRet++;\n        if (n <= 0x7F)\n            break;\n        n = (n >> 7) - 1;\n    }\n    return nRet;\n}\n\ntemplate<typename I>\ninline void WriteVarInt(CSizeComputer& os, I n);\n\ntemplate<typename Stream, typename I>\nvoid WriteVarInt(Stream& os, I n)\n{\n    unsigned char tmp[(sizeof(n)*8+6)/7];\n    int len=0;\n    while(true) {\n        tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);\n        if (n <= 0x7F)\n            break;\n        n = (n >> 7) - 1;\n        len++;\n    }\n    do {\n        ser_writedata8(os, tmp[len]);\n    } while(len--);\n}\n\ntemplate<typename Stream, typename I>\nI ReadVarInt(Stream& is)\n{\n    I n = 0;\n    while(true) {\n        unsigned char chData = ser_readdata8(is);\n        if (n > (std::numeric_limits<I>::max() >> 7)) {\n           throw std::ios_base::failure(\"ReadVarInt(): size too large\");\n        }\n        n = (n << 7) | (chData & 0x7F);\n        if (chData & 0x80) {\n            if (n == std::numeric_limits<I>::max()) {\n                throw std::ios_base::failure(\"ReadVarInt(): size too large\");\n            }\n            n++;\n        } else {\n            return n;\n        }\n    }\n}\n\n#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))\n#define VARINT(obj) REF(WrapVarInt(REF(obj)))\n#define COMPACTSIZE(obj) REF(MakeCCompactSize(REF(obj)))\n#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))\n\n/** \n * Wrapper for serializing arrays and POD.\n */\nclass CFlatData\n{\nprotected:\n    char* pbegin;\n    char* pend;\npublic:\n    CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }\n    template <class T, class TAl>\n    explicit CFlatData(std::vector<T,TAl> &v)\n    {\n        pbegin = (char*)v.data();\n        pend = (char*)(v.data() + v.size());\n    }\n    template <unsigned int N, typename T, typename S, typename D>\n    explicit CFlatData(prevector<N, T, S, D> &v)\n    {\n        pbegin = (char*)v.data();\n        pend = (char*)(v.data() + v.size());\n    }\n    char* begin() { return pbegin; }\n    const char* begin() const { return pbegin; }\n    char* end() { return pend; }\n    const char* end() const { return pend; }\n\n    template<typename Stream>\n    void Serialize(Stream& s) const\n    {\n        s.write(AsBytes(Span(pbegin, pend)));\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        s.read(AsWritableBytes(Span(pbegin, pend)));\n    }\n};\n\ntemplate<typename I>\nclass CVarInt\n{\nprotected:\n    I &n;\npublic:\n    CVarInt(I& nIn) : n(nIn) { }\n\n    template<typename Stream>\n    void Serialize(Stream &s) const {\n        WriteVarInt<Stream,I>(s, n);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s) {\n        n = ReadVarInt<Stream,I>(s);\n    }\n};\n\ntemplate<typename T> class CCompactSize\n{\nprotected:\n    T &n;\npublic:\n    CCompactSize(T& nIn) : n(nIn) { }\n\n    template<typename Stream>\n    void Serialize(Stream &s) const {\n        WriteCompactSize<Stream>(s, n);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s) {\n        n = ReadCompactSize<Stream>(s);\n    }\n};\n\ntemplate <class T> CCompactSize<T> MakeCCompactSize(T& t)\n{\n    return CCompactSize<T>(t);\n}\n\ntemplate<size_t Limit>\nclass LimitedString\n{\nprotected:\n    std::string& string;\npublic:\n    LimitedString(std::string& _string) : string(_string) {}\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        size_t size = ReadCompactSize(s);\n        if (size > Limit) {\n            throw std::ios_base::failure(\"String length limit exceeded\");\n        }\n        string.resize(size);\n        if (size != 0)\n            s.read(MakeWritableByteSpan(string));\n    }\n\n    template<typename Stream>\n    void Serialize(Stream& s) const\n    {\n        WriteCompactSize(s, string.size());\n        if (!string.empty())\n            s.write((char*)&string[0], string.size());\n    }\n};\n\ntemplate<typename I>\nCVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); }\n\n/**\n * Forward declarations\n */\n\n/**\n *  string\n */\ntemplate<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str);\ntemplate<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str);\ntemplate<typename C, typename T, typename A> unsigned int GetSerializeSize(const std::basic_string<C, T, A>& str);\ntemplate<typename Stream, typename C, typename T, typename A> void Serialize(Stream& os, const std::basic_string<C, T, A>& str);\ntemplate<typename Stream, typename C, typename T, typename A> void Unserialize(Stream& is, std::basic_string<C, T, A>& str);\n\n/**\n * prevector\n * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.\n */\ntemplate<typename Stream, unsigned int N, typename T> void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&);\ntemplate<typename Stream, unsigned int N, typename T, typename V> void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&);\ntemplate<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v);\ntemplate<typename Stream, unsigned int N, typename T> void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&);\ntemplate<typename Stream, unsigned int N, typename T, typename V> void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&);\ntemplate<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v);\n\n/**\n * vectoroverwritewrapper\n * used by compactsizevectorwrapper, varintvectorwrapper, nosizevectorwrapper to allow template specilisation of serilisation with as little overhead as possible.\n */\ntemplate <typename VectorType, typename WrapperType> class vectoroverwritewrapper\n{\npublic:\n    VectorType& vector;\n    vectoroverwritewrapper(VectorType& vector_) : vector(vector_)\n    {\n    }\n};\n\n/**\n * compactsizevectorwrapper\n * same as normal vector but using compact size to represent the size when serializing\n */\nstruct compactsizevectorwrapper\n{\n    compactsizevectorwrapper() {};\n};\n\ntemplate<typename T> vectoroverwritewrapper<T, compactsizevectorwrapper> MakeCompactSizeVector(T& obj)\n{\n    return vectoroverwritewrapper<T, compactsizevectorwrapper> (obj);\n}\ntemplate<typename T> const vectoroverwritewrapper<const T, const compactsizevectorwrapper> MakeCompactSizeVector(const T& obj)\n{\n    return vectoroverwritewrapper<const T, const compactsizevectorwrapper> (obj);\n}\n\n#define COMPACTSIZEVECTOR(obj) REF(MakeCompactSizeVector(obj))\n#define READWRITECOMPACTSIZEVECTOR(obj) (READWRITE(REF(COMPACTSIZEVECTOR(obj))))\n\n/**\n * varintvectorwrapper\n * same as normal vector but using CVarInt to represent the size when serializing\n */\nstruct varintvectorwrapper\n{\n    varintvectorwrapper() {};\n};\n\ntemplate<typename T> vectoroverwritewrapper<T, varintvectorwrapper> MakeVarIntVector(T& obj)\n{\n    return vectoroverwritewrapper<T, varintvectorwrapper> (obj);\n}\ntemplate<typename T> const vectoroverwritewrapper<const T, const varintvectorwrapper> MakeVarIntVector(const T& obj)\n{\n    return vectoroverwritewrapper<const T, const varintvectorwrapper> (obj);\n}\n\n#define VARINTVECTOR(obj) REF(MakeVarIntVector(REF(obj)))\n#define READWRITEVARINTVECTOR(obj) (READWRITE(REF(VARINTVECTOR(REF(obj)))))\n\n/**\n * nosizevectorwrapper\n * same as normal vector but no size output when serializing, size must be obtained/set independently.\n */\nstruct nosizevectorwrapper\n{\n    nosizevectorwrapper() {};\n};\n\ntemplate<typename T> vectoroverwritewrapper<T, nosizevectorwrapper> MakeNoSizeVector(T& obj)\n{\n    return vectoroverwritewrapper<T, nosizevectorwrapper> (obj);\n}\ntemplate<typename T> const vectoroverwritewrapper<const T, const nosizevectorwrapper> MakeNoSizeVector(const T& obj)\n{\n    return vectoroverwritewrapper<const T, const nosizevectorwrapper> (obj);\n}\n\n#define NOSIZEVECTOR(obj) REF(MakeNoSizeVector(REF(obj)))\n#define READWRITENOSIZEVECTOR(obj) (READWRITE(REF(NOSIZEVECTOR(REF(obj)))))\n\n/**\n * pair\n */\ntemplate<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item);\ntemplate<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item);\n\n/**\n * tuple\n */\ntemplate<typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const std::tuple<T1, T2, T3>& item);\ntemplate<typename Stream, typename T1, typename T2, typename T3> void Serialize(Stream& os, const std::tuple<T1, T2, T3>& item);\ntemplate<typename Stream, typename T1, typename T2, typename T3> void Unserialize(Stream& is, std::tuple<T1, T2, T3>& item);\n\ntemplate<typename T1, typename T2, typename T3, typename T4> unsigned int GetSerializeSize(const std::tuple<T1, T2, T3, T4>& item);\ntemplate<typename Stream, typename T1, typename T2, typename T3, typename T4> void Serialize(Stream& os, const std::tuple<T1, T2, T3, T4>& item);\ntemplate<typename Stream, typename T1, typename T2, typename T3, typename T4> void Unserialize(Stream& is, std::tuple<T1, T2, T3, T4>& item);\n\n/**\n * map\n */\ntemplate<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m);\ntemplate<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m);\n\n/**\n * set\n */\ntemplate<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m);\ntemplate<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m);\n\n/**\n * shared_ptr\n */\ntemplate<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p);\ntemplate<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p);\n\n/**\n * unique_ptr\n */\ntemplate<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);\ntemplate<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);\n\n\ntemplate<typename Stream, typename T, typename std::enable_if<std::is_enum<T>::value,int>::type =0>\ninline void Serialize(Stream& os, const T& a)\n{\n    Serialize(os, static_cast<typename std::underlying_type<T>::type>(a));\n}\n\ntemplate<typename Stream, typename T, typename std::enable_if<std::is_enum<T>::value,int>::type =0>\ninline void Unserialize(Stream& os, T& a)\n{\n    typename std::underlying_type<T>::type value;\n    Unserialize(os, value);\n    a = static_cast<T>(value);\n}\n\n/**\n * If none of the specialized versions above matched, default to calling member function.\n */\ntemplate<typename Stream, typename T, typename std::enable_if<!std::is_enum<T>::value,int>::type =0>\ninline void Serialize(Stream& os, const T& a)\n{\n    a.Serialize(os);\n}\n\ntemplate<typename Stream, typename T, typename std::enable_if<!std::is_enum<T>::value,int>::type =0>\ninline void Unserialize(Stream& is, T& a)\n{\n    a.Unserialize(is);\n}\n\n\n\n\n\n/**\n * string\n */\ntemplate<typename Stream, typename C>\nvoid Serialize(Stream& os, const std::basic_string<C>& str)\n{\n    WriteCompactSize(os, str.size());\n    if (!str.empty())\n        os.write(MakeByteSpan(str));\n}\n\ntemplate<typename Stream, typename C>\nvoid Unserialize(Stream& is, std::basic_string<C>& str)\n{\n    unsigned int nSize = ReadCompactSize(is);\n    str.resize(nSize);\n    if (nSize != 0)\n        is.read(MakeWritableByteSpan(str));\n}\n\ntemplate<typename C, typename T, typename A>\nunsigned int GetSerializeSize(const std::basic_string<C, T, A>& str)\n{\n    return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]);\n}\n\ntemplate<typename Stream, typename C, typename T, typename A>\nvoid Serialize(Stream& os, const std::basic_string<C, T, A>& str)\n{\n    WriteCompactSize(os, str.size());\n    if (!str.empty())\n        os.write((char*)&str[0], str.size() * sizeof(str[0]));\n}\n\ntemplate<typename Stream, typename C, typename T, typename A>\nvoid Unserialize(Stream& is, std::basic_string<C, T, A>& str)\n{\n    unsigned int nSize = ReadCompactSize(is);\n    str.resize(nSize);\n    if (nSize != 0)\n        is.read((char*)&str[0], nSize * sizeof(str[0]));\n}\n\n\n\n\n\n/**\n * prevector\n */\ntemplate<typename Stream, unsigned int N, typename T>\nvoid Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&)\n{\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\ntemplate<typename Stream, unsigned int N, typename T, typename V>\nvoid Serialize_impl(Stream& os, const prevector<N, T>& v, const V&)\n{\n    WriteCompactSize(os, v.size());\n    for (typename prevector<N, T>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream, unsigned int N, typename T>\ninline void Serialize(Stream& os, const prevector<N, T>& v)\n{\n    Serialize_impl(os, v, T());\n}\n\n\ntemplate<typename Stream, unsigned int N, typename T>\nvoid Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&)\n{\n    // Limit size per read so bogus size value won't cause out of memory\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));\n        v.resize_uninitialized(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\ntemplate<typename Stream, unsigned int N, typename T, typename V>\nvoid Unserialize_impl(Stream& is, prevector<N, T>& v, const V&)\n{\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(T);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            Unserialize(is, v[i]);\n    }\n}\n\ntemplate<typename Stream, unsigned int N, typename T>\ninline void Unserialize(Stream& is, prevector<N, T>& v)\n{\n    Unserialize_impl(is, v, T());\n}\n\n\n\n/**\n * vector\n */\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<const std::vector<K>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<K>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    for (typename std::vector<K>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<K>, compactsizevectorwrapper>& item)\n{\n    const std::vector<K>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    for (typename std::vector<K>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<const std::vector<std::vector<K>>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<std::vector<K>>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    for (typename std::vector<std::vector<K>>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, COMPACTSIZEVECTOR(*vi));\n}\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<const std::vector<unsigned char>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(AsBytes(MakeByteSpan(v)));\n}\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<unsigned char>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<unsigned char>, compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\n\n\n\ntemplate<typename Stream, typename A>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<const std::vector<unsigned char, A>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char, A>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\ntemplate<typename Stream, typename A>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<unsigned char, A>, const compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char, A>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\ntemplate<typename Stream, typename A>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<unsigned char, A>, compactsizevectorwrapper>& item)\n{\n    const std::vector<unsigned char, A>& v = item.vector;\n    WriteCompactSize(os, v.size());\n    if (!v.empty())\n        os.write(MakeByteSpan(v));\n}\n\n\n\n\ntemplate<typename Stream, typename K>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<K>, compactsizevectorwrapper>& item)\n{\n    std::vector<K>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(K);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            Unserialize(is, v[i]);\n    }\n}\n\ntemplate<typename Stream, typename K>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<std::vector<K>>, compactsizevectorwrapper>& item)\n{\n    std::vector<std::vector<K>>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(K);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            Unserialize(is, COMPACTSIZEVECTOR(v[i]));\n    }\n}\n\ntemplate<typename Stream>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<unsigned char>, compactsizevectorwrapper>& item)\n{\n    std::vector<unsigned char>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\ntemplate<typename Stream, typename A>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<unsigned char, A>, compactsizevectorwrapper>& item)\n{\n    std::vector<unsigned char, A>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\ntemplate<typename Stream>\nvoid Unserialize(Stream& is, const vectoroverwritewrapper<std::vector<unsigned char>, compactsizevectorwrapper>& item)\n{\n    std::vector<unsigned char>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\ntemplate<typename Stream, typename A>\nvoid Unserialize(Stream& is, const vectoroverwritewrapper<std::vector<unsigned char, A>, compactsizevectorwrapper>& item)\n{\n    std::vector<unsigned char, A>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\ntemplate<typename Stream, typename A>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<const std::vector<unsigned char, A>, compactsizevectorwrapper>& item)\n{\n    std::vector<unsigned char, A>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\n/**\n * varintvectorwrapper\n */\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<K>, varintvectorwrapper>& item)\n{\n    const std::vector<K>& v = item.vector;\n    WriteVarInt(os, v.size());\n    for (typename std::vector<K>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, vectoroverwritewrapper<std::vector<K>, varintvectorwrapper>& item)\n{\n    std::vector<K>& v = item.vector;\n    WriteVarInt(os, v.size());\n    for (typename std::vector<K>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<std::vector<K>>, varintvectorwrapper>& item)\n{\n    const std::vector<std::vector<K>>& v = item.vector;\n    WriteVarInt(os, v.size());\n    for (typename std::vector<std::vector<K>>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, VARINTVECTOR(*vi));\n}\n\n\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<unsigned char>, varintvectorwrapper>& item)\n{\n    const std::vector<unsigned char>& v = item.vector;\n    WriteVarInt(os, v.size());\n    if (!v.empty())\n        os.write((char*)&v[0], v.size() * sizeof(unsigned char));\n}\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, vectoroverwritewrapper<std::vector<unsigned char>, varintvectorwrapper>& item)\n{\n    std::vector<unsigned char>& v = item.vector;\n    WriteVarInt(os, v.size());\n    if (!v.empty())\n        os.write((char*)&v[0], v.size() * sizeof(unsigned char));\n}\n\ntemplate<typename Stream, typename K>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<K>, varintvectorwrapper>& item)\n{\n    std::vector<K>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadVarInt<Stream, unsigned int>(is);\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(K);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            Unserialize(is, v[i]);\n    }\n}\n\ntemplate<typename Stream, typename K>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<std::vector<K>>, varintvectorwrapper>& item)\n{\n    std::vector<std::vector<K>>& v = item.vector;\n    v.clear();\n    unsigned int nSize = ReadVarInt<Stream, unsigned int>(is);\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(K);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            Unserialize(is, VARINTVECTOR(v[i]));\n    }\n}\n\n\n\n\n\n/**\n * nosizevectorwrapper\n */\ntemplate<typename Stream, typename K>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<std::vector<K>, nosizevectorwrapper>& item)\n{\n    const std::vector<K>& v = item.vector;\n    for (typename std::vector<K>::const_iterator vi = v.begin(); vi != v.end(); ++vi)\n        ::Serialize(os, (*vi));\n}\n\ntemplate<typename Stream>\nvoid Serialize(Stream& os, const vectoroverwritewrapper<const std::vector<unsigned char>, nosizevectorwrapper>& item)\n{\n    const std::vector<unsigned char>& v = item.vector;\n    if (!v.empty())\n        os.write((char*)&v[0], v.size() * sizeof(unsigned char));\n}\n\ntemplate<typename Stream, typename K>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<K>, nosizevectorwrapper>& item)\n{\n    std::vector<K>& v = item.vector;\n    //v.clear();\n    unsigned int nSize = v.size();\n    unsigned int i = 0;\n    unsigned int nMid = 0;\n    while (nMid < nSize)\n    {\n        nMid += 5000000 / sizeof(K);\n        if (nMid > nSize)\n            nMid = nSize;\n        v.resize(nMid);\n        for (; i < nMid; i++)\n            ::Unserialize(is, v[i]);\n    }\n}\n\ntemplate<typename Stream>\nvoid Unserialize(Stream& is, vectoroverwritewrapper<std::vector<unsigned char>, nosizevectorwrapper>& item)\n{\n    std::vector<unsigned char>& v = item.vector;\n    //v.clear();\n    unsigned int nSize = v.size();\n    unsigned int i = 0;\n    while (i < nSize)\n    {\n        unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(unsigned char)));\n        v.resize(i + blk);\n        is.read(AsWritableBytes(Span{&v[i], blk}));\n        i += blk;\n    }\n}\n\n\n/**\n * pair\n */\ntemplate<typename Stream, typename K, typename T>\nvoid Serialize(Stream& os, const std::pair<K, T>& item)\n{\n    static_assert(!std::is_same<T, compactsizevectorwrapper>::value, \"Must not execute on vector wrapper\");\n    static_assert(!std::is_same<T, nosizevectorwrapper>::value, \"Must not execute on vector wrapper\");\n    static_assert(!std::is_same<T, varintvectorwrapper>::value, \"Must not execute on vector wrapper\");\n    \n    Serialize(os, item.first);\n    Serialize(os, item.second);\n}\n\ntemplate<typename Stream, typename K, typename T>\nvoid Unserialize(Stream& is, std::pair<K, T>& item)\n{\n    Unserialize(is, item.first);\n    Unserialize(is, item.second);\n}\n\n\n\n/**\n * tuple\n */\ntemplate<typename T1, typename T2, typename T3>\nunsigned int GetSerializeSize(const std::tuple<T1, T2, T3>& item)\n{\n    return GetSerializeSize(std::get<0>(item)) + GetSerializeSize(std::get<1>(item)) + GetSerializeSize(std::get<2>(item));\n}\n\ntemplate<typename Stream, typename T1, typename T2, typename T3>\nvoid Serialize(Stream& os, const std::tuple<T1, T2, T3>& item)\n{\n    Serialize(os, std::get<0>(item));\n    Serialize(os, std::get<1>(item));\n    Serialize(os, std::get<2>(item));\n}\n\ntemplate<typename Stream, typename T1, typename T2, typename T3>\nvoid Unserialize(Stream& is, std::tuple<T1, T2, T3>& item)\n{\n    Unserialize(is, std::get<0>(item));\n    Unserialize(is, std::get<1>(item));\n    Unserialize(is, std::get<2>(item));\n}\n\ntemplate<typename T1, typename T2, typename T3, typename T4>\nunsigned int GetSerializeSize(const std::tuple<T1, T2, T3, T4>& item)\n{\n    return GetSerializeSize(std::get<0>(item)) + GetSerializeSize(std::get<1>(item)) + GetSerializeSize(std::get<2>(item)) + GetSerializeSize(std::get<3>(item));\n}\n\ntemplate<typename Stream, typename T1, typename T2, typename T3, typename T4>\nvoid Serialize(Stream& os, const std::tuple<T1, T2, T3, T4>& item)\n{\n    Serialize(os, std::get<0>(item));\n    Serialize(os, std::get<1>(item));\n    Serialize(os, std::get<2>(item));\n    Serialize(os, std::get<3>(item));\n}\n\ntemplate<typename Stream, typename T1, typename T2, typename T3, typename T4>\nvoid Unserialize(Stream& is, std::tuple<T1, T2, T3, T4>& item)\n{\n    Unserialize(is, std::get<0>(item));\n    Unserialize(is, std::get<1>(item));\n    Unserialize(is, std::get<2>(item));\n    Unserialize(is, std::get<3>(item));\n}\n\n\n\n/**\n * map\n */\ntemplate<typename Stream, typename K, typename T, typename Pred, typename A>\nvoid Serialize(Stream& os, const std::map<K, T, Pred, A>& m)\n{\n    WriteCompactSize(os, m.size());\n    for (const auto& entry : m)\n        Serialize(os, entry);\n}\n\ntemplate<typename Stream, typename K, typename T, typename Pred, typename A>\nvoid Unserialize(Stream& is, std::map<K, T, Pred, A>& m)\n{\n    m.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    typename std::map<K, T, Pred, A>::iterator mi = m.begin();\n    for (unsigned int i = 0; i < nSize; i++)\n    {\n        std::pair<K, T> item;\n        Unserialize(is, item);\n        mi = m.insert(mi, item);\n    }\n}\n\n\n\n/**\n * set\n */\ntemplate<typename Stream, typename K, typename Pred, typename A>\nvoid Serialize(Stream& os, const std::set<K, Pred, A>& m)\n{\n    WriteCompactSize(os, m.size());\n    for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)\n        Serialize(os, (*it));\n}\n\ntemplate<typename Stream, typename K, typename Pred, typename A>\nvoid Unserialize(Stream& is, std::set<K, Pred, A>& m)\n{\n    m.clear();\n    unsigned int nSize = ReadCompactSize(is);\n    typename std::set<K, Pred, A>::iterator it = m.begin();\n    for (unsigned int i = 0; i < nSize; i++)\n    {\n        K key;\n        Unserialize(is, key);\n        it = m.insert(it, key);\n    }\n}\n\n\n\n/**\n * unique_ptr\n */\ntemplate<typename Stream, typename T> void\nSerialize(Stream& os, const std::unique_ptr<const T>& p)\n{\n    Serialize(os, *p);\n}\n\ntemplate<typename Stream, typename T>\nvoid Unserialize(Stream& is, std::unique_ptr<const T>& p)\n{\n    p.reset(new T(deserialize, is));\n}\n\n\n\n/**\n * shared_ptr\n */\ntemplate<typename Stream, typename T> void\nSerialize(Stream& os, const std::shared_ptr<const T>& p)\n{\n    Serialize(os, *p);\n}\n\ntemplate<typename Stream, typename T>\nvoid Unserialize(Stream& is, std::shared_ptr<const T>& p)\n{\n    p = std::make_shared<const T>(deserialize, is);\n}\n\n\n\n/**\n * Support for ADD_SERIALIZE_METHODS and READWRITE macro\n */\nstruct CSerActionSerialize\n{\n    constexpr bool ForRead() const { return false; }\n};\nstruct CSerActionUnserialize\n{\n    constexpr bool ForRead() const { return true; }\n};\n\ntemplate<typename Stream, typename T>\ninline void SerReadWrite(Stream& s, const T& obj, [[maybe_unused]] CSerActionSerialize ser_action)\n{\n    ::Serialize(s, obj);\n}\n\ntemplate<typename Stream, typename T>\ninline void SerReadWrite(Stream& s, T& obj, [[maybe_unused]] CSerActionUnserialize ser_action)\n{\n    ::Unserialize(s, obj);\n}\n\ntemplate<typename Stream, typename T>\ninline void SerWrite(Stream& s, const T& obj, [[maybe_unused]] CSerActionSerialize ser_action)\n{\n    ::Serialize(s, obj);\n}\n\ntemplate<typename Stream, typename T>\ninline void SerWrite([[maybe_unused]] Stream& s, [[maybe_unused]] const T& obj, [[maybe_unused]] CSerActionUnserialize ser_action)\n{\n}\n\ntemplate<typename Stream, typename T>\ninline void SerRead([[maybe_unused]] Stream& s, [[maybe_unused]] const T& obj, [[maybe_unused]] CSerActionSerialize ser_action)\n{\n}\n\ntemplate<typename Stream, typename T>\ninline void SerRead(Stream& s, T& obj, [[maybe_unused]] CSerActionUnserialize ser_action)\n{\n    ::Unserialize(s, obj);\n}\n\ntemplate<typename Stream, typename T>\ninline void SerPeek(Stream& s, T& obj, [[maybe_unused]] CSerActionSerialize ser_action)\n{\n}\n\ntemplate<typename Stream, typename T>\ninline void SerPeek(Stream& s, T& obj, [[maybe_unused]] CSerActionUnserialize ser_action)\n{\n    s.peek((char*)&obj, sizeof(obj));\n}\n\ntemplate<typename Stream, typename T>\ninline void SerSkip(Stream& s, const T& obj, [[maybe_unused]] CSerActionSerialize ser_action)\n{\n}\n\ntemplate<typename Stream, typename T>\ninline void SerSkip(Stream& s, T& obj, CSerActionUnserialize ser_action)\n{\n    s.ignore(sizeof(obj));\n}\n\n\n\n\n\n/* ::GetSerializeSize implementations\n *\n * Computing the serialized size of objects is done through a special stream\n * object of type CSizeComputer, which only records the number of bytes written\n * to it.\n *\n * If your Serialize or SerializationOp method has non-trivial overhead for\n * serialization, it may be worthwhile to implement a specialized version for\n * CSizeComputer, which uses the s.seek() method to record bytes that would\n * be written instead.\n */\nclass CSizeComputer\n{\nprotected:\n    size_t nSize;\n\n    const int nType;\n    const int nVersion;\npublic:\n    CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}\n\n    void write([[maybe_unused]] const char *psz, size_t _nSize)\n    {\n        this->nSize += _nSize;\n    }\n\n    void write(Span<const std::byte> src)\n    {\n        this->nSize += src.size();\n    }\n\n    /** Pretend _nSize bytes are written, without specifying them. */\n    void seek(size_t _nSize)\n    {\n        this->nSize += _nSize;\n    }\n\n    template<typename T>\n    CSizeComputer& operator<<(const T& obj)\n    {\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n\n    size_t size() const {\n        return nSize;\n    }\n\n    int GetVersion() const { return nVersion; }\n    int GetType() const { return nType; }\n};\n\ntemplate<typename Stream>\nvoid SerializeMany(Stream& s)\n{\n}\n\ntemplate<typename Stream, typename Arg>\nvoid SerializeMany(Stream& s, Arg&& arg)\n{\n    ::Serialize(s, std::forward<Arg>(arg));\n}\n\ntemplate<typename Stream, typename Arg, typename... Args>\nvoid SerializeMany(Stream& s, Arg&& arg, Args&&... args)\n{\n    ::Serialize(s, std::forward<Arg>(arg));\n    ::SerializeMany(s, std::forward<Args>(args)...);\n}\n\ntemplate<typename Stream>\ninline void UnserializeMany(Stream& s)\n{\n}\n\ntemplate<typename Stream, typename Arg>\ninline void UnserializeMany(Stream& s, Arg& arg)\n{\n    ::Unserialize(s, arg);\n}\n\ntemplate<typename Stream, typename Arg, typename... Args>\ninline void UnserializeMany(Stream& s, Arg& arg, Args&... args)\n{\n    ::Unserialize(s, arg);\n    ::UnserializeMany(s, args...);\n}\n\ntemplate<typename Stream, typename... Args>\ninline void SerReadWriteMany(Stream& s, [[maybe_unused]] CSerActionSerialize ser_action, Args&&... args)\n{\n    ::SerializeMany(s, std::forward<Args>(args)...);\n}\n\ntemplate<typename Stream, typename... Args>\ninline void SerReadWriteMany(Stream& s, [[maybe_unused]] CSerActionUnserialize ser_action, Args&... args)\n{\n    ::UnserializeMany(s, args...);\n}\n\ntemplate<typename I>\ninline void WriteVarInt(CSizeComputer &s, I n)\n{\n    s.seek(GetSizeOfVarInt<I>(n));\n}\n\ninline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)\n{\n    s.seek(GetSizeOfCompactSize(nSize));\n}\n\ntemplate <typename T>\nsize_t GetSerializeSize(const T& t, int nType, int nVersion = 0)\n{\n    return (CSizeComputer(nType, nVersion) << t).size();\n}\n\ntemplate <typename S, typename T>\nsize_t GetSerializeSize(const S& s, const T& t)\n{\n    return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size();\n}\n\n#endif // CORE_SERIALIZE_H\n"
  },
  {
    "path": "src/span.h",
    "content": "// Copyright (c) 2018-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_SPAN_H\n#define CORE_SPAN_H\n\n#include <type_traits>\n#include <cstddef>\n#include <algorithm>\n#include <assert.h>\n\n#ifdef DEBUG\n#define CONSTEXPR_IF_NOT_DEBUG\n#define ASSERT_IF_DEBUG(x) assert((x))\n#else\n#define CONSTEXPR_IF_NOT_DEBUG constexpr\n#define ASSERT_IF_DEBUG(x)\n#endif\n\n#if defined(__clang__)\n#if __has_attribute(lifetimebound)\n#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]]\n#else\n#define SPAN_ATTR_LIFETIMEBOUND\n#endif\n#else\n#define SPAN_ATTR_LIFETIMEBOUND\n#endif\n\n/** A Span is an object that can refer to a contiguous sequence of objects.\n *\n * This file implements a subset of C++20's std::span.  It can be considered\n * temporary compatibility code until C++20 and is designed to be a\n * self-contained abstraction without depending on other project files. For this\n * reason, Clang lifetimebound is defined here instead of including\n * <attributes.h>, which also defines it.\n *\n * Things to be aware of when writing code that deals with Spans:\n *\n * - Similar to references themselves, Spans are subject to reference lifetime\n *   issues. The user is responsible for making sure the objects pointed to by\n *   a Span live as long as the Span is used. For example:\n *\n *       std::vector<int> vec{1,2,3,4};\n *       Span<int> sp(vec);\n *       vec.push_back(5);\n *       printf(\"%i\\n\", sp.front()); // UB!\n *\n *   may exhibit undefined behavior, as increasing the size of a vector may\n *   invalidate references.\n *\n * - One particular pitfall is that Spans can be constructed from temporaries,\n *   but this is unsafe when the Span is stored in a variable, outliving the\n *   temporary. For example, this will compile, but exhibits undefined behavior:\n *\n *       Span<const int> sp(std::vector<int>{1, 2, 3});\n *       printf(\"%i\\n\", sp.front()); // UB!\n *\n *   The lifetime of the vector ends when the statement it is created in ends.\n *   Thus the Span is left with a dangling reference, and using it is undefined.\n *\n * - Due to Span's automatic creation from range-like objects (arrays, and data\n *   types that expose a data() and size() member function), functions that\n *   accept a Span as input parameter can be called with any compatible\n *   range-like object. For example, this works:\n *\n *       void Foo(Span<const int> arg);\n *\n *       Foo(std::vector<int>{1, 2, 3}); // Works\n *\n *   This is very useful in cases where a function truly does not care about the\n *   container, and only about having exactly a range of elements. However it\n *   may also be surprising to see automatic conversions in this case.\n *\n *   When a function accepts a Span with a mutable element type, it will not\n *   accept temporaries; only variables or other references. For example:\n *\n *       void FooMut(Span<int> arg);\n *\n *       FooMut(std::vector<int>{1, 2, 3}); // Does not compile\n *       std::vector<int> baz{1, 2, 3};\n *       FooMut(baz); // Works\n *\n *   This is similar to how functions that take (non-const) lvalue references\n *   as input cannot accept temporaries. This does not work either:\n *\n *       void FooVec(std::vector<int>& arg);\n *       FooVec(std::vector<int>{1, 2, 3}); // Does not compile\n *\n *   The idea is that if a function accepts a mutable reference, a meaningful\n *   result will be present in that variable after the call. Passing a temporary\n *   is useless in that context.\n */\ntemplate<typename C>\nclass Span\n{\n    C* m_data;\n    std::size_t m_size;\n\n    template <class T>\n    struct is_Span_int : public std::false_type {};\n    template <class T>\n    struct is_Span_int<Span<T>> : public std::true_type {};\n    template <class T>\n    struct is_Span : public is_Span_int<typename std::remove_cv<T>::type>{};\n\n\npublic:\n    constexpr Span() noexcept : m_data(nullptr), m_size(0) {}\n\n    /** Construct a span from a begin pointer and a size.\n     *\n     * This implements a subset of the iterator-based std::span constructor in C++20,\n     * which is hard to implement without std::address_of.\n     */\n    template <typename T, typename std::enable_if<std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>\n    constexpr Span(T* begin, std::size_t size) noexcept : m_data(begin), m_size(size) {}\n\n    /** Construct a span from a begin and end pointer.\n     *\n     * This implements a subset of the iterator-based std::span constructor in C++20,\n     * which is hard to implement without std::address_of.\n     */\n    template <typename T, typename std::enable_if<std::is_convertible<T (*)[], C (*)[]>::value, int>::type = 0>\n    CONSTEXPR_IF_NOT_DEBUG Span(T* begin, T* end) noexcept : m_data(begin), m_size(end - begin)\n    {\n        ASSERT_IF_DEBUG(end >= begin);\n    }\n\n    /** Implicit conversion of spans between compatible types.\n     *\n     *  Specifically, if a pointer to an array of type O can be implicitly converted to a pointer to an array of type\n     *  C, then permit implicit conversion of Span<O> to Span<C>. This matches the behavior of the corresponding\n     *  C++20 std::span constructor.\n     *\n     *  For example this means that a Span<T> can be converted into a Span<const T>.\n     */\n    template <typename O, typename std::enable_if<std::is_convertible<O (*)[], C (*)[]>::value, int>::type = 0>\n    constexpr Span(const Span<O>& other) noexcept : m_data(other.m_data), m_size(other.m_size) {}\n\n    /** Default copy constructor. */\n    constexpr Span(const Span&) noexcept = default;\n\n    /** Default assignment operator. */\n    Span& operator=(const Span& other) noexcept = default;\n\n    /** Construct a Span from an array. This matches the corresponding C++20 std::span constructor. */\n    template <int N>\n    constexpr Span(C (&a)[N]) noexcept : m_data(a), m_size(N) {}\n\n    /** Construct a Span for objects with .data() and .size() (std::string, std::array, std::vector, ...).\n     *\n     * This implements a subset of the functionality provided by the C++20 std::span range-based constructor.\n     *\n     * To prevent surprises, only Spans for constant value types are supported when passing in temporaries.\n     * Note that this restriction does not exist when converting arrays or other Spans (see above).\n     */\n    template <typename V>\n    constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND,\n        typename std::enable_if<!is_Span<V>::value &&\n                                std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value &&\n                                std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)\n        : m_data(other.data()), m_size(other.size()){}\n\n    template <typename V>\n    constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND,\n        typename std::enable_if<!is_Span<V>::value &&\n                                std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value &&\n                                std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)\n        : m_data(other.data()), m_size(other.size()){}\n\n    constexpr C* data() const noexcept { return m_data; }\n    constexpr C* begin() const noexcept { return m_data; }\n    constexpr C* end() const noexcept { return m_data + m_size; }\n    CONSTEXPR_IF_NOT_DEBUG C& front() const noexcept\n    {\n        ASSERT_IF_DEBUG(size() > 0);\n        return m_data[0];\n    }\n    CONSTEXPR_IF_NOT_DEBUG C& back() const noexcept\n    {\n        ASSERT_IF_DEBUG(size() > 0);\n        return m_data[m_size - 1];\n    }\n    constexpr std::size_t size() const noexcept { return m_size; }\n    constexpr std::size_t size_bytes() const noexcept { return sizeof(C) * m_size; }\n    constexpr bool empty() const noexcept { return size() == 0; }\n    CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept\n    {\n        ASSERT_IF_DEBUG(size() > pos);\n        return m_data[pos];\n    }\n    CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset) const noexcept\n    {\n        ASSERT_IF_DEBUG(size() >= offset);\n        return Span<C>(m_data + offset, m_size - offset);\n    }\n    CONSTEXPR_IF_NOT_DEBUG Span<C> subspan(std::size_t offset, std::size_t count) const noexcept\n    {\n        ASSERT_IF_DEBUG(size() >= offset + count);\n        return Span<C>(m_data + offset, count);\n    }\n    CONSTEXPR_IF_NOT_DEBUG Span<C> first(std::size_t count) const noexcept\n    {\n        ASSERT_IF_DEBUG(size() >= count);\n        return Span<C>(m_data, count);\n    }\n    CONSTEXPR_IF_NOT_DEBUG Span<C> last(std::size_t count) const noexcept\n    {\n         ASSERT_IF_DEBUG(size() >= count);\n         return Span<C>(m_data + m_size - count, count);\n    }\n\n    friend constexpr bool operator==(const Span& a, const Span& b) noexcept { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }\n    friend constexpr bool operator!=(const Span& a, const Span& b) noexcept { return !(a == b); }\n    friend constexpr bool operator<(const Span& a, const Span& b) noexcept { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); }\n    friend constexpr bool operator<=(const Span& a, const Span& b) noexcept { return !(b < a); }\n    friend constexpr bool operator>(const Span& a, const Span& b) noexcept { return (b < a); }\n    friend constexpr bool operator>=(const Span& a, const Span& b) noexcept { return !(a < b); }\n\n    template <typename O> friend class Span;\n};\n\n// Deduction guides for Span\n// For the pointer/size based and iterator based constructor:\ntemplate <typename T, typename EndOrSize> Span(T*, EndOrSize) -> Span<T>;\n// For the array constructor:\ntemplate <typename T, std::size_t N> Span(T (&)[N]) -> Span<T>;\n// For the temporaries/rvalue references constructor, only supporting const output.\ntemplate <typename T> Span(T&&) -> Span<std::enable_if_t<!std::is_lvalue_reference_v<T>, const std::remove_pointer_t<decltype(std::declval<T&&>().data())>>>;\n// For (lvalue) references, supporting mutable output.\ntemplate <typename T> Span(T&) -> Span<std::remove_pointer_t<decltype(std::declval<T&>().data())>>;\n\n/** Pop the last element off a span, and return a reference to that element. */\ntemplate <typename T>\nT& SpanPopBack(Span<T>& span)\n{\n    size_t size = span.size();\n    ASSERT_IF_DEBUG(size > 0);\n    T& back = span[size - 1];\n    span = Span<T>(span.data(), size - 1);\n    return back;\n}\n\n//! Convert a data pointer to a std::byte data pointer.\n//! Where possible, please use the safer AsBytes helpers.\ninline const std::byte* ToBytePtr(const void* data) { return reinterpret_cast<const std::byte*>(data); }\ninline std::byte* ToBytePtr(void* data) { return reinterpret_cast<std::byte*>(data); }\n\n// From C++20 as_bytes and as_writeable_bytes\ntemplate <typename T>\nSpan<const std::byte> AsBytes(Span<T> s) noexcept\n{\n    return {ToBytePtr(s.data()), s.size_bytes()};\n}\ntemplate <typename T>\nSpan<std::byte> AsWritableBytes(Span<T> s) noexcept\n{\n    return {ToBytePtr(s.data()), s.size_bytes()};\n}\n\ntemplate <typename V>\nSpan<const std::byte> MakeByteSpan(V&& v) noexcept\n{\n    return AsBytes(Span{std::forward<V>(v)});\n}\ntemplate <typename V>\nSpan<std::byte> MakeWritableByteSpan(V&& v) noexcept\n{\n    return AsWritableBytes(Span{std::forward<V>(v)});\n}\n\n// Helper functions to safely cast to unsigned char pointers.\ninline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }\ninline unsigned char* UCharCast(unsigned char* c) { return c; }\ninline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }\ninline const unsigned char* UCharCast(const unsigned char* c) { return c; }\ninline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }\n\n// Helper function to safely convert a Span to a Span<[const] unsigned char>.\ntemplate <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }\n\n/** Like the Span constructor, but for (const) unsigned char member types only. Only works for (un)signed char containers. */\ntemplate <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(Span{std::forward<V>(v)})) { return UCharSpanCast(Span{std::forward<V>(v)}); }\n\n#endif // CORE_SPAN_H\n"
  },
  {
    "path": "src/streams.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_STREAMS_H\n#define CORE_STREAMS_H\n\n#include <serialize.h>\n#include <span.h>\n#include <support/allocators/zeroafterfree.h>\n\n#include <algorithm>\n#include <assert.h>\n#include <ios>\n#include <limits>\n#include <optional>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <string>\n#include <utility>\n#include <vector>\n\ntemplate<typename Stream>\nclass OverrideStream\n{\n    Stream* stream;\n\n    const int nType;\n    const int nVersion;\n\npublic:\n    OverrideStream(Stream* stream_, int nType_, int nVersion_) : stream(stream_), nType(nType_), nVersion(nVersion_) {}\n\n    template<typename T>\n    OverrideStream<Stream>& operator<<(const T& obj)\n    {\n        // Serialize to this stream\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n\n    template<typename T>\n    OverrideStream<Stream>& operator>>(T&& obj)\n    {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n\n    void write(Span<const std::byte> src)\n    {\n        stream->write(src);\n    }\n\n    void read(Span<std::byte> dst)\n    {\n        stream->read(dst);\n    }\n\n    void peek(char* pch, size_t nSize)\n    {\n        stream->peek(pch, nSize);\n    }\n\n    int GetVersion() const { return nVersion; }\n    int GetType() const { return nType; }\n    size_t size() const { return stream->size(); }\n    void ignore(size_t size) { return stream->ignore(size); }\n};\n\n/* Minimal stream for overwriting and/or appending to an existing byte vector\n *\n * The referenced vector will grow as necessary\n */\nclass CVectorWriter\n{\n public:\n\n/*\n * @param[in]  nTypeIn Serialization Type\n * @param[in]  nVersionIn Serialization Version (including any flags)\n * @param[in]  vchDataIn  Referenced byte vector to overwrite/append\n * @param[in]  nPosIn Starting position. Vector index where writes should start. The vector will initially\n *                    grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().\n*/\n    CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)\n    {\n        if(nPos > vchData.size())\n            vchData.resize(nPos);\n    }\n/*\n * (other params same as above)\n * @param[in]  args  A list of items to serialize starting at nPosIn.\n*/\n    template <typename... Args>\n    CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)\n    {\n        ::SerializeMany(*this, std::forward<Args>(args)...);\n    }\n    void write(Span<const std::byte> src)\n    {\n        assert(nPos <= vchData.size());\n        size_t nOverwrite = std::min(src.size(), vchData.size() - nPos);\n        if (nOverwrite) {\n            memcpy(vchData.data() + nPos, src.data(), nOverwrite);\n        }\n        if (nOverwrite < src.size()) {\n            vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.end()));\n        }\n        nPos += src.size();\n    }\n    template<typename T>\n    CVectorWriter& operator<<(const T& obj)\n    {\n        // Serialize to this stream\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n    int GetVersion() const\n    {\n        return nVersion;\n    }\n    int GetType() const\n    {\n        return nType;\n    }\n    void seek(size_t nSize)\n    {\n        nPos += nSize;\n        if(nPos > vchData.size())\n            vchData.resize(nPos);\n    }\nprivate:\n    const int nType;\n    const int nVersion;\n    std::vector<unsigned char>& vchData;\n    size_t nPos;\n};\n\n/*\n** Minimal stream for reading from an existing vector by reference\n */\nclass VectorReader\n{\nprivate:\n    const int m_type;\n    const int m_version;\n    const std::vector<unsigned char>& m_data;\n    size_t m_pos = 0;\n\npublic:\n\n    /**\n     * @param[in]  type Serialization Type\n     * @param[in]  version Serialization Version (including any flags)\n     * @param[in]  data Referenced byte vector to overwrite/append\n     * @param[in]  pos Starting position. Vector index where reads should start.\n     */\n    VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)\n        : m_type(type), m_version(version), m_data(data), m_pos(pos)\n    {\n        if (m_pos > m_data.size()) {\n            throw std::ios_base::failure(\"VectorReader(...): end of data (m_pos > m_data.size())\");\n        }\n    }\n\n    /**\n     * (other params same as above)\n     * @param[in]  args  A list of items to deserialize starting at pos.\n     */\n    template <typename... Args>\n    VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,\n                  Args&&... args)\n        : VectorReader(type, version, data, pos)\n    {\n        ::UnserializeMany(*this, std::forward<Args>(args)...);\n    }\n\n    template<typename T>\n    VectorReader& operator>>(T& obj)\n    {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n\n    int GetVersion() const { return m_version; }\n    int GetType() const { return m_type; }\n\n    size_t size() const { return m_data.size() - m_pos; }\n    bool empty() const { return m_data.size() == m_pos; }\n\n    void read(Span<std::byte> dst)\n    {\n        if (dst.size() == 0) {\n            return;\n        }\n\n        // Read from the beginning of the buffer\n        size_t pos_next = m_pos + dst.size();\n        if (pos_next > m_data.size()) {\n            throw std::ios_base::failure(\"VectorReader::read(): end of data\");\n        }\n        memcpy(dst.data(), m_data.data() + m_pos, dst.size());\n        m_pos = pos_next;\n    }\n\n    void read(char* dst, size_t n)\n    {\n        if (n == 0) {\n            return;\n        }\n\n        // Read from the beginning of the buffer\n        size_t pos_next = m_pos + n;\n        if (pos_next > m_data.size()) {\n            throw std::ios_base::failure(\"VectorReader::read(): end of data\");\n        }\n        memcpy(dst, m_data.data() + m_pos, n);\n        m_pos = pos_next;\n    }\n};\n\n/** Minimal stream for reading from an existing byte array by Span.\n */\nclass SpanReader\n{\nprivate:\n    const int m_type;\n    const int m_version;\n    Span<const unsigned char> m_data;\n\npublic:\n\n    /**\n     * @param[in]  type Serialization Type\n     * @param[in]  version Serialization Version (including any flags)\n     * @param[in]  data Referenced byte vector to overwrite/append\n     */\n    SpanReader(int type, int version, Span<const unsigned char> data)\n        : m_type(type), m_version(version), m_data(data) {}\n\n    template<typename T>\n    SpanReader& operator>>(T&& obj)\n    {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n\n    int GetVersion() const { return m_version; }\n    int GetType() const { return m_type; }\n\n    size_t size() const { return m_data.size(); }\n    bool empty() const { return m_data.empty(); }\n\n    void read(Span<std::byte> dst)\n    {\n        if (dst.size() == 0) {\n            return;\n        }\n\n        // Read from the beginning of the buffer\n        if (dst.size() > m_data.size()) {\n            throw std::ios_base::failure(\"SpanReader::read(): end of data\");\n        }\n        memcpy(dst.data(), m_data.data(), dst.size());\n        m_data = m_data.subspan(dst.size());\n    }\n};\n\n/** Double ended buffer combining vector and stream-like interfaces.\n *\n * >> and << read and write unformatted data using the above serialization templates.\n * Fills with data in linear time; some stringstream implementations take N^2 time.\n */\nclass CDataStream\n{\nprotected:\n    using vector_type = CSerializeData;\n    vector_type vch;\n    unsigned int nReadPos{0};\n\n    int nType;\n    int nVersion;\n\npublic:\n    typedef vector_type::allocator_type   allocator_type;\n    typedef vector_type::size_type        size_type;\n    typedef vector_type::difference_type  difference_type;\n    typedef vector_type::reference        reference;\n    typedef vector_type::const_reference  const_reference;\n    typedef vector_type::value_type       value_type;\n    typedef vector_type::iterator         iterator;\n    typedef vector_type::const_iterator   const_iterator;\n    typedef vector_type::reverse_iterator reverse_iterator;\n\n    explicit CDataStream(int nTypeIn, int nVersionIn)\n        : nType{nTypeIn},\n          nVersion{nVersionIn} {}\n\n    explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {}\n    explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)\n        : vch(sp.data(), sp.data() + sp.size()),\n          nType{nTypeIn},\n          nVersion{nVersionIn} {}\n\n    template <typename... Args>\n    CDataStream(int nTypeIn, int nVersionIn, Args&&... args)\n        : nType{nTypeIn},\n          nVersion{nVersionIn}\n    {\n        ::SerializeMany(*this, std::forward<Args>(args)...);\n    }\n\n    std::string str() const\n    {\n        return std::string{UCharCast(data()), UCharCast(data() + size())};\n    }\n\n\n    //\n    // Vector subset\n    //\n    const_iterator begin() const                     { return vch.begin() + nReadPos; }\n    iterator begin()                                 { return vch.begin() + nReadPos; }\n    const_iterator end() const                       { return vch.end(); }\n    iterator end()                                   { return vch.end(); }\n    size_type size() const                           { return vch.size() - nReadPos; }\n    bool empty() const                               { return vch.size() == nReadPos; }\n    void resize(size_type n, value_type c = value_type{}) { vch.resize(n + nReadPos, c); }\n    void reserve(size_type n)                        { vch.reserve(n + nReadPos); }\n    const_reference operator[](size_type pos) const  { return vch[pos + nReadPos]; }\n    reference operator[](size_type pos)              { return vch[pos + nReadPos]; }\n    void clear()                                     { vch.clear(); nReadPos = 0; }\n    iterator insert(iterator it, const value_type& x=value_type()) { return vch.insert(it, x); }\n    void insert(iterator it, size_type n, const value_type& x) { vch.insert(it, n, x); }\n    value_type* data()                               { return vch.data() + nReadPos; }\n    const value_type* data() const                   { return vch.data() + nReadPos; }\n\n    void insert(iterator it, const_iterator first, const_iterator last)\n    {\n        if (last == first) return;\n        assert(last - first > 0);\n        if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)\n        {\n            // special case for inserting at the front when there's room\n            nReadPos -= (last - first);\n            memcpy(&vch[nReadPos], &first[0], last - first);\n        }\n        else\n            vch.insert(it, first, last);\n    }\n\n    void insert(iterator it, const value_type* first, const value_type* last)\n    {\n        if (last == first) return;\n        assert(last - first > 0);\n        if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)\n        {\n            // special case for inserting at the front when there's room\n            nReadPos -= (last - first);\n            memcpy(&vch[nReadPos], &first[0], last - first);\n        }\n        else\n            vch.insert(it, first, last);\n    }\n\n    iterator erase(iterator it)\n    {\n        if (it == vch.begin() + nReadPos)\n        {\n            // special case for erasing from the front\n            if (++nReadPos >= vch.size())\n            {\n                // whenever we reach the end, we take the opportunity to clear the buffer\n                nReadPos = 0;\n                return vch.erase(vch.begin(), vch.end());\n            }\n            return vch.begin() + nReadPos;\n        }\n        else\n            return vch.erase(it);\n    }\n\n    iterator erase(iterator first, iterator last)\n    {\n        if (first == vch.begin() + nReadPos)\n        {\n            // special case for erasing from the front\n            if (last == vch.end())\n            {\n                nReadPos = 0;\n                return vch.erase(vch.begin(), vch.end());\n            }\n            else\n            {\n                nReadPos = (last - vch.begin());\n                return last;\n            }\n        }\n        else\n            return vch.erase(first, last);\n    }\n\n    inline void Compact()\n    {\n        vch.erase(vch.begin(), vch.begin() + nReadPos);\n        nReadPos = 0;\n    }\n\n    bool Rewind(std::optional<size_type> n = std::nullopt)\n    {\n        // Total rewind if no size is passed\n        if (!n) {\n            nReadPos = 0;\n            return true;\n        }\n        // Rewind by n characters if the buffer hasn't been compacted yet\n        if (*n > nReadPos)\n            return false;\n        nReadPos -= *n;\n        return true;\n    }\n\n\n    //\n    // Stream subset\n    //\n    bool eof() const             { return size() == 0; }\n    CDataStream* rdbuf()         { return this; }\n    int in_avail() const         { return size(); }\n\n    void SetType(int n)          { nType = n; }\n    int GetType() const          { return nType; }\n    void SetVersion(int n)       { nVersion = n; }\n    int GetVersion() const       { return nVersion; }\n\n    void read(Span<value_type> dst)\n    {\n        if (dst.size() == 0) return;\n\n        // Read from the beginning of the buffer\n        unsigned int nReadPosNext = nReadPos + dst.size();\n        if (nReadPosNext > vch.size()) {\n            throw std::ios_base::failure(\"CDataStream::read(): end of data\");\n        }\n        memcpy(dst.data(), &vch[nReadPos], dst.size());\n        if (nReadPosNext == vch.size())\n        {\n            nReadPos = 0;\n            vch.clear();\n            return;\n        }\n        nReadPos = nReadPosNext;\n    }\n\n    void read(char* pch, size_t nSize)\n    {\n        if (nSize == 0) return;\n\n        // Read from the beginning of the buffer\n        unsigned int nReadPosNext = nReadPos + nSize;\n        if (nReadPosNext > vch.size())\n        {\n            throw std::ios_base::failure(\"CDataStream::read(): end of data\");\n        }\n        memcpy(pch, &vch[nReadPos], nSize);\n        if (nReadPosNext == vch.size())\n        {\n            nReadPos = 0;\n            vch.clear();\n            return;\n        }\n        nReadPos = nReadPosNext;\n    }\n\n    void peek(char* pch, size_t nSize)\n    {\n        if (nSize == 0) return;\n\n        // Read from the beginning of the buffer\n        unsigned int nReadPosNext = nReadPos + nSize;\n        if (nReadPosNext > vch.size())\n        {\n            throw std::ios_base::failure(\"CDataStream::read(): end of data\");\n        }\n        memcpy(pch, &vch[nReadPos], nSize);\n    }\n\n    void ignore(int nSize)\n    {\n        // Ignore from the beginning of the buffer\n        if (nSize < 0) {\n            throw std::ios_base::failure(\"CDataStream::ignore(): nSize negative\");\n        }\n        unsigned int nReadPosNext = nReadPos + nSize;\n        if (nReadPosNext >= vch.size())\n        {\n            if (nReadPosNext > vch.size())\n                throw std::ios_base::failure(\"CDataStream::ignore(): end of data\");\n            nReadPos = 0;\n            vch.clear();\n            return;\n        }\n        nReadPos = nReadPosNext;\n    }\n\n    void write(Span<const value_type> src)\n    {\n        // Write to the end of the buffer\n        vch.insert(vch.end(), src.begin(), src.end());\n    }\n\n    void write(const char* pch, size_t nSize)\n    {\n        // Write to the end of the buffer\n        auto data = AsBytes(Span(pch, pch+nSize));\n        vch.insert(vch.end(), data.begin(), data.end());\n    }\n\n    template<typename Stream>\n    void Serialize(Stream& s) const\n    {\n        // Special case: stream << stream concatenates like stream += stream\n        if (!vch.empty())\n            s.write(MakeByteSpan(vch));\n    }\n\n    template<typename T>\n    CDataStream& operator<<(const T& obj)\n    {\n        // Serialize to this stream\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n\n    template<typename T>\n    CDataStream& operator>>(T&& obj)\n    {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n\n    void GetAndClear(CSerializeData &d) {\n        d.insert(d.end(), begin(), end());\n        clear();\n    }\n\n    /**\n     * XOR the contents of this stream with a certain key.\n     *\n     * @param[in] key    The key used to XOR the data in this stream.\n     */\n    void Xor(const std::vector<unsigned char>& key)\n    {\n        if (key.size() == 0) {\n            return;\n        }\n\n        for (size_type i = 0, j = 0; i != size(); i++) {\n            vch[i] ^= std::byte{key[j++]};\n\n            // This potentially acts on very many bytes of data, so it's\n            // important that we calculate `j`, i.e. the `key` index in this\n            // way instead of doing a %, which would effectively be a division\n            // for each byte Xor'd -- much slower than need be.\n            if (j == key.size())\n                j = 0;\n        }\n    }\n};\n\ntemplate <typename IStream>\nclass BitStreamReader\n{\nprivate:\n    IStream& m_istream;\n\n    /// Buffered byte read in from the input stream. A new byte is read into the\n    /// buffer when m_offset reaches 8.\n    uint8_t m_buffer{0};\n\n    /// Number of high order bits in m_buffer already returned by previous\n    /// Read() calls. The next bit to be returned is at this offset from the\n    /// most significant bit position.\n    int m_offset{8};\n\npublic:\n    explicit BitStreamReader(IStream& istream) : m_istream(istream) {}\n\n    /** Read the specified number of bits from the stream. The data is returned\n     * in the nbits least significant bits of a 64-bit uint.\n     */\n    uint64_t Read(int nbits) {\n        if (nbits < 0 || nbits > 64) {\n            throw std::out_of_range(\"nbits must be between 0 and 64\");\n        }\n\n        uint64_t data = 0;\n        while (nbits > 0) {\n            if (m_offset == 8) {\n                m_istream >> m_buffer;\n                m_offset = 0;\n            }\n\n            int bits = std::min(8 - m_offset, nbits);\n            data <<= bits;\n            data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);\n            m_offset += bits;\n            nbits -= bits;\n        }\n        return data;\n    }\n};\n\ntemplate <typename OStream>\nclass BitStreamWriter\n{\nprivate:\n    OStream& m_ostream;\n\n    /// Buffered byte waiting to be written to the output stream. The byte is\n    /// written buffer when m_offset reaches 8 or Flush() is called.\n    uint8_t m_buffer{0};\n\n    /// Number of high order bits in m_buffer already written by previous\n    /// Write() calls and not yet flushed to the stream. The next bit to be\n    /// written to is at this offset from the most significant bit position.\n    int m_offset{0};\n\npublic:\n    explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}\n\n    ~BitStreamWriter()\n    {\n        Flush();\n    }\n\n    /** Write the nbits least significant bits of a 64-bit int to the output\n     * stream. Data is buffered until it completes an octet.\n     */\n    void Write(uint64_t data, int nbits) {\n        if (nbits < 0 || nbits > 64) {\n            throw std::out_of_range(\"nbits must be between 0 and 64\");\n        }\n\n        while (nbits > 0) {\n            int bits = std::min(8 - m_offset, nbits);\n            m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);\n            m_offset += bits;\n            nbits -= bits;\n\n            if (m_offset == 8) {\n                Flush();\n            }\n        }\n    }\n\n    /** Flush any unwritten bits to the output stream, padding with 0's to the\n     * next byte boundary.\n     */\n    void Flush() {\n        if (m_offset == 0) {\n            return;\n        }\n\n        m_ostream << m_buffer;\n        m_buffer = 0;\n        m_offset = 0;\n    }\n};\n\n\n\n/** Non-refcounted RAII wrapper for FILE*\n *\n * Will automatically close the file when it goes out of scope if not null.\n * If you're returning the file pointer, return file.release().\n * If you need to close the file early, use file.fclose() instead of fclose(file).\n */\nclass CAutoFile\n{\nprivate:\n    const int nType;\n    const int nVersion;\n\n    FILE* file;\n\npublic:\n    CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)\n    {\n        file = filenew;\n    }\n\n    ~CAutoFile()\n    {\n        fclose();\n    }\n\n    // Disallow copies\n    CAutoFile(const CAutoFile&) = delete;\n    CAutoFile& operator=(const CAutoFile&) = delete;\n\n    void fclose()\n    {\n        if (file) {\n            ::fclose(file);\n            file = nullptr;\n        }\n    }\n\n    /** Get wrapped FILE* with transfer of ownership.\n     * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller\n     * of this function to clean up the returned FILE*.\n     */\n    FILE* release()             { FILE* ret = file; file = nullptr; return ret; }\n\n    /** Get wrapped FILE* without transfer of ownership.\n     * @note Ownership of the FILE* will remain with this class. Use this only if the scope of the\n     * CAutoFile outlives use of the passed pointer.\n     */\n    FILE* Get() const           { return file; }\n\n    /** Return true if the wrapped FILE* is nullptr, false otherwise.\n     */\n    bool IsNull() const         { return (file == nullptr); }\n\n    //\n    // Stream subset\n    //\n    int GetType() const          { return nType; }\n    int GetVersion() const       { return nVersion; }\n\n    void read(Span<std::byte> dst)\n    {\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::read: file handle is nullptr\");\n        if (fread(dst.data(), 1, dst.size(), file) != dst.size()) {\n            throw std::ios_base::failure(feof(file) ? \"CAutoFile::read: end of file\" : \"CAutoFile::read: fread failed\");\n        }\n    }\n\n    void peek(char* pch, size_t nSize)\n    {\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::read: file handle is nullptr\");\n        if (fread(pch, 1, nSize, file) != nSize)\n            throw std::ios_base::failure(feof(file) ? \"CAutoFile::read: end of file\" : \"CAutoFile::read: fread failed\");\n        fseek(file, -nSize, SEEK_CUR);\n    }\n    \n    void seekg(uint64_t nOffset_)\n    {\n        fseek(file, nOffset_, SEEK_SET);\n    }\n    \n    uint64_t tellg()\n    {\n        if (!file)\n            return -1;\n        return ftell(file);\n    }\n    \n    bool peek()\n    {\n        char p;\n        if (!file)\n            return false;\n        if (fread(&p, 1, 1, file) != 1)\n            return false;\n        fseek(file, -1, SEEK_CUR);\n        return true;\n    }\n\n    void ignore(size_t nSize)\n    {\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::ignore: file handle is nullptr\");\n        unsigned char data[4096];\n        while (nSize > 0) {\n            size_t nNow = std::min<size_t>(nSize, sizeof(data));\n            if (fread(data, 1, nNow, file) != nNow)\n                throw std::ios_base::failure(feof(file) ? \"CAutoFile::ignore: end of file\" : \"CAutoFile::read: fread failed\");\n            nSize -= nNow;\n        }\n    }\n\n    void write(Span<const std::byte> src)\n    {\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::write: file handle is nullptr\");\n        if (fwrite(src.data(), 1, src.size(), file) != src.size()) {\n            throw std::ios_base::failure(\"CAutoFile::write: write failed\");\n        }\n    }\n\n    template<typename T>\n    CAutoFile& operator<<(const T& obj)\n    {\n        // Serialize to this stream\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::operator<<: file handle is nullptr\");\n        ::Serialize(*this, obj);\n        return (*this);\n    }\n\n    template<typename T>\n    CAutoFile& operator>>(T&& obj)\n    {\n        // Unserialize from this stream\n        if (!file)\n            throw std::ios_base::failure(\"CAutoFile::operator>>: file handle is nullptr\");\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n};\n\n/** Non-owner version of CAutoFile. Identical to CAutoFile except that the caller\n    remains owner, ie. is responsible for closing the file.\n*/\nclass CFile : public CAutoFile\n{\npublic:\n    CFile(FILE* filenew, int nTypeIn, int nVersionIn) :\n        CAutoFile(filenew, nTypeIn, nVersionIn) {}\n\n    ~CFile()\n    {\n        release();\n    }\n};\n\n/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to\n *  deserialize from. It guarantees the ability to rewind a given number of bytes.\n *\n *  Will automatically close the file when it goes out of scope if not null.\n *  If you need to close the file early, use file.fclose() instead of fclose(file).\n */\nclass CBufferedFile\n{\nprivate:\n    const int nType;\n    const int nVersion;\n\n    FILE *src;            //!< source file\n    uint64_t nSrcPos;     //!< how many bytes have been read from source\n    uint64_t nReadPos;    //!< how many bytes have been read from this\n    uint64_t nReadLimit;  //!< up to which position we're allowed to read\n    uint64_t nRewind;     //!< how many bytes we guarantee to rewind\n    std::vector<std::byte> vchBuf; //!< the buffer\n\nprotected:\n    //! read data from the source to fill the buffer\n    bool Fill() {\n        unsigned int pos = nSrcPos % vchBuf.size();\n        unsigned int readNow = vchBuf.size() - pos;\n        unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;\n        if (nAvail < readNow)\n            readNow = nAvail;\n        if (readNow == 0)\n            return false;\n        size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);\n        if (nBytes == 0) {\n            throw std::ios_base::failure(feof(src) ? \"CBufferedFile::Fill: end of file\" : \"CBufferedFile::Fill: fread failed\");\n        }\n        nSrcPos += nBytes;\n        return true;\n    }\n\npublic:\n    CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn)\n        : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0})\n    {\n        if (nRewindIn >= nBufSize)\n            throw std::ios_base::failure(\"Rewind limit must be less than buffer size\");\n        src = fileIn;\n    }\n\n    ~CBufferedFile()\n    {\n        fclose();\n    }\n\n    // Disallow copies\n    CBufferedFile(const CBufferedFile&) = delete;\n    CBufferedFile& operator=(const CBufferedFile&) = delete;\n\n    int GetVersion() const { return nVersion; }\n    int GetType() const { return nType; }\n\n    void fclose()\n    {\n        if (src) {\n            ::fclose(src);\n            src = nullptr;\n        }\n    }\n\n    //! check whether we're at the end of the source file\n    bool eof() const {\n        return nReadPos == nSrcPos && feof(src);\n    }\n\n    //! read a number of bytes\n    void read(Span<std::byte> dst)\n    {\n        if (dst.size() + nReadPos > nReadLimit) {\n            throw std::ios_base::failure(\"Read attempted past buffer limit\");\n        }\n        while (dst.size() > 0) {\n            if (nReadPos == nSrcPos)\n                Fill();\n            unsigned int pos = nReadPos % vchBuf.size();\n            size_t nNow = dst.size();\n            if (nNow + pos > vchBuf.size())\n                nNow = vchBuf.size() - pos;\n            if (nNow + nReadPos > nSrcPos)\n                nNow = nSrcPos - nReadPos;\n            memcpy(dst.data(), &vchBuf[pos], nNow);\n            nReadPos += nNow;\n            dst = dst.subspan(nNow);\n        }\n    }\n\n    void peek(char *pch, size_t nSize) {\n        if (nSize > nRewind)\n            nRewind = nSize;\n        if (nSize + nReadPos > nReadLimit)\n            throw std::ios_base::failure(\"Read attempted past buffer limit\");\n        if (nSize + nRewind > vchBuf.size())\n            throw std::ios_base::failure(\"Read larger than buffer size\");\n        int nRewindPos = nReadPos;\n        while (nSize > 0) {\n            if (nReadPos == nSrcPos)\n                Fill();\n            unsigned int pos = nReadPos % vchBuf.size();\n            size_t nNow = nSize;\n            if (nNow + pos > vchBuf.size())\n                nNow = vchBuf.size() - pos;\n            if (nNow + nReadPos > nSrcPos)\n                nNow = nSrcPos - nReadPos;\n            memcpy(pch, &vchBuf[pos], nNow);\n            nReadPos += nNow;\n            pch += nNow;\n            nSize -= nNow;\n        }\n        SetPos(nRewindPos);\n    }\n\n    //! return the current reading position\n    uint64_t GetPos() const {\n        return nReadPos;\n    }\n\n    //! rewind to a given reading position\n    bool SetPos(uint64_t nPos) {\n        size_t bufsize = vchBuf.size();\n        if (nPos + bufsize < nSrcPos) {\n            // rewinding too far, rewind as far as possible\n            nReadPos = nSrcPos - bufsize;\n            return false;\n        }\n        if (nPos > nSrcPos) {\n            // can't go this far forward, go as far as possible\n            nReadPos = nSrcPos;\n            return false;\n        }\n        nReadPos = nPos;\n        return true;\n    }\n\n    //! prevent reading beyond a certain position\n    //! no argument removes the limit\n    bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {\n        if (nPos < nReadPos)\n            return false;\n        nReadLimit = nPos;\n        return true;\n    }\n\n    template<typename T>\n    CBufferedFile& operator>>(T&& obj) {\n        // Unserialize from this stream\n        ::Unserialize(*this, obj);\n        return (*this);\n    }\n\n    //! search for a given byte in the stream, and remain positioned on it\n    void FindByte(uint8_t ch)\n    {\n        while (true) {\n            if (nReadPos == nSrcPos)\n                Fill();\n            if (vchBuf[nReadPos % vchBuf.size()] == std::byte{ch}) {\n                break;\n            }\n            nReadPos++;\n        }\n    }\n};\n\n#endif // CORE_STREAMS_H\n"
  },
  {
    "path": "src/support/allocators/secure.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_SUPPORT_ALLOCATORS_SECURE_H\n#define CORE_SUPPORT_ALLOCATORS_SECURE_H\n\n#include <support/lockedpool.h>\n#include <support/cleanse.h>\n\n#include <memory>\n#include <string>\n\n//\n// Allocator that locks its contents from being paged\n// out of memory and clears its contents before deletion.\n//\ntemplate <typename T>\nstruct secure_allocator : public std::allocator<T> {\n    using base = std::allocator<T>;\n    using traits = std::allocator_traits<base>;\n    using size_type = typename traits::size_type;\n    using difference_type = typename traits::difference_type;\n    using pointer = typename traits::pointer;\n    using const_pointer = typename traits::const_pointer;\n    using value_type = typename traits::value_type;\n    secure_allocator() noexcept {}\n    secure_allocator(const secure_allocator& a) noexcept : base(a) {}\n    template <typename U>\n    secure_allocator(const secure_allocator<U>& a) noexcept : base(a)\n    {\n    }\n    ~secure_allocator() noexcept {}\n    template <typename _Other>\n    struct rebind {\n        typedef secure_allocator<_Other> other;\n    };\n\n    T* allocate(std::size_t n, const void* hint = 0)\n    {\n        T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));\n        if (!allocation) {\n            throw std::bad_alloc();\n        }\n        return allocation;\n    }\n\n    void deallocate(T* p, std::size_t n)\n    {\n        if (p != nullptr) {\n            memory_cleanse(p, sizeof(T) * n);\n        }\n        LockedPoolManager::Instance().free(p);\n    }\n};\n\n// This is exactly like std::string, but with a custom allocator.\ntypedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;\n\ntypedef std::vector<char, secure_allocator<char> > SecureCharVector;\ntypedef std::vector<unsigned char, secure_allocator<unsigned char> > SecureUnsignedCharVector;\n\n#endif // CORE_SUPPORT_ALLOCATORS_SECURE_H\n"
  },
  {
    "path": "src/support/allocators/zeroafterfree.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H\n#define CORE_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H\n\n#include <support/cleanse.h>\n\n#include <memory>\n#include <vector>\n\ntemplate <typename T>\nstruct zero_after_free_allocator : public std::allocator<T> {\n    using base = std::allocator<T>;\n    using traits = std::allocator_traits<base>;\n    using size_type = typename traits::size_type;\n    using difference_type = typename traits::difference_type;\n    using pointer = typename traits::pointer;\n    using const_pointer = typename traits::const_pointer;\n    using value_type = typename traits::value_type;\n    zero_after_free_allocator() noexcept {}\n    zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}\n    template <typename U>\n    zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)\n    {\n    }\n    ~zero_after_free_allocator() noexcept {}\n    template <typename _Other>\n    struct rebind {\n        typedef zero_after_free_allocator<_Other> other;\n    };\n\n    void deallocate(T* p, std::size_t n)\n    {\n        if (p != nullptr)\n            memory_cleanse(p, sizeof(T) * n);\n        std::allocator<T>::deallocate(p, n);\n    }\n};\n\n/** Byte-vector that clears its contents before deletion. */\nusing CSerializeData = std::vector<std::byte, zero_after_free_allocator<std::byte>>;\n\n#endif // CORE_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H\n"
  },
  {
    "path": "src/support/cleanse.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"cleanse.h\"\n\n#include <cstring>\n\n#if defined(_MSC_VER)\n#include <Windows.h> // For SecureZeroMemory.\n#endif\n\nvoid memory_cleanse(void *ptr, size_t len)\n{\n#if defined(_MSC_VER)\n    /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */\n    SecureZeroMemory(ptr, len);\n#else\n    std::memset(ptr, 0, len);\n\n    /* Memory barrier that scares the compiler away from optimizing out the memset.\n     *\n     * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f\n     * in BoringSSL (ISC License):\n     *    As best as we can tell, this is sufficient to break any optimisations that\n     *    might try to eliminate \"superfluous\" memsets.\n     * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it\n     * is pretty efficient because the compiler can still implement the memset() efficiently,\n     * just not remove it entirely. See \"Dead Store Elimination (Still) Considered Harmful\" by\n     * Yang et al. (USENIX Security 2017) for more background.\n     */\n    __asm__ __volatile__(\"\" : : \"r\"(ptr) : \"memory\");\n#endif\n}\n"
  },
  {
    "path": "src/support/cleanse.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SUPPORT_CLEANSE_H\n#define SUPPORT_CLEANSE_H\n\n#include <stdlib.h>\n\n/** Secure overwrite a buffer (possibly containing secret data) with zero-bytes. The write\n * operation will not be optimized out by the compiler. */\nvoid memory_cleanse(void *ptr, size_t len);\n\n#endif\n"
  },
  {
    "path": "src/support/events.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SUPPORT_EVENTS_H\n#define SUPPORT_EVENTS_H\n\n#include <ios>\n#include <memory>\n\n#include <event2/event.h>\n#include <event2/http.h>\n\n#define MAKE_RAII(type) \\\n/* deleter */\\\nstruct type##_deleter {\\\n    void operator()(struct type* ob) {\\\n        type##_free(ob);\\\n    }\\\n};\\\n/* unique ptr typedef */\\\ntypedef std::unique_ptr<struct type, type##_deleter> raii_##type\n\nMAKE_RAII(event_base);\nMAKE_RAII(event);\nMAKE_RAII(evhttp);\nMAKE_RAII(evhttp_request);\nMAKE_RAII(evhttp_connection);\n\nraii_event_base obtain_event_base() {\n    auto result = raii_event_base(event_base_new());\n    if (!result.get())\n        throw std::runtime_error(\"cannot create event_base\");\n    return result;\n}\n\nraii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {\n    return raii_event(event_new(base, s, events, cb, arg));\n}\n\nraii_evhttp obtain_evhttp(struct event_base* base) {\n    return raii_evhttp(evhttp_new(base));\n}\n\nraii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {\n    return raii_evhttp_request(evhttp_request_new(cb, arg));\n}\n\nraii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {\n    auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port));\n    if (!result.get())\n        throw std::runtime_error(\"create connection failed\");\n    return result;\n}\n\n#endif\n"
  },
  {
    "path": "src/support/lockedpool.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"support/lockedpool.h\"\n#include \"support/cleanse.h\"\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#ifdef WIN32\n#ifdef _WIN32_WINNT\n#undef _WIN32_WINNT\n#endif\n#define _WIN32_WINNT 0x0501\n#define WIN32_LEAN_AND_MEAN 1\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#include <windows.h>\n#else\n#include <sys/mman.h> // for mmap\n#include <sys/resource.h> // for getrlimit\n#include <limits.h> // for PAGESIZE\n#include <unistd.h> // for sysconf\n#endif\n\n#include <algorithm>\n\nLockedPoolManager* LockedPoolManager::_instance = NULL;\nstd::once_flag LockedPoolManager::init_flag;\n\n/*******************************************************************************/\n// Utilities\n//\n/** Align up to power of 2 */\nstatic inline size_t align_up(size_t x, size_t align)\n{\n    return (x + align - 1) & ~(align - 1);\n}\n\n/*******************************************************************************/\n// Implementation: Arena\n\nArena::Arena(void *base_in, size_t size_in, size_t alignment_in):\n    base(static_cast<char*>(base_in)), end(static_cast<char*>(base_in) + size_in), alignment(alignment_in)\n{\n    // Start with one free chunk that covers the entire arena\n    chunks_free.emplace(base, size_in);\n}\n\nArena::~Arena()\n{\n}\n\nvoid* Arena::alloc(size_t size)\n{\n    // Round to next multiple of alignment\n    size = align_up(size, alignment);\n\n    // Don't handle zero-sized chunks\n    if (size == 0)\n        return nullptr;\n\n    // Pick a large enough free-chunk\n    auto it = std::find_if(chunks_free.begin(), chunks_free.end(),\n        [=](const std::map<char*, size_t>::value_type& chunk){ return chunk.second >= size; });\n    if (it == chunks_free.end())\n        return nullptr;\n\n    // Create the used-chunk, taking its space from the end of the free-chunk\n    auto alloced = chunks_used.emplace(it->first + it->second - size, size).first;\n    if (!(it->second -= size))\n        chunks_free.erase(it);\n    return reinterpret_cast<void*>(alloced->first);\n}\n\n/* extend the Iterator if other begins at its end */\ntemplate <class Iterator, class Pair> bool extend(Iterator it, const Pair& other) {\n    if (it->first + it->second == other.first) {\n        it->second += other.second;\n        return true;\n    }\n    return false;\n}\n\nvoid Arena::free(void *ptr)\n{\n    // Freeing the NULL pointer is OK.\n    if (ptr == nullptr) {\n        return;\n    }\n\n    // Remove chunk from used map\n    auto i = chunks_used.find(static_cast<char*>(ptr));\n    if (i == chunks_used.end()) {\n        throw std::runtime_error(\"Arena: invalid or double free\");\n    }\n    auto freed = *i;\n    chunks_used.erase(i);\n\n    // Add space to free map, coalescing contiguous chunks\n    auto next = chunks_free.upper_bound(freed.first);\n    auto prev = (next == chunks_free.begin()) ? chunks_free.end() : std::prev(next);\n    if (prev == chunks_free.end() || !extend(prev, freed))\n        prev = chunks_free.emplace_hint(next, freed);\n    if (next != chunks_free.end() && extend(prev, *next))\n        chunks_free.erase(next);\n}\n\nArena::Stats Arena::stats() const\n{\n    Arena::Stats r{ 0, 0, 0, chunks_used.size(), chunks_free.size() };\n    for (const auto& chunk: chunks_used)\n        r.used += chunk.second;\n    for (const auto& chunk: chunks_free)\n        r.free += chunk.second;\n    r.total = r.used + r.free;\n    return r;\n}\n\n#ifdef ARENA_DEBUG\nvoid printchunk(char* base, size_t sz, bool used) {\n    std::cout <<\n        \"0x\" << std::hex << std::setw(16) << std::setfill('0') << base <<\n        \" 0x\" << std::hex << std::setw(16) << std::setfill('0') << sz <<\n        \" 0x\" << used << std::endl;\n}\nvoid Arena::walk() const\n{\n    for (const auto& chunk: chunks_used)\n        printchunk(chunk.first, chunk.second, true);\n    std::cout << std::endl;\n    for (const auto& chunk: chunks_free)\n        printchunk(chunk.first, chunk.second, false);\n    std::cout << std::endl;\n}\n#endif\n\n/*******************************************************************************/\n// Implementation: Win32LockedPageAllocator\n\n#ifdef WIN32\n/** LockedPageAllocator specialized for Windows.\n */\nclass Win32LockedPageAllocator: public LockedPageAllocator\n{\npublic:\n    Win32LockedPageAllocator();\n    void* AllocateLocked(size_t len, bool *lockingSuccess);\n    void FreeLocked(void* addr, size_t len);\n    size_t GetLimit();\nprivate:\n    size_t page_size;\n};\n\nWin32LockedPageAllocator::Win32LockedPageAllocator()\n{\n    // Determine system page size in bytes\n    SYSTEM_INFO sSysInfo;\n    GetSystemInfo(&sSysInfo);\n    page_size = sSysInfo.dwPageSize;\n}\nvoid *Win32LockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)\n{\n    len = align_up(len, page_size);\n    void *addr = VirtualAlloc(nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\n    if (addr) {\n        // VirtualLock is used to attempt to keep keying material out of swap. Note\n        // that it does not provide this as a guarantee, but, in practice, memory\n        // that has been VirtualLock'd almost never gets written to the pagefile\n        // except in rare circumstances where memory is extremely low.\n        *lockingSuccess = VirtualLock(const_cast<void*>(addr), len) != 0;\n    }\n    return addr;\n}\nvoid Win32LockedPageAllocator::FreeLocked(void* addr, size_t len)\n{\n    len = align_up(len, page_size);\n    memory_cleanse(addr, len);\n    VirtualUnlock(const_cast<void*>(addr), len);\n}\n\nsize_t Win32LockedPageAllocator::GetLimit()\n{\n    // TODO is there a limit on windows, how to get it?\n    return std::numeric_limits<size_t>::max();\n}\n#endif\n\n/*******************************************************************************/\n// Implementation: PosixLockedPageAllocator\n\n#ifndef WIN32\n/** LockedPageAllocator specialized for OSes that don't try to be\n * special snowflakes.\n */\nclass PosixLockedPageAllocator: public LockedPageAllocator\n{\npublic:\n    PosixLockedPageAllocator();\n    void* AllocateLocked(size_t len, bool *lockingSuccess);\n    void FreeLocked(void* addr, size_t len);\n    size_t GetLimit();\nprivate:\n    size_t page_size;\n};\n\nPosixLockedPageAllocator::PosixLockedPageAllocator()\n{\n    // Determine system page size in bytes\n#if defined(PAGESIZE) // defined in limits.h\n    page_size = PAGESIZE;\n#else                   // assume some POSIX OS\n    page_size = sysconf(_SC_PAGESIZE);\n#endif\n}\n\n// Some systems (at least OS X) do not define MAP_ANONYMOUS yet and define\n// MAP_ANON which is deprecated\n#ifndef MAP_ANONYMOUS\n#define MAP_ANONYMOUS MAP_ANON\n#endif\n\nvoid *PosixLockedPageAllocator::AllocateLocked(size_t len, bool *lockingSuccess)\n{\n    void *addr;\n    len = align_up(len, page_size);\n    addr = mmap(nullptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);\n    if (addr) {\n        *lockingSuccess = mlock(addr, len) == 0;\n    }\n    return addr;\n}\nvoid PosixLockedPageAllocator::FreeLocked(void* addr, size_t len)\n{\n    len = align_up(len, page_size);\n    memory_cleanse(addr, len);\n    munlock(addr, len);\n    munmap(addr, len);\n}\nsize_t PosixLockedPageAllocator::GetLimit()\n{\n#ifdef RLIMIT_MEMLOCK\n    struct rlimit rlim;\n    if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) {\n        if (rlim.rlim_cur != RLIM_INFINITY) {\n            return rlim.rlim_cur;\n        }\n    }\n#endif\n    return std::numeric_limits<size_t>::max();\n}\n#endif\n\n/*******************************************************************************/\n// Implementation: LockedPool\n\nLockedPool::LockedPool(std::unique_ptr<LockedPageAllocator> allocator_in, LockingFailed_Callback lf_cb_in):\n    allocator(std::move(allocator_in)), lf_cb(lf_cb_in), cumulative_bytes_locked(0)\n{\n}\n\nLockedPool::~LockedPool()\n{\n}\nvoid* LockedPool::alloc(size_t size)\n{\n    std::lock_guard<std::mutex> lock(mutex);\n\n    // Don't handle impossible sizes\n    if (size == 0 || size > ARENA_SIZE)\n        return nullptr;\n\n    // Try allocating from each current arena\n    for (auto &arena: arenas) {\n        void *addr = arena.alloc(size);\n        if (addr) {\n            return addr;\n        }\n    }\n    // If that fails, create a new one\n    if (new_arena(ARENA_SIZE, ARENA_ALIGN)) {\n        return arenas.back().alloc(size);\n    }\n    return nullptr;\n}\n\nvoid LockedPool::free(void *ptr)\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    // TODO we can do better than this linear search by keeping a map of arena\n    // extents to arena, and looking up the address.\n    for (auto &arena: arenas) {\n        if (arena.addressInArena(ptr)) {\n            arena.free(ptr);\n            return;\n        }\n    }\n    throw std::runtime_error(\"LockedPool: invalid address not pointing to any arena\");\n}\n\nLockedPool::Stats LockedPool::stats() const\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    LockedPool::Stats r{0, 0, 0, cumulative_bytes_locked, 0, 0};\n    for (const auto &arena: arenas) {\n        Arena::Stats i = arena.stats();\n        r.used += i.used;\n        r.free += i.free;\n        r.total += i.total;\n        r.chunks_used += i.chunks_used;\n        r.chunks_free += i.chunks_free;\n    }\n    return r;\n}\n\nbool LockedPool::new_arena(size_t size, size_t align)\n{\n    bool locked;\n    // If this is the first arena, handle this specially: Cap the upper size\n    // by the process limit. This makes sure that the first arena will at least\n    // be locked. An exception to this is if the process limit is 0:\n    // in this case no memory can be locked at all so we'll skip past this logic.\n    if (arenas.empty()) {\n        size_t limit = allocator->GetLimit();\n        if (limit > 0) {\n            size = std::min(size, limit);\n        }\n    }\n    void *addr = allocator->AllocateLocked(size, &locked);\n    if (!addr) {\n        return false;\n    }\n    if (locked) {\n        cumulative_bytes_locked += size;\n    } else if (lf_cb) { // Call the locking-failed callback if locking failed\n        if (!lf_cb()) { // If the callback returns false, free the memory and fail, otherwise consider the user warned and proceed.\n            allocator->FreeLocked(addr, size);\n            return false;\n        }\n    }\n    arenas.emplace_back(allocator.get(), addr, size, align);\n    return true;\n}\n\nLockedPool::LockedPageArena::LockedPageArena(LockedPageAllocator *allocator_in, void *base_in, size_t size_in, size_t align_in):\n    Arena(base_in, size_in, align_in), base(base_in), size(size_in), allocator(allocator_in)\n{\n}\nLockedPool::LockedPageArena::~LockedPageArena()\n{\n    allocator->FreeLocked(base, size);\n}\n\n/*******************************************************************************/\n// Implementation: LockedPoolManager\n//\nLockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):\n    LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)\n{\n}\n\nbool LockedPoolManager::LockingFailed()\n{\n    // TODO: log something but how? without including util.h\n    return true;\n}\n\nvoid LockedPoolManager::CreateInstance()\n{\n    // Using a local static instance guarantees that the object is initialized\n    // when it's first needed and also deinitialized after all objects that use\n    // it are done with it.  I can think of one unlikely scenario where we may\n    // have a static deinitialization order/problem, but the check in\n    // LockedPoolManagerBase's destructor helps us detect if that ever happens.\n#ifdef WIN32\n    std::unique_ptr<LockedPageAllocator> allocator(new Win32LockedPageAllocator());\n#else\n    std::unique_ptr<LockedPageAllocator> allocator(new PosixLockedPageAllocator());\n#endif\n    static LockedPoolManager instance(std::move(allocator));\n    LockedPoolManager::_instance = &instance;\n}\n"
  },
  {
    "path": "src/support/lockedpool.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef SUPPORT_LOCKEDPOOL_H\n#define SUPPORT_LOCKEDPOOL_H\n\n#include <stdint.h>\n#include <list>\n#include <map>\n#include <mutex>\n#include <memory>\n\n/**\n * OS-dependent allocation and deallocation of locked/pinned memory pages.\n * Abstract base class.\n */\nclass LockedPageAllocator\n{\npublic:\n    virtual ~LockedPageAllocator() {}\n    /** Allocate and lock memory pages.\n     * If len is not a multiple of the system page size, it is rounded up.\n     * Returns 0 in case of allocation failure.\n     *\n     * If locking the memory pages could not be accomplished it will still\n     * return the memory, however the lockingSuccess flag will be false.\n     * lockingSuccess is undefined if the allocation fails.\n     */\n    virtual void* AllocateLocked(size_t len, bool *lockingSuccess) = 0;\n\n    /** Unlock and free memory pages.\n     * Clear the memory before unlocking.\n     */\n    virtual void FreeLocked(void* addr, size_t len) = 0;\n\n    /** Get the total limit on the amount of memory that may be locked by this\n     * process, in bytes. Return size_t max if there is no limit or the limit\n     * is unknown. Return 0 if no memory can be locked at all.\n     */\n    virtual size_t GetLimit() = 0;\n};\n\n/* An arena manages a contiguous region of memory by dividing it into\n * chunks.\n */\nclass Arena\n{\npublic:\n    Arena(void *base, size_t size, size_t alignment);\n    virtual ~Arena();\n\n    /** Memory statistics. */\n    struct Stats\n    {\n        size_t used;\n        size_t free;\n        size_t total;\n        size_t chunks_used;\n        size_t chunks_free;\n    };\n\n    /** Allocate size bytes from this arena.\n     * Returns pointer on success, or 0 if memory is full or\n     * the application tried to allocate 0 bytes.\n     */\n    void* alloc(size_t size);\n\n    /** Free a previously allocated chunk of memory.\n     * Freeing the zero pointer has no effect.\n     * Raises std::runtime_error in case of error.\n     */\n    void free(void *ptr);\n\n    /** Get arena usage statistics */\n    Stats stats() const;\n\n#ifdef ARENA_DEBUG\n    void walk() const;\n#endif\n\n    /** Return whether a pointer points inside this arena.\n     * This returns base <= ptr < (base+size) so only use it for (inclusive)\n     * chunk starting addresses.\n     */\n    bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }\nprivate:\n    Arena(const Arena& other) = delete; // non construction-copyable\n    Arena& operator=(const Arena&) = delete; // non copyable\n\n    /** Map of chunk address to chunk information. This class makes use of the\n     * sorted order to merge previous and next chunks during deallocation.\n     */\n    std::map<char*, size_t> chunks_free;\n    std::map<char*, size_t> chunks_used;\n    /** Base address of arena */\n    char* base;\n    /** End address of arena */\n    char* end;\n    /** Minimum chunk alignment */\n    size_t alignment;\n};\n\n/** Pool for locked memory chunks.\n *\n * To avoid sensitive key data from being swapped to disk, the memory in this pool\n * is locked/pinned.\n *\n * An arena manages a contiguous region of memory. The pool starts out with one arena\n * but can grow to multiple arenas if the need arises.\n *\n * Unlike a normal C heap, the administrative structures are separate from the managed\n * memory. This has been done as the sizes and bases of objects are not in themselves sensitive\n * information, as to conserve precious locked memory. In some operating systems\n * the amount of memory that can be locked is small.\n */\nclass LockedPool\n{\npublic:\n    /** Size of one arena of locked memory. This is a compromise.\n     * Do not set this too low, as managing many arenas will increase\n     * allocation and deallocation overhead. Setting it too high allocates\n     * more locked memory from the OS than strictly necessary.\n     */\n    static const size_t ARENA_SIZE = 256*1024;\n    /** Chunk alignment. Another compromise. Setting this too high will waste\n     * memory, setting it too low will facilitate fragmentation.\n     */\n    static const size_t ARENA_ALIGN = 16;\n\n    /** Callback when allocation succeeds but locking fails.\n     */\n    typedef bool (*LockingFailed_Callback)();\n\n    /** Memory statistics. */\n    struct Stats\n    {\n        size_t used;\n        size_t free;\n        size_t total;\n        size_t locked;\n        size_t chunks_used;\n        size_t chunks_free;\n    };\n\n    /** Create a new LockedPool. This takes ownership of the MemoryPageLocker,\n     * you can only instantiate this with LockedPool(std::move(...)).\n     *\n     * The second argument is an optional callback when locking a newly allocated arena failed.\n     * If this callback is provided and returns false, the allocation fails (hard fail), if\n     * it returns true the allocation proceeds, but it could warn.\n     */\n    LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = 0);\n    ~LockedPool();\n\n    /** Allocate size bytes from this arena.\n     * Returns pointer on success, or 0 if memory is full or\n     * the application tried to allocate 0 bytes.\n     */\n    void* alloc(size_t size);\n\n    /** Free a previously allocated chunk of memory.\n     * Freeing the zero pointer has no effect.\n     * Raises std::runtime_error in case of error.\n     */\n    void free(void *ptr);\n\n    /** Get pool usage statistics */\n    Stats stats() const;\nprivate:\n    LockedPool(const LockedPool& other) = delete; // non construction-copyable\n    LockedPool& operator=(const LockedPool&) = delete; // non copyable\n\n    std::unique_ptr<LockedPageAllocator> allocator;\n\n    /** Create an arena from locked pages */\n    class LockedPageArena: public Arena\n    {\n    public:\n        LockedPageArena(LockedPageAllocator *alloc_in, void *base_in, size_t size, size_t align);\n        ~LockedPageArena();\n    private:\n        void *base;\n        size_t size;\n        LockedPageAllocator *allocator;\n    };\n\n    bool new_arena(size_t size, size_t align);\n\n    std::list<LockedPageArena> arenas;\n    LockingFailed_Callback lf_cb;\n    size_t cumulative_bytes_locked;\n    /** Mutex protects access to this pool's data structures, including arenas.\n     */\n    mutable std::mutex mutex;\n};\n\n/**\n * Singleton class to keep track of locked (ie, non-swappable) memory, for use in\n * std::allocator templates.\n *\n * Some implementations of the STL allocate memory in some constructors (i.e., see\n * MSVC's vector<T> implementation where it allocates 1 byte of memory in the allocator.)\n * Due to the unpredictable order of static initializers, we have to make sure the\n * LockedPoolManager instance exists before any other STL-based objects that use\n * secure_allocator are created. So instead of having LockedPoolManager also be\n * static-initialized, it is created on demand.\n */\nclass LockedPoolManager : public LockedPool\n{\npublic:\n    /** Return the current instance, or create it once */\n    static LockedPoolManager& Instance()\n    {\n        std::call_once(LockedPoolManager::init_flag, LockedPoolManager::CreateInstance);\n        return *LockedPoolManager::_instance;\n    }\n\nprivate:\n    LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);\n\n    /** Create a new LockedPoolManager specialized to the OS */\n    static void CreateInstance();\n    /** Called when locking fails, warn the user here */\n    static bool LockingFailed();\n\n    static LockedPoolManager* _instance;\n    static std::once_flag init_flag;\n};\n\n#endif\n"
  },
  {
    "path": "src/sync.cpp",
    "content": "// Copyright (c) 2011-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif\n\n#include <sync.h>\n\n#include <tinyformat.h>\n//#include <util/strencodings.h>\n#include <util/threadnames.h>\n\n#include <map>\n#include <mutex>\n#include <set>\n#include <system_error>\n#include <thread>\n#include <type_traits>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n\n#ifdef DEBUG_LOCKORDER\n//\n// Early deadlock detection.\n// Problem being solved:\n//    Thread 1 locks A, then B, then C\n//    Thread 2 locks D, then C, then A\n//     --> may result in deadlock between the two threads, depending on when they run.\n// Solution implemented here:\n// Keep track of pairs of locks: (A before B), (A before C), etc.\n// Complain if any thread tries to lock in a different order.\n//\n\nstruct CLockLocation {\n    CLockLocation(\n        const char* pszName,\n        const char* pszFile,\n        int nLine,\n        bool fTryIn,\n        const std::string& thread_name)\n        : fTry(fTryIn),\n          mutexName(pszName),\n          sourceFile(pszFile),\n          m_thread_name(thread_name),\n          sourceLine(nLine) {}\n\n    std::string ToString() const\n    {\n        return strprintf(\n            \"'%s' in %s:%s%s (in thread '%s')\",\n            mutexName, sourceFile, sourceLine, (fTry ? \" (TRY)\" : \"\"), m_thread_name);\n    }\n\n    std::string Name() const\n    {\n        return mutexName;\n    }\n\nprivate:\n    bool fTry;\n    std::string mutexName;\n    std::string sourceFile;\n    const std::string& m_thread_name;\n    int sourceLine;\n};\n\nusing LockStackItem = std::pair<void*, CLockLocation>;\nusing LockStack = std::vector<LockStackItem>;\nusing LockStacks = std::unordered_map<std::thread::id, LockStack>;\n\nusing LockPair = std::pair<void*, void*>;\nusing LockOrders = std::map<LockPair, LockStack>;\nusing InvLockOrders = std::set<LockPair>;\n\nstruct LockData {\n    LockStacks m_lock_stacks;\n    LockOrders lockorders;\n    InvLockOrders invlockorders;\n    std::mutex dd_mutex;\n};\n\nLockData& GetLockData() {\n    // This approach guarantees that the object is not destroyed until after its last use.\n    // The operating system automatically reclaims all the memory in a program's heap when that program exits.\n    // Since the ~LockData() destructor is never called, the LockData class and all\n    // its subclasses must have implicitly-defined destructors.\n    static LockData& lock_data = *new LockData();\n    return lock_data;\n}\n\nstatic void potential_deadlock_detected(const LockPair& mismatch, const LockStack& s1, const LockStack& s2)\n{\n    LogPrintf(\"POTENTIAL DEADLOCK DETECTED\\n\");\n    LogPrintf(\"Previous lock order was:\\n\");\n    for (const LockStackItem& i : s1) {\n        std::string prefix{};\n        if (i.first == mismatch.first) {\n            prefix = \" (1)\";\n        }\n        if (i.first == mismatch.second) {\n            prefix = \" (2)\";\n        }\n        LogPrintf(\"%s %s\\n\", prefix, i.second.ToString());\n    }\n\n    std::string mutex_a, mutex_b;\n    LogPrintf(\"Current lock order is:\\n\");\n    for (const LockStackItem& i : s2) {\n        std::string prefix{};\n        if (i.first == mismatch.first) {\n            prefix = \" (1)\";\n            mutex_a = i.second.Name();\n        }\n        if (i.first == mismatch.second) {\n            prefix = \" (2)\";\n            mutex_b = i.second.Name();\n        }\n        LogPrintf(\"%s %s\\n\", prefix, i.second.ToString());\n    }\n    if (g_debug_lockorder_abort) {\n        tfm::format(std::cerr, \"Assertion failed: detected inconsistent lock order for %s, details in debug log.\\n\", s2.back().second.ToString());\n        abort();\n    }\n    throw std::logic_error(strprintf(\"potential deadlock detected: %s -> %s -> %s\", mutex_b, mutex_a, mutex_b));\n}\n\nstatic void double_lock_detected(const void* mutex, const LockStack& lock_stack)\n{\n    LogPrintf(\"DOUBLE LOCK DETECTED\\n\");\n    LogPrintf(\"Lock order:\\n\");\n    for (const LockStackItem& i : lock_stack) {\n        std::string prefix{};\n        if (i.first == mutex) {\n            prefix = \" (*)\";\n        }\n        LogPrintf(\"%s %s\\n\", prefix, i.second.ToString());\n    }\n    if (g_debug_lockorder_abort) {\n        tfm::format(std::cerr,\n                    \"Assertion failed: detected double lock for %s, details in debug log.\\n\",\n                    lock_stack.back().second.ToString());\n        abort();\n    }\n    throw std::logic_error(\"double lock detected\");\n}\n\ntemplate <typename MutexType>\nstatic void push_lock(MutexType* c, const CLockLocation& locklocation)\n{\n    constexpr bool is_recursive_mutex =\n        std::is_base_of<RecursiveMutex, MutexType>::value ||\n        std::is_base_of<std::recursive_mutex, MutexType>::value;\n\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n\n    LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];\n    lock_stack.emplace_back(c, locklocation);\n    for (size_t j = 0; j < lock_stack.size() - 1; ++j) {\n        const LockStackItem& i = lock_stack[j];\n        if (i.first == c) {\n            if (is_recursive_mutex) {\n                break;\n            }\n            // It is not a recursive mutex and it appears in the stack two times:\n            // at position `j` and at the end (which we added just before this loop).\n            // Can't allow locking the same (non-recursive) mutex two times from the\n            // same thread as that results in an undefined behavior.\n            auto lock_stack_copy = lock_stack;\n            lock_stack.pop_back();\n            double_lock_detected(c, lock_stack_copy);\n            // double_lock_detected() does not return.\n        }\n\n        const LockPair p1 = std::make_pair(i.first, c);\n        if (lockdata.lockorders.count(p1))\n            continue;\n\n        const LockPair p2 = std::make_pair(c, i.first);\n        if (lockdata.lockorders.count(p2)) {\n            auto lock_stack_copy = lock_stack;\n            lock_stack.pop_back();\n            potential_deadlock_detected(p1, lockdata.lockorders[p2], lock_stack_copy);\n            // potential_deadlock_detected() does not return.\n        }\n\n        lockdata.lockorders.emplace(p1, lock_stack);\n        lockdata.invlockorders.insert(p2);\n    }\n}\n\nstatic void pop_lock()\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n\n    LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];\n    lock_stack.pop_back();\n    if (lock_stack.empty()) {\n        lockdata.m_lock_stacks.erase(std::this_thread::get_id());\n    }\n}\n\ntemplate <typename MutexType>\nvoid EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry)\n{\n    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));\n}\ntemplate void EnterCritical(const char*, const char*, int, Mutex*, bool);\ntemplate void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);\ntemplate void EnterCritical(const char*, const char*, int, std::mutex*, bool);\ntemplate void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);\n\nvoid CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n\n    const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];\n    if (!lock_stack.empty()) {\n        const auto& lastlock = lock_stack.back();\n        if (lastlock.first == cs) {\n            lockname = lastlock.second.Name();\n            return;\n        }\n    }\n\n    LogPrintf(\"INCONSISTENT LOCK ORDER DETECTED\\n\");\n    LogPrintf(\"Current lock order (least recent first) is:\\n\");\n    for (const LockStackItem& i : lock_stack) {\n        LogPrintf(\" %s\\n\", i.second.ToString());\n    }\n    if (g_debug_lockorder_abort) {\n        tfm::format(std::cerr, \"%s:%s %s was not most recent critical section locked, details in debug log.\\n\", file, line, guardname);\n        abort();\n    }\n    throw std::logic_error(strprintf(\"%s was not most recent critical section locked\", guardname));\n}\n\nvoid LeaveCritical()\n{\n    pop_lock();\n}\n\nstd::string LocksHeld()\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n\n    const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];\n    std::string result;\n    for (const LockStackItem& i : lock_stack)\n        result += i.second.ToString() + std::string(\"\\n\");\n    return result;\n}\n\nstatic bool LockHeld(void* mutex)\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n\n    const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];\n    for (const LockStackItem& i : lock_stack) {\n        if (i.first == mutex) return true;\n    }\n\n    return false;\n}\n\ntemplate <typename MutexType>\nvoid AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)\n{\n    if (LockHeld(cs)) return;\n    tfm::format(std::cerr, \"Assertion failed: lock %s not held in %s:%i; locks held:\\n%s\", pszName, pszFile, nLine, LocksHeld());\n    abort();\n}\ntemplate void AssertLockHeldInternal(const char*, const char*, int, Mutex*);\ntemplate void AssertLockHeldInternal(const char*, const char*, int, RecursiveMutex*);\n\ntemplate <typename MutexType>\nvoid AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)\n{\n    if (!LockHeld(cs)) return;\n    tfm::format(std::cerr, \"Assertion failed: lock %s held in %s:%i; locks held:\\n%s\", pszName, pszFile, nLine, LocksHeld());\n    abort();\n}\ntemplate void AssertLockNotHeldInternal(const char*, const char*, int, Mutex*);\ntemplate void AssertLockNotHeldInternal(const char*, const char*, int, RecursiveMutex*);\n\nvoid DeleteLock(void* cs)\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n    const LockPair item = std::make_pair(cs, nullptr);\n    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);\n    while (it != lockdata.lockorders.end() && it->first.first == cs) {\n        const LockPair invitem = std::make_pair(it->first.second, it->first.first);\n        lockdata.invlockorders.erase(invitem);\n        lockdata.lockorders.erase(it++);\n    }\n    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);\n    while (invit != lockdata.invlockorders.end() && invit->first == cs) {\n        const LockPair invinvitem = std::make_pair(invit->second, invit->first);\n        lockdata.lockorders.erase(invinvitem);\n        lockdata.invlockorders.erase(invit++);\n    }\n}\n\nbool LockStackEmpty()\n{\n    LockData& lockdata = GetLockData();\n    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);\n    const auto it = lockdata.m_lock_stacks.find(std::this_thread::get_id());\n    if (it == lockdata.m_lock_stacks.end()) {\n        return true;\n    }\n    return it->second.empty();\n}\n\nbool g_debug_lockorder_abort = true;\n\n#endif /* DEBUG_LOCKORDER */\n"
  },
  {
    "path": "src/sync.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef CORE_SYNC_H\n#define CORE_SYNC_H\n\n\n#include <threadsafety.h>\n#include <tinyformat.h>\n#include <util/macros.h>\n#include \"logging.h\"\n#include <condition_variable>\n#include <mutex>\n#include <string>\n#include <thread>\n\n////////////////////////////////////////////////\n//                                            //\n// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //\n//                                            //\n////////////////////////////////////////////////\n\n/*\nRecursiveMutex mutex;\n    std::recursive_mutex mutex;\n\nLOCK(mutex);\n    std::unique_lock<std::recursive_mutex> criticalblock(mutex);\n\nLOCK2(mutex1, mutex2);\n    std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);\n    std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);\n\nTRY_LOCK(mutex, name);\n    std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);\n\nENTER_CRITICAL_SECTION(mutex); // no RAII\n    mutex.lock();\n\nLEAVE_CRITICAL_SECTION(mutex); // no RAII\n    mutex.unlock();\n */\n\n///////////////////////////////\n//                           //\n// THE ACTUAL IMPLEMENTATION //\n//                           //\n///////////////////////////////\n\n#ifdef DEBUG_LOCKORDER\ntemplate <typename MutexType>\nvoid EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false);\nvoid LeaveCritical();\nvoid CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);\nstd::string LocksHeld();\ntemplate <typename MutexType>\nvoid AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);\ntemplate <typename MutexType>\nvoid AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs);\nvoid DeleteLock(void* cs);\nbool LockStackEmpty();\n\n/**\n * Call abort() if a potential lock order deadlock bug is detected, instead of\n * just logging information and throwing a logic_error. Defaults to true, and\n * set to false in DEBUG_LOCKORDER unit tests.\n */\nextern bool g_debug_lockorder_abort;\n#else\ntemplate <typename MutexType>\ninline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}\ninline void LeaveCritical() {}\ninline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}\ntemplate <typename MutexType>\ninline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}\ntemplate <typename MutexType>\nvoid AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {}\ninline void DeleteLock(void* cs) {}\ninline bool LockStackEmpty() { return true; }\n#endif\n#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)\n#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)\n\n/**\n * Template mixin that adds -Wthread-safety locking annotations and lock order\n * checking to a subset of the mutex API.\n */\ntemplate <typename PARENT>\nclass LOCKABLE AnnotatedMixin : public PARENT\n{\npublic:\n    ~AnnotatedMixin() {\n        DeleteLock((void*)this);\n    }\n\n    void lock() EXCLUSIVE_LOCK_FUNCTION()\n    {\n        PARENT::lock();\n    }\n\n    void unlock() UNLOCK_FUNCTION()\n    {\n        PARENT::unlock();\n    }\n\n    bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)\n    {\n        return PARENT::try_lock();\n    }\n\n    using UniqueLock = std::unique_lock<PARENT>;\n#ifdef __clang__\n    //! For negative capabilities in the Clang Thread Safety Analysis.\n    //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction\n    //! with the ! operator, to indicate that a mutex should not be held.\n    const AnnotatedMixin& operator!() const { return *this; }\n#endif // __clang__\n};\n\n/**\n * Wrapped mutex: supports recursive locking, but no waiting\n * TODO: We should move away from using the recursive lock by default.\n */\nusing RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;\n\n/** Wrapped mutex: supports waiting but not recursive locking */\ntypedef AnnotatedMixin<std::mutex> Mutex;\n\n/** Wrapper around std::unique_lock style lock for Mutex. */\ntemplate <typename Mutex, typename Base = typename Mutex::UniqueLock>\nclass SCOPED_LOCKABLE UniqueLock : public Base\n{\nprivate:\n    void Enter(const char* pszName, const char* pszFile, int nLine)\n    {\n        EnterCritical(pszName, pszFile, nLine, Base::mutex());\n        if (Base::try_lock()) return;\n        LogPrint(BCLog::LOCK, \"lock contention %s, %s:%d\\n\", pszName, pszFile, nLine);\n        Base::lock();\n    }\n\n    bool TryEnter(const char* pszName, const char* pszFile, int nLine)\n    {\n        EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);\n        Base::try_lock();\n        if (!Base::owns_lock()) {\n            LeaveCritical();\n        }\n        return Base::owns_lock();\n    }\n\npublic:\n    UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)\n    {\n        if (fTry)\n            TryEnter(pszName, pszFile, nLine);\n        else\n            Enter(pszName, pszFile, nLine);\n    }\n\n    UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)\n    {\n        if (!pmutexIn) return;\n\n        *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);\n        if (fTry)\n            TryEnter(pszName, pszFile, nLine);\n        else\n            Enter(pszName, pszFile, nLine);\n    }\n\n    ~UniqueLock() UNLOCK_FUNCTION()\n    {\n        if (Base::owns_lock())\n            LeaveCritical();\n    }\n\n    operator bool()\n    {\n        return Base::owns_lock();\n    }\n\nprotected:\n    // needed for reverse_lock\n    UniqueLock() { }\n\npublic:\n    /**\n     * An RAII-style reverse lock. Unlocks on construction and locks on destruction.\n     */\n    class reverse_lock {\n    public:\n        explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {\n            CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);\n            lock.unlock();\n            LeaveCritical();\n            lock.swap(templock);\n        }\n\n        ~reverse_lock() {\n            templock.swap(lock);\n            EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());\n            lock.lock();\n        }\n\n     private:\n        reverse_lock(reverse_lock const&);\n        reverse_lock& operator=(reverse_lock const&);\n\n        UniqueLock& lock;\n        UniqueLock templock;\n        std::string lockname;\n        const std::string file;\n        const int line;\n     };\n     friend class reverse_lock;\n};\n\n#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)\n\ntemplate<typename MutexArg>\nusing DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;\n\ntemplate<class T> bool IsNullMutex([[maybe_unused]] T& mutex) { return false; }\ntemplate<class T> bool IsNullMutex(T* mutex) { if (mutex == NULL) { return true; } return false; }\n\n// Achieve LOCK2, using a loop and TRY_LOCK to allow for an opportunity for any deadlocks to resolve themselves (at the cost of performance)\n// For now we favour stability over performance, over time we should convert all DS_LOCK2 into LOCK2 one at a time with strict testing.\n#define DS_LOCK2(cs1, cs2)                                                                                                              \\\nstd::shared_ptr<DebugLock<decltype(cs1)>> criticalblock1_ds2 = nullptr;                                                                 \\\nstd::shared_ptr<DebugLock<decltype(cs2)>> criticalblock2_ds2 = nullptr;                                                                 \\\nwhile(true)                                                                                                                             \\\n{                                                                                                                                       \\\n    criticalblock1_ds2 = std::shared_ptr<DebugLock<decltype(cs1)>>(new DebugLock<decltype(cs1)>(cs1, #cs1, __FILE__, __LINE__, true));  \\\n    criticalblock2_ds2 = std::shared_ptr<DebugLock<decltype(cs2)>>(new DebugLock<decltype(cs2)>(cs2, #cs2, __FILE__, __LINE__, true));  \\\n    if ((!(*criticalblock1_ds2) && !IsNullMutex(criticalblock1_ds2)))                                                                   \\\n    {                                                                                                                                   \\\n        LogPrint(BCLog::LOCK, \"dslock_2 (cs1) contention %s %s, %s:%d\\n\", #cs1, #cs2, __FILE__, __LINE__);                              \\\n        criticalblock1_ds2 = nullptr;                                                                                                   \\\n        criticalblock2_ds2 = nullptr;                                                                                                   \\\n        MilliSleep(50);                                                                                                                 \\\n        continue;                                                                                                                       \\\n    };                                                                                                                                  \\\n    if ((!(*criticalblock2_ds2) && !IsNullMutex(criticalblock2_ds2)))                                                                   \\\n    {                                                                                                                                   \\\n        LogPrint(BCLog::LOCK, \"dslock_2 (cs2) contention %s %s, %s:%d\\n\", #cs1, #cs2, __FILE__, __LINE__);                              \\\n        criticalblock1_ds2 = nullptr;                                                                                                   \\\n        criticalblock2_ds2 = nullptr;                                                                                                   \\\n        MilliSleep(50);                                                                                                                 \\\n        continue;                                                                                                                       \\\n    };                                                                                                                                  \\\n    break;                                                                                                                              \\\n}\n\n#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)\n#define LOCK2(cs1, cs2)                                               \\\n    DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \\\n    DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);\n#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)\n#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)\n\n#define ENTER_CRITICAL_SECTION(cs)                            \\\n    {                                                         \\\n        EnterCritical(#cs, __FILE__, __LINE__, &cs); \\\n        (cs).lock();                                          \\\n    }\n\n#define LEAVE_CRITICAL_SECTION(cs)                                          \\\n    {                                                                       \\\n        std::string lockname;                                               \\\n        CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \\\n        (cs).unlock();                                                      \\\n        LeaveCritical();                                                    \\\n    }\n\n//! Run code while locking a mutex.\n//!\n//! Examples:\n//!\n//!   WITH_LOCK(cs, shared_val = shared_val + 1);\n//!\n//!   int val = WITH_LOCK(cs, return shared_val);\n//!\n//! Note:\n//!\n//! Since the return type deduction follows that of decltype(auto), while the\n//! deduced type of:\n//!\n//!   WITH_LOCK(cs, return {int i = 1; return i;});\n//!\n//! is int, the deduced type of:\n//!\n//!   WITH_LOCK(cs, return {int j = 1; return (j);});\n//!\n//! is &int, a reference to a local variable\n//!\n//! The above is detectable at compile-time with the -Wreturn-local-addr flag in\n//! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.\n#define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }()\n\nclass CSemaphore\n{\nprivate:\n    std::condition_variable condition;\n    std::mutex mutex;\n    int value;\n\npublic:\n    explicit CSemaphore(int init) : value(init) {}\n\n    void wait()\n    {\n        std::unique_lock<std::mutex> lock(mutex);\n        condition.wait(lock, [&]() { return value >= 1; });\n        value--;\n    }\n\n    bool try_wait()\n    {\n        std::lock_guard<std::mutex> lock(mutex);\n        if (value < 1)\n            return false;\n        value--;\n        return true;\n    }\n\n    void post()\n    {\n        {\n            std::lock_guard<std::mutex> lock(mutex);\n            value++;\n        }\n        condition.notify_one();\n    }\n};\n\n/** RAII-style semaphore lock */\nclass CSemaphoreGrant\n{\nprivate:\n    CSemaphore* sem;\n    bool fHaveGrant;\n\npublic:\n    void Acquire()\n    {\n        if (fHaveGrant)\n            return;\n        sem->wait();\n        fHaveGrant = true;\n    }\n\n    void Release()\n    {\n        if (!fHaveGrant)\n            return;\n        sem->post();\n        fHaveGrant = false;\n    }\n\n    bool TryAcquire()\n    {\n        if (!fHaveGrant && sem->try_wait())\n            fHaveGrant = true;\n        return fHaveGrant;\n    }\n\n    void MoveTo(CSemaphoreGrant& grant)\n    {\n        grant.Release();\n        grant.sem = sem;\n        grant.fHaveGrant = fHaveGrant;\n        fHaveGrant = false;\n    }\n\n    CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}\n\n    explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)\n    {\n        if (fTry)\n            TryAcquire();\n        else\n            Acquire();\n    }\n\n    ~CSemaphoreGrant()\n    {\n        Release();\n    }\n\n    operator bool() const\n    {\n        return fHaveGrant;\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/test/DoS_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// Unit tests for denial-of-service detection/prevention code\n\n#include \"chainparams.h\"\n#include \"keystore.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"pow/pow.h\"\n#include \"script/sign.h\"\n#include \"serialize.h\"\n#include \"util.h\"\n#include \"validation/validation.h\"\n\n#include \"test/test.h\"\n\n#include <stdint.h>\n\n#include <boost/test/unit_test.hpp>\n\n// Tests these internal-to-net_processing.cpp methods:\nextern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);\nextern void EraseOrphansFor(NodeId peer);\nextern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);\nstruct COrphanTx {\n    CTransactionRef tx;\n    NodeId fromPeer;\n    int64_t nTimeExpire;\n};\nextern std::map<uint256, COrphanTx> mapOrphanTransactions;\n\nCService ip(uint32_t i)\n{\n    struct in_addr s;\n    s.s_addr = i;\n    return CService(CNetAddr(s), Params().GetDefaultPort());\n}\n\nstatic NodeId id = 0;\n\nBOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)\n\nBOOST_AUTO_TEST_CASE(DoS_banning)\n{\n    std::atomic<bool> interruptDummy(false);\n\n    connman->ClearBanned();\n    CAddress addr1(ip(0xa0b0c001), NODE_NONE);\n    CNode dummyNode1(id++, NODE_NETWORK, 0, socket_t(get_io_context()), addr1, 0, 0, CAddress(), \"\", true);\n    dummyNode1.SetSendVersion(PROTOCOL_VERSION);\n    GetNodeSignals().InitializeNode(&dummyNode1, *connman);\n    dummyNode1.nVersion = 1;\n    dummyNode1.fSuccessfullyConnected = true;\n    Misbehaving(dummyNode1.GetId(), 100); // Should get banned\n    SendMessages(&dummyNode1, *connman, interruptDummy);\n    BOOST_CHECK(connman->IsBanned(addr1));\n    BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned\n\n    CAddress addr2(ip(0xa0b0c002), NODE_NONE);\n    CNode dummyNode2(id++, NODE_NETWORK, 0, socket_t(get_io_context()), addr2, 1, 1, CAddress(), \"\", true);\n    dummyNode2.SetSendVersion(PROTOCOL_VERSION);\n    GetNodeSignals().InitializeNode(&dummyNode2, *connman);\n    dummyNode2.nVersion = 1;\n    dummyNode2.fSuccessfullyConnected = true;\n    Misbehaving(dummyNode2.GetId(), 50);\n    SendMessages(&dummyNode2, *connman, interruptDummy);\n    BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...\n    BOOST_CHECK(connman->IsBanned(addr1));  // ... but 1 still should be\n    Misbehaving(dummyNode2.GetId(), 50);\n    SendMessages(&dummyNode2, *connman, interruptDummy);\n    BOOST_CHECK(connman->IsBanned(addr2));\n}\n\nBOOST_AUTO_TEST_CASE(DoS_banscore)\n{\n    std::atomic<bool> interruptDummy(false);\n\n    connman->ClearBanned();\n    ForceSetArg(\"-banscore\", \"111\"); // because 11 is my favorite number\n    CAddress addr1(ip(0xa0b0c001), NODE_NONE);\n    CNode dummyNode1(id++, NODE_NETWORK, 0, socket_t(get_io_context()), addr1, 3, 1, CAddress(), \"\", true);\n    dummyNode1.SetSendVersion(PROTOCOL_VERSION);\n    GetNodeSignals().InitializeNode(&dummyNode1, *connman);\n    dummyNode1.nVersion = 1;\n    dummyNode1.fSuccessfullyConnected = true;\n    Misbehaving(dummyNode1.GetId(), 100);\n    SendMessages(&dummyNode1, *connman, interruptDummy);\n    BOOST_CHECK(!connman->IsBanned(addr1));\n    Misbehaving(dummyNode1.GetId(), 10);\n    SendMessages(&dummyNode1, *connman, interruptDummy);\n    BOOST_CHECK(!connman->IsBanned(addr1));\n    Misbehaving(dummyNode1.GetId(), 1);\n    SendMessages(&dummyNode1, *connman, interruptDummy);\n    BOOST_CHECK(connman->IsBanned(addr1));\n    ForceSetArg(\"-banscore\", std::to_string(DEFAULT_BANSCORE_THRESHOLD));\n}\n\nBOOST_AUTO_TEST_CASE(DoS_bantime)\n{\n    std::atomic<bool> interruptDummy(false);\n\n    connman->ClearBanned();\n    int64_t nStartTime = GetTime();\n    SetMockTime(nStartTime); // Overrides future calls to GetTime()\n\n    CAddress addr(ip(0xa0b0c001), NODE_NONE);\n    CNode dummyNode(id++, NODE_NETWORK, 0, socket_t(get_io_context()), addr, 4, 4, CAddress(), \"\", true);\n    dummyNode.SetSendVersion(PROTOCOL_VERSION);\n    GetNodeSignals().InitializeNode(&dummyNode, *connman);\n    dummyNode.nVersion = 1;\n    dummyNode.fSuccessfullyConnected = true;\n\n    Misbehaving(dummyNode.GetId(), 100);\n    SendMessages(&dummyNode, *connman, interruptDummy);\n    BOOST_CHECK(connman->IsBanned(addr));\n\n    SetMockTime(nStartTime+60*60);\n    BOOST_CHECK(connman->IsBanned(addr));\n\n    SetMockTime(nStartTime+60*60*24+1);\n    BOOST_CHECK(!connman->IsBanned(addr));\n}\n\nCTransactionRef RandomOrphan()\n{\n    std::map<uint256, COrphanTx>::iterator it;\n    it = mapOrphanTransactions.lower_bound(InsecureRand256());\n    if (it == mapOrphanTransactions.end())\n        it = mapOrphanTransactions.begin();\n    return it->second.tx;\n}\n\nBOOST_AUTO_TEST_CASE(DoS_mapOrphans)\n{\n    CKey key;\n    key.MakeNewKey(true);\n    CBasicKeyStore keystore;\n    keystore.AddKey(key);\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n\n    // 50 orphan transactions:\n    for (int i = 0; i < 50; i++)\n    {\n        CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n        tx.vin.resize(1);\n        COutPoint changePrevOut = tx.vin[0].GetPrevOut();\n        changePrevOut.n = 0;\n        changePrevOut.setHash(InsecureRand256());\n        tx.vin[0].SetPrevOut(changePrevOut);\n        tx.vin[0].scriptSig << OP_1;\n        tx.vout.resize(1);\n        tx.vout[0].nValue = 1*CENT;\n        tx.vout[0].output.scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());\n\n        AddOrphanTx(MakeTransactionRef(tx), i);\n    }\n\n    // ... and 50 that depend on other orphans:\n    for (int i = 0; i < 50; i++)\n    {\n        CTransactionRef txPrev = RandomOrphan();\n\n        CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n        tx.vin.resize(1);\n        COutPoint changePrevOut = tx.vin[0].GetPrevOut();\n        changePrevOut.n = 0;\n        changePrevOut.setHash(txPrev->GetHash());\n        tx.vin[0].SetPrevOut(changePrevOut);\n        tx.vout.resize(1);\n        tx.vout[0].nValue = 1*CENT;\n        tx.vout[0].output.scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());\n        SignSignature(accountsToTry, *txPrev, tx, 0, SIGHASH_ALL, SignType::Spend);\n\n        AddOrphanTx(MakeTransactionRef(tx), i);\n    }\n\n    // This really-big orphan should be ignored:\n    for (int i = 0; i < 10; i++)\n    {\n        CTransactionRef txPrev = RandomOrphan();\n\n        CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n        tx.vout.resize(1);\n        tx.vout[0].nValue = 1*CENT;\n        tx.vout[0].output.scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());\n        tx.vin.resize(2777);\n        for (unsigned int j = 0; j < tx.vin.size(); j++)\n        {\n            COutPoint changePrevOut = tx.vin[j].GetPrevOut();\n            changePrevOut.n = j;\n            changePrevOut.setHash(txPrev->GetHash());\n            tx.vin[j].SetPrevOut(changePrevOut);\n        }\n        SignSignature(accountsToTry, *txPrev, tx, 0, SIGHASH_ALL, SignType::Spend);\n        // Re-use same signature for other inputs\n        // (they don't have to be valid for this test)\n        for (unsigned int j = 1; j < tx.vin.size(); j++)\n            tx.vin[j].scriptSig = tx.vin[0].scriptSig;\n\n        BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));\n    }\n\n    // Test EraseOrphansFor:\n    for (NodeId i = 0; i < 3; i++)\n    {\n        size_t sizeBefore = mapOrphanTransactions.size();\n        EraseOrphansFor(i);\n        BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore);\n    }\n\n    // Test LimitOrphanTxSize() function:\n    LimitOrphanTxSize(40);\n    BOOST_CHECK(mapOrphanTransactions.size() <= 40);\n    LimitOrphanTxSize(10);\n    BOOST_CHECK(mapOrphanTransactions.size() <= 10);\n    LimitOrphanTxSize(0);\n    BOOST_CHECK(mapOrphanTransactions.empty());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/README.md",
    "content": "### Compiling/running unit tests\n\nUnit tests will be automatically compiled if dependencies were met in `./configure`\nand tests weren't explicitly disabled.\n\nAfter configuring, they can be run with `make check`.\n\nTo run the Munt-daemon tests manually, launch `src/test/test_munt`.\n\nTo add more Munt-daemon tests, add `BOOST_AUTO_TEST_CASE` functions to the existing\n.cpp files in the `test/` directory or add new .cpp files that\nimplement new BOOST_AUTO_TEST_SUITE sections.\n\n### Running individual tests\n\ntest_munt has some built-in command-line arguments; for\nexample, to run just the getarg_tests verbosely:\n\n    test_munt --log_level=all --run_test=getarg_tests\n\n... or to run just the doubledash test:\n\n    test_munt --run_test=getarg_tests/doubledash\n\nRun `test_munt --help` for the full list.\n\n### Note on adding test cases\n\nThe sources in this directory are unit test cases.  Boost includes a\nunit testing framework, and since Munt already uses boost, it makes\nsense to simply use this framework rather than require developers to\nconfigure some other framework (we want as few impediments to creating\nunit tests as possible).\n\nThe build system is setup to compile an executable called `test_munt`\nthat runs all of the unit tests.  The main source file is called\ntest_munt.cpp. To add a new unit test file to our test suite you need \nto add the file to `src/Makefile.test.include`. The pattern is to create \none test file for each class or source file for which you want to create \nunit tests.  The file naming convention is `<source_filename>_tests.cpp` \nand such files should wrap their tests in a test suite \ncalled `<source_filename>_tests`. For an example of this pattern, \nexamine `uint256_tests.cpp`.\n\nFor further reading, I found the following website to be helpful in\nexplaining how the boost unit test framework works:\n[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).\n"
  },
  {
    "path": "src/test/addrman_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"addrman.h\"\n#include \"test/test.h\"\n#include <string>\n#include <boost/test/unit_test.hpp>\n\n#include \"hash.h\"\n#include \"netbase.h\"\n#include \"random.h\"\n\nclass CAddrManTest : public CAddrMan\n{\n    uint64_t state;\n\npublic:\n    CAddrManTest()\n    {\n        state = 1;\n    }\n\n    //! Ensure that bucket placement is always the same for testing purposes.\n    void MakeDeterministic()\n    {\n        nKey.SetNull();\n        insecure_rand = FastRandomContext(true);\n    }\n\n    int RandomInt(int nMax)\n    {\n        state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash();\n        return (unsigned int)(state % nMax);\n    }\n\n    CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL)\n    {\n        return CAddrMan::Find(addr, pnId);\n    }\n\n    CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL)\n    {\n        return CAddrMan::Create(addr, addrSource, pnId);\n    }\n\n    void Delete(int nId)\n    {\n        CAddrMan::Delete(nId);\n    }\n};\n\nstatic CNetAddr ResolveIP(const char* ip)\n{\n    CNetAddr addr;\n    BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf(\"failed to resolve: %s\", ip));\n    return addr;\n}\n\nstatic CNetAddr ResolveIP(std::string ip)\n{\n    return ResolveIP(ip.c_str());\n}\n\nstatic CService ResolveService(const char* ip, int port = 0)\n{\n    CService serv;\n    BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf(\"failed to resolve: %s:%i\", ip, port));\n    return serv;\n}\n\nstatic CService ResolveService(std::string ip, int port = 0)\n{\n    return ResolveService(ip.c_str(), port);\n}\n\nBOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(addrman_simple)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CNetAddr source = ResolveIP(\"252.2.2.2\");\n\n    // Test: Does Addrman respond correctly when empty.\n    BOOST_CHECK(addrman.size() == 0);\n    CAddrInfo addr_null = addrman.Select();\n    BOOST_CHECK_EQUAL(addr_null.ToString(), \"[::]:0\");\n\n    // Test: Does Addrman::Add work as expected.\n    CService addr1 = ResolveService(\"250.1.1.1\", 9231);\n    BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source));\n    BOOST_CHECK(addrman.size() == 1);\n    CAddrInfo addr_ret1 = addrman.Select();\n    BOOST_CHECK_EQUAL(addr_ret1.ToString(), \"250.1.1.1:9231\");\n\n    // Test: Does IP address deduplication work correctly.\n    //  Expected dup IP should not be added.\n    CService addr1_dup = ResolveService(\"250.1.1.1\", 9231);\n    BOOST_CHECK(!addrman.Add(CAddress(addr1_dup, NODE_NONE), source));\n    BOOST_CHECK(addrman.size() == 1);\n\n\n    // Test: New table has one addr and we add a diff addr we should\n    //  have at least one addr.\n    // Note that addrman's size cannot be tested reliably after insertion, as\n    // hash collisions may occur. But we can always be sure of at least one\n    // success.\n\n    CService addr2 = ResolveService(\"250.1.1.2\", 9231);\n    BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source));\n    BOOST_CHECK(addrman.size() >= 1);\n\n    // Test: AddrMan::Clear() should empty the new table.\n    addrman.Clear();\n    BOOST_CHECK(addrman.size() == 0);\n    CAddrInfo addr_null2 = addrman.Select();\n    BOOST_CHECK_EQUAL(addr_null2.ToString(), \"[::]:0\");\n\n    // Test: AddrMan::Add multiple addresses works as expected\n    std::vector<CAddress> vAddr;\n    vAddr.push_back(CAddress(ResolveService(\"250.1.1.3\", 9231), NODE_NONE));\n    vAddr.push_back(CAddress(ResolveService(\"250.1.1.4\", 9231), NODE_NONE));\n    BOOST_CHECK(addrman.Add(vAddr, source));\n    BOOST_CHECK(addrman.size() >= 1);\n}\n\nBOOST_AUTO_TEST_CASE(addrman_ports)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CNetAddr source = ResolveIP(\"252.2.2.2\");\n\n    BOOST_CHECK(addrman.size() == 0);\n\n    // Test 7; Addr with same IP but diff port does not replace existing addr.\n    CService addr1 = ResolveService(\"250.1.1.1\", 9231);\n    addrman.Add(CAddress(addr1, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 1);\n\n    CService addr1_port = ResolveService(\"250.1.1.1\", 8334);\n    addrman.Add(CAddress(addr1_port, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 1);\n    CAddrInfo addr_ret2 = addrman.Select();\n    BOOST_CHECK_EQUAL(addr_ret2.ToString(), \"250.1.1.1:9231\");\n\n    // Test: Add same IP but diff port to tried table, it doesn't get added.\n    //  Perhaps this is not ideal behavior but it is the current behavior.\n    addrman.Good(CAddress(addr1_port, NODE_NONE));\n    BOOST_CHECK(addrman.size() == 1);\n    bool newOnly = true;\n    CAddrInfo addr_ret3 = addrman.Select(newOnly);\n    BOOST_CHECK_EQUAL(addr_ret3.ToString(), \"250.1.1.1:9231\");\n}\n\n\nBOOST_AUTO_TEST_CASE(addrman_select)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CNetAddr source = ResolveIP(\"252.2.2.2\");\n\n    // Test: Select from new with 1 addr in new.\n    CService addr1 = ResolveService(\"250.1.1.1\", 9231);\n    addrman.Add(CAddress(addr1, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 1);\n\n    bool newOnly = true;\n    CAddrInfo addr_ret1 = addrman.Select(newOnly);\n    BOOST_CHECK_EQUAL(addr_ret1.ToString(), \"250.1.1.1:9231\");\n\n    // Test: move addr to tried, select from new expected nothing returned.\n    addrman.Good(CAddress(addr1, NODE_NONE));\n    BOOST_CHECK(addrman.size() == 1);\n    CAddrInfo addr_ret2 = addrman.Select(newOnly);\n    BOOST_CHECK_EQUAL(addr_ret2.ToString(), \"[::]:0\");\n\n    CAddrInfo addr_ret3 = addrman.Select();\n    BOOST_CHECK_EQUAL(addr_ret3.ToString(), \"250.1.1.1:9231\");\n\n    BOOST_CHECK(addrman.size() == 1);\n\n\n    // Add three addresses to new table.\n    CService addr2 = ResolveService(\"250.3.1.1\", 9231);\n    CService addr3 = ResolveService(\"250.3.2.2\", 9999);\n    CService addr4 = ResolveService(\"250.3.3.3\", 9999);\n\n    addrman.Add(CAddress(addr2, NODE_NONE), ResolveService(\"250.3.1.1\", 9231));\n    addrman.Add(CAddress(addr3, NODE_NONE), ResolveService(\"250.3.1.1\", 9231));\n    addrman.Add(CAddress(addr4, NODE_NONE), ResolveService(\"250.4.1.1\", 9231));\n\n    // Add three addresses to tried table.\n    CService addr5 = ResolveService(\"250.4.4.4\", 9231);\n    CService addr6 = ResolveService(\"250.4.5.5\", 7777);\n    CService addr7 = ResolveService(\"250.4.6.6\", 9231);\n\n    addrman.Add(CAddress(addr5, NODE_NONE), ResolveService(\"250.3.1.1\", 9231));\n    addrman.Good(CAddress(addr5, NODE_NONE));\n    addrman.Add(CAddress(addr6, NODE_NONE), ResolveService(\"250.3.1.1\", 9231));\n    addrman.Good(CAddress(addr6, NODE_NONE));\n    addrman.Add(CAddress(addr7, NODE_NONE), ResolveService(\"250.1.1.3\", 9231));\n    addrman.Good(CAddress(addr7, NODE_NONE));\n\n    // Test: 6 addrs + 1 addr from last test = 7.\n    BOOST_CHECK(addrman.size() == 7);\n\n    // Test: Select pulls from new and tried regardless of port number.\n    std::set<uint16_t> ports;\n    for (int i = 0; i < 20; ++i) {\n        ports.insert(addrman.Select().GetPort());\n    }\n    BOOST_CHECK(ports.size() == 3);\n}\n\nBOOST_AUTO_TEST_CASE(addrman_new_collisions)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CNetAddr source = ResolveIP(\"252.2.2.2\");\n\n    BOOST_CHECK(addrman.size() == 0);\n\n    for (unsigned int i = 1; i < 18; i++) {\n        CService addr = ResolveService(\"250.1.1.\" + boost::to_string(i));\n        addrman.Add(CAddress(addr, NODE_NONE), source);\n\n        //Test: No collision in new table yet.\n        BOOST_CHECK_EQUAL(addrman.size(), i);\n    }\n\n    //Test: new table collision!\n    CService addr1 = ResolveService(\"250.1.1.18\");\n    addrman.Add(CAddress(addr1, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 17);\n\n    CService addr2 = ResolveService(\"250.1.1.19\");\n    addrman.Add(CAddress(addr2, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 18);\n}\n\nBOOST_AUTO_TEST_CASE(addrman_tried_collisions)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CNetAddr source = ResolveIP(\"252.2.2.2\");\n\n    BOOST_CHECK(addrman.size() == 0);\n\n    for (unsigned int i = 1; i < 80; i++) {\n        CService addr = ResolveService(\"250.1.1.\" + boost::to_string(i));\n        addrman.Add(CAddress(addr, NODE_NONE), source);\n        addrman.Good(CAddress(addr, NODE_NONE));\n\n        //Test: No collision in tried table yet.\n        BOOST_CHECK_EQUAL(addrman.size(), i);\n    }\n\n    //Test: tried table collision!\n    CService addr1 = ResolveService(\"250.1.1.80\");\n    addrman.Add(CAddress(addr1, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 79);\n\n    CService addr2 = ResolveService(\"250.1.1.81\");\n    addrman.Add(CAddress(addr2, NODE_NONE), source);\n    BOOST_CHECK(addrman.size() == 80);\n}\n\nBOOST_AUTO_TEST_CASE(addrman_find)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(0));\n\n    CAddress addr1 = CAddress(ResolveService(\"250.1.2.1\", 9231), NODE_NONE);\n    CAddress addr2 = CAddress(ResolveService(\"250.1.2.1\", 9999), NODE_NONE);\n    CAddress addr3 = CAddress(ResolveService(\"251.255.2.1\", 9231), NODE_NONE);\n\n    CNetAddr source1 = ResolveIP(\"250.1.2.1\");\n    CNetAddr source2 = ResolveIP(\"250.1.2.2\");\n\n    addrman.Add(addr1, source1);\n    addrman.Add(addr2, source2);\n    addrman.Add(addr3, source1);\n\n    // Test: ensure Find returns an IP matching what we searched on.\n    CAddrInfo* info1 = addrman.Find(addr1);\n    BOOST_REQUIRE(info1);\n    BOOST_CHECK_EQUAL(info1->ToString(), \"250.1.2.1:9231\");\n\n    // Test 18; Find does not discriminate by port number.\n    CAddrInfo* info2 = addrman.Find(addr2);\n    BOOST_REQUIRE(info2);\n    BOOST_CHECK_EQUAL(info2->ToString(), info1->ToString());\n\n    // Test: Find returns another IP matching what we searched on.\n    CAddrInfo* info3 = addrman.Find(addr3);\n    BOOST_REQUIRE(info3);\n    BOOST_CHECK_EQUAL(info3->ToString(), \"251.255.2.1:9231\");\n}\n\nBOOST_AUTO_TEST_CASE(addrman_create)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(0));\n\n    CAddress addr1 = CAddress(ResolveService(\"250.1.2.1\", 9231), NODE_NONE);\n    CNetAddr source1 = ResolveIP(\"250.1.2.1\");\n\n    int nId;\n    CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId);\n\n    // Test: The result should be the same as the input addr.\n    BOOST_CHECK_EQUAL(pinfo->ToString(), \"250.1.2.1:9231\");\n\n    CAddrInfo* info2 = addrman.Find(addr1);\n    BOOST_CHECK_EQUAL(info2->ToString(), \"250.1.2.1:9231\");\n}\n\n\nBOOST_AUTO_TEST_CASE(addrman_delete)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(0));\n\n    CAddress addr1 = CAddress(ResolveService(\"250.1.2.1\", 9231), NODE_NONE);\n    CNetAddr source1 = ResolveIP(\"250.1.2.1\");\n\n    int nId;\n    addrman.Create(addr1, source1, &nId);\n\n    // Test: Delete should actually delete the addr.\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(1));\n    addrman.Delete(nId);\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(0));\n    CAddrInfo* info2 = addrman.Find(addr1);\n    BOOST_CHECK(info2 == NULL);\n}\n\nBOOST_AUTO_TEST_CASE(addrman_getaddr)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    // Test: Sanity check, GetAddr should never return anything if addrman\n    //  is empty.\n    BOOST_CHECK_EQUAL(addrman.size(), size_t(0));\n    std::vector<CAddress> vAddr1 = addrman.GetAddr();\n    BOOST_CHECK_EQUAL(vAddr1.size(), size_t(0));\n\n    CAddress addr1 = CAddress(ResolveService(\"250.250.2.1\", 9231), NODE_NONE);\n    addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false\n    CAddress addr2 = CAddress(ResolveService(\"250.251.2.2\", 9999), NODE_NONE);\n    addr2.nTime = GetAdjustedTime();\n    CAddress addr3 = CAddress(ResolveService(\"251.252.2.3\", 9231), NODE_NONE);\n    addr3.nTime = GetAdjustedTime();\n    CAddress addr4 = CAddress(ResolveService(\"252.253.3.4\", 9231), NODE_NONE);\n    addr4.nTime = GetAdjustedTime();\n    CAddress addr5 = CAddress(ResolveService(\"252.254.4.5\", 9231), NODE_NONE);\n    addr5.nTime = GetAdjustedTime();\n    CNetAddr source1 = ResolveIP(\"250.1.2.1\");\n    CNetAddr source2 = ResolveIP(\"250.2.3.3\");\n\n    // Test: Ensure GetAddr works with new addresses.\n    addrman.Add(addr1, source1);\n    addrman.Add(addr2, source2);\n    addrman.Add(addr3, source1);\n    addrman.Add(addr4, source2);\n    addrman.Add(addr5, source1);\n\n    // GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down.\n    BOOST_CHECK(addrman.GetAddr().size() == 1);\n\n    // Test: Ensure GetAddr works with new and tried addresses.\n    addrman.Good(CAddress(addr1, NODE_NONE));\n    addrman.Good(CAddress(addr2, NODE_NONE));\n    BOOST_CHECK(addrman.GetAddr().size() == 1);\n\n    // Test: Ensure GetAddr still returns 23% when addrman has many addrs.\n    for (unsigned int i = 1; i < (8 * 256); i++) {\n        int octet1 = i % 256;\n        int octet2 = i >> 8 % 256;\n        std::string strAddr = boost::to_string(octet1) + \".\" + boost::to_string(octet2) + \".1.23\";\n        CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);\n\n        // Ensure that for all addrs in addrman, isTerrible == false.\n        addr.nTime = GetAdjustedTime();\n        addrman.Add(addr, ResolveIP(strAddr));\n        if (i % 8 == 0)\n            addrman.Good(addr);\n    }\n    std::vector<CAddress> vAddr = addrman.GetAddr();\n\n    size_t percent23 = (addrman.size() * 23) / 100;\n    BOOST_CHECK_EQUAL(vAddr.size(), percent23);\n    BOOST_CHECK(vAddr.size() == 461);\n    // (Addrman.size() < number of addresses added) due to address collisions.\n    BOOST_CHECK(addrman.size() == 2006);\n}\n\n\nBOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CAddress addr1 = CAddress(ResolveService(\"250.1.1.1\", 9231), NODE_NONE);\n    CAddress addr2 = CAddress(ResolveService(\"250.1.1.1\", 9999), NODE_NONE);\n\n    CNetAddr source1 = ResolveIP(\"250.1.1.1\");\n\n\n    CAddrInfo info1 = CAddrInfo(addr1, source1);\n\n    uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();\n    uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();\n\n\n    BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1), 40);\n\n    // Test: Make sure key actually randomizes bucket placement. A fail on\n    //  this test could be a security issue.\n    BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2));\n\n    // Test: Two addresses with same IP but different ports can map to\n    //  different buckets because they have different keys.\n    CAddrInfo info2 = CAddrInfo(addr2, source1);\n\n    BOOST_CHECK(info1.GetKey() != info2.GetKey());\n    BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1));\n\n    std::set<int> buckets;\n    for (int i = 0; i < 255; i++) {\n        CAddrInfo infoi = CAddrInfo(\n            CAddress(ResolveService(\"250.1.1.\" + boost::to_string(i)), NODE_NONE),\n            ResolveIP(\"250.1.1.\" + boost::to_string(i)));\n        int bucket = infoi.GetTriedBucket(nKey1);\n        buckets.insert(bucket);\n    }\n    // Test: IP addresses in the same group (\\16 prefix for IPv4) should\n    //  never get more than 8 buckets\n    BOOST_CHECK(buckets.size() == 8);\n\n    buckets.clear();\n    for (int j = 0; j < 255; j++) {\n        CAddrInfo infoj = CAddrInfo(\n            CAddress(ResolveService(\"250.\" + boost::to_string(j) + \".1.1\"), NODE_NONE),\n            ResolveIP(\"250.\" + boost::to_string(j) + \".1.1\"));\n        int bucket = infoj.GetTriedBucket(nKey1);\n        buckets.insert(bucket);\n    }\n    // Test: IP addresses in the different groups should map to more than\n    //  8 buckets.\n    BOOST_CHECK(buckets.size() == 160);\n}\n\nBOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)\n{\n    CAddrManTest addrman;\n\n    // Set addrman addr placement to be deterministic.\n    addrman.MakeDeterministic();\n\n    CAddress addr1 = CAddress(ResolveService(\"250.1.2.1\", 9231), NODE_NONE);\n    CAddress addr2 = CAddress(ResolveService(\"250.1.2.1\", 9999), NODE_NONE);\n\n    CNetAddr source1 = ResolveIP(\"250.1.2.1\");\n\n    CAddrInfo info1 = CAddrInfo(addr1, source1);\n\n    uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();\n    uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();\n\n    // Test: Make sure the buckets are what we expect\n    BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), 786);\n    BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1), 786);\n\n    // Test: Make sure key actually randomizes bucket placement. A fail on\n    //  this test could be a security issue.\n    BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2));\n\n    // Test: Ports should not effect bucket placement in the addr\n    CAddrInfo info2 = CAddrInfo(addr2, source1);\n    BOOST_CHECK(info1.GetKey() != info2.GetKey());\n    BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), info2.GetNewBucket(nKey1));\n\n    std::set<int> buckets;\n    for (int i = 0; i < 255; i++) {\n        CAddrInfo infoi = CAddrInfo(\n            CAddress(ResolveService(\"250.1.1.\" + boost::to_string(i)), NODE_NONE),\n            ResolveIP(\"250.1.1.\" + boost::to_string(i)));\n        int bucket = infoi.GetNewBucket(nKey1);\n        buckets.insert(bucket);\n    }\n    // Test: IP addresses in the same group (\\16 prefix for IPv4) should\n    //  always map to the same bucket.\n    BOOST_CHECK(buckets.size() == 1);\n\n    buckets.clear();\n    for (int j = 0; j < 4 * 255; j++) {\n        CAddrInfo infoj = CAddrInfo(CAddress(\n                                        ResolveService(\n                                            boost::to_string(250 + (j / 255)) + \".\" + boost::to_string(j % 256) + \".1.1\"), NODE_NONE),\n            ResolveIP(\"251.4.1.1\"));\n        int bucket = infoj.GetNewBucket(nKey1);\n        buckets.insert(bucket);\n    }\n    // Test: IP addresses in the same source groups should map to no more\n    //  than 64 buckets.\n    BOOST_CHECK(buckets.size() <= 64);\n\n    buckets.clear();\n    for (int p = 0; p < 255; p++) {\n        CAddrInfo infoj = CAddrInfo(\n            CAddress(ResolveService(\"250.1.1.1\"), NODE_NONE),\n            ResolveIP(\"250.\" + boost::to_string(p) + \".1.1\"));\n        int bucket = infoj.GetNewBucket(nKey1);\n        buckets.insert(bucket);\n    }\n    // Test: IP addresses in the different source groups should map to more\n    //  than 64 buckets.\n    BOOST_CHECK(buckets.size() > 64);\n}\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/allocator_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util.h\"\n\n#include \"support/allocators/secure.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(arena_tests)\n{\n    // Fake memory base address for testing\n    // without actually using memory.\n    void *synth_base = reinterpret_cast<void*>(0x08000000);\n    const size_t synth_size = 1024*1024;\n    Arena b(synth_base, synth_size, 16);\n    void *chunk = b.alloc(1000);\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    BOOST_CHECK(chunk != nullptr);\n    BOOST_CHECK(b.stats().used == 1008); // Aligned to 16\n    BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?\n    b.free(chunk);\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    BOOST_CHECK(b.stats().used == 0);\n    BOOST_CHECK(b.stats().free == synth_size);\n    try { // Test exception on double-free\n        b.free(chunk);\n        BOOST_CHECK(0);\n    } catch(std::runtime_error &)\n    {\n    }\n\n    void *a0 = b.alloc(128);\n    void *a1 = b.alloc(256);\n    void *a2 = b.alloc(512);\n    BOOST_CHECK(b.stats().used == 896);\n    BOOST_CHECK(b.stats().total == synth_size);\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    b.free(a0);\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    BOOST_CHECK(b.stats().used == 768);\n    b.free(a1);\n    BOOST_CHECK(b.stats().used == 512);\n    void *a3 = b.alloc(128);\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    BOOST_CHECK(b.stats().used == 640);\n    b.free(a2);\n    BOOST_CHECK(b.stats().used == 128);\n    b.free(a3);\n    BOOST_CHECK(b.stats().used == 0);\n    BOOST_CHECK(b.stats().chunks_used == 0);\n    BOOST_CHECK(b.stats().total == synth_size);\n    BOOST_CHECK(b.stats().free == synth_size);\n    BOOST_CHECK_EQUAL(b.stats().chunks_free, 1U);\n\n    std::vector<void*> addr;\n    BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr\n#ifdef ARENA_DEBUG\n    b.walk();\n#endif\n    // Sweeping allocate all memory\n    for (int x=0; x<1024; ++x)\n        addr.push_back(b.alloc(1024));\n    BOOST_CHECK(b.stats().free == 0);\n    BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr\n    BOOST_CHECK(b.alloc(0) == nullptr);\n    for (int x=0; x<1024; ++x)\n        b.free(addr[x]);\n    addr.clear();\n    BOOST_CHECK(b.stats().total == synth_size);\n    BOOST_CHECK(b.stats().free == synth_size);\n\n    // Now in the other direction...\n    for (int x=0; x<1024; ++x)\n        addr.push_back(b.alloc(1024));\n    for (int x=0; x<1024; ++x)\n        b.free(addr[1023-x]);\n    addr.clear();\n\n    // Now allocate in smaller unequal chunks, then deallocate haphazardly\n    // Not all the chunks will succeed allocating, but freeing nullptr is\n    // allowed so that is no problem.\n    for (int x=0; x<2048; ++x)\n        addr.push_back(b.alloc(x+1));\n    for (int x=0; x<2048; ++x)\n        b.free(addr[((x*23)%2048)^242]);\n    addr.clear();\n\n    // Go entirely wild: free and alloc interleaved,\n    // generate targets and sizes using pseudo-randomness.\n    for (int x=0; x<2048; ++x)\n        addr.push_back(0);\n    uint32_t s = 0x12345678;\n    for (int x=0; x<5000; ++x) {\n        int idx = s & (addr.size()-1);\n        if (s & 0x80000000) {\n            b.free(addr[idx]);\n            addr[idx] = 0;\n        } else if(!addr[idx]) {\n            addr[idx] = b.alloc((s >> 16) & 2047);\n        }\n        bool lsb = s & 1;\n        s >>= 1;\n        if (lsb)\n            s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0\n    }\n    for (void *ptr: addr)\n        b.free(ptr);\n    addr.clear();\n\n    BOOST_CHECK(b.stats().total == synth_size);\n    BOOST_CHECK(b.stats().free == synth_size);\n}\n\n/** Mock LockedPageAllocator for testing */\nclass TestLockedPageAllocator: public LockedPageAllocator\n{\npublic:\n    TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}\n    void* AllocateLocked(size_t len, bool *lockingSuccess)\n    {\n        *lockingSuccess = false;\n        if (count > 0) {\n            --count;\n\n            if (lockedcount > 0) {\n                --lockedcount;\n                *lockingSuccess = true;\n            }\n\n            return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory\n        }\n        return 0;\n    }\n    void FreeLocked(void* addr, size_t len)\n    {\n    }\n    size_t GetLimit()\n    {\n        return std::numeric_limits<size_t>::max();\n    }\nprivate:\n    int count;\n    int lockedcount;\n};\n\nBOOST_AUTO_TEST_CASE(lockedpool_tests_mock)\n{\n    // Test over three virtual arenas, of which one will succeed being locked\n    std::unique_ptr<LockedPageAllocator> x(new TestLockedPageAllocator(3, 1));\n    LockedPool pool(std::move(x));\n    BOOST_CHECK(pool.stats().total == 0);\n    BOOST_CHECK(pool.stats().locked == 0);\n\n    // Ensure unreasonable requests are refused without allocating anything\n    void *invalid_toosmall = pool.alloc(0);\n    BOOST_CHECK(invalid_toosmall == nullptr);\n    BOOST_CHECK(pool.stats().used == 0);\n    BOOST_CHECK(pool.stats().free == 0);\n    void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);\n    BOOST_CHECK(invalid_toobig == nullptr);\n    BOOST_CHECK(pool.stats().used == 0);\n    BOOST_CHECK(pool.stats().free == 0);\n\n    void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a0);\n    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);\n    void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a1);\n    void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a2);\n    void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a3);\n    void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a4);\n    void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);\n    BOOST_CHECK(a5);\n    // We've passed a count of three arenas, so this allocation should fail\n    void *a6 = pool.alloc(16);\n    BOOST_CHECK(!a6);\n\n    pool.free(a0);\n    pool.free(a2);\n    pool.free(a4);\n    pool.free(a1);\n    pool.free(a3);\n    pool.free(a5);\n    BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);\n    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);\n    BOOST_CHECK(pool.stats().used == 0);\n}\n\n// These tests used the live LockedPoolManager object, this is also used\n// by other tests so the conditions are somewhat less controllable and thus the\n// tests are somewhat more error-prone.\nBOOST_AUTO_TEST_CASE(lockedpool_tests_live)\n{\n    LockedPoolManager &pool = LockedPoolManager::Instance();\n    LockedPool::Stats initial = pool.stats();\n\n    void *a0 = pool.alloc(16);\n    BOOST_CHECK(a0);\n    // Test reading and writing the allocated memory\n    *((uint32_t*)a0) = 0x1234;\n    BOOST_CHECK(*((uint32_t*)a0) == 0x1234);\n\n    pool.free(a0);\n    try { // Test exception on double-free\n        pool.free(a0);\n        BOOST_CHECK(0);\n    } catch(std::runtime_error &)\n    {\n    }\n    // If more than one new arena was allocated for the above tests, something is wrong\n    BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));\n    // Usage must be back to where it started\n    BOOST_CHECK(pool.stats().used == initial.used);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/amount_tests.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"amount.h\"\n#include \"policy/feerate.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(MoneyRangeTest)\n{\n    BOOST_CHECK_EQUAL(MoneyRange(CAmount(-1)), false);\n    BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY + CAmount(1)), false);\n    BOOST_CHECK_EQUAL(MoneyRange(CAmount(1)), true);\n}\n\nBOOST_AUTO_TEST_CASE(GetFeeTest)\n{\n    CFeeRate feeRate, altFeeRate;\n\n    feeRate = CFeeRate(0);\n    // Must always return 0\n    BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0);\n\n    feeRate = CFeeRate(1000);\n    // Must always just return the arg\n    BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3);\n\n    feeRate = CFeeRate(-1000);\n    // Must always just return -1 * arg\n    BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1), -1);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(121), -121);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(999), -999);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), -1e3);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), -9e3);\n\n    feeRate = CFeeRate(123);\n    // Truncates the result, if not integer\n    BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0\n    BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107);\n\n    feeRate = CFeeRate(-123);\n    // Truncates the result, if not integer\n    BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0\n    BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1);\n\n    // check alternate constructor\n    feeRate = CFeeRate(1000);\n    altFeeRate = CFeeRate(feeRate);\n    BOOST_CHECK_EQUAL(feeRate.GetFee(100), altFeeRate.GetFee(100));\n\n    // Check full constructor\n    // default value\n    BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));\n    BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0));\n    BOOST_CHECK(CFeeRate(CAmount(1), 1000) == CFeeRate(1));\n    // lost precision (can only resolve satoshis per kB)\n    BOOST_CHECK(CFeeRate(CAmount(1), 1001) == CFeeRate(0));\n    BOOST_CHECK(CFeeRate(CAmount(2), 1001) == CFeeRate(1));\n    // some more integer checks\n    BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32));\n    BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34));\n    // Maximum size in bytes, should not crash\n    CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();\n}\n\nBOOST_AUTO_TEST_CASE(BinaryOperatorTest)\n{\n    CFeeRate a, b;\n    a = CFeeRate(1);\n    b = CFeeRate(2);\n    BOOST_CHECK(a < b);\n    BOOST_CHECK(b > a);\n    BOOST_CHECK(a == a);\n    BOOST_CHECK(a <= b);\n    BOOST_CHECK(a <= a);\n    BOOST_CHECK(b >= a);\n    BOOST_CHECK(b >= b);\n    // a should be 0.00000002 NLG/kB now\n    a += a;\n    BOOST_CHECK(a == b);\n}\n\nBOOST_AUTO_TEST_CASE(ToStringTest)\n{\n    CFeeRate feeRate;\n    feeRate = CFeeRate(1);\n    BOOST_CHECK_EQUAL(feeRate.ToString(), \"0.00000001 \" GLOBAL_COIN_CODE \"/kB\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/arith_uint256_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <boost/test/unit_test.hpp>\n#include <stdint.h>\n#include <sstream>\n#include <iomanip>\n#include <limits>\n#include <cmath>\n#include \"uint256.h\"\n#include \"arith_uint256.h\"\n#include <string>\n#include \"version.h\"\n#include \"test/test.h\"\n\nBOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup)\n\n/// Convert vector to arith_uint256, via uint256 blob\ninline arith_uint256 arith_uint256V(const std::vector<unsigned char>& vch)\n{\n    return UintToArith256(uint256(vch));\n}\n\nconst unsigned char R1Array[] =\n    \"\\x9c\\x52\\x4a\\xdb\\xcf\\x56\\x11\\x12\\x2b\\x29\\x12\\x5e\\x5d\\x35\\xd2\\xd2\"\n    \"\\x22\\x81\\xaa\\xb5\\x33\\xf0\\x08\\x32\\xd5\\x56\\xb1\\xf9\\xea\\xe5\\x1d\\x7d\";\nconst char R1ArrayHex[] = \"7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c\";\nconst double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256\nconst arith_uint256 R1L = arith_uint256V(std::vector<unsigned char>(R1Array,R1Array+32));\nconst uint64_t R1LLow64 = 0x121156cfdb4a529cULL;\n\nconst unsigned char R2Array[] =\n    \"\\x70\\x32\\x1d\\x7c\\x47\\xa5\\x6b\\x40\\x26\\x7e\\x0a\\xc3\\xa6\\x9c\\xb6\\xbf\"\n    \"\\x13\\x30\\x47\\xa3\\x19\\x2d\\xda\\x71\\x49\\x13\\x72\\xf0\\xb4\\xca\\x81\\xd7\";\nconst arith_uint256 R2L = arith_uint256V(std::vector<unsigned char>(R2Array,R2Array+32));\n\nconst char R1LplusR2L[] = \"549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C\";\n\nconst unsigned char ZeroArray[] =\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";\nconst arith_uint256 ZeroL = arith_uint256V(std::vector<unsigned char>(ZeroArray,ZeroArray+32));\n\nconst unsigned char OneArray[] =\n    \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";\nconst arith_uint256 OneL = arith_uint256V(std::vector<unsigned char>(OneArray,OneArray+32));\n\nconst unsigned char MaxArray[] =\n    \"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\"\n    \"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\";\nconst arith_uint256 MaxL = arith_uint256V(std::vector<unsigned char>(MaxArray,MaxArray+32));\n\nconst arith_uint256 HalfL = (OneL << 255);\nstatic std::string ArrayToString(const unsigned char A[], unsigned int width)\n{\n    std::stringstream Stream;\n    Stream << std::hex;\n    for (unsigned int i = 0; i < width; ++i)\n    {\n        Stream<<std::setw(2)<<std::setfill('0')<<(unsigned int)A[width-i-1];\n    }\n    return Stream.str();\n}\n\nBOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality\n{\n    BOOST_CHECK(1 == 0+1);\n    // constructor arith_uint256(vector<char>):\n    BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32));\n    BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32));\n    BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32));\n    BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray,32));\n    BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray,32));\n    BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray,32));\n\n    // == and !=\n    BOOST_CHECK(R1L != R2L);\n    BOOST_CHECK(ZeroL != OneL);\n    BOOST_CHECK(OneL != ZeroL);\n    BOOST_CHECK(MaxL != ZeroL);\n    BOOST_CHECK(~MaxL == ZeroL);\n    BOOST_CHECK( ((R1L ^ R2L) ^ R1L) == R2L);\n\n    uint64_t Tmp64 = 0xc4dab720d9c7acaaULL;\n    for (unsigned int i = 0; i < 256; ++i)\n    {\n        BOOST_CHECK(ZeroL != (OneL << i));\n        BOOST_CHECK((OneL << i) != ZeroL);\n        BOOST_CHECK(R1L != (R1L ^ (OneL << i)));\n        BOOST_CHECK(((arith_uint256(Tmp64) ^ (OneL << i) ) != Tmp64 ));\n    }\n    BOOST_CHECK(ZeroL == (OneL << 256));\n\n    // String Constructor and Copy Constructor\n    BOOST_CHECK(arith_uint256(\"0x\"+R1L.ToString()) == R1L);\n    BOOST_CHECK(arith_uint256(\"0x\"+R2L.ToString()) == R2L);\n    BOOST_CHECK(arith_uint256(\"0x\"+ZeroL.ToString()) == ZeroL);\n    BOOST_CHECK(arith_uint256(\"0x\"+OneL.ToString()) == OneL);\n    BOOST_CHECK(arith_uint256(\"0x\"+MaxL.ToString()) == MaxL);\n    BOOST_CHECK(arith_uint256(R1L.ToString()) == R1L);\n    BOOST_CHECK(arith_uint256(\"   0x\"+R1L.ToString()+\"   \") == R1L);\n    BOOST_CHECK(arith_uint256(\"\") == ZeroL);\n    BOOST_CHECK(R1L == arith_uint256(R1ArrayHex));\n    BOOST_CHECK(arith_uint256(R1L) == R1L);\n    BOOST_CHECK((arith_uint256(R1L^R2L)^R2L) == R1L);\n    BOOST_CHECK(arith_uint256(ZeroL) == ZeroL);\n    BOOST_CHECK(arith_uint256(OneL) == OneL);\n\n    // uint64_t constructor\n    BOOST_CHECK( (R1L & arith_uint256(\"0xffffffffffffffff\")) == arith_uint256(R1LLow64));\n    BOOST_CHECK(ZeroL == arith_uint256(0));\n    BOOST_CHECK(OneL == arith_uint256(1));\n    BOOST_CHECK(arith_uint256(\"0xffffffffffffffff\") == arith_uint256(0xffffffffffffffffULL));\n\n    // Assignment (from base_uint)\n    arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL);\n    tmpL = ~OneL; BOOST_CHECK(tmpL == ~OneL);\n    tmpL = ~R1L; BOOST_CHECK(tmpL == ~R1L);\n    tmpL = ~R2L; BOOST_CHECK(tmpL == ~R2L);\n    tmpL = ~MaxL; BOOST_CHECK(tmpL == ~MaxL);\n}\n\nstatic void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift)\n{\n    for (unsigned int T=0; T < arrayLength; ++T)\n    {\n        unsigned int F = (T+bitsToShift/8);\n        if (F < arrayLength)\n            to[T]  = from[F] >> (bitsToShift%8);\n        else\n            to[T] = 0;\n        if (F + 1 < arrayLength)\n            to[T] |= from[(F+1)] << (8-bitsToShift%8);\n    }\n}\n\nstatic void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift)\n{\n    for (unsigned int T=0; T < arrayLength; ++T)\n    {\n        if (T >= bitsToShift/8)\n        {\n            unsigned int F = T-bitsToShift/8;\n            to[T]  = from[F] << (bitsToShift%8);\n            if (T >= bitsToShift/8+1)\n                to[T] |= from[F-1] >> (8-bitsToShift%8);\n        }\n        else {\n            to[T] = 0;\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE( shifts ) { // \"<<\"  \">>\"  \"<<=\"  \">>=\"\n    unsigned char TmpArray[32];\n    arith_uint256 TmpL;\n    for (unsigned int i = 0; i < 256; ++i)\n    {\n        shiftArrayLeft(TmpArray, OneArray, 32, i);\n        BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (OneL << i));\n        TmpL = OneL; TmpL <<= i;\n        BOOST_CHECK(TmpL == (OneL << i));\n        BOOST_CHECK((HalfL >> (255-i)) == (OneL << i));\n        TmpL = HalfL; TmpL >>= (255-i);\n        BOOST_CHECK(TmpL == (OneL << i));\n\n        shiftArrayLeft(TmpArray, R1Array, 32, i);\n        BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (R1L << i));\n        TmpL = R1L; TmpL <<= i;\n        BOOST_CHECK(TmpL == (R1L << i));\n\n        shiftArrayRight(TmpArray, R1Array, 32, i);\n        BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (R1L >> i));\n        TmpL = R1L; TmpL >>= i;\n        BOOST_CHECK(TmpL == (R1L >> i));\n\n        shiftArrayLeft(TmpArray, MaxArray, 32, i);\n        BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (MaxL << i));\n        TmpL = MaxL; TmpL <<= i;\n        BOOST_CHECK(TmpL == (MaxL << i));\n\n        shiftArrayRight(TmpArray, MaxArray, 32, i);\n        BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (MaxL >> i));\n        TmpL = MaxL; TmpL >>= i;\n        BOOST_CHECK(TmpL == (MaxL >> i));\n    }\n    arith_uint256 c1L = arith_uint256(0x0123456789abcdefULL);\n    arith_uint256 c2L = c1L << 128;\n    for (unsigned int i = 0; i < 128; ++i) {\n        BOOST_CHECK((c1L << i) == (c2L >> (128-i)));\n    }\n    for (unsigned int i = 128; i < 256; ++i) {\n        BOOST_CHECK((c1L << i) == (c2L << (i-128)));\n    }\n}\n\nBOOST_AUTO_TEST_CASE( unaryOperators ) // !    ~    -\n{\n    BOOST_CHECK(!ZeroL);\n    BOOST_CHECK(!(!OneL));\n    for (unsigned int i = 0; i < 256; ++i)\n        BOOST_CHECK(!(!(OneL<<i)));\n    BOOST_CHECK(!(!R1L));\n    BOOST_CHECK(!(!MaxL));\n\n    BOOST_CHECK(~ZeroL == MaxL);\n\n    unsigned char TmpArray[32];\n    for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = ~R1Array[i]; }\n    BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (~R1L));\n\n    BOOST_CHECK(-ZeroL == ZeroL);\n    BOOST_CHECK(-R1L == (~R1L)+1);\n    for (unsigned int i = 0; i < 256; ++i)\n        BOOST_CHECK(-(OneL<<i) == (MaxL << i));\n}\n\n\n// Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each\n// element of Aarray and Barray, and then converting the result into a arith_uint256.\n#define CHECKBITWISEOPERATOR(_A_,_B_,_OP_)                              \\\n    for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \\\n    BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L));\n\n#define CHECKASSIGNMENTOPERATOR(_A_,_B_,_OP_)                           \\\n    TmpL = _A_##L; TmpL _OP_##= _B_##L; BOOST_CHECK(TmpL == (_A_##L _OP_ _B_##L));\n\nBOOST_AUTO_TEST_CASE( bitwiseOperators )\n{\n    unsigned char TmpArray[32];\n\n    CHECKBITWISEOPERATOR(R1,R2,|)\n    CHECKBITWISEOPERATOR(R1,R2,^)\n    CHECKBITWISEOPERATOR(R1,R2,&)\n    CHECKBITWISEOPERATOR(R1,Zero,|)\n    CHECKBITWISEOPERATOR(R1,Zero,^)\n    CHECKBITWISEOPERATOR(R1,Zero,&)\n    CHECKBITWISEOPERATOR(R1,Max,|)\n    CHECKBITWISEOPERATOR(R1,Max,^)\n    CHECKBITWISEOPERATOR(R1,Max,&)\n    CHECKBITWISEOPERATOR(Zero,R1,|)\n    CHECKBITWISEOPERATOR(Zero,R1,^)\n    CHECKBITWISEOPERATOR(Zero,R1,&)\n    CHECKBITWISEOPERATOR(Max,R1,|)\n    CHECKBITWISEOPERATOR(Max,R1,^)\n    CHECKBITWISEOPERATOR(Max,R1,&)\n\n    arith_uint256 TmpL;\n    CHECKASSIGNMENTOPERATOR(R1,R2,|)\n    CHECKASSIGNMENTOPERATOR(R1,R2,^)\n    CHECKASSIGNMENTOPERATOR(R1,R2,&)\n    CHECKASSIGNMENTOPERATOR(R1,Zero,|)\n    CHECKASSIGNMENTOPERATOR(R1,Zero,^)\n    CHECKASSIGNMENTOPERATOR(R1,Zero,&)\n    CHECKASSIGNMENTOPERATOR(R1,Max,|)\n    CHECKASSIGNMENTOPERATOR(R1,Max,^)\n    CHECKASSIGNMENTOPERATOR(R1,Max,&)\n    CHECKASSIGNMENTOPERATOR(Zero,R1,|)\n    CHECKASSIGNMENTOPERATOR(Zero,R1,^)\n    CHECKASSIGNMENTOPERATOR(Zero,R1,&)\n    CHECKASSIGNMENTOPERATOR(Max,R1,|)\n    CHECKASSIGNMENTOPERATOR(Max,R1,^)\n    CHECKASSIGNMENTOPERATOR(Max,R1,&)\n\n    uint64_t Tmp64 = 0xe1db685c9a0b47a2ULL;\n    TmpL = R1L; TmpL |= Tmp64;  BOOST_CHECK(TmpL == (R1L | arith_uint256(Tmp64)));\n    TmpL = R1L; TmpL |= 0; BOOST_CHECK(TmpL == R1L);\n    TmpL ^= 0; BOOST_CHECK(TmpL == R1L);\n    TmpL ^= Tmp64;  BOOST_CHECK(TmpL == (R1L ^ arith_uint256(Tmp64)));\n}\n\nBOOST_AUTO_TEST_CASE( comparison ) // <= >= < >\n{\n    arith_uint256 TmpL;\n    for (unsigned int i = 0; i < 256; ++i) {\n        TmpL= OneL<< i;\n        BOOST_CHECK( TmpL >= ZeroL && TmpL > ZeroL && ZeroL < TmpL && ZeroL <= TmpL);\n        BOOST_CHECK( TmpL >= 0 && TmpL > 0 && 0 < TmpL && 0 <= TmpL);\n        TmpL |= R1L;\n        BOOST_CHECK( TmpL >= R1L ); BOOST_CHECK( (TmpL == R1L) != (TmpL > R1L)); BOOST_CHECK( (TmpL == R1L) || !( TmpL <= R1L));\n        BOOST_CHECK( R1L <= TmpL ); BOOST_CHECK( (R1L == TmpL) != (R1L < TmpL)); BOOST_CHECK( (TmpL == R1L) || !( R1L >= TmpL));\n        BOOST_CHECK(! (TmpL < R1L)); BOOST_CHECK(! (R1L > TmpL));\n    }\n}\n\nBOOST_AUTO_TEST_CASE( plusMinus )\n{\n    arith_uint256 TmpL = 0;\n    BOOST_CHECK(R1L+R2L == arith_uint256(R1LplusR2L));\n    TmpL += R1L;\n    BOOST_CHECK(TmpL == R1L);\n    TmpL += R2L;\n    BOOST_CHECK(TmpL == R1L + R2L);\n    BOOST_CHECK(OneL+MaxL == ZeroL);\n    BOOST_CHECK(MaxL+OneL == ZeroL);\n    for (unsigned int i = 1; i < 256; ++i) {\n        BOOST_CHECK( (MaxL >> i) + OneL == (HalfL >> (i-1)) );\n        BOOST_CHECK( OneL + (MaxL >> i) == (HalfL >> (i-1)) );\n        TmpL = (MaxL>>i); TmpL += OneL;\n        BOOST_CHECK( TmpL == (HalfL >> (i-1)) );\n        TmpL = (MaxL>>i); TmpL += 1;\n        BOOST_CHECK( TmpL == (HalfL >> (i-1)) );\n        TmpL = (MaxL>>i);\n        BOOST_CHECK( TmpL++ == (MaxL>>i) );\n        BOOST_CHECK( TmpL == (HalfL >> (i-1)));\n    }\n    BOOST_CHECK(arith_uint256(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL));\n    TmpL = arith_uint256(0xbedc77e27940a7ULL); TmpL += 0xee8d836fce66fbULL;\n    BOOST_CHECK(TmpL == arith_uint256(0xbedc77e27940a7ULL+0xee8d836fce66fbULL));\n    TmpL -= 0xee8d836fce66fbULL;  BOOST_CHECK(TmpL == 0xbedc77e27940a7ULL);\n    TmpL = R1L;\n    BOOST_CHECK(++TmpL == R1L+1);\n\n    BOOST_CHECK(R1L -(-R2L) == R1L+R2L);\n    BOOST_CHECK(R1L -(-OneL) == R1L+OneL);\n    BOOST_CHECK(R1L - OneL == R1L+(-OneL));\n    for (unsigned int i = 1; i < 256; ++i) {\n        BOOST_CHECK((MaxL>>i) - (-OneL)  == (HalfL >> (i-1)));\n        BOOST_CHECK((HalfL >> (i-1)) - OneL == (MaxL>>i));\n        TmpL = (HalfL >> (i-1));\n        BOOST_CHECK(TmpL-- == (HalfL >> (i-1)));\n        BOOST_CHECK(TmpL == (MaxL >> i));\n        TmpL = (HalfL >> (i-1));\n        BOOST_CHECK(--TmpL == (MaxL >> i));\n    }\n    TmpL = R1L;\n    BOOST_CHECK(--TmpL == R1L-1);\n}\n\nBOOST_AUTO_TEST_CASE( multiply )\n{\n    BOOST_CHECK((R1L * R1L).ToString() == \"62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10\");\n    BOOST_CHECK((R1L * R2L).ToString() == \"de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40\");\n    BOOST_CHECK((R1L * ZeroL) == ZeroL);\n    BOOST_CHECK((R1L * OneL) == R1L);\n    BOOST_CHECK((R1L * MaxL) == -R1L);\n    BOOST_CHECK((R2L * R1L) == (R1L * R2L));\n    BOOST_CHECK((R2L * R2L).ToString() == \"ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100\");\n    BOOST_CHECK((R2L * ZeroL) == ZeroL);\n    BOOST_CHECK((R2L * OneL) == R2L);\n    BOOST_CHECK((R2L * MaxL) == -R2L);\n\n    BOOST_CHECK(MaxL * MaxL == OneL);\n\n    BOOST_CHECK((R1L * 0) == 0);\n    BOOST_CHECK((R1L * 1) == R1L);\n    BOOST_CHECK((R1L * 3).ToString() == \"7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4\");\n    BOOST_CHECK((R2L * 0x87654321UL).ToString() == \"23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070\");\n}\n\nBOOST_AUTO_TEST_CASE( divide )\n{\n    arith_uint256 D1L(\"AD7133AC1977FA2B7\");\n    arith_uint256 D2L(\"ECD751716\");\n    BOOST_CHECK((R1L / D1L).ToString() == \"00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a\");\n    BOOST_CHECK((R1L / D2L).ToString() == \"000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a\");\n    BOOST_CHECK(R1L / OneL == R1L);\n    BOOST_CHECK(R1L / MaxL == ZeroL);\n    BOOST_CHECK(MaxL / R1L == 2);\n    BOOST_CHECK_THROW(R1L / ZeroL, uint_error);\n    BOOST_CHECK((R2L / D1L).ToString() == \"000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5\");\n    BOOST_CHECK((R2L / D2L).ToString() == \"000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4\");\n    BOOST_CHECK(R2L / OneL == R2L);\n    BOOST_CHECK(R2L / MaxL == ZeroL);\n    BOOST_CHECK(MaxL / R2L == 1);\n    BOOST_CHECK_THROW(R2L / ZeroL, uint_error);\n}\n\n\nstatic bool almostEqual(double d1, double d2)\n{\n    return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits<double>::epsilon();\n}\n\nBOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex size() GetLow64 GetSerializeSize, Serialize, Unserialize\n{\n    BOOST_CHECK(R1L.GetHex() == R1L.ToString());\n    BOOST_CHECK(R2L.GetHex() == R2L.ToString());\n    BOOST_CHECK(OneL.GetHex() == OneL.ToString());\n    BOOST_CHECK(MaxL.GetHex() == MaxL.ToString());\n    arith_uint256 TmpL(R1L);\n    BOOST_CHECK(TmpL == R1L);\n    TmpL.SetHex(R2L.ToString());   BOOST_CHECK(TmpL == R2L);\n    TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == 0);\n    TmpL.SetHex(HalfL.ToString()); BOOST_CHECK(TmpL == HalfL);\n\n    TmpL.SetHex(R1L.ToString());\n    BOOST_CHECK(R1L.size() == 32);\n    BOOST_CHECK(R2L.size() == 32);\n    BOOST_CHECK(ZeroL.size() == 32);\n    BOOST_CHECK(MaxL.size() == 32);\n    BOOST_CHECK(R1L.GetLow64()  == R1LLow64);\n    BOOST_CHECK(HalfL.GetLow64() ==0x0000000000000000ULL);\n    BOOST_CHECK(OneL.GetLow64() ==0x0000000000000001ULL);\n\n    for (unsigned int i = 0; i < 255; ++i)\n    {\n        BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0,i));\n    }\n    BOOST_CHECK(ZeroL.getdouble() == 0.0);\n    for (int i = 256; i > 53; --i)\n        BOOST_CHECK(almostEqual((R1L>>(256-i)).getdouble(), ldexp(R1Ldouble,i)));\n    uint64_t R1L64part = (R1L>>192).GetLow64();\n    for (int i = 53; i > 0; --i) // doubles can store all integers in {0,...,2^54-1} exactly\n    {\n        BOOST_CHECK((R1L>>(256-i)).getdouble() == (double)(R1L64part >> (64-i)));\n    }\n}\n\nBOOST_AUTO_TEST_CASE(bignum_SetCompact)\n{\n    arith_uint256 num;\n    bool fNegative;\n    bool fOverflow;\n    num.SetCompact(0, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x00123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x01003456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x02000056, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x03000000, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x04000000, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x00923456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x01803456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x02800056, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x03800000, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x04800000, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x01123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000000012\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    // Make sure that we don't generate compacts with the 0x00800000 bit set\n    num = 0x80;\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U);\n\n    num.SetCompact(0x01fedcba, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"000000000000000000000000000000000000000000000000000000000000007e\");\n    BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U);\n    BOOST_CHECK_EQUAL(fNegative, true);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x02123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000001234\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x03123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000000123456\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x04123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000012345600\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x04923456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000012345600\");\n    BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U);\n    BOOST_CHECK_EQUAL(fNegative, true);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x05009234, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"0000000000000000000000000000000000000000000000000000000092340000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0x20123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(num.GetHex(), \"1234560000000000000000000000000000000000000000000000000000000000\");\n    BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, false);\n\n    num.SetCompact(0xff123456, &fNegative, &fOverflow);\n    BOOST_CHECK_EQUAL(fNegative, false);\n    BOOST_CHECK_EQUAL(fOverflow, true);\n}\n\n\nBOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% coverage\n{\n    // ~R1L give a base_uint<256>\n    BOOST_CHECK((~~R1L >> 10) == (R1L >> 10));\n    BOOST_CHECK((~~R1L << 10) == (R1L << 10));\n    BOOST_CHECK(!(~~R1L < R1L));\n    BOOST_CHECK(~~R1L <= R1L);\n    BOOST_CHECK(!(~~R1L > R1L));\n    BOOST_CHECK(~~R1L >= R1L);\n    BOOST_CHECK(!(R1L < ~~R1L));\n    BOOST_CHECK(R1L <= ~~R1L);\n    BOOST_CHECK(!(R1L > ~~R1L));\n    BOOST_CHECK(R1L >= ~~R1L);\n\n    BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L);\n    BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L);\n    BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L);\n    unsigned char TmpArray[32];\n    CHECKBITWISEOPERATOR(~R1,R2,|)\n    CHECKBITWISEOPERATOR(~R1,R2,^)\n    CHECKBITWISEOPERATOR(~R1,R2,&)\n    CHECKBITWISEOPERATOR(R1,~R2,|)\n    CHECKBITWISEOPERATOR(R1,~R2,^)\n    CHECKBITWISEOPERATOR(R1,~R2,&)\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/base32_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(base32_testvectors)\n{\n    static const std::string vstrIn[]  = {\"\",\"f\",\"fo\",\"foo\",\"foob\",\"fooba\",\"foobar\"};\n    static const std::string vstrOut[] = {\"\",\"my======\",\"mzxq====\",\"mzxw6===\",\"mzxw6yq=\",\"mzxw6ytb\",\"mzxw6ytboi======\"};\n    for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)\n    {\n        std::string strEnc = EncodeBase32(vstrIn[i]);\n        BOOST_CHECK(strEnc == vstrOut[i]);\n        std::string strDec = DecodeBase32(vstrOut[i]);\n        BOOST_CHECK(strDec == vstrIn[i]);\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/base58_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"base58.h\"\n\n#include \"data/base58_encode_decode.json.h\"\n#include \"data/base58_keys_invalid.json.h\"\n#include \"data/base58_keys_valid.json.h\"\n\n#include \"key.h\"\n#include \"script/script.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\n#include <univalue.h>\n\nextern UniValue read_json(const std::string& jsondata);\n\nBOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)\n\n// Goal: test low-level base58 encoding functionality\nBOOST_AUTO_TEST_CASE(base58_EncodeBase58)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 2) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str());\n        std::string base58string = test[1].get_str();\n        BOOST_CHECK_MESSAGE(\n                    EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size()) == base58string,\n                    strTest);\n    }\n}\n\n// Goal: test low-level base58 decoding functionality\nBOOST_AUTO_TEST_CASE(base58_DecodeBase58)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));\n    std::vector<unsigned char> result;\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 2) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        std::vector<unsigned char> expected = ParseHex(test[0].get_str());\n        std::string base58string = test[1].get_str();\n        BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest);\n        BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest);\n    }\n\n    BOOST_CHECK(!DecodeBase58(\"invalid\", result));\n\n    // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.\n    BOOST_CHECK(!DecodeBase58(\" \\t\\n\\v\\f\\r skip \\r\\f\\v\\n\\t a\", result));\n    BOOST_CHECK( DecodeBase58(\" \\t\\n\\v\\f\\r skip \\r\\f\\v\\n\\t \", result));\n    std::vector<unsigned char> expected = ParseHex(\"971a55\");\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n}\n\n// Visitor to check address type\nclass TestAddrTypeVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    std::string exp_addrType;\npublic:\n    TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }\n    bool operator()(const CKeyID &id) const\n    {\n        return (exp_addrType == \"pubkey\");\n    }\n    bool operator()(const CScriptID &id) const\n    {\n        return (exp_addrType == \"script\");\n    }\n    bool operator()(const CPoW2WitnessDestination &id) const\n    {\n        //fixme: (PHASE5) (tests)\n        return false;\n    }\n    bool operator()(const CNoDestination &no) const\n    {\n        return (exp_addrType == \"none\");\n    }\n};\n\n// Visitor to check address payload\nclass TestPayloadVisitor : public boost::static_visitor<bool>\n{\nprivate:\n    std::vector<unsigned char> exp_payload;\npublic:\n    TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }\n    bool operator()(const CKeyID &id) const\n    {\n        uint160 exp_key(exp_payload);\n        return exp_key == id;\n    }\n    bool operator()(const CScriptID &id) const\n    {\n        uint160 exp_key(exp_payload);\n        return exp_key == id;\n    }\n    bool operator()(const CNoDestination &no) const\n    {\n        return exp_payload.size() == 0;\n    }\n};\n\n// Goal: check that parsed keys match test payload\nBOOST_AUTO_TEST_CASE(base58_keys_valid_parse)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));\n    CEncodedSecretKey secret;\n    CNativeAddress addr;\n    SelectParams(CBaseChainParams::MAIN);\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 3) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());\n        const UniValue &metadata = test[2].get_obj();\n        bool isPrivkey = find_value(metadata, \"isPrivkey\").get_bool();\n        bool isTestnet = find_value(metadata, \"isTestnet\").get_bool();\n        if (isTestnet)\n            SelectParams(CBaseChainParams::TESTNET);\n        else\n            SelectParams(CBaseChainParams::MAIN);\n        if(isPrivkey)\n        {\n            bool isCompressed = find_value(metadata, \"isCompressed\").get_bool();\n            // Must be valid private key\n            // Note: CEncodedSecretKey::SetString tests isValid, whereas CNativeAddress does not!\n            BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), \"!SetString:\"+ strTest);\n            BOOST_CHECK_MESSAGE(secret.IsValid(), \"!IsValid:\" + strTest);\n            CKey privkey = secret.GetKey();\n            BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, \"compressed mismatch:\" + strTest);\n            BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), \"key mismatch:\" + strTest);\n\n            // Private key must be invalid public key\n            addr.SetString(exp_base58string);\n            BOOST_CHECK_MESSAGE(!addr.IsValid(), \"IsValid privkey as pubkey:\" + strTest);\n        }\n        else\n        {\n            std::string exp_addrType = find_value(metadata, \"addrType\").get_str(); // \"script\" or \"pubkey\"\n            // Must be valid public key\n            BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), \"SetString:\" + strTest);\n            BOOST_CHECK_MESSAGE(addr.IsValid(), \"!IsValid:\" + strTest);\n            BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == \"script\"), \"isScript mismatch\" + strTest);\n            CTxDestination dest = addr.Get();\n            BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), \"addrType mismatch\" + strTest);\n\n            // Public key must be invalid private key\n            secret.SetString(exp_base58string);\n            BOOST_CHECK_MESSAGE(!secret.IsValid(), \"IsValid pubkey as privkey:\" + strTest);\n        }\n    }\n}\n\n// Goal: check that generated keys match test vectors\nBOOST_AUTO_TEST_CASE(base58_keys_valid_gen)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 3) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n        std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());\n        const UniValue &metadata = test[2].get_obj();\n        bool isPrivkey = find_value(metadata, \"isPrivkey\").get_bool();\n        bool isTestnet = find_value(metadata, \"isTestnet\").get_bool();\n        if (isTestnet)\n            SelectParams(CBaseChainParams::TESTNET);\n        else\n            SelectParams(CBaseChainParams::MAIN);\n        if(isPrivkey)\n        {\n            bool isCompressed = find_value(metadata, \"isCompressed\").get_bool();\n            CKey key;\n            key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);\n            assert(key.IsValid());\n            CEncodedSecretKey secret;\n            secret.SetKey(key);\n            BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, \"result mismatch: \" + strTest);\n        }\n        else\n        {\n            std::string exp_addrType = find_value(metadata, \"addrType\").get_str();\n            CTxDestination dest;\n            if(exp_addrType == \"pubkey\")\n            {\n                dest = CKeyID(uint160(exp_payload));\n            }\n            else if(exp_addrType == \"script\")\n            {\n                dest = CScriptID(uint160(exp_payload));\n            }\n            else if(exp_addrType == \"none\")\n            {\n                dest = CNoDestination();\n            }\n            else\n            {\n                BOOST_ERROR(\"Bad addrtype: \" << strTest);\n                continue;\n            }\n            CNativeAddress addrOut;\n            BOOST_CHECK_MESSAGE(addrOut.Set(dest), \"encode dest: \" + strTest);\n            BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, \"mismatch: \" + strTest);\n        }\n    }\n\n    // Visiting a CNoDestination must fail\n    CNativeAddress dummyAddr;\n    CTxDestination nodest = CNoDestination();\n    BOOST_CHECK(!dummyAddr.Set(nodest));\n\n    SelectParams(CBaseChainParams::MAIN);\n}\n\n// Goal: check that base58 parsing code is robust against a variety of corrupted data\nBOOST_AUTO_TEST_CASE(base58_keys_invalid)\n{\n    UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases\n    CEncodedSecretKey secret;\n    CNativeAddress addr;\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 1) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        std::string exp_base58string = test[0].get_str();\n\n        // must be invalid as public and as private key\n        addr.SetString(exp_base58string);\n        BOOST_CHECK_MESSAGE(!addr.IsValid(), \"IsValid pubkey:\" + strTest);\n        secret.SetString(exp_base58string);\n        BOOST_CHECK_MESSAGE(!secret.IsValid(), \"IsValid privkey:\" + strTest);\n    }\n}\n\n\nBOOST_AUTO_TEST_SUITE_END()\n\n"
  },
  {
    "path": "src/test/base64_tests.cpp",
    "content": "// Copyright (c) 2011-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(base64_testvectors)\n{\n    static const std::string vstrIn[]  = {\"\",\"f\",\"fo\",\"foo\",\"foob\",\"fooba\",\"foobar\"};\n    static const std::string vstrOut[] = {\"\",\"Zg==\",\"Zm8=\",\"Zm9v\",\"Zm9vYg==\",\"Zm9vYmE=\",\"Zm9vYmFy\"};\n    for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)\n    {\n        std::string strEnc = EncodeBase64(vstrIn[i]);\n        BOOST_CHECK(strEnc == vstrOut[i]);\n        std::string strDec = DecodeBase64(strEnc);\n        BOOST_CHECK(strDec == vstrIn[i]);\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/bip32_tests.cpp",
    "content": "// Copyright (c) 2013-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <boost/test/unit_test.hpp>\n\n#include \"base58.h\"\n#include \"key.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <string>\n#include <vector>\n\nstruct TestDerivation {\n    std::string pub;\n    std::string prv;\n    unsigned int nChild;\n};\n\nstruct TestVector {\n    std::string strHexMaster;\n    std::vector<TestDerivation> vDerive;\n\n    TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}\n\n    TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {\n        vDerive.push_back(TestDerivation());\n        TestDerivation &der = vDerive.back();\n        der.pub = pub;\n        der.prv = prv;\n        der.nChild = nChild;\n        return *this;\n    }\n};\n\nTestVector test1 =\n  TestVector(\"000102030405060708090a0b0c0d0e0f\")\n    (\"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\",\n     \"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi\",\n     0x80000000)\n    (\"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw\",\n     \"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7\",\n     1)\n    (\"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ\",\n     \"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs\",\n     0x80000002)\n    (\"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5\",\n     \"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM\",\n     2)\n    (\"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV\",\n     \"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334\",\n     1000000000)\n    (\"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy\",\n     \"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\",\n     0);\n\nTestVector test2 =\n  TestVector(\"fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542\")\n    (\"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB\",\n     \"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U\",\n     0)\n    (\"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH\",\n     \"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt\",\n     0xFFFFFFFF)\n    (\"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a\",\n     \"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9\",\n     1)\n    (\"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon\",\n     \"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef\",\n     0xFFFFFFFE)\n    (\"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL\",\n     \"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc\",\n     2)\n    (\"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt\",\n     \"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j\",\n     0);\n\nTestVector test3 =\n  TestVector(\"4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be\")\n    (\"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13\",\n     \"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6\",\n      0x80000000)\n    (\"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y\",\n     \"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L\",\n      0);\n\nstatic void RunTest(const TestVector &test) {\n    std::vector<unsigned char> seed = ParseHex(test.strHexMaster);\n    CExtKey key;\n    CExtPubKey pubkey;\n /*   key.SetMaster(&seed[0], seed.size());\n    pubkey = key.Neuter();\n    for(const TestDerivation &derive : test.vDerive) {\n        unsigned char data[74];\n        key.Encode(data);\n        pubkey.Encode(data);\n\n        // Test private key\n        CEncodedSecretExt b58key; b58key.SetKey(key);\n        BOOST_CHECK(b58key.ToString() == derive.prv);\n\n        CEncodedSecretExt b58keyDecodeCheck(derive.prv);\n        CExtKey checkKey = b58keyDecodeCheck.GetKey();\n        assert(checkKey == key); //ensure a base58 decoded key also matches\n\n        // Test public key\n        CEncodedSecretExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);\n        BOOST_CHECK(b58pubkey.ToString() == derive.pub);\n\n        CEncodedSecretExtPubKey b58PubkeyDecodeCheck(derive.pub);\n        CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();\n        assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches\n\n        // Derive new keys\n        CExtKey keyNew;\n        BOOST_CHECK(key.Derive(keyNew, derive.nChild));\n        CExtPubKey pubkeyNew = keyNew.Neuter();\n        if (!(derive.nChild & 0x80000000)) {\n            // Compare with public derivation\n            CExtPubKey pubkeyNew2;\n            BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild));\n            BOOST_CHECK(pubkeyNew == pubkeyNew2);\n        }\n        key = keyNew;\n        pubkey = pubkeyNew;\n\n        CDataStream ssPub(SER_DISK, CLIENT_VERSION);\n        ssPub << pubkeyNew;\n        BOOST_CHECK(ssPub.size() == 75);\n\n        CDataStream ssPriv(SER_DISK, CLIENT_VERSION);\n        ssPriv << keyNew;\n        BOOST_CHECK(ssPriv.size() == 75);\n\n        CExtPubKey pubCheck;\n        CExtKey privCheck;\n        ssPub >> pubCheck;\n        ssPriv >> privCheck;\n\n        BOOST_CHECK(pubCheck == pubkeyNew);\n        BOOST_CHECK(privCheck == keyNew);\n    }*/\n}\n\nBOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(bip32_test1) {\n    RunTest(test1);\n}\n\nBOOST_AUTO_TEST_CASE(bip32_test2) {\n    RunTest(test2);\n}\n\nBOOST_AUTO_TEST_CASE(bip32_test3) {\n    RunTest(test3);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/bip39_tests.cpp",
    "content": "// Copyright (c) 2013-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <boost/test/unit_test.hpp>\n\n#include \"base58.h\"\n#include \"key.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <string>\n#include <vector>\n\nstruct TestDerivation {\n    std::string pub;\n    std::string prv;\n    unsigned int nChild;\n};\n\nstruct TestVector {\n    std::string strHexMaster;\n    std::vector<TestDerivation> vDerive;\n\n    TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}\n\n    TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {\n        vDerive.push_back(TestDerivation());\n        TestDerivation &der = vDerive.back();\n        der.pub = pub;\n        der.prv = prv;\n        der.nChild = nChild;\n        return *this;\n    }\n};\n\nTestVector test1 =\n  TestVector(\"000102030405060708090a0b0c0d0e0f\")\n    (\"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\",\n     \"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi\",\n     0x80000000)\n    (\"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw\",\n     \"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7\",\n     1)\n    (\"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ\",\n     \"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs\",\n     0x80000002)\n    (\"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5\",\n     \"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM\",\n     2)\n    (\"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV\",\n     \"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334\",\n     1000000000)\n    (\"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy\",\n     \"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76\",\n     0);\n\nTestVector test2 =\n  TestVector(\"fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542\")\n    (\"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB\",\n     \"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U\",\n     0)\n    (\"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH\",\n     \"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt\",\n     0xFFFFFFFF)\n    (\"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a\",\n     \"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9\",\n     1)\n    (\"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon\",\n     \"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef\",\n     0xFFFFFFFE)\n    (\"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL\",\n     \"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc\",\n     2)\n    (\"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt\",\n     \"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j\",\n     0);\n\nvoid RunTest(const TestVector &test) {\n    std::vector<unsigned char> seed = ParseHex(test.strHexMaster);\n    CExtKey key;\n    CExtPubKey pubkey;\n    key.SetMaster(&seed[0], seed.size());\n    pubkey = key.Neuter();\n    for(const TestDerivation &derive : test.vDerive) {\n        unsigned char data[74];\n        key.Encode(data);\n        pubkey.Encode(data);\n\n        // Test private key\n        CEncodedSecretExt b58key; b58key.SetKey(key);\n        BOOST_CHECK(b58key.ToString() == derive.prv);\n\n        CEncodedSecretExt b58keyDecodeCheck(derive.prv);\n        CExtKey checkKey = b58keyDecodeCheck.GetKey();\n        assert(checkKey == key); //ensure a base58 decoded key also matches\n\n        // Test public key\n        CEncodedSecretExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);\n        BOOST_CHECK(b58pubkey.ToString() == derive.pub);\n\n        CEncodedSecretExtPubKey b58PubkeyDecodeCheck(derive.pub);\n        CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();\n        assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches\n\n        // Derive new keys\n        CExtKey keyNew;\n        BOOST_CHECK(key.Derive(keyNew, derive.nChild));\n        CExtPubKey pubkeyNew = keyNew.Neuter();\n        if (!(derive.nChild & 0x80000000)) {\n            // Compare with public derivation\n            CExtPubKey pubkeyNew2;\n            BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild));\n            BOOST_CHECK(pubkeyNew == pubkeyNew2);\n        }\n        key = keyNew;\n        pubkey = pubkeyNew;\n\n        CDataStream ssPub(SER_DISK, CLIENT_VERSION);\n        ssPub << pubkeyNew;\n        BOOST_CHECK(ssPub.size() == 75);\n\n        CDataStream ssPriv(SER_DISK, CLIENT_VERSION);\n        ssPriv << keyNew;\n        BOOST_CHECK(ssPriv.size() == 75);\n\n        CExtPubKey pubCheck;\n        CExtKey privCheck;\n        ssPub >> pubCheck;\n        ssPriv >> privCheck;\n\n        BOOST_CHECK(pubCheck == pubkeyNew);\n        BOOST_CHECK(privCheck == keyNew);\n    }\n}\n\nBOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(bip32_test1) {\n    RunTest(test1);\n}\n\nBOOST_AUTO_TEST_CASE(bip32_test2) {\n    RunTest(test2);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/blockencodings_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"blockencodings.h\"\n#include \"consensus/merkle.h\"\n#include \"chainparams.h\"\n#include \"random.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nstd::vector<std::pair<uint256, CTransactionRef>> extra_txn;\n\nstruct RegtestingSetup : public TestingSetup {\n    RegtestingSetup() : TestingSetup(CBaseChainParams::REGTESTLEGACY) {}\n};\n\nBOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegtestingSetup)\n\nstatic CBlock BuildBlockTestCase() {\n    CBlock block;\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    tx.vin.resize(1);\n    tx.vin[0].scriptSig.resize(10);\n    tx.vout.resize(1);\n    tx.vout[0].nValue = 42;\n\n    block.vtx.resize(3);\n    block.vtx[0] = MakeTransactionRef(tx);\n    block.nVersion = 42;\n    block.hashPrevBlock = InsecureRand256();\n    block.nBits = 0x207fffff;\n\n    COutPoint changePrevOut = tx.vin[0].GetPrevOut();\n    changePrevOut.setHash(InsecureRand256());\n    changePrevOut.n = 0;\n    tx.vin[0].SetPrevOut(changePrevOut);\n    block.vtx[1] = MakeTransactionRef(tx);\n\n    tx.vin.resize(10);\n    for (size_t i = 0; i < tx.vin.size(); i++) {\n        changePrevOut = tx.vin[i].GetPrevOut();\n        changePrevOut.setHash(InsecureRand256());\n        changePrevOut.n = 0;\n        tx.vin[i].SetPrevOut(changePrevOut);\n    }\n    block.vtx[2] = MakeTransactionRef(tx);\n\n    bool mutated;\n    block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);\n    assert(!mutated);\n    while (!CheckProofOfWork(&block, Params().GetConsensus())) ++block.nNonce;\n    return block;\n}\n\n// Number of shared use_counts we expect for a tx we havent touched\n// == 2 (mempool + our copy from the GetSharedTx call)\n#define SHARED_TX_OFFSET 2\n\nBOOST_AUTO_TEST_CASE(SimpleRoundTripTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n    CBlock block(BuildBlockTestCase());\n\n    pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));\n    BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);\n\n    // Do a simple ShortTxIDs RT\n    {\n        CBlockHeaderAndShortTxIDs shortIDs(block, true);\n\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << shortIDs;\n\n        CBlockHeaderAndShortTxIDs shortIDs2;\n        stream >> shortIDs2;\n\n        PartiallyDownloadedBlock partialBlock(&pool);\n        BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);\n        BOOST_CHECK( partialBlock.IsTxAvailable(0));\n        BOOST_CHECK(!partialBlock.IsTxAvailable(1));\n        BOOST_CHECK( partialBlock.IsTxAvailable(2));\n\n        BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);\n\n        size_t poolSize = pool.size();\n        pool.removeRecursive(*block.vtx[2]);\n        BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);\n\n        CBlock block2;\n        {\n            PartiallyDownloadedBlock tmp = partialBlock;\n            BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions\n            partialBlock = tmp;\n        }\n\n        // Wrong transaction\n        {\n            PartiallyDownloadedBlock tmp = partialBlock;\n            partialBlock.FillBlock(block2, {block.vtx[2]}); // Current implementation doesn't check txn here, but don't require that\n            partialBlock = tmp;\n        }\n        bool mutated;\n        BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));\n\n        CBlock block3;\n        BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}) == READ_STATUS_OK);\n        BOOST_CHECK_EQUAL(block.GetHashLegacy().ToString(), block3.GetHashLegacy().ToString());\n        BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());\n        BOOST_CHECK(!mutated);\n    }\n}\n\nclass TestHeaderAndShortIDs {\n    // Utility to encode custom CBlockHeaderAndShortTxIDs\npublic:\n    CBlockHeader header;\n    uint64_t nonce;\n    std::vector<uint64_t> shorttxids;\n    std::vector<PrefilledTransaction> prefilledtxn;\n\n    TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << orig;\n        stream >> *this;\n    }\n    TestHeaderAndShortIDs(const CBlock& block) :\n        TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}\n\n    uint64_t GetShortID(const uint256& txhash) const {\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << *this;\n        CBlockHeaderAndShortTxIDs base;\n        stream >> base;\n        return base.GetShortID(txhash);\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(header);\n        READWRITE(nonce);\n        size_t shorttxids_size = shorttxids.size();\n        READWRITE(VARINT(shorttxids_size));\n        shorttxids.resize(shorttxids_size);\n        for (size_t i = 0; i < shorttxids.size(); i++) {\n            uint32_t lsb = shorttxids[i] & 0xffffffff;\n            uint16_t msb = (shorttxids[i] >> 32) & 0xffff;\n            READWRITE(lsb);\n            READWRITE(msb);\n            shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb);\n        }\n        READWRITECOMPACTSIZEVECTOR(prefilledtxn);\n    }\n};\n\nBOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n    CBlock block(BuildBlockTestCase());\n\n    pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));\n    BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);\n\n    uint256 txhash;\n\n    // Test with pre-forwarding tx 1, but not coinbase\n    {\n        TestHeaderAndShortIDs shortIDs(block);\n        shortIDs.prefilledtxn.resize(1);\n        shortIDs.prefilledtxn[0] = {1, block.vtx[1]};\n        shortIDs.shorttxids.resize(2);\n        shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash());\n        shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash());\n\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << shortIDs;\n\n        CBlockHeaderAndShortTxIDs shortIDs2;\n        stream >> shortIDs2;\n\n        PartiallyDownloadedBlock partialBlock(&pool);\n        BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);\n        BOOST_CHECK(!partialBlock.IsTxAvailable(0));\n        BOOST_CHECK( partialBlock.IsTxAvailable(1));\n        BOOST_CHECK( partialBlock.IsTxAvailable(2));\n\n        BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);\n\n        CBlock block2;\n        {\n            PartiallyDownloadedBlock tmp = partialBlock;\n            BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); // No transactions\n            partialBlock = tmp;\n        }\n\n        // Wrong transaction\n        {\n            PartiallyDownloadedBlock tmp = partialBlock;\n            partialBlock.FillBlock(block2, {block.vtx[1]}); // Current implementation doesn't check txn here, but don't require that\n            partialBlock = tmp;\n        }\n        bool mutated;\n        BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));\n\n        CBlock block3;\n        PartiallyDownloadedBlock partialBlockCopy = partialBlock;\n        BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == READ_STATUS_OK);\n        BOOST_CHECK_EQUAL(block.GetHashLegacy().ToString(), block3.GetHashLegacy().ToString());\n        BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());\n        BOOST_CHECK(!mutated);\n\n        txhash = block.vtx[2]->GetHash();\n        block.vtx.clear();\n        block2.vtx.clear();\n        block3.vtx.clear();\n        BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.\n    }\n    BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);\n}\n\nBOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n    CBlock block(BuildBlockTestCase());\n\n    pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));\n    BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);\n\n    uint256 txhash;\n\n    // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool\n    {\n        TestHeaderAndShortIDs shortIDs(block);\n        shortIDs.prefilledtxn.resize(2);\n        shortIDs.prefilledtxn[0] = {0, block.vtx[0]};\n        shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1\n        shortIDs.shorttxids.resize(1);\n        shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash());\n\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << shortIDs;\n\n        CBlockHeaderAndShortTxIDs shortIDs2;\n        stream >> shortIDs2;\n\n        PartiallyDownloadedBlock partialBlock(&pool);\n        BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);\n        BOOST_CHECK( partialBlock.IsTxAvailable(0));\n        BOOST_CHECK( partialBlock.IsTxAvailable(1));\n        BOOST_CHECK( partialBlock.IsTxAvailable(2));\n\n        BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);\n\n        CBlock block2;\n        PartiallyDownloadedBlock partialBlockCopy = partialBlock;\n        BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK);\n        BOOST_CHECK_EQUAL(block.GetHashLegacy().ToString(), block2.GetHashLegacy().ToString());\n        bool mutated;\n        BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());\n        BOOST_CHECK(!mutated);\n\n        txhash = block.vtx[1]->GetHash();\n        block.vtx.clear();\n        block2.vtx.clear();\n        BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.\n    }\n    BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);\n}\n\nBOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)\n{\n    CTxMemPool pool;\n    CMutableTransaction coinbase(TEST_DEFAULT_TX_VERSION);\n    coinbase.vin.resize(1);\n    coinbase.vin[0].scriptSig.resize(10);\n    coinbase.vout.resize(1);\n    coinbase.vout[0].nValue = 42;\n\n    CBlock block;\n    block.vtx.resize(1);\n    block.vtx[0] = MakeTransactionRef(std::move(coinbase));\n    block.nVersion = 42;\n    block.hashPrevBlock = InsecureRand256();\n    block.nBits = 0x207fffff;\n\n    bool mutated;\n    block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);\n    assert(!mutated);\n    while (!CheckProofOfWork(&block, Params().GetConsensus())) ++block.nNonce;\n\n    // Test simple header round-trip with only coinbase\n    {\n        CBlockHeaderAndShortTxIDs shortIDs(block, false);\n\n        CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n        stream << shortIDs;\n\n        CBlockHeaderAndShortTxIDs shortIDs2;\n        stream >> shortIDs2;\n\n        PartiallyDownloadedBlock partialBlock(&pool);\n        BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);\n        BOOST_CHECK(partialBlock.IsTxAvailable(0));\n\n        CBlock block2;\n        std::vector<CTransactionRef> vtx_missing;\n        BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);\n        BOOST_CHECK_EQUAL(block.GetHashLegacy().ToString(), block2.GetHashLegacy().ToString());\n        BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());\n        BOOST_CHECK(!mutated);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {\n    BlockTransactionsRequest req1;\n    req1.blockhash = InsecureRand256();\n    req1.indexes.resize(4);\n    req1.indexes[0] = 0;\n    req1.indexes[1] = 1;\n    req1.indexes[2] = 3;\n    req1.indexes[3] = 4;\n\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << req1;\n\n    BlockTransactionsRequest req2;\n    stream >> req2;\n\n    BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString());\n    BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size());\n    BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]);\n    BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]);\n    BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]);\n    BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/bloom_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"bloom.h\"\n\n#include \"base58.h\"\n#include \"clientversion.h\"\n#include \"key.h\"\n#include \"merkleblock.h\"\n#include \"random.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(bloom_create_insert_serialize)\n{\n    CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL);\n\n    filter.insert(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\"));\n    BOOST_CHECK_MESSAGE( filter.contains(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter doesn't contain just-inserted object!\");\n    // One bit different in first byte\n    BOOST_CHECK_MESSAGE(!filter.contains(ParseHex(\"19108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter contains something it shouldn't!\");\n\n    filter.insert(ParseHex(\"b5a2c786d9ef4658287ced5914b37a1b4aa32eee\"));\n    BOOST_CHECK_MESSAGE(filter.contains(ParseHex(\"b5a2c786d9ef4658287ced5914b37a1b4aa32eee\")), \"Bloom filter doesn't contain just-inserted object (2)!\");\n\n    filter.insert(ParseHex(\"b9300670b4c5366e95b2699e8b18bc75e5f729c5\"));\n    BOOST_CHECK_MESSAGE(filter.contains(ParseHex(\"b9300670b4c5366e95b2699e8b18bc75e5f729c5\")), \"Bloom filter doesn't contain just-inserted object (3)!\");\n\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << filter;\n\n    std::vector<uint8_t> expected = ParseHex(\"03614e9b050000000000000001\");\n    auto result{MakeUCharSpan(stream)};\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n\n    BOOST_CHECK_MESSAGE( filter.contains(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter doesn't contain just-inserted object!\");\n    filter.clear();\n    BOOST_CHECK_MESSAGE( !filter.contains(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter should be empty!\");\n}\n\nBOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)\n{\n    // Same test as bloom_create_insert_serialize, but we add a nTweak of 100\n    CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL);\n\n    filter.insert(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\"));\n    BOOST_CHECK_MESSAGE( filter.contains(ParseHex(\"99108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter doesn't contain just-inserted object!\");\n    // One bit different in first byte\n    BOOST_CHECK_MESSAGE(!filter.contains(ParseHex(\"19108ad8ed9bb6274d3980bab5a85c048f0950c8\")), \"Bloom filter contains something it shouldn't!\");\n\n    filter.insert(ParseHex(\"b5a2c786d9ef4658287ced5914b37a1b4aa32eee\"));\n    BOOST_CHECK_MESSAGE(filter.contains(ParseHex(\"b5a2c786d9ef4658287ced5914b37a1b4aa32eee\")), \"Bloom filter doesn't contain just-inserted object (2)!\");\n\n    filter.insert(ParseHex(\"b9300670b4c5366e95b2699e8b18bc75e5f729c5\"));\n    BOOST_CHECK_MESSAGE(filter.contains(ParseHex(\"b9300670b4c5366e95b2699e8b18bc75e5f729c5\")), \"Bloom filter doesn't contain just-inserted object (3)!\");\n\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << filter;\n\n    std::vector<uint8_t> expected = ParseHex(\"03ce4299050000000100008001\");\n    auto result{MakeUCharSpan(stream)};\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n}\n\nBOOST_AUTO_TEST_CASE(bloom_create_insert_key)\n{\n    std::string strSecret = std::string(\"RamYVwk9M6328UURbNqGCPX3WeKKMUJzVPiZEXyomiWsgBaWgMkY\");\n    CEncodedSecretKey vchSecret;\n    BOOST_CHECK(vchSecret.SetString(strSecret));\n\n    CKey key = vchSecret.GetKey();\n    CPubKey pubkey = key.GetPubKey();\n    std::vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());\n\n    CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL);\n    filter.insert(vchPubKey);\n    uint160 hash = pubkey.GetID();\n    filter.insert(std::vector<unsigned char>(hash.begin(), hash.end()));\n\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << filter;\n\n    std::vector<unsigned char> expected =  ParseHex(\"03b9144f080000000000000001\");\n    auto result{MakeUCharSpan(stream)};\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n}\n\nstatic std::vector<unsigned char> RandomData()\n{\n    uint256 r = InsecureRand256();\n    return std::vector<unsigned char>(r.begin(), r.end());\n}\n\nBOOST_AUTO_TEST_CASE(rolling_bloom)\n{\n    // last-100-entry, 1% false positive:\n    CRollingBloomFilter rb1(100, 0.01);\n\n    // Overfill:\n    static const int DATASIZE=399;\n    std::vector<unsigned char> data[DATASIZE];\n    for (int i = 0; i < DATASIZE; i++) {\n        data[i] = RandomData();\n        rb1.insert(data[i]);\n    }\n    // Last 100 guaranteed to be remembered:\n    for (int i = 299; i < DATASIZE; i++) {\n        BOOST_CHECK(rb1.contains(data[i]));\n    }\n\n    // false positive rate is 1%, so we should get about 100 hits if\n    // testing 10,000 random keys. We get worst-case false positive\n    // behavior when the filter is as full as possible, which is\n    // when we've inserted one minus an integer multiple of nElement*2.\n    unsigned int nHits = 0;\n    for (int i = 0; i < 10000; i++) {\n        if (rb1.contains(RandomData()))\n            ++nHits;\n    }\n    // Run test_munt with --log_level=message to see BOOST_TEST_MESSAGEs:\n    BOOST_TEST_MESSAGE(\"RollingBloomFilter got \" << nHits << \" false positives (~100 expected)\");\n\n    // Insanely unlikely to get a fp count outside this range:\n    BOOST_CHECK(nHits > 25);\n    BOOST_CHECK(nHits < 175);\n\n    BOOST_CHECK(rb1.contains(data[DATASIZE-1]));\n    rb1.reset();\n    BOOST_CHECK(!rb1.contains(data[DATASIZE-1]));\n\n    // Now roll through data, make sure last 100 entries\n    // are always remembered:\n    for (int i = 0; i < DATASIZE; i++) {\n        if (i >= 100)\n            BOOST_CHECK(rb1.contains(data[i-100]));\n        rb1.insert(data[i]);\n        BOOST_CHECK(rb1.contains(data[i]));\n    }\n\n    // Insert 999 more random entries:\n    for (int i = 0; i < 999; i++) {\n        std::vector<unsigned char> d = RandomData();\n        rb1.insert(d);\n        BOOST_CHECK(rb1.contains(d));\n    }\n    // Sanity check to make sure the filter isn't just filling up:\n    nHits = 0;\n    for (int i = 0; i < DATASIZE; i++) {\n        if (rb1.contains(data[i]))\n            ++nHits;\n    }\n    // Expect about 5 false positives, more than 100 means\n    // something is definitely broken.\n    BOOST_TEST_MESSAGE(\"RollingBloomFilter got \" << nHits << \" false positives (~5 expected)\");\n    BOOST_CHECK(nHits < 100);\n\n    // last-1000-entry, 0.01% false positive:\n    CRollingBloomFilter rb2(1000, 0.001);\n    for (int i = 0; i < DATASIZE; i++) {\n        rb2.insert(data[i]);\n    }\n    // ... room for all of them:\n    for (int i = 0; i < DATASIZE; i++) {\n        BOOST_CHECK(rb2.contains(data[i]));\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/bswap_tests.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"compat/byteswap.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(bswap_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(bswap_tests)\n{\n\t// Sibling in Munt/src/qt/test/compattests.cpp\n\tuint16_t u1 = 0x1234;\n\tuint32_t u2 = 0x56789abc;\n\tuint64_t u3 = 0xdef0123456789abc;\n\tuint16_t e1 = 0x3412;\n\tuint32_t e2 = 0xbc9a7856;\n\tuint64_t e3 = 0xbc9a78563412f0de;\n\tBOOST_CHECK(bswap_16(u1) == e1);\n\tBOOST_CHECK(bswap_32(u2) == e2);\n\tBOOST_CHECK(bswap_64(u3) == e3);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/checkqueue_tests.cpp",
    "content": "// Copyright (c) 2012-2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util.h\"\n#include \"util/time.h\"\n#include \"validation/validation.h\"\n\n#include \"test/test.h\"\n#include \"checkqueue.h\"\n#include <boost/test/unit_test.hpp>\n#include <boost/thread.hpp>\n#include <atomic>\n#include <thread>\n#include <vector>\n#include <mutex>\n#include <condition_variable>\n\n#include <unordered_set>\n#include <memory>\n#include \"random.h\"\n\n// BasicTestingSetup not sufficient because nScriptCheckThreads is not set\n// otherwise.\nBOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup)\n\nstatic const int QUEUE_BATCH_SIZE = 128;\n\nstruct FakeCheck {\n    bool operator()()\n    {\n        return true;\n    }\n    void swap([[maybe_unused]] FakeCheck& x){};\n};\n\nstruct FakeCheckCheckCompletion {\n    static std::atomic<size_t> n_calls;\n    bool operator()()\n    {\n        ++n_calls;\n        return true;\n    }\n    void swap([[maybe_unused]] FakeCheckCheckCompletion& x){};\n};\n\nstruct FailingCheck {\n    bool fails;\n    FailingCheck(bool _fails) : fails(_fails){};\n    FailingCheck() : fails(true){};\n    bool operator()()\n    {\n        return !fails;\n    }\n    void swap(FailingCheck& x)\n    {\n        std::swap(fails, x.fails);\n    };\n};\n\nstruct UniqueCheck {\n    static Mutex m;\n    static std::unordered_multiset<size_t> results GUARDED_BY(m);\n    size_t check_id;\n    UniqueCheck(size_t check_id_in) : check_id(check_id_in){};\n    UniqueCheck() : check_id(0){};\n    bool operator()()\n    {\n        LOCK(m);\n        results.insert(check_id);\n        return true;\n    }\n    void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); };\n};\n\n\nstruct MemoryCheck {\n    static std::atomic<size_t> fake_allocated_memory;\n    bool b {false};\n    bool operator()() const\n    {\n        return true;\n    }\n    MemoryCheck(){};\n    MemoryCheck(const MemoryCheck& x)\n    {\n        // We have to do this to make sure that destructor calls are paired\n        //\n        // Really, copy constructor should be deletable, but CCheckQueue breaks\n        // if it is deleted because of internal push_back.\n        fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);\n    };\n    MemoryCheck(bool b_) : b(b_)\n    {\n        fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);\n    };\n    ~MemoryCheck()\n    {\n        fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);\n    };\n    void swap(MemoryCheck& x) { std::swap(b, x.b); };\n};\n\nstruct FrozenCleanupCheck {\n    static std::atomic<uint64_t> nFrozen;\n    static std::condition_variable cv;\n    static std::mutex m;\n    // Freezing can't be the default initialized behavior given how the queue\n    // swaps in default initialized Checks.\n    bool should_freeze {false};\n    bool operator()() const\n    {\n        return true;\n    }\n    FrozenCleanupCheck() {}\n    ~FrozenCleanupCheck()\n    {\n        if (should_freeze) {\n            std::unique_lock<std::mutex> l(m);\n            nFrozen.store(1, std::memory_order_relaxed);\n            cv.notify_one();\n            cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});\n        }\n    }\n    void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};\n};\n\n// Static Allocations\nstd::mutex FrozenCleanupCheck::m{};\nstd::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0};\nstd::condition_variable FrozenCleanupCheck::cv{};\nMutex UniqueCheck::m;\nstd::unordered_multiset<size_t> UniqueCheck::results;\nstd::atomic<size_t> FakeCheckCheckCompletion::n_calls{0};\nstd::atomic<size_t> MemoryCheck::fake_allocated_memory{0};\n\n// Queue Typedefs\ntypedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue;\ntypedef CCheckQueue<FakeCheck> Standard_Queue;\ntypedef CCheckQueue<FailingCheck> Failing_Queue;\ntypedef CCheckQueue<UniqueCheck> Unique_Queue;\ntypedef CCheckQueue<MemoryCheck> Memory_Queue;\ntypedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;\n\n\n/** This test case checks that the CCheckQueue works properly\n * with each specified size_t Checks pushed.\n */\nvoid Correct_Queue_range(std::vector<size_t> range)\n{\n    auto small_queue = std::make_unique<Correct_Queue>(QUEUE_BATCH_SIZE);\n    small_queue->StartWorkerThreads(nScriptCheckThreads);\n    // Make vChecks here to save on malloc (this test can be slow...)\n    std::vector<FakeCheckCheckCompletion> vChecks;\n    for (const size_t i : range) {\n        size_t total = i;\n        FakeCheckCheckCompletion::n_calls = 0;\n        CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());\n        while (total) {\n            vChecks.resize(std::min(total, (size_t) InsecureRandRange(10)));\n            total -= vChecks.size();\n            control.Add(vChecks);\n        }\n        BOOST_REQUIRE(control.Wait());\n        if (FakeCheckCheckCompletion::n_calls != i) {\n            BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);\n        }\n    }\n    small_queue->StopWorkerThreads();\n}\n\n/** Test that 0 checks is correct\n */\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)\n{\n    std::vector<size_t> range;\n    range.push_back((size_t)0);\n    Correct_Queue_range(range);\n}\n/** Test that 1 check is correct\n */\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)\n{\n    std::vector<size_t> range;\n    range.push_back((size_t)1);\n    Correct_Queue_range(range);\n}\n/** Test that MAX check is correct\n */\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max)\n{\n    std::vector<size_t> range;\n    range.push_back(100000);\n    Correct_Queue_range(range);\n}\n/** Test that random numbers of checks are correct\n */\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)\n{\n    std::vector<size_t> range;\n    range.reserve(100000/1000);\n    for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)InsecureRandRange(std::min((size_t)1000, ((size_t)100000) - i))))\n        range.push_back(i);\n    Correct_Queue_range(range);\n}\n\n\n/** Test that failing checks are caught */\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)\n{\n    auto fail_queue = std::make_unique<Failing_Queue>(QUEUE_BATCH_SIZE);\n    fail_queue->StartWorkerThreads(nScriptCheckThreads);\n\n    for (size_t i = 0; i < 1001; ++i) {\n        CCheckQueueControl<FailingCheck> control(fail_queue.get());\n        size_t remaining = i;\n        while (remaining) {\n            size_t r = InsecureRandRange(10);\n\n            std::vector<FailingCheck> vChecks;\n            vChecks.reserve(r);\n            for (size_t k = 0; k < r && remaining; k++, remaining--)\n                vChecks.emplace_back(remaining == 1);\n            control.Add(vChecks);\n        }\n        bool success = control.Wait();\n        if (i > 0) {\n            BOOST_REQUIRE(!success);\n        } else if (i == 0) {\n            BOOST_REQUIRE(success);\n        }\n    }\n    fail_queue->StopWorkerThreads();\n}\n// Test that a block validation which fails does not interfere with\n// future blocks, ie, the bad state is cleared.\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)\n{\n    auto fail_queue = std::make_unique<Failing_Queue>(QUEUE_BATCH_SIZE);\n    fail_queue->StartWorkerThreads(nScriptCheckThreads);\n\n    for (auto times = 0; times < 10; ++times) {\n        for (const bool end_fails : {true, false}) {\n            CCheckQueueControl<FailingCheck> control(fail_queue.get());\n            {\n                std::vector<FailingCheck> vChecks;\n                vChecks.resize(100, false);\n                vChecks[99] = end_fails;\n                control.Add(vChecks);\n            }\n            bool r =control.Wait();\n            BOOST_REQUIRE(r != end_fails);\n        }\n    }\n    fail_queue->StopWorkerThreads();\n}\n\n// Test that unique checks are actually all called individually, rather than\n// just one check being called repeatedly. Test that checks are not called\n// more than once as well\nBOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)\n{\n    auto queue = std::make_unique<Unique_Queue>(QUEUE_BATCH_SIZE);\n    queue->StartWorkerThreads(nScriptCheckThreads);\n\n    size_t COUNT = 100000;\n    size_t total = COUNT;\n    {\n        CCheckQueueControl<UniqueCheck> control(queue.get());\n        while (total) {\n            size_t r = InsecureRandRange(10);\n            std::vector<UniqueCheck> vChecks;\n            for (size_t k = 0; k < r && total; k++)\n                vChecks.emplace_back(--total);\n            control.Add(vChecks);\n        }\n    }\n    {\n        LOCK(UniqueCheck::m);\n        bool r = true;\n        BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT);\n        for (size_t i = 0; i < COUNT; ++i) {\n            r = r && UniqueCheck::results.count(i) == 1;\n        }\n        BOOST_REQUIRE(r);\n    }\n    queue->StopWorkerThreads();\n}\n\n\n// Test that blocks which might allocate lots of memory free their memory aggressively.\n//\n// This test attempts to catch a pathological case where by lazily freeing\n// checks might mean leaving a check un-swapped out, and decreasing by 1 each\n// time could leave the data hanging across a sequence of blocks.\nBOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)\n{\n    auto queue = std::make_unique<Memory_Queue>(QUEUE_BATCH_SIZE);\n    queue->StartWorkerThreads(nScriptCheckThreads);\n    for (size_t i = 0; i < 1000; ++i) {\n        size_t total = i;\n        {\n            CCheckQueueControl<MemoryCheck> control(queue.get());\n            while (total) {\n                size_t r = InsecureRandRange(10);\n                std::vector<MemoryCheck> vChecks;\n                for (size_t k = 0; k < r && total; k++) {\n                    total--;\n                    // Each iteration leaves data at the front, back, and middle\n                    // to catch any sort of deallocation failure\n                    vChecks.emplace_back(total == 0 || total == i || total == i/2);\n                }\n                control.Add(vChecks);\n            }\n        }\n        BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U);\n    }\n    queue->StopWorkerThreads();\n}\n\n// Test that a new verification cannot occur until all checks\n// have been destructed\nBOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)\n{\n    auto queue = std::make_unique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE);\n    bool fails = false;\n    queue->StartWorkerThreads(nScriptCheckThreads);\n    std::thread t0([&]() {\n        CCheckQueueControl<FrozenCleanupCheck> control(queue.get());\n        std::vector<FrozenCleanupCheck> vChecks(1);\n        // Freezing can't be the default initialized behavior given how the queue\n        // swaps in default initialized Checks (otherwise freezing destructor\n        // would get called twice).\n        vChecks[0].should_freeze = true;\n        control.Add(vChecks);\n        bool waitResult = control.Wait(); // Hangs here\n        assert(waitResult);\n    });\n    {\n        std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);\n        // Wait until the queue has finished all jobs and frozen\n        FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});\n    }\n    // Try to get control of the queue a bunch of times\n    for (auto x = 0; x < 100 && !fails; ++x) {\n        fails = queue->m_control_mutex.try_lock();\n    }\n    {\n        // Unfreeze (we need lock n case of spurious wakeup)\n        std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);\n        FrozenCleanupCheck::nFrozen = 0;\n    }\n    // Awaken frozen destructor\n    FrozenCleanupCheck::cv.notify_one();\n    // Wait for control to finish\n    t0.join();\n    BOOST_REQUIRE(!fails);\n    queue->StopWorkerThreads();\n}\n\n\n/** Test that CCheckQueueControl is threadsafe */\nBOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)\n{\n    auto queue = std::make_unique<Standard_Queue>(QUEUE_BATCH_SIZE);\n    {\n        std::vector<std::thread> tg;\n        std::atomic<int> nThreads {0};\n        std::atomic<int> fails {0};\n        for (size_t i = 0; i < 3; ++i) {\n            tg.emplace_back(\n                    [&]{\n                    CCheckQueueControl<FakeCheck> control(queue.get());\n                    // While sleeping, no other thread should execute to this point\n                    auto observed = ++nThreads;\n                    UninterruptibleSleep(std::chrono::milliseconds{10});\n                    fails += observed  != nThreads;\n                    });\n        }\n        for (auto& thread: tg) {\n            if (thread.joinable()) thread.join();\n        }\n        BOOST_REQUIRE_EQUAL(fails, 0);\n    }\n    {\n        std::vector<std::thread> tg;\n        std::mutex m;\n        std::condition_variable cv;\n        bool has_lock{false};\n        bool has_tried{false};\n        bool done{false};\n        bool done_ack{false};\n        {\n            std::unique_lock<std::mutex> l(m);\n            tg.emplace_back([&]{\n                    CCheckQueueControl<FakeCheck> control(queue.get());\n                    std::unique_lock<std::mutex> ll(m);\n                    has_lock = true;\n                    cv.notify_one();\n                    cv.wait(ll, [&]{return has_tried;});\n                    done = true;\n                    cv.notify_one();\n                    // Wait until the done is acknowledged\n                    //\n                    cv.wait(ll, [&]{return done_ack;});\n                    });\n            // Wait for thread to get the lock\n            cv.wait(l, [&](){return has_lock;});\n            bool fails = false;\n            for (auto x = 0; x < 100 && !fails; ++x) {\n                fails = queue->m_control_mutex.try_lock();\n            }\n            has_tried = true;\n            cv.notify_one();\n            cv.wait(l, [&](){return done;});\n            // Acknowledge the done\n            done_ack = true;\n            cv.notify_one();\n            BOOST_REQUIRE(!fails);\n        }\n        for (auto& thread: tg) {\n            if (thread.joinable()) thread.join();\n        }\n    }\n}\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/coins_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"coins.h\"\n#include \"script/standard.h\"\n#include \"uint256.h\"\n#include \"undo.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n#include \"validation/validation.h\"\n#include \"consensus/validation.h\"\n\n#include <vector>\n#include <map>\n\n#include <boost/test/unit_test.hpp>\n\nint ApplyTxInUndo(CoinUndo&& undo, CCoinsViewCache& view, COutPoint out);\nvoid UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, uint32_t nHeight, uint32_t nTxIndex);\n\n//fixme: (PHASE5) Add additional tests for new segsig related coin features.\n\ntemplate <typename T>\nT& operator<<(T& os, const COutPoint& op)\n{\n    os << op.ToString();\n    return os;\n}\n\nnamespace\n{\n//! equality test\nbool operator==(const Coin &a, const Coin &b) {\n    // Empty Coin objects are always equal.\n    if (a.IsSpent() && b.IsSpent()) return true;\n    return a.fCoinBase == b.fCoinBase &&\n           a.nHeight == b.nHeight &&\n           a.out == b.out;\n}\n\nclass CCoinsViewTest : public CCoinsView\n{\n    uint256 hashBestBlock_;\n    std::map<COutPoint, Coin> map_;\n\npublic:\n    bool GetCoin(const COutPoint& outpoint, Coin& coin, COutPoint* pOutpointRet=nullptr) const override\n    {\n        std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);\n        if (it == map_.end()) {\n            return false;\n        }\n        coin = it->second;\n        if (coin.IsSpent() && InsecureRandBool() == 0) {\n            // Randomly return false in case of an empty entry.\n            return false;\n        }\n        return true;\n    }\n\n    bool HaveCoin(const COutPoint& outpoint) const override\n    {\n        Coin coin;\n        return GetCoin(outpoint, coin);\n    }\n\n    uint256 GetBestBlock() const override { return hashBestBlock_; }\n\n    bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) override\n    {\n        for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {\n            if (it->second.flags & CCoinsCacheEntry::DIRTY) {\n                // Same optimization used in CCoinsViewDB is to only write dirty entries.\n                map_[it->first] = it->second.coin;\n                if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) {\n                    // Randomly delete empty entries on write.\n                    map_.erase(it->first);\n                }\n            }\n            mapCoins.erase(it++);\n        }\n        if (!hashBlock.IsNull())\n            hashBestBlock_ = hashBlock;\n        return true;\n    }\n};\n\nclass CCoinsViewCacheTest : public CCoinsViewCache\n{\npublic:\n    CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}\n\n    void SelfTest() const\n    {\n        // Manually recompute the dynamic usage of the whole data, and compare it.\n        size_t ret = memusage::DynamicUsage(cacheCoins);\n        size_t count = 0;\n        for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {\n            ret += it->second.coin.DynamicMemoryUsage();\n            ++count;\n        }\n        BOOST_CHECK_EQUAL(GetCacheSize(), count);\n        BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);\n    }\n\n    CCoinsMap& map() { return cacheCoins; }\n    CCoinsRefMap& refmap() { return cacheCoinRefs; }\n    size_t& usage() { return cachedCoinsUsage; }\n};\n\n}\n\nBOOST_FIXTURE_TEST_SUITE(coins_tests, TestingSetup)\n\nstatic const unsigned int NUM_SIMULATION_ITERATIONS = 40000;\n\n// This is a large randomized insert/remove simulation test on a variable-size\n// stack of caches on top of CCoinsViewTest.\n//\n// It will randomly create/update/delete Coin entries to a tip of caches, with\n// txids picked from a limited list of random 256-bit hashes. Occasionally, a\n// new tip is added to the stack of caches, or the tip is flushed and removed.\n//\n// During the process, booleans are kept to make sure that the randomized\n// operation hits all branches.\nBOOST_AUTO_TEST_CASE(coins_cache_simulation_test)\n{\n    // Various coverage trackers.\n    bool removed_all_caches = false;\n    bool reached_4_caches = false;\n    bool added_an_entry = false;\n    bool added_an_unspendable_entry = false;\n    bool removed_an_entry = false;\n    bool updated_an_entry = false;\n    bool found_an_entry = false;\n    bool missed_an_entry = false;\n    bool uncached_an_entry = false;\n\n    // A simple map to track what we expect the cache stack to represent.\n    std::map<COutPoint, Coin> result;\n\n    // The cache stack.\n    CCoinsViewTest base; // A CCoinsViewTest at the bottom.\n    std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.\n    stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.\n\n    // Use a limited set of random transaction ids, so we do test overwriting entries.\n    // Each tx id has to be associated with a unique block height and transaction index combination because of the index based utxo.\n    // The transaction index used will simply be the index in the array of txids constructed below, and they will share the same block height.\n    std::vector<uint256> txids;\n    txids.resize(NUM_SIMULATION_ITERATIONS / 8);\n    for (unsigned int i = 0; i < txids.size(); i++)\n    {\n        txids[i] = InsecureRand256();\n    }\n\n    for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++)\n    {\n        // Do a random modification.\n        {\n            uint32_t nTxIndex = InsecureRandRange(txids.size());\n            uint256 txid = txids[nTxIndex]; // txid we're going to modify in this iteration.\n            Coin& coin = result[COutPoint(txid, 0)];\n            const Coin& entry = (InsecureRandRange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));\n            BOOST_CHECK(coin == entry);\n\n            if (InsecureRandRange(5) == 0 || coin.IsSpent())\n            {\n                Coin newcoin;\n                newcoin.out.nValue = InsecureRand32();\n                newcoin.nTxIndex = nTxIndex;\n                if (InsecureRandRange(16) == 0 && coin.IsSpent())\n                {\n                    newcoin.out.output.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN);\n                    BOOST_CHECK(newcoin.out.output.scriptPubKey.IsUnspendable());\n                    added_an_unspendable_entry = true;\n                }\n                else\n                {\n                    newcoin.out.output.scriptPubKey.assign(InsecureRandBits(6), 0); // Random sizes so we can test memory usage accounting\n                    if (coin.IsSpent())\n                    {\n                        added_an_entry = true;\n                    }\n                    else\n                    {\n                        updated_an_entry = true;\n                    }\n                    \n                    coin = newcoin;\n                }\n                stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || InsecureRand32() & 1);\n            }\n            else\n            {\n                removed_an_entry = true;\n                coin.Spend();\n                stack.back()->SpendCoin(COutPoint(txid, 0));\n            }\n        }\n\n        // One every 10 iterations, remove a random entry from the cache\n        if (InsecureRandRange(10) == 0)\n        {\n            COutPoint out(txids[InsecureRand32() % txids.size()], 0);\n            int cacheid = InsecureRand32() % stack.size();\n            stack[cacheid]->Uncache(out);\n            uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);\n        }\n\n        // Once every 1000 iterations and at the end, verify the full cache.\n        if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1)\n        {\n            for (auto it = result.begin(); it != result.end(); it++)\n            {\n                bool have = stack.back()->HaveCoin(it->first);\n                const Coin& coin = stack.back()->AccessCoin(it->first);\n                BOOST_CHECK(have == !coin.IsSpent());\n                BOOST_CHECK(coin == it->second);\n                if (coin.IsSpent())\n                {\n                    missed_an_entry = true;\n                }\n                else\n                {\n                    BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));\n                    found_an_entry = true;\n                }\n            }\n            for(const CCoinsViewCacheTest *test : stack)\n            {\n                test->SelfTest();\n            }\n        }\n\n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, flush an intermediate cache\n            if (stack.size() > 1 && InsecureRandBool() == 0)\n            {\n                unsigned int flushIndex = InsecureRandRange(stack.size() - 1);\n                stack[flushIndex]->Flush();\n            }\n        }\n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, change the cache stack.\n            if (stack.size() > 0 && InsecureRandBool() == 0)\n            {\n                //Remove the top cache\n                stack.back()->Flush();\n                delete stack.back();\n                stack.pop_back();\n            }\n            if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool()))\n            {\n                //Add a new cache\n                CCoinsView* tip = &base;\n                if (stack.size() > 0)\n                {\n                    tip = stack.back();\n                }\n                else\n                {\n                    removed_all_caches = true;\n                }\n                stack.push_back(new CCoinsViewCacheTest(tip));\n                if (stack.size() == 4)\n                {\n                    reached_4_caches = true;\n                }\n            }\n        }\n    }\n\n    // Clean up the stack.\n    while (stack.size() > 0)\n    {\n        delete stack.back();\n        stack.pop_back();\n    }\n\n    // Verify coverage.\n    BOOST_CHECK(removed_all_caches);\n    BOOST_CHECK(reached_4_caches);\n    BOOST_CHECK(added_an_entry);\n    BOOST_CHECK(added_an_unspendable_entry);\n    BOOST_CHECK(removed_an_entry);\n    BOOST_CHECK(updated_an_entry);\n    BOOST_CHECK(found_an_entry);\n    BOOST_CHECK(missed_an_entry);\n    BOOST_CHECK(uncached_an_entry);\n}\n\n// Store of all necessary tx and undo data for next test\ntypedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData;\nUtxoData utxoData;\n\nUtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {\n    assert(utxoSet.size());\n    auto utxoSetIt = utxoSet.lower_bound(COutPoint(InsecureRand256(), 0));\n    if (utxoSetIt == utxoSet.end()) {\n        utxoSetIt = utxoSet.begin();\n    }\n    auto utxoDataIt = utxoData.find(*utxoSetIt);\n    assert(utxoDataIt != utxoData.end());\n    return utxoDataIt;\n}\n\n\n// This test is similar to the previous test except the emphasis is on testing the functionality of UpdateCoins\n// Random txs are created and UpdateCoins is used to update the cache stack\n// In particular it is tested that spending a duplicate coinbase tx has the expected effect (the other duplicate is overwitten at all cache levels)\nBOOST_AUTO_TEST_CASE(updatecoins_simulation_test)\n{\n    bool spent_a_duplicate_coinbase = false;\n    // A simple map to track what we expect the cache stack to represent.\n    std::map<COutPoint, Coin> result;\n    \n    // Keep a static height for every outpoint so that we don't trigger asserts on index based outpoints.\n    std::map<std::string, uint32_t> heights;\n    // Heights should not repeat.\n    std::set<uint32_t> usedHeights;\n\n    // The cache stack.\n    CCoinsViewTest base; // A CCoinsViewTest at the bottom.\n    std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.\n    stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.\n\n    // Track the txids we've used in various sets\n    std::set<COutPoint> coinbase_coins;\n    std::set<COutPoint> disconnected_coins;\n    std::set<COutPoint> duplicate_coins;\n    std::set<COutPoint> utxoset;\n\n    for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++)\n    {\n        uint32_t randiter = InsecureRand32();\n\n        // 19/20 txs add a new transaction\n        if (randiter % 20 < 19)\n        {\n            CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n            tx.vin.resize(1);\n            tx.vout.resize(1);\n            tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate\n            tx.vout[0].output.scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting\n            Coin old_coin;\n\n            // 2/20 times create a new coinbase\n            if (randiter % 20 < 2 || coinbase_coins.size() < 10)\n            {\n                // 1/10 of those times create a duplicate coinbase\n                if (InsecureRandRange(10) == 0 && coinbase_coins.size())\n                {\n                    auto utxod = FindRandomFrom(coinbase_coins);\n                    // Reuse the exact same coinbase\n                    tx = std::get<0>(utxod->second);\n                    // shouldn't be available for reconnection if its been duplicated\n                    disconnected_coins.erase(utxod->first);\n\n                    duplicate_coins.insert(utxod->first);\n                }\n                else\n                {\n                    coinbase_coins.insert(COutPoint(tx.GetHash(), 0));\n                }\n                assert(CTransaction(tx).IsCoinBase());\n            }\n\n            // 17/20 times reconnect previous or add a regular tx\n            else\n            {\n\n                COutPoint prevout;\n                // 1/20 times reconnect a previously disconnected tx\n                if (randiter % 20 == 2 && disconnected_coins.size())\n                {\n                    auto utxod = FindRandomFrom(disconnected_coins);\n                    tx = std::get<0>(utxod->second);\n                    prevout = tx.vin[0].GetPrevOut();\n                    if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout))\n                    {\n                        disconnected_coins.erase(utxod->first);\n                        continue;\n                    }\n\n                    // If this tx is already IN the UTXO, then it must be a coinbase, and it must be a duplicate\n                    if (utxoset.count(utxod->first))\n                    {\n                        assert(CTransaction(tx).IsCoinBase());\n                        assert(duplicate_coins.count(utxod->first));\n                    }\n                    disconnected_coins.erase(utxod->first);\n                }\n\n                // 16/20 times create a regular tx\n                else\n                {\n                    auto utxod = FindRandomFrom(utxoset);\n                    prevout = utxod->first;\n\n                    // Construct the tx to spend the coins of prevouthash\n                    tx.vin[0].SetPrevOut(prevout);\n                    assert(!CTransaction(tx).IsCoinBase());\n                }\n                // In this simple test coins only have two states, spent or unspent, save the unspent state to restore\n                old_coin = result[prevout];\n                // Update the expected result of prevouthash to know these coins are spent\n                result[prevout].Clear();\n\n                utxoset.erase(prevout);\n\n                // The test is designed to ensure spending a duplicate coinbase will work properly\n                // if that ever happens and not resurrect the previously overwritten coinbase\n                if (duplicate_coins.count(prevout))\n                {\n                    spent_a_duplicate_coinbase = true;\n                }\n\n            }\n            // Update the expected result to know about the new output coins\n            assert(tx.vout.size() == 1);\n            const COutPoint outpoint(tx.GetHash(), 0);\n            \n            // Always use the same height for the same coin (index based outpoints)\n            uint32_t height;\n            if (heights.find( outpoint.getTransactionHash().ToString()) == heights.end())\n            {\n                uint32_t newHeight;\n                do\n                {\n                    newHeight = InsecureRand32()%900000;\n                }\n                while (usedHeights.find(newHeight) != usedHeights.end());\n                heights[ outpoint.getTransactionHash().ToString()] = newHeight;\n                usedHeights.insert(newHeight);\n            }\n            height = heights[outpoint.getTransactionHash().ToString()];\n            \n            result[outpoint] = Coin(tx.vout[0], height, 0, CTransaction(tx).IsCoinBase(), !IsOldTransactionVersion(tx.nVersion));\n\n            // Call UpdateCoins on the top cache\n            CTxUndo undo;\n            UpdateCoins(tx, *(stack.back()), undo, height, 0);\n\n            // Update the utxo set for future spends\n            utxoset.insert(outpoint);\n\n            // Track this tx and undo info to use later\n            utxoData.emplace(outpoint, std::tuple(tx, undo, old_coin));\n        }\n        else if (utxoset.size())\n        {\n            //1/20 times undo a previous transaction\n            auto utxod = FindRandomFrom(utxoset);\n\n            CTransaction &tx = std::get<0>(utxod->second);\n            CTxUndo &undo = std::get<1>(utxod->second);\n            Coin &orig_coin = std::get<2>(utxod->second);\n\n            // Update the expected result\n            // Remove new outputs\n            result[utxod->first].Clear();\n            // If not coinbase restore prevout\n            if (!tx.IsCoinBase())\n            {\n                result[tx.vin[0].GetPrevOut()] = orig_coin;\n            }\n\n            // Disconnect the tx from the current UTXO\n            // See code in DisconnectBlock\n            // remove outputs\n            stack.back()->SpendCoin(utxod->first);\n            // restore inputs\n            if (!tx.IsCoinBase())\n            {\n                const COutPoint &out = tx.vin[0].GetPrevOut();\n                CoinUndo coin = undo.vprevout[0];\n                ApplyTxInUndo(std::move(coin), *(stack.back()), out);\n            }\n            // Store as a candidate for reconnection\n            disconnected_coins.insert(utxod->first);\n\n            // Update the utxoset\n            utxoset.erase(utxod->first);\n            if (!tx.IsCoinBase())\n                utxoset.insert(tx.vin[0].GetPrevOut());\n        }\n\n        // Once every 1000 iterations and at the end, verify the full cache.\n        if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1)\n        {\n            for (auto it = result.begin(); it != result.end(); it++)\n            {\n                bool have = stack.back()->HaveCoin(it->first);\n                const Coin& coin = stack.back()->AccessCoin(it->first);\n                BOOST_CHECK(have == !coin.IsSpent());\n                BOOST_CHECK(coin == it->second);\n            }\n        }\n\n        // One every 10 iterations, remove a random entry from the cache\n        if (utxoset.size() > 1 && InsecureRandRange(30) == 0)\n        {\n            stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);\n        }\n        if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0)\n        {\n            stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first);\n        }\n        if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0)\n        {\n            stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first);\n        }\n\n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, flush an intermediate cache\n            if (stack.size() > 1 && InsecureRandBool() == 0)\n            {\n                unsigned int flushIndex = InsecureRandRange(stack.size() - 1);\n                stack[flushIndex]->Flush();\n            }\n        }\n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, change the cache stack.\n            if (stack.size() > 0 && InsecureRandBool() == 0)\n            {\n                stack.back()->Flush();\n                delete stack.back();\n                stack.pop_back();\n            }\n            if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool()))\n            {\n                CCoinsView* tip = &base;\n                if (stack.size() > 0)\n                {\n                    tip = stack.back();\n                }\n                stack.push_back(new CCoinsViewCacheTest(tip));\n            }\n        }\n    }\n\n    // Clean up the stack.\n    while (stack.size() > 0)\n    {\n        delete stack.back();\n        stack.pop_back();\n    }\n\n    // Verify coverage.\n    BOOST_CHECK(spent_a_duplicate_coinbase);\n}\n\n// This test is similar to the previous test except the emphasis is on testing the functionality of index based outpoints\n// In particular it is tested that when reorganising multiple times (multiple different transactions with the same index) that the index remains consistent\nBOOST_AUTO_TEST_CASE(indexbased_simulation_test)\n{\n    fPrintToConsole = true;\n\n    // A simple map to track what we expect the cache stack to represent.\n    std::map<COutPoint, Coin> resultHashBased;\n    std::map<COutPoint, COutPoint> resultIndexBased;\n    uint64_t heightOffset = 100;\n    uint64_t blockCount = 0;\n    std::vector<std::vector<CTransaction>> blocks;\n    std::vector<std::vector<CTransaction>> removedblocks;\n    std::vector<std::vector<CTxUndo>> blockUndo;\n    std::map<COutPoint, std::tuple<uint64_t, uint64_t, uint64_t>> allCoins;\n    \n    // The cache stack.\n    CCoinsViewDB& base = *pcoinsdbview; //Proper coins view db as the base\n    std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.\n    stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.\n    \n    // \"Genesis\" block\n    {\n        blockCount = 1;\n        blocks.push_back(std::vector<CTransaction>());\n        blockUndo.push_back(std::vector<CTxUndo>());\n        \n        CMutableTransaction tx(CTransaction::CURRENT_VERSION);\n        tx.vin.resize(1);\n        tx.vout.resize(100);\n        for (int outputIndex=0; outputIndex<100; ++outputIndex)\n        {\n            tx.vout[outputIndex].nValue = outputIndex; //Keep txs unique unless intended to duplicate\n            tx.vout[outputIndex].output.scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting\n        }        \n        assert(CTransaction(tx).IsCoinBase());\n        \n        for (uint64_t outputIndex = 0; outputIndex < 100; ++outputIndex)\n        {\n            allCoins[COutPoint(tx.GetHash(), outputIndex)] = std::tuple(heightOffset+blockCount-1, 0, outputIndex);\n        }\n        \n        // Call UpdateCoins on the top cache\n        CTxUndo undo;\n        UpdateCoins(tx, *(stack.back()), undo, heightOffset, 0);\n        \n        blocks[blockCount-1].push_back(tx);\n        blockUndo[blockCount-1].push_back(undo);\n    }\n    \n    #define DO_RECONNECT_TESTS\n    #ifdef DO_RECONNECT_TESTS\n    bool lastActionWasDisconnect=false;\n    #endif\n    for (unsigned int simStep = 0; simStep < NUM_SIMULATION_ITERATIONS; simStep++)\n    {\n        uint32_t randiter = InsecureRand32();\n\n        // For first 100 iterations add a new block so we have something to work with that\n        // After that 5/20 times, add a new \"block\"\n        if (simStep<100 || randiter % 20 < 10)\n        {\n            //Simulate connecting a block\n            ++blockCount;\n            \n            LogPrintf(\"Connect block [%d]\\n\", blockCount+heightOffset);\n            blocks.push_back(std::vector<CTransaction>());\n            blockUndo.push_back(std::vector<CTxUndo>());\n            \n            // Low chance event, reconnect the same block we just disconnected again\n            #ifdef DO_RECONNECT_TESTS\n            if (lastActionWasDisconnect && randiter % 100 < 5)\n            {\n                LogPrintf(\"reconnect block [%d]\\n\", blockCount+heightOffset);\n\n                int txIndex = 0;\n                for (const auto& removedTransaction : removedblocks.back())\n                {\n                    CTxUndo undo;\n                    UpdateCoins(removedTransaction, *(stack.back()), undo, heightOffset+blockCount-1, txIndex);\n                    \n                    for (uint64_t inputIndex = 0; inputIndex < removedTransaction.vin.size(); ++inputIndex)\n                    {\n                        if (removedTransaction.vin[inputIndex].GetPrevOut().isHash)\n                        {\n                            allCoins.erase(allCoins.find(removedTransaction.vin[inputIndex].GetPrevOut()));\n                        }\n                        else\n                        {\n                            bool removed = false;\n                            for (const auto& [hashOutPoint, indexOutPoint] : allCoins)\n                            {\n                                if (removedTransaction.vin[inputIndex].GetPrevOut() == COutPoint(std::get<0>(indexOutPoint), std::get<1>(indexOutPoint), std::get<2>(indexOutPoint)))\n                                {\n                                    allCoins.erase(allCoins.find(hashOutPoint));\n                                    removed = true;\n                                    break;\n                                }\n                            }\n                            if (!removed)\n                            {\n                                assert(0);\n                            }\n                        }\n                    }\n                    \n                    for (uint64_t outputIndex = 0; outputIndex < removedTransaction.vout.size(); ++outputIndex)\n                    {\n                        LogPrintf(\"Recreate output [%s] [%s]\\n\", COutPoint(removedTransaction.GetHash(), outputIndex).ToString(), COutPoint(heightOffset+blockCount-1, txIndex, outputIndex).ToString());\n                        allCoins[COutPoint(removedTransaction.GetHash(), outputIndex)] = std::tuple(heightOffset+blockCount-1, txIndex, outputIndex);\n                    }\n                    \n                    txIndex++;\n                    blocks[blockCount-1].push_back(removedTransaction);\n                    blockUndo[blockCount-1].push_back(undo);\n                }\n            }\n            else\n            #endif\n            {    \n                uint64_t numTransactions = (randiter % 3) + 1;\n                for (uint64_t txIndex=0; txIndex < numTransactions; ++txIndex)\n                {\n                    // Randomly re-use a previously disconnected transaction instead of creating a new one\n                    bool reusedPreviouslyDisconnectedTransaction=false;\n                    #ifdef DO_RECONNECT_TESTS\n                    if (lastActionWasDisconnect && randiter % 100 < 25)\n                    {\n                        lastActionWasDisconnect = false;\n                        \n                        uint64_t oldTxIndex = InsecureRand32() % removedblocks.back().size();\n                        const auto& removedTransaction = removedblocks.back()[oldTxIndex];\n\n                        bool stillHaveAllInputs=true;\n                        for (uint64_t inputIndex = 0; inputIndex < removedTransaction.vin.size(); ++inputIndex)\n                        {\n                            if (removedTransaction.vin[inputIndex].GetPrevOut().isHash)\n                            {\n                                if (allCoins.find(removedTransaction.vin[inputIndex].GetPrevOut()) == allCoins.end())\n                                {\n                                    stillHaveAllInputs = false;\n                                    break;\n                                }\n                                else\n                                {\n                                    bool found = false;\n                                    for (const auto& [hashOutPoint, indexOutPoint] : allCoins)\n                                    {\n                                        (unused) hashOutPoint;\n                                        if (removedTransaction.vin[inputIndex].GetPrevOut() == COutPoint(std::get<0>(indexOutPoint), std::get<1>(indexOutPoint), std::get<2>(indexOutPoint)))\n                                        {\n                                            found = true;\n                                            break;\n                                        }\n                                    }\n                                    if (!found)\n                                    {\n                                        stillHaveAllInputs = false;\n                                        break;\n                                    }\n                                }\n                            }\n                        }\n                        \n                        if (stillHaveAllInputs)\n                        {      \n                            CTxUndo undo;\n                            UpdateCoins(removedTransaction, *(stack.back()), undo, heightOffset+blockCount-1, txIndex);\n                            for (uint64_t inputIndex = 0; inputIndex < removedTransaction.vin.size(); ++inputIndex)\n                            {\n                                if (removedTransaction.vin[inputIndex].GetPrevOut().isHash)\n                                {\n                                    allCoins.erase(allCoins.find(removedTransaction.vin[inputIndex].GetPrevOut()));\n                                }\n                                else\n                                {\n                                    bool removed = false;\n                                    for (const auto& [hashOutPoint, indexOutPoint] : allCoins)\n                                    {\n                                        if (removedTransaction.vin[inputIndex].GetPrevOut() == COutPoint(std::get<0>(indexOutPoint), std::get<1>(indexOutPoint), std::get<2>(indexOutPoint)))\n                                        {\n                                            allCoins.erase(allCoins.find(hashOutPoint));\n                                            removed = true;\n                                            break;\n                                        }\n                                    }\n                                    if (!removed)\n                                    {\n                                        assert(0);\n                                    }\n                                }\n                            }\n                            \n                            for (uint64_t outputIndex = 0; outputIndex < removedTransaction.vout.size(); ++outputIndex)\n                            {\n                                LogPrintf(\"Recreate output [%s] [%s]\\n\", COutPoint(removedTransaction.GetHash(), outputIndex).ToString(), COutPoint(heightOffset+blockCount-1, txIndex, outputIndex).ToString());\n                                allCoins[COutPoint(removedTransaction.GetHash(), outputIndex)] = std::tuple(heightOffset+blockCount-1, txIndex, outputIndex);\n                            }\n                            \n                            blocks[blockCount-1].push_back(removedTransaction);\n                            blockUndo[blockCount-1].push_back(undo);\n                            reusedPreviouslyDisconnectedTransaction = true;\n                        }\n                    }\n                    #endif\n                    \n                    if (!reusedPreviouslyDisconnectedTransaction)\n                    {\n                        uint64_t numInputs = (randiter % 3) + 1;\n                        uint64_t numOutputs = (randiter % 3) + 1;\n\n                        CMutableTransaction tx(CTransaction::CURRENT_VERSION);\n                        tx.vin.resize(numInputs);\n                        for (uint64_t inputIndex = 0; inputIndex < numInputs; ++inputIndex)\n                        {\n                            uint64_t selectedInput = InsecureRand32() % allCoins.size();\n                            auto selectedCoinIter = allCoins.begin();\n                            \n                            // Prevent selection from same block we are in\n                            while (true)\n                            {\n                                std::advance(selectedCoinIter, selectedInput);\n                                if (std::get<0>(selectedCoinIter->second) != blockCount+heightOffset-1)\n                                    break;  \n                                selectedInput = InsecureRand32() % allCoins.size();\n                                selectedCoinIter = allCoins.begin();\n                            }\n                            \n                            // Use index based outpoints half the time, but only once we are a little bit into the simulation, so that we first rule out problems with regular inputs\n                            bool indexBased = false;\n                            if (simStep>400)\n                                indexBased = (InsecureRand32() % 100) < 80;\n                            \n                            if (indexBased)\n                            {\n                                tx.vin[inputIndex] = CTxIn(COutPoint(std::get<0>(selectedCoinIter->second), std::get<1>(selectedCoinIter->second), std::get<2>(selectedCoinIter->second)), CScript(), 0, 0);\n                                LogPrintf(\"Spend output as index input [%s] [%s]\\n\", COutPoint(std::get<0>(selectedCoinIter->second), std::get<1>(selectedCoinIter->second), std::get<2>(selectedCoinIter->second)).ToString(), selectedCoinIter->first.ToString());\n                            }\n                            else\n                            {\n                                tx.vin[inputIndex] = CTxIn(selectedCoinIter->first, CScript(), 0, 0);\n                                LogPrintf(\"Spend output as hash input [%s] [%s]\\n\", selectedCoinIter->first.ToString(), COutPoint(std::get<0>(selectedCoinIter->second), std::get<1>(selectedCoinIter->second), std::get<2>(selectedCoinIter->second)).ToString());\n                            }\n                            allCoins.erase(selectedCoinIter);\n                        }\n                        tx.vout.resize(numOutputs);\n                        for (uint64_t outputIndex = 0; outputIndex < numOutputs; ++outputIndex)\n                        {\n                            tx.vout[outputIndex].nValue = simStep; //Keep txs unique unless intended to duplicate\n                            tx.vout[outputIndex].output.scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting                    \n                        }\n                        assert(!CTransaction(tx).IsCoinBase());\n                        \n                        for (uint64_t outputIndex = 0; outputIndex < numOutputs; ++outputIndex)\n                        {\n                            LogPrintf(\"Create output [%s] [%s]\\n\", COutPoint(tx.GetHash(), outputIndex).ToString(), COutPoint(heightOffset+blockCount-1, txIndex, outputIndex).ToString());\n                            allCoins[COutPoint(tx.GetHash(), outputIndex)] = std::tuple(heightOffset+blockCount-1, txIndex, outputIndex);\n                        }\n                        \n                        // Call UpdateCoins on the top cache\n                        CTxUndo undo;\n                        UpdateCoins(tx, *(stack.back()), undo, heightOffset+blockCount-1, txIndex);\n                        blocks[blockCount-1].push_back(tx);\n                        blockUndo[blockCount-1].push_back(undo);\n                    }\n                }\n            }\n            \n            #ifdef DO_RECONNECT_TESTS\n            lastActionWasDisconnect = false;\n            #endif\n        }\n        else if (randiter % 20 < 18)\n        {\n            //Simulate disconnecting a block\n            LogPrintf(\"Disconnect block [%d]\\n\", blockCount+heightOffset);\n            \n            int txIndex=0;\n            for (const auto& tx :  blocks[blockCount-1])\n            {\n                // Remove outputs\n                int outputIndex=0;\n                for (const auto& txOut : tx.vout)\n                {\n                    (unused)txOut;\n                    LogPrintf(\"Spend output [%s]\\n\", COutPoint(tx.GetHash(), outputIndex).ToString());\n                    allCoins.erase(allCoins.find(COutPoint(tx.GetHash(), outputIndex)));\n\n                    stack.back()->SpendCoin(COutPoint(tx.GetHash(), outputIndex));\n                    ++outputIndex;\n                }\n                \n                // restore inputs\n                if (!tx.IsCoinBase())\n                {\n                    CTxUndo &txundo = blockUndo[blockCount-1][txIndex];\n                    for (int64_t j = tx.vin.size(); j-- > 0;)\n                    {   \n                        const COutPoint &out = tx.vin[j].GetPrevOut();\n                        CoinUndo undo = txundo.vprevout[j];\n                        \n                        if (out.isHash)\n                        {\n                            assert(COutPoint(undo.prevhash, out.n) == out);\n                            LogPrintf(\"Unspend hash input [%s] [%s]\\n\", out.ToString(), COutPoint((uint64_t)undo.nHeight, undo.nTxIndex, out.n).ToString());\n                        }\n                        else\n                        {\n                            LogPrintf(\"Unspend index input [%s] [%s]\\n\", COutPoint((uint64_t)undo.nHeight, undo.nTxIndex, out.n).ToString(), COutPoint(undo.prevhash, out.n).ToString());\n                        }\n                        //NB! We delibritely don't use \"out\" as the outpoint here as we always want it to be hash based.\n                        allCoins[COutPoint(undo.prevhash, out.n)] = std::tuple((uint64_t)undo.nHeight, undo.nTxIndex, out.n);\n                        \n                        int res = ApplyTxInUndo(std::move(undo), *(stack.back()), out);\n                        BOOST_CHECK (res != DISCONNECT_FAILED);\n                    }\n                }\n                ++txIndex;\n            }\n            removedblocks.push_back(blocks[blockCount-1]);\n            blocks.pop_back();\n            blockUndo.pop_back();\n            --blockCount;\n            #ifdef DO_RECONNECT_TESTS\n            lastActionWasDisconnect = true;\n            #endif\n        }\n        \n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, flush an intermediate cache\n            if (stack.size() > 1 && InsecureRandBool() == 0)\n            {\n                unsigned int flushIndex = InsecureRandRange(stack.size() - 1);\n                stack[flushIndex]->Flush();\n                LogPrintf(\"Flush cache [%d]\\n\", flushIndex);\n            }\n        }\n        if (InsecureRandRange(100) == 0)\n        {\n            // Every 100 iterations, change the cache stack.\n            if (stack.size() > 0 && InsecureRandBool() == 0)\n            {\n                //Remove the top cache\n                stack.back()->Flush();\n                delete stack.back();\n                stack.pop_back();\n                \n                LogPrintf(\"Pop cache from stack\\n\");\n            }\n            if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool()))\n            {\n                LogPrintf(\"Add cache to stack\\n\");\n                \n                //Add a new cache\n                CCoinsView* tip = &base;\n                if (stack.size() > 0)\n                {\n                    tip = stack.back();\n                }\n                else\n                {\n                    //removed_all_caches = true;\n                }\n                stack.push_back(new CCoinsViewCacheTest(tip));\n                if (stack.size() == 4)\n                {\n                    //reached_4_caches = true;\n                }\n            }\n        }\n        \n        \n        // For every iteration make sure our expected UTXO matches our real UTXO\n        {\n            std::map<COutPoint, Coin> utxoAllCoins;\n            stack.back()->GetAllCoins(utxoAllCoins);\n            \n            std::vector<COutPoint> allCoinsL;\n            for (const auto& [outPoint, coins] : utxoAllCoins)\n            {\n                (unused) coins;\n                allCoinsL.push_back(outPoint);\n            }\n            std::vector<COutPoint> allCoinsR;\n            for (const auto& [key, value] : allCoins)\n            {\n                (unused) value;\n                allCoinsR.push_back(key);\n            }\n            BOOST_REQUIRE_EQUAL_COLLECTIONS(allCoinsL.begin(), allCoinsL.end(), allCoinsR.begin(), allCoinsR.end());\n            \n            std::map<COutPoint, Coin> utxoAllCoinsIndexBased;\n            stack.back()->GetAllCoinsIndexBased(utxoAllCoinsIndexBased);\n            \n            std::vector<COutPoint> allCoinsIndexBasedUTXO;\n            for (const auto& [outPoint, coins] : utxoAllCoinsIndexBased)\n            {\n                (unused) coins;\n                allCoinsIndexBasedUTXO.push_back(outPoint);\n            }\n            std::vector<COutPoint> allCoinsIndexBasedTracked;\n            for (const auto& [key, value] : allCoins)\n            {\n                (unused) key;\n                allCoinsIndexBasedTracked.push_back(COutPoint(std::get<0>(value), std::get<1>(value), std::get<2>(value)));\n            }\n            std::sort(allCoinsIndexBasedTracked.begin(), allCoinsIndexBasedTracked.end());\n            BOOST_REQUIRE_EQUAL_COLLECTIONS(allCoinsIndexBasedUTXO.begin(), allCoinsIndexBasedUTXO.end(), allCoinsIndexBasedTracked.begin(), allCoinsIndexBasedTracked.end());\n            \n            std::map<COutPoint, Coin> utxoAllCoinsIndexBasedDirect;\n            // clear to prevent re-use of result of GetAllCoinsIndexBased() above, both GetAllCoinsIndexBased() and GetAllCoinsIndexBasedDirect() just add to the output argument\n            // update 2022-03-10 disabled again, we now know in what way the GetAllCoinsIndexBased() is flawed adn want use this test besides it\n            // utxoAllCoinsIndexBased.clear();\n            stack.back()->GetAllCoinsIndexBasedDirect(utxoAllCoinsIndexBased);\n            std::vector<COutPoint> allCoinsIndexBasedUTXODirect;\n            for (const auto& [outPoint, coins] : utxoAllCoinsIndexBased)\n            {\n                (unused) coins;\n                allCoinsIndexBasedUTXODirect.push_back(outPoint);\n            }\n            BOOST_REQUIRE_EQUAL_COLLECTIONS(allCoinsIndexBasedUTXODirect.begin(), allCoinsIndexBasedUTXODirect.end(), allCoinsIndexBasedTracked.begin(), allCoinsIndexBasedTracked.end());\n            \n            //fetchcoin\n            for (const auto& [key, value] : allCoins)\n            {\n                CDataStream CoinLStream(SER_DISK, CLIENT_VERSION);\n                {\n                    Coin CoinL;\n                    stack.back()->GetCoin(key, CoinL);\n                    CoinLStream << CoinL;\n                }\n                CDataStream CoinRStream(SER_DISK, CLIENT_VERSION);\n                {\n                    Coin CoinR;\n                    stack.back()->GetCoin(COutPoint(std::get<0>(value), std::get<1>(value), std::get<2>(value)), CoinR);\n                    CoinRStream << CoinR;\n                }\n                BOOST_CHECK_EQUAL(HexStr(CoinLStream.begin(), CoinLStream.end()), HexStr(CoinRStream.begin(), CoinRStream.end()));\n            }\n        }\n    }\n    \n    // Clean up the stack.\n    while (stack.size() > 0)\n    {\n        delete stack.back();\n        stack.pop_back();\n    }\n}\n\n\nBOOST_AUTO_TEST_CASE(ccoins_serialization)\n{\n    // Good example\n    CDataStream ss1(ParseHex(\"b0e57800005847f80d0000001976a914816115944e077fe7c803cfa57f29b36bf87c1d3588ac\"), SER_DISK, CLIENT_VERSION);\n    Coin cc1;\n    ss1 >> cc1;\n    BOOST_CHECK_EQUAL(cc1.fCoinBase, false);\n    BOOST_CHECK(cc1.nHeight == 203998);\n    BOOST_CHECK_EQUAL(cc1.out.nValue, 60000000000LL);\n    BOOST_CHECK_EQUAL(HexStr(cc1.out.output.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex(\"816115944e077fe7c803cfa57f29b36bf87c1d35\"))))));\n\n    // Good example\n    CDataStream ss2(ParseHex(\"9cc06d003daf0100000000001976a9148c988f1a4a4de2161e0f50aac7f17e7f9555caa488ac\"), SER_DISK, CLIENT_VERSION);\n    Coin cc2;\n    ss2 >> cc2;\n    BOOST_CHECK_EQUAL(cc2.fCoinBase, true);\n    BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);\n    BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);\n    BOOST_CHECK_EQUAL(HexStr(cc2.out.output.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex(\"8c988f1a4a4de2161e0f50aac7f17e7f9555caa4\"))))));    \n\n    // Smallest possible example\n    CDataStream ss3(ParseHex(\"00000000000000000000000\"), SER_DISK, CLIENT_VERSION);\n    Coin cc3;\n    ss3 >> cc3;\n    BOOST_CHECK_EQUAL(cc3.fCoinBase, false);\n    BOOST_CHECK_EQUAL(cc3.nHeight, 0U);\n    BOOST_CHECK_EQUAL(cc3.out.nValue, 0);\n    BOOST_CHECK_EQUAL(cc3.out.output.scriptPubKey.size(), 0U);\n\n    // scriptPubKey that ends beyond the end of the stream\n    CDataStream ss4(ParseHex(\"00000007\"), SER_DISK, CLIENT_VERSION);\n    try {\n        Coin cc4;\n        ss4 >> cc4;\n        BOOST_CHECK_MESSAGE(false, \"We should have thrown\");\n    } catch (const std::ios_base::failure& e) {\n    }\n\n    // Very large scriptPubKey (3*10^9 bytes) past the end of the stream\n    CDataStream tmp(SER_DISK, CLIENT_VERSION);\n    uint64_t x = 3000000000ULL;\n    tmp << VARINT(x);\n    BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), \"8a95c0bb00\");\n    CDataStream ss5(ParseHex(\"00008a95c0bb00\"), SER_DISK, CLIENT_VERSION);\n    try {\n        Coin cc5;\n        ss5 >> cc5;\n        BOOST_CHECK_MESSAGE(false, \"We should have thrown\");\n    } catch (const std::ios_base::failure& e) {\n    }\n}\n\n\nconst static COutPoint OUTPOINT;\nconst static CAmount PRUNED = -1;\nconst static CAmount ABSENT = -2;\nconst static CAmount FAIL = -3;\nconst static CAmount VALUE1 = 100;\nconst static CAmount VALUE2 = 200;\nconst static CAmount VALUE3 = 300;\nconst static char DIRTY = CCoinsCacheEntry::DIRTY;\nconst static char FRESH = CCoinsCacheEntry::FRESH;\nconst static char NO_ENTRY = -1;\n\nconst static auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)};\nconst static auto CLEAN_FLAGS = {char(0), FRESH};\nconst static auto ABSENT_FLAGS = {NO_ENTRY};\n\nvoid SetCoinsValue(CAmount value, Coin& coin)\n{\n    assert(value != ABSENT);\n    coin.Clear();\n    assert(coin.IsSpent());\n    if (value != PRUNED) {\n        coin.out.nValue = value;\n        coin.nHeight = 1;\n        assert(!coin.IsSpent());\n    }\n}\n\nsize_t InsertCoinsMapEntry(CCoinsMap& map, CCoinsRefMap& refmap, CAmount value, char flags)\n{\n    if (value == ABSENT) {\n        assert(flags == NO_ENTRY);\n        return 0;\n    }\n    assert(flags != NO_ENTRY);\n    CCoinsCacheEntry entry;\n    entry.flags = flags;\n    SetCoinsValue(value, entry.coin);\n    auto inserted = map.emplace(OUTPOINT, std::move(entry));\n    assert(inserted.second);\n    \n    //Ensure that the \"index based outpoint\" coin map is also updated to match\n    refmap[COutPoint(entry.coin.nHeight, entry.coin.nTxIndex, OUTPOINT.n)] = OUTPOINT;\n    \n    return inserted.first->second.coin.DynamicMemoryUsage();\n}\n\nvoid GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)\n{\n    auto it = map.find(OUTPOINT);\n    if (it == map.end()) {\n        value = ABSENT;\n        flags = NO_ENTRY;\n    } else {\n        if (it->second.coin.IsSpent()) {\n            value = PRUNED;\n        } else {\n            value = it->second.coin.out.nValue;\n        }\n        flags = it->second.flags;\n        assert(flags != NO_ENTRY);\n    }\n}\n\nvoid WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags)\n{\n    CCoinsMap map;\n    CCoinsRefMap refmap;\n    InsertCoinsMapEntry(map, refmap, value, flags);\n    view.BatchWrite(map, {});\n}\n\nclass SingleEntryCacheTest\n{\npublic:\n    SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags)\n    {\n        WriteCoinsViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY);\n        cache.usage() += InsertCoinsMapEntry(cache.map(), cache.refmap(), cache_value, cache_flags);\n    }\n\n    CCoinsView root;\n    CCoinsViewCacheTest base{&root};\n    CCoinsViewCacheTest cache{&base};\n};\n\nvoid CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)\n{\n    SingleEntryCacheTest test(base_value, cache_value, cache_flags);\n    test.cache.AccessCoin(OUTPOINT);\n    test.cache.SelfTest();\n\n    CAmount result_value;\n    char result_flags;\n    GetCoinsMapEntry(test.cache.map(), result_value, result_flags);\n    BOOST_CHECK_EQUAL(result_value, expected_value);\n    BOOST_CHECK_EQUAL(result_flags, expected_flags);\n}\n\nBOOST_AUTO_TEST_CASE(ccoins_access)\n{\n    /* Check AccessCoin behavior, requesting a coin from a cache view layered on\n     * top of a base view, and checking the resulting entry in the cache after\n     * the access.\n     *\n     *               Base    Cache   Result  Cache        Result\n     *               Value   Value   Value   Flags        Flags\n     */\n    CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY   , NO_ENTRY   );\n    CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0          , 0          );\n    CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH      , FRESH      );\n    CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);\n    CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0          , 0          );\n    CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH      , FRESH      );\n    CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY      , DIRTY      );\n    CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);\n    CheckAccessCoin(PRUNED, ABSENT, PRUNED, NO_ENTRY   , FRESH      );\n    CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0          , 0          );\n    CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH      , FRESH      );\n    CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);\n    CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0          , 0          );\n    CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH      , FRESH      );\n    CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY      , DIRTY      );\n    CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);\n    CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY   , 0          );\n    CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0          , 0          );\n    CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH      , FRESH      );\n    CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);\n    CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0          , 0          );\n    CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH      , FRESH      );\n    CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY      , DIRTY      );\n    CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);\n}\n\nvoid CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)\n{\n    SingleEntryCacheTest test(base_value, cache_value, cache_flags);\n    test.cache.SpendCoin(OUTPOINT);\n    test.cache.SelfTest();\n\n    CAmount result_value;\n    char result_flags;\n    GetCoinsMapEntry(test.cache.map(), result_value, result_flags);\n    BOOST_CHECK_EQUAL(result_value, expected_value);\n    BOOST_CHECK_EQUAL(result_flags, expected_flags);\n};\n\nBOOST_AUTO_TEST_CASE(ccoins_spend)\n{\n    /* Check SpendCoin behavior, requesting a coin from a cache view layered on\n     * top of a base view, spending, and then checking\n     * the resulting entry in the cache after the modification.\n     *\n     *              Base    Cache   Result  Cache        Result\n     *              Value   Value   Value   Flags        Flags\n     */\n    CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY   , NO_ENTRY   );\n    CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n    CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n    CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY   , NO_ENTRY   );\n    CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n    CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n    CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY   , DIRTY      );\n    CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n    CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0          , DIRTY      );\n    CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH      , NO_ENTRY   );\n    CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY      , DIRTY      );\n    CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY   );\n}\n\nvoid CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)\n{\n    SingleEntryCacheTest test(base_value, cache_value, cache_flags);\n\n    CAmount result_value;\n    char result_flags;\n    try {\n        CTxOut output;\n        output.nValue = modify_value;\n        test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, 0, coinbase, false), coinbase);\n        test.cache.SelfTest();\n        GetCoinsMapEntry(test.cache.map(), result_value, result_flags);\n    } catch (std::logic_error& e) {\n        result_value = FAIL;\n        result_flags = NO_ENTRY;\n    }\n\n    BOOST_CHECK_EQUAL(result_value, expected_value);\n    BOOST_CHECK_EQUAL(result_flags, expected_flags);\n}\n\n// Simple wrapper for CheckAddCoinBase function above that loops through\n// different possible base_values, making sure each one gives the same results.\n// This wrapper lets the coins_add test below be shorter and less repetitive,\n// while still verifying that the CoinsViewCache::AddCoin implementation\n// ignores base values.\ntemplate <typename... Args>\nvoid CheckAddCoin(Args&&... args)\n{\n    for (CAmount base_value : {ABSENT, PRUNED, VALUE1})\n        CheckAddCoinBase(base_value, std::forward<Args>(args)...);\n}\n\nBOOST_AUTO_TEST_CASE(ccoins_add)\n{\n    /* Check AddCoin behavior, requesting a new coin from a cache view,\n     * writing a modification to the coin, and then checking the resulting\n     * entry in the cache after the modification. Verify behavior with the\n     * with the AddCoin potential_overwrite argument set to false, and to true.\n     *\n     *           Cache   Write   Result  Cache        Result       potential_overwrite\n     *           Value   Value   Value   Flags        Flags\n     */\n    CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY   , DIRTY|FRESH, false);\n    CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY   , DIRTY      , true );\n    // Below tests pass in release mode, but trigger some debug mode asserts, so we disable them for now in debug mode\n    #ifndef DEBUG_COINSCACHE_VALIDATE_INSERTS\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, 0          , DIRTY|FRESH, false);\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, 0          , DIRTY      , true );\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH      , DIRTY|FRESH, false);\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH      , DIRTY|FRESH, true );\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY      , DIRTY      , false);\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY      , DIRTY      , true );\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);\n    CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );\n    CheckAddCoin(VALUE2, VALUE3, FAIL  , 0          , NO_ENTRY   , false);\n    CheckAddCoin(VALUE2, VALUE3, VALUE3, 0          , DIRTY      , true );\n    CheckAddCoin(VALUE2, VALUE3, FAIL  , FRESH      , NO_ENTRY   , false);\n    CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH      , DIRTY|FRESH, true );\n    CheckAddCoin(VALUE2, VALUE3, FAIL  , DIRTY      , NO_ENTRY   , false);\n    CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY      , DIRTY      , true );\n    CheckAddCoin(VALUE2, VALUE3, FAIL  , DIRTY|FRESH, NO_ENTRY   , false);\n    CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );\n    #endif\n}\n\nvoid CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)\n{\n    SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);\n\n    CAmount result_value;\n    char result_flags;\n    try {\n        WriteCoinsViewEntry(test.cache, child_value, child_flags);\n        test.cache.SelfTest();\n        GetCoinsMapEntry(test.cache.map(), result_value, result_flags);\n    } catch (std::logic_error& e) {\n        result_value = FAIL;\n        result_flags = NO_ENTRY;\n    }\n\n    BOOST_CHECK_EQUAL(result_value, expected_value);\n    BOOST_CHECK_EQUAL(result_flags, expected_flags);\n}\n\nBOOST_AUTO_TEST_CASE(ccoins_write)\n{\n    /* Check BatchWrite behavior, flushing one entry from a child cache to a\n     * parent cache, and checking the resulting entry in the parent cache\n     * after the write.\n     *\n     *              Parent  Child   Result  Parent       Child        Result\n     *              Value   Value   Value   Flags        Flags        Flags\n     */\n    CheckWriteCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY   , NO_ENTRY   , NO_ENTRY   );\n    CheckWriteCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY   , DIRTY      , DIRTY      );\n    CheckWriteCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY   , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY   , DIRTY      , DIRTY      );\n    CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY   , DIRTY|FRESH, DIRTY|FRESH);\n    CheckWriteCoins(PRUNED, ABSENT, PRUNED, 0          , NO_ENTRY   , 0          );\n    CheckWriteCoins(PRUNED, ABSENT, PRUNED, FRESH      , NO_ENTRY   , FRESH      );\n    CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY      , NO_ENTRY   , DIRTY      );\n    CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY|FRESH, NO_ENTRY   , DIRTY|FRESH);\n    CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0          , DIRTY      , DIRTY      );\n    CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0          , DIRTY|FRESH, DIRTY      );\n    CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH      , DIRTY      , NO_ENTRY   );\n    CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH      , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY      , DIRTY      , DIRTY      );\n    CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY      , DIRTY|FRESH, DIRTY      );\n    CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY      , NO_ENTRY   );\n    CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0          , DIRTY      , DIRTY      );\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0          , DIRTY|FRESH, DIRTY      );\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH      , DIRTY      , DIRTY|FRESH);\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH      , DIRTY|FRESH, DIRTY|FRESH);\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY      , DIRTY      , DIRTY      );\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY      , DIRTY|FRESH, DIRTY      );\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY      , DIRTY|FRESH);\n    CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH, DIRTY|FRESH);\n    CheckWriteCoins(VALUE1, ABSENT, VALUE1, 0          , NO_ENTRY   , 0          );\n    CheckWriteCoins(VALUE1, ABSENT, VALUE1, FRESH      , NO_ENTRY   , FRESH      );\n    CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY      , NO_ENTRY   , DIRTY      );\n    CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY|FRESH, NO_ENTRY   , DIRTY|FRESH);\n    CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0          , DIRTY      , DIRTY      );\n    CheckWriteCoins(VALUE1, PRUNED, FAIL  , 0          , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH      , DIRTY      , NO_ENTRY   );\n    CheckWriteCoins(VALUE1, PRUNED, FAIL  , FRESH      , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY      , DIRTY      , DIRTY      );\n    CheckWriteCoins(VALUE1, PRUNED, FAIL  , DIRTY      , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, DIRTY      , NO_ENTRY   );\n    CheckWriteCoins(VALUE1, PRUNED, FAIL  , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0          , DIRTY      , DIRTY      );\n    CheckWriteCoins(VALUE1, VALUE2, FAIL  , 0          , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH      , DIRTY      , DIRTY|FRESH);\n    CheckWriteCoins(VALUE1, VALUE2, FAIL  , FRESH      , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY      , DIRTY      , DIRTY      );\n    CheckWriteCoins(VALUE1, VALUE2, FAIL  , DIRTY      , DIRTY|FRESH, NO_ENTRY   );\n    CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY      , DIRTY|FRESH);\n    CheckWriteCoins(VALUE1, VALUE2, FAIL  , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY   );\n\n    // The checks above omit cases where the child flags are not DIRTY, since\n    // they would be too repetitive (the parent cache is never updated in these\n    // cases). The loop below covers these cases and makes sure the parent cache\n    // is always left unchanged.\n    for (CAmount parent_value : {ABSENT, PRUNED, VALUE1})\n        for (CAmount child_value : {ABSENT, PRUNED, VALUE2})\n            for (char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS)\n                for (char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS)\n                    CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/compress_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"compressor.h\"\n#include \"util.h\"\n#include \"test/test.h\"\n\n#include <stdint.h>\n\n#include <boost/test/unit_test.hpp>\n\n// amounts 0.00000001 .. 0.00100000\n#define NUM_MULTIPLES_UNIT 100000\n\n// amounts 0.01 .. 100.00\n#define NUM_MULTIPLES_CENT 10000\n\n// amounts 1 .. 10000\n#define NUM_MULTIPLES_1NLG 10000\n\n// amounts 50 .. 21000000\n#define NUM_MULTIPLES_50NLG 420000\n\nBOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)\n\nbool static TestEncode(uint64_t in) {\n    return in == DecompressAmount(CompressAmount(in));\n}\n\nbool static TestDecode(uint64_t in) {\n    return in == CompressAmount(DecompressAmount(in));\n}\n\nbool static TestPair(uint64_t dec, uint64_t enc) {\n    return CompressAmount(dec) == enc &&\n           DecompressAmount(enc) == dec;\n}\n\nBOOST_AUTO_TEST_CASE(compress_amounts)\n{\n    BOOST_CHECK(TestPair(            0,       0x0));\n    BOOST_CHECK(TestPair(            1,       0x1));\n    BOOST_CHECK(TestPair(         CENT,       0x7));\n    BOOST_CHECK(TestPair(         COIN,       0x9));\n    BOOST_CHECK(TestPair(      50*COIN,      0x32));\n    BOOST_CHECK(TestPair(21000000*COIN, 0x1406f40));\n\n    for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++)\n        BOOST_CHECK(TestEncode(i));\n\n    for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++)\n        BOOST_CHECK(TestEncode(i * CENT));\n\n    for (uint64_t i = 1; i <= NUM_MULTIPLES_1NLG; i++)\n        BOOST_CHECK(TestEncode(i * COIN));\n\n    for (uint64_t i = 1; i <= NUM_MULTIPLES_50NLG; i++)\n        BOOST_CHECK(TestEncode(i * 50 * COIN));\n\n    for (uint64_t i = 0; i < 100000; i++)\n        BOOST_CHECK(TestDecode(i));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/crypto_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"crypto/chacha20.h\"\n#include \"crypto/ripemd160.h\"\n#include \"crypto/sha1.h\"\n#include \"crypto/sha256.h\"\n#include \"crypto/sha512.h\"\n#include \"crypto/hmac_sha256.h\"\n#include \"crypto/hmac_sha512.h\"\n#include \"crypto/scrypt/crypto_scrypt.h\"\n#include \"random.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <cryptopp/config.h>\n#include <cryptopp/aes.h>\n#include <cryptopp/modes.h>\n#include <cryptopp/filters.h>\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n#include <openssl/evp.h>\n\nBOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup)\n\ntemplate<typename Hasher, typename In, typename Out>\nvoid TestVector(const Hasher &h, const In &in, const Out &out) {\n    Out hash;\n    BOOST_CHECK(out.size() == h.OUTPUT_SIZE);\n    hash.resize(out.size());\n    {\n        // Test that writing the whole input string at once works.\n        Hasher(h).Write((const uint8_t*)in.data(), in.size()).Finalize(hash.data());\n        BOOST_CHECK(hash == out);\n    }\n    for (int i=0; i<32; i++) {\n        // Test that writing the string broken up in random pieces works.\n        Hasher hasher(h);\n        size_t pos = 0;\n        while (pos < in.size()) {\n            size_t len = InsecureRandRange((in.size() - pos + 1) / 2 + 1);\n            hasher.Write((const uint8_t*)in.data() + pos, len);\n            pos += len;\n            if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) {\n                // Test that writing the rest at once to a copy of a hasher works.\n                Hasher(hasher).Write((const uint8_t*)in.data() + pos, in.size() - pos).Finalize(hash.data());\n                BOOST_CHECK(hash == out);\n            }\n        }\n        hasher.Finalize(hash.data());\n        BOOST_CHECK(hash == out);\n    }\n}\n\nstatic void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));}\nstatic void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));}\nstatic void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));}\nstatic void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));}\n\nstatic void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));\n}\n\nstatic void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));\n}\n\nstatic void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)\n{\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    std::vector<unsigned char> in = ParseHex(hexin);\n    std::vector<unsigned char> correctout = ParseHex(hexout);\n    std::vector<unsigned char> buf, buf2;\n\n    assert(key.size() == 16);\n    assert(in.size() == 16);\n    assert(correctout.size() == 16);\n    \n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption enc;\n    enc.SetKey(&key[0], key.size());\n    buf.resize(correctout.size());\n    buf2.resize(correctout.size());\n    enc.ProcessData(&buf[0], &in[0], correctout.size());\n    BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));\n    \n    CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption dec;\n    dec.SetKey(&key[0], key.size());\n    dec.ProcessData(&buf2[0], &buf[0], correctout.size());\n    BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));\n}\n\nstatic void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout)\n{\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    std::vector<unsigned char> in = ParseHex(hexin);\n    std::vector<unsigned char> correctout = ParseHex(hexout);\n    std::vector<unsigned char> buf;\n\n    assert(key.size() == 32);\n    assert(in.size() == 16);\n    assert(correctout.size() == 16);\n    \n    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption enc;\n    enc.SetKey(&key[0], key.size());\n    buf.resize(correctout.size());\n    enc.ProcessData(&buf[0], &in[0], correctout.size());\n    BOOST_CHECK(buf == correctout);\n    \n    CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption dec;\n    dec.SetKey(&key[0], key.size());\n    dec.ProcessData(&buf[0], &buf[0], correctout.size());\n    BOOST_CHECK(buf == in);\n}\n\nstatic void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)\n{\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    std::vector<unsigned char> iv = ParseHex(hexiv);\n    std::vector<unsigned char> in = ParseHex(hexin);\n    std::vector<unsigned char> correctout = ParseHex(hexout);\n    std::vector<unsigned char> realout;\n\n    // Encrypt the plaintext and verify that it equals the cipher\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc;\n    enc.SetKeyWithIV(&key[0], key.size(), &iv[0]);\n    if (pad)\n    {\n        CryptoPP::VectorSource s(in, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(realout)));\n    }\n    else\n    {\n        realout.resize(in.size());\n        enc.ProcessData(&realout[0], &in[0], in.size());\n    }\n    BOOST_CHECK(realout.size() == correctout.size());\n    BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(\" != \") + hexout);\n\n    // Decrypt the cipher and verify that it equals the plaintext\n    std::vector<unsigned char> decrypted;\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec;\n    dec.SetKeyWithIV(&key[0], key.size(), &iv[0]);\n    if (pad)\n    {\n        CryptoPP::VectorSource s(correctout, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::VectorSink(decrypted)));\n    }\n    else\n    {\n        decrypted.resize(correctout.size());\n        dec.ProcessData(&decrypted[0], &correctout[0], correctout.size());\n    }\n    BOOST_CHECK(decrypted.size() == in.size());\n    BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(\" != \") + hexin);\n\n    // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other\n    for(std::vector<unsigned char>::iterator i(in.begin()); i != in.end(); ++i)\n    {\n        std::vector<unsigned char> sub(i, in.end());\n        std::vector<unsigned char> subout;\n        CryptoPP::VectorSource encryptSource(sub, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(subout)));\n        \n        std::vector<unsigned char> subdecrypted;\n        CryptoPP::VectorSource decryptSource(subout, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::VectorSink(subdecrypted)));\n\n        BOOST_CHECK(decrypted.size() == in.size());\n        BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(\" != \") + HexStr(sub));\n    }\n}\n\nstatic void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)\n{\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    std::vector<unsigned char> iv = ParseHex(hexiv);\n    std::vector<unsigned char> in = ParseHex(hexin);\n    std::vector<unsigned char> correctout = ParseHex(hexout);\n    std::vector<unsigned char> realout;\n\n    // Encrypt the plaintext and verify that it equals the cipher\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc;\n    enc.SetKeyWithIV(&key[0], key.size(), &iv[0]);\n\n    if (pad)\n    {\n        CryptoPP::VectorSource s(in, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(realout)));\n    }\n    else\n    {\n        realout.resize(in.size());\n        enc.ProcessData(&realout[0], &in[0], in.size());\n    }    \n    BOOST_CHECK(realout.size() == correctout.size());\n    BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(\" != \") + hexout);\n\n    // Decrypt the cipher and verify that it equals the plaintext\n    std::vector<unsigned char> decrypted;\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec;\n    dec.SetKeyWithIV(&key[0], key.size(), &iv[0]);\n    if (pad)\n    {\n        CryptoPP::VectorSource s(correctout, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::VectorSink(decrypted)));\n    }\n    else\n    {\n        decrypted.resize(correctout.size());\n        dec.ProcessData(&decrypted[0], &correctout[0], correctout.size());\n    }\n    BOOST_CHECK(decrypted.size() == in.size());\n    BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(\" != \") + hexin);\n\n    // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other\n    for(std::vector<unsigned char>::iterator i(in.begin()); i != in.end(); ++i)\n    {\n        std::vector<unsigned char> sub(i, in.end());\n        std::vector<unsigned char> subout;\n        CryptoPP::VectorSource encryptSource(sub, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(subout)));\n        \n        std::vector<unsigned char> subdecrypted;\n        CryptoPP::VectorSource decryptSource(subout, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::VectorSink(subdecrypted)));\n        BOOST_CHECK(decrypted.size() == in.size());\n        BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(\" != \") + HexStr(sub));\n    }\n}\n\nstatic void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)\n{\n    std::vector<unsigned char> key = ParseHex(hexkey);\n    std::vector<unsigned char> m = ParseHex(hex_message);\n    ChaCha20 rng(key.data(), key.size());\n    rng.SetIV(nonce);\n    rng.Seek(seek);\n    std::vector<unsigned char> out = ParseHex(hexout);\n    std::vector<unsigned char> outres;\n    outres.resize(out.size());\n    assert(hex_message.empty() || m.size() == out.size());\n\n    // perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream\n    if (!hex_message.empty()) {\n        rng.Crypt(m.data(), outres.data(), outres.size());\n    } else {\n        rng.Keystream(outres.data(), outres.size());\n    }\n    BOOST_CHECK(out == outres);\n    if (!hex_message.empty()) {\n        // Manually XOR with the keystream and compare the output\n        rng.SetIV(nonce);\n        rng.Seek(seek);\n        std::vector<unsigned char> only_keystream(outres.size());\n        rng.Keystream(only_keystream.data(), only_keystream.size());\n        for (size_t i = 0; i != m.size(); i++) {\n            outres[i] = m[i] ^ only_keystream[i];\n        }\n        BOOST_CHECK(out == outres);\n    }\n}\n\nstatic std::string LongTestString()\n{\n    std::string ret;\n    for (int i = 0; i < 200000; i++) {\n        ret += (char)(i);\n        ret += (char)(i >> 4);\n        ret += (char)(i >> 8);\n        ret += (char)(i >> 12);\n        ret += (char)(i >> 16);\n    }\n    return ret;\n}\n\nconst std::string test1 = LongTestString();\n\nBOOST_AUTO_TEST_CASE(ripemd160_testvectors) {\n    TestRIPEMD160(\"\", \"9c1185a5c5e9fc54612808977ee8f548b2258d31\");\n    TestRIPEMD160(\"abc\", \"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc\");\n    TestRIPEMD160(\"message digest\", \"5d0689ef49d2fae572b881b123a85ffa21595f36\");\n    TestRIPEMD160(\"secure hash algorithm\", \"20397528223b6a5f4cbc2808aba0464e645544f9\");\n    TestRIPEMD160(\"RIPEMD160 is considered to be safe\", \"a7d78608c7af8a8e728778e81576870734122b66\");\n    TestRIPEMD160(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n                  \"12a053384a9c0c88e405a06c27dcf49ada62eb2b\");\n    TestRIPEMD160(\"For this sample, this 63-byte string will be used as input data\",\n                  \"de90dbfee14b63fb5abf27c2ad4a82aaa5f27a11\");\n    TestRIPEMD160(\"This is exactly 64 bytes long, not counting the terminating byte\",\n                  \"eda31d51d3a623b81e19eb02e24ff65d27d67b37\");\n    TestRIPEMD160(std::string(1000000, 'a'), \"52783243c1697bdbe16d37f97f68f08325dc1528\");\n    TestRIPEMD160(test1, \"464243587bd146ea835cdf57bdae582f25ec45f1\");\n}\n\nBOOST_AUTO_TEST_CASE(sha1_testvectors) {\n    TestSHA1(\"\", \"da39a3ee5e6b4b0d3255bfef95601890afd80709\");\n    TestSHA1(\"abc\", \"a9993e364706816aba3e25717850c26c9cd0d89d\");\n    TestSHA1(\"message digest\", \"c12252ceda8be8994d5fa0290a47231c1d16aae3\");\n    TestSHA1(\"secure hash algorithm\", \"d4d6d2f0ebe317513bbd8d967d89bac5819c2f60\");\n    TestSHA1(\"SHA1 is considered to be safe\", \"f2b6650569ad3a8720348dd6ea6c497dee3a842a\");\n    TestSHA1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n             \"84983e441c3bd26ebaae4aa1f95129e5e54670f1\");\n    TestSHA1(\"For this sample, this 63-byte string will be used as input data\",\n             \"4f0ea5cd0585a23d028abdc1a6684e5a8094dc49\");\n    TestSHA1(\"This is exactly 64 bytes long, not counting the terminating byte\",\n             \"fb679f23e7d1ce053313e66e127ab1b444397057\");\n    TestSHA1(std::string(1000000, 'a'), \"34aa973cd4c4daa4f61eeb2bdbad27316534016f\");\n    TestSHA1(test1, \"b7755760681cbfd971451668f32af5774f4656b5\");\n}\n\nBOOST_AUTO_TEST_CASE(sha256_testvectors) {\n    TestSHA256(\"\", \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\");\n    TestSHA256(\"abc\", \"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\");\n    TestSHA256(\"message digest\",\n               \"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650\");\n    TestSHA256(\"secure hash algorithm\",\n               \"f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d\");\n    TestSHA256(\"SHA256 is considered to be safe\",\n               \"6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630\");\n    TestSHA256(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n               \"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1\");\n    TestSHA256(\"For this sample, this 63-byte string will be used as input data\",\n               \"f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342\");\n    TestSHA256(\"This is exactly 64 bytes long, not counting the terminating byte\",\n               \"ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8\");\n    TestSHA256(\"As Bitcoin relies on 80 byte header hashes, we want to have an example for that.\",\n               \"7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743\");\n    TestSHA256(std::string(1000000, 'a'),\n               \"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0\");\n    TestSHA256(test1, \"a316d55510b49662420f49d145d42fb83f31ef8dc016aa4e32df049991a91e26\");\n}\n\nBOOST_AUTO_TEST_CASE(sha512_testvectors) {\n    TestSHA512(\"\",\n               \"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce\"\n               \"47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\");\n    TestSHA512(\"abc\",\n               \"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\"\n               \"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f\");\n    TestSHA512(\"message digest\",\n               \"107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f33\"\n               \"09e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c\");\n    TestSHA512(\"secure hash algorithm\",\n               \"7746d91f3de30c68cec0dd693120a7e8b04d8073cb699bdce1a3f64127bca7a3\"\n               \"d5db502e814bb63c063a7a5043b2df87c61133395f4ad1edca7fcf4b30c3236e\");\n    TestSHA512(\"SHA512 is considered to be safe\",\n               \"099e6468d889e1c79092a89ae925a9499b5408e01b66cb5b0a3bd0dfa51a9964\"\n               \"6b4a3901caab1318189f74cd8cf2e941829012f2449df52067d3dd5b978456c2\");\n    TestSHA512(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",\n               \"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c335\"\n               \"96fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445\");\n    TestSHA512(\"For this sample, this 63-byte string will be used as input data\",\n               \"b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e\"\n               \"6663cf6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766\");\n    TestSHA512(\"This is exactly 64 bytes long, not counting the terminating byte\",\n               \"70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a38\"\n               \"7d245870e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030\");\n    TestSHA512(\"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno\"\n               \"ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu\",\n               \"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018\"\n               \"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909\");\n    TestSHA512(std::string(1000000, 'a'),\n               \"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb\"\n               \"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b\");\n    TestSHA512(test1,\n               \"40cac46c147e6131c5193dd5f34e9d8bb4951395f27b08c558c65ff4ba2de594\"\n               \"37de8c3ef5459d76a52cedc02dc499a3c9ed9dedbfb3281afd9653b8a112fafc\");\n}\n\nBOOST_AUTO_TEST_CASE(hmac_sha256_testvectors) {\n    // test cases 1, 2, 3, 4, 6 and 7 of RFC 4231\n    TestHMACSHA256(\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\",\n                   \"4869205468657265\",\n                   \"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7\");\n    TestHMACSHA256(\"4a656665\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843\");\n    TestHMACSHA256(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n                   \"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"\n                   \"dddddddddddddddddddddddddddddddddddd\",\n                   \"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe\");\n    TestHMACSHA256(\"0102030405060708090a0b0c0d0e0f10111213141516171819\",\n                   \"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\"\n                   \"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\",\n                   \"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b\");\n    TestHMACSHA256(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaa\",\n                   \"54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a\"\n                   \"65204b6579202d2048617368204b6579204669727374\",\n                   \"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54\");\n    TestHMACSHA256(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaa\",\n                   \"5468697320697320612074657374207573696e672061206c6172676572207468\"\n                   \"616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074\"\n                   \"68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565\"\n                   \"647320746f20626520686173686564206265666f7265206265696e6720757365\"\n                   \"642062792074686520484d414320616c676f726974686d2e\",\n                   \"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2\");\n    // Test case with key length 63 bytes.\n    TestHMACSHA256(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"9de4b546756c83516720a4ad7fe7bdbeac4298c6fdd82b15f895a6d10b0769a6\");\n    // Test case with key length 64 bytes.\n    TestHMACSHA256(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"528c609a4c9254c274585334946b7c2661bad8f1fc406b20f6892478d19163dd\");\n    // Test case with key length 65 bytes.\n    TestHMACSHA256(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"d06af337f359a2330deffb8e3cbe4b5b7aa8ca1f208528cdbd245d5dc63c4483\");\n}\n\nBOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {\n    // test cases 1, 2, 3, 4, 6 and 7 of RFC 4231\n    TestHMACSHA512(\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\",\n                   \"4869205468657265\",\n                   \"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\"\n                   \"daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854\");\n    TestHMACSHA512(\"4a656665\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\"\n                   \"9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737\");\n    TestHMACSHA512(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n                   \"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"\n                   \"dddddddddddddddddddddddddddddddddddd\",\n                   \"fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\"\n                   \"bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb\");\n    TestHMACSHA512(\"0102030405060708090a0b0c0d0e0f10111213141516171819\",\n                   \"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\"\n                   \"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\",\n                   \"b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\"\n                   \"a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd\");\n    TestHMACSHA512(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaa\",\n                   \"54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a\"\n                   \"65204b6579202d2048617368204b6579204669727374\",\n                   \"80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\"\n                   \"6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598\");\n    TestHMACSHA512(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n                   \"aaaaaa\",\n                   \"5468697320697320612074657374207573696e672061206c6172676572207468\"\n                   \"616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074\"\n                   \"68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565\"\n                   \"647320746f20626520686173686564206265666f7265206265696e6720757365\"\n                   \"642062792074686520484d414320616c676f726974686d2e\",\n                   \"e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\"\n                   \"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58\");\n    // Test case with key length 127 bytes.\n    TestHMACSHA512(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"267424dfb8eeb999f3e5ec39a4fe9fd14c923e6187e0897063e5c9e02b2e624a\"\n                   \"c04413e762977df71a9fb5d562b37f89dfdfb930fce2ed1fa783bbc2a203d80e\");\n    // Test case with key length 128 bytes.\n    TestHMACSHA512(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"43aaac07bb1dd97c82c04df921f83b16a68d76815cd1a30d3455ad43a3d80484\"\n                   \"2bb35462be42cc2e4b5902de4d204c1c66d93b47d1383e3e13a3788687d61258\");\n    // Test case with key length 129 bytes.\n    TestHMACSHA512(\"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\"\n                   \"4a\",\n                   \"7768617420646f2079612077616e7420666f72206e6f7468696e673f\",\n                   \"0b273325191cfc1b4b71d5075c8fcad67696309d292b1dad2cd23983a35feb8e\"\n                   \"fb29795e79f2ef27f68cb1e16d76178c307a67beaad9456fac5fdffeadb16e2c\");\n}\n\nBOOST_AUTO_TEST_CASE(aes_testvectors) {\n    // AES test vectors from FIPS 197.\n    TestAES256(\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\", \"00112233445566778899aabbccddeeff\", \"8ea2b7ca516745bfeafc49904b496089\");\n\n    // AES-ECB test vectors from NIST sp800-38a.\n    TestAES256(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \"6bc1bee22e409f96e93d7e117393172a\", \"f3eed1bdb5d2a03c064b5a7e3db181f8\");\n    TestAES256(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \"ae2d8a571e03ac9c9eb76fac45af8e51\", \"591ccb10d410ed26dc5ba74a31362870\");\n    TestAES256(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \"30c81c46a35ce411e5fbc1191a0a52ef\", \"b6ed21b99ca6f4f9f153e7b1beafed1d\");\n    TestAES256(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \"f69f2445df4f9b17ad2b417be66c3710\", \"23304b7a39f9f3ff067d8d8f9e24ecc7\");\n}\n\nBOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {\n    // NIST AES CBC 256-bit encryption test-vectors\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"000102030405060708090A0B0C0D0E0F\", false, \"6bc1bee22e409f96e93d7e117393172a\", \\\n                  \"f58c4c04d6e5f1ba779eabfb5f7bfbd6\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"F58C4C04D6E5F1BA779EABFB5F7BFBD6\", false, \"ae2d8a571e03ac9c9eb76fac45af8e51\", \\\n                  \"9cfc4e967edb808d679f777bc6702c7d\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"9CFC4E967EDB808D679F777BC6702C7D\", false, \"30c81c46a35ce411e5fbc1191a0a52ef\",\n                  \"39f23369a9d9bacfa530e26304231461\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"39F23369A9D9BACFA530E26304231461\", false, \"f69f2445df4f9b17ad2b417be66c3710\", \\\n                  \"b2eb05e2c39be9fcda6c19078c6a9d1b\");\n\n    // The same vectors with padding enabled\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"000102030405060708090A0B0C0D0E0F\", true, \"6bc1bee22e409f96e93d7e117393172a\", \\\n                  \"f58c4c04d6e5f1ba779eabfb5f7bfbd6485a5c81519cf378fa36d42b8547edc0\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"F58C4C04D6E5F1BA779EABFB5F7BFBD6\", true, \"ae2d8a571e03ac9c9eb76fac45af8e51\", \\\n                  \"9cfc4e967edb808d679f777bc6702c7d3a3aa5e0213db1a9901f9036cf5102d2\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"9CFC4E967EDB808D679F777BC6702C7D\", true, \"30c81c46a35ce411e5fbc1191a0a52ef\",\n                  \"39f23369a9d9bacfa530e263042314612f8da707643c90a6f732b3de1d3f5cee\");\n    TestAES256CBC(\"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4\", \\\n                  \"39F23369A9D9BACFA530E26304231461\", true, \"f69f2445df4f9b17ad2b417be66c3710\", \\\n                  \"b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644\");\n}\n\n\nBOOST_AUTO_TEST_CASE(chacha20_testvector)\n{\n    // Test vector from RFC 7539\n\n    // test encryption\n    TestChaCha20(\"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756\"\n                 \"c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e\"\n                 \"20776f756c642062652069742e\",\n                 \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\", 0x4a000000UL, 1,\n                 \"6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d\"\n                 \"624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74\"\n                 \"a35be6b40b8eedf2785e42874d\"\n                 );\n\n    // test keystream output\n    TestChaCha20(\"\", \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\", 0x4a000000UL, 1,\n                 \"224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb\"\n                 \"a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a\"\n                 \"832c89c167eacd901d7e2bf363\");\n\n    // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7\n    TestChaCha20(\"\", \"0000000000000000000000000000000000000000000000000000000000000000\", 0, 0,\n                 \"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b\"\n                 \"8f41518a11cc387b669b2ee6586\");\n    TestChaCha20(\"\", \"0000000000000000000000000000000000000000000000000000000000000001\", 0, 0,\n                 \"4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79\"\n                 \"2b1c43fea817e9ad275ae546963\");\n    TestChaCha20(\"\", \"0000000000000000000000000000000000000000000000000000000000000000\", 0x0100000000000000ULL, 0,\n                 \"de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770\"\n                 \"62eb7a0433e445f41e3\");\n    TestChaCha20(\"\", \"0000000000000000000000000000000000000000000000000000000000000000\", 1, 0,\n                 \"ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4\"\n                 \"97a0b466e7d6bbdb0041b2f586b\");\n    TestChaCha20(\"\", \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\", 0x0706050403020100ULL, 0,\n                 \"f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b\"\n                 \"e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1\"\n                 \"18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5\"\n                 \"a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5\"\n                 \"360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78\"\n                 \"fab78c9\");\n}\n\nstatic void TestScrypt(const char* passwd, const char* salt, uint64_t N, uint32_t r, uint32_t p, uint32_t dkLen, std::vector<uint8_t> expectedResult)\n{\n    std::vector<uint8_t> buf;\n    buf.resize(dkLen);\n    BOOST_CHECK (crypto_scrypt((const uint8_t*)passwd, strlen(passwd), (const uint8_t*)salt, strlen(salt), N, r, p, (uint8_t*)&buf[0], dkLen) == 0);\n    BOOST_CHECK (memcmp(&expectedResult[0], &buf[0], dkLen) == 0);\n}\n\nstatic void TestPBKDF2_SHA256(const char* passwd, const char* salt, uint64_t c, uint32_t dkLen, std::vector<uint8_t> expectedResult)\n{\n    std::vector<uint8_t> buf;\n    buf.resize(dkLen);\n    PBKDF2_SHA256((uint8_t*)passwd, strlen(passwd), (uint8_t*)salt, strlen(salt), c, (uint8_t *)&buf[0], dkLen);\n    BOOST_CHECK (memcmp(&expectedResult[0], &buf[0], dkLen) == 0);\n}\n\nBOOST_AUTO_TEST_CASE(scrypt_testvector)\n{\n    // Test cases from tarsnap (original scrypt authors repo)\n    // Superset of RFC 7914 test vectors\n    TestScrypt( \"\", \"\", 16, 1, 1, 64, std::vector<uint8_t>{0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97, 0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42, 0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8, 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17, 0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06} );\n    TestScrypt( \"password\", \"NaCl\", 1024, 8, 16, 64, std::vector<uint8_t>{0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40} );\n    TestScrypt( \"pleaseletmein\", \"SodiumChloride\", 16384, 8, 1, 64, std::vector<uint8_t>{0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb, 0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2, 0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf, 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9, 0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87} );\n    TestScrypt( \"pleaseletmein\", \"SodiumChloride\", 1048576, 8, 1, 64, std::vector<uint8_t>{0x21, 0x01, 0xcb, 0x9b, 0x6a, 0x51, 0x1a, 0xae, 0xad, 0xdb, 0xbe, 0x09, 0xcf, 0x70, 0xf8, 0x81, 0xec, 0x56, 0x8d, 0x57, 0x4a, 0x2f, 0xfd, 0x4d, 0xab, 0xe5, 0xee, 0x98, 0x20, 0xad, 0xaa, 0x47, 0x8e, 0x56, 0xfd, 0x8f, 0x4b, 0xa5, 0xd0, 0x9f, 0xfa, 0x1c, 0x6d, 0x92, 0x7c, 0x40, 0xf4, 0xc3, 0x37, 0x30, 0x40, 0x49, 0xe8, 0xa9, 0x52, 0xfb, 0xcb, 0xf4, 0x5c, 0x6f, 0xa7, 0x7a, 0x41, 0xa4} );\n    TestScrypt( \"pleaseletmein\", \"SodiumChloride\", 16, 8, 1, 64, std::vector<uint8_t>{0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09, 0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16, 0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf, 0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf, 0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b, 0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11, 0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7, 0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b} );\n\n    // Additional scrypt test vectors from https://github.com/ricmoo/scrypt-js\n    TestScrypt(\"password\", \"ricmoo\", 262144, 8, 1, 32, {0xe2, 0x86, 0xed, 0x02, 0x98, 0x80, 0x8c, 0x0b, 0x4b, 0xb4, 0x27, 0x2c, 0xe9, 0x47, 0x09, 0x1b, 0x0d, 0xa0, 0x6b, 0xb5, 0x30, 0xc4, 0xcb, 0xab, 0x39, 0x23, 0xe4, 0x4f, 0xf4, 0x8b, 0xbc, 0x25} );\n    TestScrypt(\"very-log-password-over-64-bytes-0123456789012345678901234567890123456789012345678901234567890123\", \"SodiumChloride\", 1048576, 8, 1, 64, {0x4b, 0x6e, 0xab, 0x51, 0x64, 0xab, 0xdf, 0xc2, 0x96, 0x6a, 0xd0, 0x95, 0x4a, 0xe9, 0x35, 0x2b, 0xac, 0x57, 0xcd, 0x95, 0x3b, 0x79, 0x1e, 0xef, 0xf4, 0x55, 0xd3, 0xee, 0xd9, 0x58, 0x02, 0xa3, 0x1f, 0xd4, 0x98, 0xb5, 0x2d, 0xa4, 0x30, 0xe6, 0x1e, 0xd2, 0xaa, 0xab, 0xd5, 0xbc, 0x8b, 0x1a, 0x8e, 0xee, 0xe6, 0x6e, 0xd1, 0x1c, 0x2b, 0xd6, 0x09, 0x87, 0x7b, 0xe4, 0x02, 0x10, 0xe9, 0xa0} );\n    TestScrypt(\"pleaseletmein\", \"very-long-password-over-64-bytes-0123456789012345678901234567890123456789012345678901234567890123\", 1048576, 8, 1, 64, {0xec, 0x1d, 0x40, 0x3e, 0x82, 0xc0, 0x12, 0x54, 0xb9, 0xc5, 0xba, 0x84, 0xac, 0x06, 0x95, 0x8b, 0x32, 0x3a, 0xc9, 0xf5, 0x26, 0x65, 0x02, 0x4f, 0x1e, 0xa6, 0xed, 0x1e, 0xdf, 0x7a, 0xa6, 0x39, 0xe6, 0x98, 0x48, 0x1e, 0x4c, 0xe4, 0xbf, 0x59, 0xf7, 0xab, 0xc3, 0xeb, 0x8c, 0x01, 0xde, 0x0b, 0xa0, 0x94, 0xfe, 0x24, 0x90, 0xe3, 0xfa, 0xe6, 0xd2, 0x9f, 0x5c, 0x9e, 0x5f, 0x69, 0x78, 0x68} );\n    TestScrypt(\"very-log-password-over-64-bytes-0123456789012345678901234567890123456789012345678901234567890123\", \"very-long-password-over-64-bytes-0123456789012345678901234567890123456789012345678901234567890123\", 1048576, 8, 1, 64, {0xbd, 0x27, 0x85, 0xea, 0xf7, 0x4e, 0x4e, 0x18, 0x83, 0xa3, 0xdd, 0x92, 0x33, 0x63, 0x46, 0xd4, 0x80, 0x20, 0x0b, 0x7b, 0x6d, 0x0b, 0x79, 0x04, 0x36, 0x9c, 0x60, 0x75, 0x57, 0xaa, 0x2b, 0x14, 0xb4, 0xcd, 0xc9, 0x0f, 0xc8, 0xb8, 0xf0, 0xd4, 0x90, 0x62, 0x03, 0xa5, 0xbd, 0x6e, 0x06, 0x4a, 0xdd, 0x86, 0xaa, 0xc9, 0xac, 0x2f, 0xc4, 0x77, 0x7a, 0x5a, 0x68, 0x3a, 0x0e, 0xd4, 0x0e, 0xf9} );\n\n    // RFC 7914 test vectors\n    TestPBKDF2_SHA256(\"passwd\", \"salt\", 1, 64, std::vector<uint8_t>{0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f, 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05, 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65, 0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc, 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45, 0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31, 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5, 0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83} );\n    TestPBKDF2_SHA256(\"Password\", \"NaCl\", 80000, 64, {0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21, 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9, 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14, 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56, 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54, 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17, 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78, 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d} );\n}\n\nBOOST_AUTO_TEST_CASE(countbits_tests)\n{\n    FastRandomContext ctx;\n    for (unsigned int i = 0; i <= 64; ++i) {\n        if (i == 0) {\n            // Check handling of zero.\n            BOOST_CHECK_EQUAL(CountBits(0), 0U);\n        } else if (i < 10) {\n            for (uint64_t j = (uint64_t)1 << (i - 1); (j >> i) == 0; ++j) {\n                // Exhaustively test up to 10 bits\n                BOOST_CHECK_EQUAL(CountBits(j), i);\n            }\n        } else {\n            for (int k = 0; k < 1000; k++) {\n                // Randomly test 1000 samples of each length above 10 bits.\n                uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1);\n                BOOST_CHECK_EQUAL(CountBits(j), i);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/cuckoocache_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#include <boost/test/unit_test.hpp>\n#include \"cuckoocache.h\"\n#include \"script/sigcache.h\"\n#include \"test/test.h\"\n#include \"random.h\"\n#include <thread>\n\n/** Test Suite for CuckooCache\n *\n *  1) All tests should have a deterministic result (using insecure rand\n *  with deterministic seeds)\n *  2) Some test methods are templated to allow for easier testing\n *  against new versions / comparing\n *  3) Results should be treated as a regression test, i.e., did the behavior\n *  change significantly from what was expected. This can be OK, depending on\n *  the nature of the change, but requires updating the tests to reflect the new\n *  expected behavior. For example improving the hit rate may cause some tests\n *  using BOOST_CHECK_CLOSE to fail.\n *\n */\nFastRandomContext local_rand_ctx(true);\n\nBOOST_AUTO_TEST_SUITE(cuckoocache_tests);\n\n\n/** insecure_GetRandHash fills in a uint256 from local_rand_ctx\n */\nvoid insecure_GetRandHash(uint256& t)\n{\n    uint32_t* ptr = (uint32_t*)t.begin();\n    for (uint8_t j = 0; j < 8; ++j)\n        *(ptr++) = local_rand_ctx.rand32();\n}\n\n\n\n/* Test that no values not inserted into the cache are read out of it.\n *\n * There are no repeats in the first 200000 insecure_GetRandHash calls\n */\nBOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)\n{\n    local_rand_ctx = FastRandomContext(true);\n    CuckooCache::cache<uint256, SignatureCacheHasher> cc{};\n    size_t megabytes = 4;\n    cc.setup_bytes(megabytes << 20);\n    uint256 v;\n    for (int x = 0; x < 100000; ++x) {\n        insecure_GetRandHash(v);\n        cc.insert(v);\n    }\n    for (int x = 0; x < 100000; ++x) {\n        insecure_GetRandHash(v);\n        BOOST_CHECK(!cc.contains(v, false));\n    }\n};\n\n/** This helper returns the hit rate when megabytes*load worth of entries are\n * inserted into a megabytes sized cache\n */\ntemplate <typename Cache>\ndouble test_cache(size_t megabytes, double load)\n{\n    local_rand_ctx = FastRandomContext(true);\n    std::vector<uint256> hashes;\n    Cache set{};\n    size_t bytes = megabytes * (1 << 20);\n    set.setup_bytes(bytes);\n    uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));\n    hashes.resize(n_insert);\n    for (uint32_t i = 0; i < n_insert; ++i) {\n        uint32_t* ptr = (uint32_t*)hashes[i].begin();\n        for (uint8_t j = 0; j < 8; ++j)\n            *(ptr++) = local_rand_ctx.rand32();\n    }\n    /** We make a copy of the hashes because future optimizations of the\n     * cuckoocache may overwrite the inserted element, so the test is\n     * \"future proofed\".\n     */\n    std::vector<uint256> hashes_insert_copy = hashes;\n    /** Do the insert */\n    for (uint256& h : hashes_insert_copy)\n        set.insert(h);\n    /** Count the hits */\n    uint32_t count = 0;\n    for (uint256& h : hashes)\n        count += set.contains(h, false);\n    double hit_rate = ((double)count) / ((double)n_insert);\n    return hit_rate;\n}\n\n/** The normalized hit rate for a given load.\n *\n * The semantics are a little confusing, so please see the below\n * explanation.\n *\n * Examples:\n *\n * 1) at load 0.5, we expect a perfect hit rate, so we multiply by\n * 1.0\n * 2) at load 2.0, we expect to see half the entries, so a perfect hit rate\n * would be 0.5. Therefore, if we see a hit rate of 0.4, 0.4*2.0 = 0.8 is the\n * normalized hit rate.\n *\n * This is basically the right semantics, but has a bit of a glitch depending on\n * how you measure around load 1.0 as after load 1.0 your normalized hit rate\n * becomes effectively perfect, ignoring freshness.\n */\ndouble normalize_hit_rate(double hits, double load)\n{\n    return hits * std::max(load, 1.0);\n}\n\n/** Check the hit rate on loads ranging from 0.1 to 2.0 */\nBOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok)\n{\n    /** Arbitrarily selected Hit Rate threshold that happens to work for this test\n     * as a lower bound on performance.\n     */\n    double HitRateThresh = 0.98;\n    size_t megabytes = 4;\n    for (double load = 0.1; load < 2; load *= 2) {\n        double hits = test_cache<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes, load);\n        BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh);\n    }\n}\n\n\n/** This helper checks that erased elements are preferentially inserted onto and\n * that the hit rate of \"fresher\" keys is reasonable*/\ntemplate <typename Cache>\nvoid test_cache_erase(size_t megabytes)\n{\n    double load = 1;\n    local_rand_ctx = FastRandomContext(true);\n    std::vector<uint256> hashes;\n    Cache set{};\n    size_t bytes = megabytes * (1 << 20);\n    set.setup_bytes(bytes);\n    uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));\n    hashes.resize(n_insert);\n    for (uint32_t i = 0; i < n_insert; ++i) {\n        uint32_t* ptr = (uint32_t*)hashes[i].begin();\n        for (uint8_t j = 0; j < 8; ++j)\n            *(ptr++) = local_rand_ctx.rand32();\n    }\n    /** We make a copy of the hashes because future optimizations of the\n     * cuckoocache may overwrite the inserted element, so the test is\n     * \"future proofed\".\n     */\n    std::vector<uint256> hashes_insert_copy = hashes;\n\n    /** Insert the first half */\n    for (uint32_t i = 0; i < (n_insert / 2); ++i)\n        set.insert(hashes_insert_copy[i]);\n    /** Erase the first quarter */\n    for (uint32_t i = 0; i < (n_insert / 4); ++i)\n        set.contains(hashes[i], true);\n    /** Insert the second half */\n    for (uint32_t i = (n_insert / 2); i < n_insert; ++i)\n        set.insert(hashes_insert_copy[i]);\n\n    /** elements that we marked erased but that are still there */\n    size_t count_erased_but_contained = 0;\n    /** elements that we did not erase but are older */\n    size_t count_stale = 0;\n    /** elements that were most recently inserted */\n    size_t count_fresh = 0;\n\n    for (uint32_t i = 0; i < (n_insert / 4); ++i)\n        count_erased_but_contained += set.contains(hashes[i], false);\n    for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)\n        count_stale += set.contains(hashes[i], false);\n    for (uint32_t i = (n_insert / 2); i < n_insert; ++i)\n        count_fresh += set.contains(hashes[i], false);\n\n    double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);\n    double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);\n    double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);\n\n    // Check that our hit_rate_fresh is perfect\n    BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0);\n    // Check that we have a more than 2x better hit rate on stale elements than\n    // erased elements.\n    BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);\n}\n\nBOOST_AUTO_TEST_CASE(cuckoocache_erase_ok)\n{\n    size_t megabytes = 4;\n    test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);\n}\n\ntemplate <typename Cache>\nvoid test_cache_erase_parallel(size_t megabytes)\n{\n    double load = 1;\n    local_rand_ctx = FastRandomContext(true);\n    std::vector<uint256> hashes;\n    Cache set{};\n    size_t bytes = megabytes * (1 << 20);\n    set.setup_bytes(bytes);\n    uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));\n    hashes.resize(n_insert);\n    for (uint32_t i = 0; i < n_insert; ++i) {\n        uint32_t* ptr = (uint32_t*)hashes[i].begin();\n        for (uint8_t j = 0; j < 8; ++j)\n            *(ptr++) = local_rand_ctx.rand32();\n    }\n    /** We make a copy of the hashes because future optimizations of the\n     * cuckoocache may overwrite the inserted element, so the test is\n     * \"future proofed\".\n     */\n    std::vector<uint256> hashes_insert_copy = hashes;\n    boost::shared_mutex mtx;\n\n    {\n        /** Grab lock to make sure we release inserts */\n        boost::unique_lock<boost::shared_mutex> l(mtx);\n        /** Insert the first half */\n        for (uint32_t i = 0; i < (n_insert / 2); ++i)\n            set.insert(hashes_insert_copy[i]);\n    }\n\n    /** Spin up 3 threads to run contains with erase.\n     */\n    std::vector<std::thread> threads;\n    /** Erase the first quarter */\n    for (uint32_t x = 0; x < 3; ++x)\n        /** Each thread is emplaced with x copy-by-value\n        */\n        threads.emplace_back([&, x] {\n            boost::shared_lock<boost::shared_mutex> l(mtx);\n            size_t ntodo = (n_insert/4)/3;\n            size_t start = ntodo*x;\n            size_t end = ntodo*(x+1);\n            for (uint32_t i = start; i < end; ++i)\n                set.contains(hashes[i], true);\n        });\n\n    /** Wait for all threads to finish\n     */\n    for (std::thread& t : threads)\n        t.join();\n    /** Grab lock to make sure we observe erases */\n    boost::unique_lock<boost::shared_mutex> l(mtx);\n    /** Insert the second half */\n    for (uint32_t i = (n_insert / 2); i < n_insert; ++i)\n        set.insert(hashes_insert_copy[i]);\n\n    /** elements that we marked erased but that are still there */\n    size_t count_erased_but_contained = 0;\n    /** elements that we did not erase but are older */\n    size_t count_stale = 0;\n    /** elements that were most recently inserted */\n    size_t count_fresh = 0;\n\n    for (uint32_t i = 0; i < (n_insert / 4); ++i)\n        count_erased_but_contained += set.contains(hashes[i], false);\n    for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i)\n        count_stale += set.contains(hashes[i], false);\n    for (uint32_t i = (n_insert / 2); i < n_insert; ++i)\n        count_fresh += set.contains(hashes[i], false);\n\n    double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0);\n    double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0);\n    double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0);\n\n    // Check that our hit_rate_fresh is perfect\n    BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0);\n    // Check that we have a more than 2x better hit rate on stale elements than\n    // erased elements.\n    BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained);\n}\nBOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok)\n{\n    size_t megabytes = 4;\n    test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);\n}\n\n\ntemplate <typename Cache>\nvoid test_cache_generations()\n{\n    // This test checks that for a simulation of network activity, the fresh hit\n    // rate is never below 99%, and the number of times that it is worse than\n    // 99.9% are less than 1% of the time.\n    double min_hit_rate = 0.99;\n    double tight_hit_rate = 0.999;\n    double max_rate_less_than_tight_hit_rate = 0.01;\n    // A cache that meets this specification is therefore shown to have a hit\n    // rate of at least tight_hit_rate * (1 - max_rate_less_than_tight_hit_rate) +\n    // min_hit_rate*max_rate_less_than_tight_hit_rate = 0.999*99%+0.99*1% == 99.89%\n    // hit rate with low variance.\n\n    // We use deterministic values, but this test has also passed on many\n    // iterations with non-deterministic values, so it isn't \"overfit\" to the\n    // specific entropy in FastRandomContext(true) and implementation of the\n    // cache.\n    local_rand_ctx = FastRandomContext(true);\n\n    // block_activity models a chunk of network activity. n_insert elements are\n    // adde to the cache. The first and last n/4 are stored for removal later\n    // and the middle n/2 are not stored. This models a network which uses half\n    // the signatures of recently (since the last block) added transactions\n    // immediately and never uses the other half.\n    struct block_activity {\n        std::vector<uint256> reads;\n        block_activity(uint32_t n_insert, Cache& c) : reads()\n        {\n            std::vector<uint256> inserts;\n            inserts.resize(n_insert);\n            reads.reserve(n_insert / 2);\n            for (uint32_t i = 0; i < n_insert; ++i) {\n                uint32_t* ptr = (uint32_t*)inserts[i].begin();\n                for (uint8_t j = 0; j < 8; ++j)\n                    *(ptr++) = local_rand_ctx.rand32();\n            }\n            for (uint32_t i = 0; i < n_insert / 4; ++i)\n                reads.push_back(inserts[i]);\n            for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i)\n                reads.push_back(inserts[i]);\n            for (auto h : inserts)\n                c.insert(h);\n        }\n    };\n\n    const uint32_t BLOCK_SIZE = 1000;\n    // We expect window size 60 to perform reasonably given that each epoch\n    // stores 45% of the cache size (~472k).\n    const uint32_t WINDOW_SIZE = 60;\n    const uint32_t POP_AMOUNT = (BLOCK_SIZE / WINDOW_SIZE) / 2;\n    const double load = 10;\n    const size_t megabytes = 4;\n    const size_t bytes = megabytes * (1 << 20);\n    const uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));\n\n    std::vector<block_activity> hashes;\n    Cache set{};\n    set.setup_bytes(bytes);\n    hashes.reserve(n_insert / BLOCK_SIZE);\n    std::deque<block_activity> last_few;\n    uint32_t out_of_tight_tolerance = 0;\n    uint32_t total = n_insert / BLOCK_SIZE;\n    // we use the deque last_few to model a sliding window of blocks. at each\n    // step, each of the last WINDOW_SIZE block_activities checks the cache for\n    // POP_AMOUNT of the hashes that they inserted, and marks these erased.\n    for (uint32_t i = 0; i < total; ++i) {\n        if (last_few.size() == WINDOW_SIZE)\n            last_few.pop_front();\n        last_few.emplace_back(BLOCK_SIZE, set);\n        uint32_t count = 0;\n        for (auto& act : last_few)\n            for (uint32_t k = 0; k < POP_AMOUNT; ++k) {\n                count += set.contains(act.reads.back(), true);\n                act.reads.pop_back();\n            }\n        // We use last_few.size() rather than WINDOW_SIZE for the correct\n        // behavior on the first WINDOW_SIZE iterations where the deque is not\n        // full yet.\n        double hit = (double(count)) / (last_few.size() * POP_AMOUNT);\n        // Loose Check that hit rate is above min_hit_rate\n        BOOST_CHECK(hit > min_hit_rate);\n        // Tighter check, count number of times we are less than tight_hit_rate\n        // (and implicitly, greater than min_hit_rate)\n        out_of_tight_tolerance += hit < tight_hit_rate;\n    }\n    // Check that being out of tolerance happens less than\n    // max_rate_less_than_tight_hit_rate of the time\n    BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate);\n}\nBOOST_AUTO_TEST_CASE(cuckoocache_generations)\n{\n    test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>();\n}\n\nBOOST_AUTO_TEST_SUITE_END();\n"
  },
  {
    "path": "src/test/data/README.md",
    "content": "Description\n------------\n\nThis directory contains data-driven tests for various aspects of Munt.\n\n"
  },
  {
    "path": "src/test/data/base58_encode_decode.json",
    "content": "[\n[\"\", \"\"],\n[\"61\", \"2g\"],\n[\"626262\", \"a3gV\"],\n[\"636363\", \"aPEr\"],\n[\"73696d706c792061206c6f6e6720737472696e67\", \"2cFupjhnEsSn59qHXstmK2ffpLv2\"],\n[\"00eb15231dfceb60925886b67d065299925915aeb172c06647\", \"1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L\"],\n[\"516b6fcd0f\", \"ABnLTmg\"],\n[\"bf4f89001e670274dd\", \"3SEo3LWLoPntC\"],\n[\"572e4794\", \"3EFU7m\"],\n[\"ecac89cad93923c02321\", \"EJDM8drfXA6uyA\"],\n[\"10c8511e\", \"Rt5zm\"],\n[\"00000000000000000000\", \"1111111111\"]\n]\n"
  },
  {
    "path": "src/test/data/base58_keys_invalid.json",
    "content": "[\n    [\n        \"\"\n    ], \n    [\n        \"x\"\n    ], \n    [\n        \"2BrjdpcH6sMTgN9v5oM3UaPcwVJ52D8EPLw5asLEYD2U83DWmAgWQLS1bXwGV9q4i43rTi93Ug7i\"\n    ], \n    [\n        \"6FXo4KnjMyZkXt8ukXTkhT9Cuwe3MbV4MvxaMbmQSHKViZTv3PHdEL1GAe9N4y7JSGi4XckpSruWq\"\n    ], \n    [\n        \"24Uz9FfP7xDxp2LJ6eYkd7GcL2Go2ryQQS1\"\n    ], \n    [\n        \"BVSjefWefWZe6A6E3znDJRCy4Tys3zC3o3qtC5r8PJV7hvEF1bHx4RDqqRyRJTUFTfngzHgJrHF\"\n    ], \n    [\n        \"2mP8dhY9MbQyV4JhooiYXNUunBd1G2e6eQmh\"\n    ], \n    [\n        \"4L2Y5j291Wu16hd5CANiBcFCQ74Q3uy7rGJs8HGemcX1a23vMSq\"\n    ], \n    [\n        \"Epe7AAFDEsdBznie6uvErMoRx1fRxXyxQw99GMzQksrYBqgha4eedPddogNNrpcnNamM2xce4T5\"\n    ], \n    [\n        \"29hqbruEg3xDRBBwJBtTn3EfAxRoSAHQTgCwj7uAF3wDZh8w7sVk4CRphGYWnXKU8bYYHJusYUFE\"\n    ], \n    [\n        \"2hyGBBdED6w47UbDXUdD7RzxnXQQVtxDCDC\"\n    ], \n    [\n        \"G2rE72UHUHqCKScT7yVvjf771vFfqQX2puML8fuR9P5HNqeJVD\"\n    ], \n    [\n        \"Rc96A48NXvezPhScvTC1xiA8XVMuEbtBt5QqU15dDYhTxdycCbYy\"\n    ], \n    [\n        \"2Bsfu3FwWEwrfGxaRAY3aoSSWp32coEBnf6cBfT9RBuBPMtj8LqzizsZFRBuZCkTUb5hQAoQ2W1D\"\n    ], \n    [\n        \"2F1absyQwExMxyba8fJ5WLG5roABYuH6UhDq5wKvBCdprwfMLbpBWvMFv7nt3QiSMEPJ6cWuicHD\"\n    ], \n    [\n        \"5XE49zKWAqS8NkLmmV3QBBTWaVMJL7Pjtd1fyeYufUsER2StBCdax86h2QioAngaPjNCbDLxrsMZx\"\n    ], \n    [\n        \"GSUHgAJX7BBB4YGYuG12YtbLc3nif35fbBM\"\n    ], \n    [\n        \"QJRghAGYBrZA1d4bdZFAHALnBqsJv7oTSjnQqskqK6uh9p4nxkopKKUKAawCNxedQtBGqM7Md4g\"\n    ], \n    [\n        \"nQNGLC7pG891LGjg59mDQtREb1zvymDy8boAPMjXPrsBYoTeEwRHxaMPgJ1wA3CHQ2dRsEFihsm\"\n    ], \n    [\n        \"3j4Njq7RArdCjRpGNuAiEryqYxRpzHM1o3GdkktZiqeN1i9kene5\"\n    ], \n    [\n        \"5RvtpgK81xKBAWtMQ3hoeenWxgpKWZ9Vdd4NStpxas4qVsAUJ7F\"\n    ], \n    [\n        \"6EjebP7LPVNF2c7JssVFahA9CubAWvV15VACWMnX64g82fUXv5Zz1R2qJjDTyKYczGRdiHg7JoQYjo\"\n    ], \n    [\n        \"21L285fSwvFYaLSGsSvos5cb7rDZS5yrDXp\"\n    ], \n    [\n        \"25LhtjxFZyQCMapuTMRVq9AQYrcmoHq7agn\"\n    ], \n    [\n        \"6EyA9azd6gxGGyohwfdfYMdn44Wm1W4GTgwKtu3Kv9MrhPk47o4rPQweaaPZ3JcDkBTM4mS9dY1au\"\n    ], \n    [\n        \"EsAgWT7QepnDSEy4fYy6KG9D8sudGFBFcL1A9igcWitfKvaWdiPCDFmCsMkmiMWu9oDJgeuVLS9\"\n    ], \n    [\n        \"bvsBUhkN1p6vMumjq7i5Um8p8kL2H1AFHZwCB7drzmNkutRnoXz34eCAyYJPZ6WqNqyqnfggNSv\"\n    ], \n    [\n        \"QJcSyaNuiS7qwdWbWBgbHcBdBoVtyEWqbuE28NVLgvE8Yx2g4adi4KcMMsQmftANd6Fs5LUuzyb\"\n    ], \n    [\n        \"kAqM4ZzR6cJsQ3vVcGFosg9z66uLH6jPTM\"\n    ], \n    [\n        \"RapWgwKAFybzT24FnGuBoFwfGNtaY8UUgCQfdUES6vuoQToTokNE\"\n    ], \n    [\n        \"Eg7kRQGL4EhczmGwX3vnpBmBEYENWgM6LCYoq3e3Mbpn7KkgoEfH4WsGkk6Ne3SCY7VR56J5twu\"\n    ], \n    [\n        \"2cKZwPduhBLEArM6y49tRimCCc5QrydYT5H\"\n    ], \n    [\n        \"4VSuoqMXMLpUvdc15LEzvax4x2z5wKWaUZWf3Us9Y3aQ1pSg3Lg\"\n    ], \n    [\n        \"2BvjaxwcdGtw3b5ZtxCpU2uLqBJ95nYRGSj9H5h7hA3Zkm6S4CnQKJut5neBAJYGKc49txVLHQw9\"\n    ], \n    [\n        \"VZhm86MMdNW2oVfZh2MEjhRyA32Jb2efQtdGt8dzSMs2RsXw6HjM\"\n    ], \n    [\n        \"gXeCXGuZJkWWctbrGhMTMKJki2gdoD8fxL\"\n    ], \n    [\n        \"22My5N2NyvemJHhi2QptuDSM8tTbDH7Bpy6wHuBZjoVu9e8wxAsZaZ6F8JF2NnDRcXx7A1bUDED6\"\n    ], \n    [\n        \"RaU7RebT5Fyhy9dgZBaygY4aj5BQEVuvrWd68kFiNTYHUNH6Hi3w\"\n    ], \n    [\n        \"NvF26L7xs7W9ayMUq4omim8ZGu7HemQuz3xp7nqd4LRmpnLWEt3Ztb3HuXJbS6uaWLBez1JjEhj\"\n    ], \n    [\n        \"VatfKYKoKcHYWnG2Ef4bbWXZnndmVDtNpz7TXuCNp2iZZzn3Nsu4\"\n    ], \n    [\n        \"nNN3HF1fnLkMugyWsXBLxCd9uGfP6pztk7hPM5FzYRQEMKJvQ7PPgJqvoH4hgXdRpVgDq7Qtxou\"\n    ], \n    [\n        \"JepVjeVqpUHkd9wzpxdPaE4akPXRL1gBkQazMekMUaNZCQjPFo9d\"\n    ], \n    [\n        \"2BiduSpren3kRYiJRTqNjn5yCuhvmJnR2h6x7CbLG2ZnpneM7kBRzgPvgzTrA9ozhBHkBWtn2Ldk\"\n    ], \n    [\n        \"2CFN3pyKnvChueDKL3TR31JJy9YsVo8JPR6HusBgwxP85mXWmaZGwrKtyhDmoXvC9RduCue2cnUhb\"\n    ], \n    [\n        \"GVkNgjzGeGZa1S8r9JZz2pxk4koNzpPpEF\"\n    ], \n    [\n        \"gYrxJCSGfU19jzw7hmbMZsEBvFrNQcoLnA\"\n    ], \n    [\n        \"2QrxxsQh13zFGspn35Dr9Eu6m9VqAjoXRwyoGgcU8MwFhj4CMF8wEDuqnkCdxTKKDhb241GAcok6\"\n    ], \n    [\n        \"22LijFp4HudtgqD7fuDoxaVHuThC8EynAFvGSc75rfgY9gZ93oH3jhA47yeTaR2guVSD949WV65Q\"\n    ], \n    [\n        \"VffAL1Xq9jfa4aRkttSWcR8EAYNvAzHfWtgwaGHWYrZ7DXtXFf7V\"\n    ], \n    [\n        \"bxZppBavkX43LfsfFrrmrigWQg91SJeHnLsPEdcVsieB5nm8uf16NG76k3dL6Vny8hRQjchUGne\"\n    ]\n]\n"
  },
  {
    "path": "src/test/data/base58_keys_valid.json",
    "content": "[\n    [\n        \"GXUJA5vCMj9YDWCA3S2iDBmMr8QS9cmvfJ\", \n        \"957ac20c9f377d59a160f133d3acbaab73034065\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gcTWcpo6U7xKkR6afGhxr53DVdMhFgmBQS\", \n        \"715c76c35215004ebc29659fc568f967956127b8\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TBS5KALFMdgaDkCwzqWspA2jf6h6DnRub1\", \n        \"100cf07157aa093bfc62d6700c8fc55bb3b1d421\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"t9qjwf2YZQwvgm5YcUrTXSMu7hotXoXiQQ\", \n        \"1ffce326b2dc044ece6dde793ad9781638743f50\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6bBKLAb3YvdRdpZsQMHB8LggCNepALVR7fmSKB7jG7wLEqnvMzG\", \n        \"c4f56e881dcc3f5ff1fe0f6e4fb7ac0c485ba7b2300984f7b50224fdb40df651\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"Reas7bS4mv1mqULSisuB6mYwCh7uPepJtT3bnrnHXfaF1KUL57D6\", \n        \"9f0f884b445f7972a7cf478ab6e6467080e956848c16704cdcea538fedd5adef\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7UKvts6A9A5Tag5ygWZXU9HsPKnDXcWh8ZTiU5YaHLTkN4oTSjL\", \n        \"15044f0f5e759a53ade578f499041a3bf62258516bf041a840f545d9fe6779b5\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"VggQsovULL7Eu8z2fGsq4xwVWwm3nJr17cAUPT9WCb3XizeyiEMk\", \n        \"e7dd89ece9c4ff841994b97741774c830eafc7208f479b5b5f884b48f9b595ae\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GehmKBG3uN4vPL7fZkJFXLwti5t3hMmVg2\", \n        \"e4cfb71f013272ccc25ff3d55bda332056fee9d1\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gUCFpJq34FDCt8RDjJgevyTU2JHLBvgBen\", \n        \"16b8dcb4269b63329292ba56026c1d9e48b28245\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TS3bdY8ZhDdaP3QxC7wNqhiZya8SXDM27U\", \n        \"b05690ea58ad9f557449a7b1faf1e23d6b48839c\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"tKeHphy8jBPRFFnD4cPohfjbCrwW3k1eNu\", \n        \"8b83c40e5227d0f50d0dfa52fbc0c628d9828f0f\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6bXJkiMeNYfePvTGdfcMbgqWv3PoKvhviqVCb2nbRF7suPfa79n\", \n        \"f2593cdda42592572a4bed6af3ae14c2135fca928aaf94ee11716550fd7763af\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"Rcn9nJKEEyVmDAtaB96s34nkdrBNHQwphGmBuinfz3FHD8NVNUyR\", \n        \"6931499f93d5c8efe3241f1d3f60e324fb1710aa0df1d282115ec5437c64be17\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7VXTmdmEEBEgJzgX3BwXpU8dLFhUK5naaGdGzo7cuNyNwtXAPBx\", \n        \"b2e60427be063da29d50da9f0ab45fa3c53fba4b9ff2e26d5917a6b98b9fc0a9\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"VZBKPPGEKqavNgbt8VnUFF5hjdTqQLwiDhWyAUGXuExQyBiZdsPN\", \n        \"08094579d10fec734798a8f23f04bcac87eaba076e7534adb03565d63ad2b4df\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GS6WqySKFLiJ5CUBtvCm9aAzdsMAUsApos\", \n        \"5a8391b126fe405020fc1610f01a6fd74f743dc4\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gUjhHkpKtwkhUzXXRCaWcATj2AddS9jixK\", \n        \"1cab055bc1a1355526ce377e7604e1ff24900950\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TZ7YD6LJKnr2PjSvEkci98T4XoXtGwnKED\", \n        \"fdde411ae9e5def0621c5add733e48cb28c7f243\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"t9edYuFmDCLQCecn61mAk9KtKBAumdgRtS\", \n        \"1de2f9c6aa910d7668951af1fdaa074b78aca628\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6azGgnMta3tPJh2itcUiHqgh3K2gSMcN8HzgGFmyJYSMnnoyP1a\", \n        \"abe0db0605a27a1f7ce105a93058574c4f5a02dfefec7e2228a1006e3fbd1842\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"RbtwDuNZKMBXMNvgDjo6b9TaR4T5dZZ7exoYXdjXG8VF7cK3WwKN\", \n        \"4ed8456183bb755ce90a56c9125d4a8fcd94c67750f848f3932eb2475a0eb0b4\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7VFCTSG1ZyBuopuAtKVsXoyZGKhFgGF6yB1HvinpkwSx65ywzNv\", \n        \"8df8125d0189c14406c59acfa9247bc5c50ad97050e1a9855b822940ffc17076\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"VdNcdcdTWx4PUaZXxYKUD9sY5RNjuRfdnYRjMZES97swvTPFn6P3\", \n        \"8532948a40053213618c574ba742bd71d62006ddff0513bd00bd97fd49dfca5b\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GZ94SuoE1JuLjGd76z7ArevmdYhP9v7oV3\", \n        \"a7c7a96ec33cdd802df1b39039257c3c6cf07d8f\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gazYnyGf64s4fKYUg5QTSg2w2fSHRVjhKm\", \n        \"614aec36a0c057c4d95fb39825c73450f2477642\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TNix4DxSp1wMf1cCy4C2vBkrvmmLpAHYLi\", \n        \"8be755fe2750bee80510c0824c8836ad4ba8b8c3\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"tAnDHr2rVQtRXM1krc1DG8G1ejMi7o66aE\", \n        \"2a4a2da45e73189a7e06606e9865c633ddafd5fb\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6Zp8LY7FhkikSYFmjnCpNAxVxGCQmocGjTtYNFK8Ru9mkdyL4fH\", \n        \"11262feb7dbe05dbba72992055270e7de070c7e1653edd6237925bfba25fde7c\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"RdYcWZ2wYJtXZhWXD3ZnV5BarG9ZK5SaY922dXJAmGoCnqYbqVvw\", \n        \"80109b2c4ba1f7ad7ed3c09ca6dc03448d5a0b78ab7659524f4f332102283769\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7V47ee6fwpqgXu6VHDEpnpp8ceWV3DL3QeUfYntDftFwkC4G5uT\", \n        \"74cdd330b013d9fc6a855b83a876c3a74b628649a5a28f2c012c58cdf79928e2\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"VbCqYaw94jDzZWZymyrJVVCtS7vEuVQmh4vwXntqBtsqzBZ8Scoy\", \n        \"447e318477532a8d5dc3a6545ed04da73015babef501be7a032935240208e2ee\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GMonLuHiXkrUj4k4YgLSSXa47EuPTobfbS\", \n        \"2b78eeae062491a0b7a6880beead03fbb1f88bfd\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gf7oGEkTR1QaurRVgrVSWsepCpCHT1YBnp\", \n        \"8e8a6aa7cdbef8dd18cdda5717bd8c460880efe3\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TCECETg6bUhQMnevjpL3jNDKPwr1y74MnN\", \n        \"18c5d95fdcb9dfe2564d2c8c78af6c1b53013fba\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"tWDrD61EPxZbKnfa35GbuQbvrGizV3Uyb2\", \n        \"ff8dc8e70dd8b3866498b2c7d617d0b2d748a9ce\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6ad4tVTFTXJLwXySKZaehdFB76s6CTv4jAWoYxfckUHrRTQDTWa\", \n        \"7bbbbf9528e9ac872ece39794588a6a2287d20a063e9b4a4b36a6dd68dfdc2e9\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"ReqjFT7vYhtfXHpD7sEuL4wKZWi8sjnmEzZiAVgTyQFakSjqTDdy\", \n        \"a6b51dce383151891cf00fe37c01f7e343abefdfe7bc8a34c8c53569b12b3c59\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7Vr5rbiPustzLz3YJyGK33TXeTZtQKZPqXCfeNucmWzrQ76h7Aa\", \n        \"dd2eb22460663acf812c357be94bac749d7fa9c545d141c619e9b51340d98744\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"Vfn1kdUkwLYjrYPxgg7CoZPsdoqk2TM1uEWgtRasVETVzJAieDAo\", \n        \"cce8d61f10995493eda7b21cc3e11a6aca3b53324520dee4046267438afcdf50\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GXgLkTSd7o5zXkhXu18kmT2zpNv3Bc3DaQ\", \n        \"97c1e9eb2a1c17cd21ae4cfe359a59d67770b8cb\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gkQepfVgUMGevwpG9WjjML4oSavcZLCUsC\", \n        \"c893121dcbb28cd0b1c535f2187ac30aac65bc80\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"TTbNaYc5CYvccZV18XS527uAhsSJz2adQF\", \n        \"c1511b93cb9c09a19a176bea644f65d590a5cd6d\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"tG9sj4Uphg58Yv4vrtRNor5S5zbtRtsiZR\", \n        \"653ba048865896f3933881b58027e2671f3a79b6\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"6b2cdk75XGh8MgPzg7rSFf8HKGVQx3cuDaiN1oqG8Ywy2pNzRpq\", \n        \"b133548a72f828a713b6d65cd5ebc72738a5dde90b38c6d78f47d4caa0733f26\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"RbEhVmtkm4MgPXzsqFq6Udvst9obhVRH3XNtNFuPJUTWsNer4VZM\", \n        \"3b2ca6ea6f897f5188b28e9701682d7c8afa740f32080cec3b2e16f48e77ca26\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"7Vd6GXEYTitUTGUTheeQ355H24QWnhJsWQS38GZhRJNDVQw85Su\", \n        \"bfae32cddf3491a549027fa394084c34876799f3482d533dfc8e7f550d21a7f6\", \n        {\n            \"isCompressed\": false, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"VbDmsEJeNNGYfgWGAZ7KHbgBmCVqK3oi42qg3UoHtBqaqhEe7THG\", \n        \"44f989747e9f363640b28e4c97d276e72b092930d34abe8f10bc00633636989a\", \n        {\n            \"isCompressed\": true, \n            \"isPrivkey\": true, \n            \"isTestnet\": true\n        }\n    ], \n    [\n        \"GSZ7Mb2nsShag82vJDA1JkvPWpTq4cQPYY\", \n        \"5f8b312d580bdab6a61c4af8f3c7f13ebdc4adb0\", \n        {\n            \"addrType\": \"pubkey\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ], \n    [\n        \"gbcNRvwKVkJbRQFBcQrhvHSVN1HxM4k7Sz\", \n        \"68113f37175f38159481f79062362141e34a86e0\", \n        {\n            \"addrType\": \"script\", \n            \"isPrivkey\": false, \n            \"isTestnet\": false\n        }\n    ]\n]\n"
  },
  {
    "path": "src/test/data/script_tests.json",
    "content": "[\n[\"Format is: [[wit..., amount]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]\"],\n[\"It is evaluated as if there was a crediting coinbase transaction with two 0\"],\n[\"pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,\"],\n[\"followed by a spending transaction which spends this output as only input (and\"],\n[\"correct prevout hash), using the given scriptSig. All nLockTimes are 0, all\"],\n[\"nSequences are max.\"],\n\n[\"\", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Test the test: we should have an empty stack after scriptSig evaluation\"],\n[\"  \", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"and multiple spaces should not change that.\"],\n[\"   \", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"    \", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 2\", \"2 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Similarly whitespace around and between symbols\"],\n[\"1  2\", \"2 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"  1  2\", \"2 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1  2  \", \"2 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"  1  2  \", \"2 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x02 0x01 0x00\", \"\", \"P2SH,STRICTENC\", \"OK\", \"all bytes are significant, not only the last one\"],\n[\"0x09 0x00000000 0x00000000 0x10\", \"\", \"P2SH,STRICTENC\", \"OK\", \"equals zero when cast to Int64\"],\n\n[\"0x01 0x0b\", \"11 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"push 1 byte\"],\n[\"0x02 0x417a\", \"'Az' EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a\",\n \"'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"push 75 bytes\"],\n\n[\"0x4c 0x01 0x07\",\"7 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"0x4c is OP_PUSHDATA1\"],\n[\"0x4d 0x0100 0x08\",\"8 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"0x4d is OP_PUSHDATA2\"],\n[\"0x4e 0x01000000 0x09\",\"9 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"0x4e is OP_PUSHDATA4\"],\n\n[\"0x4c 0x00\",\"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x4d 0x0000\",\"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x4e 0x00000000\",\"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x4f 1000 ADD\",\"999 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0x50 ENDIF 1\", \"P2SH,STRICTENC\", \"OK\", \"0x50 is reserved (ok if not executed)\"],\n[\"0x51\", \"0x5f ADD 0x60 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"0x51 through 0x60 push 1 through 16 onto stack\"],\n[\"1\",\"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF VER ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"VER non-functional (ok if not executed)\"],\n[\"0\", \"IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"RESERVED ok in un-executed IF\"],\n\n[\"1\", \"DUP IF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"IF 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"DUP IF ELSE ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"IF 1 ELSE ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1 1\", \"IF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"IF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1\", \"IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1 0\", \"NOTIF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1\", \"NOTIF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0\", \"IF 0 ELSE 1 ELSE 0 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"Multiple ELSE's are valid and executed inverts on each ELSE encountered\"],\n[\"1\", \"IF 1 ELSE 0 ELSE ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"IF ELSE 0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'' 1\", \"IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"NOTIF 0 ELSE 1 ELSE 0 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"Multiple ELSE's are valid and execution inverts on each ELSE encountered\"],\n[\"0\", \"NOTIF 1 ELSE 0 ELSE ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"NOTIF ELSE 0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'' 0\", \"NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0\", \"IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Nested ELSE ELSE\"],\n[\"1\", \"NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0\", \"IF RETURN ENDIF 1\", \"P2SH,STRICTENC\", \"OK\", \"RETURN only works if executed\"],\n\n[\"1 1\", \"VERIFY\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0x05 0x01 0x00 0x00 0x00 0x00\", \"VERIFY\", \"P2SH,STRICTENC\", \"OK\", \"values >4 bytes can be cast to boolean\"],\n[\"1 0x01 0x80\", \"IF 0 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"negative 0 is false\"],\n\n[\"10 0 11 TOALTSTACK DROP FROMALTSTACK\", \"ADD 21 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'gavin_was_here' TOALTSTACK 11 FROMALTSTACK\", \"'gavin_was_here' EQUALVERIFY 11 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0 IFDUP\", \"DEPTH 1 EQUALVERIFY 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 IFDUP\", \"DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x05 0x0100000000 IFDUP\", \"DEPTH 2 EQUALVERIFY 0x05 0x0100000000 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"IFDUP dups non ints\"],\n[\"0 DROP\", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"DUP 1 ADD 1 EQUALVERIFY 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"NIP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"OVER DEPTH 3 EQUALVERIFY\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"ROT 22 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"ROT DROP 20 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"ROT DROP DROP 21 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"ROT ROT 21 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"22 21 20\", \"ROT ROT ROT 20 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 24 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT DROP 25 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2DROP 20 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2DROP DROP 21 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2DROP 2DROP 22 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2DROP 2DROP DROP 23 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2ROT 22 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"25 24 23 22 21 20\", \"2ROT 2ROT 2ROT 20 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"SWAP 1 EQUALVERIFY 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"13 14\", \"2DUP ROT EQUALVERIFY EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0 1 2\", \"3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 2 3 5\", \"2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 3 5 7\", \"2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"SIZE 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"SIZE 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"127\", \"SIZE 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"128\", \"SIZE 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"32767\", \"SIZE 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"32768\", \"SIZE 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"8388607\", \"SIZE 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"8388608\", \"SIZE 4 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647\", \"SIZE 4 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483648\", \"SIZE 5 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"549755813887\", \"SIZE 5 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"549755813888\", \"SIZE 6 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"9223372036854775807\", \"SIZE 8 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1\", \"SIZE 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-127\", \"SIZE 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-128\", \"SIZE 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-32767\", \"SIZE 2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-32768\", \"SIZE 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-8388607\", \"SIZE 3 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-8388608\", \"SIZE 4 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483647\", \"SIZE 4 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483648\", \"SIZE 5 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-549755813887\", \"SIZE 5 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-549755813888\", \"SIZE 6 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-9223372036854775807\", \"SIZE 8 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"SIZE 26 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"42\", \"SIZE 1 EQUALVERIFY 42 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"SIZE does not consume argument\"],\n\n[\"2 -2 ADD\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647 -2147483647 ADD\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 -1 ADD\", \"-2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0 0\",\"EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1 ADD\", \"2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1ADD\", \"2 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"111 1SUB\", \"110 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"111 1 ADD 12 SUB\", \"100 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 ABS\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"16 ABS\", \"16 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-16 ABS\", \"-16 NEGATE EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 NOT\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 NOT\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 NOT\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0NOTEQUAL\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0NOTEQUAL\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"111 0NOTEQUAL\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-111 0NOTEQUAL\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1 BOOLAND\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 BOOLAND\", \"NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 BOOLAND\", \"NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0 BOOLAND\", \"NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"16 17 BOOLAND\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 1 BOOLOR\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 BOOLOR\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 BOOLOR\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0 BOOLOR\", \"NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"16 17 BOOLOR\", \"NOP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10 1 ADD\", \"NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10 1 ADD\", \"NUMEQUALVERIFY 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10 1 ADD\", \"NUMNOTEQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"111 10 1 ADD\", \"NUMNOTEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10\", \"LESSTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"4 4\", \"LESSTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"10 11\", \"LESSTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 11\", \"LESSTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 -10\", \"LESSTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10\", \"GREATERTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"4 4\", \"GREATERTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"10 11\", \"GREATERTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 11\", \"GREATERTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 -10\", \"GREATERTHAN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10\", \"LESSTHANOREQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"4 4\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"10 11\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 11\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 -10\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 10\", \"GREATERTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"4 4\", \"GREATERTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"10 11\", \"GREATERTHANOREQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 11\", \"GREATERTHANOREQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-11 -10\", \"GREATERTHANOREQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 MIN\", \"0 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 MIN\", \"0 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0 MIN\", \"-1 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 -2147483647 MIN\", \"-2147483647 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647 0 MAX\", \"2147483647 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 100 MAX\", \"100 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-100 0 MAX\", \"0 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 -2147483647 MAX\", \"0 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0 1\", \"WITHIN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 1\", \"WITHIN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 -2147483647 2147483647\", \"WITHIN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 -100 100\", \"WITHIN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"11 -100 100\", \"WITHIN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483647 -100 100\", \"WITHIN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647 -100 100\", \"WITHIN NOT\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"2147483647 2147483647 SUB\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647 DUP ADD\", \"4294967294 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \">32 bit EQUAL is valid\"],\n[\"2147483647 NEGATE DUP ADD\", \"-4294967294 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"''\", \"RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'a'\", \"RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'a'\", \"SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'a'\", \"SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"DUP HASH256 SWAP SHA256 SHA256 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'a'\", \"HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"''\", \"HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'a'\", \"HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'abcdefghijklmnopqrstuvwxyz'\", \"HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n\n[\"1\",\"NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10\",\"'NOP_1_to_10' EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"NOP\", \"P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS\", \"OK\", \"Discourage NOPx flag allows OP_NOP\"],\n\n[\"0\", \"IF NOP10 ENDIF 1\", \"P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS\", \"OK\",\n \"Discouraged NOPs are allowed if not executed\"],\n\n[\"0\", \"IF 0xba ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"opcodes above NOP10 invalid if executed\"],\n[\"0\", \"IF 0xbb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xbc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xbd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xbe ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xbf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xc9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xca ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xcb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xcc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xcd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xce ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xcf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xd9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xda ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xdb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xdc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xdd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xde ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xdf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xe9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xea ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xeb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xec ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xed ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xee ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xef ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xf9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xfa ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xfb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xfc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xfd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xfe ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"IF 0xff ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"NOP\",\n\"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'\",\n\"P2SH,STRICTENC\", \"OK\",\n\"520 byte push\"],\n[\"1\",\n\"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161\",\n\"P2SH,STRICTENC\", \"OK\",\n\"201 opcodes executed. 0x61 is NOP\"],\n[\"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"P2SH,STRICTENC\", \"OK\",\n\"1,000 stack size (0x6f is 3DUP)\"],\n[\"1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"P2SH,STRICTENC\", \"OK\",\n\"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)\"],\n[\"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161\",\n\"P2SH,STRICTENC\", \"OK\",\n\"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP\"],\n\n[\"0\",\n\"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1\",\n\"P2SH,STRICTENC\", \"OK\",\n\">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit.\"],\n\n[\"NOP\",\"1\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"0x01 0x01 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"The following is useful for checking implementations of BN_bn2mpi\"],\n[\"127\", \"0x01 0x7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"128\", \"0x02 0x8000 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Leave room for the sign bit\"],\n[\"32767\", \"0x02 0xFF7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"32768\", \"0x03 0x008000 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"8388607\", \"0x03 0xFFFF7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"8388608\", \"0x04 0x00008000 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483647\", \"0x04 0xFFFFFF7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2147483648\", \"0x05 0x0000008000 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"549755813887\", \"0x05 0xFFFFFFFF7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"549755813888\", \"0x06 0x000000008000 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"9223372036854775807\", \"0x08 0xFFFFFFFFFFFFFF7F EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1\", \"0x01 0x81 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Numbers are little-endian with the MSB being a sign bit\"],\n[\"-127\", \"0x01 0xFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-128\", \"0x02 0x8080 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-32767\", \"0x02 0xFFFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-32768\", \"0x03 0x008080 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-8388607\", \"0x03 0xFFFFFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-8388608\", \"0x04 0x00008080 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483647\", \"0x04 0xFFFFFFFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483648\", \"0x05 0x0000008080 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-4294967295\", \"0x05 0xFFFFFFFF80 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-549755813887\", \"0x05 0xFFFFFFFFFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-549755813888\", \"0x06 0x000000008080 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-9223372036854775807\", \"0x08 0xFFFFFFFFFFFFFFFF EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"2147483647\", \"1ADD 2147483648 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"We can do math on 4-byte integers, and compare 5-byte ones\"],\n[\"2147483647\", \"1ADD 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-2147483647\", \"1ADD 1\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"0x02 0x0100 EQUAL NOT\", \"P2SH,STRICTENC\", \"OK\", \"Not the same byte array...\"],\n[\"1\", \"0x02 0x0100 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\", \"... but they are numerically equal\"],\n[\"11\", \"0x4c 0x03 0x0b0000 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"0x01 0x80 EQUAL NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"0x01 0x80 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Zero numerically equals negative zero\"],\n[\"0\", \"0x02 0x0080 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x03 0x000080\", \"0x04 0x00000080 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x03 0x100080\", \"0x04 0x10000080 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0x03 0x100000\", \"0x04 0x10000000 NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"NOP\", \"NOP 1\", \"P2SH,STRICTENC\", \"OK\", \"The following tests check the if(stack.size() < N) tests in each opcode\"],\n[\"1\", \"IF 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"They are here to catch copy-and-paste errors\"],\n[\"0\", \"NOTIF 1 ENDIF\", \"P2SH,STRICTENC\", \"OK\", \"Most of them are duplicated elsewhere,\"],\n[\"1\", \"VERIFY 1\", \"P2SH,STRICTENC\", \"OK\", \"but, hey, more is always better, right?\"],\n\n[\"0\", \"TOALTSTACK 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"TOALTSTACK FROMALTSTACK\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"2DROP 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"2DUP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0 1\", \"3DUP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 0 0\", \"2OVER\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 0 0 0 0\", \"2ROT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1 0 0\", \"2SWAP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"IFDUP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"DEPTH 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"DROP 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1\", \"DUP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"NIP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"OVER\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 0 0 3\", \"PICK\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"PICK\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 0 0 3\", \"ROLL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"ROLL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0 0\", \"ROT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"SWAP\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 1\", \"TUCK\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1\", \"SIZE\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0 0\", \"EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"EQUALVERIFY 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0 1\", \"EQUAL EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"OP_0 and bools must have identical byte representations\"],\n\n[\"0\", \"1ADD\", \"P2SH,STRICTENC\", \"OK\"],\n[\"2\", \"1SUB\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1\", \"NEGATE\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1\", \"ABS\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"NOT\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1\", \"0NOTEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"1 0\", \"ADD\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"SUB\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 -1\", \"BOOLAND\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0\", \"BOOLOR\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"NUMEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"NUMEQUALVERIFY 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0\", \"NUMNOTEQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0\", \"LESSTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"GREATERTHAN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0 0\", \"GREATERTHANOREQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 0\", \"MIN\", \"P2SH,STRICTENC\", \"OK\"],\n[\"1 0\", \"MAX\", \"P2SH,STRICTENC\", \"OK\"],\n[\"-1 -1 0\", \"WITHIN\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0\", \"RIPEMD160\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"SHA1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"SHA256\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"HASH160\", \"P2SH,STRICTENC\", \"OK\"],\n[\"0\", \"HASH256\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"CODESEPARATOR 1\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"NOP\", \"NOP1 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"CHECKLOCKTIMEVERIFY 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"CHECKSEQUENCEVERIFY 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP4 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP5 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP6 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP7 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP8 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP9 1\", \"P2SH,STRICTENC\", \"OK\"],\n[\"NOP\", \"NOP10 1\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"\", \"0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"CHECKMULTISIG is allowed to have zero keys and/or sigs\"],\n[\"\", \"0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Zero sigs means no sigs are checked\"],\n[\"\", \"0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"\", \"0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"CHECKMULTISIG is allowed to have zero keys and/or sigs\"],\n[\"\", \"0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Zero sigs means no sigs are checked\"],\n[\"\", \"0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"\", \"0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Test from up to 20 pubkeys, all not checked\"],\n[\"\", \"0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n[\"\", \"0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"\",\n\"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG\",\n\"P2SH,STRICTENC\", \"OK\",\n\"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS\"],\n\n[\"1\",\n\"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY\",\n\"P2SH,STRICTENC\", \"OK\"],\n\n[\"\",\n\"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG\",\n\"P2SH,STRICTENC\", \"OK\",\n\"Even though there are no signatures being checked nOpCount is incremented by the number of keys.\"],\n\n[\"1\",\n\"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY\",\n\"P2SH,STRICTENC\", \"OK\"],\n\n[\"0 0x01 1\", \"HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Very basic P2SH\"],\n[\"0x4c 0 0x01 1\", \"HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL\", \"P2SH,STRICTENC\", \"OK\"],\n\n[\"0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242\",\n\"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL\",\n\"P2SH,STRICTENC\", \"OK\",\n\"Basic PUSH signedness check\"],\n\n[\"0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242\",\n\"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL\",\n\"P2SH,STRICTENC\", \"OK\",\n\"Basic PUSHDATA1 signedness check\"],\n\n[\"all PUSHDATA forms are equivalent\"],\n\n[\"0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", \"0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL\", \"\", \"OK\", \"PUSHDATA1 of 75 bytes equals direct push of it\"],\n[\"0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", \"0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL\", \"\", \"OK\", \"PUSHDATA2 of 255 bytes equals PUSHDATA1 of it\"],\n\n[\"0x00\", \"SIZE 0 EQUAL\", \"P2SH,STRICTENC\", \"OK\", \"Basic OP_0 execution\"],\n\n[\"Numeric pushes\"],\n\n[\"0x01 0x81\", \"0x4f EQUAL\", \"\", \"OK\", \"OP1_NEGATE pushes 0x81\"],\n[\"0x01 0x01\", \"0x51 EQUAL\", \"\", \"OK\", \"OP_1  pushes 0x01\"],\n[\"0x01 0x02\", \"0x52 EQUAL\", \"\", \"OK\", \"OP_2  pushes 0x02\"],\n[\"0x01 0x03\", \"0x53 EQUAL\", \"\", \"OK\", \"OP_3  pushes 0x03\"],\n[\"0x01 0x04\", \"0x54 EQUAL\", \"\", \"OK\", \"OP_4  pushes 0x04\"],\n[\"0x01 0x05\", \"0x55 EQUAL\", \"\", \"OK\", \"OP_5  pushes 0x05\"],\n[\"0x01 0x06\", \"0x56 EQUAL\", \"\", \"OK\", \"OP_6  pushes 0x06\"],\n[\"0x01 0x07\", \"0x57 EQUAL\", \"\", \"OK\", \"OP_7  pushes 0x07\"],\n[\"0x01 0x08\", \"0x58 EQUAL\", \"\", \"OK\", \"OP_8  pushes 0x08\"],\n[\"0x01 0x09\", \"0x59 EQUAL\", \"\", \"OK\", \"OP_9  pushes 0x09\"],\n[\"0x01 0x0a\", \"0x5a EQUAL\", \"\", \"OK\", \"OP_10 pushes 0x0a\"],\n[\"0x01 0x0b\", \"0x5b EQUAL\", \"\", \"OK\", \"OP_11 pushes 0x0b\"],\n[\"0x01 0x0c\", \"0x5c EQUAL\", \"\", \"OK\", \"OP_12 pushes 0x0c\"],\n[\"0x01 0x0d\", \"0x5d EQUAL\", \"\", \"OK\", \"OP_13 pushes 0x0d\"],\n[\"0x01 0x0e\", \"0x5e EQUAL\", \"\", \"OK\", \"OP_14 pushes 0x0e\"],\n[\"0x01 0x0f\", \"0x5f EQUAL\", \"\", \"OK\", \"OP_15 pushes 0x0f\"],\n[\"0x01 0x10\", \"0x60 EQUAL\", \"\", \"OK\", \"OP_16 pushes 0x10\"],\n\n[\"Equivalency of different numeric encodings\"],\n\n[\"0x02 0x8000\", \"128 NUMEQUAL\", \"\", \"OK\", \"0x8000 equals 128\"],\n[\"0x01 0x00\", \"0 NUMEQUAL\", \"\", \"OK\", \"0x00 numequals 0\"],\n[\"0x01 0x80\", \"0 NUMEQUAL\", \"\", \"OK\", \"0x80 (negative zero) numequals 0\"],\n[\"0x02 0x0080\", \"0 NUMEQUAL\", \"\", \"OK\", \"0x0080 numequals 0\"],\n[\"0x02 0x0500\", \"5 NUMEQUAL\", \"\", \"OK\", \"0x0500 numequals 5\"],\n[\"0x03 0xff7f80\", \"0x02 0xffff NUMEQUAL\", \"\", \"OK\", \"\"],\n[\"0x03 0xff7f00\", \"0x02 0xff7f NUMEQUAL\", \"\", \"OK\", \"\"],\n[\"0x04 0xffff7f80\", \"0x03 0xffffff NUMEQUAL\", \"\", \"OK\", \"\"],\n[\"0x04 0xffff7f00\", \"0x03 0xffff7f NUMEQUAL\", \"\", \"OK\", \"\"],\n\n[\"Unevaluated non-minimal pushes are ignored\"],\n\n[\"0 IF 0x4c 0x00 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"non-minimal PUSHDATA1 ignored\"],\n[\"0 IF 0x4d 0x0000 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"non-minimal PUSHDATA2 ignored\"],\n[\"0 IF 0x4c 0x00000000 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"non-minimal PUSHDATA4 ignored\"],\n[\"0 IF 0x01 0x81 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"1NEGATE equiv\"],\n[\"0 IF 0x01 0x01 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_1  equiv\"],\n[\"0 IF 0x01 0x02 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_2  equiv\"],\n[\"0 IF 0x01 0x03 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_3  equiv\"],\n[\"0 IF 0x01 0x04 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_4  equiv\"],\n[\"0 IF 0x01 0x05 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_5  equiv\"],\n[\"0 IF 0x01 0x06 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_6  equiv\"],\n[\"0 IF 0x01 0x07 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_7  equiv\"],\n[\"0 IF 0x01 0x08 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_8  equiv\"],\n[\"0 IF 0x01 0x09 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_9  equiv\"],\n[\"0 IF 0x01 0x0a ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_10 equiv\"],\n[\"0 IF 0x01 0x0b ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_11 equiv\"],\n[\"0 IF 0x01 0x0c ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_12 equiv\"],\n[\"0 IF 0x01 0x0d ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_13 equiv\"],\n[\"0 IF 0x01 0x0e ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_14 equiv\"],\n[\"0 IF 0x01 0x0f ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_15 equiv\"],\n[\"0 IF 0x01 0x10 ENDIF 1\", \"\", \"MINIMALDATA\", \"OK\", \"OP_16 equiv\"],\n\n[\"Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed\"],\n\n[\"0x01 0x00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x01 0x80\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0180\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0100\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0200\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0300\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0400\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0500\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0600\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0700\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0800\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0900\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0a00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0b00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0c00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0d00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0e00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x0f00\", \"1\", \"MINIMALDATA\", \"OK\"],\n[\"0x02 0x1000\", \"1\", \"MINIMALDATA\", \"OK\"],\n\n[\"Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test\"],\n\n[\"1 0x02 0x0000\", \"PICK DROP\", \"\", \"OK\"],\n[\"1 0x02 0x0000\", \"ROLL DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"1ADD DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"1SUB DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"NEGATE DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"ABS DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"NOT DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000\", \"0NOTEQUAL DROP 1\", \"\", \"OK\"],\n\n[\"0 0x02 0x0000\", \"ADD DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"ADD DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"SUB DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"SUB DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"BOOLAND DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"BOOLAND DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"BOOLOR DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"BOOLOR DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"NUMEQUAL DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 1\", \"NUMEQUAL DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"NUMEQUALVERIFY 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"NUMEQUALVERIFY 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"NUMNOTEQUAL DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"NUMNOTEQUAL DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"LESSTHAN DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"LESSTHAN DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"GREATERTHAN DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"GREATERTHAN DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"LESSTHANOREQUAL DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"LESSTHANOREQUAL DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"GREATERTHANOREQUAL DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"GREATERTHANOREQUAL DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"MIN DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"MIN DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000\", \"MAX DROP 1\", \"\", \"OK\"],\n[\"0x02 0x0000 0\", \"MAX DROP 1\", \"\", \"OK\"],\n\n[\"0x02 0x0000 0 0\", \"WITHIN DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000 0\", \"WITHIN DROP 1\", \"\", \"OK\"],\n[\"0 0 0x02 0x0000\", \"WITHIN DROP 1\", \"\", \"OK\"],\n\n[\"0 0 0x02 0x0000\", \"CHECKMULTISIG DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000 0\", \"CHECKMULTISIG DROP 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000 0 1\", \"CHECKMULTISIG DROP 1\", \"\", \"OK\"],\n[\"0 0 0x02 0x0000\", \"CHECKMULTISIGVERIFY 1\", \"\", \"OK\"],\n[\"0 0x02 0x0000 0\", \"CHECKMULTISIGVERIFY 1\", \"\", \"OK\"],\n\n[\"While not really correctly DER encoded, the empty signature is allowed by\"],\n[\"STRICTENC to provide a compact way to provide a delibrately invalid signature.\"],\n[\"0\", \"0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT\", \"STRICTENC\", \"OK\"],\n[\"0 0\", \"1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT\", \"STRICTENC\", \"OK\"],\n\n[\"CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and\"],\n[\"pubkeys in a specific order, and will exit early if the number of signatures\"],\n[\"left to check is greater than the number of keys left. As STRICTENC fails the\"],\n[\"script when it reaches an invalidly encoded signature or pubkey, we can use it\"],\n[\"to test the exact order in which signatures and pubkeys are evaluated by\"],\n[\"distinguishing CHECKMULTISIG returning false on the stack and the script as a\"],\n[\"whole failing.\"],\n[\"See also the corresponding inverted versions of these tests in script_invalid.json\"],\n[\n    \"0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501\",\n    \"2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT\",\n    \"STRICTENC\", \"OK\",\n    \"2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey.\"\n],\n[\n    \"0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501\",\n    \"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT\",\n    \"STRICTENC\", \"OK\",\n    \"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature.\"\n],\n\n[\"Increase test coverage for DERSIG\"],\n[\"0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Overly long signature is correctly encoded\"],\n[\"0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Missing S is correctly encoded\"],\n[\"0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"S with invalid S length is correctly encoded\"],\n[\"0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Non-integer R is correctly encoded\"],\n[\"0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Non-integer S is correctly encoded\"],\n[\"0x17 0x3014020002107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Zero-length R is correctly encoded\"],\n[\"0x17 0x3014021077777777777777777777777777777777020001\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Zero-length S is correctly encoded for DERSIG\"],\n[\"0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"\", \"OK\", \"Negative S is correctly encoded\"],\n \n[\"2147483648\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY\", \"OK\", \"CSV passes if stack top bit 1 << 31 is set\"],\n\n[\"\", \"DEPTH\", \"P2SH,STRICTENC\",   \"EVAL_FALSE\", \"Test the test: we should have an empty stack after scriptSig evaluation\"],\n[\"  \", \"DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\", \"and multiple spaces should not change that.\"],\n[\"   \", \"DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"    \", \"DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"\", \"\", \"P2SH,STRICTENC\",\"EVAL_FALSE\"],\n[\"\", \"NOP\", \"P2SH,STRICTENC\",\"EVAL_FALSE\"],\n[\"\", \"NOP DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\",\"NOP\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\",\"NOP DEPTH\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"DEPTH\", \"\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"0x4c01\",\"0x01 NOP\", \"P2SH,STRICTENC\",\"BAD_OPCODE\", \"PUSHDATA1 with not enough bytes\"],\n[\"0x4d0200ff\",\"0x01 NOP\", \"P2SH,STRICTENC\",\"BAD_OPCODE\", \"PUSHDATA2 with not enough bytes\"],\n[\"0x4e03000000ffff\",\"0x01 NOP\", \"P2SH,STRICTENC\",\"BAD_OPCODE\", \"PUSHDATA4 with not enough bytes\"],\n\n[\"1\", \"IF 0x50 ENDIF 1\", \"P2SH,STRICTENC\",\"BAD_OPCODE\", \"0x50 is reserved\"],\n[\"0x52\", \"0x5f ADD 0x60 EQUAL\", \"P2SH,STRICTENC\",\"EVAL_FALSE\", \"0x51 through 0x60 push 1 through 16 onto stack\"],\n[\"0\",\"NOP\", \"P2SH,STRICTENC\",\"EVAL_FALSE\",\"\"],\n[\"1\", \"IF VER ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"VER non-functional\"],\n[\"0\", \"IF VERIF ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"VERIF illegal everywhere\"],\n[\"0\", \"IF ELSE 1 ELSE VERIF ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"VERIF illegal everywhere\"],\n[\"0\", \"IF VERNOTIF ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"VERNOTIF illegal everywhere\"],\n[\"0\", \"IF ELSE 1 ELSE VERNOTIF ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"VERNOTIF illegal everywhere\"],\n\n[\"1 IF\", \"1 ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"IF/ENDIF can't span scriptSig/scriptPubKey\"],\n[\"1 IF 0 ENDIF\", \"1 ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1 ELSE 0 ENDIF\", \"1\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"0 NOTIF\", \"123\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n\n[\"0\", \"DUP IF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0\", \"IF 1 ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0\", \"DUP IF ELSE ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0\", \"IF 1 ELSE ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0\", \"NOTIF ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"0 1\", \"IF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0 0\", \"IF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"1 0\", \"IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0 1\", \"IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"0 0\", \"NOTIF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0 1\", \"NOTIF IF 1 ELSE 0 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"1 1\", \"NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"0 0\", \"NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"1\", \"IF RETURN ELSE ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"OP_RETURN\", \"Multiple ELSEs\"],\n[\"1\", \"IF 1 ELSE ELSE RETURN ENDIF\", \"P2SH,STRICTENC\", \"OP_RETURN\"],\n\n[\"1\", \"ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"Malformed IF/ELSE/ENDIF sequence\"],\n[\"1\", \"ELSE ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"ENDIF ELSE\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"ENDIF ELSE IF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"IF ELSE ENDIF ELSE\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"IF ELSE ENDIF ELSE ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"IF ENDIF ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n[\"1\", \"IF ELSE ELSE ENDIF ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\"],\n\n[\"1\", \"RETURN\", \"P2SH,STRICTENC\", \"OP_RETURN\"],\n[\"1\", \"DUP IF RETURN ENDIF\", \"P2SH,STRICTENC\", \"OP_RETURN\"],\n\n[\"1\", \"RETURN 'data'\", \"P2SH,STRICTENC\", \"OP_RETURN\", \"canonical prunable txout format\"],\n[\"0 IF\", \"RETURN ENDIF 1\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"still prunable because IF/ENDIF can't span scriptSig/scriptPubKey\"],\n\n[\"0\", \"VERIFY 1\", \"P2SH,STRICTENC\", \"VERIFY\"],\n[\"1\", \"VERIFY\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"1\", \"VERIFY 0\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"1 TOALTSTACK\", \"FROMALTSTACK 1\", \"P2SH,STRICTENC\", \"INVALID_ALTSTACK_OPERATION\", \"alt stack not shared between sig/pubkey\"],\n\n[\"IFDUP\", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"DROP\", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"DUP\", \"DEPTH 0 EQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"DUP 1 ADD 2 EQUALVERIFY 0 EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"NIP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"1 NIP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"1 0 NIP\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"OVER 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"OVER\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"0 1\", \"OVER DEPTH 3 EQUALVERIFY\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"19 20 21\", \"PICK 19 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"0 PICK\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"-1 PICK\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"19 20 21\", \"0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"19 20 21\", \"1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"19 20 21\", \"2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"NOP\", \"0 ROLL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"-1 ROLL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"19 20 21\", \"0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"19 20 21\", \"1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"19 20 21\", \"2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"NOP\", \"ROT 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"1 ROT 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"1 2 ROT 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"0 1 2 ROT\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"SWAP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"SWAP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"0 1\", \"SWAP 1 EQUALVERIFY\", \"P2SH,STRICTENC\", \"EQUALVERIFY\"],\n[\"NOP\", \"TUCK 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"TUCK 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 0\", \"TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"NOP\", \"2DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"2DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"3DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"3DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 2\", \"3DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"2OVER 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"2 3 2OVER 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"2SWAP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"2 3 2SWAP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"'a' 'b'\", \"CAT\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"CAT disabled\"],\n[\"'a' 'b' 0\", \"IF CAT ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"CAT disabled\"],\n[\"'abc' 1 1\", \"SUBSTR\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"SUBSTR disabled\"],\n[\"'abc' 1 1 0\", \"IF SUBSTR ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"SUBSTR disabled\"],\n[\"'abc' 2 0\", \"IF LEFT ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"LEFT disabled\"],\n[\"'abc' 2 0\", \"IF RIGHT ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"RIGHT disabled\"],\n\n[\"NOP\", \"SIZE 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"'abc'\", \"IF INVERT ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"INVERT disabled\"],\n[\"1 2 0 IF AND ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"AND disabled\"],\n[\"1 2 0 IF OR ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"OR disabled\"],\n[\"1 2 0 IF XOR ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"XOR disabled\"],\n[\"2 0 IF 2MUL ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"2MUL disabled\"],\n[\"2 0 IF 2DIV ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"2DIV disabled\"],\n[\"2 2 0 IF MUL ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"MUL disabled\"],\n[\"2 2 0 IF DIV ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"DIV disabled\"],\n[\"2 2 0 IF MOD ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"MOD disabled\"],\n[\"2 2 0 IF LSHIFT ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"LSHIFT disabled\"],\n[\"2 2 0 IF RSHIFT ELSE 1 ENDIF\", \"NOP\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"RSHIFT disabled\"],\n\n[\"\", \"EQUAL NOT\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\", \"EQUAL must error when there are no stack items\"],\n[\"0\", \"EQUAL NOT\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\", \"EQUAL must error when there are not 2 stack items\"],\n[\"0 1\",\"EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"1 1 ADD\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"11 1 ADD 12 SUB\", \"11 EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"2147483648 0 ADD\", \"NOP\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"arithmetic operands must be in range [-2^31...2^31] \"],\n[\"-2147483648 0 ADD\", \"NOP\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"arithmetic operands must be in range [-2^31...2^31] \"],\n[\"2147483647 DUP ADD\", \"4294967294 NUMEQUAL\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"NUMEQUAL must be in numeric range\"],\n[\"'abcdef' NOT\", \"0 EQUAL\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"NOT is an arithmetic operand\"],\n\n[\"2 DUP MUL\", \"4 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"2 DUP DIV\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"2 2MUL\", \"4 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"2 2DIV\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"7 3 MOD\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"2 2 LSHIFT\", \"8 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n[\"2 1 RSHIFT\", \"1 EQUAL\", \"P2SH,STRICTENC\", \"DISABLED_OPCODE\", \"disabled\"],\n\n[\"1\", \"NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n[\"'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10\",\"'NOP_1_to_11' EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"Ensure 100% coverage of discouraged NOPS\"],\n[\"1\", \"NOP1\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"CHECKLOCKTIMEVERIFY\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"CHECKSEQUENCEVERIFY\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP4\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP5\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP6\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP7\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP8\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP9\",  \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n[\"1\", \"NOP10\", \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\"],\n\n[\"NOP10\", \"1\", \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\", \"Discouraged NOP10 in scriptSig\"],\n\n[\"1 0x01 0xb9\", \"HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL\",\n \"P2SH,DISCOURAGE_UPGRADABLE_NOPS\", \"DISCOURAGE_UPGRADABLE_NOPS\", \"Discouraged NOP10 in redeemScript\"],\n\n[\"0x50\",\"1\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"opcode 0x50 is reserved\"],\n[\"1\", \"IF 0xba ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"opcodes above NOP10 invalid if executed\"],\n[\"1\", \"IF 0xbb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xbc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xbd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xbe ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xbf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xc9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xca ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xcb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xcc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xcd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xce ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xcf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xd9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xda ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xdb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xdc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xdd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xde ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xdf ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xe9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xea ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xeb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xec ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xed ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xee ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xef ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf0 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf1 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf2 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf3 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf4 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf5 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf6 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf7 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf8 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xf9 ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xfa ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xfb ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xfc ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xfd ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xfe ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n[\"1\", \"IF 0xff ELSE 1 ENDIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\"],\n\n[\"1 IF 1 ELSE\", \"0xff ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"invalid because scriptSig and scriptPubKey are processed separately\"],\n\n[\"NOP\", \"RIPEMD160\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"SHA1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"SHA256\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"HASH160\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"HASH256\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"NOP\",\n\"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'\",\n\"P2SH,STRICTENC\",\n\"PUSH_SIZE\",\n\">520 byte push\"],\n[\"0\",\n\"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1\",\n\"P2SH,STRICTENC\",\n\"PUSH_SIZE\",\n\">520 byte push in non-executed IF branch\"],\n[\"1\",\n\"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161\",\n\"P2SH,STRICTENC\",\n\"OP_COUNT\",\n\">201 opcodes executed. 0x61 is NOP\"],\n[\"0\",\n\"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1\",\n\"P2SH,STRICTENC\",\n\"OP_COUNT\",\n\">201 opcodes including non-executed IF branch. 0x61 is NOP\"],\n[\"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"P2SH,STRICTENC\",\n\"STACK_SIZE\",\n\">1,000 stack size (0x6f is 3DUP)\"],\n[\"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f\",\n\"P2SH,STRICTENC\",\n\"STACK_SIZE\",\n\">1,000 stack+altstack size\"],\n[\"NOP\",\n\"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161\",\n\"P2SH,STRICTENC\",\n\"SCRIPT_SIZE\",\n\"10,001-byte scriptPubKey\"],\n\n[\"NOP1\",\"NOP10\", \"P2SH,STRICTENC\", \"EVAL_FALSE\"],\n\n[\"1\",\"VER\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_VER is reserved\"],\n[\"1\",\"VERIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_VERIF is reserved\"],\n[\"1\",\"VERNOTIF\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_VERNOTIF is reserved\"],\n[\"1\",\"RESERVED\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_RESERVED is reserved\"],\n[\"1\",\"RESERVED1\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_RESERVED1 is reserved\"],\n[\"1\",\"RESERVED2\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_RESERVED2 is reserved\"],\n[\"1\",\"0xba\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"0xba == OP_NOP10 + 1\"],\n\n[\"2147483648\", \"1ADD 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do math on 5-byte integers\"],\n[\"2147483648\", \"NEGATE 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do math on 5-byte integers\"],\n[\"-2147483648\", \"1ADD 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"Because we use a sign bit, -2147483648 is also 5 bytes\"],\n[\"2147483647\", \"1ADD 1SUB 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do math on 5-byte integers, even if the result is 4-bytes\"],\n[\"2147483648\", \"1SUB 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do math on 5-byte integers, even if the result is 4-bytes\"],\n\n[\"2147483648 1\", \"BOOLOR 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)\"],\n[\"2147483648 1\", \"BOOLAND 1\", \"P2SH,STRICTENC\", \"UNKNOWN_ERROR\", \"We cannot do BOOLAND on 5-byte integers\"],\n\n[\"1\", \"1 ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"ENDIF without IF\"],\n[\"1\", \"IF 1\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"IF without ENDIF\"],\n[\"1 IF 1\", \"ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"IFs don't carry over\"],\n\n[\"NOP\", \"IF 1 ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"The following tests check the if(stack.size() < N) tests in each opcode\"],\n[\"NOP\", \"NOTIF 1 ENDIF\", \"P2SH,STRICTENC\", \"UNBALANCED_CONDITIONAL\", \"They are here to catch copy-and-paste errors\"],\n[\"NOP\", \"VERIFY 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\", \"Most of them are duplicated elsewhere,\"],\n\n[\"NOP\", \"TOALTSTACK 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\", \"but, hey, more is always better, right?\"],\n[\"1\", \"FROMALTSTACK\", \"P2SH,STRICTENC\", \"INVALID_ALTSTACK_OPERATION\"],\n[\"1\", \"2DROP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"2DUP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1\", \"3DUP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1 1\", \"2OVER\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1 1 1 1\", \"2ROT\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1 1\", \"2SWAP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"IFDUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"DROP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"DUP 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"NIP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"OVER\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1 1 3\", \"PICK\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"0\", \"PICK 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1 1 3\", \"ROLL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"0\", \"ROLL 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1\", \"ROT\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"SWAP\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"TUCK\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"NOP\", \"SIZE 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"1\", \"EQUAL 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"EQUALVERIFY 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"NOP\", \"1ADD 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"1SUB 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"NEGATE 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"ABS 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"NOT 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"0NOTEQUAL 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"1\", \"ADD\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"SUB\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"BOOLAND\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"BOOLOR\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"NUMEQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"NUMEQUALVERIFY 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"NUMNOTEQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"LESSTHAN\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"GREATERTHAN\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"LESSTHANOREQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"GREATERTHANOREQUAL\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"MIN\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1\", \"MAX\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"1 1\", \"WITHIN\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"NOP\", \"RIPEMD160 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"SHA1 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"SHA256 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"HASH160 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n[\"NOP\", \"HASH256 1\", \"P2SH,STRICTENC\", \"INVALID_STACK_OPERATION\"],\n\n[\"Increase CHECKSIG and CHECKMULTISIG negative test coverage\"],\n[\"\", \"CHECKSIG NOT\", \"STRICTENC\", \"INVALID_STACK_OPERATION\", \"CHECKSIG must error when there are no stack items\"],\n[\"0\", \"CHECKSIG NOT\", \"STRICTENC\", \"INVALID_STACK_OPERATION\", \"CHECKSIG must error when there are not 2 stack items\"],\n[\"\", \"CHECKMULTISIG NOT\", \"STRICTENC\", \"INVALID_STACK_OPERATION\", \"CHECKMULTISIG must error when there are no stack items\"],\n[\"\", \"-1 CHECKMULTISIG NOT\", \"STRICTENC\", \"PUBKEY_COUNT\", \"CHECKMULTISIG must error when the specified number of pubkeys is negative\"],\n[\"\", \"1 CHECKMULTISIG NOT\", \"STRICTENC\", \"INVALID_STACK_OPERATION\", \"CHECKMULTISIG must error when there are not enough pubkeys on the stack\"],\n[\"\", \"-1 0 CHECKMULTISIG NOT\", \"STRICTENC\", \"SIG_COUNT\", \"CHECKMULTISIG must error when the specified number of signatures is negative\"],\n[\"\", \"1 'pk1' 1 CHECKMULTISIG NOT\", \"STRICTENC\", \"INVALID_STACK_OPERATION\", \"CHECKMULTISIG must error when there are not enough signatures on the stack\"],\n[\"\", \"'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF\", \"\", \"EVAL_FALSE\", \"CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode\"],\n\n[\"\",\n\"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG\",\n\"P2SH,STRICTENC\",\n\"OP_COUNT\",\n\"202 CHECKMULTISIGS, fails due to 201 op limit\"],\n\n[\"1\",\n\"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY\",\n\"P2SH,STRICTENC\",\n\"INVALID_STACK_OPERATION\",\n\"\"],\n\n[\"\",\n\"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG\",\n\"P2SH,STRICTENC\",\n\"OP_COUNT\",\n\"Fails due to 201 script operation limit\"],\n\n[\"1\",\n\"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY\",\n\"P2SH,STRICTENC\",\n\"OP_COUNT\",\n\"\"],\n\n\n[\"0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21\", \"21 CHECKMULTISIG 1\", \"P2SH,STRICTENC\", \"PUBKEY_COUNT\", \"nPubKeys > 20\"],\n[\"0 'sig' 1 0\", \"CHECKMULTISIG 1\", \"P2SH,STRICTENC\", \"SIG_COUNT\", \"nSigs > nPubKeys\"],\n\n\n[\"NOP 0x01 1\", \"HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL\", \"P2SH,STRICTENC\", \"SIG_PUSHONLY\", \"Tests for Script.IsPushOnly()\"],\n[\"NOP1 0x01 1\", \"HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL\", \"P2SH,STRICTENC\", \"SIG_PUSHONLY\"],\n\n[\"0 0x01 0x50\", \"HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_RESERVED in P2SH should fail\"],\n[\"0 0x01 VER\", \"HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL\", \"P2SH,STRICTENC\", \"BAD_OPCODE\", \"OP_VER in P2SH should fail\"],\n\n[\"0x00\", \"'00' EQUAL\", \"P2SH,STRICTENC\", \"EVAL_FALSE\", \"Basic OP_0 execution\"],\n\n[\"MINIMALDATA enforcement for PUSHDATAs\"],\n\n[\"0x4c 0x00\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\", \"Empty vector minimally represented by OP_0\"],\n[\"0x01 0x81\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\", \"-1 minimally represented by OP_1NEGATE\"],\n[\"0x01 0x01\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\", \"1 to 16 minimally represented by OP_1 to OP_16\"],\n[\"0x01 0x02\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x03\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x04\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x05\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x06\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x07\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x08\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x09\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0a\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0b\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0c\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0d\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0e\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x0f\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n[\"0x01 0x10\", \"DROP 1\", \"MINIMALDATA\", \"MINIMALDATA\"],\n\n[\"0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", \"DROP 1\", \"MINIMALDATA\",\n \"MINIMALDATA\",\n \"PUSHDATA1 of 72 bytes minimally represented by direct push\"],\n\n[\"0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", \"DROP 1\", \"MINIMALDATA\",\n \"MINIMALDATA\",\n \"PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1\"],\n\n[\"0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", \"DROP 1\", \"MINIMALDATA\",\n \"MINIMALDATA\",\n \"PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2\"],\n\n[\"MINIMALDATA enforcement for numeric arguments\"],\n\n[\"0x01 0x00\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals 0\"],\n[\"0x02 0x0000\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals 0\"],\n[\"0x01 0x80\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"0x80 (negative zero) numequals 0\"],\n[\"0x02 0x0080\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals 0\"],\n[\"0x02 0x0500\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals 5\"],\n[\"0x03 0x050000\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals 5\"],\n[\"0x02 0x0580\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals -5\"],\n[\"0x03 0x050080\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"numequals -5\"],\n[\"0x03 0xff7f80\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"Minimal encoding is 0xffff\"],\n[\"0x03 0xff7f00\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"Minimal encoding is 0xff7f\"],\n[\"0x04 0xffff7f80\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"Minimal encoding is 0xffffff\"],\n[\"0x04 0xffff7f00\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\", \"Minimal encoding is 0xffff7f\"],\n\n[\"Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule\"],\n\n[\"1 0x02 0x0000\", \"PICK DROP\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"1 0x02 0x0000\", \"ROLL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"1ADD DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"1SUB DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"NEGATE DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"ABS DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"NOT DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000\", \"0NOTEQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n\n[\"0 0x02 0x0000\", \"ADD DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"ADD DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"SUB DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"SUB DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"BOOLAND DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"BOOLAND DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"BOOLOR DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"BOOLOR DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"NUMEQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 1\", \"NUMEQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"NUMEQUALVERIFY 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"NUMEQUALVERIFY 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"NUMNOTEQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"NUMNOTEQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"LESSTHAN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"LESSTHAN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"GREATERTHAN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"GREATERTHAN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"LESSTHANOREQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"LESSTHANOREQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"GREATERTHANOREQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"GREATERTHANOREQUAL DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"MIN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"MIN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000\", \"MAX DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0x02 0x0000 0\", \"MAX DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n\n[\"0x02 0x0000 0 0\", \"WITHIN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000 0\", \"WITHIN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0 0x02 0x0000\", \"WITHIN DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n\n[\"0 0 0x02 0x0000\", \"CHECKMULTISIG DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000 0\", \"CHECKMULTISIG DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000 0 1\", \"CHECKMULTISIG DROP 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0 0x02 0x0000\", \"CHECKMULTISIGVERIFY 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n[\"0 0x02 0x0000 0\", \"CHECKMULTISIGVERIFY 1\", \"MINIMALDATA\", \"UNKNOWN_ERROR\"],\n\n\n[\"Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of\"],\n[\"pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded\"],\n[\"signatures and pubkeys.\"],\n[\n    \"0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501\",\n    \"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT\",\n    \"STRICTENC\",\n    \"PUBKEYTYPE\",\n    \"2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded.\"\n],\n[\n    \"0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1\",\n    \"2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT\",\n    \"STRICTENC\",\n    \"SIG_DER\",\n    \"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid.\"\n],\n[\n    \"0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f\",\n    \"2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG\",\n    \"P2SH,STRICTENC\",\n    \"SIG_DER\",\n    \"2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs\"\n],\n\n[\"Increase DERSIG test coverage\"],\n[\"0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Overly long signature is incorrectly encoded for DERSIG\"],\n[\"0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Missing S is incorrectly encoded for DERSIG\"],\n[\"0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"S with invalid S length is incorrectly encoded for DERSIG\"],\n[\"0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Non-integer R is incorrectly encoded for DERSIG\"],\n[\"0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Non-integer S is incorrectly encoded for DERSIG\"],\n[\"0x17 0x3014020002107777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Zero-length R is incorrectly encoded for DERSIG\"],\n[\"0x17 0x3014021077777777777777777777777777777777020001\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Zero-length S is incorrectly encoded for DERSIG\"],\n[\"0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701\", \"0 CHECKSIG NOT\", \"DERSIG\", \"SIG_DER\", \"Negative S is incorrectly encoded for DERSIG\"],\n\n[\"Automatically generated test cases\"],\n[\n    \"0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001\",\n    \"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK\"\n],\n[\n    \"0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001\",\n    \"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"P2PK, bad sig\"\n],\n[\n    \"0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508\",\n    \"DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PKH\"\n],\n[\n    \"0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640\",\n    \"DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG\",\n    \"\",\n    \"EQUALVERIFY\",\n    \"P2PKH, bad pubkey\"\n],\n[\n    \"0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK anyonecanpay\"\n],\n[\n    \"0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"P2PK anyonecanpay marked with normal hashtype\"\n],\n[\n    \"0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\",\n    \"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL\",\n    \"P2SH\",\n    \"OK\",\n    \"P2SH(P2PK)\"\n],\n[\n    \"0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\",\n    \"HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL\",\n    \"P2SH\",\n    \"EVAL_FALSE\",\n    \"P2SH(P2PK), bad redeemscript\"\n],\n[\n    \"0x47 0x30440220781ba4f59a7b207a10db87628bc2168df4d59b844b397d2dbc9a5835fb2f2b7602206ed8fbcc1072fe2dfc5bb25909269e5dc42ffcae7ec2bc81d59692210ff30c2b01 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x19 0x76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\",\n    \"HASH160 0x14 0x7f67f0521934a57d3039f77f9f32cf313f3ac74b EQUAL\",\n    \"P2SH\",\n    \"OK\",\n    \"P2SH(P2PKH)\"\n],\n[\n    \"0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac\",\n    \"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL\",\n    \"\",\n    \"OK\",\n    \"P2SH(P2PKH), bad sig but no VERIFY_P2SH\"\n],\n[\n    \"0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac\",\n    \"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL\",\n    \"P2SH\",\n    \"EQUALVERIFY\",\n    \"P2SH(P2PKH), bad sig\"\n],\n[\n    \"0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901\",\n    \"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG\",\n    \"\",\n    \"OK\",\n    \"3-of-3\"\n],\n[\n    \"0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0\",\n    \"3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"3-of-3, 2 sigs\"\n],\n[\n    \"0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae\",\n    \"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL\",\n    \"P2SH\",\n    \"OK\",\n    \"P2SH(2-of-3)\"\n],\n[\n    \"0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae\",\n    \"HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL\",\n    \"P2SH\",\n    \"EVAL_FALSE\",\n    \"P2SH(2-of-3), 1 sig\"\n],\n[\n    \"0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with too much R padding but no DERSIG\"\n],\n[\n    \"0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK with too much R padding\"\n],\n[\n    \"0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with too much S padding but no DERSIG\"\n],\n[\n    \"0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK with too much S padding\"\n],\n[\n    \"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with too little R padding but no DERSIG\"\n],\n[\n    \"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK with too little R padding\"\n],\n[\n    \"0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT\",\n    \"\",\n    \"OK\",\n    \"P2PK NOT with bad sig with too much R padding but no DERSIG\"\n],\n[\n    \"0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK NOT with bad sig with too much R padding\"\n],\n[\n    \"0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"P2PK NOT with too much R padding but no DERSIG\"\n],\n[\n    \"0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK NOT with too much R padding\"\n],\n[\n    \"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 1, without DERSIG\"\n],\n[\n    \"0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 1, with DERSIG\"\n],\n[\n    \"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 2, without DERSIG\"\n],\n[\n    \"0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 2, with DERSIG\"\n],\n[\n    \"0\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 3, without DERSIG\"\n],\n[\n    \"0\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 3, with DERSIG\"\n],\n[\n    \"0\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 4, without DERSIG\"\n],\n[\n    \"0\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"OK\",\n    \"BIP66 example 4, with DERSIG\"\n],\n[\n    \"0x09 0x300602010102010101\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"OK\",\n    \"BIP66 example 4, with DERSIG, non-null DER-compliant signature\"\n],\n[\n    \"0\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG,NULLFAIL\",\n    \"OK\",\n    \"BIP66 example 4, with DERSIG and NULLFAIL\"\n],\n[\n    \"0x09 0x300602010102010101\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG,NULLFAIL\",\n    \"NULLFAIL\",\n    \"BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature\"\n],\n[\n    \"1\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 5, without DERSIG\"\n],\n[\n    \"1\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 5, with DERSIG\"\n],\n[\n    \"1\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 6, without DERSIG\"\n],\n[\n    \"1\",\n    \"0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 6, with DERSIG\"\n],\n[\n    \"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 7, without DERSIG\"\n],\n[\n    \"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 7, with DERSIG\"\n],\n[\n    \"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 8, without DERSIG\"\n],\n[\n    \"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 8, with DERSIG\"\n],\n[\n    \"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 9, without DERSIG\"\n],\n[\n    \"0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 9, with DERSIG\"\n],\n[\n    \"0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 10, without DERSIG\"\n],\n[\n    \"0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"BIP66 example 10, with DERSIG\"\n],\n[\n    \"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 11, without DERSIG\"\n],\n[\n    \"0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG\",\n    \"DERSIG\",\n    \"EVAL_FALSE\",\n    \"BIP66 example 11, with DERSIG\"\n],\n[\n    \"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"\",\n    \"OK\",\n    \"BIP66 example 12, without DERSIG\"\n],\n[\n    \"0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT\",\n    \"DERSIG\",\n    \"OK\",\n    \"BIP66 example 12, with DERSIG\"\n],\n[\n    \"0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with multi-byte hashtype, without DERSIG\"\n],\n[\n    \"0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG\",\n    \"DERSIG\",\n    \"SIG_DER\",\n    \"P2PK with multi-byte hashtype, with DERSIG\"\n],\n[\n    \"0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with high S but no LOW_S\"\n],\n[\n    \"0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG\",\n    \"LOW_S\",\n    \"SIG_HIGH_S\",\n    \"P2PK with high S\"\n],\n[\n    \"0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with hybrid pubkey but no STRICTENC\"\n],\n[\n    \"0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"STRICTENC\",\n    \"PUBKEYTYPE\",\n    \"P2PK with hybrid pubkey\"\n],\n[\n    \"0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT\",\n    \"\",\n    \"EVAL_FALSE\",\n    \"P2PK NOT with hybrid pubkey but no STRICTENC\"\n],\n[\n    \"0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT\",\n    \"STRICTENC\",\n    \"PUBKEYTYPE\",\n    \"P2PK NOT with hybrid pubkey\"\n],\n[\n    \"0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT\",\n    \"\",\n    \"OK\",\n    \"P2PK NOT with invalid hybrid pubkey but no STRICTENC\"\n],\n[\n    \"0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101\",\n    \"0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT\",\n    \"STRICTENC\",\n    \"PUBKEYTYPE\",\n    \"P2PK NOT with invalid hybrid pubkey\"\n],\n[\n    \"0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401\",\n    \"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG\",\n    \"\",\n    \"OK\",\n    \"1-of-2 with the second 1 hybrid pubkey and no STRICTENC\"\n],\n[\n    \"0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401\",\n    \"1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG\",\n    \"STRICTENC\",\n    \"OK\",\n    \"1-of-2 with the second 1 hybrid pubkey\"\n],\n[\n    \"0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201\",\n    \"1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG\",\n    \"STRICTENC\",\n    \"PUBKEYTYPE\",\n    \"1-of-2 with the first 1 hybrid pubkey\"\n],\n[\n    \"0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with undefined hashtype but no STRICTENC\"\n],\n[\n    \"0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG\",\n    \"STRICTENC\",\n    \"SIG_HASHTYPE\",\n    \"P2PK with undefined hashtype\"\n],\n[\n    \"0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT\",\n    \"\",\n    \"OK\",\n    \"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC\"\n],\n[\n    \"0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05\",\n    \"0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT\",\n    \"STRICTENC\",\n    \"SIG_HASHTYPE\",\n    \"P2PK NOT with invalid sig and undefined hashtype\"\n],\n[\n    \"0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG\",\n    \"\",\n    \"OK\",\n    \"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY\"\n],\n[\n    \"0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG\",\n    \"SIGPUSHONLY\",\n    \"SIG_PUSHONLY\",\n    \"2-of-2 with two identical keys and sigs pushed using OP_DUP\"\n],\n[\n    \"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac\",\n    \"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL\",\n    \"\",\n    \"OK\",\n    \"P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY\"\n],\n[\n    \"0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 NOP8\",\n    \"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG\",\n    \"\",\n    \"OK\",\n    \"P2PK with non-push scriptSig but with P2SH validation\"\n],\n[\n    \"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac\",\n    \"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL\",\n    \"P2SH\",\n    \"SIG_PUSHONLY\",\n    \"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY\"\n],\n[\n    \"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac\",\n    \"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL\",\n    \"SIGPUSHONLY\",\n    \"SIG_PUSHONLY\",\n    \"P2SH(P2PK) with non-push scriptSig but not P2SH\"\n],\n[\n    \"0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901\",\n    \"2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG\",\n    \"SIGPUSHONLY\",\n    \"OK\",\n    \"2-of-2 with two identical keys and sigs pushed\"\n],\n[\n    \"11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001\",\n    \"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"P2SH\",\n    \"OK\",\n    \"P2PK with unnecessary input but no CLEANSTACK\"\n],\n[\n    \"11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001\",\n    \"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG\",\n    \"CLEANSTACK,P2SH\",\n    \"CLEANSTACK\",\n    \"P2PK with unnecessary input\"\n],\n[\n    \"11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac\",\n    \"HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL\",\n    \"P2SH\",\n    \"OK\",\n    \"P2SH with unnecessary input but no CLEANSTACK\"\n],\n[\n    \"11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac\",\n    \"HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL\",\n    \"CLEANSTACK,P2SH\",\n    \"CLEANSTACK\",\n    \"P2SH with unnecessary input\"\n],\n[\n    \"0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac\",\n    \"HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL\",\n    \"CLEANSTACK,P2SH\",\n    \"OK\",\n    \"P2SH with CLEANSTACK\"\n],\n\n[\"CHECKSEQUENCEVERIFY tests\"],\n[\"\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY\", \"INVALID_STACK_OPERATION\", \"CSV automatically fails on a empty stack\"],\n[\"-1\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY\", \"NEGATIVE_LOCKTIME\", \"CSV automatically fails if stack top is negative\"],\n[\"0x0100\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY,MINIMALDATA\", \"UNKNOWN_ERROR\", \"CSV fails if stack top is not minimally encoded\"],\n[\"0\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY\", \"UNSATISFIED_LOCKTIME\", \"CSV fails if stack top bit 1 << 31 is set and the tx version < 2\"],\n[\"4294967296\", \"CHECKSEQUENCEVERIFY\", \"CHECKSEQUENCEVERIFY\", \"UNSATISFIED_LOCKTIME\",\n  \"CSV fails if stack top bit 1 << 31 is not set, and tx version < 2\"],\n\n[\"NULLFAIL should cover all signatures and signatures only\"],\n[\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG\", \"OK\", \"BIP66 and NULLFAIL-compliant\"],\n[\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG,NULLFAIL\", \"OK\", \"BIP66 and NULLFAIL-compliant\"],\n[\"1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG,NULLFAIL\", \"OK\", \"BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant\"],\n[\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG\", \"OK\", \"BIP66-compliant but not NULLFAIL-compliant\"],\n[\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG,NULLFAIL\", \"NULLFAIL\", \"BIP66-compliant but not NULLFAIL-compliant\"],\n[\"0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG\", \"OK\", \"BIP66-compliant but not NULLFAIL-compliant\"],\n[\"0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\", \"0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT\", \"DERSIG,NULLFAIL\", \"NULLFAIL\", \"BIP66-compliant but not NULLFAIL-compliant\"],\n\n[\"The End\"]\n]\n"
  },
  {
    "path": "src/test/data/sighash.json",
    "content": "[\n    [\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n    [\"00000020028451c5791e047ef3ed412e9d272aa9bb399b03df20787d083e36f126dd2d991b0200000004526352abafce350bb1f07c70f317d1907b47aff7844a563bd5edd0c4078c857f131f945cf0a11860000000000153ffffffff02a25d87040000000008ab63510052acab5227ed2a02000000000000000000\", \"65536563ac63\", 1, 1997473671, \"ed3f9632d9bb80c6f3f61882ab600a2004320abeffa39f122947b6703a4bc31e\"],\n    [\"030000000390c6a2ca9ecf63095a0d8676b85b7d1e20c1fb5707146c61224a596d7e5b1ded0200000000ffffffff89470a588df5f354b5a94b8ef9044cd050bd41e0f098359f29c38adc54cc68f40000000000bdc6d2b17c26311a4476ddd51fa87159a69ddd7618f9af415ee6a8835f1f2d99f57041f00200000007636a65ab525100035c001c0493284c020000000004ab53ac5119bbb8040000000008ab51abac00656aac53e88c01000000000100c7da3a02000000000000000000\", \"6551ababac53516353\", 1, 427767316, \"dfb9cfb07d5cb4f59ec3efc4c399d50ed604ba9492bbd82a1d9b5e969b2923e0\"],\n    [\"0200000002521e8d8361ff14ec1f47b9854397acf87040104ff2bd88ffd0cdbb29a2a7178f0100000006ac51ab5351abffffffffa2194aeba1e9ea23ef6d52ef5cb0a695e6c8caaf0f4c09b97d3e8820642c5464010000000900ac63ac5252abac65ffffffff02ce52780300000000095151ab00526563536aaba4b4020000000005abab6300537ef7a192\", \"636a5200\", 0, 1335108560, \"88c1e378a44db01ad45df6ff35b77eb24a26e3ea1bff03603ff5ab96c18e82fc\"],\n    [\"0000002002165b1d2e1a02fb5e638c1a5c4613c25e8833b5e4adfb812768cf0369b39247ec0200000005516a656352ffffffff813f450498cc629b8cbfca225c55272b71a3b9a48e89dbc049444a92098d8b6003000000036aab6affffffff037c7a65030000000008ac52635263ac6aab7d55de010000000008ab656500005100aba639a90400000000086a51ac5165535163c63fd42a\", \"ab510051ac\", 0, -1213774127, \"ebbbf828bf6e19eb0a4eac7e12f1dc2482bb81716df85bfb881135998c3ddbd5\"],\n    [\"00000000042818bcb723655e6dda50d7e009b24a6ad23970d156bf8021e6ec3073c13f6c9f0100000002ab65ffffffff9e58a1dd428a1a8379a7757bf271cd437b7098a595521bdf705b2ab06030dd8603000000002b000df3ca99a35ca6f2c7f0ff771bf8f0cdf1840590789d997de7a5a77f011a2b93e1c501000000096a6a65516565525263ffffffffe0eee235f34e3797480802ceb02e0b9f6f82e36be23f737d74ace5884718a3e3020000000265acd9907a2803d7fee001000000000400abacabc87c58030000000008535153516a65ac525424fa0100000000036a516500000000\", \"63\", 3, 1360005115, \"7314731e6eaab92d2a588ad3b6e27a89306fdd94676c62741fa70ba2c75fe3cd\"],\n    [\"000000000449b9dda8210f99149a92da5f37ecdf8f54369126c90c924f5a8a34beb2a05e820100000000ffffffff86444d671766912e0bd0002a649d6cc40dd1694a52e8becfe0f32c5ac70068eb0000000008abababac636a52acd610696f689339c2cfa6653869a848ba00774f2de1eb40ca4cc57311a6454ab81840c9de01000000026551ffffffff005c43811cad48d319e6f9c3716b791eb76b9e66f72adb06e8ef91a27f50a28701000000055251526a51e4ed252503c85bd3000000000006635263ac6565b7eb6405000000000951636351536a5265ab4f334c0400000000086aac5252abac6a526a5fbf9b\", \"51\", 2, 1763308788, \"842a2cdd4ff0c670115c50fd1036798e711013da4fdf83d97a285de67030d8e1\"],\n    [\"000000200220eefaf69d29bb9435733f5a89af4c12a05c7db84e0903976d71935672c62ad20300000003535352929e8c5bc25710686ddc2c248c38e3eda38847257756653410be55da265b23d628b97298010000000851630052636a51ab1b5da6d30471b5ce040000000000f2ae8b0100000000075253636352ab638bab76030000000006635263516551d7b221040000000006ac51ac63ab5300000000\", \"\", 1, -1681983184, \"a8ab65c609dba80072ddfe65ef4932e4b6ed2847ecfa6652d195863935c51a41\"],\n    [\"020000000292543856f2ac659708babe6d1668224c781bd55f60e30fac6ee17a5e23c779b101000000026500ffffffffe3353706700b7ddd8fc1ee7e9cba85c0b9037197b71e9059638ec4d3e84437340200000006656a65ab51acffffffff015196610200000000096a00526a0065516a6a00000000\", \"526a6351\", 0, 1824760501, \"afdb5c8a888b0ca39954ea5d5d9c776494acf7d1ef95d12a0f947886fa2cb730\"],\n    [\"0200000002331adda89d6217046f2f3db743e53808d94b462edfe1953dcdd63481fc3547ea0200000003ab6a51ffffffff322ed5b429f78f0cf8f7e50d82da92e848094b5cff0820040fe66f58bbdba3da000000000665ab52516551ffffffff01a7fc8f05000000000953536551ab526a535300000000\", \"ac5300ab\", 1, 951202488, \"eba06914d610d865a245395d7a5c08cddfd8fca5113d00f566a59c6460ff29ec\"],\n    [\"0100000004e743cdcf62b555905e4dc1135c0a101339cb252fa7ea1991ff6df9e80e33377e01000000085163516351ab5251ffffffff1f009950ae8f5e103fdd592bca382e206ac4b1c8077391823d6b428eda5636f00100000004abac5263ffffffff16b48fe892490866e0a1ff91a21299918127de7f7dc575788f4c35cafc73cf73010000000652ac0000635241ec1693534b667397306261e6544fdbce12e7c4540e10b6b646e985260ec70daf71c9fe0000000005ac00ab6a53e697eedd01d6c8c702000000000452acacac272ef42e\", \"00abacab6a65\", 2, 25832902, \"09a6ea679dfae21e5193223d0336c91b82025b57ef379c2e4c3c243827501a7a\"],\n    [\"000000000308d8f3ad43d4fed3d7992857be0cf2068cc3427e914e7351ac4f6d573e23f21a02000000096aabab6552006a516a7dcd3d1eac588715691fb647ea34a62a2e756df587df7f4d02c012d5ac51ee774761f9ae0300000004ac520051ffffffff0264e4dafd6c5ac7a1c882f7a057d40aa64d61fcda5d01157f9f58fb722869390000000000ffffffff026ee9910200000000046a6363631473ef01000000000653ab5200635275481fa9\", \"ab6aab\", 0, -1129982980, \"c5c769f0c181048f9f1df042536ab0f2df898935c19989d33962f51f717c83e1\"],\n    [\"0100000004478261e918bcf08ed9b0627a3df9a1a581a5d6f2446d0fa8539056c85e0302cf03000000020000ffffffff3aa1ded3f7f6874aa7771badc51a8e50959a490f03a223496a321d3de77e942300000000046365006affffffff1b10853ccbc087322177c5bde7b623a67c3c7b29170cff849ff8fa907dbff46a000000000963656363656aab636affffffff3f4826f896e8724f8844e420b3f8f044d0411d9461218801cf82d429504eceb300000000045351650092fc4b55036e85760400000000003a5e880300000000007b9a1c0400000000016a33d20996\", \"53535300000052\", 2, 512533260, \"1f61affb7722ec0efac7201592dd1e3a8ad316b7e536080bd5332d27f3455350\"],\n    [\"0100000001e46a3487289664fdc90edbd59b3244f0135d20fad1f0f38100bf2c634f98053a030000000451ab526a5726eafb017bc672040000000000793b676c\", \"635151ab516a\", 0, 1892371687, \"000938adba71f4c225f5b6c84efc0d27d9c15f386051fe3d00e869623e18942d\"],\n    [\"0100000001bb4f0e78cb3bc6c4ae0a4ac7364ee6dca4ac4593ebd5c530fb77b0c62d6a8e080000000003006553ffffffff03532ace020000000001538e762f0500000000086a6551536aabac65a6096103000000000251abd962c38e\", \"ab65656a005100ab\", 0, 1378547947, \"59283bb065250b325e1f89d7760801045ee422110e9fc3c013ab6197052d7d11\"],\n    [\"00000020011f0e78d6186c21effb6af971d138c64fa6af1a3955e0c4e54b637a9bdc28777b010000000024693b9a0215b71b04000000000463656553139e4d04000000000300006a5e277742\", \"006a53\", 0, -1086805684, \"49e0b4ecbd355eebbf2c139a9db7ca2e3780c3dcd62823747dbe2f57957922cc\"],\n    [\"0300000003096e2267827e2798747b62bb55a3325a31ba69c888b144a0868acc4f6bb9de4a000000000651005265ab001f2509e5fcc288bf56f630ff5a203d6a8656d97edd783a80c53e42e0d1fac0cd5b6aa31202000000007c70f235bf15b3376a0cf2f2260876289c986b361b6549519ac182c63608a88419f115960200000008ab526a5363ac51ac7225c4e002c7cd1c030000000008ab63ab63ab51ac633a1f5505000000000000000000\", \"ac6a52acab\", 2, 341774525, \"683274c33b9f9d0940602910770df1d9299f603b11f5f5635284282690c39316\"],\n    [\"0300000001f4123105e47bd16fd7bd75e273426c3e1343840365f7601bc21e4c63b935a34f030000000752656352515351d9a0fe60038a0baa05000000000251520f5d7c010000000009636aac526a63ac6a00b1dc59050000000002636300000000\", \"530063ac0051\", 0, -2018164870, \"f617d4d97b2e397331ea7a0694762e48d29d61de1ac4bf4486d074e06d568414\"],\n    [\"000000000457ccb68968a6f5bb9d5ce9b03be91e430a7135dbfff369ee88a438a42eefee4f010000000153924009b781e69cd171de35e8a7021ad8daac7bcd2502ab892645de057ddbb468f1958a5d0000000000ffffffffe39ba29c12294f64b0dde56c6a8b666b24c7f9a3727d002f426f8d266167e58c03000000085200abac00515253ffffffff193d1abed490cdeea613144adced4ecf437e5e14e68ca811b696bd0a407897810000000004ab6a6a53ffffffff040ec15301000000000965ab52acac63655351bade1f020000000004abab51ab75d7c6000000000004005200ab3b5ebf040000000002ab6a00000000\", \"ac63\", 3, -998451271, \"cd8c8da0f73911b005e7ef8410076ce558773a564f2e2d3fe037050ebe4661f8\"],\n    [\"040000000216a46727c8af4297d9cb1af71f87dd4365c387176e71996ff729d393d08744e50300000006006aab5352abffffffff49ceb0d8516b3073a11d3c6d299e928283424cfd0af0e7b4cd939edff71e966a03000000066a6551510065ffffffff04cda19b00000000000663ac00ab51abb179a70000000000009f9bd1030000000000a9268e030000000001ab3918fdc7\", \"5252ab65ab6552\", 1, 891515486, \"8c8adef899dd9f2d2c7d38b1d3a073f00cdd0276a17d254905b0c0956d2cc936\"],\n    [\"000000200383cadf7db482b763d1a5b10a26ab4313d94bb2afd06a68723de6e950bfeb6cfa03000000055251635263ffffffff5f3ce6c41b98fd394e5fbf558d4d371247f114519c8fa1936bd45fb714d9d249020000000152ffffffff424d295e7751e90f28844079d67bc4ecd9a93d3056d6c157bd76b90ea05f22ec030000000251ac5b4763720398377f0100000000002aaa4503000000000253003edd3d030000000009636aac5165ab65ac6a00000000\", \"\", 2, -1646915146, \"ba09189d1a86eec2c4aaf9cde7d6f9a92966252fcc7dcbe7177e19fe4dd2ffc6\"],\n    [\"0100000001f972a0aeae6bdcd342893b2e8374a2e365c775b82d1fce2221be614e53a26d56010000000100ffffffff044256bb040000000000cd707605000000000200000cf8c404000000000453ac65abf82f900400000000076300525300ac5100000000\", \"00\", 0, -99702139, \"50f8eb50ffb19b3585aa9a16103f895dba4b6cae6f6b355e357065cdb67e7a77\"],\n    [\"00000000038da222aeb8715628399bea2481c0c817f1852f85df369c9c415ccd2c1575664a0200000003516aacffffffff6bdd4dd36752b80f183769f48ee4363a20f0a8041107856cdbf1054033175acd0100000009656a656a51ac655153ffffffff601b9189bc295fc6c3082258572055c642d6397dcff94548adec5db6824e2f4c0200000005ab52ac515311a3596003b71e740300000000075253acac51525354151a0400000000036300006939da0200000000046553656a00000000\", \"63acac52520000ac53\", 2, -733137440, \"eb760133f47109c970ad5a40a4d7b83cb07422db218bf8dc8cec698adf3ff763\"],\n    [\"0100000004f82c4ad21f8e38ad13c025db6de4e1f08bc092e82145100adbadeb8be3d9d99d0000000004ac006a51ffffffffcd8c99423de640b1cb04e10e0c3beffcfc2b53216cccb3fdf6635de98db72e890200000002526522bd31efa0cdf52a712d19144004c87e3b57104aa32cf5982b9617ce7d012d07d5d28a99030000000651ab6a516553ffffffff6860ecc1e7a054c9035369bb765e11dd05314945d671d78c12dbd7fa24949775020000000352ac6affffffff02edab4c03000000000563ac63ab6a0ea3d1050000000004ab5351001194fb24\", \"535165\", 0, -528957654, \"1a9acffe0fcbc443498af4aa2513fd62f7e5b3d096c6e522844d8016ce24abdf\"],\n    [\"03000000024aff548a792f0da8d377f2471793cca5c459de33fb56b316daf34f0f61566569030000000951515151ac6565ab519f8218ccaec2c0d8e1c39e5726c80df72fdd4aad5f743eb2e94df3c4cf832a682659efd001000000003e3318740155751c010000000009ab006a655163515363f77f35b6\", \"650065ac516a65\", 1, -1113536986, \"17488fbbcd62e179d6af46ba499987650b1f3e8782a0b9f9216be67b91e02e4c\"],\n    [\"02000000047480a1439b94a16fd8d7996cba3c45957f0377a89fac3faa56db6763423266b802000000026500ffffffff6072fc6c675101d668c9ded1a7c8cd2e4f0bbf5a592e6fcf64b2cc6b0134b97b01000000055100535363eaf5d079ee0becff06a00df84c32ab51fe0a95de7ba0d4a81dd70d5d137f3a5b136b85420100000000ffffffff76346136c96b53f1213f0a9f0df4c132a76d28b9955554a5b71d3aa5df08d0e303000000035353510f568dbe02340dcb030000000004abac52521f3d8d050000000005536a0063abc62d0705\", \"516552ac6aacab0051\", 1, -286816825, \"0c8eb36a07c5274cd28945c98e67fa84a4b2e88c74673c18823f2e618ac2e04f\"],\n    [\"0400000003505341bd52ad70c73632e2d4c96dbae014a15272f2f08d193eda2aee1b5b33c300000000075163516a65ac65ffffffffb02c65f8cba55faeb8b0d837a0618b9048e887bf9c092111f3b264ccf5fd1cad02000000086353abab6a0063632be20dcb31dd8defaf0938c9e246a0c4a2ec2475186ab4cdf496851a432207e4af374cfd020000000865acacac51ac5300ffffffff01cd18cc05000000000900ac6a6363abac525300000000\", \"006aac6a526a\", 0, 702490181, \"d70c5c5ff7ebea6655d232ddc7f4d24065ea1810949e716710e2f1a7afe2372f\"],\n    [\"0100000004e50172f570a64cb8c904aa311f992c98d11405f6d9d1b57aa9520bc43425164a000000000252abb4f4e805a5bc9b09f00521f195dae6910f034cb567ddf90eee63ae38288f3111ffe3a53300000000066565ac635200ffffffff560f8b37544344d9eca2f36023ca025d68b70001cfdf5eca64ce5a516f218138010000000651006a655352ffffffffa7ab6800ca7bfa53c2ab736715d237b279e3a054126de27c26b97cc9272b97da00000000086aabab656a5200525e2927c4024a4c0105000000000665510051ab65d0edec000000000004630063ac00000000\", \"0063ac6a\", 1, -989123795, \"041cc1f606e2a6f0dd4bbda7fed1b033bacf9cf07949cd3be3bb66d698b6a0f8\"],\n    [\"0400000004812ba9558dfac4b20626981264e489097593cf38313b88a3a158f2983d9573990100000003ac51abffffffff3346d790ce8aad0099baa4ff125354ed14e5292657101f33fd3480fc6b43d66301000000096aab65636a536a6a6abbc7e4d9da3f9cf2a6e13c343552f5afcbad3e2174c22b73a2f9856fbf1b4a0eb4ffc47b02000000096a65536a65abac6552ffffffff3696f9ce0fd838aa167fef00720536e21d6088d1943687694aafd7a1c568c9b503000000056a5351ab63972cd5af03a3950b030000000000cb8f6a040000000006ac52acacab523c7c8d000000000009510053acabac656a0000000000\", \"00ac\", 2, -1451670379, \"d9be7b26d116567ad08672277aa0ef9655470f55cdfefa199b1b72c65956bbef\"],\n    [\"0200000001469c57e42b0515eab6ce4553d47e5df231dbbf17fc61c1fcbee0f7730d74a0330300000001657651b1ec035dec3f0100000000055352535200f7b62003000000000100482f55000000000005536553ac6a00000000\", \"655100ab6351\", 0, 492626732, \"43ae03b5ab63ffa71ea11546e7e45c0acb499a08f67419008244eccdfe580b26\"],\n    [\"0200000002ff7347d5bc79ef69b972a2541d1d944c3ee834d8ac27a626e537bf1728cf6033020000000863ab656551ab6a53ffffffff1639886c39721e7e9570ed48a02dd8b07f213597152ccd02cbb4a87d0e21471e010000000465656563ffffffff03225ca2050000000009006a526563abab526347d8e30500000000045365ab00bf89e70100000000085300516a5265526300000000\", \"5165ac655353\", 0, -1642766307, \"fc0c58a6d7b22c6ecfb48cd19a62753274005a308cd04e904a597f949a994909\"],\n    [\"0100000002f67bf3d2a794782e0a5c431406ce8a254ee86ae2217d091e454cb3ebced49edd0100000009655152ac53acabac52ffffffff632cc1929b8c754c85eaa137b92b3cae7ac61fe4e77b30cfbbc11418ebac9af10100000001acffffffff040151f30100000000025252f621cc0300000000055163ab5100ff17de03000000000652ababab5251186b1d02000000000551006a516500000000\", \"6a\", 1, -1405976309, \"93cdac487766f2fe9d5bdb9b2b2a7a440deff74eec0be497837b304e7f0bf46e\"],\n    [\"01000000045e35407b1624255b2489fdf424b2525654784b60a33b3aa424fe35c5a4a01bbd0100000009ac5363ab6551006a514f763bb71f43a7d51ff27e94750d0b799f3e89f76fa003f1db8907f973b84e874181289a00000000026a51b8b7111ab795c87dc98447799ea7171dcd16991bf673d1f4409afd8d53614e7188064e940100000000cf71a5304037cd150029245531e66d4b415231a2965e8f529331a156ac00f8e91939d4bd0100000000ffffffff020a43a200000000000152b0a6dd010000000002536300000000\", \"5365526a535300ac\", 3, 1212243514, \"5978b58e12f8d0678f57bb9e333780fea67eeb0641d43e25ef1d9c8ead782373\"],\n    [\"02000000020ef31949b8a6496719cc28bb45ba986fd20194b6ea3a6d7ed21322a8c47af1980300000004acab51535cdd3cf5a415e725a696fa72d4d14fe3f4c24529234220e1057d64f154479cf3f1b843660200000006006563ac6a65ffffffff01fe1b030000000000015200000000\", \"abac65ab5163\", 0, 1791384992, \"b8dca3c47a44406a47289496f5ce0f682a45a09ee16273f58ede32d8b1c3526f\"],\n    [\"020000000232a0df5d69a60b02cc52ae4e18a1c464eb661d3bb3b7dbe0229d6f2deda696ec020000000863005363535363ab16bb409be5b76c8bee3e9ff137892a7270c5d0c57cc1ef57ac0f5cf1c7c856143e242c3b020000000153987bdc2803ecce3405000000000453ac51637b4a08030000000009ac6aab636a6363ababb85218010000000008656aacac51ac000000000000\", \"65\", 0, 1241694374, \"b55640b45ad31e6a7d3b2e50911e71b842642b751ae010b32c68861140056fc2\"],\n    [\"0100000004761a6996fe8e21238e4dd887c417d9d94b00f85f04e20d3d957c27bcd507bcc602000000056aac526a00fcec5e6aa8c3c81db205c806a9cc7d38b487cb5b3fc155cc79f95cd0d39f1e73279815d3010000000353526affffffff79a2be9922329c594045a25d4645a3b5bf3dce51a2efda65b3cb18cb061bf5c402000000066a63ac536a53ffffffff36584c040e62d6ebc6e9509b963822fda7ce26ff50192e4cad755f4f4a054a1401000000055363635151c14169ab04823c7b03000000000563ab6552ab9c64d4050000000007abab635263536568f7ab0400000000006437ff000000000007005100ac63ab63de7119e5\", \"636351acab5265\", 2, 536672345, \"a59fb49809ce1c1ae191780f047036136265d16a18e901d4617a24db800785ef\"],\n    [\"0200000001805589060aef96e07ab25d9ecaf214c398dcc479bb4494a1b26eee66b2a9eb91010000000953ac5165ab5151ac514b93633603f2e24701000000000653ac6553ac002854b1050000000000153de7050000000007ac5200536a526a96ef8812\", \"63535265656a65\", 0, 456347641, \"f9a7d96284d0a6d8a47a974ca2761e26e3eba90cf74c9f4ffbbacf45065a951a\"],\n    [\"0200000001ac33a1a5db2aca00feb851e27a52dcf7c092aa23936ba3ebf0c2df3e62d339dc0200000009ab6a516a6351525365ffffffff01cf065d040000000001655ff0a5ea\", \"535251510000\", 0, -1366278759, \"de51c65ed6d00d60bbb98e4bbc39c39a5273ba6b70ac386e8ef22c99b3c29cff\"],\n    [\"0000000003d6894c9e0ec5cc0048f2f0f10e5ad47b18041db5f3a5946a446307c304edbc8700000000095365ac535265656553ffffffffd3383d15a061fb1ec342ba4bdc54785e662a4870fe019ed8dc8b9e78fd5089ca02000000036a6552ffffffffff0de3133db27a060133f3c115d1f577c2413352281a4a573fb545d99335dbd50000000007ab5353ac526365ffffffff0436d7100100000000076a516a635163ab2012120500000000035152659ebdd9000000000000fbb6420000000000036a6551a50bf641\", \"65\", 2, 1514398134, \"5b51ca2fa5e1b75932ddbf7cab5c826b590b5934d0b546caebf5c20991045078\"],\n    [\"0200000003b0d506c75a9b9aa4b4f03f05c5ebc3c23989256d45aee81024fd1f1e3fc20e9c00000000016affffffffd72a57d09bcaaf2f4c7f17f59d62a0cb018882dce6e880413640d8709663bc60000000000851ac5263525365acffffffff518e96fe051034fc07e1ca404626053860084af31d9f40502597b079fafb28f60200000009ab0052ababac53ab63ffffffff044ea482040000000002006a3d7b2c02000000000100df058b0500000000009a48d4040000000009516a6a6a5151ab656300000000\", \"ac006a6aab65\", 0, -2008432503, \"6b1abeb7e58c520cb733199c4934a8befdbea7bedee3e5e4a8e7ab806e8d02a2\"],\n    [\"0300000003e028d130176b48a6350b3dde6e6054d6bc6a30b195876eb869dd8eed473a647702000000015361c5ed895780eab3d3ac7fbe49f8680a9771a9681972751b2f41ce8116ac84235f6a42e90200000002ab512f97c610eb07171805b4a1ae859b213d5af0f62176a26338c5a89c73724d8479f21aea0903000000050063ac5163ffffffff04c74bac040000000001534bf78f0400000000086aac520053ab52518bdcf50100000000026a638c96fe00000000000965ab516aab6563636a00000000\", \"ac52\", 2, -774620676, \"94366a0d49f85a81d874fab8471e6fefe214c6c753607cf7c548b73705ad09ff\"],\n    [\"01000000025a09bb91ecc6804d114187170146d5e66f8c4b1e834a5ca6d96488140656af910300000007630063ab536552ffffffffd475c4ffb8f2c6c8df48913aca72396555295466b1e8070870b3bb1924dd5f7a0100000002acab84c331e101bce655000000000002acac74a12b68\", \"6a5200ac53\", 0, -1211794859, \"84c2960ff50b5eb82797141d92bae8053590ac32aa0502ab51a69fdecaa68fee\"],\n    [\"01000000022f301a69298aaf4d7d44fa46ce84308226c0a53799bcf91a6cd2626a43a374e00100000000ffffffffc09000624d527e9ecb4670c9b9a4100770bea45c5d980261732f79948664a527010000000963526553ab65abac00694ac1ef015b03bf02000000000651ab5265636300000000\", \"5165ab5100ac00\", 0, -84205700, \"0b55165e96fc69779c2364306392e0505725788675e4f33fb4f3e861cd40bc02\"],\n    [\"000000000203318cb6afd1fd4ce4ee86a52cee7e17252aeb73bcb1079875c4d9db07470355030000000165cc2f5ae53d924680ae7ef97989f3475bc57b3440c30520e90a7711454b2ebb60895ca9d80000000008ab51acac636a63ab8e15b1f9032c9fdd050000000002acab60eeaf040000000005006aab52635b1da903000000000352636a00000000\", \"63\", 0, -1137960225, \"64434c1d8bcf238a917017d3e125502545da7074866924afe49669c8c1723d2b\"],\n    [\"01000000022c05a3625684876a7e047dc256dd7a7d2c87d678cab452c88f7bf3ac4a09d434000000000653636a515153345b0e608a9d76765a1b4ea2b0890b5daf97ce103d2e41edd38fc497d92585e2a13efec10100000002636355de9c9c016cc5810500000000010000000000\", \"6551acab5263\", 1, 729700510, \"5285b6be262187bdf64ea129fbaceb5e9a7daf5e91d672cca1d546fd19c8e1d2\"],\n    [\"0200000002935dc7b5550468326bec24262924442c2dcd27e36cc9f7fb0a5004a7aef54d890000000002ab008fd0dd615b90d1a31b42029df8b6b5d27aa442358d91b1fafea321f61a7354da7cc8a1fd0300000003536a5231b52ecc02b9b26d05000000000165ab81f704000000000165f16b6999\", \"00\", 1, 1496667872, \"eeccd19c5439b03083d88bdf114e9dccab7eee3da92070925fa57a6c2afadc3b\"],\n    [\"00000020037bf657921ee037fa9470f88af7214c3eba8d483694ea99bb693326da3d525c3c020000000452ac6551a6e897162e6aca1818065337caf4e3ed173877363a44f077a97714ff89c9f3cf7cc736a70000000000fffffffffb13ecbb94cc8ed5ee24d60207bfddfc733f6d88929dcb95f053e70feac60c57030000000653ac52535365ffffffff04888db80300000000076a005363ab52523a3f050200000000066a656353abab33a9ed020000000000e80cee040000000005acacab65659745df57\", \"5365650052ac\", 1, -190680599, \"f7f285bacaf5bb6cf5eddc1a3ac39d404a850f9558a1dc0a269396450406f7c2\"],\n    [\"030000000428997995414d08ae6975a820f24695a2cb9f50f31d0c8e167c0cd0d88f74eb8d030000000600ac5200ababffffffff74f09dbb91880dbd8846c8c896b992d86a94ebd9a87f602fd8480c611dce11ad0000000005655353526ace973af8dc8e9379f878c1e7410a1275b8119d68ffb560779106188835b3a37b46a97c8f010000000763ab52ab6a51abd25ca620c639385adf0ca49bfbe62dbd713b5ad4ca7b07b95e8c2593643acfc87ba9a605010000000951ac0063ab63000063ffffffff0250903d010000000000192d53010000000002acac04a516bc\", \"5351635253ac\", 0, -1306085814, \"6bac3f82b217ef3146cdde80ac54fc4950f70d6c0e4656a983c3d7c52c881267\"],\n    [\"0000002003ecbe946ab501b5a48471a0530719c17d2afcb677e682136e43a16e6a561121140200000009536a6a00ababac53525c43451aa248e23871bcd9821a97dbe2b1593caa09d5ff9b7852031a91f7558ac92ab3f20000000001abffffffff6d4ed31f73b26370113fe45362c7830300dd79a0c1bcae5a16cdc92ca8954b3300000000056aababacab3288b677036c9e2404000000000863acac6552ac5100496f22050000000003650051d7e09d0300000000076a656363ab6a6500000000\", \"ab5251ab6aacac51ac\", 0, -777510124, \"9f58cd5c9f2cae0c848dc902004509824211f86d372b1a4247ff5ede12acd7cd\"],\n    [\"03000000044db1fb9a411aacf88c960f9dedc3870ed294ed7adbdf98437011a218f14ffc41020000000163ffffffff15dd279b08934ec2b30e7f3387249e88f9b9b709c3edf1d5ee015961c7b3a7b6020000000752005163535363ffffffff95a5344ee5809d4fa735a59431af6ef9e3868ec042a5d4706e851990df799ba70000000003ab656392e5661b37647594a46cc9cc7c154cd2f8292fb7b27da21c008c9bdc9a500eced72a9a7c0200000002ac65607f0fce0402bc790000000000026552de90e803000000000665ab636a6a63ba0a28030000000004ab5265acf3afaf050000000009acabac6a6551516553c074da04\", \"636a636552515253\", 0, 366361224, \"7ac4cf3e3e1325c1550db6397e9ab2b9fb353c111414024387dd5a746315fd9e\"],\n    [\"01000000030a66f812c30428a0c869372a2f1463ebfab915598cbda288fd291baac766edc00300000000ffffffffb8fcc556bbf670a8437967063e9a9043aecff8d83a2a53b67d55edbf08cc2c21000000000963006a53ac536a636affffffff1dcfb2801e35c4ca44cdc3b6166a57c704354c121cad623b2841af43e5a3e0bd03000000025200308d3748020fe120010000000001ac014c3c00000000000953636a636365ab520000000000\", \"006363525100ac\", 1, 734704777, \"6c18e9fdd0e970272c6630fc07d11f038a0908104ea2b3eb1e3b948121e64e79\"],\n    [\"0300000003ab43ea35588b45970cb1bfed8f0d917fa78548807ef9d63486052b2eee02306603000000085152ab5251515151ffffffff2c6bf1b6f67198707daf5fb7958d0bc389bee7e324ffec8ee7646a567a8efddb0200000008005265ac00515163ffffffffb4d37f2d48c8c8044fff42bbdfa7ae0a2d0564a66f1b704bca9ef28b4088924d01000000026353aeca2c05010e0d700000000000096a525252ac65ac6365a4da6339\", \"635163\", 2, -27669513, \"f7f0bc6e549e13acaa89412b20720499a83ac4edf056c76183565c436eb46c7e\"],\n    [\"00000000025093ff93132a2fac4df0ebc7764ee790524ac8ae7649e2a819f493c9308545a00100000003526565ffffffffb7c04a8c8fb08e7cecf5f77da5451dd51103f091d5dfa3f1fa840718940edc5a0300000009000000ac6500006a65ffffffff01c1d80002000000000953ab6aac5263635200d8525c14\", \"6a53ac00ac5100\", 0, 520357625, \"8e9df1bbc589a49995b7cced07d1948a30336099b7d9ae1361d1b30309bf2446\"],\n    [\"01000000037742e8e066013f582646de296580f9a2d7c26d40400152e631fbf88c48056faf01000000065263636551abbc668eb31dba257a30c1c64467e0925bc7e1ba5e1b80d4bfe975d16cba08b20c0c7953860200000000ffffffff6ac613c54cda08514696363abce622d0705740e114dd77c7385c6119c9b15a0d0100000002ac52ffffffff04617845040000000006536aacac635277c6390000000000076aac53ab536a531cd5e2050000000004515153acad806e02000000000300515100000000\", \"51abac\", 0, 2017296814, \"a55ceb3742ad65384c409f7aa779f47373a71154f8f13f7e9b22d58fb802730d\"],\n    [\"010000000403dbe2c051d0fbf3340b7d33f68e256f922ebdcae3df988deba6c831bc93a57400000000026aabb087bfc24eef7fab392fad4b32411f0c5469187d39ebb1cec0d488a1197c1cdb0591535b02000000026aac4b8703819485bebf421f5f9614eff395aee33132b4384583ac15fc4bab76728b57e61ee6020000000651520052ab52ffffffff167bb89d69dd8b0739f45471d8fcfbcbf768d5ca418931e47c44e40e81581b2300000000096a6563ab515151ac51ffffffff039386d8030000000000afb078050000000003536a511a6e4605000000000251ab26797b69\", \"52536a6a6a5165\", 2, -1082285572, \"d0dba98e2d664b603c9c43e8b2d66d48cf6302804e6536fd083381bf8712e513\"],\n    [\"010000000153f40b7e3bc5908ee0e8c81549f93d268d74588d4acc1802a1cf52c532de1b650000000003656563effed425017d7043040000000002ac0034ca7158\", \"5100515265535265\", 0, -1635280746, \"0991e78ce55ab8c421d7101b0f22c5e8266c9449797b2d2c78655fdf409c9fe4\"],\n    [\"00000000010310047d3f21afa15e3dc14a597073b2d558b61a02ef30f894603852ed11f84a02000000036552abffffffff04b069eb010000000004ac6a0065d1416c01000000000652526a650000a39061010000000004535263521ccfe401000000000652acab526a63265b81e4\", \"6a\", 0, -1035391360, \"a3318f999c300a3cc3dc572cf6b41a681860a356587dd33fae2eb446e800e68c\"],\n    [\"00000000016d0ce5a3cd10e156c449f367c2864dda88b4e7a77bf96fc3a374619ad69da8d30300000007535353656aac6afd85dd1002b5feca020000000000dd0b520300000000006725a08a\", \"0065ab6a65\", 0, -1747411097, \"6821f29df4296cd3a9a745df42c0a70b9f699242b5e4e0bef487959666eb3190\"],\n    [\"0400000004e43cf3e8f361bffb6968f32b6c03d58b09b27c7b0a99bb35430f23484c507d000100000004006a5263ffffffff694731247eb1da3bdb1156ca114fbfa9bdbe65a68975e8e4cba09e08871ac3310100000000ef3a1b0bc3a444c1014c624a81a0b84a0e2f56b6c5a7062caff9b8959497d7dc761938ee00000000065100acab65abffffffffe0efa6aad21228e8606c9703d9291aa7274718650aa177c3c23efdfdb1489db00300000005656a51abacffffffff02a385110100000000016379d9ac010000000005526365525100000000\", \"51636a6a\", 2, 1881013844, \"4422b704ec43f40184e0943e26ccb0a4c7486cff69244bade80c97e274bf203e\"],\n    [\"010000000280f9e39d841a341a4414e3c429be11c85a8e8d1a35841776fe341f6402314c090000000001abf5c6597c58cb04822bcef1bbd5bfd4837fc85d81950a8365a15c4d8208b1545b46373a47020000000100ffffffff01145570040000000006655100ac535300000000\", \"6aab\", 0, -1929379342, \"8a340eb56ed9a7c982c49a0571e98c489ace7e00620c13f8cadf0637c6fe8d7a\"],\n    [\"0100000003e257950d65d65ad8d9587c7965423ae5331125b5e48eadd7985c131ce0b1276b0000000008655352ac65abab53ffffffff3cf1066ba988f8c060eeb6b15b6411905b683678f24fbbe16057882059fddffb02000000055153abac524ee3cb9f006f963004027bcbb80dc19234386f2354fdc5e7ce0ce84b7194814f18b13d3503000000025151e7921db903790044040000000003515363a384ee010000000003526aac82e95a04000000000252ac00000000\", \"ac51ab6a6a65\", 1, -1468795111, \"936a694bdc3047c4886177dac86c1988cd27218f8b776af5ba2d71c7cff7b644\"],\n    [\"0400000004743a68b42167a576fa8cf15a538fb22920537b1292d38290b9b432f923c24a570300000007636a006351656affffffff854dc5ee6cad12ee819d6657bfa31347da517fe706cf54de060e5281de0b05140100000000529549564cea96bffc6002b104344a10883ba8905e4b897ebea2c7fcab4cf9dc869c6f480300000000668090fbd3393760b95b5f6670158d0617ed15fe1e390f1a803fd4f36e2e52e22dc7e96900000000086363655300656552f8542d47029d131b000000000001ab3f676e0100000000065153636a525100000000\", \"ac5251006a\", 2, 803270095, \"0a7a318d41c03cafd7aef08134e9b9c9b0ee45ad46a7c66482658f2ef1f35b3b\"],\n    [\"01000000030d9bcec5728045a4502d06b68d50b1f7f96b4bb9d44b18120213927272a646ac000000000253518e8fc30c851e02b08da3515a0c8e8bbfb1a6e51e34ab6730ee90ab793c1c2c67dbe02c7d030000000452000063ffffffff928ba0ec6603114fc6bdc93a7688b1740f6c201f16507e8fadd4a022521c13380300000000ffffffff03145380050000000007ab00636500abab7eb0750300000000055153ab6a63e0ac2105000000000045ec9a8e\", \"510051\", 0, -1094147853, \"525cfb8af67b0674e35bf4335a280bdf952c359a3e834da388596db4c7c9cb3e\"],\n    [\"010000000114d60839e17de4d6142f097c4e03f8253fb882ea17ff6e6092b2630274eda178030000000151ffffffff02a138a0030000000003acab65aa798d04000000000452655365a8d385db\", \"6a6aab65650051ac\", 0, -1557848139, \"8984e82dfa0904931a093deacc0a83c0b3bbad738fcdbf09aaa56598eb047510\"],\n    [\"010000000306e8e127cd7fb3c3fb77044c0c47356394fba72667fce933b9c4c23a8f79e032020000000452636351e74916fd94ed9b4fb05a00c00555c248580214e744e2e5fd72816ff4c6793444d3be6656030000000765636553636a63ffffffff3b6c427e7fe2204e7a2ad4f9530f9cf835835eb31618a3728ca6bad529ec5e5501000000026553984ba16e04b7eeaf010000000005526a00526a70621b040000000007510052abacac650ddd22040000000002515320cb66010000000008005353abab00ac0000000000\", \"51525151acabac5363\", 1, -1903343794, \"534298ad91f0b294fe77765bcab5d86a370f6b4d602c7b5e818bc65dfdfcfa31\"],\n    [\"00000020041f1e56c8490938436ced6f418f26fdae9ca2f296c4c427bcc0570a60154853110300000004630051ac38473a2e1bc3cef58d5262a1a7f00ccf0607d099f29d678cfc975d72f78ebf98c57497fc000000000251abffffffff509bc6d49cef442f8af006f5cc78763488224872a0a89cc308d50dd88aeb9ff30300000000ffffffff92c1f0493b723de89746d8221b3d905f3dede5c0ac2f0df5a2b3f9cd13bc7eed0000000009525365526353ab6a53ffffffff024a6845000000000008ac63ac5353636aac5c8ac8040000000008ab53ac656563ac0000000000\", \"53ac63\", 0, -1983375833, \"264153ae9aeb6b294c0cf54520006654542f3af7d420a2914d5fb56371008da5\"],\n    [\"0200000001a085fb00b39d5a481799677f4d7bc999caa41e1bb138232f9478805ee64a33110300000007ac0000acacab00ffffffff014886650300000000015200000000\", \"51520051\", 0, 2085232635, \"6896c14a8c095e2e14e7a614e83391012a9b9e45e043d35d4455b574a9378c82\"],\n    [\"020000000100de59cd12f5775f48f6f5ee48d790f0e00397abdf200b338e72930b94613e7102000000056551ac635154277790014e23a80000000000096500516352ab0063ac9346c771\", \"ac52515353525351\", 0, 266631607, \"693c791bf9c20ed900a1364eda474d33c52fbbc882e72b057a691c0269e02af3\"],\n    [\"0000002001f660c88ee239a24f1756ce2cf1204c252ed43c9bb1b7f02cd95087a2f95c77540300000000d57df31a012e55af0100000000036a51acbfa7a96b\", \"ab52\", 0, 1143537696, \"51c08e95572999c823249c881dab4c2d249827f71517331568b1e5d38c8d240f\"],\n    [\"04000000032872db921d006557b3ce25dd883545a69ad5afcdcf1bf3cb52719f1b085040d50200000008ac005251ab515365ffffffff2c579528d08f6f6cb941d3a630d61d37b613712b007b5a59276ae1a58722eedb0200000001531f4e0df84bfb67e00dc019c94120476ce127992fd5f785f855e2ccfd1cb7340432a8bde900000000036aacab08caf95403149add04000000000565535152005ec92b0300000000066300ac5365ac930683020000000005ac0065636500000000\", \"00\", 2, 1919568969, \"d3c55f83bfc9cc7b8eae7de874480e481bd702b6ee458eaf25fa292f446688b2\"],\n    [\"0200000003a629477716781d8eae98e7907990287597776005ab11cb767068a1bd6773d9c80200000006515100535253ca1110327462b73cd039ef9002943b3358ac3b3020223facecf175970779a24a0416bc770100000000ffffffffac8fd8345f7df3fd13c39f21b22327e4921bb3a38f2f8bb86ba54879e6fe1ea00300000001ab497a7e2c01f9406c0400000000046a5151ac00000000\", \"5152535300\", 1, -1197700236, \"ab733d13193dd322ec56ee880301afa6b7f3eba16b3d318128b732e84a27176c\"],\n    [\"0200000003f157d36429589573991e21fdf788909c36728892236eda1417b40d65dc1422d90300000006530053acab00ffffffff6c9325de4d33cca79a95892f6bdd6748ea3c3590469ba328ffec18a883ca9abe0300000009ab0052ac6365ac516affffffff18d823c4d4bb7fbd49bf2169479cea894537d9047e4dae6d2e94ae16d7b82fc30000000003655152b23ee3610270343104000000000151f39d8e02000000000753abac0051ab655cb83ab3\", \"acab53\", 1, -1810935255, \"8729509262111f9f629ada8584aa23e46bd15518c917a78c381f99e022f30208\"],\n    [\"040000000414bf20986773d15bc9309b2a0cd0c2c54b7656eb17036f7460ef268c7a44b366030000000200003600587da892c2ff9966f85ca9939d044be740b92dc6a682ccf94dc45fb23244519b6a59000000000463acababd45db1995a15decf58abe7993b762e09353fd9194078b525fe6be42d9ceab40a2ea8b2c101000000015331bd85e7f4c0550d06ae8f20627940efcc81a8c58ed99917d5e8fd97f91231cd5f27191c02000000056a63656a65ffffffff03b9f541040000000006ac51536a6a53bf2266010000000004ab51510090e9d804000000000300516a632e1f5c\", \"0063ac52\", 2, -1007187504, \"77d72ec4a36847b00b9ea7d76b3e23d389b46c0d86a901f1adfaef78c488d65f\"],\n    [\"000000000311a495eb284da602627ad25a447d85cd783273c133cacc9621d2211ff2f3a8c50300000000c2e141cb898ba2f3aaf0fa4a881b39177885097d8a5514e83390d037dbace1e75fbdf86603000000026553ffffffff4a3ec059de6498384a3db0db07b24c3a5e64cd8f3ac6970e89ca6c126e28523a030000000865516553ac536365ffffffff028f18410400000000075100005363005180477d0500000000056363ac6a5300000000\", \"6a6a52\", 1, 1649513241, \"2aded4aa8465936ce0917a3aaeb9c960b0a4005282308876be4d360479a834e9\"],\n    [\"0400000001ccbef362213fb57fef92c5fc32689987c939acfa6fdd195fd3fb574f99a379a6030000000153ffffffff038c9bcc0400000000090052ac0053516a63ab3422170100000000085100526a006aacabd54a0b050000000007ac00656a52630064f8bceb\", \"650053ab5100acac65\", 0, -427951057, \"51d8230e8b5855e3fce06751abcb24910e605925d9a80b289f800299184e63e3\"],\n    [\"0300000001f8234bea83816ac556c61c91cf1bd003b629a807a84654c1000f5af02994152203000000026500ffffffff028e9bf5040000000004ab006a53150a7a000000000003ab6a6500000000\", \"5253510063516565ac\", 0, 1259719428, \"732f19a508453e8573bb840bf1c5b60457d74bd38d92c720619940f090864ee9\"],\n    [\"040000000178750cc4570d5ee7c52de298946b2911e90090809545a08029561082b8f947b20200000003655151a21db1cf03c47531000000000003ab526a0874d40000000000030063ac5d5a8e0000000000025151c3c3685b\", \"\", 0, -1556988870, \"678bf4fb23f8f18728013d1c6f6e92ddd442bf4eb3c1ea4748153a7f09ebf2d9\"],\n    [\"0300000002cad097d9c9f891dd94c292a14ba6addfe337d430880bf54950a0c75c905a300a0200000002ab637120564d72977d7e86e4d5fe4e4c774567266805d73516dbd3ee8862ab10b51444cc4d8001000000026353ffffffff011231f10400000000015200000000\", \"ab6365ac\", 1, 2047544505, \"bc975b2859cbfd1198792de4e379bccd8e1931bfc33516fcb39b9fb92a5452be\"],\n    [\"010000000310e401f5c811ec6b1541b46d69743c4d5a3186d9fb23ccd8ec1160ac2102ac3103000000036a0052a1b92eeddb6af2e1725e410e11cce5be8e08ef28401f34254294711dcefde811b7b723f70300000001abffffffff7137ba4bd0ecd538f761f721dc0e9bc504f621c7543f6256a6e30586d26247ab0100000007516a5165526363ffffffff041934ca030000000007525251ab516a53c075ad0400000000055353ac5152b5998b0000000000076a63635363ab0062163c020000000007ac53535263525100000000\", \"ac53ab656aac\", 2, 324963431, \"3115a4036179c0379b24326190600f40b9e3dd524dc73724daea3db7d224188a\"],\n    [\"0000000003e0926dc7aeb2940b7ae093847d64c91736519bd5464f1e911d970e6a88fb2a1402000000066aacab63ac63e48e5ee3bd15c7578d84637ccb4250be858e9e8deb958c3e2a777eb705bcfa94b21ee42b0300000004ab530053ffffffff23831f45a0c7290d95f56d74bc31ed50cd6f069bf7769ec90cff74c4c5071a780300000000bbb7781204445b1000000000000400ab63ab3522f0050000000007000065ac636363c51150030000000000314d16020000000003ab525100000000\", \"6a\", 1, -696407926, \"8a278206b05c5c79980d150ad9d578edc5c11c6a3d2655d95b5abb1b78fe1114\"],\n    [\"0300000001452e70b4e84f985124bcca527f70dd14afd5d7d6d915de8ce0c9e8a8b1a6ae5b0100000008525163abab53ac6affffffff04bca3bb05000000000152f9d5e4020000000000323b1a010000000006516a00005153a24f1a030000000009516a5251ac6a636aacc818fdb9\", \"00ab6365516a5265\", 0, 946984658, \"55b1f64c740ca43cd35ef27ae6b7c103357dff4a4c20c2e5d07397149e1bf414\"],\n    [\"01000000049501b8bf6dcdf288e24bd5148e90dd544c4efd0d561b88d30c05586415e2dd410300000000ffffffffd6f881e6d4d6eeba74ed3007918d8df38be424d609a55ad7dcedbfd368b8d90703000000036352000cc6217002d7ac470cdb09fea3984dae2188bebd78b976c2b832d952aa715eb8532570ec0000000008650051656a65ab63ffffffffd6e551e0f3013fffe4b6c089db98be6acb0bfefd92162ab02c70419f564bd387020000000652ab00006365dd141a4003c7945a0200000000065163535165523f1441020000000008635363535353536362184f020000000008ab52ac00000053534c50756b\", \"5363ababab636a6551\", 3, -1736503353, \"00d06137ea8e01dcd79457ea860032df0a55112969a220d76767a4662a727c33\"],\n    [\"01000000023448b176852f79a1e5fa5c7e4db5875747170e6646d43cb40d222a49e106b8f20100000004535353acffffffffa39c763105f4be1bf79a36bd4d4e5dafa819a7f7de41d68c0be6608ef03723ba0200000005ab536aabab15846a8101419c110100000000010000000000\", \"5151535163\", 0, -1146978125, \"98b141e4acb2124986016e9b22f3f8021798b8ac7111f2de28cbfa27c65cfde5\"],\n    [\"0200000001d36944bfaf4b04799062d4c30423cfd0139f756dc3e4685ca2b5c4def704bfe50100000004510052abffffffff0195a29501000000000600ab5100526500000000\", \"6353005163ab63ac63\", 0, 1941428515, \"d59be92cd809a28ba202c2806c1a7a9a02a7399c94347a3129ad2bd0c6166f62\"],\n    [\"02000000035a42e3c6d9cd6e698e812187c0df473503a4b987bcd08c00ec8211a259acbe3001000000096a510053ab530063631d0a58e4f2dc0431e8b1fae39fd4277361224b82a9167e0e0c864533a670610debadbb3c0000000004ab6a526393ad3130734106cad6045a27fce0dbd09b535250792fcbb4510385b7443e9e9bdd68b5b30200000007520063ab656352ffffffff02be503505000000000800516351acab00ac3dd1f703000000000453acac5130e111e6\", \"51656aac52ababac51\", 1, 73718985, \"a45ac65fdfad1bb075084aa19eced362614cf20ad938c8016cb1ab33a6d1ba65\"],\n    [\"0200000003e503df0e1ced9e743adf7b7411b3583a580cdeb4c218270cc85b80377920a76a03000000085200636a630052acc40e70aa90e4ce4b3aae1592147132ed66e9711ddd1b17ef93b6cfd4c5f0b0421eea10a50000000002ababffffffff0eeecb28005f2b9f057289321cac03291dc9a90ee95c8350eea2935cd17d84e8010000000165ffffffff021e7e100400000000056300526a6514e218050000000001ac00000000\", \"000051\", 2, 255035964, \"eb7f62b9c7367ae92577c8516161c549b0a39e2e0756f53913510771d13b4f97\"],\n    [\"01000000017eab5d0a6e46b7aa4d86baf05c95e8cb6a7394a9e34589f38265f2c02fe463240000000003656a6affffffff04b1ee170100000000075265ab6a00ab651e2b36000000000005ac51516a6a0a3ce90300000000036a6aabdeb22b04000000000351ab51f5bc406e\", \"6a526a52\", 0, -453001622, \"e7351731062e61227c23d075a8b449f672390db05c4c430325fa826fd846f5cf\"],\n    [\"0200000002df9795aa142f886e8c65a31ebae32e839f6198700170d2d7ad95b788b1930a5a0300000003ac5165ffffffff6b671d1030249c1dcea9fd5ba4046981e7e60edff665a5cfb2bd99978524e70e0300000005526a52516a06aa3236036af55402000000000951ac5251636a53636a9e499a05000000000090b7a702000000000852acac51ab0053ab00000000\", \"6a63ab6aab63516a\", 1, 1173987514, \"89f2706e0a4bb87499817c37a886951349e85357308a50f3aa2147001570137a\"],\n    [\"0000000002cca68f3b0128f313ae500ad079657d6a3a383d16c096ccb9a7c6737888721d2c0200000007656353ac52abace116928f992725af832beedf4894f70e3154fc768fe84e78242e997645126b44b42857e101000000076a005200656353ffffffff03cbbbbd0400000000065165516353abf9954601000000000765ababac516a009fb7d9000000000009abac00acac5200526500000000\", \"ac00\", 1, 1263937515, \"09c5944d47a8746e5bf270877fada193b917bdda02b9302b15d66f7ad5472ce8\"],\n    [\"030000000281b71d792ef02a14b5f8b14f18f6d7d27db5f63948172b2a01181614da7c88190300000005526a65005179b3c396123203b94f421128298dd3fe02b514ac3f8d24b1286bad8be34e8decfb44f5a40300000000ffffffff02132ddc03000000000265ac123c8f01000000000700acacab6aac655ff09a48\", \"63ac\", 0, -611538801, \"25434783e45981f848ea7cbb82f09c2408ea63182bee5d764c976bd6d10050c2\"],\n    [\"0300000001bb118ef122e54f628f29065d145cd49d7a63823adb74632cdaf3fa5ca922b1800100000002ab524f35419b04bf6c0c040000000003006a5102ec70020000000000804ee4020000000006515300ac525350e3cc030000000005005252ab6a2ee2bdfa\", \"65acab53006a\", 0, -1023995890, \"4fffcab90e46bd4d9a493be9bce464c6be17edfd66a029a42e1c620f6fee01ef\"],\n    [\"0300000002edd873648065f1f5f87b329ad342bf9cabab901c0e5e08a7deda41e03d5f06fd010000000463650063ffffffff96f6255b38e619daad5d7537fb18eb16291968e36649bc6e472716551965b43a0300000005ac53516a00ad0abb2702567373040000000007630052ab51535166f40e03000000000400ab00512c4d1489\", \"000063005253535365\", 0, -42466027, \"bbdce944f0b919e2cab22024be4549f8750c2b363e7ec4ebfb023d7e8444f75b\"],\n    [\"030000000188d4b133c43369414d6f9bb83dd5e7fd89dd1d314e387ca16077447f7bae90600100000002ab656eca282f01ee72ac0200000000096351abab6a6a51ac639ecae819\", \"655163636a525353\", 0, -477112115, \"94364295c5770b83eef264f356c9b9aa9453f3f2df19489834d12d269845861c\"],\n    [\"0100000003f81250b37f6c0d1dda8ba1b7bc8af006c2a39dc31b67768579a3bb3949bb75290000000000ffffffff8acb1b4d4a81954ccb2655b401f263b7ee013902170545e6d8b880667a21254e0300000000ffffffff5e1c1de2926ee5163e51a6edb2229cce55e515267a4cfc5a0a2160f98b4e5e54000000000665006aab6565f1f25022027080590500000000070063006aab515200077900000000000000000000\", \"ac6a5263636351\", 2, 1867652022, \"e29874e34c72a5543e0b47d4b01873a2b316145dc83ca8bad3e63ab23f39a4fb\"],\n    [\"0400000004a849906ebeb7cb922fc9f7ce50a6b49543341860c7ee237468dceb1ac4f680820200000003636365c9018b91b727a45c1e5e3a7c4d305973dedf865466f12b8cca9440095f7e250c9cf80882020000000852535351abac6a00ffffffff89c367d5bb16214970785769b34162e017dee63c9f89628d0141a6a19db453230300000002abacffffffffc819dc49b7d364d6a5605d15dc3918d922690f4f254f83a6f2e09e9791e7c62e0100000002acab7651ab8002b9d5cf01000000000551ac6500ac2b14db00000000000351656a49ceef0b\", \"0000ac\", 1, 71276053, \"9e2760473e00e9fb07494a0ce68c06f4650e0bc511dfb5145c6a4df861a218ca\"],\n    [\"0300000002b1990abaec4f98b859cb87bb4474449471e02567275a2359c58f16c3ac6512b20200000003655351ffffffff19add21a0ecdda75de29b84c141daa19b3965fde9319cb87153a24cca661e61d010000000563acac655336df83b6048db801030000000009ac51516aacab536a5237c99d04000000000352ab6351cb8a0500000000006a401f04000000000853ac63655151ac519f1f2bf7\", \"6a63acabacab6353\", 1, -1644995306, \"ab1bfcf97350722c41c62fa99614cda66282fd3dca5af43af310df43b8b0e706\"],\n    [\"0100000003bef131e8e1ea6cc3b8e820ae49b684b70179ce8d9433977cf2063b606e19d4f903000000086553526a53ac63abffffffff4253f3dbecbdb431bcdf8b9e142287d23adfb64bd549ae5a2665d6a547d3aa270200000001acffffffff925b4cc2072bc777939776393c4597c90c2a333d2233fed7cc901a8d9d3179d102000000026363ffffffff048266aa000000000006656aab5265654c0ff3000000000009006a636a5252abac510fc099040000000008516353ab00006aab520b4b000000000005636a6a6353f70ed280\", \"6a6553ab53\", 2, -18299188, \"1a6da6f83590675c87ceaa504cee785ba015e5c1440521d752a8feda16d54d01\"],\n    [\"0200000004e7dbaaab6915dd3aaa6a6a50d982b186b7f77c8ca04f9cb726abae1ad3ed2909030000000765636563530065ffffffff4898dc342b6d09dc900d51839ccc582c3d9c53c83c43d25a6d487bcdb2d284f2030000000151fffffffff1ed56e500fb88011bfca5ac4ca3e2e85611602807027024efd0081bb83e7923020000000651526563abacffffffffb4027fb42950d92092d7ad9d137fc17a5eecddf0f065419f44ffbdf266d05080000000000952006a5163ab00656affffffff04f69deb0100000000035151651a76cb04000000000565acac53631066c2030000000005ab6a63ac6aa75f940200000000035351ac00000000\", \"\", 1, 409577588, \"4c0f42cb56aae248127129ef8fac93077e47025e59c8bf96304b786451e358d7\"],\n    [\"00000020028cf0b87c56bebc512cb4ce21d24f62351393912e355f34af506a34774491a9c6000000000253abffffffffa4da6b230236160c91ba8ceebeb31384e1c839abd0346c6736f0d674fec85702000000000853536aac65515152017eaea903c5fe0e0100000000015218aa50050000000000a5db63020000000007abac6351516aac6305c6bf\", \"6552ac52ac\", 1, 1643495810, \"7be77f8c92e1f4578c20edc8e6b0e995d145a8d1bf23647e21bd4be7fcde0281\"],\n    [\"010000000229562433e7aa328cbdf8f2d167f7e3973d0185a587d337726151c52107c569a00300000005006a51acab3ec4b1e9778a1e6bf273a13992fbaf5253e49c52ef390eb40a4954a9bed8fc6c6bedc34d0300000004ac6aac52ffffffff046f92d2000000000007636a6a5300acab453a38010000000005655351525351432805000000000663ab63520065c3ea96020000000005526aababac71235955\", \"6565656a6565\", 1, 998179080, \"e344765cf42f02b0e21924cce61e02015f207cdcdf06dea132507b99dbee377e\"],\n    [\"0000002003cb51798f29a061837b4321a56c9c3c8ebab4004933c1b361fabad41d5b0d19d702000000050063005252c9077cb51f5822577932fe7d087e5a1c918b0e0f2892bf60025f899b09520163b54e2191020000000252abfffffffff477f10cfb9e4ec68b6a2916803f385912a13f4d5c537e9651b7439de56d331101000000086365530065635100d6fa2676047f6241050000000008ac53ac0000525163f62a9d0300000000070052ab5100635367a28e0400000000076aabacac636a513c0d990300000000075200526a0063ac67c21c76\", \"63\", 2, 1255564188, \"204a2978eaebc07a78b64ef28bbd09240513870f0c61aa799b41aabf5ef480fa\"],\n    [\"000000200134680e3a2a047b3a627aef511a2bf12c9fff7ee68e1051b8c2aa7281226c5b00010000000663ab6a51516327867d2c03653a0c030000000006ab63006352abb0a90c02000000000263acff2e6c0000000000006efe3fb9\", \"00ab\", 0, 1548076053, \"c9284e61f25be17deb5d77a5ab06be65c4d4214e177d118bb78e593583036687\"],\n    [\"0000002004ee6c3278ba7f7d3e41dd54e3b0d3e0dfa206ad5237aa8add700eb3d99b9205b403000000040000ac53a10138e7eca5aaf84945810f92de724de69f8a2de58d376444efe929cbb21b7b52bba046030000000463526a00ffffffffb9f270748ffd837d3ecd3c1c9ae71296d34f4a36daceafaa13429b6ec2778aca0300000005536352ab63bacf9d236e73c26ffebdd23a34ee472c87ae490ab4eb851ad0b940fefbde6b38cf24f2730000000000ffffffff048fa5b40500000000016aad2d18030000000000dfa1930200000000026a5312e1d901000000000300635100000000\", \"ac5163636aab\", 0, 793499043, \"64f64dd1349b105fed426c952a57e58dbf0d47fa7d72f78b2d27b22113938a19\"],\n    [\"0400000001b79d519a5516f9aadc322cbc994b9718cd82e471d24700723c75fdc1315d4ee000000000025252ffffffff036d4054000000000007ac630053006a633e49a4040000000006ab5300636a63c3b359000000000002ac5245b6501d\", \"526a52ab526a53\", 0, -1622063537, \"211f03f440f72277e2595a74e758085ea7337052a254458ab654efa8db664aca\"],\n    [\"0200000004f8db3d9b5d7cbe770b17864ad65ed36265b14e8d50b778811ee98af5b5ea3bc90200000006ac51516553ab5d032563482daab5302402f123bc8dba21286f1dfe6cce7919aa42aa2e6130f7a47902ec02000000096a52ab520053ac51acffffffffebf3747e0a15c1354f88eab2c992d33a3fb03a19909d372450d4a0bcb1cff90901000000095251656551516a5351ffffffffd52758c040711a71c8b8ea7243d28034dcffb0323ff90b10ea607b10f95897420100000007acac00ac63ac6affffffff04ecee040300000000002e6a31020000000000ce527a0000000000045253ab512c760001000000000865536552ab635151e686a986\", \"00006a65ac63635265\", 2, 2017751517, \"cf7b39319032197883c9e58d9488f03b9c6625fc8afda8e08c50718c81233f27\"],\n    [\"0200000002392611580d2eec9579e6f1cdb1971d5f339263c423d6fda93a7e11156df379ae020000000552abab6351a74d76093ecd0bdbbfb8ab49b1117799f7d1940d41ee434d2a7807157b7676ae0da0042c000000000800655365536a63653064306b0134fad302000000000452ab655300000000\", \"65536352\", 0, 943507867, \"014ba9a077d3f53ffaa431921c3060bad63c66c871c815d8ba857ad44f185eb8\"],\n    [\"0000002004888266392aef2e45f3457b71926fd63d9a48ca32d24e4da2f7ceaed6ea376fca0300000002ababffffffffdf47603c8102eaabd7150be27bb5ba50773c1fb7479cb8820c6b82ba137a1eb10100000002abacffffffff6740d50d352b2b2f8a3652d783904f3b506ebaace0a46820841349baac37564c000000000151ffffffff44daf3bd2909fb267bbcb231b8b79b0d81d931c47baad7927071057af2e05a930000000003005363ffffffff011f38e6040000000002635200000000\", \"ac006aac65ab51\", 1, 679149822, \"230a675665f43c3e3fc7950bb4af9124b3812c17b37ce4c8b4c3d66fed0a7c23\"],\n    [\"0200000001631e916d87bc74442541405d3aa7055287161d5949a245c2457edaaa991018a1010000000951abab6a0065516a51ffffffff01de7bb6020000000001acd47ff4c0\", \"\", 0, -1411936615, \"8ccf3425a8bff11b200acac14f7cd232fb008a04f37334064b7a38b01b0f96c4\"],\n    [\"0000000001278d417db89213a6d4db5adfedb68515cae7c92fe6c686d8b6d972052b5dbb08010000000452ab53526e6886ec034c52270400000000030065523e1a60010000000005acab5200acdff358010000000008656aacacab00abab00000000\", \"5253510053ab6551\", 0, -437136814, \"4afcf00033908ca0d92dfab4d9a944f749b50e57ba98c4d517b0086fa5fcac72\"],\n    [\"0000002002dfec9162d07c65cc93e96f5d2173d3b5e8dc6cbc018df52376556e55c365698b000000000453ac525113c7cc95dbb4385a87761351fcc1e340baa5a1232fe4dd6aa5b13bd17a84d5d537d4d7eb0000000002ab527eb35e69032d694400000000000700630053acac6a63a69500000000000463656563d1375203000000000000000000\", \"516aac5263\", 1, 1691647025, \"436e21890b0ff97236e8dda7e33448d6f8dc779bfc9d6379e2caeac0bed2bdd7\"],\n    [\"00000020027d3e885adf5a3249c8543487a21814badfe437039d5f6157fcf29d9b23bd7b3301000000096300ab6351ac000053c09342a6da32e9cf9d9e07e85b5ac00e9a3877e6e379be617fe7d8d77be65198ba362d670100000000ffffffff01b676a600000000000263520d4fba90\", \"65526a636a6a53\", 1, 1931102397, \"fdcb912b399a1d215d9313c7f3a2f442168af28fca64da7ab3bedb5b6be6b211\"],\n    [\"0100000001aef0b142a35384680ee48f77909b80c17231f702d92aed640cfd5929b394113b03000000076a510065acab521f3aab4e03a81cb6040000000005abab5351ac56676703000000000163c59dc2020000000006ac65526300acb8fbd47c\", \"516a516a6300\", 0, 1966170773, \"7d4546f640e1d73f25500306047eecdf392fa9daea95ecab6f9869704a5dfc7a\"],\n    [\"0400000002c0163a25e0af324a3fcc3c68f6a04ba96cefc2761b03b3d8a638af7e1721c14e000000000353005278080d969c59f1196dcfe92eb273b2d9aa3b74fef2216964d8fe55b50c01aa8cf19b49ae000000000965006a520053525165ffffffff0329f68202000000000100ca2fe9000000000008abab526551ab636a4c4aa2010000000007635151ac6a5252901efff3\", \"6a65\", 1, -125173602, \"1efb6e1469a841eb7b24586fc1a8256c5ac35e3cf25778f0b8bcffbabe370609\"],\n    [\"000000200205d9a4d08bcd1025be6c3cd0385cddf899d6befefc0e14608e8c923dd70bde950100000002ac53ffffffffb86ae349df6f5cb47062bf2d8cc075ddbdf275ac586a4600705c9a2f1a6171950200000000ffffffff04e2a94b02000000000653536a006a5268b4d7020000000006650000ab0065549b7901000000000026bdb70200000000055352ac5300a775c323\", \"53536aab63\", 1, 376980315, \"ade56b05095e56f228c8bdc5b2524008fb7323cb30262fa37e88096d3236d828\"],\n    [\"0100000003fac80ee1b399667b9486cfce8200799536e7df1d7eb48b5280b4252070db6c39000000000863526365ab6aab009a3fb4c8bde10f2b782a65b3a58d3b8c0940b6774f38f5acd864f57197adc498e285ebc601000000056a656a535374703ba02a046945c8ca0354d76aafa1425122209c201457b2ca726fb4ea147205108660000000000951ab52ab00ac636365ffffffff04745dc2020000000004535300656204d50300000000002d5920050000000000e4261e0000000000016368ca266c\", \"535200ab\", 1, 1009824482, \"69c7b153f4939b1f5310f859efb303dc601c40c4e16ee61dd7cca5038ce7360c\"],\n    [\"0000002002597f1b4a0c4644a5b4aa2d7c74cfe76aa9be2587215796ae2d8a22cf2c533d83020000000952acabab6a516563ab02a006610d77c7b60a49b6b57fe0b337df8aad14f4fe809714ea16da69c848379cf74fbe0200000002abacf5f13c62032e81a90200000000070051535251ac63cbf3d80100000000095253ac516a530000520a0323000000000002635142629817\", \"656351\", 1, 199369841, \"11dd38978ca84c54ab3efbcbfcf343faf8e72da9a48f8e29c7a1a1165b90aff4\"],\n    [\"0100000002dc6c1a98231581de40a4d28d5483eff560f6cc59fba3ac82c3378ac9c7d6866d030000000752ac6500510000ffffffff2754009243b3d5297d7a1847aa41866439176f9e4ce0f7231b9febd1a6208aec03000000056552655200c47ffb8e0274799602000000000865005352536a5352713b90050000000002ac5100000000\", \"5163535351\", 1, 1078405036, \"a0abe955580794d62f660690390557b75cafaeb9485c73800635d12b76beab7f\"],\n    [\"0000002004b7b38d49a84fc8b6357d960a64ced370ea3c99c2ed9bcda422740db3ac848ee70300000003ac63abffffffffe6be3ce3d4dd9939a1d86f19923009bd2c0811d1be2d5a48634289f2c05db02800000000096a515251536300536a39f2a5caea3ae73039896ec1644c666e1175b1cd98af5c7e56dbc46dac15f9116b1d1d16020000000700635251ab51acffffffffac2388ee169e74f1de0365dc2522565f51232fbcf62de6b8928c6b1b515e1c940100000001ac83b5484c03dc3837040000000004515363ac03f5d4030000000001512b7e5d0200000000025252596e075c\", \"6a5100006aac6365\", 1, -872666786, \"2856be030316535f49112b3d72c26e93c1e39063c1b8856a12a8f9577a88b47a\"],\n    [\"0300000004ea7ad5c2fff0755c62259f888b4a14c1d4e903e993f22fcbf156fde60b28fc7102000000026a51ffffffffcc0d2fbd025de78d5f1ee765e80b4c2330584a9a5b6a689fdf20caa73ef943e0000000000863006a515163ac53ffffffffafb576612d3fa2fbb6194f35a432a7f043b4db04597c24cc125a778977a590610000000000ffffffff00df97fda90030b4888882b0a3b5ce5ac0d313e8d74fa9d9916fd4314e8ea24a0100000001653f357aed01e92eba00000000000665acab6a516397b0a126\", \"ac536300\", 3, 111164955, \"b12643d81af25647f1a8b9af79fdffe1956855fd17c000068380ffb180a44a4b\"],\n    [\"04000000043e3da8ac72dae33a8717a864fe8f76e4bf4ccd21e5315867e6283e15605a47bc0000000000bb4c0b34ca10ea1415601b5f58e2d2c6b60c6601d2361c377d3775ea89748e959b21311f0000000000e4ac1a8be496e44ac7911bb1e280450b38e88e0e05f04e381d92b3adf4b91148fd44537102000000096500ac00526363516a753eced9b21229210e6806cc7b74bb4f859297c21b2e6835b01ae4e3759511039f4e6a9302000000076a63526aabab00ffffffff03231995020000000006526300655300943cdb0000000000065263535153abaf8a650400000000056553acac00a064ba40\", \"ab656a\", 0, 1728675827, \"14c428be021f82a6b2199be0f3b996effed9892fd998dfa2b64d4d5d62e498d3\"],\n    [\"00000020037049a9d8d38d095bc65f5af5da1b3833b0d0e8561574506aacd780a557833e080100000001516a3180a30cddf1aa8be180d06e3b5cda68a7b7108b06f34509fa1a36d6bd4e576fbac40c0000000006635165655363ffffffff976967e909501eca9b46ebc123fe74fa7e6d4870d87f72cc6f9544b39a7d0a830000000004ac005363ffffffff026ff3990000000000006d117a0500000000040063006a50dae207\", \"65656553\", 1, -624679842, \"a251084187c82cec20c849e5cd04e59bc25c6274fd9d7907395984e667873ed4\"],\n    [\"0000000003f8cdbe5f3286e4c11dd9a102a7c15bc65a187e4a2484d56a9e56df7b6b2683a20300000005ac515263513a1a7c7205be867609f4118c7433b0f96c9e0c8db436132c42b7380504de04606d942ae10100000000f366ea64d1da6768db511689967634f94c487d4637e7e92b04beff49e2bd4655570f16370000000005ab63ab63632da85e2101b7d126000000000003535100eeaf6251\", \"ac63ab\", 1, -851149569, \"de6f71d1c3bd052c24e4f9d4a3464fa3d5bdbf02797189d18269cee66a22876e\"],\n    [\"02000000010872de55e291c7e6f0c6c49f84dd178e22fabe8f0157be92553de7a3c11a0dd50200000004ab526353057cd60e02d44915050000000009ab65ab535353ac52638bde520400000000095263ac53006a53ab634ef7a604\", \"0053\", 0, 1104141523, \"0acef0374ee3645e51eda19c08cfda51a00299e3de28a511001d20e8266b2863\"],\n    [\"000000200338a6425564c8be6f343ac9da95a43149cc75678108b4944a74f24c7aeeec13ea0200000007ac65536a525151cfb13d09b7efd9646726d50fab074ed6285340a2ca8b20c7fb1da3bb41213e9c32d07be40000000005ac536a65abffffffff90f9b06587f504464b71d04ff621ba3b6643dcc4df8890bd03bbd53775dfa0cd0100000009536363ac635253536affffffff04a302a001000000000665ab655351002637290500000000095253655263525352ac2eadde020000000005ab65acab65a4752804000000000300656300000000\", \"63\", 2, -1064328795, \"8fc6091e6a1a22a3ac47ef359bf9cfe83a2e213652a80155d72cb434831e2405\"],\n    [\"0000002001ee831b1b6da3cff83edfa70871520b3cd74070d1a2350d13a823fa199ab921f2020000000651acab53535398364896025b022b0100000000036aab5370fabb010000000009535253656a5253636500000000\", \"52\", 0, 816328533, \"9ff7bc93e6ec104cc5fc6ecd37aa95653f14006e8412c2b8c3bf79cb37bd9eed\"],\n    [\"0000002002166006f738888bd9b23d7e3833f682e90fe029f78ce679b1232cb2bbea5426030200000009ab0063520065000063ffffffff9602e18f0d0556cf8f01cdecf59d937f599fb70c9cd62917435d92ffbd84a89c000000000851656352ac53516a4c4c3943017742960100000000015308e8ff76\", \"ac5351005251656a6a\", 1, -1982574068, \"a8e55e6ebd0ac153d8cd56e7e567472e11a1e7fe3729fc98e81bb269970564ed\"],\n    [\"0200000003fffe61da525537625e8b477130608274b83c3c00e0dd8bc998e854ff3cf1a1ef010000000763630052536500ffffffff5fbdc00a728bfc52d48d6ccd3b0101a17f4a67816a34e8fb7cf74c194d647d19030000000152502d50379b2b7998daea758f577bc406dd47c4c39acce4efcc5946b0c84dcecb67393380000000000765006365006365e6d375c002c0b841010000000002535396728b010000000008535263000000ac6300000000\", \"ac63\", 2, 331352171, \"a25b8ae16686e6765270134d160273e01c3d8010500a4e7e348f8081360b0326\"],\n    [\"00000020019cb68a85e09efc797a326d4fb9ab2a4493cda808308a3cc109ccc9593f65553400000000096aac5351656a53ab52ffffffff0271bc3e010000000007ac536500656a6546542b030000000004526a5253aa046eb5\", \"51ab6551\", 0, 519298654, \"7c2763015e718be73bcbb81bb347e40122e7e11d2b73842abb4615daa6b06a92\"],\n    [\"000000000164eee2f8f768ff928dbf20cd9cbfef92a213ed55739ec2422423acf7de5c97be0000000004656a5252ffffffff04b9ab150300000000002f343b040000000003536351c8390c0000000000002ea43704000000000665516351ab0000000000\", \"5365516aac5351\", 0, -1295234792, \"4f8ee6f4de7483877ad4fc3f16760cbc7e95c8a32850e93cc11e3f72044db859\"],\n    [\"0400000002e7c3424c74a0b1d040e5836261372fdbf43f70b971f93258ce0f10d54824ba8c0200000004ab53ac51f6f652038b133d9c31da1ed006025a4e8548de8417865999a84856e2f1d04fb94b91e59b0200000006510063535165ffffffff044e370e01000000000251528506840400000000086aab526553ac6300c94cc6030000000003526a522860f0000000000004656a52ac00000000\", \"53ac63\", 0, 2081148714, \"38a44874b59a4d5c6b42ea05da224d0fbf6aa192be0cd4d282068d4c48229d2e\"],\n    [\"00000020046ca1078fbc8e9641ee734960adec7d6400f7999d4a5da406e371b819fbeb555d0000000005636353ab63ffffffffa0c803f38d86712338d04ff0d5f7391ac3087cd1b2910e7af943ba5de715f1b902000000025153249af31b9bf0d683fa36823288d2328f36d4ac21871d79f906e7a815358e66ae30c393da010000000465ab52ac14acb7b8d50f2e17302f9d9af60d7279a74521b62da6202e8dfa1c59b5a36e31dff9283d03000000015348c7d56403bcd28203000000000451ac6551e1ec97030000000001ac91e9f00300000000086352abac65536a5188b5c3ae\", \"635152ac6500536a\", 1, -1000311214, \"ac7a2c940f4a108a341ff7427820cc379a301ca357626e34bf99403d019ed706\"],\n    [\"00000000037e15d1bc4e64d77965e0519c125ce4d49df6d3d6b450e5c3e0a46844bb9ccae8000000000153ffffffff38cee0cc9fc20a58d20ae45507181fb218f3a44b95deb4198797b65c002959fb0200000005ab6a5253acffffffff4c6ceca6d061e12904c05558e651ff61e60fab52518ab15cfa2c3f3b2ca22025030000000765656565ab63000eeef0dc03bee080010000000003abac514e47c3050000000000b0065702000000000351abab00000000\", \"acac\", 2, 469901226, \"498c92484299c47f7070311f0b5a0a2053ece8912cc203d148b9e20010f142b9\"],\n    [\"01000000049511c1cca8db4c19172315a5a054918eeaa2e208887bc1f562ff7643973d41ec03000000060063ac536a63ffffffffddbfaca8683a058c7d8919aa1f7ca1e85ae8c97ec2c4f82c7f0f11d4b7cda276010000000565acab5353ffffffff9bc161d74d1ff93cc912ea5090bcc3d2b98abd885df9375db0fb9d0a775cba1e03000000096a006353525251ac6affffffff31b3c49113957af60f4978041eb4d234a2d432ed2c87583375ccad5e151626c0000000000100ffffffff01f7337d0000000000046a6563516a2a83ba\", \"00\", 2, 2041924638, \"447f48f454118211b81584c38bc235bb649ad5c59f5e050fa4a29638aded2dd4\"],\n    [\"02000000047bf8984f716fcc2595ad0dc7ca00cef72ddaf1c10a1e1949641526848f1487840100000007656a00006563abfe45256c10467e837cdbc54659c0a7c864e547460b639af856f3dea04f7bfd4f6f1f42c3020000000151ffffffff38b0a714751becc07c5e4f085b837d81dec26631c26f92872d69a9fd2ce0e07902000000085300535200516aab00764a9ca21e010b315d649a6dcca8b09037b6ba323d23c19bda7482497e87c4d777c6bc00000000066353526551005e6b5ff00208d735020000000005ac6aab006337b566000000000001ac3105812f\", \"ac53\", 3, -1981436377, \"8bd6511334a08e75dae68e99f6052954577b066bdf4db445844a54be3cfba7c5\"],\n    [\"04000000047dcd1081266273ab164bdd972ac06c5bf3e2851833cd84670b8ef8fea0a1115002000000096aac53006a526a51abffffffff97ed1764977e19fbfc16c581a2211df8c662bcebe03b7dfccc6a73fab0600bab01000000020065b1da01f970aea046e423cc9033cf5a5b6a841c6e63e3da9cc3095e8cb30cd2f698085fe800000000055363ab516a45fc5e67cb15fadacf816614134ca41991fa07d1379b46d0537390fa24b1dbef0a39417c010000000363ababffffffff043a1abd050000000001528911e304000000000552ac5265634e57d2000000000006ac6a6aac5252fcc415040000000003656a5200000000\", \"acabac\", 0, 1589968373, \"5658e9a53c0997c33116f168feaf9492be2b7151b32c39e7a427c64e621514da\"],\n    [\"000000200138002fdc5ebcafe3604023bac72e40ecf405aaaf365ad21af36af144d3681a4500000000086352526352650000d27ff0ed03812706020000000009655352ab00acac0065dc0c46040000000004ac51ab51bb6e83030000000001ac42c6b1dd\", \"abac52ab53ab\", 0, 2113457550, \"e9cd974045d2eb8cadd3634514833ce67fdaeb1e52792d36af8c1162648929a9\"],\n    [\"040000000341d3572ecabd57a00631b342f63f3829c84a32d89d8cb673f704ab5c05e4ab550100000005ab65516353ffffffffddbccb24ac31bff7563c2273560d5a4e8c94ac7357767fb970356866978850d90000000009006a526a516365516affffffff5b77cc24cc1f5ce8a86795a11c372623545302f3ddc652d3192cd063d66422f70200000008acabac65520065abffffffff01a44211040000000003536563c60fa824\", \"6aab63ab00ab0063\", 2, 999910725, \"823ccf390fc6a94ec87a78d0604f2293c064451db371949ea9b97dc8a8190d37\"],\n    [\"0400000003a9bc9b53dc0a5b9d151fa4287b463547298eac0431e0d71f4984a6c209387f31000000000451630052ffffffff3545ff8f6281425af415a5fb54c877d464d96487dccb2a0d65f7b839a2232c540100000007ab65636aab52638e9c99d9b33485b415eddb047baff1f6f995115f95aa175779fef9ab1f5ebfe5668268aa020000000863636aab0053ac00ffffffff03dae82d010000000003ac650023a3ef050000000002ac517ea708010000000000e6370283\", \"acab63536363636a\", 1, 1547550831, \"54e91a79c2d5a0aa8017da6a0fda86d6c06ad2f4b96813e6ad6c5ba65e8da2b8\"],\n    [\"0100000003996d62199b409297f22afaaac4d52eaed01bb8b383a13cce7a677e350d7d498701000000056a63ab536a28365615d75dc921f5e9fef5da9c90c4663fd9987562e374f3b58dc6c85e146d5b58c3d803000000056552635363ffffffff5668cd018fecc69776431c85a91ebe98531794c555560fe9ed50f0c956ae63d70200000002005318e28dd2017a453d0200000000066553ac53acab00000000\", \"\", 0, 1951893589, \"b166134c17d44df8aedf52a367c419fb029e926dcd56378a57608b4029a60b4b\"],\n    [\"0400000003f5bd494cd00a6d6eb27048a5595e53da88ddcfe5b46ec7a143b3d9d250b93a37010000000100ffffffffa973f67e1679f3c396a2c89201d477032806c4bb1346000e72279c2d12960ffc00000000025151ffffffff791a8e6e4c2e87e7e819518a261edc0379b81bac674d9b61fd9cba6a0ba3783a030000000565abac6a65ffffffff04f1512b0000000000046aac63003e12f2030000000003ac51ac46b4ea030000000001ab8439880500000000015200000000\", \"51535252ab536a6551\", 2, -374554462, \"1ecb6b97bd2bb3f50de917189c9c64dcd327e68a4422fadca4d4ed6402fd7b5a\"],\n    [\"0300000003f48ca5d693c6a40d197755b4e0cf30f2cc197356249758108f5b0cc87bd3cc18000000000763ac5100005363025c311e8011aca16ee85327fbcfec01811062c3ff499c5ffaf6fc01b1da5b5d54c9a4760200000000ffffffffa1476470b1d337b17bbdda1aef055d6d17a2f6e7853101f8527713d70a95d0b70200000004abab51acf353728d0156c692030000000005656aabab63784b349a\", \"ac63ab52\", 1, -1704429793, \"003bd2c200ce3d36cd8c9572b6ebd8da2959e9c40e8c56413e49ae37a1984987\"],\n    [\"01000000040ca1974c7d8f2ce30ae575f93bae4c8847c963eda93427a7f890aa9912544ea201000000026a53ffffffff3a3d23fdaea3b6d347159a0d3af88a5a8b45763507ee243ad4e251c4d3142aa30200000005ab53526a63f4df5efa8e7a88e2c56c19dc1ce9a0cb686e6c218a800b50837a05b2f7e50aac67e18600020000000963516a0063acab6aabffffffff2bc33b75d8ff6f74e1306eb9b146928b57e1e096943f10cbc0c0a0809f4fac5c00000000065253abab5200b7307c4704b0232901000000000963ac51536a65ab5353998f4a0500000000016577ba48000000000009516a005252ab6351529bcbd905000000000352655300000000\", \"63acacab53\", 2, -863685420, \"01c59e4a66fb194d63a26d61677d14829e440181bfd9c7d51b4050c762fd2f93\"],\n    [\"00000020049d57c61335648e15d9b201dfa737e6903f3d190a532908a77dbeda6b2a4dc746010000000452ac6351ffffffff561ab93662e48b986f45fd58b5aaa09ae1bbfef26fe0653e0d595cf3710c31730100000008ab6aab5200536300454c16311b337e13adb0713e706c0252ee1c6a2d584eefb46753cd2bdd5248d1f8ec168d0300000005abab6553acffffffffbb8b31893fa6603b807b01ea61bbd435b9e794ef495da015c8027dccd142accd03000000066a6a005251657b00b02f03568ed601000000000165731699010000000001ac881ef60000000000046a00635100000000\", \"abab6a\", 3, -1617600052, \"1f9d21d09cba21bd2c2bd2b6716820840b685e534459475fc87d024cced78dd7\"],\n    [\"020000000142f80952ec2d6e8fc587dc7beade21560e3bdfb18d0ae12908d7a29221553b63010000000452656a51ffffffff015450f3050000000008516351526365abac64afaee2\", \"6a536352ab636363\", 0, -893452614, \"5c1cc20b46f5d14dd66fc66e792836826158ff490da85fce5bf7a42335a023cc\"],\n    [\"0000000004c492602c334366006da1e4a0987f1d6e11712bae8190a8a6d28eeca760278a7a0000000005ac536a51631dc6116dd5d64c6679468cf10588481f5c9a98537a965a680caff87a395d5a9237888fdb03000000046a6aac6301d20ecf2c4fbfa01008a695c5e9f98d9b971cdc884b6fe511c46dccbc77d528476fa2270300000006526a535252630a805d3aa5a775ff968c3edea74a51ef10c1c826cf4991dfd9d1e11f21e80318a4ddc30e03000000096352636552abac656a48eab9e90439f8dd0100000000096aab51006aab655353f2f2620200000000002823a00500000000020052ff896601000000000363005100000000\", \"6a6553635100\", 3, -529352061, \"143358321c5f7ccf15fa1076eec3bd752e72493609de88522c75ce7110693155\"],\n    [\"0200000003431afc730efc855da610dce52519132bb4c1652fca585a6d27a7bfa02fee8f9e000000000763ac63636551ace71aded4ef69c5291be6b6c696c13673abac8d0f421c1879ebc0e1887164e323726a84d40000000003515252ffffffff7213f610d3b5f2ba716283f7719670be6efe0ce317a10ceb6a9206e81cb27f8700000000076a5151536aab51730f23e0036b27df02000000000263638116ab01000000000852635100ac52006a8fae2c020000000009ac655263526a00526a00000000\", \"00abab53\", 2, 50015555, \"d4eabbe6bbc571e8b94e6148f6fe0eee54fc879d49f2881ea2db7e99bb18d81d\"],\n    [\"0300000004314235de6d450358e8c3e4f7ade305d6923bb489c8736a44797a110df3a1c961000000000952ac5200005251ab5185abbf443d19df301144ba17f57ae5202948300be2646474ee3adbf9bc33e895c0ad68de01000000086a525351ac0063acddcea396abffec5d05285081d59055f1f6d5e6d7257c031d3f3767272a592d5a5607673003000000046a525200ffffffffa8063080d78b934311b81671d88d5cc59c92437b05a6ad984671fd583c91f1620100000009acabab005363ab51abffffffff0132506f030000000008656a526353656a0002a5d02b\", \"5300635153ab0000ab\", 2, 546912968, \"164d385aed125ab770a1108e0f1b7c6f7f140f89289e1d1cc7d2b356c9b07630\"],\n    [\"0400000003155fc977c8401d407764a2445c654eaecc3cd6d745183a5a2bfd56e360d68adf01000000016541376b353494e2b0f656ea4710460779e40c81d7426e39e69e85d45901f6c8fc9d7f9a23020000000763525165526a6affffffffc70c3395693faa431ab886cb7badfecc61e4f4f46bb5db7e3968bfb2c8177bf0010000000900ac65656552515151ffffffff032937bf04000000000452515265c04d770500000000026aab53b80d03000000000080072269\", \"6551656563\", 1, 1273024963, \"29a18c95def404c64251835d35d86cfdfe514bb6d4156fa2befd0dfa1af3ff20\"],\n    [\"0200000004798f1c8ac1ea7973a421211adcad030b16efc058ea1ce17b5113fb1a80f42289030000000200514324f6f6d3832cb015683b61e9c8092545ede397c6682a8c9a787dab4965563d52b5eb5501000000096a656a5265ab655300ffffffffdd9306990443ce0f791c3902c23cf6a154017f99ff31f9863116ef09f66f13730000000004acab51635cd9d7cd531bbd850170ff39544d900475000a7f231a785e7e7d66ec39b3f7a34986491b0300000007006a5265525351db72db9604fa0364040000000004530000aca3b9ac0100000000009188fd02000000000963ac5352ac5263acaba0a27b000000000008636a63abab5151ab00000000\", \"53ac6352acac\", 3, -635331297, \"7ab3e6e1bd2c1f8c0edde408169d0c0efc3fdcf3025a9b776bc99b7b131682f6\"],\n    [\"000000200417b7c9feeb7cf06fee5866d6d24d511423f80fc84fdcf2fff89f9131ffae9d4f0000000001ab9d5f503af0d30f0777e6e6a287f55c2e122be3b941c15dd9aee3ab8beaba08ea7dacca110100000002abab98d1cd295f991f5b583bc8f0ea30c1224cbb428af4445f665a13e2f91aa7d3d8c751778c01000000020051ffffffffffc2a7a8d2539b43779a4775a5a172aa60de63a12cac47f5fff40ffd6ccab355000000000863abab51ac515351ffffffff04872a300400000000065352ac51ac6a9585d0050000000000773d62010000000008ab5251ac52ab53657343ce000000000009ab6365ab536a52000033077859\", \"63\", 2, 948749830, \"1b4dea48c58308788d1e64614d53385dc569360ea322dcc28aa8b5d8c37e3895\"],\n    [\"02000000021457007c50aed6f827909b029acb8db830cb75a36d3956b4664689f03c170328010000000165d5a96371e1e2ae80782f1df376ab99e08e6812820b73524fd3f9b471d741cd4d75363e4e0100000002ab63ffffffff03e4a47305000000000663655363ab0015a9e000000000000563ac526353b8ea2104000000000352656300000000\", \"6aac6a52006a005165\", 1, 1467573062, \"931e0945ce32bab98b488b43620ee054e9d2668ddf814e7bad0f01f2e5c081a2\"],\n    [\"02000000045c2294c22850f4b0967bf07fc0c6374e5ee5870acadc7bdc86862faf188a07f80200000009516565650000655352ffffffff429b70845e4905c436fd7275b4c5a7c40770c55648238ee178d78485d7cd33930000000005656a6353acc1eaf729727305442cc4e0e532fa17b88fec58a52bde75d8d0e6c4a279402779b4984a1f0200000003ab00acffffffff3fc313bff6406d67471547ffb2369c4f9b71455fd4e558c15fc0adfba7361b410300000003516300ffffffff02a2e9a401000000000165dddd740300000000086a53ac52ab51655100000000\", \"0052ab51\", 3, -423526588, \"bca8c8aa1b9b6e97e2004bab0a7260bfff625d1b6cf3f19872dba2ab084bb2bb\"],\n    [\"03000000017571d8d6a259cf1d3aafdea15b0ceb7beed9b717733c6c608bb39389da0fc48a01000000076a5252006a51523d9b389202fe6f5e050000000006ab5153ac6a52f563c7010000000001ac00000000\", \"00520063\", 0, 1285626897, \"cab600cce1d79d8ae94baf87bd107b212b92f2afb811463a6a1b28105b5ba2ba\"],\n    [\"0100000002793299f37cc02b3981912b1b08ea65fc27600f42e1e9f9b9cc89587aac6f7f1c01000000026552ffffffff65445a87241958a6d3bc8aa5256026546f947e44c09340855b347184cb9594d00200000005ac6553ab6525543c4b02f9880400000000000851ac51636a650052cf2f76030000000003ab52ab22c5a303\", \"ab6365\", 0, 1252428532, \"647c7fc56451d432a22df95d8a0566f152aafcfd2fb1afa6ee02ff9b1adb5fdc\"],\n    [\"020000000247571a192a5abcac994af6140b15ac35e6ee0856512343b17b7dfc3ba7b47fa60200000001532f8c893ea488f73b420333ad3132a7444f8962806c374cf79c67ae0817d6e9a06e5c8f050000000006ab65006351632473f63e04247071000000000005006aacacab4e40ba0200000000076a516a63ac53ab0f1b3403000000000653ac6a6a6352aaa21100000000000000000000\", \"6a53005153\", 1, -1003736924, \"66b607dd40fc0ebfe9eb8ffc079a12b49d175007b893b58ff24975a4c7852e6d\"],\n    [\"0200000002f5a21fa70affc34bc4285f5a3d379e2ee6cad987ac7c36f5f31b3ccb51a29d1c00000000065165656565ab9399877f07d497cc7fd24e4a7f09a464e368553e28e4f3de999dc2b9a60cb69ad4cd0889000000000465acac6affffffff01aeb9ae050000000000d67cc602\", \"63\", 1, 501750570, \"8c81c92c96565368adc4c1638b955e71eb09461ef62e39117815854a1e99e855\"],\n    [\"000000000286bffa0acd3d800ca5bbe224d0663ee49a6fef780b7c0eff4c4456cd0ed041ea020000000665636aab5253ffffffff07cf536af544ff55750de2a69e872612db4fa01fa9fcb911aa62f79a4ede51880000000000951fac30034c5de503000000000863516a535300ac65708f2e050000000000e14ed10400000000002b6e24c1\", \"525352ac53ac\", 0, 158461238, \"5a4448a1aa23f8f82f9b0d48b2eff56075d49080dcb7004b201f316b6817770e\"],\n    [\"0000000004bd7c38ccac7353c6a74be5be0129a71ac8146f78f3313741ffbe8ca1b32a54330000000009ababac51acac5351abfffffffffd7e65c52d35d7fd0170e33f6dbaa651679a096355b7cecae2509ab48f7cd2e8020000000400acabac3a059afd58d21deff013acf3ed9b26342b9df790cc1fb6a2ce6d7ea5811a0ee794111477030000000852ab005152656a5253c039203931aa01b23dee58f3994f7cf266e642107aa348900e063139866bf81f39e5bc010000000163d3ecc48a028502be01000000000453525352930f190400000000015200000000\", \"ac5100535265ab6a\", 2, -282593952, \"a0fa5a58e1a38b5610f52998b45b9af14deeb84280aaf30aeee2092a09c4c8db\"],\n    [\"040000000257fbee400d354918530ffc5063e88696f9c3b43db076fb137be7a832c6efdbd700000000070052535263abacffffffffe7081a3995aa9fbe50c783019f685aa93e43392933f1b92873131baf81cb6fba010000000751ab5200655363ffffffff011eaa67030000000008ac516a00000000ab94604ef0\", \"65655165\", 1, 51357608, \"7b9cfd35a39227cc82866748f3db0620286d1b0f3e2bf5e08dfda7e971b45c5b\"],\n    [\"040000000158265ec1fd87735831f66d934d07c5256908c001a2bfba7a48a4ae4318bd74710000000008ac63526565006565ffffffff04f6274a02000000000163fc19380400000000055151535252caafc2000000000005ac6365ab51c9d13d040000000005005251525303c7c5ad\", \"51635363ac\", 0, -1501621807, \"70f789a65a90bd2c53076ffc26b4c841d8da71fae46cf2acd424224007bbca4d\"],\n    [\"03000000020b004e6e26c95a467b7ba6af74629d0924edb02d5c2a44514670e9e63752e64f02000000025252ffffffff175775b0d2e643a9db622225c0a529f66ea98b28c8dca550ecc8c88f5cfd06f7010000000152a939f55a02a4120a0000000000065100536353633687dc050000000005acac6500aba6986d1f\", \"5351\", 1, 1979791110, \"b8943af21dfc8e0f3b0c44fabb64103fb34585054d4a2f5652afb66fdf846f40\"],\n    [\"02000000027ff0a0b033f436639b13524097dff24d9d9df6e7939a55a1f56bba015739c8b703000000066352ab515363ffffffff2ce7c5569fda4fd77c01dfb459afdb89b3ebceeb8378745723845575517d852c0000000006655152536a63ffffffff01fe7dc10300000000002e2a280d\", \"0000\", 0, -1232095772, \"3ec9605fdf929dcb794e0df48ed67e88d6ab747ffe22165117314d6702336872\"],\n    [\"0000000002d25a8712dcf468b8ddb9d4ea31565c0856cc42a5771fdf38ca56013c00a988470000000001acffffffffcc2069ebd7c0c2428cc0f3a5706a7540dca6f75a4f9e318772880f1b8776c9d403000000025200a56b105104164a7b030000000001acc0c41e0300000000000f3bff030000000007ab63abac006a53423a1e04000000000963acab63ab5151656315f9df04\", \"63ac6aab52\", 1, 37769458, \"a448c09e19317c1ae6995239acc8cf9005b02b850fa8306b363486fd45a6c240\"],\n    [\"01000000010fca3da0ea0235f7b744d17eb3dd6c1558b2a02c7f629b4727fad80efb513faa02000000020052ffffffff049477a5010000000003ab635124b86603000000000700ab525100ab6a0b5f3f01000000000763ab53536a6a52f6451d0500000000015100000000\", \"ac\", 0, -1558475032, \"10ea4ed3ff31ee344329251d3a13c3817ba97099ba7909dbc86a3e01a78e8ab6\"],\n    [\"01000000012d10c43c25e3839157d11735cb2f3c52dadd4da5a2a070812086d444708b1d8b000000000800abab6563ab6a65ffffffff0125d52e010000000005ab5200ac5204667527\", \"635253\", 0, 1733481385, \"1291f07d2a5059396f798c77c5f0df3ec9e18276d2c84b696a85d0d8a174e872\"],\n    [\"04000000044073c19bfcf6a41a1a8858a4f0053c28593240cce594b0bd2c2b3a16375e81db02000000086a636a635100ac5337532e56d00f69b1f64060a265e8db25a47dd57ddeed11a38e96603f64c7d956705f50550200000003526a0004711c7b7faab995798b38eccf734134c70ed53b7a4d6a161bb0f7ece18da3541ae091db000000000263acfc9fa6b5270095d66e6b4f6e9955df76aecc1c2d7f034becf0fadb4c0c64a927d93263e6020000000365636a6021ef7e03292f690400000000045265535118f2230000000000045165ab51f2e2190000000000096a656a536a52ab536300000000\", \"6551ac636500ac\", 0, 134193454, \"94514f4656b599cc81e112e812500740139e6f8238d07d210201b28a37e08f7e\"],\n    [\"04000000016ca55461d5ad1cd51db9c4e267bf9e4a297afe4b31a14c32acaebc69231e5985030000000453acac006f4f56ef04ac367a04000000000353ac539cf09004000000000563ab52abab8f75aa05000000000800ab65656a6a6365e0ab1f020000000007ab5263ac65525100000000\", \"6a5153ab6a00\", 0, 1149798152, \"5ced8b8a6cf2fc126414367849b55279300d9005a70ff2d035e08bf27f7a5bc3\"],\n    [\"0000000002fc2cd1fdd5f28c95bb564d6684d8c9f650fb29fcf3591d1f0891c8a8c0b73c750000000003ab516affffffff1e8b3b612f7335bc9062da6fa6a16246c8c2b6fe86948acbc22fc1a772fca7b6020000000028d544a401baf3cd030000000009536a630051536aac52a1013bf2\", \"6aac\", 1, -466269875, \"efa416c461fe0d9bb8f2f170f6f3753307811ffb8e7138d10e860a33c4cb9877\"],\n    [\"030000000239b97fabd28121a963f769ef49e73f7c42c02af3af207ece72ec2c49784390a30300000004ab656353ffffffff8b309537595701d4814d96ddc7791020aba64d9100e697b4611553b10310791e0200000008636565ac5365ac65ffffffff02da5937030000000002ac6a60bbe50300000000010000000000\", \"52526351\", 1, -248251261, \"125d6d223038cbec1a6bf69978a049d011c22a3f61d4f08e451025fe69ed9b19\"],\n    [\"0100000001f35685a320a661add0118b60bd4e507ba917ddc0c187d786af78c212dff8a25e000000000852ac5153636a00659500a6f502f3344b010000000007ac516a006aac5310bb8e0100000000045363635300000000\", \"536aab63ab00\", 0, 80435716, \"dc84d224dcbbcb1c42e90826cefc8e6c265eacd7b747b00e0f7e91c0a1f53ac3\"],\n    [\"010000000390b55469f8f658318a1587c0f4efc947df3ae466746b059edcd993cc6547e292010000000163b0d588cc38afb31360169ff295deb23d3f66ef9819f7777564a2e2cf3f7a243f2ab5ad85030000000151ffffffff6f514e8a8a8574855a49d3ea7a018336cffe1a1c968b974a30c5b8a5ae20ea1203000000026363ffffffff01cc321e000000000004ac51ab6500000000\", \"63\", 2, 1323640093, \"db9ae9aa314e9d1a011f6b100d164984b6d4ac9c664fa9a974e39b78d5f72dba\"],\n    [\"02000000047224c413d9abfa031d35df462c708119abc8e6bca6520869d6dab1cad5e69dcf0100000002515274d30f83cfebeb2ca4a22c89c177583da504d0ee3588f152c9e6e4df9c42a165e7d822810200000008006aac51ab536a527b87d878327e6009686eeb9ca7759c6cb10811f01a2429669a600e1f29d89ca2d5604ce10000000008ab51525365516a00ffffffff5ba42d2db4e4549eef314fb5dd955a8d066b6b2a879f7980f45aec0905b8e0c40200000001652a8b1285029dd0380100000000036a65abbcd2f30200000000096a0051acacabab516538e78245\", \"53\", 1, -168022127, \"e3d0e70ad8b0c6b4acb7547117e5f1d1ec72471799eb6728724304b89f258e4c\"],\n    [\"010000000226431e9ed6a0e0c933a117e140ca2ac4c81876fca65cb863eb5a00af250a9055000000000352acabfffffffffc3769e17d71048e88502f3165747e679bf6646be7eaf98e4aca4d0aad7ec930000000000353006aa6f12e0a013827f802000000000000000000\", \"acab53635263\", 1, -351453579, \"b6926fd389d690b03a5e558c9bcd81d49b27e42c0183cb94a56557f674deac17\"],\n    [\"0000000001aae51d33a19840dc7a2f3ea371c7a7cc874556e6872d3a0ca045869eb6135be9020000000463526565bf95962601fa750a0000000000056a53536a6397116cdb\", \"656a5363\", 0, 880022727, \"48618c641b72e75d38922cef9b9cb36a271ce0c24f2654936193890282a7899b\"],\n    [\"0400000001a2686f14605dd5032abee1be10ebd61b49ab5c676ba618d47f3abe4499a818330300000003ac6a52ffffffff03a6f69d02000000000453656365f289830300000000036a51524610e3040000000006acacac63005100000000\", \"510052ab0053ac65\", 0, 47786498, \"7c9ec2c634e1849d88053bf88b1bae82483385354d6cbb65e1f53b1f9dc483c6\"],\n    [\"030000000231ddd5a1da48f32c1e2d59dc0408e5f02474bf4b33ebce9c60e663ff561d8b0c02000000046a53516ad7dbcce64b765f860782d500ea09a9731beb02ffad6a910ff562adae897d9de6e4c5960e020000000953516a5152530053ab258c90fd03c68bd1010000000000ca850f0100000000066aacab6363ac1382f5030000000006ab656552515200000000\", \"00\", 0, -1183257143, \"fcb11aed5d0918f4e49c510cf662db3328173c9f153350d2c4721d13084be06f\"],\n    [\"03000000042a2c4501270f16031cba35f272dcbcb43750c392bb7b392f689d232a18810efb0200000003656a52ffffffff2dd307f0381c16260a1ab9f8b7bd573ed4e1014c62f2f338601fbba157b0e61003000000076a536500535351a68d37593bc34859cbcc5d40c89fc6601544dfe31b239ec2eb2bad9e6a772629a04e74210000000007ac53ab63ab5253ffffffff00baa223d9a839f0176f4d912748b43ac2a21fef0158967772870a2688985cbc0200000006ab656aab635255389fbf0132bf170100000000096a6352ab006351656a8325a947\", \"636aab52ab52\", 0, -1485291470, \"25a6eed0d570caa8c3026d03a5ecea16be82a7fdf0c3803785768eac8e9a1714\"],\n    [\"0000000002750cd300fca0e0525ba0eb38fe7c2347369007e698da879220bfce9fe933e9ca02000000016affffffff4ebee436a085963818aaab9fd4c501d8824c98487c7e4f70c325804080ebbca1010000000452635251b82b38be02b9bea7020000000002ac652cc89c04000000000553536a5165a0528c88\", \"536351ab536a5252\", 1, 1068633432, \"93aaaeffd872db548e706a81ed49621919e54be3a2e30bd4a97c026d26c40b8a\"],\n    [\"02000000013110d36566b7382cc62ea19447dfc009af6789f44ea06bc9cdf100675f7bea870300000003ac6300ffffffff03f21dc60500000000066aab6a6552ac11d81205000000000953ab52ac6a530065ab9679f9010000000000c9f66986\", \"00\", 0, -1087595273, \"4bfcac100062d86bcf0ca16d9948b5c35ac19684cde27180ae29fae566d24c77\"],\n    [\"01000000015927f49c3f335cc3b88f2a328c903972a3ce830f33404fe96d9c2945a3b3cf8703000000055252536363ffffffff041705b5000000000001657356cd01000000000951525253ac656551ab5bafd102000000000753abac5351636a33a90b050000000007000065655165ac5b7f850d\", \"\", 0, 1055022258, \"56c87576b3522b7373e7af5e08e77eb30d31a0192175d13e2f9ad07636015477\"],\n    [\"0100000001bc6caa858a4b7e0d152b11ba665f25de1c7130a8c4954d1d4b8170d426fc529c020000000865ab536351530053ffffffff0129874f02000000000165eaa67a09\", \"6a6a6363\", 0, -629417172, \"6c44fff53e44b899cf15021e523239319ead8c1179419ca3cdc8b4e40f78166c\"],\n    [\"02000000031bd926695bd6cc59593f940ed1e1ecb087051b82fba950ec0c5b07fec966b4440300000007ab0052ab0052aca8745620719a0ec8c69877f41304ff7ac4d1c101f6c3707918c786f3f7070b6479073b85000000000851535353006565acffffffff054ea7d217ea56f316ac0e78d4c89d5662ed528ccc8d68c97845398b07eff4f10300000001ab76f8b0a10148aaa70000000000086551510052ab515300000000\", \"00006353526a526a6a\", 0, 2030625325, \"bc6bfd2a384e687178cbe61e3bced72c299266af23f7397699721738989f1362\"],\n    [\"0300000004e79d18c49ae3af64a59b14fbc95a4765e0e1455422597bc37002948637b9b37800000000065353ab536500e1816cfb0a14704298e45f3df3e07cac48172bdecd513b7306af3c7f77a8d6d672e1f35f020000000400526a65ffffffffdcc4c0dbf12fbefc955acb54755beec5aa4a543976a5bde52d1eda30a76598680000000002ac6acdba05a37007aca19365c8a171dd019b4e22f8eaee7deb1dbc1192c36bd28f8c803a5fb90100000003006551ffffffff033860e5000000000002ab63633fd00300000000096351006565ab52536320744c040000000001ac35dac6e0\", \"5263acac5263ac\", 1, -973904557, \"f38b56b0941754ab67501c4da738bafd057d6dbe8ad537a06dab696ba0c80e91\"],\n    [\"000000200466b139a78d88595047b942fdedf1d3ed1afacc747f2b8d25719cf68c450ac6f0010000000900525165ab536a6353ffffffffe0428725f58002c68154e9837390ed6b157b63e8c9ba15f905d4d44fff3c7e36000000000251004d5d2f95a22d4849b1f5ef7ffb59faf75a0fc059366692781c2e04bdd4b81c6b9f4b166f02000000036a636ae14f1a177622a5fdbd91b61444bb8dc77e86a78ab197e476d7a52b1784449d3864e87bbb020000000351ab51ffffffff02365fe1030000000004526a6551b397aa020000000008ac006a6552ab636300000000\", \"5163\", 2, -1148588370, \"4365a732b60b3b1a713ed8027927409f28f424c932c089f8b3193e59b5872fc3\"],\n    [\"02000000018cb13578db29ec07a0e7dc4369817dac0472e179d588869a97547c0f5b7970b7020000000863ac5363acacabab7c1ba5ac04657663050000000006ab51ac52ac00b18c6c010000000000e9da14050000000005526a006565cec24303000000000400ab515200000000\", \"ac6a516a656a\", 0, 1627336953, \"60488e5e0c42d5756e8c293b75e1603122ad5ec3f52bfb3ba5e27ef242111b5c\"],\n    [\"03000000036453e0cfeaeb7b350cb20021b362fecb260268ee6dc2dfd0334513ce25efa3cc00000000065100526552acffffffff8e4ed613faaf405c612ab5ccb222be32733488b64ae48ace6f6995ec559017f70100000003abab65ffffffffa887e76a20bb06e812320e2b6a4233b70fa36c01a070203dac5d5f5a672c718100000000056300636a63b91a79d303adc864030000000006ab656aab536326b9940000000000045251636593bbc10500000000066a5263ac526a00000000\", \"516353526a63ab6365\", 1, 877656045, \"f8dfb80f08b74226288fb3d27c55f4744dd5bdc312c8eb0a9da096e89c4b2993\"],\n    [\"000000200329650113b7456a9d29dbd2dee126b7ba5f7388887fd2fe5da4aa5c094a90225501000000086a656351ac536a53ffffffff802b8a20a8665d9cda090c3f9b051086b2ae80dec930e6ff35a9696cad58eba70200000007000063ab006aacffffffff23bfa10acb63f7cad03b026868e2fc044577b19be0256a7b6269d5961fc2763e030000000152ffffffff042fc4420400000000096a51536a00ab51abacedf60104000000000353ab65485c7001000000000852ab006a5252526a8c1b1101000000000300005300000000\", \"6a65\", 0, 101848109, \"5a22c53cec38faecdf94858941285929145c3b5f0484b70342b70d602f15c8af\"],\n    [\"0400000004f604e9113ce16133001d03b7641b0c81013e7edabcae277ebb358fb14feeb1f70000000009ab6a516500536565528b5f7f6b80cbdf3c958e6c8df78b0e0ddfdd53885b6757beda5f194fefefc8219203b90700000000030063abffffffffe84d36c6b7150e4020fd360023bbec9bbe3a9a4dde0b975d1b6b831e53a0126c020000000353ab53dd965adc1c8512dd482b3b15db08b25812a64b4605a6b43c2313a2978d47494926b145bb020000000853ab52ab6565abacffffffff03c176970400000000025353ad9468000000000008636a6a6a53525365aa35ec050000000005ac51ab6553ec35ea50\", \"ab6553\", 1, -2103253680, \"62af25b8dc390292cc4f51cb4e97672697e0adb66c63559511854fef16a1537f\"],\n    [\"0000002002cf37e1234805402276747d41fa907094f6691381625115876d5a62064d4dc163010000000353536aa3b4b6b5746e0a845eeecafd7ed54c9d002e84fb85355aaa890ed9f26c8bbbea2398633c01000000026365ffffffff0379c18f010000000006abac5100526305afdd000000000007006365ab635265d4c66d01000000000363ac5104e79b4f\", \"6a63\", 0, -692580729, \"cd65f57aae15dc7f9a364b091d641f4b671c903dcf766902ea42714ef9bf9745\"],\n    [\"01000000029a398774a3c2413456e4eaf83168af151b86e280b989160cb8c117a49e87f00e02000000066363ab6a520074ca8446f2a702375a8d054fcb3b1cb5b10bda6b03c761f051e8d20353cd026c7439d9f2010000000552526553637694ec7c02a1ce1b01000000000865525300006552634193da010000000002655361f8dcc4\", \"\", 1, -1495329920, \"3e6eb667d31228bec254094053d533ff459a8c19cf9784d63fc7f1918675a2ca\"],\n    [\"0100000002fccde84f2b194fafb8eeb038cfc29ff329dab51cd4fd1b2668810b9a3062183201000000036a5100ffffffff65636bc688318ccb9fa47be2e863da757363a33b17a3bda634517ffd5849fc5001000000066352ab6aab6a0df5b86a02383559050000000004ac005251951588030000000005ac6563650000000000\", \"63abacac53\", 1, -1402362685, \"744bd8889be682d310e2036361b25f3572d9368fa374b089e27f63f418fd7591\"],\n    [\"00000000026ed866a64444b2813eb5aef043f7f96c13723213fe057ba8cecae491e375c9a302000000076a636300006351ffffffff7c2eeda675363785c9ee698c1d5413bedc8b0f6347a3bbc4df572ab71b100eb3020000000751ab63656aac00ffffffff03c2cb240000000000016528a4540400000000075253ab006a5252878bef010000000008abac655253ab515100000000\", \"636a\", 0, -903053256, \"4ae7946a33115cd7e6be9e3b1aa50a06c715e1f08404ed2538cbe9e9067ef8fe\"],\n    [\"040000000103b981bc398cdc22f148da44811bd9f58f2a48fb638231587adab9e69873de520300000009ab656aacac00ab0065ffffffff04ba99b3010000000004516aabab68457b020000000008005365abac520000d1f3fd030000000001ac28f936000000000006536aacabac53d6f0e52a\", \"00ac656a51ac5352\", 0, 714717388, \"778c70cc6ad5d1f25c6baebccbf9ddbd9f27d2f484327c93108ceec078173aa7\"],\n    [\"00000000012639df41dd2e95bdceb0ca5374e5571b16d31a7b1692060c510fe638d6719c840000000009520000536a6352ab65ffffffff0441afb703000000000863006553ac5265abf89ec305000000000863635265ab51006a9ef1ba0400000000046a6a635284bc75010000000007526a63ab6aac65be74a132\", \"5300ab520063\", 0, -1518449302, \"9875e59270b7a467618312b8f6dc4c64442d4ea820507d642464f93a87635399\"],\n    [\"0300000002126175ed55e527f582186eb238bf08d9912ced43e14f0cb0be87e9af14bf9f0d00000000025351ffffffff4b2fafed076202468a7f92c235d841414530101d032b563a27bf523b7163d3320000000007ac63ac535300009a11ae670256e6a7040000000006516a516565ac757e1f0100000000006591cae9\", \"ac51655252\", 1, 815877885, \"7800c2c9a5e654aae226e14d20723d2edbb0ad334f3ea28a9834d9aad7a426e0\"],\n    [\"02000000010419de94e54bd2544d0cb40ee8aef0192880bcf8bcb109ebb1af24c258d27774010000000853006a5300636351c74461b00177b3650500000000075251ac53656a6351ace820\", \"ac6a52530063ab6500\", 0, 885632507, \"3a03849e17f674c59990bacc5580f395dd2b97b29728970a69066354a0cbb524\"],\n    [\"0400000003a877a05a951b7f798b38a406c5ea59a82ac82c6d35c8e4c024c4bce9eff1c8890000000000ffffffff50f36a134fc53765358a26fdd088353b8a9b49620765750c7b69c220e0ccc0d900000000025152bdf563d01b7a6062d058c70c9af85fbde3fd8eed07441298f28d3be294e59ae69a71bf5b03000000026300e79175ac01be2efb02000000000663526365ac655a60f605\", \"63ac\", 0, -2135179692, \"8d8fd6d2b7644c6d9e229a29b1f012c10dbb1b824301e784ea4db1e8e063e23a\"],\n    [\"010000000377ee77d6d13d244a7cbb97bfd4d69aae6b5bde4cf74bce1ffe24a1da620b475c000000000451516aacfffffffff7dffbe450b736ae7e1402767ff0390c985c11bc95d11e01010d020ee66fe1a4030000000351acab084493ac4c511961f4139110f24d683a2748cab4ae9bdc5677f705c5b17e94ae9e95827a02000000026553ffffffff049710ec030000000007006a63516aab53f60880020000000007656a0000ab00abb973930300000000007b2532010000000000ab46f2d7\", \"\", 0, 1220070015, \"7ed9b9aec47aa651bc45b7c192fc400d9e514dff625baa01d67474b2e0513b20\"],\n    [\"00000020039006efba3106d8b5282bb65d0d6b97ef0b574449b809e19378aee68c2c7b007a0300000005005263ac539889ce4ffd4727f76137d9e6d5a4a9e2a8db0ada055788e2cc12bd95485654b5ebd80c0803000000056aab63636a995767c086b9983a2b6088fbf2ecacacd82690eeb9b8d84a9239a4386e5c418a9ed6536401000000030053acffffffff029e772f000000000009520063535352ac526a31947a030000000006ab535353535200000000\", \"51006a65\", 0, 469104405, \"4d1f873aef237ac8f4297c02ac8d3eb71a202d802f45ecdd9ef4ec5cf04d4df7\"],\n    [\"010000000211727de873c14dbdc2772ba318268901f15259f0eb2553bd52cfa3e390c00bb4020000000265acffffffff2829b54213fcbd3d46da359bd3f3be227213005d84ad45e6a95d5e8ff2051010020000000565ac6aac51ffffffff018e9f6e0500000000060052526a525332c051ec\", \"516aac65ac5352\", 1, -1281097285, \"2a4b1b6a7c0ad2635c9d7949d4585dd29507e4cbd44be7104cbc0b6ad0b81c3c\"],\n    [\"0300000001c5658286195f76a1e73218730856627166665c40b1a031db0589045cb396f2b70000000002ac63ffffffff046e1980000000000007ab6a63636a6aab7d6f1f000000000009ab635152525251656584269c020000000002ac005c3e5c0400000000015100000000\", \"ac6a6a\", 0, -672304653, \"28d240aa048ef8afbdb139404e59c4b6c3f00fb73cbec3756f49e5d50f478796\"],\n    [\"0200000004da9c195c77f33ef38e3487bd811b3ee7c1363ed22565009a9ca6058dc3ccc0b203000000096a00525253ab5151abffffffff8fc81f933cb5c68ebb5db653f4abe7e69c604abb10c5988a8df4f232f5bad69b0300000008515363abab536a637423734d50cd16b1b42e360b81eff39cd3f420a6f652b06913c9acf63ca2bd08e7f7279f020000000652ac53acac00f8a823c12ab03c73eeb3c3e47c670f738c1f2b6eb2095e9b7ed2b780ba3fc5f3bf396a8e0000000003636353eb19106303d805c500000000000165782c44020000000007ac6a6aacac6a65612246000000000001aca214ed9f\", \"006a6353ac\", 0, 346313786, \"a942b3f35694e609621df4e5ee723318f25b11c132fc774cbc7d129e8f52e42c\"],\n    [\"0300000004486c6feee1d6f24f295d2c83aa33140917ece93c28b03be7d04f70d3d229daa50200000000fffffffff5443c55d1c73fda81dbea1748c828a5987f89d03d6b159cdb83dfb0fcdd9d8601000000055365636aac4a289c7cdc2e8a084c0e125d125c31ac89905957bda6628b70c74d12a970885da1280ef70300000007006563516351abffffffff0d22bb2168c9037ca1ca9acd1e34f3f40a50cc524c7b29185e7859e6aee672d80300000003ab6aac4d2ae87a04d646f80200000000016535206805000000000039e2c8000000000005ab51ab65652bf2090300000000056aab51520000000000\", \"6a6a536a51ac\", 0, -1876450659, \"cdc32e80a9c330affad819f684ac4336e15a72fa5cda3cfdb355c8f708f78002\"],\n    [\"0000000002b92ad8a21230d03db698c84f3ad3e0402c5a8bfd806bf135c5c54e3eaa517fba03000000008ecd2ca8b69247e5b0bc7c8ee3909e6191bb45219f9cd4a68cce44f8ea6fd95ff554500902000000045263ac63e2d21ef103d281b30500000000036352ab5c49aa0000000000090053536353655252ab23696a01000000000153f2d833c3\", \"0063ab52656a\", 1, -261425539, \"0de43108bd8324d9a3374e2011f149ad12cc939c0398a891363b94c1730e851f\"],\n    [\"00000020036bfe22dfe2b2c4db7df915abd024339f3a32a5f18545111cb01ec558278e71720200000004acac53ac7b5d9ab5fed8cda0289a229b70add6b3ff0b3d55333507f5b4002b32be6604e001eb64ff0100000002656336a760813673bfe3544f105d003cd1a7d42fb4b9a0561eca72aad44c58d62c4dc9a9ee980300000003006552ffffffff0297602a00000000000965ab63ab6aac63ac63017de500000000000751006a00ab000000000000\", \"5251ab6551\", 2, -148219721, \"90f010f1235c88a301024840ae5a645d5e1e9e4718ea563f18bab78aa4573f00\"],\n    [\"0000000004d0546519e4567d0486b540effc751b0a980161c41f5527fbf1cbc55478202de2020000000651006a51ac51ffffffff092cd43bf8411d70915598c48739723ce58955b8144dcba526440fedc89bf7120200000008ab5100536a52ac63ffffffff36ecae8e5c56ca987ef26a0fadcb4ddb199bbe4f0c9f12e1bf5da6c8cbefb87e000000000952515152526a535152695c4873696b3d474509f9fa65de40328d775d4d20920b3ad3362324ba9917985de359d102000000056353ac6a53ffffffff021466510300000000046a5300654a9698050000000002656500000000\", \"636a535263ac\", 2, 959784751, \"7494a3247e0915ca731b95e9fe0de207c2c6bdb2bec9712b0640fc749877e12c\"],\n    [\"0300000002ef9a42849a92a2942dce2b2ee6315a47652775c8ef5842ec05a893f0b19fa6240200000008abab51526a655351823b36ba7b5aa6bf571f4d42d57badeb481d8380a72ee302d9acaa9c633f16a346691bee0000000009ac636552ab655165511c3f289503bc88b2020000000001ab538d8301000000000263ac65413c04000000000000000000\", \"51\", 0, -1953078208, \"e80926a7ee0dbfab7de6d421fd25fab77df958a02bcbf0515f8b93ec7602479b\"],\n    [\"01000000028f528fab392263dcab8db5b27ff1a42845f3f3719c5ca6f42fe326a06b3bb352030000000851006aacac00656af7cc49d9081e8ee9085abde77eef44e15280c97b911aa3b03946a0d2caf1299f624c30c80100000004acab53003ee6247d04b8131503000000000163dc3c4b0000000000025253b484d40000000000036500525b302b0400000000046551516300000000\", \"6a\", 1, -1159632628, \"1ac0364bf7aa8c6ecb74440dd6fd4255eaac64cf25a9883e7c4204dd3418a430\"],\n    [\"03000000017910de035600d7bcbcbe4bfdd4b8f1ed6f4cf9976d7fbd6f73c050b6c4b2c0de02000000076aac51516a536a94fdaa5701dffae500000000000000000000\", \"\", 0, -1491950344, \"02bbf32abdfe6e5c96aa511c4d9dad4c115a090e9ea2ec5899711defeb0b842d\"],\n    [\"04000000046bc41979c978513d417ee1eabaf40e97f3bf48a33e92498ee292d1c7d5de6383010000000900acab6553ac6a5353ffffffffca61a49a1778f08a669c81ab3536a84dfd6cb47751bb5aba5d6562b522192c620100000000ffffffffbb5bcf5a67a79137c68b94053aaa63546e8d6193ae851f0f4378289c7cbebb79000000000665526a635251ffffffffe9f6a9ae6765535d4793ffd87ffe890e6e2cc7c08ea2198b8b3d4d0f2ee6d531020000000463acab0050af2f1d011fc90204000000000952ab52655353005252893126b8\", \"52\", 0, 96076923, \"2a74ff08531d71fb03d191491d8e57363ee955964e8ae344383686f3bf99df6c\"],\n    [\"0400000004a317a4b83015bca6a504e1b1e1fcaa8980137a5b35eb64f2ceae50caf5cab211000000000400ab5351ffffffff50373630cbc323de05168bf05d692dc1129d35c689ac869307ceabcc8173824d020000000151ffffffff9ba5329144dedca30ba2bd38b154ad63bd2fad978d8225d282306cf2b1499b60000000000952ac655263516553513828c797d42a9dc3ea69e62c4d822bccd13df9d6925c4f44eb200ea655e0267aca17beb60300000009acac53ac525352656a41946f7b04283e8f010000000001abd6220a020000000004650051531e70f303000000000076e0910300000000086a63ac6a5352526a00000000\", \"6a6365acac5252\", 1, 737480707, \"bfbb03e96589fa39249b476eb412d7ea2dc00f1540e253931aace7f0f72b8d67\"],\n    [\"0100000004a2c6b540d9ce9ca444ae749e9d43c823965c51864569b19bcb813bdbf20509f70200000008636365635363530002fe3ba256ab5f13cc770dcf3bc44dc65facf484f1c9492e446a2475b764d0a26942454502000000056a0052516affffffff2ce94609667a6c110af4a6b4019525f7c2e360191d1a462c7ca335f9fcfaadf6010000000763abab51535363ffffffff0054460fb2ade6aabffe1e9567a53eb03feb97bf628e07a576741eee13c3ade3020000000763006552ac6a53ffffffff03950b89050000000005ac6a51536a9100bc0300000000015300ea4c050000000005ab65515100e1b185a8\", \"5200abac526352\", 0, 902340013, \"7ca815817ab0e13ad058d88d2286cb67959c6764caeae30d7a60334873e3aa6b\"],\n    [\"020000000308428f9aea437ca6a50854b3c94412d59e515a5b6fec6006a5a459db0aeb37c4000000000452ac63ab5c2982ab7f357495e72a43ef059aec82a9d014994fde168a66fdba2c450121d3a640cdab0300000009ab52acac63ac6a5152ffffffff4c5aa7ff8f4fa239d4c067baa7f530689cd92173cc653f3a474f451d598ecf53030000000400006a5166b1ce140108462f010000000006636a51ac6a5100000000\", \"6a006a5165000063\", 2, 84090804, \"72547507ef0fdc5d61d3ba97de35552da748d683ced856c6c6d3a87c7d6bdd9a\"],\n    [\"01000000027db2db542c4ae0fefa11720da9afdea32c2de8d6103772459442ddb262ba8433030000000863ac006a0051ac6affffffff4911e0dad1e6b9fbece1b59178b71a44457f5c811080921dfcfc932f99986ebd0200000000ffffffff036c7ff7000000000005ab52ac63ab5d96540500000000001c623b04000000000465ac535200000000\", \"52\", 0, -1561405257, \"1f827b0d4c30b4369a55dcf1e204b685a8579b0299677a02ead9f6aef3293cf4\"],\n    [\"0200000004cf705338c82296d18097d175b20984cb84ba968e7d03f4321a98fde3be4bd0e10300000007ac65515151ac6affffffff5378d285467533bea868e440ff824d9cdfc58f9e89a74f2ad7679a291b6af49e030000000265abf049f98fea81d4f984446c6251118d56543a98808853ba77a125c9c03e2bc641de6f3eb802000000036553aceeaf0cdcda98360868e6a63e6a3d36501b8e5f4802875dbcb94b295e69232d0e47abee3e0200000008006a51656500656550be18e8019556090100000000065163ac51006a3947f09b\", \"0053535153\", 3, -1743110536, \"44734d00a6a6427f90a16e0ecf9513ebf3dd3c27e694d4f7a940e06524117120\"],\n    [\"00000000035f3b47148bb526c83258832cc3b338bafeeca835b852ccde0107d548158ed89a030000000100e621d6e069ddf7528aa3ee633882d591ada80867595816364ad29e8f00eb49fe13c79e340100000000c87d4f3ff5642571ddefdabf1c88f581d5dfbc16f528d9b777de485aecfc86f975740ee9000000000252acd5757f0e04bdcb3a010000000009006a5352abab63ab53830a1901000000000653abab53ab527f21f70000000000016597202f050000000007ab51656565525300000000\", \"6565acac53006a53ac\", 2, 1793977351, \"050278f281a7f1ffac65a7dce4414c3c0d91ce67c6c95b5d10048a171b112649\"],\n    [\"01000000040eeb7edadf48e11b00a17911b0e0fb0bfbd372df787c59296702d72836dee5a8010000000552006a6aabfffffffff383eb8d1e6cc35fd45299d064f1b3b6b68cf20bb624ca3e309b73659f8b9afc03000000046a656552138e308440afbdd500f704c6e5e401f240ac4829c919c53f69f97268c90ff139fdc03e9e020000000363ab537515d938fc37ce226a9a4430d5c5203fd5259f4ca89c08a1b78cebc161b12999155bae5802000000096aac6a0063516aac00ffffffff01a851a0010000000009acac005363ac6aac5100000000\", \"65\", 1, 1289870794, \"553a240906eadef60a266a857234f7430498f55fe51583653dab6cde2de20e99\"],\n    [\"000000200326279f59dbb8a38fad0777b4704e3aa839e86bfe1bbfc5a407bf821d121801de020000000700ababac63ab51ffffffff7a39896ae6e29114fc3ed871e058ee69d8928f3877804840b9d48d0ae99c975103000000086a51655300abab65a251839df1f5ee55df3059b8d92438514c201dac1f1a8ee8dbe7918cd270d77c5c314c290100000000ffffffff033313f1000000000000ac48a30000000000004f281f04000000000163c3ef4d13\", \"ac\", 2, 443581684, \"1cfc8ebc19f4e0977483dfd740199eabaf57709788bf5a2dae0cc36b88e6dc95\"],\n    [\"04000000013ea2f98e414300f213d12b3a2636ee6ff31e9de5f49c76b15a1c4cf0b41430200300000007ac5263006351acffffffff03caf3f60000000000008db2880100000000095265655251ab63636325d70c0200000000045151636a00000000\", \"\", 0, 1379656815, \"13e43e5b48474b3f138829ba03b1b2b13eee9acd1b1db294b50c497c58449090\"],\n    [\"0300000001130af438818c07fae56899891f86bd8efc016b8f3a00002d95c30188e72009a200000000056a51636363447be30701dc77b3010000000005006a53525300000000\", \"ab00\", 0, -951193453, \"bb6b3abfef5244f0e93d203278b6527308f29fcc54b5aff6b0ee2ced5a6eb776\"],\n    [\"0000002002f795afce041d546074fff00a49b9059279180e617f1ea96c2ea56d56cd9ccb710000000003515151844ad185957639639b97ea6b700ff73b13d1050b0784431e800cf63114c2587878da15f101000000085352ab52ab65ac537e91e12103765ff60100000000086aac6300ac516365cb77f4030000000000e1ec0b03000000000265ab6bcfbe61\", \"\", 0, -1072665753, \"1fe65439d1859f551f230941b0cd8dc51f72bd438a7b136f2c6d5972dcbfc770\"],\n    [\"000000200361615a873064633c3fc37e7686a89e1df94e83b6102474d271d51c142a1f2b600100000008acab636a6a65536305e94ce74598dcf130bbb68b4498f0a6c772bae20231c15b5296deb94c67a1adc66bbc980300000001abef5ddf0c76578c821d3f64e5d830e5372852cf4fdc62198defa9258ba5a2bd7cec06a9500100000008636a52525200516ae56c4716029afada030000000009ac5252635253006365722adc000000000000b9681af8\", \"5100516aac65\", 2, -893632026, \"7a51c5bc6cee7636623974f5cc85cce3dca5ad9fd30a22e2df2bc62291ba1110\"],\n    [\"0400000004d93cfc3a3776565bca4818ddaf7da273bf1fd3c91c149a865e8ed8e3e1ccd5bb0000000005ac5163630068e905a9a2350e01132ab82f09b3c585c27ff6749d4dae90d41d269c049727563973b6040100000009005152516551656a52ffffffffce208f1870a71c8c7a814f5f6df4a3f032132ee4ac666717169c1f99848b5a670200000001abfffffffff600f70680322950b4cceb212b1d7d89f61fd54e9b12b9445c5a6885c3a852e400000000035365ac55e015d6016c67b101000000000000000000\", \"ac53515252ab\", 0, 1831502310, \"7d46217bc8154fd54cbd84ab918459897c0a9ef74b17da9b7d3b6276e1ca2d81\"],\n    [\"01000000010d26d37c61f0125d842fc4e3b696c2410fd5c7a699fd5c91b5b3de95f7ce9154010000000451536353e1cf3af804be7552050000000004ab52635301fdf80100000000046a00636a0548cf01000000000800635300656aac51058693000000000006655265ac525200000000\", \"\", 0, -739010363, \"450214d003a2f0dfaff96e793bc24bce025de58ce35c3593c16c3e2f935e45ea\"],\n    [\"0200000003bd21738f6724a84fb2b8345cbf730988f57a8e115d0744fb1074b9f6561ef655020000000353536affffffff888231b53beb4b802c1ec0cc62573c7f134f4b409453ad53f13930e468e4eee20200000005ab00ac65ab0b88439a063f8e1a16ded3c27efa360ab51fa3835e430f467323fc1b9cded45f8630870d00000000066a63abac6a00c2b6847a025351a90200000000015150607a0200000000055351525100dd4ad961\", \"52ab5165\", 2, -11907393, \"e1b5f9eca77924744febda1d638772027d7dcb90e93e526e699e35266602b7f6\"],\n    [\"020000000171fdc712c1e5ffc040a2c3de930cadaa1d7f033b9a1f3b4039a7b85980597798030000000463acabab4bb1dfb303a00e3d040000000005ac53515200bd8a2d00000000000563ab005165add6e4010000000002655100000000\", \"ab535153\", 0, -213601751, \"5998de1f25867b871c7e835755f536edef6ae93c4f736b071dcd2ac73a677554\"],\n    [\"0300000004e0a023543b26f0eeaf575d01d0ca25fbcbc9d3d7b8cdfeba3af294d80a126e030200000009ac00ac5153ab53ab6affffffffe6e6975b2cb06e383b9871ca07f894c78a68731fafc561557ec7fba2adc6cd0d0000000002ab65c4967d3676a2ecc2362d5dd3427ccd236731480ac32e63540cba3afb65359515a9c25d5d00000000004d2c9c0a2835f162c011ce94792fb4ad1ab7c5fc0c0d9bfa39d01237f68fe502db12c25803000000085151abab005265ab174156a6033446ee0500000000001d9b65040000000001ab0cb06701000000000752ac52ac00656500000000\", \"6a6aac00ab65\", 3, -2080731785, \"5ad7f4a53c93f5de278561a6d923de47b0423e2affd5695828d90f44bb9e1a5b\"],\n    [\"03000000032ccbb3971caed225e1764258723f3c253628a4f169af2289135782841bbaeb100000000006656353ac5165fc3c3a6fcc51ce030472590be4515b696f8d0928bae56f6c8d2c3d7d05c5e252ff8249ee020000000553ac636353ffffffff5f5bd47736c62a637eae78f688b222e047534b772dd7f786f59bb1979dce836700000000056aabac6aacffffffff04708be2050000000009650053006a00000000747ca400000000000765abac6aac5365c51aa70300000000036352515682280000000000056a63ab516a00000000\", \"\", 2, 996248455, \"0bafe0a6f35e397251ae9285b9b31a81a80b32f82a378c8e2162a103677fccdc\"],\n    [\"0400000001b910a28b469eda9026940f097d4f97f1c098ced3352cec5eb7525288b2ed368b030000000752ac6a535365abf54cbfff01abc96505000000000865526500ab63656a00000000\", \"6a535253525300\", 0, 521523443, \"589f13b5586254ba2c786304287de92b48d20eac188abd2822419ff5baf4dd92\"],\n    [\"000000200221408774684ecf8a35f48df291e704aafcde010122a7f65269ddfbda037294af0200000000ffffffffab7f9355bdb369ca27369354d6a6e0704414a7241bad310e38999896c903d2b90000000000b65dbf90020f531705000000000851006a5365ac6aaba95c8a030000000006636a5253516521837cdf\", \"00ab6a006a51\", 1, -1070148628, \"101473a70c6891a416a47a0273599d411a76f7ca11cb2b2fda627a8dc8874719\"],\n    [\"0300000003d6e3787c1c0f7e883927eeb7e187a732ca5a125f5094c70908e680e2af8403890000000002ab00da5f01de912f5d7bc49cc090f2787d2134bbb7bfb550af83bd6c15c766b188266808834c01000000076365ac52005353ffffffffe8469ad686013f58978f2733841c5905efb1f66d6d7593bb73eb89cc8b2a36870300000009ab005165516a0065acffffffff01bed6140200000000056a006365ab1f5038aa\", \"5263ac\", 1, 1441765621, \"2d71c7e0d062a9ffc2543759fd47558bb63fe0b22d48ab8e48f69d10e62f180b\"],\n    [\"0200000001c3ed0bb7bcd2d3e5b25ee004556244eb4e6610a7ac7f2965314a942d5db309500100000005636a6a63acffffffff03afed44010000000000fc9f890500000000046565006afe22e900000000000000000000\", \"\", 0, -447273995, \"7cee8d694e0ae2495ce410f8777e11f852e4e3a0d159ea35841dae2a7334934d\"],\n    [\"030000000192a19e3999bf414f380a16fe62ad0e46cc5f7dca023cc99dba20f8e078de8a840300000001514c42019e03d01f0f000000000006ab5252ac63002e1c05040000000004006363006bcc15050000000009636353650051636553dcb52851\", \"636552\", 0, 381538904, \"e43a0fb8f625aa02d575981f24d7f995b424ef76a981831d8309bb6bd56a141a\"],\n    [\"04000000030ecb0d24e9880eaaea35e761f744e57394586c130a443e2d85b72c05df2f0bf9020000000800abab6551ac51acffffffffa7fea31eb54efa88b570874a4b0e0eecfa03091a6198f1f6031986306da22e18010000000753636a6a636500ffffffffc619294ae70d4208a09d9637ca36a59f3e7eb108fe0739ad78df7b2d3df8a4a0000000000553526a5151b6802b0a016d5baf030000000004655263ab00000000\", \"6553\", 0, 804105697, \"397d6865862cd6f7228927a36395c4413d754f6967f1f724dd5bd3ce88e559f1\"],\n    [\"0300000002eb28b2d81e64ae74bff513429196fa10b20271cf1077d4688fdfd31114a865d1020000000752ab516aabababcb7dfcfa8d78cd2cc2225f038593413201bd3bb3cf6aea08db3ed166351aa7794fbeef06000000000153ffffffff027214b20000000000016abdc32c010000000007655153ab53ac65f1f522df\", \"6563655151\", 1, -922467873, \"c74c45634f7ef052d0b08800f87805c926383267efd9d98119f385e8308d1e30\"],\n    [\"0200000003e35303138e053fe83a2230959aa555c4f8b0d357d3f15774985b152b4cef217c030000000965655365656a535153ffffffff4ba7c2af69346d23514775d9085c2c87d7f2155e9c930ac400765661b13b179903000000045165abab5fa9eb9be94318e089d2acf2c699c5c9e2778f04205d9dae264821fb674159b3d1fb4bf900000000036a5151ffffffff032b15320000000000000804de040000000004526363003131b203000000000751ab52536a51abca7b571d\", \"5351ac00636a5300\", 1, 768274951, \"4e9f7f584c1bc286504d9464e35cc637eaf376166eab37739ea83ad94b701a4e\"],\n    [\"0200000002cfdee1338b09bcdc1dc64c1341a10596e4ed99adc7a1195e20a90ec487e618700200000006655365536551ffffffff5c112d518af612564356785dd1b3baa7a993a22479e76be66fabc7ea95ad99cb01000000015356a6fb1a048032120500000000016a3d043e030000000001523a73e4020000000000d6e185040000000009515265ac6a51ab52aca728494e\", \"6a52ac\", 1, -1139794423, \"4604d471962f6f47f237d5a06bfc63a5cfaec61962a4e321dd216ef73339efac\"],\n    [\"0400000003df0a048733638d34e970f049b40a75505fb2b72a9b31f249bc780e098033320d0100000009525165ab6a00ac6a00ffffffffd76d4ea39655c77006ebb203e4124934baf5bbc0f3573912d3aa3d2f37c4a248010000000700ab6553526565ffffffff91cd0ef9092d6fe276216d87f6cff0ed4cbef5daa21e7f7f484be78286d5cbfc00000000026563d3e4b23001c83b1c030000000008526a51656563acac8b3a22b6\", \"ab65\", 2, -1458802054, \"e68bad6b6b40fa91f193fa867f83ab01fe199b73624c0f572877e48d12282fce\"],\n    [\"0400000004d3c663da768e7ffdb556640ba4e8ccf8ca315811e0fc08e337fdcf2a3682714c02000000020051ee6343cf14a141cb33b254fe1e6fa3790ff36dde47b872a051d0761ebb48534bef212fc80100000000ffffffff1fe425741fde7817486590798eaba8519024794dc31be2065640a673c162de7103000000086a6a5163ab51ac00ffffffffeeabb021bff71e637571f9c01e5b74d6dabb1687ac6928876f0389ad36b97c0e0200000003536300867cc44603402ce50000000000009d0b89000000000001abd7e06f0000000000016aa78bfd25\", \"6a\", 2, -1941167167, \"a79c711c3e3139d77a75955cf350071051235cd6817a1972cb15f477c627e76d\"],\n    [\"0100000001f25843b26bbb02d5586d3f50905cbd28660f0e70a6f6844e7420bdaf4ef90cf7000000000551ab6aab6a35bfb7760153757400000000000500ab65ab52079d7dc0\", \"51ab\", 0, 1493771235, \"ad15afe503ef3d5cdf362074867532a238e39dbd59146acb7bb746afd8605510\"],\n    [\"0100000002f2060e967e7fb015c59a81c188a8d6b79491add2910efbe3abc04415210176110100000000ffffffff6d826e5bd11467ec6c048724fb86e1937e603f59cbe13131b17d92e0668674f20300000001ab2d85ee1e04d99a99030000000009526351650000ab6352f9825702000000000365525135aa0103000000000863ac51ac005352abbd33d0020000000004ab6a525100000000\", \"\", 0, -508768182, \"3dc8172f8f3a8fefbff32c96782ce2b3d46f703ccdd98e5e02ec8aac68a0530d\"],\n    [\"010000000106a576584c01b2e6b91fd488ff2ec69723816db8d3765c95ecfca616c9a0a159030000000600ac63ab536affffffff01af58a4040000000005526551ab6af47c5142\", \"6a6aac516353\", 0, -736823632, \"981a07d754c0a41dfb1a27b1ecba6b6c39dda88bfb74333cc5a3499b7c0cc90e\"],\n    [\"0400000002675ca81824dc4e664fe4a702146a6f871115b7cd04ae9d04fe8ff62e09bb4a890300000002ab0031842137066a11673877e138b9c0f87124344939ed3451de1d0e0e49c596472d15bf43ab0000000005abacac65003ca41a8302634459040000000000e7bae70400000000026a53158a4305\", \"6a0000515352ab6365\", 0, -1531929498, \"57ca00bb560508f076c3ccd12e53be2dcec4411679bf9ed146cca3f5fac377ac\"],\n    [\"0400000003c607daad08dbfbccd46713c543ffddd467b0465e4c776a0920580b170f070fc50200000005ac5163516affffffff3f9e4d93505cbfd7a96227e47028663970e52d2362b45903c9d95d3ae44579ff01000000046a535352ffffffff1f927373c85cad4466611222c78e4917abaf16c2a549981335fcfc1c6527a85b01000000026352b994b46301a888a6040000000009abac6aab515153ab53e9f1f81f\", \"ac65acac65\", 1, 730703345, \"cd3e605c35428795b565c60e28deb019a277276d9b93023fc4694ca6602ed1dc\"],\n    [\"00000020026fa44598a0700809cc8a89956a17c1a1931296e458c2ef3e80e02265fb535d6901000000060052ab536551ffffffffa90ff27982e312ccfc40282e3555c9492db649979e30bc38cb5536ba7296db660200000007650063abac63abffffffff02a76eb600000000000351005283a6000500000000096a6aab6a536a0065ac00000000\", \"acab655100\", 0, -1497557755, \"549288675c4a6d555750b1f50699755d747ee93f399ae9478738f0499db32e41\"],\n    [\"0200000002d7ae2d01e4179525262059a112614912996cc141b5b757688104c758ff2007cd030000000563ac6a5365ee35f34cbcc47ae076a3a06eb854672fd39908c3fc50ed5d2a4969c418e38ef5df9666680200000000ffffffff018174dc020000000008630052535163ac6500000000\", \"6a52ac\", 0, 1311646011, \"e6658b2099140d4de5a6d7befc1d3f8236d638da564962dfc25604db35593938\"],\n    [\"00000020046c71a9a4621103d851094ce7145bcde5f9223ece86016ff9f1b5f2f197937db101000000026a52ffffffffbc7884044f6f900a4f5e36d326bd0e870ac8555ebfd40bb72efa58c89a2db85302000000065265656a516a92bf41267b54e73a2fab8a195ee9a2ed0824204819d5cdab03a9264e2a3dfb687fb35b750200000005ab63006500090a9c33029724bd8a8713cef203f639f7a8665bfee589ddaceaf610cc8d3167fcf249ed00000000056565acac63ffffffff0440739d020000000002ac524fbac5050000000001ac5ef6bc0100000000066a535353ac657d55420000000000075165525352656547fe1fc0\", \"6563006552ab65\", 0, 457628151, \"5d6abab40156f91a5ba0e983256f49908cf3cd670d9fbbf8fb379ca76cb74e86\"],\n    [\"0300000002ca5566a5afbc1b3284647d33e66a4b011729d0656b50fabdc93e93bea4d98a4103000000055153636a633968197f790df5c1508c64400f5fc80478cc9316537b074541d12706dde7df573d697be00000000009acac6353516563516515698fa60491ba8604000000000465ac0065e9cf0d030000000004636551ac6a294a0000000000002dc093030000000007516551005251ab00000000\", \"53536a636a51\", 1, -1805208098, \"ef66e7ce858d2c50c4790f4a3f0d93541dab1c18424e33975fa5107f461f0b08\"],\n    [\"0000002001de47e3c1b54a9ce26500201521065c1810e20645f29493bd4063f9f64b5aed4a00000000070063636500656a8720d479039972d3010000000008ab525363acab00515bedb90100000000066351ab6a6a51bf05e5000000000004005100abb6cb97be\", \"635265\", 0, 737260716, \"99ec0972584baef5dbda3623d39dbd39a2b2bd0298a19f524a561c746faaaad1\"],\n    [\"0100000002cc6dcfb9af8dfbd11c3f3d7dab7d5383454080d21f43ce34be55f94448b81a890200000003510053ca8ed4cd1accbeb9a06a9f88646660b57c394e5c3cb8949772ce6939fa9d30838025954901000000016a3dedf0c703e483df000000000007ac6352636a515252c9d60300000000036a65ac34b614000000000006ac536aab00ab4ee53466\", \"\", 1, -134145012, \"e439bed50618647b878c1a3cc4fdbb20e13f4d84a1cc0b1ed08a07f52f69b52f\"],\n    [\"010000000209af14dcea8c8b77936cc137de718ed0c330773a87463e99fafa18dd390639e0020000000953510052ab6a6aac65d1371850d966255a23e3a53ad1849b620124fcc914f9585e83f2828ea3b972063d62799c0000000002515347d4fe9503a328690000000000046351ac63674a59050000000008ac53acac636353ab615777020000000009ab656a51515263630000000000\", \"006353\", 0, 1839985641, \"657f83d24405121d1b3fa8dae0d322c1be3f828b241767924aa90e2bbf6a4100\"],\n    [\"000000000378d39481518d236304d4fc676277f6956fc53d7fb9ad56c27f135f880934391f020000000200ac807e109b721352652f3b1007803f0ff5e253cddfd2420e00b3543e67f605b318d6101a7d010000000965006aac65ac00636350dc2263c149a736a571ebbe1e75523ecaa9253576ea7b68c29d53b209377241a5aed06e0300000006650000535365ffffffff0414b4dc0200000000096363000053ab526552562e66030000000002ab6a60cd190100000000036aac6a897ba905000000000952ac00526551ac63ab00000000\", \"6551ac00ac51ab63\", 1, 223097174, \"a832aa38740fe23d2f1dc044acc74fbfc8667d80fa43a948e367060b23e85e58\"],\n    [\"0300000004e8b2a8744b0eb6e0079e4dde022964764d0f24d94310c5b4ad8c38ed5098ec250200000000cef255acf76a20b64379b1121f1a8b22ba7fb81e49dfe9c8f0c1df6d8b47a95a01e88472010000000851526351006aab51ffffffffb766d43ac274aa745cbf2bebf20dac0ade9868f5fbf04ce281979328d1bdb9290100000007ac5163ac63006affffffff189cd8d14d7f1344a24fdb1de32af143261d3616b7c55346816762f6c3a9c39200000000046a5200653b14180701d6967b0400000000015200000000\", \"ab51636a6a\", 2, 1696577425, \"a7e0e0ab7e111532a3f200a6f488193a785404e2af2845d8c68ed5377b097372\"],\n    [\"00000000024e1321acad6d252788b46c22f4c92623ed6065ef7bc062cca558e78808c131980000000000ffffffff9a4b34c5efe31ae426172c037e6e083221937917fa2aa3a2840b82113b86ed980000000003516a510d5ee5a6018793f50200000000035165ab00000000\", \"ab51ac5251\", 0, -920533482, \"2830fe6bbfcc05a4eb352e73d5f3f901f8c03960b01861180fc30f296c7288b4\"],\n    [\"0000002004670ed226cd848b16bf11f587c721f6013e9a583a3efdd5a5c1f8d067e1f3b3eb01000000096551530000515365acffffffff02a13dd640fe37888b25ab8cbe2723cbacb9379eabd826a0e633eb80df23b89800000000075200ac65acacab7d96e09070be160929223784308de3ada330480f5eb29c71b25166d408a84b6f10a56a000000000004ac00516a4af896ca8c3206a7a2b08fbd08777dc2f781e0ff30e4a4b08e2044a8b24a6136b4c6f4b30300000000ffffffff044774d4030000000008acab52536a6563658e088e010000000009526a0052ababac516350f31805000000000100ea1c2f0000000000075351516aac656500000000\", \"63acab00656563\", 1, -1667110529, \"ebbf8f52674c011405d4663a916e6113dfaaf7a96a01ee35ff99aedb9f926372\"],\n    [\"0400000001d8559a87e3f16369a04a4c90ec201fa39f0942066e274bbb9a45e1ba73e3236401000000060065ac6552acffffffff04fddd0800000000000151ee79180300000000046a6500514d360a050000000001abb085ff0000000000015200000000\", \"656a00ac6500\", 0, -1572406954, \"aa2cd4517407ea3a40712e98908a5a3f8819ba3fa5093b1ed9513c0dc9dbb5b8\"],\n    [\"0000002004fe522eae64c877775a41a979defacf6089862fd80e0c9e7b4b34df26de3a44b003000000026553fffffffffa81d114335bb9304cc2cfaec41dd65166afe0796d71cb23d0eaff222ed9f04b0300000005ab530063abc43212c8aaed1fad5bfb344779f6e9a0424812a2bacc252ba733ccd5b49626a4a09d5eeb02000000035251acffffffff88c62e0c16a3b6ff6c460fc1b71fc135bd3dfdd0876460f3b92922e280a9ad78020000000353ab51ffffffff01c87f0205000000000663ab6553536300000000\", \"656a516500ab5363\", 1, 1047326583, \"c0e82f97705331ed9424ac96ef3151248d85d468d19e23a024a689e47d8afe8a\"],\n    [\"03000000037d54d19edfa085d8ab6615f3d2a9fc334a161e0c0c09474ca256a9445a61602000000000016a2e65865833a9692a1217d60c88c3e64cf196499833fc1d0d818d84be149888a2d5e688360000000007516a636a52ac6ad33ed93739f4e88e56358f2daa6aaf67ed4cc10e821c17fe4733c4072d406c3f569ba54302000000045300006affffffff02d3105c0100000000035151523d58be050000000008acab006565526a6500000000\", \"65acac0065ac5153\", 2, 1274408111, \"06ca21dcfec886bb1b3172fcf9e13d6eb836150eede4d41fdc41428baf8f7b28\"],\n    [\"04000000018571e87ea7b830726d3e71c9660a5044feae38c4f92635d8ed94da4db996807f02000000056551ac63ab964fc6ee0148de30020000000007ab00656552005300000000\", \"00\", 0, -600318320, \"7a0c05c0afac1ebb009a1c77156e18074d825ef8743ce4888208f6f764340b5e\"],\n    [\"0400000002b876645622e8223878090de26eb678118510cf43012d9d8273514b21352676df02000000035300ac54ef51e038f0b866e5fb282e3f8eb2ead19f35338be360f5be7e0034460177856625da89020000000553525151acbdc9421e02f74a0e0400000000046a5151ac4cdab004000000000365655100000000\", \"6a6a635300ab5200\", 1, -1736008920, \"4c0a150d0434e50f99f054fb789dd207255b85aaedf04a1f0463f96c76d5d8be\"],\n    [\"0300000003ba253e273c21f63a8904c2602bfac470683bf5b7568c66873f8e7c0ae18f32580000000009acac6a656352ac6565ffffffff3dbab88c694c0adceb7e9a274657b61b2a03e36fc3aadabcf1e5b3ee89bcfea20000000003ab6a65ffffffff333056d61557984ecaa35231720add5743972f9c254d27e751b469593e458bca01000000015170cbcc540465ae850000000000035365532bc7970400000000080000ac53ac6a515115acc70500000000096353ac52ab53ac6a630d4d73030000000008535253510065ac63b4c150b7\", \"63636a00655253ac\", 0, 1919601360, \"2205a184ed7ae2088802c22e313449521caf8a8a0dadded379dee70aef16e8ec\"],\n    [\"0100000002167df8e368ea737ba86db720b5360363f06844800c82bc0ccdd40a77471a40b80000000001acb0e29f0874161c4695bcb4ad598db32c08a65e9630cd1806dcf94f87178c05fde85795c70300000001538a628d6302592e820400000000096553000052ab6563513533ca010000000002536a5d6914e5\", \"ac52ac51abac65\", 0, -142709154, \"ca7d3d38bd90c5ff42cc5a28955834c44ef4e9b53d031f69be2dc04de15e5846\"],\n    [\"0000002001be14eaab8b52a50858fb2d5a5da8e953d302ca2497d2efc0d629bf3741fa9a81010000000853636353ac515252a87d2bab02176dd1050000000007656a51acac5253670bea0000000000046aab636300000000\", \"ab52\", 0, -168875207, \"7421ca9b718ba2de015c3d098a82b2434b6397d00960166170388585b2153398\"],\n    [\"04000000049bbb64feb069b93a3d1411bd6314f0bb0e394218b544c2b5e05e950134fc42a602000000015331087d9c356dbd00ba7aa752a1aa53b97c134cf3288cfbbe5265a4a0c12bcb7a191dafbd000000000200abbf6c47fd0d9147971ac2e2f063c072cdfdbf1d9346a1384d51a40e558085e650ae8fd7ac010000000965000053ab6552536a36519b360f3ce67b2c27cabde352a02e91e6b92f45a4f1c5b48fa73d0d81a54610d83ab2030000000853ac636aacac63009c4d667a03a9d0af050000000002ab53dbc6ad04000000000073f2df0000000000075252ab0063535160cee252\", \"516a6300ac\", 2, 1288010190, \"52dbcfa3882d9c3449752afaec71aa50f47f6957570ba4627c9bdfcbbfa21f24\"],\n    [\"0300000001420bad2f04958be7b63b24dab2200090f4bcab3fefbe60eed9a8fca001fd11ef030000000363abaccc72ac9102f26aed010000000006006353655153dcf172020000000005ab00636a5168ad49db\", \"6a6aab00\", 0, 1017288384, \"e3bf20e5163bd9895dba4e06954d51f06faf7ba54276731533c507f2b8be8e05\"],\n    [\"0200000002c8a7f0954e68f861bda67cdf71fa4ff342cc901e8fbc0211cbf13b107ad5f9f80000000007516aacacab006549ef050b95660d03cbf2ad438124ae045f63d82e1e5745b823a937f57d594070a04724210200000001aced21b35403033b6203000000000853006352526a005257a5db030000000006526363ac5163099b770500000000002c63b958\", \"ac5353526553\", 1, 1204742693, \"a3ee4dd2ef9b15c8b98ab50f51b62e589eeb87369728e44c6a72ea3f04eb0578\"],\n    [\"0000000003aae83ec6cc2ef94f8c2feb988d7365e48b5f82b6ea4ceaea78580c7e545328d801000000076a52ac00520052ffffffff161ad2eeea9246f1d8f996f532af7748a9de393e88ad550c87f8cb9444f9347300000000066a5252535100ff6bcfcfae22c13f4f3a1b442da8c69c3ca8f9e24306a26507b66cc6a43d6a0c288c34990100000005acab63ababb2fe24a8020d34d9020000000001ab339cd6030000000009ac5251ab00ab6a0052510c7c34\", \"52ab6a65acac53\", 1, -1859962302, \"e27305521951aa79b3b92651d150330e12af39e7718073604cf6ce3252ae0902\"],\n    [\"0300000001a06d46b9cc28d22ce5b030c48e00e195c9b53783b1c8901177f68cff694028ee01000000055253ac5152ffffffff02c57423040000000006ac5152ac65653ca7fb020000000009ac00515365ab63005100000000\", \"530000526a5252\", 0, -1894944879, \"9cc02de7c9b45d874d7b301f5d7e16ae3f7f4232e81f13669a7622ad1c949eb7\"],\n    [\"000000000347eb6ad1ca83690c5ada0874f4988e417bed7ac592f0082b876f44b1661fca3b020000000653ac53535153a01a5494b8e077fe807a4bf2dd634dcc6a75b76dad207459d047232dab43ea04f48a132403000000066353ab0063001d0fa12fe7f8a6af1056d4ae552fcc0bec9e8fb4eaaf24f003ee4995dbf79b491e7fc0f70100000003515100ffffffff015a7c2c03000000000653acac5165533b518bac\", \"52ab65ac6365520065\", 2, -1756418651, \"ed0f941672c68eb258b777050648d799085fe9f654e9318a94effb798903b94d\"],\n    [\"0000000002365d0a56525962430d3e9b482437536bbf4ec9bed60f7501b7663e2ac695761e03000000036a5152725a22dfbe296c9428f84bacf2e8febf83ee74201addd6ee1136172c057bccaea053c61e00000000095252515200515265acffffffff0413206a0000000000036a53535cc3250100000000080065005251515165659533010000000004ab6a5363c675b4010000000007ac51ac6551ac5375d8ac28\", \"006a6a0051006351\", 1, -1666490617, \"4cdc5129b0e9a6ace879802dd31d965f4a3db64e2a756c5f15f3b4b158bfe28d\"],\n    [\"0300000002777d9770caa27251929d11b96d3fa1bb6ac740dccf079f22fed9dbfe383768010000000007ab65525152526397ee2f67bddccc81d8c1c9ab9aebcd97a998f46c92368e423e400d860850b1926c068fa10200000001000d356b06019a963e0400000000015300000000\", \"0065\", 1, -146667916, \"dacd06e93826f6ae0a8afb772eb1b2517deafbb30c8de245e2a3390b9a712dbd\"],\n    [\"0000002001251a49c5e4674635a29f88333e1fbef9e878fa4c135f8664d3d3e1a6abef84c5010000000563ac650053ffffffff035423780000000000096500ac52516a6500652225be0300000000076a63516a51ab514a03240200000000001b7c15e3\", \"\", 0, -1775005973, \"eb561eb8f7ffccf0e7b2f66e605931ed6705e298a1f5494d1ed7e529e2c8d6b7\"],\n    [\"00000000047dd5d23d42e32e00ceaeb148e53647878146d2d59c996084774d3be807bc26150300000009006a5151006a636a51ffffffff996538f5360bf97dfe83ef103bc27812160ed267ae56830c802d9600f96eff2902000000076563acac526352a4f56637d637ac39f73eb9304fc0e385d314dcd243fbbc2ce6b2f5aa88f2e71ffc5ece4c000000000353516affffffffbdf44520db3ffb3f1295dc43c28b81e264444319d0ee6b081fff7deb1eab194001000000025251ffffffff036d6cd8000000000008abac636563635265f9b97004000000000665ac00abab538d92810100000000035352ab00000000\", \"636352ac00\", 0, 1467834785, \"f4d8af57f64935651c66f5b780291d31eefa566317ddabad8c3a646a01ba94d2\"],\n    [\"000000000358135d221192c09b5ba5f15063884247177a10b31ba141d9f29014bd6dccf1d3020000000353ac6397ecd4901d105558d31db0df3ffe1711706717481ff7ca035adadbab48e19546d53f9aaa03000000055353535300ffffffff1a4c0677eaca5983fb8afe8779df1ecd69243becc351ba8e60c06202485563f00000000004ac536a6593f69a8a0447f77b0200000000010028161903000000000953ab635253536a63636ff368030000000004536300acf7d9e1020000000002005200000000\", \"51ac00535200\", 0, -865824586, \"913b2f2deae7d6481ba38e60f450152a0fa9d13ac96fce58bd26667b916fb599\"],\n    [\"02000000024c945b7280f05efc1e222a931f6a48106011763142c4bcdf2c6812752c88d0f703000000026500fffffffff4a401963eb43d03b6597461a2b1fa38232b97da365fc1e5e5d9e9474d38877a0100000006ab53ab6a65517b255eba03e9020c030000000005ac52515152dab48a010000000006526aab6563516c1d4f00000000000153bace7996\", \"51abab00ab63\", 0, 1639059705, \"5bfc7bb4c891acda08f1bd23adb6afd1cf168a57ee5521b446bf722ac9d9e439\"],\n    [\"00000020031c7b62d0658cae2548a6710f6b458af1942bcf08cc563459e4b45b2e448e26cc010000000700005363535263fffffffff8f5e41d9bc52a0b7e3529425b4be643af00f69a16d952eddc3a9c4ed62fa6c70300000001abb0c49110669512f11d058c7187b8dda390075ae5e8e2acd74050e93e80f24870bf4c98570100000006526a656aac634bb80e4c02027e81000000000004516a5153a58ce30400000000096300abab63ab0000ab6d1859b7\", \"5200ab5353\", 0, -866566253, \"7269cfa3a21f6cb3e32c675f8139707a6a462741ff7c3e6097f9f71e05258a3b\"],\n    [\"0100000003348756bbfb607190e63a73974d5e549b25c9d0f3ef6b0c103e06c68b3afb8ae6020000000452ab5100ffffffff95f1332e7463cc4ee593ab040ccfc36679c9328e9af734e7922f5748b14d25f303000000045165ab6562fe7f5da4ad788159d4a482a7544a8b23764f01f85a672106c5a9baa6c834b256b3aede0100000006ab51ab6a5353d40edd7c0261589504000000000253abd00c6a0000000000045100655310377771\", \"\", 1, 696528911, \"74db788a25e3446340d4bc9a14feb3a411c112a82cd2a3bc24215a35c085c739\"],\n    [\"0400000003c71d8bc38ba5b0f3f772b7c66a6fa6ec3a7191e925d631cfaf8dbbd2add1e371000000000752ac51526500acffffffff91ea793c297a27c0174e2fc18eafcd53c56e0acf0205a36fc36a030c4fc47f750300000006536a0053006338bb9bd90608f28616a5a723cd13f3125b7001dbb41c0cfa0574309a0dcc13f7f399c1fa030000000952ac6aabac526352523e74d21a02e71f1c0400000000010033a7530400000000055351635252954c66a4\", \"ac53ac006565acac\", 0, 2008824444, \"34304265f29b407aa4009833aaa17190f56a54ce11faea5bd3ac66ce4e0c53df\"],\n    [\"03000000030a5f2168b10311742d01097e26d416205486d982d1d53f8a254679e3cbe6804602000000065365526563638ce8fc1e87a6a307ed4e574a1fddaae136ed5445dd540d5f860bc10a37b1e714afcd794b0200000002520085dae579e428befe6a5d157833c95b6b2910087f7d0cffb9d9f5fcd25fada2e091ef887b0200000000d536e7d002711666040000000001515106ca030000000002ac5300000000\", \"\", 2, 1229245183, \"6b9a9994ca7413581d314d629ab5de4ed575f8a322e42dbdce467189a795458b\"],\n    [\"0100000003633f3b4fa0e0f5b231aecc0653f95e78fd05576b2684fbab459cc45f6527933d0300000005ac52acab63c229ad647decbbe73a7dbd38049767a2a34c070604bbe598237b71bb06e3c81050ad5acb0200000006656a006363abc0086fed5cb887e9ba7f6eb3db35498442485281c8c523142678eafa45038f73563bb7f20100000004536351636b357bd103d77eb00300000000056353acab537ca56201000000000652ab52abab6ab79043020000000005000053526381e905a1\", \"6aac00\", 2, -1012188044, \"f1ed6e7e64c305b6a176f86b5a821af80dd3404ef840ac815331b23dd93e81e5\"],\n    [\"0000002004479d64835bb79d0bd4e8cf6cc05e916b63433c230434df24e29069c739049c22000000000800000053ab636a6affffffff0fd76f98922ef30ccda77b494c73b0343923e7582ced5480231e9254cc3ab1fd02000000046a65ac53ffffffff7029b2f0acf375179bd55de6881767d85d154517ac68ab7d0693bb694e960079020000000365ab00ffffffff432a88d8a9d6a69e96f4ac839988b9ab908dbe3c9cc4583c3dfcb719c5ec2006000000000663ac53635200ffffffff022b3f5500000000000352ab51217aec0300000000065363ab516353c83381ba\", \"ab00ab000052636a6a\", 0, 680497491, \"f13dc78ca396a18daa12cee9efa0c79808ecc3becc86bdd5646f38a265cd9cde\"],\n    [\"0000000003c04bd697c27adc696f0fe51a683c1a756f0b75ef870285455987cfd1f5f26f2b0300000008acac6a5300ac6a001c12e1a20babc85f72471a3b082680d12bf79316ed881085cf0359b528f08bce658824a50000000003ab5100adf1ba5b0eadef3f7e7e27e907d9de6d416f533897e4669be85cdb449ac7a9fc459220390200000006ac65535253ac3bdf68a40472df5f010000000002ac00dc8f00010000000001658a663c0500000000076353525163526a5de1dd0100000000046aab525200000000\", \"\", 1, 367667463, \"471765a37d5e64953008d04107ea9120cb4c2866f9caa9309021c1c4653ab451\"],\n    [\"0000000001030ba52f820af7b11e88267a5345d08811f38b0190791ffa3b0aee2e0fe330930000000000ffffffff04b5b0ff02000000000165a4725d05000000000165bef5660300000000026a51ffff9b01000000000763acac5352ab5200000000\", \"\", 0, -169667913, \"3d8156fe27b6a7b5a7dade15dfceb4879f107bc2fd94c59a6e323ddd9647fe08\"],\n    [\"0100000003f39192a4b397e9d89526a5b6ae1019c7cab3fbd1abf51bf6da8cd37b4c52905c0100000007ab525253656351b24b2865fd61baa278df87698ceabf60b29b9f6ac3053f64723a829c76c4d99da3db16fe03000000065253abab525107d9c5c046cdaab710038d14cde01823a3d6819243e7f643193205f4cee7ceb125d6300a010000000060a55c700200ac3a0500000000025352b3440303000000000465acac5202f812a0\", \"ab5353535351\", 2, 1996204016, \"5d2e1bd30be90d35ee36a1360e30403d3afb5c980765e35f3f58aecb93544b40\"],\n    [\"0000000002885007ee2e6c651fcae969749b8665d4cf674a6a19f325e451c670a2e5a4e6d0030000000100ffffffff909d20b617a23c84a3bde8208a998e57c97986dcc472bde19aeac5db91b6e002030000000153cce51f9b02312a080100000000025252797fa10500000000065100536a005100000000\", \"\", 0, 1823608530, \"163748c7af91f64d5ae0ccb1b73c4420bc576efa99c110f514aa787402e50099\"],\n    [\"0400000004117aa1ef9868dc4e7068210ba0dcb9192a47b97252a12e879fd568161023a0aa0100000008ab515353ab006552ffffffff6c9f826ba05b6fc652638ef84355a9896ef881f794068de18cd66c7bfe98b66401000000046a6a5200ffffffff7886b4fd6fd60ac24e5018b61cb89aeffb221661dd9e0c7f5335a052add3df820300000000ffffffffed31a66fd9dfbdd571746d8233b8f7ddf91c1378ed16bd014f47e5a507d0413b0300000005abacab6a0062f2fc990420dbd10100000000055265ab6553be344c0400000000005d4b5d04000000000863006aac51526a53fca7270100000000026a63727fa74e\", \"5300\", 1, -669568391, \"01c2827a037aa77fb987e12b11cf5133a9909183204d1081f992d0729bae0e5a\"],\n    [\"0100000003fbad0ca0f37a90cbbf63416f6d28216e8f4183c169e8bbd74864b3deb27c744b02000000046a6a00533891b0f82595d9cbf361207935ab545e5da561dcd20e31a50b5936cb8c77ddf7e6b4fe51000000000151cca27cd765bb308299b3c0cc60b78b3c26da5445e1540280ad136e571efb2052b3a4fe740200000009acab655100630063ac3c4720e60147ecdf000000000004526553acf9c7cc87\", \"\", 1, 1288540066, \"812dacf8b58f33bb102e4fe54d2e950b2e85438527942ab03058833fe8b40bfa\"],\n    [\"04000000033233e9e7cc9a939cc0bc0ba8ec9e76d61c341e2b0c5847c2f25e0409c5a35631020000000165ffffffff3450477c69b6f412279ea069f3f71a77e26d6ae8c28b014ae2ac04d838b1e2e80200000009ac00536aab0051ab63ffffffff2b1727d221767860cb062c83957cf94a50ab2b464a8cfd96bbba37cdf64671f603000000025152ffffffff0452d581020000000003526563b495880000000000060051abab6563fddc9d020000000002ab63d1da440500000000006ec14cc3\", \"6a00\", 0, -489211729, \"5b68245cbb70527bda3769e3a716d32877268de0034f7fe639917685c30a2a85\"],\n    [\"010000000412fe18fd8d283e3fcee8ecfa228455dcf17296b2050cce72cc2da68775ce974002000000006e3b99f7e7c79b00775175a6360c0470607a2d154c1d958fc674ff07c19b2b98fe05bf01010000000300536affffffff942d11fd0385b7abf98ab26e6d07581fcfc06fff654c0b5fb755e2eb30b9c9060200000005ac63636551d8a5db7c302bfc694994c5f55f4d967769535931e8db665d04cc8ae370694f7da5d79a8a0300000002abacffffffff03451f2c010000000000a81214020000000008ac6a6563636a6351cac503010000000005515100ab51c904804a\", \"51526a53ab53ab536a\", 2, -2028077816, \"fd84f20f8c26f7a7120f7388256190b410bbc1a00b88da23ef207ebb6812b6e4\"],\n    [\"0400000002e19b1b129b4fb4f9a86812b71226c8cc5c26c5b3d18d630af6d13e82d86b6d720300000008536a6552655151ab049dafed26ee447c9fe459d13401cbf4c9b7552872ded1d80d0cde630f13361a498e9c200000000000ffffffff03949e5b02000000000751006a52ab6aabbd1bf504000000000365526a0d873b0000000000075263acac53530000000000\", \"ac656a5200\", 0, 40595790, \"7caa40b4e6154ed1cbd0817a7841a3dc8c13aa41005bfdf84660b2a63e90f2f6\"],\n    [\"0000002004a878b0ffa9f5d78bac2a3f139b611a4cde3d8ed44e9997630edc93137215c446000000000765acabab00acacffffffff27eee4a885f866a523ed4d3a3274a281baf17296ec193768e4e0166d410805d30100000003ab6565ffffffffde65feab7e753cf5ce45c8bdd5eb95a2c0070e457a8ede7b80cd8d45e98d953d03000000076a51005152ab514e1fdd8e534e5c90494aa8de59b3216234cb1c6efe0226d068291dbad2af13a7f57a6837030000000153ffffffff03c02b6a00000000000100de60c2040000000000bb70a5000000000007656a53006aac0000000000\", \"51636a65acac\", 0, -2073080441, \"1ef92e79c73a90e63295cb517bfd6cd49ea719e74a3018d341468d7f6ff9a8fd\"],\n    [\"0300000004be691ecf8fb774d02dde6733814ba807a0203bd2aa6839e7294211e984fa89fc0100000007ac526351656a63ffffffff59f51dc6990a00efb4980c58da3d5fef86885b51f088bea87b13498864eca2290200000008636aab6a65636300761a8c0edf45a3a872c5ce4b8c2a6b7910a478b646895d62727292c6a13a6d330f8c8cca00000000096a520063526aac656590b4225c21c8fb599616cce89cdfa98496df3af6b1462dc7cc30293bd1fd7ce91f5267230000000005ab51006365ffffffff045ea293000000000008ac6565abab5365acf3a19304000000000465530065ec70d80100000000055200530063f87d7d000000000001ab00000000\", \"510052636a\", 2, -975674659, \"c860be4ac6fa467cad0d5b0c14ec06222ba36133f0d8c1ba782e4ea78df66c9b\"],\n    [\"0300000004b830747f0a04dab4a7f68f3417a75d4b97e0e124d747149efd41b1035152aaed0000000008006a536565536300cf272c8c232d28e2b900f74ac5ecac989ea985cc5bee227689397ddee0897242d13d26010300000003abac53a7d6a6f206d23fc980cb30bce6369460ed5bfa3e76d3169193d8f9d0c66730abb2707e390300000003ac5352f69b6801e9591f6f94eff8cce3c69b59ece1e0b644b892b7d0345bd10f9cf49321ef3987030000000352ac52ffffffff02c0d104020000000006656563635251cb54b9040000000001ab00000000\", \"63\", 0, 1981694447, \"07f6f78b1b78b98ed38d8c40a93a5887d538471c859cd8f2f54c7e63a2f8b636\"],\n    [\"01000000033745452216cbe450df648218934a851d3aad6e91ecf263209592be9ea8f47fb8000000000351ac63f1832ac56c94253c991284f9e96a0f68ba7ee1c937115d4d8343407743b5418fba70b52201000000056553635352ffffffffb002e55524e752ae8777c4b11678c62159a5e477614b4f56f68699786096022b0200000000ffffffff011d7959000000000002ac6500000000\", \"\", 1, -1982640184, \"e28d32fbe7f007456c8912b7ad41c8b05d685d4a322c1fcbbcb1b87ab3979f54\"],\n    [\"00000020047f7108264d7bed8e8777ab1a57464371969c359f5168a20f0d273bbe3c63b3a903000000046a53ac5252c110294604e9344d42733abbdd3a4e2e1acb2de62e51a0a1e8906cd8bf13708b19752f030000000453526500ffffffff193ea86539115b76c62ab3cd57b4abab17b419b68c7d12fb3d25922b7cb946c90000000003ac65acffffffffa0a1712f2ba53594c8fed2fa08f677c2c7ee1ac78af6a8d76819124fe78e53a10300000007536363acacac65ffffffff01a80eea04000000000551ac6363acbf5bd987\", \"\", 2, -1410726106, \"7b2b4d04febbcba926065f861344e5bc0d10af2992fe4b04761cd6bd083b3a3b\"],\n    [\"0000002003634e6909aa96a6050f4d2a768bc5e4478d139d9eeda69c94f5cc3ef5ab06f4cb0300000000365b279c89fc176e9b1232ea1fcf902129dbf7ca657826e5c10615a58dbd81abb6ecbda50200000000ffffffff6c5d21d82674bca3f19d549a1a78509a3be0c569942ca3a6eabbea98bc6ad8a1010000000663acab510000ffffffff018ad40101000000000752ab53ac63ab5100000000\", \"51536a00ac6a63\", 0, -414435206, \"d950ae8dde474f21bbdf1a0156e6fb5fa4a443a14d8a1f2fb4c419598c085edc\"],\n    [\"0300000003329c82ca6e66faea9717b5432b3995b62449a7649a16b86e42e4a9ddc1d5dff00000000009ac00006aab526a0052c3ca1cc9ac071b30039e08bb4446e431a38890f15245e98be43da7f5c61093682fac9da6010000000352006affffffff1893db2954a6728d356889730ad7fcfa939ced1d1f2ad9c35435b89f5376f8a20000000001acffffffff03d9f97d0500000000055152ac6553aefa18040000000009ab52ab5352ab0052ab488e400100000000076a51515351ac6a80433c0f\", \"52656aacac\", 0, -1540526703, \"e4a1166949079d0039d558f82c039f185e06d11f1a9d0eb5bc11800cf1f8d885\"],\n    [\"00000000012f7db24ce6683615db285adb3f46bf43e96355dc3c81983251383f5c9faef8330100000008655163acab65ab00e615c677044f8b4f010000000009526553530065006351a706b302000000000012ec8f04000000000651655100535223a81301000000000565ab63525100000000\", \"00\", 0, 316855837, \"a7324d3cb85b504a5f519fc1a514f1b340bdb1585fc2b692e176a71026a26949\"],\n    [\"0100000001360b43ed415b5fd8ed47b34dc8670d8d474e3de553cd65f4947a5bde7150c5260300000000ffffffff026e3d49040000000006ac63636565536014d604000000000451516a5127f347b9\", \"\", 0, -1760328907, \"9fdd782ac75555269243bda784ba18f0ddd6bad213bf7d076a074e3a18a206dc\"],\n    [\"00000020042e1c341960b93d72d40e50555af7042581f5eee6cc20d43005a6110cf5b2148201000000095165526aac526a6a6afffffffff951395a2f7f3bd0f147e94f29db3fd43a19d5f20a2f04db995c55db0d2b5b5201000000076aab52526a526370e5ecf07657391ce86c24f596d97cb3843782763d417a14ded51b397af175e86ed784910300000000ffffffff217d8711be1df2aca65883897f685363c988d1ae60ae6aededbf6af76f544985000000000953536552630065536337ef4ec90123a18a010000000006ab536353acab00000000\", \"53\", 2, -542278726, \"73f1982e612e1d8272e96bb20dc1f06d751eb64ee8143484cfab7e92b0eb7b69\"],\n    [\"020000000273f92d49b1e335ebe2806746ca065bcf386968f607ed71e2661bd4950c9f9655000000000263510faf59ff442b53c7db0d78ec41d633cb152fd48f49886d8c08c3dc6413decfe07559b8510200000006ac5100ac6365e42bd49c02d3db0e0100000000035351ac2ab0ef010000000007636552525363521639deda\", \"\", 1, 1213606794, \"4dad00ada5eed57b62eb1f21cf32aafe3ff0aaece6e95b6930e62af4d9588b79\"],\n    [\"030000000309a1a0f480af2e2ec1002ff79d446068e091bb114a240b3daf7a0d99c8358a9d01000000036a6563b56e6097ae279182c57a37fa03b0bdcbcdfa989e0a7a78fc723c75ac1c0ffadd72bcc15700000000036565acfc6486c261f689c454b0128314b8437ebec5bcb6fa631e9c6b1d479780bf8596b7e5b328000000000151ffffffff039394d102000000000500ab6a6a00df646c020000000000af73480400000000066a51ac63ac0000000000\", \"65516363\", 0, 894805020, \"ad0fece94fa69bbb0e2e756e2d9b577731d459ab67722a798fc9869f9e0e6b85\"],\n    [\"0200000001369bf2ef6e43aca815dd4268896c157eccc89ed9fa55dd3d0964c8779d20ec0103000000086aab53acac52ab63ffffffff0456583c050000000004abab51ac24bbab040000000003536a51269c5304000000000951ab52ab00636500002d2f83030000000003636a5200000000\", \"5352ac52ab516aac52\", 0, 1854003303, \"7a73f3fcf7d6bd3fa8e90960fc9872faddfced002e528e23ff80b999a3b462e3\"],\n    [\"000000200495886f64df97fc52cdb2fd1bbe101b134dd25eba645756ec3f4e81db3ec52beb02000000066a53006a00ab903d378a70c4ce94848fa00e9758af1c4376fa77590c74317fa8456f7853755903dd807903000000095352535100ab636a65ca43206f33f6a237725589c26eeaf830f3eb69ea1a36e866357f1a5c3f4d701d4bc20c600100000004005351acffffffff96b831bff6284a896772bc6db6d8431641f9bc54b95491ed74f46c20c1ab79b20200000008ac656a00ab00636affffffff04b99c73050000000006ab6a005152636089a8000000000003ab630040f6e0050000000006abac6a536563faa8e9030000000008acac63535251ac0000000000\", \"ac\", 3, 1309862668, \"f7809b823a009f60f08203c943c8f7460a020e033b386c1dc679fd4c4f9eaae1\"],\n    [\"0200000002f269172ea2621907995d834c4a57a45121aff58afc4b4650e85b6ebef692e9e6010000000163ffffffffeca53007e90030f13f830eb99d750a2e58c481fb3894d95d2d1d136b481f0f9c000000000000d7367c021f0588010000000001000cb8d8030000000007005265ab6aac63ffcdc2e7\", \"6a65ac63\", 1, 1980453343, \"01faa7a0dcd10824fad824b5d1eae574a22fe410bbca6487b2664aec60c17daa\"],\n    [\"0200000001f7235b05d137c7e3f15d76fca53c6cd8a274c4701c13ece7fcf60cb006f52d030000000000ffffffff0125b2630400000000045153ab513a6ade6e\", \"65636aab5200\", 0, -1689687387, \"bc07d39909802ba23c228d2057ff292a1296c6357be59ab6cff033f7ed73dd68\"],\n    [\"0300000004275bdcd378cc759fcf256027c1d9fe00a4e30af91b45fefa5ae41a7a319502c80300000008acac51ac63535200dbb5e5a98f8e63fbc87edd3d406761330a3bbabde482ba7b7a1c35d580e6a00278f9ab400300000009006565656a5365ac6affffffff7132aa1254ebd7cb5c36151f9aca690dea65c6cc918f9f3dbf2734f5a3290a1b0300000008ac52635352ab656affffffff72437f0999b196323700cac78a75a8723d086f702a38d1f60a86eac21dd133a2010000000951ac6300520063ac51ffffffff0223f2a80500000000065165530063ac22a20f020000000005636a65ab6a00000000\", \"ab51526500\", 1, 1300809173, \"b67c9dd54284dcc7e87060c3701de7a3412d2b8b90fce2f5b05e025f31875a0a\"],\n    [\"0400000001e13282a782ee6bfb03079185920245868afa1a679aa15800b3cd320b95b9ac03030000000351acaba924a3260288fc2b0300000000007e374003000000000652636a5300537040539a\", \"006500\", 0, 841625017, \"6063c360eefb3c31829dafb65b4171c76c6a1ac8d69f634a3fc26214501a97fa\"],\n    [\"0400000002351f77873f2b88cef8777fcea3dfbc6786755fe54b61e508ccb2096c324a1d14000000000565656365ac78443ce9a8ae10f28d4136233bae64817345aa3590ff436b18b9b02682f193b3d4dc325c030000000800ac65ac00abac63ffffffff02e1d8910200000000070052ab53ab65537ae1f80100000000046a53006a00000000\", \"6a00655365ac51\", 0, 295426831, \"5375c67c7ef97681f21d2530f0b4758ff59f9af3a42960eea851ee10f0142618\"],\n    [\"0400000004c4cc7e01e56f0dfff902ffead9cc9f97a7fdf4c363923dfd6a0c5a86ea8aedd703000000046a656a521fccd50752ad5c2d9fa10bf293a8a1ee6df12a854a9e6781f52ba9cbc3ed4e25e0a616e2020000000565ac63ab65ffffffffeb3f89c36160fb3e6ac3012ac45c02c31ce32e6b12503675bd60bf0bae10ed780000000006535363525165ffffffff9d1540b14b332a5ad7d76c876a47feb585c7e1dd15845f407fb675b50ac6c3fa010000000253639957917c019d2f0d000000000001ab00000000\", \"ac63526563\", 1, 1701866287, \"43019f96c49dec49d991fa1479cfa75afc8aa766274bbc9f504bbf017cf9ff6e\"],\n    [\"02000000016d53bb38c5bbdb4bda71540e1f80e7f6e0cf430eaac400d090daf63dca650ffe0100000003526a63ffffffff02dc98da020000000008ab65acac51acab63b6fa2902000000000765ab516a00ac65ae8759d0\", \"6aacac006a\", 0, 1335108077, \"7dac3f2f48765b2615b41b9296c45c519427f3b4618d3a9a3bcbb2bf179e4adb\"],\n    [\"010000000317e9d95cb3628fa3c1b45a53e4fbf7fee034465f88b9d15310146e71e6abd65c0200000009636a526a5352ab6565ffffffffc96853f37a833cdfaf677ac8db8120de8f6baeab4ff17410e246681b8ebf8bf5030000000251ac69738f2baf67607637d24f6abcf0eb062b98cb7f3ce488415bd58ebee63082d9fed98812030000000951516a6551636a53513d37477a01c1a49d02000000000552ab52515100000000\", \"\", 0, -2005411223, \"c8fec68ce8fabf6284de5b9c82ec7e2fed61fd164b4eb421fdfa1a2560ce777b\"],\n    [\"03000000016d63c2106650316ff11b9b4096ec60293fb0461b0d012ec41175eb8d6d75a8d1030000000953656363ac536a63510b1f239504b1d8e90100000000076a00ab510000ac152a8c04000000000353ac52e594f50000000000025253b2b5aa0300000000026353af6c4499\", \"ab516a5263\", 0, -528374544, \"0d1b08397aebfdd281babe116bd4384e4a905cf45bb2430733df478027e38dd0\"],\n    [\"020000000285747c7e10b1f21140398aa7494fd7d8af6cf4d2bd5e3f34ffb3a2c0993e56e302000000080052636500516a51ffffffff76a5ea4d77d7c25b31754c98098816713bb1d50db60ae77c9e657bc81f38ad2001000000045252ab63ce7ddc0e03b9921d02000000000151fbb1880100000000066552630063acbac81a040000000005ac52ab650000000000\", \"\", 0, 897997200, \"7e3ae7f743635ff1efbdb81955bbdbd11373759cc5c38400d9a6cffea314dcf9\"],\n    [\"0400000003de754e93aff04dda34feffcb0aad62971fec17d64c4d0189ce40d26f308f7a2f0100000000ffffffffef96a5964d9b8ed8d544cab90df48a1f38c2d70df397ae7f4559bd83b19a775c0100000008515163ab65526a63ffffffff9e5f9dbc57ceea9c7c1678804217835ac9c750bd6db8700e3f0c0c17749fbe8801000000025353ffffffff04907c8f0000000000035351522c162f0500000000004811ea00000000000552ab5265ab9b2a9f030000000000f76507f3\", \"52655100ab53ac6500\", 0, 556535749, \"87234535033550711631676d0ca12db69786b32d2cdfac6c7de9ec983ad57f05\"],\n    [\"0200000002d258900f935bedc7a4acee84ae81b21dc0a5f71843b4ea8fcbf2d8729c0648770000000000ffffffff43aea9dd7b1ee4e1596b3dd7fc7fab0bb15e1803e98548dea71c6e5e82a961640100000001abac9878390165a1d00400000000046a53636550cab24c\", \"525263ab\", 0, 209661239, \"ff9a37120f90b5e696685521d16e71cafba5d6367361eef9ddff7d98db71b390\"],\n    [\"0000000004178a9fe5ecc8b4c8e27cd61c87e00cec16a4305ce3805aa03864c647bac62d4401000000020065ffffffffc8d4ddfe45b3097e958201c1c43f542f0df8a7c00750b7544602cabe9c2a19a8030000000400520052ffffffffada95f9e2c63f74bd60b3716bd5c9a1545b70ca2f6717021afe52da4629c8d9c000000000153ffffffffe13287f3b56d23daf22e74d584047bae006e89729998ce32783f1997c48f16ba02000000056aab52ac52784c4d9003d5a065050000000002ab000840f60400000000040063abab8eaef203000000000600516552526300000000\", \"535365ac\", 2, 997272453, \"1d4352547da1683e2f268ff992176aee17e93ff16c82457d691446f2670a0542\"],\n    [\"0400000003240678f716df12f0174cc36f90ee290b607969014c1b11dd4b1947f10029e9a10100000000ffffffff47743d25484bec665baf23b40afca10b0ff9003aa05c5fe4128c43f59eb90c2e020000000351ab63ffffffff65d0152c846be423a2f5b706f7be8a6291aea136c89accc9fca3b827c4cba404010000000565526300525ec225df022456e3040000000009ab6551ac6363005263c61ec2030000000005526363535200000000\", \"6aab5365ab\", 1, -443444777, \"e65dfee14740f2b83faa3f926c7b9224f265f20c208c36a6c9ae436988101f29\"],\n    [\"03000000041104daedcd427b579e857f80adade2f9fdd30ddd2831625a7f111f5ed85b75f202000000005c8d28ae8087b071b38a79c266e91f9aaf3957ab954b8955e8515ad4fb3c0514d23ed9de0000000008ac006a6a6a52ac00fffffffffcbb117c5b4a5c981623967149a58cebe3094e06213e3f23de6df0ab998653bf0100000007ac5100abacacacffffffffb0eb07a99546ce35ce09514be6bc34081f813e72d018bb2f6626e8040335b44303000000026a6510722667036f821c020000000000a200df010000000001ab87257e02000000000651ac0051ab5183ed8d97\", \"5300\", 0, 2125740914, \"e4a2c8460290f0b743b080f3d48ff06ab5c80052f0624c8f798a0d69bba7a3fa\"],\n    [\"020000000261ca8baebc96e5bc4587ba2f386407b340fb2fb9263148f33351869ca2572ed30000000009526363ac636a536a65db1ed1265907c14adc2e21afad57798b09a4972048cd206a6c5a1f5e87813a204b7399060100000008abab515263535363bb50045b02ff21ea0200000000095353ab006a0051ac65599ea3040000000000c21a9de0\", \"6a6365\", 0, -1817138246, \"180905b96bc8fcc53523d91de6f17def4d0724871956f1b3de2d3f637b0886f2\"],\n    [\"040000000229c7d6f0481badba5f94ff9081b1e3253764522a4e55844dd33c732e77e5e0c50200000008abac655251ab53abffffffff7ed9eb7cb6e8caef288051ee9de55dd0c599ed023fc2e4fad800838edf7819670000000000ffffffff010f5310050000000002ab5100000000\", \"abac5152005300\", 1, 803443906, \"00f4f5974fa650a7a54ed48124b72d8085554402cff7ae61419443f217357b9a\"],\n    [\"010000000360c1039a8b30f06ef28632ba5e55ca6c32f7951d9631e3ac7e61c59f4a907d870300000004525252512034b5294fa717b350eb4c6be4336f28109e8ebe690b8e460f5f63bac58d2f033f9dba540000000003ab6a00ffffffff5a38b039f635f42ac3f23c5962ca05002ddeb02fbf3395ebb7e67965f45f095b00000000050063ab5165ffffffff035c24310000000000040063ac6a4ecd85040000000007ac6563ab63656ac6d83f040000000002ab6a1628c2db\", \"005165acab6aac\", 2, 1236649411, \"83d06112280b21a7fb3d09ddea1b133df75ae382ec1669422f43d2a07fcb6ec3\"],\n    [\"040000000212a5a23574313fb78c4dc03cf3f46944ead701ff07085ca0328f81f6f343443b02000000040051636582e8ee1cdf11c2ed8056bc8aba71814cebaa3bdf555eed70ed5eaa80cb9f1e9314d8a95402000000045165ac52ffffffff04ab0f790100000000090051655251006a6aab88379b020000000005ab00635352ab9499020000000003525252200c9a00000000000097322eee\", \"655100ab5363\", 0, 1365857284, \"12bd4b2977dd1a315851dd4ed761e06f245e01a68fc3f5334337747b0262ba4a\"],\n    [\"0300000004903c6a9082132ca2b0b62854ea976df2914d201317dedc2d69aa2be433e44ab303000000026a65ab93bbd15f6576971ead99259f0a68214a0c071a2ace2d03df75f43fa9018621cfcc0bc6010000000263ab6987652608c428c47ca477e4a3867f481cffb7b79dc48d5663785a74451ae727a94a050801000000096a00acab5163526a6ac8ae0215e151571b7c74f103610c50a2ebad7e87eb114bc695192d9f0be20dfccc0e1f1a0200000002ac51ffffffff0167cbf202000000000851535100536a516abda2d259\", \"6a00ac656351\", 1, -1432045577, \"5d373e621b4fa5d45b9fbae3ba807c5856a7462b8856986e7ee8e6f88e708ed1\"],\n    [\"0400000004330ced1cb1795de01ef2fd3846ea440b4abdcf18b4fb4bf90c30aa035fd7633b0000000000ffffffff351d87063c3a486f5bf27b1c794560b8d5ead6d56d457e0fd8181befec0b468e030000000151ffffffff21e65c1db76d863e3a9984b0719453ca17d3de72d1a519f32595be0b68db4ccc020000000952536aac53ac51ab63b4870ded4e2789e62070cd7e784e987e10f6c0ef35b407090601782be3df6293ea50f74500000000076a63ab65536a63ffffffff04e40ce300000000000070405802000000000100a2275b020000000007ab526a6551ac63e37ee403000000000253ac0ae65f26\", \"52\", 3, -1931330123, \"0d842076544f278b1a38b68b08309807db40671be0e124bbc50a0c9d9e37e38f\"],\n    [\"0300000002011a2b018166950d2cf0bde93f3dc762f6465079c663c99286e3ef95b11a1095030000000074d0ac2ccdff29def6e83f5c35a8d8c38b9f83f769bec9c645a2e9eb5b0233c53047b6f6030000000952006300abab52ac51d9429d28016f9d9901000000000865ab6a525351510000000000\", \"ab6a51516a52ac\", 0, 1034358689, \"fc79d37e73e5eae02f4ab8ad9f50b15e80d650b12031ae9c37162fe2d8bd8d47\"],\n    [\"020000000353f6e94f3bb4516e2d1eb08f54ed3c05b992581ca784cced633120f160fa7fcd0200000006abac00acacab09e3f9315038932819842e0570931a9eb4013b3ee1f067bb43f96b4be63b2c9d185b01180200000000ffffffffc9463509dc15b04d8d5c8cd66ffcf90fa925074122221eb3c3df2031c2674cd402000000007c8d666e04f70f8a010000000002ac6a0aafe2020000000005acacab5263dfeb75050000000001637b0fc3020000000001ac56ed4dff\", \"00635363536a5365ac\", 2, -1889185611, \"25f15ab80db21e8358158dd25ffca56c49c3a40f7f534313dadbdc2175529039\"],\n    [\"0400000001897554bb01210cd136329cd5079d170ce0e689c2fea8861fd49bc894427dedd90200000001abffffffff04da2013010000000001abb23ae50500000000045353acacb6135c0500000000055352ab6a65ad61a6040000000008ab00ab6300abab5300000000\", \"6aab6aab65\", 0, -1101491878, \"c8212d706d5bc6485119f5b24db84402ca0efc137f005e890e34a97926f4732e\"],\n    [\"03000000032aa492fe6b9350cee9b49d1cbe4b2ba9dfb2968af66681c959db8fd539b2bdd50100000002ab51ffffffff1e03153b85db7ba6da3096e7ce1fac7d37732399f0a2a0c2f7b8e96238777b4f0000000003650053ffffffff5987b92869e831bf277567d032c315d2a86faacdce6d64b67c7e1ea192865323030000000951abacac5351535200ffffffff01fdd8c80100000000015100000000\", \"006352ab536a6a00ab\", 2, 655383728, \"e04edb713fedceada4bf483c2fb93dab97f219b1d3c2f4c35335a9f2b53ad7d0\"],\n    [\"0100000001dd074d3d707ad9f99e23c469669356f58fee2cb794de90dc0f81b1b1922b8be8000000000651ab636a63abf24e4024019a59ac000000000002526516892c59\", \"ab\", 0, -338535507, \"8c123344aa68e770392061c6ae953df159d65475365e1873686b45be5ff6d4a0\"],\n    [\"0300000004c9edf551e93b62e42b2c084de247f6c5733cf48bd4663aafa978fde5196d3ad80300000005ab6aab5365ffffffff8f1bd646ffbb50c57c12b73389f7723a901a8f14a256781f889f7da2f2554c760200000001acf2cf624bcf5f80834f665dad815a9d672b08c24b8d433d637ab61ca42e06ca53a98c286703000000066553acab51acffffffff1d92bc348deb655f1127f3751cd0eed27530083ebaad1b7c85831c5ef0228c10000000000765ac52ab515100ffffffff04d655180400000000065253abac5163ef9583050000000006515353ab510088901c0500000000056352ab6a637e085905000000000852526352ab52005100000000\", \"53635165\", 0, 1492021541, \"f8e9daf348d7810eddd4ba9e85d655f892511d54797653fe6f549566c1000d60\"],\n    [\"03000000042f2c5987e9e7c7d3740a15122c43d8ec0539377ba031a4ef26c86de879729339030000000200630c249ab009689ea229cfdf771c868212947ad5f958ceb0b536a357eda209e4c45cf9b7ba03000000036a006368db02794fbe044a58f7c52bcf6725d92ecc94ec6ddbafe9b847402566b905bb5e23bcbf00000000066aababac536360080065e0b32f0a22a951fd82e389dcd3fc9bab91e03561b70ffba47b5cb2a7815a256e02000000095252ac65525152acab6cd9648802a5163b03000000000853ac6a53ab5352006fc4b7020000000008ac65ac51005352638cd5e618\", \"00ab6a5163ab\", 2, -371743823, \"79f1f4850867aac9536efeff263bd76c8191b904b38bc266db578d206d87d594\"],\n    [\"010000000375375e789d8671d1f0baa235fb76581ecce386ee0c0762790f1a0fafff8eb7de010000000900656a6a63ac515152ffffffff5de6a910d9cf50689fc5eccdb18348d07b893560e80015b24daed8ac159cef6003000000096a5353536a53ac5352ffffffffdc10dd7b011d7c0839ae4c01aac91e33c8aac772cbb449a49267cf355150e7930000000000ffffffff024c473501000000000652ab63acab6ab64e95050000000001abcdcbddaa\", \"\", 2, -1171086434, \"ded098578251987a3b203aad985ca6376a930b7ceedf89ebd4436e01c41fef39\"],\n    [\"0400000003662763ff9a8053aca28a4e16a306d3409571dd3c41a4266d65b2282e8140818c030000000565ac536565ffffffff17a09976c58812e3ef27767be9710dbb6630614d2d73bfcbee270247b542bf7902000000056aac6a0063ffffffff6cecbc70ad06c09beb7985a6bc86daa638b7cafa6bcf2d0254682b5dc4cdde51030000000152ffffffff0318c062000000000000337d41010000000004516a65ab4db227040000000002ab6500000000\", \"\", 1, 7024552, \"b0f5513f721e6f08dade6cebcf160e7d7e62efc6d7bcf22147354e587bb11c17\"],\n    [\"000000000473cc8e76838e3acba83d676e54f11bd8af812f437d97f6304946ece9976e327301000000026353ffffffff53e295b5208e908bee9a0bf530c5c93f85d3d0167489d43cb42f41a5daebcbce0200000002630007a828b88db0fc133d14b014a7431699643259fdb2d4d120c727c984c8cb3e520e9918e6030000000853656a5252630053ffffffffcdff36b6aa2b28511a91870f9e42b9ae191a5605a545f535bd8db71b5d12c0c402000000025252ffffffff01cca0a0020000000000eadba622\", \"00\", 0, 1403517296, \"dbfb48c70261c1353d8ad97591e859a653c1d818f8c4c2d8214c428f69eb32c2\"],\n    [\"0400000004c4b7c1cc45954194fa8ab9f0b19530a2859a4615c2c7eefd8371a770b3ba15350300000008ab0065526aab6351ffffffff43ee1adc1031859e9203881f667d010df88e808b67460e9d630efa6a9d9c7d59030000000663ac63ac63ab4fefa356f12b33d726bf8af8288892eac2fc3b81c5885ac52506a270b8ff5f8c5d4cdaf0010000000152ffffffff31e2ddd6f39f2936ea61fab1a2d01a74801096fedc1f5519829106ff31e137ff0300000009525263ac6aac006a00bf6157cd0119d3ac00000000000000000000\", \"\", 1, -1905281536, \"c71c8482ee614912b872c22dbcd1ecf74119eb9e5f32479f7846124798506f04\"],\n    [\"020000000427b133040e75979fd8173bd7c509241c8f052312b1b242d08da1fd03ec00b4bf030000000251abffffffff1bee988ca1491458441bbb0d81ac4de7a82e713c120c9862db543097918b481e0200000000ca613f481e7fd37b0cd413418b9d83f8876b4cfc09811ffe5d874142ff9e716897b13a3f030000000363abab8832bd4cf2c3a8d323a46ab47bb0701c5d2213e21bf3442d1e71572c438a3fe1391cd5160300000000ffffffff04028eb4020000000001ab06573403000000000263ac5362ef000000000007006353530053654a47dd0200000000020052f7da4588\", \"abab006565acab51\", 0, -2146793360, \"8b121bcfd0644d0216ea6152d98ce049b42b083c6bbdf8dec1e825fc8a67154f\"],\n    [\"0000002002124911b511c4110ee70aff503a0c7bbf9486f5848df083750de0b7419588a0ec01000000046aac6351ffffffff614a577f2c7cc0dd0b35fe9d6876886670989e6af7d519c6882bcb2e9849d49803000000036351acb4f82d0d04ad0b04040000000004006a656548940305000000000853abac5151ababace7f32900000000000352ac6a61cd00040000000004006a52aba6b29243\", \"52005300ab\", 1, 277082916, \"661215810cf9747fe0c2d4839b2732f0efa2d1ae14e052693c5d689ed982d35f\"],\n    [\"010000000252297d204cd123aea398ecfdb10778ee72448caef87e2705cb0edd41059b11230300000009ab526a52abacab00abffffffff14d59a885e29fb3306fc95e7b69930553409b27ed2fb63cd954e7c17c0596d4e000000000953ac6aac5300510051d265ccc10430131b0400000000007ca19d03000000000451526a6a1cb7b3000000000006656a00515252ae6e190500000000046365535200000000\", \"ab00ab536a\", 0, -335419888, \"a6d1898a173d5ab661276f1b3c90ae2d1a2a52a36eaa0f41b1ff34a334f2fbc6\"],\n    [\"0300000003b80e51e0e3a7ee5a32d5d2018ce279081412f82f2adc2572ec76fe0a76969aa103000000070051ac65ac5263ee1823a839b61ec254ffdd22357c79ab0da375af3d6cab74792ceca6750feef92bf3a5080200000006006a51ab636affffffff9f5cad661cd1b5e62d6aaf7356a35373d2edc728faa3d2b33b9ae56f83b9243800000000026500ffffffff04120753030000000001531eec48000000000000c4c2400300000000086500abac006553aca503c5040000000002005200000000\", \"51516363\", 1, 183523785, \"7e36aa8b299d7d25b20af527486a7eda2d70449a5de3b1185a91ffe7285b732e\"],\n    [\"0100000001efd0bc6957b8c1705c03c7d5466e01a95b0a9fc3712293c24a10866d886cd27201000000095352006a6352ab5363ffffffff04ba6c9d05000000000565526a6365c0fd9503000000000653510000ab0019f02b00000000000263ab35cccc020000000009ab6a53636a00ac65ab697d89a3\", \"51abac5263ab\", 0, -438145626, \"509413e0c0c5a1133e02b896d17ba28c83ef45caad903076948e305af064af5e\"],\n    [\"0100000001a65a580ebf0a0b7e963fc900e405f88051957f698f6a3cc708fd6ea51c39ddb500000000056aac636a51ffffffff044e61330400000000076a636a6a6500ace83f680200000000026a6a32024f000000000003656a53b84fe9010000000002655100000000\", \"6a52\", 0, -1924442106, \"343cce2fd4eadb0c60b1e38a425bf32d24f473005849d0ce3460b2f5621b2a97\"],\n    [\"000000200312ea6dea46eb70aadcad64572224e068784691fc87c5e10ccbc5dd06f9c49d6701000000086a516363ac6aac6affffffff61ac5bc55a0e530762277a9dccda1e11ea46c0a8dff619cbe9d206a35fc258f603000000085100516a65535253ffffffff197f906e7efa336113687a3fbc4a7b4382bf02a5218b2db1a627d9d20abb90300000000002656554e9aa100152638704000000000151cb1dbe7c\", \"5100ac6a\", 0, -4270056, \"47de0ac0e4da187a86dda04fb91b827239e8246c6a51a54126b3b28294629eb0\"],\n    [\"010000000136a817d858412aaca3eb0ef3fee26e7628560a90499b60f255caa8175f93bd3c0200000006515165005200687e230401bb8c3c0300000000015100000000\", \"ab6365\", 0, 614377671, \"e7a2a6a19f0886c41a39694ed0e1fd34c1a21c7fb9431208e99e669861a3d0d8\"],\n    [\"02000000042a2d9f4703b9fcf77c807b60b061ee07cf813e90aaa64bb08bfd7182e909d41a000000000353535173e3a534797cb2557270cbe2f93d9810a205d006cfe53a37a3c011da8a9254bd1419c0ff0100000003ac0051ffffffffd423b2a56c3b3cd32fec1701ff02e09e6aa0c4803b1f65bd30759ba330f97288010000000553656aacac074c97bdb9043750255af1a0757c6dbb057f5af2b4547d4150afc107d026d85093512c660100000000a89da34b01901fbe040000000001ac0605a3a2\", \"630065ac52ab63abac\", 1, 1525246669, \"f7b9e632bd5816625e921dc22977179726d17598548dccfdf8eec0fe4685dd66\"],\n    [\"0000002004a8e29eee02a35a274ec22a183ba621381f6c97fd887741c59c8e29f707a15e720200000002ab5163081b3aca0c69a4278afb6457bbd3f1d51602603c664021c2c8fbb956dd3bb941b808160300000004acac6a00ffffffffbc555cabfaa744b19bc8765d4582a0497f17fe6ccacc2e4954f23cd01efdc78f020000000552ac516a516d489220223168f229897c244bd72e3552214f0e5fbc3331063affb00bf2a87d3029c43a0000000007655163005363ab18b63a94046b786505000000000351ab638ed30e020000000001acb1f8c8020000000009510051656553ac6a6af68e1c03000000000300ac0000000000\", \"536553ac6aac\", 3, -1318234568, \"5ea11fb6b96a5762fa5896f01ccce1dab9baef8f916018038afddb242579c63a\"],\n    [\"020000000196030d2aab9e890ec2c467150b2e79e8382e3bb59a2ad63859d839732a240737000000000451510000ffffffff015579cf05000000000000000000\", \"6a6a0051525165\", 0, -1060657695, \"80b10c2f457e0ee30240d185eb4a8ff60c7254394e0570d54bb47b6d081ebdf1\"],\n    [\"0000000003fec712f8434a4bd064a8f595a025746205a221772c678c6c4fd54b6e992b96f402000000026a00fffffffffcbe70aa9c74b10032f05f7d4731c33d917ad3392a0a4a969590468a384f8320010000000453536aacb4a36b480fe293c0df3aaec67fe486459cf911dd3f3db6a80e2c7da75e5432d8f24b016803000000076aab6500acac65ffffffff02df171e020000000007525100516a5365ce71f20200000000085165526a5151ac636a0a1491\", \"abac006a6a515163\", 1, -871022492, \"e784adf69a32c2c86127242f8833c2e305401163d809848d1079490db5951d23\"],\n    [\"040000000107458a3df5311c0e02a310446c367f370fa9c3ae5889e261e9607159ab09b9af0000000000836a841902b54949020000000006516a536a6552c722910500000000015200000000\", \"51ab5165\", 0, 758645353, \"09bb6921f09bc3a945d5a39a719e619f1f79acf53c7995c4c9c6433e41591550\"],\n    [\"030000000241a66a7a88d04e4234f85d5360dee8df2d6aabf9e88e5ee518573c35455e395701000000010045c7aa9f794b32a31c20e1501cb345b091c7e8b465d942a433021ab6befcf4e0ee2adf55030000000465516a65ffffffff03bda27f0300000000008881c40200000000076a53ab515300511e81fd00000000000663ab51ab005210b0aa5f\", \"5365515152006a\", 1, -463532791, \"e3c3982f3ab7d0fa938e97b9667967f3f2f9eb49664c75923787a23b3bd5d40d\"],\n    [\"000000000219d5314f6a0b0283cd4c81d869c21f8f832dac7e788fdff8c59d1e416aebf6db0200000004ab635351ffffffff8a2f5a346939f4b0025e214961dbfd792a613e8fba275eae2946ada737c67d9900000000075253ac5152525367251f100215e1f303000000000463ab00008bc708020000000009acab5165acab6a000000000000\", \"52\", 0, 981393344, \"4dfcfa273de8604b9e8dc6a99c2a4b93b6afb2bd3716ee7646446f128eacfc9d\"],\n    [\"00000020048992033dbc17ab15f9691d59553a618cf8307a3c66b3d50114a973b3ce53d9f5020000000400006563b8c636fafb87c9c139251d7ce1fc51f5ca63ba59162496fb1bac3ffb7fe39b390acccc8c0200000007ab526552ac6a63ffffffff2349cd87ad8a86670790e09f1a8093382d36ea2b2cbe2af54caa7230aad8703e0300000006516a006a005194781fd3532344896c47ae96d1e2a94779c543270ae9a01388d2c8b081b01ef9ce2c2cc802000000026aabffffffff03fdc35203000000000863ab52516a630053ec9d6603000000000665535163520069439301000000000565525263516e944db9\", \"65ac53ac\", 1, 1645025274, \"be3b1d3d0e29fb77bbb5b3df486b717d2dec2b0059993c38771a55fe04ea5ec9\"],\n    [\"0300000001856b2a18b1af22c5d818f5883c5f6f2ff21f53489cd97eb15919809bfa9e481b0300000002ab63bfa7fde7010ed883020000000000bcf835fe\", \"ab6300636300ab6352\", 0, -784335481, \"d762bb07660b6078f21375a999a422538835cfd00c02efac93dbbb0a09e90c81\"],\n    [\"03000000026e9c6ebfe0fd02b7e052dd64875db19d2ed8165f8397420603c7f908982870b101000000007f693fab444e474f0f07abeafa5f189d0d3e026e81588ca5ad3d2a2838454d76cec3f9800000000000ffffffff02e5c55f0300000000066a5153acab6a82da9001000000000552ab0065ab00000000\", \"ab\", 1, -1001043165, \"ea35111cd63865a73b7ef5108d8ecae120bf63f79d20c6e5c06987120fb40a9f\"],\n    [\"0100000004548817cc898a5d3be66a39695f0b826e10110ecfc0e4e3c1a6b68900a80cad9701000000045352536530e0a49732696db927153e52b681207b5a4c483d5c59224af9e705799204047ae9f82e4b030000000463630065ffffffffa16a6302fd23fe4c213c925db6a2dedf1f7f1431b9b7f26abd17611a87affe0802000000025200ffffffff43b86a569cc7371d21553fee0e4590293c80211260f4c74bc2921f8a85eaa6120100000009536aab6a65ac530000ffffffff0171336c04000000000013990621\", \"65ac5151ab52\", 2, -951450516, \"4b120599c72ebf91105f9e07954f1ca3b0a17c60433387a3ccdfbca1bcfc95cd\"],\n    [\"03000000011cd9333ec776671473732862e7e474cdcdb303711088dc9ae01bbb5cbb7c58670200000000ffffffff01ff0c1e00000000000253007bad51a3\", \"\", 0, 2103220171, \"113ac4e3fbb231661722fd8dfd57387be281419893ed8e414af2f39890526e01\"],\n    [\"04000000018b63b039a2ed7d691c5ae1875376c743991116ce2d7cab39df81e09a264afe1b030000000751ab5265006363ffffffff0236d6c8040000000006656563636a529a0f7c0500000000066a63acac516ad46f1c7d\", \"ac526351526a0065\", 0, -2093048649, \"fe77e864d492533f3e31b640bece015e57736ecec78aa5959dde21a15487632a\"],\n    [\"0100000001599dcb6736afb9924540054e3895054eccab5fa25b8199c502af5e6c29d2dc8a0100000008655100635253ab52c7075b9a021c7d79020000000009636552636353ab656a6e831502000000000365006500000000\", \"6a5100abac63515300\", 0, -1157299062, \"1471b1c39d53af98da26440a80657c4876b7f3e2727425b08217144476110a94\"],\n    [\"00000020042ca848b29a80fe21f2e2e78ddbfa906137580457a9268f3d32e0af15992bccbe020000000865ac52635365ac53e26b2067728fcabd9b865f69ce24d9ed4885ea625488caddd30273866552f6ecd49ac2ae01000000046aab52ab48e57282cccce676463163676846ef7ae32011402a98374b6958f6c9a1aaec93abfb2b550000000009ac6a53526aacacab6affffffff157fc8953d7b596a1c515266cf2d3b6319561856194cea6bbec74b07cc9c8a6300000000040000ab52e8988031046bfce2040000000006abac63516a6346b9df02000000000751ac63abab6a6a758a760200000000085153abac535265ac0a0d8d0400000000095265ac52006363515200000000\", \"65ac63\", 3, 1713934986, \"9deb70baa04394ef61401c4be2dc7a8f7ee4048a5e84202c3f470c95ae6f6aed\"],\n    [\"0400000003635d7e42a890757e545ac2080b03b2a736982b4220ab28786bbbe235f2b5926e000000000763ac6565ac65acffffffffb02d2d9d8e1613ef3c38a1ccc7a47e6ba6c9bbfeb447473af8b173173ee90ca00100000005ac5252656ad077a8301b3d7ebaee66c490433313206ae516daf442d19a3f19d3933b6a708f49ec8a280300000005ab655365526fafaa0d0395f8d5040000000009ac0052acac53535100f6a7a20300000000076500ab6a6352531eb5f50500000000096a6a0000ab5100656a00000000\", \"\", 0, 1833443036, \"692d120e191927a34b133a1891c014d8db5d55a1982ef137933d037fc09dc06b\"],\n    [\"0000002002d64ff5e7222abc75d196a648598384df7f8dbe3010fa269192c9e99685fa940e02000000046553abac783fde465cd2146b9559c50c43926922d887b18c132cf37d5ff363447cc5665b9f2a977c02000000075263526a51656affffffff03dd1aa001000000000163a71907020000000008ac000000ac5265ab01b66a0500000000076365655351656300000000\", \"53ab53\", 1, -1401212107, \"2f5dd4a2c07b8768c28ed03d0a1422748e0cd239fcd0dcf409b775f603fed7b2\"],\n    [\"02000000046a07a68da0981a2c96231ddb3a3ff90a844063f67dc061019cbf07cf32ed43990000000000ffffffffd220bc8146b364290356867d8b3d867bd1517ab833de2f28db3ee8679bd9a9d50200000000ffffffff03e713e82ebe1e09161123f9bb7ef50ec78ec782d5003f441098bb91690a9eef010000000165ffffffff72938dea60622b606a27da48bd718e9280b134813ae277bb5c767d724502eb9201000000095151ab005200000052ffffffff0396b95e02000000000851636a6a515153abd98be705000000000153216b9f000000000008526a655163acab0000000000\", \"ac5152530053ac52\", 3, -1681146609, \"8f5a43dc6b310d38c8cfd861fac2b35e5bf742c98ae7079d6c0693a798764fb1\"],\n    [\"000000000426164d0beee62e52d00d49cf79de75eedc50db5ba9ec871baa559a5beec5d0970100000006ac656a6a53acfffffffff5ad6b0ee5d16289eade2e9afae937449a928b6ce0c98d2239dc297583aaa3be020000000465005253ffffffff1d8a6f0f984dfed798c9f7edebc055131467808e50361ad3ad8e416f2a58511601000000025353ad793c52a0aee6d7b493496916e052e6ca7043446abf155b29315bb2a2b91e0e1a848f4f030000000652656a0063531cef45410382c6e6050000000008656353ab6a51ac52e0f81a020000000004ac515151bfa8440300000000056a6500655100000000\", \"52ac0051ac5363\", 2, 1247966294, \"a0030b144aed7e763f2deb52c5c6eb8edc8304c9113e8a21d8046d76d1bb2b69\"],\n    [\"0400000003120738968c1136c3c36e8e75d70e9f44221081d9affa8e6c47469133d45087500300000003515253620da71d40df893f32b593ad54e9c7b22e0b7336fa3f0494a26607f2d4c85f341095cd55010000000963526a52ac65ac6352ffffffff9c3a931e4ada921ffcf7606f7f541a50a30ef82e688ff1977709e0b274ee7f3b010000000863650000ab6a00631d83162c03d452fb010000000002ab6a90131a02000000000600abacab656ae7c68e050000000009ab65005153ab52525100000000\", \"5265\", 2, -781294807, \"c90617affc678a6093628c26c69330aecd733b31d293fe36b70844f9e0b0b3fc\"],\n    [\"000000200205158daf1772a95be84036f1cca4e95ac1899b49988ac75b221883c8952a341600000000036a6a51ffffffff0ce03c96292c0daf635a7f5a7f7bd37045a794883908c811ba43affb271d376202000000065100006a0052ffffffff02a461b60500000000036551abbeb459020000000003ac52ab00000000\", \"65abab\", 1, -211640927, \"bc74d98f514ddc56437aa11027a821695d51debeedffc73e050831cc6f0bfad3\"],\n    [\"0100000003c3f3c2b7edd743c2938ae2df2fadb3905733b0f174bef656eb0b474a2be7543b0300000009ac6a5351005351526afffffffffe1e553486b1ec27d968f06b4296dfab4d5228faa453b25a7b3a85c83de322990200000002acab72ee78e356b3c25205de4307fef2a111d208dfd61c33579a2f9dac865c887ed3a7e91df20200000002ac526b532ab8021eb5580100000000026a533e082904000000000352ab0000000000\", \"ac52\", 1, -2134828455, \"67b81dbb6da0ec8835dacf82190bd4701993b4a7c8637cf568e2d4fbcdfe08ec\"],\n    [\"010000000387b06973d970bbc90cac7a46ad79b00300c977539712f0fde63397707822b66702000000065200ababac53b80440140ca9a36d8e678211d87e6ba494e24f548e013e420e9a38be43af050fa2fdb9df0200000001abfb9c2e7fa2cc62498710f7c9022936e512558c9a9437dc5ed2543324cc01a908754f4eae000000000153ffffffff0468eb6404000000000353516593648c0300000000076a006a6a00005121f216020000000002acac5bc81603000000000753635263526aacbb741dee\", \"6a515353ac6553abac\", 0, -1779082987, \"37003e514e72cecf3ba55b1fe5843b0b20e88fb215cdd78c47ac3a0a5b48d0aa\"],\n    [\"0000002003f0d42a3ce13432432dc83be206ff5f641529f82769b011aa66d541e9b25cf93f01000000086aacab6a6363ac63c48b7f15f08030e680fc385671c1d6c03920099e070660c6fbb78238cc80ad2e6f27d3a00100000000ffffffff4cee44b0827653bf7b1bc2e2f4c4f7fe7005c0f7f641d62432e5c1ee94ff91080200000004535100ab1f64926e019ae1a4000000000002535300000000\", \"005363656a630051\", 0, -21713862, \"f32730ee40a567d41bb832dd6c50d31901ab992f7a0fe374bccd9ced6269cafd\"],\n    [\"0000002003b05f1c5e09effd208b748b0f3a8ad87abf082d663bb50b7e477a81bbd5e073160300000003535252ffffffff05a10bfa725bb2df0fb5af4d45c2de7443e49a5651b20253ced4ad64fea8362d0000000005ac6a536353ffffffff0e5a9f93aa9afe45db750d8d3940d64e7e0b8c43f1a8cd2acf472fa2ea22722d0300000002520062c0ea2c0397a601030000000007516a5252ac52520c8e22020000000007636565ac6365000be8990500000000026352783cafb8\", \"53006500526a5265\", 0, -469759831, \"8834dd6289e081ebc62ebecf640d5632de20325f54ab7f99c87a32d389cc0f67\"],\n    [\"03000000011d2a6e7bd97ea167135e0c76a9a88e24395f29f719aad0d174c5a31c0fe6d87901000000085351ac00ac65006affffffff01bb3ab1030000000001ac00000000\", \"ab52abac5265ac6a\", 0, -487172633, \"7dc73ad9b9964497b7f72236ae3e9b3e01c9387ff357d2aee70b99e724250daa\"],\n    [\"0000002004286da2e5832f9a3290f6191277398a2a9b82b055c38437d3cb66c8d1612778bf0200000003ac52005a590a2971fec597bfa18ddf447029d395404831ada836a9d2f9545015531211ee0f0e8b0000000005ab63006a51ffffffffb5be18816651e329a95902fac79601ccf25af7d20147e02e521e59640d18f3390100000002ab51ffffffff8485e5b933690344b988d2da14b21630a231bac1d88a452f0618576cfc075c6e030000000652acac526552834fe1c3041f96d605000000000752ac5351ac65536f913603000000000463ac65653e1cf00100000000005f8cf30000000000016300000000\", \"acacabab63ac63\", 2, -309282015, \"9f8bf22ae3f9cb51ab8ded46ecc87418ae956c14c8772139900021a73e4d1ba7\"],\n    [\"00000000032f476be5cff7f768ffc2fe400a9d7f1673fe01cad87a87227c9e78497a00d8d30300000000ffffffff63d1024ddf9c646278be8c11a3895c619e808c9fb123f79eb6d3ca9bf888ef8a01000000086a53520065ab65511f01173cf9a4cbb11f1514c8819d98eecff78ea0dae6048302f825c821ee81c70d4ecb94000000000800abac516363655330023a7801485ef203000000000652ac53526a6500000000\", \"5152ab00\", 1, -460842764, \"e09d743e33d94fddbbf9af99f8b3a76c07365d6dd390ebb12a1a30aacc64e40e\"],\n    [\"04000000049854feca1f4d2b0d950156c948228fedd8896fca78851e3bf5f97ec86a33905a0300000007656a005251acacffffffff9ad2eed6e7e7b8f582e4f3e01ac283e41777e411e6e782bd10eea46a31d46f11000000000952525200ac00630051ffffffffbc0582d3bf21ce17853d9649943daa0b64527d4d033dd571e32c7cae1b0063910200000007ac65ab5165ab6affffffff979735b1b1177509ddb2795ae209ccb7c12519f9c2271cf4205247a077a0e273000000000965636aab65515365abffffffff031023a60300000000086365516aacac53532c9acd05000000000553005153ab66aa710200000000086500ab6a636aacac5656ff01\", \"51006a63656a\", 3, 481835937, \"97f51adef79080108562b8258435156616c921c304d7f473e8e613ab15f6c744\"],\n    [\"01000000042cec2e2f401912ec838c25c81086625ac6208ef7bde435e2ceb7942e8527cc990200000009656a0000abab65ac63ffffffffdd066da5ef1d2a7889986c41e04495545a3c3449fa8d9d8e2371b28aee362d0b0100000002526affffffff5058c89f8b835bc19d6ccb365be8a68c54f892e05bca6e807396ab00bc18fa00010000000452ab536a85fb0c2202bb5d259456c47002d834d61ab0d5ef7ab0885e3bc5877c0a4e2594f05a946b020000000651ac65ab0000a95e74e803ab4dac01000000000900ac005163635200511c7c4c020000000004ab63ab636c6345000000000005630052656526d1b9b1\", \"\", 2, 1739588702, \"341a41b5acf8223aa3678b62f665d16e259d243c92ffd63d34d6566419de1df9\"],\n    [\"04000000046f210397392a5007ffe68336b9c19d7bf4eeb7d6198afd1cc1798352474d1f4d0300000004656a5200ffffffffd3b7d77a2f754ededc8f74e11f75aaeb22f18f56298bda662f9c4c77927abf050200000008635152ac6a6a6a0037d3e74654e947c9a14ceeda8224c6758c6977cbf2452ce5c1f6f9ae6842150495614f160200000009ac655200635253ac52c26bd4c0278df179548a99cad610eae51a3ab46242e7a9d3def635dcb704feaa47a4b5270100000006ab536aab5251ffffffff01b8b1be00000000000552006a536adf116805\", \"5163656300ac5265\", 2, -570715841, \"efc2b86581be4056657120343c33398edfa1326fd36f7d9c472ef49cc66c6245\"],\n    [\"0000002004d714b92199900144dcb265350b7e1c94b17560d789d27c2baebc30c1aacf184e010000000153ffffffff7ce880c09d3050c63dbe55f38e88073b9ad9d9eec0e2beede16636a3d317d2b0000000000663ac6300536affffffffe1c3bb754039ebfba484928e65bdfffc01683e0703c27961e6c845ccb96f0bd30200000004510053538af1eec856ee2fdee706eb55be0f6a69cb2fd37e2c8fe529876725cf2f9b260e675d1a03010000000551525252537b41470701a473ac020000000006536a51ab6a6500000000\", \"ab65636565\", 3, -1808740399, \"1aa54c63d4a1d2c485f095dd8ec5191a22c376a1711748b8c2aff55ecf1d0694\"],\n    [\"0400000002e1797b32717cdba962411a5889676e09263c85dfd1b52140e675908d34eeafc702000000056353656a632815c24871be700c2c41ceb9555a5dfb4b5cde38a3b9d7e2fb64bf34b44e300ac223eae1030000000039f0b69c03b919340400000000056a535351abc44171040000000006525265abac63d46b1a0300000000086552ac006a5351ab4880d37d\", \"ab\", 0, 760400923, \"1decc7b0db9e920bd0a9dfb3980b6a0f8c27c9be45c7b13f1e933ebe88465fd0\"],\n    [\"0200000002329e9dd71c4b523fd5e44f24071888eaf55f16644824f4101a169a2c7d4de2ec0100000005536a53ac51c3885e01b085e1cb5cbf98db3e822dea8d603499f5c1b465eb6116f0dafdcc077b7965da01000000065163ab53ac52ffffffff044b3dbc020000000006635165ac0051dea91e0400000000076a0052635152ab5e39c5010000000005636aac6552a2dc63030000000002ac6a05d4af80\", \"6353535100acab63ab\", 0, 1545112303, \"f76ee53432d92933ba290301eac6691eb9221f685300fa0ee38bc0dd709d23a7\"],\n    [\"0000000004ea72f55342846bb20eb4a06cd756d2f1e39e37c413d376567c9ac70e9ebf58290200000009655165acac006a6a007e130cccb1452ad59bec5ac60b79133349cbd4de837721e9616f6db4646599a36e4c6e84030000000851000065ab6aac65fffffffffadb67aec4565f0379dd23f0d8546da41a80a0ae4bf5277c96cdccb6e40d6ea30100000001527f27938149afb6c541b89dfc3143b21fc6903663381afdad374cc32c1dc21039de59544303000000066365ababac65e1071f5401c5c935040000000002ac655e132925\", \"6a65ab\", 0, -1496560676, \"9f76d465774c7a59403661cbe77b8ae827e0984e3d0062ccfb692e11b83df422\"],\n    [\"0300000003c15d3a9cb5d1aafc2036d31df97650af80ef8353bc0426e00c30648bbbc2e8ea0300000002ab6587292fd665c69f454f946068e7153507542f8e2fdb1a570fe6870d0a0ecdd7db0fc3b79d0200000001630af8f6c19fed45d21f4a8f46e0f4d8fa6770895786b0e65dd9ab6cfc6d8ec9193b41f3d901000000066a5165516363ffffffff02ba096e000000000008ab6565ac53636a6373b25003000000000553535353534ed4278b\", \"526553\", 2, 758395615, \"fbcc375e4440c537929d0a3570b358885756fed5e0a9310f3f9d3fc6ea57de0d\"],\n    [\"0200000004bf89f9cf28bcc41478cb8cecb97c55cdd1f3cdc25adf1b08eeefb85831973edf030000000865ac65ac656a6a65ffffffffd784e6e88ce940f0966733561556b2f8a8584e0c847879563e78b10f7178d8d201000000066563ab526a6affffffff64e622d45007fe8e224c5ae4857c82a2ef5c3bdb9bbcf99668f76114945e20410100000000ffffffff7d150ef418dd37649958dfea322ff12de93969d4e796d3bce727c25757e5579200000000065152ac535265ffffffff02b9e5950200000000016598f94004000000000653ab00536552bccde4c7\", \"ac\", 0, -1215657787, \"e65e3738b2dd710e71bd719485c65d474723c053d14209331dcdbfe883fd485b\"],\n    [\"02000000044a7b7d56c30e5a1a037ff98fc1ed04e77bab61c777cadb90706db3b420267588030000000751516a63ac536a563fe7ff82f22270c2c4e2ef015b62118b8259d3c4e640d4d6b8b9e8b0e43015ba6b014d020000000452ab6365ffffffffa5fe0eb79c173727f523ae0914db6c14b7874b69013120ef551a0467bb3bec0f0100000008655263ac53516363e9f5bc6040028c6ee3de0e361ca398dcf7f4077b33d003b54c704d0ccb769231377b6799010000000900ab656565ac5200ab0c024ac30301e9d0040000000003005365cf2b7e05000000000651abab636a009178d4030000000005536300656500000000\", \"\", 2, -1852752322, \"42d5e2bbd0881e9d2291a0d4d91f5a084aa6faf6ca911476b19dc12792053868\"],\n    [\"0000002002d734dba7b4a46297e915a10acc5e72493ac85c575c29f4de4ad8295e767afe410300000000a83ad68a734bf5fe7be8ae404652c412fb0946fc475f369349937b0fe459b0a2a90e17310000000000ffffffff026be0e00200000000036a00ab87e5b7000000000001ac00000000\", \"516a\", 0, 784984515, \"7d4f31bd6ab5f1f611464743c6de5213f49d7b091e0e41fd5548a892c40a1cac\"],\n    [\"0100000004b1197f05fe4cbde9abf4f4b8c09c986dde94167a0f9f6a111e1f52f9cfe2f8d202000000046a6aac63ffffffffde0327f93bb407f28391f5c6a0805fb0a6234da8158299ddd0db3b1c727f77640200000007656351ab656a65522fa98c0c3f232341dd38402d1fda355f60e6293e73cc8b64422c680ab203606986f2fa020000000551ab63ababffffffff413125e5362c70f7ea0eb1f41fa95b631f760b48fb1652c8770da220163f13b803000000056aab51ac6a40404d4701b326150100000000016500000000\", \"5165abac5200\", 0, 637068576, \"e405816baf0b44dcdf7d35a52864ab747b1400fe32334aec6f30793b8f94e626\"],\n    [\"0400000004bfd6ec0eeed140fee4f4d3eec70ca159899072d8ec5f0c2492a4ed6f7fa214230100000000ffffffff0bcfd3cf4301614d242df005d55fa97e7266dbc3ef9fa920ad286a42de4209190300000003ac6a00ffffffff4c66dcd711bdd615ef73c6c05babc82ff44b2223c1772405fb34c7d81be7fdac0300000002ab655549e7c2190eb51acd50b68da2a591af4d1b2acc94fa98c6ca9643c0504942dd1a63acb7030000000553abac6a00ffffffff0248589f04000000000353006a4d2da902000000000451515253283a082f\", \"00ac52ab5252\", 1, 1602377387, \"21059e75c9d87d1df1099e0a735ae48a2c38997f0586c479e2f96095117732db\"],\n    [\"00000000011198d05a8a0047f5f886ca660377085615c567aa8b5b8b81a2c94a1a7f6c30d5000000000800526300525352520e3c6526047d75c3000000000009abac006553005353abb9aa5004000000000251acdd799d0100000000003a999805000000000863ac6a53515352ab00000000\", \"6a51516a6552526565\", 0, 463355705, \"2dee75b6b04ca63eb9260730a86de72a5c21e5febcc87f15428a47a8aed5f767\"],\n    [\"0000002004cb844e75a12e437554215b583135e140880a33fd43c37431177185c4b03a78aa01000000076aabac520063ace559acfd07369d5a7ab7c3a418b268caf9d5e1d8b2995da59044e5c4defe56cb76a3bd0e03000000045300636512f4cd8080b29ed3d4c9ed2d80cfe3f7df9ab6d6feb74e952f70d2db9756ee6ea64ffb7c0000000000ffffffff79f25c23db8ea0186c3cb18b64eebfab68085631ea5efcef988e30397c6d8d340000000003630053ffffffff04b1076e050000000009ac6a5352536a6a0053f249ed010000000004525252ac12109000000000000463ab5100808f8c05000000000000000000\", \"\", 0, -563164529, \"d6b2083e9e42bcd5b2d09508b31d40f7d6a04e30446175be7c18b790adfb341e\"],\n    [\"01000000022bfcf5d275ec3580c2c2b6de93b5a61f2ea96fe39c3e42209a9792f8ef9bd1f40000000006005351530063ffffffff38436387428356f72f66be23c5b5ba32969c8e1c8026d3d516b0b608cf76657c0100000001ab93c9e888034b4a5b02000000000663ab636aac51fd134e05000000000763abac51515263975fd8010000000003acac6a00000000\", \"5251516551516353\", 1, -1506099004, \"bef0bdcdef7a77492f7ec7ad788f828aff837040632b316b1b6024692247bd7d\"],\n    [\"040000000402e7d0d09a7453328c9f15f9621903f120f55a61dce71728f61ea2be7b6185ed010000000153ffffffff43b7507f7e0683ab9ffdd55e0db2022e19683b23de5ed7b0c4b2a24cdae8dc90000000000953ab63ac656a6300520eaf574982fb2dce8a15e87f469439c6404d6ab208c10c4591052ec9c402efafd93e88aa00000000076a63ab00656551ffffffff3110830d1addb75613f285ba8e72d6ab80e86d9d3ea094c2bb462ada91dc65d302000000075163526551ac00ffffffff03546e690200000000056352ac63512027cb010000000000efe5e1010000000002ab5200000000\", \"ac6553ac\", 1, -144879503, \"9df72303258286e1dbaa7965e84c3ce6eff8d1bb2e6be9b1a66b984b62c1932b\"],\n    [\"0300000003432f2b685233d951dcf5865890a80ce6b8013cb939a9c8e14cc764da4179b42902000000085253abacab635151ffffffffb5d4ef4025b36418cb24979050c707950ceaea3fd67669e6fdb6acee87a4d5ce01000000096a00ab5351006a5351ffffffff95de192a8d3f9b80762bbe15d93bd117d1cd0df3b44ec845ef8f78e080040486020000000252512748d15604b4c3d904000000000951006353ac635163ab125afc020000000002ac5331cd27020000000003516a6aeb73a3020000000007636553515100538c379e5e\", \"\", 2, -1178099377, \"03f70e804f504e424d4c86b092648e6257184ba991a65a2e7a4e11f8c25e81df\"],\n    [\"0000002002c9da13e47e62354123c7f9d11ae29d11e16b2634f3d963343098d638978cb5cf03000000090051ac526aacac5152ffffffff94f632119b819f231e62bac0c7d5925dcb929c4762433497ec19a1e511b88dff0000000005ab526500527eddc186031c82f102000000000752ac6a000053ace5fc0a00000000000451ab656a64cd7a000000000002ab63ccacec19\", \"\", 1, 1347423884, \"e17758e62c806b557e0d6e7ab26be7d06ea1cba1e786387cc08b84b256a10365\"],\n    [\"0200000004c2ba1f40ff350ecfb5c2f83d733592f4ce085f454314995f1eded09add540ce90300000009acac53ac6352656551ffffffff84f495172e76ed4bea9a85d07db9220d9b30b10c24adbfad075cf6dbea51e92f00000000085265525100536565d2afc7a40a7cecc6463a65935b7912e87bdeccb6180cbe04eac44db844f1382c48eeab9e010000000151185a83c0e01fa8fe306da172e86c659f4aea38dd9399bcba13067cdf94890d890a6d8dfc03000000036565abffffffff02d9185504000000000253ac82db8e0500000000056a516a51ac34c7b6b9\", \"\", 0, -85668685, \"56baab362c4b777891d41d04b8b0dbfc7b14eb0be89745adc4a6a20a97c50952\"],\n    [\"000000000468363640f40ca27b304da40b54f79d4d986268676128615bb3fcc5c81db684a401000000035353531219f9750b796f1fc35d710b1a2a7038a80f8c500a768b6eb80f2afdc0686938bab8fe9a0300000005ab6a6a53aca0ef1b8513dcdd827ee830b480e6abffcc2e4e2aa44882a4d011caec170f8b63aa33459e020000000465ac535221ee1d7b3b6cd4853cad19d91c0f70721de3e5301cb3e5820d285f203e35615526ed654601000000016affffffff02c63328050000000002526577372b0400000000066363ac65000000000000\", \"00536a\", 2, -62883756, \"ed5866197a01a6145c43f8815e25ad4c31609bf3913c5934191289e9e75b4177\"],\n    [\"00000020030a96d9f40a9dac0f4c729d49d9d1672ea3acec6afb701c0688d4fb7d9bd0ac8c030000000200acffffffffc8da0fec2b0a35bbc3a8968745eb183ad1c1f75b4f69ba59d90af883e08ce3df01000000086a6aab526563ab53ae8a1f872346ed4a86ee17d505261f9f0af78859e37e51e4710f16742e47abf196e8a4b8020000000900ab636a006a65ab52ffffffff0252ec4f0000000000065363ac536a633e8b940100000000095153ab006551656a6ac95d56e4\", \"ac63\", 2, -841743427, \"dedf017a63e61b384cb4ed223c4b01108db1dd4e850ff34ef36566f4d87a669e\"],\n    [\"0000002004afb15e64206eafff48a1edf719622a42ec5027859e51f1ec4fd84fafe30e59380200000007525265acab5100ffffffffda6084d522327fe97abc5814aac422e6c8d94757d7f33a6ec9aea211413c5f99000000000451ab52654dc9e27cf331eead1acc34df0b0d05598feba2f0e1a97fc543ee76a9a3500721bbef94b2030000000653510053536a0fa85be76e8c21b8d5285083bdac2f098eef16a334427986fefbce7e1bc1892612d88b45020000000353ac539319a337028aca97050000000003635165677a71000000000005acab6a525300000000\", \"\", 0, 1200062145, \"1546b3b6fcf6776f83a4cf85bc27e70d7a1a6b5ccabed4f900643e70bb98cf3a\"],\n    [\"0200000003121f7e703ffac61c7e74c8c96b2e4da7edb465f9cc56966f2e4c8034b2642c0d00000000065352acabab51ffffffff70a7bb20837406ba718b2555c3439192e197a78501debd10a0ec54882e5f60420200000003516a6affffffff677d55ff2ee1aa544025cf4fe3bdce5eabfbc68e7c63d44c5cde5c4187b155170200000002ac65ffffffff03d92e58040000000004ac51ac63e44ee200000000000074aabd010000000005535265635136b33a60\", \"515163\", 2, -451804387, \"1abe469ddd89b2a1e21daf0acba35869297ae17d63c8313f0319529fb8021148\"],\n    [\"0000002002ee0589a15a2f2a9007d16882c2d8895fd4d58b18d408f3913a6dec67b076469e030000000100ffffffff45b5827695e60558f6289b0a6ec95b895e54ca5ac03f2fa6e67e87a29ad994f60300000000ede9fe44021db4490300000000026365e19f760200000000055263ac63ac00000000\", \"535300abac00\", 0, 828553507, \"a09357c82c7b626dc463e5571217a0898b75741b82bc7392928d1c4270b2f665\"],\n    [\"0000002003513fe00638a213ee0bd56f4e87ab52bf8f50ca6de631058335f53adf20cb9f9703000000000e72c484d7c3727b5c62db46746cdedad0c16103f03ebc697e003cc316dfb03149dbfe270000000008525253acac63acabffffffffc81ddc45bbf855607e5c1e2c40a6432098cf7f2c8c81541468dddbf21fa5ee9a0100000009ac0000ac51ab6a53abffffffff023e3c1c000000000000e74778020000000008510065005163acacb6ec4643\", \"535363005363535300\", 0, 196210525, \"179f288093b6fed849fb268b5c4ebff72e52d36f9873633242e762d305f881ee\"],\n    [\"0100000003e9ba3f34ed2624b003b9980dc4305fdf626cdbf156a1e4eb768bb6a355f4dd82020000000452abab00fffffffff6236b997fa2799e6e4c440751de260c724a2de22b6c5d6d9daaa3ae2da69d7900000000045351ac53ffffffffe548021c0fa41248a22727523a13b14d5c4dcd73acd1d6552ce6c14cd77a275a0300000004536a5165ffffffff0339964c0400000000096a5153abac006565652abf290200000000066565636a526a226c870100000000015300000000\", \"abab53ab53abac52ac\", 1, -1412493017, \"dc07bf150d6737a2b9bf03b1530853d87a93963c848f8912f2a0071d920d7bcf\"],\n    [\"040000000287329ff280e2aa90ff0d0419c2922a43483a635ae25c6c496f4b64283f59cbcc0100000000ffffffff15026700fa1cfac9e9a8ead13eadf36b6f97905878c78f467c631beb7d02a644030000000865abac6a6a5153abaae5f004029e2097030000000000b96bd50400000000004c047e79\", \"ac51650052acab\", 0, -2078463523, \"e62badc1765df6f660c04bab855ca9db7dea33e4e172ef93442a0c63ab5cde20\"],\n    [\"00000020015fe3bbcbc53a9d5d7ec91e1ea5a557c84b3490e4a4f464ff7ff9ecff088df3900000000000d15c724b02922a660200000000096551006a5353ab6a00f191e1010000000002ac6500000000\", \"005252006363\", 0, 1550561065, \"fa473fdb59b4cf23a0b7050f28f85369d024aa231739ccaa304196af308b8283\"],\n    [\"0000002003a5fffd706e23ae3e4068b94da5cb1a14fc408c2c7a6058e12eb55a6413c0428d0200000000ffffffff557e926492263aee338cab70b6bf906502b0ae1269a68fbf544fdc76aab2eb420200000000ffffffff6fc257814ce2ce790f7297321ef00bd13c103c4992b0feb07b2da174854eb3840200000000ffffffff021a017f030000000005536565656a75ca4b020000000008525163536a00526a00000000\", \"53536551\", 1, 1511845429, \"9f08aa1b384cb733a4effccc8734b0bf29bb7e7f56262fdc5f332cabe6ea490b\"],\n    [\"0100000001a9aede3f7065972567aca2c261e380f8ddbbec00e0053c912e8c3a861784e9d60200000006535263acac6ac90e5178038453a001000000000165ce41ed0300000000095153ac635363005200d746000100000000026500ca9b7c93\", \"656aabac65ac65ab51\", 0, -159365505, \"7072b571dea4ad7ee72d87002a04efe34309a2eef9db195f17eaecffb5ebe3f7\"],\n    [\"0400000001f18d932f097381115d493af480f49ae8fa6e00140d535435a4489c466b56ab8900000000065300526565acffffffff03b43b4e0500000000035300536ae8800500000000003228cc0200000000026a6518161013\", \"6a65\", 0, 2135444286, \"a12d85463a215edfb4f51c9f3835268605a4cc4ec071c27075313607c2d52619\"],\n    [\"00000020035a058326fbf1005f87e7939fda2886206f7b7ff37ea8ab2f48e7ab208765ec91000000000752ac53530063ab2e539324c28f58065526deba6455ae122f80e53802ce3b7a601d2a48b29268f895276e3c000000000400ab6351ffffffff79a75345e77727a4aee6b9d0ada732450c4b50299392b6c9a5c1deecbf938a6e030000000953535163ab65ab0052d13002c6018aa6f804000000000552526351acc6c99a74\", \"63ac6a5251ab51\", 2, -1534616140, \"cb61a9412d3f4f1ea636d83be55034bc7289983fe1db22a754952f42fca8821a\"],\n    [\"0000000003e102890766e989a684fea10e1ba07d54b7910d91a83299fd7ba1ee3d5892344402000000056553ab636584abab3f2cdff2e5eea99fa2d7721365744b9a874a07b9309947b3a0729c252afa85e0bc0100000009006a6552ab6a65acac67ffa365775434bd2e7f7a86360f1ec15d09a122927816a71b5e330427f50a2fd8bb4e7001000000045252ac008cfe7b58035c0fc5030000000007ab5151ab51656304b15f050000000005006a6a6a6a577d7a00000000000000000000\", \"6a00\", 2, 972177997, \"d858f0d6565019550daaab8b501f3d570db3f853968c7fd98640f60e6d51908e\"],\n    [\"000000200434a118565a3f0ff752290b48ea01c882b40949da3b65ee8e58e80e7be8fe0a2d03000000056352ac5152321c80b867ebdc0e8ce46b2a148a7a0fc9b64643d0c032f645618cdeeab900d52f85e800020000000451515353ffffffff8e6fedfcb98b93ad7a5821bf22b292dadb61ca9655c0c2f5664ee89a28c170b50300000000ffffffff565e5260cfdd3dfc2180bceebb2ad6369c59de78f5d30ad5d11462eb7721148a0200000002ac65ffffffff0272c9ef0500000000076551ab6352536518ee48050000000004ac525351a8c1aeaf\", \"abacab6a\", 1, 905881319, \"3f3fdaf6ff04912b987edfb016acfe3c48ac81ed212cf028d6a9e024df2ee8cb\"],\n    [\"000000200217bd1af30913cdad5d7709e1f721b905bde5d0e3ac12ef9b489ca0b57b36953d0000000006656365005252ffffffffcec365d79654334b05cccee4c164bab2d140193e6aaec4d14f194fe1774aae3a000000000252007d224ae702a379340300000000096aab6a6a000053536568415201000000000000000000\", \"ab65\", 0, -1321649925, \"5239b9aff5567efee9792375b77440de2946096c6d094b57a1508f407bb292e1\"],\n    [\"01000000019fbd399a2a087b7aa47bf6780c19e694c6db43cf6c45f95de584c91971a22f6601000000080000006365ac00633384e0dd0381a56e05000000000465ac65ac8db9f0000000000006535153526365d1829a05000000000653ab53ab51ac78247083\", \"acab650051ab\", 0, -1313391907, \"9fec60d0bf5b5ca5202888dfb3e1ccc1e54fab69bc3629b8534409e470d667be\"],\n    [\"0200000004d9e52a53621e230c5f1656df033123fd9e167803c389fba42ef8670d7c885e49010000000953655251ab0063655102bbd82fec05baf5687552f1b2f37be03d23011277713208259c5b87ea46eb1f99c3a0bf030000000563ac6a5165ffffffff3336a5fdaea61cc35cd60ed77230c65c8a7a8d3266e550a473b7445cee5927e10100000000ffffffffec82fd6c542ddb123b6e977587953a5f357c885af79fd9a067f277e315406f3000000000086a6a6a00acab656acd6665aa0303543d0500000000026a520da82d01000000000663536a6a51ac5e7c05050000000003636351b349ca15\", \"63\", 3, 1678129701, \"2d812bbd260aac78a6239727d49f42383e0129878caa3d9632c91a88c5acd084\"],\n    [\"04000000039567a6b33bf11837ee35f1abca67a21980a4fe895f85b42e7e3b1bc46186395e030000000651006500525145c02fc89c0f1a8159cbac3959af6b945a38a4c05f74bbbf7418d62b20f9b2f4506132ba0000000009655251ab6365ab63acffffffffff93ce2e6ffa8a7d5fb1b9e92f668ab15d03eca42687f3d06b1bae884186d712010000000952536553ab53acab657fdd01100395b00204000000000363525288fb36010000000005536aababacc384690100000000045165635100000000\", \"\", 2, -1855661610, \"e7d454ab80f12ab52d5d4b7e4640354c8c75e2348bc5a48e4613a55baa9afd54\"],\n    [\"010000000277e4400f3eaffa98e5c83a7adec33924a0b2dff87267c15f63b7ccc368801dbb0300000005516553ab52fffffffff78e7a23c6060949eb8710e3db1c2eac417968ac5d41617edf3ca4bd5419724f03000000025152aa17c639021c302a02000000000152bd7783000000000007ac5252acab6a6a2ff4219d\", \"5151ac65ab5263acac\", 1, -1900171293, \"29b79422bee89a22c99cca3cf17f9869ca0a270b9933ea209a8514ac22d99e8a\"],\n    [\"02000000047d2cabe6fc947bc6e66f588ffebf9797cb6118a755f5e912983b7f26f8463f410300000006ac536300655342d225c13e1231b50f0f63499fe610d34690e9b44541b9e36b88b6e3fee5a0bcf70b5fb100000000036a5352c7d85487c9d1464f6f39bd5a1150fbe304323272ca090a4fb40df5deb982e300055f313d030000000353ab52724db990d858f07714c6b7539ac764d9f5487bd1cafbcc827fc94f9ce9d545bcc1145be702000000046553ababffffffff038341cb010000000004516a6a6390633205000000000100b153200200000000055265516aab00000000\", \"ac5353ac00535252ac\", 0, -662017229, \"1fbb479dcda8afd982059637993bc5cb3fbaa220289fcf16f61b7aa7ac31d4c9\"],\n    [\"0400000001dbd63beb673b1d7f05ff8dc032c7707519640566eaefa03e2e60782c397812b20000000000ffffffff019511da01000000000300ac5200000000\", \"ab6300ab6a516a5200\", 0, 916295121, \"179bac250080e6579eff50f16313f5474489f134639421f402ed9c5165cbb331\"],\n    [\"03000000041ac588ea1ad1bfbd21eff8204a473cdee915e9bf3cfa7b0c0c66b874a1afb19a010000000800acab6a536a0000319434fe57238fcabd1b3fe8603cd28749649e358dac8440a2697ff4ec363e7f1e736d2f0200000004ab53ab528de62fea8a9531094d4298e519146ab8dba8f919b46ed0f3b1a51e03f87c454f61e0b6ec02000000085200006a6351ab65ffffffff3d5e570f9f3ac8accc46610d33470bd0d605761002c9df1e78e738caaa0e70e00100000000e75de972029b36050300000000056a63656553005d1602000000000453ac65533fb5bd2f\", \"0000ac63ac00\", 3, 1718801485, \"e2f9ecfc76c8e97bb83c29b25187daf5236baa54858f4cf55dc18437584eb57b\"],\n    [\"01000000038df3866d57b0593404e067a511db45e3d2616f6f85733e87cbeb31240d5f045e010000000751630065acac65ffffffff5b62e7bda5e949a7544468903f60881fe320054f3762cedd4dff5a58395c6df30200000009535151006aab6a536affffffff1459aafb1f026c9e1bf57f833bf4931a6b48574be7397f7de95c5218b566665b0200000005ab65526a656c1fcc7903f12ef6010000000004ab00abac1576e903000000000665526aab6363bc55af010000000002abac00000000\", \"ab5100536551ab51ab\", 0, -771037570, \"73c410d6b8ba768c86d0ea7167a0f619820104c30d001ca158f2d8f7034386a4\"],\n    [\"0000002004494ecdd987ae9d7c4ead45647c1cd7acb446f4042ca3fe436f1b454d6674df690200000003536353f5b56543347fb2143e8a4f6c803d81bff87b342ce1f8e401b2615fcdda9b589a29b8832801000000070053ac635153abb4d77c35a5ae833c0c6861429aec304c703788990227b5d4c17910d395451b8fbd30e5290000000003515163ffffffffdaf740c598a7d8746f144ef0a95c480e2ffa36b1e9646a42ed1646eae880476c0200000007ac6a65655200acffffffff025a9469030000000006abac0053636a9df1cf020000000004635351ab00000000\", \"52ab6a526a63ab\", 2, -1483842714, \"4a6ed56b896965af944f36d3ab010313cfb40685110da84269d614498676e81a\"],\n    [\"0400000004a90273f448be7834abf991511e19305c8414555855246309f358892a50f5f4a30000000001abffffffffe985f425644df15ee1c4ce02e8bb00792f6267b9d5f6c9ecb67615d1b5c6b9e40200000003636553ffffffff784a68d62d7c999602c8dafde3a8ed505fd1f70196bc8baa108bf066b42255ec02000000076a52536a525353ffffffff9a81360bdb90711ceae83ec8a4cafcdf54c99559e95c2b97b63492c6529919d2010000000753530051635153ffffffff019bf4cd0000000000016a00000000\", \"656a535100acab63\", 3, -940743182, \"4e58de20d9464a6b09b8830195d7d365c63a444ba875c53d1863e4754331e3fc\"],\n    [\"010000000168ba3ac8b55eef4c6768ccc16bcaf167baee071e957d73cec68d5ce0d993b17600000000056353525265ffffffff02e0ac5202000000000763ab516365ab63a2703a0100000000065251ababab6300000000\", \"63ab63\", 0, -2003794612, \"5b67005ef9069e5e94af53149e9a3f585b8525f36a77e7e416b94436d9f7e825\"],\n    [\"0100000004ac411d612557d96e85af3c30e4378deec4bc1efdd998e2e08cfd64610692596002000000056500ac6a00c72141812f40cf5b57fab3ebd20a80eb0fbab73fc396c6a5e8dd2db7e4c6a5252e2bced50300000003acac00ffffffff606b99dc4874d546dfae7c81bb78c24a8bf919ee1fff619b65772a64a415f8ff020000000763ab6a00630065f5bd98152acf9ae0690f3cce75f2b908ef69babb3f25961e299364751f8b34d4d062753902000000036aab6aa9c8466c04c0f23c0300000000075365ac516a52abee9b4b040000000000943e0e0200000000025363e18359000000000008ab53526363516a63596fc448\", \"abab5365ac6363\", 0, -1240320026, \"ac0cf43a995627506938fb43a2790b5378df2c52c6cc1c22ddf73846c3774e06\"],\n    [\"00000000016259a18f5b7f388ce70dd1d0fd681f03d3fac2371b4ebdddcd1d15ab9408345a0200000003636300ffffffff024844bf040000000007ab52ab525251636806c8050000000004abab535323d06307\", \"65acab6a\", 0, 1878903787, \"177140471340dce06838f20f0057207f8f63ff346d23c728609bbe598cf51699\"],\n    [\"0000000003e957c2162d5fa53163fbfd444e846892df6cfbb6f0b557337a40c46aad55466a010000000253652c16b1b89df3f6cd4c8a01b3b742bf0adaa4b0a55f4910a3c09e9d6ca70c6954d1065ce90300000009530051ac6a516aac52c92bb3305340e91a2b60db297b1c4d43ef78796642b2109eec974ee9b897b44c28384b570200000009ac5163ab6a52516300ffffffff010a4a63010000000005ab6aab536500000000\", \"5165\", 1, -1953978125, \"a7bfab40d01bb396543afa64ee5ffcb5d12a4006b9b6f4a9c7eb709b54bff84a\"],\n    [\"0200000003bc5be951aef0c33c2714a9517c326ec42ef421cc058421cd39eba8a676b9327b0300000000ffffffff0f32a591156fedf61f25e5673268a91bffecb249c32a0aab1aaca64972951e870000000008acab636aacab5365ffffffff956411fd54e01acaf0d2f9412ab394736051c690983e2174da083442e794066d0000000003006363ffffffff0348b29f02000000000865ab53ac51656a530195300100000000055300ac5200960198010000000004acac6a65429aa6c7\", \"5351526a\", 1, 2113411003, \"dbcb5f7faa6413f0b7a607503aa47b8f84104bff0fa1e431a814dac8f680f6d1\"],\n    [\"0000000004bbfc68c6674372a14f62ec63c08505461b52aecea4041389a62783ef716e775a030000000965006300535353ac00ffffffffec37ac64a96b295dfa1ac9a96940b53aaf92f4695321de32d8bfd24fe99c5ec900000000060053ac5165ac8176a7081ab81c0d0a2012cb4c53930db5baf57e8919f5f2892624388e936e59609946880300000008ac6a5100abac0063e96aed7dd61bce26a799ed183d24b964b918b4ee270a1207f93c7a38f3b9a816c853bb1e000000000663656365ac52ffffffff02e21e5e0000000000076a6a0052ac530025e8c803000000000000000000\", \"6552656a636300\", 2, -2003550314, \"0cb484e775f5015372e360e31454e3842c98beb73fd6d0f7399fc374d7aee432\"],\n    [\"00000020036b49a4ceba5751605fab47a8aee11fc9b2ebddb94885eacb5dacb71a50d3a05101000000055100ab6363bc6b11b4f95b1c96cd0cad6f41b5d64d5fc7de9c91da5cab2e98623fcb9e9f255e35d591020000000263acf3f3e5471d118026187452e0d4f97386f0fed08b03b70140b90c4c4d55a6458f5540beb10000000004530063657c55a66a0157d36802000000000552ac5153ab00000000\", \"ab63006a\", 2, -75626280, \"422bdb3c69e71b96a13d3e9f531d8984fa8fe5b09082ebdabcc82690225218c0\"],\n    [\"0000002001312ca16396b3b0fc9badd291af481526825d538908d31c2d42a9f211a65a997c000000000151ffffffff03144b7200000000000863536a536a53516568a406050000000000ebadc0010000000007636565635352ac00000000\", \"\", 0, 200211095, \"d3bb1010a7eefa87c85eb02e5a0fbbafcdd110db0bda64586bc97fbd03a4e47a\"],\n    [\"00000020035152e6f7495ba143e56a6495a10e38e30ddee163b3a44b94c8e4b7bc192a50af0000000003abac6affffffff50d31af8f9bd2f18ed8f4e389663d247d150aa89ec70da98f6c41ddfa5031b9f020000000565ab65ac51c40148bb743b4cb19f0508d1d9dcf5c79b119105ff0db0a1fb9d2e03dbeb8082e82054180200000007536351ab53ababffffffff01d3d3b60000000000086a5263acab52655200000000\", \"6a5100\", 0, 2145898971, \"ca3a721dbf5ba1ee83218e157ab6dc25c0e6d68689204b9229b109b6cc7d7109\"],\n    [\"040000000116294aa33702f070e9c4758f93a4bca0a0bbc1cfca91a4458323f725f4c3ae590100000000ffffffff03a1279c0100000000086a53635352655363945a44050000000007005153ac65536500c9880500000000016500000000\", \"53530000\", 0, -1334795560, \"86f42f42789f530728585baf526245a335a0dff7b68f4b324772d7abc498d1cf\"],\n    [\"02000000010a500d73ea2cbf2bccccd40563776788a7204b8e76cfb0fc150093c5272e27c2000000000552ab6a5351ffffffff03a3567d0500000000045163ac6af6d07a040000000000ada668000000000009630053006353ab0000ce06842d\", \"6a65ac52005165\", 0, 501735429, \"bb333a95162193b6505ac3c8bc44e318d26c261ed9c2abea1fd1b85aa46697a7\"],\n    [\"00000000040012b8ce6c2e78abb97834ec21b5de7bcd3da0374d762ed850c02cc3881f3b0e030000000465636553ffffffff27edce00758347a33e2585a7fbcb7ebeff4ac4dff7f980d68895b599c4c9a051000000000151fffffffffc04b7e203174b6863ed262e1991d326734430e206d9a8a928ec16cce037180d0000000000cac71570e2f380640661d7b4a9ffc8d5022cb1764f4dc44693c9862fc856a61dd297070b0000000003ac0053ffffffff02f1ab670500000000086a5152abab0051532fb66502000000000563ac51655100000000\", \"\", 3, 1989943341, \"1178cdc5f94098df282915b7dcad8acc04d20cd580b48f192c4ae1b507d91e97\"],\n    [\"01000000047cd6e356a041806b0dcb7a03cb2958cf3ef26f7d69bc01843823f472cdcc1e6802000000096551ab6aacabab526a140c416b54b26abc08767c9901c4769b08f179eaa78d6bd3eb86618e2fe8b61f9d2ecda703000000036353abffffffff82235fecaad8693b947a1d8c46f6a12eb38b14fbfa767d3aaf92a8ee60b62452030000000763ac6553006563ffffffff5d2e739995532a4c4c6084774b8eaffa84d20589e9949779a3acfd9b6ddae8250300000000ccc02c6d01e2de760000000000008b0fa64d\", \"\", 2, 65228966, \"eb19b233f9bc4f6e4694b5ba44c6ff923e6f699ac6da4b56fd034c70adbcf017\"],\n    [\"030000000305e40467de7a257bff504353a8b2b19894cbb9ac8c7bd157923787f85e631f6b0300000007526aac0000006affffffff5a3cb824e48f344ad461c7cdf2720fcc8a021edf0567cf27a0e5cb73d001c46f0100000007ac0000ab5353ab3e4f4073576b4a92562f12720778058ed0669c4fb7321152800a0b665bd27dc2096f70af000000000951535351ab51635353b8ef1cf7047ca3a90300000000086563635263ac63aba6a0840400000000085163636a0052ac53742420050000000002536331ce130000000000080000ab530053636a00000000\", \"650000\", 1, -1851015503, \"45132c3381c1b13579f89e56d102d6822e4e5be21bbd4c9be9b8a48644f27cce\"],\n    [\"0200000002f5cfe464ae9b6d14016834587e04660c402eea232c0ba6d7904aa49570543ff4020000000553516553abbd9b84ada4be6785e5740c04ece95bfafac44ccb1e80508f455ae676eea4923c14c177b102000000026500ffffffff0377b2a203000000000865526553655252accad9940100000000075153ac5265656a83653b010000000004ac63526500000000\", \"00ac51636a5300ac\", 0, 1464774400, \"57d2f7af7fea62b98f3a540aefe92b237230ff72df04c1315b36abc867f07f78\"],\n    [\"00000000035aec5f7b5bd6a95bc14ca52fe40329bc6f39a825864bc7cadd3d29729c577fb00200000006536363abac00ffffffff1e003c91ba7fe6b7bb11f16c0407b0e7f522a3d05dcfab3deacf4f66c72fff520100000004abac52acffffffff3d4702f96c2774bc332c1b8db3b7c24f96265f40fd7acaacece0a08b0f7bca9f0200000000ffffffff0398188d0400000000070063ab525152637299aa020000000005516300ac51ce948604000000000865ac516551636a6300000000\", \"63ac00635151656a\", 2, 1950484262, \"f29230dff73286bd1be39058bac788061d0757d7c2e85d8136f3296713471ace\"],\n    [\"0400000002112565b734a4d76299865dacb289f30b1440d89e48e0a5c4255ccc1f93a17c1300000000035152521beb0278a6e3a79c2d1983f33cb96ab64ef135b55e65228fb3c053d11df351537a394bd90000000007526352526aab63ffffffff02eedc4c0100000000095100515265636a52631322280500000000056552ab516300000000\", \"65516300526aabab\", 1, 1007196581, \"5f11600bb2f6e374762afbe38842554e3cfaf1bee03052b2cc26f262f0dcaf4d\"],\n    [\"00000020022080d90d2f9b0eea490721485d62cef6685ad09bc79e4404549e0ce9a0457cb40200000006ab5152ab6a6affffffffbfd0daf187c1725e07cf36f19f1335c277ab1f6cae88be4380c5a6b8d0f7aff40300000001513ba8580d03c1702a010000000003acabac3a9348040000000003006aaca3d3ec010000000000891d60ad\", \"6300\", 0, 1956631869, \"649700f4ce1ed67c9cd2c42612191f6fa38eebdf71fc2c3317a01f0df9ac96f0\"],\n    [\"0200000004bf04bc94ed9f5859fa0bcc99df29b3113a799b84ceb3715c84449a0bc87dcf7d0200000005536aac6a656c7e6629cf3f57c2f34299714bd8baac3accc9bb2d52f55397a39897ca39e61018b436cf020000000565ab52ac63ffffffffabccd0ffa69c10884728b79f7e8d4d7751029e4fc5ca89a41c66020a269809a50200000003acac53ffffffff6ffb75200243e18785b54e7d6b1660c94ee076c5a72b2d5dc66864a9027fb04501000000095351ab5165ab5252525edcd37401bb429a00000000000851006353ac52636300000000\", \"\", 2, -337516109, \"c3eb83d1baffeb153467e9e6e86606555f4b2efe59ac8dcc037cdb46b120b56b\"],\n    [\"010000000476651f6b7a22a805bbd5ec3e591a7f1a486cb9f26f1bdd85668b157ccfa72bc902000000056365005151e0b1553c130c58a69c35af73ae566ac176f1ea53913592808225382f01e83b680d8a004f000000000352526affffffffa80bf13335c5106a82912ee77cf656bb1785817c8a94dc081fcc0bfce4e537fc0300000006515263ac53ac7331dc5bdbeec3a0956e6a8f7f5eec9ebb3eb3a2185f640a0cffc5f68d1544c73340af4e020000000163ffffffff01f60e0c050000000009636a6351525363ab51fa6c50ef\", \"5152abac\", 3, 496465291, \"0d3ff5499a1a3f3f6d3ecb56ba96f584f3978eda6acff173183a6c71b5b1b43a\"],\n    [\"01000000043e4feab005cae018fea0cfd9ffc3c6ce782b1af3723391ddf1f49955b3095024000000000047bc8ac80079f015b9d6cbee1d15a56c792e420f3ac408fbd2748f88592afb5326b859f30000000001abffffffff27d9796dba927707b4a31c4aeece8796ca1053f556afd9de9ede73161804c1b9010000000453525251ffffffff85dfd696c752216144bd2e731926c3a5d480609b9b8ff340c33e3ca48f2d90f4010000000263abdfe6235c016560320000000000076aabab51636a005b5424c2\", \"ab\", 0, -1711117315, \"42a7aa271f2742e4cd56e2c2172c950c5c5f0a739ed7acd364b3783e4db8fb72\"],\n    [\"00000020031477492cbec1eb47c88c89e219a4a57ac7417631509bfcf3c158975bb9ecfb1f010000000151fffffffff71298d9f9691440ce890e55b0dbfb76f2fec382912093190e754e7d27b4ef7b0200000009ac65ac515153ac5265f691dfc4af6a1dc693f5cf18aa7c7429c396eaa9fa33d18aea994d7beb62d9378dcc9800000000000600ab51005352ffffffff03a1046d0400000000036a52acc164c20300000000096aab006363acab6a65b3216803000000000400656a5353839cf8\", \"ac655152\", 0, -1782119476, \"bbf02a9bd7779211c832785be700af83788783f3d425cd6f3d6e3c6740084eb5\"],\n    [\"040000000175df4ee2b7ef754a5af338df326a29e68976081a628e5118bc17c17712c40d1801000000096a00ac52536a535251ffffffff03519c6f02000000000753ac63ac0053003721c103000000000452636a6304e42d05000000000652ac6aac6565f99679cc\", \"ab630051ac6552ac6a\", 0, 2054145628, \"5b22757df9f3b22d10901b571a1391bd363880f50be0410b9b53c7b81d02f43a\"],\n    [\"01000000024fe61ad0540e770eaa0a549be19eec452f2c45c02a65c3ba59e08e6c0deacbe20200000008535151526a00ab63de9af74dd58d874328854daf4d759959c49c6be9f5683989c9b5344ba36741b24d644499010000000953ac65005100ab536affffffff03d8c4b304000000000700525265536a65d59a260500000000085352ab52006a63ac37232c050000000009006551ac655253515258b767d1\", \"\", 0, 1962464712, \"2f0788d2c02b2184316b85367ff96d90368c17fbec9454415488feea1c1f4806\"],\n    [\"020000000428ee6513483bd463cc427105c3ad1c8a492657212b86d2a830622d494419ac51030000000552ac51ac511fb05df928ed191490d1496377599c9d828f2516fdde6aeec9810237f6d7b1e613b5329b0200000000ffffffff335019563dee7ea23cf7b65e3e1a24117f249d5e3ed7b755d575b4691aceabed0100000006ac006352ab51ffffffff9c7d03a2e7996c99dc78a7cae9784ccf451401ef574bdedd70f0490f6d4058b703000000020000ffffffff0157d3810400000000086a635200656352ac00000000\", \"52ac636a5263\", 1, -493018865, \"14adfff40ee6701bc36a539a9e1f407969e5b405b5a8b36e282a2afefc105127\"],\n    [\"02000000038fe4278f548717a8ee4eae12e16072d4f7ecf71d28af37dd9c4e62c885f2778f020000000665ab535151ab64a9ea09d1c43738c67533b4826f14162050cca3556ffac5719cea65a7880c9c999236760300000000ffffffff988b4fed66dbd447437b21e6a33be721252eaa90546b139c021c5198e120259f0100000009ab65ab63656351ab00ffffffff0486ee2900000000000963ab63ac526a6552513c9d160000000000016acdadf5040000000007ab63650000ac5254141c0200000000016a4d498085\", \"ab5165526563\", 1, 376720266, \"6f1f6ca0bb6d5447791d23dab187d5dd367565390bee57aa5b911425b58a66a3\"],\n    [\"01000000045ff5741062d009d7b6f52a65bd6c466c3d1d54c5e12ed92d5872ad373b85234f01000000096aac5163ab6565526affffffffe7b9cb8f894e458c505aa4accb4e0cb6a902d74b24fdbe3ece50033acea0a7bb0200000007ac6a65ac53ab000cac7accf5869bcf8c2abd06090833778556c482b8edb77d7b9f95cd18708a24a0b9ceec02000000096a6a65516a00ac6a52980c10a688cf61c48be5a702c78ae0707948244d7bb0e3ace6a27aab97052292c16175640300000003006a53ffffffff040d1e83010000000006ab00ab65ab651f71d801000000000600536a00656ad514d7010000000009630063ab526365ac6a668dc30300000000046553526300000000\", \"ac\", 1, 284371556, \"1ba1adc09be9f6c639da90fca64339f57ce5b0b58c79802430b36df06b453088\"],\n    [\"040000000305efbea92dfc54abeaee2b8c4159ba64d4f74a4dbb2058e6dc4dfcc7cb6bfcdd010000000763006363656563ffffffff2c6b8d593be6add3fe6caf8508bc9388c60c88e4294085d2e35110196a42402100000000065300ac650000ffffffffd4332583fdfbcee927a3aac4297cb42acbb61cc6f57e0cb304e99e4ab4aea80d010000000463650051ffffffff0199b818030000000002636500000000\", \"51\", 1, -400789716, \"bf197dadeba954ffd2203cef356da7ef94487976792d479cb68c7f8b0a961155\"],\n    [\"00000020028222ce7238f5b681c208de2bd5917a4647b7d5157839f8d1042b3b96ad0c26d5000000000031812170c9a844ca907d83cfde125204f3249586b4ea0faa4543dc4cd31c0255b0f1c643030000000151ffffffff02810cfc0200000000086a53ac51525352009748270400000000026300c29a809a\", \"\", 0, 1610914618, \"21ad9659d8e31f9d384d44616db7005d976a06cb5fd3c59a53681114dc58db74\"],\n    [\"010000000180bc60950898f3bc4a27e7fe60f07ee864460c83a4c29ed52655988829df87cc0000000002ac51ffffffff0364aa4b02000000000852006a516a6353abaadf81020000000004ab526a5345d8b301000000000000000000\", \"5151\", 0, 434209734, \"8c22ddd7df2dbd0b0095e93ced4ae8e80b585227614e711305ac79541a17855c\"],\n    [\"010000000291105d8603d06c8a3e4294b77c40f1374778d2b8d0f46fd8b457af9b8f0396020100000005ab5353656affffffff3be06de34fc3a2267749a78bd137f4cb05cda6ef15ef9c97c40125851be904230300000002ab636c8f7bb502cd275b010000000000c93d9e05000000000000000000\", \"ac\", 1, -412440036, \"39e8f94b97df55b486233697ecaa6cd05f7c9d9e208622367bc88114c09b6c0a\"],\n    [\"0300000004a8fc859927b85ed9ce5bc289af705e1b732263fe9904c7e2505ea10827c5ca3001000000096a6a526300ac526a6affffffff9be3c44ee428fc904c81db30fd59802ee6d17c65fe00fb97c64653f079f23f0103000000086500006a00655165ffffffff3f6d62fa0f2b3455329f5d720f2b53faa5c73d0732bdf3dcdc87568bf936176e000000000453ab5353ffffffffe3f2be8f64213424c113cdeb6cd3f2b5b7da538b250535050ab1d4bef3da3bd40300000003ab52abffffffff02819b890400000000025353d613c90100000000085165006363ab656a00000000\", \"ac655352ac0065ac\", 1, -724004311, \"11b33d9de3aaff89633825c45e18b5dbc2007cb78ffa22d89952eba0f09bbf9c\"],\n    [\"000000200116425156236e170295d97eb602caad0b95fa5f619eba8a7c8df277757b5fb0ee01000000085165ab51ac53ac00cc94229d0117365e0100000000045352005300000000\", \"51ab\", 0, -1890324266, \"cf361e6fc25ed80145b24d100db279856bb2f821afc59f3bc0d29efceaabeff7\"],\n    [\"0400000003ac5f3e6936af47c4ed99b5e652a7139a5fbe92bddac6b6695c2307c2131b8fef0200000000bb1fbe34cf08a7969ab43aaf30a2edbb07749e7ae122b4c997939f18273393f6753aab5c020000000200acffffffff8b35664fd39ba611ad0ae5b5b344010e24260e4a30dc341d7d000aea34a801b80200000009ac51526a6363acacab0be369e602ff6b8a05000000000200ac08e90e01000000000263ab00000000\", \"ab5263516a636a\", 0, -1405195703, \"838fd9556131695ed06ab5b604b7063eb5f801743b3bfcd1dd8dd7e5f13894ac\"],\n    [\"0300000001ddcbcd3d683424090b770437cc44385ec99a34154e70c9ab8b9d05ee8af3a9820200000003536565ffffffff04dd9fe404000000000800ab510063ab5153fa6a5f050000000009ab6a6a635353ac6a63859d360300000000085251ac00535153abdfa2b4020000000008526a63ab6351ab5345c52398\", \"abab635351\", 0, -893055566, \"20b10411677024efe1f3d9bb4f8d79d7f8b842e2769289e85fbf67c0c376dd5b\"],\n    [\"0200000003eee3e2396f6c4a0bb8180a86226f17fb85e9c7e00f5e53265597969c26356ed3020000000652006565ab6affffffff9892b685011d80ec6bb5e3adb3f64919722a326e87865b4691d0c70b566646a00100000005acab51ab52ffffffffd5471e453c7339c7612672cdffd0ad40c291d6a3e54b9fd4f7c3e1d2776241570000000000ffffffff010354c00500000000046500ab514c600ada\", \"\", 0, -619837411, \"04468a53746fe421bdd7cfede1e925c94e658810d43180a258cf6e7a9a81dc8d\"],\n    [\"0400000003225a5319a0cbdf988131f51fab7abca6eec7467de95dde728c20ad9d32c30ee0020000000352526affffffffdd6043e4f270bb7733b3d9592069e5458fa81920abeea78e2a6130976d2c004e0000000001ac70f7621ab05000b8db873727fe3b7ff54f357245eacd1750f70a07719967fd26f1d1a34c02000000085363ab65ac515152d7cee17702bc06fe040000000006536363ab516a553f820400000000076a53006aab5151885593c8\", \"636551abab53\", 1, 1138373823, \"0d6ab1177667d7381649138aee5fac240eff7892580398b5bce5ed2c589131b1\"],\n    [\"0200000004aa6e9e05967d348be142e34e498b65a0646ff4bc19f4d1f6bac1854e5d0b5e7402000000056a51ab53acffffffff967b0fcfb87bba1cb582e8b6d3a77daf1597cf38b15ccdd22bdc83f06e6785de010000000800ab6a6551536365f68e27ae2b95b78f6f2fbea08a1f31f969464615b66387574a94f43d3bbc685f69a3075b0300000002536362b71a5a9b891495a0069fbf27f2eb2c8e422757f1861e7f15f21aba4f480f8344240c550100000009ab525252acacacab65ffffffff025d40920500000000055251655151acbd2102000000000865656a65636aab003d3bdd2a\", \"ab63ac65\", 1, 1237563824, \"490cdfb74b6bb3b4cb4446373dcce707d71cbd65128534d5ea5e0a928e09a612\"],\n    [\"0400000002964cff217578236050d2ef177dc4f2678de5a87b0dcb50443012fc7b0b07fa5e0300000008ab516a65ababac53c921ce52a293598bafac8bcc9411bf6d7d327b393ce4007411011627cc5cab77ea9ef1c30100000006ac52005200acffffffff01a5fad10500000000086552526a5151ac5100000000\", \"\", 1, -671371533, \"1211fb7a2a433528940f5fcf4069aad9dff700296703c884f3aa899b1839bb50\"],\n    [\"0000002003d57bacb794cdee3e119b40a1b50305afc0e327b1f6b1aeec99befabbd9150def0000000002006affffffff7d0b025f679b63fb3d0001647bdb3592ea2a8b8287ad7187b8f666cf8b538c5c02000000016affffffff1ebe0cb6c2c0cab59acdfaf3d89a27c81f8541586f0f65e69ee2f8ac904b7a260000000005ac6a006a52ffffffff02af7390050000000007526352acac0063a586f10100000000065252526a63653453d4ed\", \"53006a65abab536563\", 1, -1489728578, \"9539e04ad5c61d972a7d298e046edcbcfa4c844e6e65333404ee19d658f6cb02\"],\n    [\"01000000014de443fee098cbff872122a9475958ee06660cdbe860c7f46b941929870311460300000001636768159f012c9a7a0200000000056a006a5263d20ba815\", \"52636a\", 0, -992411709, \"a5a7d67b635d210838cf7aa73470a836362a1e694c15ab9acb08c30873596c0c\"],\n    [\"0200000004a3d50dcab7bbd0b21597e1e24146dc71ed7dce225d99a573b6b9404df8a4ac24010000000552ab6aab00f4ae72cf517d5e798bbdaaedd44596e4859b48834e85e0e0ea87c1ba79310c12c2c813c30200000005ab6aacac6abfdc7405e6be2e92048226e60c6d3591fd883d9ac9e7b7f67ae4311648eb270eb78575500300000009ab536aac6a52656552ffffffffe80beee1e61fb70193307e8d5fe04ec81c547a090de22e2d43d18c6469cc0a0f0100000001524b1e78ba0331e7cf0400000000035200abd8446402000000000351ac537d72e00200000000086a52ac00006a005100000000\", \"0052ac\", 2, 698442413, \"e146ab044e76750d25919923094ad4a4a9b9e5c10f29fa2af601c7f340a6a64d\"],\n    [\"02000000033254d97825fd27faa3410a84db4455ec502c275d5a04cb750c6ac8e65c3258c701000000026565fffffffff19c392696dabc8512b8d5ba2361b5c03340f6aea220e1069a21df914888443f0300000004515365524258a74a62f5d2b32e5867ba04ccb32065246b0344309fc6c0d83e45f48c6d0c80bdb90f0100000000dbf5d8820427e9c3030000000009525300005300ac0051b6f881010000000001ab40af3d01000000000165b74daf020000000000cef758c3\", \"6351\", 0, -980734630, \"6be4f31942e145be82955fe7933018f63c3c342a3960caf1847657b51a1e5668\"],\n    [\"040000000121f56784fab7b54d76252bef025bb682d3988914343a060bdada5f5b7736e2c40200000002636503d0e1b80302532b0000000000075153005353005261edf0020000000001acfd257103000000000651abab655153a9999aa1\", \"636a6552526353\", 0, -1018253477, \"f14f28ee7f5f8dc57c647de89c1e3fdf7d6dc204f8a75245af819d4f8aa35930\"],\n    [\"00000020018f1b95353a52ea4613f5278aa34ab641a716710491903ca13f551e5ae0d772270000000004526a0000ffffffff0262830000000000000551526553510c955f050000000002536380bbd8de\", \"0063ac65ac63630053\", 0, -836927400, \"d65309436a0195d35c900eaaa1f0ea5fc861951976abb987aa780dfc0ac774a4\"],\n    [\"04000000015b287698c3f4c42c9d5fbf29baf7049d629faa2437959d6f4c2e523b3fcf22fe0200000008acacab51ab6353acffffffff03ff67b30300000000066a006a53ab52b03fb9020000000003ab636a70de0005000000000452ac6552a8576b74\", \"\", 0, 543366495, \"26c998bd6368f3a3d9274641d37f2870ed63788e18d51e70fcb342cff2980aca\"],\n    [\"0200000002caf7a8cd021fbdb09cb95bdcc7dafa0fc814ce4ce0038164e45533c3dbadecdd00000000095352ac6363ab006aacffffffff9ba97584693129385c1fc0861989f890a549b58ff4309f14e95ab97ed9acfd8000000000004fccd946030aa6b5020000000004ab52acab7b7d7d020000000009656aab636565006300d8bf8105000000000000000000\", \"6352526353\", 1, 186172317, \"94ac5200c85cebdc6785a17cb52798611b1b113fb199e3918021b2ba13f00fe3\"],\n    [\"0400000004eb56bc53f657df7c4c1e21b4d030c56cfeab1953c17bdbcae5bda4efc17ac3eb010000000151ffffffff96811763eeb4a5ad329c365d193c0baa9a0c60b480255778e24530991e5fe38b0200000000a45397811eadf45a172f1bed441d5fbe853d7164005616be635f59b6cb427da19be2013f010000000153cfa695cd2cc37766be6158832c9ca5c0e4799bbb55a2389e2803966c263022ecdb38d6d7030000000852636a6a6aac6aab12ca2ca5044f236303000000000453ac51ac4c94c1030000000004525163ab701aa000000000000152e0623f00000000000000000000\", \"5263\", 2, 139085559, \"298abac646da305bf16b20d286c8f9a04818c7ab230647fbcffd60939c5398f5\"],\n    [\"04000000036a6fb904b60eee8bb6b5ad6cf3788d69b1afee5749d200930f52b4cb25f802a20000000005656553516affffffff66671dca2bb8ad2e74c26dcc500e6ff2f089246a0b9dc807764d60a6e0847e120100000009006a5252ab655363abbce9f97e49650bbee9da16dc41a380e265993e8fa6d6080365cd57565337897589a4219c0300000000e21ca8ae01b27d80040000000009ac515253526a63ab63f35bce93\", \"6aac65536a656a65\", 1, 1505835905, \"83b56254f4abdaeb5712fc4e8862597b31fd4db4da51a12105f1b88f77ef30f0\"],\n    [\"04000000024b8b1b53fbe5aef008544e0321adf98371964dba745c672d5986a5e87734bfcc020000000565ab6a5163ffffffffcdfb56dabc808764e3bacfc4a99880ed7d01956f9c91237510e4570ed0d0b1df02000000035263651a61aefb012cbf7c0300000000065251525265ab00000000\", \"\", 0, 700872511, \"8c550b2dbcb78977dae50f5e8b3de8ae71cf1a35c5968f87e21b8c645db34c7e\"],\n    [\"03000000037ab92dbaf556ff881f5470267874df4061d78d6716eb9c239e15663a553e020e0100000000ffffffff841c1346f4385016b5dfc8a5a5f53315bd344378cf4ab3bfa7854af5cd69ad400200000007ab536a6a65636381d30255f9c46f53aecb374538dee8dca15124e13a3b178abe62f403cb01ac12339852fd03000000085165ab5165510053ffffffff0399185f02000000000033d01d04000000000500656551ab8c1bee0300000000008156940f\", \"5252006353ac63ab00\", 2, 637616886, \"bd6b4e1698edc7f29b0a48dd1c87c3f5afca67b4b1fd26e3ea02bd8d40072999\"],\n    [\"020000000470b19c444ded43806df9587147d0c9aa2cd63d20f8cf282db06a19058aa133a3020000000400006a536aa1b9fc684e4e2680aff60f878b38efea02e47bc6da7f608e59f15d14a3d8b6ae669008020000000253abffffffffcb50c192004665271c6e196043c6a3539299fee4b48c668cdc7274eb035e758401000000016affffffffdcb5d429add369daa4a36bb646886a38e3edf3d925f5bd678aa7a16000ae1f9503000000003c224593021fa24104000000000463abac6397f64501000000000451ac6a6300000000\", \"6351ac526a51ab5353\", 2, 1442567149, \"2e2bac596346c0f8dd64fb42c63cd381f5b96581180682f0bccab91c5d8c6a05\"],\n    [\"0200000003737352e0a132fbce728cefaa195b75e23d04250c6b93bdcfac903b1ebf99b4ae000000000453526565ffffffff70fb380b1eb07a86675c363d70b259bccc78ba226ccb52aa01cfde89151bbedb0100000008005165ab6365ab65ffffffff16262b7c4c681a6b63707ad5098c906c65ed6f0d54ab3241e5ecdf50c13fa50401000000056aac655152d43ae8af02becc6f03000000000700656a5300ac6360e261050000000002000000000000\", \"63006a\", 0, 1188630257, \"8656da49a86f3d7ac64ce7b3128a917026394023513c348f27d0249fadfeff3f\"],\n    [\"02000000020d52c53a1ac5bcbfbd0a44148cb8fcbd4e40d06e46c7607f5085462f75eb950e02000000025200ffffffff9516000d95cda1b66b502fd77c2c647c3df6a125cda6fef37b08f0d4e61018dd0100000009536aab00ac00636500798c508e0218cfab020000000000695f31050000000005ac6a636aab00000000\", \"65ab6aac51536a6500\", 0, 1999783218, \"a6a6eebb3c01704121e6c495567d1d932944b3a326a9a3e8dfac8798268c7d65\"],\n    [\"0000000003b4971a556811f618f0c5e1c25400d8f96e65e38404a71aa52f0fd91ae28e9c56020000000153ffffffffd7bd3eafda5f4baaec965891dacbe3a6740c251ec4fa00868c8cce53b81205860200000009ab0052ab5200636a00dc50717b040b35072e48c111e7ea7ec2f8a4526d804e6de6e386c928ce52aada84b649bc030000000865ac0052ac6a53528afa25aa01e318b80400000000016a00000000\", \"5253acac006553ac65\", 2, 257288757, \"372cecafceafdd8ee1e4cdf98bbd3eb4c7371c74f40acec2f93345f6ba92393c\"],\n    [\"0000000001f0fa1449b761cd5d4507d77b14ab5762795354cebbbfa70c0e54708937c640eb0200000004abab6551ffffffff0293a92c0100000000065152650053ac0e66940100000000056563536365be854acf\", \"ac6363526a\", 0, 1772420187, \"b355881964e09438542bb96fe9c735c2ba25a72b1928fd26852f56d0eec68b39\"],\n    [\"0400000002c570b9f3c5e515cec3f55b4a46f64a18966655b2a48bd79d1d23f901324b3a31030000000451635300a5c3741233c7eb85edb271da6c61e2ea4e86d1d3c1a8deb198b5042575f16e66e6d63f98030000000251655871f4a304bbb986030000000003ab65639a911c040000000003006a00f025d205000000000800515252ac526a00d6ad5801000000000000000000\", \"ab5300\", 1, -377595099, \"83322865171c87a0f5805192eca326e3db6ad989ed87e19c8be6e60d249cf750\"],\n    [\"0200000004360476f25c736afa9a87fe4b305d6b63d6a585138e57a5d25eed3ff039002a9e000000000465525153496d04d0230d0d1ae969aae26218b36f240348b6cb4b6f91353136dc33e4d4b914d26c4f010000000165ffffffff4df83111a3dfe5a7d1cead661f599e427bd1a6697fa30ac69e8f4d1c2efa3e61020000000351ababcdb4c9146c4a05917150a7a90700d0938d6d7d694c1359017307748735e3a0710749216d0300000004536a6a51ffffffff0121601a0300000000076365530053636a00000000\", \"63ab00acab\", 3, -1940658737, \"cd3e6895df6edfdbfbcd5245d8479934db18c5b6be17f6b6d611fc525824fe0e\"],\n    [\"0200000003b6c3f9de487d6f273683795f025ad06bcd56fd14196eee46ddad0b129f7ec0aa020000000263acea104b936b96087ad1d5bdb1af80f6c834823d0360d1938c1d34ede828cda6b2da0b6d330200000000ffffffff85ae1e1e1596b72165fbf434fd37976767bc7a9c0a45fb871bba9f03d165fa3a0200000008516a51acab51ac65a8916c47017eb1390500000000046a53ab6a00000000\", \"51005100ac00ac\", 1, -1209796128, \"c4a3fce304aab7b5a874ddd0ec684223f895f94849002d1ee2baa99c04b5c02c\"],\n    [\"0200000002c276a77b9b3d29cb602bac0b544184bf6df27335f0d5c441f9d555fe5737d8bb0000000008526352536aab53abffffffff961dea001bf3e4644c55e5aed4a057acace69f21b6e9cb053c86e6ef3c70cca20300000009ac63ac530051ac6500ffffffff03e812ae000000000009526363ab00ac5200522d015404000000000400656a53bbb78003000000000653535251ababd3f021bd\", \"530063536aabac\", 1, -1796988747, \"7a4b6e31ae801e792fa6c2e16585747901b642b19e5ce77844de9bb3e5814476\"],\n    [\"0400000003ba618d1cfd637974cac7f8d3780e41724763d6c1fd13b7709849af9bd6a5f1c10100000004ac635353873b573b72a644653044b522d6e27aec78294604923098460996ec39a6c82d5d5da37da4020000000663abac006a0066d420d0acdadd4337641f3f77b64b6a29c3fa4fb65a150e8844fd608eb3431150b0aacf03000000016affffffff01ae6686050000000009005265acacabacacac00000000\", \"516a\", 1, -1806822386, \"2cb1d1e5b5f93d230719764860e0745cb63b277f38696d1c9dec7ea6a2287f5c\"],\n    [\"0400000003b23fa8f39be005f5d5b5aedf7116eb7e224301be5316efb49a027f3bcadf5d310000000009ab516351ac52abac63ffffffffc1d86ea594f382ebf31e1c20ae5b5260663e0f73f2723182add73621cd5c9428020000000663656a6a00acffffffff58f1ec896ed4c555a4a6439b70583187342542fdde7fc0c3dae7206512d12bee0000000009636a635151536a0052604e1074047b42d6030000000007656a5365005165f69457050000000005ab65006a637e41a7050000000002006a2612ef050000000002656a00000000\", \"0065ab65ac6a\", 0, -891265487, \"966bf4caaf6b388356595778dcb7143cef031dfa175504080897f5e7debc41e2\"],\n    [\"0400000003d5ebbd60b3163e7741348b706de136824d4d42a643342ceb31c141527003a0050200000005ab00ac63537706305e93ecc15aa00aa784b96e987f0b43c360d2415bb8f317bf12abbb460287ea9608020000000553526552ab4754b9ff61f59cef52ab829d0bbf175d763bff64d3e69e94eda0866119e5980457eb3d750300000005ab6551636ae5aa70780326c43203000000000665ac6565ab5342662705000000000353006575aa91040000000006536aab63abac47fe0831\", \"536a5351ac65ab5163\", 1, -1779947022, \"e0a03b62b7fabd12d26ce32f63cf9f32ab96b2859306c08628769642aa6e016b\"],\n    [\"0000000004301a5932960e67dbcdab085e8b12e40f70f17fb3c443a2e70258caeae9754f8d01000000045252acacfe81d505f1d8e23ab28d2b6636587d46eb2fa9c2ec9f1a8e5a4a8fb1180da14ca00ff0ba00000000025252ab5f8c6263637264408e13de37089dbd8344887e8e030f95a9fbaa9800e31a6d2bff56ba02000000096a53ac6a51635352002efcf9a96705300033d04cbc0a490eb411bf8841064f7beb1f81e94acbda8d119ee87a43020000000163ffffffff03cdb444000000000005005152536ad6f12a0200000000095352515263ac636aac453a99010000000007006352655352631c2f2430\", \"00\", 0, 658232395, \"e77919b78b2358f75b3d1eef8b54ea3f3390328fecc6d75f5a8e9d54b6d85848\"],\n    [\"01000000016c5ada601e3d338f95e1e168aab879a0e8df0a1ff64349fc23bf52811d25d2820000000009655200520052520000e7a0a5b904d813b7020000000006526565636a526ab29a0200000000075251ab6363ab53461dd5010000000000cd888e010000000005006363536ad2462657\", \"51ac53ac52acac51ab\", 0, -1478631154, \"d7f673c77d6777936adccdcbd7b2b3bb3632245523833d0a0f009ad27f7734d2\"],\n    [\"000000200482c560f54915d080a34d7846512495523ebebaf0873d1b38501f28192e7b95410000000005abab51ab52ffffffffd794e26fe3c71c94b47de0b104a657ecc924ec2adaaaf99b9a3c1cf64411621b0100000001acffffffffc2b9fdc82eb77ad05a590c527a9baed1e44969dcf0e343d7d0dfbd304ed7af6b00000000076a65ac52635300d1bd90f74c0bcd35ef142a1b9b35cd677fb228eca916d24569f45c306ee63cb45627893e0000000005ac53ab0063ffffffff049fc01501000000000152516100020000000004656565ac46c41c020000000009530000516a655100523bd9b80100000000076a51abab006a6523c55bf9\", \"5153006a6551\", 3, -1371469883, \"d8b8b404745879ee1f799c9a05979116691f5c9969077cc8eda9cf279a22183c\"],\n    [\"0200000002acc7cd6f3691672d429198e28f46b154e2c12f6fc35f725b525169300ff0043c000000000079f26415f28d3bba13628319fcb32c2e3e9d9f695ea6122559c4dde6ef87b95cf9c84b0d0100000008ac5200635353516a3b26a1db026fb14e010000000008ab516a65005300654728420000000000015300000000\", \"65\", 1, -1525715869, \"5eb3ac2e4f6bb46d173b596220ee2a1cdaf45849bfde2b60b8d1995901b89b6e\"],\n    [\"020000000406ac8d9c735b42fddb7a59b90c890bf50a27f6ef5b059e43d306fdc1409aa6af030000000651650053ac6affffffff7103aff7e6e609f6015f510d69d419f25e71b0fe332e16fe09c4c3812d132212010000000352ac53ffffffff1009875ad4eb65f09b48eeea45631b5cc3266b039358d86c1d399b257c0b65c7030000000552ab51656affffffffa63d2a25f600c41b5255ea3687c8cf0bddf1703d7c804f26eda21c60e9cb22fe00000000001e831bad0190333a0300000000066a516352006a00000000\", \"635251ac\", 3, 1196828753, \"87e41d5ac956e179e2c4e7c0d1593de48450628432aee2600906ff5338e644df\"],\n    [\"0100000001db2dbdc727a3d145544eed0a27da3a4875b256c5ca2ce6221ed7e07d1c88ef7d0200000006ab5253516a5324cad80101a2d4ea040000000005655153515174ac9c80\", \"00005253ac5163\", 0, -202513269, \"321a78d68bb271ff0def730ac12553b5aa2654eb4184ffbcadc9c27db16081f9\"],\n    [\"0400000004636f7d1b27a55186fd5c0c350fc87482f10d89def0ea21e4f6bfbb5e497e5e02020000000452535152ffffffff0a6b58c4cd04a40a667b422a15cb1b5d1e52abdd251d770333888ed0a5ccd2a3010000000265ab95c8676601c75cd1cb6c078a5ccd245d61f4aca92fc9dd5e51a07070d1619a7bd9e522b4010000000363006a771ac00b5233b4fc933e6c28bb54b91378fb69efd3d33df0bcb6ba116ddcc745421c942f02000000025265ffffffff03b6998e0400000000056563ab5151df83ab0200000000076a5165acac51abfc312702000000000000000000\", \"ac6a\", 0, -1176468424, \"6e033f1a0a6c76337e1e68fac69697140d717d8bc00110813b3eaebcc733e44b\"],\n    [\"0100000004998b25d33d610b3259a5291f3a61632d0ee0ed55230a45f82c7bd0ea6596b2de030000000353acacffffffff081c1b50d8b0f1737337829fc3578d0816d7f3853afa9ef224f7c4d091d458f70200000003525353ffffffff159ff62d680740fdf5bea27dcfe225ef858cb0ac19ddaa46da7b7bb79c24bd5c0300000005ac5352ac63fffffffff626954581585e93939da2e2d2a6f9f110de08400b75a393163f3c3b4d65d0e10300000006655263510053ffffffff02f9ee0201000000000152a179fe030000000004ab6a52651033d9b4\", \"6353\", 2, -401568199, \"af1c6717ea1358095cb25beb86c0faffb67972cc4628fe6c087bb23a4593dced\"],\n    [\"010000000334c70a7bba504287e077ec8e038e78509b1c294b5f68272c56e1d86c0b5b9c78000000000151fffffffffb69a5c174137c1864295c4651bb2a0507768ca05954d5282d25e6f4e1ca591f0300000004ab6aac519913f22ab79ce6a3cc935a5a4f3d6154779d9cf4735874c11512a3d44036b7c97b44691d02000000046353acac1be3fb430169be470100000000055351656351f279e598\", \"6a\", 1, 393914190, \"ce5e074752e525bfad78053e3382e7ddb6e68e07c6950577c92b899bceb95b9e\"],\n    [\"0000000004d1cc49f59ddf0e00896ee8b174f8a93fe6ceea031175e5c778026d5ffa3900b70200000000ffffffff18df4d052fc6e7a962cafeccd3d7957309f6f7a7c283184555e97512ef797b3802000000080051ab52ac525165ffffffffdf706411154b91796d26e3e8deaec39bdccc608d25dec6d91841b43be9cd31200100000001ac7546d4ac1c2a613a3aa0d4b3fe55a9aa08140079ca91a1437eeaf96aa2fff0f1ca1fa2c902000000036aac00ffffffff0189508b000000000002536300000000\", \"00ac526a65526a52\", 3, 1384197905, \"7c67f9bab46624a71aece5550b9b9f8244e2ece4fc7e18b50f06fe7a36fe4962\"],\n    [\"04000000014ee41b9744ae159f2536171117a3d061bf87c0ed64e854df171300d24ce922420200000000fef6c5cf01a8065a0000000000046a6a526500000000\", \"52ab00516a\", 0, -1768745756, \"391e25396a1ab8e2722a2b3c69fda33be2b02ab0d7ba58736ee75038c28721a5\"],\n    [\"0400000002b320ba15dcaa210f7cab2e09c3a91337aac290fbb8f05820b59cdc6cbb4cbb56010000000963655265ac6a6aab632c5c51d17f69393794e9242c19358f6338e44cdd4d0d402c6a7b851980004b42985cc8e10200000008650053ac6a51ab00ca8860e6043c4961010000000001517c4f70000000000008ab656a526a536353b6c87c00000000000151a6571a05000000000265527168b2c9\", \"6aac\", 1, -1798234701, \"ba633ec939bd1f41a88aeae245786a028641f53a7d8751a2e49a33359019bee8\"],\n    [\"0200000001e38a1f18d4a3aa874ce62b9bae1cbb10df77270a5c3aca550fed933420ce52ed03000000026563ffffffff0310d972000000000007ac51525153ab0033f23500000000000453525365b57446020000000008636352abac65516a00000000\", \"6a6a6a51\", 0, 1150844091, \"e07032db2a3a065f49e30364f2552cb3101a0406fb408c0b39c5e1935d53073a\"],\n    [\"01000000012fbb337e7de67fdbee5f47bb9798be26c42d38ebe7b519dd4f61ae65583b80b00100000005ab52526a63811f691e01ac7d6b000000000003ac516a00000000\", \"6a510051\", 0, -1791977144, \"707fa0d6481fbbdebb788ea045ec539549d27f54a84efaaa5356a77d3758f02b\"],\n    [\"00000000010b2ea63319d5078d303849f44c3c7d2d40d660a8390807a25b1e6a8c606df1ac0100000004ab5151657af9ab81035569db0500000000004daa730300000000086a515263ac516aabe06b6204000000000000000000\", \"51\", 0, 19185185, \"65458f4e128cc88f6be70e9ba4e9445231de612f214560cbae7e9e9a0993e39b\"],\n    [\"0100000001a9a532aa0967c9ab10698a6e65a183f2d2bc48613e034c4c5593398be0f0c87003000000055151655163ffffffff04c8c6c10000000000003ec517030000000006ab6a5365ac519ca8400400000000016a1983650400000000036a656500000000\", \"52005153ab53636565\", 0, -1377385634, \"e58debd247fccaaf78451cd465e8ee9265269b748c42c3adeef57f78a5688dda\"],\n    [\"0400000003ce49f29162c4400e2668870dae639bf70d470624196ffba86991319989ed1c2d000000000752ab005253acac4554383828fea8d3e88fa43e547f656ea0bf5a3971f6a6dea710bf5b8ae7df4e12d7cfe203000000086551ab6a51005363ca76b6cc31c36b5fadf1dd0c0f2bc51bff0c40f605818e8674400474bc4d216d8047d90f02000000046aacab00ad565f3702cbe74b000000000008ab636a0052ab52633675e9020000000005655300ac0000000000\", \"5263635300000065\", 1, 940684544, \"ff3645b43fb86e45be401c6302564dadb8163da5f537f80f171e18d5077ebf3a\"],\n    [\"030000000106c0a45048800b5d3868dd5cb7b1015e1918d973e6ec6ec5485322df4cff843e00000000096a63636363526a63abae5b5830016d693f01000000000000000000\", \"6a52\", 0, 666587938, \"b4e653e458e2fa4e0ab99b6ed93925fc85bfef170effa7005a549e077b2a952b\"],\n    [\"0100000004805bac2fecdafca06cee09c4d8dfeb4dc867bc8b81a4be1caf757943eeeb1ca502000000050063ab65abffffffff7c8f567721aa799f5d3b163f49798e9b3808f4dad44bc00256531eb303f107ef0000000001acffffffffc78d1401f08fe7269f61ff1fe55ec81996720acf2a912ae2ef495dbbe51900db01000000096a520000005263ac00fffffffffcdebe76c5e895b652755463c566486bc468afb25919b25a28f5dd5fd5f80cac0200000000ffffffff020eafdd00000000000352ac00c360220400000000035165654a47f095\", \"acab6aab53006a65\", 1, -145428476, \"da2abd15b6a1004cda1bb886c43da66ff8bc56574484a828105ccea76197b247\"],\n    [\"020000000336d96918b36dcf0b3ffef7940257a3b3786e76403eb9ecde6e38570c567fa8d60000000009656353ac006a6551ac27cca44db2e3b5596693eaf7f79d0cea75632515f18e09d531e71316bc7d8270db9237e50200000009ab6551005153656563ffffffffbdd9a049a2ccbd6c9e75a89fd206657041f36eebd5aeca8c7bbae2cd9ded2be50200000003ac0053ffffffff0470214c0400000000096565520053ab6a6a5184b3cf020000000003ab52518e0bdc02000000000951635365635153005381ba85020000000001ab00000000\", \"5351ac6aac\", 1, -1057518336, \"4eb760cfd7b83996ce641e24c693f221772d000bc560a85d956a8e7455cee0ff\"]\n]\n"
  },
  {
    "path": "src/test/data/tx_invalid.json",
    "content": "[\n[\"The following are deserialized transactions which are invalid.\"],\n[\"They are in the form\"],\n[\"[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],\"],\n[\"serializedTransaction, verifyFlags]\"],\n[\"Objects that are only a single string (like this one) are ignored\"],\n\n[\"0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey\"],\n[[[\"6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827\", 0, \"0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1\"]],\n\"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000\", \"P2SH\"],\n\n[\"This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json\"],\n[\"but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix\"],\n[\"See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json\"],\n[\"but with the signature duplicated in the scriptPubKey with a different hashtype suffix\"],\n[\"See FindAndDelete, which will only remove if the signature, including the hash type, matches\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a81\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"An invalid P2SH Transaction\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Tests for CheckTransaction()\"],\n[\"No outputs\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000\", \"P2SH\"],\n\n[\"Negative output\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000\", \"P2SH\"],\n\n[\"MAX_MONEY + 1 output\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000\", \"P2SH\"],\n\n[\"MAX_MONEY output + 1 output\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000\", \"P2SH\"],\n\n[\"Duplicate inputs\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL\"]],\n\"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Coinbase of size 1\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"]],\n\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Coinbase of size 101\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"]],\n\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Null txin, but without being a coinbase (because there are two inputs)\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"],\n  [\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"01000000020000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015100000000\", \"P2SH\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"],\n  [\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"]],\n\"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"],\n  [\"0000000000000000000000000000000000000000000000000000000000000200\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"]],\n \"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000\", \"P2SH\"],\n\n[\"CHECKMULTISIG with incorrect signature order\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223\", 0, \"HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL\"]],\n\"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000\", \"P2SH\"],\n\n\n[\"The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63\"],\n[\"It is an OP_CHECKMULTISIG with the dummy value missing\"],\n[[[\"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1\", 0, \"1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG\"]],\n\"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000\", \"P2SH\"],\n\n\n[\"Empty stack when we try to run CHECKSIG\"],\n[[[\"ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b\", 0, \"0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT\"]],\n\"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000\", \"P2SH\"],\n\n\n[\"Inverted versions of tx_valid CODESEPARATOR IF block tests\"],\n\n[\"CODESEPARATOR in an unexecuted IF block does not change what is hashed\"],\n[[[\"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944\", 0, \"IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1\"]],\n\"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0151ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"As above, with the IF block executed\"],\n[[[\"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944\", 0, \"IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1\"]],\n\"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"CHECKLOCKTIMEVERIFY tests\"],\n\n[\"By-height locks, with argument just beyond tx nLockTime\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"499999999 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"500000001 CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Argument missing\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Argument negative with by-blockheight nLockTime=0\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"-1 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Argument negative with by-blocktime nLockTime=500,000,000\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"-1 CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Input locked\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"] ,\n  [\"0000000000000000000000000000000000000000000000000000000000000200\", 1, \"1\"]],\n\"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Argument/tx height/time mismatch, both versions\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"499999999 CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"500000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"500000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Argument 2^32 with nLockTime=2^32-1\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967296 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Same, but with nLockTime=2^31-1\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"6 byte non-minimally-encoded arguments are invalid even if their contents are valid\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x06 0x000000000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"A transaction with a non-standard DER signature.\"],\n[[[\"b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132\", 0, \"DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG\"]],\n\"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000\", \"P2SH,DERSIG\"],\n\n[\"CHECKSEQUENCEVERIFY tests\"],\n\n[\"By-height locks, with argument just beyond txin.nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4259839 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194305 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4259839 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument missing\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument negative with by-blockheight txin.nSequence=0\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"-1 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"-1 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument/tx height/time mismatch, both versions\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"65535 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194304 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4259839 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"6 byte non-minimally-encoded arguments are invalid even if their contents are valid\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x06 0x000000000000 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Failure due to failing CHECKSEQUENCEVERIFY in scriptSig\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Failure due to failing CHECKSEQUENCEVERIFY in redeemScript\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL\"]],\n\"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Failure due to insufficient tx.nVersion (<2)\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKSEQUENCEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194304 CHECKSEQUENCEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Make diffs cleaner by leaving a comment here without comma at the end\"]\n]\n"
  },
  {
    "path": "src/test/data/tx_valid.json",
    "content": "[\n[\"The following are deserialized transactions which are valid.\"],\n[\"They are in the form\"],\n[\"[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],\"],\n[\"serializedTransaction, verifyFlags]\"],\n[\"Objects that are only a single string (like this one) are ignored\"],\n\n[\"The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63\"],\n[\"It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts\"],\n[\"See http://r6.ca/blog/20111119T211504Z.html\"],\n[\"It is also the first OP_CHECKMULTISIG transaction in standard form\"],\n[[[\"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1\", 0, \"1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG\"]],\n\"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000\", \"P2SH\"],\n\n[\"The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63\"],\n[\"It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string\"],\n[[[\"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1\", 0, \"1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG\"]],\n\"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000\", \"P2SH\"],\n\n[\"As above, but using a OP_1\"],\n[[[\"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1\", 0, \"1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG\"]],\n\"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000\", \"P2SH\"],\n\n[\"As above, but using a OP_1NEGATE\"],\n[[[\"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1\", 0, \"1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG\"]],\n\"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000\", \"P2SH\"],\n\n[\"The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73\"],\n[\"It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)\"],\n[[[\"406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602\", 0, \"DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG\"]],\n\"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000\", \"P2SH\"],\n\n[\"A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb\"],\n[\"It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation\"],\n[[[\"b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d\", 0, \"DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG\"],\n[\"b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21\", 1, \"DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG\"]],\n\"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000\", \"P2SH\"],\n\n[\"The following tests for the presence of a bug in the handling of SIGHASH_SINGLE\"],\n[\"It results in signing the constant 1, instead of something generated based on the transaction,\"],\n[\"when the input doing the signing has an index greater than the maximum output index\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000200\", 0, \"1\"], [\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG\"]],\n\"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"An invalid P2SH Transaction\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000\", \"NONE\"],\n\n[\"A valid P2SH Transaction using the standard transaction type put forth in BIP 16\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Tests for CheckTransaction()\"],\n[\"MAX_MONEY output\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000\", \"P2SH\"],\n\n[\"MAX_MONEY output + 0 output\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000\", \"P2SH\"],\n\n[\"Coinbase of size 2\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"]],\n\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Coinbase of size 100\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000000\", -1, \"1\"]],\n\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000\", \"P2SH\"],\n\n[\"Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"],\n  [\"0000000000000000000000000000000000000000000000000000000000000200\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"]],\n \"010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000\", \"P2SH\"],\n\n[\"Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"],\n  [\"0000000000000000000000000000000000000000000000000000000000000200\", 0, \"0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG\"]],\n \"01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000\", \"P2SH\"],\n\n[\"afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures\"],\n[[[\"63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70\", 0, \"DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG\"],\n [\"04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d\", 1, \"DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG\"],\n [\"ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f\", 1, \"DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG\"]],\n \"010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000\", \"P2SH\"],\n\n [\"ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed\"],\n [[[\"c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48\", 0, \"0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG\"]],\n \"0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000\", \"P2SH\"],\n\n[\"Correct signature order\"],\n[\"Note the input is just required to make the tester happy\"],\n[[[\"b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223\", 0, \"HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL\"]],\n\"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000\", \"P2SH\"],\n\n[\"cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0\"],\n[[[\"cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7\", 0, \"0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68\"]],\n\"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000\", \"P2SH\"],\n\n[\"Empty pubkey\"],\n[[[\"229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c\", 0, \"0x00 CHECKSIG NOT\"]],\n\"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000\", \"P2SH\"],\n\n[\"Empty signature\"],\n[[[\"9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7\", 0, \"0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT\"]],\n\"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000\", \"P2SH\"],\n\n[[[\"444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be\", 0, \"1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG\"]],\n\"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000\", \"P2SH\"],\n\n[[[\"e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612\", 0, \"1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG\"]],\n\"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000\", \"P2SH\"],\n\n[[[\"ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0\", 0, \"2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT\"]],\n\"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000\", \"P2SH\"],\n\n[[[\"ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1\", 0, \"2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT\"]],\n\"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000\", \"P2SH\"],\n\n\n[\"OP_CODESEPARATOR tests\"],\n\n[\"Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()\"],\n[[[\"bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224\", 0, \"CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG\"]],\n\"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000\", \"P2SH\"],\n[[[\"83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047\", 0, \"CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG\"]],\n\"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"Hashed data starts at the CODESEPARATOR\"],\n[[[\"326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e\", 0, \"0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG\"]],\n\"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"But only if execution has reached it\"],\n[[[\"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944\", 0, \"0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1\"]],\n\"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"CODESEPARATOR in an unexecuted IF block does not change what is hashed\"],\n[[[\"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944\", 0, \"IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1\"]],\n\"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"As above, with the IF block executed\"],\n[[[\"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944\", 0, \"IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1\"]],\n\"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n\n[\"CHECKSIG is legal in scriptSigs\"],\n[[[\"ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0\", 0, \"DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG\"]],\n\"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"Same semantics for OP_CODESEPARATOR\"],\n[[[\"10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c\", 1, \"DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG\"]],\n\"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed.\"],\n[[[\"6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f\", 0, \"DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG\"]],\n\"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"That also includes ahead of the opcode being executed.\"],\n[[[\"5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921\", 1, \"DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG\"]],\n\"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000\", \"P2SH\"],\n\n[\"Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail.\"],\n\n[\"Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9\"],\n[[[\"b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9\", 0, \"DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG\"],\n  [\"ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742\", 0, \"HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL\"]],\n\"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000\", \"P2SH\"],\n\n[\"Same idea, but with bare CHECKMULTISIG\"],\n[[[\"ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db\", 0, \"DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG\"],\n  [\"ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db\", 1, \"2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG\"]],\n\"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000\", \"P2SH\"],\n\n\n[\"CHECKLOCKTIMEVERIFY tests\"],\n\n[\"By-height locks, with argument == 0 and == tx nLockTime\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"499999999 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"500000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"500000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Any non-maxint nSequence is fine\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"The argument can be calculated rather than created directly by a PUSHDATA\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"499999999 1ADD CHECKLOCKTIMEVERIFY 1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"5 byte non-minimally-encoded arguments are valid\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1\"]],\n\"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Valid CHECKLOCKTIMEVERIFY in scriptSig\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"Valid CHECKLOCKTIMEVERIFY in redeemScript\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL\"]],\n\"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000\", \"P2SH,CHECKLOCKTIMEVERIFY\"],\n\n[\"A transaction with a non-standard DER signature.\"],\n[[[\"b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132\", 0, \"DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG\"]],\n\"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000\", \"P2SH\"],\n\n[\"CHECKSEQUENCEVERIFY tests\"],\n\n[\"By-height locks, with argument == 0 and == txin.nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"65535 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"65535 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"By-time locks, with argument == 0 and == txin.nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194304 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4259839 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4259839 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194304 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Upper sequence with upper sequence is fine\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument 2^31 with various nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483648 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument 2^32-1 with various nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4294967295 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Argument 3<<31 with various nSequence\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"6442450944 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"6442450944 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"6442450944 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"5 byte non-minimally-encoded operandss are valid\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"0x05 0x0000000000 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"The argument can be calculated rather than created directly by a PUSHDATA\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194303 1ADD CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"4194304 1SUB CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483647 65536 CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"2147483647 4259840 ADD CHECKSEQUENCEVERIFY 1\"]],\n\"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Valid CHECKSEQUENCEVERIFY in scriptSig\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"1\"]],\n\"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n[\"Valid CHECKSEQUENCEVERIFY in redeemScript\"],\n[[[\"0000000000000000000000000000000000000000000000000000000000000100\", 0, \"HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL\"]],\n\"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000\", \"P2SH,CHECKSEQUENCEVERIFY\"],\n\n\n\n[\"Make diffs cleaner by leaving a comment here without comma at the end\"]\n]\n"
  },
  {
    "path": "src/test/dbwrapper_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"dbwrapper.h\"\n#include \"uint256.h\"\n#include \"random.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\n// Test if a string consists entirely of null characters\nstatic bool is_null_key(const std::vector<unsigned char>& key) {\n    bool isnull = true;\n\n    for (unsigned int i = 0; i < key.size(); i++)\n        isnull &= (key[i] == '\\x00');\n\n    return isnull;\n}\n\nBOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(dbwrapper)\n{\n    // Perform tests both obfuscated and non-obfuscated.\n    for (int i = 0; i < 2; i++) {\n        bool obfuscate = (bool)i;\n        fs::path ph = fs::temp_directory_path() / fs::unique_path();\n        CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);\n        char key = 'k';\n        uint256 in = InsecureRand256();\n        uint256 res;\n\n        // Ensure that we're doing real obfuscation when obfuscate=true\n        BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw)));\n\n        BOOST_CHECK(dbw.Write(key, in));\n        BOOST_CHECK(dbw.Read(key, res));\n        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());\n    }\n}\n\n// Test batch operations\nBOOST_AUTO_TEST_CASE(dbwrapper_batch)\n{\n    // Perform tests both obfuscated and non-obfuscated.\n    for (int i = 0; i < 2; i++) {\n        bool obfuscate = (bool)i;\n        fs::path ph = fs::temp_directory_path() / fs::unique_path();\n        CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);\n\n        char key = 'i';\n        uint256 in = InsecureRand256();\n        char key2 = 'j';\n        uint256 in2 = InsecureRand256();\n        char key3 = 'k';\n        uint256 in3 = InsecureRand256();\n\n        uint256 res;\n        CDBBatch batch(dbw);\n\n        batch.Write(key, in);\n        batch.Write(key2, in2);\n        batch.Write(key3, in3);\n\n        // Remove key3 before it's even been written\n        batch.Erase(key3);\n\n        dbw.WriteBatch(batch);\n\n        BOOST_CHECK(dbw.Read(key, res));\n        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());\n        BOOST_CHECK(dbw.Read(key2, res));\n        BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());\n\n        // key3 should've never been written\n        BOOST_CHECK(dbw.Read(key3, res) == false);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(dbwrapper_iterator)\n{\n    // Perform tests both obfuscated and non-obfuscated.\n    for (int i = 0; i < 2; i++) {\n        bool obfuscate = (bool)i;\n        fs::path ph = fs::temp_directory_path() / fs::unique_path();\n        CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);\n\n        // The two keys are intentionally chosen for ordering\n        char key = 'j';\n        uint256 in = InsecureRand256();\n        BOOST_CHECK(dbw.Write(key, in));\n        char key2 = 'k';\n        uint256 in2 = InsecureRand256();\n        BOOST_CHECK(dbw.Write(key2, in2));\n\n        std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());\n\n        // Be sure to seek past the obfuscation key (if it exists)\n        it->Seek(key);\n\n        char key_res;\n        uint256 val_res;\n\n        it->GetKey(key_res);\n        it->GetValue(val_res);\n        BOOST_CHECK_EQUAL(key_res, key);\n        BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());\n\n        it->Next();\n\n        it->GetKey(key_res);\n        it->GetValue(val_res);\n        BOOST_CHECK_EQUAL(key_res, key2);\n        BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());\n\n        it->Next();\n        BOOST_CHECK_EQUAL(it->Valid(), false);\n    }\n}\n\n// Test that we do not obfuscation if there is existing data.\nBOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)\n{\n    // We're going to share this fs::path between two wrappers\n    fs::path ph = fs::temp_directory_path() / fs::unique_path();\n    create_directories(ph);\n\n    // Set up a non-obfuscated wrapper to write some initial data.\n    CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);\n    char key = 'k';\n    uint256 in = InsecureRand256();\n    uint256 res;\n\n    BOOST_CHECK(dbw->Write(key, in));\n    BOOST_CHECK(dbw->Read(key, res));\n    BOOST_CHECK_EQUAL(res.ToString(), in.ToString());\n\n    // Call the destructor to free leveldb LOCK\n    delete dbw;\n    dbw = nullptr;\n\n    // Now, set up another wrapper that wants to obfuscate the same directory\n    CDBWrapper odbw(ph, (1 << 10), false, false, true);\n\n    // Check that the key/val we wrote with unobfuscated wrapper exists and \n    // is readable.\n    uint256 res2;\n    BOOST_CHECK(odbw.Read(key, res2));\n    BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());\n\n    BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data\n    BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string\n\n    uint256 in2 = InsecureRand256();\n    uint256 res3;\n\n    // Check that we can write successfully\n    BOOST_CHECK(odbw.Write(key, in2));\n    BOOST_CHECK(odbw.Read(key, res3));\n    BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());\n}\n\n// Ensure that we start obfuscating during a reindex.\nBOOST_AUTO_TEST_CASE(existing_data_reindex)\n{\n    // We're going to share this fs::path between two wrappers\n    fs::path ph = fs::temp_directory_path() / fs::unique_path();\n    create_directories(ph);\n\n    // Set up a non-obfuscated wrapper to write some initial data.\n    CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);\n    char key = 'k';\n    uint256 in = InsecureRand256();\n    uint256 res;\n\n    BOOST_CHECK(dbw->Write(key, in));\n    BOOST_CHECK(dbw->Read(key, res));\n    BOOST_CHECK_EQUAL(res.ToString(), in.ToString());\n\n    // Call the destructor to free leveldb LOCK\n    delete dbw;\n    dbw = nullptr;\n\n    // Simulate a -reindex by wiping the existing data store\n    CDBWrapper odbw(ph, (1 << 10), false, true, true);\n\n    // Check that the key/val we wrote with unobfuscated wrapper doesn't exist\n    uint256 res2;\n    BOOST_CHECK(!odbw.Read(key, res2));\n    BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw)));\n\n    uint256 in2 = InsecureRand256();\n    uint256 res3;\n \n    // Check that we can write successfully\n    BOOST_CHECK(odbw.Write(key, in2));\n    BOOST_CHECK(odbw.Read(key, res3));\n    BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());\n}\n\nBOOST_AUTO_TEST_CASE(iterator_ordering)\n{\n    fs::path ph = fs::temp_directory_path() / fs::unique_path();\n    CDBWrapper dbw(ph, (1 << 20), true, false, false);\n    for (int x=0x00; x<256; ++x) {\n        uint8_t key = x;\n        uint32_t value = x*x;\n        BOOST_CHECK(dbw.Write(key, value));\n    }\n\n    std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());\n    for (int c=0; c<2; ++c) {\n        int seek_start;\n        if (c == 0)\n            seek_start = 0x00;\n        else\n            seek_start = 0x80;\n        it->Seek((uint8_t)seek_start);\n        for (unsigned int x=seek_start; x<256; ++x) {\n            uint8_t key;\n            uint32_t value;\n            BOOST_CHECK(it->Valid());\n            if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure\n                break;\n            BOOST_CHECK(it->GetKey(key));\n            BOOST_CHECK(it->GetValue(value));\n            BOOST_CHECK_EQUAL(key, x);\n            BOOST_CHECK_EQUAL(value, x*x);\n            it->Next();\n        }\n        BOOST_CHECK(!it->Valid());\n    }\n}\n\nstruct StringContentsSerializer {\n    // Used to make two serialized objects the same while letting them have a different lengths\n    // This is a terrible idea\n    std::string str;\n    StringContentsSerializer() {}\n    StringContentsSerializer(const std::string& inp) : str(inp) {}\n\n    StringContentsSerializer& operator+=(const std::string& s) {\n        str += s;\n        return *this;\n    }\n    StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        if (ser_action.ForRead()) {\n            str.clear();\n            char c = 0;\n            while (true) {\n                try {\n                    READWRITE(c);\n                    str.push_back(c);\n                } catch (const std::ios_base::failure& e) {\n                    break;\n                }\n            }\n        } else {\n            for (size_t i = 0; i < str.size(); i++)\n                READWRITE(str[i]);\n        }\n    }\n};\n\nBOOST_AUTO_TEST_CASE(iterator_string_ordering)\n{\n    char buf[10];\n\n    fs::path ph = fs::temp_directory_path() / fs::unique_path();\n    CDBWrapper dbw(ph, (1 << 20), true, false, false);\n    for (int x=0x00; x<10; ++x) {\n        for (int y = 0; y < 10; y++) {\n            snprintf(buf, sizeof(buf), \"%d\", x);\n            StringContentsSerializer key(buf);\n            for (int z = 0; z < y; z++)\n                key += key;\n            uint32_t value = x*x;\n            BOOST_CHECK(dbw.Write(key, value));\n        }\n    }\n\n    std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());\n    for (unsigned int c=0; c<2; ++c) {\n        unsigned int seek_start;\n        if (c == 0)\n            seek_start = 0;\n        else\n            seek_start = 5;\n        snprintf(buf, sizeof(buf), \"%d\", seek_start);\n        StringContentsSerializer seek_key(buf);\n        it->Seek(seek_key);\n        for (unsigned int x=seek_start; x<10; ++x) {\n            for (unsigned int y = 0; y < 10; y++) {\n                snprintf(buf, sizeof(buf), \"%d\", x);\n                std::string exp_key(buf);\n                for (unsigned int z = 0; z < y; z++)\n                    exp_key += exp_key;\n                StringContentsSerializer key;\n                uint32_t value;\n                BOOST_CHECK(it->Valid());\n                if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure\n                    break;\n                BOOST_CHECK(it->GetKey(key));\n                BOOST_CHECK(it->GetValue(value));\n                BOOST_CHECK_EQUAL(key.str, exp_key);\n                BOOST_CHECK_EQUAL(value, x*x);\n                it->Next();\n            }\n        }\n        BOOST_CHECK(!it->Valid());\n    }\n}\n\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/getarg_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"util.h\"\n#include \"test/test.h\"\n\n#include <string>\n#include <vector>\n\n#include <boost/algorithm/string.hpp>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup)\n\nstatic void ResetArgs(const std::string& strArg)\n{\n    std::vector<std::string> vecArg;\n    if (strArg.size())\n      boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on);\n\n    // Insert dummy executable name:\n    vecArg.insert(vecArg.begin(), \"testmunt\");\n\n    // Convert to char*:\n    std::vector<const char*> vecChar;\n    for(std::string& s : vecArg)\n        vecChar.push_back(s.c_str());\n\n    ParseParameters(vecChar.size(), &vecChar[0]);\n}\n\nBOOST_AUTO_TEST_CASE(boolarg)\n{\n    ResetArgs(\"-foo\");\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n\n    BOOST_CHECK(!GetBoolArg(\"-fo\", false));\n    BOOST_CHECK(GetBoolArg(\"-fo\", true));\n\n    BOOST_CHECK(!GetBoolArg(\"-fooo\", false));\n    BOOST_CHECK(GetBoolArg(\"-fooo\", true));\n\n    ResetArgs(\"-foo=0\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"-foo=1\");\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n\n    // New 0.6 feature: auto-map -nosomething to !-something:\n    ResetArgs(\"-nofoo\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"-nofoo=1\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"-foo -nofoo\");  // -nofoo should win\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"-foo=1 -nofoo=1\");  // -nofoo should win\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"-foo=0 -nofoo=0\");  // -nofoo=0 should win\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n\n    // New 0.6 feature: treat -- same as -:\n    ResetArgs(\"--foo=1\");\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n\n    ResetArgs(\"--nofoo=1\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n\n}\n\nBOOST_AUTO_TEST_CASE(stringarg)\n{\n    ResetArgs(\"\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"eleven\"), \"eleven\");\n\n    ResetArgs(\"-foo -bar\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"eleven\"), \"\");\n\n    ResetArgs(\"-foo=\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"eleven\"), \"\");\n\n    ResetArgs(\"-foo=11\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"11\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"eleven\"), \"11\");\n\n    ResetArgs(\"-foo=eleven\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"eleven\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"eleven\"), \"eleven\");\n\n}\n\nBOOST_AUTO_TEST_CASE(intarg)\n{\n    ResetArgs(\"\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", 11), 11);\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", 0), 0);\n\n    ResetArgs(\"-foo -bar\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", 11), 0);\n    BOOST_CHECK_EQUAL(GetArg(\"-bar\", 11), 0);\n\n    ResetArgs(\"-foo=11 -bar=12\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", 0), 11);\n    BOOST_CHECK_EQUAL(GetArg(\"-bar\", 11), 12);\n\n    ResetArgs(\"-foo=NaN -bar=NotANumber\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", 1), 0);\n    BOOST_CHECK_EQUAL(GetArg(\"-bar\", 11), 0);\n}\n\nBOOST_AUTO_TEST_CASE(doubledash)\n{\n    ResetArgs(\"--foo\");\n    BOOST_CHECK_EQUAL(GetBoolArg(\"-foo\", false), true);\n\n    ResetArgs(\"--foo=verbose --bar=1\");\n    BOOST_CHECK_EQUAL(GetArg(\"-foo\", \"\"), \"verbose\");\n    BOOST_CHECK_EQUAL(GetArg(\"-bar\", 0), 1);\n}\n\nBOOST_AUTO_TEST_CASE(boolargno)\n{\n    ResetArgs(\"-nofoo\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n\n    ResetArgs(\"-nofoo=1\");\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n\n    ResetArgs(\"-nofoo=0\");\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n\n    ResetArgs(\"-foo --nofoo\"); // --nofoo should win\n    BOOST_CHECK(!GetBoolArg(\"-foo\", true));\n    BOOST_CHECK(!GetBoolArg(\"-foo\", false));\n\n    ResetArgs(\"-nofoo -foo\"); // foo always wins:\n    BOOST_CHECK(GetBoolArg(\"-foo\", true));\n    BOOST_CHECK(GetBoolArg(\"-foo\", false));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/hash_tests.cpp",
    "content": "// Copyright (c) 2013-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"hash.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(murmurhash3)\n{\n\n#define T(expected, seed, data) BOOST_CHECK_EQUAL(MurmurHash3(seed, ParseHex(data)), expected)\n\n    // Test MurmurHash3 with various inputs. Of course this is retested in the\n    // bloom filter tests - they would fail if MurmurHash3() had any problems -\n    // but is useful for those trying to implement Munt libraries as a\n    // source of test data for their MurmurHash3() primitive during\n    // development.\n    //\n    // The magic number 0xFBA4C795 comes from CBloomFilter::Hash()\n\n    T(0x00000000U, 0x00000000, \"\");\n    T(0x6a396f08U, 0xFBA4C795, \"\");\n    T(0x81f16f39U, 0xffffffff, \"\");\n\n    T(0x514e28b7U, 0x00000000, \"00\");\n    T(0xea3f0b17U, 0xFBA4C795, \"00\");\n    T(0xfd6cf10dU, 0x00000000, \"ff\");\n\n    T(0x16c6b7abU, 0x00000000, \"0011\");\n    T(0x8eb51c3dU, 0x00000000, \"001122\");\n    T(0xb4471bf8U, 0x00000000, \"00112233\");\n    T(0xe2301fa8U, 0x00000000, \"0011223344\");\n    T(0xfc2e4a15U, 0x00000000, \"001122334455\");\n    T(0xb074502cU, 0x00000000, \"00112233445566\");\n    T(0x8034d2a0U, 0x00000000, \"0011223344556677\");\n    T(0xb4698defU, 0x00000000, \"001122334455667788\");\n\n#undef T\n}\n\n/*\n   SipHash-2-4 output with\n   k = 00 01 02 ...\n   and\n   in = (empty string)\n   in = 00 (1 byte)\n   in = 00 01 (2 bytes)\n   in = 00 01 02 (3 bytes)\n   ...\n   in = 00 01 02 ... 3e (63 bytes)\n\n   from: https://131002.net/siphash/siphash24.c\n*/\nuint64_t siphash_4_2_testvec[] = {\n    0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d,\n    0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137,\n    0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7,\n    0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5,\n    0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd,\n    0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8,\n    0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad,\n    0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342,\n    0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae,\n    0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c,\n    0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95,\n    0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb,\n    0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a,\n    0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499,\n    0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93,\n    0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572\n};\n\nBOOST_AUTO_TEST_CASE(siphash)\n{\n    CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x726fdb47dd0e0e31ull);\n    static const unsigned char t0[1] = {0};\n    hasher.Write(t0, 1);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x74f839c593dc67fdull);\n    static const unsigned char t1[7] = {1,2,3,4,5,6,7};\n    hasher.Write(t1, 7);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x93f5f5799a932462ull);\n    hasher.Write(0x0F0E0D0C0B0A0908ULL);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x3f2acc7f57c29bdbull);\n    static const unsigned char t2[2] = {16,17};\n    hasher.Write(t2, 2);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x4bc1b3f0968dd39cull);\n    static const unsigned char t3[9] = {18,19,20,21,22,23,24,25,26};\n    hasher.Write(t3, 9);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x2f2e6163076bcfadull);\n    static const unsigned char t4[5] = {27,28,29,30,31};\n    hasher.Write(t4, 5);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x7127512f72f27cceull);\n    hasher.Write(0x2726252423222120ULL);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0x0e3ea96b5304a7d0ull);\n    hasher.Write(0x2F2E2D2C2B2A2928ULL);\n    BOOST_CHECK_EQUAL(hasher.Finalize(),  0xe612a3cb9ecba951ull);\n\n    BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S(\"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100\")), 0x7127512f72f27cceull);\n\n    // Check test vectors from spec, one byte at a time\n    CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);\n    for (uint8_t x=0; x<ARRAYLEN(siphash_4_2_testvec); ++x)\n    {\n        BOOST_CHECK_EQUAL(hasher2.Finalize(), siphash_4_2_testvec[x]);\n        hasher2.Write(&x, 1);\n    }\n    // Check test vectors from spec, eight bytes at a time\n    CSipHasher hasher3(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);\n    for (uint8_t x=0; x<ARRAYLEN(siphash_4_2_testvec); x+=8)\n    {\n        BOOST_CHECK_EQUAL(hasher3.Finalize(), siphash_4_2_testvec[x]);\n        hasher3.Write(uint64_t(x)|(uint64_t(x+1)<<8)|(uint64_t(x+2)<<16)|(uint64_t(x+3)<<24)|\n                     (uint64_t(x+4)<<32)|(uint64_t(x+5)<<40)|(uint64_t(x+6)<<48)|(uint64_t(x+7)<<56));\n    }\n\n    CHashWriter ss(SER_DISK, CLIENT_VERSION);\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    // Note these tests were originally written with tx.nVersion=1\n    // and the test would be affected by default tx version bumps if not fixed.\n    tx.nVersion = 1;\n    ss << tx;\n    BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);\n\n    // Check consistency between CSipHasher and SipHashUint256[Extra].\n    FastRandomContext ctx;\n    for (int i = 0; i < 16; ++i) {\n        uint64_t k1 = ctx.rand64();\n        uint64_t k2 = ctx.rand64();\n        uint256 x = InsecureRand256();\n        uint32_t n = ctx.rand32();\n        uint8_t nb[4];\n        WriteLE32(nb, n);\n        CSipHasher sip256(k1, k2);\n        sip256.Write(x.begin(), 32);\n        CSipHasher sip288 = sip256;\n        sip288.Write(nb, 4);\n        BOOST_CHECK_EQUAL(SipHashUint256(k1, k2, x), sip256.Finalize());\n        BOOST_CHECK_EQUAL(SipHashUint256Extra(k1, k2, x, n), sip288.Finalize());\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/key_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"key.h\"\n\n#include \"base58.h\"\n#include \"script/script.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n\n#include <string>\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nstatic const std::string strSecret1     (\"6a2UyrZS129AKTcfehHprFcongim2vK88nvpdbfFDrHHU32CGWM\");\nstatic const std::string strSecret2     (\"6aDvMh1RCTWjjSL6qBrkAzejMGPMtWeNt1ZL2CtbkWXSXK3mZQj\");\nstatic const std::string strSecret1C    (\"RamYVwk9M6328UURbNqGCPX3WeKKMUJzVPiZEXyomiWsgBaWgMkY\");\nstatic const std::string strSecret2C    (\"Rbe2WKaqoa2FcJoJjgvZZ7TXvSuhCMqya9TgxKUkP3KMeaPtEeVy\");\nstatic const CNativeAddress addr1       (\"GfTG81CusFHEPSbxhbqhcWqmh9nxRyyXjs\");\nstatic const CNativeAddress addr2       (\"GeezUtUnnU8k7H1Ri8rYUfN8o3pbFJqrWL\");\nstatic const CNativeAddress addr1C      (\"GXpEs9RdwjWqbV3mu5Hm5S8sCQZX5XfGhJ\");\nstatic const CNativeAddress addr2C      (\"GRn6YVVQSENt6rg3XnoFtHvnkxiBZvnaj1\");\nstatic const std::string strAddressBad  (\"GWusmV4SGS9LRM3B2oCj7c58D2n8KCGhr8\");\n\n\nBOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(key_test1)\n{\n    CEncodedSecretKey bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1;\n    BOOST_CHECK( bsecret1.SetString (strSecret1));\n    BOOST_CHECK( bsecret2.SetString (strSecret2));\n    BOOST_CHECK( bsecret1C.SetString(strSecret1C));\n    BOOST_CHECK( bsecret2C.SetString(strSecret2C));\n    BOOST_CHECK(!baddress1.SetString(strAddressBad));\n\n    CKey key1  = bsecret1.GetKey();\n    BOOST_CHECK(key1.IsCompressed() == false);\n    CKey key2  = bsecret2.GetKey();\n    BOOST_CHECK(key2.IsCompressed() == false);\n    CKey key1C = bsecret1C.GetKey();\n    BOOST_CHECK(key1C.IsCompressed() == true);\n    CKey key2C = bsecret2C.GetKey();\n    BOOST_CHECK(key2C.IsCompressed() == true);\n\n    CPubKey pubkey1  = key1. GetPubKey();\n    CPubKey pubkey2  = key2. GetPubKey();\n    CPubKey pubkey1C = key1C.GetPubKey();\n    CPubKey pubkey2C = key2C.GetPubKey();\n\n    BOOST_CHECK(key1.VerifyPubKey(pubkey1));\n    BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));\n    BOOST_CHECK(!key1.VerifyPubKey(pubkey2));\n    BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));\n\n    BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));\n    BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));\n    BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));\n    BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));\n\n    BOOST_CHECK(!key2.VerifyPubKey(pubkey1));\n    BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));\n    BOOST_CHECK(key2.VerifyPubKey(pubkey2));\n    BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));\n\n    BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));\n    BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));\n    BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));\n    BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));\n\n    BOOST_CHECK(addr1.Get()  == CTxDestination(pubkey1.GetID()));\n    BOOST_CHECK(addr2.Get()  == CTxDestination(pubkey2.GetID()));\n    BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));\n    BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));\n\n    for (int n=0; n<16; n++)\n    {\n        std::string strMsg = strprintf(\"Very secret message %i: 11\", n);\n        uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());\n\n        // normal signatures\n\n        std::vector<unsigned char> sign1, sign2, sign1C, sign2C;\n\n        BOOST_CHECK(key1.Sign (hashMsg, sign1));\n        BOOST_CHECK(key2.Sign (hashMsg, sign2));\n        BOOST_CHECK(key1C.Sign(hashMsg, sign1C));\n        BOOST_CHECK(key2C.Sign(hashMsg, sign2C));\n\n        BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));\n        BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));\n        BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));\n        BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));\n\n        BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));\n        BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));\n        BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));\n        BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));\n\n        BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));\n        BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));\n        BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));\n        BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));\n\n        BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));\n        BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));\n        BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));\n        BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));\n\n        // compact signatures (with key recovery)\n\n        std::vector<unsigned char> csign1, csign2, csign1C, csign2C;\n\n        BOOST_CHECK(key1.SignCompact (hashMsg, csign1));\n        BOOST_CHECK(key2.SignCompact (hashMsg, csign2));\n        BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));\n        BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));\n\n        CPubKey rkey1, rkey2, rkey1C, rkey2C;\n\n        BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));\n        BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));\n        BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));\n        BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));\n\n        BOOST_CHECK(rkey1  == pubkey1);\n        BOOST_CHECK(rkey2  == pubkey2);\n        BOOST_CHECK(rkey1C == pubkey1C);\n        BOOST_CHECK(rkey2C == pubkey2C);\n    }\n\n    // test deterministic signing\n    std::vector<unsigned char> detsig, detsigc;\n    std::string strMsg = \"Very deterministic message\";\n    uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());\n    BOOST_CHECK(key1.Sign(hashMsg, detsig));\n    BOOST_CHECK(key1C.Sign(hashMsg, detsigc));\n    BOOST_CHECK(detsig == detsigc);\n    BOOST_CHECK(detsig == ParseHex(\"3045022100c3d356b802455485663f3a8ed55e2d10ef1d0966df990e02ead6100486e54a050220129c353117e1a691225e439d77b93e2e282c70ea766cef05464838b7943ee9e4\"));\n    BOOST_CHECK(key2.Sign(hashMsg, detsig));\n    BOOST_CHECK(key2C.Sign(hashMsg, detsigc));\n    BOOST_CHECK(detsig == detsigc);\n    BOOST_CHECK(detsig == ParseHex(\"304402204cee644c042adf26537e2e5060f38e0b68f776b91830d396b4abf86be152ecce0220662faa6458e8cedbe8e37ffff3b1212d5c9d141cfdcc9a70038ef3ff4d75119a\"));\n    BOOST_CHECK(key1.SignCompact(hashMsg, detsig));\n    BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc));\n    BOOST_CHECK(detsig == ParseHex(\"1cc3d356b802455485663f3a8ed55e2d10ef1d0966df990e02ead6100486e54a05129c353117e1a691225e439d77b93e2e282c70ea766cef05464838b7943ee9e4\"));\n    BOOST_CHECK(detsigc == ParseHex(\"20c3d356b802455485663f3a8ed55e2d10ef1d0966df990e02ead6100486e54a05129c353117e1a691225e439d77b93e2e282c70ea766cef05464838b7943ee9e4\"));\n    BOOST_CHECK(key2.SignCompact(hashMsg, detsig));\n    BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc));\n    BOOST_CHECK(detsig == ParseHex(\"1c4cee644c042adf26537e2e5060f38e0b68f776b91830d396b4abf86be152ecce662faa6458e8cedbe8e37ffff3b1212d5c9d141cfdcc9a70038ef3ff4d75119a\"));\n    BOOST_CHECK(detsigc == ParseHex(\"204cee644c042adf26537e2e5060f38e0b68f776b91830d396b4abf86be152ecce662faa6458e8cedbe8e37ffff3b1212d5c9d141cfdcc9a70038ef3ff4d75119a\"));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/limitedmap_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"limitedmap.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(limitedmap_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(limitedmap_test)\n{\n    // create a limitedmap capped at 10 items\n    limitedmap<int, int> map(10);\n\n    // check that the max size is 10\n    BOOST_CHECK(map.max_size() == 10);\n\n    // check that it's empty\n    BOOST_CHECK(map.size() == 0);\n\n    // insert (-1, -1)\n    map.insert(std::pair<int, int>(-1, -1));\n\n    // make sure that the size is updated\n    BOOST_CHECK(map.size() == 1);\n\n    // make sure that the new item is in the map\n    BOOST_CHECK(map.count(-1) == 1);\n\n    // insert 10 new items\n    for (int i = 0; i < 10; i++) {\n        map.insert(std::pair<int, int>(i, i + 1));\n    }\n\n    // make sure that the map now contains 10 items...\n    BOOST_CHECK(map.size() == 10);\n\n    // ...and that the first item has been discarded\n    BOOST_CHECK(map.count(-1) == 0);\n\n    // iterate over the map, both with an index and an iterator\n    limitedmap<int, int>::const_iterator it = map.begin();\n    for (int i = 0; i < 10; i++) {\n        // make sure the item is present\n        BOOST_CHECK(map.count(i) == 1);\n\n        // use the iterator to check for the expected key and value\n        BOOST_CHECK(it->first == i);\n        BOOST_CHECK(it->second == i + 1);\n\n        // use find to check for the value\n        BOOST_CHECK(map.find(i)->second == i + 1);\n\n        // update and recheck\n        map.update(it, i + 2);\n        BOOST_CHECK(map.find(i)->second == i + 2);\n\n        it++;\n    }\n\n    // check that we've exhausted the iterator\n    BOOST_CHECK(it == map.end());\n\n    // resize the map to 5 items\n    map.max_size(5);\n\n    // check that the max size and size are now 5\n    BOOST_CHECK(map.max_size() == 5);\n    BOOST_CHECK(map.size() == 5);\n\n    // check that items less than 5 have been discarded\n    // and items greater than 5 are retained\n    for (int i = 0; i < 10; i++) {\n        if (i < 5) {\n            BOOST_CHECK(map.count(i) == 0);\n        } else {\n            BOOST_CHECK(map.count(i) == 1);\n        }\n    }\n\n    // erase some items not in the map\n    for (int i = 100; i < 1000; i += 100) {\n        map.erase(i);\n    }\n\n    // check that the size is unaffected\n    BOOST_CHECK(map.size() == 5);\n\n    // erase the remaining elements\n    for (int i = 5; i < 10; i++) {\n        map.erase(i);\n    }\n\n    // check that the map is now empty\n    BOOST_CHECK(map.empty());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/main_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"chainparams.h\"\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"unity/signals.h\"\n\n#include \"test/test.h\"\n\n#include <boost/signals2/signal.hpp>\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)\n\nBOOST_AUTO_TEST_CASE(block_subsidy_test)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    uint64_t nP4First = chainParams->GetConsensus().pow2Phase4FirstBlockHeight;\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1).mining,                                                                     COIN * 170000000);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(250000).mining,                                                                COIN * 1000);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(250001).mining,                                                                COIN * 100);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1030001).total,                                                                COIN * 110);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(nP4First).total,                                                               COIN * 110);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(nP4First+1).total,                                                             COIN * 120);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226651).total,                                                                COIN * 120);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226652).total,                                                                COIN * 200);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226652).total-GetBlockSubsidy(1226652).dev-GetBlockSubsidy(1226652).witness,  COIN * 90);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226652).mining,                                                               COIN * 90);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226652).dev,                                                                  COIN * 80);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1226652).witness,                                                              COIN * 30);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228003).total,                                                                COIN * 200);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228004).total,                                                                COIN * 160);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228004).total-GetBlockSubsidy(1228004).dev-GetBlockSubsidy(1228004).witness,  COIN * 50);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228004).mining,                                                               COIN * 50);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228004).dev,                                                                  COIN * 80);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1228004).witness,                                                              COIN * 30);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400000).mining,                                                               COIN * 50);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400000).dev,                                                                  COIN * 80);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400000).witness,                                                              COIN * 30);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400001).mining,                                                               COIN * 10);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400001).witness,                                                              COIN * 15);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1400001).dev,                                                                  COIN * 65);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619997).mining,                                                               COIN * 10);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619997).witness,                                                              COIN * 15);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619997).dev,                                                                  COIN * 100'000'000);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619998).mining,                                                               COIN * 10);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619998).witness,                                                              COIN * 15);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(1619998).dev,                                                                  COIN * 0);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242500).mining,                                                               COIN * 5);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242500).witness,                                                              CENT * 750);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242500).dev,                                                                  COIN * 0); \n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242501).mining,                                                               COIN * 5);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242501).witness,                                                              CENT * 750);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(2242501).dev,                                                                  CENT * 0);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(433'009'989).mining,                                                                     0);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(433'009'989).witness,                                                                     0);\n    BOOST_CHECK_EQUAL(GetBlockSubsidy(433'009'989).dev,                                                                     0);\n}\n\n\nBOOST_AUTO_TEST_CASE(subsidy_limit_test)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    CAmount nSum = 0;\n    for (uint64_t nHeight = 0; nHeight < Params().GetConsensus().finalSubsidyBlockHeight + 200000; nHeight++)\n    {\n        CAmount nSubsidy = GetBlockSubsidy(nHeight).total;\n        nSum += nSubsidy;\n        BOOST_CHECK(MoneyRange(nSum));\n    }\n    BOOST_CHECK_EQUAL(nSum, 700'000'000*COIN);\n}\n\nbool ReturnFalse() { return false; }\nbool ReturnTrue() { return true; }\n\nBOOST_AUTO_TEST_CASE(test_combiner_all)\n{\n    boost::signals2::signal<bool (), BooleanAndAllReturnValues> Test;\n    BOOST_CHECK(Test());\n    Test.connect(&ReturnFalse);\n    BOOST_CHECK(!Test());\n    Test.connect(&ReturnTrue);\n    BOOST_CHECK(!Test());\n    Test.disconnect(&ReturnFalse);\n    BOOST_CHECK(Test());\n    Test.disconnect(&ReturnTrue);\n    BOOST_CHECK(Test());\n}\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/mempool_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"policy/policy.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n#include <list>\n#include <vector>\n\nBOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)\n\nBOOST_AUTO_TEST_CASE(MempoolRemoveTest)\n{\n    // Test CTxMemPool::remove functionality\n\n    TestMemPoolEntryHelper entry;\n    // Parent transaction with three children,\n    // and three grand-children:\n    CMutableTransaction txParent(TEST_DEFAULT_TX_VERSION);\n    txParent.vin.resize(1);\n    txParent.vin[0].scriptSig = CScript() << OP_11;\n    txParent.vout.resize(3);\n    for (int i = 0; i < 3; i++)\n    {\n        txParent.vout[i].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n        txParent.vout[i].nValue = 33000LL;\n    }\n    CMutableTransaction txChild[3] = { CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                       CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                       CMutableTransaction(TEST_DEFAULT_TX_VERSION)\n                                     };\n    for (int i = 0; i < 3; i++)\n    {\n        txChild[i].vin.resize(1);\n        txChild[i].vin[0].scriptSig = CScript() << OP_11;\n        COutPoint changePrevOut = txChild[i].vin[0].GetPrevOut();\n        changePrevOut.setHash(txParent.GetHash());\n        changePrevOut.n = i;\n        txChild[i].vin[0].SetPrevOut(changePrevOut);\n        txChild[i].vout.resize(1);\n        txChild[i].vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n        txChild[i].vout[0].nValue = 11000LL;\n    }\n    CMutableTransaction txGrandChild[3] = { CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                            CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                            CMutableTransaction(TEST_DEFAULT_TX_VERSION)\n                                          };\n    for (int i = 0; i < 3; i++)\n    {\n        txGrandChild[i].vin.resize(1);\n        txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;\n        COutPoint changePrevOut = txChild[i].vin[0].GetPrevOut();\n        changePrevOut.setHash(txChild[i].GetHash());\n        changePrevOut.n = 0;\n        txGrandChild[i].vin[0].SetPrevOut(changePrevOut);\n        txGrandChild[i].vout.resize(1);\n        txGrandChild[i].vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n        txGrandChild[i].vout[0].nValue = 11000LL;\n    }\n\n\n    CTxMemPool testPool;\n\n    // Nothing in pool, remove should do nothing:\n    unsigned int poolSize = testPool.size();\n    testPool.removeRecursive(txParent);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize);\n\n    // Just the parent:\n    testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));\n    poolSize = testPool.size();\n    testPool.removeRecursive(txParent);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);\n\n    // Parent, children, grandchildren:\n    testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent));\n    for (int i = 0; i < 3; i++)\n    {\n        testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i]));\n        testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));\n    }\n    // Remove Child[0], GrandChild[0] should be removed:\n    poolSize = testPool.size();\n    testPool.removeRecursive(txChild[0]);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);\n    // ... make sure grandchild and child are gone:\n    poolSize = testPool.size();\n    testPool.removeRecursive(txGrandChild[0]);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize);\n    poolSize = testPool.size();\n    testPool.removeRecursive(txChild[0]);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize);\n    // Remove parent, all children/grandchildren should go:\n    poolSize = testPool.size();\n    testPool.removeRecursive(txParent);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);\n    BOOST_CHECK_EQUAL(testPool.size(), 0U);\n\n    // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)\n    for (int i = 0; i < 3; i++)\n    {\n        testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i]));\n        testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i]));\n    }\n    // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be\n    // put into the mempool (maybe because it is non-standard):\n    poolSize = testPool.size();\n    testPool.removeRecursive(txParent);\n    BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);\n    BOOST_CHECK_EQUAL(testPool.size(), 0U);\n}\n\ntemplate<typename name>\nvoid CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)\n{\n    BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());\n    typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();\n    int count=0;\n    for (; it != pool.mapTx.get<name>().end(); ++it, ++count) {\n        BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(MempoolIndexingTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n\n    /* 3rd highest fee */\n    CMutableTransaction tx1 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx1.vout.resize(1);\n    tx1.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx1.vout[0].nValue = 10 * COIN;\n    pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));\n\n    /* highest fee */\n    CMutableTransaction tx2 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx2.vout.resize(1);\n    tx2.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx2.vout[0].nValue = 2 * COIN;\n    pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));\n\n    /* lowest fee */\n    CMutableTransaction tx3 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx3.vout.resize(1);\n    tx3.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx3.vout[0].nValue = 5 * COIN;\n    pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));\n\n    /* 2nd highest fee */\n    CMutableTransaction tx4 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx4.vout.resize(1);\n    tx4.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx4.vout[0].nValue = 6 * COIN;\n    pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));\n\n    /* equal fee rate to tx1, but newer */\n    CMutableTransaction tx5 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx5.vout.resize(1);\n    tx5.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx5.vout[0].nValue = 11 * COIN;\n    entry.nTime = 1;\n    pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));\n    BOOST_CHECK_EQUAL(pool.size(), 5U);\n\n    std::vector<std::string> sortedOrder;\n    sortedOrder.resize(5);\n    sortedOrder[0] = tx3.GetHash().ToString(); // 0\n    sortedOrder[1] = tx5.GetHash().ToString(); // 10000\n    sortedOrder[2] = tx1.GetHash().ToString(); // 10000\n    sortedOrder[3] = tx4.GetHash().ToString(); // 15000\n    sortedOrder[4] = tx2.GetHash().ToString(); // 20000\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    /* low fee but with high fee child */\n    /* tx6 -> tx7 -> tx8, tx9 -> tx10 */\n    CMutableTransaction tx6 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx6.vout.resize(1);\n    tx6.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx6.vout[0].nValue = 20 * COIN;\n    pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));\n    BOOST_CHECK_EQUAL(pool.size(), 6U);\n    // Check that at this point, tx6 is sorted low\n    sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    CTxMemPool::setEntries setAncestors;\n    setAncestors.insert(pool.mapTx.find(tx6.GetHash()));\n    CMutableTransaction tx7 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx7.vin.resize(1);\n    tx7.vin[0].SetPrevOut(COutPoint(tx6.GetHash(), 0));\n    tx7.vin[0].scriptSig = CScript() << OP_11;\n    tx7.vout.resize(2);\n    tx7.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx7.vout[0].nValue = 10 * COIN;\n    tx7.vout[1].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx7.vout[1].nValue = 1 * COIN;\n\n    CTxMemPool::setEntries setAncestorsCalculated;\n    std::string dummy;\n    BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);\n    BOOST_CHECK(setAncestorsCalculated == setAncestors);\n\n    pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors);\n    BOOST_CHECK_EQUAL(pool.size(), 7U);\n\n    // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...\n    sortedOrder.erase(sortedOrder.begin());\n    sortedOrder.push_back(tx6.GetHash().ToString());\n    sortedOrder.push_back(tx7.GetHash().ToString());\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    /* low fee child of tx7 */\n    CMutableTransaction tx8 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx8.vin.resize(1);\n    tx8.vin[0].SetPrevOut(COutPoint(tx7.GetHash(), 0));\n    tx8.vin[0].scriptSig = CScript() << OP_11;\n    tx8.vout.resize(1);\n    tx8.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx8.vout[0].nValue = 10 * COIN;\n    setAncestors.insert(pool.mapTx.find(tx7.GetHash()));\n    pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors);\n\n    // Now tx8 should be sorted low, but tx6/tx both high\n    sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    /* low fee child of tx7 */\n    CMutableTransaction tx9 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx9.vin.resize(1);\n    tx9.vin[0].SetPrevOut(COutPoint(tx7.GetHash(), 1));\n    tx9.vin[0].scriptSig = CScript() << OP_11;\n    tx9.vout.resize(1);\n    tx9.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx9.vout[0].nValue = 1 * COIN;\n    pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors);\n\n    // tx9 should be sorted low\n    BOOST_CHECK_EQUAL(pool.size(), 9U);\n    sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    std::vector<std::string> snapshotOrder = sortedOrder;\n\n    setAncestors.insert(pool.mapTx.find(tx8.GetHash()));\n    setAncestors.insert(pool.mapTx.find(tx9.GetHash()));\n    /* tx10 depends on tx8 and tx9 and has a high fee*/\n    CMutableTransaction tx10 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx10.vin.resize(2);\n    tx10.vin[0].SetPrevOut(COutPoint(tx8.GetHash(), 0));\n    tx10.vin[0].scriptSig = CScript() << OP_11;\n    tx10.vin[1].SetPrevOut(COutPoint(tx9.GetHash(), 0));\n    tx10.vin[1].scriptSig = CScript() << OP_11;\n    tx10.vout.resize(1);\n    tx10.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx10.vout[0].nValue = 10 * COIN;\n\n    setAncestorsCalculated.clear();\n    BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(4).FromTx(tx10), setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);\n    BOOST_CHECK(setAncestorsCalculated == setAncestors);\n\n    pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors);\n\n    /**\n     *  tx8 and tx9 should both now be sorted higher\n     *  Final order after tx10 is added:\n     *\n     *  tx3 = 0 (1)\n     *  tx5 = 10000 (1)\n     *  tx1 = 10000 (1)\n     *  tx4 = 15000 (1)\n     *  tx2 = 20000 (1)\n     *  tx9 = 200k (2 txs)\n     *  tx8 = 200k (2 txs)\n     *  tx10 = 200k (1 tx)\n     *  tx6 = 2.2M (5 txs)\n     *  tx7 = 2.2M (4 txs)\n     */\n    sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning\n    sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());\n    sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());\n    sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6\n    CheckSort<descendant_score>(pool, sortedOrder);\n\n    // there should be 10 transactions in the mempool\n    BOOST_CHECK_EQUAL(pool.size(), 10U);\n\n    // Now try removing tx10 and verify the sort order returns to normal\n    pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx());\n    CheckSort<descendant_score>(pool, snapshotOrder);\n\n    pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx());\n    pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx());\n    /* Now check the sort on the mining score index.\n     * Final order should be:\n     *\n     * tx7 (2M)\n     * tx2 (20k)\n     * tx4 (15000)\n     * tx1/tx5 (10000)\n     * tx3/6 (0)\n     * (Ties resolved by hash)\n     */\n    sortedOrder.clear();\n    sortedOrder.push_back(tx7.GetHash().ToString());\n    sortedOrder.push_back(tx2.GetHash().ToString());\n    sortedOrder.push_back(tx4.GetHash().ToString());\n    if (tx1.GetHash() < tx5.GetHash()) {\n        sortedOrder.push_back(tx5.GetHash().ToString());\n        sortedOrder.push_back(tx1.GetHash().ToString());\n    } else {\n        sortedOrder.push_back(tx1.GetHash().ToString());\n        sortedOrder.push_back(tx5.GetHash().ToString());\n    }\n    if (tx3.GetHash() < tx6.GetHash()) {\n        sortedOrder.push_back(tx6.GetHash().ToString());\n        sortedOrder.push_back(tx3.GetHash().ToString());\n    } else {\n        sortedOrder.push_back(tx3.GetHash().ToString());\n        sortedOrder.push_back(tx6.GetHash().ToString());\n    }\n    CheckSort<mining_score>(pool, sortedOrder);\n}\n\nBOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n\n    /* 3rd highest fee */\n    CMutableTransaction tx1 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx1.vout.resize(1);\n    tx1.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx1.vout[0].nValue = 10 * COIN;\n    pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));\n\n    /* highest fee */\n    CMutableTransaction tx2 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx2.vout.resize(1);\n    tx2.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx2.vout[0].nValue = 2 * COIN;\n    pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));\n\n    /* lowest fee */\n    CMutableTransaction tx3 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx3.vout.resize(1);\n    tx3.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx3.vout[0].nValue = 5 * COIN;\n    pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));\n\n    /* 2nd highest fee */\n    CMutableTransaction tx4 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx4.vout.resize(1);\n    tx4.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx4.vout[0].nValue = 6 * COIN;\n    pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));\n\n    /* equal fee rate to tx1, but newer */\n    CMutableTransaction tx5 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx5.vout.resize(1);\n    tx5.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx5.vout[0].nValue = 11 * COIN;\n    pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));\n    BOOST_CHECK_EQUAL(pool.size(), 5U);\n\n    std::vector<std::string> sortedOrder;\n    sortedOrder.resize(5);\n    sortedOrder[0] = tx2.GetHash().ToString(); // 20000\n    sortedOrder[1] = tx4.GetHash().ToString(); // 15000\n    // tx1 and tx5 are both 10000\n    // Ties are broken by hash, not timestamp, so determine which\n    // hash comes first.\n    if (tx1.GetHash() < tx5.GetHash()) {\n        sortedOrder[2] = tx1.GetHash().ToString();\n        sortedOrder[3] = tx5.GetHash().ToString();\n    } else {\n        sortedOrder[2] = tx5.GetHash().ToString();\n        sortedOrder[3] = tx1.GetHash().ToString();\n    }\n    sortedOrder[4] = tx3.GetHash().ToString(); // 0\n\n    CheckSort<ancestor_score>(pool, sortedOrder);\n\n    /* low fee parent with high fee child */\n    /* tx6 (0) -> tx7 (high) */\n    CMutableTransaction tx6 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx6.vout.resize(1);\n    tx6.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx6.vout[0].nValue = 20 * COIN;\n\n    pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6));\n    BOOST_CHECK_EQUAL(pool.size(), 6U);\n    // Ties are broken by hash\n    if (tx3.GetHash() < tx6.GetHash())\n        sortedOrder.push_back(tx6.GetHash().ToString());\n    else\n        sortedOrder.insert(sortedOrder.end()-1,tx6.GetHash().ToString());\n\n    CheckSort<ancestor_score>(pool, sortedOrder);\n\n    CMutableTransaction tx7 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx7.vin.resize(1);\n    tx7.vin[0].SetPrevOut(COutPoint(tx6.GetHash(), 0));\n    tx7.vin[0].scriptSig = CScript() << OP_11;\n    tx7.vout.resize(1);\n    tx7.vout[0].output.scriptPubKey = CScript() << OP_11 << OP_EQUAL;\n    tx7.vout[0].nValue = 10 * COIN;\n\n    /* set the fee to just below tx2's feerate when including ancestor */\n    CAmount fee = 39999;\n\n    pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));\n    BOOST_CHECK_EQUAL(pool.size(), 7U);\n    sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());\n    CheckSort<ancestor_score>(pool, sortedOrder);\n\n    /* after tx6 is mined, tx7 should move up in the sort */\n    std::vector<CTransactionRef> vtx;\n    vtx.push_back(MakeTransactionRef(tx6));\n    pool.removeForBlock(vtx, 1);\n\n    sortedOrder.erase(sortedOrder.begin()+1);\n    // Ties are broken by hash\n    if (tx3.GetHash() < tx6.GetHash())\n        sortedOrder.pop_back();\n    else\n        sortedOrder.erase(sortedOrder.end()-2);\n    sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());\n    CheckSort<ancestor_score>(pool, sortedOrder);\n}\n\n\nBOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)\n{\n    CTxMemPool pool;\n    TestMemPoolEntryHelper entry;\n\n    CMutableTransaction tx1 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx1.vin.resize(1);\n    tx1.vin[0].scriptSig = CScript() << OP_1;\n    tx1.vout.resize(1);\n    tx1.vout[0].output.scriptPubKey = CScript() << OP_1 << OP_EQUAL;\n    tx1.vout[0].nValue = 10 * COIN;\n    pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));\n\n    CMutableTransaction tx2 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx2.vin.resize(1);\n    tx2.vin[0].scriptSig = CScript() << OP_2;\n    tx2.vout.resize(1);\n    tx2.vout[0].output.scriptPubKey = CScript() << OP_2 << OP_EQUAL;\n    tx2.vout[0].nValue = 10 * COIN;\n    pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2));\n\n    pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing\n    BOOST_CHECK(pool.exists(tx1.GetHash()));\n    BOOST_CHECK(pool.exists(tx2.GetHash()));\n\n    pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction\n    BOOST_CHECK(pool.exists(tx1.GetHash()));\n    BOOST_CHECK(!pool.exists(tx2.GetHash()));\n\n    pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2));\n    CMutableTransaction tx3 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx3.vin.resize(1);\n    tx3.vin[0].SetPrevOut(COutPoint(tx2.GetHash(), 0));\n    tx3.vin[0].scriptSig = CScript() << OP_2;\n    tx3.vout.resize(1);\n    tx3.vout[0].output.scriptPubKey = CScript() << OP_3 << OP_EQUAL;\n    tx3.vout[0].nValue = 10 * COIN;\n    pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3));\n\n    pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)\n    BOOST_CHECK(!pool.exists(tx1.GetHash()));\n    BOOST_CHECK(pool.exists(tx2.GetHash()));\n    BOOST_CHECK(pool.exists(tx3.GetHash()));\n\n    pool.TrimToSize(GetVirtualTransactionSize(tx1)); // mempool is limited to tx1's size in memory usage, so nothing fits\n    BOOST_CHECK(!pool.exists(tx1.GetHash()));\n    BOOST_CHECK(!pool.exists(tx2.GetHash()));\n    BOOST_CHECK(!pool.exists(tx3.GetHash()));\n\n    TEST_REWRITE;\n    #if 0\n    CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(tx3) + GetVirtualTransactionSize(tx2));\n    BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);\n\n    CMutableTransaction tx4 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx4.vin.resize(2);\n    tx4.vin[0].prevout.SetNull();\n    tx4.vin[0].scriptSig = CScript() << OP_4;\n    tx4.vin[1].prevout.SetNull();\n    tx4.vin[1].scriptSig = CScript() << OP_4;\n    tx4.vout.resize(2);\n    tx4.vout[0].output.scriptPubKey = CScript() << OP_4 << OP_EQUAL;\n    tx4.vout[0].nValue = 10 * COIN;\n    tx4.vout[1].output.scriptPubKey = CScript() << OP_4 << OP_EQUAL;\n    tx4.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx5 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx5.vin.resize(2);\n    tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);\n    tx5.vin[0].scriptSig = CScript() << OP_4;\n    tx5.vin[1].prevout.SetNull();\n    tx5.vin[1].scriptSig = CScript() << OP_5;\n    tx5.vout.resize(2);\n    tx5.vout[0].output.scriptPubKey = CScript() << OP_5 << OP_EQUAL;\n    tx5.vout[0].nValue = 10 * COIN;\n    tx5.vout[1].output.scriptPubKey = CScript() << OP_5 << OP_EQUAL;\n    tx5.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx6 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx6.vin.resize(2);\n    tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);\n    tx6.vin[0].scriptSig = CScript() << OP_4;\n    tx6.vin[1].prevout.SetNull();\n    tx6.vin[1].scriptSig = CScript() << OP_6;\n    tx6.vout.resize(2);\n    tx6.vout[0].output.scriptPubKey = CScript() << OP_6 << OP_EQUAL;\n    tx6.vout[0].nValue = 10 * COIN;\n    tx6.vout[1].output.scriptPubKey = CScript() << OP_6 << OP_EQUAL;\n    tx6.vout[1].nValue = 10 * COIN;\n\n    CMutableTransaction tx7 = CMutableTransaction(TEST_DEFAULT_TX_VERSION);\n    tx7.vin.resize(2);\n    tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);\n    tx7.vin[0].scriptSig = CScript() << OP_5;\n    tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);\n    tx7.vin[1].scriptSig = CScript() << OP_6;\n    tx7.vout.resize(2);\n    tx7.vout[0].output.scriptPubKey = CScript() << OP_7 << OP_EQUAL;\n    tx7.vout[0].nValue = 10 * COIN;\n    tx7.vout[1].output.scriptPubKey = CScript() << OP_7 << OP_EQUAL;\n    tx7.vout[1].nValue = 10 * COIN;\n\n    pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));\n    pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));\n    pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));\n    pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));\n\n    // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that\n    pool.TrimToSize(pool.DynamicMemoryUsage() - 1);\n    BOOST_CHECK(pool.exists(tx4.GetHash()));\n    BOOST_CHECK(pool.exists(tx6.GetHash()));\n    BOOST_CHECK(!pool.exists(tx7.GetHash()));\n\n    if (!pool.exists(tx5.GetHash()))\n        pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));\n    pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));\n\n    pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7\n    BOOST_CHECK(pool.exists(tx4.GetHash()));\n    BOOST_CHECK(!pool.exists(tx5.GetHash()));\n    BOOST_CHECK(pool.exists(tx6.GetHash()));\n    BOOST_CHECK(!pool.exists(tx7.GetHash()));\n\n    pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));\n    pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));\n\n    std::vector<CTransactionRef> vtx;\n    SetMockTime(42);\n    SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);\n    // ... we should keep the same min fee until we get a block\n    pool.removeForBlock(vtx, 1);\n    SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);\n    // ... then feerate should drop 1/2 each halflife\n\n    SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);\n    // ... with a 1/2 halflife when mempool is < 1/2 its target size\n\n    SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);\n    // ... with a 1/4 halflife when mempool is < 1/4 its target size\n\n    SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);\n    // ... but feerate should never drop below 1000\n\n    SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);\n    BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);\n    // ... unless it has gone all the way to 0 (after getting past 1000/2)\n\n    SetMockTime(0);\n    #endif\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/merkle_tests.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/merkle.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(merkle_tests, TestingSetup)\n\n// Older version of the merkle root computation code, for comparison.\nstatic uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::vector<uint256>& vMerkleTree)\n{\n    vMerkleTree.clear();\n    vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.\n    for (std::vector<CTransactionRef>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)\n        vMerkleTree.push_back((*it)->GetHash());\n    int j = 0;\n    bool mutated = false;\n    for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)\n    {\n        for (int i = 0; i < nSize; i += 2)\n        {\n            int i2 = std::min(i+1, nSize-1);\n            if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {\n                // Two identical hashes at the end of the list at a particular level.\n                mutated = true;\n            }\n            vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(),\n                                       vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end()));\n        }\n        j += nSize;\n    }\n    if (fMutated) {\n        *fMutated = mutated;\n    }\n    return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());\n}\n\n// Older version of the merkle branch computation code, for comparison.\nstatic std::vector<uint256> BlockGetMerkleBranch(const CBlock& block, const std::vector<uint256>& vMerkleTree, int nIndex)\n{\n    std::vector<uint256> vMerkleBranch;\n    int j = 0;\n    for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)\n    {\n        int i = std::min(nIndex^1, nSize-1);\n        vMerkleBranch.push_back(vMerkleTree[j+i]);\n        nIndex >>= 1;\n        j += nSize;\n    }\n    return vMerkleBranch;\n}\n\nstatic inline int ctz(uint32_t i) {\n    if (i == 0) return 0;\n    int j = 0;\n    while (!(i & 1)) {\n        j++;\n        i >>= 1;\n    }\n    return j;\n}\n\nBOOST_AUTO_TEST_CASE(merkle_test)\n{\n    for (int i = 0; i < 32; i++) {\n        // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes.\n        int ntx = (i <= 16) ? i : 17 + (InsecureRandRange(4000));\n        // Try up to 3 mutations.\n        for (int mutate = 0; mutate <= 3; mutate++) {\n            int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first.\n            if (duplicate1 >= ntx) break; // Duplication of the entire tree results in a different root (it adds a level).\n            int ntx1 = ntx + duplicate1; // The resulting number of transactions after the first duplication.\n            int duplicate2 = mutate >= 2 ? 1 << ctz(ntx1) : 0; // Likewise for the second mutation.\n            if (duplicate2 >= ntx1) break;\n            int ntx2 = ntx1 + duplicate2;\n            int duplicate3 = mutate >= 3 ? 1 << ctz(ntx2) : 0; // And for the third mutation.\n            if (duplicate3 >= ntx2) break;\n            int ntx3 = ntx2 + duplicate3;\n            // Build a block with ntx different transactions.\n            CBlock block;\n            block.vtx.resize(ntx);\n            for (int j = 0; j < ntx; j++) {\n                CMutableTransaction mtx(TEST_DEFAULT_TX_VERSION);\n                mtx.nLockTime = j;\n                block.vtx[j] = MakeTransactionRef(std::move(mtx));\n            }\n            // Compute the root of the block before mutating it.\n            bool unmutatedMutated = false;\n            uint256 unmutatedRoot = BlockMerkleRoot(block, &unmutatedMutated);\n            BOOST_CHECK(unmutatedMutated == false);\n            // Optionally mutate by duplicating the last transactions, resulting in the same merkle root.\n            block.vtx.resize(ntx3);\n            for (int j = 0; j < duplicate1; j++) {\n                block.vtx[ntx + j] = block.vtx[ntx + j - duplicate1];\n            }\n            for (int j = 0; j < duplicate2; j++) {\n                block.vtx[ntx1 + j] = block.vtx[ntx1 + j - duplicate2];\n            }\n            for (int j = 0; j < duplicate3; j++) {\n                block.vtx[ntx2 + j] = block.vtx[ntx2 + j - duplicate3];\n            }\n            // Compute the merkle root and merkle tree using the old mechanism.\n            bool oldMutated = false;\n            std::vector<uint256> merkleTree;\n            uint256 oldRoot = BlockBuildMerkleTree(block, &oldMutated, merkleTree);\n            // Compute the merkle root using the new mechanism.\n            bool newMutated = false;\n            uint256 newRoot = BlockMerkleRoot(block, &newMutated);\n            BOOST_CHECK(oldRoot == newRoot);\n            BOOST_CHECK(newRoot == unmutatedRoot);\n            BOOST_CHECK((newRoot == uint256()) == (ntx == 0));\n            BOOST_CHECK(oldMutated == newMutated);\n            BOOST_CHECK(newMutated == !!mutate);\n            // If no mutation was done (once for every ntx value), try up to 16 branches.\n            if (mutate == 0) {\n                for (int loop = 0; loop < std::min(ntx, 16); loop++) {\n                    // If ntx <= 16, try all branches. Otherwise, try 16 random ones.\n                    int mtx = loop;\n                    if (ntx > 16) {\n                        mtx = InsecureRandRange(ntx);\n                    }\n                    std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);\n                    std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);\n                    BOOST_CHECK(oldBranch == newBranch);\n                    BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);\n                }\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/miner_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chainparams.h\"\n#include \"coins.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/merkle.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"generation/generation.h\"\n#include \"generation/miner.h\"\n#include \"policy/policy.h\"\n#include \"pubkey.h\"\n#include \"script/standard.h\"\n#include \"txmempool.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/wallet.h>\n#endif\n\n#include \"test/test.h\"\n\n#include <memory>\n\n#include <boost/test/unit_test.hpp>\n#include <boost/format.hpp>\n\n// The test was on MAIN before. Switched it to REGTEST for faster generation of the blockinfo table\n// might want to redo this on MAIN.\nstruct RegtestingSetup : public TestingSetup {\n    RegtestingSetup() : TestingSetup(CBaseChainParams::REGTESTLEGACY) {\n\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE(miner_tests, RegtestingSetup)\n\nstatic CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);\n\n#if 0\nstatic BlockAssembler AssemblerForTest(const CChainParams& params) {\n    BlockAssembler::Options options;\n\n    options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;\n    options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;\n    options.blockMinFeeRate = blockMinFeeRate;\n    return BlockAssembler(params, options);\n}\n\nstatic\nstruct {\n    unsigned char extranonce;\n    unsigned int nonce;\n} blockinfo[] = {\n    { 4, 2}, { 2, 0}, { 1, 6}, { 1, 2},\n    { 2, 1}, { 2, 0}, { 1, 1}, { 2, 0},\n    { 2, 1}, { 1, 2}, { 1, 1}, { 2, 4},\n    { 2, 0}, { 1, 1}, { 2, 1}, { 2, 0},\n    { 1, 0}, { 2, 1}, { 1, 0}, { 1, 1},\n    { 3, 1}, { 2, 0}, { 2, 1}, { 1, 1},\n    { 2, 1}, { 1, 5}, { 2, 1}, { 2, 0},\n    { 2, 2}, { 2, 1}, { 2, 1}, { 2, 3},\n    { 1, 0}, { 2, 0}, { 2, 5}, { 1, 2},\n    { 2, 1}, { 1, 0}, { 2, 0}, { 1, 1},\n    { 1, 1}, { 3, 1}, { 2, 0}, { 5, 0},\n    { 1, 1}, { 5, 0}, { 1, 0}, { 1, 4},\n    { 1, 5}, { 2, 2}, { 1, 1}, { 1, 1},\n    { 1, 0}, { 1, 0}, { 5, 2}, { 5, 0},\n    { 1, 0}, { 1, 6}, { 6, 1}, { 2, 0},\n    { 2, 1}, { 1, 1}, { 1, 0}, { 1, 1},\n    { 2, 0}, { 2, 2}, { 1, 0}, { 1, 1},\n    { 1, 2}, { 5, 2}, { 5, 1}, { 1, 1},\n    { 1, 0}, { 2, 0}, { 2, 1}, { 1, 2},\n    { 2, 2}, { 1, 1}, { 2, 0}, { 2, 1},\n    { 1, 4}, { 1, 0}, { 1, 0}, { 5, 1},\n    { 1, 2}, { 1, 3}, { 1, 2}, { 1, 0},\n    { 1, 1}, { 1, 3}, { 1, 1}, { 2, 0},\n    { 0, 4}, { 1, 0}, { 2, 0}, { 2, 1},\n    { 2, 0}, { 1, 0}, { 1, 0}, { 1, 0},\n    { 1, 0}, { 1, 3}, { 1, 4}, { 5, 2},\n    { 2, 1}, { 1, 2}, { 1, 0}, { 1, 2},\n    { 2, 0}, { 2, 0}\n};\n#endif\n\nCBlockIndex CreateBlockIndex(int nHeight)\n{\n    CBlockIndex index;\n    index.nHeight = nHeight;\n    index.pprev = chainActive.Tip();\n    return index;\n}\n\nbool TestSequenceLocks(const CTransaction &tx, int flags)\n{\n    LOCK(mempool.cs);\n    return CheckSequenceLocks(tx, flags);\n}\n\n// Test suite for ancestor feerate transaction selection.\n// Implemented as an additional function, rather than a separate test case,\n// to allow reusing the blockchain created in CreateNewBlock_validity.\n#if 0\nstatic void TestPackageSelection(const CChainParams& chainparams, std::shared_ptr<CReserveKeyOrScript> reservedScript, std::vector<CTransactionRef>& txFirst)\n{\n    // Test the ancestor feerate transaction selection.\n    TestMemPoolEntryHelper entry;\n\n    // Test that a medium fee transaction will be selected after a higher fee\n    // rate package with a low fee rate parent.\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    tx.vin.resize(1);\n    tx.vin[0].scriptSig = CScript() << OP_1;\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vin[0].prevout.n = 0;\n    tx.vout.resize(1);\n    tx.vout[0].nValue = 5000000000LL - 1000;\n    // This tx has a low fee: 1000 satoshis\n    uint256 hashParentTx = tx.GetHash(); // save this txid for later use\n    mempool.addUnchecked(hashParentTx, entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n\n    // This tx has a medium fee: 10000 satoshis\n    tx.vin[0].prevout.setHash(txFirst[1]->GetHash());\n    tx.vout[0].nValue = 5000000000LL - 10000;\n    uint256 hashMediumFeeTx = tx.GetHash();\n    mempool.addUnchecked(hashMediumFeeTx, entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n\n    // This tx has a high fee, but depends on the first transaction\n    tx.vin[0].prevout.setHash(hashParentTx);\n    tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee\n    uint256 hashHighFeeTx = tx.GetHash();\n    mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));\n\n    std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript);\n    BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);\n    BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);\n    BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx);\n\n    // Test that a package below the block min tx fee doesn't get included\n    tx.vin[0].prevout.setHash(hashHighFeeTx);\n    tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee\n    uint256 hashFreeTx = tx.GetHash();\n    mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx));\n    size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);\n\n    // Calculate a fee on child transaction that will put the package just\n    // below the block min tx fee (assuming 1 child tx of the same size).\n    CAmount feeToUse = blockMinFeeRate.GetFee(2*freeTxSize) - 1;\n\n    tx.vin[0].prevout.setHash(hashFreeTx);\n    tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;\n    uint256 hashLowFeeTx = tx.GetHash();\n    mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx));\n    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript);\n    // Verify that the free tx and the low fee tx didn't get selected\n    for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {\n        BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);\n        BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx);\n    }\n\n    // Test that packages above the min relay fee do get included, even if one\n    // of the transactions is below the min relay fee\n    // Remove the low fee transaction and replace with a higher fee transaction\n    mempool.removeRecursive(tx);\n    tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee\n    hashLowFeeTx = tx.GetHash();\n    mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx));\n    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript);\n    BOOST_CHECK(pblocktemplate->block.vtx.size() >= 5 && pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);\n    BOOST_CHECK(pblocktemplate->block.vtx.size() >= 6 && pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);\n\n    // Test that transaction selection properly updates ancestor fee\n    // calculations as ancestor transactions get included in a block.\n    // Add a 0-fee transaction that has 2 outputs.\n    tx.vin[0].prevout.setHash(txFirst[2]->GetHash());\n    tx.vout.resize(2);\n    tx.vout[0].nValue = 5000000000LL - 100000000;\n    tx.vout[1].nValue = 100000000; // 1NLG output\n    uint256 hashFreeTx2 = tx.GetHash();\n    mempool.addUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx));\n\n    // This tx can't be mined by itself\n    tx.vin[0].prevout.setHash(hashFreeTx2);\n    tx.vout.resize(1);\n    feeToUse = blockMinFeeRate.GetFee(freeTxSize);\n    tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;\n    uint256 hashLowFeeTx2 = tx.GetHash();\n    mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));\n    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript);\n\n    // Verify that this tx isn't selected.\n    for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {\n        BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2);\n        BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2);\n    }\n\n    // This tx will be mineable, and should cause hashLowFeeTx2 to be selected\n    // as well.\n    tx.vin[0].prevout.n = 1;\n    tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee\n    mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx));\n    pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript);\n    BOOST_CHECK(pblocktemplate->block.vtx.size() >= 9 && pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);\n}\n#endif\n\n// Define PRINT_TEST_NONCES_CPP to generate the blockinfo table once\n// #define PRINT_TEST_NONCES_CPP\n\n#if defined(PRINT_TEST_NONCES_CPP)\nvoid mineTestBlock(CBlock* pblock)\n{\n    arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);\n\n    // Check if something found\n    arith_uint256 hashMined;\n    while (true)\n    {\n        hashMined = UintToArith256(pblock->GetPoWHash());\n\n        // Found a solution\n        if (hashMined <= hashTarget)\n            return;\n\n        pblock->nNonce += 1;\n    }\n}\n#endif\n\n// NOTE: These tests rely on CreateNewBlock doing its own self-validation!\nBOOST_AUTO_TEST_CASE(CreateNewBlock_validity)\n{\n    TEST_REWRITE;\n    #if 0\n    // Note that by default, these tests run with size accounting enabled.\n    const CChainParams& chainparams = Params();\n    CScript scriptPubKey = CScript() << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f\") << OP_CHECKSIG;\n    std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n    std::unique_ptr<CBlockTemplate> pblocktemplate;\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION),tx2(TEST_DEFAULT_TX_VERSION);\n    CScript script;\n    uint256 hash;\n    TestMemPoolEntryHelper entry;\n    entry.nFee = 11;\n    entry.nHeight = 11;\n\n    LOCK(cs_main);\n    fCheckpointsEnabled = false;\n\n    // We can't make transactions until we have inputs\n    // Therefore, load 100 blocks :)\n    int baseheight = 0;\n    std::vector<CTransactionRef> txFirst;\n    for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)\n    {\n        // Simple block creation, nothing special yet:\n        // this used to be outside the loop, re-using the same block template. However the block reward changes within\n        // the 100 blocks, therefore it's moved in this loop\n        BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n        CBlock *pblock = &pblocktemplate->block; // pointer for convenience\n        pblock->nVersion = 1;\n        pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;\n        CMutableTransaction txCoinbase(*pblock->vtx[0]);\n        txCoinbase.nVersion = 1;\n        txCoinbase.vin[0].scriptSig = CScript();\n        txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);\n        txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());\n        txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)\n        txCoinbase.vout[0].output.scriptPubKey = CScript();\n        pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));\n        if (txFirst.size() == 0)\n            baseheight = chainActive.Height();\n        if (txFirst.size() < 4)\n            txFirst.push_back(pblock->vtx[0]);\n        pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);\n#if defined(PRINT_TEST_NONCES_CPP)\n        mineTestBlock(pblock);\n        if (i % 4 == 0)\n            std::cout << \"\\n    \";\n        std::cout << boost::format(\"{ %1%, %2%}, \") % int(blockinfo[i].extranonce) % pblock->nNonce;\n#else\n        pblock->nNonce = blockinfo[i].nonce;\n#endif\n        std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);\n        BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL, false, true));\n        pblock->hashPrevBlock = pblock->GetHashLegacy();\n    }\n\n\n    // Just to make sure we can still make simple blocks\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n\n    const CAmount BLOCKSUBSIDY = 100*COIN;\n    const CAmount LOWFEE = CENT;\n    const CAmount HIGHFEE = COIN;\n    const CAmount HIGHERFEE = 4*COIN;\n\n    // block sigops > limit: 1000 CHECKMULTISIG + 1\n    tx.vin.resize(1);\n    // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG\n    tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1;\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vin[0].prevout.n = 0;\n    tx.vout.resize(1);\n    tx.vout[0].nValue = BLOCKSUBSIDY;\n    for (unsigned int i = 0; i < 1001; ++i)\n    {\n        tx.vout[0].nValue -= LOWFEE;\n        hash = tx.GetHash();\n        bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase\n        // If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails\n        mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));\n        tx.vin[0].prevout.setHash(hash);\n    }\n    BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript), std::runtime_error);\n    mempool.clear();\n\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vout[0].nValue = BLOCKSUBSIDY;\n    for (unsigned int i = 0; i < 1001; ++i)\n    {\n        tx.vout[0].nValue -= LOWFEE;\n        hash = tx.GetHash();\n        bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase\n        // If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes\n        mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));\n        tx.vin[0].prevout.setHash(hash);\n    }\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    mempool.clear();\n\n    // block size > limit\n    tx.vin[0].scriptSig = CScript();\n    // 18 * (520char + DROP) + OP_1 = 9433 bytes\n    std::vector<unsigned char> vchData(520);\n    for (unsigned int i = 0; i < 18; ++i)\n        tx.vin[0].scriptSig << vchData << OP_DROP;\n    tx.vin[0].scriptSig << OP_1;\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vout[0].nValue = BLOCKSUBSIDY;\n    for (unsigned int i = 0; i < 128; ++i)\n    {\n        tx.vout[0].nValue -= LOWFEE;\n        hash = tx.GetHash();\n        bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase\n        mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));\n        tx.vin[0].prevout.setHash(hash);\n    }\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    mempool.clear();\n\n    // orphan in mempool, template creation fails\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));\n    BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript), std::runtime_error);\n    mempool.clear();\n\n    // child with higher feerate than parent\n    tx.vin[0].scriptSig = CScript() << OP_1;\n    tx.vin[0].prevout.setHash(txFirst[1]->GetHash());\n    tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    tx.vin[0].prevout.setHash(hash);\n    tx.vin.resize(2);\n    tx.vin[1].scriptSig = CScript() << OP_1;\n    tx.vin[1].prevout.setHash(txFirst[0]->GetHash());\n    tx.vin[1].prevout.n = 0;\n    tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    mempool.clear();\n\n    // coinbase in mempool, template creation fails\n    tx.vin.resize(1);\n    tx.vin[0].prevout.SetNull();\n    tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;\n    tx.vout[0].nValue = 0;\n    hash = tx.GetHash();\n    // give it a fee so it'll get mined\n    mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));\n    BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript), std::runtime_error);\n    mempool.clear();\n\n    // invalid (pre-p2sh) txn in mempool, template creation fails\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vin[0].prevout.n = 0;\n    tx.vin[0].scriptSig = CScript() << OP_1;\n    tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;\n    script = CScript() << OP_0;\n    tx.vout[0].output.scriptPubKey = GetScriptForDestination(CScriptID(script));\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    tx.vin[0].prevout.setHash(hash);\n    tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());\n    tx.vout[0].nValue -= LOWFEE;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));\n    BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript), std::runtime_error);\n    mempool.clear();\n\n    // double spend txn pair in mempool, template creation fails\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash());\n    tx.vin[0].scriptSig = CScript() << OP_1;\n    tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;\n    tx.vout[0].output.scriptPubKey = CScript() << OP_1;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    tx.vout[0].output.scriptPubKey = CScript() << OP_2;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript), std::runtime_error);\n    mempool.clear();\n\n    // subsidy changing\n    int nHeight = chainActive.Height();\n    // Create an actual 209999-long block chain (without valid blocks).\n    while (chainActive.Tip()->nHeight < 209999) {\n        CBlockIndex* prev = chainActive.Tip();\n        CBlockIndex* next = new CBlockIndex();\n        next->phashBlock = new uint256(InsecureRand256());\n        pcoinsTip->SetBestBlock(next->GetBlockHashLegacy());\n        next->pprev = prev;\n        next->nHeight = prev->nHeight + 1;\n        next->BuildSkip();\n        chainActive.SetTip(next);\n    }\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    // Extend to a 210000-long block chain.\n    while (chainActive.Tip()->nHeight < 210000) {\n        CBlockIndex* prev = chainActive.Tip();\n        CBlockIndex* next = new CBlockIndex();\n        next->phashBlock = new uint256(InsecureRand256());\n        pcoinsTip->SetBestBlock(next->GetBlockHashLegacy());\n        next->pprev = prev;\n        next->nHeight = prev->nHeight + 1;\n        next->BuildSkip();\n        chainActive.SetTip(next);\n    }\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    // Delete the dummy blocks again.\n    while (chainActive.Tip()->nHeight > nHeight) {\n        CBlockIndex* del = chainActive.Tip();\n        chainActive.SetTip(del->pprev);\n        pcoinsTip->SetBestBlock(del->pprev->GetBlockHashLegacy());\n        delete del->phashBlock;\n        delete del;\n    }\n\n    // non-final txs in mempool\n    SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);\n    int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST;\n    // height map\n    std::vector<int> prevheights;\n\n    // relative height locked\n    tx.nVersion = 2;\n    tx.vin.resize(1);\n    prevheights.resize(1);\n    tx.vin[0].prevout.setHash(txFirst[0]->GetHash()); // only 1 transaction\n    tx.vin[0].prevout.n = 0;\n    tx.vin[0].scriptSig = CScript() << OP_1;\n    tx.vin[0].SetSequence(chainActive.Tip()->nHeight + 1, tx.nVersion, CTxInFlags::None); // txFirst[0] is the 2nd block\n    prevheights[0] = baseheight + 1;\n    tx.vout.resize(1);\n    tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;\n    tx.vout[0].output.scriptPubKey = CScript() << OP_1;\n    tx.nLockTime = 0;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));\n    BOOST_CHECK(CheckFinalTx(tx, chainActive, flags)); // Locktime passes\n    BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail\n    BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block\n\n    // relative time locked\n    tx.vin[0].prevout.setHash(txFirst[1]->GetHash());\n    tx.vin[0].SetSequence( (CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | ((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast())) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1,\n                          tx.nVersion, CTxInFlags::HasTimeBasedRelativeLock); // txFirst[1] is the 3rd block\n    prevheights[0] = baseheight + 2;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));\n    BOOST_CHECK(CheckFinalTx(tx, chainActive, flags)); // Locktime passes\n    BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail\n\n    for (int i = 0; i < 11; i++)\n        chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast\n    BOOST_CHECK(SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later\n    for (int i = 0; i < 11; i++)\n        chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP\n\n    // absolute height locked\n    tx.vin[0].prevout.setHash(txFirst[2]->GetHash());\n    tx.vin[0].SetSequence(CTxIn::SEQUENCE_FINAL - 1, tx.nVersion, CTxInFlags::HasAbsoluteLock);\n    prevheights[0] = baseheight + 3;\n    tx.nLockTime = chainActive.Tip()->nHeight + 1;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));\n    BOOST_CHECK(!CheckFinalTx(tx, chainActive, flags)); // Locktime fails\n    BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass\n    BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block\n\n    // absolute time locked\n    tx.vin[0].prevout.setHash(txFirst[3]->GetHash());\n    tx.nLockTime = chainActive.Tip()->GetMedianTimePast();\n    prevheights.resize(1);\n    prevheights[0] = baseheight + 4;\n    hash = tx.GetHash();\n    mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));\n    BOOST_CHECK(!CheckFinalTx(tx, chainActive, flags)); // Locktime fails\n    BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass\n    BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later\n\n    // mempool-dependent transactions (not added)\n    tx.vin[0].prevout.setHash(hash);\n    prevheights[0] = chainActive.Tip()->nHeight + 1;\n    tx.nLockTime = 0;\n    tx.vin[0].SetSequence(0, tx.nVersion, CTxInFlags::None);\n    BOOST_CHECK(CheckFinalTx(tx, chainActive, flags)); // Locktime passes\n    BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass\n    tx.vin[0].SetSequence(1, tx.nVersion, CTxInFlags::None);\n    BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail\n    tx.vin[0].SetSequence(0 | CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG, tx.nVersion, CTxInFlags::HasTimeBasedRelativeLock);\n    BOOST_CHECK(TestSequenceLocks(tx, flags)); // Sequence locks pass\n    tx.vin[0].SetSequence(1 | CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG, tx.nVersion, CTxInFlags::HasTimeBasedRelativeLock);\n    BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail\n\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n\n    // None of the of the absolute height/time locked tx should have made\n    // it into the template because we still check IsFinalTx in CreateNewBlock,\n    // but relative locked txs will if inconsistently added to mempool.\n    // For now these will still generate a valid template until BIP68 soft fork\n    BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3U);\n    // However if we advance height by 1 and time by 512, all of them should be mined\n    for (int i = 0; i < 11; i++)\n        chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast\n    //fixme: (PHASE5) re-enable test - clonechain doesn't like the height tampering that this test does.\n    #if 0\n    chainActive.Tip()->nHeight++;\n    SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);\n\n    BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(chainActive.Tip(), reservedScript));\n    BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);\n\n    chainActive.Tip()->nHeight--;\n    #endif\n    SetMockTime(0);\n    mempool.clear();\n\n    TestPackageSelection(chainparams, reservedScript, txFirst);\n\n    fCheckpointsEnabled = true;\n    #endif\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/multisig_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"policy/policy.h\"\n#include \"script/script.h\"\n#include \"script/script_error.h\"\n#include \"script/interpreter.h\"\n#include \"script/sign.h\"\n#include \"script/ismine.h\"\n#include \"uint256.h\"\n#include \"test/test.h\"\n\n\n\n#include <boost/test/unit_test.hpp>\n\ntypedef std::vector<unsigned char> valtype;\n\nBOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)\n\nvoid sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, int whichIn, CScript& resultScript, CSegregatedSignatureData& resultSigData)\n{\n    auto sigversion = transaction.nVersion < CTransaction::SEGSIG_ACTIVATION_VERSION ? SIGVERSION_BASE : SIGVERSION_SEGSIG;\n    auto sigtype = SIGHASH_ALL;\n    uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, sigtype, 0, sigversion);\n\n    if (sigversion != SIGVERSION_SEGSIG)\n    {\n        resultScript << OP_0; // CHECKMULTISIG bug workaround\n    }\n    for(const CKey &key : keys)\n    {\n        //Segsig keys must be compressed\n        BOOST_CHECK (sigversion != SIGVERSION_SEGSIG || key.IsCompressed());\n        \n        std::vector<unsigned char> vchSig;\n        if (sigversion == SIGVERSION_SEGSIG)\n        {\n            BOOST_CHECK(key.SignCompact(hash, vchSig));\n            vchSig.push_back((unsigned char)sigtype);\n            resultSigData.stack.push_back(vchSig);\n        }\n        else\n        {\n            BOOST_CHECK(key.Sign(hash, vchSig));\n            vchSig.push_back((unsigned char)sigtype);\n            resultScript << vchSig;\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(multisig_verify)\n{\n    unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;\n\n    ScriptError err;\n    CKey key[4];\n    CAmount amount = 0;\n    for (int i = 0; i < 4; i++)\n        key[i].MakeNewKey(true);\n\n    CScript a_and_b;\n    a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript a_or_b;\n    a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript escrow;\n    escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);  // Funding transaction\n    txFrom.vout.resize(3);\n    txFrom.vout[0].output.scriptPubKey = a_and_b;\n    txFrom.vout[1].output.scriptPubKey = a_or_b;\n    txFrom.vout[2].output.scriptPubKey = escrow;\n\n    CMutableTransaction txTo[3] = // Spending transaction\n                                { CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                  CMutableTransaction(TEST_DEFAULT_TX_VERSION),\n                                  CMutableTransaction(TEST_DEFAULT_TX_VERSION)\n                                };\n\n    for (int i = 0; i < 3; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n    }\n\n    std::vector<CKey> keys;\n    CScript scriptSig;\n    CSegregatedSignatureData scriptSigData;\n\n    // Test a AND b:\n    keys.assign(1,key[0]);\n    keys.push_back(key[1]);\n    sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n    BOOST_CHECK(scriptSigData.stack.empty());\n    BOOST_CHECK(VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    for (int i = 0; i < 4; i++)\n    {\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[i]);\n        sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n        BOOST_CHECK(scriptSigData.stack.empty());\n        BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V1, &err), strprintf(\"a&b 1: %d\", i));\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));\n\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[1]);\n        keys.push_back(key[i]);\n        sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n        BOOST_CHECK(scriptSigData.stack.empty());\n        BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V1, &err), strprintf(\"a&b 2: %d\", i));\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n    }\n\n    // Test a OR b:\n    for (int i = 0; i < 4; i++)\n    {\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[i]);\n        sign_multisig(a_or_b, keys, txTo[1], 0, scriptSig, scriptSigData);\n        BOOST_CHECK(scriptSigData.stack.empty());\n        if (i == 0 || i == 1)\n        {\n            BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, a_or_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V1, &err), strprintf(\"a|b: %d\", i));\n            BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n        }\n        else\n        {\n            BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_or_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V1, &err), strprintf(\"a|b: %d\", i));\n            BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n        }\n    }\n    scriptSig.clear();\n    scriptSigData.stack.clear();\n    scriptSig << OP_0 << OP_1;\n    BOOST_CHECK(!VerifyScript(scriptSig, a_or_b, NULL, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));\n\n\n    for (int i = 0; i < 4; i++)\n    {\n        for (int j = 0; j < 4; j++)\n        {\n            scriptSig.clear();\n            scriptSigData.stack.clear();\n            keys.assign(1,key[i]);\n            keys.push_back(key[j]);\n            sign_multisig(escrow, keys, txTo[2], 0, scriptSig, scriptSigData);\n            BOOST_CHECK(scriptSigData.stack.empty());\n            if (i < j && i < 3 && j < 3)\n            {\n                BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, escrow, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[2], 0, amount), SCRIPT_V1, &err), strprintf(\"escrow 1: %d %d\", i, j));\n                BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n            }\n            else\n            {\n                BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, escrow, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[2], 0, amount), SCRIPT_V1, &err), strprintf(\"escrow 2: %d %d\", i, j));\n                BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n            }\n        }\n    }\n}\n\n\nBOOST_AUTO_TEST_CASE(multisig_verify_segsig)\n{\n    unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;\n\n    ScriptError err;\n    CKey key[4];\n    CAmount amount = 0;\n    for (int i = 0; i < 4; i++)\n        key[i].MakeNewKey(true);\n\n    CScript a_and_b;\n    a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript a_or_b;\n    a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript escrow;\n    escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom(CTransaction::SEGSIG_ACTIVATION_VERSION);  // Funding transaction\n    txFrom.vout.resize(3);\n    txFrom.vout[0].output.scriptPubKey = a_and_b;\n    txFrom.vout[1].output.scriptPubKey = a_or_b;\n    txFrom.vout[2].output.scriptPubKey = escrow;\n\n    CMutableTransaction txTo[3] = // Spending transaction\n                                { CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION),\n                                  CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION),\n                                  CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION)\n                                };\n\n    for (int i = 0; i < 3; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n    }\n\n    std::vector<CKey> keys;\n    CScript scriptSig;\n    CSegregatedSignatureData scriptSigData;\n\n    // Test a AND b:\n    keys.assign(1,key[0]);\n    keys.push_back(key[1]);\n    sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n    BOOST_CHECK(VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V2, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    for (int i = 0; i < 4; i++)\n    {\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[i]);\n        sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n        BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V2, &err), strprintf(\"a&b 1: %d\", i));\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));\n\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[1]);\n        keys.push_back(key[i]);\n        sign_multisig(a_and_b, keys, txTo[0], 0, scriptSig, scriptSigData);\n        BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_and_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[0], 0, amount), SCRIPT_V2, &err), strprintf(\"a&b 2: %d\", i));\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n    }\n\n    // Test a OR b:\n    for (int i = 0; i < 4; i++)\n    {\n        scriptSig.clear();\n        scriptSigData.stack.clear();\n        keys.assign(1,key[i]);\n        sign_multisig(a_or_b, keys, txTo[1], 0, scriptSig, scriptSigData);\n        if (i == 0 || i == 1)\n        {\n            BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, a_or_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V2, &err), strprintf(\"a|b: %d\", i));\n            BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n        }\n        else\n        {\n            BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, a_or_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V2, &err), strprintf(\"a|b: %d\", i));\n            BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n        }\n    }\n    \n    scriptSig.clear();\n    scriptSigData.stack.clear();\n    scriptSig << OP_0 << OP_1;\n    BOOST_CHECK(!VerifyScript(scriptSig, a_or_b, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[1], 0, amount), SCRIPT_V2, &err));\n    //fixme: (PHASE5) - See fixme: (PHASE5) (SEGSIG) (DERSIG) in interpreter.cpp for why we don't test this now.\n    //BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));\n\n    for (int i = 0; i < 4; i++)\n    {\n        for (int j = 0; j < 4; j++)\n        {\n            scriptSig.clear();\n            scriptSigData.stack.clear();\n            keys.assign(1,key[i]);\n            keys.push_back(key[j]);\n            sign_multisig(escrow, keys, txTo[2], 0, scriptSig, scriptSigData);\n            if (i < j && i < 3 && j < 3)\n            {\n                BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, escrow, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[2], 0, amount), SCRIPT_V2, &err), strprintf(\"escrow 1: %d %d\", i, j));\n                BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n            }\n            else\n            {\n                BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, escrow, &scriptSigData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo[2], 0, amount), SCRIPT_V2, &err), strprintf(\"escrow 2: %d %d\", i, j));\n                BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n            }\n        }\n    }\n}\n\n\nBOOST_AUTO_TEST_CASE(multisig_IsStandard)\n{\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n        key[i].MakeNewKey(true);\n\n    txnouttype whichType;\n\n    CScript a_and_b;\n    a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n    BOOST_CHECK(::IsStandard(a_and_b, whichType));\n\n    CScript a_or_b;\n    a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n    BOOST_CHECK(::IsStandard(a_or_b, whichType));\n\n    CScript escrow;\n    escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n    BOOST_CHECK(::IsStandard(escrow, whichType));\n\n    CScript one_of_four;\n    one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;\n    BOOST_CHECK(!::IsStandard(one_of_four, whichType));\n\n    CScript malformed[6];\n    malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n    malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n    malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n    malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;\n    malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;\n    malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());\n\n    for (int i = 0; i < 6; i++)\n        BOOST_CHECK(!::IsStandard(malformed[i], whichType));\n}\n\nBOOST_AUTO_TEST_CASE(multisig_Solver1)\n{\n    // Tests Solver() that returns lists of keys that are\n    // required to satisfy a ScriptPubKey\n    //\n    // Also tests IsMine() and ExtractDestination()\n    //\n    // Note: ExtractDestination for the multisignature transactions\n    // always returns false for this release, even if you have\n    // one key that would satisfy an (a|b) or 2-of-3 keys needed\n    // to spend an escrow transaction.\n    //\n    #ifdef ENABLE_WALLET\n    CBasicKeyStore keystore, emptykeystore, partialkeystore;\n    CKey key[3];\n    CTxDestination keyaddr[3];\n    for (int i = 0; i < 3; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n        keyaddr[i] = key[i].GetPubKey().GetID();\n    }\n    partialkeystore.AddKey(key[0]);\n\n    {\n        std::vector<valtype> solutions;\n        txnouttype whichType;\n        CScript s;\n        s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;\n        BOOST_CHECK(Solver(s, whichType, solutions));\n        BOOST_CHECK(solutions.size() == 1);\n        CTxDestination addr;\n        BOOST_CHECK(ExtractDestination(s, addr));\n        BOOST_CHECK(addr == keyaddr[0]);\n        BOOST_CHECK(IsMine(keystore, s));\n        BOOST_CHECK(!IsMine(emptykeystore, s));\n    }\n    {\n        std::vector<valtype> solutions;\n        txnouttype whichType;\n        CScript s;\n        s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;\n        BOOST_CHECK(Solver(s, whichType, solutions));\n        BOOST_CHECK(solutions.size() == 1);\n        CTxDestination addr;\n        BOOST_CHECK(ExtractDestination(s, addr));\n        BOOST_CHECK(addr == keyaddr[0]);\n        BOOST_CHECK(IsMine(keystore, s));\n        BOOST_CHECK(!IsMine(emptykeystore, s));\n    }\n    {\n        std::vector<valtype> solutions;\n        txnouttype whichType;\n        CScript s;\n        s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n        BOOST_CHECK(Solver(s, whichType, solutions));\n        BOOST_CHECK_EQUAL(solutions.size(), 4U);\n        CTxDestination addr;\n        BOOST_CHECK(!ExtractDestination(s, addr));\n        BOOST_CHECK(IsMine(keystore, s));\n        BOOST_CHECK(!IsMine(emptykeystore, s));\n        BOOST_CHECK(!IsMine(partialkeystore, s));\n    }\n    {\n        std::vector<valtype> solutions;\n        txnouttype whichType;\n        CScript s;\n        s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n        BOOST_CHECK(Solver(s, whichType, solutions));\n        BOOST_CHECK_EQUAL(solutions.size(), 4U);\n        std::vector<CTxDestination> addrs;\n        int nRequired;\n        BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));\n        BOOST_CHECK(addrs[0] == keyaddr[0]);\n        BOOST_CHECK(addrs[1] == keyaddr[1]);\n        BOOST_CHECK(nRequired == 1);\n        BOOST_CHECK(IsMine(keystore, s));\n        BOOST_CHECK(!IsMine(emptykeystore, s));\n        BOOST_CHECK(!IsMine(partialkeystore, s));\n    }\n    {\n        std::vector<valtype> solutions;\n        txnouttype whichType;\n        CScript s;\n        s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n        BOOST_CHECK(Solver(s, whichType, solutions));\n        BOOST_CHECK(solutions.size() == 5);\n    }\n    #endif\n}\n\nBOOST_AUTO_TEST_CASE(multisig_Sign)\n{\n    // Test SignSignature() (and therefore the version of Solver() that signs transactions)\n    CBasicKeyStore keystore;\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n    }\n    \n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n\n    CScript a_and_b;\n    a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript a_or_b;\n    a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript escrow;\n    escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);  // Funding transaction\n    txFrom.vout.resize(3);\n    txFrom.vout[0].output.scriptPubKey = a_and_b;\n    txFrom.vout[1].output.scriptPubKey = a_or_b;\n    txFrom.vout[2].output.scriptPubKey = escrow;\n\n    // Spending transaction\n    CMutableTransaction txTo[3] = { CMutableTransaction(TEST_DEFAULT_TX_VERSION), CMutableTransaction(TEST_DEFAULT_TX_VERSION), CMutableTransaction(TEST_DEFAULT_TX_VERSION)};\n    for (int i = 0; i < 3; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n    }\n\n    for (int i = 0; i < 3; i++)\n    {\n        BOOST_CHECK_MESSAGE(SignSignature(accountsToTry, txFrom, txTo[i], 0, SIGHASH_ALL, SignType::Spend), strprintf(\"SignSignature %d\", i));\n    }\n}\n\n\nBOOST_AUTO_TEST_CASE(multisig_Sign_segsig)\n{\n    // Test SignSignature() (and therefore the version of Solver() that signs transactions)\n    CBasicKeyStore keystore;\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n    }\n    \n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n\n    CScript a_and_b;\n    a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript a_or_b;\n    a_or_b  << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CScript escrow;\n    escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom(CTransaction::SEGSIG_ACTIVATION_VERSION);  // Funding transaction\n    txFrom.vout.resize(3);\n    txFrom.vout[0].output.scriptPubKey = a_and_b;\n    txFrom.vout[1].output.scriptPubKey = a_or_b;\n    txFrom.vout[2].output.scriptPubKey = escrow;\n\n    // Spending transaction\n    CMutableTransaction txTo[3] = { CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION), CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION), CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION)};\n    for (int i = 0; i < 3; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n    }\n\n    for (int i = 0; i < 3; i++)\n    {\n        BOOST_CHECK_MESSAGE(SignSignature(accountsToTry, txFrom, txTo[i], 0, SIGHASH_ALL, SignType::Spend), strprintf(\"SignSignature %d\", i));\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/net_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#include \"addrman.h\"\n#include \"test/test.h\"\n#include <string>\n#include <boost/test/unit_test.hpp>\n#include \"hash.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"net.h\"\n#include \"netbase.h\"\n#include \"chainparams.h\"\n#include \"util.h\"\n\nclass CAddrManSerializationMock : public CAddrMan\n{\npublic:\n    virtual void Serialize(CDataStream& s) const = 0;\n\n    //! Ensure that bucket placement is always the same for testing purposes.\n    void MakeDeterministic()\n    {\n        nKey.SetNull();\n        insecure_rand = FastRandomContext(true);\n    }\n};\n\nclass CAddrManUncorrupted : public CAddrManSerializationMock\n{\npublic:\n    void Serialize(CDataStream& s) const\n    {\n        CAddrMan::Serialize(s);\n    }\n};\n\nclass CAddrManCorrupted : public CAddrManSerializationMock\n{\npublic:\n    void Serialize(CDataStream& s) const\n    {\n        // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.\n        unsigned char nVersion = 1;\n        s << nVersion;\n        s << ((unsigned char)32);\n        s << nKey;\n        s << 10; // nNew\n        s << 10; // nTried\n\n        int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);\n        s << nUBuckets;\n\n        CService serv;\n        Lookup(\"252.1.1.1\", serv, 7777, false);\n        CAddress addr = CAddress(serv, NODE_NONE);\n        CNetAddr resolved;\n        LookupHost(\"252.2.2.2\", resolved, false);\n        CAddrInfo info = CAddrInfo(addr, resolved);\n        s << info;\n    }\n};\n\nCDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)\n{\n    CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);\n    ssPeersIn << FLATDATA(Params().MessageStart());\n    ssPeersIn << _addrman;\n    std::string str = ssPeersIn.str();\n    std::vector<unsigned char> vchData(str.begin(), str.end());\n    return CDataStream(vchData, SER_DISK, CLIENT_VERSION);\n}\n\nBOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(cnode_listen_port)\n{\n    // test default\n    unsigned short port = GetListenPort();\n    BOOST_CHECK(port == Params().GetDefaultPort());\n    // test set port\n    unsigned short altPort = 12345;\n    SoftSetArg(\"-port\", std::to_string(altPort));\n    port = GetListenPort();\n    BOOST_CHECK(port == altPort);\n}\n\nBOOST_AUTO_TEST_CASE(caddrdb_read)\n{\n    CAddrManUncorrupted addrmanUncorrupted;\n    addrmanUncorrupted.MakeDeterministic();\n\n    CService addr1, addr2, addr3;\n    Lookup(\"250.7.1.1\", addr1, 9231, false);\n    Lookup(\"250.7.2.2\", addr2, 9999, false);\n    Lookup(\"250.7.3.3\", addr3, 9999, false);\n\n    // Add three addresses to new table.\n    CService source;\n    Lookup(\"252.5.1.1\", source, 9231, false);\n    addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);\n    addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);\n    addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);\n\n    // Test that the de-serialization does not throw an exception.\n    CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);\n    bool exceptionThrown = false;\n    CAddrMan addrman1;\n\n    BOOST_CHECK(addrman1.size() == 0);\n    try {\n        unsigned char pchMsgTmp[4];\n        ssPeers1 >> FLATDATA(pchMsgTmp);\n        ssPeers1 >> addrman1;\n    } catch (const std::exception& e) {\n        exceptionThrown = true;\n    }\n\n    BOOST_CHECK(addrman1.size() == 3);\n    BOOST_CHECK(exceptionThrown == false);\n\n    // Test that CAddrDB::Read creates an addrman with the correct number of addrs.\n    CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);\n\n    CAddrMan addrman2;\n    CAddrDB adb;\n    BOOST_CHECK(addrman2.size() == 0);\n    adb.Read(addrman2, ssPeers2);\n    BOOST_CHECK(addrman2.size() == 3);\n}\n\n\nBOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)\n{\n    CAddrManCorrupted addrmanCorrupted;\n    addrmanCorrupted.MakeDeterministic();\n\n    // Test that the de-serialization of corrupted addrman throws an exception.\n    CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);\n    bool exceptionThrown = false;\n    CAddrMan addrman1;\n    BOOST_CHECK(addrman1.size() == 0);\n    try {\n        unsigned char pchMsgTmp[4];\n        ssPeers1 >> FLATDATA(pchMsgTmp);\n        ssPeers1 >> addrman1;\n    } catch (const std::exception& e) {\n        exceptionThrown = true;\n    }\n    // Even through de-serialization failed addrman is not left in a clean state.\n    BOOST_CHECK(addrman1.size() == 1);\n    BOOST_CHECK(exceptionThrown);\n\n    // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.\n    CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);\n\n    CAddrMan addrman2;\n    CAddrDB adb;\n    BOOST_CHECK(addrman2.size() == 0);\n    adb.Read(addrman2, ssPeers2);\n    BOOST_CHECK(addrman2.size() == 0);\n}\n\nBOOST_AUTO_TEST_CASE(cnode_simple_test)\n{\n    NodeId id = 0;\n    int height = 0;\n\n    in_addr ipv4Addr;\n    ipv4Addr.s_addr = 0xa0b0c001;\n\n    CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);\n    std::string pszDest = \"\";\n    bool fInboundIn = false;\n\n    // Test that fFeeler is false by default.\n    std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, socket_t(get_io_context()), addr, 0, 0, CAddress(), pszDest, fInboundIn));\n    BOOST_CHECK(pnode1->fInbound == false);\n    BOOST_CHECK(pnode1->fFeeler == false);\n\n    fInboundIn = true;\n    std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, socket_t(get_io_context()), addr, 1, 1, CAddress(), pszDest, fInboundIn));\n    BOOST_CHECK(pnode2->fInbound == true);\n    BOOST_CHECK(pnode2->fFeeler == false);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/netbase_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"netbase.h\"\n#include \"test/test.h\"\n\n#include <string>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)\n\nstatic CNetAddr ResolveIP(const char* ip)\n{\n    CNetAddr addr;\n    LookupHost(ip, addr, false);\n    return addr;\n}\n\nstatic CSubNet ResolveSubNet(const char* subnet)\n{\n    CSubNet ret;\n    LookupSubNet(subnet, ret);\n    return ret;\n}\n\nBOOST_AUTO_TEST_CASE(netbase_networks)\n{\n    BOOST_CHECK(ResolveIP(\"127.0.0.1\").GetNetwork()                              == NET_UNROUTABLE);\n    BOOST_CHECK(ResolveIP(\"::1\").GetNetwork()                                    == NET_UNROUTABLE);\n    BOOST_CHECK(ResolveIP(\"8.8.8.8\").GetNetwork()                                == NET_IPV4);\n    BOOST_CHECK(ResolveIP(\"2001::8888\").GetNetwork()                             == NET_IPV6);\n    BOOST_CHECK(ResolveIP(\"FD87:D87E:EB43:edb1:8e4:3588:e546:35ca\").GetNetwork() == NET_TOR);\n\n}\n\nBOOST_AUTO_TEST_CASE(netbase_properties)\n{\n\n    BOOST_CHECK(ResolveIP(\"127.0.0.1\").IsIPv4());\n    BOOST_CHECK(ResolveIP(\"::FFFF:192.168.1.1\").IsIPv4());\n    BOOST_CHECK(ResolveIP(\"::1\").IsIPv6());\n    BOOST_CHECK(ResolveIP(\"10.0.0.1\").IsRFC1918());\n    BOOST_CHECK(ResolveIP(\"192.168.1.1\").IsRFC1918());\n    BOOST_CHECK(ResolveIP(\"172.31.255.255\").IsRFC1918());\n    BOOST_CHECK(ResolveIP(\"2001:0DB8::\").IsRFC3849());\n    BOOST_CHECK(ResolveIP(\"169.254.1.1\").IsRFC3927());\n    BOOST_CHECK(ResolveIP(\"2002::1\").IsRFC3964());\n    BOOST_CHECK(ResolveIP(\"FC00::\").IsRFC4193());\n    BOOST_CHECK(ResolveIP(\"2001::2\").IsRFC4380());\n    BOOST_CHECK(ResolveIP(\"2001:10::\").IsRFC4843());\n    BOOST_CHECK(ResolveIP(\"FE80::\").IsRFC4862());\n    BOOST_CHECK(ResolveIP(\"64:FF9B::\").IsRFC6052());\n    BOOST_CHECK(ResolveIP(\"FD87:D87E:EB43:edb1:8e4:3588:e546:35ca\").IsTor());\n    BOOST_CHECK(ResolveIP(\"127.0.0.1\").IsLocal());\n    BOOST_CHECK(ResolveIP(\"::1\").IsLocal());\n    BOOST_CHECK(ResolveIP(\"8.8.8.8\").IsRoutable());\n    BOOST_CHECK(ResolveIP(\"2001::1\").IsRoutable());\n    BOOST_CHECK(ResolveIP(\"127.0.0.1\").IsValid());\n\n}\n\nbool static TestSplitHost(std::string test, std::string host, int port)\n{\n    std::string hostOut;\n    int portOut = -1;\n    SplitHostPort(test, portOut, hostOut);\n    return hostOut == host && port == portOut;\n}\n\nBOOST_AUTO_TEST_CASE(netbase_splithost)\n{\n    BOOST_CHECK(TestSplitHost(\"www.Munt.org\", \"www.Munt.org\", -1));\n    BOOST_CHECK(TestSplitHost(\"[www.Munt.org]\", \"www.Munt.org\", -1));\n    BOOST_CHECK(TestSplitHost(\"www.Munt.org:80\", \"www.Munt.org\", 80));\n    BOOST_CHECK(TestSplitHost(\"[www.Munt.org]:80\", \"www.Munt.org\", 80));\n    BOOST_CHECK(TestSplitHost(\"127.0.0.1\", \"127.0.0.1\", -1));\n    BOOST_CHECK(TestSplitHost(\"127.0.0.1:9231\", \"127.0.0.1\", 9231));\n    BOOST_CHECK(TestSplitHost(\"[127.0.0.1]\", \"127.0.0.1\", -1));\n    BOOST_CHECK(TestSplitHost(\"[127.0.0.1]:9231\", \"127.0.0.1\", 9231));\n    BOOST_CHECK(TestSplitHost(\"::ffff:127.0.0.1\", \"::ffff:127.0.0.1\", -1));\n    BOOST_CHECK(TestSplitHost(\"[::ffff:127.0.0.1]:9231\", \"::ffff:127.0.0.1\", 9231));\n    BOOST_CHECK(TestSplitHost(\"[::]:9231\", \"::\", 9231));\n    BOOST_CHECK(TestSplitHost(\"::9231\", \"::9231\", -1));\n    BOOST_CHECK(TestSplitHost(\":9231\", \"\", 9231));\n    BOOST_CHECK(TestSplitHost(\"[]:9231\", \"\", 9231));\n    BOOST_CHECK(TestSplitHost(\"\", \"\", -1));\n}\n\nbool static TestParse(std::string src, std::string canon)\n{\n    CService addr(LookupNumeric(src.c_str(), 65535));\n    return canon == addr.ToString();\n}\n\nBOOST_AUTO_TEST_CASE(netbase_lookupnumeric)\n{\n    BOOST_CHECK(TestParse(\"127.0.0.1\", \"127.0.0.1:65535\"));\n    BOOST_CHECK(TestParse(\"127.0.0.1:9231\", \"127.0.0.1:9231\"));\n    BOOST_CHECK(TestParse(\"::ffff:127.0.0.1\", \"127.0.0.1:65535\"));\n    BOOST_CHECK(TestParse(\"::\", \"[::]:65535\"));\n    BOOST_CHECK(TestParse(\"[::]:9231\", \"[::]:9231\"));\n    BOOST_CHECK(TestParse(\"[127.0.0.1]\", \"127.0.0.1:65535\"));\n    BOOST_CHECK(TestParse(\":::\", \"[::]:0\"));\n}\n\nBOOST_AUTO_TEST_CASE(onioncat_test)\n{\n\n    // values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat\n    CNetAddr addr1(ResolveIP(\"5wyqrzbvrdsumnok.onion\"));\n    CNetAddr addr2(ResolveIP(\"FD87:D87E:EB43:edb1:8e4:3588:e546:35ca\"));\n    BOOST_CHECK(addr1 == addr2);\n    BOOST_CHECK(addr1.IsTor());\n    BOOST_CHECK(addr1.ToStringIP() == \"5wyqrzbvrdsumnok.onion\");\n    BOOST_CHECK(addr1.IsRoutable());\n\n}\n\nBOOST_AUTO_TEST_CASE(subnet_test)\n{\n\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.0/24\") == ResolveSubNet(\"1.2.3.0/255.255.255.0\"));\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.0/24\") != ResolveSubNet(\"1.2.4.0/255.255.255.0\"));\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.0/24\").Match(ResolveIP(\"1.2.3.4\")));\n    BOOST_CHECK(!ResolveSubNet(\"1.2.2.0/24\").Match(ResolveIP(\"1.2.3.4\")));\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.4\").Match(ResolveIP(\"1.2.3.4\")));\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.4/32\").Match(ResolveIP(\"1.2.3.4\")));\n    BOOST_CHECK(!ResolveSubNet(\"1.2.3.4\").Match(ResolveIP(\"5.6.7.8\")));\n    BOOST_CHECK(!ResolveSubNet(\"1.2.3.4/32\").Match(ResolveIP(\"5.6.7.8\")));\n    BOOST_CHECK(ResolveSubNet(\"::ffff:127.0.0.1\").Match(ResolveIP(\"127.0.0.1\")));\n    BOOST_CHECK(ResolveSubNet(\"1:2:3:4:5:6:7:8\").Match(ResolveIP(\"1:2:3:4:5:6:7:8\")));\n    BOOST_CHECK(!ResolveSubNet(\"1:2:3:4:5:6:7:8\").Match(ResolveIP(\"1:2:3:4:5:6:7:9\")));\n    BOOST_CHECK(ResolveSubNet(\"1:2:3:4:5:6:7:0/112\").Match(ResolveIP(\"1:2:3:4:5:6:7:1234\")));\n    BOOST_CHECK(ResolveSubNet(\"192.168.0.1/24\").Match(ResolveIP(\"192.168.0.2\")));\n    BOOST_CHECK(ResolveSubNet(\"192.168.0.20/29\").Match(ResolveIP(\"192.168.0.18\")));\n    BOOST_CHECK(ResolveSubNet(\"1.2.2.1/24\").Match(ResolveIP(\"1.2.2.4\")));\n    BOOST_CHECK(ResolveSubNet(\"1.2.2.110/31\").Match(ResolveIP(\"1.2.2.111\")));\n    BOOST_CHECK(ResolveSubNet(\"1.2.2.20/26\").Match(ResolveIP(\"1.2.2.63\")));\n    // All-Matching IPv6 Matches arbitrary IPv4 and IPv6\n    BOOST_CHECK(ResolveSubNet(\"::/0\").Match(ResolveIP(\"1:2:3:4:5:6:7:1234\")));\n    BOOST_CHECK(ResolveSubNet(\"::/0\").Match(ResolveIP(\"1.2.3.4\")));\n    // All-Matching IPv4 does not Match IPv6\n    BOOST_CHECK(!ResolveSubNet(\"0.0.0.0/0\").Match(ResolveIP(\"1:2:3:4:5:6:7:1234\")));\n    // Invalid subnets Match nothing (not even invalid addresses)\n    BOOST_CHECK(!CSubNet().Match(ResolveIP(\"1.2.3.4\")));\n    BOOST_CHECK(!ResolveSubNet(\"\").Match(ResolveIP(\"4.5.6.7\")));\n    BOOST_CHECK(!ResolveSubNet(\"bloop\").Match(ResolveIP(\"0.0.0.0\")));\n    BOOST_CHECK(!ResolveSubNet(\"bloop\").Match(ResolveIP(\"hab\")));\n    // Check valid/invalid\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.0/0\").IsValid());\n    BOOST_CHECK(!ResolveSubNet(\"1.2.3.0/-1\").IsValid());\n    BOOST_CHECK(ResolveSubNet(\"1.2.3.0/32\").IsValid());\n    BOOST_CHECK(!ResolveSubNet(\"1.2.3.0/33\").IsValid());\n    BOOST_CHECK(ResolveSubNet(\"1:2:3:4:5:6:7:8/0\").IsValid());\n    BOOST_CHECK(ResolveSubNet(\"1:2:3:4:5:6:7:8/33\").IsValid());\n    BOOST_CHECK(!ResolveSubNet(\"1:2:3:4:5:6:7:8/-1\").IsValid());\n    BOOST_CHECK(ResolveSubNet(\"1:2:3:4:5:6:7:8/128\").IsValid());\n    BOOST_CHECK(!ResolveSubNet(\"1:2:3:4:5:6:7:8/129\").IsValid());\n    BOOST_CHECK(!ResolveSubNet(\"fuzzy\").IsValid());\n\n    //CNetAddr constructor test\n    BOOST_CHECK(CSubNet(ResolveIP(\"127.0.0.1\")).IsValid());\n    BOOST_CHECK(CSubNet(ResolveIP(\"127.0.0.1\")).Match(ResolveIP(\"127.0.0.1\")));\n    BOOST_CHECK(!CSubNet(ResolveIP(\"127.0.0.1\")).Match(ResolveIP(\"127.0.0.2\")));\n    BOOST_CHECK(CSubNet(ResolveIP(\"127.0.0.1\")).ToString() == \"127.0.0.1/32\");\n\n    CSubNet subnet = CSubNet(ResolveIP(\"1.2.3.4\"), 32);\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.4/32\");\n    subnet = CSubNet(ResolveIP(\"1.2.3.4\"), 8);\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/8\");\n    subnet = CSubNet(ResolveIP(\"1.2.3.4\"), 0);\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/0\");\n\n    subnet = CSubNet(ResolveIP(\"1.2.3.4\"), ResolveIP(\"255.255.255.255\"));\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.4/32\");\n    subnet = CSubNet(ResolveIP(\"1.2.3.4\"), ResolveIP(\"255.0.0.0\"));\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/8\");\n    subnet = CSubNet(ResolveIP(\"1.2.3.4\"), ResolveIP(\"0.0.0.0\"));\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/0\");\n\n    BOOST_CHECK(CSubNet(ResolveIP(\"1:2:3:4:5:6:7:8\")).IsValid());\n    BOOST_CHECK(CSubNet(ResolveIP(\"1:2:3:4:5:6:7:8\")).Match(ResolveIP(\"1:2:3:4:5:6:7:8\")));\n    BOOST_CHECK(!CSubNet(ResolveIP(\"1:2:3:4:5:6:7:8\")).Match(ResolveIP(\"1:2:3:4:5:6:7:9\")));\n    BOOST_CHECK(CSubNet(ResolveIP(\"1:2:3:4:5:6:7:8\")).ToString() == \"1:2:3:4:5:6:7:8/128\");\n\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.255\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.4/32\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.254\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.4/31\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.252\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.4/30\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.248\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/29\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.240\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/28\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.224\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/27\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.192\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/26\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.128\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/25\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.255.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.3.0/24\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.254.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.2.0/23\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.252.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/22\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.248.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/21\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.240.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/20\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.224.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/19\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.192.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/18\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.128.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/17\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/16\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.254.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/15\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.252.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/14\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.248.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/13\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.240.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/12\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.224.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/11\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.192.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/10\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.128.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/9\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.0.0.0/8\");\n    subnet = ResolveSubNet(\"1.2.3.4/254.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/7\");\n    subnet = ResolveSubNet(\"1.2.3.4/252.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/6\");\n    subnet = ResolveSubNet(\"1.2.3.4/248.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/5\");\n    subnet = ResolveSubNet(\"1.2.3.4/240.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/4\");\n    subnet = ResolveSubNet(\"1.2.3.4/224.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/3\");\n    subnet = ResolveSubNet(\"1.2.3.4/192.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/2\");\n    subnet = ResolveSubNet(\"1.2.3.4/128.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/1\");\n    subnet = ResolveSubNet(\"1.2.3.4/0.0.0.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"0.0.0.0/0\");\n\n    subnet = ResolveSubNet(\"1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1:2:3:4:5:6:7:8/128\");\n    subnet = ResolveSubNet(\"1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1::/16\");\n    subnet = ResolveSubNet(\"1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"::/0\");\n    subnet = ResolveSubNet(\"1.2.3.4/255.255.232.0\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1.2.0.0/255.255.232.0\");\n    subnet = ResolveSubNet(\"1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f\");\n    BOOST_CHECK_EQUAL(subnet.ToString(), \"1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f\");\n\n}\n\nBOOST_AUTO_TEST_CASE(netbase_getgroup)\n{\n\n    BOOST_CHECK(ResolveIP(\"127.0.0.1\").GetGroup() == std::vector<unsigned char>({0})); // Local -> !Routable()\n    BOOST_CHECK(ResolveIP(\"257.0.0.1\").GetGroup() == std::vector<unsigned char>({0})); // !Valid -> !Routable()\n    BOOST_CHECK(ResolveIP(\"10.0.0.1\").GetGroup() == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()\n    BOOST_CHECK(ResolveIP(\"169.254.1.1\").GetGroup() == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()\n    BOOST_CHECK(ResolveIP(\"1.2.3.4\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4\n    BOOST_CHECK(ResolveIP(\"::FFFF:0:102:304\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145\n    BOOST_CHECK(ResolveIP(\"64:FF9B::102:304\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052\n    BOOST_CHECK(ResolveIP(\"2002:102:304:9999:9999:9999:9999:9999\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964\n    BOOST_CHECK(ResolveIP(\"2001:0:9999:9999:9999:9999:FEFD:FCFB\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380\n    BOOST_CHECK(ResolveIP(\"FD87:D87E:EB43:edb1:8e4:3588:e546:35ca\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_TOR, 239})); // Tor\n    BOOST_CHECK(ResolveIP(\"2001:470:abcd:9999:9999:9999:9999:9999\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net\n    BOOST_CHECK(ResolveIP(\"2001:2001:9999:9999:9999:9999:9999:9999\").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6\n\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/pmt_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/merkle.h\"\n#include \"merkleblock.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"uint256.h\"\n#include \"arith_uint256.h\"\n#include \"version.h\"\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nclass CPartialMerkleTreeTester : public CPartialMerkleTree\n{\npublic:\n    // flip one bit in one of the hashes - this should break the authentication\n    void Damage() {\n        unsigned int n = InsecureRandRange(vHash.size());\n        int bit = InsecureRandBits(8);\n        *(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7);\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(pmt_test1)\n{\n    SeedInsecureRand(false);\n    static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095};\n\n    for (int i = 0; i < 12; i++) {\n        unsigned int nTx = nTxCounts[i];\n\n        // build a block with some dummy transactions\n        CBlock block;\n        for (unsigned int j=0; j<nTx; j++) {\n            CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n            tx.nLockTime = j; // actual transaction data doesn't matter; just make the nLockTime's unique\n            block.vtx.push_back(MakeTransactionRef(std::move(tx)));\n        }\n\n        // calculate actual merkle root and height\n        uint256 merkleRoot1 = BlockMerkleRoot(block);\n        std::vector<uint256> vTxid(nTx, uint256());\n        for (unsigned int j=0; j<nTx; j++)\n            vTxid[j] = block.vtx[j]->GetHash();\n        int nHeight = 1, nTx_ = nTx;\n        while (nTx_ > 1) {\n            nTx_ = (nTx_+1)/2;\n            nHeight++;\n        }\n\n        // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128\n        for (int att = 1; att < 15; att++) {\n            // build random subset of txid's\n            std::vector<bool> vMatch(nTx, false);\n            std::vector<uint256> vMatchTxid1;\n            for (unsigned int j=0; j<nTx; j++) {\n                bool fInclude = InsecureRandBits(att / 2) == 0;\n                vMatch[j] = fInclude;\n                if (fInclude)\n                    vMatchTxid1.push_back(vTxid[j]);\n            }\n\n            // build the partial merkle tree\n            CPartialMerkleTree pmt1(vTxid, vMatch);\n\n            // serialize\n            CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);\n            ss << pmt1;\n\n            // verify CPartialMerkleTree's size guarantees\n            unsigned int n = std::min<unsigned int>(nTx, 1 + vMatchTxid1.size()*nHeight);\n            BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8);\n\n            // deserialize into a tester copy\n            CPartialMerkleTreeTester pmt2;\n            ss >> pmt2;\n\n            // extract merkle root and matched txids from copy\n            std::vector<uint256> vMatchTxid2;\n            std::vector<unsigned int> vIndex;\n            uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex);\n\n            // check that it has the same merkle root as the original, and a valid one\n            BOOST_CHECK(merkleRoot1 == merkleRoot2);\n            BOOST_CHECK(!merkleRoot2.IsNull());\n\n            // check that it contains the matched transactions (in the same order!)\n            BOOST_CHECK(vMatchTxid1 == vMatchTxid2);\n\n            // check that random bit flips break the authentication\n            for (int j=0; j<4; j++) {\n                CPartialMerkleTreeTester pmt3(pmt2);\n                pmt3.Damage();\n                std::vector<uint256> vMatchTxid3;\n                uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex);\n                BOOST_CHECK(merkleRoot3 != merkleRoot1);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(pmt_malleability)\n{\n    std::vector<uint256> vTxid = {\n        ArithToUint256(1), ArithToUint256(2),\n        ArithToUint256(3), ArithToUint256(4),\n        ArithToUint256(5), ArithToUint256(6),\n        ArithToUint256(7), ArithToUint256(8),\n        ArithToUint256(9), ArithToUint256(10),\n        ArithToUint256(9), ArithToUint256(10),\n    };\n    std::vector<bool> vMatch = {false, false, false, false, false, false, false, false, false, true, true, false};\n\n    CPartialMerkleTree tree(vTxid, vMatch);\n    std::vector<unsigned int> vIndex;\n    BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/policyestimator_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"policy/policy.h\"\n#include \"policy/fees.h\"\n#include \"txmempool.h\"\n#include \"uint256.h\"\n#include \"util.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(BlockPolicyEstimates)\n{\n    TEST_REWRITE;\n    #if 0\n    CBlockPolicyEstimator feeEst;\n    CTxMemPool mpool(&feeEst);\n    TestMemPoolEntryHelper entry;\n    CAmount basefee(2000);\n    CAmount deltaFee(100);\n    std::vector<CAmount> feeV;\n\n    // Populate vectors of increasing fees\n    for (int j = 0; j < 10; j++) {\n        feeV.push_back(basefee * (j+1));\n    }\n\n    // Store the hashes of transactions that have been\n    // added to the mempool by their associate fee\n    // txHashes[j] is populated with transactions either of\n    // fee = basefee * (j+1)\n    std::vector<uint256> txHashes[10];\n\n    // Create a transaction template\n    CScript garbage;\n    for (unsigned int i = 0; i < 128; i++)\n        garbage.push_back('X');\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    tx.vin.resize(1);\n    tx.vin[0].scriptSig = garbage;\n    tx.vout.resize(1);\n    tx.vout[0].nValue=0LL;\n    CFeeRate baseRate(basefee, GetVirtualTransactionSize(tx));\n\n    // Create a fake block\n    std::vector<CTransactionRef> block;\n    int blocknum = 0;\n\n    // Loop through 200 blocks\n    // At a decay .9952 and 4 fee transactions per block\n    // This makes the tx count about 2.5 per bucket, well above the 0.1 threshold\n    while (blocknum < 200) {\n        for (int j = 0; j < 10; j++) { // For each fee\n            for (int k = 0; k < 4; k++) { // add 4 fee txs\n                tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique\n                uint256 hash = tx.GetHash();\n                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));\n                txHashes[j].push_back(hash);\n            }\n        }\n        //Create blocks where higher fee txs are included more often\n        for (int h = 0; h <= blocknum%10; h++) {\n            // 10/10 blocks add highest fee transactions\n            // 9/10 blocks add 2nd highest and so on until ...\n            // 1/10 blocks add lowest fee transactions\n            while (txHashes[9-h].size()) {\n                CTransactionRef ptx = mpool.get(txHashes[9-h].back());\n                if (ptx)\n                    block.push_back(ptx);\n                txHashes[9-h].pop_back();\n            }\n        }\n        mpool.removeForBlock(block, ++blocknum);\n        block.clear();\n        // Check after just a few txs that combining buckets works as expected\n        if (blocknum == 3) {\n            // At this point we should need to combine 3 buckets to get enough data points\n            // So estimateFee(1) should fail and estimateFee(2) should return somewhere around\n            // 9*baserate.  estimateFee(2) %'s are 100,100,90 = average 97%\n            BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));\n            BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() < 9*baseRate.GetFeePerK() + deltaFee);\n            BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() > 9*baseRate.GetFeePerK() - deltaFee);\n        }\n    }\n\n    std::vector<CAmount> origFeeEst;\n    // Highest feerate is 10*baseRate and gets in all blocks,\n    // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,\n    // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,\n    // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure\n    // Second highest feerate has 100% chance of being included by 2 blocks,\n    // so estimateFee(2) should return 9*baseRate etc...\n    for (int i = 1; i < 10;i++) {\n        origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());\n        if (i > 2) { // Fee estimates should be monotonically decreasing\n            BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);\n        }\n        int mult = 11-i;\n        if (i % 2 == 0) { //At scale 2, test logic is only correct for even targets\n            BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);\n            BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);\n        }\n    }\n    // Fill out rest of the original estimates\n    for (int i = 10; i <= 48; i++) {\n        origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());\n    }\n\n    // Mine 50 more blocks with no transactions happening, estimates shouldn't change\n    // We haven't decayed the moving average enough so we still have enough data points in every bucket\n    while (blocknum < 250)\n        mpool.removeForBlock(block, ++blocknum);\n\n    BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));\n    for (int i = 2; i < 10;i++) {\n        BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);\n        BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);\n    }\n\n\n    // Mine 15 more blocks with lots of transactions happening and not getting mined\n    // Estimates should go up\n    while (blocknum < 265) {\n        for (int j = 0; j < 10; j++) { // For each fee multiple\n            for (int k = 0; k < 4; k++) { // add 4 fee txs\n                tx.vin[0].prevout.n = 10000*blocknum+100*j+k;\n                uint256 hash = tx.GetHash();\n                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));\n                txHashes[j].push_back(hash);\n            }\n        }\n        mpool.removeForBlock(block, ++blocknum);\n    }\n\n    for (int i = 1; i < 10;i++) {\n        BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);\n    }\n\n    // Mine all those transactions\n    // Estimates should still not be below original\n    for (int j = 0; j < 10; j++) {\n        while(txHashes[j].size()) {\n            CTransactionRef ptx = mpool.get(txHashes[j].back());\n            if (ptx)\n                block.push_back(ptx);\n            txHashes[j].pop_back();\n        }\n    }\n    mpool.removeForBlock(block, 266);\n    block.clear();\n    BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));\n    for (int i = 2; i < 10;i++) {\n        BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);\n    }\n\n    // Mine 400 more blocks where everything is mined every block\n    // Estimates should be below original estimates\n    while (blocknum < 665) {\n        for (int j = 0; j < 10; j++) { // For each fee multiple\n            for (int k = 0; k < 4; k++) { // add 4 fee txs\n                tx.vin[0].prevout.n = 10000*blocknum+100*j+k;\n                uint256 hash = tx.GetHash();\n                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));\n                CTransactionRef ptx = mpool.get(hash);\n                if (ptx)\n                    block.push_back(ptx);\n\n            }\n        }\n        mpool.removeForBlock(block, ++blocknum);\n        block.clear();\n    }\n    BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));\n    for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2)\n        BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);\n    }\n\n    // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee\n    mpool.addUnchecked(tx.GetHash(),  entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));\n    // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]\n    mpool.TrimToSize(1);\n    BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);\n    for (int i = 1; i < 10; i++) {\n        BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= feeEst.estimateRawFee(i, 0.85, FeeEstimateHorizon::MED_HALFLIFE).GetFeePerK());\n        BOOST_CHECK(feeEst.estimateSmartFee(i, NULL, mpool).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());\n    }\n    #endif\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/pow_tests.cpp",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT/X11 software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"pow/pow.h\"\n#include \"random.h\"\n#include \"util.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup)\n\n/* Test calculation of next difficulty target with no constraints applying */\nBOOST_AUTO_TEST_CASE(get_next_work)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    //int64_t nLastRetargetTime = 1261130161; // Block #30240\n    CBlockIndex pindexLast;\n    pindexLast.nHeight = 32255;\n    pindexLast.nTime = 1262152739;  // Block #32255\n    pindexLast.nBits = 0x1d00ffff;\n    TEST_REWRITE;\n    // BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00d86a);\n}\n\n/* Test the constraint on the upper bound for next work */\nBOOST_AUTO_TEST_CASE(get_next_work_pow_limit)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    //int64_t nLastRetargetTime = 1231006505; // Block #0\n    CBlockIndex pindexLast;\n    pindexLast.nHeight = 2015;\n    pindexLast.nTime = 1233061996;  // Block #2015\n    pindexLast.nBits = 0x1d00ffff;\n    TEST_REWRITE;\n    //BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00ffff);\n}\n\n/* Test the constraint on the lower bound for actual time taken */\nBOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    //int64_t nLastRetargetTime = 1279008237; // Block #66528\n    CBlockIndex pindexLast;\n    pindexLast.nHeight = 68543;\n    pindexLast.nTime = 1279297671;  // Block #68543\n    pindexLast.nBits = 0x1c05a3f4;\n    TEST_REWRITE;\n    //BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1c0168fd);\n}\n\n/* Test the constraint on the upper bound for actual time taken */\nBOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    //int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time\n    CBlockIndex pindexLast;\n    pindexLast.nHeight = 46367;\n    pindexLast.nTime = 1269211443;  // Block #46367\n    pindexLast.nBits = 0x1c387f6f;\n    TEST_REWRITE;\n    //BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00e1fd);\n}\n\nBOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)\n{\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    std::vector<CBlockIndex> blocks(10000);\n    for (int i = 0; i < 10000; i++) {\n        blocks[i].pprev = i ? &blocks[i - 1] : NULL;\n        blocks[i].nHeight = i;\n        blocks[i].nTime = 1269211443 + i * chainParams->GetConsensus().nPowTargetSpacing;\n        blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */\n        blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);\n    }\n\n    for (int j = 0; j < 1000; j++) {\n        CBlockIndex *p1 = &blocks[InsecureRandRange(10000)];\n        CBlockIndex *p2 = &blocks[InsecureRandRange(10000)];\n        CBlockIndex *p3 = &blocks[InsecureRandRange(10000)];\n\n        int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus());\n        BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime());\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/prevector_tests.cpp",
    "content": "// Copyright (c) 2015-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"prevector.h\"\n#include <vector>\n\n#include <reverse_iterator.h>\n#include \"serialize.h\"\n#include \"streams.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(prevector_tests, TestingSetup)\n\ntemplate<unsigned int N, typename T>\nclass prevector_tester {\n    typedef std::vector<T> realtype;\n    realtype real_vector;\n    realtype real_vector_alt;\n\n    typedef prevector<N, T> pretype;\n    pretype pre_vector;\n    pretype pre_vector_alt;\n\n    typedef typename pretype::size_type Size;\n    bool passed = true;\n    FastRandomContext rand_cache;\n    uint256 rand_seed;\n\n\n    template <typename A, typename B>\n        void local_check_equal(A a, B b)\n        {\n            local_check(a == b);\n        }\n    void local_check(bool b)\n    {\n        passed &= b;\n    }\n    void test() {\n        const pretype& const_pre_vector = pre_vector;\n        local_check_equal(real_vector.size(), pre_vector.size());\n        local_check_equal(real_vector.empty(), pre_vector.empty());\n        for (Size s = 0; s < real_vector.size(); s++) {\n             local_check(real_vector[s] == pre_vector[s]);\n             local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));\n             local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));\n             local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));\n        }\n        // local_check(realtype(pre_vector) == real_vector);\n        local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);\n        local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);\n        size_t pos = 0;\n        for (const T& v : pre_vector) {\n             local_check(v == real_vector[pos++]);\n        }\n        for (const T& v : reverse_iterate(pre_vector)) {\n             local_check(v == real_vector[--pos]);\n        }\n        for (const T& v : const_pre_vector) {\n             local_check(v == real_vector[pos++]);\n        }\n        for (const T& v : reverse_iterate(const_pre_vector)) {\n             local_check(v == real_vector[--pos]);\n        }\n        CDataStream ss1(SER_DISK, 0);\n        CDataStream ss2(SER_DISK, 0);\n        ss1 << COMPACTSIZEVECTOR(real_vector);\n        ss2 << pre_vector;\n        local_check_equal(ss1.size(), ss2.size());\n        for (Size s = 0; s < ss1.size(); s++) {\n            local_check_equal(ss1[s], ss2[s]);\n        }\n    }\n\npublic:\n    void resize(Size s) {\n        real_vector.resize(s);\n        local_check_equal(real_vector.size(), s);\n        pre_vector.resize(s);\n        local_check_equal(pre_vector.size(), s);\n        test();\n    }\n\n    void reserve(Size s) {\n        real_vector.reserve(s);\n        local_check(real_vector.capacity() >= s);\n        pre_vector.reserve(s);\n        local_check(pre_vector.capacity() >= s);\n        test();\n    }\n\n    void insert(Size position, const T& value) {\n        real_vector.insert(real_vector.begin() + position, value);\n        pre_vector.insert(pre_vector.begin() + position, value);\n        test();\n    }\n\n    void insert(Size position, Size count, const T& value) {\n        real_vector.insert(real_vector.begin() + position, count, value);\n        pre_vector.insert(pre_vector.begin() + position, count, value);\n        test();\n    }\n\n    template<typename I>\n    void insert_range(Size position, I first, I last) {\n        real_vector.insert(real_vector.begin() + position, first, last);\n        pre_vector.insert(pre_vector.begin() + position, first, last);\n        test();\n    }\n\n    void erase(Size position) {\n        real_vector.erase(real_vector.begin() + position);\n        pre_vector.erase(pre_vector.begin() + position);\n        test();\n    }\n\n    void erase(Size first, Size last) {\n        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);\n        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);\n        test();\n    }\n\n    void update(Size pos, const T& value) {\n        real_vector[pos] = value;\n        pre_vector[pos] = value;\n        test();\n    }\n\n    void push_back(const T& value) {\n        real_vector.push_back(value);\n        pre_vector.push_back(value);\n        test();\n    }\n\n    void pop_back() {\n        real_vector.pop_back();\n        pre_vector.pop_back();\n        test();\n    }\n\n    void clear() {\n        real_vector.clear();\n        pre_vector.clear();\n    }\n\n    void assign(Size n, const T& value) {\n        real_vector.assign(n, value);\n        pre_vector.assign(n, value);\n    }\n\n    Size size() const {\n        return real_vector.size();\n    }\n\n    Size capacity() const {\n        return pre_vector.capacity();\n    }\n\n    void shrink_to_fit() {\n        pre_vector.shrink_to_fit();\n        test();\n    }\n\n    void swap() {\n        real_vector.swap(real_vector_alt);\n        pre_vector.swap(pre_vector_alt);\n        test();\n    }\n\n    void move() {\n        real_vector = std::move(real_vector_alt);\n        real_vector_alt.clear();\n        pre_vector = std::move(pre_vector_alt);\n        pre_vector_alt.clear();\n    }\n\n    void copy() {\n        real_vector = real_vector_alt;\n        pre_vector = pre_vector_alt;\n    }\n\n    ~prevector_tester() {\n        BOOST_CHECK_MESSAGE(passed, \"insecure_rand: \" + rand_seed.ToString());\n    }\n\n    prevector_tester() {\n        SeedInsecureRand();\n        rand_seed = InsecureRand256();\n        rand_cache = FastRandomContext(rand_seed);\n    }\n};\n\nBOOST_AUTO_TEST_CASE(PrevectorTestInt)\n{\n    for (int j = 0; j < 64; j++) {\n        prevector_tester<8, int> test;\n        for (int i = 0; i < 2048; i++) {\n            if (InsecureRandBits(2) == 0) {\n                test.insert(InsecureRandRange(test.size() + 1), InsecureRand32());\n            }\n            if (test.size() > 0 && InsecureRandBits(2) == 1) {\n                test.erase(InsecureRandRange(test.size()));\n            }\n            if (InsecureRandBits(3) == 2) {\n                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (InsecureRandRange(5)) - 2));\n                test.resize(new_size);\n            }\n            if (InsecureRandBits(3) == 3) {\n                test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), InsecureRand32());\n            }\n            if (InsecureRandBits(3) == 4) {\n                int del = std::min<int>(test.size(), 1 + (InsecureRandBool()));\n                int beg = InsecureRandRange(test.size() + 1 - del);\n                test.erase(beg, beg + del);\n            }\n            if (InsecureRandBits(4) == 5) {\n                test.push_back(InsecureRand32());\n            }\n            if (test.size() > 0 && InsecureRandBits(4) == 6) {\n                test.pop_back();\n            }\n            if (InsecureRandBits(5) == 7) {\n                int values[4];\n                int num = 1 + (InsecureRandBits(2));\n                for (int k = 0; k < num; k++) {\n                    values[k] = InsecureRand32();\n                }\n                test.insert_range(InsecureRandRange(test.size() + 1), values, values + num);\n            }\n            if (InsecureRandBits(5) == 8) {\n                int del = std::min<int>(test.size(), 1 + (InsecureRandBits(2)));\n                int beg = InsecureRandRange(test.size() + 1 - del);\n                test.erase(beg, beg + del);\n            }\n            if (InsecureRandBits(5) == 9) {\n                test.reserve(InsecureRandBits(5));\n            }\n            if (InsecureRandBits(6) == 10) {\n                test.shrink_to_fit();\n            }\n            if (test.size() > 0) {\n                test.update(InsecureRandRange(test.size()), InsecureRand32());\n            }\n            if (InsecureRandBits(10) == 11) {\n                test.clear();\n            }\n            if (InsecureRandBits(9) == 12) {\n                test.assign(InsecureRandBits(5), InsecureRand32());\n            }\n            if (InsecureRandBits(3) == 3) {\n                test.swap();\n            }\n            if (InsecureRandBits(4) == 8) {\n                test.copy();\n            }\n            if (InsecureRandBits(5) == 18) {\n                test.move();\n            }\n            if (InsecureRandBits(5) == 19) {\n                unsigned int num = 1 + (InsecureRandBits(4));\n                std::vector<int> values(num);\n                for (int& v : values) {\n                    v = int(InsecureRand32());\n                }\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/raii_event_tests.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <event2/event.h>\n\n#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED\n// It would probably be ideal to define dummy test(s) that report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)\n\n#include <map>\n#include <stdlib.h>\n\n#include \"support/events.h\"\n\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nstatic std::map<void*, short> tags;\nstatic std::map<void*, uint16_t> orders;\nstatic uint16_t tagSequence = 0;\n\nstatic void* tag_malloc(size_t sz) {\n    void* mem = malloc(sz);\n    if (!mem) return mem;\n    tags[mem]++;\n    orders[mem] = tagSequence++;\n    return mem;\n}\n\nstatic void tag_free(void* mem) {\n    tags[mem]--;\n    orders[mem] = tagSequence++;\n    free(mem);\n}\n\nBOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(raii_event_creation)\n{\n    event_set_mem_functions(tag_malloc, realloc, tag_free);\n\n    void* base_ptr = NULL;\n    {\n        auto base = obtain_event_base();\n        base_ptr = (void*)base.get();\n        BOOST_CHECK(tags[base_ptr] == 1);\n    }\n    BOOST_CHECK(tags[base_ptr] == 0);\n\n    void* event_ptr = NULL;\n    {\n        auto base = obtain_event_base();\n        auto event = obtain_event(base.get(), -1, 0, NULL, NULL);\n\n        base_ptr = (void*)base.get();\n        event_ptr = (void*)event.get();\n\n        BOOST_CHECK(tags[base_ptr] == 1);\n        BOOST_CHECK(tags[event_ptr] == 1);\n    }\n    BOOST_CHECK(tags[base_ptr] == 0);\n    BOOST_CHECK(tags[event_ptr] == 0);\n\n    event_set_mem_functions(malloc, realloc, free);\n}\n\nBOOST_AUTO_TEST_CASE(raii_event_order)\n{\n    event_set_mem_functions(tag_malloc, realloc, tag_free);\n\n    void* base_ptr = NULL;\n    void* event_ptr = NULL;\n    {\n        auto base = obtain_event_base();\n        auto event = obtain_event(base.get(), -1, 0, NULL, NULL);\n\n        base_ptr = (void*)base.get();\n        event_ptr = (void*)event.get();\n\n        // base should have allocated before event\n        BOOST_CHECK(orders[base_ptr] < orders[event_ptr]);\n    }\n    // base should be freed after event\n    BOOST_CHECK(orders[base_ptr] > orders[event_ptr]);\n\n    event_set_mem_functions(malloc, realloc, free);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif  // EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED\n"
  },
  {
    "path": "src/test/random_tests.cpp",
    "content": "// Copyright (c) 2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"random.h\"\n\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(osrandom_tests)\n{\n    BOOST_CHECK(Random_SanityCheck());\n}\n\nBOOST_AUTO_TEST_CASE(fastrandom_tests)\n{\n    // Check that deterministic FastRandomContexts are deterministic\n    FastRandomContext ctx1(true);\n    FastRandomContext ctx2(true);\n\n    BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());\n    BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());\n    BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());\n    BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));\n    BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17));\n    BOOST_CHECK(ctx1.rand256() == ctx2.rand256());\n    BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));\n    BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128));\n    BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());\n    BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));\n    BOOST_CHECK(ctx1.rand256() == ctx2.rand256());\n    BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));\n\n    // Check that a nondeterministic ones are not\n    FastRandomContext ctx3;\n    FastRandomContext ctx4;\n    BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal\n    BOOST_CHECK(ctx3.rand256() != ctx4.rand256());\n    BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));\n}\n\nBOOST_AUTO_TEST_CASE(fastrandom_randbits)\n{\n    FastRandomContext ctx1;\n    FastRandomContext ctx2;\n    for (int bits = 0; bits < 63; ++bits) {\n        for (int j = 0; j < 1000; ++j) {\n            uint64_t rangebits = ctx1.randbits(bits);\n            BOOST_CHECK_EQUAL(rangebits >> bits, 0U);\n            uint64_t range = ((uint64_t)1) << bits | rangebits;\n            uint64_t rand = ctx2.randrange(range);\n            BOOST_CHECK(rand < range);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/reverselock_tests.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"reverselock.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(reverselock_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(reverselock_basics)\n{\n    boost::mutex mutex;\n    boost::unique_lock<boost::mutex> lock(mutex);\n\n    BOOST_CHECK(lock.owns_lock());\n    {\n        reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);\n        BOOST_CHECK(!lock.owns_lock());\n    }\n    BOOST_CHECK(lock.owns_lock());\n}\n\nBOOST_AUTO_TEST_CASE(reverselock_errors)\n{\n    boost::mutex mutex;\n    boost::unique_lock<boost::mutex> lock(mutex);\n\n    // Make sure trying to reverse lock an unlocked lock fails\n    lock.unlock();\n\n    BOOST_CHECK(!lock.owns_lock());\n\n    bool failed = false;\n    try {\n        reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);\n    } catch(...) {\n        failed = true;\n    }\n\n    BOOST_CHECK(failed);\n    BOOST_CHECK(!lock.owns_lock());\n\n    // Locking the original lock after it has been taken by a reverse lock\n    // makes no sense. Ensure that the original lock no longer owns the lock\n    // after giving it to a reverse one.\n\n    lock.lock();\n    BOOST_CHECK(lock.owns_lock());\n    {\n        reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);\n        BOOST_CHECK(!lock.owns_lock());\n    }\n\n    BOOST_CHECK(failed);\n    BOOST_CHECK(lock.owns_lock());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/rpc_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"rpc/server.h\"\n#include \"rpc/client.h\"\n\n#include \"base58.h\"\n#include \"netbase.h\"\n\n#include \"test/test.h\"\n\n#include <boost/algorithm/string.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <univalue.h>\n\nstatic UniValue CallRPC(std::string args)\n{\n    std::vector<std::string> vArgs;\n    boost::split(vArgs, args, boost::is_any_of(\" \\t\"));\n    std::string strMethod = vArgs[0];\n    vArgs.erase(vArgs.begin());\n    JSONRPCRequest request;\n    request.strMethod = strMethod;\n    request.params = RPCConvertValues(strMethod, vArgs);\n    request.fHelp = false;\n    BOOST_CHECK(tableRPC[strMethod]);\n    rpcfn_type method = tableRPC[strMethod]->actor;\n    try {\n        UniValue result = (*method)(request);\n        return result;\n    }\n    catch (const UniValue& objError) {\n        throw std::runtime_error(find_value(objError, \"message\").get_str());\n    }\n}\n\n\nBOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)\n\nBOOST_AUTO_TEST_CASE(rpc_rawparams)\n{\n    // Test raw transaction API argument handling\n    UniValue r;\n\n    BOOST_CHECK_THROW(CallRPC(\"getrawtransaction\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"getrawtransaction not_hex\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int\"), std::runtime_error);\n\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction null null\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction not_array\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction [] []\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction {} {}\"), std::runtime_error);\n    BOOST_CHECK_NO_THROW(CallRPC(\"createrawtransaction [] {}\"));\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction [] {} extra\"), std::runtime_error);\n\n    BOOST_CHECK_THROW(CallRPC(\"decoderawtransaction\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"decoderawtransaction null\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"decoderawtransaction DEADBEEF\"), std::runtime_error);\n    std::string rawtx = \"0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000\";\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"decoderawtransaction \")+rawtx));\n    BOOST_CHECK_EQUAL(find_value(r.get_obj(), \"size\").get_int(), 193);\n    BOOST_CHECK_EQUAL(find_value(r.get_obj(), \"version\").get_int(), 1);\n    BOOST_CHECK_EQUAL(find_value(r.get_obj(), \"locktime\").get_int(), 0);\n    BOOST_CHECK_THROW(r = CallRPC(std::string(\"decoderawtransaction \")+rawtx+\" extra\"), std::runtime_error);\n\n    BOOST_CHECK_THROW(CallRPC(\"signrawtransaction\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"signrawtransaction null\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"signrawtransaction ff00\"), std::runtime_error);\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"signrawtransaction \")+rawtx));\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"signrawtransaction \")+rawtx+\" null null NONE|ANYONECANPAY\"));\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"signrawtransaction \")+rawtx+\" [] [] NONE|ANYONECANPAY\"));\n    BOOST_CHECK_THROW(CallRPC(std::string(\"signrawtransaction \")+rawtx+\" null null badenum\"), std::runtime_error);\n\n    // Only check failure cases for sendrawtransaction, there's no network to send to...\n    BOOST_CHECK_THROW(CallRPC(\"sendrawtransaction\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"sendrawtransaction null\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"sendrawtransaction DEADBEEF\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(std::string(\"sendrawtransaction \")+rawtx+\" extra\"), std::runtime_error);\n}\n\nBOOST_AUTO_TEST_CASE(rpc_togglenetwork)\n{\n    UniValue r;\n\n    r = CallRPC(\"getnetworkinfo\");\n    bool netState = find_value(r.get_obj(), \"networkactive\").get_bool();\n    BOOST_CHECK_EQUAL(netState, true);\n\n    BOOST_CHECK_NO_THROW(CallRPC(\"setnetworkactive false\"));\n    r = CallRPC(\"getnetworkinfo\");\n    int numConnection = find_value(r.get_obj(), \"connections\").get_int();\n    BOOST_CHECK_EQUAL(numConnection, 0);\n\n    netState = find_value(r.get_obj(), \"networkactive\").get_bool();\n    BOOST_CHECK_EQUAL(netState, false);\n\n    BOOST_CHECK_NO_THROW(CallRPC(\"setnetworkactive true\"));\n    r = CallRPC(\"getnetworkinfo\");\n    netState = find_value(r.get_obj(), \"networkactive\").get_bool();\n    BOOST_CHECK_EQUAL(netState, true);\n}\n\nBOOST_AUTO_TEST_CASE(rpc_rawsign)\n{\n    UniValue r;\n    // input is a 1-of-2 multisig (so is output):\n    std::string prevout =\n      \"[{\\\"txid\\\":\\\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\\\",\"\n      \"\\\"vout\\\":1,\\\"scriptPubKey\\\":\\\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\\\",\"\n      \"\\\"redeemScript\\\":\\\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\\\"}]\";\n    r = CallRPC(std::string(\"createrawtransaction \")+prevout+\" \"+ \"{\\\"giGGDF4gPxqGvyK7UzXDc875jVSGcpgnsy\\\":11}\");\n    std::string notsigned = r.get_str();\n    std::string privkey1 = \"\\\"RcuVhjWLPMuHQk9wXtKRD2zcbpLfspJ8J8UoxCPgjtiuCjgSEwaG\\\"\";\n    std::string privkey2 = \"\\\"RbjbPD35yJFB6M9HArb6SVJyd2NH9DN9TjqH1HQzzzfLRqtd61La\\\"\";\n    r = CallRPC(std::string(\"signrawtransaction \")+notsigned+\" \"+prevout+\" \"+\"[]\");\n    BOOST_CHECK(find_value(r.get_obj(), \"complete\").get_bool() == false);\n    r = CallRPC(std::string(\"signrawtransaction \")+notsigned+\" \"+prevout+\" \"+\"[\"+privkey1+\",\"+privkey2+\"]\");\n    BOOST_CHECK(find_value(r.get_obj(), \"complete\").get_bool() == true);\n}\n\nBOOST_AUTO_TEST_CASE(rpc_createraw_op_return)\n{\n    BOOST_CHECK_NO_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"data\\\":\\\"68656c6c6f776f726c64\\\"}\"));\n\n    // Allow more than one data transaction output\n    BOOST_CHECK_NO_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"data\\\":\\\"68656c6c6f776f726c64\\\",\\\"data\\\":\\\"68656c6c6f776f726c64\\\"}\"));\n\n    // Key not \"data\" (bad address)\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"somedata\\\":\\\"68656c6c6f776f726c64\\\"}\"), std::runtime_error);\n\n    // Bad hex encoding of data output\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"data\\\":\\\"12345\\\"}\"), std::runtime_error);\n    BOOST_CHECK_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"data\\\":\\\"12345g\\\"}\"), std::runtime_error);\n\n    // Data 81 bytes long\n    BOOST_CHECK_NO_THROW(CallRPC(\"createrawtransaction [{\\\"txid\\\":\\\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\\\",\\\"vout\\\":0}] {\\\"data\\\":\\\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\\\"}\"));\n}\n\nBOOST_AUTO_TEST_CASE(rpc_format_monetary_values)\n{\n    BOOST_CHECK(ValueFromAmount(0LL).write() == \"0.00000000\");\n    BOOST_CHECK(ValueFromAmount(1LL).write() == \"0.00000001\");\n    BOOST_CHECK(ValueFromAmount(17622195LL).write() == \"0.17622195\");\n    BOOST_CHECK(ValueFromAmount(50000000LL).write() == \"0.50000000\");\n    BOOST_CHECK(ValueFromAmount(89898989LL).write() == \"0.89898989\");\n    BOOST_CHECK(ValueFromAmount(100000000LL).write() == \"1.00000000\");\n    BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == \"20999999.99999990\");\n    BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == \"20999999.99999999\");\n\n    BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), \"0.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), \"12345.67890000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), \"-1.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), \"-0.10000000\");\n\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), \"100000000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), \"10000000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), \"1000000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), \"100000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), \"10000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), \"1000.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), \"100.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), \"10.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), \"1.00000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), \"0.10000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), \"0.01000000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), \"0.00100000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), \"0.00010000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), \"0.00001000\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), \"0.00000100\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), \"0.00000010\");\n    BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), \"0.00000001\");\n}\n\nstatic UniValue ValueFromString(const std::string &str)\n{\n    UniValue value;\n    BOOST_CHECK(value.setNumStr(str));\n    return value;\n}\n\nBOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)\n{\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"-0.00000001\")), UniValue);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0\")), 0LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.00000000\")), 0LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.00000001\")), 1LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.17622195\")), 17622195LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.5\")), 50000000LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.50000000\")), 50000000LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.89898989\")), 89898989LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"1.00000000\")), 100000000LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"20999999.9999999\")), 2099999999999990LL);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"20999999.99999999\")), 2099999999999999LL);\n\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"1e-8\")), COIN/100000000);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.1e-7\")), COIN/100000000);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.01e-6\")), COIN/100000000);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68\")), COIN/100000000);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"10000000000000000000000000000000000000000000000000000000000000000e-64\")), COIN);\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64\")), COIN);\n\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"1e-9\")), UniValue); //should fail\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"0.000000019\")), UniValue); //should fail\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.00000001000000\")), 1LL); //should pass, cut trailing 0\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"19e-9\")), UniValue); //should fail\n    BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString(\"0.19e-6\")), 19); //should pass, leading 0 is present\n\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"92233720368.54775808\")), UniValue); //overflow error\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"1e+11\")), UniValue); //overflow error\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"1e11\")), UniValue); //overflow error signless\n    BOOST_CHECK_THROW(AmountFromValue(ValueFromString(\"93e+9\")), UniValue); //overflow error\n}\n\nBOOST_AUTO_TEST_CASE(json_parse_errors)\n{\n    // Valid\n    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(\"1.0\").get_real(), 1.0);\n    // Valid, with leading or trailing whitespace\n    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(\" 1.0\").get_real(), 1.0);\n    BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(\"1.0 \").get_real(), 1.0);\n\n    BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(\".19e-6\")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON\n    BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue(\"0.00000000000000000000000000000000000001e+30 \")), 1);\n    // Invalid, initial garbage\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"[1.0\"), std::runtime_error);\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"a1.0\"), std::runtime_error);\n    // Invalid, trailing garbage\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"1.0sds\"), std::runtime_error);\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"1.0]\"), std::runtime_error);\n    // NLG addresses should fail parsing\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W\"), std::runtime_error);\n    BOOST_CHECK_THROW(ParseNonRFCJSONValue(\"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL\"), std::runtime_error);\n}\n\nBOOST_AUTO_TEST_CASE(rpc_ban)\n{\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"clearbanned\")));\n\n    UniValue r;\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 127.0.0.0 add\")));\n    BOOST_CHECK_THROW(r = CallRPC(std::string(\"setban 127.0.0.0:8334\")), std::runtime_error); //portnumber for setban not allowed\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    UniValue ar = r.get_array();\n    UniValue o1 = ar[0].get_obj();\n    UniValue adr = find_value(o1, \"address\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"127.0.0.0/32\");\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"setban 127.0.0.0 remove\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    BOOST_CHECK_EQUAL(ar.size(), 0U);\n\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 127.0.0.0/24 add 1607731200 true\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    o1 = ar[0].get_obj();\n    adr = find_value(o1, \"address\");\n    UniValue banned_until = find_value(o1, \"banned_until\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"127.0.0.0/24\");\n    BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check\n\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"clearbanned\")));\n\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 127.0.0.0/24 add 200\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    o1 = ar[0].get_obj();\n    adr = find_value(o1, \"address\");\n    banned_until = find_value(o1, \"banned_until\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"127.0.0.0/24\");\n    int64_t now = GetTime();\n    BOOST_CHECK(banned_until.get_int64() > now);\n    BOOST_CHECK(banned_until.get_int64()-now <= 200);\n\n    // must throw an exception because 127.0.0.1 is in already banned subnet range\n    BOOST_CHECK_THROW(r = CallRPC(std::string(\"setban 127.0.0.1 add\")), std::runtime_error);\n\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"setban 127.0.0.0/24 remove\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    BOOST_CHECK_EQUAL(ar.size(), 0U);\n\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 127.0.0.0/255.255.0.0 add\")));\n    BOOST_CHECK_THROW(r = CallRPC(std::string(\"setban 127.0.1.1 add\")), std::runtime_error);\n\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"clearbanned\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    BOOST_CHECK_EQUAL(ar.size(), 0U);\n\n\n    BOOST_CHECK_THROW(r = CallRPC(std::string(\"setban test add\")), std::runtime_error); //invalid IP\n\n    //IPv6 tests\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    o1 = ar[0].get_obj();\n    adr = find_value(o1, \"address\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"fe80::202:b3ff:fe1e:8329/128\");\n\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"clearbanned\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    o1 = ar[0].get_obj();\n    adr = find_value(o1, \"address\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"2001:db8::/30\");\n\n    BOOST_CHECK_NO_THROW(CallRPC(std::string(\"clearbanned\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add\")));\n    BOOST_CHECK_NO_THROW(r = CallRPC(std::string(\"listbanned\")));\n    ar = r.get_array();\n    o1 = ar[0].get_obj();\n    adr = find_value(o1, \"address\");\n    BOOST_CHECK_EQUAL(adr.get_str(), \"2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128\");\n}\n\nBOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress)\n{\n    UniValue result;\n\n    BOOST_CHECK_NO_THROW(result = RPCConvertValues(\"generatetoaddress\", {\"101\", \"mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a\"}));\n    BOOST_CHECK_EQUAL(result[0].get_int(), 101);\n    BOOST_CHECK_EQUAL(result[1].get_str(), \"mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a\");\n\n    BOOST_CHECK_NO_THROW(result = RPCConvertValues(\"generatetoaddress\", {\"101\", \"mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU\"}));\n    BOOST_CHECK_EQUAL(result[0].get_int(), 101);\n    BOOST_CHECK_EQUAL(result[1].get_str(), \"mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU\");\n\n    BOOST_CHECK_NO_THROW(result = RPCConvertValues(\"generatetoaddress\", {\"1\", \"mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a\", \"9\"}));\n    BOOST_CHECK_EQUAL(result[0].get_int(), 1);\n    BOOST_CHECK_EQUAL(result[1].get_str(), \"mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a\");\n    BOOST_CHECK_EQUAL(result[2].get_int(), 9);\n\n    BOOST_CHECK_NO_THROW(result = RPCConvertValues(\"generatetoaddress\", {\"1\", \"mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU\", \"9\"}));\n    BOOST_CHECK_EQUAL(result[0].get_int(), 1);\n    BOOST_CHECK_EQUAL(result[1].get_str(), \"mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU\");\n    BOOST_CHECK_EQUAL(result[2].get_int(), 9);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/sanity_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"compat/sanity.h\"\n#include \"key.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(basic_sanity)\n{\n  BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, \"libc sanity test\");\n  BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, \"stdlib sanity test\");\n  BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, \"openssl ECC test\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/scheduler_tests.cpp",
    "content": "// Copyright (c) 2012-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <random.h>\n#include <scheduler.h>\n\n#include <boost/test/unit_test.hpp>\n\n#include <functional>\n#include <mutex>\n#include <thread>\n#include <vector>\n\nBOOST_AUTO_TEST_SUITE(scheduler_tests)\n\nstatic void microTask(CScheduler& s, std::mutex& mutex, int& counter, int delta, std::chrono::system_clock::time_point rescheduleTime)\n{\n    {\n        std::lock_guard<std::mutex> lock(mutex);\n        counter += delta;\n    }\n    std::chrono::system_clock::time_point noTime = std::chrono::system_clock::time_point::min();\n    if (rescheduleTime != noTime) {\n        CScheduler::Function f = std::bind(&microTask, std::ref(s), std::ref(mutex), std::ref(counter), -delta + 1, noTime);\n        s.schedule(f, rescheduleTime);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(manythreads)\n{\n    // Stress test: hundreds of microsecond-scheduled tasks,\n    // serviced by 10 threads.\n    //\n    // So... ten shared counters, which if all the tasks execute\n    // properly will sum to the number of tasks done.\n    // Each task adds or subtracts a random amount from one of the\n    // counters, and then schedules another task 0-1000\n    // microseconds in the future to subtract or add from\n    // the counter -random_amount+1, so in the end the shared\n    // counters should sum to the number of initial tasks performed.\n    CScheduler microTasks;\n\n    std::mutex counterMutex[10];\n    int counter[10] = { 0 };\n    FastRandomContext rng{/*fDeterministic=*/true};\n    auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9]\n    auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000]\n    auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000]\n\n    std::chrono::system_clock::time_point start = std::chrono::system_clock::now();\n    std::chrono::system_clock::time_point now = start;\n    std::chrono::system_clock::time_point first, last;\n    size_t nTasks = microTasks.getQueueInfo(first, last);\n    BOOST_CHECK(nTasks == 0);\n\n    for (int i = 0; i < 100; ++i) {\n        std::chrono::system_clock::time_point t = now + std::chrono::microseconds(randomMsec(rng));\n        std::chrono::system_clock::time_point tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));\n        int whichCounter = zeroToNine(rng);\n        CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),\n                                             std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),\n                                             randomDelta(rng), tReschedule);\n        microTasks.schedule(f, t);\n    }\n    nTasks = microTasks.getQueueInfo(first, last);\n    BOOST_CHECK(nTasks == 100);\n    BOOST_CHECK(first < last);\n    BOOST_CHECK(last > now);\n\n    // As soon as these are created they will start running and servicing the queue\n    std::vector<std::thread> microThreads;\n    for (int i = 0; i < 5; i++)\n        microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks));\n\n    //fixme:\n    //UninterruptibleSleep(std::chrono::microseconds{600});\n    now = std::chrono::system_clock::now();\n\n    // More threads and more tasks:\n    for (int i = 0; i < 5; i++)\n        microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks));\n    for (int i = 0; i < 100; i++) {\n        std::chrono::system_clock::time_point t = now + std::chrono::microseconds(randomMsec(rng));\n        std::chrono::system_clock::time_point tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));\n        int whichCounter = zeroToNine(rng);\n        CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),\n                                             std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),\n                                             randomDelta(rng), tReschedule);\n        microTasks.schedule(f, t);\n    }\n\n    // Drain the task queue then exit threads\n    microTasks.StopWhenDrained();\n    // wait until all the threads are done\n    for (auto& thread: microThreads) {\n        if (thread.joinable()) thread.join();\n    }\n\n    int counterSum = 0;\n    for (int i = 0; i < 10; i++) {\n        BOOST_CHECK(counter[i] != 0);\n        counterSum += counter[i];\n    }\n    BOOST_CHECK_EQUAL(counterSum, 200);\n}\n\nBOOST_AUTO_TEST_CASE(wait_until_past)\n{\n    std::condition_variable condvar;\n    Mutex mtx;\n    WAIT_LOCK(mtx, lock);\n\n    const auto no_wait= [&](const std::chrono::seconds& d) {\n        return condvar.wait_until(lock, std::chrono::system_clock::now() - d);\n    };\n\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1}));\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::minutes{1}));\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1}));\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{10}));\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{100}));\n    BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1000}));\n}\n\nBOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)\n{\n    CScheduler scheduler;\n\n    // each queue should be well ordered with respect to itself but not other queues\n    SingleThreadedSchedulerClient queue1(&scheduler);\n    SingleThreadedSchedulerClient queue2(&scheduler);\n\n    // create more threads than queues\n    // if the queues only permit execution of one task at once then\n    // the extra threads should effectively be doing nothing\n    // if they don't we'll get out of order behaviour\n    std::vector<std::thread> threads;\n    for (int i = 0; i < 5; ++i) {\n        threads.emplace_back(std::bind(&CScheduler::serviceQueue, &scheduler));\n    }\n\n    // these are not atomic, if SinglethreadedSchedulerClient prevents\n    // parallel execution at the queue level no synchronization should be required here\n    int counter1 = 0;\n    int counter2 = 0;\n\n    // just simply count up on each queue - if execution is properly ordered then\n    // the callbacks should run in exactly the order in which they were enqueued\n    for (int i = 0; i < 100; ++i) {\n        queue1.AddToProcessQueue([i, &counter1]() {\n            bool expectation = i == counter1++;\n            assert(expectation);\n        });\n\n        queue2.AddToProcessQueue([i, &counter2]() {\n            bool expectation = i == counter2++;\n            assert(expectation);\n        });\n    }\n\n    // finish up\n    scheduler.StopWhenDrained();\n    for (auto& thread: threads) {\n        if (thread.joinable()) thread.join();\n    }\n\n    BOOST_CHECK_EQUAL(counter1, 100);\n    BOOST_CHECK_EQUAL(counter2, 100);\n}\n\nBOOST_AUTO_TEST_CASE(mockforward)\n{\n    CScheduler scheduler;\n\n    int counter{0};\n    CScheduler::Function dummy = [&counter]{counter++;};\n\n    // schedule jobs for 2, 5 & 8 minutes into the future\n\n    scheduler.scheduleFromNow(dummy, std::chrono::minutes{2});\n    scheduler.scheduleFromNow(dummy, std::chrono::minutes{5});\n    scheduler.scheduleFromNow(dummy, std::chrono::minutes{8});\n\n    // check taskQueue\n    std::chrono::system_clock::time_point first, last;\n    size_t num_tasks = scheduler.getQueueInfo(first, last);\n    BOOST_CHECK_EQUAL(num_tasks, 3ul);\n\n    std::thread scheduler_thread([&]() { scheduler.serviceQueue(); });\n\n    // bump the scheduler forward 5 minutes\n    scheduler.MockForward(std::chrono::minutes{5});\n\n    // ensure scheduler has chance to process all tasks queued for before 1 ms from now.\n    scheduler.scheduleFromNow([&scheduler] { scheduler.stop(); }, std::chrono::milliseconds{1});\n    scheduler_thread.join();\n\n    // check that the queue only has one job remaining\n    num_tasks = scheduler.getQueueInfo(first, last);\n    BOOST_CHECK_EQUAL(num_tasks, 1ul);\n\n    // check that the dummy function actually ran\n    BOOST_CHECK_EQUAL(counter, 2);\n\n    // check that the time of the remaining job has been updated\n    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();\n    int delta = std::chrono::duration_cast<std::chrono::seconds>(first - now).count();\n    // should be between 2 & 3 minutes from now\n    BOOST_CHECK(delta > 2*60 && delta < 3*60);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/script_P2SH_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/tx_verify.h\"\n#include \"core_io.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"validation/validation.h\"\n#include \"policy/policy.h\"\n#include \"script/script.h\"\n#include \"script/script_error.h\"\n#include \"script/sign.h\"\n#include \"script/ismine.h\"\n#include \"test/test.h\"\n#include \"witnessutil.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\n// Helpers:\nstatic std::vector<unsigned char>\nSerialize(const CScript& s)\n{\n    std::vector<unsigned char> sSerialized(s.begin(), s.end());\n    return sSerialized;\n}\n\nstatic bool Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)\n{\n    // Create dummy to/from transactions:\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);\n    txFrom.vout.resize(1);\n    txFrom.vout[0].output.scriptPubKey = scriptPubKey;\n\n    CMutableTransaction txTo(TEST_DEFAULT_TX_VERSION);\n    txTo.vin.resize(1);\n    txTo.vout.resize(1);\n    COutPoint changePrevOut = txTo.vin[0].GetPrevOut();\n    changePrevOut.n = 0;\n    changePrevOut.setHash(txFrom.GetHash());\n    txTo.vin[0].SetPrevOut(changePrevOut);\n    txTo.vin[0].scriptSig = scriptSig;\n    txTo.vout[0].nValue = 1;\n\n    return VerifyScript(scriptSig, scriptPubKey, NULL, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, txFrom.vout[0].nValue), SCRIPT_V1, &err);\n}\n\n\nBOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(sign_segsig)\n{\n    LOCK(cs_main);\n    // Pay-to-script-hash looks like this:\n    // scriptSig:    <sig> <sig...> <serialized_script>\n    // scriptPubKey: HASH160 <hash> EQUAL\n\n    #ifdef ENABLE_WALLET\n    // Test SignSignature() (and therefore the version of Solver() that signs transactions)\n    CBasicKeyStore keystore;\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n    }\n\n    // 8 Scripts: checking all combinations of\n    // different keys, straight/P2SH, pubkey/pubkeyhash\n    CScript standardScripts[4];\n    standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;\n    standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID());\n    standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;\n    standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID());\n    CScript evalScripts[4];\n    for (int i = 0; i < 4; i++)\n    {\n        keystore.AddCScript(standardScripts[i]);\n        evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i]));\n    }\n\n    CMutableTransaction txFrom(CTransaction::SEGSIG_ACTIVATION_VERSION);  // Funding transaction:\n    std::string reason;\n    txFrom.vout.resize(8);\n    for (int i = 0; i < 4; i++)\n    {\n        txFrom.vout[i].output.scriptPubKey = evalScripts[i];\n        txFrom.vout[i].nValue = COIN;\n        txFrom.vout[i+4].output.scriptPubKey = standardScripts[i];\n        txFrom.vout[i+4].nValue = COIN;\n    }\n    \n    BOOST_CHECK(IsStandardTx(txFrom, reason, 4, true));\n\n    std::vector<CMutableTransaction> txTo; // Spending transactions\n    txTo.resize(8, CMutableTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION));\n    for (int i = 0; i < 8; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n        BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].output.scriptPubKey), strprintf(\"IsMine %d\", i));\n    }\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n    for (int i = 0; i < 8; i++)\n    {\n        BOOST_CHECK_MESSAGE(SignSignature(accountsToTry, txFrom, txTo[i], 0, SIGHASH_ALL, SignType::Spend), strprintf(\"SignSignature %d\", i));\n    }\n    // All of the above should be OK, and the txTos have valid signatures\n    // Check to make sure signature verification fails if we use the wrong segregatedSignatureData:\n    for (int i = 0; i < 8; i++)\n    {\n        PrecomputedTransactionData txdata(txTo[i]);\n        for (int j = 0; j < 8; j++)\n        {\n            CScript sigSave = txTo[i].vin[0].scriptSig;\n            CSegregatedSignatureData segregatedDataSave = txTo[i].vin[0].segregatedSignatureData;\n            txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;\n            txTo[i].vin[0].segregatedSignatureData = txTo[j].vin[0].segregatedSignatureData;\n            const CTxOut& output = txFrom.vout[txTo[i].vin[0].GetPrevOut().n];\n            bool sigOK = CScriptCheck(CKeyID(), output.output.scriptPubKey, output.nValue, txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata, SCRIPT_V2)();\n            if (i == j)\n                BOOST_CHECK_MESSAGE(sigOK, strprintf(\"VerifySignature %d %d\", i, j));\n            else\n                BOOST_CHECK_MESSAGE(!sigOK, strprintf(\"VerifySignature %d %d\", i, j));\n            txTo[i].vin[0].scriptSig = sigSave;\n            txTo[i].vin[0].segregatedSignatureData = segregatedDataSave;\n        }\n    }\n    #endif\n}\n\nBOOST_AUTO_TEST_CASE(sign)\n{\n    LOCK(cs_main);\n    // Pay-to-script-hash looks like this:\n    // scriptSig:    <sig> <sig...> <serialized_script>\n    // scriptPubKey: HASH160 <hash> EQUAL\n\n    #ifdef ENABLE_WALLET\n    // Test SignSignature() (and therefore the version of Solver() that signs transactions)\n    CBasicKeyStore keystore;\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n    }\n\n    // 8 Scripts: checking all combinations of\n    // different keys, straight/P2SH, pubkey/pubkeyhash\n    CScript standardScripts[4];\n    standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;\n    standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID());\n    standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;\n    standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID());\n    CScript evalScripts[4];\n    for (int i = 0; i < 4; i++)\n    {\n        keystore.AddCScript(standardScripts[i]);\n        evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i]));\n    }\n\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);  // Funding transaction:\n    std::string reason;\n    txFrom.vout.resize(8);\n    for (int i = 0; i < 4; i++)\n    {\n        txFrom.vout[i].output.scriptPubKey = evalScripts[i];\n        txFrom.vout[i].nValue = COIN;\n        txFrom.vout[i+4].output.scriptPubKey = standardScripts[i];\n        txFrom.vout[i+4].nValue = COIN;\n    }\n    int nPoW2Version = GetPoW2Phase(chainActive.Tip());\n    BOOST_CHECK(IsStandardTx(txFrom, reason, nPoW2Version));\n\n    std::vector<CMutableTransaction> txTo; // Spending transactions\n    txTo.resize(8, CMutableTransaction(TEST_DEFAULT_TX_VERSION));\n    for (int i = 0; i < 8; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1;\n        BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].output.scriptPubKey), strprintf(\"IsMine %d\", i));\n    }\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n    for (int i = 0; i < 8; i++)\n    {\n        BOOST_CHECK_MESSAGE(SignSignature(accountsToTry, txFrom, txTo[i], 0, SIGHASH_ALL, SignType::Spend), strprintf(\"SignSignature %d\", i));\n    }\n    // All of the above should be OK, and the txTos have valid signatures\n    // Check to make sure signature verification fails if we use the wrong ScriptSig:\n    for (int i = 0; i < 8; i++) {\n        PrecomputedTransactionData txdata(txTo[i]);\n        for (int j = 0; j < 8; j++)\n        {\n            CScript sigSave = txTo[i].vin[0].scriptSig;\n            txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;\n            const CTxOut& output = txFrom.vout[txTo[i].vin[0].GetPrevOut().n];\n            bool sigOK = CScriptCheck(CKeyID(), output.output.scriptPubKey, output.nValue, txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata, SCRIPT_V1)();\n            if (i == j)\n                BOOST_CHECK_MESSAGE(sigOK, strprintf(\"VerifySignature %d %d\", i, j));\n            else\n                BOOST_CHECK_MESSAGE(!sigOK, strprintf(\"VerifySignature %d %d\", i, j));\n            txTo[i].vin[0].scriptSig = sigSave;\n        }\n    }\n    #endif\n}\n\nBOOST_AUTO_TEST_CASE(norecurse)\n{\n    ScriptError err;\n    // Make sure only the outer pay-to-script-hash does the\n    // extra-validation thing:\n    CScript invalidAsScript;\n    invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;\n\n    CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript));\n\n    CScript scriptSig;\n    scriptSig << Serialize(invalidAsScript);\n\n    // Should not verify, because it will try to execute OP_INVALIDOPCODE\n    BOOST_CHECK(!Verify(scriptSig, p2sh, true, err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err));\n\n    // Try to recur, and verification should succeed because\n    // the inner HASH160 <> EQUAL should only check the hash:\n    CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh));\n    CScript scriptSig2;\n    scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);\n\n    BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n}\n\nBOOST_AUTO_TEST_CASE(set)\n{\n    #ifdef ENABLE_WALLET\n    LOCK(cs_main);\n    // Test the CScript::Set* methods\n    CBasicKeyStore keystore;\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n    CKey key[4];\n    std::vector<CPubKey> keys;\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n        keys.push_back(key[i].GetPubKey());\n    }\n\n    CScript inner[4];\n    inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID());\n    inner[1] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));\n    inner[2] = GetScriptForMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));\n    inner[3] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));\n\n    CScript outer[4];\n    for (int i = 0; i < 4; i++)\n    {\n        outer[i] = GetScriptForDestination(CScriptID(inner[i]));\n        keystore.AddCScript(inner[i]);\n    }\n\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);  // Funding transaction:\n    std::string reason;\n    txFrom.vout.resize(4);\n    for (int i = 0; i < 4; i++)\n    {\n        txFrom.vout[i].output.scriptPubKey = outer[i];\n        txFrom.vout[i].nValue = CENT;\n    }\n    int nPoW2Version = GetPoW2Phase(chainActive.Tip());\n    BOOST_CHECK(IsStandardTx(txFrom, reason, nPoW2Version));\n\n    std::vector<CMutableTransaction> txTo; // Spending transactions\n    txTo.resize(4, CMutableTransaction(TEST_DEFAULT_TX_VERSION));\n    for (int i = 0; i < 4; i++)\n    {\n        txTo[i].vin.resize(1);\n        txTo[i].vout.resize(1);\n        COutPoint changePrevOut = txTo[i].vin[0].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo[i].vin[0].SetPrevOut(changePrevOut);\n        txTo[i].vout[0].nValue = 1*CENT;\n        txTo[i].vout[0].output.scriptPubKey = inner[i];\n        BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].output.scriptPubKey), strprintf(\"IsMine %d\", i));\n    }\n    for (int i = 0; i < 4; i++)\n    {\n        BOOST_CHECK_MESSAGE(SignSignature(accountsToTry, txFrom, txTo[i], 0, SIGHASH_ALL, SignType::Spend), strprintf(\"SignSignature %d\", i));\n        BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason, nPoW2Version), strprintf(\"txTo[%d].IsStandard\", i));\n    }\n    #endif\n}\n\nBOOST_AUTO_TEST_CASE(is)\n{\n    // Test CScript::IsPayToScriptHash()\n    uint160 dummy;\n    CScript p2sh;\n    p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL;\n    BOOST_CHECK(p2sh.IsPayToScriptHash());\n\n    // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes:\n    static const unsigned char direct[] =    { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };\n    BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash());\n    static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };\n    BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash());\n    static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };\n    BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash());\n    static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };\n    BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash());\n\n    CScript not_p2sh;\n    BOOST_CHECK(!not_p2sh.IsPayToScriptHash());\n\n    not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << ToByteVector(dummy) << OP_EQUAL;\n    BOOST_CHECK(!not_p2sh.IsPayToScriptHash());\n\n    not_p2sh.clear(); not_p2sh << OP_NOP << ToByteVector(dummy) << OP_EQUAL;\n    BOOST_CHECK(!not_p2sh.IsPayToScriptHash());\n\n    not_p2sh.clear(); not_p2sh << OP_HASH160 << ToByteVector(dummy) << OP_CHECKSIG;\n    BOOST_CHECK(!not_p2sh.IsPayToScriptHash());\n}\n\nBOOST_AUTO_TEST_CASE(switchover)\n{\n    // Test switch over code\n    CScript notValid;\n    ScriptError err;\n    notValid << OP_11 << OP_12 << OP_EQUALVERIFY;\n    CScript scriptSig;\n    scriptSig << Serialize(notValid);\n\n    CScript fund = GetScriptForDestination(CScriptID(notValid));\n\n\n    // Validation should succeed under old rules (hash is correct):\n    BOOST_CHECK(Verify(scriptSig, fund, false, err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n    // Fail under new:\n    BOOST_CHECK(!Verify(scriptSig, fund, true, err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err));\n}\n\nBOOST_AUTO_TEST_CASE(AreInputsStandard)\n{\n    LOCK(cs_main);\n    CCoinsView coinsDummy;\n    CCoinsViewCache coins(&coinsDummy);\n    CBasicKeyStore keystore;\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n    CKey key[6];\n    std::vector<CPubKey> keys;\n    for (int i = 0; i < 6; i++)\n    {\n        key[i].MakeNewKey(true);\n        keystore.AddKey(key[i]);\n    }\n    for (int i = 0; i < 3; i++)\n        keys.push_back(key[i].GetPubKey());\n\n    CMutableTransaction txFrom(TEST_DEFAULT_TX_VERSION);\n    txFrom.vout.resize(7);\n\n    // First three are standard:\n    CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID());\n    keystore.AddCScript(pay1);\n    CScript pay1of3 = GetScriptForMultisig(1, keys);\n\n    txFrom.vout[0].output.scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG)\n    txFrom.vout[0].nValue = 1000;\n    txFrom.vout[1].output.scriptPubKey = pay1; // ordinary OP_CHECKSIG\n    txFrom.vout[1].nValue = 2000;\n    txFrom.vout[2].output.scriptPubKey = pay1of3; // ordinary OP_CHECKMULTISIG\n    txFrom.vout[2].nValue = 3000;\n\n    // vout[3] is complicated 1-of-3 AND 2-of-3\n    // ... that is OK if wrapped in P2SH:\n    CScript oneAndTwo;\n    oneAndTwo << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey());\n    oneAndTwo << OP_3 << OP_CHECKMULTISIGVERIFY;\n    oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey());\n    oneAndTwo << OP_3 << OP_CHECKMULTISIG;\n    keystore.AddCScript(oneAndTwo);\n    txFrom.vout[3].output.scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo));\n    txFrom.vout[3].nValue = 4000;\n\n    // vout[4] is max sigops:\n    CScript fifteenSigops; fifteenSigops << OP_1;\n    for (unsigned i = 0; i < MAX_P2SH_SIGOPS; i++)\n        fifteenSigops << ToByteVector(key[i%3].GetPubKey());\n    fifteenSigops << OP_15 << OP_CHECKMULTISIG;\n    keystore.AddCScript(fifteenSigops);\n    txFrom.vout[4].output.scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops));\n    txFrom.vout[4].nValue = 5000;\n\n    // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS\n    CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG;\n    keystore.AddCScript(sixteenSigops);\n    txFrom.vout[5].output.scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops));\n    txFrom.vout[5].nValue = 5000;\n    CScript twentySigops; twentySigops << OP_CHECKMULTISIG;\n    keystore.AddCScript(twentySigops);\n    txFrom.vout[6].output.scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));\n    txFrom.vout[6].nValue = 6000;\n\n    AddCoins(coins, txFrom, 0, 0);\n\n    CMutableTransaction txTo(TEST_DEFAULT_TX_VERSION);\n    txTo.vout.resize(1);\n    txTo.vout[0].output.scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());\n\n    txTo.vin.resize(5);\n    for (int i = 0; i < 5; i++)\n    {\n        COutPoint changePrevOut = txTo.vin[i].GetPrevOut();\n        changePrevOut.n = i;\n        changePrevOut.setHash(txFrom.GetHash());\n        txTo.vin[i].SetPrevOut(changePrevOut);\n    }\n    BOOST_CHECK(SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend));\n    BOOST_CHECK(SignSignature(accountsToTry, txFrom, txTo, 1, SIGHASH_ALL, SignType::Spend));\n    BOOST_CHECK(SignSignature(accountsToTry, txFrom, txTo, 2, SIGHASH_ALL, SignType::Spend));\n    // SignSignature doesn't know how to sign these. We're\n    // not testing validating signatures, so just create\n    // dummy signatures that DO include the correct P2SH scripts:\n    txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());\n    txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());\n\n    BOOST_CHECK(::AreInputsStandard(txTo, coins));\n    // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]\n    BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);\n\n    CMutableTransaction txToNonStd1(TEST_DEFAULT_TX_VERSION);\n    txToNonStd1.vout.resize(1);\n    txToNonStd1.vout[0].output.scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());\n    txToNonStd1.vout[0].nValue = 1000;\n    txToNonStd1.vin.resize(1);\n    COutPoint changePrevOut = txToNonStd1.vin[0].GetPrevOut();\n    changePrevOut.n = 5;\n    changePrevOut.setHash(txFrom.GetHash());\n    txToNonStd1.vin[0].SetPrevOut(changePrevOut);\n    txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());\n\n    BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));\n    BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);\n\n    CMutableTransaction txToNonStd2(TEST_DEFAULT_TX_VERSION);\n    txToNonStd2.vout.resize(1);\n    txToNonStd2.vout[0].output.scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());\n    txToNonStd2.vout[0].nValue = 1000;\n    txToNonStd2.vin.resize(1);\n    changePrevOut = txToNonStd2.vin[0].GetPrevOut();\n    changePrevOut.n = 6;\n    changePrevOut.setHash(txFrom.GetHash());\n    txToNonStd2.vin[0].SetPrevOut(changePrevOut);\n    txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end());\n\n    BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));\n    BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/script_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"data/script_tests.json.h\"\n\n#include \"core_io.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"script/script.h\"\n#include \"script/script_error.h\"\n#include \"script/sign.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"test/test.h\"\n#include \"rpc/server.h\"\n\n#if defined(HAVE_CONSENSUS_LIB)\n#include \"script/consensus.h\"\n#endif\n\n#include <fstream>\n#include <stdint.h>\n#include <string>\n#include <vector>\n\n\n#include <boost/test/unit_test.hpp>\n\n#include <univalue.h>\n\n// Uncomment if you want to output updated JSON tests.\n// #define UPDATE_JSON_TESTS\n\nstatic const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;\n\nunsigned int ParseScriptFlags(std::string strFlags);\nstd::string FormatScriptFlags(unsigned int flags);\n\nUniValue read_json(const std::string& jsondata)\n{\n    UniValue v;\n\n    if (!v.read(jsondata) || !v.isArray())\n    {\n        BOOST_ERROR(\"Parse error.\");\n        return UniValue(UniValue::VARR);\n    }\n    return v.get_array();\n}\n\nstruct ScriptErrorDesc\n{\n    ScriptError_t err;\n    const char *name;\n};\n\nstatic ScriptErrorDesc script_errors[]={\n    {SCRIPT_ERR_OK, \"OK\"},\n    {SCRIPT_ERR_UNKNOWN_ERROR, \"UNKNOWN_ERROR\"},\n    {SCRIPT_ERR_EVAL_FALSE, \"EVAL_FALSE\"},\n    {SCRIPT_ERR_OP_RETURN, \"OP_RETURN\"},\n    {SCRIPT_ERR_SCRIPT_SIZE, \"SCRIPT_SIZE\"},\n    {SCRIPT_ERR_PUSH_SIZE, \"PUSH_SIZE\"},\n    {SCRIPT_ERR_OP_COUNT, \"OP_COUNT\"},\n    {SCRIPT_ERR_STACK_SIZE, \"STACK_SIZE\"},\n    {SCRIPT_ERR_SIG_COUNT, \"SIG_COUNT\"},\n    {SCRIPT_ERR_PUBKEY_COUNT, \"PUBKEY_COUNT\"},\n    {SCRIPT_ERR_VERIFY, \"VERIFY\"},\n    {SCRIPT_ERR_EQUALVERIFY, \"EQUALVERIFY\"},\n    {SCRIPT_ERR_CHECKMULTISIGVERIFY, \"CHECKMULTISIGVERIFY\"},\n    {SCRIPT_ERR_CHECKSIGVERIFY, \"CHECKSIGVERIFY\"},\n    {SCRIPT_ERR_NUMEQUALVERIFY, \"NUMEQUALVERIFY\"},\n    {SCRIPT_ERR_BAD_OPCODE, \"BAD_OPCODE\"},\n    {SCRIPT_ERR_DISABLED_OPCODE, \"DISABLED_OPCODE\"},\n    {SCRIPT_ERR_INVALID_STACK_OPERATION, \"INVALID_STACK_OPERATION\"},\n    {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, \"INVALID_ALTSTACK_OPERATION\"},\n    {SCRIPT_ERR_UNBALANCED_CONDITIONAL, \"UNBALANCED_CONDITIONAL\"},\n    {SCRIPT_ERR_NEGATIVE_LOCKTIME, \"NEGATIVE_LOCKTIME\"},\n    {SCRIPT_ERR_UNSATISFIED_LOCKTIME, \"UNSATISFIED_LOCKTIME\"},\n    {SCRIPT_ERR_SIG_HASHTYPE, \"SIG_HASHTYPE\"},\n    {SCRIPT_ERR_SIG_DER, \"SIG_DER\"},\n    {SCRIPT_ERR_MINIMALDATA, \"MINIMALDATA\"},\n    {SCRIPT_ERR_SIG_PUSHONLY, \"SIG_PUSHONLY\"},\n    {SCRIPT_ERR_SIG_HIGH_S, \"SIG_HIGH_S\"},\n    {SCRIPT_ERR_PUBKEYTYPE, \"PUBKEYTYPE\"},\n    {SCRIPT_ERR_CLEANSTACK, \"CLEANSTACK\"},\n    {SCRIPT_ERR_MINIMALIF, \"MINIMALIF\"},\n    {SCRIPT_ERR_SIG_NULLFAIL, \"NULLFAIL\"},\n    {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, \"DISCOURAGE_UPGRADABLE_NOPS\"},\n    {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, \"DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM\"},\n    {SCRIPT_ERR_SEGSIG_PUBKEYTYPE, \"SEGSIG_PUBKEYTYPE\"},\n};\n\nstatic const char *FormatScriptError(ScriptError_t err)\n{\n    for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i)\n        if (script_errors[i].err == err)\n            return script_errors[i].name;\n    BOOST_ERROR(\"Unknown scripterror enumeration value, update script_errors in script_tests.cpp.\");\n    return \"\";\n}\n\nstatic ScriptError_t ParseScriptError(const std::string &name)\n{\n    for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i)\n        if (script_errors[i].name == name)\n            return script_errors[i].err;\n    BOOST_ERROR(\"Unknown scripterror \\\"\" << name << \"\\\" in test description\");\n    return SCRIPT_ERR_UNKNOWN_ERROR;\n}\n\nBOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup)\n\nstatic CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int nValue = 0)\n{\n    CMutableTransaction txCredit(TEST_DEFAULT_TX_VERSION);\n    txCredit.nVersion = 1;\n    txCredit.nLockTime = 0;\n    txCredit.vin.resize(1);\n    txCredit.vout.resize(1);\n    txCredit.vin[0].SetPrevOutNull();\n    txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);\n    txCredit.vin[0].SetSequence(CTxIn::SEQUENCE_FINAL, txCredit.nVersion, CTxInFlags::None);\n    txCredit.vout[0].output.scriptPubKey = scriptPubKey;\n    txCredit.vout[0].nValue = nValue;\n\n    return txCredit;\n}\n\nstatic CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSegregatedSignatureData& segregatedSignatureData, const CMutableTransaction& txCredit)\n{\n    CMutableTransaction txSpend(TEST_DEFAULT_TX_VERSION);\n    txSpend.nVersion = 1;\n    txSpend.nLockTime = 0;\n    txSpend.vin.resize(1);\n    txSpend.vout.resize(1);\n    txSpend.vin[0].segregatedSignatureData = segregatedSignatureData;\n    COutPoint changePrevOut = txSpend.vin[0].GetPrevOut();\n    changePrevOut.setHash(txCredit.GetHash());\n    changePrevOut.n = 0;\n    txSpend.vin[0].SetPrevOut(changePrevOut);\n    txSpend.vin[0].scriptSig = scriptSig;\n    txSpend.vin[0].SetSequence(CTxIn::SEQUENCE_FINAL, txSpend.nVersion, CTxInFlags::None);\n    txSpend.vout[0].output.scriptPubKey = CScript();\n    txSpend.vout[0].nValue = txCredit.vout[0].nValue;\n\n    return txSpend;\n}\n\nstatic void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CSegregatedSignatureData& segregatedSignatureData, int flags, const std::string& message, int scriptError, CAmount nValue = 0)\n{\n    bool expect = (scriptError == SCRIPT_ERR_OK);\n    if (flags & SCRIPT_VERIFY_CLEANSTACK)\n    {\n        flags |= SCRIPT_VERIFY_P2SH;\n    }\n    ScriptError err;\n    CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue);\n    CMutableTransaction tx = BuildSpendingTransaction(scriptSig, segregatedSignatureData, txCredit);\n    CMutableTransaction tx2 = tx;\n    BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &segregatedSignatureData, flags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &tx, 0, txCredit.vout[0].nValue), SCRIPT_V1, &err) == expect, message);\n    BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + \" where \" + std::string(FormatScriptError((ScriptError_t)scriptError)) + \" expected: \" + message);\n#if defined(HAVE_CONSENSUS_LIB)\n    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);\n    stream << tx2;\n    int libconsensus_flags = flags & SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_ALL;\n    if (libconsensus_flags == flags) {\n        if (flags & SCRIPT_CONSENSUS_SCRIPT_FLAGS_VERIFY_WITNESS) {\n            BOOST_CHECK_MESSAGE(script_consensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);\n        } else {\n            BOOST_CHECK_MESSAGE(script_consensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);\n            BOOST_CHECK_MESSAGE(script_consensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect,message);\n        }\n    }\n#endif\n}\n\nvoid static NegateSignatureS(std::vector<unsigned char>& vchSig) {\n    // Parse the signature.\n    std::vector<unsigned char> r, s;\n    r = std::vector<unsigned char>(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]);\n    s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]);\n\n    // Really ugly to implement mod-n negation here, but it would be feature creep to expose such functionality from libsecp256k1.\n    static const unsigned char order[33] = {\n        0x00,\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,\n        0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,\n        0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41\n    };\n    while (s.size() < 33) {\n        s.insert(s.begin(), 0x00);\n    }\n    int carry = 0;\n    for (int p = 32; p >= 1; p--) {\n        int n = (int)order[p] - s[p] - carry;\n        s[p] = (n + 256) & 0xFF;\n        carry = (n < 0);\n    }\n    assert(carry == 0);\n    if (s.size() > 1 && s[0] == 0 && s[1] < 0x80) {\n        s.erase(s.begin());\n    }\n\n    // Reconstruct the signature.\n    vchSig.clear();\n    vchSig.push_back(0x30);\n    vchSig.push_back(4 + r.size() + s.size());\n    vchSig.push_back(0x02);\n    vchSig.push_back(r.size());\n    vchSig.insert(vchSig.end(), r.begin(), r.end());\n    vchSig.push_back(0x02);\n    vchSig.push_back(s.size());\n    vchSig.insert(vchSig.end(), s.begin(), s.end());\n}\n\nnamespace\n{\nconst unsigned char vchKey0[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};\nconst unsigned char vchKey1[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0};\nconst unsigned char vchKey2[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0};\n\nstruct KeyData\n{\n    CKey key0, key0C, key1, key1C, key2, key2C;\n    CPubKey pubkey0, pubkey0C, pubkey0H;\n    CPubKey pubkey1, pubkey1C;\n    CPubKey pubkey2, pubkey2C;\n\n    KeyData()\n    {\n\n        key0.Set(vchKey0, vchKey0 + 32, false);\n        key0C.Set(vchKey0, vchKey0 + 32, true);\n        pubkey0 = key0.GetPubKey();\n        pubkey0H = key0.GetPubKey();\n        pubkey0C = key0C.GetPubKey();\n        *const_cast<unsigned char*>(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1);\n\n        key1.Set(vchKey1, vchKey1 + 32, false);\n        key1C.Set(vchKey1, vchKey1 + 32, true);\n        pubkey1 = key1.GetPubKey();\n        pubkey1C = key1C.GetPubKey();\n\n        key2.Set(vchKey2, vchKey2 + 32, false);\n        key2C.Set(vchKey2, vchKey2 + 32, true);\n        pubkey2 = key2.GetPubKey();\n        pubkey2C = key2C.GetPubKey();\n    }\n};\n\nclass TestBuilder\n{\nprivate:\n    //! Actually executed script\n    CScript script;\n    //! The P2SH redeemscript\n    CScript redeemscript;\n    CSegregatedSignatureData segregatedSignatureData;\n    CTransactionRef creditTx;\n    CMutableTransaction spendTx;\n    bool havePush;\n    std::vector<unsigned char> push;\n    std::string comment;\n    int flags;\n    int scriptError;\n    CAmount nValue;\n\n    void DoPush()\n    {\n        if (havePush) {\n            spendTx.vin[0].scriptSig << push;\n            havePush = false;\n        }\n    }\n\n    void DoPush(const std::vector<unsigned char>& data)\n    {\n         DoPush();\n         push = data;\n         havePush = true;\n    }\n\npublic:\n    TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, CAmount nValue_ = 0) : script(script_), spendTx(TEST_DEFAULT_TX_VERSION), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_)\n    {\n        CScript scriptPubKey = script;\n        if (P2SH)\n        {\n            redeemscript = scriptPubKey;\n            scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL;\n        }\n        creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue));\n        spendTx = BuildSpendingTransaction(CScript(), CSegregatedSignatureData(), *creditTx);\n    }\n\n    TestBuilder& ScriptError(ScriptError_t err)\n    {\n        scriptError = err;\n        return *this;\n    }\n\n    TestBuilder& Add(const CScript& _script)\n    {\n        DoPush();\n        spendTx.vin[0].scriptSig += _script;\n        return *this;\n    }\n\n    TestBuilder& Num(int num)\n    {\n        DoPush();\n        spendTx.vin[0].scriptSig << num;\n        return *this;\n    }\n\n    TestBuilder& Push(const std::string& hex)\n    {\n        DoPush(ParseHex(hex));\n        return *this;\n    }\n\n    TestBuilder& Push(const CScript& _script) {\n         DoPush(std::vector<unsigned char>(_script.begin(), _script.end()));\n        return *this;\n    }\n\n    TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_BASE, CAmount amount = 0)\n    {\n        uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount, sigversion);\n        std::vector<unsigned char> vchSig, r, s;\n        uint32_t iter = 0;\n        do {\n            key.Sign(hash, vchSig, iter++);\n            if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) {\n                NegateSignatureS(vchSig);\n            }\n            r = std::vector<unsigned char>(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]);\n            s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]);\n        } while (lenR != r.size() || lenS != s.size());\n        vchSig.push_back(static_cast<unsigned char>(nHashType));\n        DoPush(vchSig);\n        return *this;\n    }\n\n    TestBuilder& Push(const CPubKey& pubkey)\n    {\n        DoPush(std::vector<unsigned char>(pubkey.begin(), pubkey.end()));\n        return *this;\n    }\n\n    TestBuilder& PushRedeem()\n    {\n        DoPush(std::vector<unsigned char>(redeemscript.begin(), redeemscript.end()));\n        return *this;\n    }\n\n    TestBuilder& EditPush(unsigned int pos, const std::string& hexin, const std::string& hexout)\n    {\n        assert(havePush);\n        std::vector<unsigned char> datain = ParseHex(hexin);\n        std::vector<unsigned char> dataout = ParseHex(hexout);\n        assert(pos + datain.size() <= push.size());\n        BOOST_CHECK_MESSAGE(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment);\n        push.erase(push.begin() + pos, push.begin() + pos + datain.size());\n        push.insert(push.begin() + pos, dataout.begin(), dataout.end());\n        return *this;\n    }\n\n    TestBuilder& DamagePush(unsigned int pos)\n    {\n        assert(havePush);\n        assert(pos < push.size());\n        push[pos] ^= 1;\n        return *this;\n    }\n\n    TestBuilder& Test()\n    {\n        TestBuilder copy = *this; // Make a copy so we can rollback the push.\n        DoPush();\n        DoTest(creditTx->vout[0].output.scriptPubKey, spendTx.vin[0].scriptSig, segregatedSignatureData, flags, comment, scriptError, nValue);\n        *this = copy;\n        return *this;\n    }\n\n    TestBuilder& AsWit()\n    {\n        assert(havePush);\n        segregatedSignatureData.stack.push_back(push);\n        havePush = false;\n        return *this;\n    }\n\n    UniValue GetJSON()\n    {\n        DoPush();\n        UniValue array(UniValue::VARR);\n        if (!segregatedSignatureData.stack.empty()) {\n            UniValue wit(UniValue::VARR);\n            for (unsigned i = 0; i < segregatedSignatureData.stack.size(); i++) {\n                wit.push_back(HexStr(segregatedSignatureData.stack[i]));\n            }\n            wit.push_back(ValueFromAmount(nValue));\n            array.push_back(wit);\n        }\n        array.push_back(FormatScript(spendTx.vin[0].scriptSig));\n        array.push_back(FormatScript(creditTx->vout[0].output.scriptPubKey));\n        array.push_back(FormatScriptFlags(flags));\n        array.push_back(FormatScriptError((ScriptError_t)scriptError));\n        array.push_back(comment);\n        return array;\n    }\n\n    std::string GetComment()\n    {\n        return comment;\n    }\n};\n\nstd::string JSONPrettyPrint(const UniValue& univalue)\n{\n    std::string ret = univalue.write(4);\n    // Workaround for libunivalue pretty printer, which puts a space between commas and newlines\n    size_t pos = 0;\n    while ((pos = ret.find(\" \\n\", pos)) != std::string::npos) {\n        ret.replace(pos, 2, \"\\n\");\n        pos++;\n    }\n    return ret;\n}\n}\n\nBOOST_AUTO_TEST_CASE(script_build)\n{\n    const KeyData keys;\n\n    std::vector<TestBuilder> tests;\n\n    #define AST(x) tests.push_back(x)\n    #define MKTEST(...) TestBuilder(CScript() << __VA_ARGS__)\n    #define PUBKEY0 ToByteVector(keys.pubkey0)\n    #define PUBKEY1 ToByteVector(keys.pubkey1)\n\n    #define PUBKEY0C ToByteVector(keys.pubkey0C)\n    #define PUBKEY1C ToByteVector(keys.pubkey1C)\n    #define PUBKEY2C ToByteVector(keys.pubkey2C)\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2PK\", 0).PushSig(keys.key0));\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2PK, bad sig\", 0).PushSig(keys.key0).DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,\"P2PKH\", 0).PushSig(keys.key1).Push(keys.pubkey1C));\n    AST(MKTEST(OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,\"P2PKH, bad pubkey\", 0).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5).ScriptError(SCRIPT_ERR_EQUALVERIFY));\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG,\"P2PK anyonecanpay\", 0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY));\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG,\"P2PK anyonecanpay marked with normal hashtype\", 0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, \"81\", \"01\").ScriptError(SCRIPT_ERR_EVAL_FALSE));\n\n    AST(MKTEST(PUBKEY0C << OP_CHECKSIG,\"P2SH(P2PK)\", SCRIPT_VERIFY_P2SH, true).PushSig(keys.key0).PushRedeem());\n    AST(MKTEST(PUBKEY0C << OP_CHECKSIG,\"P2SH(P2PK), bad redeemscript\", SCRIPT_VERIFY_P2SH, true).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n\n    AST(MKTEST(OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,\"P2SH(P2PKH)\", SCRIPT_VERIFY_P2SH, true).PushSig(keys.key0).Push(keys.pubkey0).PushRedeem());\n    AST(MKTEST(OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,\"P2SH(P2PKH), bad sig but no VERIFY_P2SH\", 0, true).PushSig(keys.key0).DamagePush(10).PushRedeem());\n    AST(MKTEST(OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,\"P2SH(P2PKH), bad sig\", SCRIPT_VERIFY_P2SH, true).PushSig(keys.key0).DamagePush(10).PushRedeem().ScriptError(SCRIPT_ERR_EQUALVERIFY));\n\n    AST(MKTEST(OP_3 << PUBKEY0C << PUBKEY1C << PUBKEY2C << OP_3 << OP_CHECKMULTISIG,\"3-of-3\", 0).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));\n    AST(MKTEST(OP_3 << PUBKEY0C << PUBKEY1C << PUBKEY2C << OP_3 << OP_CHECKMULTISIG,\"3-of-3, 2 sigs\", 0).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n\n    AST(MKTEST(OP_2 << PUBKEY0C << PUBKEY1C << PUBKEY2C << OP_3 << OP_CHECKMULTISIG,\"P2SH(2-of-3)\", SCRIPT_VERIFY_P2SH, true).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem());\n    AST(MKTEST(OP_2 << PUBKEY0C << PUBKEY1C << PUBKEY2C << OP_3 << OP_CHECKMULTISIG,\"P2SH(2-of-3), 1 sig\", SCRIPT_VERIFY_P2SH, true).Num(0).PushSig(keys.key1).Num(0).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE));\n\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too much R padding but no DERSIG\", 0).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\"));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too much R padding\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too much S padding but no DERSIG\", 0).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, \"44\", \"45\").EditPush(37, \"20\", \"2100\"));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too much S padding\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, \"44\", \"45\").EditPush(37, \"20\", \"2100\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too little R padding but no DERSIG\", 0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\"));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"P2PK with too little R padding\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG << OP_NOT,\"P2PK NOT with bad sig with too much R padding but no DERSIG\", 0).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\").DamagePush(10));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG << OP_NOT,\"P2PK NOT with bad sig with too much R padding\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\").DamagePush(10).ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG << OP_NOT,\"P2PK NOT with too much R padding but no DERSIG\", 0).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\").ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG << OP_NOT,\"P2PK NOT with too much R padding\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, \"43021F\", \"44022000\").ScriptError(SCRIPT_ERR_SIG_DER));\n\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 1, without DERSIG\", 0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\"));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 1, with DERSIG\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 2, without DERSIG\", 0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 2, with DERSIG\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 3, without DERSIG\", 0).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 3, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 4, without DERSIG\", 0).Num(0));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 4, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 5, without DERSIG\", 0).Num(1).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG,\"BIP66 example 5, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(1).ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 6, without DERSIG\", 0).Num(1));\n    AST(MKTEST(PUBKEY1C << OP_CHECKSIG << OP_NOT,\"BIP66 example 6, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(1).ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 7, without DERSIG\", 0).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").PushSig(keys.key2));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 7, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 8, without DERSIG\", 0).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").PushSig(keys.key2).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 8, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 9, without DERSIG\", 0).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 9, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 10, without DERSIG\", 0).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\"));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 10, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").ScriptError(SCRIPT_ERR_SIG_DER));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 11, without DERSIG\", 0).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG,\"BIP66 example 11, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 12, without DERSIG\", 0).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").Num(0));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY2C << OP_2 << OP_CHECKMULTISIG << OP_NOT,\"BIP66 example 12, with DERSIG\", SCRIPT_VERIFY_DERSIG).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, \"45022100\", \"440220\").Num(0));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2PK with multi-byte hashtype, without DERSIG\", 0).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, \"01\", \"0101\"));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2PK with multi-byte hashtype, with DERSIG\", SCRIPT_VERIFY_DERSIG).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, \"01\", \"0101\").ScriptError(SCRIPT_ERR_SIG_DER));\n    \n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2PK with high S but no LOW_S\", 0).PushSig(keys.key2, SIGHASH_ALL, 32, 33));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2PK with high S\", SCRIPT_VERIFY_LOW_S).PushSig(keys.key2, SIGHASH_ALL, 32, 33).ScriptError(SCRIPT_ERR_SIG_HIGH_S));\n    \n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG,\"P2PK with hybrid pubkey but no STRICTENC\", 0).PushSig(keys.key0, SIGHASH_ALL));\n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG,\"P2PK with hybrid pubkey\", SCRIPT_VERIFY_STRICTENC).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));\n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,\"P2PK NOT with hybrid pubkey but no STRICTENC\", 0).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_EVAL_FALSE));\n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,\"P2PK NOT with hybrid pubkey\", SCRIPT_VERIFY_STRICTENC).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));\n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,\"P2PK NOT with invalid hybrid pubkey but no STRICTENC\", 0).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));\n    AST(MKTEST(ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,\"P2PK NOT with invalid hybrid pubkey\", SCRIPT_VERIFY_STRICTENC).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10).ScriptError(SCRIPT_ERR_PUBKEYTYPE));\n    AST(MKTEST(OP_1 << ToByteVector(keys.pubkey0H) << PUBKEY1C << OP_2 << OP_CHECKMULTISIG,\"1-of-2 with the second 1 hybrid pubkey and no STRICTENC\", 0).Num(0).PushSig(keys.key1, SIGHASH_ALL));\n    AST(MKTEST(OP_1 << ToByteVector(keys.pubkey0H) << PUBKEY1C << OP_2 << OP_CHECKMULTISIG,\"1-of-2 with the second 1 hybrid pubkey\", SCRIPT_VERIFY_STRICTENC).Num(0).PushSig(keys.key1, SIGHASH_ALL));\n    AST(MKTEST(OP_1 << PUBKEY1C << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG,\"1-of-2 with the first 1 hybrid pubkey\", SCRIPT_VERIFY_STRICTENC).Num(0).PushSig(keys.key1, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE));\n\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG,\"P2PK with undefined hashtype but no STRICTENC\", 0).PushSig(keys.key1, 5));\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG,\"P2PK with undefined hashtype\", SCRIPT_VERIFY_STRICTENC).PushSig(keys.key1, 5).ScriptError(SCRIPT_ERR_SIG_HASHTYPE));\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG << OP_NOT,\"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC\", 0).PushSig(keys.key1, 5).DamagePush(10));\n    AST(MKTEST(PUBKEY1 << OP_CHECKSIG << OP_NOT,\"P2PK NOT with invalid sig and undefined hashtype\", SCRIPT_VERIFY_STRICTENC).PushSig(keys.key1, 5).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_HASHTYPE));\n\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY1C << OP_2 << OP_CHECKMULTISIG,\"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY\", 0).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY1C << OP_2 << OP_CHECKMULTISIG,\"2-of-2 with two identical keys and sigs pushed using OP_DUP\", SCRIPT_VERIFY_SIGPUSHONLY).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY\", 0, true).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem());\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2PK with non-push scriptSig but with P2SH validation\", 0).PushSig(keys.key2).Add(CScript() << OP_NOP8));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY\", SCRIPT_VERIFY_P2SH, true).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY));\n    AST(MKTEST(PUBKEY2C << OP_CHECKSIG,\"P2SH(P2PK) with non-push scriptSig but not P2SH\", SCRIPT_VERIFY_SIGPUSHONLY, true).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY));\n    AST(MKTEST(OP_2 << PUBKEY1C << PUBKEY1C << OP_2 << OP_CHECKMULTISIG,\"2-of-2 with two identical keys and sigs pushed\", SCRIPT_VERIFY_SIGPUSHONLY).Num(0).PushSig(keys.key1).PushSig(keys.key1));\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2PK with unnecessary input but no CLEANSTACK\", SCRIPT_VERIFY_P2SH).Num(11).PushSig(keys.key0));\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2PK with unnecessary input\", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH).Num(11).PushSig(keys.key0).ScriptError(SCRIPT_ERR_CLEANSTACK));\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2SH with unnecessary input but no CLEANSTACK\", SCRIPT_VERIFY_P2SH, true).Num(11).PushSig(keys.key0).PushRedeem());\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2SH with unnecessary input\", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true).Num(11).PushSig(keys.key0).PushRedeem().ScriptError(SCRIPT_ERR_CLEANSTACK));\n    AST(MKTEST(PUBKEY0 << OP_CHECKSIG,\"P2SH with CLEANSTACK\", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true).PushSig(keys.key0).PushRedeem());\n\n    std::set<std::string> tests_set;\n    {\n        UniValue json_tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests)));\n\n        for (unsigned int idx = 0; idx < json_tests.size(); idx++) {\n            const UniValue& tv = json_tests[idx];\n            tests_set.insert(JSONPrettyPrint(tv.get_array()));\n        }\n    }\n\n    std::string strGen;\n\n    for(TestBuilder& test : tests) {\n        test.Test();\n        std::string str = JSONPrettyPrint(test.GetJSON());\n#ifndef UPDATE_JSON_TESTS\n        if (tests_set.count(str) == 0) {\n            BOOST_CHECK_MESSAGE(false, \"Missing auto script_valid test: \" + test.GetComment());\n        }\n#endif\n        strGen += str + \",\\n\";\n    }\n\n#ifdef UPDATE_JSON_TESTS\n    FILE* file = fopen(\"script_tests.json.gen\", \"w\");\n    fputs(strGen.c_str(), file);\n    fclose(file);\n#endif\n}\n\nBOOST_AUTO_TEST_CASE(script_json_test)\n{\n    // Read tests from test/data/script_tests.json\n    // Format is an array of arrays\n    // Inner arrays are [ [\"wit\"..., nValue]?, \"scriptSig\", \"scriptPubKey\", \"flags\", \"expected_scripterror\" ]\n    // ... where scriptSig and scriptPubKey are stringified\n    // scripts.\n    // If a witness is given, then the last value in the array should be the\n    // amount (nValue) to use in the crediting tx\n    UniValue tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests)));\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        CSegregatedSignatureData witness;\n        CAmount nValue = 0;\n        unsigned int pos = 0;\n        if (test.size() > 0 && test[pos].isArray()) {\n            unsigned int i=0;\n            for (i = 0; i < test[pos].size()-1; i++) {\n                witness.stack.push_back(ParseHex(test[pos][i].get_str()));\n            }\n            nValue = AmountFromValue(test[pos][i]);\n            pos++;\n        }\n        if (test.size() < 4 + pos) // Allow size > 3; extra stuff ignored (useful for comments)\n        {\n            if (test.size() != 1) {\n                BOOST_ERROR(\"Bad test: \" << strTest);\n            }\n            continue;\n        }\n        std::string scriptSigString = test[pos++].get_str();\n        CScript scriptSig = ParseScript(scriptSigString);\n        std::string scriptPubKeyString = test[pos++].get_str();\n        CScript scriptPubKey = ParseScript(scriptPubKeyString);\n        unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str());\n        int scriptError = ParseScriptError(test[pos++].get_str());\n\n        DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(script_PushData)\n{\n    // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on\n    // the stack as the 1-75 opcodes do.\n    static const unsigned char direct[] = { 1, 0x5a };\n    static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a };\n    static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };\n    static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };\n\n    ScriptError err;\n    std::vector<std::vector<unsigned char> > directStack;\n    BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    std::vector<std::vector<unsigned char> > pushdata1Stack;\n    BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err));\n    BOOST_CHECK(pushdata1Stack == directStack);\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    std::vector<std::vector<unsigned char> > pushdata2Stack;\n    BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err));\n    BOOST_CHECK(pushdata2Stack == directStack);\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    std::vector<std::vector<unsigned char> > pushdata4Stack;\n    BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err));\n    BOOST_CHECK(pushdata4Stack == directStack);\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n}\n\nstatic CScript sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)\n{\n    uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);\n\n    CScript result;\n    //\n    // NOTE: CHECKMULTISIG has an unfortunate bug; it requires\n    // one extra item on the stack, before the signatures.\n    // Putting OP_0 on the stack is the workaround;\n    // fixing the bug would mean splitting the block chain (old\n    // clients would not accept new CHECKMULTISIG transactions,\n    // and vice-versa)\n    //\n    result << OP_0;\n    for(const CKey &key : keys)\n    {\n        std::vector<unsigned char> vchSig;\n        BOOST_CHECK(key.Sign(hash, vchSig));\n        vchSig.push_back((unsigned char)SIGHASH_ALL);\n        result << vchSig;\n    }\n    return result;\n}\nCScript\nsign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)\n{\n    std::vector<CKey> keys;\n    keys.push_back(key);\n    return sign_multisig(scriptPubKey, keys, transaction);\n}\n\nBOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)\n{\n    ScriptError err;\n    CKey key1, key2, key3;\n    key1.MakeNewKey(true);\n    key2.MakeNewKey(false);\n    key3.MakeNewKey(true);\n\n    CScript scriptPubKey12;\n    scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);\n    CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CSegregatedSignatureData(), txFrom12);\n\n    CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);\n    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo12, 0, txFrom12.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n    txTo12.vout[0].nValue = 2;\n    BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo12, 0, txFrom12.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);\n    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo12, 0, txFrom12.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);\n    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo12, 0, txFrom12.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n}\n\nBOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)\n{\n    ScriptError err;\n    CKey key1, key2, key3, key4;\n    key1.MakeNewKey(true);\n    key2.MakeNewKey(false);\n    key3.MakeNewKey(true);\n    key4.MakeNewKey(false);\n\n    CScript scriptPubKey23;\n    scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;\n\n    CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23);\n    CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), CSegregatedSignatureData(), txFrom23);\n\n    std::vector<CKey> keys;\n    keys.push_back(key1); keys.push_back(key2);\n    CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key1); keys.push_back(key3);\n    CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key2); keys.push_back(key3);\n    CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key2); keys.push_back(key2); // Can't re-use sig\n    CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order\n    CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order\n    CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys\n    CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    keys.clear();\n    keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys\n    CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));\n\n    keys.clear(); // Must have signatures\n    CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);\n    BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo23, 0, txFrom23.vout[0].nValue), SCRIPT_V1, &err));\n    BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));\n}\n\nBOOST_AUTO_TEST_CASE(script_combineSigs)\n{\n    // Test the CombineSignatures function\n    CAmount amount = 0;\n    CBasicKeyStore keystore;\n    std::vector<CKey> keys;\n    std::vector<CPubKey> pubkeys;\n    for (int i = 0; i < 3; i++)\n    {\n        CKey key;\n        key.MakeNewKey(i%2 == 1);\n        keys.push_back(key);\n        pubkeys.push_back(key.GetPubKey());\n        keystore.AddKey(key);\n    }\n\n    CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));\n    CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CSegregatedSignatureData(), txFrom);\n    CScript& scriptPubKey = txFrom.vout[0].output.scriptPubKey;\n    CScript& scriptSig = txTo.vin[0].scriptSig;\n\n    SignatureData empty;\n    SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), empty, empty, SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig.empty());\n\n    // Single signature case:\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&keystore);\n    SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend); // changes scriptSig\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSig), empty, SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), empty, SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    CScript scriptSigCopy = scriptSig;\n    // Signing again will give a different, valid signature:\n    SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);\n\n    // P2SH, single-signature case:\n    CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;\n    keystore.AddCScript(pkSingle);\n    scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));\n    SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSig), empty, SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), empty, SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    scriptSigCopy = scriptSig;\n    SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);\n    // dummy scriptSigCopy with placeholder, should always choose non-placeholder:\n    scriptSigCopy = CScript() << OP_0 << std::vector<unsigned char>(pkSingle.begin(), pkSingle.end());\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n\n    // Hardest case:  Multisig 2-of-3\n    scriptPubKey = GetScriptForMultisig(2, pubkeys);\n    keystore.AddCScript(scriptPubKey);\n    SignSignature(accountsToTry, txFrom, txTo, 0, SIGHASH_ALL, SignType::Spend);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(scriptSig), empty, SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), empty, SignatureData(scriptSig), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == scriptSig);\n\n    // A couple of partially-signed versions:\n    std::vector<unsigned char> sig1;\n    uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);\n    BOOST_CHECK(keys[0].Sign(hash1, sig1));\n    sig1.push_back(SIGHASH_ALL);\n    std::vector<unsigned char> sig2;\n    uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE);\n    BOOST_CHECK(keys[1].Sign(hash2, sig2));\n    sig2.push_back(SIGHASH_NONE);\n    std::vector<unsigned char> sig3;\n    uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE);\n    BOOST_CHECK(keys[2].Sign(hash3, sig3));\n    sig3.push_back(SIGHASH_SINGLE);\n\n    // Not fussy about order (or even existence) of placeholders or signatures:\n    CScript partial1a = CScript() << OP_0 << sig1 << OP_0;\n    CScript partial1b = CScript() << OP_0 << OP_0 << sig1;\n    CScript partial2a = CScript() << OP_0 << sig2;\n    CScript partial2b = CScript() << sig2 << OP_0;\n    CScript partial3a = CScript() << sig3;\n    CScript partial3b = CScript() << OP_0 << OP_0 << sig3;\n    CScript partial3c = CScript() << OP_0 << sig3 << OP_0;\n    CScript complete12 = CScript() << OP_0 << sig1 << sig2;\n    CScript complete13 = CScript() << OP_0 << sig1 << sig3;\n    CScript complete23 = CScript() << OP_0 << sig2 << sig3;\n\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == partial1a);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete12);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete12);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete12);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete13);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete23);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == complete23);\n    combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(CKeyID(), CKeyID(), &txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), SIGVERSION_BASE);\n    BOOST_CHECK(combined.scriptSig == partial3c);\n}\n\nBOOST_AUTO_TEST_CASE(script_standard_push)\n{\n    ScriptError err;\n    for (int i=0; i<67000; i++) {\n        CScript script;\n        script << i;\n        BOOST_CHECK_MESSAGE(script.IsPushOnly(), \"Number \" << i << \" is not pure push.\");\n        BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, NULL, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err), \"Number \" << i << \" push is not minimal data.\");\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n    }\n\n    for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {\n        std::vector<unsigned char> data(i, '\\111');\n        CScript script;\n        script << data;\n        BOOST_CHECK_MESSAGE(script.IsPushOnly(), \"Length \" << i << \" is not pure push.\");\n        BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, NULL, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(CKeyID(), CKeyID()), SCRIPT_V1, &err), \"Length \" << i << \" push is not minimal data.\");\n        BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n    }\n}\n\nBOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts)\n{\n    // IsPushOnly returns false when given a script containing only pushes that\n    // are invalid due to truncation. IsPushOnly() is consensus critical\n    // because P2SH evaluation uses it, although this specific behavior should\n    // not be consensus critical as the P2SH evaluation would fail first due to\n    // the invalid push. Still, it doesn't hurt to test it explicitly.\n    static const unsigned char direct[] = { 1 };\n    BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly());\n}\n\nBOOST_AUTO_TEST_CASE(script_GetScriptAsm)\n{\n    BOOST_CHECK_EQUAL(\"OP_CHECKLOCKTIMEVERIFY\", ScriptToAsmStr(CScript() << OP_NOP2, true));\n    BOOST_CHECK_EQUAL(\"OP_CHECKLOCKTIMEVERIFY\", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));\n    BOOST_CHECK_EQUAL(\"OP_CHECKLOCKTIMEVERIFY\", ScriptToAsmStr(CScript() << OP_NOP2));\n    BOOST_CHECK_EQUAL(\"OP_CHECKLOCKTIMEVERIFY\", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));\n\n    std::string derSig(\"304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090\");\n    std::string pubKey(\"03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2\");\n    std::vector<unsigned char> vchPubKey = ToByteVector(ParseHex(pubKey));\n\n    BOOST_CHECK_EQUAL(derSig + \"00 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"00\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"80 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"80\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[ALL] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"01\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[NONE] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"02\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[SINGLE] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"03\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[ALL|ANYONECANPAY] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"81\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[NONE|ANYONECANPAY] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"82\")) << vchPubKey, true));\n    BOOST_CHECK_EQUAL(derSig + \"[SINGLE|ANYONECANPAY] \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"83\")) << vchPubKey, true));\n\n    BOOST_CHECK_EQUAL(derSig + \"00 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"00\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"80 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"80\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"01 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"01\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"02 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"02\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"03 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"03\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"81 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"81\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"82 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"82\")) << vchPubKey));\n    BOOST_CHECK_EQUAL(derSig + \"83 \" + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + \"83\")) << vchPubKey));\n}\n\nstatic CScript\nScriptFromHex(const char* hex)\n{\n    std::vector<unsigned char> data = ParseHex(hex);\n    return CScript(data.begin(), data.end());\n}\n\n\nBOOST_AUTO_TEST_CASE(script_FindAndDelete)\n{\n    // Exercise the FindAndDelete functionality\n    CScript s;\n    CScript d;\n    CScript expect;\n\n    s = CScript() << OP_1 << OP_2;\n    d = CScript(); // delete nothing should be a no-op\n    expect = s;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);\n    BOOST_CHECK(s == expect);\n\n    s = CScript() << OP_1 << OP_2 << OP_3;\n    d = CScript() << OP_2;\n    expect = CScript() << OP_1 << OP_3;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3;\n    d = CScript() << OP_3;\n    expect = CScript() << OP_1 << OP_4;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"0302ff03\"); // PUSH 0x02ff03 onto stack\n    d = ScriptFromHex(\"0302ff03\");\n    expect = CScript();\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"0302ff030302ff03\"); // PUSH 0x2ff03 PUSH 0x2ff03\n    d = ScriptFromHex(\"0302ff03\");\n    expect = CScript();\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"0302ff030302ff03\");\n    d = ScriptFromHex(\"02\");\n    expect = s; // FindAndDelete matches entire opcodes\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"0302ff030302ff03\");\n    d = ScriptFromHex(\"ff\");\n    expect = s;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);\n    BOOST_CHECK(s == expect);\n\n    // This is an odd edge case: strip of the push-three-bytes\n    // prefix, leaving 02ff03 which is push-two-bytes:\n    s = ScriptFromHex(\"0302ff030302ff03\");\n    d = ScriptFromHex(\"03\");\n    expect = CScript() << ParseHex(\"ff03\") << ParseHex(\"ff03\");\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);\n    BOOST_CHECK(s == expect);\n\n    // Byte sequence that spans multiple opcodes:\n    s = ScriptFromHex(\"02feed5169\"); // PUSH(0xfeed) OP_1 OP_VERIFY\n    d = ScriptFromHex(\"feed51\");\n    expect = s;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"02feed5169\"); // PUSH(0xfeed) OP_1 OP_VERIFY\n    d = ScriptFromHex(\"02feed51\");\n    expect = ScriptFromHex(\"69\");\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"516902feed5169\");\n    d = ScriptFromHex(\"feed51\");\n    expect = s;\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"516902feed5169\");\n    d = ScriptFromHex(\"02feed51\");\n    expect = ScriptFromHex(\"516969\");\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = CScript() << OP_0 << OP_0 << OP_1 << OP_1;\n    d = CScript() << OP_0 << OP_1;\n    expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1;\n    d = CScript() << OP_0 << OP_1;\n    expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2);\n    BOOST_CHECK(s == expect);\n\n    // Another weird edge case:\n    // End with invalid push (not enough data)...\n    s = ScriptFromHex(\"0003feed\");\n    d = ScriptFromHex(\"03feed\"); // ... can remove the invalid push\n    expect = ScriptFromHex(\"00\");\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n\n    s = ScriptFromHex(\"0003feed\");\n    d = ScriptFromHex(\"00\");\n    expect = ScriptFromHex(\"03feed\");\n    BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1);\n    BOOST_CHECK(s == expect);\n}\n\nBOOST_AUTO_TEST_CASE(script_HasValidOps)\n{\n    // Exercise the HasValidOps functionality\n    CScript script;\n    script = ScriptFromHex(\"76a9141234567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac\"); // Normal script\n    BOOST_CHECK(script.HasValidOps());\n    script = ScriptFromHex(\"76a914ff34567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac\");\n    BOOST_CHECK(script.HasValidOps());\n    script = ScriptFromHex(\"ff88ac\"); // Script with OP_INVALIDOPCODE explicit\n    BOOST_CHECK(!script.HasValidOps());\n    script = ScriptFromHex(\"88acc0\"); // Script with undefined opcode\n    BOOST_CHECK(!script.HasValidOps());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/scriptnum10.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef TEST_SCRIPTNUM10_H\n#define TEST_SCRIPTNUM10_H\n\n#include <algorithm>\n#include <limits>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <vector>\n#include \"assert.h\"\n\nclass scriptnum10_error : public std::runtime_error\n{\npublic:\n    explicit scriptnum10_error(const std::string& str) : std::runtime_error(str) {}\n};\n\nclass CScriptNum10\n{\n/**\n * The ScriptNum implementation from Bitcoin Core 0.10.0, for cross-comparison.\n */\npublic:\n\n    explicit CScriptNum10(const int64_t& n)\n    {\n        m_value = n;\n    }\n\n    static const size_t nDefaultMaxNumSize = 4;\n\n    explicit CScriptNum10(const std::vector<unsigned char>& vch, bool fRequireMinimal,\n                        const size_t nMaxNumSize = nDefaultMaxNumSize)\n    {\n        if (vch.size() > nMaxNumSize) {\n            throw scriptnum10_error(\"script number overflow\");\n        }\n        if (fRequireMinimal && vch.size() > 0) {\n            // Check that the number is encoded with the minimum possible\n            // number of bytes.\n            //\n            // If the most-significant-byte - excluding the sign bit - is zero\n            // then we're not minimal. Note how this test also rejects the\n            // negative-zero encoding, 0x80.\n            if ((vch.back() & 0x7f) == 0) {\n                // One exception: if there's more than one byte and the most\n                // significant bit of the second-most-significant-byte is set\n                // it would conflict with the sign bit. An example of this case\n                // is +-255, which encode to 0xff00 and 0xff80 respectively.\n                // (big-endian).\n                if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {\n                    throw scriptnum10_error(\"non-minimally encoded script number\");\n                }\n            }\n        }\n        m_value = set_vch(vch);\n    }\n\n    inline bool operator==(const int64_t& rhs) const    { return m_value == rhs; }\n    inline bool operator!=(const int64_t& rhs) const    { return m_value != rhs; }\n    inline bool operator<=(const int64_t& rhs) const    { return m_value <= rhs; }\n    inline bool operator< (const int64_t& rhs) const    { return m_value <  rhs; }\n    inline bool operator>=(const int64_t& rhs) const    { return m_value >= rhs; }\n    inline bool operator> (const int64_t& rhs) const    { return m_value >  rhs; }\n\n    inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); }\n    inline bool operator!=(const CScriptNum10& rhs) const { return operator!=(rhs.m_value); }\n    inline bool operator<=(const CScriptNum10& rhs) const { return operator<=(rhs.m_value); }\n    inline bool operator< (const CScriptNum10& rhs) const { return operator< (rhs.m_value); }\n    inline bool operator>=(const CScriptNum10& rhs) const { return operator>=(rhs.m_value); }\n    inline bool operator> (const CScriptNum10& rhs) const { return operator> (rhs.m_value); }\n\n    inline CScriptNum10 operator+(   const int64_t& rhs)    const { return CScriptNum10(m_value + rhs);}\n    inline CScriptNum10 operator-(   const int64_t& rhs)    const { return CScriptNum10(m_value - rhs);}\n    inline CScriptNum10 operator+(   const CScriptNum10& rhs) const { return operator+(rhs.m_value);   }\n    inline CScriptNum10 operator-(   const CScriptNum10& rhs) const { return operator-(rhs.m_value);   }\n\n    inline CScriptNum10& operator+=( const CScriptNum10& rhs)       { return operator+=(rhs.m_value);  }\n    inline CScriptNum10& operator-=( const CScriptNum10& rhs)       { return operator-=(rhs.m_value);  }\n\n    inline CScriptNum10 operator-()                         const\n    {\n        assert(m_value != std::numeric_limits<int64_t>::min());\n        return CScriptNum10(-m_value);\n    }\n\n    inline CScriptNum10& operator=( const int64_t& rhs)\n    {\n        m_value = rhs;\n        return *this;\n    }\n\n    inline CScriptNum10& operator+=( const int64_t& rhs)\n    {\n        assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||\n                           (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));\n        m_value += rhs;\n        return *this;\n    }\n\n    inline CScriptNum10& operator-=( const int64_t& rhs)\n    {\n        assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||\n                           (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));\n        m_value -= rhs;\n        return *this;\n    }\n\n    int getint() const\n    {\n        if (m_value > std::numeric_limits<int>::max())\n            return std::numeric_limits<int>::max();\n        else if (m_value < std::numeric_limits<int>::min())\n            return std::numeric_limits<int>::min();\n        return m_value;\n    }\n\n    std::vector<unsigned char> getvch() const\n    {\n        return serialize(m_value);\n    }\n\n    static std::vector<unsigned char> serialize(const int64_t& value)\n    {\n        if(value == 0)\n            return std::vector<unsigned char>();\n\n        std::vector<unsigned char> result;\n        const bool neg = value < 0;\n        uint64_t absvalue = neg ? -value : value;\n\n        while(absvalue)\n        {\n            result.push_back(absvalue & 0xff);\n            absvalue >>= 8;\n        }\n\n//    - If the most significant byte is >= 0x80 and the value is positive, push a\n//    new zero-byte to make the significant byte < 0x80 again.\n\n//    - If the most significant byte is >= 0x80 and the value is negative, push a\n//    new 0x80 byte that will be popped off when converting to an integral.\n\n//    - If the most significant byte is < 0x80 and the value is negative, add\n//    0x80 to it, since it will be subtracted and interpreted as a negative when\n//    converting to an integral.\n\n        if (result.back() & 0x80)\n            result.push_back(neg ? 0x80 : 0);\n        else if (neg)\n            result.back() |= 0x80;\n\n        return result;\n    }\n\nprivate:\n    static int64_t set_vch(const std::vector<unsigned char>& vch)\n    {\n      if (vch.empty())\n          return 0;\n\n      int64_t result = 0;\n      for (size_t i = 0; i != vch.size(); ++i)\n          result |= static_cast<int64_t>(vch[i]) << 8*i;\n\n      // If the input vector's most significant byte is 0x80, remove it from\n      // the result's msb and return a negative.\n      if (vch.back() & 0x80)\n          return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));\n\n      return result;\n    }\n\n    int64_t m_value;\n};\n\n\n#endif // TEST_BIGNUM_H\n"
  },
  {
    "path": "src/test/scriptnum_tests.cpp",
    "content": "// Copyright (c) 2012-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"scriptnum10.h\"\n#include \"script/script.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n#include <limits.h>\n#include <stdint.h>\n\nBOOST_FIXTURE_TEST_SUITE(scriptnum_tests, BasicTestingSetup)\n\n/** A selection of numbers that do not trigger int64_t overflow\n *  when added/subtracted. */\nstatic const int64_t values[] = { 0, 1, -2, 127, 128, -255, 256, (1LL << 15) - 1, -(1LL << 16), (1LL << 24) - 1, (1LL << 31), 1 - (1LL << 32), 1LL << 40 };\n\nstatic const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000};\n\nstatic bool verify(const CScriptNum10& bignum, const CScriptNum& scriptnum)\n{\n    return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint();\n}\n\nstatic void CheckCreateVch(const int64_t& num)\n{\n    CScriptNum10 bignum(num);\n    CScriptNum scriptnum(num);\n    BOOST_CHECK(verify(bignum, scriptnum));\n\n    std::vector<unsigned char> vch = bignum.getvch();\n\n    CScriptNum10 bignum2(bignum.getvch(), false);\n    vch = scriptnum.getvch();\n    CScriptNum scriptnum2(scriptnum.getvch(), false);\n    BOOST_CHECK(verify(bignum2, scriptnum2));\n\n    CScriptNum10 bignum3(scriptnum2.getvch(), false);\n    CScriptNum scriptnum3(bignum2.getvch(), false);\n    BOOST_CHECK(verify(bignum3, scriptnum3));\n}\n\nstatic void CheckCreateInt(const int64_t& num)\n{\n    CScriptNum10 bignum(num);\n    CScriptNum scriptnum(num);\n    BOOST_CHECK(verify(bignum, scriptnum));\n    BOOST_CHECK(verify(CScriptNum10(bignum.getint()), CScriptNum(scriptnum.getint())));\n    BOOST_CHECK(verify(CScriptNum10(scriptnum.getint()), CScriptNum(bignum.getint())));\n    BOOST_CHECK(verify(CScriptNum10(CScriptNum10(scriptnum.getint()).getint()), CScriptNum(CScriptNum(bignum.getint()).getint())));\n}\n\n\nstatic void CheckAdd(const int64_t& num1, const int64_t& num2)\n{\n    const CScriptNum10 bignum1(num1);\n    const CScriptNum10 bignum2(num2);\n    const CScriptNum scriptnum1(num1);\n    const CScriptNum scriptnum2(num2);\n    CScriptNum10 bignum3(num1);\n    CScriptNum10 bignum4(num1);\n    CScriptNum scriptnum3(num1);\n    CScriptNum scriptnum4(num1);\n\n    // int64_t overflow is undefined.\n    bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits<int64_t>::max() - num2))) ||\n                    ((num2 < 0) && (num1 < (std::numeric_limits<int64_t>::min() - num2))));\n    if (!invalid)\n    {\n        BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + scriptnum2));\n        BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + num2));\n        BOOST_CHECK(verify(bignum1 + bignum2, scriptnum2 + num1));\n    }\n}\n\nstatic void CheckNegate(const int64_t& num)\n{\n    const CScriptNum10 bignum(num);\n    const CScriptNum scriptnum(num);\n\n    // -INT64_MIN is undefined\n    if (num != std::numeric_limits<int64_t>::min())\n        BOOST_CHECK(verify(-bignum, -scriptnum));\n}\n\nstatic void CheckSubtract(const int64_t& num1, const int64_t& num2)\n{\n    const CScriptNum10 bignum1(num1);\n    const CScriptNum10 bignum2(num2);\n    const CScriptNum scriptnum1(num1);\n    const CScriptNum scriptnum2(num2);\n    bool invalid = false;\n\n    // int64_t overflow is undefined.\n    invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||\n               (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));\n    if (!invalid)\n    {\n        BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2));\n        BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - num2));\n    }\n\n    invalid = ((num1 > 0 && num2 < std::numeric_limits<int64_t>::min() + num1) ||\n               (num1 < 0 && num2 > std::numeric_limits<int64_t>::max() + num1));\n    if (!invalid)\n    {\n        BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - scriptnum1));\n        BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - num1));\n    }\n}\n\nstatic void CheckCompare(const int64_t& num1, const int64_t& num2)\n{\n    const CScriptNum10 bignum1(num1);\n    const CScriptNum10 bignum2(num2);\n    const CScriptNum scriptnum1(num1);\n    const CScriptNum scriptnum2(num2);\n\n    BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == scriptnum1));\n    BOOST_CHECK((bignum1 != bignum1) ==  (scriptnum1 != scriptnum1));\n    BOOST_CHECK((bignum1 < bignum1) ==  (scriptnum1 < scriptnum1));\n    BOOST_CHECK((bignum1 > bignum1) ==  (scriptnum1 > scriptnum1));\n    BOOST_CHECK((bignum1 >= bignum1) ==  (scriptnum1 >= scriptnum1));\n    BOOST_CHECK((bignum1 <= bignum1) ==  (scriptnum1 <= scriptnum1));\n\n    BOOST_CHECK((bignum1 == bignum1) == (scriptnum1 == num1));\n    BOOST_CHECK((bignum1 != bignum1) ==  (scriptnum1 != num1));\n    BOOST_CHECK((bignum1 < bignum1) ==  (scriptnum1 < num1));\n    BOOST_CHECK((bignum1 > bignum1) ==  (scriptnum1 > num1));\n    BOOST_CHECK((bignum1 >= bignum1) ==  (scriptnum1 >= num1));\n    BOOST_CHECK((bignum1 <= bignum1) ==  (scriptnum1 <= num1));\n\n    BOOST_CHECK((bignum1 == bignum2) ==  (scriptnum1 == scriptnum2));\n    BOOST_CHECK((bignum1 != bignum2) ==  (scriptnum1 != scriptnum2));\n    BOOST_CHECK((bignum1 < bignum2) ==  (scriptnum1 < scriptnum2));\n    BOOST_CHECK((bignum1 > bignum2) ==  (scriptnum1 > scriptnum2));\n    BOOST_CHECK((bignum1 >= bignum2) ==  (scriptnum1 >= scriptnum2));\n    BOOST_CHECK((bignum1 <= bignum2) ==  (scriptnum1 <= scriptnum2));\n\n    BOOST_CHECK((bignum1 == bignum2) ==  (scriptnum1 == num2));\n    BOOST_CHECK((bignum1 != bignum2) ==  (scriptnum1 != num2));\n    BOOST_CHECK((bignum1 < bignum2) ==  (scriptnum1 < num2));\n    BOOST_CHECK((bignum1 > bignum2) ==  (scriptnum1 > num2));\n    BOOST_CHECK((bignum1 >= bignum2) ==  (scriptnum1 >= num2));\n    BOOST_CHECK((bignum1 <= bignum2) ==  (scriptnum1 <= num2));\n}\n\nstatic void RunCreate(const int64_t& num)\n{\n    CheckCreateInt(num);\n    CScriptNum scriptnum(num);\n    if (scriptnum.getvch().size() <= CScriptNum::nDefaultMaxNumSize)\n        CheckCreateVch(num);\n    else\n    {\n        BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum10_error);\n    }\n}\n\nstatic void RunOperators(const int64_t& num1, const int64_t& num2)\n{\n    CheckAdd(num1, num2);\n    CheckSubtract(num1, num2);\n    CheckNegate(num1);\n    CheckCompare(num1, num2);\n}\n\nBOOST_AUTO_TEST_CASE(creation)\n{\n    for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i)\n    {\n        for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j)\n        {\n            RunCreate(values[i]);\n            RunCreate(values[i] + offsets[j]);\n            RunCreate(values[i] - offsets[j]);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(operators)\n{\n    for(size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i)\n    {\n        for(size_t j = 0; j < sizeof(offsets) / sizeof(offsets[0]); ++j)\n        {\n            RunOperators(values[i], values[i]);\n            RunOperators(values[i], -values[i]);\n            RunOperators(values[i], values[j]);\n            RunOperators(values[i], -values[j]);\n            RunOperators(values[i] + values[j], values[j]);\n            RunOperators(values[i] + values[j], -values[j]);\n            RunOperators(values[i] - values[j], values[j]);\n            RunOperators(values[i] - values[j], -values[j]);\n            RunOperators(values[i] + values[j], values[i] + values[j]);\n            RunOperators(values[i] + values[j], values[i] - values[j]);\n            RunOperators(values[i] - values[j], values[i] + values[j]);\n            RunOperators(values[i] - values[j], values[i] - values[j]);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/serialize_tests.cpp",
    "content": "// Copyright (c) 2012-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"hash.h\"\n#include \"test/test.h\"\n\n#include <stdint.h>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup)\n\nclass CSerializeMethodsTestSingle\n{\nprotected:\n    int intval;\n    bool boolval;\n    std::string stringval;\n    char charstrval[16];\n    CTransactionRef txval;\npublic:\n    CSerializeMethodsTestSingle() = default;\n    CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const uint8_t* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(MakeTransactionRef(txvalin))\n    {\n        memcpy(charstrval, charstrvalin, sizeof(charstrval));\n    }\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(intval);\n        READWRITE(boolval);\n        READWRITE(stringval);\n        READWRITE(FLATDATA(charstrval));\n        READWRITE(txval);\n    }\n\n    bool operator==(const CSerializeMethodsTestSingle& rhs)\n    {\n        return  intval == rhs.intval && \\\n                boolval == rhs.boolval && \\\n                stringval == rhs.stringval && \\\n                strcmp(charstrval, rhs.charstrval) == 0 && \\\n                *txval == *rhs.txval;\n    }\n};\n\nclass CSerializeMethodsTestMany : public CSerializeMethodsTestSingle\n{\npublic:\n    using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle;\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval);\n    }\n};\n\nBOOST_AUTO_TEST_CASE(sizes)\n{\n    BOOST_CHECK_EQUAL(sizeof(unsigned char), GetSerializeSize((unsigned char)0, 0));\n    BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(uint16_t), GetSerializeSize(uint16_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(int32_t), GetSerializeSize(int32_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(uint32_t), GetSerializeSize(uint32_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(int64_t), GetSerializeSize(int64_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(uint64_t), GetSerializeSize(uint64_t(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(float), GetSerializeSize(float(0), 0));\n    BOOST_CHECK_EQUAL(sizeof(double), GetSerializeSize(double(0), 0));\n    // Bool is serialized as uint8_t\n    BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(bool(0), 0));\n\n    // Sanity-check GetSerializeSize and c++ type matching\n    BOOST_CHECK_EQUAL(GetSerializeSize((unsigned char)0, 0), 1U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(uint16_t(0), 0), 2U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(int32_t(0), 0), 4U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(uint32_t(0), 0), 4U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(int64_t(0), 0), 8U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(uint64_t(0), 0), 8U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(float(0), 0), 4U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(double(0), 0), 8U);\n    BOOST_CHECK_EQUAL(GetSerializeSize(bool(0), 0), 1U);\n}\n\nBOOST_AUTO_TEST_CASE(floats_conversion)\n{\n    // Choose values that map unambiguously to binary floating point to avoid\n    // rounding issues at the compiler side.\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F);\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F);\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f800000), 1.0F);\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40000000), 2.0F);\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x40800000), 4.0F);\n    BOOST_CHECK_EQUAL(ser_uint32_to_float(0x44444444), 785.066650390625F);\n\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(0.0F), 0x00000000U);\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(0.5F), 0x3f000000U);\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(1.0F), 0x3f800000U);\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(2.0F), 0x40000000U);\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(4.0F), 0x40800000U);\n    BOOST_CHECK_EQUAL(ser_float_to_uint32(785.066650390625F), 0x44444444U);\n}\n\nBOOST_AUTO_TEST_CASE(doubles_conversion)\n{\n    // Choose values that map unambiguously to binary floating point to avoid\n    // rounding issues at the compiler side.\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0);\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5);\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3ff0000000000000ULL), 1.0);\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4000000000000000ULL), 2.0);\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4010000000000000ULL), 4.0);\n    BOOST_CHECK_EQUAL(ser_uint64_to_double(0x4088888880000000ULL), 785.066650390625);\n\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(0.0), 0x0000000000000000ULL);\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(0.5), 0x3fe0000000000000ULL);\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(1.0), 0x3ff0000000000000ULL);\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(2.0), 0x4000000000000000ULL);\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(4.0), 0x4010000000000000ULL);\n    BOOST_CHECK_EQUAL(ser_double_to_uint64(785.066650390625), 0x4088888880000000ULL);\n}\n/*\nPython code to generate the below hashes:\n\n    def reversed_hex(x):\n        return binascii.hexlify(''.join(reversed(x)))\n    def dsha256(x):\n        return hashlib.sha256(hashlib.sha256(x).digest()).digest()\n\n    reversed_hex(dsha256(''.join(struct.pack('<f', x) for x in range(0,1000)))) == '8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c'\n    reversed_hex(dsha256(''.join(struct.pack('<d', x) for x in range(0,1000)))) == '43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96'\n*/\nBOOST_AUTO_TEST_CASE(floats)\n{\n    CDataStream ss(SER_DISK, 0);\n    // encode\n    for (int i = 0; i < 1000; i++) {\n        ss << float(i);\n    }\n    BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S(\"8e8b4cf3e4df8b332057e3e23af42ebc663b61e0495d5e7e32d85099d7f3fe0c\"));\n\n    // decode\n    for (int i = 0; i < 1000; i++) {\n        float j;\n        ss >> j;\n        BOOST_CHECK_MESSAGE(i == j, \"decoded:\" << j << \" expected:\" << i);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(doubles)\n{\n    CDataStream ss(SER_DISK, 0);\n    // encode\n    for (int i = 0; i < 1000; i++) {\n        ss << double(i);\n    }\n    BOOST_CHECK(Hash(ss.begin(), ss.end()) == uint256S(\"43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96\"));\n\n    // decode\n    for (int i = 0; i < 1000; i++) {\n        double j;\n        ss >> j;\n        BOOST_CHECK_MESSAGE(i == j, \"decoded:\" << j << \" expected:\" << i);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(varints)\n{\n    // encode\n\n    CDataStream ss(SER_DISK, 0);\n    CDataStream::size_type size = 0;\n    for (int i = 0; i < 100000; i++) {\n        ss << VARINT(i);\n        size += ::GetSerializeSize(VARINT(i), 0, 0);\n        BOOST_CHECK(size == ss.size());\n    }\n\n    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {\n        ss << VARINT(i);\n        size += ::GetSerializeSize(VARINT(i), 0, 0);\n        BOOST_CHECK(size == ss.size());\n    }\n\n    // decode\n    for (int i = 0; i < 100000; i++) {\n        int j = -1;\n        ss >> VARINT(j);\n        BOOST_CHECK_MESSAGE(i == j, \"decoded:\" << j << \" expected:\" << i);\n    }\n\n    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {\n        uint64_t j = std::numeric_limits<uint64_t>::max();\n        ss >> VARINT(j);\n        BOOST_CHECK_MESSAGE(i == j, \"decoded:\" << j << \" expected:\" << i);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(varints_bitpatterns)\n{\n    CDataStream ss(SER_DISK, 0);\n    ss << VARINT(0); BOOST_CHECK_EQUAL(HexStr(ss), \"00\"); ss.clear();\n    ss << VARINT(0x7f); BOOST_CHECK_EQUAL(HexStr(ss), \"7f\"); ss.clear();\n    ss << VARINT((int8_t)0x7f); BOOST_CHECK_EQUAL(HexStr(ss), \"7f\"); ss.clear();\n    ss << VARINT(0x80); BOOST_CHECK_EQUAL(HexStr(ss), \"8000\"); ss.clear();\n    ss << VARINT((uint8_t)0x80); BOOST_CHECK_EQUAL(HexStr(ss), \"8000\"); ss.clear();\n    ss << VARINT(0x1234); BOOST_CHECK_EQUAL(HexStr(ss), \"a334\"); ss.clear();\n    ss << VARINT((int16_t)0x1234); BOOST_CHECK_EQUAL(HexStr(ss), \"a334\"); ss.clear();\n    ss << VARINT(0xffff); BOOST_CHECK_EQUAL(HexStr(ss), \"82fe7f\"); ss.clear();\n    ss << VARINT((uint16_t)0xffff); BOOST_CHECK_EQUAL(HexStr(ss), \"82fe7f\"); ss.clear();\n    ss << VARINT(0x123456); BOOST_CHECK_EQUAL(HexStr(ss), \"c7e756\"); ss.clear();\n    ss << VARINT((int32_t)0x123456); BOOST_CHECK_EQUAL(HexStr(ss), \"c7e756\"); ss.clear();\n    ss << VARINT(0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), \"86ffc7e756\"); ss.clear();\n    ss << VARINT((uint32_t)0x80123456U); BOOST_CHECK_EQUAL(HexStr(ss), \"86ffc7e756\"); ss.clear();\n    ss << VARINT(0xffffffff); BOOST_CHECK_EQUAL(HexStr(ss), \"8efefefe7f\"); ss.clear();\n    ss << VARINT(0x7fffffffffffffffLL); BOOST_CHECK_EQUAL(HexStr(ss), \"fefefefefefefefe7f\"); ss.clear();\n    ss << VARINT(0xffffffffffffffffULL); BOOST_CHECK_EQUAL(HexStr(ss), \"80fefefefefefefefe7f\"); ss.clear();\n}\n\nBOOST_AUTO_TEST_CASE(compactsize)\n{\n    CDataStream ss(SER_DISK, 0);\n    std::vector<char>::size_type i, j;\n\n    for (i = 1; i <= MAX_SIZE; i *= 2)\n    {\n        WriteCompactSize(ss, i-1);\n        WriteCompactSize(ss, i);\n    }\n    for (i = 1; i <= MAX_SIZE; i *= 2)\n    {\n        j = ReadCompactSize(ss);\n        BOOST_CHECK_MESSAGE((i-1) == j, \"decoded:\" << j << \" expected:\" << (i-1));\n        j = ReadCompactSize(ss);\n        BOOST_CHECK_MESSAGE(i == j, \"decoded:\" << j << \" expected:\" << i);\n    }\n}\n\nstatic bool isCanonicalException(const std::ios_base::failure& ex)\n{\n    std::ios_base::failure expectedException(\"non-canonical ReadCompactSize()\");\n\n    // The string returned by what() can be different for different platforms.\n    // Instead of directly comparing the ex.what() with an expected string,\n    // create an instance of exception to see if ex.what() matches\n    // the expected explanatory string returned by the exception instance.\n    return strcmp(expectedException.what(), ex.what()) == 0;\n}\n\n\nBOOST_AUTO_TEST_CASE(noncanonical)\n{\n    // Write some non-canonical CompactSize encodings, and\n    // make sure an exception is thrown when read back.\n    CDataStream ss(SER_DISK, 0);\n    std::vector<char>::size_type n;\n\n    // zero encoded with three bytes:\n    ss.write(MakeByteSpan(\"\\xfd\\x00\\x00\").first(3));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n\n    // 0xfc encoded with three bytes:\n    ss.write(MakeByteSpan(\"\\xfd\\xfc\\x00\").first(3));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n\n    // 0xfd encoded with three bytes is OK:\n    ss.write(MakeByteSpan(\"\\xfd\\xfd\\x00\").first(3));\n    n = ReadCompactSize(ss);\n    BOOST_CHECK(n == 0xfd);\n\n    // zero encoded with five bytes:\n    ss.write(MakeByteSpan(\"\\xfe\\x00\\x00\\x00\\x00\").first(5));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n\n    // 0xffff encoded with five bytes:\n    ss.write(MakeByteSpan(\"\\xfe\\xff\\xff\\x00\\x00\").first(5));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n\n    // zero encoded with nine bytes:\n    ss.write(MakeByteSpan(\"\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\").first(9));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n\n    // 0x01ffffff encoded with nine bytes:\n    ss.write(MakeByteSpan(\"\\xff\\xff\\xff\\xff\\x01\\x00\\x00\\x00\\x00\").first(9));\n    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);\n}\n\nBOOST_AUTO_TEST_CASE(insert_delete)\n{\n    // Test inserting/deleting bytes.\n    CDataStream ss(SER_DISK, 0);\n    BOOST_CHECK_EQUAL(ss.size(), 0U);\n\n    ss.write(\"\\x00\\x01\\x02\\xff\", 4);\n    BOOST_CHECK_EQUAL(ss.size(), 4U);\n\n    std::byte c = (std::byte)11;\n\n    // Inserting at beginning/end/middle:\n    ss.insert(ss.begin(), c);\n    BOOST_CHECK_EQUAL(ss.size(), 5U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[0], (uint8_t)c);\n    BOOST_CHECK_EQUAL((uint8_t)ss[1],(uint8_t)0);\n\n    ss.insert(ss.end(), c);\n    BOOST_CHECK_EQUAL(ss.size(), 6U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[4], (uint8_t)0xff);\n    BOOST_CHECK_EQUAL((uint8_t)ss[5], (uint8_t)c);\n\n    ss.insert(ss.begin()+2, c);\n    BOOST_CHECK_EQUAL((uint8_t)ss.size(), (uint8_t)7U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[2], (uint8_t)c);\n\n    // Delete at beginning/end/middle\n    ss.erase(ss.begin());\n    BOOST_CHECK_EQUAL((uint8_t)ss.size(), (uint8_t)6U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[0], (uint8_t)0);\n\n    ss.erase(ss.begin()+ss.size()-1);\n    BOOST_CHECK_EQUAL((uint8_t)ss.size(), (uint8_t)5U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[4], (uint8_t)0xff);\n\n    ss.erase(ss.begin()+1);\n    BOOST_CHECK_EQUAL((uint8_t)ss.size(), (uint8_t)4U);\n    BOOST_CHECK_EQUAL((uint8_t)ss[0], (uint8_t)0);\n    BOOST_CHECK_EQUAL((uint8_t)ss[1], (uint8_t)1);\n    BOOST_CHECK_EQUAL((uint8_t)ss[2], (uint8_t)2);\n    BOOST_CHECK_EQUAL((uint8_t)ss[3], (uint8_t)0xff);\n\n    // Make sure GetAndClear does the right thing:\n    CSerializeData d;\n    ss.GetAndClear(d);\n    BOOST_CHECK_EQUAL((uint8_t)ss.size(), (uint8_t)0U);\n}\n\nBOOST_AUTO_TEST_CASE(class_methods)\n{\n    int intval(100);\n    bool boolval(true);\n    std::string stringval(\"testing\");\n    const uint8_t charstrval[16]{\"testing charstr\"};\n    CMutableTransaction txval(TEST_DEFAULT_TX_VERSION);\n    CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);\n    CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);\n    CSerializeMethodsTestSingle methodtest3;\n    CSerializeMethodsTestMany methodtest4;\n    CDataStream ss(SER_DISK, PROTOCOL_VERSION);\n    BOOST_CHECK(methodtest1 == methodtest2);\n    ss << methodtest1;\n    ss >> methodtest4;\n    ss << methodtest2;\n    ss >> methodtest3;\n    BOOST_CHECK(methodtest1 == methodtest2);\n    BOOST_CHECK(methodtest2 == methodtest3);\n    BOOST_CHECK(methodtest3 == methodtest4);\n\n    CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval);\n    ss2 >> methodtest3;\n    BOOST_CHECK(methodtest3 == methodtest4);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/sighash_tests.cpp",
    "content": "// Copyright (c) 2013-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"data/sighash.json.h\"\n#include \"hash.h\"\n#include \"script/interpreter.h\"\n#include \"script/script.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"test/test.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"version.h\"\n\n#include <iostream>\n\n#include <boost/test/unit_test.hpp>\n\n#include <univalue.h>\n\nextern UniValue read_json(const std::string& jsondata);\n\n#if defined(PRINT_SIGHASH_JSON)\nvoid static RandomScript(CScript &script) {\n    static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};\n    script = CScript();\n    int ops = (InsecureRandRange(10));\n    for (int i=0; i<ops; i++)\n        script << oplist[InsecureRandRange(sizeof(oplist)/sizeof(oplist[0]))];\n}\n\nvoid static RandomTransaction(CMutableTransaction &tx, bool fSingle) {\n    tx.nVersion = InsecureRand32();\n    tx.vin.clear();\n    tx.vout.clear();\n    tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0;\n    int ins = (InsecureRandBits(2)) + 1;\n    int outs = fSingle ? ins : (InsecureRandBits(2)) + 1;\n    for (int in = 0; in < ins; in++) {\n        tx.vin.push_back(CTxIn());\n        CTxIn &txin = tx.vin.back();\n        txin.prevout.setHash(InsecureRand256());\n        txin.prevout.n = InsecureRandBits(2);\n        RandomScript(txin.scriptSig);\n        txin.SetSequence((InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1, tx.nVersion, CTxInFlags::None);\n    }\n    for (int out = 0; out < outs; out++) {\n        tx.vout.push_back(CTxOut());\n        CTxOut &txout = tx.vout.back();\n        txout.nValue = InsecureRandRange(100000000);\n        RandomScript(txout.output.scriptPubKey);\n    }\n}\n#endif\n\nBOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup)\n\n// use this test to generate the test data\n// with PRINT_SIGHASH_JSON defined capture the output into sighash.json\n// #define PRINT_SIGHASH_JSON 1\nBOOST_AUTO_TEST_CASE(sighash_test)\n{\n#if defined(PRINT_SIGHASH_JSON)\n    SeedInsecureRand(false);\n\n    std::cout << \"[\\n\";\n    std::cout << \"\\t[\\\"raw_transaction, script, input_index, hashType, signature_hash (result)\\\"],\\n\";\n\n    int nRandomTests = 500;\n\n    for (int i=0; i<nRandomTests; i++) {\n        int nHashType = InsecureRand32();\n        CMutableTransaction txTo(TEST_DEFAULT_TX_VERSION);\n        RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);\n        CScript scriptCode;\n        RandomScript(scriptCode);\n        int nIn = InsecureRandRange(txTo.vin.size());\n\n        uint256 sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SIGVERSION_BASE);\n        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);\n        ss << txTo;\n\n        std::cout << \"\\t[\\\"\" ;\n        std::cout << HexStr(ss.begin(), ss.end()) << \"\\\", \\\"\";\n        std::cout << HexStr(scriptCode) << \"\\\", \";\n        std::cout << nIn << \", \";\n        std::cout << nHashType << \", \\\"\";\n        std::cout << sh.GetHex() << \"\\\"]\";\n        if (i+1 != nRandomTests) {\n          std::cout << \",\";\n        }\n        std::cout << \"\\n\";\n    }\n    std::cout << \"]\\n\";\n#endif\n}\n\n// Goal: check that SignatureHash generates correct hash\nBOOST_AUTO_TEST_CASE(sighash_from_data)\n{\n    UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));\n\n    for (unsigned int idx = 0; idx < tests.size(); idx++)\n    {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test.size() < 1) // Allow for extra stuff (useful for comments)\n        {\n            BOOST_ERROR(\"Bad test: \" << strTest);\n            continue;\n        }\n        if (test.size() == 1) continue; // comment\n\n        std::string raw_tx, raw_script, sigHashHex;\n        int nIn, nHashType;\n        uint256 sh;\n        CTransactionRef tx;\n        CScript scriptCode = CScript();\n\n        try\n        {\n          // deserialize test data\n          raw_tx = test[0].get_str();\n          raw_script = test[1].get_str();\n          nIn = test[2].get_int();\n          nHashType = test[3].get_int();\n          sigHashHex = test[4].get_str();\n\n          CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);\n          stream >> tx;\n\n          CValidationState state;\n          BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);\n          BOOST_CHECK(state.IsValid());\n\n          std::vector<unsigned char> raw = ParseHex(raw_script);\n          scriptCode.insert(scriptCode.end(), raw.begin(), raw.end());\n        }\n        catch (...)\n        {\n          BOOST_ERROR(\"Bad test, couldn't deserialize data: \" << strTest);\n          continue;\n        }\n\n        sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SIGVERSION_BASE);\n        BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);\n    }\n}\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/sigopcount_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/tx_verify.h\"\n#include \"pubkey.h\"\n#include \"key.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"uint256.h\"\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\n// Helpers:\nstatic std::vector<unsigned char>\nSerialize(const CScript& s)\n{\n    std::vector<unsigned char> sSerialized(s.begin(), s.end());\n    return sSerialized;\n}\n\nBOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(GetSigOpCount)\n{\n    // Test CScript::GetSigOpCount()\n    CScript s1;\n    BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U);\n    BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U);\n\n    uint160 dummy;\n    s1 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << OP_2 << OP_CHECKMULTISIG;\n    BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U);\n    s1 << OP_IF << OP_CHECKSIG << OP_ENDIF;\n    BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U);\n    BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U);\n\n    CScript p2sh = GetScriptForDestination(CScriptID(s1));\n    CScript scriptSig;\n    scriptSig << OP_0 << Serialize(s1);\n    BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);\n\n    std::vector<CPubKey> keys;\n    for (int i = 0; i < 3; i++)\n    {\n        CKey k;\n        k.MakeNewKey(true);\n        keys.push_back(k.GetPubKey());\n    }\n    CScript s2 = GetScriptForMultisig(1, keys);\n    BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U);\n    BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U);\n\n    p2sh = GetScriptForDestination(CScriptID(s2));\n    BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U);\n    BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U);\n    CScript scriptSig2;\n    scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s2);\n    BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U);\n}\n\n/**\n * Verifies script execution of the zeroth scriptPubKey of tx output and\n * zeroth scriptSig and witness of tx input.\n */\nstatic ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags)\n{\n    ScriptError error;\n    CTransaction inputi(input);\n    ScriptVersion scriptversion = (inputi.vin[0].segregatedSignatureData.IsNull()) ? SCRIPT_V1 : SCRIPT_V2;\n    bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].output.scriptPubKey, &inputi.vin[0].segregatedSignatureData, flags, TransactionSignatureChecker(CKeyID(), CKeyID(), &inputi, 0, output.vout[0].nValue), scriptversion, &error);\n    BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK));\n\n    return error;\n}\n\n/**\n * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig\n * and segregatedSignatureData such that spendingTx spends output zero of creationTx.\n * Also inserts creationTx's output into the coins view.\n */\nstatic void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CSegregatedSignatureData& segregatedSignatureData)\n{\n    creationTx.nVersion = 1;\n    creationTx.vin.resize(1);\n    creationTx.vin[0].SetPrevOutNull();\n    creationTx.vin[0].scriptSig = CScript();\n    creationTx.vout.resize(1);\n    creationTx.vout[0].nValue = 1;\n    creationTx.vout[0].output.scriptPubKey = scriptPubKey;\n\n    spendingTx.nVersion = 1;\n    spendingTx.vin.resize(1);\n    COutPoint changePrevOut = spendingTx.vin[0].GetPrevOut();\n    changePrevOut.setHash(creationTx.GetHash());\n    changePrevOut.n = 0;\n    spendingTx.vin[0].SetPrevOut(changePrevOut);\n    spendingTx.vin[0].scriptSig = scriptSig;\n    spendingTx.vin[0].segregatedSignatureData = segregatedSignatureData;\n    spendingTx.vout.resize(1);\n    spendingTx.vout[0].nValue = 1;\n    spendingTx.vout[0].output.scriptPubKey = CScript();\n\n    AddCoins(coins, creationTx, 0, 0);\n}\n\nBOOST_AUTO_TEST_CASE(GetTxSigOpCost)\n{\n    // Transaction creates outputs\n    CMutableTransaction creationTx(TEST_DEFAULT_TX_VERSION);\n    // Transaction that spends outputs and whose\n    // sig op cost is going to be tested\n    CMutableTransaction spendingTx(TEST_DEFAULT_TX_VERSION);\n\n    // Create utxo set\n    CCoinsView coinsDummy;\n    CCoinsViewCache coins(&coinsDummy);\n    // Create key\n    CKey key;\n    key.MakeNewKey(true);\n    CPubKey pubkey = key.GetPubKey();\n    // Default flags\n    int flags = SCRIPT_VERIFY_P2SH;\n\n    // Multisig script (legacy counting)\n    {\n        CScript scriptPubKey = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;\n        // Do not use a valid signature to avoid using wallet operations.\n        CScript scriptSig = CScript() << OP_0 << OP_0;\n\n        BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CSegregatedSignatureData());\n        // Legacy counting only includes signature operations in scriptSigs and scriptPubKeys\n        // of a transaction and does not take the actual executed sig operations into account.\n        // spendingTx in itself does not contain a signature operation.\n        BOOST_CHECK(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 0);\n        // creationTx contains two signature operations in its scriptPubKey, but legacy counting\n        // is not accurate.\n        BOOST_CHECK(GetTransactionSigOpCost(CTransaction(creationTx), coins, flags) == MAX_PUBKEYS_PER_MULTISIG);\n        // Sanity check: script verification fails because of an invalid signature.\n        BOOST_CHECK(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);\n    }\n\n    // Multisig nested in P2SH\n    {\n        CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;\n        CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));\n        CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript);\n\n        #ifndef DEBUG_COINSCACHE_VALIDATE_INSERTS\n        BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CSegregatedSignatureData());\n        BOOST_CHECK(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2 );\n        BOOST_CHECK(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);\n        #endif\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/skiplist_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n#include \"util.h\"\n#include \"test/test.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\n#define SKIPLIST_LENGTH 300000\n\nBOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(skiplist_test)\n{\n    std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH);\n\n    for (int i=0; i<SKIPLIST_LENGTH; i++) {\n        vIndex[i].nHeight = i;\n        vIndex[i].pprev = (i == 0) ? NULL : &vIndex[i - 1];\n        vIndex[i].BuildSkip();\n    }\n\n    for (int i=0; i<SKIPLIST_LENGTH; i++) {\n        if (i > 0) {\n            BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]);\n            BOOST_CHECK(vIndex[i].pskip->nHeight < i);\n        } else {\n            BOOST_CHECK(vIndex[i].pskip == NULL);\n        }\n    }\n\n    for (int i=0; i < 1000; i++) {\n        int from = InsecureRandRange(SKIPLIST_LENGTH - 1);\n        int to = InsecureRandRange(from + 1);\n\n        BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);\n        BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);\n        BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(getlocator_test)\n{\n    // Build a main chain 100000 blocks long.\n    std::vector<uint256> vHashMain(100000);\n    std::vector<CBlockIndex> vBlocksMain(100000);\n    for (unsigned int i=0; i<vBlocksMain.size(); i++) {\n        vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances.\n        vBlocksMain[i].nHeight = i;\n        vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;\n        vBlocksMain[i].phashBlock = &vHashMain[i];\n        vBlocksMain[i].BuildSkip();\n        BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHashLegacy()).GetLow64(), vBlocksMain[i].nHeight);\n        BOOST_CHECK(vBlocksMain[i].pprev == NULL || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);\n    }\n\n    // Build a branch that splits off at block 49999, 50000 blocks long.\n    std::vector<uint256> vHashSide(50000);\n    std::vector<CBlockIndex> vBlocksSide(50000);\n    for (unsigned int i=0; i<vBlocksSide.size(); i++) {\n        vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.\n        vBlocksSide[i].nHeight = i + 50000;\n        vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999];\n        vBlocksSide[i].phashBlock = &vHashSide[i];\n        vBlocksSide[i].BuildSkip();\n        BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHashLegacy()).GetLow64(), vBlocksSide[i].nHeight);\n        BOOST_CHECK(vBlocksSide[i].pprev == NULL || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);\n    }\n\n    // Build a CChain for the main branch.\n    CChain chain;\n    chain.SetTip(&vBlocksMain.back());\n\n    // Test 100 random starting points for locators.\n    for (int n=0; n<100; n++) {\n        int r = InsecureRandRange(150000);\n        CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];\n        CBlockLocator locator = chain.GetLocatorLegacy(tip);\n\n        // The first result must be the block itself, the last one must be genesis.\n        BOOST_CHECK(locator.vHave.front() == tip->GetBlockHashLegacy());\n        BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHashLegacy());\n\n        // Entries 1 through 11 (inclusive) go back one step each.\n        for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) {\n            BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i]).GetLow64(), tip->nHeight - i);\n        }\n\n        // The further ones (excluding the last one) go back with exponential steps.\n        unsigned int dist = 2;\n        for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) {\n            BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i - 1]).GetLow64() - UintToArith256(locator.vHave[i]).GetLow64(), dist);\n            dist *= 2;\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(findearliestatleast_test)\n{\n    std::vector<uint256> vHashMain(100000);\n    std::vector<CBlockIndex> vBlocksMain(100000);\n    for (unsigned int i=0; i<vBlocksMain.size(); i++) {\n        vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height\n        vBlocksMain[i].nHeight = i;\n        vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;\n        vBlocksMain[i].phashBlock = &vHashMain[i];\n        vBlocksMain[i].BuildSkip();\n        if (i < 10) {\n            vBlocksMain[i].nTime = i;\n            vBlocksMain[i].nTimeMax = i;\n        } else {\n            // randomly choose something in the range [MTP, MTP*2]\n            int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();\n            int r = InsecureRandRange(medianTimePast);\n            vBlocksMain[i].nTime = r + medianTimePast;\n            vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);\n        }\n    }\n    // Check that we set nTimeMax up correctly.\n    unsigned int curTimeMax = 0;\n    for (unsigned int i=0; i<vBlocksMain.size(); ++i) {\n        curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime);\n        BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax);\n    }\n\n    // Build a CChain for the main branch.\n    CChain chain;\n    chain.SetTip(&vBlocksMain.back());\n\n    // Verify that FindEarliestAtLeast is correct.\n    for (unsigned int i=0; i<10000; ++i) {\n        // Pick a random element in vBlocksMain.\n        int r = InsecureRandRange(vBlocksMain.size());\n        int64_t test_time = vBlocksMain[r].nTime;\n        CBlockIndex *ret = chain.FindEarliestAtLeast(test_time);\n        BOOST_CHECK(ret->nTimeMax >= test_time);\n        BOOST_CHECK((ret->pprev==NULL) || ret->pprev->nTimeMax < test_time);\n        BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)\n{\n    std::list<CBlockIndex> blocks;\n    for (unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) {\n        CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back();\n        blocks.emplace_back();\n        blocks.back().nHeight = prev ? prev->nHeight + 1 : 0;\n        blocks.back().pprev = prev;\n        blocks.back().BuildSkip();\n        blocks.back().nTimeMax = timeMax;\n    }\n\n    CChain chain;\n    chain.SetTip(&blocks.back());\n\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50)->nHeight, 0);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100)->nHeight, 0);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(150)->nHeight, 3);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(200)->nHeight, 3);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(250)->nHeight, 6);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(300)->nHeight, 6);\n    BOOST_CHECK(!chain.FindEarliestAtLeast(350));\n\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0)->nHeight, 0);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1)->nHeight, 0);\n\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min())->nHeight, 0);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::min())->nHeight, 0);\n    BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1)->nHeight, 0);\n    BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max()));\n    BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max()));\n    BOOST_CHECK(!chain.FindEarliestAtLeast(int64_t(std::numeric_limits<unsigned int>::max()) + 1));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/streams_tests.cpp",
    "content": "// Copyright (c) 2012-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"streams.h\"\n#include \"support/allocators/zeroafterfree.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nusing namespace std::string_literals;\n\nBOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(streams_vector_writer)\n{\n    unsigned char a(1);\n    unsigned char b(2);\n    unsigned char bytes[] = { 3, 4, 5, 6 };\n    std::vector<unsigned char> vch;\n\n    // Each test runs twice. Serializing a second time at the same starting\n    // point should yield the same results, even if the first test grew the\n    // vector.\n\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));\n    vch.clear();\n\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));\n    vch.clear();\n\n    vch.resize(5, 0);\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));\n    vch.clear();\n\n    vch.resize(4, 0);\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 3, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));\n    vch.clear();\n\n    vch.resize(4, 0);\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 4, a, b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));\n    vch.clear();\n\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));\n    BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 0, FLATDATA(bytes));\n    BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));\n    vch.clear();\n\n    vch.resize(4, 8);\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));\n    CVectorWriter(SER_NETWORK, INIT_PROTO_VERSION, vch, 2, a, FLATDATA(bytes), b);\n    BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));\n    vch.clear();\n}\n\nBOOST_AUTO_TEST_CASE(streams_serializedata_xor)\n{\n    std::vector<std::byte> in;\n\n    // Degenerate case\n    {\n        CDataStream ds{in, 0, 0};\n        ds.Xor({0x00, 0x00});\n        BOOST_CHECK_EQUAL(\"\"s, ds.str());\n    }\n\n    in.push_back(std::byte{0x0f});\n    in.push_back(std::byte{0xf0});\n\n    // Single character key\n    {\n        CDataStream ds{in, 0, 0};\n        ds.Xor({0xff});\n        BOOST_CHECK_EQUAL(\"\\xf0\\x0f\"s, ds.str());\n    }\n\n    // Multi character key\n\n    in.clear();\n    in.push_back(std::byte{0xf0});\n    in.push_back(std::byte{0x0f});\n\n    {\n        CDataStream ds{in, 0, 0};\n        ds.Xor({0xff, 0x0f});\n        BOOST_CHECK_EQUAL(\"\\x0f\\x00\"s, ds.str());\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/test.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"test.h\"\n\n#include \"chainparams.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/validation.h\"\n#include \"fs.h\"\n#include \"key.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"generation/miner.h\"\n#include \"net_processing.h\"\n#include \"pubkey.h\"\n#include \"random.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"ui_interface.h\"\n#include \"rpc/server.h\"\n#include \"rpc/register.h\"\n#include \"script/sigcache.h\"\n#include \"scheduler.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/wallet.h>\n#endif\n\n#include \"test/testutil.h\"\n\n#include <memory>\n#include <util/thread.h>\n\nuint256 insecure_rand_seed = GetRandHash();\nFastRandomContext insecure_rand_ctx(insecure_rand_seed);\n\nextern bool fPrintToConsole;\nextern void noui_connect();\n\nBasicTestingSetup::BasicTestingSetup(const std::string& chainName)\n{\n        ECC_Start();\n        SetupEnvironment();\n        SetupNetworking();\n        InitSignatureCache();\n        fPrintToDebugLog = false; // don't want to write to debug.log file\n        fCheckBlockIndex = true;\n        SelectParams(chainName);\n        noui_connect();\n}\n\nBasicTestingSetup::~BasicTestingSetup()\n{\n        ECC_Stop();\n        if (g_connman)\n        {\n            g_connman->Interrupt();\n            g_connman->Stop();\n        }\n        g_connman.reset();\n}\n\nTestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)\n{\n    const CChainParams& chainparams = Params();\n        // Ideally we'd move all the RPC tests to the functional testing framework\n        // instead of unit tests, but for now we need these here.\n\n        RegisterAllCoreRPCCommands(tableRPC);\n        ClearDatadirCache();\n        pathTemp = GetTempPath() / strprintf(\"test_munt_%lu_%i\", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));\n        fs::create_directories(pathTemp);\n        ForceSetArg(\"-datadir\", pathTemp.string());\n        mempool.setSanityCheck(1.0);\n        pblocktree = new CBlockTreeDB(1 << 20, true);\n        pcoinsdbview = new CCoinsViewDB(1 << 23, true);\n        pcoinsTip = new CCoinsViewCache(pcoinsdbview);\n\n        ppow2witdbview = new CWitViewDB(1 << 20);\n        ppow2witTip = std::shared_ptr<CCoinsViewCache>(new CCoinsViewCache(ppow2witdbview));\n        \n        nodeScheduler = new CScheduler();\n        nodeScheduler->m_service_thread = std::thread(&util::TraceThread, \"scheduler\", std::function<void()>([&] { nodeScheduler->serviceQueue(); }));\n        GetMainSignals().RegisterBackgroundSignalScheduler(*nodeScheduler);\n\n        if (!InitBlockIndex(chainparams)) {\n            throw std::runtime_error(\"InitBlockIndex failed.\");\n        }\n        {\n            CValidationState state;\n            if (!ActivateBestChain(state, chainparams)) {\n                throw std::runtime_error(\"ActivateBestChain failed.\");\n            }\n        }\n        nScriptCheckThreads = 3;\n        StartScriptCheckWorkerThreads(nScriptCheckThreads);\n        \n        g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.\n        connman = g_connman.get();\n        RegisterNodeSignals(GetNodeSignals());\n}\n\nTestingSetup::~TestingSetup()\n{\n        UnregisterNodeSignals(GetNodeSignals());\n        threadGroup.interrupt_all();\n        threadGroup.join_all();\n        UnloadBlockIndex();\n\n        StopScriptCheckWorkerThreads();\n\n        GetMainSignals().UnregisterBackgroundSignalScheduler();\n        nodeScheduler->stop();\n        delete nodeScheduler;\n        \n        ppow2witTip = nullptr;\n        delete ppow2witdbview;\n\n        delete pcoinsTip;\n        delete pcoinsdbview;\n        delete pblocktree;\n        fs::remove_all(pathTemp);\n}\n\nTestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTESTLEGACY)\n{\n    // Generate a 100-block chain:\n    coinbaseKey.MakeNewKey(true);\n    CScript scriptPubKey = CScript() <<  ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;\n    std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n    for (int i = 0; i < COINBASE_MATURITY; i++)\n    {\n        std::vector<CMutableTransaction> noTxns;\n        CBlock b = CreateAndProcessBlock(noTxns, reservedScript);\n        coinbaseTxns.push_back(*b.vtx[0]);\n    }\n}\n\n//\n// Create a new block with just given transactions, coinbase paying to\n// scriptPubKey, and try to add it to the current chain.\n//\nCBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, std::shared_ptr<CReserveKeyOrScript> reserveScript)\n{\n    const CChainParams& chainparams = Params();\n    std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(chainActive.Tip(), reserveScript);\n    CBlock& block = pblocktemplate->block;\n\n    // Replace mempool-selected txns with just coinbase plus passed-in txns:\n    block.vtx.resize(1);\n    for (const CMutableTransaction& tx : txns)\n        block.vtx.push_back(MakeTransactionRef(tx));\n    // IncrementExtraNonce creates a valid coinbase and merkleRoot\n    {\n        LOCK(cs_main);\n        unsigned int extraNonce = 0;\n        IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);\n    }\n\n    while (!CheckProofOfWork(&block, chainparams.GetConsensus())) ++block.nNonce;\n\n    std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);\n    ProcessNewBlock(chainparams, shared_pblock, true, nullptr, false, true);\n\n    CBlock result = block;\n    return result;\n}\n\nTestChain100Setup::~TestChain100Setup()\n{\n}\n\n\nCTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {\n    CTransaction txn(tx);\n    return FromTx(txn);\n}\n\nCTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {\n    return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,\n                           spendsCoinbase?0:1, sigOpCost, lp);\n}\n"
  },
  {
    "path": "src/test/test.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef TEST_TEST_H\n#define TEST_TEST_H\n\n#include \"chainparamsbase.h\"\n#include \"fs.h\"\n#include \"key.h\"\n#include \"pubkey.h\"\n#include \"random.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"generation/generation.h\"\n\n#include <boost/thread.hpp>\n\n#ifdef BYPASS_TEST_REWRITES\n#define TEST_REWRITE\n#else\n#define TEST_REWRITE BOOST_TEST(false, \"test needs rewrite\")\n#endif\n\n#define TEST_DEFAULT_TX_VERSION CTransaction::CURRENT_VERSION\nextern uint256 insecure_rand_seed;\nextern FastRandomContext insecure_rand_ctx;\n\nclass CScheduler;\n\nstatic inline void SeedInsecureRand(bool fDeterministic = false)\n{\n    if (fDeterministic) {\n        insecure_rand_seed = uint256();\n    } else {\n        insecure_rand_seed = GetRandHash();\n    }\n    insecure_rand_ctx = FastRandomContext(insecure_rand_seed);\n}\n\nstatic inline uint32_t InsecureRand32() { return insecure_rand_ctx.rand32(); }\nstatic inline uint256 InsecureRand256() { return insecure_rand_ctx.rand256(); }\nstatic inline uint64_t InsecureRandBits(int bits) { return insecure_rand_ctx.randbits(bits); }\nstatic inline uint64_t InsecureRandRange(uint64_t range) { return insecure_rand_ctx.randrange(range); }\nstatic inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); }\nstatic inline std::vector<unsigned char> InsecureRandBytes(size_t len) { return insecure_rand_ctx.randbytes(len); }\n\n/** Basic testing setup.\n * This just configures logging and chain parameters.\n */\nstruct BasicTestingSetup {\n    ECCVerifyHandle globalVerifyHandle;\n\n    BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);\n    ~BasicTestingSetup();\n};\n\n/** Testing setup that configures a complete environment.\n * Included are data directory, coins database, script check threads setup.\n */\nclass CConnman;\nstruct TestingSetup: public BasicTestingSetup {\n    CCoinsViewDB *pcoinsdbview;\n    fs::path pathTemp;\n    boost::thread_group threadGroup;\n    CConnman* connman;\n    \n    CScheduler* nodeScheduler=nullptr;\n\n    TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);\n    ~TestingSetup();\n};\n\nclass CBlock;\nstruct CMutableTransaction;\nclass CScript;\n\n//\n// Testing fixture that pre-creates a\n// 100-block REGTEST-mode block chain\n//\nstruct TestChain100Setup : public TestingSetup {\n    TestChain100Setup();\n\n    // Create a new block with just given transactions, coinbase paying to\n    // scriptPubKey, and try to add it to the current chain.\n    CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, std::shared_ptr<CReserveKeyOrScript> reserveScript);\n\n    ~TestChain100Setup();\n\n    std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions\n    CKey coinbaseKey; // private/public key needed to spend coinbase transactions\n};\n\nclass CTxMemPoolEntry;\n\nstruct TestMemPoolEntryHelper\n{\n    // Default values\n    CAmount nFee;\n    int64_t nTime;\n    unsigned int nHeight;\n    bool spendsCoinbase;\n    unsigned int sigOpCost;\n    LockPoints lp;\n\n    TestMemPoolEntryHelper() :\n        nFee(0), nTime(0), nHeight(1),\n        spendsCoinbase(false), sigOpCost(4) { }\n\n    CTxMemPoolEntry FromTx(const CMutableTransaction &tx);\n    CTxMemPoolEntry FromTx(const CTransaction &tx);\n\n    // Change the default value\n    TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }\n    TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }\n    TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }\n    TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }\n    TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }\n};\n#endif\n"
  },
  {
    "path": "src/test/test_fuzzy.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"consensus/merkle.h\"\n#include \"primitives/block.h\"\n#include \"script/script.h\"\n#include \"addrman.h\"\n#include \"chain.h\"\n#include \"coins.h\"\n#include \"compressor.h\"\n#include \"net.h\"\n#include \"protocol.h\"\n#include \"streams.h\"\n#include \"undo.h\"\n#include \"version.h\"\n#include \"pubkey.h\"\n\n#include <stdint.h>\n#include <unistd.h>\n\n#include <algorithm>\n#include <vector>\n\nenum TEST_ID {\n    CBLOCK_DESERIALIZE=0,\n    CTRANSACTION_DESERIALIZE,\n    CBLOCKLOCATOR_DESERIALIZE,\n    CBLOCKMERKLEROOT,\n    CADDRMAN_DESERIALIZE,\n    CBLOCKHEADER_DESERIALIZE,\n    CBANENTRY_DESERIALIZE,\n    CTXUNDO_DESERIALIZE,\n    CBLOCKUNDO_DESERIALIZE,\n    CCOINS_DESERIALIZE,\n    CNETADDR_DESERIALIZE,\n    CSERVICE_DESERIALIZE,\n    CMESSAGEHEADER_DESERIALIZE,\n    CADDRESS_DESERIALIZE,\n    CINV_DESERIALIZE,\n    CBLOOMFILTER_DESERIALIZE,\n    CDISKBLOCKINDEX_DESERIALIZE,\n    CTXOUTCOMPRESSOR_DESERIALIZE,\n    TEST_ID_END\n};\n\nstatic bool read_stdin(std::vector<uint8_t>& data)\n{\n    uint8_t buffer[1024];\n    ssize_t length = 0;\n    while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {\n        data.insert(data.end(), buffer, buffer + length);\n    }\n    return length == 0;\n}\n\nint do_fuzz()\n{\n    std::vector<uint8_t> buffer;\n    if (!read_stdin(buffer)) return 0;\n\n    if (buffer.size() < sizeof(uint32_t)) return 0;\n\n    uint32_t test_id = 0xffffffff;\n    memcpy(&test_id, &buffer[0], sizeof(uint32_t));\n    buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));\n\n    if (test_id >= TEST_ID_END) return 0;\n\n    CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);\n    try {\n        int nVersion;\n        ds >> nVersion;\n        ds.SetVersion(nVersion);\n    } catch (const std::ios_base::failure& e) {\n        return 0;\n    }\n\n    switch(test_id) {\n        case CBLOCK_DESERIALIZE:\n        {\n            try\n            {\n                CBlock block;\n                ds >> block;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CTRANSACTION_DESERIALIZE:\n        {\n            try\n            {\n                CTransaction tx(deserialize, ds);\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBLOCKLOCATOR_DESERIALIZE:\n        {\n            try\n            {\n                CBlockLocator bl;\n                ds >> bl;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBLOCKMERKLEROOT:\n        {\n            try\n            {\n                CBlock block;\n                ds >> block;\n                bool mutated;\n                BlockMerkleRoot(block, &mutated);\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CADDRMAN_DESERIALIZE:\n        {\n            try\n            {\n                CAddrMan am;\n                ds >> am;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBLOCKHEADER_DESERIALIZE:\n        {\n            try\n            {\n                CBlockHeader bh;\n                ds >> bh;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBANENTRY_DESERIALIZE:\n        {\n            try\n            {\n                CBanEntry be;\n                ds >> be;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CTXUNDO_DESERIALIZE:\n        {\n            try\n            {\n                CTxUndo tu;\n                ds >> tu;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBLOCKUNDO_DESERIALIZE:\n        {\n            try\n            {\n                CBlockUndo bu;\n                ds >> bu;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CCOINS_DESERIALIZE:\n        {\n            try\n            {\n                Coin coin;\n                ds >> coin;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CNETADDR_DESERIALIZE:\n        {\n            try\n            {\n                CNetAddr na;\n                ds >> na;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CSERVICE_DESERIALIZE:\n        {\n            try\n            {\n                CService s;\n                ds >> s;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CMESSAGEHEADER_DESERIALIZE:\n        {\n            CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};\n            try\n            {\n                CMessageHeader mh(pchMessageStart);\n                ds >> mh;\n                if (!mh.IsValid(pchMessageStart)) {return 0;}\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CADDRESS_DESERIALIZE:\n        {\n            try\n            {\n                CAddress a;\n                ds >> a;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CINV_DESERIALIZE:\n        {\n            try\n            {\n                CInv i;\n                ds >> i;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CBLOOMFILTER_DESERIALIZE:\n        {\n            try\n            {\n                CBloomFilter bf;\n                ds >> bf;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CDISKBLOCKINDEX_DESERIALIZE:\n        {\n            try\n            {\n                CDiskBlockIndex dbi;\n                ds >> dbi;\n            } catch (const std::ios_base::failure& e) {return 0;}\n            break;\n        }\n        case CTXOUTCOMPRESSOR_DESERIALIZE:\n        {\n            CTxOut to;\n            CTxOutCompressorLegacy toc(to);\n            try\n            {\n                ds >> toc;\n            } catch (const std::ios_base::failure& e) {return 0;}\n\n            break;\n        }\n        default:\n            return 0;\n    }\n    return 0;\n}\n\nint main(int argc, char **argv)\n{\n    ECCVerifyHandle globalVerifyHandle;\n#ifdef __AFL_INIT\n    // Enable AFL deferred forkserver mode. Requires compilation using\n    // afl-clang-fast++. See fuzzing.md for details.\n    __AFL_INIT();\n#endif\n\n#ifdef __AFL_LOOP\n    // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.\n    // See fuzzing.md for details.\n    while (__AFL_LOOP(1000)) {\n        do_fuzz();\n    }\n    return 0;\n#else\n    return do_fuzz();\n#endif\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/test/test_main.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n\n#include \"appname.h\"\n\n#define BOOST_TEST_MODULE (GLOBAL_APPNAME \" unit tests\")\n\n#include \"net.h\"\n\n#include <boost/test/unit_test.hpp>\n"
  },
  {
    "path": "src/test/testutil.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"testutil.h\"\n\n#ifdef WIN32\n#include <shlobj.h>\n#endif\n\n#include \"fs.h\"\n\nfs::path GetTempPath() {\n    return fs::temp_directory_path();\n}\n"
  },
  {
    "path": "src/test/testutil.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n/**\n * Utility functions shared by unit tests\n */\n#ifndef TEST_TESTUTIL_H\n#define TEST_TESTUTIL_H\n\n#include \"fs.h\"\n\nfs::path GetTempPath();\n\n#endif\n"
  },
  {
    "path": "src/test/timedata_tests.cpp",
    "content": "// Copyright (c) 2011-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n#include \"timedata.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(util_MedianFilter)\n{\n    CMedianFilter<int> filter(5, 15);\n\n    BOOST_CHECK_EQUAL(filter.median(), 15);\n\n    filter.input(20); // [15 20]\n    BOOST_CHECK_EQUAL(filter.median(), 17);\n\n    filter.input(30); // [15 20 30]\n    BOOST_CHECK_EQUAL(filter.median(), 20);\n\n    filter.input(3); // [3 15 20 30]\n    BOOST_CHECK_EQUAL(filter.median(), 17);\n\n    filter.input(7); // [3 7 15 20 30]\n    BOOST_CHECK_EQUAL(filter.median(), 15);\n\n    filter.input(18); // [3 7 18 20 30]\n    BOOST_CHECK_EQUAL(filter.median(), 18);\n\n    filter.input(0); // [0 3 7 18 30]\n    BOOST_CHECK_EQUAL(filter.median(), 7);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/torcontrol_tests.cpp",
    "content": "// Copyright (c) 2017 The Zcash developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n#include \"test/test.h\"\n#include \"torcontrol.cpp\"\n\n#include <boost/test/unit_test.hpp>\n\n\nBOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup)\n\nvoid CheckSplitTorReplyLine(std::string input, std::string command, std::string args)\n{\n    BOOST_TEST_MESSAGE(std::string(\"CheckSplitTorReplyLine(\") + input + \")\");\n    auto ret = SplitTorReplyLine(input);\n    BOOST_CHECK_EQUAL(ret.first, command);\n    BOOST_CHECK_EQUAL(ret.second, args);\n}\n\nBOOST_AUTO_TEST_CASE(util_SplitTorReplyLine)\n{\n    // Data we should receive during normal usage\n    CheckSplitTorReplyLine(\n        \"PROTOCOLINFO PIVERSION\",\n        \"PROTOCOLINFO\", \"PIVERSION\");\n    CheckSplitTorReplyLine(\n        \"AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\\\"/home/x/.tor/control_auth_cookie\\\"\",\n        \"AUTH\", \"METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\\\"/home/x/.tor/control_auth_cookie\\\"\");\n    CheckSplitTorReplyLine(\n        \"AUTH METHODS=NULL\",\n        \"AUTH\", \"METHODS=NULL\");\n    CheckSplitTorReplyLine(\n        \"AUTH METHODS=HASHEDPASSWORD\",\n        \"AUTH\", \"METHODS=HASHEDPASSWORD\");\n    CheckSplitTorReplyLine(\n        \"VERSION Tor=\\\"0.2.9.8 (git-a0df013ea241b026)\\\"\",\n        \"VERSION\", \"Tor=\\\"0.2.9.8 (git-a0df013ea241b026)\\\"\");\n    CheckSplitTorReplyLine(\n        \"AUTHCHALLENGE SERVERHASH=aaaa SERVERNONCE=bbbb\",\n        \"AUTHCHALLENGE\", \"SERVERHASH=aaaa SERVERNONCE=bbbb\");\n\n    // Other valid inputs\n    CheckSplitTorReplyLine(\"COMMAND\", \"COMMAND\", \"\");\n    CheckSplitTorReplyLine(\"COMMAND SOME  ARGS\", \"COMMAND\", \"SOME  ARGS\");\n\n    // These inputs are valid because PROTOCOLINFO accepts an OtherLine that is\n    // just an OptArguments, which enables multiple spaces to be present\n    // between the command and arguments.\n    CheckSplitTorReplyLine(\"COMMAND  ARGS\", \"COMMAND\", \" ARGS\");\n    CheckSplitTorReplyLine(\"COMMAND   EVEN+more  ARGS\", \"COMMAND\", \"  EVEN+more  ARGS\");\n}\n\nvoid CheckParseTorReplyMapping(std::string input, std::map<std::string,std::string> expected)\n{\n    BOOST_TEST_MESSAGE(std::string(\"CheckParseTorReplyMapping(\") + input + \")\");\n    auto ret = ParseTorReplyMapping(input);\n    BOOST_CHECK_EQUAL(ret.size(), expected.size());\n    auto r_it = ret.begin();\n    auto e_it = expected.begin();\n    while (r_it != ret.end() && e_it != expected.end()) {\n        BOOST_CHECK_EQUAL(r_it->first, e_it->first);\n        BOOST_CHECK_EQUAL(r_it->second, e_it->second);\n        r_it++;\n        e_it++;\n    }\n}\n\nBOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping)\n{\n    // Data we should receive during normal usage\n    CheckParseTorReplyMapping(\n        \"METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\\\"/home/x/.tor/control_auth_cookie\\\"\", {\n            {\"METHODS\", \"COOKIE,SAFECOOKIE\"},\n            {\"COOKIEFILE\", \"/home/x/.tor/control_auth_cookie\"},\n        });\n    CheckParseTorReplyMapping(\n        \"METHODS=NULL\", {\n            {\"METHODS\", \"NULL\"},\n        });\n    CheckParseTorReplyMapping(\n        \"METHODS=HASHEDPASSWORD\", {\n            {\"METHODS\", \"HASHEDPASSWORD\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Tor=\\\"0.2.9.8 (git-a0df013ea241b026)\\\"\", {\n            {\"Tor\", \"0.2.9.8 (git-a0df013ea241b026)\"},\n        });\n    CheckParseTorReplyMapping(\n        \"SERVERHASH=aaaa SERVERNONCE=bbbb\", {\n            {\"SERVERHASH\", \"aaaa\"},\n            {\"SERVERNONCE\", \"bbbb\"},\n        });\n    CheckParseTorReplyMapping(\n        \"ServiceID=exampleonion1234\", {\n            {\"ServiceID\", \"exampleonion1234\"},\n        });\n    CheckParseTorReplyMapping(\n        \"PrivateKey=RSA1024:BLOB\", {\n            {\"PrivateKey\", \"RSA1024:BLOB\"},\n        });\n    CheckParseTorReplyMapping(\n        \"ClientAuth=bob:BLOB\", {\n            {\"ClientAuth\", \"bob:BLOB\"},\n        });\n\n    // Other valid inputs\n    CheckParseTorReplyMapping(\n        \"Foo=Bar=Baz Spam=Eggs\", {\n            {\"Foo\", \"Bar=Baz\"},\n            {\"Spam\", \"Eggs\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar=Baz\\\"\", {\n            {\"Foo\", \"Bar=Baz\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar Baz\\\"\", {\n            {\"Foo\", \"Bar Baz\"},\n        });\n\n    // Escapes\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\ Baz\\\"\", {\n            {\"Foo\", \"Bar Baz\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\Baz\\\"\", {\n            {\"Foo\", \"BarBaz\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\@Baz\\\"\", {\n            {\"Foo\", \"Bar@Baz\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\\\\"Baz\\\" Spam=\\\"\\\\\\\"Eggs\\\\\\\"\\\"\", {\n            {\"Foo\", \"Bar\\\"Baz\"},\n            {\"Spam\", \"\\\"Eggs\\\"\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\\\\\Baz\\\"\", {\n            {\"Foo\", \"Bar\\\\Baz\"},\n        });\n\n    // C escapes\n    CheckParseTorReplyMapping(\n        \"Foo=\\\"Bar\\\\nBaz\\\\t\\\" Spam=\\\"\\\\rEggs\\\" Octals=\\\"\\\\1a\\\\11\\\\17\\\\18\\\\81\\\\377\\\\378\\\\400\\\\2222\\\" Final=Check\", {\n            {\"Foo\", \"Bar\\nBaz\\t\"},\n            {\"Spam\", \"\\rEggs\"},\n            {\"Octals\", \"\\1a\\11\\17\\1\" \"881\\377\\37\" \"8\\40\" \"0\\222\" \"2\"},\n            {\"Final\", \"Check\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Valid=Mapping Escaped=\\\"Escape\\\\\\\\\\\"\", {\n            {\"Valid\", \"Mapping\"},\n            {\"Escaped\", \"Escape\\\\\"},\n        });\n    CheckParseTorReplyMapping(\n        \"Valid=Mapping Bare=\\\"Escape\\\\\\\"\", {});\n    CheckParseTorReplyMapping(\n        \"OneOctal=\\\"OneEnd\\\\1\\\" TwoOctal=\\\"TwoEnd\\\\11\\\"\", {\n            {\"OneOctal\", \"OneEnd\\1\"},\n            {\"TwoOctal\", \"TwoEnd\\11\"},\n        });\n\n    // Special handling for null case\n    // (needed because string comparison reads the null as end-of-string)\n    BOOST_TEST_MESSAGE(std::string(\"CheckParseTorReplyMapping(Null=\\\"\\\\0\\\")\"));\n    auto ret = ParseTorReplyMapping(\"Null=\\\"\\\\0\\\"\");\n    BOOST_CHECK(ret.size() == 1);\n    auto r_it = ret.begin();\n    BOOST_CHECK_EQUAL(r_it->first, \"Null\");\n    BOOST_CHECK(r_it->second.size() == 1);\n    BOOST_CHECK_EQUAL(r_it->second[0], '\\0');\n\n    // A more complex valid grammar. PROTOCOLINFO accepts a VersionLine that\n    // takes a key=value pair followed by an OptArguments, making this valid.\n    // Because an OptArguments contains no semantic data, there is no point in\n    // parsing it.\n    CheckParseTorReplyMapping(\n        \"SOME=args,here MORE optional=arguments  here\", {\n            {\"SOME\", \"args,here\"},\n        });\n\n    // Inputs that are effectively invalid under the target grammar.\n    // PROTOCOLINFO accepts an OtherLine that is just an OptArguments, which\n    // would make these inputs valid. However,\n    // - This parser is never used in that situation, because the\n    //   SplitTorReplyLine parser enables OtherLine to be skipped.\n    // - Even if these were valid, an OptArguments contains no semantic data,\n    //   so there is no point in parsing it.\n    CheckParseTorReplyMapping(\"ARGS\", {});\n    CheckParseTorReplyMapping(\"MORE ARGS\", {});\n    CheckParseTorReplyMapping(\"MORE  ARGS\", {});\n    CheckParseTorReplyMapping(\"EVEN more=ARGS\", {});\n    CheckParseTorReplyMapping(\"EVEN+more ARGS\", {});\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/transaction_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"data/tx_invalid.json.h\"\n#include \"data/tx_valid.json.h\"\n#include \"test/test.h\"\n\n#include \"clientversion.h\"\n#include \"checkqueue.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"core_io.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"validation/validation.h\"\n#include \"policy/policy.h\"\n#include \"script/script.h\"\n#include \"script/sign.h\"\n#include \"script/script_error.h\"\n#include \"script/standard.h\"\n#include \"util/strencodings.h\"\n#include \"witnessutil.h\"\n#include \"coins.h\"\n\n#include <map>\n#include <string>\n\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/split.hpp>\n#include <boost/test/unit_test.hpp>\n\n\n#include <univalue.h>\n\ntypedef std::vector<unsigned char> valtype;\n\n// In script_tests.cpp\nextern UniValue read_json(const std::string& jsondata);\n\nstatic std::map<std::string, unsigned int> mapFlagNames = {\n    {std::string(\"NONE\"), (unsigned int)SCRIPT_VERIFY_NONE},\n    {std::string(\"P2SH\"), (unsigned int)SCRIPT_VERIFY_P2SH},\n    {std::string(\"STRICTENC\"), (unsigned int)SCRIPT_VERIFY_STRICTENC},\n    {std::string(\"DERSIG\"), (unsigned int)SCRIPT_VERIFY_DERSIG},\n    {std::string(\"LOW_S\"), (unsigned int)SCRIPT_VERIFY_LOW_S},\n    {std::string(\"SIGPUSHONLY\"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},\n    {std::string(\"MINIMALDATA\"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},\n    {std::string(\"DISCOURAGE_UPGRADABLE_NOPS\"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},\n    {std::string(\"CLEANSTACK\"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},\n    {std::string(\"MINIMALIF\"), (unsigned int)SCRIPT_VERIFY_MINIMALIF},\n    {std::string(\"NULLFAIL\"), (unsigned int)SCRIPT_VERIFY_NULLFAIL},\n    {std::string(\"CHECKLOCKTIMEVERIFY\"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},\n    {std::string(\"CHECKSEQUENCEVERIFY\"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},\n};\n\nunsigned int ParseScriptFlags(std::string strFlags)\n{\n    if (strFlags.empty()) {\n        return 0;\n    }\n    unsigned int flags = 0;\n    std::vector<std::string> words;\n    boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(\",\"));\n\n    for(std::string word : words)\n    {\n        if (!mapFlagNames.count(word))\n            BOOST_ERROR(\"Bad test: unknown verification flag '\" << word << \"'\");\n        flags |= mapFlagNames[word];\n    }\n\n    return flags;\n}\n\nstd::string FormatScriptFlags(unsigned int flags)\n{\n    if (flags == 0) {\n        return \"\";\n    }\n    std::string ret;\n    std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();\n    while (it != mapFlagNames.end()) {\n        if (flags & it->second) {\n            ret += it->first + \",\";\n        }\n        it++;\n    }\n    return ret.substr(0, ret.size() - 1);\n}\n\nBOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(tx_valid)\n{\n    // Read tests from test/data/tx_valid.json\n    // Format is an array of arrays\n    // Inner arrays are either [ \"comment\" ]\n    // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],\"], serializedTransaction, verifyFlags\n    // ... where all scripts are stringified scripts.\n    //\n    // verifyFlags is a comma separated list of script verification flags to apply, or \"NONE\"\n    UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));\n\n    ScriptError err;\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test[0].isArray())\n        {\n            if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())\n            {\n                BOOST_ERROR(\"Bad test: \" << strTest);\n                continue;\n            }\n\n            std::map<COutPoint, CScript> mapprevOutScriptPubKeys;\n            std::map<COutPoint, int64_t> mapprevOutValues;\n            UniValue inputs = test[0].get_array();\n            bool fValid = true;\n            for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++)\n            {\n                const UniValue& input = inputs[inpIdx];\n                if (!input.isArray())\n                {\n                    fValid = false;\n                    break;\n                }\n                UniValue vinput = input.get_array();\n                if (vinput.size() < 3 || vinput.size() > 4)\n                {\n                    fValid = false;\n                    break;\n                }\n                COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int());\n                mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str());\n                if (vinput.size() >= 4)\n                {\n                    mapprevOutValues[outpoint] = vinput[3].get_int64();\n                }\n            }\n            if (!fValid)\n            {\n                BOOST_ERROR(\"Bad test: \" << strTest);\n                continue;\n            }\n\n            std::string transaction = test[1].get_str();\n            CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);\n            CTransaction tx(deserialize, stream);\n\n            CValidationState state;\n            BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);\n            BOOST_CHECK(state.IsValid());\n\n            PrecomputedTransactionData txdata(tx);\n            for (unsigned int i = 0; i < tx.vin.size(); i++)\n            {\n                if (!mapprevOutScriptPubKeys.count(tx.vin[i].GetPrevOut()))\n                {\n                    BOOST_ERROR(\"Bad test: \" << strTest);\n                    break;\n                }\n\n                CAmount amount = 0;\n                if (mapprevOutValues.count(tx.vin[i].GetPrevOut())) {\n                    amount = mapprevOutValues[tx.vin[i].GetPrevOut()];\n                }\n                unsigned int verify_flags = ParseScriptFlags(test[2].get_str());\n                const CSegregatedSignatureData *segregatedSignatureData = &tx.vin[i].segregatedSignatureData;\n                BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].GetPrevOut()],segregatedSignatureData, verify_flags, TransactionSignatureChecker(CKeyID(), CKeyID(), &tx, i, amount, txdata), SCRIPT_V1, &err), strTest);\n                BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(tx_invalid)\n{\n    // Read tests from test/data/tx_invalid.json\n    // Format is an array of arrays\n    // Inner arrays are either [ \"comment\" ]\n    // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],\"], serializedTransaction, verifyFlags\n    // ... where all scripts are stringified scripts.\n    //\n    // verifyFlags is a comma separated list of script verification flags to apply, or \"NONE\"\n    UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));\n\n    // Initialize to SCRIPT_ERR_OK. The tests expect err to be changed to a\n    // value other than SCRIPT_ERR_OK.\n    ScriptError err = SCRIPT_ERR_OK;\n    for (unsigned int idx = 0; idx < tests.size(); idx++) {\n        UniValue test = tests[idx];\n        std::string strTest = test.write();\n        if (test[0].isArray())\n        {\n            if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())\n            {\n                BOOST_ERROR(\"Bad test: \" << strTest);\n                continue;\n            }\n\n            std::map<COutPoint, CScript> mapprevOutScriptPubKeys;\n            std::map<COutPoint, int64_t> mapprevOutValues;\n            UniValue inputs = test[0].get_array();\n            bool fValid = true;\n            for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++)\n            {\n                const UniValue& input = inputs[inpIdx];\n                if (!input.isArray())\n                {\n                    fValid = false;\n                    break;\n                }\n                UniValue vinput = input.get_array();\n                if (vinput.size() < 3 || vinput.size() > 4)\n                {\n                    fValid = false;\n                    break;\n                }\n                COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int());\n                mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str());\n                if (vinput.size() >= 4)\n                {\n                    mapprevOutValues[outpoint] = vinput[3].get_int64();\n                }\n            }\n            if (!fValid)\n            {\n                BOOST_ERROR(\"Bad test: \" << strTest);\n                continue;\n            }\n\n            std::string transaction = test[1].get_str();\n            CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION );\n            CTransaction tx(deserialize, stream);\n\n            CValidationState state;\n            fValid = CheckTransaction(tx, state) && state.IsValid();\n\n            PrecomputedTransactionData txdata(tx);\n            for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)\n            {\n                if (!mapprevOutScriptPubKeys.count(tx.vin[i].GetPrevOut()))\n                {\n                    BOOST_ERROR(\"Bad test: \" << strTest);\n                    break;\n                }\n\n                unsigned int verify_flags = ParseScriptFlags(test[2].get_str());\n                CAmount amount = 0;\n                if (mapprevOutValues.count(tx.vin[i].GetPrevOut())) {\n                    amount = mapprevOutValues[tx.vin[i].GetPrevOut()];\n                }\n                const CSegregatedSignatureData *segregatedSignatureData = &tx.vin[i].segregatedSignatureData;\n                fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].GetPrevOut()],segregatedSignatureData, verify_flags, TransactionSignatureChecker(CKeyID(), CKeyID(), &tx, i, amount, txdata), SCRIPT_V1, &err);\n            }\n            BOOST_CHECK_MESSAGE(!fValid, strTest);\n            BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(basic_transaction_tests)\n{\n    // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)\n    unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};\n    std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1);\n    CDataStream stream(vch, SER_DISK, CLIENT_VERSION);\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    stream >> tx;\n    CValidationState state;\n    BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), \"Simple deserialized transaction should be valid.\");\n\n    // Check that duplicate txins fail\n    tx.vin.push_back(tx.vin[0]);\n    BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), \"Transaction with duplicate txins should be invalid.\");\n}\n\n//\n// Helper: create two dummy transactions, each with\n// two outputs.  The first has 11 and 50 CENT outputs\n// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs\n// paid to a TX_PUBKEYHASH.\n//\n#ifndef DEBUG_COINSCACHE_VALIDATE_INSERTS\nstatic std::vector<CMutableTransaction> SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)\n{\n    std::vector<CMutableTransaction> dummyTransactions;\n    dummyTransactions.resize(2, CMutableTransaction(TEST_DEFAULT_TX_VERSION));\n\n    // Add some keys to the keystore:\n    CKey key[4];\n    for (int i = 0; i < 4; i++)\n    {\n        key[i].MakeNewKey(i % 2);\n        keystoreRet.AddKey(key[i]);\n    }\n\n    // Create some dummy input transactions\n    dummyTransactions[0].vout.resize(2);\n    dummyTransactions[0].vout[0].nValue = 11*CENT;\n    dummyTransactions[0].vout[0].output.scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;\n    dummyTransactions[0].vout[1].nValue = 50*CENT;\n    dummyTransactions[0].vout[1].output.scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;\n    AddCoins(coinsRet, dummyTransactions[0], 0, 0);\n\n    dummyTransactions[1].vout.resize(2);\n    dummyTransactions[1].vout[0].nValue = 21*CENT;\n    dummyTransactions[1].vout[0].output.scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());\n    dummyTransactions[1].vout[1].nValue = 22*CENT;\n    dummyTransactions[1].vout[1].output.scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());\n    AddCoins(coinsRet, dummyTransactions[1], 0, 0);\n\n    return dummyTransactions;\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(test_Get)\n{\n    #ifndef DEBUG_COINSCACHE_VALIDATE_INSERTS\n    CBasicKeyStore keystore;\n    CCoinsView coinsDummy;\n    CCoinsViewCache coins(&coinsDummy);\n    std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);\n\n    CMutableTransaction t1(TEST_DEFAULT_TX_VERSION);\n    t1.vin.resize(3);\n    COutPoint changePrevOut = t1.vin[0].GetPrevOut();\n    changePrevOut.setHash(dummyTransactions[0].GetHash());\n    changePrevOut.n = 1;\n    t1.vin[0].SetPrevOut(changePrevOut);\n    t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);\n    changePrevOut = t1.vin[1].GetPrevOut();\n    changePrevOut.setHash(dummyTransactions[1].GetHash());\n    changePrevOut.n = 0;\n    t1.vin[1].SetPrevOut(changePrevOut);\n    t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);\n    changePrevOut = t1.vin[2].GetPrevOut();\n    changePrevOut.setHash(dummyTransactions[1].GetHash());\n    changePrevOut.n = 1;\n    t1.vin[2].SetPrevOut(changePrevOut);\n    t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);\n    t1.vout.resize(2);\n    t1.vout[0].nValue = 90*CENT;\n    t1.vout[0].output.scriptPubKey << OP_1;\n\n    BOOST_CHECK(AreInputsStandard(t1, coins));\n    BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);\n    #endif\n}\n\n\nBOOST_AUTO_TEST_CASE(test_IsStandard)\n{\n    #ifndef DEBUG_COINSCACHE_VALIDATE_INSERTS\n    LOCK(cs_main);\n    CBasicKeyStore keystore;\n    CCoinsView coinsDummy;\n    CCoinsViewCache coins(&coinsDummy);\n    std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);\n\n    CMutableTransaction t(TEST_DEFAULT_TX_VERSION);\n    t.vin.resize(1);\n    COutPoint changePrevOut = t.vin[0].GetPrevOut();\n    changePrevOut.setHash(dummyTransactions[0].GetHash());\n    changePrevOut.n = 1;\n    t.vin[0].SetPrevOut(changePrevOut);\n    t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);\n    t.vout.resize(1);\n    t.vout[0].nValue = 90*CENT;\n    CKey key;\n    key.MakeNewKey(true);\n    t.vout[0].output.scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());\n\n    std::string reason;\n    int nPoW2Version = GetPoW2Phase(chainActive.Tip());\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n\n    // Check dust with default relay fee:\n    CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000 * 3;\n    BOOST_CHECK_EQUAL(nDustThreshold, 546);\n\n    //fixme: (PHASE5) re-implement these tests if we decide to re-implement dust rules, currently they don't apply for us.\n    #if 0\n    // dust:\n    t.vout[0].nValue = nDustThreshold - 1;\n    BOOST_CHECK(!IsStandardTx(t, reason));\n    #endif\n    // not dust:\n    t.vout[0].nValue = nDustThreshold;\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n\n    //fixme: (PHASE5) re-implement these tests if we decide to re-implement dust rules, currently they don't apply for us.\n    #if 0\n    // Check dust with odd relay fee to verify rounding:\n    // nDustThreshold = 182 * 1234 / 1000 * 3\n    dustRelayFee = CFeeRate(1234);\n    // dust:\n    t.vout[0].nValue = 672 - 1;\n    BOOST_CHECK(!IsStandardTx(t, reason));\n    #endif\n    // not dust:\n    t.vout[0].nValue = 672;\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n    dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);\n\n    t.vout[0].output.scriptPubKey = CScript() << OP_1;\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n\n    // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38\");\n    BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].output.scriptPubKey.size());\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n\n    // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800\");\n    BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].output.scriptPubKey.size());\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n\n    // Data payload can be encoded in any way...\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"\");\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"00\") << ParseHex(\"01\");\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n    // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex(\"01\") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16;\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex(\"01\") << 2 << ParseHex(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n\n    // ...so long as it only contains PUSHDATA's\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << OP_RETURN;\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n\n    // TX_NULL_DATA w/o PUSHDATA\n    t.vout.resize(1);\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN;\n    BOOST_CHECK(IsStandardTx(t, reason, nPoW2Version));\n\n    // Only one TX_NULL_DATA permitted in all cases\n    t.vout.resize(2);\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38\");\n    t.vout[1].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38\");\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN << ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38\");\n    t.vout[1].output.scriptPubKey = CScript() << OP_RETURN;\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n\n    t.vout[0].output.scriptPubKey = CScript() << OP_RETURN;\n    t.vout[1].output.scriptPubKey = CScript() << OP_RETURN;\n    BOOST_CHECK(!IsStandardTx(t, reason, nPoW2Version));\n    #endif\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/txvalidationcache_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"consensus/validation.h\"\n#include \"key.h\"\n#include \"validation/validation.h\"\n#include \"generation/miner.h\"\n#include \"pubkey.h\"\n#include \"txmempool.h\"\n#include \"random.h\"\n#include \"script/standard.h\"\n#include \"test/test.h\"\n#include \"util/time.h\"\n\n#ifdef ENABLE_WALLET\n#include <wallet/wallet.h>\n#endif\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_AUTO_TEST_SUITE(tx_validationcache_tests)\n\nstatic bool\nToMemPool(CMutableTransaction& tx)\n{\n    LOCK(cs_main);\n\n    CValidationState state;\n    return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, NULL, NULL, true, 0);\n}\n\nBOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)\n{\n    // Make sure skipping validation of transctions that were\n    // validated going into the memory pool does not allow\n    // double-spends in blocks to pass validation when they should not.\n\n    CScript scriptPubKey = CScript() <<  ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;\n    std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n\n    // Create a double-spend of mature coinbase txn:\n    std::vector<CMutableTransaction> spends;\n    spends.resize(2, CMutableTransaction(TEST_DEFAULT_TX_VERSION));\n    for (int i = 0; i < 2; i++)\n    {\n        spends[i].nVersion = 1;\n        spends[i].vin.resize(1);\n        COutPoint changePrevOut = spends[i].vin[0].GetPrevOut();\n        changePrevOut.setHash(coinbaseTxns[0].GetHash());\n        changePrevOut.n = 0;\n        spends[i].vin[0].SetPrevOut(changePrevOut);\n        spends[i].vout.resize(1);\n        spends[i].vout[0].nValue = 11*CENT;\n        spends[i].vout[0].output.scriptPubKey = scriptPubKey;\n\n        // Sign:\n        std::vector<unsigned char> vchSig;\n        uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SIGVERSION_BASE);\n        BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));\n        vchSig.push_back((unsigned char)SIGHASH_ALL);\n        spends[i].vin[0].scriptSig << vchSig;\n    }\n\n    CBlock block;\n\n    // Test 1: block with both of those transactions should be rejected.\n    block = CreateAndProcessBlock(spends, reservedScript);\n    BOOST_CHECK(chainActive.Tip()->GetBlockHashLegacy() != block.GetHashLegacy());\n\n    // Test 2: ... and should be rejected if spend1 is in the memory pool\n    BOOST_CHECK(ToMemPool(spends[0]));\n    block = CreateAndProcessBlock(spends, reservedScript);\n    BOOST_CHECK(chainActive.Tip()->GetBlockHashLegacy() != block.GetHashLegacy());\n    mempool.clear();\n\n    // Test 3: ... and should be rejected if spend2 is in the memory pool\n    BOOST_CHECK(ToMemPool(spends[1]));\n    block = CreateAndProcessBlock(spends, reservedScript);\n    BOOST_CHECK(chainActive.Tip()->GetBlockHashLegacy() != block.GetHashLegacy());\n    mempool.clear();\n\n    // Final sanity test: first spend in mempool, second in block, that's OK:\n    std::vector<CMutableTransaction> oneSpend;\n    oneSpend.push_back(spends[0]);\n    BOOST_CHECK(ToMemPool(spends[1]));\n    block = CreateAndProcessBlock(oneSpend, reservedScript);\n    BOOST_CHECK(chainActive.Tip()->GetBlockHashLegacy() == block.GetHashLegacy());\n    // spends[1] should have been removed from the mempool when the\n    // block with spends[0] is accepted:\n    BOOST_CHECK_EQUAL(mempool.size(), 0U);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/uint256_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#include \"arith_uint256.h\"\n#include \"uint256.h\"\n#include \"version.h\"\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n#include <stdint.h>\n#include <sstream>\n#include <iomanip>\n#include <limits>\n#include <cmath>\n#include <string>\n#include <stdio.h>\n\nBOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup)\n\nconst unsigned char R1Array[] =\n    \"\\x9c\\x52\\x4a\\xdb\\xcf\\x56\\x11\\x12\\x2b\\x29\\x12\\x5e\\x5d\\x35\\xd2\\xd2\"\n    \"\\x22\\x81\\xaa\\xb5\\x33\\xf0\\x08\\x32\\xd5\\x56\\xb1\\xf9\\xea\\xe5\\x1d\\x7d\";\nconst char R1ArrayHex[] = \"7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c\";\nconst uint256 R1L = uint256(std::vector<unsigned char>(R1Array,R1Array+32));\nconst uint160 R1S = uint160(std::vector<unsigned char>(R1Array,R1Array+20));\n\nconst unsigned char R2Array[] =\n    \"\\x70\\x32\\x1d\\x7c\\x47\\xa5\\x6b\\x40\\x26\\x7e\\x0a\\xc3\\xa6\\x9c\\xb6\\xbf\"\n    \"\\x13\\x30\\x47\\xa3\\x19\\x2d\\xda\\x71\\x49\\x13\\x72\\xf0\\xb4\\xca\\x81\\xd7\";\nconst uint256 R2L = uint256(std::vector<unsigned char>(R2Array,R2Array+32));\nconst uint160 R2S = uint160(std::vector<unsigned char>(R2Array,R2Array+20));\n\nconst unsigned char ZeroArray[] =\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";\nconst uint256 ZeroL = uint256(std::vector<unsigned char>(ZeroArray,ZeroArray+32));\nconst uint160 ZeroS = uint160(std::vector<unsigned char>(ZeroArray,ZeroArray+20));\n\nconst unsigned char OneArray[] =\n    \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n    \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";\nconst uint256 OneL = uint256(std::vector<unsigned char>(OneArray,OneArray+32));\nconst uint160 OneS = uint160(std::vector<unsigned char>(OneArray,OneArray+20));\n\nconst unsigned char MaxArray[] =\n    \"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\"\n    \"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\";\nconst uint256 MaxL = uint256(std::vector<unsigned char>(MaxArray,MaxArray+32));\nconst uint160 MaxS = uint160(std::vector<unsigned char>(MaxArray,MaxArray+20));\n\nstd::string ArrayToString(const unsigned char A[], unsigned int width)\n{\n    std::stringstream Stream;\n    Stream << std::hex;\n    for (unsigned int i = 0; i < width; ++i)\n    {\n        Stream<<std::setw(2)<<std::setfill('0')<<(unsigned int)A[width-i-1];\n    }\n    return Stream.str();\n}\n\ninline uint160 uint160S(const char *str)\n{\n    uint160 rv;\n    rv.SetHex(str);\n    return rv;\n}\ninline uint160 uint160S(const std::string& str)\n{\n    uint160 rv;\n    rv.SetHex(str);\n    return rv;\n}\n\nBOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality\n{\n    BOOST_CHECK(1 == 0+1);\n    // constructor uint256(vector<char>):\n    BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32));\n    BOOST_CHECK(R1S.ToString() == ArrayToString(R1Array,20));\n    BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32));\n    BOOST_CHECK(R2S.ToString() == ArrayToString(R2Array,20));\n    BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32));\n    BOOST_CHECK(ZeroS.ToString() == ArrayToString(ZeroArray,20));\n    BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray,32));\n    BOOST_CHECK(OneS.ToString() == ArrayToString(OneArray,20));\n    BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray,32));\n    BOOST_CHECK(MaxS.ToString() == ArrayToString(MaxArray,20));\n    BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray,32));\n    BOOST_CHECK(OneS.ToString() != ArrayToString(ZeroArray,20));\n\n    // == and !=\n    BOOST_CHECK(R1L != R2L && R1S != R2S);\n    BOOST_CHECK(ZeroL != OneL && ZeroS != OneS);\n    BOOST_CHECK(OneL != ZeroL && OneS != ZeroS);\n    BOOST_CHECK(MaxL != ZeroL && MaxS != ZeroS);\n\n    // String Constructor and Copy Constructor\n    BOOST_CHECK(uint256S(\"0x\"+R1L.ToString()) == R1L);\n    BOOST_CHECK(uint256S(\"0x\"+R2L.ToString()) == R2L);\n    BOOST_CHECK(uint256S(\"0x\"+ZeroL.ToString()) == ZeroL);\n    BOOST_CHECK(uint256S(\"0x\"+OneL.ToString()) == OneL);\n    BOOST_CHECK(uint256S(\"0x\"+MaxL.ToString()) == MaxL);\n    BOOST_CHECK(uint256S(R1L.ToString()) == R1L);\n    BOOST_CHECK(uint256S(\"   0x\"+R1L.ToString()+\"   \") == R1L);\n    BOOST_CHECK(uint256S(\"\") == ZeroL);\n    BOOST_CHECK(R1L == uint256S(R1ArrayHex));\n    BOOST_CHECK(uint256(R1L) == R1L);\n    BOOST_CHECK(uint256(ZeroL) == ZeroL);\n    BOOST_CHECK(uint256(OneL) == OneL);\n\n    BOOST_CHECK(uint160S(\"0x\"+R1S.ToString()) == R1S);\n    BOOST_CHECK(uint160S(\"0x\"+R2S.ToString()) == R2S);\n    BOOST_CHECK(uint160S(\"0x\"+ZeroS.ToString()) == ZeroS);\n    BOOST_CHECK(uint160S(\"0x\"+OneS.ToString()) == OneS);\n    BOOST_CHECK(uint160S(\"0x\"+MaxS.ToString()) == MaxS);\n    BOOST_CHECK(uint160S(R1S.ToString()) == R1S);\n    BOOST_CHECK(uint160S(\"   0x\"+R1S.ToString()+\"   \") == R1S);\n    BOOST_CHECK(uint160S(\"\") == ZeroS);\n    BOOST_CHECK(R1S == uint160S(R1ArrayHex));\n\n    BOOST_CHECK(uint160(R1S) == R1S);\n    BOOST_CHECK(uint160(ZeroS) == ZeroS);\n    BOOST_CHECK(uint160(OneS) == OneS);\n}\n\nBOOST_AUTO_TEST_CASE( comparison ) // <= >= < >\n{\n    uint256 LastL;\n    for (int i = 255; i >= 0; --i) {\n        uint256 TmpL;\n        *(TmpL.begin() + (i>>3)) |= 1<<(7-(i&7));\n        BOOST_CHECK( LastL < TmpL );\n        LastL = TmpL;\n    }\n\n    BOOST_CHECK( ZeroL < R1L );\n    BOOST_CHECK( R2L < R1L );\n    BOOST_CHECK( ZeroL < OneL );\n    BOOST_CHECK( OneL < MaxL );\n    BOOST_CHECK( R1L < MaxL );\n    BOOST_CHECK( R2L < MaxL );\n\n    uint160 LastS;\n    for (int i = 159; i >= 0; --i) {\n        uint160 TmpS;\n        *(TmpS.begin() + (i>>3)) |= 1<<(7-(i&7));\n        BOOST_CHECK( LastS < TmpS );\n        LastS = TmpS;\n    }\n    BOOST_CHECK( ZeroS < R1S );\n    BOOST_CHECK( R2S < R1S );\n    BOOST_CHECK( ZeroS < OneS );\n    BOOST_CHECK( OneS < MaxS );\n    BOOST_CHECK( R1S < MaxS );\n    BOOST_CHECK( R2S < MaxS );\n}\n\nBOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 GetSerializeSize, Serialize, Unserialize\n{\n    BOOST_CHECK(R1L.GetHex() == R1L.ToString());\n    BOOST_CHECK(R2L.GetHex() == R2L.ToString());\n    BOOST_CHECK(OneL.GetHex() == OneL.ToString());\n    BOOST_CHECK(MaxL.GetHex() == MaxL.ToString());\n    uint256 TmpL(R1L);\n    BOOST_CHECK(TmpL == R1L);\n    TmpL.SetHex(R2L.ToString());   BOOST_CHECK(TmpL == R2L);\n    TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == uint256());\n\n    TmpL.SetHex(R1L.ToString());\n    BOOST_CHECK(memcmp(R1L.begin(), R1Array, 32)==0);\n    BOOST_CHECK(memcmp(TmpL.begin(), R1Array, 32)==0);\n    BOOST_CHECK(memcmp(R2L.begin(), R2Array, 32)==0);\n    BOOST_CHECK(memcmp(ZeroL.begin(), ZeroArray, 32)==0);\n    BOOST_CHECK(memcmp(OneL.begin(), OneArray, 32)==0);\n    BOOST_CHECK(R1L.size() == sizeof(R1L));\n    BOOST_CHECK(sizeof(R1L) == 32);\n    BOOST_CHECK(R1L.size() == 32);\n    BOOST_CHECK(R2L.size() == 32);\n    BOOST_CHECK(ZeroL.size() == 32);\n    BOOST_CHECK(MaxL.size() == 32);\n    BOOST_CHECK(R1L.begin() + 32 == R1L.end());\n    BOOST_CHECK(R2L.begin() + 32 == R2L.end());\n    BOOST_CHECK(OneL.begin() + 32 == OneL.end());\n    BOOST_CHECK(MaxL.begin() + 32 == MaxL.end());\n    BOOST_CHECK(TmpL.begin() + 32 == TmpL.end());\n    BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32);\n    BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32);\n\n    CDataStream ss(0, PROTOCOL_VERSION);\n    ss << R1L;\n    BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32));\n    ss >> TmpL;\n    BOOST_CHECK(R1L == TmpL);\n    ss.clear();\n    ss << ZeroL;\n    BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+32));\n    ss >> TmpL;\n    BOOST_CHECK(ZeroL == TmpL);\n    ss.clear();\n    ss << MaxL;\n    BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+32));\n    ss >> TmpL;\n    BOOST_CHECK(MaxL == TmpL);\n    ss.clear();\n\n    BOOST_CHECK(R1S.GetHex() == R1S.ToString());\n    BOOST_CHECK(R2S.GetHex() == R2S.ToString());\n    BOOST_CHECK(OneS.GetHex() == OneS.ToString());\n    BOOST_CHECK(MaxS.GetHex() == MaxS.ToString());\n    uint160 TmpS(R1S);\n    BOOST_CHECK(TmpS == R1S);\n    TmpS.SetHex(R2S.ToString());   BOOST_CHECK(TmpS == R2S);\n    TmpS.SetHex(ZeroS.ToString()); BOOST_CHECK(TmpS == uint160());\n\n    TmpS.SetHex(R1S.ToString());\n    BOOST_CHECK(memcmp(R1S.begin(), R1Array, 20)==0);\n    BOOST_CHECK(memcmp(TmpS.begin(), R1Array, 20)==0);\n    BOOST_CHECK(memcmp(R2S.begin(), R2Array, 20)==0);\n    BOOST_CHECK(memcmp(ZeroS.begin(), ZeroArray, 20)==0);\n    BOOST_CHECK(memcmp(OneS.begin(), OneArray, 20)==0);\n    BOOST_CHECK(R1S.size() == sizeof(R1S));\n    BOOST_CHECK(sizeof(R1S) == 20);\n    BOOST_CHECK(R1S.size() == 20);\n    BOOST_CHECK(R2S.size() == 20);\n    BOOST_CHECK(ZeroS.size() == 20);\n    BOOST_CHECK(MaxS.size() == 20);\n    BOOST_CHECK(R1S.begin() + 20 == R1S.end());\n    BOOST_CHECK(R2S.begin() + 20 == R2S.end());\n    BOOST_CHECK(OneS.begin() + 20 == OneS.end());\n    BOOST_CHECK(MaxS.begin() + 20 == MaxS.end());\n    BOOST_CHECK(TmpS.begin() + 20 == TmpS.end());\n    BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20);\n    BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20);\n\n    ss << R1S;\n    BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20));\n    ss >> TmpS;\n    BOOST_CHECK(R1S == TmpS);\n    ss.clear();\n    ss << ZeroS;\n    BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+20));\n    ss >> TmpS;\n    BOOST_CHECK(ZeroS == TmpS);\n    ss.clear();\n    ss << MaxS;\n    BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+20));\n    ss >> TmpS;\n    BOOST_CHECK(MaxS == TmpS);\n    ss.clear();\n}\n\nBOOST_AUTO_TEST_CASE( conversion )\n{\n    BOOST_CHECK(ArithToUint256(UintToArith256(ZeroL)) == ZeroL);\n    BOOST_CHECK(ArithToUint256(UintToArith256(OneL)) == OneL);\n    BOOST_CHECK(ArithToUint256(UintToArith256(R1L)) == R1L);\n    BOOST_CHECK(ArithToUint256(UintToArith256(R2L)) == R2L);\n    BOOST_CHECK(UintToArith256(ZeroL) == 0);\n    BOOST_CHECK(UintToArith256(OneL) == 1);\n    BOOST_CHECK(ArithToUint256(0) == ZeroL);\n    BOOST_CHECK(ArithToUint256(1) == OneL);\n    BOOST_CHECK(arith_uint256(R1L.GetHex()) == UintToArith256(R1L));\n    BOOST_CHECK(arith_uint256(R2L.GetHex()) == UintToArith256(R2L));\n    BOOST_CHECK(R1L.GetHex() == UintToArith256(R1L).GetHex());\n    BOOST_CHECK(R2L.GetHex() == UintToArith256(R2L).GetHex());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/unity_tests.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"unity/compat/android_wallet.h\"\n\n#include \"clientversion.h\"\n#include \"primitives/transaction.h\"\n#include \"sync.h\"\n#include \"util/strencodings.h\"\n#include \"util/moneystr.h\"\n#include \"test/test.h\"\n\n#include <stdint.h>\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(unity_tests, BasicTestingSetup)\n\n#ifdef ANDROID\nbool retrieveWallet(std::string sFile, std::string sPassword, std::string phraseCheck)\n{\n    android_wallet wallet = ParseAndroidProtoWallet(sFile, sPassword);\n    if (!wallet.validWalletProto || ! wallet.validWallet)\n        return false;\n    if (sPassword.length() > 0 && !wallet.encrypted)\n        return false;\n\n    return wallet.walletSeedMnemonic == phraseCheck;\n}\n\nbool retrieveEncryptedWalletWithoutPassword(std::string sFile, std::string sPassword, std::string phraseCheck)\n{\n    android_wallet wallet = ParseAndroidProtoWallet(sFile, sPassword);\n    if (!wallet.validWalletProto)\n        return false;\n    if (wallet.encrypted && !wallet.validWallet)\n        return true;\n\n    return false;\n}\n\nbool retrieveEncryptedWalletWithWrongPassword(std::string sFile, std::string sPassword, std::string phraseCheck)\n{\n    android_wallet wallet = ParseAndroidProtoWallet(sFile, sPassword);\n    if (!wallet.validWalletProto)\n        return false;\n    if (wallet.encrypted && !wallet.validWallet)\n        return true;\n\n    return false;\n}\n#endif\n\n#ifdef ANDROID\n// Issues using protobuf with _GLIBCXX_DEBUG enabled on travis\n#ifndef _GLIBCXX_DEBUG\nBOOST_AUTO_TEST_CASE(unity_android_wallet_import)\n{\n    BOOST_CHECK(retrieveWallet(TESTDATADIR\"wallet-seed-password-1234-protobuf\",\"1234\",\"umbrella dune genuine busy whip core famous pattern impulse solid nice film\"));\n    BOOST_CHECK(retrieveWallet(TESTDATADIR\"wallet-seed-no-password-protobuf\",\"\",\"umbrella dune genuine busy whip core famous pattern impulse solid nice film\"));\n\n    BOOST_CHECK(retrieveWallet(TESTDATADIR\"wallet-linked-password-5281-protobuf\",\"5281\",\"EZv3Mzbf2XnGNZ1a8RUXhpuA6KKEmQh57Goqb3o7VBgy-F8zKT5BzCjcMyoQApTvu6jEtViUuGiCQnVBhFjXzeYbj:3mM4jYg7L4FhLC\"));\n    BOOST_CHECK(retrieveWallet(TESTDATADIR\"wallet-linked-no-password-protobuf\",\"\",\"EZv3Mzbf2XnGNZ1a8RUXhpuA6KKEmQh57Goqb3o7VBgy-F8zKT5BzCjcMyoQApTvu6jEtViUuGiCQnVBhFjXzeYbj:3mM4jYg7L4FhLC\"));\n\n    BOOST_CHECK(retrieveEncryptedWalletWithoutPassword(TESTDATADIR\"wallet-seed-password-1234-protobuf\",\"\",\"umbrella dune genuine busy whip core famous pattern impulse solid nice film\"));\n    BOOST_CHECK(retrieveEncryptedWalletWithWrongPassword(TESTDATADIR\"wallet-seed-password-1234-protobuf\",\"4321\",\"umbrella dune genuine busy whip core famous pattern impulse solid nice film\"));\n}\n#endif\n#endif\n\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/univalue_tests.cpp",
    "content": "// Copyright (c) 2014 BitPay Inc.\n// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <stdint.h>\n#include <vector>\n#include <string>\n#include <map>\n#include <univalue.h>\n#include \"test/test.h\"\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(univalue_constructor)\n{\n    UniValue v1;\n    BOOST_CHECK(v1.isNull());\n\n    UniValue v2(UniValue::VSTR);\n    BOOST_CHECK(v2.isStr());\n\n    UniValue v3(UniValue::VSTR, \"foo\");\n    BOOST_CHECK(v3.isStr());\n    BOOST_CHECK_EQUAL(v3.getValStr(), \"foo\");\n\n    UniValue numTest;\n    BOOST_CHECK(numTest.setNumStr(\"82\"));\n    BOOST_CHECK(numTest.isNum());\n    BOOST_CHECK_EQUAL(numTest.getValStr(), \"82\");\n\n    uint64_t vu64 = 82;\n    UniValue v4(vu64);\n    BOOST_CHECK(v4.isNum());\n    BOOST_CHECK_EQUAL(v4.getValStr(), \"82\");\n\n    int64_t vi64 = -82;\n    UniValue v5(vi64);\n    BOOST_CHECK(v5.isNum());\n    BOOST_CHECK_EQUAL(v5.getValStr(), \"-82\");\n\n    int vi = -688;\n    UniValue v6(vi);\n    BOOST_CHECK(v6.isNum());\n    BOOST_CHECK_EQUAL(v6.getValStr(), \"-688\");\n\n    double vd = -7.21;\n    UniValue v7(vd);\n    BOOST_CHECK(v7.isNum());\n    BOOST_CHECK_EQUAL(v7.getValStr(), \"-7.21\");\n\n    std::string vs(\"yawn\");\n    UniValue v8(vs);\n    BOOST_CHECK(v8.isStr());\n    BOOST_CHECK_EQUAL(v8.getValStr(), \"yawn\");\n\n    const char *vcs = \"zappa\";\n    UniValue v9(vcs);\n    BOOST_CHECK(v9.isStr());\n    BOOST_CHECK_EQUAL(v9.getValStr(), \"zappa\");\n}\n\nBOOST_AUTO_TEST_CASE(univalue_typecheck)\n{\n    UniValue v1;\n    BOOST_CHECK(v1.setNumStr(\"1\"));\n    BOOST_CHECK(v1.isNum());\n    BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);\n\n    UniValue v2;\n    BOOST_CHECK(v2.setBool(true));\n    BOOST_CHECK_EQUAL(v2.get_bool(), true);\n    BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);\n\n    UniValue v3;\n    BOOST_CHECK(v3.setNumStr(\"32482348723847471234\"));\n    BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);\n    BOOST_CHECK(v3.setNumStr(\"1000\"));\n    BOOST_CHECK_EQUAL(v3.get_int64(), 1000);\n\n    UniValue v4;\n    BOOST_CHECK(v4.setNumStr(\"2147483648\"));\n    BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);\n    BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);\n    BOOST_CHECK(v4.setNumStr(\"1000\"));\n    BOOST_CHECK_EQUAL(v4.get_int(), 1000);\n    BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);\n    BOOST_CHECK_EQUAL(v4.get_real(), 1000);\n    BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);\n\n    UniValue v5;\n    BOOST_CHECK(v5.read(\"[true, 10]\"));\n    BOOST_CHECK_NO_THROW(v5.get_array());\n    std::vector<UniValue> vals = v5.getValues();\n    BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);\n    BOOST_CHECK_EQUAL(vals[0].get_bool(), true);\n\n    BOOST_CHECK_EQUAL(vals[1].get_int(), 10);\n    BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);\n}\n\nBOOST_AUTO_TEST_CASE(univalue_set)\n{\n    UniValue v(UniValue::VSTR, \"foo\");\n    v.clear();\n    BOOST_CHECK(v.isNull());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"\");\n\n    BOOST_CHECK(v.setObject());\n    BOOST_CHECK(v.isObject());\n    BOOST_CHECK_EQUAL(v.size(), 0U);\n    BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);\n    BOOST_CHECK(v.empty());\n\n    BOOST_CHECK(v.setArray());\n    BOOST_CHECK(v.isArray());\n    BOOST_CHECK_EQUAL(v.size(), 0U);\n\n    BOOST_CHECK(v.setStr(\"zum\"));\n    BOOST_CHECK(v.isStr());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"zum\");\n\n    BOOST_CHECK(v.setFloat(-1.01));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-1.01\");\n\n    BOOST_CHECK(v.setInt((int)1023));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"1023\");\n\n    BOOST_CHECK(v.setInt((int64_t)-1023LL));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-1023\");\n\n    BOOST_CHECK(v.setInt((uint64_t)1023ULL));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"1023\");\n\n    BOOST_CHECK(v.setNumStr(\"-688\"));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-688\");\n\n    BOOST_CHECK(v.setBool(false));\n    BOOST_CHECK_EQUAL(v.isBool(), true);\n    BOOST_CHECK_EQUAL(v.isTrue(), false);\n    BOOST_CHECK_EQUAL(v.isFalse(), true);\n    BOOST_CHECK_EQUAL(v.getBool(), false);\n\n    BOOST_CHECK(v.setBool(true));\n    BOOST_CHECK_EQUAL(v.isBool(), true);\n    BOOST_CHECK_EQUAL(v.isTrue(), true);\n    BOOST_CHECK_EQUAL(v.isFalse(), false);\n    BOOST_CHECK_EQUAL(v.getBool(), true);\n\n    BOOST_CHECK(!v.setNumStr(\"zombocom\"));\n\n    BOOST_CHECK(v.setNull());\n    BOOST_CHECK(v.isNull());\n}\n\nBOOST_AUTO_TEST_CASE(univalue_array)\n{\n    UniValue arr(UniValue::VARR);\n\n    UniValue v((int64_t)1023LL);\n    BOOST_CHECK(arr.push_back(v));\n\n    std::string vStr(\"zippy\");\n    BOOST_CHECK(arr.push_back(vStr));\n\n    const char *s = \"pippy\";\n    BOOST_CHECK(arr.push_back(s));\n\n    std::vector<UniValue> vec;\n    v.setStr(\"boing\");\n    vec.push_back(v);\n\n    v.setStr(\"going\");\n    vec.push_back(v);\n\n    BOOST_CHECK(arr.push_backV(vec));\n\n    BOOST_CHECK_EQUAL(arr.empty(), false);\n    BOOST_CHECK_EQUAL(arr.size(), 5U);\n\n    BOOST_CHECK_EQUAL(arr[0].getValStr(), \"1023\");\n    BOOST_CHECK_EQUAL(arr[1].getValStr(), \"zippy\");\n    BOOST_CHECK_EQUAL(arr[2].getValStr(), \"pippy\");\n    BOOST_CHECK_EQUAL(arr[3].getValStr(), \"boing\");\n    BOOST_CHECK_EQUAL(arr[4].getValStr(), \"going\");\n\n    BOOST_CHECK_EQUAL(arr[999].getValStr(), \"\");\n\n    arr.clear();\n    BOOST_CHECK(arr.empty());\n    BOOST_CHECK_EQUAL(arr.size(), 0U);\n}\n\nBOOST_AUTO_TEST_CASE(univalue_object)\n{\n    UniValue obj(UniValue::VOBJ);\n    std::string strKey, strVal;\n    UniValue v;\n\n    strKey = \"age\";\n    v.setInt(100);\n    BOOST_CHECK(obj.pushKV(strKey, v));\n\n    strKey = \"first\";\n    strVal = \"John\";\n    BOOST_CHECK(obj.pushKV(strKey, strVal));\n\n    strKey = \"last\";\n    const char *cVal = \"Smith\";\n    BOOST_CHECK(obj.pushKV(strKey, cVal));\n\n    strKey = \"distance\";\n    BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));\n\n    strKey = \"time\";\n    BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));\n\n    strKey = \"calories\";\n    BOOST_CHECK(obj.pushKV(strKey, (int) 12));\n\n    strKey = \"temperature\";\n    BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));\n\n    UniValue obj2(UniValue::VOBJ);\n    BOOST_CHECK(obj2.pushKV(\"cat1\", 9000));\n    BOOST_CHECK(obj2.pushKV(\"cat2\", 12345));\n\n    BOOST_CHECK(obj.pushKVs(obj2));\n\n    BOOST_CHECK_EQUAL(obj.empty(), false);\n    BOOST_CHECK_EQUAL(obj.size(), 9U);\n\n    BOOST_CHECK_EQUAL(obj[\"age\"].getValStr(), \"100\");\n    BOOST_CHECK_EQUAL(obj[\"first\"].getValStr(), \"John\");\n    BOOST_CHECK_EQUAL(obj[\"last\"].getValStr(), \"Smith\");\n    BOOST_CHECK_EQUAL(obj[\"distance\"].getValStr(), \"25\");\n    BOOST_CHECK_EQUAL(obj[\"time\"].getValStr(), \"3600\");\n    BOOST_CHECK_EQUAL(obj[\"calories\"].getValStr(), \"12\");\n    BOOST_CHECK_EQUAL(obj[\"temperature\"].getValStr(), \"90.012\");\n    BOOST_CHECK_EQUAL(obj[\"cat1\"].getValStr(), \"9000\");\n    BOOST_CHECK_EQUAL(obj[\"cat2\"].getValStr(), \"12345\");\n\n    BOOST_CHECK_EQUAL(obj[\"nyuknyuknyuk\"].getValStr(), \"\");\n\n    BOOST_CHECK(obj.exists(\"age\"));\n    BOOST_CHECK(obj.exists(\"first\"));\n    BOOST_CHECK(obj.exists(\"last\"));\n    BOOST_CHECK(obj.exists(\"distance\"));\n    BOOST_CHECK(obj.exists(\"time\"));\n    BOOST_CHECK(obj.exists(\"calories\"));\n    BOOST_CHECK(obj.exists(\"temperature\"));\n    BOOST_CHECK(obj.exists(\"cat1\"));\n    BOOST_CHECK(obj.exists(\"cat2\"));\n\n    BOOST_CHECK(!obj.exists(\"nyuknyuknyuk\"));\n\n    std::map<std::string, UniValue::VType> objTypes;\n    objTypes[\"age\"] = UniValue::VNUM;\n    objTypes[\"first\"] = UniValue::VSTR;\n    objTypes[\"last\"] = UniValue::VSTR;\n    objTypes[\"distance\"] = UniValue::VNUM;\n    objTypes[\"time\"] = UniValue::VNUM;\n    objTypes[\"calories\"] = UniValue::VNUM;\n    objTypes[\"temperature\"] = UniValue::VNUM;\n    objTypes[\"cat1\"] = UniValue::VNUM;\n    objTypes[\"cat2\"] = UniValue::VNUM;\n    BOOST_CHECK(obj.checkObject(objTypes));\n\n    objTypes[\"cat2\"] = UniValue::VSTR;\n    BOOST_CHECK(!obj.checkObject(objTypes));\n\n    obj.clear();\n    BOOST_CHECK(obj.empty());\n    BOOST_CHECK_EQUAL(obj.size(), 0U);\n}\n\nstatic const char *json1 =\n\"[1.10000000,{\\\"key1\\\":\\\"str\\\\u0000\\\",\\\"key2\\\":800,\\\"key3\\\":{\\\"name\\\":\\\"martian http://test.com\\\"}}]\";\n\nBOOST_AUTO_TEST_CASE(univalue_readwrite)\n{\n    UniValue v;\n    BOOST_CHECK(v.read(json1));\n\n    std::string strJson1(json1);\n    BOOST_CHECK(v.read(strJson1));\n\n    BOOST_CHECK(v.isArray());\n    BOOST_CHECK_EQUAL(v.size(), 2U);\n\n    BOOST_CHECK_EQUAL(v[0].getValStr(), \"1.10000000\");\n\n    UniValue obj = v[1];\n    BOOST_CHECK(obj.isObject());\n    BOOST_CHECK_EQUAL(obj.size(), 3U);\n\n    BOOST_CHECK(obj[\"key1\"].isStr());\n    std::string correctValue(\"str\");\n    correctValue.push_back('\\0');\n    BOOST_CHECK_EQUAL(obj[\"key1\"].getValStr(), correctValue);\n    BOOST_CHECK(obj[\"key2\"].isNum());\n    BOOST_CHECK_EQUAL(obj[\"key2\"].getValStr(), \"800\");\n    BOOST_CHECK(obj[\"key3\"].isObject());\n\n    BOOST_CHECK_EQUAL(strJson1, v.write());\n\n    /* Check for (correctly reporting) a parsing error if the initial\n       JSON construct is followed by more stuff.  Note that whitespace\n       is, of course, exempt.  */\n\n    BOOST_CHECK(v.read(\"  {}\\n  \"));\n    BOOST_CHECK(v.isObject());\n    BOOST_CHECK(v.read(\"  []\\n  \"));\n    BOOST_CHECK(v.isArray());\n\n    BOOST_CHECK(!v.read(\"@{}\"));\n    BOOST_CHECK(!v.read(\"{} garbage\"));\n    BOOST_CHECK(!v.read(\"[]{}\"));\n    BOOST_CHECK(!v.read(\"{}[]\"));\n    BOOST_CHECK(!v.read(\"{} 42\"));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/util_tests.cpp",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util.h\"\n\n#include \"clientversion.h\"\n#include \"primitives/transaction.h\"\n#include \"sync.h\"\n#include \"util/strencodings.h\"\n#include \"util/moneystr.h\"\n#include \"util/time.h\"\n#include \"test/test.h\"\n\n#include <stdint.h>\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(util_criticalsection)\n{\n    RecursiveMutex cs;\n\n    do {\n        LOCK(cs);\n        break;\n\n        BOOST_ERROR(\"break was swallowed!\");\n    } while(0);\n\n    do {\n        TRY_LOCK(cs, lockTest);\n        if (lockTest)\n            break;\n\n        BOOST_ERROR(\"break was swallowed!\");\n    } while(0);\n}\n\nstatic const unsigned char ParseHex_expected[65] = {\n    0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,\n    0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,\n    0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,\n    0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,\n    0x5f\n};\nBOOST_AUTO_TEST_CASE(util_ParseHex)\n{\n    std::vector<unsigned char> result;\n    std::vector<unsigned char> expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected));\n    // Basic test vector\n    result = ParseHex(\"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f\");\n    BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());\n\n    // Spaces between bytes must be supported\n    result = ParseHex(\"12 34 56 78\");\n    BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);\n\n    // Leading space must be supported (used in CDBEnv::Salvage)\n    result = ParseHex(\" 89 34 56 78\");\n    BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);\n\n    // Stop parsing at invalid value\n    result = ParseHex(\"1234 invalid 1234\");\n    BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);\n}\n\nBOOST_AUTO_TEST_CASE(util_HexStr)\n{\n    BOOST_CHECK_EQUAL(\n        HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)),\n        \"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f\");\n\n    BOOST_CHECK_EQUAL(\n        HexStr(ParseHex_expected, ParseHex_expected + 5, true),\n        \"04 67 8a fd b0\");\n\n    BOOST_CHECK_EQUAL(\n        HexStr(ParseHex_expected, ParseHex_expected, true),\n        \"\");\n\n    std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);\n\n    BOOST_CHECK_EQUAL(\n        HexStr(ParseHex_vec, true),\n        \"04 67 8a fd b0\");\n}\n\n\nclass TestArgsManager : public ArgsManager\n{\npublic:\n    std::map<std::string, std::string>& GetMapArgs()\n    {\n        return mapArgs;\n    };\n    const std::map<std::string, std::vector<std::string> >& GetMapMultiArgs()\n    {\n        return mapMultiArgs;\n    };\n};\n\nBOOST_AUTO_TEST_CASE(util_ParseParameters)\n{\n    TestArgsManager testArgs;\n    const char *argv_test[] = {\"-ignored\", \"-a\", \"-b\", \"-ccc=argument\", \"-ccc=multiple\", \"f\", \"-d=e\"};\n\n    testArgs.ParseParameters(0, (char**)argv_test);\n    BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());\n\n    testArgs.ParseParameters(1, (char**)argv_test);\n    BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());\n\n    testArgs.ParseParameters(5, (char**)argv_test);\n    // expectation: -ignored is ignored (program name argument),\n    // -a, -b and -ccc end up in map, -d ignored because it is after\n    // a non-option argument (non-GNU option parsing)\n    BOOST_CHECK(testArgs.GetMapArgs().size() == 3 && testArgs.GetMapMultiArgs().size() == 3);\n    BOOST_CHECK(testArgs.IsArgSet(\"-a\") && testArgs.IsArgSet(\"-b\") && testArgs.IsArgSet(\"-ccc\")\n                && !testArgs.IsArgSet(\"f\") && !testArgs.IsArgSet(\"-d\"));\n    BOOST_CHECK(testArgs.GetMapMultiArgs().count(\"-a\") && testArgs.GetMapMultiArgs().count(\"-b\") && testArgs.GetMapMultiArgs().count(\"-ccc\")\n                && !testArgs.GetMapMultiArgs().count(\"f\") && !testArgs.GetMapMultiArgs().count(\"-d\"));\n\n    BOOST_CHECK(testArgs.GetMapArgs()[\"-a\"] == \"\" && testArgs.GetMapArgs()[\"-ccc\"] == \"multiple\");\n    BOOST_CHECK(testArgs.GetArgs(\"-ccc\").size() == 2);\n}\n\nBOOST_AUTO_TEST_CASE(util_GetArg)\n{\n    TestArgsManager testArgs;\n    testArgs.GetMapArgs().clear();\n    testArgs.GetMapArgs()[\"strtest1\"] = \"string...\";\n    // strtest2 undefined on purpose\n    testArgs.GetMapArgs()[\"inttest1\"] = \"12345\";\n    testArgs.GetMapArgs()[\"inttest2\"] = \"81985529216486895\";\n    // inttest3 undefined on purpose\n    testArgs.GetMapArgs()[\"booltest1\"] = \"\";\n    // booltest2 undefined on purpose\n    testArgs.GetMapArgs()[\"booltest3\"] = \"0\";\n    testArgs.GetMapArgs()[\"booltest4\"] = \"1\";\n\n    BOOST_CHECK_EQUAL(testArgs.GetArg(\"strtest1\", \"default\"), \"string...\");\n    BOOST_CHECK_EQUAL(testArgs.GetArg(\"strtest2\", \"default\"), \"default\");\n    BOOST_CHECK_EQUAL(testArgs.GetArg(\"inttest1\", -1), 12345);\n    BOOST_CHECK_EQUAL(testArgs.GetArg(\"inttest2\", -1), 81985529216486895LL);\n    BOOST_CHECK_EQUAL(testArgs.GetArg(\"inttest3\", -1), -1);\n    BOOST_CHECK_EQUAL(testArgs.GetBoolArg(\"booltest1\", false), true);\n    BOOST_CHECK_EQUAL(testArgs.GetBoolArg(\"booltest2\", false), false);\n    BOOST_CHECK_EQUAL(testArgs.GetBoolArg(\"booltest3\", false), false);\n    BOOST_CHECK_EQUAL(testArgs.GetBoolArg(\"booltest4\", false), true);\n}\n\nBOOST_AUTO_TEST_CASE(util_FormatMoney)\n{\n    BOOST_CHECK_EQUAL(FormatMoney(0), \"0.00\");\n    BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), \"12345.6789\");\n    BOOST_CHECK_EQUAL(FormatMoney(-COIN), \"-1.00\");\n\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), \"100000000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), \"10000000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), \"1000000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), \"100000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), \"10000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), \"1000.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*100), \"100.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN*10), \"10.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN), \"1.00\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/10), \"0.10\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/100), \"0.01\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), \"0.001\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), \"0.0001\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), \"0.00001\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), \"0.000001\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), \"0.0000001\");\n    BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), \"0.00000001\");\n}\n\nBOOST_AUTO_TEST_CASE(util_ParseMoney)\n{\n    CAmount ret = 0;\n    BOOST_CHECK(ParseMoney(\"0.0\", ret));\n    BOOST_CHECK_EQUAL(ret, 0);\n\n    BOOST_CHECK(ParseMoney(\"12345.6789\", ret));\n    BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789);\n\n    BOOST_CHECK(ParseMoney(\"100000000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*100000000);\n    BOOST_CHECK(ParseMoney(\"10000000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*10000000);\n    BOOST_CHECK(ParseMoney(\"1000000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*1000000);\n    BOOST_CHECK(ParseMoney(\"100000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*100000);\n    BOOST_CHECK(ParseMoney(\"10000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*10000);\n    BOOST_CHECK(ParseMoney(\"1000.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*1000);\n    BOOST_CHECK(ParseMoney(\"100.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*100);\n    BOOST_CHECK(ParseMoney(\"10.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN*10);\n    BOOST_CHECK(ParseMoney(\"1.00\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN);\n    BOOST_CHECK(ParseMoney(\"1\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN);\n    BOOST_CHECK(ParseMoney(\"0.1\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/10);\n    BOOST_CHECK(ParseMoney(\"0.01\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/100);\n    BOOST_CHECK(ParseMoney(\"0.001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/1000);\n    BOOST_CHECK(ParseMoney(\"0.0001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/10000);\n    BOOST_CHECK(ParseMoney(\"0.00001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/100000);\n    BOOST_CHECK(ParseMoney(\"0.000001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/1000000);\n    BOOST_CHECK(ParseMoney(\"0.0000001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/10000000);\n    BOOST_CHECK(ParseMoney(\"0.00000001\", ret));\n    BOOST_CHECK_EQUAL(ret, COIN/100000000);\n\n    // Attempted 63 bit overflow should fail\n    BOOST_CHECK(!ParseMoney(\"92233720368.54775808\", ret));\n\n    // Parsing negative amounts must fail\n    BOOST_CHECK(!ParseMoney(\"-1\", ret));\n}\n\nBOOST_AUTO_TEST_CASE(util_IsHex)\n{\n    BOOST_CHECK(IsHex(\"00\"));\n    BOOST_CHECK(IsHex(\"00112233445566778899aabbccddeeffAABBCCDDEEFF\"));\n    BOOST_CHECK(IsHex(\"ff\"));\n    BOOST_CHECK(IsHex(\"FF\"));\n\n    BOOST_CHECK(!IsHex(\"\"));\n    BOOST_CHECK(!IsHex(\"0\"));\n    BOOST_CHECK(!IsHex(\"a\"));\n    BOOST_CHECK(!IsHex(\"eleven\"));\n    BOOST_CHECK(!IsHex(\"00xx00\"));\n    BOOST_CHECK(!IsHex(\"0x0000\"));\n}\n\nBOOST_AUTO_TEST_CASE(util_seed_insecure_rand)\n{\n    SeedInsecureRand(true);\n    for (int mod=2;mod<11;mod++)\n    {\n        int mask = 1;\n        // Really rough binomial confidence approximation.\n        int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);\n        //mask is 2^ceil(log2(mod))-1\n        while(mask<mod-1)mask=(mask<<1)+1;\n\n        int count = 0;\n        //How often does it get a zero from the uniform range [0,mod)?\n        for (int i = 0; i < 10000; i++) {\n            uint32_t rval;\n            do{\n                rval=InsecureRand32()&mask;\n            }while(rval>=(uint32_t)mod);\n            count += rval==0;\n        }\n        BOOST_CHECK(count<=10000/mod+err);\n        BOOST_CHECK(count>=10000/mod-err);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(util_TimingResistantEqual)\n{\n    BOOST_CHECK(TimingResistantEqual(std::string(\"\"), std::string(\"\")));\n    BOOST_CHECK(!TimingResistantEqual(std::string(\"abc\"), std::string(\"\")));\n    BOOST_CHECK(!TimingResistantEqual(std::string(\"\"), std::string(\"abc\")));\n    BOOST_CHECK(!TimingResistantEqual(std::string(\"a\"), std::string(\"aa\")));\n    BOOST_CHECK(!TimingResistantEqual(std::string(\"aa\"), std::string(\"a\")));\n    BOOST_CHECK(TimingResistantEqual(std::string(\"abc\"), std::string(\"abc\")));\n    BOOST_CHECK(!TimingResistantEqual(std::string(\"abc\"), std::string(\"aba\")));\n}\n\n/* Test strprintf formatting directives.\n * Put a string before and after to ensure sanity of element sizes on stack. */\n#define B \"check_prefix\"\n#define E \"check_postfix\"\nBOOST_AUTO_TEST_CASE(strprintf_numbers)\n{\n    int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */\n    uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */\n    BOOST_CHECK(strprintf(\"%s %d %s\", B, s64t, E) == B\" -9223372036854775807 \" E);\n    BOOST_CHECK(strprintf(\"%s %u %s\", B, u64t, E) == B\" 18446744073709551615 \" E);\n    BOOST_CHECK(strprintf(\"%s %x %s\", B, u64t, E) == B\" ffffffffffffffff \" E);\n\n    size_t st = 12345678; /* unsigned size_t test value */\n    ssize_t sst = -12345678; /* signed size_t test value */\n    BOOST_CHECK(strprintf(\"%s %d %s\", B, sst, E) == B\" -12345678 \" E);\n    BOOST_CHECK(strprintf(\"%s %u %s\", B, st, E) == B\" 12345678 \" E);\n    BOOST_CHECK(strprintf(\"%s %x %s\", B, st, E) == B\" bc614e \" E);\n\n    ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */\n    ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */\n    BOOST_CHECK(strprintf(\"%s %d %s\", B, spt, E) == B\" -87654321 \" E);\n    BOOST_CHECK(strprintf(\"%s %u %s\", B, pt, E) == B\" 87654321 \" E);\n    BOOST_CHECK(strprintf(\"%s %x %s\", B, pt, E) == B\" 5397fb1 \" E);\n}\n#undef B\n#undef E\n\n/* Check for mingw/wine issue #3494\n * Remove this test before time.ctime(0xffffffff) == 'Sun Feb  7 07:28:15 2106'\n */\nBOOST_AUTO_TEST_CASE(gettime)\n{\n    BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseInt32)\n{\n    int32_t n;\n    // Valid values\n    BOOST_CHECK(ParseInt32(\"1234\", NULL));\n    BOOST_CHECK(ParseInt32(\"0\", &n) && n == 0);\n    BOOST_CHECK(ParseInt32(\"1234\", &n) && n == 1234);\n    BOOST_CHECK(ParseInt32(\"01234\", &n) && n == 1234); // no octal\n    BOOST_CHECK(ParseInt32(\"2147483647\", &n) && n == 2147483647);\n    BOOST_CHECK(ParseInt32(\"-2147483648\", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN\n    BOOST_CHECK(ParseInt32(\"-1234\", &n) && n == -1234);\n    // Invalid values\n    BOOST_CHECK(!ParseInt32(\"\", &n));\n    BOOST_CHECK(!ParseInt32(\" 1\", &n)); // no padding inside\n    BOOST_CHECK(!ParseInt32(\"1 \", &n));\n    BOOST_CHECK(!ParseInt32(\"1a\", &n));\n    BOOST_CHECK(!ParseInt32(\"aap\", &n));\n    BOOST_CHECK(!ParseInt32(\"0x1\", &n)); // no hex\n    BOOST_CHECK(!ParseInt32(\"0x1\", &n)); // no hex\n    const char test_bytes[] = {'1', 0, '1'};\n    std::string teststr(test_bytes, sizeof(test_bytes));\n    BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs\n    // Overflow and underflow\n    BOOST_CHECK(!ParseInt32(\"-2147483649\", NULL));\n    BOOST_CHECK(!ParseInt32(\"2147483648\", NULL));\n    BOOST_CHECK(!ParseInt32(\"-32482348723847471234\", NULL));\n    BOOST_CHECK(!ParseInt32(\"32482348723847471234\", NULL));\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseInt64)\n{\n    int64_t n;\n    // Valid values\n    BOOST_CHECK(ParseInt64(\"1234\", NULL));\n    BOOST_CHECK(ParseInt64(\"0\", &n) && n == 0LL);\n    BOOST_CHECK(ParseInt64(\"1234\", &n) && n == 1234LL);\n    BOOST_CHECK(ParseInt64(\"01234\", &n) && n == 1234LL); // no octal\n    BOOST_CHECK(ParseInt64(\"2147483647\", &n) && n == 2147483647LL);\n    BOOST_CHECK(ParseInt64(\"-2147483648\", &n) && n == -2147483648LL);\n    BOOST_CHECK(ParseInt64(\"9223372036854775807\", &n) && n == (int64_t)9223372036854775807);\n    BOOST_CHECK(ParseInt64(\"-9223372036854775808\", &n) && n == (int64_t)-9223372036854775807-1);\n    BOOST_CHECK(ParseInt64(\"-1234\", &n) && n == -1234LL);\n    // Invalid values\n    BOOST_CHECK(!ParseInt64(\"\", &n));\n    BOOST_CHECK(!ParseInt64(\" 1\", &n)); // no padding inside\n    BOOST_CHECK(!ParseInt64(\"1 \", &n));\n    BOOST_CHECK(!ParseInt64(\"1a\", &n));\n    BOOST_CHECK(!ParseInt64(\"aap\", &n));\n    BOOST_CHECK(!ParseInt64(\"0x1\", &n)); // no hex\n    const char test_bytes[] = {'1', 0, '1'};\n    std::string teststr(test_bytes, sizeof(test_bytes));\n    BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs\n    // Overflow and underflow\n    BOOST_CHECK(!ParseInt64(\"-9223372036854775809\", NULL));\n    BOOST_CHECK(!ParseInt64(\"9223372036854775808\", NULL));\n    BOOST_CHECK(!ParseInt64(\"-32482348723847471234\", NULL));\n    BOOST_CHECK(!ParseInt64(\"32482348723847471234\", NULL));\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseUInt32)\n{\n    uint32_t n;\n    // Valid values\n    BOOST_CHECK(ParseUInt32(\"1234\", NULL));\n    BOOST_CHECK(ParseUInt32(\"0\", &n) && n == 0);\n    BOOST_CHECK(ParseUInt32(\"1234\", &n) && n == 1234);\n    BOOST_CHECK(ParseUInt32(\"01234\", &n) && n == 1234); // no octal\n    BOOST_CHECK(ParseUInt32(\"2147483647\", &n) && n == 2147483647);\n    BOOST_CHECK(ParseUInt32(\"2147483648\", &n) && n == (uint32_t)2147483648);\n    BOOST_CHECK(ParseUInt32(\"4294967295\", &n) && n == (uint32_t)4294967295);\n    // Invalid values\n    BOOST_CHECK(!ParseUInt32(\"\", &n));\n    BOOST_CHECK(!ParseUInt32(\" 1\", &n)); // no padding inside\n    BOOST_CHECK(!ParseUInt32(\" -1\", &n));\n    BOOST_CHECK(!ParseUInt32(\"1 \", &n));\n    BOOST_CHECK(!ParseUInt32(\"1a\", &n));\n    BOOST_CHECK(!ParseUInt32(\"aap\", &n));\n    BOOST_CHECK(!ParseUInt32(\"0x1\", &n)); // no hex\n    BOOST_CHECK(!ParseUInt32(\"0x1\", &n)); // no hex\n    const char test_bytes[] = {'1', 0, '1'};\n    std::string teststr(test_bytes, sizeof(test_bytes));\n    BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs\n    // Overflow and underflow\n    BOOST_CHECK(!ParseUInt32(\"-2147483648\", &n));\n    BOOST_CHECK(!ParseUInt32(\"4294967296\", &n));\n    BOOST_CHECK(!ParseUInt32(\"-1234\", &n));\n    BOOST_CHECK(!ParseUInt32(\"-32482348723847471234\", NULL));\n    BOOST_CHECK(!ParseUInt32(\"32482348723847471234\", NULL));\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseUInt64)\n{\n    uint64_t n;\n    // Valid values\n    BOOST_CHECK(ParseUInt64(\"1234\", NULL));\n    BOOST_CHECK(ParseUInt64(\"0\", &n) && n == 0LL);\n    BOOST_CHECK(ParseUInt64(\"1234\", &n) && n == 1234LL);\n    BOOST_CHECK(ParseUInt64(\"01234\", &n) && n == 1234LL); // no octal\n    BOOST_CHECK(ParseUInt64(\"2147483647\", &n) && n == 2147483647LL);\n    BOOST_CHECK(ParseUInt64(\"9223372036854775807\", &n) && n == 9223372036854775807ULL);\n    BOOST_CHECK(ParseUInt64(\"9223372036854775808\", &n) && n == 9223372036854775808ULL);\n    BOOST_CHECK(ParseUInt64(\"18446744073709551615\", &n) && n == 18446744073709551615ULL);\n    // Invalid values\n    BOOST_CHECK(!ParseUInt64(\"\", &n));\n    BOOST_CHECK(!ParseUInt64(\" 1\", &n)); // no padding inside\n    BOOST_CHECK(!ParseUInt64(\" -1\", &n));\n    BOOST_CHECK(!ParseUInt64(\"1 \", &n));\n    BOOST_CHECK(!ParseUInt64(\"1a\", &n));\n    BOOST_CHECK(!ParseUInt64(\"aap\", &n));\n    BOOST_CHECK(!ParseUInt64(\"0x1\", &n)); // no hex\n    const char test_bytes[] = {'1', 0, '1'};\n    std::string teststr(test_bytes, sizeof(test_bytes));\n    BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs\n    // Overflow and underflow\n    BOOST_CHECK(!ParseUInt64(\"-9223372036854775809\", NULL));\n    BOOST_CHECK(!ParseUInt64(\"18446744073709551616\", NULL));\n    BOOST_CHECK(!ParseUInt64(\"-32482348723847471234\", NULL));\n    BOOST_CHECK(!ParseUInt64(\"-2147483648\", &n));\n    BOOST_CHECK(!ParseUInt64(\"-9223372036854775808\", &n));\n    BOOST_CHECK(!ParseUInt64(\"-1234\", &n));\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseDouble)\n{\n    double n;\n    // Valid values\n    BOOST_CHECK(ParseDouble(\"1234\", NULL));\n    BOOST_CHECK(ParseDouble(\"0\", &n) && n == 0.0);\n    BOOST_CHECK(ParseDouble(\"1234\", &n) && n == 1234.0);\n    BOOST_CHECK(ParseDouble(\"01234\", &n) && n == 1234.0); // no octal\n    BOOST_CHECK(ParseDouble(\"2147483647\", &n) && n == 2147483647.0);\n    BOOST_CHECK(ParseDouble(\"-2147483648\", &n) && n == -2147483648.0);\n    BOOST_CHECK(ParseDouble(\"-1234\", &n) && n == -1234.0);\n    BOOST_CHECK(ParseDouble(\"1e6\", &n) && n == 1e6);\n    BOOST_CHECK(ParseDouble(\"-1e6\", &n) && n == -1e6);\n    // Invalid values\n    BOOST_CHECK(!ParseDouble(\"\", &n));\n    BOOST_CHECK(!ParseDouble(\" 1\", &n)); // no padding inside\n    BOOST_CHECK(!ParseDouble(\"1 \", &n));\n    BOOST_CHECK(!ParseDouble(\"1a\", &n));\n    BOOST_CHECK(!ParseDouble(\"aap\", &n));\n    BOOST_CHECK(!ParseDouble(\"0x1\", &n)); // no hex\n    const char test_bytes[] = {'1', 0, '1'};\n    std::string teststr(test_bytes, sizeof(test_bytes));\n    BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs\n    // Overflow and underflow\n    BOOST_CHECK(!ParseDouble(\"-1e10000\", NULL));\n    BOOST_CHECK(!ParseDouble(\"1e10000\", NULL));\n}\n\nBOOST_AUTO_TEST_CASE(test_FormatParagraph)\n{\n    BOOST_CHECK_EQUAL(FormatParagraph(\"\", 79, 0), \"\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"test\", 79, 0), \"test\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\" test\", 79, 0), \" test\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"test test\", 79, 0), \"test test\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"test test\", 4, 0), \"test\\ntest\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"testerde test\", 4, 0), \"testerde\\ntest\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"test test\", 4, 4), \"test\\n    test\");\n\n    // Make sure we don't indent a fully-new line following a too-long line ending\n    BOOST_CHECK_EQUAL(FormatParagraph(\"test test\\nabc\", 4, 4), \"test\\n    test\\nabc\");\n\n    BOOST_CHECK_EQUAL(FormatParagraph(\"This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length until it gets here\", 79), \"This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length\\nuntil it gets here\");\n\n    // Test wrap length is exact\n    BOOST_CHECK_EQUAL(FormatParagraph(\"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p\", 79), \"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\\nf g h i j k l m n o p\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"x\\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p\", 79), \"x\\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\\nf g h i j k l m n o p\");\n    // Indent should be included in length of lines\n    BOOST_CHECK_EQUAL(FormatParagraph(\"x\\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg h i j k\", 79, 4), \"x\\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\\n    f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg\\n    h i j k\");\n\n    BOOST_CHECK_EQUAL(FormatParagraph(\"This is a very long test string. This is a second sentence in the very long test string.\", 79), \"This is a very long test string. This is a second sentence in the very long\\ntest string.\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"This is a very long test string.\\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.\", 79), \"This is a very long test string.\\nThis is a second sentence in the very long test string. This is a third\\nsentence in the very long test string.\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"This is a very long test string.\\n\\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.\", 79), \"This is a very long test string.\\n\\nThis is a second sentence in the very long test string. This is a third\\nsentence in the very long test string.\");\n    BOOST_CHECK_EQUAL(FormatParagraph(\"Testing that normal newlines do not get indented.\\nLike here.\", 79), \"Testing that normal newlines do not get indented.\\nLike here.\");\n}\n\nBOOST_AUTO_TEST_CASE(test_FormatSubVersion)\n{\n    std::vector<std::string> comments;\n    comments.push_back(std::string(\"comment1\"));\n    std::vector<std::string> comments2;\n    comments2.push_back(std::string(\"comment1\"));\n    comments2.push_back(SanitizeString(std::string(\"Comment2; .,_?@-; !\\\"#$%&'()*+/<=>[]\\\\^`{|}~\"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014\n    BOOST_CHECK_EQUAL(FormatSubVersion(\"Test\", 99900, std::vector<std::string>()),std::string(\"/Test:0.9.99/\"));\n    BOOST_CHECK_EQUAL(FormatSubVersion(\"Test\", 99900, comments),std::string(\"/Test:0.9.99(comment1)/\"));\n    BOOST_CHECK_EQUAL(FormatSubVersion(\"Test\", 99900, comments2),std::string(\"/Test:0.9.99(comment1; Comment2; .,_?@-; )/\"));\n}\n\nBOOST_AUTO_TEST_CASE(test_ParseFixedPoint)\n{\n    int64_t amount = 0;\n    BOOST_CHECK(ParseFixedPoint(\"0\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 0LL);\n    BOOST_CHECK(ParseFixedPoint(\"1\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 100000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"0.0\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 0LL);\n    BOOST_CHECK(ParseFixedPoint(\"-0.1\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, -10000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"1.1\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 110000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"1.10000000000000000\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 110000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"1.1e1\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 1100000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"1.1e-1\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 11000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"1000\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 100000000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"-1000\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, -100000000000LL);\n    BOOST_CHECK(ParseFixedPoint(\"0.00000001\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 1LL);\n    BOOST_CHECK(ParseFixedPoint(\"0.0000000100000000\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 1LL);\n    BOOST_CHECK(ParseFixedPoint(\"-0.00000001\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, -1LL);\n    BOOST_CHECK(ParseFixedPoint(\"1000000000.00000001\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 100000000000000001LL);\n    BOOST_CHECK(ParseFixedPoint(\"9999999999.99999999\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, 999999999999999999LL);\n    BOOST_CHECK(ParseFixedPoint(\"-9999999999.99999999\", 8, &amount));\n    BOOST_CHECK_EQUAL(amount, -999999999999999999LL);\n\n    BOOST_CHECK(!ParseFixedPoint(\"\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"a-1000\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-a1000\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-1000a\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-01000\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"00.1\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\".1\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"--0.1\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"0.000000001\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-0.000000001\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"0.00000001000000001\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-10000000000.00000000\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"10000000000.00000000\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-10000000000.00000001\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"10000000000.00000001\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-10000000000.00000009\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"10000000000.00000009\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-99999999999.99999999\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"99999909999.09999999\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"92233720368.54775807\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"92233720368.54775808\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-92233720368.54775808\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"-92233720368.54775809\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"1.1e\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"1.1e-\", 8, &amount));\n    BOOST_CHECK(!ParseFixedPoint(\"1.\", 8, &amount));\n}\n\nBOOST_AUTO_TEST_CASE(util_Base10Checksum)\n{\n    // test valid checksums\n    for (int i = 0; i < 30000; i++)\n    {\n        int encoded = Base10ChecksumEncode(i);\n        int decoded=-1;\n        BOOST_CHECK(Base10ChecksumDecode(encoded, &decoded));\n        BOOST_CHECK(decoded == i);\n    }\n\n    // test a range of number, which should mostly fail\n    // note that exactly 1% can be decoded\n    // there is almost no chance that a typo will result in a number that can be decoded\n    int fail = 0;\n    for (int i = 0; i < 30000; i++)\n    {\n        if (Base10ChecksumDecode(i))\n            fail++;\n    }\n    BOOST_CHECK(fail == 300);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/test/versionbits_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"chain.h\"\n#include \"versionbits.h\"\n#include \"test/test.h\"\n#include \"chainparams.h\"\n#include \"validation/validation.h\"\n#include \"consensus/params.h\"\n\n#include <boost/test/unit_test.hpp>\n\nstatic std::map<uint256, CBlockIndex*> tempBlockIndex;\n\n/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */\nint32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }\n\nstatic const Consensus::Params paramsDummy = Consensus::Params();\n\nclass TestConditionChecker : public AbstractThresholdConditionChecker\n{\nprivate:\n    mutable ThresholdConditionCache cache;\n\npublic:\n    int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); }\n    int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); }\n    int Period(const Consensus::Params& params) const { return 1000; }\n    int Threshold(const Consensus::Params& params) const { return 900; }\n    bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }\n\n    ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }\n    int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }\n};\n\n#define CHECKERS 6\nclass VersionBitsTester\n{\n    // A fake blockchain\n    std::vector<CBlockIndex*> vpblock;\n\n    // 6 independent checkers for the same bit.\n    // The first one performs all checks, the second only 50%, the third only 25%, etc...\n    // This is to test whether lack of cached information leads to the same results.\n    TestConditionChecker checker[CHECKERS];\n\n    // Test counter (to identify failures)\n    int num;\n\npublic:\n    VersionBitsTester() : num(0) {}\n\n    VersionBitsTester& Reset() {\n        for (unsigned int i = 0; i < vpblock.size(); i++) {\n            delete vpblock[i];\n        }\n        for (unsigned int  i = 0; i < CHECKERS; i++) {\n            checker[i] = TestConditionChecker();\n        }\n        vpblock.clear();\n        return *this;\n    }\n\n    ~VersionBitsTester() {\n         Reset();\n    }\n\n    VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) {\n        while (vpblock.size() < height) {\n            CBlockIndex* pindex = new CBlockIndex();\n            // Set the block up with a random hash as versionbits needs this to function correctly.\n            auto insertIter = tempBlockIndex.insert(std::pair(GetRandHash(), pindex)).first;\n            pindex->phashBlock = &((*insertIter).first);\n            pindex->nHeight = vpblock.size();\n            pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL;\n            pindex->nTime = nTime;\n            pindex->nVersion = nVersion;\n            pindex->BuildSkip();\n            vpblock.push_back(pindex);\n        }\n        return *this;\n    }\n\n    VersionBitsTester& TestStateSinceHeight(int height) {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? NULL : vpblock.back()) == height, strprintf(\"Test %i for StateSinceHeight\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    VersionBitsTester& TestDefined() {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf(\"Test %i for DEFINED\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    VersionBitsTester& TestStarted() {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf(\"Test %i for STARTED\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    VersionBitsTester& TestLockedIn() {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf(\"Test %i for LOCKED_IN\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    VersionBitsTester& TestActive() {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf(\"Test %i for ACTIVE\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    VersionBitsTester& TestFailed() {\n        for (int i = 0; i < CHECKERS; i++) {\n            if (InsecureRandBits(i) == 0) {\n                BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf(\"Test %i for FAILED\", num));\n            }\n        }\n        num++;\n        return *this;\n    }\n\n    CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; }\n};\n\nBOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup)\n\nBOOST_AUTO_TEST_CASE(versionbits_test)\n{\n    for (int i = 0; i < 64; i++) {\n        // DEFINED -> FAILED\n        VersionBitsTester().TestDefined().TestStateSinceHeight(0)\n                           .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)\n                           .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)\n                           .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)\n                           .Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0)\n                           .Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000)\n                           .Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000)\n                           .Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000)\n                           .Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000)\n                           .Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000)\n                           .Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000)\n\n        // DEFINED -> STARTED -> FAILED\n                           .Reset().TestDefined().TestStateSinceHeight(0)\n                           .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined\n                           .Mine(2000, TestTime(10000), 0x100).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period\n                           .Mine(2051, TestTime(10010), 0).TestStarted().TestStateSinceHeight(2000) // 51 old blocks\n                           .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 899 new blocks\n                           .Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)\n                           .Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)\n\n        // DEFINED -> STARTED -> FAILED while threshold reached\n                           .Reset().TestDefined().TestStateSinceHeight(0)\n                           .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined\n                           .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period\n                           .Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks\n                           .Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)\n                           .Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000)\n                           .Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000)\n                           .Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000)\n                           .Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000)\n\n        // DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE\n                           .Reset().TestDefined()\n                           .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined\n                           .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period\n                           .Mine(2050, TestTime(10010), 0x200).TestStarted().TestStateSinceHeight(2000) // 50 old blocks\n                           .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 900 new blocks\n                           .Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks\n                           .Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000)\n                           .Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)\n                           .Mine(4000, TestTime(30002), 0).TestActive().TestStateSinceHeight(4000)\n                           .Mine(14333, TestTime(30003), 0).TestActive().TestStateSinceHeight(4000)\n                           .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000)\n\n        // DEFINED multiple periods -> STARTED multiple periods -> FAILED\n                           .Reset().TestDefined().TestStateSinceHeight(0)\n                           .Mine(999, TestTime(999), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(1000, TestTime(1000), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(2000, TestTime(2000), 0).TestDefined().TestStateSinceHeight(0)\n                           .Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)\n                           .Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)\n                           .Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)\n                           .Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000)\n                           .Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000);\n    }\n\n    // Sanity checks of version bit deployments\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    const Consensus::Params &mainnetParams = chainParams->GetConsensus();\n    for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {\n        uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i);\n        // Make sure that no deployment tries to set an invalid bit.\n        BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);\n\n        // Verify that the deployment windows of different deployment using the\n        // same bit are disjoint.\n        // This test may need modification at such time as a new deployment\n        // is proposed that reuses the bit of an activated soft fork, before the\n        // end time of that soft fork.  (Alternatively, the end time of that\n        // activated soft fork could be later changed to be earlier to avoid\n        // overlap.)\n        for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {\n            if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) {\n                BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||\n                        mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(versionbits_computeblockversion)\n{\n    // Check that ComputeBlockVersion will set the appropriate bit correctly\n    // on mainnet.\n    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);\n    const Consensus::Params &mainnetParams = chainParams->GetConsensus();\n\n    // Use the TESTDUMMY deployment for testing purposes.\n    int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit;\n    int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime;\n    int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout;\n\n    assert(nStartTime < nTimeout);\n\n    // In the first chain, test that the bit is set by CBV until it has failed.\n    // In the second chain, test the bit is set by CBV while STARTED and\n    // LOCKED-IN, and then no longer set while ACTIVE.\n    VersionBitsTester firstChain, secondChain;\n\n    // Start generating blocks before nStartTime\n    int64_t nTime = nStartTime - 1;\n\n    // Before MedianTimePast of the chain has crossed nStartTime, the bit\n    // should not be set.\n    CBlockIndex *lastBlock = NULL;\n    lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);\n\n    // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet.\n    for (int i=1; i<2012; i++) {\n        lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n        // This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens\n        // to be 4, and the bit we're testing happens to be bit 28.\n        BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);\n    }\n    // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so\n    // CBV should still not yet set the bit.\n    nTime = nStartTime;\n    for (int i=2012; i<=2016; i++) {\n        lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n        BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);\n    }\n\n    // Advance to the next period and transition to STARTED,\n    lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    // so ComputeBlockVersion should now set the bit,\n    BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n    // and should also be using the VERSIONBITS_TOP_BITS.\n    BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);\n\n    // Check that ComputeBlockVersion will set the bit until nTimeout\n    nTime += 600;\n    int blocksToMine = 4032; // test blocks for up to 2 time periods\n    int nHeight = 6048;\n    // These blocks are all before nTimeout is reached.\n    while (nTime < nTimeout && blocksToMine > 0) {\n        lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n        BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n        BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);\n        blocksToMine--;\n        nTime += 600;\n        nHeight += 1;\n    }\n\n    nTime = nTimeout;\n    // FAILED is only triggered at the end of a period, so CBV should be setting\n    // the bit until the period transition.\n    for (int i=0; i<2015; i++) {\n        lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n        BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n        nHeight += 1;\n    }\n    // The next block should trigger no longer setting the bit.\n    lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);\n\n    // On a new chain:\n    // verify that the bit will be set after lock-in, and then stop being set\n    // after activation.\n    nTime = nStartTime;\n\n    // Mine one period worth of blocks, and check that the bit will be on for the\n    // next period.\n    lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n\n    // Mine another period worth of blocks, signaling the new bit.\n    lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();\n    // After one period of setting the bit on each block, it should have locked in.\n    // We keep setting the bit for one more period though, until activation.\n    BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n\n    // Now check that we keep mining the block until the end of this period, and\n    // then stop at the beginning of the next period.\n    lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);\n    lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();\n    BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);\n\n    // Finally, verify that after a soft fork has activated, CBV no longer uses\n    // VERSIONBITS_LAST_OLD_BLOCK_VERSION.\n    //BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);\n\n    //fixme: (PHASE5) - Add unit tests for new version bits functionality here.\n}\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/threadinterrupt.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"threadinterrupt.h\"\n\nCThreadInterrupt::operator bool() const\n{\n    return flag.load(std::memory_order_acquire);\n}\n\nvoid CThreadInterrupt::reset()\n{\n    flag.store(false, std::memory_order_release);\n}\n\nvoid CThreadInterrupt::operator()()\n{\n    {\n        std::unique_lock<std::mutex> lock(mut);\n        flag.store(true, std::memory_order_release);\n    }\n    cond.notify_all();\n}\n\nbool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time)\n{\n    std::unique_lock<std::mutex> lock(mut);\n    return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); });\n}\n\nbool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time)\n{\n    return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));\n}\n\nbool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time)\n{\n    return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));\n}\n"
  },
  {
    "path": "src/threadinterrupt.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef THREADINTERRUPT_H\n#define THREADINTERRUPT_H\n\n#include <atomic>\n#include <chrono>\n#include <condition_variable>\n#include <mutex>\n\n/*\n    A helper class for interruptible sleeps. Calling operator() will interrupt\n    any current sleep, and after that point operator bool() will return true\n    until reset.\n*/\nclass CThreadInterrupt\n{\npublic:\n    explicit operator bool() const;\n    void operator()();\n    void reset();\n    bool sleep_for(std::chrono::milliseconds rel_time);\n    bool sleep_for(std::chrono::seconds rel_time);\n    bool sleep_for(std::chrono::minutes rel_time);\n\nprivate:\n    std::condition_variable cond;\n    std::mutex mut;\n    std::atomic<bool> flag;\n};\n\n#endif\n"
  },
  {
    "path": "src/threadsafety.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef THREADSAFETY_H\n#define THREADSAFETY_H\n\n#ifdef __clang__\n// TL;DR Add GUARDED_BY(mutex) to member variables. The others are\n// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo);\n//\n// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety\n// for documentation.  The clang compiler can do advanced static analysis\n// of locking when given the -Wthread-safety option.\n#define LOCKABLE __attribute__((lockable))\n#define SCOPED_LOCKABLE __attribute__((scoped_lockable))\n#define GUARDED_BY(x) __attribute__((guarded_by(x)))\n#define GUARDED_VAR __attribute__((guarded_var))\n#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))\n#define PT_GUARDED_VAR __attribute__((pt_guarded_var))\n#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))\n#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))\n#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))\n#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))\n#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))\n#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))\n#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))\n#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))\n#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))\n#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))\n#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))\n#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))\n#else\n#define LOCKABLE\n#define SCOPED_LOCKABLE\n#define GUARDED_BY(x)\n#define GUARDED_VAR\n#define PT_GUARDED_BY(x)\n#define PT_GUARDED_VAR\n#define ACQUIRED_AFTER(...)\n#define ACQUIRED_BEFORE(...)\n#define EXCLUSIVE_LOCK_FUNCTION(...)\n#define SHARED_LOCK_FUNCTION(...)\n#define EXCLUSIVE_TRYLOCK_FUNCTION(...)\n#define SHARED_TRYLOCK_FUNCTION(...)\n#define UNLOCK_FUNCTION(...)\n#define LOCK_RETURNED(x)\n#define LOCKS_EXCLUDED(...)\n#define EXCLUSIVE_LOCKS_REQUIRED(...)\n#define SHARED_LOCKS_REQUIRED(...)\n#define NO_THREAD_SAFETY_ANALYSIS\n#endif // __GNUC__\n\n#endif\n"
  },
  {
    "path": "src/timedata.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"timedata.h\"\n\n#include \"netaddress.h\"\n#include \"sync.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"warnings.h\"\n\n\n\nstatic RecursiveMutex cs_nTimeOffset;\nstatic int64_t nTimeOffset = 0;\n\n/**\n * \"Never go to sea with two chronometers; take one or three.\"\n * Our three time sources are:\n *  - System clock\n *  - Median of other nodes clocks\n *  - The user (asking the user to fix the system clock if the first two disagree)\n */\nint64_t GetTimeOffset()\n{\n    LOCK(cs_nTimeOffset);\n    return nTimeOffset;\n}\n\nint64_t GetAdjustedTime()\n{\n    return GetTime() + GetTimeOffset();\n}\n\nstatic int64_t abs64(int64_t n)\n{\n    return (n >= 0 ? n : -n);\n}\n\n#define TIMEDATA_MAX_SAMPLES 200\n\nvoid AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)\n{\n    LOCK(cs_nTimeOffset);\n    // Ignore duplicates\n    static std::set<CNetAddr> setKnown;\n    if (setKnown.size() == TIMEDATA_MAX_SAMPLES)\n        return;\n    if (!setKnown.insert(ip).second)\n        return;\n\n    // Add data\n    static CMedianFilter<int64_t> vTimeOffsets(TIMEDATA_MAX_SAMPLES, 0);\n    vTimeOffsets.input(nOffsetSample);\n    LogPrint(BCLog::NET,\"added time data, samples %d, offset %+d (%+d minutes)\\n\", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);\n\n    // There is a known issue here (see issue #4521):\n    //\n    // - The structure vTimeOffsets contains up to 200 elements, after which\n    // any new element added to it will not increase its size, replacing the\n    // oldest element.\n    //\n    // - The condition to update nTimeOffset includes checking whether the\n    // number of elements in vTimeOffsets is odd, which will never happen after\n    // there are 200 elements.\n    //\n    // But in this case the 'bug' is protective against some attacks, and may\n    // actually explain why we've never seen attacks which manipulate the\n    // clock offset.\n    //\n    // So we should hold off on fixing this and clean it up as part of\n    // a timing cleanup that strengthens it in a number of other ways.\n    //\n    if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)\n    {\n        int64_t nMedian = vTimeOffsets.median();\n        std::vector<int64_t> vSorted = vTimeOffsets.sorted();\n        // Only let other nodes change our time by so much\n        if (abs64(nMedian) <= std::max<int64_t>(0, GetArg(\"-maxtimeadjustment\", DEFAULT_MAX_TIME_ADJUSTMENT)))\n        {\n            nTimeOffset = nMedian;\n        }\n        else\n        {\n            nTimeOffset = 0;\n\n            static bool fDone;\n            if (!fDone)\n            {\n                // If nobody has a time different than ours but within 5 minutes of ours, give a warning\n                bool fMatch = false;\n                for(int64_t nOffset : vSorted)\n                    if (nOffset != 0 && abs64(nOffset) < 5 * 60)\n                        fMatch = true;\n\n                if (!fMatch)\n                {\n                    fDone = true;\n                    std::string strMessage = strprintf(_(\"Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.\"), _(PACKAGE_NAME));\n                    SetMiscWarning(strMessage);\n                    uiInterface.ThreadSafeMessageBox(strMessage, \"\", CClientUIInterface::MSG_WARNING);\n                }\n            }\n        }\n\n        if (LogAcceptCategory(BCLog::NET)) {\n            for(int64_t n : vSorted) {\n                LogPrint(BCLog::NET, \"%+d  \", n);\n            }\n            LogPrint(BCLog::NET, \"|  \");\n\n            LogPrint(BCLog::NET, \"nTimeOffset = %+d  (%+d minutes)\\n\", nTimeOffset, nTimeOffset/60);\n        }\n    }\n}\n"
  },
  {
    "path": "src/timedata.h",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef TIMEDATA_H\n#define TIMEDATA_H\n\n#include <algorithm>\n#include <assert.h>\n#include <stdint.h>\n#include <vector>\n\nstatic const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 10;\n\nclass CNetAddr;\n\n/** \n * Median filter over a stream of values.\n * Returns the median of the last N numbers\n */\ntemplate <typename T>\nclass CMedianFilter\n{\nprivate:\n    std::vector<T> vValues;\n    std::vector<T> vSorted;\n    unsigned int nSize;\n\npublic:\n    CMedianFilter(unsigned int _size, T initial_value) : nSize(_size)\n    {\n        vValues.reserve(_size);\n        vValues.push_back(initial_value);\n        vSorted = vValues;\n    }\n\n    void input(T value)\n    {\n        if (vValues.size() == nSize) {\n            vValues.erase(vValues.begin());\n        }\n        vValues.push_back(value);\n\n        vSorted.resize(vValues.size());\n        std::copy(vValues.begin(), vValues.end(), vSorted.begin());\n        std::sort(vSorted.begin(), vSorted.end());\n    }\n\n    T median() const\n    {\n        int vSortedSize = vSorted.size();\n        assert(vSortedSize > 0);\n        if (vSortedSize & 1) // Odd number of elements\n        {\n            return vSorted[vSortedSize / 2];\n        } else // Even number of elements\n        {\n            return (vSorted[vSortedSize / 2 - 1] + vSorted[vSortedSize / 2]) / 2;\n        }\n    }\n\n    int size() const\n    {\n        return vValues.size();\n    }\n\n    std::vector<T> sorted() const\n    {\n        return vSorted;\n    }\n};\n\n/** Functions to keep track of adjusted P2P time */\nint64_t GetTimeOffset();\nint64_t GetAdjustedTime();\nvoid AddTimeData(const CNetAddr& ip, int64_t nTime);\n\n#endif\n"
  },
  {
    "path": "src/tinyformat.h",
    "content": "// tinyformat.h\n// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]\n//\n// Boost Software License - Version 1.0\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n\n//------------------------------------------------------------------------------\n// Tinyformat: A minimal type safe printf replacement\n//\n// tinyformat.h is a type safe printf replacement library in a single C++\n// header file.  Design goals include:\n//\n// * Type safety and extensibility for user defined types.\n// * C99 printf() compatibility, to the extent possible using std::ostream\n// * Simplicity and minimalism.  A single header file to include and distribute\n//   with your projects.\n// * Augment rather than replace the standard stream formatting mechanism\n// * C++98 support, with optional C++11 niceties\n//\n//\n// Main interface example usage\n// ----------------------------\n//\n// To print a date to std::cout:\n//\n//   std::string weekday = \"Wednesday\";\n//   const char* month = \"July\";\n//   size_t day = 27;\n//   long hour = 14;\n//   int min = 44;\n//\n//   tfm::printf(\"%s, %s %d, %.2d:%.2d\\n\", weekday, month, day, hour, min);\n//\n// The strange types here emphasize the type safety of the interface; it is\n// possible to print a std::string using the \"%s\" conversion, and a\n// size_t using the \"%d\" conversion.  A similar result could be achieved\n// using either of the tfm::format() functions.  One prints on a user provided\n// stream:\n//\n//   tfm::format(std::cerr, \"%s, %s %d, %.2d:%.2d\\n\",\n//               weekday, month, day, hour, min);\n//\n// The other returns a std::string:\n//\n//   std::string date = tfm::format(\"%s, %s %d, %.2d:%.2d\\n\",\n//                                  weekday, month, day, hour, min);\n//   std::cout << date;\n//\n// These are the three primary interface functions.  There is also a\n// convenience function printfln() which appends a newline to the usual result\n// of printf() for super simple logging.\n//\n//\n// User defined format functions\n// -----------------------------\n//\n// Simulating variadic templates in C++98 is pretty painful since it requires\n// writing out the same function for each desired number of arguments.  To make\n// this bearable tinyformat comes with a set of macros which are used\n// internally to generate the API, but which may also be used in user code.\n//\n// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and\n// TINYFORMAT_PASSARGS(n) will generate a list of n argument types,\n// type/name pairs and argument names respectively when called with an integer\n// n between 1 and 16.  We can use these to define a macro which generates the\n// desired user defined function with n arguments.  To generate all 16 user\n// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM.  For an\n// example, see the implementation of printf() at the end of the source file.\n//\n// Sometimes it's useful to be able to pass a list of format arguments through\n// to a non-template function.  The FormatList class is provided as a way to do\n// this by storing the argument list in a type-opaque way.  Continuing the\n// example from above, we construct a FormatList using makeFormatList():\n//\n//   FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min);\n//\n// The format list can now be passed into any non-template function and used\n// via a call to the vformat() function:\n//\n//   tfm::vformat(std::cout, \"%s, %s %d, %.2d:%.2d\\n\", formatList);\n//\n//\n// Additional API information\n// --------------------------\n//\n// Error handling: Define TINYFORMAT_ERROR to customize the error handling for\n// format strings which are unsupported or have the wrong number of format\n// specifiers (calls assert() by default).\n//\n// User defined types: Uses operator<< for user defined types by default.\n// Overload formatValue() for more control.\n\n\n#ifndef TINYFORMAT_H_INCLUDED\n#define TINYFORMAT_H_INCLUDED\n\nnamespace tinyformat {}\n//------------------------------------------------------------------------------\n// Config section.  Customize to your liking!\n\n// Namespace alias to encourage brevity\nnamespace tfm = tinyformat;\n\n// Error handling; calls assert() by default.\n#define TINYFORMAT_ERROR(reasonString) throw tinyformat::format_error(reasonString)\n\n// Define for C++11 variadic templates which make the code shorter & more\n// general.  If you don't define this, C++11 support is autodetected below.\n#define TINYFORMAT_USE_VARIADIC_TEMPLATES\n\n\n//------------------------------------------------------------------------------\n// Implementation details.\n#include <algorithm>\n#include <cassert>\n#include <iostream>\n#include <sstream>\n#include <stdexcept>\n\n#ifndef TINYFORMAT_ERROR\n#   define TINYFORMAT_ERROR(reason) assert(0 && reason)\n#endif\n\n#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)\n#   ifdef __GXX_EXPERIMENTAL_CXX0X__\n#       define TINYFORMAT_USE_VARIADIC_TEMPLATES\n#   endif\n#endif\n\n#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201\n//  std::showpos is broken on old libstdc++ as provided with OSX.  See\n//  http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html\n#   define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND\n#endif\n\n#ifdef __APPLE__\n// Workaround OSX linker warning: xcode uses different default symbol\n// visibilities for static libs vs executables (see issue #25)\n#   define TINYFORMAT_HIDDEN __attribute__((visibility(\"hidden\")))\n#else\n#   define TINYFORMAT_HIDDEN\n#endif\n\nnamespace tinyformat {\n\nclass format_error: public std::runtime_error\n{\npublic:\n    format_error(const std::string &what): std::runtime_error(what) {\n    }\n};\n\n//------------------------------------------------------------------------------\nnamespace detail {\n\n// Test whether type T1 is convertible to type T2\ntemplate <typename T1, typename T2>\nstruct is_convertible\n{\n    private:\n        // two types of different size\n        struct fail { char dummy[2]; };\n        struct succeed { char dummy; };\n        // Try to convert a T1 to a T2 by plugging into tryConvert\n        static fail tryConvert(...);\n        static succeed tryConvert(const T2&);\n        static const T1& makeT1();\n    public:\n#       ifdef _MSC_VER\n        // Disable spurious loss of precision warnings in tryConvert(makeT1())\n#       pragma warning(push)\n#       pragma warning(disable:4244)\n#       pragma warning(disable:4267)\n#       endif\n        // Standard trick: the (...) version of tryConvert will be chosen from\n        // the overload set only if the version taking a T2 doesn't match.\n        // Then we compare the sizes of the return types to check which\n        // function matched.  Very neat, in a disgusting kind of way :)\n        static const bool value =\n            sizeof(tryConvert(makeT1())) == sizeof(succeed);\n#       ifdef _MSC_VER\n#       pragma warning(pop)\n#       endif\n};\n\n\n// Detect when a type is not a wchar_t string\ntemplate<typename T> struct is_wchar { typedef int tinyformat_wchar_is_not_supported; };\ntemplate<> struct is_wchar<wchar_t*> {};\ntemplate<> struct is_wchar<const wchar_t*> {};\ntemplate<int n> struct is_wchar<const wchar_t[n]> {};\ntemplate<int n> struct is_wchar<wchar_t[n]> {};\n\n\n// Format the value by casting to type fmtT.  This default implementation\n// should never be called.\ntemplate<typename T, typename fmtT, bool convertible = is_convertible<T, fmtT>::value>\nstruct formatValueAsType\n{\n    static void invoke(std::ostream& /*out*/, const T& /*value*/) { assert(0); }\n};\n// Specialized version for types that can actually be converted to fmtT, as\n// indicated by the \"convertible\" template parameter.\ntemplate<typename T, typename fmtT>\nstruct formatValueAsType<T,fmtT,true>\n{\n    static void invoke(std::ostream& out, const T& value)\n        { out << static_cast<fmtT>(value); }\n};\n\n#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND\ntemplate<typename T, bool convertible = is_convertible<T, int>::value>\nstruct formatZeroIntegerWorkaround\n{\n    static bool invoke(std::ostream& /**/, const T& /**/) { return false; }\n};\ntemplate<typename T>\nstruct formatZeroIntegerWorkaround<T,true>\n{\n    static bool invoke(std::ostream& out, const T& value)\n    {\n        if (static_cast<int>(value) == 0 && out.flags() & std::ios::showpos)\n        {\n            out << \"+0\";\n            return true;\n        }\n        return false;\n    }\n};\n#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND\n\n// Convert an arbitrary type to integer.  The version with convertible=false\n// throws an error.\ntemplate<typename T, bool convertible = is_convertible<T,int>::value>\nstruct convertToInt\n{\n    static int invoke(const T& /*value*/)\n    {\n        TINYFORMAT_ERROR(\"tinyformat: Cannot convert from argument type to \"\n                         \"integer for use as variable width or precision\");\n        return 0;\n    }\n};\n// Specialization for convertToInt when conversion is possible\ntemplate<typename T>\nstruct convertToInt<T,true>\n{\n    static int invoke(const T& value) { return static_cast<int>(value); }\n};\n\n// Format at most ntrunc characters to the given stream.\ntemplate<typename T>\ninline void formatTruncated(std::ostream& out, const T& value, int ntrunc)\n{\n    std::ostringstream tmp;\n    tmp << value;\n    std::string result = tmp.str();\n    out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));\n}\n#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type)       \\\ninline void formatTruncated(std::ostream& out, type* value, int ntrunc) \\\n{                                                           \\\n    std::streamsize len = 0;                                \\\n    while(len < ntrunc && value[len] != 0)                  \\\n        ++len;                                              \\\n    out.write(value, len);                                  \\\n}\n// Overload for const char* and char*.  Could overload for signed & unsigned\n// char too, but these are technically unneeded for printf compatibility.\nTINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)\nTINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)\n#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR\n\n} // namespace detail\n\n\n//------------------------------------------------------------------------------\n// Variable formatting functions.  May be overridden for user-defined types if\n// desired.\n\n\n/// Format a value into a stream, delegating to operator<< by default.\n///\n/// Users may override this for their own types.  When this function is called,\n/// the stream flags will have been modified according to the format string.\n/// The format specification is provided in the range [fmtBegin, fmtEnd).  For\n/// truncating conversions, ntrunc is set to the desired maximum number of\n/// characters, for example \"%.7s\" calls formatValue with ntrunc = 7.\n///\n/// By default, formatValue() uses the usual stream insertion operator\n/// operator<< to format the type T, with special cases for the %c and %p\n/// conversions.\ntemplate<typename T>\ninline void formatValue(std::ostream& out, const char* /*fmtBegin*/,\n                        const char* fmtEnd, int ntrunc, const T& value)\n{\n#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS\n    // Since we don't support printing of wchar_t using \"%ls\", make it fail at\n    // compile time in preference to printing as a void* at runtime.\n    typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported DummyType;\n    (void) DummyType(); // avoid unused type warning with gcc-4.8\n#endif\n    // The mess here is to support the %c and %p conversions: if these\n    // conversions are active we try to convert the type to a char or const\n    // void* respectively and format that instead of the value itself.  For the\n    // %p conversion it's important to avoid dereferencing the pointer, which\n    // could otherwise lead to a crash when printing a dangling (const char*).\n    const bool canConvertToChar = detail::is_convertible<T,char>::value;\n    const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;\n    if(canConvertToChar && *(fmtEnd-1) == 'c')\n        detail::formatValueAsType<T, char>::invoke(out, value);\n    else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p')\n        detail::formatValueAsType<T, const void*>::invoke(out, value);\n#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND\n    else if(detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/;\n#endif\n    else if(ntrunc >= 0)\n    {\n        // Take care not to overread C strings in truncating conversions like\n        // \"%.4s\" where at most 4 characters may be read.\n        detail::formatTruncated(out, value, ntrunc);\n    }\n    else\n        out << value;\n}\n\n\n// Overloaded version for char types to support printing as an integer\n#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType)                  \\\ninline void formatValue(std::ostream& out, const char* /*fmtBegin*/,  \\\n                        const char* fmtEnd, int /**/, charType value) \\\n{                                                                     \\\n    switch(*(fmtEnd-1))                                               \\\n    {                                                                 \\\n        case 'u': case 'd': case 'i': case 'o': case 'X': case 'x':   \\\n            out << static_cast<int>(value); break;                    \\\n        default:                                                      \\\n            out << value;                   break;                    \\\n    }                                                                 \\\n}\n// per 3.9.1: char, signed char and unsigned char are all distinct types\nTINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)\nTINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)\nTINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char)\n#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR\n\n\n//------------------------------------------------------------------------------\n// Tools for emulating variadic templates in C++98.  The basic idea here is\n// stolen from the boost preprocessor metaprogramming library and cut down to\n// be just general enough for what we need.\n\n#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n\n#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n\n#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n\n#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n\n\n// To keep it as transparent as possible, the macros below have been generated\n// using python via the excellent cog.py code generation script.  This avoids\n// the need for a bunch of complex (but more general) preprocessor tricks as\n// used in boost.preprocessor.\n//\n// To rerun the code generation in place, use `cog.py -r tinyformat.h`\n// (see http://nedbatchelder.com/code/cog).  Alternatively you can just create\n// extra versions by hand.\n\n/*[[[cog\nmaxParams = 16\n\ndef makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):\n    for j in range(startInd,maxParams+1):\n        list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])\n        cog.outl(lineTemplate % {'j':j, 'list':list})\n\nmakeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',\n                  'class T%(i)d')\n\ncog.outl()\nmakeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',\n                  'const T%(i)d& v%(i)d')\n\ncog.outl()\nmakeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')\n\ncog.outl()\ncog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')\nmakeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',\n                  'v%(i)d', startInd = 2)\n\ncog.outl()\ncog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\\\\n    ' +\n         ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))\n]]]*/\n#define TINYFORMAT_ARGTYPES_1 class T1\n#define TINYFORMAT_ARGTYPES_2 class T1, class T2\n#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3\n#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4\n#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5\n#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6\n#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7\n#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8\n#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9\n#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10\n#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11\n#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12\n#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13\n#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14\n#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15\n#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16\n\n#define TINYFORMAT_VARARGS_1 const T1& v1\n#define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2\n#define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3\n#define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4\n#define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5\n#define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6\n#define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7\n#define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8\n#define TINYFORMAT_VARARGS_9 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9\n#define TINYFORMAT_VARARGS_10 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10\n#define TINYFORMAT_VARARGS_11 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11\n#define TINYFORMAT_VARARGS_12 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12\n#define TINYFORMAT_VARARGS_13 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13\n#define TINYFORMAT_VARARGS_14 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14\n#define TINYFORMAT_VARARGS_15 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15\n#define TINYFORMAT_VARARGS_16 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15, const T16& v16\n\n#define TINYFORMAT_PASSARGS_1 v1\n#define TINYFORMAT_PASSARGS_2 v1, v2\n#define TINYFORMAT_PASSARGS_3 v1, v2, v3\n#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4\n#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5\n#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6\n#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7\n#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8\n#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9\n#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10\n#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11\n#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12\n#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13\n#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14\n#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15\n#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16\n\n#define TINYFORMAT_PASSARGS_TAIL_1\n#define TINYFORMAT_PASSARGS_TAIL_2 , v2\n#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3\n#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4\n#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5\n#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6\n#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7\n#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8\n#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9\n#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10\n#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11\n#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12\n#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13\n#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14\n#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15\n#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16\n\n#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n    m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16)\n//[[[end]]]\n\n\n\nnamespace detail {\n\n// Type-opaque holder for an argument to format(), with associated actions on\n// the type held as explicit function pointers.  This allows FormatArg's for\n// each argument to be allocated as a homogenous array inside FormatList\n// whereas a naive implementation based on inheritance does not.\nclass FormatArg\n{\n    public:\n        FormatArg() {}\n\n        template<typename T>\n        FormatArg(const T& value)\n            : m_value(static_cast<const void*>(&value)),\n            m_formatImpl(&formatImpl<T>),\n            m_toIntImpl(&toIntImpl<T>)\n        { }\n\n        void format(std::ostream& out, const char* fmtBegin,\n                    const char* fmtEnd, int ntrunc) const\n        {\n            m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);\n        }\n\n        int toInt() const\n        {\n            return m_toIntImpl(m_value);\n        }\n\n    private:\n        template<typename T>\n        TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin,\n                        const char* fmtEnd, int ntrunc, const void* value)\n        {\n            formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));\n        }\n\n        template<typename T>\n        TINYFORMAT_HIDDEN static int toIntImpl(const void* value)\n        {\n            return convertToInt<T>::invoke(*static_cast<const T*>(value));\n        }\n\n        const void* m_value;\n        void (*m_formatImpl)(std::ostream& out, const char* fmtBegin,\n                             const char* fmtEnd, int ntrunc, const void* value);\n        int (*m_toIntImpl)(const void* value);\n};\n\n\n// Parse and return an integer from the string c, as atoi()\n// On return, c is set to one past the end of the integer.\ninline int parseIntAndAdvance(const char*& c)\n{\n    int i = 0;\n    for(;*c >= '0' && *c <= '9'; ++c)\n        i = 10*i + (*c - '0');\n    return i;\n}\n\n// Print literal part of format string and return next format spec\n// position.\n//\n// Skips over any occurrences of '%%', printing a literal '%' to the\n// output.  The position of the first % character of the next\n// nontrivial format spec is returned, or the end of string.\ninline const char* printFormatStringLiteral(std::ostream& out, const char* fmt)\n{\n    const char* c = fmt;\n    for(;; ++c)\n    {\n        switch(*c)\n        {\n            case '\\0':\n                out.write(fmt, c - fmt);\n                return c;\n            case '%':\n                out.write(fmt, c - fmt);\n                if(*(c+1) != '%')\n                    return c;\n                // for \"%%\", tack trailing % onto next literal section.\n                fmt = ++c;\n                break;\n            default:\n                break;\n        }\n    }\n}\n\n\n// Parse a format string and set the stream state accordingly.\n//\n// The format mini-language recognized here is meant to be the one from C99,\n// with the form \"%[flags][width][.precision][length]type\".\n//\n// Formatting options which can't be natively represented using the ostream\n// state are returned in spacePadPositive (for space padded positive numbers)\n// and ntrunc (for truncating conversions).  argIndex is incremented if\n// necessary to pull out variable width and precision .  The function returns a\n// pointer to the character after the end of the current format spec.\ninline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive,\n                                         int& ntrunc, const char* fmtStart,\n                                         const detail::FormatArg* formatters,\n                                         int& argIndex, int numFormatters)\n{\n    if(*fmtStart != '%')\n    {\n        TINYFORMAT_ERROR(\"tinyformat: Not enough conversion specifiers in format string\");\n        return fmtStart;\n    }\n    // Reset stream state to defaults.\n    out.width(0);\n    out.precision(6);\n    out.fill(' ');\n    // Reset most flags; ignore irrelevant unitbuf & skipws.\n    out.unsetf(std::ios::adjustfield | std::ios::basefield |\n               std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |\n               std::ios::showpoint | std::ios::showpos | std::ios::uppercase);\n    bool precisionSet = false;\n    bool widthSet = false;\n    int widthExtra = 0;\n    const char* c = fmtStart + 1;\n    // 1) Parse flags\n    for(;; ++c)\n    {\n        switch(*c)\n        {\n            case '#':\n                out.setf(std::ios::showpoint | std::ios::showbase);\n                continue;\n            case '0':\n                // overridden by left alignment ('-' flag)\n                if(!(out.flags() & std::ios::left))\n                {\n                    // Use internal padding so that numeric values are\n                    // formatted correctly, eg -00010 rather than 000-10\n                    out.fill('0');\n                    out.setf(std::ios::internal, std::ios::adjustfield);\n                }\n                continue;\n            case '-':\n                out.fill(' ');\n                out.setf(std::ios::left, std::ios::adjustfield);\n                continue;\n            case ' ':\n                // overridden by show positive sign, '+' flag.\n                if(!(out.flags() & std::ios::showpos))\n                    spacePadPositive = true;\n                continue;\n            case '+':\n                out.setf(std::ios::showpos);\n                spacePadPositive = false;\n                widthExtra = 1;\n                continue;\n            default:\n                break;\n        }\n        break;\n    }\n    // 2) Parse width\n    if(*c >= '0' && *c <= '9')\n    {\n        widthSet = true;\n        out.width(parseIntAndAdvance(c));\n    }\n    if(*c == '*')\n    {\n        widthSet = true;\n        int width = 0;\n        if(argIndex < numFormatters)\n            width = formatters[argIndex++].toInt();\n        else\n            TINYFORMAT_ERROR(\"tinyformat: Not enough arguments to read variable width\");\n        if(width < 0)\n        {\n            // negative widths correspond to '-' flag set\n            out.fill(' ');\n            out.setf(std::ios::left, std::ios::adjustfield);\n            width = -width;\n        }\n        out.width(width);\n        ++c;\n    }\n    // 3) Parse precision\n    if(*c == '.')\n    {\n        ++c;\n        int precision = 0;\n        if(*c == '*')\n        {\n            ++c;\n            if(argIndex < numFormatters)\n                precision = formatters[argIndex++].toInt();\n            else\n                TINYFORMAT_ERROR(\"tinyformat: Not enough arguments to read variable precision\");\n        }\n        else\n        {\n            if(*c >= '0' && *c <= '9')\n                precision = parseIntAndAdvance(c);\n            else if(*c == '-') // negative precisions ignored, treated as zero.\n                parseIntAndAdvance(++c);\n        }\n        out.precision(precision);\n        precisionSet = true;\n    }\n    // 4) Ignore any C99 length modifier\n    while(*c == 'l' || *c == 'h' || *c == 'L' ||\n          *c == 'j' || *c == 'z' || *c == 't')\n        ++c;\n    // 5) We're up to the conversion specifier character.\n    // Set stream flags based on conversion specifier (thanks to the\n    // boost::format class for forging the way here).\n    bool intConversion = false;\n    switch(*c)\n    {\n        case 'u': case 'd': case 'i':\n            out.setf(std::ios::dec, std::ios::basefield);\n            intConversion = true;\n            break;\n        case 'o':\n            out.setf(std::ios::oct, std::ios::basefield);\n            intConversion = true;\n            break;\n        case 'X':\n            out.setf(std::ios::uppercase);\n        case 'x': case 'p':\n            out.setf(std::ios::hex, std::ios::basefield);\n            intConversion = true;\n            break;\n        case 'E':\n            out.setf(std::ios::uppercase);\n        case 'e':\n            out.setf(std::ios::scientific, std::ios::floatfield);\n            out.setf(std::ios::dec, std::ios::basefield);\n            break;\n        case 'F':\n            out.setf(std::ios::uppercase);\n        case 'f':\n            out.setf(std::ios::fixed, std::ios::floatfield);\n            break;\n        case 'G':\n            out.setf(std::ios::uppercase);\n        case 'g':\n            out.setf(std::ios::dec, std::ios::basefield);\n            // As in boost::format, let stream decide float format.\n            out.flags(out.flags() & ~std::ios::floatfield);\n            break;\n        case 'a': case 'A':\n            TINYFORMAT_ERROR(\"tinyformat: the %a and %A conversion specs \"\n                             \"are not supported\");\n            break;\n        case 'c':\n            // Handled as special case inside formatValue()\n            break;\n        case 's':\n            if(precisionSet)\n                ntrunc = static_cast<int>(out.precision());\n            // Make %s print booleans as \"true\" and \"false\"\n            out.setf(std::ios::boolalpha);\n            break;\n        case 'n':\n            // Not supported - will cause problems!\n            TINYFORMAT_ERROR(\"tinyformat: %n conversion spec not supported\");\n            break;\n        case '\\0':\n            TINYFORMAT_ERROR(\"tinyformat: Conversion spec incorrectly \"\n                             \"terminated by end of string\");\n            return c;\n        default:\n            break;\n    }\n    if(intConversion && precisionSet && !widthSet)\n    {\n        // \"precision\" for integers gives the minimum number of digits (to be\n        // padded with zeros on the left).  This isn't really supported by the\n        // iostreams, but we can approximately simulate it with the width if\n        // the width isn't otherwise used.\n        out.width(out.precision() + widthExtra);\n        out.setf(std::ios::internal, std::ios::adjustfield);\n        out.fill('0');\n    }\n    return c+1;\n}\n\n\n//------------------------------------------------------------------------------\ninline void formatImpl(std::ostream& out, const char* fmt,\n                       const detail::FormatArg* formatters,\n                       int numFormatters)\n{\n    // Saved stream state\n    std::streamsize origWidth = out.width();\n    std::streamsize origPrecision = out.precision();\n    std::ios::fmtflags origFlags = out.flags();\n    char origFill = out.fill();\n\n    for (int argIndex = 0; argIndex < numFormatters; ++argIndex)\n    {\n        // Parse the format string\n        fmt = printFormatStringLiteral(out, fmt);\n        bool spacePadPositive = false;\n        int ntrunc = -1;\n        const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt,\n                                                   formatters, argIndex, numFormatters);\n        if (argIndex >= numFormatters)\n        {\n            // Check args remain after reading any variable width/precision\n            TINYFORMAT_ERROR(\"tinyformat: Not enough format arguments\");\n            return;\n        }\n        const FormatArg& arg = formatters[argIndex];\n        // Format the arg into the stream.\n        if(!spacePadPositive)\n            arg.format(out, fmt, fmtEnd, ntrunc);\n        else\n        {\n            // The following is a special case with no direct correspondence\n            // between stream formatting and the printf() behaviour.  Simulate\n            // it crudely by formatting into a temporary string stream and\n            // munging the resulting string.\n            std::ostringstream tmpStream;\n            tmpStream.copyfmt(out);\n            tmpStream.setf(std::ios::showpos);\n            arg.format(tmpStream, fmt, fmtEnd, ntrunc);\n            std::string result = tmpStream.str(); // allocates... yuck.\n            for(size_t i = 0, iend = result.size(); i < iend; ++i)\n                if(result[i] == '+') result[i] = ' ';\n            out << result;\n        }\n        fmt = fmtEnd;\n    }\n\n    // Print remaining part of format string.\n    fmt = printFormatStringLiteral(out, fmt);\n    if(*fmt != '\\0')\n        TINYFORMAT_ERROR(\"tinyformat: Too many conversion specifiers in format string\");\n\n    // Restore stream state\n    out.width(origWidth);\n    out.precision(origPrecision);\n    out.flags(origFlags);\n    out.fill(origFill);\n}\n\n} // namespace detail\n\n\n/// List of template arguments format(), held in a type-opaque way.\n///\n/// A const reference to FormatList (typedef'd as FormatListRef) may be\n/// conveniently used to pass arguments to non-template functions: All type\n/// information has been stripped from the arguments, leaving just enough of a\n/// common interface to perform formatting as required.\nclass FormatList\n{\n    public:\n        FormatList(detail::FormatArg* formatters, int N)\n            : m_formatters(formatters), m_N(N) { }\n\n        friend void vformat(std::ostream& out, const char* fmt,\n                            const FormatList& list);\n\n    private:\n        const detail::FormatArg* m_formatters;\n        int m_N;\n};\n\n/// Reference to type-opaque format list for passing to vformat()\ntypedef const FormatList& FormatListRef;\n\n\nnamespace detail {\n\n// Format list subclass with fixed storage to avoid dynamic allocation\ntemplate<int N>\nclass FormatListN : public FormatList\n{\n    public:\n#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES\n        template<typename... Args>\n        FormatListN(const Args&... args)\n            : FormatList(&m_formatterStore[0], N),\n            m_formatterStore { FormatArg(args)... }\n        { static_assert(sizeof...(args) == N, \"Number of args must be N\"); }\n#else // C++98 version\n        void init(int) {}\n#       define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n)       \\\n                                                               \\\n        template<TINYFORMAT_ARGTYPES(n)>                       \\\n        FormatListN(TINYFORMAT_VARARGS(n))                     \\\n            : FormatList(&m_formatterStore[0], n)              \\\n        { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); }   \\\n                                                               \\\n        template<TINYFORMAT_ARGTYPES(n)>                       \\\n        void init(int i, TINYFORMAT_VARARGS(n))                \\\n        {                                                      \\\n            m_formatterStore[i] = FormatArg(v1);               \\\n            init(i+1 TINYFORMAT_PASSARGS_TAIL(n));             \\\n        }\n\n        TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)\n#       undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR\n#endif\n\n    private:\n        FormatArg m_formatterStore[N];\n};\n\n// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard\ntemplate<> class FormatListN<0> : public FormatList\n{\n    public: FormatListN() : FormatList(0, 0) {}\n};\n\n} // namespace detail\n\n\n//------------------------------------------------------------------------------\n// Primary API functions\n\n#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES\n\n/// Make type-agnostic format list from list of template arguments.\n///\n/// The exact return type of this function is an implementation detail and\n/// shouldn't be relied upon.  Instead it should be stored as a FormatListRef:\n///\n///   FormatListRef formatList = makeFormatList( /*...*/ );\ntemplate<typename... Args>\ndetail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args)\n{\n    return detail::FormatListN<sizeof...(args)>(args...);\n}\n\n#else // C++98 version\n\ninline detail::FormatListN<0> makeFormatList()\n{\n    return detail::FormatListN<0>();\n}\n#define TINYFORMAT_MAKE_MAKEFORMATLIST(n)                     \\\ntemplate<TINYFORMAT_ARGTYPES(n)>                              \\\ndetail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n))  \\\n{                                                             \\\n    return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n));    \\\n}\nTINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)\n#undef TINYFORMAT_MAKE_MAKEFORMATLIST\n\n#endif\n\n/// Format list of arguments to the stream according to the given format string.\n///\n/// The name vformat() is chosen for the semantic similarity to vprintf(): the\n/// list of format arguments is held in a single function argument.\ninline void vformat(std::ostream& out, const char* fmt, FormatListRef list)\n{\n    detail::formatImpl(out, fmt, list.m_formatters, list.m_N);\n}\n\n\n#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES\n\n/// Format list of arguments to the stream according to given format string.\ntemplate<typename... Args>\nvoid format(std::ostream& out, const char* fmt, const Args&... args)\n{\n    vformat(out, fmt, makeFormatList(args...));\n}\n\n/// Format list of arguments according to the given format string and return\n/// the result as a string.\ntemplate<typename... Args>\nstd::string format(const char* fmt, const Args&... args)\n{\n    std::ostringstream oss;\n    format(oss, fmt, args...);\n    return oss.str();\n}\n\n/// Format list of arguments to std::cout, according to the given format string\ntemplate<typename... Args>\nvoid printf(const char* fmt, const Args&... args)\n{\n    format(std::cout, fmt, args...);\n}\n\ntemplate<typename... Args>\nvoid printfln(const char* fmt, const Args&... args)\n{\n    format(std::cout, fmt, args...);\n    std::cout << '\\n';\n}\n\n#else // C++98 version\n\ninline void format(std::ostream& out, const char* fmt)\n{\n    vformat(out, fmt, makeFormatList());\n}\n\ninline std::string format(const char* fmt)\n{\n    std::ostringstream oss;\n    format(oss, fmt);\n    return oss.str();\n}\n\ninline void printf(const char* fmt)\n{\n    format(std::cout, fmt);\n}\n\ninline void printfln(const char* fmt)\n{\n    format(std::cout, fmt);\n    std::cout << '\\n';\n}\n\n#define TINYFORMAT_MAKE_FORMAT_FUNCS(n)                                   \\\n                                                                          \\\ntemplate<TINYFORMAT_ARGTYPES(n)>                                          \\\nvoid format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n))    \\\n{                                                                         \\\n    vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n)));            \\\n}                                                                         \\\n                                                                          \\\ntemplate<TINYFORMAT_ARGTYPES(n)>                                          \\\nstd::string format(const char* fmt, TINYFORMAT_VARARGS(n))                \\\n{                                                                         \\\n    std::ostringstream oss;                                               \\\n    format(oss, fmt, TINYFORMAT_PASSARGS(n));                             \\\n    return oss.str();                                                     \\\n}                                                                         \\\n                                                                          \\\ntemplate<TINYFORMAT_ARGTYPES(n)>                                          \\\nvoid printf(const char* fmt, TINYFORMAT_VARARGS(n))                       \\\n{                                                                         \\\n    format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                       \\\n}                                                                         \\\n                                                                          \\\ntemplate<TINYFORMAT_ARGTYPES(n)>                                          \\\nvoid printfln(const char* fmt, TINYFORMAT_VARARGS(n))                     \\\n{                                                                         \\\n    format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                       \\\n    std::cout << '\\n';                                                    \\\n}\n\nTINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)\n#undef TINYFORMAT_MAKE_FORMAT_FUNCS\n\n#endif\n\n// Added for Munt Core\ntemplate<typename... Args>\nstd::string format(const std::string &fmt, const Args&... args)\n{\n    std::ostringstream oss;\n    format(oss, fmt.c_str(), args...);\n    return oss.str();\n}\n\n} // namespace tinyformat\n\n#define strprintf tfm::format\n\n#endif // TINYFORMAT_H_INCLUDED\n"
  },
  {
    "path": "src/torcontrol.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Copyright (c) 2017 The Zcash developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"torcontrol.h\"\n#include \"util/strencodings.h\"\n#include \"netbase.h\"\n#include \"net.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"crypto/hmac_sha256.h\"\n\n#include <vector>\n#include <deque>\n#include <set>\n#include <stdlib.h>\n#include <thread>\n\n#include <boost/bind.hpp>\n#include <boost/signals2/signal.hpp>\n\n#include <boost/algorithm/string/split.hpp>\n#include <boost/algorithm/string/classification.hpp>\n#include <boost/algorithm/string/replace.hpp>\n\n#include <event2/bufferevent.h>\n#include <event2/buffer.h>\n#include <event2/util.h>\n#include <event2/event.h>\n#include <event2/thread.h>\n\n/** Default control port */\nconst std::string DEFAULT_TOR_CONTROL = \"127.0.0.1:9051\";\n/** Tor cookie size (from control-spec.txt) */\nstatic const int TOR_COOKIE_SIZE = 32;\n/** Size of client/server nonce for SAFECOOKIE */\nstatic const int TOR_NONCE_SIZE = 32;\n/** For computing serverHash in SAFECOOKIE */\nstatic const std::string TOR_SAFE_SERVERKEY = \"Tor safe cookie authentication server-to-controller hash\";\n/** For computing clientHash in SAFECOOKIE */\nstatic const std::string TOR_SAFE_CLIENTKEY = \"Tor safe cookie authentication controller-to-server hash\";\n/** Exponential backoff configuration - initial timeout in seconds */\nstatic const float RECONNECT_TIMEOUT_START = 1.0;\n/** Exponential backoff configuration - growth factor */\nstatic const float RECONNECT_TIMEOUT_EXP = 1.5;\n/** Maximum length for lines received on TorControlConnection.\n * tor-control-spec.txt mentions that there is explicitly no limit defined to line length,\n * this is belt-and-suspenders sanity limit to prevent memory exhaustion.\n */\nstatic const int MAX_LINE_LENGTH = 100000;\n\n/****** Low-level TorControlConnection ********/\n\n/** Reply from Tor, can be single or multi-line */\nclass TorControlReply\n{\npublic:\n    TorControlReply() { Clear(); }\n\n    int code;\n    std::vector<std::string> lines;\n\n    void Clear()\n    {\n        code = 0;\n        lines.clear();\n    }\n};\n\n/** Low-level handling for Tor control connection.\n * Speaks the SMTP-like protocol as defined in torspec/control-spec.txt\n */\nclass TorControlConnection\n{\npublic:\n    typedef std::function<void(TorControlConnection&)> ConnectionCB;\n    typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;\n\n    /** Create a new TorControlConnection.\n     */\n    TorControlConnection(struct event_base *base);\n    ~TorControlConnection();\n\n    /**\n     * Connect to a Tor control port.\n     * target is address of the form host:port.\n     * connected is the handler that is called when connection is successfully established.\n     * disconnected is a handler that is called when the connection is broken.\n     * Return true on success.\n     */\n    bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected);\n\n    /**\n     * Disconnect from Tor control port.\n     */\n    bool Disconnect();\n\n    /** Send a command, register a handler for the reply.\n     * A trailing CRLF is automatically added.\n     * Return true on success.\n     */\n    bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);\n\n    /** Response handlers for async replies */\n    boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;\nprivate:\n    /** Callback when ready for use */\n    std::function<void(TorControlConnection&)> connected;\n    /** Callback when connection lost */\n    std::function<void(TorControlConnection&)> disconnected;\n    /** Libevent event base */\n    struct event_base *base;\n    /** Connection to control socket */\n    struct bufferevent *b_conn;\n    /** Message being received */\n    TorControlReply message;\n    /** Response handlers */\n    std::deque<ReplyHandlerCB> reply_handlers;\n\n    /** Libevent handlers: internal */\n    static void readcb(struct bufferevent *bev, void *ctx);\n    static void eventcb(struct bufferevent *bev, short what, void *ctx);\n};\n\nTorControlConnection::TorControlConnection(struct event_base *_base):\n    base(_base), b_conn(0)\n{\n}\n\nTorControlConnection::~TorControlConnection()\n{\n    if (b_conn)\n        bufferevent_free(b_conn);\n}\n\nvoid TorControlConnection::readcb(struct bufferevent *bev, void *ctx)\n{\n    TorControlConnection *self = (TorControlConnection*)ctx;\n    struct evbuffer *input = bufferevent_get_input(bev);\n    size_t n_read_out = 0;\n    char *line;\n    assert(input);\n    //  If there is not a whole line to read, evbuffer_readln returns NULL\n    while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL)\n    {\n        std::string s(line, n_read_out);\n        free(line);\n        if (s.size() < 4) // Short line\n            continue;\n        // <status>(-|+| )<data><CRLF>\n        self->message.code = atoi(s.substr(0,3));\n        self->message.lines.push_back(s.substr(4));\n        char ch = s[3]; // '-','+' or ' '\n        if (ch == ' ') {\n            // Final line, dispatch reply and clean up\n            if (self->message.code >= 600) {\n                // Dispatch async notifications to async handler\n                // Synchronous and asynchronous messages are never interleaved\n                self->async_handler(*self, self->message);\n            } else {\n                if (!self->reply_handlers.empty()) {\n                    // Invoke reply handler with message\n                    self->reply_handlers.front()(*self, self->message);\n                    self->reply_handlers.pop_front();\n                } else {\n                    LogPrint(BCLog::TOR, \"tor: Received unexpected sync reply %i\\n\", self->message.code);\n                }\n            }\n            self->message.Clear();\n        }\n    }\n    //  Check for size of buffer - protect against memory exhaustion with very long lines\n    //  Do this after evbuffer_readln to make sure all full lines have been\n    //  removed from the buffer. Everything left is an incomplete line.\n    if (evbuffer_get_length(input) > MAX_LINE_LENGTH) {\n        LogPrintf(\"tor: Disconnecting because MAX_LINE_LENGTH exceeded\\n\");\n        self->Disconnect();\n    }\n}\n\nvoid TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx)\n{\n    (void) bev;\n    TorControlConnection *self = (TorControlConnection*)ctx;\n    if (what & BEV_EVENT_CONNECTED) {\n        LogPrint(BCLog::TOR, \"tor: Successfully connected!\\n\");\n        self->connected(*self);\n    } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {\n        if (what & BEV_EVENT_ERROR) {\n            LogPrint(BCLog::TOR, \"tor: Error connecting to Tor control socket\\n\");\n        } else {\n            LogPrint(BCLog::TOR, \"tor: End of stream\\n\");\n        }\n        self->Disconnect();\n        self->disconnected(*self);\n    }\n}\n\nbool TorControlConnection::Connect(const std::string &target, const ConnectionCB& _connected, const ConnectionCB&  _disconnected)\n{\n    if (b_conn)\n        Disconnect();\n    // Parse target address:port\n    struct sockaddr_storage connect_to_addr;\n    int connect_to_addrlen = sizeof(connect_to_addr);\n    if (evutil_parse_sockaddr_port(target.c_str(),\n        (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) {\n        LogPrintf(\"tor: Error parsing socket address %s\\n\", target);\n        return false;\n    }\n\n    // Create a new socket, set up callbacks and enable notification bits\n    b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);\n    if (!b_conn)\n        return false;\n    bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this);\n    bufferevent_enable(b_conn, EV_READ|EV_WRITE);\n    this->connected = _connected;\n    this->disconnected = _disconnected;\n\n    // Finally, connect to target\n    if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) {\n        LogPrintf(\"tor: Error connecting to address %s\\n\", target);\n        return false;\n    }\n    return true;\n}\n\nbool TorControlConnection::Disconnect()\n{\n    if (b_conn)\n        bufferevent_free(b_conn);\n    b_conn = 0;\n    return true;\n}\n\nbool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB& reply_handler)\n{\n    if (!b_conn)\n        return false;\n    struct evbuffer *buf = bufferevent_get_output(b_conn);\n    if (!buf)\n        return false;\n    evbuffer_add(buf, cmd.data(), cmd.size());\n    evbuffer_add(buf, \"\\r\\n\", 2);\n    reply_handlers.push_back(reply_handler);\n    return true;\n}\n\n/****** General parsing utilities ********/\n\n/* Split reply line in the form 'AUTH METHODS=...' into a type\n * 'AUTH' and arguments 'METHODS=...'.\n * Grammar is implicitly defined in https://spec.torproject.org/control-spec by\n * the server reply formats for PROTOCOLINFO (S3.21) and AUTHCHALLENGE (S3.24).\n */\nstatic std::pair<std::string,std::string> SplitTorReplyLine(const std::string &s)\n{\n    size_t ptr=0;\n    std::string type;\n    while (ptr < s.size() && s[ptr] != ' ') {\n        type.push_back(s[ptr]);\n        ++ptr;\n    }\n    if (ptr < s.size())\n        ++ptr; // skip ' '\n    return std::pair(type, s.substr(ptr));\n}\n\n/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\".../control_auth_cookie\"'.\n * Returns a map of keys to values, or an empty map if there was an error.\n * Grammar is implicitly defined in https://spec.torproject.org/control-spec by\n * the server reply formats for PROTOCOLINFO (S3.21), AUTHCHALLENGE (S3.24),\n * and ADD_ONION (S3.27). See also sections 2.1 and 2.3.\n */\nstatic std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)\n{\n    std::map<std::string,std::string> mapping;\n    size_t ptr=0;\n    while (ptr < s.size()) {\n        std::string key, value;\n        while (ptr < s.size() && s[ptr] != '=' && s[ptr] != ' ') {\n            key.push_back(s[ptr]);\n            ++ptr;\n        }\n        if (ptr == s.size()) // unexpected end of line\n            return std::map<std::string,std::string>();\n        if (s[ptr] == ' ') // The remaining string is an OptArguments\n            break;\n        ++ptr; // skip '='\n        if (ptr < s.size() && s[ptr] == '\"') { // Quoted string\n            ++ptr; // skip opening '\"'\n            bool escape_next = false;\n            while (ptr < s.size() && (escape_next || s[ptr] != '\"')) {\n                // Repeated backslashes must be interpreted as pairs\n                escape_next = (s[ptr] == '\\\\' && !escape_next);\n                value.push_back(s[ptr]);\n                ++ptr;\n            }\n            if (ptr == s.size()) // unexpected end of line\n                return std::map<std::string,std::string>();\n            ++ptr; // skip closing '\"'\n            /**\n             * Unescape value. Per https://spec.torproject.org/control-spec section 2.1.1:\n             *\n             *   For future-proofing, controller implementors MAY use the following\n             *   rules to be compatible with buggy Tor implementations and with\n             *   future ones that implement the spec as intended:\n             *\n             *     Read \\n \\t \\r and \\0 ... \\377 as C escapes.\n             *     Treat a backslash followed by any other character as that character.\n             */\n            std::string escaped_value;\n            for (size_t i = 0; i < value.size(); ++i) {\n                if (value[i] == '\\\\') {\n                    // This will always be valid, because if the QuotedString\n                    // ended in an odd number of backslashes, then the parser\n                    // would already have returned above, due to a missing\n                    // terminating double-quote.\n                    ++i;\n                    if (value[i] == 'n') {\n                        escaped_value.push_back('\\n');\n                    } else if (value[i] == 't') {\n                        escaped_value.push_back('\\t');\n                    } else if (value[i] == 'r') {\n                        escaped_value.push_back('\\r');\n                    } else if ('0' <= value[i] && value[i] <= '7') {\n                        size_t j;\n                        // Octal escape sequences have a limit of three octal digits,\n                        // but terminate at the first character that is not a valid\n                        // octal digit if encountered sooner.\n                        for (j = 1; j < 3 && (i+j) < value.size() && '0' <= value[i+j] && value[i+j] <= '7'; ++j) {}\n                        // Tor restricts first digit to 0-3 for three-digit octals.\n                        // A leading digit of 4-7 would therefore be interpreted as\n                        // a two-digit octal.\n                        if (j == 3 && value[i] > '3') {\n                            j--;\n                        }\n                        escaped_value.push_back(strtol(value.substr(i, j).c_str(), NULL, 8));\n                        // Account for automatic incrementing at loop end\n                        i += j - 1;\n                    } else {\n                        escaped_value.push_back(value[i]);\n                    }\n                } else {\n                    escaped_value.push_back(value[i]);\n                }\n            }\n            value = escaped_value;\n        } else { // Unquoted value. Note that values can contain '=' at will, just no spaces\n            while (ptr < s.size() && s[ptr] != ' ') {\n                value.push_back(s[ptr]);\n                ++ptr;\n            }\n        }\n        if (ptr < s.size() && s[ptr] == ' ')\n            ++ptr; // skip ' ' after key=value\n        mapping[key] = value;\n    }\n    return mapping;\n}\n\n/** Read full contents of a file and return them in a std::string.\n * Returns a pair <status, string>.\n * If an error occurred, status will be false, otherwise status will be true and the data will be returned in string.\n *\n * @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data\n *         (with len > maxsize) will be returned.\n */\nstatic std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxsize=std::numeric_limits<size_t>::max())\n{\n    FILE *f = fsbridge::fopen(filename, \"rb\");\n    if (f == NULL)\n        return std::pair(false,\"\");\n    std::string retval;\n    char buffer[128];\n    size_t n;\n    while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) {\n        // Check for reading errors so we don't return any data if we couldn't\n        // read the entire file (or up to maxsize)\n        if (ferror(f))\n            return std::pair(false,\"\");\n        retval.append(buffer, buffer+n);\n        if (retval.size() > maxsize)\n            break;\n    }\n    fclose(f);\n    return std::pair(true,retval);\n}\n\n/** Write contents of std::string to a file.\n * @return true on success.\n */\nstatic bool WriteBinaryFile(const fs::path &filename, const std::string &data)\n{\n    FILE *f = fsbridge::fopen(filename, \"wb\");\n    if (f == NULL)\n        return false;\n    if (fwrite(data.data(), 1, data.size(), f) != data.size()) {\n        fclose(f);\n        return false;\n    }\n    fclose(f);\n    return true;\n}\n\n/****** TorController implementation ********/\n\n/** Controller that connects to Tor control socket, authenticate, then create\n * and maintain a ephemeral hidden service.\n */\nclass TorController\n{\npublic:\n    TorController(struct event_base* base, const std::string& target);\n    ~TorController();\n\n    /** Get name fo file to store private key in */\n    fs::path GetPrivateKeyFile();\n\n    /** Reconnect, after getting disconnected */\n    void Reconnect();\nprivate:\n    struct event_base* base;\n    std::string target;\n    TorControlConnection conn;\n    std::string private_key;\n    std::string service_id;\n    bool reconnect;\n    struct event *reconnect_ev;\n    float reconnect_timeout;\n    CService service;\n    /** Cookie for SAFECOOKIE auth */\n    std::vector<uint8_t> cookie;\n    /** ClientNonce for SAFECOOKIE auth */\n    std::vector<uint8_t> clientNonce;\n\n    /** Callback for ADD_ONION result */\n    void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);\n    /** Callback for AUTHENTICATE result */\n    void auth_cb(TorControlConnection& conn, const TorControlReply& reply);\n    /** Callback for AUTHCHALLENGE result */\n    void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);\n    /** Callback for PROTOCOLINFO result */\n    void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);\n    /** Callback after successful connection */\n    void connected_cb(TorControlConnection& conn);\n    /** Callback after connection lost or failed connection attempt */\n    void disconnected_cb(TorControlConnection& conn);\n\n    /** Callback for reconnect timer */\n    static void reconnect_cb(evutil_socket_t fd, short what, void *arg);\n};\n\nTorController::TorController(struct event_base* _base, const std::string& _target):\n    base(_base),\n    target(_target), conn(base), reconnect(true), reconnect_ev(0),\n    reconnect_timeout(RECONNECT_TIMEOUT_START)\n{\n    reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);\n    if (!reconnect_ev)\n        LogPrintf(\"tor: Failed to create event for reconnection: out of memory?\\n\");\n    // Start connection attempts immediately\n    if (!conn.Connect(_target, boost::bind(&TorController::connected_cb, this, _1),\n         boost::bind(&TorController::disconnected_cb, this, _1) )) {\n        LogPrintf(\"tor: Initiating connection to Tor control port %s failed\\n\", _target);\n    }\n    // Read service private key if cached\n    std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());\n    if (pkf.first) {\n        LogPrint(BCLog::TOR, \"tor: Reading cached private key from %s\\n\", GetPrivateKeyFile().string());\n        private_key = pkf.second;\n    }\n}\n\nTorController::~TorController()\n{\n    if (reconnect_ev) {\n        event_free(reconnect_ev);\n        reconnect_ev = 0;\n    }\n    if (service.IsValid()) {\n        RemoveLocal(service);\n    }\n}\n\nvoid TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)\n{\n    (void) _conn;\n    if (reply.code == 250) {\n        LogPrint(BCLog::TOR, \"tor: ADD_ONION successful\\n\");\n        for(const std::string &s : reply.lines) {\n            std::map<std::string,std::string> m = ParseTorReplyMapping(s);\n            std::map<std::string,std::string>::iterator i;\n            if ((i = m.find(\"ServiceID\")) != m.end())\n                service_id = i->second;\n            if ((i = m.find(\"PrivateKey\")) != m.end())\n                private_key = i->second;\n        }\n        if (service_id.empty()) {\n            LogPrintf(\"tor: Error parsing ADD_ONION parameters:\\n\");\n            for (const std::string &s : reply.lines) {\n                LogPrintf(\"    %s\\n\", SanitizeString(s));\n            }\n            return;\n        }\n        service = LookupNumeric(std::string(service_id+\".onion\").c_str(), GetListenPort());\n        LogPrintf(\"tor: Got service ID %s, advertising service %s\\n\", service_id, service.ToString());\n        if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {\n            LogPrint(BCLog::TOR, \"tor: Cached service private key to %s\\n\", GetPrivateKeyFile().string());\n        } else {\n            LogPrintf(\"tor: Error writing service private key to %s\\n\", GetPrivateKeyFile().string());\n        }\n        AddLocal(service, LOCAL_MANUAL);\n        // ... onion requested - keep connection open\n    } else if (reply.code == 510) { // 510 Unrecognized command\n        LogPrintf(\"tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\\n\");\n    } else {\n        LogPrintf(\"tor: Add onion failed; error code %d\\n\", reply.code);\n    }\n}\n\nvoid TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& reply)\n{\n    if (reply.code == 250) {\n        LogPrint(BCLog::TOR, \"tor: Authentication successful\\n\");\n\n        // Now that we know Tor is running setup the proxy for onion addresses\n        // if -onion isn't set to something else.\n        if (GetArg(\"-onion\", \"\") == \"\") {\n            CService resolved(LookupNumeric(\"127.0.0.1\", 9050));\n            proxyType addrOnion = proxyType(resolved, true);\n            SetProxy(NET_TOR, addrOnion);\n            SetLimited(NET_TOR, false);\n        }\n\n        // Finally - now create the service\n        if (private_key.empty()) // No private key, generate one\n            private_key = \"NEW:RSA1024\"; // Explicitly request RSA1024 - see issue #9214\n        // Request hidden service, redirect port.\n        // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient\n        // choice.  TODO; refactor the shutdown sequence some day.\n        _conn.Command(strprintf(\"ADD_ONION %s Port=%i,127.0.0.1:%i\", private_key, GetListenPort(), GetListenPort()),\n            boost::bind(&TorController::add_onion_cb, this, _1, _2));\n    } else {\n        LogPrintf(\"tor: Authentication failed\\n\");\n    }\n}\n\n/** Compute Tor SAFECOOKIE response.\n *\n *    ServerHash is computed as:\n *      HMAC-SHA256(\"Tor safe cookie authentication server-to-controller hash\",\n *                  CookieString | ClientNonce | ServerNonce)\n *    (with the HMAC key as its first argument)\n *\n *    After a controller sends a successful AUTHCHALLENGE command, the\n *    next command sent on the connection must be an AUTHENTICATE command,\n *    and the only authentication string which that AUTHENTICATE command\n *    will accept is:\n *\n *      HMAC-SHA256(\"Tor safe cookie authentication controller-to-server hash\",\n *                  CookieString | ClientNonce | ServerNonce)\n *\n */\nstatic std::vector<uint8_t> ComputeResponse(const std::string &key, const std::vector<uint8_t> &cookie,  const std::vector<uint8_t> &clientNonce, const std::vector<uint8_t> &serverNonce)\n{\n    CHMAC_SHA256 computeHash((const uint8_t*)key.data(), key.size());\n    std::vector<uint8_t> computedHash(CHMAC_SHA256::OUTPUT_SIZE, 0);\n    computeHash.Write(cookie.data(), cookie.size());\n    computeHash.Write(clientNonce.data(), clientNonce.size());\n    computeHash.Write(serverNonce.data(), serverNonce.size());\n    computeHash.Finalize(computedHash.data());\n    return computedHash;\n}\n\nvoid TorController::authchallenge_cb(TorControlConnection& _conn, const TorControlReply& reply)\n{\n    if (reply.code == 250) {\n        LogPrint(BCLog::TOR, \"tor: SAFECOOKIE authentication challenge successful\\n\");\n        std::pair<std::string,std::string> l = SplitTorReplyLine(reply.lines[0]);\n        if (l.first == \"AUTHCHALLENGE\") {\n            std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);\n            if (m.empty()) {\n                LogPrintf(\"tor: Error parsing AUTHCHALLENGE parameters: %s\\n\", SanitizeString(l.second));\n                return;\n            }\n            std::vector<uint8_t> serverHash = ParseHex(m[\"SERVERHASH\"]);\n            std::vector<uint8_t> serverNonce = ParseHex(m[\"SERVERNONCE\"]);\n            LogPrint(BCLog::TOR, \"tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\\n\", HexStr(serverHash), HexStr(serverNonce));\n            if (serverNonce.size() != 32) {\n                LogPrintf(\"tor: ServerNonce is not 32 bytes, as required by spec\\n\");\n                return;\n            }\n\n            std::vector<uint8_t> computedServerHash = ComputeResponse(TOR_SAFE_SERVERKEY, cookie, clientNonce, serverNonce);\n            if (computedServerHash != serverHash) {\n                LogPrintf(\"tor: ServerHash %s does not match expected ServerHash %s\\n\", HexStr(serverHash), HexStr(computedServerHash));\n                return;\n            }\n\n            std::vector<uint8_t> computedClientHash = ComputeResponse(TOR_SAFE_CLIENTKEY, cookie, clientNonce, serverNonce);\n            _conn.Command(\"AUTHENTICATE \" + HexStr(computedClientHash), boost::bind(&TorController::auth_cb, this, _1, _2));\n        } else {\n            LogPrintf(\"tor: Invalid reply to AUTHCHALLENGE\\n\");\n        }\n    } else {\n        LogPrintf(\"tor: SAFECOOKIE authentication challenge failed\\n\");\n    }\n}\n\nvoid TorController::protocolinfo_cb(TorControlConnection& _conn, const TorControlReply& reply)\n{\n    if (reply.code == 250) {\n        std::set<std::string> methods;\n        std::string cookiefile;\n        /*\n         * 250-AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"\n         * 250-AUTH METHODS=NULL\n         * 250-AUTH METHODS=HASHEDPASSWORD\n         */\n        for(const std::string &s : reply.lines) {\n            std::pair<std::string,std::string> l = SplitTorReplyLine(s);\n            if (l.first == \"AUTH\") {\n                std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);\n                std::map<std::string,std::string>::iterator i;\n                if ((i = m.find(\"METHODS\")) != m.end())\n                    boost::split(methods, i->second, boost::is_any_of(\",\"));\n                if ((i = m.find(\"COOKIEFILE\")) != m.end())\n                    cookiefile = i->second;\n            } else if (l.first == \"VERSION\") {\n                std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);\n                std::map<std::string,std::string>::iterator i;\n                if ((i = m.find(\"Tor\")) != m.end()) {\n                    LogPrint(BCLog::TOR, \"tor: Connected to Tor version %s\\n\", i->second);\n                }\n            }\n        }\n        for(const std::string &s : methods) {\n            LogPrint(BCLog::TOR, \"tor: Supported authentication method: %s\\n\", s);\n        }\n        // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD\n        /* Authentication:\n         *   cookie:   hex-encoded ~/.tor/control_auth_cookie\n         *   password: \"password\"\n         */\n        std::string torpassword = GetArg(\"-torpassword\", \"\");\n        if (!torpassword.empty()) {\n            if (methods.count(\"HASHEDPASSWORD\")) {\n                LogPrint(BCLog::TOR, \"tor: Using HASHEDPASSWORD authentication\\n\");\n                boost::replace_all(torpassword, \"\\\"\", \"\\\\\\\"\");\n                _conn.Command(\"AUTHENTICATE \\\"\" + torpassword + \"\\\"\", boost::bind(&TorController::auth_cb, this, _1, _2));\n            } else {\n                LogPrintf(\"tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\\n\");\n            }\n        } else if (methods.count(\"NULL\")) {\n            LogPrint(BCLog::TOR, \"tor: Using NULL authentication\\n\");\n            _conn.Command(\"AUTHENTICATE\", boost::bind(&TorController::auth_cb, this, _1, _2));\n        } else if (methods.count(\"SAFECOOKIE\")) {\n            // Cookie: hexdump -e '32/1 \"%02x\"\"\\n\"'  ~/.tor/control_auth_cookie\n            LogPrint(BCLog::TOR, \"tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\\n\", cookiefile);\n            std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);\n            if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {\n                // _conn.Command(\"AUTHENTICATE \" + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2));\n                cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());\n                clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);\n                GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE);\n                _conn.Command(\"AUTHCHALLENGE SAFECOOKIE \" + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));\n            } else {\n                if (status_cookie.first) {\n                    LogPrintf(\"tor: Authentication cookie %s is not exactly %i bytes, as is required by the spec\\n\", cookiefile, TOR_COOKIE_SIZE);\n                } else {\n                    LogPrintf(\"tor: Authentication cookie %s could not be opened (check permissions)\\n\", cookiefile);\n                }\n            }\n        } else if (methods.count(\"HASHEDPASSWORD\")) {\n            LogPrintf(\"tor: The only supported authentication mechanism left is password, but no password provided with -torpassword\\n\");\n        } else {\n            LogPrintf(\"tor: No supported authentication method\\n\");\n        }\n    } else {\n        LogPrintf(\"tor: Requesting protocol info failed\\n\");\n    }\n}\n\nvoid TorController::connected_cb(TorControlConnection& _conn)\n{\n    (void) _conn;\n    reconnect_timeout = RECONNECT_TIMEOUT_START;\n    // First send a PROTOCOLINFO command to figure out what authentication is expected\n    if (!_conn.Command(\"PROTOCOLINFO 1\", boost::bind(&TorController::protocolinfo_cb, this, _1, _2)))\n        LogPrintf(\"tor: Error sending initial protocolinfo command\\n\");\n}\n\nvoid TorController::disconnected_cb(TorControlConnection& _conn)\n{\n    // Stop advertising service when disconnected\n    if (service.IsValid())\n        RemoveLocal(service);\n    service = CService();\n    if (!reconnect)\n        return;\n\n    LogPrint(BCLog::TOR, \"tor: Not connected to Tor control port %s, trying to reconnect\\n\", target);\n\n    // Single-shot timer for reconnect. Use exponential backoff.\n    struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));\n    if (reconnect_ev)\n        event_add(reconnect_ev, &time);\n    reconnect_timeout *= RECONNECT_TIMEOUT_EXP;\n}\n\nvoid TorController::Reconnect()\n{\n    /* Try to reconnect and reestablish if we get booted - for example, Tor\n     * may be restarting.\n     */\n    if (!conn.Connect(target, boost::bind(&TorController::connected_cb, this, _1),\n         boost::bind(&TorController::disconnected_cb, this, _1) )) {\n        LogPrintf(\"tor: Re-initiating connection to Tor control port %s failed\\n\", target);\n    }\n}\n\nfs::path TorController::GetPrivateKeyFile()\n{\n    return GetDataDir() / \"onion_private_key\";\n}\n\nvoid TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)\n{\n    (void) fd;\n    (void) what;\n    TorController *self = (TorController*)arg;\n    self->Reconnect();\n}\n\n/****** Thread ********/\nstatic struct event_base *gBase;\nstatic std::thread torControlThread;\n\nstatic void TorControlThread()\n{\n    TorController ctrl(gBase, GetArg(\"-torcontrol\", DEFAULT_TOR_CONTROL));\n\n    event_base_dispatch(gBase);\n}\n\nvoid StartTorControl()\n{\n    assert(!gBase);\n#ifdef WIN32\n    evthread_use_windows_threads();\n#else\n    evthread_use_pthreads();\n#endif\n    gBase = event_base_new();\n    if (!gBase) {\n        LogPrintf(\"tor: Unable to create event_base\\n\");\n        return;\n    }\n\n    torControlThread = std::thread(&util::TraceThread, \"torcontrol\", [] {\n        TorControlThread();\n    });\n}\n\nvoid InterruptTorControl()\n{\n    if (gBase) {\n        LogPrintf(\"tor: Thread interrupt\\n\");\n        event_base_loopbreak(gBase);\n    }\n}\n\nvoid StopTorControl()\n{\n    if (gBase) {\n        torControlThread.join();\n        event_base_free(gBase);\n        gBase = 0;\n    }\n}\n\n"
  },
  {
    "path": "src/torcontrol.h",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n/**\n * Functionality for communicating with Tor.\n */\n#ifndef TORCONTROL_H\n#define TORCONTROL_H\n\n#include <string>\n\nextern const std::string DEFAULT_TOR_CONTROL;\nstatic const bool DEFAULT_LISTEN_ONION = true;\n\nvoid StartTorControl();\nvoid InterruptTorControl();\nvoid StopTorControl();\n\n#endif\n"
  },
  {
    "path": "src/tx-main.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"validation/validation.h\"\n\n#include \"base58.h\"\n#include \"clientversion.h\"\n#include \"coins.h\"\n#include \"consensus/consensus.h\"\n#include \"core_io.h\"\n#include \"keystore.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"script/sign.h\"\n#include <univalue.h>\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/moneystr.h\"\n#include \"util/strencodings.h\"\n\n#include <stdio.h>\n\n#include <boost/algorithm/string.hpp>\n#include <boost/thread.hpp>\n\n#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */\n\n\nstatic bool fCreateBlank;\nstatic std::map<std::string,UniValue> registers;\nstatic const int CONTINUE_EXECUTION=-1;\n\n//\n// This function returns either one of EXIT_ codes when it's expected to stop the process or\n// CONTINUE_EXECUTION when it's expected to continue further.\n//\nstatic int AppInitRawTx(int argc, char* argv[])\n{\n    //\n    // Parameters\n    //\n    ParseParameters(argc, argv);\n\n    // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)\n    try {\n        SelectParams(ChainNameFromCommandLine());\n    } catch (const std::exception& e) {\n        fprintf(stderr, \"Error: %s\\n\", e.what());\n        return EXIT_FAILURE;\n    }\n\n    fCreateBlank = GetBoolArg(\"-create\", false);\n\n    if (argc<2 || IsArgSet(\"-?\") || IsArgSet(\"-h\") || IsArgSet(\"-help\"))\n    {\n        // First part of help message is specific to this utility\n        std::string strUsage = strprintf(_(\"%s Munt-tx utility version\"), _(PACKAGE_NAME)) + \" \" + FormatFullVersion() + \"\\n\\n\" +\n            _(\"Usage:\") + \"\\n\" +\n              \"  Munt-tx [options] <hex-tx> [commands]  \" + _(\"Update hex-encoded munt transaction\") + \"\\n\" +\n              \"  Munt-tx [options] -create [commands]   \" + _(\"Create hex-encoded munt transaction\") + \"\\n\" +\n              \"\\n\";\n\n        fprintf(stdout, \"%s\", strUsage.c_str());\n\n        strUsage = HelpMessageGroup(_(\"Options:\"));\n        strUsage += HelpMessageOpt(\"-?\", _(\"This help message\"));\n        strUsage += HelpMessageOpt(\"-create\", _(\"Create new, empty TX.\"));\n        strUsage += HelpMessageOpt(\"-json\", _(\"Select JSON output\"));\n        strUsage += HelpMessageOpt(\"-txid\", _(\"Output only the hex-encoded transaction id of the resultant transaction.\"));\n        AppendParamsHelpMessages(strUsage);\n\n        fprintf(stdout, \"%s\", strUsage.c_str());\n\n        strUsage = HelpMessageGroup(_(\"Commands:\"));\n        strUsage += HelpMessageOpt(\"delin=N\", _(\"Delete input N from TX\"));\n        strUsage += HelpMessageOpt(\"delout=N\", _(\"Delete output N from TX\"));\n        strUsage += HelpMessageOpt(\"in=TXID:VOUT(:SEQUENCE_NUMBER)\", _(\"Add input to TX\"));\n        strUsage += HelpMessageOpt(\"locktime=N\", _(\"Set TX lock time to N\"));\n        strUsage += HelpMessageOpt(\"nversion=N\", _(\"Set TX version to N\"));\n        strUsage += HelpMessageOpt(\"rbfoptin(=N)\", _(\"Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)\"));\n        strUsage += HelpMessageOpt(\"outaddr=VALUE:ADDRESS\", _(\"Add address-based output to TX\"));\n        strUsage += HelpMessageOpt(\"outpubkey=VALUE:PUBKEY[:FLAGS]\", _(\"Add pay-to-pubkey output to TX\") + \". \" +\n            _(\"Optionally add the \\\"S\\\" flag to wrap the output in a pay-to-script-hash.\"));\n        strUsage += HelpMessageOpt(\"outdata=[VALUE:]DATA\", _(\"Add data-based output to TX\"));\n        strUsage += HelpMessageOpt(\"outscript=VALUE:SCRIPT[:FLAGS]\", _(\"Add raw script output to TX\") + \". \" +\n            _(\"Optionally add the \\\"S\\\" flag to wrap the output in a pay-to-script-hash.\"));\n        strUsage += HelpMessageOpt(\"outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]\", _(\"Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS\") + \". \" +\n            _(\"Optionally add the \\\"S\\\" flag to wrap the output in a pay-to-script-hash.\"));\n        strUsage += HelpMessageOpt(\"sign=SIGHASH-FLAGS\", _(\"Add zero or more signatures to transaction\") + \". \" +\n            _(\"This command requires JSON registers:\") +\n            _(\"prevtxs=JSON object\") + \", \" +\n            _(\"privatekeys=JSON object\") + \". \" +\n            _(\"See signrawtransaction docs for format of sighash flags, JSON objects.\"));\n        fprintf(stdout, \"%s\", strUsage.c_str());\n\n        strUsage = HelpMessageGroup(_(\"Register Commands:\"));\n        strUsage += HelpMessageOpt(\"load=NAME:FILENAME\", _(\"Load JSON file FILENAME into register NAME\"));\n        strUsage += HelpMessageOpt(\"set=NAME:JSON-STRING\", _(\"Set register NAME to given JSON-STRING\"));\n        fprintf(stdout, \"%s\", strUsage.c_str());\n\n        if (argc < 2) {\n            fprintf(stderr, \"Error: too few parameters\\n\");\n            return EXIT_FAILURE;\n        }\n        return EXIT_SUCCESS;\n    }\n    return CONTINUE_EXECUTION;\n}\n\nstatic void RegisterSetJson(const std::string& key, const std::string& rawJson)\n{\n    UniValue val;\n    if (!val.read(rawJson)) {\n        std::string strErr = \"Cannot parse JSON for key \" + key;\n        throw std::runtime_error(strErr);\n    }\n\n    registers[key] = val;\n}\n\nstatic void RegisterSet(const std::string& strInput)\n{\n    // separate NAME:VALUE in string\n    size_t pos = strInput.find(':');\n    if ((pos == std::string::npos) ||\n        (pos == 0) ||\n        (pos == (strInput.size() - 1)))\n        throw std::runtime_error(\"Register input requires NAME:VALUE\");\n\n    std::string key = strInput.substr(0, pos);\n    std::string valStr = strInput.substr(pos + 1, std::string::npos);\n\n    RegisterSetJson(key, valStr);\n}\n\nstatic void RegisterLoad(const std::string& strInput)\n{\n    // separate NAME:FILENAME in string\n    size_t pos = strInput.find(':');\n    if ((pos == std::string::npos) ||\n        (pos == 0) ||\n        (pos == (strInput.size() - 1)))\n        throw std::runtime_error(\"Register load requires NAME:FILENAME\");\n\n    std::string key = strInput.substr(0, pos);\n    std::string filename = strInput.substr(pos + 1, std::string::npos);\n\n    FILE *f = fopen(filename.c_str(), \"r\");\n    if (!f) {\n        std::string strErr = \"Cannot open file \" + filename;\n        throw std::runtime_error(strErr);\n    }\n\n    // load file chunks into one big buffer\n    std::string valStr;\n    while ((!feof(f)) && (!ferror(f))) {\n        char buf[4096];\n        int bread = fread(buf, 1, sizeof(buf), f);\n        if (bread <= 0)\n            break;\n\n        valStr.insert(valStr.size(), buf, bread);\n    }\n\n    int error = ferror(f);\n    fclose(f);\n\n    if (error) {\n        std::string strErr = \"Error reading file \" + filename;\n        throw std::runtime_error(strErr);\n    }\n\n    // evaluate as JSON buffer register\n    RegisterSetJson(key, valStr);\n}\n\nstatic CAmount ExtractAndValidateValue(const std::string& strValue)\n{\n    CAmount value;\n    if (!ParseMoney(strValue, value))\n        throw std::runtime_error(\"invalid TX output value\");\n    return value;\n}\n\nstatic void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)\n{\n    int64_t newVersion = atoi64(cmdVal);\n    if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)\n        throw std::runtime_error(\"Invalid TX version requested\");\n\n    tx.nVersion = (int) newVersion;\n}\n\nstatic void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)\n{\n    int64_t newLocktime = atoi64(cmdVal);\n    if (newLocktime < 0LL || newLocktime > 0xffffffffLL)\n        throw std::runtime_error(\"Invalid TX locktime requested\");\n\n    tx.nLockTime = (unsigned int) newLocktime;\n}\n\nstatic void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)\n{\n    // parse requested index\n    int inIdx = atoi(strInIdx);\n    if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {\n        throw std::runtime_error(\"Invalid TX input index '\" + strInIdx + \"'\");\n    }\n\n    //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n    // Enable RBF\n    int cnt = 0;\n    for (CTxIn& txin : tx.vin)\n    {\n        if (strInIdx == \"\" || cnt == inIdx)\n        {\n            txin.SetFlag(CTxInFlags::OptInRBF);\n        }\n        ++cnt;\n    }\n}\n\nstatic void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)\n{\n    std::vector<std::string> vStrInputParts;\n    boost::split(vStrInputParts, strInput, boost::is_any_of(\":\"));\n\n    // separate TXID:VOUT in string\n    if (vStrInputParts.size()<2)\n        throw std::runtime_error(\"TX input missing separator\");\n\n    // extract and validate TXID\n    std::string strTxid = vStrInputParts[0];\n    if ((strTxid.size() != 64) || !IsHex(strTxid))\n        throw std::runtime_error(\"invalid TX input txid\");\n    uint256 txid(uint256S(strTxid));\n\n    static const unsigned int minTxOutSz = 9;\n    static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz;\n\n    // extract and validate vout\n    std::string strVout = vStrInputParts[1];\n    int vout = atoi(strVout);\n    if ((vout < 0) || (vout > (int)maxVout))\n        throw std::runtime_error(\"invalid TX input vout\");\n\n    // extract the optional sequence number\n    uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();\n    if (vStrInputParts.size() > 2)\n        nSequenceIn = std::stoul(vStrInputParts[2]);\n\n    // append to transaction input list\n    //fixme: (PHASE4POSTREL) (SEGSIG)\n    CTxIn txin(txid, vout, CScript(), nSequenceIn, 0);\n    tx.vin.push_back(txin);\n}\n\nstatic void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)\n{\n    // Separate into VALUE:ADDRESS\n    std::vector<std::string> vStrInputParts;\n    boost::split(vStrInputParts, strInput, boost::is_any_of(\":\"));\n\n    if (vStrInputParts.size() != 2)\n        throw std::runtime_error(\"TX output missing or too many separators\");\n\n    // Extract and validate VALUE\n    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);\n\n    // extract and validate ADDRESS\n    std::string strAddr = vStrInputParts[1];\n    CNativeAddress addr(strAddr);\n    if (!addr.IsValid())\n        throw std::runtime_error(\"invalid TX output address\");\n    // build standard output script via GetScriptForDestination()\n    CScript scriptPubKey = GetScriptForDestination(addr.Get());\n\n    // construct TxOut, append to transaction output list\n    CTxOut txout(value, scriptPubKey);\n    tx.vout.push_back(txout);\n}\n\nstatic void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)\n{\n    // Separate into VALUE:PUBKEY[:FLAGS]\n    std::vector<std::string> vStrInputParts;\n    boost::split(vStrInputParts, strInput, boost::is_any_of(\":\"));\n\n    if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)\n        throw std::runtime_error(\"TX output missing or too many separators\");\n\n    // Extract and validate VALUE\n    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);\n\n    // Extract and validate PUBKEY\n    CPubKey pubkey(ParseHex(vStrInputParts[1]));\n    if (!pubkey.IsFullyValid())\n        throw std::runtime_error(\"invalid TX output pubkey\");\n    CScript scriptPubKey = GetScriptForRawPubKey(pubkey);\n    CNativeAddress addr(scriptPubKey);\n\n    // Extract and validate FLAGS\n    bool bScriptHash = false;\n    if (vStrInputParts.size() == 3) {\n        std::string flags = vStrInputParts[2];\n        bScriptHash = (flags.find(\"S\") != std::string::npos);\n    }\n\n    if (bScriptHash) {\n        // Get the address for the redeem script, then call\n        // GetScriptForDestination() to construct a P2SH scriptPubKey.\n        CNativeAddress redeemScriptAddr(scriptPubKey);\n        scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());\n    }\n\n    // construct TxOut, append to transaction output list\n    CTxOut txout(value, scriptPubKey);\n    tx.vout.push_back(txout);\n}\n\nstatic void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)\n{\n    // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]\n    std::vector<std::string> vStrInputParts;\n    boost::split(vStrInputParts, strInput, boost::is_any_of(\":\"));\n\n    // Check that there are enough parameters\n    if (vStrInputParts.size()<3)\n        throw std::runtime_error(\"Not enough multisig parameters\");\n\n    // Extract and validate VALUE\n    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);\n\n    // Extract REQUIRED\n    uint32_t required = stoul(vStrInputParts[1]);\n\n    // Extract NUMKEYS\n    uint32_t numkeys = stoul(vStrInputParts[2]);\n\n    // Validate there are the correct number of pubkeys\n    if (vStrInputParts.size() < numkeys + 3)\n        throw std::runtime_error(\"incorrect number of multisig pubkeys\");\n\n    if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)\n        throw std::runtime_error(\"multisig parameter mismatch. Required \" \\\n                            + std::to_string(required) + \" of \" + std::to_string(numkeys) + \"signatures.\");\n\n    // extract and validate PUBKEYs\n    std::vector<CPubKey> pubkeys;\n    for(int pos = 1; pos <= int(numkeys); pos++) {\n        CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));\n        if (!pubkey.IsFullyValid())\n            throw std::runtime_error(\"invalid TX output pubkey\");\n        pubkeys.push_back(pubkey);\n    }\n\n    // Extract FLAGS\n    bool bScriptHash = false;\n    if (vStrInputParts.size() == numkeys + 4) {\n        std::string flags = vStrInputParts.back();\n        bScriptHash = (flags.find(\"S\") != std::string::npos);\n    }\n    else if (vStrInputParts.size() > numkeys + 4) {\n        // Validate that there were no more parameters passed\n        throw std::runtime_error(\"Too many parameters\");\n    }\n\n    CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);\n\n    if (bScriptHash) {\n        // Get the address for the redeem script, then call\n        // GetScriptForDestination() to construct a P2SH scriptPubKey.\n        CNativeAddress addr(scriptPubKey);\n        scriptPubKey = GetScriptForDestination(addr.Get());\n    }\n\n    // construct TxOut, append to transaction output list\n    CTxOut txout(value, scriptPubKey);\n    tx.vout.push_back(txout);\n}\n\nstatic void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)\n{\n    CAmount value = 0;\n\n    // separate [VALUE:]DATA in string\n    size_t pos = strInput.find(':');\n\n    if (pos==0)\n        throw std::runtime_error(\"TX output value not specified\");\n\n    if (pos != std::string::npos) {\n        // Extract and validate VALUE\n        value = ExtractAndValidateValue(strInput.substr(0, pos));\n    }\n\n    // extract and validate DATA\n    std::string strData = strInput.substr(pos + 1, std::string::npos);\n\n    if (!IsHex(strData))\n        throw std::runtime_error(\"invalid TX output data\");\n\n    std::vector<unsigned char> data = ParseHex(strData);\n\n    CTxOut txout(value, CScript() << OP_RETURN << data);\n    tx.vout.push_back(txout);\n}\n\nstatic void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)\n{\n    // separate VALUE:SCRIPT[:FLAGS]\n    std::vector<std::string> vStrInputParts;\n    boost::split(vStrInputParts, strInput, boost::is_any_of(\":\"));\n    if (vStrInputParts.size() < 2)\n        throw std::runtime_error(\"TX output missing separator\");\n\n    // Extract and validate VALUE\n    CAmount value = ExtractAndValidateValue(vStrInputParts[0]);\n\n    // extract and validate script\n    std::string strScript = vStrInputParts[1];\n    CScript scriptPubKey = ParseScript(strScript);\n\n    // Extract FLAGS\n    bool bScriptHash = false;\n    if (vStrInputParts.size() == 3) {\n        std::string flags = vStrInputParts.back();\n        bScriptHash = (flags.find(\"S\") != std::string::npos);\n    }\n\n    if (bScriptHash) {\n      CNativeAddress addr(scriptPubKey);\n      scriptPubKey = GetScriptForDestination(addr.Get());\n    }\n\n    // construct TxOut, append to transaction output list\n    CTxOut txout(value, scriptPubKey);\n    tx.vout.push_back(txout);\n}\n\nstatic void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)\n{\n    // parse requested deletion index\n    int inIdx = atoi(strInIdx);\n    if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {\n        std::string strErr = \"Invalid TX input index '\" + strInIdx + \"'\";\n        throw std::runtime_error(strErr.c_str());\n    }\n\n    // delete input from transaction\n    tx.vin.erase(tx.vin.begin() + inIdx);\n}\n\nstatic void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)\n{\n    // parse requested deletion index\n    int outIdx = atoi(strOutIdx);\n    if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {\n        std::string strErr = \"Invalid TX output index '\" + strOutIdx + \"'\";\n        throw std::runtime_error(strErr.c_str());\n    }\n\n    // delete output from transaction\n    tx.vout.erase(tx.vout.begin() + outIdx);\n}\n\nstatic const unsigned int N_SIGHASH_OPTS = 6;\nstatic const struct {\n    const char *flagStr;\n    int flags;\n} sighashOptions[N_SIGHASH_OPTS] = {\n    {\"ALL\", SIGHASH_ALL},\n    {\"NONE\", SIGHASH_NONE},\n    {\"SINGLE\", SIGHASH_SINGLE},\n    {\"ALL|ANYONECANPAY\", SIGHASH_ALL|SIGHASH_ANYONECANPAY},\n    {\"NONE|ANYONECANPAY\", SIGHASH_NONE|SIGHASH_ANYONECANPAY},\n    {\"SINGLE|ANYONECANPAY\", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},\n};\n\nstatic bool findSighashFlags(int& flags, const std::string& flagStr)\n{\n    flags = 0;\n\n    for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {\n        if (flagStr == sighashOptions[i].flagStr) {\n            flags = sighashOptions[i].flags;\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic CAmount AmountFromValue(const UniValue& value)\n{\n    if (!value.isNum() && !value.isStr())\n        throw std::runtime_error(\"Amount is not a number or string\");\n    CAmount amount;\n    if (!ParseFixedPoint(value.getValStr(), 8, &amount))\n        throw std::runtime_error(\"Invalid amount\");\n    if (!MoneyRange(amount))\n        throw std::runtime_error(\"Amount out of range\");\n    return amount;\n}\n\nstatic void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)\n{\n    int nHashType = SIGHASH_ALL;\n\n    if (flagStr.size() > 0)\n        if (!findSighashFlags(nHashType, flagStr))\n            throw std::runtime_error(\"unknown sighash flag/sign option\");\n\n    std::vector<CTransaction> txVariants;\n    txVariants.push_back(tx);\n\n    // mergedTx will end up with all the signatures; it\n    // starts as a clone of the raw tx:\n    CMutableTransaction mergedTx(txVariants[0]);\n    bool fComplete = true;\n    CCoinsView viewDummy;\n    CCoinsViewCache view(&viewDummy);\n\n    if (!registers.count(\"privatekeys\"))\n        throw std::runtime_error(\"privatekeys register variable must be set.\");\n    CBasicKeyStore tempKeystore;\n    UniValue keysObj = registers[\"privatekeys\"];\n\n    for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {\n        if (!keysObj[kidx].isStr())\n            throw std::runtime_error(\"privatekey not a std::string\");\n        CEncodedSecretKey vchSecret;\n        bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());\n        if (!fGood)\n            throw std::runtime_error(\"privatekey not valid\");\n\n        CKey key = vchSecret.GetKey();\n        tempKeystore.AddKey(key);\n    }\n\n    // Add previous txouts given in the RPC call:\n    if (!registers.count(\"prevtxs\"))\n        throw std::runtime_error(\"prevtxs register variable must be set.\");\n    UniValue prevtxsObj = registers[\"prevtxs\"];\n    {\n        for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {\n            UniValue prevOut = prevtxsObj[previdx];\n            if (!prevOut.isObject())\n                throw std::runtime_error(\"expected prevtxs internal object\");\n\n            std::map<std::string, UniValue::VType> types = {\n                {\"txid\", UniValue::VSTR},\n                {\"vout\", UniValue::VNUM},\n                {\"scriptPubKey\", UniValue::VSTR},\n            };\n            if (!prevOut.checkObject(types))\n                throw std::runtime_error(\"prevtxs internal object typecheck fail\");\n\n            uint256 txid = ParseHashUV(prevOut[\"txid\"], \"txid\");\n\n            int nOut = atoi(prevOut[\"vout\"].getValStr());\n            if (nOut < 0)\n                throw std::runtime_error(\"vout must be positive\");\n\n            //fixme: (PHASE4POSTREL) (SEGSIG)\n            COutPoint out(txid, nOut);\n            std::vector<unsigned char> pkData(ParseHexUV(prevOut[\"scriptPubKey\"], \"scriptPubKey\"));\n            CScript scriptPubKey(pkData.begin(), pkData.end());\n\n            {\n                const Coin& coin = view.AccessCoin(out);\n                //fixme: (PHASE4POSTREL) (SEGSIG)\n                if (!coin.IsSpent() && coin.out.output.scriptPubKey != scriptPubKey) {\n                    std::string err(\"Previous output scriptPubKey mismatch:\\n\");\n                    err = err + ScriptToAsmStr(coin.out.output.scriptPubKey) + \"\\nvs:\\n\"+\n                        ScriptToAsmStr(scriptPubKey);\n                    throw std::runtime_error(err);\n                }\n                Coin newcoin;\n                newcoin.out.output.scriptPubKey = scriptPubKey;\n                newcoin.out.nValue = 0;\n                if (prevOut.exists(\"amount\")) {\n                    newcoin.out.nValue = AmountFromValue(prevOut[\"amount\"]);\n                }\n                newcoin.nHeight = 1;\n                view.AddCoin(out, std::move(newcoin), true);\n            }\n\n            // if redeemScript given and private keys given,\n            // add redeemScript to the tempKeystore so it can be signed:\n            if ((scriptPubKey.IsPayToScriptHash()) && prevOut.exists(\"redeemScript\"))\n            {\n                UniValue v = prevOut[\"redeemScript\"];\n                std::vector<unsigned char> rsData(ParseHexUV(v, \"redeemScript\"));\n                CScript redeemScript(rsData.begin(), rsData.end());\n                tempKeystore.AddCScript(redeemScript);\n            }\n        }\n    }\n\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(&tempKeystore);\n\n    bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);\n\n    // Sign what we can:\n    for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {\n        CTxIn& txin = mergedTx.vin[i];\n        const Coin& coin = view.AccessCoin(txin.GetPrevOut());\n        if (coin.IsSpent()) {\n            fComplete = false;\n            continue;\n        }\n        const CScript& prevPubKey = coin.out.output.scriptPubKey;\n        const CAmount& amount = coin.out.nValue;\n\n        CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(coin.out, SignType::Spend);\n\n        SignatureData sigdata;\n        // Only sign SIGHASH_SINGLE if there's a corresponding output:\n        if (!fHashSingle || (i < mergedTx.vout.size()))\n            ProduceSignature(MutableTransactionSignatureCreator(signingKeyID, accountsToTry, &mergedTx, i, amount, nHashType), coin.out, sigdata, SignType::Spend, mergedTx.nVersion);\n\n        ScriptVersion scriptversion = (txin.segregatedSignatureData.IsNull()) ? SCRIPT_V1 : SCRIPT_V2;\n        \n        // ... and merge in other signatures:\n        for(const CTransaction& txv : txVariants)\n            sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(signingKeyID, CKeyID(), &mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), (scriptversion == SCRIPT_V1) ? SIGVERSION_BASE : SIGVERSION_SEGSIG);\n        UpdateTransaction(mergedTx, i, sigdata);\n       \n        if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.segregatedSignatureData, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(signingKeyID, CKeyID(), &mergedTx, i, amount), scriptversion))\n            fComplete = false;\n    }\n\n    if (fComplete) {\n        // do nothing... for now\n        // perhaps store this for later optional JSON output\n    }\n\n    tx = mergedTx;\n}\n\nclass Secp256k1Init\n{\n    ECCVerifyHandle globalVerifyHandle;\n\npublic:\n    Secp256k1Init() {\n        ECC_Start();\n    }\n    ~Secp256k1Init() {\n        ECC_Stop();\n    }\n};\n\nstatic void MutateTx(CMutableTransaction& tx, const std::string& command,\n                     const std::string& commandVal)\n{\n    std::unique_ptr<Secp256k1Init> ecc;\n\n    if (command == \"nversion\")\n        MutateTxVersion(tx, commandVal);\n    else if (command == \"locktime\")\n        MutateTxLocktime(tx, commandVal);\n    else if (command == \"rbfoptin\") {\n        MutateTxRBFOptIn(tx, commandVal);\n    }\n\n    else if (command == \"delin\")\n        MutateTxDelInput(tx, commandVal);\n    else if (command == \"in\")\n        MutateTxAddInput(tx, commandVal);\n\n    else if (command == \"delout\")\n        MutateTxDelOutput(tx, commandVal);\n    else if (command == \"outaddr\")\n        MutateTxAddOutAddr(tx, commandVal);\n    else if (command == \"outpubkey\") {\n        if (!ecc) { ecc.reset(new Secp256k1Init()); }\n        MutateTxAddOutPubKey(tx, commandVal);\n    } else if (command == \"outmultisig\") {\n        if (!ecc) { ecc.reset(new Secp256k1Init()); }\n        MutateTxAddOutMultiSig(tx, commandVal);\n    } else if (command == \"outscript\")\n        MutateTxAddOutScript(tx, commandVal);\n    else if (command == \"outdata\")\n        MutateTxAddOutData(tx, commandVal);\n\n    else if (command == \"sign\") {\n        if (!ecc) { ecc.reset(new Secp256k1Init()); }\n        MutateTxSign(tx, commandVal);\n    }\n\n    else if (command == \"load\")\n        RegisterLoad(commandVal);\n\n    else if (command == \"set\")\n        RegisterSet(commandVal);\n\n    else\n        throw std::runtime_error(\"unknown command\");\n}\n\nstatic void OutputTxJSON(const CTransaction& tx)\n{\n    UniValue entry(UniValue::VOBJ);\n    TxToUniv(tx, uint256(), entry);\n\n    std::string jsonOutput = entry.write(4);\n    fprintf(stdout, \"%s\\n\", jsonOutput.c_str());\n}\n\nstatic void OutputTxHash(const CTransaction& tx)\n{\n    std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)\n\n    fprintf(stdout, \"%s\\n\", strHexHash.c_str());\n}\n\nstatic void OutputTxHex(const CTransaction& tx)\n{\n    std::string strHex = EncodeHexTx(tx);\n\n    fprintf(stdout, \"%s\\n\", strHex.c_str());\n}\n\nstatic void OutputTx(const CTransaction& tx)\n{\n    if (GetBoolArg(\"-json\", false))\n        OutputTxJSON(tx);\n    else if (GetBoolArg(\"-txid\", false))\n        OutputTxHash(tx);\n    else\n        OutputTxHex(tx);\n}\n\nstatic std::string readStdin()\n{\n    char buf[4096];\n    std::string ret;\n\n    while (!feof(stdin)) {\n        size_t bread = fread(buf, 1, sizeof(buf), stdin);\n        ret.append(buf, bread);\n        if (bread < sizeof(buf))\n            break;\n    }\n\n    if (ferror(stdin))\n        throw std::runtime_error(\"error reading stdin\");\n\n    boost::algorithm::trim_right(ret);\n\n    return ret;\n}\n\nstatic int CommandLineRawTx(int argc, char* argv[])\n{\n    std::string strPrint;\n    int nRet = 0;\n    try {\n        // Skip switches; Permit common stdin convention \"-\"\n        while (argc > 1 && IsSwitchChar(argv[1][0]) &&\n               (argv[1][1] != 0)) {\n            argc--;\n            argv++;\n        }\n\n        //fixme: (PHASE4POSTREL) SEGSIG) Some of the MutateTx stuff doesn't work at all for segsig - it is only used by munt-tx, we should consider just refusing to allow them for now.\n        //fixme: (PHASE4POSTREL) (SEGSIG) (HIGH) (CURRENT_TX_VERSION_POW2) - Hardcoding to 1 below is (probably?) wrong but CURRENT_TX_VERSION_POW2 doesn't work right as it requires symbols that are undefined for Munt-tx\n        CMutableTransaction tx(1);\n        int startArg;\n\n        if (!fCreateBlank) {\n            // require at least one param\n            if (argc < 2)\n                throw std::runtime_error(\"too few parameters\");\n\n            // param: hex-encoded Munt transaction\n            std::string strHexTx(argv[1]);\n            if (strHexTx == \"-\")                 // \"-\" implies standard input\n                strHexTx = readStdin();\n\n            if (!DecodeHexTx(tx, strHexTx, true))\n                throw std::runtime_error(\"invalid transaction encoding\");\n\n            startArg = 2;\n        } else\n            startArg = 1;\n\n        for (int i = startArg; i < argc; i++) {\n            std::string arg = argv[i];\n            std::string key, value;\n            size_t eqpos = arg.find('=');\n            if (eqpos == std::string::npos)\n                key = arg;\n            else {\n                key = arg.substr(0, eqpos);\n                value = arg.substr(eqpos + 1);\n            }\n\n            MutateTx(tx, key, value);\n        }\n\n        OutputTx(tx);\n    }\n\n    catch (const boost::thread_interrupted&) {\n        throw;\n    }\n    catch (const std::exception& e) {\n        strPrint = std::string(\"error: \") + e.what();\n        nRet = EXIT_FAILURE;\n    }\n    catch (...) {\n        PrintExceptionContinue(NULL, \"CommandLineRawTx()\");\n        throw;\n    }\n\n    if (strPrint != \"\") {\n        fprintf((nRet == 0 ? stdout : stderr), \"%s\\n\", strPrint.c_str());\n    }\n    return nRet;\n}\n\nint main(int argc, char* argv[])\n{\n    SetupEnvironment();\n\n    try {\n        int ret = AppInitRawTx(argc, argv);\n        if (ret != CONTINUE_EXECUTION)\n            return ret;\n    }\n    catch (const std::exception& e) {\n        PrintExceptionContinue(&e, \"AppInitRawTx()\");\n        return EXIT_FAILURE;\n    } catch (...) {\n        PrintExceptionContinue(NULL, \"AppInitRawTx()\");\n        return EXIT_FAILURE;\n    }\n\n    int ret = EXIT_FAILURE;\n    try {\n        ret = CommandLineRawTx(argc, argv);\n    }\n    catch (const std::exception& e) {\n        PrintExceptionContinue(&e, \"CommandLineRawTx()\");\n    } catch (...) {\n        PrintExceptionContinue(NULL, \"CommandLineRawTx()\");\n    }\n    return ret;\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/tx-res.rc",
    "content": "#include <windows.h>             // needed for VERSIONINFO\n#include \"clientversion.h\"       // holds the needed client version information\n#include \"appname.h\"\n\n#define VER_PRODUCTVERSION     CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD\n#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) \".\" STRINGIZE(CLIENT_VERSION_MINOR) \".\" STRINGIZE(CLIENT_VERSION_REVISION) \".\" STRINGIZE(CLIENT_VERSION_BUILD)\n#define VER_FILEVERSION        VER_PRODUCTVERSION\n#define VER_FILEVERSION_STR    VER_PRODUCTVERSION_STR\n\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION     VER_FILEVERSION\nPRODUCTVERSION  VER_PRODUCTVERSION\nFILEOS          VOS_NT_WINDOWS32\nFILETYPE        VFT_APP\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\" // U.S. English - multilingual (hex)\n        BEGIN\n            VALUE \"CompanyName\",        GLOBAL_APPNAME\"\"\n            VALUE \"FileDescription\",    GLOBAL_APPNAME\"-tx (CLI \"GLOBAL_APPNAME\" transaction editor utility)\"\n            VALUE \"FileVersion\",        VER_FILEVERSION_STR\n            VALUE \"InternalName\",       GLOBAL_APPNAME\"-tx\"\n            VALUE \"LegalCopyright\",     COPYRIGHT_STR\n            VALUE \"LegalTrademarks1\",   \"Distributed under the GNU Lesser General Public License v3, see the accompanying file COPYING or github.com/muntorg/munt-official/COPYING\"\n            VALUE \"OriginalFilename\",   GLOBAL_APPNAME\"-tx.exe\"\n            VALUE \"ProductName\",        GLOBAL_APPNAME\"-tx\"\n            VALUE \"ProductVersion\",     VER_PRODUCTVERSION_STR\n        END\n    END\n\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0, 1252 // language neutral - multilingual (decimal)\n    END\nEND\n"
  },
  {
    "path": "src/txdb.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"txdb.h\"\n\n#include \"chainparams.h\"\n#include \"hash.h\"\n#include \"pow/pow.h\"\n#include \"uint256.h\"\n\n#include <witnessutil.h>\n#include <stdint.h>\n\n#include <boost/thread.hpp>\n\n#include <validation/witnessvalidation.h> //For ppow2witTip (remove in future)\n\n// Old v0 format, deprecated v1\nstatic const char DB_COINS = 'c';\n\n// v1 format\nstatic const char DB_COIN = 'C';\n\nstatic const char DB_BLOCK_FILES = 'f';\nstatic const char DB_TXINDEX = 't';\nstatic const char DB_BLOCK_INDEX = 'b';\n\nstatic const char DB_BEST_BLOCK = 'B';\nstatic const char DB_FLAG = 'F';\nstatic const char DB_REINDEX_FLAG = 'R';\nstatic const char DB_LAST_BLOCK = 'l';\n\nstatic const char DB_VERSION     = '1';\nstatic const char DB_POW2_PHASE2 = '2';\nstatic const char DB_POW2_PHASE3 = '3';\nstatic const char DB_POW2_PHASE4 = '4';\nstatic const char DB_POW2_PHASE5 = '5';\n\n// Additional v2 format\nstatic const char DB_COIN_REF = 'r';\n\nnamespace\n{\n\nstruct CoinEntry\n{\n    COutPoint* outpoint;\n    char key;\n    CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN)  {}\n\n    template<typename Stream>\n    void Serialize(Stream &s) const\n    {\n        s << key;\n        s << outpoint->getTransactionHash();\n        uint32_t nTemp = outpoint->n;\n        s << VARINT(nTemp);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        s >> key;\n        uint256 hash;\n        s >> hash;\n        outpoint->setHash(hash);\n        uint32_t n_ = 0;\n        s >> VARINT(n_);\n        outpoint->n = n_;\n    }\n};\n\nstruct CoinEntryRef\n{\n    char key;\n    uint64_t nHeight;\n    uint64_t nTxIndex;\n    uint32_t n;\n    CoinEntryRef(uint64_t nHeightIn, uint64_t nTxIndexIn, uint64_t nIn)\n    : key(DB_COIN_REF)\n    , nHeight(nHeightIn)\n    , nTxIndex(nTxIndexIn)\n    , n(nIn)\n    {}\n    \n    CoinEntryRef(const COutPoint& outpoint)\n    : key(DB_COIN_REF)\n    {\n        assert(!outpoint.isHash);\n        nHeight = outpoint.getTransactionBlockNumber();\n        nTxIndex = outpoint.getTransactionIndex();\n        n = outpoint.n;\n    }\n\n    template<typename Stream>\n    void Serialize(Stream &s) const\n    {\n        s << key;\n        s << nHeight; //NB! We delibritely don't use varint here, to remove the possibility of collisions.\n        s << nTxIndex;\n        s << VARINT(n);\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        s >> key;\n        s >> nHeight;\n        s >> nTxIndex;\n        s >> VARINT(n);\n    }\n};\n\n}\n\nCWitViewDB::CWitViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : CCoinsViewDB(nCacheSize, fMemory, fWipe, \"witstate\")\n{\n}\n\nCCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe, std::string name) : db(GetDataDir() / name, nCacheSize, fMemory, fWipe, true)\n{\n}\n\nbool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet) const\n{\n    if (!outpoint.isHash)\n    {\n        uint256 hash;\n        if (db.Read(CoinEntryRef(outpoint), hash))\n        {\n            COutPoint dereferencedOutpoint(hash, outpoint.n);\n            if (pOutpointRet)\n                *pOutpointRet = dereferencedOutpoint;\n            return db.Read(CoinEntry(&dereferencedOutpoint), coin);\n        }\n        return false;\n    }\n    else \n    {\n        if (pOutpointRet)\n            *pOutpointRet = outpoint;\n        return db.Read(CoinEntry(&outpoint), coin);\n    }\n}\n\nbool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const\n{\n    if (outpoint.isHash)\n        return db.Exists(CoinEntryRef(outpoint));\n    else \n        return db.Exists(CoinEntry(&outpoint));\n}\n\nvoid CCoinsViewDB::SetPhase2ActivationHash(const uint256 &hashPhase2ActivationPoint)\n{\n    db.Write(DB_POW2_PHASE2, hashPhase2ActivationPoint);\n}\n\nuint256 CCoinsViewDB::GetPhase2ActivationHash()\n{\n    uint256 hashPhase2ActivationPoint;\n    if (!db.Read(DB_POW2_PHASE2, hashPhase2ActivationPoint))\n        return uint256();\n    return hashPhase2ActivationPoint;\n}\n\nvoid CCoinsViewDB::SetPhase3ActivationHash(const uint256 &hashPhase3ActivationPoint)\n{\n    db.Write(DB_POW2_PHASE3, hashPhase3ActivationPoint);\n}\n\nuint256 CCoinsViewDB::GetPhase3ActivationHash()\n{\n    uint256 hashPhase3ActivationPoint;\n    if (!db.Read(DB_POW2_PHASE3, hashPhase3ActivationPoint))\n        return uint256();\n    return hashPhase3ActivationPoint;\n}\n\nvoid CCoinsViewDB::SetPhase4ActivationHash(const uint256 &hashPhase4ActivationPoint)\n{\n    db.Write(DB_POW2_PHASE4, hashPhase4ActivationPoint);\n}\n\nuint256 CCoinsViewDB::GetPhase4ActivationHash()\n{\n    uint256 hashPhase4ActivationPoint;\n    if (!db.Read(DB_POW2_PHASE4, hashPhase4ActivationPoint))\n        return uint256();\n    return hashPhase4ActivationPoint;\n}\n\nvoid CCoinsViewDB::SetPhase5ActivationHash(const uint256 &hashPhase5ActivationPoint)\n{\n    db.Write(DB_POW2_PHASE5, hashPhase5ActivationPoint);\n}\n\nuint256 CCoinsViewDB::GetPhase5ActivationHash()\n{\n    uint256 hashPhase5ActivationPoint;\n    if (!db.Read(DB_POW2_PHASE5, hashPhase5ActivationPoint))\n        return uint256();\n    return hashPhase5ActivationPoint;\n}\n\nuint256 CCoinsViewDB::GetBestBlock() const\n{\n    uint256 hashBestChain;\n    if (!db.Read(DB_BEST_BLOCK, hashBestChain))\n        return uint256();\n    return hashBestChain;\n}\n\nbool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock)\n{\n    CDBBatch batch(db);\n    size_t count = 0;\n    size_t changed = 0;\n    // It is possible (in fact likely) for the same batch to be both erasing and writing the same entryref e.g. if swapping one block 1963 for a competing block 1963\n    // mapCoins is 'randomly' ordered so doing this would create random behaviour and an inconsistent coin database\n    // To overcome this we erase first always, and then pool up the inserts to do at the end\n    std::vector<std::pair<CoinEntryRef, uint256>> writeRefHashes;\n    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();)\n    {\n        if (it->second.flags & CCoinsCacheEntry::DIRTY)\n        {\n            CoinEntry entry(&it->first);\n            CoinEntryRef entryRef(it->second.coin.nHeight, it->second.coin.nTxIndex, it->first.n);\n            if (it->second.coin.IsSpent())\n            {\n                batch.Erase(entry);\n                batch.Erase(entryRef);\n            }\n            else\n            {\n                batch.Write(entry, it->second.coin);\n                writeRefHashes.emplace_back(entryRef,it->first.getTransactionHash());\n            }\n            changed++;\n        }\n        count++;\n        CCoinsMap::iterator itOld = it++;\n        mapCoins.erase(itOld);\n    }\n    for (const auto& [entryRef, entryHash] : writeRefHashes)\n    {\n        batch.Write(entryRef, entryHash);\n    }\n    if (!hashBlock.IsNull())\n        batch.Write(DB_BEST_BLOCK, hashBlock);\n\n    bool ret = db.WriteBatch(batch);\n    LogPrint(BCLog::COINDB, \"Committed %u changed transaction outputs (out of %u) to coin database...\\n\", (unsigned int)changed, (unsigned int)count);\n    return ret;\n}\n\nsize_t CCoinsViewDB::EstimateSize() const\n{\n    return db.EstimateSize(DB_COIN, (char)(DB_COIN+1));\n}\n\nvoid CCoinsViewDB::GetAllCoins(std::map<COutPoint, Coin>& allCoins) const\n{\n    CCoinsViewCursor* cursor = Cursor();\n    if (cursor)\n    {\n        while (cursor->Valid())\n        {\n            COutPoint outPoint;\n            if (!cursor->GetKey(outPoint))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n\n            Coin outCoin;\n            if (!cursor->GetValue(outCoin))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n\n            allCoins.emplace(std::pair(outPoint, outCoin));\n\n            cursor->Next();\n        }\n        delete cursor;\n    }\n}\n\nvoid CCoinsViewDB::GetAllCoinsIndexBased(std::map<COutPoint, Coin>& allCoinsIndexBased) const\n{\n    CCoinsViewCursor* cursor = Cursor();\n    if (cursor)\n    {\n        while (cursor->Valid())\n        {\n            COutPoint outPoint;\n            if (!cursor->GetKey(outPoint))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n            \n            Coin outCoin;\n            if (!cursor->GetValue(outCoin))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n            \n            COutPoint indexBased(outCoin.nHeight, outCoin.nTxIndex, outPoint.n);\n\n            allCoinsIndexBased.emplace(std::pair(indexBased, outCoin));\n\n            cursor->Next();\n        }\n        delete cursor;\n    }\n}\n\nvoid CCoinsViewDB::GetAllCoinsIndexBasedDirect(std::map<COutPoint, Coin>& allCoinsIndexBased) const\n{\n    CCoinsViewCursor* cursor = Cursor();\n    if (cursor)\n    {\n        while (cursor->Valid())\n        {\n            COutPoint outPoint;\n            if (!cursor->GetKey(outPoint))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n            \n            Coin outCoin;\n            if (!cursor->GetValue(outCoin))\n                throw std::runtime_error(\"Error fetching record from witness cache.\");\n            \n            COutPoint indexBased(outCoin.nHeight, outCoin.nTxIndex, outPoint.n);\n\n            allCoinsIndexBased.emplace(std::pair(indexBased, outCoin));\n\n            cursor->Next();\n        }\n        delete cursor;\n    }\n}\n\nCBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / \"blocks\" / \"index\", nCacheSize, fMemory, fWipe) {\n}\n\nbool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {\n    return Read(std::pair(DB_BLOCK_FILES, nFile), info);\n}\n\nbool CBlockTreeDB::WriteReindexing(bool fReindexing) {\n    if (fReindexing)\n        return Write(DB_REINDEX_FLAG, '1');\n    else\n        return Erase(DB_REINDEX_FLAG);\n}\n\nbool CBlockTreeDB::ReadReindexing(bool &fReindexing) {\n    fReindexing = Exists(DB_REINDEX_FLAG);\n    return true;\n}\n\nbool CBlockTreeDB::ReadLastBlockFile(int &nFile) {\n    return Read(DB_LAST_BLOCK, nFile);\n}\n\nCCoinsViewCursor *CCoinsViewDB::Cursor() const\n{\n    CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());\n    /* It seems that there are no \"const iterators\" for LevelDB.  Since we\n       only need read operations on it, use a const-cast to get around\n       that restriction.  */\n    i->pcursor->Seek(DB_COIN);\n    // Cache key of first record\n    if (i->pcursor->Valid()) {\n        CoinEntry entry(&i->keyTmp.second);\n        i->pcursor->GetKey(entry);\n        i->keyTmp.first = entry.key;\n    } else {\n        i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false\n    }\n    return i;\n}\n\nbool CCoinsViewDBCursor::GetKey(COutPoint &key) const\n{\n    // Return cached key\n    if (keyTmp.first == DB_COIN) {\n        key = keyTmp.second;\n        return true;\n    }\n    return false;\n}\n\nbool CCoinsViewDBCursor::GetValue(Coin &coin) const\n{\n    return pcursor->GetValue(coin);\n}\n\nunsigned int CCoinsViewDBCursor::GetValueSize() const\n{\n    return pcursor->GetValueSize();\n}\n\nbool CCoinsViewDBCursor::Valid() const\n{\n    return keyTmp.first == DB_COIN;\n}\n\nvoid CCoinsViewDBCursor::Next()\n{\n    pcursor->Next();\n    CoinEntry entry(&keyTmp.second);\n    if (!pcursor->Valid() || !pcursor->GetKey(entry)) {\n        keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false\n    } else {\n        keyTmp.first = entry.key;\n    }\n}\n\nbool CBlockTreeDB::UpdateBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*>>& fileInfo, int nLastFile,\n                                   const std::vector<const CBlockIndex*>& vWriteIndices,\n                                   const std::vector<uint256>& vEraseHashes,\n                                   const std::set<std::pair<uint256, CDiskTxPos>>& vEraseTxIndexes,\n                                   const std::set<std::pair<uint256, CDiskTxPos>>& vWriteTxIndexes\n                                  )\n{\n    CDBBatch batch(*this);\n    for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++)\n    {\n        batch.Write(std::pair(DB_BLOCK_FILES, it->first), *it->second);\n    }\n    batch.Write(DB_LAST_BLOCK, nLastFile);\n    for (std::vector<const CBlockIndex*>::const_iterator it=vWriteIndices.begin(); it != vWriteIndices.end(); it++)\n    {\n        batch.Write(std::pair(DB_BLOCK_INDEX, (*it)->GetBlockHashPoW2()), CDiskBlockIndex(*it));\n    }\n    for (const uint256& hash: vEraseHashes)\n    {\n        batch.Erase(std::pair(DB_BLOCK_INDEX, hash));\n    }\n    for (const auto& [hash, diskPos]: vEraseTxIndexes)\n    {\n        (unused) diskPos;\n        batch.Erase(std::pair(DB_TXINDEX, hash));\n    }\n    for (const auto& [hash, diskPos]: vWriteTxIndexes)\n    {\n        batch.Write(std::pair(DB_TXINDEX, hash), diskPos);\n    }\n    return WriteBatch(batch, true);\n}\n\nbool CBlockTreeDB::EraseBatchSync(const std::vector<uint256>& vEraseHashes)\n{\n    CDBBatch batch(*this);\n    for (const uint256& hash: vEraseHashes)\n    {\n        batch.Erase(std::pair(DB_BLOCK_INDEX, hash));\n    }\n    return WriteBatch(batch, true);\n}\n\nbool CBlockTreeDB::MoveTxIndexDiskPos(std::map<CDiskBlockPos, CDiskBlockPos> vUpdateTxIndexes, std::set<std::pair<uint256, CDiskTxPos>>& vEraseTxIndexes, std::set<std::pair<uint256, CDiskTxPos>>& vWriteTxIndexes)\n{\n    std::unique_ptr<CDBIterator> pcursor(NewIterator());\n    pcursor->Seek(std::pair(DB_TXINDEX, uint256()));\n    while (pcursor->Valid())\n    {\n        std::pair<char, uint256> key;\n        if (pcursor->GetKey(key) && key.first == DB_TXINDEX)\n        {\n            CDiskTxPos diskTxPos;\n            if (pcursor->GetValue(diskTxPos))\n            {\n                vEraseTxIndexes.insert(std::pair(key.second, diskTxPos));\n                const auto& iter = vUpdateTxIndexes.find(diskTxPos);\n                if (iter != vUpdateTxIndexes.end())\n                {\n                    diskTxPos.nFile = iter->second.nFile;\n                    diskTxPos.nPos = iter->second.nPos;\n                    vWriteTxIndexes.insert(std::pair(key.second, diskTxPos));\n                }\n            }\n            pcursor->Next();\n        }\n        else\n        {\n            break;\n        }\n    }\n    return true;\n}\n\nbool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos)\n{\n    return Read(std::pair(DB_TXINDEX, txid), pos);\n}\n\nbool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect)\n{\n    CDBBatch batch(*this);\n    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)\n        batch.Write(std::pair(DB_TXINDEX, it->first), it->second);\n    return WriteBatch(batch);\n}\n\nbool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue)\n{\n    return Write(std::pair(DB_FLAG, name), fValue ? '1' : '0');\n}\n\nbool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue)\n{\n    char ch;\n    if (!Read(std::pair(DB_FLAG, name), ch))\n        return false;\n    fValue = ch == '1';\n    return true;\n}\n\nbool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)> insertBlockIndex)\n{\n    std::unique_ptr<CDBIterator> pcursor(NewIterator());\n\n    pcursor->Seek(std::pair(DB_BLOCK_INDEX, uint256()));\n\n    // Load mapBlockIndex\n    while (pcursor->Valid())\n    {\n        boost::this_thread::interruption_point();\n        std::pair<char, uint256> key;\n        if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {\n            CDiskBlockIndex diskindex;\n            if (pcursor->GetValue(diskindex)) {\n                // Construct block index object\n                CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHashPoW2());\n                // this insertBlockIndex can create an index block that is never loaded with data\n                pindexNew->pprev          = insertBlockIndex(diskindex.hashPrev);\n                pindexNew->nHeight        = diskindex.nHeight;\n                pindexNew->nFile          = diskindex.nFile;\n                pindexNew->nDataPos       = diskindex.nDataPos;\n                pindexNew->nUndoPos       = diskindex.nUndoPos;\n                pindexNew->nVersion       = diskindex.nVersion;\n                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;\n                pindexNew->nTime          = diskindex.nTime;\n                pindexNew->nBits          = diskindex.nBits;\n                pindexNew->nNonce         = diskindex.nNonce;\n                pindexNew->nStatus        = diskindex.nStatus;\n                // nStatus later used to check if a block index was created during loading but never filled\n                assert(pindexNew->nStatus != 0);\n                pindexNew->nTx            = diskindex.nTx;\n\n                pindexNew->nVersionPoW2Witness = diskindex.nVersionPoW2Witness;\n                pindexNew->nTimePoW2Witness = diskindex.nTimePoW2Witness;\n                pindexNew->hashMerkleRootPoW2Witness = diskindex.hashMerkleRootPoW2Witness;\n                pindexNew->witnessHeaderPoW2Sig = diskindex.witnessHeaderPoW2Sig;\n                pindexNew->witnessUTXODelta = diskindex.witnessUTXODelta;\n\n                /** Scrypt is used for block proof-of-work, but for purposes of performance the index internally uses sha256.\n                *  This check was considered unneccessary given the other safeguards like the genesis and checkpoints. */\n                //if (!CheckProofOfWork(pindexNew, Params().GetConsensus()))\n                    //return error(\"LoadBlockIndex(): CheckProofOfWork failed: %s\", pindexNew->ToString());\n\n                pcursor->Next();\n            } else {\n                return error(\"LoadBlockIndex() : failed to read value\");\n            }\n        } else {\n            break;\n        }\n    }\n\n    return true;\n}\n\nnamespace\n{\n\n//! Legacy class to deserialize pre-pertxout database entries without reindex.\nclass CCoins\n{\npublic:\n    //! whether transaction is a coinbase\n    bool fCoinBase;\n\n    //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped\n    std::vector<CTxOut> vout;\n\n    //! at which height this transaction was included in the active block chain\n    int nHeight;\n\n    //! empty constructor\n    CCoins() : fCoinBase(false), vout(0), nHeight(0) { }\n\n    template<typename Stream>\n    void Unserialize(Stream &s)\n    {\n        unsigned int nCode = 0;\n        // version\n        int nVersionDummy;\n        ::Unserialize(s, VARINT(nVersionDummy));\n        // header code\n        ::Unserialize(s, VARINT(nCode));\n        fCoinBase = nCode & 1;\n        std::vector<bool> vAvail(2, false);\n        vAvail[0] = (nCode & 2) != 0;\n        vAvail[1] = (nCode & 4) != 0;\n        unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);\n        // spentness bitmask\n        while (nMaskCode > 0)\n        {\n            unsigned char chAvail = 0;\n            ::Unserialize(s, chAvail);\n            for (unsigned int p = 0; p < 8; p++)\n            {\n                bool f = (chAvail & (1 << p)) != 0;\n                vAvail.push_back(f);\n            }\n            if (chAvail != 0)\n                nMaskCode--;\n        }\n        // txouts themself\n        vout.assign(vAvail.size(), CTxOut());\n        for (unsigned int i = 0; i < vAvail.size(); i++)\n        {\n            if (vAvail[i])\n                ::Unserialize(s, REF(CTxOutCompressor(vout[i])));\n        }\n        // coinbase height\n        ::Unserialize(s, VARINT(nHeight));\n    }\n\n    template<typename Stream>\n    void UnserializeLegacy(Stream &s)\n    {\n        unsigned int nCode = 0;\n        // version\n        int nVersionDummy;\n        ::Unserialize(s, VARINT(nVersionDummy));\n        // header code\n        ::Unserialize(s, VARINT(nCode));\n        fCoinBase = nCode & 1;\n        std::vector<bool> vAvail(2, false);\n        vAvail[0] = (nCode & 2) != 0;\n        vAvail[1] = (nCode & 4) != 0;\n        unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);\n        // spentness bitmask\n        while (nMaskCode > 0)\n        {\n            unsigned char chAvail = 0;\n            ::Unserialize(s, chAvail);\n            for (unsigned int p = 0; p < 8; p++)\n            {\n                bool f = (chAvail & (1 << p)) != 0;\n                vAvail.push_back(f);\n            }\n            if (chAvail != 0)\n                nMaskCode--;\n        }\n        // txouts themself\n        vout.assign(vAvail.size(), CTxOut());\n        for (unsigned int i = 0; i < vAvail.size(); i++)\n        {\n            if (vAvail[i])\n                ::Unserialize(s, REF(CTxOutCompressorLegacy(vout[i])));\n        }\n        // coinbase height\n        ::Unserialize(s, VARINT(nHeight));\n    }\n};\n\n}\n\n\n// For non backwards compatible/major upgrades we return true here and force the entire database to be regenerated.\nbool CCoinsViewDB::RequiresReindex()\n{\n    if (db.Exists(DB_VERSION))\n    {\n        db.Read(DB_VERSION, nPreviousVersion);\n    }\n    \n    // PHASE4 related update, store transaction index as part of output database.\n    if (nPreviousVersion < 2)\n    {\n        return true;\n    }\n        \n    return false;\n}\n    \n// Minor upgrades take place inside here, for major upgrades see 'RequiresReindex'\nbool CCoinsViewDB::Upgrade()\n{\n    if (nPreviousVersion == 2)\n    {\n        LogPrintf(\"Repairing V2 coindb index based utxo outpoints...\\n\");\n\n        CDBBatch batch(db);\n        size_t batch_size = 1 << 24;\n        \n        COutPoint cursorOutpoint(0, 0, 0);\n        \n        std::unique_ptr<CDBIterator> pcursor(db.NewIterator());\n        pcursor->Seek(std::pair(DB_COIN_REF, uint256()));        \n        LogPrintf(\"Erasing index based utxo outpoints...\\n\");\n        while (pcursor->Valid())\n        {\n            boost::this_thread::interruption_point();\n            CoinEntryRef coinEntryRef(cursorOutpoint);\n            if (pcursor->GetKey(coinEntryRef))\n            {\n                batch.Erase(coinEntryRef);\n            \n                if (batch.SizeEstimate() > batch_size)\n                {\n                    db.WriteBatch(batch);\n                    batch.Clear();\n                }\n            }\n            pcursor->Next();\n        }\n        db.WriteBatch(batch);\n        \n        pcursor->Seek(std::pair(DB_COIN, uint256()));\n        if (!pcursor->Valid())\n        {\n            LogPrintf(\"Failed to repair index based utxo outpoints...\\n\");\n            return false;\n        }\n        \n        LogPrintf(\"Regenerating index based utxo outpoints...\\n\");\n        while (pcursor->Valid())\n        {\n            boost::this_thread::interruption_point();\n            CoinEntry coinEntry(&cursorOutpoint);\n            if (pcursor->GetKey(coinEntry))\n            {\n                Coin coin;\n                if (!pcursor->GetValue(coin))\n                {\n                    return error(\"%s: cannot parse Coin record\", __func__);\n                }\n                CoinEntryRef refEntry(COutPoint(coin.nHeight, coin.nTxIndex, coinEntry.outpoint->n));\n                batch.Write(refEntry, coinEntry.outpoint->getTransactionHash());\n                if (batch.SizeEstimate() > batch_size)\n                {\n                    db.WriteBatch(batch);\n                    batch.Clear();\n                }\n                pcursor->Next();\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        db.WriteBatch(batch);\n        db.Write(DB_VERSION, (uint32_t)nCurrentVersion);\n    }\n    else if(nPreviousVersion == 3)\n    {\n        db.Write(DB_VERSION, (uint32_t)nCurrentVersion);\n    }\n    return true;\n}\n\nbool CCoinsViewDB::WriteVersion()\n{\n    std::unique_ptr<CDBIterator> pcursor(db.NewIterator());\n    pcursor->Seek(std::pair(DB_COINS, uint256()));\n    \n    if (!pcursor->Valid())\n    {\n        db.Write(DB_VERSION, (uint32_t)nCurrentVersion);\n        return true;\n    }\n    return true;\n}\n\n"
  },
  {
    "path": "src/txdb.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef TXDB_H\n#define TXDB_H\n\n#include \"coins.h\"\n#include \"dbwrapper.h\"\n#include \"chain.h\"\n\n#include <map>\n#include <string>\n#include <utility>\n#include <vector>\n\nclass CBlockIndex;\nclass CCoinsViewDBCursor;\nclass uint256;\nclass CWitViewDB;\n\n//! Compensate for extra memory peak (x1.5-x1.9) at flush time.\nstatic constexpr int DB_PEAK_USAGE_FACTOR = 2;\n//! No need to periodic flush if at least this much space still available.\nstatic constexpr int MAX_BLOCK_COINSDB_USAGE = 10 * DB_PEAK_USAGE_FACTOR;\n//! -dbcache default (MiB)\nstatic const int64_t nDefaultDbCache = 450;\n//! max. -dbcache (MiB)\nstatic const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;\n//! min. -dbcache (MiB)\nstatic const int64_t nMinDbCache = 4;\n//! Max memory allocated to block tree DB specific cache, if no -txindex (MiB)\nstatic const int64_t nMaxBlockDBCache = 2;\n//! Max memory allocated to block tree DB specific cache, if -txindex (MiB)\n// Unlike for the UTXO database, for the txindex scenario the leveldb cache make\n// a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991\nstatic const int64_t nMaxBlockDBAndTxIndexCache = 1024;\n//! Max memory allocated to coin DB specific cache (MiB)\nstatic const int64_t nMaxCoinsDBCache = 8;\n\nstruct CDiskTxPos : public CDiskBlockPos\n{\n    unsigned int nTxOffset; // after header\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(*(CDiskBlockPos*)this);\n        READWRITE(VARINT(nTxOffset));\n    }\n\n    CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {\n    }\n\n    CDiskTxPos() {\n        SetNull();\n    }\n\n    void SetNull() {\n        CDiskBlockPos::SetNull();\n        nTxOffset = 0;\n    }\n    \n    friend bool operator< (const CDiskTxPos a, const CDiskTxPos b)\n    {\n        if ((CDiskBlockPos)a < (CDiskBlockPos)b)\n            return true;\n        if ((CDiskBlockPos)b < (CDiskBlockPos)a)\n            return false;\n        if (a.nTxOffset < b.nTxOffset)\n            return true;\n        return false;\n    }\n};\n\n/** CCoinsView backed by the coin database (chainstate/) */\nclass CCoinsViewDB : public CCoinsView\n{\nprotected:\n    CDBWrapper db;\npublic:\n    CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false, std::string name=\"chainstate\");\n\n    bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const override;\n    bool HaveCoin(const COutPoint &outpoint) const override;\n    uint256 GetBestBlock() const override;\n    bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;\n    CCoinsViewCursor *Cursor() const override;\n\n    //fixme: (PHASE5) We can remove some of these once phase4 is active.\n    //We will first need to figure out how to handle testnet however.\n    void SetPhase2ActivationHash(const uint256 &hashPhase2ActivationPoint);\n    uint256 GetPhase2ActivationHash();\n    void SetPhase3ActivationHash(const uint256 &hashPhase3ActivationPoint);\n    uint256 GetPhase3ActivationHash();\n    void SetPhase4ActivationHash(const uint256 &hashPhase4ActivationPoint);\n    uint256 GetPhase4ActivationHash();\n    void SetPhase5ActivationHash(const uint256 &hashPhase5ActivationPoint);\n    uint256 GetPhase5ActivationHash();\n\n    //! Attempt to update from an older database format. Returns whether an error occurred.\n    bool Upgrade();\n    \n    //! In extreme cases an update might require a complete re-index; if this is the case then this function will return true.\n    bool RequiresReindex();\n    \n    //! Write the version number after creating a new database; no-op if its an existing database with an existing version.\n    bool WriteVersion();\n    \n    \n    size_t EstimateSize() const override;\n    // For handling of upgrades.\n    uint32_t nCurrentVersion=4;\n    uint32_t nPreviousVersion=1;\n\n    void GetAllCoins(std::map<COutPoint, Coin>& allCoins) const override;\n    void GetAllCoinsIndexBased(std::map<COutPoint, Coin>& allCoins) const override;\n    void GetAllCoinsIndexBasedDirect(std::map<COutPoint, Coin>& allCoins) const override;\n};\n\n/** CWitViewDB backed by the witness database (witstate/) */\nclass CWitViewDB : public CCoinsViewDB\n{\npublic:\n    CWitViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);\n};\n\n/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */\nclass CCoinsViewDBCursor: public CCoinsViewCursor\n{\npublic:\n    ~CCoinsViewDBCursor() {}\n\n    bool GetKey(COutPoint &key) const;\n    bool GetValue(Coin &coin) const;\n    unsigned int GetValueSize() const;\n\n    bool Valid() const;\n    void Next();\n\nprivate:\n    CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):\n        CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}\n    std::unique_ptr<CDBIterator> pcursor;\n    std::pair<char, COutPoint> keyTmp;\n\n    friend class CCoinsViewDB;\n};\n\n/** Access to the block database (blocks/index/) */\nclass CBlockTreeDB : public CDBWrapper\n{\npublic:\n    CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);\nprivate:\n    CBlockTreeDB(const CBlockTreeDB&);\n    void operator=(const CBlockTreeDB&);\npublic:\n    bool UpdateBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile,\n                         const std::vector<const CBlockIndex*>& vWriteIndices,\n                         const std::vector<uint256>& vEraseHashes,\n                         const std::set<std::pair<uint256, CDiskTxPos>>& vEraseTxIndexes,\n                         const std::set<std::pair<uint256, CDiskTxPos>>& vWriteTxIndexes\n                        );\n    bool EraseBatchSync(const std::vector<uint256>& vEraseHashes);\n    // Populate vEraseTxIndexes/vWriteTxIndexes with proposed changes (if any) for a moved CDiskBlockPos\n    // Note this doesn't actually perform the changes, to do that pass the returned results into 'UpdateBatchSync'\n    // NB! This must iterate the entire set for each call so is relatively slow\n    bool MoveTxIndexDiskPos(std::map<CDiskBlockPos, CDiskBlockPos> vUpdateTxIndexes, std::set<std::pair<uint256, CDiskTxPos>>& vEraseTxIndexes, std::set<std::pair<uint256, CDiskTxPos>>& vWriteTxIndexes);\n    bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);\n    bool ReadLastBlockFile(int &nFile);\n    bool WriteReindexing(bool fReindex);\n    bool ReadReindexing(bool &fReindex);\n    bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);\n    bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);\n    bool WriteFlag(const std::string &name, bool fValue);\n    bool ReadFlag(const std::string &name, bool &fValue);\n    bool LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)> insertBlockIndex);\n};\n\n#endif\n"
  },
  {
    "path": "src/txmempool.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"txmempool.h\"\n\n#include \"consensus/consensus.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"policy/policy.h\"\n#include \"policy/fees.h\"\n#include \"streams.h\"\n#include \"timedata.h\"\n#include \"util.h\"\n#include \"util/moneystr.h\"\n#include \"util/time.h\"\n\n#include <boost/foreach.hpp>\n#include \"checkpoints.h\"\n\nCTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,\n                                 int64_t _nTime, unsigned int _entryHeight,\n                                 uint64_t _spendCoinbaseCount, int64_t _sigOpsCost, LockPoints lp):\n    tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),\n    spendCoinbaseCount(_spendCoinbaseCount), sigOpCost(_sigOpsCost), lockPoints(lp)\n{\n    nTxWeight = tx->GetTotalSize();\n    nUsageSize = RecursiveDynamicUsage(tx);\n\n    nCountWithDescendants = 1;\n    nSizeWithDescendants = GetTxSize();\n    nModFeesWithDescendants = nFee;\n\n    feeDelta = 0;\n\n    nCountWithAncestors = 1;\n    nSizeWithAncestors = GetTxSize();\n    nModFeesWithAncestors = nFee;\n    nSigOpCostWithAncestors = sigOpCost;\n}\n\nCTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)\n{\n    *this = other;\n}\n\nvoid CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)\n{\n    nModFeesWithDescendants += newFeeDelta - feeDelta;\n    nModFeesWithAncestors += newFeeDelta - feeDelta;\n    feeDelta = newFeeDelta;\n}\n\nvoid CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)\n{\n    lockPoints = lp;\n}\n\nsize_t CTxMemPoolEntry::GetTxSize() const\n{\n    return GetVirtualTransactionSize(nTxWeight, sigOpCost);\n}\n\nsize_t CTxMemPoolEntry::GetTxSizeDiscounted() const\n{\n    return GetVirtualTransactionSizeDiscounted(nTxWeight, spendCoinbaseCount, sigOpCost);\n}\n\n// Update the given tx for any in-mempool descendants.\n// Assumes that setMemPoolChildren is correct for the given tx and all\n// descendants.\nvoid CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)\n{\n    setEntries stageEntries, setAllDescendants;\n    stageEntries = GetMemPoolChildren(updateIt);\n\n    while (!stageEntries.empty()) {\n        const txiter cit = *stageEntries.begin();\n        setAllDescendants.insert(cit);\n        stageEntries.erase(cit);\n        const setEntries &setChildren = GetMemPoolChildren(cit);\n        for(const txiter childEntry : setChildren) {\n            cacheMap::iterator cacheIt = cachedDescendants.find(childEntry);\n            if (cacheIt != cachedDescendants.end()) {\n                // We've already calculated this one, just add the entries for this set\n                // but don't traverse again.\n                for(const txiter cacheEntry : cacheIt->second) {\n                    setAllDescendants.insert(cacheEntry);\n                }\n            } else if (!setAllDescendants.count(childEntry)) {\n                // Schedule for later processing\n                stageEntries.insert(childEntry);\n            }\n        }\n    }\n    // setAllDescendants now contains all in-mempool descendants of updateIt.\n    // Update and add to cached descendant map\n    int64_t modifySize = 0;\n    CAmount modifyFee = 0;\n    int64_t modifyCount = 0;\n    for(txiter cit : setAllDescendants) {\n        if (!setExclude.count(cit->GetTx().GetHash())) {\n            modifySize += cit->GetTxSize();\n            modifyFee += cit->GetModifiedFee();\n            modifyCount++;\n            cachedDescendants[updateIt].insert(cit);\n            // Update ancestor state for each descendant\n            mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost()));\n        }\n    }\n    mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));\n}\n\n// vHashesToUpdate is the set of transaction hashes from a disconnected block\n// which has been re-added to the mempool.\n// for each entry, look for descendants that are outside vHashesToUpdate, and\n// add fee/size information for such descendants to the parent.\n// for each such descendant, also update the ancestor state to include the parent.\nvoid CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate)\n{\n    LOCK(cs);\n    // For each entry in vHashesToUpdate, store the set of in-mempool, but not\n    // in-vHashesToUpdate transactions, so that we don't have to recalculate\n    // descendants when we come across a previously seen entry.\n    cacheMap mapMemPoolDescendantsToUpdate;\n\n    // Use a set for lookups into vHashesToUpdate (these entries are already\n    // accounted for in the state of their ancestors)\n    std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end());\n\n    // Iterate in reverse, so that whenever we are looking at at a transaction\n    // we are sure that all in-mempool descendants have already been processed.\n    // This maximizes the benefit of the descendant cache and guarantees that\n    // setMemPoolChildren will be updated, an assumption made in\n    // UpdateForDescendants.\n    BOOST_REVERSE_FOREACH(const uint256 &hash, vHashesToUpdate) {\n        // we cache the in-mempool children to avoid duplicate updates\n        setEntries setChildren;\n        // calculate children from mapNextTx\n        txiter it = mapTx.find(hash);\n        if (it == mapTx.end()) {\n            continue;\n        }\n        auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));\n        // First calculate the children, and update setMemPoolChildren to\n        // include them, and update their setMemPoolParents to include this tx.\n        for (; iter != mapNextTx.end() && iter->first->getTransactionHash() == hash; ++iter) {\n            const uint256 &childHash = iter->second->GetHash();\n            txiter childIter = mapTx.find(childHash);\n            assert(childIter != mapTx.end());\n            // We can skip updating entries we've encountered before or that\n            // are in the block (which are already accounted for).\n            if (setChildren.insert(childIter).second && !setAlreadyIncluded.count(childHash)) {\n                UpdateChild(it, childIter, true);\n                UpdateParent(childIter, it, true);\n            }\n        }\n        UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded);\n    }\n}\n\nbool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const\n{\n    LOCK(cs);\n\n    setEntries parentHashes;\n    const CTransaction &tx = entry.GetTx();\n\n    if (fSearchForParents) {\n        // Get parents of this transaction that are in the mempool\n        // GetMemPoolParents() is only valid for entries in the mempool, so we\n        // iterate mapTx to find parents.\n        for (unsigned int i = 0; i < tx.vin.size(); i++) {\n            if (tx.vin[i].GetPrevOut().isHash) {\n                txiter piter = mapTx.find(tx.vin[i].GetPrevOut().getTransactionHash());\n                if (piter != mapTx.end()) {\n                    parentHashes.insert(piter);\n                    if (parentHashes.size() + 1 > limitAncestorCount) {\n                        errString = strprintf(\"too many unconfirmed parents [limit: %u]\", limitAncestorCount);\n                        return false;\n                    }\n                }\n            }\n        }\n    } else {\n        // If we're not searching for parents, we require this to be an\n        // entry in the mempool already.\n        txiter it = mapTx.iterator_to(entry);\n        parentHashes = GetMemPoolParents(it);\n    }\n\n    size_t totalSizeWithAncestors = entry.GetTxSize();\n\n    while (!parentHashes.empty()) {\n        txiter stageit = *parentHashes.begin();\n\n        setAncestors.insert(stageit);\n        parentHashes.erase(stageit);\n        totalSizeWithAncestors += stageit->GetTxSize();\n\n        if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > limitDescendantSize) {\n            errString = strprintf(\"exceeds descendant size limit for tx %s [limit: %u]\", stageit->GetTx().GetHash().ToString(), limitDescendantSize);\n            return false;\n        } else if (stageit->GetCountWithDescendants() + 1 > limitDescendantCount) {\n            errString = strprintf(\"too many descendants for tx %s [limit: %u]\", stageit->GetTx().GetHash().ToString(), limitDescendantCount);\n            return false;\n        } else if (totalSizeWithAncestors > limitAncestorSize) {\n            errString = strprintf(\"exceeds ancestor size limit [limit: %u]\", limitAncestorSize);\n            return false;\n        }\n\n        const setEntries & setMemPoolParents = GetMemPoolParents(stageit);\n        for(const txiter &phash : setMemPoolParents) {\n            // If this is a new ancestor, add it.\n            if (setAncestors.count(phash) == 0) {\n                parentHashes.insert(phash);\n            }\n            if (parentHashes.size() + setAncestors.size() + 1 > limitAncestorCount) {\n                errString = strprintf(\"too many unconfirmed ancestors [limit: %u]\", limitAncestorCount);\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\nvoid CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)\n{\n    setEntries parentIters = GetMemPoolParents(it);\n    // add or remove this tx as a child of each parent\n    for(txiter piter : parentIters) {\n        UpdateChild(piter, it, add);\n    }\n    const int64_t updateCount = (add ? 1 : -1);\n    const int64_t updateSize = updateCount * it->GetTxSize();\n    const CAmount updateFee = updateCount * it->GetModifiedFee();\n    for(txiter ancestorIt : setAncestors) {\n        mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));\n    }\n}\n\nvoid CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors)\n{\n    int64_t updateCount = setAncestors.size();\n    int64_t updateSize = 0;\n    CAmount updateFee = 0;\n    int64_t updateSigOpsCost = 0;\n    for(txiter ancestorIt : setAncestors) {\n        updateSize += ancestorIt->GetTxSize();\n        updateFee += ancestorIt->GetModifiedFee();\n        updateSigOpsCost += ancestorIt->GetSigOpCost();\n    }\n    mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost));\n}\n\nvoid CTxMemPool::UpdateChildrenForRemoval(txiter it)\n{\n    const setEntries &setMemPoolChildren = GetMemPoolChildren(it);\n    for(txiter updateIt : setMemPoolChildren) {\n        UpdateParent(updateIt, it, false);\n    }\n}\n\nvoid CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants)\n{\n    // For each entry, walk back all ancestors and decrement size associated with this\n    // transaction\n    const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();\n    if (updateDescendants) {\n        // updateDescendants should be true whenever we're not recursively\n        // removing a tx and all its descendants, eg when a transaction is\n        // confirmed in a block.\n        // Here we only update statistics and not data in mapLinks (which\n        // we need to preserve until we're finished with all operations that\n        // need to traverse the mempool).\n        for(txiter removeIt : entriesToRemove) {\n            setEntries setDescendants;\n            CalculateDescendants(removeIt, setDescendants);\n            setDescendants.erase(removeIt); // don't update state for self\n            int64_t modifySize = -((int64_t)removeIt->GetTxSize());\n            CAmount modifyFee = -removeIt->GetModifiedFee();\n            int modifySigOps = -removeIt->GetSigOpCost();\n            for(txiter dit : setDescendants) {\n                mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps));\n            }\n        }\n    }\n    for(txiter removeIt : entriesToRemove) {\n        setEntries setAncestors;\n        const CTxMemPoolEntry &entry = *removeIt;\n        std::string dummy;\n        // Since this is a tx that is already in the mempool, we can call CMPA\n        // with fSearchForParents = false.  If the mempool is in a consistent\n        // state, then using true or false should both be correct, though false\n        // should be a bit faster.\n        // However, if we happen to be in the middle of processing a reorg, then\n        // the mempool can be in an inconsistent state.  In this case, the set\n        // of ancestors reachable via mapLinks will be the same as the set of \n        // ancestors whose packages include this transaction, because when we\n        // add a new transaction to the mempool in addUnchecked(), we assume it\n        // has no children, and in the case of a reorg where that assumption is\n        // false, the in-mempool children aren't linked to the in-block tx's\n        // until UpdateTransactionsFromBlock() is called.\n        // So if we're being called during a reorg, ie before\n        // UpdateTransactionsFromBlock() has been called, then mapLinks[] will\n        // differ from the set of mempool parents we'd calculate by searching,\n        // and it's important that we use the mapLinks[] notion of ancestor\n        // transactions as the set of things to update for removal.\n        CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);\n        // Note that UpdateAncestorsOf severs the child links that point to\n        // removeIt in the entries for the parents of removeIt.\n        UpdateAncestorsOf(false, removeIt, setAncestors);\n    }\n    // After updating all the ancestor sizes, we can now sever the link between each\n    // transaction being removed and any mempool children (ie, update setMemPoolParents\n    // for each direct child of a transaction being removed).\n    for(txiter removeIt : entriesToRemove) {\n        UpdateChildrenForRemoval(removeIt);\n    }\n}\n\nvoid CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)\n{\n    nSizeWithDescendants += modifySize;\n    assert(int64_t(nSizeWithDescendants) > 0);\n    nModFeesWithDescendants += modifyFee;\n    nCountWithDescendants += modifyCount;\n    assert(int64_t(nCountWithDescendants) > 0);\n}\n\nvoid CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps)\n{\n    nSizeWithAncestors += modifySize;\n    assert(int64_t(nSizeWithAncestors) > 0);\n    nModFeesWithAncestors += modifyFee;\n    nCountWithAncestors += modifyCount;\n    assert(int64_t(nCountWithAncestors) > 0);\n    nSigOpCostWithAncestors += modifySigOps;\n    assert(int(nSigOpCostWithAncestors) >= 0);\n}\n\nCTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :\n    nTransactionsUpdated(0), minerPolicyEstimator(estimator)\n{\n    _clear(); //lock free clear\n\n    // Sanity checks off by default for performance, because otherwise\n    // accepting transactions becomes O(N^2) where N is the number\n    // of transactions in the pool\n    nCheckFrequency = 0;\n}\n\nbool CTxMemPool::isSpent(const COutPoint& outpoint)\n{\n    LOCK(cs);\n    return mapNextTx.count(outpoint);\n}\n\nunsigned int CTxMemPool::GetTransactionsUpdated() const\n{\n    LOCK(cs);\n    return nTransactionsUpdated;\n}\n\nvoid CTxMemPool::AddTransactionsUpdated(unsigned int n)\n{\n    LOCK(cs);\n    nTransactionsUpdated += n;\n}\n\nbool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)\n{\n    NotifyEntryAdded(entry.GetSharedTx());\n    // Add to memory pool without checking anything.\n    // Used by AcceptToMemoryPool(), which DOES do\n    // all the appropriate checks.\n    LOCK(cs);\n    indexed_transaction_set::iterator newit = mapTx.insert(entry).first;\n    mapLinks.insert(std::pair(newit, TxLinks()));\n\n    // Update transaction for any feeDelta created by PrioritiseTransaction\n    // TODO: refactor so that the fee delta is calculated before inserting\n    // into mapTx.\n    std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);\n    if (pos != mapDeltas.end()) {\n        const CAmount &delta = pos->second;\n        if (delta) {\n            mapTx.modify(newit, update_fee_delta(delta));\n        }\n    }\n\n    // Update cachedInnerUsage to include contained transaction's usage.\n    // (When we update the entry for in-mempool parents, memory usage will be\n    // further updated.)\n    cachedInnerUsage += entry.DynamicMemoryUsage();\n\n    const CTransaction& tx = newit->GetTx();\n    std::set<uint256> setParentTransactions;\n    for (unsigned int i = 0; i < tx.vin.size(); i++) {\n        mapNextTx.insert(std::pair(&tx.vin[i].GetPrevOut(), &tx));\n        uint256 txHash;\n        if (GetTxHash(tx.vin[i].GetPrevOut(), txHash))\n            setParentTransactions.insert(txHash);\n    }\n    // Don't bother worrying about child transactions of this one.\n    // Normal case of a new transaction arriving is that there can't be any\n    // children, because such children would be orphans.\n    // An exception to that is if a transaction enters that used to be in a block.\n    // In that case, our disconnect block logic will call UpdateTransactionsFromBlock\n    // to clean up the mess we're leaving here.\n\n    // Update ancestors with information about this tx\n    for (const uint256 &phash : setParentTransactions) {\n        txiter pit = mapTx.find(phash);\n        if (pit != mapTx.end()) {\n            UpdateParent(newit, pit, true);\n        }\n    }\n    UpdateAncestorsOf(true, newit, setAncestors);\n    UpdateEntryForAncestors(newit, setAncestors);\n\n    nTransactionsUpdated++;\n    totalTxSize += entry.GetTxSize();\n    if (minerPolicyEstimator && (Params().IsTestnet() || ((uint64_t)entry.GetHeight()>(uint64_t)Checkpoints::LastCheckPointHeight()))) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);}\n\n    vTxHashes.emplace_back(tx.GetWitnessHash(), newit);\n    newit->vTxHashesIdx = vTxHashes.size() - 1;\n\n    return true;\n}\n\nvoid CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)\n{\n    NotifyEntryRemoved(it->GetSharedTx(), reason);\n    const uint256 hash = it->GetTx().GetHash();\n    for(const CTxIn& txin : it->GetTx().vin)\n        mapNextTx.erase(txin.GetPrevOut());\n\n    if (vTxHashes.size() > 1) {\n        vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back());\n        vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx;\n        vTxHashes.pop_back();\n        if (vTxHashes.size() * 2 < vTxHashes.capacity())\n            vTxHashes.shrink_to_fit();\n    } else\n        vTxHashes.clear();\n\n    totalTxSize -= it->GetTxSize();\n    cachedInnerUsage -= it->DynamicMemoryUsage();\n    cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children);\n    mapLinks.erase(it);\n    mapTx.erase(it);\n    nTransactionsUpdated++;\n    if (minerPolicyEstimator && (Params().IsTestnet() || ((uint64_t)it->GetHeight()>(uint64_t)Checkpoints::LastCheckPointHeight()))) {minerPolicyEstimator->removeTx(hash, false);}\n}\n\n// Calculates descendants of entry that are not already in setDescendants, and adds to\n// setDescendants. Assumes entryit is already a tx in the mempool and setMemPoolChildren\n// is correct for tx and all descendants.\n// Also assumes that if an entry is in setDescendants already, then all\n// in-mempool descendants of it are already in setDescendants as well, so that we\n// can save time by not iterating over those entries.\nvoid CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants)\n{\n    setEntries stage;\n    if (setDescendants.count(entryit) == 0) {\n        stage.insert(entryit);\n    }\n    // Traverse down the children of entry, only adding children that are not\n    // accounted for in setDescendants already (because those children have either\n    // already been walked, or will be walked in this iteration).\n    while (!stage.empty()) {\n        txiter it = *stage.begin();\n        setDescendants.insert(it);\n        stage.erase(it);\n\n        const setEntries &setChildren = GetMemPoolChildren(it);\n        for(const txiter &childiter : setChildren) {\n            if (!setDescendants.count(childiter)) {\n                stage.insert(childiter);\n            }\n        }\n    }\n}\n\nvoid CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason)\n{\n    // Remove transaction from memory pool\n    {\n        LOCK(cs);\n        setEntries txToRemove;\n        txiter origit = mapTx.find(origTx.GetHash());\n        if (origit != mapTx.end()) {\n            txToRemove.insert(origit);\n        } else {\n            // When recursively removing but origTx isn't in the mempool\n            // be sure to remove any children that are in the pool. This can\n            // happen during chain re-orgs if origTx isn't re-accepted into\n            // the mempool for any reason.\n            for (unsigned int i = 0; i < origTx.vout.size(); i++) {\n                auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i));\n                if (it == mapNextTx.end())\n                    continue;\n                txiter nextit = mapTx.find(it->second->GetHash());\n                assert(nextit != mapTx.end());\n                txToRemove.insert(nextit);\n            }\n        }\n        setEntries setAllRemoves;\n        for(txiter it : txToRemove) {\n            CalculateDescendants(it, setAllRemoves);\n        }\n\n        RemoveStaged(setAllRemoves, false, reason);\n    }\n}\n\nvoid CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags)\n{\n    // Remove transactions spending a coinbase which are now immature and no-longer-final transactions\n    LOCK(cs);\n    setEntries txToRemove;\n    for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {\n        const CTransaction& tx = it->GetTx();\n        LockPoints lp = it->GetLockPoints();\n        \n        bool validLP =  TestLockPointValidity(&lp);\n        if (!CheckFinalTx(tx, chainActive, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) {\n            // Note if CheckSequenceLocks fails the LockPoints may still be invalid\n            // So it's critical that we remove the tx and not depend on the LockPoints.\n            txToRemove.insert(it);\n        } else if (it->GetSpendsCoinbase()) {\n            for(const CTxIn& txin : tx.vin) {\n                uint256 txHash;\n                if (!GetTxHash(txin.GetPrevOut(), txHash))\n                    continue;\n                indexed_transaction_set::const_iterator it2 = mapTx.find(txHash);\n                if (it2 != mapTx.end())\n                    continue;\n                const Coin &coin = pcoins->AccessCoin(txin.GetPrevOut());\n                if (nCheckFrequency != 0) assert(!coin.IsSpent());\n                if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {\n                    txToRemove.insert(it);\n                    break;\n                }\n            }\n        }\n        if (!validLP) {\n            mapTx.modify(it, update_lock_points(lp));\n        }\n    }\n    setEntries setAllRemoves;\n    for (txiter it : txToRemove) {\n        CalculateDescendants(it, setAllRemoves);\n    }\n    RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);\n}\n\nvoid CTxMemPool::removeConflicts(const CTransaction &tx)\n{\n    // Remove transactions which depend on inputs of tx, recursively\n    LOCK(cs);\n    for(const CTxIn &txin : tx.vin) {\n        auto it = mapNextTx.find(txin.GetPrevOut());\n        if (it != mapNextTx.end()) {\n            const CTransaction &txConflict = *it->second;\n            if (txConflict != tx)\n            {\n                ClearPrioritisation(txConflict.GetHash());\n                removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT);\n            }\n        }\n    }\n}\n\n/**\n * Called when a block is connected. Removes from mempool and updates the miner fee estimator.\n */\nvoid CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight)\n{\n    LOCK(cs);\n    std::vector<const CTxMemPoolEntry*> entries;\n    for (const auto& tx : vtx)\n    {\n        uint256 hash = tx->GetHash();\n\n        indexed_transaction_set::iterator i = mapTx.find(hash);\n        if (i != mapTx.end())\n            entries.push_back(&*i);\n    }\n    // Before the txs in the new block have been removed from the mempool, update policy estimates\n    if (minerPolicyEstimator && (Params().IsTestnet() || ((uint64_t)nBlockHeight>(uint64_t)Checkpoints::LastCheckPointHeight()))) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}\n    for (const auto& tx : vtx)\n    {\n        txiter it = mapTx.find(tx->GetHash());\n        if (it != mapTx.end()) {\n            setEntries stage;\n            stage.insert(it);\n            RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);\n        }\n        removeConflicts(*tx);\n        ClearPrioritisation(tx->GetHash());\n    }\n    lastRollingFeeUpdate = GetTime();\n    blockSinceLastRollingFeeBump = true;\n}\n\nvoid CTxMemPool::_clear()\n{\n    mapLinks.clear();\n    mapTx.clear();\n    mapNextTx.clear();\n    totalTxSize = 0;\n    cachedInnerUsage = 0;\n    lastRollingFeeUpdate = GetTime();\n    blockSinceLastRollingFeeBump = false;\n    rollingMinimumFeeRate = 0;\n    ++nTransactionsUpdated;\n}\n\nvoid CTxMemPool::clear()\n{\n    LOCK(cs);\n    _clear();\n}\n\nvoid CTxMemPool::check(const CCoinsViewCache *pcoins) const\n{\n    if (nCheckFrequency == 0)\n        return;\n\n    if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)\n        return;\n\n    LogPrint(BCLog::MEMPOOL, \"Checking mempool with %u transactions and %u inputs\\n\", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());\n\n    uint64_t checkTotal = 0;\n    uint64_t innerUsage = 0;\n\n    CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));\n    const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate);\n\n    LOCK(cs);\n    std::list<const CTxMemPoolEntry*> waitingOnDependants;\n    for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {\n        unsigned int i = 0;\n        checkTotal += it->GetTxSize();\n        innerUsage += it->DynamicMemoryUsage();\n        const CTransaction& tx = it->GetTx();\n        txlinksMap::const_iterator linksiter = mapLinks.find(it);\n        assert(linksiter != mapLinks.end());\n        const TxLinks &links = linksiter->second;\n        innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);\n        bool fDependsWait = false;\n        setEntries setParentCheck;\n        int64_t parentSizes = 0;\n        int64_t parentSigOpCost = 0;\n        for(const CTxIn &txin : tx.vin) {\n            // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.\n            uint256 txHash;\n            indexed_transaction_set::const_iterator it2 = GetTxHash(txin.GetPrevOut(), txHash)\n                                                              ? mapTx.find(txHash)\n                                                              : mapTx.end();\n            if (it2 != mapTx.end()) {\n                const CTransaction& tx2 = it2->GetTx();\n                assert(tx2.vout.size() > txin.GetPrevOut().n && !tx2.vout[txin.GetPrevOut().n].IsNull());\n                fDependsWait = true;\n                if (setParentCheck.insert(it2).second) {\n                    parentSizes += it2->GetTxSize();\n                    parentSigOpCost += it2->GetSigOpCost();\n                }\n            } else {\n                assert(pcoins->HaveCoin(txin.GetPrevOut()));\n            }\n            // Check whether its inputs are marked in mapNextTx.\n            auto it3 = mapNextTx.find(txin.GetPrevOut());\n            assert(it3 != mapNextTx.end());\n            assert(it3->first == &txin.GetPrevOut());\n            assert(it3->second == &tx);\n            i++;\n        }\n        assert(setParentCheck == GetMemPoolParents(it));\n        // Verify ancestor state is correct.\n        setEntries setAncestors;\n        uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();\n        std::string dummy;\n        CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);\n        uint64_t nCountCheck = setAncestors.size() + 1;\n        uint64_t nSizeCheck = it->GetTxSize();\n        CAmount nFeesCheck = it->GetModifiedFee();\n        int64_t nSigOpCheck = it->GetSigOpCost();\n\n        for(txiter ancestorIt : setAncestors) {\n            nSizeCheck += ancestorIt->GetTxSize();\n            nFeesCheck += ancestorIt->GetModifiedFee();\n            nSigOpCheck += ancestorIt->GetSigOpCost();\n        }\n\n        assert(it->GetCountWithAncestors() == nCountCheck);\n        assert(it->GetSizeWithAncestors() == nSizeCheck);\n        assert(it->GetSigOpCostWithAncestors() == nSigOpCheck);\n        assert(it->GetModFeesWithAncestors() == nFeesCheck);\n\n        // Check children against mapNextTx\n        CTxMemPool::setEntries setChildrenCheck;\n        auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));\n        int64_t childSizes = 0;\n        for (; iter != mapNextTx.end(); ++iter) {\n            uint256 txHash;\n            if (GetTxHash(*iter->first, txHash) && txHash != it->GetTx().GetHash())\n                break;\n            txiter childit = mapTx.find(iter->second->GetHash());\n            assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions\n            if (setChildrenCheck.insert(childit).second) {\n                childSizes += childit->GetTxSize();\n            }\n        }\n        assert(setChildrenCheck == GetMemPoolChildren(it));\n        // Also check to make sure size is greater than sum with immediate children.\n        // just a sanity check, not definitive that this calc is correct...\n        assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());\n\n        if (fDependsWait)\n            waitingOnDependants.push_back(&(*it));\n        else {\n            CValidationState state;\n            bool fCheckResult = tx.IsCoinBase() ||\n                Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, nullptr);\n            assert(fCheckResult);\n            UpdateCoins(tx, mempoolDuplicate, MEMPOOL_HEIGHT, MEMPOOL_INDEX);\n        }\n    }\n    unsigned int stepsSinceLastRemove = 0;\n    while (!waitingOnDependants.empty()) {\n        const CTxMemPoolEntry* entry = waitingOnDependants.front();\n        waitingOnDependants.pop_front();\n        CValidationState state;\n        if (!mempoolDuplicate.HaveInputs(entry->GetTx())) {\n            waitingOnDependants.push_back(entry);\n            stepsSinceLastRemove++;\n            assert(stepsSinceLastRemove < waitingOnDependants.size());\n        } else {\n            bool fCheckResult = entry->GetTx().IsCoinBase() ||\n                Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, nullptr);\n            assert(fCheckResult);\n            UpdateCoins(entry->GetTx(), mempoolDuplicate, MEMPOOL_HEIGHT, MEMPOOL_INDEX);\n            stepsSinceLastRemove = 0;\n        }\n    }\n    for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {\n        uint256 hash = it->second->GetHash();\n        indexed_transaction_set::const_iterator it2 = mapTx.find(hash);\n        const CTransaction& tx = it2->GetTx();\n        assert(it2 != mapTx.end());\n        assert(&tx == it->second);\n    }\n\n    assert(totalTxSize == checkTotal);\n    assert(innerUsage == cachedInnerUsage);\n}\n\nbool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb)\n{\n    LOCK(cs);\n    indexed_transaction_set::const_iterator i = mapTx.find(hasha);\n    if (i == mapTx.end()) return false;\n    indexed_transaction_set::const_iterator j = mapTx.find(hashb);\n    if (j == mapTx.end()) return true;\n    uint64_t counta = i->GetCountWithAncestors();\n    uint64_t countb = j->GetCountWithAncestors();\n    if (counta == countb) {\n        return CompareTxMemPoolEntryByScore()(*i, *j);\n    }\n    return counta < countb;\n}\n\nnamespace {\nclass DepthAndScoreComparator\n{\npublic:\n    bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b)\n    {\n        uint64_t counta = a->GetCountWithAncestors();\n        uint64_t countb = b->GetCountWithAncestors();\n        if (counta == countb) {\n            return CompareTxMemPoolEntryByScore()(*a, *b);\n        }\n        return counta < countb;\n    }\n};\n}\n\nstd::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const\n{\n    std::vector<indexed_transaction_set::const_iterator> iters;\n    AssertLockHeld(cs);\n\n    iters.reserve(mapTx.size());\n\n    for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {\n        iters.push_back(mi);\n    }\n    std::sort(iters.begin(), iters.end(), DepthAndScoreComparator());\n    return iters;\n}\n\nvoid CTxMemPool::queryHashes(std::vector<uint256>& vtxid)\n{\n    LOCK(cs);\n    auto iters = GetSortedDepthAndScore();\n\n    vtxid.clear();\n    vtxid.reserve(mapTx.size());\n\n    for (auto it : iters)\n    {\n        vtxid.push_back(it->GetTx().GetHash());\n    }\n}\n\nstatic TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {\n    return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize()), it->GetModifiedFee() - it->GetFee()};\n}\n\nstd::vector<TxMempoolInfo> CTxMemPool::infoAll() const\n{\n    LOCK(cs);\n    auto iters = GetSortedDepthAndScore();\n\n    std::vector<TxMempoolInfo> ret;\n    ret.reserve(mapTx.size());\n    for (auto it : iters) {\n        ret.push_back(GetInfo(it));\n    }\n\n    return ret;\n}\n\nCTransactionRef CTxMemPool::get(const uint256& hash) const\n{\n    LOCK(cs);\n    indexed_transaction_set::const_iterator i = mapTx.find(hash);\n    if (i == mapTx.end())\n        return nullptr;\n    return i->GetSharedTx();\n}\n\nTxMempoolInfo CTxMemPool::info(const uint256& hash) const\n{\n    LOCK(cs);\n    indexed_transaction_set::const_iterator i = mapTx.find(hash);\n    if (i == mapTx.end())\n        return TxMempoolInfo();\n    return GetInfo(i);\n}\n\nvoid CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)\n{\n    {\n        LOCK(cs);\n        CAmount &delta = mapDeltas[hash];\n        delta += nFeeDelta;\n        txiter it = mapTx.find(hash);\n        if (it != mapTx.end()) {\n            mapTx.modify(it, update_fee_delta(delta));\n            // Now update all ancestors' modified fees with descendants\n            setEntries setAncestors;\n            uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();\n            std::string dummy;\n            CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);\n            for(txiter ancestorIt : setAncestors) {\n                mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));\n            }\n            // Now update all descendants' modified fees with ancestors\n            setEntries setDescendants;\n            CalculateDescendants(it, setDescendants);\n            setDescendants.erase(it);\n            for(txiter descendantIt : setDescendants) {\n                mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));\n            }\n            ++nTransactionsUpdated;\n        }\n    }\n    LogPrintf(\"PrioritiseTransaction: %s feerate += %s\\n\", hash.ToString(), FormatMoney(nFeeDelta));\n}\n\nvoid CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const\n{\n    LOCK(cs);\n    std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);\n    if (pos == mapDeltas.end())\n        return;\n    const CAmount &delta = pos->second;\n    nFeeDelta += delta;\n}\n\nvoid CTxMemPool::ClearPrioritisation(const uint256 hash)\n{\n    LOCK(cs);\n    mapDeltas.erase(hash);\n}\n\nbool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const\n{\n    for (unsigned int i = 0; i < tx.vin.size(); i++)\n        if (tx.vin[i].GetPrevOut().isHash && exists(tx.vin[i].GetPrevOut().getTransactionHash()))\n            return false;\n    return true;\n}\n\nCCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }\n\nbool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet) const {\n    // If an entry in the mempool exists, always return that one, as it's guaranteed to never\n    // conflict with the underlying cache, and it cannot have pruned entries (as it contains full)\n    // transactions. First checking the underlying cache risks returning a pruned entry instead.\n    CTransactionRef ptx = outpoint.isHash ? mempool.get(outpoint.getTransactionHash()) : nullptr;\n    if (pOutpointRet)\n        *pOutpointRet = outpoint;\n    if (ptx) {\n        if (outpoint.n < ptx->vout.size()) {\n            coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, MEMPOOL_INDEX, false, !IsOldTransactionVersion(ptx->nVersion));\n            return true;\n        } else {\n            return false;\n        }\n    }\n    return (base->GetCoin(outpoint, coin, pOutpointRet) && !coin.IsSpent());\n}\n\nbool CCoinsViewMemPool::HaveCoin(const COutPoint &outpoint) const {\n    return mempool.exists(outpoint) || base->HaveCoin(outpoint);\n}\n\nsize_t CTxMemPool::DynamicMemoryUsage() const {\n    LOCK(cs);\n    // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.\n    return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;\n}\n\nvoid CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) {\n    AssertLockHeld(cs);\n    UpdateForRemoveFromMempool(stage, updateDescendants);\n    for(const txiter& it : stage) {\n        removeUnchecked(it, reason);\n    }\n}\n\nint CTxMemPool::Expire(int64_t time, std::vector<uint256>* removed) {\n    LOCK(cs);\n    indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin();\n    setEntries toremove;\n    while (it != mapTx.get<entry_time>().end() && it->GetTime() < time) {\n        toremove.insert(mapTx.project<0>(it));\n        it++;\n    }\n\n    setEntries stage;\n    for(txiter removeit : toremove) {\n        CalculateDescendants(removeit, stage);\n    }\n\n    // Collect transaction hashes for mempool entries that will be removed.\n    if (removed != nullptr) {\n        for (txiter it: stage) {\n            removed->push_back(it->GetTx().GetHash());\n        }\n    }\n\n    RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY);\n\n    return stage.size();\n}\n\nbool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate)\n{\n    LOCK(cs);\n    setEntries setAncestors;\n    uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();\n    std::string dummy;\n    CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);\n    return addUnchecked(hash, entry, setAncestors, validFeeEstimate);\n}\n\nvoid CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)\n{\n    setEntries s;\n    if (add && mapLinks[entry].children.insert(child).second) {\n        cachedInnerUsage += memusage::IncrementalDynamicUsage(s);\n    } else if (!add && mapLinks[entry].children.erase(child)) {\n        cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);\n    }\n}\n\nvoid CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add)\n{\n    setEntries s;\n    if (add && mapLinks[entry].parents.insert(parent).second) {\n        cachedInnerUsage += memusage::IncrementalDynamicUsage(s);\n    } else if (!add && mapLinks[entry].parents.erase(parent)) {\n        cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);\n    }\n}\n\nconst CTxMemPool::setEntries & CTxMemPool::GetMemPoolParents(txiter entry) const\n{\n    assert (entry != mapTx.end());\n    txlinksMap::const_iterator it = mapLinks.find(entry);\n    assert(it != mapLinks.end());\n    return it->second.parents;\n}\n\nconst CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) const\n{\n    assert (entry != mapTx.end());\n    txlinksMap::const_iterator it = mapLinks.find(entry);\n    assert(it != mapLinks.end());\n    return it->second.children;\n}\n\nCFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {\n    LOCK(cs);\n    if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)\n        return CFeeRate(rollingMinimumFeeRate);\n\n    int64_t time = GetTime();\n    if (time > lastRollingFeeUpdate + 10) {\n        double halflife = ROLLING_FEE_HALFLIFE;\n        if (DynamicMemoryUsage() < sizelimit / 4)\n            halflife /= 4;\n        else if (DynamicMemoryUsage() < sizelimit / 2)\n            halflife /= 2;\n\n        rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);\n        lastRollingFeeUpdate = time;\n\n        if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {\n            rollingMinimumFeeRate = 0;\n            return CFeeRate(0);\n        }\n    }\n    return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);\n}\n\nvoid CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {\n    AssertLockHeld(cs);\n    if (rate.GetFeePerK() > rollingMinimumFeeRate) {\n        rollingMinimumFeeRate = rate.GetFeePerK();\n        blockSinceLastRollingFeeBump = false;\n    }\n}\n\nvoid CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {\n    LOCK(cs);\n\n    unsigned nTxnRemoved = 0;\n    CFeeRate maxFeeRateRemoved(0);\n    while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) {\n        indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin();\n\n        // We set the new mempool min fee to the feerate of the removed set, plus the\n        // \"minimum reasonable fee rate\" (ie some value under which we consider txn\n        // to have 0 fee). This way, we don't allow txn to enter mempool with feerate\n        // equal to txn which were removed with no block in between.\n        CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());\n        removed += incrementalRelayFee;\n        trackPackageRemoved(removed);\n        maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);\n\n        setEntries stage;\n        CalculateDescendants(mapTx.project<0>(it), stage);\n        nTxnRemoved += stage.size();\n\n        std::vector<CTransaction> txn;\n        if (pvNoSpendsRemaining) {\n            txn.reserve(stage.size());\n            for(txiter iter : stage)\n                txn.push_back(iter->GetTx());\n        }\n        RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT);\n        if (pvNoSpendsRemaining) {\n            for(const CTransaction& tx : txn) {\n                for(const CTxIn& txin : tx.vin) {\n                    if (txin.GetPrevOut().isHash && exists(txin.GetPrevOut().getTransactionHash())) continue;\n                    if (!mapNextTx.count(txin.GetPrevOut())) {\n                        pvNoSpendsRemaining->push_back(txin.GetPrevOut());\n                    }\n                }\n            }\n        }\n    }\n\n    if (maxFeeRateRemoved > CFeeRate(0)) {\n        LogPrint(BCLog::MEMPOOL, \"Removed %u txn, rolling minimum fee bumped to %s\\n\", nTxnRemoved, maxFeeRateRemoved.ToString());\n    }\n}\n\nbool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const {\n    LOCK(cs);\n    auto it = mapTx.find(txid);\n    return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit &&\n       it->GetCountWithDescendants() < chainLimit);\n}\n\nSaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}\n"
  },
  {
    "path": "src/txmempool.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef TXMEMPOOL_H\n#define TXMEMPOOL_H\n\n#include <memory>\n#include <set>\n#include <map>\n#include <vector>\n#include <utility>\n#include <string>\n\n#include \"amount.h\"\n#include \"coins.h\"\n#include \"indirectmap.h\"\n#include \"policy/feerate.h\"\n#include \"primitives/transaction.h\"\n#include \"sync.h\"\n#include \"random.h\"\n\n#include \"boost/multi_index_container.hpp\"\n#include \"boost/multi_index/ordered_index.hpp\"\n#include \"boost/multi_index/hashed_index.hpp\"\n#include <boost/multi_index/sequenced_index.hpp>\n\n#include <boost/signals2/signal.hpp>\n\nclass CAutoFile;\nclass CBlockIndex;\n\n/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */\nstatic const uint32_t MEMPOOL_HEIGHT = 1073741823; // 2^30-1 (Coin height is only 30 bits)\n/** Fake index value used in Coin to signify they are only in the memory pool */\nstatic const uint32_t MEMPOOL_INDEX = 4294967295; // 2^32-1 (Coin height is only 30 bits)\n\nstruct LockPoints\n{\n    // Will be set to the blockchain height and median time past\n    // values that would be necessary to satisfy all relative locktime\n    // constraints (BIP68) of this tx given our view of block chain history\n    int height;\n    int64_t time;\n    // As long as the current chain descends from the highest height block\n    // containing one of the inputs used in the calculation, then the cached\n    // values are still valid even after a reorg.\n    CBlockIndex* maxInputBlock;\n\n    LockPoints() : height(0), time(0), maxInputBlock(NULL) { }\n};\n\nclass CTxMemPool;\n\n/** \\class CTxMemPoolEntry\n *\n * CTxMemPoolEntry stores data about the corresponding transaction, as well\n * as data about all in-mempool transactions that depend on the transaction\n * (\"descendant\" transactions).\n *\n * When a new entry is added to the mempool, we update the descendant state\n * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for\n * all ancestors of the newly added transaction.\n *\n */\n\nclass CTxMemPoolEntry\n{\nprivate:\n    CTransactionRef tx;\n    CAmount nFee;              //!< Cached to avoid expensive parent-transaction lookups\n    size_t nTxWeight;          //!< ... and avoid recomputing tx weight (also used for GetTxSize())\n    size_t nUsageSize;         //!< ... and total memory usage\n    int64_t nTime;             //!< Local time when entering the mempool\n    unsigned int entryHeight;  //!< Chain height when entering the mempool\n    uint64_t spendCoinbaseCount;       //!< keep track of transactions that spend a coinbase, and how many they spend\n    int64_t sigOpCost;         //!< Total sigop cost\n    int64_t feeDelta;          //!< Used for determining the priority of the transaction for mining in a block\n    LockPoints lockPoints;     //!< Track the height and time at which tx was final\n\n    // Information about descendants of this transaction that are in the\n    // mempool; if we remove this transaction we must remove all of these\n    // descendants as well.\n    uint64_t nCountWithDescendants;  //!< number of descendant transactions\n    uint64_t nSizeWithDescendants;   //!< ... and size\n    CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)\n\n    // Analogous statistics for ancestor transactions\n    uint64_t nCountWithAncestors;\n    uint64_t nSizeWithAncestors;\n    CAmount nModFeesWithAncestors;\n    int64_t nSigOpCostWithAncestors;\n\npublic:\n    CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,\n                    int64_t _nTime, unsigned int _entryHeight,\n                    uint64_t spendCoinbaseCount,\n                    int64_t nSigOpsCost, LockPoints lp);\n\n    CTxMemPoolEntry(const CTxMemPoolEntry& other);\n\n    const CTransaction& GetTx() const { return *this->tx; }\n    CTransactionRef GetSharedTx() const { return this->tx; }\n    const CAmount& GetFee() const { return nFee; }\n    size_t GetTxSize() const;\n    size_t GetTxSizeDiscounted() const;\n    size_t GetTxWeight() const { return nTxWeight; }\n    int64_t GetTime() const { return nTime; }\n    unsigned int GetHeight() const { return entryHeight; }\n    int64_t GetSigOpCost() const { return sigOpCost; }\n    int64_t GetModifiedFee() const { return nFee + feeDelta; }\n    size_t DynamicMemoryUsage() const { return nUsageSize; }\n    const LockPoints& GetLockPoints() const { return lockPoints; }\n\n    // Adjusts the descendant state.\n    void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);\n    // Adjusts the ancestor state\n    void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);\n    // Updates the fee delta used for mining priority score, and the\n    // modified fees with descendants.\n    void UpdateFeeDelta(int64_t feeDelta);\n    // Update the LockPoints after a reorg\n    void UpdateLockPoints(const LockPoints& lp);\n\n    uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }\n    uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }\n    CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }\n\n    bool GetSpendsCoinbase() const { return spendCoinbaseCount>0; }\n\n    uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }\n    uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }\n    CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }\n    int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }\n\n    mutable size_t vTxHashesIdx; //!< Index in mempool's vTxHashes\n};\n\n// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.\nstruct update_descendant_state\n{\n    update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount) :\n        modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount)\n    {}\n\n    void operator() (CTxMemPoolEntry &e)\n        { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }\n\n    private:\n        int64_t modifySize;\n        CAmount modifyFee;\n        int64_t modifyCount;\n};\n\nstruct update_ancestor_state\n{\n    update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost) :\n        modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost)\n    {}\n\n    void operator() (CTxMemPoolEntry &e)\n        { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOpsCost); }\n\n    private:\n        int64_t modifySize;\n        CAmount modifyFee;\n        int64_t modifyCount;\n        int64_t modifySigOpsCost;\n};\n\nstruct update_fee_delta\n{\n    update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }\n\n    void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }\n\nprivate:\n    int64_t feeDelta;\n};\n\nstruct update_lock_points\n{\n    update_lock_points(const LockPoints& _lp) : lp(_lp) { }\n\n    void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }\n\nprivate:\n    const LockPoints& lp;\n};\n\n// extracts a transaction hash from CTxMempoolEntry or CTransactionRef\nstruct mempoolentry_txid\n{\n    typedef uint256 result_type;\n    result_type operator() (const CTxMemPoolEntry &entry) const\n    {\n        return entry.GetTx().GetHash();\n    }\n\n    result_type operator() (const CTransactionRef& tx) const\n    {\n        return tx->GetHash();\n    }\n};\n\n/** \\class CompareTxMemPoolEntryByDescendantScore\n *\n *  Sort an entry by max(score/size of entry's tx, score/size with all descendants).\n */\nclass CompareTxMemPoolEntryByDescendantScore\n{\npublic:\n    bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const\n    {\n        bool fUseADescendants = UseDescendantScore(a);\n        bool fUseBDescendants = UseDescendantScore(b);\n\n        double aModFee = fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee();\n        double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize();\n\n        double bModFee = fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee();\n        double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize();\n\n        // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).\n        double f1 = aModFee * bSize;\n        double f2 = aSize * bModFee;\n\n        if (f1 == f2) {\n            return a.GetTime() >= b.GetTime();\n        }\n        return f1 < f2;\n    }\n\n    // Calculate which score to use for an entry (avoiding division).\n    bool UseDescendantScore(const CTxMemPoolEntry &a) const\n    {\n        double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();\n        double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();\n        return f2 > f1;\n    }\n};\n\n/** \\class CompareTxMemPoolEntryByScore\n *\n *  Sort by score of entry ((fee+delta)/size) in descending order\n */\nclass CompareTxMemPoolEntryByScore\n{\npublic:\n    bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const\n    {\n        double f1 = (double)a.GetModifiedFee() * b.GetTxSize();\n        double f2 = (double)b.GetModifiedFee() * a.GetTxSize();\n        if (f1 == f2) {\n            return b.GetTx().GetHash() < a.GetTx().GetHash();\n        }\n        return f1 > f2;\n    }\n};\n\nclass CompareTxMemPoolEntryByEntryTime\n{\npublic:\n    bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const\n    {\n        return a.GetTime() < b.GetTime();\n    }\n};\n\nclass CompareTxMemPoolEntryByAncestorFee\n{\npublic:\n    bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const\n    {\n        double aFees = a.GetModFeesWithAncestors();\n        double aSize = a.GetSizeWithAncestors();\n\n        double bFees = b.GetModFeesWithAncestors();\n        double bSize = b.GetSizeWithAncestors();\n\n        // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).\n        double f1 = aFees * bSize;\n        double f2 = aSize * bFees;\n\n        if (f1 == f2) {\n            return a.GetTx().GetHash() < b.GetTx().GetHash();\n        }\n\n        return f1 > f2;\n    }\n};\n\n// Multi_index tag names\nstruct descendant_score {};\nstruct entry_time {};\nstruct mining_score {};\nstruct ancestor_score {};\n\nclass CBlockPolicyEstimator;\n\n/**\n * Information about a mempool transaction.\n */\nstruct TxMempoolInfo\n{\n    /** The transaction itself */\n    CTransactionRef tx;\n\n    /** Time the transaction entered the mempool. */\n    int64_t nTime;\n\n    /** Feerate of the transaction. */\n    CFeeRate feeRate;\n\n    /** The fee delta. */\n    int64_t nFeeDelta;\n};\n\n/** Reason why a transaction was removed from the mempool,\n * this is passed to the notification signal.\n */\nenum class MemPoolRemovalReason {\n    UNKNOWN = 0, //! Manually removed or unknown reason\n    EXPIRY,      //! Expired from mempool\n    SIZELIMIT,   //! Removed in size limiting\n    REORG,       //! Removed for reorganization\n    BLOCK,       //! Removed for block\n    CONFLICT,    //! Removed for conflict with in-block transaction\n    REPLACED     //! Removed for replacement\n};\n\nclass SaltedTxidHasher\n{\nprivate:\n    /** Salt */\n    const uint64_t k0, k1;\n\npublic:\n    SaltedTxidHasher();\n\n    size_t operator()(const uint256& txid) const {\n        return SipHashUint256(k0, k1, txid);\n    }\n};\n\n/**\n * CTxMemPool stores valid-according-to-the-current-best-chain transactions\n * that may be included in the next block.\n *\n * Transactions are added when they are seen on the network (or created by the\n * local node), but not all transactions seen are added to the pool. For\n * example, the following new transactions will not be added to the mempool:\n * - a transaction which doesn't meet the minimum fee requirements.\n * - a new transaction that double-spends an input of a transaction already in\n * the pool where the new transaction does not meet the Replace-By-Fee\n * requirements as defined in BIP 125.\n * - a non-standard transaction.\n *\n * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:\n *\n * mapTx is a boost::multi_index that sorts the mempool on 4 criteria:\n * - transaction hash\n * - feerate [we use max(feerate of tx, feerate of tx with all descendants)]\n * - time in mempool\n * - mining score (feerate modified by any fee deltas from PrioritiseTransaction)\n *\n * Note: the term \"descendant\" refers to in-mempool transactions that depend on\n * this one, while \"ancestor\" refers to in-mempool transactions that a given\n * transaction depends on.\n *\n * In order for the feerate sort to remain correct, we must update transactions\n * in the mempool when new descendants arrive.  To facilitate this, we track\n * the set of in-mempool direct parents and direct children in mapLinks.  Within\n * each CTxMemPoolEntry, we track the size and fees of all descendants.\n *\n * Usually when a new transaction is added to the mempool, it has no in-mempool\n * children (because any such children would be an orphan).  So in\n * addUnchecked(), we:\n * - update a new entry's setMemPoolParents to include all in-mempool parents\n * - update the new entry's direct parents to include the new tx as a child\n * - update all ancestors of the transaction to include the new tx's size/fee\n *\n * When a transaction is removed from the mempool, we must:\n * - update all in-mempool parents to not track the tx in setMemPoolChildren\n * - update all ancestors to not include the tx's size/fees in descendant state\n * - update all in-mempool children to not include it as a parent\n *\n * These happen in UpdateForRemoveFromMempool().  (Note that when removing a\n * transaction along with its descendants, we must calculate that set of\n * transactions to be removed before doing the removal, or else the mempool can\n * be in an inconsistent state where it's impossible to walk the ancestors of\n * a transaction.)\n *\n * In the event of a reorg, the assumption that a newly added tx has no\n * in-mempool children is false.  In particular, the mempool is in an\n * inconsistent state while new transactions are being added, because there may\n * be descendant transactions of a tx coming from a disconnected block that are\n * unreachable from just looking at transactions in the mempool (the linking\n * transactions may also be in the disconnected block, waiting to be added).\n * Because of this, there's not much benefit in trying to search for in-mempool\n * children in addUnchecked().  Instead, in the special case of transactions\n * being added from a disconnected block, we require the caller to clean up the\n * state, to account for in-mempool, out-of-block descendants for all the\n * in-block transactions by calling UpdateTransactionsFromBlock().  Note that\n * until this is called, the mempool state is not consistent, and in particular\n * mapLinks may not be correct (and therefore functions like\n * CalculateMemPoolAncestors() and CalculateDescendants() that rely\n * on them to walk the mempool are not generally safe to use).\n *\n * Computational limits:\n *\n * Updating all in-mempool ancestors of a newly added transaction can be slow,\n * if no bound exists on how many in-mempool ancestors there may be.\n * CalculateMemPoolAncestors() takes configurable limits that are designed to\n * prevent these calculations from being too CPU intensive.\n *\n */\nclass CTxMemPool\n{\nprivate:\n    uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check.\n    unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation\n    CBlockPolicyEstimator* minerPolicyEstimator;\n\n    uint64_t totalTxSize;      //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.\n    uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)\n\n    mutable int64_t lastRollingFeeUpdate;\n    mutable bool blockSinceLastRollingFeeBump;\n    mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially\n\n    void trackPackageRemoved(const CFeeRate& rate);\n\npublic:\n\n    static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing\n\n    typedef boost::multi_index_container<\n        CTxMemPoolEntry,\n        boost::multi_index::indexed_by<\n            // sorted by txid\n            boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>,\n            // sorted by fee rate\n            boost::multi_index::ordered_non_unique<\n                boost::multi_index::tag<descendant_score>,\n                boost::multi_index::identity<CTxMemPoolEntry>,\n                CompareTxMemPoolEntryByDescendantScore\n            >,\n            // sorted by entry time\n            boost::multi_index::ordered_non_unique<\n                boost::multi_index::tag<entry_time>,\n                boost::multi_index::identity<CTxMemPoolEntry>,\n                CompareTxMemPoolEntryByEntryTime\n            >,\n            // sorted by score (for mining prioritization)\n            boost::multi_index::ordered_unique<\n                boost::multi_index::tag<mining_score>,\n                boost::multi_index::identity<CTxMemPoolEntry>,\n                CompareTxMemPoolEntryByScore\n            >,\n            // sorted by fee rate with ancestors\n            boost::multi_index::ordered_non_unique<\n                boost::multi_index::tag<ancestor_score>,\n                boost::multi_index::identity<CTxMemPoolEntry>,\n                CompareTxMemPoolEntryByAncestorFee\n            >\n        >\n    > indexed_transaction_set;\n\n    mutable RecursiveMutex cs;\n    indexed_transaction_set mapTx;\n\n    typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;\n    std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx witness hashes/entries in mapTx, in random order\n\n    struct CompareIteratorByHash {\n        bool operator()(const txiter &a, const txiter &b) const {\n            return a->GetTx().GetHash() < b->GetTx().GetHash();\n        }\n    };\n    typedef std::set<txiter, CompareIteratorByHash> setEntries;\n\n    const setEntries & GetMemPoolParents(txiter entry) const;\n    const setEntries & GetMemPoolChildren(txiter entry) const;\nprivate:\n    typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;\n\n    struct TxLinks {\n        setEntries parents;\n        setEntries children;\n    };\n\n    typedef std::map<txiter, TxLinks, CompareIteratorByHash> txlinksMap;\n    txlinksMap mapLinks;\n\n    void UpdateParent(txiter entry, txiter parent, bool add);\n    void UpdateChild(txiter entry, txiter child, bool add);\n\n    std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const;\n\npublic:\n    indirectmap<COutPoint, const CTransaction*> mapNextTx;\n    std::map<uint256, CAmount> mapDeltas;\n\n    /** Create a new CTxMemPool.\n     */\n    CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);\n\n    /**\n     * If sanity-checking is turned on, check makes sure the pool is\n     * consistent (does not contain two transactions that spend the same inputs,\n     * all inputs are in the mapNextTx array). If sanity-checking is turned off,\n     * check does nothing.\n     */\n    void check(const CCoinsViewCache *pcoins) const;\n    void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }\n\n    // addUnchecked must updated state for all ancestors of a given transaction,\n    // to track size/count of descendant transactions.  First version of\n    // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and\n    // then invoke the second version.\n    bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);\n    bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);\n\n    void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);\n    void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);\n    void removeConflicts(const CTransaction &tx);\n    void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);\n\n    void clear();\n    void _clear(); //lock free\n    bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);\n    void queryHashes(std::vector<uint256>& vtxid);\n    bool isSpent(const COutPoint& outpoint);\n    unsigned int GetTransactionsUpdated() const;\n    void AddTransactionsUpdated(unsigned int n);\n    /**\n     * Check that none of this transactions inputs are in the mempool, and thus\n     * the tx is not dependent on other mempool transactions to be included in a block.\n     */\n    bool HasNoInputsOf(const CTransaction& tx) const;\n\n    /** Affect CreateNewBlock prioritisation of transactions */\n    void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);\n    void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;\n    void ClearPrioritisation(const uint256 hash);\n\npublic:\n    /** Remove a set of transactions from the mempool.\n     *  If a transaction is in this set, then all in-mempool descendants must\n     *  also be in the set, unless this transaction is being removed for being\n     *  in a block.\n     *  Set updateDescendants to true when removing a tx that was in a block, so\n     *  that any in-mempool descendants have their ancestor state updated.\n     */\n    void RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);\n\n    /** When adding transactions from a disconnected block back to the mempool,\n     *  new mempool entries may have children in the mempool (which is generally\n     *  not the case when otherwise adding transactions).\n     *  UpdateTransactionsFromBlock() will find child transactions and update the\n     *  descendant state for each transaction in vHashesToUpdate (excluding any\n     *  child transactions present in vHashesToUpdate, which are already accounted\n     *  for).  Note: vHashesToUpdate should be the set of transactions from the\n     *  disconnected block that have been accepted back into the mempool.\n     */\n    void UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate);\n\n    /** Try to calculate all in-mempool ancestors of entry.\n     *  (these are all calculated including the tx itself)\n     *  limitAncestorCount = max number of ancestors\n     *  limitAncestorSize = max size of ancestors\n     *  limitDescendantCount = max number of descendants any ancestor can have\n     *  limitDescendantSize = max size of descendants any ancestor can have\n     *  errString = populated with error reason if any limits are hit\n     *  fSearchForParents = whether to search a tx's vin for in-mempool parents, or\n     *    look up parents from mapLinks. Must be true for entries not in the mempool\n     */\n    bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const;\n\n    /** Populate setDescendants with all in-mempool descendants of hash.\n     *  Assumes that setDescendants includes all in-mempool descendants of anything\n     *  already in it.  */\n    void CalculateDescendants(txiter it, setEntries &setDescendants);\n\n    /** The minimum fee to get into the mempool, which may itself not be enough\n      *  for larger-sized transactions.\n      *  The incrementalRelayFee policy variable is used to bound the time it\n      *  takes the fee rate to go back down all the way to 0. When the feerate\n      *  would otherwise be half of this, it is set to 0 instead.\n      */\n    CFeeRate GetMinFee(size_t sizelimit) const;\n\n    /** Remove transactions from the mempool until its dynamic size is <= sizelimit.\n      *  pvNoSpendsRemaining, if set, will be populated with the list of outpoints\n      *  which are not in mempool which no longer have any spends in this mempool.\n      */\n    void TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining=NULL);\n\n    /** Expire all transaction (and their dependencies) in the mempool older than time.\n     * Return the number of removed transactions and optiallay their hashes.\n     * Note removed hashes is not cleared up front.\n     */\n    int Expire(int64_t time, std::vector<uint256>* removed = nullptr);\n\n    /** Returns false if the transaction is in the mempool and not within the chain limit specified. */\n    bool TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const;\n\n    unsigned long size()\n    {\n        LOCK(cs);\n        return mapTx.size();\n    }\n\n    uint64_t GetTotalTxSize()\n    {\n        LOCK(cs);\n        return totalTxSize;\n    }\n\n    bool exists(uint256 hash) const\n    {\n        LOCK(cs);\n        return (mapTx.count(hash) != 0);\n    }\n\n    bool exists(const COutPoint& outpoint) const\n    {\n        // an index based outpoint references a block, so by definition it cannot be in the mempool\n        // as that onlly holds tx that are NOT in a block (yet)\n        if (!outpoint.isHash)\n            return false;\n        LOCK(cs);\n        auto it = mapTx.find(outpoint.getTransactionHash());\n        return (it != mapTx.end() && outpoint.n < it->GetTx().vout.size());\n    }\n\n    CTransactionRef get(const uint256& hash) const;\n    TxMempoolInfo info(const uint256& hash) const;\n    std::vector<TxMempoolInfo> infoAll() const;\n\n    size_t DynamicMemoryUsage() const;\n\n    boost::signals2::signal<void (CTransactionRef)> NotifyEntryAdded;\n    boost::signals2::signal<void (CTransactionRef, MemPoolRemovalReason)> NotifyEntryRemoved;\n\nprivate:\n    /** UpdateForDescendants is used by UpdateTransactionsFromBlock to update\n     *  the descendants for a single transaction that has been added to the\n     *  mempool but may have child transactions in the mempool, eg during a\n     *  chain reorg.  setExclude is the set of descendant transactions in the\n     *  mempool that must not be accounted for (because any descendants in\n     *  setExclude were added to the mempool after the transaction being\n     *  updated and hence their state is already reflected in the parent\n     *  state).\n     *\n     *  cachedDescendants will be updated with the descendants of the transaction\n     *  being updated, so that future invocations don't need to walk the\n     *  same transaction again, if encountered in another transaction chain.\n     */\n    void UpdateForDescendants(txiter updateIt,\n            cacheMap &cachedDescendants,\n            const std::set<uint256> &setExclude);\n    /** Update ancestors of hash to add/remove it as a descendant transaction. */\n    void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors);\n    /** Set ancestor state for an entry */\n    void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors);\n    /** For each transaction being removed, update ancestors and any direct children.\n      * If updateDescendants is true, then also update in-mempool descendants'\n      * ancestor state. */\n    void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants);\n    /** Sever link between specified transaction and direct children. */\n    void UpdateChildrenForRemoval(txiter entry);\n\n    /** Before calling removeUnchecked for a given transaction,\n     *  UpdateForRemoveFromMempool must be called on the entire (dependent) set\n     *  of transactions being removed at the same time.  We use each\n     *  CTxMemPoolEntry's setMemPoolParents in order to walk ancestors of a\n     *  given transaction that is removed, so we can't remove intermediate\n     *  transactions in a chain before we've updated all the state for the\n     *  removal.\n     */\n    void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);\n};\n\n/** \n * CCoinsView that brings transactions from a memorypool into view.\n * It does not check for spendings by memory pool transactions.\n */\nclass CCoinsViewMemPool : public CCoinsViewBacked\n{\nprotected:\n    const CTxMemPool& mempool;\n\npublic:\n    CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);\n    bool GetCoin(const COutPoint &outpoint, Coin &coin, COutPoint* pOutpointRet=nullptr) const;\n    bool HaveCoin(const COutPoint &outpoint) const;\n};\n\n/**\n * DisconnectedBlockTransactions\n\n * During the reorg, it's desirable to re-add previously confirmed transactions\n * to the mempool, so that anything not re-confirmed in the new chain is\n * available to be mined. However, it's more efficient to wait until the reorg\n * is complete and process all still-unconfirmed transactions at that time,\n * since we expect most confirmed transactions to (typically) still be\n * confirmed in the new chain, and re-accepting to the memory pool is expensive\n * (and therefore better to not do in the middle of reorg-processing).\n * Instead, store the disconnected transactions (in order!) as we go, remove any\n * that are included in blocks in the new chain, and then process the remaining\n * still-unconfirmed transactions at the end.\n */\n\n// multi_index tag names\nstruct txid_index {};\nstruct insertion_order {};\n\nstruct DisconnectedBlockTransactions {\n    typedef boost::multi_index_container<\n        CTransactionRef,\n        boost::multi_index::indexed_by<\n            // sorted by txid\n            boost::multi_index::hashed_unique<\n                boost::multi_index::tag<txid_index>,\n                mempoolentry_txid,\n                SaltedTxidHasher\n            >,\n            // sorted by order in the blockchain\n            boost::multi_index::sequenced<\n                boost::multi_index::tag<insertion_order>\n            >\n        >\n    > indexed_disconnected_transactions;\n\n    // It's almost certainly a logic bug if we don't clear out queuedTx before\n    // destruction, as we add to it while disconnecting blocks, and then we\n    // need to re-process remaining transactions to ensure mempool consistency.\n    // For now, assert() that we've emptied out this object on destruction.\n    // This assert() can always be removed if the reorg-processing code were\n    // to be refactored such that this assumption is no longer true (for\n    // instance if there was some other way we cleaned up the mempool after a\n    // reorg, besides draining this object).\n    ~DisconnectedBlockTransactions() { assert(queuedTx.empty()); }\n\n    indexed_disconnected_transactions queuedTx;\n    uint64_t cachedInnerUsage = 0;\n\n    // Estimate the overhead of queuedTx to be 6 pointers + an allocation, as\n    // no exact formula for boost::multi_index_contained is implemented.\n    size_t DynamicMemoryUsage() const {\n        return memusage::MallocUsage(sizeof(CTransactionRef) + 6 * sizeof(void*)) * queuedTx.size() + cachedInnerUsage;\n    }\n\n    void addTransaction(const CTransactionRef& tx)\n    {\n        queuedTx.insert(tx);\n        cachedInnerUsage += RecursiveDynamicUsage(tx);\n    }\n\n    // Remove entries based on txid_index, and update memory usage.\n    void removeForBlock(const std::vector<CTransactionRef>& vtx)\n    {\n        // Short-circuit in the common case of a block being added to the tip\n        if (queuedTx.empty()) {\n            return;\n        }\n        for (auto const &tx : vtx) {\n            auto it = queuedTx.find(tx->GetHash());\n            if (it != queuedTx.end()) {\n                cachedInnerUsage -= RecursiveDynamicUsage(*it);\n                queuedTx.erase(it);\n            }\n        }\n    }\n\n    // Remove an entry by insertion_order index, and update memory usage.\n    void removeEntry(indexed_disconnected_transactions::index<insertion_order>::type::iterator entry)\n    {\n        cachedInnerUsage -= RecursiveDynamicUsage(*entry);\n        queuedTx.get<insertion_order>().erase(entry);\n    }\n\n    void clear()\n    {\n        cachedInnerUsage = 0;\n        queuedTx.clear();\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/ui_interface.cpp",
    "content": "// Copyright (c) 2010-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"ui_interface.h\"\n#include \"util.h\"\n\nCClientUIInterface uiInterface;\n\nbool InitError(const std::string& str)\n{\n    uiInterface.ThreadSafeMessageBox(str, \"\", CClientUIInterface::MSG_ERROR);\n    return false;\n}\n\nvoid InitWarning(const std::string& str)\n{\n    uiInterface.ThreadSafeMessageBox(str, \"\", CClientUIInterface::MSG_WARNING);\n}\n\nstd::string AmountHighWarn(const std::string& optname)\n{\n    return strprintf(_(\"%s is set very high!\"), optname);\n}\n\nstd::string AmountErrMsg(const char* const optname, const std::string& strValue)\n{\n    return strprintf(_(\"Invalid amount for -%s=<amount>: '%s'\"), optname, strValue);\n}\n"
  },
  {
    "path": "src/ui_interface.h",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef UI_INTERFACE_H\n#define UI_INTERFACE_H\n\n\n#include <stdint.h>\n#include <string>\n\n#include <boost/signals2/last_value.hpp>\n#include <boost/signals2/signal.hpp>\n\nclass CBasicKeyStore;\nclass CWallet;\nclass uint256;\nclass CBlockIndex;\n\n/** General change type (added, updated, removed). */\nenum ChangeType\n{\n    CT_NEW,\n    CT_UPDATED,\n    CT_DELETED\n};\n\n/** Signals for UI communication. */\nclass CClientUIInterface\n{\npublic:\n    /** Flags for CClientUIInterface::ThreadSafeMessageBox */\n    enum MessageBoxFlags\n    {\n        ICON_INFORMATION    = 0,\n        ICON_WARNING        = (1U << 0),\n        ICON_ERROR          = (1U << 1),\n        /**\n         * Mask of all available icons in CClientUIInterface::MessageBoxFlags\n         * This needs to be updated, when icons are changed there!\n         */\n        ICON_MASK = (ICON_INFORMATION | ICON_WARNING | ICON_ERROR),\n\n        /** These values are taken from qmessagebox.h \"enum StandardButton\" to be directly usable */\n        BTN_OK      = 0x00000400U, // QMessageBox::Ok\n        BTN_YES     = 0x00004000U, // QMessageBox::Yes\n        BTN_NO      = 0x00010000U, // QMessageBox::No\n        BTN_ABORT   = 0x00040000U, // QMessageBox::Abort\n        BTN_RETRY   = 0x00080000U, // QMessageBox::Retry\n        BTN_IGNORE  = 0x00100000U, // QMessageBox::Ignore\n        BTN_CLOSE   = 0x00200000U, // QMessageBox::Close\n        BTN_CANCEL  = 0x00400000U, // QMessageBox::Cancel\n        BTN_DISCARD = 0x00800000U, // QMessageBox::Discard\n        BTN_HELP    = 0x01000000U, // QMessageBox::Help\n        BTN_APPLY   = 0x02000000U, // QMessageBox::Apply\n        BTN_RESET   = 0x04000000U, // QMessageBox::Reset\n        /**\n         * Mask of all available buttons in CClientUIInterface::MessageBoxFlags\n         * This needs to be updated, when buttons are changed there!\n         */\n        BTN_MASK = (BTN_OK | BTN_YES | BTN_NO | BTN_ABORT | BTN_RETRY | BTN_IGNORE |\n                    BTN_CLOSE | BTN_CANCEL | BTN_DISCARD | BTN_HELP | BTN_APPLY | BTN_RESET),\n\n        /** Force blocking, modal message box dialog (not just OS notification) */\n        MODAL               = 0x10000000U,\n\n        /** Do not print contents of message to debug log */\n        SECURE              = 0x40000000U,\n\n        /** Predefined combinations for certain default usage cases */\n        MSG_INFORMATION = ICON_INFORMATION,\n        MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL),\n        MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL)\n    };\n\n    /** Show message box. */\n    boost::signals2::signal<bool (const std::string& message, const std::string& caption, unsigned int style) > ThreadSafeMessageBox;\n\n    /** If possible, ask the user a question. If not, falls back to ThreadSafeMessageBox(noninteractive_message, caption, style) and returns false. */\n    boost::signals2::signal<bool (const std::string& message, const std::string& noninteractive_message, const std::string& caption, unsigned int style), boost::signals2::optional_last_value<bool> > ThreadSafeQuestion;\n\n    /** Progress message during initialization. */\n    boost::signals2::signal<void (const std::string &message)> InitMessage;\n\n    /** Number of network connections changed. */\n    boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;\n\n    /** Network activity state changed. */\n    boost::signals2::signal<void (bool networkActive)> NotifyNetworkActiveChanged;\n\n    /**\n     * Status bar alerts changed.\n     */\n    boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged;\n\n    //! Alert for user (top of UI) changed.\n    boost::signals2::signal<void (const std::string& alertMessage)> NotifyUIAlertChanged;\n\n    /** A wallet has been loaded. */\n    boost::signals2::signal<void (CWallet* wallet)> LoadWallet;\n\n    /** The core requires a wallet unlock. */\n    boost::signals2::signal<void (CWallet* wallet, std::string reason)> RequestUnlock;\n    boost::signals2::signal<void (CWallet* wallet, std::string reason, std::function<void (void)> successCallback)> RequestUnlockWithCallback;\n\n    /** Show progress e.g. for verifychain */\n    boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;\n\n    /** New block has been accepted */\n    boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;\n\n    /** Header progress has changed */\n    boost::signals2::signal<void (int, int, int, int64_t)> NotifyHeaderProgress;\n\n    /** Banlist did change. */\n    boost::signals2::signal<void (void)> BannedListChanged;\n\n    /** SPV progress */\n    boost::signals2::signal<void (int start_height, int processed_height, int probable_height)> NotifySPVProgress;\n\n    /** unified progress */\n    boost::signals2::signal<void (float progress)> NotifyUnifiedProgress;\n\n    /** SPV pruning */\n    boost::signals2::signal<void (int height)> NotifySPVPrune;\n};\n\n/** Show warning message **/\nvoid InitWarning(const std::string& str);\n\n/** Show error message **/\nbool InitError(const std::string& str);\n\nstd::string AmountHighWarn(const std::string& optname);\n\nstd::string AmountErrMsg(const char* const optname, const std::string& strValue);\n\nextern CClientUIInterface uiInterface;\n\n#endif // UI_INTERFACE_H\n"
  },
  {
    "path": "src/uint256.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"uint256.h\"\n\n#include \"util/strencodings.h\"\n\n#include <stdio.h>\n#include <string.h>\n\ntemplate <unsigned int BITS>\nbase_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)\n{\n    assert(vch.size() == sizeof(m_data));\n    memcpy(m_data, vch.data(), sizeof(m_data));\n}\n\ntemplate <unsigned int BITS>\nstd::string base_blob<BITS>::GetHex() const\n{\n    return HexStr(std::reverse_iterator<const uint8_t*>(m_data + sizeof(m_data)), std::reverse_iterator<const uint8_t*>(m_data));\n}\n\ntemplate <unsigned int BITS>\nvoid base_blob<BITS>::SetHex(const char* psz)\n{\n    memset(m_data, 0, sizeof(m_data));\n\n    // skip leading spaces\n    while (isspace(*psz))\n        psz++;\n\n    // skip 0x\n    if (psz[0] == '0' && tolower(psz[1]) == 'x')\n        psz += 2;\n\n    // hex string to uint\n    size_t digits = 0;\n    while (::HexDigit(psz[digits]) != -1)\n        digits++;\n    unsigned char* p1 = (unsigned char*)m_data;\n    unsigned char* pend = p1 + WIDTH;\n    while (digits > 0 && p1 < pend) {\n        *p1 = ::HexDigit(psz[--digits]);\n        if (digits > 0) {\n            *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4);\n            p1++;\n        }\n    }\n}\n\ntemplate <unsigned int BITS>\nvoid base_blob<BITS>::SetHex(const std::string& str)\n{\n    SetHex(str.c_str());\n}\n\ntemplate <unsigned int BITS>\nstd::string base_blob<BITS>::ToString() const\n{\n    return (GetHex());\n}\n\n// Explicit instantiations for base_blob<160>\ntemplate base_blob<160>::base_blob(const std::vector<unsigned char>&);\ntemplate std::string base_blob<160>::GetHex() const;\ntemplate std::string base_blob<160>::ToString() const;\ntemplate void base_blob<160>::SetHex(const char*);\ntemplate void base_blob<160>::SetHex(const std::string&);\n\n// Explicit instantiations for base_blob<256>\ntemplate base_blob<256>::base_blob(const std::vector<unsigned char>&);\ntemplate std::string base_blob<256>::GetHex() const;\ntemplate std::string base_blob<256>::ToString() const;\ntemplate void base_blob<256>::SetHex(const char*);\ntemplate void base_blob<256>::SetHex(const std::string&);\n"
  },
  {
    "path": "src/uint256.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UINT256_H\n#define CORE_UINT256_H\n\n#include <assert.h>\n#include <cstring>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <vector>\n#include \"crypto/common.h\"\n#include \"span.h\"\n\n/** Template base class for fixed-sized opaque blobs. */\ntemplate<unsigned int BITS>\nclass base_blob\n{\nprotected:\n    static constexpr int WIDTH = BITS / 8;\n    uint8_t m_data[WIDTH];\npublic:\n    base_blob()\n    {\n        memset(m_data, 0, sizeof(m_data));\n    }\n\n    explicit base_blob(const std::vector<unsigned char>& vch);\n\n    bool IsNull() const\n    {\n        for (int i = 0; i < WIDTH; i++)\n            if (m_data[i] != 0)\n                return false;\n        return true;\n    }\n\n    void SetNull()\n    {\n        memset(m_data, 0, sizeof(m_data));\n    }\n\n    inline int Compare(const base_blob& other) const { return memcmp(m_data, other.m_data, sizeof(m_data)); }\n\n    friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }\n    friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }\n    friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }\n\n    std::string GetHex() const;\n    void SetHex(const char* psz);\n    void SetHex(const std::string& str);\n    std::string ToString() const;\n\n    const unsigned char* data() const { return m_data; }\n    unsigned char* data() { return m_data; }\n\n    unsigned char* begin()\n    {\n        return &m_data[0];\n    }\n\n    unsigned char* end()\n    {\n        return &m_data[WIDTH];\n    }\n\n    const unsigned char* begin() const\n    {\n        return &m_data[0];\n    }\n\n    const unsigned char* end() const\n    {\n        return &m_data[WIDTH];\n    }\n\n    unsigned int size() const\n    {\n        return sizeof(m_data);\n    }\n\n    uint64_t GetUint64(int pos) const\n    {\n        const uint8_t* ptr = m_data + pos * 8;\n        return ((uint64_t)ptr[0]) | \\\n               ((uint64_t)ptr[1]) << 8 | \\\n               ((uint64_t)ptr[2]) << 16 | \\\n               ((uint64_t)ptr[3]) << 24 | \\\n               ((uint64_t)ptr[4]) << 32 | \\\n               ((uint64_t)ptr[5]) << 40 | \\\n               ((uint64_t)ptr[6]) << 48 | \\\n               ((uint64_t)ptr[7]) << 56;\n    }\n\n    template<typename Stream>\n    void Serialize(Stream& s) const\n    {\n        s.write(MakeByteSpan(m_data));\n    }\n\n    template<typename Stream>\n    void Unserialize(Stream& s)\n    {\n        s.read(MakeWritableByteSpan(m_data));\n    }\n};\n\n/** 160-bit opaque blob.\n * @note This type is called uint160 for historical reasons only. It is an opaque\n * blob of 160 bits and has no integer operations.\n */\nclass uint160 : public base_blob<160> {\npublic:\n    uint160() {}\n    uint160(const base_blob<160>& b) : base_blob<160>(b) {}\n    explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}\n};\n\n/** 256-bit opaque blob.\n * @note This type is called uint256 for historical reasons only. It is an\n * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if\n * those are required.\n */\nclass uint256 : public base_blob<256> {\npublic:\n    uint256() {}\n    uint256(const base_blob<256>& b) : base_blob<256>(b) {}\n    explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}\n\n    /** A cheap hash function that just returns 64 bits from the result, it can be\n     * used when the contents are considered uniformly random. It is not appropriate\n     * when the value can easily be influenced from outside as e.g. a network adversary could\n     * provide values to trigger worst-case behavior.\n     */\n    uint64_t GetCheapHash() const\n    {\n        return ReadLE64(m_data);\n    }\n};\n\n/* uint256 from const char *.\n * This is a separate function because the constructor uint256(const char*) can result\n * in dangerously catching uint256(0).\n */\ninline uint256 uint256S(const char *str)\n{\n    uint256 rv;\n    rv.SetHex(str);\n    return rv;\n}\n/* uint256 from std::string.\n * This is a separate function because the constructor uint256(const std::string &str) can result\n * in dangerously catching uint256(0) via std::string(const char*).\n */\ninline uint256 uint256S(const std::string& str)\n{\n    uint256 rv;\n    rv.SetHex(str);\n    return rv;\n}\n\n#endif // CORE_UINT256_H\n"
  },
  {
    "path": "src/undo.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef TRANSACTION_UNDO_H\n#define TRANSACTION_UNDO_H\n\n#include \"coins.h\"\n#include \"compressor.h\" \n#include \"consensus/consensus.h\"\n#include \"primitives/transaction.h\"\n#include \"serialize.h\"\n\n//fixme: (PHASE5) This can potentially be improved.\n//6 is the lower bound for the size of a SegSig txin\nstatic const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / 6; // TODO: merge with similar definition in undo.h.\n\n/** Undo information for a CTransaction */\nclass CTxUndo\n{\npublic:\n    // undo information for all txins\n    std::vector<CoinUndo> vprevout;\n\n    template <typename Stream>\n    void Serialize(Stream& s) const {\n        // TODO: avoid reimplementing vector serializer\n        uint64_t count = vprevout.size();\n        ::Serialize(s, COMPACTSIZE(REF(count)));\n        for (const auto& prevout : vprevout) {\n            ::Serialize(s, prevout);\n        }\n    }\n\n    template <typename Stream>\n    void Unserialize(Stream& s) {\n        // TODO: avoid reimplementing vector deserializer\n        uint64_t count = 0;\n        ::Unserialize(s, COMPACTSIZE(count));\n        if (count > MAX_INPUTS_PER_BLOCK) {\n            throw std::ios_base::failure(\"Too many input undo records\");\n        }\n        vprevout.resize(count);\n        for (auto& prevout : vprevout) {\n            ::Unserialize(s, prevout);\n        }\n    }\n};\n\n/** Undo information for a CBlock */\nclass CBlockUndo\n{\npublic:\n    std::vector<CTxUndo> vtxundo; // for all but the coinbase\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITECOMPACTSIZEVECTOR(vtxundo);\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/unity/android/init_android.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"appname.h\"\n#include <boost/thread.hpp>\n#include \"chain.h\"\n#include \"init.h\"\n#include \"node/context.h\"\n\n#include \"unity/compat/android_wallet.h\"\n#include \"unity/djinni/cpp/legacy_wallet_result.hpp\"\n#include \"unity/djinni/cpp/i_library_controller.hpp\"\n#include \"mnemonic_record.hpp\"\n\nextern std::string HelpMessage(HelpMessageMode mode)\n{\n    return \"\";\n}\n\nvoid InitRegisterRPC()\n{\n}\n\nvoid ServerInterrupt()\n{\n}\n\nbool InitRPCWarmup()\n{\n    return true;\n}\n\nvoid SetRPCWarmupFinished()\n{\n}\n\nvoid RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)\n{\n}\n\nvoid ServerShutdown(node::NodeContext& nodeContext)\n{\n    // After everything has been shut down, but before things get flushed, stop the\n    // CScheduler/checkqueue, scheduler and load block thread.\n    if (nodeContext.scheduler) nodeContext.scheduler->stop();\n}\n\nvoid InitRPCMining()\n{\n}\n\nbool InitTor()\n{\n    return true;\n}\n\n\nbool ILibraryController::InitWalletFromAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword, const std::string& newPassword)\n{\n    android_wallet wallet = ParseAndroidProtoWallet(walletFile, oldPassword);\n    if (wallet.validWalletProto && wallet.validWallet)\n    {\n        if (wallet.walletSeedMnemonic.length() > 0)\n        {\n            if (wallet.walletSeedMnemonic.find(\"-\") != std::string::npos && wallet.walletSeedMnemonic.find(\":\") != std::string::npos)\n            {\n                return InitWalletLinkedFromURI(GLOBAL_APP_URIPREFIX\"sync:\"+wallet.walletSeedMnemonic+\";unused_payout_address\", newPassword.c_str());\n            }\n            else\n            {\n                if (wallet.walletBirth > 0)\n                {\n                    return InitWalletFromRecoveryPhrase(ComposeRecoveryPhrase(wallet.walletSeedMnemonic, wallet.walletBirth).phrase_with_birth_number.c_str(), newPassword.c_str());\n                }\n                else\n                {\n                    return InitWalletFromRecoveryPhrase(wallet.walletSeedMnemonic.c_str(), newPassword.c_str());\n                }\n            }\n        }\n    }\n    return false;\n}\n\nLegacyWalletResult ILibraryController::isValidAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword)\n{\n    LogPrintf(\"Checking for valid legacy wallet proto [%s]\\n\", walletFile.c_str());\n\n    android_wallet wallet = ParseAndroidProtoWallet(walletFile, oldPassword);\n\n    if (wallet.validWalletProto)\n    {\n        LogPrintf(\"Valid proto found\\n\");\n\n        if (wallet.encrypted)\n        {\n            LogPrintf(\"Proto is encrypted\\n\");\n\n            if (!wallet.validWallet)\n            {\n                if ( oldPassword.length() == 0 )\n                {\n                    LogPrintf(\"Password required\\n\");\n                    return LegacyWalletResult::ENCRYPTED_PASSWORD_REQUIRED;\n                }\n                LogPrintf(\"Password is invalid\\n\");\n                return LegacyWalletResult::PASSWORD_INVALID;\n            }\n        }\n        if (wallet.walletSeedMnemonic.length() > 0)\n        {\n            LogPrintf(\"Wallet is valid\\n\");\n            return LegacyWalletResult::VALID;\n        }\n    }\n    LogPrintf(\"Wallet invalid or corrupt [%s]\\n\", wallet.resultMessage);\n    return LegacyWalletResult::INVALID_OR_CORRUPT;\n}\n"
  },
  {
    "path": "src/unity/android/logging_android.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"appname.h\"\n#include <string>\n#include <android/log.h>\n#include \"../unity_impl.h\"\n#include \"i_library_listener.hpp\"\n\nvoid OpenDebugLog()\n{\n}\n\nint LogPrintStr(const std::string &str)\n{\n    return __android_log_print(ANDROID_LOG_INFO, GLOBAL_APPNAME\"_core_jni_\", \"%s\", str.c_str());\n}\n\nvoid UnityReportError(const std::string &str)\n{\n    if (signalHandler)\n    {\n        signalHandler->notifyError(str);\n    }\n}\n"
  },
  {
    "path": "src/unity/appmanager.cpp",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"appname.h\"\n#include \"appmanager.h\"\n#include \"chainparams.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"util/threadnames.h\"\n#include \"witnessutil.h\"\n#include \"init.h\"\n#include \"warnings.h\"\n\n// Below  includes is for the socketpair that controls shutdown.\n#ifdef WIN32\n#include <sys/types.h>\n#endif\n\n#if HAVE_DECL_FORK\n#include <errno.h>\n#include <signal.h>\n#include <fcntl.h>\n#include <unistd.h>\n#endif\n\nAppLifecycleManager* AppLifecycleManager::gApp = nullptr;\n\nAppLifecycleManager::AppLifecycleManager()\n: fShutDownHasBeenInitiated(false)\n, fShutDownFromSigterm(false)\n, shutdownDidFinish(false)\n, recoveryBirthNumber(0)\n{\n    if (gApp)\n        assert(0);\n\n    gApp = this;\n\n    // Create the shutdown handler thread.\n    shutdownThread();\n}\n\nAppLifecycleManager::~AppLifecycleManager()\n{\n    // Refuse to close if initialize() or shutdown() is still busy.\n    std::lock_guard<std::mutex> lock(appManagerInitShutDownMutex);\n}\n\nvoid AppLifecycleManager::handleRunawayException(const std::exception *e)\n{\n    PrintExceptionContinue(e, \"Runaway exception\");\n    signalRunawayException((GetWarnings(\"gui\")));\n}\n\nvoid AppLifecycleManager::initialize()\n{\n    std::thread([=]\n    {\n        //RenameThread(GLOBAL_APPNAME\"-initialise\");\n        std::lock_guard<std::mutex> lock(appManagerInitShutDownMutex);\n        try\n        {\n            LogPrintf(\"AppLifecycleManager::initialize: Running initialization in thread\\n\");\n            if (fShutDownHasBeenInitiated)\n                return;\n            if (!AppInitBasicSetup())\n            {\n                signalAppInitializeResult(false);\n                return;\n            }\n            if (fShutDownHasBeenInitiated)\n                return;\n            if (!AppInitParameterInteraction())\n            {\n                signalAppInitializeResult(false);\n                return;\n            }\n            if (fShutDownHasBeenInitiated)\n                return;\n            if (!AppInitSanityChecks())\n            {\n                signalAppInitializeResult(false);\n                return;\n            }\n            if (fShutDownHasBeenInitiated)\n                return;\n\n            //fixme: (UNITY) - We handle only the last slot return here - this is fine for now as there -is- only one.\n            //However we should just use a custom combiner and boolean && the results to be future safe for other ports.\n            if (!signalAboutToInitMain())\n            {\n                LogPrintf(\"shutdown: AppLifecycleManager, signalAboutToInitMain returned false, terminating app\");\n                //Start shutdown process.\n                shutdown();\n                return;\n            }\n\n            if (fShutDownHasBeenInitiated)\n                return;\n\n            bool rv = AppInitMain(threadGroup, nodeContext);\n            signalAppInitializeResult(rv);\n        }\n        catch (const std::exception& e)\n        {\n            handleRunawayException(&e);\n        }\n        catch (...)\n        {\n            handleRunawayException(NULL);\n        }\n    }).detach();\n}\n\n// We use a socket here to signal shutdown to the main app.\n// As we (may) have been called from sigterm it is not safe to do anything else here.\n// See http://doc.qt.io/qt-5/unix-signals.html for more information.\nvoid AppLifecycleManager::shutdown(bool fromSigTerm)\n{\n    // Let the core know that we are in the early process of shutting down.\n    // Do this before the mutex so that if we are still in init we can abandon the init.\n    fShutDownHasBeenInitiated = true;\n    \n    fShutDownFromSigterm = fromSigTerm;\n\n    #ifdef WIN32\n    sigtermCv.notify_one();\n    #else\n    char signalClose = 1;\n\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wunused-result\"\n    ::write(sigtermFd[0], &signalClose, sizeof(signalClose));\n    #pragma GCC diagnostic pop\n\n    #endif\n}\n\nvoid AppLifecycleManager::waitForShutDown()\n{\n    std::unique_lock<std::mutex> lock(shutdownFinishMutex);\n    shutdownFinishCondition.wait(lock, [&]{ return shutdownDidFinish; });\n}\n\n#if HAVE_DECL_FORK\nbool daemoniseUsingFork() {\n    // deamonize using double fork as daemonise() is not standarized and available on all platforms\n    // instead use POSIX compliant fork() using double forking as described (for example)\n    // at http://www.microhowto.info/howto/cause_a_process_to_become_a_daemon_in_c.html\n\n    pid_t pid = fork();\n    if (pid == -1) {\n        return false;\n    } else if (pid != 0) {\n        // I'm the parent of the first fork, exit\n        _exit(0);\n    }\n\n    // Start a new session for the daemon.\n    if (setsid()==-1) {\n        return false;\n    }\n\n    // ignore closing of controlliing terminal\n    signal(SIGHUP,SIG_IGN);\n\n    pid=fork();\n    if (pid == -1) {\n        return false;\n    } else if (pid != 0) {\n        // I'm the parent of the 2nd fork, exit\n        _exit(0);\n    }\n\n    // close standard file descriptors.\n    close(STDIN_FILENO);\n    close(STDOUT_FILENO);\n    close(STDERR_FILENO);\n\n    // re-open\n    const char* DEV_NULL = \"/dev/null\";\n    if (open(DEV_NULL, O_RDONLY) == -1) {\n        return false;\n    }\n    if (open(DEV_NULL, O_WRONLY) == -1) {\n        return false;\n    }\n    if (open(DEV_NULL, O_RDWR) == -1) {\n        return false;\n    }\n\n    return true;\n}\n#endif\n\nbool AppLifecycleManager::daemonise()\n{\n    #if HAVE_DECL_FORK\n    {\n        bool managedToDeamonise = daemoniseUsingFork();\n\n        if (!managedToDeamonise)\n        {\n            fprintf(stderr, \"Error: daemon() failed: %s\\n\", strerror(errno));\n        }\n\n        // Create a new shutdownThread\n        shutdownThread();\n        return managedToDeamonise;\n    }\n    #else\n    fprintf(stderr, \"Error: -daemon is not supported on this operating system\\n\");\n    return false;\n    #endif\n}\n\nvoid AppLifecycleManager::shutdownThread()\n{\n    #ifndef WIN32\n    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd) == -1)\n    {\n        LogPrintf(\"shutdown thread: Failed to create socket pair\\n\");\n        assert(0);\n    }\n    #endif\n\n    std::thread([=]\n    {\n        util::ThreadRename(GLOBAL_APPNAME\"-shutdown\");\n\n        // Block until we are signalled to commence\n        #ifdef WIN32\n        std::unique_lock<std::mutex> lk(appManagerInitShutDownMutex);\n        sigtermCv.wait(lk, [this]{ return fShutDownHasBeenInitiated == true; });\n        #else\n        char signalClose = 0;\n        #pragma GCC diagnostic push\n        #pragma GCC diagnostic ignored \"-Wunused-result\"\n        ::read(sigtermFd[1], &signalClose, sizeof(signalClose));\n        #pragma GCC diagnostic pop\n        LogPrintf(\"shutdown thread: App shutdown requested\\n\");\n        if (fShutDownFromSigterm)\n            LogPrintf(\"shutdown thread: App shutdown requested from SIGTERM\\n\");\n        std::lock_guard<std::mutex> lock(appManagerInitShutDownMutex);\n        #endif\n\n        LogPrintf(\"shutdown thread: Commence app shutdown\\n\");\n\n        try\n        {\n            // Allow UI to visually alert start of shutdown progress.\n            LogPrintf(\"shutdown thread: Signal start of shutdown to UI\\n\");\n            signalAppShutdownStarted();\n            MilliSleep(200);\n\n            LogPrintf(\"shutdown thread: Signal UI to alert user of shutdown\\n\");\n            signalAppShutdownAlertUser();\n            MilliSleep(50);\n\n            // Notify all core and network threads to start \"wrapping up\".\n            LogPrintf(\"shutdown thread: Interrupt core\\n\");\n            CoreInterrupt(threadGroup);\n            MilliSleep(50);\n\n            // Notify UI that core shutdown has begun and that it should start disconnecting the various models/signals.\n            LogPrintf(\"shutdown thread: Signal core interrupt to UI\\n\");\n            signalAppShutdownCoreInterrupted();\n            MilliSleep(50);\n\n            // Terminate all core threads.\n            LogPrintf(\"shutdown thread: Shut down core\\n\");\n            CoreShutdown(threadGroup, nodeContext);\n            MilliSleep(50);\n\n            LogPrintf(\"shutdown thread: Core shutdown finished, signaling UI to shut itself down\\n\");\n            signalAppShutdownFinished();\n            MilliSleep(50);\n\n            // signal threads blocked on waitForShutDown()\n            {\n                std::lock_guard<std::mutex> lock(shutdownFinishMutex);\n                shutdownDidFinish = true;\n            }\n            shutdownFinishCondition.notify_all();\n\n            LogPrintf(\"shutdown thread: Exiting shutdown thread\\n\");\n        }\n        catch (const std::exception& e)\n        {\n            LogPrintf(\"AppLifecycleManager::shutdownThread: App shutdown exception [%s]\\n\", e.what());\n            handleRunawayException(&e);\n        }\n        catch (...)\n        {\n            LogPrintf(\"AppLifecycleManager::shutdownThread: App shutdown exception\\n\");\n            handleRunawayException(NULL);\n        }\n    }).detach();\n}\n\nvoid AppLifecycleManager::setRecoveryPhrase(const SecureString& recoveryPhrase_)\n{\n    recoveryPhrase = recoveryPhrase_;\n}\n\nSecureString AppLifecycleManager::getRecoveryPhrase()\n{\n    return recoveryPhrase;\n}\n\nvoid AppLifecycleManager::BurnRecoveryPhrase()\n{\n    // The below is a 'SecureString' - so no memory burn necessary, it should burn itself.\n    recoveryPhrase = \"\";\n}\n\n// if no birth number given or birth number is invalid the result will be zero\nvoid AppLifecycleManager::splitRecoveryPhraseAndBirth(const SecureString& input, SecureString& phrase, int& birthNumber)\n{\n    phrase = input;\n\n    auto lastSpace = phrase.find_last_of(\" \");\n    if (lastSpace != SecureString::npos) {\n        std::string birthString(phrase.substr(lastSpace));\n        try {\n            birthNumber = std::stoi(birthString);\n        }\n        catch (const std::exception&) {\n            birthNumber = 0;\n        }\n        if (birthNumber != 0 || birthString == \"0\") {\n            // succesfull numeric conversion, strip birth number from phrase\n            phrase.erase(lastSpace);\n        }\n    }\n}\n\nint AppLifecycleManager::getRecoveryBirth() const\n{\n    return recoveryBirthNumber;\n}\n\nvoid AppLifecycleManager::setRecoveryBirthNumber(int _recoveryBirth)\n{\n    recoveryBirthNumber = _recoveryBirth;\n}\n\nint64_t AppLifecycleManager::getRecoveryBirthTime() const\n{\n    return birthNumberToTime(recoveryBirthNumber);\n}\n\nvoid AppLifecycleManager::setRecoveryBirthTime(int64_t birthTime)\n{\n    if (birthTime >= Params().GenesisBlock().nTime) {\n        recoveryBirthNumber = timeToBirthNumber(birthTime);\n    }\n    else\n        recoveryBirthNumber = 0;\n}\n\nSecureString AppLifecycleManager::getCombinedRecoveryPhrase() const\n{\n    if (recoveryBirthNumber != 0)\n        return recoveryPhrase + SecureString(\" \") + SecureString(i64tostr(recoveryBirthNumber));\n    else\n        return recoveryPhrase;\n}\n\nvoid AppLifecycleManager::setCombinedRecoveryPhrase(const SecureString& combinedPhrase)\n{\n    SecureString phrase;\n    int birth;\n    splitRecoveryPhraseAndBirth(combinedPhrase, phrase, birth);\n    setRecoveryPhrase(phrase);\n    setRecoveryBirthNumber(birth);\n}\n\nstd::pair<SecureString, int> AppLifecycleManager::composeRecoveryPhrase(const SecureString& phrase, int64_t birthTime)\n{\n    if (birthTime != 0)\n    {\n        int birthNumber = timeToBirthNumber(birthTime);\n        return std::pair(phrase + SecureString(\" \") + SecureString(i64tostr(birthNumber)), birthNumber);\n    }\n    else\n        return std::pair(phrase, 0);\n}\n\nvoid AppLifecycleManager::setLinkKey(CEncodedSecretKeyExt<CExtKey> _linkKey)\n{\n    linkKey = _linkKey;\n}\n\nint64_t AppLifecycleManager::getLinkedBirthTime() const\n{\n    return linkKey.getCreationTime();\n}\n\nCEncodedSecretKeyExt<CExtKey> AppLifecycleManager::getLinkedKey() const\n{\n    return linkKey;\n}\n\nvoid AppLifecycleManager::setRecoveryPassword(const SecureString& password_)\n{\n    recoveryPassword = password_;\n}\n\nSecureString AppLifecycleManager::getRecoveryPassword()\n{\n    return recoveryPassword;\n}\n\nvoid AppLifecycleManager::SecureWipeRecoveryDetails()\n{\n    //fixme: (UNITY) Burn all seeds/passwords etc. here.\n}\n\nbool ShutdownRequested()\n{\n    return AppLifecycleManager::gApp ? (bool)AppLifecycleManager::gApp->fShutDownHasBeenInitiated : false;\n}\n"
  },
  {
    "path": "src/unity/appmanager.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef UNITY_APP_MANAGER_H\n#define UNITY_APP_MANAGER_H\n\n#include \"signals.h\"\n#include \"scheduler.h\"\n#include \"base58.h\"\n#include \"support/allocators/secure.h\"\n#include <atomic>\n#include <string>\n#include <thread>\n#include <boost/signals2/signal.hpp>\n#include <boost/thread.hpp>\n#include <condition_variable>\n#include <node/context.h>\n\n\n/** Class encapsulating Munt startup and shutdown.\n * Allows running startup and shutdown in a different thread from the UI thread.\n */\nclass AppLifecycleManager\n{\npublic:\n    //! NB! Only initialise once, afterwards refer to by gApp static instance.\n    AppLifecycleManager();\n    ~AppLifecycleManager();\n    static AppLifecycleManager* gApp;\n\n    //! NB! This runs in a detached thread\n    void initialize();\n\n    //! NB! This signals, in a sigterm safe way, to shutdownThread that it should start the shutdown process.\n    //! All actual work takes places inside shutdownThread which is a detached thread\n    void shutdown(bool fromSigTerm=false);\n\n    //! Explicitly wait for shutdown to complete\n    void waitForShutDown();\n\n    //! This places the app in a daemonised state.\n    //! NB! Always call this before calling initialise.\n    bool daemonise();\n\n    std::atomic<bool> fShutDownHasBeenInitiated;\n    std::atomic<bool> fShutDownFromSigterm;\n\n    //NB! The below signals are -not- from UI thread, if the UI handles them it should take this into account.\n    boost::signals2::signal<void (bool initializeResult)> signalAppInitializeResult;\n    boost::signals2::signal<bool (), BooleanAndAllReturnValues> signalAboutToInitMain;\n    boost::signals2::signal<void ()> signalAppShutdownStarted;\n    boost::signals2::signal<void ()> signalAppShutdownAlertUser;\n    boost::signals2::signal<void ()> signalAppShutdownCoreInterrupted;\n    boost::signals2::signal<void ()> signalAppShutdownFinished;\n    boost::signals2::signal<void (std::string exceptionMessage)> signalRunawayException;\nprivate:\n    std::mutex shutdownFinishMutex;\n    std::condition_variable shutdownFinishCondition;\n    bool shutdownDidFinish;\n\n    std::mutex appManagerInitShutDownMutex;\n    #ifdef WIN32\n    std::condition_variable sigtermCv;\n    #else\n    int sigtermFd[2];\n    #endif\n    void handleRunawayException(const std::exception *e);\n    void shutdownThread();\n\n    // App globals, not used internally by AppLifecycleManager.\npublic:\n    void setRecoveryPhrase(const SecureString& recoveryPhrase);\n    SecureString getRecoveryPhrase();\n    // Set to true if we are busy starting a new wallet via \"recovery phrase\"\n    bool isRecovery = false;\n    // Set to true if we are busy starting a new wallet via \"link\"\n    bool isLink = false;\n\n    //fixme: (UNITY) (SPV) move these recovery helpers to a better place\n    int getRecoveryBirth() const;\n    int64_t getRecoveryBirthTime() const;\n    void setRecoveryBirthNumber(int _recoveryBirth);\n    void setRecoveryBirthTime(int64_t birthTime);\n    SecureString getCombinedRecoveryPhrase() const;\n    static std::pair<SecureString, int> composeRecoveryPhrase(const SecureString& phrase, int64_t birthTime);\n    void setCombinedRecoveryPhrase(const SecureString& combinedPhrase);\n    static void splitRecoveryPhraseAndBirth(const SecureString& input, SecureString& phrase, int& birthNumber);\n    void setLinkKey(CEncodedSecretKeyExt<CExtKey> _linkKey);\n    int64_t getLinkedBirthTime() const;\n    void setRecoveryPassword(const SecureString& password_);\n    SecureString getRecoveryPassword();\n    CEncodedSecretKeyExt<CExtKey> getLinkedKey() const;\n\n    void SecureWipeRecoveryDetails();\nprivate:\n    void BurnRecoveryPhrase();\n    CEncodedSecretKeyExt<CExtKey> linkKey;\n    SecureString recoveryPhrase;\n    SecureString recoveryPassword;\n    int recoveryBirthNumber;\n\n    // Passed on to the rest of the app but not used internally by AppLifecycleManager.\n    boost::thread_group threadGroup;\n    node::NodeContext nodeContext;\n};\n\nbool ShutdownRequested();\n\n#endif\n"
  },
  {
    "path": "src/unity/compat/android_wallet.cpp",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"android_wallet.h\"\n#include \"util.h\"\n\n\n#include <google/protobuf/descriptor.h>\n#include <google/protobuf/dynamic_message.h>\n#include <google/protobuf/io/zero_copy_stream_impl.h>\n#include <google/protobuf/descriptor.pb.h>\n#include <crypto/scrypt/crypto_scrypt.h>\n\n#include <cryptopp/config.h>\n#include <cryptopp/aes.h>\n#include <cryptopp/modes.h>\n#include <cryptopp/filters.h>\n\n#include <codecvt>\n#include <locale>\n\n#include <boost/scope_exit.hpp>\n\n#ifdef WIN32\n#include <fcntl.h>\n#endif\n\n\nusing namespace google::protobuf;\n\n\n// The bitcoinj authors opted to split the utf16 password characters into bytes as opposed to doing a utf8 conversion or similar\n// This replicates that behaviour.\nstd::vector<uint8_t> convertToJavaByteArray(const std::u16string& u16_string)\n{\n    std::vector<uint8_t> ret;\n    ret.resize(u16_string.length()*2);\n    for(uint32_t i = 0; i < u16_string.length(); i++)\n    {\n        int bytePosition = i << 1;\n        ret[bytePosition] = uint8_t((u16_string[i]&0xFF00) >> 8);\n        ret[bytePosition + 1] = uint8_t(u16_string[i]&0x00FF);\n    }\n    return ret;\n}\n\nstd::string codec_type = \"EmptyMessage\";\nandroid_wallet ParseAndroidProtoWallet(std::string walletPath, std::string walletPassword)\n{\n    android_wallet walletRet;\n\n    //Parse the file with a blank/empty proto\n    DescriptorPool pool;\n    FileDescriptorProto file;\n    file.set_name(\"empty_message.proto\");\n    file.add_message_type()->set_name(codec_type);\n    pool.BuildFile(file);\n    const Descriptor* type = pool.FindMessageTypeByName(codec_type);\n\n    DynamicMessageFactory dynamic_factory(&pool);\n    std::unique_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());\n    std::unique_ptr<Message> nestedMessage(dynamic_factory.GetPrototype(type)->New());\n\n    int fd = open(walletPath.c_str(), O_RDONLY);\n    if (fd<=0)\n    {\n        walletRet.resultMessage = \"Failed to open input file.\";\n        walletRet.fileOpenError = true;\n        return walletRet;\n    }\n    // Parse binary input\n    io::FileInputStream in(fd);\n    BOOST_SCOPE_EXIT(&fd) { close(fd); } BOOST_SCOPE_EXIT_END\n\n    if (!message->ParsePartialFromZeroCopyStream(&in))\n    {\n        walletRet.resultMessage = \"Failed to parse input.\";\n        return walletRet;\n    }\n\n    if (!message->IsInitialized())\n    {\n        walletRet.resultMessage = \"Failed to parse input, missing required fields.\";\n        return walletRet;\n    }\n\n    auto fieldSet = message->GetReflection()->MutableUnknownFields(message.get());\n\n    walletRet.numWalletFields = fieldSet->field_count();\n\n    //Variables for dealing with password hashing\n    std::string scryptSalt;\n    int64_t scryptN=16383;\n    int32_t scryptR=8;\n    int32_t scryptP=1;\n    std::string aesIV;\n    std::string aesCryptedData;\n\n    // Navigate the field tree\n    for (int i=0;i<fieldSet->field_count();++i)\n    {\n        auto field = fieldSet->field(i);\n        switch (field.number())\n        {\n            case 1:\n            {\n                if (field.type() == 3)\n                {\n                    // All valid wallet files should have this field.\n                    if (field.length_delimited() == \"com.munt.production\") { walletRet.validWalletProto = true; }\n                }\n                break;\n            }\n            case 6:\n            {\n                if (!nestedMessage->ParsePartialFromString(field.length_delimited()))\n                {\n                    walletRet.resultMessage = \"Failed to parse input for nested scrypt data.\";\n                    return walletRet;\n                }\n                auto nestedFieldSet =  nestedMessage->GetReflection()->MutableUnknownFields(nestedMessage.get());\n                for (int j=0;j<nestedFieldSet->field_count();++j)\n                {\n                    auto nestedField = nestedFieldSet->field(j);\n                    switch (nestedField.number())\n                    {\n                        case 1: scryptSalt = nestedField.length_delimited(); break;\n                        case 2: scryptN = nestedField.varint(); break;\n                        case 3: scryptR = nestedField.varint(); break;\n                        case 4: scryptP = nestedField.varint(); break;\n                        default: walletRet.resultMessage = \"Unknown encyption paramater.\"; return walletRet;\n                    }\n                }\n                break;\n            }\n            case 3:\n            {\n                if (!nestedMessage->ParsePartialFromString(field.length_delimited()))\n                {\n                    walletRet.resultMessage = \"Failed to parse input for nested key.\";\n                    return walletRet;\n                }\n                auto nestedFieldSet =  nestedMessage->GetReflection()->MutableUnknownFields(nestedMessage.get());\n                int keyType = -1;\n                for (int j=0;j<nestedFieldSet->field_count();++j)\n                {\n                    auto nestedField = nestedFieldSet->field(j);\n                    // Grab the lowest possible birth date from the proto.\n                    if (nestedField.number() == 5 && nestedField.type() == 0)\n                    {\n                        //Birth dates were stored in milliseconds to convert to seconds\n                        uint64_t timeStamp = nestedField.varint()/1000;\n                        if (walletRet.walletBirth == 0 || walletRet.walletBirth > timeStamp)\n                        {\n                            walletRet.walletBirth = timeStamp;\n                        }\n                    }\n                    if (keyType < 0)\n                    {\n                        if (nestedField.number() == 1 && nestedField.type() == 0)\n                        {\n                            keyType = nestedField.varint();\n                            switch (keyType)\n                            {\n                                case 3: break;\n                                case 5: break;\n                                case 4: LogPrintf(\"ParseAndroidProtoWallet: Skipping HD key\\n\"); break;\n                                default: LogPrintf(\"ParseAndroidProtoWallet: Unhandled key type [%d]\\n\", keyType); break;\n                            }\n                        }\n                    }\n                    else \n                    {\n                        switch (keyType)\n                        {\n                            case 3:\n                            case 5:\n                            {\n                                if (nestedField.type()==3)\n                                {\n                                    switch (nestedField.number())\n                                    {\n                                        case 2:\n                                        {\n                                            walletRet.walletSeedMnemonic = nestedField.length_delimited();\n                                            break;\n                                        }\n                                        case 6:\n                                        {\n                                            walletRet.encrypted = true;\n\n                                            std::unique_ptr<Message> aesMessage(dynamic_factory.GetPrototype(type)->New());\n                                            if (!aesMessage->ParsePartialFromString(nestedField.length_delimited()))\n                                            {\n                                                walletRet.resultMessage = \"Failed to parse input for encrypted key.\";\n                                                return walletRet;\n                                            }\n                                            auto aesFieldSet = aesMessage->GetReflection()->MutableUnknownFields(aesMessage.get());\n                                            for (int k=0;k<aesFieldSet->field_count();++k)\n                                            {\n                                                auto aesField = aesFieldSet->field(k);\n                                                switch (aesField.number())\n                                                {\n                                                    case 1: aesIV = aesField.length_delimited(); break;\n                                                    case 2: aesCryptedData = aesField.length_delimited(); break;\n                                                    default: walletRet.resultMessage = \"Invalid encryption data for encrypted key.\"; return walletRet;\n                                                }\n                                            }\n                                            break;\n                                        }\n                                    }\n                                }\n                                break;\n                            }\n                            case 4: break;\n                            default: LogPrintf(\"ParseAndroidProtoWallet: Unhandled field         [%d] [%d]\\n\", nestedField.number(), nestedField.type()); break;\n                        }\n                    }\n                }\n                break;\n            }\n            default: LogPrintf(\"ParseAndroidProtoWallet: Unhandled field [%d] [%d]\\n\", field.number(), field.type()); break;\n        }\n    }\n\n    if (!scryptSalt.empty())\n    {\n        // Generate aes key data from password using the provided scrypt paramaters.\n        std::vector<uint8_t> aesKeyData;\n        aesKeyData.resize(32);\n        std::vector<uint8_t> passwordData = convertToJavaByteArray(std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(walletPassword));\n        crypto_scrypt((uint8_t*)&passwordData[0], passwordData.size(), (uint8_t*)scryptSalt.c_str(), scryptSalt.length(), scryptN, scryptR, scryptP, &aesKeyData[0], 32);\n\n        // Combine the AES key with the IV and the encrypted data to retrieve the original unencrypted data\n        CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec;\n        dec.SetKeyWithIV(&aesKeyData[0], aesKeyData.size(), (const unsigned char*)&aesIV[0]);\n        bool failed = false;\n        try\n        {\n            auto sink = new CryptoPP::StringSink(walletRet.walletSeedMnemonic);\n            {\n                CryptoPP::StringSource s(aesCryptedData, true, new CryptoPP::StreamTransformationFilter(dec, sink));\n            }\n            if (walletRet.walletSeedMnemonic.length() == 0)\n            {\n                failed = true;\n            }\n        }\n        catch(...)\n        {\n            failed = true;\n        }\n        if (failed)\n        {\n            walletRet.resultMessage = \"Decryption failed.\";\n            return walletRet;\n        }\n    }\n    if (!walletRet.walletSeedMnemonic.empty())\n    {\n        walletRet.validWallet = true;\n    }\n\n    return walletRet;\n}\n"
  },
  {
    "path": "src/unity/compat/android_wallet.h",
    "content": "// Copyright (c) 2019-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <string>\n\nstruct android_wallet\n{\n    bool fileOpenError = false;\n    // True if we recognise the data file as being a minimally valid wallet file, does not guarantee that it actually contains any useful info.\n    bool validWalletProto = false;\n    // True if we manages to succesfully extract information from the wallet, may be false if that information is encrypted and no password was provided.\n    bool validWallet = false;\n    // True if we encountered encrypted information in the wallet.\n    bool encrypted = false;\n    // If the wallet contained a seed mnemonic that we managed to extract it will be set here.\n    std::string walletSeedMnemonic;\n    // If we managed to extract a wallet birth date this will be set to non zero with that date.\n    uint64_t walletBirth=0;\n    // In the case of failure resultMessage will be non empty and contain additional information.\n    std::string resultMessage;\n    // The number of fields encountered inside the wallet file.\n    uint64_t numWalletFields=0;\n};\n\nandroid_wallet ParseAndroidProtoWallet(std::string walletPath, std::string walletPassword);\n"
  },
  {
    "path": "src/unity/controllers/iaccountscontroller.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n#include \"appname.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"validation/validation.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n\n\n#include <wallet/wallet.h>\n#include <wallet/account.h>\n#include <wallet/witness_operations.h>\n\n// Unity specific includes\n#include \"../unity_impl.h\"\n#include \"i_accounts_controller.hpp\"\n#include \"i_accounts_listener.hpp\"\n#include \"account_record.hpp\"\n#include \"account_link_record.hpp\"\n#include \"balance_record.hpp\"\n#include \"mutation_record.hpp\"\n\nstd::shared_ptr<IAccountsListener> accountsListener;\nstd::list<boost::signals2::connection> coreSignalConnections;\n\nstd::vector<AccountLinkRecord> listAccountLinksHelper(CAccount* forAccount)\n{\n    std::vector<AccountLinkRecord> result;\n    if (forAccount)\n    {\n        const auto& accountLinks = forAccount->getLinks();\n        for (const auto& [serviceName, serviceData] : accountLinks)\n        {\n            result.push_back(AccountLinkRecord(serviceName, serviceData));\n        }\n    }\n    return result;\n}\n\n//fixme: (DEDUP) - try share common code with RPC listallaccounts function\nAccountRecord GetAccountRecord(const boost::uuids::uuid& accountUUID, CAccount* forAccount)\n{\n    AccountRecord rec(\"\", \"\", \"\", \"\", false, std::vector<AccountLinkRecord>());\n    rec.UUID = getUUIDAsString(accountUUID);\n    rec.label = forAccount->getLabel();\n    rec.state = GetAccountStateString(forAccount->m_State);\n    rec.type = GetAccountTypeString(forAccount->m_Type);\n    rec.accountLinks = listAccountLinksHelper(forAccount);\n    if (!forAccount->IsHD())\n    {\n        rec.isHD = false;\n    }\n    else\n    {\n        rec.isHD = true;\n    }\n    return rec;\n}\n\nvoid IAccountsController::setListener(const std::shared_ptr<IAccountsListener>& accountsListener_)\n{\n    accountsListener = accountsListener_;\n        \n    // Disconnect all already connected signals\n    for (auto& connection: coreSignalConnections)\n    {\n        connection.disconnect();\n    }\n    coreSignalConnections.clear();\n        \n    if (pactiveWallet && accountsListener)\n    {\n        coreSignalConnections.push_back(pactiveWallet->NotifyActiveAccountChanged.connect([](CWallet* pWallet, CAccount* pAccount)\n        {\n            accountsListener->onActiveAccountChanged(getUUIDAsString(pAccount->getUUID()));\n        }));\n        coreSignalConnections.push_back(pactiveWallet->NotifyAccountNameChanged.connect([](CWallet* pWallet, CAccount* pAccount)\n        {\n            accountsListener->onAccountNameChanged(getUUIDAsString(pAccount->getUUID()), pAccount->getLabel());\n            if (pAccount == pactiveWallet->activeAccount)\n            {\n                accountsListener->onActiveAccountNameChanged(pAccount->getLabel());\n            }\n        }));\n        coreSignalConnections.push_back(pactiveWallet->NotifyAccountModified.connect([](CWallet* pWallet, CAccount* pAccount)\n        {\n            accountsListener->onAccountModified(getUUIDAsString(pAccount->getUUID()), GetAccountRecord(pAccount->getUUID(), pAccount));\n        }));\n        coreSignalConnections.push_back(pactiveWallet->NotifyAccountAdded.connect([](CWallet* pWallet, CAccount* pAccount)\n        {\n            accountsListener->onAccountAdded(getUUIDAsString(pAccount->getUUID()), pAccount->getLabel());\n        }));\n        coreSignalConnections.push_back(pactiveWallet->NotifyAccountDeleted.connect([](CWallet* pWallet, CAccount* pAccount)\n        {\n            accountsListener->onAccountDeleted(getUUIDAsString(pAccount->getUUID()));\n        }));\n        //NotifyAccountWarningChanged\n        //NotifyAccountCompoundingChanged\n    }\n}\n\nbool IAccountsController::setActiveAccount(const std::string & accountUUID)\n{\n    if (!pactiveWallet)\n        return false;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        CWalletDB walletdb(*pactiveWallet->dbw);\n        pactiveWallet->setActiveAccount(walletdb, forAccount);\n        return true;\n    }\n    return false;\n}\n\nstd::string IAccountsController::getActiveAccount()\n{\n    if (pactiveWallet)\n    {        \n        CAccount* activeAccount = pactiveWallet->getActiveAccount();\n        if (activeAccount)\n        {\n            return getUUIDAsString(activeAccount->getUUID());\n        }\n    }\n    return \"\";\n}\n\n//fixme: Move this out into a common helper and add an RPC equivalent\nstd::string IAccountsController::getAccountLinkURI(const std::string & accountUUID)\n{\n    if (!pactiveWallet || dynamic_cast<CExtWallet*>(pactiveWallet)->IsLocked())\n        return \"\";\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        \n        int64_t currentTime = forAccount->getEarliestPossibleCreationTime();\n        std::string payoutAddress;\n        std::string qrString = \"\";\n        if (forAccount->IsHD() && !forAccount->IsPoW2Witness())\n        {\n            CReserveKeyOrScript reservekey(pactiveWallet, forAccount, KEYCHAIN_CHANGE);\n            CPubKey vchPubKey;\n            if (!reservekey.GetReservedKey(vchPubKey))\n                return \"\";\n            payoutAddress = CNativeAddress(vchPubKey.GetID()).ToString();\n\n            qrString = GLOBAL_APPNAME\"sync:\" + CEncodedSecretKeyExt<CExtKey>(*(static_cast<CAccountHD*>(forAccount)->GetAccountMasterPrivKey())).SetCreationTime(i64tostr(currentTime)).SetPayAccount(payoutAddress).ToURIString();\n            \n            return qrString;\n        }\n        \n        return \"\";\n    }\n    return \"\";\n}\n\nstd::string IAccountsController::getWitnessKeyURI(const std::string & accountUUID)\n{\n    if (!pactiveWallet || dynamic_cast<CExtWallet*>(pactiveWallet)->IsLocked())\n        return \"\";\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        if (forAccount->IsPoW2Witness())\n        {\n            return witnessKeysLinkUrlForAccount(pactiveWallet, forAccount);\n        }\n    }\n    return \"\";\n}\n\nstd::string IAccountsController::createAccountFromWitnessKeyURI(const std::string& witnessKeyURI, const std::string& newAccountName)\n{\n    if (!pactiveWallet || dynamic_cast<CExtWallet*>(pactiveWallet)->IsLocked())\n        return \"\";\n\n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        if (account->getLabel() == newAccountName)\n        {\n            return \"\";\n        }\n    }\n        \n    bool shouldRescan = true;\n    const auto& keysAndBirthDates = pactiveWallet->ParseWitnessKeyURL(SecureString(witnessKeyURI.begin(), witnessKeyURI.end()));\n    if (keysAndBirthDates.empty())\n        throw std::runtime_error(\"Invalid encoded key URL\");\n\n    CAccount* account = nullptr;\n    //NB! CreateWitnessOnlyWitnessAccount triggers a rescan for us\n    account = pactiveWallet->CreateWitnessOnlyWitnessAccount(newAccountName, keysAndBirthDates, shouldRescan);\n    if (!account)\n        return \"\";\n\n    return getUUIDAsString(account->getUUID());\n}\n\nbool IAccountsController::deleteAccount(const std::string & accountUUID)\n{\n    if (!pactiveWallet)\n        return false;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        CWalletDB walletdb(*pactiveWallet->dbw);\n        pactiveWallet->deleteAccount(walletdb, forAccount, false);\n        return true;\n    }\n    return false;\n}\n\nbool IAccountsController::purgeAccount(const std::string & accountUUID)\n{\n    if (!pactiveWallet)\n        return false;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        CWalletDB walletdb(*pactiveWallet->dbw);\n        pactiveWallet->deleteAccount(walletdb, forAccount, true);\n        return true;\n    }\n    return false;\n}\n\nstd::string IAccountsController::createAccount(const std::string& accountName, const std::string& accountType)\n{\n    if (!pactiveWallet)\n        return \"\";\n\n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* pNewAccount = CreateAccountHelper(pactiveWallet, accountName, accountType, false);\n    if (pNewAccount)\n        return getUUIDAsString(pNewAccount->getUUID());\n    \n    return \"\";\n}\n\nstd::string IAccountsController::getAccountName(const std::string& accountUUID)\n{\n    if (!pactiveWallet)\n        return \"\";\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        return forAccount->getLabel();\n    }\n    return \"\";\n}\n\nbool IAccountsController::renameAccount(const std::string& accountUUID, const std::string& newAccountName)\n{\n    if (!pactiveWallet)\n        return false;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = NULL;\n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n    if (findIter != pactiveWallet->mapAccounts.end())\n    {\n        forAccount = findIter->second;\n        pactiveWallet->changeAccountName(forAccount, newAccountName);\n        return true;\n    }\n        \n    return false;\n}\n\n\nstd::vector<AccountRecord> IAccountsController::listAccounts()\n{\n    std::vector<AccountRecord> ret;\n\n    if (!pactiveWallet)\n        return ret;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    for (const auto& accountPair : pactiveWallet->mapAccounts)\n    {\n        ret.emplace_back(GetAccountRecord(accountPair.first, accountPair.second));\n    }\n    return ret;\n}\n  \nBalanceRecord IAccountsController::getActiveAccountBalance()\n{\n    if (!pactiveWallet)\n        return BalanceRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, pactiveWallet->activeAccount, true);\n    return BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked);\n}\n\nBalanceRecord IAccountsController::getAccountBalance(const std::string& accountUUID)\n{\n    if (pactiveWallet)\n    {\n        DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            WalletBalances balances;\n            pactiveWallet->GetBalances(balances, findIter->second, true);\n            return BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked);\n        }\n    }\n    return BalanceRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n}\n\nstd::unordered_map<std::string, BalanceRecord> IAccountsController::getAllAccountBalances()\n{\n    std::unordered_map<std::string, BalanceRecord> ret;\n    \n    if (!pactiveWallet)\n        return ret;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        if (account->m_State == AccountState::Normal)\n        {\n            WalletBalances balances;\n            pactiveWallet->GetBalances(balances, account, true);\n            ret.emplace(getUUIDAsString(accountUUID), BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked));\n        }\n    }    \n    return ret;\n}\n\nstd::vector<TransactionRecord> IAccountsController::getTransactionHistory(const std::string& accountUUID)\n{\n    if (pactiveWallet)\n    {\n        DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            return getTransactionHistoryForAccount(findIter->second);\n        }\n    }\n    return std::vector<TransactionRecord>();\n}\n\nstd::vector<MutationRecord> IAccountsController::getMutationHistory(const std::string& accountUUID)\n{\n    if (pactiveWallet)\n    {\n        DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            return getMutationHistoryForAccount(findIter->second);\n        }\n    }\n    return std::vector<MutationRecord>();\n}\n\nstd::string IAccountsController::getReceiveAddress(const std::string & accountUUID)\n{\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CReserveKeyOrScript* receiveAddress = new CReserveKeyOrScript(pactiveWallet, findIter->second, KEYCHAIN_EXTERNAL);\n            CPubKey pubKey;\n            if (receiveAddress->GetReservedKey(pubKey))\n            {\n                CKeyID keyID = pubKey.GetID();\n                receiveAddress->ReturnKey();\n                delete receiveAddress;\n                return CNativeAddress(keyID).ToString();\n            }\n        }\n    }\n    return \"\";\n}\n\nbool IAccountsController::addAccountLink(const std::string& accountUUID, const std::string& serviceName, const std::string& serviceData)\n{\n    if (serviceName.empty())\n    {\n        return false;\n    }\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* forAccount = findIter->second;\n            CWalletDB walletdb(*pactiveWallet->dbw);\n            forAccount->addLink(serviceName, serviceData, &walletdb);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool IAccountsController::removeAccountLink(const std::string& accountUUID, const std::string& serviceName)\n{\n    if (serviceName.empty())\n    {\n        return false;\n    }\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* forAccount = findIter->second;\n            CWalletDB walletdb(*pactiveWallet->dbw);\n            forAccount->removeLink(serviceName, &walletdb);\n            return true;\n        }\n    }\n    return false;\n}\n\nstd::vector<AccountLinkRecord> IAccountsController::listAccountLinks(const std::string& accountUUID)\n{\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(accountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* forAccount = findIter->second;\n            return listAccountLinksHelper(forAccount);\n        }\n    }\n    return std::vector<AccountLinkRecord>();\n}\n"
  },
  {
    "path": "src/unity/controllers/igenerationcontroller.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n#include \"appname.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"validation/validation.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n\n#include \"util.h\"\n#include \"generation/miner.h\"\n\n\n#include <wallet/wallet.h>\n#include <wallet/extwallet.h>\n#include <wallet/account.h>\n#include <wallet/witness_operations.h>\n\n// Unity specific includes\n#include \"i_generation_controller.hpp\"\n#include \"i_generation_listener.hpp\"\n\nstd::shared_ptr<IGenerationListener> generationListener;\nstd::list<boost::signals2::connection> coreGenerationSignalConnections;\n\nvoid IGenerationController::setListener(const std::shared_ptr<IGenerationListener>& generationListener_)\n{\n    generationListener = generationListener_;\n        \n    // Disconnect all already connected signals\n    for (auto& connection: coreGenerationSignalConnections)\n    {\n        connection.disconnect();\n    }\n    coreGenerationSignalConnections.clear();\n        \n    if (pactiveWallet && generationListener)\n    {\n        coreGenerationSignalConnections.push_back(pactiveWallet->NotifyGenerationStarted.connect([]()\n        {\n            generationListener->onGenerationStarted();\n        }));\n        coreGenerationSignalConnections.push_back(pactiveWallet->NotifyGenerationStopped.connect([]()\n        {\n            generationListener->onGenerationStopped();\n        }));\n        coreGenerationSignalConnections.push_back(pactiveWallet->NotifyGenerationStatisticsUpdate.connect([]()\n        {\n            //fixme: (DEDUP) - Share this code with RPC if possible\n            double dHashPerSecLog = dHashesPerSec;\n            std::string sHashPerSecLogLabel = \" h\";\n            selectLargesHashUnit(dHashPerSecLog, sHashPerSecLogLabel);\n            double dRollingHashPerSecLog = dRollingHashesPerSec;\n            std::string sRollingHashPerSecLogLabel = \" h\";\n            selectLargesHashUnit(dRollingHashPerSecLog, sRollingHashPerSecLogLabel);\n            double dBestHashPerSecLog = dBestHashesPerSec;\n            std::string sBestHashPerSecLogLabel = \" h\";\n            selectLargesHashUnit(dBestHashPerSecLog, sBestHashPerSecLogLabel);\n            generationListener->onStatsUpdated(dHashPerSecLog, sHashPerSecLogLabel, dRollingHashPerSecLog, sRollingHashPerSecLogLabel, dBestHashPerSecLog, sBestHashPerSecLogLabel, nArenaSetupTime/1000.0);\n        }));\n    }\n}\n\nCAccount* findMiningAccount(CWallet* pWallet)\n{\n    for (const auto& [accountUUID, account] : pWallet->mapAccounts)\n    {\n        (unused) accountUUID;\n        if (account->IsMiningAccount() && account->m_State == AccountState::Normal)\n        {\n            return account;\n        }\n    }\n    return nullptr;\n}\n\nbool IGenerationController::startGeneration(int32_t numThreads, int32_t numArenaThreads, const std::string& memoryLimit)\n{\n    if (!pactiveWallet)\n    {\n        return false;\n    }\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    CAccount* forAccount = findMiningAccount(pactiveWallet);\n    if (!forAccount)\n    {\n        return false;\n    }\n    \n    std::string overrideAccountAddress;\n    CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(overrideAccountAddress);\n\n    // Allow user to override default memory selection.\n    uint64_t nGenMemoryLimitBytes = GetMemLimitInBytesFromFormattedStringSpecifier(memoryLimit);\n    \n    // Normalise for SIGMA arena expectations (arena size must be a multiple of 16mb)\n    normaliseBufferSize(nGenMemoryLimitBytes);\n    \n    std::thread([=]\n    {\n        try\n        {\n            PoWGenerateBlocks(true, numThreads, numArenaThreads, nGenMemoryLimitBytes/1024, Params(), forAccount, overrideAccountAddress);\n        }\n        catch(...)\n        {\n        }\n    }).detach();\n    \n    if (overrideAccountAddress.length() > 0)\n    {\n        LogPrintf(\"Block generation enabled into account [%s] using target address [%s], thread limit: [%d threads], memory: [%d Mb].\", pactiveWallet->mapAccountLabels[forAccount->getUUID()], overrideAccountAddress ,numThreads, nGenMemoryLimitBytes/1024/1024);\n    }\n    else\n    {\n        LogPrintf(\"Block generation enabled into account [%s], thread limit: [%d threads], memory: [%d Mb].\", pactiveWallet->mapAccountLabels[forAccount->getUUID()] ,numThreads, nGenMemoryLimitBytes/1024/1024);\n    }\n    return true;\n}\n\nbool IGenerationController::stopGeneration()\n{\n    std::thread([=]\n    {\n        PoWStopGeneration();\n    }).detach();\n    return true;\n}\n\nstd::string IGenerationController::getGenerationAddress()\n{\n    CAccount* forAccount = findMiningAccount(pactiveWallet);\n    if (forAccount)\n    {\n        CReserveKeyOrScript* receiveAddress = new CReserveKeyOrScript(pactiveWallet, forAccount, KEYCHAIN_EXTERNAL);\n        CPubKey pubKey;\n        if (receiveAddress->GetReservedKey(pubKey))\n        {\n            CKeyID keyID = pubKey.GetID();\n            return CNativeAddress(keyID).ToString();\n        }\n    }\n    return \"\";\n}\n\nstd::string IGenerationController::getGenerationOverrideAddress()\n{\n    std::string overrideAccountAddress;\n    if (CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(overrideAccountAddress))\n    {\n        return overrideAccountAddress;\n    }\n    else\n    {\n        return \"\";\n    }\n}\n\nbool IGenerationController::setGenerationOverrideAddress(const std::string& overrideAddress)\n{\n    if (!pactiveWallet)\n        return false;\n\n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    if (!findMiningAccount(pactiveWallet))\n        return false;\n    \n    if (!overrideAddress.empty())\n    {\n        CNativeAddress address(overrideAddress);\n        if (!address.IsValid())\n        {\n            return false;\n        }\n    }\n    return CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString(overrideAddress);\n}\n\nint64_t IGenerationController::getAvailableCores()\n{\n    return std::max((uint32_t)2, (uint32_t)std::thread::hardware_concurrency());\n}\n\nint64_t IGenerationController::getMinimumMemory()\n{\n    return 128;\n}\n\nint64_t IGenerationController::getMaximumMemory()\n{\n    uint64_t systemMemoryInMb = systemPhysicalMemoryInBytes()/1024/1024;\n    if (systemMemoryInMb < 2048)\n        return std::min(systemMemoryInMb, (uint64_t)256);\n    \n    systemMemoryInMb -= 2048;\n    uint64_t nMaxMemoryInMb = std::min(systemMemoryInMb, defaultSigmaSettings.arenaSizeKb/1024);\n    // 32 bit windows can only address 2gb of memory per process (3gb if /largeaddressaware)\n    // 32 bit linux is 4gb per process.\n    // Limit both accordingly\n    #ifdef ARCH_X86\n        #ifdef WIN32\n            nMaxMemoryInMb = std::min((uint64_t)nMaxMemoryInMb, (uint64_t)1*1024);\n        #else\n            nMaxMemoryInMb = std::min((uint64_t)nMaxMemoryInMb, (uint64_t)2*1024);\n        #endif\n    #endif\n    return nMaxMemoryInMb;\n}\n\n\n"
  },
  {
    "path": "src/unity/controllers/ip2pnetworkcontroller.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"validation/validation.h\"\n#include \"ui_interface.h\"\n\n\n// Unity specific includes\n#include \"../unity_impl.h\"\n#include \"i_p2p_network_controller.hpp\"\n#include \"i_p2p_network_listener.hpp\"\n#include \"peer_record.hpp\"\n#include \"banned_peer_record.hpp\"\n\nstd::shared_ptr<IP2pNetworkListener> networkListener;\nboost::signals2::connection enabledConn;\nboost::signals2::connection disabledConn;\n\nvoid IP2pNetworkController::setListener(const std::shared_ptr<IP2pNetworkListener>& networkListener_)\n{\n    networkListener = networkListener_;\n    if (networkListener)\n    {\n        enabledConn = uiInterface.NotifyNetworkActiveChanged.connect([](bool networkActive)\n        {\n            if (networkActive)\n            {\n                networkListener->onNetworkEnabled();\n            }\n            else\n            {\n                networkListener->onNetworkDisabled();\n            }\n        });\n        disabledConn = uiInterface.NotifyNumConnectionsChanged.connect([](int newNumConnections)\n        {\n            networkListener->onConnectionCountChanged(newNumConnections);\n        });\n    }\n    else\n    {\n        enabledConn.disconnect();\n        disabledConn.disconnect();\n    }\n    \n    std::thread([=]\n    {\n        while(networkListener && g_connman)\n        {\n            networkListener->onBytesChanged(g_connman->GetTotalBytesRecv(), g_connman->GetTotalBytesSent());\n            MilliSleep(30000);\n        }\n    }).detach();\n}\n\nvoid IP2pNetworkController::disableNetwork()\n{\n    if (g_connman)\n    {\n        g_connman->SetNetworkActive(false);\n    }\n}\n\nvoid IP2pNetworkController::enableNetwork()\n{\n    if (g_connman)\n    {\n        g_connman->SetNetworkActive(true);\n    }\n}\n\nstd::vector<PeerRecord> IP2pNetworkController::getPeerInfo()\n{\n    std::vector<PeerRecord> ret;\n\n    if (g_connman) {\n        std::vector<CNodeStats> vstats;\n        g_connman->GetNodeStats(vstats);\n        for (CNodeStats& nstat: vstats)\n        {\n            int64_t nSyncedHeight = 0;\n            int64_t nCommonHeight = 0;\n            int64_t nMisbehavior = 0;\n            CNodeStateStats stateStats;\n            TRY_LOCK(cs_main, lockMain);\n            if (lockMain && GetNodeStateStats(nstat.nodeid, stateStats))\n            {\n                nSyncedHeight = stateStats.nSyncHeight;\n                nCommonHeight = stateStats.nCommonHeight;\n                nMisbehavior = stateStats.nMisbehavior;\n            }\n\n            PeerRecord rec((int64_t)nstat.nodeid,\n                           nstat.addr.ToString(),\n                           nstat.addr.HostnameLookup(),\n                           nstat.addrLocal,\n                           nstat.addrBind.IsValid()?nstat.addrBind.ToString():\"\",\n                           (int64_t)nstat.nStartingHeight,\n                           (int64_t)nSyncedHeight,\n                           (int64_t)nCommonHeight,\n                           (int64_t)nstat.nTimeConnected,\n                           (int64_t)nstat.nTimeOffset,\n                           (int64_t)(nstat.dPingTime * 1000),\n                           (int64_t)nstat.nLastSend,\n                           (int64_t)nstat.nLastRecv,\n                           (int64_t)nstat.nSendBytes,\n                           (int64_t)nstat.nRecvBytes,\n                           nstat.cleanSubVer,\n                           (int64_t)nstat.nVersion,\n                           (int64_t)nstat.nServices,\n                           nstat.fInbound,\n                           nstat.fWhitelisted,\n                           nstat.fAddnode,\n                           nstat.fRelayTxes,\n                           (int64_t)nMisbehavior\n                           );\n            ret.emplace_back(rec);\n        }\n    }\n\n    return ret;\n}\n\nstd::vector<BannedPeerRecord> IP2pNetworkController::listBannedPeers()\n{\n    std::vector<BannedPeerRecord> ret;\n    \n    if (g_connman)\n    {   \n        banmap_t banMap;\n        g_connman->GetBanned(banMap);\n        for (const auto& [subNet, banEntry] : banMap)\n        {\n            BannedPeerRecord rec(subNet.ToString(), banEntry.nBanUntil, banEntry.nCreateTime, banEntry.banReasonToString());\n            ret.push_back(rec);\n        }\n    }\n    return ret;\n}\n\nbool IP2pNetworkController::banPeer(const std::string& address, int64_t banTimeInSeconds)\n{\n    if (g_connman)\n    {\n        std::string host;\n        int port;\n        SplitHostPort(address, port, host);\n        CNetAddr netAddr;\n        if (!LookupHost(host.c_str(), netAddr, false))\n            return false;\n        \n        g_connman->Ban(netAddr, BanReasonManuallyAdded, banTimeInSeconds, false);\n        return true;\n    }\n    return false;\n}\n\nbool IP2pNetworkController::unbanPeer(const std::string& address)\n{\n    if (g_connman)\n    {\n        CNetAddr netAddr;\n        CSubNet subnet;\n        if (LookupHost(address.c_str(), netAddr, false))\n        {\n            g_connman->Unban(netAddr);\n            return true;\n        }\n        else if(LookupSubNet(address.c_str(), subnet))\n        {\n            g_connman->Unban(subnet);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool IP2pNetworkController::disconnectPeer(int64_t nodeID)\n{\n    if (g_connman)\n    {        \n        g_connman->DisconnectNode(nodeID);\n        return true;\n    }\n    return false;\n}\n\nbool IP2pNetworkController::ClearBanned()\n{\n    if (g_connman)\n    {\n        g_connman->ClearBanned();\n        return true;\n    }\n    return false;\n}\n"
  },
  {
    "path": "src/unity/controllers/irpccontroller.cpp",
    "content": "// Copyright (c) 2020 The Novo developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the NOVO software license, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n// Unity specific includes\n#include \"../unity_impl.h\"\n#include \"i_rpc_controller.hpp\"\n#include \"i_rpc_listener.hpp\"\n#include \"controllers/rpccontroller.h\"\n\nvoid IRpcController::execute(const std::string& rpcCommandLine, const std::shared_ptr<IRpcListener>& resultListener)\n{\n    std::thread([=]\n    {\n        RPCController controller;\n        const std::function<void(const std::string&, const std::string&)>& errorHandler = [=](const std::string& filteredCommand, const std::string& errorMessage) {resultListener->onError(filteredCommand, errorMessage);};\n        const std::function<void(const std::string&)>& filteredCommandHandler = [=](const std::string& filteredCommand) {resultListener->onFilteredCommand(filteredCommand);};\n        const std::function<void(const std::string&, const std::string&)>& successHandler = [=](const std::string& filteredCommand, const std::string& result) {resultListener->onSuccess(filteredCommand, result);};\n        controller.executeCommandLine(rpcCommandLine, filteredCommandHandler, errorHandler, successHandler);\n    }).detach();\n}\n\nstd::vector<std::string> IRpcController::getAutocompleteList()\n{\n    RPCController controller;\n    return controller.getAutocompleteList();\n}\n"
  },
  {
    "path": "src/unity/controllers/iwalletcontroller.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n#include \"appname.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"validation/validation.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n\n\n#include <wallet/wallet.h>\n#include <wallet/account.h>\n#include <wallet/witness_operations.h>\n\n// Unity specific includes\n#include \"../unity_impl.h\"\n#include \"i_wallet_controller.hpp\"\n#include \"i_wallet_listener.hpp\"\n#include \"account_record.hpp\"\n#include \"balance_record.hpp\"\n#include \"mutation_record.hpp\"\n\nstd::shared_ptr<IWalletListener> walletListener;\n\n// rate limited mutations notifier\nstatic CRateLimit<std::pair<uint256, bool>>* walletNewMutationsNotifier=nullptr;\n// rate limited balance change notifier\nstatic CRateLimit<int>* walletBalanceChangeNotifier=nullptr;\n\nextern bool syncDoneFired;\n\n#ifdef ENABLE_WALLET\nvoid NotifyRequestUnlockS(CWallet* wallet, std::string reason)\n{\n    if (walletListener)\n    {\n        walletListener->notifyCoreWantsUnlock(reason);\n    }\n}\n\nvoid NotifyRequestUnlockWithCallbackS(CWallet* wallet, std::string reason, std::function<void (void)> successCallback)\n{\n    if (walletListener)\n    {\n        walletListener->notifyCoreWantsUnlock(reason);\n    }\n    //fixme: (UNITY) (HIGH)\n    //Need to be able to get a response here and deal with the callback, or else fix the code that relies on this\n    //successCallback();\n}\n#endif\n\nbool unityMessageBox(const std::string& message, const std::string& caption, unsigned int style)\n{\n    bool fSecure = style & CClientUIInterface::SECURE;\n    style &= ~CClientUIInterface::SECURE;\n    \n    std::string strType;\n    switch (style)\n    {\n        case CClientUIInterface::MSG_ERROR:\n            strType = \"MSG_ERROR\";\n            break;\n        case CClientUIInterface::MSG_WARNING:\n            strType = \"MSG_WARNING\";\n            break;\n        case CClientUIInterface::MSG_INFORMATION:\n            strType = \"MSG_INFORMATION\";\n            break;\n        default:\n            break;\n    }\n\n    if (!fSecure)\n        LogPrintf(\"unityMessageBox: %s %s %s\\n\", strType, caption, message);\n    \n    if (walletListener)\n    {\n        walletListener->notifyCoreInfo(strType, caption, message);\n    }\n    \n    return false;\n}\n\nvoid IWalletController::setListener(const std::shared_ptr<IWalletListener>& walletListener_)\n{\n    walletListener = walletListener_;\n\n    if (pactiveWallet && walletListener)\n    {\n        walletBalanceChangeNotifier = new CRateLimit<int>([](int)\n        {\n            if (pactiveWallet && walletListener)\n            {\n                WalletBalances balances;\n                pactiveWallet->GetBalances(balances, nullptr, true);\n                walletListener->notifyBalanceChange(BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked));\n            }\n        }, std::chrono::milliseconds(BALANCE_NOTIFY_THRESHOLD_MS));\n\n        walletNewMutationsNotifier = new CRateLimit<std::pair<uint256, bool>>([](const std::pair<uint256, bool>& txInfo)\n        {\n            if (pactiveWallet && walletListener && syncDoneFired)\n            {\n                const uint256& txHash = txInfo.first;\n                const bool fSelfComitted = txInfo.second;\n\n                LOCK2(cs_main, pactiveWallet->cs_wallet);\n                if (pactiveWallet->mapWallet.find(txHash) != pactiveWallet->mapWallet.end())\n                {\n                    const CWalletTx& wtx = pactiveWallet->mapWallet[txHash];\n                    std::vector<MutationRecord> mutations;\n                    addMutationsForTransaction(&wtx, mutations, nullptr);\n                    for (auto& m: mutations)\n                    {\n                        LogPrintf(\"unity: notify new wallet mutation for tx %s\", txHash.ToString().c_str());\n                        walletListener->notifyNewMutation(m, fSelfComitted);\n                    }\n                }\n            }\n        }, std::chrono::milliseconds(NEW_MUTATIONS_NOTIFY_THRESHOLD_MS));\n\n        // Fire events for lock status changes\n        pactiveWallet->NotifyLockingChanged.connect( [&](const bool isLocked)\n        {\n            if (isLocked)\n            {\n                walletListener->notifyWalletLocked();\n            }\n            else\n            {\n                walletListener->notifyWalletUnlocked();\n            }\n        } );\n\n        // Fire events for transaction depth changes (up to depth 10 only)\n        pactiveWallet->NotifyTransactionDepthChanged.connect( [&](CWallet* pwallet, const uint256& hash)\n        {\n            if (syncDoneFired)\n            {\n                DS_LOCK2(cs_main, pwallet->cs_wallet);\n                if (pwallet->mapWallet.find(hash) != pwallet->mapWallet.end())\n                {\n                    const CWalletTx& wtx = pwallet->mapWallet[hash];\n                    LogPrintf(\"unity: notify transaction depth changed %s\",hash.ToString().c_str());\n                    if (walletListener)\n                    {\n                        bool anyInputsOrOutputsAreMine = false;\n                        std::vector<CAccount*> forAccounts;\n                        for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n                        {\n                            forAccounts.push_back(account);\n                        }\n                        TransactionRecord walletTransaction = calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n                        if (anyInputsOrOutputsAreMine)\n                        {\n                            walletListener->notifyUpdatedTransaction(walletTransaction);\n                        }\n                    }\n                }\n            }\n        } );\n\n        // Fire events for transaction status changes, or new transactions (this won't fire for simple depth changes)\n        pactiveWallet->NotifyTransactionChanged.connect( [&](CWallet* pwallet, const uint256& hash, ChangeType status, bool fSelfComitted) {\n            if (syncDoneFired)\n            {\n                DS_LOCK2(cs_main, pwallet->cs_wallet);\n                if (pwallet->mapWallet.find(hash) != pwallet->mapWallet.end())\n                {\n                    if (status == CT_NEW) {\n                        walletNewMutationsNotifier->trigger(std::make_pair(hash, fSelfComitted));\n                    }\n                    else if (status == CT_UPDATED && walletListener)\n                    {\n                        LogPrintf(\"unity: notify tx updated %s\",hash.ToString().c_str());\n                        const CWalletTx& wtx = pwallet->mapWallet[hash];\n                        bool anyInputsOrOutputsAreMine = false;\n                        std::vector<CAccount*> forAccounts;\n                        for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n                        {\n                            forAccounts.push_back(account);\n                        }\n                        TransactionRecord walletTransaction = calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n                        if (anyInputsOrOutputsAreMine)\n                        {\n                            walletListener->notifyUpdatedTransaction(walletTransaction);\n                        }\n                    }\n                    //fixme: (UNITY) - Consider implementing f.e.x if a 0 conf transaction gets deleted...\n                    // else if (status == CT_DELETED)\n                }\n                walletBalanceChangeNotifier->trigger(0);\n            }\n        });\n    }\n}\n\nbool IWalletController::HaveUnconfirmedFunds()\n{\n    if (!pactiveWallet)\n        return true;\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, nullptr, true);\n\n    if (balances.unconfirmedIncludingLocked > 0 || balances.immatureIncludingLocked > 0)\n    {\n        return true;\n    }\n    return false;\n}\n\nBalanceRecord IWalletController::GetBalance()\n{\n    if (!pactiveWallet)\n        return BalanceRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, nullptr, true);\n    return BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked);\n    \n}\n\nint64_t IWalletController::GetBalanceSimple()\n{\n    if (!pactiveWallet)\n        return 0;\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, nullptr, true);\n    return balances.availableIncludingLocked + balances.unconfirmedIncludingLocked + balances.immatureIncludingLocked;\n}\n\nbool IWalletController::AbandonTransaction(const std::string& txHash)\n{\n    if (!pactiveWallet)\n        return false;\n\n    uint256 hash = uint256S(txHash);\n    return pactiveWallet->AbandonTransaction(hash);\n}\n\nstd::string IWalletController::GetUUID()\n{\n    if (!pactiveWallet || !pactiveWallet->getActiveAccount())\n        return \"\";\n    \n    return getUUIDAsString(pactiveWallet->getActiveAccount()->getUUID());\n}\n\n"
  },
  {
    "path": "src/unity/controllers/iwitnesscontroller.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n#include \"appname.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n\n\n#include \"witnessutil.h\"\n\n#include <wallet/wallet.h>\n#include <wallet/account.h>\n#include <wallet/witness_operations.h>\n\n// Unity specific includes\n#include \"../unity_impl.h\"\n#include \"i_witness_controller.hpp\"\n#include \"witness_estimate_info_record.hpp\"\n#include \"witness_funding_result_record.hpp\"\n#include \"result_record.hpp\"\n#include \"witness_account_statistics_record.hpp\"\n\n#include <consensus/validation.h>\n\n// stdlib includes\n#include <numeric>\n\n\nstd::unordered_map<std::string, std::string> IWitnessController::getNetworkLimits()\n{\n    std::unordered_map<std::string, std::string> ret;\n    if (pactiveWallet)\n    {\n        // Testnet does these calculations on \"mainnet time\" even though its block targer may be faster/slower (giving a sort of \"time warp\" illusion for testers)\n        if (Params().IsTestnet())\n        {\n            ret.insert(std::pair(\"expected_blocks_per_day\", i64tostr(gRefactorDailyBlocksUsage)));\n            ret.insert(std::pair(\"minimum_lock_period_blocks\", i64tostr(gMinimumWitnessLockDays*gRefactorDailyBlocksUsage)));\n            ret.insert(std::pair(\"maximum_lock_period_blocks\", i64tostr(gMaximumWitnessLockDays*gRefactorDailyBlocksUsage)));\n        }\n        else\n        {\n            ret.insert(std::pair(\"expected_blocks_per_day\", i64tostr(DailyBlocksTarget())));\n            ret.insert(std::pair(\"minimum_lock_period_blocks\", i64tostr(gMinimumWitnessLockDays*DailyBlocksTarget())));\n            ret.insert(std::pair(\"maximum_lock_period_blocks\", i64tostr(gMaximumWitnessLockDays*DailyBlocksTarget())));\n        }\n        ret.insert(std::pair(\"witness_cooldown_period\", i64tostr(gMinimumParticipationAge)));\n        ret.insert(std::pair(\"minimum_witness_amount\", i64tostr(gMinimumWitnessAmount)));\n        ret.insert(std::pair(\"minimum_witness_weight\", i64tostr(gMinimumWitnessWeight)));\n        ret.insert(std::pair(\"minimum_lock_period_days\", i64tostr(gMinimumWitnessLockDays)));        \n        ret.insert(std::pair(\"maximum_lock_period_days\", i64tostr(gMaximumWitnessLockDays)));\n    }\n    return ret;\n}\n\nstatic int64_t GetNetworkWeight()\n{\n    static int64_t nNetworkWeight = 9000000;\n    if (chainActive.Tip())\n    {\n        static uint64_t lastUpdate = 0;\n        // Only check this once a minute, no need to be constantly updating.\n        if (GetTimeMillis() - lastUpdate > 60000)\n        {\n            LOCK(cs_main);\n\n            lastUpdate = GetTimeMillis();\n            if (IsPow2WitnessingActive(chainActive.TipPrev()->nHeight))\n            {\n                CGetWitnessInfo witnessInfo;\n                CBlock block;\n                if (!ReadBlockFromDisk(block, chainActive.Tip(), Params()))\n                {\n                    return nNetworkWeight;\n                }\n                if (!GetWitnessInfo(chainActive, Params(), nullptr, chainActive.Tip()->pprev, block, witnessInfo, chainActive.Tip()->nHeight))\n                {\n                    return nNetworkWeight;\n                }\n                //fixme: Ideally this should use nTotalWeightEligibleRaw, but its not set from the above calls and would require additional computation\n                if (witnessInfo.nTotalWeightRaw != 0)\n                {\n                    nNetworkWeight = witnessInfo.nTotalWeightRaw;\n                }\n            }\n        }\n    }\n    return nNetworkWeight;\n}\n\nWitnessEstimateInfoRecord IWitnessController::getEstimatedWeight(int64_t amountToLock, int64_t lockPeriodInBlocks)\n{\n    if (!pactiveWallet)\n        return WitnessEstimateInfoRecord(0, 0, 0, 0, 0, 0, 0);\n    \n    if (!chainActive.Tip() || chainActive.Tip()->nHeight < 10)\n        return WitnessEstimateInfoRecord(0, 0, 0, 0, 0, 0, 0);\n    \n    int64_t lockPeriodInDays;\n    if (Params().IsTestnet())\n    {\n        lockPeriodInDays = lockPeriodInBlocks / gRefactorDailyBlocksUsage;\n    }\n    else\n    {\n        lockPeriodInDays = lockPeriodInBlocks / DailyBlocksTarget();\n    }\n    \n    uint64_t networkWeight = GetNetworkWeight();\n    const auto optimalAmounts = optimalWitnessDistribution(amountToLock, lockPeriodInBlocks, networkWeight);\n    int64_t ourTotalWeight = combinedWeight(optimalAmounts, chainActive.Height(), lockPeriodInBlocks);\n    \n    double witnessProbability = witnessFraction(optimalAmounts, chainActive.Height(), lockPeriodInBlocks, networkWeight);\n    double estimatedBlocksPerDay = DailyBlocksTarget() * witnessProbability;\n    \n    CAmount witnessSubsidy = GetBlockSubsidy(chainActive.Tip()?chainActive.Tip()->nHeight:1).witness;\n\n    CAmount estimatedDailyEarnings = estimatedBlocksPerDay * witnessSubsidy;\n    CAmount estimatedLifetimeEarnings = (DailyBlocksTarget() * lockPeriodInDays) * witnessProbability * witnessSubsidy;\n    \n    return WitnessEstimateInfoRecord(networkWeight, ourTotalWeight, optimalAmounts.size(), witnessProbability, estimatedBlocksPerDay, estimatedDailyEarnings, estimatedLifetimeEarnings);\n}\n\nWitnessFundingResultRecord IWitnessController::fundWitnessAccount(const std::string& fundingAccountUUID, const std::string& witnessAccountUUID, int64_t fundingAmount, int64_t requestedLockPeriodInBlocks)\n{\n    if (!pactiveWallet)\n        return WitnessFundingResultRecord(\"no active wallet present\", \"\", 0);;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(fundingAccountUUID));\n    if (findIter == pactiveWallet->mapAccounts.end())\n        return WitnessFundingResultRecord(\"invalid funding account\", \"\", 0);;\n    CAccount* fundingAccount = findIter->second;\n    \n    findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n    if (findIter == pactiveWallet->mapAccounts.end())\n        return WitnessFundingResultRecord(\"invalid witness account\", \"\", 0);;\n    CAccount* witnessAccount = findIter->second;\n    \n    if (!witnessAccount->IsPoW2Witness())\n        return WitnessFundingResultRecord(\"not a witness account\", \"\", 0);;\n        \n    try\n    {\n        std::string txid;\n        CAmount fee;\n        fundwitnessaccount(pactiveWallet, fundingAccount, witnessAccount, fundingAmount, requestedLockPeriodInBlocks, true, &txid, &fee);\n        return WitnessFundingResultRecord(\"success\", txid, fee);\n    }\n    catch (witness_error& e)\n    {\n        return WitnessFundingResultRecord(e.what(), \"\", 0);\n    }\n    catch (std::runtime_error& e)\n    {\n        return WitnessFundingResultRecord(e.what(), \"\", 0);\n    }\n}\n\nWitnessFundingResultRecord IWitnessController::renewWitnessAccount(const std::string& fundingAccountUUID, const std::string& witnessAccountUUID)\n{\n    if (!pactiveWallet)\n        return WitnessFundingResultRecord(\"no active wallet present\", \"\", 0);;\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(fundingAccountUUID));\n    if (findIter == pactiveWallet->mapAccounts.end())\n        return WitnessFundingResultRecord(\"invalid funding account\", \"\", 0);;\n    CAccount* fundingAccount = findIter->second;\n    \n    findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n    if (findIter == pactiveWallet->mapAccounts.end())\n        return WitnessFundingResultRecord(\"invalid witness account\", \"\", 0);;\n    CAccount* witnessAccount = findIter->second;\n    \n    if (!witnessAccount->IsPoW2Witness())\n        return WitnessFundingResultRecord(\"not a witness account\", \"\", 0);;\n        \n    try\n    {\n        std::string txid;\n        CAmount fee;\n        renewwitnessaccount(pactiveWallet, fundingAccount, witnessAccount, &txid, &fee);\n        return WitnessFundingResultRecord(\"success\", txid, fee);\n    }\n    catch (witness_error& e)\n    {\n        return WitnessFundingResultRecord(e.what(), \"\", 0);\n    }\n    catch (std::runtime_error& e)\n    {\n        return WitnessFundingResultRecord(e.what(), \"\", 0);\n    }\n}\n\n\nstruct WitnessInfoForAccount\n{\n    CWitnessAccountStatus accountStatus;\n\n    uint64_t nOurWeight = 0;\n    uint64_t nTotalNetworkWeightTip = 0;\n    uint64_t nWitnessLength = 0;\n    uint64_t nExpectedWitnessBlockPeriod = 0;\n    uint64_t nEstimatedWitnessBlockPeriod = 0;\n    uint64_t nLockBlocksRemaining = 0;\n    int64_t  nOriginNetworkWeight = 0;\n    uint64_t nOriginBlock = 0;\n    uint64_t nOriginLength = 0;\n    uint64_t nEarningsToDate = 0;\n};\n\nbool GetWitnessInfoForAccount(CAccount* forAccount, WitnessInfoForAccount& infoForAccount, CGetWitnessInfo& witnessInfo)\n{\n    if (!forAccount->IsPoW2Witness())\n        return false;\n        \n    CWitnessAccountStatus accountStatus;\n    accountStatus = GetWitnessAccountStatus(pactiveWallet, forAccount, &witnessInfo);\n\n    infoForAccount.accountStatus = accountStatus;\n\n    infoForAccount.nTotalNetworkWeightTip = accountStatus.networkWeight;\n    infoForAccount.nOurWeight = accountStatus.currentWeight;\n\n    infoForAccount.nOriginLength = accountStatus.nLockPeriodInBlocks;\n    infoForAccount.nOriginBlock = accountStatus.nLockFromBlock;\n    \n    #if 0 //unused and potentially quite slow\n    LOCK(cs_main);\n    CBlockIndex* originIndex = chainActive[infoForAccount.nOriginBlock];\n\n    // We take the network weight 100 blocks ahead to give a chance for our own weight to filter into things (and also if e.g. the first time witnessing activated - testnet - then weight will only climb once other people also join)\n    CBlockIndex* sampleWeightIndex = chainActive[infoForAccount.nOriginBlock+100 > (uint64_t)chainActive.Tip()->nHeight ? infoForAccount.nOriginBlock : infoForAccount.nOriginBlock+100];\n    int64_t nUnused1;\n    if (!GetPow2NetworkWeight(sampleWeightIndex, Params(), nUnused1, infoForAccount.nOriginNetworkWeight, chainActive))\n    {\n        std::string strErrorMessage = \"Error in witness dialog, failed to get weight for account\";\n        return false;\n    }\n    \n    if (infoForAccount.nOriginNetworkWeight == 0)\n        infoForAccount.nOriginNetworkWeight = gStartingWitnessNetworkWeightEstimate;\n    #endif\n\n    infoForAccount.nWitnessLength = infoForAccount.nOriginLength;\n\n    const auto& parts = infoForAccount.accountStatus.parts;\n    if (!parts.empty())\n    {\n        uint64_t networkWeight = infoForAccount.nTotalNetworkWeightTip;\n        // Worst case all parts witness at latest opportunity so part with maximum weight will be the first to be required to witness\n        infoForAccount.nExpectedWitnessBlockPeriod = expectedWitnessBlockPeriod(std::get<0>(*std::max_element(parts.begin(), parts.end(), [](std::tuple<uint64_t, uint64_t> l, std::tuple<uint64_t, uint64_t> r) {return std::get<0>(l) > std::get<0>(r);})), networkWeight);\n            // Combine estimated witness frequency f for part frequencies f1..fN: 1/f = 1/f1 + .. 1/fN\n            double fInv = std::accumulate(parts.begin(), parts.end(), 0.0, [=](const double acc, const std::tuple<uint64_t, uint64_t> w){\n            uint64_t fn = estimatedWitnessBlockPeriod(std::get<0>(w), networkWeight);\n            return acc + 1.0/fn;\n        });\n        infoForAccount.nEstimatedWitnessBlockPeriod = uint64_t(1.0/fInv);\n    }\n    else\n    {\n        infoForAccount.nExpectedWitnessBlockPeriod = 0;\n        infoForAccount.nEstimatedWitnessBlockPeriod = 0;\n    }\n\n    infoForAccount.nLockBlocksRemaining = GetPoW2RemainingLockLengthInBlocks(accountStatus.nLockUntilBlock, chainActive.Tip()->nHeight);\n\n    return true;\n}\n\nWitnessAccountStatisticsRecord IWitnessController::getAccountWitnessStatistics(const std::string& witnessAccountUUID)\n{\n    if (!pactiveWallet)\n        return WitnessAccountStatisticsRecord(\"no active wallet present\", \"\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false);\n    \n    DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n    auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n    if (findIter == pactiveWallet->mapAccounts.end())\n        return WitnessAccountStatisticsRecord(\"invalid witness account\", \"\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false);\n    CAccount* witnessAccount = findIter->second;\n    \n    CGetWitnessInfo witnessInfo;\n    WitnessInfoForAccount infoForAccount;\n    if (!GetWitnessInfoForAccount(witnessAccount, infoForAccount, witnessInfo))\n    {\n        return WitnessAccountStatisticsRecord(\"failed to get witness info for account\", \"\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false);\n    }\n    std::string accountStatus;\n    switch (infoForAccount.accountStatus.status)\n    {\n        case WitnessStatus::Empty: accountStatus = \"empty\"; break;\n        case WitnessStatus::EmptyWithRemainder: accountStatus = \"empty_with_remainder\"; break;\n        case WitnessStatus::Pending: accountStatus = \"pending\"; break;\n        case WitnessStatus::Witnessing: accountStatus = \"active\"; break;\n        case WitnessStatus::Ended: accountStatus = \"ended\"; break;\n        case WitnessStatus::Expired: accountStatus = \"expired\"; break;\n        case WitnessStatus::Emptying: accountStatus = \"emptying\"; break;\n    }\n    int64_t compoundingPercent = 0;\n    if (witnessAccount->getCompounding() != 0)\n    {\n        compoundingPercent = 100;\n    }\n    else\n    {\n        compoundingPercent = witnessAccount->getCompoundingPercent();\n    }\n\n    bool accountNearOptimal = isWitnessDistributionNearOptimal(pactiveWallet, witnessAccount, witnessInfo);\n    \n    uint64_t nBlocksSinceLastActivity = 0;\n    if (infoForAccount.accountStatus.parts.size() > 0)\n    {\n        nBlocksSinceLastActivity = std::get<1>(*std::min_element(infoForAccount.accountStatus.parts.begin(), infoForAccount.accountStatus.parts.end(), [](std::tuple<uint64_t, uint64_t> l, std::tuple<uint64_t, uint64_t> r) {return std::get<1>(l) < std::get<1>(r);}));\n    }\n    \n    return WitnessAccountStatisticsRecord(\n        \"success\",                                                      //request_status\n        accountStatus,                                                  //account_status\n        nBlocksSinceLastActivity,                                       //account_blocks_since_last_activity\n        infoForAccount.nOurWeight,                                      //account_weight\n        infoForAccount.accountStatus.originWeight,                      //account_weight_at_creation\n        infoForAccount.accountStatus.parts.size(),                      //account_parts\n        infoForAccount.accountStatus.currentAmountLocked,               //account_amount_locked\n        infoForAccount.accountStatus.originAmountLocked,                //account_amount_locked_at_creation\n        infoForAccount.nTotalNetworkWeightTip,                          //network_tip_total_weight\n        infoForAccount.accountStatus.networkWeight,                     //network_total_weight_at_creation\n        infoForAccount.nOriginLength,                                   //account_initial_lock_period_in_blocks\n        infoForAccount.nLockBlocksRemaining,                            //account_remaining_lock_period_in_blocks\n        infoForAccount.nExpectedWitnessBlockPeriod,                     //account_expected_witness_period_in_blocks\n        infoForAccount.nEstimatedWitnessBlockPeriod,                    //account_estimated_witness_period_in_blocks\n        infoForAccount.nOriginBlock,                                    //account_initial_lock_creation_block_height\n        compoundingPercent,                                             //compounding_percent\n        accountNearOptimal                                              //is_optimal\n    );\n}\n\n\nvoid IWitnessController::setAccountCompounding(const std::string& witnessAccountUUID, int32_t percentToCompound)\n{\n    if (pactiveWallet)\n    {\n        DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* witnessAccount = findIter->second;\n            \n            CWalletDB db(*pactiveWallet->dbw);\n            if (percentToCompound > 0)\n            {\n                // erase any regular compounding setting\n                witnessAccount->setCompounding(0, &db);\n            }\n            witnessAccount->setCompoundingPercent(percentToCompound, &db);\n        }\n    }\n}\n\nint32_t IWitnessController::isAccountCompounding(const std::string& witnessAccountUUID)\n{\n    if (pactiveWallet)\n    {\n        DS_LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* witnessAccount = findIter->second;\n            if (witnessAccount->getCompounding() != 0)\n            {\n                return 100;\n            }\n            else\n            {\n                return witnessAccount->getCompoundingPercent();\n            }\n        }\n    }\n    return 0;\n}\n\nstd::string IWitnessController::getWitnessAddress(const std::string& witnessAccountUUID)\n{\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* witnessAccount = findIter->second;\n            \n            return witnessAddressForAccount(pactiveWallet, witnessAccount);\n        }\n    }\n    return \"\";\n}\n\n\nstd::vector<int64_t> IWitnessController::getOptimalWitnessDistribution(const int64_t amount, const int64_t durationInBlocks, const int64_t totalNetworkWeight)\n{\n    return optimalWitnessDistribution(amount, durationInBlocks, totalNetworkWeight);\n}\n\nstd::vector<int64_t> IWitnessController::getOptimalWitnessDistributionForAccount(const std::string& witnessAccountUUID)\n{\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            CAccount* witnessAccount = findIter->second;\n            \n            CGetWitnessInfo witnessInfo = GetWitnessInfoWrapper();\n            auto [currentDistribution, duration, totalAmount] = witnessDistribution(pactiveWallet, witnessAccount);\n            return getOptimalWitnessDistribution(totalAmount, duration, witnessInfo.nTotalWeightEligibleRaw);\n        }\n    }\n    return std::vector<int64_t>();\n}\n\nResultRecord IWitnessController::optimiseWitnessAccount(const std::string& witnessAccountUUID, const std::string& fundingAccountUUID, const std::vector<int64_t>& optimalDistribution)\n{\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n    \n        auto findIter = pactiveWallet->mapAccounts.find(getUUIDFromString(witnessAccountUUID));\n        if (findIter != pactiveWallet->mapAccounts.end())\n        {\n            auto findFundingIter = pactiveWallet->mapAccounts.find(getUUIDFromString(fundingAccountUUID));\n            if (findFundingIter != pactiveWallet->mapAccounts.end())\n            {\n                CAccount* witnessAccount = findIter->second;\n                CAccount* fundingAccount = findFundingIter->second;\n                \n                try\n                {\n                    redistributewitnessaccount(pactiveWallet, fundingAccount, witnessAccount, optimalDistribution, nullptr, nullptr); // ignore result params      \n                }\n                catch(const std::string& e)\n                {\n                    return ResultRecord(false, e);\n                }\n                catch(...)\n                {\n                    return ResultRecord(false, \"unknown error\");\n                }\n                return ResultRecord(true, \"\");\n            }\n        }\n    }\n    return ResultRecord(false, \"no wallet available\");\n}\n"
  },
  {
    "path": "src/unity/djinni/cpp/account_link_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n#include <utility>\n\n/**Data record representing a link between an account and an external service (e.g. Holdin.com) */\nstruct AccountLinkRecord final {\n    /** What service is it (each service should use a unique string to identify itself)  */\n    std::string serviceName;\n    /** Any data unique to the service, e.g. a key used for secure communication or similar */\n    std::string serviceData;\n\n    AccountLinkRecord(std::string serviceName_,\n                      std::string serviceData_)\n    : serviceName(std::move(serviceName_))\n    , serviceData(std::move(serviceData_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/account_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"account_link_record.hpp\"\n#include <string>\n#include <utility>\n#include <vector>\n\nstruct AccountRecord final {\n    std::string UUID;\n    std::string label;\n    std::string state;\n    std::string type;\n    /**Is this account 'HD' (i.e. part of what can be recovered from a recovery phrase) */\n    bool isHD;\n    /**Has this account been linked to any other services/wallets; if so which see 'account_link_record' for more information */\n    std::vector<AccountLinkRecord> accountLinks;\n\n    AccountRecord(std::string UUID_,\n                  std::string label_,\n                  std::string state_,\n                  std::string type_,\n                  bool isHD_,\n                  std::vector<AccountLinkRecord> accountLinks_)\n    : UUID(std::move(UUID_))\n    , label(std::move(label_))\n    , state(std::move(state_))\n    , type(std::move(type_))\n    , isHD(std::move(isHD_))\n    , accountLinks(std::move(accountLinks_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/address_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n#include <utility>\n\nstruct AddressRecord final {\n    std::string address;\n    std::string name;\n    std::string desc;\n    std::string purpose;\n\n    AddressRecord(std::string address_,\n                  std::string name_,\n                  std::string desc_,\n                  std::string purpose_)\n    : address(std::move(address_))\n    , name(std::move(name_))\n    , desc(std::move(desc_))\n    , purpose(std::move(purpose_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/balance_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <utility>\n\nstruct BalanceRecord final {\n    int64_t availableIncludingLocked;\n    int64_t availableExcludingLocked;\n    int64_t availableLocked;\n    int64_t unconfirmedIncludingLocked;\n    int64_t unconfirmedExcludingLocked;\n    int64_t unconfirmedLocked;\n    int64_t immatureIncludingLocked;\n    int64_t immatureExcludingLocked;\n    int64_t immatureLocked;\n    int64_t totalLocked;\n\n    BalanceRecord(int64_t availableIncludingLocked_,\n                  int64_t availableExcludingLocked_,\n                  int64_t availableLocked_,\n                  int64_t unconfirmedIncludingLocked_,\n                  int64_t unconfirmedExcludingLocked_,\n                  int64_t unconfirmedLocked_,\n                  int64_t immatureIncludingLocked_,\n                  int64_t immatureExcludingLocked_,\n                  int64_t immatureLocked_,\n                  int64_t totalLocked_)\n    : availableIncludingLocked(std::move(availableIncludingLocked_))\n    , availableExcludingLocked(std::move(availableExcludingLocked_))\n    , availableLocked(std::move(availableLocked_))\n    , unconfirmedIncludingLocked(std::move(unconfirmedIncludingLocked_))\n    , unconfirmedExcludingLocked(std::move(unconfirmedExcludingLocked_))\n    , unconfirmedLocked(std::move(unconfirmedLocked_))\n    , immatureIncludingLocked(std::move(immatureIncludingLocked_))\n    , immatureExcludingLocked(std::move(immatureExcludingLocked_))\n    , immatureLocked(std::move(immatureLocked_))\n    , totalLocked(std::move(totalLocked_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/banned_peer_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct BannedPeerRecord final {\n    std::string address;\n    int64_t banned_until;\n    int64_t banned_from;\n    std::string reason;\n\n    BannedPeerRecord(std::string address_,\n                     int64_t banned_until_,\n                     int64_t banned_from_,\n                     std::string reason_)\n    : address(std::move(address_))\n    , banned_until(std::move(banned_until_))\n    , banned_from(std::move(banned_from_))\n    , reason(std::move(reason_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/block_info_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct BlockInfoRecord final {\n    int32_t height;\n    int64_t timeStamp;\n    std::string blockHash;\n\n    BlockInfoRecord(int32_t height_,\n                    int64_t timeStamp_,\n                    std::string blockHash_)\n    : height(std::move(height_))\n    , timeStamp(std::move(timeStamp_))\n    , blockHash(std::move(blockHash_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_accounts_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSIAccountsListener.hpp\"\n#else\nclass IAccountsListener;\n#endif\nstruct AccountLinkRecord;\nstruct AccountRecord;\nstruct BalanceRecord;\nstruct MutationRecord;\nstruct TransactionRecord;\n\n/** C++ interface to control accounts */\nclass IAccountsController {\npublic:\n    virtual ~IAccountsController() {}\n\n    /** Register listener to be notified of account related events */\n    static void setListener(const std::shared_ptr<IAccountsListener> & accountslistener);\n\n    /** List all currently visible accounts in the wallet */\n    static std::vector<AccountRecord> listAccounts();\n\n    /** Set the currently active account */\n    static bool setActiveAccount(const std::string & accountUUID);\n\n    /** Get the currently active account */\n    static std::string getActiveAccount();\n\n    /** Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account */\n    static std::string createAccount(const std::string & accountName, const std::string & accountType);\n\n    /** Check name of account */\n    static std::string getAccountName(const std::string & accountUUID);\n\n    /** Rename an account */\n    static bool renameAccount(const std::string & accountUUID, const std::string & newAccountName);\n\n    /** Delete an account, account remains available in background but is hidden from user */\n    static bool deleteAccount(const std::string & accountUUID);\n\n    /**\n     * Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n     * If it is a Legacy or imported witness key or similar account then it will be gone forever\n     * Generally prefer 'deleteAccount' and use this with caution\n     */\n    static bool purgeAccount(const std::string & accountUUID);\n\n    /** Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure.  */\n    static std::string getAccountLinkURI(const std::string & accountUUID);\n\n    /** Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account */\n    static std::string getWitnessKeyURI(const std::string & accountUUID);\n\n    /**\n     * Create a new \"witness-only\" account from a previously exported URI\n     * Returns UUID on success, empty string on failiure\n     */\n    static std::string createAccountFromWitnessKeyURI(const std::string & witnessKeyURI, const std::string & newAccountName);\n\n    /** Get a receive address for account */\n    static std::string getReceiveAddress(const std::string & accountUUID);\n\n    /** Get list of all transactions account has been involved in */\n    static std::vector<TransactionRecord> getTransactionHistory(const std::string & accountUUID);\n\n    /** Get list of mutations for account */\n    static std::vector<MutationRecord> getMutationHistory(const std::string & accountUUID);\n\n    /** Check balance for active account */\n    static BalanceRecord getActiveAccountBalance();\n\n    /** Check balance for account */\n    static BalanceRecord getAccountBalance(const std::string & accountUUID);\n\n    /** Check balance for all accounts, returns a map of account_uuid->balance_record */\n    static std::unordered_map<std::string, BalanceRecord> getAllAccountBalances();\n\n    /**Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key) */\n    static bool addAccountLink(const std::string & accountUUID, const std::string & serviceName, const std::string & data);\n\n    /**Register with wallet to remove an existing link */\n    static bool removeAccountLink(const std::string & accountUUID, const std::string & serviceName);\n\n    /**List all active account links that we have previously registered */\n    static std::vector<AccountLinkRecord> listAccountLinks(const std::string & accountUUID);\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_accounts_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n\nstruct AccountRecord;\n\n/** Interface to receive updates about accounts */\n#ifdef DJINNI_NODEJS\n#include \"NJSIAccountsListener.hpp\" \n#define IAccountsListener NJSIAccountsListener\n#else\n\nclass IAccountsListener {\npublic:\n    virtual ~IAccountsListener() {}\n\n    /** Notify that the active account has changed */\n    virtual void onActiveAccountChanged(const std::string & accountUUID) = 0;\n\n    /** Notify that the active account name has changed */\n    virtual void onActiveAccountNameChanged(const std::string & newAccountName) = 0;\n\n    /** Notify that an account name has changed */\n    virtual void onAccountNameChanged(const std::string & accountUUID, const std::string & newAccountName) = 0;\n\n    /** Notify that a new account has been added */\n    virtual void onAccountAdded(const std::string & accountUUID, const std::string & accountName) = 0;\n\n    /** Notify that an account has been deleted */\n    virtual void onAccountDeleted(const std::string & accountUUID) = 0;\n\n    /** Notify that an account has been modified */\n    virtual void onAccountModified(const std::string & accountUUID, const AccountRecord & accountData) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_generation_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <string>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSIGenerationListener.hpp\"\n#else\nclass IGenerationListener;\n#endif\n\n/** C++ interface to control generation of blocks (proof of work) */\nclass IGenerationController {\npublic:\n    virtual ~IGenerationController() {}\n\n    /** Register listener to be notified of generation related events */\n    static void setListener(const std::shared_ptr<IGenerationListener> & generationListener);\n\n    /**\n     * Activate block generation (proof of work)\n     * Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n     */\n    static bool startGeneration(int32_t numThreads, int32_t numArenaThreads, const std::string & memoryLimit);\n\n    /** Stop any active block generation (proof of work) */\n    static bool stopGeneration();\n\n    /**\n     * Get the address of the account that is used for generation by default. Empty on failiure\n     * Note that this isn't necessarily the actual generation address as there might be an override\n     * See: getGenerationOverrideAddress\n     */\n    static std::string getGenerationAddress();\n\n    /**\n     * Get the 'override' address for generation, if one has been set\n     * The override address, when present it used for all block generation in place of the default account address\n     */\n    static std::string getGenerationOverrideAddress();\n\n    /** Set an override address to use for block generation in place of the default */\n    static bool setGenerationOverrideAddress(const std::string & overrideAddress);\n\n    static int64_t getAvailableCores();\n\n    static int64_t getMinimumMemory();\n\n    static int64_t getMaximumMemory();\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_generation_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n\n/** Interface to receive updates about block generation */\n#ifdef DJINNI_NODEJS\n#include \"NJSIGenerationListener.hpp\" \n#define IGenerationListener NJSIGenerationListener\n#else\n\nclass IGenerationListener {\npublic:\n    virtual ~IGenerationListener() {}\n\n    /** Signal that block generation has started */\n    virtual void onGenerationStarted() = 0;\n\n    /** Signal that block generation has stopped */\n    virtual void onGenerationStopped() = 0;\n\n    /** Periodically signal latest block generation statistics */\n    virtual void onStatsUpdated(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_library_controller.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_library_controller.hpp\"  // my header\n#include \"address_record.hpp\"\n#include \"block_info_record.hpp\"\n#include \"legacy_wallet_result.hpp\"\n#include \"mnemonic_record.hpp\"\n#include \"monitor_record.hpp\"\n#include \"mutation_record.hpp\"\n#include \"payment_result_status.hpp\"\n#include \"qr_code_record.hpp\"\n#include \"transaction_record.hpp\"\n#include \"uri_recipient.hpp\"\n#include \"uri_record.hpp\"\n#include \"wallet_lock_status.hpp\"\n\nint32_t constexpr ILibraryController::VERSION;\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_library_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSILibraryListener.hpp\"\n#else\nclass ILibraryListener;\n#endif\n#ifdef DJINNI_NODEJS\n#include \"NJSMonitorListener.hpp\"\n#else\nclass MonitorListener;\n#endif\nenum class LegacyWalletResult;\nenum class PaymentResultStatus;\nstruct AddressRecord;\nstruct BlockInfoRecord;\nstruct MnemonicRecord;\nstruct MonitorRecord;\nstruct MutationRecord;\nstruct QrCodeRecord;\nstruct TransactionRecord;\nstruct UriRecipient;\nstruct UriRecord;\nstruct WalletLockStatus;\n\n/**\n * The library controller is used to Init/Terminate the library, and other similar tasks.\n * It is also home to various generic utility functions that don't (yet) have a place in more specific controllers\n * Specific functionality should go in specific controllers; account related functionality -> accounts_controller, network related functionality -> network_controller and so on\n */\nclass ILibraryController {\npublic:\n    virtual ~ILibraryController() {}\n\n    /** Interface constants */\n    static constexpr int32_t VERSION = 1;\n\n    /** Get the build information (ie. commit id and status) */\n    static std::string BuildInfo();\n\n    /**\n     * Start the library\n     * extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n     * NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n     * If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n     */\n    static int32_t InitUnityLib(const std::string & data_dir, const std::string & staticFilterPath, int64_t staticFilterOffset, int64_t staticFilterLength, bool testnet, bool spvMode, const std::shared_ptr<ILibraryListener> & signalHandler, const std::string & extraArgs);\n\n    /** Threaded implementation of InitUnityLib */\n    static void InitUnityLibThreaded(const std::string & data_dir, const std::string & staticFilterPath, int64_t staticFilterOffset, int64_t staticFilterLength, bool testnet, bool spvMode, const std::shared_ptr<ILibraryListener> & signalHandler, const std::string & extraArgs);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static bool InitWalletFromRecoveryPhrase(const std::string & phrase, const std::string & password);\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    static bool ContinueWalletFromRecoveryPhrase(const std::string & phrase, const std::string & password);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static bool InitWalletLinkedFromURI(const std::string & linked_uri, const std::string & password);\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    static bool ContinueWalletLinkedFromURI(const std::string & linked_uri, const std::string & password);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static bool InitWalletFromAndroidLegacyProtoWallet(const std::string & wallet_file, const std::string & old_password, const std::string & new_password);\n\n    /** Check if a file is a valid legacy proto wallet */\n    static LegacyWalletResult isValidAndroidLegacyProtoWallet(const std::string & wallet_file, const std::string & old_password);\n\n    /** Check link URI for validity */\n    static bool IsValidLinkURI(const std::string & phrase);\n\n    /** Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet. */\n    static bool ReplaceWalletLinkedFromURI(const std::string & linked_uri, const std::string & password);\n\n    /**\n     * Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n     * After calling this it will be necessary to create a new linked account or recovery phrase account again.\n     * NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n     */\n    static bool EraseWalletSeedsAndAccounts();\n\n    /**\n     * Check recovery phrase for (syntactic) validity\n     * Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n     */\n    static bool IsValidRecoveryPhrase(const std::string & phrase);\n\n    /** Generate a new recovery mnemonic */\n    static MnemonicRecord GenerateRecoveryMnemonic();\n\n    static std::string GenerateGenesisKeys();\n\n    /** Compute recovery phrase with birth number */\n    static MnemonicRecord ComposeRecoveryPhrase(const std::string & mnemonic, int64_t birthTime);\n\n    /** Stop the library */\n    static void TerminateUnityLib();\n\n    /** Generate a QR code for a string, QR code will be as close to width_hint as possible when applying simple scaling. */\n    static QrCodeRecord QRImageFromString(const std::string & qr_string, int32_t width_hint);\n\n    /** Get a receive address for the active account */\n    static std::string GetReceiveAddress();\n\n    /** Get the recovery phrase for the wallet */\n    static MnemonicRecord GetRecoveryPhrase();\n\n    /** Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet) */\n    static bool IsMnemonicWallet();\n\n    /** Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time) */\n    static bool IsMnemonicCorrect(const std::string & phrase);\n\n    /**\n     * Get the 'dictionary' of valid words that a recovery phrase can be composed of\n     * NB! Not all combinations of these words are valid\n     * Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n     * This function should only be used for input validation/auto-completion\n     */\n    static std::vector<std::string> GetMnemonicDictionary();\n\n    /** Unlock wallet; wallet will automatically relock after \"timeout_in_seconds\" */\n    static bool UnlockWallet(const std::string & password, int64_t timeout_in_seconds);\n\n    /** Forcefully lock wallet again */\n    static bool LockWallet();\n\n    static WalletLockStatus GetWalletLockStatus();\n\n    /** Change the wallet password */\n    static bool ChangePassword(const std::string & oldPassword, const std::string & newPassword);\n\n    /** Rescan blockchain for wallet transactions */\n    static void DoRescan();\n\n    /** Check if text/address is something we are capable of sending money too */\n    static UriRecipient IsValidRecipient(const UriRecord & request);\n\n    /** Check if text/address is a native (to our blockchain) address */\n    static bool IsValidNativeAddress(const std::string & address);\n\n    /** Check if text/address is a valid bitcoin address */\n    static bool IsValidBitcoinAddress(const std::string & address);\n\n    /** Compute the fee required to send amount to given recipient */\n    static int64_t feeForRecipient(const UriRecipient & request);\n\n    /** Attempt to pay a recipient, will throw on failure with description */\n    static PaymentResultStatus performPaymentToRecipient(const UriRecipient & request, bool substract_fee);\n\n    /**\n     * Get the wallet transaction for the hash\n     * Will throw if not found\n     */\n    static TransactionRecord getTransaction(const std::string & txHash);\n\n    /** resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail */\n    static std::string resendTransaction(const std::string & txHash);\n\n    /** Get list of all address book entries */\n    static std::vector<AddressRecord> getAddressBookRecords();\n\n    /** Add a record to the address book */\n    static void addAddressBookRecord(const AddressRecord & address);\n\n    /** Delete a record from the address book */\n    static void deleteAddressBookRecord(const AddressRecord & address);\n\n    /** Interim persist and prune of state. Use at key moments like app backgrounding. */\n    static void PersistAndPruneForSPV();\n\n    /**\n     * Reset progress notification. In cases where there has been no progress for a long time, but the process\n     * is still running the progress can be reset and will represent work to be done from this reset onwards.\n     * For example when the process is in the background on iOS for a long long time (but has not been terminated\n     * by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n     */\n    static void ResetUnifiedProgress();\n\n    /** Get info of last blocks (at most 32) in SPV chain */\n    static std::vector<BlockInfoRecord> getLastSPVBlockInfos();\n\n    static float getUnifiedProgress();\n\n    static MonitorRecord getMonitoringStats();\n\n    static void RegisterMonitorListener(const std::shared_ptr<MonitorListener> & listener);\n\n    static void UnregisterMonitorListener(const std::shared_ptr<MonitorListener> & listener);\n\n    static std::unordered_map<std::string, std::string> getClientInfo();\n\n    /**\n     * Get list of wallet mutations\n     *NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n     */\n    static std::vector<MutationRecord> getMutationHistory();\n\n    /**\n     * Get list of all transactions wallet has been involved in\n     *NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n     */\n    static std::vector<TransactionRecord> getTransactionHistory();\n\n    /**\n     * Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n     *NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n     */\n    static bool HaveUnconfirmedFunds();\n\n    /**\n     * Check current wallet balance (including unconfirmed funds)\n     *NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n     */\n    static int64_t GetBalance();\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_library_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n\nstruct BalanceRecord;\nstruct MutationRecord;\nstruct TransactionRecord;\n\n/** Interface to receive events from the core */\n#ifdef DJINNI_NODEJS\n#include \"NJSILibraryListener.hpp\" \n#define ILibraryListener NJSILibraryListener\n#else\n\nclass ILibraryListener {\npublic:\n    virtual ~ILibraryListener() {}\n\n    /**\n     * Fraction of work done since session start or last progress reset [0..1]\n     * Unified progress combines connection state, header and block sync\n     */\n    virtual void notifyUnifiedProgress(float progress) = 0;\n\n    /** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n    virtual void notifySyncDone() = 0;\n\n    virtual void notifyBalanceChange(const BalanceRecord & new_balance) = 0;\n\n    /**\n     * Notification of new mutations\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    virtual void notifyNewMutation(const MutationRecord & mutation, bool self_committed) = 0;\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    virtual void notifyUpdatedTransaction(const TransactionRecord & transaction) = 0;\n\n    virtual void notifyInitWithExistingWallet() = 0;\n\n    virtual void notifyInitWithoutExistingWallet() = 0;\n\n    virtual void notifyShutdown() = 0;\n\n    virtual void notifyCoreReady() = 0;\n\n    virtual void notifyError(const std::string & error) = 0;\n\n    virtual void logPrint(const std::string & str) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_p2p_network_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSIP2pNetworkListener.hpp\"\n#else\nclass IP2pNetworkListener;\n#endif\nstruct BannedPeerRecord;\nstruct PeerRecord;\n\n/** C++ interface to control networking related aspects of the software */\nclass IP2pNetworkController {\npublic:\n    virtual ~IP2pNetworkController() {}\n\n    /** Register listener to be notified of networking events */\n    static void setListener(const std::shared_ptr<IP2pNetworkListener> & networklistener);\n\n    /** Turn p2p networking off */\n    static void disableNetwork();\n\n    /** Turn p2p networking on */\n    static void enableNetwork();\n\n    /** Get connected peer info */\n    static std::vector<PeerRecord> getPeerInfo();\n\n    /** Get all banned peers */\n    static std::vector<BannedPeerRecord> listBannedPeers();\n\n    static bool banPeer(const std::string & address, int64_t banTimeInSeconds);\n\n    /** Unban a single peer */\n    static bool unbanPeer(const std::string & address);\n\n    /** Disconnect a specific peer */\n    static bool disconnectPeer(int64_t nodeid);\n\n    /** Clear all banned peers */\n    static bool ClearBanned();\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_p2p_network_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n\n/** Interface to receive updates about network status */\n#ifdef DJINNI_NODEJS\n#include \"NJSIP2pNetworkListener.hpp\" \n#define IP2pNetworkListener NJSIP2pNetworkListener\n#else\n\nclass IP2pNetworkListener {\npublic:\n    virtual ~IP2pNetworkListener() {}\n\n    /** Notify that p2p networking has been enabled */\n    virtual void onNetworkEnabled() = 0;\n\n    /** Notify that p2p networking has been disabled */\n    virtual void onNetworkDisabled() = 0;\n\n    /** Notify that number of peers has changed */\n    virtual void onConnectionCountChanged(int32_t numConnections) = 0;\n\n    /** Notify that amount of data sent/received has changed */\n    virtual void onBytesChanged(int32_t totalRecv, int32_t totalSent) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_rpc_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <memory>\n#include <string>\n#include <vector>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSIRpcListener.hpp\"\n#else\nclass IRpcListener;\n#endif\n\n/** C++ interface to execute RPC commands */\nclass IRpcController {\npublic:\n    virtual ~IRpcController() {}\n\n    static void execute(const std::string & rpcCommandLine, const std::shared_ptr<IRpcListener> & resultListener);\n\n    static std::vector<std::string> getAutocompleteList();\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_rpc_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n\n/**\n * Interface to handle result of RPC commands\n * Calls either onSuccess or onError depending on whether command suceedes or fails\n */\n#ifdef DJINNI_NODEJS\n#include \"NJSIRpcListener.hpp\" \n#define IRpcListener NJSIRpcListener\n#else\n\nclass IRpcListener {\npublic:\n    virtual ~IRpcListener() {}\n\n    /**\n     * Returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    virtual void onFilteredCommand(const std::string & filteredCommand) = 0;\n\n    /**\n     * Returns the result and a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    virtual void onSuccess(const std::string & filteredCommand, const std::string & result) = 0;\n\n    /**\n     * Returns an error message which might be a plain string or JSON depending on the type of error\n     * Also returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    virtual void onError(const std::string & filteredCommand, const std::string & errorMessage) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_wallet_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <string>\n\n#ifdef DJINNI_NODEJS\n#include \"NJSIWalletListener.hpp\"\n#else\nclass IWalletListener;\n#endif\nstruct BalanceRecord;\n\n/**\n * Controller to perform functions at a wallet level (e.g. get balance of the entire wallet)\n * For per account functionality see accounts_controller\n */\nclass IWalletController {\npublic:\n    virtual ~IWalletController() {}\n\n    /** Set listener to be notified of wallet events */\n    static void setListener(const std::shared_ptr<IWalletListener> & networklistener);\n\n    /** Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait. */\n    static bool HaveUnconfirmedFunds();\n\n    /** Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds */\n    static int64_t GetBalanceSimple();\n\n    /** Check current wallet balance */\n    static BalanceRecord GetBalance();\n\n    /** Abandon a transaction */\n    static bool AbandonTransaction(const std::string & txHash);\n\n    /** Get a unique UUID that identifies this wallet */\n    static std::string GetUUID();\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_wallet_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n\nstruct BalanceRecord;\nstruct MutationRecord;\nstruct TransactionRecord;\n\n/** Interface to receive wallet level events */\n#ifdef DJINNI_NODEJS\n#include \"NJSIWalletListener.hpp\" \n#define IWalletListener NJSIWalletListener\n#else\n\nclass IWalletListener {\npublic:\n    virtual ~IWalletListener() {}\n\n    /** Notification of change in overall wallet balance */\n    virtual void notifyBalanceChange(const BalanceRecord & new_balance) = 0;\n\n    /**\n     * Notification of new mutations.\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    virtual void notifyNewMutation(const MutationRecord & mutation, bool self_committed) = 0;\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    virtual void notifyUpdatedTransaction(const TransactionRecord & transaction) = 0;\n\n    /** Wallet unlocked */\n    virtual void notifyWalletUnlocked() = 0;\n\n    /** Wallet locked */\n    virtual void notifyWalletLocked() = 0;\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    virtual void notifyCoreWantsUnlock(const std::string & reason) = 0;\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    virtual void notifyCoreInfo(const std::string & type, const std::string & caption, const std::string & message) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/i_witness_controller.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\nstruct ResultRecord;\nstruct WitnessAccountStatisticsRecord;\nstruct WitnessEstimateInfoRecord;\nstruct WitnessFundingResultRecord;\n\n/** C++ interface to control witness accounts */\nclass IWitnessController {\npublic:\n    virtual ~IWitnessController() {}\n\n    /** Get information on min/max witness periods, weights etc. */\n    static std::unordered_map<std::string, std::string> getNetworkLimits();\n\n    /** Get an estimate of weights/parts that a witness account will be funded with */\n    static WitnessEstimateInfoRecord getEstimatedWeight(int64_t amount_to_lock, int64_t lock_period_in_blocks);\n\n    /** Fund a witness account */\n    static WitnessFundingResultRecord fundWitnessAccount(const std::string & funding_account_UUID, const std::string & witness_account_UUID, int64_t funding_amount, int64_t requestedLockPeriodInBlocks);\n\n    /** Renew a witness account */\n    static WitnessFundingResultRecord renewWitnessAccount(const std::string & funding_account_UUID, const std::string & witness_account_UUID);\n\n    /** Get information on account weight and other witness statistics for account */\n    static WitnessAccountStatisticsRecord getAccountWitnessStatistics(const std::string & witnessAccountUUID);\n\n    /** Turn compounding on/off */\n    static void setAccountCompounding(const std::string & witnessAccountUUID, int32_t percent_to_compount);\n\n    /** Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding */\n    static int32_t isAccountCompounding(const std::string & witnessAccountUUID);\n\n    /** Get the witness address of the account */\n    static std::string getWitnessAddress(const std::string & witnessAccountUUID);\n\n    /** Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\" */\n    static std::vector<int64_t> getOptimalWitnessDistribution(int64_t amount, int64_t durationInBlocks, int64_t totalNetworkWeight);\n\n    /** Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values */\n    static std::vector<int64_t> getOptimalWitnessDistributionForAccount(const std::string & witnessAccountUUID);\n\n    /** Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this */\n    static ResultRecord optimiseWitnessAccount(const std::string & witnessAccountUUID, const std::string & fundingAccountUUID, const std::vector<int64_t> & optimalDistribution);\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/input_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n#include <utility>\n\nstruct InputRecord final {\n    std::string address;\n    std::string label;\n    std::string desc;\n    bool isMine;\n\n    InputRecord(std::string address_,\n                std::string label_,\n                std::string desc_,\n                bool isMine_)\n    : address(std::move(address_))\n    , label(std::move(label_))\n    , desc(std::move(desc_))\n    , isMine(std::move(isMine_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/legacy_wallet_result.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <functional>\n\nenum class LegacyWalletResult : int {\n    UNSUPPORTED_ON_THIS_PLATFORM,\n    INVALID_OR_CORRUPT,\n    ENCRYPTED_PASSWORD_REQUIRED,\n    PASSWORD_INVALID,\n    VALID,\n};\n\nnamespace std {\n\ntemplate <>\nstruct hash<::LegacyWalletResult> {\n    size_t operator()(::LegacyWalletResult type) const {\n        return std::hash<int>()(static_cast<int>(type));\n    }\n};\n\n}  // namespace std\n"
  },
  {
    "path": "src/unity/djinni/cpp/mnemonic_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct MnemonicRecord final {\n    std::string phrase_with_birth_number;\n    std::string phrase;\n    int64_t birth_number;\n\n    MnemonicRecord(std::string phrase_with_birth_number_,\n                   std::string phrase_,\n                   int64_t birth_number_)\n    : phrase_with_birth_number(std::move(phrase_with_birth_number_))\n    , phrase(std::move(phrase_))\n    , birth_number(std::move(birth_number_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/monitor_listener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n\n/** Monitoring events */\n#ifdef DJINNI_NODEJS\n#include \"NJSMonitorListener.hpp\" \n#define MonitorListener NJSMonitorListener\n#else\n\nclass MonitorListener {\npublic:\n    virtual ~MonitorListener() {}\n\n    virtual void onPartialChain(int32_t height, int32_t probable_height, int32_t offset) = 0;\n\n    virtual void onPruned(int32_t height) = 0;\n\n    virtual void onProcessedSPVBlocks(int32_t height) = 0;\n};\n#endif\n"
  },
  {
    "path": "src/unity/djinni/cpp/monitor_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <utility>\n\n/** monitoring stats */\nstruct MonitorRecord final {\n    int32_t partialHeight;\n    int32_t partialOffset;\n    int32_t prunedHeight;\n    int32_t processedSPVHeight;\n    int32_t probableHeight;\n\n    MonitorRecord(int32_t partialHeight_,\n                  int32_t partialOffset_,\n                  int32_t prunedHeight_,\n                  int32_t processedSPVHeight_,\n                  int32_t probableHeight_)\n    : partialHeight(std::move(partialHeight_))\n    , partialOffset(std::move(partialOffset_))\n    , prunedHeight(std::move(prunedHeight_))\n    , processedSPVHeight(std::move(processedSPVHeight_))\n    , probableHeight(std::move(probableHeight_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/mutation_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"transaction_status.hpp\"\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct MutationRecord final {\n    int64_t change;\n    int64_t timestamp;\n    std::string txHash;\n    /** Address(es) of transaction recipient(s) (if transaction is sent by us then this excludes e.g. change and only has other wallets addresses) */\n    std::string recipient_addresses;\n    TransactionStatus status;\n    int32_t depth;\n\n    MutationRecord(int64_t change_,\n                   int64_t timestamp_,\n                   std::string txHash_,\n                   std::string recipient_addresses_,\n                   TransactionStatus status_,\n                   int32_t depth_)\n    : change(std::move(change_))\n    , timestamp(std::move(timestamp_))\n    , txHash(std::move(txHash_))\n    , recipient_addresses(std::move(recipient_addresses_))\n    , status(std::move(status_))\n    , depth(std::move(depth_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/output_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct OutputRecord final {\n    int64_t amount;\n    std::string address;\n    std::string label;\n    std::string desc;\n    bool isMine;\n\n    OutputRecord(int64_t amount_,\n                 std::string address_,\n                 std::string label_,\n                 std::string desc_,\n                 bool isMine_)\n    : amount(std::move(amount_))\n    , address(std::move(address_))\n    , label(std::move(label_))\n    , desc(std::move(desc_))\n    , isMine(std::move(isMine_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/payment_result_status.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <functional>\n\nenum class PaymentResultStatus : int {\n    SUCCESS,\n    INSUFFICIENT_FUNDS,\n};\n\nnamespace std {\n\ntemplate <>\nstruct hash<::PaymentResultStatus> {\n    size_t operator()(::PaymentResultStatus type) const {\n        return std::hash<int>()(static_cast<int>(type));\n    }\n};\n\n}  // namespace std\n"
  },
  {
    "path": "src/unity/djinni/cpp/peer_record.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"peer_record.hpp\"  // my header\n\n\nbool operator==(const PeerRecord& lhs, const PeerRecord& rhs) {\n    return lhs.id == rhs.id &&\n           lhs.ip == rhs.ip &&\n           lhs.hostname == rhs.hostname &&\n           lhs.addrLocal == rhs.addrLocal &&\n           lhs.addrBind == rhs.addrBind &&\n           lhs.start_height == rhs.start_height &&\n           lhs.synced_height == rhs.synced_height &&\n           lhs.common_height == rhs.common_height &&\n           lhs.time_connected == rhs.time_connected &&\n           lhs.time_offset == rhs.time_offset &&\n           lhs.latency == rhs.latency &&\n           lhs.last_send == rhs.last_send &&\n           lhs.last_receive == rhs.last_receive &&\n           lhs.send_bytes == rhs.send_bytes &&\n           lhs.receive_bytes == rhs.receive_bytes &&\n           lhs.userAgent == rhs.userAgent &&\n           lhs.protocol == rhs.protocol &&\n           lhs.services == rhs.services &&\n           lhs.inbound == rhs.inbound &&\n           lhs.whitelisted == rhs.whitelisted &&\n           lhs.addnode == rhs.addnode &&\n           lhs.relay_txes == rhs.relay_txes &&\n           lhs.banscore == rhs.banscore;\n}\n\nbool operator!=(const PeerRecord& lhs, const PeerRecord& rhs) {\n    return !(lhs == rhs);\n}\n"
  },
  {
    "path": "src/unity/djinni/cpp/peer_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct PeerRecord final {\n    int64_t id;\n    std::string ip;\n    std::string hostname;\n    std::string addrLocal;\n    std::string addrBind;\n    int64_t start_height;\n    int64_t synced_height;\n    int64_t common_height;\n    int64_t time_connected;\n    int64_t time_offset;\n    int64_t latency;\n    int64_t last_send;\n    int64_t last_receive;\n    int64_t send_bytes;\n    int64_t receive_bytes;\n    std::string userAgent;\n    int64_t protocol;\n    int64_t services;\n    bool inbound;\n    bool whitelisted;\n    bool addnode;\n    bool relay_txes;\n    int64_t banscore;\n\n    friend bool operator==(const PeerRecord& lhs, const PeerRecord& rhs);\n    friend bool operator!=(const PeerRecord& lhs, const PeerRecord& rhs);\n\n    PeerRecord(int64_t id_,\n               std::string ip_,\n               std::string hostname_,\n               std::string addrLocal_,\n               std::string addrBind_,\n               int64_t start_height_,\n               int64_t synced_height_,\n               int64_t common_height_,\n               int64_t time_connected_,\n               int64_t time_offset_,\n               int64_t latency_,\n               int64_t last_send_,\n               int64_t last_receive_,\n               int64_t send_bytes_,\n               int64_t receive_bytes_,\n               std::string userAgent_,\n               int64_t protocol_,\n               int64_t services_,\n               bool inbound_,\n               bool whitelisted_,\n               bool addnode_,\n               bool relay_txes_,\n               int64_t banscore_)\n    : id(std::move(id_))\n    , ip(std::move(ip_))\n    , hostname(std::move(hostname_))\n    , addrLocal(std::move(addrLocal_))\n    , addrBind(std::move(addrBind_))\n    , start_height(std::move(start_height_))\n    , synced_height(std::move(synced_height_))\n    , common_height(std::move(common_height_))\n    , time_connected(std::move(time_connected_))\n    , time_offset(std::move(time_offset_))\n    , latency(std::move(latency_))\n    , last_send(std::move(last_send_))\n    , last_receive(std::move(last_receive_))\n    , send_bytes(std::move(send_bytes_))\n    , receive_bytes(std::move(receive_bytes_))\n    , userAgent(std::move(userAgent_))\n    , protocol(std::move(protocol_))\n    , services(std::move(services_))\n    , inbound(std::move(inbound_))\n    , whitelisted(std::move(whitelisted_))\n    , addnode(std::move(addnode_))\n    , relay_txes(std::move(relay_txes_))\n    , banscore(std::move(banscore_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/qr_code_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <utility>\n#include <vector>\n\nstruct QrCodeRecord final {\n    int32_t width;\n    std::vector<uint8_t> pixel_data;\n\n    QrCodeRecord(int32_t width_,\n                 std::vector<uint8_t> pixel_data_)\n    : width(std::move(width_))\n    , pixel_data(std::move(pixel_data_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/result_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n#include <utility>\n\n/**\n * Copyright (c) 2018-2022 The Centure developers\n * Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n * Distributed under the GNU Lesser General Public License v3, see the accompanying\n * file COPYING\n */\nstruct ResultRecord final {\n    bool result;\n    std::string info;\n\n    ResultRecord(bool result_,\n                 std::string info_)\n    : result(std::move(result_))\n    , info(std::move(info_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/transaction_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"input_record.hpp\"\n#include \"output_record.hpp\"\n#include \"transaction_status.hpp\"\n#include <cstdint>\n#include <string>\n#include <utility>\n#include <vector>\n\nstruct TransactionRecord final {\n    std::string txHash;\n    int64_t timeStamp;\n    int64_t amount;\n    int64_t fee;\n    TransactionStatus status;\n    int32_t height;\n    int64_t blockTime;\n    int32_t depth;\n    std::vector<InputRecord> inputs;\n    std::vector<OutputRecord> outputs;\n\n    TransactionRecord(std::string txHash_,\n                      int64_t timeStamp_,\n                      int64_t amount_,\n                      int64_t fee_,\n                      TransactionStatus status_,\n                      int32_t height_,\n                      int64_t blockTime_,\n                      int32_t depth_,\n                      std::vector<InputRecord> inputs_,\n                      std::vector<OutputRecord> outputs_)\n    : txHash(std::move(txHash_))\n    , timeStamp(std::move(timeStamp_))\n    , amount(std::move(amount_))\n    , fee(std::move(fee_))\n    , status(std::move(status_))\n    , height(std::move(height_))\n    , blockTime(std::move(blockTime_))\n    , depth(std::move(depth_))\n    , inputs(std::move(inputs_))\n    , outputs(std::move(outputs_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/transaction_status.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <functional>\n\nenum class TransactionStatus : int {\n    UNCONFIRMED,\n    CONFIRMING,\n    CONFIRMED,\n    ABANDONED,\n    CONFLICTED,\n};\n\nnamespace std {\n\ntemplate <>\nstruct hash<::TransactionStatus> {\n    size_t operator()(::TransactionStatus type) const {\n        return std::hash<int>()(static_cast<int>(type));\n    }\n};\n\n}  // namespace std\n"
  },
  {
    "path": "src/unity/djinni/cpp/uri_recipient.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct UriRecipient final {\n    bool valid;\n    std::string address;\n    std::string label;\n    std::string desc;\n    int64_t amount;\n\n    UriRecipient(bool valid_,\n                 std::string address_,\n                 std::string label_,\n                 std::string desc_,\n                 int64_t amount_)\n    : valid(std::move(valid_))\n    , address(std::move(address_))\n    , label(std::move(label_))\n    , desc(std::move(desc_))\n    , amount(std::move(amount_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/uri_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <string>\n#include <unordered_map>\n#include <utility>\n\nstruct UriRecord final {\n    std::string scheme;\n    std::string path;\n    std::unordered_map<std::string, std::string> items;\n\n    UriRecord(std::string scheme_,\n              std::string path_,\n              std::unordered_map<std::string, std::string> items_)\n    : scheme(std::move(scheme_))\n    , path(std::move(path_))\n    , items(std::move(items_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/wallet_lock_status.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <utility>\n\nstruct WalletLockStatus final {\n    bool locked;\n    int64_t lock_timeout;\n\n    WalletLockStatus(bool locked_,\n                     int64_t lock_timeout_)\n    : locked(std::move(locked_))\n    , lock_timeout(std::move(lock_timeout_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/witness_account_statistics_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct WitnessAccountStatisticsRecord final {\n    /** Success if request succeeded, otherwise an error message */\n    std::string request_status;\n    /** Current state of the witness account, one of: \"empty\", \"empty_with_remainder\", \"pending\", \"witnessing\", \"ended\", \"expired\", \"emptying\" */\n    std::string account_status;\n    /** Account weight */\n    int64_t blocks_since_last_activity;\n    /** Account weight */\n    int64_t account_weight;\n    /** Account weight when it was created */\n    int64_t account_weight_at_creation;\n    /** How many parts the account weight is split up into */\n    int64_t account_parts;\n    /** Account amount currently locked */\n    int64_t account_amount_locked;\n    /** Account amount locked when it was created */\n    int64_t account_amount_locked_at_creation;\n    /** Current network weight */\n    int64_t network_tip_total_weight;\n    /** Network weight when account was created */\n    int64_t network_total_weight_at_creation;\n    /** Account total lock period in blocks (from creation block) */\n    int64_t account_initial_lock_period_in_blocks;\n    /** Account remaining lock period in blocks (from chain tip) */\n    int64_t account_remaining_lock_period_in_blocks;\n    /** How often the account is \"expected\" by the network to witness in order to not be kicked off */\n    int64_t account_expected_witness_period_in_blocks;\n    /** How often the account is estimated to witness */\n    int64_t account_estimated_witness_period_in_blocks;\n    /** Height at which the account lock first entered the chain */\n    int64_t account_initial_lock_creation_block_height;\n    /** How much of the reward that this account earns is set to be compound */\n    int32_t compounding_percent;\n    /** Is the account weight split in an optimal way */\n    bool is_optimal;\n\n    WitnessAccountStatisticsRecord(std::string request_status_,\n                                   std::string account_status_,\n                                   int64_t blocks_since_last_activity_,\n                                   int64_t account_weight_,\n                                   int64_t account_weight_at_creation_,\n                                   int64_t account_parts_,\n                                   int64_t account_amount_locked_,\n                                   int64_t account_amount_locked_at_creation_,\n                                   int64_t network_tip_total_weight_,\n                                   int64_t network_total_weight_at_creation_,\n                                   int64_t account_initial_lock_period_in_blocks_,\n                                   int64_t account_remaining_lock_period_in_blocks_,\n                                   int64_t account_expected_witness_period_in_blocks_,\n                                   int64_t account_estimated_witness_period_in_blocks_,\n                                   int64_t account_initial_lock_creation_block_height_,\n                                   int32_t compounding_percent_,\n                                   bool is_optimal_)\n    : request_status(std::move(request_status_))\n    , account_status(std::move(account_status_))\n    , blocks_since_last_activity(std::move(blocks_since_last_activity_))\n    , account_weight(std::move(account_weight_))\n    , account_weight_at_creation(std::move(account_weight_at_creation_))\n    , account_parts(std::move(account_parts_))\n    , account_amount_locked(std::move(account_amount_locked_))\n    , account_amount_locked_at_creation(std::move(account_amount_locked_at_creation_))\n    , network_tip_total_weight(std::move(network_tip_total_weight_))\n    , network_total_weight_at_creation(std::move(network_total_weight_at_creation_))\n    , account_initial_lock_period_in_blocks(std::move(account_initial_lock_period_in_blocks_))\n    , account_remaining_lock_period_in_blocks(std::move(account_remaining_lock_period_in_blocks_))\n    , account_expected_witness_period_in_blocks(std::move(account_expected_witness_period_in_blocks_))\n    , account_estimated_witness_period_in_blocks(std::move(account_estimated_witness_period_in_blocks_))\n    , account_initial_lock_creation_block_height(std::move(account_initial_lock_creation_block_height_))\n    , compounding_percent(std::move(compounding_percent_))\n    , is_optimal(std::move(is_optimal_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/witness_estimate_info_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <utility>\n\nstruct WitnessEstimateInfoRecord final {\n    /** Current network weight */\n    int64_t network_weight;\n    /** Weight of resulting witness account */\n    int64_t weight;\n    /** How many parts this weight will be split into */\n    int64_t parts;\n    /** The per block probability of resulting account witnesing */\n    double estimated_witness_probability;\n    /** The estimated number of blocks the resulting account should find per day */\n    double estimated_blocks_per_day;\n    /** The estimated earnings the account should make per day */\n    int64_t estimated_daily_earnings;\n    /** The estimated earnings the account should make over its entire lifetime */\n    int64_t estimated_lifetime_earnings;\n\n    WitnessEstimateInfoRecord(int64_t network_weight_,\n                              int64_t weight_,\n                              int64_t parts_,\n                              double estimated_witness_probability_,\n                              double estimated_blocks_per_day_,\n                              int64_t estimated_daily_earnings_,\n                              int64_t estimated_lifetime_earnings_)\n    : network_weight(std::move(network_weight_))\n    , weight(std::move(weight_))\n    , parts(std::move(parts_))\n    , estimated_witness_probability(std::move(estimated_witness_probability_))\n    , estimated_blocks_per_day(std::move(estimated_blocks_per_day_))\n    , estimated_daily_earnings(std::move(estimated_daily_earnings_))\n    , estimated_lifetime_earnings(std::move(estimated_lifetime_earnings_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/cpp/witness_funding_result_record.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <utility>\n\nstruct WitnessFundingResultRecord final {\n    /** \"success\" on success, otherwise an error message */\n    std::string status;\n    /** txid of the funding transaction, empty on failure */\n    std::string txid;\n    /** fee charged by the transaction, 0 on failure */\n    int64_t fee;\n\n    WitnessFundingResultRecord(std::string status_,\n                               std::string txid_,\n                               int64_t fee_)\n    : status(std::move(status_))\n    , txid(std::move(txid_))\n    , fee(std::move(fee_))\n    {}\n};\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAccountLinkRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeAccountLinkRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeAccountLinkRecord::NativeAccountLinkRecord() = default;\n\nNativeAccountLinkRecord::~NativeAccountLinkRecord() = default;\n\nauto NativeAccountLinkRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeAccountLinkRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.serviceName)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.serviceData)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeAccountLinkRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 3);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeAccountLinkRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mServiceName)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mServiceData))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAccountLinkRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"account_link_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeAccountLinkRecord final {\npublic:\n    using CppType = ::AccountLinkRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeAccountLinkRecord;\n\n    ~NativeAccountLinkRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeAccountLinkRecord();\n    friend ::djinni::JniClass<NativeAccountLinkRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/AccountLinkRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;)V\") };\n    const jfieldID field_mServiceName { ::djinni::jniGetFieldID(clazz.get(), \"mServiceName\", \"Ljava/lang/String;\") };\n    const jfieldID field_mServiceData { ::djinni::jniGetFieldID(clazz.get(), \"mServiceData\", \"Ljava/lang/String;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAccountRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeAccountRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeAccountLinkRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeAccountRecord::NativeAccountRecord() = default;\n\nNativeAccountRecord::~NativeAccountRecord() = default;\n\nauto NativeAccountRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeAccountRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.UUID)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.label)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.state)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.type)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.isHD)),\n                                                           ::djinni::get(::djinni::List<::djinni_generated::NativeAccountLinkRecord>::fromCpp(jniEnv, c.accountLinks)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeAccountRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 7);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeAccountRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mUUID)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mLabel)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mState)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mType)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mIsHD)),\n            ::djinni::List<::djinni_generated::NativeAccountLinkRecord>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mAccountLinks))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAccountRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"account_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeAccountRecord final {\npublic:\n    using CppType = ::AccountRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeAccountRecord;\n\n    ~NativeAccountRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeAccountRecord();\n    friend ::djinni::JniClass<NativeAccountRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/AccountRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/util/ArrayList;)V\") };\n    const jfieldID field_mUUID { ::djinni::jniGetFieldID(clazz.get(), \"mUUID\", \"Ljava/lang/String;\") };\n    const jfieldID field_mLabel { ::djinni::jniGetFieldID(clazz.get(), \"mLabel\", \"Ljava/lang/String;\") };\n    const jfieldID field_mState { ::djinni::jniGetFieldID(clazz.get(), \"mState\", \"Ljava/lang/String;\") };\n    const jfieldID field_mType { ::djinni::jniGetFieldID(clazz.get(), \"mType\", \"Ljava/lang/String;\") };\n    const jfieldID field_mIsHD { ::djinni::jniGetFieldID(clazz.get(), \"mIsHD\", \"Z\") };\n    const jfieldID field_mAccountLinks { ::djinni::jniGetFieldID(clazz.get(), \"mAccountLinks\", \"Ljava/util/ArrayList;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAddressRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeAddressRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeAddressRecord::NativeAddressRecord() = default;\n\nNativeAddressRecord::~NativeAddressRecord() = default;\n\nauto NativeAddressRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeAddressRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.address)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.name)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.desc)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.purpose)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeAddressRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 5);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeAddressRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddress)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mName)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mDesc)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mPurpose))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeAddressRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"address_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeAddressRecord final {\npublic:\n    using CppType = ::AddressRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeAddressRecord;\n\n    ~NativeAddressRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeAddressRecord();\n    friend ::djinni::JniClass<NativeAddressRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/AddressRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\") };\n    const jfieldID field_mAddress { ::djinni::jniGetFieldID(clazz.get(), \"mAddress\", \"Ljava/lang/String;\") };\n    const jfieldID field_mName { ::djinni::jniGetFieldID(clazz.get(), \"mName\", \"Ljava/lang/String;\") };\n    const jfieldID field_mDesc { ::djinni::jniGetFieldID(clazz.get(), \"mDesc\", \"Ljava/lang/String;\") };\n    const jfieldID field_mPurpose { ::djinni::jniGetFieldID(clazz.get(), \"mPurpose\", \"Ljava/lang/String;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBalanceRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeBalanceRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeBalanceRecord::NativeBalanceRecord() = default;\n\nNativeBalanceRecord::~NativeBalanceRecord() = default;\n\nauto NativeBalanceRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeBalanceRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.availableIncludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.availableExcludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.availableLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.unconfirmedIncludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.unconfirmedExcludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.unconfirmedLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.immatureIncludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.immatureExcludingLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.immatureLocked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.totalLocked)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeBalanceRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 11);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeBalanceRecord>::get();\n    return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAvailableIncludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAvailableExcludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAvailableLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mUnconfirmedIncludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mUnconfirmedExcludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mUnconfirmedLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mImmatureIncludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mImmatureExcludingLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mImmatureLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTotalLocked))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBalanceRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"balance_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeBalanceRecord final {\npublic:\n    using CppType = ::BalanceRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeBalanceRecord;\n\n    ~NativeBalanceRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeBalanceRecord();\n    friend ::djinni::JniClass<NativeBalanceRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/BalanceRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(JJJJJJJJJJ)V\") };\n    const jfieldID field_mAvailableIncludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mAvailableIncludingLocked\", \"J\") };\n    const jfieldID field_mAvailableExcludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mAvailableExcludingLocked\", \"J\") };\n    const jfieldID field_mAvailableLocked { ::djinni::jniGetFieldID(clazz.get(), \"mAvailableLocked\", \"J\") };\n    const jfieldID field_mUnconfirmedIncludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mUnconfirmedIncludingLocked\", \"J\") };\n    const jfieldID field_mUnconfirmedExcludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mUnconfirmedExcludingLocked\", \"J\") };\n    const jfieldID field_mUnconfirmedLocked { ::djinni::jniGetFieldID(clazz.get(), \"mUnconfirmedLocked\", \"J\") };\n    const jfieldID field_mImmatureIncludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mImmatureIncludingLocked\", \"J\") };\n    const jfieldID field_mImmatureExcludingLocked { ::djinni::jniGetFieldID(clazz.get(), \"mImmatureExcludingLocked\", \"J\") };\n    const jfieldID field_mImmatureLocked { ::djinni::jniGetFieldID(clazz.get(), \"mImmatureLocked\", \"J\") };\n    const jfieldID field_mTotalLocked { ::djinni::jniGetFieldID(clazz.get(), \"mTotalLocked\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBannedPeerRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeBannedPeerRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeBannedPeerRecord::NativeBannedPeerRecord() = default;\n\nNativeBannedPeerRecord::~NativeBannedPeerRecord() = default;\n\nauto NativeBannedPeerRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeBannedPeerRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.address)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.banned_until)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.banned_from)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.reason)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeBannedPeerRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 5);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeBannedPeerRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddress)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBannedUntil)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBannedFrom)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mReason))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBannedPeerRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"banned_peer_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeBannedPeerRecord final {\npublic:\n    using CppType = ::BannedPeerRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeBannedPeerRecord;\n\n    ~NativeBannedPeerRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeBannedPeerRecord();\n    friend ::djinni::JniClass<NativeBannedPeerRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/BannedPeerRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;JJLjava/lang/String;)V\") };\n    const jfieldID field_mAddress { ::djinni::jniGetFieldID(clazz.get(), \"mAddress\", \"Ljava/lang/String;\") };\n    const jfieldID field_mBannedUntil { ::djinni::jniGetFieldID(clazz.get(), \"mBannedUntil\", \"J\") };\n    const jfieldID field_mBannedFrom { ::djinni::jniGetFieldID(clazz.get(), \"mBannedFrom\", \"J\") };\n    const jfieldID field_mReason { ::djinni::jniGetFieldID(clazz.get(), \"mReason\", \"Ljava/lang/String;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBlockInfoRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeBlockInfoRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeBlockInfoRecord::NativeBlockInfoRecord() = default;\n\nNativeBlockInfoRecord::~NativeBlockInfoRecord() = default;\n\nauto NativeBlockInfoRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeBlockInfoRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.height)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.timeStamp)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.blockHash)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeBlockInfoRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 4);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeBlockInfoRecord>::get();\n    return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mHeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimeStamp)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mBlockHash))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeBlockInfoRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"block_info_record.hpp\"\n#include \"djinni_support.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeBlockInfoRecord final {\npublic:\n    using CppType = ::BlockInfoRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeBlockInfoRecord;\n\n    ~NativeBlockInfoRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeBlockInfoRecord();\n    friend ::djinni::JniClass<NativeBlockInfoRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/BlockInfoRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(IJLjava/lang/String;)V\") };\n    const jfieldID field_mHeight { ::djinni::jniGetFieldID(clazz.get(), \"mHeight\", \"I\") };\n    const jfieldID field_mTimeStamp { ::djinni::jniGetFieldID(clazz.get(), \"mTimeStamp\", \"J\") };\n    const jfieldID field_mBlockHash { ::djinni::jniGetFieldID(clazz.get(), \"mBlockHash\", \"Ljava/lang/String;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIAccountsController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIAccountsController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeAccountLinkRecord.hpp\"\n#include \"NativeAccountRecord.hpp\"\n#include \"NativeBalanceRecord.hpp\"\n#include \"NativeIAccountsListener.hpp\"\n#include \"NativeMutationRecord.hpp\"\n#include \"NativeTransactionRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeIAccountsController::NativeIAccountsController() : ::djinni::JniInterface<::IAccountsController, NativeIAccountsController>(\"unity_wallet/jniunifiedbackend/IAccountsController$CppProxy\") {}\n\nNativeIAccountsController::~NativeIAccountsController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IAccountsController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_setListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_accountslistener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IAccountsController::setListener(::djinni_generated::NativeIAccountsListener::toCpp(jniEnv, j_accountslistener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_listAccounts(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::listAccounts();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeAccountRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_setActiveAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::setActiveAccount(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getActiveAccount(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getActiveAccount();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_createAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountName, jstring j_accountType)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::createAccount(::djinni::String::toCpp(jniEnv, j_accountName),\n                                                      ::djinni::String::toCpp(jniEnv, j_accountType));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getAccountName(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getAccountName(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_renameAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID, jstring j_newAccountName)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::renameAccount(::djinni::String::toCpp(jniEnv, j_accountUUID),\n                                                      ::djinni::String::toCpp(jniEnv, j_newAccountName));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_deleteAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::deleteAccount(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_purgeAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::purgeAccount(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getAccountLinkURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getAccountLinkURI(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getWitnessKeyURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getWitnessKeyURI(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_createAccountFromWitnessKeyURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessKeyURI, jstring j_newAccountName)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::createAccountFromWitnessKeyURI(::djinni::String::toCpp(jniEnv, j_witnessKeyURI),\n                                                                       ::djinni::String::toCpp(jniEnv, j_newAccountName));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getReceiveAddress(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getReceiveAddress(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getTransactionHistory(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getTransactionHistory(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeTransactionRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getMutationHistory(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getMutationHistory(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeMutationRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getActiveAccountBalance(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getActiveAccountBalance();\n        return ::djinni::release(::djinni_generated::NativeBalanceRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getAccountBalance(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getAccountBalance(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni_generated::NativeBalanceRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_getAllAccountBalances(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::getAllAccountBalances();\n        return ::djinni::release(::djinni::Map<::djinni::String, ::djinni_generated::NativeBalanceRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_addAccountLink(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID, jstring j_serviceName, jstring j_data)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::addAccountLink(::djinni::String::toCpp(jniEnv, j_accountUUID),\n                                                       ::djinni::String::toCpp(jniEnv, j_serviceName),\n                                                       ::djinni::String::toCpp(jniEnv, j_data));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_removeAccountLink(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID, jstring j_serviceName)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::removeAccountLink(::djinni::String::toCpp(jniEnv, j_accountUUID),\n                                                          ::djinni::String::toCpp(jniEnv, j_serviceName));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IAccountsController_00024CppProxy_listAccountLinks(JNIEnv* jniEnv, jobject /*this*/, jstring j_accountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IAccountsController::listAccountLinks(::djinni::String::toCpp(jniEnv, j_accountUUID));\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeAccountLinkRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIAccountsController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_accounts_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIAccountsController final : ::djinni::JniInterface<::IAccountsController, NativeIAccountsController> {\npublic:\n    using CppType = std::shared_ptr<::IAccountsController>;\n    using CppOptType = std::shared_ptr<::IAccountsController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIAccountsController;\n\n    ~NativeIAccountsController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIAccountsController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIAccountsController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIAccountsController();\n    friend ::djinni::JniClass<NativeIAccountsController>;\n    friend ::djinni::JniInterface<::IAccountsController, NativeIAccountsController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIAccountsListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIAccountsListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeAccountRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeIAccountsListener::NativeIAccountsListener() : ::djinni::JniInterface<::IAccountsListener, NativeIAccountsListener>() {}\n\nNativeIAccountsListener::~NativeIAccountsListener() = default;\n\nNativeIAccountsListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeIAccountsListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeIAccountsListener::JavaProxy::onActiveAccountChanged(const std::string & c_accountUUID) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onActiveAccountChanged,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountUUID)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIAccountsListener::JavaProxy::onActiveAccountNameChanged(const std::string & c_newAccountName) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onActiveAccountNameChanged,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_newAccountName)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIAccountsListener::JavaProxy::onAccountNameChanged(const std::string & c_accountUUID, const std::string & c_newAccountName) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onAccountNameChanged,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountUUID)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_newAccountName)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIAccountsListener::JavaProxy::onAccountAdded(const std::string & c_accountUUID, const std::string & c_accountName) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onAccountAdded,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountUUID)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountName)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIAccountsListener::JavaProxy::onAccountDeleted(const std::string & c_accountUUID) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onAccountDeleted,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountUUID)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIAccountsListener::JavaProxy::onAccountModified(const std::string & c_accountUUID, const ::AccountRecord & c_accountData) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIAccountsListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onAccountModified,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_accountUUID)),\n                           ::djinni::get(::djinni_generated::NativeAccountRecord::fromCpp(jniEnv, c_accountData)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIAccountsListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_accounts_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIAccountsListener final : ::djinni::JniInterface<::IAccountsListener, NativeIAccountsListener> {\npublic:\n    using CppType = std::shared_ptr<::IAccountsListener>;\n    using CppOptType = std::shared_ptr<::IAccountsListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeIAccountsListener;\n\n    ~NativeIAccountsListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIAccountsListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIAccountsListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIAccountsListener();\n    friend ::djinni::JniClass<NativeIAccountsListener>;\n    friend ::djinni::JniInterface<::IAccountsListener, NativeIAccountsListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::IAccountsListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void onActiveAccountChanged(const std::string & accountUUID) override;\n        void onActiveAccountNameChanged(const std::string & newAccountName) override;\n        void onAccountNameChanged(const std::string & accountUUID, const std::string & newAccountName) override;\n        void onAccountAdded(const std::string & accountUUID, const std::string & accountName) override;\n        void onAccountDeleted(const std::string & accountUUID) override;\n        void onAccountModified(const std::string & accountUUID, const ::AccountRecord & accountData) override;\n\n    private:\n        friend ::djinni::JniInterface<::IAccountsListener, ::djinni_generated::NativeIAccountsListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/IAccountsListener\") };\n    const jmethodID method_onActiveAccountChanged { ::djinni::jniGetMethodID(clazz.get(), \"onActiveAccountChanged\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_onActiveAccountNameChanged { ::djinni::jniGetMethodID(clazz.get(), \"onActiveAccountNameChanged\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_onAccountNameChanged { ::djinni::jniGetMethodID(clazz.get(), \"onAccountNameChanged\", \"(Ljava/lang/String;Ljava/lang/String;)V\") };\n    const jmethodID method_onAccountAdded { ::djinni::jniGetMethodID(clazz.get(), \"onAccountAdded\", \"(Ljava/lang/String;Ljava/lang/String;)V\") };\n    const jmethodID method_onAccountDeleted { ::djinni::jniGetMethodID(clazz.get(), \"onAccountDeleted\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_onAccountModified { ::djinni::jniGetMethodID(clazz.get(), \"onAccountModified\", \"(Ljava/lang/String;Lunity_wallet/jniunifiedbackend/AccountRecord;)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIGenerationController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIGenerationController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeIGenerationListener.hpp\"\n\nnamespace djinni_generated {\n\nNativeIGenerationController::NativeIGenerationController() : ::djinni::JniInterface<::IGenerationController, NativeIGenerationController>(\"unity_wallet/jniunifiedbackend/IGenerationController$CppProxy\") {}\n\nNativeIGenerationController::~NativeIGenerationController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IGenerationController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_setListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_generationListener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IGenerationController::setListener(::djinni_generated::NativeIGenerationListener::toCpp(jniEnv, j_generationListener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_startGeneration(JNIEnv* jniEnv, jobject /*this*/, jint j_numThreads, jint j_numArenaThreads, jstring j_memoryLimit)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::startGeneration(::djinni::I32::toCpp(jniEnv, j_numThreads),\n                                                          ::djinni::I32::toCpp(jniEnv, j_numArenaThreads),\n                                                          ::djinni::String::toCpp(jniEnv, j_memoryLimit));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_stopGeneration(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::stopGeneration();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_getGenerationAddress(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::getGenerationAddress();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_getGenerationOverrideAddress(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::getGenerationOverrideAddress();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_setGenerationOverrideAddress(JNIEnv* jniEnv, jobject /*this*/, jstring j_overrideAddress)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::setGenerationOverrideAddress(::djinni::String::toCpp(jniEnv, j_overrideAddress));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_getAvailableCores(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::getAvailableCores();\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_getMinimumMemory(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::getMinimumMemory();\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_IGenerationController_00024CppProxy_getMaximumMemory(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IGenerationController::getMaximumMemory();\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIGenerationController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_generation_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIGenerationController final : ::djinni::JniInterface<::IGenerationController, NativeIGenerationController> {\npublic:\n    using CppType = std::shared_ptr<::IGenerationController>;\n    using CppOptType = std::shared_ptr<::IGenerationController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIGenerationController;\n\n    ~NativeIGenerationController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIGenerationController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIGenerationController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIGenerationController();\n    friend ::djinni::JniClass<NativeIGenerationController>;\n    friend ::djinni::JniInterface<::IGenerationController, NativeIGenerationController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIGenerationListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIGenerationListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeIGenerationListener::NativeIGenerationListener() : ::djinni::JniInterface<::IGenerationListener, NativeIGenerationListener>() {}\n\nNativeIGenerationListener::~NativeIGenerationListener() = default;\n\nNativeIGenerationListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeIGenerationListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeIGenerationListener::JavaProxy::onGenerationStarted() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIGenerationListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onGenerationStarted);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIGenerationListener::JavaProxy::onGenerationStopped() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIGenerationListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onGenerationStopped);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIGenerationListener::JavaProxy::onStatsUpdated(double c_hashesPerSecond, const std::string & c_hashesPerSecondUnit, double c_rollingHashesPerSecond, const std::string & c_rollingHashesPerSecondUnit, double c_bestHashesPerSecond, const std::string & c_bestHashesPerSecondUnit, double c_arenaSetupTime) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIGenerationListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onStatsUpdated,\n                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c_hashesPerSecond)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_hashesPerSecondUnit)),\n                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c_rollingHashesPerSecond)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_rollingHashesPerSecondUnit)),\n                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c_bestHashesPerSecond)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_bestHashesPerSecondUnit)),\n                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c_arenaSetupTime)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIGenerationListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_generation_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIGenerationListener final : ::djinni::JniInterface<::IGenerationListener, NativeIGenerationListener> {\npublic:\n    using CppType = std::shared_ptr<::IGenerationListener>;\n    using CppOptType = std::shared_ptr<::IGenerationListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeIGenerationListener;\n\n    ~NativeIGenerationListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIGenerationListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIGenerationListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIGenerationListener();\n    friend ::djinni::JniClass<NativeIGenerationListener>;\n    friend ::djinni::JniInterface<::IGenerationListener, NativeIGenerationListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::IGenerationListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void onGenerationStarted() override;\n        void onGenerationStopped() override;\n        void onStatsUpdated(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime) override;\n\n    private:\n        friend ::djinni::JniInterface<::IGenerationListener, ::djinni_generated::NativeIGenerationListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/IGenerationListener\") };\n    const jmethodID method_onGenerationStarted { ::djinni::jniGetMethodID(clazz.get(), \"onGenerationStarted\", \"()V\") };\n    const jmethodID method_onGenerationStopped { ::djinni::jniGetMethodID(clazz.get(), \"onGenerationStopped\", \"()V\") };\n    const jmethodID method_onStatsUpdated { ::djinni::jniGetMethodID(clazz.get(), \"onStatsUpdated\", \"(DLjava/lang/String;DLjava/lang/String;DLjava/lang/String;D)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeILibraryController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeILibraryController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeAddressRecord.hpp\"\n#include \"NativeBlockInfoRecord.hpp\"\n#include \"NativeILibraryListener.hpp\"\n#include \"NativeLegacyWalletResult.hpp\"\n#include \"NativeMnemonicRecord.hpp\"\n#include \"NativeMonitorListener.hpp\"\n#include \"NativeMonitorRecord.hpp\"\n#include \"NativeMutationRecord.hpp\"\n#include \"NativePaymentResultStatus.hpp\"\n#include \"NativeQrCodeRecord.hpp\"\n#include \"NativeTransactionRecord.hpp\"\n#include \"NativeUriRecipient.hpp\"\n#include \"NativeUriRecord.hpp\"\n#include \"NativeWalletLockStatus.hpp\"\n\nnamespace djinni_generated {\n\nNativeILibraryController::NativeILibraryController() : ::djinni::JniInterface<::ILibraryController, NativeILibraryController>(\"unity_wallet/jniunifiedbackend/ILibraryController$CppProxy\") {}\n\nNativeILibraryController::~NativeILibraryController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::ILibraryController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_BuildInfo(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::BuildInfo();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jint JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_InitUnityLib(JNIEnv* jniEnv, jobject /*this*/, jstring j_dataDir, jstring j_staticFilterPath, jlong j_staticFilterOffset, jlong j_staticFilterLength, jboolean j_testnet, jboolean j_spvMode, jobject j_signalHandler, jstring j_extraArgs)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::InitUnityLib(::djinni::String::toCpp(jniEnv, j_dataDir),\n                                                    ::djinni::String::toCpp(jniEnv, j_staticFilterPath),\n                                                    ::djinni::I64::toCpp(jniEnv, j_staticFilterOffset),\n                                                    ::djinni::I64::toCpp(jniEnv, j_staticFilterLength),\n                                                    ::djinni::Bool::toCpp(jniEnv, j_testnet),\n                                                    ::djinni::Bool::toCpp(jniEnv, j_spvMode),\n                                                    ::djinni_generated::NativeILibraryListener::toCpp(jniEnv, j_signalHandler),\n                                                    ::djinni::String::toCpp(jniEnv, j_extraArgs));\n        return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_InitUnityLibThreaded(JNIEnv* jniEnv, jobject /*this*/, jstring j_dataDir, jstring j_staticFilterPath, jlong j_staticFilterOffset, jlong j_staticFilterLength, jboolean j_testnet, jboolean j_spvMode, jobject j_signalHandler, jstring j_extraArgs)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::InitUnityLibThreaded(::djinni::String::toCpp(jniEnv, j_dataDir),\n                                                   ::djinni::String::toCpp(jniEnv, j_staticFilterPath),\n                                                   ::djinni::I64::toCpp(jniEnv, j_staticFilterOffset),\n                                                   ::djinni::I64::toCpp(jniEnv, j_staticFilterLength),\n                                                   ::djinni::Bool::toCpp(jniEnv, j_testnet),\n                                                   ::djinni::Bool::toCpp(jniEnv, j_spvMode),\n                                                   ::djinni_generated::NativeILibraryListener::toCpp(jniEnv, j_signalHandler),\n                                                   ::djinni::String::toCpp(jniEnv, j_extraArgs));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_InitWalletFromRecoveryPhrase(JNIEnv* jniEnv, jobject /*this*/, jstring j_phrase, jstring j_password)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::InitWalletFromRecoveryPhrase(::djinni::String::toCpp(jniEnv, j_phrase),\n                                                                    ::djinni::String::toCpp(jniEnv, j_password));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ContinueWalletFromRecoveryPhrase(JNIEnv* jniEnv, jobject /*this*/, jstring j_phrase, jstring j_password)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::ContinueWalletFromRecoveryPhrase(::djinni::String::toCpp(jniEnv, j_phrase),\n                                                                        ::djinni::String::toCpp(jniEnv, j_password));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_InitWalletLinkedFromURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_linkedUri, jstring j_password)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::InitWalletLinkedFromURI(::djinni::String::toCpp(jniEnv, j_linkedUri),\n                                                               ::djinni::String::toCpp(jniEnv, j_password));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ContinueWalletLinkedFromURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_linkedUri, jstring j_password)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::ContinueWalletLinkedFromURI(::djinni::String::toCpp(jniEnv, j_linkedUri),\n                                                                   ::djinni::String::toCpp(jniEnv, j_password));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_InitWalletFromAndroidLegacyProtoWallet(JNIEnv* jniEnv, jobject /*this*/, jstring j_walletFile, jstring j_oldPassword, jstring j_newPassword)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::InitWalletFromAndroidLegacyProtoWallet(::djinni::String::toCpp(jniEnv, j_walletFile),\n                                                                              ::djinni::String::toCpp(jniEnv, j_oldPassword),\n                                                                              ::djinni::String::toCpp(jniEnv, j_newPassword));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_isValidAndroidLegacyProtoWallet(JNIEnv* jniEnv, jobject /*this*/, jstring j_walletFile, jstring j_oldPassword)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::isValidAndroidLegacyProtoWallet(::djinni::String::toCpp(jniEnv, j_walletFile),\n                                                                       ::djinni::String::toCpp(jniEnv, j_oldPassword));\n        return ::djinni::release(::djinni_generated::NativeLegacyWalletResult::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsValidLinkURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_phrase)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsValidLinkURI(::djinni::String::toCpp(jniEnv, j_phrase));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ReplaceWalletLinkedFromURI(JNIEnv* jniEnv, jobject /*this*/, jstring j_linkedUri, jstring j_password)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::ReplaceWalletLinkedFromURI(::djinni::String::toCpp(jniEnv, j_linkedUri),\n                                                                  ::djinni::String::toCpp(jniEnv, j_password));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_EraseWalletSeedsAndAccounts(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::EraseWalletSeedsAndAccounts();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsValidRecoveryPhrase(JNIEnv* jniEnv, jobject /*this*/, jstring j_phrase)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsValidRecoveryPhrase(::djinni::String::toCpp(jniEnv, j_phrase));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GenerateRecoveryMnemonic(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GenerateRecoveryMnemonic();\n        return ::djinni::release(::djinni_generated::NativeMnemonicRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GenerateGenesisKeys(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GenerateGenesisKeys();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ComposeRecoveryPhrase(JNIEnv* jniEnv, jobject /*this*/, jstring j_mnemonic, jlong j_birthTime)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::ComposeRecoveryPhrase(::djinni::String::toCpp(jniEnv, j_mnemonic),\n                                                             ::djinni::I64::toCpp(jniEnv, j_birthTime));\n        return ::djinni::release(::djinni_generated::NativeMnemonicRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_TerminateUnityLib(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::TerminateUnityLib();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_QRImageFromString(JNIEnv* jniEnv, jobject /*this*/, jstring j_qrString, jint j_widthHint)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::QRImageFromString(::djinni::String::toCpp(jniEnv, j_qrString),\n                                                         ::djinni::I32::toCpp(jniEnv, j_widthHint));\n        return ::djinni::release(::djinni_generated::NativeQrCodeRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GetReceiveAddress(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GetReceiveAddress();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GetRecoveryPhrase(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GetRecoveryPhrase();\n        return ::djinni::release(::djinni_generated::NativeMnemonicRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsMnemonicWallet(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsMnemonicWallet();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsMnemonicCorrect(JNIEnv* jniEnv, jobject /*this*/, jstring j_phrase)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsMnemonicCorrect(::djinni::String::toCpp(jniEnv, j_phrase));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GetMnemonicDictionary(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GetMnemonicDictionary();\n        return ::djinni::release(::djinni::List<::djinni::String>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_UnlockWallet(JNIEnv* jniEnv, jobject /*this*/, jstring j_password, jlong j_timeoutInSeconds)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::UnlockWallet(::djinni::String::toCpp(jniEnv, j_password),\n                                                    ::djinni::I64::toCpp(jniEnv, j_timeoutInSeconds));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_LockWallet(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::LockWallet();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GetWalletLockStatus(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GetWalletLockStatus();\n        return ::djinni::release(::djinni_generated::NativeWalletLockStatus::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ChangePassword(JNIEnv* jniEnv, jobject /*this*/, jstring j_oldPassword, jstring j_newPassword)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::ChangePassword(::djinni::String::toCpp(jniEnv, j_oldPassword),\n                                                      ::djinni::String::toCpp(jniEnv, j_newPassword));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_DoRescan(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::DoRescan();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsValidRecipient(JNIEnv* jniEnv, jobject /*this*/, jobject j_request)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsValidRecipient(::djinni_generated::NativeUriRecord::toCpp(jniEnv, j_request));\n        return ::djinni::release(::djinni_generated::NativeUriRecipient::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsValidNativeAddress(JNIEnv* jniEnv, jobject /*this*/, jstring j_address)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsValidNativeAddress(::djinni::String::toCpp(jniEnv, j_address));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_IsValidBitcoinAddress(JNIEnv* jniEnv, jobject /*this*/, jstring j_address)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::IsValidBitcoinAddress(::djinni::String::toCpp(jniEnv, j_address));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_feeForRecipient(JNIEnv* jniEnv, jobject /*this*/, jobject j_request)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::feeForRecipient(::djinni_generated::NativeUriRecipient::toCpp(jniEnv, j_request));\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_performPaymentToRecipient(JNIEnv* jniEnv, jobject /*this*/, jobject j_request, jboolean j_substractFee)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::performPaymentToRecipient(::djinni_generated::NativeUriRecipient::toCpp(jniEnv, j_request),\n                                                                 ::djinni::Bool::toCpp(jniEnv, j_substractFee));\n        return ::djinni::release(::djinni_generated::NativePaymentResultStatus::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getTransaction(JNIEnv* jniEnv, jobject /*this*/, jstring j_txHash)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getTransaction(::djinni::String::toCpp(jniEnv, j_txHash));\n        return ::djinni::release(::djinni_generated::NativeTransactionRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_resendTransaction(JNIEnv* jniEnv, jobject /*this*/, jstring j_txHash)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::resendTransaction(::djinni::String::toCpp(jniEnv, j_txHash));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getAddressBookRecords(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getAddressBookRecords();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeAddressRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_addAddressBookRecord(JNIEnv* jniEnv, jobject /*this*/, jobject j_address)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::addAddressBookRecord(::djinni_generated::NativeAddressRecord::toCpp(jniEnv, j_address));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_deleteAddressBookRecord(JNIEnv* jniEnv, jobject /*this*/, jobject j_address)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::deleteAddressBookRecord(::djinni_generated::NativeAddressRecord::toCpp(jniEnv, j_address));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_PersistAndPruneForSPV(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::PersistAndPruneForSPV();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_ResetUnifiedProgress(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::ResetUnifiedProgress();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getLastSPVBlockInfos(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getLastSPVBlockInfos();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeBlockInfoRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jfloat JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getUnifiedProgress(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getUnifiedProgress();\n        return ::djinni::release(::djinni::F32::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getMonitoringStats(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getMonitoringStats();\n        return ::djinni::release(::djinni_generated::NativeMonitorRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_RegisterMonitorListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_listener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::RegisterMonitorListener(::djinni_generated::NativeMonitorListener::toCpp(jniEnv, j_listener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_UnregisterMonitorListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_listener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::ILibraryController::UnregisterMonitorListener(::djinni_generated::NativeMonitorListener::toCpp(jniEnv, j_listener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getClientInfo(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getClientInfo();\n        return ::djinni::release(::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getMutationHistory(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getMutationHistory();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeMutationRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_getTransactionHistory(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::getTransactionHistory();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeTransactionRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_HaveUnconfirmedFunds(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::HaveUnconfirmedFunds();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_ILibraryController_00024CppProxy_GetBalance(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::ILibraryController::GetBalance();\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeILibraryController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_library_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeILibraryController final : ::djinni::JniInterface<::ILibraryController, NativeILibraryController> {\npublic:\n    using CppType = std::shared_ptr<::ILibraryController>;\n    using CppOptType = std::shared_ptr<::ILibraryController>;\n    using JniType = jobject;\n\n    using Boxed = NativeILibraryController;\n\n    ~NativeILibraryController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeILibraryController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeILibraryController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeILibraryController();\n    friend ::djinni::JniClass<NativeILibraryController>;\n    friend ::djinni::JniInterface<::ILibraryController, NativeILibraryController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeILibraryListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeILibraryListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeBalanceRecord.hpp\"\n#include \"NativeMutationRecord.hpp\"\n#include \"NativeTransactionRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeILibraryListener::NativeILibraryListener() : ::djinni::JniInterface<::ILibraryListener, NativeILibraryListener>() {}\n\nNativeILibraryListener::~NativeILibraryListener() = default;\n\nNativeILibraryListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeILibraryListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeILibraryListener::JavaProxy::notifyUnifiedProgress(float c_progress) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyUnifiedProgress,\n                           ::djinni::get(::djinni::F32::fromCpp(jniEnv, c_progress)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifySyncDone() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifySyncDone);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyBalanceChange(const ::BalanceRecord & c_new_balance) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyBalanceChange,\n                           ::djinni::get(::djinni_generated::NativeBalanceRecord::fromCpp(jniEnv, c_new_balance)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyNewMutation(const ::MutationRecord & c_mutation, bool c_self_committed) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyNewMutation,\n                           ::djinni::get(::djinni_generated::NativeMutationRecord::fromCpp(jniEnv, c_mutation)),\n                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c_self_committed)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyUpdatedTransaction(const ::TransactionRecord & c_transaction) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyUpdatedTransaction,\n                           ::djinni::get(::djinni_generated::NativeTransactionRecord::fromCpp(jniEnv, c_transaction)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyInitWithExistingWallet() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyInitWithExistingWallet);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyInitWithoutExistingWallet() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyInitWithoutExistingWallet);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyShutdown() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyShutdown);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyCoreReady() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyCoreReady);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::notifyError(const std::string & c_error) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyError,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_error)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeILibraryListener::JavaProxy::logPrint(const std::string & c_str) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeILibraryListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_logPrint,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_str)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeILibraryListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_library_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeILibraryListener final : ::djinni::JniInterface<::ILibraryListener, NativeILibraryListener> {\npublic:\n    using CppType = std::shared_ptr<::ILibraryListener>;\n    using CppOptType = std::shared_ptr<::ILibraryListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeILibraryListener;\n\n    ~NativeILibraryListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeILibraryListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeILibraryListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeILibraryListener();\n    friend ::djinni::JniClass<NativeILibraryListener>;\n    friend ::djinni::JniInterface<::ILibraryListener, NativeILibraryListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::ILibraryListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void notifyUnifiedProgress(float progress) override;\n        void notifySyncDone() override;\n        void notifyBalanceChange(const ::BalanceRecord & new_balance) override;\n        void notifyNewMutation(const ::MutationRecord & mutation, bool self_committed) override;\n        void notifyUpdatedTransaction(const ::TransactionRecord & transaction) override;\n        void notifyInitWithExistingWallet() override;\n        void notifyInitWithoutExistingWallet() override;\n        void notifyShutdown() override;\n        void notifyCoreReady() override;\n        void notifyError(const std::string & error) override;\n        void logPrint(const std::string & str) override;\n\n    private:\n        friend ::djinni::JniInterface<::ILibraryListener, ::djinni_generated::NativeILibraryListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/ILibraryListener\") };\n    const jmethodID method_notifyUnifiedProgress { ::djinni::jniGetMethodID(clazz.get(), \"notifyUnifiedProgress\", \"(F)V\") };\n    const jmethodID method_notifySyncDone { ::djinni::jniGetMethodID(clazz.get(), \"notifySyncDone\", \"()V\") };\n    const jmethodID method_notifyBalanceChange { ::djinni::jniGetMethodID(clazz.get(), \"notifyBalanceChange\", \"(Lunity_wallet/jniunifiedbackend/BalanceRecord;)V\") };\n    const jmethodID method_notifyNewMutation { ::djinni::jniGetMethodID(clazz.get(), \"notifyNewMutation\", \"(Lunity_wallet/jniunifiedbackend/MutationRecord;Z)V\") };\n    const jmethodID method_notifyUpdatedTransaction { ::djinni::jniGetMethodID(clazz.get(), \"notifyUpdatedTransaction\", \"(Lunity_wallet/jniunifiedbackend/TransactionRecord;)V\") };\n    const jmethodID method_notifyInitWithExistingWallet { ::djinni::jniGetMethodID(clazz.get(), \"notifyInitWithExistingWallet\", \"()V\") };\n    const jmethodID method_notifyInitWithoutExistingWallet { ::djinni::jniGetMethodID(clazz.get(), \"notifyInitWithoutExistingWallet\", \"()V\") };\n    const jmethodID method_notifyShutdown { ::djinni::jniGetMethodID(clazz.get(), \"notifyShutdown\", \"()V\") };\n    const jmethodID method_notifyCoreReady { ::djinni::jniGetMethodID(clazz.get(), \"notifyCoreReady\", \"()V\") };\n    const jmethodID method_notifyError { ::djinni::jniGetMethodID(clazz.get(), \"notifyError\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_logPrint { ::djinni::jniGetMethodID(clazz.get(), \"logPrint\", \"(Ljava/lang/String;)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIP2pNetworkController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIP2pNetworkController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeBannedPeerRecord.hpp\"\n#include \"NativeIP2pNetworkListener.hpp\"\n#include \"NativePeerRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeIP2pNetworkController::NativeIP2pNetworkController() : ::djinni::JniInterface<::IP2pNetworkController, NativeIP2pNetworkController>(\"unity_wallet/jniunifiedbackend/IP2pNetworkController$CppProxy\") {}\n\nNativeIP2pNetworkController::~NativeIP2pNetworkController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IP2pNetworkController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_setListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_networklistener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IP2pNetworkController::setListener(::djinni_generated::NativeIP2pNetworkListener::toCpp(jniEnv, j_networklistener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_disableNetwork(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IP2pNetworkController::disableNetwork();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_enableNetwork(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IP2pNetworkController::enableNetwork();\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_getPeerInfo(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::getPeerInfo();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativePeerRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_listBannedPeers(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::listBannedPeers();\n        return ::djinni::release(::djinni::List<::djinni_generated::NativeBannedPeerRecord>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_banPeer(JNIEnv* jniEnv, jobject /*this*/, jstring j_address, jlong j_banTimeInSeconds)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::banPeer(::djinni::String::toCpp(jniEnv, j_address),\n                                                  ::djinni::I64::toCpp(jniEnv, j_banTimeInSeconds));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_unbanPeer(JNIEnv* jniEnv, jobject /*this*/, jstring j_address)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::unbanPeer(::djinni::String::toCpp(jniEnv, j_address));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_disconnectPeer(JNIEnv* jniEnv, jobject /*this*/, jlong j_nodeid)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::disconnectPeer(::djinni::I64::toCpp(jniEnv, j_nodeid));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IP2pNetworkController_00024CppProxy_ClearBanned(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IP2pNetworkController::ClearBanned();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIP2pNetworkController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_p2p_network_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIP2pNetworkController final : ::djinni::JniInterface<::IP2pNetworkController, NativeIP2pNetworkController> {\npublic:\n    using CppType = std::shared_ptr<::IP2pNetworkController>;\n    using CppOptType = std::shared_ptr<::IP2pNetworkController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIP2pNetworkController;\n\n    ~NativeIP2pNetworkController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIP2pNetworkController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIP2pNetworkController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIP2pNetworkController();\n    friend ::djinni::JniClass<NativeIP2pNetworkController>;\n    friend ::djinni::JniInterface<::IP2pNetworkController, NativeIP2pNetworkController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIP2pNetworkListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIP2pNetworkListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeIP2pNetworkListener::NativeIP2pNetworkListener() : ::djinni::JniInterface<::IP2pNetworkListener, NativeIP2pNetworkListener>() {}\n\nNativeIP2pNetworkListener::~NativeIP2pNetworkListener() = default;\n\nNativeIP2pNetworkListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeIP2pNetworkListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeIP2pNetworkListener::JavaProxy::onNetworkEnabled() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIP2pNetworkListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onNetworkEnabled);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIP2pNetworkListener::JavaProxy::onNetworkDisabled() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIP2pNetworkListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onNetworkDisabled);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIP2pNetworkListener::JavaProxy::onConnectionCountChanged(int32_t c_numConnections) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIP2pNetworkListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onConnectionCountChanged,\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_numConnections)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIP2pNetworkListener::JavaProxy::onBytesChanged(int32_t c_totalRecv, int32_t c_totalSent) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIP2pNetworkListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onBytesChanged,\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_totalRecv)),\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_totalSent)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIP2pNetworkListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_p2p_network_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIP2pNetworkListener final : ::djinni::JniInterface<::IP2pNetworkListener, NativeIP2pNetworkListener> {\npublic:\n    using CppType = std::shared_ptr<::IP2pNetworkListener>;\n    using CppOptType = std::shared_ptr<::IP2pNetworkListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeIP2pNetworkListener;\n\n    ~NativeIP2pNetworkListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIP2pNetworkListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIP2pNetworkListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIP2pNetworkListener();\n    friend ::djinni::JniClass<NativeIP2pNetworkListener>;\n    friend ::djinni::JniInterface<::IP2pNetworkListener, NativeIP2pNetworkListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::IP2pNetworkListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void onNetworkEnabled() override;\n        void onNetworkDisabled() override;\n        void onConnectionCountChanged(int32_t numConnections) override;\n        void onBytesChanged(int32_t totalRecv, int32_t totalSent) override;\n\n    private:\n        friend ::djinni::JniInterface<::IP2pNetworkListener, ::djinni_generated::NativeIP2pNetworkListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/IP2pNetworkListener\") };\n    const jmethodID method_onNetworkEnabled { ::djinni::jniGetMethodID(clazz.get(), \"onNetworkEnabled\", \"()V\") };\n    const jmethodID method_onNetworkDisabled { ::djinni::jniGetMethodID(clazz.get(), \"onNetworkDisabled\", \"()V\") };\n    const jmethodID method_onConnectionCountChanged { ::djinni::jniGetMethodID(clazz.get(), \"onConnectionCountChanged\", \"(I)V\") };\n    const jmethodID method_onBytesChanged { ::djinni::jniGetMethodID(clazz.get(), \"onBytesChanged\", \"(II)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIRpcController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIRpcController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeIRpcListener.hpp\"\n\nnamespace djinni_generated {\n\nNativeIRpcController::NativeIRpcController() : ::djinni::JniInterface<::IRpcController, NativeIRpcController>(\"unity_wallet/jniunifiedbackend/IRpcController$CppProxy\") {}\n\nNativeIRpcController::~NativeIRpcController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IRpcController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IRpcController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IRpcController_00024CppProxy_execute(JNIEnv* jniEnv, jobject /*this*/, jstring j_rpcCommandLine, jobject j_resultListener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IRpcController::execute(::djinni::String::toCpp(jniEnv, j_rpcCommandLine),\n                                  ::djinni_generated::NativeIRpcListener::toCpp(jniEnv, j_resultListener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IRpcController_00024CppProxy_getAutocompleteList(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IRpcController::getAutocompleteList();\n        return ::djinni::release(::djinni::List<::djinni::String>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIRpcController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_rpc_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIRpcController final : ::djinni::JniInterface<::IRpcController, NativeIRpcController> {\npublic:\n    using CppType = std::shared_ptr<::IRpcController>;\n    using CppOptType = std::shared_ptr<::IRpcController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIRpcController;\n\n    ~NativeIRpcController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIRpcController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIRpcController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIRpcController();\n    friend ::djinni::JniClass<NativeIRpcController>;\n    friend ::djinni::JniInterface<::IRpcController, NativeIRpcController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIRpcListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIRpcListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeIRpcListener::NativeIRpcListener() : ::djinni::JniInterface<::IRpcListener, NativeIRpcListener>() {}\n\nNativeIRpcListener::~NativeIRpcListener() = default;\n\nNativeIRpcListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeIRpcListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeIRpcListener::JavaProxy::onFilteredCommand(const std::string & c_filteredCommand) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIRpcListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onFilteredCommand,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_filteredCommand)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIRpcListener::JavaProxy::onSuccess(const std::string & c_filteredCommand, const std::string & c_result) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIRpcListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onSuccess,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_filteredCommand)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_result)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIRpcListener::JavaProxy::onError(const std::string & c_filteredCommand, const std::string & c_errorMessage) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIRpcListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onError,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_filteredCommand)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_errorMessage)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIRpcListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_rpc_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIRpcListener final : ::djinni::JniInterface<::IRpcListener, NativeIRpcListener> {\npublic:\n    using CppType = std::shared_ptr<::IRpcListener>;\n    using CppOptType = std::shared_ptr<::IRpcListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeIRpcListener;\n\n    ~NativeIRpcListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIRpcListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIRpcListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIRpcListener();\n    friend ::djinni::JniClass<NativeIRpcListener>;\n    friend ::djinni::JniInterface<::IRpcListener, NativeIRpcListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::IRpcListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void onFilteredCommand(const std::string & filteredCommand) override;\n        void onSuccess(const std::string & filteredCommand, const std::string & result) override;\n        void onError(const std::string & filteredCommand, const std::string & errorMessage) override;\n\n    private:\n        friend ::djinni::JniInterface<::IRpcListener, ::djinni_generated::NativeIRpcListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/IRpcListener\") };\n    const jmethodID method_onFilteredCommand { ::djinni::jniGetMethodID(clazz.get(), \"onFilteredCommand\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_onSuccess { ::djinni::jniGetMethodID(clazz.get(), \"onSuccess\", \"(Ljava/lang/String;Ljava/lang/String;)V\") };\n    const jmethodID method_onError { ::djinni::jniGetMethodID(clazz.get(), \"onError\", \"(Ljava/lang/String;Ljava/lang/String;)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWalletController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIWalletController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeBalanceRecord.hpp\"\n#include \"NativeIWalletListener.hpp\"\n\nnamespace djinni_generated {\n\nNativeIWalletController::NativeIWalletController() : ::djinni::JniInterface<::IWalletController, NativeIWalletController>(\"unity_wallet/jniunifiedbackend/IWalletController$CppProxy\") {}\n\nNativeIWalletController::~NativeIWalletController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IWalletController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_setListener(JNIEnv* jniEnv, jobject /*this*/, jobject j_networklistener)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IWalletController::setListener(::djinni_generated::NativeIWalletListener::toCpp(jniEnv, j_networklistener));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_HaveUnconfirmedFunds(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWalletController::HaveUnconfirmedFunds();\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jlong JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_GetBalanceSimple(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWalletController::GetBalanceSimple();\n        return ::djinni::release(::djinni::I64::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_GetBalance(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWalletController::GetBalance();\n        return ::djinni::release(::djinni_generated::NativeBalanceRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jboolean JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_AbandonTransaction(JNIEnv* jniEnv, jobject /*this*/, jstring j_txHash)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWalletController::AbandonTransaction(::djinni::String::toCpp(jniEnv, j_txHash));\n        return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IWalletController_00024CppProxy_GetUUID(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWalletController::GetUUID();\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWalletController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_wallet_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIWalletController final : ::djinni::JniInterface<::IWalletController, NativeIWalletController> {\npublic:\n    using CppType = std::shared_ptr<::IWalletController>;\n    using CppOptType = std::shared_ptr<::IWalletController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIWalletController;\n\n    ~NativeIWalletController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIWalletController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIWalletController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIWalletController();\n    friend ::djinni::JniClass<NativeIWalletController>;\n    friend ::djinni::JniInterface<::IWalletController, NativeIWalletController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWalletListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIWalletListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeBalanceRecord.hpp\"\n#include \"NativeMutationRecord.hpp\"\n#include \"NativeTransactionRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeIWalletListener::NativeIWalletListener() : ::djinni::JniInterface<::IWalletListener, NativeIWalletListener>() {}\n\nNativeIWalletListener::~NativeIWalletListener() = default;\n\nNativeIWalletListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeIWalletListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeIWalletListener::JavaProxy::notifyBalanceChange(const ::BalanceRecord & c_new_balance) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyBalanceChange,\n                           ::djinni::get(::djinni_generated::NativeBalanceRecord::fromCpp(jniEnv, c_new_balance)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyNewMutation(const ::MutationRecord & c_mutation, bool c_self_committed) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyNewMutation,\n                           ::djinni::get(::djinni_generated::NativeMutationRecord::fromCpp(jniEnv, c_mutation)),\n                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c_self_committed)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyUpdatedTransaction(const ::TransactionRecord & c_transaction) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyUpdatedTransaction,\n                           ::djinni::get(::djinni_generated::NativeTransactionRecord::fromCpp(jniEnv, c_transaction)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyWalletUnlocked() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyWalletUnlocked);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyWalletLocked() {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyWalletLocked);\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyCoreWantsUnlock(const std::string & c_reason) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyCoreWantsUnlock,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_reason)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeIWalletListener::JavaProxy::notifyCoreInfo(const std::string & c_type, const std::string & c_caption, const std::string & c_message) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeIWalletListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_notifyCoreInfo,\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_type)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_caption)),\n                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c_message)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWalletListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_wallet_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIWalletListener final : ::djinni::JniInterface<::IWalletListener, NativeIWalletListener> {\npublic:\n    using CppType = std::shared_ptr<::IWalletListener>;\n    using CppOptType = std::shared_ptr<::IWalletListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeIWalletListener;\n\n    ~NativeIWalletListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIWalletListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIWalletListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIWalletListener();\n    friend ::djinni::JniClass<NativeIWalletListener>;\n    friend ::djinni::JniInterface<::IWalletListener, NativeIWalletListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::IWalletListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void notifyBalanceChange(const ::BalanceRecord & new_balance) override;\n        void notifyNewMutation(const ::MutationRecord & mutation, bool self_committed) override;\n        void notifyUpdatedTransaction(const ::TransactionRecord & transaction) override;\n        void notifyWalletUnlocked() override;\n        void notifyWalletLocked() override;\n        void notifyCoreWantsUnlock(const std::string & reason) override;\n        void notifyCoreInfo(const std::string & type, const std::string & caption, const std::string & message) override;\n\n    private:\n        friend ::djinni::JniInterface<::IWalletListener, ::djinni_generated::NativeIWalletListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/IWalletListener\") };\n    const jmethodID method_notifyBalanceChange { ::djinni::jniGetMethodID(clazz.get(), \"notifyBalanceChange\", \"(Lunity_wallet/jniunifiedbackend/BalanceRecord;)V\") };\n    const jmethodID method_notifyNewMutation { ::djinni::jniGetMethodID(clazz.get(), \"notifyNewMutation\", \"(Lunity_wallet/jniunifiedbackend/MutationRecord;Z)V\") };\n    const jmethodID method_notifyUpdatedTransaction { ::djinni::jniGetMethodID(clazz.get(), \"notifyUpdatedTransaction\", \"(Lunity_wallet/jniunifiedbackend/TransactionRecord;)V\") };\n    const jmethodID method_notifyWalletUnlocked { ::djinni::jniGetMethodID(clazz.get(), \"notifyWalletUnlocked\", \"()V\") };\n    const jmethodID method_notifyWalletLocked { ::djinni::jniGetMethodID(clazz.get(), \"notifyWalletLocked\", \"()V\") };\n    const jmethodID method_notifyCoreWantsUnlock { ::djinni::jniGetMethodID(clazz.get(), \"notifyCoreWantsUnlock\", \"(Ljava/lang/String;)V\") };\n    const jmethodID method_notifyCoreInfo { ::djinni::jniGetMethodID(clazz.get(), \"notifyCoreInfo\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWitnessController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeIWitnessController.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeResultRecord.hpp\"\n#include \"NativeWitnessAccountStatisticsRecord.hpp\"\n#include \"NativeWitnessEstimateInfoRecord.hpp\"\n#include \"NativeWitnessFundingResultRecord.hpp\"\n\nnamespace djinni_generated {\n\nNativeIWitnessController::NativeIWitnessController() : ::djinni::JniInterface<::IWitnessController, NativeIWitnessController>(\"unity_wallet/jniunifiedbackend/IWitnessController$CppProxy\") {}\n\nNativeIWitnessController::~NativeIWitnessController() = default;\n\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);\n        delete reinterpret_cast<::djinni::CppProxyHandle<::IWitnessController>*>(nativeRef);\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getNetworkLimits(JNIEnv* jniEnv, jobject /*this*/)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getNetworkLimits();\n        return ::djinni::release(::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getEstimatedWeight(JNIEnv* jniEnv, jobject /*this*/, jlong j_amountToLock, jlong j_lockPeriodInBlocks)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getEstimatedWeight(::djinni::I64::toCpp(jniEnv, j_amountToLock),\n                                                          ::djinni::I64::toCpp(jniEnv, j_lockPeriodInBlocks));\n        return ::djinni::release(::djinni_generated::NativeWitnessEstimateInfoRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_fundWitnessAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_fundingAccountUUID, jstring j_witnessAccountUUID, jlong j_fundingAmount, jlong j_requestedLockPeriodInBlocks)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::fundWitnessAccount(::djinni::String::toCpp(jniEnv, j_fundingAccountUUID),\n                                                          ::djinni::String::toCpp(jniEnv, j_witnessAccountUUID),\n                                                          ::djinni::I64::toCpp(jniEnv, j_fundingAmount),\n                                                          ::djinni::I64::toCpp(jniEnv, j_requestedLockPeriodInBlocks));\n        return ::djinni::release(::djinni_generated::NativeWitnessFundingResultRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_renewWitnessAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_fundingAccountUUID, jstring j_witnessAccountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::renewWitnessAccount(::djinni::String::toCpp(jniEnv, j_fundingAccountUUID),\n                                                           ::djinni::String::toCpp(jniEnv, j_witnessAccountUUID));\n        return ::djinni::release(::djinni_generated::NativeWitnessFundingResultRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getAccountWitnessStatistics(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getAccountWitnessStatistics(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID));\n        return ::djinni::release(::djinni_generated::NativeWitnessAccountStatisticsRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT void JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_setAccountCompounding(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID, jint j_percentToCompount)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        ::IWitnessController::setAccountCompounding(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID),\n                                                    ::djinni::I32::toCpp(jniEnv, j_percentToCompount));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )\n}\n\nCJNIEXPORT jint JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_isAccountCompounding(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::isAccountCompounding(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID));\n        return ::djinni::release(::djinni::I32::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jstring JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getWitnessAddress(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getWitnessAddress(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID));\n        return ::djinni::release(::djinni::String::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getOptimalWitnessDistribution(JNIEnv* jniEnv, jobject /*this*/, jlong j_amount, jlong j_durationInBlocks, jlong j_totalNetworkWeight)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getOptimalWitnessDistribution(::djinni::I64::toCpp(jniEnv, j_amount),\n                                                                     ::djinni::I64::toCpp(jniEnv, j_durationInBlocks),\n                                                                     ::djinni::I64::toCpp(jniEnv, j_totalNetworkWeight));\n        return ::djinni::release(::djinni::List<::djinni::I64>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_getOptimalWitnessDistributionForAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::getOptimalWitnessDistributionForAccount(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID));\n        return ::djinni::release(::djinni::List<::djinni::I64>::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\nCJNIEXPORT jobject JNICALL Java_unity_1wallet_jniunifiedbackend_IWitnessController_00024CppProxy_optimiseWitnessAccount(JNIEnv* jniEnv, jobject /*this*/, jstring j_witnessAccountUUID, jstring j_fundingAccountUUID, jobject j_optimalDistribution)\n{\n    try {\n        DJINNI_FUNCTION_PROLOGUE0(jniEnv);\n        auto r = ::IWitnessController::optimiseWitnessAccount(::djinni::String::toCpp(jniEnv, j_witnessAccountUUID),\n                                                              ::djinni::String::toCpp(jniEnv, j_fundingAccountUUID),\n                                                              ::djinni::List<::djinni::I64>::toCpp(jniEnv, j_optimalDistribution));\n        return ::djinni::release(::djinni_generated::NativeResultRecord::fromCpp(jniEnv, r));\n    } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeIWitnessController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"i_witness_controller.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeIWitnessController final : ::djinni::JniInterface<::IWitnessController, NativeIWitnessController> {\npublic:\n    using CppType = std::shared_ptr<::IWitnessController>;\n    using CppOptType = std::shared_ptr<::IWitnessController>;\n    using JniType = jobject;\n\n    using Boxed = NativeIWitnessController;\n\n    ~NativeIWitnessController();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeIWitnessController>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeIWitnessController>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeIWitnessController();\n    friend ::djinni::JniClass<NativeIWitnessController>;\n    friend ::djinni::JniInterface<::IWitnessController, NativeIWitnessController>;\n\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeInputRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeInputRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeInputRecord::NativeInputRecord() = default;\n\nNativeInputRecord::~NativeInputRecord() = default;\n\nauto NativeInputRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeInputRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.address)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.label)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.desc)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.isMine)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeInputRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 5);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeInputRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddress)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mLabel)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mDesc)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mIsMine))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeInputRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"input_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeInputRecord final {\npublic:\n    using CppType = ::InputRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeInputRecord;\n\n    ~NativeInputRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeInputRecord();\n    friend ::djinni::JniClass<NativeInputRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/InputRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V\") };\n    const jfieldID field_mAddress { ::djinni::jniGetFieldID(clazz.get(), \"mAddress\", \"Ljava/lang/String;\") };\n    const jfieldID field_mLabel { ::djinni::jniGetFieldID(clazz.get(), \"mLabel\", \"Ljava/lang/String;\") };\n    const jfieldID field_mDesc { ::djinni::jniGetFieldID(clazz.get(), \"mDesc\", \"Ljava/lang/String;\") };\n    const jfieldID field_mIsMine { ::djinni::jniGetFieldID(clazz.get(), \"mIsMine\", \"Z\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeLegacyWalletResult.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"legacy_wallet_result.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeLegacyWalletResult final : ::djinni::JniEnum {\npublic:\n    using CppType = ::LegacyWalletResult;\n    using JniType = jobject;\n\n    using Boxed = NativeLegacyWalletResult;\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<NativeLegacyWalletResult>::get().ordinal(jniEnv, j)); }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<NativeLegacyWalletResult>::get().create(jniEnv, static_cast<jint>(c)); }\n\nprivate:\n    NativeLegacyWalletResult() : JniEnum(\"unity_wallet/jniunifiedbackend/LegacyWalletResult\") {}\n    friend ::djinni::JniClass<NativeLegacyWalletResult>;\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMnemonicRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeMnemonicRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeMnemonicRecord::NativeMnemonicRecord() = default;\n\nNativeMnemonicRecord::~NativeMnemonicRecord() = default;\n\nauto NativeMnemonicRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeMnemonicRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.phrase_with_birth_number)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.phrase)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.birth_number)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeMnemonicRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 4);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeMnemonicRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mPhraseWithBirthNumber)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mPhrase)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBirthNumber))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMnemonicRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"mnemonic_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeMnemonicRecord final {\npublic:\n    using CppType = ::MnemonicRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeMnemonicRecord;\n\n    ~NativeMnemonicRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeMnemonicRecord();\n    friend ::djinni::JniClass<NativeMnemonicRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/MnemonicRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;J)V\") };\n    const jfieldID field_mPhraseWithBirthNumber { ::djinni::jniGetFieldID(clazz.get(), \"mPhraseWithBirthNumber\", \"Ljava/lang/String;\") };\n    const jfieldID field_mPhrase { ::djinni::jniGetFieldID(clazz.get(), \"mPhrase\", \"Ljava/lang/String;\") };\n    const jfieldID field_mBirthNumber { ::djinni::jniGetFieldID(clazz.get(), \"mBirthNumber\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMonitorListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeMonitorListener.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeMonitorListener::NativeMonitorListener() : ::djinni::JniInterface<::MonitorListener, NativeMonitorListener>() {}\n\nNativeMonitorListener::~NativeMonitorListener() = default;\n\nNativeMonitorListener::JavaProxy::JavaProxy(JniType j) : Handle(::djinni::jniGetThreadEnv(), j) { }\n\nNativeMonitorListener::JavaProxy::~JavaProxy() = default;\n\nvoid NativeMonitorListener::JavaProxy::onPartialChain(int32_t c_height, int32_t c_probable_height, int32_t c_offset) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeMonitorListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onPartialChain,\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_height)),\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_probable_height)),\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_offset)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeMonitorListener::JavaProxy::onPruned(int32_t c_height) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeMonitorListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onPruned,\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_height)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\nvoid NativeMonitorListener::JavaProxy::onProcessedSPVBlocks(int32_t c_height) {\n    auto jniEnv = ::djinni::jniGetThreadEnv();\n    ::djinni::JniLocalScope jscope(jniEnv, 10);\n    const auto& data = ::djinni::JniClass<::djinni_generated::NativeMonitorListener>::get();\n    jniEnv->CallVoidMethod(Handle::get().get(), data.method_onProcessedSPVBlocks,\n                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c_height)));\n    ::djinni::jniExceptionCheck(jniEnv);\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMonitorListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"monitor_listener.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeMonitorListener final : ::djinni::JniInterface<::MonitorListener, NativeMonitorListener> {\npublic:\n    using CppType = std::shared_ptr<::MonitorListener>;\n    using CppOptType = std::shared_ptr<::MonitorListener>;\n    using JniType = jobject;\n\n    using Boxed = NativeMonitorListener;\n\n    ~NativeMonitorListener();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeMonitorListener>::get()._fromJava(jniEnv, j); }\n    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeMonitorListener>::get()._toJava(jniEnv, c)}; }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }\n\nprivate:\n    NativeMonitorListener();\n    friend ::djinni::JniClass<NativeMonitorListener>;\n    friend ::djinni::JniInterface<::MonitorListener, NativeMonitorListener>;\n\n    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::MonitorListener\n    {\n    public:\n        JavaProxy(JniType j);\n        ~JavaProxy();\n\n        void onPartialChain(int32_t height, int32_t probable_height, int32_t offset) override;\n        void onPruned(int32_t height) override;\n        void onProcessedSPVBlocks(int32_t height) override;\n\n    private:\n        friend ::djinni::JniInterface<::MonitorListener, ::djinni_generated::NativeMonitorListener>;\n    };\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/MonitorListener\") };\n    const jmethodID method_onPartialChain { ::djinni::jniGetMethodID(clazz.get(), \"onPartialChain\", \"(III)V\") };\n    const jmethodID method_onPruned { ::djinni::jniGetMethodID(clazz.get(), \"onPruned\", \"(I)V\") };\n    const jmethodID method_onProcessedSPVBlocks { ::djinni::jniGetMethodID(clazz.get(), \"onProcessedSPVBlocks\", \"(I)V\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMonitorRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeMonitorRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeMonitorRecord::NativeMonitorRecord() = default;\n\nNativeMonitorRecord::~NativeMonitorRecord() = default;\n\nauto NativeMonitorRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeMonitorRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.partialHeight)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.partialOffset)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.prunedHeight)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.processedSPVHeight)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.probableHeight)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeMonitorRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 6);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeMonitorRecord>::get();\n    return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mPartialHeight)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mPartialOffset)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mPrunedHeight)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mProcessedSPVHeight)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mProbableHeight))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMonitorRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"monitor_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeMonitorRecord final {\npublic:\n    using CppType = ::MonitorRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeMonitorRecord;\n\n    ~NativeMonitorRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeMonitorRecord();\n    friend ::djinni::JniClass<NativeMonitorRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/MonitorRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(IIIII)V\") };\n    const jfieldID field_mPartialHeight { ::djinni::jniGetFieldID(clazz.get(), \"mPartialHeight\", \"I\") };\n    const jfieldID field_mPartialOffset { ::djinni::jniGetFieldID(clazz.get(), \"mPartialOffset\", \"I\") };\n    const jfieldID field_mPrunedHeight { ::djinni::jniGetFieldID(clazz.get(), \"mPrunedHeight\", \"I\") };\n    const jfieldID field_mProcessedSPVHeight { ::djinni::jniGetFieldID(clazz.get(), \"mProcessedSPVHeight\", \"I\") };\n    const jfieldID field_mProbableHeight { ::djinni::jniGetFieldID(clazz.get(), \"mProbableHeight\", \"I\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMutationRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeMutationRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeTransactionStatus.hpp\"\n\nnamespace djinni_generated {\n\nNativeMutationRecord::NativeMutationRecord() = default;\n\nNativeMutationRecord::~NativeMutationRecord() = default;\n\nauto NativeMutationRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeMutationRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.change)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.timestamp)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.txHash)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.recipient_addresses)),\n                                                           ::djinni::get(::djinni_generated::NativeTransactionStatus::fromCpp(jniEnv, c.status)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.depth)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeMutationRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 7);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeMutationRecord>::get();\n    return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mChange)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimestamp)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mTxHash)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mRecipientAddresses)),\n            ::djinni_generated::NativeTransactionStatus::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mStatus)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mDepth))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeMutationRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"mutation_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeMutationRecord final {\npublic:\n    using CppType = ::MutationRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeMutationRecord;\n\n    ~NativeMutationRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeMutationRecord();\n    friend ::djinni::JniClass<NativeMutationRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/MutationRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(JJLjava/lang/String;Ljava/lang/String;Lunity_wallet/jniunifiedbackend/TransactionStatus;I)V\") };\n    const jfieldID field_mChange { ::djinni::jniGetFieldID(clazz.get(), \"mChange\", \"J\") };\n    const jfieldID field_mTimestamp { ::djinni::jniGetFieldID(clazz.get(), \"mTimestamp\", \"J\") };\n    const jfieldID field_mTxHash { ::djinni::jniGetFieldID(clazz.get(), \"mTxHash\", \"Ljava/lang/String;\") };\n    const jfieldID field_mRecipientAddresses { ::djinni::jniGetFieldID(clazz.get(), \"mRecipientAddresses\", \"Ljava/lang/String;\") };\n    const jfieldID field_mStatus { ::djinni::jniGetFieldID(clazz.get(), \"mStatus\", \"Lunity_wallet/jniunifiedbackend/TransactionStatus;\") };\n    const jfieldID field_mDepth { ::djinni::jniGetFieldID(clazz.get(), \"mDepth\", \"I\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeOutputRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeOutputRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeOutputRecord::NativeOutputRecord() = default;\n\nNativeOutputRecord::~NativeOutputRecord() = default;\n\nauto NativeOutputRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeOutputRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.amount)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.address)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.label)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.desc)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.isMine)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeOutputRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 6);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeOutputRecord>::get();\n    return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAmount)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddress)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mLabel)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mDesc)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mIsMine))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeOutputRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"output_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeOutputRecord final {\npublic:\n    using CppType = ::OutputRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeOutputRecord;\n\n    ~NativeOutputRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeOutputRecord();\n    friend ::djinni::JniClass<NativeOutputRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/OutputRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V\") };\n    const jfieldID field_mAmount { ::djinni::jniGetFieldID(clazz.get(), \"mAmount\", \"J\") };\n    const jfieldID field_mAddress { ::djinni::jniGetFieldID(clazz.get(), \"mAddress\", \"Ljava/lang/String;\") };\n    const jfieldID field_mLabel { ::djinni::jniGetFieldID(clazz.get(), \"mLabel\", \"Ljava/lang/String;\") };\n    const jfieldID field_mDesc { ::djinni::jniGetFieldID(clazz.get(), \"mDesc\", \"Ljava/lang/String;\") };\n    const jfieldID field_mIsMine { ::djinni::jniGetFieldID(clazz.get(), \"mIsMine\", \"Z\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativePaymentResultStatus.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"payment_result_status.hpp\"\n\nnamespace djinni_generated {\n\nclass NativePaymentResultStatus final : ::djinni::JniEnum {\npublic:\n    using CppType = ::PaymentResultStatus;\n    using JniType = jobject;\n\n    using Boxed = NativePaymentResultStatus;\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<NativePaymentResultStatus>::get().ordinal(jniEnv, j)); }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<NativePaymentResultStatus>::get().create(jniEnv, static_cast<jint>(c)); }\n\nprivate:\n    NativePaymentResultStatus() : JniEnum(\"unity_wallet/jniunifiedbackend/PaymentResultStatus\") {}\n    friend ::djinni::JniClass<NativePaymentResultStatus>;\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativePeerRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativePeerRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativePeerRecord::NativePeerRecord() = default;\n\nNativePeerRecord::~NativePeerRecord() = default;\n\nauto NativePeerRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativePeerRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.id)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.ip)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.hostname)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.addrLocal)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.addrBind)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.start_height)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.synced_height)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.common_height)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.time_connected)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.time_offset)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.latency)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.last_send)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.last_receive)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.send_bytes)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.receive_bytes)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.userAgent)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.protocol)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.services)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.inbound)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.whitelisted)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.addnode)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.relay_txes)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.banscore)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativePeerRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 24);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativePeerRecord>::get();\n    return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mId)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mIp)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mHostname)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddrLocal)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddrBind)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mStartHeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mSyncedHeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mCommonHeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimeConnected)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimeOffset)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mLatency)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mLastSend)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mLastReceive)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mSendBytes)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mReceiveBytes)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mUserAgent)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mProtocol)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mServices)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mInbound)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mWhitelisted)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mAddnode)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mRelayTxes)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBanscore))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativePeerRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"peer_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativePeerRecord final {\npublic:\n    using CppType = ::PeerRecord;\n    using JniType = jobject;\n\n    using Boxed = NativePeerRecord;\n\n    ~NativePeerRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativePeerRecord();\n    friend ::djinni::JniClass<NativePeerRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/PeerRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JJJJJJJJJJLjava/lang/String;JJZZZZJ)V\") };\n    const jfieldID field_mId { ::djinni::jniGetFieldID(clazz.get(), \"mId\", \"J\") };\n    const jfieldID field_mIp { ::djinni::jniGetFieldID(clazz.get(), \"mIp\", \"Ljava/lang/String;\") };\n    const jfieldID field_mHostname { ::djinni::jniGetFieldID(clazz.get(), \"mHostname\", \"Ljava/lang/String;\") };\n    const jfieldID field_mAddrLocal { ::djinni::jniGetFieldID(clazz.get(), \"mAddrLocal\", \"Ljava/lang/String;\") };\n    const jfieldID field_mAddrBind { ::djinni::jniGetFieldID(clazz.get(), \"mAddrBind\", \"Ljava/lang/String;\") };\n    const jfieldID field_mStartHeight { ::djinni::jniGetFieldID(clazz.get(), \"mStartHeight\", \"J\") };\n    const jfieldID field_mSyncedHeight { ::djinni::jniGetFieldID(clazz.get(), \"mSyncedHeight\", \"J\") };\n    const jfieldID field_mCommonHeight { ::djinni::jniGetFieldID(clazz.get(), \"mCommonHeight\", \"J\") };\n    const jfieldID field_mTimeConnected { ::djinni::jniGetFieldID(clazz.get(), \"mTimeConnected\", \"J\") };\n    const jfieldID field_mTimeOffset { ::djinni::jniGetFieldID(clazz.get(), \"mTimeOffset\", \"J\") };\n    const jfieldID field_mLatency { ::djinni::jniGetFieldID(clazz.get(), \"mLatency\", \"J\") };\n    const jfieldID field_mLastSend { ::djinni::jniGetFieldID(clazz.get(), \"mLastSend\", \"J\") };\n    const jfieldID field_mLastReceive { ::djinni::jniGetFieldID(clazz.get(), \"mLastReceive\", \"J\") };\n    const jfieldID field_mSendBytes { ::djinni::jniGetFieldID(clazz.get(), \"mSendBytes\", \"J\") };\n    const jfieldID field_mReceiveBytes { ::djinni::jniGetFieldID(clazz.get(), \"mReceiveBytes\", \"J\") };\n    const jfieldID field_mUserAgent { ::djinni::jniGetFieldID(clazz.get(), \"mUserAgent\", \"Ljava/lang/String;\") };\n    const jfieldID field_mProtocol { ::djinni::jniGetFieldID(clazz.get(), \"mProtocol\", \"J\") };\n    const jfieldID field_mServices { ::djinni::jniGetFieldID(clazz.get(), \"mServices\", \"J\") };\n    const jfieldID field_mInbound { ::djinni::jniGetFieldID(clazz.get(), \"mInbound\", \"Z\") };\n    const jfieldID field_mWhitelisted { ::djinni::jniGetFieldID(clazz.get(), \"mWhitelisted\", \"Z\") };\n    const jfieldID field_mAddnode { ::djinni::jniGetFieldID(clazz.get(), \"mAddnode\", \"Z\") };\n    const jfieldID field_mRelayTxes { ::djinni::jniGetFieldID(clazz.get(), \"mRelayTxes\", \"Z\") };\n    const jfieldID field_mBanscore { ::djinni::jniGetFieldID(clazz.get(), \"mBanscore\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeQrCodeRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeQrCodeRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeQrCodeRecord::NativeQrCodeRecord() = default;\n\nNativeQrCodeRecord::~NativeQrCodeRecord() = default;\n\nauto NativeQrCodeRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeQrCodeRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.width)),\n                                                           ::djinni::get(::djinni::Binary::fromCpp(jniEnv, c.pixel_data)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeQrCodeRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 3);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeQrCodeRecord>::get();\n    return {::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mWidth)),\n            ::djinni::Binary::toCpp(jniEnv, (jbyteArray)jniEnv->GetObjectField(j, data.field_mPixelData))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeQrCodeRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"qr_code_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeQrCodeRecord final {\npublic:\n    using CppType = ::QrCodeRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeQrCodeRecord;\n\n    ~NativeQrCodeRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeQrCodeRecord();\n    friend ::djinni::JniClass<NativeQrCodeRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/QrCodeRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(I[B)V\") };\n    const jfieldID field_mWidth { ::djinni::jniGetFieldID(clazz.get(), \"mWidth\", \"I\") };\n    const jfieldID field_mPixelData { ::djinni::jniGetFieldID(clazz.get(), \"mPixelData\", \"[B\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeResultRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeResultRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeResultRecord::NativeResultRecord() = default;\n\nNativeResultRecord::~NativeResultRecord() = default;\n\nauto NativeResultRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeResultRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.result)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.info)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeResultRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 3);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeResultRecord>::get();\n    return {::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mResult)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mInfo))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeResultRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"result_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeResultRecord final {\npublic:\n    using CppType = ::ResultRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeResultRecord;\n\n    ~NativeResultRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeResultRecord();\n    friend ::djinni::JniClass<NativeResultRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/ResultRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(ZLjava/lang/String;)V\") };\n    const jfieldID field_mResult { ::djinni::jniGetFieldID(clazz.get(), \"mResult\", \"Z\") };\n    const jfieldID field_mInfo { ::djinni::jniGetFieldID(clazz.get(), \"mInfo\", \"Ljava/lang/String;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeTransactionRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeTransactionRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n#include \"NativeInputRecord.hpp\"\n#include \"NativeOutputRecord.hpp\"\n#include \"NativeTransactionStatus.hpp\"\n\nnamespace djinni_generated {\n\nNativeTransactionRecord::NativeTransactionRecord() = default;\n\nNativeTransactionRecord::~NativeTransactionRecord() = default;\n\nauto NativeTransactionRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeTransactionRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.txHash)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.timeStamp)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.amount)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.fee)),\n                                                           ::djinni::get(::djinni_generated::NativeTransactionStatus::fromCpp(jniEnv, c.status)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.height)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.blockTime)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.depth)),\n                                                           ::djinni::get(::djinni::List<::djinni_generated::NativeInputRecord>::fromCpp(jniEnv, c.inputs)),\n                                                           ::djinni::get(::djinni::List<::djinni_generated::NativeOutputRecord>::fromCpp(jniEnv, c.outputs)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeTransactionRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 11);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeTransactionRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mTxHash)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mTimeStamp)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAmount)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mFee)),\n            ::djinni_generated::NativeTransactionStatus::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mStatus)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mHeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBlockTime)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mDepth)),\n            ::djinni::List<::djinni_generated::NativeInputRecord>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mInputs)),\n            ::djinni::List<::djinni_generated::NativeOutputRecord>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mOutputs))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeTransactionRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"transaction_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeTransactionRecord final {\npublic:\n    using CppType = ::TransactionRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeTransactionRecord;\n\n    ~NativeTransactionRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeTransactionRecord();\n    friend ::djinni::JniClass<NativeTransactionRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/TransactionRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;JJJLunity_wallet/jniunifiedbackend/TransactionStatus;IJILjava/util/ArrayList;Ljava/util/ArrayList;)V\") };\n    const jfieldID field_mTxHash { ::djinni::jniGetFieldID(clazz.get(), \"mTxHash\", \"Ljava/lang/String;\") };\n    const jfieldID field_mTimeStamp { ::djinni::jniGetFieldID(clazz.get(), \"mTimeStamp\", \"J\") };\n    const jfieldID field_mAmount { ::djinni::jniGetFieldID(clazz.get(), \"mAmount\", \"J\") };\n    const jfieldID field_mFee { ::djinni::jniGetFieldID(clazz.get(), \"mFee\", \"J\") };\n    const jfieldID field_mStatus { ::djinni::jniGetFieldID(clazz.get(), \"mStatus\", \"Lunity_wallet/jniunifiedbackend/TransactionStatus;\") };\n    const jfieldID field_mHeight { ::djinni::jniGetFieldID(clazz.get(), \"mHeight\", \"I\") };\n    const jfieldID field_mBlockTime { ::djinni::jniGetFieldID(clazz.get(), \"mBlockTime\", \"J\") };\n    const jfieldID field_mDepth { ::djinni::jniGetFieldID(clazz.get(), \"mDepth\", \"I\") };\n    const jfieldID field_mInputs { ::djinni::jniGetFieldID(clazz.get(), \"mInputs\", \"Ljava/util/ArrayList;\") };\n    const jfieldID field_mOutputs { ::djinni::jniGetFieldID(clazz.get(), \"mOutputs\", \"Ljava/util/ArrayList;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeTransactionStatus.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"transaction_status.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeTransactionStatus final : ::djinni::JniEnum {\npublic:\n    using CppType = ::TransactionStatus;\n    using JniType = jobject;\n\n    using Boxed = NativeTransactionStatus;\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<NativeTransactionStatus>::get().ordinal(jniEnv, j)); }\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<NativeTransactionStatus>::get().create(jniEnv, static_cast<jint>(c)); }\n\nprivate:\n    NativeTransactionStatus() : JniEnum(\"unity_wallet/jniunifiedbackend/TransactionStatus\") {}\n    friend ::djinni::JniClass<NativeTransactionStatus>;\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeUriRecipient.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeUriRecipient.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeUriRecipient::NativeUriRecipient() = default;\n\nNativeUriRecipient::~NativeUriRecipient() = default;\n\nauto NativeUriRecipient::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeUriRecipient>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.valid)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.address)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.label)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.desc)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.amount)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeUriRecipient::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 6);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeUriRecipient>::get();\n    return {::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mValid)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAddress)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mLabel)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mDesc)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAmount))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeUriRecipient.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"uri_recipient.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeUriRecipient final {\npublic:\n    using CppType = ::UriRecipient;\n    using JniType = jobject;\n\n    using Boxed = NativeUriRecipient;\n\n    ~NativeUriRecipient();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeUriRecipient();\n    friend ::djinni::JniClass<NativeUriRecipient>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/UriRecipient\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V\") };\n    const jfieldID field_mValid { ::djinni::jniGetFieldID(clazz.get(), \"mValid\", \"Z\") };\n    const jfieldID field_mAddress { ::djinni::jniGetFieldID(clazz.get(), \"mAddress\", \"Ljava/lang/String;\") };\n    const jfieldID field_mLabel { ::djinni::jniGetFieldID(clazz.get(), \"mLabel\", \"Ljava/lang/String;\") };\n    const jfieldID field_mDesc { ::djinni::jniGetFieldID(clazz.get(), \"mDesc\", \"Ljava/lang/String;\") };\n    const jfieldID field_mAmount { ::djinni::jniGetFieldID(clazz.get(), \"mAmount\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeUriRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeUriRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeUriRecord::NativeUriRecord() = default;\n\nNativeUriRecord::~NativeUriRecord() = default;\n\nauto NativeUriRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeUriRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.scheme)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.path)),\n                                                           ::djinni::get(::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(jniEnv, c.items)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeUriRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 4);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeUriRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mScheme)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mPath)),\n            ::djinni::Map<::djinni::String, ::djinni::String>::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mItems))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeUriRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"uri_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeUriRecord final {\npublic:\n    using CppType = ::UriRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeUriRecord;\n\n    ~NativeUriRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeUriRecord();\n    friend ::djinni::JniClass<NativeUriRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/UriRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/util/HashMap;)V\") };\n    const jfieldID field_mScheme { ::djinni::jniGetFieldID(clazz.get(), \"mScheme\", \"Ljava/lang/String;\") };\n    const jfieldID field_mPath { ::djinni::jniGetFieldID(clazz.get(), \"mPath\", \"Ljava/lang/String;\") };\n    const jfieldID field_mItems { ::djinni::jniGetFieldID(clazz.get(), \"mItems\", \"Ljava/util/HashMap;\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWalletLockStatus.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeWalletLockStatus.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeWalletLockStatus::NativeWalletLockStatus() = default;\n\nNativeWalletLockStatus::~NativeWalletLockStatus() = default;\n\nauto NativeWalletLockStatus::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeWalletLockStatus>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.locked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.lock_timeout)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeWalletLockStatus::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 3);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeWalletLockStatus>::get();\n    return {::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mLockTimeout))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWalletLockStatus.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"wallet_lock_status.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeWalletLockStatus final {\npublic:\n    using CppType = ::WalletLockStatus;\n    using JniType = jobject;\n\n    using Boxed = NativeWalletLockStatus;\n\n    ~NativeWalletLockStatus();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeWalletLockStatus();\n    friend ::djinni::JniClass<NativeWalletLockStatus>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/WalletLockStatus\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(ZJ)V\") };\n    const jfieldID field_mLocked { ::djinni::jniGetFieldID(clazz.get(), \"mLocked\", \"Z\") };\n    const jfieldID field_mLockTimeout { ::djinni::jniGetFieldID(clazz.get(), \"mLockTimeout\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessAccountStatisticsRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeWitnessAccountStatisticsRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeWitnessAccountStatisticsRecord::NativeWitnessAccountStatisticsRecord() = default;\n\nNativeWitnessAccountStatisticsRecord::~NativeWitnessAccountStatisticsRecord() = default;\n\nauto NativeWitnessAccountStatisticsRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeWitnessAccountStatisticsRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.request_status)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.account_status)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.blocks_since_last_activity)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_weight)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_weight_at_creation)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_parts)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_amount_locked)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_amount_locked_at_creation)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.network_tip_total_weight)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.network_total_weight_at_creation)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_initial_lock_period_in_blocks)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_remaining_lock_period_in_blocks)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_expected_witness_period_in_blocks)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_estimated_witness_period_in_blocks)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.account_initial_lock_creation_block_height)),\n                                                           ::djinni::get(::djinni::I32::fromCpp(jniEnv, c.compounding_percent)),\n                                                           ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c.is_optimal)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeWitnessAccountStatisticsRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 18);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeWitnessAccountStatisticsRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mRequestStatus)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mAccountStatus)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mBlocksSinceLastActivity)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountWeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountWeightAtCreation)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountParts)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountAmountLocked)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountAmountLockedAtCreation)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mNetworkTipTotalWeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mNetworkTotalWeightAtCreation)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountInitialLockPeriodInBlocks)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountRemainingLockPeriodInBlocks)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountExpectedWitnessPeriodInBlocks)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountEstimatedWitnessPeriodInBlocks)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mAccountInitialLockCreationBlockHeight)),\n            ::djinni::I32::toCpp(jniEnv, jniEnv->GetIntField(j, data.field_mCompoundingPercent)),\n            ::djinni::Bool::toCpp(jniEnv, jniEnv->GetBooleanField(j, data.field_mIsOptimal))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessAccountStatisticsRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"witness_account_statistics_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeWitnessAccountStatisticsRecord final {\npublic:\n    using CppType = ::WitnessAccountStatisticsRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeWitnessAccountStatisticsRecord;\n\n    ~NativeWitnessAccountStatisticsRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeWitnessAccountStatisticsRecord();\n    friend ::djinni::JniClass<NativeWitnessAccountStatisticsRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/WitnessAccountStatisticsRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;JJJJJJJJJJJJJIZ)V\") };\n    const jfieldID field_mRequestStatus { ::djinni::jniGetFieldID(clazz.get(), \"mRequestStatus\", \"Ljava/lang/String;\") };\n    const jfieldID field_mAccountStatus { ::djinni::jniGetFieldID(clazz.get(), \"mAccountStatus\", \"Ljava/lang/String;\") };\n    const jfieldID field_mBlocksSinceLastActivity { ::djinni::jniGetFieldID(clazz.get(), \"mBlocksSinceLastActivity\", \"J\") };\n    const jfieldID field_mAccountWeight { ::djinni::jniGetFieldID(clazz.get(), \"mAccountWeight\", \"J\") };\n    const jfieldID field_mAccountWeightAtCreation { ::djinni::jniGetFieldID(clazz.get(), \"mAccountWeightAtCreation\", \"J\") };\n    const jfieldID field_mAccountParts { ::djinni::jniGetFieldID(clazz.get(), \"mAccountParts\", \"J\") };\n    const jfieldID field_mAccountAmountLocked { ::djinni::jniGetFieldID(clazz.get(), \"mAccountAmountLocked\", \"J\") };\n    const jfieldID field_mAccountAmountLockedAtCreation { ::djinni::jniGetFieldID(clazz.get(), \"mAccountAmountLockedAtCreation\", \"J\") };\n    const jfieldID field_mNetworkTipTotalWeight { ::djinni::jniGetFieldID(clazz.get(), \"mNetworkTipTotalWeight\", \"J\") };\n    const jfieldID field_mNetworkTotalWeightAtCreation { ::djinni::jniGetFieldID(clazz.get(), \"mNetworkTotalWeightAtCreation\", \"J\") };\n    const jfieldID field_mAccountInitialLockPeriodInBlocks { ::djinni::jniGetFieldID(clazz.get(), \"mAccountInitialLockPeriodInBlocks\", \"J\") };\n    const jfieldID field_mAccountRemainingLockPeriodInBlocks { ::djinni::jniGetFieldID(clazz.get(), \"mAccountRemainingLockPeriodInBlocks\", \"J\") };\n    const jfieldID field_mAccountExpectedWitnessPeriodInBlocks { ::djinni::jniGetFieldID(clazz.get(), \"mAccountExpectedWitnessPeriodInBlocks\", \"J\") };\n    const jfieldID field_mAccountEstimatedWitnessPeriodInBlocks { ::djinni::jniGetFieldID(clazz.get(), \"mAccountEstimatedWitnessPeriodInBlocks\", \"J\") };\n    const jfieldID field_mAccountInitialLockCreationBlockHeight { ::djinni::jniGetFieldID(clazz.get(), \"mAccountInitialLockCreationBlockHeight\", \"J\") };\n    const jfieldID field_mCompoundingPercent { ::djinni::jniGetFieldID(clazz.get(), \"mCompoundingPercent\", \"I\") };\n    const jfieldID field_mIsOptimal { ::djinni::jniGetFieldID(clazz.get(), \"mIsOptimal\", \"Z\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessEstimateInfoRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeWitnessEstimateInfoRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeWitnessEstimateInfoRecord::NativeWitnessEstimateInfoRecord() = default;\n\nNativeWitnessEstimateInfoRecord::~NativeWitnessEstimateInfoRecord() = default;\n\nauto NativeWitnessEstimateInfoRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeWitnessEstimateInfoRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.network_weight)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.weight)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.parts)),\n                                                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.estimated_witness_probability)),\n                                                           ::djinni::get(::djinni::F64::fromCpp(jniEnv, c.estimated_blocks_per_day)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.estimated_daily_earnings)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.estimated_lifetime_earnings)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeWitnessEstimateInfoRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 8);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeWitnessEstimateInfoRecord>::get();\n    return {::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mNetworkWeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mWeight)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mParts)),\n            ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mEstimatedWitnessProbability)),\n            ::djinni::F64::toCpp(jniEnv, jniEnv->GetDoubleField(j, data.field_mEstimatedBlocksPerDay)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mEstimatedDailyEarnings)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mEstimatedLifetimeEarnings))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessEstimateInfoRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"witness_estimate_info_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeWitnessEstimateInfoRecord final {\npublic:\n    using CppType = ::WitnessEstimateInfoRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeWitnessEstimateInfoRecord;\n\n    ~NativeWitnessEstimateInfoRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeWitnessEstimateInfoRecord();\n    friend ::djinni::JniClass<NativeWitnessEstimateInfoRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/WitnessEstimateInfoRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(JJJDDJJ)V\") };\n    const jfieldID field_mNetworkWeight { ::djinni::jniGetFieldID(clazz.get(), \"mNetworkWeight\", \"J\") };\n    const jfieldID field_mWeight { ::djinni::jniGetFieldID(clazz.get(), \"mWeight\", \"J\") };\n    const jfieldID field_mParts { ::djinni::jniGetFieldID(clazz.get(), \"mParts\", \"J\") };\n    const jfieldID field_mEstimatedWitnessProbability { ::djinni::jniGetFieldID(clazz.get(), \"mEstimatedWitnessProbability\", \"D\") };\n    const jfieldID field_mEstimatedBlocksPerDay { ::djinni::jniGetFieldID(clazz.get(), \"mEstimatedBlocksPerDay\", \"D\") };\n    const jfieldID field_mEstimatedDailyEarnings { ::djinni::jniGetFieldID(clazz.get(), \"mEstimatedDailyEarnings\", \"J\") };\n    const jfieldID field_mEstimatedLifetimeEarnings { ::djinni::jniGetFieldID(clazz.get(), \"mEstimatedLifetimeEarnings\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessFundingResultRecord.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NativeWitnessFundingResultRecord.hpp\"  // my header\n#include \"Marshal.hpp\"\n\nnamespace djinni_generated {\n\nNativeWitnessFundingResultRecord::NativeWitnessFundingResultRecord() = default;\n\nNativeWitnessFundingResultRecord::~NativeWitnessFundingResultRecord() = default;\n\nauto NativeWitnessFundingResultRecord::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {\n    const auto& data = ::djinni::JniClass<NativeWitnessFundingResultRecord>::get();\n    auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.status)),\n                                                           ::djinni::get(::djinni::String::fromCpp(jniEnv, c.txid)),\n                                                           ::djinni::get(::djinni::I64::fromCpp(jniEnv, c.fee)))};\n    ::djinni::jniExceptionCheck(jniEnv);\n    return r;\n}\n\nauto NativeWitnessFundingResultRecord::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {\n    ::djinni::JniLocalScope jscope(jniEnv, 4);\n    assert(j != nullptr);\n    const auto& data = ::djinni::JniClass<NativeWitnessFundingResultRecord>::get();\n    return {::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mStatus)),\n            ::djinni::String::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mTxid)),\n            ::djinni::I64::toCpp(jniEnv, jniEnv->GetLongField(j, data.field_mFee))};\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/jni/NativeWitnessFundingResultRecord.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include \"witness_funding_result_record.hpp\"\n\nnamespace djinni_generated {\n\nclass NativeWitnessFundingResultRecord final {\npublic:\n    using CppType = ::WitnessFundingResultRecord;\n    using JniType = jobject;\n\n    using Boxed = NativeWitnessFundingResultRecord;\n\n    ~NativeWitnessFundingResultRecord();\n\n    static CppType toCpp(JNIEnv* jniEnv, JniType j);\n    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);\n\nprivate:\n    NativeWitnessFundingResultRecord();\n    friend ::djinni::JniClass<NativeWitnessFundingResultRecord>;\n\n    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass(\"unity_wallet/jniunifiedbackend/WitnessFundingResultRecord\") };\n    const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;J)V\") };\n    const jfieldID field_mStatus { ::djinni::jniGetFieldID(clazz.get(), \"mStatus\", \"Ljava/lang/String;\") };\n    const jfieldID field_mTxid { ::djinni::jniGetFieldID(clazz.get(), \"mTxid\", \"Ljava/lang/String;\") };\n    const jfieldID field_mFee { ::djinni::jniGetFieldID(clazz.get(), \"mFee\", \"J\") };\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIAccountsController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIAccountsController.hpp\"\nusing namespace std;\n\nvoid NJSIAccountsController::setListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::setListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSIAccountsListener> arg_0(std::shared_ptr<NJSIAccountsListener>{}, NJSIAccountsListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        IAccountsController::setListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIAccountsController::listAccounts(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::listAccounts needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IAccountsController::listAccounts();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::String::New(env, result[arg_0_id].UUID);\n            arg_0_elem.Set(\"UUID\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::String::New(env, result[arg_0_id].label);\n            arg_0_elem.Set(\"label\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::String::New(env, result[arg_0_id].state);\n            arg_0_elem.Set(\"state\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::String::New(env, result[arg_0_id].type);\n            arg_0_elem.Set(\"type\", arg_0_elem_4);\n            auto arg_0_elem_5 = Napi::Value::From(env, result[arg_0_id].isHD);\n            arg_0_elem.Set(\"isHD\", arg_0_elem_5);\n            auto arg_0_elem_6 = Napi::Array::New(env);\n            for(size_t arg_0_elem_6_id = 0; arg_0_elem_6_id < result[arg_0_id].accountLinks.size(); arg_0_elem_6_id++)\n            {\n                auto arg_0_elem_6_elem = Napi::Object::New(env);\n                auto arg_0_elem_6_elem_1 = Napi::String::New(env, result[arg_0_id].accountLinks[arg_0_elem_6_id].serviceName);\n                arg_0_elem_6_elem.Set(\"serviceName\", arg_0_elem_6_elem_1);\n                auto arg_0_elem_6_elem_2 = Napi::String::New(env, result[arg_0_id].accountLinks[arg_0_elem_6_id].serviceData);\n                arg_0_elem_6_elem.Set(\"serviceData\", arg_0_elem_6_elem_2);\n\n                arg_0_elem_6.Set((int)arg_0_elem_6_id,arg_0_elem_6_elem);\n            }\n\n            arg_0_elem.Set(\"accountLinks\", arg_0_elem_6);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::setActiveAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::setActiveAccount needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::setActiveAccount(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getActiveAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getActiveAccount needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IAccountsController::getActiveAccount();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::createAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::createAccount needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::createAccount(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::String::New(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getAccountName(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getAccountName needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getAccountName(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::renameAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::renameAccount needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::renameAccount(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::deleteAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::deleteAccount needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::deleteAccount(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::purgeAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::purgeAccount needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::purgeAccount(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getAccountLinkURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getAccountLinkURI needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getAccountLinkURI(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getWitnessKeyURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getWitnessKeyURI needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getWitnessKeyURI(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::createAccountFromWitnessKeyURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::createAccountFromWitnessKeyURI needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::createAccountFromWitnessKeyURI(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::String::New(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getReceiveAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getReceiveAddress needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getReceiveAddress(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getTransactionHistory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getTransactionHistory needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getTransactionHistory(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Array::New(env);\n        for(size_t arg_1_id = 0; arg_1_id < result.size(); arg_1_id++)\n        {\n            auto arg_1_elem = Napi::Object::New(env);\n            auto arg_1_elem_1 = Napi::String::New(env, result[arg_1_id].txHash);\n            arg_1_elem.Set(\"txHash\", arg_1_elem_1);\n            auto arg_1_elem_2 = Napi::Value::From(env, result[arg_1_id].timeStamp);\n            arg_1_elem.Set(\"timeStamp\", arg_1_elem_2);\n            auto arg_1_elem_3 = Napi::Value::From(env, result[arg_1_id].amount);\n            arg_1_elem.Set(\"amount\", arg_1_elem_3);\n            auto arg_1_elem_4 = Napi::Value::From(env, result[arg_1_id].fee);\n            arg_1_elem.Set(\"fee\", arg_1_elem_4);\n            auto arg_1_elem_5 = Napi::Value::From(env, (int)result[arg_1_id].status);\n            arg_1_elem.Set(\"status\", arg_1_elem_5);\n            auto arg_1_elem_6 = Napi::Value::From(env, result[arg_1_id].height);\n            arg_1_elem.Set(\"height\", arg_1_elem_6);\n            auto arg_1_elem_7 = Napi::Value::From(env, result[arg_1_id].blockTime);\n            arg_1_elem.Set(\"blockTime\", arg_1_elem_7);\n            auto arg_1_elem_8 = Napi::Value::From(env, result[arg_1_id].depth);\n            arg_1_elem.Set(\"depth\", arg_1_elem_8);\n            auto arg_1_elem_9 = Napi::Array::New(env);\n            for(size_t arg_1_elem_9_id = 0; arg_1_elem_9_id < result[arg_1_id].inputs.size(); arg_1_elem_9_id++)\n            {\n                auto arg_1_elem_9_elem = Napi::Object::New(env);\n                auto arg_1_elem_9_elem_1 = Napi::String::New(env, result[arg_1_id].inputs[arg_1_elem_9_id].address);\n                arg_1_elem_9_elem.Set(\"address\", arg_1_elem_9_elem_1);\n                auto arg_1_elem_9_elem_2 = Napi::String::New(env, result[arg_1_id].inputs[arg_1_elem_9_id].label);\n                arg_1_elem_9_elem.Set(\"label\", arg_1_elem_9_elem_2);\n                auto arg_1_elem_9_elem_3 = Napi::String::New(env, result[arg_1_id].inputs[arg_1_elem_9_id].desc);\n                arg_1_elem_9_elem.Set(\"desc\", arg_1_elem_9_elem_3);\n                auto arg_1_elem_9_elem_4 = Napi::Value::From(env, result[arg_1_id].inputs[arg_1_elem_9_id].isMine);\n                arg_1_elem_9_elem.Set(\"isMine\", arg_1_elem_9_elem_4);\n\n                arg_1_elem_9.Set((int)arg_1_elem_9_id,arg_1_elem_9_elem);\n            }\n\n            arg_1_elem.Set(\"inputs\", arg_1_elem_9);\n            auto arg_1_elem_10 = Napi::Array::New(env);\n            for(size_t arg_1_elem_10_id = 0; arg_1_elem_10_id < result[arg_1_id].outputs.size(); arg_1_elem_10_id++)\n            {\n                auto arg_1_elem_10_elem = Napi::Object::New(env);\n                auto arg_1_elem_10_elem_1 = Napi::Value::From(env, result[arg_1_id].outputs[arg_1_elem_10_id].amount);\n                arg_1_elem_10_elem.Set(\"amount\", arg_1_elem_10_elem_1);\n                auto arg_1_elem_10_elem_2 = Napi::String::New(env, result[arg_1_id].outputs[arg_1_elem_10_id].address);\n                arg_1_elem_10_elem.Set(\"address\", arg_1_elem_10_elem_2);\n                auto arg_1_elem_10_elem_3 = Napi::String::New(env, result[arg_1_id].outputs[arg_1_elem_10_id].label);\n                arg_1_elem_10_elem.Set(\"label\", arg_1_elem_10_elem_3);\n                auto arg_1_elem_10_elem_4 = Napi::String::New(env, result[arg_1_id].outputs[arg_1_elem_10_id].desc);\n                arg_1_elem_10_elem.Set(\"desc\", arg_1_elem_10_elem_4);\n                auto arg_1_elem_10_elem_5 = Napi::Value::From(env, result[arg_1_id].outputs[arg_1_elem_10_id].isMine);\n                arg_1_elem_10_elem.Set(\"isMine\", arg_1_elem_10_elem_5);\n\n                arg_1_elem_10.Set((int)arg_1_elem_10_id,arg_1_elem_10_elem);\n            }\n\n            arg_1_elem.Set(\"outputs\", arg_1_elem_10);\n\n            arg_1.Set((int)arg_1_id,arg_1_elem);\n        }\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getMutationHistory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getMutationHistory needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getMutationHistory(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Array::New(env);\n        for(size_t arg_1_id = 0; arg_1_id < result.size(); arg_1_id++)\n        {\n            auto arg_1_elem = Napi::Object::New(env);\n            auto arg_1_elem_1 = Napi::Value::From(env, result[arg_1_id].change);\n            arg_1_elem.Set(\"change\", arg_1_elem_1);\n            auto arg_1_elem_2 = Napi::Value::From(env, result[arg_1_id].timestamp);\n            arg_1_elem.Set(\"timestamp\", arg_1_elem_2);\n            auto arg_1_elem_3 = Napi::String::New(env, result[arg_1_id].txHash);\n            arg_1_elem.Set(\"txHash\", arg_1_elem_3);\n            auto arg_1_elem_4 = Napi::String::New(env, result[arg_1_id].recipient_addresses);\n            arg_1_elem.Set(\"recipient_addresses\", arg_1_elem_4);\n            auto arg_1_elem_5 = Napi::Value::From(env, (int)result[arg_1_id].status);\n            arg_1_elem.Set(\"status\", arg_1_elem_5);\n            auto arg_1_elem_6 = Napi::Value::From(env, result[arg_1_id].depth);\n            arg_1_elem.Set(\"depth\", arg_1_elem_6);\n\n            arg_1.Set((int)arg_1_id,arg_1_elem);\n        }\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getActiveAccountBalance(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getActiveAccountBalance needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IAccountsController::getActiveAccountBalance();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::Value::From(env, result.availableIncludingLocked);\n        arg_0.Set(\"availableIncludingLocked\", arg_0_1);\n        auto arg_0_2 = Napi::Value::From(env, result.availableExcludingLocked);\n        arg_0.Set(\"availableExcludingLocked\", arg_0_2);\n        auto arg_0_3 = Napi::Value::From(env, result.availableLocked);\n        arg_0.Set(\"availableLocked\", arg_0_3);\n        auto arg_0_4 = Napi::Value::From(env, result.unconfirmedIncludingLocked);\n        arg_0.Set(\"unconfirmedIncludingLocked\", arg_0_4);\n        auto arg_0_5 = Napi::Value::From(env, result.unconfirmedExcludingLocked);\n        arg_0.Set(\"unconfirmedExcludingLocked\", arg_0_5);\n        auto arg_0_6 = Napi::Value::From(env, result.unconfirmedLocked);\n        arg_0.Set(\"unconfirmedLocked\", arg_0_6);\n        auto arg_0_7 = Napi::Value::From(env, result.immatureIncludingLocked);\n        arg_0.Set(\"immatureIncludingLocked\", arg_0_7);\n        auto arg_0_8 = Napi::Value::From(env, result.immatureExcludingLocked);\n        arg_0.Set(\"immatureExcludingLocked\", arg_0_8);\n        auto arg_0_9 = Napi::Value::From(env, result.immatureLocked);\n        arg_0.Set(\"immatureLocked\", arg_0_9);\n        auto arg_0_10 = Napi::Value::From(env, result.totalLocked);\n        arg_0.Set(\"totalLocked\", arg_0_10);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getAccountBalance(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getAccountBalance needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::getAccountBalance(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Object::New(env);\n        auto arg_1_1 = Napi::Value::From(env, result.availableIncludingLocked);\n        arg_1.Set(\"availableIncludingLocked\", arg_1_1);\n        auto arg_1_2 = Napi::Value::From(env, result.availableExcludingLocked);\n        arg_1.Set(\"availableExcludingLocked\", arg_1_2);\n        auto arg_1_3 = Napi::Value::From(env, result.availableLocked);\n        arg_1.Set(\"availableLocked\", arg_1_3);\n        auto arg_1_4 = Napi::Value::From(env, result.unconfirmedIncludingLocked);\n        arg_1.Set(\"unconfirmedIncludingLocked\", arg_1_4);\n        auto arg_1_5 = Napi::Value::From(env, result.unconfirmedExcludingLocked);\n        arg_1.Set(\"unconfirmedExcludingLocked\", arg_1_5);\n        auto arg_1_6 = Napi::Value::From(env, result.unconfirmedLocked);\n        arg_1.Set(\"unconfirmedLocked\", arg_1_6);\n        auto arg_1_7 = Napi::Value::From(env, result.immatureIncludingLocked);\n        arg_1.Set(\"immatureIncludingLocked\", arg_1_7);\n        auto arg_1_8 = Napi::Value::From(env, result.immatureExcludingLocked);\n        arg_1.Set(\"immatureExcludingLocked\", arg_1_8);\n        auto arg_1_9 = Napi::Value::From(env, result.immatureLocked);\n        arg_1.Set(\"immatureLocked\", arg_1_9);\n        auto arg_1_10 = Napi::Value::From(env, result.totalLocked);\n        arg_1.Set(\"totalLocked\", arg_1_10);\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::getAllAccountBalances(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::getAllAccountBalances needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IAccountsController::getAllAccountBalances();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        for(auto const& arg_0_elem : result)\n        {\n            auto arg_0_first = Napi::String::New(env, arg_0_elem.first);\n            auto arg_0_second = Napi::Object::New(env);\n            auto arg_0_second_1 = Napi::Value::From(env, arg_0_elem.second.availableIncludingLocked);\n            arg_0_second.Set(\"availableIncludingLocked\", arg_0_second_1);\n            auto arg_0_second_2 = Napi::Value::From(env, arg_0_elem.second.availableExcludingLocked);\n            arg_0_second.Set(\"availableExcludingLocked\", arg_0_second_2);\n            auto arg_0_second_3 = Napi::Value::From(env, arg_0_elem.second.availableLocked);\n            arg_0_second.Set(\"availableLocked\", arg_0_second_3);\n            auto arg_0_second_4 = Napi::Value::From(env, arg_0_elem.second.unconfirmedIncludingLocked);\n            arg_0_second.Set(\"unconfirmedIncludingLocked\", arg_0_second_4);\n            auto arg_0_second_5 = Napi::Value::From(env, arg_0_elem.second.unconfirmedExcludingLocked);\n            arg_0_second.Set(\"unconfirmedExcludingLocked\", arg_0_second_5);\n            auto arg_0_second_6 = Napi::Value::From(env, arg_0_elem.second.unconfirmedLocked);\n            arg_0_second.Set(\"unconfirmedLocked\", arg_0_second_6);\n            auto arg_0_second_7 = Napi::Value::From(env, arg_0_elem.second.immatureIncludingLocked);\n            arg_0_second.Set(\"immatureIncludingLocked\", arg_0_second_7);\n            auto arg_0_second_8 = Napi::Value::From(env, arg_0_elem.second.immatureExcludingLocked);\n            arg_0_second.Set(\"immatureExcludingLocked\", arg_0_second_8);\n            auto arg_0_second_9 = Napi::Value::From(env, arg_0_elem.second.immatureLocked);\n            arg_0_second.Set(\"immatureLocked\", arg_0_second_9);\n            auto arg_0_second_10 = Napi::Value::From(env, arg_0_elem.second.totalLocked);\n            arg_0_second.Set(\"totalLocked\", arg_0_second_10);\n\n            arg_0.Set(arg_0_first, arg_0_second);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::addAccountLink(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 3)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::addAccountLink needs 3 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    std::string arg_2 = info[2].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::addAccountLink(arg_0,arg_1,arg_2);\n\n        //Wrap result in node object\n        auto arg_3 = Napi::Value::From(env, result);\n\n        return arg_3;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::removeAccountLink(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::removeAccountLink needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::removeAccountLink(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIAccountsController::listAccountLinks(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIAccountsController::listAccountLinks needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IAccountsController::listAccountLinks(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Array::New(env);\n        for(size_t arg_1_id = 0; arg_1_id < result.size(); arg_1_id++)\n        {\n            auto arg_1_elem = Napi::Object::New(env);\n            auto arg_1_elem_1 = Napi::String::New(env, result[arg_1_id].serviceName);\n            arg_1_elem.Set(\"serviceName\", arg_1_elem_1);\n            auto arg_1_elem_2 = Napi::String::New(env, result[arg_1_id].serviceData);\n            arg_1_elem.Set(\"serviceData\", arg_1_elem_2);\n\n            arg_1.Set((int)arg_1_id,arg_1_elem);\n        }\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIAccountsController::constructor;\n\nNapi::Object NJSIAccountsController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIAccountsController\", {\n    InstanceMethod(\"setListener\", &NJSIAccountsController::setListener),\n    InstanceMethod(\"listAccounts\", &NJSIAccountsController::listAccounts),\n    InstanceMethod(\"setActiveAccount\", &NJSIAccountsController::setActiveAccount),\n    InstanceMethod(\"getActiveAccount\", &NJSIAccountsController::getActiveAccount),\n    InstanceMethod(\"createAccount\", &NJSIAccountsController::createAccount),\n    InstanceMethod(\"getAccountName\", &NJSIAccountsController::getAccountName),\n    InstanceMethod(\"renameAccount\", &NJSIAccountsController::renameAccount),\n    InstanceMethod(\"deleteAccount\", &NJSIAccountsController::deleteAccount),\n    InstanceMethod(\"purgeAccount\", &NJSIAccountsController::purgeAccount),\n    InstanceMethod(\"getAccountLinkURI\", &NJSIAccountsController::getAccountLinkURI),\n    InstanceMethod(\"getWitnessKeyURI\", &NJSIAccountsController::getWitnessKeyURI),\n    InstanceMethod(\"createAccountFromWitnessKeyURI\", &NJSIAccountsController::createAccountFromWitnessKeyURI),\n    InstanceMethod(\"getReceiveAddress\", &NJSIAccountsController::getReceiveAddress),\n    InstanceMethod(\"getTransactionHistory\", &NJSIAccountsController::getTransactionHistory),\n    InstanceMethod(\"getMutationHistory\", &NJSIAccountsController::getMutationHistory),\n    InstanceMethod(\"getActiveAccountBalance\", &NJSIAccountsController::getActiveAccountBalance),\n    InstanceMethod(\"getAccountBalance\", &NJSIAccountsController::getAccountBalance),\n    InstanceMethod(\"getAllAccountBalances\", &NJSIAccountsController::getAllAccountBalances),\n    InstanceMethod(\"addAccountLink\", &NJSIAccountsController::addAccountLink),\n    InstanceMethod(\"removeAccountLink\", &NJSIAccountsController::removeAccountLink),\n    InstanceMethod(\"listAccountLinks\", &NJSIAccountsController::listAccountLinks),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIAccountsController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIAccountsController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIACCOUNTSCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIACCOUNTSCONTROLLER_HPP\n\n\n#include \"NJSIAccountsListener.hpp\"\n#include \"account_link_record.hpp\"\n#include \"account_record.hpp\"\n#include \"balance_record.hpp\"\n#include \"input_record.hpp\"\n#include \"mutation_record.hpp\"\n#include \"output_record.hpp\"\n#include \"transaction_record.hpp\"\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_accounts_controller.hpp>\n\nusing namespace std;\n\nclass NJSIAccountsController: public Napi::ObjectWrap<NJSIAccountsController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIAccountsController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIAccountsController>(info){};\n\nprivate:\n    /** Register listener to be notified of account related events */\n    void setListener(const Napi::CallbackInfo& info);\n\n    /** List all currently visible accounts in the wallet */\n    Napi::Value listAccounts(const Napi::CallbackInfo& info);\n\n    /** Set the currently active account */\n    Napi::Value setActiveAccount(const Napi::CallbackInfo& info);\n\n    /** Get the currently active account */\n    Napi::Value getActiveAccount(const Napi::CallbackInfo& info);\n\n    /** Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account */\n    Napi::Value createAccount(const Napi::CallbackInfo& info);\n\n    /** Check name of account */\n    Napi::Value getAccountName(const Napi::CallbackInfo& info);\n\n    /** Rename an account */\n    Napi::Value renameAccount(const Napi::CallbackInfo& info);\n\n    /** Delete an account, account remains available in background but is hidden from user */\n    Napi::Value deleteAccount(const Napi::CallbackInfo& info);\n\n    /**\n     * Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n     * If it is a Legacy or imported witness key or similar account then it will be gone forever\n     * Generally prefer 'deleteAccount' and use this with caution\n     */\n    Napi::Value purgeAccount(const Napi::CallbackInfo& info);\n\n    /** Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure.  */\n    Napi::Value getAccountLinkURI(const Napi::CallbackInfo& info);\n\n    /** Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account */\n    Napi::Value getWitnessKeyURI(const Napi::CallbackInfo& info);\n\n    /**\n     * Create a new \"witness-only\" account from a previously exported URI\n     * Returns UUID on success, empty string on failiure\n     */\n    Napi::Value createAccountFromWitnessKeyURI(const Napi::CallbackInfo& info);\n\n    /** Get a receive address for account */\n    Napi::Value getReceiveAddress(const Napi::CallbackInfo& info);\n\n    /** Get list of all transactions account has been involved in */\n    Napi::Value getTransactionHistory(const Napi::CallbackInfo& info);\n\n    /** Get list of mutations for account */\n    Napi::Value getMutationHistory(const Napi::CallbackInfo& info);\n\n    /** Check balance for active account */\n    Napi::Value getActiveAccountBalance(const Napi::CallbackInfo& info);\n\n    /** Check balance for account */\n    Napi::Value getAccountBalance(const Napi::CallbackInfo& info);\n\n    /** Check balance for all accounts, returns a map of account_uuid->balance_record */\n    Napi::Value getAllAccountBalances(const Napi::CallbackInfo& info);\n\n    /**Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key) */\n    Napi::Value addAccountLink(const Napi::CallbackInfo& info);\n\n    /**Register with wallet to remove an existing link */\n    Napi::Value removeAccountLink(const Napi::CallbackInfo& info);\n\n    /**List all active account links that we have previously registered */\n    Napi::Value listAccountLinks(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIACCOUNTSCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIAccountsListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIAccountsListener.hpp\"\nusing namespace std;\n\nvoid NJSIAccountsListener::onActiveAccountChanged_aimpl__(const std::string & accountUUID)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, accountUUID);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onActiveAccountChanged\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onActiveAccountChanged = calling_function.Call(args);\n        if(result_onActiveAccountChanged.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onActiveAccountChanged call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onActiveAccountChanged(const std::string & accountUUID)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string>(this, accountUUID);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data));\n        pthis->onActiveAccountChanged_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIAccountsListener::onActiveAccountNameChanged_aimpl__(const std::string & newAccountName)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, newAccountName);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onActiveAccountNameChanged\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onActiveAccountNameChanged = calling_function.Call(args);\n        if(result_onActiveAccountNameChanged.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onActiveAccountNameChanged call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onActiveAccountNameChanged(const std::string & newAccountName)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string>(this, newAccountName);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data));\n        pthis->onActiveAccountNameChanged_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIAccountsListener::onAccountNameChanged_aimpl__(const std::string & accountUUID, const std::string & newAccountName)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, accountUUID);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, newAccountName);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onAccountNameChanged\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onAccountNameChanged = calling_function.Call(args);\n        if(result_onAccountNameChanged.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onAccountNameChanged call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onAccountNameChanged(const std::string & accountUUID, const std::string & newAccountName)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string, std::string>(this, accountUUID, newAccountName);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data));\n        pthis->onAccountNameChanged_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data)), std::get<2>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIAccountsListener::onAccountAdded_aimpl__(const std::string & accountUUID, const std::string & accountName)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, accountUUID);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, accountName);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onAccountAdded\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onAccountAdded = calling_function.Call(args);\n        if(result_onAccountAdded.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onAccountAdded call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onAccountAdded(const std::string & accountUUID, const std::string & accountName)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string, std::string>(this, accountUUID, accountName);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data));\n        pthis->onAccountAdded_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data)), std::get<2>(*((std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIAccountsListener::onAccountDeleted_aimpl__(const std::string & accountUUID)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, accountUUID);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onAccountDeleted\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onAccountDeleted = calling_function.Call(args);\n        if(result_onAccountDeleted.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onAccountDeleted call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onAccountDeleted(const std::string & accountUUID)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string>(this, accountUUID);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data));\n        pthis->onAccountDeleted_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIAccountsListener::onAccountModified_aimpl__(const std::string & accountUUID, const AccountRecord & accountData)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, accountUUID);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::Object::New(env);\n    auto arg_1_1 = Napi::String::New(env, accountData.UUID);\n    arg_1.Set(\"UUID\", arg_1_1);\n    auto arg_1_2 = Napi::String::New(env, accountData.label);\n    arg_1.Set(\"label\", arg_1_2);\n    auto arg_1_3 = Napi::String::New(env, accountData.state);\n    arg_1.Set(\"state\", arg_1_3);\n    auto arg_1_4 = Napi::String::New(env, accountData.type);\n    arg_1.Set(\"type\", arg_1_4);\n    auto arg_1_5 = Napi::Value::From(env, accountData.isHD);\n    arg_1.Set(\"isHD\", arg_1_5);\n    auto arg_1_6 = Napi::Array::New(env);\n    for(size_t arg_1_6_id = 0; arg_1_6_id < accountData.accountLinks.size(); arg_1_6_id++)\n    {\n        auto arg_1_6_elem = Napi::Object::New(env);\n        auto arg_1_6_elem_1 = Napi::String::New(env, accountData.accountLinks[arg_1_6_id].serviceName);\n        arg_1_6_elem.Set(\"serviceName\", arg_1_6_elem_1);\n        auto arg_1_6_elem_2 = Napi::String::New(env, accountData.accountLinks[arg_1_6_id].serviceData);\n        arg_1_6_elem.Set(\"serviceData\", arg_1_6_elem_2);\n\n        arg_1_6.Set((int)arg_1_6_id,arg_1_6_elem);\n    }\n\n    arg_1.Set(\"accountLinks\", arg_1_6);\n\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onAccountModified\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onAccountModified = calling_function.Call(args);\n        if(result_onAccountModified.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIAccountsListener::onAccountModified call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIAccountsListener::onAccountModified(const std::string & accountUUID, const AccountRecord & accountData)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIAccountsListener*, std::string, AccountRecord>(this, accountUUID, accountData);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIAccountsListener* pthis = std::get<0>(*((std::tuple<NJSIAccountsListener*, std::string, AccountRecord>*)req->data));\n        pthis->onAccountModified_aimpl__(std::get<1>(*((std::tuple<NJSIAccountsListener*, std::string, AccountRecord>*)req->data)), std::get<2>(*((std::tuple<NJSIAccountsListener*, std::string, AccountRecord>*)req->data)));\n        delete (std::tuple<NJSIAccountsListener*, std::string, AccountRecord>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSIAccountsListener::constructor;\n\nNapi::Object NJSIAccountsListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSIAccountsListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIAccountsListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIAccountsListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIACCOUNTSLISTENER_HPP\n#define DJINNI_GENERATED_NJSIACCOUNTSLISTENER_HPP\n\n\n#include \"account_link_record.hpp\"\n#include \"account_record.hpp\"\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_accounts_listener.hpp>\n\nusing namespace std;\n\nclass NJSIAccountsListener: public Napi::ObjectWrap<NJSIAccountsListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIAccountsListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIAccountsListener>(info){};\n\n    /** Notify that the active account has changed */\n    void onActiveAccountChanged(const std::string & accountUUID);\n\n    /** Notify that the active account name has changed */\n    void onActiveAccountNameChanged(const std::string & newAccountName);\n\n    /** Notify that an account name has changed */\n    void onAccountNameChanged(const std::string & accountUUID, const std::string & newAccountName);\n\n    /** Notify that a new account has been added */\n    void onAccountAdded(const std::string & accountUUID, const std::string & accountName);\n\n    /** Notify that an account has been deleted */\n    void onAccountDeleted(const std::string & accountUUID);\n\n    /** Notify that an account has been modified */\n    void onAccountModified(const std::string & accountUUID, const AccountRecord & accountData);\n\nprivate:\n    /** Notify that the active account has changed */\n    void onActiveAccountChanged(const Napi::CallbackInfo& info);\n    void onActiveAccountChanged_aimpl__(const std::string & accountUUID);\n\n    /** Notify that the active account name has changed */\n    void onActiveAccountNameChanged(const Napi::CallbackInfo& info);\n    void onActiveAccountNameChanged_aimpl__(const std::string & newAccountName);\n\n    /** Notify that an account name has changed */\n    void onAccountNameChanged(const Napi::CallbackInfo& info);\n    void onAccountNameChanged_aimpl__(const std::string & accountUUID, const std::string & newAccountName);\n\n    /** Notify that a new account has been added */\n    void onAccountAdded(const Napi::CallbackInfo& info);\n    void onAccountAdded_aimpl__(const std::string & accountUUID, const std::string & accountName);\n\n    /** Notify that an account has been deleted */\n    void onAccountDeleted(const Napi::CallbackInfo& info);\n    void onAccountDeleted_aimpl__(const std::string & accountUUID);\n\n    /** Notify that an account has been modified */\n    void onAccountModified(const Napi::CallbackInfo& info);\n    void onAccountModified_aimpl__(const std::string & accountUUID, const AccountRecord & accountData);\n\n};\n#endif //DJINNI_GENERATED_NJSIACCOUNTSLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIGenerationController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIGenerationController.hpp\"\nusing namespace std;\n\nvoid NJSIGenerationController::setListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::setListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSIGenerationListener> arg_0(std::shared_ptr<NJSIGenerationListener>{}, NJSIGenerationListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        IGenerationController::setListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIGenerationController::startGeneration(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 3)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::startGeneration needs 3 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    auto arg_0 = info[0].ToNumber().Int32Value();\n    auto arg_1 = info[1].ToNumber().Int32Value();\n    std::string arg_2 = info[2].As<Napi::String>();\n\n    try\n    {\n        auto result = IGenerationController::startGeneration(arg_0,arg_1,arg_2);\n\n        //Wrap result in node object\n        auto arg_3 = Napi::Value::From(env, result);\n\n        return arg_3;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::stopGeneration(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::stopGeneration needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::stopGeneration();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::getGenerationAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::getGenerationAddress needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::getGenerationAddress();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::getGenerationOverrideAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::getGenerationOverrideAddress needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::getGenerationOverrideAddress();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::setGenerationOverrideAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::setGenerationOverrideAddress needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IGenerationController::setGenerationOverrideAddress(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::getAvailableCores(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::getAvailableCores needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::getAvailableCores();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::getMinimumMemory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::getMinimumMemory needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::getMinimumMemory();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIGenerationController::getMaximumMemory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIGenerationController::getMaximumMemory needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IGenerationController::getMaximumMemory();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIGenerationController::constructor;\n\nNapi::Object NJSIGenerationController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIGenerationController\", {\n    InstanceMethod(\"setListener\", &NJSIGenerationController::setListener),\n    InstanceMethod(\"startGeneration\", &NJSIGenerationController::startGeneration),\n    InstanceMethod(\"stopGeneration\", &NJSIGenerationController::stopGeneration),\n    InstanceMethod(\"getGenerationAddress\", &NJSIGenerationController::getGenerationAddress),\n    InstanceMethod(\"getGenerationOverrideAddress\", &NJSIGenerationController::getGenerationOverrideAddress),\n    InstanceMethod(\"setGenerationOverrideAddress\", &NJSIGenerationController::setGenerationOverrideAddress),\n    InstanceMethod(\"getAvailableCores\", &NJSIGenerationController::getAvailableCores),\n    InstanceMethod(\"getMinimumMemory\", &NJSIGenerationController::getMinimumMemory),\n    InstanceMethod(\"getMaximumMemory\", &NJSIGenerationController::getMaximumMemory),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIGenerationController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIGenerationController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIGENERATIONCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIGENERATIONCONTROLLER_HPP\n\n\n#include \"NJSIGenerationListener.hpp\"\n#include <cstdint>\n#include <memory>\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_generation_controller.hpp>\n\nusing namespace std;\n\nclass NJSIGenerationController: public Napi::ObjectWrap<NJSIGenerationController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIGenerationController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIGenerationController>(info){};\n\nprivate:\n    /** Register listener to be notified of generation related events */\n    void setListener(const Napi::CallbackInfo& info);\n\n    /**\n     * Activate block generation (proof of work)\n     * Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n     */\n    Napi::Value startGeneration(const Napi::CallbackInfo& info);\n\n    /** Stop any active block generation (proof of work) */\n    Napi::Value stopGeneration(const Napi::CallbackInfo& info);\n\n    /**\n     * Get the address of the account that is used for generation by default. Empty on failiure\n     * Note that this isn't necessarily the actual generation address as there might be an override\n     * See: getGenerationOverrideAddress\n     */\n    Napi::Value getGenerationAddress(const Napi::CallbackInfo& info);\n\n    /**\n     * Get the 'override' address for generation, if one has been set\n     * The override address, when present it used for all block generation in place of the default account address\n     */\n    Napi::Value getGenerationOverrideAddress(const Napi::CallbackInfo& info);\n\n    /** Set an override address to use for block generation in place of the default */\n    Napi::Value setGenerationOverrideAddress(const Napi::CallbackInfo& info);\n\n    Napi::Value getAvailableCores(const Napi::CallbackInfo& info);\n\n    Napi::Value getMinimumMemory(const Napi::CallbackInfo& info);\n\n    Napi::Value getMaximumMemory(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIGENERATIONCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIGenerationListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIGenerationListener.hpp\"\nusing namespace std;\n\nvoid NJSIGenerationListener::onGenerationStarted_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"onGenerationStarted\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onGenerationStarted = calling_function.Call(args);\n        if(result_onGenerationStarted.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIGenerationListener::onGenerationStarted call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIGenerationListener::onGenerationStarted()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIGenerationListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIGenerationListener* pthis = std::get<0>(*((std::tuple<NJSIGenerationListener*>*)req->data));\n        pthis->onGenerationStarted_aimpl__();\n        delete (std::tuple<NJSIGenerationListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIGenerationListener::onGenerationStopped_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"onGenerationStopped\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onGenerationStopped = calling_function.Call(args);\n        if(result_onGenerationStopped.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIGenerationListener::onGenerationStopped call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIGenerationListener::onGenerationStopped()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIGenerationListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIGenerationListener* pthis = std::get<0>(*((std::tuple<NJSIGenerationListener*>*)req->data));\n        pthis->onGenerationStopped_aimpl__();\n        delete (std::tuple<NJSIGenerationListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIGenerationListener::onStatsUpdated_aimpl__(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, hashesPerSecond);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, hashesPerSecondUnit);\n    args.push_back(arg_1);\n    auto arg_2 = Napi::Value::From(env, rollingHashesPerSecond);\n    args.push_back(arg_2);\n    auto arg_3 = Napi::String::New(env, rollingHashesPerSecondUnit);\n    args.push_back(arg_3);\n    auto arg_4 = Napi::Value::From(env, bestHashesPerSecond);\n    args.push_back(arg_4);\n    auto arg_5 = Napi::String::New(env, bestHashesPerSecondUnit);\n    args.push_back(arg_5);\n    auto arg_6 = Napi::Value::From(env, arenaSetupTime);\n    args.push_back(arg_6);\n    Napi::Value calling_function_as_value = Value().Get(\"onStatsUpdated\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onStatsUpdated = calling_function.Call(args);\n        if(result_onStatsUpdated.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIGenerationListener::onStatsUpdated call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIGenerationListener::onStatsUpdated(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>(this, hashesPerSecond, hashesPerSecondUnit, rollingHashesPerSecond, rollingHashesPerSecondUnit, bestHashesPerSecond, bestHashesPerSecondUnit, arenaSetupTime);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIGenerationListener* pthis = std::get<0>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data));\n        pthis->onStatsUpdated_aimpl__(std::get<1>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<2>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<3>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<4>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<5>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<6>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)), std::get<7>(*((std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data)));\n        delete (std::tuple<NJSIGenerationListener*, double, std::string, double, std::string, double, std::string, double>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSIGenerationListener::constructor;\n\nNapi::Object NJSIGenerationListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSIGenerationListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIGenerationListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIGenerationListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIGENERATIONLISTENER_HPP\n#define DJINNI_GENERATED_NJSIGENERATIONLISTENER_HPP\n\n\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_generation_listener.hpp>\n\nusing namespace std;\n\nclass NJSIGenerationListener: public Napi::ObjectWrap<NJSIGenerationListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIGenerationListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIGenerationListener>(info){};\n\n    /** Signal that block generation has started */\n    void onGenerationStarted();\n\n    /** Signal that block generation has stopped */\n    void onGenerationStopped();\n\n    /** Periodically signal latest block generation statistics */\n    void onStatsUpdated(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime);\n\nprivate:\n    /** Signal that block generation has started */\n    void onGenerationStarted(const Napi::CallbackInfo& info);\n    void onGenerationStarted_aimpl__();\n\n    /** Signal that block generation has stopped */\n    void onGenerationStopped(const Napi::CallbackInfo& info);\n    void onGenerationStopped_aimpl__();\n\n    /** Periodically signal latest block generation statistics */\n    void onStatsUpdated(const Napi::CallbackInfo& info);\n    void onStatsUpdated_aimpl__(double hashesPerSecond, const std::string & hashesPerSecondUnit, double rollingHashesPerSecond, const std::string & rollingHashesPerSecondUnit, double bestHashesPerSecond, const std::string & bestHashesPerSecondUnit, double arenaSetupTime);\n\n};\n#endif //DJINNI_GENERATED_NJSIGENERATIONLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSILibraryController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSILibraryController.hpp\"\nusing namespace std;\n\nNapi::Value NJSILibraryController::BuildInfo(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::BuildInfo needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::BuildInfo();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::InitUnityLib(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 8)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::InitUnityLib needs 8 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    auto arg_2 = info[2].ToNumber().Int64Value();\n    auto arg_3 = info[3].ToNumber().Int64Value();\n    auto arg_4 = info[4].ToBoolean().Value();\n    auto arg_5 = info[5].ToBoolean().Value();\n    std::shared_ptr<NJSILibraryListener> arg_6(std::shared_ptr<NJSILibraryListener>{}, NJSILibraryListener::Unwrap(info[6].As<Napi::Object>()));\n\n    std::string arg_7 = info[7].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::InitUnityLib(arg_0,arg_1,arg_2,arg_3,arg_4,arg_5,arg_6,arg_7);\n\n        //Wrap result in node object\n        auto arg_8 = Napi::Value::From(env, result);\n\n        return arg_8;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSILibraryController::InitUnityLibThreaded(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 8)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::InitUnityLibThreaded needs 8 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    auto arg_2 = info[2].ToNumber().Int64Value();\n    auto arg_3 = info[3].ToNumber().Int64Value();\n    auto arg_4 = info[4].ToBoolean().Value();\n    auto arg_5 = info[5].ToBoolean().Value();\n    std::shared_ptr<NJSILibraryListener> arg_6(std::shared_ptr<NJSILibraryListener>{}, NJSILibraryListener::Unwrap(info[6].As<Napi::Object>()));\n\n    std::string arg_7 = info[7].As<Napi::String>();\n    try\n    {\n        ILibraryController::InitUnityLibThreaded(arg_0,arg_1,arg_2,arg_3,arg_4,arg_5,arg_6,arg_7);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSILibraryController::InitWalletFromRecoveryPhrase(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::InitWalletFromRecoveryPhrase needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::InitWalletFromRecoveryPhrase(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::ContinueWalletFromRecoveryPhrase(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ContinueWalletFromRecoveryPhrase needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::ContinueWalletFromRecoveryPhrase(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::InitWalletLinkedFromURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::InitWalletLinkedFromURI needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::InitWalletLinkedFromURI(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::ContinueWalletLinkedFromURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ContinueWalletLinkedFromURI needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::ContinueWalletLinkedFromURI(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::InitWalletFromAndroidLegacyProtoWallet(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 3)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::InitWalletFromAndroidLegacyProtoWallet needs 3 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    std::string arg_2 = info[2].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::InitWalletFromAndroidLegacyProtoWallet(arg_0,arg_1,arg_2);\n\n        //Wrap result in node object\n        auto arg_3 = Napi::Value::From(env, result);\n\n        return arg_3;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::isValidAndroidLegacyProtoWallet(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::isValidAndroidLegacyProtoWallet needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::isValidAndroidLegacyProtoWallet(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, (int)result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsValidLinkURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsValidLinkURI needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::IsValidLinkURI(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::ReplaceWalletLinkedFromURI(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ReplaceWalletLinkedFromURI needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::ReplaceWalletLinkedFromURI(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::EraseWalletSeedsAndAccounts(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::EraseWalletSeedsAndAccounts needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::EraseWalletSeedsAndAccounts();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsValidRecoveryPhrase(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsValidRecoveryPhrase needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::IsValidRecoveryPhrase(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GenerateRecoveryMnemonic(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GenerateRecoveryMnemonic needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GenerateRecoveryMnemonic();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::String::New(env, result.phrase_with_birth_number);\n        arg_0.Set(\"phrase_with_birth_number\", arg_0_1);\n        auto arg_0_2 = Napi::String::New(env, result.phrase);\n        arg_0.Set(\"phrase\", arg_0_2);\n        auto arg_0_3 = Napi::Value::From(env, result.birth_number);\n        arg_0.Set(\"birth_number\", arg_0_3);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GenerateGenesisKeys(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GenerateGenesisKeys needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GenerateGenesisKeys();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::ComposeRecoveryPhrase(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ComposeRecoveryPhrase needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    auto arg_1 = info[1].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = ILibraryController::ComposeRecoveryPhrase(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Object::New(env);\n        auto arg_2_1 = Napi::String::New(env, result.phrase_with_birth_number);\n        arg_2.Set(\"phrase_with_birth_number\", arg_2_1);\n        auto arg_2_2 = Napi::String::New(env, result.phrase);\n        arg_2.Set(\"phrase\", arg_2_2);\n        auto arg_2_3 = Napi::Value::From(env, result.birth_number);\n        arg_2.Set(\"birth_number\", arg_2_3);\n\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSILibraryController::TerminateUnityLib(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::TerminateUnityLib needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        ILibraryController::TerminateUnityLib();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSILibraryController::QRImageFromString(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::QRImageFromString needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    auto arg_1 = info[1].ToNumber().Int32Value();\n\n    try\n    {\n        auto result = ILibraryController::QRImageFromString(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Object::New(env);\n        auto arg_2_1 = Napi::Value::From(env, result.width);\n        arg_2.Set(\"width\", arg_2_1);\n        auto arg_2_2 = Napi::Array::New(env);\n        for(size_t arg_2_2_id = 0; arg_2_2_id < result.pixel_data.size(); arg_2_2_id++)\n        {\n            auto arg_2_2_elem = Napi::Value::From(env, result.pixel_data[arg_2_2_id]);\n            arg_2_2.Set((int)arg_2_2_id,arg_2_2_elem);\n        }\n\n        arg_2.Set(\"pixel_data\", arg_2_2);\n\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GetReceiveAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GetReceiveAddress needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GetReceiveAddress();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GetRecoveryPhrase(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GetRecoveryPhrase needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GetRecoveryPhrase();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::String::New(env, result.phrase_with_birth_number);\n        arg_0.Set(\"phrase_with_birth_number\", arg_0_1);\n        auto arg_0_2 = Napi::String::New(env, result.phrase);\n        arg_0.Set(\"phrase\", arg_0_2);\n        auto arg_0_3 = Napi::Value::From(env, result.birth_number);\n        arg_0.Set(\"birth_number\", arg_0_3);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsMnemonicWallet(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsMnemonicWallet needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::IsMnemonicWallet();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsMnemonicCorrect(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsMnemonicCorrect needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::IsMnemonicCorrect(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GetMnemonicDictionary(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GetMnemonicDictionary needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GetMnemonicDictionary();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::String::New(env, result[arg_0_id]);\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::UnlockWallet(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::UnlockWallet needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    auto arg_1 = info[1].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = ILibraryController::UnlockWallet(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::LockWallet(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::LockWallet needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::LockWallet();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GetWalletLockStatus(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GetWalletLockStatus needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GetWalletLockStatus();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::Value::From(env, result.locked);\n        arg_0.Set(\"locked\", arg_0_1);\n        auto arg_0_2 = Napi::Value::From(env, result.lock_timeout);\n        arg_0.Set(\"lock_timeout\", arg_0_2);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::ChangePassword(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ChangePassword needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::ChangePassword(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSILibraryController::DoRescan(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::DoRescan needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        ILibraryController::DoRescan();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSILibraryController::IsValidRecipient(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsValidRecipient needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    auto field_arg_0_1 = info[0].ToObject().Get(\"scheme\");\n    if (field_arg_0_1.IsEmpty() || field_arg_0_1.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'scheme' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_1 = field_arg_0_1.As<Napi::String>();\n\n    auto field_arg_0_2 = info[0].ToObject().Get(\"path\");\n    if (field_arg_0_2.IsEmpty() || field_arg_0_2.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'path' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_2 = field_arg_0_2.As<Napi::String>();\n\n    auto field_arg_0_3 = info[0].ToObject().Get(\"items\");\n    if (field_arg_0_3.IsEmpty() || field_arg_0_3.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'items' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    unordered_map<std::string, std::string> arg_0_3;\n    auto arg_0_3_prop_names = field_arg_0_3.ToObject().GetPropertyNames();\n    for(uint32_t arg_0_3_id = 0; arg_0_3_id < arg_0_3_prop_names.Length(); arg_0_3_id++)\n    {\n        std::string arg_0_3_key = arg_0_3_prop_names.Get(arg_0_3_id).ToString();\n        std::string arg_0_3_value = arg_0_3_prop_names.Get(arg_0_3_key).ToString();\n        arg_0_3.emplace(arg_0_3_key,arg_0_3_value);\n    }\n\n    UriRecord arg_0(arg_0_1, arg_0_2, arg_0_3);\n\n\n    try\n    {\n        auto result = ILibraryController::IsValidRecipient(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Object::New(env);\n        auto arg_1_1 = Napi::Value::From(env, result.valid);\n        arg_1.Set(\"valid\", arg_1_1);\n        auto arg_1_2 = Napi::String::New(env, result.address);\n        arg_1.Set(\"address\", arg_1_2);\n        auto arg_1_3 = Napi::String::New(env, result.label);\n        arg_1.Set(\"label\", arg_1_3);\n        auto arg_1_4 = Napi::String::New(env, result.desc);\n        arg_1.Set(\"desc\", arg_1_4);\n        auto arg_1_5 = Napi::Value::From(env, result.amount);\n        arg_1.Set(\"amount\", arg_1_5);\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsValidNativeAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsValidNativeAddress needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::IsValidNativeAddress(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::IsValidBitcoinAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::IsValidBitcoinAddress needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::IsValidBitcoinAddress(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::feeForRecipient(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::feeForRecipient needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    auto field_arg_0_1 = info[0].ToObject().Get(\"valid\");\n    if (field_arg_0_1.IsEmpty() || field_arg_0_1.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'valid' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    auto arg_0_1 = field_arg_0_1.ToBoolean().Value();\n\n    auto field_arg_0_2 = info[0].ToObject().Get(\"address\");\n    if (field_arg_0_2.IsEmpty() || field_arg_0_2.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'address' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_2 = field_arg_0_2.As<Napi::String>();\n\n    auto field_arg_0_3 = info[0].ToObject().Get(\"label\");\n    if (field_arg_0_3.IsEmpty() || field_arg_0_3.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'label' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_3 = field_arg_0_3.As<Napi::String>();\n\n    auto field_arg_0_4 = info[0].ToObject().Get(\"desc\");\n    if (field_arg_0_4.IsEmpty() || field_arg_0_4.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'desc' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_4 = field_arg_0_4.As<Napi::String>();\n\n    auto field_arg_0_5 = info[0].ToObject().Get(\"amount\");\n    if (field_arg_0_5.IsEmpty() || field_arg_0_5.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'amount' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    auto arg_0_5 = field_arg_0_5.ToNumber().Int64Value();\n    UriRecipient arg_0(arg_0_1, arg_0_2, arg_0_3, arg_0_4, arg_0_5);\n\n\n    try\n    {\n        auto result = ILibraryController::feeForRecipient(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::performPaymentToRecipient(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::performPaymentToRecipient needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    auto field_arg_0_1 = info[0].ToObject().Get(\"valid\");\n    if (field_arg_0_1.IsEmpty() || field_arg_0_1.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'valid' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    auto arg_0_1 = field_arg_0_1.ToBoolean().Value();\n\n    auto field_arg_0_2 = info[0].ToObject().Get(\"address\");\n    if (field_arg_0_2.IsEmpty() || field_arg_0_2.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'address' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_2 = field_arg_0_2.As<Napi::String>();\n\n    auto field_arg_0_3 = info[0].ToObject().Get(\"label\");\n    if (field_arg_0_3.IsEmpty() || field_arg_0_3.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'label' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_3 = field_arg_0_3.As<Napi::String>();\n\n    auto field_arg_0_4 = info[0].ToObject().Get(\"desc\");\n    if (field_arg_0_4.IsEmpty() || field_arg_0_4.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'desc' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    std::string arg_0_4 = field_arg_0_4.As<Napi::String>();\n\n    auto field_arg_0_5 = info[0].ToObject().Get(\"amount\");\n    if (field_arg_0_5.IsEmpty() || field_arg_0_5.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'amount' field\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    auto arg_0_5 = field_arg_0_5.ToNumber().Int64Value();\n    UriRecipient arg_0(arg_0_1, arg_0_2, arg_0_3, arg_0_4, arg_0_5);\n\n    auto arg_1 = info[1].ToBoolean().Value();\n\n    try\n    {\n        auto result = ILibraryController::performPaymentToRecipient(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, (int)result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getTransaction(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getTransaction needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::getTransaction(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Object::New(env);\n        auto arg_1_1 = Napi::String::New(env, result.txHash);\n        arg_1.Set(\"txHash\", arg_1_1);\n        auto arg_1_2 = Napi::Value::From(env, result.timeStamp);\n        arg_1.Set(\"timeStamp\", arg_1_2);\n        auto arg_1_3 = Napi::Value::From(env, result.amount);\n        arg_1.Set(\"amount\", arg_1_3);\n        auto arg_1_4 = Napi::Value::From(env, result.fee);\n        arg_1.Set(\"fee\", arg_1_4);\n        auto arg_1_5 = Napi::Value::From(env, (int)result.status);\n        arg_1.Set(\"status\", arg_1_5);\n        auto arg_1_6 = Napi::Value::From(env, result.height);\n        arg_1.Set(\"height\", arg_1_6);\n        auto arg_1_7 = Napi::Value::From(env, result.blockTime);\n        arg_1.Set(\"blockTime\", arg_1_7);\n        auto arg_1_8 = Napi::Value::From(env, result.depth);\n        arg_1.Set(\"depth\", arg_1_8);\n        auto arg_1_9 = Napi::Array::New(env);\n        for(size_t arg_1_9_id = 0; arg_1_9_id < result.inputs.size(); arg_1_9_id++)\n        {\n            auto arg_1_9_elem = Napi::Object::New(env);\n            auto arg_1_9_elem_1 = Napi::String::New(env, result.inputs[arg_1_9_id].address);\n            arg_1_9_elem.Set(\"address\", arg_1_9_elem_1);\n            auto arg_1_9_elem_2 = Napi::String::New(env, result.inputs[arg_1_9_id].label);\n            arg_1_9_elem.Set(\"label\", arg_1_9_elem_2);\n            auto arg_1_9_elem_3 = Napi::String::New(env, result.inputs[arg_1_9_id].desc);\n            arg_1_9_elem.Set(\"desc\", arg_1_9_elem_3);\n            auto arg_1_9_elem_4 = Napi::Value::From(env, result.inputs[arg_1_9_id].isMine);\n            arg_1_9_elem.Set(\"isMine\", arg_1_9_elem_4);\n\n            arg_1_9.Set((int)arg_1_9_id,arg_1_9_elem);\n        }\n\n        arg_1.Set(\"inputs\", arg_1_9);\n        auto arg_1_10 = Napi::Array::New(env);\n        for(size_t arg_1_10_id = 0; arg_1_10_id < result.outputs.size(); arg_1_10_id++)\n        {\n            auto arg_1_10_elem = Napi::Object::New(env);\n            auto arg_1_10_elem_1 = Napi::Value::From(env, result.outputs[arg_1_10_id].amount);\n            arg_1_10_elem.Set(\"amount\", arg_1_10_elem_1);\n            auto arg_1_10_elem_2 = Napi::String::New(env, result.outputs[arg_1_10_id].address);\n            arg_1_10_elem.Set(\"address\", arg_1_10_elem_2);\n            auto arg_1_10_elem_3 = Napi::String::New(env, result.outputs[arg_1_10_id].label);\n            arg_1_10_elem.Set(\"label\", arg_1_10_elem_3);\n            auto arg_1_10_elem_4 = Napi::String::New(env, result.outputs[arg_1_10_id].desc);\n            arg_1_10_elem.Set(\"desc\", arg_1_10_elem_4);\n            auto arg_1_10_elem_5 = Napi::Value::From(env, result.outputs[arg_1_10_id].isMine);\n            arg_1_10_elem.Set(\"isMine\", arg_1_10_elem_5);\n\n            arg_1_10.Set((int)arg_1_10_id,arg_1_10_elem);\n        }\n\n        arg_1.Set(\"outputs\", arg_1_10);\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::resendTransaction(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::resendTransaction needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = ILibraryController::resendTransaction(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getAddressBookRecords(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getAddressBookRecords needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getAddressBookRecords();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::String::New(env, result[arg_0_id].address);\n            arg_0_elem.Set(\"address\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::String::New(env, result[arg_0_id].name);\n            arg_0_elem.Set(\"name\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::String::New(env, result[arg_0_id].desc);\n            arg_0_elem.Set(\"desc\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::String::New(env, result[arg_0_id].purpose);\n            arg_0_elem.Set(\"purpose\", arg_0_elem_4);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSILibraryController::addAddressBookRecord(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::addAddressBookRecord needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    auto field_arg_0_1 = info[0].ToObject().Get(\"address\");\n    if (field_arg_0_1.IsEmpty() || field_arg_0_1.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'address' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_1 = field_arg_0_1.As<Napi::String>();\n\n    auto field_arg_0_2 = info[0].ToObject().Get(\"name\");\n    if (field_arg_0_2.IsEmpty() || field_arg_0_2.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'name' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_2 = field_arg_0_2.As<Napi::String>();\n\n    auto field_arg_0_3 = info[0].ToObject().Get(\"desc\");\n    if (field_arg_0_3.IsEmpty() || field_arg_0_3.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'desc' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_3 = field_arg_0_3.As<Napi::String>();\n\n    auto field_arg_0_4 = info[0].ToObject().Get(\"purpose\");\n    if (field_arg_0_4.IsEmpty() || field_arg_0_4.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'purpose' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_4 = field_arg_0_4.As<Napi::String>();\n    AddressRecord arg_0(arg_0_1, arg_0_2, arg_0_3, arg_0_4);\n\n    try\n    {\n        ILibraryController::addAddressBookRecord(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSILibraryController::deleteAddressBookRecord(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::deleteAddressBookRecord needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    auto field_arg_0_1 = info[0].ToObject().Get(\"address\");\n    if (field_arg_0_1.IsEmpty() || field_arg_0_1.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'address' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_1 = field_arg_0_1.As<Napi::String>();\n\n    auto field_arg_0_2 = info[0].ToObject().Get(\"name\");\n    if (field_arg_0_2.IsEmpty() || field_arg_0_2.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'name' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_2 = field_arg_0_2.As<Napi::String>();\n\n    auto field_arg_0_3 = info[0].ToObject().Get(\"desc\");\n    if (field_arg_0_3.IsEmpty() || field_arg_0_3.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'desc' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_3 = field_arg_0_3.As<Napi::String>();\n\n    auto field_arg_0_4 = info[0].ToObject().Get(\"purpose\");\n    if (field_arg_0_4.IsEmpty() || field_arg_0_4.IsUndefined())\n    {\n        Napi::Error::New(env, \"Object is missing 'purpose' field\").ThrowAsJavaScriptException();\n        return;\n    }\n    std::string arg_0_4 = field_arg_0_4.As<Napi::String>();\n    AddressRecord arg_0(arg_0_1, arg_0_2, arg_0_3, arg_0_4);\n\n    try\n    {\n        ILibraryController::deleteAddressBookRecord(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSILibraryController::PersistAndPruneForSPV(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::PersistAndPruneForSPV needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        ILibraryController::PersistAndPruneForSPV();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSILibraryController::ResetUnifiedProgress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::ResetUnifiedProgress needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        ILibraryController::ResetUnifiedProgress();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSILibraryController::getLastSPVBlockInfos(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getLastSPVBlockInfos needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getLastSPVBlockInfos();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::Value::From(env, result[arg_0_id].height);\n            arg_0_elem.Set(\"height\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::Value::From(env, result[arg_0_id].timeStamp);\n            arg_0_elem.Set(\"timeStamp\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::String::New(env, result[arg_0_id].blockHash);\n            arg_0_elem.Set(\"blockHash\", arg_0_elem_3);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getUnifiedProgress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getUnifiedProgress needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getUnifiedProgress();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getMonitoringStats(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getMonitoringStats needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getMonitoringStats();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::Value::From(env, result.partialHeight);\n        arg_0.Set(\"partialHeight\", arg_0_1);\n        auto arg_0_2 = Napi::Value::From(env, result.partialOffset);\n        arg_0.Set(\"partialOffset\", arg_0_2);\n        auto arg_0_3 = Napi::Value::From(env, result.prunedHeight);\n        arg_0.Set(\"prunedHeight\", arg_0_3);\n        auto arg_0_4 = Napi::Value::From(env, result.processedSPVHeight);\n        arg_0.Set(\"processedSPVHeight\", arg_0_4);\n        auto arg_0_5 = Napi::Value::From(env, result.probableHeight);\n        arg_0.Set(\"probableHeight\", arg_0_5);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSILibraryController::RegisterMonitorListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::RegisterMonitorListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSMonitorListener> arg_0(std::shared_ptr<NJSMonitorListener>{}, NJSMonitorListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        ILibraryController::RegisterMonitorListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSILibraryController::UnregisterMonitorListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::UnregisterMonitorListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSMonitorListener> arg_0(std::shared_ptr<NJSMonitorListener>{}, NJSMonitorListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        ILibraryController::UnregisterMonitorListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSILibraryController::getClientInfo(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getClientInfo needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getClientInfo();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        for(auto const& arg_0_elem : result)\n        {\n            auto arg_0_first = Napi::String::New(env, arg_0_elem.first);\n            auto arg_0_second = Napi::String::New(env, arg_0_elem.second);\n            arg_0.Set(arg_0_first, arg_0_second);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getMutationHistory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getMutationHistory needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getMutationHistory();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::Value::From(env, result[arg_0_id].change);\n            arg_0_elem.Set(\"change\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::Value::From(env, result[arg_0_id].timestamp);\n            arg_0_elem.Set(\"timestamp\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::String::New(env, result[arg_0_id].txHash);\n            arg_0_elem.Set(\"txHash\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::String::New(env, result[arg_0_id].recipient_addresses);\n            arg_0_elem.Set(\"recipient_addresses\", arg_0_elem_4);\n            auto arg_0_elem_5 = Napi::Value::From(env, (int)result[arg_0_id].status);\n            arg_0_elem.Set(\"status\", arg_0_elem_5);\n            auto arg_0_elem_6 = Napi::Value::From(env, result[arg_0_id].depth);\n            arg_0_elem.Set(\"depth\", arg_0_elem_6);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::getTransactionHistory(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::getTransactionHistory needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::getTransactionHistory();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::String::New(env, result[arg_0_id].txHash);\n            arg_0_elem.Set(\"txHash\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::Value::From(env, result[arg_0_id].timeStamp);\n            arg_0_elem.Set(\"timeStamp\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::Value::From(env, result[arg_0_id].amount);\n            arg_0_elem.Set(\"amount\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::Value::From(env, result[arg_0_id].fee);\n            arg_0_elem.Set(\"fee\", arg_0_elem_4);\n            auto arg_0_elem_5 = Napi::Value::From(env, (int)result[arg_0_id].status);\n            arg_0_elem.Set(\"status\", arg_0_elem_5);\n            auto arg_0_elem_6 = Napi::Value::From(env, result[arg_0_id].height);\n            arg_0_elem.Set(\"height\", arg_0_elem_6);\n            auto arg_0_elem_7 = Napi::Value::From(env, result[arg_0_id].blockTime);\n            arg_0_elem.Set(\"blockTime\", arg_0_elem_7);\n            auto arg_0_elem_8 = Napi::Value::From(env, result[arg_0_id].depth);\n            arg_0_elem.Set(\"depth\", arg_0_elem_8);\n            auto arg_0_elem_9 = Napi::Array::New(env);\n            for(size_t arg_0_elem_9_id = 0; arg_0_elem_9_id < result[arg_0_id].inputs.size(); arg_0_elem_9_id++)\n            {\n                auto arg_0_elem_9_elem = Napi::Object::New(env);\n                auto arg_0_elem_9_elem_1 = Napi::String::New(env, result[arg_0_id].inputs[arg_0_elem_9_id].address);\n                arg_0_elem_9_elem.Set(\"address\", arg_0_elem_9_elem_1);\n                auto arg_0_elem_9_elem_2 = Napi::String::New(env, result[arg_0_id].inputs[arg_0_elem_9_id].label);\n                arg_0_elem_9_elem.Set(\"label\", arg_0_elem_9_elem_2);\n                auto arg_0_elem_9_elem_3 = Napi::String::New(env, result[arg_0_id].inputs[arg_0_elem_9_id].desc);\n                arg_0_elem_9_elem.Set(\"desc\", arg_0_elem_9_elem_3);\n                auto arg_0_elem_9_elem_4 = Napi::Value::From(env, result[arg_0_id].inputs[arg_0_elem_9_id].isMine);\n                arg_0_elem_9_elem.Set(\"isMine\", arg_0_elem_9_elem_4);\n\n                arg_0_elem_9.Set((int)arg_0_elem_9_id,arg_0_elem_9_elem);\n            }\n\n            arg_0_elem.Set(\"inputs\", arg_0_elem_9);\n            auto arg_0_elem_10 = Napi::Array::New(env);\n            for(size_t arg_0_elem_10_id = 0; arg_0_elem_10_id < result[arg_0_id].outputs.size(); arg_0_elem_10_id++)\n            {\n                auto arg_0_elem_10_elem = Napi::Object::New(env);\n                auto arg_0_elem_10_elem_1 = Napi::Value::From(env, result[arg_0_id].outputs[arg_0_elem_10_id].amount);\n                arg_0_elem_10_elem.Set(\"amount\", arg_0_elem_10_elem_1);\n                auto arg_0_elem_10_elem_2 = Napi::String::New(env, result[arg_0_id].outputs[arg_0_elem_10_id].address);\n                arg_0_elem_10_elem.Set(\"address\", arg_0_elem_10_elem_2);\n                auto arg_0_elem_10_elem_3 = Napi::String::New(env, result[arg_0_id].outputs[arg_0_elem_10_id].label);\n                arg_0_elem_10_elem.Set(\"label\", arg_0_elem_10_elem_3);\n                auto arg_0_elem_10_elem_4 = Napi::String::New(env, result[arg_0_id].outputs[arg_0_elem_10_id].desc);\n                arg_0_elem_10_elem.Set(\"desc\", arg_0_elem_10_elem_4);\n                auto arg_0_elem_10_elem_5 = Napi::Value::From(env, result[arg_0_id].outputs[arg_0_elem_10_id].isMine);\n                arg_0_elem_10_elem.Set(\"isMine\", arg_0_elem_10_elem_5);\n\n                arg_0_elem_10.Set((int)arg_0_elem_10_id,arg_0_elem_10_elem);\n            }\n\n            arg_0_elem.Set(\"outputs\", arg_0_elem_10);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::HaveUnconfirmedFunds(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::HaveUnconfirmedFunds needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::HaveUnconfirmedFunds();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSILibraryController::GetBalance(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSILibraryController::GetBalance needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = ILibraryController::GetBalance();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSILibraryController::constructor;\n\nNapi::Object NJSILibraryController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSILibraryController\", {\n    InstanceMethod(\"BuildInfo\", &NJSILibraryController::BuildInfo),\n    InstanceMethod(\"InitUnityLib\", &NJSILibraryController::InitUnityLib),\n    InstanceMethod(\"InitUnityLibThreaded\", &NJSILibraryController::InitUnityLibThreaded),\n    InstanceMethod(\"InitWalletFromRecoveryPhrase\", &NJSILibraryController::InitWalletFromRecoveryPhrase),\n    InstanceMethod(\"ContinueWalletFromRecoveryPhrase\", &NJSILibraryController::ContinueWalletFromRecoveryPhrase),\n    InstanceMethod(\"InitWalletLinkedFromURI\", &NJSILibraryController::InitWalletLinkedFromURI),\n    InstanceMethod(\"ContinueWalletLinkedFromURI\", &NJSILibraryController::ContinueWalletLinkedFromURI),\n    InstanceMethod(\"InitWalletFromAndroidLegacyProtoWallet\", &NJSILibraryController::InitWalletFromAndroidLegacyProtoWallet),\n    InstanceMethod(\"isValidAndroidLegacyProtoWallet\", &NJSILibraryController::isValidAndroidLegacyProtoWallet),\n    InstanceMethod(\"IsValidLinkURI\", &NJSILibraryController::IsValidLinkURI),\n    InstanceMethod(\"ReplaceWalletLinkedFromURI\", &NJSILibraryController::ReplaceWalletLinkedFromURI),\n    InstanceMethod(\"EraseWalletSeedsAndAccounts\", &NJSILibraryController::EraseWalletSeedsAndAccounts),\n    InstanceMethod(\"IsValidRecoveryPhrase\", &NJSILibraryController::IsValidRecoveryPhrase),\n    InstanceMethod(\"GenerateRecoveryMnemonic\", &NJSILibraryController::GenerateRecoveryMnemonic),\n    InstanceMethod(\"GenerateGenesisKeys\", &NJSILibraryController::GenerateGenesisKeys),\n    InstanceMethod(\"ComposeRecoveryPhrase\", &NJSILibraryController::ComposeRecoveryPhrase),\n    InstanceMethod(\"TerminateUnityLib\", &NJSILibraryController::TerminateUnityLib),\n    InstanceMethod(\"QRImageFromString\", &NJSILibraryController::QRImageFromString),\n    InstanceMethod(\"GetReceiveAddress\", &NJSILibraryController::GetReceiveAddress),\n    InstanceMethod(\"GetRecoveryPhrase\", &NJSILibraryController::GetRecoveryPhrase),\n    InstanceMethod(\"IsMnemonicWallet\", &NJSILibraryController::IsMnemonicWallet),\n    InstanceMethod(\"IsMnemonicCorrect\", &NJSILibraryController::IsMnemonicCorrect),\n    InstanceMethod(\"GetMnemonicDictionary\", &NJSILibraryController::GetMnemonicDictionary),\n    InstanceMethod(\"UnlockWallet\", &NJSILibraryController::UnlockWallet),\n    InstanceMethod(\"LockWallet\", &NJSILibraryController::LockWallet),\n    InstanceMethod(\"GetWalletLockStatus\", &NJSILibraryController::GetWalletLockStatus),\n    InstanceMethod(\"ChangePassword\", &NJSILibraryController::ChangePassword),\n    InstanceMethod(\"DoRescan\", &NJSILibraryController::DoRescan),\n    InstanceMethod(\"IsValidRecipient\", &NJSILibraryController::IsValidRecipient),\n    InstanceMethod(\"IsValidNativeAddress\", &NJSILibraryController::IsValidNativeAddress),\n    InstanceMethod(\"IsValidBitcoinAddress\", &NJSILibraryController::IsValidBitcoinAddress),\n    InstanceMethod(\"feeForRecipient\", &NJSILibraryController::feeForRecipient),\n    InstanceMethod(\"performPaymentToRecipient\", &NJSILibraryController::performPaymentToRecipient),\n    InstanceMethod(\"getTransaction\", &NJSILibraryController::getTransaction),\n    InstanceMethod(\"resendTransaction\", &NJSILibraryController::resendTransaction),\n    InstanceMethod(\"getAddressBookRecords\", &NJSILibraryController::getAddressBookRecords),\n    InstanceMethod(\"addAddressBookRecord\", &NJSILibraryController::addAddressBookRecord),\n    InstanceMethod(\"deleteAddressBookRecord\", &NJSILibraryController::deleteAddressBookRecord),\n    InstanceMethod(\"PersistAndPruneForSPV\", &NJSILibraryController::PersistAndPruneForSPV),\n    InstanceMethod(\"ResetUnifiedProgress\", &NJSILibraryController::ResetUnifiedProgress),\n    InstanceMethod(\"getLastSPVBlockInfos\", &NJSILibraryController::getLastSPVBlockInfos),\n    InstanceMethod(\"getUnifiedProgress\", &NJSILibraryController::getUnifiedProgress),\n    InstanceMethod(\"getMonitoringStats\", &NJSILibraryController::getMonitoringStats),\n    InstanceMethod(\"RegisterMonitorListener\", &NJSILibraryController::RegisterMonitorListener),\n    InstanceMethod(\"UnregisterMonitorListener\", &NJSILibraryController::UnregisterMonitorListener),\n    InstanceMethod(\"getClientInfo\", &NJSILibraryController::getClientInfo),\n    InstanceMethod(\"getMutationHistory\", &NJSILibraryController::getMutationHistory),\n    InstanceMethod(\"getTransactionHistory\", &NJSILibraryController::getTransactionHistory),\n    InstanceMethod(\"HaveUnconfirmedFunds\", &NJSILibraryController::HaveUnconfirmedFunds),\n    InstanceMethod(\"GetBalance\", &NJSILibraryController::GetBalance),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSILibraryController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSILibraryController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSILIBRARYCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSILIBRARYCONTROLLER_HPP\n\n\n#include \"NJSILibraryListener.hpp\"\n#include \"NJSMonitorListener.hpp\"\n#include \"address_record.hpp\"\n#include \"block_info_record.hpp\"\n#include \"input_record.hpp\"\n#include \"legacy_wallet_result.hpp\"\n#include \"mnemonic_record.hpp\"\n#include \"monitor_record.hpp\"\n#include \"mutation_record.hpp\"\n#include \"output_record.hpp\"\n#include \"payment_result_status.hpp\"\n#include \"qr_code_record.hpp\"\n#include \"transaction_record.hpp\"\n#include \"uri_recipient.hpp\"\n#include \"uri_record.hpp\"\n#include \"wallet_lock_status.hpp\"\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_library_controller.hpp>\n\nusing namespace std;\n\nclass NJSILibraryController: public Napi::ObjectWrap<NJSILibraryController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSILibraryController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSILibraryController>(info){};\n\nprivate:\n    /** Get the build information (ie. commit id and status) */\n    Napi::Value BuildInfo(const Napi::CallbackInfo& info);\n\n    /**\n     * Start the library\n     * extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n     * NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n     * If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n     */\n    Napi::Value InitUnityLib(const Napi::CallbackInfo& info);\n\n    /** Threaded implementation of InitUnityLib */\n    void InitUnityLibThreaded(const Napi::CallbackInfo& info);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    Napi::Value InitWalletFromRecoveryPhrase(const Napi::CallbackInfo& info);\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    Napi::Value ContinueWalletFromRecoveryPhrase(const Napi::CallbackInfo& info);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    Napi::Value InitWalletLinkedFromURI(const Napi::CallbackInfo& info);\n\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    Napi::Value ContinueWalletLinkedFromURI(const Napi::CallbackInfo& info);\n\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    Napi::Value InitWalletFromAndroidLegacyProtoWallet(const Napi::CallbackInfo& info);\n\n    /** Check if a file is a valid legacy proto wallet */\n    Napi::Value isValidAndroidLegacyProtoWallet(const Napi::CallbackInfo& info);\n\n    /** Check link URI for validity */\n    Napi::Value IsValidLinkURI(const Napi::CallbackInfo& info);\n\n    /** Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet. */\n    Napi::Value ReplaceWalletLinkedFromURI(const Napi::CallbackInfo& info);\n\n    /**\n     * Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n     * After calling this it will be necessary to create a new linked account or recovery phrase account again.\n     * NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n     */\n    Napi::Value EraseWalletSeedsAndAccounts(const Napi::CallbackInfo& info);\n\n    /**\n     * Check recovery phrase for (syntactic) validity\n     * Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n     */\n    Napi::Value IsValidRecoveryPhrase(const Napi::CallbackInfo& info);\n\n    /** Generate a new recovery mnemonic */\n    Napi::Value GenerateRecoveryMnemonic(const Napi::CallbackInfo& info);\n\n    Napi::Value GenerateGenesisKeys(const Napi::CallbackInfo& info);\n\n    /** Compute recovery phrase with birth number */\n    Napi::Value ComposeRecoveryPhrase(const Napi::CallbackInfo& info);\n\n    /** Stop the library */\n    void TerminateUnityLib(const Napi::CallbackInfo& info);\n\n    /** Generate a QR code for a string, QR code will be as close to width_hint as possible when applying simple scaling. */\n    Napi::Value QRImageFromString(const Napi::CallbackInfo& info);\n\n    /** Get a receive address for the active account */\n    Napi::Value GetReceiveAddress(const Napi::CallbackInfo& info);\n\n    /** Get the recovery phrase for the wallet */\n    Napi::Value GetRecoveryPhrase(const Napi::CallbackInfo& info);\n\n    /** Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet) */\n    Napi::Value IsMnemonicWallet(const Napi::CallbackInfo& info);\n\n    /** Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time) */\n    Napi::Value IsMnemonicCorrect(const Napi::CallbackInfo& info);\n\n    /**\n     * Get the 'dictionary' of valid words that a recovery phrase can be composed of\n     * NB! Not all combinations of these words are valid\n     * Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n     * This function should only be used for input validation/auto-completion\n     */\n    Napi::Value GetMnemonicDictionary(const Napi::CallbackInfo& info);\n\n    /** Unlock wallet; wallet will automatically relock after \"timeout_in_seconds\" */\n    Napi::Value UnlockWallet(const Napi::CallbackInfo& info);\n\n    /** Forcefully lock wallet again */\n    Napi::Value LockWallet(const Napi::CallbackInfo& info);\n\n    Napi::Value GetWalletLockStatus(const Napi::CallbackInfo& info);\n\n    /** Change the wallet password */\n    Napi::Value ChangePassword(const Napi::CallbackInfo& info);\n\n    /** Rescan blockchain for wallet transactions */\n    void DoRescan(const Napi::CallbackInfo& info);\n\n    /** Check if text/address is something we are capable of sending money too */\n    Napi::Value IsValidRecipient(const Napi::CallbackInfo& info);\n\n    /** Check if text/address is a native (to our blockchain) address */\n    Napi::Value IsValidNativeAddress(const Napi::CallbackInfo& info);\n\n    /** Check if text/address is a valid bitcoin address */\n    Napi::Value IsValidBitcoinAddress(const Napi::CallbackInfo& info);\n\n    /** Compute the fee required to send amount to given recipient */\n    Napi::Value feeForRecipient(const Napi::CallbackInfo& info);\n\n    /** Attempt to pay a recipient, will throw on failure with description */\n    Napi::Value performPaymentToRecipient(const Napi::CallbackInfo& info);\n\n    /**\n     * Get the wallet transaction for the hash\n     * Will throw if not found\n     */\n    Napi::Value getTransaction(const Napi::CallbackInfo& info);\n\n    /** resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail */\n    Napi::Value resendTransaction(const Napi::CallbackInfo& info);\n\n    /** Get list of all address book entries */\n    Napi::Value getAddressBookRecords(const Napi::CallbackInfo& info);\n\n    /** Add a record to the address book */\n    void addAddressBookRecord(const Napi::CallbackInfo& info);\n\n    /** Delete a record from the address book */\n    void deleteAddressBookRecord(const Napi::CallbackInfo& info);\n\n    /** Interim persist and prune of state. Use at key moments like app backgrounding. */\n    void PersistAndPruneForSPV(const Napi::CallbackInfo& info);\n\n    /**\n     * Reset progress notification. In cases where there has been no progress for a long time, but the process\n     * is still running the progress can be reset and will represent work to be done from this reset onwards.\n     * For example when the process is in the background on iOS for a long long time (but has not been terminated\n     * by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n     */\n    void ResetUnifiedProgress(const Napi::CallbackInfo& info);\n\n    /** Get info of last blocks (at most 32) in SPV chain */\n    Napi::Value getLastSPVBlockInfos(const Napi::CallbackInfo& info);\n\n    Napi::Value getUnifiedProgress(const Napi::CallbackInfo& info);\n\n    Napi::Value getMonitoringStats(const Napi::CallbackInfo& info);\n\n    void RegisterMonitorListener(const Napi::CallbackInfo& info);\n\n    void UnregisterMonitorListener(const Napi::CallbackInfo& info);\n\n    Napi::Value getClientInfo(const Napi::CallbackInfo& info);\n\n    /**\n     * Get list of wallet mutations\n     *NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n     */\n    Napi::Value getMutationHistory(const Napi::CallbackInfo& info);\n\n    /**\n     * Get list of all transactions wallet has been involved in\n     *NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n     */\n    Napi::Value getTransactionHistory(const Napi::CallbackInfo& info);\n\n    /**\n     * Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n     *NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n     */\n    Napi::Value HaveUnconfirmedFunds(const Napi::CallbackInfo& info);\n\n    /**\n     * Check current wallet balance (including unconfirmed funds)\n     *NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n     */\n    Napi::Value GetBalance(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSILIBRARYCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSILibraryListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSILibraryListener.hpp\"\nusing namespace std;\n\nvoid NJSILibraryListener::notifyUnifiedProgress_aimpl__(float progress)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, progress);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyUnifiedProgress\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyUnifiedProgress = calling_function.Call(args);\n        if(result_notifyUnifiedProgress.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyUnifiedProgress call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyUnifiedProgress(float progress)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, float>(this, progress);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, float>*)req->data));\n        pthis->notifyUnifiedProgress_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, float>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, float>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifySyncDone_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifySyncDone\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifySyncDone = calling_function.Call(args);\n        if(result_notifySyncDone.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifySyncDone call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifySyncDone()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*>*)req->data));\n        pthis->notifySyncDone_aimpl__();\n        delete (std::tuple<NJSILibraryListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyBalanceChange_aimpl__(const BalanceRecord & new_balance)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::Value::From(env, new_balance.availableIncludingLocked);\n    arg_0.Set(\"availableIncludingLocked\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, new_balance.availableExcludingLocked);\n    arg_0.Set(\"availableExcludingLocked\", arg_0_2);\n    auto arg_0_3 = Napi::Value::From(env, new_balance.availableLocked);\n    arg_0.Set(\"availableLocked\", arg_0_3);\n    auto arg_0_4 = Napi::Value::From(env, new_balance.unconfirmedIncludingLocked);\n    arg_0.Set(\"unconfirmedIncludingLocked\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, new_balance.unconfirmedExcludingLocked);\n    arg_0.Set(\"unconfirmedExcludingLocked\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, new_balance.unconfirmedLocked);\n    arg_0.Set(\"unconfirmedLocked\", arg_0_6);\n    auto arg_0_7 = Napi::Value::From(env, new_balance.immatureIncludingLocked);\n    arg_0.Set(\"immatureIncludingLocked\", arg_0_7);\n    auto arg_0_8 = Napi::Value::From(env, new_balance.immatureExcludingLocked);\n    arg_0.Set(\"immatureExcludingLocked\", arg_0_8);\n    auto arg_0_9 = Napi::Value::From(env, new_balance.immatureLocked);\n    arg_0.Set(\"immatureLocked\", arg_0_9);\n    auto arg_0_10 = Napi::Value::From(env, new_balance.totalLocked);\n    arg_0.Set(\"totalLocked\", arg_0_10);\n\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyBalanceChange\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyBalanceChange = calling_function.Call(args);\n        if(result_notifyBalanceChange.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyBalanceChange call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyBalanceChange(const BalanceRecord & new_balance)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, BalanceRecord>(this, new_balance);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, BalanceRecord>*)req->data));\n        pthis->notifyBalanceChange_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, BalanceRecord>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, BalanceRecord>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyNewMutation_aimpl__(const MutationRecord & mutation, bool self_committed)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::Value::From(env, mutation.change);\n    arg_0.Set(\"change\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, mutation.timestamp);\n    arg_0.Set(\"timestamp\", arg_0_2);\n    auto arg_0_3 = Napi::String::New(env, mutation.txHash);\n    arg_0.Set(\"txHash\", arg_0_3);\n    auto arg_0_4 = Napi::String::New(env, mutation.recipient_addresses);\n    arg_0.Set(\"recipient_addresses\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, (int)mutation.status);\n    arg_0.Set(\"status\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, mutation.depth);\n    arg_0.Set(\"depth\", arg_0_6);\n\n    args.push_back(arg_0);\n    auto arg_1 = Napi::Value::From(env, self_committed);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyNewMutation\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyNewMutation = calling_function.Call(args);\n        if(result_notifyNewMutation.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyNewMutation call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyNewMutation(const MutationRecord & mutation, bool self_committed)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, MutationRecord, bool>(this, mutation, self_committed);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, MutationRecord, bool>*)req->data));\n        pthis->notifyNewMutation_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, MutationRecord, bool>*)req->data)), std::get<2>(*((std::tuple<NJSILibraryListener*, MutationRecord, bool>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, MutationRecord, bool>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyUpdatedTransaction_aimpl__(const TransactionRecord & transaction)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::String::New(env, transaction.txHash);\n    arg_0.Set(\"txHash\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, transaction.timeStamp);\n    arg_0.Set(\"timeStamp\", arg_0_2);\n    auto arg_0_3 = Napi::Value::From(env, transaction.amount);\n    arg_0.Set(\"amount\", arg_0_3);\n    auto arg_0_4 = Napi::Value::From(env, transaction.fee);\n    arg_0.Set(\"fee\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, (int)transaction.status);\n    arg_0.Set(\"status\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, transaction.height);\n    arg_0.Set(\"height\", arg_0_6);\n    auto arg_0_7 = Napi::Value::From(env, transaction.blockTime);\n    arg_0.Set(\"blockTime\", arg_0_7);\n    auto arg_0_8 = Napi::Value::From(env, transaction.depth);\n    arg_0.Set(\"depth\", arg_0_8);\n    auto arg_0_9 = Napi::Array::New(env);\n    for(size_t arg_0_9_id = 0; arg_0_9_id < transaction.inputs.size(); arg_0_9_id++)\n    {\n        auto arg_0_9_elem = Napi::Object::New(env);\n        auto arg_0_9_elem_1 = Napi::String::New(env, transaction.inputs[arg_0_9_id].address);\n        arg_0_9_elem.Set(\"address\", arg_0_9_elem_1);\n        auto arg_0_9_elem_2 = Napi::String::New(env, transaction.inputs[arg_0_9_id].label);\n        arg_0_9_elem.Set(\"label\", arg_0_9_elem_2);\n        auto arg_0_9_elem_3 = Napi::String::New(env, transaction.inputs[arg_0_9_id].desc);\n        arg_0_9_elem.Set(\"desc\", arg_0_9_elem_3);\n        auto arg_0_9_elem_4 = Napi::Value::From(env, transaction.inputs[arg_0_9_id].isMine);\n        arg_0_9_elem.Set(\"isMine\", arg_0_9_elem_4);\n\n        arg_0_9.Set((int)arg_0_9_id,arg_0_9_elem);\n    }\n\n    arg_0.Set(\"inputs\", arg_0_9);\n    auto arg_0_10 = Napi::Array::New(env);\n    for(size_t arg_0_10_id = 0; arg_0_10_id < transaction.outputs.size(); arg_0_10_id++)\n    {\n        auto arg_0_10_elem = Napi::Object::New(env);\n        auto arg_0_10_elem_1 = Napi::Value::From(env, transaction.outputs[arg_0_10_id].amount);\n        arg_0_10_elem.Set(\"amount\", arg_0_10_elem_1);\n        auto arg_0_10_elem_2 = Napi::String::New(env, transaction.outputs[arg_0_10_id].address);\n        arg_0_10_elem.Set(\"address\", arg_0_10_elem_2);\n        auto arg_0_10_elem_3 = Napi::String::New(env, transaction.outputs[arg_0_10_id].label);\n        arg_0_10_elem.Set(\"label\", arg_0_10_elem_3);\n        auto arg_0_10_elem_4 = Napi::String::New(env, transaction.outputs[arg_0_10_id].desc);\n        arg_0_10_elem.Set(\"desc\", arg_0_10_elem_4);\n        auto arg_0_10_elem_5 = Napi::Value::From(env, transaction.outputs[arg_0_10_id].isMine);\n        arg_0_10_elem.Set(\"isMine\", arg_0_10_elem_5);\n\n        arg_0_10.Set((int)arg_0_10_id,arg_0_10_elem);\n    }\n\n    arg_0.Set(\"outputs\", arg_0_10);\n\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyUpdatedTransaction\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyUpdatedTransaction = calling_function.Call(args);\n        if(result_notifyUpdatedTransaction.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyUpdatedTransaction call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyUpdatedTransaction(const TransactionRecord & transaction)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, TransactionRecord>(this, transaction);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, TransactionRecord>*)req->data));\n        pthis->notifyUpdatedTransaction_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, TransactionRecord>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, TransactionRecord>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyInitWithExistingWallet_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyInitWithExistingWallet\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyInitWithExistingWallet = calling_function.Call(args);\n        if(result_notifyInitWithExistingWallet.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyInitWithExistingWallet call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyInitWithExistingWallet()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*>*)req->data));\n        pthis->notifyInitWithExistingWallet_aimpl__();\n        delete (std::tuple<NJSILibraryListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyInitWithoutExistingWallet_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyInitWithoutExistingWallet\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyInitWithoutExistingWallet = calling_function.Call(args);\n        if(result_notifyInitWithoutExistingWallet.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyInitWithoutExistingWallet call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyInitWithoutExistingWallet()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*>*)req->data));\n        pthis->notifyInitWithoutExistingWallet_aimpl__();\n        delete (std::tuple<NJSILibraryListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyShutdown_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyShutdown\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyShutdown = calling_function.Call(args);\n        if(result_notifyShutdown.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyShutdown call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyShutdown()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*>*)req->data));\n        pthis->notifyShutdown_aimpl__();\n        delete (std::tuple<NJSILibraryListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyCoreReady_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyCoreReady\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyCoreReady = calling_function.Call(args);\n        if(result_notifyCoreReady.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyCoreReady call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyCoreReady()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*>*)req->data));\n        pthis->notifyCoreReady_aimpl__();\n        delete (std::tuple<NJSILibraryListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::notifyError_aimpl__(const std::string & error)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, error);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyError\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyError = calling_function.Call(args);\n        if(result_notifyError.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::notifyError call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::notifyError(const std::string & error)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, std::string>(this, error);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, std::string>*)req->data));\n        pthis->notifyError_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSILibraryListener::logPrint_aimpl__(const std::string & str)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, str);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"logPrint\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_logPrint = calling_function.Call(args);\n        if(result_logPrint.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSILibraryListener::logPrint call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSILibraryListener::logPrint(const std::string & str)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSILibraryListener*, std::string>(this, str);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSILibraryListener* pthis = std::get<0>(*((std::tuple<NJSILibraryListener*, std::string>*)req->data));\n        pthis->logPrint_aimpl__(std::get<1>(*((std::tuple<NJSILibraryListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSILibraryListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSILibraryListener::constructor;\n\nNapi::Object NJSILibraryListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSILibraryListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSILibraryListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSILibraryListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSILIBRARYLISTENER_HPP\n#define DJINNI_GENERATED_NJSILIBRARYLISTENER_HPP\n\n\n#include \"balance_record.hpp\"\n#include \"input_record.hpp\"\n#include \"mutation_record.hpp\"\n#include \"output_record.hpp\"\n#include \"transaction_record.hpp\"\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_library_listener.hpp>\n\nusing namespace std;\n\nclass NJSILibraryListener: public Napi::ObjectWrap<NJSILibraryListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSILibraryListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSILibraryListener>(info){};\n\n    /**\n     * Fraction of work done since session start or last progress reset [0..1]\n     * Unified progress combines connection state, header and block sync\n     */\n    void notifyUnifiedProgress(float progress);\n\n    /** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n    void notifySyncDone();\n\n    void notifyBalanceChange(const BalanceRecord & new_balance);\n\n    /**\n     * Notification of new mutations\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyNewMutation(const MutationRecord & mutation, bool self_committed);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyUpdatedTransaction(const TransactionRecord & transaction);\n\n    void notifyInitWithExistingWallet();\n\n    void notifyInitWithoutExistingWallet();\n\n    void notifyShutdown();\n\n    void notifyCoreReady();\n\n    void notifyError(const std::string & error);\n\n    void logPrint(const std::string & str);\n\nprivate:\n    /**\n     * Fraction of work done since session start or last progress reset [0..1]\n     * Unified progress combines connection state, header and block sync\n     */\n    void notifyUnifiedProgress(const Napi::CallbackInfo& info);\n    void notifyUnifiedProgress_aimpl__(float progress);\n\n    /** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n    void notifySyncDone(const Napi::CallbackInfo& info);\n    void notifySyncDone_aimpl__();\n\n    void notifyBalanceChange(const Napi::CallbackInfo& info);\n    void notifyBalanceChange_aimpl__(const BalanceRecord & new_balance);\n\n    /**\n     * Notification of new mutations\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyNewMutation(const Napi::CallbackInfo& info);\n    void notifyNewMutation_aimpl__(const MutationRecord & mutation, bool self_committed);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyUpdatedTransaction(const Napi::CallbackInfo& info);\n    void notifyUpdatedTransaction_aimpl__(const TransactionRecord & transaction);\n\n    void notifyInitWithExistingWallet(const Napi::CallbackInfo& info);\n    void notifyInitWithExistingWallet_aimpl__();\n\n    void notifyInitWithoutExistingWallet(const Napi::CallbackInfo& info);\n    void notifyInitWithoutExistingWallet_aimpl__();\n\n    void notifyShutdown(const Napi::CallbackInfo& info);\n    void notifyShutdown_aimpl__();\n\n    void notifyCoreReady(const Napi::CallbackInfo& info);\n    void notifyCoreReady_aimpl__();\n\n    void notifyError(const Napi::CallbackInfo& info);\n    void notifyError_aimpl__(const std::string & error);\n\n    void logPrint(const Napi::CallbackInfo& info);\n    void logPrint_aimpl__(const std::string & str);\n\n};\n#endif //DJINNI_GENERATED_NJSILIBRARYLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIP2pNetworkController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIP2pNetworkController.hpp\"\nusing namespace std;\n\nvoid NJSIP2pNetworkController::setListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::setListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSIP2pNetworkListener> arg_0(std::shared_ptr<NJSIP2pNetworkListener>{}, NJSIP2pNetworkListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        IP2pNetworkController::setListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSIP2pNetworkController::disableNetwork(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::disableNetwork needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        IP2pNetworkController::disableNetwork();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nvoid NJSIP2pNetworkController::enableNetwork(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::enableNetwork needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    try\n    {\n        IP2pNetworkController::enableNetwork();\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIP2pNetworkController::getPeerInfo(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::getPeerInfo needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IP2pNetworkController::getPeerInfo();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::Value::From(env, result[arg_0_id].id);\n            arg_0_elem.Set(\"id\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::String::New(env, result[arg_0_id].ip);\n            arg_0_elem.Set(\"ip\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::String::New(env, result[arg_0_id].hostname);\n            arg_0_elem.Set(\"hostname\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::String::New(env, result[arg_0_id].addrLocal);\n            arg_0_elem.Set(\"addrLocal\", arg_0_elem_4);\n            auto arg_0_elem_5 = Napi::String::New(env, result[arg_0_id].addrBind);\n            arg_0_elem.Set(\"addrBind\", arg_0_elem_5);\n            auto arg_0_elem_6 = Napi::Value::From(env, result[arg_0_id].start_height);\n            arg_0_elem.Set(\"start_height\", arg_0_elem_6);\n            auto arg_0_elem_7 = Napi::Value::From(env, result[arg_0_id].synced_height);\n            arg_0_elem.Set(\"synced_height\", arg_0_elem_7);\n            auto arg_0_elem_8 = Napi::Value::From(env, result[arg_0_id].common_height);\n            arg_0_elem.Set(\"common_height\", arg_0_elem_8);\n            auto arg_0_elem_9 = Napi::Value::From(env, result[arg_0_id].time_connected);\n            arg_0_elem.Set(\"time_connected\", arg_0_elem_9);\n            auto arg_0_elem_10 = Napi::Value::From(env, result[arg_0_id].time_offset);\n            arg_0_elem.Set(\"time_offset\", arg_0_elem_10);\n            auto arg_0_elem_11 = Napi::Value::From(env, result[arg_0_id].latency);\n            arg_0_elem.Set(\"latency\", arg_0_elem_11);\n            auto arg_0_elem_12 = Napi::Value::From(env, result[arg_0_id].last_send);\n            arg_0_elem.Set(\"last_send\", arg_0_elem_12);\n            auto arg_0_elem_13 = Napi::Value::From(env, result[arg_0_id].last_receive);\n            arg_0_elem.Set(\"last_receive\", arg_0_elem_13);\n            auto arg_0_elem_14 = Napi::Value::From(env, result[arg_0_id].send_bytes);\n            arg_0_elem.Set(\"send_bytes\", arg_0_elem_14);\n            auto arg_0_elem_15 = Napi::Value::From(env, result[arg_0_id].receive_bytes);\n            arg_0_elem.Set(\"receive_bytes\", arg_0_elem_15);\n            auto arg_0_elem_16 = Napi::String::New(env, result[arg_0_id].userAgent);\n            arg_0_elem.Set(\"userAgent\", arg_0_elem_16);\n            auto arg_0_elem_17 = Napi::Value::From(env, result[arg_0_id].protocol);\n            arg_0_elem.Set(\"protocol\", arg_0_elem_17);\n            auto arg_0_elem_18 = Napi::Value::From(env, result[arg_0_id].services);\n            arg_0_elem.Set(\"services\", arg_0_elem_18);\n            auto arg_0_elem_19 = Napi::Value::From(env, result[arg_0_id].inbound);\n            arg_0_elem.Set(\"inbound\", arg_0_elem_19);\n            auto arg_0_elem_20 = Napi::Value::From(env, result[arg_0_id].whitelisted);\n            arg_0_elem.Set(\"whitelisted\", arg_0_elem_20);\n            auto arg_0_elem_21 = Napi::Value::From(env, result[arg_0_id].addnode);\n            arg_0_elem.Set(\"addnode\", arg_0_elem_21);\n            auto arg_0_elem_22 = Napi::Value::From(env, result[arg_0_id].relay_txes);\n            arg_0_elem.Set(\"relay_txes\", arg_0_elem_22);\n            auto arg_0_elem_23 = Napi::Value::From(env, result[arg_0_id].banscore);\n            arg_0_elem.Set(\"banscore\", arg_0_elem_23);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIP2pNetworkController::listBannedPeers(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::listBannedPeers needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IP2pNetworkController::listBannedPeers();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::Object::New(env);\n            auto arg_0_elem_1 = Napi::String::New(env, result[arg_0_id].address);\n            arg_0_elem.Set(\"address\", arg_0_elem_1);\n            auto arg_0_elem_2 = Napi::Value::From(env, result[arg_0_id].banned_until);\n            arg_0_elem.Set(\"banned_until\", arg_0_elem_2);\n            auto arg_0_elem_3 = Napi::Value::From(env, result[arg_0_id].banned_from);\n            arg_0_elem.Set(\"banned_from\", arg_0_elem_3);\n            auto arg_0_elem_4 = Napi::String::New(env, result[arg_0_id].reason);\n            arg_0_elem.Set(\"reason\", arg_0_elem_4);\n\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIP2pNetworkController::banPeer(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::banPeer needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    auto arg_1 = info[1].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = IP2pNetworkController::banPeer(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Value::From(env, result);\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIP2pNetworkController::unbanPeer(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::unbanPeer needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IP2pNetworkController::unbanPeer(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIP2pNetworkController::disconnectPeer(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::disconnectPeer needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    auto arg_0 = info[0].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = IP2pNetworkController::disconnectPeer(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIP2pNetworkController::ClearBanned(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIP2pNetworkController::ClearBanned needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IP2pNetworkController::ClearBanned();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIP2pNetworkController::constructor;\n\nNapi::Object NJSIP2pNetworkController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIP2pNetworkController\", {\n    InstanceMethod(\"setListener\", &NJSIP2pNetworkController::setListener),\n    InstanceMethod(\"disableNetwork\", &NJSIP2pNetworkController::disableNetwork),\n    InstanceMethod(\"enableNetwork\", &NJSIP2pNetworkController::enableNetwork),\n    InstanceMethod(\"getPeerInfo\", &NJSIP2pNetworkController::getPeerInfo),\n    InstanceMethod(\"listBannedPeers\", &NJSIP2pNetworkController::listBannedPeers),\n    InstanceMethod(\"banPeer\", &NJSIP2pNetworkController::banPeer),\n    InstanceMethod(\"unbanPeer\", &NJSIP2pNetworkController::unbanPeer),\n    InstanceMethod(\"disconnectPeer\", &NJSIP2pNetworkController::disconnectPeer),\n    InstanceMethod(\"ClearBanned\", &NJSIP2pNetworkController::ClearBanned),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIP2pNetworkController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIP2pNetworkController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIP2PNETWORKCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIP2PNETWORKCONTROLLER_HPP\n\n\n#include \"NJSIP2pNetworkListener.hpp\"\n#include \"banned_peer_record.hpp\"\n#include \"peer_record.hpp\"\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_p2p_network_controller.hpp>\n\nusing namespace std;\n\nclass NJSIP2pNetworkController: public Napi::ObjectWrap<NJSIP2pNetworkController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIP2pNetworkController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIP2pNetworkController>(info){};\n\nprivate:\n    /** Register listener to be notified of networking events */\n    void setListener(const Napi::CallbackInfo& info);\n\n    /** Turn p2p networking off */\n    void disableNetwork(const Napi::CallbackInfo& info);\n\n    /** Turn p2p networking on */\n    void enableNetwork(const Napi::CallbackInfo& info);\n\n    /** Get connected peer info */\n    Napi::Value getPeerInfo(const Napi::CallbackInfo& info);\n\n    /** Get all banned peers */\n    Napi::Value listBannedPeers(const Napi::CallbackInfo& info);\n\n    Napi::Value banPeer(const Napi::CallbackInfo& info);\n\n    /** Unban a single peer */\n    Napi::Value unbanPeer(const Napi::CallbackInfo& info);\n\n    /** Disconnect a specific peer */\n    Napi::Value disconnectPeer(const Napi::CallbackInfo& info);\n\n    /** Clear all banned peers */\n    Napi::Value ClearBanned(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIP2PNETWORKCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIP2pNetworkListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIP2pNetworkListener.hpp\"\nusing namespace std;\n\nvoid NJSIP2pNetworkListener::onNetworkEnabled_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"onNetworkEnabled\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onNetworkEnabled = calling_function.Call(args);\n        if(result_onNetworkEnabled.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIP2pNetworkListener::onNetworkEnabled call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIP2pNetworkListener::onNetworkEnabled()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIP2pNetworkListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIP2pNetworkListener* pthis = std::get<0>(*((std::tuple<NJSIP2pNetworkListener*>*)req->data));\n        pthis->onNetworkEnabled_aimpl__();\n        delete (std::tuple<NJSIP2pNetworkListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIP2pNetworkListener::onNetworkDisabled_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"onNetworkDisabled\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onNetworkDisabled = calling_function.Call(args);\n        if(result_onNetworkDisabled.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIP2pNetworkListener::onNetworkDisabled call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIP2pNetworkListener::onNetworkDisabled()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIP2pNetworkListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIP2pNetworkListener* pthis = std::get<0>(*((std::tuple<NJSIP2pNetworkListener*>*)req->data));\n        pthis->onNetworkDisabled_aimpl__();\n        delete (std::tuple<NJSIP2pNetworkListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIP2pNetworkListener::onConnectionCountChanged_aimpl__(int32_t numConnections)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, numConnections);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onConnectionCountChanged\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onConnectionCountChanged = calling_function.Call(args);\n        if(result_onConnectionCountChanged.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIP2pNetworkListener::onConnectionCountChanged call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIP2pNetworkListener::onConnectionCountChanged(int32_t numConnections)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIP2pNetworkListener*, int32_t>(this, numConnections);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIP2pNetworkListener* pthis = std::get<0>(*((std::tuple<NJSIP2pNetworkListener*, int32_t>*)req->data));\n        pthis->onConnectionCountChanged_aimpl__(std::get<1>(*((std::tuple<NJSIP2pNetworkListener*, int32_t>*)req->data)));\n        delete (std::tuple<NJSIP2pNetworkListener*, int32_t>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIP2pNetworkListener::onBytesChanged_aimpl__(int32_t totalRecv, int32_t totalSent)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, totalRecv);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::Value::From(env, totalSent);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onBytesChanged\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onBytesChanged = calling_function.Call(args);\n        if(result_onBytesChanged.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIP2pNetworkListener::onBytesChanged call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIP2pNetworkListener::onBytesChanged(int32_t totalRecv, int32_t totalSent)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIP2pNetworkListener*, int32_t, int32_t>(this, totalRecv, totalSent);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIP2pNetworkListener* pthis = std::get<0>(*((std::tuple<NJSIP2pNetworkListener*, int32_t, int32_t>*)req->data));\n        pthis->onBytesChanged_aimpl__(std::get<1>(*((std::tuple<NJSIP2pNetworkListener*, int32_t, int32_t>*)req->data)), std::get<2>(*((std::tuple<NJSIP2pNetworkListener*, int32_t, int32_t>*)req->data)));\n        delete (std::tuple<NJSIP2pNetworkListener*, int32_t, int32_t>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSIP2pNetworkListener::constructor;\n\nNapi::Object NJSIP2pNetworkListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSIP2pNetworkListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIP2pNetworkListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIP2pNetworkListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIP2PNETWORKLISTENER_HPP\n#define DJINNI_GENERATED_NJSIP2PNETWORKLISTENER_HPP\n\n\n#include <cstdint>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_p2p_network_listener.hpp>\n\nusing namespace std;\n\nclass NJSIP2pNetworkListener: public Napi::ObjectWrap<NJSIP2pNetworkListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIP2pNetworkListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIP2pNetworkListener>(info){};\n\n    /** Notify that p2p networking has been enabled */\n    void onNetworkEnabled();\n\n    /** Notify that p2p networking has been disabled */\n    void onNetworkDisabled();\n\n    /** Notify that number of peers has changed */\n    void onConnectionCountChanged(int32_t numConnections);\n\n    /** Notify that amount of data sent/received has changed */\n    void onBytesChanged(int32_t totalRecv, int32_t totalSent);\n\nprivate:\n    /** Notify that p2p networking has been enabled */\n    void onNetworkEnabled(const Napi::CallbackInfo& info);\n    void onNetworkEnabled_aimpl__();\n\n    /** Notify that p2p networking has been disabled */\n    void onNetworkDisabled(const Napi::CallbackInfo& info);\n    void onNetworkDisabled_aimpl__();\n\n    /** Notify that number of peers has changed */\n    void onConnectionCountChanged(const Napi::CallbackInfo& info);\n    void onConnectionCountChanged_aimpl__(int32_t numConnections);\n\n    /** Notify that amount of data sent/received has changed */\n    void onBytesChanged(const Napi::CallbackInfo& info);\n    void onBytesChanged_aimpl__(int32_t totalRecv, int32_t totalSent);\n\n};\n#endif //DJINNI_GENERATED_NJSIP2PNETWORKLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIRpcController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIRpcController.hpp\"\nusing namespace std;\n\nvoid NJSIRpcController::execute(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIRpcController::execute needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::shared_ptr<NJSIRpcListener> arg_1(std::shared_ptr<NJSIRpcListener>{}, NJSIRpcListener::Unwrap(info[1].As<Napi::Object>()));\n\n    try\n    {\n        IRpcController::execute(arg_0,arg_1);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIRpcController::getAutocompleteList(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIRpcController::getAutocompleteList needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IRpcController::getAutocompleteList();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Array::New(env);\n        for(size_t arg_0_id = 0; arg_0_id < result.size(); arg_0_id++)\n        {\n            auto arg_0_elem = Napi::String::New(env, result[arg_0_id]);\n            arg_0.Set((int)arg_0_id,arg_0_elem);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIRpcController::constructor;\n\nNapi::Object NJSIRpcController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIRpcController\", {\n    InstanceMethod(\"execute\", &NJSIRpcController::execute),\n    InstanceMethod(\"getAutocompleteList\", &NJSIRpcController::getAutocompleteList),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIRpcController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIRpcController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIRPCCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIRPCCONTROLLER_HPP\n\n\n#include \"NJSIRpcListener.hpp\"\n#include <memory>\n#include <string>\n#include <vector>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_rpc_controller.hpp>\n\nusing namespace std;\n\nclass NJSIRpcController: public Napi::ObjectWrap<NJSIRpcController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIRpcController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIRpcController>(info){};\n\nprivate:\n    void execute(const Napi::CallbackInfo& info);\n\n    Napi::Value getAutocompleteList(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIRPCCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIRpcListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIRpcListener.hpp\"\nusing namespace std;\n\nvoid NJSIRpcListener::onFilteredCommand_aimpl__(const std::string & filteredCommand)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, filteredCommand);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onFilteredCommand\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onFilteredCommand = calling_function.Call(args);\n        if(result_onFilteredCommand.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIRpcListener::onFilteredCommand call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIRpcListener::onFilteredCommand(const std::string & filteredCommand)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIRpcListener*, std::string>(this, filteredCommand);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIRpcListener* pthis = std::get<0>(*((std::tuple<NJSIRpcListener*, std::string>*)req->data));\n        pthis->onFilteredCommand_aimpl__(std::get<1>(*((std::tuple<NJSIRpcListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSIRpcListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIRpcListener::onSuccess_aimpl__(const std::string & filteredCommand, const std::string & result)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, filteredCommand);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, result);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onSuccess\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onSuccess = calling_function.Call(args);\n        if(result_onSuccess.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIRpcListener::onSuccess call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIRpcListener::onSuccess(const std::string & filteredCommand, const std::string & result)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIRpcListener*, std::string, std::string>(this, filteredCommand, result);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIRpcListener* pthis = std::get<0>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data));\n        pthis->onSuccess_aimpl__(std::get<1>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data)), std::get<2>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data)));\n        delete (std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIRpcListener::onError_aimpl__(const std::string & filteredCommand, const std::string & errorMessage)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, filteredCommand);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, errorMessage);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"onError\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onError = calling_function.Call(args);\n        if(result_onError.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIRpcListener::onError call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIRpcListener::onError(const std::string & filteredCommand, const std::string & errorMessage)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIRpcListener*, std::string, std::string>(this, filteredCommand, errorMessage);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIRpcListener* pthis = std::get<0>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data));\n        pthis->onError_aimpl__(std::get<1>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data)), std::get<2>(*((std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data)));\n        delete (std::tuple<NJSIRpcListener*, std::string, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSIRpcListener::constructor;\n\nNapi::Object NJSIRpcListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSIRpcListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIRpcListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIRpcListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIRPCLISTENER_HPP\n#define DJINNI_GENERATED_NJSIRPCLISTENER_HPP\n\n\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_rpc_listener.hpp>\n\nusing namespace std;\n\nclass NJSIRpcListener: public Napi::ObjectWrap<NJSIRpcListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIRpcListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIRpcListener>(info){};\n\n    /**\n     * Returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onFilteredCommand(const std::string & filteredCommand);\n\n    /**\n     * Returns the result and a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onSuccess(const std::string & filteredCommand, const std::string & result);\n\n    /**\n     * Returns an error message which might be a plain string or JSON depending on the type of error\n     * Also returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onError(const std::string & filteredCommand, const std::string & errorMessage);\n\nprivate:\n    /**\n     * Returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onFilteredCommand(const Napi::CallbackInfo& info);\n    void onFilteredCommand_aimpl__(const std::string & filteredCommand);\n\n    /**\n     * Returns the result and a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onSuccess(const Napi::CallbackInfo& info);\n    void onSuccess_aimpl__(const std::string & filteredCommand, const std::string & result);\n\n    /**\n     * Returns an error message which might be a plain string or JSON depending on the type of error\n     * Also returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    void onError(const Napi::CallbackInfo& info);\n    void onError_aimpl__(const std::string & filteredCommand, const std::string & errorMessage);\n\n};\n#endif //DJINNI_GENERATED_NJSIRPCLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWalletController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIWalletController.hpp\"\nusing namespace std;\n\nvoid NJSIWalletController::setListener(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::setListener needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::shared_ptr<NJSIWalletListener> arg_0(std::shared_ptr<NJSIWalletListener>{}, NJSIWalletListener::Unwrap(info[0].As<Napi::Object>()));\n\n    try\n    {\n        IWalletController::setListener(arg_0);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIWalletController::HaveUnconfirmedFunds(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::HaveUnconfirmedFunds needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IWalletController::HaveUnconfirmedFunds();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWalletController::GetBalanceSimple(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::GetBalanceSimple needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IWalletController::GetBalanceSimple();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Value::From(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWalletController::GetBalance(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::GetBalance needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IWalletController::GetBalance();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        auto arg_0_1 = Napi::Value::From(env, result.availableIncludingLocked);\n        arg_0.Set(\"availableIncludingLocked\", arg_0_1);\n        auto arg_0_2 = Napi::Value::From(env, result.availableExcludingLocked);\n        arg_0.Set(\"availableExcludingLocked\", arg_0_2);\n        auto arg_0_3 = Napi::Value::From(env, result.availableLocked);\n        arg_0.Set(\"availableLocked\", arg_0_3);\n        auto arg_0_4 = Napi::Value::From(env, result.unconfirmedIncludingLocked);\n        arg_0.Set(\"unconfirmedIncludingLocked\", arg_0_4);\n        auto arg_0_5 = Napi::Value::From(env, result.unconfirmedExcludingLocked);\n        arg_0.Set(\"unconfirmedExcludingLocked\", arg_0_5);\n        auto arg_0_6 = Napi::Value::From(env, result.unconfirmedLocked);\n        arg_0.Set(\"unconfirmedLocked\", arg_0_6);\n        auto arg_0_7 = Napi::Value::From(env, result.immatureIncludingLocked);\n        arg_0.Set(\"immatureIncludingLocked\", arg_0_7);\n        auto arg_0_8 = Napi::Value::From(env, result.immatureExcludingLocked);\n        arg_0.Set(\"immatureExcludingLocked\", arg_0_8);\n        auto arg_0_9 = Napi::Value::From(env, result.immatureLocked);\n        arg_0.Set(\"immatureLocked\", arg_0_9);\n        auto arg_0_10 = Napi::Value::From(env, result.totalLocked);\n        arg_0.Set(\"totalLocked\", arg_0_10);\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWalletController::AbandonTransaction(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::AbandonTransaction needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IWalletController::AbandonTransaction(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWalletController::GetUUID(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIWalletController::GetUUID needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IWalletController::GetUUID();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::String::New(env, result);\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIWalletController::constructor;\n\nNapi::Object NJSIWalletController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIWalletController\", {\n    InstanceMethod(\"setListener\", &NJSIWalletController::setListener),\n    InstanceMethod(\"HaveUnconfirmedFunds\", &NJSIWalletController::HaveUnconfirmedFunds),\n    InstanceMethod(\"GetBalanceSimple\", &NJSIWalletController::GetBalanceSimple),\n    InstanceMethod(\"GetBalance\", &NJSIWalletController::GetBalance),\n    InstanceMethod(\"AbandonTransaction\", &NJSIWalletController::AbandonTransaction),\n    InstanceMethod(\"GetUUID\", &NJSIWalletController::GetUUID),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIWalletController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWalletController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIWALLETCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIWALLETCONTROLLER_HPP\n\n\n#include \"NJSIWalletListener.hpp\"\n#include \"balance_record.hpp\"\n#include <cstdint>\n#include <memory>\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_wallet_controller.hpp>\n\nusing namespace std;\n\nclass NJSIWalletController: public Napi::ObjectWrap<NJSIWalletController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIWalletController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIWalletController>(info){};\n\nprivate:\n    /** Set listener to be notified of wallet events */\n    void setListener(const Napi::CallbackInfo& info);\n\n    /** Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait. */\n    Napi::Value HaveUnconfirmedFunds(const Napi::CallbackInfo& info);\n\n    /** Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds */\n    Napi::Value GetBalanceSimple(const Napi::CallbackInfo& info);\n\n    /** Check current wallet balance */\n    Napi::Value GetBalance(const Napi::CallbackInfo& info);\n\n    /** Abandon a transaction */\n    Napi::Value AbandonTransaction(const Napi::CallbackInfo& info);\n\n    /** Get a unique UUID that identifies this wallet */\n    Napi::Value GetUUID(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIWALLETCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWalletListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIWalletListener.hpp\"\nusing namespace std;\n\nvoid NJSIWalletListener::notifyBalanceChange_aimpl__(const BalanceRecord & new_balance)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::Value::From(env, new_balance.availableIncludingLocked);\n    arg_0.Set(\"availableIncludingLocked\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, new_balance.availableExcludingLocked);\n    arg_0.Set(\"availableExcludingLocked\", arg_0_2);\n    auto arg_0_3 = Napi::Value::From(env, new_balance.availableLocked);\n    arg_0.Set(\"availableLocked\", arg_0_3);\n    auto arg_0_4 = Napi::Value::From(env, new_balance.unconfirmedIncludingLocked);\n    arg_0.Set(\"unconfirmedIncludingLocked\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, new_balance.unconfirmedExcludingLocked);\n    arg_0.Set(\"unconfirmedExcludingLocked\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, new_balance.unconfirmedLocked);\n    arg_0.Set(\"unconfirmedLocked\", arg_0_6);\n    auto arg_0_7 = Napi::Value::From(env, new_balance.immatureIncludingLocked);\n    arg_0.Set(\"immatureIncludingLocked\", arg_0_7);\n    auto arg_0_8 = Napi::Value::From(env, new_balance.immatureExcludingLocked);\n    arg_0.Set(\"immatureExcludingLocked\", arg_0_8);\n    auto arg_0_9 = Napi::Value::From(env, new_balance.immatureLocked);\n    arg_0.Set(\"immatureLocked\", arg_0_9);\n    auto arg_0_10 = Napi::Value::From(env, new_balance.totalLocked);\n    arg_0.Set(\"totalLocked\", arg_0_10);\n\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyBalanceChange\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyBalanceChange = calling_function.Call(args);\n        if(result_notifyBalanceChange.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyBalanceChange call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyBalanceChange(const BalanceRecord & new_balance)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*, BalanceRecord>(this, new_balance);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*, BalanceRecord>*)req->data));\n        pthis->notifyBalanceChange_aimpl__(std::get<1>(*((std::tuple<NJSIWalletListener*, BalanceRecord>*)req->data)));\n        delete (std::tuple<NJSIWalletListener*, BalanceRecord>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyNewMutation_aimpl__(const MutationRecord & mutation, bool self_committed)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::Value::From(env, mutation.change);\n    arg_0.Set(\"change\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, mutation.timestamp);\n    arg_0.Set(\"timestamp\", arg_0_2);\n    auto arg_0_3 = Napi::String::New(env, mutation.txHash);\n    arg_0.Set(\"txHash\", arg_0_3);\n    auto arg_0_4 = Napi::String::New(env, mutation.recipient_addresses);\n    arg_0.Set(\"recipient_addresses\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, (int)mutation.status);\n    arg_0.Set(\"status\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, mutation.depth);\n    arg_0.Set(\"depth\", arg_0_6);\n\n    args.push_back(arg_0);\n    auto arg_1 = Napi::Value::From(env, self_committed);\n    args.push_back(arg_1);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyNewMutation\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyNewMutation = calling_function.Call(args);\n        if(result_notifyNewMutation.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyNewMutation call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyNewMutation(const MutationRecord & mutation, bool self_committed)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*, MutationRecord, bool>(this, mutation, self_committed);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*, MutationRecord, bool>*)req->data));\n        pthis->notifyNewMutation_aimpl__(std::get<1>(*((std::tuple<NJSIWalletListener*, MutationRecord, bool>*)req->data)), std::get<2>(*((std::tuple<NJSIWalletListener*, MutationRecord, bool>*)req->data)));\n        delete (std::tuple<NJSIWalletListener*, MutationRecord, bool>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyUpdatedTransaction_aimpl__(const TransactionRecord & transaction)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Object::New(env);\n    auto arg_0_1 = Napi::String::New(env, transaction.txHash);\n    arg_0.Set(\"txHash\", arg_0_1);\n    auto arg_0_2 = Napi::Value::From(env, transaction.timeStamp);\n    arg_0.Set(\"timeStamp\", arg_0_2);\n    auto arg_0_3 = Napi::Value::From(env, transaction.amount);\n    arg_0.Set(\"amount\", arg_0_3);\n    auto arg_0_4 = Napi::Value::From(env, transaction.fee);\n    arg_0.Set(\"fee\", arg_0_4);\n    auto arg_0_5 = Napi::Value::From(env, (int)transaction.status);\n    arg_0.Set(\"status\", arg_0_5);\n    auto arg_0_6 = Napi::Value::From(env, transaction.height);\n    arg_0.Set(\"height\", arg_0_6);\n    auto arg_0_7 = Napi::Value::From(env, transaction.blockTime);\n    arg_0.Set(\"blockTime\", arg_0_7);\n    auto arg_0_8 = Napi::Value::From(env, transaction.depth);\n    arg_0.Set(\"depth\", arg_0_8);\n    auto arg_0_9 = Napi::Array::New(env);\n    for(size_t arg_0_9_id = 0; arg_0_9_id < transaction.inputs.size(); arg_0_9_id++)\n    {\n        auto arg_0_9_elem = Napi::Object::New(env);\n        auto arg_0_9_elem_1 = Napi::String::New(env, transaction.inputs[arg_0_9_id].address);\n        arg_0_9_elem.Set(\"address\", arg_0_9_elem_1);\n        auto arg_0_9_elem_2 = Napi::String::New(env, transaction.inputs[arg_0_9_id].label);\n        arg_0_9_elem.Set(\"label\", arg_0_9_elem_2);\n        auto arg_0_9_elem_3 = Napi::String::New(env, transaction.inputs[arg_0_9_id].desc);\n        arg_0_9_elem.Set(\"desc\", arg_0_9_elem_3);\n        auto arg_0_9_elem_4 = Napi::Value::From(env, transaction.inputs[arg_0_9_id].isMine);\n        arg_0_9_elem.Set(\"isMine\", arg_0_9_elem_4);\n\n        arg_0_9.Set((int)arg_0_9_id,arg_0_9_elem);\n    }\n\n    arg_0.Set(\"inputs\", arg_0_9);\n    auto arg_0_10 = Napi::Array::New(env);\n    for(size_t arg_0_10_id = 0; arg_0_10_id < transaction.outputs.size(); arg_0_10_id++)\n    {\n        auto arg_0_10_elem = Napi::Object::New(env);\n        auto arg_0_10_elem_1 = Napi::Value::From(env, transaction.outputs[arg_0_10_id].amount);\n        arg_0_10_elem.Set(\"amount\", arg_0_10_elem_1);\n        auto arg_0_10_elem_2 = Napi::String::New(env, transaction.outputs[arg_0_10_id].address);\n        arg_0_10_elem.Set(\"address\", arg_0_10_elem_2);\n        auto arg_0_10_elem_3 = Napi::String::New(env, transaction.outputs[arg_0_10_id].label);\n        arg_0_10_elem.Set(\"label\", arg_0_10_elem_3);\n        auto arg_0_10_elem_4 = Napi::String::New(env, transaction.outputs[arg_0_10_id].desc);\n        arg_0_10_elem.Set(\"desc\", arg_0_10_elem_4);\n        auto arg_0_10_elem_5 = Napi::Value::From(env, transaction.outputs[arg_0_10_id].isMine);\n        arg_0_10_elem.Set(\"isMine\", arg_0_10_elem_5);\n\n        arg_0_10.Set((int)arg_0_10_id,arg_0_10_elem);\n    }\n\n    arg_0.Set(\"outputs\", arg_0_10);\n\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyUpdatedTransaction\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyUpdatedTransaction = calling_function.Call(args);\n        if(result_notifyUpdatedTransaction.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyUpdatedTransaction call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyUpdatedTransaction(const TransactionRecord & transaction)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*, TransactionRecord>(this, transaction);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*, TransactionRecord>*)req->data));\n        pthis->notifyUpdatedTransaction_aimpl__(std::get<1>(*((std::tuple<NJSIWalletListener*, TransactionRecord>*)req->data)));\n        delete (std::tuple<NJSIWalletListener*, TransactionRecord>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyWalletUnlocked_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyWalletUnlocked\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyWalletUnlocked = calling_function.Call(args);\n        if(result_notifyWalletUnlocked.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyWalletUnlocked call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyWalletUnlocked()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*>*)req->data));\n        pthis->notifyWalletUnlocked_aimpl__();\n        delete (std::tuple<NJSIWalletListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyWalletLocked_aimpl__()\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    Napi::Value calling_function_as_value = Value().Get(\"notifyWalletLocked\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyWalletLocked = calling_function.Call(args);\n        if(result_notifyWalletLocked.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyWalletLocked call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyWalletLocked()\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*>(this);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*>*)req->data));\n        pthis->notifyWalletLocked_aimpl__();\n        delete (std::tuple<NJSIWalletListener*>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyCoreWantsUnlock_aimpl__(const std::string & reason)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, reason);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyCoreWantsUnlock\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyCoreWantsUnlock = calling_function.Call(args);\n        if(result_notifyCoreWantsUnlock.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyCoreWantsUnlock call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyCoreWantsUnlock(const std::string & reason)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*, std::string>(this, reason);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*, std::string>*)req->data));\n        pthis->notifyCoreWantsUnlock_aimpl__(std::get<1>(*((std::tuple<NJSIWalletListener*, std::string>*)req->data)));\n        delete (std::tuple<NJSIWalletListener*, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nvoid NJSIWalletListener::notifyCoreInfo_aimpl__(const std::string & type, const std::string & caption, const std::string & message)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::String::New(env, type);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::String::New(env, caption);\n    args.push_back(arg_1);\n    auto arg_2 = Napi::String::New(env, message);\n    args.push_back(arg_2);\n    Napi::Value calling_function_as_value = Value().Get(\"notifyCoreInfo\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_notifyCoreInfo = calling_function.Call(args);\n        if(result_notifyCoreInfo.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSIWalletListener::notifyCoreInfo call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSIWalletListener::notifyCoreInfo(const std::string & type, const std::string & caption, const std::string & message)\n{\n    uv_work_t* request = new uv_work_t;\n    request->data = new std::tuple<NJSIWalletListener*, std::string, std::string, std::string>(this, type, caption, message);\n\n    uv_queue_work(uv_default_loop(), request, [](uv_work_t*) -> void{}, [](uv_work_t* req, int status) -> void\n    {\n        NJSIWalletListener* pthis = std::get<0>(*((std::tuple<NJSIWalletListener*, std::string, std::string, std::string>*)req->data));\n        pthis->notifyCoreInfo_aimpl__(std::get<1>(*((std::tuple<NJSIWalletListener*, std::string, std::string, std::string>*)req->data)), std::get<2>(*((std::tuple<NJSIWalletListener*, std::string, std::string, std::string>*)req->data)), std::get<3>(*((std::tuple<NJSIWalletListener*, std::string, std::string, std::string>*)req->data)));\n        delete (std::tuple<NJSIWalletListener*, std::string, std::string, std::string>*)req->data;\n        req->data = nullptr;\n    }\n    );\n}\n\nNapi::FunctionReference NJSIWalletListener::constructor;\n\nNapi::Object NJSIWalletListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSIWalletListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIWalletListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWalletListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIWALLETLISTENER_HPP\n#define DJINNI_GENERATED_NJSIWALLETLISTENER_HPP\n\n\n#include \"balance_record.hpp\"\n#include \"input_record.hpp\"\n#include \"mutation_record.hpp\"\n#include \"output_record.hpp\"\n#include \"transaction_record.hpp\"\n#include <string>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_wallet_listener.hpp>\n\nusing namespace std;\n\nclass NJSIWalletListener: public Napi::ObjectWrap<NJSIWalletListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIWalletListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIWalletListener>(info){};\n\n    /** Notification of change in overall wallet balance */\n    void notifyBalanceChange(const BalanceRecord & new_balance);\n\n    /**\n     * Notification of new mutations.\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyNewMutation(const MutationRecord & mutation, bool self_committed);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyUpdatedTransaction(const TransactionRecord & transaction);\n\n    /** Wallet unlocked */\n    void notifyWalletUnlocked();\n\n    /** Wallet locked */\n    void notifyWalletLocked();\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    void notifyCoreWantsUnlock(const std::string & reason);\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    void notifyCoreInfo(const std::string & type, const std::string & caption, const std::string & message);\n\nprivate:\n    /** Notification of change in overall wallet balance */\n    void notifyBalanceChange(const Napi::CallbackInfo& info);\n    void notifyBalanceChange_aimpl__(const BalanceRecord & new_balance);\n\n    /**\n     * Notification of new mutations.\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyNewMutation(const Napi::CallbackInfo& info);\n    void notifyNewMutation_aimpl__(const MutationRecord & mutation, bool self_committed);\n\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    void notifyUpdatedTransaction(const Napi::CallbackInfo& info);\n    void notifyUpdatedTransaction_aimpl__(const TransactionRecord & transaction);\n\n    /** Wallet unlocked */\n    void notifyWalletUnlocked(const Napi::CallbackInfo& info);\n    void notifyWalletUnlocked_aimpl__();\n\n    /** Wallet locked */\n    void notifyWalletLocked(const Napi::CallbackInfo& info);\n    void notifyWalletLocked_aimpl__();\n\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    void notifyCoreWantsUnlock(const Napi::CallbackInfo& info);\n    void notifyCoreWantsUnlock_aimpl__(const std::string & reason);\n\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    void notifyCoreInfo(const Napi::CallbackInfo& info);\n    void notifyCoreInfo_aimpl__(const std::string & type, const std::string & caption, const std::string & message);\n\n};\n#endif //DJINNI_GENERATED_NJSIWALLETLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWitnessController.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSIWitnessController.hpp\"\nusing namespace std;\n\nNapi::Value NJSIWitnessController::getNetworkLimits(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 0)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getNetworkLimits needs 0 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n\n    try\n    {\n        auto result = IWitnessController::getNetworkLimits();\n\n        //Wrap result in node object\n        auto arg_0 = Napi::Object::New(env);\n        for(auto const& arg_0_elem : result)\n        {\n            auto arg_0_first = Napi::String::New(env, arg_0_elem.first);\n            auto arg_0_second = Napi::String::New(env, arg_0_elem.second);\n            arg_0.Set(arg_0_first, arg_0_second);\n        }\n\n\n        return arg_0;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::getEstimatedWeight(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getEstimatedWeight needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    auto arg_0 = info[0].ToNumber().Int64Value();\n    auto arg_1 = info[1].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = IWitnessController::getEstimatedWeight(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Object::New(env);\n        auto arg_2_1 = Napi::Value::From(env, result.network_weight);\n        arg_2.Set(\"network_weight\", arg_2_1);\n        auto arg_2_2 = Napi::Value::From(env, result.weight);\n        arg_2.Set(\"weight\", arg_2_2);\n        auto arg_2_3 = Napi::Value::From(env, result.parts);\n        arg_2.Set(\"parts\", arg_2_3);\n        auto arg_2_4 = Napi::Value::From(env, result.estimated_witness_probability);\n        arg_2.Set(\"estimated_witness_probability\", arg_2_4);\n        auto arg_2_5 = Napi::Value::From(env, result.estimated_blocks_per_day);\n        arg_2.Set(\"estimated_blocks_per_day\", arg_2_5);\n        auto arg_2_6 = Napi::Value::From(env, result.estimated_daily_earnings);\n        arg_2.Set(\"estimated_daily_earnings\", arg_2_6);\n        auto arg_2_7 = Napi::Value::From(env, result.estimated_lifetime_earnings);\n        arg_2.Set(\"estimated_lifetime_earnings\", arg_2_7);\n\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::fundWitnessAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 4)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::fundWitnessAccount needs 4 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    auto arg_2 = info[2].ToNumber().Int64Value();\n    auto arg_3 = info[3].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = IWitnessController::fundWitnessAccount(arg_0,arg_1,arg_2,arg_3);\n\n        //Wrap result in node object\n        auto arg_4 = Napi::Object::New(env);\n        auto arg_4_1 = Napi::String::New(env, result.status);\n        arg_4.Set(\"status\", arg_4_1);\n        auto arg_4_2 = Napi::String::New(env, result.txid);\n        arg_4.Set(\"txid\", arg_4_2);\n        auto arg_4_3 = Napi::Value::From(env, result.fee);\n        arg_4.Set(\"fee\", arg_4_3);\n\n\n        return arg_4;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::renewWitnessAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::renewWitnessAccount needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n\n    try\n    {\n        auto result = IWitnessController::renewWitnessAccount(arg_0,arg_1);\n\n        //Wrap result in node object\n        auto arg_2 = Napi::Object::New(env);\n        auto arg_2_1 = Napi::String::New(env, result.status);\n        arg_2.Set(\"status\", arg_2_1);\n        auto arg_2_2 = Napi::String::New(env, result.txid);\n        arg_2.Set(\"txid\", arg_2_2);\n        auto arg_2_3 = Napi::Value::From(env, result.fee);\n        arg_2.Set(\"fee\", arg_2_3);\n\n\n        return arg_2;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::getAccountWitnessStatistics(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getAccountWitnessStatistics needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IWitnessController::getAccountWitnessStatistics(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Object::New(env);\n        auto arg_1_1 = Napi::String::New(env, result.request_status);\n        arg_1.Set(\"request_status\", arg_1_1);\n        auto arg_1_2 = Napi::String::New(env, result.account_status);\n        arg_1.Set(\"account_status\", arg_1_2);\n        auto arg_1_3 = Napi::Value::From(env, result.blocks_since_last_activity);\n        arg_1.Set(\"blocks_since_last_activity\", arg_1_3);\n        auto arg_1_4 = Napi::Value::From(env, result.account_weight);\n        arg_1.Set(\"account_weight\", arg_1_4);\n        auto arg_1_5 = Napi::Value::From(env, result.account_weight_at_creation);\n        arg_1.Set(\"account_weight_at_creation\", arg_1_5);\n        auto arg_1_6 = Napi::Value::From(env, result.account_parts);\n        arg_1.Set(\"account_parts\", arg_1_6);\n        auto arg_1_7 = Napi::Value::From(env, result.account_amount_locked);\n        arg_1.Set(\"account_amount_locked\", arg_1_7);\n        auto arg_1_8 = Napi::Value::From(env, result.account_amount_locked_at_creation);\n        arg_1.Set(\"account_amount_locked_at_creation\", arg_1_8);\n        auto arg_1_9 = Napi::Value::From(env, result.network_tip_total_weight);\n        arg_1.Set(\"network_tip_total_weight\", arg_1_9);\n        auto arg_1_10 = Napi::Value::From(env, result.network_total_weight_at_creation);\n        arg_1.Set(\"network_total_weight_at_creation\", arg_1_10);\n        auto arg_1_11 = Napi::Value::From(env, result.account_initial_lock_period_in_blocks);\n        arg_1.Set(\"account_initial_lock_period_in_blocks\", arg_1_11);\n        auto arg_1_12 = Napi::Value::From(env, result.account_remaining_lock_period_in_blocks);\n        arg_1.Set(\"account_remaining_lock_period_in_blocks\", arg_1_12);\n        auto arg_1_13 = Napi::Value::From(env, result.account_expected_witness_period_in_blocks);\n        arg_1.Set(\"account_expected_witness_period_in_blocks\", arg_1_13);\n        auto arg_1_14 = Napi::Value::From(env, result.account_estimated_witness_period_in_blocks);\n        arg_1.Set(\"account_estimated_witness_period_in_blocks\", arg_1_14);\n        auto arg_1_15 = Napi::Value::From(env, result.account_initial_lock_creation_block_height);\n        arg_1.Set(\"account_initial_lock_creation_block_height\", arg_1_15);\n        auto arg_1_16 = Napi::Value::From(env, result.compounding_percent);\n        arg_1.Set(\"compounding_percent\", arg_1_16);\n        auto arg_1_17 = Napi::Value::From(env, result.is_optimal);\n        arg_1.Set(\"is_optimal\", arg_1_17);\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nvoid NJSIWitnessController::setAccountCompounding(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 2)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::setAccountCompounding needs 2 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    auto arg_1 = info[1].ToNumber().Int32Value();\n    try\n    {\n        IWitnessController::setAccountCompounding(arg_0,arg_1);\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return;\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return;\n    }\n}\nNapi::Value NJSIWitnessController::isAccountCompounding(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::isAccountCompounding needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IWitnessController::isAccountCompounding(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Value::From(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::getWitnessAddress(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getWitnessAddress needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IWitnessController::getWitnessAddress(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::String::New(env, result);\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::getOptimalWitnessDistribution(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 3)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getOptimalWitnessDistribution needs 3 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    auto arg_0 = info[0].ToNumber().Int64Value();\n    auto arg_1 = info[1].ToNumber().Int64Value();\n    auto arg_2 = info[2].ToNumber().Int64Value();\n\n    try\n    {\n        auto result = IWitnessController::getOptimalWitnessDistribution(arg_0,arg_1,arg_2);\n\n        //Wrap result in node object\n        auto arg_3 = Napi::Array::New(env);\n        for(size_t arg_3_id = 0; arg_3_id < result.size(); arg_3_id++)\n        {\n            auto arg_3_elem = Napi::Value::From(env, result[arg_3_id]);\n            arg_3.Set((int)arg_3_id,arg_3_elem);\n        }\n\n\n        return arg_3;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::getOptimalWitnessDistributionForAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 1)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::getOptimalWitnessDistributionForAccount needs 1 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n\n    try\n    {\n        auto result = IWitnessController::getOptimalWitnessDistributionForAccount(arg_0);\n\n        //Wrap result in node object\n        auto arg_1 = Napi::Array::New(env);\n        for(size_t arg_1_id = 0; arg_1_id < result.size(); arg_1_id++)\n        {\n            auto arg_1_elem = Napi::Value::From(env, result[arg_1_id]);\n            arg_1.Set((int)arg_1_id,arg_1_elem);\n        }\n\n\n        return arg_1;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\nNapi::Value NJSIWitnessController::optimiseWitnessAccount(const Napi::CallbackInfo& info) {\n    Napi::Env env = info.Env();\n\n\n    //Check if method called with right number of arguments\n    if(info.Length() != 3)\n    {\n        Napi::Error::New(env, \"NJSIWitnessController::optimiseWitnessAccount needs 3 arguments\").ThrowAsJavaScriptException();\n    }\n\n    //Check if parameters have correct types\n    std::string arg_0 = info[0].As<Napi::String>();\n    std::string arg_1 = info[1].As<Napi::String>();\n    vector<int64_t> arg_2;\n    auto arg_2_container = info[2].As<Napi::Array>();\n    for(uint32_t arg_2_id = 0; arg_2_id < arg_2_container.Length(); arg_2_id++)\n    {\n        if(arg_2_container.Get(arg_2_id).IsNumber())\n        {\n            auto arg_2_elem = arg_2_container.Get(arg_2_id).ToNumber().Int64Value();\n            arg_2.emplace_back(arg_2_elem);\n        }\n    }\n\n\n    try\n    {\n        auto result = IWitnessController::optimiseWitnessAccount(arg_0,arg_1,arg_2);\n\n        //Wrap result in node object\n        auto arg_3 = Napi::Object::New(env);\n        auto arg_3_1 = Napi::Value::From(env, result.result);\n        arg_3.Set(\"result\", arg_3_1);\n        auto arg_3_2 = Napi::String::New(env, result.info);\n        arg_3.Set(\"info\", arg_3_2);\n\n\n        return arg_3;\n    }\n    catch (std::exception& e)\n    {\n        Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n    catch (...)\n    {\n        Napi::Error::New(env, \"core exception thrown\").ThrowAsJavaScriptException();\n        return Napi::Value();\n    }\n}\n\nNapi::FunctionReference NJSIWitnessController::constructor;\n\nNapi::Object NJSIWitnessController::Init(Napi::Env env, Napi::Object exports) {\n\n    // Hook all method callbacks\n    Napi::Function func = DefineClass(env, \"NJSIWitnessController\", {\n    InstanceMethod(\"getNetworkLimits\", &NJSIWitnessController::getNetworkLimits),\n    InstanceMethod(\"getEstimatedWeight\", &NJSIWitnessController::getEstimatedWeight),\n    InstanceMethod(\"fundWitnessAccount\", &NJSIWitnessController::fundWitnessAccount),\n    InstanceMethod(\"renewWitnessAccount\", &NJSIWitnessController::renewWitnessAccount),\n    InstanceMethod(\"getAccountWitnessStatistics\", &NJSIWitnessController::getAccountWitnessStatistics),\n    InstanceMethod(\"setAccountCompounding\", &NJSIWitnessController::setAccountCompounding),\n    InstanceMethod(\"isAccountCompounding\", &NJSIWitnessController::isAccountCompounding),\n    InstanceMethod(\"getWitnessAddress\", &NJSIWitnessController::getWitnessAddress),\n    InstanceMethod(\"getOptimalWitnessDistribution\", &NJSIWitnessController::getOptimalWitnessDistribution),\n    InstanceMethod(\"getOptimalWitnessDistributionForAccount\", &NJSIWitnessController::getOptimalWitnessDistributionForAccount),\n    InstanceMethod(\"optimiseWitnessAccount\", &NJSIWitnessController::optimiseWitnessAccount),\n    });\n    // Create a peristent reference to the class constructor. This will allow a function called on a class prototype and a function called on instance of a class to be distinguished from each other.\n    constructor = Napi::Persistent(func);\n    // Call the SuppressDestruct() method on the static data prevent the calling to this destructor to reset the reference when the environment is no longer available.\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSIWitnessController\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSIWitnessController.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSIWITNESSCONTROLLER_HPP\n#define DJINNI_GENERATED_NJSIWITNESSCONTROLLER_HPP\n\n\n#include \"result_record.hpp\"\n#include \"witness_account_statistics_record.hpp\"\n#include \"witness_estimate_info_record.hpp\"\n#include \"witness_funding_result_record.hpp\"\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#include <napi.h>\n#include <uv.h>\n#include <i_witness_controller.hpp>\n\nusing namespace std;\n\nclass NJSIWitnessController: public Napi::ObjectWrap<NJSIWitnessController> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSIWitnessController(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSIWitnessController>(info){};\n\nprivate:\n    /** Get information on min/max witness periods, weights etc. */\n    Napi::Value getNetworkLimits(const Napi::CallbackInfo& info);\n\n    /** Get an estimate of weights/parts that a witness account will be funded with */\n    Napi::Value getEstimatedWeight(const Napi::CallbackInfo& info);\n\n    /** Fund a witness account */\n    Napi::Value fundWitnessAccount(const Napi::CallbackInfo& info);\n\n    /** Renew a witness account */\n    Napi::Value renewWitnessAccount(const Napi::CallbackInfo& info);\n\n    /** Get information on account weight and other witness statistics for account */\n    Napi::Value getAccountWitnessStatistics(const Napi::CallbackInfo& info);\n\n    /** Turn compounding on/off */\n    void setAccountCompounding(const Napi::CallbackInfo& info);\n\n    /** Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding */\n    Napi::Value isAccountCompounding(const Napi::CallbackInfo& info);\n\n    /** Get the witness address of the account */\n    Napi::Value getWitnessAddress(const Napi::CallbackInfo& info);\n\n    /** Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\" */\n    Napi::Value getOptimalWitnessDistribution(const Napi::CallbackInfo& info);\n\n    /** Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values */\n    Napi::Value getOptimalWitnessDistributionForAccount(const Napi::CallbackInfo& info);\n\n    /** Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this */\n    Napi::Value optimiseWitnessAccount(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSIWITNESSCONTROLLER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSMonitorListener.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"NJSMonitorListener.hpp\"\nusing namespace std;\n\nvoid NJSMonitorListener::onPartialChain(int32_t height, int32_t probable_height, int32_t offset)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, height);\n    args.push_back(arg_0);\n    auto arg_1 = Napi::Value::From(env, probable_height);\n    args.push_back(arg_1);\n    auto arg_2 = Napi::Value::From(env, offset);\n    args.push_back(arg_2);\n    Napi::Value calling_function_as_value = Value().Get(\"onPartialChain\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onPartialChain = calling_function.Call(args);\n        if(result_onPartialChain.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSMonitorListener::onPartialChain call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSMonitorListener::onPruned(int32_t height)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, height);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onPruned\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onPruned = calling_function.Call(args);\n        if(result_onPruned.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSMonitorListener::onPruned call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nvoid NJSMonitorListener::onProcessedSPVBlocks(int32_t height)\n{\n    const auto& env = Env();\n    Napi::HandleScope scope(env);\n    //Wrap parameters\n    std::vector<napi_value> args;\n    auto arg_0 = Napi::Value::From(env, height);\n    args.push_back(arg_0);\n    Napi::Value calling_function_as_value = Value().Get(\"onProcessedSPVBlocks\");\n    if(!calling_function_as_value.IsUndefined() && !calling_function_as_value.IsNull())\n    {\n        Napi::Function calling_function = calling_function_as_value.As<Napi::Function>();\n        auto result_onProcessedSPVBlocks = calling_function.Call(args);\n        if(result_onProcessedSPVBlocks.IsEmpty())\n        {\n            Napi::Error::New(env, \"NJSMonitorListener::onProcessedSPVBlocks call failed\").ThrowAsJavaScriptException();\n            return;\n        }\n    }\n}\n\nNapi::FunctionReference NJSMonitorListener::constructor;\n\nNapi::Object NJSMonitorListener::Init(Napi::Env env, Napi::Object exports) {\n\n    Napi::Function func = DefineClass(env, \"NJSMonitorListener\",{});\n    constructor = Napi::Persistent(func);\n    constructor.SuppressDestruct();\n    exports.Set(\"NJSMonitorListener\", func);\n    return exports;\n}\n"
  },
  {
    "path": "src/unity/djinni/node_js/NJSMonitorListener.hpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#ifndef DJINNI_GENERATED_NJSMONITORLISTENER_HPP\n#define DJINNI_GENERATED_NJSMONITORLISTENER_HPP\n\n\n#include <cstdint>\n\n#include <napi.h>\n#include <uv.h>\n#include <monitor_listener.hpp>\n\nusing namespace std;\n\nclass NJSMonitorListener: public Napi::ObjectWrap<NJSMonitorListener> {\npublic:\n\n    static Napi::FunctionReference constructor;\n    static Napi::Object Init(Napi::Env env, Napi::Object exports);\n    NJSMonitorListener(const Napi::CallbackInfo& info) : Napi::ObjectWrap<NJSMonitorListener>(info){};\n\n    void onPartialChain(int32_t height, int32_t probable_height, int32_t offset);\n\n    void onPruned(int32_t height);\n\n    void onProcessedSPVBlocks(int32_t height);\n\nprivate:\n    void onPartialChain(const Napi::CallbackInfo& info);\n\n    void onPruned(const Napi::CallbackInfo& info);\n\n    void onProcessedSPVBlocks(const Napi::CallbackInfo& info);\n\n};\n#endif //DJINNI_GENERATED_NJSMONITORLISTENER_HPP\n"
  },
  {
    "path": "src/unity/djinni/node_js/unifiedbackend.cpp",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni\n\n#include <napi.h>\n\n#include \"NJSILibraryController.hpp\"\n#include \"NJSIWalletController.hpp\"\n#include \"NJSIWalletListener.hpp\"\n#include \"NJSMonitorListener.hpp\"\n#include \"NJSILibraryListener.hpp\"\n#include \"NJSIRpcController.hpp\"\n#include \"NJSIRpcListener.hpp\"\n#include \"NJSIP2pNetworkController.hpp\"\n#include \"NJSIP2pNetworkListener.hpp\"\n#include \"NJSIAccountsController.hpp\"\n#include \"NJSIAccountsListener.hpp\"\n#include \"NJSIWitnessController.hpp\"\n#include \"NJSIGenerationController.hpp\"\n#include \"NJSIGenerationListener.hpp\"\n\n\nNapi::Object InitAll(Napi::Env env, Napi::Object exports)\n{\n    NJSILibraryController::Init(env, exports);\n    NJSIWalletController::Init(env, exports);\n    NJSIWalletListener::Init(env, exports);\n    NJSMonitorListener::Init(env, exports);\n    NJSILibraryListener::Init(env, exports);\n    NJSIRpcController::Init(env, exports);\n    NJSIRpcListener::Init(env, exports);\n    NJSIP2pNetworkController::Init(env, exports);\n    NJSIP2pNetworkListener::Init(env, exports);\n    NJSIAccountsController::Init(env, exports);\n    NJSIAccountsListener::Init(env, exports);\n    NJSIWitnessController::Init(env, exports);\n    NJSIGenerationController::Init(env, exports);\n    NJSIGenerationListener::Init(env, exports);\n    return exports;\n}\nNODE_API_MODULE(unifiedbackend,InitAll);\n"
  },
  {
    "path": "src/unity/djinni/node_js/unifiedbackend_doc.js",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni\n\n/**\n * The library controller is used to Init/Terminate the library, and other similar tasks.\n * It is also home to various generic utility functions that don't (yet) have a place in more specific controllers\n * Specific functionality should go in specific controllers; account related functionality -> accounts_controller, network related functionality -> network_controller and so on\n */\ndeclare class NJSILibraryController\n{\n    /** Get the build information (ie. commit id and status) */\n    static declare function BuildInfo(): string;\n    /**\n     * Start the library\n     * extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n     * NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n     * If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n     */\n    static declare function InitUnityLib(data_dir: string, staticFilterPath: string, staticFilterOffset: number, staticFilterLength: number, testnet: boolean, spvMode: boolean, signalHandler: NJSILibraryListener, extraArgs: string): number;\n    /** Threaded implementation of InitUnityLib */\n    static declare function InitUnityLibThreaded(data_dir: string, staticFilterPath: string, staticFilterOffset: number, staticFilterLength: number, testnet: boolean, spvMode: boolean, signalHandler: NJSILibraryListener, extraArgs: string);\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static declare function InitWalletFromRecoveryPhrase(phrase: string, password: string): boolean;\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    static declare function ContinueWalletFromRecoveryPhrase(phrase: string, password: string): boolean;\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static declare function InitWalletLinkedFromURI(linked_uri: string, password: string): boolean;\n    /** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n    static declare function ContinueWalletLinkedFromURI(linked_uri: string, password: string): boolean;\n    /** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n    static declare function InitWalletFromAndroidLegacyProtoWallet(wallet_file: string, old_password: string, new_password: string): boolean;\n    /** Check if a file is a valid legacy proto wallet */\n    static declare function isValidAndroidLegacyProtoWallet(wallet_file: string, old_password: string): LegacyWalletResult;\n    /** Check link URI for validity */\n    static declare function IsValidLinkURI(phrase: string): boolean;\n    /** Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet. */\n    static declare function ReplaceWalletLinkedFromURI(linked_uri: string, password: string): boolean;\n    /**\n     * Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n     * After calling this it will be necessary to create a new linked account or recovery phrase account again.\n     * NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n     */\n    static declare function EraseWalletSeedsAndAccounts(): boolean;\n    /**\n     * Check recovery phrase for (syntactic) validity\n     * Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n     */\n    static declare function IsValidRecoveryPhrase(phrase: string): boolean;\n    /** Generate a new recovery mnemonic */\n    static declare function GenerateRecoveryMnemonic(): MnemonicRecord;\n    static declare function GenerateGenesisKeys(): string;\n    /** Compute recovery phrase with birth number */\n    static declare function ComposeRecoveryPhrase(mnemonic: string, birthTime: number): MnemonicRecord;\n    /** Stop the library */\n    static declare function TerminateUnityLib();\n    /** Generate a QR code for a string, QR code will be as close to width_hint as possible when applying simple scaling. */\n    static declare function QRImageFromString(qr_string: string, width_hint: number): QrCodeRecord;\n    /** Get a receive address for the active account */\n    static declare function GetReceiveAddress(): string;\n    /** Get the recovery phrase for the wallet */\n    static declare function GetRecoveryPhrase(): MnemonicRecord;\n    /** Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet) */\n    static declare function IsMnemonicWallet(): boolean;\n    /** Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time) */\n    static declare function IsMnemonicCorrect(phrase: string): boolean;\n    /**\n     * Get the 'dictionary' of valid words that a recovery phrase can be composed of\n     * NB! Not all combinations of these words are valid\n     * Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n     * This function should only be used for input validation/auto-completion\n     */\n    static declare function GetMnemonicDictionary(): Array<string>;\n    /** Unlock wallet; wallet will automatically relock after \"timeout_in_seconds\" */\n    static declare function UnlockWallet(password: string, timeout_in_seconds: number): boolean;\n    /** Forcefully lock wallet again */\n    static declare function LockWallet(): boolean;\n    static declare function GetWalletLockStatus(): WalletLockStatus;\n    /** Change the wallet password */\n    static declare function ChangePassword(oldPassword: string, newPassword: string): boolean;\n    /** Rescan blockchain for wallet transactions */\n    static declare function DoRescan();\n    /** Check if text/address is something we are capable of sending money too */\n    static declare function IsValidRecipient(request: UriRecord): UriRecipient;\n    /** Check if text/address is a native (to our blockchain) address */\n    static declare function IsValidNativeAddress(address: string): boolean;\n    /** Check if text/address is a valid bitcoin address */\n    static declare function IsValidBitcoinAddress(address: string): boolean;\n    /** Compute the fee required to send amount to given recipient */\n    static declare function feeForRecipient(request: UriRecipient): number;\n    /** Attempt to pay a recipient, will throw on failure with description */\n    static declare function performPaymentToRecipient(request: UriRecipient, substract_fee: boolean): PaymentResultStatus;\n    /**\n     * Get the wallet transaction for the hash\n     * Will throw if not found\n     */\n    static declare function getTransaction(txHash: string): TransactionRecord;\n    /** resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail */\n    static declare function resendTransaction(txHash: string): string;\n    /** Get list of all address book entries */\n    static declare function getAddressBookRecords(): Array<AddressRecord>;\n    /** Add a record to the address book */\n    static declare function addAddressBookRecord(address: AddressRecord);\n    /** Delete a record from the address book */\n    static declare function deleteAddressBookRecord(address: AddressRecord);\n    /** Interim persist and prune of state. Use at key moments like app backgrounding. */\n    static declare function PersistAndPruneForSPV();\n    /**\n     * Reset progress notification. In cases where there has been no progress for a long time, but the process\n     * is still running the progress can be reset and will represent work to be done from this reset onwards.\n     * For example when the process is in the background on iOS for a long long time (but has not been terminated\n     * by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n     */\n    static declare function ResetUnifiedProgress();\n    /** Get info of last blocks (at most 32) in SPV chain */\n    static declare function getLastSPVBlockInfos(): Array<BlockInfoRecord>;\n    static declare function getUnifiedProgress(): number;\n    static declare function getMonitoringStats(): MonitorRecord;\n    static declare function RegisterMonitorListener(listener: NJSMonitorListener);\n    static declare function UnregisterMonitorListener(listener: NJSMonitorListener);\n    static declare function getClientInfo(): Map<string, string>;\n    /**\n     * Get list of wallet mutations\n     *NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n     */\n    static declare function getMutationHistory(): Array<MutationRecord>;\n    /**\n     * Get list of all transactions wallet has been involved in\n     *NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n     */\n    static declare function getTransactionHistory(): Array<TransactionRecord>;\n    /**\n     * Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n     *NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n     */\n    static declare function HaveUnconfirmedFunds(): boolean;\n    /**\n     * Check current wallet balance (including unconfirmed funds)\n     *NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n     */\n    static declare function GetBalance(): number;\n}\n/**\n * Controller to perform functions at a wallet level (e.g. get balance of the entire wallet)\n * For per account functionality see accounts_controller\n */\ndeclare class NJSIWalletController\n{\n    /** Set listener to be notified of wallet events */\n    static declare function setListener(networklistener: NJSIWalletListener);\n    /** Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait. */\n    static declare function HaveUnconfirmedFunds(): boolean;\n    /** Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds */\n    static declare function GetBalanceSimple(): number;\n    /** Check current wallet balance */\n    static declare function GetBalance(): BalanceRecord;\n    /** Abandon a transaction */\n    static declare function AbandonTransaction(txHash: string): boolean;\n    /** Get a unique UUID that identifies this wallet */\n    static declare function GetUUID(): string;\n}\n/** Interface to receive wallet level events */\ndeclare class NJSIWalletListener\n{\n    /** Notification of change in overall wallet balance */\n    declare function notifyBalanceChange(new_balance: BalanceRecord);\n    /**\n     * Notification of new mutations.\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    declare function notifyNewMutation(mutation: MutationRecord, self_committed: boolean);\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    declare function notifyUpdatedTransaction(transaction: TransactionRecord);\n    /** Wallet unlocked */\n    declare function notifyWalletUnlocked();\n    /** Wallet locked */\n    declare function notifyWalletLocked();\n    /** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n    declare function notifyCoreWantsUnlock(reason: string);\n    /** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n    declare function notifyCoreInfo(type: string, caption: string, message: string);\n}\n/** Monitoring events */\ndeclare class NJSMonitorListener\n{\n    declare function onPartialChain(height: number, probable_height: number, offset: number);\n    declare function onPruned(height: number);\n    declare function onProcessedSPVBlocks(height: number);\n}\n/** Interface to receive events from the core */\ndeclare class NJSILibraryListener\n{\n    /**\n     * Fraction of work done since session start or last progress reset [0..1]\n     * Unified progress combines connection state, header and block sync\n     */\n    declare function notifyUnifiedProgress(progress: number);\n    /** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n    declare function notifySyncDone();\n    declare function notifyBalanceChange(new_balance: BalanceRecord);\n    /**\n     * Notification of new mutations\n     * If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n     * reached us in another way. In general this will be because we received funds from someone, hower there are\n     * also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n     * or another wallet instance using the same keys as ours).\n     *\n     * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    declare function notifyNewMutation(mutation: MutationRecord, self_committed: boolean);\n    /**\n     * Notification that an existing transaction/mutation  has updated\n     *\n     * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n     * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n     */\n    declare function notifyUpdatedTransaction(transaction: TransactionRecord);\n    declare function notifyInitWithExistingWallet();\n    declare function notifyInitWithoutExistingWallet();\n    declare function notifyShutdown();\n    declare function notifyCoreReady();\n    declare function notifyError(error: string);\n    declare function logPrint(str: string);\n}\n/** C++ interface to execute RPC commands */\ndeclare class NJSIRpcController\n{\n    static declare function execute(rpcCommandLine: string, resultListener: NJSIRpcListener);\n    static declare function getAutocompleteList(): Array<string>;\n}\n/**\n * Interface to handle result of RPC commands\n * Calls either onSuccess or onError depending on whether command suceedes or fails\n */\ndeclare class NJSIRpcListener\n{\n    /**\n     * Returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    declare function onFilteredCommand(filteredCommand: string);\n    /**\n     * Returns the result and a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    declare function onSuccess(filteredCommand: string, result: string);\n    /**\n     * Returns an error message which might be a plain string or JSON depending on the type of error\n     * Also returns a filtered version of the command with sensitive information like passwords removed\n     * Any kind of 'command history' functionality should store this filtered command and not the original command\n     */\n    declare function onError(filteredCommand: string, errorMessage: string);\n}\n/** C++ interface to control networking related aspects of the software */\ndeclare class NJSIP2pNetworkController\n{\n    /** Register listener to be notified of networking events */\n    static declare function setListener(networklistener: NJSIP2pNetworkListener);\n    /** Turn p2p networking off */\n    static declare function disableNetwork();\n    /** Turn p2p networking on */\n    static declare function enableNetwork();\n    /** Get connected peer info */\n    static declare function getPeerInfo(): Array<PeerRecord>;\n    /** Get all banned peers */\n    static declare function listBannedPeers(): Array<BannedPeerRecord>;\n    static declare function banPeer(address: string, banTimeInSeconds: number): boolean;\n    /** Unban a single peer */\n    static declare function unbanPeer(address: string): boolean;\n    /** Disconnect a specific peer */\n    static declare function disconnectPeer(nodeid: number): boolean;\n    /** Clear all banned peers */\n    static declare function ClearBanned(): boolean;\n}\n/** Interface to receive updates about network status */\ndeclare class NJSIP2pNetworkListener\n{\n    /** Notify that p2p networking has been enabled */\n    declare function onNetworkEnabled();\n    /** Notify that p2p networking has been disabled */\n    declare function onNetworkDisabled();\n    /** Notify that number of peers has changed */\n    declare function onConnectionCountChanged(numConnections: number);\n    /** Notify that amount of data sent/received has changed */\n    declare function onBytesChanged(totalRecv: number, totalSent: number);\n}\n/** C++ interface to control accounts */\ndeclare class NJSIAccountsController\n{\n    /** Register listener to be notified of account related events */\n    static declare function setListener(accountslistener: NJSIAccountsListener);\n    /** List all currently visible accounts in the wallet */\n    static declare function listAccounts(): Array<AccountRecord>;\n    /** Set the currently active account */\n    static declare function setActiveAccount(accountUUID: string): boolean;\n    /** Get the currently active account */\n    static declare function getActiveAccount(): string;\n    /** Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account */\n    static declare function createAccount(accountName: string, accountType: string): string;\n    /** Check name of account */\n    static declare function getAccountName(accountUUID: string): string;\n    /** Rename an account */\n    static declare function renameAccount(accountUUID: string, newAccountName: string): boolean;\n    /** Delete an account, account remains available in background but is hidden from user */\n    static declare function deleteAccount(accountUUID: string): boolean;\n    /**\n     * Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n     * If it is a Legacy or imported witness key or similar account then it will be gone forever\n     * Generally prefer 'deleteAccount' and use this with caution\n     */\n    static declare function purgeAccount(accountUUID: string): boolean;\n    /** Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure.  */\n    static declare function getAccountLinkURI(accountUUID: string): string;\n    /** Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account */\n    static declare function getWitnessKeyURI(accountUUID: string): string;\n    /**\n     * Create a new \"witness-only\" account from a previously exported URI\n     * Returns UUID on success, empty string on failiure\n     */\n    static declare function createAccountFromWitnessKeyURI(witnessKeyURI: string, newAccountName: string): string;\n    /** Get a receive address for account */\n    static declare function getReceiveAddress(accountUUID: string): string;\n    /** Get list of all transactions account has been involved in */\n    static declare function getTransactionHistory(accountUUID: string): Array<TransactionRecord>;\n    /** Get list of mutations for account */\n    static declare function getMutationHistory(accountUUID: string): Array<MutationRecord>;\n    /** Check balance for active account */\n    static declare function getActiveAccountBalance(): BalanceRecord;\n    /** Check balance for account */\n    static declare function getAccountBalance(accountUUID: string): BalanceRecord;\n    /** Check balance for all accounts, returns a map of account_uuid->balance_record */\n    static declare function getAllAccountBalances(): Map<string, BalanceRecord>;\n    /**Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key) */\n    static declare function addAccountLink(accountUUID: string, serviceName: string, data: string): boolean;\n    /**Register with wallet to remove an existing link */\n    static declare function removeAccountLink(accountUUID: string, serviceName: string): boolean;\n    /**List all active account links that we have previously registered */\n    static declare function listAccountLinks(accountUUID: string): Array<AccountLinkRecord>;\n}\n/** Interface to receive updates about accounts */\ndeclare class NJSIAccountsListener\n{\n    /** Notify that the active account has changed */\n    declare function onActiveAccountChanged(accountUUID: string);\n    /** Notify that the active account name has changed */\n    declare function onActiveAccountNameChanged(newAccountName: string);\n    /** Notify that an account name has changed */\n    declare function onAccountNameChanged(accountUUID: string, newAccountName: string);\n    /** Notify that a new account has been added */\n    declare function onAccountAdded(accountUUID: string, accountName: string);\n    /** Notify that an account has been deleted */\n    declare function onAccountDeleted(accountUUID: string);\n    /** Notify that an account has been modified */\n    declare function onAccountModified(accountUUID: string, accountData: AccountRecord);\n}\n/** C++ interface to control witness accounts */\ndeclare class NJSIWitnessController\n{\n    /** Get information on min/max witness periods, weights etc. */\n    static declare function getNetworkLimits(): Map<string, string>;\n    /** Get an estimate of weights/parts that a witness account will be funded with */\n    static declare function getEstimatedWeight(amount_to_lock: number, lock_period_in_blocks: number): WitnessEstimateInfoRecord;\n    /** Fund a witness account */\n    static declare function fundWitnessAccount(funding_account_UUID: string, witness_account_UUID: string, funding_amount: number, requestedLockPeriodInBlocks: number): WitnessFundingResultRecord;\n    /** Renew a witness account */\n    static declare function renewWitnessAccount(funding_account_UUID: string, witness_account_UUID: string): WitnessFundingResultRecord;\n    /** Get information on account weight and other witness statistics for account */\n    static declare function getAccountWitnessStatistics(witnessAccountUUID: string): WitnessAccountStatisticsRecord;\n    /** Turn compounding on/off */\n    static declare function setAccountCompounding(witnessAccountUUID: string, percent_to_compount: number);\n    /** Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding */\n    static declare function isAccountCompounding(witnessAccountUUID: string): number;\n    /** Get the witness address of the account */\n    static declare function getWitnessAddress(witnessAccountUUID: string): string;\n    /** Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\" */\n    static declare function getOptimalWitnessDistribution(amount: number, durationInBlocks: number, totalNetworkWeight: number): Array<number>;\n    /** Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values */\n    static declare function getOptimalWitnessDistributionForAccount(witnessAccountUUID: string): Array<number>;\n    /** Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this */\n    static declare function optimiseWitnessAccount(witnessAccountUUID: string, fundingAccountUUID: string, optimalDistribution: Array<number>): ResultRecord;\n}\n/** C++ interface to control generation of blocks (proof of work) */\ndeclare class NJSIGenerationController\n{\n    /** Register listener to be notified of generation related events */\n    static declare function setListener(generationListener: NJSIGenerationListener);\n    /**\n     * Activate block generation (proof of work)\n     * Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n     */\n    static declare function startGeneration(numThreads: number, numArenaThreads: number, memoryLimit: string): boolean;\n    /** Stop any active block generation (proof of work) */\n    static declare function stopGeneration(): boolean;\n    /**\n     * Get the address of the account that is used for generation by default. Empty on failiure\n     * Note that this isn't necessarily the actual generation address as there might be an override\n     * See: getGenerationOverrideAddress\n     */\n    static declare function getGenerationAddress(): string;\n    /**\n     * Get the 'override' address for generation, if one has been set\n     * The override address, when present it used for all block generation in place of the default account address\n     */\n    static declare function getGenerationOverrideAddress(): string;\n    /** Set an override address to use for block generation in place of the default */\n    static declare function setGenerationOverrideAddress(overrideAddress: string): boolean;\n    static declare function getAvailableCores(): number;\n    static declare function getMinimumMemory(): number;\n    static declare function getMaximumMemory(): number;\n}\n/** Interface to receive updates about block generation */\ndeclare class NJSIGenerationListener\n{\n    /** Signal that block generation has started */\n    declare function onGenerationStarted();\n    /** Signal that block generation has stopped */\n    declare function onGenerationStopped();\n    /** Periodically signal latest block generation statistics */\n    declare function onStatsUpdated(hashesPerSecond: number, hashesPerSecondUnit: string, rollingHashesPerSecond: number, rollingHashesPerSecondUnit: string, bestHashesPerSecond: number, bestHashesPerSecondUnit: string, arenaSetupTime: number);\n}\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountLinkRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountLinkRecord.h\"\n#include \"account_link_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBAccountLinkRecord;\n\nnamespace djinni_generated {\n\nstruct AccountLinkRecord\n{\n    using CppType = ::AccountLinkRecord;\n    using ObjcType = DBAccountLinkRecord*;\n\n    using Boxed = AccountLinkRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountLinkRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountLinkRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto AccountLinkRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.serviceName),\n            ::djinni::String::toCpp(obj.serviceData)};\n}\n\nauto AccountLinkRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBAccountLinkRecord alloc] initWithServiceName:(::djinni::String::fromCpp(cpp.serviceName))\n                                                serviceData:(::djinni::String::fromCpp(cpp.serviceData))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountLinkRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n/**Data record representing a link between an account and an external service (e.g. Holdin.com) */\n@interface DBAccountLinkRecord : NSObject\n- (nonnull instancetype)initWithServiceName:(nonnull NSString *)serviceName\n                                serviceData:(nonnull NSString *)serviceData;\n+ (nonnull instancetype)accountLinkRecordWithServiceName:(nonnull NSString *)serviceName\n                                             serviceData:(nonnull NSString *)serviceData;\n\n/** What service is it (each service should use a unique string to identify itself)  */\n@property (nonatomic, readonly, nonnull) NSString * serviceName;\n\n/** Any data unique to the service, e.g. a key used for secure communication or similar */\n@property (nonatomic, readonly, nonnull) NSString * serviceData;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountLinkRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountLinkRecord.h\"\n\n\n@implementation DBAccountLinkRecord\n\n- (nonnull instancetype)initWithServiceName:(nonnull NSString *)serviceName\n                                serviceData:(nonnull NSString *)serviceData\n{\n    if (self = [super init]) {\n        _serviceName = [serviceName copy];\n        _serviceData = [serviceData copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)accountLinkRecordWithServiceName:(nonnull NSString *)serviceName\n                                             serviceData:(nonnull NSString *)serviceData\n{\n    return [(DBAccountLinkRecord*)[self alloc] initWithServiceName:serviceName\n                                                       serviceData:serviceData];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p serviceName:%@ serviceData:%@>\", self.class, (void *)self, self.serviceName, self.serviceData];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountRecord.h\"\n#include \"account_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBAccountRecord;\n\nnamespace djinni_generated {\n\nstruct AccountRecord\n{\n    using CppType = ::AccountRecord;\n    using ObjcType = DBAccountRecord*;\n\n    using Boxed = AccountRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountRecord+Private.h\"\n#import \"DBAccountLinkRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto AccountRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.UUID),\n            ::djinni::String::toCpp(obj.label),\n            ::djinni::String::toCpp(obj.state),\n            ::djinni::String::toCpp(obj.type),\n            ::djinni::Bool::toCpp(obj.isHD),\n            ::djinni::List<::djinni_generated::AccountLinkRecord>::toCpp(obj.accountLinks)};\n}\n\nauto AccountRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBAccountRecord alloc] initWithUUID:(::djinni::String::fromCpp(cpp.UUID))\n                                           label:(::djinni::String::fromCpp(cpp.label))\n                                           state:(::djinni::String::fromCpp(cpp.state))\n                                            type:(::djinni::String::fromCpp(cpp.type))\n                                            isHD:(::djinni::Bool::fromCpp(cpp.isHD))\n                                    accountLinks:(::djinni::List<::djinni_generated::AccountLinkRecord>::fromCpp(cpp.accountLinks))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountLinkRecord.h\"\n#import <Foundation/Foundation.h>\n\n@interface DBAccountRecord : NSObject\n- (nonnull instancetype)initWithUUID:(nonnull NSString *)UUID\n                               label:(nonnull NSString *)label\n                               state:(nonnull NSString *)state\n                                type:(nonnull NSString *)type\n                                isHD:(BOOL)isHD\n                        accountLinks:(nonnull NSArray<DBAccountLinkRecord *> *)accountLinks;\n+ (nonnull instancetype)accountRecordWithUUID:(nonnull NSString *)UUID\n                                        label:(nonnull NSString *)label\n                                        state:(nonnull NSString *)state\n                                         type:(nonnull NSString *)type\n                                         isHD:(BOOL)isHD\n                                 accountLinks:(nonnull NSArray<DBAccountLinkRecord *> *)accountLinks;\n\n@property (nonatomic, readonly, nonnull) NSString * UUID;\n\n@property (nonatomic, readonly, nonnull) NSString * label;\n\n@property (nonatomic, readonly, nonnull) NSString * state;\n\n@property (nonatomic, readonly, nonnull) NSString * type;\n\n/**Is this account 'HD' (i.e. part of what can be recovered from a recovery phrase) */\n@property (nonatomic, readonly) BOOL isHD;\n\n/**Has this account been linked to any other services/wallets; if so which see 'account_link_record' for more information */\n@property (nonatomic, readonly, nonnull) NSArray<DBAccountLinkRecord *> * accountLinks;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAccountRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountRecord.h\"\n\n\n@implementation DBAccountRecord\n\n- (nonnull instancetype)initWithUUID:(nonnull NSString *)UUID\n                               label:(nonnull NSString *)label\n                               state:(nonnull NSString *)state\n                                type:(nonnull NSString *)type\n                                isHD:(BOOL)isHD\n                        accountLinks:(nonnull NSArray<DBAccountLinkRecord *> *)accountLinks\n{\n    if (self = [super init]) {\n        _UUID = [UUID copy];\n        _label = [label copy];\n        _state = [state copy];\n        _type = [type copy];\n        _isHD = isHD;\n        _accountLinks = [accountLinks copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)accountRecordWithUUID:(nonnull NSString *)UUID\n                                        label:(nonnull NSString *)label\n                                        state:(nonnull NSString *)state\n                                         type:(nonnull NSString *)type\n                                         isHD:(BOOL)isHD\n                                 accountLinks:(nonnull NSArray<DBAccountLinkRecord *> *)accountLinks\n{\n    return [(DBAccountRecord*)[self alloc] initWithUUID:UUID\n                                                  label:label\n                                                  state:state\n                                                   type:type\n                                                   isHD:isHD\n                                           accountLinks:accountLinks];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p UUID:%@ label:%@ state:%@ type:%@ isHD:%@ accountLinks:%@>\", self.class, (void *)self, self.UUID, self.label, self.state, self.type, @(self.isHD), self.accountLinks];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAddressRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAddressRecord.h\"\n#include \"address_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBAddressRecord;\n\nnamespace djinni_generated {\n\nstruct AddressRecord\n{\n    using CppType = ::AddressRecord;\n    using ObjcType = DBAddressRecord*;\n\n    using Boxed = AddressRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAddressRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAddressRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto AddressRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.address),\n            ::djinni::String::toCpp(obj.name),\n            ::djinni::String::toCpp(obj.desc),\n            ::djinni::String::toCpp(obj.purpose)};\n}\n\nauto AddressRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBAddressRecord alloc] initWithAddress:(::djinni::String::fromCpp(cpp.address))\n                                               name:(::djinni::String::fromCpp(cpp.name))\n                                               desc:(::djinni::String::fromCpp(cpp.desc))\n                                            purpose:(::djinni::String::fromCpp(cpp.purpose))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAddressRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBAddressRecord : NSObject\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                                   name:(nonnull NSString *)name\n                                   desc:(nonnull NSString *)desc\n                                purpose:(nonnull NSString *)purpose;\n+ (nonnull instancetype)addressRecordWithAddress:(nonnull NSString *)address\n                                            name:(nonnull NSString *)name\n                                            desc:(nonnull NSString *)desc\n                                         purpose:(nonnull NSString *)purpose;\n\n@property (nonatomic, readonly, nonnull) NSString * address;\n\n@property (nonatomic, readonly, nonnull) NSString * name;\n\n@property (nonatomic, readonly, nonnull) NSString * desc;\n\n@property (nonatomic, readonly, nonnull) NSString * purpose;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBAddressRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAddressRecord.h\"\n\n\n@implementation DBAddressRecord\n\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                                   name:(nonnull NSString *)name\n                                   desc:(nonnull NSString *)desc\n                                purpose:(nonnull NSString *)purpose\n{\n    if (self = [super init]) {\n        _address = [address copy];\n        _name = [name copy];\n        _desc = [desc copy];\n        _purpose = [purpose copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)addressRecordWithAddress:(nonnull NSString *)address\n                                            name:(nonnull NSString *)name\n                                            desc:(nonnull NSString *)desc\n                                         purpose:(nonnull NSString *)purpose\n{\n    return [(DBAddressRecord*)[self alloc] initWithAddress:address\n                                                      name:name\n                                                      desc:desc\n                                                   purpose:purpose];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p address:%@ name:%@ desc:%@ purpose:%@>\", self.class, (void *)self, self.address, self.name, self.desc, self.purpose];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBalanceRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord.h\"\n#include \"balance_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBBalanceRecord;\n\nnamespace djinni_generated {\n\nstruct BalanceRecord\n{\n    using CppType = ::BalanceRecord;\n    using ObjcType = DBBalanceRecord*;\n\n    using Boxed = BalanceRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBalanceRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto BalanceRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I64::toCpp(obj.availableIncludingLocked),\n            ::djinni::I64::toCpp(obj.availableExcludingLocked),\n            ::djinni::I64::toCpp(obj.availableLocked),\n            ::djinni::I64::toCpp(obj.unconfirmedIncludingLocked),\n            ::djinni::I64::toCpp(obj.unconfirmedExcludingLocked),\n            ::djinni::I64::toCpp(obj.unconfirmedLocked),\n            ::djinni::I64::toCpp(obj.immatureIncludingLocked),\n            ::djinni::I64::toCpp(obj.immatureExcludingLocked),\n            ::djinni::I64::toCpp(obj.immatureLocked),\n            ::djinni::I64::toCpp(obj.totalLocked)};\n}\n\nauto BalanceRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBBalanceRecord alloc] initWithAvailableIncludingLocked:(::djinni::I64::fromCpp(cpp.availableIncludingLocked))\n                                            availableExcludingLocked:(::djinni::I64::fromCpp(cpp.availableExcludingLocked))\n                                                     availableLocked:(::djinni::I64::fromCpp(cpp.availableLocked))\n                                          unconfirmedIncludingLocked:(::djinni::I64::fromCpp(cpp.unconfirmedIncludingLocked))\n                                          unconfirmedExcludingLocked:(::djinni::I64::fromCpp(cpp.unconfirmedExcludingLocked))\n                                                   unconfirmedLocked:(::djinni::I64::fromCpp(cpp.unconfirmedLocked))\n                                             immatureIncludingLocked:(::djinni::I64::fromCpp(cpp.immatureIncludingLocked))\n                                             immatureExcludingLocked:(::djinni::I64::fromCpp(cpp.immatureExcludingLocked))\n                                                      immatureLocked:(::djinni::I64::fromCpp(cpp.immatureLocked))\n                                                         totalLocked:(::djinni::I64::fromCpp(cpp.totalLocked))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBalanceRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBBalanceRecord : NSObject\n- (nonnull instancetype)initWithAvailableIncludingLocked:(int64_t)availableIncludingLocked\n                                availableExcludingLocked:(int64_t)availableExcludingLocked\n                                         availableLocked:(int64_t)availableLocked\n                              unconfirmedIncludingLocked:(int64_t)unconfirmedIncludingLocked\n                              unconfirmedExcludingLocked:(int64_t)unconfirmedExcludingLocked\n                                       unconfirmedLocked:(int64_t)unconfirmedLocked\n                                 immatureIncludingLocked:(int64_t)immatureIncludingLocked\n                                 immatureExcludingLocked:(int64_t)immatureExcludingLocked\n                                          immatureLocked:(int64_t)immatureLocked\n                                             totalLocked:(int64_t)totalLocked;\n+ (nonnull instancetype)balanceRecordWithAvailableIncludingLocked:(int64_t)availableIncludingLocked\n                                         availableExcludingLocked:(int64_t)availableExcludingLocked\n                                                  availableLocked:(int64_t)availableLocked\n                                       unconfirmedIncludingLocked:(int64_t)unconfirmedIncludingLocked\n                                       unconfirmedExcludingLocked:(int64_t)unconfirmedExcludingLocked\n                                                unconfirmedLocked:(int64_t)unconfirmedLocked\n                                          immatureIncludingLocked:(int64_t)immatureIncludingLocked\n                                          immatureExcludingLocked:(int64_t)immatureExcludingLocked\n                                                   immatureLocked:(int64_t)immatureLocked\n                                                      totalLocked:(int64_t)totalLocked;\n\n@property (nonatomic, readonly) int64_t availableIncludingLocked;\n\n@property (nonatomic, readonly) int64_t availableExcludingLocked;\n\n@property (nonatomic, readonly) int64_t availableLocked;\n\n@property (nonatomic, readonly) int64_t unconfirmedIncludingLocked;\n\n@property (nonatomic, readonly) int64_t unconfirmedExcludingLocked;\n\n@property (nonatomic, readonly) int64_t unconfirmedLocked;\n\n@property (nonatomic, readonly) int64_t immatureIncludingLocked;\n\n@property (nonatomic, readonly) int64_t immatureExcludingLocked;\n\n@property (nonatomic, readonly) int64_t immatureLocked;\n\n@property (nonatomic, readonly) int64_t totalLocked;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBalanceRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord.h\"\n\n\n@implementation DBBalanceRecord\n\n- (nonnull instancetype)initWithAvailableIncludingLocked:(int64_t)availableIncludingLocked\n                                availableExcludingLocked:(int64_t)availableExcludingLocked\n                                         availableLocked:(int64_t)availableLocked\n                              unconfirmedIncludingLocked:(int64_t)unconfirmedIncludingLocked\n                              unconfirmedExcludingLocked:(int64_t)unconfirmedExcludingLocked\n                                       unconfirmedLocked:(int64_t)unconfirmedLocked\n                                 immatureIncludingLocked:(int64_t)immatureIncludingLocked\n                                 immatureExcludingLocked:(int64_t)immatureExcludingLocked\n                                          immatureLocked:(int64_t)immatureLocked\n                                             totalLocked:(int64_t)totalLocked\n{\n    if (self = [super init]) {\n        _availableIncludingLocked = availableIncludingLocked;\n        _availableExcludingLocked = availableExcludingLocked;\n        _availableLocked = availableLocked;\n        _unconfirmedIncludingLocked = unconfirmedIncludingLocked;\n        _unconfirmedExcludingLocked = unconfirmedExcludingLocked;\n        _unconfirmedLocked = unconfirmedLocked;\n        _immatureIncludingLocked = immatureIncludingLocked;\n        _immatureExcludingLocked = immatureExcludingLocked;\n        _immatureLocked = immatureLocked;\n        _totalLocked = totalLocked;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)balanceRecordWithAvailableIncludingLocked:(int64_t)availableIncludingLocked\n                                         availableExcludingLocked:(int64_t)availableExcludingLocked\n                                                  availableLocked:(int64_t)availableLocked\n                                       unconfirmedIncludingLocked:(int64_t)unconfirmedIncludingLocked\n                                       unconfirmedExcludingLocked:(int64_t)unconfirmedExcludingLocked\n                                                unconfirmedLocked:(int64_t)unconfirmedLocked\n                                          immatureIncludingLocked:(int64_t)immatureIncludingLocked\n                                          immatureExcludingLocked:(int64_t)immatureExcludingLocked\n                                                   immatureLocked:(int64_t)immatureLocked\n                                                      totalLocked:(int64_t)totalLocked\n{\n    return [(DBBalanceRecord*)[self alloc] initWithAvailableIncludingLocked:availableIncludingLocked\n                                                   availableExcludingLocked:availableExcludingLocked\n                                                            availableLocked:availableLocked\n                                                 unconfirmedIncludingLocked:unconfirmedIncludingLocked\n                                                 unconfirmedExcludingLocked:unconfirmedExcludingLocked\n                                                          unconfirmedLocked:unconfirmedLocked\n                                                    immatureIncludingLocked:immatureIncludingLocked\n                                                    immatureExcludingLocked:immatureExcludingLocked\n                                                             immatureLocked:immatureLocked\n                                                                totalLocked:totalLocked];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p availableIncludingLocked:%@ availableExcludingLocked:%@ availableLocked:%@ unconfirmedIncludingLocked:%@ unconfirmedExcludingLocked:%@ unconfirmedLocked:%@ immatureIncludingLocked:%@ immatureExcludingLocked:%@ immatureLocked:%@ totalLocked:%@>\", self.class, (void *)self, @(self.availableIncludingLocked), @(self.availableExcludingLocked), @(self.availableLocked), @(self.unconfirmedIncludingLocked), @(self.unconfirmedExcludingLocked), @(self.unconfirmedLocked), @(self.immatureIncludingLocked), @(self.immatureExcludingLocked), @(self.immatureLocked), @(self.totalLocked)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBannedPeerRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBannedPeerRecord.h\"\n#include \"banned_peer_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBBannedPeerRecord;\n\nnamespace djinni_generated {\n\nstruct BannedPeerRecord\n{\n    using CppType = ::BannedPeerRecord;\n    using ObjcType = DBBannedPeerRecord*;\n\n    using Boxed = BannedPeerRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBannedPeerRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBannedPeerRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto BannedPeerRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.address),\n            ::djinni::I64::toCpp(obj.bannedUntil),\n            ::djinni::I64::toCpp(obj.bannedFrom),\n            ::djinni::String::toCpp(obj.reason)};\n}\n\nauto BannedPeerRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBBannedPeerRecord alloc] initWithAddress:(::djinni::String::fromCpp(cpp.address))\n                                           bannedUntil:(::djinni::I64::fromCpp(cpp.banned_until))\n                                            bannedFrom:(::djinni::I64::fromCpp(cpp.banned_from))\n                                                reason:(::djinni::String::fromCpp(cpp.reason))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBannedPeerRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBBannedPeerRecord : NSObject\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                            bannedUntil:(int64_t)bannedUntil\n                             bannedFrom:(int64_t)bannedFrom\n                                 reason:(nonnull NSString *)reason;\n+ (nonnull instancetype)bannedPeerRecordWithAddress:(nonnull NSString *)address\n                                        bannedUntil:(int64_t)bannedUntil\n                                         bannedFrom:(int64_t)bannedFrom\n                                             reason:(nonnull NSString *)reason;\n\n@property (nonatomic, readonly, nonnull) NSString * address;\n\n@property (nonatomic, readonly) int64_t bannedUntil;\n\n@property (nonatomic, readonly) int64_t bannedFrom;\n\n@property (nonatomic, readonly, nonnull) NSString * reason;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBannedPeerRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBannedPeerRecord.h\"\n\n\n@implementation DBBannedPeerRecord\n\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                            bannedUntil:(int64_t)bannedUntil\n                             bannedFrom:(int64_t)bannedFrom\n                                 reason:(nonnull NSString *)reason\n{\n    if (self = [super init]) {\n        _address = [address copy];\n        _bannedUntil = bannedUntil;\n        _bannedFrom = bannedFrom;\n        _reason = [reason copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)bannedPeerRecordWithAddress:(nonnull NSString *)address\n                                        bannedUntil:(int64_t)bannedUntil\n                                         bannedFrom:(int64_t)bannedFrom\n                                             reason:(nonnull NSString *)reason\n{\n    return [(DBBannedPeerRecord*)[self alloc] initWithAddress:address\n                                                  bannedUntil:bannedUntil\n                                                   bannedFrom:bannedFrom\n                                                       reason:reason];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p address:%@ bannedUntil:%@ bannedFrom:%@ reason:%@>\", self.class, (void *)self, self.address, @(self.bannedUntil), @(self.bannedFrom), self.reason];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBlockInfoRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBlockInfoRecord.h\"\n#include \"block_info_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBBlockInfoRecord;\n\nnamespace djinni_generated {\n\nstruct BlockInfoRecord\n{\n    using CppType = ::BlockInfoRecord;\n    using ObjcType = DBBlockInfoRecord*;\n\n    using Boxed = BlockInfoRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBlockInfoRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBlockInfoRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto BlockInfoRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I32::toCpp(obj.height),\n            ::djinni::I64::toCpp(obj.timeStamp),\n            ::djinni::String::toCpp(obj.blockHash)};\n}\n\nauto BlockInfoRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBBlockInfoRecord alloc] initWithHeight:(::djinni::I32::fromCpp(cpp.height))\n                                           timeStamp:(::djinni::I64::fromCpp(cpp.timeStamp))\n                                           blockHash:(::djinni::String::fromCpp(cpp.blockHash))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBlockInfoRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBBlockInfoRecord : NSObject\n- (nonnull instancetype)initWithHeight:(int32_t)height\n                             timeStamp:(int64_t)timeStamp\n                             blockHash:(nonnull NSString *)blockHash;\n+ (nonnull instancetype)blockInfoRecordWithHeight:(int32_t)height\n                                        timeStamp:(int64_t)timeStamp\n                                        blockHash:(nonnull NSString *)blockHash;\n\n@property (nonatomic, readonly) int32_t height;\n\n@property (nonatomic, readonly) int64_t timeStamp;\n\n@property (nonatomic, readonly, nonnull) NSString * blockHash;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBBlockInfoRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBlockInfoRecord.h\"\n\n\n@implementation DBBlockInfoRecord\n\n- (nonnull instancetype)initWithHeight:(int32_t)height\n                             timeStamp:(int64_t)timeStamp\n                             blockHash:(nonnull NSString *)blockHash\n{\n    if (self = [super init]) {\n        _height = height;\n        _timeStamp = timeStamp;\n        _blockHash = [blockHash copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)blockInfoRecordWithHeight:(int32_t)height\n                                        timeStamp:(int64_t)timeStamp\n                                        blockHash:(nonnull NSString *)blockHash\n{\n    return [(DBBlockInfoRecord*)[self alloc] initWithHeight:height\n                                                  timeStamp:timeStamp\n                                                  blockHash:blockHash];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p height:%@ timeStamp:%@ blockHash:%@>\", self.class, (void *)self, @(self.height), @(self.timeStamp), self.blockHash];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_accounts_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIAccountsController;\n\nnamespace djinni_generated {\n\nclass IAccountsController\n{\npublic:\n    using CppType = std::shared_ptr<::IAccountsController>;\n    using CppOptType = std::shared_ptr<::IAccountsController>;\n    using ObjcType = DBIAccountsController*;\n\n    using Boxed = IAccountsController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIAccountsController+Private.h\"\n#import \"DBIAccountsController.h\"\n#import \"DBAccountLinkRecord+Private.h\"\n#import \"DBAccountRecord+Private.h\"\n#import \"DBBalanceRecord+Private.h\"\n#import \"DBIAccountsListener+Private.h\"\n#import \"DBMutationRecord+Private.h\"\n#import \"DBTransactionRecord+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIAccountsController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IAccountsController>&)cppRef;\n\n@end\n\n@implementation DBIAccountsController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IAccountsController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IAccountsController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (void)setListener:(nullable id<DBIAccountsListener>)accountslistener {\n    try {\n        ::IAccountsController::setListener(::djinni_generated::IAccountsListener::toCpp(accountslistener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBAccountRecord *> *)listAccounts {\n    try {\n        auto objcpp_result_ = ::IAccountsController::listAccounts();\n        return ::djinni::List<::djinni_generated::AccountRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)setActiveAccount:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::setActiveAccount(::djinni::String::toCpp(accountUUID));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getActiveAccount {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getActiveAccount();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)createAccount:(nonnull NSString *)accountName\n                        accountType:(nonnull NSString *)accountType {\n    try {\n        auto objcpp_result_ = ::IAccountsController::createAccount(::djinni::String::toCpp(accountName),\n                                                                   ::djinni::String::toCpp(accountType));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getAccountName:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getAccountName(::djinni::String::toCpp(accountUUID));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)renameAccount:(nonnull NSString *)accountUUID\n       newAccountName:(nonnull NSString *)newAccountName {\n    try {\n        auto objcpp_result_ = ::IAccountsController::renameAccount(::djinni::String::toCpp(accountUUID),\n                                                                   ::djinni::String::toCpp(newAccountName));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)deleteAccount:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::deleteAccount(::djinni::String::toCpp(accountUUID));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)purgeAccount:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::purgeAccount(::djinni::String::toCpp(accountUUID));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getAccountLinkURI:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getAccountLinkURI(::djinni::String::toCpp(accountUUID));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getWitnessKeyURI:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getWitnessKeyURI(::djinni::String::toCpp(accountUUID));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)createAccountFromWitnessKeyURI:(nonnull NSString *)witnessKeyURI\n                                      newAccountName:(nonnull NSString *)newAccountName {\n    try {\n        auto objcpp_result_ = ::IAccountsController::createAccountFromWitnessKeyURI(::djinni::String::toCpp(witnessKeyURI),\n                                                                                    ::djinni::String::toCpp(newAccountName));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getReceiveAddress:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getReceiveAddress(::djinni::String::toCpp(accountUUID));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBTransactionRecord *> *)getTransactionHistory:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getTransactionHistory(::djinni::String::toCpp(accountUUID));\n        return ::djinni::List<::djinni_generated::TransactionRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBMutationRecord *> *)getMutationHistory:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getMutationHistory(::djinni::String::toCpp(accountUUID));\n        return ::djinni::List<::djinni_generated::MutationRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBBalanceRecord *)getActiveAccountBalance {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getActiveAccountBalance();\n        return ::djinni_generated::BalanceRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBBalanceRecord *)getAccountBalance:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getAccountBalance(::djinni::String::toCpp(accountUUID));\n        return ::djinni_generated::BalanceRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSDictionary<NSString *, DBBalanceRecord *> *)getAllAccountBalances {\n    try {\n        auto objcpp_result_ = ::IAccountsController::getAllAccountBalances();\n        return ::djinni::Map<::djinni::String, ::djinni_generated::BalanceRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)addAccountLink:(nonnull NSString *)accountUUID\n           serviceName:(nonnull NSString *)serviceName\n                  data:(nonnull NSString *)data {\n    try {\n        auto objcpp_result_ = ::IAccountsController::addAccountLink(::djinni::String::toCpp(accountUUID),\n                                                                    ::djinni::String::toCpp(serviceName),\n                                                                    ::djinni::String::toCpp(data));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)removeAccountLink:(nonnull NSString *)accountUUID\n              serviceName:(nonnull NSString *)serviceName {\n    try {\n        auto objcpp_result_ = ::IAccountsController::removeAccountLink(::djinni::String::toCpp(accountUUID),\n                                                                       ::djinni::String::toCpp(serviceName));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBAccountLinkRecord *> *)listAccountLinks:(nonnull NSString *)accountUUID {\n    try {\n        auto objcpp_result_ = ::IAccountsController::listAccountLinks(::djinni::String::toCpp(accountUUID));\n        return ::djinni::List<::djinni_generated::AccountLinkRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IAccountsController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IAccountsController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIAccountsController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountLinkRecord.h\"\n#import \"DBAccountRecord.h\"\n#import \"DBBalanceRecord.h\"\n#import \"DBMutationRecord.h\"\n#import \"DBTransactionRecord.h\"\n#import <Foundation/Foundation.h>\n@protocol DBIAccountsListener;\n\n\n/** C++ interface to control accounts */\n@interface DBIAccountsController : NSObject\n\n/** Register listener to be notified of account related events */\n+ (void)setListener:(nullable id<DBIAccountsListener>)accountslistener;\n\n/** List all currently visible accounts in the wallet */\n+ (nonnull NSArray<DBAccountRecord *> *)listAccounts;\n\n/** Set the currently active account */\n+ (BOOL)setActiveAccount:(nonnull NSString *)accountUUID;\n\n/** Get the currently active account */\n+ (nonnull NSString *)getActiveAccount;\n\n/** Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account */\n+ (nonnull NSString *)createAccount:(nonnull NSString *)accountName\n                        accountType:(nonnull NSString *)accountType;\n\n/** Check name of account */\n+ (nonnull NSString *)getAccountName:(nonnull NSString *)accountUUID;\n\n/** Rename an account */\n+ (BOOL)renameAccount:(nonnull NSString *)accountUUID\n       newAccountName:(nonnull NSString *)newAccountName;\n\n/** Delete an account, account remains available in background but is hidden from user */\n+ (BOOL)deleteAccount:(nonnull NSString *)accountUUID;\n\n/**\n * Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n * If it is a Legacy or imported witness key or similar account then it will be gone forever\n * Generally prefer 'deleteAccount' and use this with caution\n */\n+ (BOOL)purgeAccount:(nonnull NSString *)accountUUID;\n\n/** Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure.  */\n+ (nonnull NSString *)getAccountLinkURI:(nonnull NSString *)accountUUID;\n\n/** Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account */\n+ (nonnull NSString *)getWitnessKeyURI:(nonnull NSString *)accountUUID;\n\n/**\n * Create a new \"witness-only\" account from a previously exported URI\n * Returns UUID on success, empty string on failiure\n */\n+ (nonnull NSString *)createAccountFromWitnessKeyURI:(nonnull NSString *)witnessKeyURI\n                                      newAccountName:(nonnull NSString *)newAccountName;\n\n/** Get a receive address for account */\n+ (nonnull NSString *)getReceiveAddress:(nonnull NSString *)accountUUID;\n\n/** Get list of all transactions account has been involved in */\n+ (nonnull NSArray<DBTransactionRecord *> *)getTransactionHistory:(nonnull NSString *)accountUUID;\n\n/** Get list of mutations for account */\n+ (nonnull NSArray<DBMutationRecord *> *)getMutationHistory:(nonnull NSString *)accountUUID;\n\n/** Check balance for active account */\n+ (nonnull DBBalanceRecord *)getActiveAccountBalance;\n\n/** Check balance for account */\n+ (nonnull DBBalanceRecord *)getAccountBalance:(nonnull NSString *)accountUUID;\n\n/** Check balance for all accounts, returns a map of account_uuid->balance_record */\n+ (nonnull NSDictionary<NSString *, DBBalanceRecord *> *)getAllAccountBalances;\n\n/**Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key) */\n+ (BOOL)addAccountLink:(nonnull NSString *)accountUUID\n           serviceName:(nonnull NSString *)serviceName\n                  data:(nonnull NSString *)data;\n\n/**Register with wallet to remove an existing link */\n+ (BOOL)removeAccountLink:(nonnull NSString *)accountUUID\n              serviceName:(nonnull NSString *)serviceName;\n\n/**List all active account links that we have previously registered */\n+ (nonnull NSArray<DBAccountLinkRecord *> *)listAccountLinks:(nonnull NSString *)accountUUID;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_accounts_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBIAccountsListener;\n\nnamespace djinni_generated {\n\nclass IAccountsListener\n{\npublic:\n    using CppType = std::shared_ptr<::IAccountsListener>;\n    using CppOptType = std::shared_ptr<::IAccountsListener>;\n    using ObjcType = id<DBIAccountsListener>;\n\n    using Boxed = IAccountsListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIAccountsListener+Private.h\"\n#import \"DBIAccountsListener.h\"\n#import \"DBAccountRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass IAccountsListener::ObjcProxy final\n: public ::IAccountsListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::IAccountsListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void onActiveAccountChanged(const std::string & c_accountUUID) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onActiveAccountChanged:(::djinni::String::fromCpp(c_accountUUID))];\n        }\n    }\n    void onActiveAccountNameChanged(const std::string & c_newAccountName) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onActiveAccountNameChanged:(::djinni::String::fromCpp(c_newAccountName))];\n        }\n    }\n    void onAccountNameChanged(const std::string & c_accountUUID, const std::string & c_newAccountName) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onAccountNameChanged:(::djinni::String::fromCpp(c_accountUUID))\n                                                            newAccountName:(::djinni::String::fromCpp(c_newAccountName))];\n        }\n    }\n    void onAccountAdded(const std::string & c_accountUUID, const std::string & c_accountName) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onAccountAdded:(::djinni::String::fromCpp(c_accountUUID))\n                                                         accountName:(::djinni::String::fromCpp(c_accountName))];\n        }\n    }\n    void onAccountDeleted(const std::string & c_accountUUID) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onAccountDeleted:(::djinni::String::fromCpp(c_accountUUID))];\n        }\n    }\n    void onAccountModified(const std::string & c_accountUUID, const ::AccountRecord & c_accountData) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onAccountModified:(::djinni::String::fromCpp(c_accountUUID))\n                                                            accountData:(::djinni_generated::AccountRecord::fromCpp(c_accountData))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto IAccountsListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto IAccountsListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIAccountsListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAccountRecord.h\"\n#import <Foundation/Foundation.h>\n\n\n/** Interface to receive updates about accounts */\n@protocol DBIAccountsListener\n\n/** Notify that the active account has changed */\n- (void)onActiveAccountChanged:(nonnull NSString *)accountUUID;\n\n/** Notify that the active account name has changed */\n- (void)onActiveAccountNameChanged:(nonnull NSString *)newAccountName;\n\n/** Notify that an account name has changed */\n- (void)onAccountNameChanged:(nonnull NSString *)accountUUID\n              newAccountName:(nonnull NSString *)newAccountName;\n\n/** Notify that a new account has been added */\n- (void)onAccountAdded:(nonnull NSString *)accountUUID\n           accountName:(nonnull NSString *)accountName;\n\n/** Notify that an account has been deleted */\n- (void)onAccountDeleted:(nonnull NSString *)accountUUID;\n\n/** Notify that an account has been modified */\n- (void)onAccountModified:(nonnull NSString *)accountUUID\n              accountData:(nonnull DBAccountRecord *)accountData;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_generation_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIGenerationController;\n\nnamespace djinni_generated {\n\nclass IGenerationController\n{\npublic:\n    using CppType = std::shared_ptr<::IGenerationController>;\n    using CppOptType = std::shared_ptr<::IGenerationController>;\n    using ObjcType = DBIGenerationController*;\n\n    using Boxed = IGenerationController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIGenerationController+Private.h\"\n#import \"DBIGenerationController.h\"\n#import \"DBIGenerationListener+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIGenerationController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IGenerationController>&)cppRef;\n\n@end\n\n@implementation DBIGenerationController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IGenerationController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IGenerationController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (void)setListener:(nullable id<DBIGenerationListener>)generationListener {\n    try {\n        ::IGenerationController::setListener(::djinni_generated::IGenerationListener::toCpp(generationListener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)startGeneration:(int32_t)numThreads\n        numArenaThreads:(int32_t)numArenaThreads\n            memoryLimit:(nonnull NSString *)memoryLimit {\n    try {\n        auto objcpp_result_ = ::IGenerationController::startGeneration(::djinni::I32::toCpp(numThreads),\n                                                                       ::djinni::I32::toCpp(numArenaThreads),\n                                                                       ::djinni::String::toCpp(memoryLimit));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)stopGeneration {\n    try {\n        auto objcpp_result_ = ::IGenerationController::stopGeneration();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getGenerationAddress {\n    try {\n        auto objcpp_result_ = ::IGenerationController::getGenerationAddress();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getGenerationOverrideAddress {\n    try {\n        auto objcpp_result_ = ::IGenerationController::getGenerationOverrideAddress();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)setGenerationOverrideAddress:(nonnull NSString *)overrideAddress {\n    try {\n        auto objcpp_result_ = ::IGenerationController::setGenerationOverrideAddress(::djinni::String::toCpp(overrideAddress));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)getAvailableCores {\n    try {\n        auto objcpp_result_ = ::IGenerationController::getAvailableCores();\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)getMinimumMemory {\n    try {\n        auto objcpp_result_ = ::IGenerationController::getMinimumMemory();\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)getMaximumMemory {\n    try {\n        auto objcpp_result_ = ::IGenerationController::getMaximumMemory();\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IGenerationController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IGenerationController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIGenerationController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n@protocol DBIGenerationListener;\n\n\n/** C++ interface to control generation of blocks (proof of work) */\n@interface DBIGenerationController : NSObject\n\n/** Register listener to be notified of generation related events */\n+ (void)setListener:(nullable id<DBIGenerationListener>)generationListener;\n\n/**\n * Activate block generation (proof of work)\n * Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n */\n+ (BOOL)startGeneration:(int32_t)numThreads\n        numArenaThreads:(int32_t)numArenaThreads\n            memoryLimit:(nonnull NSString *)memoryLimit;\n\n/** Stop any active block generation (proof of work) */\n+ (BOOL)stopGeneration;\n\n/**\n * Get the address of the account that is used for generation by default. Empty on failiure\n * Note that this isn't necessarily the actual generation address as there might be an override\n * See: getGenerationOverrideAddress\n */\n+ (nonnull NSString *)getGenerationAddress;\n\n/**\n * Get the 'override' address for generation, if one has been set\n * The override address, when present it used for all block generation in place of the default account address\n */\n+ (nonnull NSString *)getGenerationOverrideAddress;\n\n/** Set an override address to use for block generation in place of the default */\n+ (BOOL)setGenerationOverrideAddress:(nonnull NSString *)overrideAddress;\n\n+ (int64_t)getAvailableCores;\n\n+ (int64_t)getMinimumMemory;\n\n+ (int64_t)getMaximumMemory;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_generation_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBIGenerationListener;\n\nnamespace djinni_generated {\n\nclass IGenerationListener\n{\npublic:\n    using CppType = std::shared_ptr<::IGenerationListener>;\n    using CppOptType = std::shared_ptr<::IGenerationListener>;\n    using ObjcType = id<DBIGenerationListener>;\n\n    using Boxed = IGenerationListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIGenerationListener+Private.h\"\n#import \"DBIGenerationListener.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass IGenerationListener::ObjcProxy final\n: public ::IGenerationListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::IGenerationListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void onGenerationStarted() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onGenerationStarted];\n        }\n    }\n    void onGenerationStopped() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onGenerationStopped];\n        }\n    }\n    void onStatsUpdated(double c_hashesPerSecond, const std::string & c_hashesPerSecondUnit, double c_rollingHashesPerSecond, const std::string & c_rollingHashesPerSecondUnit, double c_bestHashesPerSecond, const std::string & c_bestHashesPerSecondUnit, double c_arenaSetupTime) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onStatsUpdated:(::djinni::F64::fromCpp(c_hashesPerSecond))\n                                                 hashesPerSecondUnit:(::djinni::String::fromCpp(c_hashesPerSecondUnit))\n                                              rollingHashesPerSecond:(::djinni::F64::fromCpp(c_rollingHashesPerSecond))\n                                          rollingHashesPerSecondUnit:(::djinni::String::fromCpp(c_rollingHashesPerSecondUnit))\n                                                 bestHashesPerSecond:(::djinni::F64::fromCpp(c_bestHashesPerSecond))\n                                             bestHashesPerSecondUnit:(::djinni::String::fromCpp(c_bestHashesPerSecondUnit))\n                                                      arenaSetupTime:(::djinni::F64::fromCpp(c_arenaSetupTime))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto IGenerationListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto IGenerationListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIGenerationListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n\n/** Interface to receive updates about block generation */\n@protocol DBIGenerationListener\n\n/** Signal that block generation has started */\n- (void)onGenerationStarted;\n\n/** Signal that block generation has stopped */\n- (void)onGenerationStopped;\n\n/** Periodically signal latest block generation statistics */\n- (void)onStatsUpdated:(double)hashesPerSecond\n   hashesPerSecondUnit:(nonnull NSString *)hashesPerSecondUnit\nrollingHashesPerSecond:(double)rollingHashesPerSecond\nrollingHashesPerSecondUnit:(nonnull NSString *)rollingHashesPerSecondUnit\n   bestHashesPerSecond:(double)bestHashesPerSecond\nbestHashesPerSecondUnit:(nonnull NSString *)bestHashesPerSecondUnit\n        arenaSetupTime:(double)arenaSetupTime;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_library_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBILibraryController;\n\nnamespace djinni_generated {\n\nclass ILibraryController\n{\npublic:\n    using CppType = std::shared_ptr<::ILibraryController>;\n    using CppOptType = std::shared_ptr<::ILibraryController>;\n    using ObjcType = DBILibraryController*;\n\n    using Boxed = ILibraryController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBILibraryController+Private.h\"\n#import \"DBILibraryController.h\"\n#import \"DBAddressRecord+Private.h\"\n#import \"DBBlockInfoRecord+Private.h\"\n#import \"DBILibraryListener+Private.h\"\n#import \"DBLegacyWalletResult+Private.h\"\n#import \"DBMnemonicRecord+Private.h\"\n#import \"DBMonitorListener+Private.h\"\n#import \"DBMonitorRecord+Private.h\"\n#import \"DBMutationRecord+Private.h\"\n#import \"DBPaymentResultStatus+Private.h\"\n#import \"DBQrCodeRecord+Private.h\"\n#import \"DBTransactionRecord+Private.h\"\n#import \"DBUriRecipient+Private.h\"\n#import \"DBUriRecord+Private.h\"\n#import \"DBWalletLockStatus+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBILibraryController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::ILibraryController>&)cppRef;\n\n@end\n\n@implementation DBILibraryController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::ILibraryController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::ILibraryController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (nonnull NSString *)BuildInfo {\n    try {\n        auto objcpp_result_ = ::ILibraryController::BuildInfo();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int32_t)InitUnityLib:(nonnull NSString *)dataDir\n       staticFilterPath:(nonnull NSString *)staticFilterPath\n     staticFilterOffset:(int64_t)staticFilterOffset\n     staticFilterLength:(int64_t)staticFilterLength\n                testnet:(BOOL)testnet\n                spvMode:(BOOL)spvMode\n          signalHandler:(nullable id<DBILibraryListener>)signalHandler\n              extraArgs:(nonnull NSString *)extraArgs {\n    try {\n        auto objcpp_result_ = ::ILibraryController::InitUnityLib(::djinni::String::toCpp(dataDir),\n                                                                 ::djinni::String::toCpp(staticFilterPath),\n                                                                 ::djinni::I64::toCpp(staticFilterOffset),\n                                                                 ::djinni::I64::toCpp(staticFilterLength),\n                                                                 ::djinni::Bool::toCpp(testnet),\n                                                                 ::djinni::Bool::toCpp(spvMode),\n                                                                 ::djinni_generated::ILibraryListener::toCpp(signalHandler),\n                                                                 ::djinni::String::toCpp(extraArgs));\n        return ::djinni::I32::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)InitUnityLibThreaded:(nonnull NSString *)dataDir\n            staticFilterPath:(nonnull NSString *)staticFilterPath\n          staticFilterOffset:(int64_t)staticFilterOffset\n          staticFilterLength:(int64_t)staticFilterLength\n                     testnet:(BOOL)testnet\n                     spvMode:(BOOL)spvMode\n               signalHandler:(nullable id<DBILibraryListener>)signalHandler\n                   extraArgs:(nonnull NSString *)extraArgs {\n    try {\n        ::ILibraryController::InitUnityLibThreaded(::djinni::String::toCpp(dataDir),\n                                                   ::djinni::String::toCpp(staticFilterPath),\n                                                   ::djinni::I64::toCpp(staticFilterOffset),\n                                                   ::djinni::I64::toCpp(staticFilterLength),\n                                                   ::djinni::Bool::toCpp(testnet),\n                                                   ::djinni::Bool::toCpp(spvMode),\n                                                   ::djinni_generated::ILibraryListener::toCpp(signalHandler),\n                                                   ::djinni::String::toCpp(extraArgs));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)InitWalletFromRecoveryPhrase:(nonnull NSString *)phrase\n                            password:(nonnull NSString *)password {\n    try {\n        auto objcpp_result_ = ::ILibraryController::InitWalletFromRecoveryPhrase(::djinni::String::toCpp(phrase),\n                                                                                 ::djinni::String::toCpp(password));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)ContinueWalletFromRecoveryPhrase:(nonnull NSString *)phrase\n                                password:(nonnull NSString *)password {\n    try {\n        auto objcpp_result_ = ::ILibraryController::ContinueWalletFromRecoveryPhrase(::djinni::String::toCpp(phrase),\n                                                                                     ::djinni::String::toCpp(password));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)InitWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                       password:(nonnull NSString *)password {\n    try {\n        auto objcpp_result_ = ::ILibraryController::InitWalletLinkedFromURI(::djinni::String::toCpp(linkedUri),\n                                                                            ::djinni::String::toCpp(password));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)ContinueWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                           password:(nonnull NSString *)password {\n    try {\n        auto objcpp_result_ = ::ILibraryController::ContinueWalletLinkedFromURI(::djinni::String::toCpp(linkedUri),\n                                                                                ::djinni::String::toCpp(password));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)InitWalletFromAndroidLegacyProtoWallet:(nonnull NSString *)walletFile\n                                   oldPassword:(nonnull NSString *)oldPassword\n                                   newPassword:(nonnull NSString *)newPassword {\n    try {\n        auto objcpp_result_ = ::ILibraryController::InitWalletFromAndroidLegacyProtoWallet(::djinni::String::toCpp(walletFile),\n                                                                                           ::djinni::String::toCpp(oldPassword),\n                                                                                           ::djinni::String::toCpp(newPassword));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (DBLegacyWalletResult)isValidAndroidLegacyProtoWallet:(nonnull NSString *)walletFile\n                                            oldPassword:(nonnull NSString *)oldPassword {\n    try {\n        auto objcpp_result_ = ::ILibraryController::isValidAndroidLegacyProtoWallet(::djinni::String::toCpp(walletFile),\n                                                                                    ::djinni::String::toCpp(oldPassword));\n        return ::djinni::Enum<::LegacyWalletResult, DBLegacyWalletResult>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsValidLinkURI:(nonnull NSString *)phrase {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsValidLinkURI(::djinni::String::toCpp(phrase));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)ReplaceWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                          password:(nonnull NSString *)password {\n    try {\n        auto objcpp_result_ = ::ILibraryController::ReplaceWalletLinkedFromURI(::djinni::String::toCpp(linkedUri),\n                                                                               ::djinni::String::toCpp(password));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)EraseWalletSeedsAndAccounts {\n    try {\n        auto objcpp_result_ = ::ILibraryController::EraseWalletSeedsAndAccounts();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsValidRecoveryPhrase:(nonnull NSString *)phrase {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsValidRecoveryPhrase(::djinni::String::toCpp(phrase));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBMnemonicRecord *)GenerateRecoveryMnemonic {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GenerateRecoveryMnemonic();\n        return ::djinni_generated::MnemonicRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)GenerateGenesisKeys {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GenerateGenesisKeys();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBMnemonicRecord *)ComposeRecoveryPhrase:(nonnull NSString *)mnemonic\n                                          birthTime:(int64_t)birthTime {\n    try {\n        auto objcpp_result_ = ::ILibraryController::ComposeRecoveryPhrase(::djinni::String::toCpp(mnemonic),\n                                                                          ::djinni::I64::toCpp(birthTime));\n        return ::djinni_generated::MnemonicRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)TerminateUnityLib {\n    try {\n        ::ILibraryController::TerminateUnityLib();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBQrCodeRecord *)QRImageFromString:(nonnull NSString *)qrString\n                                    widthHint:(int32_t)widthHint {\n    try {\n        auto objcpp_result_ = ::ILibraryController::QRImageFromString(::djinni::String::toCpp(qrString),\n                                                                      ::djinni::I32::toCpp(widthHint));\n        return ::djinni_generated::QrCodeRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)GetReceiveAddress {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GetReceiveAddress();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBMnemonicRecord *)GetRecoveryPhrase {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GetRecoveryPhrase();\n        return ::djinni_generated::MnemonicRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsMnemonicWallet {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsMnemonicWallet();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsMnemonicCorrect:(nonnull NSString *)phrase {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsMnemonicCorrect(::djinni::String::toCpp(phrase));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<NSString *> *)GetMnemonicDictionary {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GetMnemonicDictionary();\n        return ::djinni::List<::djinni::String>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)UnlockWallet:(nonnull NSString *)password\n    timeoutInSeconds:(int64_t)timeoutInSeconds {\n    try {\n        auto objcpp_result_ = ::ILibraryController::UnlockWallet(::djinni::String::toCpp(password),\n                                                                 ::djinni::I64::toCpp(timeoutInSeconds));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)LockWallet {\n    try {\n        auto objcpp_result_ = ::ILibraryController::LockWallet();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBWalletLockStatus *)GetWalletLockStatus {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GetWalletLockStatus();\n        return ::djinni_generated::WalletLockStatus::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)ChangePassword:(nonnull NSString *)oldPassword\n           newPassword:(nonnull NSString *)newPassword {\n    try {\n        auto objcpp_result_ = ::ILibraryController::ChangePassword(::djinni::String::toCpp(oldPassword),\n                                                                   ::djinni::String::toCpp(newPassword));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)DoRescan {\n    try {\n        ::ILibraryController::DoRescan();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBUriRecipient *)IsValidRecipient:(nonnull DBUriRecord *)request {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsValidRecipient(::djinni_generated::UriRecord::toCpp(request));\n        return ::djinni_generated::UriRecipient::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsValidNativeAddress:(nonnull NSString *)address {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsValidNativeAddress(::djinni::String::toCpp(address));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)IsValidBitcoinAddress:(nonnull NSString *)address {\n    try {\n        auto objcpp_result_ = ::ILibraryController::IsValidBitcoinAddress(::djinni::String::toCpp(address));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)feeForRecipient:(nonnull DBUriRecipient *)request {\n    try {\n        auto objcpp_result_ = ::ILibraryController::feeForRecipient(::djinni_generated::UriRecipient::toCpp(request));\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (DBPaymentResultStatus)performPaymentToRecipient:(nonnull DBUriRecipient *)request\n                                      substractFee:(BOOL)substractFee {\n    try {\n        auto objcpp_result_ = ::ILibraryController::performPaymentToRecipient(::djinni_generated::UriRecipient::toCpp(request),\n                                                                              ::djinni::Bool::toCpp(substractFee));\n        return ::djinni::Enum<::PaymentResultStatus, DBPaymentResultStatus>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBTransactionRecord *)getTransaction:(nonnull NSString *)txHash {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getTransaction(::djinni::String::toCpp(txHash));\n        return ::djinni_generated::TransactionRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)resendTransaction:(nonnull NSString *)txHash {\n    try {\n        auto objcpp_result_ = ::ILibraryController::resendTransaction(::djinni::String::toCpp(txHash));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBAddressRecord *> *)getAddressBookRecords {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getAddressBookRecords();\n        return ::djinni::List<::djinni_generated::AddressRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)addAddressBookRecord:(nonnull DBAddressRecord *)address {\n    try {\n        ::ILibraryController::addAddressBookRecord(::djinni_generated::AddressRecord::toCpp(address));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)deleteAddressBookRecord:(nonnull DBAddressRecord *)address {\n    try {\n        ::ILibraryController::deleteAddressBookRecord(::djinni_generated::AddressRecord::toCpp(address));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)PersistAndPruneForSPV {\n    try {\n        ::ILibraryController::PersistAndPruneForSPV();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)ResetUnifiedProgress {\n    try {\n        ::ILibraryController::ResetUnifiedProgress();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBBlockInfoRecord *> *)getLastSPVBlockInfos {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getLastSPVBlockInfos();\n        return ::djinni::List<::djinni_generated::BlockInfoRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (float)getUnifiedProgress {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getUnifiedProgress();\n        return ::djinni::F32::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBMonitorRecord *)getMonitoringStats {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getMonitoringStats();\n        return ::djinni_generated::MonitorRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)RegisterMonitorListener:(nullable id<DBMonitorListener>)listener {\n    try {\n        ::ILibraryController::RegisterMonitorListener(::djinni_generated::MonitorListener::toCpp(listener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)UnregisterMonitorListener:(nullable id<DBMonitorListener>)listener {\n    try {\n        ::ILibraryController::UnregisterMonitorListener(::djinni_generated::MonitorListener::toCpp(listener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSDictionary<NSString *, NSString *> *)getClientInfo {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getClientInfo();\n        return ::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBMutationRecord *> *)getMutationHistory {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getMutationHistory();\n        return ::djinni::List<::djinni_generated::MutationRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBTransactionRecord *> *)getTransactionHistory {\n    try {\n        auto objcpp_result_ = ::ILibraryController::getTransactionHistory();\n        return ::djinni::List<::djinni_generated::TransactionRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)HaveUnconfirmedFunds {\n    try {\n        auto objcpp_result_ = ::ILibraryController::HaveUnconfirmedFunds();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)GetBalance {\n    try {\n        auto objcpp_result_ = ::ILibraryController::GetBalance();\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n\nnamespace djinni_generated {\n\nauto ILibraryController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto ILibraryController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBILibraryController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBAddressRecord.h\"\n#import \"DBBlockInfoRecord.h\"\n#import \"DBLegacyWalletResult.h\"\n#import \"DBMnemonicRecord.h\"\n#import \"DBMonitorRecord.h\"\n#import \"DBMutationRecord.h\"\n#import \"DBPaymentResultStatus.h\"\n#import \"DBQrCodeRecord.h\"\n#import \"DBTransactionRecord.h\"\n#import \"DBUriRecipient.h\"\n#import \"DBUriRecord.h\"\n#import \"DBWalletLockStatus.h\"\n#import <Foundation/Foundation.h>\n@protocol DBILibraryListener;\n@protocol DBMonitorListener;\n\n/** Interface constants */\nextern int32_t const DBILibraryControllerVersion;\n\n/**\n * The library controller is used to Init/Terminate the library, and other similar tasks.\n * It is also home to various generic utility functions that don't (yet) have a place in more specific controllers\n * Specific functionality should go in specific controllers; account related functionality -> accounts_controller, network related functionality -> network_controller and so on\n */\n@interface DBILibraryController : NSObject\n\n/** Get the build information (ie. commit id and status) */\n+ (nonnull NSString *)BuildInfo;\n\n/**\n * Start the library\n * extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n * NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n * If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n */\n+ (int32_t)InitUnityLib:(nonnull NSString *)dataDir\n       staticFilterPath:(nonnull NSString *)staticFilterPath\n     staticFilterOffset:(int64_t)staticFilterOffset\n     staticFilterLength:(int64_t)staticFilterLength\n                testnet:(BOOL)testnet\n                spvMode:(BOOL)spvMode\n          signalHandler:(nullable id<DBILibraryListener>)signalHandler\n              extraArgs:(nonnull NSString *)extraArgs;\n\n/** Threaded implementation of InitUnityLib */\n+ (void)InitUnityLibThreaded:(nonnull NSString *)dataDir\n            staticFilterPath:(nonnull NSString *)staticFilterPath\n          staticFilterOffset:(int64_t)staticFilterOffset\n          staticFilterLength:(int64_t)staticFilterLength\n                     testnet:(BOOL)testnet\n                     spvMode:(BOOL)spvMode\n               signalHandler:(nullable id<DBILibraryListener>)signalHandler\n                   extraArgs:(nonnull NSString *)extraArgs;\n\n/** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n+ (BOOL)InitWalletFromRecoveryPhrase:(nonnull NSString *)phrase\n                            password:(nonnull NSString *)password;\n\n/** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n+ (BOOL)ContinueWalletFromRecoveryPhrase:(nonnull NSString *)phrase\n                                password:(nonnull NSString *)password;\n\n/** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n+ (BOOL)InitWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                       password:(nonnull NSString *)password;\n\n/** Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts */\n+ (BOOL)ContinueWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                           password:(nonnull NSString *)password;\n\n/** Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib */\n+ (BOOL)InitWalletFromAndroidLegacyProtoWallet:(nonnull NSString *)walletFile\n                                   oldPassword:(nonnull NSString *)oldPassword\n                                   newPassword:(nonnull NSString *)newPassword;\n\n/** Check if a file is a valid legacy proto wallet */\n+ (DBLegacyWalletResult)isValidAndroidLegacyProtoWallet:(nonnull NSString *)walletFile\n                                            oldPassword:(nonnull NSString *)oldPassword;\n\n/** Check link URI for validity */\n+ (BOOL)IsValidLinkURI:(nonnull NSString *)phrase;\n\n/** Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet. */\n+ (BOOL)ReplaceWalletLinkedFromURI:(nonnull NSString *)linkedUri\n                          password:(nonnull NSString *)password;\n\n/**\n * Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n * After calling this it will be necessary to create a new linked account or recovery phrase account again.\n * NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n */\n+ (BOOL)EraseWalletSeedsAndAccounts;\n\n/**\n * Check recovery phrase for (syntactic) validity\n * Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n */\n+ (BOOL)IsValidRecoveryPhrase:(nonnull NSString *)phrase;\n\n/** Generate a new recovery mnemonic */\n+ (nonnull DBMnemonicRecord *)GenerateRecoveryMnemonic;\n\n+ (nonnull NSString *)GenerateGenesisKeys;\n\n/** Compute recovery phrase with birth number */\n+ (nonnull DBMnemonicRecord *)ComposeRecoveryPhrase:(nonnull NSString *)mnemonic\n                                          birthTime:(int64_t)birthTime;\n\n/** Stop the library */\n+ (void)TerminateUnityLib;\n\n/** Generate a QR code for a string, QR code will be as close to widthHint as possible when applying simple scaling. */\n+ (nonnull DBQrCodeRecord *)QRImageFromString:(nonnull NSString *)qrString\n                                    widthHint:(int32_t)widthHint;\n\n/** Get a receive address for the active account */\n+ (nonnull NSString *)GetReceiveAddress;\n\n/** Get the recovery phrase for the wallet */\n+ (nonnull DBMnemonicRecord *)GetRecoveryPhrase;\n\n/** Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet) */\n+ (BOOL)IsMnemonicWallet;\n\n/** Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time) */\n+ (BOOL)IsMnemonicCorrect:(nonnull NSString *)phrase;\n\n/**\n * Get the 'dictionary' of valid words that a recovery phrase can be composed of\n * NB! Not all combinations of these words are valid\n * Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n * This function should only be used for input validation/auto-completion\n */\n+ (nonnull NSArray<NSString *> *)GetMnemonicDictionary;\n\n/** Unlock wallet; wallet will automatically relock after \"timeoutInSeconds\" */\n+ (BOOL)UnlockWallet:(nonnull NSString *)password\n    timeoutInSeconds:(int64_t)timeoutInSeconds;\n\n/** Forcefully lock wallet again */\n+ (BOOL)LockWallet;\n\n+ (nonnull DBWalletLockStatus *)GetWalletLockStatus;\n\n/** Change the wallet password */\n+ (BOOL)ChangePassword:(nonnull NSString *)oldPassword\n           newPassword:(nonnull NSString *)newPassword;\n\n/** Rescan blockchain for wallet transactions */\n+ (void)DoRescan;\n\n/** Check if text/address is something we are capable of sending money too */\n+ (nonnull DBUriRecipient *)IsValidRecipient:(nonnull DBUriRecord *)request;\n\n/** Check if text/address is a native (to our blockchain) address */\n+ (BOOL)IsValidNativeAddress:(nonnull NSString *)address;\n\n/** Check if text/address is a valid bitcoin address */\n+ (BOOL)IsValidBitcoinAddress:(nonnull NSString *)address;\n\n/** Compute the fee required to send amount to given recipient */\n+ (int64_t)feeForRecipient:(nonnull DBUriRecipient *)request;\n\n/** Attempt to pay a recipient, will throw on failure with description */\n+ (DBPaymentResultStatus)performPaymentToRecipient:(nonnull DBUriRecipient *)request\n                                      substractFee:(BOOL)substractFee;\n\n/**\n * Get the wallet transaction for the hash\n * Will throw if not found\n */\n+ (nonnull DBTransactionRecord *)getTransaction:(nonnull NSString *)txHash;\n\n/** resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail */\n+ (nonnull NSString *)resendTransaction:(nonnull NSString *)txHash;\n\n/** Get list of all address book entries */\n+ (nonnull NSArray<DBAddressRecord *> *)getAddressBookRecords;\n\n/** Add a record to the address book */\n+ (void)addAddressBookRecord:(nonnull DBAddressRecord *)address;\n\n/** Delete a record from the address book */\n+ (void)deleteAddressBookRecord:(nonnull DBAddressRecord *)address;\n\n/** Interim persist and prune of state. Use at key moments like app backgrounding. */\n+ (void)PersistAndPruneForSPV;\n\n/**\n * Reset progress notification. In cases where there has been no progress for a long time, but the process\n * is still running the progress can be reset and will represent work to be done from this reset onwards.\n * For example when the process is in the background on iOS for a long long time (but has not been terminated\n * by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n */\n+ (void)ResetUnifiedProgress;\n\n/** Get info of last blocks (at most 32) in SPV chain */\n+ (nonnull NSArray<DBBlockInfoRecord *> *)getLastSPVBlockInfos;\n\n+ (float)getUnifiedProgress;\n\n+ (nonnull DBMonitorRecord *)getMonitoringStats;\n\n+ (void)RegisterMonitorListener:(nullable id<DBMonitorListener>)listener;\n\n+ (void)UnregisterMonitorListener:(nullable id<DBMonitorListener>)listener;\n\n+ (nonnull NSDictionary<NSString *, NSString *> *)getClientInfo;\n\n/**\n * Get list of wallet mutations\n *NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n */\n+ (nonnull NSArray<DBMutationRecord *> *)getMutationHistory;\n\n/**\n * Get list of all transactions wallet has been involved in\n *NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n */\n+ (nonnull NSArray<DBTransactionRecord *> *)getTransactionHistory;\n\n/**\n * Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n *NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n */\n+ (BOOL)HaveUnconfirmedFunds;\n\n/**\n * Check current wallet balance (including unconfirmed funds)\n *NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n */\n+ (int64_t)GetBalance;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryController.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBILibraryController.h\"\n\n\nint32_t const DBILibraryControllerVersion = 1;\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_library_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBILibraryListener;\n\nnamespace djinni_generated {\n\nclass ILibraryListener\n{\npublic:\n    using CppType = std::shared_ptr<::ILibraryListener>;\n    using CppOptType = std::shared_ptr<::ILibraryListener>;\n    using ObjcType = id<DBILibraryListener>;\n\n    using Boxed = ILibraryListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBILibraryListener+Private.h\"\n#import \"DBILibraryListener.h\"\n#import \"DBBalanceRecord+Private.h\"\n#import \"DBMutationRecord+Private.h\"\n#import \"DBTransactionRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass ILibraryListener::ObjcProxy final\n: public ::ILibraryListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::ILibraryListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void notifyUnifiedProgress(float c_progress) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyUnifiedProgress:(::djinni::F32::fromCpp(c_progress))];\n        }\n    }\n    void notifySyncDone() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifySyncDone];\n        }\n    }\n    void notifyBalanceChange(const ::BalanceRecord & c_new_balance) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyBalanceChange:(::djinni_generated::BalanceRecord::fromCpp(c_new_balance))];\n        }\n    }\n    void notifyNewMutation(const ::MutationRecord & c_mutation, bool c_self_committed) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyNewMutation:(::djinni_generated::MutationRecord::fromCpp(c_mutation))\n                                                          selfCommitted:(::djinni::Bool::fromCpp(c_self_committed))];\n        }\n    }\n    void notifyUpdatedTransaction(const ::TransactionRecord & c_transaction) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyUpdatedTransaction:(::djinni_generated::TransactionRecord::fromCpp(c_transaction))];\n        }\n    }\n    void notifyInitWithExistingWallet() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyInitWithExistingWallet];\n        }\n    }\n    void notifyInitWithoutExistingWallet() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyInitWithoutExistingWallet];\n        }\n    }\n    void notifyShutdown() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyShutdown];\n        }\n    }\n    void notifyCoreReady() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyCoreReady];\n        }\n    }\n    void notifyError(const std::string & c_error) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyError:(::djinni::String::fromCpp(c_error))];\n        }\n    }\n    void logPrint(const std::string & c_str) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() logPrint:(::djinni::String::fromCpp(c_str))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto ILibraryListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto ILibraryListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBILibraryListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord.h\"\n#import \"DBMutationRecord.h\"\n#import \"DBTransactionRecord.h\"\n#import <Foundation/Foundation.h>\n\n\n/** Interface to receive events from the core */\n@protocol DBILibraryListener\n\n/**\n * Fraction of work done since session start or last progress reset [0..1]\n * Unified progress combines connection state, header and block sync\n */\n- (void)notifyUnifiedProgress:(float)progress;\n\n/** Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start */\n- (void)notifySyncDone;\n\n- (void)notifyBalanceChange:(nonnull DBBalanceRecord *)newBalance;\n\n/**\n * Notification of new mutations\n * If selfCommitted it is due to a call to performPaymentToRecipient, else it is because of a transaction\n * reached us in another way. In general this will be because we received funds from someone, hower there are\n * also cases where funds is send from our wallet while !selfCommitted (for example by a linked desktop wallet\n * or another wallet instance using the same keys as ours).\n *\n * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n */\n- (void)notifyNewMutation:(nonnull DBMutationRecord *)mutation\n            selfCommitted:(BOOL)selfCommitted;\n\n/**\n * Notification that an existing transaction/mutation  has updated\n *\n * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n */\n- (void)notifyUpdatedTransaction:(nonnull DBTransactionRecord *)transaction;\n\n- (void)notifyInitWithExistingWallet;\n\n- (void)notifyInitWithoutExistingWallet;\n\n- (void)notifyShutdown;\n\n- (void)notifyCoreReady;\n\n- (void)notifyError:(nonnull NSString *)error;\n\n- (void)logPrint:(nonnull NSString *)str;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_p2p_network_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIP2pNetworkController;\n\nnamespace djinni_generated {\n\nclass IP2pNetworkController\n{\npublic:\n    using CppType = std::shared_ptr<::IP2pNetworkController>;\n    using CppOptType = std::shared_ptr<::IP2pNetworkController>;\n    using ObjcType = DBIP2pNetworkController*;\n\n    using Boxed = IP2pNetworkController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIP2pNetworkController+Private.h\"\n#import \"DBIP2pNetworkController.h\"\n#import \"DBBannedPeerRecord+Private.h\"\n#import \"DBIP2pNetworkListener+Private.h\"\n#import \"DBPeerRecord+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIP2pNetworkController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IP2pNetworkController>&)cppRef;\n\n@end\n\n@implementation DBIP2pNetworkController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IP2pNetworkController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IP2pNetworkController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (void)setListener:(nullable id<DBIP2pNetworkListener>)networklistener {\n    try {\n        ::IP2pNetworkController::setListener(::djinni_generated::IP2pNetworkListener::toCpp(networklistener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)disableNetwork {\n    try {\n        ::IP2pNetworkController::disableNetwork();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)enableNetwork {\n    try {\n        ::IP2pNetworkController::enableNetwork();\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBPeerRecord *> *)getPeerInfo {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::getPeerInfo();\n        return ::djinni::List<::djinni_generated::PeerRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<DBBannedPeerRecord *> *)listBannedPeers {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::listBannedPeers();\n        return ::djinni::List<::djinni_generated::BannedPeerRecord>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)banPeer:(nonnull NSString *)address\nbanTimeInSeconds:(int64_t)banTimeInSeconds {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::banPeer(::djinni::String::toCpp(address),\n                                                               ::djinni::I64::toCpp(banTimeInSeconds));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)unbanPeer:(nonnull NSString *)address {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::unbanPeer(::djinni::String::toCpp(address));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)disconnectPeer:(int64_t)nodeid {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::disconnectPeer(::djinni::I64::toCpp(nodeid));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)ClearBanned {\n    try {\n        auto objcpp_result_ = ::IP2pNetworkController::ClearBanned();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IP2pNetworkController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IP2pNetworkController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIP2pNetworkController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBannedPeerRecord.h\"\n#import \"DBPeerRecord.h\"\n#import <Foundation/Foundation.h>\n@protocol DBIP2pNetworkListener;\n\n\n/** C++ interface to control networking related aspects of the software */\n@interface DBIP2pNetworkController : NSObject\n\n/** Register listener to be notified of networking events */\n+ (void)setListener:(nullable id<DBIP2pNetworkListener>)networklistener;\n\n/** Turn p2p networking off */\n+ (void)disableNetwork;\n\n/** Turn p2p networking on */\n+ (void)enableNetwork;\n\n/** Get connected peer info */\n+ (nonnull NSArray<DBPeerRecord *> *)getPeerInfo;\n\n/** Get all banned peers */\n+ (nonnull NSArray<DBBannedPeerRecord *> *)listBannedPeers;\n\n+ (BOOL)banPeer:(nonnull NSString *)address\nbanTimeInSeconds:(int64_t)banTimeInSeconds;\n\n/** Unban a single peer */\n+ (BOOL)unbanPeer:(nonnull NSString *)address;\n\n/** Disconnect a specific peer */\n+ (BOOL)disconnectPeer:(int64_t)nodeid;\n\n/** Clear all banned peers */\n+ (BOOL)ClearBanned;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_p2p_network_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBIP2pNetworkListener;\n\nnamespace djinni_generated {\n\nclass IP2pNetworkListener\n{\npublic:\n    using CppType = std::shared_ptr<::IP2pNetworkListener>;\n    using CppOptType = std::shared_ptr<::IP2pNetworkListener>;\n    using ObjcType = id<DBIP2pNetworkListener>;\n\n    using Boxed = IP2pNetworkListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIP2pNetworkListener+Private.h\"\n#import \"DBIP2pNetworkListener.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass IP2pNetworkListener::ObjcProxy final\n: public ::IP2pNetworkListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::IP2pNetworkListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void onNetworkEnabled() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onNetworkEnabled];\n        }\n    }\n    void onNetworkDisabled() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onNetworkDisabled];\n        }\n    }\n    void onConnectionCountChanged(int32_t c_numConnections) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onConnectionCountChanged:(::djinni::I32::fromCpp(c_numConnections))];\n        }\n    }\n    void onBytesChanged(int32_t c_totalRecv, int32_t c_totalSent) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onBytesChanged:(::djinni::I32::fromCpp(c_totalRecv))\n                                                           totalSent:(::djinni::I32::fromCpp(c_totalSent))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto IP2pNetworkListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto IP2pNetworkListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIP2pNetworkListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n\n/** Interface to receive updates about network status */\n@protocol DBIP2pNetworkListener\n\n/** Notify that p2p networking has been enabled */\n- (void)onNetworkEnabled;\n\n/** Notify that p2p networking has been disabled */\n- (void)onNetworkDisabled;\n\n/** Notify that number of peers has changed */\n- (void)onConnectionCountChanged:(int32_t)numConnections;\n\n/** Notify that amount of data sent/received has changed */\n- (void)onBytesChanged:(int32_t)totalRecv\n             totalSent:(int32_t)totalSent;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_rpc_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIRpcController;\n\nnamespace djinni_generated {\n\nclass IRpcController\n{\npublic:\n    using CppType = std::shared_ptr<::IRpcController>;\n    using CppOptType = std::shared_ptr<::IRpcController>;\n    using ObjcType = DBIRpcController*;\n\n    using Boxed = IRpcController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIRpcController+Private.h\"\n#import \"DBIRpcController.h\"\n#import \"DBIRpcListener+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIRpcController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IRpcController>&)cppRef;\n\n@end\n\n@implementation DBIRpcController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IRpcController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IRpcController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (void)execute:(nonnull NSString *)rpcCommandLine\n resultListener:(nullable id<DBIRpcListener>)resultListener {\n    try {\n        ::IRpcController::execute(::djinni::String::toCpp(rpcCommandLine),\n                                  ::djinni_generated::IRpcListener::toCpp(resultListener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<NSString *> *)getAutocompleteList {\n    try {\n        auto objcpp_result_ = ::IRpcController::getAutocompleteList();\n        return ::djinni::List<::djinni::String>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IRpcController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IRpcController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIRpcController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n@protocol DBIRpcListener;\n\n\n/** C++ interface to execute RPC commands */\n@interface DBIRpcController : NSObject\n\n+ (void)execute:(nonnull NSString *)rpcCommandLine\n resultListener:(nullable id<DBIRpcListener>)resultListener;\n\n+ (nonnull NSArray<NSString *> *)getAutocompleteList;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_rpc_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBIRpcListener;\n\nnamespace djinni_generated {\n\nclass IRpcListener\n{\npublic:\n    using CppType = std::shared_ptr<::IRpcListener>;\n    using CppOptType = std::shared_ptr<::IRpcListener>;\n    using ObjcType = id<DBIRpcListener>;\n\n    using Boxed = IRpcListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIRpcListener+Private.h\"\n#import \"DBIRpcListener.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass IRpcListener::ObjcProxy final\n: public ::IRpcListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::IRpcListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void onFilteredCommand(const std::string & c_filteredCommand) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onFilteredCommand:(::djinni::String::fromCpp(c_filteredCommand))];\n        }\n    }\n    void onSuccess(const std::string & c_filteredCommand, const std::string & c_result) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onSuccess:(::djinni::String::fromCpp(c_filteredCommand))\n                                                         result:(::djinni::String::fromCpp(c_result))];\n        }\n    }\n    void onError(const std::string & c_filteredCommand, const std::string & c_errorMessage) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onError:(::djinni::String::fromCpp(c_filteredCommand))\n                                                 errorMessage:(::djinni::String::fromCpp(c_errorMessage))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto IRpcListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto IRpcListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIRpcListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n\n/**\n * Interface to handle result of RPC commands\n * Calls either onSuccess or onError depending on whether command suceedes or fails\n */\n@protocol DBIRpcListener\n\n/**\n * Returns a filtered version of the command with sensitive information like passwords removed\n * Any kind of 'command history' functionality should store this filtered command and not the original command\n */\n- (void)onFilteredCommand:(nonnull NSString *)filteredCommand;\n\n/**\n * Returns the result and a filtered version of the command with sensitive information like passwords removed\n * Any kind of 'command history' functionality should store this filtered command and not the original command\n */\n- (void)onSuccess:(nonnull NSString *)filteredCommand\n           result:(nonnull NSString *)result;\n\n/**\n * Returns an error message which might be a plain string or JSON depending on the type of error\n * Also returns a filtered version of the command with sensitive information like passwords removed\n * Any kind of 'command history' functionality should store this filtered command and not the original command\n */\n- (void)onError:(nonnull NSString *)filteredCommand\n   errorMessage:(nonnull NSString *)errorMessage;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_wallet_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIWalletController;\n\nnamespace djinni_generated {\n\nclass IWalletController\n{\npublic:\n    using CppType = std::shared_ptr<::IWalletController>;\n    using CppOptType = std::shared_ptr<::IWalletController>;\n    using ObjcType = DBIWalletController*;\n\n    using Boxed = IWalletController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIWalletController+Private.h\"\n#import \"DBIWalletController.h\"\n#import \"DBBalanceRecord+Private.h\"\n#import \"DBIWalletListener+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIWalletController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IWalletController>&)cppRef;\n\n@end\n\n@implementation DBIWalletController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IWalletController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IWalletController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (void)setListener:(nullable id<DBIWalletListener>)networklistener {\n    try {\n        ::IWalletController::setListener(::djinni_generated::IWalletListener::toCpp(networklistener));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)HaveUnconfirmedFunds {\n    try {\n        auto objcpp_result_ = ::IWalletController::HaveUnconfirmedFunds();\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int64_t)GetBalanceSimple {\n    try {\n        auto objcpp_result_ = ::IWalletController::GetBalanceSimple();\n        return ::djinni::I64::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBBalanceRecord *)GetBalance {\n    try {\n        auto objcpp_result_ = ::IWalletController::GetBalance();\n        return ::djinni_generated::BalanceRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (BOOL)AbandonTransaction:(nonnull NSString *)txHash {\n    try {\n        auto objcpp_result_ = ::IWalletController::AbandonTransaction(::djinni::String::toCpp(txHash));\n        return ::djinni::Bool::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)GetUUID {\n    try {\n        auto objcpp_result_ = ::IWalletController::GetUUID();\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IWalletController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IWalletController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIWalletController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord.h\"\n#import <Foundation/Foundation.h>\n@protocol DBIWalletListener;\n\n\n/**\n * Controller to perform functions at a wallet level (e.g. get balance of the entire wallet)\n * For per account functionality see accounts_controller\n */\n@interface DBIWalletController : NSObject\n\n/** Set listener to be notified of wallet events */\n+ (void)setListener:(nullable id<DBIWalletListener>)networklistener;\n\n/** Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait. */\n+ (BOOL)HaveUnconfirmedFunds;\n\n/** Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds */\n+ (int64_t)GetBalanceSimple;\n\n/** Check current wallet balance */\n+ (nonnull DBBalanceRecord *)GetBalance;\n\n/** Abandon a transaction */\n+ (BOOL)AbandonTransaction:(nonnull NSString *)txHash;\n\n/** Get a unique UUID that identifies this wallet */\n+ (nonnull NSString *)GetUUID;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_wallet_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBIWalletListener;\n\nnamespace djinni_generated {\n\nclass IWalletListener\n{\npublic:\n    using CppType = std::shared_ptr<::IWalletListener>;\n    using CppOptType = std::shared_ptr<::IWalletListener>;\n    using ObjcType = id<DBIWalletListener>;\n\n    using Boxed = IWalletListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIWalletListener+Private.h\"\n#import \"DBIWalletListener.h\"\n#import \"DBBalanceRecord+Private.h\"\n#import \"DBMutationRecord+Private.h\"\n#import \"DBTransactionRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass IWalletListener::ObjcProxy final\n: public ::IWalletListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::IWalletListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void notifyBalanceChange(const ::BalanceRecord & c_new_balance) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyBalanceChange:(::djinni_generated::BalanceRecord::fromCpp(c_new_balance))];\n        }\n    }\n    void notifyNewMutation(const ::MutationRecord & c_mutation, bool c_self_committed) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyNewMutation:(::djinni_generated::MutationRecord::fromCpp(c_mutation))\n                                                          selfCommitted:(::djinni::Bool::fromCpp(c_self_committed))];\n        }\n    }\n    void notifyUpdatedTransaction(const ::TransactionRecord & c_transaction) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyUpdatedTransaction:(::djinni_generated::TransactionRecord::fromCpp(c_transaction))];\n        }\n    }\n    void notifyWalletUnlocked() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyWalletUnlocked];\n        }\n    }\n    void notifyWalletLocked() override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyWalletLocked];\n        }\n    }\n    void notifyCoreWantsUnlock(const std::string & c_reason) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyCoreWantsUnlock:(::djinni::String::fromCpp(c_reason))];\n        }\n    }\n    void notifyCoreInfo(const std::string & c_type, const std::string & c_caption, const std::string & c_message) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() notifyCoreInfo:(::djinni::String::fromCpp(c_type))\n                                                             caption:(::djinni::String::fromCpp(c_caption))\n                                                             message:(::djinni::String::fromCpp(c_message))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto IWalletListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto IWalletListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWalletListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBBalanceRecord.h\"\n#import \"DBMutationRecord.h\"\n#import \"DBTransactionRecord.h\"\n#import <Foundation/Foundation.h>\n\n\n/** Interface to receive wallet level events */\n@protocol DBIWalletListener\n\n/** Notification of change in overall wallet balance */\n- (void)notifyBalanceChange:(nonnull DBBalanceRecord *)newBalance;\n\n/**\n * Notification of new mutations.\n * If selfCommitted it is due to a call to performPaymentToRecipient, else it is because of a transaction\n * reached us in another way. In general this will be because we received funds from someone, hower there are\n * also cases where funds is send from our wallet while !selfCommitted (for example by a linked desktop wallet\n * or another wallet instance using the same keys as ours).\n *\n * Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n */\n- (void)notifyNewMutation:(nonnull DBMutationRecord *)mutation\n            selfCommitted:(BOOL)selfCommitted;\n\n/**\n * Notification that an existing transaction/mutation  has updated\n *\n * Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n * Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n */\n- (void)notifyUpdatedTransaction:(nonnull DBTransactionRecord *)transaction;\n\n/** Wallet unlocked */\n- (void)notifyWalletUnlocked;\n\n/** Wallet locked */\n- (void)notifyWalletLocked;\n\n/** Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet' */\n- (void)notifyCoreWantsUnlock:(nonnull NSString *)reason;\n\n/** Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display */\n- (void)notifyCoreInfo:(nonnull NSString *)type\n               caption:(nonnull NSString *)caption\n               message:(nonnull NSString *)message;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWitnessController+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"i_witness_controller.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBIWitnessController;\n\nnamespace djinni_generated {\n\nclass IWitnessController\n{\npublic:\n    using CppType = std::shared_ptr<::IWitnessController>;\n    using CppOptType = std::shared_ptr<::IWitnessController>;\n    using ObjcType = DBIWitnessController*;\n\n    using Boxed = IWitnessController;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWitnessController+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBIWitnessController+Private.h\"\n#import \"DBIWitnessController.h\"\n#import \"DBResultRecord+Private.h\"\n#import \"DBWitnessAccountStatisticsRecord+Private.h\"\n#import \"DBWitnessEstimateInfoRecord+Private.h\"\n#import \"DBWitnessFundingResultRecord+Private.h\"\n#import \"DJICppWrapperCache+Private.h\"\n#import \"DJIError.h\"\n#import \"DJIMarshal+Private.h\"\n#include <exception>\n#include <stdexcept>\n#include <utility>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@interface DBIWitnessController ()\n\n- (id)initWithCpp:(const std::shared_ptr<::IWitnessController>&)cppRef;\n\n@end\n\n@implementation DBIWitnessController {\n    ::djinni::CppProxyCache::Handle<std::shared_ptr<::IWitnessController>> _cppRefHandle;\n}\n\n- (id)initWithCpp:(const std::shared_ptr<::IWitnessController>&)cppRef\n{\n    if (self = [super init]) {\n        _cppRefHandle.assign(cppRef);\n    }\n    return self;\n}\n\n+ (nonnull NSDictionary<NSString *, NSString *> *)getNetworkLimits {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getNetworkLimits();\n        return ::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBWitnessEstimateInfoRecord *)getEstimatedWeight:(int64_t)amountToLock\n                                         lockPeriodInBlocks:(int64_t)lockPeriodInBlocks {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getEstimatedWeight(::djinni::I64::toCpp(amountToLock),\n                                                                       ::djinni::I64::toCpp(lockPeriodInBlocks));\n        return ::djinni_generated::WitnessEstimateInfoRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBWitnessFundingResultRecord *)fundWitnessAccount:(nonnull NSString *)fundingAccountUUID\n                                          witnessAccountUUID:(nonnull NSString *)witnessAccountUUID\n                                               fundingAmount:(int64_t)fundingAmount\n                                 requestedLockPeriodInBlocks:(int64_t)requestedLockPeriodInBlocks {\n    try {\n        auto objcpp_result_ = ::IWitnessController::fundWitnessAccount(::djinni::String::toCpp(fundingAccountUUID),\n                                                                       ::djinni::String::toCpp(witnessAccountUUID),\n                                                                       ::djinni::I64::toCpp(fundingAmount),\n                                                                       ::djinni::I64::toCpp(requestedLockPeriodInBlocks));\n        return ::djinni_generated::WitnessFundingResultRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBWitnessFundingResultRecord *)renewWitnessAccount:(nonnull NSString *)fundingAccountUUID\n                                           witnessAccountUUID:(nonnull NSString *)witnessAccountUUID {\n    try {\n        auto objcpp_result_ = ::IWitnessController::renewWitnessAccount(::djinni::String::toCpp(fundingAccountUUID),\n                                                                        ::djinni::String::toCpp(witnessAccountUUID));\n        return ::djinni_generated::WitnessFundingResultRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBWitnessAccountStatisticsRecord *)getAccountWitnessStatistics:(nonnull NSString *)witnessAccountUUID {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getAccountWitnessStatistics(::djinni::String::toCpp(witnessAccountUUID));\n        return ::djinni_generated::WitnessAccountStatisticsRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (void)setAccountCompounding:(nonnull NSString *)witnessAccountUUID\n            percentToCompount:(int32_t)percentToCompount {\n    try {\n        ::IWitnessController::setAccountCompounding(::djinni::String::toCpp(witnessAccountUUID),\n                                                    ::djinni::I32::toCpp(percentToCompount));\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (int32_t)isAccountCompounding:(nonnull NSString *)witnessAccountUUID {\n    try {\n        auto objcpp_result_ = ::IWitnessController::isAccountCompounding(::djinni::String::toCpp(witnessAccountUUID));\n        return ::djinni::I32::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSString *)getWitnessAddress:(nonnull NSString *)witnessAccountUUID {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getWitnessAddress(::djinni::String::toCpp(witnessAccountUUID));\n        return ::djinni::String::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<NSNumber *> *)getOptimalWitnessDistribution:(int64_t)amount\n                                              durationInBlocks:(int64_t)durationInBlocks\n                                            totalNetworkWeight:(int64_t)totalNetworkWeight {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getOptimalWitnessDistribution(::djinni::I64::toCpp(amount),\n                                                                                  ::djinni::I64::toCpp(durationInBlocks),\n                                                                                  ::djinni::I64::toCpp(totalNetworkWeight));\n        return ::djinni::List<::djinni::I64>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull NSArray<NSNumber *> *)getOptimalWitnessDistributionForAccount:(nonnull NSString *)witnessAccountUUID {\n    try {\n        auto objcpp_result_ = ::IWitnessController::getOptimalWitnessDistributionForAccount(::djinni::String::toCpp(witnessAccountUUID));\n        return ::djinni::List<::djinni::I64>::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\n+ (nonnull DBResultRecord *)optimiseWitnessAccount:(nonnull NSString *)witnessAccountUUID\n                                fundingAccountUUID:(nonnull NSString *)fundingAccountUUID\n                               optimalDistribution:(nonnull NSArray<NSNumber *> *)optimalDistribution {\n    try {\n        auto objcpp_result_ = ::IWitnessController::optimiseWitnessAccount(::djinni::String::toCpp(witnessAccountUUID),\n                                                                           ::djinni::String::toCpp(fundingAccountUUID),\n                                                                           ::djinni::List<::djinni::I64>::toCpp(optimalDistribution));\n        return ::djinni_generated::ResultRecord::fromCpp(objcpp_result_);\n    } DJINNI_TRANSLATE_EXCEPTIONS()\n}\n\nnamespace djinni_generated {\n\nauto IWitnessController::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return objc->_cppRefHandle.get();\n}\n\nauto IWitnessController::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return ::djinni::get_cpp_proxy<DBIWitnessController>(cpp);\n}\n\n}  // namespace djinni_generated\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBIWitnessController.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBResultRecord.h\"\n#import \"DBWitnessAccountStatisticsRecord.h\"\n#import \"DBWitnessEstimateInfoRecord.h\"\n#import \"DBWitnessFundingResultRecord.h\"\n#import <Foundation/Foundation.h>\n\n\n/** C++ interface to control witness accounts */\n@interface DBIWitnessController : NSObject\n\n/** Get information on min/max witness periods, weights etc. */\n+ (nonnull NSDictionary<NSString *, NSString *> *)getNetworkLimits;\n\n/** Get an estimate of weights/parts that a witness account will be funded with */\n+ (nonnull DBWitnessEstimateInfoRecord *)getEstimatedWeight:(int64_t)amountToLock\n                                         lockPeriodInBlocks:(int64_t)lockPeriodInBlocks;\n\n/** Fund a witness account */\n+ (nonnull DBWitnessFundingResultRecord *)fundWitnessAccount:(nonnull NSString *)fundingAccountUUID\n                                          witnessAccountUUID:(nonnull NSString *)witnessAccountUUID\n                                               fundingAmount:(int64_t)fundingAmount\n                                 requestedLockPeriodInBlocks:(int64_t)requestedLockPeriodInBlocks;\n\n/** Renew a witness account */\n+ (nonnull DBWitnessFundingResultRecord *)renewWitnessAccount:(nonnull NSString *)fundingAccountUUID\n                                           witnessAccountUUID:(nonnull NSString *)witnessAccountUUID;\n\n/** Get information on account weight and other witness statistics for account */\n+ (nonnull DBWitnessAccountStatisticsRecord *)getAccountWitnessStatistics:(nonnull NSString *)witnessAccountUUID;\n\n/** Turn compounding on/off */\n+ (void)setAccountCompounding:(nonnull NSString *)witnessAccountUUID\n            percentToCompount:(int32_t)percentToCompount;\n\n/** Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding */\n+ (int32_t)isAccountCompounding:(nonnull NSString *)witnessAccountUUID;\n\n/** Get the witness address of the account */\n+ (nonnull NSString *)getWitnessAddress:(nonnull NSString *)witnessAccountUUID;\n\n/** Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\" */\n+ (nonnull NSArray<NSNumber *> *)getOptimalWitnessDistribution:(int64_t)amount\n                                              durationInBlocks:(int64_t)durationInBlocks\n                                            totalNetworkWeight:(int64_t)totalNetworkWeight;\n\n/** Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values */\n+ (nonnull NSArray<NSNumber *> *)getOptimalWitnessDistributionForAccount:(nonnull NSString *)witnessAccountUUID;\n\n/** Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this */\n+ (nonnull DBResultRecord *)optimiseWitnessAccount:(nonnull NSString *)witnessAccountUUID\n                                fundingAccountUUID:(nonnull NSString *)fundingAccountUUID\n                               optimalDistribution:(nonnull NSArray<NSNumber *> *)optimalDistribution;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBInputRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBInputRecord.h\"\n#include \"input_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBInputRecord;\n\nnamespace djinni_generated {\n\nstruct InputRecord\n{\n    using CppType = ::InputRecord;\n    using ObjcType = DBInputRecord*;\n\n    using Boxed = InputRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBInputRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBInputRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto InputRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.address),\n            ::djinni::String::toCpp(obj.label),\n            ::djinni::String::toCpp(obj.desc),\n            ::djinni::Bool::toCpp(obj.isMine)};\n}\n\nauto InputRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBInputRecord alloc] initWithAddress:(::djinni::String::fromCpp(cpp.address))\n                                            label:(::djinni::String::fromCpp(cpp.label))\n                                             desc:(::djinni::String::fromCpp(cpp.desc))\n                                           isMine:(::djinni::Bool::fromCpp(cpp.isMine))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBInputRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBInputRecord : NSObject\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                                  label:(nonnull NSString *)label\n                                   desc:(nonnull NSString *)desc\n                                 isMine:(BOOL)isMine;\n+ (nonnull instancetype)inputRecordWithAddress:(nonnull NSString *)address\n                                         label:(nonnull NSString *)label\n                                          desc:(nonnull NSString *)desc\n                                        isMine:(BOOL)isMine;\n\n@property (nonatomic, readonly, nonnull) NSString * address;\n\n@property (nonatomic, readonly, nonnull) NSString * label;\n\n@property (nonatomic, readonly, nonnull) NSString * desc;\n\n@property (nonatomic, readonly) BOOL isMine;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBInputRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBInputRecord.h\"\n\n\n@implementation DBInputRecord\n\n- (nonnull instancetype)initWithAddress:(nonnull NSString *)address\n                                  label:(nonnull NSString *)label\n                                   desc:(nonnull NSString *)desc\n                                 isMine:(BOOL)isMine\n{\n    if (self = [super init]) {\n        _address = [address copy];\n        _label = [label copy];\n        _desc = [desc copy];\n        _isMine = isMine;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)inputRecordWithAddress:(nonnull NSString *)address\n                                         label:(nonnull NSString *)label\n                                          desc:(nonnull NSString *)desc\n                                        isMine:(BOOL)isMine\n{\n    return [(DBInputRecord*)[self alloc] initWithAddress:address\n                                                   label:label\n                                                    desc:desc\n                                                  isMine:isMine];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p address:%@ label:%@ desc:%@ isMine:%@>\", self.class, (void *)self, self.address, self.label, self.desc, @(self.isMine)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBLegacyWalletResult+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"legacy_wallet_result.hpp\"\n#import \"DJIMarshal+Private.h\"\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBLegacyWalletResult.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\ntypedef NS_ENUM(NSInteger, DBLegacyWalletResult)\n{\n    DBLegacyWalletResultUnsupportedOnThisPlatform,\n    DBLegacyWalletResultInvalidOrCorrupt,\n    DBLegacyWalletResultEncryptedPasswordRequired,\n    DBLegacyWalletResultPasswordInvalid,\n    DBLegacyWalletResultValid,\n};\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMnemonicRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMnemonicRecord.h\"\n#include \"mnemonic_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBMnemonicRecord;\n\nnamespace djinni_generated {\n\nstruct MnemonicRecord\n{\n    using CppType = ::MnemonicRecord;\n    using ObjcType = DBMnemonicRecord*;\n\n    using Boxed = MnemonicRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMnemonicRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMnemonicRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto MnemonicRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.phraseWithBirthNumber),\n            ::djinni::String::toCpp(obj.phrase),\n            ::djinni::I64::toCpp(obj.birthNumber)};\n}\n\nauto MnemonicRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBMnemonicRecord alloc] initWithPhraseWithBirthNumber:(::djinni::String::fromCpp(cpp.phrase_with_birth_number))\n                                                            phrase:(::djinni::String::fromCpp(cpp.phrase))\n                                                       birthNumber:(::djinni::I64::fromCpp(cpp.birth_number))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMnemonicRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBMnemonicRecord : NSObject\n- (nonnull instancetype)initWithPhraseWithBirthNumber:(nonnull NSString *)phraseWithBirthNumber\n                                               phrase:(nonnull NSString *)phrase\n                                          birthNumber:(int64_t)birthNumber;\n+ (nonnull instancetype)mnemonicRecordWithPhraseWithBirthNumber:(nonnull NSString *)phraseWithBirthNumber\n                                                         phrase:(nonnull NSString *)phrase\n                                                    birthNumber:(int64_t)birthNumber;\n\n@property (nonatomic, readonly, nonnull) NSString * phraseWithBirthNumber;\n\n@property (nonatomic, readonly, nonnull) NSString * phrase;\n\n@property (nonatomic, readonly) int64_t birthNumber;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMnemonicRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMnemonicRecord.h\"\n\n\n@implementation DBMnemonicRecord\n\n- (nonnull instancetype)initWithPhraseWithBirthNumber:(nonnull NSString *)phraseWithBirthNumber\n                                               phrase:(nonnull NSString *)phrase\n                                          birthNumber:(int64_t)birthNumber\n{\n    if (self = [super init]) {\n        _phraseWithBirthNumber = [phraseWithBirthNumber copy];\n        _phrase = [phrase copy];\n        _birthNumber = birthNumber;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)mnemonicRecordWithPhraseWithBirthNumber:(nonnull NSString *)phraseWithBirthNumber\n                                                         phrase:(nonnull NSString *)phrase\n                                                    birthNumber:(int64_t)birthNumber\n{\n    return [(DBMnemonicRecord*)[self alloc] initWithPhraseWithBirthNumber:phraseWithBirthNumber\n                                                                   phrase:phrase\n                                                              birthNumber:birthNumber];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p phraseWithBirthNumber:%@ phrase:%@ birthNumber:%@>\", self.class, (void *)self, self.phraseWithBirthNumber, self.phrase, @(self.birthNumber)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorListener+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"monitor_listener.hpp\"\n#include <memory>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@protocol DBMonitorListener;\n\nnamespace djinni_generated {\n\nclass MonitorListener\n{\npublic:\n    using CppType = std::shared_ptr<::MonitorListener>;\n    using CppOptType = std::shared_ptr<::MonitorListener>;\n    using ObjcType = id<DBMonitorListener>;\n\n    using Boxed = MonitorListener;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCppOpt(const CppOptType& cpp);\n    static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }\n\nprivate:\n    class ObjcProxy;\n};\n\n}  // namespace djinni_generated\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorListener+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMonitorListener+Private.h\"\n#import \"DBMonitorListener.h\"\n#import \"DJIMarshal+Private.h\"\n#import \"DJIObjcWrapperCache+Private.h\"\n#include <stdexcept>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni_generated {\n\nclass MonitorListener::ObjcProxy final\n: public ::MonitorListener\n, private ::djinni::ObjcProxyBase<ObjcType>\n{\n    friend class ::djinni_generated::MonitorListener;\npublic:\n    using ObjcProxyBase::ObjcProxyBase;\n    void onPartialChain(int32_t c_height, int32_t c_probable_height, int32_t c_offset) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onPartialChain:(::djinni::I32::fromCpp(c_height))\n                                                      probableHeight:(::djinni::I32::fromCpp(c_probable_height))\n                                                              offset:(::djinni::I32::fromCpp(c_offset))];\n        }\n    }\n    void onPruned(int32_t c_height) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onPruned:(::djinni::I32::fromCpp(c_height))];\n        }\n    }\n    void onProcessedSPVBlocks(int32_t c_height) override\n    {\n        @autoreleasepool {\n            [djinni_private_get_proxied_objc_object() onProcessedSPVBlocks:(::djinni::I32::fromCpp(c_height))];\n        }\n    }\n};\n\n}  // namespace djinni_generated\n\nnamespace djinni_generated {\n\nauto MonitorListener::toCpp(ObjcType objc) -> CppType\n{\n    if (!objc) {\n        return nullptr;\n    }\n    return ::djinni::get_objc_proxy<ObjcProxy>(objc);\n}\n\nauto MonitorListener::fromCppOpt(const CppOptType& cpp) -> ObjcType\n{\n    if (!cpp) {\n        return nil;\n    }\n    return dynamic_cast<ObjcProxy&>(*cpp).djinni_private_get_proxied_objc_object();\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorListener.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n\n/** Monitoring events */\n@protocol DBMonitorListener\n\n- (void)onPartialChain:(int32_t)height\n        probableHeight:(int32_t)probableHeight\n                offset:(int32_t)offset;\n\n- (void)onPruned:(int32_t)height;\n\n- (void)onProcessedSPVBlocks:(int32_t)height;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMonitorRecord.h\"\n#include \"monitor_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBMonitorRecord;\n\nnamespace djinni_generated {\n\nstruct MonitorRecord\n{\n    using CppType = ::MonitorRecord;\n    using ObjcType = DBMonitorRecord*;\n\n    using Boxed = MonitorRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMonitorRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto MonitorRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I32::toCpp(obj.partialHeight),\n            ::djinni::I32::toCpp(obj.partialOffset),\n            ::djinni::I32::toCpp(obj.prunedHeight),\n            ::djinni::I32::toCpp(obj.processedSPVHeight),\n            ::djinni::I32::toCpp(obj.probableHeight)};\n}\n\nauto MonitorRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBMonitorRecord alloc] initWithPartialHeight:(::djinni::I32::fromCpp(cpp.partialHeight))\n                                            partialOffset:(::djinni::I32::fromCpp(cpp.partialOffset))\n                                             prunedHeight:(::djinni::I32::fromCpp(cpp.prunedHeight))\n                                       processedSPVHeight:(::djinni::I32::fromCpp(cpp.processedSPVHeight))\n                                           probableHeight:(::djinni::I32::fromCpp(cpp.probableHeight))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n/** monitoring stats */\n@interface DBMonitorRecord : NSObject\n- (nonnull instancetype)initWithPartialHeight:(int32_t)partialHeight\n                                partialOffset:(int32_t)partialOffset\n                                 prunedHeight:(int32_t)prunedHeight\n                           processedSPVHeight:(int32_t)processedSPVHeight\n                               probableHeight:(int32_t)probableHeight;\n+ (nonnull instancetype)monitorRecordWithPartialHeight:(int32_t)partialHeight\n                                         partialOffset:(int32_t)partialOffset\n                                          prunedHeight:(int32_t)prunedHeight\n                                    processedSPVHeight:(int32_t)processedSPVHeight\n                                        probableHeight:(int32_t)probableHeight;\n\n@property (nonatomic, readonly) int32_t partialHeight;\n\n@property (nonatomic, readonly) int32_t partialOffset;\n\n@property (nonatomic, readonly) int32_t prunedHeight;\n\n@property (nonatomic, readonly) int32_t processedSPVHeight;\n\n@property (nonatomic, readonly) int32_t probableHeight;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMonitorRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMonitorRecord.h\"\n\n\n@implementation DBMonitorRecord\n\n- (nonnull instancetype)initWithPartialHeight:(int32_t)partialHeight\n                                partialOffset:(int32_t)partialOffset\n                                 prunedHeight:(int32_t)prunedHeight\n                           processedSPVHeight:(int32_t)processedSPVHeight\n                               probableHeight:(int32_t)probableHeight\n{\n    if (self = [super init]) {\n        _partialHeight = partialHeight;\n        _partialOffset = partialOffset;\n        _prunedHeight = prunedHeight;\n        _processedSPVHeight = processedSPVHeight;\n        _probableHeight = probableHeight;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)monitorRecordWithPartialHeight:(int32_t)partialHeight\n                                         partialOffset:(int32_t)partialOffset\n                                          prunedHeight:(int32_t)prunedHeight\n                                    processedSPVHeight:(int32_t)processedSPVHeight\n                                        probableHeight:(int32_t)probableHeight\n{\n    return [(DBMonitorRecord*)[self alloc] initWithPartialHeight:partialHeight\n                                                   partialOffset:partialOffset\n                                                    prunedHeight:prunedHeight\n                                              processedSPVHeight:processedSPVHeight\n                                                  probableHeight:probableHeight];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p partialHeight:%@ partialOffset:%@ prunedHeight:%@ processedSPVHeight:%@ probableHeight:%@>\", self.class, (void *)self, @(self.partialHeight), @(self.partialOffset), @(self.prunedHeight), @(self.processedSPVHeight), @(self.probableHeight)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMutationRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMutationRecord.h\"\n#include \"mutation_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBMutationRecord;\n\nnamespace djinni_generated {\n\nstruct MutationRecord\n{\n    using CppType = ::MutationRecord;\n    using ObjcType = DBMutationRecord*;\n\n    using Boxed = MutationRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMutationRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMutationRecord+Private.h\"\n#import \"DBTransactionStatus+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto MutationRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I64::toCpp(obj.change),\n            ::djinni::I64::toCpp(obj.timestamp),\n            ::djinni::String::toCpp(obj.txHash),\n            ::djinni::String::toCpp(obj.recipientAddresses),\n            ::djinni::Enum<::TransactionStatus, DBTransactionStatus>::toCpp(obj.status),\n            ::djinni::I32::toCpp(obj.depth)};\n}\n\nauto MutationRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBMutationRecord alloc] initWithChange:(::djinni::I64::fromCpp(cpp.change))\n                                          timestamp:(::djinni::I64::fromCpp(cpp.timestamp))\n                                             txHash:(::djinni::String::fromCpp(cpp.txHash))\n                                 recipientAddresses:(::djinni::String::fromCpp(cpp.recipient_addresses))\n                                             status:(::djinni::Enum<::TransactionStatus, DBTransactionStatus>::fromCpp(cpp.status))\n                                              depth:(::djinni::I32::fromCpp(cpp.depth))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMutationRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBTransactionStatus.h\"\n#import <Foundation/Foundation.h>\n\n@interface DBMutationRecord : NSObject\n- (nonnull instancetype)initWithChange:(int64_t)change\n                             timestamp:(int64_t)timestamp\n                                txHash:(nonnull NSString *)txHash\n                    recipientAddresses:(nonnull NSString *)recipientAddresses\n                                status:(DBTransactionStatus)status\n                                 depth:(int32_t)depth;\n+ (nonnull instancetype)mutationRecordWithChange:(int64_t)change\n                                       timestamp:(int64_t)timestamp\n                                          txHash:(nonnull NSString *)txHash\n                              recipientAddresses:(nonnull NSString *)recipientAddresses\n                                          status:(DBTransactionStatus)status\n                                           depth:(int32_t)depth;\n\n@property (nonatomic, readonly) int64_t change;\n\n@property (nonatomic, readonly) int64_t timestamp;\n\n@property (nonatomic, readonly, nonnull) NSString * txHash;\n\n/** Address(es) of transaction recipient(s) (if transaction is sent by us then this excludes e.g. change and only has other wallets addresses) */\n@property (nonatomic, readonly, nonnull) NSString * recipientAddresses;\n\n@property (nonatomic, readonly) DBTransactionStatus status;\n\n@property (nonatomic, readonly) int32_t depth;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBMutationRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBMutationRecord.h\"\n\n\n@implementation DBMutationRecord\n\n- (nonnull instancetype)initWithChange:(int64_t)change\n                             timestamp:(int64_t)timestamp\n                                txHash:(nonnull NSString *)txHash\n                    recipientAddresses:(nonnull NSString *)recipientAddresses\n                                status:(DBTransactionStatus)status\n                                 depth:(int32_t)depth\n{\n    if (self = [super init]) {\n        _change = change;\n        _timestamp = timestamp;\n        _txHash = [txHash copy];\n        _recipientAddresses = [recipientAddresses copy];\n        _status = status;\n        _depth = depth;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)mutationRecordWithChange:(int64_t)change\n                                       timestamp:(int64_t)timestamp\n                                          txHash:(nonnull NSString *)txHash\n                              recipientAddresses:(nonnull NSString *)recipientAddresses\n                                          status:(DBTransactionStatus)status\n                                           depth:(int32_t)depth\n{\n    return [(DBMutationRecord*)[self alloc] initWithChange:change\n                                                 timestamp:timestamp\n                                                    txHash:txHash\n                                        recipientAddresses:recipientAddresses\n                                                    status:status\n                                                     depth:depth];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p change:%@ timestamp:%@ txHash:%@ recipientAddresses:%@ status:%@ depth:%@>\", self.class, (void *)self, @(self.change), @(self.timestamp), self.txHash, self.recipientAddresses, @(self.status), @(self.depth)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBOutputRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBOutputRecord.h\"\n#include \"output_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBOutputRecord;\n\nnamespace djinni_generated {\n\nstruct OutputRecord\n{\n    using CppType = ::OutputRecord;\n    using ObjcType = DBOutputRecord*;\n\n    using Boxed = OutputRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBOutputRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBOutputRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto OutputRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I64::toCpp(obj.amount),\n            ::djinni::String::toCpp(obj.address),\n            ::djinni::String::toCpp(obj.label),\n            ::djinni::String::toCpp(obj.desc),\n            ::djinni::Bool::toCpp(obj.isMine)};\n}\n\nauto OutputRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBOutputRecord alloc] initWithAmount:(::djinni::I64::fromCpp(cpp.amount))\n                                          address:(::djinni::String::fromCpp(cpp.address))\n                                            label:(::djinni::String::fromCpp(cpp.label))\n                                             desc:(::djinni::String::fromCpp(cpp.desc))\n                                           isMine:(::djinni::Bool::fromCpp(cpp.isMine))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBOutputRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBOutputRecord : NSObject\n- (nonnull instancetype)initWithAmount:(int64_t)amount\n                               address:(nonnull NSString *)address\n                                 label:(nonnull NSString *)label\n                                  desc:(nonnull NSString *)desc\n                                isMine:(BOOL)isMine;\n+ (nonnull instancetype)outputRecordWithAmount:(int64_t)amount\n                                       address:(nonnull NSString *)address\n                                         label:(nonnull NSString *)label\n                                          desc:(nonnull NSString *)desc\n                                        isMine:(BOOL)isMine;\n\n@property (nonatomic, readonly) int64_t amount;\n\n@property (nonatomic, readonly, nonnull) NSString * address;\n\n@property (nonatomic, readonly, nonnull) NSString * label;\n\n@property (nonatomic, readonly, nonnull) NSString * desc;\n\n@property (nonatomic, readonly) BOOL isMine;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBOutputRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBOutputRecord.h\"\n\n\n@implementation DBOutputRecord\n\n- (nonnull instancetype)initWithAmount:(int64_t)amount\n                               address:(nonnull NSString *)address\n                                 label:(nonnull NSString *)label\n                                  desc:(nonnull NSString *)desc\n                                isMine:(BOOL)isMine\n{\n    if (self = [super init]) {\n        _amount = amount;\n        _address = [address copy];\n        _label = [label copy];\n        _desc = [desc copy];\n        _isMine = isMine;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)outputRecordWithAmount:(int64_t)amount\n                                       address:(nonnull NSString *)address\n                                         label:(nonnull NSString *)label\n                                          desc:(nonnull NSString *)desc\n                                        isMine:(BOOL)isMine\n{\n    return [(DBOutputRecord*)[self alloc] initWithAmount:amount\n                                                 address:address\n                                                   label:label\n                                                    desc:desc\n                                                  isMine:isMine];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p amount:%@ address:%@ label:%@ desc:%@ isMine:%@>\", self.class, (void *)self, @(self.amount), self.address, self.label, self.desc, @(self.isMine)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPaymentResultStatus+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"payment_result_status.hpp\"\n#import \"DJIMarshal+Private.h\"\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPaymentResultStatus.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\ntypedef NS_ENUM(NSInteger, DBPaymentResultStatus)\n{\n    DBPaymentResultStatusSuccess,\n    DBPaymentResultStatusInsufficientFunds,\n};\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPeerRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBPeerRecord.h\"\n#include \"peer_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBPeerRecord;\n\nnamespace djinni_generated {\n\nstruct PeerRecord\n{\n    using CppType = ::PeerRecord;\n    using ObjcType = DBPeerRecord*;\n\n    using Boxed = PeerRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPeerRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBPeerRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto PeerRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I64::toCpp(obj.id),\n            ::djinni::String::toCpp(obj.ip),\n            ::djinni::String::toCpp(obj.hostname),\n            ::djinni::String::toCpp(obj.addrLocal),\n            ::djinni::String::toCpp(obj.addrBind),\n            ::djinni::I64::toCpp(obj.startHeight),\n            ::djinni::I64::toCpp(obj.syncedHeight),\n            ::djinni::I64::toCpp(obj.commonHeight),\n            ::djinni::I64::toCpp(obj.timeConnected),\n            ::djinni::I64::toCpp(obj.timeOffset),\n            ::djinni::I64::toCpp(obj.latency),\n            ::djinni::I64::toCpp(obj.lastSend),\n            ::djinni::I64::toCpp(obj.lastReceive),\n            ::djinni::I64::toCpp(obj.sendBytes),\n            ::djinni::I64::toCpp(obj.receiveBytes),\n            ::djinni::String::toCpp(obj.userAgent),\n            ::djinni::I64::toCpp(obj.protocol),\n            ::djinni::I64::toCpp(obj.services),\n            ::djinni::Bool::toCpp(obj.inbound),\n            ::djinni::Bool::toCpp(obj.whitelisted),\n            ::djinni::Bool::toCpp(obj.addnode),\n            ::djinni::Bool::toCpp(obj.relayTxes),\n            ::djinni::I64::toCpp(obj.banscore)};\n}\n\nauto PeerRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBPeerRecord alloc] initWithId:(::djinni::I64::fromCpp(cpp.id))\n                                         ip:(::djinni::String::fromCpp(cpp.ip))\n                                   hostname:(::djinni::String::fromCpp(cpp.hostname))\n                                  addrLocal:(::djinni::String::fromCpp(cpp.addrLocal))\n                                   addrBind:(::djinni::String::fromCpp(cpp.addrBind))\n                                startHeight:(::djinni::I64::fromCpp(cpp.start_height))\n                               syncedHeight:(::djinni::I64::fromCpp(cpp.synced_height))\n                               commonHeight:(::djinni::I64::fromCpp(cpp.common_height))\n                              timeConnected:(::djinni::I64::fromCpp(cpp.time_connected))\n                                 timeOffset:(::djinni::I64::fromCpp(cpp.time_offset))\n                                    latency:(::djinni::I64::fromCpp(cpp.latency))\n                                   lastSend:(::djinni::I64::fromCpp(cpp.last_send))\n                                lastReceive:(::djinni::I64::fromCpp(cpp.last_receive))\n                                  sendBytes:(::djinni::I64::fromCpp(cpp.send_bytes))\n                               receiveBytes:(::djinni::I64::fromCpp(cpp.receive_bytes))\n                                  userAgent:(::djinni::String::fromCpp(cpp.userAgent))\n                                   protocol:(::djinni::I64::fromCpp(cpp.protocol))\n                                   services:(::djinni::I64::fromCpp(cpp.services))\n                                    inbound:(::djinni::Bool::fromCpp(cpp.inbound))\n                                whitelisted:(::djinni::Bool::fromCpp(cpp.whitelisted))\n                                    addnode:(::djinni::Bool::fromCpp(cpp.addnode))\n                                  relayTxes:(::djinni::Bool::fromCpp(cpp.relay_txes))\n                                   banscore:(::djinni::I64::fromCpp(cpp.banscore))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPeerRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBPeerRecord : NSObject\n- (nonnull instancetype)initWithId:(int64_t)id\n                                ip:(nonnull NSString *)ip\n                          hostname:(nonnull NSString *)hostname\n                         addrLocal:(nonnull NSString *)addrLocal\n                          addrBind:(nonnull NSString *)addrBind\n                       startHeight:(int64_t)startHeight\n                      syncedHeight:(int64_t)syncedHeight\n                      commonHeight:(int64_t)commonHeight\n                     timeConnected:(int64_t)timeConnected\n                        timeOffset:(int64_t)timeOffset\n                           latency:(int64_t)latency\n                          lastSend:(int64_t)lastSend\n                       lastReceive:(int64_t)lastReceive\n                         sendBytes:(int64_t)sendBytes\n                      receiveBytes:(int64_t)receiveBytes\n                         userAgent:(nonnull NSString *)userAgent\n                          protocol:(int64_t)protocol\n                          services:(int64_t)services\n                           inbound:(BOOL)inbound\n                       whitelisted:(BOOL)whitelisted\n                           addnode:(BOOL)addnode\n                         relayTxes:(BOOL)relayTxes\n                          banscore:(int64_t)banscore;\n+ (nonnull instancetype)peerRecordWithId:(int64_t)id\n                                      ip:(nonnull NSString *)ip\n                                hostname:(nonnull NSString *)hostname\n                               addrLocal:(nonnull NSString *)addrLocal\n                                addrBind:(nonnull NSString *)addrBind\n                             startHeight:(int64_t)startHeight\n                            syncedHeight:(int64_t)syncedHeight\n                            commonHeight:(int64_t)commonHeight\n                           timeConnected:(int64_t)timeConnected\n                              timeOffset:(int64_t)timeOffset\n                                 latency:(int64_t)latency\n                                lastSend:(int64_t)lastSend\n                             lastReceive:(int64_t)lastReceive\n                               sendBytes:(int64_t)sendBytes\n                            receiveBytes:(int64_t)receiveBytes\n                               userAgent:(nonnull NSString *)userAgent\n                                protocol:(int64_t)protocol\n                                services:(int64_t)services\n                                 inbound:(BOOL)inbound\n                             whitelisted:(BOOL)whitelisted\n                                 addnode:(BOOL)addnode\n                               relayTxes:(BOOL)relayTxes\n                                banscore:(int64_t)banscore;\n\n@property (nonatomic, readonly) int64_t id;\n\n@property (nonatomic, readonly, nonnull) NSString * ip;\n\n@property (nonatomic, readonly, nonnull) NSString * hostname;\n\n@property (nonatomic, readonly, nonnull) NSString * addrLocal;\n\n@property (nonatomic, readonly, nonnull) NSString * addrBind;\n\n@property (nonatomic, readonly) int64_t startHeight;\n\n@property (nonatomic, readonly) int64_t syncedHeight;\n\n@property (nonatomic, readonly) int64_t commonHeight;\n\n@property (nonatomic, readonly) int64_t timeConnected;\n\n@property (nonatomic, readonly) int64_t timeOffset;\n\n@property (nonatomic, readonly) int64_t latency;\n\n@property (nonatomic, readonly) int64_t lastSend;\n\n@property (nonatomic, readonly) int64_t lastReceive;\n\n@property (nonatomic, readonly) int64_t sendBytes;\n\n@property (nonatomic, readonly) int64_t receiveBytes;\n\n@property (nonatomic, readonly, nonnull) NSString * userAgent;\n\n@property (nonatomic, readonly) int64_t protocol;\n\n@property (nonatomic, readonly) int64_t services;\n\n@property (nonatomic, readonly) BOOL inbound;\n\n@property (nonatomic, readonly) BOOL whitelisted;\n\n@property (nonatomic, readonly) BOOL addnode;\n\n@property (nonatomic, readonly) BOOL relayTxes;\n\n@property (nonatomic, readonly) int64_t banscore;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBPeerRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBPeerRecord.h\"\n\n\n@implementation DBPeerRecord\n\n- (nonnull instancetype)initWithId:(int64_t)id\n                                ip:(nonnull NSString *)ip\n                          hostname:(nonnull NSString *)hostname\n                         addrLocal:(nonnull NSString *)addrLocal\n                          addrBind:(nonnull NSString *)addrBind\n                       startHeight:(int64_t)startHeight\n                      syncedHeight:(int64_t)syncedHeight\n                      commonHeight:(int64_t)commonHeight\n                     timeConnected:(int64_t)timeConnected\n                        timeOffset:(int64_t)timeOffset\n                           latency:(int64_t)latency\n                          lastSend:(int64_t)lastSend\n                       lastReceive:(int64_t)lastReceive\n                         sendBytes:(int64_t)sendBytes\n                      receiveBytes:(int64_t)receiveBytes\n                         userAgent:(nonnull NSString *)userAgent\n                          protocol:(int64_t)protocol\n                          services:(int64_t)services\n                           inbound:(BOOL)inbound\n                       whitelisted:(BOOL)whitelisted\n                           addnode:(BOOL)addnode\n                         relayTxes:(BOOL)relayTxes\n                          banscore:(int64_t)banscore\n{\n    if (self = [super init]) {\n        _id = id;\n        _ip = [ip copy];\n        _hostname = [hostname copy];\n        _addrLocal = [addrLocal copy];\n        _addrBind = [addrBind copy];\n        _startHeight = startHeight;\n        _syncedHeight = syncedHeight;\n        _commonHeight = commonHeight;\n        _timeConnected = timeConnected;\n        _timeOffset = timeOffset;\n        _latency = latency;\n        _lastSend = lastSend;\n        _lastReceive = lastReceive;\n        _sendBytes = sendBytes;\n        _receiveBytes = receiveBytes;\n        _userAgent = [userAgent copy];\n        _protocol = protocol;\n        _services = services;\n        _inbound = inbound;\n        _whitelisted = whitelisted;\n        _addnode = addnode;\n        _relayTxes = relayTxes;\n        _banscore = banscore;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)peerRecordWithId:(int64_t)id\n                                      ip:(nonnull NSString *)ip\n                                hostname:(nonnull NSString *)hostname\n                               addrLocal:(nonnull NSString *)addrLocal\n                                addrBind:(nonnull NSString *)addrBind\n                             startHeight:(int64_t)startHeight\n                            syncedHeight:(int64_t)syncedHeight\n                            commonHeight:(int64_t)commonHeight\n                           timeConnected:(int64_t)timeConnected\n                              timeOffset:(int64_t)timeOffset\n                                 latency:(int64_t)latency\n                                lastSend:(int64_t)lastSend\n                             lastReceive:(int64_t)lastReceive\n                               sendBytes:(int64_t)sendBytes\n                            receiveBytes:(int64_t)receiveBytes\n                               userAgent:(nonnull NSString *)userAgent\n                                protocol:(int64_t)protocol\n                                services:(int64_t)services\n                                 inbound:(BOOL)inbound\n                             whitelisted:(BOOL)whitelisted\n                                 addnode:(BOOL)addnode\n                               relayTxes:(BOOL)relayTxes\n                                banscore:(int64_t)banscore\n{\n    return [(DBPeerRecord*)[self alloc] initWithId:id\n                                                ip:ip\n                                          hostname:hostname\n                                         addrLocal:addrLocal\n                                          addrBind:addrBind\n                                       startHeight:startHeight\n                                      syncedHeight:syncedHeight\n                                      commonHeight:commonHeight\n                                     timeConnected:timeConnected\n                                        timeOffset:timeOffset\n                                           latency:latency\n                                          lastSend:lastSend\n                                       lastReceive:lastReceive\n                                         sendBytes:sendBytes\n                                      receiveBytes:receiveBytes\n                                         userAgent:userAgent\n                                          protocol:protocol\n                                          services:services\n                                           inbound:inbound\n                                       whitelisted:whitelisted\n                                           addnode:addnode\n                                         relayTxes:relayTxes\n                                          banscore:banscore];\n}\n\n- (BOOL)isEqual:(id)other\n{\n    if (![other isKindOfClass:[DBPeerRecord class]]) {\n        return NO;\n    }\n    DBPeerRecord *typedOther = (DBPeerRecord *)other;\n    return self.id == typedOther.id &&\n            [self.ip isEqualToString:typedOther.ip] &&\n            [self.hostname isEqualToString:typedOther.hostname] &&\n            [self.addrLocal isEqualToString:typedOther.addrLocal] &&\n            [self.addrBind isEqualToString:typedOther.addrBind] &&\n            self.startHeight == typedOther.startHeight &&\n            self.syncedHeight == typedOther.syncedHeight &&\n            self.commonHeight == typedOther.commonHeight &&\n            self.timeConnected == typedOther.timeConnected &&\n            self.timeOffset == typedOther.timeOffset &&\n            self.latency == typedOther.latency &&\n            self.lastSend == typedOther.lastSend &&\n            self.lastReceive == typedOther.lastReceive &&\n            self.sendBytes == typedOther.sendBytes &&\n            self.receiveBytes == typedOther.receiveBytes &&\n            [self.userAgent isEqualToString:typedOther.userAgent] &&\n            self.protocol == typedOther.protocol &&\n            self.services == typedOther.services &&\n            self.inbound == typedOther.inbound &&\n            self.whitelisted == typedOther.whitelisted &&\n            self.addnode == typedOther.addnode &&\n            self.relayTxes == typedOther.relayTxes &&\n            self.banscore == typedOther.banscore;\n}\n\n- (NSUInteger)hash\n{\n    return NSStringFromClass([self class]).hash ^\n            (NSUInteger)self.id ^\n            self.ip.hash ^\n            self.hostname.hash ^\n            self.addrLocal.hash ^\n            self.addrBind.hash ^\n            (NSUInteger)self.startHeight ^\n            (NSUInteger)self.syncedHeight ^\n            (NSUInteger)self.commonHeight ^\n            (NSUInteger)self.timeConnected ^\n            (NSUInteger)self.timeOffset ^\n            (NSUInteger)self.latency ^\n            (NSUInteger)self.lastSend ^\n            (NSUInteger)self.lastReceive ^\n            (NSUInteger)self.sendBytes ^\n            (NSUInteger)self.receiveBytes ^\n            self.userAgent.hash ^\n            (NSUInteger)self.protocol ^\n            (NSUInteger)self.services ^\n            (NSUInteger)self.inbound ^\n            (NSUInteger)self.whitelisted ^\n            (NSUInteger)self.addnode ^\n            (NSUInteger)self.relayTxes ^\n            (NSUInteger)self.banscore;\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p id:%@ ip:%@ hostname:%@ addrLocal:%@ addrBind:%@ startHeight:%@ syncedHeight:%@ commonHeight:%@ timeConnected:%@ timeOffset:%@ latency:%@ lastSend:%@ lastReceive:%@ sendBytes:%@ receiveBytes:%@ userAgent:%@ protocol:%@ services:%@ inbound:%@ whitelisted:%@ addnode:%@ relayTxes:%@ banscore:%@>\", self.class, (void *)self, @(self.id), self.ip, self.hostname, self.addrLocal, self.addrBind, @(self.startHeight), @(self.syncedHeight), @(self.commonHeight), @(self.timeConnected), @(self.timeOffset), @(self.latency), @(self.lastSend), @(self.lastReceive), @(self.sendBytes), @(self.receiveBytes), self.userAgent, @(self.protocol), @(self.services), @(self.inbound), @(self.whitelisted), @(self.addnode), @(self.relayTxes), @(self.banscore)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBQrCodeRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBQrCodeRecord.h\"\n#include \"qr_code_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBQrCodeRecord;\n\nnamespace djinni_generated {\n\nstruct QrCodeRecord\n{\n    using CppType = ::QrCodeRecord;\n    using ObjcType = DBQrCodeRecord*;\n\n    using Boxed = QrCodeRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBQrCodeRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBQrCodeRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto QrCodeRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I32::toCpp(obj.width),\n            ::djinni::Binary::toCpp(obj.pixelData)};\n}\n\nauto QrCodeRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBQrCodeRecord alloc] initWithWidth:(::djinni::I32::fromCpp(cpp.width))\n                                       pixelData:(::djinni::Binary::fromCpp(cpp.pixel_data))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBQrCodeRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBQrCodeRecord : NSObject\n- (nonnull instancetype)initWithWidth:(int32_t)width\n                            pixelData:(nonnull NSData *)pixelData;\n+ (nonnull instancetype)qrCodeRecordWithWidth:(int32_t)width\n                                    pixelData:(nonnull NSData *)pixelData;\n\n@property (nonatomic, readonly) int32_t width;\n\n@property (nonatomic, readonly, nonnull) NSData * pixelData;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBQrCodeRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBQrCodeRecord.h\"\n\n\n@implementation DBQrCodeRecord\n\n- (nonnull instancetype)initWithWidth:(int32_t)width\n                            pixelData:(nonnull NSData *)pixelData\n{\n    if (self = [super init]) {\n        _width = width;\n        _pixelData = [pixelData copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)qrCodeRecordWithWidth:(int32_t)width\n                                    pixelData:(nonnull NSData *)pixelData\n{\n    return [(DBQrCodeRecord*)[self alloc] initWithWidth:width\n                                              pixelData:pixelData];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p width:%@ pixelData:%@>\", self.class, (void *)self, @(self.width), self.pixelData];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBResultRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBResultRecord.h\"\n#include \"result_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBResultRecord;\n\nnamespace djinni_generated {\n\nstruct ResultRecord\n{\n    using CppType = ::ResultRecord;\n    using ObjcType = DBResultRecord*;\n\n    using Boxed = ResultRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBResultRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBResultRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto ResultRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::Bool::toCpp(obj.result),\n            ::djinni::String::toCpp(obj.info)};\n}\n\nauto ResultRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBResultRecord alloc] initWithResult:(::djinni::Bool::fromCpp(cpp.result))\n                                             info:(::djinni::String::fromCpp(cpp.info))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBResultRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n/**\n * Copyright (c) 2018-2022 The Centure developers\n * Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n * Distributed under the GNU Lesser General Public License v3, see the accompanying\n * file COPYING\n */\n@interface DBResultRecord : NSObject\n- (nonnull instancetype)initWithResult:(BOOL)result\n                                  info:(nonnull NSString *)info;\n+ (nonnull instancetype)resultRecordWithResult:(BOOL)result\n                                          info:(nonnull NSString *)info;\n\n@property (nonatomic, readonly) BOOL result;\n\n@property (nonatomic, readonly, nonnull) NSString * info;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBResultRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBResultRecord.h\"\n\n\n@implementation DBResultRecord\n\n- (nonnull instancetype)initWithResult:(BOOL)result\n                                  info:(nonnull NSString *)info\n{\n    if (self = [super init]) {\n        _result = result;\n        _info = [info copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)resultRecordWithResult:(BOOL)result\n                                          info:(nonnull NSString *)info\n{\n    return [(DBResultRecord*)[self alloc] initWithResult:result\n                                                    info:info];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p result:%@ info:%@>\", self.class, (void *)self, @(self.result), self.info];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBTransactionRecord.h\"\n#include \"transaction_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBTransactionRecord;\n\nnamespace djinni_generated {\n\nstruct TransactionRecord\n{\n    using CppType = ::TransactionRecord;\n    using ObjcType = DBTransactionRecord*;\n\n    using Boxed = TransactionRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBTransactionRecord+Private.h\"\n#import \"DBInputRecord+Private.h\"\n#import \"DBOutputRecord+Private.h\"\n#import \"DBTransactionStatus+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto TransactionRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.txHash),\n            ::djinni::I64::toCpp(obj.timeStamp),\n            ::djinni::I64::toCpp(obj.amount),\n            ::djinni::I64::toCpp(obj.fee),\n            ::djinni::Enum<::TransactionStatus, DBTransactionStatus>::toCpp(obj.status),\n            ::djinni::I32::toCpp(obj.height),\n            ::djinni::I64::toCpp(obj.blockTime),\n            ::djinni::I32::toCpp(obj.depth),\n            ::djinni::List<::djinni_generated::InputRecord>::toCpp(obj.inputs),\n            ::djinni::List<::djinni_generated::OutputRecord>::toCpp(obj.outputs)};\n}\n\nauto TransactionRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBTransactionRecord alloc] initWithTxHash:(::djinni::String::fromCpp(cpp.txHash))\n                                             timeStamp:(::djinni::I64::fromCpp(cpp.timeStamp))\n                                                amount:(::djinni::I64::fromCpp(cpp.amount))\n                                                   fee:(::djinni::I64::fromCpp(cpp.fee))\n                                                status:(::djinni::Enum<::TransactionStatus, DBTransactionStatus>::fromCpp(cpp.status))\n                                                height:(::djinni::I32::fromCpp(cpp.height))\n                                             blockTime:(::djinni::I64::fromCpp(cpp.blockTime))\n                                                 depth:(::djinni::I32::fromCpp(cpp.depth))\n                                                inputs:(::djinni::List<::djinni_generated::InputRecord>::fromCpp(cpp.inputs))\n                                               outputs:(::djinni::List<::djinni_generated::OutputRecord>::fromCpp(cpp.outputs))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBInputRecord.h\"\n#import \"DBOutputRecord.h\"\n#import \"DBTransactionStatus.h\"\n#import <Foundation/Foundation.h>\n\n@interface DBTransactionRecord : NSObject\n- (nonnull instancetype)initWithTxHash:(nonnull NSString *)txHash\n                             timeStamp:(int64_t)timeStamp\n                                amount:(int64_t)amount\n                                   fee:(int64_t)fee\n                                status:(DBTransactionStatus)status\n                                height:(int32_t)height\n                             blockTime:(int64_t)blockTime\n                                 depth:(int32_t)depth\n                                inputs:(nonnull NSArray<DBInputRecord *> *)inputs\n                               outputs:(nonnull NSArray<DBOutputRecord *> *)outputs;\n+ (nonnull instancetype)transactionRecordWithTxHash:(nonnull NSString *)txHash\n                                          timeStamp:(int64_t)timeStamp\n                                             amount:(int64_t)amount\n                                                fee:(int64_t)fee\n                                             status:(DBTransactionStatus)status\n                                             height:(int32_t)height\n                                          blockTime:(int64_t)blockTime\n                                              depth:(int32_t)depth\n                                             inputs:(nonnull NSArray<DBInputRecord *> *)inputs\n                                            outputs:(nonnull NSArray<DBOutputRecord *> *)outputs;\n\n@property (nonatomic, readonly, nonnull) NSString * txHash;\n\n@property (nonatomic, readonly) int64_t timeStamp;\n\n@property (nonatomic, readonly) int64_t amount;\n\n@property (nonatomic, readonly) int64_t fee;\n\n@property (nonatomic, readonly) DBTransactionStatus status;\n\n@property (nonatomic, readonly) int32_t height;\n\n@property (nonatomic, readonly) int64_t blockTime;\n\n@property (nonatomic, readonly) int32_t depth;\n\n@property (nonatomic, readonly, nonnull) NSArray<DBInputRecord *> * inputs;\n\n@property (nonatomic, readonly, nonnull) NSArray<DBOutputRecord *> * outputs;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBTransactionRecord.h\"\n\n\n@implementation DBTransactionRecord\n\n- (nonnull instancetype)initWithTxHash:(nonnull NSString *)txHash\n                             timeStamp:(int64_t)timeStamp\n                                amount:(int64_t)amount\n                                   fee:(int64_t)fee\n                                status:(DBTransactionStatus)status\n                                height:(int32_t)height\n                             blockTime:(int64_t)blockTime\n                                 depth:(int32_t)depth\n                                inputs:(nonnull NSArray<DBInputRecord *> *)inputs\n                               outputs:(nonnull NSArray<DBOutputRecord *> *)outputs\n{\n    if (self = [super init]) {\n        _txHash = [txHash copy];\n        _timeStamp = timeStamp;\n        _amount = amount;\n        _fee = fee;\n        _status = status;\n        _height = height;\n        _blockTime = blockTime;\n        _depth = depth;\n        _inputs = [inputs copy];\n        _outputs = [outputs copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)transactionRecordWithTxHash:(nonnull NSString *)txHash\n                                          timeStamp:(int64_t)timeStamp\n                                             amount:(int64_t)amount\n                                                fee:(int64_t)fee\n                                             status:(DBTransactionStatus)status\n                                             height:(int32_t)height\n                                          blockTime:(int64_t)blockTime\n                                              depth:(int32_t)depth\n                                             inputs:(nonnull NSArray<DBInputRecord *> *)inputs\n                                            outputs:(nonnull NSArray<DBOutputRecord *> *)outputs\n{\n    return [(DBTransactionRecord*)[self alloc] initWithTxHash:txHash\n                                                    timeStamp:timeStamp\n                                                       amount:amount\n                                                          fee:fee\n                                                       status:status\n                                                       height:height\n                                                    blockTime:blockTime\n                                                        depth:depth\n                                                       inputs:inputs\n                                                      outputs:outputs];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p txHash:%@ timeStamp:%@ amount:%@ fee:%@ status:%@ height:%@ blockTime:%@ depth:%@ inputs:%@ outputs:%@>\", self.class, (void *)self, self.txHash, @(self.timeStamp), @(self.amount), @(self.fee), @(self.status), @(self.height), @(self.blockTime), @(self.depth), self.inputs, self.outputs];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionStatus+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#include \"transaction_status.hpp\"\n#import \"DJIMarshal+Private.h\"\n\n"
  },
  {
    "path": "src/unity/djinni/objc/DBTransactionStatus.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\ntypedef NS_ENUM(NSInteger, DBTransactionStatus)\n{\n    DBTransactionStatusUnconfirmed,\n    DBTransactionStatusConfirming,\n    DBTransactionStatusConfirmed,\n    DBTransactionStatusAbandoned,\n    DBTransactionStatusConflicted,\n};\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecipient+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecipient.h\"\n#include \"uri_recipient.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBUriRecipient;\n\nnamespace djinni_generated {\n\nstruct UriRecipient\n{\n    using CppType = ::UriRecipient;\n    using ObjcType = DBUriRecipient*;\n\n    using Boxed = UriRecipient;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecipient+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecipient+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto UriRecipient::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::Bool::toCpp(obj.valid),\n            ::djinni::String::toCpp(obj.address),\n            ::djinni::String::toCpp(obj.label),\n            ::djinni::String::toCpp(obj.desc),\n            ::djinni::I64::toCpp(obj.amount)};\n}\n\nauto UriRecipient::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBUriRecipient alloc] initWithValid:(::djinni::Bool::fromCpp(cpp.valid))\n                                         address:(::djinni::String::fromCpp(cpp.address))\n                                           label:(::djinni::String::fromCpp(cpp.label))\n                                            desc:(::djinni::String::fromCpp(cpp.desc))\n                                          amount:(::djinni::I64::fromCpp(cpp.amount))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecipient.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBUriRecipient : NSObject\n- (nonnull instancetype)initWithValid:(BOOL)valid\n                              address:(nonnull NSString *)address\n                                label:(nonnull NSString *)label\n                                 desc:(nonnull NSString *)desc\n                               amount:(int64_t)amount;\n+ (nonnull instancetype)uriRecipientWithValid:(BOOL)valid\n                                      address:(nonnull NSString *)address\n                                        label:(nonnull NSString *)label\n                                         desc:(nonnull NSString *)desc\n                                       amount:(int64_t)amount;\n\n@property (nonatomic, readonly) BOOL valid;\n\n@property (nonatomic, readonly, nonnull) NSString * address;\n\n@property (nonatomic, readonly, nonnull) NSString * label;\n\n@property (nonatomic, readonly, nonnull) NSString * desc;\n\n@property (nonatomic, readonly) int64_t amount;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecipient.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecipient.h\"\n\n\n@implementation DBUriRecipient\n\n- (nonnull instancetype)initWithValid:(BOOL)valid\n                              address:(nonnull NSString *)address\n                                label:(nonnull NSString *)label\n                                 desc:(nonnull NSString *)desc\n                               amount:(int64_t)amount\n{\n    if (self = [super init]) {\n        _valid = valid;\n        _address = [address copy];\n        _label = [label copy];\n        _desc = [desc copy];\n        _amount = amount;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)uriRecipientWithValid:(BOOL)valid\n                                      address:(nonnull NSString *)address\n                                        label:(nonnull NSString *)label\n                                         desc:(nonnull NSString *)desc\n                                       amount:(int64_t)amount\n{\n    return [(DBUriRecipient*)[self alloc] initWithValid:valid\n                                                address:address\n                                                  label:label\n                                                   desc:desc\n                                                 amount:amount];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p valid:%@ address:%@ label:%@ desc:%@ amount:%@>\", self.class, (void *)self, @(self.valid), self.address, self.label, self.desc, @(self.amount)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecord.h\"\n#include \"uri_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBUriRecord;\n\nnamespace djinni_generated {\n\nstruct UriRecord\n{\n    using CppType = ::UriRecord;\n    using ObjcType = DBUriRecord*;\n\n    using Boxed = UriRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto UriRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.scheme),\n            ::djinni::String::toCpp(obj.path),\n            ::djinni::Map<::djinni::String, ::djinni::String>::toCpp(obj.items)};\n}\n\nauto UriRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBUriRecord alloc] initWithScheme:(::djinni::String::fromCpp(cpp.scheme))\n                                          path:(::djinni::String::fromCpp(cpp.path))\n                                         items:(::djinni::Map<::djinni::String, ::djinni::String>::fromCpp(cpp.items))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBUriRecord : NSObject\n- (nonnull instancetype)initWithScheme:(nonnull NSString *)scheme\n                                  path:(nonnull NSString *)path\n                                 items:(nonnull NSDictionary<NSString *, NSString *> *)items;\n+ (nonnull instancetype)uriRecordWithScheme:(nonnull NSString *)scheme\n                                       path:(nonnull NSString *)path\n                                      items:(nonnull NSDictionary<NSString *, NSString *> *)items;\n\n@property (nonatomic, readonly, nonnull) NSString * scheme;\n\n@property (nonatomic, readonly, nonnull) NSString * path;\n\n@property (nonatomic, readonly, nonnull) NSDictionary<NSString *, NSString *> * items;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBUriRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBUriRecord.h\"\n\n\n@implementation DBUriRecord\n\n- (nonnull instancetype)initWithScheme:(nonnull NSString *)scheme\n                                  path:(nonnull NSString *)path\n                                 items:(nonnull NSDictionary<NSString *, NSString *> *)items\n{\n    if (self = [super init]) {\n        _scheme = [scheme copy];\n        _path = [path copy];\n        _items = [items copy];\n    }\n    return self;\n}\n\n+ (nonnull instancetype)uriRecordWithScheme:(nonnull NSString *)scheme\n                                       path:(nonnull NSString *)path\n                                      items:(nonnull NSDictionary<NSString *, NSString *> *)items\n{\n    return [(DBUriRecord*)[self alloc] initWithScheme:scheme\n                                                 path:path\n                                                items:items];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p scheme:%@ path:%@ items:%@>\", self.class, (void *)self, self.scheme, self.path, self.items];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWalletLockStatus+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWalletLockStatus.h\"\n#include \"wallet_lock_status.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBWalletLockStatus;\n\nnamespace djinni_generated {\n\nstruct WalletLockStatus\n{\n    using CppType = ::WalletLockStatus;\n    using ObjcType = DBWalletLockStatus*;\n\n    using Boxed = WalletLockStatus;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWalletLockStatus+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWalletLockStatus+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto WalletLockStatus::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::Bool::toCpp(obj.locked),\n            ::djinni::I64::toCpp(obj.lockTimeout)};\n}\n\nauto WalletLockStatus::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBWalletLockStatus alloc] initWithLocked:(::djinni::Bool::fromCpp(cpp.locked))\n                                          lockTimeout:(::djinni::I64::fromCpp(cpp.lock_timeout))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWalletLockStatus.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBWalletLockStatus : NSObject\n- (nonnull instancetype)initWithLocked:(BOOL)locked\n                           lockTimeout:(int64_t)lockTimeout;\n+ (nonnull instancetype)walletLockStatusWithLocked:(BOOL)locked\n                                       lockTimeout:(int64_t)lockTimeout;\n\n@property (nonatomic, readonly) BOOL locked;\n\n@property (nonatomic, readonly) int64_t lockTimeout;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWalletLockStatus.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWalletLockStatus.h\"\n\n\n@implementation DBWalletLockStatus\n\n- (nonnull instancetype)initWithLocked:(BOOL)locked\n                           lockTimeout:(int64_t)lockTimeout\n{\n    if (self = [super init]) {\n        _locked = locked;\n        _lockTimeout = lockTimeout;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)walletLockStatusWithLocked:(BOOL)locked\n                                       lockTimeout:(int64_t)lockTimeout\n{\n    return [(DBWalletLockStatus*)[self alloc] initWithLocked:locked\n                                                 lockTimeout:lockTimeout];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p locked:%@ lockTimeout:%@>\", self.class, (void *)self, @(self.locked), @(self.lockTimeout)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessAccountStatisticsRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessAccountStatisticsRecord.h\"\n#include \"witness_account_statistics_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBWitnessAccountStatisticsRecord;\n\nnamespace djinni_generated {\n\nstruct WitnessAccountStatisticsRecord\n{\n    using CppType = ::WitnessAccountStatisticsRecord;\n    using ObjcType = DBWitnessAccountStatisticsRecord*;\n\n    using Boxed = WitnessAccountStatisticsRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessAccountStatisticsRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessAccountStatisticsRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto WitnessAccountStatisticsRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.requestStatus),\n            ::djinni::String::toCpp(obj.accountStatus),\n            ::djinni::I64::toCpp(obj.blocksSinceLastActivity),\n            ::djinni::I64::toCpp(obj.accountWeight),\n            ::djinni::I64::toCpp(obj.accountWeightAtCreation),\n            ::djinni::I64::toCpp(obj.accountParts),\n            ::djinni::I64::toCpp(obj.accountAmountLocked),\n            ::djinni::I64::toCpp(obj.accountAmountLockedAtCreation),\n            ::djinni::I64::toCpp(obj.networkTipTotalWeight),\n            ::djinni::I64::toCpp(obj.networkTotalWeightAtCreation),\n            ::djinni::I64::toCpp(obj.accountInitialLockPeriodInBlocks),\n            ::djinni::I64::toCpp(obj.accountRemainingLockPeriodInBlocks),\n            ::djinni::I64::toCpp(obj.accountExpectedWitnessPeriodInBlocks),\n            ::djinni::I64::toCpp(obj.accountEstimatedWitnessPeriodInBlocks),\n            ::djinni::I64::toCpp(obj.accountInitialLockCreationBlockHeight),\n            ::djinni::I32::toCpp(obj.compoundingPercent),\n            ::djinni::Bool::toCpp(obj.isOptimal)};\n}\n\nauto WitnessAccountStatisticsRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBWitnessAccountStatisticsRecord alloc] initWithRequestStatus:(::djinni::String::fromCpp(cpp.request_status))\n                                                             accountStatus:(::djinni::String::fromCpp(cpp.account_status))\n                                                   blocksSinceLastActivity:(::djinni::I64::fromCpp(cpp.blocks_since_last_activity))\n                                                             accountWeight:(::djinni::I64::fromCpp(cpp.account_weight))\n                                                   accountWeightAtCreation:(::djinni::I64::fromCpp(cpp.account_weight_at_creation))\n                                                              accountParts:(::djinni::I64::fromCpp(cpp.account_parts))\n                                                       accountAmountLocked:(::djinni::I64::fromCpp(cpp.account_amount_locked))\n                                             accountAmountLockedAtCreation:(::djinni::I64::fromCpp(cpp.account_amount_locked_at_creation))\n                                                     networkTipTotalWeight:(::djinni::I64::fromCpp(cpp.network_tip_total_weight))\n                                              networkTotalWeightAtCreation:(::djinni::I64::fromCpp(cpp.network_total_weight_at_creation))\n                                          accountInitialLockPeriodInBlocks:(::djinni::I64::fromCpp(cpp.account_initial_lock_period_in_blocks))\n                                        accountRemainingLockPeriodInBlocks:(::djinni::I64::fromCpp(cpp.account_remaining_lock_period_in_blocks))\n                                      accountExpectedWitnessPeriodInBlocks:(::djinni::I64::fromCpp(cpp.account_expected_witness_period_in_blocks))\n                                     accountEstimatedWitnessPeriodInBlocks:(::djinni::I64::fromCpp(cpp.account_estimated_witness_period_in_blocks))\n                                     accountInitialLockCreationBlockHeight:(::djinni::I64::fromCpp(cpp.account_initial_lock_creation_block_height))\n                                                        compoundingPercent:(::djinni::I32::fromCpp(cpp.compounding_percent))\n                                                                 isOptimal:(::djinni::Bool::fromCpp(cpp.is_optimal))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessAccountStatisticsRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBWitnessAccountStatisticsRecord : NSObject\n- (nonnull instancetype)initWithRequestStatus:(nonnull NSString *)requestStatus\n                                accountStatus:(nonnull NSString *)accountStatus\n                      blocksSinceLastActivity:(int64_t)blocksSinceLastActivity\n                                accountWeight:(int64_t)accountWeight\n                      accountWeightAtCreation:(int64_t)accountWeightAtCreation\n                                 accountParts:(int64_t)accountParts\n                          accountAmountLocked:(int64_t)accountAmountLocked\n                accountAmountLockedAtCreation:(int64_t)accountAmountLockedAtCreation\n                        networkTipTotalWeight:(int64_t)networkTipTotalWeight\n                 networkTotalWeightAtCreation:(int64_t)networkTotalWeightAtCreation\n             accountInitialLockPeriodInBlocks:(int64_t)accountInitialLockPeriodInBlocks\n           accountRemainingLockPeriodInBlocks:(int64_t)accountRemainingLockPeriodInBlocks\n         accountExpectedWitnessPeriodInBlocks:(int64_t)accountExpectedWitnessPeriodInBlocks\n        accountEstimatedWitnessPeriodInBlocks:(int64_t)accountEstimatedWitnessPeriodInBlocks\n        accountInitialLockCreationBlockHeight:(int64_t)accountInitialLockCreationBlockHeight\n                           compoundingPercent:(int32_t)compoundingPercent\n                                    isOptimal:(BOOL)isOptimal;\n+ (nonnull instancetype)witnessAccountStatisticsRecordWithRequestStatus:(nonnull NSString *)requestStatus\n                                                          accountStatus:(nonnull NSString *)accountStatus\n                                                blocksSinceLastActivity:(int64_t)blocksSinceLastActivity\n                                                          accountWeight:(int64_t)accountWeight\n                                                accountWeightAtCreation:(int64_t)accountWeightAtCreation\n                                                           accountParts:(int64_t)accountParts\n                                                    accountAmountLocked:(int64_t)accountAmountLocked\n                                          accountAmountLockedAtCreation:(int64_t)accountAmountLockedAtCreation\n                                                  networkTipTotalWeight:(int64_t)networkTipTotalWeight\n                                           networkTotalWeightAtCreation:(int64_t)networkTotalWeightAtCreation\n                                       accountInitialLockPeriodInBlocks:(int64_t)accountInitialLockPeriodInBlocks\n                                     accountRemainingLockPeriodInBlocks:(int64_t)accountRemainingLockPeriodInBlocks\n                                   accountExpectedWitnessPeriodInBlocks:(int64_t)accountExpectedWitnessPeriodInBlocks\n                                  accountEstimatedWitnessPeriodInBlocks:(int64_t)accountEstimatedWitnessPeriodInBlocks\n                                  accountInitialLockCreationBlockHeight:(int64_t)accountInitialLockCreationBlockHeight\n                                                     compoundingPercent:(int32_t)compoundingPercent\n                                                              isOptimal:(BOOL)isOptimal;\n\n/** Success if request succeeded, otherwise an error message */\n@property (nonatomic, readonly, nonnull) NSString * requestStatus;\n\n/** Current state of the witness account, one of: \"empty\", \"empty_with_remainder\", \"pending\", \"witnessing\", \"ended\", \"expired\", \"emptying\" */\n@property (nonatomic, readonly, nonnull) NSString * accountStatus;\n\n/** Account weight */\n@property (nonatomic, readonly) int64_t blocksSinceLastActivity;\n\n/** Account weight */\n@property (nonatomic, readonly) int64_t accountWeight;\n\n/** Account weight when it was created */\n@property (nonatomic, readonly) int64_t accountWeightAtCreation;\n\n/** How many parts the account weight is split up into */\n@property (nonatomic, readonly) int64_t accountParts;\n\n/** Account amount currently locked */\n@property (nonatomic, readonly) int64_t accountAmountLocked;\n\n/** Account amount locked when it was created */\n@property (nonatomic, readonly) int64_t accountAmountLockedAtCreation;\n\n/** Current network weight */\n@property (nonatomic, readonly) int64_t networkTipTotalWeight;\n\n/** Network weight when account was created */\n@property (nonatomic, readonly) int64_t networkTotalWeightAtCreation;\n\n/** Account total lock period in blocks (from creation block) */\n@property (nonatomic, readonly) int64_t accountInitialLockPeriodInBlocks;\n\n/** Account remaining lock period in blocks (from chain tip) */\n@property (nonatomic, readonly) int64_t accountRemainingLockPeriodInBlocks;\n\n/** How often the account is \"expected\" by the network to witness in order to not be kicked off */\n@property (nonatomic, readonly) int64_t accountExpectedWitnessPeriodInBlocks;\n\n/** How often the account is estimated to witness */\n@property (nonatomic, readonly) int64_t accountEstimatedWitnessPeriodInBlocks;\n\n/** Height at which the account lock first entered the chain */\n@property (nonatomic, readonly) int64_t accountInitialLockCreationBlockHeight;\n\n/** How much of the reward that this account earns is set to be compound */\n@property (nonatomic, readonly) int32_t compoundingPercent;\n\n/** Is the account weight split in an optimal way */\n@property (nonatomic, readonly) BOOL isOptimal;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessAccountStatisticsRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessAccountStatisticsRecord.h\"\n\n\n@implementation DBWitnessAccountStatisticsRecord\n\n- (nonnull instancetype)initWithRequestStatus:(nonnull NSString *)requestStatus\n                                accountStatus:(nonnull NSString *)accountStatus\n                      blocksSinceLastActivity:(int64_t)blocksSinceLastActivity\n                                accountWeight:(int64_t)accountWeight\n                      accountWeightAtCreation:(int64_t)accountWeightAtCreation\n                                 accountParts:(int64_t)accountParts\n                          accountAmountLocked:(int64_t)accountAmountLocked\n                accountAmountLockedAtCreation:(int64_t)accountAmountLockedAtCreation\n                        networkTipTotalWeight:(int64_t)networkTipTotalWeight\n                 networkTotalWeightAtCreation:(int64_t)networkTotalWeightAtCreation\n             accountInitialLockPeriodInBlocks:(int64_t)accountInitialLockPeriodInBlocks\n           accountRemainingLockPeriodInBlocks:(int64_t)accountRemainingLockPeriodInBlocks\n         accountExpectedWitnessPeriodInBlocks:(int64_t)accountExpectedWitnessPeriodInBlocks\n        accountEstimatedWitnessPeriodInBlocks:(int64_t)accountEstimatedWitnessPeriodInBlocks\n        accountInitialLockCreationBlockHeight:(int64_t)accountInitialLockCreationBlockHeight\n                           compoundingPercent:(int32_t)compoundingPercent\n                                    isOptimal:(BOOL)isOptimal\n{\n    if (self = [super init]) {\n        _requestStatus = [requestStatus copy];\n        _accountStatus = [accountStatus copy];\n        _blocksSinceLastActivity = blocksSinceLastActivity;\n        _accountWeight = accountWeight;\n        _accountWeightAtCreation = accountWeightAtCreation;\n        _accountParts = accountParts;\n        _accountAmountLocked = accountAmountLocked;\n        _accountAmountLockedAtCreation = accountAmountLockedAtCreation;\n        _networkTipTotalWeight = networkTipTotalWeight;\n        _networkTotalWeightAtCreation = networkTotalWeightAtCreation;\n        _accountInitialLockPeriodInBlocks = accountInitialLockPeriodInBlocks;\n        _accountRemainingLockPeriodInBlocks = accountRemainingLockPeriodInBlocks;\n        _accountExpectedWitnessPeriodInBlocks = accountExpectedWitnessPeriodInBlocks;\n        _accountEstimatedWitnessPeriodInBlocks = accountEstimatedWitnessPeriodInBlocks;\n        _accountInitialLockCreationBlockHeight = accountInitialLockCreationBlockHeight;\n        _compoundingPercent = compoundingPercent;\n        _isOptimal = isOptimal;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)witnessAccountStatisticsRecordWithRequestStatus:(nonnull NSString *)requestStatus\n                                                          accountStatus:(nonnull NSString *)accountStatus\n                                                blocksSinceLastActivity:(int64_t)blocksSinceLastActivity\n                                                          accountWeight:(int64_t)accountWeight\n                                                accountWeightAtCreation:(int64_t)accountWeightAtCreation\n                                                           accountParts:(int64_t)accountParts\n                                                    accountAmountLocked:(int64_t)accountAmountLocked\n                                          accountAmountLockedAtCreation:(int64_t)accountAmountLockedAtCreation\n                                                  networkTipTotalWeight:(int64_t)networkTipTotalWeight\n                                           networkTotalWeightAtCreation:(int64_t)networkTotalWeightAtCreation\n                                       accountInitialLockPeriodInBlocks:(int64_t)accountInitialLockPeriodInBlocks\n                                     accountRemainingLockPeriodInBlocks:(int64_t)accountRemainingLockPeriodInBlocks\n                                   accountExpectedWitnessPeriodInBlocks:(int64_t)accountExpectedWitnessPeriodInBlocks\n                                  accountEstimatedWitnessPeriodInBlocks:(int64_t)accountEstimatedWitnessPeriodInBlocks\n                                  accountInitialLockCreationBlockHeight:(int64_t)accountInitialLockCreationBlockHeight\n                                                     compoundingPercent:(int32_t)compoundingPercent\n                                                              isOptimal:(BOOL)isOptimal\n{\n    return [(DBWitnessAccountStatisticsRecord*)[self alloc] initWithRequestStatus:requestStatus\n                                                                    accountStatus:accountStatus\n                                                          blocksSinceLastActivity:blocksSinceLastActivity\n                                                                    accountWeight:accountWeight\n                                                          accountWeightAtCreation:accountWeightAtCreation\n                                                                     accountParts:accountParts\n                                                              accountAmountLocked:accountAmountLocked\n                                                    accountAmountLockedAtCreation:accountAmountLockedAtCreation\n                                                            networkTipTotalWeight:networkTipTotalWeight\n                                                     networkTotalWeightAtCreation:networkTotalWeightAtCreation\n                                                 accountInitialLockPeriodInBlocks:accountInitialLockPeriodInBlocks\n                                               accountRemainingLockPeriodInBlocks:accountRemainingLockPeriodInBlocks\n                                             accountExpectedWitnessPeriodInBlocks:accountExpectedWitnessPeriodInBlocks\n                                            accountEstimatedWitnessPeriodInBlocks:accountEstimatedWitnessPeriodInBlocks\n                                            accountInitialLockCreationBlockHeight:accountInitialLockCreationBlockHeight\n                                                               compoundingPercent:compoundingPercent\n                                                                        isOptimal:isOptimal];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p requestStatus:%@ accountStatus:%@ blocksSinceLastActivity:%@ accountWeight:%@ accountWeightAtCreation:%@ accountParts:%@ accountAmountLocked:%@ accountAmountLockedAtCreation:%@ networkTipTotalWeight:%@ networkTotalWeightAtCreation:%@ accountInitialLockPeriodInBlocks:%@ accountRemainingLockPeriodInBlocks:%@ accountExpectedWitnessPeriodInBlocks:%@ accountEstimatedWitnessPeriodInBlocks:%@ accountInitialLockCreationBlockHeight:%@ compoundingPercent:%@ isOptimal:%@>\", self.class, (void *)self, self.requestStatus, self.accountStatus, @(self.blocksSinceLastActivity), @(self.accountWeight), @(self.accountWeightAtCreation), @(self.accountParts), @(self.accountAmountLocked), @(self.accountAmountLockedAtCreation), @(self.networkTipTotalWeight), @(self.networkTotalWeightAtCreation), @(self.accountInitialLockPeriodInBlocks), @(self.accountRemainingLockPeriodInBlocks), @(self.accountExpectedWitnessPeriodInBlocks), @(self.accountEstimatedWitnessPeriodInBlocks), @(self.accountInitialLockCreationBlockHeight), @(self.compoundingPercent), @(self.isOptimal)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessEstimateInfoRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessEstimateInfoRecord.h\"\n#include \"witness_estimate_info_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBWitnessEstimateInfoRecord;\n\nnamespace djinni_generated {\n\nstruct WitnessEstimateInfoRecord\n{\n    using CppType = ::WitnessEstimateInfoRecord;\n    using ObjcType = DBWitnessEstimateInfoRecord*;\n\n    using Boxed = WitnessEstimateInfoRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessEstimateInfoRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessEstimateInfoRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto WitnessEstimateInfoRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::I64::toCpp(obj.networkWeight),\n            ::djinni::I64::toCpp(obj.weight),\n            ::djinni::I64::toCpp(obj.parts),\n            ::djinni::F64::toCpp(obj.estimatedWitnessProbability),\n            ::djinni::F64::toCpp(obj.estimatedBlocksPerDay),\n            ::djinni::I64::toCpp(obj.estimatedDailyEarnings),\n            ::djinni::I64::toCpp(obj.estimatedLifetimeEarnings)};\n}\n\nauto WitnessEstimateInfoRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBWitnessEstimateInfoRecord alloc] initWithNetworkWeight:(::djinni::I64::fromCpp(cpp.network_weight))\n                                                               weight:(::djinni::I64::fromCpp(cpp.weight))\n                                                                parts:(::djinni::I64::fromCpp(cpp.parts))\n                                          estimatedWitnessProbability:(::djinni::F64::fromCpp(cpp.estimated_witness_probability))\n                                                estimatedBlocksPerDay:(::djinni::F64::fromCpp(cpp.estimated_blocks_per_day))\n                                               estimatedDailyEarnings:(::djinni::I64::fromCpp(cpp.estimated_daily_earnings))\n                                            estimatedLifetimeEarnings:(::djinni::I64::fromCpp(cpp.estimated_lifetime_earnings))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessEstimateInfoRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBWitnessEstimateInfoRecord : NSObject\n- (nonnull instancetype)initWithNetworkWeight:(int64_t)networkWeight\n                                       weight:(int64_t)weight\n                                        parts:(int64_t)parts\n                  estimatedWitnessProbability:(double)estimatedWitnessProbability\n                        estimatedBlocksPerDay:(double)estimatedBlocksPerDay\n                       estimatedDailyEarnings:(int64_t)estimatedDailyEarnings\n                    estimatedLifetimeEarnings:(int64_t)estimatedLifetimeEarnings;\n+ (nonnull instancetype)witnessEstimateInfoRecordWithNetworkWeight:(int64_t)networkWeight\n                                                            weight:(int64_t)weight\n                                                             parts:(int64_t)parts\n                                       estimatedWitnessProbability:(double)estimatedWitnessProbability\n                                             estimatedBlocksPerDay:(double)estimatedBlocksPerDay\n                                            estimatedDailyEarnings:(int64_t)estimatedDailyEarnings\n                                         estimatedLifetimeEarnings:(int64_t)estimatedLifetimeEarnings;\n\n/** Current network weight */\n@property (nonatomic, readonly) int64_t networkWeight;\n\n/** Weight of resulting witness account */\n@property (nonatomic, readonly) int64_t weight;\n\n/** How many parts this weight will be split into */\n@property (nonatomic, readonly) int64_t parts;\n\n/** The per block probability of resulting account witnesing */\n@property (nonatomic, readonly) double estimatedWitnessProbability;\n\n/** The estimated number of blocks the resulting account should find per day */\n@property (nonatomic, readonly) double estimatedBlocksPerDay;\n\n/** The estimated earnings the account should make per day */\n@property (nonatomic, readonly) int64_t estimatedDailyEarnings;\n\n/** The estimated earnings the account should make over its entire lifetime */\n@property (nonatomic, readonly) int64_t estimatedLifetimeEarnings;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessEstimateInfoRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessEstimateInfoRecord.h\"\n\n\n@implementation DBWitnessEstimateInfoRecord\n\n- (nonnull instancetype)initWithNetworkWeight:(int64_t)networkWeight\n                                       weight:(int64_t)weight\n                                        parts:(int64_t)parts\n                  estimatedWitnessProbability:(double)estimatedWitnessProbability\n                        estimatedBlocksPerDay:(double)estimatedBlocksPerDay\n                       estimatedDailyEarnings:(int64_t)estimatedDailyEarnings\n                    estimatedLifetimeEarnings:(int64_t)estimatedLifetimeEarnings\n{\n    if (self = [super init]) {\n        _networkWeight = networkWeight;\n        _weight = weight;\n        _parts = parts;\n        _estimatedWitnessProbability = estimatedWitnessProbability;\n        _estimatedBlocksPerDay = estimatedBlocksPerDay;\n        _estimatedDailyEarnings = estimatedDailyEarnings;\n        _estimatedLifetimeEarnings = estimatedLifetimeEarnings;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)witnessEstimateInfoRecordWithNetworkWeight:(int64_t)networkWeight\n                                                            weight:(int64_t)weight\n                                                             parts:(int64_t)parts\n                                       estimatedWitnessProbability:(double)estimatedWitnessProbability\n                                             estimatedBlocksPerDay:(double)estimatedBlocksPerDay\n                                            estimatedDailyEarnings:(int64_t)estimatedDailyEarnings\n                                         estimatedLifetimeEarnings:(int64_t)estimatedLifetimeEarnings\n{\n    return [(DBWitnessEstimateInfoRecord*)[self alloc] initWithNetworkWeight:networkWeight\n                                                                      weight:weight\n                                                                       parts:parts\n                                                 estimatedWitnessProbability:estimatedWitnessProbability\n                                                       estimatedBlocksPerDay:estimatedBlocksPerDay\n                                                      estimatedDailyEarnings:estimatedDailyEarnings\n                                                   estimatedLifetimeEarnings:estimatedLifetimeEarnings];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p networkWeight:%@ weight:%@ parts:%@ estimatedWitnessProbability:%@ estimatedBlocksPerDay:%@ estimatedDailyEarnings:%@ estimatedLifetimeEarnings:%@>\", self.class, (void *)self, @(self.networkWeight), @(self.weight), @(self.parts), @(self.estimatedWitnessProbability), @(self.estimatedBlocksPerDay), @(self.estimatedDailyEarnings), @(self.estimatedLifetimeEarnings)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessFundingResultRecord+Private.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessFundingResultRecord.h\"\n#include \"witness_funding_result_record.hpp\"\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n@class DBWitnessFundingResultRecord;\n\nnamespace djinni_generated {\n\nstruct WitnessFundingResultRecord\n{\n    using CppType = ::WitnessFundingResultRecord;\n    using ObjcType = DBWitnessFundingResultRecord*;\n\n    using Boxed = WitnessFundingResultRecord;\n\n    static CppType toCpp(ObjcType objc);\n    static ObjcType fromCpp(const CppType& cpp);\n};\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessFundingResultRecord+Private.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessFundingResultRecord+Private.h\"\n#import \"DJIMarshal+Private.h\"\n#include <cassert>\n\nnamespace djinni_generated {\n\nauto WitnessFundingResultRecord::toCpp(ObjcType obj) -> CppType\n{\n    assert(obj);\n    return {::djinni::String::toCpp(obj.status),\n            ::djinni::String::toCpp(obj.txid),\n            ::djinni::I64::toCpp(obj.fee)};\n}\n\nauto WitnessFundingResultRecord::fromCpp(const CppType& cpp) -> ObjcType\n{\n    return [[DBWitnessFundingResultRecord alloc] initWithStatus:(::djinni::String::fromCpp(cpp.status))\n                                                           txid:(::djinni::String::fromCpp(cpp.txid))\n                                                            fee:(::djinni::I64::fromCpp(cpp.fee))];\n}\n\n}  // namespace djinni_generated\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessFundingResultRecord.h",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import <Foundation/Foundation.h>\n\n@interface DBWitnessFundingResultRecord : NSObject\n- (nonnull instancetype)initWithStatus:(nonnull NSString *)status\n                                  txid:(nonnull NSString *)txid\n                                   fee:(int64_t)fee;\n+ (nonnull instancetype)witnessFundingResultRecordWithStatus:(nonnull NSString *)status\n                                                        txid:(nonnull NSString *)txid\n                                                         fee:(int64_t)fee;\n\n/** \"success\" on success, otherwise an error message */\n@property (nonatomic, readonly, nonnull) NSString * status;\n\n/** txid of the funding transaction, empty on failure */\n@property (nonatomic, readonly, nonnull) NSString * txid;\n\n/** fee charged by the transaction, 0 on failure */\n@property (nonatomic, readonly) int64_t fee;\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/objc/DBWitnessFundingResultRecord.mm",
    "content": "// AUTOGENERATED FILE - DO NOT MODIFY!\n// This file generated by Djinni from libunity.djinni\n\n#import \"DBWitnessFundingResultRecord.h\"\n\n\n@implementation DBWitnessFundingResultRecord\n\n- (nonnull instancetype)initWithStatus:(nonnull NSString *)status\n                                  txid:(nonnull NSString *)txid\n                                   fee:(int64_t)fee\n{\n    if (self = [super init]) {\n        _status = [status copy];\n        _txid = [txid copy];\n        _fee = fee;\n    }\n    return self;\n}\n\n+ (nonnull instancetype)witnessFundingResultRecordWithStatus:(nonnull NSString *)status\n                                                        txid:(nonnull NSString *)txid\n                                                         fee:(int64_t)fee\n{\n    return [(DBWitnessFundingResultRecord*)[self alloc] initWithStatus:status\n                                                                  txid:txid\n                                                                   fee:fee];\n}\n\n- (NSString *)description\n{\n    return [NSString stringWithFormat:@\"<%@ %p status:%@ txid:%@ fee:%@>\", self.class, (void *)self, self.status, self.txid, @(self.fee)];\n}\n\n@end\n"
  },
  {
    "path": "src/unity/djinni/support-lib/djinni_common.hpp",
    "content": "//\n// Copyright 2015 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#ifdef _MSC_VER\n    #define DJINNI_WEAK_DEFINITION // weak attribute not supported by MSVC\n    #define DJINNI_NORETURN_DEFINITION __declspec(noreturn)\n    #if _MSC_VER < 1900 // snprintf not implemented prior to VS2015\n        #define DJINNI_SNPRINTF snprintf\n        #define noexcept _NOEXCEPT // work-around for missing noexcept VS2015\n        #define constexpr // work-around for missing constexpr VS2015\n    #else\n        #define DJINNI_SNPRINTF _snprintf\n    #endif\n#else\n    #define DJINNI_WEAK_DEFINITION __attribute__((weak))\n    #define DJINNI_NORETURN_DEFINITION __attribute__((noreturn))\n    #define DJINNI_SNPRINTF snprintf\n#endif\n"
  },
  {
    "path": "src/unity/djinni/support-lib/ios-build-support-lib.sh",
    "content": "#!/bin/sh\n# This script helps you to build apple fat binaries.\n# This uses the excellent https://github.com/leetal/ios-cmake cmake platform file.\n\nBASEDIR=$(cd \"$(dirname \"$0\")\"; pwd)\n\n# The directory used for building\nBUILD_DIR=${BASEDIR}/build\n\n# The directory where library will be generated\nOUTPUT_DIR=${BASEDIR}/out/apple\n\n# The architecture to build for apple\n# See https://github.com/leetal/ios-cmake for more informations\nBUILD_APPLE_ARCHITECTURES=(OS SIMULATOR64)\n\n# Enable disable bitcode\nENABLE_BITCODE=true\n\n# Helper functions for building one arhcitecture\nfunction build_apple_native_static_arch {\n  echo \"Building Native $1\"\n\n  cd ${BUILD_DIR}\n  BUILD_PATH=build_$1\n  if [ -d ${BUILD_PATH} ]; then\n    rm -f ${BUILD_PATH}/*\n    rmdir ${BUILD_PATH}\n  fi\n\n  mkdir -p  ${BUILD_PATH}\n  cd ${BUILD_PATH}\n  \n  cmake ${BASEDIR}/.. -DDJINNI_WITH_OBJC=ON -DDJINNI_WITH_JNI=OFF -DDJINNI_STATIC_LIB=ON -DCMAKE_TOOLCHAIN_FILE=${BASEDIR}/../cmake/ios.toolchain.cmake -DIOS_PLATFORM=$1 -DENABLE_BITCODE=${ENABLE_BITCODE} -DCMAKE_INSTALL_PREFIX=${BUILD_PATH}\n  make -j 4\n  \n  cp ${BUILD_DIR}/${BUILD_PATH}/libdjinni_support_lib.a ${OUTPUT_DIR}/libdjinni_support_lib_$1.a\n  \n  cd ${BUILD_DIR}\n  rm -rf ${BUILD_PATH}\n}\n\n# Start of the script\necho \"Checking build directory...\"\nif [ -d ${BUILD_DIR} ]; then\n    rm -rf ${BUILD_DIR}/*\n    rmdir ${BUILD_DIR}\nfi\nmkdir -p ${BUILD_DIR}\n\necho \"Checking output directory...\"\nif [ -d ${OUTPUT_DIR} ]; then\n    rm -rf ${OUTPUT_DIR}/*\n    rmdir ${OUTPUT_DIR}\nfi\n\nmkdir -p ${OUTPUT_DIR}\n\n# Build elements\n\nfor arch in ${BUILD_APPLE_ARCHITECTURES[@]}\ndo\n  build_apple_native_static_arch ${arch}\ndone\n\n# Lipo creates a fat binary\nlipo -create ${OUTPUT_DIR}/*.a -output ${OUTPUT_DIR}/libdjinni_support_lib_UNIVERSAL.a\n"
  },
  {
    "path": "src/unity/djinni/support-lib/java/com/dropbox/djinni/NativeLibLoader.java",
    "content": "//\n// Copyright 2015 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//        http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\npackage com.dropbox.djinni;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.util.Collections;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Utilities for loading native libraries containing djinni interfaces\n * and records. To load libraries in your application at startup,\n * simply place them:\n *  * inside the jar containing this code at the (jar-relative)\n *      path `djinniNativeLibsJarPath`\n *  * somewhere on the host filesystem and use the `djinniNativeLibsSysProp`\n *      system property to provide path(s)\n *\n * Then execute:\n * <code>\n *     NativeLibLoader.loadLibs()\n * </code>\n * to load the libraries (e.g. in your main() or a class static initializer).\n */\npublic class NativeLibLoader {\n\n    /**\n     * Canonical directory in a jar containing (djinni-adapted) native libraries\n     */\n    public static final String djinniNativeLibsJarPath =\n            \"resources/djinni_native_libs\";\n\n    /**\n     * Load native libraries with djinni support from the (comma-separated)\n     * path(s) provided in this system property\n     */\n    public static final String djinniNativeLibsSysProp =\n            \"djinni.native_libs_dirs\";\n\n    private static final Logger log =\n            Logger.getLogger(NativeLibLoader.class.getName());\n\n    private NativeLibLoader() { }\n\n    // Load native libs from canonical locations\n    public static void loadLibs() throws URISyntaxException, IOException {\n        // Try to load from Jar\n        loadLibsFromJarPath(djinniNativeLibsJarPath);\n\n        // Try to load from system\n        String localPaths = System.getProperty(djinniNativeLibsSysProp);\n        if (localPaths != null) {\n            log.log(Level.FINE, \"Loading local native libs\");\n            for (String localPath : localPaths.split(\",\")) {\n                loadLibsFromLocalPath(Paths.get(localPath));\n            }\n        }\n    }\n\n    // Load native lib(s) from the given `localPath` - a file or directory\n    public static void loadLibsFromLocalPath(Path localPath) throws IOException {\n        File localFile = localPath.toFile();\n        if (!localFile.exists()) { return; }\n        if (localFile.isDirectory()) {\n            log.log(Level.FINE, \"Loading all libs in \" + localFile.getAbsolutePath());\n            for (File f : localFile.listFiles()) {\n                if (f.isFile()) {\n                    loadLibrary(f.getAbsolutePath());\n                }\n            }\n        } else {\n            loadLibrary(localFile.getAbsolutePath());\n        }\n    }\n\n    // Load a directory of libs from a jar resource path\n    public static void loadLibsFromJarPath(String jarPath)\n            throws URISyntaxException, IOException {\n\n        // Do we have a valid path?\n        URL libsURL =\n                NativeLibLoader.class\n                    .getClassLoader()\n                    .getResource(djinniNativeLibsJarPath);\n        if (libsURL == null) { return; }\n\n        // Are we actually referencing a jar path?\n        if (!libsURL.toURI().getScheme().equals(\"jar\")) { return; }\n\n        log.log(Level.FINE, \"Loading libs from jar path \" + jarPath);\n\n        // Walk the directory and load libs\n        FileSystem fs =\n                FileSystems.newFileSystem(libsURL.toURI(), Collections.<String, String>emptyMap());\n        Path myPath = fs.getPath(jarPath);\n\n        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(myPath);\n        try {\n            for (Path p : directoryStream) {\n                loadLibFromJarPath(p);\n            }\n        } finally {\n            directoryStream.close();\n        }\n\n        fs.close();\n    }\n\n    // Load a single native lib from a jar resource with path `libPath`\n    public static void loadLibFromJarPath(Path libPath) throws IOException {\n\n        // System libraries *must* be loaded from the filesystem,\n        // so we must copy the lib's data from the jar to a tempfile\n\n        InputStream libIn =\n            NativeLibLoader.class.getResourceAsStream(libPath.toString());\n        if (libIn == null) { return; } // Invalid `libPath`\n\n        // Name the tempfile\n        String libName = libPath.getName(libPath.getNameCount() - 1).toString();\n            // Name the tempfile after the lib to ease debugging\n        String suffix = null;\n        int extPos = libName.lastIndexOf('.');\n        if (extPos > 0) { suffix = libName.substring(extPos + 1); }\n            // Try to suffix the tempfile with the lib's suffix so that other\n            // tools (e.g. profilers) identify the file correctly\n\n        File tempLib = File.createTempFile(libName, suffix);\n        tempLib.deleteOnExit();\n\n        log.log(\n            Level.FINE,\n            \"Copying jar lib \" + libPath + \" to \" + tempLib.getAbsolutePath());\n        try {\n            Files.copy(libIn, tempLib.toPath(), StandardCopyOption.REPLACE_EXISTING);\n        } catch (SecurityException e) {\n            throw new RuntimeException(\n                    \"SecurityException while trying to create tempfile: \" +\n                        e.getMessage() + \"\\n\\n If you cannot grant this process \" +\n                        \"permissions to create temporary files, you need to install \" +\n                        \"the native libraries manually and provide the installation \" +\n                        \"path(s) using the system property \" + djinniNativeLibsSysProp);\n        }\n\n        loadLibrary(tempLib.getAbsolutePath());\n    }\n\n    private static void loadLibrary(String abspath) {\n        System.load(abspath);\n        log.log(Level.INFO, \"Loaded \" + abspath);\n    }\n}\n"
  },
  {
    "path": "src/unity/djinni/support-lib/jni/Marshal.hpp",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#include \"djinni_support.hpp\"\n#include <cassert>\n#include <chrono>\n#include <cstdint>\n#include <string>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\nnamespace djinni\n{\n    template<class Self, class CppT, class JniT>\n    class Primitive\n    {\n    public:\n        using CppType = CppT;\n        using JniType = JniT;\n\n        static CppType toCpp(JNIEnv* /*jniEnv*/, JniType j) noexcept { return static_cast<CppType>(j); }\n        static JniType fromCpp(JNIEnv* /*jniEnv*/, CppType c) noexcept { return static_cast<JniType>(c); }\n\n        struct Boxed\n        {\n            using JniType = jobject;\n            static CppType toCpp(JNIEnv* jniEnv, JniType j)\n            {\n                assert(j != nullptr);\n                const auto& data = JniClass<Self>::get();\n                assert(jniEnv->IsInstanceOf(j, data.clazz.get()));\n                auto ret = Primitive::toCpp(jniEnv, Self::unbox(jniEnv, data.method_unbox, j));\n                jniExceptionCheck(jniEnv);\n                return ret;\n            }\n            static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c)\n            {\n                const auto& data = JniClass<Self>::get();\n                auto ret = jniEnv->CallStaticObjectMethod(data.clazz.get(), data.method_box, Primitive::fromCpp(jniEnv, c));\n                jniExceptionCheck(jniEnv);\n                return {jniEnv, ret};\n            }\n        };\n\n    protected:\n        Primitive(const char* javaClassSpec,\n                  const char* staticBoxMethod,\n                  const char* staticBoxMethodSignature,\n                  const char* unboxMethod,\n                  const char* unboxMethodSignature)\n        : clazz(jniFindClass(javaClassSpec))\n        , method_box(jniGetStaticMethodID(clazz.get(), staticBoxMethod, staticBoxMethodSignature))\n        , method_unbox(jniGetMethodID(clazz.get(), unboxMethod, unboxMethodSignature))\n        {}\n\n    private:\n        const GlobalRef<jclass> clazz;\n        const jmethodID method_box;\n        const jmethodID method_unbox;\n    };\n\n    class Bool : public Primitive<Bool, bool, jboolean>\n    {\n        Bool() : Primitive(\"java/lang/Boolean\", \"valueOf\", \"(Z)Ljava/lang/Boolean;\", \"booleanValue\", \"()Z\") {}\n        friend JniClass<Bool>;\n        friend Primitive<Bool, bool, jboolean>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallBooleanMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class I8 : public Primitive<I8, int8_t, jbyte>\n    {\n        I8() : Primitive(\"java/lang/Byte\", \"valueOf\", \"(B)Ljava/lang/Byte;\", \"byteValue\", \"()B\") {}\n        friend JniClass<I8>;\n        friend Primitive<I8, int8_t, jbyte>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallByteMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class I16 : public Primitive<I16, int16_t, jshort>\n    {\n        I16() : Primitive(\"java/lang/Short\", \"valueOf\", \"(S)Ljava/lang/Short;\", \"shortValue\", \"()S\") {}\n        friend JniClass<I16>;\n        friend Primitive<I16, int16_t, jshort>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallShortMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class I32 : public Primitive<I32, int32_t, jint>\n    {\n        I32() : Primitive(\"java/lang/Integer\", \"valueOf\", \"(I)Ljava/lang/Integer;\", \"intValue\", \"()I\") {}\n        friend JniClass<I32>;\n        friend Primitive<I32, int32_t, jint>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallIntMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class I64 : public Primitive<I64, int64_t, jlong>\n    {\n        I64() : Primitive(\"java/lang/Long\", \"valueOf\", \"(J)Ljava/lang/Long;\", \"longValue\", \"()J\") {}\n        friend JniClass<I64>;\n        friend Primitive<I64, int64_t, jlong>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallLongMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class F32 : public Primitive<F32, float, jfloat>\n    {\n        F32() : Primitive(\"java/lang/Float\", \"valueOf\", \"(F)Ljava/lang/Float;\", \"floatValue\", \"()F\") {}\n        friend JniClass<F32>;\n        friend Primitive<F32, float, jfloat>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallFloatMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    class F64 : public Primitive<F64, double, jdouble>\n    {\n        F64() : Primitive(\"java/lang/Double\", \"valueOf\", \"(D)Ljava/lang/Double;\", \"doubleValue\", \"()D\") {}\n        friend JniClass<F64>;\n        friend Primitive<F64, double, jdouble>;\n        static JniType unbox(JNIEnv* jniEnv, jmethodID method, jobject j) {\n            auto result = jniEnv->CallDoubleMethod(j, method);\n            jniExceptionCheck(jniEnv);\n            return result;\n        }\n    };\n\n    struct String\n    {\n        using CppType = std::string;\n        using JniType = jstring;\n\n        using Boxed = String;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n            return jniUTF8FromString(jniEnv, j);\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            return {jniEnv, jniStringFromUTF8(jniEnv, c)};\n        }\n    };\n\n    struct WString\n    {\n        using CppType = std::wstring;\n        using JniType = jstring;\n\n        using Boxed = WString;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n            return jniWStringFromString(jniEnv, j);\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            return {jniEnv, jniStringFromWString(jniEnv, c)};\n        }\n    };\n\n    struct Binary\n    {\n        using CppType = std::vector<uint8_t>;\n        using JniType = jbyteArray;\n\n        using Boxed = Binary;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n\n            std::vector<uint8_t> ret;\n            jsize length = jniEnv->GetArrayLength(j);\n            jniExceptionCheck(jniEnv);\n\n            if (!length) {\n                return ret;\n            }\n\n            {\n                auto deleter = [jniEnv, j] (void* c) {\n                    if (c) {\n                        jniEnv->ReleasePrimitiveArrayCritical(j, c, JNI_ABORT);\n                    }\n                };\n\n                std::unique_ptr<uint8_t, decltype(deleter)> ptr(\n                    reinterpret_cast<uint8_t*>(jniEnv->GetPrimitiveArrayCritical(j, nullptr)),\n                    deleter\n                );\n\n                if (ptr) {\n                    // Construct and then move-assign. This copies the elements only once,\n                    // and avoids having to initialize before filling (as with resize())\n                    ret = std::vector<uint8_t>{ptr.get(), ptr.get() + length};\n                } else {\n                    // Something failed...\n                    jniExceptionCheck(jniEnv);\n                }\n            }\n\n            return ret;\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            assert(c.size() <= std::numeric_limits<jsize>::max());\n            auto j = LocalRef<jbyteArray>(jniEnv, jniEnv->NewByteArray(static_cast<jsize>(c.size())));\n            jniExceptionCheck(jniEnv);\n            // Using .data() on an empty vector is UB\n            if(!c.empty())\n            {\n                jniEnv->SetByteArrayRegion(j.get(), 0, jsize(c.size()), reinterpret_cast<const jbyte*>(c.data()));\n            }\n            return j;\n        }\n    };\n\n    struct Date\n    {\n        using CppType = std::chrono::system_clock::time_point;\n        using JniType = jobject;\n\n        using Boxed = Date;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);\n            assert(j != nullptr);\n            const auto & data = JniClass<Date>::get();\n            assert(jniEnv->IsInstanceOf(j, data.clazz.get()));\n            auto time_millis = jniEnv->CallLongMethod(j, data.method_get_time);\n            jniExceptionCheck(jniEnv);\n            return POSIX_EPOCH + std::chrono::milliseconds{time_millis};\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            static const auto POSIX_EPOCH = std::chrono::system_clock::from_time_t(0);\n            const auto & data = JniClass<Date>::get();\n            const auto cpp_millis = std::chrono::duration_cast<std::chrono::milliseconds>(c - POSIX_EPOCH);\n            const jlong millis = static_cast<jlong>(cpp_millis.count());\n            auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, millis));\n            jniExceptionCheck(jniEnv);\n            return j;\n        }\n\n    private:\n        Date() = default;\n        friend ::djinni::JniClass<Date>;\n\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/Date\") };\n        const jmethodID constructor { jniGetMethodID(clazz.get(), \"<init>\", \"(J)V\") };\n        const jmethodID method_get_time { jniGetMethodID(clazz.get(), \"getTime\", \"()J\") };\n    };\n\n    template <template <class> class OptionalType, class T>\n    struct Optional\n    {\n        // SFINAE helper: if C::CppOptType exists, opt_type<T>(nullptr) will return\n        // that type. If not, it returns OptionalType<C::CppType>. This is necessary\n        // because we special-case optional interfaces to be represented as a nullable\n        // std::shared_ptr<T>, not optional<shared_ptr<T>> or optional<nn<shared_ptr<T>>>.\n        template <typename C> static OptionalType<typename C::CppType> opt_type(...);\n        template <typename C> static typename C::CppOptType opt_type(typename C::CppOptType *);\n        using CppType = decltype(opt_type<T>(nullptr));\n\n        using JniType = typename T::Boxed::JniType;\n\n        using Boxed = Optional;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            if (j) {\n                return T::Boxed::toCpp(jniEnv, j);\n            } else {\n                return CppType();\n            }\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const OptionalType<typename T::CppType> &c)\n        {\n            return c ? T::Boxed::fromCpp(jniEnv, *c) : LocalRef<JniType>{};\n        }\n\n        // fromCpp used for nullable shared_ptr\n        template <typename C = T>\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const typename C::CppOptType & cppOpt) {\n            return T::Boxed::fromCppOpt(jniEnv, cppOpt);\n        }\n    };\n\n    struct ListJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/ArrayList\") };\n        const jmethodID constructor { jniGetMethodID(clazz.get(), \"<init>\", \"(I)V\") };\n        const jmethodID method_add { jniGetMethodID(clazz.get(), \"add\", \"(Ljava/lang/Object;)Z\") };\n        const jmethodID method_get { jniGetMethodID(clazz.get(), \"get\", \"(I)Ljava/lang/Object;\") };\n        const jmethodID method_size { jniGetMethodID(clazz.get(), \"size\", \"()I\") };\n    };\n\n    template <class T>\n    class List\n    {\n        using ECppType = typename T::CppType;\n        using EJniType = typename T::Boxed::JniType;\n\n    public:\n        using CppType = std::vector<ECppType>;\n        using JniType = jobject;\n\n        using Boxed = List;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n            const auto& data = JniClass<ListJniInfo>::get();\n            assert(jniEnv->IsInstanceOf(j, data.clazz.get()));\n            auto size = jniEnv->CallIntMethod(j, data.method_size);\n            jniExceptionCheck(jniEnv);\n            auto c = CppType();\n            c.reserve(size);\n            for(jint i = 0; i < size; ++i)\n            {\n                auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_get, i));\n                jniExceptionCheck(jniEnv);\n                c.push_back(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));\n            }\n            return c;\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            const auto& data = JniClass<ListJniInfo>::get();\n            assert(c.size() <= std::numeric_limits<jint>::max());\n            auto size = static_cast<jint>(c.size());\n            auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));\n            jniExceptionCheck(jniEnv);\n            for(const auto& ce : c)\n            {\n                auto je = T::Boxed::fromCpp(jniEnv, ce);\n                jniEnv->CallBooleanMethod(j, data.method_add, get(je));\n                jniExceptionCheck(jniEnv);\n            }\n            return j;\n        }\n    };\n\n    struct IteratorJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/Iterator\") };\n        const jmethodID method_next { jniGetMethodID(clazz.get(), \"next\", \"()Ljava/lang/Object;\") };\n    };\n\n    struct SetJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/HashSet\") };\n        const jmethodID constructor { jniGetMethodID(clazz.get(), \"<init>\", \"()V\") };\n        const jmethodID method_add { jniGetMethodID(clazz.get(), \"add\", \"(Ljava/lang/Object;)Z\") };\n        const jmethodID method_size { jniGetMethodID(clazz.get(), \"size\", \"()I\") };\n        const jmethodID method_iterator { jniGetMethodID(clazz.get(), \"iterator\", \"()Ljava/util/Iterator;\") };\n    };\n\n    template <class T>\n    class Set\n    {\n        using ECppType = typename T::CppType;\n        using EJniType = typename T::Boxed::JniType;\n\n    public:\n        using CppType = std::unordered_set<ECppType>;\n        using JniType = jobject;\n\n        using Boxed = Set;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n            const auto& data = JniClass<SetJniInfo>::get();\n            const auto& iteData = JniClass<IteratorJniInfo>::get();\n            assert(jniEnv->IsInstanceOf(j, data.clazz.get()));\n            auto size = jniEnv->CallIntMethod(j, data.method_size);\n            jniExceptionCheck(jniEnv);\n            auto c = CppType();\n            auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_iterator));\n            jniExceptionCheck(jniEnv);\n            for(jint i = 0; i < size; ++i)\n            {\n                auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));\n                jniExceptionCheck(jniEnv);\n                c.insert(T::Boxed::toCpp(jniEnv, static_cast<EJniType>(je.get())));\n            }\n            return c;\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            const auto& data = JniClass<SetJniInfo>::get();\n            assert(c.size() <= std::numeric_limits<jint>::max());\n            auto size = static_cast<jint>(c.size());\n            auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));\n            jniExceptionCheck(jniEnv);\n            for(const auto& ce : c)\n            {\n                auto je = T::Boxed::fromCpp(jniEnv, ce);\n                jniEnv->CallBooleanMethod(j, data.method_add, get(je));\n                jniExceptionCheck(jniEnv);\n            }\n            return j;\n        }\n    };\n\n    struct MapJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/HashMap\") };\n        const jmethodID constructor { jniGetMethodID(clazz.get(), \"<init>\", \"()V\") };\n        const jmethodID method_put { jniGetMethodID(clazz.get(), \"put\", \"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;\") };\n        const jmethodID method_size { jniGetMethodID(clazz.get(), \"size\", \"()I\") };\n        const jmethodID method_entrySet { jniGetMethodID(clazz.get(), \"entrySet\", \"()Ljava/util/Set;\") };\n    };\n\n    struct EntrySetJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/Set\") };\n        const jmethodID method_iterator { jniGetMethodID(clazz.get(), \"iterator\", \"()Ljava/util/Iterator;\") };\n    };\n\n    struct EntryJniInfo\n    {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/Map$Entry\") };\n        const jmethodID method_getKey { jniGetMethodID(clazz.get(), \"getKey\", \"()Ljava/lang/Object;\") };\n        const jmethodID method_getValue { jniGetMethodID(clazz.get(), \"getValue\", \"()Ljava/lang/Object;\") };\n    };\n\n    template <class Key, class Value>\n    class Map\n    {\n        using CppKeyType = typename Key::CppType;\n        using CppValueType = typename Value::CppType;\n        using JniKeyType = typename Key::Boxed::JniType;\n        using JniValueType = typename Value::Boxed::JniType;\n\n    public:\n        using CppType = std::unordered_map<CppKeyType, CppValueType>;\n        using JniType = jobject;\n\n        using Boxed = Map;\n\n        static CppType toCpp(JNIEnv* jniEnv, JniType j)\n        {\n            assert(j != nullptr);\n            const auto& data = JniClass<MapJniInfo>::get();\n            const auto& entrySetData = JniClass<EntrySetJniInfo>::get();\n            const auto& entryData = JniClass<EntryJniInfo>::get();\n            const auto& iteData = JniClass<IteratorJniInfo>::get();\n            assert(jniEnv->IsInstanceOf(j, data.clazz.get()));\n            auto size = jniEnv->CallIntMethod(j, data.method_size);\n            jniExceptionCheck(jniEnv);\n            auto entrySet = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(j, data.method_entrySet));\n            jniExceptionCheck(jniEnv);\n            auto c = CppType();\n            c.reserve(size);\n            auto it = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(entrySet, entrySetData.method_iterator));\n            jniExceptionCheck(jniEnv);\n            for(jint i = 0; i < size; ++i)\n            {\n                auto je = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(it, iteData.method_next));\n                jniExceptionCheck(jniEnv);\n                auto jKey = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getKey));\n                jniExceptionCheck(jniEnv);\n                auto jValue = LocalRef<jobject>(jniEnv, jniEnv->CallObjectMethod(je, entryData.method_getValue));\n                jniExceptionCheck(jniEnv);\n                c.emplace(Key::Boxed::toCpp(jniEnv, static_cast<JniKeyType>(jKey.get())),\n                          Value::Boxed::toCpp(jniEnv, static_cast<JniValueType>(jValue.get())));\n            }\n            return c;\n        }\n\n        static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)\n        {\n            const auto& data = JniClass<MapJniInfo>::get();\n            assert(c.size() <= std::numeric_limits<jint>::max());\n            auto size = c.size();\n            auto j = LocalRef<jobject>(jniEnv, jniEnv->NewObject(data.clazz.get(), data.constructor, size));\n            jniExceptionCheck(jniEnv);\n            for(const auto& ce : c)\n            {\n                auto jKey = Key::Boxed::fromCpp(jniEnv, ce.first);\n                auto jValue = Value::Boxed::fromCpp(jniEnv, ce.second);\n                jniEnv->CallObjectMethod(j, data.method_put, get(jKey), get(jValue));\n                jniExceptionCheck(jniEnv);\n            }\n            return j;\n        }\n    };\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/jni/djinni_main.cpp",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// This provides a minimal JNI_OnLoad and JNI_OnUnload implementation - include it if your\n// app doesn't use JNI except through Djinni.\n\n#include \"djinni_support.hpp\"\n\n// Called when library is loaded by the first class which uses it.\nCJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * jvm, void * /*reserved*/) {\n    djinni::jniInit(jvm);\n    return JNI_VERSION_1_6;\n}\n\n// (Potentially) called when library is about to be unloaded.\nCJNIEXPORT void JNICALL JNI_OnUnload(JavaVM * /*jvm*/, void * /*reserved*/) {\n    djinni::jniShutdown();\n}\n"
  },
  {
    "path": "src/unity/djinni/support-lib/jni/djinni_support.cpp",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#include \"../djinni_common.hpp\"\n#include \"djinni_support.hpp\"\n#include \"../proxy_cache_impl.hpp\"\n#include <cassert>\n#include <cstdlib>\n#include <cstring>\n\nstatic_assert(sizeof(jlong) >= sizeof(void*), \"must be able to fit a void* into a jlong\");\n\nnamespace djinni {\n\n// Set only once from JNI_OnLoad before any other JNI calls, so no lock needed.\nstatic JavaVM * g_cachedJVM;\n\n/*static*/\nJniClassInitializer::registration_vec & JniClassInitializer::get_vec() {\n    static JniClassInitializer::registration_vec m;\n    return m;\n}\n\n/*static*/\nstd::mutex & JniClassInitializer::get_mutex() {\n    static std::mutex mtx;\n    return mtx;\n}\n\n/*static*/\nJniClassInitializer::registration_vec JniClassInitializer::get_all() {\n    const std::lock_guard<std::mutex> lock(get_mutex());\n    return get_vec();\n}\n\nJniClassInitializer::JniClassInitializer(std::function<void()> init) {\n    const std::lock_guard<std::mutex> lock(get_mutex());\n    get_vec().push_back(std::move(init));\n}\n\nvoid jniInit(JavaVM * jvm) {\n    g_cachedJVM = jvm;\n\n    try {\n        for (const auto & initializer : JniClassInitializer::get_all()) {\n            initializer();\n        }\n    } catch (const std::exception &) {\n        // Default exception handling only, since non-default might not be safe if init\n        // is incomplete.\n        jniDefaultSetPendingFromCurrent(jniGetThreadEnv(), __func__);\n    }\n}\n\nvoid jniShutdown() {\n    g_cachedJVM = nullptr;\n}\n\nJNIEnv * jniGetThreadEnv() {\n    assert(g_cachedJVM);\n    JNIEnv * env = nullptr;\n    jint get_res = g_cachedJVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);\n    #ifdef EXPERIMENTAL_AUTO_CPP_THREAD_ATTACH\n    if (get_res == JNI_EDETACHED) {\n        get_res = g_cachedJVM->AttachCurrentThread(&env, nullptr);\n        thread_local struct DetachOnExit {\n            ~DetachOnExit() {\n                g_cachedJVM->DetachCurrentThread();\n            }\n        } detachOnExit;\n    }\n    #endif\n    if (get_res != 0 || !env) {\n        // :(\n        std::abort();\n    }\n\n    return env;\n}\n\nstatic JNIEnv * getOptThreadEnv() {\n    if (!g_cachedJVM) {\n        return nullptr;\n    }\n\n    // Special case: this allows us to ignore GlobalRef deletions that happen after this\n    // thread has been detached. (This is known to happen during process shutdown, when\n    // there's no need to release the ref anyway.)\n    JNIEnv * env = nullptr;\n    const jint get_res = g_cachedJVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);\n\n    if (get_res == JNI_EDETACHED) {\n        return nullptr;\n    }\n\n    // Still bail on any other error.\n    if (get_res != 0 || !env) {\n        // :(\n        std::abort();\n    }\n\n    return env;\n}\n\nvoid GlobalRefDeleter::operator() (jobject globalRef) noexcept {\n    if (globalRef) {\n        if (JNIEnv * env = getOptThreadEnv()) {\n            env->DeleteGlobalRef(globalRef);\n        }\n    }\n}\n\nvoid LocalRefDeleter::operator() (jobject localRef) noexcept {\n    if (localRef) {\n        jniGetThreadEnv()->DeleteLocalRef(localRef);\n    }\n}\n\nvoid jni_exception::set_as_pending(JNIEnv * env) const noexcept {\n    assert(env);\n    env->Throw(java_exception());\n}\n\n\nvoid jniExceptionCheck(JNIEnv * env) {\n    if (!env) {\n        abort();\n    }\n    const LocalRef<jthrowable> e(env->ExceptionOccurred());\n    if (e) {\n        env->ExceptionClear();\n        jniThrowCppFromJavaException(env, e.get());\n    }\n}\n\nDJINNI_WEAK_DEFINITION\nDJINNI_NORETURN_DEFINITION\nvoid jniThrowCppFromJavaException(JNIEnv * env, jthrowable java_exception) {\n    throw jni_exception { env, java_exception };\n}\n\nnamespace { // anonymous namespace to guard the struct below\nstruct SystemClassInfo {\n    // This is a singleton class - an instance will be constructed by\n    // JniClassInitializer::init_all() at library init time.\n    const GlobalRef<jclass> clazz { jniFindClass(\"java/lang/System\") };\n    const jmethodID staticmethIdentityHashCode { jniGetStaticMethodID(clazz.get(),\n            \"identityHashCode\", \"(Ljava/lang/Object;)I\") };\n};\n} // namespace\n\n/*\n * Hasher and comparator based on Java object identity.\n */\nstruct JavaIdentityHash { size_t operator() (jobject obj) const; };\nstruct JavaIdentityEquals { bool operator() (jobject obj1, jobject obj2) const; };\n\nsize_t JavaIdentityHash::operator() (jobject obj) const {\n    JNIEnv * const env = jniGetThreadEnv();\n    const SystemClassInfo & sys = JniClass<SystemClassInfo>::get();\n    jint res = env->CallStaticIntMethod(sys.clazz.get(), sys.staticmethIdentityHashCode, obj);\n    jniExceptionCheck(env);\n    return res;\n}\nbool JavaIdentityEquals::operator() (jobject obj1, jobject obj2) const {\n    JNIEnv * const env = jniGetThreadEnv();\n    const bool res = env->IsSameObject(obj1, obj2);\n    jniExceptionCheck(env);\n    return res;\n}\n\nvoid jniThrowAssertionError(JNIEnv * env, const char * file, int line, const char * check) {\n    // basename() exists, but is bad (it's allowed to modify its input).\n    const char * slash = strrchr(file, '/');\n    const char * file_basename = slash ? slash + 1 : file;\n\n    char buf[256];\n    DJINNI_SNPRINTF(buf, sizeof buf, \"djinni (%s:%d): %s\", file_basename, line, check);\n\n    const jclass cassert = env->FindClass(\"java/lang/Error\");\n    assert(cassert);\n    env->ThrowNew(cassert, buf);\n    assert(env->ExceptionCheck());\n    const jthrowable e = env->ExceptionOccurred();\n    assert(e);\n    env->ExceptionClear();\n\n    env->DeleteLocalRef(cassert);\n\n    jniThrowCppFromJavaException(env, e);\n}\n\nGlobalRef<jclass> jniFindClass(const char * name) {\n    JNIEnv * env = jniGetThreadEnv();\n    DJINNI_ASSERT(name, env);\n    GlobalRef<jclass> guard(env, LocalRef<jclass>(env, env->FindClass(name)).get());\n    jniExceptionCheck(env);\n    if (!guard) {\n        jniThrowAssertionError(env, __FILE__, __LINE__, \"FindClass returned null\");\n    }\n    return guard;\n}\n\njmethodID jniGetStaticMethodID(jclass clazz, const char * name, const char * sig) {\n    JNIEnv * env = jniGetThreadEnv();\n    DJINNI_ASSERT(clazz, env);\n    DJINNI_ASSERT(name, env);\n    DJINNI_ASSERT(sig, env);\n    jmethodID id = env->GetStaticMethodID(clazz, name, sig);\n    jniExceptionCheck(env);\n    if (!id) {\n        jniThrowAssertionError(env, __FILE__, __LINE__, \"GetStaticMethodID returned null\");\n    }\n    return id;\n}\n\njmethodID jniGetMethodID(jclass clazz, const char * name, const char * sig) {\n    JNIEnv * env = jniGetThreadEnv();\n    DJINNI_ASSERT(clazz, env);\n    DJINNI_ASSERT(name, env);\n    DJINNI_ASSERT(sig, env);\n    jmethodID id = env->GetMethodID(clazz, name, sig);\n    jniExceptionCheck(env);\n    if (!id) {\n        jniThrowAssertionError(env, __FILE__, __LINE__, \"GetMethodID returned null\");\n    }\n    return id;\n}\n\njfieldID jniGetFieldID(jclass clazz, const char * name, const char * sig) {\n    JNIEnv * env = jniGetThreadEnv();\n    DJINNI_ASSERT(clazz, env);\n    DJINNI_ASSERT(name, env);\n    DJINNI_ASSERT(sig, env);\n    jfieldID id = env->GetFieldID(clazz, name, sig);\n    jniExceptionCheck(env);\n    if (!id) {\n        jniThrowAssertionError(env, __FILE__, __LINE__, \"GetFieldID returned null\");\n    }\n    return id;\n}\n\nJniEnum::JniEnum(const std::string & name)\n    : m_clazz { jniFindClass(name.c_str()) },\n      m_staticmethValues { jniGetStaticMethodID(m_clazz.get(), \"values\", (\"()[L\" + name + \";\").c_str()) },\n      m_methOrdinal { jniGetMethodID(m_clazz.get(), \"ordinal\", \"()I\") }\n    {}\n\njint JniEnum::ordinal(JNIEnv * env, jobject obj) const {\n    DJINNI_ASSERT(obj, env);\n    const jint res = env->CallIntMethod(obj, m_methOrdinal);\n    jniExceptionCheck(env);\n    return res;\n}\n\nLocalRef<jobject> JniEnum::create(JNIEnv * env, jint value) const {\n    LocalRef<jobject> values(env, env->CallStaticObjectMethod(m_clazz.get(), m_staticmethValues));\n    jniExceptionCheck(env);\n    DJINNI_ASSERT(values, env);\n    LocalRef<jobject> result(env,\n                             env->GetObjectArrayElement(static_cast<jobjectArray>(values.get()),\n                                                        value));\n    jniExceptionCheck(env);\n    return result;\n}\n\nJniFlags::JniFlags(const std::string & name)\n    : JniEnum { name }\n    {}\n\nunsigned JniFlags::flags(JNIEnv * env, jobject obj) const {\n    DJINNI_ASSERT(obj && env->IsInstanceOf(obj, m_clazz.get()), env);\n    const auto size = env->CallIntMethod(obj, m_methSize);\n    jniExceptionCheck(env);\n    unsigned flags = 0;\n    auto it = LocalRef<jobject>(env, env->CallObjectMethod(obj, m_methIterator));\n    jniExceptionCheck(env);\n    for(jint i = 0; i < size; ++i) {\n        auto jf = LocalRef<jobject>(env, env->CallObjectMethod(it, m_iterator.methNext));\n        jniExceptionCheck(env);\n        flags |= (1u << static_cast<unsigned>(ordinal(env, jf)));\n    }\n    return flags;\n}\n\nLocalRef<jobject> JniFlags::create(JNIEnv * env, unsigned flags, int bits) const {\n    auto j = LocalRef<jobject>(env, env->CallStaticObjectMethod(m_clazz.get(), m_methNoneOf, enumClass()));\n    jniExceptionCheck(env);\n    unsigned mask = 1;\n    for(int i = 0; i < bits; ++i, mask <<= 1) {\n        if((flags & mask) != 0) {\n            auto jf = create(env, static_cast<jint>(i));\n            jniExceptionCheck(env);\n            env->CallBooleanMethod(j, m_methAdd, jf.get());\n            jniExceptionCheck(env);\n        }\n    }\n    return j;\n}\n\nJniLocalScope::JniLocalScope(JNIEnv* p_env, jint capacity, bool throwOnError)\n    : m_env(p_env)\n    , m_success(_pushLocalFrame(m_env, capacity)) {\n    if (throwOnError) {\n        DJINNI_ASSERT(m_success, m_env);\n    }\n}\nJniLocalScope::~JniLocalScope() {\n    if (m_success) {\n        _popLocalFrame(m_env, nullptr);\n    }\n}\n\nbool JniLocalScope::_pushLocalFrame(JNIEnv* const env, jint capacity) {\n    DJINNI_ASSERT(capacity >= 0, env);\n    const jint push_res = env->PushLocalFrame(capacity);\n    return 0 == push_res;\n}\n\nvoid JniLocalScope::_popLocalFrame(JNIEnv* const env, jobject returnRef) {\n    env->PopLocalFrame(returnRef);\n}\n\n/*\n * UTF-8 and UTF-16 conversion functions from miniutf: https://github.com/dropbox/miniutf\n */\n\nstruct offset_pt {\n    int offset;\n    char32_t pt;\n};\n\nstatic constexpr const offset_pt invalid_pt = { -1, 0 };\n\n/*\n * Decode a codepoint starting at str[i], and return the number of code units (bytes, for\n * UTF-8) consumed and the result. If no valid codepoint is at str[i], return invalid_pt.\n */\nstatic offset_pt utf8_decode_check(const std::string & str, std::string::size_type i) {\n    uint32_t b0, b1, b2, b3;\n\n    b0 = static_cast<unsigned char>(str[i]);\n\n    if (b0 < 0x80) {\n        // 1-byte character\n        return { 1, b0 };\n    } else if (b0 < 0xC0) {\n        // Unexpected continuation byte\n        return invalid_pt;\n    } else if (b0 < 0xE0) {\n        // 2-byte character\n        if (((b1 = str[i+1]) & 0xC0) != 0x80)\n            return invalid_pt;\n\n        char32_t pt = (b0 & 0x1F) << 6 | (b1 & 0x3F);\n        if (pt < 0x80)\n            return invalid_pt;\n\n        return { 2, pt };\n    } else if (b0 < 0xF0) {\n        // 3-byte character\n        if (((b1 = str[i+1]) & 0xC0) != 0x80)\n            return invalid_pt;\n        if (((b2 = str[i+2]) & 0xC0) != 0x80)\n            return invalid_pt;\n\n        char32_t pt = (b0 & 0x0F) << 12 | (b1 & 0x3F) << 6 | (b2 & 0x3F);\n        if (pt < 0x800)\n            return invalid_pt;\n\n        return { 3, pt };\n    } else if (b0 < 0xF8) {\n        // 4-byte character\n        if (((b1 = str[i+1]) & 0xC0) != 0x80)\n            return invalid_pt;\n        if (((b2 = str[i+2]) & 0xC0) != 0x80)\n            return invalid_pt;\n        if (((b3 = str[i+3]) & 0xC0) != 0x80)\n            return invalid_pt;\n\n        char32_t pt = (b0 & 0x0F) << 18 | (b1 & 0x3F) << 12\n                    | (b2 & 0x3F) << 6  | (b3 & 0x3F);\n        if (pt < 0x10000 || pt >= 0x110000)\n            return invalid_pt;\n\n        return { 4, pt };\n    } else {\n        // Codepoint out of range\n        return invalid_pt;\n    }\n}\n\nstatic char32_t utf8_decode(const std::string & str, std::string::size_type & i) {\n    offset_pt res = utf8_decode_check(str, i);\n    if (res.offset < 0) {\n        i += 1;\n        return 0xFFFD;\n    } else {\n        i += res.offset;\n        return res.pt;\n    }\n}\n\nstatic void utf16_encode(char32_t pt, std::u16string & out) {\n    if (pt < 0x10000) {\n        out += static_cast<char16_t>(pt);\n    } else if (pt < 0x110000) {\n        out += { static_cast<char16_t>(((pt - 0x10000) >> 10) + 0xD800),\n                 static_cast<char16_t>((pt & 0x3FF) + 0xDC00) };\n    } else {\n        out += 0xFFFD;\n    }\n}\n\njstring jniStringFromUTF8(JNIEnv * env, const std::string & str) {\n\n    std::u16string utf16;\n    utf16.reserve(str.length()); // likely overallocate\n    for (std::string::size_type i = 0; i < str.length(); )\n        utf16_encode(utf8_decode(str, i), utf16);\n\n    jstring res = env->NewString(\n        reinterpret_cast<const jchar *>(utf16.data()), jsize(utf16.length()));\n    DJINNI_ASSERT(res, env);\n    return res;\n}\n\ntemplate<int wcharTypeSize>\nstatic std::u16string implWStringToUTF16(std::wstring::const_iterator, std::wstring::const_iterator)\n{\n    static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, \"wchar_t must be represented by UTF-16 or UTF-32 encoding\");\n    return {}; // unreachable\n}\n\ntemplate<>\ninline std::u16string implWStringToUTF16<2>(std::wstring::const_iterator begin, std::wstring::const_iterator end) {\n    // case when wchar_t is represented by utf-16 encoding\n    return std::u16string(begin, end);\n}\n\ntemplate<>\ninline std::u16string implWStringToUTF16<4>(std::wstring::const_iterator begin, std::wstring::const_iterator end) {\n    // case when wchar_t is represented by utf-32 encoding\n    std::u16string utf16;\n    utf16.reserve(std::distance(begin, end));\n    for(; begin != end; ++begin)\n        utf16_encode(static_cast<char32_t>(*begin), utf16);\n    return utf16;\n}\n\ninline std::u16string wstringToUTF16(const std::wstring & str) {\n    // hide \"defined but not used\" warnings\n    (void)implWStringToUTF16<2>;\n    (void)implWStringToUTF16<4>;\n    // Note: The template helper operates on iterators to work around a compiler issue we saw on Mac.\n    // It triggered undefined symbols if wstring methods were called directly in the template function.\n    return implWStringToUTF16<sizeof(wchar_t)>(str.cbegin(), str.cend());\n}\n\njstring jniStringFromWString(JNIEnv * env, const std::wstring & str) {\n    std::u16string utf16 = wstringToUTF16(str);\n    jstring res = env->NewString(\n        reinterpret_cast<const jchar *>(utf16.data()), utf16.length());\n    DJINNI_ASSERT(res, env);\n    return res;\n}\n\n// UTF-16 decode helpers.\nstatic inline bool is_high_surrogate(char16_t c) { return (c >= 0xD800) && (c < 0xDC00); }\nstatic inline bool is_low_surrogate(char16_t c)  { return (c >= 0xDC00) && (c < 0xE000); }\n\n/*\n * Like utf8_decode_check, but for UTF-16.\n */\nstatic offset_pt utf16_decode_check(const char16_t * str, std::u16string::size_type i) {\n    if (is_high_surrogate(str[i]) && is_low_surrogate(str[i+1])) {\n        // High surrogate followed by low surrogate\n        char32_t pt = (((str[i] - 0xD800) << 10) | (str[i+1] - 0xDC00)) + 0x10000;\n        return { 2, pt };\n    } else if (is_high_surrogate(str[i]) || is_low_surrogate(str[i])) {\n        // High surrogate *not* followed by low surrogate, or unpaired low surrogate\n        return invalid_pt;\n    } else {\n        return { 1, str[i] };\n    }\n}\n\nstatic char32_t utf16_decode(const char16_t * str, std::u16string::size_type & i) {\n    offset_pt res = utf16_decode_check(str, i);\n    if (res.offset < 0) {\n        i += 1;\n        return 0xFFFD;\n    } else {\n        i += res.offset;\n        return res.pt;\n    }\n}\n\nstatic void utf8_encode(char32_t pt, std::string & out) {\n    if (pt < 0x80) {\n        out += static_cast<char>(pt);\n    } else if (pt < 0x800) {\n        out += { static_cast<char>((pt >> 6)   | 0xC0),\n                 static_cast<char>((pt & 0x3F) | 0x80) };\n    } else if (pt < 0x10000) {\n        out += { static_cast<char>((pt >> 12)         | 0xE0),\n                 static_cast<char>(((pt >> 6) & 0x3F) | 0x80),\n                 static_cast<char>((pt & 0x3F)        | 0x80) };\n    } else if (pt < 0x110000) {\n        out += { static_cast<char>((pt >> 18)          | 0xF0),\n                 static_cast<char>(((pt >> 12) & 0x3F) | 0x80),\n                 static_cast<char>(((pt >> 6)  & 0x3F) | 0x80),\n                 static_cast<char>((pt & 0x3F)         | 0x80) };\n    } else {\n        out += { static_cast<char>(0xEF),\n                 static_cast<char>(0xBF),\n                 static_cast<char>(0xBD) }; // U+FFFD\n    }\n}\n\nstd::string jniUTF8FromString(JNIEnv * env, const jstring jstr) {\n    DJINNI_ASSERT(jstr, env);\n    const jsize length = env->GetStringLength(jstr);\n    jniExceptionCheck(env);\n\n    const auto deleter = [env, jstr] (const jchar * c) { env->ReleaseStringChars(jstr, c); };\n    std::unique_ptr<const jchar, decltype(deleter)> ptr(env->GetStringChars(jstr, nullptr),\n                                                        deleter);\n\n    std::u16string str(reinterpret_cast<const char16_t *>(ptr.get()), length);\n    std::string out;\n    out.reserve(str.length() * 3 / 2); // estimate\n    for (std::u16string::size_type i = 0; i < str.length(); )\n        utf8_encode(utf16_decode(str.data(), i), out);\n    return out;\n}\n\ntemplate<int wcharTypeSize>\nstatic std::wstring implUTF16ToWString(const char16_t * /*data*/, size_t /*length*/)\n{\n    static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, \"wchar_t must be represented by UTF-16 or UTF-32 encoding\");\n    return {}; // unreachable\n}\n\ntemplate<>\ninline std::wstring implUTF16ToWString<2>(const char16_t * data, size_t length) {\n    // case when wchar_t is represented by utf-16 encoding\n    return std::wstring(data, data + length);\n}\n\ntemplate<>\ninline std::wstring implUTF16ToWString<4>(const char16_t * data, size_t length) {\n    // case when wchar_t is represented by utf-32 encoding\n    std::wstring result;\n    result.reserve(length);\n    for (size_t i = 0; i < length; )\n        result += static_cast<wchar_t>(utf16_decode(data, i));\n    return result;\n}\n\ninline std::wstring UTF16ToWString(const char16_t * data, size_t length) {\n    // hide \"defined but not used\" warnings\n    (void)implUTF16ToWString<2>;\n    (void)implUTF16ToWString<4>;\n    return implUTF16ToWString<sizeof(wchar_t)>(data, length);\n}\n\nstd::wstring jniWStringFromString(JNIEnv * env, const jstring jstr) {\n    DJINNI_ASSERT(jstr, env);\n    const jsize length = env->GetStringLength(jstr);\n    jniExceptionCheck(env);\n\n    const auto deleter = [env, jstr] (const jchar * c) { env->ReleaseStringChars(jstr, c); };\n    std::unique_ptr<const jchar, decltype(deleter)> ptr(env->GetStringChars(jstr, nullptr),\n                                                        deleter);\n    const char16_t * data = reinterpret_cast<const char16_t *>(ptr.get());\n    return UTF16ToWString(data, length);\n}\n\nDJINNI_WEAK_DEFINITION\nvoid jniSetPendingFromCurrent(JNIEnv * env, const char * ctx) noexcept {\n    jniDefaultSetPendingFromCurrent(env, ctx);\n}\n\nvoid jniDefaultSetPendingFromCurrentImpl(JNIEnv * env) {\n    assert(env);\n    try {\n        throw;\n    } catch (const jni_exception & e) {\n        e.set_as_pending(env);\n        return;\n    } catch (const std::exception & e) {\n        env->ThrowNew(env->FindClass(\"java/lang/RuntimeException\"), e.what());\n    }\n}\n\nvoid jniDefaultSetPendingFromCurrent(JNIEnv * env, const char * /*ctx*/) noexcept {\n \n    /* It is necessary to go through a layer of indirection here because this\n    function is marked noexcept, but the implementation may still throw. \n    Any exceptions which are not caught (i.e. exceptions which aren't \n    std::exception subclasses) will result in a call to terminate() since this\n    function is marked noexcept */\n\t\n\tjniDefaultSetPendingFromCurrentImpl(env);\n}\n\ntemplate class ProxyCache<JavaProxyCacheTraits>;\n\nCppProxyClassInfo::CppProxyClassInfo(const char * className)\n    : clazz(jniFindClass(className)),\n      constructor(jniGetMethodID(clazz.get(), \"<init>\", \"(J)V\")),\n      idField(jniGetFieldID(clazz.get(), \"nativeRef\", \"J\")) {\n}\n\nCppProxyClassInfo::CppProxyClassInfo() : constructor{}, idField{} {\n}\n\nCppProxyClassInfo::~CppProxyClassInfo() {\n}\n\n/*\n * Wrapper around Java WeakReference objects. (We can't use JNI NewWeakGlobalRef() because\n * it doesn't have the right semantics - see comment in djinni_support.hpp.)\n */\nclass JavaWeakRef {\nprivate:\n    struct JniInfo {\n    public:\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/lang/ref/WeakReference\") };\n        const jmethodID constructor { jniGetMethodID(clazz.get(), \"<init>\", \"(Ljava/lang/Object;)V\") };\n        const jmethodID method_get { jniGetMethodID(clazz.get(), \"get\", \"()Ljava/lang/Object;\") };\n    };\n\n    // Helper used by constructor\n    static GlobalRef<jobject> create(JNIEnv * jniEnv, jobject obj) {\n        const JniInfo & weakRefClass = JniClass<JniInfo>::get();\n        LocalRef<jobject> weakRef(jniEnv, jniEnv->NewObject(weakRefClass.clazz.get(), weakRefClass.constructor, obj));\n        // DJINNI_ASSERT performs an exception check before anything else, so we don't need\n        // a separate jniExceptionCheck call.\n        DJINNI_ASSERT(weakRef, jniEnv);\n        return GlobalRef<jobject>(jniEnv, weakRef);\n    }\n\npublic:\n    // Constructor\n    JavaWeakRef(jobject obj) : JavaWeakRef(jniGetThreadEnv(), obj) {}\n    JavaWeakRef(JNIEnv * jniEnv, jobject obj) : m_weakRef(create(jniEnv, obj)) {}\n\n    // Get the object pointed to if it's still strongly reachable or, return null if not.\n    // (Analogous to weak_ptr::lock.) Returns a local reference.\n    jobject lock() const {\n        const auto & jniEnv = jniGetThreadEnv();\n        const JniInfo & weakRefClass = JniClass<JniInfo>::get();\n        LocalRef<jobject> javaObj(jniEnv->CallObjectMethod(m_weakRef.get(), weakRefClass.method_get));\n        jniExceptionCheck(jniEnv);\n        return javaObj.release();\n    }\n\n    // Java WeakReference objects don't have a way to check whether they're expired except\n    // by upgrading them to a strong ref.\n    bool expired() const {\n        LocalRef<jobject> javaObj { lock() };\n        return !javaObj;\n    }\n\nprivate:\n    GlobalRef<jobject> m_weakRef;\n};\n\ntemplate class ProxyCache<JniCppProxyCacheTraits>;\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/jni/djinni_support.hpp",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#include <cassert>\n#include <exception>\n#include <memory>\n#include <mutex>\n#include <string>\n#include <vector>\n\n#include \"../proxy_cache_interface.hpp\"\n#include \"../djinni_common.hpp\"\n#include <jni.h>\n\n/*\n * Djinni support library\n */\n\n// jni.h should really put extern \"C\" in JNIEXPORT, but it doesn't. :(\n#define CJNIEXPORT extern \"C\" JNIEXPORT\n\nnamespace djinni {\n\n/*\n * Global initialization and shutdown. Call these from JNI_OnLoad and JNI_OnUnload.\n */\nvoid jniInit(JavaVM * jvm);\nvoid jniShutdown();\n\n/*\n * Get the JNIEnv for the invoking thread. Should only be called on Java-created threads.\n */\nJNIEnv * jniGetThreadEnv();\n\n/*\n * Global and local reference guard objects.\n *\n * A GlobalRef<T> is constructed with a local reference; the constructor upgrades the local\n * reference to a global reference, and the destructor deletes the local ref.\n *\n * A LocalRef<T> should be constructed with a new local reference. The local reference will\n * be deleted when the LocalRef is deleted.\n */\nstruct GlobalRefDeleter { void operator() (jobject globalRef) noexcept; };\n\ntemplate <typename PointerType>\nclass GlobalRef : public std::unique_ptr<typename std::remove_pointer<PointerType>::type,\n                                         GlobalRefDeleter> {\npublic:\n    GlobalRef() {}\n    GlobalRef(GlobalRef && obj)\n        : std::unique_ptr<typename std::remove_pointer<PointerType>::type, ::djinni::GlobalRefDeleter>(\n            std::move(obj)\n        ) {}\n    GlobalRef(JNIEnv * env, PointerType localRef)\n        : std::unique_ptr<typename std::remove_pointer<PointerType>::type, ::djinni::GlobalRefDeleter>(\n            static_cast<PointerType>(env->NewGlobalRef(localRef)),\n            ::djinni::GlobalRefDeleter{}\n        ) {}\n};\n\nstruct LocalRefDeleter { void operator() (jobject localRef) noexcept; };\n\ntemplate <typename PointerType>\nclass LocalRef : public std::unique_ptr<typename std::remove_pointer<PointerType>::type,\n                                        LocalRefDeleter> {\npublic:\n    LocalRef() {}\n    LocalRef(JNIEnv * /*env*/, PointerType localRef)\n        : std::unique_ptr<typename std::remove_pointer<PointerType>::type, ::djinni::LocalRefDeleter>(\n            localRef) {}\n    explicit LocalRef(PointerType localRef)\n        : std::unique_ptr<typename std::remove_pointer<PointerType>::type, LocalRefDeleter>(\n            localRef) {}\n    // Allow implicit conversion to PointerType so it can be passed\n    // as argument to JNI functions expecting PointerType.\n    // All functions creating new local references should return LocalRef instead of PointerType\n    operator PointerType() const & { return this->get(); }\n    operator PointerType() && = delete;\n};\n\ntemplate<class T>\nconst T& get(const T& x) noexcept { return x; }\ntemplate<class T>\ntypename LocalRef<T>::pointer get(const LocalRef<T>& x) noexcept { return x.get(); }\n\ntemplate<class T>\nconst T& release(const T& x) noexcept { return x; }\ntemplate<class T>\ntypename LocalRef<T>::pointer release(LocalRef<T>& x) noexcept { return x.release(); }\ntemplate<class T>\ntypename LocalRef<T>::pointer release(LocalRef<T>&& x) noexcept { return x.release(); }\n\n/*\n * Exception to indicate that a Java exception is pending in the JVM.\n */\nclass jni_exception : public std::exception {\n    GlobalRef<jthrowable> m_java_exception;\npublic:\n    jni_exception(JNIEnv * env, jthrowable java_exception)\n        : m_java_exception(env, java_exception) {\n        assert(java_exception);\n    }\n    jthrowable java_exception() const { return m_java_exception.get(); }\n\n    /*\n     * Sets the pending JNI exception using this Java exception.\n     */\n    void set_as_pending(JNIEnv * env) const noexcept;\n};\n\n/*\n * Throw if any Java exception is pending in the JVM.\n *\n * If an exception is pending, this function will clear the\n * pending state, and pass the exception to\n * jniThrowCppFromJavaException().\n */\nvoid jniExceptionCheck(JNIEnv * env);\n\n/*\n * Throws a C++ exception based on the given Java exception.\n *\n * java_exception is a local reference to a Java throwable, which\n * must not be null, and should no longer set as \"pending\" in the JVM.\n * This is called to handle errors in other JNI processing, including\n * by jniExceptionCheck().\n *\n * The default implementation is defined with __attribute__((weak)) so you\n * can replace it by defining your own version.  The default implementation\n * will throw a jni_exception containing the given jthrowable.\n */\nDJINNI_NORETURN_DEFINITION\nvoid jniThrowCppFromJavaException(JNIEnv * env, jthrowable java_exception);\n\n/*\n * Set an AssertionError in env with message message, and then throw via jniExceptionCheck.\n */\nDJINNI_NORETURN_DEFINITION\nvoid jniThrowAssertionError(JNIEnv * env, const char * file, int line, const char * check);\n\n#define DJINNI_ASSERT_MSG(check, env, message) \\\n    do { \\\n        ::djinni::jniExceptionCheck(env); \\\n        const bool check__res = bool(check); \\\n        ::djinni::jniExceptionCheck(env); \\\n        if (!check__res) { \\\n            ::djinni::jniThrowAssertionError(env, __FILE__, __LINE__, message); \\\n        } \\\n    } while(false)\n#define DJINNI_ASSERT(check, env) DJINNI_ASSERT_MSG(check, env, #check)\n\n/*\n * Helper for JniClass. (This can't be a subclass because it needs to not be templatized.)\n */\nclass JniClassInitializer {\n\n    using registration_vec = std::vector<std::function<void()>>;\n    static registration_vec get_all();\n\nprivate:\n\n    JniClassInitializer(std::function<void()> init);\n\n    template <class C> friend class JniClass;\n    friend void jniInit(JavaVM *);\n\n    static registration_vec & get_vec();\n    static std::mutex       & get_mutex();\n};\n\n/*\n * Each instantiation of this template produces a singleton object of type C which\n * will be initialized by djinni::jniInit(). For example:\n *\n * struct JavaFooInfo {\n *     jmethodID foo;\n *     JavaFooInfo() // initialize clazz and foo from jniGetThreadEnv\n * }\n *\n * To use this in a JNI function or callback, invoke:\n *\n *     CallVoidMethod(object, JniClass<JavaFooInfo>::get().foo, ...);\n *\n * This uses C++'s template instantiation behavior to guarantee that any T for which\n * JniClass<T>::get() is *used* anywhere in the program will be *initialized* by init_all().\n * Therefore, it's always safe to compile in wrappers for all known Java types - the library\n * will only depend on the presence of those actually needed.\n */\ntemplate <class C>\nclass JniClass {\npublic:\n    static const C & get() {\n        (void)s_initializer; // ensure that initializer is actually instantiated\n        assert(s_singleton);\n        return *s_singleton;\n    }\n\nprivate:\n    static const JniClassInitializer s_initializer;\n    static std::unique_ptr<C> s_singleton;\n\n    static void allocate() {\n        // We can't use make_unique here, because C will have a private constructor and\n        // list JniClass as a friend; so we have to allocate it by hand.\n        s_singleton = std::unique_ptr<C>(new C());\n    }\n};\n\ntemplate <class C>\nconst JniClassInitializer JniClass<C>::s_initializer ( allocate );\n\ntemplate <class C>\nstd::unique_ptr<C> JniClass<C>::s_singleton;\n\n/*\n * Exception-checking helpers. These will throw if an exception is pending.\n */\nGlobalRef<jclass> jniFindClass(const char * name);\njmethodID jniGetStaticMethodID(jclass clazz, const char * name, const char * sig);\njmethodID jniGetMethodID(jclass clazz, const char * name, const char * sig);\njfieldID jniGetFieldID(jclass clazz, const char * name, const char * sig);\n\n/*\n * Helper for maintaining shared_ptrs to wrapped Java objects.\n *\n * This is used for automatically wrapping a Java object that exposes some interface\n * with a C++ object that calls back into the JVM, such as a listener. Calling\n * get_java_proxy<T>(obj) the first time will construct a T and return a shared_ptr to it, and\n * also save a weak_ptr to the new object internally. The constructed T contains a strong\n * GlobalRef to jobj. As long as something in C++ maintains a strong reference to the wrapper,\n * future calls to get(jobj) will return the *same* wrapper object.\n *\n *        Java            |           C++\n *                        |        ________________________                ___________\n *   _____________        |       |                        |              |           |\n *  |             |       |       |   JniImplFooListener   | <=========== |    Foo    |\n *  | FooListener | <============ |  : public FooListener, |  shared_ptr  |___________|\n *  |_____________|   GlobalRef   |    JavaProxyCacheEntry |\n *                        |       |________________________|\n *                        |                 ^             ______________________\n *                        |                 \\            |                      |\n *                        |                  - - - - - - |    JavaProxyCache    |\n *                        |                   weak_ptr   |______________________|\n *\n * As long as the C++ FooListener has references, the Java FooListener is kept alive.\n *\n * We use a custom unordered_map with Java objects (jobject) as keys, and JNI object\n * identity and hashing functions. This means that as long as a key is in the map,\n * we must have some other GlobalRef keeping it alive. To ensure safety, the Entry\n * destructor removes *itself* from the map - destruction order guarantees that this\n * will happen before the contained global reference becomes invalid (by destruction of\n * the GlobalRef).\n */\nstruct JavaIdentityHash;\nstruct JavaIdentityEquals;\nstruct JavaProxyCacheTraits {\n    using UnowningImplPointer = jobject;\n    using OwningImplPointer = jobject;\n    using OwningProxyPointer = std::shared_ptr<void>;\n    using WeakProxyPointer = std::weak_ptr<void>;\n    using UnowningImplPointerHash = JavaIdentityHash;\n    using UnowningImplPointerEqual = JavaIdentityEquals;\n};\nextern template class ProxyCache<JavaProxyCacheTraits>;\nusing JavaProxyCache = ProxyCache<JavaProxyCacheTraits>;\ntemplate <typename T> using JavaProxyHandle = JavaProxyCache::Handle<GlobalRef<jobject>, T>;\n\n/*\n * Cache for CppProxy objects. This is the inverse of the JavaProxyCache mechanism above,\n * ensuring that each time we pass an interface from Java to C++, we get the *same* CppProxy\n * object on the Java side:\n *\n *      Java               |            C++\n *                         |\n *    ______________       |         ________________                  ___________\n *   |              |      |        |                |                |           |\n *   | Foo.CppProxy | ------------> | CppProxyHandle | =============> |    Foo    |\n *   |______________|   (jlong)     |      <Foo>     |  (shared_ptr)  |___________|\n *           ^             |        |________________|\n *            \\            |\n *        _________        |                     __________________\n *       |         |       |                    |                  |\n *       | WeakRef | <------------------------- | jniCppProxyCache |\n *       |_________|  (GlobalRef)               |__________________|\n *                         |\n *\n * We don't use JNI WeakGlobalRef objects, because they last longer than is safe - a\n * WeakGlobalRef can still be upgraded to a strong reference even during finalization, which\n * leads to use-after-free. Java WeakRefs provide the right lifetime guarantee.\n */\nclass JavaWeakRef;\nstruct JniCppProxyCacheTraits {\n    using UnowningImplPointer = void *;\n    using OwningImplPointer = std::shared_ptr<void>;\n    using OwningProxyPointer = jobject;\n    using WeakProxyPointer = JavaWeakRef;\n    using UnowningImplPointerHash = std::hash<void *>;\n    using UnowningImplPointerEqual = std::equal_to<void *>;\n};\nextern template class ProxyCache<JniCppProxyCacheTraits>;\nusing JniCppProxyCache = ProxyCache<JniCppProxyCacheTraits>;\ntemplate <class T> using CppProxyHandle = JniCppProxyCache::Handle<std::shared_ptr<T>>;\n\ntemplate <class T>\nstatic const std::shared_ptr<T> & objectFromHandleAddress(jlong handle) {\n    assert(handle);\n    assert(handle > 4096);\n    // Below line segfaults gcc-4.8. Using a temporary variable hides the bug.\n    //const auto & ret = reinterpret_cast<const CppProxyHandle<T> *>(handle)->get();\n    const CppProxyHandle<T> *proxy_handle =\n        reinterpret_cast<const CppProxyHandle<T> *>(handle);\n    const auto & ret = proxy_handle->get();\n    assert(ret);\n    return ret;\n}\n\n/*\n * Information needed to use a CppProxy class.\n *\n * In an ideal world, this object would be properly always-valid RAII, and we'd use an\n * optional<CppProxyClassInfo> where needed. Unfortunately we don't want to depend on optional\n * here, so this object has an invalid state and default constructor.\n */\nstruct CppProxyClassInfo {\n    const GlobalRef<jclass> clazz;\n    const jmethodID constructor;\n    const jfieldID idField;\n\n    CppProxyClassInfo(const char * className);\n    CppProxyClassInfo();\n    ~CppProxyClassInfo();\n\n    // Validity check\n    explicit operator bool() const { return bool(clazz); }\n};\n\n/*\n * Base class for Java <-> C++ interface adapters.\n *\n * I is the C++ base class (interface) being adapted; Self is the interface adapter class\n * derived from JniInterface (using CRTP). For example:\n *\n *     class NativeToken final : djinni::JniInterface<Token, NativeToken> { ... }\n */\ntemplate <class I, class Self>\nclass JniInterface {\npublic:\n    /*\n     * Given a C++ object, find or create a Java version. The cases here are:\n     * 1. Null\n     * 2. The provided C++ object is actually a JavaProxy (C++-side proxy for Java impl)\n     * 3. The provided C++ object has an existing CppProxy (Java-side proxy for C++ impl)\n     * 4. The provided C++ object needs a new CppProxy allocated\n     */\n    jobject _toJava(JNIEnv* jniEnv, const std::shared_ptr<I> & c) const {\n        // Case 1 - null\n        if (!c) {\n            return nullptr;\n        }\n\n        // Case 2 - already a JavaProxy. Only possible if Self::JavaProxy exists.\n        if (jobject impl = _unwrapJavaProxy<Self>(&c)) {\n            return jniEnv->NewLocalRef(impl);\n        }\n\n        // Cases 3 and 4.\n        assert(m_cppProxyClass);\n        return JniCppProxyCache::get(typeid(c), c, &newCppProxy);\n\n    }\n\n    /*\n     * Given a Java object, find or create a C++ version. The cases here are:\n     * 1. Null\n     * 2. The provided Java object is actually a CppProxy (Java-side proxy for a C++ impl)\n     * 3. The provided Java object has an existing JavaProxy (C++-side proxy for a Java impl)\n     * 4. The provided Java object needs a new JavaProxy allocated\n     */\n    std::shared_ptr<I> _fromJava(JNIEnv* jniEnv, jobject j) const {\n        // Case 1 - null\n        if (!j) {\n            return nullptr;\n        }\n\n        // Case 2 - already a Java proxy; we just need to pull the C++ impl out. (This case\n        // is only possible if we were constructed with a cppProxyClassName parameter.)\n        if (m_cppProxyClass\n                && jniEnv->IsSameObject(jniEnv->GetObjectClass(j), m_cppProxyClass.clazz.get())) {\n            jlong handle = jniEnv->GetLongField(j, m_cppProxyClass.idField);\n            jniExceptionCheck(jniEnv);\n            return objectFromHandleAddress<I>(handle);\n        }\n\n        // Cases 3 and 4 - see _getJavaProxy helper below. JavaProxyCache is responsible for\n        // distinguishing between the two cases. Only possible if Self::JavaProxy exists.\n        return _getJavaProxy<Self>(j);\n    }\n\n    // Constructor for interfaces for which a Java-side CppProxy class exists\n    JniInterface(const char * cppProxyClassName) : m_cppProxyClass(cppProxyClassName) {}\n\n    // Constructor for interfaces without a Java proxy class\n    JniInterface() : m_cppProxyClass{} {}\n\nprivate:\n    /*\n     * Helpers for _toJava above. The possibility that an object is already a C++-side proxy\n     * only exists if the code generator emitted one (if Self::JavaProxy exists).\n     */\n    template <typename S, typename JavaProxy = typename S::JavaProxy>\n    jobject _unwrapJavaProxy(const std::shared_ptr<I> * c) const {\n        if (auto proxy = dynamic_cast<JavaProxy *>(c->get())) {\n            return proxy->JavaProxyHandle<JavaProxy>::get().get();\n        } else {\n            return nullptr;\n        }\n    }\n\n    template <typename S>\n    jobject _unwrapJavaProxy(...) const {\n        return nullptr;\n    }\n\n    /*\n     * Helper for _toJava above: given a C++ object, allocate a CppProxy on the Java side for\n     * it. This is actually called by jniCppProxyCacheGet, which holds a lock on the global\n     * C++-to-Java proxy map object.\n     */\n    static std::pair<jobject, void*> newCppProxy(const std::shared_ptr<void> & cppObj) {\n        const auto & data = JniClass<Self>::get();\n        const auto & jniEnv = jniGetThreadEnv();\n        std::unique_ptr<CppProxyHandle<I>> to_encapsulate(\n                new CppProxyHandle<I>(std::static_pointer_cast<I>(cppObj)));\n        jlong handle = static_cast<jlong>(reinterpret_cast<uintptr_t>(to_encapsulate.get()));\n        jobject cppProxy = jniEnv->NewObject(data.m_cppProxyClass.clazz.get(),\n                                             data.m_cppProxyClass.constructor,\n                                             handle);\n        jniExceptionCheck(jniEnv);\n        to_encapsulate.release();\n        return { cppProxy, cppObj.get() };\n    }\n\n    /*\n     * Helpers for _fromJava above. We can only produce a C++-side proxy if the code generator\n     * emitted one (if Self::JavaProxy exists).\n     */\n    template <typename S, typename JavaProxy = typename S::JavaProxy>\n    std::shared_ptr<I> _getJavaProxy(jobject j) const {\n        static_assert(std::is_base_of<JavaProxyHandle<JavaProxy>, JavaProxy>::value,\n            \"JavaProxy must derive from JavaProxyCacheEntry\");\n\n        return std::static_pointer_cast<JavaProxy>(JavaProxyCache::get(\n            typeid(JavaProxy), j,\n            [] (const jobject & obj) -> std::pair<std::shared_ptr<void>, jobject> {\n                auto ret = std::make_shared<JavaProxy>(obj);\n                return { ret, ret->JavaProxyHandle<JavaProxy>::get().get() };\n            }\n        ));\n    }\n\n    template <typename S>\n    std::shared_ptr<I> _getJavaProxy(...) const {\n        assert(false);\n        return nullptr;\n    }\n\n    const CppProxyClassInfo m_cppProxyClass;\n};\n\n/*\n * Guard object which automatically begins and ends a JNI local frame when\n * it is created and destroyed, using PushLocalFrame and PopLocalFrame.\n *\n * Local frame creation can fail. The throwOnError parameter specifies how\n * errors are reported:\n * - true (default): throws on failure\n * - false: queues a JNI exception on failure; the user must call checkSuccess()\n *\n * The JNIEnv given at construction is expected to still be valid at\n * destruction, so this class isn't suitable for use across threads.\n * It is intended for use on the stack.\n *\n * All JNI local references created within the defined scope will be\n * released at the end of the scope.  This class doesn't support\n * the jobject return value supported by PopLocalFrame(), because\n * the destructor cannot return the new reference value for the parent\n * frame.\n */\nclass JniLocalScope {\npublic:\n    /*\n     * Create the guard object and begin the local frame.\n     *\n     * @param p_env the JNIEnv for the current thread.\n     * @param capacity the initial number of local references to\n     *  allocate.\n     */\n    JniLocalScope(JNIEnv* p_env, jint capacity, bool throwOnError = true);\n    bool checkSuccess() const { return m_success; }\n    ~JniLocalScope();\nprivate:\n    JniLocalScope(const JniLocalScope& other);\n    JniLocalScope& operator=(const JniLocalScope& other);\n\n    static bool _pushLocalFrame(JNIEnv* const env, jint capacity);\n    static void _popLocalFrame(JNIEnv* const env, jobject returnRef);\n\n    JNIEnv* const m_env;\n    const bool m_success;\n};\n\njstring jniStringFromUTF8(JNIEnv * env, const std::string & str);\nstd::string jniUTF8FromString(JNIEnv * env, const jstring jstr);\n\njstring jniStringFromWString(JNIEnv * env, const std::wstring & str);\nstd::wstring jniWStringFromString(JNIEnv * env, const jstring jstr);\n\nclass JniEnum {\npublic:\n    /*\n     * Given a Java object, find its numeric value. This returns a jint, which the caller can\n     * static_cast<> into the necessary C++ enum type.\n     */\n    jint ordinal(JNIEnv * env, jobject obj) const;\n\n    /*\n     * Create a Java value of the wrapped class with the given value.\n     */\n    LocalRef<jobject> create(JNIEnv * env, jint value) const;\n\nprotected:\n    JniEnum(const std::string & name);\n    jclass enumClass() const { return m_clazz.get(); }\n\nprivate:\n    const GlobalRef<jclass> m_clazz;\n    const jmethodID m_staticmethValues;\n    const jmethodID m_methOrdinal;\n};\n\nclass JniFlags : private JniEnum {\npublic:\n    /*\n     * Given a Java EnumSet convert it to the corresponding bit pattern\n     * which can then be static_cast<> to the actual enum.\n     */\n    unsigned flags(JNIEnv * env, jobject obj) const;\n\n    /*\n     * Create a Java EnumSet of the specified flags considering the given number of active bits.\n     */\n    LocalRef<jobject> create(JNIEnv * env, unsigned flags, int bits) const;\n\n    using JniEnum::create;\n\nprotected:\n    JniFlags(const std::string & name);\n\nprivate:\n    const GlobalRef<jclass> m_clazz { jniFindClass(\"java/util/EnumSet\") };\n    const jmethodID m_methNoneOf { jniGetStaticMethodID(m_clazz.get(), \"noneOf\", \"(Ljava/lang/Class;)Ljava/util/EnumSet;\") };\n    const jmethodID m_methAdd { jniGetMethodID(m_clazz.get(), \"add\", \"(Ljava/lang/Object;)Z\") };\n    const jmethodID m_methIterator { jniGetMethodID(m_clazz.get(), \"iterator\", \"()Ljava/util/Iterator;\") };\n    const jmethodID m_methSize { jniGetMethodID(m_clazz.get(), \"size\", \"()I\") };\n\n    struct {\n        const GlobalRef<jclass> clazz { jniFindClass(\"java/util/Iterator\") };\n        const jmethodID methNext { jniGetMethodID(clazz.get(), \"next\", \"()Ljava/lang/Object;\") };\n    } m_iterator;\n};\n\n#define DJINNI_FUNCTION_PROLOGUE0(env_)\n#define DJINNI_FUNCTION_PROLOGUE1(env_, arg1_)\n\n/*\n * Helper for JNI_TRANSLATE_EXCEPTIONS_RETURN.\n *\n * Must be called in a catch block.  Responsible for setting the pending\n * exception in JNI based on the current C++ exception.\n *\n * The default implementation is defined with __attribute__((weak)) so you\n * can replace it by defining your own version.  The default implementation\n * will call jniDefaultSetPendingFromCurrent(), which will propagate a\n * jni_exception directly into Java, or throw a RuntimeException for any\n * other std::exception.\n */\nvoid jniSetPendingFromCurrent(JNIEnv * env, const char * ctx) noexcept;\n\n/*\n * Helper for JNI_TRANSLATE_EXCEPTIONS_RETURN.\n *\n * Must be called in a catch block.  Responsible for setting the pending\n * exception in JNI based on the current C++ exception.\n *\n * This will call jniSetPendingFrom(env, jni_exception) if the current exception\n * is a jni_exception, or otherwise will set a RuntimeException from any\n * other std::exception.  Any non-std::exception will result in a call\n * to terminate().\n *\n * This is called by the default implementation of jniSetPendingFromCurrent.\n */\nvoid jniDefaultSetPendingFromCurrent(JNIEnv * env, const char * ctx) noexcept;\n\n/* Catch C++ exceptions and translate them to Java exceptions.\n *\n * All functions called by Java must be fully wrapped by an outer try...catch block like so:\n *\n * try {\n *     ...\n * } JNI_TRANSLATE_EXCEPTIONS_RETURN(env, 0)\n * ... or JNI_TRANSLATE_EXCEPTIONS_RETURN(env, ) for functions returning void\n *\n * The second parameter is a default return value to be used if an exception is caught and\n * converted. (For JNI outer-layer calls, this result will always be ignored by JNI, so\n * it can safely be 0 for any function with a non-void return value.)\n */\n#define JNI_TRANSLATE_EXCEPTIONS_RETURN(env, ret) \\\n    catch (const std::exception &) { \\\n        ::djinni::jniSetPendingFromCurrent(env, __func__); \\\n        return ret; \\\n    }\n\n/* Catch jni_exception and translate it back to a Java exception, without catching\n * any other C++ exceptions.  Can be used to wrap code which might cause JNI\n * exceptions like so:\n *\n * try {\n *     ...\n * } JNI_TRANSLATE_JAVA_EXCEPTIONS_RETURN(env, 0)\n * ... or JNI_TRANSLATE_JAVA_EXCEPTIONS_RETURN(env, ) for functions returning void\n *\n * The second parameter is a default return value to be used if an exception is caught and\n * converted. (For JNI outer-layer calls, this result will always be ignored by JNI, so\n * it can safely be 0 for any function with a non-void return value.)\n */\n#define JNI_TRANSLATE_JNI_EXCEPTIONS_RETURN(env, ret) \\\n    catch (const ::djinni::jni_exception & e) { \\\n        e.set_as_pending(env); \\\n        return ret; \\\n    }\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/nodejs/win_delay_load_hook.cpp",
    "content": "/*\n * When this file is linked to a DLL, it sets up a delay-load hook that\n * intervenes when the DLL is trying to load the host executable\n * dynamically. Instead of trying to locate the .exe file it'll just\n * return a handle to the process image.\n *\n * This allows compiled addons to work when the host executable is renamed.\n */\n\n#ifdef WIN32\n\n#ifdef _MSC_VER\n#pragma managed(push, off)\n#endif\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n\n#include <windows.h>\n\n#include <delayimp.h>\n#include <string.h>\n\n#ifndef NODE_HOST_BINARY\n#error NODE_HOST_BINARY must be defined\n#endif\n\n#define Q(x) #x\n#define QUOTE(x) Q(x)\n\nstatic FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {\n  HMODULE m;\n  if (event != dliNotePreLoadLibrary)\n    return NULL;\n\n  if (_stricmp(info->szDll, QUOTE(NODE_HOST_BINARY)) != 0)\n    return NULL;\n\n  m = GetModuleHandle(NULL);\n  return (FARPROC) m;\n}\n\ndecltype(__pfnDliNotifyHook2) __pfnDliNotifyHook2 = load_exe_hook;\n\n#ifdef _MSC_VER\n#pragma managed(pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJICppWrapperCache+Private.h",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n//  This header can only be imported to Objective-C++ source code!\n\n#import <Foundation/Foundation.h>\n#include <memory>\n\n#include \"../proxy_cache_interface.hpp\"\n\nnamespace djinni {\n\nstruct CppProxyCacheTraits {\n    using UnowningImplPointer = void *;\n    using OwningImplPointer = std::shared_ptr<void>;\n    using OwningProxyPointer = __strong id;\n    using WeakProxyPointer = __weak id;\n    using UnowningImplPointerHash = std::hash<void *>;\n    using UnowningImplPointerEqual = std::equal_to<void *>;\n};\n\n// This declares that GenericProxyCache will be instantiated separately. The actual\n// explicit instantiations are in DJIProxyCaches.mm.\nextern template class ProxyCache<CppProxyCacheTraits>;\nusing CppProxyCache = ProxyCache<CppProxyCacheTraits>;\n\n// Helper for get_cpp_proxy_impl that takes a std::shared_ptr.\ntemplate <typename ObjcType, typename CppType>\nObjcType * get_cpp_proxy_impl(const std::shared_ptr<CppType> & cppRef) {\n    return CppProxyCache::get(\n        typeid(cppRef),\n        cppRef,\n        [] (const std::shared_ptr<void> & cppRef) -> std::pair<id, void *> {\n            return {\n                [[ObjcType alloc] initWithCpp:std::static_pointer_cast<CppType>(cppRef)],\n                cppRef.get()\n            };\n        }\n    );\n}\n\n// get_cpp_proxy takes any smart pointer type, as long as it can be implicitly cast\n// to std::shared_ptr. This means get_cpp_proxy can also be passed non-nullable pointers.\ntemplate <typename ObjcType, typename CppPtrType>\nObjcType * get_cpp_proxy(const CppPtrType & cppRef) {\n    return get_cpp_proxy_impl<ObjcType, typename std::remove_reference<decltype(*cppRef)>::type>(cppRef);\n}\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJIError.h",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\nnamespace djinni {\n\n// Throws an exception for an unimplemented method call.\n[[noreturn]] void throwUnimplemented(const char * ctx, NSString * msg);\n\n// Helper function for exception translation. Do not call directly!\n[[noreturn]] void throwNSExceptionFromCurrent(const char * ctx);\n\n} // namespace djinni\n\n#define DJINNI_UNIMPLEMENTED(msg) \\\n    ::djinni::throwUnimplemented(__PRETTY_FUNCTION__, msg);\n\n#define DJINNI_TRANSLATE_EXCEPTIONS() \\\n    catch (const std::exception & e) { \\\n        ::djinni::throwNSExceptionFromCurrent(__PRETTY_FUNCTION__); \\\n    }\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJIError.mm",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#include <Foundation/Foundation.h>\n#include \"DJIError.h\"\n#include <exception>\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni {\n\n[[noreturn]] __attribute__((weak)) void throwUnimplemented(const char * /*ctx*/, NSString * message) {\n    [NSException raise:NSInternalInconsistencyException format:@\"Unimplemented: %@\", message];\n    __builtin_unreachable();\n}\n\n[[noreturn]] __attribute__((weak)) void throwNSExceptionFromCurrent(const char * /*ctx*/) {\n    try {\n        throw;\n    } catch (const std::exception & e) {\n        NSString *message = [NSString stringWithCString:e.what() encoding:NSUTF8StringEncoding];\n        [NSException raise:message format:@\"%@\", message];\n        __builtin_unreachable();\n    }\n}\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJIMarshal+Private.h",
    "content": "//\n//  DJIMarshal+Private.h\n//  Djinni\n//\n//  Created by knejp on 20.3.15.\n//  Copyright (c) 2015 Dropbox. All rights reserved.\n//\n\n#pragma once\n#import <Foundation/Foundation.h>\n#include <chrono>\n#include <cstdint>\n#include <string>\n#include <type_traits>\n#include <unordered_set>\n#include <unordered_map>\n#include <vector>\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\nnamespace djinni {\n\nstruct Bool {\n    using CppType = bool;\n    using ObjcType = BOOL;\n\n    static CppType toCpp(ObjcType x) noexcept { return x ? true : false; }\n    static ObjcType fromCpp(CppType x) noexcept { return x ? YES : NO; }\n\n    struct Boxed {\n        using ObjcType = NSNumber*;\n        static CppType toCpp(ObjcType x) noexcept { assert(x); return Bool::toCpp([x boolValue]); }\n        static ObjcType fromCpp(CppType x) noexcept { return [NSNumber numberWithBool:Bool::fromCpp(x)]; }\n    };\n};\n\ntemplate<class Self, class T>\nstruct Primitive {\n    using CppType = T;\n    using ObjcType = T;\n\n    static CppType toCpp(ObjcType x) noexcept { return x; }\n    static ObjcType fromCpp(CppType x) noexcept { return x; }\n\n    struct Boxed {\n        using ObjcType = NSNumber*;\n        static CppType toCpp(ObjcType x) noexcept { assert(x); return static_cast<CppType>(Self::unbox(x)); }\n        static ObjcType fromCpp(CppType x) noexcept { return Self::box(x); }\n    };\n};\n\nclass I8 : public Primitive<I8, int8_t> {\n    friend Primitive<I8, int8_t>;\n    static char unbox(Boxed::ObjcType x) noexcept { return [x charValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithChar:static_cast<char>(x)]; }\n};\n\nclass I16 : public Primitive<I16, int16_t> {\n    friend Primitive<I16, int16_t>;\n    static short unbox(Boxed::ObjcType x) noexcept { return [x shortValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithShort:static_cast<short>(x)]; }\n};\n\nclass I32 : public Primitive<I32, int32_t> {\n    friend Primitive<I32, int32_t>;\n    static int unbox(Boxed::ObjcType x) noexcept { return [x intValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithInt:static_cast<int>(x)]; }\n};\n\nclass I64 : public Primitive<I64, int64_t> {\n    friend Primitive<I64, int64_t>;\n    static long long unbox(Boxed::ObjcType x) noexcept { return [x longLongValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithLongLong:static_cast<long long>(x)]; }\n};\n\nclass F32 : public Primitive<F32, float> {\n    friend Primitive<F32, float>;\n    static CppType unbox(Boxed::ObjcType x) noexcept { return [x floatValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithFloat:x]; }\n};\n\nclass F64 : public Primitive<F64, double> {\n    friend Primitive<F64, double>;\n    static CppType unbox(Boxed::ObjcType x) noexcept { return [x doubleValue]; }\n    static Boxed::ObjcType box(CppType x) noexcept { return [NSNumber numberWithDouble:x]; }\n};\n\ntemplate<class CppEnum, class ObjcEnum>\nstruct Enum {\n    using CppType = CppEnum;\n    using ObjcType = ObjcEnum;\n\n    static CppType toCpp(ObjcType e) noexcept { return static_cast<CppType>(e); }\n    static ObjcType fromCpp(CppType e) noexcept { return static_cast<ObjcType>(e); }\n\n    struct Boxed {\n        using ObjcType = NSNumber*;\n        static CppType toCpp(ObjcType x) noexcept { return toCpp(x, Tag<typename std::underlying_type<CppType>::type>()); }\n        static ObjcType fromCpp(CppType x) noexcept { return fromCpp(x, Tag<typename std::underlying_type<CppType>::type>()); }\n\n    private:\n        template<class T> struct Tag { };\n\n        static CppType toCpp(ObjcType x, Tag<int>) noexcept { return Enum::toCpp(static_cast<Enum::ObjcType>([x integerValue])); }\n        static ObjcType fromCpp(CppType x, Tag<int>) noexcept { return [NSNumber numberWithInteger:static_cast<NSInteger>(Enum::fromCpp(x))]; }\n\n        static CppType toCpp(ObjcType x, Tag<unsigned>) noexcept { return Enum::toCpp(static_cast<Enum::ObjcType>([x unsignedIntegerValue])); }\n        static ObjcType fromCpp(CppType x, Tag<unsigned>) noexcept { return [NSNumber numberWithUnsignedInteger:static_cast<NSUInteger>(Enum::fromCpp(x))]; }\n    };\n};\n\nstruct String {\n    using CppType = std::string;\n    using ObjcType = NSString*;\n\n    using Boxed = String;\n\n    static CppType toCpp(ObjcType string) {\n        assert(string);\n        return {[string UTF8String], [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]};\n    }\n\n    static ObjcType fromCpp(const CppType& string) {\n        assert(string.size() <= std::numeric_limits<NSUInteger>::max());\n        return [[NSString alloc] initWithBytes:string.data()\n                                        length:static_cast<NSUInteger>(string.size())\n                                      encoding:NSUTF8StringEncoding];\n    }\n};\n\ntemplate<int wcharTypeSize>\nstatic NSStringEncoding getWCharEncoding()\n{\n    static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, \"wchar_t must be represented by UTF-16 or UTF-32 encoding\");\n    return {}; // unreachable\n}\n\ntemplate<>\ninline NSStringEncoding getWCharEncoding<2>() {\n    // case when wchar_t is represented by utf-16 encoding\n#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n    return NSUTF16BigEndianStringEncoding;\n#else\n    return NSUTF16LittleEndianStringEncoding;\n#endif\n}\n\ntemplate<>\ninline NSStringEncoding getWCharEncoding<4>() {\n    // case when wchar_t is represented by utf-32 encoding\n#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n    return NSUTF32BigEndianStringEncoding;\n#else\n    return NSUTF32LittleEndianStringEncoding;\n#endif\n}\n\nstruct WString {\n    using CppType = std::wstring;\n    using ObjcType = NSString*;\n\n    using Boxed = WString;\n\n    static CppType toCpp(ObjcType string) {\n        assert(string);\n        NSStringEncoding encoding = getWCharEncoding<sizeof(wchar_t)>();\n        NSData* data = [string dataUsingEncoding:encoding];\n        return std::wstring((wchar_t*)[data bytes], [data length] / sizeof (wchar_t));\n    }\n\n    static ObjcType fromCpp(const CppType& string) {\n        assert(string.size() <= std::numeric_limits<NSUInteger>::max());\n        return [[NSString alloc] initWithBytes:string.data()\n                                     length:string.size() * sizeof(wchar_t)\n                                     encoding:getWCharEncoding<sizeof(wchar_t)>()];\n    }\n};\n\nstruct Date {\n    using CppType = std::chrono::system_clock::time_point;\n    using ObjcType = NSDate*;\n\n    using Boxed = Date;\n\n    static CppType toCpp(ObjcType date) {\n        using namespace std::chrono;\n        static const auto POSIX_EPOCH = system_clock::from_time_t(0);\n        auto timeIntervalSince1970 = duration<double>([date timeIntervalSince1970]);\n        return POSIX_EPOCH + duration_cast<system_clock::duration>(timeIntervalSince1970);\n    }\n\n    static ObjcType fromCpp(const CppType& date) {\n        using namespace std::chrono;\n        static const auto POSIX_EPOCH = system_clock::from_time_t(0);\n        return [NSDate dateWithTimeIntervalSince1970:duration_cast<duration<double>>(date - POSIX_EPOCH).count()];\n\n    }\n};\n\nstruct Binary {\n    using CppType = std::vector<uint8_t>;\n    using ObjcType = NSData*;\n\n    using Boxed = Binary;\n\n    static CppType toCpp(ObjcType data) {\n        assert(data);\n        auto bytes = reinterpret_cast<const uint8_t*>(data.bytes);\n        return data.length > 0 ? CppType{bytes, bytes + data.length} : CppType{};\n    }\n\n    static ObjcType fromCpp(const CppType& bytes) {\n        assert(bytes.size() <= std::numeric_limits<NSUInteger>::max());\n        // Using the pointer from .data() on an empty vector is UB\n        return bytes.empty() ? [NSData data] : [NSData dataWithBytes:bytes.data()\n                                                              length:static_cast<NSUInteger>(bytes.size())];\n    }\n};\n\ntemplate<template<class> class OptionalType, class T>\nclass Optional {\n    // SFINAE helper: if C::CppOptType exists, opt_type<T>(nullptr) will return\n    // that type. If not, it returns OptionalType<C::CppType>. This is necessary\n    // because we special-case optional interfaces to be represented as a nullable\n    // std::shared_ptr<T>, not optional<shared_ptr<T>> or optional<nn<shared_ptr<T>>>.\n    template <typename C> static OptionalType<typename C::CppType> opt_type(...);\n    template <typename C> static typename C::CppOptType opt_type(typename C::CppOptType *);\n\npublic:\n    using CppType = decltype(opt_type<T>(nullptr));\n    using ObjcType = typename T::Boxed::ObjcType;\n\n    using Boxed = Optional;\n\n    static CppType toCpp(ObjcType obj) {\n        if (obj) {\n            return T::Boxed::toCpp(obj);\n        } else {\n            return CppType();\n        }\n    }\n\n    // fromCpp used for normal optionals\n    static ObjcType fromCpp(const OptionalType<typename T::CppType>& opt) {\n        return opt ? T::Boxed::fromCpp(*opt) : nil;\n    }\n\n    // fromCpp used for nullable shared_ptr\n    template <typename C = T>\n    static ObjcType fromCpp(const typename C::CppOptType & cppOpt) {\n        return T::Boxed::fromCppOpt(cppOpt);\n    }\n};\n\ntemplate<class T>\nclass List {\n    using ECppType = typename T::CppType;\n    using EObjcType = typename T::Boxed::ObjcType;\n\npublic:\n    using CppType = std::vector<ECppType>;\n    using ObjcType = NSArray*;\n\n    using Boxed = List;\n\n    static CppType toCpp(ObjcType array) {\n        assert(array);\n        auto v = CppType();\n        v.reserve(array.count);\n        for(EObjcType value in array) {\n            v.push_back(T::Boxed::toCpp(value));\n        }\n        return v;\n    }\n\n    static ObjcType fromCpp(const CppType& v) {\n        assert(v.size() <= std::numeric_limits<NSUInteger>::max());\n        auto array = [NSMutableArray arrayWithCapacity:static_cast<NSUInteger>(v.size())];\n        for(const auto& value : v) {\n            [array addObject:T::Boxed::fromCpp(value)];\n        }\n        return [array copy];\n    }\n};\n\ntemplate<class T>\nclass Set {\n    using ECppType = typename T::CppType;\n    using EObjcType = typename T::Boxed::ObjcType;\n\npublic:\n    using CppType = std::unordered_set<ECppType>;\n    using ObjcType = NSSet*;\n\n    using Boxed = Set;\n\n    static CppType toCpp(ObjcType set) {\n        assert(set);\n        auto s = CppType();\n        for(EObjcType value in set) {\n            s.insert(T::Boxed::toCpp(value));\n        }\n        return s;\n    }\n\n    static ObjcType fromCpp(const CppType& s) {\n        assert(s.size() <= std::numeric_limits<NSUInteger>::max());\n        auto set = [NSMutableSet setWithCapacity:static_cast<NSUInteger>(s.size())];\n        for(const auto& value : s) {\n            [set addObject:T::Boxed::fromCpp(value)];\n        }\n        return [set copy];\n    }\n};\n\ntemplate<class Key, class Value>\nclass Map {\n    using CppKeyType = typename Key::CppType;\n    using CppValueType = typename Value::CppType;\n    using ObjcKeyType = typename Key::Boxed::ObjcType;\n    using ObjcValueType = typename Value::Boxed::ObjcType;\n\npublic:\n    using CppType = std::unordered_map<CppKeyType, CppValueType>;\n    using ObjcType = NSDictionary*;\n\n    using Boxed = Map;\n\n    static CppType toCpp(ObjcType map) {\n        assert(map);\n        __block auto m = CppType();\n        m.reserve(map.count);\n        [map enumerateKeysAndObjectsUsingBlock:^(ObjcKeyType key, ObjcValueType obj, BOOL *) {\n            m.emplace(Key::Boxed::toCpp(key), Value::Boxed::toCpp(obj));\n        }];\n        return m;\n    }\n\n    static ObjcType fromCpp(const CppType& m) {\n        assert(m.size() <= std::numeric_limits<NSUInteger>::max());\n        auto map = [NSMutableDictionary dictionaryWithCapacity:static_cast<NSUInteger>(m.size())];\n        for(const auto& kvp : m) {\n            [map setObject:Value::Boxed::fromCpp(kvp.second) forKey:Key::Boxed::fromCpp(kvp.first)];\n        }\n        return [map copy];\n    }\n};\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJIObjcWrapperCache+Private.h",
    "content": "//\n// Copyright 2014 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n//  This header can only be imported to Objective-C++ source code!\n\n#import <Foundation/Foundation.h>\n#include <memory>\n\n#include \"../proxy_cache_interface.hpp\"\n\nnamespace djinni {\n\nstruct unretained_id_hash { std::size_t operator()(__unsafe_unretained id ptr) const; };\n\nstruct ObjcProxyCacheTraits {\n    using UnowningImplPointer = __unsafe_unretained id;\n    using OwningImplPointer = __strong id;\n    using OwningProxyPointer = std::shared_ptr<void>;\n    using WeakProxyPointer = std::weak_ptr<void>;\n    using UnowningImplPointerHash = unretained_id_hash;\n    using UnowningImplPointerEqual = std::equal_to<__unsafe_unretained id>;\n};\n\n// This declares that GenericProxyCache will be instantiated separately. The actual\n// explicit instantiations are in DJIProxyCaches.mm.\nextern template class ProxyCache<ObjcProxyCacheTraits>;\nusing ObjcProxyCache = ProxyCache<ObjcProxyCacheTraits>;\n\ntemplate <typename CppType, typename ObjcType>\nstatic std::shared_ptr<CppType> get_objc_proxy(ObjcType * objcRef) {\n    return std::static_pointer_cast<CppType>(ObjcProxyCache::get(\n        typeid(objcRef),\n        objcRef,\n        [] (const __strong id & objcRef) -> std::pair<std::shared_ptr<void>, __unsafe_unretained id> {\n            return {\n                std::make_shared<CppType>(objcRef),\n                objcRef\n            };\n        }\n    ));\n}\n\n// Private implementation base class for all ObjC proxies, which manages the\n// Handle, and ensures that it is created and destroyed in a safe way, inside\n// of an @autoreleasepool to avoid leaks.  The complexity here is just necessary\n// to gain explicit control of construction and destruction time of the member\n// Handle, to make sure it's inside the @autoreleasepool block.\n// An optional<HandleType> would meet our needs, but we can't use it directly\n// since the support-lib doesn't know which optional implementation might be in\n// use, if any.  We can't take OptionalType as a template arg here, because we\n// also need to know where to find nullopt in order to implement the destructor\n// above.  This class uses the same technique as at least one optional\n// implementation: The union ensures proper alignment, while leaving construction\n// and destruction under our direct control.\ntemplate <typename ObjcType>\nclass ObjcProxyBase {\n    using HandleType = ::djinni::ObjcProxyCache::Handle<ObjcType>;\npublic:\n    ObjcProxyBase(ObjcType objc) {\n        @autoreleasepool {\n            new (&m_djinni_private_proxy_handle) HandleType(objc);\n        }\n    }\n\n    ObjcProxyBase(const ObjcProxyBase&) = delete;\n    ObjcProxyBase& operator=(const ObjcProxyBase&) = delete;\n\n    // Not intended for polymorphic use, so dtor is not virtual\n    ~ObjcProxyBase() {\n        @autoreleasepool {\n            m_djinni_private_proxy_handle.~HandleType();\n        }\n    }\n\n    // Long name to minimize likelyhood of collision with interface methods.\n    // Return by reference to make it clear there's nothing for ARC to do here.\n    // Call site should have its own autoreleasepool if necessary.\n    const ObjcType & djinni_private_get_proxied_objc_object() const {\n        return m_djinni_private_proxy_handle.get();\n    }\n\nprivate:\n    union {\n        // Long names to minimize likelyhood of collision with interface methods.\n        char m_djinni_private_dummy;\n        HandleType m_djinni_private_proxy_handle;\n    };\n};\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/objc/DJIProxyCaches.mm",
    "content": "//\n// Copyright 2015 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nstatic_assert(__has_feature(objc_arc), \"Djinni requires ARC to be enabled for this file\");\n\n#include \"../proxy_cache_impl.hpp\"\n#include \"DJIObjcWrapperCache+Private.h\"\n#include \"DJICppWrapperCache+Private.h\"\n\nnamespace djinni {\n\nstd::size_t unretained_id_hash::operator()(__unsafe_unretained id ptr) const {\n    return std::hash<void*>()((__bridge void*)ptr);\n}\n\ntemplate class ProxyCache<ObjcProxyCacheTraits>;\ntemplate class ProxyCache<CppProxyCacheTraits>;\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/proxy_cache_impl.hpp",
    "content": "//\n// Copyright 2015 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#include \"proxy_cache_interface.hpp\"\n#include <functional>\n#include <mutex>\n#include <unordered_map>\n\n// \"\"\"\n//    This place is not a place of honor.\n//    No highly esteemed deed is commemorated here.\n//    Nothing valued is here.\n//    This place is a message and part of a system of messages.\n//    Pay attention to it!\n//    Sending this message was important to us.\n//    We considered ourselves to be a powerful culture.\n// \"\"\"\n//\n// From \"Expert Judgment on Markers to Deter Inadvertent Human Intrusion into the Waste\n// Isolation Pilot Plant\", Sandia National Laboratories report SAND92-1382 / UC-721, p. F-49\n\nnamespace djinni {\n\n// See comment on `get_unowning()` in proxy_cache_interface.hpp.\ntemplate <typename T> static inline auto upgrade_weak(const T & ptr) -> decltype(ptr.lock()) {\n    return ptr.lock();\n}\ntemplate <typename T> static inline T * upgrade_weak(T* ptr) { return ptr; }\ntemplate <typename T> static inline bool is_expired(const T & ptr) { return ptr.expired(); }\ntemplate <typename T> static inline bool is_expired(T* ptr) { return !ptr; }\n\n/*\n * Generic proxy cache.\n *\n * This provides a general-purpose mechanism for proxies to be re-used. When we pass an object\n * across the language boundary from A to B, we must create a proxy object within language B\n * that passes calls back to language A. For example, if have a C++ object that is passed into\n * Java, we would create a Java object that owns a `shared_ptr` and has a set of native methods\n * that call in to C++.\n *\n * When we create such an object, we also want to cache a weak reference to it, so that if we\n * later pass the *same* object across the boundary, the same proxy will be returned. This is\n * necessary for correctness in some situations: for example, in the case of an `add_listener`\n * and `remove_listener` pattern.\n *\n * To reduce code size, only one GenericProxyCache need be instantiated for each language\n * boundary direction. The pointer types passed to this function can be generic, e.g. `id`,\n * `shared_ptr<void>`, `jobject`, etc.\n *\n * In the types below, \"Impl\" refers to some interface that is being wrapped, and Proxy refers\n * to the generated other-language object that wraps it.\n */\ntemplate <typename Traits>\nclass ProxyCache<Traits>::Pimpl {\n    using Key = std::pair<std::type_index, UnowningImplPointer>;\n\npublic:\n    /*\n     * Look up an object in the proxy cache, and create a new one if not found.\n     *\n     * This takes a function pointer, not an arbitrary functor, because we want to minimize\n     * code size: this function should only be instantiated *once* per langauge direction.\n     */\n    OwningProxyPointer get(const std::type_index & tag,\n                           const OwningImplPointer & impl,\n                           AllocatorFunction * alloc) {\n        std::unique_lock<std::mutex> lock(m_mutex);\n        UnowningImplPointer ptr = get_unowning(impl);\n        auto existing_proxy_iter = m_mapping.find({tag, ptr});\n        if (existing_proxy_iter != m_mapping.end()) {\n            OwningProxyPointer existing_proxy = upgrade_weak(existing_proxy_iter->second);\n            if (existing_proxy) {\n                return existing_proxy;\n            } else {\n                // The weak reference is expired, so prune it from the map eagerly.\n                m_mapping.erase(existing_proxy_iter);\n            }\n        }\n\n        auto alloc_result = alloc(impl);\n        m_mapping.emplace(Key{tag, alloc_result.second}, alloc_result.first);\n        return alloc_result.first;\n    }\n\n    /*\n     * Erase an object from the proxy cache.\n     */\n    void remove(const std::type_index & tag, const UnowningImplPointer & impl_unowning) {\n        std::unique_lock<std::mutex> lock(m_mutex);\n        auto it = m_mapping.find({tag, impl_unowning});\n        if (it != m_mapping.end()) {\n            // The entry in the map should already be expired: this is called from Handle's\n            // destructor, so the proxy must already be gone. However, remove() does not\n            // happen atomically with the proxy object becoming weakly reachable. It's\n            // possible that during the window between when the weak-ref holding this proxy\n            // expires and when we enter remove() and take m_mutex, another thread could have\n            // created a new proxy for the same original object and added it to the map. In\n            // that case, `it->second` will contain a live pointer to a different proxy object,\n            // not an expired weak pointer to the Handle currently being destructed. We only\n            // remove the map entry if its pointer is already expired.\n            if (is_expired(it->second)) {\n                m_mapping.erase(it);\n            }\n        }\n    }\n\nprivate:\n    struct KeyHash {\n        std::size_t operator()(const Key & k) const {\n            return k.first.hash_code() ^ UnowningImplPointerHash{}(k.second);\n        }\n    };\n\n    struct KeyEqual {\n        bool operator()(const Key & lhs, const Key & rhs) const {\n            return lhs.first == rhs.first\n                && UnowningImplPointerEqual{}(lhs.second, rhs.second);\n        }\n    };\n\n    std::unordered_map<Key, WeakProxyPointer, KeyHash, KeyEqual> m_mapping;\n    std::mutex m_mutex;\n\n    // Only ProxyCache<Traits>::get_base() can allocate these objects.\n    Pimpl() = default;\n    friend class ProxyCache<Traits>;\n};\n\ntemplate <typename Traits>\nvoid ProxyCache<Traits>::cleanup(const std::shared_ptr<Pimpl> & base,\n                                 const std::type_index & tag,\n                                 UnowningImplPointer ptr) {\n    base->remove(tag, ptr);\n}\n\n/*\n * Magic-static singleton.\n *\n * It's possible for someone to hold Djinni-static objects in a global (like a shared_ptr\n * at namespace scope), which can cause problems at static destruction time: if the proxy\n * cache itself is destroyed before the other global, use-of-destroyed-object will result.\n * To fix this, we make it possible to take a shared_ptr to the GenericProxyCache instance,\n * so it will only be destroyed once all references are gone.\n */\ntemplate <typename Traits>\nauto ProxyCache<Traits>::get_base() -> const std::shared_ptr<Pimpl> & {\n    static const std::shared_ptr<Pimpl> instance(new Pimpl);\n    // Return by const-ref. This is safe to call any time except during static destruction.\n    // Returning by reference lets us avoid touching the refcount unless needed.\n    return instance;\n}\n\ntemplate <typename Traits>\nauto ProxyCache<Traits>::get(const std::type_index & tag,\n                             const OwningImplPointer & impl,\n                             AllocatorFunction * alloc)\n        -> OwningProxyPointer {\n    return get_base()->get(tag, impl, alloc);\n}\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/proxy_cache_interface.hpp",
    "content": "//\n// Copyright 2015 Dropbox, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#include <memory>\n#include <functional>\n#include <typeindex>\n\nnamespace djinni {\n\n/*\n * The template parameters we receive here can be a number of different types: C++ smart\n * pointers, custom wrappers, or language-specific types (like ObjC's `id` / `__weak id`).\n * If custom wrapper types are used, like the `JavaWeakRef` type in the JNI library, then\n * they must implement `.get()` or `.lock()` by analogy with C++'s smart pointers.\n *\n * We assume that built-in types are pointer-compatible. This is the case with ObjC: for\n * example, __weak id pointers can be implicitly converted to __strong id, and so on.\n *\n * (The helper for .lock() is only used by proxy_cache_impl.hpp, so it's defined there.)\n */\ntemplate <typename T> static inline auto get_unowning(const T & ptr) -> decltype(ptr.get()) {\n    return ptr.get();\n}\ntemplate <typename T> static inline T * get_unowning(T * ptr) { return ptr; }\n\n/*\n * ProxyCache provides a mechanism for re-using proxy objects generated in one language\n * that wrap around implementations in a different language. This is for correctness, not\n * just performance: when we pass the same object across a language boundary twice, we want\n * to get the same proxy object on the other side each time, so that identity semantics\n * behave as expected.\n *\n * ProxyCache is instantiated with a Traits class that must contain the following typedefs.\n * Examples refer to the use of ProxyCache to cache C++ wrappers around ObjC objects.\n * ProxyCache itself is generic (type-erased), though Handle is not, so we use e.g. `id`\n * and `shared_ptr<void>` rather than any specific types.\n *\n * - UnowningImplPointer:\n *       a non-owning pointer to an object being wrapped, e.g. __unsafe_unretained id\n * - OwningImplPointer:\n *       a strong owning pointer to an object being wrapped, e.g. __strong id\n * - OwningProxyPointer:\n *       a strong owning pointer to a wrapper, e.g. std::shared_ptr<void>\n * - WeakProxyPointer:\n *       a safe weak pointer to a wrapper, e.g. std::weak_ptr<void>\n * - UnowningImplPointerHash:\n *       a hasher for UnowningImplPointer, usually std::hash<UnowningImplPointer>, unless\n *       std::hash doesn't work with UnowningImplPointer in which case a custom type can be\n *       provided.\n * - UnowningImplPointerEqual:\n *       an equality predicate for UnowningImplPointer, like std::equal_to<UnowningImplPointer>.\n *       In some cases (e.g. Java) a custom equality predicate may be needed.\n *\n * Generally, ProxyCache will be explicitly instantiated in one source file with C++11's\n * `extern template` mechanism. The WeakProxyPointer, UnowningImplPointerHash, and\n * UnowningImplPointerEqual types can be incomplete except for where the explicit\n * instantiation is actually defined.\n *\n * Here's an overview of the structure:\n *\n *                           ______________  std::pair<ImplType,\n *          WeakProxyPonter |              | UnowningImplPointer>\n *           - - - - - - - -|  ProxyCache  |- - - - - - - - - -\n *          |               |              |                   |\n *          |               |______________|                   |\n *          |                                                  |\n *      ____v____        ______________          ______________v__________\n *     |         |      |              |        |                         |\n *     | (Proxy  | ===> | ProxyCache:: | =====> | (Impl object providing  |\n *     | object) |  ^   |   Handle<T>  |   T    |  actual functionality)  |\n *     |_________|  .   |______________|   ^    |_________________________|\n *                  .                     .\n *     ( can be member, base, )       ( T is a generally a specific   )\n *     ( or cross-language    )       ( owning type like id<Foo>,     )\n *     ( reference like jlong )       ( shared_ptr<Foo>, or GlobalRef )\n *\n * The cache contains a map from pair<ImplType, UnowningImplPointer>\n * to WeakProxyPointer, allowing it to answer the question: \"given this\n * impl, do we already have a proxy in existence?\"\n *\n * We use one map for all translated types, rather than a separate one for each type,\n * to minimize duplication of code and make it so the unordered_map is as contained as\n * possible.\n */\ntemplate <typename Traits>\nclass ProxyCache {\npublic:\n    using UnowningImplPointer = typename Traits::UnowningImplPointer;\n    using OwningImplPointer = typename Traits::OwningImplPointer;\n    using OwningProxyPointer = typename Traits::OwningProxyPointer;\n    using WeakProxyPointer = typename Traits::WeakProxyPointer;\n    using UnowningImplPointerHash = typename Traits::UnowningImplPointerHash;\n    using UnowningImplPointerEqual = typename Traits::UnowningImplPointerEqual;\n    class Pimpl;\n\n    /*\n     * Each proxy object must own a Handle. The Handle carries a strong reference to whatever\n     * the proxy wraps. When `ProxyCache::get()` creates a proxy, it also adds the proxy to\n     * the global proxy cache; Handle::~Handle() removes the reference from the cache.\n     *\n     * The Handle can be held by the proxy in any of a number of ways: as a C++ member or\n     * base, as an ObjC instance variable, or across an FFI boundary (a Java object might\n     * contain the address of a Handle as a `long` and delete it in the destructor.)\n     *\n     * T is generally a more-specialized version of OwningImplPointer. For example, when\n     * managing C++ proxies for ObjC objects, OwningImplPointer would be `id`, and the C++\n     * proxy class `MyInterface` which wraps `@protocol DBMyInterface` would contain a\n     * `Handle<id<DBMyInterface>>`.\n     *\n     * TagType should be the same type that was passed in to `get()` when this handle was\n     * created. Normally this is the same as T (a specialized OwningImplPointer), but in\n     * cases like Java where all object types are uniformly represented as `jobject` in C++,\n     * another type may be used.\n     */\n    template <typename T, typename TagType = T>\n    class Handle {\n    public:\n        template <typename... Args> Handle(Args &&... args)\n            : m_cache(get_base()), m_obj(std::forward<Args>(args)...) {}\n        Handle(const Handle &) = delete;\n        Handle & operator=(const Handle &) = delete;\n        ~Handle() { if (m_obj) cleanup(m_cache, typeid(TagType), get_unowning(m_obj)); }\n\n        void assign(const T & obj) { m_obj = obj; }\n\n        const T & get() const & noexcept { return m_obj; }\n\n    private:\n        const std::shared_ptr<Pimpl> m_cache;\n        T m_obj;\n    };\n\n    /*\n     * Function typedef for helpers passed in to allocate new objects.\n     * To reduce code size, the proxy cache type-erases the objects inside it.\n     *\n     * An allocator function takes an OwningImplPointer to the source language object,\n     * and returns a newly-created proxy.\n     *\n     * In Java, an OwningImplPointer does not provide the same identity semantics as the\n     * underlying object. (A JNI 'jobject' can be one of a few different types of reference,\n     * and JNI is structured to allow copying GCs, so an object's address might change over\n     * time.) This is why ProxyCache takes hasher and comparator paramters. In particular,\n     * the OwningImplPointer passed into the allocator might be a JNI local reference. The\n     * allocator will create a GlobalRef to the impl object and store it in the returned proxy.\n     *\n     * Because we don't constrain how Handle objects are held, there's no generic way for the\n     * proxy cache to get the GlobalRef out of the returned proxy object, so AllocatorFunction\n     * returns a pair: the first element is the newly created proxy, and the second is an\n     * UnowningImplPointer that will be used as a key in the map.\n     */\n    using AllocatorFunction =\n        std::pair<OwningProxyPointer, UnowningImplPointer>(const OwningImplPointer &);\n\n    /*\n     * Return the existing proxy for `impl`, if any. If not, create one by calling `alloc`,\n     * store a weak reference to it in the proxy cache, and return it.\n     */\n    static OwningProxyPointer get(const std::type_index &,\n                                  const OwningImplPointer & impl,\n                                  AllocatorFunction * alloc);\n\nprivate:\n    static void cleanup(const std::shared_ptr<Pimpl> &,\n                        const std::type_index &,\n                        UnowningImplPointer);\n    static const std::shared_ptr<Pimpl> & get_base();\n};\n\n} // namespace djinni\n"
  },
  {
    "path": "src/unity/djinni/support-lib/support-lib.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/java\" isTestSource=\"false\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "src/unity/djinni/support-lib/support_lib.gyp",
    "content": "{\n  \"targets\": [\n    {\n      \"target_name\": \"djinni_jni\",\n      \"type\": \"static_library\",\n      \"sources\": [\n        \"djinni_common.hpp\",\n        \"jni/djinni_support.cpp\",\n        \"jni/djinni_support.hpp\",\n        \"jni/Marshal.hpp\",\n      ],\n      \"include_dirs\": [\n        \"jni\",\n      ],\n      \"direct_dependent_settings\": {\n        \"include_dirs\": [\n          \"jni\",\n        ],\n      },\n    },\n    {\n      \"target_name\": \"djinni_jni_main\",\n      \"type\": \"static_library\",\n      \"sources\": [\n        \"jni/djinni_main.cpp\",\n      ],\n      \"link_settings\": {\n        \"aosp_build_settings\": {\n          \"LOCAL_WHOLE_STATIC_LIBRARIES\": [ 'djinni_jni_main' ], # Ensure JNI symbols are exposed\n        },\n      },\n    },\n    {\n      \"target_name\": \"djinni_objc\",\n      \"type\": \"static_library\",\n      \"xcode_settings\": {\n        \"CLANG_ENABLE_OBJC_ARC\": \"YES\",\n      },\n      \"sources\": [\n        \"objc/DJICppWrapperCache+Private.h\",\n        \"objc/DJIError.h\",\n        \"objc/DJIError.mm\",\n        \"objc/DJIMarshal+Private.h\",\n        \"objc/DJIObjcWrapperCache+Private.h\",\n        \"objc/DJIProxyCaches.mm\",\n        \"proxy_cache_impl.hpp\",\n        \"proxy_cache_interface.hpp\",\n      ],\n      \"include_dirs\": [\n        \"objc\",\n      ],\n      \"direct_dependent_settings\": {\n        \"include_dirs\": [\n          \"objc\",\n        ],\n      },\n    },\n  ],\n}\n"
  },
  {
    "path": "src/unity/generic/init_generic.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"init.h\"\n#include \"chainparams.h\"\n#include \"chain.h\"\n#include \"generation/miner.h\"\n#include \"httprpc.h\"\n#include \"httpserver.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"policy/policy.h\"\n#include \"rpc/blockchain.h\"\n#include \"rpc/register.h\"\n#include \"rpc/server.h\"\n#include \"script/sigcache.h\"\n#include \"torcontrol.h\"\n#include \"txdb.h\"\n#include \"util.h\"\n#include \"util/moneystr.h\"\n#include <warnings.h>\n#include \"init.h\"\n\n\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n\n//If we want to translate help messages in future we can replace helptr with _ and everything will just work.\n#define helptr(x) std::string(x)\n//If we want to translate error messages in future we can replace helptr with _ and everything will just work.\n#define errortr(x) std::string(x)\n\n\nstd::string HelpMessage(HelpMessageMode mode)\n{\n    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);\n    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);\n    const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);\n    const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);\n    const bool showDebug = GetBoolArg(\"-help-debug\", false);\n\n    // When adding new options to the categories, please keep and ensure alphabetical ordering.\n    // Do not translate helptr(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.\n    std::string strUsage = HelpMessageGroup(helptr(\"Options:\"));\n    strUsage += HelpMessageOpt(\"-?\", helptr(\"Print this help message and exit\"));\n    strUsage += HelpMessageOpt(\"-version\", helptr(\"Print version and exit\"));\n    strUsage += HelpMessageOpt(\"-alerts\", strprintf(helptr(\"Receive and display P2P network alerts (default: %u)\"), DEFAULT_ALERTS));\n    strUsage += HelpMessageOpt(\"-alertnotify=<cmd>\", helptr(\"Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)\"));\n    strUsage += HelpMessageOpt(\"-blocknotify=<cmd>\", helptr(\"Execute command when the best block changes (%s in cmd is replaced by block hash)\"));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-blocksonly\", strprintf(helptr(\"Whether to operate in a blocks only mode (default: %u)\"), DEFAULT_BLOCKSONLY));\n    strUsage +=HelpMessageOpt(\"-assumevalid=<hex>\", strprintf(helptr(\"If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)\"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()));\n    strUsage += HelpMessageOpt(\"-fullsync\", strprintf(_(\"Synchronize the whole chain for full validation mode. If used with SPV the sync will start when SPV if catched up. If disabled, blocks will not be requested automatically (default: %u)\"), DEFAULT_FULL_SYNC_MODE));\n    strUsage += HelpMessageOpt(\"-conf=<file>\", strprintf(helptr(\"Specify configuration file (default: %s)\"), DEFAULT_CONF_FILENAME));\n    if (mode == HMM_DAEMON)\n    {\n#if HAVE_DECL_FORK\n        strUsage += HelpMessageOpt(\"-daemon\", helptr(\"Run in the background as a daemon and accept commands\"));\n#endif\n    }\n    strUsage += HelpMessageOpt(\"-datadir=<dir>\", helptr(\"Specify data directory\"));\n    strUsage += HelpMessageOpt(\"-dbcache=<n>\", strprintf(helptr(\"Set database cache size in megabytes (%d to %d, default: %d)\"), nMinDbCache, nMaxDbCache, nDefaultDbCache));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-feefilter\", strprintf(\"Tell other nodes to filter invs to us by our mempool min fee (default: %u)\", DEFAULT_FEEFILTER));\n    strUsage += HelpMessageOpt(\"-loadblock=<file>\", helptr(\"Imports blocks from external blk000??.dat file on startup\"));\n    strUsage += HelpMessageOpt(\"-maxorphantx=<n>\", strprintf(helptr(\"Keep at most <n> unconnectable transactions in memory (default: %u)\"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));\n    strUsage += HelpMessageOpt(\"-maxmempool=<n>\", strprintf(helptr(\"Keep the transaction memory pool below <n> megabytes (default: %u)\"), DEFAULT_MAX_MEMPOOL_SIZE));\n    strUsage += HelpMessageOpt(\"-mempoolexpiry=<n>\", strprintf(helptr(\"Do not keep transactions in the mempool longer than <n> hours (default: %u)\"), DEFAULT_MEMPOOL_EXPIRY));\n    strUsage += HelpMessageOpt(\"-persistmempool\", strprintf(helptr(\"Whether to save the mempool on shutdown and load on restart (default: %u)\"), DEFAULT_PERSIST_MEMPOOL));\n    strUsage += HelpMessageOpt(\"-blockreconstructionextratxn=<n>\", strprintf(helptr(\"Extra transactions to keep in memory for compact block reconstructions (default: %u)\"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));\n    strUsage += HelpMessageOpt(\"-par=<n>\", strprintf(helptr(\"Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)\"),\n        -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));\n#ifndef WIN32\n    strUsage += HelpMessageOpt(\"-pid=<file>\", strprintf(helptr(\"Specify pid file (default: %s)\"), DEFAULT_PID_FILENAME));\n#endif\n    strUsage += HelpMessageOpt(\"-prune=<n>\", strprintf(helptr(\"Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. \"\n            \"Warning: Reverting this setting requires re-downloading the entire blockchain. \"\n            \"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)\"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));\n    strUsage += HelpMessageOpt(\"-reindex-chainstate\", helptr(\"Rebuild chain state from the currently indexed blocks\"));\n    strUsage += HelpMessageOpt(\"-reindex\", helptr(\"Rebuild chain state and block index from the blk*.dat files on disk\"));\n    strUsage += HelpMessageOpt(\"-resyncforblockindexupgrade\", helptr(\"In the event that the system requires an expensive block index upgrade, the system will bypass the upgrade in favour of simply doing a complete resync. This might be favourable for unattended devices like pis.\"));\n#ifndef WIN32\n    strUsage += HelpMessageOpt(\"-sysperms\", helptr(\"Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)\"));\n#endif\n    strUsage += HelpMessageOpt(\"-txindex\", strprintf(helptr(\"Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)\"), DEFAULT_TXINDEX));\n\n    strUsage += HelpMessageGroup(helptr(\"Connection options:\"));\n    strUsage += HelpMessageOpt(\"-addnode=<ip>\", helptr(\"Add a node to connect to and attempt to keep the connection open\"));\n    strUsage += HelpMessageOpt(\"-banscore=<n>\", strprintf(helptr(\"Threshold for disconnecting misbehaving peers (default: %u)\"), DEFAULT_BANSCORE_THRESHOLD));\n    strUsage += HelpMessageOpt(\"-bantime=<n>\", strprintf(helptr(\"Number of seconds to keep misbehaving peers from reconnecting (default: %u)\"), DEFAULT_MISBEHAVING_BANTIME));\n    strUsage += HelpMessageOpt(\"-bind=<addr>\", helptr(\"Bind to given address and always listen on it. Use [host]:port notation for IPv6\"));\n    strUsage += HelpMessageOpt(\"-connect=<ip>\", helptr(\"Connect only to the specified node(s); -connect=0 disables automatic connections\"));\n    strUsage += HelpMessageOpt(\"-discover\", helptr(\"Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)\"));\n    strUsage += HelpMessageOpt(\"-dns\", helptr(\"Allow DNS lookups for -addnode, -seednode and -connect\") + \" \" + strprintf(helptr(\"(default: %u)\"), DEFAULT_NAME_LOOKUP));\n    strUsage += HelpMessageOpt(\"-dnsseed\", helptr(\"Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)\"));\n    strUsage += HelpMessageOpt(\"-externalip=<ip>\", helptr(\"Specify your own public address\"));\n    strUsage += HelpMessageOpt(\"-forcednsseed\", strprintf(helptr(\"Always query for peer addresses via DNS lookup (default: %u)\"), DEFAULT_FORCEDNSSEED));\n    strUsage += HelpMessageOpt(\"-listen\", helptr(\"Accept connections from outside (default: 1 if no -proxy or -connect)\"));\n    strUsage += HelpMessageOpt(\"-listenonion\", strprintf(helptr(\"Automatically create Tor hidden service (default: %d)\"), DEFAULT_LISTEN_ONION));\n    strUsage += HelpMessageOpt(\"-maxconnections=<n>\", strprintf(helptr(\"Maintain at most <n> connections to peers (default: %u)\"), DEFAULT_MAX_PEER_CONNECTIONS));\n    strUsage += HelpMessageOpt(\"-maxreceivebuffer=<n>\", strprintf(helptr(\"Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)\"), DEFAULT_MAXRECEIVEBUFFER));\n    strUsage += HelpMessageOpt(\"-maxsendbuffer=<n>\", strprintf(helptr(\"Maximum per-connection send buffer, <n>*1000 bytes (default: %u)\"), DEFAULT_MAXSENDBUFFER));\n    strUsage += HelpMessageOpt(\"-maxtimeadjustment\", strprintf(helptr(\"Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)\"), DEFAULT_MAX_TIME_ADJUSTMENT));\n    strUsage += HelpMessageOpt(\"-onion=<ip:port>\", strprintf(helptr(\"Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)\"), \"-proxy\"));\n    strUsage += HelpMessageOpt(\"-onlynet=<net>\", helptr(\"Only connect to nodes in network <net> (ipv4, ipv6 or onion)\"));\n    strUsage += HelpMessageOpt(\"-permitbaremultisig\", strprintf(helptr(\"Relay non-P2SH multisig (default: %u)\"), DEFAULT_PERMIT_BAREMULTISIG));\n    strUsage += HelpMessageOpt(\"-peerbloomfilters\", strprintf(helptr(\"Support filtering of blocks and transaction with bloom filters (default: %u)\"), DEFAULT_PEERBLOOMFILTERS));\n    strUsage += HelpMessageOpt(\"-port=<port>\", strprintf(helptr(\"Listen for connections on <port> (default: %u or testnet: %u)\"), defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()));\n    strUsage += HelpMessageOpt(\"-proxy=<ip:port>\", helptr(\"Connect through SOCKS5 proxy\"));\n    strUsage += HelpMessageOpt(\"-proxyrandomize\", strprintf(helptr(\"Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)\"), DEFAULT_PROXYRANDOMIZE));\n    strUsage += HelpMessageOpt(\"-seednode=<ip>\", helptr(\"Connect to a node to retrieve peer addresses, and disconnect\"));\n    strUsage += HelpMessageOpt(\"-timeout=<n>\", strprintf(helptr(\"Specify connection timeout in milliseconds (minimum: 1, default: %d)\"), DEFAULT_CONNECT_TIMEOUT));\n    strUsage += HelpMessageOpt(\"-torcontrol=<ip>:<port>\", strprintf(helptr(\"Tor control port to use if onion listening enabled (default: %s)\"), DEFAULT_TOR_CONTROL));\n    strUsage += HelpMessageOpt(\"-torpassword=<pass>\", helptr(\"Tor control port password (default: empty)\"));\n#ifdef USE_UPNP\n#if USE_UPNP\n    strUsage += HelpMessageOpt(\"-upnp\", helptr(\"Use UPnP to map the listening port (default: 1 when listening and no -proxy)\"));\n#else\n    strUsage += HelpMessageOpt(\"-upnp\", strprintf(helptr(\"Use UPnP to map the listening port (default: %u)\"), 0));\n#endif\n#endif\n    strUsage += HelpMessageOpt(\"-whitebind=<addr>\", helptr(\"Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6\"));\n    strUsage += HelpMessageOpt(\"-whitelist=<IP address or network>\", helptr(\"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.\") +\n        \" \" + helptr(\"Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway\"));\n    strUsage += HelpMessageOpt(\"-maxuploadtarget=<n>\", strprintf(helptr(\"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)\"), DEFAULT_MAX_UPLOAD_TARGET));\n\n#ifdef ENABLE_WALLET\n    strUsage += CWallet::GetWalletHelpString(showDebug);\n#endif\n    strUsage += HelpMessageOpt(\"-mininput=<amt>\", helptr(\"When creating transactions, ignore inputs with value less than this (default: 0.0001)\"));\n\n#if ENABLE_ZMQ\n    strUsage += HelpMessageGroup(helptr(\"ZeroMQ notification options:\"));\n    strUsage += HelpMessageOpt(\"-zmqpubhashblock=<address>\", helptr(\"Enable publish hash block in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubhashtx=<address>\", helptr(\"Enable publish hash transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubrawblock=<address>\", helptr(\"Enable publish raw block in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubrawtx=<address>\", helptr(\"Enable publish raw transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubwallettx=<address>\", helptr(\"Enable publish wallet transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubstalledwitness=<address>\", helptr(\"Enable publish of slow witnesses in <address>\"));\n#endif\n\n    strUsage += HelpMessageGroup(helptr(\"Debugging/Testing options:\"));\n    strUsage += HelpMessageOpt(\"-uacomment=<cmt>\", helptr(\"Append comment to the user agent string\"));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-checkblocks=<n>\", strprintf(helptr(\"How many blocks to check at startup (default: %u, 0 = all)\"), DEFAULT_CHECKBLOCKS));\n        strUsage += HelpMessageOpt(\"-checklevel=<n>\", strprintf(helptr(\"How thorough the block verification of -checkblocks is (0-4, default: %u)\"), DEFAULT_CHECKLEVEL));\n        strUsage += HelpMessageOpt(\"-checkblockindex\", strprintf(\"Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)\", defaultChainParams->DefaultConsistencyChecks()));\n        strUsage += HelpMessageOpt(\"-checkmempool=<n>\", strprintf(\"Run checks every <n> transactions (default: %u)\", defaultChainParams->DefaultConsistencyChecks()));\n        strUsage += HelpMessageOpt(\"-checkpoints\", strprintf(\"Disable expensive verification for known chain history (default: %u)\", DEFAULT_CHECKPOINTS_ENABLED));\n        strUsage += HelpMessageOpt(\"-disablesafemode\", strprintf(\"Disable safemode, override a real safe mode event (default: %u)\", DEFAULT_DISABLE_SAFEMODE));\n        strUsage += HelpMessageOpt(\"-testsafemode\", strprintf(\"Force safe mode (default: %u)\", DEFAULT_TESTSAFEMODE));\n        strUsage += HelpMessageOpt(\"-dropmessagestest=<n>\", \"Randomly drop 1 of every <n> network messages\");\n        strUsage += HelpMessageOpt(\"-fuzzmessagestest=<n>\", \"Randomly fuzz 1 of every <n> network messages\");\n        strUsage += HelpMessageOpt(\"-stopafterblockimport\", strprintf(\"Stop running after importing blocks from disk (default: %u)\", DEFAULT_STOPAFTERBLOCKIMPORT));\n        strUsage += HelpMessageOpt(\"-stopatheight\", strprintf(\"Stop running after reaching the given height in the main chain (default: %u)\", DEFAULT_STOPATHEIGHT));\n\n        strUsage += HelpMessageOpt(\"-limitancestorcount=<n>\", strprintf(\"Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)\", DEFAULT_ANCESTOR_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitancestorsize=<n>\", strprintf(\"Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)\", DEFAULT_ANCESTOR_SIZE_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitdescendantcount=<n>\", strprintf(\"Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)\", DEFAULT_DESCENDANT_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitdescendantsize=<n>\", strprintf(\"Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).\", DEFAULT_DESCENDANT_SIZE_LIMIT));\n        strUsage += HelpMessageOpt(\"-vbparams=deployment:start:end\", \"Use given start/end times for specified version bits deployment (regtest-only)\");\n    }\n    strUsage += HelpMessageOpt(\"-debug=<category>\", strprintf(helptr(\"Output debugging information (default: %u, supplying <category> is optional)\"), 0) + \". \" +\n        helptr(\"If <category> is not supplied or if <category> = 1, output all debugging information.\") + \" \" + helptr(\"<category> can be:\") + \" \" + ListLogCategories() + \".\");\n    strUsage += HelpMessageOpt(\"-debugexclude=<category>\", strprintf(helptr(\"Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.\")));\n    strUsage += HelpMessageOpt(\"-gen\", strprintf(helptr(\"Generate coins (default: %u)\"), DEFAULT_GENERATE));\n    strUsage += HelpMessageOpt(\"-genproclimit=<n>\", strprintf(helptr(\"Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)\"), DEFAULT_GENERATE_THREADS));\n    strUsage += HelpMessageOpt(\"-genarenaproclimit=<n>\", strprintf(helptr(\"Set the number of threads for arena setup potrion of coin generation if enabled (-1 = all cores, default: %d)\"), DEFAULT_GENERATE_THREADS));\n    strUsage += HelpMessageOpt(\"-help-debug\", helptr(\"Show all debugging options (usage: --help -help-debug)\"));\n    strUsage += HelpMessageOpt(\"-logips\", strprintf(helptr(\"Include IP addresses in debug output (default: %u)\"), DEFAULT_LOGIPS));\n    strUsage += HelpMessageOpt(\"-logtimestamps\", strprintf(helptr(\"Prepend debug output with timestamp (default: %u)\"), DEFAULT_LOGTIMESTAMPS));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-logtimemicros\", strprintf(\"Add microsecond precision to debug timestamps (default: %u)\", DEFAULT_LOGTIMEMICROS));\n        strUsage += HelpMessageOpt(\"-mocktime=<n>\", \"Replace actual time with <n> seconds since epoch (default: 0)\");\n        strUsage += HelpMessageOpt(\"-maxsigcachesize=<n>\", strprintf(\"Limit size of signature cache to <n> MiB (default: %u)\", DEFAULT_MAX_SIG_CACHE_SIZE));\n        strUsage += HelpMessageOpt(\"-maxtipage=<n>\", strprintf(\"Maximum tip age in seconds to consider node in initial block download (default: %u)\", DEFAULT_MAX_TIP_AGE));\n    }\n    strUsage += HelpMessageOpt(\"-maxtxfee=<amt>\", strprintf(helptr(\"Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)\"),\n        CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)));\n    strUsage += HelpMessageOpt(\"-printtoconsole\", helptr(\"Send trace/debug info to console instead of debug.log file\"));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-printpriority\", strprintf(\"Log transaction fee per kB when mining blocks (default: %u)\", DEFAULT_PRINTPRIORITY));\n    }\n    strUsage += HelpMessageOpt(\"-shrinkdebugfile\", helptr(\"Shrink debug.log file on client startup (default: 1 when no -debug)\"));\n\n    AppendParamsHelpMessages(strUsage, showDebug);\n\n    strUsage += HelpMessageGroup(helptr(\"Node relay options:\"));\n    if (showDebug) {\n        strUsage += HelpMessageOpt(\"-acceptnonstdtxn\", strprintf(\"Relay and mine \\\"non-standard\\\" transactions (%sdefault: %u)\", \"testnet/regtest only; \", defaultChainParams->RequireStandard()));\n        strUsage += HelpMessageOpt(\"-incrementalrelayfee=<amt>\", strprintf(\"Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)\", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));\n        strUsage += HelpMessageOpt(\"-dustrelayfee=<amt>\", strprintf(\"Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)\", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));\n    }\n    strUsage += HelpMessageOpt(\"-bytespersigop\", strprintf(helptr(\"Equivalent bytes per sigop in transactions for relay and mining (default: %u)\"), DEFAULT_BYTES_PER_SIGOP));\n    strUsage += HelpMessageOpt(\"-datacarrier\", strprintf(helptr(\"Relay and mine data carrier transactions (default: %u)\"), DEFAULT_ACCEPT_DATACARRIER));\n    strUsage += HelpMessageOpt(\"-datacarriersize\", strprintf(helptr(\"Maximum size of data in data carrier transactions we relay and mine (default: %u)\"), MAX_OP_RETURN_RELAY));\n    strUsage += HelpMessageOpt(\"-mempoolreplacement\", strprintf(helptr(\"Enable transaction replacement in the memory pool (default: %u)\"), DEFAULT_ENABLE_REPLACEMENT));\n    strUsage += HelpMessageOpt(\"-minrelaytxfee=<amt>\", strprintf(helptr(\"Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)\"),\n        CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));\n    strUsage += HelpMessageOpt(\"-whitelistrelay\", strprintf(helptr(\"Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)\"), DEFAULT_WHITELISTRELAY));\n    strUsage += HelpMessageOpt(\"-whitelistforcerelay\", strprintf(helptr(\"Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)\"), DEFAULT_WHITELISTFORCERELAY));\n\n    strUsage += HelpMessageGroup(helptr(\"Block generation options:\"));\n    strUsage += HelpMessageOpt(\"-blockmaxweight=<n>\", strprintf(helptr(\"Set maximum BIP141 block weight (default: %d)\"), DEFAULT_BLOCK_MAX_WEIGHT));\n    strUsage += HelpMessageOpt(\"-blockmaxsize=<n>\", strprintf(helptr(\"Set maximum block size in bytes (default: %d)\"), DEFAULT_BLOCK_MAX_SIZE));\n    strUsage += HelpMessageOpt(\"-blockmintxfee=<amt>\", strprintf(helptr(\"Set lowest fee rate (in %s/kB) for transactions to be included in block generation. (default: %s)\"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-blockversion=<n>\", \"Override block version to test forking scenarios\");\n\n    strUsage += HelpMessageGroup(helptr(\"RPC server options:\"));\n    strUsage += HelpMessageOpt(\"-server\", helptr(\"Accept command line and JSON-RPC commands\"));\n    strUsage += HelpMessageOpt(\"-rest\", strprintf(helptr(\"Accept public REST requests (default: %u)\"), DEFAULT_REST_ENABLE));\n    strUsage += HelpMessageOpt(\"-rpcbind=<addr>[:port]\", helptr(\"Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)\"));\n    strUsage += HelpMessageOpt(\"-rpccookiefile=<loc>\", helptr(\"Location of the auth cookie (default: data dir)\"));\n    strUsage += HelpMessageOpt(\"-rpcuser=<user>\", helptr(\"Username for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcpassword=<pw>\", helptr(\"Password for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcauth=<userpw>\", helptr(\"Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times\"));\n    strUsage += HelpMessageOpt(\"-rpcport=<port>\", strprintf(helptr(\"Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)\"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));\n    strUsage += HelpMessageOpt(\"-rpcallowip=<ip>\", helptr(\"Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times\"));\n    strUsage += HelpMessageOpt(\"-rpcthreads=<n>\", strprintf(helptr(\"Set the number of threads to service RPC calls (default: %d)\"), DEFAULT_HTTP_THREADS));\n\n    strUsage += HelpMessageGroup(helptr(\"Developer options:\"));\n    strUsage += HelpMessageOpt(\"-genkeypair\", helptr(\"Generate a random public/private keypair for use with alert system and other similar functionality.\"));\n    strUsage += HelpMessageOpt(\"-setwindowtitle\", helptr(\"Change the window title name, useful for distinguishing multiple program instances during testing.\"));\n    strUsage += HelpMessageOpt(\"-coinbasesignature\", helptr(\"Insert value into coinbase of generated blocks, useful during testing.\"));\n    strUsage += HelpMessageOpt(\"-accountpool\", helptr(\"Use to increase the default account pool look ahead size. (Needed in some cases to find accounts on rescan when large account gaps are present)\"));\n    //fixme: (UNITY) (SPV) decide if we want to keep this option\n    strUsage += HelpMessageOpt(\"-phrase=<phrase>\", _(\"When creating a new wallet use this phrase. Useful for repeatedly starting fresh with the same seed when testing SPV\"));\n\n    if (showDebug) {\n        strUsage += HelpMessageOpt(\"-rpcworkqueue=<n>\", strprintf(\"Set the depth of the work queue to service RPC calls (default: %d)\", DEFAULT_HTTP_WORKQUEUE));\n        strUsage += HelpMessageOpt(\"-rpcservertimeout=<n>\", strprintf(\"Timeout during HTTP requests (default: %d)\", DEFAULT_HTTP_SERVER_TIMEOUT));\n    }\n\n    return strUsage;\n}\n\nvoid InitRegisterRPC()\n{\n}\n\nvoid ServerInterrupt()\n{\n}\n\nvoid ServerShutdown(node::NodeContext& nodeContext)\n{\n}\n\nbool InitRPCWarmup()\n{\n    return true;\n}\n\nbool InitTor()\n{\n    return true;\n}\n\n\n"
  },
  {
    "path": "src/unity/generic/init_generic_node.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"init.h\"\n#include \"chainparams.h\"\n#include \"chain.h\"\n#include \"generation/miner.h\"\n#include \"httprpc.h\"\n#include \"httpserver.h\"\n#include \"net.h\"\n#include \"net_processing.h\"\n#include \"policy/policy.h\"\n#include \"rpc/blockchain.h\"\n#include \"rpc/register.h\"\n#include \"rpc/server.h\"\n#include \"script/sigcache.h\"\n#include \"torcontrol.h\"\n#include \"txdb.h\"\n#include \"ui_interface.h\"\n#include \"util.h\"\n#include \"util/moneystr.h\"\n#include \"validation/validation.h\"\n#include \"node/context.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n#include \"warnings.h\"\n\n\n#include <boost/thread.hpp>\n\n//If we want to translate help messages in future we can replace helptr with _ and everything will just work.\n#define helptr(x) std::string(x)\n//If we want to translate error messages in future we can replace helptr with _ and everything will just work.\n#define errortr(x) std::string(x)\n\n\nstd::string HelpMessage(HelpMessageMode mode)\n{\n    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);\n    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);\n    const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);\n    const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);\n    const bool showDebug = GetBoolArg(\"-help-debug\", false);\n\n    // When adding new options to the categories, please keep and ensure alphabetical ordering.\n    // Do not translate helptr(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.\n    std::string strUsage = HelpMessageGroup(helptr(\"Options:\"));\n    strUsage += HelpMessageOpt(\"-?\", helptr(\"Print this help message and exit\"));\n    strUsage += HelpMessageOpt(\"-version\", helptr(\"Print version and exit\"));\n    strUsage += HelpMessageOpt(\"-alerts\", strprintf(helptr(\"Receive and display P2P network alerts (default: %u)\"), DEFAULT_ALERTS));\n    strUsage += HelpMessageOpt(\"-alertnotify=<cmd>\", helptr(\"Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)\"));\n    strUsage += HelpMessageOpt(\"-blocknotify=<cmd>\", helptr(\"Execute command when the best block changes (%s in cmd is replaced by block hash)\"));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-blocksonly\", strprintf(helptr(\"Whether to operate in a blocks only mode (default: %u)\"), DEFAULT_BLOCKSONLY));\n    strUsage +=HelpMessageOpt(\"-assumevalid=<hex>\", strprintf(helptr(\"If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)\"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()));\n    strUsage += HelpMessageOpt(\"-fullsync\", strprintf(_(\"Synchronize the whole chain for full validation mode. If used with SPV the sync will start when SPV if catched up. If disabled, blocks will not be requested automatically (default: %u)\"), DEFAULT_FULL_SYNC_MODE));\n    strUsage += HelpMessageOpt(\"-conf=<file>\", strprintf(helptr(\"Specify configuration file (default: %s)\"), DEFAULT_CONF_FILENAME));\n    if (mode == HMM_DAEMON)\n    {\n#if HAVE_DECL_FORK\n        strUsage += HelpMessageOpt(\"-daemon\", helptr(\"Run in the background as a daemon and accept commands\"));\n#endif\n    }\n    strUsage += HelpMessageOpt(\"-datadir=<dir>\", helptr(\"Specify data directory\"));\n    strUsage += HelpMessageOpt(\"-dbcache=<n>\", strprintf(helptr(\"Set database cache size in megabytes (%d to %d, default: %d)\"), nMinDbCache, nMaxDbCache, nDefaultDbCache));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-feefilter\", strprintf(\"Tell other nodes to filter invs to us by our mempool min fee (default: %u)\", DEFAULT_FEEFILTER));\n    strUsage += HelpMessageOpt(\"-loadblock=<file>\", helptr(\"Imports blocks from external blk000??.dat file on startup\"));\n    strUsage += HelpMessageOpt(\"-maxorphantx=<n>\", strprintf(helptr(\"Keep at most <n> unconnectable transactions in memory (default: %u)\"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));\n    strUsage += HelpMessageOpt(\"-maxmempool=<n>\", strprintf(helptr(\"Keep the transaction memory pool below <n> megabytes (default: %u)\"), DEFAULT_MAX_MEMPOOL_SIZE));\n    strUsage += HelpMessageOpt(\"-mempoolexpiry=<n>\", strprintf(helptr(\"Do not keep transactions in the mempool longer than <n> hours (default: %u)\"), DEFAULT_MEMPOOL_EXPIRY));\n    strUsage += HelpMessageOpt(\"-persistmempool\", strprintf(helptr(\"Whether to save the mempool on shutdown and load on restart (default: %u)\"), DEFAULT_PERSIST_MEMPOOL));\n    strUsage += HelpMessageOpt(\"-blockreconstructionextratxn=<n>\", strprintf(helptr(\"Extra transactions to keep in memory for compact block reconstructions (default: %u)\"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));\n    strUsage += HelpMessageOpt(\"-par=<n>\", strprintf(helptr(\"Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)\"),\n        -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));\n#ifndef WIN32\n    strUsage += HelpMessageOpt(\"-pid=<file>\", strprintf(helptr(\"Specify pid file (default: %s)\"), DEFAULT_PID_FILENAME));\n#endif\n    strUsage += HelpMessageOpt(\"-prune=<n>\", strprintf(helptr(\"Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. \"\n            \"Warning: Reverting this setting requires re-downloading the entire blockchain. \"\n            \"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)\"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));\n    strUsage += HelpMessageOpt(\"-reindex-chainstate\", helptr(\"Rebuild chain state from the currently indexed blocks\"));\n    strUsage += HelpMessageOpt(\"-reindex\", helptr(\"Rebuild chain state and block index from the blk*.dat files on disk\"));\n    strUsage += HelpMessageOpt(\"-resyncforblockindexupgrade\", helptr(\"In the event that the system requires an expensive block index upgrade, the system will bypass the upgrade in favour of simply doing a complete resync. This might be favourable for unattended devices like pis.\"));\n#ifndef WIN32\n    strUsage += HelpMessageOpt(\"-sysperms\", helptr(\"Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)\"));\n#endif\n    strUsage += HelpMessageOpt(\"-txindex\", strprintf(helptr(\"Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)\"), DEFAULT_TXINDEX));\n\n    strUsage += HelpMessageGroup(helptr(\"Connection options:\"));\n    strUsage += HelpMessageOpt(\"-addnode=<ip>\", helptr(\"Add a node to connect to and attempt to keep the connection open\"));\n    strUsage += HelpMessageOpt(\"-banscore=<n>\", strprintf(helptr(\"Threshold for disconnecting misbehaving peers (default: %u)\"), DEFAULT_BANSCORE_THRESHOLD));\n    strUsage += HelpMessageOpt(\"-bantime=<n>\", strprintf(helptr(\"Number of seconds to keep misbehaving peers from reconnecting (default: %u)\"), DEFAULT_MISBEHAVING_BANTIME));\n    strUsage += HelpMessageOpt(\"-bind=<addr>\", helptr(\"Bind to given address and always listen on it. Use [host]:port notation for IPv6\"));\n    strUsage += HelpMessageOpt(\"-connect=<ip>\", helptr(\"Connect only to the specified node(s); -connect=0 disables automatic connections\"));\n    strUsage += HelpMessageOpt(\"-discover\", helptr(\"Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)\"));\n    strUsage += HelpMessageOpt(\"-dns\", helptr(\"Allow DNS lookups for -addnode, -seednode and -connect\") + \" \" + strprintf(helptr(\"(default: %u)\"), DEFAULT_NAME_LOOKUP));\n    strUsage += HelpMessageOpt(\"-dnsseed\", helptr(\"Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)\"));\n    strUsage += HelpMessageOpt(\"-externalip=<ip>\", helptr(\"Specify your own public address\"));\n    strUsage += HelpMessageOpt(\"-forcednsseed\", strprintf(helptr(\"Always query for peer addresses via DNS lookup (default: %u)\"), DEFAULT_FORCEDNSSEED));\n    strUsage += HelpMessageOpt(\"-listen\", helptr(\"Accept connections from outside (default: 1 if no -proxy or -connect)\"));\n    strUsage += HelpMessageOpt(\"-listenonion\", strprintf(helptr(\"Automatically create Tor hidden service (default: %d)\"), DEFAULT_LISTEN_ONION));\n    strUsage += HelpMessageOpt(\"-maxconnections=<n>\", strprintf(helptr(\"Maintain at most <n> connections to peers (default: %u)\"), DEFAULT_MAX_PEER_CONNECTIONS));\n    strUsage += HelpMessageOpt(\"-maxreceivebuffer=<n>\", strprintf(helptr(\"Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)\"), DEFAULT_MAXRECEIVEBUFFER));\n    strUsage += HelpMessageOpt(\"-maxsendbuffer=<n>\", strprintf(helptr(\"Maximum per-connection send buffer, <n>*1000 bytes (default: %u)\"), DEFAULT_MAXSENDBUFFER));\n    strUsage += HelpMessageOpt(\"-maxtimeadjustment\", strprintf(helptr(\"Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)\"), DEFAULT_MAX_TIME_ADJUSTMENT));\n    strUsage += HelpMessageOpt(\"-onion=<ip:port>\", strprintf(helptr(\"Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)\"), \"-proxy\"));\n    strUsage += HelpMessageOpt(\"-onlynet=<net>\", helptr(\"Only connect to nodes in network <net> (ipv4, ipv6 or onion)\"));\n    strUsage += HelpMessageOpt(\"-permitbaremultisig\", strprintf(helptr(\"Relay non-P2SH multisig (default: %u)\"), DEFAULT_PERMIT_BAREMULTISIG));\n    strUsage += HelpMessageOpt(\"-peerbloomfilters\", strprintf(helptr(\"Support filtering of blocks and transaction with bloom filters (default: %u)\"), DEFAULT_PEERBLOOMFILTERS));\n    strUsage += HelpMessageOpt(\"-port=<port>\", strprintf(helptr(\"Listen for connections on <port> (default: %u or testnet: %u)\"), defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()));\n    strUsage += HelpMessageOpt(\"-proxy=<ip:port>\", helptr(\"Connect through SOCKS5 proxy\"));\n    strUsage += HelpMessageOpt(\"-proxyrandomize\", strprintf(helptr(\"Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)\"), DEFAULT_PROXYRANDOMIZE));\n    strUsage += HelpMessageOpt(\"-seednode=<ip>\", helptr(\"Connect to a node to retrieve peer addresses, and disconnect\"));\n    strUsage += HelpMessageOpt(\"-timeout=<n>\", strprintf(helptr(\"Specify connection timeout in milliseconds (minimum: 1, default: %d)\"), DEFAULT_CONNECT_TIMEOUT));\n    strUsage += HelpMessageOpt(\"-torcontrol=<ip>:<port>\", strprintf(helptr(\"Tor control port to use if onion listening enabled (default: %s)\"), DEFAULT_TOR_CONTROL));\n    strUsage += HelpMessageOpt(\"-torpassword=<pass>\", helptr(\"Tor control port password (default: empty)\"));\n#ifdef USE_UPNP\n#if USE_UPNP\n    strUsage += HelpMessageOpt(\"-upnp\", helptr(\"Use UPnP to map the listening port (default: 1 when listening and no -proxy)\"));\n#else\n    strUsage += HelpMessageOpt(\"-upnp\", strprintf(helptr(\"Use UPnP to map the listening port (default: %u)\"), 0));\n#endif\n#endif\n    strUsage += HelpMessageOpt(\"-whitebind=<addr>\", helptr(\"Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6\"));\n    strUsage += HelpMessageOpt(\"-whitelist=<IP address or network>\", helptr(\"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.\") +\n        \" \" + helptr(\"Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway\"));\n    strUsage += HelpMessageOpt(\"-maxuploadtarget=<n>\", strprintf(helptr(\"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)\"), DEFAULT_MAX_UPLOAD_TARGET));\n\n#ifdef ENABLE_WALLET\n    strUsage += CWallet::GetWalletHelpString(showDebug);\n#endif\n    strUsage += HelpMessageOpt(\"-mininput=<amt>\", helptr(\"When creating transactions, ignore inputs with value less than this (default: 0.0001)\"));\n\n#if ENABLE_ZMQ\n    strUsage += HelpMessageGroup(helptr(\"ZeroMQ notification options:\"));\n    strUsage += HelpMessageOpt(\"-zmqpubhashblock=<address>\", helptr(\"Enable publish hash block in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubhashtx=<address>\", helptr(\"Enable publish hash transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubrawblock=<address>\", helptr(\"Enable publish raw block in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubrawtx=<address>\", helptr(\"Enable publish raw transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubwallettx=<address>\", helptr(\"Enable publish wallet transaction in <address>\"));\n    strUsage += HelpMessageOpt(\"-zmqpubstalledwitness=<address>\", helptr(\"Enable publish of slow witnesses in <address>\"));\n#endif\n\n    strUsage += HelpMessageGroup(helptr(\"Debugging/Testing options:\"));\n    strUsage += HelpMessageOpt(\"-uacomment=<cmt>\", helptr(\"Append comment to the user agent string\"));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-checkblocks=<n>\", strprintf(helptr(\"How many blocks to check at startup (default: %u, 0 = all)\"), DEFAULT_CHECKBLOCKS));\n        strUsage += HelpMessageOpt(\"-checklevel=<n>\", strprintf(helptr(\"How thorough the block verification of -checkblocks is (0-4, default: %u)\"), DEFAULT_CHECKLEVEL));\n        strUsage += HelpMessageOpt(\"-checkblockindex\", strprintf(\"Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)\", defaultChainParams->DefaultConsistencyChecks()));\n        strUsage += HelpMessageOpt(\"-checkmempool=<n>\", strprintf(\"Run checks every <n> transactions (default: %u)\", defaultChainParams->DefaultConsistencyChecks()));\n        strUsage += HelpMessageOpt(\"-checkpoints\", strprintf(\"Disable expensive verification for known chain history (default: %u)\", DEFAULT_CHECKPOINTS_ENABLED));\n        strUsage += HelpMessageOpt(\"-disablesafemode\", strprintf(\"Disable safemode, override a real safe mode event (default: %u)\", DEFAULT_DISABLE_SAFEMODE));\n        strUsage += HelpMessageOpt(\"-testsafemode\", strprintf(\"Force safe mode (default: %u)\", DEFAULT_TESTSAFEMODE));\n        strUsage += HelpMessageOpt(\"-dropmessagestest=<n>\", \"Randomly drop 1 of every <n> network messages\");\n        strUsage += HelpMessageOpt(\"-fuzzmessagestest=<n>\", \"Randomly fuzz 1 of every <n> network messages\");\n        strUsage += HelpMessageOpt(\"-stopafterblockimport\", strprintf(\"Stop running after importing blocks from disk (default: %u)\", DEFAULT_STOPAFTERBLOCKIMPORT));\n        strUsage += HelpMessageOpt(\"-stopatheight\", strprintf(\"Stop running after reaching the given height in the main chain (default: %u)\", DEFAULT_STOPATHEIGHT));\n\n        strUsage += HelpMessageOpt(\"-limitancestorcount=<n>\", strprintf(\"Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)\", DEFAULT_ANCESTOR_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitancestorsize=<n>\", strprintf(\"Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)\", DEFAULT_ANCESTOR_SIZE_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitdescendantcount=<n>\", strprintf(\"Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)\", DEFAULT_DESCENDANT_LIMIT));\n        strUsage += HelpMessageOpt(\"-limitdescendantsize=<n>\", strprintf(\"Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).\", DEFAULT_DESCENDANT_SIZE_LIMIT));\n        strUsage += HelpMessageOpt(\"-vbparams=deployment:start:end\", \"Use given start/end times for specified version bits deployment (regtest-only)\");\n    }\n    strUsage += HelpMessageOpt(\"-debug=<category>\", strprintf(helptr(\"Output debugging information (default: %u, supplying <category> is optional)\"), 0) + \". \" +\n        helptr(\"If <category> is not supplied or if <category> = 1, output all debugging information.\") + \" \" + helptr(\"<category> can be:\") + \" \" + ListLogCategories() + \".\");\n    strUsage += HelpMessageOpt(\"-debugexclude=<category>\", strprintf(helptr(\"Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.\")));\n    strUsage += HelpMessageOpt(\"-gen\", strprintf(helptr(\"Generate coins (default: %u)\"), DEFAULT_GENERATE));\n    strUsage += HelpMessageOpt(\"-genproclimit=<n>\", strprintf(helptr(\"Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)\"), DEFAULT_GENERATE_THREADS));\n    strUsage += HelpMessageOpt(\"-genarenaproclimit=<n>\", strprintf(helptr(\"Set the number of threads for arena setup potrion of coin generation if enabled (-1 = all cores, default: %d)\"), DEFAULT_GENERATE_THREADS));\n    strUsage += HelpMessageOpt(\"-help-debug\", helptr(\"Show all debugging options (usage: --help -help-debug)\"));\n    strUsage += HelpMessageOpt(\"-logips\", strprintf(helptr(\"Include IP addresses in debug output (default: %u)\"), DEFAULT_LOGIPS));\n    strUsage += HelpMessageOpt(\"-logtimestamps\", strprintf(helptr(\"Prepend debug output with timestamp (default: %u)\"), DEFAULT_LOGTIMESTAMPS));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-logtimemicros\", strprintf(\"Add microsecond precision to debug timestamps (default: %u)\", DEFAULT_LOGTIMEMICROS));\n        strUsage += HelpMessageOpt(\"-mocktime=<n>\", \"Replace actual time with <n> seconds since epoch (default: 0)\");\n        strUsage += HelpMessageOpt(\"-maxsigcachesize=<n>\", strprintf(\"Limit size of signature cache to <n> MiB (default: %u)\", DEFAULT_MAX_SIG_CACHE_SIZE));\n        strUsage += HelpMessageOpt(\"-maxtipage=<n>\", strprintf(\"Maximum tip age in seconds to consider node in initial block download (default: %u)\", DEFAULT_MAX_TIP_AGE));\n    }\n    strUsage += HelpMessageOpt(\"-maxtxfee=<amt>\", strprintf(helptr(\"Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)\"),\n        CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)));\n    strUsage += HelpMessageOpt(\"-printtoconsole\", helptr(\"Send trace/debug info to console instead of debug.log file\"));\n    if (showDebug)\n    {\n        strUsage += HelpMessageOpt(\"-printpriority\", strprintf(\"Log transaction fee per kB when mining blocks (default: %u)\", DEFAULT_PRINTPRIORITY));\n    }\n    strUsage += HelpMessageOpt(\"-shrinkdebugfile\", helptr(\"Shrink debug.log file on client startup (default: 1 when no -debug)\"));\n\n    AppendParamsHelpMessages(strUsage, showDebug);\n\n    strUsage += HelpMessageGroup(helptr(\"Node relay options:\"));\n    if (showDebug) {\n        strUsage += HelpMessageOpt(\"-acceptnonstdtxn\", strprintf(\"Relay and mine \\\"non-standard\\\" transactions (%sdefault: %u)\", \"testnet/regtest only; \", defaultChainParams->RequireStandard()));\n        strUsage += HelpMessageOpt(\"-incrementalrelayfee=<amt>\", strprintf(\"Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)\", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));\n        strUsage += HelpMessageOpt(\"-dustrelayfee=<amt>\", strprintf(\"Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)\", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));\n    }\n    strUsage += HelpMessageOpt(\"-bytespersigop\", strprintf(helptr(\"Equivalent bytes per sigop in transactions for relay and mining (default: %u)\"), DEFAULT_BYTES_PER_SIGOP));\n    strUsage += HelpMessageOpt(\"-datacarrier\", strprintf(helptr(\"Relay and mine data carrier transactions (default: %u)\"), DEFAULT_ACCEPT_DATACARRIER));\n    strUsage += HelpMessageOpt(\"-datacarriersize\", strprintf(helptr(\"Maximum size of data in data carrier transactions we relay and mine (default: %u)\"), MAX_OP_RETURN_RELAY));\n    strUsage += HelpMessageOpt(\"-mempoolreplacement\", strprintf(helptr(\"Enable transaction replacement in the memory pool (default: %u)\"), DEFAULT_ENABLE_REPLACEMENT));\n    strUsage += HelpMessageOpt(\"-minrelaytxfee=<amt>\", strprintf(helptr(\"Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)\"),\n        CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));\n    strUsage += HelpMessageOpt(\"-whitelistrelay\", strprintf(helptr(\"Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)\"), DEFAULT_WHITELISTRELAY));\n    strUsage += HelpMessageOpt(\"-whitelistforcerelay\", strprintf(helptr(\"Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)\"), DEFAULT_WHITELISTFORCERELAY));\n\n    strUsage += HelpMessageGroup(helptr(\"Block generation options:\"));\n    strUsage += HelpMessageOpt(\"-blockmaxweight=<n>\", strprintf(helptr(\"Set maximum BIP141 block weight (default: %d)\"), DEFAULT_BLOCK_MAX_WEIGHT));\n    strUsage += HelpMessageOpt(\"-blockmaxsize=<n>\", strprintf(helptr(\"Set maximum block size in bytes (default: %d)\"), DEFAULT_BLOCK_MAX_SIZE));\n    strUsage += HelpMessageOpt(\"-blockmintxfee=<amt>\", strprintf(helptr(\"Set lowest fee rate (in %s/kB) for transactions to be included in block generation. (default: %s)\"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));\n    if (showDebug)\n        strUsage += HelpMessageOpt(\"-blockversion=<n>\", \"Override block version to test forking scenarios\");\n\n    strUsage += HelpMessageGroup(helptr(\"RPC server options:\"));\n    strUsage += HelpMessageOpt(\"-server\", helptr(\"Accept command line and JSON-RPC commands\"));\n    strUsage += HelpMessageOpt(\"-rest\", strprintf(helptr(\"Accept public REST requests (default: %u)\"), DEFAULT_REST_ENABLE));\n    strUsage += HelpMessageOpt(\"-rpcbind=<addr>[:port]\", helptr(\"Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)\"));\n    strUsage += HelpMessageOpt(\"-rpccookiefile=<loc>\", helptr(\"Location of the auth cookie (default: data dir)\"));\n    strUsage += HelpMessageOpt(\"-rpcuser=<user>\", helptr(\"Username for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcpassword=<pw>\", helptr(\"Password for JSON-RPC connections\"));\n    strUsage += HelpMessageOpt(\"-rpcauth=<userpw>\", helptr(\"Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times\"));\n    strUsage += HelpMessageOpt(\"-rpcport=<port>\", strprintf(helptr(\"Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)\"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));\n    strUsage += HelpMessageOpt(\"-rpcallowip=<ip>\", helptr(\"Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times\"));\n    strUsage += HelpMessageOpt(\"-rpcthreads=<n>\", strprintf(helptr(\"Set the number of threads to service RPC calls (default: %d)\"), DEFAULT_HTTP_THREADS));\n\n    strUsage += HelpMessageGroup(helptr(\"Developer options:\"));\n    strUsage += HelpMessageOpt(\"-genkeypair\", helptr(\"Generate a random public/private keypair for use with alert system and other similar functionality.\"));\n    strUsage += HelpMessageOpt(\"-setwindowtitle\", helptr(\"Change the window title name, useful for distinguishing multiple program instances during testing.\"));\n    strUsage += HelpMessageOpt(\"-coinbasesignature\", helptr(\"Insert value into coinbase of generated blocks, useful during testing.\"));\n    strUsage += HelpMessageOpt(\"-accountpool\", helptr(\"Use to increase the default account pool look ahead size. (Needed in some cases to find accounts on rescan when large account gaps are present)\"));\n    //fixme: (UNITY) (SPV) decide if we want to keep this option\n    strUsage += HelpMessageOpt(\"-phrase=<phrase>\", _(\"When creating a new wallet use this phrase. Useful for repeatedly starting fresh with the same seed when testing SPV\"));\n\n    if (showDebug) {\n        strUsage += HelpMessageOpt(\"-rpcworkqueue=<n>\", strprintf(\"Set the depth of the work queue to service RPC calls (default: %d)\", DEFAULT_HTTP_WORKQUEUE));\n        strUsage += HelpMessageOpt(\"-rpcservertimeout=<n>\", strprintf(\"Timeout during HTTP requests (default: %d)\", DEFAULT_HTTP_SERVER_TIMEOUT));\n    }\n\n    return strUsage;\n}\n\nvoid InitRegisterRPC()\n{\n    RegisterAllCoreRPCCommands(tableRPC);\n    #ifdef ENABLE_WALLET\n        RegisterWalletRPCCommands(tableRPC);\n    #endif\n}\n\nvoid ServerInterrupt()\n{\n    InterruptHTTPServer();\n    InterruptHTTPRPC();\n    InterruptRPC();\n    InterruptREST();\n    InterruptTorControl();\n}\n\nvoid ServerShutdown(node::NodeContext& nodeContext)\n{\n    StopHTTPServer();\n    StopHTTPRPC();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    StopRPC();\n    StopREST();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    StopTorControl();\n    // After everything has been shut down, but before things get flushed, stop the\n    // CScheduler/checkqueue, scheduler and load block thread.\n    if (nodeContext.scheduler) nodeContext.scheduler->stop();\n    StopScriptCheckWorkerThreads();\n}\n\nstatic void OnRPCStarted()\n{\n    uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);\n}\n\nstatic void OnRPCStopped()\n{\n    uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);\n    RPCNotifyBlockChange(false, nullptr);\n    cvBlockChange.notify_all();\n    LogPrint(BCLog::RPC, \"RPC stopped.\\n\");\n}\n\nstatic void OnRPCPreCommand(const CRPCCommand& cmd)\n{\n    // Observe safe mode\n    std::string strWarning = GetWarnings(\"rpc\");\n    if (strWarning != \"\" && !GetBoolArg(\"-disablesafemode\", DEFAULT_DISABLE_SAFEMODE) &&\n        !cmd.okSafeMode)\n        throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string(\"Safe mode: \") + strWarning);\n}\n\nstatic bool AppInitServers()\n{\n    RPCServer::OnStarted(&OnRPCStarted);\n    RPCServer::OnStopped(&OnRPCStopped);\n    RPCServer::OnPreCommand(&OnRPCPreCommand);\n    if (!InitHTTPServer())\n        return false;\n    if (!StartRPC())\n        return false;\n    if (!StartHTTPRPC())\n        return false;\n    if (GetBoolArg(\"-rest\", DEFAULT_REST_ENABLE) && !StartREST())\n        return false;\n    if (!StartHTTPServer())\n        return false;\n    return true;\n}\n\nbool InitRPCWarmup()\n{\n    if (GetBoolArg(\"-server\", false))\n    {\n        uiInterface.InitMessage.connect(SetRPCWarmupStatus);\n        if (!AppInitServers())\n            return InitError(errortr(\"Unable to start HTTP server. See debug log for details.\"));\n    }\n    return true;\n}\n\nbool InitTor()\n{\n    if (GetBoolArg(\"-listenonion\", DEFAULT_LISTEN_ONION))\n        StartTorControl();\n    return true;\n}\n\n\n"
  },
  {
    "path": "src/unity/generic/logging.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"util.h\"\n#include \"fs.h\"\n#include <boost/thread.hpp>\n\n/**\n * LogPrintf() has been broken a couple of times now\n * by well-meaning people adding mutexes in the most straightforward way.\n * It breaks because it may be called by global destructors during shutdown.\n * Since the order of destruction of static/global objects is undefined,\n * defining a mutex as a global object doesn't work (the mutex gets\n * destroyed, and then some later destructor calls OutputDebugStringF,\n * maybe indirectly, and you get a core dump at shutdown trying to lock\n * the mutex).\n */\n\nstatic boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;\n\n/**\n * We use boost::call_once() to make sure mutexDebugLog and\n * vMsgsBeforeOpenLog are initialized in a thread-safe manner.\n *\n * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog\n * are leaked on exit. This is ugly, but will be cleaned up by\n * the OS/libc. When the shutdown sequence is fully audited and\n * tested, explicit destruction of these objects can be implemented.\n */\nstatic FILE* fileout = NULL;\nstatic boost::mutex* mutexDebugLog = NULL;\nstatic std::list<std::string>* vMsgsBeforeOpenLog;\n\nstatic int FileWriteStr(const std::string &str, FILE *fp)\n{\n    return fwrite(str.data(), 1, str.size(), fp);\n}\n\nstatic void DebugPrintInit()\n{\n    assert(mutexDebugLog == NULL);\n    mutexDebugLog = new boost::mutex();\n    vMsgsBeforeOpenLog = new std::list<std::string>;\n}\n\nvoid OpenDebugLog()\n{\n    boost::call_once(&DebugPrintInit, debugPrintInitFlag);\n    boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);\n\n    assert(fileout == NULL);\n    assert(vMsgsBeforeOpenLog);\n    fs::path pathDebug = GetDataDir() / \"debug.log\";\n    fileout = fsbridge::fopen(pathDebug, \"a\");\n    if (fileout) {\n        setbuf(fileout, NULL); // unbuffered\n        // dump buffered messages from before we opened the log\n        while (!vMsgsBeforeOpenLog->empty()) {\n            FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);\n            vMsgsBeforeOpenLog->pop_front();\n        }\n    }\n\n    delete vMsgsBeforeOpenLog;\n    vMsgsBeforeOpenLog = NULL;\n}\n\n/**\n * fStartedNewLine is a state variable held by the calling context that will\n * suppress printing of the timestamp when multiple calls are made that don't\n * end in a newline. Initialize it to true, and hold it, in the calling context.\n */\nstatic std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)\n{\n    std::string strStamped;\n\n    if (!fLogTimestamps)\n        return str;\n\n    if (*fStartedNewLine) {\n        int64_t nTimeMicros = GetTimeMicros();\n        strStamped = FormatISO8601DateTime(nTimeMicros/1000000);\n        if (fLogTimeMicros) {\n            strStamped.pop_back();\n            strStamped += strprintf(\".%06dZ\", nTimeMicros%1000000);\n        }\n        std::chrono::seconds mocktime = GetMockTime();\n        if (mocktime > 0s) {\n            strStamped += \" (mocktime: \" + FormatISO8601DateTime(count_seconds(mocktime)) + \")\";\n        }\n        strStamped += ' ' + str;\n    } else\n        strStamped = str;\n\n    if (!str.empty() && str[str.size()-1] == '\\n')\n        *fStartedNewLine = true;\n    else\n        *fStartedNewLine = false;\n\n    return strStamped;\n}\n\nint LogPrintStr(const std::string &str)\n{\n    int ret = 0; // Returns total number of characters written\n    static std::atomic_bool fStartedNewLine(true);\n\n    std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);\n\n    if (fPrintToConsole)\n    {\n        // print to console\n        ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);\n        fflush(stdout);\n    }\n    else if (fPrintToDebugLog)\n    {\n        boost::call_once(&DebugPrintInit, debugPrintInitFlag);\n        boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);\n\n        // buffer if we haven't opened the log yet\n        if (fileout == NULL) {\n            assert(vMsgsBeforeOpenLog);\n            ret = strTimestamped.length();\n            vMsgsBeforeOpenLog->push_back(strTimestamped);\n        }\n        else\n        {\n            // reopen the log file, if requested\n            if (fReopenDebugLog) {\n                fReopenDebugLog = false;\n                fs::path pathDebug = GetDataDir() / \"debug.log\";\n                if (fsbridge::freopen(pathDebug,\"a\",fileout) != NULL)\n                    setbuf(fileout, NULL); // unbuffered\n            }\n\n            ret = FileWriteStr(strTimestamped, fileout);\n        }\n    }\n    return ret;\n}\n\nvoid UnityReportError(const std::string &str)\n{\n    //fixme: Implement\n}\n"
  },
  {
    "path": "src/unity/glob.py",
    "content": "#!/usr/bin/env python\n# a helper for gyp to do file globbing cross platform\n# Usage: python glob.py root_dir pattern [pattern...]\n\nfrom __future__ import print_function\n\nimport fnmatch\nimport os\nimport sys\n\nroot_dir = sys.argv[1]\npatterns = sys.argv[2:]\n\nfor (dirpath, dirnames, files) in os.walk(root_dir):\n    for f in files:\n        match = False\n        for pattern in patterns:\n            match = match or fnmatch.fnmatch(f, pattern)\n        if match:\n            print(os.path.join(dirpath, f))\n"
  },
  {
    "path": "src/unity/ios/init_ios.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include <boost/thread.hpp>\n#include \"chain.h\"\n#include \"init.h\"\n#include \"node/context.h\"\n\n\n#include \"unity/djinni/cpp/legacy_wallet_result.hpp\"\n#include \"unity/djinni/cpp/i_library_controller.hpp\"\n\nextern std::string HelpMessage(HelpMessageMode mode)\n{\n    return \"\";\n}\n\nvoid InitRegisterRPC()\n{\n}\n\nvoid ServerInterrupt()\n{\n}\n\nbool InitRPCWarmup()\n{\n    return true;\n}\n\nvoid SetRPCWarmupFinished()\n{\n}\n\nvoid RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)\n{\n}\n\nvoid ServerShutdown(node::NodeContext& nodeContext)\n{\n    // After everything has been shut down, but before things get flushed, stop the\n    // CScheduler/checkqueue, scheduler and load block thread.\n    if (nodeContext.scheduler) nodeContext.scheduler->stop();\n}\n\nvoid InitRPCMining()\n{\n}\n\nbool InitTor()\n{\n    return true;\n}\n\nbool ILibraryController::InitWalletFromAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword, const std::string& newPassword)\n{\n    // only exists here to keep the compiler happy, never call this on iOS\n    LogPrintf(\"DO NOT call ILibraryController::InitWalletFromAndroidLegacyProtoWallet on iOS\\n\");\n    assert(false);\n}\n\nLegacyWalletResult ILibraryController::isValidAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword)\n{\n    // only exists here to keep the compiler happy, never call this on iOS\n    LogPrintf(\"DO NOT call ILibraryController::isValidAndroidLegacyProtoWallet on iOS\\n\");\n    assert(false);\n    return LegacyWalletResult::INVALID_OR_CORRUPT;\n}\n"
  },
  {
    "path": "src/unity/ios/logging_ios.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <string>\n#include \"../unity_impl.h\"\n#include \"i_library_listener.hpp\"\n\nvoid OpenDebugLog()\n{\n}\n\nint LogPrintStr(const std::string &str)\n{\n    signalHandler->logPrint(str);\n    return str.size();\n}\n\nvoid UnityReportError(const std::string &str)\n{\n    if (signalHandler)\n    {\n        signalHandler->notifyError(str);\n    }\n}\n"
  },
  {
    "path": "src/unity/ios/munt_static/MuntCore/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "src/unity/libinit.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"libinit.h\"\n#include \"chainparams.h\"\n#include \"clientversion.h\"\n#include \"compat.h\"\n#include \"fs.h\"\n#include \"init.h\"\n#include \"scheduler.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n#include \"net.h\"\n#include \"util/thread.h\"\n#include \"wallet/wallet.h\"\n#include <unity/appmanager.h>\n\n#include <boost/thread.hpp>\n#include <boost/interprocess/sync/file_lock.hpp>\n\n\n#include <stdio.h>\n\n#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */\n\n\nbool shutDownFinalised = false;\n\nextern void terminateUnityFrontend();\nstatic void handleFinalShutdown()\n{\n    terminateUnityFrontend();\n    shutDownFinalised = true;\n}\n\nextern void handlePostInitMain();\nstatic void handleAppInitResult(bool bResult)\n{\n    if (!bResult)\n    {\n        // InitError will have been called with detailed error, which ends up on console\n        LogPrintf(\"shutdown: handleAppInitResult called with error, terminating app\");\n        AppLifecycleManager::gApp->shutdown();\n        return;\n    }\n    handlePostInitMain();\n}\n\nstatic bool handlePreInitMain()\n{\n    return true;\n}\n\n\n\nextern void handleInitWithExistingWallet();\nextern void handleInitWithoutExistingWallet();\nextern bool unityMessageBox(const std::string& message, const std::string& caption, unsigned int style);\n\nstatic bool unityThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)\n{\n    //fixme: (UNITY) (HIGH)\n    //Implement...\n    return false;\n}\n\n//fixme: See if we can remove this, looks like it may no longer be used.\nstatic void unityInitMessage(const std::string& message)\n{\n    LogPrintf(\"init message: %s\\n\", message);\n}\n\n#ifdef ENABLE_WALLET\nextern void NotifyRequestUnlockS(CWallet* wallet, std::string reason);\nextern void NotifyRequestUnlockWithCallbackS(CWallet* wallet, std::string reason, std::function<void (void)> successCallback);\n#endif\n\nvoid connectUIInterface()\n{\n    // Connect signal handlers\n    uiInterface.ThreadSafeMessageBox.connect(unityMessageBox);\n    uiInterface.ThreadSafeQuestion.connect(unityThreadSafeQuestion);\n    uiInterface.InitMessage.connect(unityInitMessage);\n\n    #ifdef ENABLE_WALLET\n    uiInterface.RequestUnlock.connect(boost::bind(NotifyRequestUnlockS,  boost::placeholders::_1,  boost::placeholders::_2));\n    uiInterface.RequestUnlockWithCallback.connect(boost::bind(NotifyRequestUnlockWithCallbackS,  boost::placeholders::_1,  boost::placeholders::_2,  boost::placeholders::_3));\n    #endif\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Start\n//\nint InitUnity()\n{\n    SetupEnvironment();\n\n    // Connect signal handlers\n    connectUIInterface();\n\n    AppLifecycleManager appManager; \n    appManager.signalAppInitializeResult.connect(boost::bind(handleAppInitResult, boost::placeholders::_1));\n    appManager.signalAboutToInitMain.connect(&handlePreInitMain);\n    appManager.signalAppShutdownFinished.connect(&handleFinalShutdown);\n\n    //NB! Must be set before AppInitMain.\n    fNoUI = true;\n\n    try\n    {\n        InitAppSpecificDatadirParamaters();\n        \n        if (!fs::is_directory(GetDataDir(false)))\n        {\n            fprintf(stderr, \"Error: Specified data directory \\\"%s\\\" does not exist.\\n\", GetArg(\"-datadir\", \"\").c_str());\n            return EXIT_FAILURE;\n        }\n        try\n        {\n            ReadConfigFile(GetArg(\"-conf\", DEFAULT_CONF_FILENAME));\n        }\n        catch (const std::exception& e)\n        {\n            fprintf(stderr,\"Error reading configuration file: %s\\n\", e.what());\n            return EXIT_FAILURE;\n        }\n        \n        InitAppSpecificConfigParamaters();\n\n        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)\n        try\n        {\n            SelectParams(ChainNameFromCommandLine());\n        }\n        catch (const std::exception& e)\n        {\n            fprintf(stderr, \"Error: %s\\n\", e.what());\n            return EXIT_FAILURE;\n        }\n\n        std::string walletFile = GetArg(\"-wallet\", DEFAULT_WALLET_DAT);\n        if (!fs::exists(GetDataDir() / walletFile))\n        {\n            //Temporary - migrate old 'Gulden' wallets to new 'Munt' wallets.\n            try\n            {\n                std::string newPathString = GetDataDir().string();\n                std::string oldPathString = newPathString;\n\n                boost::replace_all(oldPathString, \"Munt\", \"Gulden\");\n                boost::replace_all(oldPathString, \"munt\", \"Gulden\");\n                boost::filesystem::path oldPath(oldPathString);\n                if (fs::exists( (oldPath / walletFile).string() ))\n                {\n                    for(auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(oldPath), {}))\n                    {\n                        try { fs::rename((oldPath / entry.path().filename()).string(), (GetDataDir() / entry.path().filename()).string() ); } catch(...) {}\n                    }\n                    boost::filesystem::path newPath(newPathString); \n                    if (fs::exists(GetDataDir() / \"gulden.conf\"))\n                        fs::rename((GetDataDir() / \"gulden.conf\").string(), (GetDataDir() / \"munt.conf\").string());\n                    if (fs::exists(GetDataDir() / \"Gulden.conf\"))\n                        fs::rename((GetDataDir() / \"Gulden.conf\").string(), (GetDataDir() / \"munt.conf\").string());\n                }\n                else\n                {\n                    std::string newPathString = GetDataDir().string();\n                    std::string oldPathString = newPathString;\n                    boost::replace_all(oldPathString, \"Munt\", \"gulden\");\n                    boost::replace_all(oldPathString, \"munt\", \"gulden\");\n                    oldPath = boost::filesystem::path(boost::filesystem::path(oldPathString));\n                    if (fs::exists( (oldPath / walletFile).string() ))\n                    {\n                        for(auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(oldPath), {}))\n                        {\n       \t                    try { fs::rename((oldPath / entry.path().filename()).string(), (GetDataDir() / entry.path().filename()).string() ); } catch(...) {}\n                        }\n                        if (fs::exists(GetDataDir() / \"gulden.conf\"))\n\t                    fs::rename((GetDataDir() / \"gulden.conf\").string(), (GetDataDir() / \"munt.conf\").string());\n                        if (fs::exists(GetDataDir() / \"Gulden.conf\"))\n                            fs::rename((GetDataDir() / \"Gulden.conf\").string(), (GetDataDir() / \"munt.conf\").string());\n                    }\n                }\n            }\n            catch(...){}\n        }\n\n        // Set this early so that parameter interactions go to console\n        InitLogging();\n        InitParameterInteraction();\n\n        //fixme: (UNITY) - This is now duplicated, factor this out into a common helper.\n        // NB! This has to happen before we deamonise\n        // Make sure only a single Munt process is using the data directory.\n        {\n            fs::path pathLockFile = GetDataDir() / \".lock\";\n            FILE* file = fopen(pathLockFile.string().c_str(), \"a\"); // empty lock file; created if it doesn't exist.\n            if (file)\n                fclose(file);\n\n            try\n            {\n                static boost::interprocess::file_lock lock(pathLockFile.string().c_str());\n                if (!lock.try_lock())\n                {\n                    fprintf(stderr, \"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());\n                    AppLifecycleManager::gApp->shutdown();\n                    return EXIT_FAILURE;\n                }\n            }\n            catch(const boost::interprocess::interprocess_exception& e)\n            {\n                fprintf(stderr, \"ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.\", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());\n                AppLifecycleManager::gApp->shutdown();\n                return EXIT_FAILURE;\n            }\n        }\n\n        bool havePrimary = false;\n        if (fs::exists(GetDataDir() / walletFile))\n        {\n            CWalletDBWrapper dbw(&bitdb, walletFile);\n            CDB db(dbw);\n            std::string primaryUUID;\n            havePrimary = db.Read(std::string(\"primaryaccount\"), primaryUUID);\n            if (havePrimary)\n                fprintf(stderr, \"Existing wallet file has primary account %s\", primaryUUID.c_str());\n            else\n                fprintf(stderr, \"Wallet file exists but hase no primary account (erased)\");\n        }\n\n        if (havePrimary)\n        {\n            handleInitWithExistingWallet();\n        }\n        else\n        {\n            handleInitWithoutExistingWallet();\n        }\n    }\n    catch (const std::exception& e)\n    {\n        PrintExceptionContinue(&e, \"AppInit()\");\n    }\n    catch (...)\n    {\n        PrintExceptionContinue(NULL, \"AppInit()\");\n    }\n\n    AppLifecycleManager::gApp->waitForShutDown();\n\n    return EXIT_SUCCESS;\n}\n\n//fixme: (HIGH)\n//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.\n#ifdef MAC_OSX\n#include \"llvm-cpumodel-hack.cpp\"\n#endif\n"
  },
  {
    "path": "src/unity/libinit.h",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef UNITY_LIB_INIT_H\n#define UNITY_LIB_INIT_H\n\nint InitUnity();\n\n#endif\n"
  },
  {
    "path": "src/unity/libmunt_unity.gyp",
    "content": "{\n    \"targets\": [\n        {\n            \"target_name\": \"libmunt_unity_objc\",\n            \"type\": 'static_library',\n            \"dependencies\": [\n              \"../../djinni/djinni/support-lib/support_lib.gyp:djinni_objc\",\n            ],\n            \"sources\": [\n              \"<!@(python glob.py djinni/objc  '*.cpp' '*.mm' '*.m' '*.h' '*.hpp')\",\n              \"<!@(python glob.py djinni/cpp   '*.cpp' '*.hpp')\",\n              \"appmanager.h\",\n              \"libinit.h\",\n              \"signals.h\",\n              \"unity_impl.h\",\n              \"appmanager.cpp\",\n              \"libinit.cpp\",\n              \"unity_impl.cpp\",\n            ],\n            \"include_dirs\": [\n              \"djinni/objc\",\n            ],\n        },\n    ],\n}\n"
  },
  {
    "path": "src/unity/libunity.djinni",
    "content": "# Copyright (c) 2018-2022 The Centure developers\n# Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n# Distributed under the GNU Lesser General Public License v3, see the accompanying\n# file COPYING\n\nresult_record = record {\n    result : bool;\n    info : string;\n}\n\nqr_code_record = record {\n    width: i32;\n    pixel_data: binary;\n}\n\nbalance_record = record {\n    availableIncludingLocked: i64;\n    availableExcludingLocked: i64;\n    availableLocked: i64;\n    unconfirmedIncludingLocked: i64;\n    unconfirmedExcludingLocked: i64;\n    unconfirmedLocked: i64;\n    immatureIncludingLocked: i64;\n    immatureExcludingLocked: i64;\n    immatureLocked: i64;\n    totalLocked: i64;\n}\n\nuri_record = record {\n    scheme : string;\n    path : string;\n    items: map<string, string>;\n}\n\nuri_recipient = record {\n    valid : bool;\n    address : string;\n    label : string;\n    desc : string;\n    amount : i64;\n} deriving(parcelable)\n\nmutation_record = record {\n    change : i64;\n    timestamp : i64;\n    txHash : string;\n    # Address(es) of transaction recipient(s) (if transaction is sent by us then this excludes e.g. change and only has other wallets addresses)\n    recipient_addresses : string;\n    status : transaction_status;\n    depth : i32;\n}\n\ntransaction_record = record {\n    txHash: string;\n    timeStamp : i64;\n    amount : i64;\n    fee : i64;\n    status : transaction_status;\n    height : i32;\n    blockTime : i64;\n    depth : i32;\n    inputs : list<input_record>;\n    outputs : list<output_record>;\n} deriving(parcelable)\n\ntransaction_status = enum {\n    unconfirmed;\n    confirming;\n    confirmed;\n    abandoned;\n    conflicted;\n}\n\ninput_record = record {\n    address : string;\n    label : string;\n    desc : string;\n    isMine : bool;\n} deriving(parcelable)\n\noutput_record = record {\n    amount : i64;\n    address : string;\n    label : string;\n    desc : string;\n    isMine : bool;\n} deriving(parcelable)\n\naddress_record = record {\n    address : string;\n    name : string;\n    desc : string;\n    purpose : string;\n} deriving(parcelable)\n\npeer_record = record {\n    id : i64;\n    ip : string;\n    hostname : string;\n    addrLocal : string;\n    addrBind : string;\n    start_height : i64;\n    synced_height : i64;\n    common_height : i64;\n    time_connected : i64;\n    time_offset : i64;\n    latency : i64;\n    last_send : i64;\n    last_receive : i64;\n    send_bytes : i64;\n    receive_bytes : i64;\n    userAgent : string;\n    protocol : i64;\n    services : i64;\n    inbound : bool;\n    whitelisted : bool;\n    addnode : bool;\n    relay_txes : bool;\n    banscore : i64;\n} deriving(eq)\n\nbanned_peer_record = record {\n    address : string;\n    banned_until : i64;\n    banned_from : i64;\n    reason : string;\n}\n\nblock_info_record = record {\n    height : i32;\n    timeStamp : i64;\n    blockHash : string;\n}\n\nlegacy_wallet_result = enum {\n    unsupported_on_this_platform;\n    invalid_or_corrupt;\n    encrypted_password_required;\n    password_invalid;\n    valid;\n}\n\npayment_result_status = enum {\n    success;\n    insufficient_funds;\n}\n\nmnemonic_record = record {\n    phrase_with_birth_number : string;\n    phrase : string;\n    birth_number : i64;\n}\n\nwallet_lock_status = record {\n    locked : bool;\n    lock_timeout : i64;\n}\n\n# The library controller is used to Init/Terminate the library, and other similar tasks.\n# It is also home to various generic utility functions that don't (yet) have a place in more specific controllers\n# Specific functionality should go in specific controllers; account related functionality -> accounts_controller, network related functionality -> network_controller and so on\ni_library_controller = interface +c {\n\n    # Get the build information (ie. commit id and status)\n    static BuildInfo(): string;\n\n    # Start the library\n    # extraArgs - any additional commandline arguments as could normally be passed to the daemon binary\n    # NB!!! This call blocks until the library is terminated, it is the callers responsibility to place it inside a thread or similar.\n    # If you are in an environment where this is not possible (node.js for example use InitUnityLibThreaded instead which places it in a thread on your behalf)\n    static InitUnityLib(data_dir : string, staticFilterPath : string, staticFilterOffset : i64, staticFilterLength : i64,testnet : bool,spvMode : bool, signalHandler : i_library_listener, extraArgs : string): i32;\n    # Threaded implementation of InitUnityLib\n    static InitUnityLibThreaded(data_dir : string, staticFilterPath : string, staticFilterOffset : i64, staticFilterLength : i64,testnet : bool,spvMode : bool, signalHandler : i_library_listener, extraArgs : string);\n\n    # Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib\n    static InitWalletFromRecoveryPhrase(phrase : string, password : string): bool;\n\n    # Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts\n    static ContinueWalletFromRecoveryPhrase(phrase : string, password : string): bool;\n\n    # Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib\n    static InitWalletLinkedFromURI(linked_uri : string, password : string): bool;\n\n    # Continue creating wallet that was previously erased using EraseWalletSeedsAndAccounts\n    static ContinueWalletLinkedFromURI(linked_uri : string, password : string): bool;\n\n    # Create the wallet - this should only be called after receiving a `notifyInit...` signal from InitUnityLib\n    static InitWalletFromAndroidLegacyProtoWallet(wallet_file : string, old_password : string, new_password : string): bool;\n\n    # Check if a file is a valid legacy proto wallet\n    static isValidAndroidLegacyProtoWallet(wallet_file : string, old_password : string): legacy_wallet_result;\n\n    # Check link URI for validity\n    static IsValidLinkURI(phrase: string): bool;\n\n    # Replace the existing wallet accounts with a new one from a linked URI - only after first emptying the wallet.\n    static ReplaceWalletLinkedFromURI(linked_uri : string, password : string): bool;\n\n    # Erase the seeds and accounts of a wallet leaving an empty wallet (with things like the address book intact)\n    # After calling this it will be necessary to create a new linked account or recovery phrase account again.\n    # NB! This will empty a wallet regardless of whether it has funds in it or not and makes no provisions to check for this - it is the callers responsibility to ensure that erasing the wallet is safe to do in this regard.\n    static EraseWalletSeedsAndAccounts(): bool;\n\n    # Check recovery phrase for (syntactic) validity\n    # Considered valid if the contained mnemonic is valid and the birth-number is either absent or passes Base-10 checksum\n    static IsValidRecoveryPhrase(phrase: string): bool;\n\n    # Generate a new recovery mnemonic\n    static GenerateRecoveryMnemonic(): mnemonic_record;\n    \n    static GenerateGenesisKeys(): string;\n\n    # Compute recovery phrase with birth number\n    static ComposeRecoveryPhrase(mnemonic: string, birthTime: i64): mnemonic_record;\n\n    # Stop the library\n    static TerminateUnityLib();\n\n    # Generate a QR code for a string, QR code will be as close to width_hint as possible when applying simple scaling.\n    static QRImageFromString(qr_string : string, width_hint : i32): qr_code_record;\n\n    # Get a receive address for the active account\n    static GetReceiveAddress(): string;\n\n    # Get the recovery phrase for the wallet\n    static GetRecoveryPhrase(): mnemonic_record;\n\n    # Check if the wallet is using a mnemonic seed ie. recovery phrase (else it is a linked wallet)\n    static IsMnemonicWallet(): bool;\n\n    # Check if the phrase mnemonic is a correct one for the wallet (phrase can be with or without birth time)\n    static IsMnemonicCorrect(phrase: string): bool;\n    \n    # Get the 'dictionary' of valid words that a recovery phrase can be composed of\n    # NB! Not all combinations of these words are valid\n    # Do not use this to generate/compose your own phrases - always use 'GenerateRecoveryMnemonic' for this\n    # This function should only be used for input validation/auto-completion\n    static GetMnemonicDictionary(): list<string>;\n\n    # Unlock wallet; wallet will automatically relock after \"timeout_in_seconds\"\n    static UnlockWallet(password: string, timeout_in_seconds: i64): bool;\n\n    # Forcefully lock wallet again\n    static LockWallet(): bool;\n    \n    static GetWalletLockStatus() : wallet_lock_status;\n\n    # Change the wallet password\n    static ChangePassword(oldPassword: string, newPassword: string) : bool;\n\n    # Rescan blockchain for wallet transactions\n    static DoRescan();\n\n    # Check if text/address is something we are capable of sending money too\n    static IsValidRecipient(request : uri_record): uri_recipient;\n    \n    # Check if text/address is a native (to our blockchain) address\n    static IsValidNativeAddress(address : string): bool;\n    \n    # Check if text/address is a valid bitcoin address\n    static IsValidBitcoinAddress(address : string): bool;\n\n    # Compute the fee required to send amount to given recipient\n    static feeForRecipient(request : uri_recipient) : i64;\n\n    # Attempt to pay a recipient, will throw on failure with description\n    static performPaymentToRecipient(request : uri_recipient, substract_fee: bool ) : payment_result_status;\n\n    # Get the wallet transaction for the hash\n    # Will throw if not found\n    static getTransaction(txHash : string) :  transaction_record;\n    \n    # resubmit a transaction to the network, returns the raw hex of the transaction as a string or empty on fail\n    static resendTransaction(txHash : string) : string;\n\n    # Get list of all address book entries\n    static getAddressBookRecords() : list<address_record>;\n\n    # Add a record to the address book\n    static addAddressBookRecord(address : address_record);\n\n    # Delete a record from the address book\n    static deleteAddressBookRecord(address : address_record);\n\n    # Interim persist and prune of state. Use at key moments like app backgrounding.\n    static PersistAndPruneForSPV();\n\n    # Reset progress notification. In cases where there has been no progress for a long time, but the process\n    # is still running the progress can be reset and will represent work to be done from this reset onwards.\n    # For example when the process is in the background on iOS for a long long time (but has not been terminated\n    # by the OS) this might make more sense then to continue the progress from where it was a day or more ago.\n    static ResetUnifiedProgress();\n\n    # Get info of last blocks (at most 32) in SPV chain\n    static getLastSPVBlockInfos() : list<block_info_record>;\n\n    static getUnifiedProgress(): f32;\n\n    static getMonitoringStats(): monitor_record;\n\n    static RegisterMonitorListener(listener : monitor_listener);\n    static UnregisterMonitorListener(listener : monitor_listener);\n\n    static getClientInfo() : map<string, string>;\n    \n    # Interface constants\n    const version: i32 = 1;\n    \n    # Get list of wallet mutations\n    #NB! This is SPV specific, non SPV wallets should use account specific getMutationHistory on an accounts controller instead\n    static getMutationHistory() : list<mutation_record>;\n    \n    # Get list of all transactions wallet has been involved in\n    #NB! This is SPV specific, non SPV wallets should use account specific getTransactionHistory on an accounts controller instead\n    static getTransactionHistory() : list<transaction_record>;\n    \n    # Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n    #NB! This is SPV specific, non SPV wallets should use HaveUnconfirmedFunds on wallet controller instead\n    static HaveUnconfirmedFunds(): bool;\n\n    # Check current wallet balance (including unconfirmed funds)\n    #NB! This is SPV specific, non SPV wallets should use GetBalance on wallet controller instead\n    static GetBalance(): i64;\n}\n\n# Controller to perform functions at a wallet level (e.g. get balance of the entire wallet)\n# For per account functionality see accounts_controller\ni_wallet_controller = interface +c {\n    # Set listener to be notified of wallet events\n    static setListener(networklistener : i_wallet_listener);\n    \n    # Check if the wallet has any transactions that are still pending confirmation, to be used to determine if e.g. it is safe to perform a link or whether we should wait.\n    static HaveUnconfirmedFunds(): bool;\n        \n    # Check current wallet balance, as a single simple number that includes confirmed/unconfirmed/immature funds\n    static GetBalanceSimple(): i64;\n    \n    # Check current wallet balance\n    static GetBalance(): balance_record;\n    \n    # Abandon a transaction\n    static AbandonTransaction(txHash : string): bool;\n    \n    # Get a unique UUID that identifies this wallet\n    static GetUUID(): string;\n}\n\n# Interface to receive wallet level events\ni_wallet_listener = interface +j +o +n {\n    # Notification of change in overall wallet balance\n    notifyBalanceChange(new_balance : balance_record): &;\n    \n    # Notification of new mutations.\n    # If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n    # reached us in another way. In general this will be because we received funds from someone, hower there are\n    # also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n    # or another wallet instance using the same keys as ours).\n    #\n    # Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n    # Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n    notifyNewMutation(mutation : mutation_record, self_committed: bool): &;\n    \n    # Notification that an existing transaction/mutation  has updated\n    #\n    # Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n    # Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n    notifyUpdatedTransaction(transaction : transaction_record): &;\n    \n    # Wallet unlocked\n    notifyWalletUnlocked(): &;\n    \n    # Wallet locked\n    notifyWalletLocked(): &;\n    \n    # Core wants the wallet to unlock; UI should respond to this by calling 'UnlockWallet'\n    notifyCoreWantsUnlock(reason : string): &;\n    \n    # Core wants display info to the user, type can be one of \"MSG_ERROR\", \"MSG_WARNING\", \"MSG_INFORMATION\"; caption is the suggested caption and message the suggested message to display\n    notifyCoreInfo(type : string, caption : string, message : string): &;\n}\n\n# monitoring stats\nmonitor_record = record {\n    partialHeight: i32;\n    partialOffset: i32;\n    prunedHeight: i32;\n    processedSPVHeight: i32;\n    probableHeight: i32;\n}\n\n# Monitoring events\nmonitor_listener = interface +j +o +n {\n    onPartialChain(height : i32, probable_height : i32, offset : i32);\n    onPruned(height : i32);\n    onProcessedSPVBlocks(height : i32);\n}\n\n# Interface to receive events from the core\ni_library_listener = interface +j +o +n {\n    # Fraction of work done since session start or last progress reset [0..1]\n    # Unified progress combines connection state, header and block sync\n    notifyUnifiedProgress(progress : f32): &;\n    \n    # Called once when 'notifyUnifiedProgress' reaches '1' for first time after session start\n    notifySyncDone(): &;\n    \n    notifyBalanceChange(new_balance : balance_record): &;\n    # Notification of new mutations\n    # If self_committed it is due to a call to performPaymentToRecipient, else it is because of a transaction\n    # reached us in another way. In general this will be because we received funds from someone, hower there are\n    # also cases where funds is send from our wallet while !self_committed (for example by a linked desktop wallet\n    # or another wallet instance using the same keys as ours).\n    #\n    # Note that no notifyNewMutation events will fire until after 'notifySyncDone'\n    # Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n    notifyNewMutation(mutation : mutation_record, self_committed: bool): &;\n\n    # Notification that an existing transaction/mutation  has updated\n    #\n    # Note that no notifyUpdatedTransaction events will fire until after 'notifySyncDone'\n    # Therefore it is necessary to first fetch the full mutation history before starting to listen for this event.\n    notifyUpdatedTransaction(transaction : transaction_record): &;\n    \n    notifyInitWithExistingWallet(): &;\n    \n    notifyInitWithoutExistingWallet(): &;\n    \n    notifyShutdown(): &;\n    \n    notifyCoreReady(): &;\n    \n    notifyError(error : string): &;\n\n    logPrint(str : string): &;\n}\n\n# C++ interface to execute RPC commands\ni_rpc_controller = interface +c {\n    static execute(rpcCommandLine : string, resultListener : i_rpc_listener);\n    static getAutocompleteList() : list<string>;\n}\n\n# Interface to handle result of RPC commands\n# Calls either onSuccess or onError depending on whether command suceedes or fails\ni_rpc_listener = interface +j +o +n {\n    # Returns a filtered version of the command with sensitive information like passwords removed\n    # Any kind of 'command history' functionality should store this filtered command and not the original command\n    onFilteredCommand(filteredCommand : string) : &;\n    # Returns the result and a filtered version of the command with sensitive information like passwords removed\n    # Any kind of 'command history' functionality should store this filtered command and not the original command\n    onSuccess(filteredCommand : string, result : string) : &;\n    # Returns an error message which might be a plain string or JSON depending on the type of error\n    # Also returns a filtered version of the command with sensitive information like passwords removed\n    # Any kind of 'command history' functionality should store this filtered command and not the original command\n    onError(filteredCommand : string, errorMessage : string) : &;\n}\n\n# C++ interface to control networking related aspects of the software\ni_p2p_network_controller = interface +c {\n    # Register listener to be notified of networking events\n    static setListener(networklistener : i_p2p_network_listener);\n    \n    # Turn p2p networking off\n    static disableNetwork();\n    \n    # Turn p2p networking on\n    static enableNetwork();\n    \n    # Get connected peer info\n    static getPeerInfo() : list<peer_record>;\n    \n    # Get all banned peers\n    static listBannedPeers() : list<banned_peer_record>;\n    \n    static banPeer(address : string, banTimeInSeconds : i64) : bool;\n    \n    # Unban a single peer\n    static unbanPeer(address : string) : bool;\n    \n    # Disconnect a specific peer\n    static disconnectPeer(nodeid : i64) : bool;\n    \n    # Clear all banned peers\n    static ClearBanned() : bool;\n}\n\n# Interface to receive updates about network status\ni_p2p_network_listener = interface +j +o +n {\n    # Notify that p2p networking has been enabled\n    onNetworkEnabled() : &;\n    # Notify that p2p networking has been disabled\n    onNetworkDisabled() : &;\n    # Notify that number of peers has changed\n    onConnectionCountChanged(numConnections : i32) : &;\n    # Notify that amount of data sent/received has changed\n    onBytesChanged(totalRecv : i32, totalSent : i32): &;\n}\n\n#Data record representing a link between an account and an external service (e.g. Holdin.com)\naccount_link_record = record {\n    # What service is it (each service should use a unique string to identify itself) \n    serviceName : string;\n    # Any data unique to the service, e.g. a key used for secure communication or similar\n    serviceData : string;\n}\n\naccount_record = record {\n    UUID : string;\n    label : string;\n    state : string;\n    type : string;\n    #Is this account 'HD' (i.e. part of what can be recovered from a recovery phrase)\n    isHD : bool;\n    #Has this account been linked to any other services/wallets; if so which see 'account_link_record' for more information\n    accountLinks : list<account_link_record>;\n}\n\n# C++ interface to control accounts\ni_accounts_controller = interface +c {\n    # Register listener to be notified of account related events\n    static setListener(accountslistener : i_accounts_listener);\n    \n    # List all currently visible accounts in the wallet\n    static listAccounts() : list<account_record>;\n\n    # Set the currently active account\n    static setActiveAccount(accountUUID : string) : bool;\n    # Get the currently active account\n    static getActiveAccount() : string;\n    \n    # Create an account, possible types are (HD/Mobile/Witness/Mining/Legacy). Returns the UUID of the new account\n    static createAccount(accountName : string, accountType : string) : string;\n    # Check name of account\n    static getAccountName(accountUUID : string): string;\n    # Rename an account\n    static renameAccount(accountUUID : string, newAccountName : string) : bool;\n    # Delete an account, account remains available in background but is hidden from user\n    static deleteAccount(accountUUID : string) : bool;\n    # Purge an account, account is permenently removed from wallet (but may still reappear in some instances if it is an HD account and user recovers from phrase in future)\n    # If it is a Legacy or imported witness key or similar account then it will be gone forever\n    # Generally prefer 'deleteAccount' and use this with caution\n    static purgeAccount(accountUUID : string) : bool;\n    \n    # Get a URI that will enable 'linking' of this account in another wallet (for e.g. mobile wallet linking) for an account. Empty on failiure. \n    static getAccountLinkURI(accountUUID : string) : string;\n    # Get a URI that will enable creation of a \"witness only\" account in another wallet that can witness on behalf of this account\n    static getWitnessKeyURI(accountUUID : string) : string;\n    # Create a new \"witness-only\" account from a previously exported URI\n    # Returns UUID on success, empty string on failiure\n    static createAccountFromWitnessKeyURI(witnessKeyURI : string, newAccountName : string) : string;\n        \n    # Get a receive address for account\n    static getReceiveAddress(accountUUID : string): string;\n    \n    # Get list of all transactions account has been involved in\n    static getTransactionHistory(accountUUID : string) : list<transaction_record>;\n    # Get list of mutations for account\n    static getMutationHistory(accountUUID : string) : list<mutation_record>;\n    \n    # Check balance for active account\n    static getActiveAccountBalance(): balance_record;\n    # Check balance for account\n    static getAccountBalance(accountUUID : string): balance_record;\n    # Check balance for all accounts, returns a map of account_uuid->balance_record\n    static getAllAccountBalances(): map<string, balance_record>;\n    \n    #Register with wallet that this account has been \"linked\" with an external service (e.g. to host holding key)\n    static addAccountLink(accountUUID : string, serviceName : string, data : string) : bool;\n    #Register with wallet to remove an existing link\n    static removeAccountLink(accountUUID : string, serviceName : string) : bool;\n    #List all active account links that we have previously registered\n    static listAccountLinks(accountUUID : string) : list<account_link_record>;\n}\n\n# Interface to receive updates about accounts\ni_accounts_listener = interface +j +o +n {\n    # Notify that the active account has changed\n    onActiveAccountChanged(accountUUID : string) : &;\n    # Notify that the active account name has changed\n    onActiveAccountNameChanged(newAccountName : string) : &;\n    # Notify that an account name has changed\n    onAccountNameChanged(accountUUID : string, newAccountName : string) : &;\n    # Notify that a new account has been added\n    onAccountAdded(accountUUID : string, accountName : string) : &;\n    # Notify that an account has been deleted\n    onAccountDeleted(accountUUID : string) : &;\n    # Notify that an account has been modified\n    onAccountModified(accountUUID : string, accountData : account_record) : &;\n}\n\nwitness_estimate_info_record = record {\n    # Current network weight\n    network_weight : i64;\n    # Weight of resulting witness account\n    weight : i64;\n    # How many parts this weight will be split into\n    parts : i64;\n    # The per block probability of resulting account witnesing\n    estimated_witness_probability : f64;\n    # The estimated number of blocks the resulting account should find per day\n    estimated_blocks_per_day : f64;\n    # The estimated earnings the account should make per day\n    estimated_daily_earnings: i64;\n    # The estimated earnings the account should make over its entire lifetime\n    estimated_lifetime_earnings: i64;\n} deriving(parcelable)\n\nwitness_funding_result_record = record {\n    # \"success\" on success, otherwise an error message\n    status : string;\n    # txid of the funding transaction, empty on failure\n    txid : string;\n    # fee charged by the transaction, 0 on failure\n    fee : i64;\n} deriving(parcelable)\n\nwitness_account_statistics_record = record {\n    # Success if request succeeded, otherwise an error message\n    request_status : string;\n    \n    # Current state of the witness account, one of: \"empty\", \"empty_with_remainder\", \"pending\", \"witnessing\", \"ended\", \"expired\", \"emptying\"\n    account_status : string;\n    \n    # Account weight\n    blocks_since_last_activity : i64;\n    \n    # Account weight\n    account_weight : i64;\n    # Account weight when it was created\n    account_weight_at_creation : i64;\n    \n    # How many parts the account weight is split up into\n    account_parts : i64;\n    \n    # Account amount currently locked\n    account_amount_locked : i64;\n    # Account amount locked when it was created\n    account_amount_locked_at_creation : i64;\n    \n    # Current network weight\n    network_tip_total_weight : i64;\n    # Network weight when account was created\n    network_total_weight_at_creation : i64;\n    \n    # Account total lock period in blocks (from creation block)\n    account_initial_lock_period_in_blocks : i64;\n\n    # Account remaining lock period in blocks (from chain tip)\n    account_remaining_lock_period_in_blocks : i64;\n\n    # How often the account is \"expected\" by the network to witness in order to not be kicked off\n    account_expected_witness_period_in_blocks : i64;\n\n    # How often the account is estimated to witness\n    account_estimated_witness_period_in_blocks : i64;\n\n    # Height at which the account lock first entered the chain\n    account_initial_lock_creation_block_height : i64;\n\n    # How much of the reward that this account earns is set to be compound\n    compounding_percent : i32;\n    \n    # Is the account weight split in an optimal way\n    is_optimal : bool;\n} deriving(parcelable)\n\n# C++ interface to control witness accounts\ni_witness_controller = interface +c {\n    # Get information on min/max witness periods, weights etc.\n    static getNetworkLimits() : map<string, string>;\n    \n    # Get an estimate of weights/parts that a witness account will be funded with\n    static getEstimatedWeight(amount_to_lock : i64, lock_period_in_blocks : i64) : witness_estimate_info_record;\n    \n    # Fund a witness account\n    static fundWitnessAccount(funding_account_UUID : string, witness_account_UUID : string, funding_amount : i64, requestedLockPeriodInBlocks : i64) : witness_funding_result_record;\n    \n    # Renew a witness account\n    static renewWitnessAccount(funding_account_UUID : string, witness_account_UUID : string) : witness_funding_result_record;\n    \n    # Get information on account weight and other witness statistics for account\n    static getAccountWitnessStatistics(witnessAccountUUID : string) : witness_account_statistics_record;\n    \n    # Turn compounding on/off\n    static setAccountCompounding(witnessAccountUUID : string, percent_to_compount : i32);\n    \n    # Check state of compounding; returns a percentage between 1 and 100, or 0 if not compounding\n    static isAccountCompounding(witnessAccountUUID : string) : i32;\n    \n    # Get the witness address of the account\n    static getWitnessAddress(witnessAccountUUID : string): string;\n    \n    # Get the optimal distribution amounts for the account; totalNetworkWeight should be the value of \"total_weight_eligible_raw\"\n    static getOptimalWitnessDistribution(amount : i64, durationInBlocks : i64, totalNetworkWeight : i64): list<i64>;\n    # Same as the above but calculates all the paramaters from the account UUID; its more efficient to use the other call if you already have these values\n    static getOptimalWitnessDistributionForAccount(witnessAccountUUID : string): list<i64>;\n    \n    # Redistribute a witness account to its optimal distribution, call 'getOptimalWitnessDistribution' first to calculate this\n    static optimiseWitnessAccount(witnessAccountUUID : string, fundingAccountUUID : string, optimalDistribution : list<i64>) : result_record;\n}\n\n# C++ interface to control generation of blocks (proof of work)\ni_generation_controller = interface +c {\n    # Register listener to be notified of generation related events\n    static setListener(generationListener : i_generation_listener);\n    # Activate block generation (proof of work)\n    # Number of threads should not exceed physical threads, memory limit is a string specifier in the form of #B/#K/#M/#G (e.g. 102400B, 10240K, 1024M, 1G)\n    static startGeneration(numThreads : i32, numArenaThreads : i32, memoryLimit : string) : bool;\n    # Stop any active block generation (proof of work)\n    static stopGeneration() : bool;\n    # Get the address of the account that is used for generation by default. Empty on failiure\n    # Note that this isn't necessarily the actual generation address as there might be an override\n    # See: getGenerationOverrideAddress\n    static getGenerationAddress() : string;\n    # Get the 'override' address for generation, if one has been set\n    # The override address, when present it used for all block generation in place of the default account address\n    static getGenerationOverrideAddress() : string;\n    # Set an override address to use for block generation in place of the default\n    static setGenerationOverrideAddress(overrideAddress : string) : bool;\n    \n    static getAvailableCores() : i64;\n    static getMinimumMemory() : i64;\n    static getMaximumMemory() : i64;\n}\n\n# Interface to receive updates about block generation\ni_generation_listener = interface +j +o +n {\n    # Signal that block generation has started\n    onGenerationStarted() : &;\n    # Signal that block generation has stopped\n    onGenerationStopped() : &;\n    # Periodically signal latest block generation statistics\n    onStatsUpdated(hashesPerSecond : f64, hashesPerSecondUnit : string, rollingHashesPerSecond : f64, rollingHashesPerSecondUnit : string, bestHashesPerSecond : f64, bestHashesPerSecondUnit : string, arenaSetupTime : f64) : &;\n}\n"
  },
  {
    "path": "src/unity/node_js/init_node_js.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n#include \"init.h\"\n#include \"rpc/register.h\"\n#include \"rpc/server.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/rpcwallet.h\"\n#endif\n#include \"warnings.h\"\n#include \"node/context.h\"\n\n#include \"unity/djinni/cpp/legacy_wallet_result.hpp\"\n#include \"unity/djinni/cpp/i_library_controller.hpp\"\n\n#include <thread>\n#include <torcontrol.h>\n#include <rpc/server.h>\n#include <httpserver.h>\n#include <httprpc.h>\n#include \"ui_interface.h\"\n#include \"rpc/blockchain.h\"\n#include \"validation/validation.h\"\n\n\nextern std::string HelpMessage(HelpMessageMode mode)\n{\n    return \"\";\n}\n\n\nvoid InitRegisterRPC()\n{\n    RegisterAllCoreRPCCommands(tableRPC);\n    #ifdef ENABLE_WALLET\n        RegisterWalletRPCCommands(tableRPC);\n    #endif\n}\n\nvoid ServerInterrupt()\n{\n    InterruptHTTPServer();\n    InterruptHTTPRPC();\n    InterruptRPC();\n    InterruptREST();\n    InterruptTorControl();\n}\n\nvoid ServerShutdown(node::NodeContext& nodeContext)\n{\n    StopHTTPServer();\n    StopHTTPRPC();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    StopRPC();\n    StopREST();\n    MilliSleep(20); //Allow other threads (UI etc. a chance to cleanup as well)\n    StopTorControl();\n    // After everything has been shut down, but before things get flushed, stop the\n    // CScheduler/checkqueue, scheduler and load block thread.\n    if (nodeContext.scheduler) nodeContext.scheduler->stop();\n    StopScriptCheckWorkerThreads();\n}\n\nstatic void OnRPCStarted()\n{\n    uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);\n}\n\nstatic void OnRPCStopped()\n{\n    uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);\n    RPCNotifyBlockChange(false, nullptr);\n    cvBlockChange.notify_all();\n    LogPrint(BCLog::RPC, \"RPC stopped.\\n\");\n}\n\nstatic void OnRPCPreCommand(const CRPCCommand& cmd)\n{\n    // Observe safe mode\n    std::string strWarning = GetWarnings(\"rpc\");\n    if (strWarning != \"\" && !GetBoolArg(\"-disablesafemode\", DEFAULT_DISABLE_SAFEMODE) &&\n        !cmd.okSafeMode)\n        throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string(\"Safe mode: \") + strWarning);\n}\n\nstatic bool AppInitServers()\n{\n    RPCServer::OnStarted(&OnRPCStarted);\n    RPCServer::OnStopped(&OnRPCStopped);\n    RPCServer::OnPreCommand(&OnRPCPreCommand);\n    if (!InitHTTPServer())\n        return false;\n    if (!StartRPC())\n        return false;\n    if (!StartHTTPRPC())\n        return false;\n    if (GetBoolArg(\"-rest\", DEFAULT_REST_ENABLE) && !StartREST())\n        return false;\n    if (!StartHTTPServer())\n        return false;\n    return true;\n}\n\nbool InitRPCWarmup()\n{\n    if (GetBoolArg(\"-server\", false))\n    {\n        uiInterface.InitMessage.connect(SetRPCWarmupStatus);\n        if (!AppInitServers())\n            return InitError(\"Unable to start HTTP server. See debug log for details.\");\n    }\n    return true;\n}\n\nbool InitTor()\n{\n    if (GetBoolArg(\"-listenonion\", DEFAULT_LISTEN_ONION))\n        StartTorControl();\n    return true;\n}\n\nbool ILibraryController::InitWalletFromAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword, const std::string& newPassword)\n{\n    // only exists here to keep the compiler happy, never call this on nodejs\n    LogPrintf(\"DO NOT call ILibraryController::InitWalletFromAndroidLegacyProtoWallet on nodejs\\n\");\n    assert(false);\n    return false;\n}\n\nLegacyWalletResult ILibraryController::isValidAndroidLegacyProtoWallet(const std::string& walletFile, const std::string& oldPassword)\n{\n    // only exists here to keep the compiler happy, never call this on nodejs\n    LogPrintf(\"DO NOT call ILibraryController::isValidAndroidLegacyProtoWallet on nodejs\\n\");\n    assert(false);\n    return LegacyWalletResult::INVALID_OR_CORRUPT;\n}\n"
  },
  {
    "path": "src/unity/node_js/logging_node_js.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"util.h\"\n#include \"fs.h\"\n#include <boost/thread.hpp>\n#include \"../unity_impl.h\"\n#include \"i_library_listener.hpp\"\n\nstatic boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;\n\n/**\n * We use boost::call_once() to make sure mutexDebugLog and\n * vMsgsBeforeOpenLog are initialized in a thread-safe manner.\n *\n * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog\n * are leaked on exit. This is ugly, but will be cleaned up by\n * the OS/libc. When the shutdown sequence is fully audited and\n * tested, explicit destruction of these objects can be implemented.\n */\nstatic FILE* fileout = NULL;\nstatic boost::mutex* mutexDebugLog = NULL;\nstatic std::list<std::string>* vMsgsBeforeOpenLog;\n\nstatic int FileWriteStr(const std::string &str, FILE *fp)\n{\n    return fwrite(str.data(), 1, str.size(), fp);\n}\n\nstatic void DebugPrintInit()\n{\n    assert(mutexDebugLog == NULL);\n    mutexDebugLog = new boost::mutex();\n    vMsgsBeforeOpenLog = new std::list<std::string>;\n}\n\nvoid OpenDebugLog()\n{\n    boost::call_once(&DebugPrintInit, debugPrintInitFlag);\n    boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);\n\n    assert(fileout == NULL);\n    assert(vMsgsBeforeOpenLog);\n    fs::path pathDebug = GetDataDir() / \"debug.log\";\n    fileout = fsbridge::fopen(pathDebug, \"a\");\n    if (fileout) {\n        setbuf(fileout, NULL); // unbuffered\n        // dump buffered messages from before we opened the log\n        while (!vMsgsBeforeOpenLog->empty()) {\n            FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);\n            vMsgsBeforeOpenLog->pop_front();\n        }\n    }\n\n    delete vMsgsBeforeOpenLog;\n    vMsgsBeforeOpenLog = NULL;\n}\n\n/**\n * fStartedNewLine is a state variable held by the calling context that will\n * suppress printing of the timestamp when multiple calls are made that don't\n * end in a newline. Initialize it to true, and hold it, in the calling context.\n */\nstatic std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)\n{\n    std::string strStamped;\n\n    if (!fLogTimestamps)\n        return str;\n\n    if (*fStartedNewLine) {\n        int64_t nTimeMicros = GetTimeMicros();\n        strStamped = FormatISO8601DateTime(nTimeMicros/1000000);\n        if (fLogTimeMicros)\n            strStamped += strprintf(\".%06d\", nTimeMicros%1000000);\n        std::chrono::seconds mocktime = GetMockTime();\n        if (mocktime > 0s) {\n            strStamped += \" (mocktime: \" + FormatISO8601DateTime(count_seconds(mocktime)) + \")\";\n        }\n        strStamped += ' ' + str;\n    } else\n        strStamped = str;\n\n    if (!str.empty() && str[str.size()-1] == '\\n')\n        *fStartedNewLine = true;\n    else\n        *fStartedNewLine = false;\n\n    return strStamped;\n}\n\nint LogPrintStr(const std::string &str)\n{\n    int ret = 0; // Returns total number of characters written\n    static std::atomic_bool fStartedNewLine(true);\n\n    if (signalHandler)\n    {\n        signalHandler->logPrint(str);\n    }\n    \n    std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);\n    \n    \n    boost::call_once(&DebugPrintInit, debugPrintInitFlag);\n    boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);\n\n    // buffer if we haven't opened the log yet\n    if (fileout == NULL) {\n        assert(vMsgsBeforeOpenLog);\n        ret = strTimestamped.length();\n        vMsgsBeforeOpenLog->push_back(strTimestamped);\n    }\n    else\n    {\n        // reopen the log file, if requested\n        if (fReopenDebugLog) {\n            fReopenDebugLog = false;\n            fs::path pathDebug = GetDataDir() / \"debug.log\";\n            if (fsbridge::freopen(pathDebug,\"a\",fileout) != NULL)\n                setbuf(fileout, NULL); // unbuffered\n        }\n\n        ret = FileWriteStr(strTimestamped, fileout);\n    }\n    return ret;\n}\n\nvoid UnityReportError(const std::string &str)\n{\n    if (signalHandler)\n    {\n        signalHandler->notifyError(str);\n    }\n}\n\n\n"
  },
  {
    "path": "src/unity/signals.h",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef UNITY_SIGNAL_H\n#define UNITY_SIGNAL_H\n\n// Return true if all slots return true (or no slots), return false otherwise.\nstruct BooleanAndAllReturnValues\n{\n    typedef bool result_type;\n\n    template<typename I>\n    bool operator()(I first, I last) const\n    {\n        while (first != last) {\n            if (!(*first)) return false;\n            ++first;\n        }\n        return true;\n    }\n};\n\n// Helper macros to connect a boost signal to connect in a thread safe way a Qt UI signal. Signal is queued and executed in the UI event loop.\n#define THREADSAFE_CONNECT_UI_SIGNAL_TO_CORE_SIGNAL0(CORE_SIGNAL, UI_OBJ, UI_SIGNAL) CORE_SIGNAL.connect( [&]() { QMetaObject::invokeMethod(UI_OBJ, UI_SIGNAL, Qt::QueuedConnection); });\n#define THREADSAFE_CONNECT_UI_SIGNAL_TO_CORE_SIGNAL1(CORE_SIGNAL, ARG1_TYPE, UI_OBJ, UI_SIGNAL) CORE_SIGNAL.connect( [&](ARG1_TYPE arg1) { QMetaObject::invokeMethod(UI_OBJ, UI_SIGNAL, Qt::QueuedConnection, Q_ARG(ARG1_TYPE, arg1)); });\n#define THREADSAFE_CONNECT_UI_SIGNAL_TO_CORE_SIGNAL2(CORE_SIGNAL, ARG1_TYPE, ARG2_TYPE, UI_OBJ, UI_SIGNAL) CORE_SIGNAL.connect( [&](ARG1_TYPE arg1, ARG2_TYPE arg2) { QMetaObject::invokeMethod(UI_OBJ, UI_SIGNAL, Qt::QueuedConnection, Q_ARG(ARG1_TYPE, arg1), Q_ARG(ARG2_TYPE, arg2)); });\n\n#endif\n"
  },
  {
    "path": "src/unity/unity_impl.cpp",
    "content": "// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n//Workaround braindamaged 'hack' in libtool.m4 that defines DLL_EXPORT when building a dll via libtool (this in turn imports unwanted symbols from e.g. pthread that breaks static pthread linkage)\n#ifdef DLL_EXPORT\n#undef DLL_EXPORT\n#endif\n\n// Unity specific includes\n#include \"unity_impl.h\"\n#include \"libinit.h\"\n\n// Standard munt headers\n#include \"appname.h\"\n#include \"clientversion.h\"\n\n#include \"util.h\"\n#include \"witnessutil.h\"\n#include \"ui_interface.h\"\n#include \"unity/appmanager.h\"\n#include \"util/moneystr.h\"\n#include <chain.h>\n#include \"consensus/validation.h\"\n#include \"net.h\"\n#include \"wallet/mnemonic.h\"\n#include \"net_processing.h\"\n#include \"wallet/spvscanner.h\"\n#include \"sync.h\"\n#include \"init.h\"\n\n// Djinni generated files\n#include \"i_library_controller.hpp\"\n#include \"i_library_listener.hpp\"\n#include \"qr_code_record.hpp\"\n#include \"balance_record.hpp\"\n#include \"uri_record.hpp\"\n#include \"uri_recipient.hpp\"\n#include \"mutation_record.hpp\"\n#include \"input_record.hpp\"\n#include \"output_record.hpp\"\n#include \"address_record.hpp\"\n#include \"peer_record.hpp\"\n#include \"block_info_record.hpp\"\n#include \"monitor_record.hpp\"\n#include \"monitor_listener.hpp\"\n#include \"payment_result_status.hpp\"\n#include \"mnemonic_record.hpp\"\n#include \"wallet_lock_status.hpp\"\n#ifdef __ANDROID__\n#include \"djinni_support.hpp\"\n#endif\n\n// External libraries\n#include <boost/algorithm/string.hpp>\n#include <boost/program_options/parsers.hpp>\n#include <qrencode.h>\n#include <memory>\n\n#include \"pow/pow.h\"\n#include <crypto/hash/sigma/sigma.h>\n#include <algorithm>\n\nstd::shared_ptr<ILibraryListener> signalHandler;\n\nRecursiveMutex cs_monitoringListeners;\nstd::set<std::shared_ptr<MonitorListener> > monitoringListeners;\n\nboost::asio::io_context ioctx;\nboost::asio::executor_work_guard<boost::asio::io_context::executor_type> work = boost::asio::make_work_guard(ioctx);\nboost::thread run_thread(boost::bind(&boost::asio::io_context::run, boost::ref(ioctx)));\n\nstatic const int64_t nClientStartupTime = GetTime();\n\nstd::vector<CAccount*> GetAccountsForAccount(CAccount* forAccount)\n{\n    std::vector<CAccount*> forAccounts;\n    forAccounts.push_back(forAccount);\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused) accountUUID;\n        if (account->getParentUUID() == forAccount->getUUID())\n        {\n            forAccounts.push_back(account);\n        }\n    }\n    return forAccounts;\n}\n\nTransactionStatus getStatusForTransaction(const CWalletTx* wtx)\n{\n    TransactionStatus status;\n    int depth = wtx->GetDepthInMainChain();\n    if (depth < 0)\n        status = TransactionStatus::CONFLICTED;\n    else if (depth == 0) {\n        if (wtx->isAbandoned())\n            status = TransactionStatus::ABANDONED;\n        else\n            status = TransactionStatus::UNCONFIRMED;\n    }\n    else if (depth < RECOMMENDED_CONFIRMATIONS) {\n        status = TransactionStatus::CONFIRMING;\n    }\n    else {\n        status = TransactionStatus::CONFIRMED;\n    }\n    return status;\n}\n\nstd::string getRecipientAddressesForWalletTransaction(CAccount* forAccount, CWallet* pWallet, const CWalletTx* wtx, bool isSentByUs)\n{\n    std::string address = \"\";\n    for (const CTxOut& txout: wtx->tx->vout)\n    {\n        bool isMine = false;\n        if (forAccount && IsMine(*forAccount, txout))\n        {\n            isMine = true;\n        }\n        if (!forAccount && pWallet && IsMine(*pWallet, txout))\n        {\n            isMine = true;\n        }\n        if ((isSentByUs && !isMine) || (!isSentByUs && isMine) || (wtx->tx->IsPoW2WitnessCoinBase() && isMine))\n        {\n            CNativeAddress addr;\n            CTxDestination dest;\n            if (!ExtractDestination(txout, dest) && !txout.IsUnspendable())\n            {\n                dest = CNoDestination();\n            }\n\n            if (addr.Set(dest))\n            {\n                if (!address.empty())\n                    address += \", \";\n                address += addr.ToString();\n            }\n        }\n    }\n    return address;\n}\n\nvoid addMutationsForTransaction(const CWalletTx* wtx, std::vector<MutationRecord>& mutations, CAccount* forAccount)\n{\n    // exclude generated that are orphaned\n    if (wtx->IsCoinBase() && wtx->GetDepthInMainChain() < 1)\n        return;\n\n    int64_t subtracted = wtx->GetDebit(ISMINE_SPENDABLE, forAccount, true);\n    int64_t added = wtx->GetCredit(ISMINE_SPENDABLE, forAccount, true) +\n                    wtx->GetImmatureCreditIncludingLockedWitnesses(false, forAccount, true);\n\n    uint64_t time = wtx->nTimeSmart;\n    std::string hash = wtx->GetHash().ToString();\n\n    TransactionStatus status = getStatusForTransaction(wtx);\n    int depth = wtx->GetDepthInMainChain();\n\n    // if any funds were subtracted the transaction was sent by us\n    if (subtracted > 0)\n    {\n        int64_t fee = subtracted - wtx->tx->GetValueOut();\n        int64_t change = wtx->GetChange();\n\n        std::string recipientAddresses = getRecipientAddressesForWalletTransaction(forAccount, pactiveWallet, wtx, true);\n\n        // detect internal transfer and split it\n        if (subtracted - fee == added)\n        {\n            // amount received\n            bool receivedZero = (added - change == 0);\n            if (!receivedZero)\n            {\n                mutations.push_back(MutationRecord(added - change, time, hash, recipientAddresses, status, depth));\n            }\n\n            // amount send including fee\n            // If we didn't add a transaction for received then add one here (even if zero) as it may be a special data transaction or something similar.\n            bool sendZero = (change - subtracted == 0);\n            if (!sendZero || receivedZero)\n            {\n                mutations.push_back(MutationRecord(change - subtracted, time, hash, recipientAddresses, status, depth));\n            }\n        }\n        else\n        {\n            mutations.push_back(MutationRecord(added - subtracted, time, hash, recipientAddresses, status, depth));\n        }\n    }\n    else if (added != 0) // nothing subtracted so we received funds\n    {\n        std::string recipientAddresses = getRecipientAddressesForWalletTransaction(forAccount, pactiveWallet, wtx, false);\n        mutations.push_back(MutationRecord(added, time, hash, recipientAddresses, status, depth));\n    }\n}\n\nTransactionRecord calculateTransactionRecordForWalletTransaction(const CWalletTx& wtx, std::vector<CAccount*>& forAccounts, bool& anyInputsOrOutputsAreMine)\n{\n    CWallet* pwallet = pactiveWallet;\n\n    std::vector<InputRecord> inputs;\n    std::vector<OutputRecord> outputs;\n\n    int64_t subtracted=0;\n    int64_t added=0;\n    for (const auto& account : forAccounts)\n    {\n        subtracted += wtx.GetDebit(ISMINE_SPENDABLE, account, true);\n        added += wtx.GetCredit(ISMINE_SPENDABLE, account, true);\n    }\n\n    CAmount fee = 0;\n    // if any funds were subtracted the transaction was sent by us\n    if (subtracted > 0)\n        fee = subtracted - wtx.tx->GetValueOut();\n\n    const CTransaction& tx = *wtx.tx;\n\n    for (const CTxIn& txin: tx.vin)\n    {\n        CNativeAddress addr;\n        CTxDestination dest = CNoDestination();\n\n        // Try to extract destination, this is not possible in general. Only if the previous\n        // ouput of our input happens to be in our wallet. Which will usually only be the case for\n        // our own transactions.\n        uint256 txHashPrev;\n        bool havePrevOut=true;\n        if (txin.GetPrevOut().isHash)\n        {\n            txHashPrev = txin.GetPrevOut().getTransactionHash();\n        }\n        else\n        {\n            if (!pwallet->GetTxHash(txin.GetPrevOut(), txHashPrev))\n            {\n                if (!fSPV)\n                {\n                    LogPrintf(\"Transaction with no corresponding hash found, txid [%d] [%d]\\n\", txin.GetPrevOut().getTransactionBlockNumber(), txin.GetPrevOut().getTransactionIndex());\n                }\n                havePrevOut = false;\n            }\n        }\n\n        std::string address;\n        std::string label;\n        std::string description;\n        if (havePrevOut)\n        {\n            std::map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(txHashPrev);\n            if (mi != pwallet->mapWallet.end())\n            {\n                const CWalletTx& prev = (*mi).second;\n                if (txin.GetPrevOut().n < prev.tx->vout.size())\n                {\n                    const auto& prevOut =  prev.tx->vout[txin.GetPrevOut().n];\n                    if (!ExtractDestination(prevOut, dest) && !prevOut.IsUnspendable())\n                    {\n                        LogPrintf(\"Unknown transaction type found, txid %s\\n\", wtx.GetHash().ToString());\n                        dest = CNoDestination();\n                    }\n                }\n            }\n            if (addr.Set(dest))\n            {\n                address = addr.ToString();\n            }\n            if (pwallet->mapAddressBook.count(address))\n            {\n                const auto& data = pwallet->mapAddressBook[address];\n                label = data.name;\n                description = data.description;\n            }\n        }\n        bool isMine = false;\n        for (const auto& account : forAccounts)\n        {\n            if (static_cast<const CExtWallet*>(pwallet)->IsMine(*account, txin))\n            {\n                isMine = true;\n                anyInputsOrOutputsAreMine = true;\n            }\n        }\n        inputs.push_back(InputRecord(address, label, description, isMine));\n    }\n\n    for (const CTxOut& txout: tx.vout)\n    {\n        std::string address;\n        CNativeAddress addr;\n        CTxDestination dest;\n        if (!ExtractDestination(txout, dest) && !txout.IsUnspendable())\n        {\n            LogPrintf(\"Unknown transaction type found, txid %s\\n\", tx.GetHash().ToString());\n            dest = CNoDestination();\n        }\n\n        if (addr.Set(dest))\n        {\n            address = addr.ToString();\n        }\n        std::string label;\n        std::string description;\n        if (pwallet->mapAddressBook.count(address))\n        {\n            const auto& data = pwallet->mapAddressBook[address];\n            label = data.name;\n            description = data.description;\n        }\n        bool isMine = false;\n        for (const auto& account : forAccounts)\n        {\n            if (IsMine(*account, txout))\n            {\n                isMine = true;\n                anyInputsOrOutputsAreMine = true;\n            }\n        }\n        outputs.push_back(OutputRecord(txout.nValue, address, label, description, isMine));\n    }\n\n    TransactionStatus status = getStatusForTransaction(&wtx);\n\n    return TransactionRecord(wtx.GetHash().ToString(), wtx.nTimeSmart,\n                             added - subtracted,\n                             fee, status, wtx.nHeight, wtx.nBlockTime, wtx.GetDepthInMainChain(),\n                             inputs, outputs);\n}\n\n// rate limited balance change notifier\nstatic CRateLimit<int>* balanceChangeNotifier=nullptr;\n\nvoid terminateUnityFrontend()\n{\n    if (signalHandler)\n    {\n        signalHandler->notifyShutdown();\n    }\n\n    // Allow frontend time to clean up and free any references to objects before unloading the library\n    // Otherwise we get a free after close (on macOS at least)\n    while (signalHandler.use_count() > 1)\n    {\n        MilliSleep(50);\n    }\n    signalHandler=nullptr;\n}\n\n#include <boost/chrono/thread_clock.hpp>\n\nstatic float lastProgress=0;\nbool syncDoneFired = false;\nvoid handlePostInitMain()\n{\n    //fixme: (SIGMA) (PHASE4) Remove this once we have witness-header-sync\n    // Select appropriate verification factor based on devices performance.\n    std::thread([=]\n    {\n// When available measure thread relative cpu time to avoid effects of thread suspension\n// which occur when observing system time.\n#if false && defined(BOOST_CHRONO_HAS_THREAD_CLOCK) && BOOST_CHRONO_THREAD_CLOCK_IS_STEADY\n        boost::chrono::time_point tpStart = boost::chrono::thread_clock::now();\n#else\n        uint64_t nStart = GetTimeMicros();\n#endif\n\n        // note that measurement is on single thread, which makes the measurement more stable\n        // actual verification might use more threads which helps overall app performance\n        sigma_verify_context verify(defaultSigmaSettings, 1);\n        CBlockHeader header;\n        verify.verifyHeader<1>(header);\n\n        // We want at least 1000 blocks per second\n#if false && defined(BOOST_CHRONO_HAS_THREAD_CLOCK) && BOOST_CHRONO_THREAD_CLOCK_IS_STEADY\n        boost::chrono::microseconds ms  = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::thread_clock::now() - tpStart);\n        uint64_t nTotal = ms.count();\n#else\n        uint64_t nTotal = std::max(GetTimeMicros() - nStart, (uint64_t)1);\n#endif\n        uint64_t nPerSec = 1000000/nTotal;\n        if (nPerSec > 1000) // Fast enough to do most the blocks\n        {\n            verifyFactor = 5;\n        }\n        else if(nPerSec > 0) // Slower so reduce the number of blocks\n        {\n            // 2 in verifyFactor chance of verifying.\n            // We verify 2 in verifyFactor blocks - or target_speed/(num_per_sec/2)\n            verifyFactor = 1000/(nPerSec/2.0);\n            verifyFactor = std::max((uint64_t)5, verifyFactor);\n            verifyFactor = std::min((uint64_t)200, verifyFactor);\n        }\n        LogPrintf(\"unity: selected verification factor %d\", verifyFactor);\n    }).detach();\n\n    if (signalHandler)\n    {\n        signalHandler->notifyCoreReady();\n    }\n\n\n    // unified progress notification\n    if (!GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        static bool haveFinishedHeaderSync=false;\n        static int totalHeaderCount=0;\n        static int startHeight = chainActive.Tip() ? chainActive.Tip()->nHeight : 0;\n\n        // If tip is relatively recent set progress to \"completed\" to begin with\n        if (chainActive.Tip() && ((GetTime() - chainActive.Tip()->nTime) < 3600))\n        {\n            lastProgress = 1.0;\n            syncDoneFired = true;\n            signalHandler->notifySyncDone();\n        }\n\n\n        // Weight a full header sync as 20%, blocks as rest\n        uiInterface.NotifyHeaderProgress.connect([=](int currentCount, int probableHeight, int headerTipHeight, int64_t headerTipTime)\n        {\n            totalHeaderCount = currentCount;\n            if (currentCount == probableHeight)\n            {\n                haveFinishedHeaderSync = true;\n            }\n            if (!haveFinishedHeaderSync && signalHandler && IsInitialBlockDownload())\n            {\n                float progress = ((((float)currentCount-startHeight)/((float)probableHeight-startHeight))*0.20);\n                if (lastProgress != 1 && (progress-lastProgress > 0.02 || progress == 1))\n                {\n                    signalHandler->notifyUnifiedProgress(progress);\n                    if (progress == 1)\n                    {\n                        syncDoneFired = true;\n                        signalHandler->notifySyncDone();\n                    }\n                    lastProgress = progress;\n                }\n            }\n        });\n        uiInterface.NotifyBlockTip.connect([=](bool isInitialBlockDownload, const CBlockIndex* pNewTip)\n        {\n            if (haveFinishedHeaderSync && signalHandler)\n            {\n                float progress = pNewTip->nHeight==totalHeaderCount?1:((0.20+((((float)pNewTip->nHeight-startHeight)/((float)totalHeaderCount-startHeight))*0.80)));\n                if (lastProgress != 1 && (progress-lastProgress > 0.02 || progress == 1))\n                {\n                    signalHandler->notifyUnifiedProgress(progress);\n                    if (progress == 1)\n                    {\n                        syncDoneFired = true;\n                        signalHandler->notifySyncDone();\n                    }\n                    lastProgress = progress;\n                }\n            }\n        });\n    }\n    else\n    {\n        uiInterface.NotifyUnifiedProgress.connect([=](float progress)\n        {\n            if (signalHandler)\n            {\n                signalHandler->notifyUnifiedProgress(progress);\n                if (progress == 1)\n                {\n                    syncDoneFired = true;\n                    signalHandler->notifySyncDone();\n                }\n                lastProgress = progress;\n            }\n        });\n\n        // monitoring listeners notifications\n        uiInterface.NotifyHeaderProgress.connect([=](int, int, int, int64_t)\n        {\n            int32_t height, probable_height, offset;\n            {\n                LOCK(cs_main);\n                height = partialChain.Height();\n                probable_height = GetProbableHeight();\n                offset = partialChain.HeightOffset();\n            }\n            LOCK(cs_monitoringListeners);\n            for (const auto &listener: monitoringListeners)\n            {\n                listener->onPartialChain(height, probable_height, offset);\n            }\n        });\n\n        uiInterface.NotifySPVPrune.connect([=](int height)\n        {\n            LOCK(cs_monitoringListeners);\n            for (const auto &listener: monitoringListeners)\n            {\n                listener->onPruned(height);\n            }\n        });\n\n        uiInterface.NotifySPVProgress.connect([=](int /*start_height*/, int processed_height, int /*probable_height*/)\n        {\n            LOCK(cs_monitoringListeners);\n            for (const auto &listener: monitoringListeners)\n            {\n                listener->onProcessedSPVBlocks(processed_height);\n            }\n        });\n    }  \n\n    // Update transaction/balance changes\n    if (pactiveWallet)\n    {\n        // Fire events for transaction depth changes (up to depth 10 only)\n        pactiveWallet->NotifyTransactionDepthChanged.connect( [&](CWallet* pwallet, const uint256& hash)\n        {\n            // Don't fire notifyNewMutation or notifyUpdatedTransaction events while in initial sync\n            // We only start firing them after 'notifySyncDone' has fired.\n            if (syncDoneFired)\n            {\n                LOCK2(cs_main, pwallet->cs_wallet);\n                if (pwallet->mapWallet.find(hash) != pwallet->mapWallet.end())\n                {\n                    const CWalletTx& wtx = pwallet->mapWallet[hash];\n                    LogPrintf(\"unity: notify transaction depth changed %s\",hash.ToString().c_str());\n                    if (signalHandler)\n                    {\n                        std::vector<CAccount*> forAccounts = GetAccountsForAccount(pactiveWallet->activeAccount);\n                        bool anyInputsOrOutputsAreMine = false;\n                        TransactionRecord walletTransaction = calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n                        if (anyInputsOrOutputsAreMine)\n                        {\n                            signalHandler->notifyUpdatedTransaction(walletTransaction);\n                        }\n                    }\n                }\n            }\n        });\n\n        // Fire events for transaction status changes, or new transactions (this won't fire for simple depth changes)\n        pactiveWallet->NotifyTransactionChanged.connect( [&](CWallet* pwallet, const uint256& hash, ChangeType status, bool fSelfComitted)\n        {\n            // Don't fire notifyNewMutation or notifyUpdatedTransaction events while in initial sync\n            // We only start firing them after 'notifySyncDone' has fired.\n            if (syncDoneFired)\n            {\n                LOCK2(cs_main, pwallet->cs_wallet);\n                if (pwallet->mapWallet.find(hash) != pwallet->mapWallet.end())\n                {\n                    if (status == CT_NEW && signalHandler) {\n                        if (pactiveWallet->mapWallet.find(hash) != pactiveWallet->mapWallet.end())\n                        {\n                            const CWalletTx& wtx = pactiveWallet->mapWallet[hash];\n                            std::vector<MutationRecord> mutations;\n                            addMutationsForTransaction(&wtx, mutations, pactiveWallet->activeAccount);\n                            for (auto& m: mutations)\n                            {\n                                LogPrintf(\"unity: notify new mutation for tx %s\", hash.ToString().c_str());\n                                signalHandler->notifyNewMutation(m, fSelfComitted);\n                            }\n                        }                    \n                    }\n                    else if (status == CT_UPDATED && signalHandler)\n                    {\n                        LogPrintf(\"unity: notify tx updated %s\",hash.ToString().c_str());\n                        const CWalletTx& wtx = pwallet->mapWallet[hash];\n                        std::vector<CAccount*> forAccounts = GetAccountsForAccount(pactiveWallet->activeAccount);\n                        bool anyInputsOrOutputsAreMine = false;\n                        TransactionRecord walletTransaction = calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n                        if (anyInputsOrOutputsAreMine)\n                        {\n                            signalHandler->notifyUpdatedTransaction(walletTransaction);\n                        }\n                    }\n                    //fixme: (UNITY) - Consider implementing f.e.x if a 0 conf transaction gets deleted...\n                    // else if (status == CT_DELETED)\n                }\n                balanceChangeNotifier->trigger(0);\n            }\n        });\n\n        // Fire once immediately to update with latest on load.\n        balanceChangeNotifier->trigger(0);\n    }\n}\n\nvoid handleInitWithExistingWallet()\n{\n    if (signalHandler)\n    {\n        signalHandler->notifyInitWithExistingWallet();\n    }\n    AppLifecycleManager::gApp->initialize();\n}\n\nvoid handleInitWithoutExistingWallet()\n{\n    signalHandler->notifyInitWithoutExistingWallet();\n}\n\nstd::string ILibraryController::BuildInfo()\n{\n    std::string info = FormatThreeDigitVersion();\n\n#if defined(__aarch64__)\n    info += \" aarch64\";\n#elif defined(__arm__)\n    info += \" arm (32bit)\";\n#elif defined(__x86_64__)\n    info += \" x86_64\";\n#elif defined(__i386__)\n    info += \" x86\";\n#endif\n    return info;\n}\n\nbool ILibraryController::InitWalletFromRecoveryPhrase(const std::string& phrase, const std::string& password)\n{\n    // Refuse to acknowledge an empty recovery phrase, or one that doesn't pass even the most obvious requirement\n    if (phrase.length() < 16)\n    {\n        return false;\n    }\n\n    //fixme: (UNITY) (SPV) - Handle all the various birth date (or lack of birthdate) cases here instead of just the one.\n    SecureString phraseOnly;\n    int phraseBirthNumber = 0;\n    AppLifecycleManager::gApp->splitRecoveryPhraseAndBirth(phrase.c_str(), phraseOnly, phraseBirthNumber);\n    if (!checkMnemonic(phraseOnly))\n    {\n        return false;\n    }\n\n    // ensure that wallet is initialized with a starting time (else it will start from now and old tx will not be scanned)\n    // Use the hardcoded timestamp 1441212522 of block 250000, we didn't have any recovery phrase style wallets (using current phrase system) before that.\n    if (phraseBirthNumber == 0)\n        phraseBirthNumber = timeToBirthNumber(1441212522L);\n\n    //fixme: (UNITY) (SPV) - Handle all the various birth date (or lack of birthdate) cases here instead of just the one.\n    AppLifecycleManager::gApp->setRecoveryPhrase(phraseOnly);\n    AppLifecycleManager::gApp->setRecoveryBirthNumber(phraseBirthNumber);\n    AppLifecycleManager::gApp->setRecoveryPassword(password.c_str());\n    AppLifecycleManager::gApp->isRecovery = true;\n    AppLifecycleManager::gApp->initialize();\n\n    return true;\n}\n\nvoid DoRescanInternal()\n{\n    if (pactiveWallet)\n    {\n        ResetSPVStartRescanThread();\n    }\n}\n\nbool ValidateAndSplitRecoveryPhrase(const std::string & phrase, SecureString& mnemonic, int& birthNumber)\n{\n    if (phrase.length() < 16)\n        return false;\n\n    AppLifecycleManager::gApp->splitRecoveryPhraseAndBirth(phrase.c_str(), mnemonic, birthNumber);\n    return checkMnemonic(mnemonic) && (birthNumber == 0 || Base10ChecksumDecode(birthNumber, nullptr));\n}\n\nbool ILibraryController::ContinueWalletFromRecoveryPhrase(const std::string& phrase, const std::string& password)\n{\n    SecureString phraseOnly;\n    int phraseBirthNumber;\n\n    if (!ValidateAndSplitRecoveryPhrase(phrase, phraseOnly, phraseBirthNumber))\n        return false;\n\n    // ensure that wallet is initialized with a starting time (else it will start from now and old tx will not be scanned)\n    // Use the hardcoded timestamp 1441212522 of block 250000, we didn't have any recovery phrase style wallets (using current phrase system) before that.\n    if (phraseBirthNumber == 0)\n        phraseBirthNumber = timeToBirthNumber(1441212522L);\n\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"ContinueWalletFromRecoveryPhrase: No active wallet\");\n        return false;\n    }\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n    AppLifecycleManager::gApp->setRecoveryPhrase(phraseOnly);\n    AppLifecycleManager::gApp->setRecoveryBirthNumber(phraseBirthNumber);\n    AppLifecycleManager::gApp->setRecoveryPassword(password.c_str());\n    AppLifecycleManager::gApp->isRecovery = true;\n\n    CWallet::CreateSeedAndAccountFromPhrase(pactiveWallet);\n\n    // Allow update of balance for deleted accounts/transactions\n    LogPrintf(\"%s: Update balance and rescan\", __func__);\n    balanceChangeNotifier->trigger(0);\n\n    // Rescan for transactions on the linked account\n    DoRescanInternal();\n\n    return true;\n}\n\nbool ILibraryController::IsValidRecoveryPhrase(const std::string & phrase)\n{\n    SecureString dummyMnemonic;\n    int dummyNumber;\n    return ValidateAndSplitRecoveryPhrase(phrase, dummyMnemonic, dummyNumber);\n}\n\n#include \"base58.h\"\nstd::string ILibraryController::GenerateGenesisKeys()\n{\n    std::string address = GetReceiveAddress();\n    CNativeAddress addr(address);\n    CTxDestination dest = addr.Get();\n    CPubKey vchPubKeyDevSubsidy;\n    pactiveWallet->GetPubKey(boost::get<CKeyID>(dest), vchPubKeyDevSubsidy);\n    std::string devSubsidyPubKey = HexStr(vchPubKeyDevSubsidy);\n    std::string devSubsidyPubKeyID = boost::get<CKeyID>(dest).GetHex();\n\n    CKey key;\n    key.MakeNewKey(true);    \n    CPrivKey vchPrivKey = key.GetPrivKey();\n    CPubKey vchPubKey = key.GetPubKey();\n    std::string privkey = HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end()).c_str();\n    std::string pubKeyID = vchPubKey.GetID().GetHex();\n    std::string witnessKeys = GLOBAL_APP_URIPREFIX\"://witnesskeys?keys=\" + CEncodedSecretKey(key).ToString() + strprintf(\"#%s\", GetAdjustedTime());\n    \n    return \"privkey: \"+privkey+\"\\n\"+\"pubkeyID: \"+pubKeyID+\"\\n\"+\"witness: \"+witnessKeys+\"\\n\"+\"dev subsidy addr: \"+address+\"\\n\"+\"dev subsidy pubkey: \"+devSubsidyPubKey+\"\\n\"+\"dev subsidy pubkey ID: \"+devSubsidyPubKeyID+\"\\n\";\n}\n\nMnemonicRecord ILibraryController::GenerateRecoveryMnemonic()\n{\n    std::vector<unsigned char> entropy(16);\n    GetStrongRandBytes(&entropy[0], 16);\n    int64_t birthTime = GetAdjustedTime();\n    SecureString phraseOnly = mnemonicFromEntropy(entropy, entropy.size()*8);\n    return ComposeRecoveryPhrase(phraseOnly.c_str(), birthTime);\n}\n\nMnemonicRecord ILibraryController::ComposeRecoveryPhrase(const std::string & mnemonic, int64_t birthTime)\n{\n    const auto& result = AppLifecycleManager::composeRecoveryPhrase(SecureString(mnemonic), birthTime);\n    return MnemonicRecord(result.first.c_str(), mnemonic.c_str(), result.second);\n}\n\nbool ILibraryController::InitWalletLinkedFromURI(const std::string& linked_uri, const std::string& password)\n{\n    CEncodedSecretKeyExt<CExtKey> linkedKey;\n    if (!linkedKey.fromURIString(linked_uri))\n    {\n        return false;\n    }\n    AppLifecycleManager::gApp->setLinkKey(linkedKey);\n    AppLifecycleManager::gApp->isLink = true;\n    AppLifecycleManager::gApp->setRecoveryPassword(password.c_str());\n    AppLifecycleManager::gApp->initialize();\n\n    return true;\n}\n\nbool ILibraryController::ContinueWalletLinkedFromURI(const std::string & linked_uri, const std::string& password)\n{\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"%s: No active wallet\", __func__);\n        return false;\n    }\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    CEncodedSecretKeyExt<CExtKey> linkedKey;\n    if (!linkedKey.fromURIString(linked_uri))\n    {\n        LogPrintf(\"%s: Failed to parse link URI\", __func__);\n        return false;\n    }\n\n    AppLifecycleManager::gApp->setLinkKey(linkedKey);\n    AppLifecycleManager::gApp->setRecoveryPassword(password.c_str());\n    AppLifecycleManager::gApp->isLink = true;\n\n    CWallet::CreateSeedAndAccountFromLink(pactiveWallet);\n\n    // Allow update of balance for deleted accounts/transactions\n    LogPrintf(\"%s: Update balance and rescan\", __func__);\n    balanceChangeNotifier->trigger(0);\n\n    // Rescan for transactions on the linked account\n    DoRescanInternal();\n\n    return true;\n}\n\nbool ILibraryController::ReplaceWalletLinkedFromURI(const std::string& linked_uri, const std::string& password)\n{\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    if (!pactiveWallet || !pactiveWallet->activeAccount)\n    {\n        LogPrintf(\"ReplaceWalletLinkedFromURI: No active wallet\");\n        return false;\n    }\n\n    // Create ext key for new linked account from parsed data\n    CEncodedSecretKeyExt<CExtKey> linkedKey;\n    if (!linkedKey.fromURIString(linked_uri))\n    {\n        LogPrintf(\"ReplaceWalletLinkedFromURI: Failed to parse link URI\");\n        return false;\n    }\n\n    // Ensure we have a valid location to send all the funds\n    CNativeAddress address(linkedKey.getPayAccount());\n    if (!address.IsValid())\n    {\n        LogPrintf(\"ReplaceWalletLinkedFromURI: invalid address %s\", linkedKey.getPayAccount().c_str());\n        return false;\n    }\n\n    // Empty wallet to target address\n    LogPrintf(\"ReplaceWalletLinkedFromURI: Empty accounts into linked address\");\n    bool fSubtractFeeFromAmount = true;\n    std::vector<std::tuple<CWalletTx*, CReserveKeyOrScript*>> transactionsToCommit;\n    for (const auto& [accountUUID, pAccount] : pactiveWallet->mapAccounts)\n    {\n        CAmount nBalance = pactiveWallet->GetBalance(pAccount, false, true, true);\n        if (nBalance > 0)\n        {\n            LogPrintf(\"ReplaceWalletLinkedFromURI: Empty account into linked address [%s]\", getUUIDAsString(accountUUID).c_str());\n            std::vector<CRecipient> vecSend;\n            CRecipient recipient = GetRecipientForDestination(address.Get(), nBalance, fSubtractFeeFromAmount, GetPoW2Phase(chainTip()));\n            vecSend.push_back(recipient);\n\n            CWalletTx* pWallettx = new CWalletTx();\n            CAmount nFeeRequired;\n            int nChangePosRet = -1;\n            std::string strError;\n            CReserveKeyOrScript* pReserveKey = new CReserveKeyOrScript(pactiveWallet, pAccount, KEYCHAIN_CHANGE);\n            std::vector<CKeyStore*> accountsToTry;\n            for ( const auto& accountPair : pactiveWallet->mapAccounts )\n            {\n                if(accountPair.second->getParentUUID() == pAccount->getUUID())\n                {\n                    accountsToTry.push_back(accountPair.second);\n                }\n                accountsToTry.push_back(pAccount);\n            }\n            if (!pactiveWallet->CreateTransaction(accountsToTry, vecSend, *pWallettx, *pReserveKey, nFeeRequired, nChangePosRet, strError))\n            {\n                LogPrintf(\"ReplaceWalletLinkedFromURI: Failed to create transaction %s [%d]\",strError.c_str(), nBalance);\n                return false;\n            }\n            transactionsToCommit.push_back(std::tuple(pWallettx, pReserveKey));\n        }\n        else\n        {\n            LogPrintf(\"ReplaceWalletLinkedFromURI: Account already empty [%s]\", getUUIDAsString(accountUUID).c_str());\n        }\n    }\n\n    if (!EraseWalletSeedsAndAccounts())\n    {\n        LogPrintf(\"ReplaceWalletLinkedFromURI: Failed to erase seed and accounts\");\n        return false;\n    }\n\n    AppLifecycleManager::gApp->setLinkKey(linkedKey);\n    AppLifecycleManager::gApp->setRecoveryPassword(password.c_str());\n    AppLifecycleManager::gApp->isLink = true;\n\n    CWallet::CreateSeedAndAccountFromLink(pactiveWallet);\n\n    for (auto& [pWalletTx, pReserveKey] : transactionsToCommit)\n    {\n        CValidationState state;\n        //NB! We delibritely pass nullptr for connman here to prevent transaction from relaying\n        //We allow the relaying to occur inside DoRescan instead\n        if (!pactiveWallet->CommitTransaction(*pWalletTx, *pReserveKey, nullptr, state))\n        {\n            LogPrintf(\"ReplaceWalletLinkedFromURI: Failed to commit transaction\");\n            return false;\n        }\n        delete pWalletTx;\n        delete pReserveKey;\n    }\n\n    // Allow update of balance for deleted accounts/transactions\n    LogPrintf(\"ReplaceWalletLinkedFromURI: Update balance and rescan\");\n    balanceChangeNotifier->trigger(0);\n\n    // Rescan for transactions on the linked account\n    DoRescanInternal();\n\n    return true;\n}\n\nbool ILibraryController::EraseWalletSeedsAndAccounts()\n{\n    pactiveWallet->EraseWalletSeedsAndAccounts();\n    return true;\n}\n\nbool ILibraryController::IsValidLinkURI(const std::string& linked_uri)\n{\n    CEncodedSecretKeyExt<CExtKey> linkedKey;\n    if (!linkedKey.fromURIString(linked_uri))\n        return false;\n    return true;\n}\n\nbool testnet_;\nbool spvMode_;\nstd::string extraArgs_;\nstd::string staticFilterPath_;\nint64_t staticFilterOffset_;\nint64_t staticFilterLength_;\n\nint32_t ILibraryController::InitUnityLib(const std::string& dataDir, const std::string& staticFilterPath, int64_t staticFilterOffset, int64_t staticFilterLength, bool testnet, bool spvMode, const std::shared_ptr<ILibraryListener>& signalHandler_, const std::string& extraArgs)\n{\n    balanceChangeNotifier = new CRateLimit<int>([](int)\n    {\n        if (pactiveWallet && signalHandler)\n        {\n            WalletBalances balances;\n            pactiveWallet->GetBalances(balances, pactiveWallet->activeAccount, true);\n            signalHandler->notifyBalanceChange(BalanceRecord(balances.availableIncludingLocked, balances.availableExcludingLocked, balances.availableLocked, balances.unconfirmedIncludingLocked, balances.unconfirmedExcludingLocked, balances.unconfirmedLocked, balances.immatureIncludingLocked, balances.immatureExcludingLocked, balances.immatureLocked, balances.totalLocked));\n        }\n    }, std::chrono::milliseconds(BALANCE_NOTIFY_THRESHOLD_MS));\n\n    // Force the datadir to specific place on e.g. android devices\n    defaultDataDirOverride = dataDir;\n\n    signalHandler = signalHandler_;\n    \n    testnet_ = testnet;\n    spvMode_ = spvMode;\n    extraArgs_ = extraArgs;\n    staticFilterPath_ = staticFilterPath;\n    staticFilterOffset_ = staticFilterOffset;\n    staticFilterLength_ = staticFilterLength;\n\n    return InitUnity();\n}\n\nvoid InitAppSpecificConfigParamaters()\n{\n    if (spvMode_)\n    {\n        // SPV wallets definitely shouldn't be listening for incoming connections at all\n        SoftSetArg(\"-listen\", \"0\");\n\n        // Minimise logging for performance reasons\n        SoftSetArg(\"-debug\", \"0\");\n\n        // Turn SPV mode on\n        SoftSetArg(\"-fullsync\", \"0\");\n        SoftSetArg(\"-spv\", \"1\");\n\n        #ifdef DJINNI_NODEJS\n            #ifdef SPV_MULTI_ACCOUNT\n                SoftSetArg(\"-accountpool\", \"3\");\n                SoftSetArg(\"-accountpoolmobi\", \"1\");\n                SoftSetArg(\"-accountpoolwitness\", \"1\");\n                SoftSetArg(\"-accountpoolmining\", \"1\");\n            #else\n                SoftSetArg(\"-accountpool\", \"0\");\n                SoftSetArg(\"-accountpoolmobi\", \"0\");\n                SoftSetArg(\"-accountpoolwitness\", \"0\");\n                SoftSetArg(\"-accountpoolmining\", \"0\");\n            #endif\n            SoftSetArg(\"-keypool\", \"10\");\n        #else\n            // Minimise lookahead size for performance reasons\n            SoftSetArg(\"-accountpool\", \"1\");\n\n            // Minimise background threads and memory consumption\n            SoftSetArg(\"-par\", \"-100\");\n            SoftSetArg(\"-maxsigcachesize\", \"0\");\n            SoftSetArg(\"-dbcache\", \"4\");\n            SoftSetArg(\"-maxmempool\", \"5\");\n            SoftSetArg(\"-maxconnections\", \"8\");\n\n            //fixme: (FUT) (UNITY) Reverse headers\n            // Temporarily disable reverse headers for mobile until memory requirements can be reduced.\n            SoftSetArg(\"-reverseheaders\", \"false\");\n        #endif\n    }\n    else\n    {\n        #ifdef DJINNI_NODEJS\n        SoftSetArg(\"-accountpool\", \"3\");\n        SoftSetArg(\"-accountpoolmobi\", \"1\");\n        SoftSetArg(\"-accountpoolwitness\", \"2\");\n        SoftSetArg(\"-keypool\", \"20\");\n        #endif\n    }\n    \n    SoftSetArg(\"-spvstaticfilterfile\", staticFilterPath_);\n    SoftSetArg(\"-spvstaticfilterfileoffset\", i64tostr(staticFilterOffset_));\n    SoftSetArg(\"-spvstaticfilterfilelength\", i64tostr(staticFilterLength_));\n\n    // Change client name\n#if defined(__APPLE__) && TARGET_OS_IPHONE == 1\n    SoftSetArg(\"-clientname\", GLOBAL_APPNAME\" ios\");\n#elif defined(__ANDROID__)\n    SoftSetArg(\"-clientname\", GLOBAL_APPNAME\" android\");\n#else\n    SoftSetArg(\"-clientname\", GLOBAL_APPNAME\" desktop\");\n#endif\n\n    // Testnet\n    if (testnet_)\n    {\n        SoftSetArg(\"-testnet\", \"S1595347850:60\");\n        SoftSetArg(\"-addnode\", \"178.62.195.19\");\n    }\n    else\n    {\n        SoftSetArg(\"-addnode\", \"178.62.195.19\");\n        SoftSetArg(\"-addnode\", \"149.210.165.218\");\n    }\n    \n    if (!extraArgs_.empty()) {\n        std::vector<const char*> args;\n        auto splitted = boost::program_options::split_unix(extraArgs_);\n        for(const auto& part: splitted)\n        {\n            if (!boost::starts_with(part, \"-datadir\"))\n            {\n                args.push_back(part.c_str());\n            }\n        }\n        gArgs.ParseExtraParameters(int(args.size()), args.data());\n    }\n}\n\nvoid InitAppSpecificDatadirParamaters()\n{\n    std::vector<const char*> args;\n    auto splitted = boost::program_options::split_unix(extraArgs_);\n    for(const auto& part: splitted)\n    {\n        if (boost::starts_with(part, \"-datadir\"))\n        {\n            args.push_back(part.c_str());\n        }\n    }\n    gArgs.ParseExtraParameters(int(args.size()), args.data());\n}\n\nvoid ILibraryController::InitUnityLibThreaded(const std::string& dataDir, const std::string& staticFilterPath, int64_t staticFilterOffset, int64_t staticFilterLength, bool testnet, bool spvMode, const std::shared_ptr<ILibraryListener>& signalHandler_, const std::string& extraArgs)\n{\n    std::thread([=]\n    {\n        InitUnityLib(dataDir, staticFilterPath, staticFilterOffset, staticFilterLength, testnet, spvMode, signalHandler_, extraArgs);\n    }).detach();\n}\n\nvoid ILibraryController::TerminateUnityLib()\n{\n    LogPrintf(\"shutdown: TerminateUnityLib called from frontend\");\n\n    // Terminate in thread so we don't block interprocess communication\n    std::thread([=]\n    {\n        work.reset();\n        ioctx.stop();\n        AppLifecycleManager::gApp->shutdown();\n        AppLifecycleManager::gApp->waitForShutDown();\n        run_thread.join();\n    }).detach();\n}\n\nQrCodeRecord ILibraryController::QRImageFromString(const std::string& qr_string, int32_t width_hint)\n{\n    QRcode* code = QRcode_encodeString(qr_string.c_str(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);\n    if (!code)\n    {\n        return QrCodeRecord(0, std::vector<uint8_t>());\n    }\n    else\n    {\n        const int32_t generatedWidth = code->width;\n        const int32_t finalWidth = (width_hint / generatedWidth) * generatedWidth;\n        const int32_t scaleMultiplier = finalWidth / generatedWidth;\n        std::vector<uint8_t> dataVector;\n        dataVector.reserve(finalWidth*finalWidth);\n        int nIndex=0;\n        for (int nRow=0; nRow<generatedWidth; ++nRow)\n        {\n            for (int nCol=0; nCol<generatedWidth; ++nCol)\n            {\n                dataVector.insert(dataVector.end(), scaleMultiplier, (code->data[nIndex++] & 1) * 255);\n            }\n            for (int i=1; i<scaleMultiplier; ++i)\n            {\n                dataVector.insert(dataVector.end(), dataVector.end()-finalWidth, dataVector.end());\n            }\n        }\n        QRcode_free(code);\n        return QrCodeRecord(finalWidth, dataVector);\n    }\n}\n\nstd::string ILibraryController::GetReceiveAddress()\n{\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    if (!pactiveWallet || !pactiveWallet->activeAccount)\n        return \"\";\n\n    CReserveKeyOrScript* receiveAddress = new CReserveKeyOrScript(pactiveWallet, pactiveWallet->activeAccount, KEYCHAIN_EXTERNAL);\n    CPubKey pubKey;\n    if (receiveAddress->GetReservedKey(pubKey))\n    {\n        CKeyID keyID = pubKey.GetID();\n        receiveAddress->ReturnKey();\n        delete receiveAddress;\n        return CNativeAddress(keyID).ToString();\n    }\n    else\n    {\n        return \"\";\n    }\n}\n\n//fixme: (UNITY) - find a way to use char[] here as well as on the java side.\nMnemonicRecord ILibraryController::GetRecoveryPhrase()\n{\n    if (pactiveWallet && pactiveWallet->activeAccount)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        //WalletModel::UnlockContext ctx(walletModel->requestUnlock());\n        //if (ctx.isValid())\n        {\n            int64_t birthTime = pactiveWallet->birthTime();\n            std::set<SecureString> allPhrases;\n            for (const auto& seedIter : pactiveWallet->mapSeeds)\n            {\n                SecureString phrase = seedIter.second->getMnemonic();\n                return ComposeRecoveryPhrase(phrase.c_str(), birthTime);\n            }\n        }\n    }\n    return MnemonicRecord(\"\", \"\", 0);\n}\n\nbool ILibraryController::IsMnemonicWallet()\n{\n    if (!pactiveWallet || !pactiveWallet->activeAccount)\n        throw std::runtime_error(_(\"No active internal wallet.\"));\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    return pactiveWallet->activeSeed != nullptr;\n}\n\nbool ILibraryController::IsMnemonicCorrect(const std::string & phrase)\n{\n    if (!pactiveWallet || !pactiveWallet->activeAccount)\n        throw std::runtime_error(_(\"No active internal wallet.\"));\n\n    SecureString mnemonicPhrase;\n    int birthNumber;\n\n    AppLifecycleManager::splitRecoveryPhraseAndBirth(SecureString(phrase), mnemonicPhrase, birthNumber);\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    for (const auto& seedIter : pactiveWallet->mapSeeds)\n    {\n        if (mnemonicPhrase == seedIter.second->getMnemonic())\n            return true;\n    }\n    return false;\n}\n\nstd::vector<std::string> ILibraryController::GetMnemonicDictionary()\n{\n    return getMnemonicDictionary();\n}\n\n\nbool ILibraryController::UnlockWallet(const std::string& password, int64_t lockTimeoutSeconds)\n{\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"UnlockWallet: No active wallet\");\n        return false;\n    }\n\n    if (!dynamic_cast<CExtWallet*>(pactiveWallet)->IsCrypted())\n    {\n        LogPrintf(\"UnlockWallet: Wallet not encrypted\");\n        return false;\n    }\n\n    return pactiveWallet->UnlockWithTimeout(password.c_str(), lockTimeoutSeconds);\n}\n\nbool ILibraryController::LockWallet()\n{\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"LockWallet: No active wallet\");\n        return false;\n    }\n\n    if (dynamic_cast<CExtWallet*>(pactiveWallet)->IsLocked())\n        return true;\n\n    return dynamic_cast<CExtWallet*>(pactiveWallet)->Lock();\n}\n\nWalletLockStatus ILibraryController::GetWalletLockStatus()\n{\n    WalletLockStatus status(false, 0);\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"WalletLockStatus: No active wallet\");\n        return status;\n    }\n\n    status.locked = dynamic_cast<CExtWallet*>(pactiveWallet)->IsLocked();\n    status.lock_timeout = pactiveWallet->nRelockTime;\n    \n    return status;\n}\n\nbool ILibraryController::ChangePassword(const std::string& oldPassword, const std::string& newPassword)\n{\n    if (!pactiveWallet)\n    {\n        LogPrintf(\"ChangePassword: No active wallet\");\n        return false;\n    }\n\n    if (newPassword.length() == 0)\n    {\n        LogPrintf(\"ChangePassword: Refusing invalid password of length 0\");\n        return false;\n    }\n\n    return pactiveWallet->ChangeWalletPassphrase(oldPassword.c_str(), newPassword.c_str());\n}\n\nbool ILibraryController::HaveUnconfirmedFunds()\n{\n    if (!pactiveWallet)\n        return true;\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, pactiveWallet->activeAccount, true);\n\n    if (balances.unconfirmedIncludingLocked > 0 || balances.immatureIncludingLocked > 0)\n    {\n        return true;\n    }\n    return false;\n}\n\nint64_t ILibraryController::GetBalance()\n{\n    if (!pactiveWallet)\n        return 0;\n\n    WalletBalances balances;\n    pactiveWallet->GetBalances(balances, pactiveWallet->activeAccount, true);\n    return balances.availableIncludingLocked + balances.unconfirmedIncludingLocked + balances.immatureIncludingLocked;\n}\n\nvoid ILibraryController::DoRescan()\n{\n    if (!pactiveWallet)\n        return;\n\n    // Allocate some extra keys\n    //fixme: Persist this across runs in some way\n    static int32_t extraKeys=0;\n    extraKeys += 5;    \n    int nKeyPoolTargetDepth = GetArg(\"-keypool\", DEFAULT_ACCOUNT_KEYPOOL_SIZE)+extraKeys;\n    pactiveWallet->TopUpKeyPool(nKeyPoolTargetDepth, 0, nullptr, 1);\n    \n    // Do the rescan\n    DoRescanInternal();\n}\n\nUriRecipient ILibraryController::IsValidRecipient(const UriRecord & request)\n{\n     // return if URI is not valid or is no Munt: URI\n    std::string lowerCaseScheme = boost::algorithm::to_lower_copy(request.scheme);\n    if (lowerCaseScheme != \"munt\")\n        return UriRecipient(false, \"\", \"\", \"\", 0);\n\n    if (!CNativeAddress(request.path).IsValid())\n        return UriRecipient(false, \"\", \"\", \"\", 0);\n\n    std::string address = request.path;\n    std::string label = \"\";\n    std::string description = \"\";\n    CAmount amount = 0;\n    if (request.items.find(\"amount\") != request.items.end())\n    {\n        ParseMoney(request.items.find(\"amount\")->second, amount);\n    }\n\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        if (pactiveWallet->mapAddressBook.find(address) != pactiveWallet->mapAddressBook.end())\n        {\n            const auto& data = pactiveWallet->mapAddressBook[address];\n            label = data.name;\n            description = data.description;\n        }\n    }\n\n    return UriRecipient(true, address, label, description, amount);\n}\n\nbool ILibraryController::IsValidNativeAddress(const std::string& address)\n{\n    CNativeAddress addr(address);\n    return addr.IsValid();\n}\n\nbool ILibraryController::IsValidBitcoinAddress(const std::string& address)\n{\n    CNativeAddress addr(address);\n    return addr.IsValidBitcoin();\n}\n\nint64_t ILibraryController::feeForRecipient(const UriRecipient & request)\n{\n    if (!pactiveWallet)\n        throw std::runtime_error(_(\"No active internal wallet.\"));\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    CNativeAddress address(request.address);\n    if (!address.IsValid())\n    {\n        LogPrintf(\"feeForRecipient: invalid address %s\", request.address.c_str());\n        throw std::runtime_error(_(\"Invalid address\"));\n    }\n\n    CRecipient recipient = GetRecipientForDestination(address.Get(), std::min(GetBalance(), request.amount), true, GetPoW2Phase(chainTip()));\n    std::vector<CRecipient> vecSend;\n    vecSend.push_back(recipient);\n\n    CWalletTx wtx;\n    CAmount nFeeRequired;\n    int nChangePosRet = -1;\n    std::string strError;\n    CReserveKeyOrScript reservekey(pactiveWallet, pactiveWallet->activeAccount, KEYCHAIN_CHANGE);\n    std::vector<CKeyStore*> accountsToTry;\n    for ( const auto& accountPair : pactiveWallet->mapAccounts )\n    {\n        if(accountPair.second->getParentUUID() == pactiveWallet->activeAccount->getUUID())\n        {\n            accountsToTry.push_back(accountPair.second);\n        }\n        accountsToTry.push_back(pactiveWallet->activeAccount);\n    }\n    if (!pactiveWallet->CreateTransaction(accountsToTry, vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, NULL, false))\n    {\n        LogPrintf(\"feeForRecipient: failed to create transaction %s\",strError.c_str());\n        throw std::runtime_error(strprintf(_(\"Failed to calculate fee\\n%s\"), strError));\n    }\n\n    return nFeeRequired;\n}\n\nPaymentResultStatus ILibraryController::performPaymentToRecipient(const UriRecipient & request, bool substract_fee)\n{\n    if (!pactiveWallet)\n        throw std::runtime_error(_(\"No active internal wallet.\"));\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    CNativeAddress address(request.address);\n    if (!address.IsValid())\n    {\n        LogPrintf(\"performPaymentToRecipient: invalid address %s\", request.address.c_str());\n        throw std::runtime_error(_(\"Invalid address\"));\n    }\n\n    CRecipient recipient = GetRecipientForDestination(address.Get(), request.amount, substract_fee, GetPoW2Phase(chainTip()));\n    std::vector<CRecipient> vecSend;\n    vecSend.push_back(recipient);\n\n    CWalletTx wtx;\n    CAmount nFeeRequired;\n    int nChangePosRet = -1;\n    std::string strError;\n    CReserveKeyOrScript reservekey(pactiveWallet, pactiveWallet->activeAccount, KEYCHAIN_CHANGE);\n    std::vector<CKeyStore*> accountsToTry;\n    for ( const auto& accountPair : pactiveWallet->mapAccounts )\n    {\n        if(accountPair.second->getParentUUID() == pactiveWallet->activeAccount->getUUID())\n        {\n            accountsToTry.push_back(accountPair.second);\n        }\n        accountsToTry.push_back(pactiveWallet->activeAccount);\n    }\n    if (!pactiveWallet->CreateTransaction(accountsToTry, vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError))\n    {\n        if (!substract_fee && request.amount + nFeeRequired > GetBalance()) {\n            return PaymentResultStatus::INSUFFICIENT_FUNDS;\n        }\n        LogPrintf(\"performPaymentToRecipient: failed to create transaction %s\",strError.c_str());\n        throw std::runtime_error(strprintf(_(\"Failed to create transaction\\n%s\"), strError));\n    }\n\n    CValidationState state;\n    if (!pactiveWallet->CommitTransaction(wtx, reservekey, g_connman.get(), state))\n    {\n        strError = strprintf(\"Error: The transaction was rejected! Reason given: %s\", state.GetRejectReason());\n        LogPrintf(\"performPaymentToRecipient: failed to commit transaction %s\",strError.c_str());\n        throw std::runtime_error(strprintf(_(\"Transaction rejected, reason: %s\"), state.GetRejectReason()));\n    }\n    \n    // Prevent accidental double spends\n    for (const auto &txin : wtx.tx->vin)\n    {\n        pactiveWallet->LockCoin(txin.GetPrevOut());\n    }\n\n    return PaymentResultStatus::SUCCESS;\n}\n\nstd::vector<TransactionRecord> getTransactionHistoryForAccount(CAccount* forAccount)\n{\n    std::vector<TransactionRecord> ret;    \n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    std::vector<CAccount*> forAccounts = GetAccountsForAccount(forAccount);    \n    for (const auto& [hash, wtx] : pactiveWallet->mapWallet)\n    {\n        bool anyInputsOrOutputsAreMine = false;\n        TransactionRecord tx = calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n        if (anyInputsOrOutputsAreMine)\n        {\n            ret.push_back(tx);\n        }\n    }\n    std::sort(ret.begin(), ret.end(), [&](TransactionRecord& x, TransactionRecord& y){ return (x.timeStamp > y.timeStamp); });\n    return ret;\n}\n\nstd::vector<TransactionRecord> ILibraryController::getTransactionHistory()\n{\n    if (!pactiveWallet)\n        return std::vector<TransactionRecord>();\n    \n    return getTransactionHistoryForAccount(pactiveWallet->activeAccount);\n}\n\nTransactionRecord ILibraryController::getTransaction(const std::string& txHash)\n{\n    if (!pactiveWallet)\n        throw std::runtime_error(strprintf(\"No active wallet to query tx hash [%s]\", txHash));\n\n    uint256 hash = uint256S(txHash);\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    if (pactiveWallet->mapWallet.find(hash) == pactiveWallet->mapWallet.end())\n        throw std::runtime_error(strprintf(\"No transaction found for hash [%s]\", txHash));\n\n    \n    std::vector<CAccount*> forAccounts = GetAccountsForAccount(pactiveWallet->activeAccount);\n    const CWalletTx& wtx = pactiveWallet->mapWallet[hash];\n    bool anyInputsOrOutputsAreMine = false;\n    return calculateTransactionRecordForWalletTransaction(wtx, forAccounts, anyInputsOrOutputsAreMine);\n}\n\nstd::string ILibraryController::resendTransaction(const std::string& txHash)\n{\n    if (!pactiveWallet)\n        throw std::runtime_error(strprintf(\"No active wallet to query tx hash [%s]\", txHash));\n\n    uint256 hash = uint256S(txHash);\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    if (pactiveWallet->mapWallet.find(hash) == pactiveWallet->mapWallet.end())\n        return \"\";\n\n    const CWalletTx& wtx = pactiveWallet->mapWallet[hash];\n    \n    CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);\n    ssTx << *wtx.tx;\n    std::string strHex = HexStr(ssTx.begin(), ssTx.end());\n    if(!g_connman)\n        return \"\";\n\n    const uint256& hashTx = wtx.tx->GetHash();\n    CInv inv(MSG_TX, hashTx);\n    g_connman->ForEachNode([&inv](CNode* pnode)\n    {\n        pnode->PushInventory(inv);\n    });\n    \n    return strHex;\n}\n\nstd::vector<MutationRecord> getMutationHistoryForAccount(CAccount* forAccount)\n{\n    std::vector<MutationRecord> ret;\n\n    LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n    // wallet transactions in reverse chronological ordering\n    std::vector<const CWalletTx*> vWtx;\n    for (const auto& [hash, wtx] : pactiveWallet->mapWallet)\n    {\n        vWtx.push_back(&wtx);\n    }\n    std::sort(vWtx.begin(), vWtx.end(), [&](const CWalletTx* x, const CWalletTx* y){ return (x->nTimeSmart > y->nTimeSmart); });\n\n    // build mutation list based on transactions\n    for (const CWalletTx* wtx : vWtx)\n    {\n        addMutationsForTransaction(wtx, ret, forAccount);\n    }\n\n    return ret;\n}\n\nstd::vector<MutationRecord> ILibraryController::getMutationHistory()\n{\n    if (!pactiveWallet)\n        return std::vector<MutationRecord>();\n    return getMutationHistoryForAccount(pactiveWallet->activeAccount);\n}\n\nstd::vector<AddressRecord> ILibraryController::getAddressBookRecords()\n{\n    std::vector<AddressRecord> ret;\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        for(const auto& [address, addressData] : pactiveWallet->mapAddressBook)\n        {\n            ret.emplace_back(AddressRecord(address, addressData.name, addressData.description, addressData.purpose));\n        }\n    }\n\n    return ret;\n}\n\nvoid ILibraryController::addAddressBookRecord(const AddressRecord& address)\n{\n    if (pactiveWallet)\n    {\n        pactiveWallet->SetAddressBook(address.address, address.name, address.desc, address.purpose);\n    }\n}\n\nvoid ILibraryController::deleteAddressBookRecord(const AddressRecord& address)\n{\n    if (pactiveWallet)\n    {\n        pactiveWallet->DelAddressBook(address.address);\n    }\n}\n\nvoid ILibraryController::PersistAndPruneForSPV()\n{\n    PersistAndPruneForPartialSync();\n}\n\nvoid ILibraryController::ResetUnifiedProgress()\n{\n    CWallet::ResetUnifiedSPVProgressNotification();\n}\n\nfloat ILibraryController::getUnifiedProgress()\n{\n    if (!g_connman)\n        return 200;\n\n    if (!GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        return lastProgress;\n    }\n    else\n    {\n        return CSPVScanner::lastProgressReported;\n    }\n}\n\nstd::vector<BlockInfoRecord> ILibraryController::getLastSPVBlockInfos()\n{\n    std::vector<BlockInfoRecord> ret;\n\n    LOCK(cs_main);\n\n    int height = partialChain.Height();\n    while (ret.size() < 32 && height > partialChain.HeightOffset()) {\n        const CBlockIndex* pindex = partialChain[height];\n        ret.push_back(BlockInfoRecord(pindex->nHeight, pindex->GetBlockTime(), pindex->GetBlockHashPoW2().ToString()));\n        height--;\n    }\n\n    return ret;\n}\n\nMonitorRecord ILibraryController::getMonitoringStats()\n{\n    LOCK(cs_main);\n    int32_t partialHeight_ = partialChain.Height();\n    int32_t partialOffset_ = partialChain.HeightOffset();\n    int32_t prunedHeight_ = nPartialPruneHeightDone;\n    int32_t processedSPVHeight_ = CSPVScanner::getProcessedHeight();\n    int32_t probableHeight_ = GetProbableHeight();\n\n    return MonitorRecord(partialHeight_,\n                         partialOffset_,\n                         prunedHeight_,\n                         processedSPVHeight_,\n                         probableHeight_);\n}\n\nvoid ILibraryController::RegisterMonitorListener(const std::shared_ptr<MonitorListener> & listener)\n{\n    LOCK(cs_monitoringListeners);\n    monitoringListeners.insert(listener);\n}\n\nvoid ILibraryController::UnregisterMonitorListener(const std::shared_ptr<MonitorListener> & listener)\n{\n    LOCK(cs_monitoringListeners);\n    monitoringListeners.erase(listener);\n}\n\nstd::unordered_map<std::string, std::string> ILibraryController::getClientInfo()\n{\n    std::unordered_map<std::string, std::string> ret;\n    \n    ret.insert(std::pair(\"client_version\", FormatFullVersion()));\n    ret.insert(std::pair(\"user_agent\", strSubVersion));\n    ret.insert(std::pair(\"datadir_path\", GetDataDir().string()));\n    std::string logfilePath = (GetDataDir() / \"debug.log\").string();\n    ret.insert(std::pair(\"logfile_path\", logfilePath));\n    ret.insert(std::pair(\"startup_timestamp\", i64tostr(nClientStartupTime)));\n    \n    if (!g_connman->GetNetworkActive())\n    {\n        ret.insert(std::pair(\"network_status\", \"disabled\"));    \n        ret.insert(std::pair(\"num_connections_in\", \"0\"));\n        ret.insert(std::pair(\"num_connections_out\", \"0\"));\n    }\n    else\n    {\n        ret.insert(std::pair(\"network_status\", \"enabled\"));\n        std::string connectionsIn = i64tostr(g_connman->GetNodeCount(CConnman::NumConnections::CONNECTIONS_IN));\n        std::string connectionsOut = i64tostr(g_connman->GetNodeCount(CConnman::NumConnections::CONNECTIONS_OUT));\n        ret.insert(std::pair(\"num_connections_in\", connectionsIn));\n        ret.insert(std::pair(\"num_connections_out\", connectionsOut));\n    }\n    \n    if (fSPV)\n    {\n        if (partialChain.Tip())\n        {\n            ret.insert(std::pair(\"chain_tip_height\", i64tostr(partialChain.Height())));\n            ret.insert(std::pair(\"chain_tip_time\", i64tostr(partialChain.Tip()->GetBlockTime())));\n            ret.insert(std::pair(\"chain_tip_hash\", partialChain.Tip()->GetBlockHashPoW2().ToString()));\n            ret.insert(std::pair(\"chain_offset\", i64tostr(partialChain.HeightOffset())));\n            ret.insert(std::pair(\"chain_pruned_height\", i64tostr(nPartialPruneHeightDone)));\n            ret.insert(std::pair(\"chain_processed_height\", i64tostr(CSPVScanner::getProcessedHeight())));\n            ret.insert(std::pair(\"chain_probable_height\", i64tostr(GetProbableHeight())));\n        }\n    }\n    else if (chainActive.Tip())\n    {\n        ret.insert(std::pair(\"chain_tip_height\", i64tostr(chainActive.Tip()->nHeight)));\n        ret.insert(std::pair(\"chain_tip_time\", i64tostr(chainActive.Tip()->GetBlockTime())));\n        ret.insert(std::pair(\"chain_tip_hash\", chainActive.Tip()->GetBlockHashPoW2().ToString()));\n    }\n    \n    ret.insert(std::pair(\"mempool_transaction_count\", i64tostr(mempool.size())));\n    ret.insert(std::pair(\"mempool_memory_size\", i64tostr(mempool.GetTotalTxSize())));\n    \n    return ret;\n}\n"
  },
  {
    "path": "src/unity/unity_impl.h",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef UNITY_IMPL\n#define UNITY_IMPL\n\n#include \"i_library_controller.hpp\"\n#include \"wallet/wallet.h\"\n#include \"transaction_record.hpp\"\n\nconst int RECOMMENDED_CONFIRMATIONS = 3;\nconst int BALANCE_NOTIFY_THRESHOLD_MS = 4000;\nconst int NEW_MUTATIONS_NOTIFY_THRESHOLD_MS = 10000;\n\nextern std::shared_ptr<ILibraryListener> signalHandler;\n\nextern TransactionRecord calculateTransactionRecordForWalletTransaction(const CWalletTx& wtx, std::vector<CAccount*>& forAccounts, bool& anyInputsOrOutputsAreMine);\nextern std::vector<TransactionRecord> getTransactionHistoryForAccount(CAccount* forAccount);\nextern std::vector<MutationRecord> getMutationHistoryForAccount(CAccount* forAccount);\nextern void addMutationsForTransaction(const CWalletTx* wtx, std::vector<MutationRecord>& mutations, CAccount* forAccount);\n\nextern boost::asio::io_context ioctx;\nextern boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;\nextern boost::thread run_thread;\n\n/* Helper for rate limiting notifications.\n * This helper is agnostic of state like chain sync etc.\n * It is limited by a minimum time that has to pass between notifications. Any updates that come in too fast will\n * be absorbed. Finally the last update is guaranteed to be delivered and will take the latest data.\n * So for example with a rate limit of 3 seconds we get this scenario:\n * trigger(1)\n * trigger(2)\n * wait of 1 seconds\n * trigger(3)\n * trigger(4)\n * wait of 4 seconds\n * trigger(5)\n * trigger(6)\n * will see trigger 1 (or 2 depending on thread scheduling) delivered at t=0s, 4 at t=3s and finally 6 at t=6s.\n */\ntemplate <typename EventData> class CRateLimit\n{\npublic:\n\n    CRateLimit(std::function<void (const EventData&)> _notifier, const std::chrono::milliseconds& _timeLimit):\n        notifier(_notifier),\n        timeLimit(_timeLimit),\n        pending(false),\n        lastTimeHandled(std::chrono::steady_clock::now() - timeLimit),\n        timer(ioctx) {}\n\n    virtual ~CRateLimit()\n    {\n        timer.cancel();\n    }\n\n    void trigger(const EventData& data)\n    {\n        std::scoped_lock lock(mtx);\n        mostRecentData = data;\n        if (!pending) {\n            pending = true;\n            timer.expires_at(lastTimeHandled + timeLimit);\n            timer.async_wait(boost::bind(&CRateLimit::handler, this));\n        }\n    }\n\n    void handler() {\n        EventData data;\n        {\n            std::scoped_lock lock(mtx);\n            data = mostRecentData;\n            pending = false;\n            lastTimeHandled = std::chrono::steady_clock::now();\n\n        }\n        notifier(data); // notify using a copy of event data such that the notifier will not block new triggers\n    }\n\nprivate:\n    std::function<void (const EventData&)> notifier;\n    boost::asio::steady_timer::duration timeLimit;\n\n    std::mutex mtx;\n    bool pending;\n    EventData mostRecentData;\n    std::chrono::time_point<std::chrono::steady_clock> lastTimeHandled;\n    boost::asio::steady_timer timer;\n};\n\n#endif\n"
  },
  {
    "path": "src/univalue/.gitignore",
    "content": ".deps/\nINSTALL\nMakefile\nMakefile.in\naclocal.m4\nautom4te.cache/\ncompile\nconfig.log\nconfig.status\nconfig.guess\nconfig.sub\nconfigure\ndepcomp\ninstall-sh\nmissing\nstamp-h1\nunivalue-config.h*\ntest-driver\nlibtool\nltmain.sh\ntest-suite.log\n\n*.a\n*.la\n*.lo\n*.logs\n*.o\n*.pc\n*.trs\n\n.dirstamp\n.libs\n"
  },
  {
    "path": "src/univalue/COPYING",
    "content": "\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "src/univalue/Makefile.am",
    "content": "include sources.mk\nACLOCAL_AMFLAGS = -I build-aux/m4\n.PHONY: gen FORCE\n.INTERMEDIATE: $(GENBIN)\n\ninclude_HEADERS = $(UNIVALUE_DIST_HEADERS_INT)\nnoinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT)\n\nlib_LTLIBRARIES = libunivalue.la\n\npkgconfigdir = $(libdir)/pkgconfig\npkgconfig_DATA = pc/libunivalue.pc\n\nlibunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT)\n\nlibunivalue_la_LDFLAGS = \\\n\t-version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \\\n\t-no-undefined\nlibunivalue_la_CXXFLAGS = -I$(top_srcdir)/include\n\nTESTS = test/object test/unitester test/no_nul\n\nGENBIN = gen/gen$(BUILD_EXEEXT)\nGEN_SRCS = gen/gen.cpp\n\n$(GENBIN): $(GEN_SRCS)\n\t@echo Building $@\n\t$(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $<\n\ngen: $(GENBIN) FORCE\n\t@echo Updating lib/univalue_escapes.h\n\t$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h\n\nnoinst_PROGRAMS = $(TESTS) test/test_json\n\ntest_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT)\ntest_unitester_LDADD = libunivalue.la\ntest_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\\\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\\\"\ntest_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)\n\ntest_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT)\ntest_test_json_LDADD = libunivalue.la\ntest_test_json_CXXFLAGS = -I$(top_srcdir)/include\ntest_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)\n\ntest_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT)\ntest_no_nul_LDADD = libunivalue.la\ntest_no_nul_CXXFLAGS = -I$(top_srcdir)/include\ntest_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)\n\ntest_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT)\ntest_object_LDADD = libunivalue.la\ntest_object_CXXFLAGS = -I$(top_srcdir)/include\ntest_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)\n\nTEST_FILES = $(UNIVALUE_TEST_FILES_INT)\n\nEXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS)\n"
  },
  {
    "path": "src/univalue/README.md",
    "content": "\n# UniValue\n\n## Summary\n\nA universal value class, with JSON encoding and decoding.\n\nUniValue is an abstract data type that may be a null, boolean, string,\nnumber, array container, or a key/value dictionary container, nested to\nan arbitrary depth.\n\nThis class is aligned with the JSON standard, [RFC\n7159](https://tools.ietf.org/html/rfc7159.html).\n\n## Library usage\n\nThis is a fork of univalue used by Bitcoin Core. It is not maintained for usage\nby other projects. Notably, the API may break in non-backward-compatible ways.\n\nOther projects looking for a maintained library should use the upstream\nunivalue at https://github.com/jgarzik/univalue.\n"
  },
  {
    "path": "src/univalue/TODO",
    "content": "\nRearrange tree for easier 'git subtree' style use\n\nMove towards C++11 etc.\n\nNamespace support - must come up with useful shorthand, avoiding\nlong Univalue::Univalue::Univalue usages forced upon library users.\n\nImprove test suite\n\n"
  },
  {
    "path": "src/univalue/autogen.sh",
    "content": "#!/bin/sh\nset -e\nsrcdir=\"$(dirname $0)\"\ncd \"$srcdir\"\nif [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE=\"`which glibtoolize 2>/dev/null`\"; then\n  LIBTOOLIZE=\"${GLIBTOOLIZE}\"\n  export LIBTOOLIZE\nfi\nautoreconf --install --force\n"
  },
  {
    "path": "src/univalue/build-aux/m4/.gitignore",
    "content": "/*.m4\n"
  },
  {
    "path": "src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4",
    "content": "# ===========================================================================\n#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])\n#\n# DESCRIPTION\n#\n#   Check for baseline language coverage in the compiler for the specified\n#   version of the C++ standard.  If necessary, add switches to CXX and\n#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)\n#   or '14' (for the C++14 standard).\n#\n#   The second argument, if specified, indicates whether you insist on an\n#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.\n#   -std=c++11).  If neither is specified, you get whatever works, with\n#   preference for no added switch, and then for an extended mode.\n#\n#   The third argument, if specified 'mandatory' or if left unspecified,\n#   indicates that baseline support for the specified C++ standard is\n#   required and that the macro should error out if no mode with that\n#   support is found.  If specified 'optional', then configuration proceeds\n#   regardless, after defining HAVE_CXX${VERSION} if and only if a\n#   supporting mode is found.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>\n#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>\n#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>\n#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>\n#   Copyright (c) 2015 Paul Norman <penorman@mac.com>\n#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>\n#   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>\n#   Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>\n#   Copyright (c) 2020 Jason Merrill <jason@redhat.com>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved.  This file is offered as-is, without any\n#   warranty.\n\n#serial 12\n\ndnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro\ndnl  (serial version number 13).\n\nAC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl\n  m4_if([$1], [11], [ax_cxx_compile_alternatives=\"11 0x\"],\n        [$1], [14], [ax_cxx_compile_alternatives=\"14 1y\"],\n        [$1], [17], [ax_cxx_compile_alternatives=\"17 1z\"],\n        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl\n  m4_if([$2], [], [],\n        [$2], [ext], [],\n        [$2], [noext], [],\n        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl\n  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],\n        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],\n        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],\n        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])\n  AC_LANG_PUSH([C++])dnl\n  ac_success=no\n\n  m4_if([$2], [], [dnl\n    AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,\n       ax_cv_cxx_compile_cxx$1,\n      [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n        [ax_cv_cxx_compile_cxx$1=yes],\n        [ax_cv_cxx_compile_cxx$1=no])])\n    if test x$ax_cv_cxx_compile_cxx$1 = xyes; then\n      ac_success=yes\n    fi])\n\n  m4_if([$2], [noext], [], [dnl\n  if test x$ac_success = xno; then\n    for alternative in ${ax_cxx_compile_alternatives}; do\n      switch=\"-std=gnu++${alternative}\"\n      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])\n      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,\n                     $cachevar,\n        [ac_save_CXX=\"$CXX\"\n         CXX=\"$CXX $switch\"\n         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n          [eval $cachevar=yes],\n          [eval $cachevar=no])\n         CXX=\"$ac_save_CXX\"])\n      if eval test x\\$$cachevar = xyes; then\n        CXX=\"$CXX $switch\"\n        if test -n \"$CXXCPP\" ; then\n          CXXCPP=\"$CXXCPP $switch\"\n        fi\n        ac_success=yes\n        break\n      fi\n    done\n  fi])\n\n  m4_if([$2], [ext], [], [dnl\n  if test x$ac_success = xno; then\n    dnl HP's aCC needs +std=c++11 according to:\n    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf\n    dnl Cray's crayCC needs \"-h std=c++11\"\n    for alternative in ${ax_cxx_compile_alternatives}; do\n      for switch in -std=c++${alternative} +std=c++${alternative} \"-h std=c++${alternative}\"; do\n        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])\n        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,\n                       $cachevar,\n          [ac_save_CXX=\"$CXX\"\n           CXX=\"$CXX $switch\"\n           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],\n            [eval $cachevar=yes],\n            [eval $cachevar=no])\n           CXX=\"$ac_save_CXX\"])\n        if eval test x\\$$cachevar = xyes; then\n          CXX=\"$CXX $switch\"\n          if test -n \"$CXXCPP\" ; then\n            CXXCPP=\"$CXXCPP $switch\"\n          fi\n          ac_success=yes\n          break\n        fi\n      done\n      if test x$ac_success = xyes; then\n        break\n      fi\n    done\n  fi])\n  AC_LANG_POP([C++])\n  if test x$ax_cxx_compile_cxx$1_required = xtrue; then\n    if test x$ac_success = xno; then\n      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])\n    fi\n  fi\n  if test x$ac_success = xno; then\n    HAVE_CXX$1=0\n    AC_MSG_NOTICE([No compiler with C++$1 support was found])\n  else\n    HAVE_CXX$1=1\n    AC_DEFINE(HAVE_CXX$1,1,\n              [define if the compiler supports basic C++$1 syntax])\n  fi\n  AC_SUBST(HAVE_CXX$1)\n])\n\n\ndnl  Test body for checking C++11 support\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11\n)\n\n\ndnl  Test body for checking C++14 support\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14\n)\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14\n  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17\n)\n\ndnl  Tests for new features in C++11\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[\n\n// If the compiler admits that it is not ready for C++11, why torture it?\n// Hopefully, this will speed up the test.\n\n#ifndef __cplusplus\n\n#error \"This is not a C++ compiler\"\n\n#elif __cplusplus < 201103L\n\n#error \"This is not a C++11 compiler\"\n\n#else\n\nnamespace cxx11\n{\n\n  namespace test_static_assert\n  {\n\n    template <typename T>\n    struct check\n    {\n      static_assert(sizeof(int) <= sizeof(T), \"not big enough\");\n    };\n\n  }\n\n  namespace test_final_override\n  {\n\n    struct Base\n    {\n      virtual ~Base() {}\n      virtual void f() {}\n    };\n\n    struct Derived : public Base\n    {\n      virtual ~Derived() override {}\n      virtual void f() override {}\n    };\n\n  }\n\n  namespace test_double_right_angle_brackets\n  {\n\n    template < typename T >\n    struct check {};\n\n    typedef check<void> single_type;\n    typedef check<check<void>> double_type;\n    typedef check<check<check<void>>> triple_type;\n    typedef check<check<check<check<void>>>> quadruple_type;\n\n  }\n\n  namespace test_decltype\n  {\n\n    int\n    f()\n    {\n      int a = 1;\n      decltype(a) b = 2;\n      return a + b;\n    }\n\n  }\n\n  namespace test_type_deduction\n  {\n\n    template < typename T1, typename T2 >\n    struct is_same\n    {\n      static const bool value = false;\n    };\n\n    template < typename T >\n    struct is_same<T, T>\n    {\n      static const bool value = true;\n    };\n\n    template < typename T1, typename T2 >\n    auto\n    add(T1 a1, T2 a2) -> decltype(a1 + a2)\n    {\n      return a1 + a2;\n    }\n\n    int\n    test(const int c, volatile int v)\n    {\n      static_assert(is_same<int, decltype(0)>::value == true, \"\");\n      static_assert(is_same<int, decltype(c)>::value == false, \"\");\n      static_assert(is_same<int, decltype(v)>::value == false, \"\");\n      auto ac = c;\n      auto av = v;\n      auto sumi = ac + av + 'x';\n      auto sumf = ac + av + 1.0;\n      static_assert(is_same<int, decltype(ac)>::value == true, \"\");\n      static_assert(is_same<int, decltype(av)>::value == true, \"\");\n      static_assert(is_same<int, decltype(sumi)>::value == true, \"\");\n      static_assert(is_same<int, decltype(sumf)>::value == false, \"\");\n      static_assert(is_same<int, decltype(add(c, v))>::value == true, \"\");\n      return (sumf > 0.0) ? sumi : add(c, v);\n    }\n\n  }\n\n  namespace test_noexcept\n  {\n\n    int f() { return 0; }\n    int g() noexcept { return 0; }\n\n    static_assert(noexcept(f()) == false, \"\");\n    static_assert(noexcept(g()) == true, \"\");\n\n  }\n\n  namespace test_constexpr\n  {\n\n    template < typename CharT >\n    unsigned long constexpr\n    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept\n    {\n      return *s ? strlen_c_r(s + 1, acc + 1) : acc;\n    }\n\n    template < typename CharT >\n    unsigned long constexpr\n    strlen_c(const CharT *const s) noexcept\n    {\n      return strlen_c_r(s, 0UL);\n    }\n\n    static_assert(strlen_c(\"\") == 0UL, \"\");\n    static_assert(strlen_c(\"1\") == 1UL, \"\");\n    static_assert(strlen_c(\"example\") == 7UL, \"\");\n    static_assert(strlen_c(\"another\\0example\") == 7UL, \"\");\n\n  }\n\n  namespace test_rvalue_references\n  {\n\n    template < int N >\n    struct answer\n    {\n      static constexpr int value = N;\n    };\n\n    answer<1> f(int&)       { return answer<1>(); }\n    answer<2> f(const int&) { return answer<2>(); }\n    answer<3> f(int&&)      { return answer<3>(); }\n\n    void\n    test()\n    {\n      int i = 0;\n      const int c = 0;\n      static_assert(decltype(f(i))::value == 1, \"\");\n      static_assert(decltype(f(c))::value == 2, \"\");\n      static_assert(decltype(f(0))::value == 3, \"\");\n    }\n\n  }\n\n  namespace test_uniform_initialization\n  {\n\n    struct test\n    {\n      static const int zero {};\n      static const int one {1};\n    };\n\n    static_assert(test::zero == 0, \"\");\n    static_assert(test::one == 1, \"\");\n\n  }\n\n  namespace test_lambdas\n  {\n\n    void\n    test1()\n    {\n      auto lambda1 = [](){};\n      auto lambda2 = lambda1;\n      lambda1();\n      lambda2();\n    }\n\n    int\n    test2()\n    {\n      auto a = [](int i, int j){ return i + j; }(1, 2);\n      auto b = []() -> int { return '0'; }();\n      auto c = [=](){ return a + b; }();\n      auto d = [&](){ return c; }();\n      auto e = [a, &b](int x) mutable {\n        const auto identity = [](int y){ return y; };\n        for (auto i = 0; i < a; ++i)\n          a += b--;\n        return x + identity(a + b);\n      }(0);\n      return a + b + c + d + e;\n    }\n\n    int\n    test3()\n    {\n      const auto nullary = [](){ return 0; };\n      const auto unary = [](int x){ return x; };\n      using nullary_t = decltype(nullary);\n      using unary_t = decltype(unary);\n      const auto higher1st = [](nullary_t f){ return f(); };\n      const auto higher2nd = [unary](nullary_t f1){\n        return [unary, f1](unary_t f2){ return f2(unary(f1())); };\n      };\n      return higher1st(nullary) + higher2nd(nullary)(unary);\n    }\n\n  }\n\n  namespace test_variadic_templates\n  {\n\n    template <int...>\n    struct sum;\n\n    template <int N0, int... N1toN>\n    struct sum<N0, N1toN...>\n    {\n      static constexpr auto value = N0 + sum<N1toN...>::value;\n    };\n\n    template <>\n    struct sum<>\n    {\n      static constexpr auto value = 0;\n    };\n\n    static_assert(sum<>::value == 0, \"\");\n    static_assert(sum<1>::value == 1, \"\");\n    static_assert(sum<23>::value == 23, \"\");\n    static_assert(sum<1, 2>::value == 3, \"\");\n    static_assert(sum<5, 5, 11>::value == 21, \"\");\n    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, \"\");\n\n  }\n\n  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae\n  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function\n  // because of this.\n  namespace test_template_alias_sfinae\n  {\n\n    struct foo {};\n\n    template<typename T>\n    using member = typename T::member_type;\n\n    template<typename T>\n    void func(...) {}\n\n    template<typename T>\n    void func(member<T>*) {}\n\n    void test();\n\n    void test() { func<foo>(0); }\n\n  }\n\n}  // namespace cxx11\n\n#endif  // __cplusplus >= 201103L\n\n]])\n\n\ndnl  Tests for new features in C++14\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[\n\n// If the compiler admits that it is not ready for C++14, why torture it?\n// Hopefully, this will speed up the test.\n\n#ifndef __cplusplus\n\n#error \"This is not a C++ compiler\"\n\n#elif __cplusplus < 201402L\n\n#error \"This is not a C++14 compiler\"\n\n#else\n\nnamespace cxx14\n{\n\n  namespace test_polymorphic_lambdas\n  {\n\n    int\n    test()\n    {\n      const auto lambda = [](auto&&... args){\n        const auto istiny = [](auto x){\n          return (sizeof(x) == 1UL) ? 1 : 0;\n        };\n        const int aretiny[] = { istiny(args)... };\n        return aretiny[0];\n      };\n      return lambda(1, 1L, 1.0f, '1');\n    }\n\n  }\n\n  namespace test_binary_literals\n  {\n\n    constexpr auto ivii = 0b0000000000101010;\n    static_assert(ivii == 42, \"wrong value\");\n\n  }\n\n  namespace test_generalized_constexpr\n  {\n\n    template < typename CharT >\n    constexpr unsigned long\n    strlen_c(const CharT *const s) noexcept\n    {\n      auto length = 0UL;\n      for (auto p = s; *p; ++p)\n        ++length;\n      return length;\n    }\n\n    static_assert(strlen_c(\"\") == 0UL, \"\");\n    static_assert(strlen_c(\"x\") == 1UL, \"\");\n    static_assert(strlen_c(\"test\") == 4UL, \"\");\n    static_assert(strlen_c(\"another\\0test\") == 7UL, \"\");\n\n  }\n\n  namespace test_lambda_init_capture\n  {\n\n    int\n    test()\n    {\n      auto x = 0;\n      const auto lambda1 = [a = x](int b){ return a + b; };\n      const auto lambda2 = [a = lambda1(x)](){ return a; };\n      return lambda2();\n    }\n\n  }\n\n  namespace test_digit_separators\n  {\n\n    constexpr auto ten_million = 100'000'000;\n    static_assert(ten_million == 100000000, \"\");\n\n  }\n\n  namespace test_return_type_deduction\n  {\n\n    auto f(int& x) { return x; }\n    decltype(auto) g(int& x) { return x; }\n\n    template < typename T1, typename T2 >\n    struct is_same\n    {\n      static constexpr auto value = false;\n    };\n\n    template < typename T >\n    struct is_same<T, T>\n    {\n      static constexpr auto value = true;\n    };\n\n    int\n    test()\n    {\n      auto x = 0;\n      static_assert(is_same<int, decltype(f(x))>::value, \"\");\n      static_assert(is_same<int&, decltype(g(x))>::value, \"\");\n      return x;\n    }\n\n  }\n\n}  // namespace cxx14\n\n#endif  // __cplusplus >= 201402L\n\n]])\n\n\ndnl  Tests for new features in C++17\n\nm4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[\n\n// If the compiler admits that it is not ready for C++17, why torture it?\n// Hopefully, this will speed up the test.\n\n#ifndef __cplusplus\n\n#error \"This is not a C++ compiler\"\n\n#elif __cplusplus < 201703L\n\n#error \"This is not a C++17 compiler\"\n\n#else\n\n#include <initializer_list>\n#include <utility>\n#include <type_traits>\n\nnamespace cxx17\n{\n\n  namespace test_constexpr_lambdas\n  {\n\n    constexpr int foo = [](){return 42;}();\n\n  }\n\n  namespace test::nested_namespace::definitions\n  {\n\n  }\n\n  namespace test_fold_expression\n  {\n\n    template<typename... Args>\n    int multiply(Args... args)\n    {\n      return (args * ... * 1);\n    }\n\n    template<typename... Args>\n    bool all(Args... args)\n    {\n      return (args && ...);\n    }\n\n  }\n\n  namespace test_extended_static_assert\n  {\n\n    static_assert (true);\n\n  }\n\n  namespace test_auto_brace_init_list\n  {\n\n    auto foo = {5};\n    auto bar {5};\n\n    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);\n    static_assert(std::is_same<int, decltype(bar)>::value);\n  }\n\n  namespace test_typename_in_template_template_parameter\n  {\n\n    template<template<typename> typename X> struct D;\n\n  }\n\n  namespace test_fallthrough_nodiscard_maybe_unused_attributes\n  {\n\n    int f1()\n    {\n      return 42;\n    }\n\n    [[nodiscard]] int f2()\n    {\n      [[maybe_unused]] auto unused = f1();\n\n      switch (f1())\n      {\n      case 17:\n        f1();\n        [[fallthrough]];\n      case 42:\n        f1();\n      }\n      return f1();\n    }\n\n  }\n\n  namespace test_extended_aggregate_initialization\n  {\n\n    struct base1\n    {\n      int b1, b2 = 42;\n    };\n\n    struct base2\n    {\n      base2() {\n        b3 = 42;\n      }\n      int b3;\n    };\n\n    struct derived : base1, base2\n    {\n        int d;\n    };\n\n    derived d1 {{1, 2}, {}, 4};  // full initialization\n    derived d2 {{}, {}, 4};      // value-initialized bases\n\n  }\n\n  namespace test_general_range_based_for_loop\n  {\n\n    struct iter\n    {\n      int i;\n\n      int& operator* ()\n      {\n        return i;\n      }\n\n      const int& operator* () const\n      {\n        return i;\n      }\n\n      iter& operator++()\n      {\n        ++i;\n        return *this;\n      }\n    };\n\n    struct sentinel\n    {\n      int i;\n    };\n\n    bool operator== (const iter& i, const sentinel& s)\n    {\n      return i.i == s.i;\n    }\n\n    bool operator!= (const iter& i, const sentinel& s)\n    {\n      return !(i == s);\n    }\n\n    struct range\n    {\n      iter begin() const\n      {\n        return {0};\n      }\n\n      sentinel end() const\n      {\n        return {5};\n      }\n    };\n\n    void f()\n    {\n      range r {};\n\n      for (auto i : r)\n      {\n        [[maybe_unused]] auto v = i;\n      }\n    }\n\n  }\n\n  namespace test_lambda_capture_asterisk_this_by_value\n  {\n\n    struct t\n    {\n      int i;\n      int foo()\n      {\n        return [*this]()\n        {\n          return i;\n        }();\n      }\n    };\n\n  }\n\n  namespace test_enum_class_construction\n  {\n\n    enum class byte : unsigned char\n    {};\n\n    byte foo {42};\n\n  }\n\n  namespace test_constexpr_if\n  {\n\n    template <bool cond>\n    int f ()\n    {\n      if constexpr(cond)\n      {\n        return 13;\n      }\n      else\n      {\n        return 42;\n      }\n    }\n\n  }\n\n  namespace test_selection_statement_with_initializer\n  {\n\n    int f()\n    {\n      return 13;\n    }\n\n    int f2()\n    {\n      if (auto i = f(); i > 0)\n      {\n        return 3;\n      }\n\n      switch (auto i = f(); i + 4)\n      {\n      case 17:\n        return 2;\n\n      default:\n        return 1;\n      }\n    }\n\n  }\n\n  namespace test_template_argument_deduction_for_class_templates\n  {\n\n    template <typename T1, typename T2>\n    struct pair\n    {\n      pair (T1 p1, T2 p2)\n        : m1 {p1},\n          m2 {p2}\n      {}\n\n      T1 m1;\n      T2 m2;\n    };\n\n    void f()\n    {\n      [[maybe_unused]] auto p = pair{13, 42u};\n    }\n\n  }\n\n  namespace test_non_type_auto_template_parameters\n  {\n\n    template <auto n>\n    struct B\n    {};\n\n    B<5> b1;\n    B<'a'> b2;\n\n  }\n\n  namespace test_structured_bindings\n  {\n\n    int arr[2] = { 1, 2 };\n    std::pair<int, int> pr = { 1, 2 };\n\n    auto f1() -> int(&)[2]\n    {\n      return arr;\n    }\n\n    auto f2() -> std::pair<int, int>&\n    {\n      return pr;\n    }\n\n    struct S\n    {\n      int x1 : 2;\n      volatile double y1;\n    };\n\n    S f3()\n    {\n      return {};\n    }\n\n    auto [ x1, y1 ] = f1();\n    auto& [ xr1, yr1 ] = f1();\n    auto [ x2, y2 ] = f2();\n    auto& [ xr2, yr2 ] = f2();\n    const auto [ x3, y3 ] = f3();\n\n  }\n\n  namespace test_exception_spec_type_system\n  {\n\n    struct Good {};\n    struct Bad {};\n\n    void g1() noexcept;\n    void g2();\n\n    template<typename T>\n    Bad\n    f(T*, T*);\n\n    template<typename T1, typename T2>\n    Good\n    f(T1*, T2*);\n\n    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);\n\n  }\n\n  namespace test_inline_variables\n  {\n\n    template<class T> void f(T)\n    {}\n\n    template<class T> inline T g(T)\n    {\n      return T{};\n    }\n\n    template<> inline void f<>(int)\n    {}\n\n    template<> int g<>(int)\n    {\n      return 5;\n    }\n\n  }\n\n}  // namespace cxx17\n\n#endif  // __cplusplus < 201703L\n\n]])\n"
  },
  {
    "path": "src/univalue/configure.ac",
    "content": "m4_define([libunivalue_major_version], [1])\nm4_define([libunivalue_minor_version], [1])\nm4_define([libunivalue_micro_version], [4])\nm4_define([libunivalue_interface_age], [4])\n# If you need a modifier for the version number. \n# Normally empty, but can be used to make \"fixup\" releases.\nm4_define([libunivalue_extraversion], [])\n\ndnl libtool versioning from libunivalue\nm4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)])\nm4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)])\nm4_define([libunivalue_revision], [libunivalue_interface_age])\nm4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)])\nm4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])\n\n\nAC_INIT([univalue], [1.0.4],\n        [http://github.com/jgarzik/univalue/])\n\ndnl make the compilation flags quiet unless V=1 is used\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\n\nAC_PREREQ(2.60)\nAC_CONFIG_SRCDIR([lib/univalue.cpp])\nAC_CONFIG_AUX_DIR([build-aux])\nAC_CONFIG_MACRO_DIR([build-aux/m4])\nAC_CONFIG_HEADERS([univalue-config.h])\nAM_INIT_AUTOMAKE([subdir-objects foreign])\n\nLIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version\nLIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version\nLIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version\nLIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age\n\n# ABI version\n# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html\nLIBUNIVALUE_CURRENT=libunivalue_current\nLIBUNIVALUE_REVISION=libunivalue_revision\nLIBUNIVALUE_AGE=libunivalue_age\n\nAC_SUBST(LIBUNIVALUE_CURRENT)\nAC_SUBST(LIBUNIVALUE_REVISION)\nAC_SUBST(LIBUNIVALUE_AGE)\n\nLT_INIT\nLT_LANG([C++])\n\ndnl Require C++11 compiler (no GNU extensions)\nAX_CXX_COMPILE_STDCXX([17], [noext], [mandatory], [nodefault])\n\ncase $host in\n  *mingw*)\n    LIBTOOL_APP_LDFLAGS=\"$LIBTOOL_APP_LDFLAGS -all-static\"\n  ;;\nesac\n\nBUILD_EXEEXT=\ncase $build in\n  *mingw*)\n    BUILD_EXEEXT=\".exe\"\n  ;;\nesac\n\nAC_CONFIG_FILES([\n    Makefile\n    pc/libunivalue.pc\n    pc/libunivalue-uninstalled.pc])\n\nAC_SUBST(LIBTOOL_APP_LDFLAGS)\nAC_SUBST(BUILD_EXEEXT)\nAC_OUTPUT\n\n"
  },
  {
    "path": "src/univalue/include/univalue.h",
    "content": "// Copyright 2014 BitPay Inc.\n// Copyright 2015 Bitcoin Core Developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#ifndef __UNIVALUE_H__\n#define __UNIVALUE_H__\n\n#include <stdint.h>\n#include <string.h>\n\n#include <string>\n#include <vector>\n#include <map>\n#include <cassert>\n\nclass UniValue {\npublic:\n    enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };\n\n    UniValue() { typ = VNULL; }\n    UniValue(UniValue::VType initialType, const std::string& initialStr = \"\") {\n        typ = initialType;\n        val = initialStr;\n    }\n    UniValue(uint64_t val_) {\n        setInt(val_);\n    }\n    UniValue(int64_t val_) {\n        setInt(val_);\n    }\n    UniValue(bool val_) {\n        setBool(val_);\n    }\n    UniValue(int val_) {\n        setInt(val_);\n    }\n    UniValue(double val_) {\n        setFloat(val_);\n    }\n    UniValue(const std::string& val_) {\n        setStr(val_);\n    }\n    UniValue(const char *val_) {\n        std::string s(val_);\n        setStr(s);\n    }\n\n    void clear();\n\n    bool setNull();\n    bool setBool(bool val);\n    bool setNumStr(const std::string& val);\n    bool setInt(uint64_t val);\n    bool setInt(int64_t val);\n    bool setInt(int val_) { return setInt((int64_t)val_); }\n    bool setFloat(double val);\n    bool setStr(const std::string& val);\n    bool setArray();\n    bool setObject();\n\n    enum VType getType() const { return typ; }\n    const std::string& getValStr() const { return val; }\n    bool empty() const { return (values.size() == 0); }\n\n    size_t size() const { return values.size(); }\n\n    bool getBool() const { return isTrue(); }\n    void getObjMap(std::map<std::string,UniValue>& kv) const;\n    bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;\n    const UniValue& operator[](const std::string& key) const;\n    const UniValue& operator[](size_t index) const;\n    bool exists(const std::string& key) const { size_t i; return findKey(key, i); }\n\n    bool isNull() const { return (typ == VNULL); }\n    bool isTrue() const { return (typ == VBOOL) && (val == \"1\"); }\n    bool isFalse() const { return (typ == VBOOL) && (val != \"1\"); }\n    bool isBool() const { return (typ == VBOOL); }\n    bool isStr() const { return (typ == VSTR); }\n    bool isNum() const { return (typ == VNUM); }\n    bool isArray() const { return (typ == VARR); }\n    bool isObject() const { return (typ == VOBJ); }\n\n    bool push_back(const UniValue& val);\n    bool push_back(const std::string& val_) {\n        UniValue tmpVal(VSTR, val_);\n        return push_back(tmpVal);\n    }\n    bool push_back(const char *val_) {\n        std::string s(val_);\n        return push_back(s);\n    }\n    bool push_back(uint64_t val_) {\n        UniValue tmpVal(val_);\n        return push_back(tmpVal);\n    }\n    bool push_back(int64_t val_) {\n        UniValue tmpVal(val_);\n        return push_back(tmpVal);\n    }\n    bool push_back(bool val_) {\n        UniValue tmpVal(val_);\n        return push_back(tmpVal);\n    }\n    bool push_back(int val_) {\n        UniValue tmpVal(val_);\n        return push_back(tmpVal);\n    }\n    bool push_back(double val_) {\n        UniValue tmpVal(val_);\n        return push_back(tmpVal);\n    }\n    bool push_backV(const std::vector<UniValue>& vec);\n\n    void __pushKV(const std::string& key, const UniValue& val);\n    bool pushKV(const std::string& key, const UniValue& val);\n    bool pushKV(const std::string& key, const std::string& val_) {\n        UniValue tmpVal(VSTR, val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKV(const std::string& key, const char *val_) {\n        std::string _val(val_);\n        return pushKV(key, _val);\n    }\n    bool pushKV(const std::string& key, int64_t val_) {\n        UniValue tmpVal(val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKV(const std::string& key, uint64_t val_) {\n        UniValue tmpVal(val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKV(const std::string& key, bool val_) {\n        UniValue tmpVal(val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKV(const std::string& key, int val_) {\n        UniValue tmpVal((int64_t)val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKV(const std::string& key, double val_) {\n        UniValue tmpVal(val_);\n        return pushKV(key, tmpVal);\n    }\n    bool pushKVs(const UniValue& obj);\n\n    std::string write(unsigned int prettyIndent = 0,\n                      unsigned int indentLevel = 0) const;\n\n    bool read(const char *raw, size_t len);\n    bool read(const char *raw) { return read(raw, strlen(raw)); }\n    bool read(const std::string& rawStr) {\n        return read(rawStr.data(), rawStr.size());\n    }\n\nprivate:\n    UniValue::VType typ;\n    std::string val;                       // numbers are stored as C++ strings\n    std::vector<std::string> keys;\n    std::vector<UniValue> values;\n\n    bool findKey(const std::string& key, size_t& retIdx) const;\n    void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;\n    void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;\n\npublic:\n    // Strict type-specific getters, these throw std::runtime_error if the\n    // value is of unexpected type\n    const std::vector<std::string>& getKeys() const;\n    const std::vector<UniValue>& getValues() const;\n    bool get_bool() const;\n    const std::string& get_str() const;\n    int get_int() const;\n    int64_t get_int64() const;\n    double get_real() const;\n    const UniValue& get_obj() const;\n    const UniValue& get_array() const;\n\n    enum VType type() const { return getType(); }\n    friend const UniValue& find_value( const UniValue& obj, const std::string& name);\n};\n\nenum jtokentype {\n    JTOK_ERR        = -1,\n    JTOK_NONE       = 0,                           // eof\n    JTOK_OBJ_OPEN,\n    JTOK_OBJ_CLOSE,\n    JTOK_ARR_OPEN,\n    JTOK_ARR_CLOSE,\n    JTOK_COLON,\n    JTOK_COMMA,\n    JTOK_KW_NULL,\n    JTOK_KW_TRUE,\n    JTOK_KW_FALSE,\n    JTOK_NUMBER,\n    JTOK_STRING,\n};\n\nextern enum jtokentype getJsonToken(std::string& tokenVal,\n                                    unsigned int& consumed, const char *raw, const char *end);\nextern const char *uvTypeName(UniValue::VType t);\n\nstatic inline bool jsonTokenIsValue(enum jtokentype jtt)\n{\n    switch (jtt) {\n    case JTOK_KW_NULL:\n    case JTOK_KW_TRUE:\n    case JTOK_KW_FALSE:\n    case JTOK_NUMBER:\n    case JTOK_STRING:\n        return true;\n\n    default:\n        return false;\n    }\n\n    // not reached\n}\n\nstatic inline bool json_isspace(int ch)\n{\n    switch (ch) {\n    case 0x20:\n    case 0x09:\n    case 0x0a:\n    case 0x0d:\n        return true;\n\n    default:\n        return false;\n    }\n\n    // not reached\n}\n\nextern const UniValue NullUniValue;\n\nconst UniValue& find_value( const UniValue& obj, const std::string& name);\n\n#endif // __UNIVALUE_H__\n"
  },
  {
    "path": "src/univalue/lib/.gitignore",
    "content": "gen\n.libs\n"
  },
  {
    "path": "src/univalue/lib/univalue.cpp",
    "content": "// Copyright 2014 BitPay Inc.\n// Copyright 2015 Bitcoin Core Developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <stdint.h>\n#include <iomanip>\n#include <sstream>\n#include <stdlib.h>\n\n#include \"univalue.h\"\n\nconst UniValue NullUniValue;\n\nvoid UniValue::clear()\n{\n    typ = VNULL;\n    val.clear();\n    keys.clear();\n    values.clear();\n}\n\nbool UniValue::setNull()\n{\n    clear();\n    return true;\n}\n\nbool UniValue::setBool(bool val_)\n{\n    clear();\n    typ = VBOOL;\n    if (val_)\n        val = \"1\";\n    return true;\n}\n\nstatic bool validNumStr(const std::string& s)\n{\n    std::string tokenVal;\n    unsigned int consumed;\n    enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());\n    return (tt == JTOK_NUMBER);\n}\n\nbool UniValue::setNumStr(const std::string& val_)\n{\n    if (!validNumStr(val_))\n        return false;\n\n    clear();\n    typ = VNUM;\n    val = val_;\n    return true;\n}\n\nbool UniValue::setInt(uint64_t val_)\n{\n    std::ostringstream oss;\n\n    oss << val_;\n\n    return setNumStr(oss.str());\n}\n\nbool UniValue::setInt(int64_t val_)\n{\n    std::ostringstream oss;\n\n    oss << val_;\n\n    return setNumStr(oss.str());\n}\n\nbool UniValue::setFloat(double val_)\n{\n    std::ostringstream oss;\n\n    oss << std::setprecision(16) << val_;\n\n    bool ret = setNumStr(oss.str());\n    typ = VNUM;\n    return ret;\n}\n\nbool UniValue::setStr(const std::string& val_)\n{\n    clear();\n    typ = VSTR;\n    val = val_;\n    return true;\n}\n\nbool UniValue::setArray()\n{\n    clear();\n    typ = VARR;\n    return true;\n}\n\nbool UniValue::setObject()\n{\n    clear();\n    typ = VOBJ;\n    return true;\n}\n\nbool UniValue::push_back(const UniValue& val_)\n{\n    if (typ != VARR)\n        return false;\n\n    values.push_back(val_);\n    return true;\n}\n\nbool UniValue::push_backV(const std::vector<UniValue>& vec)\n{\n    if (typ != VARR)\n        return false;\n\n    values.insert(values.end(), vec.begin(), vec.end());\n\n    return true;\n}\n\nvoid UniValue::__pushKV(const std::string& key, const UniValue& val_)\n{\n    keys.push_back(key);\n    values.push_back(val_);\n}\n\nbool UniValue::pushKV(const std::string& key, const UniValue& val_)\n{\n    if (typ != VOBJ)\n        return false;\n\n    size_t idx;\n    if (findKey(key, idx))\n        values[idx] = val_;\n    else\n        __pushKV(key, val_);\n    return true;\n}\n\nbool UniValue::pushKVs(const UniValue& obj)\n{\n    if (typ != VOBJ || obj.typ != VOBJ)\n        return false;\n\n    for (size_t i = 0; i < obj.keys.size(); i++)\n        __pushKV(obj.keys[i], obj.values.at(i));\n\n    return true;\n}\n\nvoid UniValue::getObjMap(std::map<std::string,UniValue>& kv) const\n{\n    if (typ != VOBJ)\n        return;\n\n    kv.clear();\n    for (size_t i = 0; i < keys.size(); i++)\n        kv[keys[i]] = values[i];\n}\n\nbool UniValue::findKey(const std::string& key, size_t& retIdx) const\n{\n    for (size_t i = 0; i < keys.size(); i++) {\n        if (keys[i] == key) {\n            retIdx = i;\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const\n{\n    if (typ != VOBJ) {\n        return false;\n    }\n\n    for (const auto& object: t) {\n        size_t idx = 0;\n        if (!findKey(object.first, idx)) {\n            return false;\n        }\n\n        if (values.at(idx).getType() != object.second) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nconst UniValue& UniValue::operator[](const std::string& key) const\n{\n    if (typ != VOBJ)\n        return NullUniValue;\n\n    size_t index = 0;\n    if (!findKey(key, index))\n        return NullUniValue;\n\n    return values.at(index);\n}\n\nconst UniValue& UniValue::operator[](size_t index) const\n{\n    if (typ != VOBJ && typ != VARR)\n        return NullUniValue;\n    if (index >= values.size())\n        return NullUniValue;\n\n    return values.at(index);\n}\n\nconst char *uvTypeName(UniValue::VType t)\n{\n    switch (t) {\n    case UniValue::VNULL: return \"null\";\n    case UniValue::VBOOL: return \"bool\";\n    case UniValue::VOBJ: return \"object\";\n    case UniValue::VARR: return \"array\";\n    case UniValue::VSTR: return \"string\";\n    case UniValue::VNUM: return \"number\";\n    }\n\n    // not reached\n    return nullptr;\n}\n\nconst UniValue& find_value(const UniValue& obj, const std::string& name)\n{\n    for (unsigned int i = 0; i < obj.keys.size(); i++)\n        if (obj.keys[i] == name)\n            return obj.values.at(i);\n\n    return NullUniValue;\n}\n\n"
  },
  {
    "path": "src/univalue/lib/univalue_escapes.h",
    "content": "// Automatically generated file. Do not modify.\n#ifndef CORE_UNIVALUE_UNIVALUE_ESCAPES_H\n#define CORE_UNIVALUE_UNIVALUE_ESCAPES_H\nstatic const char *escapes[256] = {\n\t\"\\\\u0000\",\n\t\"\\\\u0001\",\n\t\"\\\\u0002\",\n\t\"\\\\u0003\",\n\t\"\\\\u0004\",\n\t\"\\\\u0005\",\n\t\"\\\\u0006\",\n\t\"\\\\u0007\",\n\t\"\\\\b\",\n\t\"\\\\t\",\n\t\"\\\\n\",\n\t\"\\\\u000b\",\n\t\"\\\\f\",\n\t\"\\\\r\",\n\t\"\\\\u000e\",\n\t\"\\\\u000f\",\n\t\"\\\\u0010\",\n\t\"\\\\u0011\",\n\t\"\\\\u0012\",\n\t\"\\\\u0013\",\n\t\"\\\\u0014\",\n\t\"\\\\u0015\",\n\t\"\\\\u0016\",\n\t\"\\\\u0017\",\n\t\"\\\\u0018\",\n\t\"\\\\u0019\",\n\t\"\\\\u001a\",\n\t\"\\\\u001b\",\n\t\"\\\\u001c\",\n\t\"\\\\u001d\",\n\t\"\\\\u001e\",\n\t\"\\\\u001f\",\n\tnullptr,\n\tnullptr,\n\t\"\\\\\\\"\",\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\t\"\\\\\\\\\",\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\t\"\\\\u007f\",\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n\tnullptr,\n};\n#endif // CORE_UNIVALUE_UNIVALUE_ESCAPES_H\n"
  },
  {
    "path": "src/univalue/lib/univalue_get.cpp",
    "content": "// Copyright 2014 BitPay Inc.\n// Copyright 2015 Bitcoin Core Developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <stdint.h>\n#include <errno.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdexcept>\n#include <vector>\n#include <limits>\n#include <string>\n#include <sstream>\n\n#include \"univalue.h\"\n\nnamespace\n{\nstatic bool ParsePrechecks(const std::string& str)\n{\n    if (str.empty()) // No empty string allowed\n        return false;\n    if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed\n        return false;\n    if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed\n        return false;\n    return true;\n}\n\nbool ParseInt32(const std::string& str, int32_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    char *endp = nullptr;\n    errno = 0; // strtol will not set errno if valid\n    long int n = strtol(str.c_str(), &endp, 10);\n    if(out) *out = (int32_t)n;\n    // Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow\n    // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit\n    // platforms the size of these types may be different.\n    return endp && *endp == 0 && !errno &&\n        n >= std::numeric_limits<int32_t>::min() &&\n        n <= std::numeric_limits<int32_t>::max();\n}\n\nbool ParseInt64(const std::string& str, int64_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    char *endp = nullptr;\n    errno = 0; // strtoll will not set errno if valid\n    long long int n = strtoll(str.c_str(), &endp, 10);\n    if(out) *out = (int64_t)n;\n    // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow\n    // we still have to check that the returned value is within the range of an *int64_t*.\n    return endp && *endp == 0 && !errno &&\n        n >= std::numeric_limits<int64_t>::min() &&\n        n <= std::numeric_limits<int64_t>::max();\n}\n\nbool ParseDouble(const std::string& str, double *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed\n        return false;\n    std::istringstream text(str);\n    text.imbue(std::locale::classic());\n    double result;\n    text >> result;\n    if(out) *out = result;\n    return text.eof() && !text.fail();\n}\n}\n\nconst std::vector<std::string>& UniValue::getKeys() const\n{\n    if (typ != VOBJ)\n        throw std::runtime_error(\"JSON value is not an object as expected\");\n    return keys;\n}\n\nconst std::vector<UniValue>& UniValue::getValues() const\n{\n    if (typ != VOBJ && typ != VARR)\n        throw std::runtime_error(\"JSON value is not an object or array as expected\");\n    return values;\n}\n\nbool UniValue::get_bool() const\n{\n    if (typ != VBOOL)\n        throw std::runtime_error(\"JSON value is not a boolean as expected\");\n    return getBool();\n}\n\nconst std::string& UniValue::get_str() const\n{\n    if (typ != VSTR)\n        throw std::runtime_error(\"JSON value is not a string as expected\");\n    return getValStr();\n}\n\nint UniValue::get_int() const\n{\n    if (typ != VNUM)\n        throw std::runtime_error(\"JSON value is not an integer as expected\");\n    int32_t retval;\n    if (!ParseInt32(getValStr(), &retval))\n        throw std::runtime_error(\"JSON integer out of range\");\n    return retval;\n}\n\nint64_t UniValue::get_int64() const\n{\n    if (typ != VNUM)\n        throw std::runtime_error(\"JSON value is not an integer as expected\");\n    int64_t retval;\n    if (!ParseInt64(getValStr(), &retval))\n        throw std::runtime_error(\"JSON integer out of range\");\n    return retval;\n}\n\ndouble UniValue::get_real() const\n{\n    if (typ != VNUM)\n        throw std::runtime_error(\"JSON value is not a number as expected\");\n    double retval;\n    if (!ParseDouble(getValStr(), &retval))\n        throw std::runtime_error(\"JSON double out of range\");\n    return retval;\n}\n\nconst UniValue& UniValue::get_obj() const\n{\n    if (typ != VOBJ)\n        throw std::runtime_error(\"JSON value is not an object as expected\");\n    return *this;\n}\n\nconst UniValue& UniValue::get_array() const\n{\n    if (typ != VARR)\n        throw std::runtime_error(\"JSON value is not an array as expected\");\n    return *this;\n}\n\n"
  },
  {
    "path": "src/univalue/lib/univalue_read.cpp",
    "content": "// Copyright 2014 BitPay Inc.\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <string.h>\n#include <vector>\n#include <stdio.h>\n#include \"univalue.h\"\n#include \"univalue_utffilter.h\"\n\n/*\n * According to stackexchange, the original json test suite wanted\n * to limit depth to 22.  Widely-deployed PHP bails at depth 512,\n * so we will follow PHP's lead, which should be more than sufficient\n * (further stackexchange comments indicate depth > 32 rarely occurs).\n */\nstatic const size_t MAX_JSON_DEPTH = 512;\n\nstatic bool json_isdigit(int ch)\n{\n    return ((ch >= '0') && (ch <= '9'));\n}\n\n// convert hexadecimal string to unsigned integer\nstatic const char *hatoui(const char *first, const char *last,\n                          unsigned int& out)\n{\n    unsigned int result = 0;\n    for (; first != last; ++first)\n    {\n        int digit;\n        if (json_isdigit(*first))\n            digit = *first - '0';\n\n        else if (*first >= 'a' && *first <= 'f')\n            digit = *first - 'a' + 10;\n\n        else if (*first >= 'A' && *first <= 'F')\n            digit = *first - 'A' + 10;\n\n        else\n            break;\n\n        result = 16 * result + digit;\n    }\n    out = result;\n\n    return first;\n}\n\nenum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,\n                            const char *raw, const char *end)\n{\n    tokenVal.clear();\n    consumed = 0;\n\n    const char *rawStart = raw;\n\n    while (raw < end && (json_isspace(*raw)))          // skip whitespace\n        raw++;\n\n    if (raw >= end)\n        return JTOK_NONE;\n\n    switch (*raw) {\n\n    case '{':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_OBJ_OPEN;\n    case '}':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_OBJ_CLOSE;\n    case '[':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_ARR_OPEN;\n    case ']':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_ARR_CLOSE;\n\n    case ':':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_COLON;\n    case ',':\n        raw++;\n        consumed = (raw - rawStart);\n        return JTOK_COMMA;\n\n    case 'n':\n    case 't':\n    case 'f':\n        if (!strncmp(raw, \"null\", 4)) {\n            raw += 4;\n            consumed = (raw - rawStart);\n            return JTOK_KW_NULL;\n        } else if (!strncmp(raw, \"true\", 4)) {\n            raw += 4;\n            consumed = (raw - rawStart);\n            return JTOK_KW_TRUE;\n        } else if (!strncmp(raw, \"false\", 5)) {\n            raw += 5;\n            consumed = (raw - rawStart);\n            return JTOK_KW_FALSE;\n        } else\n            return JTOK_ERR;\n\n    case '-':\n    case '0':\n    case '1':\n    case '2':\n    case '3':\n    case '4':\n    case '5':\n    case '6':\n    case '7':\n    case '8':\n    case '9': {\n        // part 1: int\n        std::string numStr;\n\n        const char *first = raw;\n\n        const char *firstDigit = first;\n        if (!json_isdigit(*firstDigit))\n            firstDigit++;\n        if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))\n            return JTOK_ERR;\n\n        numStr += *raw;                       // copy first char\n        raw++;\n\n        if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))\n            return JTOK_ERR;\n\n        while (raw < end && json_isdigit(*raw)) {  // copy digits\n            numStr += *raw;\n            raw++;\n        }\n\n        // part 2: frac\n        if (raw < end && *raw == '.') {\n            numStr += *raw;                   // copy .\n            raw++;\n\n            if (raw >= end || !json_isdigit(*raw))\n                return JTOK_ERR;\n            while (raw < end && json_isdigit(*raw)) { // copy digits\n                numStr += *raw;\n                raw++;\n            }\n        }\n\n        // part 3: exp\n        if (raw < end && (*raw == 'e' || *raw == 'E')) {\n            numStr += *raw;                   // copy E\n            raw++;\n\n            if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-\n                numStr += *raw;\n                raw++;\n            }\n\n            if (raw >= end || !json_isdigit(*raw))\n                return JTOK_ERR;\n            while (raw < end && json_isdigit(*raw)) { // copy digits\n                numStr += *raw;\n                raw++;\n            }\n        }\n\n        tokenVal = numStr;\n        consumed = (raw - rawStart);\n        return JTOK_NUMBER;\n        }\n\n    case '\"': {\n        raw++;                                // skip \"\n\n        std::string valStr;\n        JSONUTF8StringFilter writer(valStr);\n\n        while (true) {\n            if (raw >= end || (unsigned char)*raw < 0x20)\n                return JTOK_ERR;\n\n            else if (*raw == '\\\\') {\n                raw++;                        // skip backslash\n\n                if (raw >= end)\n                    return JTOK_ERR;\n\n                switch (*raw) {\n                case '\"':  writer.push_back('\\\"'); break;\n                case '\\\\': writer.push_back('\\\\'); break;\n                case '/':  writer.push_back('/'); break;\n                case 'b':  writer.push_back('\\b'); break;\n                case 'f':  writer.push_back('\\f'); break;\n                case 'n':  writer.push_back('\\n'); break;\n                case 'r':  writer.push_back('\\r'); break;\n                case 't':  writer.push_back('\\t'); break;\n\n                case 'u': {\n                    unsigned int codepoint;\n                    if (raw + 1 + 4 >= end ||\n                        hatoui(raw + 1, raw + 1 + 4, codepoint) !=\n                               raw + 1 + 4)\n                        return JTOK_ERR;\n                    writer.push_back_u(codepoint);\n                    raw += 4;\n                    break;\n                    }\n                default:\n                    return JTOK_ERR;\n\n                }\n\n                raw++;                        // skip esc'd char\n            }\n\n            else if (*raw == '\"') {\n                raw++;                        // skip \"\n                break;                        // stop scanning\n            }\n\n            else {\n                writer.push_back(static_cast<unsigned char>(*raw));\n                raw++;\n            }\n        }\n\n        if (!writer.finalize())\n            return JTOK_ERR;\n        tokenVal = valStr;\n        consumed = (raw - rawStart);\n        return JTOK_STRING;\n        }\n\n    default:\n        return JTOK_ERR;\n    }\n}\n\nenum expect_bits : unsigned {\n    EXP_OBJ_NAME = (1U << 0),\n    EXP_COLON = (1U << 1),\n    EXP_ARR_VALUE = (1U << 2),\n    EXP_VALUE = (1U << 3),\n    EXP_NOT_VALUE = (1U << 4),\n};\n\n#define expect(bit) (expectMask & (EXP_##bit))\n#define setExpect(bit) (expectMask |= EXP_##bit)\n#define clearExpect(bit) (expectMask &= ~EXP_##bit)\n\nbool UniValue::read(const char *raw, size_t size)\n{\n    clear();\n\n    uint32_t expectMask = 0;\n    std::vector<UniValue*> stack;\n\n    std::string tokenVal;\n    unsigned int consumed;\n    enum jtokentype tok = JTOK_NONE;\n    enum jtokentype last_tok = JTOK_NONE;\n    const char* end = raw + size;\n    do {\n        last_tok = tok;\n\n        tok = getJsonToken(tokenVal, consumed, raw, end);\n        if (tok == JTOK_NONE || tok == JTOK_ERR)\n            return false;\n        raw += consumed;\n\n        bool isValueOpen = jsonTokenIsValue(tok) ||\n            tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN;\n\n        if (expect(VALUE)) {\n            if (!isValueOpen)\n                return false;\n            clearExpect(VALUE);\n\n        } else if (expect(ARR_VALUE)) {\n            bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE);\n            if (!isArrValue)\n                return false;\n\n            clearExpect(ARR_VALUE);\n\n        } else if (expect(OBJ_NAME)) {\n            bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING);\n            if (!isObjName)\n                return false;\n\n        } else if (expect(COLON)) {\n            if (tok != JTOK_COLON)\n                return false;\n            clearExpect(COLON);\n\n        } else if (!expect(COLON) && (tok == JTOK_COLON)) {\n            return false;\n        }\n\n        if (expect(NOT_VALUE)) {\n            if (isValueOpen)\n                return false;\n            clearExpect(NOT_VALUE);\n        }\n\n        switch (tok) {\n\n        case JTOK_OBJ_OPEN:\n        case JTOK_ARR_OPEN: {\n            VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR);\n            if (!stack.size()) {\n                if (utyp == VOBJ)\n                    setObject();\n                else\n                    setArray();\n                stack.push_back(this);\n            } else {\n                UniValue tmpVal(utyp);\n                UniValue *top = stack.back();\n                top->values.push_back(tmpVal);\n\n                UniValue *newTop = &(top->values.back());\n                stack.push_back(newTop);\n            }\n\n            if (stack.size() > MAX_JSON_DEPTH)\n                return false;\n\n            if (utyp == VOBJ)\n                setExpect(OBJ_NAME);\n            else\n                setExpect(ARR_VALUE);\n            break;\n            }\n\n        case JTOK_OBJ_CLOSE:\n        case JTOK_ARR_CLOSE: {\n            if (!stack.size() || (last_tok == JTOK_COMMA))\n                return false;\n\n            VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);\n            UniValue *top = stack.back();\n            if (utyp != top->getType())\n                return false;\n\n            stack.pop_back();\n            clearExpect(OBJ_NAME);\n            setExpect(NOT_VALUE);\n            break;\n            }\n\n        case JTOK_COLON: {\n            if (!stack.size())\n                return false;\n\n            UniValue *top = stack.back();\n            if (top->getType() != VOBJ)\n                return false;\n\n            setExpect(VALUE);\n            break;\n            }\n\n        case JTOK_COMMA: {\n            if (!stack.size() ||\n                (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN))\n                return false;\n\n            UniValue *top = stack.back();\n            if (top->getType() == VOBJ)\n                setExpect(OBJ_NAME);\n            else\n                setExpect(ARR_VALUE);\n            break;\n            }\n\n        case JTOK_KW_NULL:\n        case JTOK_KW_TRUE:\n        case JTOK_KW_FALSE: {\n            UniValue tmpVal;\n            switch (tok) {\n            case JTOK_KW_NULL:\n                // do nothing more\n                break;\n            case JTOK_KW_TRUE:\n                tmpVal.setBool(true);\n                break;\n            case JTOK_KW_FALSE:\n                tmpVal.setBool(false);\n                break;\n            default: /* impossible */ break;\n            }\n\n            if (!stack.size()) {\n                *this = tmpVal;\n                break;\n            }\n\n            UniValue *top = stack.back();\n            top->values.push_back(tmpVal);\n\n            setExpect(NOT_VALUE);\n            break;\n            }\n\n        case JTOK_NUMBER: {\n            UniValue tmpVal(VNUM, tokenVal);\n            if (!stack.size()) {\n                *this = tmpVal;\n                break;\n            }\n\n            UniValue *top = stack.back();\n            top->values.push_back(tmpVal);\n\n            setExpect(NOT_VALUE);\n            break;\n            }\n\n        case JTOK_STRING: {\n            if (expect(OBJ_NAME)) {\n                UniValue *top = stack.back();\n                top->keys.push_back(tokenVal);\n                clearExpect(OBJ_NAME);\n                setExpect(COLON);\n            } else {\n                UniValue tmpVal(VSTR, tokenVal);\n                if (!stack.size()) {\n                    *this = tmpVal;\n                    break;\n                }\n                UniValue *top = stack.back();\n                top->values.push_back(tmpVal);\n            }\n\n            setExpect(NOT_VALUE);\n            break;\n            }\n\n        default:\n            return false;\n        }\n    } while (!stack.empty ());\n\n    /* Check that nothing follows the initial construct (parsed above).  */\n    tok = getJsonToken(tokenVal, consumed, raw, end);\n    if (tok != JTOK_NONE)\n        return false;\n\n    return true;\n}\n\n"
  },
  {
    "path": "src/univalue/lib/univalue_utffilter.h",
    "content": "// Copyright 2016 Wladimir J. van der Laan\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n#ifndef UNIVALUE_UTFFILTER_H\n#define UNIVALUE_UTFFILTER_H\n\n#include <string>\n\n/**\n * Filter that generates and validates UTF-8, as well as collates UTF-16\n * surrogate pairs as specified in RFC4627.\n */\nclass JSONUTF8StringFilter\n{\npublic:\n    explicit JSONUTF8StringFilter(std::string &s):\n        str(s), is_valid(true), codepoint(0), state(0), surpair(0)\n    {\n    }\n    // Write single 8-bit char (may be part of UTF-8 sequence)\n    void push_back(unsigned char ch)\n    {\n        if (state == 0) {\n            if (ch < 0x80) // 7-bit ASCII, fast direct pass-through\n                str.push_back(ch);\n            else if (ch < 0xc0) // Mid-sequence character, invalid in this state\n                is_valid = false;\n            else if (ch < 0xe0) { // Start of 2-byte sequence\n                codepoint = (ch & 0x1f) << 6;\n                state = 6;\n            } else if (ch < 0xf0) { // Start of 3-byte sequence\n                codepoint = (ch & 0x0f) << 12;\n                state = 12;\n            } else if (ch < 0xf8) { // Start of 4-byte sequence\n                codepoint = (ch & 0x07) << 18;\n                state = 18;\n            } else // Reserved, invalid\n                is_valid = false;\n        } else {\n            if ((ch & 0xc0) != 0x80) // Not a continuation, invalid\n                is_valid = false;\n            state -= 6;\n            codepoint |= (ch & 0x3f) << state;\n            if (state == 0)\n                push_back_u(codepoint);\n        }\n    }\n    // Write codepoint directly, possibly collating surrogate pairs\n    void push_back_u(unsigned int codepoint_)\n    {\n        if (state) // Only accept full codepoints in open state\n            is_valid = false;\n        if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair\n            if (surpair) // Two subsequent surrogate pair openers - fail\n                is_valid = false;\n            else\n                surpair = codepoint_;\n        } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair\n            if (surpair) { // Open surrogate pair, expect second half\n                // Compute code point from UTF-16 surrogate pair\n                append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00));\n                surpair = 0;\n            } else // Second half doesn't follow a first half - fail\n                is_valid = false;\n        } else {\n            if (surpair) // First half of surrogate pair not followed by second - fail\n                is_valid = false;\n            else\n                append_codepoint(codepoint_);\n        }\n    }\n    // Check that we're in a state where the string can be ended\n    // No open sequences, no open surrogate pairs, etc\n    bool finalize()\n    {\n        if (state || surpair)\n            is_valid = false;\n        return is_valid;\n    }\nprivate:\n    std::string &str;\n    bool is_valid;\n    // Current UTF-8 decoding state\n    unsigned int codepoint;\n    int state; // Top bit to be filled in for next UTF-8 byte, or 0\n\n    // Keep track of the following state to handle the following section of\n    // RFC4627:\n    //\n    //    To escape an extended character that is not in the Basic Multilingual\n    //    Plane, the character is represented as a twelve-character sequence,\n    //    encoding the UTF-16 surrogate pair.  So, for example, a string\n    //    containing only the G clef character (U+1D11E) may be represented as\n    //    \"\\uD834\\uDD1E\".\n    //\n    //  Two subsequent \\u.... may have to be replaced with one actual codepoint.\n    unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0\n\n    void append_codepoint(unsigned int codepoint_)\n    {\n        if (codepoint_ <= 0x7f)\n            str.push_back((char)codepoint_);\n        else if (codepoint_ <= 0x7FF) {\n            str.push_back((char)(0xC0 | (codepoint_ >> 6)));\n            str.push_back((char)(0x80 | (codepoint_ & 0x3F)));\n        } else if (codepoint_ <= 0xFFFF) {\n            str.push_back((char)(0xE0 | (codepoint_ >> 12)));\n            str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));\n            str.push_back((char)(0x80 | (codepoint_ & 0x3F)));\n        } else if (codepoint_ <= 0x1FFFFF) {\n            str.push_back((char)(0xF0 | (codepoint_ >> 18)));\n            str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F)));\n            str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));\n            str.push_back((char)(0x80 | (codepoint_ & 0x3F)));\n        }\n    }\n};\n\n#endif\n"
  },
  {
    "path": "src/univalue/lib/univalue_write.cpp",
    "content": "// Copyright 2014 BitPay Inc.\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <iomanip>\n#include <stdio.h>\n#include \"univalue.h\"\n#include \"univalue_escapes.h\"\n\nstatic std::string json_escape(const std::string& inS)\n{\n    std::string outS;\n    outS.reserve(inS.size() * 2);\n\n    for (unsigned int i = 0; i < inS.size(); i++) {\n        unsigned char ch = static_cast<unsigned char>(inS[i]);\n        const char *escStr = escapes[ch];\n\n        if (escStr)\n            outS += escStr;\n        else\n            outS += static_cast<char>(ch);\n    }\n\n    return outS;\n}\n\nstd::string UniValue::write(unsigned int prettyIndent,\n                            unsigned int indentLevel) const\n{\n    std::string s;\n    s.reserve(1024);\n\n    unsigned int modIndent = indentLevel;\n    if (modIndent == 0)\n        modIndent = 1;\n\n    switch (typ) {\n    case VNULL:\n        s += \"null\";\n        break;\n    case VOBJ:\n        writeObject(prettyIndent, modIndent, s);\n        break;\n    case VARR:\n        writeArray(prettyIndent, modIndent, s);\n        break;\n    case VSTR:\n        s += \"\\\"\" + json_escape(val) + \"\\\"\";\n        break;\n    case VNUM:\n        s += val;\n        break;\n    case VBOOL:\n        s += (val == \"1\" ? \"true\" : \"false\");\n        break;\n    }\n\n    return s;\n}\n\nstatic void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s)\n{\n    s.append(prettyIndent * indentLevel, ' ');\n}\n\nvoid UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const\n{\n    s += \"[\";\n    if (prettyIndent)\n        s += \"\\n\";\n\n    for (unsigned int i = 0; i < values.size(); i++) {\n        if (prettyIndent)\n            indentStr(prettyIndent, indentLevel, s);\n        s += values[i].write(prettyIndent, indentLevel + 1);\n        if (i != (values.size() - 1)) {\n            s += \",\";\n        }\n        if (prettyIndent)\n            s += \"\\n\";\n    }\n\n    if (prettyIndent)\n        indentStr(prettyIndent, indentLevel - 1, s);\n    s += \"]\";\n}\n\nvoid UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const\n{\n    s += \"{\";\n    if (prettyIndent)\n        s += \"\\n\";\n\n    for (unsigned int i = 0; i < keys.size(); i++) {\n        if (prettyIndent)\n            indentStr(prettyIndent, indentLevel, s);\n        s += \"\\\"\" + json_escape(keys[i]) + \"\\\":\";\n        if (prettyIndent)\n            s += \" \";\n        s += values.at(i).write(prettyIndent, indentLevel + 1);\n        if (i != (values.size() - 1))\n            s += \",\";\n        if (prettyIndent)\n            s += \"\\n\";\n    }\n\n    if (prettyIndent)\n        indentStr(prettyIndent, indentLevel - 1, s);\n    s += \"}\";\n}\n\n"
  },
  {
    "path": "src/univalue/pc/libunivalue-uninstalled.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libunivalue\nDescription: libunivalue, C++ universal value object and JSON library\nVersion: @VERSION@\nLibs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la\n"
  },
  {
    "path": "src/univalue/pc/libunivalue.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libunivalue\nDescription: libunivalue, C++ universal value object and JSON library\nVersion: @VERSION@\nLibs: -L${libdir} -lunivalue\nCflags: -I${includedir}\n"
  },
  {
    "path": "src/univalue/sources.mk",
    "content": "# - All variables are namespaced with UNIVALUE_ to avoid colliding with\n#     downstream makefiles.\n# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the\n#     _INT postfix is applied.\n# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used\n#     as they interfere with automatic dependency generation\n# - The %reldir% is the relative path from the Makefile.am. This allows\n#   downstreams to use these variables without having to manually account for\n#   the path change.\n\nUNIVALUE_INCLUDE_DIR_INT = %reldir%/include\n\nUNIVALUE_DIST_HEADERS_INT =\nUNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h\n\nUNIVALUE_LIB_HEADERS_INT =\nUNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h\nUNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h\n\nUNIVALUE_LIB_SOURCES_INT =\nUNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp\nUNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp\nUNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp\nUNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp\n\nUNIVALUE_TEST_DATA_DIR_INT = %reldir%/test\n\nUNIVALUE_TEST_UNITESTER_INT =\nUNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp\n\nUNIVALUE_TEST_JSON_INT =\nUNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp\n\nUNIVALUE_TEST_NO_NUL_INT =\nUNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp\n\nUNIVALUE_TEST_OBJECT_INT =\nUNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp\n\nUNIVALUE_TEST_FILES_INT =\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json\nUNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json\n"
  },
  {
    "path": "src/univalue/test/.gitignore",
    "content": "\nobject\nunitester\ntest_json\nno_nul\n\n*.trs\n*.log\n"
  },
  {
    "path": "src/univalue/test/fail1.json",
    "content": "\"This is a string that never ends, yes it goes on and on, my friends.\n"
  },
  {
    "path": "src/univalue/test/fail10.json",
    "content": "{\"Extra value after close\": true} \"misplaced quoted value\""
  },
  {
    "path": "src/univalue/test/fail11.json",
    "content": "{\"Illegal expression\": 1 + 2}"
  },
  {
    "path": "src/univalue/test/fail12.json",
    "content": "{\"Illegal invocation\": alert()}"
  },
  {
    "path": "src/univalue/test/fail13.json",
    "content": "{\"Numbers cannot have leading zeroes\": 013}"
  },
  {
    "path": "src/univalue/test/fail14.json",
    "content": "{\"Numbers cannot be hex\": 0x14}"
  },
  {
    "path": "src/univalue/test/fail15.json",
    "content": "[\"Illegal backslash escape: \\x15\"]"
  },
  {
    "path": "src/univalue/test/fail16.json",
    "content": "[\\naked]"
  },
  {
    "path": "src/univalue/test/fail17.json",
    "content": "[\"Illegal backslash escape: \\017\"]"
  },
  {
    "path": "src/univalue/test/fail18.json",
    "content": "[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]"
  },
  {
    "path": "src/univalue/test/fail19.json",
    "content": "{\"Missing colon\" null}"
  },
  {
    "path": "src/univalue/test/fail2.json",
    "content": "[\"Unclosed array\""
  },
  {
    "path": "src/univalue/test/fail20.json",
    "content": "{\"Double colon\":: null}"
  },
  {
    "path": "src/univalue/test/fail21.json",
    "content": "{\"Comma instead of colon\", null}"
  },
  {
    "path": "src/univalue/test/fail22.json",
    "content": "[\"Colon instead of comma\": false]"
  },
  {
    "path": "src/univalue/test/fail23.json",
    "content": "[\"Bad value\", truth]"
  },
  {
    "path": "src/univalue/test/fail24.json",
    "content": "['single quote']"
  },
  {
    "path": "src/univalue/test/fail25.json",
    "content": "[\"\ttab\tcharacter\tin\tstring\t\"]"
  },
  {
    "path": "src/univalue/test/fail26.json",
    "content": "[\"tab\\   character\\   in\\  string\\  \"]"
  },
  {
    "path": "src/univalue/test/fail27.json",
    "content": "[\"line\nbreak\"]"
  },
  {
    "path": "src/univalue/test/fail28.json",
    "content": "[\"line\\\nbreak\"]"
  },
  {
    "path": "src/univalue/test/fail29.json",
    "content": "[0e]"
  },
  {
    "path": "src/univalue/test/fail3.json",
    "content": "{unquoted_key: \"keys must be quoted\"}"
  },
  {
    "path": "src/univalue/test/fail30.json",
    "content": "[0e+]"
  },
  {
    "path": "src/univalue/test/fail31.json",
    "content": "[0e+-1]"
  },
  {
    "path": "src/univalue/test/fail32.json",
    "content": "{\"Comma instead if closing brace\": true,"
  },
  {
    "path": "src/univalue/test/fail33.json",
    "content": "[\"mismatch\"}"
  },
  {
    "path": "src/univalue/test/fail34.json",
    "content": "{} garbage"
  },
  {
    "path": "src/univalue/test/fail35.json",
    "content": "[ true true true [] [] [] ]\n"
  },
  {
    "path": "src/univalue/test/fail36.json",
    "content": "{\"a\":}\n"
  },
  {
    "path": "src/univalue/test/fail37.json",
    "content": "{\"a\":1 \"b\":2}\n"
  },
  {
    "path": "src/univalue/test/fail38.json",
    "content": "[\"\\ud834\"]\n"
  },
  {
    "path": "src/univalue/test/fail39.json",
    "content": "[\"\\udd61\"]\n"
  },
  {
    "path": "src/univalue/test/fail4.json",
    "content": "[\"extra comma\",]"
  },
  {
    "path": "src/univalue/test/fail40.json",
    "content": "[\"\"]"
  },
  {
    "path": "src/univalue/test/fail41.json",
    "content": "[\"\"]"
  },
  {
    "path": "src/univalue/test/fail44.json",
    "content": "\"This file ends without a newline or close-quote."
  },
  {
    "path": "src/univalue/test/fail45.json",
    "content": "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\n"
  },
  {
    "path": "src/univalue/test/fail5.json",
    "content": "[\"double extra comma\",,]"
  },
  {
    "path": "src/univalue/test/fail6.json",
    "content": "[   , \"<-- missing value\"]"
  },
  {
    "path": "src/univalue/test/fail7.json",
    "content": "[\"Comma after the close\"],"
  },
  {
    "path": "src/univalue/test/fail8.json",
    "content": "[\"Extra close\"]]"
  },
  {
    "path": "src/univalue/test/fail9.json",
    "content": "{\"Extra comma\": true,}"
  },
  {
    "path": "src/univalue/test/no_nul.cpp",
    "content": "#include \"univalue.h\"\n\nint main (int argc, char *argv[])\n{\n    char buf[] = \"___[1,2,3]___\";\n    UniValue val;\n    return val.read(buf + 3, 7) ? 0 : 1;\n}\n"
  },
  {
    "path": "src/univalue/test/object.cpp",
    "content": "// Copyright (c) 2014 BitPay Inc.\n// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <stdint.h>\n#include <vector>\n#include <string>\n#include <map>\n#include <cassert>\n#include <stdexcept>\n#include <univalue.h>\n\n#define BOOST_FIXTURE_TEST_SUITE(a, b)\n#define BOOST_AUTO_TEST_CASE(funcName) void funcName()\n#define BOOST_AUTO_TEST_SUITE_END()\n#define BOOST_CHECK(expr) assert(expr)\n#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))\n#define BOOST_CHECK_THROW(stmt, excMatch) { \\\n        try { \\\n            (stmt); \\\n            assert(0 && \"No exception caught\"); \\\n        } catch (excMatch & e) { \\\n\t} catch (...) { \\\n\t    assert(0 && \"Wrong exception caught\"); \\\n\t} \\\n    }\n#define BOOST_CHECK_NO_THROW(stmt) { \\\n        try { \\\n            (stmt); \\\n\t} catch (...) { \\\n\t    assert(0); \\\n\t} \\\n    }\n\nBOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)\n\nBOOST_AUTO_TEST_CASE(univalue_constructor)\n{\n    UniValue v1;\n    BOOST_CHECK(v1.isNull());\n\n    UniValue v2(UniValue::VSTR);\n    BOOST_CHECK(v2.isStr());\n\n    UniValue v3(UniValue::VSTR, \"foo\");\n    BOOST_CHECK(v3.isStr());\n    BOOST_CHECK_EQUAL(v3.getValStr(), \"foo\");\n\n    UniValue numTest;\n    BOOST_CHECK(numTest.setNumStr(\"82\"));\n    BOOST_CHECK(numTest.isNum());\n    BOOST_CHECK_EQUAL(numTest.getValStr(), \"82\");\n\n    uint64_t vu64 = 82;\n    UniValue v4(vu64);\n    BOOST_CHECK(v4.isNum());\n    BOOST_CHECK_EQUAL(v4.getValStr(), \"82\");\n\n    int64_t vi64 = -82;\n    UniValue v5(vi64);\n    BOOST_CHECK(v5.isNum());\n    BOOST_CHECK_EQUAL(v5.getValStr(), \"-82\");\n\n    int vi = -688;\n    UniValue v6(vi);\n    BOOST_CHECK(v6.isNum());\n    BOOST_CHECK_EQUAL(v6.getValStr(), \"-688\");\n\n    double vd = -7.21;\n    UniValue v7(vd);\n    BOOST_CHECK(v7.isNum());\n    BOOST_CHECK_EQUAL(v7.getValStr(), \"-7.21\");\n\n    std::string vs(\"yawn\");\n    UniValue v8(vs);\n    BOOST_CHECK(v8.isStr());\n    BOOST_CHECK_EQUAL(v8.getValStr(), \"yawn\");\n\n    const char *vcs = \"zappa\";\n    UniValue v9(vcs);\n    BOOST_CHECK(v9.isStr());\n    BOOST_CHECK_EQUAL(v9.getValStr(), \"zappa\");\n}\n\nBOOST_AUTO_TEST_CASE(univalue_typecheck)\n{\n    UniValue v1;\n    BOOST_CHECK(v1.setNumStr(\"1\"));\n    BOOST_CHECK(v1.isNum());\n    BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);\n\n    UniValue v2;\n    BOOST_CHECK(v2.setBool(true));\n    BOOST_CHECK_EQUAL(v2.get_bool(), true);\n    BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);\n\n    UniValue v3;\n    BOOST_CHECK(v3.setNumStr(\"32482348723847471234\"));\n    BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);\n    BOOST_CHECK(v3.setNumStr(\"1000\"));\n    BOOST_CHECK_EQUAL(v3.get_int64(), 1000);\n\n    UniValue v4;\n    BOOST_CHECK(v4.setNumStr(\"2147483648\"));\n    BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);\n    BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);\n    BOOST_CHECK(v4.setNumStr(\"1000\"));\n    BOOST_CHECK_EQUAL(v4.get_int(), 1000);\n    BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);\n    BOOST_CHECK_EQUAL(v4.get_real(), 1000);\n    BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);\n    BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);\n\n    UniValue v5;\n    BOOST_CHECK(v5.read(\"[true, 10]\"));\n    BOOST_CHECK_NO_THROW(v5.get_array());\n    std::vector<UniValue> vals = v5.getValues();\n    BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);\n    BOOST_CHECK_EQUAL(vals[0].get_bool(), true);\n\n    BOOST_CHECK_EQUAL(vals[1].get_int(), 10);\n    BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);\n}\n\nBOOST_AUTO_TEST_CASE(univalue_set)\n{\n    UniValue v(UniValue::VSTR, \"foo\");\n    v.clear();\n    BOOST_CHECK(v.isNull());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"\");\n\n    BOOST_CHECK(v.setObject());\n    BOOST_CHECK(v.isObject());\n    BOOST_CHECK_EQUAL(v.size(), 0);\n    BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);\n    BOOST_CHECK(v.empty());\n\n    BOOST_CHECK(v.setArray());\n    BOOST_CHECK(v.isArray());\n    BOOST_CHECK_EQUAL(v.size(), 0);\n\n    BOOST_CHECK(v.setStr(\"zum\"));\n    BOOST_CHECK(v.isStr());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"zum\");\n\n    BOOST_CHECK(v.setFloat(-1.01));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-1.01\");\n\n    BOOST_CHECK(v.setInt((int)1023));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"1023\");\n\n    BOOST_CHECK(v.setInt((int64_t)-1023LL));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-1023\");\n\n    BOOST_CHECK(v.setInt((uint64_t)1023ULL));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"1023\");\n\n    BOOST_CHECK(v.setNumStr(\"-688\"));\n    BOOST_CHECK(v.isNum());\n    BOOST_CHECK_EQUAL(v.getValStr(), \"-688\");\n\n    BOOST_CHECK(v.setBool(false));\n    BOOST_CHECK_EQUAL(v.isBool(), true);\n    BOOST_CHECK_EQUAL(v.isTrue(), false);\n    BOOST_CHECK_EQUAL(v.isFalse(), true);\n    BOOST_CHECK_EQUAL(v.getBool(), false);\n\n    BOOST_CHECK(v.setBool(true));\n    BOOST_CHECK_EQUAL(v.isBool(), true);\n    BOOST_CHECK_EQUAL(v.isTrue(), true);\n    BOOST_CHECK_EQUAL(v.isFalse(), false);\n    BOOST_CHECK_EQUAL(v.getBool(), true);\n\n    BOOST_CHECK(!v.setNumStr(\"zombocom\"));\n\n    BOOST_CHECK(v.setNull());\n    BOOST_CHECK(v.isNull());\n}\n\nBOOST_AUTO_TEST_CASE(univalue_array)\n{\n    UniValue arr(UniValue::VARR);\n\n    UniValue v((int64_t)1023LL);\n    BOOST_CHECK(arr.push_back(v));\n\n    std::string vStr(\"zippy\");\n    BOOST_CHECK(arr.push_back(vStr));\n\n    const char *s = \"pippy\";\n    BOOST_CHECK(arr.push_back(s));\n\n    std::vector<UniValue> vec;\n    v.setStr(\"boing\");\n    vec.push_back(v);\n\n    v.setStr(\"going\");\n    vec.push_back(v);\n\n    BOOST_CHECK(arr.push_backV(vec));\n\n    BOOST_CHECK(arr.push_back((uint64_t) 400ULL));\n    BOOST_CHECK(arr.push_back((int64_t) -400LL));\n    BOOST_CHECK(arr.push_back((int) -401));\n    BOOST_CHECK(arr.push_back(-40.1));\n    BOOST_CHECK(arr.push_back(true));\n\n    BOOST_CHECK_EQUAL(arr.empty(), false);\n    BOOST_CHECK_EQUAL(arr.size(), 10);\n\n    BOOST_CHECK_EQUAL(arr[0].getValStr(), \"1023\");\n    BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM);\n    BOOST_CHECK_EQUAL(arr[1].getValStr(), \"zippy\");\n    BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR);\n    BOOST_CHECK_EQUAL(arr[2].getValStr(), \"pippy\");\n    BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR);\n    BOOST_CHECK_EQUAL(arr[3].getValStr(), \"boing\");\n    BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR);\n    BOOST_CHECK_EQUAL(arr[4].getValStr(), \"going\");\n    BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR);\n    BOOST_CHECK_EQUAL(arr[5].getValStr(), \"400\");\n    BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM);\n    BOOST_CHECK_EQUAL(arr[6].getValStr(), \"-400\");\n    BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM);\n    BOOST_CHECK_EQUAL(arr[7].getValStr(), \"-401\");\n    BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM);\n    BOOST_CHECK_EQUAL(arr[8].getValStr(), \"-40.1\");\n    BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM);\n    BOOST_CHECK_EQUAL(arr[9].getValStr(), \"1\");\n    BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL);\n\n    BOOST_CHECK_EQUAL(arr[999].getValStr(), \"\");\n\n    arr.clear();\n    BOOST_CHECK(arr.empty());\n    BOOST_CHECK_EQUAL(arr.size(), 0);\n}\n\nBOOST_AUTO_TEST_CASE(univalue_object)\n{\n    UniValue obj(UniValue::VOBJ);\n    std::string strKey, strVal;\n    UniValue v;\n\n    strKey = \"age\";\n    v.setInt(100);\n    BOOST_CHECK(obj.pushKV(strKey, v));\n\n    strKey = \"first\";\n    strVal = \"John\";\n    BOOST_CHECK(obj.pushKV(strKey, strVal));\n\n    strKey = \"last\";\n    const char *cVal = \"Smith\";\n    BOOST_CHECK(obj.pushKV(strKey, cVal));\n\n    strKey = \"distance\";\n    BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));\n\n    strKey = \"time\";\n    BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));\n\n    strKey = \"calories\";\n    BOOST_CHECK(obj.pushKV(strKey, (int) 12));\n\n    strKey = \"temperature\";\n    BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));\n\n    strKey = \"moon\";\n    BOOST_CHECK(obj.pushKV(strKey, true));\n\n    strKey = \"spoon\";\n    BOOST_CHECK(obj.pushKV(strKey, false));\n\n    UniValue obj2(UniValue::VOBJ);\n    BOOST_CHECK(obj2.pushKV(\"cat1\", 9000));\n    BOOST_CHECK(obj2.pushKV(\"cat2\", 12345));\n\n    BOOST_CHECK(obj.pushKVs(obj2));\n\n    BOOST_CHECK_EQUAL(obj.empty(), false);\n    BOOST_CHECK_EQUAL(obj.size(), 11);\n\n    BOOST_CHECK_EQUAL(obj[\"age\"].getValStr(), \"100\");\n    BOOST_CHECK_EQUAL(obj[\"first\"].getValStr(), \"John\");\n    BOOST_CHECK_EQUAL(obj[\"last\"].getValStr(), \"Smith\");\n    BOOST_CHECK_EQUAL(obj[\"distance\"].getValStr(), \"25\");\n    BOOST_CHECK_EQUAL(obj[\"time\"].getValStr(), \"3600\");\n    BOOST_CHECK_EQUAL(obj[\"calories\"].getValStr(), \"12\");\n    BOOST_CHECK_EQUAL(obj[\"temperature\"].getValStr(), \"90.012\");\n    BOOST_CHECK_EQUAL(obj[\"moon\"].getValStr(), \"1\");\n    BOOST_CHECK_EQUAL(obj[\"spoon\"].getValStr(), \"\");\n    BOOST_CHECK_EQUAL(obj[\"cat1\"].getValStr(), \"9000\");\n    BOOST_CHECK_EQUAL(obj[\"cat2\"].getValStr(), \"12345\");\n\n    BOOST_CHECK_EQUAL(obj[\"nyuknyuknyuk\"].getValStr(), \"\");\n\n    BOOST_CHECK(obj.exists(\"age\"));\n    BOOST_CHECK(obj.exists(\"first\"));\n    BOOST_CHECK(obj.exists(\"last\"));\n    BOOST_CHECK(obj.exists(\"distance\"));\n    BOOST_CHECK(obj.exists(\"time\"));\n    BOOST_CHECK(obj.exists(\"calories\"));\n    BOOST_CHECK(obj.exists(\"temperature\"));\n    BOOST_CHECK(obj.exists(\"moon\"));\n    BOOST_CHECK(obj.exists(\"spoon\"));\n    BOOST_CHECK(obj.exists(\"cat1\"));\n    BOOST_CHECK(obj.exists(\"cat2\"));\n\n    BOOST_CHECK(!obj.exists(\"nyuknyuknyuk\"));\n\n    std::map<std::string, UniValue::VType> objTypes;\n    objTypes[\"age\"] = UniValue::VNUM;\n    objTypes[\"first\"] = UniValue::VSTR;\n    objTypes[\"last\"] = UniValue::VSTR;\n    objTypes[\"distance\"] = UniValue::VNUM;\n    objTypes[\"time\"] = UniValue::VNUM;\n    objTypes[\"calories\"] = UniValue::VNUM;\n    objTypes[\"temperature\"] = UniValue::VNUM;\n    objTypes[\"moon\"] = UniValue::VBOOL;\n    objTypes[\"spoon\"] = UniValue::VBOOL;\n    objTypes[\"cat1\"] = UniValue::VNUM;\n    objTypes[\"cat2\"] = UniValue::VNUM;\n    BOOST_CHECK(obj.checkObject(objTypes));\n\n    objTypes[\"cat2\"] = UniValue::VSTR;\n    BOOST_CHECK(!obj.checkObject(objTypes));\n\n    obj.clear();\n    BOOST_CHECK(obj.empty());\n    BOOST_CHECK_EQUAL(obj.size(), 0);\n    BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);\n\n    BOOST_CHECK_EQUAL(obj.setObject(), true);\n    UniValue uv;\n    uv.setInt(42);\n    obj.__pushKV(\"age\", uv);\n    BOOST_CHECK_EQUAL(obj.size(), 1);\n    BOOST_CHECK_EQUAL(obj[\"age\"].getValStr(), \"42\");\n\n    uv.setInt(43);\n    obj.pushKV(\"age\", uv);\n    BOOST_CHECK_EQUAL(obj.size(), 1);\n    BOOST_CHECK_EQUAL(obj[\"age\"].getValStr(), \"43\");\n\n    obj.pushKV(\"name\", \"foo bar\");\n\n    std::map<std::string,UniValue> kv;\n    obj.getObjMap(kv);\n    BOOST_CHECK_EQUAL(kv[\"age\"].getValStr(), \"43\");\n    BOOST_CHECK_EQUAL(kv[\"name\"].getValStr(), \"foo bar\");\n\n}\n\nstatic const char *json1 =\n\"[1.10000000,{\\\"key1\\\":\\\"str\\\\u0000\\\",\\\"key2\\\":800,\\\"key3\\\":{\\\"name\\\":\\\"martian http://test.com\\\"}}]\";\n\nBOOST_AUTO_TEST_CASE(univalue_readwrite)\n{\n    UniValue v;\n    BOOST_CHECK(v.read(json1));\n\n    std::string strJson1(json1);\n    BOOST_CHECK(v.read(strJson1));\n\n    BOOST_CHECK(v.isArray());\n    BOOST_CHECK_EQUAL(v.size(), 2);\n\n    BOOST_CHECK_EQUAL(v[0].getValStr(), \"1.10000000\");\n\n    UniValue obj = v[1];\n    BOOST_CHECK(obj.isObject());\n    BOOST_CHECK_EQUAL(obj.size(), 3);\n\n    BOOST_CHECK(obj[\"key1\"].isStr());\n    std::string correctValue(\"str\");\n    correctValue.push_back('\\0');\n    BOOST_CHECK_EQUAL(obj[\"key1\"].getValStr(), correctValue);\n    BOOST_CHECK(obj[\"key2\"].isNum());\n    BOOST_CHECK_EQUAL(obj[\"key2\"].getValStr(), \"800\");\n    BOOST_CHECK(obj[\"key3\"].isObject());\n\n    BOOST_CHECK_EQUAL(strJson1, v.write());\n\n    /* Check for (correctly reporting) a parsing error if the initial\n       JSON construct is followed by more stuff.  Note that whitespace\n       is, of course, exempt.  */\n\n    BOOST_CHECK(v.read(\"  {}\\n  \"));\n    BOOST_CHECK(v.isObject());\n    BOOST_CHECK(v.read(\"  []\\n  \"));\n    BOOST_CHECK(v.isArray());\n\n    BOOST_CHECK(!v.read(\"@{}\"));\n    BOOST_CHECK(!v.read(\"{} garbage\"));\n    BOOST_CHECK(!v.read(\"[]{}\"));\n    BOOST_CHECK(!v.read(\"{}[]\"));\n    BOOST_CHECK(!v.read(\"{} 42\"));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nint main (int argc, char *argv[])\n{\n    univalue_constructor();\n    univalue_typecheck();\n    univalue_set();\n    univalue_array();\n    univalue_object();\n    univalue_readwrite();\n    return 0;\n}\n\n"
  },
  {
    "path": "src/univalue/test/pass1.json",
    "content": "[\n    \"JSON Test Pattern pass1\",\n    {\"object with 1 member\":[\"array with 1 element\"]},\n    {},\n    [],\n    -42,\n    true,\n    false,\n    null,\n    {\n        \"integer\": 1234567890,\n        \"real\": -9876.543210,\n        \"e\": 0.123456789e-12,\n        \"E\": 1.234567890E+34,\n        \"\":  23456789012E66,\n        \"zero\": 0,\n        \"one\": 1,\n        \"space\": \" \",\n        \"quote\": \"\\\"\",\n        \"backslash\": \"\\\\\",\n        \"controls\": \"\\b\\f\\n\\r\\t\",\n        \"slash\": \"/ & \\/\",\n        \"alpha\": \"abcdefghijklmnopqrstuvwyz\",\n        \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",\n        \"digit\": \"0123456789\",\n        \"0123456789\": \"digit\",\n        \"special\": \"`1~!@#$%^&*()_+-={':[,]}|;.</>?\",\n        \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\n        \"true\": true,\n        \"false\": false,\n        \"null\": null,\n        \"array\":[  ],\n        \"object\":{  },\n        \"address\": \"50 St. James Street\",\n        \"url\": \"http://www.JSON.org/\",\n        \"comment\": \"// /* <!-- --\",\n        \"# -- --> */\": \" \",\n        \" s p a c e d \" :[1,2 , 3\n\n,\n\n4 , 5        ,          6           ,7        ],\"compact\":[1,2,3,4,5,6,7],\n        \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",\n        \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",\n        \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\"\n: \"A key can be any string\"\n    },\n    0.5 ,98.6\n,\n99.44\n,\n\n1066,\n1e1,\n0.1e1,\n1e-1,\n1e00,2e+00,2e-00\n,\"rosebud\"]"
  },
  {
    "path": "src/univalue/test/pass2.json",
    "content": "[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]"
  },
  {
    "path": "src/univalue/test/pass3.json",
    "content": "{\n    \"JSON Test Pattern pass3\": {\n        \"The outermost value\": \"must be an object or array.\",\n        \"In this test\": \"It is an object.\"\n    }\n}\n"
  },
  {
    "path": "src/univalue/test/pass4.json",
    "content": "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\n"
  },
  {
    "path": "src/univalue/test/round1.json",
    "content": "[\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007f\"]\n"
  },
  {
    "path": "src/univalue/test/round2.json",
    "content": "[\"a§■𐎒𝅘𝅥𝅯\"]\n"
  },
  {
    "path": "src/univalue/test/round3.json",
    "content": "\"abcdefghijklmnopqrstuvwxyz\"\n"
  },
  {
    "path": "src/univalue/test/round4.json",
    "content": "7\n"
  },
  {
    "path": "src/univalue/test/round5.json",
    "content": "true\n"
  },
  {
    "path": "src/univalue/test/round6.json",
    "content": "false\n"
  },
  {
    "path": "src/univalue/test/round7.json",
    "content": "null\n"
  },
  {
    "path": "src/univalue/test/test_json.cpp",
    "content": "// Test program that can be called by the JSON test suite at\n// https://github.com/nst/JSONTestSuite.\n//\n// It reads JSON input from stdin and exits with code 0 if it can be parsed\n// successfully. It also pretty prints the parsed JSON value to stdout.\n\n#include <iostream>\n#include <string>\n#include \"univalue.h\"\n\nusing namespace std;\n\nint main (int argc, char *argv[])\n{\n    UniValue val;\n    if (val.read(string(istreambuf_iterator<char>(cin),\n                        istreambuf_iterator<char>()))) {\n        cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl;\n        return 0;\n    } else {\n        cerr << \"JSON Parse Error.\" << endl;\n        return 1;\n    }\n}\n"
  },
  {
    "path": "src/univalue/test/unitester.cpp",
    "content": "// Copyright 2014 BitPay Inc.\n// Distributed under the MIT/X11 software license, see the accompanying\n// file COPYING or https://opensource.org/licenses/mit-license.php.\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <cassert>\n#include <string>\n#include \"univalue.h\"\n\n#ifndef JSON_TEST_SRC\n#error JSON_TEST_SRC must point to test source directory\n#endif\n\n#ifndef ARRAY_SIZE\n#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))\n#endif\n\nstd::string srcdir(JSON_TEST_SRC);\nstatic bool test_failed = false;\n\n#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, \"%s failed\\n\", filename.c_str()); } }\n#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, \"%s failed\\n\", __func__); } }\n\nstatic std::string rtrim(std::string s)\n{\n    s.erase(s.find_last_not_of(\" \\n\\r\\t\")+1);\n    return s;\n}\n\nstatic void runtest(std::string filename, const std::string& jdata)\n{\n        std::string prefix = filename.substr(0, 4);\n\n        bool wantPass = (prefix == \"pass\") || (prefix == \"roun\");\n        bool wantFail = (prefix == \"fail\");\n        bool wantRoundTrip = (prefix == \"roun\");\n        assert(wantPass || wantFail);\n\n        UniValue val;\n        bool testResult = val.read(jdata);\n\n        if (wantPass) {\n            d_assert(testResult == true);\n        } else {\n            d_assert(testResult == false);\n        }\n\n        if (wantRoundTrip) {\n            std::string odata = val.write(0, 0);\n            assert(odata == rtrim(jdata));\n        }\n}\n\nstatic void runtest_file(const char *filename_)\n{\n        std::string basename(filename_);\n        std::string filename = srcdir + \"/\" + basename;\n        FILE *f = fopen(filename.c_str(), \"r\");\n        assert(f != nullptr);\n\n        std::string jdata;\n\n        char buf[4096];\n        while (!feof(f)) {\n                int bread = fread(buf, 1, sizeof(buf), f);\n                assert(!ferror(f));\n\n                std::string s(buf, bread);\n                jdata += s;\n        }\n\n        assert(!ferror(f));\n        fclose(f);\n\n        runtest(basename, jdata);\n}\n\nstatic const char *filenames[] = {\n        \"fail10.json\",\n        \"fail11.json\",\n        \"fail12.json\",\n        \"fail13.json\",\n        \"fail14.json\",\n        \"fail15.json\",\n        \"fail16.json\",\n        \"fail17.json\",\n        //\"fail18.json\",             // investigate\n        \"fail19.json\",\n        \"fail1.json\",\n        \"fail20.json\",\n        \"fail21.json\",\n        \"fail22.json\",\n        \"fail23.json\",\n        \"fail24.json\",\n        \"fail25.json\",\n        \"fail26.json\",\n        \"fail27.json\",\n        \"fail28.json\",\n        \"fail29.json\",\n        \"fail2.json\",\n        \"fail30.json\",\n        \"fail31.json\",\n        \"fail32.json\",\n        \"fail33.json\",\n        \"fail34.json\",\n        \"fail35.json\",\n        \"fail36.json\",\n        \"fail37.json\",\n        \"fail38.json\",               // invalid unicode: only first half of surrogate pair\n        \"fail39.json\",               // invalid unicode: only second half of surrogate pair\n        \"fail40.json\",               // invalid unicode: broken UTF-8\n        \"fail41.json\",               // invalid unicode: unfinished UTF-8\n        \"fail42.json\",               // valid json with garbage following a nul byte\n        \"fail44.json\",               // unterminated string\n        \"fail45.json\",               // nested beyond max depth\n        \"fail3.json\",\n        \"fail4.json\",                // extra comma\n        \"fail5.json\",\n        \"fail6.json\",\n        \"fail7.json\",\n        \"fail8.json\",\n        \"fail9.json\",               // extra comma\n        \"pass1.json\",\n        \"pass2.json\",\n        \"pass3.json\",\n        \"pass4.json\",\n        \"round1.json\",              // round-trip test\n        \"round2.json\",              // unicode\n        \"round3.json\",              // bare string\n        \"round4.json\",              // bare number\n        \"round5.json\",              // bare true\n        \"round6.json\",              // bare false\n        \"round7.json\",              // bare null\n};\n\n// Test \\u handling\nvoid unescape_unicode_test()\n{\n    UniValue val;\n    bool testResult;\n    // Escaped ASCII (quote)\n    testResult = val.read(\"[\\\"\\\\u0022\\\"]\");\n    f_assert(testResult);\n    f_assert(val[0].get_str() == \"\\\"\");\n    // Escaped Basic Plane character, two-byte UTF-8\n    testResult = val.read(\"[\\\"\\\\u0191\\\"]\");\n    f_assert(testResult);\n    f_assert(val[0].get_str() == \"\\xc6\\x91\");\n    // Escaped Basic Plane character, three-byte UTF-8\n    testResult = val.read(\"[\\\"\\\\u2191\\\"]\");\n    f_assert(testResult);\n    f_assert(val[0].get_str() == \"\\xe2\\x86\\x91\");\n    // Escaped Supplementary Plane character U+1d161\n    testResult = val.read(\"[\\\"\\\\ud834\\\\udd61\\\"]\");\n    f_assert(testResult);\n    f_assert(val[0].get_str() == \"\\xf0\\x9d\\x85\\xa1\");\n}\n\nint main (int argc, char *argv[])\n{\n    for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) {\n        runtest_file(filenames[fidx]);\n    }\n\n    unescape_unicode_test();\n\n    return test_failed ? 1 : 0;\n}\n\n"
  },
  {
    "path": "src/util/bytevectorhash.cpp",
    "content": "// Copyright (c) 2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <hash.h>\n#include <random.h>\n#include \"bytevectorhash.h\"\n\nByteVectorHash::ByteVectorHash()\n{\n    GetRandBytes(reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0));\n    GetRandBytes(reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1));\n}\n\nsize_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const\n{\n    return CSipHasher(m_k0, m_k1).Write(input.data(), input.size()).Finalize();\n}\n"
  },
  {
    "path": "src/util/bytevectorhash.h",
    "content": "// Copyright (c) 2018 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_UTIL_BYTEVECTORHASH_H\n#define BITCOIN_UTIL_BYTEVECTORHASH_H\n\n#include <stdint.h>\n#include <vector>\n\n/**\n * Implementation of Hash named requirement for types that internally store a byte array. This may\n * be used as the hash function in std::unordered_set or std::unordered_map over such types.\n * Internally, this uses a random instance of SipHash-2-4.\n */\nclass ByteVectorHash final\n{\nprivate:\n    uint64_t m_k0, m_k1;\n\npublic:\n    ByteVectorHash();\n    size_t operator()(const std::vector<unsigned char>& input) const;\n};\n\n#endif // BITCOIN_UTIL_BYTEVECTORHASH_H\n"
  },
  {
    "path": "src/util/check.h",
    "content": "// Copyright (c) 2019-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_CHECK_H\n#define CORE_UTIL_CHECK_H\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif\n\n#include <tinyformat.h>\n\n#include <stdexcept>\n\nclass NonFatalCheckError : public std::runtime_error\n{\n    using std::runtime_error::runtime_error;\n};\n\n/**\n * Throw a NonFatalCheckError when the condition evaluates to false\n *\n * This should only be used\n * - where the condition is assumed to be true, not for error handling or validating user input\n * - where a failure to fulfill the condition is recoverable and does not abort the program\n *\n * For example in RPC code, where it is undesirable to crash the whole program, this can be generally used to replace\n * asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC\n * caller, which can then report the issue to the developers.\n */\n#define CHECK_NONFATAL(condition)                                 \\\n    do {                                                          \\\n        if (!(condition)) {                                       \\\n            throw NonFatalCheckError(                             \\\n                strprintf(\"Internal bug detected: '%s'\\n\"         \\\n                          \"%s:%d (%s)\\n\"                          \\\n                          \"You may report this issue here: %s\\n\", \\\n                    (#condition),                                 \\\n                    __FILE__, __LINE__, __func__,                 \\\n                    PACKAGE_BUGREPORT));                          \\\n        }                                                         \\\n    } while (false)\n\n#if defined(NDEBUG)\n#error \"Cannot compile without assertions!\"\n#endif\n\n/** Helper for Assert() */\ntemplate <typename T>\nT get_pure_r_value(T&& val)\n{\n    return std::forward<T>(val);\n}\n\n/** Identity function. Abort if the value compares equal to zero */\n#define Assert(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }())\n\n/**\n * Assume is the identity function.\n *\n * - Should be used to run non-fatal checks. In debug builds it behaves like\n *   Assert()/assert() to notify developers and testers about non-fatal errors.\n *   In production it doesn't warn or log anything.\n * - For fatal errors, use Assert().\n * - For non-fatal errors in interactive sessions (e.g. RPC or command line\n *   interfaces), CHECK_NONFATAL() might be more appropriate.\n */\n#ifdef ABORT_ON_FAILED_ASSUME\n#define Assume(val) Assert(val)\n#else\n#define Assume(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); return std::forward<decltype(get_pure_r_value(val))>(check); }())\n#endif\n\n#endif // CORE_UTIL_CHECK_H\n"
  },
  {
    "path": "src/util/getuniquepath.cpp",
    "content": "// Copyright (c) 2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <random.h>\n#include <fs.h>\n#include <util/strencodings.h>\n\nfs::path GetUniquePath(const fs::path& base)\n{\n    FastRandomContext rnd;\n    fs::path tmpFile = base / HexStr(rnd.randbytes(8));\n    return tmpFile;\n}\n"
  },
  {
    "path": "src/util/getuniquepath.h",
    "content": "// Copyright (c) 2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_GETUNIQUEPATH_H\n#define CORE_UTIL_GETUNIQUEPATH_H\n\n#include <fs.h>\n\n/**\n * Helper function for getting a unique path\n *\n * @param[in] base  Base path\n * @returns base joined with a random 8-character long string.\n * @post Returned path is unique with high probability.\n */\nfs::path GetUniquePath(const fs::path& base);\n\n#endif // CORE_UTIL_GETUNIQUEPATH_H\n"
  },
  {
    "path": "src/util/macros.h",
    "content": "// Copyright (c) 2019-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_MACROS_H\n#define CORE_UTIL_MACROS_H\n\n#define PASTE(x, y) x ## y\n#define PASTE2(x, y) PASTE(x, y)\n\n/**\n * Converts the parameter X to a string after macro replacement on X has been performed.\n * Don't merge these into one macro!\n */\n#define STRINGIZE(X) DO_STRINGIZE(X)\n#define DO_STRINGIZE(X) #X\n\n#endif // CORE_UTIL_MACROS_H\n"
  },
  {
    "path": "src/util/moneystr.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"util/moneystr.h\"\n\n#include \"primitives/transaction.h\"\n#include \"tinyformat.h\"\n#include \"util/strencodings.h\"\n\nstd::string FormatMoney(const CAmount& n)\n{\n    // Note: not using straight sprintf here because we do NOT want\n    // localized number formatting.\n    int64_t n_abs = (n > 0 ? n : -n);\n    int64_t quotient = n_abs/COIN;\n    int64_t remainder = n_abs%COIN;\n    std::string str = strprintf(\"%d.%08d\", quotient, remainder);\n\n    // Right-trim excess zeros before the decimal point:\n    int nTrim = 0;\n    for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)\n        ++nTrim;\n    if (nTrim)\n        str.erase(str.size()-nTrim, nTrim);\n\n    if (n < 0)\n        str.insert((unsigned int)0, 1, '-');\n    return str;\n}\n\n\nbool ParseMoney(const std::string& str, CAmount& nRet)\n{\n    return ParseMoney(str.c_str(), nRet);\n}\n\nbool ParseMoney(const char* pszIn, CAmount& nRet)\n{\n    std::string strWhole;\n    int64_t nUnits = 0;\n    const char* p = pszIn;\n    while (isspace(*p))\n        p++;\n    for (; *p; p++)\n    {\n        if (*p == '.')\n        {\n            p++;\n            int64_t nMult = CENT*10;\n            while (isdigit(*p) && (nMult > 0))\n            {\n                nUnits += nMult * (*p++ - '0');\n                nMult /= 10;\n            }\n            break;\n        }\n        if (isspace(*p))\n            break;\n        if (!isdigit(*p))\n            return false;\n        strWhole.insert(strWhole.end(), *p);\n    }\n    for (; *p; p++)\n        if (!isspace(*p))\n            return false;\n    if (strWhole.size() > 10) // guard against 63 bit overflow\n        return false;\n    if (nUnits < 0 || nUnits > COIN)\n        return false;\n    int64_t nWhole = atoi64(strWhole);\n    CAmount nValue = nWhole*COIN + nUnits;\n\n    nRet = nValue;\n    return true;\n}\n"
  },
  {
    "path": "src/util/moneystr.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n/**\n * Money parsing/formatting utilities.\n */\n#ifndef UTIL_MONEY_STR_H\n#define UTIL_MONEY_STR_H\n\n#include <stdint.h>\n#include <string>\n\n#include \"amount.h\"\n\nstd::string FormatMoney(const CAmount& n);\nbool ParseMoney(const std::string& str, CAmount& nRet);\nbool ParseMoney(const char* pszIn, CAmount& nRet);\n\n#endif //UTIL_MONEY_STR_H\n"
  },
  {
    "path": "src/util/overloaded.h",
    "content": "// Copyright (c) 2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_OVERLOADED_H\n#define CORE_UTIL_OVERLOADED_H\n\nnamespace util {\n//! Overloaded helper for std::visit. This helper and std::visit in general are\n//! useful to write code that switches on a variant type. Unlike if/else-if and\n//! switch/case statements, std::visit will trigger compile errors if there are\n//! unhandled cases.\n//!\n//! Implementation comes from and example usage can be found at\n//! https://en.cppreference.com/w/cpp/utility/variant/visit#Example\ntemplate<class... Ts> struct Overloaded : Ts... { using Ts::operator()...; };\n\n//! Explicit deduction guide (not needed as of C++20)\ntemplate<class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;\n} // namespace util\n\n#endif // CORE_UTIL_OVERLOADED_H\n"
  },
  {
    "path": "src/util/strencodings.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"util/strencodings.h\"\n\n#include \"tinyformat.h\"\n\n#include <cstdlib>\n#include <cstring>\n#include <errno.h>\n#include <limits>\n\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and ends_with()\n\nstatic const std::string CHARS_ALPHA_NUM = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n\nstatic const std::string SAFE_CHARS[] =\n{\n    CHARS_ALPHA_NUM + \" .,;-_/:?@()\", // SAFE_CHARS_DEFAULT\n    CHARS_ALPHA_NUM + \" .,;-_?@\", // SAFE_CHARS_UA_COMMENT\n    CHARS_ALPHA_NUM + \".-_\", // SAFE_CHARS_FILENAME\n};\n\nstd::string SanitizeString(const std::string& str, int rule)\n{\n    std::string strResult;\n    for (std::string::size_type i = 0; i < str.size(); i++)\n    {\n        if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)\n            strResult.push_back(str[i]);\n    }\n    return strResult;\n}\n\nconst signed char p_util_hexdigit[256] =\n{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,\n  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\n  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };\n\nsigned char HexDigit(char c)\n{\n    return p_util_hexdigit[(unsigned char)c];\n}\n\nbool IsHex(const std::string& str)\n{\n    for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)\n    {\n        if (HexDigit(*it) < 0)\n            return false;\n    }\n    return (str.size() > 0) && (str.size()%2 == 0);\n}\n\nstd::vector<unsigned char> ParseHex(const char* psz)\n{\n    // convert hex dump to vector\n    std::vector<unsigned char> vch;\n    while (true)\n    {\n        while (isspace(*psz))\n            psz++;\n        signed char c = HexDigit(*psz++);\n        if (c == (signed char)-1)\n            break;\n        unsigned char n = (c << 4);\n        c = HexDigit(*psz++);\n        if (c == (signed char)-1)\n            break;\n        n |= c;\n        vch.push_back(n);\n    }\n    return vch;\n}\n\nstd::vector<unsigned char> ParseHex(const std::string& str)\n{\n    return ParseHex(str.c_str());\n}\n\nstd::string EncodeBase64(const unsigned char* pch, size_t len)\n{\n    static const char *pbase64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n    std::string strRet = \"\";\n    strRet.reserve((len+2)/3*4);\n\n    int mode=0, left=0;\n    const unsigned char *pchEnd = pch+len;\n\n    while (pch<pchEnd)\n    {\n        int enc = *(pch++);\n        switch (mode)\n        {\n            case 0: // we have no bits\n                strRet += pbase64[enc >> 2];\n                left = (enc & 3) << 4;\n                mode = 1;\n                break;\n\n            case 1: // we have two bits\n                strRet += pbase64[left | (enc >> 4)];\n                left = (enc & 15) << 2;\n                mode = 2;\n                break;\n\n            case 2: // we have four bits\n                strRet += pbase64[left | (enc >> 6)];\n                strRet += pbase64[enc & 63];\n                mode = 0;\n                break;\n        }\n    }\n\n    if (mode)\n    {\n        strRet += pbase64[left];\n        strRet += '=';\n        if (mode == 1)\n            strRet += '=';\n    }\n\n    return strRet;\n}\n\nstd::string EncodeBase64(const std::string& str)\n{\n    return EncodeBase64((const unsigned char*)str.c_str(), str.size());\n}\n\nstd::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)\n{\n    static const int decode64_table[256] =\n    {\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,\n        -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,\n        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\n        49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\n    };\n\n    if (pfInvalid)\n        *pfInvalid = false;\n\n    std::vector<unsigned char> vchRet;\n    vchRet.reserve(strlen(p)*3/4);\n\n    int mode = 0;\n    int left = 0;\n\n    while (1)\n    {\n         int dec = decode64_table[(unsigned char)*p];\n         if (dec == -1) break;\n         p++;\n         switch (mode)\n         {\n             case 0: // we have no bits and get 6\n                 left = dec;\n                 mode = 1;\n                 break;\n\n              case 1: // we have 6 bits and keep 4\n                  vchRet.push_back((left<<2) | (dec>>4));\n                  left = dec & 15;\n                  mode = 2;\n                  break;\n\n             case 2: // we have 4 bits and get 6, we keep 2\n                 vchRet.push_back((left<<4) | (dec>>2));\n                 left = dec & 3;\n                 mode = 3;\n                 break;\n\n             case 3: // we have 2 bits and get 6\n                 vchRet.push_back((left<<6) | dec);\n                 mode = 0;\n                 break;\n         }\n    }\n\n    if (pfInvalid)\n        switch (mode)\n        {\n            case 0: // 4n base64 characters processed: ok\n                break;\n\n            case 1: // 4n+1 base64 character processed: impossible\n                *pfInvalid = true;\n                break;\n\n            case 2: // 4n+2 base64 characters processed: require '=='\n                if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)\n                    *pfInvalid = true;\n                break;\n\n            case 3: // 4n+3 base64 characters processed: require '='\n                if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)\n                    *pfInvalid = true;\n                break;\n        }\n\n    return vchRet;\n}\n\nstd::string DecodeBase64(const std::string& str)\n{\n    std::vector<unsigned char> vchRet = DecodeBase64(str.c_str());\n    return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());\n}\n\nstd::string EncodeBase32(const unsigned char* pch, size_t len)\n{\n    static const char *pbase32 = \"abcdefghijklmnopqrstuvwxyz234567\";\n\n    std::string strRet=\"\";\n    strRet.reserve((len+4)/5*8);\n\n    int mode=0, left=0;\n    const unsigned char *pchEnd = pch+len;\n\n    while (pch<pchEnd)\n    {\n        int enc = *(pch++);\n        switch (mode)\n        {\n            case 0: // we have no bits\n                strRet += pbase32[enc >> 3];\n                left = (enc & 7) << 2;\n                mode = 1;\n                break;\n\n            case 1: // we have three bits\n                strRet += pbase32[left | (enc >> 6)];\n                strRet += pbase32[(enc >> 1) & 31];\n                left = (enc & 1) << 4;\n                mode = 2;\n                break;\n\n            case 2: // we have one bit\n                strRet += pbase32[left | (enc >> 4)];\n                left = (enc & 15) << 1;\n                mode = 3;\n                break;\n\n            case 3: // we have four bits\n                strRet += pbase32[left | (enc >> 7)];\n                strRet += pbase32[(enc >> 2) & 31];\n                left = (enc & 3) << 3;\n                mode = 4;\n                break;\n\n            case 4: // we have two bits\n                strRet += pbase32[left | (enc >> 5)];\n                strRet += pbase32[enc & 31];\n                mode = 0;\n        }\n    }\n\n    static const int nPadding[5] = {0, 6, 4, 3, 1};\n    if (mode)\n    {\n        strRet += pbase32[left];\n        for (int n=0; n<nPadding[mode]; n++)\n             strRet += '=';\n    }\n\n    return strRet;\n}\n\nstd::string EncodeBase32(const std::string& str)\n{\n    return EncodeBase32((const unsigned char*)str.c_str(), str.size());\n}\n\nstd::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)\n{\n    static const int decode32_table[256] =\n    {\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,\n         3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,\n        23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\n    };\n\n    if (pfInvalid)\n        *pfInvalid = false;\n\n    std::vector<unsigned char> vchRet;\n    vchRet.reserve((strlen(p))*5/8);\n\n    int mode = 0;\n    int left = 0;\n\n    while (1)\n    {\n         int dec = decode32_table[(unsigned char)*p];\n         if (dec == -1) break;\n         p++;\n         switch (mode)\n         {\n             case 0: // we have no bits and get 5\n                 left = dec;\n                 mode = 1;\n                 break;\n\n              case 1: // we have 5 bits and keep 2\n                  vchRet.push_back((left<<3) | (dec>>2));\n                  left = dec & 3;\n                  mode = 2;\n                  break;\n\n             case 2: // we have 2 bits and keep 7\n                 left = left << 5 | dec;\n                 mode = 3;\n                 break;\n\n             case 3: // we have 7 bits and keep 4\n                 vchRet.push_back((left<<1) | (dec>>4));\n                 left = dec & 15;\n                 mode = 4;\n                 break;\n\n             case 4: // we have 4 bits, and keep 1\n                 vchRet.push_back((left<<4) | (dec>>1));\n                 left = dec & 1;\n                 mode = 5;\n                 break;\n\n             case 5: // we have 1 bit, and keep 6\n                 left = left << 5 | dec;\n                 mode = 6;\n                 break;\n\n             case 6: // we have 6 bits, and keep 3\n                 vchRet.push_back((left<<2) | (dec>>3));\n                 left = dec & 7;\n                 mode = 7;\n                 break;\n\n             case 7: // we have 3 bits, and keep 0\n                 vchRet.push_back((left<<5) | dec);\n                 mode = 0;\n                 break;\n         }\n    }\n\n    if (pfInvalid)\n        switch (mode)\n        {\n            case 0: // 8n base32 characters processed: ok\n                break;\n\n            case 1: // 8n+1 base32 characters processed: impossible\n            case 3: //   +3\n            case 6: //   +6\n                *pfInvalid = true;\n                break;\n\n            case 2: // 8n+2 base32 characters processed: require '======'\n                if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)\n                    *pfInvalid = true;\n                break;\n\n            case 4: // 8n+4 base32 characters processed: require '===='\n                if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)\n                    *pfInvalid = true;\n                break;\n\n            case 5: // 8n+5 base32 characters processed: require '==='\n                if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)\n                    *pfInvalid = true;\n                break;\n\n            case 7: // 8n+7 base32 characters processed: require '='\n                if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)\n                    *pfInvalid = true;\n                break;\n        }\n\n    return vchRet;\n}\n\nstd::string DecodeBase32(const std::string& str)\n{\n    std::vector<unsigned char> vchRet = DecodeBase32(str.c_str());\n    return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());\n}\n\nstatic bool ParsePrechecks(const std::string& str)\n{\n    if (str.empty()) // No empty string allowed\n        return false;\n    if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed\n        return false;\n    if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed\n        return false;\n    return true;\n}\n\nbool ParseInt32(const std::string& str, int32_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    char *endp = NULL;\n    errno = 0; // strtol will not set errno if valid\n    long int n = strtol(str.c_str(), &endp, 10);\n    if(out) *out = (int32_t)n;\n    // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow\n    // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit\n    // platforms the size of these types may be different.\n    return endp && *endp == 0 && !errno &&\n        n >= std::numeric_limits<int32_t>::min() &&\n        n <= std::numeric_limits<int32_t>::max();\n}\n\nbool ParseInt64(const std::string& str, int64_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    char *endp = NULL;\n    errno = 0; // strtoll will not set errno if valid\n    long long int n = strtoll(str.c_str(), &endp, 10);\n    if(out) *out = (int64_t)n;\n    // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow\n    // we still have to check that the returned value is within the range of an *int64_t*.\n    return endp && *endp == 0 && !errno &&\n        n >= std::numeric_limits<int64_t>::min() &&\n        n <= std::numeric_limits<int64_t>::max();\n}\n\nbool ParseUInt32(const std::string& str, uint32_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range\n        return false;\n    char *endp = NULL;\n    errno = 0; // strtoul will not set errno if valid\n    unsigned long int n = strtoul(str.c_str(), &endp, 10);\n    if(out) *out = (uint32_t)n;\n    // Note that strtoul returns a *unsigned long int*, so even if it doesn't report a over/underflow\n    // we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit\n    // platforms the size of these types may be different.\n    return endp && *endp == 0 && !errno &&\n        n <= std::numeric_limits<uint32_t>::max();\n}\n\nbool ParseUInt64(const std::string& str, uint64_t *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range\n        return false;\n    char *endp = NULL;\n    errno = 0; // strtoull will not set errno if valid\n    unsigned long long int n = strtoull(str.c_str(), &endp, 10);\n    if(out) *out = (uint64_t)n;\n    // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report a over/underflow\n    // we still have to check that the returned value is within the range of an *uint64_t*.\n    return endp && *endp == 0 && !errno &&\n        n <= std::numeric_limits<uint64_t>::max();\n}\n\n\nbool ParseDouble(const std::string& str, double *out)\n{\n    if (!ParsePrechecks(str))\n        return false;\n    if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed\n        return false;\n    std::istringstream text(str);\n    text.imbue(std::locale::classic());\n    double result;\n    text >> result;\n    if(out) *out = result;\n    return text.eof() && !text.fail();\n}\n\nstd::string FormatParagraph(const std::string& in, size_t width, size_t indent)\n{\n    std::stringstream out;\n    size_t ptr = 0;\n    size_t indented = 0;\n    while (ptr < in.size())\n    {\n        size_t lineend = in.find_first_of('\\n', ptr);\n        if (lineend == std::string::npos) {\n            lineend = in.size();\n        }\n        const size_t linelen = lineend - ptr;\n        const size_t rem_width = width - indented;\n        if (linelen <= rem_width) {\n            out << in.substr(ptr, linelen + 1);\n            ptr = lineend + 1;\n            indented = 0;\n        } else {\n            size_t finalspace = in.find_last_of(\" \\n\", ptr + rem_width);\n            if (finalspace == std::string::npos || finalspace < ptr) {\n                // No place to break; just include the entire word and move on\n                finalspace = in.find_first_of(\"\\n \", ptr);\n                if (finalspace == std::string::npos) {\n                    // End of the string, just add it and break\n                    out << in.substr(ptr);\n                    break;\n                }\n            }\n            out << in.substr(ptr, finalspace - ptr) << \"\\n\";\n            if (in[finalspace] == '\\n') {\n                indented = 0;\n            } else if (indent) {\n                out << std::string(indent, ' ');\n                indented = indent;\n            }\n            ptr = finalspace + 1;\n        }\n    }\n    return out.str();\n}\n\nstd::string i64tostr(int64_t n)\n{\n    return strprintf(\"%d\", n);\n}\n\nstd::string itostr(int n)\n{\n    return strprintf(\"%d\", n);\n}\n\nint64_t atoi64(const char* psz)\n{\n#ifdef _MSC_VER\n    return _atoi64(psz);\n#else\n    return strtoll(psz, NULL, 10);\n#endif\n}\n\nint64_t atoi64(const std::string& str)\n{\n#ifdef _MSC_VER\n    return _atoi64(str.c_str());\n#else\n    return strtoll(str.c_str(), NULL, 10);\n#endif\n}\n\nint atoi(const std::string& str)\n{\n    return atoi(str.c_str());\n}\n\n/** Upper bound for mantissa.\n * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.\n * Larger integers cannot consist of arbitrary combinations of 0-9:\n *\n *   999999999999999999  1^18-1\n *  9223372036854775807  (1<<63)-1  (max int64_t)\n *  9999999999999999999  1^19-1     (would overflow)\n */\nstatic const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;\n\n/** Helper function for ParseFixedPoint */\nstatic inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)\n{\n    if(ch == '0')\n        ++mantissa_tzeros;\n    else {\n        for (int i=0; i<=mantissa_tzeros; ++i) {\n            if (mantissa > (UPPER_BOUND / 10LL))\n                return false; /* overflow */\n            mantissa *= 10;\n        }\n        mantissa += ch - '0';\n        mantissa_tzeros = 0;\n    }\n    return true;\n}\n\nbool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)\n{\n    int64_t mantissa = 0;\n    int64_t exponent = 0;\n    int mantissa_tzeros = 0;\n    bool mantissa_sign = false;\n    bool exponent_sign = false;\n    int ptr = 0;\n    int end = val.size();\n    int point_ofs = 0;\n\n    if (ptr < end && val[ptr] == '-') {\n        mantissa_sign = true;\n        ++ptr;\n    }\n    if (ptr < end)\n    {\n        if (val[ptr] == '0') {\n            /* pass single 0 */\n            ++ptr;\n        } else if (val[ptr] >= '1' && val[ptr] <= '9') {\n            while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {\n                if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))\n                    return false; /* overflow */\n                ++ptr;\n            }\n        } else return false; /* missing expected digit */\n    } else return false; /* empty string or loose '-' */\n    if (ptr < end && val[ptr] == '.')\n    {\n        ++ptr;\n        if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9')\n        {\n            while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {\n                if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))\n                    return false; /* overflow */\n                ++ptr;\n                ++point_ofs;\n            }\n        } else return false; /* missing expected digit */\n    }\n    if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))\n    {\n        ++ptr;\n        if (ptr < end && val[ptr] == '+')\n            ++ptr;\n        else if (ptr < end && val[ptr] == '-') {\n            exponent_sign = true;\n            ++ptr;\n        }\n        if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {\n            while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {\n                if (exponent > (UPPER_BOUND / 10LL))\n                    return false; /* overflow */\n                exponent = exponent * 10 + val[ptr] - '0';\n                ++ptr;\n            }\n        } else return false; /* missing expected digit */\n    }\n    if (ptr != end)\n        return false; /* trailing garbage */\n\n    /* finalize exponent */\n    if (exponent_sign)\n        exponent = -exponent;\n    exponent = exponent - point_ofs + mantissa_tzeros;\n\n    /* finalize mantissa */\n    if (mantissa_sign)\n        mantissa = -mantissa;\n\n    /* convert to one 64-bit fixed-point value */\n    exponent += decimals;\n    if (exponent < 0)\n        return false; /* cannot represent values smaller than 10^-decimals */\n    if (exponent >= 18)\n        return false; /* cannot represent values larger than or equal to 10^(18-decimals) */\n\n    for (int i=0; i < exponent; ++i) {\n        if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))\n            return false; /* overflow */\n        mantissa *= 10;\n    }\n    if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)\n        return false; /* overflow */\n\n    if (amount_out)\n        *amount_out = mantissa;\n\n    return true;\n}\n\nuint64_t GetMemLimitInBytesFromFormattedStringSpecifier(std::string formattedLockPeriodSpecifier)\n{\n    if (formattedLockPeriodSpecifier.empty())\n        return 0;\n\n    uint64_t memLimitInBytes = 0;\n    uint64_t nMultiplier = 1;\n    if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"B\") || boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"b\"))\n    {\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"K\") || boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"k\"))\n    {\n        nMultiplier = 1024;\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"M\") || boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"m\"))\n    {\n        nMultiplier = 1024*1024;\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    else if (boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"G\") || boost::algorithm::ends_with(formattedLockPeriodSpecifier, \"g\"))\n    {\n        nMultiplier = 1024*1024*1024;\n        formattedLockPeriodSpecifier.pop_back();\n    }\n    if (!ParseUInt64(formattedLockPeriodSpecifier, &memLimitInBytes))\n        return 0;\n    memLimitInBytes *=  nMultiplier;\n    return memLimitInBytes;\n}\n"
  },
  {
    "path": "src/util/strencodings.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2020-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n/**\n * Utilities for converting data from/to strings.\n */\n\n#ifndef UTIL_STRENCODINGS_H\n#define UTIL_STRENCODINGS_H\n\n#include <stdint.h>\n#include <string>\n#include <vector>\n\n#define BEGIN(a)            ((char*)&(a))\n#define END(a)              ((char*)&((&(a))[1]))\n#define UBEGIN(a)           ((unsigned char*)&(a))\n#define UEND(a)             ((unsigned char*)&((&(a))[1]))\n#define ARRAYLEN(array)     (sizeof(array)/sizeof((array)[0]))\n\n/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */\n#define PAIRTYPE(t1, t2)    std::pair<t1, t2>\n\n/** Used by SanitizeString() */\nenum SafeChars\n{\n    SAFE_CHARS_DEFAULT, //!< The full set of allowed chars\n    SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset\n    SAFE_CHARS_FILENAME, //!< Chars allowed in filenames\n};\n\n/**\n* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email\n* addresses, but avoid anything even possibly remotely dangerous like & or >\n* @param[in] str    The string to sanitize\n* @param[in] rule   The set of safe chars to choose (default: least restrictive)\n* @return           A new string without unsafe chars\n*/\nstd::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);\nstd::vector<unsigned char> ParseHex(const char* psz);\nstd::vector<unsigned char> ParseHex(const std::string& str);\nsigned char HexDigit(char c);\nbool IsHex(const std::string& str);\nstd::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);\nstd::string DecodeBase64(const std::string& str);\nstd::string EncodeBase64(const unsigned char* pch, size_t len);\nstd::string EncodeBase64(const std::string& str);\nstd::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);\nstd::string DecodeBase32(const std::string& str);\nstd::string EncodeBase32(const unsigned char* pch, size_t len);\nstd::string EncodeBase32(const std::string& str);\n\nstd::string i64tostr(int64_t n);\nstd::string itostr(int n);\nint64_t atoi64(const char* psz);\nint64_t atoi64(const std::string& str);\nint atoi(const std::string& str);\n\n/**\n * Convert string to signed 32-bit integer with strict parse error feedback.\n * @returns true if the entire string could be parsed as valid integer,\n *   false if not the entire string could be parsed or when overflow or underflow occurred.\n */\nbool ParseInt32(const std::string& str, int32_t *out);\n\n/**\n * Convert string to signed 64-bit integer with strict parse error feedback.\n * @returns true if the entire string could be parsed as valid integer,\n *   false if not the entire string could be parsed or when overflow or underflow occurred.\n */\nbool ParseInt64(const std::string& str, int64_t *out);\n\n/**\n * Convert decimal string to unsigned 32-bit integer with strict parse error feedback.\n * @returns true if the entire string could be parsed as valid integer,\n *   false if not the entire string could be parsed or when overflow or underflow occurred.\n */\nbool ParseUInt32(const std::string& str, uint32_t *out);\n\n/**\n * Convert decimal string to unsigned 64-bit integer with strict parse error feedback.\n * @returns true if the entire string could be parsed as valid integer,\n *   false if not the entire string could be parsed or when overflow or underflow occurred.\n */\nbool ParseUInt64(const std::string& str, uint64_t *out);\n\n/**\n * Convert string to double with strict parse error feedback.\n * @returns true if the entire string could be parsed as valid double,\n *   false if not the entire string could be parsed or when overflow or underflow occurred.\n */\nbool ParseDouble(const std::string& str, double *out);\n\ntemplate<typename T>\nstd::string HexStr(const T itbegin, const T itend, bool fSpaces=false)\n{\n    std::string rv;\n    static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',\n                                     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n    rv.reserve((itend-itbegin)*3);\n    for(T it = itbegin; it < itend; ++it)\n    {\n        unsigned char val = (unsigned char)(*it);\n        if(fSpaces && it != itbegin)\n            rv.push_back(' ');\n        rv.push_back(hexmap[val>>4]);\n        rv.push_back(hexmap[val&15]);\n    }\n\n    return rv;\n}\n\ntemplate<typename T>\ninline std::string HexStr(const T& vch, bool fSpaces=false)\n{\n    return HexStr(vch.begin(), vch.end(), fSpaces);\n}\n\n/**\n * Format a paragraph of text to a fixed width, adding spaces for\n * indentation to any added line.\n */\nstd::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0);\n\n/**\n * Timing-attack-resistant comparison.\n * Takes time proportional to length\n * of first argument.\n */\ntemplate <typename T>\nbool TimingResistantEqual(const T& a, const T& b)\n{\n    if (b.size() == 0) return a.size() == 0;\n    size_t accumulator = a.size() ^ b.size();\n    for (size_t i = 0; i < a.size(); i++)\n        accumulator |= a[i] ^ b[i%b.size()];\n    return accumulator == 0;\n}\n\n/** Parse number as fixed point according to JSON number syntax.\n * See http://json.org/number.gif\n * @returns true on success, false on error.\n * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.\n */\nbool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);\n\n//! Given a string specifier, calculate a memory size in bytes to match it e.g. 1K -> 1024; 2M -> 2097152;\n//! Returns 0 if specifier is invalid.\nuint64_t GetMemLimitInBytesFromFormattedStringSpecifier(std::string formattedLockPeriodSpecifier);\n\n#endif //UTIL_STRENCODINGS_H\n"
  },
  {
    "path": "src/util/syscall_sandbox.cpp",
    "content": "// Copyright (c) 2020-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif // defined(HAVE_CONFIG_H)\n\n#include <util/syscall_sandbox.h>\n\n#if defined(USE_SYSCALL_SANDBOX)\n#include <array>\n#include <cassert>\n#include <cstdint>\n#include <exception>\n#include <map>\n#include <new>\n#include <set>\n#include <string>\n#include <vector>\n\n#include <logging.h>\n#include <tinyformat.h>\n#include <util/threadnames.h>\n\n#include <linux/audit.h>\n#include <linux/filter.h>\n#include <linux/seccomp.h>\n#include <linux/unistd.h>\n#include <signal.h>\n#include <sys/prctl.h>\n#include <sys/types.h>\n#include <unistd.h>\n\nnamespace {\nbool g_syscall_sandbox_enabled{false};\nbool g_syscall_sandbox_log_violation_before_terminating{false};\n\n#if !defined(__x86_64__)\n#error Syscall sandbox is an experimental feature currently available only under Linux x86-64.\n#endif // defined(__x86_64__)\n\n#ifndef SECCOMP_RET_KILL_PROCESS\n#define SECCOMP_RET_KILL_PROCESS 0x80000000U\n#endif\n\n// Define system call numbers for x86_64 that are referenced in the system call profile\n// but not provided by the kernel headers used in the GUIX build.\n// Usually, they can be found via \"grep name /usr/include/x86_64-linux-gnu/asm/unistd_64.h\"\n\n#ifndef __NR_clone3\n#define __NR_clone3 435\n#endif\n\n#ifndef __NR_statx\n#define __NR_statx 332\n#endif\n\n#ifndef __NR_getrandom\n#define __NR_getrandom 318\n#endif\n\n#ifndef __NR_membarrier\n#define __NR_membarrier 324\n#endif\n\n#ifndef __NR_copy_file_range\n#define __NR_copy_file_range 326\n#endif\n\n// This list of syscalls in LINUX_SYSCALLS is only used to map syscall numbers to syscall names in\n// order to be able to print user friendly error messages which include the syscall name in addition\n// to the syscall number.\n//\n// Example output in case of a syscall violation where the syscall is present in LINUX_SYSCALLS:\n//\n// ```\n// 2021-06-09T12:34:56Z ERROR: The syscall \"execve\" (syscall number 59) is not allowed by the syscall sandbox in thread \"msghand\". Please report.\n// ```\n//\n// Example output in case of a syscall violation where the syscall is not present in LINUX_SYSCALLS:\n//\n// ```\n// 2021-06-09T12:34:56Z ERROR: The syscall \"*unknown*\" (syscall number 314) is not allowed by the syscall sandbox in thread \"msghand\". Please report.\n// ``\n//\n// LINUX_SYSCALLS contains two types of syscalls:\n// 1.) Syscalls that are present under all architectures or relevant Linux kernel versions for which\n//     we support the syscall sandbox feature (currently only Linux x86-64). Examples include read,\n//     write, open, close, etc.\n// 2.) Syscalls that are present under a subset of architectures or relevant Linux kernel versions\n//     for which we support the syscall sandbox feature. This type of syscalls should be added to\n//     LINUX_SYSCALLS conditional on availability like in the following example:\n//         ...\n//         #if defined(__NR_arch_dependent_syscall)\n//             {__NR_arch_dependent_syscall, \"arch_dependent_syscall\"},\n//         #endif // defined(__NR_arch_dependent_syscall)\n//         ...\nconst std::map<uint32_t, std::string> LINUX_SYSCALLS{\n    {__NR_accept, \"accept\"},\n    {__NR_accept4, \"accept4\"},\n    {__NR_access, \"access\"},\n    {__NR_acct, \"acct\"},\n    {__NR_add_key, \"add_key\"},\n    {__NR_adjtimex, \"adjtimex\"},\n    {__NR_afs_syscall, \"afs_syscall\"},\n    {__NR_alarm, \"alarm\"},\n    {__NR_arch_prctl, \"arch_prctl\"},\n    {__NR_bind, \"bind\"},\n    {__NR_bpf, \"bpf\"},\n    {__NR_brk, \"brk\"},\n    {__NR_capget, \"capget\"},\n    {__NR_capset, \"capset\"},\n    {__NR_chdir, \"chdir\"},\n    {__NR_chmod, \"chmod\"},\n    {__NR_chown, \"chown\"},\n    {__NR_chroot, \"chroot\"},\n    {__NR_clock_adjtime, \"clock_adjtime\"},\n    {__NR_clock_getres, \"clock_getres\"},\n    {__NR_clock_gettime, \"clock_gettime\"},\n    {__NR_clock_nanosleep, \"clock_nanosleep\"},\n    {__NR_clock_settime, \"clock_settime\"},\n    {__NR_clone, \"clone\"},\n    {__NR_clone3, \"clone3\"},\n    {__NR_close, \"close\"},\n    {__NR_connect, \"connect\"},\n    {__NR_copy_file_range, \"copy_file_range\"},\n    {__NR_creat, \"creat\"},\n    {__NR_create_module, \"create_module\"},\n    {__NR_delete_module, \"delete_module\"},\n    {__NR_dup, \"dup\"},\n    {__NR_dup2, \"dup2\"},\n    {__NR_dup3, \"dup3\"},\n    {__NR_epoll_create, \"epoll_create\"},\n    {__NR_epoll_create1, \"epoll_create1\"},\n    {__NR_epoll_ctl, \"epoll_ctl\"},\n    {__NR_epoll_ctl_old, \"epoll_ctl_old\"},\n    {__NR_epoll_pwait, \"epoll_pwait\"},\n    {__NR_epoll_wait, \"epoll_wait\"},\n    {__NR_epoll_wait_old, \"epoll_wait_old\"},\n    {__NR_eventfd, \"eventfd\"},\n    {__NR_eventfd2, \"eventfd2\"},\n    {__NR_execve, \"execve\"},\n    {__NR_execveat, \"execveat\"},\n    {__NR_exit, \"exit\"},\n    {__NR_exit_group, \"exit_group\"},\n    {__NR_faccessat, \"faccessat\"},\n    {__NR_fadvise64, \"fadvise64\"},\n    {__NR_fallocate, \"fallocate\"},\n    {__NR_fanotify_init, \"fanotify_init\"},\n    {__NR_fanotify_mark, \"fanotify_mark\"},\n    {__NR_fchdir, \"fchdir\"},\n    {__NR_fchmod, \"fchmod\"},\n    {__NR_fchmodat, \"fchmodat\"},\n    {__NR_fchown, \"fchown\"},\n    {__NR_fchownat, \"fchownat\"},\n    {__NR_fcntl, \"fcntl\"},\n    {__NR_fdatasync, \"fdatasync\"},\n    {__NR_fgetxattr, \"fgetxattr\"},\n    {__NR_finit_module, \"finit_module\"},\n    {__NR_flistxattr, \"flistxattr\"},\n    {__NR_flock, \"flock\"},\n    {__NR_fork, \"fork\"},\n    {__NR_fremovexattr, \"fremovexattr\"},\n    {__NR_fsetxattr, \"fsetxattr\"},\n    {__NR_fstat, \"fstat\"},\n    {__NR_fstatfs, \"fstatfs\"},\n    {__NR_fsync, \"fsync\"},\n    {__NR_ftruncate, \"ftruncate\"},\n    {__NR_futex, \"futex\"},\n    {__NR_futimesat, \"futimesat\"},\n    {__NR_get_kernel_syms, \"get_kernel_syms\"},\n    {__NR_get_mempolicy, \"get_mempolicy\"},\n    {__NR_get_robust_list, \"get_robust_list\"},\n    {__NR_get_thread_area, \"get_thread_area\"},\n    {__NR_getcpu, \"getcpu\"},\n    {__NR_getcwd, \"getcwd\"},\n    {__NR_getdents, \"getdents\"},\n    {__NR_getdents64, \"getdents64\"},\n    {__NR_getegid, \"getegid\"},\n    {__NR_geteuid, \"geteuid\"},\n    {__NR_getgid, \"getgid\"},\n    {__NR_getgroups, \"getgroups\"},\n    {__NR_getitimer, \"getitimer\"},\n    {__NR_getpeername, \"getpeername\"},\n    {__NR_getpgid, \"getpgid\"},\n    {__NR_getpgrp, \"getpgrp\"},\n    {__NR_getpid, \"getpid\"},\n    {__NR_getpmsg, \"getpmsg\"},\n    {__NR_getppid, \"getppid\"},\n    {__NR_getpriority, \"getpriority\"},\n    {__NR_getrandom, \"getrandom\"},\n    {__NR_getresgid, \"getresgid\"},\n    {__NR_getresuid, \"getresuid\"},\n    {__NR_getrlimit, \"getrlimit\"},\n    {__NR_getrusage, \"getrusage\"},\n    {__NR_getsid, \"getsid\"},\n    {__NR_getsockname, \"getsockname\"},\n    {__NR_getsockopt, \"getsockopt\"},\n    {__NR_gettid, \"gettid\"},\n    {__NR_gettimeofday, \"gettimeofday\"},\n    {__NR_getuid, \"getuid\"},\n    {__NR_getxattr, \"getxattr\"},\n    {__NR_init_module, \"init_module\"},\n    {__NR_inotify_add_watch, \"inotify_add_watch\"},\n    {__NR_inotify_init, \"inotify_init\"},\n    {__NR_inotify_init1, \"inotify_init1\"},\n    {__NR_inotify_rm_watch, \"inotify_rm_watch\"},\n    {__NR_io_cancel, \"io_cancel\"},\n    {__NR_io_destroy, \"io_destroy\"},\n    {__NR_io_getevents, \"io_getevents\"},\n    {__NR_io_setup, \"io_setup\"},\n    {__NR_io_submit, \"io_submit\"},\n    {__NR_ioctl, \"ioctl\"},\n    {__NR_ioperm, \"ioperm\"},\n    {__NR_iopl, \"iopl\"},\n    {__NR_ioprio_get, \"ioprio_get\"},\n    {__NR_ioprio_set, \"ioprio_set\"},\n    {__NR_kcmp, \"kcmp\"},\n    {__NR_kexec_file_load, \"kexec_file_load\"},\n    {__NR_kexec_load, \"kexec_load\"},\n    {__NR_keyctl, \"keyctl\"},\n    {__NR_kill, \"kill\"},\n    {__NR_lchown, \"lchown\"},\n    {__NR_lgetxattr, \"lgetxattr\"},\n    {__NR_link, \"link\"},\n    {__NR_linkat, \"linkat\"},\n    {__NR_listen, \"listen\"},\n    {__NR_listxattr, \"listxattr\"},\n    {__NR_llistxattr, \"llistxattr\"},\n    {__NR_lookup_dcookie, \"lookup_dcookie\"},\n    {__NR_lremovexattr, \"lremovexattr\"},\n    {__NR_lseek, \"lseek\"},\n    {__NR_lsetxattr, \"lsetxattr\"},\n    {__NR_lstat, \"lstat\"},\n    {__NR_madvise, \"madvise\"},\n    {__NR_mbind, \"mbind\"},\n    {__NR_membarrier, \"membarrier\"},\n    {__NR_memfd_create, \"memfd_create\"},\n    {__NR_migrate_pages, \"migrate_pages\"},\n    {__NR_mincore, \"mincore\"},\n    {__NR_mkdir, \"mkdir\"},\n    {__NR_mkdirat, \"mkdirat\"},\n    {__NR_mknod, \"mknod\"},\n    {__NR_mknodat, \"mknodat\"},\n    {__NR_mlock, \"mlock\"},\n    {__NR_mlock2, \"mlock2\"},\n    {__NR_mlockall, \"mlockall\"},\n    {__NR_mmap, \"mmap\"},\n    {__NR_modify_ldt, \"modify_ldt\"},\n    {__NR_mount, \"mount\"},\n    {__NR_move_pages, \"move_pages\"},\n    {__NR_mprotect, \"mprotect\"},\n    {__NR_mq_getsetattr, \"mq_getsetattr\"},\n    {__NR_mq_notify, \"mq_notify\"},\n    {__NR_mq_open, \"mq_open\"},\n    {__NR_mq_timedreceive, \"mq_timedreceive\"},\n    {__NR_mq_timedsend, \"mq_timedsend\"},\n    {__NR_mq_unlink, \"mq_unlink\"},\n    {__NR_mremap, \"mremap\"},\n    {__NR_msgctl, \"msgctl\"},\n    {__NR_msgget, \"msgget\"},\n    {__NR_msgrcv, \"msgrcv\"},\n    {__NR_msgsnd, \"msgsnd\"},\n    {__NR_msync, \"msync\"},\n    {__NR_munlock, \"munlock\"},\n    {__NR_munlockall, \"munlockall\"},\n    {__NR_munmap, \"munmap\"},\n    {__NR_name_to_handle_at, \"name_to_handle_at\"},\n    {__NR_nanosleep, \"nanosleep\"},\n    {__NR_newfstatat, \"newfstatat\"},\n    {__NR_nfsservctl, \"nfsservctl\"},\n    {__NR_open, \"open\"},\n    {__NR_open_by_handle_at, \"open_by_handle_at\"},\n    {__NR_openat, \"openat\"},\n    {__NR_pause, \"pause\"},\n    {__NR_perf_event_open, \"perf_event_open\"},\n    {__NR_personality, \"personality\"},\n    {__NR_pipe, \"pipe\"},\n    {__NR_pipe2, \"pipe2\"},\n    {__NR_pivot_root, \"pivot_root\"},\n#ifdef __NR_pkey_alloc\n    {__NR_pkey_alloc, \"pkey_alloc\"},\n#endif\n#ifdef __NR_pkey_free\n    {__NR_pkey_free, \"pkey_free\"},\n#endif\n#ifdef __NR_pkey_mprotect\n    {__NR_pkey_mprotect, \"pkey_mprotect\"},\n#endif\n    {__NR_poll, \"poll\"},\n    {__NR_ppoll, \"ppoll\"},\n    {__NR_prctl, \"prctl\"},\n    {__NR_pread64, \"pread64\"},\n    {__NR_preadv, \"preadv\"},\n#ifdef __NR_preadv2\n    {__NR_preadv2, \"preadv2\"},\n#endif\n    {__NR_prlimit64, \"prlimit64\"},\n    {__NR_process_vm_readv, \"process_vm_readv\"},\n    {__NR_process_vm_writev, \"process_vm_writev\"},\n    {__NR_pselect6, \"pselect6\"},\n    {__NR_ptrace, \"ptrace\"},\n    {__NR_putpmsg, \"putpmsg\"},\n    {__NR_pwrite64, \"pwrite64\"},\n    {__NR_pwritev, \"pwritev\"},\n#ifdef __NR_pwritev2\n    {__NR_pwritev2, \"pwritev2\"},\n#endif\n    {__NR__sysctl, \"_sysctl\"},\n    {__NR_query_module, \"query_module\"},\n    {__NR_quotactl, \"quotactl\"},\n    {__NR_read, \"read\"},\n    {__NR_readahead, \"readahead\"},\n    {__NR_readlink, \"readlink\"},\n    {__NR_readlinkat, \"readlinkat\"},\n    {__NR_readv, \"readv\"},\n    {__NR_reboot, \"reboot\"},\n    {__NR_recvfrom, \"recvfrom\"},\n    {__NR_recvmmsg, \"recvmmsg\"},\n    {__NR_recvmsg, \"recvmsg\"},\n    {__NR_remap_file_pages, \"remap_file_pages\"},\n    {__NR_removexattr, \"removexattr\"},\n    {__NR_rename, \"rename\"},\n    {__NR_renameat, \"renameat\"},\n    {__NR_renameat2, \"renameat2\"},\n    {__NR_request_key, \"request_key\"},\n    {__NR_restart_syscall, \"restart_syscall\"},\n    {__NR_rmdir, \"rmdir\"},\n    {__NR_rt_sigaction, \"rt_sigaction\"},\n    {__NR_rt_sigpending, \"rt_sigpending\"},\n    {__NR_rt_sigprocmask, \"rt_sigprocmask\"},\n    {__NR_rt_sigqueueinfo, \"rt_sigqueueinfo\"},\n    {__NR_rt_sigreturn, \"rt_sigreturn\"},\n    {__NR_rt_sigsuspend, \"rt_sigsuspend\"},\n    {__NR_rt_sigtimedwait, \"rt_sigtimedwait\"},\n    {__NR_rt_tgsigqueueinfo, \"rt_tgsigqueueinfo\"},\n    {__NR_sched_get_priority_max, \"sched_get_priority_max\"},\n    {__NR_sched_get_priority_min, \"sched_get_priority_min\"},\n    {__NR_sched_getaffinity, \"sched_getaffinity\"},\n    {__NR_sched_getattr, \"sched_getattr\"},\n    {__NR_sched_getparam, \"sched_getparam\"},\n    {__NR_sched_getscheduler, \"sched_getscheduler\"},\n    {__NR_sched_rr_get_interval, \"sched_rr_get_interval\"},\n    {__NR_sched_setaffinity, \"sched_setaffinity\"},\n    {__NR_sched_setattr, \"sched_setattr\"},\n    {__NR_sched_setparam, \"sched_setparam\"},\n    {__NR_sched_setscheduler, \"sched_setscheduler\"},\n    {__NR_sched_yield, \"sched_yield\"},\n    {__NR_seccomp, \"seccomp\"},\n    {__NR_security, \"security\"},\n    {__NR_select, \"select\"},\n    {__NR_semctl, \"semctl\"},\n    {__NR_semget, \"semget\"},\n    {__NR_semop, \"semop\"},\n    {__NR_semtimedop, \"semtimedop\"},\n    {__NR_sendfile, \"sendfile\"},\n    {__NR_sendmmsg, \"sendmmsg\"},\n    {__NR_sendmsg, \"sendmsg\"},\n    {__NR_sendto, \"sendto\"},\n    {__NR_set_mempolicy, \"set_mempolicy\"},\n    {__NR_set_robust_list, \"set_robust_list\"},\n    {__NR_set_thread_area, \"set_thread_area\"},\n    {__NR_set_tid_address, \"set_tid_address\"},\n    {__NR_setdomainname, \"setdomainname\"},\n    {__NR_setfsgid, \"setfsgid\"},\n    {__NR_setfsuid, \"setfsuid\"},\n    {__NR_setgid, \"setgid\"},\n    {__NR_setgroups, \"setgroups\"},\n    {__NR_sethostname, \"sethostname\"},\n    {__NR_setitimer, \"setitimer\"},\n    {__NR_setns, \"setns\"},\n    {__NR_setpgid, \"setpgid\"},\n    {__NR_setpriority, \"setpriority\"},\n    {__NR_setregid, \"setregid\"},\n    {__NR_setresgid, \"setresgid\"},\n    {__NR_setresuid, \"setresuid\"},\n    {__NR_setreuid, \"setreuid\"},\n    {__NR_setrlimit, \"setrlimit\"},\n    {__NR_setsid, \"setsid\"},\n    {__NR_setsockopt, \"setsockopt\"},\n    {__NR_settimeofday, \"settimeofday\"},\n    {__NR_setuid, \"setuid\"},\n    {__NR_setxattr, \"setxattr\"},\n    {__NR_shmat, \"shmat\"},\n    {__NR_shmctl, \"shmctl\"},\n    {__NR_shmdt, \"shmdt\"},\n    {__NR_shmget, \"shmget\"},\n    {__NR_shutdown, \"shutdown\"},\n    {__NR_sigaltstack, \"sigaltstack\"},\n    {__NR_signalfd, \"signalfd\"},\n    {__NR_signalfd4, \"signalfd4\"},\n    {__NR_socket, \"socket\"},\n    {__NR_socketpair, \"socketpair\"},\n    {__NR_splice, \"splice\"},\n    {__NR_stat, \"stat\"},\n    {__NR_statfs, \"statfs\"},\n    {__NR_statx, \"statx\"},\n    {__NR_swapoff, \"swapoff\"},\n    {__NR_swapon, \"swapon\"},\n    {__NR_symlink, \"symlink\"},\n    {__NR_symlinkat, \"symlinkat\"},\n    {__NR_sync, \"sync\"},\n    {__NR_sync_file_range, \"sync_file_range\"},\n    {__NR_syncfs, \"syncfs\"},\n    {__NR_sysfs, \"sysfs\"},\n    {__NR_sysinfo, \"sysinfo\"},\n    {__NR_syslog, \"syslog\"},\n    {__NR_tee, \"tee\"},\n    {__NR_tgkill, \"tgkill\"},\n    {__NR_time, \"time\"},\n    {__NR_timer_create, \"timer_create\"},\n    {__NR_timer_delete, \"timer_delete\"},\n    {__NR_timer_getoverrun, \"timer_getoverrun\"},\n    {__NR_timer_gettime, \"timer_gettime\"},\n    {__NR_timer_settime, \"timer_settime\"},\n    {__NR_timerfd_create, \"timerfd_create\"},\n    {__NR_timerfd_gettime, \"timerfd_gettime\"},\n    {__NR_timerfd_settime, \"timerfd_settime\"},\n    {__NR_times, \"times\"},\n    {__NR_tkill, \"tkill\"},\n    {__NR_truncate, \"truncate\"},\n    {__NR_tuxcall, \"tuxcall\"},\n    {__NR_umask, \"umask\"},\n    {__NR_umount2, \"umount2\"},\n    {__NR_uname, \"uname\"},\n    {__NR_unlink, \"unlink\"},\n    {__NR_unlinkat, \"unlinkat\"},\n    {__NR_unshare, \"unshare\"},\n    {__NR_uselib, \"uselib\"},\n    {__NR_userfaultfd, \"userfaultfd\"},\n    {__NR_ustat, \"ustat\"},\n    {__NR_utime, \"utime\"},\n    {__NR_utimensat, \"utimensat\"},\n    {__NR_utimes, \"utimes\"},\n    {__NR_vfork, \"vfork\"},\n    {__NR_vhangup, \"vhangup\"},\n    {__NR_vmsplice, \"vmsplice\"},\n    {__NR_vserver, \"vserver\"},\n    {__NR_wait4, \"wait4\"},\n    {__NR_waitid, \"waitid\"},\n    {__NR_write, \"write\"},\n    {__NR_writev, \"writev\"},\n};\n\nstd::string GetLinuxSyscallName(uint32_t syscall_number)\n{\n    const auto element = LINUX_SYSCALLS.find(syscall_number);\n    if (element != LINUX_SYSCALLS.end()) {\n        return element->second;\n    }\n    return \"*unknown*\";\n}\n\n// See Linux kernel developer Kees Cook's seccomp guide at <https://outflux.net/teach-seccomp/> for\n// an accessible introduction to using seccomp.\n//\n// This function largely follows <https://outflux.net/teach-seccomp/step-3/syscall-reporter.c> and\n// <https://outflux.net/teach-seccomp/step-3/seccomp-bpf.h>.\n//\n// Seccomp BPF resources:\n// * Seccomp BPF documentation: <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html>\n// * seccomp(2) manual page: <https://www.kernel.org/doc/man-pages/online/pages/man2/seccomp.2.html>\n// * Seccomp BPF demo code samples: <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/seccomp>\nvoid SyscallSandboxDebugSignalHandler(int, siginfo_t* signal_info, void* void_signal_context)\n{\n    // The si_code field inside the siginfo_t argument that is passed to a SA_SIGINFO signal handler\n    // is a value indicating why the signal was sent.\n    //\n    // The following value can be placed in si_code for a SIGSYS signal:\n    // * SYS_SECCOMP (since Linux 3.5): Triggered by a seccomp(2) filter rule.\n    constexpr int32_t SYS_SECCOMP_SI_CODE{1};\n    assert(signal_info->si_code == SYS_SECCOMP_SI_CODE);\n\n    // The ucontext_t structure contains signal context information that was saved on the user-space\n    // stack by the kernel.\n    const ucontext_t* signal_context = static_cast<ucontext_t*>(void_signal_context);\n    assert(signal_context != nullptr);\n\n    std::set_new_handler(std::terminate);\n    // Portability note: REG_RAX is Linux x86_64 specific.\n    const uint32_t syscall_number = static_cast<uint32_t>(signal_context->uc_mcontext.gregs[REG_RAX]);\n    const std::string syscall_name = GetLinuxSyscallName(syscall_number);\n    const std::string thread_name = !util::ThreadGetInternalName().empty() ? util::ThreadGetInternalName() : \"*unnamed*\";\n    const std::string error_message = strprintf(\"ERROR: The syscall \\\"%s\\\" (syscall number %d) is not allowed by the syscall sandbox in thread \\\"%s\\\". Please report.\", syscall_name, syscall_number, thread_name);\n    tfm::format(std::cerr, \"%s\\n\", error_message);\n    LogPrintf(\"%s\\n\", error_message);\n    std::terminate();\n}\n\n// This function largely follows install_syscall_reporter from Kees Cook's seccomp guide:\n// <https://outflux.net/teach-seccomp/step-3/syscall-reporter.c>\nbool SetupSyscallSandboxDebugHandler()\n{\n    struct sigaction action = {};\n    sigset_t mask;\n    sigemptyset(&mask);\n    sigaddset(&mask, SIGSYS);\n    action.sa_sigaction = &SyscallSandboxDebugSignalHandler;\n    action.sa_flags = SA_SIGINFO;\n    if (sigaction(SIGSYS, &action, nullptr) < 0) {\n        return false;\n    }\n    if (sigprocmask(SIG_UNBLOCK, &mask, nullptr)) {\n        return false;\n    }\n    return true;\n}\n\nenum class SyscallSandboxAction {\n    KILL_PROCESS,\n    INVOKE_SIGNAL_HANDLER,\n};\n\nclass SeccompPolicyBuilder\n{\n    std::set<uint32_t> allowed_syscalls;\n\npublic:\n    SeccompPolicyBuilder()\n    {\n        // Allowed by default.\n        AllowAddressSpaceAccess();\n        AllowEpoll();\n        AllowEventFd();\n        AllowFutex();\n        AllowGeneralIo();\n        AllowGetRandom();\n        AllowGetSimpleId();\n        AllowGetTime();\n        AllowGlobalProcessEnvironment();\n        AllowGlobalSystemStatus();\n        AllowKernelInternalApi();\n        AllowNetworkSocketInformation();\n        AllowOperationOnExistingFileDescriptor();\n        AllowPipe();\n        AllowPrctl();\n        AllowProcessStartOrDeath();\n        AllowScheduling();\n        AllowSignalHandling();\n        AllowSleep();\n        AllowUmask();\n    }\n\n    void AllowAddressSpaceAccess()\n    {\n        allowed_syscalls.insert(__NR_brk);        // change data segment size\n        allowed_syscalls.insert(__NR_madvise);    // give advice about use of memory\n        allowed_syscalls.insert(__NR_membarrier); // issue memory barriers on a set of threads\n        allowed_syscalls.insert(__NR_mincore);    // check if virtual memory is in RAM\n        allowed_syscalls.insert(__NR_mlock);      // lock memory\n        allowed_syscalls.insert(__NR_mmap);       // map files or devices into memory\n        allowed_syscalls.insert(__NR_mprotect);   // set protection on a region of memory\n        allowed_syscalls.insert(__NR_mremap);     // remap a file in memory\n        allowed_syscalls.insert(__NR_munlock);    // unlock memory\n        allowed_syscalls.insert(__NR_munmap);     // unmap files or devices into memory\n    }\n\n    void AllowEpoll()\n    {\n        allowed_syscalls.insert(__NR_epoll_create1); // open an epoll file descriptor\n        allowed_syscalls.insert(__NR_epoll_ctl);     // control interface for an epoll file descriptor\n        allowed_syscalls.insert(__NR_epoll_pwait);   // wait for an I/O event on an epoll file descriptor\n        allowed_syscalls.insert(__NR_epoll_wait);    // wait for an I/O event on an epoll file descriptor\n    }\n\n    void AllowEventFd()\n    {\n        allowed_syscalls.insert(__NR_eventfd2); // create a file descriptor for event notification\n    }\n\n    void AllowFileSystem()\n    {\n        allowed_syscalls.insert(__NR_access);          // check user's permissions for a file\n        allowed_syscalls.insert(__NR_chdir);           // change working directory\n        allowed_syscalls.insert(__NR_chmod);           // change permissions of a file\n        allowed_syscalls.insert(__NR_copy_file_range); // copy a range of data from one file to another\n        allowed_syscalls.insert(__NR_fallocate);       // manipulate file space\n        allowed_syscalls.insert(__NR_fchmod);          // change permissions of a file\n        allowed_syscalls.insert(__NR_fchown);          // change ownership of a file\n        allowed_syscalls.insert(__NR_fdatasync);       // synchronize a file's in-core state with storage device\n        allowed_syscalls.insert(__NR_flock);           // apply or remove an advisory lock on an open file\n        allowed_syscalls.insert(__NR_fstat);           // get file status\n        allowed_syscalls.insert(__NR_fstatfs);         // get file system status\n        allowed_syscalls.insert(__NR_fsync);           // synchronize a file's in-core state with storage device\n        allowed_syscalls.insert(__NR_ftruncate);       // truncate a file to a specified length\n        allowed_syscalls.insert(__NR_getcwd);          // get current working directory\n        allowed_syscalls.insert(__NR_getdents);        // get directory entries\n        allowed_syscalls.insert(__NR_getdents64);      // get directory entries\n        allowed_syscalls.insert(__NR_lstat);           // get file status\n        allowed_syscalls.insert(__NR_mkdir);           // create a directory\n        allowed_syscalls.insert(__NR_newfstatat);      // get file status\n        allowed_syscalls.insert(__NR_open);            // open and possibly create a file\n        allowed_syscalls.insert(__NR_openat);          // open and possibly create a file\n        allowed_syscalls.insert(__NR_readlink);        // read value of a symbolic link\n        allowed_syscalls.insert(__NR_rename);          // change the name or location of a file\n        allowed_syscalls.insert(__NR_rmdir);           // delete a directory\n        allowed_syscalls.insert(__NR_stat);            // get file status\n        allowed_syscalls.insert(__NR_statfs);          // get filesystem statistics\n        allowed_syscalls.insert(__NR_statx);           // get file status (extended)\n        allowed_syscalls.insert(__NR_unlink);          // delete a name and possibly the file it refers to\n    }\n\n    void AllowFutex()\n    {\n        allowed_syscalls.insert(__NR_futex);           // fast user-space locking\n        allowed_syscalls.insert(__NR_set_robust_list); // set list of robust futexes\n    }\n\n    void AllowGeneralIo()\n    {\n        allowed_syscalls.insert(__NR_ioctl);    // control device\n        allowed_syscalls.insert(__NR_lseek);    // reposition read/write file offset\n        allowed_syscalls.insert(__NR_poll);     // wait for some event on a file descriptor\n        allowed_syscalls.insert(__NR_ppoll);    // wait for some event on a file descriptor\n        allowed_syscalls.insert(__NR_pread64);  // read from a file descriptor at a given offset\n        allowed_syscalls.insert(__NR_pwrite64); // write to a file descriptor at a given offset\n        allowed_syscalls.insert(__NR_read);     // read from a file descriptor\n        allowed_syscalls.insert(__NR_readv);    // read data into multiple buffers\n        allowed_syscalls.insert(__NR_recvfrom); // receive a message from a socket\n        allowed_syscalls.insert(__NR_recvmsg);  // receive a message from a socket\n        allowed_syscalls.insert(__NR_select);   // synchronous I/O multiplexing\n        allowed_syscalls.insert(__NR_sendmmsg); // send multiple messages on a socket\n        allowed_syscalls.insert(__NR_sendmsg);  // send a message on a socket\n        allowed_syscalls.insert(__NR_sendto);   // send a message on a socket\n        allowed_syscalls.insert(__NR_write);    // write to a file descriptor\n        allowed_syscalls.insert(__NR_writev);   // write data into multiple buffers\n    }\n\n    void AllowGetRandom()\n    {\n        allowed_syscalls.insert(__NR_getrandom); // obtain a series of random bytes\n    }\n\n    void AllowGetSimpleId()\n    {\n        allowed_syscalls.insert(__NR_getegid);   // get group identity\n        allowed_syscalls.insert(__NR_geteuid);   // get user identity\n        allowed_syscalls.insert(__NR_getgid);    // get group identity\n        allowed_syscalls.insert(__NR_getpgid);   // get process group\n        allowed_syscalls.insert(__NR_getpid);    // get process identification\n        allowed_syscalls.insert(__NR_getppid);   // get process identification\n        allowed_syscalls.insert(__NR_getresgid); // get real, effective and saved group IDs\n        allowed_syscalls.insert(__NR_getresuid); // get real, effective and saved user IDs\n        allowed_syscalls.insert(__NR_getsid);    // get session ID\n        allowed_syscalls.insert(__NR_gettid);    // get thread identification\n        allowed_syscalls.insert(__NR_getuid);    // get user identity\n    }\n\n    void AllowGetTime()\n    {\n        allowed_syscalls.insert(__NR_clock_getres);  // find the resolution (precision) of the specified clock\n        allowed_syscalls.insert(__NR_clock_gettime); // retrieve the time of the specified clock\n        allowed_syscalls.insert(__NR_gettimeofday);  // get timeval\n    }\n\n    void AllowGlobalProcessEnvironment()\n    {\n        allowed_syscalls.insert(__NR_getrlimit); // get resource limits\n        allowed_syscalls.insert(__NR_getrusage); // get resource usage\n        allowed_syscalls.insert(__NR_prlimit64); // get/set resource limits\n    }\n\n    void AllowGlobalSystemStatus()\n    {\n        allowed_syscalls.insert(__NR_sysinfo); // return system information\n        allowed_syscalls.insert(__NR_uname);   // get name and information about current kernel\n    }\n\n    void AllowKernelInternalApi()\n    {\n        allowed_syscalls.insert(__NR_restart_syscall); // restart a system call after interruption by a stop signal\n    }\n\n    void AllowNetwork()\n    {\n        allowed_syscalls.insert(__NR_accept);     // accept a connection on a socket\n        allowed_syscalls.insert(__NR_accept4);    // accept a connection on a socket\n        allowed_syscalls.insert(__NR_bind);       // bind a name to a socket\n        allowed_syscalls.insert(__NR_connect);    // initiate a connection on a socket\n        allowed_syscalls.insert(__NR_listen);     // listen for connections on a socket\n        allowed_syscalls.insert(__NR_setsockopt); // set options on sockets\n        allowed_syscalls.insert(__NR_socket);     // create an endpoint for communication\n        allowed_syscalls.insert(__NR_socketpair); // create a pair of connected sockets\n    }\n\n    void AllowNetworkSocketInformation()\n    {\n        allowed_syscalls.insert(__NR_getpeername); // get name of connected peer socket\n        allowed_syscalls.insert(__NR_getsockname); // get socket name\n        allowed_syscalls.insert(__NR_getsockopt);  // get options on sockets\n    }\n\n    void AllowOperationOnExistingFileDescriptor()\n    {\n        allowed_syscalls.insert(__NR_close);    // close a file descriptor\n        allowed_syscalls.insert(__NR_dup);      // duplicate a file descriptor\n        allowed_syscalls.insert(__NR_dup2);     // duplicate a file descriptor\n        allowed_syscalls.insert(__NR_fcntl);    // manipulate file descriptor\n        allowed_syscalls.insert(__NR_shutdown); // shut down part of a full-duplex connection\n    }\n\n    void AllowPipe()\n    {\n        allowed_syscalls.insert(__NR_pipe);  // create pipe\n        allowed_syscalls.insert(__NR_pipe2); // create pipe\n    }\n\n    void AllowPrctl()\n    {\n        allowed_syscalls.insert(__NR_arch_prctl); // set architecture-specific thread state\n        allowed_syscalls.insert(__NR_prctl);      // operations on a process\n    }\n\n    void AllowProcessStartOrDeath()\n    {\n        allowed_syscalls.insert(__NR_clone);      // create a child process\n        allowed_syscalls.insert(__NR_clone3);     // create a child process\n        allowed_syscalls.insert(__NR_exit);       // terminate the calling process\n        allowed_syscalls.insert(__NR_exit_group); // exit all threads in a process\n        allowed_syscalls.insert(__NR_fork);       // create a child process\n        allowed_syscalls.insert(__NR_tgkill);     // send a signal to a thread\n        allowed_syscalls.insert(__NR_wait4);      // wait for process to change state, BSD style\n    }\n\n    void AllowScheduling()\n    {\n        allowed_syscalls.insert(__NR_sched_getaffinity);  // set a thread's CPU affinity mask\n        allowed_syscalls.insert(__NR_sched_getparam);     // get scheduling parameters\n        allowed_syscalls.insert(__NR_sched_getscheduler); // get scheduling policy/parameters\n        allowed_syscalls.insert(__NR_sched_setscheduler); // set scheduling policy/parameters\n        allowed_syscalls.insert(__NR_sched_yield);        // yield the processor\n    }\n\n    void AllowSignalHandling()\n    {\n        allowed_syscalls.insert(__NR_rt_sigaction);   // examine and change a signal action\n        allowed_syscalls.insert(__NR_rt_sigprocmask); // examine and change blocked signals\n        allowed_syscalls.insert(__NR_rt_sigreturn);   // return from signal handler and cleanup stack frame\n        allowed_syscalls.insert(__NR_sigaltstack);    // set and/or get signal stack context\n    }\n\n    void AllowSleep()\n    {\n        allowed_syscalls.insert(__NR_clock_nanosleep); // high-resolution sleep with specifiable clock\n        allowed_syscalls.insert(__NR_nanosleep);       // high-resolution sleep\n    }\n\n    void AllowUmask()\n    {\n        allowed_syscalls.insert(__NR_umask); // set file mode creation mask\n    }\n\n    // See Linux kernel developer Kees Cook's seccomp guide at <https://outflux.net/teach-seccomp/>\n    // for an accessible introduction to using seccomp.\n    //\n    // This function largely follows <https://outflux.net/teach-seccomp/step-3/seccomp-bpf.h>.\n    std::vector<sock_filter> BuildFilter(SyscallSandboxAction default_action)\n    {\n        std::vector<sock_filter> bpf_policy;\n        // See VALIDATE_ARCHITECTURE in seccomp-bpf.h referenced above.\n        bpf_policy.push_back(BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, arch)));\n        // Portability note: AUDIT_ARCH_X86_64 is Linux x86_64 specific.\n        bpf_policy.push_back(BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, AUDIT_ARCH_X86_64, 1, 0));\n        bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL_PROCESS));\n        // See EXAMINE_SYSCALL in seccomp-bpf.h referenced above.\n        bpf_policy.push_back(BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr)));\n        for (const uint32_t allowed_syscall : allowed_syscalls) {\n            // See ALLOW_SYSCALL in seccomp-bpf.h referenced above.\n            bpf_policy.push_back(BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, allowed_syscall, 0, 1));\n            bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW));\n        }\n        switch (default_action) {\n        case SyscallSandboxAction::KILL_PROCESS:\n            // Disallow syscall and kill the process.\n            //\n            // See KILL_PROCESS in seccomp-bpf.h referenced above.\n            //\n            // Note that we're using SECCOMP_RET_KILL_PROCESS (kill the process) instead\n            // of SECCOMP_RET_KILL_THREAD (kill the thread). The SECCOMP_RET_KILL_PROCESS\n            // action was introduced in Linux 4.14.\n            //\n            // SECCOMP_RET_KILL_PROCESS: Results in the entire process exiting immediately without\n            // executing the system call.\n            //\n            // SECCOMP_RET_KILL_PROCESS documentation:\n            // <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html>\n            bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL_PROCESS));\n            break;\n        case SyscallSandboxAction::INVOKE_SIGNAL_HANDLER:\n            // Disallow syscall and force a SIGSYS to trigger syscall debug reporter.\n            //\n            // SECCOMP_RET_TRAP: Results in the kernel sending a SIGSYS signal to the triggering\n            // task without executing the system call.\n            //\n            // SECCOMP_RET_TRAP documentation:\n            // <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html>\n            bpf_policy.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP));\n            break;\n        }\n        return bpf_policy;\n    }\n};\n} // namespace\n\nbool SetupSyscallSandbox(bool log_syscall_violation_before_terminating)\n{\n    assert(!g_syscall_sandbox_enabled && \"SetupSyscallSandbox(...) should only be called once.\");\n    g_syscall_sandbox_enabled = true;\n    g_syscall_sandbox_log_violation_before_terminating = log_syscall_violation_before_terminating;\n    if (log_syscall_violation_before_terminating) {\n        if (!SetupSyscallSandboxDebugHandler()) {\n            return false;\n        }\n    }\n    SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION);\n    return true;\n}\n\nvoid TestDisallowedSandboxCall()\n{\n    // The getgroups syscall is assumed NOT to be allowed by the syscall sandbox policy.\n    std::array<gid_t, 1> groups;\n    [[maybe_unused]] int32_t ignored = getgroups(groups.size(), groups.data());\n}\n#endif // defined(USE_SYSCALL_SANDBOX)\n\nvoid SetSyscallSandboxPolicy(SyscallSandboxPolicy syscall_policy)\n{\n#if defined(USE_SYSCALL_SANDBOX)\n    if (!g_syscall_sandbox_enabled) {\n        return;\n    }\n    SeccompPolicyBuilder seccomp_policy_builder;\n    switch (syscall_policy) {\n    case SyscallSandboxPolicy::INITIALIZATION: // Thread: main thread (state: init)\n        // SyscallSandboxPolicy::INITIALIZATION is the first policy loaded.\n        //\n        // Subsequently loaded policies can reduce the abilities further, but\n        // abilities can never be regained.\n        //\n        // SyscallSandboxPolicy::INITIALIZATION must thus be a superset of all\n        // other policies.\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::INITIALIZATION_DNS_SEED: // Thread: dnsseed\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::INITIALIZATION_LOAD_BLOCKS: // Thread: loadblk\n        seccomp_policy_builder.AllowFileSystem();\n        break;\n    case SyscallSandboxPolicy::INITIALIZATION_MAP_PORT: // Thread: mapport\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::MESSAGE_HANDLER: // Thread: msghand\n        seccomp_policy_builder.AllowFileSystem();\n        break;\n    case SyscallSandboxPolicy::NET: // Thread: net\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::NET_ADD_CONNECTION: // Thread: addcon\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::NET_HTTP_SERVER: // Thread: http\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::NET_HTTP_SERVER_WORKER: // Thread: httpworker.<N>\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::NET_OPEN_CONNECTION: // Thread: opencon\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::SCHEDULER: // Thread: scheduler\n        seccomp_policy_builder.AllowFileSystem();\n        break;\n    case SyscallSandboxPolicy::TOR_CONTROL: // Thread: torcontrol\n        seccomp_policy_builder.AllowFileSystem();\n        seccomp_policy_builder.AllowNetwork();\n        break;\n    case SyscallSandboxPolicy::TX_INDEX: // Thread: txindex\n        seccomp_policy_builder.AllowFileSystem();\n        break;\n    case SyscallSandboxPolicy::VALIDATION_SCRIPT_CHECK: // Thread: scriptch.<N>\n        break;\n    case SyscallSandboxPolicy::SHUTOFF: // Thread: main thread (state: shutoff)\n        seccomp_policy_builder.AllowFileSystem();\n        break;\n    }\n\n    const SyscallSandboxAction default_action = g_syscall_sandbox_log_violation_before_terminating ? SyscallSandboxAction::INVOKE_SIGNAL_HANDLER : SyscallSandboxAction::KILL_PROCESS;\n    std::vector<sock_filter> filter = seccomp_policy_builder.BuildFilter(default_action);\n    const sock_fprog prog = {\n        .len = static_cast<uint16_t>(filter.size()),\n        .filter = filter.data(),\n    };\n    // Do not allow abilities to be regained after being dropped.\n    //\n    // PR_SET_NO_NEW_PRIVS documentation: <https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html>\n    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {\n        throw std::runtime_error(\"Syscall sandbox enforcement failed: prctl(PR_SET_NO_NEW_PRIVS)\");\n    }\n    // Install seccomp-bpf syscall filter.\n    //\n    // PR_SET_SECCOMP documentation: <https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html>\n    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) {\n        throw std::runtime_error(\"Syscall sandbox enforcement failed: prctl(PR_SET_SECCOMP)\");\n    }\n\n    const std::string thread_name = !util::ThreadGetInternalName().empty() ? util::ThreadGetInternalName() : \"*unnamed*\";\n    LogPrint(BCLog::UTIL, \"Syscall filter installed for thread \\\"%s\\\"\\n\", thread_name);\n#endif // defined(USE_SYSCALL_SANDBOX)\n}\n"
  },
  {
    "path": "src/util/syscall_sandbox.h",
    "content": "// Copyright (c) 2020-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_SYSCALL_SANDBOX_H\n#define CORE_UTIL_SYSCALL_SANDBOX_H\n\nenum class SyscallSandboxPolicy {\n    // 1. Initialization\n    INITIALIZATION,\n    INITIALIZATION_DNS_SEED,\n    INITIALIZATION_LOAD_BLOCKS,\n    INITIALIZATION_MAP_PORT,\n\n    // 2. Steady state (non-initialization, non-shutdown)\n    MESSAGE_HANDLER,\n    NET,\n    NET_ADD_CONNECTION,\n    NET_HTTP_SERVER,\n    NET_HTTP_SERVER_WORKER,\n    NET_OPEN_CONNECTION,\n    SCHEDULER,\n    TOR_CONTROL,\n    TX_INDEX,\n    VALIDATION_SCRIPT_CHECK,\n\n    // 3. Shutdown\n    SHUTOFF,\n};\n\n//! Force the current thread (and threads created from the current thread) into a restricted-service\n//! operating mode where only a subset of all syscalls are available.\n//!\n//! Subsequent calls to this function can reduce the abilities further, but abilities can never be\n//! regained.\n//!\n//! This function is a no-op unless SetupSyscallSandbox(...) has been called.\n//!\n//! SetupSyscallSandbox(...) is called during bitcoind initialization if Bitcoin Core was compiled\n//! with seccomp-bpf support (--with-seccomp) *and* the parameter -sandbox=<mode> was passed to\n//! bitcoind.\n//!\n//! This experimental feature is available under Linux x86_64 only.\nvoid SetSyscallSandboxPolicy(SyscallSandboxPolicy syscall_policy);\n\n#if defined(USE_SYSCALL_SANDBOX)\n//! Setup and enable the experimental syscall sandbox for the running process.\n//!\n//! SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION) is called as part of\n//! SetupSyscallSandbox(...).\n[[nodiscard]] bool SetupSyscallSandbox(bool log_syscall_violation_before_terminating);\n\n//! Invoke a disallowed syscall. Use for testing purposes.\nvoid TestDisallowedSandboxCall();\n#endif // defined(USE_SYSCALL_SANDBOX)\n\n#endif // CORE_UTIL_SYSCALL_SANDBOX_H\n"
  },
  {
    "path": "src/util/thread.cpp",
    "content": "// Copyright (c) 2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include <util/thread.h>\n\n#include <logging.h>\n#include <util/threadnames.h>\n\n#include <exception>\n\nvoid util::TraceThread(const char* thread_name, std::function<void()> thread_func)\n{\n    util::ThreadRename(thread_name);\n    try {\n        LogPrintf(\"%s thread start\\n\", thread_name);\n        thread_func();\n        LogPrintf(\"%s thread exit\\n\", thread_name);\n    } catch (const std::exception& e) {\n        PrintExceptionContinue(&e, thread_name);\n        throw;\n    } catch (...) {\n        PrintExceptionContinue(nullptr, thread_name);\n        throw;\n    }\n}\n"
  },
  {
    "path": "src/util/thread.h",
    "content": "// Copyright (c) 2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_THREAD_H\n#define CORE_UTIL_THREAD_H\n\n#include <functional>\n#include <string>\n#include <appname.h>\n#include <tinyformat.h>\n#include \"logging.h\"\n\nvoid PrintExceptionContinue(const std::exception *pex, const char* pszThread);\n\nnamespace util {\n/**\n * A wrapper for do-something-once thread functions.\n */\nvoid TraceThread(const char* thread_name, std::function<void()> thread_func);\n\n} // namespace util\n\n#endif // CORE_UTIL_THREAD_H\n"
  },
  {
    "path": "src/util/threadnames.cpp",
    "content": "// Copyright (c) 2018-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif\n\n#include <thread>\n\n#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))\n#include <pthread.h>\n#include <pthread_np.h>\n#endif\n\n#include <util/threadnames.h>\n\n#ifdef HAVE_SYS_PRCTL_H\n#include <sys/prctl.h> // For prctl, PR_SET_NAME, PR_GET_NAME\n#endif\n\n//! Set the thread's name at the process level. Does not affect the\n//! internal name.\nstatic void SetThreadName(const char* name)\n{\n#if defined(PR_SET_NAME)\n    // Only the first 15 characters are used (16 - NUL terminator)\n    ::prctl(PR_SET_NAME, name, 0, 0, 0);\n#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))\n    pthread_set_name_np(pthread_self(), name);\n#elif defined(MAC_OSX)\n    pthread_setname_np(name);\n#else\n    // Prevent warnings for unused parameters...\n    (void)name;\n#endif\n}\n\n// If we have thread_local, just keep thread ID and name in a thread_local\n// global.\n#if defined(HAVE_THREAD_LOCAL)\n\nstatic thread_local std::string g_thread_name;\nconst std::string& util::ThreadGetInternalName() { return g_thread_name; }\n//! Set the in-memory internal name for this thread. Does not affect the process\n//! name.\nstatic void SetInternalName(std::string name) { g_thread_name = std::move(name); }\n\n// Without thread_local available, don't handle internal name at all.\n#else\n\nstatic const std::string empty_string;\nconst std::string& util::ThreadGetInternalName() { return empty_string; }\nstatic void SetInternalName(std::string name) { }\n#endif\n\nvoid util::ThreadRename(std::string&& name)\n{\n    SetThreadName((\"b-\" + name).c_str());\n    SetInternalName(std::move(name));\n}\n\nvoid util::ThreadSetInternalName(std::string&& name)\n{\n    SetInternalName(std::move(name));\n}\n"
  },
  {
    "path": "src/util/threadnames.h",
    "content": "// Copyright (c) 2018-2019 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef CORE_UTIL_THREADNAMES_H\n#define CORE_UTIL_THREADNAMES_H\n\n#include <string>\n\nnamespace util {\n//! Rename a thread both in terms of an internal (in-memory) name as well\n//! as its system thread name.\n//! @note Do not call this for the main thread, as this will interfere with\n//! UNIX utilities such as top and killall. Use ThreadSetInternalName instead.\nvoid ThreadRename(std::string&&);\n\n//! Set the internal (in-memory) name of the current thread only.\nvoid ThreadSetInternalName(std::string&&);\n\n//! Get the thread's internal (in-memory) name; used e.g. for identification in\n//! logging.\nconst std::string& ThreadGetInternalName();\n\n} // namespace util\n\n#endif // CORE_UTIL_THREADNAMES_H\n"
  },
  {
    "path": "src/util/time.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#if defined(HAVE_CONFIG_H)\n#include <config/build-config.h>\n#endif\n\n#include <compat.h>\n#include <util/time.h>\n\n#include <util/check.h>\n\n#include <atomic>\n#include <boost/date_time/posix_time/posix_time.hpp>\n#include <ctime>\n#include <thread>\n\n#include <tinyformat.h>\n\n#include <boost/thread.hpp>\n\nvoid UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread::sleep_for(n); }\n\nstatic std::atomic<int64_t> nMockTime(0); //!< For testing\n\nint64_t GetTime()\n{\n    int64_t mocktime = nMockTime.load(std::memory_order_relaxed);\n    if (mocktime) return mocktime;\n\n    time_t now = time(nullptr);\n    assert(now > 0);\n    return now;\n}\n\nbool ChronoSanityCheck()\n{\n    // std::chrono::system_clock.time_since_epoch and time_t(0) are not guaranteed\n    // to use the Unix epoch timestamp, prior to C++20, but in practice they almost\n    // certainly will. Any differing behavior will be assumed to be an error, unless\n    // certain platforms prove to consistently deviate, at which point we'll cope\n    // with it by adding offsets.\n\n    // Create a new clock from time_t(0) and make sure that it represents 0\n    // seconds from the system_clock's time_since_epoch. Then convert that back\n    // to a time_t and verify that it's the same as before.\n    const time_t time_t_epoch{};\n    auto clock = std::chrono::system_clock::from_time_t(time_t_epoch);\n    if (std::chrono::duration_cast<std::chrono::seconds>(clock.time_since_epoch()).count() != 0) {\n        return false;\n    }\n\n    time_t time_val = std::chrono::system_clock::to_time_t(clock);\n    if (time_val != time_t_epoch) {\n        return false;\n    }\n\n    // Check that the above zero time is actually equal to the known unix timestamp.\n    struct tm epoch;\n#ifdef HAVE_GMTIME_R\n    if (gmtime_r(&time_val, &epoch) == nullptr) {\n#else\n    if (gmtime_s(&epoch, &time_val) != 0) {\n#endif\n        return false;\n    }\n\n    if ((epoch.tm_sec != 0)  ||\n       (epoch.tm_min  != 0)  ||\n       (epoch.tm_hour != 0)  ||\n       (epoch.tm_mday != 1)  ||\n       (epoch.tm_mon  != 0)  ||\n       (epoch.tm_year != 70)) {\n        return false;\n    }\n    return true;\n}\n\ntemplate <typename T>\nT GetTime()\n{\n    const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};\n\n    return std::chrono::duration_cast<T>(\n        mocktime.count() ?\n            mocktime :\n            std::chrono::microseconds{GetTimeMicros()});\n}\ntemplate std::chrono::seconds GetTime();\ntemplate std::chrono::milliseconds GetTime();\ntemplate std::chrono::microseconds GetTime();\n\ntemplate <typename T>\nstatic T GetSystemTime()\n{\n    const auto now = std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch());\n    assert(now.count() > 0);\n    return now;\n}\n\nvoid SetMockTime(int64_t nMockTimeIn)\n{\n    Assert(nMockTimeIn >= 0);\n    nMockTime.store(nMockTimeIn, std::memory_order_relaxed);\n}\n\nvoid SetMockTime(std::chrono::seconds mock_time_in)\n{\n    nMockTime.store(mock_time_in.count(), std::memory_order_relaxed);\n}\n\nstd::chrono::seconds GetMockTime()\n{\n    return std::chrono::seconds(nMockTime.load(std::memory_order_relaxed));\n}\n\nint64_t GetTimeMillis()\n{\n    return int64_t{GetSystemTime<std::chrono::milliseconds>().count()};\n}\n\nint64_t GetTimeMicros()\n{\n    return int64_t{GetSystemTime<std::chrono::microseconds>().count()};\n}\n\nint64_t GetTimeSeconds()\n{\n    return int64_t{GetSystemTime<std::chrono::seconds>().count()};\n}\n\nvoid MilliSleep(int64_t n)\n{\n    /**\n    * Boost's sleep_for was uninterruptible when backed by nanosleep from 1.50\n    * until fixed in 1.52. Use the deprecated sleep method for the broken case.\n    * See: https://svn.boost.org/trac/boost/ticket/7238\n    */\n    #if defined(HAVE_WORKING_BOOST_SLEEP_FOR)\n        boost::this_thread::sleep_for(boost::chrono::milliseconds(n));\n    #elif defined(HAVE_WORKING_BOOST_SLEEP)\n        boost::this_thread::sleep(boost::posix_time::milliseconds(n));\n    #else\n        //should never get here\n        #error missing boost sleep implementation\n    #endif\n}\n\nstd::string FormatISO8601DateTime(int64_t nTime) {\n    struct tm ts;\n    time_t time_val = nTime;\n#ifdef HAVE_GMTIME_R\n    if (gmtime_r(&time_val, &ts) == nullptr) {\n#else\n    if (gmtime_s(&ts, &time_val) != 0) {\n#endif\n        return {};\n    }\n    return strprintf(\"%04i-%02i-%02iT%02i:%02i:%02iZ\", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);\n}\n\nstd::string FormatISO8601Date(int64_t nTime) {\n    struct tm ts;\n    time_t time_val = nTime;\n#ifdef HAVE_GMTIME_R\n    if (gmtime_r(&time_val, &ts) == nullptr) {\n#else\n    if (gmtime_s(&ts, &time_val) != 0) {\n#endif\n        return {};\n    }\n    return strprintf(\"%04i-%02i-%02i\", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);\n}\n\nint64_t ParseISO8601DateTime(const std::string& str)\n{\n    static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);\n    static const std::locale loc(std::locale::classic(),\n        new boost::posix_time::time_input_facet(\"%Y-%m-%dT%H:%M:%SZ\"));\n    std::istringstream iss(str);\n    iss.imbue(loc);\n    boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);\n    iss >> ptime;\n    if (ptime.is_not_a_date_time() || epoch > ptime)\n        return 0;\n    return (ptime - epoch).total_seconds();\n}\n\nstruct timeval MillisToTimeval(int64_t nTimeout)\n{\n    struct timeval timeout;\n    timeout.tv_sec  = nTimeout / 1000;\n    timeout.tv_usec = (nTimeout % 1000) * 1000;\n    return timeout;\n}\n\nstruct timeval MillisToTimeval(std::chrono::milliseconds ms)\n{\n    return MillisToTimeval(count_milliseconds(ms));\n}\n"
  },
  {
    "path": "src/util/time.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2021 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_UTIL_TIME_H\n#define BITCOIN_UTIL_TIME_H\n\n#include <compat.h>\n\n#include <chrono>\n#include <stdint.h>\n#include <string>\n\nusing namespace std::chrono_literals;\n\nvoid UninterruptibleSleep(const std::chrono::microseconds& n);\n\n/**\n * Helper to count the seconds of a duration.\n *\n * All durations should be using std::chrono and calling this should generally\n * be avoided in code. Though, it is still preferred to an inline t.count() to\n * protect against a reliance on the exact type of t.\n *\n * This helper is used to convert durations before passing them over an\n * interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI)\n */\nconstexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); }\nconstexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }\nconstexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); }\n\nusing SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;\n\n/**\n * Helper to count the seconds in any std::chrono::duration type\n */\ninline double CountSecondsDouble(SecondsDouble t) { return t.count(); }\n\n/**\n * DEPRECATED\n * Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable)\n */\nint64_t GetTime();\n\n/** Returns the system time (not mockable) */\nint64_t GetTimeMillis();\n/** Returns the system time (not mockable) */\nint64_t GetTimeMicros();\n/** Returns the system time (not mockable) */\nint64_t GetTimeSeconds(); // Like GetTime(), but not mockable\n\nvoid MilliSleep(int64_t n);\n\n\n/**\n * DEPRECATED\n * Use SetMockTime with chrono type\n *\n * @param[in] nMockTimeIn Time in seconds.\n */\nvoid SetMockTime(int64_t nMockTimeIn);\n\n/** For testing. Set e.g. with the setmocktime rpc, or -mocktime argument */\nvoid SetMockTime(std::chrono::seconds mock_time_in);\n\n/** For testing */\nstd::chrono::seconds GetMockTime();\n\n/** Return system time (or mocked time, if set) */\ntemplate <typename T>\nT GetTime();\n\n/**\n * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}\n * helper functions if possible.\n */\nstd::string FormatISO8601DateTime(int64_t nTime);\nstd::string FormatISO8601Date(int64_t nTime);\nint64_t ParseISO8601DateTime(const std::string& str);\n\n/**\n * Convert milliseconds to a struct timeval for e.g. select.\n */\nstruct timeval MillisToTimeval(int64_t nTimeout);\n\n/**\n * Convert milliseconds to a struct timeval for e.g. select.\n */\nstruct timeval MillisToTimeval(std::chrono::milliseconds ms);\n\n/** Sanity check epoch match normal Unix epoch */\nbool ChronoSanityCheck();\n\n#endif // BITCOIN_UTIL_TIME_H\n"
  },
  {
    "path": "src/util.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"util.h\"\n\n#include \"chainparamsbase.h\"\n#include \"fs.h\"\n#include \"random.h\"\n#include \"serialize.h\"\n#include \"util/strencodings.h\"\n#include \"util/time.h\"\n#include \"appname.h\"\n\n#include <stdarg.h>\n\n#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))\n#include <pthread.h>\n#include <pthread_np.h>\n#endif\n\n#if defined(__APPLE__) && defined(__MACH__)\n#include <TargetConditionals.h>\n#endif\n\n#ifndef WIN32\n// for posix_fallocate\n#ifdef __linux__\n\n#ifdef _POSIX_C_SOURCE\n#undef _POSIX_C_SOURCE\n#endif\n\n#define _POSIX_C_SOURCE 200112L\n\n#endif // __linux__\n\n#include <algorithm>\n#include <fcntl.h>\n#include <sys/resource.h>\n#include <sys/stat.h>\n\n#else\n\n#ifdef _MSC_VER\n#pragma warning(disable:4786)\n#pragma warning(disable:4804)\n#pragma warning(disable:4805)\n#pragma warning(disable:4717)\n#endif\n\n#ifdef _WIN32_WINNT\n#undef _WIN32_WINNT\n#endif\n#define _WIN32_WINNT 0x0501\n\n#ifdef _WIN32_IE\n#undef _WIN32_IE\n#endif\n#define _WIN32_IE 0x0501\n\n#define WIN32_LEAN_AND_MEAN 1\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n\n#include <io.h> /* for _commit */\n#include <shlobj.h>\n#endif\n\n#ifdef HAVE_SYS_PRCTL_H\n#include <sys/prctl.h>\n#endif\n\n#include <boost/algorithm/string/replace.hpp>\n#ifdef HAVE_MALLOPT_ARENA_MAX\n#include <malloc.h>\n#endif\n\n#include <boost/algorithm/string/case_conv.hpp> // for to_lower()\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and ends_with()\n#include <boost/program_options/detail/config_file.hpp>\n#include <boost/thread.hpp>\n#include <openssl/crypto.h>\n#include <openssl/rand.h>\n#include <openssl/conf.h>\n\n\nconst char * const DEFAULT_CONF_FILENAME = \"munt.conf\";\nconst char * const DEFAULT_PID_FILENAME = \"munt_daemon.pid\";\n\nArgsManager gArgs;\nbool fPrintToConsole = false;\nbool fPrintToDebugLog = true;\nbool fNoUI = false;\nbool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;\nbool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;\nbool fLogIPs = DEFAULT_LOGIPS;\nbool gbMinimalLogging = false;\nstd::atomic<bool> fReopenDebugLog(false);\nCTranslationInterface translationInterface;\n\n/** Log categories bitfield. */\nstd::atomic<uint32_t> logCategories(0);\n\n/** Init OpenSSL library multithreading support */\nstatic std::unique_ptr<RecursiveMutex[]> ppmutexOpenSSL;\n\n#pragma message(\"Check thread safety of OpenSSL usage!\")\n/* In recent versions of OpenSSL the CRYPTO_set_locking_callback taking the locking_callback below as an argument is\n * an empty define. So the locking_callback is reported as unused. It could be fine as it is, but we should check\n * that our usage of OpenSSL doesn't have concurrency issues because we should update to newer OpenSSL APIs or something.\n */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunused-function\"\nstatic void locking_callback(int mode, int i, [[maybe_unused]] const char* file, [[maybe_unused]] int line) NO_THREAD_SAFETY_ANALYSIS\n{\n    if (mode & CRYPTO_LOCK) {\n        ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);\n    } else {\n        LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);\n    }\n}\n#pragma GCC diagnostic pop\n\n\n// Singleton for wrapping OpenSSL setup/teardown.\nclass CInit\n{\npublic:\n    CInit()\n    {\n        // Init OpenSSL library multithreading support\n        ppmutexOpenSSL.reset(new RecursiveMutex[CRYPTO_num_locks()]);\n        CRYPTO_set_locking_callback(locking_callback);\n\n        // OpenSSL can optionally load a config file which lists optional loadable modules and engines.\n        // We don't use them so we don't require the config. However some of our libs may call functions\n        // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing\n        // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be\n        // that the config appears to have been loaded and there are no modules/engines available.\n        OPENSSL_no_config();\n\n#ifdef WIN32\n        // Seed OpenSSL PRNG with current contents of the screen\n        RAND_screen();\n#endif\n\n        // Seed OpenSSL PRNG with performance counter\n        RandAddSeed();\n    }\n    ~CInit()\n    {\n        // Securely erase the memory used by the PRNG\n        RAND_cleanup();\n        // Shutdown OpenSSL library multithreading support\n        CRYPTO_set_locking_callback(NULL);\n        // Clear the set of locks now to maintain symmetry with the constructor.\n        ppmutexOpenSSL.reset();\n    }\n}\ninstance_of_cinit;\n\nstruct CLogCategoryDesc\n{\n    uint32_t flag;\n    std::string category;\n};\n\nconst CLogCategoryDesc LogCategories[] =\n{\n    {BCLog::NONE, \"0\"},\n    {BCLog::ALERT, \"alert\"},\n    {BCLog::NET, \"net\"},\n    {BCLog::TOR, \"tor\"},\n    {BCLog::MEMPOOL, \"mempool\"},\n    {BCLog::HTTP, \"http\"},\n    {BCLog::BENCH, \"bench\"},\n    {BCLog::IO, \"io\"},\n    {BCLog::ZMQ, \"zmq\"},\n    {BCLog::DB, \"db\"},\n    {BCLog::RPC, \"rpc\"},\n    {BCLog::ESTIMATEFEE, \"estimatefee\"},\n    {BCLog::ADDRMAN, \"addrman\"},\n    {BCLog::SELECTCOINS, \"selectcoins\"},\n    {BCLog::REINDEX, \"reindex\"},\n    {BCLog::CMPCTBLOCK, \"cmpctblock\"},\n    {BCLog::RAND, \"rand\"},\n    {BCLog::PRUNE, \"prune\"},\n    {BCLog::PROXY, \"proxy\"},\n    {BCLog::MEMPOOLREJ, \"mempoolrej\"},\n    {BCLog::LIBEVENT, \"libevent\"},\n    {BCLog::COINDB, \"coindb\"},\n    {BCLog::DELTA, \"delta\"},\n    {BCLog::WITNESS, \"witness\"},\n    {BCLog::QT, \"qt\"},\n    {BCLog::LEVELDB, \"leveldb\"},\n    {BCLog::WALLET, \"wallet\"},\n    {BCLog::ALL, \"1\"},\n    {BCLog::ALL, \"all\"},\n};\n\nbool GetLogCategory(uint32_t *f, const std::string *str)\n{\n    if (f && str) {\n        if (*str == \"\") {\n            *f = BCLog::ALL;\n            return true;\n        }\n        for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {\n            if (LogCategories[i].category == *str) {\n                *f = LogCategories[i].flag;\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nstd::string ListLogCategories()\n{\n    std::string ret;\n    int outcount = 0;\n    for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {\n        // Omit the special cases.\n        if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {\n            if (outcount != 0) ret += \", \";\n            ret += LogCategories[i].category;\n            outcount++;\n        }\n    }\n    return ret;\n}\n\nstd::vector<CLogCategoryActive> ListActiveLogCategories()\n{\n    std::vector<CLogCategoryActive> ret;\n    for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {\n        // Omit the special cases.\n        if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {\n            CLogCategoryActive catActive;\n            catActive.category = LogCategories[i].category;\n            catActive.active = LogAcceptCategory(LogCategories[i].flag);\n            ret.push_back(catActive);\n        }\n    }\n    return ret;\n}\n\n/** Interpret string as boolean, for argument parsing */\nstatic bool InterpretBool(const std::string& strValue)\n{\n    if (strValue.empty())\n        return true;\n    if (strValue == \"true\")\n        return true;\n    if (strValue == \"yes\")\n        return true;\n    if (strValue == \"1\")\n        return true;\n    if (strValue == \"false\")\n        return false;\n    if (strValue == \"no\")\n        return false;\n    if (strValue == \"0\")\n        return false;\n    return (atoi(strValue) != 0);\n}\n\n/** Turn -noX into -X=0 */\nstatic void InterpretNegativeSetting(std::string& strKey, std::string& strValue)\n{\n    if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')\n    {\n        strKey = \"-\" + strKey.substr(3);\n        strValue = InterpretBool(strValue) ? \"0\" : \"1\";\n    }\n}\n\nvoid ArgsManager::ParseParameters(int argc, const char* const argv[])\n{\n    LOCK(cs_args);\n    //Temporary - migrate old wallet directoriess to new 'munt' wallet directories.\n    fs::path newPath = GetDefaultDataDir();\n    if (!fs::exists(newPath.string()))\n    {\n        try\n        {\n            std::string newPathString = newPath.string();\n            boost::replace_all(newPathString, \"munt\", \"Gulden\");\n            fs::path oldPath(newPathString);\n            if (fs::exists( oldPath.string() ))\n            {\n                fs::rename(oldPath.string(), newPath.string());\n                fs::rename((newPath/\"gulden.conf\").string(), (newPath/\"munt.conf\").string());\n                fs::rename((newPath/\"Gulden.conf\").string(), (newPath/\"munt.conf\").string());\n            }\n        }\n        catch(...){}\n        try\n        {\n            std::string newPathString = newPath.string();\n            boost::replace_all(newPathString, \"munt\", \"gulden\");\n            fs::path oldPath(newPathString);\n            if (fs::exists( oldPath.string() ))\n            {\n                fs::rename(oldPath.string(), newPath.string());\n                fs::rename((newPath/\"guldencoin.conf\").string(), (newPath/\"munt.conf\").string());\n                fs::rename((newPath/\"Guldencoin.conf\").string(), (newPath/\"munt.conf\").string());\n            }\n        }\n        catch(...){}\n    }\n\n    mapArgs.clear();\n    mapMultiArgs.clear();\n\n    ParseExtraParameters(argc - 1, argv + 1);\n}\n\nvoid ArgsManager::ParseExtraParameters(int argc, const char*const argv[])\n{\n    LOCK(cs_args);\n    for (int i = 0; i < argc; i++)\n    {\n        std::string str(argv[i]);\n        std::string strValue;\n        size_t is_index = str.find('=');\n        if (is_index != std::string::npos)\n        {\n            strValue = str.substr(is_index+1);\n            str = str.substr(0, is_index);\n        }\n#ifdef WIN32\n        boost::to_lower(str);\n        if (boost::algorithm::starts_with(str, \"/\"))\n            str = \"-\" + str.substr(1);\n#endif\n\n        if (str[0] != '-')\n            break;\n\n        // Interpret --foo as -foo.\n        // If both --foo and -foo are set, the last takes effect.\n        if (str.length() > 1 && str[1] == '-')\n            str = str.substr(1);\n        InterpretNegativeSetting(str, strValue);\n\n        mapArgs[str] = strValue;\n        mapMultiArgs[str].push_back(strValue);\n    }\n}\n\nstd::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)\n{\n    LOCK(cs_args);\n    return mapMultiArgs.at(strArg);\n}\n\nbool ArgsManager::IsArgSet(const std::string& strArg)\n{\n    LOCK(cs_args);\n    return mapArgs.count(strArg);\n}\n\nstd::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)\n{\n    LOCK(cs_args);\n    if (mapArgs.count(strArg))\n        return mapArgs[strArg];\n    return strDefault;\n}\n\nint64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault)\n{\n    LOCK(cs_args);\n    if (mapArgs.count(strArg))\n        return atoi64(mapArgs[strArg]);\n    return nDefault;\n}\n\nbool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault)\n{\n    LOCK(cs_args);\n    if (mapArgs.count(strArg))\n        return InterpretBool(mapArgs[strArg]);\n    return fDefault;\n}\n\nbool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)\n{\n    LOCK(cs_args);\n    if (mapArgs.count(strArg))\n        return false;\n    ForceSetArg(strArg, strValue);\n    return true;\n}\n\nbool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)\n{\n    if (fValue)\n        return SoftSetArg(strArg, std::string(\"1\"));\n    else\n        return SoftSetArg(strArg, std::string(\"0\"));\n}\n\nvoid ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)\n{\n    LOCK(cs_args);\n    mapArgs[strArg] = strValue;\n    mapMultiArgs[strArg].clear();\n    mapMultiArgs[strArg].push_back(strValue);\n}\n\n\n\nstatic const int screenWidth = 79;\nstatic const int optIndent = 2;\nstatic const int msgIndent = 7;\n\nstd::string HelpMessageGroup(const std::string &message) {\n    return std::string(message) + std::string(\"\\n\\n\");\n}\n\nstd::string HelpMessageOpt(const std::string &option, const std::string &message) {\n    return std::string(optIndent,' ') + std::string(option) +\n           std::string(\"\\n\") + std::string(msgIndent,' ') +\n           FormatParagraph(message, screenWidth - msgIndent, msgIndent) +\n           std::string(\"\\n\\n\");\n}\n\nstatic std::string FormatException(const std::exception* pex, const char* pszThread)\n{\n#ifdef WIN32\n    char pszModule[MAX_PATH] = \"\";\n    GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));\n#else\n    const char* pszModule = GLOBAL_APPNAME;\n#endif\n    if (pex)\n        return strprintf(\n            \"EXCEPTION: %s       \\n%s       \\n%s in %s       \\n\", typeid(*pex).name(), pex->what(), pszModule, pszThread);\n    else\n        return strprintf(\n            \"UNKNOWN EXCEPTION       \\n%s in %s       \\n\", pszModule, pszThread);\n}\n\nvoid PrintExceptionContinue(const std::exception* pex, const char* pszThread)\n{\n    std::string message = FormatException(pex, pszThread);\n    LogPrintf(\"\\n\\n************************\\n%s\\n\", message);\n    fprintf(stderr, \"\\n\\n************************\\n%s\\n\", message.c_str());\n}\n\nstd::string defaultDataDirOverride=\"\";\nfs::path GetDefaultDataDir()\n{\n    if (!defaultDataDirOverride.empty())\n        return defaultDataDirOverride;\n\n    // Windows < Vista: C:\\Documents and Settings\\Username\\Application Data\\munt\n    // Windows >= Vista: C:\\Users\\Username\\AppData\\Roaming\\munt\n    // Mac: ~/Library/Application Support/munt\n    // Unix: ~/.munt\n#ifdef WIN32\n    // Windows\n    return GetSpecialFolderPath(CSIDL_APPDATA) / \"munt\";\n#else\n    fs::path pathRet;\n    char* pszHome = getenv(\"HOME\");\n    if (pszHome == NULL || strlen(pszHome) == 0)\n        pathRet = fs::path(\"/\");\n    else\n        pathRet = fs::path(pszHome);\n#ifdef MAC_OSX\n    // Mac\n    return pathRet / \"Library/Application Support/munt\";\n#else\n    // Unix\n    return pathRet / \".munt\";\n#endif\n#endif\n}\n\nstatic fs::path pathCached;\nstatic fs::path pathCachedNetSpecific;\nstatic RecursiveMutex csPathCached;\n\nconst fs::path &GetDataDir(bool fNetSpecific)\n{\n    LOCK(csPathCached);\n\n    fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;\n\n    // This can be called during exceptions by LogPrintf(), so we cache the\n    // value so we don't have to do memory allocations after that.\n    if (!path.empty())\n        return path;\n\n    if (IsArgSet(\"-datadir\")) {\n        path = fs::system_complete(GetArg(\"-datadir\", \"\"));\n        if (!fs::is_directory(path)) {\n            path = \"\";\n            return path;\n        }\n    } else {\n        path = GetDefaultDataDir();\n    }\n    if (fNetSpecific)\n        path /= BaseParams().DataDir();\n\n    fs::create_directories(path);\n\n    return path;\n}\n\nvoid ClearDatadirCache()\n{\n    LOCK(csPathCached);\n\n    pathCached = fs::path();\n    pathCachedNetSpecific = fs::path();\n}\n\nfs::path GetConfigFile(const std::string& confPath)\n{\n    fs::path pathConfigFile(confPath);\n    if (!pathConfigFile.is_complete())\n        pathConfigFile = GetDataDir(false) / pathConfigFile;\n\n    return pathConfigFile;\n}\n\nvoid ArgsManager::ReadConfigFile(const std::string& confPath)\n{\n    static bool fTestnet = IsArgSet(\"-testnet\");\n    static bool fRegTest = IsArgSet(\"-regtest\");\n    static bool fRegTestLegacy = IsArgSet(\"-regtestlegacy\");\n    fs::ifstream streamConfig(GetConfigFile(confPath));\n    if (!streamConfig.good())\n        return; // No munt.conf file is OK\n\n    {\n        LOCK(cs_args);\n        std::set<std::string> setOptions;\n        setOptions.insert(\"*\");\n\n        for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)\n        {\n            // Don't overwrite existing settings so command line settings override munt.conf\n            std::string strKey = std::string(\"-\") + it->string_key;\n            std::string strValue = it->value[0];\n            if (fRegTest)\n                boost::replace_all(strKey, \"regtest.\", \"\");\n            if (fRegTestLegacy)\n                boost::replace_all(strKey, \"regtestlegacy.\", \"\");\n            else if (fTestnet)\n                boost::replace_all(strKey, \"testnet.\", \"\");\n            else\n                boost::replace_all(strKey, \"mainnet.\", \"\");\n            InterpretNegativeSetting(strKey, strValue);\n            if (mapArgs.count(strKey) == 0)\n                mapArgs[strKey] = strValue;\n            mapMultiArgs[strKey].push_back(strValue);\n            \n            if (strKey == \"-testnet\")\n                fTestnet=true;\n            if (strKey == \"-regtest\")\n                fRegTest=true;\n            if (strKey == \"-regtestlegacy\")\n                fRegTestLegacy=true;\n        }\n    }\n    // If datadir is changed in .conf file:\n    ClearDatadirCache();\n}\n\n#ifndef WIN32\nfs::path GetPidFile()\n{\n    fs::path pathPidFile(GetArg(\"-pid\", DEFAULT_PID_FILENAME));\n    if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;\n    return pathPidFile;\n}\n\nvoid CreatePidFile(const fs::path &path, pid_t pid)\n{\n    FILE* file = fsbridge::fopen(path, \"w\");\n    if (file)\n    {\n        fprintf(file, \"%d\\n\", pid);\n        fclose(file);\n    }\n}\n#endif\n\nbool RenameOver(fs::path src, fs::path dest)\n{\n#ifdef WIN32\n    return MoveFileExA(src.string().c_str(), dest.string().c_str(),\n                       MOVEFILE_REPLACE_EXISTING) != 0;\n#else\n    int rc = std::rename(src.string().c_str(), dest.string().c_str());\n    return (rc == 0);\n#endif /* WIN32 */\n}\n\n/**\n * Ignores exceptions thrown by Boost's create_directory if the requested directory exists.\n * Specifically handles case where path p exists, but it wasn't possible for the user to\n * write to the parent directory.\n */\nbool TryCreateDirectory(const fs::path& p)\n{\n    try\n    {\n        return fs::create_directory(p);\n    } catch (const fs::filesystem_error&) {\n        if (!fs::exists(p) || !fs::is_directory(p))\n            throw;\n    }\n\n    // create_directory didn't create the directory, it had to have existed already\n    return false;\n}\n\nvoid FileCommit(FILE *file)\n{\n    fflush(file); // harmless if redundantly called\n#ifdef WIN32\n    HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));\n    FlushFileBuffers(hFile);\n#else\n    #if defined(__linux__) || defined(__NetBSD__)\n    fdatasync(fileno(file));\n    #elif defined(__APPLE__) && defined(F_FULLFSYNC)\n    fcntl(fileno(file), F_FULLFSYNC, 0);\n    #else\n    fsync(fileno(file));\n    #endif\n#endif\n}\n\nbool TruncateFile(FILE *file, unsigned int length) {\n#if defined(WIN32)\n    return _chsize(_fileno(file), length) == 0;\n#else\n    return ftruncate(fileno(file), length) == 0;\n#endif\n}\n\n/**\n * this function tries to raise the file descriptor limit to the requested number.\n * It returns the actual file descriptor limit (which may be more or less than nMinFD)\n */\nint RaiseFileDescriptorLimit(int nMinFD) {\n#if defined(WIN32)\n    return 2048;\n#else\n    struct rlimit limitFD;\n    if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {\n        if (limitFD.rlim_cur < (rlim_t)nMinFD) {\n            limitFD.rlim_cur = nMinFD;\n            if (limitFD.rlim_cur > limitFD.rlim_max)\n                limitFD.rlim_cur = limitFD.rlim_max;\n            setrlimit(RLIMIT_NOFILE, &limitFD);\n            getrlimit(RLIMIT_NOFILE, &limitFD);\n        }\n        return limitFD.rlim_cur;\n    }\n    return nMinFD; // getrlimit failed, assume it's fine\n#endif\n}\n\n/**\n * this function tries to make a particular range of a file allocated (corresponding to disk space)\n * it is advisory, and the range specified in the arguments will never contain live data\n */\nvoid AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {\n#if defined(WIN32)\n    // Windows-specific version\n    HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));\n    LARGE_INTEGER nFileSize;\n    int64_t nEndPos = (int64_t)offset + length;\n    nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;\n    nFileSize.u.HighPart = nEndPos >> 32;\n    SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);\n    SetEndOfFile(hFile);\n#elif defined(MAC_OSX)\n    // OSX specific version\n    fstore_t fst;\n    fst.fst_flags = F_ALLOCATECONTIG;\n    fst.fst_posmode = F_PEOFPOSMODE;\n    fst.fst_offset = 0;\n    fst.fst_length = (off_t)offset + length;\n    fst.fst_bytesalloc = 0;\n    if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {\n        fst.fst_flags = F_ALLOCATEALL;\n        fcntl(fileno(file), F_PREALLOCATE, &fst);\n    }\n    ftruncate(fileno(file), fst.fst_length);\n#elif defined(__linux__)\n    // Version using posix_fallocate\n    off_t nEndPos = (off_t)offset + length;\n    posix_fallocate(fileno(file), 0, nEndPos);\n#else\n    // Fallback version\n    // TODO: just write one byte per block\n    static const char buf[65536] = {};\n    fseek(file, offset, SEEK_SET);\n    while (length > 0) {\n        unsigned int now = 65536;\n        if (length < now)\n            now = length;\n        fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway\n        length -= now;\n    }\n#endif\n}\n\nvoid ShrinkDebugFile()\n{\n    // Amount of debug.log to save at end when shrinking (must fit in memory)\n    constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;\n    // Scroll debug.log if it's getting too big\n    fs::path pathLog = GetDataDir() / \"debug.log\";\n    FILE* file = fsbridge::fopen(pathLog, \"r\");\n    // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE\n    // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes\n    if (file && fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))\n    {\n        // Restart the file with some of the end\n        std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);\n        fseek(file, -((long)vch.size()), SEEK_END);\n        int nBytes = fread(vch.data(), 1, vch.size(), file);\n        fclose(file);\n\n        file = fsbridge::fopen(pathLog, \"w\");\n        if (file)\n        {\n            fwrite(vch.data(), 1, nBytes, file);\n            fclose(file);\n        }\n    }\n    else if (file != NULL)\n        fclose(file);\n}\n\n#ifdef WIN32\nfs::path GetSpecialFolderPath(int nFolder, bool fCreate)\n{\n    char pszPath[MAX_PATH] = \"\";\n\n    if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))\n    {\n        return fs::path(pszPath);\n    }\n\n    LogPrintf(\"SHGetSpecialFolderPathA() failed, could not obtain requested path.\\n\");\n    return fs::path(\"\");\n}\n#endif\n\nvoid runCommand(const std::string& strCommand)\n{\n#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE!=0 // it's defined, but as 0 on macOS\n        LogPrintf(\"runCommand not supported on iOS!\\n\");\n#else\n    int nErr = ::system(strCommand.c_str());\n    if (nErr)\n        LogPrintf(\"runCommand error: system(%s) returned %d\\n\", strCommand, nErr);\n#endif\n}\n\n// Application startup time (used for uptime calculation)\nconst int64_t nStartupTime = GetTime();\n\n// Obtain the application startup time (used for uptime calculation)\nint64_t GetStartupTime()\n{\n    return nStartupTime;\n}\n\nvoid SetupEnvironment()\n{\n#ifdef HAVE_MALLOPT_ARENA_MAX\n    // glibc-specific: On 32-bit systems set the number of arenas to 1.\n    // By default, since glibc 2.10, the C library will create up to two heap\n    // arenas per core. This is known to cause excessive virtual address space\n    // usage in our usage. Work around it by setting the maximum number of\n    // arenas to 1.\n    if (sizeof(void*) == 4) {\n        mallopt(M_ARENA_MAX, 1);\n    }\n#endif\n    // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale\n    // may be invalid, in which case the \"C\" locale is used as fallback.\n#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)\n    try {\n        std::locale(\"\"); // Raises a runtime error if current locale is invalid\n    } catch (const std::runtime_error&) {\n        setenv(\"LC_ALL\", \"C\", 1);\n    }\n#endif\n    // The path locale is lazy initialized and to avoid deinitialization errors\n    // in multithreading environments, it is set explicitly by the main thread.\n    // A dummy locale is used to extract the internal default locale, used by\n    // fs::path, which is then used to explicitly imbue the path.\n    std::locale loc = fs::path::imbue(std::locale::classic());\n    fs::path::imbue(loc);\n}\n\nbool SetupNetworking()\n{\n#ifdef WIN32\n    // Initialize Windows Sockets\n    WSADATA wsadata;\n    int ret = WSAStartup(MAKEWORD(2,2), &wsadata);\n    if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)\n        return false;\n#endif\n    return true;\n}\n\nint GetNumCores()\n{\n#if BOOST_VERSION >= 105600\n    return boost::thread::physical_concurrency();\n#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores\n    return boost::thread::hardware_concurrency();\n#endif\n}\n\n// Base-10 variation on Fletcher's checksum algorithm to create a position dependent checksum\nint Base10ChecksumEncode(int data)\n{\n    int number = data;\n\n    int sum1 = 0;\n    int sum2 = 0;\n    while (data>0)\n    {\n        int v = data % 10;\n        sum1 = (sum1 + v) % 10;\n        sum2 = (sum2 + sum1) % 10;\n        data = data / 10;\n    }\n\n    int f0 = sum1;\n    int f1 = sum2;\n    int c0 = 10 - (( f0 + f1) % 10);\n    int c1 = 10 - (( f0 + c0 ) % 10);\n\n    // here we have c0/c1 in [1..10], map onto [0..9] to fit into single digit\n    c0 = c0 - 1;\n    c1 = c1 - 1;\n\n    return 100 * number + 10 * c1 + c0;\n}\n\nbool Base10ChecksumDecode(int number, int* decoded)\n{\n    int c0 = number % 10;\n    int c1 = (number / 10) % 10;\n\n    // remap c0/1 from [0..9] onto their original [1..10] range\n    c0 += 1;\n    c1 += 1;\n\n    int data = number / 100;\n\n    int sum1 = 0;\n    int sum2 = 0;\n    while (data>0)\n    {\n        int v = data % 10;\n        sum1 = (sum1 + v) % 10;\n        sum2 = (sum2 + sum1) % 10;\n        data = data / 10;\n    }\n\n    sum1 = (sum1 + c0) % 10;\n    sum2 = (sum2 + sum1) % 10;\n\n    sum1 = (sum1 + c1) % 10;\n    sum2 = (sum2 + sum1) % 10;\n\n    bool succes = sum1 == 0 && sum2 == 0;\n\n    if (succes && decoded)\n        *decoded = number / 100;\n\n    return succes;\n}\n"
  },
  {
    "path": "src/util.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n/**\n * Server/client environment: argument handling, config file parsing,\n * logging, thread wrappers\n */\n#ifndef CORE_UTIL_H\n#define CORE_UTIL_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"appname.h\"\n#include \"compat.h\"\n#include \"fs.h\"\n#include \"sync.h\"\n#include \"tinyformat.h\"\n#include \"util/time.h\"\n#include \"logging.h\"\n\n#include <atomic>\n#include <exception>\n#include <map>\n#include <stdint.h>\n#include <string>\n#include <vector>\n\n#include <boost/signals2/signal.hpp>\n\n// Standardise on (unused) indicator to silence unused warnings in cases where it makes sense.\ntypedef void unused;\n\nstatic const bool DEFAULT_LOGTIMEMICROS = false;\nstatic const bool DEFAULT_LOGIPS        = false;\nstatic const bool DEFAULT_LOGTIMESTAMPS = true;\n\n/** Signals for translation. */\nclass CTranslationInterface\n{\npublic:\n    /** Translate a message to the native language of the user. */\n    boost::signals2::signal<std::string (const char* psz)> Translate;\n};\n\nextern bool fPrintToConsole;\nextern bool fPrintToDebugLog;\nextern bool fNoUI;\nextern bool fLogTimestamps;\nextern bool fLogTimeMicros;\nextern bool fLogIPs;\nextern bool gbMinimalLogging;\nextern std::atomic<bool> fReopenDebugLog;\nextern CTranslationInterface translationInterface;\n\nextern const char * const DEFAULT_CONF_FILENAME;\nextern const char * const DEFAULT_PID_FILENAME;\n\n/**\n * Translation function: Call Translate signal on UI interface, which returns a boost::optional result.\n * If no translation slot is registered, nothing is returned, and simply return the input.\n */\ninline std::string _(const char* psz)\n{\n    boost::optional<std::string> rv = translationInterface.Translate(psz);\n    return rv ? (*rv) : psz;\n}\n\n// Application startup time (used for uptime calculation)\nint64_t GetStartupTime();\n\nvoid SetupEnvironment();\nbool SetupNetworking();\n\nvoid FileCommit(FILE *file);\nbool TruncateFile(FILE *file, unsigned int length);\nint RaiseFileDescriptorLimit(int nMinFD);\nvoid AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);\nbool RenameOver(fs::path src, fs::path dest);\nbool TryCreateDirectory(const fs::path& p);\nextern std::string defaultDataDirOverride;\nfs::path GetDefaultDataDir();\nconst fs::path &GetDataDir(bool fNetSpecific = true);\nvoid ClearDatadirCache();\nfs::path GetConfigFile(const std::string& confPath);\n#ifndef WIN32\nfs::path GetPidFile();\nvoid CreatePidFile(const fs::path &path, pid_t pid);\n#endif\n#ifdef WIN32\nfs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);\n#endif\nvoid OpenDebugLog();\nvoid ShrinkDebugFile();\nvoid runCommand(const std::string& strCommand);\n\n// Base-10 variation on Fletcher's checksum algorithm to create a position dependent checksum\nint Base10ChecksumEncode(int data);\nbool Base10ChecksumDecode(int number, int* decoded=nullptr);\n\ninline bool IsSwitchChar(char c)\n{\n#ifdef WIN32\n    return c == '-' || c == '/';\n#else\n    return c == '-';\n#endif\n}\n\nclass ArgsManager\n{\nprotected:\n    RecursiveMutex cs_args;\n    std::map<std::string, std::string> mapArgs;\n    std::map<std::string, std::vector<std::string> > mapMultiArgs;\npublic:\n    void ParseParameters(int argc, const char*const argv[]);\n    /** Parse additional parameters, overwriting but not clearing previous paramers */\n    void ParseExtraParameters(int argc, const char*const argv[]);\n    void ReadConfigFile(const std::string& confPath);\n    std::vector<std::string> GetArgs(const std::string& strArg);\n/**\n * Return true if the given argument has been manually set\n *\n * @param strArg Argument to get (e.g. \"-foo\")\n * @return true if the argument has been set\n */\nbool IsArgSet(const std::string& strArg);\n\n/**\n * Return string argument or default value\n *\n * @param strArg Argument to get (e.g. \"-foo\")\n * @param default (e.g. \"1\")\n * @return command-line argument or default value\n */\nstd::string GetArg(const std::string& strArg, const std::string& strDefault);\n\n/**\n * Return integer argument or default value\n *\n * @param strArg Argument to get (e.g. \"-foo\")\n * @param default (e.g. 1)\n * @return command-line argument (0 if invalid number) or default value\n */\nint64_t GetArg(const std::string& strArg, int64_t nDefault);\n\n/**\n * Return boolean argument or default value\n *\n * @param strArg Argument to get (e.g. \"-foo\")\n * @param default (true or false)\n * @return command-line argument or default value\n */\nbool GetBoolArg(const std::string& strArg, bool fDefault);\n\n/**\n * Set an argument if it doesn't already have a value\n *\n * @param strArg Argument to set (e.g. \"-foo\")\n * @param strValue Value (e.g. \"1\")\n * @return true if argument gets set, false if it already had a value\n */\nbool SoftSetArg(const std::string& strArg, const std::string& strValue);\n\n/**\n * Set a boolean argument if it doesn't already have a value\n *\n * @param strArg Argument to set (e.g. \"-foo\")\n * @param fValue Value (e.g. false)\n * @return true if argument gets set, false if it already had a value\n */\nbool SoftSetBoolArg(const std::string& strArg, bool fValue);\n\n// Forces an arg setting. Called by SoftSetArg() if the arg hasn't already\n// been set. Also called directly in testing.\nvoid ForceSetArg(const std::string& strArg, const std::string& strValue);\n};\n\nextern ArgsManager gArgs;\n\n// wrappers using the global ArgsManager:\nstatic inline void ParseParameters(int argc, const char*const argv[])\n{\n    gArgs.ParseParameters(argc, argv);\n}\n\nstatic inline void ReadConfigFile(const std::string& confPath)\n{\n    gArgs.ReadConfigFile(confPath);\n}\n\nstatic inline bool SoftSetArg(const std::string& strArg, const std::string& strValue)\n{\n    return gArgs.SoftSetArg(strArg, strValue);\n}\n\nstatic inline void ForceSetArg(const std::string& strArg, const std::string& strValue)\n{\n    gArgs.ForceSetArg(strArg, strValue);\n}\n\nstatic inline bool IsArgSet(const std::string& strArg)\n{\n    return gArgs.IsArgSet(strArg);\n}\n\nstatic inline std::string GetArg(const std::string& strArg, const std::string& strDefault)\n{\n    return gArgs.GetArg(strArg, strDefault);\n}\n\nstatic inline int64_t GetArg(const std::string& strArg, int64_t nDefault)\n{\n    return gArgs.GetArg(strArg, nDefault);\n}\n\nstatic inline bool GetBoolArg(const std::string& strArg, bool fDefault)\n{\n    return gArgs.GetBoolArg(strArg, fDefault);\n}\n\nstatic inline bool SoftSetBoolArg(const std::string& strArg, bool fValue)\n{\n    return gArgs.SoftSetBoolArg(strArg, fValue);\n}\n\n/**\n * Format a string to be used as group of options in help messages\n *\n * @param message Group name (e.g. \"RPC server options:\")\n * @return the formatted string\n */\nstd::string HelpMessageGroup(const std::string& message);\n\n/**\n * Format a string to be used as option description in help messages\n *\n * @param option Option message (e.g. \"-rpcuser=<user>\")\n * @param message Option description (e.g. \"Username for JSON-RPC connections\")\n * @return the formatted string\n */\nstd::string HelpMessageOpt(const std::string& option, const std::string& message);\n\ninline uint32_t ByteReverse(uint32_t value)\n{\n    value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);\n    return (value<<16) | (value>>16);\n}\n\n/**\n * Format a hash number and string to be displayed to a user in the most compact/understandable form.\n */\ninline static void selectLargesHashUnit(double& dHashes, std::string& sLabel)\n{\n    if (dHashes > 1000)\n    {\n        //NB! k=1000 K=1024 (however all other prefix are uppercase)\n        sLabel = \"kh\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000 || dHashes == 0)\n    {\n        sLabel = \"Mh\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Gh\";\n        dHashes /= 1000.0;        \n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Th\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Ph\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Eh\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Zh\";\n        dHashes /= 1000.0;\n    }\n    if (dHashes > 1000)\n    {\n        sLabel = \"Yh\";\n        dHashes /= 1000.0;\n    }\n}\n/**\n * Return the number of physical cores available on the current system.\n * @note This does not count virtual cores, such as those provided by HyperThreading\n * when boost is newer than 1.56.\n */\nint GetNumCores();\n\n//fixme: (FUT) (C++-20) We should be able to take the string desc as a constant compile time paramater as well.\n// Little helper class to RAII encapusulate benchmarks at minimal runtime overhead.\ntemplate <uint32_t logCategory=BCLog::BENCH> class BenchMarkHelper\n{\npublic:\n    BenchMarkHelper(const char* strDesc_, uint64_t& nTotal_, uint64_t& nCounter_, const uint32_t nLogThreshold_=1)\n    : strDesc(strDesc_)\n    , nTotal(nTotal_)\n    , nCounter(nCounter_)\n    , nLogThreshold(nLogThreshold_)\n    {\n        nStart = GetTimeMicros();\n        ++nCounter_;\n    }\n    ~BenchMarkHelper()\n    {\n        Split();\n    }\n    void Split()\n    {\n        uint64_t nTime1 = GetTimeMicros(); \n        nTotal += nTime1 - nStart;\n        if (++nCounter % 100 == 0)\n        {\n            if (nTotal * 0.000001 > nLogThreshold)\n            {\n                //fixme: (FUT) (C++-20) We should be able to concat the strDesc at compile time as well.\n                LogPrint(logCategory, \"%s: %.2fms [%.2fs]\\n\", strDesc, 0.001 * (nTime1 - nStart), nTotal * 0.000001);\n            }\n        }\n    }\nprivate:\n    const char* strDesc;\n    uint64_t& nTotal;\n    uint64_t& nCounter;\n    uint32_t nLogThreshold;\n    uint64_t nStart;\n};\n\n/** Run a benchmark - only logs once every 100 calls, and only once overall time passes THRESHOLD (default 1) */\n#define DO_BENCHMARK(DESC, LOGCATEGORY) static uint64_t nTotalBenchMarkTime = 0; static uint64_t nBenchmarkCounter = 0; BenchMarkHelper<LOGCATEGORY>(DESC, nTotalBenchMarkTime, nBenchmarkCounter);\n#define DO_BENCHMARKT(DESC, LOGCATEGORY, THRESHOLD) static uint64_t nTotalBenchMarkTime = 0; static uint64_t nBenchmarkCounter = 0; BenchMarkHelper<LOGCATEGORY>(DESC, nTotalBenchMarkTime, nBenchmarkCounter, THRESHOLD);\n\n\n// Optimised branch prediction\n#if defined(__GNUC__) || defined(__clang__)\n#define LIKELY(x)   __builtin_expect((x),(true))\n#define UNLIKELY(x) __builtin_expect((x),(false))\n#else\n#define LIKELY(x) (x)\n#define UNLIKELY(x) (x)\n#endif\n\n#endif // CORE_UTIL_H\n"
  },
  {
    "path": "src/validation/validation.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n\n#include \"alert.h\"\n#include \"appname.h\"\n#include \"arith_uint256.h\"\n#include \"blockstore.h\"\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"checkpoints.h\"\n#include \"checkqueue.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/merkle.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"fs.h\"\n#include \"hash.h\"\n#include \"unity/appmanager.h\"\n#include \"init.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"pow/pow.h\"\n#include <pow/diff.h>\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"random.h\"\n#include \"script/script.h\"\n#include \"script/sigcache.h\"\n#include \"script/sign.h\"\n#include \"script/standard.h\"\n#include \"timedata.h\"\n#include \"tinyformat.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"ui_interface.h\"\n#include \"undo.h\"\n#include \"util.h\"\n#include \"util/thread.h\"\n#include \"witnessutil.h\"\n#include \"util/moneystr.h\"\n#include \"util/strencodings.h\"\n#include \"validation/validationinterface.h\"\n#include \"validation/versionbitsvalidation.h\"\n#include \"versionbits.h\"\n#include \"warnings.h\"\n#include \"blockfilter.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n\n#include <atomic>\n#include <sstream>\n\n#include <boost/foreach.hpp>\n#include <boost/algorithm/string/replace.hpp>\n#include <boost/algorithm/string/join.hpp>\n#include <boost/thread.hpp>\n\n#if defined(NDEBUG)\n# error \"Cannot be compiled without assertions.\"\n#endif\n\n#define DEBUG_PARTIAL_SYNC\n\n#include <boost/bind/bind.hpp>\nusing namespace boost::placeholders;\n\n/**\n * Global state\n */\n\nRecursiveMutex cs_main;\n\nbool fSPV = false;\nint ChainHeight()\n{\n    LOCK(cs_main);\n    return fSPV ? partialChain.Height() : chainActive.Height();\n}\n\nCBlockIndex* chainTip()\n{\n    return fSPV ? partialChain.Tip() : chainActive.Tip();\n}\n\nCBlockIndex* chainPrevTip()\n{\n    return fSPV ? partialChain.TipPrev() : chainActive.TipPrev();\n}\n\nBlockMap mapBlockIndex;\nCChain chainActive;\nCBlockIndex *pindexBestHeader = NULL;\nCPartialChain partialChain;\nCBlockIndex *pindexBestPartial = nullptr;\nMutex csBestBlock;\nstd::condition_variable cvBlockChange;\nint nScriptCheckThreads = 0;\nstd::atomic_bool fImporting(false);\nbool fReindex = false;\nbool fReverseHeaders = false;\nbool fTxIndex = false;\nbool fHavePruned = false;\nbool fPruneMode = false;\nbool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;\nbool fRequireStandard = true;\nbool fCheckBlockIndex = false;\nbool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;\nsize_t nCoinCacheUsage = 5000 * 300;\nuint64_t nPruneTarget = 0;\nint nPartialPruneHeightDone = 0;\nbool fAlerts = DEFAULT_ALERTS;\nint64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;\nbool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;\n\nuint256 hashAssumeValid;\n\nCFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);\nCAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;\n\nCBlockPolicyEstimator feeEstimator;\nCTxMemPool mempool(&feeEstimator);\n\nstatic void CheckBlockIndex(const Consensus::Params& consensusParams);\n\n/** Constant stuff for coinbase transactions we create: */\nCScript COINBASE_FLAGS;\n\nconst std::string strMessageMagic = \"Munt Signed Message:\\n\";\n\nstd::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;\n\n// Internal stuff\nnamespace {\n    CBlockIndex *pindexBestInvalid;\n\n    /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.\n     * Pruned nodes may have entries where B is missing data.\n     */\n    std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;\n\n    RecursiveMutex cs_LastBlockFile;\n    std::vector<CBlockFileInfo> vinfoBlockFile;\n    int nLastBlockFile = 0;\n    /** Global flag to indicate we should check to see if there are\n     *  block/undo files that should be deleted.  Set on startup\n     *  or if we allocate more file space when we're in prune mode\n     */\n    bool fCheckForPruning = false;\n    std::atomic<int> nMaxSPVPruneHeight = 0;\n    /**\n     * Every received block is assigned a unique and increasing identifier, so we\n     * know which one to give priority in case of a fork.\n     */\n    RecursiveMutex cs_nBlockSequenceId;\n    /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */\n    int32_t nBlockSequenceId = 1;\n    /** Decreasing counter (used by subsequent preciousblock calls). */\n    int32_t nBlockReverseSequenceId = -1;\n    /** chainwork for the last block that preciousblock has been applied to. */\n    arith_uint256 nLastPreciousChainwork = 0;\n\n    /** Dirty block index entries. */\n    std::set<CBlockIndex*> setDirtyBlockIndex;\n\n    /** Dirty block file entries. */\n    std::set<int> setDirtyFileInfo;\n\n    std::atomic<bool> fFullSyncMode(DEFAULT_FULL_SYNC_MODE);\n\n    boost::signals2::signal<void (const CBlockIndex *pTip)> headerTipSignal;\n} // anon namespace\n\nCBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)\n{\n    // Find the first block the caller has in the main chain\n    for(const uint256& hash : locator.vHave) {\n        BlockMap::iterator mi = mapBlockIndex.find(hash);\n        if (mi != mapBlockIndex.end())\n        {\n            CBlockIndex* pindex = (*mi).second;\n            if (chain.Contains(pindex))\n                return pindex;\n            if (pindex->GetAncestor(chain.Height()) == chain.Tip()) {\n                return chain.Tip();\n            }\n        }\n    }\n    return chain.Genesis();\n}\n\nCCoinsViewDB *pcoinsdbview = NULL;\nCCoinsViewCache *pcoinsTip = NULL;\nCBlockTreeDB *pblocktree = NULL;\n\nbool CheckFinalTx(const CTransaction &tx, const CChain& chain, int flags)\n{\n    AssertLockHeld(cs_main);\n\n    // By convention a negative value for flags indicates that the\n    // current network-enforced consensus rules should be used. In\n    // a future soft-fork scenario that would mean checking which\n    // rules would be enforced for the next block and setting the\n    // appropriate flags. At the present time no soft-forks are\n    // scheduled, so no flags are set.\n    flags = std::max(flags, 0);\n\n    // CheckFinalTx() uses chainActive.Height()+1 to evaluate\n    // nLockTime because when IsFinalTx() is called within\n    // CBlock::AcceptBlock(), the height of the block *being*\n    // evaluated is what is used. Thus if we want to know if a\n    // transaction can be part of the *next* block, we need to call\n    // IsFinalTx() with one more than chainActive.Height().\n    const int nBlockHeight = chain.Height() + 1;\n\n    // BIP113 will require that time-locked transactions have nLockTime set to\n    // less than the median time of the previous block they're contained in.\n    // When the next block is created its previous block will be the current\n    // chain tip, so we use that to calculate the median time passed to\n    // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.\n    const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST)\n                             ? chain.Tip()->GetMedianTimePast()\n                             : GetAdjustedTime();\n\n    return IsFinalTx(tx, nBlockHeight, nBlockTime);\n}\n\nbool TestLockPointValidity(const LockPoints* lp)\n{\n    AssertLockHeld(cs_main);\n    assert(lp);\n    // If there are relative lock times then the maxInputBlock will be set\n    // If there are no relative lock times, the LockPoints don't depend on the chain\n    if (lp->maxInputBlock) {\n        // Check whether chainActive is an extension of the block at which the LockPoints\n        // calculation was valid.  If not LockPoints are no longer valid\n        if (!chainActive.Contains(lp->maxInputBlock)) {\n            return false;\n        }\n    }\n\n    // LockPoints still valid\n    return true;\n}\n\nbool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints)\n{\n    AssertLockHeld(cs_main);\n    AssertLockHeld(mempool.cs);\n\n    CBlockIndex* tip = chainActive.Tip();\n    CBlockIndex index;\n    index.pprev = tip;\n    // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate\n    // height based locks because when SequenceLocks() is called within\n    // ConnectBlock(), the height of the block *being*\n    // evaluated is what is used.\n    // Thus if we want to know if a transaction can be part of the\n    // *next* block, we need to use one more than chainActive.Height()\n    index.nHeight = tip->nHeight + 1;\n\n    std::pair<int, int64_t> lockPair;\n    if (useExistingLockPoints)\n    {\n        assert(lp);\n        lockPair.first = lp->height;\n        lockPair.second = lp->time;\n    }\n    else\n    {\n        // pcoinsTip contains the UTXO set for chainActive.Tip()\n        CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);\n        std::vector<int> prevheights;\n        prevheights.resize(tx.vin.size());\n        for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++)\n        {\n            const CTxIn& txin = tx.vin[txinIndex];\n            Coin coin;\n            if (!viewMemPool.GetCoin(txin.GetPrevOut(), coin))\n            {\n                return error(\"%s: Missing input\", __func__);\n            }\n            if (coin.nHeight == MEMPOOL_HEIGHT)\n            {\n                // Assume all mempool transaction confirm in the next block\n                prevheights[txinIndex] = tip->nHeight + 1;\n            }\n            else\n            {\n                prevheights[txinIndex] = coin.nHeight;\n            }\n        }\n        lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);\n        if (lp)\n        {\n            lp->height = lockPair.first;\n            lp->time = lockPair.second;\n            // Also store the hash of the block with the highest height of\n            // all the blocks which have sequence locked prevouts.\n            // This hash needs to still be on the chain\n            // for these LockPoint calculations to be valid\n            // Note: It is impossible to correctly calculate a maxInputBlock\n            // if any of the sequence locked inputs depend on unconfirmed txs,\n            // except in the special case where the relative lock time/height\n            // is 0, which is equivalent to no sequence lock. Since we assume\n            // input height of tip+1 for mempool txs and test the resulting\n            // lockPair from CalculateSequenceLocks against tip+1.  We know\n            // EvaluateSequenceLocks will fail if there was a non-zero sequence\n            // lock on a mempool input, so we can use the return value of\n            // CheckSequenceLocks to indicate the LockPoints validity\n            int maxInputHeight = 0;\n            for(int height : prevheights)\n            {\n                // Can ignore mempool inputs since we'll fail if they had non-zero locks\n                if (height != tip->nHeight+1)\n                {\n                    maxInputHeight = std::max(maxInputHeight, height);\n                }\n            }\n            lp->maxInputBlock = tip->GetAncestor(maxInputHeight);\n        }\n    }\n    return EvaluateSequenceLocks(index, lockPair);\n}\n\n\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// CBlock and CBlockIndex\n//\n\nbool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const CChainParams& params)\n{\n    return blockStore.ReadBlockFromDisk(block, pindex->GetBlockPos(), params, pindex);\n}\n\n\nCBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;\n\n\nstatic void CheckForkWarningConditions()\n{\n    AssertLockHeld(cs_main);\n    // Before we get past initial download, we cannot reliably alert about forks\n    // (we assume we don't get stuck on a fork before finishing our initial sync)\n    if (IsInitialBlockDownload())\n        return;\n\n    // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)\n    // of our head, drop it\n    if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)\n        pindexBestForkTip = NULL;\n\n    if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6)))\n    {\n        if (!GetfLargeWorkForkFound() && pindexBestForkBase)\n        {\n            std::string warning = std::string(\"'Warning: Large-work fork detected, forking after block \") +\n                pindexBestForkBase->phashBlock->ToString() + std::string(\"'\");\n            CAlert::Notify(warning, true);\n        }\n        if (pindexBestForkTip && pindexBestForkBase)\n        {\n            LogPrintf(\"%s: Warning: Large valid fork found\\n  forking the chain at height %d (%s)\\n  lasting to height %d (%s).\\nChain state database corruption likely.\\n\", __func__,\n                   pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(),\n                   pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString());\n            SetfLargeWorkForkFound(true);\n        }\n        else\n        {\n            LogPrintf(\"%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\\nChain state database corruption likely.\\n\", __func__);\n            SetfLargeWorkInvalidChainFound(true);\n        }\n    }\n    else\n    {\n        SetfLargeWorkForkFound(false);\n        SetfLargeWorkInvalidChainFound(false);\n    }\n}\n\nstatic void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)\n{\n    AssertLockHeld(cs_main);\n    // If we are on a fork that is sufficiently large, set a warning flag\n    CBlockIndex* pfork = pindexNewForkTip;\n    CBlockIndex* plonger = chainActive.Tip();\n    while (pfork && pfork != plonger)\n    {\n        while (plonger && plonger->nHeight > pfork->nHeight)\n            plonger = plonger->pprev;\n        if (pfork == plonger)\n            break;\n        pfork = pfork->pprev;\n    }\n\n    // We define a condition where we should warn the user about as a fork of at least 7 blocks\n    // with a tip within 72 blocks (+/- 12 hours if no one mines it) of ours\n    // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network\n    // hash rate operating on the fork.\n    // or a chain that is entirely longer than ours and invalid (note that this should be detected by both)\n    // We define it this way because it allows us to only store the highest fork tip (+ base) which meets\n    // the 7-block condition and from this always have the most-likely-to-cause-warning fork\n    if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&\n            pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&\n            chainActive.Height() - pindexNewForkTip->nHeight < 72)\n    {\n        pindexBestForkTip = pindexNewForkTip;\n        pindexBestForkBase = pfork;\n    }\n\n    CheckForkWarningConditions();\n}\n\nvoid static InvalidChainFound(CBlockIndex* pindexNew)\n{\n    if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)\n        pindexBestInvalid = pindexNew;\n\n    LogPrintf(\"%s: invalid block=%s  height=%d  log2_work=%.8g  date=%s\\n\", __func__,\n      pindexNew->GetBlockHashPoW2().ToString(), pindexNew->nHeight,\n      log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));\n    CBlockIndex *tip = chainActive.Tip();\n    assert (tip);\n    LogPrintf(\"%s:  current best=%s  height=%d  log2_work=%.8g  date=%s\\n\", __func__,\n      tip->GetBlockHashPoW2().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0),\n      FormatISO8601DateTime(tip->GetBlockTime()));\n    CheckForkWarningConditions();\n}\n\nvoid static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {\n    if (!state.CorruptionPossible()) {\n        LOCK(cs_main);\n        pindex->nStatus |= BLOCK_FAILED_VALID;\n        setDirtyBlockIndex.insert(pindex);\n        setBlockIndexCandidates.erase(pindex);\n        InvalidChainFound(pindex);\n    }\n}\n\nvoid UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, uint32_t nHeight, uint32_t nTxIndex)\n{\n    // mark inputs spent\n    if (!tx.IsCoinBase() || tx.IsPoW2WitnessCoinBase()) {\n        //fixme: (FUT) (MED) See if we can bring back the reserve efficiency here.\n        //txundo.vprevout.reserve(tx.vin.size());\n        for(const CTxIn &txin : tx.vin) {\n            if (!txin.GetPrevOut().IsNull())\n            {\n                txundo.vprevout.emplace_back();\n                inputs.SpendCoin(txin.GetPrevOut(), &txundo.vprevout.back());\n            }\n        }\n    }\n    // add outputs\n    AddCoins(inputs, tx, nHeight, nTxIndex);\n}\n\nvoid UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, uint32_t nHeight, uint32_t nTxIndex)\n{\n    CTxUndo txundo;\n    UpdateCoins(tx, inputs, txundo, nHeight, nTxIndex);\n}\n\nbool CScriptCheck::operator()() {\n    const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;\n    const CSegregatedSignatureData *witness = &ptxTo->vin[nIn].segregatedSignatureData;\n    return VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(signingKeyID, ptxTo, nIn, amount, cacheStore, *txdata), scriptVer, &error);\n}\n\nint GetSpendHeight(const CCoinsViewCache& inputs)\n{\n    LOCK(cs_main);\n    CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;\n    return pindexPrev->nHeight + 1;\n}\n\n//fixme: (PHASE5) This should rather use move semantics, but CScript doesn't currently seem compatible with this.\nCScript GetScriptForNonScriptOutput(const CTxOut& out)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        std::vector<unsigned char> sWitnessPlaceholder = {'p','o','w','2','w','i','t','n','e','s','s'};\n        return CScript(sWitnessPlaceholder.begin(), sWitnessPlaceholder.end());\n    }\n    else if (out.GetType() == CTxOutType::StandardKeyHashOutput)\n    {\n        std::vector<unsigned char> sWitnessPlaceholder = {'k','e','y','h','a','s','h'};\n        return CScript(sWitnessPlaceholder.begin(), sWitnessPlaceholder.end());\n    }\n    return CScript();\n}\n\n\n/**\n * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)\n * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it\n * instead of being performed inline.\n */\nbool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const std::vector<CWitnessTxBundle>* pWitnessBundles, std::vector<CScriptCheck> *pvChecks)\n{\n    if (!tx.IsCoinBase() || tx.IsPoW2WitnessCoinBase())\n    {\n        if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), pWitnessBundles))\n            return false;\n\n        if (pvChecks)\n            pvChecks->reserve(tx.vin.size());\n\n        // The first loop above does all the inexpensive checks.\n        // Only if ALL inputs pass do we perform expensive ECDSA signature checks.\n        // Helps prevent CPU exhaustion attacks.\n\n        // Skip script verification when connecting blocks under the\n        // assumevalid block. Assuming the assumevalid block is valid this\n        // is safe because block merkle hashes are still computed and checked,\n        // Of course, if an assumed valid block is invalid due to false scriptSigs\n        // this optimization would allow an invalid chain to be accepted.\n        if (fScriptChecks)\n        {\n            for (unsigned int i = 0; i < tx.vin.size(); i++)\n            {\n                const COutPoint &prevout = tx.vin[i].GetPrevOut();\n                if (prevout.IsNull() && tx.IsPoW2WitnessCoinBase())\n                    continue;\n                const Coin& coin = inputs.AccessCoin(prevout);\n                assert(!coin.IsSpent());\n\n                // We very carefully only pass in things to CScriptCheck which\n                // are clearly committed to by tx' witness hash. This provides\n                // a sanity check that our caching is not introducing consensus\n                // failures through additional data in, eg, the coins being\n                // spent being checked as a part of CScriptCheck.\n                const CAmount amount = coin.out.nValue;\n\n                CKeyID witnessSigningKeyID = ExtractSigningPubkeyFromTxOutput(coin.out, SignType::Witness);\n                if (coin.out.GetType() > CTxOutType::ScriptLegacyOutput)\n                {\n                    CKeyID spendSigningKeyID;\n                    if (coin.out.GetType() == CTxOutType::StandardKeyHashOutput || coin.out.GetType() == CTxOutType::PoW2WitnessOutput)\n                    {\n                        if (coin.out.GetType() == CTxOutType::StandardKeyHashOutput)\n                        {\n                            if (tx.vin[i].segregatedSignatureData.stack.size() != 1)\n                            {\n                                return state.DoS(100,false, REJECT_INVALID, strprintf(\"invalid-segregated-signature-stack-size (%d) (standard-key-hash-input should always have a segregatedSignatureData stack size of exactly 1)\", tx.vin[i].segregatedSignatureData.stack.size()));\n                            }\n                        }\n                        else\n                        {\n                            // NB! The checks in tx_verify ensure that we have the right number of signatures (2 or 1) based on the type of witness operation.\n                            // A spend operation with only 1 signature will fail etc.\n                            // So we can safely assume at this point in the code that a spend will always have 2 signatures and can't try trick the system by providing only 1 signature.\n                            // Here we therefore just validate signatures based on number of signatures provided (If there are 2 validate for spending, otherwise for witnessing)\n                            if (tx.vin[i].segregatedSignatureData.stack.size() == 2)\n                            {\n                                spendSigningKeyID = ExtractSigningPubkeyFromTxOutput(coin.out, SignType::Spend);\n                                if (spendSigningKeyID.IsNull())\n                                {\n                                    return state.DoS(100,false, REJECT_INVALID, strprintf(\"invalid-witness-prevout (unable to extract a valid spending key from prevout)\"));\n                                }\n                                if (witnessSigningKeyID.IsNull())\n                                {\n                                    return state.DoS(100,false, REJECT_INVALID, strprintf(\"invalid-witness-prevout (unable to extract a valid witness key from prevout)\"));\n                                }\n                            }\n                            else if (tx.vin[i].segregatedSignatureData.stack.size() == 1)\n                            {\n                                if (witnessSigningKeyID.IsNull())\n                                {\n                                    return state.DoS(100,false, REJECT_INVALID, strprintf(\"invalid-witness-prevout (unable to extract a valid witness key from prevout)\"));\n                                }\n                            }\n                            else\n                            {\n                                return state.DoS(100,false, REJECT_INVALID, strprintf(\"invalid-scriptwitness-segregated-signature-data-size (%d) (witness-input should always have a segregatedSignatureData stack size of either 1 or 2 depending on whether it is a spend or witness operation)\", tx.vin[i].segregatedSignatureData.stack.size()));\n                            }\n                        }\n\n                        CScript scriptCodePlaceHolder = GetScriptForNonScriptOutput(coin.out);\n\n                        //We extract the pubkey from the signatures so just pass in an empty pubkey for the checks.\n                        std::vector<unsigned char> vchEmptyPubKey;\n                        CachingTransactionSignatureChecker check1(witnessSigningKeyID, &tx, i, amount, cacheStore, txdata);\n                        if (!check1.CheckSig(tx.vin[i].segregatedSignatureData.stack[0], vchEmptyPubKey, scriptCodePlaceHolder, SIGVERSION_SEGSIG))\n                        {\n                            return false;\n                        }\n                        // For a witness spend operation we have a second key that also needs checking.\n                        if (!spendSigningKeyID.IsNull())\n                        {\n                            CachingTransactionSignatureChecker check2(spendSigningKeyID, &tx, i, amount, cacheStore, txdata);\n                            if (!check2.CheckSig(tx.vin[i].segregatedSignatureData.stack[1], vchEmptyPubKey, scriptCodePlaceHolder, SIGVERSION_SEGSIG))\n                            {\n                                return false;\n                            }\n                        }\n                    }\n                    else\n                    {\n                        return state.DoS(100,false, REJECT_INVALID, strprintf(\"unknown-transaction-type [%d]\", coin.out.GetType()));\n                    }\n                    return true;\n                }\n\n                // Verify signature\n                ScriptVersion scriptversion = IsOldTransactionVersion(tx.nVersion) ? SCRIPT_V1 : SCRIPT_V2;\n                const CScript& scriptPubKey = coin.out.output.scriptPubKey;\n                CScriptCheck check(witnessSigningKeyID, scriptPubKey, amount, tx, i, flags, cacheStore, &txdata, scriptversion);\n                if (pvChecks)\n                {\n                    pvChecks->push_back(CScriptCheck());\n                    check.swap(pvChecks->back());\n                }\n                else if (!check())\n                {\n                    if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS)\n                    {\n                        // Check whether the failure was caused by a\n                        // non-mandatory script verification check, such as\n                        // non-standard DER encodings or non-null dummy\n                        // arguments; if so, don't trigger DoS protection to\n                        // avoid splitting the network between upgraded and\n                        // non-upgraded nodes.\n                        CScriptCheck check2(witnessSigningKeyID, scriptPubKey, amount, tx, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata, SCRIPT_V1);\n                        if (check2())\n                        {\n                            return state.Invalid(false, REJECT_NONSTANDARD, strprintf(\"non-mandatory-script-verify-flag (%s)\", ScriptErrorString(check.GetScriptError())));\n                        }\n                    }\n                    // Failures of other flags indicate a transaction that is\n                    // invalid in new blocks, e.g. a invalid P2SH. We DoS ban\n                    // such nodes as they are not following the protocol. That\n                    // said during an upgrade careful thought should be taken\n                    // as to the correct behavior - we may want to continue\n                    // peering with non-upgraded nodes even after soft-fork\n                    // super-majority signaling has occurred.\n                    return state.DoS(100,false, REJECT_INVALID, strprintf(\"mandatory-script-verify-flag-failed (%s)\", ScriptErrorString(check.GetScriptError())));\n                }\n            }\n        }\n    }\n\n    return true;\n}\n\nnamespace {\n\n/** Abort with a message */\nbool AbortNode(const std::string& strMessage, const std::string& userMessage=\"\")\n{\n    SetMiscWarning(strMessage);\n    LogPrintf(\"*** %s\\n\", strMessage);\n    uiInterface.ThreadSafeMessageBox(userMessage.empty() ? _(\"Error: A fatal internal error occurred, see debug.log for details\") : userMessage, \"\", CClientUIInterface::MSG_ERROR);\n    LogPrintf(\"shutdown: triggering shutdown from AbortNode\");\n    AppLifecycleManager::gApp->shutdown();\n    return false;\n}\n\nbool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage=\"\")\n{\n    AbortNode(strMessage, userMessage);\n    return state.Error(strMessage);\n}\n\n} // anon namespace\n\n/**\n * Restore the UTXO in a Coin at a given COutPoint\n * @param undo The Coin to be restored.\n * @param view The coins view to which to apply the changes.\n * @param out The out point that corresponds to the tx input.\n * @return A DisconnectResult as an int\n */\nint ApplyTxInUndo(CoinUndo&& undo, CCoinsViewCache& view, COutPoint out)\n{\n    bool fClean = true;\n\n    // We always want to revert to using the hash based outpoint here to keep the coin database consistent\n    if (!out.isHash)\n    {\n        out.setHash(undo.prevhash);\n    }\n\n    if (view.HaveCoin(out))\n    {\n        fClean = false; // overwriting transaction output\n    }\n\n    if (undo.nHeight == 0)\n    {\n        // Missing undo metadata (height and coinbase). Older versions included this\n        // information only in undo records for the last spend of a transactions'\n        // outputs. This implies that it must be present for some other output of the same tx.\n        uint256 txHash;\n        if (!GetTxHash(out, txHash))\n            return DISCONNECT_FAILED; // adding output for transaction without known metadata\n        const Coin& alternate = AccessByTxid(view, txHash);\n        if (!alternate.IsSpent()) \n        {\n            undo.nHeight = alternate.nHeight;\n            undo.fCoinBase = alternate.fCoinBase;\n        }\n        else\n        {\n            return DISCONNECT_FAILED; // adding output for transaction without known metadata\n        }\n    }\n    view.AddCoin(out, std::move(undo), undo.fCoinBase);\n\n    return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;\n}\n\n\nDisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)\n{\n    assert(pindex->GetBlockHashPoW2() == view.GetBestBlock());\n\n    bool fClean = true;\n\n    CBlockUndo blockUndo;\n    CDiskBlockPos pos = pindex->GetUndoPos();\n    if (pos.IsNull()) {\n        error(\"DisconnectBlock(): no undo data available\");\n        return DISCONNECT_FAILED;\n    }\n    if (!blockStore.UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHashPoW2())) {\n        error(\"DisconnectBlock(): failure reading undo data\");\n        return DISCONNECT_FAILED;\n    }\n\n    if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) {\n        error(\"DisconnectBlock(): block and undo data inconsistent\");\n        return DISCONNECT_FAILED;\n    }\n\n    // undo transactions in reverse order\n    for (int i = block.vtx.size() - 1; i >= 0; i--) {\n        const CTransaction &tx = *(block.vtx[i]);\n        uint256 hash = tx.GetHash();\n\n        // Check that all outputs are available and match the outputs in the block itself\n        // exactly.\n        for (size_t o = 0; o < tx.vout.size(); o++) {\n            if (!tx.vout[o].IsUnspendable()) {\n                COutPoint out(hash, o);\n                CoinUndo coin;\n                view.SpendCoin(out, &coin);\n                if (tx.vout[o] != coin.out) {\n                    fClean = false; // transaction output mismatch\n                }\n            }\n        }\n\n        // restore inputs (not coinbases)\n        if (i > 0)\n        {\n            CTxUndo &txundo = blockUndo.vtxundo[i-1];\n            if (tx.IsPoW2WitnessCoinBase())\n            {\n                //NB! 'IsPoW2WitnessCoinBase' already forces vin size to be 2, and the first input NULL, so we don't need to validate the size here\n                if (txundo.vprevout.size() != 1)\n                {\n                    error(\"DisconnectBlock(): transaction and undo data inconsistent\");\n                    return DISCONNECT_FAILED;\n                }\n                for (unsigned int j = tx.vin.size(); j-- > 0;)\n                {\n                    if (!tx.vin[j].GetPrevOut().IsNull())\n                    {\n                        const COutPoint &out = tx.vin[j].GetPrevOut();\n                        int res = ApplyTxInUndo(std::move(txundo.vprevout[0]), view, out);\n                        if (res == DISCONNECT_FAILED)\n                            return DISCONNECT_FAILED;\n                        fClean = fClean && res != DISCONNECT_UNCLEAN;\n                    }\n                }\n            }\n            else\n            {\n                if (txundo.vprevout.size() != tx.vin.size())\n                {\n                    error(\"DisconnectBlock(): transaction and undo data inconsistent\");\n                    return DISCONNECT_FAILED;\n                }\n                for (unsigned int j = tx.vin.size(); j-- > 0;)\n                {\n                    const COutPoint &out = tx.vin[j].GetPrevOut();\n                    int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out);\n                    if (res == DISCONNECT_FAILED)\n                        return DISCONNECT_FAILED;\n                    fClean = fClean && res != DISCONNECT_UNCLEAN;\n                }\n            }\n            // At this point, all of txundo.vprevout should have been moved out.\n        }\n    }\n\n    // move best block pointer to prevout block\n    view.SetBestBlock(pindex->pprev->GetBlockHashPoW2());\n\n    return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;\n}\n\nvoid static FlushBlockFile(bool fFinalize = false)\n{\n    LOCK(cs_LastBlockFile);\n\n    CDiskBlockPos posOld(nLastBlockFile, 0);\n\n    FILE *fileOld = blockStore.GetBlockFile(posOld);\n    if (fileOld) {\n        if (fFinalize)\n            TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);\n        FileCommit(fileOld);\n    }\n\n    fileOld = blockStore.GetUndoFile(posOld);\n    if (fileOld) {\n        if (fFinalize)\n            TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);\n        FileCommit(fileOld);\n    }\n}\n\nstatic bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);\n\nstatic CCheckQueue<CScriptCheck> scriptcheckqueue(128);\n\nvoid StartScriptCheckWorkerThreads(int threads_num)\n{\n    scriptcheckqueue.StartWorkerThreads(threads_num);\n}\n\nvoid StopScriptCheckWorkerThreads()\n{\n    scriptcheckqueue.StopWorkerThreads();\n}\n\n\n/**\n * Threshold condition checker that triggers when unknown versionbits are seen on the network.\n */\nclass WarningBitsConditionChecker : public AbstractThresholdConditionChecker\n{\nprivate:\n    int bit;\n\npublic:\n    WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}\n\n    int64_t BeginTime(const Consensus::Params& params) const { return 0; }\n    int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); }\n    int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }\n    int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }\n\n    bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const\n    {\n        return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&\n               ((pindex->nVersion >> bit) & 1) != 0 &&\n               ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;\n    }\n};\n\n// Protected by cs_main\nstatic ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];\n\nstatic int64_t nTimeCheck = 0;\nstatic int64_t nTimeForks = 0;\nstatic int64_t nTimeVerify = 0;\nstatic int64_t nTimeConnect = 0;\nstatic int64_t nTimeIndex = 0;\nstatic int64_t nTimeCallbacks = 0;\nstatic int64_t nTimeTotal = 0;\n\n/*\nvoid LogWitnessInfo(CGetWitnessInfo witInfo)\n{\n    LogPrintf(\"witinfo>>>\\n\");\n    LogPrintf(\"filtered:\\n\");\n    for (const auto& item : witInfo.witnessSelectionPoolFiltered)\n    {\n        LogPrintf(\"outpoint %d\\n\", item.outpoint.n);\n        LogPrintf(\"coin %d\\n\", item.coin.nHeight);\n        LogPrintf(\"weight %s\\n\", item.nWeight);\n        LogPrintf(\"age %s\\n\", item.nAge);\n        LogPrintf(\"cumulative %s\\n\", item.nCumulativeWeight);\n    }\n    LogPrintf(\"unfiltered:\\n\");\n    for (const auto& item : witInfo.witnessSelectionPoolUnfiltered)\n    {\n        LogPrintf(\"outpoint %d\\n\", item.outpoint.n);\n        LogPrintf(\"coin %d\\n\", item.coin.nHeight);\n        LogPrintf(\"weight %s\\n\", item.nWeight);\n        LogPrintf(\"age %s\\n\", item.nAge);\n        LogPrintf(\"cumulative %s\\n\", item.nCumulativeWeight);\n    }\n    LogPrintf(\"<<<witinfo\\n\");\n}*/\n\n/** Apply the effects of this block (with given index) on the UTXO set represented by coins.\n *  Validity checks that depend on the UTXO set are also done; ConnectBlock()\n *  can fail if those validity checks fail (among other reasons). */\nbool ConnectBlock(CChain& chain, const CBlock& block, CValidationState& state, CBlockIndex* pindex,\n                  CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck, bool fVerifyWitness, bool fVerifyWitnessDelta, bool fDoScriptChecks)\n{\n    //Force disable witness delta for now\n    fVerifyWitnessDelta = false;\n\n    if (!ContextualCheckBlock(block, state, chainparams, pindex->pprev, chain, &view, true))\n        return error(\"%s: Consensus::CheckBlock, failed ContextualCheckBlock with utxo check: %s\", __func__, FormatStateMessage(state));\n\n    AssertLockHeld(cs_main);\n    assert(pindex);\n    // pindex->phashBlock can be null if called by CreateNewBlock/TestBlockValidity\n    assert((pindex->phashBlock == NULL) || (*pindex->phashBlock == block.GetHashPoW2()));\n    int64_t nTimeStart = GetTimeMicros();\n\n    // Check it again in case a previous version let a bad block in\n    if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck))\n        return error(\"%s: Consensus::CheckBlock: %s\", __func__, FormatStateMessage(state));\n\n    // verify that the view's current state corresponds to the previous block\n    uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHashPoW2();\n    uint256 hashBestBlock = view.GetBestBlock();\n    assert(hashPrevBlock == hashBestBlock);\n    \n    // Previous block must be witnessed\n    if (pindex->nHeight >= (int64_t)Params().GetConsensus().pow2Phase4FirstBlockHeight+2)\n    {\n        if (pindex->pprev->nVersionPoW2Witness == 0)\n        {\n            return state.DoS(100, false, REJECT_INVALID, \"invalid-prevblock-unwitnessed\", false, \"previous block lacks witness information\");\n        }\n    }\n\n    // Special case for the genesis block, skipping connection of its transactions\n    // (its coinbase is unspendable)\n    if (block.GetHashPoW2() == chainparams.GetConsensus().hashGenesisBlock)\n    {\n        if (!fJustCheck)\n        {\n            view.SetBestBlock(pindex->GetBlockHashPoW2());\n            if (block.vtx.size() == 1 && block.vtx[0]->vout.size()>1)\n            {\n                CTxUndo undoDummy;\n                UpdateCoins(*block.vtx[0], view, undoDummy, pindex->nHeight, 0);\n            }\n        }\n        return true;\n    }\n\n    // Check transactions\n    for (const auto& tx : block.vtx)\n    {\n        if (!CheckTransactionContextual(*tx, state, pindex->nHeight))\n        {\n            return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), strprintf(\"Transaction check failed (tx hash %s) %s\", tx->GetHash().ToString(), state.GetDebugMessage()));\n        }\n    }\n\n    bool fScriptChecks = true;\n    if (!hashAssumeValid.IsNull())\n    {\n        // We've been configured with the hash of a block which has been externally verified to have a valid history.\n        // A suitable default value is included with the software and updated from time to time.  Because validity\n        //  relative to a piece of software is an objective fact these defaults can be easily reviewed.\n        // This setting doesn't force the selection of any particular chain but makes validating some faster by\n        //  effectively caching the result of part of the verification.\n        BlockMap::const_iterator  it = mapBlockIndex.find(hashAssumeValid);\n        if (it != mapBlockIndex.end())\n        {\n            if (it->second->GetAncestor(pindex->nHeight) == pindex &&\n                pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&\n                pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork))\n            {\n                // This block is a member of the assumed verified chain and an ancestor of the best header.\n                // The equivalent time check discourages hash power from extorting the network via DOS attack\n                //  into accepting an invalid block through telling users they must manually set assumevalid.\n                //  Requiring a software change or burying the invalid block, regardless of the setting, makes\n                //  it hard to hide the implication of the demand.  This also avoids having release candidates\n                //  that are hardly doing any signature verification at all in testing without having to\n                //  artificially set the default assumed verified block further back.\n                // The test against nMinimumChainWork prevents the skipping when denied access to any chain at\n                //  least as good as the expected chain.\n                fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);\n            }\n        }\n    }\n\n    int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;\n    LogPrint(BCLog::BENCH, \"    - Sanity checks: %.2fms [%.2fs]\\n\", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);\n\n    // Do not allow blocks that contain transactions which 'overwrite' older transactions,\n    // unless those are already completely spent.\n    // If such overwrites are allowed, coinbases and transactions depending upon those\n    // can be duplicated to remove the ability to spend the first instance -- even after\n    // being sent to another address.\n    // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.\n    // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool\n    // already refuses previously-known transaction ids entirely.\n    // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC.\n    // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the\n    // two in the chain that violate it. This prevents exploiting the issue against nodes during their\n    // initial block download.\n    //Munt: BIP30 always true for us.\n    bool fEnforceBIP30 = true;\n/*\n    bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash.\n                          !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S(\"0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec\")) ||\n                           (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S(\"0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721\")));\n*/\n\n    // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting\n    // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs.  But by the\n    // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first\n    // before the first had been spent.  Since those coinbases are sufficiently buried its no longer possible to create further\n    // duplicate transactions descending from the known pairs either.\n    // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.\n    CBlockIndex *pindexBIP34height = pindex->pprev ? pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height) : pindex;\n    //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.\n    fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHashPoW2() == chainparams.GetConsensus().BIP34Hash));\n\n    if (fEnforceBIP30)\n    {\n        for (const auto& tx : block.vtx)\n        {\n            for (size_t o = 0; o < tx->vout.size(); o++)\n            {\n                if (view.HaveCoin(COutPoint(tx->GetHash(), o)))\n                {\n                    return state.DoS(100, error(\"ConnectBlock(): tried to overwrite transaction [%s]\", tx->GetHash().ToString()), REJECT_INVALID, \"bad-txns-BIP30\");\n                }\n            }\n        }\n    }\n\n    // BIP16 didn't become active until Oct 1 2012\n    int64_t nBIP16SwitchTime = 1349049600;\n    bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);\n\n    unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;\n\n    // Start enforcing the DERSIG (BIP66) rule\n    if (pindex->nHeight >= chainparams.GetConsensus().BIP66Height)\n    {\n        flags |= SCRIPT_VERIFY_DERSIG;\n    }\n\n    // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule\n    if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height)\n    {\n        flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;\n    }\n\n    // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.\n    int nLockTimeFlags = 0;\n    if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE)\n    {\n        flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;\n        nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;\n    }\n\n    int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;\n    LogPrint(BCLog::BENCH, \"    - Fork checks: %.2fms [%.2fs]\\n\", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);\n\n    CBlockUndo blockundo;\n\n    CPubKey witnessPubKey;\n    //fixme: (PHASE5) Ideally this would be placed lower down (just before CAmount blockReward = nFees + nSubsidy;) \n    //However GetWitness calls recursively into ConnectBlock and CCheckQueueControl has a non-recursive mutex - so we must call this before creating \n    // Witness block must have valid signature from witness.\n    if ((uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2Phase5FirstBlockHeight)\n    {\n        if (block.nVersionPoW2Witness != 0)\n        {\n            uint256 hash = block.GetHashPoW2();\n            if (!witnessPubKey.RecoverCompact(hash, block.witnessHeaderPoW2Sig))\n                return state.DoS(50, false, REJECT_INVALID, \"invalid-witness-signature\", false, \"witness signature validation failed\");\n\n            // Prefer delta verification where possible\n            if (fVerifyWitness && !fVerifyWitnessDelta)\n            {\n                CGetWitnessInfo witInfo;\n                if (!GetWitness(chain, chainparams, &view, pindex->pprev, block, witInfo))\n                    return state.DoS(100, false, REJECT_INVALID, \"invalid-witness\", false, \"could not determine a valid witness for block\");\n                if(witInfo.selectedWitnessTransaction.GetType() == CTxOutType::PoW2WitnessOutput)\n                {\n                    if (witInfo.selectedWitnessTransaction.output.witnessDetails.witnessKeyID != witnessPubKey.GetID())\n                        return state.DoS(100, false, REJECT_INVALID, \"invalid-witness-signature\", false, \"witness signature incorrect for block\");\n                }\n                else\n                {\n                    return state.DoS(100, false, REJECT_INVALID, \"invalid-witness-signature\", false, \"witness signature missing for block\");\n                }\n            }\n        }\n    }\n\n    //NB! This must occur before CCheckQueueControl to prevent CCheckQueueControl re-entrancy.\n    //fixme: (PHASE5) After phase4 activates the below re-entrancy from WitnessCoinbaseInfoIsValid is no longer a thing.\n    //So we can move this down and combine it with the scope where we check:\n    //unsigned int nWitnessCoinbasePayoutIndex = nWitnessCoinbaseIndex + 1;\n    unsigned int nWitnessCoinbaseIndex = 0;\n    if (block.nVersionPoW2Witness == 0)\n    {\n        // PoW block\n        // Phase 4 + 5 - miner mines 80 reward instead of 100, so nothing to do here (GetBlockSubsidy returns correct amount)\n    }\n    else\n    {\n        // PoW2 block\n        // Ensure witness coinbase is present and that it pays out the right amount.\n        {\n            for (unsigned int i = 1; i < block.vtx.size(); i++)\n            {\n                if (block.vtx[i]->IsCoinBase() && block.vtx[i]->IsPoW2WitnessCoinBase())\n                {\n                    nWitnessCoinbaseIndex = i;\n                    if ((uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2Phase5FirstBlockHeight)\n                    {\n                        if (block.vtx[i]->vout.size() == 0 || block.vtx[i]->vout[0].GetType() != CTxOutType::PoW2WitnessOutput)\n                        {\n                            return state.DoS(100, error(\"ConnectBlock(): PoW2 witness coinbase invalid output position)\"), REJECT_INVALID, \"bad-witness-cb\");\n                        }\n                    }\n                    break;\n                }\n            }\n            if (pindex->nHeight > 0)\n            {\n                if (nWitnessCoinbaseIndex == 0)\n                {\n                    return state.DoS(100, error(\"ConnectBlock(): PoW2 witness coinbase missing)\"), REJECT_INVALID, \"bad-witness-cb\");\n                }\n            }\n        }\n    }\n    \n    //NB! This must occur before CCheckQueueControl variable \"control\", to prevent CCheckQueueControl re-entrancy as GetSimplifiedWitnessUTXOSetForIndex calls into connectblock which lands us back here\n    //Having two CCheckQueueControl instances simultaneously deadlocks the entire software\n    //\n    //Ideally this would be called just before or as part of GetSimplifiedWitnessUTXODeltaForBlock instead\n    //\n    //fixme: (WITNESS_SYNC) - See if we can solve this re-entrancy issue\n    //Note the block above this one has a similar problem so look into that at same time.\n    //\n    std::shared_ptr<SimplifiedWitnessUTXOSet> pow2SimplifiedWitnessUTXOForPrevBlock = nullptr;\n    if (fVerifyWitnessDelta && block.nVersionPoW2Witness != 0 && (uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2Phase5FirstBlockHeight)\n    {\n        pow2SimplifiedWitnessUTXOForPrevBlock = std::make_shared<SimplifiedWitnessUTXOSet>();\n        if (!GetSimplifiedWitnessUTXOSetForIndex(pindex->pprev, *pow2SimplifiedWitnessUTXOForPrevBlock))\n        {\n            return state.DoS(100, error(\"ConnectBlock(): Unable to compute simplified witness utxo for block\"), REJECT_INVALID, \"bad-witness-utxo\");\n        }\n    }\n\n    CCheckQueueControl<CScriptCheck> control(fDoScriptChecks && fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);\n\n    CAmount nFees = 0;\n    CAmount nFeesPoW2Witness = 0;\n    int nInputs = 0;\n    int64_t nSigOpsCost = 0;\n    CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));\n    std::vector<std::pair<uint256, CDiskTxPos> > vPos;\n    vPos.reserve(block.vtx.size());\n    blockundo.vtxundo.reserve(block.vtx.size() - 1);\n    std::vector<PrecomputedTransactionData> txdata;\n    txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated\n    std::vector<CWitnessBundlesRef> witnessBundles;\n    for (unsigned int txIndex = 0; txIndex < block.vtx.size(); txIndex++)\n    {\n        const CTransaction &tx = *(block.vtx[txIndex]);\n        nInputs += tx.vin.size();\n\n        if (tx.IsPoW2WitnessCoinBase())\n        {\n            std::vector<int> prevheights;\n            prevheights.resize(tx.vin.size());\n            for (unsigned int inputIndex = 0; inputIndex < tx.vin.size(); inputIndex++)\n            {\n                if (tx.vin[inputIndex].GetPrevOut().IsNull())\n                {\n                    prevheights[inputIndex] = 0;\n                }\n                else\n                {\n                    if (!view.HaveCoin(tx.vin[inputIndex].GetPrevOut()))\n                    {\n                        return state.DoS(100, error(\"ConnectBlock(): witness coinbase inputs missing/spent\"), REJECT_INVALID, \"bad-txns-inputs-missingorspent\");\n                    }\n                    prevheights[inputIndex] = view.AccessCoin(tx.vin[inputIndex].GetPrevOut()).nHeight;\n                }\n            }\n            // Check that transaction is BIP68 final\n            // BIP68 lock checks (as opposed to nLockTime checks) must\n            // be in ConnectBlock because they require the UTXO set\n            if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex))\n            {\n                return state.DoS(100, error(\"%s: contains a non-BIP68-final transaction\", __func__), REJECT_INVALID, \"bad-txns-nonfinal\");\n            }\n        }\n        else\n        {\n            if (!tx.IsCoinBase())\n            {\n                if (!view.HaveInputs(tx))\n                {\n                    //fixme: (PHASE5) - Low level fix for problem of conflicting transaction entering mempool and causing miners to be unable to mine (due to selecting invalid transactions for block continuously).\n                    //This fix should remain in place, but a follow up fix is needed to try stop the conflicting transaction entering the mempool to begin with - need to hunt the source of this down.\n                    //Seems to have something to do with a double (conflicting) witness renewal transaction.\n                    mempool.removeRecursive(tx, MemPoolRemovalReason::UNKNOWN);\n                    LogPrintf(\"ConnectBlock: mempool contains transaction with invalid inputs [%s]\", tx.GetHash().ToString());\n                    return state.DoS(100, error(\"ConnectBlock: inputs missing/spent\"), REJECT_INVALID, \"bad-txns-inputs-missingorspent\");\n                }\n\n                // Check that transaction is BIP68 final\n                // BIP68 lock checks (as opposed to nLockTime checks) must\n                // be in ConnectBlock because they require the UTXO set\n                std::vector<int> prevheights;\n                prevheights.resize(tx.vin.size());\n                for (size_t j = 0; j < tx.vin.size(); j++) {\n                    prevheights[j] = view.AccessCoin(tx.vin[j].GetPrevOut()).nHeight;\n                }\n\n                if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex))\n                {\n                    return state.DoS(100, error(\"%s: contains a non-BIP68-final transaction\", __func__), REJECT_INVALID, \"bad-txns-nonfinal\");\n                }\n            }\n        }\n\n        // GetTransactionSigOpCost counts 3 types of sigops:\n        // * legacy (always)\n        // * p2sh (when P2SH enabled in flags and excludes coinbase)\n        // * witness (when witness enabled in flags and excludes coinbase)\n        nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);\n        if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST)\n            return state.DoS(100, error(\"ConnectBlock(): too many sigops\"), REJECT_INVALID, \"bad-blk-sigops\");\n\n        txdata.emplace_back(tx);\n\n        CWitnessBundles bundles;\n        if ((uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2Phase5FirstBlockHeight)\n        {\n            assert(GetSpendHeight(view) == pindex->nHeight);\n            if (!BuildWitnessBundles(tx, state, GetSpendHeight(view), txIndex,\n                    [&](const COutPoint& outpoint, CTxOut& txOut, uint64_t& txHeight, uint64_t& txIndex_, uint64_t& txOutputIndex) -> bool {\n                        const Coin& coin = view.AccessCoin(outpoint);\n                        if (coin.IsSpent())\n                            return false;\n                        txOut = coin.out;\n                        txHeight = coin.nHeight;\n                        txIndex_ = coin.nTxIndex;\n                        txOutputIndex = outpoint.n;\n                        return true;\n                    },\n                    bundles))\n            {\n                return error(\"ConnectBlock(): BuildWitnessBundles on %s failed with %s\", tx.GetHash().ToString(), FormatStateMessage(state));\n            }\n        }\n\n        witnessBundles.push_back(std::make_shared<CWitnessBundles>(bundles));\n        tx.witnessBundles = witnessBundles[txIndex];\n\n        //fixme: (PHASE4) (CODEBASE CLEANUP) - CheckInputs needs to run as well for witness coinbase (can we just run this whole block for witness coinbase?) - we already test this elsewhere so it would only be a cleanness improvement.\n        if (!tx.IsCoinBase())\n        {\n            if (nWitnessCoinbaseIndex != 0 && txIndex > nWitnessCoinbaseIndex)\n            {\n                nFeesPoW2Witness += view.GetValueIn(tx)-tx.GetValueOut();;\n            }\n            else\n            {\n                nFees += view.GetValueIn(tx)-tx.GetValueOut();\n            }\n\n\n            std::vector<CScriptCheck> vChecks;\n            bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */\n            if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[txIndex], witnessBundles[txIndex].get(), nScriptCheckThreads ? &vChecks : NULL))\n                return error(\"ConnectBlock(): CheckInputs on %s failed with %s\",\n                             tx.GetHash().ToString(), FormatStateMessage(state));\n            control.Add(vChecks);\n        }\n\n        CTxUndo undoDummy;\n        if (txIndex > 0) {\n            blockundo.vtxundo.push_back(CTxUndo());\n        }\n        UpdateCoins(tx, view, txIndex == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight, txIndex);\n\n        vPos.push_back(std::pair(tx.GetHash(), pos));\n        pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);\n    }\n    int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;\n    LogPrint(BCLog::BENCH, \"      - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\\n\", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);\n\n\n    //Forbid any transactions that would affect the witness set from occuring after the witness coinbase index\n    //As this would present complications for the \"simplified witness set\" accounting\n    if ((uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2WitnessSyncHeight && nWitnessCoinbaseIndex != 0)\n    {\n        for (unsigned int i = nWitnessCoinbaseIndex+1; i < block.vtx.size(); i++)\n        {\n            if (!block.vtx[i]->witnessBundles || block.vtx[i]->witnessBundles->size()>0)\n            {\n                return state.DoS(100, error(\"ConnectBlock(): Witness related transaction after witness coinbase)\"), REJECT_INVALID, \"bad-witness-transactions\");\n            }\n        }\n    }\n\n    //Check that the actual witness changes contained in the block match those described in the header as populated by the witness\n    //\n    //fixme: (FUT): We could consider some kind of active penalty for a witness caught doing this\n    //Though whether there is really a need or reason to go that far is not clear, that it won't succeed is likely a large enough deterrent.\n    //fixme: (WITNESS_SYNC) - Change this check to pow2WitnessSyncHeight after we have more testing in place\n    if (fVerifyWitnessDelta && block.nVersionPoW2Witness != 0 && (uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2Phase5FirstBlockHeight)\n    {\n        if ((uint64_t)pindex->nHeight > chainparams.GetConsensus().pow2WitnessSyncHeight)\n        {\n            if (!witnessPubKey.IsValid())\n                return state.DoS(50, false, REJECT_INVALID, \"invalid-witness-signature\", false, \"witness signature validation failed\");\n\n            std::vector<unsigned char> compWitnessUTXODelta;\n            if (!GetSimplifiedWitnessUTXODeltaForBlock(pindex, block, pow2SimplifiedWitnessUTXOForPrevBlock, compWitnessUTXODelta, &witnessPubKey))\n            {\n                return state.DoS(100, error(\"ConnectBlock(): Unable to compute witness delta for block\"), REJECT_INVALID, \"bad-witness-utxo-delta\");\n            }\n            if (!std::equal(compWitnessUTXODelta.begin(), compWitnessUTXODelta.end(), block.witnessUTXODelta.begin()))\n            {\n                return state.DoS(100, error(\"ConnectBlock(): PoW2 simplified witness delta incorrect\"), REJECT_INVALID, \"bad-witness-utxo-delta\");\n            }\n        }\n        else\n        {\n            std::vector<unsigned char> compWitnessUTXODelta;\n            if (!GetSimplifiedWitnessUTXODeltaForBlock(pindex, block, pow2SimplifiedWitnessUTXOForPrevBlock, compWitnessUTXODelta, nullptr))\n            {\n                return state.DoS(100, error(\"ConnectBlock(): Unable to compute witness delta for block\"), REJECT_INVALID, \"bad-witness-utxo-delta\");\n            }\n            if (block.witnessUTXODelta.size() > 0)\n            {\n                return state.DoS(100, error(\"ConnectBlock(): PoW2 simplified witness delta before activation\"), REJECT_INVALID, \"premature-witness-utxo-delta\");\n            }\n        }\n    }\n\n    //fixme: (PHASE5) (CLEANUP) - We can remove this after phase4 becomes active.\n\n    //Until PoW2 activates mining subsidy remains full.\n    //Phase 3 - miner mines 80 reward for himself and 20 reward for previous blocks witness...\n    //Phase 4/5 - miner mines 80 reward for himself, witness 20 reward for himself (two seperate coinbases)\n    CAmount nSubsidy = GetBlockSubsidy(pindex->nHeight).total;\n    CAmount nSubsidyWitnessExpected = GetBlockSubsidy(pindex->nHeight).witness;\n    CAmount nSubsidyDev = GetBlockSubsidy(pindex->nHeight).dev;\n\n    bool haveSegregatedSignatures = IsSegSigEnabled(pindex);\n    if (IsPow2Phase4Active(pindex->pprev))\n    {\n        nSubsidy -= nSubsidyWitnessExpected;\n    }\n\n    if (block.nVersionPoW2Witness == 0 || pindex->nHeight == 0)\n    {\n        // PoW block\n        // Phase 4 + 5 - miner mines 80 reward instead of 100, so nothing to do here (GetBlockSubsidy returns correct amount)\n    }\n    else\n    {\n        // PoW2 block\n        // Ensure witness coinbase is present and that it pays out the right amount.\n        CAmount nValIn = 0;\n        for (auto output : blockundo.vtxundo[nWitnessCoinbaseIndex-1].vprevout)\n        {\n            if (output.out.nValue > 0)\n                nValIn += output.out.nValue;\n        }\n\n        nSubsidyWitnessExpected += nFeesPoW2Witness;\n        if (block.vtx[nWitnessCoinbaseIndex]->GetValueOut() - nValIn > nSubsidyWitnessExpected)\n        {\n            return state.DoS(100, error(\"ConnectBlock(): PoW2 witness pays too much (actual=%d vs limit=%d)\", block.vtx[nWitnessCoinbaseIndex]->GetValueOut(), nSubsidyWitnessExpected), REJECT_INVALID, \"bad-witness-cb-amount\");\n        }\n\n        if (block.vtx[nWitnessCoinbaseIndex]->vin.size() != 2)\n            return state.DoS(100, error(\"ConnectBlock(): PoW2 witness coinbase invalid vin size)\"), REJECT_INVALID, \"bad-witness-cb\");\n\n        if (!block.vtx[nWitnessCoinbaseIndex]->vin[0].GetPrevOut().IsNull())\n            return state.DoS(100, error(\"ConnectBlock(): PoW2 witness coinbase invalid prevout)\"), REJECT_INVALID, \"bad-witness-cb\");\n\n        if (block.vtx[nWitnessCoinbaseIndex]->vin[0].GetSequence(block.vtx[nWitnessCoinbaseIndex]->nVersion) != 0)\n            return state.DoS(100, error(\"ConnectBlock(): PoW2 witness coinbase invalid sequence)\"), REJECT_INVALID, \"bad-witness-cb\");\n    }\n\n    //fixme: (PHASE5) (SEGSIG/POW2) - Triple check that there are no additional remaining tests that should go here.\n    // We already check:\n    // 1) The witness signature matches the witness (earlier in this function)\n    // 2) The witness coinbase has the right number of inputs (earlier in this function)\n    // 3) The witness timestamp is valid (when we verify the header)\n    // 4) The transactions just get checked as normal\n\n    CAmount expectedBlockReward = nFees + nSubsidy;\n    CAmount actualBlockReward = block.vtx[0]->GetValueOut();\n    if ((actualBlockReward > expectedBlockReward))\n    {\n        return state.DoS(100, error(\"ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)\", actualBlockReward, expectedBlockReward), REJECT_INVALID, \"bad-cb-amount\");\n    }\n    // fixme: (PHASE5) Forbid block reward that under pays as well - leave this for now and reconsider in future.\n    \n    if (nSubsidyDev > 0)\n    {\n        std::string devSubsidyAddressFinal = devSubsidyAddress1;\n        if (nSubsidyDev > 1'000'000*COIN)\n        {\n            devSubsidyAddressFinal = devSubsidyAddress2;\n        }\n\n        // Phase 4 - Must have 2 outputs (miner, dev) - witness in seperate transaction\n        if ((IsSegSigEnabled(pindex->pprev) && block.vtx[0]->vout.size() != 2))\n        {\n            return state.DoS(100, error(\"ConnectBlock(): coinbase has incorrect number of outputs (actual=%d vs limit=%d)\", block.vtx[0]->vout.size(), 2), REJECT_INVALID, \"bad-cb-amount\");\n        }\n        \n        static std::vector<unsigned char> data(ParseHex(devSubsidyAddressFinal));\n        static CPubKey pubKeyDevSubsidyCheck(data.begin(), data.end());\n        static CScript scriptDevSubsidyCheck = (CScript() << ToByteVector(pubKeyDevSubsidyCheck) << OP_CHECKSIG);\n        if (block.vtx[0]->vout[1].output.nType == CTxOutType::StandardKeyHashOutput)\n        {\n            if (block.vtx[0]->vout[1].output.standardKeyHash.keyID != pubKeyDevSubsidyCheck.GetID())\n            {\n                return state.DoS(100, error(\"ConnectBlock(): coinbase lacks dev subsidy output\"), REJECT_INVALID, \"bad-cb-amount\");\n            }\n        }\n        else if (block.vtx[0]->vout[1].output.nType == CTxOutType::ScriptLegacyOutput)\n        {\n            if (block.vtx[0]->vout[1].output.scriptPubKey != scriptDevSubsidyCheck)\n            {\n                return state.DoS(100, error(\"ConnectBlock(): coinbase lacks dev subsidy output\"), REJECT_INVALID, \"bad-cb-amount\");\n            }\n        }\n        else\n        {\n            return state.DoS(100, error(\"ConnectBlock(): coinbase has invalid type for dev subsidy output\"), REJECT_INVALID, \"bad-cb-amount\");\n        }\n        if (block.vtx[0]->vout[1].nValue != nSubsidyDev)\n        {\n            return state.DoS(100, error(\"ConnectBlock(): coinbase has invalid dev subsidy (actual=%d vs limit=%d)\", block.vtx[0]->vout[1].nValue, nSubsidyDev), REJECT_INVALID, \"bad-cb-amount\");\n        }\n    }\n    \n    // From phase 3 onward we forbid miners from not claiming the full reward.\n    if (haveSegregatedSignatures && expectedBlockReward < actualBlockReward)\n    {\n        return state.DoS(100, error(\"ConnectBlock(): coinbase pays too little (actual=%d vs limit=%d)\", actualBlockReward, expectedBlockReward), REJECT_INVALID, \"bad-cb-amount\");\n    }\n\n    if (!control.Wait())\n        return state.DoS(100, error(\"%s: CheckQueue failed\", __func__), REJECT_INVALID, \"block-validation-failed\");\n    int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;\n    LogPrint(BCLog::BENCH, \"    - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\\n\", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);\n\n    if (fJustCheck)\n        return true;\n\n    // Write undo information to disk\n    if (pindex->pprev &&(pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)))\n    {\n        if (pindex->GetUndoPos().IsNull()) {\n            CDiskBlockPos _pos;\n            if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))\n                return error(\"ConnectBlock(): FindUndoPos failed\");\n            if (!blockStore.UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHashPoW2(), chainparams.MessageStart()))\n                return AbortNode(state, \"Failed to write undo data\");\n\n            // update nUndoPos in block index\n            pindex->nUndoPos = _pos.nPos;\n            pindex->nStatus |= BLOCK_HAVE_UNDO;\n        }\n\n        pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);\n        if (chain == chainActive)\n        {\n            setDirtyBlockIndex.insert(pindex);\n        }\n    }\n\n    if (fTxIndex)\n        if (!pblocktree->WriteTxIndex(vPos))\n            return AbortNode(state, \"Failed to write transaction index\");\n\n    // add this block to the view's block chain\n    view.SetBestBlock(pindex->GetBlockHashPoW2());\n\n    int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;\n    LogPrint(BCLog::BENCH, \"    - Index writing: %.2fms [%.2fs]\\n\", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);\n\n    int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5;\n    LogPrint(BCLog::BENCH, \"    - Callbacks: %.2fms [%.2fs]\\n\", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);\n\n    return true;\n}\n\nvoid FindFilesToPruneExplicit(std::set<int>& setFilesToPrune, unsigned int nPruneHeight)\n{\n    LOCK2(cs_main, cs_LastBlockFile);\n\n    int count=0;\n    for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {\n        if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast >= nPruneHeight)\n            continue;\n        PruneOneBlockFile(fileNumber);\n        setFilesToPrune.insert(fileNumber);\n        count++;\n    }\n    LogPrint(BCLog::PRUNE, \"Prune (Manual): prune_height=%d removed %d blk/rev pairs\\n\", nPruneHeight, count);\n}\n\n/**\n * Update the on-disk chain state.\n * The caches and indexes are flushed depending on the mode we're called with\n * if they're too large, if it's been a while since the last write,\n * or always and in all cases if we're in prune mode and are deleting files.\n */\nbool FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight, bool fFlushPartialSync) {\n    int64_t nMempoolUsage = mempool.DynamicMemoryUsage();\n    LOCK2(cs_main, cs_LastBlockFile);\n    static int64_t nLastWrite = 0;\n    static int64_t nLastFlush = 0;\n    static int64_t nLastSetChain = 0;\n    std::set<int> setFilesToPrune;\n    bool fFlushForPrune = false;\n    try {\n    if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex)\n    {\n        if (nManualPruneHeight > 0 && !fFlushPartialSync)\n        {\n            FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);\n        }\n        else if (nManualPruneHeight > 0 && fFlushPartialSync)\n        {\n            FindFilesToPruneExplicit(setFilesToPrune, nManualPruneHeight);\n        }\n        else\n        {\n            FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());\n            fCheckForPruning = false;\n        }\n\n        if (!setFilesToPrune.empty()) {\n            fFlushForPrune = true;\n            if (!fHavePruned) {\n                pblocktree->WriteFlag(\"prunedblockfiles\", true);\n                fHavePruned = true;\n            }\n        }\n    }\n    int64_t nNow = GetTimeMicros();\n    // Avoid writing/flushing immediately after startup.\n    if (nLastWrite == 0) {\n        nLastWrite = nNow;\n    }\n    if (nLastFlush == 0) {\n        nLastFlush = nNow;\n    }\n    if (nLastSetChain == 0) {\n        nLastSetChain = nNow;\n    }\n    int64_t nMempoolSizeMax = GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;\n    int64_t cacheSize = pcoinsTip->DynamicMemoryUsage() * DB_PEAK_USAGE_FACTOR;\n    int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);\n    // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).\n    bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);\n    // The cache is over the limit, we have to write now.\n    bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace;\n    // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash.\n    bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;\n    // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.\n    bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;\n    // Combine all conditions that result in a full cache flush.\n    bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;\n    // Write blocks and block index to disk.\n    if (fDoFullFlush || fPeriodicWrite) {\n        // Depend on nMinDiskSpace to ensure we can write block index\n        if (!CheckDiskSpace(0))\n            return state.Error(\"out of disk space\");\n        // First make sure all block and undo data is flushed to disk.\n        FlushBlockFile();\n        // Then update all block file information (which may refer to block and undo files).\n        {\n            std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;\n            vFiles.reserve(setDirtyFileInfo.size());\n            for (std::set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) {\n                vFiles.push_back(std::pair(*it, &vinfoBlockFile[*it]));\n                setDirtyFileInfo.erase(it++);\n            }\n\n            // prune block index for partial sync\n            std::vector<uint256> removals;\n            if (fFlushPartialSync) {\n#ifdef DEBUG_PARTIAL_SYNC\n                int numNotOnPartialChain = 0;\n#endif\n                for(const auto& it: mapBlockIndex)\n                {\n                    CBlockIndex* index = it.second;\n                    if ((index->nHeight < nManualPruneHeight && // prune anything below prune-height\n                         (index->nHeight !=0 || index->GetBlockHashPoW2() != Params().GenesisBlock().GetHashPoW2()) && // that is not the Genesis\n                         index->nHeight >= nPartialPruneHeightDone // skip pruning below height that was already pruned this session\n                        )\n                        || index->nStatus & BLOCK_FAILED_MASK) // always prune invalid blocks (if it changes they will be dirty again)\n                    {\n                        // blocks below partial sync pruning height that are not on the chain have to be marked as conflicting permanantly now\n                        // as after pruning this information will be lost and there it can not be determined any more if the block was part of the chain\n                        if (!partialChain.Contains(index))\n                        {\n                            GetMainSignals().PruningConflictingBlock(index->GetBlockHashPoW2());\n                        }\n\n                        removals.push_back(index->GetBlockHashPoW2());\n                        setDirtyBlockIndex.erase(index); // prevent pruned indexes to be rewritten\n                    }\n#ifdef DEBUG_PARTIAL_SYNC\n                    if (!partialChain.Contains(index)) {\n                        numNotOnPartialChain++;\n                        // think about what to do, do we need to remove/mark the tx to be conflicting/abandon, and what about the block?\n                        // it is normal to have forks (and blocks getting witnessed) at/near the tip, only log deeper ones\n                        if (index->nHeight < partialChain.Height() - 20)\n                            LogPrintf(\"Index not on partial chain during prune: [%s] height = %d\\n\", index->GetBlockHashPoW2().ToString(), index->nHeight);\n                    }\n#endif\n                }\n                nPartialPruneHeightDone = std::max(nManualPruneHeight, nPartialPruneHeightDone);\n#ifdef DEBUG_PARTIAL_SYNC\n                int numOrphans = mapBlockIndex.size() - (partialChain.Height()-partialChain.HeightOffset()) - 1;\n                assert(numOrphans == numNotOnPartialChain);\n#endif\n            }\n\n            std::vector<const CBlockIndex*> vBlocks;\n            vBlocks.reserve(setDirtyBlockIndex.size());\n            for (std::set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {\n                vBlocks.push_back(*it);\n                setDirtyBlockIndex.erase(it++);\n            }\n            LogPrintf(\"%s: updating %d and deleting %d block indexes, prune height = %d\\n\", __func__, vBlocks.size(), removals.size(), nManualPruneHeight);\n            std::set<std::pair<uint256, CDiskTxPos>> unusedEmptySet;\n            if (!pblocktree->UpdateBatchSync(vFiles, nLastBlockFile, vBlocks, removals, unusedEmptySet, unusedEmptySet )) {\n                return AbortNode(state, \"Failed to write to block index database\");\n            }\n            uiInterface.NotifySPVPrune(nPartialPruneHeightDone);\n        }\n        // Finally remove any pruned files\n        if (fFlushForPrune)\n            blockStore.UnlinkPrunedFiles(setFilesToPrune);\n        nLastWrite = nNow;\n    }\n    // Flush best chain related state. This can only be done if the blocks / block index write was also done.\n    if (fDoFullFlush) {\n        // Typical Coin structures on disk are around 48 bytes in size.\n        // Pushing a new one to the database can cause it to be written\n        // twice (once in the log, and once in the tables). This is already\n        // an overestimation, as most will delete an existing entry or\n        // overwrite one. Still, use a conservative safety factor of 2.\n        if (!CheckDiskSpace(48 * 2 * 2 * pcoinsTip->GetCacheSize()))\n            return state.Error(\"out of disk space\");\n        // Flush the chainstate (which may refer to block index entries).\n        if (!pcoinsTip->Flush())\n            return AbortNode(state, \"Failed to write to coin database\");\n        nLastFlush = nNow;\n    }\n    if (   !fFlushPartialSync\n        && (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000))) {\n        // Update best block in wallet (so we can detect restored wallets).\n        GetMainSignals().SetBestChain(chainActive.GetLocatorPoW2());\n        nLastSetChain = nNow;\n    }\n    } catch (const std::runtime_error& e) {\n        return AbortNode(state, std::string(\"System error while flushing: \") + e.what());\n    }\n    return true;\n}\n\nvoid FlushStateToDisk() {\n    CValidationState state;\n    const CChainParams& chainparams = Params();\n    FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS);\n}\n\nvoid PruneAndFlush() {\n    CValidationState state;\n    fCheckForPruning = true;\n    const CChainParams& chainparams = Params();\n    FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE);\n}\n\nstatic void DoWarning(const std::string& strWarning)\n{\n    static bool fWarned = false;\n    SetMiscWarning(strWarning);\n    if (!fWarned)\n    {\n        CAlert::Notify(strWarning, true, true);\n        fWarned = true;\n    }\n}\n\n/** Update chainActive and related internal data structures. */\nvoid static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {\n    chainActive.SetTip(pindexNew);\n\n    // New best block\n    mempool.AddTransactionsUpdated(1);\n\n    cvBlockChange.notify_all();\n\n    std::vector<std::string> warningMessages;\n    if (!IsInitialBlockDownload())\n    {\n        int nUpgraded = 0;\n        const CBlockIndex* pindex = chainActive.Tip();\n        for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++)\n        {\n            //fixme: (PHASE5) \n            //Silence phase 2 bit warning (as we retroactively removed phase2 check)\n            if (bit == 27)\n                continue;\n            WarningBitsConditionChecker checker(bit);\n            ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);\n            if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN)\n            {\n                const std::string strWarning = strprintf(_(\"Warning: unknown new rules activated (versionbit %i)\"), bit);\n                if (state == THRESHOLD_ACTIVE)\n                {\n                    DoWarning(strWarning);\n                }\n                else\n                {\n                    warningMessages.push_back(strWarning);\n                }\n            }\n        }\n        // Check the version of the last 100 blocks to see if we need to upgrade:\n        for (int i = 0; i < 100 && pindex != NULL; i++)\n        {\n            int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());\n            if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)\n                ++nUpgraded;\n            pindex = pindex->pprev;\n        }\n        if (nUpgraded > 0)\n            warningMessages.push_back(strprintf(_(\"%d of last 100 blocks have unexpected version\"), nUpgraded));\n        if (nUpgraded > 100/2)\n        {\n            std::string strWarning = _(\"Warning: Unknown block versions in chain! It's possible unknown rules are in effect\");\n            // notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user:\n            DoWarning(strWarning);\n        }\n    }\n    //fixme: (PHASE5) - Replace this 1000000 constant with a chainparams paramater so we remember to update it.\n    if(!gbMinimalLogging || !warningMessages.empty() || Params().IsTestnet() || chainActive.Height() % 1000 == 0 || chainActive.Height() > 1000000)\n    {\n        LogPrintf(\"%s: new best=%s height=%d version=0x%08x versionpow2=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)\", __func__,\n            chainActive.Tip()->GetBlockHashPoW2().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, chainActive.Tip()->nVersionPoW2Witness,\n            log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,\n            FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()),\n            GuessVerificationProgress(chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());\n        if (!warningMessages.empty())\n            LogPrintf(\" warning='%s'\", boost::algorithm::join(warningMessages, \", \"));\n        LogPrintf(\"\\n\");\n    }\n}\n\n/** Disconnect chainActive's tip.\n  * After calling, the mempool will be in an inconsistent state, with\n  * transactions from disconnected blocks being added to disconnectpool.  You\n  * should make the mempool consistent again by calling UpdateMempoolForReorg.\n  * with cs_main held.\n  *\n  * If disconnectpool is NULL, then no disconnected transactions are added to\n  * disconnectpool (note that the caller is responsible for mempool consistency\n  * in any case).\n  */\nbool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)\n{\n    AssertLockHeld(cs_main); // Required for ReadBlockFromDisk.\n\n    CBlockIndex *pindexDelete = chainActive.Tip();\n    assert(pindexDelete);\n    // Read block from disk.\n    std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n    CBlock& block = *pblock;\n    if (!ReadBlockFromDisk(block, pindexDelete, chainparams))\n        return AbortNode(state, \"Failed to read block\");\n    // Apply the block atomically to the chain state.\n    int64_t nStart = GetTimeMicros();\n    {\n        CCoinsViewCache view(pcoinsTip);\n        if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)\n            return error(\"DisconnectTip(): DisconnectBlock %s failed\", pindexDelete->GetBlockHashPoW2().ToString());\n        bool flushed = view.Flush();\n        assert(flushed);\n    }\n    LogPrint(BCLog::BENCH, \"- Disconnect block: %.2fms\\n\", (GetTimeMicros() - nStart) * 0.001);\n    // Write the chain state to disk, if necessary.\n    if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))\n        return false;\n\n    if (disconnectpool) {\n        // Save transactions to re-add to mempool at end of reorg\n        for (auto it = block.vtx.rbegin(); it != block.vtx.rend(); ++it) {\n            disconnectpool->addTransaction(*it);\n        }\n        while (disconnectpool->DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE * 1000) {\n            // Drop the earliest entry, and remove its children from the mempool.\n            auto it = disconnectpool->queuedTx.get<insertion_order>().begin();\n            mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);\n            disconnectpool->removeEntry(it);\n        }\n    }\n\n    // Update chainActive and related variables.\n    UpdateTip(pindexDelete->pprev, chainparams);\n    // Let wallets know transactions went from 1-confirmed to\n    // 0-confirmed or conflicted:\n    GetMainSignals().BlockDisconnected(pblock);\n    return true;\n}\n\nstatic int64_t nTimeReadFromDisk = 0;\nstatic int64_t nTimeConnectTotal = 0;\nstatic int64_t nTimeFlush = 0;\nstatic int64_t nTimeChainState = 0;\nstatic int64_t nTimePostConnect = 0;\n\nstruct PerBlockConnectTrace {\n    CBlockIndex* pindex = NULL;\n    std::shared_ptr<const CBlock> pblock;\n    std::shared_ptr<std::vector<CTransactionRef>> conflictedTxs;\n    PerBlockConnectTrace() : conflictedTxs(std::make_shared<std::vector<CTransactionRef>>()) {}\n};\n/**\n * Used to track blocks whose transactions were applied to the UTXO state as a\n * part of a single ActivateBestChainStep call.\n *\n * This class also tracks transactions that are removed from the mempool as\n * conflicts (per block) and can be used to pass all those transactions\n * through SyncTransaction.\n *\n * This class assumes (and asserts) that the conflicted transactions for a given\n * block are added via mempool callbacks prior to the BlockConnected() associated\n * with those transactions. If any transactions are marked conflicted, it is\n * assumed that an associated block will always be added.\n *\n * This class is single-use, once you call GetBlocksConnected() you have to throw\n * it away and make a new one.\n */\nclass ConnectTrace {\nprivate:\n    std::vector<PerBlockConnectTrace> blocksConnected;\n    CTxMemPool &pool;\n\npublic:\n    ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {\n        pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));\n    }\n\n    ~ConnectTrace() {\n        pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));\n    }\n\n    void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {\n        assert(!blocksConnected.back().pindex);\n        assert(pindex);\n        assert(pblock);\n        blocksConnected.back().pindex = pindex;\n        blocksConnected.back().pblock = std::move(pblock);\n        blocksConnected.emplace_back();\n    }\n\n    std::vector<PerBlockConnectTrace>& GetBlocksConnected() {\n        // We always keep one extra block at the end of our list because\n        // blocks are added after all the conflicted transactions have\n        // been filled in. Thus, the last entry should always be an empty\n        // one waiting for the transactions from the next block. We pop\n        // the last entry here to make sure the list we return is sane.\n        assert(!blocksConnected.back().pindex);\n        assert(blocksConnected.back().conflictedTxs->empty());\n        blocksConnected.pop_back();\n        return blocksConnected;\n    }\n\n    void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {\n        assert(!blocksConnected.back().pindex);\n        if (reason == MemPoolRemovalReason::CONFLICT) {\n            blocksConnected.back().conflictedTxs->emplace_back(std::move(txRemoved));\n        }\n    }\n};\n\n/**\n * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock\n * corresponding to pindexNew, to bypass loading it again from disk.\n *\n * The block is added to connectTrace if connection succeeds.\n */\nbool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)\n{\n    AssertLockHeld(cs_main); // Required for ReadBlockFromDisk.\n\n    assert(pindexNew->pprev == chainActive.Tip());\n    // Read block from disk.\n    int64_t nTime1 = GetTimeMicros();\n    std::shared_ptr<const CBlock> pthisBlock;\n    if (!pblock) {\n        std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();\n        if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams))\n            return AbortNode(state, \"Failed to read block\");\n        pthisBlock = pblockNew;\n    } else {\n        pthisBlock = pblock;\n    }\n    const CBlock& blockConnecting = *pthisBlock;\n    // Apply the block atomically to the chain state.\n    int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;\n    int64_t nTime3;\n    LogPrint(BCLog::BENCH, \"  - Load block from disk: %.2fms [%.2fs]\\n\", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);\n    {\n        CCoinsViewCache view(pcoinsTip);\n        bool fJustCheck = false;\n        bool fValidateWitness = true;\n        //fixme: (PHASE5) (WITNESS/HEADER sync)- relook into this for phase5.\n        //This check is expensive when syncing\n        //So we bypass this with a small random chance of still checking IFF we are below the checkpoint heights.\n        //Note:\n        // 1) An attacker would still have to meet/break/forge the sha ppev hash checks for an entire chain from the checkpoints\n        // 2) An attacker would still have to meet all other PoW check *and* keep all witness states intact\n        // This is enough to ensure that an attacker would have to go to great lengths for what would amount to a minor nuisance (having to refetch some more headers after detecting wrong chain)\n        // So this is not really a major weakening of security in any way and still more than sufficient.\n        if ((uint64_t)pindexNew->nHeight < std::max((uint64_t)Checkpoints::LastCheckPointHeight(), (uint64_t)1859000))\n            fValidateWitness = false;\n        bool rv = ConnectBlock(chainActive, blockConnecting, state, pindexNew, view, chainparams, fJustCheck, fValidateWitness);\n        GetMainSignals().BlockChecked(blockConnecting, state);\n        if (!rv) {\n            if (state.IsInvalid())\n                InvalidBlockFound(pindexNew, state);\n            return error(\"ConnectTip(): ConnectBlock %s failed (%s)\", pindexNew->GetBlockHashPoW2().ToString(), state.GetRejectReason().c_str());\n        }\n        nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;\n        LogPrint(BCLog::BENCH, \"  - Connect total: %.2fms [%.2fs]\\n\", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);\n\n        bool flushed = view.Flush();\n        assert(flushed);\n    }\n    int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;\n    LogPrint(BCLog::BENCH, \"  - Flush: %.2fms [%.2fs]\\n\", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);\n    // Write the chain state to disk, if necessary.\n    if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))\n        return false;\n    int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;\n    LogPrint(BCLog::BENCH, \"  - Writing chainstate: %.2fms [%.2fs]\\n\", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);\n    // Remove conflicting transactions from the mempool.;\n    mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);\n    disconnectpool.removeForBlock(blockConnecting.vtx);\n    // Update chainActive & related variables.\n    UpdateTip(pindexNew, chainparams);\n\n    int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;\n    LogPrint(BCLog::BENCH, \"  - Connect postprocess: %.2fms [%.2fs]\\n\", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);\n    LogPrint(BCLog::BENCH, \"- Connect block: %.2fms [%.2fs]\\n\", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);\n\n    connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));\n    return true;\n}\n\n/**\n * Return the tip of the chain with the most work in it, that isn't\n * known to be invalid (it's however far from certain to be valid).\n */\nstatic CBlockIndex* FindMostWorkChain() {\n    LOCK(cs_main);\n    do {\n        CBlockIndex *pindexNew = NULL;\n\n        // Find the best candidate header.\n        {\n            std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexCandidates.rbegin();\n            if (it == setBlockIndexCandidates.rend())\n                return NULL;\n            pindexNew = *it;\n        }\n\n        // Check whether all blocks on the path between the currently active chain and the candidate are valid.\n        // Just going until the active chain is an optimization, as we know all blocks in it are valid already.\n        CBlockIndex *pindexTest = pindexNew;\n        bool fInvalidAncestor = false;\n        while (pindexTest && !chainActive.Contains(pindexTest)) {\n            assert(pindexTest->nChainTx || pindexTest->nHeight == 0);\n\n            // Pruned nodes may have entries in setBlockIndexCandidates for\n            // which block files have been deleted.  Remove those as candidates\n            // for the most work chain if we come across them; we can't switch\n            // to a chain unless we have all the non-active-chain parent blocks.\n            bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK;\n            bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA);\n            if (fFailedChain || fMissingData) {\n                // Candidate chain is not usable (either invalid or missing data)\n                if (fFailedChain && (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork))\n                    pindexBestInvalid = pindexNew;\n                CBlockIndex *pindexFailed = pindexNew;\n                // Remove the entire chain from the set.\n                while (pindexTest != pindexFailed) {\n                    if (fFailedChain) {\n                        pindexFailed->nStatus |= BLOCK_FAILED_CHILD;\n                    } else if (fMissingData) {\n                        // If we're missing data, then add back to mapBlocksUnlinked,\n                        // so that if the block arrives in the future we can try adding\n                        // to setBlockIndexCandidates again.\n                        mapBlocksUnlinked.insert(std::pair(pindexFailed->pprev, pindexFailed));\n                    }\n                    setBlockIndexCandidates.erase(pindexFailed);\n                    pindexFailed = pindexFailed->pprev;\n                }\n                setBlockIndexCandidates.erase(pindexTest);\n                fInvalidAncestor = true;\n                break;\n            }\n            pindexTest = pindexTest->pprev;\n        }\n        if (!fInvalidAncestor)\n            return pindexNew;\n    } while(true);\n}\n\n/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */\nstatic void PruneBlockIndexCandidates() {\n    LOCK(cs_main);\n    // Note that we can't delete the current block itself, as we may need to return to it later in case a\n    // reorganization to a better block fails.\n    std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();\n\n    //NB! We don't prune blocks that are the same height as the current tip when the current tip is PoW.\n    //The reason for this is that we must consider all such blocks as witness candidates even if they are of lower weight - in case the higher weight block has an \"absent\" witness.\n    while ( ( it != setBlockIndexCandidates.end() ) && ( (*it)->nChainWork < chainActive.Tip()->nChainWork ) && ( (*it)->nHeight < chainActive.Tip()->nHeight /*|| (*it)->nVersionPoW2Witness == 0*/ ) ) {\n        setBlockIndexCandidates.erase(it++);\n    }\n    // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates.\n    if (!fSPV)\n    {\n        assert(!setBlockIndexCandidates.empty());\n    }\n}\n\n/**\n * Try to make some progress towards making pindexMostWork the active block.\n * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.\n */\nstatic bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)\n{\n    AssertLockHeld(cs_main);\n    const CBlockIndex *pindexOldTip = chainActive.Tip();\n    const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);\n\n    // Disconnect active blocks which are no longer in the best chain.\n    bool fBlocksDisconnected = false;\n    DisconnectedBlockTransactions disconnectpool;\n    while (chainActive.Tip() && chainActive.Tip() != pindexFork) {\n        if (!DisconnectTip(state, chainparams, &disconnectpool)) {\n            // This is likely a fatal error, but keep the mempool consistent,\n            // just in case. Only remove from the mempool in this case.\n            UpdateMempoolForReorg(disconnectpool, false);\n            return false;\n        }\n        fBlocksDisconnected = true;\n    }\n\n    // Build list of new blocks to connect.\n    std::vector<CBlockIndex*> vpindexToConnect;\n    bool fContinue = true;\n    int nHeight = pindexFork ? pindexFork->nHeight : -1;\n    while (fContinue && nHeight != pindexMostWork->nHeight) {\n        // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need\n        // a few blocks along the way.\n        int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight);\n        vpindexToConnect.clear();\n        vpindexToConnect.reserve(nTargetHeight - nHeight);\n        CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight);\n        while (pindexIter && pindexIter->nHeight != nHeight) {\n            vpindexToConnect.push_back(pindexIter);\n            pindexIter = pindexIter->pprev;\n        }\n        nHeight = nTargetHeight;\n\n        // Connect new blocks.\n        BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {\n            if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {\n                if (state.IsInvalid()) {\n                    // The block violates a consensus rule.\n                    if (!state.CorruptionPossible())\n                        InvalidChainFound(vpindexToConnect.back());\n                    state = CValidationState();\n                    fInvalidFound = true;\n                    fContinue = false;\n                    break;\n                } else {\n                    // A system error occurred (disk space, database error, ...).\n                    // Make the mempool consistent with the current tip, just in case\n                    // any observers try to use it before shutdown.\n                    UpdateMempoolForReorg(disconnectpool, false);\n                    return false;\n                }\n            } else {\n                PruneBlockIndexCandidates();\n                if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {\n                    // We're in a better position than we were. Return temporarily to release the lock.\n                    fContinue = false;\n                    break;\n                }\n            }\n        }\n    }\n\n    if (fBlocksDisconnected) {\n        // If any blocks were disconnected, disconnectpool may be non empty.  Add\n        // any disconnected transactions back to the mempool.\n        UpdateMempoolForReorg(disconnectpool, true);\n    }\n    mempool.check(pcoinsTip);\n\n    // Callbacks/notifications for a new best chain.\n    if (fInvalidFound)\n        CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());\n    else\n        CheckForkWarningConditions();\n\n    return true;\n}\n\n// Requires cs_main\nvoid DeactivatePartialSync()\n{\n    LogPrintf(\"Transition partial into full sync height = %d\\n\", chainActive.Height());\n\n    // clear partial chain => !IsPartialSyncActive()\n    partialChain.SetTip(nullptr);\n    partialChain.SetHeightOffset(0);\n    pindexBestPartial = nullptr;\n\n    // clear partial chain from blockindex (not can trigger partial sync on next session)\n    for (auto& it: mapBlockIndex) {\n        CBlockIndex* idx = it.second;\n        if (idx->IsPartialValid())\n        {\n            idx->nStatus &= ~BLOCK_PARTIAL_MASK;\n            setDirtyBlockIndex.insert(idx);\n        }\n    }\n\n    // notify and stop future notifications\n    headerTipSignal(nullptr);\n    headerTipSignal.disconnect_all_slots();\n\n    // clear mempool to avoid complexity of transitioning partial validated mempool entries\n    mempool.clear();\n}\n\n/**\n * Make the best chain active, in multiple steps. The result is either failure\n * or an activated best chain. pblock is either NULL or a pointer to a block\n * that is already loaded (to avoid loading it again from disk).\n */\nbool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {\n    // Note that while we're often called here from ProcessNewBlock, this is\n    // far from a guarantee. Things in the P2P/RPC will often end up calling\n    // us in the middle of ProcessNewBlock - do not assume pblock is set\n    // sanely for performance or correctness!\n\n    CBlockIndex *pindexMostWork = NULL;\n    CBlockIndex *pindexNewTip = NULL;\n    int nStopAtHeight = GetArg(\"-stopatheight\", DEFAULT_STOPATHEIGHT);\n    do {\n        boost::this_thread::interruption_point();\n        if (ShutdownRequested())\n            break;\n\n        const CBlockIndex *pindexFork;\n        bool fInitialDownload;\n        {\n            #ifdef ENABLE_WALLET\n            LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:NULL);\n            #else\n            LOCK(cs_main);\n            #endif\n\n            ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked\n\n            CBlockIndex *pindexOldTip = chainActive.Tip();\n            if (pindexMostWork == NULL) {\n                pindexMostWork = FindMostWorkChain();\n            }\n\n            // Munt - This is PoW2 related (unwitnessed blocks sit ahead of the chain tip with 0 extra chain work until they are activated).\n            if (pindexMostWork && pindexMostWork->pprev && pindexMostWork->nChainWork == pindexMostWork->pprev->nChainWork)\n                pindexMostWork = pindexMostWork->pprev;\n\n\n            // Whether we have anything to do at all.\n            if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())\n                return true;\n\n            bool fInvalidFound = false;\n            std::shared_ptr<const CBlock> nullBlockPtr;\n            if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHashPoW2() == pindexMostWork->GetBlockHashPoW2() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))\n                return false;\n\n            if (fInvalidFound) {\n                // Wipe cache, we may need another branch now.\n                pindexMostWork = NULL;\n            }\n            pindexNewTip = chainActive.Tip();\n            pindexFork = chainActive.FindFork(pindexOldTip);\n            fInitialDownload = IsInitialBlockDownload();\n\n            for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {\n                assert(trace.pblock && trace.pindex);\n                GetMainSignals().BlockConnected(trace.pblock, trace.pindex, *trace.conflictedTxs);\n            }\n        }\n        // When we reach this point, we switched to a new tip (stored in pindexNewTip).\n\n        if (IsPartialSyncActive() && isFullSyncMode() && chainActive.Height() >= partialChain.Height())\n            DeactivatePartialSync();\n\n        // Notifications/callbacks that can run without cs_main\n        // Notify external listeners about the new tip.\n        GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);\n\n        // Always notify the UI if a new block tip was connected\n        if (pindexFork != pindexNewTip) {\n            uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);\n        }\n\n        if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight)\n        {\n            LogPrintf(\"shutdown: triggering shutdown because ActivateBestChain reached stopatheight [%d]\", nStopAtHeight);\n            AppLifecycleManager::gApp->shutdown();\n        }\n    } while (pindexNewTip != pindexMostWork);\n    CheckBlockIndex(chainparams.GetConsensus());\n\n    // Write changes periodically to disk, after relay.\n    if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_PERIODIC)) {\n        return false;\n    }\n\n    return true;\n}\n\n\nbool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)\n{\n    {\n        LOCK(cs_main);\n        if (pindex->nChainWork < chainActive.Tip()->nChainWork) {\n            // Nothing to do, this block is not at the tip.\n            return true;\n        }\n        if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) {\n            // The chain has been extended since the last call, reset the counter.\n            nBlockReverseSequenceId = -1;\n        }\n        nLastPreciousChainwork = chainActive.Tip()->nChainWork;\n        setBlockIndexCandidates.erase(pindex);\n        pindex->nSequenceId = nBlockReverseSequenceId;\n        if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {\n            // We can't keep reducing the counter if somebody really wants to\n            // call preciousblock 2**31-1 times on the same set of tips...\n            nBlockReverseSequenceId--;\n        }\n        if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) {\n            if (!gbMinimalLogging)\n                LogPrintf(\"PreciousBlock: New index candidate: [%s] [%d]\\n\", pindex->GetBlockHashPoW2().ToString(), pindex->nHeight);\n            setBlockIndexCandidates.insert(pindex);\n            PruneBlockIndexCandidates();\n        }\n    }\n\n    return ActivateBestChain(state, params);\n}\n\nbool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)\n{\n    AssertLockHeld(cs_main);\n\n    // Mark the block itself as invalid.\n    pindex->nStatus |= BLOCK_FAILED_VALID;\n    setDirtyBlockIndex.insert(pindex);\n    setBlockIndexCandidates.erase(pindex);\n\n    if (chainActive.Contains(pindex))\n    {\n        DisconnectedBlockTransactions disconnectpool;\n        while (chainActive.Contains(pindex)) {\n            CBlockIndex *pindexWalk = chainActive.Tip();\n            pindexWalk->nStatus |= BLOCK_FAILED_CHILD;\n            setDirtyBlockIndex.insert(pindexWalk);\n            setBlockIndexCandidates.erase(pindexWalk);\n            // ActivateBestChain considers blocks already in chainActive\n            // unconditionally valid already, so force disconnect away from it.\n            if (!DisconnectTip(state, chainparams, &disconnectpool)) {\n                // It's probably hopeless to try to make the mempool consistent\n                // here if DisconnectTip failed, but we can try.\n                UpdateMempoolForReorg(disconnectpool, false);\n                return false;\n            }\n        }\n\n        // DisconnectTip will add transactions to disconnectpool; try to add these\n        // back to the mempool.\n        UpdateMempoolForReorg(disconnectpool, true);\n\n        // The resulting new best tip may not be in setBlockIndexCandidates anymore, so\n        // add it again.\n        BlockMap::iterator it = mapBlockIndex.begin();\n        while (it != mapBlockIndex.end()) {\n            if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {\n                setBlockIndexCandidates.insert(it->second);\n            }\n            it++;\n        }\n\n        InvalidChainFound(pindex);\n        uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);\n    }\n    else\n    {\n        InvalidChainFound(pindex);\n    }\n    return true;\n}\n\nbool ResetBlockFailureFlagsForSingleBlock(CBlockIndex *pindex) {\n    AssertLockHeld(cs_main);\n\n    pindex->nStatus &= ~BLOCK_FAILED_MASK;\n    setDirtyBlockIndex.insert(pindex);\n    if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), pindex))\n    {\n        setBlockIndexCandidates.insert(pindex);\n    }\n    if (pindex == pindexBestInvalid)\n    {\n        // Reset invalid block marker if it was pointing to one of those.\n        pindexBestInvalid = NULL;\n    }\n    return true;\n}\n\nbool ResetBlockFailureFlags(CBlockIndex *pindex) {\n    AssertLockHeld(cs_main);\n\n    int nHeight = pindex->nHeight;\n\n    // Remove the invalidity flag from this block and all its descendants.\n    BlockMap::iterator it = mapBlockIndex.begin();\n    while (it != mapBlockIndex.end()) {\n        if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {\n            it->second->nStatus &= ~BLOCK_FAILED_MASK;\n            setDirtyBlockIndex.insert(it->second);\n            if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {\n                setBlockIndexCandidates.insert(it->second);\n            }\n            if (it->second == pindexBestInvalid) {\n                // Reset invalid block marker if it was pointing to one of those.\n                pindexBestInvalid = NULL;\n            }\n        }\n        it++;\n    }\n\n    // Remove the invalidity flag from all ancestors too.\n    while (pindex != NULL) {\n        if (pindex->nStatus & BLOCK_FAILED_MASK) {\n            pindex->nStatus &= ~BLOCK_FAILED_MASK;\n            setDirtyBlockIndex.insert(pindex);\n        }\n        pindex = pindex->pprev;\n    }\n    return true;\n}\n\nstatic arith_uint256 CalculateChainWork(const CBlockIndex* pIndex, const CChainParams& chainparams)\n{\n    LOCK(cs_main);\n\n    arith_uint256 nBlockProof = GetBlockProof(*pIndex);\n    arith_uint256 chainWork = (pIndex->pprev ? pIndex->pprev->nChainWork : 0) + nBlockProof;\n    if (pIndex->nVersionPoW2Witness != 0 && pIndex->pprev)\n    {\n        // Note: (PoW2) If we wanted to include witness weight in the chain weight this would be the place to do it.\n        // This would have the benefit of making it harder to mine a side chain using lots of small witnesses.\n        // However it would also bias the earnings and chain control even more to large witnesses and act as a 'centralisation' incentive.\n        // So at this point we don't do this - and prefer instead to be witness-size-agnostic, so we increase witnessed blocks always by a fixed weight.\n        if (pIndex->pprev->nVersionPoW2Witness != 0)\n        {\n            // Witnessed blocks sit ahead of non-witnessed blocks in the chain so must have more work than our non-witnessed counterpart.\n            // However this is more complicated than it would seem at first.\n            // If we increase the work by some arbitrary amount e.g. 1 or 10000 then we sit with the following problem:\n            // 1) Miner mines a block at high difficulty. 2) Witness is 'absent'. 3) Chain temporarily stalls.\n            // 4) Miners start mining competing blocks at lower difficulty (delta difficulty halving).\n            // 5) Witnesses witness the lower difficulty block\n            // 6) However because they are substantially lower difficulty - nBlockProof + 1 is not enough to put the new block at tip of chain\n            // 7) It takes multiple lower difficulty blocks to form a new chain tip and for chain to progress (chain stalls unacceptably long)\n            // If we base it on the current block weight (e.g. 2x current weight) then we face the opposite - i.e. an attacker can hold back a high difficulty witnessed block and then orphan a bunch of lower difficulty blocks using it.\n            // If we base it on the weight of a previous block (some arbitrary distance backwards) then we fix the above some of the time, however with careful timing the possibility to manipulate is still there.\n            // So instead we base it on the average of the last 10 blocks inclusive of the current, this provides sufficient protection from fluctuations.\n            int nCount = 1;\n            CBlockIndex* pprev = pIndex->pprev;\n            while (pprev && nCount < 10)\n            {\n                ++nCount;\n                nBlockProof += GetBlockProof(*pprev);\n                pprev = pprev->pprev;\n            }\n            if (!fSPV)\n            {\n                assert (pIndex->nHeight < 11 || nCount == 10);\n            }\n            nBlockProof /= nCount;\n            chainWork += nBlockProof;\n        }\n    }\n    return chainWork;\n}\n\nstatic CBlockIndex* AddToBlockIndex(const CChainParams& chainParams, const CBlockHeader& block)\n{\n    // Check for duplicate\n    uint256 hash = block.GetHashPoW2();\n    BlockMap::iterator it = mapBlockIndex.find(hash);\n    if (it != mapBlockIndex.end())\n        return it->second;\n\n    // Construct new block index object\n    CBlockIndex* pindexNew = new CBlockIndex(block);\n    assert(pindexNew);\n    // We assign the sequence id to blocks only when the full data is available,\n    // to avoid miners withholding blocks but broadcasting headers, to get a\n    // competitive advantage.\n    pindexNew->nSequenceId = 0;\n    BlockMap::iterator mi = mapBlockIndex.insert(std::pair(hash, pindexNew)).first;\n    pindexNew->phashBlock = &((*mi).first);\n    BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);\n    if (miPrev != mapBlockIndex.end())\n    {\n        pindexNew->pprev = (*miPrev).second;\n        pindexNew->nHeight = pindexNew->pprev->nHeight + 1;\n        // Skip list can only be build for full chain\n        if (pindexNew->pprev->pskip || pindexNew->pprev->nHeight == 0)\n            pindexNew->BuildSkip();\n    }\n    pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);\n\n    // we're only called for blocks that have the header verified (or Genenis)\n    pindexNew->RaiseValidity(BLOCK_VALID_HEADER);\n\n    pindexNew->nChainWork = CalculateChainWork(pindexNew, chainParams);\n    if (isFullSyncMode() && ((pindexNew->nHeight > 0 && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) || pindexNew->nHeight == 0))\n    {\n        // block is extending the main tree\n        if (pindexNew->nChainTx && (pindexNew->nChainWork >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nChainWork) || pindexNew->nHeight >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nHeight)))\n        {\n            if (!gbMinimalLogging || (pindexNew->nHeight%10000==0))\n                LogPrintf(\"AddToBlockIndex: New index candidate: [%s] [%d]\\n\", pindexNew->GetBlockHashPoW2().ToString(), pindexNew->nHeight);\n            setBlockIndexCandidates.insert(pindexNew);\n        }\n        pindexNew->RaiseValidity(BLOCK_VALID_TREE);\n        if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)\n            pindexBestHeader = pindexNew;\n    }\n\n    if (IsPartialSyncActive() && pindexNew->nHeight > 0 && pindexNew->pprev->IsPartialValid(BLOCK_PARTIAL_TREE))\n    {\n        // block is not extending main tree, so it's extending the partial tree\n        pindexNew->RaisePartialValidity(BLOCK_PARTIAL_TREE);\n    }\n\n    if (IsPartialSyncActive() && (pindexBestPartial == nullptr || pindexBestPartial->nChainWork < pindexNew->nChainWork))\n    {\n        if (pindexNew->nHeight > partialChain.HeightOffset())\n        {\n            pindexBestPartial = pindexNew;\n            partialChain.SetTip(pindexBestPartial);\n        }\n    }\n\n    setDirtyBlockIndex.insert(pindexNew);\n\n    return pindexNew;\n}\n\n/** Promote a blockindex in the partial tree to the full tree, connecting it if needed */\nstatic bool PromoteBlockIndex(CBlockIndex* pindexNew, const CBlockHeader& header, CBlockIndex* pindexPrev)\n{\n    if (!pindexPrev->IsValid(BLOCK_VALID_TREE))\n        return false;\n\n    // Partial block might not have been fully initalized if it was constructed from a checkpoint, do so here\n    pindexNew->nVersionPoW2Witness = header.nVersionPoW2Witness;\n    pindexNew->nTimePoW2Witness = header.nTimePoW2Witness;\n    pindexNew->hashMerkleRootPoW2Witness = header.hashMerkleRootPoW2Witness;\n    pindexNew->witnessHeaderPoW2Sig = header.witnessHeaderPoW2Sig;\n    pindexNew->witnessUTXODelta = header.witnessUTXODelta;\n    pindexNew->nVersion       = header.nVersion;\n    pindexNew->hashMerkleRoot = header.hashMerkleRoot;\n    pindexNew->nTime          = header.nTime;\n    pindexNew->nBits          = header.nBits;\n    pindexNew->nNonce         = header.nNonce;\n\n    pindexNew->pprev = pindexPrev;\n    pindexNew->nHeight = pindexNew->pprev->nHeight + 1;\n    pindexNew->BuildSkip();\n    pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);\n\n    arith_uint256 chainWork = CalculateChainWork(pindexNew, Params());\n    if (pindexNew->nChainTx && (pindexNew->nChainWork >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nChainWork) || pindexNew->nHeight >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nHeight)))\n    {\n        if (!gbMinimalLogging)\n            LogPrintf(\"PromoteBlockIndex: new/updated index candidate: [%s] [%d]\\n\", pindexNew->GetBlockHashPoW2().ToString(), pindexNew->nHeight);\n        setBlockIndexCandidates.erase(pindexNew);\n        pindexNew->nChainWork = chainWork;\n        setBlockIndexCandidates.insert(pindexNew);\n    }\n    else\n    {\n        pindexNew->nChainWork = chainWork;\n    }\n\n    pindexNew->RaiseValidity(BLOCK_VALID_TREE);\n    if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)\n        pindexBestHeader = pindexNew;\n\n    setDirtyBlockIndex.insert(pindexNew);\n\n    return true;\n}\n\n/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS or BLOCK_PARTIAL_TRANSACTIONS). */\nstatic bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)\n{\n    pindexNew->nTx = block.vtx.size();\n    pindexNew->nChainTx = 0;\n    pindexNew->nFile = pos.nFile;\n    pindexNew->nDataPos = pos.nPos;\n    pindexNew->nUndoPos = 0;\n    pindexNew->nStatus |= BLOCK_HAVE_DATA;\n    if (IsSegSigEnabled(pindexNew->pprev)) {\n        pindexNew->nStatus |= BLOCK_OPT_WITNESS;\n    }\n\n    if (pindexNew->nHeight == 0 || (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)))\n    {\n        pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);\n        setDirtyBlockIndex.insert(pindexNew);\n    }\n    else if (pindexNew->pprev && pindexNew->pprev->IsPartialValid(BLOCK_PARTIAL_TREE)) {\n        pindexNew->RaisePartialValidity(BLOCK_PARTIAL_TRANSACTIONS);\n        setDirtyBlockIndex.insert(pindexNew);\n    }\n    else\n        return false;\n\n    if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) {\n        // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS.\n        std::deque<CBlockIndex*> queue;\n        queue.push_back(pindexNew);\n\n        LOCK(cs_main);\n        // Recursively process any descendant blocks that now may be eligible to be connected.\n        while (!queue.empty()) {\n            CBlockIndex *pindex = queue.front();\n            queue.pop_front();\n            pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;\n            {\n                LOCK(cs_nBlockSequenceId);\n                setBlockIndexCandidates.erase(pindex);\n                pindex->nSequenceId = nBlockSequenceId++;\n            }\n            if (pindex->nChainWork >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nChainWork) || pindex->nHeight >= (chainActive.Tip() == NULL ? 0 : chainActive.Tip()->nHeight))\n            {\n                if (!gbMinimalLogging || (pindexNew->nHeight%10000==0))\n                    LogPrintf(\"ReceivedBlockTransactions: New index candidate: [%s] [%d]\\n\", pindex->GetBlockHashPoW2().ToString(), pindex->nHeight);\n                setBlockIndexCandidates.insert(pindex);\n            }\n            std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);\n            while (range.first != range.second) {\n                std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first;\n                queue.push_back(it->second);\n                range.first++;\n                mapBlocksUnlinked.erase(it);\n            }\n        }\n    } else {\n        if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) {\n            mapBlocksUnlinked.insert(std::pair(pindexNew->pprev, pindexNew));\n        }\n    }\n\n    return true;\n}\n\nstatic bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)\n{\n    LOCK(cs_LastBlockFile);\n\n    unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile;\n    if (vinfoBlockFile.size() <= nFile) {\n        vinfoBlockFile.resize(nFile + 1);\n    }\n\n    if (!fKnown) {\n        while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {\n            nFile++;\n            if (vinfoBlockFile.size() <= nFile) {\n                vinfoBlockFile.resize(nFile + 1);\n            }\n        }\n        pos.nFile = nFile;\n        pos.nPos = vinfoBlockFile[nFile].nSize;\n    }\n\n    if ((int)nFile != nLastBlockFile) {\n        if (!fKnown) {\n            LogPrintf(\"Leaving block file %i: %s\\n\", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());\n        }\n        FlushBlockFile(!fKnown);\n        nLastBlockFile = nFile;\n    }\n\n    vinfoBlockFile[nFile].AddBlock(nHeight, nTime);\n    if (fKnown)\n        vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize);\n    else\n        vinfoBlockFile[nFile].nSize += nAddSize;\n\n    if (!fKnown) {\n        unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;\n        unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;\n        if (nNewChunks > nOldChunks) {\n            if (fPruneMode)\n                fCheckForPruning = true;\n            if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) {\n                FILE *file = blockStore.GetBlockFile(pos);\n                if (file) {\n                    LogPrintf(\"Pre-allocating up to position 0x%x in blk%05u.dat\\n\", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);\n                    AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);\n                }\n            }\n            else\n                return state.Error(\"out of disk space\");\n        }\n    }\n\n    setDirtyFileInfo.insert(nFile);\n    return true;\n}\n\nstatic bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize)\n{\n    pos.nFile = nFile;\n\n    LOCK(cs_LastBlockFile);\n\n    unsigned int nNewSize;\n    pos.nPos = vinfoBlockFile[nFile].nUndoSize;\n    nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize;\n    setDirtyFileInfo.insert(nFile);\n\n    unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;\n    unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;\n    if (nNewChunks > nOldChunks) {\n        if (fPruneMode)\n            fCheckForPruning = true;\n        if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) {\n            FILE *file = blockStore.GetUndoFile(pos);\n            if (file) {\n                LogPrintf(\"Pre-allocating up to position 0x%x in rev%05u.dat\\n\", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);\n                AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);\n            }\n        }\n        else\n            return state.Error(\"out of disk space\");\n    }\n\n    return true;\n}\n\nstatic bool CheckBlockHeader(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)\n{\n    // Check proof of work matches claimed amount\n    if (fCheckPOW) {\n        uint256 blockHash = block.GetHashLegacy();\n        \n        //fixme: (PHASE5) We can probably remove this after phase4\n        //Avoid unnecessary extra checkpow computation on witness blocks as they contain the exact same pow as their non-witness counterparts.\n        if (checkedPoWCache.contains(blockHash))\n            return checkedPoWCache.get(blockHash);\n\n        //fixme: (HIGH) (SYNC) (SPV)\n        //Temporary performance boost (at the cost of possible bandwidth attacks) until we can implement witness based syncing\n        if (fSPV)\n        {\n            LOCK(cs_main);\n            const auto& prevIndex = mapBlockIndex.find(block.hashPrevBlock);\n            if (prevIndex != mapBlockIndex.end())\n            {\n                if (prevIndex->second->nHeight+1 < Checkpoints::LastCheckPointHeight())\n                {\n                    checkedPoWCache.insert(blockHash, true);\n                    return true;\n                }\n            }\n        }\n\n        // Nested if statement for easier breakpoint management\n        if (!CheckProofOfWork(&block, consensusParams))\n        {\n            checkedPoWCache.insert(blockHash, false);\n            return state.DoS(50, false, REJECT_INVALID, \"high-hash\", false, \"proof of work failed\");\n        }\n        \n        checkedPoWCache.insert(blockHash, true);\n    }\n    \n    return true;\n}\n\nbool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fAssumePOWGood)\n{\n    // These are checks that are independent of context.\n\n    if (block.fChecked)\n        return true;\n\n    // Check that the header is valid (particularly PoW).  This is mostly\n    // redundant with the call in AcceptBlockHeader.\n    if (fCheckPOW)\n    {\n        if (!CheckBlockHeader(block, state, consensusParams, !fAssumePOWGood && !block.fPOWChecked))\n            return false;\n        else\n            block.fPOWChecked = true;\n    }\n\n    // All potential-corruption validation must be done before we do any\n    // transaction validation, as otherwise we may mark the header as invalid\n    // because we receive the wrong transactions for it.\n    // Note that witness malleability is checked in ContextualCheckBlock, so no\n    // checks that use witness data may be performed here.\n\n    // Size limits\n    if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_BASE_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_SEGREGATED_SIGNATURES) > MAX_BLOCK_BASE_SIZE)\n        return state.DoS(100, false, REJECT_INVALID, \"bad-blk-length\", false, \"size limits failed\");\n\n    // First transaction must be coinbase, the rest must not be\n    if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())\n        return state.DoS(100, false, REJECT_INVALID, \"bad-cb-missing\", false, \"first tx is not coinbase\");\n\n    // Witness block has two coinbases\n    unsigned int nWitnessCoinbaseIndex = 0;\n    if (block.nVersionPoW2Witness != 0)\n    {\n        for (unsigned int i = 1; i < block.vtx.size(); i++)\n        {\n            if (block.vtx[i]->IsCoinBase() && block.vtx[i]->IsPoW2WitnessCoinBase())\n            {\n                nWitnessCoinbaseIndex = i;\n            }\n        }\n    }\n\n    // Extra coinbase (invalid)\n    for (unsigned int i = (nWitnessCoinbaseIndex == 0 ? 1 : nWitnessCoinbaseIndex+1); i < block.vtx.size(); i++)\n    {\n        if (block.vtx[i]->IsCoinBase())\n            return state.DoS(100, false, REJECT_INVALID, \"bad-cb-multiple\", false, \"block contains excess coinbase transactions\");\n    }\n\n    // Check the merkle root.\n    if (fCheckMerkleRoot)\n    {\n        bool mutated;\n        uint256 hashMerkleRoot2 = BlockMerkleRoot(block.vtx.begin(), (nWitnessCoinbaseIndex == 0 ? block.vtx.end() : block.vtx.begin()+nWitnessCoinbaseIndex), &mutated);\n        if (block.hashMerkleRoot != hashMerkleRoot2)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txnmrklroot\", true, \"hashMerkleRoot mismatch\");\n\n        // Check for merkle tree malleability (CVE-2012-2459): repeating sequences\n        // of transactions in a block without affecting the merkle root of a block,\n        // while still invalidating it.\n        if (mutated)\n            return state.DoS(100, false, REJECT_INVALID, \"bad-txns-duplicate\", true, \"duplicate transaction\");\n\n        if (block.nVersionPoW2Witness != 0)\n        {\n            uint256 hashMerkleRoot3 = BlockMerkleRoot(block.vtx.begin()+nWitnessCoinbaseIndex, block.vtx.end(), &mutated);\n            if (block.hashMerkleRootPoW2Witness != hashMerkleRoot3)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txnmrklroot\", true, \"pow2 witness hashMerkleRoot mismatch\");\n\n            // Check for merkle tree malleability (CVE-2012-2459): repeating sequences\n            // of transactions in a block without affecting the merkle root of a block,\n            // while still invalidating it.\n            if (mutated)\n                return state.DoS(100, false, REJECT_INVALID, \"bad-txns-duplicate\", true, \"witness duplicate transaction\");\n        }\n    }\n\n    // Check transactions\n    for (const auto& tx : block.vtx)\n    {\n        if (!CheckTransaction(*tx, state, true))\n            return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),\n                                 strprintf(\"Transaction check failed (tx hash %s) %s\", tx->GetHash().ToString(), state.GetDebugMessage()));\n    }\n\n    unsigned int nSigOps = 0;\n    for (const auto& tx : block.vtx)\n    {\n        nSigOps += GetLegacySigOpCount(*tx);\n    }\n    if (nSigOps > MAX_BLOCK_SIGOPS_COST)\n        return state.DoS(100, false, REJECT_INVALID, \"bad-blk-sigops\", false, \"out-of-bounds SigOpCount\");\n\n    if (fCheckPOW && fCheckMerkleRoot)\n        block.fChecked = true;\n\n    return true;\n}\n\nstatic bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)\n{\n    if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)\n        return true;\n\n    int nHeight = pindexPrev->nHeight+1;\n    \n    // Don't accept any forks from the main chain prior to last checkpoint.\n    // GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our\n    // MapBlockIndex.\n    CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpointIndex();\n    if (pcheckpoint && nHeight < pcheckpoint->nHeight)\n        return state.DoS(100, error(\"%s: forked chain older than last checkpoint (height %d)\", __func__, nHeight), REJECT_CHECKPOINT, \"bad-fork-prior-to-checkpoint\");\n\n    return true;\n}\n\n// We go for a cheap check here, instead of checking for phase 4 (which can be expensive and lead to problems) \n// We instead just check if the previous block is a witness block (if it is we are in phase 4 as this isn't allowed in other phases.\nbool IsSegSigEnabled(const CBlockIndex* pindexPrev)\n{\n    LOCK(cs_main);\n    if (!pindexPrev)\n        return false;\n    if (pindexPrev->nVersionPoW2Witness != 0)\n        return true;\n    return false;\n}\n\n\nbool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)\n{\n    assert(pindexPrev != NULL);\n    \n    bool fTestNet = Params().IsTestnet();\n\n    //const int nHeight = pindexPrev->nHeight + 1;\n    // Check proof of work\n    if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))\n        return state.DoS(100, false, REJECT_INVALID, \"bad-diffbits\", false, \"incorrect proof of work\");\n\n    // Check timestamp against prev\n    if (block.GetBlockTime() <= pindexPrev->GetMedianTimePastWitness())\n        return state.Invalid(false, REJECT_INVALID, \"time-too-old\", \"blocks PoW timestamp is too early\");\n\n    // Check timestamp\n    if (pindexPrev->nHeight > (fTestNet ? 446500 : 437500) )\n    {\n        if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)\n            return state.Invalid(false, REJECT_INVALID, \"time-too-new\", \"block timestamp too far in the future\");\n    }\n    else\n    {\n        if (block.GetBlockTime() > nAdjustedTime + 15 * 60)\n            return state.Invalid(false, REJECT_INVALID, \"time-too-new\", \"block timestamp too far in the future\");\n    }\n\n    if (block.nVersionPoW2Witness != 0)\n    {\n        if (block.nTimePoW2Witness <= pindexPrev->GetMedianTimePastPoW())\n        {\n            return state.Invalid(false, REJECT_INVALID, \"time-too-old\", \"blocks witness timestamp is too early\");\n        }\n        if (block.hashMerkleRootPoW2Witness == uint256())\n        {\n            return state.Invalid(false, REJECT_INVALID, \"witness-merkle-invalid\", \"block sets null witness merkle root\");\n        }\n        if ( std::all_of(block.witnessHeaderPoW2Sig.begin(), block.witnessHeaderPoW2Sig.end(), [](auto c){return c==0;}) )\n        {\n            return state.Invalid(false, REJECT_INVALID, \"witness-signature-invalid\", \"block sets null witness signature\");\n        }\n        if ((int64_t)pindexPrev->nHeight > (int64_t)Params().GetConsensus().pow2WitnessSyncHeight)\n        {\n            if (block.witnessUTXODelta.size() == 0)\n            {\n                return state.Invalid(false, REJECT_INVALID, \"witness-utxo-delta-invalid\", \"block has no witness utxo delta\");\n            }\n        }\n    }\n    else\n    {\n        if (block.nTimePoW2Witness != 0)\n        {\n            return state.Invalid(false, REJECT_INVALID, \"time-invalid\", \"block sets witness time without witness version\");\n        }\n        if (block.hashMerkleRootPoW2Witness != uint256())\n        {\n            return state.Invalid(false, REJECT_INVALID, \"witness-merkle-invalid\", \"block sets witness merkle root without witness version\");\n        }\n        if ( !std::all_of(block.witnessHeaderPoW2Sig.begin(), block.witnessHeaderPoW2Sig.end(), [](auto c){return c==0;}) )\n        {\n            return state.Invalid(false, REJECT_INVALID, \"witness-signature-invalid\", \"block sets witness signature without witness version\");\n        }\n        if (block.witnessUTXODelta.size() > 0)\n        {\n            return state.Invalid(false, REJECT_INVALID, \"witness-utxo-delta-invalid\", \"block sets witness utxo delta without witness version\");\n        }\n    }    \n\n    return true;\n}\n\n//fixme: (PHASE5) Do away with this doUTXOChecks junk\n//Long story short; we need to call this twice, the second time from within ConnectTip as we can't do the 'phase' checks without the utxo\n//After phase4 activation we won't need the phase checks so we can code this properly.\nbool ContextualCheckBlock(const CBlock& block, CValidationState& state, const CChainParams& chainParams, const CBlockIndex* pindexPrev, CChain& chainOverride, CCoinsViewCache* viewOverride, bool doUTXOChecks)\n{\n    bool haveSegregatedSignatures = IsSegSigEnabled(pindexPrev);\n    \n    const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;\n\n    // Start enforcing BIP113 (Median Time Past) using versionbits logic.\n    int nLockTimeFlags = 0;\n    if (VersionBitsState(pindexPrev, chainParams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE)\n    {\n        nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;\n    }\n\n    int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST)\n                              ? pindexPrev->GetMedianTimePast()\n                              : block.GetBlockTime();\n\n    // Check that all transactions are finalized\n    for (const auto& tx : block.vtx)\n    {\n        if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff))\n        {\n            return state.DoS(10, false, REJECT_INVALID, \"bad-txns-nonfinal\", false, \"non-final transaction\");\n        }\n    }\n\n    // Check that no transactions (from phase2 onward) have transaction version above 4 - this behaviour is no longer allowed\n    if (doUTXOChecks && haveSegregatedSignatures)\n    {\n        for (const auto& tx : block.vtx)\n        {\n            if (tx->nVersion > CTransaction::MAX_STANDARD_VERSION)\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-transaction-version\", false, \"non-standard transaction versions above are no longer permitted.\");\n            }\n        }\n    }\n\n    // Check that no transactions (from phase4 onward) contain a scriptSig - scriptSig is completely deprecated.\n    if (haveSegregatedSignatures)\n    {\n        for (const auto& tx : block.vtx)\n        {\n            for (const auto& txIn : tx->vin)\n            {\n                (unused)txIn;\n                if (IsOldTransactionVersion(tx->nVersion))\n                {\n                    return state.DoS(100, false, REJECT_INVALID, \"bad-transaction-version\", false, \"mining non-segsig version transactions after activation is forbidden\");\n                }\n                if (txIn.scriptSig.size() > 0)\n                {\n                    return state.DoS(100, false, REJECT_INVALID, \"bad-segsig-txin\", false, \"segsig blocks may not contain scriptSig which has been deprecated\");\n                }\n            }\n        }\n    }\n\n    // Enforce rule that the PoW coinbase starts with serialized block height\n    if (nHeight >= chainParams.GetConsensus().BIP34Height)\n    {\n        if (haveSegregatedSignatures)\n        {\n            std::vector<unsigned char> expect;\n            CVectorWriter(0, 0, expect, 0) << VARINT(nHeight);\n            if (block.vtx[0]->vin[0].segregatedSignatureData.stack.empty() || !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].segregatedSignatureData.stack[0].begin()))\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-cb-height\", false, \"block height mismatch in coinbase\");\n            }\n        }\n    }\n    \n    // And the same for witness coinbase. (Enforce rule that the coinbase starts with serialized block height)\n    if (nHeight!= 0 && block.nVersionPoW2Witness != 0)\n    {\n        unsigned int nWitnessCoinbaseIndex = 0;\n        for (unsigned int i = 1; i < block.vtx.size(); i++)\n        {\n            if (block.vtx[i]->IsCoinBase() && block.vtx[i]->IsPoW2WitnessCoinBase())\n            {\n                nWitnessCoinbaseIndex = i;\n                break;\n            }\n        }\n        //fixme: (PHASE5) Pretty sure this is a duplicate check - so we should eventually remove it, for now we just leave it in.\n        if (nWitnessCoinbaseIndex == 0)\n        {\n            return state.DoS(100, error(\"ContextualCheckBlock(): PoW2 witness coinbase missing)\"), REJECT_INVALID, \"bad-witness-cb\");\n        }\n        if (haveSegregatedSignatures)\n        {\n            std::vector<unsigned char> expect;\n            CVectorWriter(0, 0, expect, 0) << VARINT(nHeight);\n            if (block.vtx[nWitnessCoinbaseIndex]->vin[0].segregatedSignatureData.stack.empty() || !std::equal(expect.begin(), expect.end(), block.vtx[nWitnessCoinbaseIndex]->vin[0].segregatedSignatureData.stack[0].begin()))\n            {\n                return state.DoS(100, false, REJECT_INVALID, \"bad-cb-height\", false, \"block height mismatch in witness coinbase\");\n            }\n        }\n    }\n\n    //NB!! MUNT - segwit commits/adds a coinbase commitment here.\n    //For segsig this is unnecessary; we hash this data as part of the normal merkle root instead.\n\n    //fixme: (PHASE5) Below checks can be removed/simplified\n    // No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam\n    if (haveSegregatedSignatures)\n    {\n        for (const auto& tx : block.vtx)\n        {\n            if (!tx->HasSegregatedSignatures())\n                return state.DoS(100, false, REJECT_INVALID, \"missing-segregated-signature\", true, strprintf(\"%s : missing segregated signature data found\", __func__));\n        }\n    }\n\n    // After the coinbase witness nonce and commitment are verified,\n    // we can check if the block weight passes (before we've checked the\n    // coinbase witness, it would be possible for the weight to be too\n    // large by filling up the coinbase witness, which doesn't change\n    // the block hash, so we couldn't mark the block as permanently\n    // failed).\n    if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT)\n    {\n        return state.DoS(100, false, REJECT_INVALID, \"bad-blk-weight\", false, strprintf(\"%s : weight limit failed\", __func__));\n    }\n\n    return true;\n}\n\nstatic bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fAssumePOWGood = false)\n{\n    AssertLockHeld(cs_main);\n\n    //fixme: (PHASE5) Double check handling of different header types.\n\n    CBlockIndex* pindexPrev = nullptr;\n    bool promoteToFullTree = false;\n\n    // Check for duplicate\n    uint256 hash = block.GetHashPoW2();\n    BlockMap::iterator miSelf = mapBlockIndex.find(hash);\n    CBlockIndex *pindex = NULL;\n    if (hash != chainparams.GetConsensus().hashGenesisBlock) {\n\n        if (miSelf != mapBlockIndex.end()) {\n            // Block header is already known.\n            pindex = miSelf->second;\n            if (ppindex)\n                *ppindex = pindex;\n            if (pindex->nStatus & BLOCK_FAILED_MASK)\n                return state.Invalid(error(\"%s: block %s is marked invalid\", __func__, hash.ToString()), 0, \"duplicate\");\n            if (!pindex->IsValid(BLOCK_VALID_TREE) && pindex->IsPartialValid(BLOCK_PARTIAL_TREE))\n            {\n                // check if the block can be promoted to the full tree\n                if (pindex->pprev)\n                    pindexPrev = pindex->pprev;\n                else\n                {\n                    const auto prevIt = mapBlockIndex.find(block.hashPrevBlock);\n                    if (prevIt != mapBlockIndex.end())\n                        pindexPrev = prevIt->second;\n                }\n                promoteToFullTree = pindexPrev && pindexPrev->IsValid(BLOCK_VALID_TREE);\n            }\n            else\n                return true;\n        }\n\n        // Get prev block index if we don't have it yet\n        if (!pindexPrev)\n        {\n            BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);\n            if (mi == mapBlockIndex.end())\n                return state.DoS(10, error(\"%s: prev block not found\", __func__), 0, \"prev-blk-not-found\");\n            pindexPrev = (*mi).second;\n        }\n\n        //fixme: (UNITY) (SPV) - Reconsider this when/if we have partial filtered header sync functional.\n        //On SPV (Android) for instance these scrypt checks on the headers are really expensive.\n        //We bypass this with a small random chance of still checking.\n        //NB! Previously this was before the pindexPrev call - it is fine for it to be after, however if we alter this further consider putting it before again.\n        //\n        //Note:\n        // 1) This check gets called again (and not skipped) for any actual blocks we fetch from within CheckBlock()\n        // 2) An attacker would still have to meet/break/forge the sha ppev hash checks for an entire chain from the checkpoints\n        // 3) We still check randomly\n        // This is enough to ensure that an attacker would have to go to great lengths for what would amount to a minor nuisance (having to refetch some more headers after detecting wrong chain)\n        // So this is not really a major weakening of security in any way and still more than sufficient.\n        if (!fAssumePOWGood && IsPartialSyncActive() && pindexPrev->nHeight < Checkpoints::LastCheckPointHeight() && (GetRandInt(400) != 10))\n            fAssumePOWGood = true;\n\n        // CheckBlockHeader can take long so temporarily relinquish the lock to avoid freezing the UI\n        LEAVE_CRITICAL_SECTION(cs_main);\n        bool blockHeaderIsValid = CheckBlockHeader(block, state, chainparams.GetConsensus(), !fAssumePOWGood);\n        ENTER_CRITICAL_SECTION(cs_main);\n        if (!blockHeaderIsValid)\n            return error(\"%s: Consensus::CheckBlockHeader: %s, %s\", __func__, hash.ToString(), FormatStateMessage(state));\n\n        if (pindexPrev->nStatus & BLOCK_FAILED_MASK)\n            return state.DoS(100, error(\"%s: prev block invalid\", __func__), REJECT_INVALID, \"bad-prevblk\");\n\n        assert(pindexPrev);\n        if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))\n            return error(\"%s: CheckIndexAgainstCheckpoint(): %s, %s\", __func__, hash.ToString(), state.GetRejectReason().c_str());\n\n        // do context check if block header connects to the full tree or when we have at least the required amount of partial tree available\n        bool doContextCheck = pindexPrev->IsValid(BLOCK_VALID_TREE) || ((pindexPrev->IsPartialValid(BLOCK_PARTIAL_TREE)) && pindexPrev->nHeight - partialChain.HeightOffset() > 576);\n        if (doContextCheck && !ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev, GetAdjustedTime()))\n            return error(\"%s: Consensus::ContextualCheckBlockHeader: %s, %s\", __func__, hash.ToString(), FormatStateMessage(state));\n    }\n\n    if (promoteToFullTree)\n        PromoteBlockIndex(pindex, block, pindexPrev);\n    else if (pindex == nullptr)\n        pindex = AddToBlockIndex(chainparams, block);\n\n    if (ppindex)\n        *ppindex = pindex;\n\n    CheckBlockIndex(chainparams.GetConsensus());\n\n    return true;\n}\n\nstatic void CheckAndNotifyHeaderTip()\n{\n    if (!IsPartialSyncActive())\n        return;\n\n    static const CBlockIndex* pPreviousHeaderTip = nullptr;\n    bool fNotify = false;\n    {\n        LOCK(cs_main);\n        if (partialChain.Tip() != pPreviousHeaderTip) {\n            fNotify = true;\n            pPreviousHeaderTip = partialChain.Tip();\n        }\n    }\n    if (fNotify)\n        headerTipSignal(pPreviousHeaderTip);\n}\n\n// Exposed wrapper for AcceptBlockHeader\nbool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, bool fAssumePOWGood)\n{\n    {\n        LOCK(cs_main);\n        for (const CBlockHeader& header : headers) {\n            CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast\n            if (!AcceptBlockHeader(header, state, chainparams, &pindex, fAssumePOWGood)) {\n                return false;\n            }\n            if (ppindex) {\n                *ppindex = pindex;\n            }\n        }\n    }\n\n    CheckAndNotifyHeaderTip();\n\n    if (IsPartialSyncActive() && !isFullSyncMode())\n        PersistAndPruneForPartialSync(true);\n\n    return true;\n}\n\n/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */\nstatic bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock, bool fAssumePOWGood, bool checkFarAhead)\n{\n    const CBlock& block = *pblock;\n\n    if (fNewBlock) *fNewBlock = false;\n    AssertLockHeld(cs_main);\n\n    CBlockIndex *pindexDummy = NULL;\n    CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;\n\n    if (!AcceptBlockHeader(block, state, chainparams, &pindex, fAssumePOWGood))\n        return false;\n\n    // Try to process all requested blocks that we don't have, but only\n    // process an unrequested block if it's new and has enough work to\n    // advance our tip, and isn't too many blocks ahead.\n    bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;\n    bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);\n    // Blocks that are too out-of-order needlessly limit the effectiveness of\n    // pruning, because pruning will not delete block files that contain any\n    // blocks which are too close in height to the tip.  Apply this test\n    // regardless of whether pruning is enabled; it should generally be safe to\n    // not process unrequested blocks.\n    bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));\n\n    // TODO: Decouple this function from the block download logic by removing fRequested\n    // This requires some new chain data structure to efficiently look up if a\n    // block is in a chain leading to a candidate for best tip, despite not\n    // being such a candidate itself.\n\n    // TODO: deal better with return value and error conditions for duplicate\n    // and unrequested blocks.\n    if (fAlreadyHave) return true;\n    if (!fRequested) {  // If we didn't ask for it:\n        if (pindex->nTx != 0) return true;  // This is a previously-processed block that was pruned\n        if (!fHasMoreWork) return true;     // Don't process less-work chains\n        if (checkFarAhead && fTooFarAhead) return true;      // Block height is too high\n    }\n    if (fNewBlock) *fNewBlock = true;\n\n    if (!CheckBlock(block, state, chainparams.GetConsensus(), true, true, fAssumePOWGood) ||\n        !ContextualCheckBlock(block, state, chainparams, pindex->pprev, chainActive)) {\n        if (state.IsInvalid() && !state.CorruptionPossible()) {\n            pindex->nStatus |= BLOCK_FAILED_VALID;\n            setDirtyBlockIndex.insert(pindex);\n        }\n        return error(\"%s: %s\", __func__, FormatStateMessage(state));\n    }\n\n    // TODO, do not relay if we are SPV and have not fully validated the block? Something with the contextual block check\n    // fails in our partial sync.\n\n    // Header is valid/has work, merkle tree are good...RELAY NOW\n    // (but if it does not build on our best tip, let the SendMessages loop relay it)\n    //fixme: (PHASE5) (HIGH) This will probably increase forks slightly - but we need to keep pushing tip contenders out in case of stalled witness\n    // Maybe we could 'delay' such candidates slightly, store them in a cache and then only relay after some time has passed with tip not advancing.\n    static bool fRegTest = Params().IsRegtest();\n    static bool fRegTestLegacy = Params().IsRegtestLegacy();\n    if (((!IsInitialBlockDownload())||fRegTest||fRegTestLegacy) && (chainActive.Tip() == pindex->pprev || pindex->nHeight >= chainActive.Tip()->nHeight))\n        GetMainSignals().NewPoWValidBlock(pindex, pblock);\n\n    int nHeight = pindex->nHeight;\n\n    // Write block to history file\n    try {\n        unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);\n        CDiskBlockPos blockPos;\n        if (dbp != NULL)\n            blockPos = *dbp;\n        if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))\n            return error(\"AcceptBlock(): FindBlockPos failed\");\n        if (dbp == NULL)\n            if (!blockStore.WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))\n                AbortNode(state, \"Failed to write block\");\n        if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))\n            return error(\"AcceptBlock(): ReceivedBlockTransactions failed\");\n    } catch (const std::runtime_error& e) {\n        return AbortNode(state, std::string(\"System error: \") + e.what());\n    }\n\n    if (fCheckForPruning)\n        FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files\n\n    return true;\n}\n\nbool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock, bool fAssumePOWGood, bool checkFarAhead)\n{\n    bool fCloseToTip;\n    {\n        CBlockIndex *pindex = NULL;\n        if (fNewBlock) *fNewBlock = false;\n        CValidationState state;\n        // Ensure that CheckBlock() passes before calling AcceptBlock, as\n        // belt-and-suspenders.\n        bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus(), true, true, fAssumePOWGood);\n        if (!ret)\n        {\n            return error(\"%s: CheckBlock FAILED [%s]\", __func__, state.GetRejectReason().c_str());\n        }\n\n        LOCK(cs_main);\n\n        if (ret) {\n            // Store to disk, skip toFarAway check if we are not planing to activate the best chain\n            ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock, fAssumePOWGood, checkFarAhead);\n        }\n        CheckBlockIndex(chainparams.GetConsensus());\n        if (!ret) {\n            GetMainSignals().BlockChecked(*pblock, state);\n            return error(\"%s: AcceptBlock FAILED [%s]\", __func__, state.GetRejectReason().c_str());\n        }\n        fCloseToTip = pindex->nHeight <= chainActive.Height() + int(MIN_BLOCKS_TO_KEEP);\n    }\n\n    if (fCloseToTip && isFullSyncMode()) {\n        CValidationState state; // Only used to report errors, not invalidity - ignore it\n        if (!ActivateBestChain(state, chainparams, pblock))\n            return error(\"%s: ActivateBestChain failed\", __func__);\n    }\n\n    CheckAndNotifyHeaderTip();\n\n    return true;\n}\n\nbool TestBlockValidity(CChain& chain, CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot, CCoinsViewCache* cacheOverride)\n{\n    AssertLockHeld(cs_main);\n\n    if(!pindexPrev || pindexPrev != chain.Tip())\n        return false;\n\n    CCoinsViewCache viewNew(cacheOverride?cacheOverride:pcoinsTip);\n    CBlockIndex indexDummy(block);\n    indexDummy.pprev = pindexPrev;\n    indexDummy.nHeight = pindexPrev->nHeight + 1;\n\n    // NOTE: CheckBlockHeader is called by CheckBlock\n    if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev, GetAdjustedTime()))\n        return error(\"%s: Consensus::ContextualCheckBlockHeader: %s\", __func__, FormatStateMessage(state));\n    if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))\n        return error(\"%s: Consensus::CheckBlock: %s\", __func__, FormatStateMessage(state));\n    if (!ContextualCheckBlock(block, state, chainparams, pindexPrev, chain, cacheOverride))\n        return error(\"%s: Consensus::ContextualCheckBlock: %s\", __func__, FormatStateMessage(state));\n    if (!ConnectBlock(chain, block, state, &indexDummy, viewNew, chainparams, true))\n        return false;\n    assert(state.IsValid());\n\n    return true;\n}\n\n/**\n * BLOCK PRUNING CODE\n */\n\n/* Calculate the amount of disk space the block & undo files currently use */\nstatic uint64_t CalculateCurrentUsage()\n{\n    uint64_t retval = 0;\n    for(const CBlockFileInfo &file : vinfoBlockFile) {\n        retval += file.nSize + file.nUndoSize;\n    }\n    return retval;\n}\n\n/* Prune a block file (modify associated database entries)*/\nvoid PruneOneBlockFile(const int fileNumber)\n{\n    for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) {\n        CBlockIndex* pindex = it->second;\n        if (pindex->nFile == fileNumber) {\n            pindex->nStatus &= ~BLOCK_HAVE_DATA;\n            pindex->nStatus &= ~BLOCK_HAVE_UNDO;\n            pindex->nFile = 0;\n            pindex->nDataPos = 0;\n            pindex->nUndoPos = 0;\n            setDirtyBlockIndex.insert(pindex);\n\n            // Prune from mapBlocksUnlinked -- any block we prune would have\n            // to be downloaded again in order to consider its chain, at which\n            // point it would be considered as a candidate for\n            // mapBlocksUnlinked or setBlockIndexCandidates.\n            std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev);\n            while (range.first != range.second) {\n                std::multimap<CBlockIndex *, CBlockIndex *>::iterator _it = range.first;\n                range.first++;\n                if (_it->second == pindex) {\n                    mapBlocksUnlinked.erase(_it);\n                }\n            }\n        }\n    }\n\n    vinfoBlockFile[fileNumber].SetNull();\n    setDirtyFileInfo.insert(fileNumber);\n}\n\n/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */\nvoid FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight)\n{\n    assert(fPruneMode && nManualPruneHeight > 0);\n\n    LOCK2(cs_main, cs_LastBlockFile);\n    if (chainActive.Tip() == NULL)\n        return;\n\n    // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)\n    unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP);\n\n    FindFilesToPruneExplicit(setFilesToPrune, nLastBlockWeCanPrune);\n}\n\n/* This function is called from the RPC code for pruneblockchain */\nvoid PruneBlockFilesManual(int nManualPruneHeight)\n{\n    CValidationState state;\n    const CChainParams& chainparams = Params();\n    FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE, nManualPruneHeight);\n}\n\n/**\n * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.\n * The user sets the target (in MB) on the command line or in config file.  This will be run on startup and whenever new\n * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex\n * (which in this case means the blockchain must be re-downloaded.)\n *\n * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set.\n * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)\n * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest).\n * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.\n * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.\n * A db flag records the fact that at least some block files have been pruned.\n *\n * @param[out]   setFilesToPrune   The set of file indices that can be unlinked will be returned\n */\nvoid FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)\n{\n    LOCK2(cs_main, cs_LastBlockFile);\n    if (chainActive.Tip() == NULL || nPruneTarget == 0) {\n        return;\n    }\n    if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) {\n        return;\n    }\n\n    unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;\n    uint64_t nCurrentUsage = CalculateCurrentUsage();\n    // We don't check to prune until after we've allocated new space for files\n    // So we should leave a buffer under our target to account for another allocation\n    // before the next pruning.\n    uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;\n    uint64_t nBytesToPrune;\n    int count=0;\n\n    if (nCurrentUsage + nBuffer >= nPruneTarget) {\n        for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {\n            nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize;\n\n            if (vinfoBlockFile[fileNumber].nSize == 0)\n                continue;\n\n            if (nCurrentUsage + nBuffer < nPruneTarget)  // are we below our target?\n                break;\n\n            // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning\n            if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)\n                continue;\n\n            PruneOneBlockFile(fileNumber);\n            // Queue up the files for removal\n            setFilesToPrune.insert(fileNumber);\n            nCurrentUsage -= nBytesToPrune;\n            count++;\n        }\n    }\n\n    LogPrint(BCLog::PRUNE, \"Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\\n\",\n           nPruneTarget/1024/1024, nCurrentUsage/1024/1024,\n           ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,\n           nLastBlockWeCanPrune, count);\n}\n\nbool CheckDiskSpace(uint64_t nAdditionalBytes)\n{\n    uint64_t nFreeBytesAvailable = fs::space(GetDataDir()).available;\n\n    // Check for nMinDiskSpace bytes (currently 50MB)\n    if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)\n        return AbortNode(\"Disk space is low!\", _(\"Error: Disk space is low!\"));\n\n    return true;\n}\n\nCBlockIndex * InsertBlockIndex(uint256 hash)\n{\n    if (hash.IsNull())\n        return NULL;\n\n    // Return existing\n    BlockMap::iterator mi = mapBlockIndex.find(hash);\n    if (mi != mapBlockIndex.end())\n        return (*mi).second;\n\n    // Create new\n    CBlockIndex* pindexNew = new CBlockIndex();\n    if (!pindexNew)\n        throw std::runtime_error(std::string(__func__) + \": new CBlockIndex failed\");\n    mi = mapBlockIndex.insert(std::pair(hash, pindexNew)).first;\n    pindexNew->phashBlock = &((*mi).first);\n\n    return pindexNew;\n}\n\n#ifdef DEBUG_PARTIAL_SYNC\nbool static checkBlockIndexForPartialSync()\n{\n    LogPrintf(\"Checking block index for partial sync integrity\\n\");\n\n    bool integrityOK = true;\n\n    // test for blocks with nHeight == 0 and nStatus == 0\n    int num00 = 0;\n    CBlockIndex* theOne = nullptr;\n    for(const PAIRTYPE(uint256, CBlockIndex*)& item : mapBlockIndex)\n    {\n        CBlockIndex* pindex = item.second;\n        if (pindex->nHeight == 0 && pindex->nStatus == 0)\n        {\n            theOne = pindex;\n            LogPrintf(\"  Index with height 0 and status 0: %s\\n\", pindex->GetBlockHashPoW2().ToString());\n            num00++;\n        }\n    }\n    LogPrintf(\"  Number of indexes with height 0 and status 0: %d\\n\", num00);\n\n    // there can be at most one index with height 0 and status 0 (this is the index that precedes\n    // the start of the partial chain and was automtically creted during loading of the block-index\n    if (num00 > 1)\n        integrityOK = false;\n\n    // check that the one block with height 0 & status 0 precedes the partial chain\n    if (integrityOK && num00 == 1) {\n        if (partialChain[partialChain.HeightOffset()]->pprev == theOne) {\n            LogPrintf(\"  Exactly one index with height 0 and status 0 and it precedes the partial chain.\\n\");\n        }\n        else {\n            LogPrintf(\"  Exactly one index with height 0 and status 0 but is does NOT precede the partial chain, this and is a BUG!\\n\");\n            integrityOK = false;\n        }\n    }\n\n    // note for case where num00 == 0 there is no partial chain (yet)\n\n    // check that there are no partial valid blocks beyond the pindexBestPartial\n    for(const auto &[hash, pindex] : mapBlockIndex)\n    {\n        if (pindex->IsPartialValid() && (!pindexBestPartial || pindex->nHeight > pindexBestPartial->nHeight)) {\n            LogPrintf(\"  Index partial valid beyond pindexBestPartial: %s height = %d status  %d\\n\", hash.ToString(), pindex->nHeight, pindex->nStatus);\n            integrityOK = false;\n        }\n    }\n\n    LogPrintf(integrityOK ? \"  integrity is OK.\\n\"\n                          : \"  integrity check FAILED! Block index has invalid state.\\n\");\n\n    return integrityOK;\n}\n#endif\n\nvoid static heightSortedBlockIndex(std::vector<std::pair<int, CBlockIndex*> >& vSorted)\n{\n    vSorted.clear();\n    vSorted.reserve(mapBlockIndex.size());\n    for(const PAIRTYPE(uint256, CBlockIndex*)& item : mapBlockIndex)\n    {\n        CBlockIndex* pindex = item.second;\n        vSorted.push_back(std::pair(pindex->nHeight, pindex));\n    }\n    sort(vSorted.begin(), vSorted.end(), [](const std::pair<int, CBlockIndex*>& a, const std::pair<int, CBlockIndex*>& b) -> bool\n    {\n        //Ensure PoW block always comes first in sort before witness block of same height.\n        if (a.first == b.first)\n        {\n            if (a.second->nVersionPoW2Witness == 0 && b.second->nVersionPoW2Witness > 0)\n                return true;\n            if (a.second->nVersionPoW2Witness > 0 && b.second->nVersionPoW2Witness == 0)\n                return false;\n            return a.second < b.second;\n        }\n        return a.first < b.first;\n    });\n}\n\nbool static LoadBlockIndexDB(const CChainParams& chainparams)\n{\n    LOCK(cs_main);\n\n    if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))\n        return false;\n\n    boost::this_thread::interruption_point();\n\n    // find pindexBestPartial\n    for (const auto& it: mapBlockIndex) {\n        CBlockIndex* pindex = it.second;\n        if ((pindex->IsPartialValid(BLOCK_PARTIAL_TREE))\n                && (!pindexBestPartial || pindex->nHeight >= pindexBestPartial->nHeight))\n            pindexBestPartial = pindex;\n    }\n\n     if (fSPV && !pindexBestPartial)\n     {\n         LogPrintf(\"Cannot load a full blockchain with a SPV wallet, index will have to be regenerated\");\n         return false;\n     }\n\n    // initialize partial chain and cleanup block index\n    if (pindexBestPartial)\n    {\n        if (!fSPV)\n        {\n            LogPrintf(\"Cannot load an SPV blockchain with non SPV wallet, index will have to be regenerated\");\n            exit(EXIT_FAILURE);\n            return false;\n        }\n\n        CBlockIndex* pindex = pindexBestPartial;\n        while (pindex->pprev && pindex->pprev->IsPartialValid(BLOCK_PARTIAL_TREE))\n            pindex = pindex->pprev;\n        partialChain.SetHeightOffset(pindex->nHeight);\n        partialChain.SetTip(pindexBestPartial);\n\n#ifdef DEBUG_PARTIAL_SYNC\n        checkBlockIndexForPartialSync();\n#endif\n\n        // Kill link before partial chain offset unless it is linked:\n        // a) beyond pindex->pprev in which case it connects to the main chain.\n        // b)  to the genesis\n        if (pindex->pprev && !pindex->pprev->pprev && pindex->pprev->GetBlockHashPoW2() != Params().GenesisBlock().GetHashPoW2()) {\n            pindex->pprev = 0;\n        }\n\n        // if we are not in full sync mode any index block not in the partial chain is useless and can and should be removed\n        // if our partial chain is on a fork and blocks (now known) to be on the main chain are removed by this they will be\n        // re-requested (so that is ok)\n        if (!isFullSyncMode())\n        {\n            // collect orphans\n            std::vector<uint256> removals;\n            for (auto it = mapBlockIndex.begin(); it != mapBlockIndex.end(); )\n            {\n                CBlockIndex* pindex = it->second;\n\n                // When not in full sync mode we should not have any full validation status so clear it.\n                // This should normally not happen. An edge case is when with full sync mode in a previous session and\n                // in a later session switching to pure partial sync.\n                if (pindex->nHeight != 0) {\n                    pindex->nStatus &= ~(BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS);\n                    pindex->nChainTx = 0;\n                }\n\n                if (!partialChain.Contains(pindex) && (pindex->nHeight != 0 || pindex->GetBlockHashPoW2() != Params().GenesisBlock().GetHashPoW2()))\n                {\n                    // important to get hash for removals here first before erasing from mapBlockIndex\n                    // as the erase will invalidate the internal hash block ptr\n                    removals.push_back(pindex->GetBlockHashPoW2());\n                    it = mapBlockIndex.erase(it);\n\n                    // Reclaim memory now that it's not used anymore.\n                    delete pindex;\n                }\n                else {\n                    it++;\n                }\n            }\n\n            if (!removals.empty())\n            {\n                LogPrintf(\"Collected %d orphans from block index which will be removed\\n\", removals.size());\n\n                // remove them from disk\n                if (!pblocktree->EraseBatchSync(removals)) {\n                    LogPrintf(\"Failed to erase orphans from block index database\");\n                    return false;\n                }\n            }\n        }\n\n#ifdef DEBUG_PARTIAL_SYNC\n        assert(checkBlockIndexForPartialSync());\n#endif\n    }\n\n    std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;\n\n    // Build skiplist, calculate nChainWork and block index candidates\n    if (!fSPV)\n    {\n        heightSortedBlockIndex(vSortedByHeight);\n        for(const PAIRTYPE(int, CBlockIndex*)& item : vSortedByHeight)\n        {\n            CBlockIndex* pindex = item.second;\n            pindex->BuildSkip();\n            pindex->nChainWork = CalculateChainWork(pindex, chainparams);;\n            pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);\n            // We can link the chain of blocks for which we've received transactions at some point.\n            \n            \n            // Pruned nodes may have deleted the block.\n            if (pindex->nTx > 0) {\n                if (pindex->pprev) {\n                    if (pindex->pprev->nChainTx) {\n                        pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;\n                    } else {\n                        pindex->nChainTx = 0;\n                        mapBlocksUnlinked.insert(std::pair(pindex->pprev, pindex));\n                    }\n                } else {\n                    pindex->nChainTx = pindex->nTx;\n                }\n            }\n\n            \n            if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))\n            {\n                setBlockIndexCandidates.insert(pindex);\n                //LogPrintf(\"LoadBlockIndexDB: New index candidate: [%s] [%d]\\n\", pindex->GetBlockHashPoW2().ToString(), pindex->nHeight);\n            }\n            \n            if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))\n                pindexBestInvalid = pindex;\n            \n            if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) {\n                pindexBestHeader = pindex;\n            }\n        }\n    }\n\n    // Load block file info\n    pblocktree->ReadLastBlockFile(nLastBlockFile);\n    vinfoBlockFile.resize(nLastBlockFile + 1);\n    LogPrintf(\"%s: last block file = %i\\n\", __func__, nLastBlockFile);\n    for (int nFile = 0; nFile <= nLastBlockFile; nFile++) {\n        pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]);\n    }\n    LogPrintf(\"%s: last block file info: %s\\n\", __func__, vinfoBlockFile[nLastBlockFile].ToString());\n    for (int nFile = nLastBlockFile + 1; true; nFile++) {\n        CBlockFileInfo info;\n        if (pblocktree->ReadBlockFileInfo(nFile, info)) {\n            vinfoBlockFile.push_back(info);\n        } else {\n            break;\n        }\n    }\n\n    // Check presence of blk files\n    LogPrintf(\"Checking all blk files are present...\\n\");\n    std::set<int> setBlkDataFiles;\n    for(const PAIRTYPE(uint256, CBlockIndex*)& item : mapBlockIndex)\n    {\n        CBlockIndex* pindex = item.second;\n        if (pindex->nStatus & BLOCK_HAVE_DATA) {\n            setBlkDataFiles.insert(pindex->nFile);\n        }\n    }\n    for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)\n    {\n        CDiskBlockPos pos(*it, 0);\n        if (CFile(blockStore.GetBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) {\n            return false;\n        }\n    }\n\n    // Check whether we have ever pruned block & undo files\n    pblocktree->ReadFlag(\"prunedblockfiles\", fHavePruned);\n    if (fHavePruned)\n        LogPrintf(\"LoadBlockIndexDB(): Block files have previously been pruned\\n\");\n\n    // Check whether we need to continue reindexing\n    bool fReindexing = false;\n    pblocktree->ReadReindexing(fReindexing);\n    fReindex |= fReindexing;\n\n    // Check whether we have a transaction index\n    pblocktree->ReadFlag(\"txindex\", fTxIndex);\n    LogPrintf(\"%s: transaction index %s\\n\", __func__, fTxIndex ? \"enabled\" : \"disabled\");\n\n    // Load pointer to end of best chain\n    BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());\n    if (it == mapBlockIndex.end())\n        return true;\n    chainActive.SetTip(it->second);\n\n    PruneBlockIndexCandidates();\n    \n    \n    // If we were stuck on the wrong side of a fork (due to not updating)\n    // And have now updated to a newer version, then this block may be valid on the newer version despite being marked invalid previously by the outdated version\n    // If we don't reconsider the block we will be permanently \"stuck\"\n    // We can use the checkpoint to find out if this is the case, so we do this here.\n    // If we are the ancestor of a checkpoint then reset the failiure flags and try again\n    int numReset = 0;\n    int64_t lastCheckpointHeight = Checkpoints::LastCheckPointHeight();\n    bool fTestNet = Params().IsTestnet();\n    if (chainActive.Tip()->nHeight < lastCheckpointHeight)\n    {\n        for (auto it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it)\n        {\n            CBlockIndex* resetIndex = it->second;\n            if ((fTestNet || ((resetIndex->nHeight > lastCheckpointHeight - 300000) && resetIndex->nHeight < lastCheckpointHeight)) && !resetIndex->IsValid())\n            {\n                // Reset block failiure flags and give it another chance\n                ResetBlockFailureFlagsForSingleBlock(resetIndex);\n                ++numReset;\n            }\n        }\n    }\n    if (numReset > 0)\n    {\n        LogPrintf(\"LoadBlockIndexDB(): Allowing [%d] invalid blocks below checkpoint height to have their validity reconsidered \\n\", numReset);\n    }\n\n    LogPrintf(\"%s: hashBestChain=%s height=%d date=%s progress=%f\\n\", __func__,\n        chainActive.Tip()->GetBlockHashPoW2().ToString(), chainActive.Height(),\n        FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()),\n        GuessVerificationProgress(chainActive.Tip()));\n\n    return true;\n}\n\nbool UpgradeBlockIndex(const CChainParams& chainparams, int nPreviousVersion, int nCurrentVersion)\n{\n    // Any future upgrade code goes here.\n    // Refresh all blocks on disk - change in serialisation format.\n    if (nPreviousVersion == 3 && nCurrentVersion >= 4)\n    {\n         LOCK(cs_main);\n                \n        blockStore.CloseBlockFiles();\n\n        CBlockStore oldStore;\n\n        oldStore.Rename(\"prewitsync_\");\n\n        {\n            LOCK(cs_LastBlockFile);\n            vinfoBlockFile.clear();\n            nLastBlockFile = 0;\n        }\n\n        // (Optimisation) Sort by height so that the files end up \"in order\" in the new block files.\n        std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;\n        vSortedByHeight.reserve(mapBlockIndex.size());\n        for(const PAIRTYPE(uint256, CBlockIndex*)& item : mapBlockIndex)\n        {\n            CBlockIndex* pindex = item.second;\n            vSortedByHeight.push_back(std::pair(pindex->nHeight, pindex));\n        }\n        sort(vSortedByHeight.begin(), vSortedByHeight.end(), [](const std::pair<int, CBlockIndex*>& a, const std::pair<int, CBlockIndex*>& b) -> bool { return a.first < b.first; });\n\n        // Now read the block files in one at a time from the old files and write them into the new files.\n        CBlock* pblock = new CBlock();\n        std::vector<std::pair<int, const CBlockFileInfo*> > vDirtyFiles;\n        std::vector<const CBlockIndex*> vDirtyBlocks;\n        std::map<CDiskBlockPos, CDiskBlockPos> vUpdateTxIndexes;\n        for(const auto& item: vSortedByHeight)\n        {\n            CBlockIndex* pindex = item.second;\n            pblock->SetNull();\n\n            CDiskBlockPos oldBlockPos = pindex->GetBlockPos();\n            CDiskBlockPos oldUndoPos = pindex->GetUndoPos();\n            if (oldBlockPos.nFile >= 0)\n            {\n                vDirtyFiles.push_back(std::pair(pindex->nFile, &vinfoBlockFile[pindex->nFile]));\n                // Read block in, using old transaction format.\n                {\n                    if (!oldStore.ReadBlockFromDisk(*pblock, oldBlockPos, chainparams, nullptr, SERIALIZE_BLOCK_HEADER_NO_WITNESS_DELTA))\n                        return error(\"UpgradeBlockIndex: ReadBlockFromDisk: Errors in block at %s\", oldBlockPos.ToString());\n                }\n\n                // Write block out using new transaction format.\n                {\n                    unsigned int nSize = ::GetSerializeSize(*pblock, SER_DISK, CLIENT_VERSION);\n                    CValidationState state;\n                    CDiskBlockPos blockpos;\n                    FindBlockPos(state, blockpos, nSize+8, pindex->nHeight, pblock->GetBlockTime());\n                    if (!blockStore.WriteBlockToDisk(*pblock, blockpos, chainparams.MessageStart()))\n                        return error(\"UpgradeBlockIndex: WriteBlockToDisk: failed\");\n                    pindex->nFile = blockpos.nFile;\n                    pindex->nDataPos = blockpos.nPos;\n                    \n                    // Update the tx index as well as those reference the block disk positions...\n                    vUpdateTxIndexes[oldBlockPos] = blockpos;\n                }\n                \n                CDiskBlockPos newUndoPos;\n                if (pindex->nStatus & BLOCK_HAVE_UNDO)\n                {\n                    CBlockUndo undo;\n                    if (!oldUndoPos.IsNull())\n                    {\n                        if (!oldStore.UndoReadFromDisk(undo, oldUndoPos, pindex->pprev->GetBlockHashPoW2()))\n                            return error(\"UpgradeBlockIndex(): *** found bad undo data at %d, hash=%s\\n\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n\n                        pindex->nUndoPos = 0;\n                        CValidationState state;\n                        if (!FindUndoPos(state, pindex->nFile, newUndoPos, ::GetSerializeSize(undo, SER_DISK, CLIENT_VERSION) + 40))\n                            return error(\"ConnectBlock(): FindUndoPos failed\");\n                        if (!blockStore.UndoWriteToDisk(undo, newUndoPos, pindex->pprev->GetBlockHashPoW2(), chainparams.MessageStart()))\n                            return AbortNode(state, \"Failed to write undo data\");\n\n                        // update nUndoPos in block index\n                        pindex->nUndoPos = newUndoPos.nPos;\n                    }\n                }\n                \n                // Update the block index as the position of the block on disk has changed.\n                {\n                    vDirtyBlocks.push_back(pindex);\n                    vDirtyFiles.push_back(std::pair(pindex->nFile, &vinfoBlockFile[pindex->nFile]));\n                }\n            }\n        }\n        delete pblock;\n\n        FlushBlockFile();\n        \n        std::set<std::pair<uint256, CDiskTxPos> > vWriteTxIndexes;\n        std::set<std::pair<uint256, CDiskTxPos> > vEraseTxIndexes;\n        \n        if (!pblocktree->MoveTxIndexDiskPos(vUpdateTxIndexes, vEraseTxIndexes, vWriteTxIndexes))\n            return error(\"UpgradeBlockIndex: Failed to calculate update to block transaction index database\");\n        \n        if (!pblocktree->UpdateBatchSync(vDirtyFiles, nLastBlockFile, vDirtyBlocks, std::vector<uint256>(), vEraseTxIndexes, vWriteTxIndexes))\n        {\n            return error(\"UpgradeBlockIndex: Failed to write to block index database\");\n        }\n\n        oldStore.Delete();\n        return true;\n    }\n    else if (nPreviousVersion != nCurrentVersion)\n    {\n        return false;\n    }\n    return true;\n}\n\nCVerifyDB::CVerifyDB()\n{\n    uiInterface.ShowProgress(_(\"Verifying blocks...\"), 0);\n}\n\nCVerifyDB::~CVerifyDB()\n{\n    uiInterface.ShowProgress(\"\", 100);\n}\n\nbool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)\n{\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n    if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)\n        return true;\n\n    // Verify blocks in the best chain\n    if (nCheckDepth <= 0)\n        nCheckDepth = 1000000000; // suffices until the year 19000\n    if (nCheckDepth > chainActive.Height())\n        nCheckDepth = chainActive.Height();\n    nCheckLevel = std::max(0, std::min(4, nCheckLevel));\n    LogPrintf(\"Verifying last %i blocks at level %i\\n\", nCheckDepth, nCheckLevel);\n    CCoinsViewCache coins(coinsview);\n    CBlockIndex* pindexState = chainActive.Tip();\n    CBlockIndex* pindexFailure = NULL;\n    int nGoodTransactions = 0;\n    CValidationState state;\n    int reportDone = 0;\n    LogPrintf(\"[0%%]...\");\n    for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)\n    {\n        boost::this_thread::interruption_point();\n        int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));\n        if (reportDone < percentageDone/10) {\n            // report every 10% step\n            LogPrintf(\"[%d%%]...\", percentageDone);\n            reportDone = percentageDone/10;\n        }\n        uiInterface.ShowProgress(_(\"Verifying blocks...\"), percentageDone);\n        if (pindex->nHeight < chainActive.Height()-nCheckDepth)\n            break;\n        if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {\n            // If pruning, only go back as far as we have data.\n            LogPrintf(\"VerifyDB(): block verification stopping at height %d (pruning, no data)\\n\", pindex->nHeight);\n            break;\n        }\n        CBlock block;\n        // check level 0: read from disk\n        if (!ReadBlockFromDisk(block, pindex, chainparams))\n            return error(\"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n        // check level 1: verify block validity\n        if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus()))\n            return error(\"%s: *** found bad block at %d, hash=%s (%s)\\n\", __func__,\n                         pindex->nHeight, pindex->GetBlockHashPoW2().ToString(), FormatStateMessage(state));\n        // check level 2: verify undo validity\n        if (nCheckLevel >= 2 && pindex) {\n            CBlockUndo undo;\n            CDiskBlockPos pos = pindex->GetUndoPos();\n            if (!pos.IsNull()) {\n                if (!blockStore.UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHashPoW2()))\n                    return error(\"VerifyDB(): *** found bad undo data at %d, hash=%s\\n\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n            }\n        }\n        // check level 3: check for inconsistencies during memory-only disconnect of tip blocks\n        if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {\n            DisconnectResult res = DisconnectBlock(block, pindex, coins);\n            if (res == DISCONNECT_FAILED) {\n                return error(\"VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n            }\n            pindexState = pindex->pprev;\n            if (res == DISCONNECT_UNCLEAN) {\n                nGoodTransactions = 0;\n                pindexFailure = pindex;\n            } else {\n                nGoodTransactions += block.vtx.size();\n            }\n        }\n        if (ShutdownRequested())\n            return true;\n    }\n    if (pindexFailure)\n        return error(\"VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\\n\", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);\n\n    // check level 4: try reconnecting blocks\n    if (nCheckLevel >= 4) {\n        CBlockIndex *pindex = pindexState;\n        while (pindex != chainActive.Tip()) {\n            boost::this_thread::interruption_point();\n            uiInterface.ShowProgress(_(\"Verifying blocks...\"), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))));\n            pindex = chainActive.Next(pindex);\n            CBlock block;\n            if (!ReadBlockFromDisk(block, pindex, chainparams))\n                return error(\"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n            if (!ConnectBlock(chainActive, block, state, pindex, coins, chainparams))\n                return error(\"VerifyDB(): *** found unconnectable block at %d, hash=%s\", pindex->nHeight, pindex->GetBlockHashPoW2().ToString());\n        }\n    }\n\n    LogPrintf(\"[DONE].\\n\");\n    LogPrintf(\"No coin database inconsistencies in last %i blocks (%i transactions)\\n\", chainActive.Height() - pindexState->nHeight, nGoodTransactions);\n\n    return true;\n}\n\nbool RewindBlockIndex(const CChainParams& params)\n{\n    LOCK(cs_main);\n\n    int nHeight = 1;\n    while (nHeight <= chainActive.Height())\n    {\n        if (IsSegSigEnabled(chainActive[nHeight - 1]) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS))\n        {\n            break;\n        }\n        nHeight++;\n    }\n\n    // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1\n    CValidationState state;\n    CBlockIndex* pindex = chainActive.Tip();\n    while (chainActive.Height() >= nHeight) {\n        if (fPruneMode && !(chainActive.Tip()->nStatus & BLOCK_HAVE_DATA)) {\n            // If pruning, don't try rewinding past the HAVE_DATA point;\n            // since older blocks can't be served anyway, there's\n            // no need to walk further, and trying to DisconnectTip()\n            // will fail (and require a needless reindex/redownload\n            // of the blockchain).\n            break;\n        }\n        if (!DisconnectTip(state, params, NULL)) {\n            return error(\"RewindBlockIndex: unable to disconnect block at height %i\", pindex->nHeight);\n        }\n        // Occasionally flush state to disk.\n        if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC))\n            return false;\n    }\n\n    // Reduce validity flag and have-data flags.\n    // We do this after actual disconnecting, otherwise we'll end up writing the lack of data\n    // to disk before writing the chainstate, resulting in a failure to continue if interrupted.\n    for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {\n        CBlockIndex* pindexIter = it->second;\n\n        // Note: If we encounter an insufficiently validated block that\n        // is on chainActive, it must be because we are a pruning node, and\n        // this block or some successor doesn't HAVE_DATA, so we were unable to\n        // rewind all the way.  Blocks remaining on chainActive at this point\n        // must not have their validity reduced.\n        if (IsSegSigEnabled(pindexIter->pprev) && !(pindexIter->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains(pindexIter)) {\n            // Reduce validity\n            pindexIter->nStatus = std::min<unsigned int>(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindexIter->nStatus & ~BLOCK_VALID_MASK);\n            // Remove have-data flags.\n            pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);\n            // Remove storage location.\n            pindexIter->nFile = 0;\n            pindexIter->nDataPos = 0;\n            pindexIter->nUndoPos = 0;\n            // Remove various other things\n            pindexIter->nTx = 0;\n            pindexIter->nChainTx = 0;\n            pindexIter->nSequenceId = 0;\n            // Make sure it gets written.\n            setDirtyBlockIndex.insert(pindexIter);\n            // Update indexes\n            setBlockIndexCandidates.erase(pindexIter);\n            std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> ret = mapBlocksUnlinked.equal_range(pindexIter->pprev);\n            while (ret.first != ret.second) {\n                if (ret.first->second == pindexIter) {\n                    mapBlocksUnlinked.erase(ret.first++);\n                } else {\n                    ++ret.first;\n                }\n            }\n        } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx)\n        {\n            setBlockIndexCandidates.insert(pindexIter);\n            //LogPrintf(\"RewindBlockIndex: New index candidate: [%s] [%d]\\n\", pindexIter->GetBlockHashPoW2().ToString(), pindexIter->nHeight);\n        }\n    }\n\n    PruneBlockIndexCandidates();\n\n    CheckBlockIndex(params.GetConsensus());\n\n    if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {\n        return false;\n    }\n\n    return true;\n}\n\n// May NOT be used after any connections are up as much\n// of the peer-processing logic assumes a consistent\n// block index state\nvoid UnloadBlockIndex()\n{\n    LOCK(cs_main);\n    setBlockIndexCandidates.clear();\n    chainActive.SetTip(NULL);\n    pindexBestInvalid = NULL;\n    pindexBestHeader = NULL;\n    partialChain.SetTip(nullptr);\n    mempool.clear();\n    mapBlocksUnlinked.clear();\n    vinfoBlockFile.clear();\n    nLastBlockFile = 0;\n    nBlockSequenceId = 1;\n    setDirtyBlockIndex.clear();\n    setDirtyFileInfo.clear();\n    versionbitscache.Clear();\n    for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {\n        warningcache[b].clear();\n    }\n\n    for(BlockMap::value_type& entry : mapBlockIndex) {\n        delete entry.second;\n    }\n    mapBlockIndex.clear();\n    fHavePruned = false;\n}\n\nbool LoadBlockIndex(const CChainParams& chainparams)\n{\n    // Load block index from databases\n    if (!fReindex && !LoadBlockIndexDB(chainparams))\n        return false;\n    return true;\n}\n\nbool InitBlockIndex(const CChainParams& chainparams)\n{\n    LOCK(cs_main);\n\n    // Check whether we're already initialized\n    if (chainActive.Genesis() != NULL)\n        return true;\n\n    // Use the provided setting for -txindex in the new database\n    fTxIndex = GetBoolArg(\"-txindex\", DEFAULT_TXINDEX);\n    pblocktree->WriteFlag(\"txindex\", fTxIndex);\n    LogPrintf(\"Initializing databases...\\n\");\n\n    // Only add the genesis block if not reindexing (in which case we reuse the one already on disk)\n    if (!fReindex) {\n        try {\n            CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());\n            // Start new block file\n            unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);\n            CDiskBlockPos blockPos;\n            CValidationState state;\n            if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))\n                return error(\"LoadBlockIndex(): FindBlockPos failed\");\n            if (!blockStore.WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))\n                return error(\"LoadBlockIndex(): writing genesis block to disk failed\");\n            CBlockIndex *pindex = AddToBlockIndex(chainparams, block);\n            if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))\n                return error(\"LoadBlockIndex(): genesis block not accepted\");\n\n            // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data\n            return FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS);\n        } catch (const std::runtime_error& e) {\n            return error(\"LoadBlockIndex(): failed to initialize block database: %s\", e.what());\n        }\n    }\n\n    return true;\n}\n\nvoid PersistAndPruneForPartialSync(bool periodic)\n{\n    // should be run at shutdown so that the block index remains small and\n    // next startup stays fast\n    // also run periodically (and on demand at key points, ie. app to background)\n    // to prevent loss of data and needing to re-dowload\n\n    LOCK(cs_main);\n\n    if (isFullSyncMode() || !IsPartialSyncActive())\n        return;\n\n    // never use a pruning height above what has been spv processed, if it has been set at all\n    // there is no point in keeping blocks below the partial chain offset\n    int pruneHeight = std::max(nMaxSPVPruneHeight.load(), partialChain.HeightOffset());\n\n    CValidationState state;\n    FlushStateToDisk(Params(), state,\n                     periodic ? FlushStateMode::FLUSH_STATE_PERIODIC : FlushStateMode::FLUSH_STATE_ALWAYS,\n                     pruneHeight, true);\n}\n\nbool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp)\n{\n    // Map of disk positions for blocks with unknown parent (only used for reindex)\n    static std::multimap<uint256, CDiskBlockPos> mapBlocksUnknownParent;\n    int64_t nStart = GetTimeMillis();\n\n    int nLoaded = 0;\n    try {\n        // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor\n        CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE+8, SER_DISK, CLIENT_VERSION-1);\n        uint64_t nRewind = blkdat.GetPos();\n        while (!blkdat.eof()) {\n            boost::this_thread::interruption_point();\n\n            blkdat.SetPos(nRewind);\n            nRewind++; // start one byte further next time, in case of failure\n            blkdat.SetLimit(); // remove former limit\n            unsigned int nSize = 0;\n            try {\n                // locate a header\n                unsigned char buf[CMessageHeader::MESSAGE_START_SIZE];\n                blkdat.FindByte(chainparams.MessageStart()[0]);\n                nRewind = blkdat.GetPos()+1;\n                blkdat >> FLATDATA(buf);\n                if (memcmp(buf, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE))\n                    continue;\n                // read size\n                blkdat >> nSize;\n                if (nSize < 80 || nSize > MAX_BLOCK_SERIALIZED_SIZE)\n                    continue;\n            } catch (const std::exception&) {\n                // no valid block header found; don't complain\n                break;\n            }\n            try {\n                // read block\n                uint64_t nBlockPos = blkdat.GetPos();\n                if (dbp)\n                    dbp->nPos = nBlockPos;\n                blkdat.SetLimit(nBlockPos + nSize);\n                blkdat.SetPos(nBlockPos);\n                std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n                CBlock& block = *pblock;\n                blkdat >> block;\n                nRewind = blkdat.GetPos();\n\n                // detect out of order blocks, and store them for later\n                uint256 hash = block.GetHashPoW2();\n                if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) {\n                    LogPrint(BCLog::REINDEX, \"%s: Out of order block %s, parent %s not known\\n\", __func__, hash.ToString(),\n                            block.hashPrevBlock.ToString());\n                    if (dbp)\n                        mapBlocksUnknownParent.insert(std::pair(block.hashPrevBlock, *dbp));\n                    continue;\n                }\n\n                // process in case the block isn't known yet\n                if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {\n                    LOCK(cs_main);\n                    CValidationState state;\n                    bool fAssumePOWGood=false;\n                    //This check is expensive\n                    //Bypass with a small random chance of still checking IFF we are below the checkpoint heights.\n                    //Note: an attacker would still have to meet/break/forge the sha ppev hash checks for an entire chain from the checkpoints\n                    // This is enough to ensure that an attacker would have to go to great lengths for what would amount to a minor nuisance (having to refetch some data after detecting wrong chain)\n                    // So this is not really a major weakening of security in any way and still more than sufficient.\n                    if (mapBlockIndex.find(block.hashPrevBlock)->second->nHeight < Checkpoints::LastCheckPointHeight())\n                    {\n                        fAssumePOWGood = true;\n                    }\n                    if (AcceptBlock(pblock, state, chainparams, NULL, true, dbp, NULL, fAssumePOWGood, true))\n                        nLoaded++;\n                    if (state.IsError())\n                        break;\n                } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) {\n                    LogPrint(BCLog::REINDEX, \"Block Import: already had block %s at height %d\\n\", hash.ToString(), mapBlockIndex[hash]->nHeight);\n                }\n\n                // Activate the genesis block so normal node progress can continue\n                if (hash == chainparams.GetConsensus().hashGenesisBlock) {\n                    CValidationState state;\n                    if (!ActivateBestChain(state, chainparams)) {\n                        break;\n                    }\n                }\n\n                // Recursively process earlier encountered successors of this block\n                std::deque<uint256> queue;\n                queue.push_back(hash);\n                while (!queue.empty()) {\n                    uint256 head = queue.front();\n                    queue.pop_front();\n                    std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);\n                    while (range.first != range.second) {\n                        std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;\n                        std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();\n                        {\n                            LOCK(cs_main); // acquire cs_main here to protect ReadBlockFromDisk\n                            if (blockStore.ReadBlockFromDisk(*pblockrecursive, it->second, chainparams))\n                            {\n                                LogPrint(BCLog::REINDEX, \"%s: Processing out of order child %s of %s\\n\", __func__, pblockrecursive->GetHashPoW2().ToString(),\n                                        head.ToString());\n                                CValidationState dummy;\n                                if (AcceptBlock(pblockrecursive, dummy, chainparams, NULL, true, &it->second, NULL, false, true))\n                                {\n                                    nLoaded++;\n                                    queue.push_back(pblockrecursive->GetHashPoW2());\n                                }\n                            }\n                        }\n                        range.first++;\n                        mapBlocksUnknownParent.erase(it);\n                    }\n                }\n            } catch (const std::exception& e) {\n                LogPrintf(\"%s: Deserialize or I/O error - %s\\n\", __func__, e.what());\n            }\n        }\n    } catch (const std::runtime_error& e) {\n        AbortNode(std::string(\"System error: \") + e.what());\n    }\n    if (nLoaded > 0)\n        LogPrintf(\"Loaded %i blocks from external file in %dms\\n\", nLoaded, GetTimeMillis() - nStart);\n    return nLoaded > 0;\n}\n\nvoid static CheckBlockIndex(const Consensus::Params& consensusParams)\n{\n    if (!fCheckBlockIndex) {\n        return;\n    }\n\n    LOCK(cs_main);\n\n    // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain,\n    // so we have the genesis block in mapBlockIndex but no active chain.  (A few of the tests when\n    // iterating the block tree require that chainActive has been initialized.)\n    if (chainActive.Height() < 0) {\n        assert(mapBlockIndex.size() <= 1);\n        return;\n    }\n\n    // Build forward-pointing map of the entire block tree.\n    std::multimap<CBlockIndex*,CBlockIndex*> forward;\n    for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {\n        forward.insert(std::pair(it->second->pprev, it->second));\n    }\n\n    assert(forward.size() == mapBlockIndex.size());\n\n    std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(NULL);\n    CBlockIndex *pindex = rangeGenesis.first->second;\n    rangeGenesis.first++;\n    assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL.\n\n    // Iterate over the entire block tree, using depth-first search.\n    // Along the way, remember whether there are blocks on the path from genesis\n    // block being explored which are the first to have certain properties.\n    size_t nNodes = 0;\n    int nHeight = 0;\n    CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid.\n    CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.\n    CBlockIndex* pindexFirstNeverProcessed = NULL; // Oldest ancestor of pindex for which nTx == 0.\n    CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).\n    CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not).\n    CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).\n    CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).\n    while (pindex != NULL) {\n        nNodes++;\n        if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;\n        if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex;\n        if (pindexFirstNeverProcessed == NULL && pindex->nTx == 0) pindexFirstNeverProcessed = pindex;\n        if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex;\n        if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex;\n        if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex;\n        if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex;\n\n        // Begin: actual consistency checks.\n        if (pindex->pprev == NULL) {\n            // Genesis block checks.\n            assert(pindex->GetBlockHashLegacy() == consensusParams.hashGenesisBlock); // Genesis block's hash must match.\n            assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.\n        }\n        if (pindex->nChainTx == 0) assert(pindex->nSequenceId <= 0);  // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)\n        // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).\n        // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.\n        if (!fHavePruned) {\n            // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0\n            assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));\n            assert(pindexFirstMissing == pindexFirstNeverProcessed);\n        } else {\n            // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0\n            if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);\n        }\n        if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);\n        assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent.\n        // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set.\n        assert((pindexFirstNeverProcessed != NULL) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned).\n        assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0));\n        assert(pindex->nHeight == nHeight); // nHeight must be consistent.\n        assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.\n        assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.\n        assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid\n        if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid\n        if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid\n        if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid\n        if (pindexFirstInvalid == NULL) {\n            // Checks for not-invalid blocks.\n            assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.\n        }\n        if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) {\n            if (pindexFirstInvalid == NULL) {\n                // If this block sorts at least as good as the current tip and\n                // is valid and we have all data for its parents, it must be in\n                // setBlockIndexCandidates.  chainActive.Tip() must also be there\n                // even if some data has been pruned.\n                if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) {\n                    assert(setBlockIndexCandidates.count(pindex));\n                }\n                // If some parent is missing, then it could be that this block was in\n                // setBlockIndexCandidates but had to be removed because of the missing data.\n                // In this case it must be in mapBlocksUnlinked -- see test below.\n            }\n        } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates.\n            assert(setBlockIndexCandidates.count(pindex) == 0);\n        }\n        // Check whether this block is in mapBlocksUnlinked.\n        std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev);\n        bool foundInUnlinked = false;\n        while (rangeUnlinked.first != rangeUnlinked.second) {\n            assert(rangeUnlinked.first->first == pindex->pprev);\n            if (rangeUnlinked.first->second == pindex) {\n                foundInUnlinked = true;\n                break;\n            }\n            rangeUnlinked.first++;\n        }\n        if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != NULL && pindexFirstInvalid == NULL) {\n            // If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked.\n            assert(foundInUnlinked);\n        }\n        if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA\n        if (pindexFirstMissing == NULL) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked.\n        if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == NULL && pindexFirstMissing != NULL) {\n            // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.\n            assert(fHavePruned); // We must have pruned.\n            // This block may have entered mapBlocksUnlinked if:\n            //  - it has a descendant that at some point had more work than the\n            //    tip, and\n            //  - we tried switching to that descendant but were missing\n            //    data for some intermediate block between chainActive and the\n            //    tip.\n            // So if this block is itself better than chainActive.Tip() and it wasn't in\n            // setBlockIndexCandidates, then it must be in mapBlocksUnlinked.\n            if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {\n                if (pindexFirstInvalid == NULL) {\n                    assert(foundInUnlinked);\n                }\n            }\n        }\n        // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow\n        // End: actual consistency checks.\n\n        // Try descending into the first subnode.\n        std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range(pindex);\n        if (range.first != range.second) {\n            // A subnode was found.\n            pindex = range.first->second;\n            nHeight++;\n            continue;\n        }\n        // This is a leaf node.\n        // Move upwards until we reach a node of which we have not yet visited the last child.\n        while (pindex) {\n            // We are going to either move to a parent or a sibling of pindex.\n            // If pindex was the first with a certain property, unset the corresponding variable.\n            if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL;\n            if (pindex == pindexFirstMissing) pindexFirstMissing = NULL;\n            if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = NULL;\n            if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL;\n            if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL;\n            if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL;\n            if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL;\n            // Find our parent.\n            CBlockIndex* pindexPar = pindex->pprev;\n            // Find which child we just visited.\n            std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangePar = forward.equal_range(pindexPar);\n            while (rangePar.first->second != pindex) {\n                assert(rangePar.first != rangePar.second); // Our parent must have at least the node we're coming from as child.\n                rangePar.first++;\n            }\n            // Proceed to the next one.\n            rangePar.first++;\n            if (rangePar.first != rangePar.second) {\n                // Move to the sibling.\n                pindex = rangePar.first->second;\n                break;\n            } else {\n                // Move up further.\n                pindex = pindexPar;\n                nHeight--;\n                continue;\n            }\n        }\n    }\n\n    // Check that we actually traversed the entire map.\n    assert(nNodes == forward.size());\n}\n\nstd::string CBlockFileInfo::ToString() const\n{\n    return strprintf(\"CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)\", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601DateTime(nTimeFirst), FormatISO8601DateTime(nTimeLast));\n}\n\nCBlockFileInfo* GetBlockFileInfo(size_t n)\n{\n    return &vinfoBlockFile.at(n);\n}\n\nvoid SetFullSyncMode(bool state) {\n    fFullSyncMode = state;\n}\n\nbool isFullSyncMode() {\n    return fFullSyncMode;\n}\n\nvoid ResetPartialSync()\n{\n    pindexBestPartial = nullptr;\n    partialChain.SetTip(nullptr);\n    partialChain.SetHeightOffset(0);\n    nPartialPruneHeightDone = 0;\n\n    std::vector<uint256> removals;\n    for (auto it = mapBlockIndex.begin(); it != mapBlockIndex.end(); )\n    {\n        CBlockIndex* pindex = it->second;\n\n        if (pindex->IsPartialValid()) {\n            if (pindex->IsValid(BLOCK_VALID_TREE)) {\n                // has some main tree validity, only remove partial sync reference\n                pindex->nStatus &= ~BLOCK_PARTIAL_MASK;\n                setDirtyBlockIndex.insert(pindex);\n                it++;\n            }\n            else {\n                // only partial validity, completely remove it\n                removals.push_back(pindex->GetBlockHashPoW2());\n                setDirtyBlockIndex.erase(pindex);\n                it = mapBlockIndex.erase(it);\n                // Reclaim memory\n                delete pindex;\n            }\n        }\n        else\n            it++;\n    }\n\n    if (!removals.empty())\n    {\n        LogPrintf(\"Partial sync reset collected %d blocks for removal.\\n\", removals.size());\n        if (!pblocktree->EraseBatchSync(removals)) {\n            AbortNode(\"Failed to write to block index database\");\n        }\n    }\n\n#ifdef DEBUG_PARTIAL_SYNC\n    checkBlockIndexForPartialSync();\n#endif\n\n    nMaxSPVPruneHeight = 0;\n    PersistAndPruneForPartialSync();\n}\n\nvoid ComputeNewFilterRanges(uint64_t nWalletBirthBlockHard, uint64_t& nWalletBirthBlockSoft)\n{\n    // Once we are beyond the last checkpoint there is no filtering anymore\n    if (nWalletBirthBlockHard >= (uint64_t)Checkpoints::LastCheckPointHeight())\n    {\n        LOCK(partialChain.cs_blockFilterRanges);\n        partialChain.blockFilterRanges.clear();\n        partialChain.blockFilterRanges.shrink_to_fit();\n        LogPrintf(\"Hard birth block [%d] passed last checkpoint [%d], cleared filter ranges.\\n\", nWalletBirthBlockHard, Checkpoints::LastCheckPointHeight());\n        return;\n    }\n\n    //fixme: (UNITY) (SPV) - Look closer into this - unclear what behaviour should be if there is SPV but no wallet (or if it should be allowed at all?)\n    #ifdef ENABLE_WALLET\n    if (pactiveWallet)\n    {\n        LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:NULL);\n\n        GCSFilter::ElementSet elementSet;\n        for (const auto& [accountUUID, forAccount] : pactiveWallet->mapAccounts)\n        {\n            (unused) accountUUID;\n            std::set<CKeyID> setAddresses;\n            forAccount->GetKeys(setAddresses);\n            for (const auto& key : setAddresses)\n                elementSet.insert(std::vector<unsigned char>(key.begin(), key.end()));\n        }\n        std::vector<std::tuple<uint64_t, uint64_t>> blockFilterRanges;\n        getBlockFilterBirthAndRanges(nWalletBirthBlockHard, nWalletBirthBlockSoft, elementSet, blockFilterRanges);\n        {\n            LOCK(partialChain.cs_blockFilterRanges);\n            std::swap(blockFilterRanges, partialChain.blockFilterRanges);\n        }\n    }\n    else\n    #endif\n    {\n        nWalletBirthBlockSoft = nWalletBirthBlockHard;\n    }\n}\n\nvoid StopPartialHeaders(const std::function<void(const CBlockIndex*)>& notifyCallback)\n{\n    headerTipSignal.disconnect_all_slots();\n    ResetPartialSync();\n}\n\nbool StartPartialHeaders(int64_t time, const std::function<void(const CBlockIndex*)>& notifyCallback)\n{\n    // To ensure that context checks can be done on headers from *time* onwards, a window of\n    // at least 576 headers is required. So the youngest block that is before the requested time\n    // should have at least 576 headers before it.\n    const CBlockIndex* youngestBefore = partialChain.FindYoungest(time, [](int64_t before, const CBlockIndex* index)\n    {\n        return index->GetBlockTime() < before;\n    });\n\n    if (IsPartialSyncActive())\n    {\n        LogPrintf(\"Partial chain height = %d offset = %d.\\n\", partialChain.Height(), partialChain.HeightOffset());\n    }\n\n    if (IsPartialSyncActive() && youngestBefore && (youngestBefore->nHeight <= 576 || youngestBefore->nHeight - partialChain.HeightOffset() > 576))\n    {\n        LogPrintf(\"Partial sync continues.\\n\");\n\n        if (youngestBefore->nHeight < Checkpoints::LastCheckPointHeight())\n        {\n            // Determine the first checkpoint that comes before wallet birth date\n            int64_t nWalletBirthBlockHard = Checkpoints::LastCheckpointBeforeTime(time);\n            if (nWalletBirthBlockHard < 0)\n                nWalletBirthBlockHard = 0;\n\n            // Now determine the first checkpoint of actual interest using block filters\n            uint64_t nWalletBirthBlockSoft = Checkpoints::LastCheckPointHeight();\n\n            ComputeNewFilterRanges(nWalletBirthBlockHard, nWalletBirthBlockSoft);\n        }\n    }\n    else\n    {\n        if (IsPartialSyncActive()) // IsPartialSyncActive() => above checks for time and/or 576 window failed\n        {\n            LogPrintf(\"Partial sync in progress but starting point is too young for requested start. Sync reset.\\n\");\n            ResetPartialSync();\n        }\n\n        // Determine the first checkpoint that comes before wallet birth date\n        int64_t nWalletBirthBlockHard = Checkpoints::LastCheckpointBeforeTime(time);\n        if (nWalletBirthBlockHard < 0)\n            nWalletBirthBlockHard = 0;\n\n        // Now determine the first checkpoint of actual interest using block filters\n        uint64_t nWalletBirthBlockSoft = Checkpoints::LastCheckPointHeight();\n\n        ComputeNewFilterRanges(nWalletBirthBlockHard, nWalletBirthBlockSoft);\n\n        //fixme: (UNITY) (SPV) We don't always necessarily need to go back an entire checkpoint.\n        // We could instead look at difference in time between original birth date and checkpoint to see if its necessary\n        // Or alternatively we could just skip delta checks in the rare case where it isn't etc.\n        // However if checkpoint gaps are small enough it doesn't matter, so this is a very minor issue and possibly not worth further effort\n        // Leave this for now but revisit in future.\n\n        // Now determine the actual checkpoint we will use.\n        // This checkpoint needs to be at least 576 blocks before the one we were actually interested in, to ensure we can context check properly when we reach the actual data\n        // The largest window for context checking is the DELTA algorithm, which needs 576 blocks of prior context to work properly.\n        uint64_t nOffsetContextBirthCheckpoint = nWalletBirthBlockSoft >= 576 ? Checkpoints::LastCheckpointBeforeBlock(nWalletBirthBlockSoft-576) : 0;\n\n        if (nOffsetContextBirthCheckpoint - 576 >= (uint64_t)chainActive.Height() || !isFullSyncMode())\n        {\n            // inititalize partial sync\n            partialChain.SetHeightOffset(nOffsetContextBirthCheckpoint);\n            CBlockIndex* index = InsertBlockIndex(Params().Checkpoints().find(nOffsetContextBirthCheckpoint)->second.hash);\n            index->nHeight = nOffsetContextBirthCheckpoint;\n            index->RaisePartialValidity(BLOCK_PARTIAL_TREE);\n            partialChain.SetTip(index);\n            pindexBestPartial = index;\n\n            setDirtyBlockIndex.insert(index);\n\n            LogPrintf(\"Partial headers started from built-in checkpoint with height=%d\\n\", nOffsetContextBirthCheckpoint);\n\n            // from now IsPartialSyncActive() == true, as the offset is set and the partial chain has at least one entry\n        }\n        else\n        {\n            LogPrintf(\"Partial headers NOT started started as full chain is ahead of required offset, height=%d offset=%d\\n\", chainActive.Height(), nOffsetContextBirthCheckpoint);\n            return false;\n        }\n    }\n\n    headerTipSignal.connect(notifyCallback);\n    return true;\n}\n\nvoid SetMaxSPVPruneHeight(int height)\n{\n    nMaxSPVPruneHeight = height;\n}\n\nclass CMainCleanup\n{\npublic:\n    CMainCleanup() {}\n    ~CMainCleanup() {\n        // block headers\n        BlockMap::iterator it1 = mapBlockIndex.begin();\n        for (; it1 != mapBlockIndex.end(); it1++)\n            delete (*it1).second;\n        mapBlockIndex.clear();\n    }\n} instance_of_cmaincleanup;\n"
  },
  {
    "path": "src/validation/validation.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef VALIDATION_VALIDATION_H\n#define VALIDATION_VALIDATION_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <compat/sys.h> // For PLATFORM_MOBILE define\n\n#include \"amount.h\"\n#include \"coins.h\"\n#include \"fs.h\"\n#include \"policy/feerate.h\"\n#include \"script/script_error.h\"\n#include \"sync.h\"\n#include \"chain.h\"\n\n#include <algorithm>\n#include <exception>\n#include <map>\n#include <set>\n#include <stdint.h>\n#include <string>\n#include <utility>\n#include <vector>\n#include \"consensus/tx_verify.h\"\n#include \"txmempool.h\"\n\n#include <script/interpreter.h>\n\n#include <atomic>\n\n#include \"uint256.h\"\n\n#include <LRUCache/LRUCache11.hpp>\n\n#if defined(__APPLE__) && defined(__MACH__)\n#include <TargetConditionals.h>\n#endif\n\n#ifdef PLATFORM_MOBILE\n#define VALIDATION_MOBILE\n#endif\nclass CBlockIndex;\nclass CBlockTreeDB;\nclass CChainParams;\nclass CCoinsViewDB;\nclass CInv;\nclass CConnman;\nclass CScriptCheck;\nclass CBlockPolicyEstimator;\nclass CTxMemPool;\nclass CValidationInterface;\nclass CValidationState;\n\n\nstruct PrecomputedTransactionData;\nstruct LockPoints;\n\nclass CWitViewDB;\n\nenum FlushStateMode {\n    FLUSH_STATE_NONE,\n    FLUSH_STATE_IF_NEEDED,\n    FLUSH_STATE_PERIODIC,\n    FLUSH_STATE_ALWAYS\n};\n\n/** Default for accepting alerts from the P2P network. */\nstatic const bool DEFAULT_ALERTS = true;\n/** Default for DEFAULT_WHITELISTRELAY. */\nstatic const bool DEFAULT_WHITELISTRELAY = true;\n/** Default for DEFAULT_WHITELISTFORCERELAY. */\nstatic const bool DEFAULT_WHITELISTFORCERELAY = true;\n/** Default for -minrelaytxfee, minimum relay fee for transactions */\nstatic const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;\n//! -maxtxfee default\nstatic const CAmount DEFAULT_TRANSACTION_MAXFEE = 2 * COIN;\n//! Discourage users to set fees higher than this amount (in satoshis) per kB\nstatic const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;\n//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)\nstatic const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB;\n/** Default for -limitancestorcount, max number of in-mempool ancestors */\nstatic const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;\n/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */\nstatic const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101;\n/** Default for -limitdescendantcount, max number of in-mempool descendants */\nstatic const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;\n/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */\nstatic const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;\n/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */\nstatic const unsigned int DEFAULT_MEMPOOL_EXPIRY = 1;\n/** Maximum kilobytes for transactions to store for processing during reorg */\nstatic const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000;\n#if defined(VALIDATION_MOBILE)\n/** The maximum size of a blk?????.dat file (since 0.8) */\nstatic const unsigned int MAX_BLOCKFILE_SIZE = 0x2000000; // 32 MiB\n/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */\nstatic const unsigned int BLOCKFILE_CHUNK_SIZE = 0x0400000; // 4 MiB\n#else\n/** The maximum size of a blk?????.dat file (since 0.8) */\nstatic const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB\n/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */\nstatic const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB\n#endif\n/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */\nstatic const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB\n/** Dust Soft Limit, allowed with additional fee per output */\nstatic const int64_t DUST_SOFT_LIMIT = 100000000; // 1 NLG\n/** Dust Hard Limit, ignored as wallet inputs (mininput default) */\nstatic const int64_t DUST_HARD_LIMIT = 1000;   // 0.00001 NLG mininput\n/** Maximum number of script-checking threads allowed */\nstatic const int MAX_SCRIPTCHECK_THREADS = 16;\n/** -par default (number of script-checking threads, 0 = auto) */\nstatic const int DEFAULT_SCRIPTCHECK_THREADS = 0;\n/** Number of blocks that can be requested at any given time from a single peer. */\nstatic const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 64;\n/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */\nstatic const unsigned int BLOCK_STALLING_TIMEOUT = 2;\n/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends\n *  less than this number, we reached its tip. Changing this value is a protocol upgrade. */\nstatic const unsigned int MAX_HEADERS_RESULTS = 2000;\nstatic const unsigned int MAX_RHEADERS_RESULTS = 4000;\n/** Maximum depth of blocks we're willing to serve as compact blocks to peers\n *  when requested. For older blocks, a regular BLOCK response will be sent. */\nstatic const int MAX_CMPCTBLOCK_DEPTH = 5;\n/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */\nstatic const int MAX_BLOCKTXN_DEPTH = 10;\n/** Size of the \"block download window\": how far ahead of our current height do we fetch?\n *  Larger windows tolerate larger download speed differences between peer, but increase the potential\n *  degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning\n *  harder). We'll probably want to make this a per-peer adaptive value at some point. */\nstatic const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;\n/** Time to wait (in seconds) between writing blocks/block index to disk.\n *  Use a very short write interval on mobile platforms as it is very likely (and normal procedure)\n *  to be terminated without notice. Also the writing is quite fast as there is little work in pure SPV mode.\n*/\n#if defined(VALIDATION_MOBILE)\nstatic const unsigned int DATABASE_WRITE_INTERVAL = 10;\n#else\nstatic const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;\n#endif\n/** Time to wait (in seconds) between flushing chainstate to disk. */\nstatic const unsigned int DATABASE_FLUSH_INTERVAL = 2 * 60 * 60;\n/** Maximum length of reject messages. */\nstatic const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;\n/** Average delay between local address broadcasts in seconds. */\nstatic const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60;\n/** Average delay between peer address broadcasts in seconds. */\nstatic const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;\n/** Average delay between trickled inventory transmissions in seconds.\n *  Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */\nstatic const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;\n/** Maximum number of inventory items to send per transmission.\n *  Limits the impact of low-fee transaction floods. */\nstatic const unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;\n/** Average delay between feefilter broadcasts in seconds. */\nstatic const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;\n/** Maximum feefilter broadcast delay after significant change. */\nstatic const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;\n/** Block download timeout base, expressed in microseconds */\nstatic const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 10000000;\n/** Additional block download timeout per parallel downloading peer, expressed in microseconds*/\nstatic const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 5000000;\n\nstatic const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;\n/** Maximum age of our tip in seconds for us to be considered current for fee estimation */\nstatic const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;\n\n/** Default for -permitbaremultisig */\nstatic const bool DEFAULT_PERMIT_BAREMULTISIG = true;\nstatic const bool DEFAULT_CHECKPOINTS_ENABLED = true;\nstatic const bool DEFAULT_TXINDEX = false;\nstatic const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;\n/** Default for -persistmempool */\nstatic const bool DEFAULT_PERSIST_MEMPOOL = true;\n/** Default for -mempoolreplacement */\nstatic const bool DEFAULT_ENABLE_REPLACEMENT = true;\n/** Default for using fee filter */\nstatic const bool DEFAULT_FEEFILTER = true;\n\n/** Maximum number of headers to announce when relaying blocks with headers message.*/\nstatic const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;\n\n//fixme: (PHASE5) Temporary increase from 10 (if lots of absent witnesses a miner could send quite a few unconnecting headers)\n//re-look at special logic for this.\n/** Maximum number of unconnecting headers announcements before DoS score */\nstatic const int MAX_UNCONNECTING_HEADERS = 200;\n\nstatic const bool DEFAULT_PEERBLOOMFILTERS = true;\n\n/** Default for -stopatheight */\nstatic const int DEFAULT_STOPATHEIGHT = 0;\n\n/** if disabled full sync and validation will be skipped, ie. no chain is build. */\nstatic const bool DEFAULT_FULL_SYNC_MODE = true;\n\nstruct BlockHasher\n{\n    size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }\n};\n\nextern CScript COINBASE_FLAGS;\nextern RecursiveMutex cs_main;\nextern CBlockPolicyEstimator feeEstimator;\nextern CTxMemPool mempool;\nusing BlockMap = std::unordered_map<uint256, CBlockIndex*, BlockHasher>;\n\n#if defined(__clang__)\n// Specialize BlockMap [] operator to ensure that it is only used for\n// (valid) lookup and never triggers an insert (which is considered a bug).\n// Unfortunatly this specialization won't work on GCC (why?) so it only detected on clang\ntemplate<> inline BlockMap::mapped_type& BlockMap::operator [](const uint256& key)\n{\n    const auto i = find(key);\n    assert(i != end());\n    return (*i).second;\n}\n#endif\n\nextern BlockMap mapBlockIndex;\nextern uint64_t nLastBlockTx;\nextern uint64_t nLastBlockSize;\nextern uint64_t nLastBlockWeight;\nextern const std::string strMessageMagic;\nextern Mutex csBestBlock;\nextern std::condition_variable cvBlockChange;\nextern std::atomic_bool fImporting;\nextern bool fReindex;\nextern bool fReverseHeaders;\nextern int nScriptCheckThreads;\nextern bool fTxIndex;\nextern bool fIsBareMultisigStd;\nextern bool fRequireStandard;\nextern bool fCheckBlockIndex;\nextern bool fCheckpointsEnabled;\nextern size_t nCoinCacheUsage;\n/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */\nextern CFeeRate minRelayTxFee;\n/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */\nextern CAmount maxTxFee;\nextern bool fAlerts;\n/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */\nextern int64_t nMaxTipAge;\nextern bool fEnableReplacement;\n\n/** Block hash whose ancestors we will assume to have valid scripts without checking them. */\nextern uint256 hashAssumeValid;\n\n/** Cache to prevent repeated calls of same expensive CheckProofOfWork in certain situations */\ninline lru11::Cache<uint256, bool, lru11::NullLock, std::unordered_map<uint256, typename std::list<lru11::KeyValuePair<uint256, bool>>::iterator, BlockHasher>> checkedPoWCache(2000, 100);\n\n/** Best header we've seen so far (used for getheaders queries' starting points). */\nextern CBlockIndex *pindexBestHeader;\n\n/** Best header sofar connecting to the partial chain. */\nextern CBlockIndex *pindexBestPartial;\n\n/** Minimum disk space required - used in CheckDiskSpace() */\nstatic const uint64_t nMinDiskSpace = 52428800;\n\n/** Pruning-related variables and constants */\n/** True if any block files have ever been pruned. */\nextern bool fHavePruned;\n/** True if we're running in -prune mode. */\nextern bool fPruneMode;\n/** Number of MiB of block files that we're trying to stay below. */\nextern uint64_t nPruneTarget;\n/** Track pruning of partial chain to optimize & prevent duplicate erase */\nextern int nPartialPruneHeightDone;\n\n/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */\nstatic const unsigned int MIN_BLOCKS_TO_KEEP = 288;\n\nstatic const signed int DEFAULT_CHECKBLOCKS = 6;\nstatic const unsigned int DEFAULT_CHECKLEVEL = 3;\n\n// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)\n// At 1MB per block, 288 blocks = 288MB.\n// Add 15% for Undo data = 331MB\n// Add 20% for Orphan block rate = 397MB\n// We want the low water mark after pruning to be at least 397 MB and since we prune in\n// full block file chunks, we need the high water mark which triggers the prune to be\n// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB\n// Setting the target to > than 550MB will make it likely we can respect the target.\nstatic const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;\n\n/** \n * Process an incoming block. This only returns after the best known valid\n * block is made active. Note that it does not, however, guarantee that the\n * specific block passed to it has been checked for validity!\n *\n * If you want to *possibly* get feedback on whether pblock is valid, you must\n * install a CValidationInterface (see validation/validationinterface.h) - this will have\n * its BlockChecked method called whenever *any* block completes validation.\n *\n * Note that we guarantee that either the proof-of-work is valid on pblock, or\n * (and possibly also) BlockChecked will have been called.\n * \n * Call without cs_main held.\n *\n * @param[in]   pblock  The block we want to process.\n * @param[in]   fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.\n * @param[out]  fNewBlock A boolean which is set to indicate if the block was first received via this call\n * @param[in]  fAssumePOWGood A boolean to indicate that the POW can be assumed to be correct\n * @param[in]   activateBestChain will allow to bypass the activate best chain logic (for priority block downloads)\n * @return True if state.IsValid()\n */\nbool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool* fNewBlock, bool fAssumePOWGood, bool activateBestChain);\n\n/**\n * Process incoming block headers.\n *\n * Call without cs_main held.\n *\n * @param[in]  block The block headers themselves\n * @param[out] state This may be set to an Error state if any error occurred processing them\n * @param[in]  chainparams The params for the chain we want to connect to\n * @param[in]  fAssumePOWGood A boolean to indicate that the POW can be assumed to be correct\n * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers\n */\nbool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=NULL, bool fAssumePOWGood = false);\n\n/** Check whether enough disk space is available for an incoming block */\nbool CheckDiskSpace(uint64_t nAdditionalBytes = 0);\n/** Import blocks from an external file */\nbool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL);\n/** Initialize a new block tree database + block data on disk */\nbool InitBlockIndex(const CChainParams& chainparams);\n/** Load the block tree and coins database from disk */\nbool LoadBlockIndex(const CChainParams& chainparams);\n/** Unload database information */\nvoid UnloadBlockIndex();\n/** Run instances of script checking worker threads */\nvoid StartScriptCheckWorkerThreads(int threads_num);\n/** Stop all of the script checking worker threads */\nvoid StopScriptCheckWorkerThreads();\n/** Check whether we are doing an initial block download (synchronizing from disk or network) */\nbool IsInitialBlockDownload();\n/** Retrieve a transaction (from memory pool, or from disk, if possible) */\nbool GetTransaction(const uint256 &hash, CTransactionRef &tx, const CChainParams& params, uint256 &hashBlock, bool fAllowSlow = false);\n/** Find the best known block, and make it the tip of the block chain */\nbool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());\n\nstruct BlockSubsidy\n{\n    BlockSubsidy(CAmount mining_, CAmount witness_, CAmount dev_)\n    : mining(mining_)\n    , witness(witness_)\n    , dev(dev_)\n    , total(mining_ + witness_ + dev_)\n    {\n    }\n    CAmount mining;\n    CAmount witness;\n    CAmount dev;\n    CAmount total;\n};\n\n/** The reward that must be paid out per block */\nBlockSubsidy GetBlockSubsidy(uint64_t nHeight);\ninline std::string devSubsidyAddress1 = \"03ae258dc3463de883e9fbda5239353fe9dc98805cf31800d5a6eeaa3ed4afcc70\";\ninline std::string devSubsidyAddress2 = \"03f0ea45eb7fcf57c6f0f47f88004fd5a82641721890b9e6f4ae392efb858ce21e\";\n\n/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */\ndouble GuessVerificationProgress(CBlockIndex* pindex);\n\n/**\n *  Mark one block file as pruned.\n */\nvoid PruneOneBlockFile(const int fileNumber);\n\n/** Create a new block index entry for a given block hash */\nCBlockIndex * InsertBlockIndex(uint256 hash);\n/** Flush all state, indexes and buffers to disk. */\nvoid FlushStateToDisk();\n/** Prune block files and flush state to disk. */\nvoid PruneAndFlush();\n/** Prune block files up to a given height */\nvoid PruneBlockFilesManual(int nManualPruneHeight);\n/**\n * Persist and prune block index and blk/rev files if using partial sync only\n * Deleting block indexes unnesesary for partial sync reduces database size, memory usage and\n * results in faster startup times.\n * Call periodically to prevent re-download after forced kill (= normal iOS behavior) or crash\n * also call at shutdown.\n*/\nvoid PersistAndPruneForPartialSync(bool periodic=false);\n/** (try to) add transaction to memory pool\n * plTxnReplaced will be appended to with all transactions replaced from mempool **/\nbool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,\n                        bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced = NULL,\n                        bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);\n\n/**\n * In pure partial sync expire transactions that stay in the memorypool too long.\n * It's for example possible that created transaction pass local spv validation but are\n * rejected by the full validation.\n */\nint ExpireMempoolForPartialSync(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* tip);\n\n/** Convert CValidationState to a human-readable message for logging */\nstd::string FormatStateMessage(const CValidationState &state);\n\n/** Apply the effects of this transaction on the UTXO set represented by view */\nvoid UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, uint32_t nHeight, uint32_t nTxIndex);\n\n/** Transaction validation functions */\n\n/**\n * Check if transaction will be final in the next block to be created.\n *\n * Calls IsFinalTx() with current block height and appropriate block time.\n *\n * See consensus/consensus.h for flag definitions.\n */\nbool CheckFinalTx(const CTransaction &tx, const CChain& chain, int flags = -1);\n\n/**\n * Test whether the LockPoints height and time are still valid on the current chain\n */\nbool TestLockPointValidity(const LockPoints* lp);\n\n/**\n * Check if transaction will be BIP 68 final in the next block to be created.\n *\n * Simulates calling SequenceLocks() with data from the tip of the current active chain.\n * Optionally stores in LockPoints the resulting height and time calculated and the hash\n * of the block needed for calculation or skips the calculation and uses the LockPoints\n * passed in for evaluation.\n * The LockPoints should not be considered valid if CheckSequenceLocks returns false.\n *\n * See consensus/consensus.h for flag definitions.\n */\nbool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false);\n\n/**\n * Closure representing one script verification\n * Note that this stores references to the spending transaction \n */\nclass CScriptCheck\n{\nprivate:\n    CKeyID signingKeyID;\n    CScript scriptPubKey;\n    CAmount amount;\n    const CTransaction *ptxTo;\n    unsigned int nIn;\n    unsigned int nFlags;\n    bool cacheStore;\n    ScriptError error;\n    PrecomputedTransactionData *txdata;\n    ScriptVersion scriptVer;\n\npublic:\n\n    CScriptCheck(): signingKeyID(CKeyID()), amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR), scriptVer(SCRIPT_V1) {}\n    CScriptCheck(CKeyID signingKeyID_, const CScript& scriptPubKeyIn, const CAmount amountIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn, ScriptVersion scriptVerIn)\n    : signingKeyID(signingKeyID_)\n    , scriptPubKey(scriptPubKeyIn)\n    , amount(amountIn)\n    , ptxTo(&txToIn)\n    , nIn(nInIn)\n    , nFlags(nFlagsIn)\n    , cacheStore(cacheIn)\n    , error(SCRIPT_ERR_UNKNOWN_ERROR)\n    , txdata(txdataIn)\n    , scriptVer(scriptVerIn)\n    { }\n\n    bool operator()();\n\n    void swap(CScriptCheck &check) {\n        scriptPubKey.swap(check.scriptPubKey);\n        std::swap(ptxTo, check.ptxTo);\n        std::swap(amount, check.amount);\n        std::swap(nIn, check.nIn);\n        std::swap(nFlags, check.nFlags);\n        std::swap(cacheStore, check.cacheStore);\n        std::swap(error, check.error);\n        std::swap(txdata, check.txdata);\n        std::swap(signingKeyID, check.signingKeyID);\n        std::swap(scriptVer, check.scriptVer);\n    }\n\n    ScriptError GetScriptError() const { return error; }\n};\n\n/** Functions for disk access for blocks */\nbool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const CChainParams& params);\n\n/** Functions for validating blocks and updating the block tree */\n\n/** Context-independent validity checks */\nbool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fAssumePOWGood = false);\n\n/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */\nbool TestBlockValidity(CChain& chain, CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true, CCoinsViewCache* cacheOverride = nullptr);\n\n/** Check whether segregated signatures are required for block. */\nbool IsSegSigEnabled(const CBlockIndex* pindexPrev);\n\n/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */\nbool RewindBlockIndex(const CChainParams& params);\n\n/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */\nclass CVerifyDB {\npublic:\n    CVerifyDB();\n    ~CVerifyDB();\n    bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth);\n};\n\n/** Find the last common block between the parameter chain and a locator. */\nCBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);\n\n/** Mark a block as precious and reorganize. */\nbool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);\n\n/** Mark a block as invalid. */\nbool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);\n\n/** Remove invalidity status from a block and its descendants. */\nbool ResetBlockFailureFlags(CBlockIndex *pindex);\n\n/** Remove invalidity status from a block. */\nbool ResetBlockFailureFlagsForSingleBlock(CBlockIndex *pindex);\n\n/** The currently-connected chain of blocks (protected by cs_main). */\nextern CChain chainActive;\n\n/** The currently-connected chain of header, POW only validated (protected by cs_main). */\nextern CPartialChain partialChain;\n\nextern bool fSPV;\n//! Chain height for active chain (either chainActive or partialChain)\nint ChainHeight();\n\n//! Chain tip for active chain (either chainActive or partialChain)\nCBlockIndex* chainTip();\n\n//! Chain previous for active chain (either chainActive or partialChain)\nCBlockIndex* chainPrevTip();\n\n/** Global variable that points to the coins database (protected by cs_main) */\nextern CCoinsViewDB *pcoinsdbview;\n\n/** Global variable that points to the active CCoinsView (protected by cs_main) */\nextern CCoinsViewCache *pcoinsTip;\n\n/** Global variable that points to the active block tree (protected by cs_main) */\nextern CBlockTreeDB *pblocktree;\n\nstruct CBlockIndexWorkComparator\n{\n    bool operator()(CBlockIndex *pa, CBlockIndex *pb) const {\n        // First sort by most total work, ...\n        if (pa->nChainWork > pb->nChainWork) return false;\n        if (pa->nChainWork < pb->nChainWork) return true;\n\n        // (Phase 3) PoW blocks at same height as witness blocks - always make the PoW blocks rank higher.\n        if (pa->nHeight == pb->nHeight)\n        {\n            if (pa->nVersionPoW2Witness == 0 && pb->nVersionPoW2Witness != 0)\n            {\n                return false;\n            }\n            if (pa->nVersionPoW2Witness != 0 && pb->nVersionPoW2Witness == 0)\n            {\n                return true;\n            }\n        }\n\n        // ... then by earliest time received, ...\n        if (pa->nSequenceId < pb->nSequenceId) return false;\n        if (pa->nSequenceId > pb->nSequenceId) return true;\n\n        // Use pointer address as tie breaker (should only happen with blocks\n        // loaded from disk, as those all have id 0).\n        if (pa < pb) return false;\n        if (pa > pb) return true;\n\n        // Identical blocks.\n        return false;\n    }\n};\n\n//fixme: (FUT) (MED) (REFACTOR) Move DisconnectBlock/ConnectBlock/setBlockIndexCandidates/ContextualCheckBlockHeader/ContextualCheckBlock/CheckInputs/FlushStateToDisk/FindFilesToPruneManual/FindFilesToPrune/UpdateMempoolForReorg out of header files they should be source file only - this will require moving all the chain connect/disconnect/forceactivate stuff into their own shared source file\n//validation.cpp is too large and needs to shrink.\n\nvoid UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool);\n\n// Force mempool to empty\nvoid EmptyMempool(CTxMemPool& pool);\n\n// See definition for documentation\nbool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0, bool fFlushPartialSync=false);\nvoid FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);\nvoid FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);\n\nbool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const std::vector<CWitnessTxBundle>* pWitnessBundles, std::vector<CScriptCheck> *pvChecks = NULL);\n\n/**\n * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and\n * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be\n * missing the data for the block.\n */\nextern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;\n\nenum DisconnectResult\n{\n    DISCONNECT_OK,      // All good.\n    DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.\n    DISCONNECT_FAILED   // Something else went wrong.\n};\n\n/** Undo the effects of this block (with given index) on the UTXO set represented by coins.\n *  When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */\nDisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);\n\n/** Apply the effects of this block (with given index) on the UTXO set represented by coins.\n *  Validity checks that depend on the UTXO set are also done; ConnectBlock()\n *  can fail if those validity checks fail (among other reasons). */\nbool ConnectBlock(CChain& chain, const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false, bool fVerifyWitness=true, bool fVerifyWitnessDelta=true, bool fDoScriptChecks=true);\n\n/** Context-dependent validity checks.\n *  By \"context\", we mean only the previous block headers, but not the UTXO\n *  set; UTXO-related validity checks are done in ConnectBlock(). */\nbool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime);\n\nbool ContextualCheckBlock(const CBlock& block, CValidationState& state, const CChainParams& chainParams, const CBlockIndex* pindexPrev, CChain& chainOverride, CCoinsViewCache* viewOverride=nullptr, bool doUTXOChecks=false);\n\nbool UpgradeBlockIndex(const CChainParams& chainparams, int nPreviousVersion, int nCurrentVersion);\n\n/**\n * Return the spend height, which is one more than the inputs.GetBestBlock().\n * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)\n * This is also true for mempool checks.\n */\nint GetSpendHeight(const CCoinsViewCache& inputs);\n\n/**\n * Determine what nVersion a new block should use.\n */\nint32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);\n\n/** Reject codes greater or equal to this can be returned by AcceptToMemPool\n * for transactions, to signal internal conditions. They cannot and should not\n * be sent over the P2P network.\n */\nstatic const unsigned int REJECT_INTERNAL = 0x100;\n/** Too high fee. Can not be triggered by P2P transactions */\nstatic const unsigned int REJECT_HIGHFEE = 0x100;\n/** Transaction is already known (either in mempool or blockchain) */\nstatic const unsigned int REJECT_ALREADY_KNOWN = 0x101;\n/** Transaction conflicts with a transaction already known */\nstatic const unsigned int REJECT_CONFLICT = 0x102;\n\n/** Get block file info entry for one block file */\nCBlockFileInfo* GetBlockFileInfo(size_t n);\n\n/** Dump the mempool to disk. */\nvoid DumpMempool();\n\n/** Load the mempool from disk. */\nbool LoadMempool();\n\n/** Full sync and validation. */\nvoid SetFullSyncMode(bool state);\nbool isFullSyncMode();\n\nvoid StopPartialHeaders(const std::function<void(const CBlockIndex*)>& notifyCallback);\nbool StartPartialHeaders(int64_t time, const std::function<void(const CBlockIndex*)>& notifyCallback);\nvoid SetMaxSPVPruneHeight(int height);\n\n/**\n * Compute new filter ranges, stored in partialChain.blockFilterRanges.\n * Filter range starts at nWalletBirthBlockHard and moves nWalletBirthBlockSoft down to the\n * first block that might contain data for the activeWallet.\n */\nvoid ComputeNewFilterRanges(uint64_t nWalletBirthBlockHard, uint64_t& nWalletBirthBlockSoft);\n\n/** Transaction hash from outpoint. Even if it is index based. */\nbool GetTxHash(const COutPoint& outpoint, uint256& txHash);\n\n#endif\n"
  },
  {
    "path": "src/validation/validation_mempool.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n\n#include \"validation/validation.h\"\n#include \"validation/validationinterface.h\"\n#include \"validation/witnessvalidation.h\"\n#include <consensus/validation.h>\n\n#include \"init.h\"\n#include <unity/appmanager.h>\n#include \"policy/policy.h\"\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"timedata.h\"\n#include \"tinyformat.h\"\n#include \"txdb.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"util/moneystr.h\"\n#include \"chainparams.h\"\n#include \"witnessutil.h\"\n\nstatic const uint64_t MEMPOOL_DUMP_VERSION = 1;\n\nstatic void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {\n    int expired = pool.Expire(GetTime() - age);\n    if (expired != 0) {\n        LogPrint(BCLog::MEMPOOL, \"Expired %i transactions from the memory pool\\n\", expired);\n    }\n\n    std::vector<COutPoint> vNoSpendsRemaining;\n    pool.TrimToSize(limit, &vNoSpendsRemaining);\n    for(const COutPoint& removed : vNoSpendsRemaining)\n        pcoinsTip->Uncache(removed);\n}\n\n//fixme: (FUT) (REFACTOR) (DEDUP) (see: LimitMempoolSize)\nvoid EmptyMempool(CTxMemPool& pool)\n{\n    int expired = pool.Expire(std::numeric_limits<int64_t>::max());\n    if (expired != 0) {\n        LogPrint(BCLog::MEMPOOL, \"Expired %i transactions from the memory pool\\n\", expired);\n    }\n\n    std::vector<COutPoint> vNoSpendsRemaining;\n    pool.TrimToSize(GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, &vNoSpendsRemaining);\n    for(const COutPoint& removed : vNoSpendsRemaining)\n        pcoinsTip->Uncache(removed);\n}\n\n/* Make mempool consistent after a reorg, by re-adding or recursively erasing\n * disconnected block transactions from the mempool, and also removing any\n * other transactions from the mempool that are no longer valid given the new\n * tip/height.\n *\n * Note: we assume that disconnectpool only contains transactions that are NOT\n * confirmed in the current chain nor already in the mempool (otherwise,\n * in-mempool descendants of such transactions would be removed).\n *\n * Passing fAddToMempool=false will skip trying to add the transactions back,\n * and instead just erase from the mempool as needed.\n */\n\nvoid UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool)\n{\n    AssertLockHeld(cs_main);\n    std::vector<uint256> vHashUpdate;\n    // disconnectpool's insertion_order index sorts the entries from\n    // oldest to newest, but the oldest entry will be the last tx from the\n    // latest mined block that was disconnected.\n    // Iterate disconnectpool in reverse, so that we add transactions\n    // back to the mempool starting with the earliest transaction that had\n    // been previously seen in a block.\n    auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();\n    while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {\n        // ignore validation errors in resurrected transactions\n        CValidationState stateDummy;\n        if (!fAddToMempool || (*it)->IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, *it, false, NULL, NULL, true)) {\n            // If the transaction doesn't make it in to the mempool, remove any\n            // transactions that depend on it (which would now be orphans).\n            mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);\n        } else if (mempool.exists((*it)->GetHash())) {\n            vHashUpdate.push_back((*it)->GetHash());\n        }\n        ++it;\n    }\n    disconnectpool.queuedTx.clear();\n    // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have\n    // no in-mempool children, which is generally not true when adding\n    // previously-confirmed transactions back to the mempool.\n    // UpdateTransactionsFromBlock finds descendants of any transactions in\n    // the disconnectpool that were added back and cleans up the mempool state.\n    mempool.UpdateTransactionsFromBlock(vHashUpdate);\n\n    // We also need to remove any now-immature transactions\n    mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);\n    // Re-limit mempool size, in case we added any transactions\n    LimitMempoolSize(mempool, GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg(\"-mempoolexpiry\", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);\n}\n\nstatic bool IsCurrentForFeeEstimation()\n{\n    AssertLockHeld(cs_main);\n    if (IsInitialBlockDownload())\n        return false;\n    if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))\n        return false;\n    if (chainActive.Height() < pindexBestHeader->nHeight - 1)\n        return false;\n    return true;\n}\n\nstatic bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,\n                              bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,\n                              bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)\n{\n    bool fPartialChecksOnly =    IsPartialSyncActive()\n                              && partialChain.Height() > chainActive.Height()\n                              // for GetMedianTimePast calculation minimum depth of 6 is required, should pass as we\n                              // keep a much longer partial chain for difficulty verification and fork recovery\n                              && partialChain.Height() - partialChain.HeightOffset() > 6;\n\n    const CChain& chain = fPartialChecksOnly ? partialChain : chainActive;\n\n    const CTransaction& tx = *ptx;\n    const uint256 hash = tx.GetHash();\n    AssertLockHeld(cs_main);\n    if (pfMissingInputs)\n        *pfMissingInputs = false;\n\n    if (!CheckTransaction(tx, state))\n        return false; // state filled in by CheckTransaction\n\n    if (!CheckTransactionContextual(tx, state, chain.Height()))\n        return false; // state filled in by CheckTransaction\n\n    // Coinbase is only valid in a block, not as a loose transaction\n    if (tx.IsCoinBase())\n        return state.DoS(100, false, REJECT_INVALID, \"coinbase\");\n\n    // Reject transactions with witness before segregated witness activates\n    bool segsigEnabled = IsSegSigEnabled(chain.TipPrev());\n    bool hasSegregatedSignatures = tx.HasSegregatedSignatures();\n    if (segsigEnabled && !hasSegregatedSignatures)\n    {\n        return state.DoS(0, false, REJECT_NONSTANDARD, \"non-segregated-sigdata-after-segregated-signatures-active\", true);\n    }\n    if (!segsigEnabled && hasSegregatedSignatures)\n    {\n        return state.DoS(0, false, REJECT_NONSTANDARD, \"segregated-sigdata-before-segregated-signatures-active\", true);\n    }\n\n    if (!fPartialChecksOnly)\n    {\n        // Rather not work on nonstandard transactions (unless -testnet/-regtest)\n        std::string reason;\n        int nPoW2Version = GetPoW2Phase(chainActive.Tip());\n        if (fRequireStandard && !IsStandardTx(tx, reason, nPoW2Version, segsigEnabled))\n            return state.DoS(0, false, REJECT_NONSTANDARD, reason);\n    }\n\n    // Only accept nLockTime-using transactions that can be mined in the next\n    // block; we don't want our mempool filled up with transactions that can't\n    // be mined yet.\n    if (!CheckFinalTx(tx, chain, STANDARD_LOCKTIME_VERIFY_FLAGS))\n        return state.DoS(0, false, REJECT_NONSTANDARD, \"non-final\");\n\n    // is it already in the memory pool?\n    if (pool.exists(hash))\n        return state.Invalid(false, REJECT_ALREADY_KNOWN, \"txn-already-in-mempool\");\n\n    // Check for conflicts with in-memory transactions\n    std::set<uint256> setConflicts;\n    {\n        LOCK(pool.cs); // protect pool.mapNextTx\n        for(const CTxIn &txin : tx.vin)\n        {\n            auto itConflicting = pool.mapNextTx.find(txin.GetPrevOut());\n            if (itConflicting != pool.mapNextTx.end())\n            {\n                const CTransaction *ptxConflicting = itConflicting->second;\n                if (!setConflicts.count(ptxConflicting->GetHash()))\n                {\n                    // Allow opt-out of transaction replacement by setting\n                    // nSequence >= maxint-1 on all inputs.\n                    //\n                    // maxint-1 is picked to still allow use of nLockTime by\n                    // non-replaceable transactions. All inputs rather than just one\n                    // is for the sake of multi-party protocols, where we don't\n                    // want a single party to be able to disable replacement.\n                    //\n                    // The opt-out ignores descendants as anyone relying on\n                    // first-seen mempool behavior should be checking all\n                    // unconfirmed ancestors anyway; doing otherwise is hopelessly\n                    // insecure.\n                    bool fReplacementOptOut = true;\n                    if (fEnableReplacement)\n                    {\n                        if (IsOldTransactionVersion(tx.nVersion))\n                        {\n                            for(const CTxIn &_txin : ptxConflicting->vin)\n                            {\n                                if (_txin.GetSequence(ptxConflicting->nVersion) < std::numeric_limits<unsigned int>::max()-1)\n                                {\n                                    fReplacementOptOut = false;\n                                    break;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            for(const CTxIn &_txin : ptxConflicting->vin)\n                            {\n                                if (_txin.FlagIsSet(CTxInFlags::OptInRBF))\n                                {\n                                    fReplacementOptOut = false;\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                    if (fReplacementOptOut)\n                        return state.Invalid(false, REJECT_CONFLICT, \"txn-mempool-conflict\");\n\n                    setConflicts.insert(ptxConflicting->GetHash());\n                }\n            }\n        }\n    }\n\n    if (fPartialChecksOnly)\n    {\n        LOCK(pool.cs);\n        CTxMemPoolEntry entry(ptx, 0, nAcceptTime, chain.Height(), 0, 0, LockPoints());\n\n        // Store transaction in memory pool\n        pool.addUnchecked(hash, entry, false);\n    }\n    else\n    {\n        CCoinsView dummy;\n        CCoinsViewCache view(&dummy);\n\n        CAmount nValueIn = 0;\n        LockPoints lp;\n        {\n            LOCK(pool.cs);\n            CCoinsViewMemPool viewMemPool(pcoinsTip, pool);\n            view.SetBackend(viewMemPool);\n\n            // do we already have it?\n            for (size_t out = 0; out < tx.vout.size(); out++) {\n                COutPoint outpoint(hash, out);\n                bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint);\n                if (view.HaveCoin(outpoint)) {\n                    if (!had_coin_in_cache) {\n                        coins_to_uncache.push_back(outpoint);\n                    }\n                    return state.Invalid(false, REJECT_ALREADY_KNOWN, \"txn-already-known\");\n                }\n            }\n\n            // do all inputs exist?\n            for(const CTxIn txin : tx.vin) {\n                if (!pcoinsTip->HaveCoinInCache(txin.GetPrevOut())) {\n                    coins_to_uncache.push_back(txin.GetPrevOut());\n                }\n                if (!view.HaveCoin(txin.GetPrevOut())) {\n                    if (pfMissingInputs) {\n                        *pfMissingInputs = true;\n                    }\n                    return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid()\n                }\n            }\n\n            // Bring the best block into scope\n            view.GetBestBlock();\n\n            nValueIn = view.GetValueIn(tx);\n\n            // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool\n            view.SetBackend(dummy);\n\n            // Only accept BIP68 sequence locked transactions that can be mined in the next\n            // block; we don't want our mempool filled up with transactions that can't\n            // be mined yet.\n            // Must keep pool.cs for this unless we change CheckSequenceLocks to take a\n            // CoinsViewCache instead of create its own\n            if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))\n                return state.DoS(0, false, REJECT_NONSTANDARD, \"non-BIP68-final\");\n        }\n\n        if (fRequireStandard)\n        {\n            // Check for non-standard segregated signatures\n            if (tx.HasSegregatedSignatures() && !IsSegregatedSignatureDataStandard(tx, view))\n                return state.Invalid(false, REJECT_NONSTANDARD, \"bad-segregated-sigdata-nonstandard\");\n\n            // Check for non-standard pay-to-script-hash in inputs\n            if (!AreInputsStandard(tx, view))\n                return state.Invalid(false, REJECT_NONSTANDARD, \"bad-txns-nonstandard-inputs\");\n        }\n\n        int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);\n\n        CAmount nValueOut = tx.GetValueOut();\n        CAmount nFees = nValueIn-nValueOut;\n        // nModifiedFees includes any fee deltas from PrioritiseTransaction\n        CAmount nModifiedFees = nFees;\n        pool.ApplyDelta(hash, nModifiedFees);\n\n        // Keep track of transactions that spend a coinbase, which we re-scan\n        // during reorgs to ensure COINBASE_MATURITY is still met.\n        uint64_t spendsCoinbaseCount = 0;\n        for(const CTxIn &txin : tx.vin) {\n            const Coin &coin = view.AccessCoin(txin.GetPrevOut());\n            if (coin.IsCoinBase()) {\n                ++spendsCoinbaseCount;\n            }\n        }\n\n        CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),\n                              spendsCoinbaseCount, nSigOpsCost, lp);\n        \n        unsigned int nSize = entry.GetTxSize();\n        unsigned int nDiscountedSize = entry.GetTxSizeDiscounted();\n\n        // Check that the transaction doesn't have an excessive number of\n        // sigops, making it impossible to mine. Since the coinbase transaction\n        // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than\n        // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than\n        // merely non-standard transaction.\n        if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)\n            return state.DoS(0, false, REJECT_NONSTANDARD, \"bad-txns-too-many-sigops\", false,\n                strprintf(\"%d\", nSigOpsCost));\n\n        CAmount mempoolRejectFee = pool.GetMinFee(GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nDiscountedSize);\n        if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {\n            return state.DoS(0, false, REJECT_INSUFFICIENTFEE, \"mempool min fee not met\", false, strprintf(\"%d < %d\", nFees, mempoolRejectFee));\n        }\n\n        // No transactions are allowed below minRelayTxFee except from disconnected blocks\n        if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nDiscountedSize)) {\n            return state.DoS(0, false, REJECT_INSUFFICIENTFEE, \"min relay fee not met\");\n        }\n\n        if (nAbsurdFee && nFees > nAbsurdFee)\n            return state.Invalid(false,\n                REJECT_HIGHFEE, \"absurdly-high-fee\",\n                strprintf(\"%d > %d\", nFees, nAbsurdFee));\n\n        // Calculate in-mempool ancestors, up to a limit.\n        CTxMemPool::setEntries setAncestors;\n        size_t nLimitAncestors = GetArg(\"-limitancestorcount\", DEFAULT_ANCESTOR_LIMIT);\n        size_t nLimitAncestorSize = GetArg(\"-limitancestorsize\", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;\n        size_t nLimitDescendants = GetArg(\"-limitdescendantcount\", DEFAULT_DESCENDANT_LIMIT);\n        size_t nLimitDescendantSize = GetArg(\"-limitdescendantsize\", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;\n        std::string errString;\n        if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {\n            return state.DoS(0, false, REJECT_NONSTANDARD, \"too-long-mempool-chain\", false, errString);\n        }\n\n        // A transaction that spends outputs that would be replaced by it is invalid. Now\n        // that we have the set of all ancestors we can detect this\n        // pathological case by making sure setConflicts and setAncestors don't\n        // intersect.\n        for(CTxMemPool::txiter ancestorIt : setAncestors)\n        {\n            const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();\n            if (setConflicts.count(hashAncestor))\n            {\n                return state.DoS(10, false,\n                                 REJECT_INVALID, \"bad-txns-spends-conflicting-tx\", false,\n                                 strprintf(\"%s spends conflicting transaction %s\",\n                                           hash.ToString(),\n                                           hashAncestor.ToString()));\n            }\n        }\n\n        // Check if it's economically rational to mine this transaction rather\n        // than the ones it replaces.\n        CAmount nConflictingFees = 0;\n        size_t nConflictingSize = 0;\n        uint64_t nConflictingCount = 0;\n        CTxMemPool::setEntries allConflicting;\n\n        // If we don't hold the lock allConflicting might be incomplete; the\n        // subsequent RemoveStaged() and addUnchecked() calls don't guarantee\n        // mempool consistency for us.\n        LOCK(pool.cs);\n        const bool fReplacementTransaction = setConflicts.size();\n        if (fReplacementTransaction)\n        {\n            CFeeRate newFeeRate(nModifiedFees, nDiscountedSize);\n            std::set<uint256> setConflictsParents;\n            const int maxDescendantsToVisit = 100;\n            CTxMemPool::setEntries setIterConflicting;\n            for(const uint256 &hashConflicting : setConflicts)\n            {\n                CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting);\n                if (mi == pool.mapTx.end())\n                    continue;\n\n                // Save these to avoid repeated lookups\n                setIterConflicting.insert(mi);\n\n                // Don't allow the replacement to reduce the feerate of the\n                // mempool.\n                //\n                // We usually don't want to accept replacements with lower\n                // feerates than what they replaced as that would lower the\n                // feerate of the next block. Requiring that the feerate always\n                // be increased is also an easy-to-reason about way to prevent\n                // DoS attacks via replacements.\n                //\n                // The mining code doesn't (currently) take children into\n                // account (CPFP) so we only consider the feerates of\n                // transactions being directly replaced, not their indirect\n                // descendants. While that does mean high feerate children are\n                // ignored when deciding whether or not to replace, we do\n                // require the replacement to pay more overall fees too,\n                // mitigating most cases.\n                CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());\n                if (newFeeRate <= oldFeeRate)\n                {\n                    return state.DoS(0, false,\n                            REJECT_INSUFFICIENTFEE, \"insufficient fee\", false,\n                            strprintf(\"rejecting replacement %s; new feerate %s <= old feerate %s\",\n                                  hash.ToString(),\n                                  newFeeRate.ToString(),\n                                  oldFeeRate.ToString()));\n                }\n\n                for(const CTxIn &txin : mi->GetTx().vin)\n                {\n                    uint256 txHash;\n                    if (GetTxHash(txin.GetPrevOut(), txHash))\n                        setConflictsParents.insert(txHash);\n                }\n\n                nConflictingCount += mi->GetCountWithDescendants();\n            }\n            // This potentially overestimates the number of actual descendants\n            // but we just want to be conservative to avoid doing too much\n            // work.\n            if (nConflictingCount <= maxDescendantsToVisit) {\n                // If not too many to replace, then calculate the set of\n                // transactions that would have to be evicted\n                for(CTxMemPool::txiter it : setIterConflicting) {\n                    pool.CalculateDescendants(it, allConflicting);\n                }\n                for(CTxMemPool::txiter it : allConflicting) {\n                    nConflictingFees += it->GetModifiedFee();\n                    nConflictingSize += it->GetTxSize();\n                }\n            } else {\n                return state.DoS(0, false,\n                        REJECT_NONSTANDARD, \"too many potential replacements\", false,\n                        strprintf(\"rejecting replacement %s; too many potential replacements (%d > %d)\\n\",\n                            hash.ToString(),\n                            nConflictingCount,\n                            maxDescendantsToVisit));\n            }\n\n            for (unsigned int j = 0; j < tx.vin.size(); j++)\n            {\n                // We don't want to accept replacements that require low\n                // feerate junk to be mined first. Ideally we'd keep track of\n                // the ancestor feerates and make the decision based on that,\n                // but for now requiring all new inputs to be confirmed works.\n                uint256 txHash;\n                bool haveHash = GetTxHash(tx.vin[j].GetPrevOut(), txHash);\n                if (haveHash && !setConflictsParents.count(txHash))\n                {\n                    // Rather than check the UTXO set - potentially expensive -\n                    // it's cheaper to just check if the new input refers to a\n                    // tx that's in the mempool.\n                    if (pool.mapTx.find(txHash) != pool.mapTx.end())\n                        return state.DoS(0, false,\n                                         REJECT_NONSTANDARD, \"replacement-adds-unconfirmed\", false,\n                                         strprintf(\"replacement %s adds unconfirmed input, idx %d\",\n                                                  hash.ToString(), j));\n                }\n            }\n\n            // The replacement must pay greater fees than the transactions it\n            // replaces - if we did the bandwidth used by those conflicting\n            // transactions would not be paid for.\n            if (nModifiedFees < nConflictingFees)\n            {\n                return state.DoS(0, false,\n                                 REJECT_INSUFFICIENTFEE, \"insufficient fee\", false,\n                                 strprintf(\"rejecting replacement %s, less fees than conflicting txs; %s < %s\",\n                                          hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));\n            }\n\n            // Finally in addition to paying more fees than the conflicts the\n            // new transaction must pay for its own bandwidth.\n            CAmount nDeltaFees = nModifiedFees - nConflictingFees;\n            if (nDeltaFees < ::incrementalRelayFee.GetFee(nDiscountedSize))\n            {\n                return state.DoS(0, false,\n                        REJECT_INSUFFICIENTFEE, \"insufficient fee\", false,\n                        strprintf(\"rejecting replacement %s, not enough additional fees to relay; %s < %s\",\n                              hash.ToString(),\n                              FormatMoney(nDeltaFees),\n                              FormatMoney(::incrementalRelayFee.GetFee(nDiscountedSize))));\n            }\n        }\n\n        unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;\n        if (!chainparams.RequireStandard()) {\n            scriptVerifyFlags = GetArg(\"-promiscuousmempoolflags\", scriptVerifyFlags);\n        }\n\n\n        CWitnessBundles bundles;\n        if (!BuildWitnessBundles(tx, state, GetSpendHeight(view), 0,\n                [&](const COutPoint& outpoint, CTxOut& txOut, uint64_t& txHeight, uint64_t& txIndex, uint64_t& txOutputIndex) -> bool {\n                    const Coin& coin = view.AccessCoin(outpoint);\n                    if (coin.IsSpent())\n                        return false;\n                    txOut = coin.out;\n                    txHeight = coin.nHeight;\n                    txIndex = coin.nTxIndex;\n                    txOutputIndex = outpoint.n;\n                    return true;\n                }, bundles))\n            return false;\n\n        tx.witnessBundles = std::make_shared<CWitnessBundles>(bundles);\n\n        // Check against previous transactions\n        // This is done last to help prevent CPU exhaustion denial-of-service attacks.\n        PrecomputedTransactionData txdata(tx);\n        if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata, tx.witnessBundles.get()))\n        {\n            //fixme: (PHASE5) (SEGSIG) removed cleanstack/witness check here as it wasn't necessary anymore. However triple check if we may have missed something.\n            return false; // state filled in by CheckInputs\n        }\n\n        // Check again against just the consensus-critical mandatory script\n        // verification flags, in case of bugs in the standard flags that cause\n        // transactions to pass as valid when they're actually invalid. For\n        // instance the STRICTENC flag was incorrectly allowing certain\n        // CHECKSIG NOT scripts to pass, even though they were invalid.\n        //\n        // There is a similar check in CreateNewBlock() to prevent creating\n        // invalid blocks, however allowing such transactions into the mempool\n        // can be exploited as a DoS attack.\n        if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, nullptr))\n        {\n            return error(\"%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s\",\n                __func__, hash.ToString(), FormatStateMessage(state));\n        }\n\n        // Remove conflicting transactions from the mempool\n        for(const CTxMemPool::txiter it : allConflicting)\n        {\n            LogPrint(BCLog::MEMPOOL, \"replacing tx %s with %s for %s NLG additional fees, %d delta bytes\\n\",\n                    it->GetTx().GetHash().ToString(),\n                    hash.ToString(),\n                    FormatMoney(nModifiedFees - nConflictingFees),\n                    (int)nSize - (int)nConflictingSize);\n            if (plTxnReplaced)\n                plTxnReplaced->push_back(it->GetSharedTx());\n        }\n        pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);\n\n        // This transaction should only count for fee estimation if it isn't a\n        // BIP 125 replacement transaction (may not be widely supported), the\n        // node is not behind, and the transaction is not dependent on any other\n        // transactions in the mempool.\n        bool validForFeeEstimation = !fReplacementTransaction && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);\n\n        // Store transaction in memory\n        pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation);\n\n        // trim mempool and check if tx was trimmed\n        if (!fOverrideMempoolLimit) {\n            LimitMempoolSize(pool, GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg(\"-mempoolexpiry\", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);\n            if (!pool.exists(hash))\n                return state.DoS(0, false, REJECT_INSUFFICIENTFEE, \"mempool full\");\n        }\n    }\n\n    GetMainSignals().TransactionAddedToMempool(ptx);\n\n    return true;\n}\n\n/** (try to) add transaction to memory pool with a specified acceptance time **/\nstatic bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,\n                        bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,\n                        bool fOverrideMempoolLimit, const CAmount nAbsurdFee)\n{\n    std::vector<COutPoint> coins_to_uncache;\n    bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache);\n    if (!res) {\n        for(const COutPoint& hashTx : coins_to_uncache)\n            pcoinsTip->Uncache(hashTx);\n    }\n    // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits\n    CValidationState stateDummy;\n    FlushStateToDisk(chainparams, stateDummy, FLUSH_STATE_PERIODIC);\n    return res;\n}\n\nbool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,\n                        bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,\n                        bool fOverrideMempoolLimit, const CAmount nAbsurdFee)\n{\n    const CChainParams& chainparams = Params();\n    return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee);\n}\n\nbool LoadMempool(void)\n{\n    const CChainParams& chainparams = Params();\n    int64_t nExpiryTimeout = GetArg(\"-mempoolexpiry\", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;\n    FILE* filestr = fsbridge::fopen(GetDataDir() / \"mempool.dat\", \"rb\");\n    CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);\n    if (file.IsNull()) {\n        LogPrintf(\"Failed to open mempool file from disk. Continuing anyway.\\n\");\n        return false;\n    }\n\n    int64_t count = 0;\n    int64_t skipped = 0;\n    int64_t failed = 0;\n    int64_t nNow = GetTime();\n\n    try {\n        uint64_t version;\n        file >> version;\n        if (version != MEMPOOL_DUMP_VERSION) {\n            return false;\n        }\n        uint64_t num;\n        file >> num;\n        while (num--) {\n            CTransactionRef tx;\n            int64_t nTime;\n            int64_t nFeeDelta;\n            file >> tx;\n            file >> nTime;\n            file >> nFeeDelta;\n\n            CAmount amountdelta = nFeeDelta;\n            if (amountdelta) {\n                mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);\n            }\n            CValidationState state;\n            if (nTime + nExpiryTimeout > nNow) {\n                LOCK(cs_main);\n                AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, true, NULL, nTime, NULL, false, 0);\n                if (state.IsValid()) {\n                    ++count;\n                } else {\n                    ++failed;\n                }\n            } else {\n                ++skipped;\n            }\n            if (ShutdownRequested())\n                return false;\n        }\n        std::map<uint256, CAmount> mapDeltas;\n        file >> mapDeltas;\n\n        for (const auto& i : mapDeltas) {\n            mempool.PrioritiseTransaction(i.first, i.second);\n        }\n    } catch (const std::exception& e) {\n        LogPrintf(\"Failed to deserialize mempool data on disk: %s. Continuing anyway.\\n\", e.what());\n        return false;\n    }\n\n    LogPrintf(\"Imported mempool transactions from disk: %i successes, %i failed, %i expired\\n\", count, failed, skipped);\n    return true;\n}\n\nvoid DumpMempool(void)\n{\n    int64_t start = GetTimeMicros();\n\n    std::map<uint256, CAmount> mapDeltas;\n    std::vector<TxMempoolInfo> vinfo;\n\n    {\n        LOCK(mempool.cs);\n        for (const auto &i : mempool.mapDeltas) {\n            mapDeltas[i.first] = i.second;\n        }\n        vinfo = mempool.infoAll();\n    }\n\n    int64_t mid = GetTimeMicros();\n\n    try {\n        FILE* filestr = fsbridge::fopen(GetDataDir() / \"mempool.dat.new\", \"wb\");\n        if (!filestr) {\n            return;\n        }\n\n        CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);\n\n        uint64_t version = MEMPOOL_DUMP_VERSION;\n        file << version;\n\n        file << (uint64_t)vinfo.size();\n        for (const auto& i : vinfo) {\n            file << *(i.tx);\n            file << (int64_t)i.nTime;\n            file << (int64_t)i.nFeeDelta;\n            mapDeltas.erase(i.tx->GetHash());\n        }\n\n        file << mapDeltas;\n        FileCommit(file.Get());\n        file.fclose();\n        RenameOver(GetDataDir() / \"mempool.dat.new\", GetDataDir() / \"mempool.dat\");\n        int64_t last = GetTimeMicros();\n        LogPrintf(\"Dumped mempool: %gs to copy, %gs to dump\\n\", (mid-start)*0.000001, (last-mid)*0.000001);\n    } catch (const std::exception& e) {\n        LogPrintf(\"Failed to dump mempool: %s. Continuing anyway.\\n\", e.what());\n    }\n}\n\nint ExpireMempoolForPartialSync(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* tip)\n{\n    AssertLockHeld(cs_main);\n    assert(tip);\n\n    /* Using the provided tip remove transactions from the mempool using the following logic:\n     * Transactions older then PARTIALSYNC_MEMPOOL_EXPIRE should be expired, but only if at least\n     * PARTIALSYNC_MEMPOOL_BLOCKS blocks have been mined that could/should have included the transaction.\n     * These blocks should be at least PARTIALSYNC_MEMPOOL_PROPAGATION_DELAY newer then the expire time,\n     * this is to account for time fro transactions to propagate through the network and be picked up by\n     * the miners.\n     */\n\n    const int PARTIALSYNC_MEMPOOL_EXPIRE = 3600; // one hour\n    const int PARTIALSYNC_MEMPOOL_PROPAGATION_DELAY = 60; // one minute\n    const int PARTIALSYNC_MEMPOOL_BLOCKS = 3;\n\n    // When tip too old don't expire at all. Perhaps we're doing inital sync or catching up\n    // from way behind. So we bail out as early as possible reduce the workload while catching up.\n\n    int64_t expireTime = GetTime() - PARTIALSYNC_MEMPOOL_EXPIRE;\n    if (tip->GetBlockTime() < expireTime)\n        return 0;\n\n    // Remove tx in new block from mempool (also only when tip recent for efficiency)\n    mempool.removeForBlock(pblock->vtx, tip->nHeight);\n\n    // propagation time accounts for the required number of blocks having been mined very close to each\n    // other and before the transaction might have been propagated through the network properly\n    int64_t propagationTime = expireTime + PARTIALSYNC_MEMPOOL_PROPAGATION_DELAY;\n\n    // count # blocks since propagationTime\n    int numBlocks = 0;\n    const CBlockIndex* pindex = tip;\n    while (tip && numBlocks < PARTIALSYNC_MEMPOOL_BLOCKS && tip->GetBlockTime() >= propagationTime) {\n        numBlocks++;\n        pindex = pindex->pprev;\n    }\n\n    // if enough blocks passed expire from mempool\n    if (numBlocks >= PARTIALSYNC_MEMPOOL_BLOCKS) {\n        std::vector<uint256> removed;\n        int numExpired = mempool.Expire(expireTime, &removed);\n        for (const auto& txHash: removed) {\n            GetMainSignals().TransactionRemovedFromMempool(txHash, MemPoolRemovalReason::EXPIRY);\n        }\n        return numExpired;\n    }\n    else\n        return 0;\n}\n"
  },
  {
    "path": "src/validation/validation_misc.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"validation.h\"\n#include \"validationinterface.h\"\n#include \"witnessvalidation.h\"\n#include \"versionbitsvalidation.h\"\n#include <consensus/validation.h>\n\n#include \"blockstore.h\"\n#include \"txdb.h\"\n#include \"net.h\"\n#include \"chainparams.h\"\n#include \"versionbits.h\"\n#include <net_processing.h>\n\n/** Convert CValidationState to a human-readable message for logging */\nstd::string FormatStateMessage(const CValidationState &state)\n{\n    return strprintf(\"%s%s (code %i)\",\n        state.GetRejectReason(),\n        state.GetDebugMessage().empty() ? \"\" : \", \"+state.GetDebugMessage(),\n        state.GetRejectCode());\n}\n\n/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */\nbool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const CChainParams& params, uint256 &hashBlock, bool fAllowSlow)\n{\n    CBlockIndex *pindexSlow = NULL;\n\n    LOCK(cs_main); // Required for ReadBlockFromDisk.\n\n    CTransactionRef ptx = mempool.get(hash);\n    if (ptx)\n    {\n        txOut = ptx;\n        return true;\n    }\n\n    if (fTxIndex) {\n        CDiskTxPos postx;\n        if (pblocktree->ReadTxIndex(hash, postx)) {\n            CFile file(blockStore.GetBlockFile(postx, true), SER_DISK, CLIENT_VERSION);\n            if (file.IsNull())\n                return error(\"%s: OpenBlockFile failed\", __func__);\n            CBlockHeader header;\n            try {\n                file >> header;\n                fseek(file.Get(), postx.nTxOffset, SEEK_CUR);\n                file >> txOut;\n            } catch (const std::exception& e) {\n                return error(\"%s: Deserialize or I/O error - %s\", __func__, e.what());\n            }\n            hashBlock = header.GetHashPoW2();\n            if (txOut->GetHash() != hash)\n                return error(\"%s: txid mismatch, block hash [%s]\", __func__, hashBlock.ToString());\n            return true;\n        }\n    }\n\n    if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it\n        const Coin& coin = AccessByTxid(*pcoinsTip, hash);\n        if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];\n    }\n\n    if (pindexSlow) {\n        CBlock block;\n        if (ReadBlockFromDisk(block, pindexSlow, params)) {\n            for (const auto& tx : block.vtx) {\n                if (tx->GetHash() == hash) {\n                    txOut = tx;\n                    hashBlock = pindexSlow->GetBlockHashPoW2();\n                    return true;\n                }\n            }\n        }\n    }\n\n    return false;\n}\n\n\nBlockSubsidy GetBlockSubsidy(uint64_t nHeight)\n{\n    static bool fRegTest = Params().IsRegtest();\n    static bool fRegTestLegacy = Params().IsRegtestLegacy();\n    static bool fTestnet = Params().IsTestnet();\n    if (fRegTestLegacy)\n        return BlockSubsidy(50*COIN, 0, 0); \n    if (fRegTest)\n    {\n        if (nHeight == 0)\n        {\n            return BlockSubsidy(50*COIN, 50*COIN, 0*COIN);\n        }\n        else\n        {\n            return BlockSubsidy(50*COIN, 50*COIN, 50*COIN);\n        }\n    }\n    \n\n    if(nHeight == 1)\n    {\n        CAmount witnessSubsidyGenesis=0;\n        if (fTestnet)\n            witnessSubsidyGenesis=30*COIN;\n        return BlockSubsidy(170000000*COIN, witnessSubsidyGenesis, 0); // First block (premine)\n    }\n    else if(nHeight < Params().GetConsensus().fixedRewardReductionHeight)\n    {\n        return BlockSubsidy(1000*COIN, 0, 0); // 1000 Munt per block for first 250k blocks\n    }\n    else if(nHeight < Params().GetConsensus().devBlockSubsidyActivationHeight)\n    {\n        return BlockSubsidy(100*COIN, 0, 0); // 100 Munt per block (fixed reward/no halving)\n    }\n    else if (nHeight < Params().GetConsensus().pow2Phase4FirstBlockHeight+1)\n    {\n        return BlockSubsidy(50*COIN, 20*COIN, 40*COIN); // 110 Munt per block (fixed reward/no halving) - 50 mining, 40 development, 20 witness.\n    }\n    else if(nHeight <= 1226651)\n    {\n        return BlockSubsidy(50*COIN, 30*COIN, 40*COIN); // 120 Munt per block (fixed reward/no halving) - 50 mining, 40 development, 30 witness.\n    }\n    else if(nHeight <= 1228003)\n    {\n        return BlockSubsidy(90*COIN, 30*COIN, 80*COIN); // 200 Munt per block (fixed reward/no halving) - 90 mining, 80 development, 30 witness.\n    }\n    else if(nHeight <= Params().GetConsensus().halvingIntroductionHeight)\n    {\n        return BlockSubsidy(50*COIN, 30*COIN, 80*COIN); // 160 Munt per block (fixed reward/no halving) - 50 mining, 80 development, 30 witness.\n    }\n    // 90 Munt per block; 10 mining, 15 witness, 65 development    \n    else if (nHeight < 1619997)\n    {\n        return BlockSubsidy(1000000*MILLICENT, 1500000*MILLICENT, 6500000*MILLICENT);\n    }\n    // Once off large development fund distribution after which the per block development reward is dropped\n    else if (nHeight == 1619997)\n    {\n        return BlockSubsidy(1000000*MILLICENT, 1500000*MILLICENT, 100'000'000*COIN); //1619997  56817116000000000\n    }\n    // From this point on reward is as follows:\n    // 25 Munt per block; 10 mining, 15 witness\n    // Halving every 842500 blocks (roughly 4 years); first halving at block ???\n    // We round to force only a single non-zero decimal digit instead of exact halving in order to keep the numbers as clean as possible throughout.\n    // Halvings as follows:\n    // 5 mining,          7.5 witness\n    // 2 mining,          4 witness\n    // 1 mining,          2 witness\n    // 0.5 mining,        1 witness\n    // 0.2 mining,        0.5 witness\n    // 0.1 mining,        0.2 witness\n    // 0.05 mining,       0.1 witness\n    // 0.02 mining,       0.05 witness\n    // 0.01 mining,       0.02 witness\n    // 0.005 mining,      0.01 witness\n    // 0.002 mining,      0.005 witness\n    // 0.001 mining,      0.002 witness\n    // 0.0005 mining,     0.001 witness\n    // 0.0002 mining,     0.0005 witness\n    // 0.0001 mining,     0.0002 witness\n    // 0.00005 mining,    0.0001 witness\n    // 0.00002 mining,    0.00005 witness\n    // 0.00001 mining,    0.00002 witness\n    // 0.000005 mining,   0.00001 witness\n    // 0.000002 mining,   0.000005 witness\n    // 0.000001 mining,   0.000002 witness\n    // 0.0000005 mining,  0.000001 witness\n    // 0.0000002 mining,  0.0000005 witness\n    // 0.0000001 mining,  0.0000002 witness\n    // 0.00000005 mining, 0.0000001 witness\n    // 0.00000002 mining, 0.00000005 witness\n    // 0.00000001 mining, 0.00000002 witness\n    else\n    {\n        // NB! We opt for this simple human readable \"table-like\" layout so that it is easier for humans to inspect/verify this..\n        int nHalvings = (nHeight - 1 - (Params().GetConsensus().halvingIntroductionHeight-167512)) / 842500;\n        switch(nHalvings)\n        {\n            case 0:  return BlockSubsidy(1000000*MILLICENT, 1500000*MILLICENT, 0); // 1'619'998  668'171'185.00000000\n            case 1:  return BlockSubsidy( 500000*MILLICENT,  750000*MILLICENT, 0); // 2'074'989  679'545'960.00000000\n            case 2:  return BlockSubsidy( 200000*MILLICENT,  400000*MILLICENT, 0); // 2'917'489  690'077'210.00000000\n            case 3:  return BlockSubsidy( 100000*MILLICENT,  200000*MILLICENT, 0); // 3'759'989  695'132'210.00000000\n            case 4:  return BlockSubsidy(  50000*MILLICENT,  100000*MILLICENT, 0); // 4'602'489  697'659'710.00000000\n            case 5:  return BlockSubsidy(  20000*MILLICENT,   50000*MILLICENT, 0); // 5'444'989  698'923'460.00000000\n            case 6:  return BlockSubsidy(  10000*MILLICENT,   20000*MILLICENT, 0); // 6'287'489  699'513'210.00000000\n            case 7:  return BlockSubsidy(   5000*MILLICENT,   10000*MILLICENT, 0); // 7'129'989  699'765'960.00000000\n            case 8:  return BlockSubsidy(   2000*MILLICENT,    5000*MILLICENT, 0); // 7'972'489  699'892'335.00000000\n            case 9:  return BlockSubsidy(   1000*MILLICENT,    2000*MILLICENT, 0); // 8'814'989  699'951'310.00000000\n            case 10: return BlockSubsidy(    500*MILLICENT,    1000*MILLICENT, 0); // 9'657'489  699'976'585.00000000\n            case 11: return BlockSubsidy(    200*MILLICENT,     500*MILLICENT, 0); //10'499'989  699'989'222.50000000\n            case 12: return BlockSubsidy(    100*MILLICENT,     200*MILLICENT, 0); //11'342'489  699'995'120.00000000\n            case 13: return BlockSubsidy(     50*MILLICENT,     100*MILLICENT, 0); //12'184'989  699'997'647.50000000\n            case 14: return BlockSubsidy(     20*MILLICENT,      50*MILLICENT, 0); //13'027'489  699'998'911.25000000\n            case 15: return BlockSubsidy(     10*MILLICENT,      20*MILLICENT, 0); //13'869'989  699'999'501.00000000\n            case 16: return BlockSubsidy(      5*MILLICENT,      10*MILLICENT, 0); //14'712'489  699'999'753.75000000\n            case 17: return BlockSubsidy(      2*MILLICENT,       5*MILLICENT, 0); //15'554'989  699'999'880.12500000\n            case 18: return BlockSubsidy(      1*MILLICENT,       2*MILLICENT, 0); //16'397'489  699'999'939.10000000\n            case 19: return BlockSubsidy(      500,               1*MILLICENT, 0); //17'239'989  699'999'964.37500000\n            case 20: return BlockSubsidy(      200,               500        , 0); //18'082'489  699'999'977.01250000\n            case 21: return BlockSubsidy(      100,               200        , 0); //18'924'989  699'999'982.91000000\n            case 22: return BlockSubsidy(       50,               100        , 0); //19'767'489  699'999'985.43750000\n            case 23: return BlockSubsidy(       20,                50        , 0); //20'609'989  699'999'986.70125000\n            case 24: return BlockSubsidy(       10,                20        , 0); //21'452'489  699'999'987.29100000\n            case 25: return BlockSubsidy(        5,                10        , 0); //22'294'989  699'999'987.54375000\n            case 26: return BlockSubsidy(        2,                 5        , 0); //23'137'489  699'999'987.67012500\n            default: {\n                if (nHeight <= Params().GetConsensus().finalSubsidyBlockHeight)\n                     return BlockSubsidy(        1,                 2        , 0); //23'979'989  699'999'987.72910000\n            }\n        }\n    }\n    return BlockSubsidy(0, 0, 0);                                                  //433'009'989 700'000'000.00000000\n}\n\nbool IsInitialBlockDownload()\n{\n    //AssertLockHeld(cs_main);\n    const CChainParams& chainParams = Params();\n\n    // Once this function has returned false, it must remain false.\n    static std::atomic<bool> latchToFalse{false};\n    // Optimization: pre-test latch before taking the lock.\n    if (latchToFalse.load(std::memory_order_relaxed))\n        return false;\n\n    if (latchToFalse.load(std::memory_order_relaxed))\n        return false;\n    if (fImporting || fReindex)\n        return true;\n    if (chainActive.Tip() == NULL)\n        return true;\n    if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))\n        return true;\n    if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))\n        return true;\n    LogPrintf(\"Leaving InitialBlockDownload (latching to false)\\n\");\n    latchToFalse.store(true, std::memory_order_relaxed);\n    return false;\n}\n\nbool HaveRequiredPeerUpgradePercent(int nRequiredProtoVersion, unsigned int nRequiredPercent)\n{\n    std::vector<CNodeStats> vstats;\n    g_connman->GetNodeStats(vstats);\n\n    // Insufficient peers to determine.\n    if (vstats.size() < 3)\n    {\n        return true;\n    }\n\n    int nUpgradeCount = 0;\n    for (const CNodeStats& stats : vstats)\n    {\n        if (stats.nVersion >= nRequiredProtoVersion)\n        {\n            ++nUpgradeCount;\n        }\n    }\n    return (100 * nUpgradeCount) / vstats.size() > nRequiredPercent;\n}\n\nint32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)\n{\n    LOCK(cs_main);\n    int32_t nVersion = VERSIONBITS_TOP_BITS;\n\n    for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++)\n    {\n        ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache);\n        if (state == THRESHOLD_LOCKED_IN)\n        {\n            nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);\n        }\n        else if (state == THRESHOLD_STARTED)\n        {\n            if (params.vDeployments[i].protoVersion == 0 || HaveRequiredPeerUpgradePercent(params.vDeployments[i].protoVersion, params.vDeployments[i].requiredProtoUpgradePercent))\n            {\n                nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);\n            }\n        }\n    }\n\n    return nVersion;\n}\n\n//! Guess how far we are in the verification process at the given block index\ndouble GuessVerificationProgress(CBlockIndex *pindex) {\n    if (pindex == NULL)\n        return 0.0;\n\n    double nSyncProgress = std::min(1.0, (double)pindex->nHeight / GetProbableHeight());\n    return nSyncProgress;\n}\n\nbool GetTxHash(const COutPoint& outpoint, uint256& txHash)\n{\n    if (outpoint.isHash)\n    {\n        txHash = outpoint.getTransactionHash();\n        return true;\n    }\n    else\n    {\n        LOCK(cs_main);\n        CBlock block;\n        if ((int)outpoint.getTransactionBlockNumber() <= chainActive.Height() && ReadBlockFromDisk(block, chainActive[outpoint.getTransactionBlockNumber()], Params()))\n        {\n            if (outpoint.getTransactionIndex() < block.vtx.size())\n            {\n                txHash = block.vtx[outpoint.getTransactionIndex()]->GetHash();\n                return true;\n            }\n        }\n    }\n    return false;\n}\n"
  },
  {
    "path": "src/validation/validationinterface.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"validation/validationinterface.h\"\n\n#include <scheduler.h>\n\n#include <future>\n#include <unordered_map>\n#include <utility>\n\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"wallet/wallet.h\"\n\n//! The MainSignalsInstance manages a list of shared_ptr<CValidationInterface>\n//! callbacks.\n//!\n//! A std::unordered_map is used to track what callbacks are currently\n//! registered, and a std::list is to used to store the callbacks that are\n//! currently registered as well as any callbacks that are just unregistered\n//! and about to be deleted when they are done executing.\nstruct MainSignalsInstance {\nprivate:\n    Mutex m_mutex;\n    //! List entries consist of a callback pointer and reference count. The\n    //! count is equal to the number of current executions of that entry, plus 1\n    //! if it's registered. It cannot be 0 because that would imply it is\n    //! unregistered and also not being executed (so shouldn't exist).\n    struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };\n    std::list<ListEntry> m_list GUARDED_BY(m_mutex);\n    std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);\n\npublic:\n    // We are not allowed to assume the scheduler only runs in one thread,\n    // but must ensure all callbacks happen in-order, so we end up creating\n    // our own queue here :(\n    SingleThreadedSchedulerClient m_schedulerClient;\n\n    explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}\n\n    void Register(std::shared_ptr<CValidationInterface> callbacks)\n    {\n        LOCK(m_mutex);\n        auto inserted = m_map.emplace(callbacks.get(), m_list.end());\n        if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());\n        inserted.first->second->callbacks = std::move(callbacks);\n    }\n\n    void Unregister(CValidationInterface* callbacks)\n    {\n        LOCK(m_mutex);\n        auto it = m_map.find(callbacks);\n        if (it != m_map.end()) {\n            if (!--it->second->count) m_list.erase(it->second);\n            m_map.erase(it);\n        }\n    }\n\n    //! Clear unregisters every previously registered callback, erasing every\n    //! map entry. After this call, the list may still contain callbacks that\n    //! are currently executing, but it will be cleared when they are done\n    //! executing.\n    void Clear()\n    {\n        LOCK(m_mutex);\n        for (const auto& entry : m_map) {\n            if (!--entry.second->count) m_list.erase(entry.second);\n        }\n        m_map.clear();\n    }\n\n    template<typename F> void Iterate(F&& f)\n    {\n        WAIT_LOCK(m_mutex, lock);\n        for (auto it = m_list.begin(); it != m_list.end();) {\n            ++it->count;\n            {\n                REVERSE_LOCK(lock);\n                f(*it->callbacks);\n            }\n            it = --it->count ? std::next(it) : m_list.erase(it);\n        }\n    }\n};\n\nstatic CMainSignals g_signals;\n\nvoid CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)\n{\n    assert(!m_internals);\n    m_internals.reset(new MainSignalsInstance(&scheduler));\n}\n\nvoid CMainSignals::UnregisterBackgroundSignalScheduler()\n{\n    m_internals.reset(nullptr);\n}\n\nvoid CMainSignals::FlushBackgroundCallbacks()\n{\n    if (m_internals) {\n        m_internals->m_schedulerClient.EmptyQueue();\n    }\n}\n\nsize_t CMainSignals::CallbacksPending()\n{\n    if (!m_internals) return 0;\n    return m_internals->m_schedulerClient.CallbacksPending();\n}\n\nCMainSignals& GetMainSignals()\n{\n    return g_signals;\n}\n\nvoid RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)\n{\n    // Each connection captures the shared_ptr to ensure that each callback is\n    // executed before the subscriber is destroyed. For more details see #18338.\n    g_signals.m_internals->Register(std::move(callbacks));\n}\n\nvoid RegisterValidationInterface(CValidationInterface* callbacks)\n{\n    // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle\n    // is managed by the caller.\n    RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});\n}\n\nvoid UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)\n{\n    UnregisterValidationInterface(callbacks.get());\n}\n\nvoid UnregisterValidationInterface(CValidationInterface* callbacks)\n{\n    if (g_signals.m_internals) {\n        g_signals.m_internals->Unregister(callbacks);\n    }\n}\n\nvoid UnregisterAllValidationInterfaces()\n{\n    if (!g_signals.m_internals) {\n        return;\n    }\n    g_signals.m_internals->Clear();\n}\n\nvoid CallFunctionInValidationInterfaceQueue(std::function<void()> func)\n{\n    g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));\n}\n\nvoid SyncWithValidationInterfaceQueue()\n{\n    AssertLockNotHeld(cs_main);\n    // Block until the validation queue drains\n    std::promise<void> promise;\n    CallFunctionInValidationInterfaceQueue([&promise] {\n        promise.set_value();\n    });\n    promise.get_future().wait();\n}\n\n// Use a macro instead of a function for conditional logging to prevent\n// evaluating arguments when logging is not enabled.\n//\n// NOTE: The lambda captures all local variables by value.\n#define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...)           \\\n    do {                                                       \\\n        auto local_name = (name);                              \\\n        LOG_EVENT(\"Enqueuing \" fmt, local_name, __VA_ARGS__);  \\\n        m_internals->m_schedulerClient.AddToProcessQueue([=] { \\\n            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \\\n            event();                                           \\\n        });                                                    \\\n    } while (0)\n\n#define LOG_EVENT(fmt, ...) \\\n    LogPrint(BCLog::VALIDATION, fmt \"\\n\", __VA_ARGS__)\n\nvoid CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {\n    // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which\n    // the chain actually updates. One way to ensure this is for the caller to invoke this signal\n    // in the same critical section where the chain is updated\n\n    auto event = [pindexNew, pindexFork, fInitialDownload, this] {\n        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });\n    };\n    ENQUEUE_AND_LOG_EVENT(event, \"%s: new block hash=%s fork block hash=%s (in IBD=%s)\", __func__,\n                          pindexNew->GetBlockHashPoW2().ToString(),\n                          pindexFork ? pindexFork->GetBlockHashPoW2().ToString() : \"null\",\n                          fInitialDownload);\n}\n\nvoid CMainSignals::TransactionAddedToMempool(const CTransactionRef& tx) {\n    auto event = [tx, this] {\n        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx); });\n    };\n    ENQUEUE_AND_LOG_EVENT(event, \"%s: txid=%s wtxid=%s\", __func__,\n                          tx->GetHash().ToString(),\n                          tx->GetWitnessHash().ToString());\n}\n\nvoid CMainSignals::TransactionRemovedFromMempool(const uint256 &transactionHash, MemPoolRemovalReason reason)\n{\n    auto event = [transactionHash, reason, this] {\n        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(transactionHash, reason); });\n    };\n    ENQUEUE_AND_LOG_EVENT(event, \"%s: txid=%s\", __func__,\n                          transactionHash.ToString());\n}\n\nvoid CMainSignals::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& txnConflicted) {\n    auto event = [pblock, pindex, txnConflicted, this] {\n        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex, txnConflicted); });\n    };\n    ENQUEUE_AND_LOG_EVENT(event, \"%s: block hash=%s, block height=%d\", __func__,\n                          pblock->GetHashPoW2().ToString(), pindex->nHeight);\n}\n\nvoid CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock)\n{\n    auto event = [pblock, this] {\n        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock); });\n    };\n    ENQUEUE_AND_LOG_EVENT(event, \"%s: block hash=%s\", __func__,\n                          pblock->GetHashPoW2().ToString());\n}\n\nvoid CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {\n    LOG_EVENT(\"%s: block hash=%s state=%s\", __func__,\n              block.GetHashPoW2().ToString(), state.ToString());\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });\n}\n\nvoid CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {\n    LOG_EVENT(\"%s: block hash=%s\", __func__, block->GetHashPoW2().ToString());\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });\n}\n\nvoid CMainSignals::PruningConflictingBlock (const uint256& orphanBlockHash)\n{\n    LOG_EVENT(\"%s: block hash=%s\", __func__, orphanBlockHash.ToString());\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.PruningConflictingBlock(orphanBlockHash); });\n}\n\nvoid CMainSignals::Broadcast (int64_t nBestBlockTime, CConnman* connman)\n{\n    LOG_EVENT(\"%s: best block time=%d\", __func__, nBestBlockTime);\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.Broadcast(nBestBlockTime, connman); });\n}\n\nvoid CMainSignals::ScriptForMining(std::shared_ptr<CReserveKeyOrScript>& scriptForMining, CAccount* forAccount)\n{\n    LOG_EVENT(\"%s\", __func__);\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ScriptForMining(scriptForMining, forAccount); });\n}\n\nvoid CMainSignals::ScriptForWitnessing(std::shared_ptr<CReserveKeyOrScript>& scriptForWitnessing, CAccount* forAccount)\n{\n    LOG_EVENT(\"%s\", __func__);\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ScriptForWitnessing(scriptForWitnessing, forAccount); });\n}\n\nvoid CMainSignals::SetBestChain(const CBlockLocator& locator)\n{\n    LOG_EVENT(\"%s: best block time=%d\", __func__, locator.IsNull() ? \"null\" : locator.vHave.front().ToString());\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.SetBestChain(locator); });\n}\n\nvoid CMainSignals::StalledWitness(const CBlockIndex* pBlockIndex, uint64_t nSeconds)\n{\n    LOG_EVENT(\"%s: block hash=%s seconds=%d\", __func__, pBlockIndex->GetBlockHashPoW2().ToString(), nSeconds);\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.StalledWitness(pBlockIndex, nSeconds); });\n}\n    \n    \nvoid CMainSignals::WalletTransactionAdded(CWallet* const pWallet, const CWalletTx& wtx)\n{\n    LOG_EVENT(\"%s: wallet=%s transactionHash=%d\", __func__, pWallet->GetName(), wtx.GetHash().ToString());\n    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.WalletTransactionAdded(pWallet, wtx); });\n}\n\n/*/\nvoid RegisterValidationInterface(CValidationInterface* pwalletIn)\n{\n    g_signals.StalledWitness.connect(boost::bind(&CValidationInterface::StalledWitness, pwalletIn, _1, _2));\n    g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));\n    g_signals.TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));\n    g_signals.TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1, _2));\n    #ifdef ENABLE_WALLET\n    g_signals.WalletTransactionAdded.connect(boost::bind(&CValidationInterface::WalletTransactionAdded, pwalletIn, _1, _2));\n    #endif\n    g_signals.BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));\n    g_signals.BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));\n    g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));\n    g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));\n    g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));\n    g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1, _2));\n    g_signals.ScriptForWitnessing.connect(boost::bind(&CValidationInterface::GetScriptForWitnessing, pwalletIn, _1, _2));\n    g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));\n    g_signals.PruningConflictingBlock.connect(boost::bind(&CValidationInterface::PruningConflictingBlock, pwalletIn, _1));\n}\n\nvoid UnregisterValidationInterface(CValidationInterface* pwalletIn)\n{\n    g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));\n    g_signals.ScriptForWitnessing.disconnect(boost::bind(&CValidationInterface::GetScriptForWitnessing, pwalletIn, _1, _2));\n    g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1, _2));\n    g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));\n    g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));\n    g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));\n    g_signals.BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));\n    g_signals.BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));\n    g_signals.TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));\n    g_signals.TransactionRemovedFromMempool.disconnect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1, _2));\n    #ifdef ENABLE_WALLET\n    g_signals.WalletTransactionAdded.disconnect(boost::bind(&CValidationInterface::WalletTransactionAdded, pwalletIn, _1, _2));\n    #endif\n    g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));\n    g_signals.StalledWitness.disconnect(boost::bind(&CValidationInterface::StalledWitness, pwalletIn, _1, _2));\n    g_signals.PruningConflictingBlock.disconnect(boost::bind(&CValidationInterface::PruningConflictingBlock, pwalletIn, _1));\n}\n\nvoid UnregisterAllValidationInterfaces()\n{\n    g_signals.ScriptForWitnessing.disconnect_all_slots();\n    g_signals.ScriptForMining.disconnect_all_slots();\n    g_signals.BlockChecked.disconnect_all_slots();\n    g_signals.Broadcast.disconnect_all_slots();\n    g_signals.SetBestChain.disconnect_all_slots();\n    g_signals.TransactionAddedToMempool.disconnect_all_slots();\n    g_signals.TransactionRemovedFromMempool.disconnect_all_slots();\n    g_signals.BlockConnected.disconnect_all_slots();\n    g_signals.BlockDisconnected.disconnect_all_slots();\n    g_signals.UpdatedBlockTip.disconnect_all_slots();\n    g_signals.NewPoWValidBlock.disconnect_all_slots();\n    g_signals.StalledWitness.disconnect_all_slots();\n    g_signals.PruningConflictingBlock.disconnect_all_slots();\n}*/\n"
  },
  {
    "path": "src/validation/validationinterface.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2020 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef VALIDATIONINTERFACE_H\n#define VALIDATIONINTERFACE_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include \"validation/validation.h\" // For cs_main\n\n#include <boost/signals2/signal.hpp>\n#include <memory>\n\n#include \"generation/generation.h\"\n\n#include \"primitives/transaction.h\" // CTransaction(Ref)\n\n#ifdef ENABLE_WALLET\nclass CWalletTx;\n#endif\n\nclass CBlock;\nclass CBlockIndex;\nstruct CBlockLocator;\nclass CBlockIndex;\nclass CConnman;\nclass CValidationInterface;\nclass CValidationState;\nclass uint256;\nclass CAccount;\nclass CScheduler;\nenum class MemPoolRemovalReason;\n\n// These functions dispatch to one or all registered wallets\n\n/** Register subscriber */\nvoid RegisterValidationInterface(CValidationInterface* callbacks);\n/** Unregister subscriber. DEPRECATED. This is not safe to use when the RPC server or main message handler thread is running. */\nvoid UnregisterValidationInterface(CValidationInterface* callbacks);\n/** Unregister all subscribers */\nvoid UnregisterAllValidationInterfaces();\n\n// Alternate registration functions that release a shared_ptr after the last\n// notification is sent. These are useful for race-free cleanup, since\n// unregistration is nonblocking and can return before the last notification is\n// processed.\n/** Register subscriber */\nvoid RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);\n/** Unregister subscriber */\nvoid UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);\n\n/**\n * Pushes a function to callback onto the notification queue, guaranteeing any\n * callbacks generated prior to now are finished when the function is called.\n *\n * Be very careful blocking on func to be called if any locks are held -\n * validation interface clients may not be able to make progress as they often\n * wait for things like cs_main, so blocking until func is called with cs_main\n * will result in a deadlock (that DEBUG_LOCKORDER will miss).\n */\nvoid CallFunctionInValidationInterfaceQueue(std::function<void ()> func);\n/**\n * This is a synonym for the following, which asserts certain locks are not\n * held:\n *     std::promise<void> promise;\n *     CallFunctionInValidationInterfaceQueue([&promise] {\n *         promise.set_value();\n *     });\n *     promise.get_future().wait();\n */\nvoid SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main);\n\n/**\n * Implement this to subscribe to events generated in validation\n *\n * Each CValidationInterface() subscriber will receive event callbacks\n * in the order in which the events were generated by validation.\n * Furthermore, each ValidationInterface() subscriber may assume that\n * callbacks effectively run in a single thread with single-threaded\n * memory consistency. That is, for a given ValidationInterface()\n * instantiation, each callback will complete before the next one is\n * invoked. This means, for example when a block is connected that the\n * UpdatedBlockTip() callback may depend on an operation performed in\n * the BlockConnected() callback without worrying about explicit\n * synchronization. No ordering should be assumed across\n * ValidationInterface() subscribers.\n */\nclass CValidationInterface {\nprotected:\n    /**\n     * Protected destructor so that instances can only be deleted by derived classes.\n     * If that restriction is no longer desired, this should be made public and virtual.\n     */\n    ~CValidationInterface() = default;\npublic:\n    virtual void StalledWitness([[maybe_unused]] const CBlockIndex* pBlock, [[maybe_unused]] uint64_t nSeconds) {}\n    /**\n     * Notifies listeners when the block chain tip advances.\n     *\n     * When multiple blocks are connected at once, UpdatedBlockTip will be called on the final tip\n     * but may not be called on every intermediate tip. If the latter behavior is desired,\n     * subscribe to BlockConnected() instead.\n     *\n     * Called on a background thread.\n     */\n    virtual void UpdatedBlockTip([[maybe_unused]] const CBlockIndex *pindexNew, [[maybe_unused]] const CBlockIndex *pindexFork, [[maybe_unused]] bool fInitialDownload) {}\n    /**\n     * Notifies listeners of a transaction having been added to mempool.\n     *\n     * Called on a background thread.\n     */\n    virtual void TransactionAddedToMempool([[maybe_unused]] const CTransactionRef &ptxn) {}\n    /**\n     * Notifies listeners of a transaction leaving mempool.\n     *\n     * This notification fires for transactions that are removed from the\n     * mempool for the following reasons:\n     *\n     * - EXPIRY (expired from mempool after -mempoolexpiry hours)\n     * - SIZELIMIT (removed in size limiting if the mempool exceeds -maxmempool megabytes)\n     * - REORG (removed during a reorg)\n     * - CONFLICT (removed because it conflicts with in-block transaction)\n     * - REPLACED (removed due to RBF replacement)\n     *\n     * This does not fire for transactions that are removed from the mempool\n     * because they have been included in a block. Any client that is interested\n     * in transactions removed from the mempool for inclusion in a block can learn\n     * about those transactions from the BlockConnected notification.\n     *\n     * Transactions that are removed from the mempool because they conflict\n     * with a transaction in the new block will have\n     * TransactionRemovedFromMempool events fired *before* the BlockConnected\n     * event is fired. If multiple blocks are connected in one step, then the\n     * ordering could be:\n     *\n     * - TransactionRemovedFromMempool(tx1 from block A)\n     * - TransactionRemovedFromMempool(tx2 from block A)\n     * - TransactionRemovedFromMempool(tx1 from block B)\n     * - TransactionRemovedFromMempool(tx2 from block B)\n     * - BlockConnected(A)\n     * - BlockConnected(B)\n     *\n     * Called on a background thread.\n     */\n    virtual void TransactionRemovedFromMempool([[maybe_unused]] const uint256 &hash, [[maybe_unused]] MemPoolRemovalReason reason) {}\n    /**\n     * Notifies listeners of a block being connected.\n     * Provides a vector of transactions evicted from the mempool as a result.\n     *\n     * Called on a background thread.\n     */\n    virtual void BlockConnected([[maybe_unused]] const std::shared_ptr<const CBlock> &block, [[maybe_unused]] const CBlockIndex *pindex, [[maybe_unused]] const std::vector<CTransactionRef> &txnConflicted) {}\n     /**\n     * Notifies listeners of a block being disconnected\n     *\n     * Called on a background thread.\n     */\n    virtual void BlockDisconnected([[maybe_unused]] const std::shared_ptr<const CBlock> &block) {}\n     /**\n     * Notifies listeners of a block validation result.\n     * If the provided BlockValidationState IsValid, the provided block\n     * is guaranteed to be the current best block at the time the\n     * callback was generated (not necessarily now)\n     */\n    virtual void BlockChecked([[maybe_unused]] const CBlock&, [[maybe_unused]] const CValidationState&) {}\n    /**\n     * Notifies listeners that a block which builds directly on our current tip\n     * has been received and connected to the headers tree, though not validated yet */\n    virtual void NewPoWValidBlock([[maybe_unused]] const CBlockIndex *pindex, [[maybe_unused]] const std::shared_ptr<const CBlock>& block) {};\n    virtual void PruningConflictingBlock([[maybe_unused]] const uint256& orphanBlockHash) {}\n    /** Tells listeners to broadcast their data. */\n    virtual void Broadcast(int64_t nBestBlockTime, CConnman* connman) {};\n    virtual void ScriptForMining([[maybe_unused]] std::shared_ptr<CReserveKeyOrScript>&, [[maybe_unused]] CAccount* forAccount) {};\n    virtual void ScriptForWitnessing([[maybe_unused]] std::shared_ptr<CReserveKeyOrScript>&, [[maybe_unused]] CAccount* forAccount) {};\n    #ifdef ENABLE_WALLET\n    virtual void WalletTransactionAdded([[maybe_unused]] CWallet* const pWallet, [[maybe_unused]] const CWalletTx& wtx) {}\n    #endif\n    virtual void SetBestChain([[maybe_unused]] const CBlockLocator &locator) {}\n    virtual void ResendWalletTransactions([[maybe_unused]] int64_t nBestBlockTime, [[maybe_unused]] CConnman* connman) {}\n    friend class CMainSignals;\n};\n\nstruct MainSignalsInstance;\nclass CMainSignals {\nprivate:\n    std::unique_ptr<MainSignalsInstance> m_internals;\n\n    friend void ::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface>);\n    friend void ::UnregisterValidationInterface(CValidationInterface*);\n    friend void ::UnregisterAllValidationInterfaces();\n    friend void ::CallFunctionInValidationInterfaceQueue(std::function<void ()> func);\n\npublic:\n    /** Register a CScheduler to give callbacks which should run in the background (may only be called once) */\n    void RegisterBackgroundSignalScheduler(CScheduler& scheduler);\n    /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */\n    void UnregisterBackgroundSignalScheduler();\n    /** Call any remaining callbacks on the calling thread */\n    void FlushBackgroundCallbacks();\n\n    size_t CallbacksPending();\n\n    void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);\n    void TransactionAddedToMempool(const CTransactionRef&);\n    void TransactionRemovedFromMempool(const uint256 &transactionHash, MemPoolRemovalReason);\n    void BlockConnected(const std::shared_ptr<const CBlock>& pBlock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& txnConflicted);\n    void BlockDisconnected(const std::shared_ptr<const CBlock> &);\n    void BlockChecked(const CBlock&, const CValidationState&);\n    void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);\n    void PruningConflictingBlock (const uint256& orphanBlockHash);\n    \n    void Broadcast(int64_t nBestBlockTime, CConnman* connman);\n    \n    /** Notifies listeners that a key for mining is required (coinbase) */\n    void ScriptForMining([[maybe_unused]] std::shared_ptr<CReserveKeyOrScript>&, [[maybe_unused]] CAccount* forAccount);\n    \n    //! Notifies listeners that a key for witnessing is required (to generate non-compound coinbase outputs)\n    void ScriptForWitnessing([[maybe_unused]] std::shared_ptr<CReserveKeyOrScript>&, [[maybe_unused]] CAccount* forAccount);\n    \n    void SetBestChain(const CBlockLocator&);\n\n    //! Notifies listeners of a stalled witness at tip of chain\n    void StalledWitness(const CBlockIndex*, uint64_t nSeconds);\n    \n    #ifdef ENABLE_WALLET\n    void WalletTransactionAdded(CWallet* const pWallet, const CWalletTx& wtx);\n    #endif\n};\n\nCMainSignals& GetMainSignals();\n\n#endif\n"
  },
  {
    "path": "src/validation/versionbitsvalidation.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"versionbitsvalidation.h\"\n#include \"validation.h\"\n\n// Protected by cs_main\nVersionBitsCache versionbitscache;\n\nThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)\n{\n    LOCK(cs_main);\n    return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);\n}\n\nBIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos)\n{\n    LOCK(cs_main);\n    return VersionBitsStatistics(chainActive.Tip(), params, pos);\n}\n\nint VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)\n{\n    LOCK(cs_main);\n    return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);\n}\n"
  },
  {
    "path": "src/validation/versionbitsvalidation.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2018-2022 The Centure developers\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef VERSION_BITS_VALIDATION_H\n#define VERSION_BITS_VALIDATION_H\n\n#include \"versionbits.h\"\n\nextern VersionBitsCache versionbitscache;\n\n/** Get the BIP9 state for a given deployment at the current tip. */\nThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);\n\n/** Get the numerical statistics for the BIP9 state for a given deployment at the current tip. */\nBIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos);\n\n/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */\nint VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);\n\n#endif\n"
  },
  {
    "path": "src/validation/witnessvalidation.cpp",
    "content": "// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include <consensus/validation.h>\n#include <witnessutil.h>\n#include \"timedata.h\" // GetAdjustedTime()\n\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n\n#include <boost/foreach.hpp> // reverse_foreach\n#include <boost/algorithm/string/replace.hpp>\n#include <boost/algorithm/string/join.hpp>\n#include <boost/thread.hpp>\n\n#include \"alert.h\"\n\n\n\nCWitViewDB *ppow2witdbview = NULL;\nstd::shared_ptr<CCoinsViewCache> ppow2witTip = NULL;\nSimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXO;\n\n//fixme: (PHASE5) Can remove this.\nint GetPoW2WitnessCoinbaseIndex(const CBlock& block)\n{\n    int commitpos = -1;\n    if (!block.vtx.empty()) {\n        for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {\n            if (block.vtx[0]->vout[o].GetType() <= CTxOutType::ScriptLegacyOutput)\n            {\n                if (block.vtx[0]->vout[o].output.scriptPubKey.size() == 143 && block.vtx[0]->vout[o].output.scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].output.scriptPubKey[1] == 0x50 && block.vtx[0]->vout[o].output.scriptPubKey[2] == 0x6f && block.vtx[0]->vout[o].output.scriptPubKey[3] == 0x57 && block.vtx[0]->vout[o].output.scriptPubKey[4] == 0xc2 && block.vtx[0]->vout[o].output.scriptPubKey[5] == 0xb2) {\n                    commitpos = o;\n                }\n            }\n        }\n    }\n    return commitpos;\n}\n\nstd::vector<CBlockIndex*> GetTopLevelPoWOrphans(const int64_t nHeight, const uint256& prevHash)\n{\n    LOCK(cs_main);\n    std::vector<CBlockIndex*> vRet;\n    for (const auto candidateIter : setBlockIndexCandidates)\n    {\n        if (candidateIter->nVersionPoW2Witness == 0)\n        {\n            if (candidateIter->nHeight >= nHeight)\n            {\n                vRet.push_back(candidateIter);\n            }\n        }\n    }\n    return vRet;\n}\n\nstd::vector<CBlockIndex*> GetTopLevelWitnessOrphans(const int64_t nHeight)\n{\n    std::vector<CBlockIndex*> vRet;\n\n    // Don't hold up the witness loop if we can't get the lock, it can just check this again next time\n    TRY_LOCK(cs_main, lockGetOrphans);\n    if(!lockGetOrphans)\n    {\n        return vRet;\n    }\n    \n    for (const auto candidateIter : setBlockIndexCandidates)\n    {\n        if (candidateIter->nVersionPoW2Witness != 0)\n        {\n            if (candidateIter->nHeight >= nHeight)\n            {\n                vRet.push_back(candidateIter);\n            }\n        }\n    }\n    return vRet;\n}\n\nCBlockIndex* GetWitnessOrphanForBlock(const int64_t nHeight, const uint256& prevHash, const uint256& powHash)\n{\n    LOCK(cs_main);\n    for (const auto candidateIter : setBlockIndexCandidates)\n    {\n        if (candidateIter->nVersionPoW2Witness != 0)\n        {\n            if (candidateIter->nHeight == nHeight && candidateIter->pprev && *candidateIter->pprev->phashBlock == prevHash)\n            {\n                if (candidateIter->GetBlockHashLegacy() == powHash)\n                {\n                    return candidateIter;\n                }\n            }\n        }\n    }\n    return NULL;\n}\n\nstatic bool ForceActivateChainStep(CValidationState& state, CChain& currentChain, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, CCoinsViewCache& coinView)\n{\n    AssertLockHeld(cs_main); // Required for ReadBlockFromDisk.\n    const CBlockIndex *pindexFork = currentChain.FindFork(pindexMostWork);\n\n    if (!pindexFork)\n    {\n        while (currentChain.Tip() && currentChain.Tip()->nHeight >= pindexMostWork->nHeight - 1)\n        {\n            CBlockIndex* pindexNew = currentChain.Tip()->pprev;\n            std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n            CBlock& block = *pblock;\n            if (!ReadBlockFromDisk(block, currentChain.Tip(), chainparams))\n                return false;\n            if (DisconnectBlock(block, currentChain.Tip(), coinView) != DISCONNECT_OK)\n                return false;\n            currentChain.SetTip(pindexNew);\n        }\n        pindexFork = currentChain.FindFork(pindexMostWork);\n    }\n\n    // Disconnect active blocks which are no longer in the best chain.\n    while (currentChain.Tip() && currentChain.Tip() != pindexFork) {\n        CBlockIndex* pindexNew = currentChain.Tip()->pprev;\n        std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n        CBlock& block = *pblock;\n        if (!ReadBlockFromDisk(block, currentChain.Tip(), chainparams))\n            return false;\n        if (DisconnectBlock(block, currentChain.Tip(), coinView) != DISCONNECT_OK)\n            return false;\n        currentChain.SetTip(pindexNew);\n    }\n\n    // Build list of new blocks to connect.\n    std::vector<CBlockIndex*> vpindexToConnect;\n    bool fContinue = true;\n    int nHeight = pindexFork ? pindexFork->nHeight : -1;\n    while (fContinue && nHeight != pindexMostWork->nHeight) {\n        // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need\n        // a few blocks along the way.\n        int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight);\n        vpindexToConnect.clear();\n        vpindexToConnect.reserve(nTargetHeight - nHeight);\n        CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight);\n        while (pindexIter && pindexIter->nHeight != nHeight) {\n            vpindexToConnect.push_back(pindexIter);\n            pindexIter = pindexIter->pprev;\n        }\n        nHeight = nTargetHeight;\n\n        // Connect new blocks.\n        BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {\n            std::shared_ptr<CBlock> pblockConnect = nullptr;\n            if (pindexConnect != pindexMostWork || !pblock)\n            {\n                pblockConnect = std::make_shared<CBlock>();\n                CBlock& block = *pblockConnect;\n                if (!ReadBlockFromDisk(block, pindexConnect, chainparams))\n                    return false;\n            }\n            bool rv = ConnectBlock(currentChain, pblockConnect?*pblockConnect:*pblock, state, pindexConnect, coinView, chainparams, false, false, false, false);\n            if (!rv)\n                return false;\n            currentChain.SetTip(pindexConnect);\n        }\n    }\n\n    return true;\n}\n\n// pblock is either NULL or a pointer to a CBlock corresponding to pActiveIndex, to bypass loading it again from disk.\nbool ForceActivateChain(CBlockIndex* pActivateIndex, std::shared_ptr<const CBlock> pblock, CValidationState& state, const CChainParams& chainparams, CChain& currentChain, CCoinsViewCache& coinView)\n{\n    DO_BENCHMARK(\"WIT: ForceActivateChain\", BCLog::BENCH|BCLog::WITNESS);\n\n    CBlockIndex* pindexNewTip = nullptr;\n    do {\n        {\n            LOCK(cs_main);\n\n            // Whether we have anything to do at all.\n            if (pActivateIndex == NULL || pActivateIndex == currentChain.Tip())\n                return true;\n\n            bool fInvalidFound = false;\n            std::shared_ptr<const CBlock> nullBlockPtr;\n            if (!ForceActivateChainStep(state, currentChain, chainparams, pActivateIndex, pblock, fInvalidFound, coinView))\n                return false;\n\n            if (fInvalidFound) {\n                return false;\n            }\n            pindexNewTip = currentChain.Tip();\n        }\n        // When we reach this point, we switched to a new tip (stored in pindexNewTip).\n    } while (pindexNewTip != pActivateIndex);\n\n    return true;\n}\n\nbool ForceActivateChainWithBlockAsTip(CBlockIndex* pActivateIndex, std::shared_ptr<const CBlock> pblock, CValidationState& state, const CChainParams& chainparams, CChain& currentChain, CCoinsViewCache& coinView, CBlockIndex* pnewblockastip)\n{\n    if(!ForceActivateChain(pActivateIndex, pblock, state, chainparams, currentChain, coinView))\n        return false;\n    return ForceActivateChain(pnewblockastip, nullptr, state, chainparams, currentChain, coinView);\n}\n\nuint64_t expectedWitnessBlockPeriod(uint64_t nWeight, uint64_t networkTotalWeight)\n{\n    if (nWeight == 0 || networkTotalWeight == 0)\n        return 0;\n\n    if (nWeight > networkTotalWeight/100)\n        nWeight = networkTotalWeight/100;\n\n    static const arith_uint256 base = arith_uint256(100000000) * arith_uint256(100000000) * arith_uint256(100000000);\n    #define BASE(x) (arith_uint256(x)*base)\n    #define AI(x) arith_uint256(x)\n    return 100 + std::max(( ((BASE(1)/((BASE(nWeight)/AI(networkTotalWeight))))).GetLow64() * 10 ), (uint64_t)1000);\n    #undef AI\n    #undef BASE\n}\n\nuint64_t estimatedWitnessBlockPeriod(uint64_t nWeight, uint64_t networkTotalWeight)\n{\n    DO_BENCHMARK(\"WIT: estimatedWitnessBlockPeriod\", BCLog::BENCH|BCLog::WITNESS);\n\n    if (nWeight == 0 || networkTotalWeight == 0)\n        return 0;\n\n    if (nWeight > networkTotalWeight/100)\n        nWeight = networkTotalWeight/100;\n\n    static const arith_uint256 base = arith_uint256(100000000) * arith_uint256(100000000) * arith_uint256(100000000);\n    #define BASE(x) (arith_uint256(x)*base)\n    #define AI(x) arith_uint256(x)\n    return 100 + ((BASE(1)/((BASE(nWeight)/AI(networkTotalWeight))))).GetLow64();\n    #undef AI\n    #undef BASE\n}\n\n\nbool getAllUnspentWitnessCoins(CChain& chain, const CChainParams& chainParams, const CBlockIndex* pPreviousIndexChain_, std::map<COutPoint, Coin>& allWitnessCoins, CBlock* newBlock, CCoinsViewCache* viewOverride, bool forceIndexBased)\n{\n    DO_BENCHMARK(\"WIT: getAllUnspentWitnessCoins\", BCLog::BENCH|BCLog::WITNESS);\n\n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    assert(pPreviousIndexChain_);\n\n    allWitnessCoins.clear();\n    //fixme: (PHASE5) Add more error handling to this function.\n    // Sort out pre-conditions.\n    // We have to make sure that we are using a view and chain that includes the PoW block we are witnessing and all of its transactions as the tip.\n    // It won't necessarily be part of the chain yet; if we are in the process of witnessing; or if the block is an older one on a fork; because only blocks that have already been witnessed can be part of the chain.\n    // So we have to temporarily force disconnect/reconnect of blocks as necessary to make a temporary working chain that suits the properties we want.\n    // NB!!! - It is important that we don't flush either of these before destructing, we want to throw the result away.\n    CCoinsViewCache viewNew(viewOverride?viewOverride:pcoinsTip);\n\n    if ((uint64_t)pPreviousIndexChain_->nHeight < Params().GetConsensus().pow2Phase2FirstBlockHeight)\n        return true;\n\n    // We work on a clone of the chain to prevent modifying the actual chain.\n    CBlockIndex* pPreviousIndexChain = nullptr;\n    CCloneChain tempChain(chain, GetPow2ValidationCloneHeight(chain, pPreviousIndexChain_, 2), pPreviousIndexChain_, pPreviousIndexChain);\n    CValidationState state;\n    assert(pPreviousIndexChain);\n\n    // Force the tip of the chain to the block that comes before the block we are examining.\n    // For phase 3 this must be a PoW block - from phase 4 it should be a witness block \n    if (pPreviousIndexChain->nHeight == 0)\n    {\n        ForceActivateChain(pPreviousIndexChain, nullptr, state, chainParams, tempChain, viewNew);\n    }\n    else\n    {\n        if (pPreviousIndexChain->nVersionPoW2Witness==0 || IsPow2Phase4Active(pPreviousIndexChain->pprev))\n        {\n            ForceActivateChain(pPreviousIndexChain, nullptr, state, chainParams, tempChain, viewNew);\n        }\n        else\n        {\n            CBlockIndex* pPreviousIndexChainPoW = new CBlockIndex(*GetPoWBlockForPoSBlock(pPreviousIndexChain));\n            assert(pPreviousIndexChainPoW);\n            pPreviousIndexChainPoW->pprev = pPreviousIndexChain->pprev;\n            ForceActivateChainWithBlockAsTip(pPreviousIndexChain->pprev, nullptr, state, chainParams, tempChain, viewNew, pPreviousIndexChainPoW);\n            pPreviousIndexChain = tempChain.Tip();\n        }\n    }\n\n    // If we have been passed a new tip block (not yet part of the chain) then add it to the chain now.\n    if (newBlock)\n    {\n        // Strip any witness information from the block we have been given we want a non-witness block as the tip in order to calculate the witness for it.\n        if (newBlock->nVersionPoW2Witness != 0)\n        {\n            for (unsigned int i = 1; i < newBlock->vtx.size(); i++)\n            {\n                if (newBlock->vtx[i]->IsCoinBase() && newBlock->vtx[i]->IsPoW2WitnessCoinBase())\n                {\n                    while (newBlock->vtx.size() > i)\n                    {\n                        newBlock->vtx.pop_back();\n                    }\n                    break;\n                }\n            }\n            newBlock->nVersionPoW2Witness = 0;\n            newBlock->nTimePoW2Witness = 0;\n            newBlock->hashMerkleRootPoW2Witness = uint256();\n            newBlock->witnessHeaderPoW2Sig.clear();\n            newBlock->witnessUTXODelta.clear();\n        }\n\n        // Place the block in question at the tip of the chain.\n        CBlockIndex* indexDummy = new CBlockIndex(*newBlock);\n        indexDummy->pprev = pPreviousIndexChain;\n        indexDummy->nHeight = pPreviousIndexChain->nHeight + 1;\n        if (!ConnectBlock(tempChain, *newBlock, state, indexDummy, viewNew, chainParams, true, false, false, false))\n        {\n            //fixme: (PHASE5) If we are inside a GetWitness call ban the peer that sent us this?\n            return false;\n        }\n        tempChain.SetTip(indexDummy);\n    }\n\n    /** Gather a list of all unspent witness outputs.\n        NB!!! There are multiple layers of cache at play here, with insertions/deletions possibly having taken place at each layer.\n        Therefore the order of operations is crucial, we must first iterate the lowest layer, then the second lowest and finally the highest layer.\n        For each iteration we should remove items from allWitnessCoins if they have been deleted in the higher layer as the higher layer overrides the lower layer.\n        GetAllCoins takes care of all of this automatically.\n    **/\n    if (forceIndexBased || (uint64_t)tempChain.Tip()->nHeight >= Params().GetConsensus().pow2WitnessSyncHeight)\n    {\n        viewNew.pChainedWitView->GetAllCoinsIndexBased(allWitnessCoins);\n    }\n    else\n    {\n        viewNew.pChainedWitView->GetAllCoins(allWitnessCoins);\n    }\n\n    return true;\n}\n\n\n//fixme: (PHASE5) Improve error handling.\n//fixme: (PHASE5) Handle nodes with excessive pruning. //pblocktree->ReadFlag(\"prunedblockfiles\", fHavePruned);\nbool GetWitnessHelper(uint256 blockHash, CGetWitnessInfo& witnessInfo, uint64_t nBlockHeight)\n{\n    DO_BENCHMARK(\"WIT: GetWitnessHelper\", BCLog::BENCH|BCLog::WITNESS);\n\n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:nullptr);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    /** Generate the pool of potential witnesses for the given block index **/\n    /** Addresses younger than nMinAge blocks are discarded **/\n    uint64_t nMinAge = gMinimumParticipationAge;\n    while (true)\n    {\n        witnessInfo.witnessSelectionPoolFiltered.clear();\n        witnessInfo.witnessSelectionPoolFiltered = witnessInfo.witnessSelectionPoolUnfiltered;\n\n        /** Eliminate addresses that have witnessed within the last `gMinimumParticipationAge` blocks **/\n        witnessInfo.witnessSelectionPoolFiltered.erase(std::remove_if(witnessInfo.witnessSelectionPoolFiltered.begin(), witnessInfo.witnessSelectionPoolFiltered.end(), [&](RouletteItem& x){ return (x.nAge <= nMinAge); }), witnessInfo.witnessSelectionPoolFiltered.end());\n\n        /** Eliminate addresses that have not witnessed within the expected period of time that they should have **/\n        witnessInfo.witnessSelectionPoolFiltered.erase(std::remove_if(witnessInfo.witnessSelectionPoolFiltered.begin(), witnessInfo.witnessSelectionPoolFiltered.end(), [&](RouletteItem& x){ return witnessHasExpired(x.nAge, x.nWeight, witnessInfo.nTotalWeightRaw); }), witnessInfo.witnessSelectionPoolFiltered.end());\n\n        /** Eliminate addresses that are within 100 blocks from lock period expiring, or whose lock period has expired. **/\n        witnessInfo.witnessSelectionPoolFiltered.erase(std::remove_if(witnessInfo.witnessSelectionPoolFiltered.begin(), witnessInfo.witnessSelectionPoolFiltered.end(), [&](RouletteItem& x){ CTxOutPoW2Witness details; GetPow2WitnessOutput(x.coin.out, details); return (GetPoW2RemainingLockLengthInBlocks(details.lockUntilBlock, nBlockHeight) <= nMinAge); }), witnessInfo.witnessSelectionPoolFiltered.end());\n\n        // We must have at least 100 accounts to keep odds of being selected down below 1% at all times.\n        if (witnessInfo.witnessSelectionPoolFiltered.size() < 100)\n        {\n            if(!Params().IsTestnet() && nBlockHeight > 880000)\n                CAlert::Notify(\"Warning network is experiencing low levels of witnessing participants!\", true, true);\n\n\n            // NB!! This part of the code should (ideally) never actually be used, it exists only for instances where there are a shortage of witnesses paticipating on the network.\n            if (nMinAge == 0 || (nMinAge <= 10 && witnessInfo.witnessSelectionPoolFiltered.size() > 5))\n            {\n                break;\n            }\n            else\n            {\n                // Try again to reach 100 candidates with a smaller min age.\n                nMinAge -= 5;\n            }\n        }\n        else\n        {\n            break;\n        }\n    }\n\n    if (witnessInfo.witnessSelectionPoolFiltered.size() == 0)\n    {\n        return error(\"Unable to determine any witnesses for block.\");\n    }\n\n    /** Ensure the pool is sorted deterministically **/\n    std::sort(witnessInfo.witnessSelectionPoolFiltered.begin(), witnessInfo.witnessSelectionPoolFiltered.end());\n\n    /** Calculate total eligible weight **/\n    witnessInfo.nTotalWeightEligibleRaw = 0;\n    for (auto& item : witnessInfo.witnessSelectionPoolFiltered)\n    {\n        witnessInfo.nTotalWeightEligibleRaw += item.nWeight;\n    }\n\n    uint64_t genesisWeight=0;\n    if (Params().numGenesisWitnesses > 0)\n    {\n        genesisWeight = std::max(witnessInfo.nTotalWeightEligibleRaw / Params().genesisWitnessWeightDivisor, (uint64_t)1000);\n        witnessInfo.nTotalWeightEligibleRaw += Params().numGenesisWitnesses*genesisWeight;\n    }\n    \n    /** Reduce larger weightings to a maximum weighting of 1% of network weight. **/\n    /** NB!! this actually will end up a little bit more than 1% as the overall network weight will also be reduced as a result. **/\n    /** This is however unimportant as 1% is in and of itself also somewhat arbitrary, simpler code is favoured here over exactness. **/\n    /** So we delibritely make no attempt to compensate for this. **/\n    witnessInfo.nMaxIndividualWeight = witnessInfo.nTotalWeightEligibleRaw / 100;\n    witnessInfo.nTotalWeightEligibleAdjusted = 0;\n    for (auto& item : witnessInfo.witnessSelectionPoolFiltered)\n    {\n        if (item.nWeight == 0)\n            item.nWeight = genesisWeight;\n        if (item.nWeight > witnessInfo.nMaxIndividualWeight)\n            item.nWeight = witnessInfo.nMaxIndividualWeight;\n        witnessInfo.nTotalWeightEligibleAdjusted += item.nWeight;\n        item.nCumulativeWeight = witnessInfo.nTotalWeightEligibleAdjusted;\n    }\n\n    /** sha256 as random roulette spin/seed - NB! We delibritely use sha256 and -not- the normal PoW hash here as the normal PoW hash is biased towards certain number ranges by -design- (block target) so is not a good RNG... **/\n    arith_uint256 rouletteSelectionSeed = UintToArith256(blockHash);\n\n    //fixme: (PHASE5) Update whitepaper then delete this code.\n    /** ensure random seed exceeds one full spin of the wheel to prevent any possible bias towards low numbers **/\n    //while (rouletteSelectionSeed < witnessInfo.nTotalWeightEligibleAdjusted)\n    //{\n        //rouletteSelectionSeed = rouletteSelectionSeed * 2;\n    //}\n\n    /** Reduce selection number to fit within possible range of values **/\n    if (rouletteSelectionSeed > arith_uint256(witnessInfo.nTotalWeightEligibleAdjusted))\n    {\n        // 'BigNum' Modulo operator via mathematical identity:  a % b = a - (b * int(a/b))\n        rouletteSelectionSeed = rouletteSelectionSeed - (arith_uint256(witnessInfo.nTotalWeightEligibleAdjusted) * arith_uint256(rouletteSelectionSeed/arith_uint256(witnessInfo.nTotalWeightEligibleAdjusted)));\n    }\n\n    /** Perform selection **/\n    auto selectedWitness = std::lower_bound(witnessInfo.witnessSelectionPoolFiltered.begin(), witnessInfo.witnessSelectionPoolFiltered.end(), rouletteSelectionSeed.GetLow64());\n    witnessInfo.selectedWitnessTransaction = selectedWitness->coin.out;\n    witnessInfo.selectedWitnessIndex = selectedWitness-(witnessInfo.witnessSelectionPoolFiltered.begin());\n    #ifdef DEBUG\n    assert((witnessInfo.witnessSelectionPoolFiltered[witnessInfo.selectedWitnessIndex].coin.out == selectedWitness->coin.out));\n    #endif\n    witnessInfo.selectedWitnessBlockHeight = selectedWitness->coin.nHeight;\n    witnessInfo.selectedWitnessOutpoint = selectedWitness->outpoint;\n\n    return true;\n}\n\nbool GetWitnessInfo(CChain& chain, const CChainParams& chainParams, CCoinsViewCache* viewOverride, CBlockIndex* pPreviousIndexChain, CBlock block, CGetWitnessInfo& witnessInfo, uint64_t nBlockHeight)\n{\n    DO_BENCHMARK(\"WIT: GetWitnessInfo\", BCLog::BENCH|BCLog::WITNESS);\n\n    #ifdef DISABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:nullptr);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    // Fetch all unspent witness outputs for the chain in which -block- acts as the tip.\n    if (!getAllUnspentWitnessCoins(chain, chainParams, pPreviousIndexChain, witnessInfo.allWitnessCoins, &block, viewOverride))\n        return false;\n\n    bool outputsShouldBeHashes = (nBlockHeight < Params().GetConsensus().pow2WitnessSyncHeight);\n\n    // Gather all witnesses that exceed minimum weight and count the total witness weight.\n    for (auto coinIter : witnessInfo.allWitnessCoins)\n    {\n        //fixme: (PHASE5) Unit tests\n        uint64_t nAge = nBlockHeight - coinIter.second.nHeight;\n        COutPoint outPoint = coinIter.first;\n        assert(outPoint.isHash == outputsShouldBeHashes);\n        Coin coin = coinIter.second;\n        if (coin.out.nValue >= (gMinimumWitnessAmount*COIN))\n        {\n            uint64_t nUnused1, nUnused2;\n            int64_t nWeight = GetPoW2RawWeightForAmount(coin.out.nValue, pPreviousIndexChain->nHeight, GetPoW2LockLengthInBlocksFromOutput(coin.out, coin.nHeight, nUnused1, nUnused2));\n            if (nWeight < gMinimumWitnessWeight)\n                continue;\n            witnessInfo.witnessSelectionPoolUnfiltered.push_back(RouletteItem(outPoint, coin, nWeight, nAge));\n            witnessInfo.nTotalWeightRaw += nWeight;\n        }\n        else if (coin.out.output.witnessDetails.lockFromBlock == 1)\n        {\n            int64_t nWeight = 0;\n            witnessInfo.witnessSelectionPoolUnfiltered.push_back(RouletteItem(outPoint, coin, nWeight, nAge));                     \n        }\n    }\n    \n    return true;\n}\n\nbool GetWitness(CChain& chain, const CChainParams& chainParams, CCoinsViewCache* viewOverride, CBlockIndex* pPreviousIndexChain, CBlock block, CGetWitnessInfo& witnessInfo)\n{\n    DO_BENCHMARK(\"WIT: GetWitness\", BCLog::BENCH|BCLog::WITNESS);\n\n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:nullptr);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    // Fetch all the chain info (for specific block) we will need to calculate the witness.\n    uint64_t nBlockHeight = pPreviousIndexChain->nHeight + 1;\n    if (!GetWitnessInfo(chain, chainParams, viewOverride, pPreviousIndexChain, block, witnessInfo, nBlockHeight))\n        return false;\n\n    return GetWitnessHelper(block.GetHashLegacy(), witnessInfo, nBlockHeight);\n}\n\n\nbool GetWitnessFromSimplifiedUTXO(SimplifiedWitnessUTXOSet simplifiedWitnessUTXO, const CBlockIndex* pBlockIndex, CGetWitnessInfo& witnessInfo)\n{\n    DO_BENCHMARK(\"WIT: GetWitnessFromSimplifiedUTXO\", BCLog::BENCH|BCLog::WITNESS);\n    \n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:nullptr);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    // Populate the witness info from the utxo\n    uint64_t nBlockHeight = pBlockIndex->nHeight;\n    \n    // Equivalent of GetWitnessInfo\n    {\n        // Gather all witnesses that exceed minimum weight and count the total witness weight.\n        for (auto simplifiedRouletteItem : simplifiedWitnessUTXO.witnessCandidates)\n        {\n            // We delibritely leave failCount, actionNonce and spendingKeyId unset here, as they aren't used by the code that follows.\n            CTxOutPoW2Witness simplifiedWitnessInfo;\n            simplifiedWitnessInfo.witnessKeyID = simplifiedRouletteItem.witnessPubKeyID;\n            simplifiedWitnessInfo.lockFromBlock = simplifiedRouletteItem.lockFromBlock;\n            simplifiedWitnessInfo.lockUntilBlock = simplifiedRouletteItem.lockUntilBlock;\n            \n            // Set our partially filled in coin item (we have filled in all the parts that GetWitnessHelper touches)\n            Coin rouletteCoin = Coin(CTxOut(simplifiedRouletteItem.nValue, CTxOutPoW2Witness(simplifiedWitnessInfo)), simplifiedRouletteItem.blockNumber, 0, false, false);\n            COutPoint rouletteOutpoint = COutPoint(simplifiedRouletteItem.blockNumber, simplifiedRouletteItem.transactionIndex, simplifiedRouletteItem.transactionOutputIndex);\n            \n            RouletteItem item(rouletteOutpoint, rouletteCoin, 0, 0);\n            item.nAge = nBlockHeight - simplifiedRouletteItem.blockNumber;\n\n            if (simplifiedRouletteItem.nValue >= (gMinimumWitnessAmount*COIN))\n            {\n                item.nWeight = GetPoW2RawWeightForAmount(item.coin.out.nValue, nBlockHeight, simplifiedRouletteItem.GetLockLength());\n                if (item.nWeight < gMinimumWitnessWeight)\n                    continue;\n                witnessInfo.witnessSelectionPoolUnfiltered.push_back(item);\n                witnessInfo.nTotalWeightRaw += item.nWeight;\n            }\n            else if (simplifiedRouletteItem.lockFromBlock == 1)\n            {\n                item.nWeight = 0;\n                witnessInfo.witnessSelectionPoolUnfiltered.push_back(item);\n            }\n        }\n    }\n\n    return GetWitnessHelper(pBlockIndex->GetBlockHashLegacy(), witnessInfo, nBlockHeight);\n}\n\nbool GetWitnessFromUTXO(std::vector<RouletteItem> witnessUtxo, CBlockIndex* pBlockIndex, CGetWitnessInfo& witnessInfo)\n{\n    DO_BENCHMARK(\"WIT: GetWitnessFromUTXO\", BCLog::BENCH|BCLog::WITNESS);\n    \n    #ifdef ENABLE_WALLET\n    LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:nullptr);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    // Populate the witness info from the utxo\n    uint64_t nBlockHeight = pBlockIndex->nHeight;\n    \n    // Equivalent of GetWitnessInfo\n    {\n        // Gather all witnesses that exceed minimum weight and count the total witness weight.\n        for (auto rouletteItem : witnessUtxo)\n        {\n            //uint64_t nAge = nBlockHeight - coinIter.second.nHeight;\n            assert(!rouletteItem.outpoint.isHash);\n            //COutPoint outPoint = coinIter.first;\n            if (rouletteItem.coin.out.nValue >= (gMinimumWitnessAmount*COIN))\n            {\n                uint64_t nUnused1, nUnused2;\n                int64_t nWeight = GetPoW2RawWeightForAmount(rouletteItem.coin.out.nValue, nBlockHeight, GetPoW2LockLengthInBlocksFromOutput(rouletteItem.coin.out, rouletteItem.coin.nHeight, nUnused1, nUnused2));\n                if (nWeight < gMinimumWitnessWeight)\n                    continue;\n                witnessInfo.witnessSelectionPoolUnfiltered.push_back(rouletteItem);\n                witnessInfo.nTotalWeightRaw += nWeight;\n            }\n            else if (rouletteItem.coin.out.output.witnessDetails.lockFromBlock == 1)\n            {\n                rouletteItem.nWeight = 0;\n                witnessInfo.witnessSelectionPoolUnfiltered.push_back(rouletteItem);\n            }\n        }\n    }\n\n    return GetWitnessHelper(pBlockIndex->GetBlockHashLegacy(), witnessInfo, nBlockHeight);\n}\n\n// Ideally this should have been some hybrid of witInfo.nTotalWeight / witInfo.nReducedTotalWeight - as both independantly aren't perfect.\n// Total weight is prone to be too high if there are lots of large >1% witnesses, nReducedTotalWeight is prone to be too low if there is one large witness who has recently witnessed.\n// However on a large network with lots of participants this should not matter - and technical constraints make the total the best compromise\n// As we need to call this from within the witness algorithm from before nReducedTotalWeight is even known. \nbool witnessHasExpired(uint64_t nWitnessAge, uint64_t nWitnessWeight, uint64_t nNetworkTotalWitnessWeight)\n{\n    if (nWitnessWeight == 0)\n        return false;\n\n    uint64_t nExpectedWitnessPeriod = expectedWitnessBlockPeriod(nWitnessWeight, nNetworkTotalWitnessWeight);\n    return ( nWitnessAge > gMaximumParticipationAge ) || ( nWitnessAge > nExpectedWitnessPeriod );\n}\n\nconst char changeTypeCreation = 0;\nconst char changeTypeSpend = 1;\nconst char changeTypeRenew = 2;\nconst char changeTypeRearrange = 3;\nconst char changeTypeIncrease = 4;\nconst char changeTypeChangeKey = 5;\nconst char changeTypeWitnessAction = 6;\n\nstruct deltaItem\n{\npublic:\n    int changeType;\n    std::vector<SimplifiedWitnessRouletteItem> removedItems;\n    std::vector<SimplifiedWitnessRouletteItem> addedItems;\n};\n\nbool GenerateSimplifiedWitnessUTXODeltaUndoForHeader(std::vector<unsigned char>& undoWitnessUTXODelta, SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXOUndo, std::vector<deltaItem>& deltaItems)\n{\n    CVectorWriter deltaUndoStream(SER_NETWORK, 0, undoWitnessUTXODelta, 0);\n\n    // Play back the changes to generate the undo info\n    // Note that we have to actually perform the changes as we go, and not just serialise them\n    // The reason for this is that each operation that does an insert/remove can change the index of all future insert/removes\n    // So if we just serialise the indexes will be wrong when we replay the changes later\n    \n    // First handle the witness that signed the block as a special case, as there is always only one of these at the start, then loop for everything else.\n    {\n        // Remove the updated witness item and put back the original one\n        const auto& deltaWitnessItem = deltaItems[0];\n\n        assert(deltaWitnessItem.addedItems.size() == 1);\n        assert(deltaWitnessItem.removedItems.size() == 1);\n        assert(deltaWitnessItem.changeType == changeTypeWitnessAction);\n\n        const auto& addedItemIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(deltaWitnessItem.addedItems[0]);\n        \n        deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(addedItemIter));\n        deltaUndoStream << COMPRESSEDAMOUNT(deltaWitnessItem.removedItems[0].nValue);\n        deltaUndoStream << VARINT(deltaWitnessItem.removedItems[0].blockNumber);\n        deltaUndoStream << VARINT(deltaWitnessItem.removedItems[0].transactionIndex);\n        deltaUndoStream << COMPACTSIZE(deltaWitnessItem.removedItems[0].transactionOutputIndex);\n        \n        pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(addedItemIter);\n        pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(deltaWitnessItem.removedItems[0]);\n        \n        deltaItems.erase(deltaItems.begin());\n    }\n    \n    // Loop for remaining changes, and serialise along with change type identifier\n    for (const auto& deltaItem : deltaItems)\n    {\n        switch(deltaItem.changeType)\n        {\n            case changeTypeWitnessAction:\n            {\n                continue;\n            }\n            case changeTypeCreation:\n            {\n                // We delete the created item\n                assert(deltaItem.addedItems.size() == 1);\n                assert(deltaItem.removedItems.size() == 0);\n\n                auto addedItemIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(deltaItem.addedItems[0]);\n                               \n                deltaUndoStream << changeTypeCreation;\n                deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(addedItemIter));\n                pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(addedItemIter);\n                \n                break;\n            }\n            case changeTypeSpend:\n            {\n                // We add the spent item back into the set\n                assert(deltaItem.addedItems.size() == 0);\n                assert(deltaItem.removedItems.size() == 1);\n\n                auto originalItem = deltaItem.removedItems[0];\n                pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(originalItem);\n\n                deltaUndoStream << changeTypeSpend;\n                deltaUndoStream << VARINT(originalItem.blockNumber);\n                deltaUndoStream << VARINT(originalItem.transactionIndex);\n                deltaUndoStream << COMPACTSIZE(originalItem.transactionOutputIndex);\n                deltaUndoStream << COMPRESSEDAMOUNT(originalItem.nValue);\n                deltaUndoStream << VARINT(originalItem.lockFromBlock);\n                deltaUndoStream << VARINT(originalItem.lockUntilBlock);\n                deltaUndoStream << originalItem.witnessPubKeyID;\n                \n                break;\n            }\n            case changeTypeRenew:\n            {\n                // Revert the renewed item to its original state/position\n                assert(deltaItem.addedItems.size() == 1);\n                assert(deltaItem.removedItems.size() == 1);\n                \n                auto& renewedItem = deltaItem.addedItems[0];\n                auto renewedItemIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(renewedItem);\n                auto& originalItem = deltaItem.removedItems[0];\n                \n                pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(renewedItemIter);\n                pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(originalItem);\n\n                deltaUndoStream << changeTypeRenew;\n                deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(renewedItemIter));\n                deltaUndoStream << VARINT(originalItem.blockNumber);\n                deltaUndoStream << VARINT(originalItem.transactionIndex);\n                deltaUndoStream << COMPACTSIZE(originalItem.transactionOutputIndex);\n                \n                break;\n            }\n            case changeTypeRearrange:\n            {\n                // Remove all the rearranged items and put back the originals\n                assert(deltaItem.addedItems.size() > 0);\n                assert(deltaItem.removedItems.size() > 0);\n                                \n                deltaUndoStream << changeTypeRearrange << COMPACTSIZE(deltaItem.addedItems.size()) << COMPACTSIZE(deltaItem.removedItems.size());\n\n                for (const auto& addItem : deltaItem.addedItems)\n                {\n                    auto addIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(addItem);\n                    deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(addIter));\n                    pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(addIter);\n                }\n                for (const auto& removeItem : deltaItem.removedItems)\n                {\n                    deltaUndoStream << VARINT(removeItem.blockNumber);\n                    deltaUndoStream << VARINT(removeItem.transactionIndex);\n                    deltaUndoStream << COMPACTSIZE(removeItem.transactionOutputIndex);\n                    deltaUndoStream << COMPRESSEDAMOUNT(removeItem.nValue);\n                    pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(removeItem);\n                }\n                break;\n            }\n            case changeTypeIncrease:\n            {\n                // Remove all the increased items and put back the originals\n                assert(deltaItem.addedItems.size() > 0);\n                assert(deltaItem.removedItems.size() > 0);\n                                \n                deltaUndoStream << changeTypeIncrease << COMPACTSIZE(deltaItem.addedItems.size()) << COMPACTSIZE(deltaItem.removedItems.size()) << VARINT(deltaItem.removedItems[0].lockUntilBlock);\n\n                for (const auto& addItem : deltaItem.addedItems)\n                {\n                    auto addIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(addItem);\n                    deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(addIter));\n                    pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(addIter);\n                }\n                for (const auto& removeItem : deltaItem.removedItems)\n                {\n                    deltaUndoStream << VARINT(removeItem.blockNumber);\n                    deltaUndoStream << VARINT(removeItem.transactionIndex);\n                    deltaUndoStream << COMPACTSIZE(removeItem.transactionOutputIndex);\n                    deltaUndoStream << COMPRESSEDAMOUNT(removeItem.nValue);\n                    deltaUndoStream << VARINT(removeItem.lockFromBlock);\n                    pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(removeItem);\n                }\n                break;\n            }\n            case changeTypeChangeKey:\n            {\n                // Remove all the updated items and put back the items with their original key\n                assert(deltaItem.addedItems.size() > 0);\n                assert(deltaItem.removedItems.size() > 0);\n                assert(deltaItem.addedItems.size() == deltaItem.removedItems.size());\n                \n                deltaUndoStream << changeTypeChangeKey << COMPACTSIZE(deltaItem.removedItems.size()) << deltaItem.removedItems[0].witnessPubKeyID;\n                for (uint64_t i=0; i < deltaItem.addedItems.size(); ++i)\n                {\n                    // Remove added item\n                    auto addIter = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.find(deltaItem.addedItems[i]);                    \n                    deltaUndoStream << VARINT(pow2SimplifiedWitnessUTXOUndo.witnessCandidates.index_of(addIter));\n                    \n                    pow2SimplifiedWitnessUTXOUndo.witnessCandidates.erase(addIter);\n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXOUndo.witnessCandidates.insert(deltaItem.removedItems[i]);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                    \n                    // Place back original item\n                    deltaUndoStream << VARINT(deltaItem.removedItems[i].blockNumber);\n                    deltaUndoStream << VARINT(deltaItem.removedItems[i].transactionIndex);\n                    deltaUndoStream << COMPACTSIZE(deltaItem.removedItems[i].transactionOutputIndex);\n                }\n                break;\n            }\n        }\n    }\n    return true;\n}\n\nbool UndoSimplifiedWitnessUTXODeltaForHeader(SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXO, std::vector<unsigned char>& undoWitnessUTXODelta)\n{\n    VectorReader deltaUndoStream(SER_NETWORK, 0, undoWitnessUTXODelta, 0);\n    \n    // First handle the witness that signed the block as a special case, as there is always only one of these at the start, then loop for everything else.\n    {\n        uint64_t selectedWitnessIndex;\n        deltaUndoStream >> VARINT(selectedWitnessIndex);\n        \n        auto witnessIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(selectedWitnessIndex);\n        SimplifiedWitnessRouletteItem witnessItem = *witnessIter;\n        SimplifiedWitnessRouletteItem updatedWitnessItem = witnessItem;\n        deltaUndoStream >> COMPRESSEDAMOUNT(updatedWitnessItem.nValue);\n        deltaUndoStream >> VARINT(updatedWitnessItem.blockNumber);\n        deltaUndoStream >> VARINT(updatedWitnessItem.transactionIndex);\n        deltaUndoStream >> COMPACTSIZE(updatedWitnessItem.transactionOutputIndex);\n        \n        pow2SimplifiedWitnessUTXO.witnessCandidates.erase(witnessIter);\n        auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(updatedWitnessItem);\n        (unused) insertIter;\n        if (!didInsert)\n            return false;\n    }\n    \n    // Rest of the changes are encoded with a type\n    char changeType;\n    while (!deltaUndoStream.empty())\n    {\n        deltaUndoStream >> changeType;\n        switch(changeType)\n        {\n            // Delete the created item\n            case changeTypeCreation:\n            {\n                uint64_t createdItemIndex;\n                deltaUndoStream >> VARINT(createdItemIndex);\n                pow2SimplifiedWitnessUTXO.witnessCandidates.erase(pow2SimplifiedWitnessUTXO.witnessCandidates.nth(createdItemIndex));\n                break;\n            }\n            // Recreate the deleted/spent item\n            case changeTypeSpend:\n            {\n                SimplifiedWitnessRouletteItem item;\n                deltaUndoStream >> VARINT(item.blockNumber);\n                deltaUndoStream >> VARINT(item.transactionIndex);\n                deltaUndoStream >> COMPACTSIZE(item.transactionOutputIndex);\n                deltaUndoStream >> COMPRESSEDAMOUNT(item.nValue);\n                deltaUndoStream >> VARINT(item.lockFromBlock);\n                deltaUndoStream >> VARINT(item.lockUntilBlock);\n                deltaUndoStream >> item.witnessPubKeyID;\n                \n                auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                (unused) insertIter;\n                if (!didInsert)\n                    return false;\n\n                break;\n            }\n            // Remove the renewed item and place back the original item\n            case changeTypeRenew:\n            {\n                uint64_t renewedItemIndex;\n                deltaUndoStream >> VARINT(renewedItemIndex);\n                \n                auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(renewedItemIndex);\n                SimplifiedWitnessRouletteItem item = *itemIter;\n                SimplifiedWitnessRouletteItem modifiedItem = item;\n                deltaUndoStream >> VARINT(modifiedItem.blockNumber);\n                deltaUndoStream >> VARINT(modifiedItem.transactionIndex);\n                deltaUndoStream >> COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                \n                pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                (unused) insertIter;\n                if (!didInsert)\n                    return false;\n                \n                break;\n            }\n            // Perform the re-arrangement but in reverse\n            case changeTypeRearrange:\n            {\n                uint64_t numItemsToRemove;\n                uint64_t numItemsToAdd;\n                deltaUndoStream >> COMPACTSIZE(numItemsToRemove) >> COMPACTSIZE(numItemsToAdd);\n                \n                SimplifiedWitnessRouletteItem item;\n                for (uint64_t i=0; i<numItemsToRemove; ++i)\n                {\n                    uint64_t outputIndex;\n                    deltaUndoStream >> VARINT(outputIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(outputIndex);\n                    if (i == 0)\n                    {\n                        item = *itemIter;\n                    }\n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                }\n                for (uint64_t i=0; i<numItemsToAdd; ++i)\n                {\n                    deltaUndoStream >> VARINT(item.blockNumber);\n                    deltaUndoStream >> VARINT(item.transactionIndex);\n                    deltaUndoStream >> COMPACTSIZE(item.transactionOutputIndex);\n                    deltaUndoStream >> COMPRESSEDAMOUNT(item.nValue);\n                    \n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                }\n                break;\n            }\n            // Reverse the increase/re-arrangement\n            case changeTypeIncrease:\n            {\n                uint64_t numItemsToRemove;\n                uint64_t numItemsToAdd;\n                uint64_t originalLockUntilBlock;\n                deltaUndoStream >> COMPACTSIZE(numItemsToRemove) >> COMPACTSIZE(numItemsToAdd) >> VARINT(originalLockUntilBlock);\n                \n                SimplifiedWitnessRouletteItem item;\n                for (uint64_t i=0; i<numItemsToRemove; ++i)\n                {\n                    uint64_t outputIndex;\n                    deltaUndoStream >> VARINT(outputIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(outputIndex);\n                    if (i == 0)\n                    {\n                        item = *itemIter;\n                        item.lockUntilBlock = originalLockUntilBlock;\n                    }\n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                }\n                for (uint64_t i=0; i<numItemsToAdd; ++i)\n                {\n                    deltaUndoStream >> VARINT(item.blockNumber);\n                    deltaUndoStream >> VARINT(item.transactionIndex);\n                    deltaUndoStream >> COMPACTSIZE(item.transactionOutputIndex);\n                    deltaUndoStream >> COMPRESSEDAMOUNT(item.nValue);\n                    deltaUndoStream >> VARINT(item.lockFromBlock);\n                    \n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                }\n                break;\n            }\n            // Change the key back\n            case changeTypeChangeKey:\n            {\n                uint64_t numItems;\n                deltaUndoStream >> COMPACTSIZE(numItems);\n                CKeyID witnessKeyID;\n                deltaUndoStream >> witnessKeyID;\n                \n                for (uint64_t i=0; i < numItems; ++i )\n                {\n                    uint64_t itemIndex;\n                    deltaUndoStream >> VARINT(itemIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(itemIndex);\n                    SimplifiedWitnessRouletteItem item = *itemIter;\n                    \n                    item.witnessPubKeyID = witnessKeyID;\n                    deltaUndoStream >> VARINT(item.blockNumber);\n                    deltaUndoStream >> VARINT(item.transactionIndex);\n                    deltaUndoStream >> COMPACTSIZE(item.transactionOutputIndex);\n                    \n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                }\n                break;\n            }\n        }\n    }\n    return true;\n}\n\n//fixme: (WITNESS_SYNC) - REMOVE AFTER TESTING\n#ifdef DEBUG\n#define EXTRA_DELTA_TESTS 1\n#endif\n\nbool ApplySimplifiedWitnessUTXODeltaForHeader(const CBlockIndex* pIndex, SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXO, std::vector<unsigned char>& undoWitnessUTXODelta)\n{\n    #ifdef EXTRA_DELTA_TESTS\n    SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXOOrig = pow2SimplifiedWitnessUTXO;\n    #endif\n    \n    if (pIndex->witnessUTXODelta.size() == 0)\n        return false;\n\n    VectorReader deltaStream(SER_NETWORK, 0, pIndex->witnessUTXODelta, 0);\n    \n    std::vector<deltaItem> deltaItems;\n\n    // First handle the witness that signed the block as a special case, as there is always only one of these at the start, then loop for everything else.\n    {\n        uint64_t selectedWitnessIndex;\n        deltaStream >> VARINT(selectedWitnessIndex);\n        \n        auto removedItemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(selectedWitnessIndex);\n        SimplifiedWitnessRouletteItem witnessItem = *removedItemIter;\n        SimplifiedWitnessRouletteItem updatedWitnessItem = witnessItem;\n        deltaStream >> COMPRESSEDAMOUNT(updatedWitnessItem.nValue);\n        updatedWitnessItem.blockNumber = pIndex->nHeight;\n        deltaStream >> VARINT(updatedWitnessItem.transactionIndex);\n        //We don't encode the transactionOutputIndex it always becomes 0\n        updatedWitnessItem.transactionOutputIndex=0;\n        \n        pow2SimplifiedWitnessUTXO.witnessCandidates.erase(removedItemIter);\n        auto [updatedItemIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(updatedWitnessItem);\n        (unused) updatedItemIter;\n        if (!didInsert)\n            return false;\n        \n        deltaItem undo;\n        undo.changeType=changeTypeWitnessAction;\n        undo.removedItems.push_back(witnessItem);\n        undo.addedItems.push_back(updatedWitnessItem);\n        deltaItems.push_back(undo);\n    }\n\n    // Rest of the changes are encoded with a type\n    // We store the changes as we go so that we can generate undo information\n    // NB! Its not possible/enough to generate undo data on the fly, as each action can affect the index(es) of other actions, we must actually replay the actions as we generate the items (just like how we generate the actual changes)\n    char changeType;\n    while (!deltaStream.empty())\n    {\n        deltaStream >> changeType;\n        switch(changeType)\n        {\n            case changeTypeCreation:\n            {\n                SimplifiedWitnessRouletteItem modifiedItem;\n                modifiedItem.blockNumber = pIndex->nHeight;\n                deltaStream >> VARINT(modifiedItem.transactionIndex);\n                deltaStream >> COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                deltaStream >> COMPRESSEDAMOUNT(modifiedItem.nValue);\n                modifiedItem.lockFromBlock = pIndex->nHeight;\n                deltaStream >> VARINT(modifiedItem.lockUntilBlock);\n                deltaStream >> modifiedItem.witnessPubKeyID;\n                \n                auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                (unused) insertIter;\n                if (!didInsert)\n                    return false;\n                \n                deltaItem undo;\n                undo.changeType=changeTypeCreation;\n                undo.addedItems.push_back(modifiedItem);\n                deltaItems.push_back(undo);                \n                break;\n            }\n            case changeTypeSpend:\n            {\n                uint64_t spentWitnessSetIndex;\n                deltaStream >> VARINT(spentWitnessSetIndex);\n                \n                auto iter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(spentWitnessSetIndex);\n                SimplifiedWitnessRouletteItem originalItem = *iter;\n                //only one input allowed, must be completely consumed, so we just cancel its existence in the set\n                pow2SimplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                \n                deltaItem undo;\n                undo.changeType=changeTypeSpend;\n                undo.removedItems.push_back(originalItem);\n                deltaItems.push_back(undo);\n                \n                break;\n            }\n            case changeTypeRenew:\n            {\n                uint64_t renewWitnessSetIndex;\n                deltaStream >> VARINT(renewWitnessSetIndex);\n                \n                auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(renewWitnessSetIndex);\n                SimplifiedWitnessRouletteItem originalItem = *itemIter;\n                SimplifiedWitnessRouletteItem modifiedItem = originalItem;\n                modifiedItem.blockNumber = pIndex->nHeight;\n                deltaStream >> VARINT(modifiedItem.transactionIndex);\n                deltaStream >> COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                \n                pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                (unused) insertIter;\n                if (!didInsert)\n                    return false;\n                \n                deltaItem undo;\n                undo.changeType=changeTypeRenew;\n                undo.removedItems.push_back(originalItem);\n                undo.addedItems.push_back(modifiedItem);\n                deltaItems.push_back(undo);\n                \n                break;\n            }\n            case changeTypeRearrange:\n            {\n                uint64_t numInputs;\n                uint64_t numOutputs;\n                deltaStream >> COMPACTSIZE(numInputs) >> COMPACTSIZE(numOutputs);\n                \n                deltaItem undo;\n                undo.changeType=changeTypeRearrange;\n\n                SimplifiedWitnessRouletteItem item;\n                for (uint64_t i=0; i<numInputs; ++i)\n                {\n                    uint64_t inputIndex;\n                    deltaStream >> VARINT(inputIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(inputIndex);\n                    item=*itemIter;\n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                    \n                    undo.removedItems.push_back(item);\n                }\n                for (uint64_t i=0; i<numOutputs; ++i)\n                {\n                    item.blockNumber = pIndex->nHeight;\n                    deltaStream >> VARINT(item.transactionIndex);\n                    deltaStream >> COMPACTSIZE(item.transactionOutputIndex);\n                    deltaStream >> COMPRESSEDAMOUNT(item.nValue);\n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                    \n                    undo.addedItems.push_back(item);\n                }\n                deltaItems.push_back(undo);\n                break;\n            }\n            case changeTypeIncrease:\n            {\n                uint64_t numInputs;\n                uint64_t numOutputs;\n                uint64_t lockUntilBlock;\n                deltaStream >> COMPACTSIZE(numInputs) >> COMPACTSIZE(numOutputs) >> VARINT(lockUntilBlock);\n                \n                deltaItem undo;\n                undo.changeType=changeTypeIncrease;\n\n                SimplifiedWitnessRouletteItem item;\n                for (uint64_t i=0; i<numInputs; ++i)\n                {\n                    uint64_t inputIndex;\n                    deltaStream >> VARINT(inputIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(inputIndex);\n                    item = *itemIter;\n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                    \n                    undo.removedItems.push_back(item);\n                }                \n                item.lockFromBlock = pIndex->nHeight;\n                item.lockUntilBlock = lockUntilBlock;\n                for (uint64_t i=0; i<numOutputs; ++i)\n                {\n                    item.blockNumber = pIndex->nHeight;\n                    deltaStream >> VARINT(item.transactionIndex);\n                    deltaStream >> COMPACTSIZE(item.transactionOutputIndex);\n                    deltaStream >> COMPRESSEDAMOUNT(item.nValue);\n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(item);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                    \n                    undo.addedItems.push_back(item);\n                }\n                deltaItems.push_back(undo);\n                break;\n            }\n            case changeTypeChangeKey:\n            {\n                uint64_t numItems;\n                deltaStream >> COMPACTSIZE(numItems);\n                CKeyID witnessKeyID;\n                deltaStream >> witnessKeyID;\n                \n                deltaItem undo;\n                undo.changeType=changeTypeChangeKey;\n                \n                for (uint64_t i=0; i < numItems; ++i )\n                {\n                    uint64_t itemIndex;\n                    deltaStream >> VARINT(itemIndex);\n                    auto itemIter = pow2SimplifiedWitnessUTXO.witnessCandidates.nth(itemIndex);\n                    SimplifiedWitnessRouletteItem originalItem = *itemIter;\n                    SimplifiedWitnessRouletteItem changedItem = originalItem;\n                    \n                    changedItem.witnessPubKeyID = witnessKeyID;\n                    changedItem.blockNumber = pIndex->nHeight;\n                    deltaStream >> VARINT(changedItem.transactionIndex);\n                    deltaStream >> COMPACTSIZE(changedItem.transactionOutputIndex);\n                    \n                    pow2SimplifiedWitnessUTXO.witnessCandidates.erase(itemIter);\n                    auto [insertIter, didInsert] = pow2SimplifiedWitnessUTXO.witnessCandidates.insert(changedItem);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                    \n                    undo.removedItems.push_back(originalItem);\n                    undo.addedItems.push_back(changedItem);\n                }\n                deltaItems.push_back(undo);\n                break;\n            }\n        }\n    }\n    \n    \n    #ifdef EXTRA_DELTA_TESTS\n    // After applying the undo information the two should be identical again\n    assert(pow2SimplifiedWitnessUTXOOrig != pow2SimplifiedWitnessUTXO);\n    #endif\n    \n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOUndo = pow2SimplifiedWitnessUTXO;\n    if (!GenerateSimplifiedWitnessUTXODeltaUndoForHeader(undoWitnessUTXODelta, pow2SimplifiedWitnessUTXOUndo, deltaItems))\n        return false;\n    \n    #ifdef EXTRA_DELTA_TESTS\n    // After applying the undo information the two should be identical again\n    assert(pow2SimplifiedWitnessUTXOOrig == pow2SimplifiedWitnessUTXOUndo);\n    \n    pow2SimplifiedWitnessUTXOUndo = pow2SimplifiedWitnessUTXO;\n    UndoSimplifiedWitnessUTXODeltaForHeader(pow2SimplifiedWitnessUTXOUndo, undoWitnessUTXODelta);\n    // After applying the undo information the two should be identical again\n    assert(pow2SimplifiedWitnessUTXOOrig == pow2SimplifiedWitnessUTXOUndo);\n    #endif\n    \n    return true;\n}\n\nSimplifiedWitnessUTXOSet GenerateSimplifiedWitnessUTXOSetFromUTXOSet(std::map<COutPoint, Coin> allWitnessCoinsIndexBased)\n{\n    SimplifiedWitnessUTXOSet witnessUTXOset;\n    \n    for (const auto& [outpoint, coin] : allWitnessCoinsIndexBased) \n    {\n        SimplifiedWitnessRouletteItem item;\n        \n        item.blockNumber = outpoint.getTransactionBlockNumber();\n        item.transactionIndex = outpoint.getTransactionIndex();\n        item.transactionOutputIndex = outpoint.n;\n        item.lockUntilBlock = coin.out.output.witnessDetails.lockUntilBlock;\n        item.lockFromBlock = coin.out.output.witnessDetails.lockFromBlock;\n        if (item.lockFromBlock == 0)\n        {\n            item.lockFromBlock = item.blockNumber;\n        }\n        item.witnessPubKeyID = coin.out.output.witnessDetails.witnessKeyID;\n        item.nValue = coin.out.nValue;\n        witnessUTXOset.witnessCandidates.insert(item);\n    }\n    \n    return witnessUTXOset;\n}\n\nbool GetSimplifiedWitnessUTXOSetForIndex(const CBlockIndex* pBlockIndex, SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXOForBlock)\n{\n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOCopy = pow2SimplifiedWitnessUTXO;\n    if (pow2SimplifiedWitnessUTXOCopy.currentTipForSet.IsNull() || pow2SimplifiedWitnessUTXO.currentTipForSet != pBlockIndex->GetBlockHashPoW2())\n    {\n        std::map<COutPoint, Coin> allWitnessCoinsIndexBased;\n        if (!getAllUnspentWitnessCoins(chainActive, Params(), pBlockIndex, allWitnessCoinsIndexBased, nullptr, nullptr, true))\n            return false;\n    \n        pow2SimplifiedWitnessUTXOCopy = GenerateSimplifiedWitnessUTXOSetFromUTXOSet(allWitnessCoinsIndexBased);\n        pow2SimplifiedWitnessUTXOCopy.currentTipForSet = pBlockIndex->GetBlockHashPoW2();\n        pow2SimplifiedWitnessUTXOForBlock = pow2SimplifiedWitnessUTXO = pow2SimplifiedWitnessUTXOCopy;\n        return true;\n    }\n    else\n    {\n        // We are already the tip so no further action required\n        pow2SimplifiedWitnessUTXOForBlock = pow2SimplifiedWitnessUTXOCopy;\n        return true;\n    }\n}\n\n\nbool GetSimplifiedWitnessUTXODeltaForBlockHelper(uint64_t nBlockHeight, const CBlock& block, CVectorWriter& deltaStream, std::vector<deltaItem>& deltaItems, SimplifiedWitnessUTXOSet& simplifiedWitnessUTXO, SimplifiedWitnessUTXOSet& simplifiedWitnessUTXOWithoutWitnessAction)\n{\n    bool anyChanges=false;\n    // Calculate changes this block would make\n    for (const auto& tx : block.vtx)\n    {\n        if (!tx->witnessBundles)\n            return false;\n\n        for (const auto& bundle : *tx->witnessBundles)\n        {\n            anyChanges = true;\n            if (bundle.bundleType == CWitnessTxBundle::WitnessType)\n            {\n                // Basic sanity checks\n                assert(bundle.inputs.size() == 1);\n                assert(bundle.outputs.size() == 1);\n                assert(!std::get<2>(bundle.inputs[0]).IsNull());\n                \n                // Find existing item\n                SimplifiedWitnessRouletteItem originalItem(bundle.inputs[0]);\n                auto iter = simplifiedWitnessUTXO.witnessCandidates.find(originalItem);\n                if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                    return false;\n\n                // Generate changeset\n                {\n                    deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n                    deltaStream << COMPRESSEDAMOUNT(std::get<0>(bundle.outputs[0]).nValue);\n                    //No need to encode block number, we can obtain it from the block index\n                    deltaStream << VARINT(std::get<2>(bundle.outputs[0]).getTransactionIndex());\n                    //No need to encode vout position, its always 0\n                    assert(std::get<2>(bundle.outputs[0]).n == 0);\n                }\n                \n                // Perform the change so that subsequent changes can use the right indexing \n                // from here we can reset the blocknumber and value and identify that signature matches\n                // Only ever one witness action.\n                {\n                    SimplifiedWitnessRouletteItem modifiedItem=originalItem;\n                    modifiedItem.nValue = std::get<0>(bundle.outputs[0]).nValue;\n                    modifiedItem.blockNumber = nBlockHeight;\n                    if (modifiedItem.lockFromBlock == 0)\n                        modifiedItem.lockFromBlock = modifiedItem.blockNumber;\n                    modifiedItem.transactionIndex = std::get<2>(bundle.outputs[0]).getTransactionIndex();\n                    modifiedItem.transactionOutputIndex = 0;\n                    \n                    simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                    auto [insertIter, didInsert] = simplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                    (unused) insertIter;\n                    if (!didInsert)\n                        return false;\n                    \n                    deltaItem undo;\n                    undo.changeType=changeTypeWitnessAction;\n                    undo.removedItems.push_back(originalItem);\n                    undo.addedItems.push_back(modifiedItem);\n                    deltaItems.push_back(undo);\n                }\n\n                break;\n            }\n        }\n    }\n    for (const auto& tx : block.vtx)\n    {   \n        for (const auto& bundle : *tx->witnessBundles)\n        {\n            switch (bundle.bundleType)\n            {\n                case CWitnessTxBundle::WitnessType:\n                {\n                    // Already done in previous loop\n                    continue;\n                }\n                case CWitnessTxBundle::CreationType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() == 0);\n                    assert(bundle.outputs.size() > 0);\n\n                    // Treat each item in the bundle as its own seperate creation, instead of trying to cram them all into one\n                    for (const auto& output: bundle.outputs)\n                    {\n                        SimplifiedWitnessRouletteItem modifiedItem;\n                        modifiedItem.blockNumber = nBlockHeight;\n                        modifiedItem.transactionIndex = std::get<2>(output).getTransactionIndex();\n                        modifiedItem.transactionOutputIndex = std::get<2>(output).n;\n                        modifiedItem.nValue = std::get<0>(output).nValue;\n                        modifiedItem.lockFromBlock = modifiedItem.blockNumber;\n                        modifiedItem.lockUntilBlock = std::get<1>(output).lockUntilBlock;\n                        modifiedItem.witnessPubKeyID = std::get<1>(output).witnessKeyID;\n                        \n                        deltaStream << changeTypeCreation;\n                        //no need to encode blockNumber because it can be determined from the header\n                        deltaStream << VARINT(modifiedItem.transactionIndex);\n                        deltaStream << COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                        deltaStream << VARINT(modifiedItem.nValue);\n                        deltaStream << VARINT(modifiedItem.lockUntilBlock);\n                        //lockFrom can in turn be figured out from the blockNumber\n                        deltaStream << modifiedItem.witnessPubKeyID;\n                        \n                        // Insert new item into set\n                        simplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.insert(modifiedItem);\n                        \n                        deltaItem undo;\n                        undo.changeType=changeTypeCreation;\n                        undo.addedItems.push_back(modifiedItem);\n                        deltaItems.push_back(undo);\n                    }\n                    break;\n                }\n                //only one input allowed, must be completely consumed (removed from set)\n                case CWitnessTxBundle::SpendType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() == 1);\n                    assert(bundle.outputs.size() == 0);\n                    assert(!std::get<2>(bundle.inputs[0]).IsNull());\n\n                    // Find existing item\n                    SimplifiedWitnessRouletteItem originalItem(bundle.inputs[0]);\n                    auto iter = simplifiedWitnessUTXO.witnessCandidates.find(originalItem);\n                    if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                        return false;\n                \n                    deltaStream << changeTypeSpend;\n                    deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n                    \n                    // Remove spent item from set\n                    simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                    simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.erase(simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.find(originalItem));\n                    \n                    deltaItem undo;\n                    undo.changeType=changeTypeSpend;\n                    undo.removedItems.push_back(originalItem);\n                    deltaItems.push_back(undo);\n\n                    break;\n                }\n                case CWitnessTxBundle::RenewType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() > 0);\n                    assert(bundle.outputs.size() > 0);\n                    assert(bundle.inputs.size() == bundle.outputs.size());\n                    assert(!std::get<2>(bundle.inputs[0]).IsNull());\n                    \n                    // Treat each renew as a seperate change instead of trying to encode them all together\n                    for (uint64_t i=0; i<bundle.inputs.size(); ++i)\n                    {\n                        const auto& input = bundle.inputs[i];\n                        const auto& output = bundle.outputs[i];\n                    \n                        // Find existing item\n                        SimplifiedWitnessRouletteItem originalItem(input);\n                        auto iter = simplifiedWitnessUTXO.witnessCandidates.find(originalItem);\n                        if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                            return false;\n                        \n                        SimplifiedWitnessRouletteItem modifiedItem = originalItem;\n                        modifiedItem.blockNumber = nBlockHeight;\n                        modifiedItem.transactionIndex = std::get<2>(output).getTransactionIndex();\n                        modifiedItem.transactionOutputIndex = std::get<2>(output).n;\n                        if (modifiedItem.lockFromBlock == 0)\n                            modifiedItem.lockFromBlock = modifiedItem.blockNumber;\n                        \n                        deltaStream << changeTypeRenew;\n                        deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n                        //no need to encode blockNumber because it can be determined from the header\n                        deltaStream << VARINT(modifiedItem.transactionIndex);\n                        deltaStream << COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                        \n                        // Update renewed item in set\n                        simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.erase(simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.find(originalItem));\n                        auto [insertIter, didInsert] = simplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                        (unused) insertIter;\n                        if (!didInsert)\n                            assert(0);\n                        \n                        deltaItem undo;\n                        undo.changeType=changeTypeRenew;\n                        undo.removedItems.push_back(originalItem);\n                        undo.addedItems.push_back(modifiedItem);\n                        deltaItems.push_back(undo);\n                    }\n                    break;\n                }\n                case CWitnessTxBundle::RearrangeType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() > 0);\n                    assert(bundle.outputs.size() > 0);\n                    \n                    // Encode common information\n                    deltaStream << changeTypeRearrange << COMPACTSIZE(bundle.inputs.size()) << COMPACTSIZE(bundle.outputs.size());\n                    \n                    deltaItem undo;\n                    undo.changeType=changeTypeRearrange;\n                    \n                    // Encode removal of items; don't perform removal yet as they will then invalidate one anothers indexes\n                    SimplifiedWitnessRouletteItem item;\n                    for (const auto& input : bundle.inputs)\n                    {\n                        item = SimplifiedWitnessRouletteItem(input);\n                        auto iter = simplifiedWitnessUTXO.witnessCandidates.find(item);\n                        if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                            return false;\n\n                        deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n                        \n                        undo.removedItems.push_back(item);\n                        simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.erase(simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.find(item));\n                    }\n\n                    // Encode and perform reinsertion of modified items\n                    for (const auto& output : bundle.outputs)\n                    {\n                        item.blockNumber = nBlockHeight;\n                        item.transactionIndex = std::get<2>(output).getTransactionIndex();\n                        item.transactionOutputIndex = std::get<2>(output).n;\n                        item.nValue = std::get<0>(output).nValue;\n                        if (item.lockFromBlock == 0)\n                            item.lockFromBlock = nBlockHeight;\n                        \n                        //no need to encode blockNumber because it can be determined from the header\n                        deltaStream << VARINT(item.transactionIndex);\n                        deltaStream << COMPACTSIZE(item.transactionOutputIndex);\n                        deltaStream << COMPRESSEDAMOUNT(item.nValue);\n                        \n                        simplifiedWitnessUTXO.witnessCandidates.insert(item);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.insert(item);\n                        undo.addedItems.push_back(item);\n                    }\n                    deltaItems.push_back(undo);\n                    break;\n                }\n                case CWitnessTxBundle::IncreaseType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() > 0);\n                    assert(bundle.outputs.size() > 0);\n                    \n                    // Encode common information, all new items must share the same lockUntilBlock so we encode that here instead of repeating it for each item\n                    uint64_t newLockUntilBlock = std::get<1>(bundle.outputs[0]).lockUntilBlock;\n                    deltaStream << changeTypeIncrease << COMPACTSIZE(bundle.inputs.size()) << COMPACTSIZE(bundle.outputs.size()) << VARINT(newLockUntilBlock);\n                    \n                    deltaItem undo;\n                    undo.changeType=changeTypeIncrease;\n\n                    // Encode removal of items; don't perform removal yet as they will then invalidate one anothers indexes\n                    SimplifiedWitnessRouletteItem item;\n                    for (const auto& input : bundle.inputs)\n                    {\n                        item = SimplifiedWitnessRouletteItem(input);\n                        auto iter = simplifiedWitnessUTXO.witnessCandidates.find(item);\n                        if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                            return false;\n                    \n                        deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n\n                        undo.removedItems.push_back(item);\n                        simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.erase(simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.find(item));\n                    }\n\n                    // Encode and perform reinsertion of modified items\n                    for (const auto& output : bundle.outputs)\n                    {\n                        item.blockNumber = nBlockHeight;\n                        item.transactionIndex = std::get<2>(output).getTransactionIndex();\n                        item.transactionOutputIndex = std::get<2>(output).n;\n                        item.nValue = std::get<0>(output).nValue;\n                        item.lockFromBlock = nBlockHeight;\n                        item.lockUntilBlock = std::get<1>(output).lockUntilBlock;\n                        \n                        //no need to encode blockNumber because it can be determined from the header\n                        deltaStream << VARINT(item.transactionIndex);\n                        deltaStream << COMPACTSIZE(item.transactionOutputIndex);\n                        deltaStream << COMPRESSEDAMOUNT(item.nValue);\n                        //no need to encode lockfrom  because it can be determined from the header (note lockfrom changes with an increase type bundle)\n                        //lockUntilBlock encoded once for all bundles, before this loop\n                        \n                        simplifiedWitnessUTXO.witnessCandidates.insert(item);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.insert(item);\n                        undo.addedItems.push_back(item);\n                    }\n                    deltaItems.push_back(undo);\n                    break;\n                }\n                case CWitnessTxBundle::ChangeWitnessKeyType:\n                {\n                    // Basic sanity checks\n                    assert(bundle.inputs.size() > 0);\n                    assert(bundle.inputs.size() == bundle.outputs.size());\n                    \n                    // Encode common information\n                    // Can have multiple inputs/outputs, always matching in number so only encode output size\n                    // All new items must share a new witness key, so encode the key once here instead of individually for each item\n                    CKeyID newWitnessKeyID = std::get<1>(bundle.outputs[0]).witnessKeyID;\n                    deltaStream << changeTypeChangeKey << COMPACTSIZE(bundle.outputs.size()) << newWitnessKeyID;\n                    \n                    deltaItem undo;\n                    undo.changeType=changeTypeChangeKey;\n                    \n                    for (uint64_t index=0; index < bundle.inputs.size();++index)\n                    {\n                        auto& input = bundle.inputs[index];\n                        auto& output = bundle.outputs[index];\n\n                        SimplifiedWitnessRouletteItem originalItem(input);\n                        auto iter = simplifiedWitnessUTXO.witnessCandidates.find(originalItem);\n                        if (iter == simplifiedWitnessUTXO.witnessCandidates.end())\n                            return false;\n                    \n                        deltaStream << VARINT(simplifiedWitnessUTXO.witnessCandidates.index_of(iter));\n                        \n                        SimplifiedWitnessRouletteItem modifiedItem = originalItem;\n                        modifiedItem.blockNumber = nBlockHeight;\n                        modifiedItem.transactionIndex = std::get<2>(output).getTransactionIndex();\n                        modifiedItem.transactionOutputIndex = std::get<2>(output).n;\n                        modifiedItem.witnessPubKeyID = newWitnessKeyID;\n                        \n                        //no need to encode blockNumber because it can be determined from the header\n                        deltaStream << VARINT(modifiedItem.transactionIndex);\n                        deltaStream << COMPACTSIZE(modifiedItem.transactionOutputIndex);\n                        //no need to encode lockfrom  because it can be determined from the header (note lockfrom changes with an increase type bundle)\n                        \n                        simplifiedWitnessUTXO.witnessCandidates.erase(iter);\n                        simplifiedWitnessUTXO.witnessCandidates.insert(modifiedItem);\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.erase(simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.find(originalItem));\n                        simplifiedWitnessUTXOWithoutWitnessAction.witnessCandidates.insert(modifiedItem);\n                        \n                        undo.removedItems.push_back(originalItem);\n                        undo.addedItems.push_back(modifiedItem);\n                    }\n                    deltaItems.push_back(undo);\n                    break;\n                }\n            }\n        }\n    }\n    if (!anyChanges)\n        return false;\n\n    return true;\n}\n\nbool GetSimplifiedWitnessUTXODeltaForBlock(const CBlockIndex* pBlockIndex, const CBlock& block, std::shared_ptr<SimplifiedWitnessUTXOSet> pow2SimplifiedWitnessUTXOForPrevBlock, std::vector<unsigned char>& compWitnessUTXODelta, CPubKey* pubkey)\n{\n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOModified = *pow2SimplifiedWitnessUTXOForPrevBlock;\n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOModifiedWithoutWitnessAction = pow2SimplifiedWitnessUTXOModified;\n    \n    #ifdef EXTRA_DELTA_TESTS\n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOOrig = pow2SimplifiedWitnessUTXOModified;\n    #endif\n    \n    // Calculate what changes the block makes to the simplified witness utxo set\n    std::vector<deltaItem> deltaItems;\n    CVectorWriter deltaStream(SER_NETWORK, 0, compWitnessUTXODelta, 0);\n    if (!GetSimplifiedWitnessUTXODeltaForBlockHelper(pBlockIndex->nHeight, block, deltaStream, deltaItems, pow2SimplifiedWitnessUTXOModified, pow2SimplifiedWitnessUTXOModifiedWithoutWitnessAction))\n        return false;\n\n    // Our copy must have changes so should not match the original\n    #ifdef EXTRA_DELTA_TESTS\n    assert(pow2SimplifiedWitnessUTXOModified != pow2SimplifiedWitnessUTXOOrig);\n    #endif\n    \n    if (pubkey)\n    {\n        DO_BENCHMARKT(\"CheckBlockHeaderIsPoWValid - VERIFYWITNESS_SIMPLIFIED_INTERNAL\", BCLog::BENCH, 0);\n\n        CGetWitnessInfo witInfo;\n        GetWitnessFromSimplifiedUTXO(pow2SimplifiedWitnessUTXOModifiedWithoutWitnessAction, pBlockIndex, witInfo);\n        if(witInfo.selectedWitnessTransaction.GetType() == CTxOutType::PoW2WitnessOutput)\n        {\n            if (witInfo.selectedWitnessTransaction.output.witnessDetails.witnessKeyID != pubkey->GetID())\n            {\n                return false;\n            }\n        }\n        else\n        {\n            return false;\n        }\n    }\n    \n    // Generate the undo info, when done pow2SimplifiedWitnessUTXOUndo should match our original item again\n    SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXOUndo = pow2SimplifiedWitnessUTXOModified;\n    std::vector<unsigned char> undoWitnessUTXODelta;\n    if (!GenerateSimplifiedWitnessUTXODeltaUndoForHeader(undoWitnessUTXODelta, pow2SimplifiedWitnessUTXOUndo, deltaItems))\n        return false;\n    \n    // As we have now undone the changes while generating the undo info, we should match the original again\n    #ifdef EXTRA_DELTA_TESTS\n    assert(pow2SimplifiedWitnessUTXOUndo == pow2SimplifiedWitnessUTXOOrig);\n    #endif\n    \n    // Revert to the modified set (with changes), apply the generated undo info, and ensure the final result matches the original set (this tests full roundtrip)\n    #ifdef EXTRA_DELTA_TESTS\n    pow2SimplifiedWitnessUTXOUndo = pow2SimplifiedWitnessUTXOModified;\n    UndoSimplifiedWitnessUTXODeltaForHeader(pow2SimplifiedWitnessUTXOUndo, undoWitnessUTXODelta);\n    assert(pow2SimplifiedWitnessUTXOUndo == pow2SimplifiedWitnessUTXOOrig);\n    #endif\n\n    // Set our modified set as the latest we have\n    if (pBlockIndex->nVersionPoW2Witness != 0)\n    {\n        pow2SimplifiedWitnessUTXOModified.currentTipForSet = pBlockIndex->GetBlockHashPoW2();    \n        pow2SimplifiedWitnessUTXO = pow2SimplifiedWitnessUTXOModified;\n    }\n    \n    return true;\n}\n"
  },
  {
    "path": "src/validation/witnessvalidation.h",
    "content": "// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WITNESS_VALIDATION_H\n#define WITNESS_VALIDATION_H\n\n#include \"validation/validation.h\"\n#include <boost/container/flat_set.hpp>\n\n//fixme: (PHASE5) - Properly document all of these; including pre/post conditions;\n//fixme: (PHASE5) implement unit tests.\n\n\n// Encapusulate the bare minimum information we need to know about every witness address in order to select/verify a valid witness for a block\n// Without any of the additional information thats necessary for other parts of the witness system (e.g. spending key) but not this specific function\n// And without information that can be derived from this core information (e.g. age)\nclass SimplifiedWitnessRouletteItem\n{\npublic:\n    SimplifiedWitnessRouletteItem(){};\n    SimplifiedWitnessRouletteItem(const std::tuple<const CTxOut, CTxOutPoW2Witness, COutPoint>& witnessInput)\n    {    \n        blockNumber = std::get<2>(witnessInput).getTransactionBlockNumber();\n        transactionIndex = std::get<2>(witnessInput).getTransactionIndex();\n        transactionOutputIndex = std::get<2>(witnessInput).n;\n\n        lockUntilBlock = std::get<1>(witnessInput).lockUntilBlock;\n        lockFromBlock = std::get<1>(witnessInput).lockFromBlock;\n        if (lockFromBlock == 0)\n        {\n            lockFromBlock = blockNumber;\n        }\n        witnessPubKeyID = std::get<1>(witnessInput).witnessKeyID;\n        nValue = std::get<0>(witnessInput).nValue;\n    }\n    uint64_t blockNumber;\n    uint64_t transactionIndex;\n    uint32_t transactionOutputIndex;\n    uint64_t lockUntilBlock;\n    uint64_t lockFromBlock;\n    CKeyID witnessPubKeyID;\n    CAmount nValue;\n    \n    uint64_t GetLockLength()\n    {\n        return (lockUntilBlock-lockFromBlock)+1;\n    }\n    \n    friend inline bool operator!=(const SimplifiedWitnessRouletteItem& a, const SimplifiedWitnessRouletteItem& b)\n    {\n        return !(a == b);\n    }\n\n    friend inline bool operator==(const SimplifiedWitnessRouletteItem& a, const SimplifiedWitnessRouletteItem& b)\n    {\n        if (a.blockNumber != b.blockNumber ||\n            a.transactionIndex != b.transactionIndex ||\n            a.transactionOutputIndex != b.transactionOutputIndex ||\n            a.lockUntilBlock != b.lockUntilBlock ||\n            a.nValue != b.nValue ||\n            a.witnessPubKeyID != b.witnessPubKeyID\n        )\n        {\n            return false;\n        }\n        return true;\n    }\n    \n    //NB! This ordering must precisely match the ordering of RouletteItem::operator< (assuming all items use index based outpoints)\n    friend inline bool operator<(const SimplifiedWitnessRouletteItem& a, const SimplifiedWitnessRouletteItem& b)\n    {\n        if (a.blockNumber == b.blockNumber)\n        {\n            if (a.transactionIndex == b.transactionIndex)\n            {\n                return a.transactionOutputIndex < b.transactionOutputIndex;\n            }\n            return a.transactionIndex < b.transactionIndex;\n        }\n        return a.blockNumber < b.blockNumber;\n    }\n};\n\n// Simplified view of the entire \"witness UTXO\" encapsulated as basic SimplifiedWitnessRouletteItem items instead of transactions\nclass SimplifiedWitnessUTXOSet\n{\npublic:\n    uint256 currentTipForSet;\n    //fixme: (OPTIMISE) - We make an educated guess that for our specific case 'flat_set' will perform well\n    //We base this on a few things:\n    // 1) Set size is not very large (around 600-1200 elements in size)\n    // 2) We have to iterate the entire set a lot for witness selection (for which contiguous memory is good)\n    // 3) We only perform at most a few inserts/deletions per block, so slightly slower insertion/deletion isn't necessarily that bad\n    //However we don't know this for a fact; therefore this should actually be tested against other alternatives and the most performant container for the job chosen.\n    boost::container::flat_set<SimplifiedWitnessRouletteItem> witnessCandidates;\n    \n    friend inline bool operator!=(const SimplifiedWitnessUTXOSet& a, const SimplifiedWitnessUTXOSet& b)\n    {\n        return !(a == b);\n    }\n    \n    friend inline bool operator==(const SimplifiedWitnessUTXOSet& a, const SimplifiedWitnessUTXOSet& b)\n    {\n        if (a.currentTipForSet != b.currentTipForSet)\n            return false;\n\n        if (a.witnessCandidates.size() != b.witnessCandidates.size())\n            return false;\n\n        for (uint64_t i=0; i<a.witnessCandidates.size(); ++i)\n        {\n            auto aComp = *a.witnessCandidates.nth(i);\n            auto bComp = *b.witnessCandidates.nth(i);\n            if (aComp != bComp)\n            {\n                return false;\n            }\n        }\n        return true;\n    }\n};\n\nSimplifiedWitnessUTXOSet GenerateSimplifiedWitnessUTXOSetFromUTXOSet(std::map<COutPoint, Coin> allWitnessCoinsIndexBased);\nbool GetSimplifiedWitnessUTXOSetForIndex(const CBlockIndex* pBlockIndex, SimplifiedWitnessUTXOSet& pow2SimplifiedWitnessUTXOForBlock);\nbool GetSimplifiedWitnessUTXODeltaForBlock(const CBlockIndex* pBlockIndexPrev, const CBlock& block, std::shared_ptr<SimplifiedWitnessUTXOSet> pow2SimplifiedWitnessUTXOForPrevBlock, std::vector<unsigned char>& compWitnessUTXODelta, CPubKey* pubkey);\n\n/** Global variable that points to the witness coins database (protected by cs_main) */\nextern CWitViewDB* ppow2witdbview;\nextern std::shared_ptr<CCoinsViewCache> ppow2witTip;\nextern SimplifiedWitnessUTXOSet pow2SimplifiedWitnessUTXO;\n\nstruct RouletteItem\n{\npublic:\n    RouletteItem(const COutPoint& outpoint_, const Coin& coin_, int64_t nWeight_, int64_t nAge_) : outpoint(outpoint_), coin(coin_), nWeight(nWeight_), nAge(nAge_), nCumulativeWeight(0) {};\n    COutPoint outpoint;\n    Coin coin;\n    uint64_t nWeight;\n    uint64_t nAge;\n    uint64_t nCumulativeWeight;\n\n    friend inline bool operator<(const RouletteItem& a, const RouletteItem& b)\n    {\n        if (a.nAge == b.nAge)\n            return a.outpoint < b.outpoint;\n        return a.nAge < b.nAge;\n    }\n    friend inline bool operator<(const RouletteItem& a, const uint64_t& b)\n    {\n        return a.nCumulativeWeight < b;\n    }\n};\n\nstruct CGetWitnessInfo\n{\n    //! All unspent witness coins on the network\n    std::map<COutPoint, Coin> allWitnessCoins;\n\n    //! All witness coins on the network that meet the basic criteria of minimum weight/amount\n    std::vector<RouletteItem> witnessSelectionPoolUnfiltered;\n\n    //! All witness coins on the network that were considered eligible for the purpose of selecting the winner. (All contenders)\n    std::vector<RouletteItem> witnessSelectionPoolFiltered;\n\n    //! Transaction output of the selected witness\n    CTxOut selectedWitnessTransaction;\n    \n    //! The index of the selected witness transaction in the filtered pool\n    uint64_t selectedWitnessIndex = 0;\n\n    //! Coin object containing the output of the selected witness\n    COutPoint selectedWitnessOutpoint;\n\n    //! Coin object containing the output of the selected witness\n    Coin selectedWitnessCoin;\n\n    uint64_t selectedWitnessBlockHeight = 0;\n\n    //! The total weight of all witness accounts\n    uint64_t nTotalWeightRaw = 0;\n\n    //! The total weight of all witness accounts considered eligible for this round of witnessing\n    uint64_t nTotalWeightEligibleRaw = 0;\n\n    //! The reduced total weight after applying the individual weight maximum\n    uint64_t nTotalWeightEligibleAdjusted = 0;\n\n    //! The maximum individual weight that any single address was allowed when performing the reduction.\n    uint64_t nMaxIndividualWeight = 0;\n};\n\nint GetPoW2WitnessCoinbaseIndex(const CBlock& block);\n\n// Returns all competing orphans at same height and same parent as current tip.\n// NB! It is important that we consider height and not chain weight here.\n// If there is a stalled chain due to absentee signer(s) delta may drop the difficulty so competing PoW blocks will have a lower chain weight, but we still want to sign them to get the chain moving again.\nstd::vector<CBlockIndex*> GetTopLevelPoWOrphans(const int64_t nHeight, const uint256& prevhash);\n\nstd::vector<CBlockIndex*> GetTopLevelWitnessOrphans(const int64_t nHeight);\n\n// Retrieve the witness for a PoW block (phase 3 only)\nCBlockIndex* GetWitnessOrphanForBlock(const int64_t nHeight, const uint256& prevHash, const uint256& powHash);\n\nbool ForceActivateChain(CBlockIndex* pActivateIndex, std::shared_ptr<const CBlock> pblock, CValidationState& state, const CChainParams& chainparams, CChain& currentChain, CCoinsViewCache& coinView);\n\nbool ForceActivateChainWithBlockAsTip(CBlockIndex* pActivateIndex, std::shared_ptr<const CBlock> pblock, CValidationState& state, const CChainParams& chainparams, CChain& currentChain, CCoinsViewCache& coinView, CBlockIndex* pnewblockastip);\n\n// The period in which we are required to witness before we are forcefully removed from the pool.\nuint64_t expectedWitnessBlockPeriod(uint64_t nWeight, uint64_t networkTotalWeight);\n\n// The average frequency which we are expected to witness in.\nuint64_t estimatedWitnessBlockPeriod(uint64_t nWeight, uint64_t networkTotalWeight);\n\nbool getAllUnspentWitnessCoins(CChain& chain, const CChainParams& chainParams, const CBlockIndex* pPreviousIndexChain, std::map<COutPoint, Coin>& allWitnessCoins, CBlock* newBlock=nullptr, CCoinsViewCache* viewOverride=nullptr, bool forceIndexBased=false);\n\nbool GetWitnessHelper(uint256 blockHash, CGetWitnessInfo& witnessInfo, uint64_t nBlockHeight);\n\nbool GetWitnessInfo(CChain& chain, const CChainParams& chainParams, CCoinsViewCache* viewOverride, CBlockIndex* pPreviousIndexChain, CBlock block, CGetWitnessInfo& witnessInfo, uint64_t nBlockHeight);\n\nbool GetWitness(CChain& chain, const CChainParams& chainParams, CCoinsViewCache* viewOverride, CBlockIndex* pPreviousIndexChain, CBlock block, CGetWitnessInfo& witnessInfo);\nbool GetWitnessFromSimplifiedUTXO(SimplifiedWitnessUTXOSet simplifiedWitnessUTXO, const CBlockIndex* pBlockIndex, CGetWitnessInfo& witnessInfo);\n\nbool witnessHasExpired(uint64_t nWitnessAge, uint64_t nWitnessWeight, uint64_t nNetworkTotalWitnessWeight);\n\n#endif\n"
  },
  {
    "path": "src/version.h",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef VERSION_H\n#define VERSION_H\n\n/**\n * network protocol versioning\n */\n\nstatic const int PROTOCOL_VERSION = 70020;\n\n//! In this version, 'witness sync' was introduced.\nstatic const int WITNESS_SYNC_VERSION = 70020;\n\n//! initial proto version, to be increased after version/verack negotiation\nstatic const int INIT_PROTO_VERSION = 209;\n\n//! In this version, 'getheaders' was introduced.\nstatic const int GETHEADERS_VERSION = 31800;\n\n//! disconnect from peers older than this proto version\nstatic const int MIN_PEER_PROTO_VERSION = 70020;\n\n//! nTime field added to CAddress, starting with this version;\n//! if possible, avoid requesting addresses nodes older than this\nstatic const int CADDR_TIME_VERSION = 31402;\n\n//! BIP 0031, pong message, is enabled for all versions AFTER this one\nstatic const int BIP0031_VERSION = 60000;\n\n//! \"filter*\" commands are disabled without NODE_BLOOM after and including this version\nstatic const int NO_BLOOM_VERSION = 70011;\n\n//! \"sendheaders\" command and announcing blocks with headers starts with this version\nstatic const int SENDHEADERS_VERSION = 70012;\n\n//! \"feefilter\" tells peers to filter invs to you by fee starts with this version\nstatic const int FEEFILTER_VERSION = 70013;\n\n//! short-id-based block download starts with this version\nstatic const int SHORT_IDS_BLOCKS_VERSION = 70014;\n\n//! not banning for invalid compact blocks starts with this version\nstatic const int INVALID_CB_NO_BAN_VERSION = 70015;\n\n//! Reverse headers for fast header synchronisation from last checkpoint\nstatic const int REVERSEHEADERS_VERSION = 70016;\n\n#endif\n"
  },
  {
    "path": "src/versionbits.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"versionbits.h\"\n#include \"consensus/params.h\"\n\n//Munt\n#include \"witnessutil.h\"\n#include \"validation/validation.h\"\n\nconst struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {\n    {\n        /*.name =*/ \"testdummy\",\n        /*.gbt_force =*/ true,\n    },\n    {\n        /*.name =*/ \"csv\",\n        /*.gbt_force =*/ true,\n    }\n};\n\n//NB! It is important that we use a hash here instead of a pointer - see comment in header file.\n#define PREVHASH (!pindexPrev?uint256():pindexPrev->GetBlockHeader().GetHashPoW2())\n\nThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const\n{\n    int nPeriod = Period(params);\n    int nThreshold = Threshold(params);\n    int64_t nTimeStart = BeginTime(params);\n    int64_t nTimeTimeout = EndTime(params);\n\n    // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.\n    if (pindexPrev != NULL) {\n        pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));\n    }\n\n    // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known\n    std::vector<const CBlockIndex*> vToCompute;\n    while (cache.count(PREVHASH) == 0) {\n        if (pindexPrev == NULL) {\n            // The genesis block is by definition defined.\n            cache[PREVHASH] = THRESHOLD_DEFINED;\n            break;\n        }\n        if (pindexPrev->GetMedianTimePast() < nTimeStart) {\n            // Optimization: don't recompute down further, as we know every earlier block will be before the start time\n            cache[PREVHASH] = THRESHOLD_DEFINED;\n            break;\n        }\n        vToCompute.push_back(pindexPrev);\n        pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);\n    }\n\n    // At this point, cache[pindexPrev] is known\n    assert(cache.count(PREVHASH));\n    ThresholdState state = cache[PREVHASH];\n\n    // Now walk forward and compute the state of descendants of pindexPrev\n    while (!vToCompute.empty()) {\n        ThresholdState stateNext = state;\n        pindexPrev = vToCompute.back();\n        vToCompute.pop_back();\n\n        switch (state) {\n            case THRESHOLD_DEFINED: {\n                if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {\n                    stateNext = THRESHOLD_FAILED;\n                } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) {\n                    stateNext = THRESHOLD_STARTED;\n                }\n                break;\n            }\n            case THRESHOLD_STARTED: {\n                if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {\n                    stateNext = THRESHOLD_FAILED;\n                    break;\n                }\n                // We need to count\n                const CBlockIndex* pindexCount = pindexPrev;\n                int count = 0;\n                for (int i = 0; i < nPeriod; i++) {\n                    if (Condition(pindexCount, params)) {\n                        count++;\n                    }\n                    pindexCount = pindexCount->pprev;\n                }\n                if (count >= nThreshold) {\n                    stateNext = THRESHOLD_LOCKED_IN;\n                }\n                break;\n            }\n            case THRESHOLD_LOCKED_IN: {\n                // Always progresses into ACTIVE.\n                stateNext = THRESHOLD_ACTIVE;\n                break;\n            }\n            case THRESHOLD_FAILED:\n            case THRESHOLD_ACTIVE: {\n                // Nothing happens, these are terminal states.\n                break;\n            }\n        }\n        cache[PREVHASH] = state = stateNext;\n    }\n\n    return state;\n}\n\n// return the numerical statistics of blocks signalling the specified BIP9 condition in this current period\nBIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const\n{\n    BIP9Stats stats;\n\n    stats.period = Period(params);\n    stats.threshold = Threshold(params);\n\n    if (pindex == NULL)\n        return stats;\n\n    // Find beginning of period\n    const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));\n    stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;\n\n    // Count from current block to beginning of period\n    int count = 0;\n    const CBlockIndex* currentIndex = pindex;\n    while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){\n        if (Condition(currentIndex, params))\n            count++;\n        currentIndex = currentIndex->pprev;\n    }\n\n    stats.count = count;\n    stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);\n\n    return stats;\n}\n\nint AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const\n{\n    const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);\n\n    // BIP 9 about state DEFINED: \"The genesis block is by definition in this state for each deployment.\"\n    if (initialState == THRESHOLD_DEFINED) {\n        return 0;\n    }\n\n    const int nPeriod = Period(params);\n\n    // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.\n    // To ease understanding of the following height calculation, it helps to remember that\n    // right now pindexPrev points to the block prior to the block that we are computing for, thus:\n    // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and\n    // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.\n    // The parent of the genesis block is represented by NULL.\n    pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));\n\n    const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);\n\n    while (previousPeriodParent != NULL && GetStateFor(previousPeriodParent, params, cache) == initialState) {\n        pindexPrev = previousPeriodParent;\n        previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);\n    }\n\n    // Adjust the result because right now we point to the parent block.\n    return pindexPrev->nHeight + 1;\n}\n\nnamespace\n{\n/**\n * Class to implement versionbits logic.\n */\nclass VersionBitsConditionChecker : public AbstractThresholdConditionChecker {\nprivate:\n    const Consensus::DeploymentPos id;\n\nprotected:\n    int64_t BeginTime(const Consensus::Params& params) const\n    {\n        return params.vDeployments[id].nStartTime;\n    }\n    int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; }\n    int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }\n    int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }\n\n    bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const\n    {\n        switch (params.vDeployments[id].type)\n        {\n            case Consensus::DEPLOYMENT_POW:\n                return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);\n            case Consensus::DEPLOYMENT_WITNESS:\n                return (((pindex->nVersionPoW2Witness & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersionPoW2Witness & Mask(params)) != 0);\n            case Consensus::DEPLOYMENT_BOTH:\n                return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0) && (((pindex->nVersionPoW2Witness & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersionPoW2Witness & Mask(params)) != 0);\n        }\n        return false;\n    }\n\npublic:\n    VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}\n    uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }\n};\n\n}\n\nThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)\n{\n    return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);\n}\n\nBIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)\n{\n    return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params);\n}\n\nint VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)\n{\n    return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);\n}\n\nuint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)\n{\n    return VersionBitsConditionChecker(pos).Mask(params);\n}\n\nvoid VersionBitsCache::Clear()\n{\n    for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {\n        cachespow[d].clear();\n        cacheswitness[d].clear();\n        cachescombined[d].clear();\n    }\n}\n"
  },
  {
    "path": "src/versionbits.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef BITCOIN_CONSENSUS_VERSIONBITS\n#define BITCOIN_CONSENSUS_VERSIONBITS\n\n#include \"chain.h\"\n#include <map>\n\n#include \"chainparams.h\"\n\n/** What block version to use for new blocks (pre versionbits) */\nstatic const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;\n/** What bits to set in version for versionbits blocks */\nstatic const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL;\n/** What bitmask determines whether versionbits is in use */\nstatic const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;\n/** Total bits available for versionbits */\nstatic const int32_t VERSIONBITS_NUM_BITS = 29;\n\nenum ThresholdState {\n    THRESHOLD_DEFINED,\n    THRESHOLD_STARTED,\n    THRESHOLD_LOCKED_IN,\n    THRESHOLD_ACTIVE,\n    THRESHOLD_FAILED,\n};\n\n// A map that gives the state for blocks whose height is a multiple of Period().\n// The map is indexed by the block's parent, however, so all keys in the map\n// will either be NULL or a block with (height + 1) % Period() == 0.\n//NB! It is important that we cache on -hash- and not pointers here, as it is possible for the same identical block to have two pointers.\n//This can happen (amongst other times) due to the use of CCloneChains in PoW2 computation.\n//In which case it pollutes the cache with multiple entries per block (indeterministically) - using a hash instead prevents this.\ntypedef std::map<const uint256, ThresholdState> ThresholdConditionCache;\n\nstruct VBDeploymentInfo {\n    /** Deployment name */\n    const char *name;\n    /** Whether GBT clients can safely ignore this rule in simplified usage */\n    bool gbt_force;\n};\n\nstruct BIP9Stats {\n    int period;\n    int threshold;\n    int elapsed;\n    int count;\n    bool possible;\n};\n\nextern const struct VBDeploymentInfo VersionBitsDeploymentInfo[];\n\n/**\n * Abstract class that implements BIP9-style threshold logic, and caches results.\n */\nclass AbstractThresholdConditionChecker {\nprotected:\n    virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0;\n    virtual int64_t BeginTime(const Consensus::Params& params) const =0;\n    virtual int64_t EndTime(const Consensus::Params& params) const =0;\n    virtual int Period(const Consensus::Params& params) const =0;\n    virtual int Threshold(const Consensus::Params& params) const =0;\n\npublic:\n    BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const;\n    // Note that the functions below take a pindexPrev as input: they compute information for block B based on its parent.\n    ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;\n    int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;\n};\n\nstruct VersionBitsCache\n{\n    // A little bit of 'nasty' trickery to make this a drop in replacement for the single cache Munt code.\n    VersionBitsCache() : caches(*this) {};\n    VersionBitsCache& caches;\n    ThresholdConditionCache& operator [](int idx)\n    {\n        //fixme: (FUT) (LOW) (params should be passed in)\n        switch (Params().GetConsensus().vDeployments[idx].type)\n        {\n            case Consensus::DEPLOYMENT_POW:\n                return cachespow[idx];\n            case Consensus::DEPLOYMENT_WITNESS:\n                return cacheswitness[idx];\n            case Consensus::DEPLOYMENT_BOTH:\n                return cachescombined[idx];\n            default:\n                assert(0);\n        }\n    }\n\n    ThresholdConditionCache cachespow[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];\n    ThresholdConditionCache cacheswitness[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];\n    ThresholdConditionCache cachescombined[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];\n\n    void Clear();\n};\n\nThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);\nBIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);\nint VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);\nuint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);\n\n#endif\n"
  },
  {
    "path": "src/wallet/account.cpp",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"account.h\"\n#include \"wallet/wallet.h\"\n#include <wallet/mnemonic.h>\n#include \"base58.h\"\n#include \"wallet/walletdb.h\"\n#include \"wallet/crypter.h\"\n\n#include <map>\n\n#define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX\n#include <boost/uuid/random_generator.hpp>\n#include <boost/uuid/nil_generator.hpp>\n\nstd::string GetAccountStateString(AccountState state)\n{\n    switch(state)\n    {\n        case Normal:\n            return \"Normal\";\n        case Shadow:\n            return \"Shadow\";\n        case ShadowChild:\n            return \"ShadowChild\";\n        case Deleted:\n            return \"Deleted\";\n    }\n    return \"\";\n}\n\nstd::string getUUIDAsString(const boost::uuids::uuid& uuid)\n{\n    return boost::uuids::to_string(uuid);\n}\n\nboost::uuids::uuid getUUIDFromString(const std::string& uuid)\n{\n    try\n    {\n        boost::uuids::string_generator generator;\n        return generator(uuid);\n    }\n    catch(...)\n    {\n        return boost::uuids::nil_generator()();\n    }\n}\n\nstd::string GetAccountTypeString(AccountType type)\n{\n    switch(type)\n    {\n        case Desktop:\n            return \"Desktop\";\n        case Mobi:\n            return \"Mobile\";\n        case PoW2Witness:\n            return \"Witness\";\n        case WitnessOnlyWitnessAccount:\n            return \"Witness-only witness\";\n        case ImportedPrivateKeyAccount:\n            return \"Imported private key\";\n        case MiningAccount:\n            return \"Mining\";\n    }\n    return \"Regular\";\n}\n\nCAccount* CreateAccountHelper(CWallet* pwallet, std::string accountName, std::string accountType, bool bMakeActive)\n{\n    CAccount* account = nullptr;\n\n    if (pwallet->IsLocked())\n        return nullptr;\n\n    if (accountType == \"HD\")\n    {\n        account = pwallet->GenerateNewAccount(accountName, AccountState::Normal, AccountType::Desktop, bMakeActive);\n    }\n    else if (accountType == \"Mobile\")\n    {\n        account = pwallet->GenerateNewAccount(accountName.c_str(), AccountState::Normal, AccountType::Mobi, bMakeActive);\n    }\n    else if (accountType == \"Witness\")\n    {\n        account = pwallet->GenerateNewAccount(accountName.c_str(), AccountState::Normal, AccountType::PoW2Witness, bMakeActive);\n    }\n    else if (accountType == \"Mining\")\n    {\n        account = pwallet->GenerateNewAccount(accountName.c_str(), AccountState::Normal, AccountType::MiningAccount, bMakeActive);\n    }\n    else if (accountType == \"Legacy\")\n    {\n        account = pwallet->GenerateNewLegacyAccount(accountName.c_str());\n    }\n\n    return account;\n}\n\n\nCHDSeed::CHDSeed()\n: m_type(BIP44)\n, m_UUID(boost::uuids::nil_generator()())\n{\n}\n\nCHDSeed::CHDSeed(SecureString mnemonic, SeedType type)\n: m_type(type)\n, m_UUID(boost::uuids::nil_generator()())\n{\n    //fixme: (FUT) (ACCOUNTS) Encrypt the seeds immediately upon creation so that they are never written to disk unencrypted.\n    unencryptedMnemonic = mnemonic;\n    Init();\n}\n\nCHDSeed::CHDSeed(CExtPubKey& pubkey, SeedType type)\n: m_type(type)\n, m_UUID(boost::uuids::nil_generator()())\n, m_readOnly(true)\n{\n    unencryptedMnemonic = \"\";\n    masterKeyPub = pubkey;\n\n    //Random key - not actually used, but written to disk to avoid unnecessary complexity in serialisation code\n    masterKeyPriv.GetMutableKey().MakeNewKey(true);\n    assert(masterKeyPriv.key.IsValid());\n    cointypeKeyPriv.GetMutableKey().MakeNewKey(true);\n    purposeKeyPriv.GetMutableKey().MakeNewKey(true);\n\n    InitReadOnly();\n}\n\nvoid CHDSeed::Init()\n{\n    unsigned char* seed = seedFromMnemonic(unencryptedMnemonic);\n    static const std::vector<unsigned char> hashkey = {'G','u','l','d','e','n',' ','b','i','p','3','2'};\n    static const std::vector<unsigned char> hashkeylegacy = {'B','i','t','c','o','i','n',' ','s','e','e','d'};\n\n    // Legacy support for old iOS and android wallets.\n    if (m_type == BIP32Legacy || m_type == BIP44External)\n    {\n        masterKeyPriv.SetMaster(hashkeylegacy, seed, 64);\n    }\n    else\n    {\n        masterKeyPriv.SetMaster(hashkey, seed, 64);\n    }\n\n\n    switch (m_type)\n    {\n        case BIP32:\n        case BIP32Legacy:\n            masterKeyPriv.Derive(purposeKeyPriv, 100 | BIP32_HARDENED_KEY_LIMIT);  //Unused - but we generate anyway so that we don't save predictable/blank encrypted data to disk (tiny security precaution)\n            purposeKeyPriv.Derive(cointypeKeyPriv, 100 | BIP32_HARDENED_KEY_LIMIT);  //Unused - but we generate anyway so that we don't save predictable/blank encrypted data to disk (tiny security precaution)\n            break;\n        case BIP44External:\n        case BIP44:\n            {\n                masterKeyPriv.Derive(purposeKeyPriv, 44 | BIP32_HARDENED_KEY_LIMIT);  //m/44'\n                purposeKeyPriv.Derive(cointypeKeyPriv, 87 | BIP32_HARDENED_KEY_LIMIT);  //m/44'/87'\n            }\n            break;\n        case BIP44NoHardening:\n            {\n                masterKeyPriv.Derive(purposeKeyPriv, 44);  //m/44\n                purposeKeyPriv.Derive(cointypeKeyPriv, 87);  //m/44/87\n            }\n            break;\n        default:\n            assert(0);\n    }\n    masterKeyPub = masterKeyPriv.Neuter();\n    purposeKeyPub = purposeKeyPriv.Neuter();\n    cointypeKeyPub = cointypeKeyPriv.Neuter();\n\n    if(m_UUID.is_nil())\n    {\n        m_UUID = boost::uuids::random_generator()();\n    }\n}\n\nvoid CHDSeed::InitReadOnly()\n{\n    assert(m_type == BIP44NoHardening);\n    masterKeyPub.Derive(purposeKeyPub, 44);  //m/44\n    purposeKeyPub.Derive(cointypeKeyPub, 87);  //m/44/87\n\n    if(m_UUID.is_nil())\n    {\n        m_UUID = boost::uuids::random_generator()();\n    }\n}\n\n\nCAccountHD* CHDSeed::GenerateAccount(AccountType type, CWalletDB* Db)\n{\n    CAccountHD* account = nullptr;\n    switch (type)\n    {\n        case Desktop:\n            assert(m_nAccountIndex < HDMobileStartIndex);\n            account = GenerateAccount(m_nAccountIndex, type);\n            if (!account)\n                return nullptr;\n            ++m_nAccountIndex;\n            break;\n        case Mobi:\n            assert(m_nAccountIndexMobi < HDWitnessStartIndex);\n            account = GenerateAccount(m_nAccountIndexMobi, type);\n            if (!account)\n                return nullptr;\n            ++m_nAccountIndexMobi;\n            break;\n        case PoW2Witness:\n            assert(m_nAccountIndexWitness < HDMiningStartIndex);\n            account = GenerateAccount(m_nAccountIndexWitness, type);\n            if (!account)\n                return nullptr;\n            ++m_nAccountIndexWitness;\n            break;\n        case MiningAccount:\n            assert(m_nAccountIndexMining < HDFutureReservedStartIndex);\n            account = GenerateAccount(m_nAccountIndexMining, type);\n            if (!account)\n                return nullptr;\n            ++m_nAccountIndexMining;\n            break;\n            \n        default:\n            ; // fall through on purpose with null account\n    }\n\n    if (Db)\n    {\n        //fixme: (FUT) (ACCOUNTS) Can we just set dirty or something and then it gets saved later? That would be cleaner than doing this here.\n        Db->WriteHDSeed(*this);\n    }\n\n    if (IsCrypted())\n    {\n        account->Encrypt(vMasterKey);\n    }\n    return account;\n}\n\nCAccountHD* CHDSeed::GenerateAccount(int nAccountIndex, AccountType type)\n{\n    if ( IsReadOnly() )\n    {\n        //fixme: (FUT) (ACCOUNTS) (LOW) We should be able to combine this with IsLocked() (BIP44NoHardening) case below to simplify the code here.\n        CExtPubKey accountKeyPub;\n        cointypeKeyPub.Derive(accountKeyPub, nAccountIndex);  // m/44/87/n (BIP44)\n        return new CAccountHD(accountKeyPub, m_UUID, type);\n    }\n    else if (IsLocked())\n    {\n        return nullptr;\n    }\n    else\n    {\n        CExtKey accountKeyPriv;\n        GetPrivKeyForAccountInternal(nAccountIndex, accountKeyPriv);\n        return new CAccountHD(accountKeyPriv, m_UUID, type);\n    }\n}\n\nbool CHDSeed::GetPrivKeyForAccount(uint64_t nAccountIndex, CExtKey& accountKeyPriv)\n{\n    if (IsReadOnly() || IsLocked())\n        return false;\n\n    GetPrivKeyForAccountInternal(nAccountIndex, accountKeyPriv);\n    return true;\n}\n\nbool CHDSeed::GetPrivKeyForAccountInternal(uint64_t nAccountIndex, CExtKey& accountKeyPriv)\n{\n    switch (m_type)\n    {\n        case BIP32:\n        case BIP32Legacy:\n            masterKeyPriv.Derive(accountKeyPriv, nAccountIndex | BIP32_HARDENED_KEY_LIMIT);  // m/n' (BIP32) \n            break;\n        case BIP44:\n        case BIP44External:\n            cointypeKeyPriv.Derive(accountKeyPriv, nAccountIndex | BIP32_HARDENED_KEY_LIMIT);  // m/44'/87'/n' (BIP44)\n            break;\n        case BIP44NoHardening:\n            cointypeKeyPriv.Derive(accountKeyPriv, nAccountIndex);  // m/44'/87'/n (BIP44 without hardening (for read only sync))\n            break;\n    }\n    return true;\n}\n\nboost::uuids::uuid CHDSeed::getUUID() const\n{\n    return m_UUID;\n}\n\n\nSecureString CHDSeed::getMnemonic()\n{\n    return unencryptedMnemonic;\n}\n\nSecureString CHDSeed::getPubkey()\n{\n    return CEncodedSecretKeyExt<CExtPubKey>(masterKeyPub).ToString().c_str();\n}\n\nbool CHDSeed::IsLocked() const\n{\n    if (unencryptedMnemonic.size() > 0 || m_readOnly)\n    {\n        return false;\n    }\n    return true;\n}\n\nbool CHDSeed::IsCrypted() const\n{\n    return encrypted;\n}\n\nbool CHDSeed::Lock()\n{\n    // We can't lock if we are not encrypted, nothing to do.\n    if (!encrypted)\n        return false;\n\n    // The below is a 'SecureString' - so no memory burn necessary, it should burn itself.\n    unencryptedMnemonic = \"\";\n    // The below is a 'SecureString' - so no memory burn necessary, it should burn itself.\n    masterKeyPriv = CExtKey();\n    purposeKeyPriv = CExtKey();\n    cointypeKeyPriv = CExtKey();\n\n    //fixme: (FUT) (ACCOUNTS) - Also burn the memory just to be sure?\n    vMasterKey.clear();\n\n    return true;\n}\n\nbool CHDSeed::Unlock(const CKeyingMaterial& vMasterKeyIn)\n{\n    // Decrypt mnemonic\n    assert(sizeof(m_UUID) == WALLET_CRYPTO_IV_SIZE);\n    CKeyingMaterial vchMnemonic;\n    if (!DecryptSecret(vMasterKeyIn, encryptedMnemonic, std::vector<unsigned char>(m_UUID.begin(), m_UUID.end()), vchMnemonic))\n        return false;\n    unencryptedMnemonic = SecureString(vchMnemonic.begin(), vchMnemonic.end());\n\n    // Decrypt master key\n    CKeyingMaterial vchMasterKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, masterKeyPrivEncrypted, masterKeyPub.pubkey.GetHash(), vchMasterKeyPrivEncoded))\n        return false;\n    masterKeyPriv.Decode(vchMasterKeyPrivEncoded.data());\n\n    // Decrypt purpose key\n    CKeyingMaterial vchPurposeKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, purposeKeyPrivEncrypted, purposeKeyPub.pubkey.GetHash(), vchPurposeKeyPrivEncoded))\n        return false;\n    purposeKeyPriv.Decode(vchPurposeKeyPrivEncoded.data());\n\n    // Decrypt coin type key\n    CKeyingMaterial vchCoinTypeKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, cointypeKeyPrivEncrypted, cointypeKeyPub.pubkey.GetHash(), vchCoinTypeKeyPrivEncoded))\n        return false;\n    cointypeKeyPriv.Decode(vchCoinTypeKeyPrivEncoded.data());\n\n    vMasterKey = vMasterKeyIn;\n\n    return true;\n}\n\nbool CHDSeed::Encrypt(const CKeyingMaterial& vMasterKeyIn)\n{\n    // Encrypt mnemonic\n    assert(sizeof(m_UUID) == WALLET_CRYPTO_IV_SIZE);\n    encryptedMnemonic.clear();\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(unencryptedMnemonic.begin(), unencryptedMnemonic.end()), std::vector<unsigned char>(m_UUID.begin(), m_UUID.end()), encryptedMnemonic))\n    {\n        LogPrintf(\"CHDSeed::Encrypt failed to encrypt mnemonic\");\n        return false;\n    }\n\n    // Encrypt master key\n    SecureUnsignedCharVector masterKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    masterKeyPriv.Encode(masterKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(masterKeyPrivEncoded.begin(), masterKeyPrivEncoded.end()), masterKeyPub.pubkey.GetHash(), masterKeyPrivEncrypted))\n    {\n        LogPrintf(\"CHDSeed::Encrypt failed to encrypt master key\");\n        return false;\n    }\n\n    // Encrypt purpose key\n    SecureUnsignedCharVector purposeKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    purposeKeyPriv.Encode(purposeKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(purposeKeyPrivEncoded.begin(), purposeKeyPrivEncoded.end()), purposeKeyPub.pubkey.GetHash(), purposeKeyPrivEncrypted))\n    {\n        LogPrintf(\"CHDSeed::Encrypt failed to encrypt purpose key\");\n        return false;\n    }\n\n    // Encrypt coin type key\n    SecureUnsignedCharVector cointypeKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    cointypeKeyPriv.Encode(cointypeKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(cointypeKeyPrivEncoded.begin(), cointypeKeyPrivEncoded.end()), cointypeKeyPub.pubkey.GetHash(), cointypeKeyPrivEncrypted))\n    {\n        LogPrintf(\"CHDSeed::Encrypt failed to encrypt coin type key\");\n        return false;\n    }\n\n    encrypted = true;\n    vMasterKey = vMasterKeyIn;\n\n    return true;\n}\n\n\n\nCAccountHD::CAccountHD(CExtKey accountKey_, boost::uuids::uuid seedID, AccountType type)\n: CAccount()\n, m_SeedID(seedID)\n, m_nIndex(accountKey_.nChild)\n, accountKeyPriv(accountKey_)\n{\n    m_Type = type;\n\n    accountKeyPriv.Derive(primaryChainKeyPriv, 0);  //a'/0\n    if (m_Type != AccountType::PoW2Witness) \n        accountKeyPriv.Derive(changeChainKeyPriv, 1);  //a'/1\n    else\n        accountKeyPriv.Derive(changeChainKeyPriv, 1 | BIP32_HARDENED_KEY_LIMIT);  //a'/1' - Witness account requires hardening at the change level for extra security (it will be quite common to share witness account change keys)\n    primaryChainKeyPub = primaryChainKeyPriv.Neuter();\n    changeChainKeyPub = changeChainKeyPriv.Neuter();\n}\n\nCAccountHD::CAccountHD(CExtPubKey accountKey_, boost::uuids::uuid seedID, AccountType type)\n: CAccount()\n, m_SeedID(seedID)\n, m_nIndex(accountKey_.nChild)\n{\n    m_Type = type;\n\n    //Random key - not actually used, but written to disk to avoid unnecessary complexity in serialisation code\n    accountKeyPriv.GetMutableKey().MakeNewKey(true);\n    primaryChainKeyPriv.GetMutableKey().MakeNewKey(true);\n    changeChainKeyPriv.GetMutableKey().MakeNewKey(true);\n\n    //NB! The change keys will be wrong here for read only witness accounts, but it doesn't matter because we only need to match one of the two keys to be able to tell it is ours.\n    accountKey_.Derive(primaryChainKeyPub, 0);  //a/0\n    accountKey_.Derive(changeChainKeyPub, 1);  //a/1\n    m_readOnly = true;\n}\n\nbool CAccountHD::GetAccountKeyIDWithHighestIndex(CKeyID& HDKeyID, int nChain) const\n{\n    if (nChain == KEYCHAIN_EXTERNAL)\n    {\n        return externalKeyStore.GetKeyIDWithHighestIndex(HDKeyID);\n    }\n    else\n    {\n        return internalKeyStore.GetKeyIDWithHighestIndex(HDKeyID);\n    }\n}\n\nbool CAccountHD::GetKey(CExtKey& childKey, int nChain) const\n{\n    assert(!m_readOnly);\n    assert(!IsLocked());\n    if (nChain == KEYCHAIN_EXTERNAL)\n    {\n        return primaryChainKeyPriv.Derive(childKey, m_nNextChildIndex++);\n    }\n    else\n    {\n        return changeChainKeyPriv.Derive(childKey, m_nNextChangeIndex++);\n    }\n}\n\nbool CAccountHD::GetKey(const CKeyID& keyID, CKey& key) const\n{\n    assert(!m_readOnly);\n    assert(IsHD());\n\n    // Witness keys are a special case.\n    // They are stored instead of generated on demand (so that they work in encrypted wallets)\n    if (IsPoW2Witness())\n    {\n        if (internalKeyStore.GetKey(keyID, key))\n        {\n            // But skip it if it is an empty key... (Which can happen by design)\n            // Technical: Witness keystore is filled with \"public/empty\" pairs as the public keys are created and then populated on demand with \"public/witness\" keys only when they are needed/generated (first use)\n            if (key.IsValid())\n                return true;\n        }\n    }\n\n    if (IsLocked())\n        return false;\n\n    int64_t nKeyIndex = -1;\n    CExtKey privKey;\n    if (externalKeyStore.GetKey(keyID, nKeyIndex))\n    {\n        primaryChainKeyPriv.Derive(privKey, nKeyIndex);\n        if(privKey.Neuter().pubkey.GetID() != keyID)\n            assert(0);\n        key = privKey.key;\n        return true;\n    }\n    if (internalKeyStore.GetKey(keyID, nKeyIndex))\n    {\n        changeChainKeyPriv.Derive(privKey, nKeyIndex);\n        if(privKey.Neuter().pubkey.GetID() != keyID)\n            assert(0);\n        key = privKey.key;\n        return true;\n    }\n    return false;\n}\n\nbool CAccountHD::GetKey([[maybe_unused]] const CKeyID &address, [[maybe_unused]] std::vector<unsigned char>& encryptedKeyOut) const\n{\n    assert(0); // asserts are always compiled in even in releae builds, should this ever change we fallback to the throw below\n    throw std::runtime_error(\"Should never call CAccountHD::GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut)\");\n}\n\nvoid CAccountHD::GetPubKey(CExtPubKey& childKey, int nChain) const\n{\n    if (nChain == KEYCHAIN_EXTERNAL)\n    {\n        primaryChainKeyPub.Derive(childKey, m_nNextChildIndex++);\n    }\n    else\n    {\n        changeChainKeyPub.Derive(childKey, m_nNextChangeIndex++);\n    }\n}\n\nbool CAccountHD::GetPubKeyManual(int64_t HDKeyIndex, int keyChain, CExtPubKey& childKey) const\n{\n    if (keyChain == KEYCHAIN_EXTERNAL)\n    {\n        primaryChainKeyPub.Derive(childKey, HDKeyIndex);\n        return true;\n    }\n    else\n    {\n        changeChainKeyPub.Derive(childKey, HDKeyIndex);\n        return true;\n    }\n    return false;\n}\n\nbool CAccountHD::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const\n{\n    int64_t nKeyIndex = -1;\n    if(externalKeyStore.GetKey(address, nKeyIndex))\n    {\n        CExtPubKey extPubKey;\n        primaryChainKeyPub.Derive(extPubKey, nKeyIndex);\n        vchPubKeyOut = extPubKey.pubkey;\n        return true;\n    }\n    if(internalKeyStore.GetKey(address, nKeyIndex))\n    {\n        CExtPubKey extPubKey;\n        changeChainKeyPub.Derive(extPubKey, nKeyIndex);\n        vchPubKeyOut = extPubKey.pubkey;\n        return true;\n    }\n    return false;\n}\n\nbool CAccountHD::Lock()\n{\n    // NB! We don't encrypt the keystores for HD accounts - as they only contain public keys.\n    // So we don't need to unlock the underlying keystore.\n    if (!IsReadOnly())\n    {\n        return true;\n    }\n\n    // We can't lock if we are not encrypted, nothing to do.\n    if (!encrypted)\n        return false;\n\n    // We don't encrypt the keystores for HD accounts - as they only contain public keys.\n    // The exception being witness accounts, which may contain (select) witness keys in their keystores.\n    // However these must -never- be encrypted anyway.\n    //CAccount::Lock()\n\n    //fixme: (FUT) (ACCOUNTS) - Also burn the memory just to be sure?\n    vMasterKey.clear();\n\n    //fixme: (FUT) (ACCOUNTS) burn the memory here.\n    accountKeyPriv = CExtKey();\n    primaryChainKeyPriv = CExtKey();\n    changeChainKeyPriv = CExtKey();\n\n    return true;\n}\n\nbool CAccountHD::Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk)\n{\n    needsWriteToDisk = false;\n    assert(sizeof(accountUUID) == WALLET_CRYPTO_IV_SIZE);\n\n    // NB! We don't encrypt the keystores for HD accounts - as they only contain public keys.\n    // So we don't need to unlock the underlying keystore.\n    if (IsReadOnly())\n        return true;\n\n    // Decrypt account key\n    CKeyingMaterial vchAccountKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, accountKeyPrivEncrypted, std::vector<unsigned char>(accountUUID.begin(), accountUUID.end()), vchAccountKeyPrivEncoded))\n    {\n        LogPrintf(\"CAccountHD::Unlock Failed to decrypt secret account key\");\n        return false;\n    }\n    accountKeyPriv.Decode(vchAccountKeyPrivEncoded.data());\n\n    // Decrypt primary chain key\n    CKeyingMaterial vchPrimaryChainKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, primaryChainKeyEncrypted, primaryChainKeyPub.pubkey.GetHash(), vchPrimaryChainKeyPrivEncoded))\n    {\n        LogPrintf(\"CAccountHD::Unlock Failed to decrypt secret primary chain key\");\n        return false;\n    }\n    primaryChainKeyPriv.Decode(vchPrimaryChainKeyPrivEncoded.data());\n\n    // Decrypt change chain key\n    CKeyingMaterial vchChangeChainKeyPrivEncoded;\n    if (!DecryptSecret(vMasterKeyIn, changeChainKeyEncrypted, changeChainKeyPub.pubkey.GetHash(), vchChangeChainKeyPrivEncoded))\n    {\n        LogPrintf(\"CAccountHD::Unlock Failed to decrypt secret change chanin key\");\n        return false;\n    }\n    changeChainKeyPriv.Decode(vchChangeChainKeyPrivEncoded.data());\n\n    vMasterKey = vMasterKeyIn;\n\n    return true;\n}\n\nbool CAccountHD::Encrypt(const CKeyingMaterial& vMasterKeyIn)\n{\n    assert(sizeof(accountUUID) == WALLET_CRYPTO_IV_SIZE);\n\n    if (IsReadOnly())\n    {\n        return true;\n    }\n\n    // NB! We don't encrypt the keystores for HD accounts - as they only contain public keys.\n\n    // Encrypt account key\n    SecureUnsignedCharVector accountKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    accountKeyPriv.Encode(accountKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(accountKeyPrivEncoded.begin(), accountKeyPrivEncoded.end()), std::vector<unsigned char>(accountUUID.begin(), accountUUID.end()), accountKeyPrivEncrypted))\n        return false;\n\n    // Encrypt primary chain key\n    SecureUnsignedCharVector primaryChainKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    primaryChainKeyPriv.Encode(primaryChainKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(primaryChainKeyPrivEncoded.begin(), primaryChainKeyPrivEncoded.end()), primaryChainKeyPub.pubkey.GetHash(), primaryChainKeyEncrypted))\n        return false;\n\n    // Encrypt change chain key\n    SecureUnsignedCharVector changeChainKeyPrivEncoded(BIP32_EXTKEY_SIZE);\n    changeChainKeyPriv.Encode(changeChainKeyPrivEncoded.data());\n    if (!EncryptSecret(vMasterKeyIn, CKeyingMaterial(changeChainKeyPrivEncoded.begin(), changeChainKeyPrivEncoded.end()), changeChainKeyPub.pubkey.GetHash(), changeChainKeyEncrypted))\n        return false;\n\n    encrypted = true;\n    vMasterKey = vMasterKeyIn;\n\n    return true;\n}\n\nbool CAccountHD::IsCrypted() const\n{\n    return encrypted;\n}\n\nbool CAccountHD::IsLocked() const\n{\n    return !accountKeyPriv.key.IsValid();\n}\n\nbool CAccountHD::AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int keyChain)\n{\n    // This should never be called on a HD account.\n    // We don't store private keys for HD we just generate them as needed.\n    // The exception being PoW² witnesses which may contain witness keys unencrypted (change chain keys)\n    assert(IsPoW2Witness());\n    assert(keyChain == KEYCHAIN_WITNESS);\n    return internalKeyStore.AddKeyPubKey(key, pubkey);\n}\n\nbool CAccountHD::AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, int keyChain)\n{\n    if(keyChain == KEYCHAIN_EXTERNAL)\n        return externalKeyStore.AddKeyPubKey(HDKeyIndex, pubkey);\n    else\n    {\n        // Add public key with null private key - we later write the private key IFF it is used in a witnessing operation\n        if (IsPoW2Witness())\n        {\n            CKey nullKey;\n            //fixme: (FUT) (ACCOUNTS) This is possibly a bit inefficient - see if it can be sped up.\n            if(!internalKeyStore.HaveKey(pubkey.GetID()))\n            {\n                if(!internalKeyStore.AddKeyPubKey(nullKey, pubkey))\n                {\n                    throw std::runtime_error(\"CAccountHD::AddKeyPubKey failed to store witness key.\");\n                }\n            }\n        }\n        return internalKeyStore.AddKeyPubKey(HDKeyIndex, pubkey);\n    }\n}\n\n\nCPubKey CAccountHD::GenerateNewKey(CWallet& wallet, CKeyMetadata& metadata, int keyChain)\n{\n    CExtPubKey childKey;\n    do\n    {\n        GetPubKey(childKey, keyChain);\n    }\n    while( wallet.HaveKey(childKey.pubkey.GetID()) );//fixme: (FUT) (ACCOUNTS) (BIP44) No longer need wallet here.\n\n    //LogPrintf(\"CAccount::GenerateNewKey(): NewHDKey [%s]\\n\", CNativeAddress(childKey.pubkey.GetID()).ToString());\n\n    metadata.hdKeypath = std::string(\"m/44'/87'/\") +  std::to_string(m_nIndex)  + \"/\" + std::to_string(keyChain) + \"/\" + std::to_string(childKey.nChild) + \"'\";\n    metadata.hdAccountUUID = getUUIDAsString(getUUID());\n\n    if (!wallet.AddHDKeyPubKey(childKey.nChild, childKey.pubkey, *this, keyChain))\n        throw std::runtime_error(\"CAccount::GenerateNewKey(): AddKeyPubKey failed\");\n\n    return childKey.pubkey;\n}\n\n\nCExtKey* CAccountHD::GetAccountMasterPrivKey()\n{\n    if (IsLocked())\n        return NULL;\n\n    return &accountKeyPriv;\n}\n\nSecureString CAccountHD::GetAccountMasterPubKeyEncoded()\n{\n    if (IsLocked())\n        return NULL;\n\n    return CEncodedSecretKeyExt<CExtPubKey>(accountKeyPriv.Neuter()).ToString().c_str();\n}\n\nboost::uuids::uuid CAccountHD::getSeedUUID() const\n{\n    return m_SeedID;\n}\n\nuint32_t CAccountHD::getIndex()\n{\n    return m_nIndex;\n}\n\nCAccount::CAccount()\n{\n    SetNull();\n    //Start at current time and go backwards as we find transactions.\n    earliestPossibleCreationTime = GetTime();\n    accountUUID = boost::uuids::random_generator()();\n    parentUUID = boost::uuids::nil_generator()();\n    m_State = AccountState::Normal;\n    m_Type = AccountType::Desktop;\n    m_readOnly = false;\n}\n\nvoid CAccount::SetNull()\n{\n    vchPubKey = CPubKey();\n}\n\nCPubKey CAccount::GenerateNewKey(CWallet& wallet, CKeyMetadata& metadata, int keyChain)\n{\n    if (IsFixedKeyPool())\n        throw std::runtime_error(strprintf(\"GenerateNewKey called on a \\\"%s\\\" witness account - this is invalid\", GetAccountTypeString(m_Type).c_str()));\n\n    CKey secret;\n    secret.MakeNewKey(true);\n\n    CPubKey pubkey = secret.GetPubKey();\n    assert(secret.VerifyPubKey(pubkey));\n\n    if (!wallet.AddKeyPubKey(secret, pubkey, *this, keyChain))\n        throw std::runtime_error(\"CAccount::GenerateNewKey(): AddKeyPubKey failed\");\n\n    return pubkey;\n}\n\n\n//fixme: (FUT) (ACCOUNTS) (WATCH_ONLY)\nbool CAccount::HaveWalletTx(const CTransaction& tx)\n{\n    for(const CTxOut& txout : tx.vout)\n    {\n        isminetype ret = isminetype::ISMINE_NO;\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            isminetype temp = ( keyChain == KEYCHAIN_EXTERNAL ? IsMine(externalKeyStore, txout) : IsMine(internalKeyStore, txout) );\n            if (temp > ret)\n                ret = temp;\n        }\n        if (ret > isminetype::ISMINE_NO)\n            return true;\n    }\n    for(const CTxIn& txin : tx.vin)\n    {\n        isminetype ret = isminetype::ISMINE_NO;\n        const CWalletTx* prev = pactiveWallet->GetWalletTx(txin.GetPrevOut());\n        if (prev && prev->tx->vout.size() != 0)\n        {\n            if (txin.GetPrevOut().n < prev->tx->vout.size())\n            {\n                for(const CTxOut& txout : prev->tx->vout)\n                {\n                    for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n                    {\n                        isminetype temp = ( keyChain == KEYCHAIN_EXTERNAL ? IsMine(externalKeyStore, txout) : IsMine(internalKeyStore, txout) );\n                        if (temp > ret)\n                            ret = temp;\n                    }\n                }\n            }\n        }\n        if (ret > isminetype::ISMINE_NO)\n            return true;\n    }\n    return false;\n}\n\n\nbool CAccount::HaveKey(const CKeyID &address) const\n{\n    return externalKeyStore.HaveKey(address) || internalKeyStore.HaveKey(address);\n}\n\nbool CAccount::HaveKeyInternal(const CKeyID &address) const\n{\n    return internalKeyStore.HaveKey(address);\n}\n\nbool CAccount::HaveWatchOnly(const CScript &dest) const\n{\n    return externalKeyStore.HaveWatchOnly(dest) || internalKeyStore.HaveWatchOnly(dest);\n}\n\nbool CAccount::HaveWatchOnly() const\n{\n    return externalKeyStore.HaveWatchOnly() || internalKeyStore.HaveWatchOnly();\n}\n\nbool CAccount::HaveCScript(const CScriptID &hash) const\n{\n    return externalKeyStore.HaveCScript(hash) || internalKeyStore.HaveCScript(hash);\n}\n\nbool CAccount::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const\n{\n    return externalKeyStore.GetCScript(hash, redeemScriptOut) || internalKeyStore.GetCScript(hash, redeemScriptOut);\n}\n\nbool CAccount::IsLocked() const\n{\n    return externalKeyStore.IsLocked() || internalKeyStore.IsLocked();\n}\n\nbool CAccount::IsCrypted() const\n{\n    return externalKeyStore.IsCrypted() || internalKeyStore.IsCrypted();\n}\n\nbool CAccount::Lock()\n{\n    // NB! We don't encrypt the keystores for witness-only accounts - as they only contain keys for witnessing.\n    // So we don't need to unlock the underlying keystore..\n    if (IsWitnessOnly())\n    {\n        return true;\n    }\n\n    //fixme: (FUT) (ACCOUNTS) - Also burn the memory just to be sure?\n    vMasterKey.clear();\n\n    return externalKeyStore.Lock() && internalKeyStore.Lock();\n}\n\nbool CAccount::Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk)\n{\n    // NB! We don't encrypt the keystores for witness-only accounts - as they only contain keys for witnessing.\n    // So we don't need to unlock the underlying keystore..\n    if (IsWitnessOnly())\n    {\n        return true;\n    }\n\n    needsWriteToDisk = false;\n    vMasterKey = vMasterKeyIn;\n\n    return externalKeyStore.Unlock(vMasterKeyIn, needsWriteToDisk) && internalKeyStore.Unlock(vMasterKeyIn, needsWriteToDisk);\n}\n\nbool CAccount::GetKey(const CKeyID& keyID, CKey& key) const\n{\n    return externalKeyStore.GetKey(keyID, key) || internalKeyStore.GetKey(keyID, key);\n}\n\nbool CAccount::GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut) const\n{\n    return externalKeyStore.GetKey(address, encryptedKeyOut) || internalKeyStore.GetKey(address, encryptedKeyOut);\n}\n\nvoid CAccount::GetKeys(std::set<CKeyID> &setAddress) const\n{\n    std::set<CKeyID> setExternal;\n    externalKeyStore.GetKeys(setExternal);\n    std::set<CKeyID> setInternal;\n    internalKeyStore.GetKeys(setInternal);\n    setAddress.clear();\n    setAddress.insert(setExternal.begin(), setExternal.end());\n    setAddress.insert(setInternal.begin(), setInternal.end());\n}\n\nvoid CAccount::GetKeys(std::set<CKeyID> &setKeysExternal, std::set<CKeyID> &setKeysInternal) const\n{\n    externalKeyStore.GetKeys(setKeysExternal);\n    internalKeyStore.GetKeys(setKeysInternal);\n}\n\nbool CAccount::EncryptKeys(const CKeyingMaterial& vMasterKeyIn)\n{\n    if (!externalKeyStore.EncryptKeys(vMasterKeyIn))\n        return false;\n    if (!internalKeyStore.EncryptKeys(vMasterKeyIn))\n        return false;\n\n    if (pactiveWallet)\n    {\n        {\n            std::set<CKeyID> setAddress;\n            GetKeys(setAddress);\n\n            LOCK(pactiveWallet->cs_wallet);\n            for (const auto& keyID : setAddress)\n            {\n                CPubKey pubKey;\n                if (!GetPubKey(keyID, pubKey))\n                {\n                    LogPrintf(\"CAccount::EncryptKeys(): Failed to get pubkey\\n\");\n                    return false;\n                }\n                if (pactiveWallet->pwalletdbEncryption)\n                    pactiveWallet->pwalletdbEncryption->EraseKey(pubKey);\n                else\n                    CWalletDB(*pactiveWallet->dbw).EraseKey(pubKey);\n\n                std::vector<unsigned char> secret;\n                if (!GetKey(keyID, secret))\n                { \n                    LogPrintf(\"CAccount::EncryptKeys(): Failed to get crypted key\\n\");\n                    return false;\n                }\n                if (pactiveWallet->pwalletdbEncryption)\n                {\n                    if (!pactiveWallet->pwalletdbEncryption->WriteCryptedKey(pubKey, secret, pactiveWallet->mapKeyMetadata[keyID], getUUIDAsString(getUUID()), KEYCHAIN_EXTERNAL))\n                    {\n                        LogPrintf(\"CAccount::EncryptKeys(): Failed to write key\\n\");\n                        return false;\n                    }\n                }\n                else\n                {\n                    if (!CWalletDB(*pactiveWallet->dbw).WriteCryptedKey(pubKey, secret, pactiveWallet->mapKeyMetadata[keyID], getUUIDAsString(getUUID()), KEYCHAIN_EXTERNAL))\n                    {\n                        LogPrintf(\"CAccount::EncryptKeys(): Failed to write key\\n\");\n                        return false;\n                    }\n                }\n            }\n        }\n    }\n    return true;\n}\n\nbool CAccount::Encrypt(const CKeyingMaterial& vMasterKeyIn)\n{\n    // NB! We don't encrypt the keystores for witness-only accounts - as they only contain keys for witnessing.\n    // So we don't need to unlock the underlying keystore..\n    if (IsWitnessOnly())\n    {\n        return true;\n    }\n\n    bool needsWriteToDisk;\n    if (!EncryptKeys(vMasterKeyIn))\n        return false;\n    if (!externalKeyStore.SetCrypted() || !externalKeyStore.Unlock(vMasterKeyIn, needsWriteToDisk))\n        return false;\n    if (!internalKeyStore.SetCrypted() || !internalKeyStore.Unlock(vMasterKeyIn, needsWriteToDisk))\n        return false;\n\n    vMasterKey = vMasterKeyIn;\n\n    return true;\n}\n\n\n\nbool CAccount::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const\n{\n    return externalKeyStore.GetPubKey(address, vchPubKeyOut) || internalKeyStore.GetPubKey(address, vchPubKeyOut);\n}\n\n\nbool CAccount::AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int keyChain)\n{\n    if(keyChain == KEYCHAIN_EXTERNAL)\n    {\n        return externalKeyStore.AddKeyPubKey(key, pubkey);\n    }\n    else\n    {\n        return internalKeyStore.AddKeyPubKey(key, pubkey);\n    }\n}\n\nbool CAccount::AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, int keyChain)\n{\n    //This should never be called on a non-HD wallet\n    assert(0);\n    return true;\n}\n\nbool CAccount::AddWatchOnly(const CScript &dest)\n{\n    //fixme: (FUT) (ACCOUNTS) (WATCH_ONLY) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n    assert(0);\n    return externalKeyStore.AddWatchOnly(dest);\n}\n\nbool CAccount::RemoveWatchOnly(const CScript &dest)\n{\n    //fixme: (FUT) (ACCOUNTS) (WATCH_ONLY) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n    assert(0);\n    return externalKeyStore.RemoveWatchOnly(dest) || internalKeyStore.RemoveWatchOnly(dest);\n}\n\n//checkme: CHILD ACCOUNTS - DOES THIS END UP IN THE RIGHT PLACE?\n//fixme: (FUT) (ACCOUNTS)\nbool CAccount::AddCScript(const CScript& redeemScript)\n{\n    return externalKeyStore.AddCScript(redeemScript);\n}\n\nbool CAccount::AddCryptedKeyWithChain(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, int64_t nKeyChain)\n{\n    //fixme: (FUT) (ACCOUNTS) This is essentially dead code now - it has been replaced at the bottom of CWallet::AddKeyPubKey\n    //For technical reasons (wallet upgrade)\n\n    //This should never be called on a non-HD wallet\n    assert(!IsHD());\n\n    if (nKeyChain == KEYCHAIN_EXTERNAL)\n    {\n        if (!externalKeyStore.AddCryptedKey(vchPubKey, vchCryptedSecret))\n            return false;\n    }\n    else\n    {\n        if (!internalKeyStore.AddCryptedKey(vchPubKey, vchCryptedSecret))\n            return false;\n    }\n\n    // If we don't have a wallet yet (busy during wallet upgrade) - then the below not being called is fine as the wallet does a 'force resave' of all keys at the end of the upgrade.\n    if (pactiveWallet)\n    {\n        {\n            LOCK(pactiveWallet->cs_wallet);\n            if (pactiveWallet->pwalletdbEncryption)\n                return pactiveWallet->pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, pactiveWallet->mapKeyMetadata[vchPubKey.GetID()], getUUIDAsString(getUUID()), nKeyChain);\n            else\n                return CWalletDB(*pactiveWallet->dbw).WriteCryptedKey(vchPubKey, vchCryptedSecret, pactiveWallet->mapKeyMetadata[vchPubKey.GetID()], getUUIDAsString(getUUID()), nKeyChain);\n        }\n    }\n    else\n    {\n        return true;\n    }\n    return false;\n}\n\nvoid CAccount::AddChild(CAccount* childAccount)\n{\n    childAccount->parentUUID = accountUUID;\n}\n\nvoid CAccount::possiblyUpdateEarliestTime(uint64_t creationTime, CWalletDB* Db)\n{\n    if (creationTime < earliestPossibleCreationTime)\n        earliestPossibleCreationTime = creationTime;\n\n    //fixme: (FUT) (ACCOUNTS) Can we just set dirty or something and then it gets saved later? This would be cleaner instead of taking the Db here and writing directly to it...\n    if (Db)\n    {\n        Db->WriteAccount(getUUIDAsString(getUUID()), this);\n    }\n}\n\nuint64_t CAccount::getEarliestPossibleCreationTime()\n{\n    return earliestPossibleCreationTime;\n}\n\nunsigned int CAccount::GetKeyPoolSize()\n{\n    AssertLockHeld(cs_keypool); // setKeyPool\n    return setKeyPoolExternal.size();\n}\n\nunsigned int CAccount::GetKeyPoolSize(int nChain)\n{\n    AssertLockHeld(cs_keypool); // setKeyPool\n    if (nChain == KEYCHAIN_EXTERNAL)\n    {\n        return setKeyPoolExternal.size();\n    }\n    else\n    {\n        return setKeyPoolInternal.size();\n    }\n}\n\nstd::string CAccount::getLabel() const\n{\n    return accountLabel;\n}\n\nvoid CAccount::setLabel(const std::string& label, CWalletDB* Db)\n{\n    accountLabel = label;\n    if (Db)\n    {\n        Db->EraseAccountLabel(getUUIDAsString(getUUID()));\n        Db->WriteAccountLabel(getUUIDAsString(getUUID()), label);\n    }\n}\n\nvoid CAccount::addLink(const std::string& serviceName, const std::string& serviceData, CWalletDB* Db)\n{\n    accountLinks[serviceName] = serviceData;\n    if (accountLinks.count(serviceName) == 0)\n    {\n        if (Db)\n        {\n            Db->EraseAccountLinks(getUUIDAsString(getUUID()));\n            Db->WriteAccountLinks(getUUIDAsString(getUUID()), accountLinks);\n            if (pactiveWallet)\n            {\n                dynamic_cast<CExtWallet*>(pactiveWallet)->NotifyAccountModified(pactiveWallet, this);\n            }\n        }   \n    }\n}\n\nvoid CAccount::removeLink(const std::string& serviceName, CWalletDB* Db)\n{\n    if (accountLinks.find(serviceName) != accountLinks.end())\n    {\n        accountLinks.erase(accountLinks.find(serviceName));\n        if (Db)\n        {\n            Db->EraseAccountLinks(getUUIDAsString(getUUID()));\n            Db->WriteAccountLinks(getUUIDAsString(getUUID()), accountLinks);\n            if (pactiveWallet)\n            {\n                dynamic_cast<CExtWallet*>(pactiveWallet)->NotifyAccountModified(pactiveWallet, this);\n            }\n        }\n    }\n}\n\nstd::map<std::string, std::string> CAccount::getLinks() const\n{\n    return accountLinks;\n}\n\nvoid CAccount::loadLinks(std::map<std::string, std::string>& accountLinks_)\n{\n    accountLinks = accountLinks_;\n}\n\nCAmount CAccount::getCompounding() const\n{\n    // If compound earnings percent is set in any way then it overrides this, in which case we always set 0.\n    if (compoundEarningsPercent == std::numeric_limits<int32_t>::max())\n    {\n        return compoundEarnings;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nvoid CAccount::setCompounding(CAmount compoundAmount_, CWalletDB* Db)\n{\n    if (pactiveWallet)\n    {\n        dynamic_cast<CExtWallet*>(pactiveWallet)->NotifyAccountCompoundingChanged(pactiveWallet, this);\n    }\n    compoundEarnings = compoundAmount_;\n    if (Db)\n    {\n        Db->EraseAccountCompoundingSettings(getUUIDAsString(getUUID()));\n        if (compoundEarnings > 0)\n        {\n            Db->WriteAccountCompoundingSettings(getUUIDAsString(getUUID()), compoundEarnings);\n        }\n    }\n}\n\n\nint32_t CAccount::getCompoundingPercent() const\n{\n    if (compoundEarningsPercent == std::numeric_limits<int32_t>::max())\n        return 0;\n    return compoundEarningsPercent;\n}\n\nvoid CAccount::setCompoundingPercent(int32_t compoundPercent_, CWalletDB* Db)\n{\n    if (pactiveWallet)\n    {\n        dynamic_cast<CExtWallet*>(pactiveWallet)->NotifyAccountCompoundingChanged(pactiveWallet, this);\n    }\n    compoundEarningsPercent = compoundPercent_;\n    if (Db)\n    {\n        Db->EraseAccountCompoundingSettings(getUUIDAsString(getUUID()));\n        Db->EraseAccountCompoundingPercentSettings(getUUIDAsString(getUUID()));\n        Db->WriteAccountCompoundingPercentSettings(getUUIDAsString(getUUID()), compoundEarningsPercent);\n    }\n}\n\nbool CAccount::hasNonCompoundRewardScript() const\n{\n    return !nonCompoundRewardScript.empty();\n}\n\nCScript CAccount::getNonCompoundRewardScript() const\n{\n    return nonCompoundRewardScript;\n}\n\nvoid CAccount::setNonCompoundRewardScript(const CScript& rewardScript, CWalletDB* Db)\n{\n    nonCompoundRewardScript = rewardScript;\n    if (Db)\n    {\n        Db->EraseAccountNonCompoundWitnessEarningsScript(getUUIDAsString(getUUID()));\n        Db->WriteAccountNonCompoundWitnessEarningsScript(getUUIDAsString(getUUID()), nonCompoundRewardScript);\n    }\n}\n\nbool CAccount::hasRewardTemplate() const\n{\n    return !rewardTemplate.empty();\n}\n\nCWitnessRewardTemplate CAccount::getRewardTemplate() const\n{\n    return rewardTemplate;\n}\n\nvoid CAccount::setRewardTemplate(const CWitnessRewardTemplate& _rewardTemplate, CWalletDB* Db)\n{\n    rewardTemplate = _rewardTemplate;\n    if (Db)\n    {\n        Db->EraseAccountRewardTemplate(getUUIDAsString(getUUID()));\n        Db->WriteAccountRewardTemplate(getUUIDAsString(getUUID()), rewardTemplate);\n    }\n}\n\nboost::uuids::uuid CAccount::getUUID() const\n{\n    return accountUUID;\n}\n\nvoid CAccount::setUUID(const std::string& stringUUID)\n{\n    accountUUID = getUUIDFromString(stringUUID);\n}\n\nboost::uuids::uuid CAccount::getParentUUID() const\n{\n    return parentUUID;\n}\n\n\n\n\n"
  },
  {
    "path": "src/wallet/account.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef ACCOUNT_H\n#define ACCOUNT_H\n\n#include \"amount.h\"\n#include \"streams.h\"\n#include \"tinyformat.h\"\n#include \"util/strencodings.h\"\n#include \"validation/validationinterface.h\"\n#include \"generation/witnessrewardtemplate.h\"\n#include \"script/ismine.h\"\n#include \"wallet/crypter.h\"\n#include <validation/validation.h>\n\n#include <algorithm>\n#include <map>\n#include <set>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <utility>\n#include <vector>\n\n#define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX\n#include <boost/uuid/uuid.hpp>\n#include <boost/uuid/uuid_io.hpp>\n#include <boost/uuid/string_generator.hpp>\n#include <boost/uuid/nil_generator.hpp>\n\n#include <LRUCache/LRUCache11.hpp>\n\n#define KEYCHAIN_EXTERNAL 0\n#define KEYCHAIN_CHANGE 1\n#define KEYCHAIN_WITNESS KEYCHAIN_CHANGE\n#define KEYCHAIN_SPENDING KEYCHAIN_EXTERNAL\nconst uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;\n\nclass CAccountHD;\nclass CWallet;\nclass CWalletDB;\nclass CKeyMetadata;\n\nenum AccountState\n{\n    Normal = 0,                      // Standard account (or HD account)\n    Shadow = 1,                      // Shadow account (account remains invisible until it becomes active - either through account creation or a payment)\n    ShadowChild = 2,                 // Shadow child account (as above but a child of another account) - used to handle legacy accounts (e.g. BIP32 child of BIP44 account that shares the same seed)\n    Deleted = 3,                     // An account that has been deleted - we keep it arround anyway in case it receives funds, if it receives funds then we re-activate it.\n    AccountStateMax = Deleted\n};\n\nenum AccountType\n{\n    Desktop = 0,                     // Standard desktop account.\n    Mobi = 1,                        // Mobile phone. (Android, iOS)\n    PoW2Witness = 2,                 // PoW2 witness account.\n    WitnessOnlyWitnessAccount = 3,   // non-HD witness account without spending keys only witness keys.\n    ImportedPrivateKeyAccount = 4,   // non-HD account contains one or more imported private keys.\n    MiningAccount = 5,               // HD account for mining - special key treatment, re-uses the same key instead of generating new ones repeatedly.\n    AccountTypeMax = MiningAccount\n};\n\nstd::string GetAccountStateString(AccountState state);\nstd::string getUUIDAsString(const boost::uuids::uuid& uuid);\nboost::uuids::uuid getUUIDFromString(const std::string& uuid);\nstd::string GetAccountTypeString(AccountType type);\n\nCAccount* CreateAccountHelper(CWallet* pwallet, std::string accountName, std::string accountType, bool bMakeActive=true);\n\nconst int HDDesktopStartIndex = 0;\nconst int HDMobileStartIndex  = 100000;\nconst int HDWitnessStartIndex = 200000;\nconst int HDMiningStartIndex = 300000;\nconst int HDFutureReservedStartIndex = 400000;\n\nenum AccountStatus\n{\n    WitnessEmpty,       // New witness account no funds yet.\n    WitnessPending,     // New witness account first funds received but not yet confirmed.\n    Default,            // Funded witness account.\n    WitnessExpired,     // Expired witness account.\n    WitnessEnded        // Witness account with lock ended.\n};\n\nclass CHDSeed\n{\npublic:\n    enum SeedType\n    {\n        BIP44 = 0, // New Munt standard based on BIP44 for /all/ Munt wallets (desktop/iOS/android)\n        BIP32 = 1, // Old Munt android/iOS wallets\n        BIP32Legacy = 2, // Very old wallets\n        BIP44External = 3, //External BIP44 wallets like 'coinomi' (uses a different hash that Munt BIP44)\n        BIP44NoHardening = 4 // Same as BIP44 however with no hardening on accounts (Users have to be more careful with key security but allows for synced read only wallets... whereas with normal BIP44 only accounts are possible)\n    };\n\n    CHDSeed();\n    CHDSeed(SecureString mnemonic, SeedType type);\n    CHDSeed(CExtPubKey& pubkey, SeedType type);\n    virtual ~CHDSeed()\n    {\n        //fixme: (FUT) (ACCOUNTS) Check if any cleanup needed here?\n    }\n\n    void Init();\n    void InitReadOnly();\n    CAccountHD* GenerateAccount(AccountType type, CWalletDB* Db);\n    bool GetPrivKeyForAccount(uint64_t nAccountIndex, CExtKey& accountKeyPriv);\n\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        int nVersion = 3;\n        READWRITE(nVersion);\n        //fixme: (2.1) - Remove the below in future if we need to upgrade versions; but delay as long as possible to purge all ald wallets that may have had a corrupted version.\n        if (nVersion > 3)\n            nVersion = 1;\n\n        if (ser_action.ForRead())\n        {\n            int type;\n            READWRITE(type);\n            m_type = (SeedType)type;\n            std::string sUUID;\n            READWRITE(sUUID);\n            m_UUID = getUUIDFromString(sUUID);\n        }\n        else\n        {\n            int type = (int)m_type;\n            READWRITE(type);\n            std::string sUUID = boost::uuids::to_string(m_UUID);\n            READWRITE(sUUID);\n        }\n\n        READWRITE(m_nAccountIndex);\n        READWRITE(m_nAccountIndexMobi);\n        if (nVersion >= 2)\n        {\n            READWRITE(m_nAccountIndexWitness);\n        }\n        if (nVersion >= 3)\n        {\n            READWRITE(m_nAccountIndexMining);\n        }\n\n        READWRITE(masterKeyPub);\n        READWRITE(purposeKeyPub);\n        READWRITE(cointypeKeyPub);\n\n        READWRITE(encrypted);\n        if(encrypted)\n        {\n            READWRITECOMPACTSIZEVECTOR(encryptedMnemonic);\n            READWRITECOMPACTSIZEVECTOR(masterKeyPrivEncrypted);\n            READWRITECOMPACTSIZEVECTOR(purposeKeyPrivEncrypted);\n            READWRITECOMPACTSIZEVECTOR(cointypeKeyPrivEncrypted);\n        }\n        else\n        {\n            READWRITE(unencryptedMnemonic);\n            READWRITE(masterKeyPriv);\n            READWRITE(purposeKeyPriv);\n            READWRITE(cointypeKeyPriv);\n        }\n\n        // Read may fail on older wallets, this is not a problem.\n        try\n        {\n            READWRITE(m_readOnly);\n        }\n        catch(...)\n        {\n        }\n    }\n\n    boost::uuids::uuid getUUID() const;\n    SecureString getMnemonic();\n    SecureString getPubkey();\n\n    virtual bool IsLocked() const;\n    virtual bool IsCrypted() const;\n    virtual bool Lock();\n    virtual bool Unlock(const CKeyingMaterial& vMasterKeyIn);\n    virtual bool Encrypt(const CKeyingMaterial& vMasterKeyIn);\n    virtual bool IsReadOnly() { return m_readOnly; };\n\n    // What type of seed this is (BIP32 or BIP44)\n    SeedType m_type;\n\nprotected:\n    CAccountHD* GenerateAccount(int nAccountIndex, AccountType type);\n    // Worker function for GetPrivKeyForAccount that doesn't contain the safety checks which GetPrivKeyForAccount has.\n    // Other classes should call GetPrivKeyForAccount while internally we call this to avoid unnecessary duplicate safety checks.\n    bool GetPrivKeyForAccountInternal(uint64_t nAccountIndex, CExtKey& accountKeyPriv);\n\n    // Unique seed identifier\n    boost::uuids::uuid m_UUID;\n\n    // Index of next account to generate (normal accounts)\n    int m_nAccountIndex = HDDesktopStartIndex;\n    // Index of next account to generate (mobile accounts)\n    int m_nAccountIndexMobi = HDMobileStartIndex;\n    // Index of next account to generate (witness accounts)\n    int m_nAccountIndexWitness = HDWitnessStartIndex;\n    // Index of next account to generate (mining accounts)\n    int m_nAccountIndexMining = HDMiningStartIndex;\n\n    //Always available\n    CExtPubKey masterKeyPub;  //hd master key (m)      - BIP32 and BIP44\n    CExtPubKey purposeKeyPub; //key at m/44'           - BIP44 only\n    CExtPubKey cointypeKeyPub;//key at m/44'/87'       - BIP44 only\n\n    bool encrypted = false;\n    // These members are only valid when the account is unlocked/unencrypted.\n    SecureString unencryptedMnemonic;\n    CExtKey masterKeyPriv;  //hd master key (m)      - BIP32 and BIP44\n    CExtKey purposeKeyPriv; //key at m/44'           - BIP44 only\n    CExtKey cointypeKeyPriv;//key at m/44'/87'       - BIP44 only\n    CKeyingMaterial vMasterKey;//Memory only.\n\n    bool m_readOnly=false;\n\n    // Contains the encrypted versions of the above - only valid when the account is an encrypted one.\n    std::vector<unsigned char> encryptedMnemonic;\n    std::vector<unsigned char> masterKeyPrivEncrypted;\n    std::vector<unsigned char> purposeKeyPrivEncrypted;\n    std::vector<unsigned char> cointypeKeyPrivEncrypted;\n};\n\n\n/**\n * Account information.\n * Stored in wallet with key \"acc\"+string account name.\n */\nclass CAccount : public CCryptoKeyStore\n{\npublic:\n    CPubKey vchPubKey;\n\n    CAccount();\n    void SetNull();\n\n    //fixme: (FUT) (ACCOUNTS) (CLEANUP)\n    virtual CPubKey GenerateNewKey(CWallet& wallet, CKeyMetadata& metadata, int keyChain);\n\n    //! Account uses hierarchial deterministic key generation and not legacy (random) key generation.\n    virtual bool IsHD() const {return false;};\n\n    //! Account is of the mobile type (linkable via qr)\n    virtual bool IsMobi() const {return m_Type == Mobi;}\n\n    //! Account is capable of performing witness operations.\n    virtual bool IsPoW2Witness() const { return m_Type == PoW2Witness || m_Type == WitnessOnlyWitnessAccount; }\n\n    //! Account has a fixed keypool that should not remove the keys on use.\n    virtual bool IsFixedKeyPool() const { return m_Type == WitnessOnlyWitnessAccount || m_Type == ImportedPrivateKeyAccount; }\n    \n    //! Account has a minimal keypool that should attempt to grow as little as possible (only mark keys used if explicitely requested to do so)\n    virtual bool IsMinimalKeyPool() const { return m_Type == MiningAccount; }\n    \n    //! Account is a witness-only account.\n    virtual bool IsWitnessOnly() const { return (IsPoW2Witness() && IsFixedKeyPool()); }\n    \n    //! Account is for mining\n    virtual bool IsMiningAccount() const { return m_Type == MiningAccount; }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        if (ser_action.ForRead())\n        {\n            int32_t nState;\n            int32_t nType;\n            READWRITE(nState);\n            READWRITE(nType);\n            m_State = (AccountState)nState;\n            m_Type = (AccountType)nType;\n            if (m_State == AccountState::ShadowChild)\n            {\n                std::string sParentUUID;\n                READWRITE(sParentUUID);\n                parentUUID = getUUIDFromString(sParentUUID);\n            }\n        }\n        else\n        {\n            int32_t nState = (int)m_State;\n            int32_t nType = (int)m_Type;\n            READWRITE(nState);\n            READWRITE(nType);\n            if (m_State == AccountState::ShadowChild)\n            {\n                std::string sParentUUID = boost::uuids::to_string(parentUUID);\n                READWRITE(sParentUUID);\n            }\n        }\n        READWRITE(earliestPossibleCreationTime);\n\n        // Read may fail on older wallets, this is not a problem.\n        try\n        {\n            READWRITE(m_readOnly);\n        }\n        catch(...)\n        {\n        }\n        //Handle invalid values (in case older wallets ended up with an invalid state somehow)\n        if (m_State > AccountState::AccountStateMax)\n        {\n            m_State = AccountState::Normal;\n            m_readOnly = false;\n        }\n        if (m_Type > AccountType::AccountTypeMax)\n        {\n            m_Type = AccountType::Desktop;\n            m_readOnly = false;\n        }\n        if (!IsHD())\n        {\n            m_readOnly = false;\n        }\n    }\n\n\n    virtual bool HaveKey(const CKeyID &address) const override;\n    bool HaveKeyInternal(const CKeyID &address) const;\n    virtual bool HaveWatchOnly(const CScript &dest) const override;\n    virtual bool HaveWatchOnly() const override;\n    virtual bool HaveCScript(const CScriptID &hash) const override;\n    virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;\n    virtual bool IsLocked() const override;\n    virtual bool IsCrypted() const override;\n    virtual bool Lock() override;\n    virtual bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk) override;\n    virtual bool GetKey(const CKeyID& keyID, CKey& key) const override;\n    virtual bool GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut) const override;\n    virtual void GetKeys(std::set<CKeyID> &setAddress) const override;\n    void GetKeys(std::set<CKeyID> &setAddressExternal, std::set<CKeyID> &setAddressInternal) const;\n    virtual bool EncryptKeys(const CKeyingMaterial& vMasterKeyIn) override;\n    virtual bool Encrypt(const CKeyingMaterial& vMasterKeyIn);\n    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;\n    virtual bool AddWatchOnly(const CScript &dest) override;\n    virtual bool RemoveWatchOnly(const CScript &dest) override;\n    virtual bool AddCScript(const CScript& redeemScript) override;\n    virtual bool AddCryptedKeyWithChain(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, int64_t nKeyChain);\n\n    virtual bool AddKeyPubKey([[maybe_unused]] const CKey& key, [[maybe_unused]] const CPubKey &pubkey) override {assert(0);};//Must never be called directly\n    virtual bool AddKeyPubKey([[maybe_unused]] int64_t HDKeyIndex, [[maybe_unused]] const CPubKey &pubkey) override {assert(0);};//Must never be called directly\n\n    virtual bool HaveWalletTx(const CTransaction& tx);\n    virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int keyChain);\n    virtual bool AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, int keyChain);\n    void AddChild(CAccount* childAccount);\n\n    unsigned int GetKeyPoolSize(int keyChain);\n    //Deprecated, should be removed in future in favour of the one above\n    unsigned int GetKeyPoolSize();\n\n    std::string getLabel() const;\n    void setLabel(const std::string& label, CWalletDB* Db);\n\n    //! We store a database of \"links\" that have been established with other services, below functions manipulate this database\n    //! e.g. a user may link his holding account with one or more cloud services\n    //! NB! loadLinks is only for wallet load and should not be used elsewhere\n    void loadLinks(std::map<std::string, std::string>& accountLinks_);\n    void addLink(const std::string& serviceName, const std::string& serviceData, CWalletDB* Db);\n    void removeLink(const std::string& serviceName, CWalletDB* Db);\n    std::map<std::string, std::string> getLinks() const;\n\n    //! Sets whether a witness account should compound earnings or not.\n    //! 0 sets compounding off.\n    //! If compoundAmount is positive - rewards up to amount compoundAmount are compounded and the remainder not.\n    //! If compoundAmount is negative - the first compoundAmount earnings are not compounded and the remainder is.\n    //! If the amount to be compounded exceeds network rules it will be truncated to the network maximum and the remainder will go to a non-compound output.\n    //! If both this and compounding percent are set then compounding percent will override this\n    void setCompounding(CAmount compoundAmount, CWalletDB* Db);\n    CAmount getCompounding() const;\n    \n    //! Sets whether a witness account should compound earnings as a percentage or not.\n    //! 0 sets compounding off.\n    //! If compoundAmount is non zero - then this percentage of the rewards are compounded and the remainder not.\n    //! If the amount to be compounded exceeds network rules it will be truncated to the network maximum and the remainder will go to a non-compound output.\n    //! If both this and compounding are set then this will override compounding percent\n    void setCompoundingPercent(int32_t compoundPercent, CWalletDB* Db);\n    int32_t getCompoundingPercent() const;\n\n    //! Sets a script that should be used to handle the portion of witnessing rewards not compounded via 'setCompounding'.\n    //! See 'setCompounding' for a description on how to control which rewards go where.\n    //! If no script is set the wallet will create a default one using a key from the accounts keypool, and fail if none are available (though this should never happen)\n    void setNonCompoundRewardScript(const CScript& rewardScript, CWalletDB* Db);\n    bool hasNonCompoundRewardScript() const;\n    CScript getNonCompoundRewardScript() const;\n\n    //! Reward template controlling how witness rewards are are distributed. If set it takes precedence over the compounding amount above. See rpc setwitnessrewardtemplate help for more documentation.\n    bool hasRewardTemplate() const;\n    CWitnessRewardTemplate getRewardTemplate() const;\n    void setRewardTemplate(const CWitnessRewardTemplate& _rewardTemplate, CWalletDB* Db);\n\n    AccountStatus GetWarningState() { return nWarningState; };\n    void SetWarningState(AccountStatus nWarningState_) { nWarningState = nWarningState_; };\n\n    boost::uuids::uuid getUUID() const;\n    void setUUID(const std::string& stringUUID);\n    boost::uuids::uuid getParentUUID() const;\n\n    bool IsReadOnly() { return m_readOnly; };\n\n    CCryptoKeyStore externalKeyStore;\n    CCryptoKeyStore internalKeyStore;\n    mutable RecursiveMutex cs_keypool;\n    std::set<int64_t> setKeyPoolInternal;\n    std::set<int64_t> setKeyPoolExternal;\n    AccountState m_State = AccountState::Normal;\n    AccountType m_Type = AccountType::Desktop;\n\n    void possiblyUpdateEarliestTime(uint64_t creationTime, CWalletDB* Db);\n    uint64_t getEarliestPossibleCreationTime();\nprotected:\n    //We keep a UUID for internal referencing - and a label for user purposes, this way the user can freely change the label without us having to rewrite huge parts of the database on disk.\n    boost::uuids::uuid accountUUID;\n    boost::uuids::uuid parentUUID;\n    std::string accountLabel;\n    std::map<std::string, std::string> accountLinks;\n    CAmount compoundEarnings = 0;\n    int32_t compoundEarningsPercent = std::numeric_limits<int32_t>::max();\n    CScript nonCompoundRewardScript;\n    CWitnessRewardTemplate rewardTemplate;\n    uint64_t earliestPossibleCreationTime;\n\n    bool m_readOnly = false;\n\n    CKeyingMaterial vMasterKey; // Memory only.\n    friend class CExtWallet;\n    friend class CWallet;\n\n    AccountStatus nWarningState = AccountStatus::Default; // Memory only\n};\n\n\n\nclass CAccountHD: public CAccount\n{\npublic:\n    //Normal construction.\n    CAccountHD(CExtKey accountKey, boost::uuids::uuid seedID, AccountType type);\n    //Read only construction.\n    CAccountHD(CExtPubKey accountKey, boost::uuids::uuid seedID, AccountType type);\n    //For serialization only.\n    CAccountHD(){};\n\n    virtual bool GetAccountKeyIDWithHighestIndex(CKeyID& HDKeyID, int nChain) const;\n    virtual bool GetKey(CExtKey& childKey, int nChain) const;\n    virtual bool GetKey(const CKeyID& keyID, CKey& key) const override;\n    virtual bool GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut) const override;\n    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;\n    virtual CPubKey GenerateNewKey(CWallet& wallet, CKeyMetadata& metadata, int keyChain) override;\n    virtual bool Lock() override;\n    virtual bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk) override;\n    virtual bool Encrypt(const CKeyingMaterial& vMasterKeyIn) override;\n    virtual bool IsCrypted() const override;\n    virtual bool IsLocked() const override;\n    virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int keyChain) override;\n    virtual bool AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, int keyChain) override;\n    \n    //NB!! This only exists for the sake of recovery code in wallet_init - it should not be used directly anywhere else in the codebase\n    bool GetPubKeyManual(int64_t HDKeyIndex, int keyChain, CExtPubKey& childKey) const;\n\n    void GetPubKey(CExtPubKey& childKey, int nChain) const;\n    bool IsHD() const override {return true;};\n    uint32_t getIndex();\n    boost::uuids::uuid getSeedUUID() const;\n    CExtKey* GetAccountMasterPrivKey();\n    SecureString GetAccountMasterPubKeyEncoded();\n\n\n    ADD_SERIALIZE_METHODS;\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        int nVersion = 2;\n        READWRITE(nVersion);\n        if (nVersion > 3)\n            nVersion = 1;\n\n\n        if (ser_action.ForRead())\n        {\n            std::string sUUID;\n            READWRITE(sUUID);\n            m_SeedID = getUUIDFromString(sUUID);\n        }\n        else\n        {\n            std::string sUUID = boost::uuids::to_string(m_SeedID);\n            READWRITE(sUUID);\n        }\n        READWRITE(m_nIndex);\n        READWRITE(m_nNextChildIndex);\n        READWRITE(m_nNextChangeIndex);\n\n        READWRITE(primaryChainKeyPub);\n        READWRITE(changeChainKeyPub);\n\n        READWRITE(encrypted);\n\n        if ( IsCrypted() )\n        {\n            READWRITECOMPACTSIZEVECTOR(accountKeyPrivEncrypted);\n            READWRITECOMPACTSIZEVECTOR(primaryChainKeyEncrypted);\n            READWRITECOMPACTSIZEVECTOR(changeChainKeyEncrypted);\n        }\n        else\n        {\n            READWRITE(accountKeyPriv);\n            READWRITE(primaryChainKeyPriv);\n            READWRITE(changeChainKeyPriv);\n        }\n\n        CAccount::SerializationOp(s, ser_action);\n    }\nprivate:\n    boost::uuids::uuid m_SeedID;\n    uint32_t m_nIndex = 0;\n    mutable uint32_t m_nNextChildIndex = 0;\n    mutable uint32_t m_nNextChangeIndex = 0;\n\n    //These members are always valid.\n    CExtPubKey primaryChainKeyPub;\n    CExtPubKey changeChainKeyPub;\n    bool encrypted = false;\n\n    //These members are only valid when the account is unlocked/unencrypted.\n    CExtKey accountKeyPriv;         //key at m/0' (bip32) or m/44'/87'/n' (bip44)\n    CExtKey primaryChainKeyPriv;    //key at m/0'/0 (bip32) or m/44'/87'/0'/0 (bip44)\n    CExtKey changeChainKeyPriv;     //key at m/0'/1 (bip32) or m/44'/87'/0'/1 (bip44)\n\n    //Contains the encrypted versions of the above - only valid when the account is an encrypted one.\n    std::vector<unsigned char> accountKeyPrivEncrypted;\n    std::vector<unsigned char> primaryChainKeyEncrypted;\n    std::vector<unsigned char> changeChainKeyEncrypted;\n};\n\n\n#endif\n"
  },
  {
    "path": "src/wallet/coincontrol.h",
    "content": "// Copyright (c) 2011-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef WALLET_COINCONTROL_H\n#define WALLET_COINCONTROL_H\n\n#include \"policy/feerate.h\"\n#include \"primitives/transaction.h\"\n#include \"wallet/wallet.h\"\n\n/** Coin Control Features. */\nclass CCoinControl\n{\npublic:\n    CTxDestination destChange;\n    //! If false, allows unselected inputs, but requires all selected inputs be used\n    bool fAllowOtherInputs;\n    //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria\n    bool fAllowWatchOnly;\n    //! Override estimated feerate\n    bool fOverrideFeeRate;\n    //! Feerate to use if overrideFeeRate is true\n    CFeeRate nFeeRate;\n    //! Override the default confirmation target, 0 = use default\n    int nConfirmTarget;\n    //! Signal BIP-125 replace by fee.\n    bool signalRbf;\n\n    CCoinControl()\n    {\n        SetNull();\n    }\n\n    void SetNull()\n    {\n        destChange = CNoDestination();\n        fAllowOtherInputs = false;\n        fAllowWatchOnly = false;\n        setSelected.clear();\n        nFeeRate = CFeeRate(0);\n        fOverrideFeeRate = false;\n        nConfirmTarget = 0;\n        signalRbf = fWalletRbf;\n    }\n\n    bool HasSelected() const\n    {\n        return (setSelected.size() > 0);\n    }\n\n    bool IsSelected(const COutPoint& output) const\n    {\n        return (setSelected.count(output) > 0);\n    }\n\n    void Select(const COutPoint& output)\n    {\n        setSelected.insert(output);\n    }\n\n    void UnSelect(const COutPoint& output)\n    {\n        setSelected.erase(output);\n    }\n\n    void UnSelectAll()\n    {\n        setSelected.clear();\n    }\n\n    void ListSelected(std::vector<COutPoint>& vOutpoints) const\n    {\n        vOutpoints.assign(setSelected.begin(), setSelected.end());\n    }\n\nprivate:\n    std::set<COutPoint> setSelected;\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/crypter.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"crypter.h\"\n\n#include \"crypto/sha512.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"util.h\"\n\n#include <string>\n#include <vector>\n\n#include <cryptopp/config.h>\n#include <cryptopp/aes.h>\n#include <cryptopp/modes.h>\n#include <cryptopp/filters.h>\n\nint CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const\n{\n    // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc\n    // cipher and sha512 message digest. Because sha512's output size (64b) is\n    // greater than the aes256 block size (16b) + aes256 key size (32b),\n    // there's no need to process more than once (D_0).\n\n    if(!count || !key || !iv)\n        return 0;\n\n    unsigned char buf[CSHA512::OUTPUT_SIZE];\n    CSHA512 di;\n\n    di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());\n    if(chSalt.size())\n        di.Write(&chSalt[0], chSalt.size());\n    di.Finalize(buf);\n\n    for(int i = 0; i != count - 1; i++)\n        di.Reset().Write(buf, sizeof(buf)).Finalize(buf);\n\n    memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);\n    memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);\n    memory_cleanse(buf, sizeof(buf));\n    return WALLET_CRYPTO_KEY_SIZE;\n}\n\nbool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)\n{\n    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)\n        return false;\n\n    int i = 0;\n    if (nDerivationMethod == 0)\n        i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());\n\n    if (i != (int)WALLET_CRYPTO_KEY_SIZE)\n    {\n        memory_cleanse(vchKey.data(), vchKey.size());\n        memory_cleanse(vchIV.data(), vchIV.size());\n        return false;\n    }\n\n    fKeySet = true;\n    return true;\n}\n\nbool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)\n{\n    if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE)\n    {\n        LogPrintf(\"CCrypter::SetKey Invalid key size [%d] expected [%d]\", chNewKey.size(), WALLET_CRYPTO_KEY_SIZE);\n        return false;\n    }\n    if (chNewIV.size() != WALLET_CRYPTO_IV_SIZE)\n    {\n        LogPrintf(\"CCrypter::SetKey Invalid IV size [%d] expected [%d]\", chNewIV.size(), WALLET_CRYPTO_IV_SIZE);\n        return false;\n    }\n\n    memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());\n    memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());\n\n    fKeySet = true;\n    return true;\n}\n\n//fixme: See https://github.com/weidai11/cryptopp/issues/953\n//Ideally this should be resolved in cryptopp library, when it is remove this class\ntemplate <typename T> class CryptoVectorSource : public CryptoPP::SourceTemplate<CryptoPP::StringStore>\n{\npublic:\n    CryptoVectorSource(BufferedTransformation *attachment = NULLPTR)\n        : SourceTemplate<CryptoPP::StringStore>(attachment) {}\n    CryptoVectorSource(const T &vec, bool pumpAll, BufferedTransformation *attachment = NULLPTR)\n        : SourceTemplate<CryptoPP::StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters(\"InputBuffer\", CryptoPP::ConstByteArrayParameter(vec)));}\n};\n\nbool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const\n{\n    if (!fKeySet)\n        return false;\n\n    //NB! Some of our calling code (wallet password change) relies on us clearing the cipher text for it (i.e. passes in a non cleared variable) so don't remove this.\n    vchCiphertext.clear();\n\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc;\n    enc.SetKeyWithIV(vchKey.data(), vchKey.size(), vchIV.data());\n    try\n    {\n        CryptoVectorSource s(vchPlaintext, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::VectorSink(vchCiphertext)));\n        if (vchCiphertext.size() < vchPlaintext.size())\n            return false;\n    }\n    catch(...)\n    {\n        return false;\n    }\n\n    return true;\n}\n\nbool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const\n{\n    if (!fKeySet)\n        return false;\n\n    //Always clear for symmetry with Encrypt function; see comment in Encrypt function for why Encrypt behaves in this manner\n    vchPlaintext.clear();\n\n    CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec;\n    dec.SetKeyWithIV(vchKey.data(), vchKey.size(), vchIV.data());\n    try\n    {\n        {\n            CryptoVectorSource s(vchCiphertext, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::StringSinkTemplate<CKeyingMaterial>(vchPlaintext)));\n        }\n        if (vchPlaintext.size() == 0)\n            return false;\n    }\n    catch(...)\n    {\n        return false;\n    }\n    return true;\n}\n\nbool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const std::vector<unsigned char>& nIV, std::vector<unsigned char> &vchCiphertext)\n{\n    assert(nIV.size() == WALLET_CRYPTO_IV_SIZE);\n    CCrypter cKeyCrypter;\n    if(!cKeyCrypter.SetKey(vMasterKey, nIV))\n        return false;\n    return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);\n}\n\nbool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)\n{\n    std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);\n    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);\n    return EncryptSecret(vMasterKey, vchPlaintext, chIV, vchCiphertext);\n}\n\nbool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const std::vector<unsigned char>& nIV, CKeyingMaterial& vchPlaintext)\n{\n    assert(nIV.size() == WALLET_CRYPTO_IV_SIZE);\n    CCrypter cKeyCrypter;\n    if(!cKeyCrypter.SetKey(vMasterKey, nIV))\n        return false;\n    return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));\n}\n\nbool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)\n{\n    std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);\n    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);\n    return DecryptSecret(vMasterKey, vchCiphertext, chIV, vchPlaintext);\n}\n\nstatic bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)\n{\n    CKeyingMaterial vchSecret;\n    if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))\n        return false;\n\n    if (vchSecret.size() != 32)\n        return false;\n\n    key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());\n    return key.VerifyPubKey(vchPubKey);\n}\n\nbool CCryptoKeyStore::SetCrypted()\n{\n    LOCK(cs_KeyStore);\n    if (fUseCrypto)\n        return true;\n    if (!mapKeys.empty())\n        return false;\n    fUseCrypto = true;\n    return true;\n}\n\nbool CCryptoKeyStore::Lock()\n{\n    if (!SetCrypted())\n        return false;\n\n    {\n        LOCK(cs_KeyStore);\n        vMasterKey.clear();\n    }\n\n    NotifyStatusChanged(this);\n    return true;\n}\n\nbool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk)\n{\n    needsWriteToDisk = false;\n    {\n        LOCK(cs_KeyStore);\n        if (!SetCrypted())\n            return false;\n\n        bool keyPass = false;\n        bool keyFail = false;\n        bool KeyNone = true;\n        CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();\n        for (; mi != mapCryptedKeys.end(); ++mi)\n        {\n            KeyNone = false;\n            const CPubKey &vchPubKey = (*mi).second.first;\n            const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;\n            CKey key;\n            if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))\n            {\n                keyFail = true;\n                break;\n            }\n            keyPass = true;\n            if (fDecryptionThoroughlyChecked)\n                break;\n        }\n        if (keyPass && keyFail)\n        {\n            LogPrintf(\"The wallet is probably corrupted: Some keys decrypt but not all.\\n\");\n            assert(false);\n        }\n        if (!KeyNone && (keyFail || !keyPass))\n            return false;\n        vMasterKey = vMasterKeyIn;\n        fDecryptionThoroughlyChecked = true;\n    }\n    NotifyStatusChanged(this);\n    return true;\n}\n\nbool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!IsCrypted())\n            return CBasicKeyStore::AddKeyPubKey(key, pubkey);\n\n        if (IsLocked())\n            return false;\n\n        std::vector<unsigned char> vchCryptedSecret;\n        CKeyingMaterial vchSecret(key.begin(), key.end());\n        if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))\n            return false;\n\n        if (!AddCryptedKey(pubkey, vchCryptedSecret))\n            return false;\n    }\n    return true;\n}\n\nbool CCryptoKeyStore::AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey)\n{\n    // For HD we don't encrypt anything here - as the public key we need access to anyway, and the index is not special info - we derive the private key when we need it.\n    {\n        LOCK(cs_KeyStore);\n        return CBasicKeyStore::AddKeyPubKey(HDKeyIndex, pubkey);\n    }\n}\n\n\nbool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!SetCrypted())\n            return false;\n\n        mapCryptedKeys[vchPubKey.GetID()] = std::pair(vchPubKey, vchCryptedSecret);\n    }\n    return true;\n}\n\nbool CCryptoKeyStore::GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut) const\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!IsCrypted())\n            return false;\n\n        CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);\n        if (mi != mapCryptedKeys.end())\n        {\n            encryptedKeyOut = (*mi).second.second;\n            return true;\n        }\n    }\n    return false;\n}\n\nbool CCryptoKeyStore::GetKeyIDWithHighestIndex(CKeyID &address) const\n{\n   // For HD we don't encrypt anything here - as the public key we need access to anyway, and the index is not special info - we derive the private key when we need it.\n    {\n        LOCK(cs_KeyStore);\n        return CBasicKeyStore::GetKeyIDWithHighestIndex(address);\n    }\n}\n\nbool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!IsCrypted())\n            return CBasicKeyStore::GetKey(address, keyOut);\n\n        CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);\n        if (mi != mapCryptedKeys.end())\n        {\n            const CPubKey &vchPubKey = (*mi).second.first;\n            const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;\n            return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);\n        }\n    }\n    return false;\n}\n\nbool CCryptoKeyStore::GetKey(const CKeyID &address, int64_t& HDKeyIndex) const\n{\n    // For HD we don't encrypt anything here - as the public key we need access to anyway, and the index is not special info - we derive the private key when we need it.\n    {\n        LOCK(cs_KeyStore);\n        return CBasicKeyStore::GetKey(address, HDKeyIndex);\n    }\n}\n\nbool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!IsCrypted())\n            return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);\n\n        CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);\n        if (mi != mapCryptedKeys.end())\n        {\n            vchPubKeyOut = (*mi).second.first;\n            return true;\n        }\n        // Check for watch-only pubkeys\n        return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);\n    }\n    return false;\n}\n\nbool CCryptoKeyStore::EncryptKeys(const CKeyingMaterial& vMasterKeyIn)\n{\n    {\n        LOCK(cs_KeyStore);\n        if (!mapCryptedKeys.empty() || IsCrypted())\n            return false;\n\n        fUseCrypto = true;\n        for(KeyMap::value_type& mKey : mapKeys)\n        {\n            const CKey &key = mKey.second;\n            CPubKey vchPubKey = key.GetPubKey();\n            CKeyingMaterial vchSecret(key.begin(), key.end());\n            std::vector<unsigned char> vchCryptedSecret;\n            if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))\n                return false;\n            if (!AddCryptedKey(vchPubKey, vchCryptedSecret))\n                return false;\n        }\n        mapKeys.clear();\n    }\n    return true;\n}\n"
  },
  {
    "path": "src/wallet/crypter.h",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_CRYPTER_H\n#define WALLET_CRYPTER_H\n\n#include \"keystore.h\"\n#include \"serialize.h\"\n#include \"support/allocators/secure.h\"\n\nclass uint256;\n\nconst unsigned int WALLET_CRYPTO_KEY_SIZE = 32;\nconst unsigned int WALLET_CRYPTO_SALT_SIZE = 8;\nconst unsigned int WALLET_CRYPTO_IV_SIZE = 16;\n\n/**\n * Private key encryption is done based on a CMasterKey,\n * which holds a salt and random encryption key.\n * \n * CMasterKeys are encrypted using AES-256-CBC using a key\n * derived using derivation method nDerivationMethod\n * (0 == EVP_sha512()) and derivation iterations nDeriveIterations.\n * vchOtherDerivationParameters is provided for alternative algorithms\n * which may require more parameters (such as scrypt).\n * \n * Wallet Private Keys are then encrypted using AES-256-CBC\n * with the double-sha256 of the public key as the IV, and the\n * master key's key as the encryption key (see keystore.[ch]).\n */\n\n/** Master key for wallet encryption */\nclass CMasterKey\n{\npublic:\n    std::vector<unsigned char> vchCryptedKey;\n    std::vector<unsigned char> vchSalt;\n    //! 0 = EVP_sha512()\n    //! 1 = scrypt()\n    unsigned int nDerivationMethod;\n    unsigned int nDeriveIterations;\n    //! Use this for more parameters to key derivation,\n    //! such as the various parameters to scrypt\n    std::vector<unsigned char> vchOtherDerivationParameters;\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITECOMPACTSIZEVECTOR(vchCryptedKey);\n        READWRITECOMPACTSIZEVECTOR(vchSalt);\n        READWRITE(nDerivationMethod);\n        READWRITE(nDeriveIterations);\n        READWRITECOMPACTSIZEVECTOR(vchOtherDerivationParameters);\n    }\n\n    CMasterKey()\n    {\n        // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M\n        // ie slightly lower than the lowest hardware we need bother supporting\n        nDeriveIterations = 25000;\n        nDerivationMethod = 0;\n        vchOtherDerivationParameters = std::vector<unsigned char>(0);\n    }\n};\n\ntypedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;\n\nnamespace wallet_crypto\n{\n    class TestCrypter;\n}\n\nbool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const std::vector<unsigned char>& nIV, std::vector<unsigned char> &vchCiphertext);\nbool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);\nbool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const std::vector<unsigned char>& nIV, CKeyingMaterial& vchPlaintext);\nbool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);\n\n/** Encryption/decryption context with key information */\nclass CCrypter\n{\nfriend class wallet_crypto::TestCrypter; // for test access to chKey/chIV\nprivate:\n    std::vector<unsigned char, secure_allocator<unsigned char>> vchKey;\n    std::vector<unsigned char, secure_allocator<unsigned char>> vchIV;\n    bool fKeySet;\n\n    int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const;\n\npublic:\n    bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);\n    bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const;\n    bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const;\n    bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);\n\n    void CleanKey()\n    {\n        memory_cleanse(vchKey.data(), vchKey.size());\n        memory_cleanse(vchIV.data(), vchIV.size());\n        fKeySet = false;\n    }\n\n    CCrypter()\n    {\n        fKeySet = false;\n        vchKey.resize(WALLET_CRYPTO_KEY_SIZE);\n        vchIV.resize(WALLET_CRYPTO_IV_SIZE);\n    }\n\n    ~CCrypter()\n    {\n        CleanKey();\n    }\n};\n\n/** Keystore which keeps the private keys encrypted.\n * It derives from the basic key store, which is used if no encryption is active.\n */\nclass CCryptoKeyStore : public CBasicKeyStore\n{\nprivate:\n    CryptedKeyMap mapCryptedKeys;\n\n    CKeyingMaterial vMasterKey;\n\n    //! if fUseCrypto is true, mapKeys must be empty\n    //! if fUseCrypto is false, vMasterKey must be empty\n    bool fUseCrypto;\n\n    //! keeps track of whether Unlock has run a thorough check before\n    bool fDecryptionThoroughlyChecked;\n\nprotected:\n    virtual bool SetCrypted();\n\n    //! will encrypt previously unencrypted keys\n    virtual bool EncryptKeys(const CKeyingMaterial& vMasterKeyIn);\n\n    virtual bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool& needsWriteToDisk);\n\n    CCryptoKeyStore()\n    : CBasicKeyStore()\n    , fUseCrypto(false)\n    , fDecryptionThoroughlyChecked(false)\n    {\n    }\n\n    virtual bool IsCrypted() const\n    {\n        return fUseCrypto;\n    }\n\n    virtual bool IsLocked() const\n    {\n        if (!IsCrypted())\n            return false;\n        bool result;\n        {\n            LOCK(cs_KeyStore);\n            result = vMasterKey.empty();\n        }\n        return result;\n    }\n\n    virtual bool Lock();\n\n    virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);\n    virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);\n    virtual bool AddKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey);\n    virtual bool HaveKey(const CKeyID &address) const\n    {\n        {\n            LOCK(cs_KeyStore);\n            if (!IsCrypted())\n                return CBasicKeyStore::HaveKey(address);\n            return mapCryptedKeys.count(address) > 0;\n        }\n        return false;\n    }\n    virtual bool GetKey(const CKeyID &address, std::vector<unsigned char>& encryptedKeyOut) const;\n    virtual bool GetKey(const CKeyID &address, CKey& keyOut) const;\n    virtual bool GetKeyIDWithHighestIndex(CKeyID& address) const;\n    virtual bool GetKey(const CKeyID &address, int64_t& HDKeyIndex) const;\n    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;\n    virtual void GetKeys(std::set<CKeyID> &setAddress) const\n    {\n        if (!IsCrypted())\n        {\n            CBasicKeyStore::GetKeys(setAddress);\n            return;\n        }\n        setAddress.clear();\n        CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();\n        while (mi != mapCryptedKeys.end())\n        {\n            setAddress.insert((*mi).first);\n            mi++;\n        }\n    }\n\npublic:\n    /**\n     * Wallet status (encrypted, locked) changed.\n     * Note: Called without locks held.\n     */\n    boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;\n    friend class CAccount;\n    friend class CAccountHD;\n    friend class CWallet;\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/db.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"db.h\"\n\n#include \"addrman.h\"\n#include \"fs.h\"\n#include \"hash.h\"\n#include \"protocol.h\"\n#include \"util.h\"\n#include \"util/strencodings.h\"\n\n#include <stdint.h>\n\n#ifndef WIN32\n#include <sys/stat.h>\n#endif\n\n\n#include <boost/thread.hpp>\n\n//\n// CDB\n//\n\nCDBEnv bitdb;\n\nvoid CDBEnv::EnvShutdown()\n{\n    if (!fDbEnvInit)\n        return;\n\n    fDbEnvInit = false;\n    int ret = dbenv->close(0);\n    if (ret != 0)\n        LogPrintf(\"CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\\n\", ret, DbEnv::strerror(ret));\n    if (!fMockDb)\n        DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);\n}\n\nvoid CDBEnv::Reset()\n{\n    delete dbenv;\n    dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);\n    fDbEnvInit = false;\n    fMockDb = false;\n}\n\nCDBEnv::CDBEnv() : dbenv(NULL)\n{\n    Reset();\n}\n\nCDBEnv::~CDBEnv()\n{\n    EnvShutdown();\n    delete dbenv;\n    dbenv = NULL;\n}\n\nvoid CDBEnv::Close()\n{\n    EnvShutdown();\n}\n\nbool CDBEnv::Open(const fs::path& pathIn)\n{\n    if (fDbEnvInit)\n        return true;\n\n    boost::this_thread::interruption_point();\n\n    strPath = pathIn.string();\n    fs::path pathLogDir = pathIn / \"database\";\n    TryCreateDirectory(pathLogDir);\n    fs::path pathErrorFile = pathIn / \"db.log\";\n    LogPrintf(\"CDBEnv::Open: LogDir=%s ErrorFile=%s\\n\", pathLogDir.string(), pathErrorFile.string());\n\n    unsigned int nEnvFlags = 0;\n    if (GetBoolArg(\"-privdb\", DEFAULT_WALLET_PRIVDB))\n        nEnvFlags |= DB_PRIVATE;\n\n    dbenv->set_lg_dir(pathLogDir.string().c_str());\n    dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet\n    dbenv->set_lg_bsize(0x10000);\n    dbenv->set_lg_max(1048576);\n    dbenv->set_lk_max_locks(40000);\n    dbenv->set_lk_max_objects(40000);\n    dbenv->set_errfile(fsbridge::fopen(pathErrorFile, \"a\")); /// debug\n    dbenv->set_flags(DB_AUTO_COMMIT, 1);\n    dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);\n    dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);\n    int ret = dbenv->open(strPath.c_str(),\n                         DB_CREATE |\n                             DB_INIT_LOCK |\n                             DB_INIT_LOG |\n                             DB_INIT_MPOOL |\n                             DB_INIT_TXN |\n                             DB_THREAD |\n                             DB_RECOVER |\n                             nEnvFlags,\n                         S_IRUSR | S_IWUSR);\n    if (ret != 0)\n        return error(\"CDBEnv::Open: Error %d opening database environment: %s\\n\", ret, DbEnv::strerror(ret));\n\n    fDbEnvInit = true;\n    fMockDb = false;\n    return true;\n}\n\nvoid CDBEnv::MakeMock()\n{\n    if (fDbEnvInit)\n        throw std::runtime_error(\"CDBEnv::MakeMock: Already initialized\");\n\n    boost::this_thread::interruption_point();\n\n    LogPrint(BCLog::DB, \"CDBEnv::MakeMock\\n\");\n\n    dbenv->set_cachesize(1, 0, 1);\n    dbenv->set_lg_bsize(10485760 * 4);\n    dbenv->set_lg_max(10485760);\n    dbenv->set_lk_max_locks(10000);\n    dbenv->set_lk_max_objects(10000);\n    dbenv->set_flags(DB_AUTO_COMMIT, 1);\n    dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);\n    int ret = dbenv->open(NULL,\n                         DB_CREATE |\n                             DB_INIT_LOCK |\n                             DB_INIT_LOG |\n                             DB_INIT_MPOOL |\n                             DB_INIT_TXN |\n                             DB_THREAD |\n                             DB_PRIVATE,\n                         S_IRUSR | S_IWUSR);\n    if (ret > 0)\n        throw std::runtime_error(strprintf(\"CDBEnv::MakeMock: Error %d opening database environment.\", ret));\n\n    fDbEnvInit = true;\n    fMockDb = true;\n}\n\nCDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename)\n{\n    LOCK(cs_db);\n    assert(mapFileUseCount.count(strFile) == 0 || mapFileUseCount[strFile]== 0);\n\n    Db db(dbenv, 0);\n    int result = db.verify(strFile.c_str(), NULL, NULL, 0);\n    if (result == 0)\n        return VERIFY_OK;\n    else if (recoverFunc == NULL)\n        return RECOVER_FAIL;\n\n    // Try to recover:\n    bool fRecovered = (*recoverFunc)(strFile, out_backup_filename);\n    return (fRecovered ? RECOVER_OK : RECOVER_FAIL);\n}\n\nbool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)\n{\n    // Recovery procedure:\n    // move wallet file to walletfilename.timestamp.bak\n    // Call Salvage with fAggressive=true to\n    // get as much data as possible.\n    // Rewrite salvaged data to fresh wallet file\n    // Set -rescan so any missing transactions will be\n    // found.\n    int64_t now = GetTime();\n    newFilename = strprintf(\"%s.%d.bak\", filename, now);\n\n    int result = bitdb.dbenv->dbrename(NULL, filename.c_str(), NULL,\n                                       newFilename.c_str(), DB_AUTO_COMMIT);\n    if (result == 0)\n        LogPrintf(\"Renamed %s to %s\\n\", filename, newFilename);\n    else\n    {\n        LogPrintf(\"Failed to rename %s to %s\\n\", filename, newFilename);\n        return false;\n    }\n\n    std::vector<CDBEnv::KeyValPair> salvagedData;\n    bool fSuccess = bitdb.Salvage(newFilename, true, salvagedData);\n    if (salvagedData.empty())\n    {\n        LogPrintf(\"Salvage(aggressive) found no records in %s.\\n\", newFilename);\n        return false;\n    }\n    LogPrintf(\"Salvage(aggressive) found %u records\\n\", salvagedData.size());\n\n    std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0));\n    int ret = pdbCopy->open(NULL,               // Txn pointer\n                            filename.c_str(),   // Filename\n                            \"main\",             // Logical db name\n                            DB_BTREE,           // Database type\n                            DB_CREATE,          // Flags\n                            0);\n    if (ret > 0)\n    {\n        LogPrintf(\"Cannot create database file %s\\n\", filename);\n        return false;\n    }\n\n    DbTxn* ptxn = bitdb.TxnBegin();\n    for(CDBEnv::KeyValPair& row : salvagedData)\n    {\n        if (recoverKVcallback)\n        {\n            CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);\n            CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);\n            if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue))\n                continue;\n        }\n        Dbt datKey(&row.first[0], row.first.size());\n        Dbt datValue(&row.second[0], row.second.size());\n        int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);\n        if (ret2 > 0)\n            fSuccess = false;\n    }\n    ptxn->commit(0);\n    pdbCopy->close(0);\n\n    return fSuccess;\n}\n\nbool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)\n{\n    LogPrintf(\"Using BerkeleyDB version %s\\n\", DbEnv::version(0, 0, 0));\n    LogPrintf(\"Using wallet %s\\n\", walletFile);\n\n    // Wallet file must be a plain filename without a directory\n    if (walletFile != fs::basename(walletFile) + fs::extension(walletFile))\n    {\n        errorStr = strprintf(_(\"Wallet %s resides outside data directory %s\"), walletFile, dataDir.string());\n        return false;\n    }\n\n    if (!bitdb.Open(dataDir))\n    {\n        // try moving the database env out of the way\n        fs::path pathDatabase = dataDir / \"database\";\n        fs::path pathDatabaseBak = dataDir / strprintf(\"database.%d.bak\", GetTime());\n        try {\n            fs::rename(pathDatabase, pathDatabaseBak);\n            LogPrintf(\"Moved old %s to %s. Retrying.\\n\", pathDatabase.string(), pathDatabaseBak.string());\n        } catch (const fs::filesystem_error&) {\n            // failure is ok (well, not really, but it's not worse than what we started with)\n        }\n\n        // try again\n        if (!bitdb.Open(dataDir)) {\n            // if it still fails, it probably means we can't even create the database env\n            errorStr = strprintf(_(\"Error initializing wallet database environment %s!\"), GetDataDir());\n            return false;\n        }\n    }\n    return true;\n}\n\nbool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)\n{\n    if (fs::exists(dataDir / walletFile))\n    {\n        std::string backup_filename;\n        CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc, backup_filename);\n        if (r == CDBEnv::RECOVER_OK)\n        {\n            warningStr = strprintf(_(\"Warning: Wallet file corrupt, data salvaged!\"\n                                     \" Original %s saved as %s in %s; if\"\n                                     \" your balance or transactions are incorrect you should\"\n                                     \" restore from a backup.\"),\n                                   walletFile, backup_filename, dataDir);\n        }\n        if (r == CDBEnv::RECOVER_FAIL)\n        {\n            errorStr = strprintf(_(\"%s corrupt, salvage failed\"), walletFile);\n            return false;\n        }\n    }\n    // also return true if files does not exists\n    return true;\n}\n\n/* End of headers, beginning of key/value data */\nstatic const char *HEADER_END = \"HEADER=END\";\n/* End of key/value data */\nstatic const char *DATA_END = \"DATA=END\";\n\nbool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)\n{\n    LOCK(cs_db);\n    assert(mapFileUseCount.count(strFile) == 0);\n\n    u_int32_t flags = DB_SALVAGE;\n    if (fAggressive)\n        flags |= DB_AGGRESSIVE;\n\n    std::stringstream strDump;\n\n    Db db(dbenv, 0);\n    int result = db.verify(strFile.c_str(), NULL, &strDump, flags);\n    if (result == DB_VERIFY_BAD) {\n        LogPrintf(\"CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\\n\");\n        if (!fAggressive) {\n            LogPrintf(\"CDBEnv::Salvage: Rerun with aggressive mode to ignore errors and continue.\\n\");\n            return false;\n        }\n    }\n    if (result != 0 && result != DB_VERIFY_BAD) {\n        LogPrintf(\"CDBEnv::Salvage: Database salvage failed with result %d.\\n\", result);\n        return false;\n    }\n\n    // Format of bdb dump is ascii lines:\n    // header lines...\n    // HEADER=END\n    //  hexadecimal key\n    //  hexadecimal value\n    //  ... repeated\n    // DATA=END\n\n    std::string strLine;\n    while (!strDump.eof() && strLine != HEADER_END)\n        getline(strDump, strLine); // Skip past header\n\n    std::string keyHex, valueHex;\n    while (!strDump.eof() && keyHex != DATA_END) {\n        getline(strDump, keyHex);\n        if (keyHex != DATA_END) {\n            if (strDump.eof())\n                break;\n            getline(strDump, valueHex);\n            if (valueHex == DATA_END) {\n                LogPrintf(\"CDBEnv::Salvage: WARNING: Number of keys in data does not match number of values.\\n\");\n                break;\n            }\n            vResult.push_back(std::pair(ParseHex(keyHex), ParseHex(valueHex)));\n        }\n    }\n\n    if (keyHex != DATA_END) {\n        LogPrintf(\"CDBEnv::Salvage: WARNING: Unexpected end of file while reading salvage output.\\n\");\n        return false;\n    }\n\n    return (result == 0);\n}\n\n\nvoid CDBEnv::CheckpointLSN(const std::string& strFile)\n{\n    dbenv->txn_checkpoint(0, 0, 0);\n    if (fMockDb)\n        return;\n    dbenv->lsn_reset(strFile.c_str(), 0);\n}\n\n\nCDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL)\n{\n    fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));\n    fFlushOnClose = fFlushOnCloseIn;\n    env = dbw.env;\n    if (dbw.IsDummy()) {\n        return;\n    }\n    const std::string &strFilename = dbw.strFile;\n\n    bool fCreate = strchr(pszMode, 'c') != NULL;\n    unsigned int nFlags = DB_THREAD;\n    if (fCreate)\n        nFlags |= DB_CREATE;\n\n    {\n        LOCK(env->cs_db);\n        if (!env->Open(GetDataDir()))\n            throw std::runtime_error(\"CDB: Failed to open database environment.\");\n\n        strFile = strFilename;\n        ++env->mapFileUseCount[strFile];\n        pdb = env->mapDb[strFile];\n        if (pdb == NULL) {\n            int ret;\n            pdb = new Db(env->dbenv, 0);\n\n            bool fMockDb = env->IsMock();\n            if (fMockDb) {\n                DbMpoolFile* mpf = pdb->get_mpf();\n                ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);\n                if (ret != 0)\n                    throw std::runtime_error(strprintf(\"CDB: Failed to configure for no temp file backing for database %s\", strFile));\n            }\n\n            ret = pdb->open(NULL,                               // Txn pointer\n                            fMockDb ? NULL : strFile.c_str(),   // Filename\n                            fMockDb ? strFile.c_str() : \"main\", // Logical db name\n                            DB_BTREE,                           // Database type\n                            nFlags,                             // Flags\n                            0);\n\n            if (ret != 0) {\n                delete pdb;\n                pdb = NULL;\n                --env->mapFileUseCount[strFile];\n                strFile = \"\";\n                throw std::runtime_error(strprintf(\"CDB: Error %d, can't open database %s\", ret, strFilename));\n            }\n\n            if (fCreate && !Exists(std::string(\"version\"))) {\n                bool fTmp = fReadOnly;\n                fReadOnly = false;\n                WriteVersion(CLIENT_VERSION);\n                fReadOnly = fTmp;\n            }\n\n            env->mapDb[strFile] = pdb;\n        }\n    }\n}\n\nvoid CDB::Flush()\n{\n    if (activeTxn)\n        return;\n\n    // Flush database activity from memory pool to disk log\n    unsigned int nMinutes = 0;\n    if (fReadOnly)\n        nMinutes = 1;\n\n    env->dbenv->txn_checkpoint(nMinutes ? GetArg(\"-dblogsize\", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);\n}\n\nvoid CWalletDBWrapper::IncrementUpdateCounter()\n{\n    ++nUpdateCounter;\n}\n\nvoid CDB::Close()\n{\n    if (!pdb)\n        return;\n    if (activeTxn)\n        activeTxn->abort();\n    activeTxn = NULL;\n    pdb = NULL;\n\n    if (fFlushOnClose)\n        Flush();\n\n    {\n        LOCK(env->cs_db);\n        --env->mapFileUseCount[strFile];\n    }\n}\n\nvoid CDBEnv::CloseDb(const std::string& strFile)\n{\n    {\n        LOCK(cs_db);\n        if (mapDb[strFile] != NULL) {\n            // Close the database handle\n            Db* pdb = mapDb[strFile];\n            pdb->close(0);\n            delete pdb;\n            mapDb[strFile] = NULL;\n        }\n    }\n}\n\nbool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)\n{\n    if (dbw.IsDummy()) {\n        return true;\n    }\n    CDBEnv *env = dbw.env;\n    const std::string& strFile = dbw.strFile;\n    while (true) {\n        {\n            LOCK(env->cs_db);\n            if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) {\n                // Flush log data to the dat file\n                env->CloseDb(strFile);\n                env->CheckpointLSN(strFile);\n                env->mapFileUseCount.erase(strFile);\n\n                bool fSuccess = true;\n                LogPrintf(\"CDB::Rewrite: Rewriting %s...\\n\", strFile);\n                std::string strFileRes = strFile + \".rewrite\";\n                { // surround usage of db with extra {}\n                    CDB db(dbw, \"r\");\n                    Db* pdbCopy = new Db(env->dbenv, 0);\n\n                    int ret = pdbCopy->open(NULL,               // Txn pointer\n                                            strFileRes.c_str(), // Filename\n                                            \"main\",             // Logical db name\n                                            DB_BTREE,           // Database type\n                                            DB_CREATE,          // Flags\n                                            0);\n                    if (ret > 0) {\n                        LogPrintf(\"CDB::Rewrite: Can't create database file %s\\n\", strFileRes);\n                        fSuccess = false;\n                    }\n\n                    Dbc* pcursor = db.GetCursor();\n                    if (pcursor)\n                        while (fSuccess) {\n                            CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n                            CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n                            int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue);\n                            if (ret1 == DB_NOTFOUND) {\n                                pcursor->close();\n                                break;\n                            } else if (ret1 != 0) {\n                                pcursor->close();\n                                fSuccess = false;\n                                break;\n                            }\n                            if (pszSkip &&\n                                strncmp((const char*)ssKey.data(), pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)\n                                continue;\n                            if (strncmp((const char*)ssKey.data(), \"\\x07version\", 8) == 0) {\n                                // Update version:\n                                ssValue.clear();\n                                ssValue << CLIENT_VERSION;\n                            }\n                            Dbt datKey(ssKey.data(), ssKey.size());\n                            Dbt datValue(ssValue.data(), ssValue.size());\n                            int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);\n                            if (ret2 > 0)\n                                fSuccess = false;\n                        }\n                    if (fSuccess) {\n                        db.Close();\n                        env->CloseDb(strFile);\n                        if (pdbCopy->close(0))\n                            fSuccess = false;\n                        delete pdbCopy;\n                    }\n                }\n                if (fSuccess) {\n                    Db dbA(env->dbenv, 0);\n                    if (dbA.remove(strFile.c_str(), NULL, 0))\n                        fSuccess = false;\n                    Db dbB(env->dbenv, 0);\n                    if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))\n                        fSuccess = false;\n                }\n                if (!fSuccess)\n                    LogPrintf(\"CDB::Rewrite: Failed to rewrite database file %s\\n\", strFileRes);\n                return fSuccess;\n            }\n        }\n        MilliSleep(100);\n    }\n    return false;\n}\n\n\nvoid CDBEnv::Flush(bool fShutdown)\n{\n    int64_t nStart = GetTimeMillis();\n    // Flush log data to the actual data file on all files that are not in use\n    LogPrint(BCLog::DB, \"CDBEnv::Flush: Flush(%s)%s\\n\", fShutdown ? \"true\" : \"false\", fDbEnvInit ? \"\" : \" database not started\");\n    if (!fDbEnvInit)\n        return;\n    {\n        LOCK(cs_db);\n        std::map<std::string, int>::iterator mi = mapFileUseCount.begin();\n        while (mi != mapFileUseCount.end()) {\n            std::string strFile = (*mi).first;\n            int nRefCount = (*mi).second;\n            LogPrint(BCLog::DB, \"CDBEnv::Flush: Flushing %s (refcount = %d)...\\n\", strFile, nRefCount);\n            if (nRefCount == 0) {\n                // Move log data to the dat file\n                CloseDb(strFile);\n                LogPrint(BCLog::DB, \"CDBEnv::Flush: %s checkpoint\\n\", strFile);\n                dbenv->txn_checkpoint(0, 0, 0);\n                LogPrint(BCLog::DB, \"CDBEnv::Flush: %s detach\\n\", strFile);\n                if (!fMockDb)\n                    dbenv->lsn_reset(strFile.c_str(), 0);\n                LogPrint(BCLog::DB, \"CDBEnv::Flush: %s closed\\n\", strFile);\n                mapFileUseCount.erase(mi++);\n            } else\n                mi++;\n        }\n        LogPrint(BCLog::DB, \"CDBEnv::Flush: Flush(%s)%s took %15dms\\n\", fShutdown ? \"true\" : \"false\", fDbEnvInit ? \"\" : \" database not started\", GetTimeMillis() - nStart);\n        if (fShutdown) {\n            char** listp;\n            if (mapFileUseCount.empty()) {\n                dbenv->log_archive(&listp, DB_ARCH_REMOVE);\n                Close();\n                if (!fMockDb)\n                    fs::remove_all(fs::path(strPath) / \"database\");\n            }\n        }\n    }\n}\n\nbool CDB::PeriodicFlush(CWalletDBWrapper& dbw)\n{\n    if (dbw.IsDummy()) {\n        return true;\n    }\n    bool ret = false;\n    CDBEnv *env = dbw.env;\n    const std::string& strFile = dbw.strFile;\n    TRY_LOCK(bitdb.cs_db,lockDb);\n    if (lockDb)\n    {\n        // Don't do this if any databases are in use\n        int nRefCount = 0;\n        std::map<std::string, int>::iterator mit = env->mapFileUseCount.begin();\n        while (mit != env->mapFileUseCount.end())\n        {\n            nRefCount += (*mit).second;\n            mit++;\n        }\n\n        if (nRefCount == 0)\n        {\n            boost::this_thread::interruption_point();\n            std::map<std::string, int>::iterator mi = env->mapFileUseCount.find(strFile);\n            if (mi != env->mapFileUseCount.end())\n            {\n                LogPrint(BCLog::DB, \"Flushing %s\\n\", strFile);\n                int64_t nStart = GetTimeMillis();\n\n                // Flush wallet file so it's self contained\n                env->CloseDb(strFile);\n                env->CheckpointLSN(strFile);\n\n                env->mapFileUseCount.erase(mi++);\n                LogPrint(BCLog::DB, \"Flushed %s %dms\\n\", strFile, GetTimeMillis() - nStart);\n                ret = true;\n            }\n        }\n    }\n\n    return ret;\n}\n\nbool CWalletDBWrapper::Rewrite(const char* pszSkip)\n{\n    return CDB::Rewrite(*this, pszSkip);\n}\n\nbool CWalletDBWrapper::Backup(const std::string& strDest)\n{\n    if (IsDummy()) {\n        return false;\n    }\n    while (true)\n    {\n        {\n            LOCK(env->cs_db);\n            if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0)\n            {\n                // Flush log data to the dat file\n                env->CloseDb(strFile);\n                env->CheckpointLSN(strFile);\n                env->mapFileUseCount.erase(strFile);\n\n                // Copy wallet file\n                fs::path pathSrc = GetDataDir() / strFile;\n                fs::path pathDest(strDest);\n                if (fs::is_directory(pathDest))\n                    pathDest /= strFile;\n\n                try {\n                    if (fs::equivalent(pathSrc, pathDest)) {\n                        LogPrintf(\"cannot backup to wallet source file %s\\n\", pathDest.string());\n                        return false;\n                    }\n\n                    fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);\n                    LogPrintf(\"copied %s to %s\\n\", strFile, pathDest.string());\n                    return true;\n                } catch (const fs::filesystem_error& e) {\n                    LogPrintf(\"error copying %s to %s - %s\\n\", strFile, pathDest.string(), e.what());\n                    return false;\n                }\n            }\n        }\n        MilliSleep(100);\n    }\n    return false;\n}\n\nvoid CWalletDBWrapper::Flush(bool shutdown)\n{\n    if (!IsDummy()) {\n        env->Flush(shutdown);\n    }\n}\n"
  },
  {
    "path": "src/wallet/db.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_DB_H\n#define WALLET_DB_H\n\n#include \"clientversion.h\"\n#include \"fs.h\"\n#include \"serialize.h\"\n#include \"streams.h\"\n#include \"sync.h\"\n#include \"version.h\"\n#include <span.h>\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include <db_cxx.h>\n\nstatic const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;\nstatic const bool DEFAULT_WALLET_PRIVDB = true;\n\nclass CDBEnv\n{\nprivate:\n    bool fDbEnvInit;\n    bool fMockDb;\npublic:\n    // Don't change into fs::path, as that can result in\n    // shutdown problems/crashes caused by a static initialized internal pointer.\n    std::string strPath;\n\n    void EnvShutdown();\n\n\n    mutable RecursiveMutex cs_db;\n    DbEnv *dbenv;\n    std::map<std::string, int> mapFileUseCount;\n    std::map<std::string, Db*> mapDb;\n\n    CDBEnv();\n    ~CDBEnv();\n    void Reset();\n\n    void MakeMock();\n    bool IsMock() { return fMockDb; }\n\n    /**\n     * Verify that database file strFile is OK. If it is not,\n     * call the callback to try to recover.\n     * This must be called BEFORE strFile is opened.\n     * Returns true if strFile is OK.\n     */\n    enum VerifyResult { VERIFY_OK,\n                        RECOVER_OK,\n                        RECOVER_FAIL };\n    typedef bool (*recoverFunc_type)(const std::string& strFile, std::string& out_backup_filename);\n    VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);\n    /**\n     * Salvage data from a file that Verify says is bad.\n     * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).\n     * Appends binary key/value pairs to vResult, returns true if successful.\n     * NOTE: reads the entire database into memory, so cannot be used\n     * for huge databases.\n     */\n    typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;\n    bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);\n\n    bool Open(const fs::path& path);\n    void Close();\n    void Flush(bool fShutdown);\n    void CheckpointLSN(const std::string& strFile);\n\n    void CloseDb(const std::string& strFile);\n\n    DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)\n    {\n        DbTxn* ptxn = NULL;\n        int ret = dbenv->txn_begin(NULL, &ptxn, flags);\n        if (!ptxn || ret != 0)\n            return NULL;\n        return ptxn;\n    }\n};\n\nextern CDBEnv bitdb;\n\n/** An instance of this class represents one database.\n * For BerkeleyDB this is just a (env, strFile) tuple.\n **/\nclass CWalletDBWrapper\n{\n    friend class CDB;\npublic:\n    /** Create dummy DB handle */\n    CWalletDBWrapper() : nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)\n    {\n    }\n\n    /** Create DB handle to real database */\n    CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :\n        nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)\n    {\n    }\n\n    /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero\n     */\n    bool Rewrite(const char* pszSkip=nullptr);\n\n    /** Back up the entire database to a file.\n     */\n    bool Backup(const std::string& strDest);\n\n    /** Get a name for this database, for debugging etc.\n     */\n    std::string GetName() const { return strFile; }\n\n    /** Make sure all changes are flushed to disk.\n     */\n    void Flush(bool shutdown);\n\n    void IncrementUpdateCounter();\n\n    std::atomic<unsigned int> nUpdateCounter;\n    unsigned int nLastSeen;\n    unsigned int nLastFlushed;\n    int64_t nLastWalletUpdate;\n\nprivate:\n    /** BerkeleyDB specific */\n    CDBEnv *env;\n    std::string strFile;\n\n    /** Return whether this database handle is a dummy for testing.\n     * Only to be used at a low level, application should ideally not care\n     * about this.\n     */\n    bool IsDummy() { return env == nullptr; }\n};\n\n\n/** RAII class that provides access to a Berkeley database */\nclass CDB\n{\nprotected:\n    Db* pdb;\n    std::string strFile;\n    DbTxn* activeTxn;\n    bool fReadOnly;\n    bool fFlushOnClose;\n    CDBEnv *env;\n\npublic:\n    explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = \"r+\", bool fFlushOnCloseIn=true);\n    ~CDB() { Close(); }\n\n    void Flush();\n    void Close();\n    static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);\n\n    /* flush the wallet passively (TRY_LOCK)\n       ideal to be called periodically */\n    static bool PeriodicFlush(CWalletDBWrapper& dbw);\n    /* verifies the database environment */\n    static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);\n    /* verifies the database file */\n    static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);\n\nprivate:\n    CDB(const CDB&);\n    void operator=(const CDB&);\n\npublic:\n    template <typename K, typename T>\n    bool Read(const K& key, T& value)\n    {\n        if (!pdb)\n            return false;\n\n        // Key\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(1000);\n        ssKey << key;\n        Dbt datKey(ssKey.data(), ssKey.size());\n\n        // Read\n        Dbt datValue;\n        datValue.set_flags(DB_DBT_MALLOC);\n        int ret = pdb->get(activeTxn, &datKey, &datValue, 0);\n        memory_cleanse(datKey.get_data(), datKey.get_size());\n        bool success = false;\n        if (datValue.get_data() != NULL) {\n            // Unserialize value\n            try {\n                CDataStream ssValue(AsBytes(Span((char*)datValue.get_data(), datValue.get_size())), SER_DISK, CLIENT_VERSION);\n                ssValue >> value;\n                success = true;\n            } catch (const std::exception&) {\n                // In this case success remains 'false'\n            }\n\n            // Clear and free memory\n            memory_cleanse(datValue.get_data(), datValue.get_size());\n            free(datValue.get_data());\n        }\n        return ret == 0 && success;\n    }\n\n    template <typename K, typename T>\n    bool Write(const K& key, const T& value, bool fOverwrite = true)\n    {\n        if (!pdb)\n            return true;\n        if (fReadOnly)\n            assert(!\"Write called on database in read-only mode\");\n\n        // Key\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(1000);\n        ssKey << key;\n        Dbt datKey(ssKey.data(), ssKey.size());\n\n        // Value\n        CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n        ssValue.reserve(10000);\n        ssValue << value;\n        Dbt datValue(ssValue.data(), ssValue.size());\n\n        // Write\n        int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));\n\n        // Clear memory in case it was a private key\n        memory_cleanse(datKey.get_data(), datKey.get_size());\n        memory_cleanse(datValue.get_data(), datValue.get_size());\n        return (ret == 0);\n    }\n\n    template <typename K>\n    bool Erase(const K& key)\n    {\n        if (!pdb)\n            return false;\n        if (fReadOnly)\n            assert(!\"Erase called on database in read-only mode\");\n\n        // Key\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(1000);\n        ssKey << key;\n        Dbt datKey(ssKey.data(), ssKey.size());\n\n        // Erase\n        int ret = pdb->del(activeTxn, &datKey, 0);\n\n        // Clear memory\n        memory_cleanse(datKey.get_data(), datKey.get_size());\n        return (ret == 0 || ret == DB_NOTFOUND);\n    }\n\n    template <typename K>\n    bool Exists(const K& key)\n    {\n        if (!pdb)\n            return false;\n\n        // Key\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        ssKey.reserve(1000);\n        ssKey << key;\n        Dbt datKey(ssKey.data(), ssKey.size());\n\n        // Exists\n        int ret = pdb->exists(activeTxn, &datKey, 0);\n\n        // Clear memory\n        memory_cleanse(datKey.get_data(), datKey.get_size());\n        return (ret == 0);\n    }\n\n    Dbc* GetCursor()\n    {\n        if (!pdb)\n            return NULL;\n        Dbc* pcursor = NULL;\n        int ret = pdb->cursor(NULL, &pcursor, 0);\n        if (ret != 0)\n            return NULL;\n        return pcursor;\n    }\n\n    int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)\n    {\n        // Read at cursor\n        Dbt datKey;\n        unsigned int fFlags = DB_NEXT;\n        if (setRange) {\n            datKey.set_data(ssKey.data());\n            datKey.set_size(ssKey.size());\n            fFlags = DB_SET_RANGE;\n        }\n        Dbt datValue;\n        datKey.set_flags(DB_DBT_MALLOC);\n        datValue.set_flags(DB_DBT_MALLOC);\n        int ret = pcursor->get(&datKey, &datValue, fFlags);\n        if (ret != 0)\n            return ret;\n        else if (datKey.get_data() == NULL || datValue.get_data() == NULL)\n            return 99999;\n\n        // Convert to streams\n        ssKey.SetType(SER_DISK);\n        ssKey.clear();\n        ssKey.write(AsWritableBytes(Span{(char*)datKey.get_data(), datKey.get_size()}));\n        ssValue.SetType(SER_DISK);\n        ssValue.clear();\n        ssValue.write(AsWritableBytes(Span{(char*)datValue.get_data(), datValue.get_size()}));\n\n        // Clear and free memory\n        memory_cleanse(datKey.get_data(), datKey.get_size());\n        memory_cleanse(datValue.get_data(), datValue.get_size());\n        free(datKey.get_data());\n        free(datValue.get_data());\n        return 0;\n    }\n\npublic:\n    bool TxnBegin()\n    {\n        if (!pdb || activeTxn)\n            return false;\n        DbTxn* ptxn = bitdb.TxnBegin();\n        if (!ptxn)\n            return false;\n        activeTxn = ptxn;\n        return true;\n    }\n\n    bool TxnCommit()\n    {\n        if (!pdb || !activeTxn)\n            return false;\n        int ret = activeTxn->commit(0);\n        activeTxn = NULL;\n        return (ret == 0);\n    }\n\n    bool TxnAbort()\n    {\n        if (!pdb || !activeTxn)\n            return false;\n        int ret = activeTxn->abort();\n        activeTxn = NULL;\n        return (ret == 0);\n    }\n\n    bool ReadVersion(int& nVersion)\n    {\n        nVersion = 0;\n        return Read(std::string(\"version\"), nVersion);\n    }\n\n    bool WriteVersion(int nVersion)\n    {\n        return Write(std::string(\"version\"), nVersion);\n    }\n\n    bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = NULL);\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/extwallet.cpp",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"policy/fees.h\"\n#include \"alert.h\"\n#include \"appname.h\"\n#include \"account.h\"\n#include \"script/ismine.h\"\n\n#define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX\n#include <boost/uuid/nil_generator.hpp>\n#include <boost/algorithm/string/predicate.hpp> // for starts_with() and end_swith()\n#include <boost/algorithm/string.hpp> // for split()\n#include <wallet/mnemonic.h>\n#include \"util.h\"\n#include \"util/thread.h\"\n#include <validation/validation.h>\n\nbool fShowChildAccountsSeperately = false;\n\n// TODO: consider moving shadow thread functionality into wallet class to reduce usage of global pactiveWallet\n// and possibly make some members private.\n\nstatic void AllocateShadowAccountsIfNeeded(int nAccountPoolTargetSize, int nAccountPoolTargetSizeWitness, int nAccountPoolTargetSizeMobi, int nAccountPoolTargetSizeMining, int& nNumNewAccountsAllocated, bool& tryLockWallet)\n{\n    // Special SPV optimisation\n    // Prevent extra accounts from generating until after we have found the first transaction\n    // This keeps our filter ranges smaller and speeds up sync\n    if (fSPV && IsInitialBlockDownload() && pactiveWallet->mapAccounts.size() == 1 && pactiveWallet->wtxOrdered.size() == 0)\n    {\n        tryLockWallet = false;\n        return;\n    }\n    \n    for (const auto& seedIter : pactiveWallet->mapSeeds)\n    {\n        //fixme: (FUT) (ACCOUNTS) (Support other seed types here)\n        if (seedIter.second->m_type != CHDSeed::CHDSeed::BIP44 && seedIter.second->m_type != CHDSeed::CHDSeed::BIP44External && seedIter.second->m_type != CHDSeed::CHDSeed::BIP44NoHardening)\n            continue;\n\n        for (const auto shadowSubType : { AccountType::Desktop, AccountType::Mobi, AccountType::PoW2Witness, AccountType::MiningAccount })\n        {\n            int nFinalAccountPoolTargetSize = nAccountPoolTargetSize;\n            switch (shadowSubType)\n            {\n                case AccountType::MiningAccount:\n                    nFinalAccountPoolTargetSize = nAccountPoolTargetSizeMining;\n                    break;\n                case AccountType::PoW2Witness:\n                    nFinalAccountPoolTargetSize = nAccountPoolTargetSizeWitness;\n                    break;\n                case AccountType::Desktop:\n                case AccountType::Mobi:\n                case AccountType::WitnessOnlyWitnessAccount:\n                case AccountType::ImportedPrivateKeyAccount:\n                    nFinalAccountPoolTargetSize = nAccountPoolTargetSizeMobi;\n                    break;\n            }\n            int numShadow = 0;\n            {\n                for (const auto& accountPair : pactiveWallet->mapAccounts)\n                {\n                    if (accountPair.second->IsHD() && ((CAccountHD*)accountPair.second)->getSeedUUID() == seedIter.second->getUUID())\n                    {\n                        if (accountPair.second->m_Type == shadowSubType)\n                        {\n                            if (accountPair.second->m_State == AccountState::Shadow)\n                            {\n                                ++numShadow;\n                            }\n                        }\n                    }\n                }\n            }\n            if (numShadow < nFinalAccountPoolTargetSize)\n            {\n                CWalletDB db(*pactiveWallet->dbw);\n                while (numShadow < nFinalAccountPoolTargetSize)\n                {\n                    // New shadow account\n                    CAccountHD* newShadow = seedIter.second->GenerateAccount(shadowSubType, &db);\n\n                    if (newShadow == NULL)\n                    {\n                        // Only explicitely ask for an unlock if really low on shadow accounts\n                        if ((shadowSubType != AccountType::MiningAccount) && (numShadow < std::max(nFinalAccountPoolTargetSize, 2)))\n                        {\n                            tryLockWallet = false;\n                        }\n                        return;\n                    }\n\n                    ++numShadow;\n                    ++nNumNewAccountsAllocated;\n\n                    newShadow->m_State = AccountState::Shadow;\n\n                    // Write new account\n                    pactiveWallet->addAccount(newShadow, \"Shadow_\"+GetAccountTypeString(shadowSubType));\n\n                    if (nNumNewAccountsAllocated > 4)\n                        return;\n                }\n            }\n        }\n    }\n}\n\nstatic void ThreadShadowPoolManager()\n{\n    static bool promptOnceForAccountGenerationUnlock = true;\n    static bool promptOnceForAddressGenerationUnlock = true;\n    int depth = 1;\n    int nAccountPoolTargetSize = GetArg(\"-accountpool\", 10);\n    int nAccountPoolTargetSizeWitness = GetArg(\"-accountpool\", 2);\n    if (IsArgSet(\"-accountpoolwitness\"))\n    {\n        nAccountPoolTargetSizeWitness = GetArg(\"-accountpoolwitness\", nAccountPoolTargetSizeWitness);\n    }\n    int nAccountPoolTargetSizeMobi = nAccountPoolTargetSize;\n    if (IsArgSet(\"-accountpoolmobi\"))\n    {\n        nAccountPoolTargetSizeMobi = GetArg(\"-accountpoolmobi\", nAccountPoolTargetSizeMobi);\n    }\n    int nAccountPoolTargetSizeMining = 1;\n    if (IsArgSet(\"-accountpoolmining\"))\n    {\n        nAccountPoolTargetSizeMining = GetArg(\"-accountpoolmining\", nAccountPoolTargetSizeMining);\n    }\n    \n    int nKeyPoolTargetDepth = GetArg(\"-keypool\", DEFAULT_ACCOUNT_KEYPOOL_SIZE);\n    while (true)\n    {\n        long milliSleep = 500;\n        bool tryLockWallet = true;\n\n        if (pactiveWallet)\n        {\n            LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n            int nNumNewAccountsAllocated = 0;\n\n            // First we expand the amount of shadow accounts until we have the desired amount.\n            AllocateShadowAccountsIfNeeded(nAccountPoolTargetSize, nAccountPoolTargetSizeWitness, nAccountPoolTargetSizeMobi, nAccountPoolTargetSizeMining, nNumNewAccountsAllocated, tryLockWallet);\n            if (nNumNewAccountsAllocated > 0)\n            {\n                // Reset the depth to 1, so that our new accounts get their first keys as a priority instead of expanding deeper the other accounts.\n                depth = 1;\n                milliSleep = 100;\n                continue;\n            }\n            else if (!tryLockWallet)\n            {\n                // If we reach here we need to unlock to generate more background shadow accounts.\n                // So try to initiate an unlock session\n                tryLockWallet = false;\n                if (promptOnceForAccountGenerationUnlock)\n                {\n                    promptOnceForAccountGenerationUnlock = false;\n\n                    // If the user cancels then we don't prompt him for this again in this program run.\n                    // If user performs the unlock then we leave prompting enabled in case we reach this situation again.\n                    //fixme: (FUT) (ACCOUNTS) - Should this maybe be a timer to only prompt once a day or something for users who keep the program open?\n                    // Might also want a \"don't ask me this again\" checkbox on prompt etc.\n                    // Discuss with UI team and reconsider how to handle this.\n\n                    pactiveWallet->BeginUnlocked(_(\"Wallet unlock required for account generation\"), [&]() {\n                        promptOnceForAccountGenerationUnlock = true;\n                        // transfer ownership of unlock session to shadow thread\n                        LOCK(pactiveWallet->cs_wallet);\n                        pactiveWallet->nUnlockedSessionsOwnedByShadow++;\n                    });\n                    milliSleep = 1;\n                }\n            }\n\n            // Once we have allocated all the shadow accounts (or if wallet is locked and unable to allocate shadow accounts) we start to allocate keys for the accounts.\n            // Allocate up to 'depth' keys for all accounts, however only do numToAllocatePerRound allocations at a time before sleeping so that we don't hog the entire CPU.\n            int targetPoolDepth = nKeyPoolTargetDepth;\n            int numToAllocatePerRound = 5;\n            if (targetPoolDepth > 40)\n                numToAllocatePerRound = 20;\n            int numAllocated = pactiveWallet->TopUpKeyPool(depth, numToAllocatePerRound);\n            // Increase the depth for next round of allocation.\n            if (numAllocated == 0 && depth < targetPoolDepth)\n            {\n                ++depth;\n                // If we didn't allocate any then we want to try again almost immediately and not have a long sleep.\n                milliSleep = 1;\n            }\n            else if (numAllocated >= 0 || depth < targetPoolDepth)\n            {\n                // Otherwise we sleep for increasingly longer depending on how deep into the allocation we are, the deeper we are the less urgent it becomes to allocate more. \n                //fixme: (FUT) (ACCOUNTS) Look some more into these times, they are a bit arbitrary.\n                // If the user has set an especially large depth then we want to try again almost immediately and not have a long sleep.\n                if (targetPoolDepth > 40)\n                    milliSleep = 1;\n                else if (depth < 10) \n                    milliSleep = 80;\n                else if (depth < 20)\n                    milliSleep = 100;\n                else\n                    milliSleep = 300;\n            }\n            else\n            {\n                // If we reach here we have a non HD account that require wallet unlock to allocate keys.\n                // So try to initiate an unlock session\n                milliSleep = 500;\n                tryLockWallet = false;\n                if (promptOnceForAddressGenerationUnlock)\n                {\n                    promptOnceForAddressGenerationUnlock = false;\n                    // If the user cancels then we don't prompt him for this again in this program run.\n                    // If user performs the unlock then we leave prompting enabled in case we reach this situation again.\n                    //fixme: (FUT) (ACCOUNTS) - Should this maybe be a timer to only prompt once a day or something for users who keep the program open?\n                    // Might also want a \"don't ask me this again\" checkbox on prompt etc.\n                    // Discuss with UI team and reconsider how to handle this.\n\n                    pactiveWallet->BeginUnlocked(_(\"Wallet unlock required for address generation\"), [&]() {\n                        promptOnceForAddressGenerationUnlock = true;\n                        // transfer ownership of unlock session to shadow thread\n                        LOCK(pactiveWallet->cs_wallet);\n                        pactiveWallet->nUnlockedSessionsOwnedByShadow++;\n                    });\n                }\n            }\n\n            // If we no longer have a need for an unlocked wallet (ie. all work done) end all unlock sessions that we own.\n            if (tryLockWallet)\n            {\n                for (unsigned int i = 0; i < pactiveWallet->nUnlockedSessionsOwnedByShadow; i++) {\n                    pactiveWallet->EndUnlocked();\n                }\n                pactiveWallet->nUnlockedSessionsOwnedByShadow = 0;\n            }\n        }\n\n        boost::this_thread::interruption_point();\n        MilliSleep(milliSleep);\n    }\n}\n\nvoid StartShadowPoolManagerThread(boost::thread_group& threadGroup)\n{\n    threadGroup.create_thread(boost::bind(&util::TraceThread, \"shadowpoolmanager\", &ThreadShadowPoolManager));\n}\n\nstd::string accountNameForAddress(const CWallet &wallet, const CTxDestination& dest)\n{\n    LOCK(wallet.cs_wallet);\n    std::string accountNameForAddress;\n\n    isminetype ret = isminetype::ISMINE_NO;\n    for (const auto& accountItem : wallet.mapAccounts)\n    {\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            isminetype temp = ( keyChain == KEYCHAIN_EXTERNAL ? IsMine(accountItem.second->externalKeyStore, dest) : IsMine(accountItem.second->internalKeyStore, dest) );\n            if (temp > ret)\n            {\n                ret = temp;\n                accountNameForAddress = accountItem.second->getLabel();\n            }\n        }\n    }\n    if (ret < isminetype::ISMINE_WATCH_ONLY)\n        return \"\";\n    return accountNameForAddress;\n}\n\nisminetype IsMine(const CWallet &wallet, const CTxDestination& dest)\n{\n    LOCK(wallet.cs_wallet);\n\n    isminetype ret = isminetype::ISMINE_NO;\n    for (const auto& accountItem : wallet.mapAccounts)\n    {\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            isminetype temp = ( keyChain == KEYCHAIN_EXTERNAL ? IsMine(accountItem.second->externalKeyStore, dest) : IsMine(accountItem.second->internalKeyStore, dest) );\n            if (temp > ret)\n                ret = temp;\n        }\n    }\n    return ret;\n}\n\nisminetype IsMine(const CWallet &wallet, const CTxOut& out)\n{\n    LOCK(wallet.cs_wallet);\n\n    isminetype ret = isminetype::ISMINE_NO;\n    for (const auto& [accountUUID, account] : wallet.mapAccounts)\n    {\n        (unused)accountUUID;\n        isminetype temp = IsMine(*account, out);\n        if (temp > ret)\n        {\n            ret = temp;\n        }\n        // No need to keep going through the remaining accounts at this point.\n        if (ret >= ISMINE_SPENDABLE)\n            return ret;\n    }\n    return ret;\n}\n\nisminetype IsMineWitness(const CWallet &wallet, const CTxOut& out)\n{\n    LOCK(wallet.cs_wallet);\n\n    isminetype ret = isminetype::ISMINE_NO;\n    for (const auto& [accountUUID, account] : wallet.mapAccounts)\n    {\n        if (account->IsPoW2Witness() && account->m_State == AccountState::Normal)\n        {\n            (unused)accountUUID;\n            isminetype temp = IsMine(*account, out);\n            if (temp > ret)\n            {\n                ret = temp;\n            }\n            // No need to keep going through the remaining accounts at this point.\n            if (ret >= ISMINE_SPENDABLE)\n                return ret;\n        }\n    }\n    return ret;\n}\n\nbool IsMine(const CKeyStore* forAccount, const CWalletTx& tx)\n{\n    for (const auto& txout : tx.tx->vout)\n    {\n        isminetype ret = IsMine(*forAccount, txout);\n        // No need to keep going through the remaining outputs at this point.\n        if (ret > isminetype::ISMINE_NO)\n            return true;\n        //NB! We don't insert into the \"IsNotMineCache\" here as it is for the whole wallet\n        //This output could still belong to a different account...\n    }\n    return false;\n}\n\nisminetype CExtWallet::IsMine(const CKeyStore &keystore, const CTxIn& txin) const\n{\n    {\n        LOCK(cs_wallet);\n        uint256 txHash;\n        if (GetTxHash(txin.GetPrevOut(), txHash))\n        {\n            const CWalletTx* prev = pactiveWallet->GetWalletTx(txHash);\n            if (prev && prev->tx->vout.size() != 0)\n            {\n                if (txin.GetPrevOut().n < prev->tx->vout.size())\n                    return ::IsMine(keystore, prev->tx->vout[txin.GetPrevOut().n]);\n            }\n        }\n    }\n    return ISMINE_NO;\n}\n\nvoid CExtWallet::MarkKeyUsed(CKeyID keyID, uint64_t usageTime)\n{\n    {\n        // Remove from key pool\n        CWalletDB walletdb(*dbw);\n        //NB! Must call ErasePool here even if HasPool is false - as ErasePool has other side effects.\n        walletdb.ErasePool(static_cast<CWallet*>(this), keyID);\n    }\n\n    //Update accounts if needed (creation time - shadow accounts etc.)\n    {\n        LOCK(cs_wallet);\n        for (const auto& accountIter : mapAccounts)\n        {\n            auto& forAccount = accountIter.second;\n            if (forAccount->HaveKey(keyID))\n            {\n                if (usageTime > 0)\n                {\n                    CWalletDB walletdb(*dbw);\n                    forAccount->possiblyUpdateEarliestTime(usageTime, &walletdb);\n                }\n\n                // We only do this the first time MarkKeyUsed is called - otherwise we have the following problem\n                // 1) User empties account. 2) User deletes account 3) At a later point MarkKeyUsed is called subsequent times (new blocks) 4) The account user just deleted is now recovered.\n\n                //fixme: (FUT) (ACCOUNTS) This is still not 100% right, if the user does the following there can still be issues:\n                //1) Send funds from account\n                //2) Immediately close wallet\n                //3) Reopen wallet, as the new blocks are processed this code will be called and the just deleted account will be restored.\n                //We will need a better way to detect this...\n\n                //fixme: (FUT) (ACCOUNTS)\n                //Another edge bug here\n                //1) User sends/receives from address\n                //2) User deleted account\n                //3) User receives on same address again\n                //Account will not reappear - NB! This happens IFF there is no wallet restart anywhere in this process, and the user can always rescan still so it's not a disaster.\n                static std::set<CKeyID> keyUsedSet;\n                if (keyUsedSet.find(keyID) == keyUsedSet.end())\n                {\n                    keyUsedSet.insert(keyID);\n\n                    if (forAccount->IsMiningAccount())\n                    {\n                        CKeyID highestKeyID;\n                        //fixme: (HIGH) (KEYPOOL) All HD accounts should use a similar (not identical) method to this\n                        //To obtain a proper key gap instead of what we have now\n                        //Probably we should be storing the 'highest used key' somewhere in this function\n                        //And then topupkeypool should utilise it for allocation (instead of the allocation trick we use here)\n                        if (dynamic_cast<CAccountHD*>(forAccount)->GetAccountKeyIDWithHighestIndex(highestKeyID, KEYCHAIN_EXTERNAL) && (highestKeyID == keyID))\n                        {\n                            // Assign 1 extra key, because mining accounts never discard keys the keypool size always grows when new keys are allocated\n                            // Ideally most mining accounts will only have 1 key, but due to a previous bug some have more\n                            LOCK(forAccount->cs_keypool);\n                            uint64_t topupSize = forAccount->GetKeyPoolSize(KEYCHAIN_EXTERNAL)+1;\n                            static_cast<CWallet*>(this)->TopUpKeyPool(topupSize, 10, forAccount, topupSize);\n                        }\n                    }\n\n                    if (forAccount->m_State != AccountState::Normal && forAccount->m_State != AccountState::ShadowChild)\n                    {\n                        forAccount->m_State = AccountState::Normal;\n                        std::string name = forAccount->getLabel();\n\n                        //fixme: (FUT) (ACCOUNTS) remove this in name delete/restore labelling for something less error prone. (translations would break this for instance)\n                        //We should just set a restored attribute on the account or something.\n                        if (name.find(_(\"[Deleted]\")) != std::string::npos)\n                        {\n                            name = name.replace(name.find(_(\"[Deleted]\")), _(\"[Deleted]\").length(), _(\"[Restored]\"));\n                        }\n                        else\n                        {\n                            name = _(\"Restored\");\n                            switch(forAccount->m_Type)\n                            {\n                                case AccountType::MiningAccount:\n                                    name += \" mining\";\n                                    break;\n                                case AccountType::PoW2Witness:\n                                    name += \" witness\";\n                                    break;\n                                case AccountType::Mobi:\n                                    name += \" mobile\";\n                                    break;\n                                case AccountType::Desktop:\n                                case AccountType::WitnessOnlyWitnessAccount:\n                                case AccountType::ImportedPrivateKeyAccount:\n                                    break;\n                            }\n                        }\n                        // Add the account, don't let it steal focus (this can create issues on e.g. mobile wallets where the UI/Unity lib expects a single account to always be the active one)\n                        addAccount(forAccount, name, false);\n\n                        //fixme: (FUT) (ACCOUNTS) Shadow accounts during rescan...\n                    }\n\n                    if (forAccount->IsHD() && forAccount->IsPoW2Witness())\n                    {\n                        //This is here for the sake of restoring wallets from recovery phrase only, in the normal case this has already been done by the funding code...\n                        //fixme: (FUT) (ACCOUNTS) Improve this, there are two things that need improving:\n                        //1) When restoring from phrase but also encrypting and locking - it won't be able to add the key here.\n                        //We try to work around this by using an unlock callback, but if the user refuses to unlock then there might be issues.\n                        //2) This will indescriminately add -all- used change keys in a witness account; even if used for normal transactions (which shouldn't be done, but still it would be preferable to avoid this)\n                        //Note as witness-only accounts are not HD this is not an issue for witness-only accounts.\n                        if (forAccount->getLabel().find(_(\"[Restored]\")) != std::string::npos)\n                        {\n                            if (forAccount->HaveKeyInternal(keyID))\n                            {\n                                std::function<void (void)> witnessKeyCallback = [=]()\n                                {\n                                    CKey privWitnessKey;\n                                    if (!forAccount->GetKey(keyID, privWitnessKey))\n                                    {\n                                        //fixme: (FUT) localise\n                                        std::string strErrorMessage = \"Failed to mark witnessing key for encrypted usage\";\n                                        LogPrintf(strErrorMessage.c_str());\n                                        CAlert::Notify(strErrorMessage, true, true);\n                                    }\n                                    if (!static_cast<CWallet*>(this)->AddKeyPubKey(privWitnessKey, privWitnessKey.GetPubKey(), *forAccount, KEYCHAIN_WITNESS))\n                                    {\n                                        //fixme: (FUT) localise\n                                        std::string strErrorMessage = \"Failed to mark witnessing key for encrypted usage\";\n                                        LogPrintf(strErrorMessage.c_str());\n                                        CAlert::Notify(strErrorMessage, true, true);\n                                    }\n                                };\n                                if (forAccount->IsLocked())\n                                {\n                                    //Last ditch effort to try work around 1.\n                                    uiInterface.RequestUnlockWithCallback(pactiveWallet, _(\"Wallet unlock required for witness key\"), witnessKeyCallback);\n                                    continue;\n                                }\n                                else\n                                {\n                                    witnessKeyCallback();\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    //Only assign the bare minimum keys - let the background thread do the rest.\n    #ifdef DJINNI_NODEJS\n    if (fSPV)\n    {\n        static_cast<CWallet*>(this)->TopUpKeyPool(10);\n    }\n    else\n    #endif\n    {\n        static_cast<CWallet*>(this)->TopUpKeyPool(1);\n    }\n}\n\nvoid CExtWallet::changeAccountName(CAccount* account, const std::string& newName, bool notify)\n{\n    // Force names to be unique\n    std::string finalNewName = newName;\n    std::string oldName = account->getLabel();\n    {\n        LOCK(cs_wallet);\n\n        CWalletDB db(*dbw);\n\n        int nPrefix = 1;\n        bool possibleDuplicate = true;\n        while(possibleDuplicate)\n        {\n            possibleDuplicate = false;\n            for (const auto& labelIter : mapAccountLabels)\n            {\n                if (labelIter.second == finalNewName)\n                {\n                    finalNewName = newName + strprintf(\"_%d\", nPrefix++);\n                    possibleDuplicate = true;\n                    continue;\n                }\n            }\n        }\n\n        account->setLabel(finalNewName, &db);\n        mapAccountLabels[account->getUUID()] = finalNewName;\n    }\n\n    if (notify && oldName != finalNewName)\n        NotifyAccountNameChanged(static_cast<CWallet*>(this), account);\n}\n\nvoid CExtWallet::deleteAccount(CWalletDB& db, CAccount* account, bool shouldPurge)\n{\n    LogPrintf(\"CExtWallet::deleteAccount\");\n    //fixme: (FUT) (ACCOUNTS) - If we are trying to delete the last remaining account we should return false\n    //As this may leave the wallet in an invalid state.\n    //Alternatively we must make sure that the wallet can handle having 0 accounts in it.\n    if (shouldPurge)\n    {\n        LogPrintf(\"CExtWallet::deleteAccount - purge account\");\n\n        // We should never be purging an HD account unless we have also purged the seed that it belongs too (or it has no seed)\n        // It makes no sense to purge an account while retaining the seed as it can always be regenerated from the seed (so purging is still not permanent) and it can only lead to difficult to understand issues.\n        if (account->IsHD() && (mapSeeds.find(dynamic_cast<CAccountHD*>(account)->getSeedUUID()) != mapSeeds.end()))\n            assert(0);\n\n        LOCK2(cs_main, cs_wallet);\n\n        LogPrintf(\"CExtWallet::deleteAccount - wipe account from disk\");\n        if (!db.EraseAccount(getUUIDAsString(account->getUUID()), account))\n        {\n            throw std::runtime_error(\"erasing account failed\");\n        }\n        if (!db.EraseAccountLabel(getUUIDAsString(account->getUUID())))\n        {\n            throw std::runtime_error(\"erasing account failed\");\n        }\n        if (!db.EraseAccountCompoundingSettings(getUUIDAsString(account->getUUID())))\n        {\n            throw std::runtime_error(\"erasing account failed\");\n        }\n        if (!db.EraseAccountNonCompoundWitnessEarningsScript(getUUIDAsString(account->getUUID())))\n        {\n            throw std::runtime_error(\"erasing account failed\");\n        }\n\n        // Wipe all the keys\n        LogPrintf(\"CExtWallet::deleteAccount - wipe keys from disk\");\n        {\n            std::set<CKeyID> setAddress;\n            account->GetKeys(setAddress);\n\n            for (const auto& keyID : setAddress)\n            {\n                CPubKey pubKey;\n                if (!GetPubKey(keyID, pubKey))\n                {\n                    LogPrintf(\"deleteAccount: Failed to get pubkey\\n\");\n                }\n                else\n                {\n                    if (IsCrypted())\n                    {\n                        db.EraseEncryptedKey(pubKey);\n                    }\n                    db.EraseKey(pubKey);\n                }\n            }\n        }\n\n        LogPrintf(\"CExtWallet::deleteAccount - wipe keypool from disk\");\n        // Wipe our keypool\n        {\n            bool forceErase = true;\n            for(int64_t nIndex : account->setKeyPoolInternal)\n                db.ErasePool(pactiveWallet, nIndex, forceErase);\n            for(int64_t nIndex : account->setKeyPoolExternal)\n                db.ErasePool(pactiveWallet, nIndex, forceErase);\n\n            account->setKeyPoolInternal.clear();\n            account->setKeyPoolExternal.clear();\n        }\n\n        // Wipe all the transactions associated with account\n        LogPrintf(\"CExtWallet::deleteAccount - wipe transactions\");\n        {\n            std::vector<uint256> hashesToErase;\n            std::vector<uint256> hashesErased;\n            for (const auto& [txHash, tx] : pactiveWallet->mapWallet)\n            {\n                if (::IsMine(account, tx))\n                {\n                    hashesToErase.push_back(txHash);\n                    auto range = wtxOrdered.equal_range(tx.nOrderPos);\n                    for (auto i = range.first; i != range.second;)\n                    {\n                        if (tx.GetHash() == i->second.first->GetHash())\n                            i = wtxOrdered.erase(i);\n                        else\n                            i++;\n                    }\n                }\n            }\n            pactiveWallet->ZapSelectTx(db, hashesToErase, hashesErased);\n        }\n\n        LogPrintf(\"CExtWallet::deleteAccount - wipe account from memory\");\n        mapAccountLabels.erase(mapAccountLabels.find(account->getUUID()));\n        mapAccounts.erase(mapAccounts.find(account->getUUID()));\n\n        // Make sure we are no longer the active account\n        if(!getActiveAccount() || (getActiveAccount()->getUUID() == account->getUUID()))\n        {\n            if (mapAccounts.size() > 0)\n            {\n                setAnyActiveAccount(db);\n            }\n        }\n\n        //fixme: (FUT) (ACCOUNTS) (LOW) - this leaks until program exit\n        //We can't easily delete the account as other places may still be referencing it...\n        // Let UI handle deletion [hide account etc.] (we can't actually delete the account pointer because of this so we leak)\n        NotifyAccountDeleted(static_cast<CWallet*>(this), account);\n    }\n    else\n    {\n        std::string newLabel = account->getLabel();\n        if (newLabel.find(_(\"[Restored]\")) != std::string::npos)\n        {\n            newLabel = newLabel.replace(newLabel.find(_(\"[Restored]\")), _(\"[Restored]\").length(), _(\"[Deleted]\"));\n        }\n        else\n        {\n            newLabel = newLabel + \" \" + _(\"[Deleted]\");\n        }\n\n        {\n            LOCK(cs_wallet);\n\n            account->setLabel(newLabel, &db);\n            account->m_State = AccountState::Deleted;\n            mapAccountLabels[account->getUUID()] = newLabel;\n            if (!db.WriteAccount(getUUIDAsString(account->getUUID()), account))\n            {\n                throw std::runtime_error(\"Writing account failed\");\n            }\n        }\n        NotifyAccountDeleted(static_cast<CWallet*>(this), account);\n    }\n}\n\nvoid CExtWallet::addAccount(CAccount* account, const std::string& newName, bool bMakeActive)\n{\n    {\n        LOCK(cs_wallet);\n\n        CWalletDB walletdb(*dbw);\n        if (!walletdb.WriteAccount(getUUIDAsString(account->getUUID()), account))\n        {\n            throw std::runtime_error(\"Writing account failed\");\n        }\n        mapAccounts[account->getUUID()] = account;\n        changeAccountName(account, newName, false);\n    }\n    NotifyAccountAdded(static_cast<CWallet*>(this), account);\n\n    if (account->m_State == AccountState::Normal)\n    {\n        if (bMakeActive)\n        {\n            CWalletDB walletdb(*dbw);\n            setActiveAccount(walletdb, account);\n        }\n    }\n}\n\nvoid CExtWallet::setActiveAccount(CWalletDB& walletdb, CAccount* newActiveAccount)\n{\n    if (activeAccount != newActiveAccount)\n    {\n        activeAccount = newActiveAccount;\n        walletdb.WritePrimaryAccount(activeAccount);\n\n        NotifyActiveAccountChanged(static_cast<CWallet*>(this), newActiveAccount);\n    }\n}\n\nvoid CExtWallet::setAnyActiveAccount(CWalletDB& walletdb)\n{\n    for (const auto& [accountUUID, account] : pactiveWallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        if (account->m_State == AccountState::Normal)\n        {\n            setActiveAccount(walletdb, account);\n            return;\n        }\n    }\n}\n\nCAccount* CExtWallet::getActiveAccount()\n{\n    return activeAccount;\n}\n\nvoid CExtWallet::setActiveSeed(CWalletDB& walletdb, CHDSeed* newActiveSeed)\n{\n    if (activeSeed != newActiveSeed)\n    {\n        activeSeed = newActiveSeed;\n        if (activeSeed)\n            walletdb.WritePrimarySeed(*activeSeed);\n        else\n            walletdb.ErasePrimarySeed();\n\n        //fixme: (FUT) (ACCOUNTS) (LOW)\n        //NotifyActiveSeedChanged(this, newActiveAccount);\n    }\n}\n\nCHDSeed* CExtWallet::GenerateHDSeed(CHDSeed::SeedType seedType)\n{\n    if (IsCrypted() && (!activeAccount || IsLocked()))\n    {\n        throw std::runtime_error(\"Generating seed requires unlocked wallet\");\n    }\n\n    std::vector<unsigned char> entropy(16);\n    GetStrongRandBytes(&entropy[0], 16);\n    CHDSeed* newSeed = new CHDSeed(mnemonicFromEntropy(entropy, entropy.size()*8).c_str(), seedType);\n    if (!CWalletDB(*dbw).WriteHDSeed(*newSeed))\n    {\n        throw std::runtime_error(\"Writing seed failed\");\n    }\n    if (IsCrypted())\n    {\n        if (!newSeed->Encrypt(activeAccount->vMasterKey))\n        {\n            throw std::runtime_error(\"Encrypting seed failed\");\n        }\n    }\n    mapSeeds[newSeed->getUUID()] = newSeed;\n\n    return newSeed;\n}\n\nvoid CExtWallet::DeleteSeed(CWalletDB& walletDB, CHDSeed* deleteSeed, bool shouldPurgeAccounts)\n{\n    LogPrintf(\"CExtWallet::DeleteSeed\");\n    mapSeeds.erase(mapSeeds.find(deleteSeed->getUUID()));\n    if (!walletDB.DeleteHDSeed(*deleteSeed))\n    {\n        throw std::runtime_error(\"Deleting seed failed\");\n    }\n\n    //fixme: (FUT) (ACCOUNTS) purge accounts completely if empty?\n    LogPrintf(\"CExtWallet::DeleteSeed - testing which accounts to delete [%d]\", pactiveWallet->mapAccounts.size());\n    std::vector<CAccount*> deleteAccounts;\n    for (const auto& accountPair : pactiveWallet->mapAccounts)\n    {\n        if (accountPair.second->IsHD() && ((CAccountHD*)accountPair.second)->getSeedUUID() == deleteSeed->getUUID())\n        {\n            deleteAccounts.push_back(accountPair.second);\n        }\n    }\n    LogPrintf(\"CExtWallet::DeleteSeed - Deleting  accounts [%d]\", deleteAccounts.size());\n    for (const auto& accountForDeletion : deleteAccounts)\n    {\n        //fixme: (FUT) (ACCOUNTS) check balance\n        deleteAccount(walletDB, accountForDeletion, shouldPurgeAccounts);\n    }\n    LogPrintf(\"CExtWallet::DeleteSeed - done deleting accounts\");\n\n    if (activeSeed == deleteSeed)\n    {\n        LogPrintf(\"CExtWallet::DeleteSeed - set active seed to new seed\");\n        if (mapSeeds.empty())\n        {\n            LogPrintf(\"CExtWallet::DeleteSeed - set NULL active seed\");\n            setActiveSeed(walletDB, NULL);\n        }\n        else\n        {\n            LogPrintf(\"CExtWallet::DeleteSeed - setting first mapped seed as active\");\n            setActiveSeed(walletDB, mapSeeds.begin()->second);\n        }\n    }\n\n    LogPrintf(\"CExtWallet::DeleteSeed - Finished\");\n    delete deleteSeed;\n}\n\nCHDSeed* CExtWallet::ImportHDSeedFromPubkey(SecureString pubKeyString)\n{\n    if (IsCrypted() && (!activeAccount || IsLocked()))\n    {\n        throw std::runtime_error(\"Generating seed requires unlocked wallet\");\n    }\n\n    CExtPubKey pubkey;\n    try\n    {\n        CEncodedSecretKeyExt<CExtPubKey> secretExt;\n        secretExt.SetString(pubKeyString.c_str());\n        pubkey = secretExt.GetKeyFromString();\n    }\n    catch(...)\n    {\n        throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" extended public key\");\n    }\n\n    if (!pubkey.pubkey.IsValid())\n    {\n        throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" extended public key\");\n    }\n\n    CHDSeed* newSeed = new CHDSeed(pubkey, CHDSeed::CHDSeed::BIP44NoHardening);\n    if (!CWalletDB(*dbw).WriteHDSeed(*newSeed))\n    {\n        throw std::runtime_error(\"Writing seed failed\");\n    }\n    if (IsCrypted())\n    {\n        if (!newSeed->Encrypt(activeAccount->vMasterKey))\n        {\n            throw std::runtime_error(\"Encrypting seed failed\");\n        }\n    }\n    mapSeeds[newSeed->getUUID()] = newSeed;\n\n    return newSeed;\n}\n\nCHDSeed* CExtWallet::ImportHDSeed(SecureString mnemonic, CHDSeed::SeedType type)\n{\n    if (IsCrypted() && (!activeAccount || IsLocked()))\n    {\n        throw std::runtime_error(\"Generating seed requires unlocked wallet\");\n    }\n\n    if (!checkMnemonic(mnemonic))\n    {\n        throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" mnemonic\");\n    }\n\n    std::vector<unsigned char> entropy(16);\n    GetStrongRandBytes(&entropy[0], 16);\n    CHDSeed* newSeed = new CHDSeed(mnemonic, type);\n    if (!CWalletDB(*dbw).WriteHDSeed(*newSeed))\n    {\n        throw std::runtime_error(\"Writing seed failed\");\n    }\n    if (IsCrypted())\n    {\n        if (!newSeed->Encrypt(activeAccount->vMasterKey))\n        {\n            throw std::runtime_error(\"Encrypting seed failed\");\n        }\n    }\n    mapSeeds[newSeed->getUUID()] = newSeed;\n\n    return newSeed;\n}\n\n\nCHDSeed* CExtWallet::getActiveSeed()\n{\n    return activeSeed;\n}\n\nvoid CExtWallet::RemoveAddressFromKeypoolIfIsMine(const CTxOut& txout, uint64_t time)\n{\n    ::RemoveAddressFromKeypoolIfIsMine(*static_cast<CWallet*>(this), txout, time);\n}\n\n\nvoid CExtWallet::RemoveAddressFromKeypoolIfIsMine(const CTransaction& tx, uint64_t time)\n{\n    for(const CTxOut& txout : tx.vout)\n    {\n        RemoveAddressFromKeypoolIfIsMine(txout, time);\n    }\n}\n\nvoid CExtWallet::RemoveAddressFromKeypoolIfIsMine(const CTxIn& txin, uint64_t time)\n{\n    LOCK(cs_wallet);\n    const CWalletTx* prev = static_cast<CWallet*>(this)->GetWalletTx(txin.GetPrevOut());\n    if (prev)\n    {\n        if (txin.GetPrevOut().n < prev->tx->vout.size())\n            RemoveAddressFromKeypoolIfIsMine(prev->tx->vout[txin.GetPrevOut().n], time);\n    }\n}\n\n// Shadow accounts... For HD we keep a 'cache' of already created accounts, the reason being that another shared wallet might create new addresses, and we need to be able to detect those.\n// So we keep these 'shadow' accounts, and if they ever receive a transaction we automatically 'convert' them into normal accounts in the UI.\n// If/When the user wants new accounts, we hand out the previous shadow account and generate a new Shadow account to take it's place...\nCAccountHD* CExtWallet::GenerateNewAccount(std::string strAccount, AccountState state, AccountType subType, bool bMakeActive)\n{\n    assert(state != AccountState::ShadowChild);\n    assert(state != AccountState::Deleted);\n    CAccountHD* newAccount = NULL;\n\n    // Grab account with lowest index from existing pool of shadow accounts and convert it into a new account.\n    if (state == AccountState::Normal || state == AccountState::Shadow)\n    {\n        LOCK(cs_wallet);\n\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->m_Type == subType)\n            {\n                if (forAccount->m_State == AccountState::Shadow)\n                {\n                    if (!newAccount || ((CAccountHD*)forAccount)->getIndex() < newAccount->getIndex())\n                    {\n                        if (((CAccountHD*)forAccount)->getSeedUUID() == getActiveSeed()->getUUID())\n                        {\n                            //Only consider accounts that are\n                            //1) Of the required state\n                            //2) Marked as being shadow\n                            //3) From the active seed\n                            //4) Always take the lowest account index that we can find\n                            newAccount = (CAccountHD*)forAccount;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Create a new account in the (unlikely) event there was no shadow state\n    if (!newAccount)\n    {\n        if (!IsLocked())\n        {\n            CWalletDB db(*dbw);\n            newAccount = activeSeed->GenerateAccount(subType, &db);\n        }\n        else\n        {\n            return nullptr;\n        }\n    }\n    newAccount->m_State = state;\n\n    // We don't top up the shadow pool here - we have a thread for that.\n\n    // Write new account\n    //NB! We have to do this -after- we create the new shadow account, otherwise the shadow account ends up being the active account.\n    addAccount(newAccount, strAccount, bMakeActive);\n\n    if (subType == AccountType::PoW2Witness)\n    {\n        newAccount->SetWarningState(AccountStatus::WitnessEmpty);\n    }\n    else\n    {\n        newAccount->SetWarningState(AccountStatus::Default);\n    }\n\n    // Shadow accounts have less keys - so we need to top up the keypool for our new 'non shadow' account at this point.\n    if( activeAccount ) //fixme: (FUT) (ACCOUNTS) IsLocked() requires activeAccount - so we avoid calling this if activeAccount not yet set.\n        static_cast<CWallet*>(this)->TopUpKeyPool(1, 0, activeAccount);//We only assign the bare minimum addresses here - and let the background thread do the rest\n\n    return newAccount;\n}\n\nCAccount* CExtWallet::GenerateNewLegacyAccount(std::string strAccount)\n{\n    CAccount* newAccount = new CAccount();\n    //fixme: (FUT) (ACCOUNTS) Improve the way encryption of legacy accounts is handled\n    if (IsCrypted())\n    {\n        LOCK2(cs_main, cs_wallet);\n        if (IsLocked())\n            return nullptr;\n\n        if (!activeAccount)\n            return nullptr;\n\n        if (!newAccount->Encrypt(activeAccount->vMasterKey))\n            return nullptr;\n    }\n    addAccount(newAccount, strAccount);\n\n    return newAccount;\n}\n\nbool CExtWallet::ImportKeysIntoWitnessOnlyWitnessAccount(CAccount* forAccount, std::vector<std::pair<CKey, uint64_t>> privateWitnessKeysWithBirthDates, bool allowRescan)\n{\n    if (!forAccount)\n        return false;\n\n    if (forAccount->m_Type != WitnessOnlyWitnessAccount)\n        return false;\n\n    //Don't import an address that is already in wallet.\n    for (const auto& [privateWitnessKey, nKeyBirthDate] : privateWitnessKeysWithBirthDates)\n    {\n        (unused) nKeyBirthDate;\n        if (static_cast<CWallet*>(this)->HaveKey(privateWitnessKey.GetPubKey().GetID()))\n        {\n            std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + _(\"Wallet already contains key.\");\n            LogPrintf(strErrorMessage.c_str());\n            CAlert::Notify(strErrorMessage, true, true);\n            return false;\n        }\n    }\n\n    for (const auto& [privateWitnessKey, nKeyBirthDate] : privateWitnessKeysWithBirthDates)\n    {\n        CPubKey pubWitnessKey = privateWitnessKey.GetPubKey();\n        CKeyID witnessKeyID = pubWitnessKey.GetID();\n        static_cast<CWallet*>(this)->importPrivKeyIntoAccount(forAccount, privateWitnessKey, witnessKeyID, nKeyBirthDate, allowRescan);\n    }\n    return true;\n}\n\nstd::vector<std::pair<CKey, uint64_t>> CExtWallet::ParseWitnessKeyURL(SecureString sEncodedPrivWitnessKeysURL)\n{\n    std::string keyPrefix = GLOBAL_APP_URIPREFIX\"://witnesskeys?keys=\";\n    if (!boost::starts_with(sEncodedPrivWitnessKeysURL, keyPrefix))\n        throw std::runtime_error(\"Not a valid \\\"witness only\\\" witness account URI\");\n\n    std::vector<SecureString> encodedPrivateWitnessKeyStrings;\n    SecureString encPrivWitnessKeyWithoutPrefix(sEncodedPrivWitnessKeysURL.begin()+keyPrefix.length(), sEncodedPrivWitnessKeysURL.end());\n    boost::split(encodedPrivateWitnessKeyStrings, encPrivWitnessKeyWithoutPrefix, boost::is_any_of(\":\"));\n\n    std::vector<std::pair<CKey, uint64_t>> privateWitnessKeys;\n    privateWitnessKeys.reserve(encodedPrivateWitnessKeyStrings.size());\n    for (const auto& encodedPrivateWitnessKeyString : encodedPrivateWitnessKeyStrings)\n    {\n        std::vector<SecureString> encodedPrivateWitnessKeyAndBirthDate;\n        boost::split(encodedPrivateWitnessKeyAndBirthDate, encodedPrivateWitnessKeyString, boost::is_any_of(\"#\"));\n        if (encodedPrivateWitnessKeyAndBirthDate.size() > 2)\n            throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" private witness key/birthdate pair\");\n\n        uint64_t nKeyBirthDate = 1;\n        if (encodedPrivateWitnessKeyAndBirthDate.size() == 2)\n            ParseUInt64(encodedPrivateWitnessKeyAndBirthDate[1].c_str(), &nKeyBirthDate);\n\n        bool keyError = false;\n        try\n        {\n            CEncodedSecretKey secretPrivWitnessKey;\n            secretPrivWitnessKey.SetString(encodedPrivateWitnessKeyAndBirthDate[0].c_str());\n            if (secretPrivWitnessKey.IsValid())\n            {\n                privateWitnessKeys.emplace_back(secretPrivWitnessKey.GetKey(), nKeyBirthDate);\n            }\n            else\n            {\n                keyError = true;\n            }\n        }\n        catch(...)\n        {\n            keyError = true;\n        }\n        if (keyError)\n        {\n            throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" private witness key\");\n        }\n    }\n    return privateWitnessKeys;\n}\n\nCAccount* CExtWallet::CreateWitnessOnlyWitnessAccount(std::string strAccount, std::vector<std::pair<CKey, uint64_t>> privateWitnessKeysWithBirthDates, bool allowRescan)\n{\n    CAccount* newAccount = NULL;\n\n    newAccount = new CAccount();\n    newAccount->m_Type = WitnessOnlyWitnessAccount;\n\n    if (IsCrypted())\n    {\n        LOCK2(cs_main, cs_wallet);\n        if (IsLocked())\n            return nullptr;\n\n        if (!activeAccount)\n            return nullptr;\n\n        if (!newAccount->Encrypt(activeAccount->vMasterKey))\n            return nullptr;\n    }\n\n    if (ImportKeysIntoWitnessOnlyWitnessAccount(newAccount, privateWitnessKeysWithBirthDates, allowRescan))\n    {\n        // Write new account\n        addAccount(newAccount, strAccount);\n\n        return newAccount;\n    }\n    else\n    {\n        delete newAccount;\n        return nullptr;\n    }\n}\n\nCAccountHD* CExtWallet::CreateReadOnlyAccount(std::string strAccount, SecureString encExtPubKey)\n{\n    CAccountHD* newAccount = NULL;\n\n    CExtPubKey pubkey;\n    try\n    {\n        CEncodedSecretKeyExt<CExtPubKey> secretExt;\n        secretExt.SetString(encExtPubKey.c_str());\n        pubkey = secretExt.GetKeyFromString();\n    }\n    catch(...)\n    {\n        throw std::runtime_error(\"Not a valid \" GLOBAL_APPNAME \" extended public key\");\n    }\n\n    newAccount = new CAccountHD(pubkey, boost::uuids::nil_generator()(), AccountType::Desktop);\n\n\n    // Write new account\n    addAccount(newAccount, strAccount);\n\n    //We only assign the bare minimum addresses here - and let the background thread do the rest\n    static_cast<CWallet*>(this)->TopUpKeyPool(2, 0, newAccount);\n\n    return newAccount;\n}\n\nCAccountHD* CExtWallet::CreateSeedlessHDAccount(std::string strAccount, CEncodedSecretKeyExt<CExtKey> accountExtKey, AccountState state, AccountType type, bool generateKeys)\n{\n    //fixme: (FUT) (ACCOUNTS) (HIGH) add key validation checks here.\n\n    CAccountHD* newAccount = new CAccountHD(accountExtKey.getKeyRaw(), boost::uuids::nil_generator()(), type);\n    newAccount->m_State = state;\n\n    // Write new account\n    addAccount(newAccount, strAccount);\n\n    //We only assign the bare minimum addresses here - and let the background thread do the rest\n    if (generateKeys)\n    {\n        static_cast<CWallet*>(this)->TopUpKeyPool(2, 0, newAccount);\n    }\n\n    return newAccount;\n}\n\n\nvoid CExtWallet::ForceRewriteKeys(CAccount& forAccount)\n{\n    {\n        LOCK(cs_wallet);\n\n        std::set<CKeyID> setAddress;\n        forAccount.GetKeys(setAddress);\n\n        CWalletDB walletDB(*dbw);\n        for (const auto& keyID : setAddress)\n        {\n            if (!IsCrypted())\n            {\n                CKey keyPair;\n                if (!GetKey(keyID, keyPair))\n                {\n                    throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade all keys\");\n                }\n                walletDB.EraseKey(keyPair.GetPubKey());\n                if (!walletDB.WriteKey(keyPair.GetPubKey(), keyPair.GetPrivKey(), static_cast<CWallet*>(this)->mapKeyMetadata[keyID], getUUIDAsString(forAccount.getUUID()), KEYCHAIN_EXTERNAL))\n                {\n                    throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not write all upgraded keys\");\n                }\n            }\n            else\n            {\n                CPubKey pubKey;\n                if (!GetPubKey(keyID, pubKey))\n                { \n                    throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade all encrypted keys\");\n                }\n                walletDB.EraseEncryptedKey(pubKey);\n                std::vector<unsigned char> secret;\n                if (!forAccount.GetKey(keyID, secret))\n                { \n                    throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade all encrypted keys\");\n                }\n                if (!walletDB.WriteCryptedKey(pubKey, secret, static_cast<CWallet*>(this)->mapKeyMetadata[keyID], getUUIDAsString(forAccount.getUUID()), KEYCHAIN_EXTERNAL))\n                {\n                    throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not write all upgraded keys\");\n                }\n            }\n        }\n    }\n\n\n    CWalletDB walletDB(*dbw);\n    for(int64_t nIndex : forAccount.setKeyPoolInternal)\n    {\n        CKeyPool keypoolentry;\n        if (!walletDB.ReadPool(nIndex, keypoolentry))\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n        if (!walletDB.ErasePool( static_cast<CWallet*>(this), nIndex ))\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n        keypoolentry.accountName = getUUIDAsString(forAccount.getUUID());\n        keypoolentry.nChain = KEYCHAIN_CHANGE;\n        if ( !walletDB.WritePool( nIndex, keypoolentry ) )\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n    }\n    for(int64_t nIndex : forAccount.setKeyPoolExternal)\n    {\n        CKeyPool keypoolentry;\n        if (!walletDB.ReadPool(nIndex, keypoolentry))\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n        if (!walletDB.ErasePool( static_cast<CWallet*>(this), nIndex ))\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n        keypoolentry.accountName = getUUIDAsString(forAccount.getUUID());\n        keypoolentry.nChain = KEYCHAIN_EXTERNAL;\n        if ( !walletDB.WritePool( nIndex, keypoolentry ) )\n        {\n            throw std::runtime_error(\"Fatal error upgrading legacy wallet - could not upgrade entire keypool\");\n        }\n    }\n}\n\n\nbool CExtWallet::AddHDKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, CAccount& forAccount, int keyChain)\n{\n    AssertLockHeld(cs_wallet); // mapKeyMetadata\n    if (!forAccount.AddKeyPubKey(HDKeyIndex, pubkey, keyChain))\n    {\n        LogPrintf(\"CExtWallet::AddHDKeyPubKey: AddKeyPubKey failed for account\");\n        return false;\n    }\n\n    // check if we need to remove from watch-only\n    CScript script;\n    script = GetScriptForDestination(pubkey.GetID());\n    if (HaveWatchOnly(script))\n        static_cast<CWallet*>(this)->RemoveWatchOnly(script);\n    script = GetScriptForRawPubKey(pubkey);\n    if (HaveWatchOnly(script))\n        static_cast<CWallet*>(this)->RemoveWatchOnly(script);\n\n    if (!CWalletDB(*dbw).WriteKeyHD(pubkey, HDKeyIndex, keyChain, static_cast<CWallet*>(this)->mapKeyMetadata[pubkey.GetID()], getUUIDAsString(forAccount.getUUID())))\n    {\n        LogPrintf(\"CExtWallet::AddHDKeyPubKey: WriteKeyHD failed for key\");\n        return false;\n    }\n    else if (forAccount.IsPoW2Witness() && keyChain == KEYCHAIN_WITNESS)\n    {\n        CPrivKey nullKey;\n        return CWalletDB(*dbw).WriteKeyOverride(pubkey, nullKey, getUUIDAsString(forAccount.getUUID()), KEYCHAIN_WITNESS);\n    }\n    return true;\n}\n\n\nbool CExtWallet::LoadHDKey(int64_t HDKeyIndex, int64_t keyChain, const CPubKey &pubkey, const std::string& forAccount)\n{\n    LOCK(cs_wallet);\n    return mapAccounts[getUUIDFromString(forAccount)]->AddKeyPubKey(HDKeyIndex, pubkey, keyChain);\n}\n\n\nbool CExtWallet::Lock()\n{\n    LOCK(cs_wallet);\n\n    if (nUnlockSessions > 0) {\n        fAutoLock = true;\n        return true;\n    }\n    else {\n        return LockHard();\n    }\n}\n\nbool CExtWallet::LockHard()\n{\n    AssertLockHeld(cs_wallet);\n\n    static_cast<CWallet*>(this)->nRelockTime = 0;\n\n    bool ret = true;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        if (!forAccount->Lock())\n            ret = false;\n    }\n    for (const auto& [seedUUID, forSeed] : mapSeeds)\n    {\n        (unused) seedUUID;\n        if (!forSeed->Lock())\n            ret = false;\n    }\n\n    // Only notify changed locking state if the locking actually changed, that is:\n    // - actaul locking took place, it is NOT delayed\n    // - locking succeeded\n    if (ret)\n        NotifyLockingChanged(true);\n\n    return ret;\n}\n\nCPubKey CWallet::GenerateNewKey(CAccount& forAccount, int keyChain)\n{\n    AssertLockHeld(cs_wallet); // mapKeyMetadata\n\n    // Create new metadata\n    int64_t nCreationTime = GetTime();\n    CKeyMetadata metadata(nCreationTime);\n\n    CPubKey pubkey = forAccount.GenerateNewKey(*this, metadata, keyChain);\n\n    mapKeyMetadata[pubkey.GetID()] = metadata;\n    UpdateTimeFirstKey(nCreationTime);\n\n    return pubkey;\n}\n\nbool CWallet::LoadKey(const CKey& key, const CPubKey &pubkey, const std::string& forAccount, int64_t nKeyChain)\n{\n    LOCK(cs_wallet);\n    return mapAccounts[getUUIDFromString(forAccount)]->AddKeyPubKey(key, pubkey, nKeyChain);\n}\n"
  },
  {
    "path": "src/wallet/extwallet.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef EXT_WALLET_H\n#define EXT_WALLET_H\n\n#include \"amount.h\"\n#include \"streams.h\"\n#include \"tinyformat.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n#include \"validation/validationinterface.h\"\n#include \"script/ismine.h\"\n#include \"script/sign.h\"\n#include \"wallet/crypter.h\"\n#include \"wallet/walletdb.h\"\n#include \"wallet/rpcwallet.h\"\n\n#include <algorithm>\n#include <atomic>\n#include <map>\n#include <set>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <utility>\n#include <vector>\n\n//Munt specific includes\n#include \"wallet/walletdberrors.h\"\n#include \"account.h\"\n\n#include <boost/thread.hpp>\n\n\nvoid StartShadowPoolManagerThread(boost::thread_group& threadGroup);\n\n//fixme: (FUT) (ACCOUNTS) (LOW) Make configurable option\nextern bool fShowChildAccountsSeperately;\n\nstd::string accountNameForAddress(const CWallet &wallet, const CTxDestination& dest);\nisminetype IsMine(const CWallet &wallet, const CTxDestination& dest);\nisminetype IsMine(const CWallet &wallet, const CTxOut& out);\nisminetype IsMineWitness(const CWallet &wallet, const CTxOut& out);\n\n/** \n * A CExtWallet maintains a set of transactions and balances\n * and provides the ability to create new transactions.\n * it contains one or more accounts, which are responsible for creating/allocating/managing keys via their keystore interfaces.\n */\nclass CExtWallet : public CValidationInterface\n{\npublic:\n    CExtWallet() : dbw(new CWalletDBWrapper()){};\n    CExtWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in)){};\n    virtual ~CExtWallet(){};\n\n    //Members that are shared with CWallet.\n    mutable RecursiveMutex cs_wallet;\n    uint64_t nTimeFirstKey = 0;\n    //const std::string strWalletFile;\n    std::unique_ptr<CWalletDBWrapper> dbw;\n\n    typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;\n    typedef std::multimap<int64_t, TxPair > TxItems;\n    TxItems wtxOrdered;\n\n    /**\n     * Lock wallet keys. If any unlock sessions are in progress the lock will be delayed until there are no\n     * open unlock sessions.\n     * @return succesfully locked wallet. This value seems of little use as it will always return true if locking is delayed.\n     */\n    bool Lock();\n\n    /**\n     * Actual lock operation, unconditionally locking the wallet, ie. not depending on unlock sessions or anything.\n     */\n    bool LockHard();\n\n\n    bool UnlockWithMasterKey(const CKeyingMaterial& vMasterKeyIn) const\n    {\n        LOCK(cs_wallet);\n        bool ret = true;\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            bool needsWriteToDisk = false;\n            if (!forAccount->Unlock(vMasterKeyIn, needsWriteToDisk))\n            {\n                LogPrintf(\"CWallet::UnlockWithMasterKey - Failed to unlock account\");\n                ret = false;\n            }\n            if (needsWriteToDisk)\n            {\n                CWalletDB db(*dbw);\n                if (!db.WriteAccount(getUUIDAsString(accountUUID), forAccount))\n                {\n                    throw std::runtime_error(\"Writing account failed\");\n                }\n            }\n        }\n        for (const auto& [seedUUID, forSeed] : mapSeeds)\n        {\n            (unused) seedUUID;\n            if (!forSeed->Unlock(vMasterKeyIn))\n            {\n                LogPrintf(\"CWallet::UnlockWithMasterKey - Failed to unlock seed\");\n                ret = false;\n            }\n        }\n\n        // Only notify changed locking state if unlocking succeeded\n        if (ret)\n            NotifyLockingChanged(false);\n\n        return ret;\n    }\n\n\n    virtual bool IsCrypted() const\n    {\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if(forAccount->IsCrypted())\n                return true;\n        }\n        for (const auto& [seedUUID, forSeed] : mapSeeds)\n        {\n            (unused) seedUUID;\n            if (forSeed->IsCrypted())\n                return true;\n        }\n        return false;\n    }\n\n\n    virtual bool IsLocked() const\n    {\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if(forAccount->IsLocked())\n                return true;\n        }\n        for (const auto& [seedUUID, forSeed] : mapSeeds)\n        {\n            (unused) seedUUID;\n            if (forSeed->IsLocked())\n                return true;\n        }\n        return false;\n    }\n\n    virtual bool GetKey(const CKeyID &address, CKey& keyOut) const\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->GetKey(address, keyOut))\n                return true;\n        }\n        return false;\n    }\n\n\n    virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut)\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->GetPubKey(address, vchPubKeyOut))\n                return true;\n        }\n        return false;\n    }\n\n\n    virtual bool HaveWatchOnly(const CScript &dest) const\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->HaveWatchOnly(dest))\n                return true;\n        }\n        return false;\n    }\n\n    virtual bool HaveWatchOnly() const\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->HaveWatchOnly())\n                return true;\n        }\n        return false;\n    }\n\n    virtual bool HaveCScript(const CScriptID &hash)\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->HaveCScript(hash))\n                return true;\n        }\n        return false;\n    }\n\n    virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut)\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->GetCScript(hash, redeemScriptOut))\n                return true;\n        }\n        return false;\n    }\n\n\n    virtual bool HaveKey(const CKeyID &address) const\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->HaveKey(address))\n                return true;\n        }\n        return false;\n    }\n\n    virtual bool HaveWatchOnly(const CScript &dest)\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (forAccount->HaveWatchOnly(dest))\n                return true;\n        }\n        return false;\n    }\n    virtual bool AddHDKeyPubKey(int64_t HDKeyIndex, const CPubKey &pubkey, CAccount& forAccount, int keyChain);\n    virtual bool LoadHDKey(int64_t HDKeyIndex, int64_t keyChain, const CPubKey &pubkey, const std::string& forAccount);\n\n    virtual void MarkKeyUsed(CKeyID keyID, uint64_t usageTime);\n\n    isminetype IsMine(const CKeyStore &keystore, const CTxIn& txin) const;\n    virtual void RemoveAddressFromKeypoolIfIsMine(const CTxIn& txin, uint64_t time);\n    virtual void RemoveAddressFromKeypoolIfIsMine(const CTxOut& txout, uint64_t time);\n    virtual void RemoveAddressFromKeypoolIfIsMine(const CTransaction& tx, uint64_t time);\n\n    void changeAccountName(CAccount* account, const std::string& newName, bool notify=true);\n    void addAccount(CAccount* account, const std::string& newName, bool bMakeActive=true);\n    void deleteAccount(CWalletDB& walletDB, CAccount* account, bool shouldPurge=false);\n\n    CAccountHD* GenerateNewAccount(std::string strAccount, AccountState state, AccountType subType, bool bMakeActive=true);\n\n    //! Create a new legacy account. Legacy accounts are accounts that generate random keys in a keypool as required instead of generating keys deterministically.\n    virtual CAccount* GenerateNewLegacyAccount(std::string strAccount);\n\n    //! Parse the contents of a munt \"witness key\" URL into an vector of  private key / birth date  pairs.\n    std::vector<std::pair<CKey, uint64_t>> ParseWitnessKeyURL(SecureString sEncodedPrivWitnessKeysURL);\n\n    //! Import vector of  private key / birth date  pairs into an existing \"witness only\" account.\n    CAccount* CreateWitnessOnlyWitnessAccount(std::string strAccount, std::vector<std::pair<CKey, uint64_t>> privateWitnessKeysWithBirthDates, bool allowRescan=true);\n\n    //! Create a new \"witness only\" account and import vector of  private key / birth date  pairs into it.\n    bool ImportKeysIntoWitnessOnlyWitnessAccount(CAccount* forAccount, std::vector<std::pair<CKey, uint64_t>> privateWitnessKeysWithBirthDates, bool allowRescan=true);\n\n    //! Create a read-only HD account using an encoded public key.\n    CAccountHD* CreateReadOnlyAccount(std::string strAccount, SecureString encExtPubKey);\n\n    //! Create an HD account directly from a key and not assosciated with any seed.\n    CAccountHD* CreateSeedlessHDAccount(std::string strAccount, CEncodedSecretKeyExt<CExtKey> accountExtKey, AccountState state, AccountType type, bool generateKeys=true);\n\n    void setActiveAccount(CWalletDB& walletdb, CAccount* newActiveAccount);\n\n    //! Find the first account that is not deleted/shadow etc. and set it as active\n    void setAnyActiveAccount(CWalletDB& walletdb);\n\n    CAccount* getActiveAccount();\n    void setActiveSeed(CWalletDB& walletdb, CHDSeed* newActiveSeed);\n    CHDSeed* GenerateHDSeed(CHDSeed::SeedType);\n    void DeleteSeed(CWalletDB& walletDB, CHDSeed* deleteSeed, bool shouldPurgeAccounts);\n    CHDSeed* ImportHDSeed(SecureString mnemonic, CHDSeed::SeedType type);\n    CHDSeed* ImportHDSeedFromPubkey(SecureString pubKeyString);\n    CHDSeed* getActiveSeed();\n\n    //! for wallet upgrade\n    void ForceRewriteKeys(CAccount& forAccount);\n\n    // for transfer of ownership of unlock sessions to the shadowpool thread, protected by cs_wallet\n    unsigned int nUnlockedSessionsOwnedByShadow;\n\n    std::map<boost::uuids::uuid, CHDSeed*> mapSeeds;\n    std::map<boost::uuids::uuid, CAccount*> mapAccounts;\n    std::map<boost::uuids::uuid, std::string> mapAccountLabels;\n    std::map<uint256, CWalletTx> mapWallet;\n\n    CAccount* activeAccount;\n    CHDSeed* activeSeed;\n\n    // Account changed (name change)\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountNameChanged;\n\n    // Account warning state changed (witness account expired)\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountWarningChanged;\n\n    // New account added to the wallet\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountAdded;\n\n    // Account marked as deleted.\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountDeleted;\n    \n    // Account properties modified in some way (excludes deletion and name changes)\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountModified;\n\n    // Currently active account changed\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyActiveAccountChanged;\n\n    // Account compound setting changed\n    boost::signals2::signal<void (CWallet* wallet, CAccount* account)> NotifyAccountCompoundingChanged;\n    \n    // Block generation turned on\n    boost::signals2::signal<void (void)> NotifyGenerationStarted;\n    \n    // Block generation turned off\n    boost::signals2::signal<void (void)> NotifyGenerationStopped;\n    \n    // New generation statistics\n    boost::signals2::signal<void (void)> NotifyGenerationStatisticsUpdate;\n\n    /** Locking state changed */\n    boost::signals2::signal<void (bool isLocked)> NotifyLockingChanged;\n\nprotected:\n    // number of active unlocked sessions protected by cs_wallet\n    unsigned int nUnlockSessions;\n\n    // automatically lock when nUnlockSessions becomes 0\n    mutable bool fAutoLock;\n};\n#endif\n"
  },
  {
    "path": "src/wallet/feebumper.cpp",
    "content": "// Copyright (c) 2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"consensus/validation.h\"\n#include \"wallet/feebumper.h\"\n#include \"wallet/wallet.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"validation/validation.h\" //for mempool access\n#include \"txmempool.h\"\n#include \"util/moneystr.h\"\n#include \"util.h\"\n#include \"net.h\"\n\n// Calculate the size of the transaction assuming all signatures are max size\n// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.\n// TODO: re-use this in CWallet::CreateTransaction (right now\n// CreateTransaction uses the constructed dummy-signed tx to do a priority\n// calculation, but we should be able to refactor after priority is removed).\n// NOTE: this requires that all inputs must be in mapWallet (eg the tx should\n// be IsAllFromMe).\nint64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)\n{\n    CMutableTransaction txNew(tx);\n    std::vector<CInputCoin> vCoins;\n    // Look up the inputs.  We should have already checked that this transaction\n    // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our\n    // wallet, with a valid index into the vout array.\n    for (auto& input : tx.vin) {\n        const CWalletTx* prev = pWallet->GetWalletTx(input.GetPrevOut());\n        assert(prev && input.GetPrevOut().n < prev->tx->vout.size());\n        vCoins.emplace_back(CInputCoin(prev, input.GetPrevOut().n, IsOldTransactionVersion(tx.nVersion)));\n    }\n    std::vector<CKeyStore*> accountsToTry;\n    for (const auto& [accountUUID, account] : pWallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        accountsToTry.push_back(account);\n    }\n    if (!pWallet->DummySignTx(accountsToTry, txNew, vCoins, Spend))\n    {\n         // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)\n        // implies that we can sign for every input.\n        return -1;\n    }\n    return GetVirtualTransactionSize(txNew);\n}\n\nbool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx) {\n    if (pWallet->HasWalletSpend(wtx.GetHash())) {\n        vErrors.push_back(\"Transaction has descendants in the wallet\");\n        currentResult = BumpFeeResult::INVALID_PARAMETER;\n        return false;\n    }\n\n    {\n        LOCK(mempool.cs);\n        auto it_mp = mempool.mapTx.find(wtx.GetHash());\n        if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {\n            vErrors.push_back(\"Transaction has descendants in the mempool\");\n            currentResult = BumpFeeResult::INVALID_PARAMETER;\n            return false;\n        }\n    }\n\n    if (wtx.GetDepthInMainChain() != 0) {\n        vErrors.push_back(\"Transaction has been generated, or is conflicted with a generated transaction\");\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return false;\n    }\n    return true;\n}\n\n//fixme: (PHASE5) We can remove these includes after phase 4 activation\n#include \"witnessutil.h\"\n#include \"validation/validation.h\"\n\nCFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable)\n    :\n    txid(std::move(txidIn)),\n    nOldFee(0),\n    nNewFee(0),\n    mtx(CURRENT_TX_VERSION_POW2)\n{\n    vErrors.clear();\n    bumpedTxid.SetNull();\n    AssertLockHeld(pWallet->cs_wallet);\n    if (!pWallet->mapWallet.count(txid)) {\n        vErrors.push_back(\"Invalid or non-wallet transaction id\");\n        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;\n        return;\n    }\n    auto it = pWallet->mapWallet.find(txid);\n    const CWalletTx& wtx = it->second;\n\n    if (!preconditionChecks(pWallet, wtx)) {\n        return;\n    }\n\n    if (!SignalsOptInRBF(wtx)) {\n        vErrors.push_back(\"Transaction is not BIP 125 replaceable\");\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    if (wtx.mapValue.count(\"replaced_by_txid\")) {\n        vErrors.push_back(strprintf(\"Cannot bump transaction %s which was already bumped by transaction %s\", txid.ToString(), wtx.mapValue.at(\"replaced_by_txid\")));\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    // check that original tx consists entirely of our inputs\n    // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)\n    if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {\n        vErrors.push_back(\"Transaction contains inputs that don't belong to this wallet\");\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    // figure out which output was change\n    // if there was no change output or multiple change outputs, fail\n    int nOutput = -1;\n    for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {\n        if (pWallet->IsChange(wtx.tx->vout[i])) {\n            if (nOutput != -1) {\n                vErrors.push_back(\"Transaction has multiple change outputs\");\n                currentResult = BumpFeeResult::WALLET_ERROR;\n                return;\n            }\n            nOutput = i;\n        }\n    }\n    if (nOutput == -1) {\n        vErrors.push_back(\"Transaction does not have a change output\");\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    // Calculate the expected size of the new transaction.\n    int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));\n    const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, pWallet);\n    if (maxNewTxSize < 0) {\n        vErrors.push_back(\"Transaction contains inputs that cannot be signed\");\n        currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;\n        return;\n    }\n\n    // calculate the old fee and fee-rate\n    nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();\n    CFeeRate nOldFeeRate(nOldFee, txSize);\n    CFeeRate nNewFeeRate;\n    // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to\n    // future proof against changes to network wide policy for incremental relay\n    // fee that our node may not be aware of.\n    CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);\n    if (::incrementalRelayFee > walletIncrementalRelayFee) {\n        walletIncrementalRelayFee = ::incrementalRelayFee;\n    }\n\n    if (totalFee > 0) {\n        CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);\n        if (totalFee < minTotalFee) {\n            vErrors.push_back(strprintf(\"Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)\",\n                                                                FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));\n            currentResult = BumpFeeResult::INVALID_PARAMETER;\n            return;\n        }\n        CAmount requiredFee = CWallet::GetRequiredFee(maxNewTxSize);\n        if (totalFee < requiredFee) {\n            vErrors.push_back(strprintf(\"Insufficient totalFee (cannot be less than required fee %s)\",\n                                                                FormatMoney(requiredFee)));\n            currentResult = BumpFeeResult::INVALID_PARAMETER;\n            return;\n        }\n        nNewFee = totalFee;\n        nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);\n    } else {\n        nNewFee = CWallet::GetMinimumFee(maxNewTxSize, newConfirmTarget, mempool, ::feeEstimator, ignoreGlobalPayTxFee);\n        nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);\n\n        // New fee rate must be at least old rate + minimum incremental relay rate\n        // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized\n        // in that unit (fee per kb).\n        // However, nOldFeeRate is a calculated value from the tx fee/size, so\n        // add 1 satoshi to the result, because it may have been rounded down.\n        if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {\n            nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());\n            nNewFee = nNewFeeRate.GetFee(maxNewTxSize);\n        }\n    }\n\n    // Check that in all cases the new fee doesn't violate maxTxFee\n     if (nNewFee > maxTxFee) {\n         vErrors.push_back(strprintf(\"Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)\",\n                               FormatMoney(nNewFee), FormatMoney(maxTxFee)));\n         currentResult = BumpFeeResult::WALLET_ERROR;\n         return;\n     }\n\n    // check that fee rate is higher than mempool's minimum fee\n    // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)\n    // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,\n    // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a\n    // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.\n    CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg(\"-maxmempool\", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);\n    if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {\n        vErrors.push_back(strprintf(\"New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.\", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    // Now modify the output to increase the fee.\n    // If the output is not large enough to pay the fee, fail.\n    CAmount nDelta = nNewFee - nOldFee;\n    assert(nDelta > 0);\n    mtx =  *wtx.tx;\n    CTxOut* poutput = &(mtx.vout[nOutput]);\n    if (poutput->nValue < nDelta) {\n        vErrors.push_back(\"Change output is too small to bump the fee\");\n        currentResult = BumpFeeResult::WALLET_ERROR;\n        return;\n    }\n\n    // If the output would become dust, discard it (converting the dust to fee)\n    poutput->nValue -= nDelta;\n    if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {\n        LogPrint(BCLog::RPC, \"Bumping fee and discarding dust output\\n\");\n        nNewFee += poutput->nValue;\n        mtx.vout.erase(mtx.vout.begin() + nOutput);\n    }\n\n    // Mark new tx not replaceable, if requested.\n    if (!newTxReplaceable)\n    {\n        if (!IsOldTransactionVersion(mtx.nVersion))\n        {\n            for (auto& input : mtx.vin)\n            {\n                input.UnsetFlag(CTxInFlags::OptInRBF);\n            }\n        }\n        else\n        {\n            for (auto& input : mtx.vin) {\n                if (input.GetSequence(mtx.nVersion) < 0xfffffffe) input.SetSequence(0xfffffffe, mtx.nVersion, CTxInFlags::None);\n            }\n        }\n    }\n\n    currentResult = BumpFeeResult::OK;\n}\n\nbool CFeeBumper::signTransaction(CWallet *pWallet)\n{\n    for (auto accountPair : pWallet->mapAccounts)\n    {\n        if (pWallet->SignTransaction(accountPair.second, mtx, Spend))\n            return true;\n    }\n    return false;\n}\n\nbool CFeeBumper::commit(CWallet *pWallet)\n{\n    AssertLockHeld(pWallet->cs_wallet);\n    if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {\n        return false;\n    }\n    if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {\n        vErrors.push_back(\"Invalid or non-wallet transaction id\");\n        currentResult = BumpFeeResult::MISC_ERROR;\n        return false;\n    }\n    CWalletTx& oldWtx = pWallet->mapWallet[txid];\n\n    // make sure the transaction still has no descendants and hasn't been mined in the meantime\n    if (!preconditionChecks(pWallet, oldWtx)) {\n        return false;\n    }\n\n    CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));\n    // commit/broadcast the tx\n    CReserveKeyOrScript reservekey(pWallet, pWallet->mapAccounts[getUUIDFromString(oldWtx.strFromAccount)], KEYCHAIN_CHANGE);\n    wtxBumped.mapValue = oldWtx.mapValue;\n    wtxBumped.mapValue[\"replaces_txid\"] = oldWtx.GetHash().ToString();\n    wtxBumped.vOrderForm = oldWtx.vOrderForm;\n    wtxBumped.strFromAccount = oldWtx.strFromAccount;\n    wtxBumped.fTimeReceivedIsTxTime = true;\n    wtxBumped.fFromMe = true;\n    CValidationState state;\n    if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {\n        // NOTE: CommitTransaction never returns false, so this should never happen.\n        vErrors.push_back(strprintf(\"Error: The transaction was rejected! Reason given: %s\", state.GetRejectReason()));\n        return false;\n    }\n\n    bumpedTxid = wtxBumped.GetHash();\n    if (state.IsInvalid()) {\n        // This can happen if the mempool rejected the transaction.  Report\n        // what happened in the \"errors\" response.\n        vErrors.push_back(strprintf(\"Error: The transaction was rejected: %s\", FormatStateMessage(state)));\n    }\n\n    // mark the original tx as bumped\n    if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {\n        // TODO: see if JSON-RPC has a standard way of returning a response\n        // along with an exception. It would be good to return information about\n        // wtxBumped to the caller even if marking the original transaction\n        // replaced does not succeed for some reason.\n        vErrors.push_back(\"Error: Created new bumpfee transaction but could not mark the original transaction as replaced.\");\n    }\n    return true;\n}\n\n"
  },
  {
    "path": "src/wallet/feebumper.h",
    "content": "// Copyright (c) 2017 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef WALLET_FEEBUMPER_H\n#define WALLET_FEEBUMPER_H\n\n#include <primitives/transaction.h>\n\nclass CWallet;\nclass CWalletTx;\nclass uint256;\n\nenum class BumpFeeResult\n{\n    OK,\n    INVALID_ADDRESS_OR_KEY,\n    INVALID_REQUEST,\n    INVALID_PARAMETER,\n    WALLET_ERROR,\n    MISC_ERROR,\n};\n\nextern int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet);\n\nclass CFeeBumper\n{\npublic:\n    CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, int newConfirmTarget, bool ignoreGlobalPayTxFee, CAmount totalFee, bool newTxReplaceable);\n    BumpFeeResult getResult() const { return currentResult; }\n    const std::vector<std::string>& getErrors() const { return vErrors; }\n    CAmount getOldFee() const { return nOldFee; }\n    CAmount getNewFee() const { return nNewFee; }\n    uint256 getBumpedTxId() const { return bumpedTxid; }\n\n    /* signs the new transaction,\n     * returns false if the tx couldn't be found or if it was\n     * impossible to create the signature(s)\n     */\n    bool signTransaction(CWallet *pWallet);\n\n    /* commits the fee bump,\n     * returns true, in case of CWallet::CommitTransaction was successful\n     * but, eventually sets vErrors if the tx could not be added to the mempool (will try later)\n     * or if the old transaction could not be marked as replaced\n     */\n    bool commit(CWallet *pWalletNonConst);\n\nprivate:\n    bool preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx);\n\n    const uint256 txid;\n    uint256 bumpedTxid;\n    CAmount nOldFee;\n    CAmount nNewFee;\n    CMutableTransaction mtx;\n    std::vector<std::string> vErrors;\n    BumpFeeResult currentResult;\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/merkletx.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"wallet/merkletx.h\"\n#include \"validation/validation.h\" //cs_main\n#include <consensus/consensus.h>\n#include \"witnessutil.h\"\n\nconst uint256 CMerkleTx::ABANDON_HASH(uint256S(\"0000000000000000000000000000000000000000000000000000000000000001\"));\n\nvoid CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)\n{\n    // Update the tx's hashBlock\n    hashBlock = pindex->GetBlockHashPoW2();\n\n    // Record block height and timestamp\n    nHeight = pindex->nHeight;\n    nBlockTime = pindex->nTime;\n\n    // set the position of the transaction in the block\n    nIndex = posInBlock;\n}\n\nint CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const\n{\n    if (hashUnset())\n        return 0;\n\n    AssertLockHeld(cs_main);\n\n    // Find the block it claims to be in\n    BlockMap::iterator mi = mapBlockIndex.find(hashBlock);\n    if (mi != mapBlockIndex.end())\n    {\n\n        CBlockIndex* pindex = (*mi).second;\n        if (pindex == nullptr)\n            return 0;\n\n        pindexRet = pindex;\n        bool conflicts = nIndex == -1 || !(chainActive.Contains(pindex) || partialChain.Contains(pindex));\n        CChain& chain = IsPartialSyncActive() && partialChain.Height() > chainActive.Height() ? partialChain : chainActive;\n        return (conflicts ? (-1) : 1) * (chain.Height() - pindex->nHeight + 1);\n    }\n    else\n    {\n        // fall back to using nHeight, only allowed in spv/partial sync\n        if (IsPartialSyncActive() && nHeight >= 0)\n        {\n\n            pindexRet = nullptr;\n\n            // tx conflicts if it was abandoned or block is orphaned which is detected here if the tx height >= partial chain offset\n            // and the block is not in the index so it must have been purged by spv\n            bool conflicts = nIndex == -1 || nHeight >= partialChain.HeightOffset();\n            return (conflicts ? (-1) : 1) * (partialChain.Height() - nHeight + 1);\n        }\n        else\n            return 0;\n    }\n}\n\nint CMerkleTx::GetBlocksToMaturity() const\n{\n    if (!IsCoinBase())\n        return 0;\n    return std::max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());\n}\n\n\nbool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)\n{\n    return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee);\n}\n"
  },
  {
    "path": "src/wallet/merkletx.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_MERKLETX_H\n#define WALLET_MERKLETX_H\n\n#include <uint256.h>\n#include \"chain.h\"\n#include <primitives/transaction.h>\n\nclass CValidationState;\n\n/** A transaction with a merkle branch linking it to the block chain. */\nclass CMerkleTx\n{\nprivate:\n  /** Constant used in hashBlock to indicate tx has been abandoned */\n    static const uint256 ABANDON_HASH;\n\npublic:\n    CTransactionRef tx;\n    uint256 hashBlock;\n\n    /*\n     * nHeight introduced in 2.1 for SPV. In pure SPV we don't have the full block index\n     * and so the height cannot be found using hashBlock.\n     * nHeight < 0, blockheight unkown\n     */\n    int nHeight;\n\n    /* Copy of the timestamp of the block the transaction is in, if any.\n     * Recorded together with nHeight, only valid if > 0\n     * Intended use when block not available, ie. it has been pruned from the index in SPV\n     */\n    unsigned int nBlockTime;\n\n    /* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest\n     * block in the chain we know this or any in-wallet dependency conflicts\n     * with. Older clients interpret nIndex == -1 as unconfirmed for backward\n     * compatibility.\n     */\n    int nIndex;\n\n    CMerkleTx()\n    {\n        SetTx(MakeTransactionRef(CTransaction::MAX_STANDARD_VERSION));\n        Init();\n    }\n\n    CMerkleTx(CTransactionRef arg)\n    {\n        SetTx(std::move(arg));\n        Init();\n    }\n\n    /** Helper conversion operator to allow passing CMerkleTx where CTransaction is expected.\n     *  TODO: adapt callers and remove this operator. */\n    operator const CTransaction&() const { return *tx; }\n\n    void Init()\n    {\n        hashBlock = uint256();\n        nIndex = -1;\n        nHeight = -1;\n        nBlockTime = 0;\n    }\n\n    void SetTx(CTransactionRef arg)\n    {\n        tx = std::move(arg);\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action)\n    {\n        std::vector<uint256> vMerkleBranch; // For compatibility with older versions.\n        READWRITE(tx);\n        READWRITE(hashBlock);\n\n        // From 2.1 (mobile unity wallets) and 2.2 (desktop wallets) we introduce block height and time for transactions.\n        if ( (s.GetType() & SER_DISK) && (s.GetVersion() >= 2020000))\n        {\n            READWRITE(nHeight);\n            READWRITE(nBlockTime);\n        }\n\n        READWRITECOMPACTSIZEVECTOR(vMerkleBranch);\n        READWRITE(nIndex);\n    }\n\n    void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);\n\n    /**\n     * Return depth of transaction in blockchain:\n     * <0  : conflicts with a transaction this deep in the blockchain\n     *  0  : in memory pool, waiting to be included in a block\n     * >=1 : this many blocks deep in the main chain\n     */\n    int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;\n    int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }\n    bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }\n    int GetBlocksToMaturity() const;\n    /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */\n    bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);\n    bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }\n    bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }\n    void setAbandoned() { hashBlock = ABANDON_HASH; }\n\n    const uint256& GetHash() const { return tx->GetHash(); }\n    bool IsCoinBase() const { return tx->IsCoinBase(); }\n    bool IsPoW2WitnessCoinBase() const { return tx->IsPoW2WitnessCoinBase(); }\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/mnemonic.cpp",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"mnemonic.h\"\n#include \"arith_uint256.h\"\n\n#include <crypto/hash/scrypt.h>\n#include <crypto/hash/hash.h>\n\n#include <bitset>\n#include <sstream>\n#include <iterator>\n#include \"util/strencodings.h\"\n\n\nconst char* wordList[] = {\n\"abandon\", \"ability\", \"able\", \"about\", \"above\", \"absent\", \"absorb\", \"abstract\", \"absurd\", \"abuse\", \"access\", \"accident\", \"account\", \"accuse\", \"achieve\", \"acid\", \"acoustic\", \"acquire\", \n\"across\", \"act\", \"action\", \"actor\", \"actress\", \"actual\", \"adapt\", \"add\", \"addict\", \"address\", \"adjust\", \"admit\", \"adult\", \"advance\", \"advice\", \"aerobic\", \"affair\", \"afford\", \"afraid\", \n\"again\", \"age\", \"agent\", \"agree\", \"ahead\", \"aim\", \"air\", \"airport\", \"aisle\", \"alarm\", \"album\", \"alcohol\", \"alert\", \"alien\", \"all\", \"alley\", \"allow\", \"almost\", \"alone\", \"alpha\", \n\"already\", \"also\", \"alter\", \"always\", \"amateur\", \"amazing\", \"among\", \"amount\", \"amused\", \"analyst\", \"anchor\", \"ancient\", \"anger\", \"angle\", \"angry\", \"animal\", \"ankle\", \"announce\", \n\"annual\", \"another\", \"answer\", \"antenna\", \"antique\", \"anxiety\", \"any\", \"apart\", \"apology\", \"appear\", \"apple\", \"approve\", \"april\", \"arch\", \"arctic\", \"area\", \"arena\", \"argue\", \"arm\", \n\"armed\", \"armor\", \"army\", \"around\", \"arrange\", \"arrest\", \"arrive\", \"arrow\", \"art\", \"artefact\", \"artist\", \"artwork\", \"ask\", \"aspect\", \"assault\", \"asset\", \"assist\", \"assume\", \"asthma\", \n\"athlete\", \"atom\", \"attack\", \"attend\", \"attitude\", \"attract\", \"auction\", \"audit\", \"august\", \"aunt\", \"author\", \"auto\", \"autumn\", \"average\", \"avocado\", \"avoid\", \"awake\", \"aware\", \"away\", \n\"awesome\", \"awful\", \"awkward\", \"axis\", \"baby\", \"bachelor\", \"bacon\", \"badge\", \"bag\", \"balance\", \"balcony\", \"ball\", \"bamboo\", \"banana\", \"banner\", \"bar\", \"barely\", \"bargain\",\n\"barrel\", \"base\", \"basic\", \"basket\", \"battle\", \"beach\", \"bean\", \"beauty\", \"because\", \"become\", \"beef\", \"before\", \"begin\", \"behave\", \"behind\", \"believe\", \"below\", \"belt\", \"bench\", \n\"benefit\", \"best\", \"betray\", \"better\", \"between\", \"beyond\", \"bicycle\", \"bid\", \"bike\", \"bind\", \"biology\", \"bird\", \"birth\", \"bitter\", \"black\", \"blade\", \"blame\", \"blanket\", \"blast\", \n\"bleak\", \"bless\", \"blind\", \"blood\", \"blossom\", \"blouse\", \"blue\", \"blur\", \"blush\", \"board\", \"boat\", \"body\", \"boil\", \"bomb\", \"bone\", \"bonus\", \"book\", \"boost\", \"border\", \"boring\", \n\"borrow\", \"boss\", \"bottom\", \"bounce\", \"box\", \"boy\", \"bracket\", \"brain\", \"brand\", \"brass\", \"brave\", \"bread\", \"breeze\", \"brick\", \"bridge\", \"brief\", \"bright\", \"bring\", \"brisk\", \n\"broccoli\", \"broken\", \"bronze\", \"broom\", \"brother\", \"brown\", \"brush\", \"bubble\", \"buddy\", \"budget\", \"buffalo\", \"build\", \"bulb\", \"bulk\", \"bullet\", \"bundle\", \"bunker\", \"burden\", \n\"burger\", \"burst\", \"bus\", \"business\", \"busy\", \"butter\", \"buyer\", \"buzz\", \"cabbage\", \"cabin\", \"cable\", \"cactus\", \"cage\", \"cake\", \"call\", \"calm\", \"camera\", \"camp\", \"can\", \"canal\", \n\"cancel\", \"candy\", \"cannon\", \"canoe\", \"canvas\", \"canyon\", \"capable\", \"capital\", \"captain\", \"car\", \"carbon\", \"card\", \"cargo\", \"carpet\", \"carry\", \"cart\", \"case\", \"cash\", \"casino\", \"castle\", \"casual\",\n\"cat\", \"catalog\", \"catch\", \"category\", \"cattle\", \"caught\", \"cause\", \"caution\", \"cave\", \"ceiling\", \"celery\", \"cement\", \"census\", \"century\", \"cereal\", \"certain\", \"chair\", \"chalk\", \"champion\", \n\"change\", \"chaos\", \"chapter\", \"charge\", \"chase\", \"chat\", \"cheap\", \"check\", \"cheese\", \"chef\", \"cherry\", \"chest\", \"chicken\", \"chief\", \"child\", \"chimney\", \"choice\", \"choose\", \"chronic\", \"chuckle\", \n\"chunk\", \"churn\", \"cigar\", \"cinnamon\", \"circle\", \"citizen\", \"city\", \"civil\", \"claim\", \"clap\", \"clarify\", \"claw\", \"clay\", \"clean\", \"clerk\", \"clever\", \"click\", \"client\", \"cliff\", \"climb\", \"clinic\", \n\"clip\", \"clock\", \"clog\", \"close\", \"cloth\", \"cloud\", \"clown\", \"club\", \"clump\", \"cluster\", \"clutch\", \"coach\", \"coast\", \"coconut\", \"code\", \"coffee\", \"coil\", \"coin\", \"collect\", \"color\", \"column\", \n\"combine\", \"come\", \"comfort\", \"comic\", \"common\", \"company\", \"concert\", \"conduct\", \"confirm\", \"congress\", \"connect\", \"consider\", \"control\", \"convince\", \"cook\", \"cool\", \"copper\", \"copy\", \"coral\",\n\"core\", \"corn\", \"correct\", \"cost\", \"cotton\", \"couch\", \"country\", \"couple\", \"course\", \"cousin\", \"cover\", \"coyote\", \"crack\", \"cradle\", \"craft\", \"cram\", \"crane\", \"crash\", \"crater\", \"crawl\", \"crazy\", \n\"cream\", \"credit\", \"creek\", \"crew\", \"cricket\", \"crime\", \"crisp\", \"critic\", \"crop\", \"cross\", \"crouch\", \"crowd\", \"crucial\", \"cruel\", \"cruise\", \"crumble\", \"crunch\", \"crush\", \"cry\", \n\"crystal\", \"cube\", \"culture\", \"cup\", \"cupboard\", \"curious\", \"current\", \"curtain\", \"curve\", \"cushion\", \"custom\", \"cute\", \"cycle\", \"dad\", \"damage\", \"damp\", \"dance\", \"danger\", \"daring\", \"dash\", \n\"daughter\", \"dawn\", \"day\", \"deal\", \"debate\", \"debris\", \"decade\", \"december\", \"decide\", \"decline\", \"decorate\", \"decrease\", \"deer\", \"defense\", \"define\", \"defy\", \"degree\", \"delay\", \"deliver\", \"demand\", \n\"demise\", \"denial\", \"dentist\", \"deny\", \"depart\", \"depend\", \"deposit\", \"depth\", \"deputy\", \"derive\", \"describe\", \"desert\", \"design\", \"desk\", \"despair\", \"destroy\", \"detail\", \"detect\", \"develop\", \n\"device\",\"devote\", \"diagram\", \"dial\", \"diamond\", \"diary\", \"dice\", \"diesel\", \"diet\", \"differ\", \"digital\", \"dignity\", \"dilemma\", \"dinner\", \"dinosaur\", \"direct\", \"dirt\", \"disagree\", \"discover\", \"disease\", \n\"dish\", \"dismiss\", \"disorder\", \"display\", \"distance\", \"divert\", \"divide\", \"divorce\", \"dizzy\", \"doctor\", \"document\", \"dog\", \"doll\", \"dolphin\", \"domain\", \"donate\", \"donkey\", \"donor\", \"door\", \"dose\", \n\"double\", \"dove\", \"draft\", \"dragon\", \"drama\", \"drastic\", \"draw\", \"dream\", \"dress\", \"drift\", \"drill\", \"drink\", \"drip\", \"drive\", \"drop\", \"drum\", \"dry\", \"duck\", \"dumb\", \"dune\", \"during\", \"dust\", \"dutch\", \n\"duty\", \"dwarf\", \"dynamic\", \"eager\", \"eagle\", \"early\", \"earn\", \"earth\", \"easily\", \"east\", \"easy\", \"echo\", \"ecology\", \"economy\", \"edge\", \"edit\", \"educate\", \"effort\", \"egg\", \"eight\", \"either\", \"elbow\", \n\"elder\", \"electric\", \"elegant\", \"element\", \"elephant\", \"elevator\", \"elite\", \"else\", \"embark\", \"embody\", \"embrace\", \"emerge\", \"emotion\", \"employ\", \"empower\", \"empty\", \"enable\", \"enact\", \"end\", \"endless\", \n\"endorse\", \"enemy\", \"energy\", \"enforce\", \"engage\", \"engine\", \"enhance\", \"enjoy\", \"enlist\", \"enough\", \"enrich\", \"enroll\", \"ensure\", \"enter\", \"entire\", \"entry\", \"envelope\", \"episode\", \"equal\", \"equip\", \n\"era\", \"erase\", \"erode\", \"erosion\", \"error\", \"erupt\", \"escape\", \"essay\", \"essence\", \"estate\", \"eternal\", \"ethics\", \"evidence\", \"evil\", \"evoke\", \"evolve\", \"exact\", \"example\", \"excess\", \"exchange\", \n\"excite\", \"exclude\", \"excuse\", \"execute\", \"exercise\", \"exhaust\", \"exhibit\", \"exile\", \"exist\", \"exit\", \"exotic\", \"expand\", \"expect\", \"expire\", \"explain\", \"expose\", \"express\", \"extend\", \"extra\", \"eye\", \n\"eyebrow\", \"fabric\", \"face\", \"faculty\", \"fade\", \"faint\", \"faith\", \"fall\", \"false\", \"fame\", \"family\", \"famous\", \"fan\", \"fancy\", \"fantasy\", \"farm\", \"fashion\", \"fat\", \"fatal\", \"father\", \"fatigue\", \"fault\", \n\"favorite\", \"feature\", \"february\", \"federal\", \"fee\", \"feed\", \"feel\", \"female\", \"fence\", \"festival\", \"fetch\", \"fever\", \"few\", \"fiber\", \"fiction\", \"field\", \"figure\", \"file\", \"film\", \"filter\", \"final\", \"find\",\n\"fine\", \"finger\", \"finish\", \"fire\", \"firm\", \"first\", \"fiscal\", \"fish\", \"fit\", \"fitness\", \"fix\", \"flag\", \"flame\", \"flash\", \"flat\", \"flavor\", \"flee\", \"flight\", \"flip\", \"float\", \"flock\", \"floor\", \"flower\", \n\"fluid\", \"flush\", \"fly\", \"foam\", \"focus\", \"fog\", \"foil\", \"fold\", \"follow\", \"food\", \"foot\", \"force\", \"forest\", \"forget\", \"fork\", \"fortune\", \"forum\", \"forward\", \"fossil\", \"foster\", \"found\", \"fox\", \n\"fragile\", \"frame\", \"frequent\", \"fresh\", \"friend\", \"fringe\", \"frog\", \"front\", \"frost\", \"frown\", \"frozen\", \"fruit\", \"fuel\", \"fun\", \"funny\", \"furnace\", \"fury\", \"future\", \"gadget\", \"gain\", \n\"galaxy\", \"gallery\", \"game\", \"gap\", \"garage\", \"garbage\", \"garden\", \"garlic\", \"garment\", \"gas\", \"gasp\", \"gate\", \"gather\", \"gauge\", \"gaze\", \"general\", \"genius\", \"genre\", \"gentle\", \"genuine\", \"gesture\", \n\"ghost\", \"giant\", \"gift\", \"giggle\", \"ginger\", \"giraffe\", \"girl\", \"give\", \"glad\", \"glance\", \"glare\", \"glass\", \"glide\", \"glimpse\", \"globe\", \"gloom\", \"glory\", \"glove\", \"glow\", \"glue\", \"goat\", \"goddess\", \n\"gold\", \"good\", \"goose\", \"gorilla\", \"gospel\", \"gossip\", \"govern\", \"gown\", \"grab\", \"grace\", \"grain\", \"grant\", \"grape\", \"grass\", \"gravity\", \"great\", \"green\", \"grid\", \"grief\", \"grit\", \"grocery\", \"group\", \n\"grow\", \"grunt\", \"guard\", \"guess\", \"guide\", \"guilt\", \"guitar\", \"gun\", \"gym\", \"habit\", \"hair\", \"half\", \"hammer\", \"hamster\", \"hand\", \"happy\", \"harbor\", \"hard\", \"harsh\", \"harvest\", \"hat\", \"have\", \"hawk\",\n\"hazard\", \"head\", \"health\", \"heart\", \"heavy\", \"hedgehog\", \"height\", \"hello\", \"helmet\", \"help\", \"hen\", \"hero\", \"hidden\", \"high\", \"hill\", \"hint\", \"hip\", \"hire\", \"history\", \"hobby\", \"hockey\", \"hold\", \n\"hole\", \"holiday\", \"hollow\", \"home\", \"honey\", \"hood\", \"hope\", \"horn\", \"horror\", \"horse\", \"hospital\", \"host\", \"hotel\", \"hour\", \"hover\", \"hub\", \"huge\", \"human\", \"humble\", \"humor\", \"hundred\", \"hungry\", \n\"hunt\", \"hurdle\", \"hurry\", \"hurt\", \"husband\", \"hybrid\", \"ice\", \"icon\", \"idea\", \"identify\", \"idle\", \"ignore\", \"ill\", \"illegal\", \"illness\", \"image\", \"imitate\", \"immense\", \"immune\", \"impact\", \"impose\", \n\"improve\", \"impulse\", \"inch\", \"include\", \"income\", \"increase\", \"index\", \"indicate\", \"indoor\", \"industry\", \"infant\", \"inflict\", \"inform\", \"inhale\", \"inherit\", \"initial\", \"inject\", \"injury\", \"inmate\", \n\"inner\", \"innocent\", \"input\", \"inquiry\", \"insane\", \"insect\", \"inside\", \"inspire\", \"install\", \"intact\", \"interest\", \"into\", \"invest\", \"invite\", \"involve\", \"iron\", \"island\", \"isolate\", \"issue\", \"item\", \n\"ivory\", \"jacket\", \"jaguar\", \"jar\", \"jazz\", \"jealous\", \"jeans\", \"jelly\", \"jewel\", \"job\", \"join\", \"joke\", \"journey\", \"joy\", \"judge\", \"juice\", \"jump\", \"jungle\", \"junior\", \"junk\", \"just\", \"kangaroo\", \"keen\", \n\"keep\", \"ketchup\", \"key\", \"kick\", \"kid\", \"kidney\", \"kind\", \"kingdom\", \"kiss\", \"kit\", \"kitchen\", \"kite\", \"kitten\", \"kiwi\", \"knee\", \"knife\", \"knock\", \"know\", \"lab\", \"label\", \"labor\", \"ladder\", \"lady\", \"lake\", \n\"lamp\", \"language\", \"laptop\", \"large\", \"later\", \"latin\", \"laugh\", \"laundry\", \"lava\", \"law\", \"lawn\", \"lawsuit\", \"layer\", \"lazy\", \"leader\", \"leaf\", \"learn\", \"leave\", \"lecture\", \"left\", \"leg\", \"legal\", \"legend\", \n\"leisure\", \"lemon\", \"lend\", \"length\", \"lens\", \"leopard\", \"lesson\", \"letter\", \"level\", \"liar\", \"liberty\", \"library\", \"license\", \"life\", \"lift\", \"light\", \"like\", \"limb\", \"limit\", \"link\", \"lion\", \"liquid\", \n\"list\", \"little\", \"live\", \"lizard\", \"load\", \"loan\", \"lobster\", \"local\", \"lock\", \"logic\", \"lonely\", \"long\", \"loop\", \"lottery\", \"loud\", \"lounge\", \"love\", \"loyal\", \"lucky\", \"luggage\", \"lumber\", \"lunar\", \n\"lunch\", \"luxury\", \"lyrics\", \"machine\", \"mad\", \"magic\", \"magnet\", \"maid\", \"mail\", \"main\", \"major\", \"make\", \"mammal\", \"man\", \"manage\", \"mandate\", \"mango\", \"mansion\", \"manual\", \"maple\", \"marble\", \"march\", \n\"margin\", \"marine\", \"market\", \"marriage\", \"mask\", \"mass\", \"master\", \"match\", \"material\", \"math\", \"matrix\", \"matter\", \"maximum\", \"maze\", \"meadow\", \"mean\", \"measure\", \"meat\", \"mechanic\", \"medal\", \"media\", \n\"melody\", \"melt\", \"member\", \"memory\", \"mention\", \"menu\", \"mercy\", \"merge\", \"merit\", \"merry\", \"mesh\", \"message\", \"metal\", \"method\", \"middle\", \"midnight\", \"milk\", \"million\", \"mimic\", \"mind\", \"minimum\", \n\"minor\", \"minute\", \"miracle\", \"mirror\", \"misery\", \"miss\", \"mistake\", \"mix\", \"mixed\", \"mixture\", \"mobile\", \"model\", \"modify\", \"mom\", \"moment\", \"monitor\", \"monkey\", \"monster\", \"month\", \"moon\", \"moral\", \n\"more\", \"morning\", \"mosquito\", \"mother\", \"motion\", \"motor\", \"mountain\", \"mouse\", \"move\", \"movie\", \"much\", \"muffin\", \"mule\", \"multiply\", \"muscle\", \"museum\", \"mushroom\", \"music\", \"must\", \"mutual\", \n\"myself\", \"mystery\", \"myth\", \"naive\", \"name\", \"napkin\", \"narrow\", \"nasty\", \"nation\", \"nature\", \"near\", \"neck\", \"need\", \"negative\", \"neglect\", \"neither\", \"nephew\", \"nerve\", \"nest\", \"net\", \"network\", \n\"neutral\", \"never\", \"news\", \"next\", \"nice\", \"night\", \"noble\", \"noise\", \"nominee\", \"noodle\", \"normal\", \"north\", \"nose\", \"notable\", \"note\", \"nothing\", \"notice\", \"novel\", \"now\", \"nuclear\", \"number\", \n\"nurse\", \"nut\", \"oak\", \"obey\", \"object\", \"oblige\", \"obscure\", \"observe\", \"obtain\", \"obvious\", \"occur\", \"ocean\", \"october\", \"odor\", \"off\", \"offer\", \"office\", \"often\", \"oil\", \"okay\", \"old\", \"olive\", \n\"olympic\", \"omit\", \"once\", \"one\", \"onion\", \"online\", \"only\", \"open\", \"opera\", \"opinion\", \"oppose\", \"option\", \"orange\", \"orbit\", \"orchard\", \"order\", \"ordinary\", \"organ\", \"orient\", \"original\", \"orphan\", \n\"ostrich\", \"other\", \"outdoor\", \"outer\", \"output\", \"outside\", \"oval\", \"oven\", \"over\", \"own\", \"owner\", \"oxygen\", \"oyster\", \"ozone\", \"pact\", \"paddle\", \"page\", \"pair\", \"palace\", \"palm\", \"panda\", \"panel\", \n\"panic\", \"panther\", \"paper\", \"parade\", \"parent\", \"park\", \"parrot\", \"party\", \"pass\", \"patch\", \"path\", \"patient\", \"patrol\", \"pattern\", \"pause\", \"pave\", \"payment\", \"peace\", \"peanut\", \"pear\", \"peasant\",\n\"pelican\", \"pen\", \"penalty\", \"pencil\", \"people\", \"pepper\", \"perfect\", \"permit\", \"person\", \"pet\", \"phone\", \"photo\", \"phrase\", \"physical\", \"piano\", \"picnic\", \"picture\", \"piece\", \"pig\", \"pigeon\", \"pill\",\n\"pilot\", \"pink\", \"pioneer\", \"pipe\", \"pistol\", \"pitch\", \"pizza\", \"place\", \"planet\", \"plastic\", \"plate\", \"play\", \"please\", \"pledge\", \"pluck\", \"plug\", \"plunge\", \"poem\", \"poet\", \"point\", \"polar\", \"pole\", \n\"police\", \"pond\", \"pony\", \"pool\", \"popular\", \"portion\", \"position\", \"possible\", \"post\", \"potato\", \"pottery\", \"poverty\", \"powder\", \"power\", \"practice\", \"praise\", \"predict\", \"prefer\", \"prepare\", \"present\", \n\"pretty\", \"prevent\", \"price\", \"pride\", \"primary\", \"print\", \"priority\", \"prison\", \"private\", \"prize\", \"problem\", \"process\", \"produce\", \"profit\", \"program\", \"project\", \"promote\", \"proof\", \"property\", \n\"prosper\", \"protect\", \"proud\", \"provide\", \"public\", \"pudding\", \"pull\", \"pulp\", \"pulse\", \"pumpkin\", \"punch\", \"pupil\", \"puppy\", \"purchase\", \"purity\", \"purpose\", \"purse\", \"push\", \"put\", \"puzzle\", \n\"pyramid\", \"quality\", \"quantum\", \"quarter\", \"question\", \"quick\", \"quit\", \"quiz\", \"quote\", \"rabbit\", \"raccoon\", \"race\", \"rack\", \"radar\", \"radio\", \"rail\", \"rain\", \"raise\", \"rally\", \"ramp\", \"ranch\", \n\"random\", \"range\", \"rapid\", \"rare\", \"rate\", \"rather\", \"raven\", \"raw\", \"razor\", \"ready\", \"real\", \"reason\", \"rebel\", \"rebuild\", \"recall\", \"receive\", \"recipe\", \"record\", \"recycle\", \"reduce\", \n\"reflect\", \"reform\", \"refuse\", \"region\", \"regret\", \"regular\", \"reject\", \"relax\", \"release\", \"relief\", \"rely\", \"remain\", \"remember\", \"remind\", \"remove\", \"render\", \"renew\", \"rent\", \"reopen\", \n\"repair\", \"repeat\", \"replace\", \"report\", \"require\", \"rescue\", \"resemble\", \"resist\", \"resource\", \"response\", \"result\", \"retire\", \"retreat\", \"return\", \"reunion\", \"reveal\", \"review\", \"reward\", \n\"rhythm\", \"rib\", \"ribbon\", \"rice\", \"rich\", \"ride\", \"ridge\", \"rifle\", \"right\", \"rigid\", \"ring\", \"riot\", \"ripple\", \"risk\", \"ritual\", \"rival\", \"river\", \"road\", \"roast\", \"robot\", \"robust\", \"rocket\", \n\"romance\", \"roof\", \"rookie\", \"room\", \"rose\", \"rotate\", \"rough\", \"round\", \"route\", \"royal\", \"rubber\", \"rude\", \"rug\", \"rule\", \"run\", \"runway\", \"rural\", \"sad\", \"saddle\", \"sadness\", \"safe\", \n\"sail\", \"salad\", \"salmon\", \"salon\", \"salt\", \"salute\", \"same\", \"sample\", \"sand\", \"satisfy\", \"satoshi\", \"sauce\", \"sausage\", \"save\", \"say\", \"scale\", \"scan\", \"scare\", \"scatter\", \"scene\", \"scheme\", \n\"school\", \"science\", \"scissors\", \"scorpion\", \"scout\", \"scrap\", \"screen\", \"script\", \"scrub\", \"sea\", \"search\", \"season\", \"seat\", \"second\", \"secret\", \"section\", \"security\", \"seed\", \"seek\", \"segment\", \n\"select\", \"sell\", \"seminar\", \"senior\", \"sense\", \"sentence\", \"series\", \"service\", \"session\", \"settle\", \"setup\", \"seven\", \"shadow\", \"shaft\", \"shallow\", \"share\", \"shed\", \"shell\", \"sheriff\", \"shield\", \n\"shift\", \"shine\", \"ship\", \"shiver\", \"shock\", \"shoe\", \"shoot\", \"shop\", \"short\", \"shoulder\", \"shove\", \"shrimp\", \"shrug\", \"shuffle\", \"shy\", \"sibling\", \"sick\", \"side\", \"siege\", \"sight\", \"sign\", \"silent\", \n\"silk\", \"silly\", \"silver\", \"similar\", \"simple\", \"since\", \"sing\", \"siren\", \"sister\", \"situate\", \"six\", \"size\", \"skate\", \"sketch\", \"ski\", \"skill\", \"skin\", \"skirt\", \"skull\", \"slab\", \"slam\", \n\"sleep\", \"slender\", \"slice\", \"slide\", \"slight\", \"slim\", \"slogan\", \"slot\", \"slow\", \"slush\", \"small\", \"smart\", \"smile\", \"smoke\", \"smooth\", \"snack\", \"snake\", \"snap\", \"sniff\", \"snow\", \"soap\", \n\"soccer\", \"social\", \"sock\", \"soda\", \"soft\", \"solar\", \"soldier\", \"solid\", \"solution\", \"solve\", \"someone\", \"song\", \"soon\", \"sorry\", \"sort\", \"soul\", \"sound\", \"soup\", \"source\", \"south\", \"space\", \n\"spare\", \"spatial\", \"spawn\", \"speak\", \"special\", \"speed\", \"spell\", \"spend\", \"sphere\", \"spice\", \"spider\", \"spike\", \"spin\", \"spirit\", \"split\", \"spoil\", \"sponsor\", \"spoon\", \"sport\", \"spot\", \"spray\", \n\"spread\", \"spring\", \"spy\", \"square\", \"squeeze\", \"squirrel\", \"stable\", \"stadium\", \"staff\", \"stage\", \"stairs\", \"stamp\", \"stand\", \"start\", \"state\", \"stay\", \"steak\", \"steel\", \"stem\", \"step\", \"stereo\", \n\"stick\", \"still\", \"sting\", \"stock\", \"stomach\", \"stone\", \"stool\", \"story\", \"stove\", \"strategy\", \"street\", \"strike\", \"strong\", \"struggle\", \"student\", \"stuff\", \"stumble\", \"style\", \"subject\", \"submit\", \n\"subway\", \"success\", \"such\", \"sudden\", \"suffer\", \"sugar\", \"suggest\", \"suit\", \"summer\", \"sun\", \"sunny\", \"sunset\", \"super\", \"supply\", \"supreme\", \"sure\", \"surface\", \"surge\", \"surprise\", \"surround\", \n\"survey\", \"suspect\", \"sustain\", \"swallow\", \"swamp\", \"swap\", \"swarm\", \"swear\", \"sweet\", \"swift\", \"swim\", \"swing\", \"switch\", \"sword\", \"symbol\", \"symptom\", \"syrup\", \"system\", \"table\", \"tackle\", \"tag\", \n\"tail\", \"talent\", \"talk\", \"tank\", \"tape\", \"target\", \"task\", \"taste\", \"tattoo\", \"taxi\", \"teach\", \"team\", \"tell\", \"ten\", \"tenant\", \"tennis\", \"tent\", \"term\", \"test\", \"text\", \"thank\", \"that\", \"theme\", \n\"then\", \"theory\", \"there\", \"they\", \"thing\", \"this\", \"thought\", \"three\", \"thrive\", \"throw\", \"thumb\", \"thunder\", \"ticket\", \"tide\", \"tiger\", \"tilt\", \"timber\", \"time\", \"tiny\", \"tip\", \"tired\", \"tissue\", \n\"title\", \"toast\", \"tobacco\", \"today\", \"toddler\", \"toe\", \"together\", \"toilet\", \"token\", \"tomato\", \"tomorrow\", \"tone\", \"tongue\", \"tonight\", \"tool\", \"tooth\", \"top\", \"topic\", \"topple\", \"torch\", \n\"tornado\", \"tortoise\", \"toss\", \"total\", \"tourist\", \"toward\", \"tower\", \"town\", \"toy\", \"track\", \"trade\", \"traffic\", \"tragic\", \"train\", \"transfer\", \"trap\", \"trash\", \"travel\", \"tray\", \"treat\", \n\"tree\", \"trend\", \"trial\", \"tribe\", \"trick\", \"trigger\", \"trim\", \"trip\", \"trophy\", \"trouble\", \"truck\", \"true\", \"truly\", \"trumpet\", \"trust\", \"truth\", \"try\", \"tube\", \"tuition\", \"tumble\", \"tuna\", \n\"tunnel\", \"turkey\", \"turn\", \"turtle\", \"twelve\", \"twenty\", \"twice\", \"twin\", \"twist\", \"two\", \"type\", \"typical\", \"ugly\", \"umbrella\", \"unable\", \"unaware\", \"uncle\", \"uncover\", \"under\", \"undo\", \n\"unfair\", \"unfold\", \"unhappy\", \"uniform\", \"unique\", \"unit\", \"universe\", \"unknown\", \"unlock\", \"until\", \"unusual\", \"unveil\", \"update\", \"upgrade\", \"uphold\", \"upon\", \"upper\", \"upset\", \"urban\", \n\"urge\", \"usage\", \"use\", \"used\", \"useful\", \"useless\", \"usual\", \"utility\", \"vacant\", \"vacuum\", \"vague\", \"valid\", \"valley\", \"valve\", \"van\", \"vanish\", \"vapor\", \"various\", \"vast\", \"vault\", \"vehicle\", \n\"velvet\", \"vendor\", \"venture\", \"venue\", \"verb\", \"verify\", \"version\", \"very\", \"vessel\", \"veteran\", \"viable\", \"vibrant\", \"vicious\", \"victory\", \"video\", \"view\", \"village\", \"vintage\", \"violin\", \n\"virtual\", \"virus\", \"visa\", \"visit\", \"visual\", \"vital\", \"vivid\", \"vocal\", \"voice\", \"void\", \"volcano\", \"volume\", \"vote\", \"voyage\", \"wage\", \"wagon\", \"wait\", \"walk\", \"wall\", \"walnut\", \"want\", \n\"warfare\", \"warm\", \"warrior\", \"wash\", \"wasp\", \"waste\", \"water\", \"wave\", \"way\", \"wealth\", \"weapon\", \"wear\", \"weasel\", \"weather\", \"web\", \"wedding\", \"weekend\", \"weird\", \"welcome\", \"west\", \"wet\", \n\"whale\", \"what\", \"wheat\", \"wheel\", \"when\", \"where\", \"whip\", \"whisper\", \"wide\", \"width\", \"wife\", \"wild\", \"will\", \"win\", \"window\", \"wine\", \"wing\", \"wink\", \"winner\", \"winter\", \"wire\", \"wisdom\", \n\"wise\", \"wish\", \"witness\", \"wolf\", \"woman\", \"wonder\", \"wood\", \"wool\", \"word\", \"work\", \"world\", \"worry\", \"worth\", \"wrap\", \"wreck\", \"wrestle\", \"wrist\", \"write\", \"wrong\", \"yard\", \"year\", \"yellow\", \n\"you\", \"young\", \"youth\", \"zebra\", \"zero\", \"zone\", \"zoo\"};\n\n\nunsigned char* seedFromMnemonic(const SecureString& mnemonic, const SecureString& passphrase)\n{\n    SecureString salt = \"mnemonic\" + passphrase;\n    unsigned char* seed = new unsigned char[64];\n    PBKDF2_SHA512((char*)mnemonic.c_str(), mnemonic.length(), (unsigned char*)salt.c_str(), salt.length(), 2048, seed, 64);\n    return seed;\n}\n\nstd::vector<unsigned char> entropyFromMnemonic(const SecureString& mnemonic)\n{\n    std::vector<unsigned char> entropy;\n\n    std::stringstream ss(mnemonic.c_str());\n    std::istream_iterator<SecureString> begin(ss);\n    std::istream_iterator<SecureString> end;\n    std::vector<SecureString> mnemonicWords(begin, end);\n\n    // Word list must be minimum of 12 words, always a multiple of 3.\n    if (mnemonicWords.size() < 12 || mnemonicWords.size() % 3 > 0)\n        return std::vector<unsigned char>();\n\n    std::bitset<11> memoryWord;\n    int32_t wordIndex;\n    int32_t totalBitsRead=0;\n    unsigned char word=0;\n    for (const SecureString& mnemonicWord : mnemonicWords)\n    {\n        wordIndex = 0;\n        auto iter = std::find(std::begin(wordList), std::end(wordList), mnemonicWord);\n        if (iter == std::end(wordList))\n            return std::vector<unsigned char>();\n\n        wordIndex = iter - std::begin(wordList);\n        memoryWord = wordIndex;\n        for (unsigned int i = 0; i < 11; ++i)\n        {\n            word <<= 1;\n            if (memoryWord[10 - i])\n                word |= 0x1;\n            if (++totalBitsRead % 8 == 0)\n            {\n                entropy.push_back(word);\n                word = 0;\n            }\n        }\n    }\n    word <<= (8 - (totalBitsRead % 8));\n    entropy.push_back(word);\n\n    int checksumLengthBits = totalBitsRead / 33;\n    int entropyLengthBits = totalBitsRead - checksumLengthBits;\n    int entropyWords = entropyLengthBits / 8;\n\n    //Generate new checksum\n    uint32_t hash[8];\n    hash_sha256((unsigned char*)&entropy[0], entropyLengthBits/8, (unsigned char*)&hash[0]);\n\n    //Compare checksums\n    std::bitset<32> hashWord;\n    std::bitset<8> entropyWord;\n    for (int i=0; i < checksumLengthBits; ++i)\n    {\n        entropyWord = entropy[entropyWords + (i/8)];\n        hashWord = ReadBE32((const unsigned char*)&hash[i/32]);\n        if (hashWord[31 - i%32] !=  entropyWord[7 - i%8])\n            return std::vector<unsigned char>();\n    }\n    entropy.resize(entropyWords);\n    return entropy;\n}\n\nSecureString mnemonicFromEntropy(std::vector<unsigned char> entropyIn, int entropySizeInBits)\n{\n    // Entropy must be at least 128 bits - only multiples of 32 bits are acceptible\n    if (entropySizeInBits % 32 > 0)\n        return \"\";\n    if (entropySizeInBits < 128)\n        return \"\";\n    // Upper limit of 4000 - this is not a limit of the standard but just an implementation limit.\n    if (entropySizeInBits > 4000)\n        return \"\";\n\n    // Entropy\n    std::bitset<4096> entropy = entropyIn[0];\n    for (int i = 1; i < entropySizeInBits/8; ++i)\n    {\n        entropy <<= 8;\n        entropy |= entropyIn[i];\n    }\n\n    // First, an initial entropy of ENT bits is generated. A checksum is generated by taking the first ENT / 32\n    // bits of its SHA256 hash\n    uint32_t hash[8];\n    hash_sha256((unsigned char*)&entropyIn[0], entropySizeInBits/8, (unsigned char*)&hash[0]);\n    unsigned int checksumSize = entropySizeInBits / 32;\n    unsigned int totalSizeInBits = entropySizeInBits + checksumSize;\n\n    // This checksum is appended to the end of the initial entropy.\n    for (unsigned int i=0; i < 8; ++i)\n    {\n        if ( (i+1) * 32 < checksumSize )\n        {\n            entropy <<= 32;\n            entropy |= hash[i];\n        }\n        else\n        {\n            std::bitset<32> temp = ReadBE32((unsigned char*)&hash[i]);\n            for(unsigned int j=0; j < checksumSize - (i * 32); ++j)\n            {\n                entropy <<= 1;\n                if (temp[31-j])\n                    entropy[0] = 1;\n            }\n            break;\n        }\n    }\n\n    // Next, these concatenated bits are split into groups of 11 bits, each encoding a number from 0-2047, serving as an index into a wordlist.\n    // Finally, we convert these numbers into words and use the joined words as a mnemonic sentence. \n    SecureString mnemonicPhrase = \"\";\n    unsigned int index = 0;\n    unsigned int bitIndex = 0;\n    for (unsigned int i = 0; i < totalSizeInBits / 11; ++i)\n    {\n        if (i>0)\n            mnemonicPhrase += \" \";\n\n        index = 0;\n        for(int j = 0; j < 11; ++j)\n        {\n            index <<= 1;\n            // bitset indexes operate in reverse order to what we might expect\n            if (entropy[totalSizeInBits - 1 - bitIndex++])\n                index |= 0x1;\n        }\n        mnemonicPhrase += wordList[index];\n    }\n\n    return mnemonicPhrase;\n}\n\nbool checkMnemonic(const SecureString& mnemonic)\n{\n    return entropyFromMnemonic(mnemonic).size() > 0;\n}\n\nstd::vector<std::string> getMnemonicDictionary()\n{\n    return std::vector<std::string>(std::begin(wordList), std::end(wordList));\n}\n"
  },
  {
    "path": "src/wallet/mnemonic.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n// The below file implements the various Mnemonic/Seed/Entropy relations required to create a BIP39 compliant HD wallet.\n// It is likely that none of these functions are implemented in the most elegant (or efficient) way possible\n// However they are called infrequently (usually once per user) and the time spent in them is negligable - so it doesn't matter much\n// Correctness is favoured here over speed - also deadlines were tight :)\n\n// Note this has not been tested on big endian machines and likely requires further work for them.\n\n#ifndef MNEMONIC_H\n#define MNEMONIC_H\n\n#include <string>\n#include <vector>\n#include \"support/allocators/secure.h\"\n\nextern unsigned char* seedFromMnemonic(const SecureString& mnemonic, const SecureString& passphrase=\"\");\nextern SecureString mnemonicFromEntropy(std::vector<unsigned char> entropyIn, int entropySizeInBytes);\nextern std::vector<unsigned char> entropyFromMnemonic(const SecureString& mnemonic);\nextern bool checkMnemonic(const SecureString& mnemonic);\nextern std::vector<std::string> getMnemonicDictionary();\n\n#endif\n"
  },
  {
    "path": "src/wallet/rpcdump.cpp",
    "content": "// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"appname.h\"\n#include \"base58.h\"\n#include \"chain.h\"\n#include \"rpc/server.h\"\n#include \"init.h\"\n#include \"validation/validation.h\"\n#include \"script/script.h\"\n#include \"script/standard.h\"\n#include \"sync.h\"\n#include \"util.h\"\n#include \"util/time.h\"\n#include \"wallet.h\"\n#include \"walletdb.h\"\n#include \"merkleblock.h\"\n#include \"core_io.h\"\n#include \"rpcwallet.h\"\n\n#include <fstream>\n#include <stdint.h>\n\n#include <boost/algorithm/string.hpp>\n#include <boost/date_time/posix_time/posix_time.hpp>\n\n#include <univalue.h>\n#include <witnessutil.h>\n\n\n\n\nstatic std::string EncodeDumpString(const std::string &str) {\n    std::stringstream ret;\n    for(unsigned char c : str) {\n        if (c <= 32 || c >= 128 || c == '%') {\n            ret << '%' << HexStr(&c, &c + 1);\n        } else {\n            ret << c;\n        }\n    }\n    return ret.str();\n}\n\nstatic std::string DecodeDumpString(const std::string &str) {\n    std::stringstream ret;\n    for (unsigned int pos = 0; pos < str.length(); pos++) {\n        unsigned char c = str[pos];\n        if (c == '%' && pos+2 < str.length()) {\n            c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | \n                ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));\n            pos += 2;\n        }\n        ret << c;\n    }\n    return ret.str();\n}\n\nUniValue importprivkey(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"importprivkey \\\"privkey\\\" \\\"account\\\" ( \\\"label\\\" ) ( rescan )\\n\"\n            \"\\nAdds a private key (as returned by dumpprivkey) to your wallet.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"privkey\\\"          (string, required) The private key (see dumpprivkey)\\n\"\n            \"2. \\\"account\\\"          (string, required) The account in which to import the key. \\\"\\\" for the currently active account. NB! Must be a legacy account, cannot import keys into an HD account.\\n\"\n            \"3. \\\"label\\\"            (string, optional, default=\\\"\\\") An optional label\\n\"\n            \"4. rescan               (boolean, optional, default=true) Rescan the wallet for transactions\\n\"\n            \"\\nNote: This call can take minutes to complete if rescan is true.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nDump a private key\\n\"\n            + HelpExampleCli(\"dumpprivkey\", \"\\\"myaddress\\\"\") +\n            \"\\nImport the private key with rescan\\n\"\n            + HelpExampleCli(\"importprivkey\", \"\\\"mykey\\\"\") +\n            \"\\nImport using a label and without rescan\\n\"\n            + HelpExampleCli(\"importprivkey\", \"\\\"mykey\\\" \\\"testing\\\" false\") +\n            \"\\nImport using default blank label and without rescan\\n\"\n            + HelpExampleCli(\"importprivkey\", \"\\\"mykey\\\" \\\"\\\" false\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"importprivkey\", \"\\\"mykey\\\", \\\"testing\\\", false\")\n        );\n\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::string strSecret = request.params[0].get_str();\n    std::string strLabel = \"\";\n    if (request.params.size() > 2)\n        strLabel = request.params[2].get_str();\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[1], true);\n\n    if (forAccount->IsHD())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot import a privkey into an HD account.\");\n\n    // Whether to perform rescan after import\n    bool fRescan = true;\n    if (request.params.size() > 3)\n        fRescan = request.params[3].get_bool();\n\n    if (fRescan && fPruneMode)\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Rescan is disabled in pruned mode\");\n\n    CEncodedSecretKey vchSecret;\n    bool fGood = vchSecret.SetString(strSecret);\n\n    if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid private key encoding\");\n\n    CKey key = vchSecret.GetKey();\n    if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Private key outside allowed range\");\n\n    CPubKey pubkey = key.GetPubKey();\n    assert(key.VerifyPubKey(pubkey));\n    CKeyID vchAddress = pubkey.GetID();\n    {\n        pwallet->MarkDirty();\n        pwallet->SetAddressBook(CNativeAddress(vchAddress).ToString(), strLabel, \"\", \"receive\");\n\n        // Don't throw error in case a key is already there\n        if (pwallet->HaveKey(vchAddress)){\n            return NullUniValue;\n        }\n\n        pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;\n\n        if (!pwallet->AddKeyPubKey(key, pubkey, *forAccount, KEYCHAIN_EXTERNAL)) {\n            throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding key to wallet\");\n        }\n\n        // whenever a key is imported, we need to scan the whole chain\n        pwallet->UpdateTimeFirstKey(1);\n        if (fRescan)\n        {\n            ResetSPVStartRescanThread();\n        }\n    }\n\n    return NullUniValue;\n}\n\nUniValue abortrescan(const JSONRPCRequest& request)\n{\n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"abortrescan\\n\"\n            \"\\nStops current wallet rescan triggered e.g. by an importprivkey call.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nImport a private key\\n\"\n            + HelpExampleCli(\"importprivkey\", \"\\\"mykey\\\"\") +\n            \"\\nAbort the running wallet rescan\\n\"\n            + HelpExampleCli(\"abortrescan\", \"\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"abortrescan\", \"\")\n        );\n\n    if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;\n    pwallet->AbortRescan();\n    return true;\n}\n\nvoid ImportAddress(CWallet*, const CNativeAddress& address, const std::string& strLabel);\nvoid ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)\n{\n    if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"The wallet already contains the private key for this address or script\");\n    }\n\n    pwallet->MarkDirty();\n\n    //fixme: (FUT) (MERGE) (WATCH_ONLY)\n    if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, -1)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n    }\n\n    if (isRedeemScript) {\n        if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {\n            throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding p2sh redeemScript to wallet\");\n        }\n        ImportAddress(pwallet, CNativeAddress(CScriptID(script)), strLabel);\n    } else {\n        CTxDestination destination;\n        if (ExtractDestination(script, destination)) {\n            pwallet->SetAddressBook(CNativeAddress(destination).ToString(), strLabel, \"\", \"receive\");\n        }\n    }\n}\n\nvoid ImportAddress(CWallet* const pwallet, const CNativeAddress& address, const std::string& strLabel)\n{\n    CScript script = GetScriptForDestination(address.Get());\n    ImportScript(pwallet, script, strLabel, false);\n    // add to address book or update label\n    if (address.IsValid())\n        pwallet->SetAddressBook(address.ToString(), strLabel, \"\", \"receive\");\n}\n\nUniValue importaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"importaddress \\\"address\\\" ( \\\"label\\\" rescan p2sh )\\n\"\n            \"\\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"script\\\"           (string, required) The hex-encoded script (or address)\\n\"\n            \"2. \\\"label\\\"            (string, optional, default=\\\"\\\") An optional label\\n\"\n            \"3. rescan               (boolean, optional, default=true) Rescan the wallet for transactions\\n\"\n            \"4. p2sh                 (boolean, optional, default=false) Add the P2SH version of the script as well\\n\"\n            \"\\nNote: This call can take minutes to complete if rescan is true.\\n\"\n            \"If you have the full public key, you should call importpubkey instead of this.\\n\"\n            \"\\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\\n\"\n            \"as change, and not show up in many RPCs.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nImport a script with rescan\\n\"\n            + HelpExampleCli(\"importaddress\", \"\\\"myscript\\\"\") +\n            \"\\nImport using a label without rescan\\n\"\n            + HelpExampleCli(\"importaddress\", \"\\\"myscript\\\" \\\"testing\\\" false\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"importaddress\", \"\\\"myscript\\\", \\\"testing\\\", false\")\n        );\n\n\n    std::string strLabel = \"\";\n    //fixme: (FUT) (WATCH_ONLY)\n    throw JSONRPCError(RPC_INVALID_PARAMETER, \"Sorry for the inconvenience, watch only addresses are temporarily disabled but will come back in a future release.\");\n\n    if (request.params.size() > 1)\n        strLabel = request.params[1].get_str();\n\n    // Whether to perform rescan after import\n    bool fRescan = true;\n    if (request.params.size() > 2)\n        fRescan = request.params[2].get_bool();\n\n    if (fRescan && fPruneMode)\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Rescan is disabled in pruned mode\");\n\n    // Whether to import a p2sh version, too\n    bool fP2SH = false;\n    if (request.params.size() > 3)\n        fP2SH = request.params[3].get_bool();\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    CNativeAddress address(request.params[0].get_str());\n    if (address.IsValid()) {\n        if (fP2SH)\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Cannot use the p2sh flag with an address - use a script instead\");\n        ImportAddress(pwallet, address, strLabel);\n    } else if (IsHex(request.params[0].get_str())) {\n        std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));\n        ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);\n    } else {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address or script\");\n    }\n\n    if (fRescan)\n    {\n        pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);\n        pwallet->ReacceptWalletTransactions();\n    }\n\n    return NullUniValue;\n}\n\n//fixme: (PHASE5) - We can remove this include after phase4 activation\n#include \"witnessutil.h\"\n\nUniValue importprunedfunds(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"importprunedfunds\\n\"\n            \"\\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"rawtransaction\\\" (string, required) A raw transaction in hex funding an already-existing address in wallet\\n\"\n            \"2. \\\"txoutproof\\\"     (string, required) The hex output from gettxoutproof that contains the transaction\\n\"\n        );\n\n    CMutableTransaction tx(CURRENT_TX_VERSION_POW2);\n    if (!DecodeHexTx(tx, request.params[0].get_str()))\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"TX decode failed\");\n    uint256 hashTx = tx.GetHash();\n    CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));\n\n    CDataStream ssMB(ParseHexV(request.params[1], \"proof\"), SER_NETWORK, PROTOCOL_VERSION);\n    CMerkleBlock merkleBlock;\n    ssMB >> merkleBlock;\n\n    //Search partial merkle tree in proof for our transaction and index in valid block\n    std::vector<uint256> vMatch;\n    std::vector<unsigned int> vIndex;\n    unsigned int txnIndex = 0;\n    if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {\n\n        LOCK(cs_main);\n\n        if (!mapBlockIndex.count(merkleBlock.header.GetHashPoW2()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHashPoW2()]))\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Block not found in chain\");\n\n        std::vector<uint256>::const_iterator it;\n        if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction given doesn't exist in proof\");\n        }\n\n        txnIndex = vIndex[it - vMatch.begin()];\n    }\n    else {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Something wrong with merkleblock\");\n    }\n\n    wtx.nIndex = txnIndex;\n    wtx.hashBlock = merkleBlock.header.GetHashPoW2();\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (pwallet->IsMine(wtx)) {\n        pwallet->AddToWallet(wtx, false);\n        return NullUniValue;\n    }\n\n    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"No addresses in wallet correspond to included transaction\");\n}\n\nUniValue removeprunedfunds(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"removeprunedfunds \\\"txid\\\"\\n\"\n            \"\\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"           (string, required) The hex-encoded id of the transaction you are deleting\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"removeprunedfunds\", \"\\\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\\\"\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"removprunedfunds\", \"\\\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\\\"\")\n        );\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    uint256 hash;\n    hash.SetHex(request.params[0].get_str());\n    std::vector<uint256> vHash;\n    vHash.push_back(hash);\n    std::vector<uint256> vHashOut;\n\n    CWalletDB walletdb(*pwallet->dbw);\n    if (pwallet->ZapSelectTx(walletdb, vHash, vHashOut) != DB_LOAD_OK) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Could not properly delete the transaction.\");\n    }\n\n    if(vHashOut.empty()) {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Transaction does not exist in wallet.\");\n    }\n\n    return NullUniValue;\n}\n\nUniValue importpubkey(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)\n        throw std::runtime_error(\n            \"importpubkey \\\"pubkey\\\" ( \\\"label\\\" rescan )\\n\"\n            \"\\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"pubkey\\\"           (string, required) The hex-encoded public key\\n\"\n            \"2. \\\"label\\\"            (string, optional, default=\\\"\\\") An optional label\\n\"\n            \"3. rescan               (boolean, optional, default=true) Rescan the wallet for transactions\\n\"\n            \"\\nNote: This call can take minutes to complete if rescan is true.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nImport a public key with rescan\\n\"\n            + HelpExampleCli(\"importpubkey\", \"\\\"mypubkey\\\"\") +\n            \"\\nImport using a label without rescan\\n\"\n            + HelpExampleCli(\"importpubkey\", \"\\\"mypubkey\\\" \\\"testing\\\" false\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"importpubkey\", \"\\\"mypubkey\\\", \\\"testing\\\", false\")\n        );\n\n    //fixme: (FUT) (WATCH_ONLY)\n    throw JSONRPCError(RPC_INVALID_PARAMETER, \"Sorry for the inconvenience, watch only addresses are temporarily disabled but will come back in a future release.\");\n\n    std::string strLabel = \"\";\n    if (request.params.size() > 1)\n        strLabel = request.params[1].get_str();\n\n    // Whether to perform rescan after import\n    bool fRescan = true;\n    if (request.params.size() > 2)\n        fRescan = request.params[2].get_bool();\n\n    if (fRescan && fPruneMode)\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Rescan is disabled in pruned mode\");\n\n    if (!IsHex(request.params[0].get_str()))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Pubkey must be a hex string\");\n    std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));\n    CPubKey pubKey(data.begin(), data.end());\n    if (!pubKey.IsFullyValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Pubkey is not a valid public key\");\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    ImportAddress(pwallet, CNativeAddress(pubKey.GetID()), strLabel);\n    ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);\n\n    if (fRescan)\n    {\n        pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);\n        pwallet->ReacceptWalletTransactions();\n    }\n\n    return NullUniValue;\n}\n\n\nUniValue importwallet(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"importwallet \\\"filename\\\" \\\"account\\\"\\n\"\n            \"\\nImports keys from a wallet dump file (see dumpwallet).\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"filename\\\"    (string, required) The wallet file\\n\"\n            \"2. \\\"account\\\"     (string, required) The account in which to import the key. \\\"\\\" for the currently active account. NB! Must be a legacy account, cannot import keys into an HD account.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nDump the wallet\\n\"\n            + HelpExampleCli(\"dumpwallet\", \"\\\"test\\\"\") +\n            \"\\nImport the wallet\\n\"\n            + HelpExampleCli(\"importwallet\", \"\\\"test\\\"\") +\n            \"\\nImport using the json rpc call\\n\"\n            + HelpExampleRpc(\"importwallet\", \"\\\"test\\\"\")\n        );\n\n    if (fPruneMode)\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Importing wallets is disabled in pruned mode\");\n\n    CAccount* forAccount = AccountFromValue(pwallet, request.params[1], true);\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (forAccount->IsHD())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot import a privkey into an HD account.\");\n\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::ifstream file;\n    file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);\n    if (!file.is_open())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot open wallet dump file\");\n\n    int64_t nTimeBegin = chainActive.Tip()->GetBlockTime();\n\n    bool fGood = true;\n\n    int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());\n    file.seekg(0, file.beg);\n\n    pwallet->ShowProgress(_(\"Importing...\"), 0); // show progress dialog in GUI\n    while (file.good()) {\n        pwallet->ShowProgress(\"\", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));\n        std::string line;\n        std::getline(file, line);\n        if (line.empty() || line[0] == '#')\n            continue;\n\n        std::vector<std::string> vstr;\n        boost::split(vstr, line, boost::is_any_of(\" \"));\n        if (vstr.size() < 2)\n            continue;\n        CEncodedSecretKey vchSecret;\n        if (!vchSecret.SetString(vstr[0]))\n            continue;\n        CKey key = vchSecret.GetKey();\n        CPubKey pubkey = key.GetPubKey();\n        assert(key.VerifyPubKey(pubkey));\n        CKeyID keyid = pubkey.GetID();\n        if (pwallet->HaveKey(keyid)) {\n            LogPrintf(\"Skipping import of %s (key already present)\\n\", CNativeAddress(keyid).ToString());\n            continue;\n        }\n        int64_t nTime = ParseISO8601DateTime(vstr[1]);\n        std::string strLabel;\n        bool fLabel = true;\n        for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {\n            if (boost::algorithm::starts_with(vstr[nStr], \"#\"))\n                break;\n            if (vstr[nStr] == \"change=1\")\n                fLabel = false;\n            if (vstr[nStr] == \"reserve=1\")\n                fLabel = false;\n            if (boost::algorithm::starts_with(vstr[nStr], \"label=\")) {\n                strLabel = DecodeDumpString(vstr[nStr].substr(6));\n                fLabel = true;\n            }\n        }\n        LogPrintf(\"Importing %s...\\n\", CNativeAddress(keyid).ToString());\n\n        if (!pwallet->AddKeyPubKey(key, pubkey, *forAccount, KEYCHAIN_EXTERNAL)) {\n            fGood = false;\n            continue;\n        }\n        pwallet->mapKeyMetadata[keyid].nCreateTime = nTime;\n        if (fLabel)\n            pwallet->SetAddressBook(keyid.ToString(), strLabel, \"\", \"receive\");\n        nTimeBegin = std::min(nTimeBegin, nTime);\n    }\n    file.close();\n    pwallet->ShowProgress(\"\", 100); // hide progress dialog in GUI\n    pwallet->UpdateTimeFirstKey(nTimeBegin);\n\n    CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW);\n\n    LogPrintf(\"Rescanning last %i blocks\\n\", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0);\n    pwallet->ScanForWalletTransactions(pindex);\n    pwallet->MarkDirty();\n\n    if (!fGood)\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding some keys to wallet\");\n\n    return NullUniValue;\n}\n\nUniValue dumpprivkey(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"dumpprivkey \\\"address\\\"\\n\"\n            \"\\nReveals the private key corresponding to 'address'.\\n\"\n            \"Then the importprivkey can be used with this output\\n\"\n            \"WARNING! If a dumped private key from an HD account is exposed or given out -all- keys within that account (current and future) are also at risk, if the attacker can also get hold of your public key for that account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"   (string, required) The \" GLOBAL_APPNAME \" address for the private key\\n\"\n            \"2. \\\"HDConsent\\\"        (string, optional) If dumping from an HD account please pass the string 'I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY' for this paramater, if you do not understand the risk then please do not do this.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"key\\\"                (string) The private key\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpprivkey\", \"\\\"myaddress\\\"\")\n            + HelpExampleCli(\"importprivkey\", \"\\\"mykey\\\"\")\n            + HelpExampleRpc(\"dumpprivkey\", \"\\\"myaddress\\\"\")\n        );\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::string strAddress = request.params[0].get_str();\n    CNativeAddress address;\n    if (!address.SetString(strAddress))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n    CKeyID keyID;\n    if (!address.GetKeyID(keyID))\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Address does not refer to a key\");\n\n    CKey vchSecret;\n    for(const auto& accountIter : pwallet->mapAccounts)\n    {\n        if (accountIter.second->HaveKey(keyID))\n        {\n            if (accountIter.second->IsHD())\n            {\n                if (request.params.size() < 2 || request.params[1].get_str() != \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\")\n                {\n                    throw JSONRPCError(RPC_INTERNAL_ERROR, \"Please pass the correct HDConsent option in order to proceed.\");\n                }\n            }\n            if (!accountIter.second->GetKey(keyID, vchSecret))\n            {\n                throw JSONRPCError(RPC_WALLET_ERROR, \"Private key for address \" + strAddress + \" is not known\");\n            }\n        }\n    }\n\n    return CEncodedSecretKey(vchSecret).ToString();\n}\n\nUniValue checkwalletagainstutxo(const JSONRPCRequest& request)\n{    \n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"checkwalletagainstutxo\\n\"\n            \"Check wallet transactions against UTXO and look for any inconsistencies\\n\"\n            \"Use 'repairwalletfromutxo' (after making a backup) to attempt to repair any issues that are found\\n\"\n        );\n    \n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    int nMismatchSpent;\n    int nOrphansFound;\n    int64_t nBalanceInQuestion;\n    pwallet->CompareWalletAgainstUTXO(nMismatchSpent, nOrphansFound, nBalanceInQuestion);\n    UniValue result(UniValue::VOBJ);\n    if(!nMismatchSpent && !nOrphansFound)\n    {\n        result.pushKV(\"wallet check passed\", true);\n    }\n    else\n    {\n        if(nMismatchSpent)\n        {\n            result.pushKV(\"mismatched spent coins\", nMismatchSpent);\n            result.pushKV(\"amount in question\", ValueFromAmount(nBalanceInQuestion));\n        }\n        if(nOrphansFound)\n        {\n            result.pushKV(\"orphans found\", nOrphansFound);\n        }\n    }\n    return result;\n}\n\nUniValue repairwalletfromutxo(const JSONRPCRequest& request)\n{    \n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"repairwalletfromutxo\\n\"\n            \"Attempt to repair any issues found by checkwalletagainstutxo\\n\"\n            \"Always make a backup before running this command.\\n\"\n        );\n    \n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    int nMismatchSpent;\n    int nOrphansFound;\n    int64_t nBalanceInQuestion;\n    pwallet->CompareWalletAgainstUTXO(nMismatchSpent, nOrphansFound, nBalanceInQuestion, true);\n    return NullUniValue;\n}\n\nUniValue removeallorphans(const JSONRPCRequest& request)\n{    \n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"removeallorphans\\n\"\n            \"Remove all orphaned transactions from the wallet\\n\"\n        );\n    \n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n    \n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    uint64_t numErased;\n    uint64_t numDetected;\n    std::string strError;\n    bool success = (pwallet->RemoveAllOrphans(numErased, numDetected, strError) == DB_LOAD_OK);\n    \n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"succeeded\", success);\n    if (!success)\n    {\n        result.pushKV(\"error_message\", strError);\n    }\n    result.pushKV(\"num_erased\", numErased);\n    result.pushKV(\"num_detected\", numDetected);\n    \n    return result;\n}\n\nUniValue dumpwallet(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"dumpwallet \\\"filename\\\"\\n\"\n            \"\\nDumps all wallet keys in a human-readable format.\\n\"\n            \"WARNING! If a dumped private key from an HD account is exposed or given out -all- keys within that account (current and future) are also at risk, if the attacker can also get hold of your public key for that account.\\n\"\n            \"It is strongly advised not to use this function with an HD wallet, please proceed at your own risk.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"filename\\\"         (string, required) The filename with path (either absolute or relative to \" GLOBAL_APPNAME \" executable)\\n\"\n            \"2. \\\"HDConsent\\\"        (string, optional) If dumping from an HD account please pass the string 'I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY' for this paramater, if you do not understand the risk then please do not do this.\\n\"\n            \"\\nResult:\\n\"\n            \"{                     (json object)\\n\"\n            \"  \\\"filename\\\" : {      (string) The filename with full absolute path\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"dumpwallet\", \"\\\"test\\\"\")\n            + HelpExampleRpc(\"dumpwallet\", \"\\\"test\\\"\")\n        );\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::ofstream file;\n    boost::filesystem::path filepath = request.params[0].get_str();\n    filepath = boost::filesystem::absolute(filepath);\n    file.open(filepath.string().c_str());\n    if (!file.is_open())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot open wallet dump file\");\n\n    for(const auto& accountIter : pwallet->mapAccounts)\n    {\n        if (accountIter.second->IsHD())\n        {\n            if (request.params.size() < 2 || request.params[1].get_str() != \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\")\n            {\n                throw JSONRPCError(RPC_INTERNAL_ERROR, \"Please pass the correct HDConsent option in order to proceed.\");\n            }\n        }\n    }\n\n    std::map<CKeyID, int64_t> mapKeyBirth;\n    std::set<CKeyID> setKeyPool;\n    pwallet->GetKeyBirthTimes(mapKeyBirth);\n    pwallet->GetAllReserveKeys(setKeyPool);\n\n    // sort time/key pairs\n    std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;\n    for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {\n        vKeyBirth.push_back(std::pair(it->second, it->first));\n    }\n    mapKeyBirth.clear();\n    std::sort(vKeyBirth.begin(), vKeyBirth.end());\n\n    // produce output\n    file << strprintf(\"# Wallet dump created by \" GLOBAL_APPNAME \" %s\\n\", CLIENT_BUILD);\n    file << strprintf(\"# * Created on %s\\n\", FormatISO8601DateTime(GetTime()));\n    file << strprintf(\"# * Best block at time of backup was %i (%s),\\n\", chainActive.Height(), chainActive.Tip()->GetBlockHashPoW2().ToString());\n    file << strprintf(\"#   timestamp %s\\n\", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()));\n    file << \"\\n\";\n\n    // add the base58check encoded extended master if the wallet uses HD \n    /*MUNT - no masterkeyid...\n    CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;\n    if (!masterKeyID.IsNull())\n    {\n        CKey key;\n        if (pwallet->GetKey(masterKeyID, key)) {\n            CExtKey masterKey;\n            masterKey.SetMaster(key.begin(), key.size());\n\n            CEncodedSecretExt b58extkey;\n            b58extkey.SetKey(masterKey);\n\n            file << \"# extended private masterkey: \" << b58extkey.ToString() << \"\\n\\n\";\n        }\n    }*/\n    for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {\n        const CKeyID &keyid = it->second;\n        std::string strTime = FormatISO8601DateTime(it->first);\n        std::string strAddr = CNativeAddress(keyid).ToString();\n        CKey key;\n        if (pwallet->GetKey(keyid, key)) {\n            file << strprintf(\"%s %s \", CEncodedSecretKey(key).ToString(), strTime);\n            if (pwallet->mapAddressBook.count(CNativeAddress(keyid).ToString())) {\n                file << strprintf(\"label=%s\", EncodeDumpString(pwallet->mapAddressBook[CNativeAddress(keyid).ToString()].name));\n            /*} else if (keyid == masterKeyID) {\n                file << \"hdmaster=1\";*/\n            } else if (setKeyPool.count(keyid)) {\n                file << \"reserve=1\";\n            /*} else if (pwallet->mapKeyMetadata[keyid].hdKeypath == \"m\") {\n                file << \"inactivehdmaster=1\";*/\n            } else {\n                file << \"change=1\";\n            }\n            file << strprintf(\" # addr=%s%s\\n\", strAddr, (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? \" hdkeypath=\"+pwallet->mapKeyMetadata[keyid].hdKeypath : \"\"));\n        }\n    }\n    file << \"\\n\";\n    file << \"# End of dump\\n\";\n    file.close();\n\n    UniValue reply(UniValue::VOBJ);\n    reply.pushKV(\"filename\", filepath.string());\n\n    return reply;\n}\n\n\nUniValue ProcessImport(CWallet* const pwallet, CAccount* forAccount, const UniValue& data, const int64_t timestamp)\n{\n    try {\n        bool success = false;\n\n        // Required fields.\n        const UniValue& scriptPubKey = data[\"scriptPubKey\"];\n\n        // Should have script or JSON with \"address\".\n        if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists(\"address\")) && !(scriptPubKey.getType() == UniValue::VSTR)) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid scriptPubKey\");\n        }\n\n        // Optional fields.\n        const std::string& strRedeemScript = data.exists(\"redeemscript\") ? data[\"redeemscript\"].get_str() : \"\";\n        const UniValue& pubKeys = data.exists(\"pubkeys\") ? data[\"pubkeys\"].get_array() : UniValue();\n        const UniValue& keys = data.exists(\"keys\") ? data[\"keys\"].get_array() : UniValue();\n        const bool& internal = data.exists(\"internal\") ? data[\"internal\"].get_bool() : false;\n        const bool& watchOnly = data.exists(\"watchonly\") ? data[\"watchonly\"].get_bool() : false;\n        const std::string& label = data.exists(\"label\") && !internal ? data[\"label\"].get_str() : \"\";\n        const int64_t& timestamp = data.exists(\"timestamp\") && data[\"timestamp\"].get_int64() > 1 ? data[\"timestamp\"].get_int64() : 1;\n\n        bool isScript = scriptPubKey.getType() == UniValue::VSTR;\n        bool isP2SH = strRedeemScript.length() > 0;\n        const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey[\"address\"].get_str();\n\n        // Parse the output.\n        CScript script;\n        CNativeAddress address;\n\n        if (!isScript) {\n            address = CNativeAddress(output);\n            if (!address.IsValid()) {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid address\");\n            }\n            script = GetScriptForDestination(address.Get());\n        } else {\n            if (!IsHex(output)) {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid scriptPubKey\");\n            }\n\n            std::vector<unsigned char> vData(ParseHex(output));\n            script = CScript(vData.begin(), vData.end());\n        }\n\n        // Watchonly and private keys\n        if (watchOnly && keys.size()) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Incompatibility found between watchonly and keys\");\n        }\n\n        // Internal + Label\n        if (internal && data.exists(\"label\")) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Incompatibility found between internal and label\");\n        }\n\n        // Not having Internal + Script\n        if (!internal && isScript) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Internal must be set for hex scriptPubKey\");\n        }\n\n        // Keys / PubKeys size check.\n        if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"More than private key given for one address\");\n        }\n\n        // Invalid P2SH redeemScript\n        if (isP2SH && !IsHex(strRedeemScript)) {\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid redeem script\");\n        }\n\n        // Process. //\n\n        // P2SH\n        if (isP2SH)\n        {\n            // Import redeem script.\n            std::vector<unsigned char> vData(ParseHex(strRedeemScript));\n            CScript redeemScript = CScript(vData.begin(), vData.end());\n\n            // Invalid P2SH address\n            if (!script.IsPayToScriptHash()) {\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid P2SH address / script\");\n            }\n\n            pwallet->MarkDirty();\n\n            //fixme: (FUT) (WATCH_ONLY) - timestamp\n            //fixme: (FUT) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n            //if (!forAccount->AddWatchOnly(redeemScript/*, timestamp*/)) {\n                //throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n            //}\n\n            if (!forAccount->HaveCScript(redeemScript) && !forAccount->AddCScript(redeemScript)) {\n                throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding p2sh redeemScript to wallet\");\n            }\n\n            CNativeAddress redeemAddress = CNativeAddress(CScriptID(redeemScript));\n            CScript redeemDestination = GetScriptForDestination(redeemAddress.Get());\n\n            if (::IsMine(*forAccount, redeemDestination) == ISMINE_SPENDABLE) {\n                throw JSONRPCError(RPC_WALLET_ERROR, \"The wallet already contains the private key for this address or script\");\n            }\n\n            pwallet->MarkDirty();\n\n            //fixme: (FUT) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n            //fixme: (FUT) (WATCH_ONLY) - timestamp\n            //if (!forAccount->AddWatchOnly(redeemDestination/*, timestamp*/)) {\n                //throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n            //}\n\n            // add to address book or update label\n            if (address.IsValid()) {\n                pwallet->SetAddressBook(address.ToString(), label, \"\", \"receive\");\n            }\n\n            // Import private keys.\n            if (keys.size()) {\n                for (size_t i = 0; i < keys.size(); i++) {\n                    const std::string& privkey = keys[i].get_str();\n\n                    CEncodedSecretKey vchSecret;\n                    bool fGood = vchSecret.SetString(privkey);\n\n                    if (!fGood) {\n                        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid private key encoding\");\n                    }\n\n                    CKey key = vchSecret.GetKey();\n\n                    if (!key.IsValid()) {\n                        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Private key outside allowed range\");\n                    }\n\n                    CPubKey pubkey = key.GetPubKey();\n                    assert(key.VerifyPubKey(pubkey));\n\n                    CKeyID vchAddress = pubkey.GetID();\n                    pwallet->MarkDirty();\n                    pwallet->SetAddressBook(CNativeAddress(vchAddress).ToString(), label, \"\", \"receive\");\n\n                    if (forAccount->HaveKey(vchAddress)) {\n                        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Already have this key\");\n                    }\n\n                    pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;\n\n                    if (!forAccount->AddKeyPubKey(key, pubkey)) {\n                        throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding key to wallet\");\n                    }\n\n                    pwallet->UpdateTimeFirstKey(timestamp);\n                }\n            }\n\n            success = true;\n        }\n        else\n        {\n            // Import public keys.\n            if (pubKeys.size() && keys.size() == 0)\n            {\n                const std::string& strPubKey = pubKeys[0].get_str();\n\n                if (!IsHex(strPubKey)) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Pubkey must be a hex string\");\n                }\n\n                std::vector<unsigned char> vData(ParseHex(strPubKey));\n                CPubKey pubKey(vData.begin(), vData.end());\n\n                if (!pubKey.IsFullyValid()) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Pubkey is not a valid public key\");\n                }\n\n                CNativeAddress pubKeyAddress = CNativeAddress(pubKey.GetID());\n\n                // Consistency check.\n                if (!isScript && !(pubKeyAddress.Get() == address.Get())) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Consistency check failed\");\n                }\n\n                // Consistency check.\n                if (isScript) {\n                    CNativeAddress scriptAddress;\n                    CTxDestination destination;\n\n                    if (ExtractDestination(script, destination)) {\n                        scriptAddress = CNativeAddress(destination);\n                        if (!(scriptAddress.Get() == pubKeyAddress.Get())) {\n                            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Consistency check failed\");\n                        }\n                    }\n                }\n\n                CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());\n\n                if (::IsMine(*forAccount, pubKeyScript) == ISMINE_SPENDABLE) {\n                    throw JSONRPCError(RPC_WALLET_ERROR, \"The wallet already contains the private key for this address or script\");\n                }\n\n                pwallet->MarkDirty();\n\n                //fixme: (FUT) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n                //fixme: (FUT) (WATCH_ONLY) - timestamp\n                //if (!forAccount->AddWatchOnly(pubKeyScript/*, timestamp*/)) {\n                    //throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n                //}\n\n                // add to address book or update label\n                if (pubKeyAddress.IsValid()) {\n                    pwallet->SetAddressBook(pubKeyAddress.ToString(), label, \"\", \"receive\");\n                }\n\n                // TODO Is this necessary?\n                CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey);\n\n                if (::IsMine(*forAccount, scriptRawPubKey) == ISMINE_SPENDABLE) {\n                    throw JSONRPCError(RPC_WALLET_ERROR, \"The wallet already contains the private key for this address or script\");\n                }\n\n                pwallet->MarkDirty();\n\n                //fixme: (FUT) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n                //fixme: (FUT) (WATCH_ONLY) - timestamp\n                //if (!forAccount->AddWatchOnly(scriptRawPubKey/*, timestamp*/)) {\n                    //throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n                //}\n\n                success = true;\n            }\n\n            // Import private keys.\n            if (keys.size())\n            {\n                const std::string& strPrivkey = keys[0].get_str();\n\n                // Checks.\n                CEncodedSecretKey vchSecret;\n                bool fGood = vchSecret.SetString(strPrivkey);\n\n                if (!fGood) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid private key encoding\");\n                }\n\n                CKey key = vchSecret.GetKey();\n                if (!key.IsValid()) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Private key outside allowed range\");\n                }\n\n                CPubKey pubKey = key.GetPubKey();\n                assert(key.VerifyPubKey(pubKey));\n\n                CNativeAddress pubKeyAddress = CNativeAddress(pubKey.GetID());\n\n                // Consistency check.\n                if (!isScript && !(pubKeyAddress.Get() == address.Get())) {\n                    throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Consistency check failed\");\n                }\n\n                // Consistency check.\n                if (isScript) {\n                    CNativeAddress scriptAddress;\n                    CTxDestination destination;\n\n                    if (ExtractDestination(script, destination)) {\n                        scriptAddress = CNativeAddress(destination);\n                        if (!(scriptAddress.Get() == pubKeyAddress.Get())) {\n                            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Consistency check failed\");\n                        }\n                    }\n                }\n\n                CKeyID vchAddress = pubKey.GetID();\n                pwallet->MarkDirty();\n                pwallet->SetAddressBook(CNativeAddress(vchAddress).ToString(), label, \"\", \"receive\");\n\n                if (forAccount->HaveKey(vchAddress)) {\n                    return false;\n                }\n\n                pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;\n\n                if (!forAccount->AddKeyPubKey(key, pubKey)) {\n                    throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding key to wallet\");\n                }\n\n                pwallet->UpdateTimeFirstKey(timestamp);\n\n                success = true;\n            }\n\n            // Import scriptPubKey only.\n            if (pubKeys.size() == 0 && keys.size() == 0)\n            {\n                if (::IsMine(*forAccount, script) == ISMINE_SPENDABLE) {\n                    throw JSONRPCError(RPC_WALLET_ERROR, \"The wallet already contains the private key for this address or script\");\n                }\n\n                pwallet->MarkDirty();\n\n                //fixme: (FUT) (REIMPLEMENT AS SPECIAL WATCH ACCOUNT)\n                //fixme: (FUT) (WATCH_ONLY) - timestamp\n                //if (!forAccount->AddWatchOnly(script/*, timestamp*/)) {\n                    //throw JSONRPCError(RPC_WALLET_ERROR, \"Error adding address to wallet\");\n                //}\n\n                if (scriptPubKey.getType() == UniValue::VOBJ)\n                {\n                    // add to address book or update label\n                    if (address.IsValid())\n                    {\n                        pwallet->SetAddressBook(address.ToString(), label, \"\", \"receive\");\n                    }\n                }\n\n                success = true;\n            }\n        }\n\n        UniValue result = UniValue(UniValue::VOBJ);\n        result.pushKV(\"success\", UniValue(success));\n        return result;\n    } catch (const UniValue& e) {\n        UniValue result = UniValue(UniValue::VOBJ);\n        result.pushKV(\"success\", UniValue(false));\n        result.pushKV(\"error\", e);\n        return result;\n    } catch (...) {\n        UniValue result = UniValue(UniValue::VOBJ);\n        result.pushKV(\"success\", UniValue(false));\n        result.pushKV(\"error\", JSONRPCError(RPC_MISC_ERROR, \"Missing required fields\"));\n        return result;\n    }\n}\n\nint64_t GetImportTimestamp(const UniValue& data, int64_t now)\n{\n    if (data.exists(\"timestamp\")) {\n        const UniValue& timestamp = data[\"timestamp\"];\n        if (timestamp.isNum()) {\n            return timestamp.get_int64();\n        } else if (timestamp.isStr() && timestamp.get_str() == \"now\") {\n            return now;\n        }\n        throw JSONRPCError(RPC_TYPE_ERROR, strprintf(\"Expected number or \\\"now\\\" timestamp value for key. got type %s\", uvTypeName(timestamp.type())));\n    }\n    throw JSONRPCError(RPC_TYPE_ERROR, \"Missing required timestamp field for key\");\n}\n\nUniValue importmulti(const JSONRPCRequest& mainRequest)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest);\n    if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (mainRequest.fHelp || mainRequest.params.size() < 2 || mainRequest.params.size() > 3)\n        throw std::runtime_error(\n            \"importmulti \\\"account\\\" \\\"requests\\\" ( \\\"options\\\" )\\n\\n\"\n            \"Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\\n\\n\"\n            \"Arguments:\\n\"\n            \"1. \\\"account\\\"  (string, required) The account in which to import the requests. \\\"\\\" for the currently active account. NB! Must be a legacy account, cannot import keys into an HD account.\\n\"\n            \"2. requests     (array, required) Data to be imported\\n\"\n            \"  [     (array of json objects)\\n\"\n            \"    {\\n\"\n            \"      \\\"scriptPubKey\\\": \\\"<script>\\\" | { \\\"address\\\":\\\"<address>\\\" }, (string / json, required) Type of scriptPubKey (string for script, json for address)\\n\"\n            \"      \\\"timestamp\\\": timestamp | \\\"now\\\"                            , (integer / string, required) Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\\n\"\n            \"                                                                    or the string \\\"now\\\" to substitute the current synced blockchain time. The timestamp of the oldest\\n\"\n            \"                                                                    key will determine how far back blockchain rescans need to begin for missing wallet transactions.\\n\"\n            \"                                                                    \\\"now\\\" can be specified to bypass scanning, for keys which are known to never have been used, and\\n\"\n            \"                                                                    0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\\n\"\n            \"                                                                    creation time of all keys being imported by the importmulti call will be scanned.\\n\"\n            \"      \\\"redeemscript\\\": \\\"<script>\\\"                                , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\\n\"\n            \"      \\\"pubkeys\\\": [\\\"<pubKey>\\\", ... ]                             , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\\n\"\n            \"      \\\"keys\\\": [\\\"<key>\\\", ... ]                                   , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\\n\"\n            \"      \\\"internal\\\": <true>                                          , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\\n\"\n            \"      \\\"watchonly\\\": <true>                                         , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\\n\"\n            \"      \\\"label\\\": <label>                                            , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\\n\"\n            \"    }\\n\"\n            \"  ,...\\n\"\n            \"  ]\\n\"\n            \"3. options                 (json, optional)\\n\"\n            \"  {\\n\"\n            \"     \\\"rescan\\\": <false>,         (boolean, optional, default: true) Stating if should rescan the blockchain after all imports\\n\"\n            \"  }\\n\"\n            \"\\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\\n\"\n            \"may report that the imported keys, addresses or scripts exists but related transactions are still missing.\\n\"\n            \"\\nExamples:\\n\" +\n            HelpExampleCli(\"importmulti\", \"'[{ \\\"scriptPubKey\\\": { \\\"address\\\": \\\"<my address>\\\" }, \\\"timestamp\\\":1455191478 }, \"\n                                          \"{ \\\"scriptPubKey\\\": { \\\"address\\\": \\\"<my 2nd address>\\\" }, \\\"label\\\": \\\"example 2\\\", \\\"timestamp\\\": 1455191480 }]'\") +\n            HelpExampleCli(\"importmulti\", \"'[{ \\\"scriptPubKey\\\": { \\\"address\\\": \\\"<my address>\\\" }, \\\"timestamp\\\":1455191478 }]' '{ \\\"rescan\\\": false}'\") +\n\n            \"\\nResponse is an array with the same size as the input that has the execution result :\\n\"\n            \"  [{ \\\"success\\\": true } , { \\\"success\\\": false, \\\"error\\\": { \\\"code\\\": -1, \\\"message\\\": \\\"Internal Server Error\\\"} }, ... ]\\n\");\n\n    RPCTypeCheck(mainRequest.params, {UniValue::VSTR, UniValue::VARR, UniValue::VOBJ});\n\n    CAccount* forAccount = AccountFromValue(pwallet, mainRequest.params[0], true);\n    if (forAccount->IsHD())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Cannot import a privkey into an HD account.\");\n\n    const UniValue& requests = mainRequest.params[1];\n\n    //Default options\n    bool fRescan = true;\n\n    if (!mainRequest.params[2].isNull())\n    {\n        const UniValue& options = mainRequest.params[2];\n        if (options.exists(\"rescan\"))\n            fRescan = options[\"rescan\"].get_bool();\n    }\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n    EnsureWalletIsUnlocked(pwallet);\n\n    int64_t now = 0;\n    bool fRunScan = false;\n    int64_t nLowestTimestamp = 0;\n    UniValue response(UniValue::VARR);\n    {\n        // Verify all timestamps are present before importing any keys.\n        now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;\n        for (const UniValue& data : requests.getValues())\n        {\n            GetImportTimestamp(data, now);\n        }\n\n        const int64_t minimumTimestamp = 1;\n        if (fRescan && chainActive.Tip())\n            nLowestTimestamp = chainActive.Tip()->GetBlockTime();\n        else\n            fRescan = false;\n\n        for (const UniValue& data : requests.getValues())\n        {\n            const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);\n            const UniValue result = ProcessImport(pwallet, forAccount, data, timestamp);\n            response.push_back(result);\n\n            if (!fRescan)\n                continue;\n\n            if (result[\"success\"].get_bool())// If at least one request was successful then allow rescan.\n                fRunScan = true;\n\n            if (timestamp < nLowestTimestamp)// Get the lowest timestamp.\n                nLowestTimestamp = timestamp;\n        }\n    }\n    if (fRescan && fRunScan && requests.size())\n    {\n        int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);\n        pwallet->ReacceptWalletTransactions();\n\n        if (pwallet->IsAbortingRescan()) { throw JSONRPCError(RPC_MISC_ERROR, \"Rescan aborted by user.\"); }\n        if (scannedTime > nLowestTimestamp)\n        {\n            std::vector<UniValue> results = response.getValues();\n            response.clear();\n            response.setArray();\n            size_t i = 0;\n            for (const UniValue& request : requests.getValues()) {\n                // If key creation date is within the successfully scanned\n                // range, or if the import result already has an error set, let\n                // the result stand unmodified. Otherwise replace the result\n                // with an error message.\n                if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists(\"error\"))\n                {\n                    response.push_back(results.at(i));\n                }\n                else\n                {\n                    UniValue result = UniValue(UniValue::VOBJ);\n                    result.pushKV(\"success\", UniValue(false));\n                    std::string errorMessage = strprintf(\"Rescan failed for key with creation timestamp %d. There was an error reading a block from time %d, which is after or within %d seconds of key creation, and \"\n                                      \"could contain transactions pertaining to the key. As a result, transactions and coins using this key may not appear in the wallet. This error could be \"\n                                      \"caused by pruning or data corruption (see \" GLOBAL_APPNAME \" log for details) and could be dealt with by downloading and rescanning the relevant blocks (see -reindex and -rescan options).\", GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW);\n                    result.pushKV(\"error\", JSONRPCError(RPC_MISC_ERROR,errorMessage));\n                    response.push_back(std::move(result));\n                }\n                ++i;\n            }\n        }\n    }\n\n    return response;\n}\n"
  },
  {
    "path": "src/wallet/rpcwallet.cpp",
    "content": "// Copyright (c) 2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"appname.h\"\n#include \"amount.h\"\n#include \"base58.h\"\n#include \"chain.h\"\n#include \"consensus/validation.h\"\n#include \"core_io.h\"\n#include \"init.h\"\n#include <unity/appmanager.h>\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"policy/feerate.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"rpc/server.h\"\n#include \"script/sign.h\"\n#include \"timedata.h\"\n#include \"util.h\"\n#include \"witnessutil.h\"\n#include \"util/moneystr.h\"\n#include \"wallet/coincontrol.h\"\n#include \"wallet/feebumper.h\"\n#include \"wallet/wallet.h\"\n#include \"wallet/walletdb.h\"\n#include \"wallet/witness_operations.h\"\n#include \"script/ismine.h\"\n\n#include <stdint.h>\n\n#include <univalue.h>\n\n\nCWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)\n{\n    // TODO: Some way to access secondary wallets\n    return vpwallets.empty() ? nullptr : vpwallets[0];\n}\n\nstd::string HelpRequiringPassphrase(CWallet * const pwallet)\n{\n    return pwallet && pwallet->IsCrypted()\n        ? \"\\nRequires wallet passphrase to be set with walletpassphrase call.\"\n        : \"\";\n}\n\nbool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)\n{\n    if (!pwallet) {\n        if (!avoidException)\n            throw JSONRPCError(RPC_METHOD_NOT_FOUND, \"Method not found (disabled)\");\n        else\n            return false;\n    }\n    return true;\n}\n\nvoid EnsureWalletIsUnlocked(CWallet * const pwallet)\n{\n    if (pwallet->IsLocked()) {\n        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, \"Error: Please enter the wallet passphrase with walletpassphrase first.\");\n    }\n}\n\nvoid WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)\n{\n    int confirms = wtx.GetDepthInMainChain();\n    entry.pushKV(\"confirmations\", confirms);\n    if (wtx.IsCoinBase())\n        entry.pushKV(\"generated\", true);\n    if (confirms > 0)\n    {\n        entry.pushKV(\"blockhash\", wtx.hashBlock.GetHex());\n        entry.pushKV(\"blockindex\", wtx.nIndex);\n        entry.pushKV(\"blocktime\", mapBlockIndex[wtx.hashBlock]->GetBlockTime());\n    } else {\n        entry.pushKV(\"trusted\", wtx.IsTrusted());\n    }\n    uint256 hash = wtx.GetHash();\n    entry.pushKV(\"txid\", hash.GetHex());\n    UniValue conflicts(UniValue::VARR);\n    for(const uint256& conflict : wtx.GetConflicts())\n        conflicts.push_back(conflict.GetHex());\n    entry.pushKV(\"walletconflicts\", conflicts);\n    entry.pushKV(\"time\", wtx.GetTxTime());\n    entry.pushKV(\"timereceived\", (int64_t)wtx.nTimeReceived);\n\n    // Add opt-in RBF status\n    std::string rbfStatus = \"no\";\n    if (confirms <= 0) {\n        LOCK(mempool.cs);\n        RBFTransactionState rbfState = IsRBFOptIn(wtx, mempool);\n        if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN)\n            rbfStatus = \"unknown\";\n        else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125)\n            rbfStatus = \"yes\";\n    }\n    entry.pushKV(\"bip125-replaceable\", rbfStatus);\n\n    for(const PAIRTYPE(std::string, std::string)& item : wtx.mapValue)\n        entry.pushKV(item.first, item.second);\n}\n\nCAccount* AccountFromValue(CWallet* pwallet, const UniValue& value, bool useDefaultIfEmpty)\n{\n    std::string strAccountUUIDOrLabel = value.get_str();\n\n    if (!pwallet)\n        throw std::runtime_error(\"Cannot use command without an active wallet\");\n\n    //fixme: (FUT) (ACCOUNTS) (HIGH) Forbid \"*\" as an account name to prevent clash with this.\n    if (strAccountUUIDOrLabel == \"*\")\n        return nullptr;\n\n    if (strAccountUUIDOrLabel.empty())\n    {\n        if (useDefaultIfEmpty)\n        {\n            if (!pwallet->getActiveAccount())\n            {\n                throw std::runtime_error(\"No account identifier passed, and no active account selected, please select an active account or pass a valid identifier.\");\n            }\n            return pwallet->getActiveAccount();\n        }\n        else\n        {\n            return nullptr;\n        }\n    }\n\n    CAccount* foundAccount = NULL;\n    if (pwallet->mapAccounts.find(getUUIDFromString(strAccountUUIDOrLabel)) != pwallet->mapAccounts.end())\n    {\n        foundAccount = pwallet->mapAccounts[getUUIDFromString(strAccountUUIDOrLabel)];\n    }\n    for (const auto& [accountUUID, account] : pwallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        if (account->getLabel() == strAccountUUIDOrLabel)\n        {\n            if (foundAccount)\n            {\n                throw std::runtime_error(\"failed due to ambiguity, given UUID or label matches multiple accounts.\");\n            }\n            foundAccount = account;\n        }\n    }\n\n    if (!foundAccount)\n        throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, \"Not a valid account UUID or label.\");\n\n    return foundAccount;\n}\n\nUniValue getnewaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getnewaddress ( \\\"account\\\" )\\n\"\n            \"\\nReturns a new \" GLOBAL_APPNAME \" address for receiving payments.\\n\"\n            \"If 'account' is not specified the currently active account is used \\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"        (string, optional) The unique account name or UUID for the address to be linked to. If not provided, the currently active account is used. Account must already exist.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"address\\\"    (string) The new \" GLOBAL_APPNAME \" address\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getnewaddress\", \"\")\n            + HelpExampleRpc(\"getnewaddress\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // Parse the account first so we don't generate a key if there's an error\n    CAccount* account;\n    if (request.params.size() > 0)\n        account = AccountFromValue(pwallet, request.params[0], true);\n    else\n        account = AccountFromValue(pwallet, UniValue(\"\"), true);\n\n    if (!pwallet->IsLocked()) {\n        pwallet->TopUpKeyPool();\n    }\n\n    // Generate a new key that is added to wallet\n    CPubKey newKey;\n    if (!pwallet->GetKeyFromPool(newKey, account, KEYCHAIN_EXTERNAL))\n        throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n    CKeyID keyID = newKey.GetID();\n\n    return CNativeAddress(keyID).ToString();\n}\n\nUniValue getaccountaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getaccountaddress ( \\\"account\\\" )\\n\"\n            \"\\nReturns the current \" GLOBAL_APPNAME \" address for receiving payments to this account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"       (string, optional) The unique account name or UUID for the address to retrieve. If not provided, the currently active account is used. Account must already exist.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"address\\\"          (string) The current \" GLOBAL_APPNAME \" address\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getaccountaddress\", \"\")\n            + HelpExampleCli(\"getaccountaddress\", \"\\\"myaccount\\\"\")\n            + HelpExampleRpc(\"getaccountaddress\", \"\\\"myaccount\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // Parse the account first so we don't generate a key if there's an error\n    CAccount* account;\n    if (request.params.size() > 0)\n        account = AccountFromValue(pwallet, request.params[0], true);\n    else\n        account = AccountFromValue(pwallet, UniValue(\"\"), true);\n\n    CReserveKeyOrScript reservekey(pwallet, account, KEYCHAIN_EXTERNAL);\n    CPubKey vchPubKey;\n    if (!reservekey.GetReservedKey(vchPubKey))\n        throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n\n    CKeyID keyID = vchPubKey.GetID();\n\n    return CNativeAddress(keyID).ToString();\n}\n\nUniValue getrawchangeaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"getrawchangeaddress\\n\"\n            \"\\nReturns a new \" GLOBAL_APPNAME \" address, for receiving change.\\n\"\n            \"1. \\\"account\\\"        (string, optional) The unique account name or UUID for the address to be linked to. If not provided, the currently active account is used. Account must already exist.\\n\"\n            \"This is for use with raw transactions, NOT normal use.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"address\\\"    (string) The address\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getrawchangeaddress\", \"\")\n            + HelpExampleRpc(\"getrawchangeaddress\", \"\")\n       );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n    CAccount* fromAccount;\n    if (request.params.size() > 0)\n        fromAccount = AccountFromValue(pwallet, request.params[0], true);\n    else\n        fromAccount = AccountFromValue(pwallet, UniValue(\"\"), true);\n\n    if (!fromAccount)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"No active account for request.\");\n\n\n    if (!pwallet->IsLocked()) {\n        pwallet->TopUpKeyPool();\n    }\n\n\n    CReserveKeyOrScript reservekey(pwallet, fromAccount, KEYCHAIN_CHANGE);\n    CPubKey vchPubKey;\n    if (!reservekey.GetReservedKey(vchPubKey))\n        throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n\n    reservekey.KeepKey();\n\n    CKeyID keyID = vchPubKey.GetID();\n\n    return CNativeAddress(keyID).ToString();\n}\n\n\nUniValue getaccount(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getaccount \\\"address\\\"\\n\"\n            \"\\nReturns the UUID and label of the account associated with the given address.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"         (string, required) The \" GLOBAL_APPNAME \" address for account lookup.\\n\"\n            \"\\nResult:\\n\"\n            \"[                     (json array of string)\\n\"\n            \"  \\\"accountUUID\\\"   (string) a \" GLOBAL_APPNAME \" address associated with the given account\\n\"\n            \"  \\\"accountLabel\\\"  (string) a \" GLOBAL_APPNAME \" address associated with the given account\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getaccount\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\"\")\n            + HelpExampleRpc(\"getaccount\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CNativeAddress address(request.params[0].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n\n    UniValue jsonGroupings(UniValue::VARR);\n\n    //fixme: (FUT) (WATCH_ONLY)\n    for(const auto& [accountUUID, account] : pwallet->mapAccounts)\n    {\n        if (::IsMine(*account, address.Get()))\n        {\n            UniValue jsonGrouping(UniValue::VARR);\n            UniValue addressInfo(UniValue::VARR);\n            addressInfo.push_back(getUUIDAsString(accountUUID));\n            addressInfo.push_back(account->getLabel());\n            jsonGrouping.push_back(addressInfo);\n            jsonGroupings.push_back(jsonGrouping);\n        }\n    }\n\n    return jsonGroupings;\n}\n\n\nUniValue getaddressesbyaccount(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"getaddressesbyaccount \\\"account\\\"\\n\"\n            \"\\nReturns the list of assigned addresses for the given account, includes empty addresses but excludes addresses still in the keypool.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"  (string, required) The UUID or unique label of the account to move funds from. May be the currently active account using \\\"\\\"\\n\"\n            \"\\nResult:\\n\"\n            \"[                     (json array of string)\\n\"\n            \"  \\\"address\\\"         (string) a \" GLOBAL_APPNAME \" address associated with the given account\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getaddressesbyaccount\", \"\\\"tabby\\\"\")\n            + HelpExampleRpc(\"getaddressesbyaccount\", \"\\\"tabby\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n\n    // Find all addresses that have the given account and are not in the key pool\n    std::set<CKeyID> setAddressExternal;\n    std::set<CKeyID> setAddressInternal;\n    fromAccount->GetKeys(setAddressExternal, setAddressInternal);\n\n    CWalletDB walletdb(*pwallet->dbw);\n    for (auto& keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n    {\n        CKeyPool keypoolentry;\n        auto& setAddresses = keyChain == KEYCHAIN_EXTERNAL ? setAddressExternal : setAddressInternal;\n        for (const auto& keyIndex : keyChain == KEYCHAIN_EXTERNAL ? fromAccount->setKeyPoolExternal : fromAccount->setKeyPoolInternal)\n        {\n            if (!walletdb.ReadPool(keyIndex, keypoolentry))\n                throw std::runtime_error(std::string(__func__) + \": read failed\");\n\n            if (setAddresses.find(keypoolentry.vchPubKey.GetID()) != setAddresses.end())\n            {\n                setAddresses.erase(setAddresses.find(keypoolentry.vchPubKey.GetID()));\n            }\n        }\n    }\n\n    UniValue ret(UniValue::VARR);\n    // Enumerate witness addresses first\n    if (fromAccount->IsPoW2Witness() && !fromAccount->IsWitnessOnly())\n    {\n        for (const auto& externalKey : setAddressExternal)\n        {\n            for (const auto& internalKey : setAddressInternal)\n            {\n                ret.push_back(CNativeAddress(CPoW2WitnessDestination(externalKey, internalKey)).ToString());\n            }\n        }\n    }\n    // Then normal addresses\n    for(const auto& setAddresses : { setAddressExternal, setAddressInternal })\n    {\n        for(const auto& key : setAddresses)\n        {\n            ret.push_back(CNativeAddress(key).ToString());\n        }\n    }\n    return ret;\n}\n\nstatic void SendMoney(CWallet * const pwallet, CAccount* fromAccount, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)\n{\n    CAmount curBalance = pwallet->GetBalance();\n\n    if (fromAccount->IsReadOnly())\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Can't send from a read only account\");\n\n    // Check amount\n    if (nValue <= 0)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid amount\");\n\n    if (nValue > curBalance)\n        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, \"Insufficient funds\");\n\n    if (pwallet->GetBroadcastTransactions() && !g_connman) {\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n    }\n\n    // Create and send the transaction\n    CReserveKeyOrScript reservekey(pwallet, fromAccount, KEYCHAIN_CHANGE);\n    CAmount nFeeRequired;\n    std::string strError;\n    std::vector<CRecipient> vecSend;\n    int nChangePosRet = -1;\n    CRecipient recipient = GetRecipientForDestination(address, nValue, fSubtractFeeFromAmount, GetPoW2Phase(chainActive.Tip()));\n    vecSend.push_back(recipient);\n    \n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(fromAccount);\n    for ( const auto& accountPair : pactiveWallet->mapAccounts )\n    {\n        if(accountPair.second->getParentUUID() == fromAccount->getUUID())\n        {\n            accountsToTry.push_back(accountPair.second);\n        }\n    }\n    if (!pwallet->CreateTransaction(accountsToTry, vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError))\n    {\n        if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)\n        {\n            strError = strprintf(\"Error: This transaction requires a transaction fee of at least %s\", FormatMoney(nFeeRequired));\n        }\n        else if (fromAccount->IsPoW2Witness() && fSubtractFeeFromAmount)\n        {\n            const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(fromAccount);\n            if (unspentWitnessOutputs.size() > 0)\n            {\n                const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] = unspentWitnessOutputs[0];\n                (unused) currentWitnessHeight;\n                (unused) currentWitnessTxIndex;\n                (unused) currentWitnessOutpoint;\n                const std::vector<CAccount*> accounts = pwallet->FindAccountsForTransaction(currentWitnessTxOut);\n                accountsToTry.clear();\n                for ( const auto& accountToTry : accounts )\n                {\n                    accountsToTry.push_back(accountToTry);\n                }\n                strError = \"\";\n                if (!pwallet->CreateTransaction(accountsToTry, vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError))\n                {\n                    throw JSONRPCError(RPC_WALLET_ERROR, strError);\n                }\n            }\n            else\n            {\n                throw JSONRPCError(RPC_WALLET_ERROR, strError);\n            }\n        }\n        else\n        {\n            throw JSONRPCError(RPC_WALLET_ERROR, strError);\n        }\n    }\n    CValidationState state;\n    if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) {\n        strError = strprintf(\"Error: The transaction was rejected! Reason given: %s\", state.GetRejectReason());\n        throw JSONRPCError(RPC_WALLET_ERROR, strError);\n    }\n}\n\nUniValue sendtoaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)\n        throw std::runtime_error(\n            \"sendtoaddress \\\"address\\\" amount ( \\\"comment\\\" \\\"comment_to\\\" subtract_fee_from_amount )\\n\"\n            \"\\nSend an amount to a given address using the currently active account. If you want to use a specific account then use sendtoaddressfromaccount instead\\n\"\n            + HelpRequiringPassphrase(pwallet) +\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"            (string, required) The \" GLOBAL_APPNAME \" address to send to.\\n\"\n            \"2. \\\"amount\\\"             (numeric or string, required) The amount in \" + CURRENCY_UNIT + \" to send. eg 0.1\\n\"\n            \"3. \\\"comment\\\"            (string, optional) A comment used to store what the transaction is for. \\n\"\n            \"                             This is not part of the transaction, just kept in your wallet.\\n\"\n            \"4. \\\"comment_to\\\"         (string, optional) A comment to store the name of the person or organization \\n\"\n            \"                             to which you're sending the transaction. This is not part of the \\n\"\n            \"                             transaction, just kept in your wallet.\\n\"\n            \"5. subtractfeefromamount  (boolean, optional, default=false) The fee will be deducted from the amount being sent.\\n\"\n            \"                             The recipient will receive less \" GLOBAL_APPNAME \" than you enter in the amount field.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"txid\\\"                  (string) The transaction id.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"sendtoaddress\", \"\\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1\")\n            + HelpExampleCli(\"sendtoaddress\", \"\\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1 \\\"donation\\\" \\\"seans outpost\\\"\")\n            + HelpExampleCli(\"sendtoaddress\", \"\\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1 \\\"\\\" \\\"\\\" true\")\n            + HelpExampleRpc(\"sendtoaddress\", \"\\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\", 0.1, \\\"donation\\\", \\\"seans outpost\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CNativeAddress address(request.params[0].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n\n    // Amount\n    CAmount nAmount = AmountFromValue(request.params[1]);\n    if (nAmount <= 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount for send\");\n\n    // Wallet comments\n    CWalletTx wtx;\n    if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())\n        wtx.mapValue[\"comment\"] = request.params[2].get_str();\n    if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())\n        wtx.mapValue[\"to\"]      = request.params[3].get_str();\n\n    bool fSubtractFeeFromAmount = false;\n    if (request.params.size() > 4)\n        fSubtractFeeFromAmount = request.params[4].get_bool();\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    SendMoney(pwallet, pwallet->getActiveAccount(), address.Get(), nAmount, fSubtractFeeFromAmount, wtx);\n\n    return wtx.GetHash().GetHex();\n}\n\nUniValue sendtoaddressfromaccount(const JSONRPCRequest& request)\n{\n    #ifdef ENABLE_WALLET\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    DS_LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);\n    #else\n    LOCK(cs_main);\n    #endif\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)\n        throw std::runtime_error(\n            \"sendtoaddressfromaccount \\\"from_account\\\" \\\"muntaddress\\\" amount ( \\\"comment\\\" \\\"comment-to\\\" subtract_fee_from_amount )\\n\"\n            \"\\nSend an amount to \\\"muntaddress\\\" using \\\"account\\\"\\n\"\n            + HelpRequiringPassphrase(pwallet) +\n            \"\\nArguments:\\n\"\n            \"1. \\\"from_account\\\"           (string, required) The UUID or unique label of the account to move funds from. May be the currently active account using \\\"\\\".\\n\"\n            \"2. \\\"muntaddress\\\"            (string, required) The \" GLOBAL_APPNAME \" address to send to.\\n\"\n            \"3. \\\"amount\\\"                 (numeric or string, required) The amount in \" + CURRENCY_UNIT + \" to send. eg 0.1\\n\"\n            \"4. \\\"comment\\\"                (string, optional) A comment used to store what the transaction is for. \\n\"\n            \"                            This is not part of the transaction, just kept in your wallet.\\n\"\n            \"5. \\\"comment-to\\\"             (string, optional) A comment to store the name of the person or organization \\n\"\n            \"                            to which you're sending the transaction. This is not part of the \\n\"\n            \"                            transaction, just kept in your wallet.\\n\"\n            \"6. subtract_fee_from_amount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\\n\"\n            \"                             The recipient will receive less \" GLOBAL_APPNAME \" than you enter in the amount field.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"transactionid\\\"  (string) The transaction id.\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"sendtoaddressfromaccount\", \"\\\"My account\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1\")\n            + HelpExampleCli(\"sendtoaddressfromaccount\", \"\\\"\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1 \\\"donation\\\" \\\"seans outpost\\\"\")\n            + HelpExampleCli(\"sendtoaddressfromaccount\", \"\\\"My account\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.1 \\\"\\\" \\\"\\\" true\")\n            + HelpExampleRpc(\"sendtoaddressfromaccount\", \"\\\"\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\", 0.1, \\\"donation\\\", \\\"seans outpost\\\"\")\n        );\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n\n    CNativeAddress address(request.params[1].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n\n    // Amount\n    CAmount nAmount = AmountFromValue(request.params[2]);\n    if (nAmount <= 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount for send\");\n\n    // Wallet comments\n    CWalletTx wtx;\n    if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())\n        wtx.mapValue[\"comment\"] = request.params[2].get_str();\n    if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())\n        wtx.mapValue[\"to\"]      = request.params[4].get_str();\n\n    bool fSubtractFeeFromAmount = false;\n    if (request.params.size() > 5)\n        fSubtractFeeFromAmount = request.params[5].get_bool();\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    SendMoney(pwallet, fromAccount, address.Get(), nAmount, fSubtractFeeFromAmount, wtx);\n\n    return wtx.GetHash().GetHex();\n}\n\nUniValue listaddressgroupings(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp)\n        throw std::runtime_error(\n            \"listaddressgroupings\\n\"\n            \"\\nLists groups of addresses which have had their common ownership\\n\"\n            \"made public by common use as inputs or as the resulting change\\n\"\n            \"in past transactions\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  [\\n\"\n            \"    [\\n\"\n            \"      \\\"address\\\",            (string) The \" GLOBAL_APPNAME \" address\\n\"\n            \"      amount,                 (numeric) The amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"account\\\"             (string, optional) The account\\n\"\n            \"    ]\\n\"\n            \"    ,...\\n\"\n            \"  ]\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listaddressgroupings\", \"\")\n            + HelpExampleRpc(\"listaddressgroupings\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    UniValue jsonGroupings(UniValue::VARR);\n    std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();\n    for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {\n        UniValue jsonGrouping(UniValue::VARR);\n        for(CTxDestination address : grouping)\n        {\n            UniValue addressInfo(UniValue::VARR);\n            addressInfo.push_back(CNativeAddress(address).ToString());\n            addressInfo.push_back(ValueFromAmount(balances[address]));\n            //fixme: (FUT) CBSU - Rather do this inside GetAddressGroupings\n            for(const auto& [accountUUID, account] : pwallet->mapAccounts)\n            {\n                (unused)(accountUUID);\n                if (IsMine(*account, address))\n                {\n                    addressInfo.push_back(account->getLabel());\n                }\n            }\n            jsonGrouping.push_back(addressInfo);\n        }\n        jsonGroupings.push_back(jsonGrouping);\n    }\n    return jsonGroupings;\n}\n\nUniValue signmessage(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 2)\n        throw std::runtime_error(\n            \"signmessage \\\"address\\\" \\\"message\\\"\\n\"\n            \"\\nSign a message with the private key of an address\"\n            + HelpRequiringPassphrase(pwallet) + \"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"         (string, required) The \" GLOBAL_APPNAME \" address to use for the private key.\\n\"\n            \"2. \\\"message\\\"         (string, required) The message to create a signature of.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"signature\\\"          (string) The signature of the message encoded in base 64\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nUnlock the wallet for 30 seconds\\n\"\n            + HelpExampleCli(\"walletpassphrase\", \"\\\"mypassphrase\\\" 30\") +\n            \"\\nCreate the signature\\n\"\n            + HelpExampleCli(\"signmessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" \\\"my message\\\"\") +\n            \"\\nVerify the signature\\n\"\n            + HelpExampleCli(\"verifymessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" \\\"signature\\\" \\\"my message\\\"\") +\n            \"\\nAs json rpc\\n\"\n            + HelpExampleRpc(\"signmessage\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\", \\\"my message\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    std::string strAddress = request.params[0].get_str();\n    std::string strMessage = request.params[1].get_str();\n\n    CNativeAddress addr(strAddress);\n    if (!addr.IsValid())\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid address\");\n\n    CKeyID keyID;\n    if (!addr.GetKeyID(keyID))\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Address does not refer to key\");\n\n    CKey key;\n    if (!pwallet->GetKey(keyID, key)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Private key not available\");\n    }\n\n    CHashWriter ss(SER_GETHASH, 0);\n    ss << strMessageMagic;\n    ss << strMessage;\n\n    std::vector<unsigned char> vchSig;\n    if (!key.SignCompact(ss.GetHash(), vchSig))\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Sign failed\");\n\n    return EncodeBase64(&vchSig[0], vchSig.size());\n}\n\nUniValue getreceivedbyaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"getreceivedbyaddress \\\"address\\\" ( min_conf )\\n\"\n            \"\\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\\n\"\n            \"\\nNB! For witness addresses this will not return locked funds or earnings, but will return regular received funds that have been sent to either of the two address keys.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"address\\\"     (string, required) The \" GLOBAL_APPNAME \" address for transactions.\\n\"\n            \"2. min_conf      (numeric, optional, default=1) Only include transactions confirmed at least this many times.\\n\"\n            \"\\nResult:\\n\"\n            \"amount           (numeric) The total amount in \" + CURRENCY_UNIT + \" received at this address.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nThe amount from transactions with at least 1 confirmation\\n\"\n            + HelpExampleCli(\"getreceivedbyaddress\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\"\") +\n            \"\\nThe amount including unconfirmed transactions, zero confirmations\\n\"\n            + HelpExampleCli(\"getreceivedbyaddress\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" 0\") +\n            \"\\nThe amount with at least 6 confirmation, very safe\\n\"\n            + HelpExampleCli(\"getreceivedbyaddress\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\" 6\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"getreceivedbyaddress\", \"\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\", 6\")\n       );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // Munt address\n    CNativeAddress address = CNativeAddress(request.params[0].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n\n    // Below check handles both script, standard key hash and witness cases\n    if (!IsMine(*pwallet, address.Get()))\n    {\n        return ValueFromAmount(0);\n    }\n\n    // Minimum confirmations\n    int nMinDepth = 1;\n    if (request.params.size() > 1)\n        nMinDepth = request.params[1].get_int();\n\n    // Tally\n    CAmount nAmount = 0;\n    for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet)\n    {\n        const CWalletTx& wtx = pairWtx.second;\n        if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx, chainActive))\n            continue;\n\n        for(const CTxOut& txout : wtx.tx->vout)\n        {\n            bool matchedOutput = false;\n            CKeyID idPrimary;\n            CKeyID idSecondary;\n            address.GetKeyID(idPrimary, &idSecondary);\n            switch(txout.output.nType)\n            {\n                case CTxOutType::ScriptLegacyOutput:\n                {\n                    if (txout.output.scriptPubKey == GetScriptForDestination(address.Get())) { matchedOutput = true; }; break;\n                }\n                case CTxOutType::StandardKeyHashOutput:\n                {\n                    bool primaryMatched = ((!idPrimary.IsNull()) && txout.output.standardKeyHash.keyID == idPrimary);\n                    bool secondaryMatched = ((!idSecondary.IsNull()) && txout.output.standardKeyHash.keyID == idSecondary);\n                    if (primaryMatched || secondaryMatched)\n                        matchedOutput = true;\n                    break;\n                }\n                //NB! The below test will not succeed except on a new witness account because PoW2WitnessOutput is always in coinbase\n                //Leaving the code here for clarity and possible future implementation.\n                #if 0\n                case CTxOutType::PoW2WitnessOutput:\n                {\n                    bool primaryMatched = ((!idPrimary.IsNull()) && txout.output.witnessDetails.witnessKeyID == idPrimary);\n                    bool secondaryMatched = ((!idSecondary.IsNull()) && txout.output.witnessDetails.spendingKeyID == idSecondary);\n                    if (primaryMatched || secondaryMatched)\n                        matchedOutput = true;\n                    break;\n                }\n                #else\n                case CTxOutType::PoW2WitnessOutput: break;\n                #endif\n            }\n            if (matchedOutput && wtx.GetDepthInMainChain() >= nMinDepth)\n                nAmount += txout.nValue;\n        }\n    }\n\n    return  ValueFromAmount(nAmount);\n}\n\n\nUniValue getbalance(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 3)\n        throw std::runtime_error(\n            \"getbalance ( \\\"account\\\" min_conf include_watchonly )\\n\"\n            \"\\nIf account is not specified, returns the server's total available balance.\\n\"\n            \"If account is specified, returns the balance in the account.\\n\"\n            \"Note that the account \\\"\\\" is not the same as leaving the parameter out, but rather will use the currently selected account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"      (string, optional). The selected account, or \\\"*\\\" for entire wallet. It may be the currently active account using \\\"\\\".\\n\"\n            \"                     specific account name to find the balance associated with wallet keys in\\n\"\n            \"                     a named account, or as the empty string (\\\"\\\") to find the balance\\n\"\n            \"                     associated with wallet keys not in any named account, or as \\\"*\\\" to find\\n\"\n            \"                     the balance associated with all wallet keys regardless of account.\\n\"\n            \"2. min_conf          (numeric, optional, default=1) Only include transactions confirmed at least this many times.\\n\"\n            \"3. include_watchonly (bool, optional, default=false) Also include balance in watch-only addresses (see 'importaddress')\\n\"\n            \"\\nResult:\\n\"\n            \"amount              (numeric) The total amount in \" + CURRENCY_UNIT + \" received for this account.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nThe total amount in the wallet\\n\"\n            + HelpExampleCli(\"getbalance\", \"\") +\n            \"\\nThe total amount in the wallet at least 5 blocks confirmed\\n\"\n            + HelpExampleCli(\"getbalance\", \"\\\"*\\\" 6\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"getbalance\", \"\\\"*\\\", 6\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    boost::uuids::uuid accountUUID = boost::uuids::nil_generator()();\n    int nMinDepth = 1;\n    bool includeWatchOnly = false;\n\n    CAccount* forAccount = nullptr;\n    if (request.params.size() > 0)\n    {\n        if (request.params.size() > 1)\n            nMinDepth = request.params[1].get_int();\n\n        if (request.params.size() > 2)\n            includeWatchOnly = request.params[2].get_bool();\n\n        if (request.params[0].get_str() != \"\" && request.params[0].get_str() != \"*\")\n        {\n            //NB! - Intermediate AccountFromValue step is required in order to handle default account semantics.\n            forAccount = request.params[0].get_str() != \"*\" ? AccountFromValue(pwallet, request.params[0], true) : nullptr;\n            if (forAccount)\n                accountUUID = forAccount->getUUID();\n        }\n    }\n\n    int64_t nTime = GetTimeMicros();\n    CAmount balance = pwallet->GetBalanceForDepth(nMinDepth, forAccount, false, true);\n    if (includeWatchOnly)\n        balance += pwallet->GetWatchOnlyBalance(nMinDepth, forAccount, true);\n    int64_t nTime1 = GetTimeMicros();\n    LogPrint(BCLog::BENCH, \"GetBalanceTiming: %.2fms [%.2fs]\\n\", (nTime1 - nTime) * 0.001, (nTime1 - nTime) * 0.000001);\n    return ValueFromAmount(balance);\n}\n\nUniValue getunconfirmedbalance(const JSONRPCRequest &request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n                \"getunconfirmedbalance \\\"for_account\\\"\\n\"\n                \"\\nArguments:\\n\"\n                \"1. \\\"for_account\\\"   (string, optional) The UUID or unique label of the account you want the balance for.\\n\"\n                \"Returns the server's total unconfirmed balance\\n\");\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* forAccount = nullptr;\n    std::string accountSpecifier = \"\";\n    if (request.params.size() > 0)\n    {\n        accountSpecifier = request.params[0].get_str();\n        forAccount = AccountFromValue(pwallet, request.params[0], false);\n    }\n    if (!forAccount && !accountSpecifier.empty() && accountSpecifier != std::string(\"*\"))\n        throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid account label or UUID\"));\n\n    return ValueFromAmount(pwallet->GetUnconfirmedBalance(forAccount, false, true));\n}\n\nUniValue getimmaturebalance(const JSONRPCRequest &request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n                \"getimmaturebalance \\\"for_account\\\"\\n\"\n                \"\\nArguments:\\n\"\n                \"1. \\\"for_account\\\"   (string, optional) The UUID or unique label of the account you want the balance for.\\n\"\n                \"Returns the server's total immature balance\\n\");\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* forAccount = nullptr;\n    std::string accountSpecifier = \"\";\n    if (request.params.size() > 0)\n    {\n        accountSpecifier = request.params[0].get_str();\n        forAccount = AccountFromValue(pwallet, request.params[0], false);\n    }\n    if (!forAccount && !accountSpecifier.empty() && accountSpecifier != std::string(\"*\"))\n        throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid account label or UUID\"));\n\n    return ValueFromAmount(pwallet->GetImmatureBalance(forAccount, false, true));\n}\n\nUniValue getlockedbalance(const JSONRPCRequest &request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n                \"getlockedbalance \\\"for_account\\\"\\n\"\n                \"\\nArguments:\\n\"\n                \"1. \\\"for_account\\\"   (string, optional) The UUID or unique label of the account you want the balance for.\\n\"\n                \"Returns the server's total locked balance (inclusive of immature and unconfirmed transactions)\\n\");\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* forAccount = nullptr;\n    std::string accountSpecifier = \"\";\n    if (request.params.size() > 0)\n    {\n        accountSpecifier = request.params[0].get_str();\n        forAccount = AccountFromValue(pwallet, request.params[0], false);\n    }\n    if (!forAccount && !accountSpecifier.empty() && accountSpecifier != std::string(\"*\"))\n        throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid account label or UUID\"));\n\n    return ValueFromAmount(pwallet->GetLockedBalance(forAccount, true));\n}\n\nUniValue movecmd(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)\n        throw std::runtime_error(\n            \"move \\\"from_account\\\" \\\"to_account\\\" amount ( min_conf \\\"comment\\\" )\\n\"\n            \"\\nMove a specified amount from one account in your wallet to another.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"from_account\\\"   (string, required) The UUID or unique label of the account to move funds from. May be the currently active account using \\\"\\\".\\n\"\n            \"2. \\\"to_account\\\"     (string, required) The UUID or unique label of the account to move funds to. May be the currently active account using \\\"\\\".\\n\"\n            \"3. amount               (numeric) Quantity of \" + CURRENCY_UNIT + \" to move between accounts, -1 to move all available funds (based on min depth).\\n\"\n            \"4. \\\"min_conf\\\"       (numeric, optional, default=1) Only use funds with at least this many confirmations.\\n\"\n            \"5. \\\"comment\\\"        (string, optional) An optional comment, stored in the wallet only.\\n\"\n            \"\\nResult:\\n\"\n            \"true|false              (boolean) true if successful.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nMove 0.01 \" + CURRENCY_UNIT + \" from the default account to the account named tabby\\n\"\n            + HelpExampleCli(\"move\", \"\\\"\\\" \\\"tabby\\\" 0.01\") +\n            \"\\nMove 0.01 \" + CURRENCY_UNIT + \" timotei to akiko with a comment and funds have 6 confirmations\\n\"\n            + HelpExampleCli(\"move\", \"\\\"timotei\\\" \\\"akiko\\\" 0.01 6 \\\"happy birthday!\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"move\", \"\\\"timotei\\\", \\\"akiko\\\", 0.01, 6, \\\"happy birthday!\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n    CAccount* toAccount = AccountFromValue(pwallet, request.params[1], true);\n\n    if (fromAccount->getUUID() == toAccount->getUUID())\n    {\n        throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"From and to account are the same\"));\n    }\n\n    std::string strComment = \"\";\n    int nMinDepth = 1;\n    if (request.params.size() > 3)\n        nMinDepth = request.params[3].get_int();\n    if (request.params.size() > 4)\n        strComment = request.params[4].get_str();\n\n    bool subtractFeeFromAmount = false;\n    CAmount nBalance = pwallet->GetBalanceForDepth(nMinDepth, fromAccount, false, true);\n\n    CAmount nAmount = 0;\n    if (request.params[2].getValStr() == \"-1\")\n    {\n        subtractFeeFromAmount = true;\n        nAmount = nBalance;\n    }\n    else\n        nAmount = AmountFromValue(request.params[2]);\n\n    if (nAmount <= 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount for send\");\n\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // Check funds\n    if (nAmount > nBalance)\n        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, \"Account has insufficient funds\");\n\n    CWalletTx wtx;\n    wtx.strFromAccount = getUUIDAsString(fromAccount->getUUID());\n    if (!strComment.empty())\n        wtx.mapValue[\"comment\"] = request.params[4].get_str();\n\n\n    CReserveKeyOrScript receiveKey(pwallet, toAccount, KEYCHAIN_EXTERNAL);\n    CPubKey vchPubKey;\n    if (!receiveKey.GetReservedKey(vchPubKey))\n        throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n\n    SendMoney(pwallet, fromAccount, vchPubKey.GetID(), nAmount, subtractFeeFromAmount, wtx);\n\n    receiveKey.KeepKey();\n\n    return true;\n}\n\nUniValue defrag(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 5 || request.params.size() > 6)\n    {\n        throw std::runtime_error(\n            \"defrag \\\"from_account\\\" \\\"to_address\\\" min_input_amount max_input_amount max_input_quantity ( min_conf )\\n\"\n            \"\\nCombine all inputs larger than \\\"min_input_amount\\\" and smaller than \\\"max_input_amount\\\" into a single output belonging to \\\"to_address\\\"\\n\"\n            \"\\nStop when number of inputs exceeds \\\"max_input_quantity\\\"; for large wallet repeated calls may be necessary before all inputs are combined\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"from_account\\\"     (string, required) The UUID or unique label of the account to move funds from. May be the currently active account using \\\"\\\".\\n\"\n            \"2. \\\"to_address\\\"       (string, required) Address to combine funds into. May be the currently active account using \\\"\\\".\\n\"\n            \"3. min_input_amount   (numeric string) Ignore inputs smaller than this size\\n\"\n            \"4. max_input_amount   (numeric string) Ignore inputs larger than this size\\n\"\n            \"5. max_input_quantity (numeric) Maximum number of inputs to combine in a single run\\n\"\n            \"6. min_conf           (numeric, optional, default=100) Only use funds with at least this many confirmations.\\n\"\n            \"\\nResult:\\n\"\n            \"Returns the number of inputs that were combined on this run.\\n\"\n        );\n    }\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    LogPrintf(\"DEFRAG: Start account defrag\\n\");\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n    CNativeAddress receiveAddress(request.params[1].get_str());\n    if (!receiveAddress.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n\n    CAmount nMinimumAmount = AmountFromValue(request.params[2]);\n    CAmount nMaximumAmount = AmountFromValue(request.params[3]);\n    uint64_t nMaximumCount = request.params[4].get_int();\n\n    int nMinDepth = 100;\n    if (request.params.size() > 5)\n        nMinDepth = request.params[5].get_int();\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // Grab as many outputs as possible that meet our constraints\n    LogPrintf(\"DEFRAG: Retrieving a list of viable inputs matching our paramaters\\n\");\n    std::vector<COutput> vecOutputs;\n    pwallet->AvailableCoins(fromAccount, vecOutputs, false, NULL, nMinimumAmount, nMaximumAmount, MAX_MONEY, nMaximumCount, nMinDepth);\n    if (vecOutputs.size()==0)\n        return 0;\n\n    LogPrintf(\"DEFRAG: Retrieved [%d] inputs matching our paramaters\\n\", vecOutputs.size());\n    uint64_t totalInputCount = 0;\n    uint64_t assembledTransactionCount=0;\n    const int batchSize=1500;\n    do\n    {\n        LogPrintf(\"DEFRAG: Assembling transaction [%d] of [%d]\\n\", ++assembledTransactionCount, vecOutputs.size()/batchSize);\n\n        // Place them all in our transaction and sum the total value\n        CMutableTransaction rawTx(CURRENT_TX_VERSION_POW2);\n        CAmount nTotalSent=0;\n        uint64_t inputCount = 0;\n        for (uint64_t idx = totalInputCount; idx < vecOutputs.size(); ++idx )\n        {\n            const auto& input = vecOutputs[idx];\n            CTxIn in(COutPoint(input.tx->GetHash(), input.i), CScript(), 0, 0);\n            rawTx.vin.push_back(in);\n            nTotalSent += input.tx->tx->vout[input.i].nValue;\n            if (++totalInputCount > nMaximumCount)\n                break;\n            if (++inputCount > batchSize)\n                break;\n        }\n\n        if (rawTx.vin.size() == 0)\n            break;\n\n        // Add a single output to which the entire amount goes\n        CScript scriptPubKey = GetScriptForDestination(receiveAddress.Get());\n        {\n            CTxOut out(nTotalSent, scriptPubKey);\n            rawTx.vout.push_back(out);\n        }\n\n        // Calculate transaction fee\n        const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(rawTx, pwallet);\n        CAmount nFeeNeeded = std::max(pwallet->GetMinimumFee(maxNewTxSize, 1, ::mempool, ::feeEstimator), COIN/100);\n        nFeeNeeded = std::min(nFeeNeeded, COIN/30);\n\n        // re-add the output, this time subtracting the transaction fee\n        rawTx.vout.clear();\n        {\n            CTxOut out(nTotalSent-nFeeNeeded, scriptPubKey);\n            rawTx.vout.push_back(out);\n        }\n\n        // Sign and send transaction\n        LogPrintf(\"DEFRAG: Sign and send transaction\\n\");\n        std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n        std::string strError;\n        if (!pwallet->SignAndSubmitTransaction(*reservedScript, rawTx, strError))\n        {\n            LogPrintf(\"DEFRAG: Failed to sign transaction [%s]\\n\", strError.c_str());\n        }\n    }\n    while (totalInputCount < nMaximumCount);\n\n    LogPrintf(\"DEFRAG: Done, processed [%d] inputs\\n\", totalInputCount);\n    return totalInputCount;\n}\n\n\nUniValue sendfrom(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)\n        throw std::runtime_error(\n            \"sendfrom \\\"from_account\\\" \\\"to_address\\\" amount ( min_conf \\\"comment\\\" \\\"comment_to\\\" )\\n\"\n            \"\\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a \" GLOBAL_APPNAME \" address.\"\n            + HelpRequiringPassphrase(pwallet) + \"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"from_account\\\"      (string, required) The UUID or unique label of the account to send funds from. May be the active account using \\\"\\\".\\n\"\n            \"                       Specifying an account does not influence coin selection, but it does associate the newly created\\n\"\n            \"                       transaction with the account, so the account's balance computation and transaction history can reflect\\n\"\n            \"                       the spend.\\n\"\n            \"2. \\\"to_address\\\"        (string, required) The \" GLOBAL_APPNAME \" address to send funds to.\\n\"\n            \"3. amount              (numeric or string, required) The amount in \" + CURRENCY_UNIT + \" (transaction fee is added on top).\\n\"\n            \"4. min_conf            (numeric, optional, default=1) Only use funds with at least this many confirmations.\\n\"\n            \"5. \\\"comment\\\"           (string, optional) A comment used to store what the transaction is for. \\n\"\n            \"                       This is not part of the transaction, just kept in your wallet.\\n\"\n            \"6. \\\"comment_to\\\"        (string, optional) An optional comment to store the name of the person or organization \\n\"\n            \"                       to which you're sending the transaction. This is not part of the transaction, \\n\"\n            \"                       it is just kept in your wallet.\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"txid\\\"                 (string) The transaction id.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nSend 0.01 \" + CURRENCY_UNIT + \" from the default account to the address, must have at least 1 confirmation\\n\"\n            + HelpExampleCli(\"sendfrom\", \"\\\"\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.01\") +\n            \"\\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\\n\"\n            + HelpExampleCli(\"sendfrom\", \"\\\"tabby\\\" \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 0.01 6 \\\"donation\\\" \\\"seans outpost\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"sendfrom\", \"\\\"tabby\\\", \\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\", 0.01, 6, \\\"donation\\\", \\\"seans outpost\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n    CNativeAddress address(request.params[1].get_str());\n    if (!address.IsValid())\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid \" GLOBAL_APPNAME \" address\");\n    CAmount nAmount = AmountFromValue(request.params[2]);\n    if (nAmount <= 0)\n        throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount for send\");\n    int nMinDepth = 1;\n    if (request.params.size() > 3)\n        nMinDepth = request.params[3].get_int();\n\n    CWalletTx wtx;\n    wtx.strFromAccount = getUUIDAsString(fromAccount->getUUID());\n    if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())\n        wtx.mapValue[\"comment\"] = request.params[4].get_str();\n    if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())\n        wtx.mapValue[\"to\"]      = request.params[5].get_str();\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // Check funds\n    CAmount nBalance = pwallet->GetBalanceForDepth(nMinDepth, fromAccount, false, true);\n    if (nAmount > nBalance)\n        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, \"Account has insufficient funds\");\n\n    SendMoney(pwallet, fromAccount, address.Get(), nAmount, false, wtx);\n\n    return wtx.GetHash().GetHex();\n}\n\n\nUniValue sendmany(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)\n        throw std::runtime_error(\n            \"sendmany \\\"from_account\\\" {\\\"address_or_account\\\":amount,...} ( min_conf \\\"comment\\\" [\\\"address_or_account\\\",...] )\\n\"\n            \"\\nSend multiple times. Amounts are double-precision floating point numbers.\"\n            + HelpRequiringPassphrase(pwallet) + \"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"from_account\\\"        (string, required) The UUID or unique label of the account to send the funds from. Should be \\\"\\\" for the active account\\n\"\n            \"2. \\\"amounts\\\"             (string, required) A json object with addresses and amounts\\n\"\n            \"    {\\n\"\n            \"      \\\"address_or_account\\\":amount   (numeric or string) The \" GLOBAL_APPNAME \" address or account is the key, the numeric amount (can be string) in \" + CURRENCY_UNIT + \" is the value\\n\"\n            \"      ,...\\n\"\n            \"    }\\n\"\n            \"3. min_conf              (numeric, optional, default=1) Only use the balance confirmed at least this many times.\\n\"\n            \"4. \\\"comment\\\"             (string, optional) A comment\\n\"\n            \"5. subtract_fee_from     (array, optional) A json array with addresses.\\n\"\n            \"                         The fee will be equally deducted from the amount of each selected address.\\n\"\n            \"                         Those recipients will receive less \" GLOBAL_APPNAME \" than you enter in their corresponding amount field.\\n\"\n            \"                         If no addresses are specified here, the sender pays the fee.\\n\"\n            \"    [\\n\"\n            \"      \\\"address_or_account\\\"          (string) Subtract fee from this address or account\\n\"\n            \"      ,...\\n\"\n            \"    ]\\n\"\n            \"\\nResult:\\n\"\n            \"\\\"txid\\\"                   (string) The transaction id for the send. Only 1 transaction is created regardless of \\n\"\n            \"                                    the number of addresses.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nSend two amounts to two different addresses:\\n\"\n            + HelpExampleCli(\"sendmany\", \"\\\"\\\" \\\"{\\\\\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\\\\\":0.01,\\\\\\\"G353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\\\\\":0.02}\\\"\") +\n            \"\\nSend two amounts to two different addresses setting the confirmation and comment:\\n\"\n            + HelpExampleCli(\"sendmany\", \"\\\"\\\" \\\"{\\\\\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\\\\\":0.01,\\\\\\\"G353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\\\\\":0.02}\\\" 6 \\\"testing\\\"\") +\n            \"\\nSend two amounts to two different addresses, subtract fee from amount:\\n\"\n            + HelpExampleCli(\"sendmany\", \"\\\"\\\" \\\"{\\\\\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\\\\\":0.01,\\\\\\\"G353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\\\\\":0.02}\\\" 1 \\\"\\\" \\\"[\\\\\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\\\\\",\\\\\\\"G353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\\\\\"]\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"sendmany\", \"\\\"\\\", \\\"{\\\\\\\"GD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\\\\\":0.01,\\\\\\\"G353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\\\\\":0.02}\\\", 6, \\\"testing\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (pwallet->GetBroadcastTransactions() && !g_connman) {\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n    }\n\n    CAccount* fromAccount = AccountFromValue(pwallet, request.params[0], true);\n    UniValue sendTo = request.params[1].get_obj();\n    int nMinDepth = 1;\n    if (request.params.size() > 2)\n        nMinDepth = request.params[2].get_int();\n\n    CWalletTx wtx;\n    wtx.strFromAccount = getUUIDAsString(fromAccount->getUUID());\n    if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())\n        wtx.mapValue[\"comment\"] = request.params[3].get_str();\n\n    UniValue subtractFeeFromAmount(UniValue::VARR);\n    if (request.params.size() > 4)\n        subtractFeeFromAmount = request.params[4].get_array();\n\n    std::set<CNativeAddress> setAddress;\n    std::vector<CRecipient> vecSend;\n\n    CAmount totalAmount = 0;\n    std::vector<std::string> keys = sendTo.getKeys();\n    std::vector<CReserveKeyOrScript> reservedKeys;\n    for(const std::string& name_ : keys)\n    {\n        CNativeAddress address(name_);\n\n        CAccount* toAccount = nullptr;\n        try{ toAccount = AccountFromValue(pwallet, name_, false); } catch(...) {}\n        if (toAccount)\n        {\n            CReserveKeyOrScript receiveKey(pwallet, toAccount, KEYCHAIN_EXTERNAL);\n            CPubKey vchPubKey;\n            if (!receiveKey.GetReservedKey(vchPubKey))\n                throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, \"Error: Keypool ran out, please call keypoolrefill first\");\n\n            address = CNativeAddress(vchPubKey.GetID());\n\n            reservedKeys.emplace_back(std::move(receiveKey));\n        }\n        else\n        {\n            if (setAddress.count(address))\n                throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid parameter, duplicated address: \")+name_);\n            setAddress.insert(address);\n        }\n\n        if (!address.IsValid())\n            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(\"Invalid \" GLOBAL_APPNAME \" address: \")+name_);\n\n        CAmount nAmount = AmountFromValue(sendTo[name_]);\n        if (nAmount <= 0)\n            throw JSONRPCError(RPC_TYPE_ERROR, \"Invalid amount for send\");\n        totalAmount += nAmount;\n\n        bool fSubtractFeeFromAmount = false;\n        for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {\n            const UniValue& addr = subtractFeeFromAmount[idx];\n            if (addr.get_str() == name_)\n                fSubtractFeeFromAmount = true;\n        }\n\n        CRecipient recipient = GetRecipientForDestination(address.Get(), nAmount, fSubtractFeeFromAmount, GetPoW2Phase(chainActive.Tip()));\n        vecSend.push_back(recipient);\n    }\n\n    EnsureWalletIsUnlocked(pwallet);\n\n    // Check funds\n    CAmount nBalance = pwallet->GetBalanceForDepth(nMinDepth, fromAccount, false, true);\n    if (totalAmount > nBalance)\n        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, \"Account has insufficient funds\");\n\n    // Send\n    CReserveKeyOrScript keyChange(pwallet, fromAccount, KEYCHAIN_CHANGE);\n    CAmount nFeeRequired = 0;\n    int nChangePosRet = -1;\n    std::string strFailReason;\n    bool fCreated = pwallet->CreateTransaction(fromAccount, vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);\n    if (!fCreated)\n        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);\n    CValidationState state;\n    if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {\n        strFailReason = strprintf(\"Transaction commit failed:: %s\", state.GetRejectReason());\n        throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);\n    }\n\n    for (auto& reservedKey : reservedKeys)\n    {\n        reservedKey.KeepKey();\n    }\n\n    return wtx.GetHash().GetHex();\n}\n\n// Defined in rpc/misc.cpp\nextern CScript _createmultisig_redeemScript(CAccount* const forAccount, const UniValue& params);\n\nUniValue addmultisigaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 3)\n    {\n        std::string msg = \"addmultisigaddress num_required [\\\"key\\\",...] ( \\\"account\\\" )\\n\"\n            \"\\nAdd a num-required-to-sign multisignature address to the wallet.\\n\"\n            \"Each key is a \" GLOBAL_APPNAME \" address or hex-encoded public key.\\n\"\n            \"Assign address to the specified account.\\n\"\n\n            \"\\nArguments:\\n\"\n            \"1. num_required   (numeric, required) The number of required signatures out of the n keys or addresses.\\n\"\n            \"2. \\\"keys\\\"         (string, required) A json array of \" GLOBAL_APPNAME \" addresses or hex-encoded public keys\\n\"\n            \"     [\\n\"\n            \"       \\\"address\\\"  (string) \" GLOBAL_APPNAME \" address or hex-encoded public key\\n\"\n            \"       ...,\\n\"\n            \"     ]\\n\"\n            \"3. \\\"account\\\"      (string) An account to assign the addresses to.\\n\"\n\n            \"\\nResult:\\n\"\n            \"\\\"address\\\"         (string) A \" GLOBAL_APPNAME \" address associated with the keys.\\n\"\n\n            \"\\nExamples:\\n\"\n            \"\\nAdd a multisig address from 2 addresses\\n\"\n            + HelpExampleCli(\"addmultisigaddress\", \"2 \\\"[\\\\\\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\\\\\",\\\\\\\"G71sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\\\\\"]\\\"\") +\n            \"\\nAs json rpc call\\n\"\n            + HelpExampleRpc(\"addmultisigaddress\", \"2, \\\"[\\\\\\\"G6sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\\\\\",\\\\\\\"G71sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\\\\\"]\\\"\")\n        ;\n        throw std::runtime_error(msg);\n    }\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    CAccount* forAccount = AccountFromValue(pactiveWallet, request.params[2], false);\n    \n    // Construct using pay-to-script-hash:\n    CScript inner = _createmultisig_redeemScript(forAccount, request.params);\n    CScriptID innerID(inner);\n    forAccount->AddCScript(inner);\n\n    return CNativeAddress(innerID).ToString();\n}\n\nstruct tallyitem\n{\n    CAmount nAmount;\n    int nConf;\n    std::vector<uint256> txids;\n    bool fIsWatchonly;\n    tallyitem()\n    {\n        nAmount = 0;\n        nConf = std::numeric_limits<int>::max();\n        fIsWatchonly = false;\n    }\n};\n\nUniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts)\n{\n    // Minimum confirmations\n    int nMinDepth = 1;\n    if (params.size() > 0)\n        nMinDepth = params[0].get_int();\n\n    // Whether to include empty accounts\n    bool fIncludeEmpty = false;\n    if (params.size() > 1)\n        fIncludeEmpty = params[1].get_bool();\n\n    isminefilter filter = ISMINE_SPENDABLE;\n    if(params.size() > 2)\n        if(params[2].get_bool())\n            filter = filter | ISMINE_WATCH_ONLY;\n\n    // Tally\n    std::map<CNativeAddress, tallyitem> mapTally;\n    for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {\n        const CWalletTx& wtx = pairWtx.second;\n\n        if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx, chainActive))\n            continue;\n\n        int nDepth = wtx.GetDepthInMainChain();\n        if (nDepth < nMinDepth)\n            continue;\n\n        for(const CTxOut& txout : wtx.tx->vout)\n        {\n            CTxDestination address;\n            if (!ExtractDestination(txout, address))\n                continue;\n\n            isminefilter mine = IsMine(*pwallet, address);\n            if(!(mine & filter))\n                continue;\n\n            tallyitem& item = mapTally[address];\n            item.nAmount += txout.nValue;\n            item.nConf = std::min(item.nConf, nDepth);\n            item.txids.push_back(wtx.GetHash());\n            if (mine & ISMINE_WATCH_ONLY)\n                item.fIsWatchonly = true;\n        }\n    }\n\n    // Reply\n    UniValue ret(UniValue::VARR);\n    std::map<boost::uuids::uuid, tallyitem> mapAccountTally;\n    for (const auto& [accountUUID, account] : pwallet->mapAccounts)\n    {\n        if (account->m_State == AccountState::Shadow)\n            continue;\n\n        std::string accountLabel = account->getLabel();\n\n        if (account->m_State == AccountState::Shadow)\n            accountLabel = pwallet->mapAccounts[accountUUID]->getLabel();\n\n        std::set<CKeyID> setAddress;\n        account->GetKeys(setAddress);\n        for(const auto& key : setAddress)\n        {\n            CNativeAddress address(key);\n            std::map<CNativeAddress, tallyitem>::iterator it = mapTally.find(address);\n            if (it == mapTally.end() && !fIncludeEmpty)\n                continue;\n\n            CAmount nAmount = 0;\n            int nConf = std::numeric_limits<int>::max();\n            bool fIsWatchonly = false;\n            if (it != mapTally.end())\n            {\n                nAmount = (*it).second.nAmount;\n                nConf = (*it).second.nConf;\n                fIsWatchonly = (*it).second.fIsWatchonly;\n            }\n\n            if (fByAccounts)\n            {\n                tallyitem& _item = mapAccountTally[accountUUID];\n                _item.nAmount += nAmount;\n                _item.nConf = std::min(_item.nConf, nConf);\n                _item.fIsWatchonly = fIsWatchonly;\n            }\n            else\n            {\n                UniValue obj(UniValue::VOBJ);\n                if(fIsWatchonly)\n                    obj.pushKV(\"involvesWatchonly\", true);\n                obj.pushKV(\"address\",       address.ToString());\n                obj.pushKV(\"account\",       getUUIDAsString(accountUUID));\n                obj.pushKV(\"accountlabel\",  accountLabel);\n                obj.pushKV(\"amount\",        ValueFromAmount(nAmount));\n                obj.pushKV(\"confirmations\", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));\n                if (!fByAccounts)\n                    obj.pushKV(\"label\", accountLabel);\n                UniValue transactions(UniValue::VARR);\n                if (it != mapTally.end())\n                {\n                    for(const uint256& _item : (*it).second.txids)\n                    {\n                        transactions.push_back(_item.GetHex());\n                    }\n                }\n                obj.pushKV(\"txids\", transactions);\n                ret.push_back(obj);\n            }\n        }\n    }\n\n    if (fByAccounts)\n    {\n        for (auto it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)\n        {\n            CAmount nAmount = (*it).second.nAmount;\n            int nConf = (*it).second.nConf;\n            UniValue obj(UniValue::VOBJ);\n            if((*it).second.fIsWatchonly)\n                obj.pushKV(\"involvesWatchonly\", true);\n            obj.pushKV(\"account\",       getUUIDAsString((*it).first));\n            obj.pushKV(\"amount\",        ValueFromAmount(nAmount));\n            obj.pushKV(\"confirmations\", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));\n            ret.push_back(obj);\n        }\n    }\n\n    return ret;\n}\n\nUniValue listreceivedbyaddress(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 3)\n        throw std::runtime_error(\n            \"listreceivedbyaddress ( min_conf include_empty include_watchonly)\\n\"\n            \"\\nList balances by receiving address.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. min_conf          (numeric, optional, default=1) The minimum number of confirmations before payments are included.\\n\"\n            \"2. include_empty     (bool, optional, default=false) Whether to include addresses that haven't received any payments.\\n\"\n            \"3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\\n\"\n\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"involvesWatchonly\\\" : true,        (bool) Only returned if imported addresses were involved in transaction\\n\"\n            \"    \\\"address\\\" : \\\"receivingaddress\\\",  (string) The receiving address\\n\"\n            \"    \\\"account\\\" : \\\"accountname\\\",       (string) The account of the receiving address.\\n\"\n            \"    \\\"amount\\\" : x.xxx,                  (numeric) The total amount in \" + CURRENCY_UNIT + \" received by the address\\n\"\n            \"    \\\"confirmations\\\" : n,               (numeric) The number of confirmations of the most recent transaction included\\n\"\n            \"    \\\"label\\\" : \\\"label\\\",               (string) A comment for the address/transaction, if any\\n\"\n            \"    \\\"txids\\\": [\\n\"\n            \"       n,                                (numeric) The ids of transactions received with the address \\n\"\n            \"       ...\\n\"\n            \"    ]\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listreceivedbyaddress\", \"\")\n            + HelpExampleCli(\"listreceivedbyaddress\", \"6 true\")\n            + HelpExampleRpc(\"listreceivedbyaddress\", \"6, true, true\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    return ListReceived(pwallet, request.params, false);\n}\n\nUniValue listreceivedbyaccount(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 3)\n        throw std::runtime_error(\n            \"listreceivedbyaccount ( min_conf include_empty include_watchonly)\\n\"\n            \"\\nList balances by account.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. min_conf          (numeric, optional, default=1) The minimum number of confirmations before payments are included.\\n\"\n            \"2. include_empty     (bool, optional, default=false) Whether to include accounts that haven't received any payments.\\n\"\n            \"3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\\n\"\n\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"involvesWatchonly\\\" : true,   (bool) Only returned if imported addresses were involved in transaction\\n\"\n            \"    \\\"account\\\" : \\\"UUID\\\",         (string) The UUID of the receiving account\\n\"\n            \"    \\\"amount\\\" : x.xxx,             (numeric) The total amount received by addresses with this account\\n\"\n            \"    \\\"confirmations\\\" : n,          (numeric) The number of confirmations of the most recent transaction included\\n\"\n            \"    \\\"label\\\" : \\\"label\\\"           (string) A comment for the address/transaction, if any\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listreceivedbyaccount\", \"\")\n            + HelpExampleCli(\"listreceivedbyaccount\", \"6 true\")\n            + HelpExampleRpc(\"listreceivedbyaccount\", \"6, true, true\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    return ListReceived(pwallet, request.params, true);\n}\n\nstatic void MaybePushAddress(UniValue & entry, const CTxDestination &dest)\n{\n    CNativeAddress addr;\n    if (addr.Set(dest))\n        entry.pushKV(\"address\", addr.ToString());\n}\n\nvoid ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)\n{\n    CAmount nFee;\n    std::string strSentAccount;\n    std::list<COutputEntry> listReceived;\n    std::list<COutputEntry> listSent;\n\n    std::vector<CAccount*> doForAccounts;\n    if (strAccount == std::string(\"*\"))\n    {\n        for (const auto& [accountUUID, account] : pwallet->mapAccounts)\n        {\n            (unused)accountUUID;\n            if (account->m_State != AccountState::Shadow)\n            {\n                doForAccounts.push_back(account);\n            }\n            //fixme: (FUT) (ACCOUNTS) (MED) - Handle shadow children\n        }\n    }\n    else\n    {\n        doForAccounts.push_back(AccountFromValue(pwallet, strAccount, true));\n    }\n\n\n    for (auto& account : doForAccounts)\n    {\n        wtx.GetAmounts(listReceived, listSent, nFee, filter, account);\n\n        bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);\n\n        // Sent\n        if ((!listSent.empty() || nFee != 0) )\n        {\n            for(const COutputEntry& s : listSent)\n            {\n                UniValue entry(UniValue::VOBJ);\n                if(involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY))\n                    entry.pushKV(\"involvesWatchonly\", true);\n                entry.pushKV(\"account\", getUUIDAsString(account->getUUID()));\n                entry.pushKV(\"accountlabel\", account->getLabel());\n                MaybePushAddress(entry, s.destination);\n                entry.pushKV(\"category\", \"send\");\n                entry.pushKV(\"amount\", ValueFromAmount(-s.amount));\n                if (pwallet->mapAddressBook.count(CNativeAddress(s.destination).ToString())) {\n                    entry.pushKV(\"label\", pwallet->mapAddressBook[CNativeAddress(s.destination).ToString()].name);\n                }\n                entry.pushKV(\"vout\", s.vout);\n                entry.pushKV(\"fee\", ValueFromAmount(-nFee));\n                if (fLong)\n                    WalletTxToJSON(wtx, entry);\n                entry.pushKV(\"abandoned\", wtx.isAbandoned());\n                ret.push_back(entry);\n            }\n        }\n\n        // Received\n        if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)\n        {\n            for(const COutputEntry& r : listReceived)\n            {\n                UniValue entry(UniValue::VOBJ);\n                if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {\n                    entry.pushKV(\"involvesWatchonly\", true);\n                }\n                entry.pushKV(\"account\", getUUIDAsString(account->getUUID()));\n                entry.pushKV(\"accountlabel\", account->getLabel());\n                MaybePushAddress(entry, r.destination);\n                if (wtx.IsCoinBase())\n                {\n                    if (wtx.GetDepthInMainChain() < 1)\n                        entry.pushKV(\"category\", \"orphan\");\n                    else if (wtx.GetBlocksToMaturity() > 0)\n                        entry.pushKV(\"category\", \"immature\");\n                    else\n                        entry.pushKV(\"category\", \"generate\");\n                }\n                else\n                {\n                    entry.pushKV(\"category\", \"receive\");\n                }\n                entry.pushKV(\"amount\", ValueFromAmount(r.amount));\n                if (pwallet->mapAddressBook.count(CNativeAddress(r.destination).ToString())) {\n                    entry.pushKV(\"label\", account);\n                }\n                entry.pushKV(\"vout\", r.vout);\n                if (fLong)\n                    WalletTxToJSON(wtx, entry);\n                ret.push_back(entry);\n            }\n        }\n    }\n}\n\nvoid AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret)\n{\n    bool fAllAccounts = (strAccount == std::string(\"*\"));\n\n    if (fAllAccounts || acentry.strAccount == strAccount)\n    {\n        UniValue entry(UniValue::VOBJ);\n        entry.pushKV(\"account\", acentry.strAccount);\n        entry.pushKV(\"category\", \"move\");\n        entry.pushKV(\"time\", acentry.nTime);\n        entry.pushKV(\"amount\", ValueFromAmount(acentry.nCreditDebit));\n        entry.pushKV(\"otheraccount\", acentry.strOtherAccount);\n        entry.pushKV(\"comment\", acentry.strComment);\n        ret.push_back(entry);\n    }\n}\n\nUniValue listtransactions(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 4)\n        throw std::runtime_error(\n            \"listtransactions ( \\\"account\\\" count skip include_watchonly)\\n\"\n            \"\\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"account\\\"    (string, optional) The account UUID or unique label. \\\"*\\\" for all accounts.\\n\"\n            \"2. count          (numeric, optional, default=10) The number of transactions to return\\n\"\n            \"3. skip           (numeric, optional, default=0) The number of transactions to skip\\n\"\n            \"4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"account\\\":\\\"accountname\\\",       (string) The account name associated with the transaction. \\n\"\n            \"                                                It will be \\\"\\\" for the active account.\\n\"\n            \"    \\\"address\\\":\\\"address\\\",    (string) The \" GLOBAL_APPNAME \" address of the transaction. Not present for \\n\"\n            \"                                                move transactions (category = move).\\n\"\n            \"    \\\"category\\\":\\\"send|receive|move\\\", (string) The transaction category. 'move' is a local (off blockchain)\\n\"\n            \"                                                transaction between accounts, and not associated with an address,\\n\"\n            \"                                                transaction id or block. 'send' and 'receive' transactions are \\n\"\n            \"                                                associated with an address, transaction id and block details\\n\"\n            \"    \\\"amount\\\": x.xxx,          (numeric) The amount in \" + CURRENCY_UNIT + \". This is negative for the 'send' category, and for the\\n\"\n            \"                                         'move' category for moves outbound. It is positive for the 'receive' category,\\n\"\n            \"                                         and for the 'move' category for inbound funds.\\n\"\n            \"    \\\"label\\\": \\\"label\\\",       (string) A comment for the address/transaction, if any\\n\"\n            \"    \\\"vout\\\": n,                (numeric) the vout value\\n\"\n            \"    \\\"fee\\\": x.xxx,             (numeric) The amount of the fee in \" + CURRENCY_UNIT + \". This is negative and only available for the \\n\"\n            \"                                         'send' category of transactions.\\n\"\n            \"    \\\"confirmations\\\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and \\n\"\n            \"                                         'receive' category of transactions. Negative confirmations indicate the\\n\"\n            \"                                         transaction conflicts with the block chain\\n\"\n            \"    \\\"trusted\\\": xxx,           (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\\n\"\n            \"    \\\"blockhash\\\": \\\"hashvalue\\\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\\n\"\n            \"                                          category of transactions.\\n\"\n            \"    \\\"blockindex\\\": n,          (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\\n\"\n            \"                                          category of transactions.\\n\"\n            \"    \\\"blocktime\\\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\\n\"\n            \"    \\\"txid\\\": \\\"transactionid\\\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"time\\\": xxx,              (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\\n\"\n            \"    \\\"timereceived\\\": xxx,      (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \\n\"\n            \"                                          for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"comment\\\": \\\"...\\\",       (string) If a comment is associated with the transaction.\\n\"\n            \"    \\\"otheraccount\\\": \\\"accountname\\\",  (string) DEPRECATED. For the 'move' category of transactions, the account the funds came \\n\"\n            \"                                          from (for receiving funds, positive amounts), or went to (for sending funds,\\n\"\n            \"                                          negative amounts).\\n\"\n            \"    \\\"bip125-replaceable\\\": \\\"yes|no|unknown\\\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\\n\"\n            \"                                                     may be unknown for unconfirmed transactions not in the mempool\\n\"\n            \"    \\\"abandoned\\\": xxx          (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \\n\"\n            \"                                         'send' category of transactions.\\n\"\n            \"  }\\n\"\n            \"]\\n\"\n\n            \"\\nExamples:\\n\"\n            \"\\nList the most recent 10 transactions in the systems\\n\"\n            + HelpExampleCli(\"listtransactions\", \"\") +\n            \"\\nList transactions 100 to 120\\n\"\n            + HelpExampleCli(\"listtransactions\", \"\\\"*\\\" 20 100\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"listtransactions\", \"\\\"*\\\", 20, 100\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    std::string strAccount = \"*\";\n    if (request.params.size() > 0)\n        strAccount = request.params[0].get_str();\n    int nCount = 10;\n    if (request.params.size() > 1)\n        nCount = request.params[1].get_int();\n    int nFrom = 0;\n    if (request.params.size() > 2)\n        nFrom = request.params[2].get_int();\n    isminefilter filter = ISMINE_SPENDABLE;\n    if(request.params.size() > 3)\n        if(request.params[3].get_bool())\n            filter = filter | ISMINE_WATCH_ONLY;\n\n    if (nCount < 0)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Negative count\");\n    if (nFrom < 0)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"Negative from\");\n\n    UniValue ret(UniValue::VARR);\n\n    const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;\n\n    // iterate backwards until we have nCount items to return:\n    for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)\n    {\n        CWalletTx *const pwtx = (*it).second.first;\n        if (pwtx != 0)\n            ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);\n        CAccountingEntry *const pacentry = (*it).second.second;\n        if (pacentry != 0)\n            AcentryToJSON(*pacentry, strAccount, ret);\n\n        if ((int)ret.size() >= (nCount+nFrom)) break;\n    }\n    // ret is newest to oldest\n\n    if (nFrom > (int)ret.size())\n        nFrom = ret.size();\n    if ((nFrom + nCount) > (int)ret.size())\n        nCount = ret.size() - nFrom;\n\n    std::vector<UniValue> arrTmp = ret.getValues();\n\n    std::vector<UniValue>::iterator first = arrTmp.begin();\n    std::advance(first, nFrom);\n    std::vector<UniValue>::iterator last = arrTmp.begin();\n    std::advance(last, nFrom+nCount);\n\n    if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());\n    if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);\n\n    std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest\n\n    ret.clear();\n    ret.setArray();\n    ret.push_backV(arrTmp);\n\n    return ret;\n}\n\nUniValue listsinceblock(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp)\n        throw std::runtime_error(\n            \"listsinceblock ( \\\"blockhash\\\" target_confirmations include_watchonly)\\n\"\n            \"\\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"blockhash\\\"            (string, optional) The block hash to list transactions since\\n\"\n            \"2. target_confirmations:    (numeric, optional) The confirmations required, must be 1 or more\\n\"\n            \"3. include_watchonly:       (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"transactions\\\": [\\n\"\n            \"    \\\"account\\\":\\\"accountname\\\",       (string) The account name associated with the transaction.\\n\"\n            \"    \\\"address\\\":\\\"address\\\",    (string) The \" GLOBAL_APPNAME \" address of the transaction. Not present for move transactions (category = move).\\n\"\n            \"    \\\"category\\\":\\\"send|receive\\\",     (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\\n\"\n            \"    \\\"amount\\\": x.xxx,          (numeric) The amount in \" + CURRENCY_UNIT + \". This is negative for the 'send' category, and for the 'move' category for moves \\n\"\n            \"                                          outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\\n\"\n            \"    \\\"vout\\\" : n,               (numeric) the vout value\\n\"\n            \"    \\\"fee\\\": x.xxx,             (numeric) The amount of the fee in \" + CURRENCY_UNIT + \". This is negative and only available for the 'send' category of transactions.\\n\"\n            \"    \\\"confirmations\\\": n,       (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\\n\"\n            \"                                          When it's < 0, it means the transaction conflicted that many blocks ago.\\n\"\n            \"    \\\"blockhash\\\": \\\"hashvalue\\\",     (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"blockindex\\\": n,          (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"blocktime\\\": xxx,         (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\\n\"\n            \"    \\\"txid\\\": \\\"transactionid\\\",  (string) The transaction id. Available for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"time\\\": xxx,              (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\\n\"\n            \"    \\\"timereceived\\\": xxx,      (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\\n\"\n            \"    \\\"bip125-replaceable\\\": \\\"yes|no|unknown\\\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\\n\"\n            \"                                                   may be unknown for unconfirmed transactions not in the mempool\\n\"\n            \"    \\\"abandoned\\\": xxx,         (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the 'send' category of transactions.\\n\"\n            \"    \\\"comment\\\": \\\"...\\\",       (string) If a comment is associated with the transaction.\\n\"\n            \"    \\\"label\\\" : \\\"label\\\"       (string) A comment for the address/transaction, if any\\n\"\n            \"    \\\"to\\\": \\\"...\\\",            (string) If a comment to is associated with the transaction.\\n\"\n             \"  ],\\n\"\n            \"  \\\"lastblock\\\": \\\"lastblockhash\\\"     (string) The hash of the last block\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"listsinceblock\", \"\")\n            + HelpExampleCli(\"listsinceblock\", \"\\\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\\\" 6\")\n            + HelpExampleRpc(\"listsinceblock\", \"\\\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\\\", 6\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    const CBlockIndex *pindex = NULL;\n    int target_confirms = 1;\n    isminefilter filter = ISMINE_SPENDABLE;\n\n    if (request.params.size() > 0)\n    {\n        uint256 blockId;\n\n        blockId.SetHex(request.params[0].get_str());\n        BlockMap::iterator it = mapBlockIndex.find(blockId);\n        if (it != mapBlockIndex.end())\n        {\n            pindex = it->second;\n            if (chainActive[pindex->nHeight] != pindex)\n            {\n                // the block being asked for is a part of a deactivated chain;\n                // we don't want to depend on its perceived height in the block\n                // chain, we want to instead use the last common ancestor\n                pindex = chainActive.FindFork(pindex);\n            }\n        }\n    }\n\n    if (request.params.size() > 1)\n    {\n        target_confirms = request.params[1].get_int();\n\n        if (target_confirms < 1)\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter\");\n    }\n\n    if (request.params.size() > 2 && request.params[2].get_bool())\n    {\n        filter = filter | ISMINE_WATCH_ONLY;\n    }\n\n    int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;\n\n    UniValue transactions(UniValue::VARR);\n\n    for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {\n        CWalletTx tx = pairWtx.second;\n\n        if (depth == -1 || tx.GetDepthInMainChain() < depth)\n            ListTransactions(pwallet, tx, \"*\", 0, true, transactions, filter);\n    }\n\n    CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];\n    uint256 lastblock = pblockLast ? pblockLast->GetBlockHashPoW2() : uint256();\n\n    UniValue ret(UniValue::VOBJ);\n    ret.pushKV(\"transactions\", transactions);\n    ret.pushKV(\"lastblock\", lastblock.GetHex());\n\n    return ret;\n}\n\nUniValue gettransaction(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"gettransaction \\\"txid\\\" ( include_watchonly )\\n\"\n            \"\\nGet detailed information about in-wallet transaction <txid>\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"                  (string, required) The transaction id\\n\"\n            \"2. \\\"include_watchonly\\\"     (bool, optional, default=false) Whether to include watch-only addresses in balance calculation and details[]\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"amount\\\" : x.xxx,        (numeric) The transaction amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"  \\\"fee\\\": x.xxx,            (numeric) The amount of the fee in \" + CURRENCY_UNIT + \". This is negative and only available for the \\n\"\n            \"                              'send' category of transactions.\\n\"\n            \"  \\\"confirmations\\\" : n,     (numeric) The number of confirmations\\n\"\n            \"  \\\"blockhash\\\" : \\\"hash\\\",  (string) The block hash\\n\"\n            \"  \\\"blockindex\\\" : xx,       (numeric) The index of the transaction in the block that includes it\\n\"\n            \"  \\\"blocktime\\\" : ttt,       (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\\n\"\n            \"  \\\"txid\\\" : \\\"transactionid\\\",   (string) The transaction id.\\n\"\n            \"  \\\"time\\\" : ttt,            (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\\n\"\n            \"  \\\"timereceived\\\" : ttt,    (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\\n\"\n            \"  \\\"bip125-replaceable\\\": \\\"yes|no|unknown\\\",  (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\\n\"\n            \"                                                   may be unknown for unconfirmed transactions not in the mempool\\n\"\n            \"  \\\"details\\\" : [\\n\"\n            \"    {\\n\"\n            \"      \\\"account\\\" : \\\"accountname\\\",  (string) The account name involved in the transaction.\\n\"\n            \"      \\\"address\\\" : \\\"address\\\",          (string) The \" GLOBAL_APPNAME \" address involved in the transaction\\n\"\n            \"      \\\"category\\\" : \\\"send|receive\\\",    (string) The category, either 'send' or 'receive'\\n\"\n            \"      \\\"amount\\\" : x.xxx,                 (numeric) The amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"label\\\" : \\\"label\\\",              (string) A comment for the address/transaction, if any\\n\"\n            \"      \\\"vout\\\" : n,                       (numeric) the vout value\\n\"\n            \"      \\\"fee\\\": x.xxx,                     (numeric) The amount of the fee in \" + CURRENCY_UNIT + \". This is negative and only available for the \\n\"\n            \"                                           'send' category of transactions.\\n\"\n            \"      \\\"abandoned\\\": xxx                  (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \\n\"\n            \"                                           'send' category of transactions.\\n\"\t\t\t\n            \"    }\\n\"\n            \"    ,...\\n\"\n            \"  ],\\n\"\n            \"  \\\"hex\\\" : \\\"data\\\"         (string) Raw data for transaction\\n\"\n            \"}\\n\"\n\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"gettransaction\", \"\\\"G075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\\\"\")\n            + HelpExampleCli(\"gettransaction\", \"\\\"G075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\\\" true\")\n            + HelpExampleRpc(\"gettransaction\", \"\\\"G075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    uint256 hash;\n    hash.SetHex(request.params[0].get_str());\n\n    isminefilter filter = ISMINE_SPENDABLE;\n    if(request.params.size() > 1)\n        if(request.params[1].get_bool())\n            filter = filter | ISMINE_WATCH_ONLY;\n\n    UniValue entry(UniValue::VOBJ);\n    if (!pwallet->mapWallet.count(hash)) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid or non-wallet transaction id\");\n    }\n    const CWalletTx& wtx = pwallet->mapWallet[hash];\n\n    CAmount nCredit = wtx.GetCredit(filter);\n    CAmount nDebit = wtx.GetDebit(filter);\n    CAmount nNet = nCredit - nDebit;\n    CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);\n\n    entry.pushKV(\"amount\", ValueFromAmount(nNet - nFee));\n    if (wtx.IsFromMe(filter))\n        entry.pushKV(\"fee\", ValueFromAmount(nFee));\n\n    WalletTxToJSON(wtx, entry);\n\n    UniValue details(UniValue::VARR);\n    ListTransactions(pwallet, wtx, \"*\", 0, false, details, filter);\n    entry.pushKV(\"details\", details);\n\n    std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());\n    entry.pushKV(\"hex\", strHex);\n\n    return entry;\n}\n\nUniValue abandontransaction(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"abandontransaction \\\"txid\\\"\\n\"\n            \"\\nMark in-wallet transaction <txid> as abandoned\\n\"\n            \"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\\n\"\n            \"for their inputs to be respent.  It can be used to replace \\\"stuck\\\" or evicted transactions.\\n\"\n            \"It only works on transactions which are not included in a block and are not currently in the mempool.\\n\"\n            \"It has no effect on transactions which are already conflicted or abandoned.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"txid\\\"    (string, required) The transaction id\\n\"\n            \"\\nResult:\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"abandontransaction\", \"\\\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\\\"\")\n            + HelpExampleRpc(\"abandontransaction\", \"\\\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    uint256 hash;\n    hash.SetHex(request.params[0].get_str());\n\n    if (!pwallet->mapWallet.count(hash)) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Invalid or non-wallet transaction id\");\n    }\n    if (!pwallet->AbandonTransaction(hash)) {\n        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"Transaction not eligible for abandonment\");\n    }\n\n    return NullUniValue;\n}\n\n\nUniValue backupwallet(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 1)\n        throw std::runtime_error(\n            \"backupwallet \\\"destination\\\"\\n\"\n            \"\\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"destination\\\"   (string) The destination directory or file\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"backupwallet\", \"\\\"backup.dat\\\"\")\n            + HelpExampleRpc(\"backupwallet\", \"\\\"backup.dat\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    std::string strDest = request.params[0].get_str();\n    if (!pwallet->BackupWallet(strDest)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Error: Wallet backup failed!\");\n    }\n\n    return NullUniValue;\n}\n\n\nUniValue keypoolrefill(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 1)\n        throw std::runtime_error(\n            \"keypoolrefill ( new_size )\\n\"\n            \"\\nFills the keypool.\"\n            + HelpRequiringPassphrase(pwallet) + \"\\n\"\n            \"\\nArguments\\n\"\n            \"1. new_size    (numeric, optional, default=100) The new keypool size\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"keypoolrefill\", \"\")\n            + HelpExampleRpc(\"keypoolrefill\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool\n    unsigned int kpSize = 0;\n    if (request.params.size() > 0) {\n        if (request.params[0].get_int() < 0)\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, expected valid size.\");\n        kpSize = (unsigned int)request.params[0].get_int();\n    }\n\n    EnsureWalletIsUnlocked(pwallet);\n    pwallet->TopUpKeyPool(kpSize);\n\n    //fixme: (FUT) (ACCOUNTS)\n    /*\n    if (pwallet->GetKeyPoolSize() < kpSize) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Error refreshing keypool.\");\n    }\n    */\n\n    return NullUniValue;\n}\n\n\nUniValue walletpassphrase(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if ((request.fHelp || request.params.size() != 2)) {\n        throw std::runtime_error(\n            \"walletpassphrase \\\"passphrase\\\" timeout\\n\"\n            \"\\nStores the wallet decryption key in memory for 'timeout' seconds.\\n\"\n            \"This is needed prior to performing transactions related to private keys such as sending \" GLOBAL_APPNAME \"\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"passphrase\\\"     (string, required) The wallet passphrase\\n\"\n            \"2. timeout            (numeric, required) The time to keep the decryption key in seconds.\\n\"\n            \"\\nNote:\\n\"\n            \"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\\n\"\n            \"time that overrides the old one.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nunlock the wallet for 60 seconds\\n\"\n            + HelpExampleCli(\"walletpassphrase\", \"\\\"my pass phrase\\\" 60\") +\n            \"\\nLock the wallet again (before 60 seconds)\\n\"\n            + HelpExampleCli(\"walletlock\", \"\") +\n            \"\\nAs json rpc call\\n\"\n            + HelpExampleRpc(\"walletpassphrase\", \"\\\"my pass phrase\\\", 60\")\n        );\n    }\n\n    if (request.fHelp)\n        return true;\n    if (!pwallet->IsCrypted()) {\n        throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, \"Error: running with an unencrypted wallet, but walletpassphrase was called.\");\n    }\n    \n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed\n    SecureString strWalletPass;\n    strWalletPass.reserve(100);\n    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)\n    // Alternately, find a way to make request.params[0] mlock()'d to begin with.\n    strWalletPass = request.params[0].get_str().c_str();\n\n    int64_t nSleepTime = request.params[1].get_int64();\n    if (strWalletPass.length() > 0)\n    {\n        if (!pwallet->UnlockWithTimeout(strWalletPass, nSleepTime)) {\n            throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, \"Error: The wallet passphrase entered was incorrect.\");\n        }\n    }\n    else\n        throw std::runtime_error(\n            \"walletpassphrase <passphrase> <timeout>\\n\"\n            \"Stores the wallet decryption key in memory for <timeout> seconds.\");\n\n    pwallet->TopUpKeyPool();\n\n    return NullUniValue;\n}\n\n\nUniValue walletpassphrasechange(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if ((request.fHelp || request.params.size() != 2)) {\n        throw std::runtime_error(\n            \"walletpassphrasechange \\\"oldpassphrase\\\" \\\"newpassphrase\\\"\\n\"\n            \"\\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"oldpassphrase\\\"      (string) The current passphrase\\n\"\n            \"2. \\\"newpassphrase\\\"      (string) The new passphrase\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"walletpassphrasechange\", \"\\\"old one\\\" \\\"new one\\\"\")\n            + HelpExampleRpc(\"walletpassphrasechange\", \"\\\"old one\\\", \\\"new one\\\"\")\n        );\n    }\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (request.fHelp)\n        return true;\n    if (!pwallet->IsCrypted()) {\n        throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, \"Error: running with an unencrypted wallet, but walletpassphrasechange was called.\");\n    }\n\n    // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)\n    // Alternately, find a way to make request.params[0] mlock()'d to begin with.\n    SecureString strOldWalletPass;\n    strOldWalletPass.reserve(100);\n    strOldWalletPass = request.params[0].get_str().c_str();\n\n    SecureString strNewWalletPass;\n    strNewWalletPass.reserve(100);\n    strNewWalletPass = request.params[1].get_str().c_str();\n\n    if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)\n        throw std::runtime_error(\n            \"walletpassphrasechange <oldpassphrase> <newpassphrase>\\n\"\n            \"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.\");\n\n    if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {\n        throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, \"Error: The wallet passphrase entered was incorrect.\");\n    }\n\n    return NullUniValue;\n}\n\n\nUniValue walletlock(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if ((request.fHelp || request.params.size() != 0)) {\n        throw std::runtime_error(\n            \"walletlock\\n\"\n            \"\\nRemoves the wallet encryption key from memory, locking the wallet.\\n\"\n            \"After calling this method, you will need to call walletpassphrase again\\n\"\n            \"before being able to call any methods which require the wallet to be unlocked.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nSet the passphrase for 2 minutes to perform a transaction\\n\"\n            + HelpExampleCli(\"walletpassphrase\", \"\\\"my pass phrase\\\" 120\") +\n            \"\\nPerform a send (requires passphrase set)\\n\"\n            + HelpExampleCli(\"sendtoaddress\", \"\\\"GM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\" 1.0\") +\n            \"\\nClear the passphrase since we are done before 2 minutes is up\\n\"\n            + HelpExampleCli(\"walletlock\", \"\") +\n            \"\\nAs json rpc call\\n\"\n            + HelpExampleRpc(\"walletlock\", \"\")\n        );\n    }\n\n    if (request.fHelp)\n        return true;\n    if (!pwallet->IsCrypted()) {\n        throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, \"Error: running with an unencrypted wallet, but walletlock was called.\");\n    }\n    \n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n    pwallet->Lock();\n\n    return NullUniValue;\n}\n\n\nUniValue encryptwallet(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if ((request.fHelp || request.params.size() != 1)) {\n        throw std::runtime_error(\n            \"encryptwallet \\\"passphrase\\\"\\n\"\n            \"\\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\\n\"\n            \"After this, any calls that interact with private keys such as sending or signing \\n\"\n            \"will require the passphrase to be set prior the making these calls.\\n\"\n            \"Use the walletpassphrase call for this, and then walletlock call.\\n\"\n            \"If the wallet is already encrypted, use the walletpassphrasechange call.\\n\"\n            \"Note that this will shutdown the server.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. \\\"passphrase\\\"    (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nEncrypt you wallet\\n\"\n            + HelpExampleCli(\"encryptwallet\", \"\\\"my pass phrase\\\"\") +\n            \"\\nNow set the passphrase to use the wallet, such as for signing or sending \" GLOBAL_APPNAME \"\\n\"\n            + HelpExampleCli(\"walletpassphrase\", \"\\\"my pass phrase\\\"\") +\n            \"\\nNow we can so something like sign\\n\"\n            + HelpExampleCli(\"signmessage\", \"\\\"address\\\" \\\"test message\\\"\") +\n            \"\\nNow lock the wallet again by removing the passphrase\\n\"\n            + HelpExampleCli(\"walletlock\", \"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"encryptwallet\", \"\\\"my pass phrase\\\"\")\n        );\n    }\n\n    if (request.fHelp)\n        return true;\n    if (pwallet->IsCrypted()) {\n        throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, \"Error: running with an encrypted wallet, but encryptwallet was called.\");\n    }\n    \n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)\n    // Alternately, find a way to make request.params[0] mlock()'d to begin with.\n    SecureString strWalletPass;\n    strWalletPass.reserve(100);\n    strWalletPass = request.params[0].get_str().c_str();\n\n    if (strWalletPass.length() < 1)\n        throw std::runtime_error(\n            \"encryptwallet <passphrase>\\n\"\n            \"Encrypts the wallet with <passphrase>.\");\n\n    if (!pwallet->EncryptWallet(strWalletPass)) {\n        throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, \"Error: Failed to encrypt the wallet.\");\n    }\n\n    // BDB seems to have a bad habit of writing old data into\n    // slack space in .dat files; that is bad if the old data is\n    // unencrypted private keys. So:\n    LogPrintf(\"shutdown: triggering shutdown to encrypt wallet\");\n    AppLifecycleManager::gApp->shutdown();\n    return \"wallet encrypted; \" GLOBAL_APPNAME \" server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.\";\n}\n\nUniValue lockunspent(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)\n        throw std::runtime_error(\n            \"lockunspent unlock ([{\\\"txid\\\":\\\"txid\\\",\\\"vout\\\":n},...])\\n\"\n            \"\\nUpdates list of temporarily unspendable outputs.\\n\"\n            \"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\\n\"\n            \"If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\\n\"\n            \"A locked transaction output will not be chosen by automatic coin selection, when spending \" GLOBAL_APPNAME \".\\n\"\n            \"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\\n\"\n            \"is always cleared (by virtue of process exit) when a node stops or fails.\\n\"\n            \"Also see the listunspent call\\n\"\n            \"\\nArguments:\\n\"\n            \"1. unlock            (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\\n\"\n            \"2. \\\"transactions\\\"  (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\\n\"\n            \"     [           (json array of json objects)\\n\"\n            \"       {\\n\"\n            \"         \\\"txid\\\":\\\"id\\\",    (string) The transaction id\\n\"\n            \"         \\\"vout\\\": n         (numeric) The output number\\n\"\n            \"       }\\n\"\n            \"       ,...\\n\"\n            \"     ]\\n\"\n\n            \"\\nResult:\\n\"\n            \"true|false    (boolean) Whether the command was successful or not\\n\"\n\n            \"\\nExamples:\\n\"\n            \"\\nList the unspent transactions\\n\"\n            + HelpExampleCli(\"listunspent\", \"\") +\n            \"\\nLock an unspent transaction\\n\"\n            + HelpExampleCli(\"lockunspent\", \"false \\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\\\\\",\\\\\\\"vout\\\\\\\":1}]\\\"\") +\n            \"\\nList the locked transactions\\n\"\n            + HelpExampleCli(\"listlockunspent\", \"\") +\n            \"\\nUnlock the transaction again\\n\"\n            + HelpExampleCli(\"lockunspent\", \"true \\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\\\\\",\\\\\\\"vout\\\\\\\":1}]\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"lockunspent\", \"false, \\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\\\\\",\\\\\\\"vout\\\\\\\":1}]\\\"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (request.params.size() == 1)\n        RPCTypeCheck(request.params, {UniValue::VBOOL});\n    else\n        RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VARR});\n\n    bool fUnlock = request.params[0].get_bool();\n\n    if (request.params.size() == 1) {\n        if (fUnlock)\n            pwallet->UnlockAllCoins();\n        return true;\n    }\n\n    UniValue outputs = request.params[1].get_array();\n    for (unsigned int idx = 0; idx < outputs.size(); idx++) {\n        const UniValue& output = outputs[idx];\n        if (!output.isObject())\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, expected object\");\n        const UniValue& o = output.get_obj();\n\n        RPCTypeCheckObj(o,\n            {\n                {\"txid\", UniValueType(UniValue::VSTR)},\n                {\"vout\", UniValueType(UniValue::VNUM)},\n            });\n\n        std::string txid = find_value(o, \"txid\").get_str();\n        if (!IsHex(txid))\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, expected hex txid\");\n\n        int nOutput = find_value(o, \"vout\").get_int();\n        if (nOutput < 0)\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid parameter, vout must be positive\");\n\n        COutPoint outpt(uint256S(txid), nOutput);\n\n        if (fUnlock)\n            pwallet->UnlockCoin(outpt);\n        else\n            pwallet->LockCoin(outpt);\n    }\n\n    return true;\n}\n\nUniValue listlockunspent(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 0)\n        throw std::runtime_error(\n            \"listlockunspent\\n\"\n            \"\\nReturns list of temporarily unspendable outputs.\\n\"\n            \"See the lockunspent call to lock and unlock transactions for spending.\\n\"\n            \"\\nResult:\\n\"\n            \"[\\n\"\n            \"  {\\n\"\n            \"    \\\"txid\\\" : \\\"transactionid\\\",     (string) The transaction id locked\\n\"\n            \"    \\\"vout\\\" : n                      (numeric) The vout value\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nList the unspent transactions\\n\"\n            + HelpExampleCli(\"listunspent\", \"\") +\n            \"\\nLock an unspent transaction\\n\"\n            + HelpExampleCli(\"lockunspent\", \"false \\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\\\\\",\\\\\\\"vout\\\\\\\":1}]\\\"\") +\n            \"\\nList the locked transactions\\n\"\n            + HelpExampleCli(\"listlockunspent\", \"\") +\n            \"\\nUnlock the transaction again\\n\"\n            + HelpExampleCli(\"lockunspent\", \"true \\\"[{\\\\\\\"txid\\\\\\\":\\\\\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\\\\\",\\\\\\\"vout\\\\\\\":1}]\\\"\") +\n            \"\\nAs a json rpc call\\n\"\n            + HelpExampleRpc(\"listlockunspent\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    std::vector<COutPoint> vOutpts;\n    pwallet->ListLockedCoins(vOutpts);\n\n    UniValue ret(UniValue::VARR);\n\n    for(COutPoint &outpt : vOutpts) {\n        UniValue o(UniValue::VOBJ);\n\n        uint256 txHash;\n        if (GetTxHash(outpt, txHash))\n            o.pushKV(\"txid\", txHash.GetHex());\n        o.pushKV(\"vout\", (int)outpt.n);\n        ret.push_back(o);\n    }\n\n    return ret;\n}\n\nUniValue settxfee(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)\n        throw std::runtime_error(\n            \"settxfee amount\\n\"\n            \"\\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. amount         (numeric or string, required) The transaction fee in \" + CURRENCY_UNIT + \"/kB\\n\"\n            \"\\nResult\\n\"\n            \"true|false        (boolean) Returns true if successful\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"settxfee\", \"0.00001\")\n            + HelpExampleRpc(\"settxfee\", \"0.00001\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    // Amount\n    CAmount nAmount = AmountFromValue(request.params[0]);\n\n    payTxFee = CFeeRate(nAmount, 1000);\n    return true;\n}\n\nUniValue rescan(const JSONRPCRequest& request)\n{\n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n             \"rescan\\n\"\n            \"\\nRun a wallet rescan against the blockchain.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nRescan for missing transactions\\n\"\n            + HelpExampleCli(\"rescan\", \"\\\"\\\"\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"rescan\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    ResetSPVStartRescanThread();\n\n    return NullUniValue;\n}\n\nUniValue getrescanprogress(const JSONRPCRequest& request)\n{\n    CWallet* const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n             \"getrescanprogress\\n\"\n            \"\\nGet progress of wallet rescan.\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nResult:\\n\"\n            \"false|number        Returns false if no scan is in progress, otherwise returns a percentage.\\n\"\n            + HelpExampleCli(\"getrescanprogress\", \"\\\"\\\"\") +\n            \"\\nAs a JSON-RPC call\\n\"\n            + HelpExampleRpc(\"getrescanprogress\", \"\")\n        );\n\n    //NB!! Intentionally don't lock here - rescan is very lock heavy\n    //We instead make sure to only use methods that don't need locks\n    if (!pwallet->IsScanning() || pwallet->IsAbortingRescan())\n        return false;\n\n    return pwallet->GetTransactionScanProgressPercent();\n}\n\nUniValue getwalletinfo(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"getwalletinfo\\n\"\n            \"Returns an object containing various wallet state info.\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"walletversion\\\": xxxxx,       (numeric) the wallet version\\n\"\n            \"  \\\"balance\\\": xxxxxxx,           (numeric) the total confirmed balance of the wallet in \" + CURRENCY_UNIT + \"\\n\"\n            \"  \\\"unconfirmed_balance\\\": xxx,   (numeric) the total unconfirmed balance of the wallet in \" + CURRENCY_UNIT + \"\\n\"\n            \"  \\\"immature_balance\\\": xxxxxx,   (numeric) the total immature balance of the wallet in \" + CURRENCY_UNIT + \"\\n\"\n            \"  \\\"txcount\\\": xxxxxxx,           (numeric) the total number of transactions in the wallet\\n\"\n            \"  \\\"keypoololdest\\\": xxxxxx,      (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\\n\"\n            //\"  \\\"keypoolsize\\\": xxxx,          (numeric) how many new keys are pre-generated\\n\"\n            \"  \\\"unlocked_until\\\": ttt,        (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\\n\"\n            \"  \\\"paytxfee\\\": x.xxxx,           (numeric) the transaction fee configuration, set in \" + CURRENCY_UNIT + \"/kB\\n\"\n            //\"  \\\"hdmasterkeyid\\\": \\\"<hash160>\\\" (string) the Hash160 of the HD master pubkey\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            + HelpExampleCli(\"getwalletinfo\", \"\")\n            + HelpExampleRpc(\"getwalletinfo\", \"\")\n        );\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    UniValue obj(UniValue::VOBJ);\n\n    //size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();\n    obj.pushKV(\"walletversion\", pwallet->GetVersion());\n    obj.pushKV(\"balance\",       ValueFromAmount(pwallet->GetBalance()));\n    obj.pushKV(\"unconfirmed_balance\", ValueFromAmount(pwallet->GetUnconfirmedBalance()));\n    obj.pushKV(\"immature_balance\",    ValueFromAmount(pwallet->GetImmatureBalance()));\n    obj.pushKV(\"txcount\",       (int)pwallet->mapWallet.size());\n    obj.pushKV(\"keypoololdest\", pwallet->GetOldestKeyPoolTime());\n    //fixme: (FUT) (ACCOUNTS)\n    /*\n    obj.pushKV(\"keypoolsize\", (int64_t)kpExternalSize);\n    CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;\n    if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {\n        obj.pushKV(\"keypoolsize_hd_internal\",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));\n    }\n    */\n    if (pwallet->IsCrypted()) {\n        obj.pushKV(\"unlocked_until\", pwallet->nRelockTime);\n    }\n    obj.pushKV(\"paytxfee\",      ValueFromAmount(payTxFee.GetFeePerK()));\n    return obj;\n}\n\nUniValue resendwallettransactions(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() != 0)\n        throw std::runtime_error(\n            \"resendwallettransactions\\n\"\n            \"Immediately re-broadcast unconfirmed wallet transactions to all peers.\\n\"\n            \"Intended only for testing; the wallet code periodically re-broadcasts\\n\"\n            \"automatically.\\n\"\n            \"Returns array of transaction ids that were re-broadcast.\\n\"\n            );\n\n    if (!g_connman)\n        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, \"Error: Peer-to-peer functionality missing or disabled\");\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n\n    std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());\n    UniValue result(UniValue::VARR);\n    for(const uint256& txid : txids)\n    {\n        result.push_back(txid.ToString());\n    }\n    return result;\n}\n\n\nUniValue listunspentforaccounts(CWallet* pWallet, std::vector<CAccount*>& doForAccounts, const UniValue* pMinDepth, const UniValue* pMaxDepth, const UniValue* pFilterAddresses, const UniValue* pIncludeUnsafe, const UniValue* pOptions)\n{\n    int nMinDepth = 1;\n    if (pMinDepth)\n    {\n        RPCTypeCheckArgument(*pMinDepth, UniValue::VNUM);\n        nMinDepth = pMinDepth->get_int();\n    }\n\n    int nMaxDepth = 9999999;\n    if (pMaxDepth)\n    {\n        RPCTypeCheckArgument(*pMaxDepth, UniValue::VNUM);\n        nMaxDepth = pMaxDepth->get_int();\n    }\n\n    std::set<CNativeAddress> setAddress;\n    if (pFilterAddresses)\n    {\n        RPCTypeCheckArgument(*pFilterAddresses, UniValue::VARR);\n        UniValue inputs = pFilterAddresses->get_array();\n        for (unsigned int idx = 0; idx < inputs.size(); idx++)\n        {\n            const UniValue& input = inputs[idx];\n            CNativeAddress address(input.get_str());\n            if (!address.IsValid())\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(\"Invalid \" GLOBAL_APPNAME \" address: \")+input.get_str());\n            if (setAddress.count(address))\n                throw JSONRPCError(RPC_INVALID_PARAMETER, std::string(\"Invalid parameter, duplicated address: \")+input.get_str());\n           setAddress.insert(address);\n        }\n    }\n\n    bool include_unsafe = true;\n    if (pIncludeUnsafe)\n    {\n        RPCTypeCheckArgument(*pIncludeUnsafe, UniValue::VBOOL);\n        include_unsafe = pIncludeUnsafe->get_bool();\n    }\n\n    CAmount nMinimumAmount = 0;\n    CAmount nMaximumAmount = MAX_MONEY;\n    CAmount nMinimumSumAmount = MAX_MONEY;\n    uint64_t nMaximumCount = 0;\n\n    if (pOptions)\n    {\n        const UniValue& options = pOptions->get_obj();\n\n        if (options.exists(\"minimumAmount\"))\n            nMinimumAmount = AmountFromValue(options[\"minimumAmount\"]);\n\n        if (options.exists(\"maximumAmount\"))\n            nMaximumAmount = AmountFromValue(options[\"maximumAmount\"]);\n\n        if (options.exists(\"minimumSumAmount\"))\n            nMinimumSumAmount = AmountFromValue(options[\"minimumSumAmount\"]);\n\n        if (options.exists(\"maximumCount\"))\n            nMaximumCount = options[\"maximumCount\"].get_int64();\n    }\n\n    UniValue results(UniValue::VARR);\n    for (auto& account : doForAccounts)\n    {\n        std::vector<COutput> vecOutputs;\n        pWallet->AvailableCoins(account, vecOutputs, !include_unsafe, NULL, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);\n        for(const COutput& out : vecOutputs)\n        {\n            CTxDestination address;\n            bool fValidAddress = ExtractDestination(out.tx->tx->vout[out.i], address);\n\n            if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))\n                continue;\n\n            UniValue entry(UniValue::VOBJ);\n            entry.pushKV(\"txid\", out.tx->GetHash().GetHex());\n            entry.pushKV(\"vout\", out.i);\n\n            if (fValidAddress)\n            {\n                entry.pushKV(\"address\", CNativeAddress(address).ToString());\n\n                entry.pushKV(\"account\", getUUIDAsString(account->getUUID()));\n                entry.pushKV(\"accountlabel\", account->getLabel());\n            }\n\n            if (out.tx->tx->vout[out.i].GetType() <= CTxOutType::ScriptLegacyOutput)\n            {\n                const CScript& scriptPubKey = out.tx->tx->vout[out.i].output.scriptPubKey;\n                if (scriptPubKey.IsPayToScriptHash())\n                {\n                    const CScriptID& hash = boost::get<CScriptID>(address);\n                    CScript redeemScript;\n                    if (pWallet->GetCScript(hash, redeemScript))\n                        entry.pushKV(\"redeemScript\", HexStr(redeemScript.begin(), redeemScript.end()));\n                }\n                entry.pushKV(\"scriptPubKey\", HexStr(scriptPubKey.begin(), scriptPubKey.end()));\n            }\n\n            entry.pushKV(\"amount\", ValueFromAmount(out.tx->tx->vout[out.i].nValue));\n            entry.pushKV(\"confirmations\", out.nDepth);\n            entry.pushKV(\"spendable\", out.fSpendable);\n            entry.pushKV(\"solvable\", out.fSolvable);\n            entry.pushKV(\"safe\", out.fSafe);\n            results.push_back(entry);\n        }\n    }\n\n    return results;\n}\n\nUniValue listunspent(const JSONRPCRequest& request)\n{\n    CWallet * const pWallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pWallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() > 5)\n        throw std::runtime_error(\n            \"listunspent ( min_conf max_conf  [\\\"addresses\\\",...] [include_unsafe] [query_options])\\n\"\n            \"\\nReturns array of unspent transaction outputs\\n\"\n            \"with between min_conf and max_conf (inclusive) confirmations.\\n\"\n            \"Optionally filter to only include txouts paid to specified addresses.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. min_conf         (numeric, optional, default=1) The minimum confirmations to filter\\n\"\n            \"2. max_conf         (numeric, optional, default=9999999) The maximum confirmations to filter\\n\"\n            \"3. \\\"addresses\\\"      (string) A json array of \" GLOBAL_APPNAME \" addresses to filter\\n\"\n            \"    [\\n\"\n            \"      \\\"address\\\"     (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"      ,...\\n\"\n            \"    ]\\n\"\n            \"4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\\n\"\n            \"                  See description of \\\"safe\\\" attribute below.\\n\"\n            \"5. query_options    (json, optional) JSON with query options\\n\"\n            \"    {\\n\"\n            \"      \\\"minimumAmount\\\"    (numeric or string, default=0) Minimum value of each UTXO in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"maximumAmount\\\"    (numeric or string, default=unlimited) Maximum value of each UTXO in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"maximumCount\\\"     (numeric or string, default=unlimited) Maximum number of UTXOs\\n\"\n            \"      \\\"minimumSumAmount\\\" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in \" + CURRENCY_UNIT + \"\\n\"\n            \"    }\\n\"\n            \"\\nResult\\n\"\n            \"[                   (array of json object)\\n\"\n            \"  {\\n\"\n            \"    \\\"txid\\\" : \\\"txid\\\",          (string) the transaction id \\n\"\n            \"    \\\"vout\\\" : n,               (numeric) the vout value\\n\"\n            \"    \\\"address\\\" : \\\"address\\\",    (string) the \" GLOBAL_APPNAME \" address\\n\"\n            \"    \\\"account\\\" : \\\"account\\\",    (string) The associated account.\"\n            \"    \\\"scriptPubKey\\\" : \\\"key\\\",   (string) the script key\\n\"\n            \"    \\\"amount\\\" : x.xxx,         (numeric) the transaction output amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"    \\\"confirmations\\\" : n,      (numeric) The number of confirmations\\n\"\n            \"    \\\"redeemScript\\\" : n        (string) The redeemScript if scriptPubKey is P2SH\\n\"\n            \"    \\\"spendable\\\" : xxx,        (bool) Whether we have the private keys to spend this output\\n\"\n            \"    \\\"solvable\\\" : xxx,         (bool) Whether we know how to spend this output, ignoring the lack of keys\\n\"\n            \"    \\\"safe\\\" : xxx              (bool) Whether this output is considered safe to spend. Unconfirmed transactions\\n\"\n            \"                              from outside keys and unconfirmed replacement transactions are considered unsafe\\n\"\n            \"                              and are not eligible for spending by fundrawtransaction and sendtoaddress.\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n\n            \"\\nExamples\\n\"\n            + HelpExampleCli(\"listunspent\", \"\")\n            + HelpExampleCli(\"listunspent\", \"6 9999999 \\\"[\\\\\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\\\\\",\\\\\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\\\\\"]\\\"\")\n            + HelpExampleRpc(\"listunspent\", \"6, 9999999 \\\"[\\\\\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\\\\\",\\\\\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\\\\\"]\\\"\")\n            + HelpExampleCli(\"listunspent\", \"6 9999999 '[]' true '{ \\\"minimumAmount\\\": 0.005 }'\")\n            + HelpExampleRpc(\"listunspent\", \"6, 9999999, [] , true, { \\\"minimumAmount\\\": 0.005 } \")\n        );\n\n    const UniValue* pMinDepth = nullptr;\n    if (request.params.size() > 0 && !request.params[0].isNull())\n        pMinDepth = &request.params[0];\n\n    const UniValue* pMaxDepth = nullptr;\n    if (request.params.size() > 1 && !request.params[1].isNull())\n        pMaxDepth = &request.params[1];\n\n    const UniValue* pFilterAddresses = nullptr;\n    if (request.params.size() > 2 && !request.params[2].isNull())\n        pFilterAddresses = &request.params[2];\n\n    const UniValue* pIncludeUnsafe = nullptr;\n    if (request.params.size() > 3 && !request.params[3].isNull())\n        pIncludeUnsafe = &request.params[3];\n\n    const UniValue* pOptions = nullptr;\n    if (request.params.size() > 4 && !request.params[4].isNull())\n        pOptions = &request.params[4];\n\n    assert(pWallet != NULL);\n    DS_LOCK2(cs_main, pWallet->cs_wallet);\n    std::vector<CAccount*> doForAccounts;\n    for (const auto& [accountUUID, account] : pWallet->mapAccounts)\n    {\n        (unused)accountUUID;\n        if (account->m_State != AccountState::Shadow)\n        {\n            doForAccounts.push_back(account);\n        }\n        //fixme: (FUT) (ACCOUNTS) (MED) - Handle shadow children\n    }\n\n    return listunspentforaccounts(pWallet, doForAccounts, pMinDepth, pMaxDepth, pFilterAddresses, pIncludeUnsafe, pOptions);\n}\n\nUniValue listunspentforaccount(const JSONRPCRequest& request)\n{\n    CWallet * const pWallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pWallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 6)\n        throw std::runtime_error(\n            \"listunspentforaccount \\\"account\\\" ( min_conf max_conf  [\\\"addresses\\\",...] [include_unsafe] [query_options])\\n\"\n            \"\\nReturns array of unspent transaction outputs\\n\"\n            \"with between min_conf and max_conf (inclusive) confirmations.\\n\"\n            \"Optionally filter to only include txouts paid to specified addresses.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. account          (string) Account UUID or label. If empty the active account is used.\\n\"\n            \"2. min_conf         (numeric, optional, default=1) The minimum confirmations to filter\\n\"\n            \"3. max_conf         (numeric, optional, default=9999999) The maximum confirmations to filter\\n\"\n            \"4. \\\"addresses\\\"      (string) A json array of \" GLOBAL_APPNAME \" addresses to filter\\n\"\n            \"    [\\n\"\n            \"      \\\"address\\\"     (string) \" GLOBAL_APPNAME \" address\\n\"\n            \"      ,...\\n\"\n            \"    ]\\n\"\n            \"5. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\\n\"\n            \"                  See description of \\\"safe\\\" attribute below.\\n\"\n            \"6. query_options    (json, optional) JSON with query options\\n\"\n            \"    {\\n\"\n            \"      \\\"minimumAmount\\\"    (numeric or string, default=0) Minimum value of each UTXO in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"maximumAmount\\\"    (numeric or string, default=unlimited) Maximum value of each UTXO in \" + CURRENCY_UNIT + \"\\n\"\n            \"      \\\"maximumCount\\\"     (numeric or string, default=unlimited) Maximum number of UTXOs\\n\"\n            \"      \\\"minimumSumAmount\\\" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in \" + CURRENCY_UNIT + \"\\n\"\n            \"    }\\n\"\n            \"\\nResult\\n\"\n            \"[                   (array of json object)\\n\"\n            \"  {\\n\"\n            \"    \\\"txid\\\" : \\\"txid\\\",          (string) the transaction id \\n\"\n            \"    \\\"vout\\\" : n,               (numeric) the vout value\\n\"\n            \"    \\\"address\\\" : \\\"address\\\",    (string) the \" GLOBAL_APPNAME \" address\\n\"\n            \"    \\\"account\\\" : \\\"account\\\",    (string) The associated account.\"\n            \"    \\\"scriptPubKey\\\" : \\\"key\\\",   (string) the script key\\n\"\n            \"    \\\"amount\\\" : x.xxx,         (numeric) the transaction output amount in \" + CURRENCY_UNIT + \"\\n\"\n            \"    \\\"confirmations\\\" : n,      (numeric) The number of confirmations\\n\"\n            \"    \\\"redeemScript\\\" : n        (string) The redeemScript if scriptPubKey is P2SH\\n\"\n            \"    \\\"spendable\\\" : xxx,        (bool) Whether we have the private keys to spend this output\\n\"\n            \"    \\\"solvable\\\" : xxx,         (bool) Whether we know how to spend this output, ignoring the lack of keys\\n\"\n            \"    \\\"safe\\\" : xxx              (bool) Whether this output is considered safe to spend. Unconfirmed transactions\\n\"\n            \"                              from outside keys and unconfirmed replacement transactions are considered unsafe\\n\"\n            \"                              and are not eligible for spending by fundrawtransaction and sendtoaddress.\\n\"\n            \"  }\\n\"\n            \"  ,...\\n\"\n            \"]\\n\"\n\n            \"\\nExamples\\n\"\n            + HelpExampleCli(\"listunspent\", \"\")\n            + HelpExampleCli(\"listunspent\", \"6 9999999 \\\"[\\\\\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\\\\\",\\\\\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\\\\\"]\\\"\")\n            + HelpExampleRpc(\"listunspent\", \"6, 9999999 \\\"[\\\\\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\\\\\",\\\\\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\\\\\"]\\\"\")\n            + HelpExampleCli(\"listunspent\", \"6 9999999 '[]' true '{ \\\"minimumAmount\\\": 0.005 }'\")\n            + HelpExampleRpc(\"listunspent\", \"6, 9999999, [] , true, { \\\"minimumAmount\\\": 0.005 } \")\n        );\n\n    CAccount* forAccount = AccountFromValue(pWallet, request.params[0], true);\n\n    const UniValue* pMinDepth = nullptr;\n    if (request.params.size() > 1 && !request.params[1].isNull())\n        pMinDepth = &request.params[1];\n\n    const UniValue* pMaxDepth = nullptr;\n    if (request.params.size() > 2 && !request.params[2].isNull())\n        pMaxDepth = &request.params[2];\n\n    const UniValue* pFilterAddresses = nullptr;\n    if (request.params.size() > 3 && !request.params[3].isNull())\n        pFilterAddresses = &request.params[3];\n\n    const UniValue* pIncludeUnsafe = nullptr;\n    if (request.params.size() > 4 && !request.params[4].isNull())\n        pIncludeUnsafe = &request.params[4];\n\n    const UniValue* pOptions = nullptr;\n    if (request.params.size() > 5 && !request.params[5].isNull())\n        pOptions = &request.params[5];\n\n    assert(pWallet != NULL);\n    DS_LOCK2(cs_main, pWallet->cs_wallet);\n    std::vector<CAccount*> doForAccounts;\n    doForAccounts.push_back(forAccount);\n\n    return listunspentforaccounts(pWallet, doForAccounts, pMinDepth, pMaxDepth, pFilterAddresses, pIncludeUnsafe, pOptions);\n}\n\nUniValue fundrawtransaction(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {\n        return NullUniValue;\n    }\n\n    if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)\n        throw std::runtime_error(\n                            \"fundrawtransaction \\\"hexstring\\\" ( options )\\n\"\n                            \"\\nAdd inputs to a transaction until it has enough in value to meet its out value.\\n\"\n                            \"This will not modify existing inputs, and will add at most one change output to the outputs.\\n\"\n                            \"No existing outputs will be modified unless \\\"subtractFeeFromOutputs\\\" is specified.\\n\"\n                            \"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\\n\"\n                            \"The inputs added will not be signed, use signrawtransaction for that.\\n\"\n                            \"Note that all existing inputs must have their previous output transaction be in the wallet.\\n\"\n                            \"Note that all inputs selected must be of standard form and P2SH scripts must be\\n\"\n                            \"in the wallet using importaddress or addmultisigaddress (to calculate fees).\\n\"\n                            \"You can see whether this is the case by checking the \\\"solvable\\\" field in the listunspent output.\\n\"\n                            \"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\\n\"\n                            \"\\nArguments:\\n\"\n                            \"1. \\\"hexstring\\\"         (string, required) The hex string of the raw transaction\\n\"\n                            \"2. \\\"account\\\"           (string, required) The account from which to fund the transaction. \\\"\\\" to use the currently active account.\\n\"\n                            \"3. options               (object, optional)\\n\"\n                            \"   {\\n\"\n                            \"     \\\"changeAddress\\\"          (string, optional, default pool address) The \" GLOBAL_APPNAME \" address to receive the change\\n\"\n                            \"     \\\"changePosition\\\"         (numeric, optional, default random) The index of the change output\\n\"\n                            \"     \\\"includeWatching\\\"        (boolean, optional, default false) Also select inputs which are watch only\\n\"\n                            \"     \\\"lockUnspents\\\"           (boolean, optional, default false) Lock selected unspent outputs\\n\"\n                            \"     \\\"reserveChangeKey\\\"       (boolean, optional, default true) Reserves the change output key from the keypool\\n\"\n                            \"     \\\"feeRate\\\"                (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (\" + CURRENCY_UNIT + \" per KB)\\n\"\n                            \"     \\\"subtractFeeFromOutputs\\\" (array, optional) A json array of integers.\\n\"\n                            \"                              The fee will be equally deducted from the amount of each specified output.\\n\"\n                            \"                              The outputs are specified by their zero-based index, before any change output is added.\\n\"\n                            \"                              Those recipients will receive less \" GLOBAL_APPNAME \" than you enter in their corresponding amount field.\\n\"\n                            \"                              If no outputs are specified here, the sender pays the fee.\\n\"\n                            \"                                  [vout_index,...]\\n\"\n                            \"     \\\"optIntoRbf\\\"             (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees\\n\"\n                            \"   }\\n\"\n                            \"                         for backward compatibility: passing in a true instead of an object will result in {\\\"includeWatching\\\":true}\\n\"\n                            \"\\nResult:\\n\"\n                            \"{\\n\"\n                            \"  \\\"hex\\\":       \\\"value\\\", (string)  The resulting raw transaction (hex-encoded string)\\n\"\n                            \"  \\\"fee\\\":       n,         (numeric) Fee in \" + CURRENCY_UNIT + \" the resulting transaction pays\\n\"\n                            \"  \\\"changepos\\\": n          (numeric) The position of the added change output, or -1\\n\"\n                            \"}\\n\"\n                            \"\\nExamples:\\n\"\n                            \"\\nCreate a transaction with no inputs\\n\"\n                            + HelpExampleCli(\"createrawtransaction\", \"\\\"[]\\\" \\\"{\\\\\\\"myaddress\\\\\\\":0.01}\\\"\") +\n                            \"\\nAdd sufficient unsigned inputs to meet the output value\\n\"\n                            + HelpExampleCli(\"fundrawtransaction\", \"\\\"rawtransactionhex\\\"\") +\n                            \"\\nSign the transaction\\n\"\n                            + HelpExampleCli(\"signrawtransaction\", \"\\\"fundedtransactionhex\\\"\") +\n                            \"\\nSend the transaction\\n\"\n                            + HelpExampleCli(\"sendrawtransaction\", \"\\\"signedtransactionhex\\\"\")\n                            );\n\n    RPCTypeCheck(request.params, {UniValue::VSTR});\n\n    CCoinControl coinControl;\n    coinControl.destChange = CNoDestination();\n    int changePosition = -1;\n    coinControl.fAllowWatchOnly = false;  // include watching\n    bool lockUnspents = false;\n    bool reserveChangeKey = true;\n    coinControl.nFeeRate = CFeeRate(0);\n    coinControl.fOverrideFeeRate = false;\n    UniValue subtractFeeFromOutputs;\n    std::set<int> setSubtractFeeFromOutputs;\n\n    if (request.params.size() > 2) {\n      if (request.params[2].type() == UniValue::VBOOL) {\n        // backward compatibility bool only fallback\n        coinControl.fAllowWatchOnly = request.params[2].get_bool();\n      }\n      else {\n        RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR, UniValue::VOBJ});\n\n        UniValue options = request.params[2];\n\n        RPCTypeCheckObj(options,\n            {\n                {\"changeAddress\", UniValueType(UniValue::VSTR)},\n                {\"changePosition\", UniValueType(UniValue::VNUM)},\n                {\"includeWatching\", UniValueType(UniValue::VBOOL)},\n                {\"lockUnspents\", UniValueType(UniValue::VBOOL)},\n                {\"reserveChangeKey\", UniValueType(UniValue::VBOOL)},\n                {\"feeRate\", UniValueType()}, // will be checked below\n                {\"subtractFeeFromOutputs\", UniValueType(UniValue::VARR)},\n                {\"optIntoRbf\", UniValueType(UniValue::VBOOL)},\n            },\n            true, true);\n\n        if (options.exists(\"changeAddress\")) {\n            CNativeAddress address(options[\"changeAddress\"].get_str());\n\n            if (!address.IsValid())\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, \"changeAddress must be a valid \" GLOBAL_APPNAME \" address\");\n\n            coinControl.destChange = address.Get();\n        }\n\n        if (options.exists(\"changePosition\"))\n            changePosition = options[\"changePosition\"].get_int();\n\n        if (options.exists(\"includeWatching\"))\n            coinControl.fAllowWatchOnly = options[\"includeWatching\"].get_bool();\n\n        if (options.exists(\"lockUnspents\"))\n            lockUnspents = options[\"lockUnspents\"].get_bool();\n\n        if (options.exists(\"reserveChangeKey\"))\n            reserveChangeKey = options[\"reserveChangeKey\"].get_bool();\n\n        if (options.exists(\"feeRate\"))\n        {\n            coinControl.nFeeRate = CFeeRate(AmountFromValue(options[\"feeRate\"]));\n            coinControl.fOverrideFeeRate = true;\n        }\n\n        if (options.exists(\"subtractFeeFromOutputs\"))\n            subtractFeeFromOutputs = options[\"subtractFeeFromOutputs\"].get_array();\n\n        if (options.exists(\"optIntoRbf\")) {\n            coinControl.signalRbf = options[\"optIntoRbf\"].get_bool();\n        }\n      }\n    }\n\n    // parse hex string from parameter\n    CMutableTransaction tx(CURRENT_TX_VERSION_POW2);\n    if (!DecodeHexTx(tx, request.params[0].get_str(), true))\n        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, \"TX decode failed\");\n\n    if (tx.vout.size() == 0)\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"TX must have at least one output\");\n\n    if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > tx.vout.size()))\n        throw JSONRPCError(RPC_INVALID_PARAMETER, \"changePosition out of bounds\");\n\n    for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {\n        int pos = subtractFeeFromOutputs[idx].get_int();\n        if (setSubtractFeeFromOutputs.count(pos))\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid parameter, duplicated position: %d\", pos));\n        if (pos < 0)\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid parameter, negative position: %d\", pos));\n        if (pos >= int(tx.vout.size()))\n            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid parameter, position too large: %d\", pos));\n        setSubtractFeeFromOutputs.insert(pos);\n    }\n\n    CAmount nFeeOut;\n    std::string strFailReason;\n\n    CAccount* fundingAccount = AccountFromValue(pwallet, request.params[1], true);\n\n    CReserveKeyOrScript reservekey(pwallet, fundingAccount, KEYCHAIN_CHANGE);\n    if (!pwallet->FundTransaction(fundingAccount, tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl, reservekey)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);\n    }\n\n    if (reserveChangeKey)\n        reservekey.KeepKey();\n\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"hex\", EncodeHexTx(tx));\n    result.pushKV(\"changepos\", changePosition);\n    result.pushKV(\"fee\", ValueFromAmount(nFeeOut));\n\n    return result;\n}\n\nUniValue bumpfee(const JSONRPCRequest& request)\n{\n    CWallet * const pwallet = GetWalletForJSONRPCRequest(request);\n\n    if (!EnsureWalletIsAvailable(pwallet, request.fHelp))\n        return NullUniValue;\n\n    if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {\n        throw std::runtime_error(\n            \"bumpfee \\\"txid\\\" ( options ) \\n\"\n            \"\\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\\n\"\n            \"An opt-in RBF transaction with the given txid must be in the wallet.\\n\"\n            \"The command will pay the additional fee by decreasing (or perhaps removing) its change output.\\n\"\n            \"If the change output is not big enough to cover the increased fee, the command will currently fail\\n\"\n            \"instead of adding new inputs to compensate. (A future implementation could improve this.)\\n\"\n            \"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\\n\"\n            \"By default, the new fee will be calculated automatically using estimatefee.\\n\"\n            \"The user can specify a confirmation target for estimatefee.\\n\"\n            \"Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\\n\"\n            \"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\\n\"\n            \"returned by getnetworkinfo) to enter the node's mempool.\\n\"\n            \"\\nArguments:\\n\"\n            \"1. txid                  (string, required) The txid to be bumped\\n\"\n            \"2. options               (object, optional)\\n\"\n            \"   {\\n\"\n            \"     \\\"confTarget\\\"        (numeric, optional) Confirmation target (in blocks)\\n\"\n            \"     \\\"totalFee\\\"          (numeric, optional) Total fee (NOT feerate) to pay, in satoshis.\\n\"\n            \"                         In rare cases, the actual fee paid might be slightly higher than the specified\\n\"\n            \"                         totalFee if the tx change output has to be removed because it is too close to\\n\"\n            \"                         the dust threshold.\\n\"\n            \"     \\\"replaceable\\\"       (boolean, optional, default true) Whether the new transaction should still be\\n\"\n            \"                         marked bip-125 replaceable. If true, the sequence numbers in the transaction will\\n\"\n            \"                         be left unchanged from the original. If false, any input sequence numbers in the\\n\"\n            \"                         original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\\n\"\n            \"                         so the new transaction will not be explicitly bip-125 replaceable (though it may\\n\"\n            \"                         still be replacable in practice, for example if it has unconfirmed ancestors which\\n\"\n            \"                         are replaceable).\\n\"\n            \"   }\\n\"\n            \"\\nResult:\\n\"\n            \"{\\n\"\n            \"  \\\"txid\\\":    \\\"value\\\",   (string)  The id of the new transaction\\n\"\n            \"  \\\"origfee\\\":  n,         (numeric) Fee of the replaced transaction\\n\"\n            \"  \\\"fee\\\":      n,         (numeric) Fee of the new transaction\\n\"\n            \"  \\\"errors\\\":  [ str... ] (json array of strings) Errors encountered during processing (may be empty)\\n\"\n            \"}\\n\"\n            \"\\nExamples:\\n\"\n            \"\\nBump the fee, get the new transaction\\'s txid\\n\" +\n            HelpExampleCli(\"bumpfee\", \"<txid>\"));\n    }\n\n    RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});\n    uint256 hash;\n    hash.SetHex(request.params[0].get_str());\n\n    // optional parameters\n    bool ignoreGlobalPayTxFee = false;\n    int newConfirmTarget = nTxConfirmTarget;\n    CAmount totalFee = 0;\n    bool replaceable = true;\n    if (request.params.size() > 1) {\n        UniValue options = request.params[1];\n        RPCTypeCheckObj(options,\n            {\n                {\"confTarget\", UniValueType(UniValue::VNUM)},\n                {\"totalFee\", UniValueType(UniValue::VNUM)},\n                {\"replaceable\", UniValueType(UniValue::VBOOL)},\n            },\n            true, true);\n\n        if (options.exists(\"confTarget\") && options.exists(\"totalFee\")) {\n            throw JSONRPCError(RPC_INVALID_PARAMETER, \"confTarget and totalFee options should not both be set. Please provide either a confirmation target for fee estimation or an explicit total fee for the transaction.\");\n        } else if (options.exists(\"confTarget\")) {\n            // If the user has explicitly set a confTarget in this rpc call,\n            // then override the default logic that uses the global payTxFee\n            // instead of the confirmation target.\n            ignoreGlobalPayTxFee = true;\n            newConfirmTarget = options[\"confTarget\"].get_int();\n            if (newConfirmTarget <= 0) { // upper-bound will be checked by estimatefee/smartfee\n                throw JSONRPCError(RPC_INVALID_PARAMETER, \"Invalid confTarget (cannot be <= 0)\");\n            }\n        } else if (options.exists(\"totalFee\")) {\n            totalFee = options[\"totalFee\"].get_int64();\n            if (totalFee <= 0) {\n                throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf(\"Invalid totalFee %s (must be greater than 0)\", FormatMoney(totalFee)));\n            }\n        }\n\n        if (options.exists(\"replaceable\")) {\n            replaceable = options[\"replaceable\"].get_bool();\n        }\n    }\n\n    DS_LOCK2(cs_main, pwallet->cs_wallet);\n    EnsureWalletIsUnlocked(pwallet);\n\n    CFeeBumper feeBump(pwallet, hash, newConfirmTarget, ignoreGlobalPayTxFee, totalFee, replaceable);\n    BumpFeeResult res = feeBump.getResult();\n    if (res != BumpFeeResult::OK)\n    {\n        switch(res) {\n            case BumpFeeResult::INVALID_ADDRESS_OR_KEY:\n                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, feeBump.getErrors()[0]);\n                break;\n            case BumpFeeResult::INVALID_REQUEST:\n                throw JSONRPCError(RPC_INVALID_REQUEST, feeBump.getErrors()[0]);\n                break;\n            case BumpFeeResult::INVALID_PARAMETER:\n                throw JSONRPCError(RPC_INVALID_PARAMETER, feeBump.getErrors()[0]);\n                break;\n            case BumpFeeResult::WALLET_ERROR:\n                throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);\n                break;\n            default:\n                throw JSONRPCError(RPC_MISC_ERROR, feeBump.getErrors()[0]);\n                break;\n        }\n    }\n\n    // sign bumped transaction\n    if (!feeBump.signTransaction(pwallet)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, \"Can't sign transaction.\");\n    }\n    // commit the bumped transaction\n    if(!feeBump.commit(pwallet)) {\n        throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);\n    }\n    UniValue result(UniValue::VOBJ);\n    result.pushKV(\"txid\", feeBump.getBumpedTxId().GetHex());\n    result.pushKV(\"origfee\", ValueFromAmount(feeBump.getOldFee()));\n    result.pushKV(\"fee\", ValueFromAmount(feeBump.getNewFee()));\n    UniValue errors(UniValue::VARR);\n    for (const std::string& err: feeBump.getErrors())\n        errors.push_back(err);\n    result.pushKV(\"errors\", errors);\n\n    return result;\n}\n\nextern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp\nextern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp\nextern UniValue importprivkey(const JSONRPCRequest& request);\nextern UniValue importaddress(const JSONRPCRequest& request);\nextern UniValue importpubkey(const JSONRPCRequest& request);\nextern UniValue dumpwallet(const JSONRPCRequest& request);\nextern UniValue checkwalletagainstutxo(const JSONRPCRequest& request);\nextern UniValue repairwalletfromutxo(const JSONRPCRequest& request);\nextern UniValue removeallorphans(const JSONRPCRequest& request);\nextern UniValue importwallet(const JSONRPCRequest& request);\nextern UniValue importprunedfunds(const JSONRPCRequest& request);\nextern UniValue removeprunedfunds(const JSONRPCRequest& request);\nextern UniValue importmulti(const JSONRPCRequest& request);\n\nstatic const CRPCCommand commands[] =\n{ //  category              name                        actor (function)           okSafeMode\n    //  --------------------- ------------------------    -----------------------    ----------\n    { \"rawtransactions\",    \"fundrawtransaction\",       &fundrawtransaction,       false,  {\"hexstring\", \"account\", \"options\"} },\n    { \"hidden\",             \"resendwallettransactions\", &resendwallettransactions, true,   {} },\n    { \"wallet\",             \"abandontransaction\",       &abandontransaction,       false,  {\"txid\"} },\n    { \"wallet\",             \"abortrescan\",              &abortrescan,              false,  {} },\n    { \"wallet\",             \"addmultisigaddress\",       &addmultisigaddress,       true,   {\"num_required\",\"keys\",\"account\"} },\n    { \"wallet\",             \"backupwallet\",             &backupwallet,             true,   {\"destination\"} },\n    //{ \"wallet\",             \"bumpfee\",                  &bumpfee,                true,   {\"txid\", \"options\"} },\n    { \"wallet\",             \"dumpprivkey\",              &dumpprivkey,              true,   {\"address\"}  },\n    { \"wallet\",             \"dumpwallet\",               &dumpwallet,               true,   {\"filename\", \"HDConsent\"} },\n    { \"wallet\",             \"checkwalletagainstutxo\",   &checkwalletagainstutxo,   true,   {} },\n    { \"wallet\",             \"repairwalletfromutxo\",     &repairwalletfromutxo,     true,   {} },\n    { \"wallet\",             \"removeallorphans\",         &removeallorphans,         true,   {} },\n    { \"wallet\",             \"encryptwallet\",            &encryptwallet,            true,   {\"passphrase\"} },\n    { \"wallet\",             \"getaccount\",               &getaccount,               true,   {\"address\"} },\n    { \"wallet\",             \"getaddressesbyaccount\",    &getaddressesbyaccount,    true,   {\"account\"} },\n    { \"wallet\",             \"getbalance\",               &getbalance,               false,  {\"account\",\"min_conf\",\"include_watchonly\"} },\n    { \"wallet\",             \"getnewaddress\",            &getnewaddress,            true,   {\"account\"} },\n    { \"wallet\",             \"getaccountaddress\",        &getaccountaddress,        true,   {\"account\"} },\n    { \"wallet\",             \"getrawchangeaddress\",      &getrawchangeaddress,      true,   {} },\n    { \"wallet\",             \"getreceivedbyaddress\",     &getreceivedbyaddress,     false,  {\"address\",\"min_conf\"} },\n    { \"wallet\",             \"getrescanprogress\",        &getrescanprogress,        false,  {} },\n    { \"wallet\",             \"gettransaction\",           &gettransaction,           false,  {\"txid\",\"include_watchonly\"} },\n    { \"wallet\",             \"getunconfirmedbalance\",    &getunconfirmedbalance,    false,  {} },\n    { \"wallet\",             \"getimmaturebalance\",       &getimmaturebalance,       false,  {} },\n    { \"wallet\",             \"getlockedbalance\",         &getlockedbalance,         false,  {} },\n    { \"wallet\",             \"getwalletinfo\",            &getwalletinfo,            false,  {} },\n    { \"wallet\",             \"importmulti\",              &importmulti,              true,   {\"account\",\"requests\",\"options\"} },\n    { \"wallet\",             \"importprivkey\",            &importprivkey,            true,   {\"muntprivkey\", \"account\", \"label\",\"rescan\"} },\n    { \"wallet\",             \"importwallet\",             &importwallet,             true,   {\"filename\"} },\n    { \"wallet\",             \"importaddress\",            &importaddress,            true,   {\"address\",\"label\",\"rescan\",\"p2sh\"} },\n    { \"wallet\",             \"importprunedfunds\",        &importprunedfunds,        true,   {\"rawtransaction\",\"txoutproof\"} },\n    { \"wallet\",             \"importpubkey\",             &importpubkey,             true,   {\"pubkey\",\"label\",\"rescan\"} },\n    { \"wallet\",             \"keypoolrefill\",            &keypoolrefill,            true,   {\"new_size\"} },\n    { \"wallet\",             \"listaddressgroupings\",     &listaddressgroupings,     false,  {} },\n    { \"wallet\",             \"listlockunspent\",          &listlockunspent,          false,  {} },\n    { \"wallet\",             \"listreceivedbyaccount\",    &listreceivedbyaccount,    false,  {\"minconf\",\"include_empty\",\"include_watchonly\"} },\n    { \"wallet\",             \"listreceivedbyaddress\",    &listreceivedbyaddress,    false,  {\"min_conf\",\"include_empty\",\"include_watchonly\"} },\n    { \"wallet\",             \"listsinceblock\",           &listsinceblock,           false,  {\"blockhash\",\"target_confirmations\",\"include_watchonly\"} },\n    { \"wallet\",             \"listtransactions\",         &listtransactions,         false,  {\"account\",\"count\",\"skip\",\"include_watchonly\"} },\n    { \"wallet\",             \"listunspent\",              &listunspent,              false,  {\"min_conf\",\"max_conf\",\"addresses\",\"include_unsafe\",\"query_options\"} },\n    { \"wallet\",             \"listunspentforaccount\",    &listunspentforaccount,    false,  {\"account\",\"min_conf\",\"max_conf\",\"addresses\",\"include_unsafe\",\"query_options\"} },\n    { \"wallet\",             \"lockunspent\",              &lockunspent,              true,   {\"unlock\",\"transactions\"} },\n    { \"wallet\",             \"move\",                     &movecmd,                  false,  {\"from_account\",\"to_account\",\"amount\",\"min_conf\",\"comment\"} },\n    { \"wallet\",             \"defrag\",                   &defrag,                   false,  {\"from_account\",\"to_address\",\"min_input_amount\",\"max_input_amount\",\"max_input_quantity\", \"min_conf\"} },\n    { \"wallet\",             \"rescan\",                   &rescan,                   false,  {} },\n    { \"wallet\",             \"sendfrom\",                 &sendfrom,                 false,  {\"from_account\",\"to_address\",\"amount\",\"min_conf\",\"comment\",\"comment_to\"} },\n    { \"wallet\",             \"sendmany\",                 &sendmany,                 false,  {\"from_account\",\"amounts\",\"min_conf\",\"comment\",\"subtract_fee_from\"} },\n    { \"wallet\",             \"sendtoaddress\",            &sendtoaddress,            false,  {\"address\",\"amount\",\"comment\",\"comment_to\",\"subtract_fee_from_amount\"} },\n    { \"wallet\",             \"sendtoaddressfromaccount\", &sendtoaddressfromaccount, false,  {\"from_account\", \"address\", \"amount\", \"comment\", \"comment-to\", \"subtract_fee_from_amount\"} },\n    { \"wallet\",             \"settxfee\",                 &settxfee,                 true,   {\"amount\"} },\n    { \"wallet\",             \"signmessage\",              &signmessage,              true,   {\"address\",\"message\"} },\n    { \"wallet\",             \"walletlock\",               &walletlock,               true,   {} },\n    { \"wallet\",             \"walletpassphrasechange\",   &walletpassphrasechange,   true,   {\"oldpassphrase\",\"newpassphrase\"} },\n    { \"wallet\",             \"walletpassphrase\",         &walletpassphrase,         true,   {\"passphrase\",\"timeout\"} },\n    { \"wallet\",             \"removeprunedfunds\",        &removeprunedfunds,        true,   {\"txid\"} },\n};\n\nvoid RegisterWalletRPCCommands(CRPCTable &t)\n{\n    if (GetBoolArg(\"-disablewallet\", false))\n        return;\n\n    for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)\n        t.appendCommand(commands[vcidx].name, &commands[vcidx]);\n}\n"
  },
  {
    "path": "src/wallet/rpcwallet.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_RPCWALLET_H\n#define WALLET_RPCWALLET_H\n\nclass CRPCTable;\nclass CAccount;\nclass JSONRPCRequest;\nclass UniValue;\n\nCAccount* AccountFromValue(CWallet* pwallet, const UniValue& value, bool useDefaultIfEmpty);\nvoid RegisterWalletRPCCommands(CRPCTable &t);\n\n/**\n * Figures out what wallet, if any, to use for a JSONRPCRequest.\n *\n * @param[in] request JSONRPCRequest that wishes to access a wallet\n * @return NULL if no wallet should be used, or a pointer to the CWallet\n */\nCWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest&);\n\nstd::string HelpRequiringPassphrase(CWallet *);\nvoid EnsureWalletIsUnlocked(CWallet *);\nbool EnsureWalletIsAvailable(CWallet *, bool avoidException);\n\n#endif\n"
  },
  {
    "path": "src/wallet/spvscanner.cpp",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"spvscanner.h\"\n#include \"../net_processing.h\"\n#include \"timedata.h\"\n#include \"../validation/validation.h\"\n#include \"wallet.h\"\n#include \"checkpoints.h\"\n\n#include <algorithm>\n\n#include <boost/bind/bind.hpp>\nusing namespace boost::placeholders;\n\n// Maximum number of requests pending. This number should be high enough so that\n// the requests can be reasonably distributed over our peers.\nconst int MAX_PENDING_REQUESTS = 512;\n\n// Duration (seconds) of longest fork that can be handled\nconst int64_t MAX_FORK_DURATION = 1 * 12 * 3600;\n\n// Persisting wallet db updates are limited as they are very expensive\n// and updating at every processed block would give very poor performance.\n// Therefore the state is only written to the db when a minimum time interval has passed,\n// or a certain of number of blocks have been processed (whichever comes first).\n// Note that due to this some blocks might be re-processed in case of abnormal termination,\n// this is fine.\n\n// Interval in seconds for writing the scan progress to the wallet db\nconst int64_t PERSIST_INTERVAL_SEC = 5;\n\n// Blocks count after which scan processing state is written to the db.\nconst int PERSIST_BLOCK_COUNT = 500;\n\n// limit UI update notifications (except when catched up)\nconst int UI_UPDATE_LIMIT = 50;\n\nstd::atomic<int> CSPVScanner::lastProcessedBlockHeight = 0;\nstd::atomic<float> CSPVScanner::lastProgressReported = -1.0f;\n\nCSPVScanner::CSPVScanner(CWallet& _wallet) :\n    wallet(_wallet),\n    numConnections(0)\n{\n    LOCK(cs_main);\n    Init();\n}\n\nCSPVScanner::~CSPVScanner()\n{\n    uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(&CSPVScanner::OnNumConnectionsChanged, this, _1));\n}\n\nvoid CSPVScanner::Init()\n{\n    AssertLockHeld(cs_main);\n\n    blockLastProcessed = nullptr;\n    lastProgressReported = -1.0f;\n    lastPersistedBlockTime = 0;\n    lastPersistTime = 0;\n    startHeight = -1;\n    nRequestsPending = 0;\n    lastProcessedBlockHeight = 0;\n\n    // init scan starting time to birth of first key\n    startTime =  wallet.nTimeFirstKey;\n\n    // forward scan starting time to last block processed if available\n    CWalletDB walletdb(*wallet.dbw);\n    CBlockLocator locator;\n    if (walletdb.ReadLastSPVBlockProcessed(locator, lastPersistedBlockTime))\n        startTime = lastPersistedBlockTime;\n\n    // rewind scan starting time by maximum handled fork duration\n    startTime = std::max(Params().GenesisBlock().GetBlockTime(), startTime - MAX_FORK_DURATION);\n}\n\nvoid CSPVScanner::ResetScan()\n{\n    LOCK2(cs_main, wallet.cs_wallet);\n\n    StopPartialHeaders(std::bind(&CSPVScanner::HeaderTipChanged, this, std::placeholders::_1));\n    wallet.NotifyKeyPoolToppedUp.disconnect(boost::bind(&CSPVScanner::onKeyPoolToppedUp, this));\n    CancelAllPriorityDownloads();\n\n    // erase persisted spv progress\n    CWalletDB walletdb(*wallet.dbw);\n    walletdb.EraseLastSPVBlockProcessed();\n\n    Init();\n\n    ResetUnifiedProgressNotification();\n\n}\n\nbool CSPVScanner::StartScan()\n{\n    LOCK(cs_main);\n    if (StartPartialHeaders(startTime, std::bind(&CSPVScanner::HeaderTipChanged, this, std::placeholders::_1)))\n    {\n        uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(&CSPVScanner::OnNumConnectionsChanged, this, _1));\n        HeaderTipChanged(partialChain.Tip());\n        NotifyUnifiedProgress();\n        {\n            LOCK(wallet.cs_wallet);\n            wallet.NotifyKeyPoolToppedUp.connect(boost::bind(&CSPVScanner::onKeyPoolToppedUp, this));\n        }\n        return true;\n    }\n    else\n        return false;\n}\n\nconst CBlockIndex* CSPVScanner::LastBlockProcessed() const\n{\n    LOCK(cs_main);\n    return blockLastProcessed;\n}\n\nvoid CSPVScanner::onKeyPoolToppedUp()\n{\n    static std::atomic_flag computingRanges;\n\n    const CBlockIndex* pIndexLast = LastBlockProcessed();\n    if (pIndexLast == nullptr)\n        return;\n\n    if (computingRanges.test_and_set())\n    {\n        std::thread([&, pIndexLast]() {\n            uint64_t nBirthBLockHard = pIndexLast->nHeight;\n            uint64_t nDummyBlockSoft = Checkpoints::LastCheckPointHeight();\n            ComputeNewFilterRanges(nBirthBLockHard, nDummyBlockSoft);\n            computingRanges.clear();\n        }).detach();\n    }\n}\n\n// If we are before the first range or not in one of the ranges then we can skip fetching the data.\n// If we are in one of the ranges or if we are after the last checkpoint then we must fetch the data.\n// If we have no filter ranges then we must fetch the data.\nbool CSPVScanner::CanSkipBlockFetch(const CBlockIndex* pIndex, uint64_t lastCheckPointHeight)\n{\n    AssertLockHeld(partialChain.cs_blockFilterRanges);\n    if ((uint64_t)pIndex->nHeight > lastCheckPointHeight)\n        return false;\n\n    if (partialChain.blockFilterRanges.empty())\n        return false;\n\n    for (const auto& [rangeStart, rangeEnd] : partialChain.blockFilterRanges)\n    {\n        if ((uint64_t)pIndex->nHeight >= rangeStart)\n        {\n            if ((uint64_t)pIndex->nHeight < rangeEnd)\n                return false;\n        }\n        else\n        {\n            // Short circuit optimisation: Ranges are ordered so if we aren't > this first one then we won't be > than any of the subsequent ones.\n            break;\n        }\n    }\n    return true;\n}\n\nvoid CSPVScanner::RequestBlocks()\n{\n    LOCK2(cs_main, wallet.cs_wallet);\n\n    // put blockLastProcessed and/or blockRequestTip back on chain if forked\n    while (!partialChain.Contains(blockRequestTip)) {\n        if (blockRequestTip->nHeight > blockLastProcessed->nHeight) {\n            CancelPriorityDownload(blockRequestTip, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));\n            blockRequestTip = blockRequestTip->pprev;\n        }\n        else { // so here blockRequestTip == blockLastProcessed\n            std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();\n            if (ReadBlockFromDisk(*pblock, blockLastProcessed, Params())) {\n                wallet.BlockDisconnected(pblock);\n            }\n            else {\n                // This block must be on disk, it was processed before.\n                // So pruning has to keep at least as many blocks back as the longest fork we are willing to handle.\n                //\n                // Reset the chain as we are clearly in a bad state\n                //fixme: (HIGH) Collect analytics on this.\n                LogPrintf(\"Error: SPV scanner encountered invalid state and resetting chain sync [Could not find disconnected block on disk.]\");\n                ResetScan();\n                return;\n            }\n            UpdateLastProcessed(blockLastProcessed->pprev);\n            blockRequestTip = blockLastProcessed;\n        }\n    }\n\n    // skip blocks that are before startTime\n    CBlockIndex* skip = blockLastProcessed;\n    while (skip->GetBlockTime() < startTime && partialChain.Height() > skip->nHeight)\n    {\n        skip = partialChain.Next(skip);\n    }\n    if (skip != blockLastProcessed)\n    {\n        LogPrint(BCLog::WALLET, \"Skipping %d old blocks for SPV scan, up to height %d\\n\", skip->nHeight - blockLastProcessed->nHeight, skip->nHeight);\n        UpdateLastProcessed(skip);\n        if (blockLastProcessed->nHeight > blockRequestTip->nHeight)\n        {\n            blockRequestTip = blockLastProcessed;\n        }\n    }\n\n    std::vector<const CBlockIndex*> blocksToRequest;\n\n    // add requests for as long as nMaxPendingRequests is not reached and there are still higher blocks in headerChain\n    // In the special case of 'skipped' blocks we allow a higher restriction - as they don't represent real network processing so won't starve peers\n    int nNumSkipped=0;\n    {\n        LOCK(partialChain.cs_blockFilterRanges);\n        while (nRequestsPending < MAX_PENDING_REQUESTS && partialChain.Height() > blockRequestTip->nHeight)\n        {\n            blockRequestTip = partialChain.Next(blockRequestTip);\n            if (CanSkipBlockFetch(blockRequestTip, Checkpoints::LastCheckPointHeight()))\n            {\n                ++nNumSkipped;\n                LogPrint(BCLog::WALLET, \"Skip block fetch [%d]\\n\", blockRequestTip->nHeight);\n            }\n            else\n            {\n                LogPrint(BCLog::WALLET, \"Unable to skip block fetch [%d]\\n\", blockRequestTip->nHeight);\n                blocksToRequest.push_back(blockRequestTip);\n                nRequestsPending++;\n            }\n        }\n    }\n\n    if (!blocksToRequest.empty()) {\n        LogPrint(BCLog::WALLET, \"Requesting %d blocks for SPV, up to height %d\\n\", blocksToRequest.size(), blockRequestTip->nHeight);\n        AddPriorityDownload(blocksToRequest, std::bind(&CSPVScanner::ProcessPriorityRequest, this, std::placeholders::_1, std::placeholders::_2));\n    }\n}\n\nvoid CSPVScanner::ProcessPriorityRequest(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex)\n{\n    LOCK2(cs_main, wallet.cs_wallet);\n\n    nRequestsPending--;\n\n    // if chainActive is up-to-date no SPV blocks need to be requested, we can update SPV to the activeChain\n    if (chainActive.Tip() == partialChain.Tip()) {\n        LogPrint(BCLog::WALLET, \"chainActive is up-to-date, skipping SPV processing block %d\\n\", pindex->nHeight);\n        if (blockLastProcessed != partialChain.Tip()) {\n            UpdateLastProcessed(chainActive.Tip());\n            blockRequestTip = blockLastProcessed;\n        }\n    }\n\n    // The block we're getting might have skipped some because they were filtered out and so never requested.\n    // Blocks are guaranteed to be delivered in requested order and therefore we can safely \"fastforward\" the blockLastProcessed\n    // knowing that the blocks in between have never been requested.\n    if (blockLastProcessed->nHeight < Checkpoints::LastCheckPointHeight() && pindex->pprev != blockLastProcessed) {\n        CBlockIndex* pSkip = blockLastProcessed;\n        while (pindex->pprev != pSkip && pSkip != nullptr) {\n            pSkip = partialChain.Next(pSkip);\n        }\n\n        assert(pSkip != nullptr); // The block has a pprev that is not in partialChain, impossible that it was requested\n\n        UpdateLastProcessed(pSkip);\n    }\n\n    if (pindex->pprev == blockLastProcessed) {\n        LogPrint(BCLog::WALLET, \"SPV processing block %d\\n\", pindex->nHeight);\n\n\n        std::vector<CTransactionRef> vtxConflicted; // dummy for now\n        wallet.BlockConnected(block, pindex, vtxConflicted);\n\n        UpdateLastProcessed((CBlockIndex*)pindex);\n\n        RequestBlocks();\n\n        if (partialChain.Height() == pindex->nHeight || pindex->nHeight % UI_UPDATE_LIMIT == 0)\n            uiInterface.NotifySPVProgress(startHeight, pindex->nHeight, partialChain.Height());\n\n        NotifyUnifiedProgress();\n\n        blocksSincePersist++;\n\n        ExpireMempoolForPartialSync(block, blockLastProcessed);\n    }\n}\n\nvoid CSPVScanner::HeaderTipChanged(const CBlockIndex* pTip)\n{\n    LOCK(cs_main);\n    if (pTip)\n    {\n        // initialization on the first header tip notification\n        if (blockLastProcessed == nullptr)\n        {\n            if (partialChain.Height() >= partialChain.HeightOffset()\n                    && partialChain[partialChain.HeightOffset()]->GetBlockTime() <= startTime)\n            {\n                // use start of partial chain to init blockLastProcessed\n                // forks are handled when requesting blocks which will also fast-forward to startTime\n                // should the headerChain be very early\n                blockLastProcessed = partialChain[partialChain.HeightOffset()];\n                blockRequestTip = blockLastProcessed;\n                startHeight = blockLastProcessed->nHeight;\n\n                LogPrint(BCLog::WALLET, \"SPV init using %s (height = %d) as last processed block\\n\",\n                          blockLastProcessed->GetBlockHashPoW2().ToString(), blockLastProcessed->nHeight);\n            }\n            else\n            {\n                // headerChain not usable, it does not start early enough or has no data.\n                // This should not happen, as StartPartialHeaders was explicitly given the startTime\n                // so if this occurs it's a bug.\n                throw std::runtime_error(\"partialChain not usable, starting late or too little data\");\n            }\n        }\n\n        RequestBlocks();\n\n        NotifyUnifiedProgress();\n    }\n    else // pTip == nullptr => partial sync stopped\n    {\n        CancelAllPriorityDownloads();\n        Persist();\n    }\n}\n\nvoid CSPVScanner::OnNumConnectionsChanged(int newNumConnections)\n{\n    LOCK(cs_main);\n\n    numConnections = newNumConnections;\n    NotifyUnifiedProgress();\n}\n\nvoid CSPVScanner::ResetUnifiedProgressNotification()\n{\n    LOCK(cs_main);\n\n    lastProgressReported = -1.0f;\n    startHeight = -1;\n    if (blockLastProcessed)\n        startHeight = blockLastProcessed->nHeight;\n    NotifyUnifiedProgress();\n}\n\nvoid CSPVScanner::NotifyUnifiedProgress()\n{\n    AssertLockHeld(cs_main);\n\n    const float CONNECTION_WEIGHT = 0.05f;\n    const float MIN_REPORTING_DELTA = 0.005f;\n\n    float newProgress = 0.0f;\n\n    // Only calculate progress if there are connections. Without connections progress is reported as zero\n    // which is the only case where progress can decrease during a session (ie. if all connections are lost)\n    if (numConnections > 0) {\n        newProgress += CONNECTION_WEIGHT;\n\n        int probableHeight = GetProbableHeight();\n\n        if (probableHeight > 0 && startHeight >= 0 &&\n            probableHeight != startHeight &&\n                blockLastProcessed != nullptr && blockLastProcessed->nHeight > 0)\n        {\n            float pgs = (blockLastProcessed->nHeight - startHeight)/float(probableHeight - startHeight);\n            newProgress += (1.0f - CONNECTION_WEIGHT) * pgs;\n        }\n        else if (probableHeight == startHeight)\n            newProgress = 1.0f;\n\n        // Limit progress notification to reduce overhead, only notify if delta since previous ntf is > MIN_REPORTING_DELTA\n        if (lastProgressReported >= 0.0f && newProgress < 1.0f && fabs(newProgress - lastProgressReported) < MIN_REPORTING_DELTA)\n                return;\n        // else lastProgressReported < 0 => progress was reset/initialized so always notify\n    }\n\n    if (newProgress != lastProgressReported) {\n        uiInterface.NotifyUnifiedProgress(newProgress);\n        lastProgressReported = newProgress;\n    }\n}\n\nvoid CSPVScanner::UpdateLastProcessed(CBlockIndex* pindex)\n{\n    AssertLockHeld(cs_main);\n\n    blockLastProcessed = pindex;\n\n    lastProcessedBlockHeight = blockLastProcessed ? blockLastProcessed->nHeight : 0;\n\n    int64_t now = GetAdjustedTime();\n    if (now - lastPersistTime > PERSIST_INTERVAL_SEC || blocksSincePersist >= PERSIST_BLOCK_COUNT)\n        Persist();\n}\n\nvoid CSPVScanner::Persist()\n{\n    LOCK(cs_main);\n\n    if (blockLastProcessed != nullptr && blockLastProcessed->GetBlockTime() > lastPersistedBlockTime)\n    {\n        // persist & prune block index\n        PersistAndPruneForPartialSync();\n\n        // persist lastProcessed\n        CWalletDB walletdb(*wallet.dbw);\n        walletdb.WriteLastSPVBlockProcessed(partialChain.GetLocatorPoW2(blockLastProcessed), blockLastProcessed->GetBlockTime());\n\n        // now that we are sure both the index and lastProcessed time locator have been saved\n        // compute the new pruning height for the next iteration\n\n        int64_t forkTimeLimit = blockLastProcessed->GetBlockTime() - 2 * MAX_FORK_DURATION;\n\n        int maxPruneHeight =\n                // determine oldest block that is at most forkTimeLimit in the past\n                partialChain.LowerBound(partialChain.HeightOffset(),\n                                        std::min(blockLastProcessed->nHeight, partialChain.Height()),\n                                        forkTimeLimit,\n                                        [](const CBlockIndex* index, int64_t limit){ return index->GetBlockTime() < limit; })\n                // the block before that is the youngest that is more than forkTimeLimit ago\n                - 1\n                // the window required to do context checks on the headers\n                - 576;\n\n        if (maxPruneHeight > 0)\n            SetMaxSPVPruneHeight(maxPruneHeight);\n\n        lastPersistTime = GetAdjustedTime();\n        lastPersistedBlockTime = blockLastProcessed->GetBlockTime();\n        blocksSincePersist = 0;\n    }\n}\n\nint CSPVScanner::getProcessedHeight()\n{\n    return lastProcessedBlockHeight;\n}\n"
  },
  {
    "path": "src/wallet/spvscanner.h",
    "content": "// Copyright (c) 2018-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef SPVSCANNER_H\n#define SPVSCANNER_H\n\n#include \"../validation/validationinterface.h\"\n#include <atomic>\n\nclass CWallet;\n\nclass CSPVScanner\n{\npublic:\n    CSPVScanner(CWallet& _wallet);\n    ~CSPVScanner();\n\n    bool StartScan();\n    void ResetScan();\n\n    const CBlockIndex* LastBlockProcessed() const;\n\n    CSPVScanner(const CSPVScanner&) = delete;\n    CSPVScanner& operator=(const CSPVScanner&) = delete;\n\n    // write locator for blockLastProcessed to db for resuming next session, call sparingly\n    void Persist();\n\n    void ResetUnifiedProgressNotification();\n\n    static std::atomic<float> lastProgressReported;\n\n    static int getProcessedHeight();\n\nprivate:\n    CWallet& wallet;\n\n    // timestamp to start block requests, older blocks are known to have no\n    // transactions for the wallet\n    int64_t startTime;\n\n    // SPV scan processed up to this block\n    CBlockIndex* blockLastProcessed;\n\n    // Blocks (blockLastProcessed .. blockRequestTip] have been requested and are pending\n    CBlockIndex* blockRequestTip;\n\n    // Session start height for progress reporting\n    int startHeight;\n\n    // Common initialisation\n    void Init();\n\n    void HeaderTipChanged(const CBlockIndex* pTip);\n\n    // Number of connections for progress reporting\n    // (mirrored from net using NotifyNumConnectionsChanged signal)\n    int numConnections;\n    void OnNumConnectionsChanged(int newNumConnections);\n\n    // triggerred by NotifyKeyPoolToppedUp to recompute filter ranges when keys are added\n    void onKeyPoolToppedUp();\n\n    // Calculate unified progress and trigger\n    void NotifyUnifiedProgress();\n\n    void RequestBlocks();\n\n    // Update value of blockLastProcessed to pindex and persist it to the wallet db\n    void UpdateLastProcessed(CBlockIndex* pindex);\n\n    void ProcessPriorityRequest(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex);\n\n    bool CanSkipBlockFetch(const CBlockIndex* pIndex, uint64_t lastCheckPointHeight);\n\n    // timestamp of peristed last processed block\n    int64_t lastPersistedBlockTime;\n\n    // last time when scan progress was persisted to the db\n    int64_t lastPersistTime;\n\n    // blocks processed since last persist\n    int blocksSincePersist;\n\n    int nRequestsPending;\n\n    // book keeping for monitoring\n    static std::atomic<int> lastProcessedBlockHeight;\n};\n\n#endif // SPVSCANNER_H\n"
  },
  {
    "path": "src/wallet/test/accounting_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"wallet/wallet.h\"\n\n#include \"wallet/test/wallet_test_fixture.h\"\n\n#include <stdint.h>\n\n\n#include <boost/test/unit_test.hpp>\n\nextern CWallet* pwalletMain;\n\nBOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)\n\nstatic void\nGetResults(std::map<CAmount, CAccountingEntry>& results)\n{\n    std::list<CAccountingEntry> aes;\n\n    results.clear();\n    BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);\n    pwalletMain->ListAccountCreditDebit(\"\", aes);\n    for(CAccountingEntry& ae : aes)\n    {\n        results[ae.nOrderPos] = ae;\n    }\n}\n\nBOOST_AUTO_TEST_CASE(acc_orderupgrade)\n{\n    std::vector<CWalletTx*> vpwtx;\n    CWalletTx wtx;\n    CAccountingEntry ae;\n    std::map<CAmount, CAccountingEntry> results;\n\n    LOCK(pwalletMain->cs_wallet);\n\n    ae.strAccount = \"\";\n    ae.nCreditDebit = 1;\n    ae.nTime = 1333333333;\n    ae.strOtherAccount = \"b\";\n    ae.strComment = \"\";\n    pwalletMain->AddAccountingEntry(ae);\n\n    wtx.mapValue[\"comment\"] = \"z\";\n    pwalletMain->AddToWallet(wtx);\n    vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);\n    vpwtx[0]->nTimeReceived = (unsigned int)1333333335;\n    vpwtx[0]->nOrderPos = -1;\n\n    ae.nTime = 1333333336;\n    ae.strOtherAccount = \"c\";\n    pwalletMain->AddAccountingEntry(ae);\n\n    GetResults(results);\n\n    BOOST_CHECK(pwalletMain->nOrderPosNext == 3);\n    BOOST_CHECK(2 == results.size());\n    BOOST_CHECK(results[0].nTime == 1333333333);\n    BOOST_CHECK(results[0].strComment.empty());\n    BOOST_CHECK(1 == vpwtx[0]->nOrderPos);\n    BOOST_CHECK(results[2].nTime == 1333333336);\n    BOOST_CHECK(results[2].strOtherAccount == \"c\");\n\n\n    ae.nTime = 1333333330;\n    ae.strOtherAccount = \"d\";\n    ae.nOrderPos = pwalletMain->IncOrderPosNext();\n    pwalletMain->AddAccountingEntry(ae);\n\n    GetResults(results);\n\n    BOOST_CHECK(results.size() == 3);\n    BOOST_CHECK(pwalletMain->nOrderPosNext == 4);\n    BOOST_CHECK(results[0].nTime == 1333333333);\n    BOOST_CHECK(1 == vpwtx[0]->nOrderPos);\n    BOOST_CHECK(results[2].nTime == 1333333336);\n    BOOST_CHECK(results[3].nTime == 1333333330);\n    BOOST_CHECK(results[3].strComment.empty());\n\n\n    wtx.mapValue[\"comment\"] = \"y\";\n    {\n        CMutableTransaction tx(wtx);\n        --tx.nLockTime;  // Just to change the hash :)\n        wtx.SetTx(MakeTransactionRef(std::move(tx)));\n    }\n    pwalletMain->AddToWallet(wtx);\n    vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);\n    vpwtx[1]->nTimeReceived = (unsigned int)1333333336;\n\n    wtx.mapValue[\"comment\"] = \"x\";\n    {\n        CMutableTransaction tx(wtx);\n        --tx.nLockTime;  // Just to change the hash :)\n        wtx.SetTx(MakeTransactionRef(std::move(tx)));\n    }\n    pwalletMain->AddToWallet(wtx);\n    vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);\n    vpwtx[2]->nTimeReceived = (unsigned int)1333333329;\n    vpwtx[2]->nOrderPos = -1;\n\n    GetResults(results);\n\n    BOOST_CHECK(results.size() == 3);\n    BOOST_CHECK(pwalletMain->nOrderPosNext == 6);\n    BOOST_CHECK(0 == vpwtx[2]->nOrderPos);\n    BOOST_CHECK(results[1].nTime == 1333333333);\n    BOOST_CHECK(2 == vpwtx[0]->nOrderPos);\n    BOOST_CHECK(results[3].nTime == 1333333336);\n    BOOST_CHECK(results[4].nTime == 1333333330);\n    BOOST_CHECK(results[4].strComment.empty());\n    BOOST_CHECK(5 == vpwtx[1]->nOrderPos);\n\n\n    ae.nTime = 1333333334;\n    ae.strOtherAccount = \"e\";\n    ae.nOrderPos = -1;\n    pwalletMain->AddAccountingEntry(ae);\n\n    GetResults(results);\n\n    BOOST_CHECK(results.size() == 4);\n    BOOST_CHECK(pwalletMain->nOrderPosNext == 7);\n    BOOST_CHECK(0 == vpwtx[2]->nOrderPos);\n    BOOST_CHECK(results[1].nTime == 1333333333);\n    BOOST_CHECK(2 == vpwtx[0]->nOrderPos);\n    BOOST_CHECK(results[3].nTime == 1333333336);\n    BOOST_CHECK(results[3].strComment.empty());\n    BOOST_CHECK(results[4].nTime == 1333333330);\n    BOOST_CHECK(results[4].strComment.empty());\n    BOOST_CHECK(results[5].nTime == 1333333334);\n    BOOST_CHECK(6 == vpwtx[1]->nOrderPos);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/wallet/test/crypto_tests.cpp",
    "content": "// Copyright (c) 2014-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"test/test.h\"\n#include \"util/strencodings.h\"\n#include \"wallet/crypter.h\"\n\n#include <vector>\n\n#include <boost/test/unit_test.hpp>\n#include <openssl/aes.h>\n#include <openssl/evp.h>\n\nBOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)\n\nstatic bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)\n{\n    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)\n        return false;\n\n    int i = 0;\n    if (nDerivationMethod == 0)\n        i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],\n                          (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);\n\n    if (i != (int)WALLET_CRYPTO_KEY_SIZE)\n    {\n        memory_cleanse(chKey, sizeof(chKey));\n        memory_cleanse(chIV, sizeof(chIV));\n        return false;\n    }\n    return true;\n}\n\nstatic bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])\n{\n    // max ciphertext len for a n bytes of plaintext is\n    // n + AES_BLOCK_SIZE - 1 bytes\n    int nLen = vchPlaintext.size();\n    int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;\n    vchCiphertext = std::vector<unsigned char> (nCLen);\n\n    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();\n\n    if (!ctx) return false;\n\n    bool fOk = true;\n\n    EVP_CIPHER_CTX_init(ctx);\n    if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;\n    if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;\n    if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;\n    EVP_CIPHER_CTX_cleanup(ctx);\n\n    EVP_CIPHER_CTX_free(ctx);\n\n    if (!fOk) return false;\n\n    vchCiphertext.resize(nCLen + nFLen);\n    return true;\n}\n\nstatic bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])\n{\n    // plaintext will always be equal to or lesser than length of ciphertext\n    int nLen = vchCiphertext.size();\n    int nPLen = nLen, nFLen = 0;\n\n    vchPlaintext = CKeyingMaterial(nPLen);\n\n    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();\n\n    if (!ctx) return false;\n\n    bool fOk = true;\n\n    EVP_CIPHER_CTX_init(ctx);\n    if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;\n    if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;\n    if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;\n    EVP_CIPHER_CTX_cleanup(ctx);\n\n    EVP_CIPHER_CTX_free(ctx);\n\n    if (!fOk) return false;\n\n    vchPlaintext.resize(nPLen + nFLen);\n    return true;\n}\n\nclass TestCrypter\n{\npublic:\nstatic void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,\n                 const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),\n                 const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())\n{\n    unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];\n    unsigned char chIV[WALLET_CRYPTO_IV_SIZE];\n\n    CCrypter crypt;\n    crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);\n\n    OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);\n\n    BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, \\\n        HexStr(chKey, chKey+sizeof(chKey)) + std::string(\" != \") + HexStr(crypt.vchKey));\n    BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, \\\n        HexStr(chIV, chIV+sizeof(chIV)) + std::string(\" != \") + HexStr(crypt.vchIV));\n\n    if(!correctKey.empty())\n        BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \\\n            HexStr(chKey, chKey+sizeof(chKey)) + std::string(\" != \") + HexStr(correctKey.begin(), correctKey.end()));\n    if(!correctIV.empty())\n        BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,\n            HexStr(chIV, chIV+sizeof(chIV)) + std::string(\" != \") + HexStr(correctIV.begin(), correctIV.end()));\n}\n\nstatic void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,\n                 const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),\n                 const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())\n{\n    TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, correctIV);\n    for(SecureString::const_iterator i(passphrase.begin()); i != passphrase.end(); ++i)\n        TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);\n}\n\n\nstatic void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \\\n                        const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())\n{\n    CKeyingMaterial vchDecrypted1;\n    CKeyingMaterial vchDecrypted2;\n    int result1, result2;\n    result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);\n    result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), crypt.vchIV.data());\n    BOOST_CHECK(result1 == result2);\n\n    // These two should be equal. However, OpenSSL 1.0.1j introduced a change\n    // that would zero all padding except for the last byte for failed decrypts.\n    // This behavior was reverted for 1.0.1k.\n    if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)\n    {\n        for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)\n            *it = 0;\n    }\n\n    BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + \" != \" + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));\n\n    if (vchPlaintext.size())\n        BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);\n}\n\nstatic void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,\n                       const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())\n{\n    std::vector<unsigned char> vchCiphertext1;\n    std::vector<unsigned char> vchCiphertext2;\n    int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);\n\n    int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data());\n    BOOST_CHECK(result1 == result2);\n    BOOST_CHECK(vchCiphertext1 == vchCiphertext2);\n\n    if (!vchCiphertextCorrect.empty())\n        BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);\n\n    const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());\n\n    if(vchCiphertext1 == vchCiphertext2)\n        TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);\n}\n\nstatic void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \\\n                       const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())\n{\n    TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), vchPlaintextIn.end()), vchCiphertextCorrect);\n    for(std::vector<unsigned char>::const_iterator i(vchPlaintextIn.begin()); i != vchPlaintextIn.end(); ++i)\n        TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end()));\n}\n\n};\n\nBOOST_AUTO_TEST_CASE(passphrase) {\n    // These are expensive.\n\n    TestCrypter::TestPassphrase(ParseHex(\"0000deadbeef0000\"), \"test\", 25000, \\\n                                ParseHex(\"fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a\"), \\\n                                ParseHex(\"cf2f2691526dd1aa220896fb8bf7c369\"));\n\n    std::string hash(GetRandHash().ToString());\n    std::vector<unsigned char> vchSalt(8);\n    GetRandBytes(&vchSalt[0], vchSalt.size());\n    uint32_t rounds = InsecureRand32();\n    if (rounds > 30000)\n        rounds = 30000;\n    TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds);\n}\n\nBOOST_AUTO_TEST_CASE(encrypt) {\n    std::vector<unsigned char> vchSalt = ParseHex(\"0000deadbeef0000\");\n    BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);\n    CCrypter crypt;\n    crypt.SetKeyFromPassphrase(\"passphrase\", vchSalt, 25000, 0);\n    TestCrypter::TestEncrypt(crypt, ParseHex(\"22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d\"));\n\n    for (int i = 0; i != 100; i++)\n    {\n        uint256 hash(GetRandHash());\n        TestCrypter::TestEncrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));\n    }\n\n}\n\nBOOST_AUTO_TEST_CASE(decrypt) {\n    std::vector<unsigned char> vchSalt = ParseHex(\"0000deadbeef0000\");\n    BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);\n    CCrypter crypt;\n    crypt.SetKeyFromPassphrase(\"passphrase\", vchSalt, 25000, 0);\n\n    // Some corner cases the came up while testing\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca\"));\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486\"));\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c\"));\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea\"));\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd\"));\n    TestCrypter::TestDecrypt(crypt,ParseHex(\"8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9\"));\n\n    for (int i = 0; i != 100; i++)\n    {\n        uint256 hash(GetRandHash());\n        TestCrypter::TestDecrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/wallet/test/wallet_test_fixture.cpp",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/test/wallet_test_fixture.h\"\n\n#include \"rpc/server.h\"\n#include \"wallet/db.h\"\n#include \"wallet/wallet.h\"\n\nCWallet *pwalletMain;\n\nWalletTestingSetup::WalletTestingSetup(const std::string& chainName):\n    TestingSetup(chainName)\n{\n    bitdb.MakeMock();\n\n    WalletLoadState loadState;\n    std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, \"wallet_test.dat\"));\n    pwalletMain = new CWallet(std::move(dbw));\n    pwalletMain->LoadWallet(loadState);\n    RegisterValidationInterface(pwalletMain);\n\n    RegisterWalletRPCCommands(tableRPC);\n}\n\nWalletTestingSetup::~WalletTestingSetup()\n{\n    UnregisterValidationInterface(pwalletMain);\n    delete pwalletMain;\n    pwalletMain = NULL;\n\n    bitdb.Flush(true);\n    bitdb.Reset();\n}\n"
  },
  {
    "path": "src/wallet/test/wallet_test_fixture.h",
    "content": "// Copyright (c) 2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef WALLET_TEST_FIXTURE_H\n#define WALLET_TEST_FIXTURE_H\n\n#include \"test/test.h\"\n\n/** Testing setup and teardown for wallet.\n */\nstruct WalletTestingSetup: public TestingSetup {\n    WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);\n    ~WalletTestingSetup();\n};\n\n#endif\n\n"
  },
  {
    "path": "src/wallet/test/wallet_tests.cpp",
    "content": "// Copyright (c) 2012-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n\n#include <set>\n#include <stdint.h>\n#include <utility>\n#include <vector>\n\n#include \"consensus/validation.h\"\n#include \"rpc/server.h\"\n#include \"test/test.h\"\n#include \"validation/validation.h\"\n#include \"blockstore.h\"\n#include \"wallet/test/wallet_test_fixture.h\"\n\n#include <boost/test/unit_test.hpp>\n#include <univalue.h>\n\n#include <wallet/wallet.h>\n#include <wallet/mnemonic.h>\n\nextern CWallet* pwalletMain;\n\nextern UniValue importmulti(const JSONRPCRequest& request);\nextern UniValue dumpwallet(const JSONRPCRequest& request);\nextern UniValue importwallet(const JSONRPCRequest& request);\n\n// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles\n#define RUN_TESTS 100\n\n// some tests fail 1% of the time due to bad luck.\n// we repeat those tests this many times and only complain if all iterations of the test fail\n#define RANDOM_REPEATS 5\n\nstd::vector<std::unique_ptr<CWalletTx>> wtxn;\n\ntypedef std::set<CInputCoin> CoinSet;\n\nBOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)\n\nstatic const CWallet wallet;\nstatic std::vector<COutput> vCoins;\n\nstatic void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)\n{\n    static int nextLockTime = 0;\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    tx.nLockTime = nextLockTime++;        // so all transactions get different hashes\n    tx.vout.resize(nInput+1);\n    tx.vout[nInput].nValue = nValue;\n    if (fIsFromMe) {\n        // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),\n        // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()\n        tx.vin.resize(1);\n    }\n    std::unique_ptr<CWalletTx> wtx(new CWalletTx(&wallet, MakeTransactionRef(std::move(tx))));\n    // patch wtx cache, this is a dirty hack which replaces the former dirty bitcoin hack\n    // it would be better if CWallet and CWalletTx could operate in this test environment\n    // without needing these hacks to its data stuctures\n    //\n    if (fIsFromMe)\n    {\n        wtx->debitCached[0] = nValue;\n    }\n    COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);\n    vCoins.push_back(output);\n    wtxn.emplace_back(std::move(wtx));\n}\n\nstatic void empty_wallet(void)\n{\n    vCoins.clear();\n    wtxn.clear();\n}\n\nstatic bool equal_sets(CoinSet a, CoinSet b)\n{\n    std::pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());\n    return ret.first == a.end() && ret.second == b.end();\n}\n\nBOOST_AUTO_TEST_CASE(coin_selection_tests)\n{\n    CoinSet setCoinsRet, setCoinsRet2;\n    CAmount nValueRet;\n\n    CWallet wallet;\n    LOCK(wallet.cs_wallet);\n    wallet.GenerateNewLegacyAccount(\"My account\");\n\n    // test multiple times to allow for differences in the shuffle order\n    for (int i = 0; i < RUN_TESTS; i++)\n    {\n        empty_wallet();\n\n        // with an empty wallet we can't even pay one cent\n        BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n\n        add_coin(wallet, 1*CENT, 4);        // add a new 1 cent coin\n\n        // with a new 1 cent coin, we still can't find a mature 1 cent\n        BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n\n        // but we can find a new 1 cent\n        BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);\n\n        add_coin(wallet, 2*CENT);           // add a mature 2 cent coin\n\n        // we can't make 3 cents of mature coins\n        BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n\n        // we can make 3 cents of new  coins\n        BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);\n\n        add_coin(wallet, 5*CENT);           // add a mature 5 cent coin,\n        add_coin(wallet, 10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses\n        add_coin(wallet, 20*CENT);          // and a mature 20 cent coin\n\n        // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27.  total = 38\n\n        // we can't make 38 cents only if we disallow new coins:\n        BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n        // we can't even make 37 cents if we don't allow new coins even if they're from us\n        BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n        // but we can make 37 cents if we accept new coins from ourself\n        BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);\n        // and we can make 38 cents if we accept all new coins\n        BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);\n\n        // try making 34 cents from 1,2,5,10,20 - we can't do it exactly\n        BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 35 * CENT);       // but 35 cents is closest\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);     // the best should be 20+10+5.  it's incredibly unlikely the 1 or 2 got included (but possible)\n\n        // when we try making 7 cents, the smaller coins (1,2,5) are enough.  We should see just 2+5\n        BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);\n\n        // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.\n        BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK(nValueRet == 8 * CENT);\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);\n\n        // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)\n        BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n\n        // now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin\n        empty_wallet();\n\n        add_coin(wallet,  6*CENT);\n        add_coin(wallet,  7*CENT);\n        add_coin(wallet,  8*CENT);\n        add_coin(wallet, 20*CENT);\n        add_coin(wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total\n\n        // check that we have 71 and not 72\n        BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n\n        // now try making 16 cents.  the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20\n        BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n\n        add_coin(wallet,  5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total\n\n        // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20\n        BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);\n\n        add_coin(wallet,  18*CENT); // now we have 5+6+7+8+18+20+30\n\n        // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18\n        BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 18 * CENT);  // we should get 18 in 1 coin\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins\n\n        // now try making 11 cents.  we should get 5+6\n        BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);\n\n        // check that the smallest bigger coin is used\n        add_coin(wallet,  1*COIN);\n        add_coin(wallet,  2*COIN);\n        add_coin(wallet,  3*COIN);\n        add_coin(wallet,  4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents\n        BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 1 * COIN);  // we should get 1 NLG in 1 coin\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n\n        BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 2 * COIN);  // we should get 2 NLG in 1 coin\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n\n        // empty the wallet and start again, now with fractions of a cent, to test small change avoidance\n\n        empty_wallet();\n        add_coin(wallet, MIN_CHANGE * 1 / 10);\n        add_coin(wallet, MIN_CHANGE * 2 / 10);\n        add_coin(wallet, MIN_CHANGE * 3 / 10);\n        add_coin(wallet, MIN_CHANGE * 4 / 10);\n        add_coin(wallet, MIN_CHANGE * 5 / 10);\n\n        // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE\n        // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly\n        BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);\n\n        // but if we add a bigger coin, small change is avoided\n        add_coin(wallet, 1111*MIN_CHANGE);\n\n        // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5\n        BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount\n\n        // if we add more small coins:\n        add_coin(wallet, MIN_CHANGE * 6 / 10);\n        add_coin(wallet, MIN_CHANGE * 7 / 10);\n\n        // and try again to make 1.0 * MIN_CHANGE\n        BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount\n\n        // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)\n        // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change\n        empty_wallet();\n        for (int j = 0; j < 20; j++)\n            add_coin(wallet, 50000 * COIN);\n\n        BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins\n\n        // if there's not enough in the smaller coins to make at least 1 * MIN_CHANGE change (0.5+0.6+0.7 < 1.0+1.0),\n        // we need to try finding an exact subset anyway\n\n        // sometimes it will fail, and so we use the next biggest coin:\n        empty_wallet();\n        add_coin(wallet, MIN_CHANGE * 5 / 10);\n        add_coin(wallet, MIN_CHANGE * 6 / 10);\n        add_coin(wallet, MIN_CHANGE * 7 / 10);\n        add_coin(wallet, 1111 * MIN_CHANGE);\n        BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n\n        // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)\n        empty_wallet();\n        add_coin(wallet, MIN_CHANGE * 4 / 10);\n        add_coin(wallet, MIN_CHANGE * 6 / 10);\n        add_coin(wallet, MIN_CHANGE * 8 / 10);\n        add_coin(wallet, 1111 * MIN_CHANGE);\n        BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);   // we should get the exact amount\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6\n\n        // test avoiding small change\n        empty_wallet();\n        add_coin(wallet, MIN_CHANGE * 5 / 100);\n        add_coin(wallet, MIN_CHANGE * 1);\n        add_coin(wallet, MIN_CHANGE * 100);\n\n        // trying to make 100.01 from these three coins\n        BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);\n\n        // but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change\n        BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n        BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);\n        BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);\n\n        // test with many inputs\n        for (CAmount amt=1500; amt < COIN; amt*=10) {\n             empty_wallet();\n             // Create 676 inputs (=  (old MAX_STANDARD_TX_SIZE == 100000)  / 148 bytes per input)\n             for (uint16_t j = 0; j < 676; j++)\n                 add_coin(wallet, amt);\n             BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, 0, vCoins, setCoinsRet, nValueRet, false));\n             if (amt - 2000 < MIN_CHANGE) {\n                 // needs more than one input:\n                 uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);\n                 CAmount returnValue = amt * returnSize;\n                 BOOST_CHECK_EQUAL(nValueRet, returnValue);\n                 BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize);\n             } else {\n                 // one input is sufficient:\n                 BOOST_CHECK_EQUAL(nValueRet, amt);\n                 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);\n             }\n        }\n\n        // test randomness\n        {\n            empty_wallet();\n            for (int i2 = 0; i2 < 100; i2++)\n                add_coin(wallet, COIN);\n\n            // picking 50 from 100 coins doesn't depend on the shuffle,\n            // but does depend on randomness in the stochastic approximation code\n            BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet, false));\n            BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet, false));\n            BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));\n\n            int fails = 0;\n            for (int j = 0; j < RANDOM_REPEATS; j++)\n            {\n                // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time\n                // run the test RANDOM_REPEATS times and only complain if all of them fail\n                BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet, false));\n                BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet, false));\n                if (equal_sets(setCoinsRet, setCoinsRet2))\n                    fails++;\n            }\n            BOOST_CHECK_NE(fails, RANDOM_REPEATS);\n\n            // add 75 cents in small change.  not enough to make 90 cents,\n            // then try making 90 cents.  there are multiple competing \"smallest bigger\" coins,\n            // one of which should be picked at random\n            add_coin(wallet, 5 * CENT);\n            add_coin(wallet, 10 * CENT);\n            add_coin(wallet, 15 * CENT);\n            add_coin(wallet, 20 * CENT);\n            add_coin(wallet, 25 * CENT);\n\n            fails = 0;\n            for (int j = 0; j < RANDOM_REPEATS; j++)\n            {\n                // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time\n                // run the test RANDOM_REPEATS times and only complain if all of them fail\n                BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet , nValueRet, false));\n                BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet, false));\n                if (equal_sets(setCoinsRet, setCoinsRet2))\n                    fails++;\n            }\n            BOOST_CHECK_NE(fails, RANDOM_REPEATS);\n        }\n    }\n    empty_wallet();\n}\n\nBOOST_AUTO_TEST_CASE(ApproximateBestSubset)\n{\n    CoinSet setCoinsRet;\n    CAmount nValueRet;\n\n    CWallet wallet;\n    LOCK(wallet.cs_wallet);\n    wallet.GenerateNewLegacyAccount(\"My account\");\n    empty_wallet();\n\n    // Test vValue sort order\n    for (int i = 0; i < 1000; i++)\n        add_coin(wallet, 1000 * COIN);\n    add_coin(wallet, 3 * COIN);\n\n    BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet, false));\n    BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);\n    BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);\n\n    empty_wallet();\n}\n\nBOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)\n{\n    LOCK(cs_main);\n\n    CScript scriptPubKey = GetScriptForRawPubKey(coinbaseKey.GetPubKey());\n    std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n\n    // Cap last block file size, and mine new block in a new block file.\n    CBlockIndex* const nullBlock = nullptr;\n    CBlockIndex* oldTip = chainActive.Tip();\n    GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;\n    CreateAndProcessBlock({}, reservedScript);\n    CBlockIndex* newTip = chainActive.Tip();\n\n    // Verify ScanForWalletTransactions picks up transactions in both the old\n    // and new block files.\n    {\n        CWallet wallet;\n        LOCK(wallet.cs_wallet);\n        wallet.GenerateNewLegacyAccount(\"My account\");\n        CAccount* account = wallet.getActiveAccount();\n        wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey(), *account, KEYCHAIN_EXTERNAL);\n        BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));\n        BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 2 * 1000 * COIN);\n    }\n\n    // Prune the older block file.\n    int nFile = oldTip->GetBlockPos().nFile;\n    PruneOneBlockFile(nFile);\n    blockStore.UnlinkPrunedFiles({nFile});\n\n    // Verify ScanForWalletTransactions only picks transactions in the new block\n    // file.\n    {\n        CWallet wallet;\n        LOCK(wallet.cs_wallet);\n        wallet.GenerateNewLegacyAccount(\"My account\");\n        CAccount* account = wallet.getActiveAccount();\n        wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey(), *account, KEYCHAIN_EXTERNAL);\n        BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));\n        BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 1000 * COIN);\n    }\n\n    // Verify importmulti RPC returns failure for a key whose creation time is\n    // before the missing block, and success for a key whose creation time is\n    // after.\n    {\n        CWallet wallet;\n        vpwallets.insert(vpwallets.begin(), &wallet);\n        UniValue keys;\n        keys.setArray();\n        UniValue key;\n        key.setObject();\n        key.pushKV(\"scriptPubKey\", HexStr(GetScriptForRawPubKey(coinbaseKey.GetPubKey())));\n        key.pushKV(\"timestamp\", 0);\n        key.pushKV(\"internal\", UniValue(true));\n        keys.push_back(key);\n        key.clear();\n        key.setObject();\n        CKey futureKey;\n        futureKey.MakeNewKey(true);\n        key.pushKV(\"scriptPubKey\", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));\n        key.pushKV(\"timestamp\", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);\n        key.pushKV(\"internal\", UniValue(true));\n        keys.push_back(key);\n\n        // We need a legacy account where we want the keys to go.\n        wallet.GenerateNewLegacyAccount(\"LegacyForImport\");\n\n        JSONRPCRequest request;\n        request.params.setArray();\n        request.params.push_back(\"LegacyForImport\");\n        request.params.push_back(keys);\n\n\n        UniValue response = importmulti(request);\n        BOOST_CHECK_EQUAL(response.write(), strprintf(\"[{\\\"success\\\":false,\\\"error\\\":{\\\"code\\\":-1,\\\"message\\\":\\\"Rescan failed for key with creation timestamp %d. There was an error reading a block from time %d, which is after or within %d seconds of key creation, and could contain transactions pertaining to the key. As a result, transactions and coins using this key may not appear in the wallet. This error could be caused by pruning or data corruption (see Munt log for details) and could be dealt with by downloading and rescanning the relevant blocks (see -reindex and -rescan options).\\\"}},{\\\"success\\\":true}]\", 0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));\n        vpwallets.erase(vpwallets.begin());\n    }\n}\n\n// Verify importwallet RPC starts rescan at earliest block with timestamp\n// greater or equal than key birthday. Previously there was a bug where\n// importwallet RPC would start the scan at the latest block with timestamp less\n// than or equal to key birthday.\nBOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)\n{\n    LOCK(cs_main);\n\n    CScript scriptPubKey = GetScriptForRawPubKey(coinbaseKey.GetPubKey());\n    std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n\n    // Create two blocks with same timestamp to verify that importwallet rescan\n    // will pick up both blocks, not just the first.\n    const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;\n    SetMockTime(BLOCK_TIME);\n    coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, reservedScript).vtx[0]);\n    coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, reservedScript).vtx[0]);\n\n    // Set key birthday to block time increased by the timestamp window, so\n    // rescan will start at the block time.\n    const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;\n    SetMockTime(KEY_TIME);\n    coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, reservedScript).vtx[0]);\n\n    // Import key into wallet and call dumpwallet to create backup file.\n    {\n        CWallet wallet;\n        LOCK(wallet.cs_wallet);\n        wallet.GenerateNewLegacyAccount(\"My account\");\n        CAccount* account = wallet.getActiveAccount();\n        wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;\n        wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey(), *account, KEYCHAIN_EXTERNAL);\n\n        JSONRPCRequest request;\n        request.params.setArray();\n        request.params.push_back(\"wallet.backup\");\n        vpwallets.insert(vpwallets.begin(), &wallet);\n        ::dumpwallet(request);\n    }\n\n    // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME\n    // were scanned, and no prior blocks were scanned.\n    {\n        CWallet wallet;\n        wallet.GenerateNewLegacyAccount(\"My account\");\n\n        JSONRPCRequest request;\n        request.params.setArray();\n        request.params.push_back(\"wallet.backup\");\n        request.params.push_back(\"My account\");\n        vpwallets[0] = &wallet;\n        ::importwallet(request);\n\n        BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);\n        BOOST_CHECK_EQUAL(coinbaseTxns.size(), COINBASE_MATURITY+3U);\n        for (size_t i = 0; i < coinbaseTxns.size(); ++i)\n        {\n            bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());\n            bool expected = i >= (size_t)COINBASE_MATURITY;\n            BOOST_CHECK_EQUAL(found, expected);\n        }\n    }\n\n    SetMockTime(0);\n    vpwallets.erase(vpwallets.begin());\n}\n\n// Check that GetImmatureCredit() returns a newly calculated value instead of\n// the cached value after a MarkDirty() call.\n//\n// This is a regression test written to verify a bugfix for the immature credit\n// function. Similar tests probably should be written for the other credit and\n// debit functions.\nBOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)\n{\n    CWallet wallet;\n    CWalletTx wtx(&wallet, MakeTransactionRef(coinbaseTxns.back()));\n    LOCK2(cs_main, wallet.cs_wallet);\n    wtx.hashBlock = chainActive.Tip()->GetBlockHashLegacy();\n    wtx.nIndex = 0;\n\n    // Call GetImmatureCredit() once before adding the key to the wallet to\n    // cache the current immature credit amount, which is 0.\n    BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);\n\n    // Invalidate the cached value, add the key, and make sure a new immature\n    // credit amount is calculated.\n    wtx.MarkDirty();\n    wallet.GenerateNewLegacyAccount(\"My account\");\n    CAccount* account = wallet.getActiveAccount();\n    wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey(), *account, KEYCHAIN_EXTERNAL);\n    BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 1000*COIN);\n}\n\nstatic int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)\n{\n    CMutableTransaction tx(TEST_DEFAULT_TX_VERSION);\n    tx.nLockTime = lockTime;\n    SetMockTime(mockTime);\n    CBlockIndex* block = nullptr;\n    if (blockTime > 0) {\n        auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);\n        assert(inserted.second);\n        const uint256& hash = inserted.first->first;\n        block = inserted.first->second;\n        block->nTime = blockTime;\n        block->phashBlock = &hash;\n    }\n\n    CWalletTx wtx(&wallet, MakeTransactionRef(tx));\n    if (block) {\n        wtx.SetMerkleBranch(block, 0);\n    }\n    wallet.AddToWallet(wtx);\n    return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;\n}\n\n// Simple test to verify assignment of CWalletTx::nTimeSmart value. Could be\n// expanded to cover more corner cases of smart time logic.\nBOOST_AUTO_TEST_CASE(ComputeTimeSmart)\n{\n    CWallet wallet;\n\n    // New transaction should use clock time if lower than block time.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 1, 100, 120), 100);\n\n    // Test that updating existing transaction does not change smart time.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 1, 200, 220), 100);\n\n    // New transaction should use clock time if there's no block time.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 2, 300, 0), 300);\n\n    // New transaction should use block time if lower than clock time.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 3, 420, 400), 400);\n\n    // New transaction should use block time if lower than clock time and latest entry time.\n    //NB! This behaviour differs from bitcoin where the latest entry time (400) would be expected to be returned instead.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 4, 500, 390), 390);\n\n    // If there are future entries, new transaction should use time of the\n    // newest entry that is no more than 300 seconds ahead of the clock time.\n    BOOST_CHECK_EQUAL(AddTx(wallet, 5, 50, 600), 300);\n\n    // Reset mock time for other tests.\n    SetMockTime(0);\n}\n\nBOOST_AUTO_TEST_CASE(LoadReceiveRequests)\n{\n    CTxDestination dest = CKeyID();\n    pwalletMain->AddDestData(dest, \"misc\", \"val_misc\");\n    pwalletMain->AddDestData(dest, \"rr0\", \"val_rr0\");\n    pwalletMain->AddDestData(dest, \"rr1\", \"val_rr1\");\n\n    auto values = pwalletMain->GetDestValues(\"rr\");\n    BOOST_CHECK_EQUAL(values.size(), 2U);\n    BOOST_CHECK_EQUAL(values[0], \"val_rr0\");\n    BOOST_CHECK_EQUAL(values[1], \"val_rr1\");\n}\n\nclass ListCoinsTestingSetup : public TestChain100Setup\n{\npublic:\n    ListCoinsTestingSetup()\n    {\n        CScript scriptPubKey = GetScriptForRawPubKey(coinbaseKey.GetPubKey());\n        std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n        CreateAndProcessBlock({}, reservedScript);\n        ::bitdb.MakeMock();\n        wallet.reset(new CWallet(std::unique_ptr<CWalletDBWrapper>(new CWalletDBWrapper(&bitdb, \"wallet_test.dat\"))));\n        WalletLoadState firstRun;\n        wallet->LoadWallet(firstRun);\n        LOCK(wallet->cs_wallet);\n        wallet->GenerateNewLegacyAccount(\"My account\");\n        CAccount* account = wallet->getActiveAccount();\n        wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey(), *account, KEYCHAIN_EXTERNAL);\n        wallet->ScanForWalletTransactions(chainActive.Genesis());\n    }\n\n    ~ListCoinsTestingSetup()\n    {\n        wallet.reset();\n        ::bitdb.Flush(true);\n        ::bitdb.Reset();\n    }\n\n    CWalletTx& AddTx(CRecipient recipient)\n    {\n        CScript scriptPubKey = GetScriptForRawPubKey(coinbaseKey.GetPubKey());\n        std::shared_ptr<CReserveKeyOrScript> reservedScript = std::make_shared<CReserveKeyOrScript>(scriptPubKey);\n\n        CWalletTx wtx;\n        CAccount* account = wallet->getActiveAccount();\n        CReserveKeyOrScript reservekey(wallet.get(), account, KEYCHAIN_CHANGE);\n        CAmount fee;\n        int changePos = -1;\n        std::string error;\n        BOOST_CHECK(wallet->CreateTransaction(account, {recipient}, wtx, reservekey, fee, changePos, error));\n        CValidationState state;\n        BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));\n        auto it = wallet->mapWallet.find(wtx.GetHash());\n        BOOST_CHECK(it != wallet->mapWallet.end());\n        CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, reservedScript);\n        it->second.SetMerkleBranch(chainActive.Tip(), 1);\n        return it->second;\n    }\n\n    std::unique_ptr<CWallet> wallet;\n};\n\nBOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)\n{\n    std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();\n    LOCK(wallet->cs_wallet);\n    CAccount* account = wallet->getActiveAccount();\n\n    // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey\n    // address.\n    auto list = wallet->ListCoins(account);\n    BOOST_CHECK_EQUAL(list.size(), 1U);\n    BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);\n    BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);\n\n    // Check initial balance from first mature coinbase transaction.\n    BOOST_CHECK_EQUAL(17000000000000000, wallet->GetAvailableBalance(account));\n\n    // Add a transaction creating a change address, and confirm ListCoins still\n    // returns the coin associated with the change address underneath the\n    // coinbaseKey pubkey, even though the change address has a different\n    // pubkey.\n    AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});\n    list = wallet->ListCoins(account);\n    BOOST_CHECK_EQUAL(list.size(), 1U);\n    BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);\n    BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);\n\n    // Lock both coins. Confirm number of available coins drops to 0.\n    std::vector<COutput> available;\n    wallet->AvailableCoins(account, available);\n    BOOST_CHECK_EQUAL(available.size(), 2U);\n    for (const auto& group : list) {\n        for (const auto& coin : group.second) {\n            wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));\n        }\n    }\n    wallet->AvailableCoins(account, available);\n    BOOST_CHECK_EQUAL(available.size(), 0U);\n\n    // Confirm ListCoins still returns same result as before, despite coins\n    // being locked.\n    list = wallet->ListCoins(account);\n    BOOST_CHECK_EQUAL(list.size(), 1U);\n    BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);\n    BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);\n}\n\nBOOST_AUTO_TEST_CASE(TestMnemonics)\n{\n    std::vector<std::pair<SecureString, SecureString> > testVector;\n\n    testVector.push_back(std::pair(\"00000000000000000000000000000000\", \"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about\"));\n    testVector.push_back(std::pair(\"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f\", \"legal winner thank year wave sausage worth useful legal winner thank yellow\"));\n    testVector.push_back(std::pair(\"80808080808080808080808080808080\", \"letter advice cage absurd amount doctor acoustic avoid letter advice cage above\"));\n    testVector.push_back(std::pair(\"ffffffffffffffffffffffffffffffff\", \"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong\"));\n    testVector.push_back(std::pair(\"000000000000000000000000000000000000000000000000\", \"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent\"));\n    testVector.push_back(std::pair(\"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f\", \"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will\"));\n    testVector.push_back(std::pair(\"808080808080808080808080808080808080808080808080\", \"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always\"));\n    testVector.push_back(std::pair(\"ffffffffffffffffffffffffffffffffffffffffffffffff\", \"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when\"));\n    testVector.push_back(std::pair(\"0000000000000000000000000000000000000000000000000000000000000000\", \"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art\"));\n    testVector.push_back(std::pair(\"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f\", \"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title\"));\n    testVector.push_back(std::pair(\"8080808080808080808080808080808080808080808080808080808080808080\",  \"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless\"));\n    testVector.push_back(std::pair(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",  \"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote\"));\n    testVector.push_back(std::pair(\"9e885d952ad362caeb4efe34a8e91bd2\",  \"ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic\"));\n    testVector.push_back(std::pair(\"6610b25967cdcca9d59875f5cb50b0ea75433311869e930b\",  \"gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog\"));\n    testVector.push_back(std::pair(\"68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c\",  \"hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length\"));\n    testVector.push_back(std::pair(\"c0ba5a8e914111210f2bd131f3d5e08d\", \"scheme spot photo card baby mountain device kick cradle pact join borrow\"));\n    testVector.push_back(std::pair(\"6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3\", \"horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave\"));\n    testVector.push_back(std::pair(\"9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863\",  \"panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside\"));\n    testVector.push_back(std::pair(\"23db8160a31d3e0dca3688ed941adbf3\",  \"cat swing flag economy stadium alone churn speed unique patch report train\"));\n    testVector.push_back(std::pair(\"8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0\",  \"light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access\"));\n    testVector.push_back(std::pair(\"066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad\",  \"all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform\"));\n    testVector.push_back(std::pair(\"f30f8c1da665478f49b001d94c5fc452\", \"vessel ladder alter error federal sibling chat ability sun glass valve picture\"));\n    testVector.push_back(std::pair(\"c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05\",  \"scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump\"));\n    testVector.push_back(std::pair(\"f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f\",  \"void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold\"));\n\n    for(auto test : testVector)\n    {\n        std::vector<unsigned char> data = ParseHex(test.first.c_str());\n        SecureString comp = mnemonicFromEntropy(data, data.size()*8);\n        BOOST_CHECK_EQUAL(comp, test.second);\n        std::vector<unsigned char> datacomp = entropyFromMnemonic(test.second);\n        BOOST_CHECK_EQUAL(SecureString(HexStr(datacomp.begin(),datacomp.end()).c_str()), test.first);\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "src/wallet/wallet.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"alert.h\"\n#include \"base58.h\"\n#include \"checkpoints.h\"\n#include \"chain.h\"\n#include \"wallet/coincontrol.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/validation.h\"\n#include \"consensus/tx_verify.h\"\n#include \"fs.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"net.h\"\n#include \"policy/fees.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n#include \"script/script.h\"\n#include \"script/sign.h\"\n#include \"scheduler.h\"\n#include \"spvscanner.h\"\n#include \"timedata.h\"\n#include \"txmempool.h\"\n#include \"util.h\"\n#include \"ui_interface.h\"\n#include \"util/moneystr.h\"\n\n#include <assert.h>\n\n#include <boost/algorithm/string/replace.hpp>\n#include <algorithm>\n#include <random>\n#include <fstream>\n#include <thread>\n\n//Munt specific includes\n#include \"init.h\"\n#include <unity/appmanager.h>\n#include <wallet/mnemonic.h>\n#include <script/ismine.h>\n#include <txdb.h>\n\n//fixme: (PHASE5) - we can remove these includes after phase4 activation.\n#include \"witnessutil.h\"\n\nstd::vector<CWalletRef> vpwallets;\nCWalletRef pactiveWallet = NULL;\n\n\n/** Transaction fee set by the user */\nCFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);\nunsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;\nbool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;\nbool fWalletRbf = DEFAULT_WALLET_RBF;\n\nconst char * DEFAULT_WALLET_DAT = \"wallet.dat\";\n//const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;\n\n/**\n * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)\n * Override with -mintxfee\n */\nCFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);\n/**\n * If fee estimation does not have enough data to provide estimates, use this fee instead.\n * Has no effect if not using fee estimation\n * Override with -fallbackfee\n */\nCFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);\n\n/** @defgroup mapWallet\n *\n * @{\n */\n\nstruct CompareValueOnly\n{\n    bool operator()(const CInputCoin& t1,\n                    const CInputCoin& t2) const\n    {\n        return t1.txout.nValue < t2.txout.nValue;\n    }\n};\n\nstd::string COutput::ToString() const\n{\n    return strprintf(\"COutput(%s, %d, %d) [%s]\", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));\n}\n\nconst CWalletTx* CWallet::GetWalletTx(const uint256& hash) const\n{\n    LOCK(cs_wallet);\n    std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);\n    if (it == mapWallet.end())\n        return NULL;\n    return &(it->second);\n}\n\nbool CWallet::GetTxHash(const COutPoint& outpoint, uint256& txHash) const\n{\n    auto hashIter = mapWalletHash.find(outpoint.getBucketHash());\n    if (hashIter != mapWalletHash.end())\n    {\n        txHash = hashIter->second;\n        return true;\n    }\n    else\n    {\n        return ::GetTxHash(outpoint, txHash);\n    }\n}\n\nCWalletTx* CWallet::GetWalletTx(const COutPoint& outpoint) const\n{\n    uint256 txHash;\n    if (outpoint.isHash)\n    {\n        txHash = outpoint.getTransactionHash();\n    }\n    else\n    {\n        if (!CWallet::GetTxHash(outpoint, txHash))\n        {\n            return nullptr;\n        }\n    }\n    return const_cast<CWalletTx*>(GetWalletTx(txHash));\n}\n\nbool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey, CAccount& forAccount, int nKeyChain)\n{\n    AssertLockHeld(cs_wallet); // mapKeyMetadata\n    if (!forAccount.AddKeyPubKey(secret, pubkey, nKeyChain))\n        return false;\n\n    // check if we need to remove from watch-only\n    CScript script;\n    script = GetScriptForDestination(pubkey.GetID());\n    if (HaveWatchOnly(script))\n        RemoveWatchOnly(script);\n    script = GetScriptForRawPubKey(pubkey);\n    if (HaveWatchOnly(script))\n        RemoveWatchOnly(script);\n\n    // Special case, witness keys are never encrypted when added.\n    if ((forAccount.IsHD() && forAccount.IsPoW2Witness() && nKeyChain == KEYCHAIN_WITNESS))\n    {\n        return CWalletDB(*dbw).WriteKeyOverride(pubkey, secret.GetPrivKey(), getUUIDAsString(forAccount.getUUID()), nKeyChain);\n    }\n    else if (!IsCrypted() || (forAccount.IsFixedKeyPool() && forAccount.IsPoW2Witness()))\n    {\n        return CWalletDB(*dbw).WriteKey(pubkey, secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()], getUUIDAsString(forAccount.getUUID()), nKeyChain);\n    }\n    else\n    {\n        std::vector<unsigned char> encryptedKeyOut;\n        if (nKeyChain == KEYCHAIN_EXTERNAL)\n        {\n            if (!forAccount.externalKeyStore.GetKey(pubkey.GetID(), encryptedKeyOut))\n            {\n                return false;\n            }\n            return CWalletDB(*dbw).WriteCryptedKey(pubkey, encryptedKeyOut, mapKeyMetadata[pubkey.GetID()], getUUIDAsString(forAccount.getUUID()), nKeyChain);\n        }\n        else\n        {\n            if (!forAccount.internalKeyStore.GetKey(pubkey.GetID(), encryptedKeyOut))\n            {\n                return false;\n            }\n            return CWalletDB(*dbw).WriteCryptedKey(pubkey, encryptedKeyOut, mapKeyMetadata[pubkey.GetID()], getUUIDAsString(forAccount.getUUID()), nKeyChain);\n        }\n    }\n    return true;\n}\n\nbool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)\n{\n    AssertLockHeld(cs_wallet); // mapKeyMetadata\n    if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < int64_t(nTimeFirstKey)))\n        nTimeFirstKey = meta.nCreateTime;\n\n    mapKeyMetadata[pubkey.GetID()] = meta;\n    return true;\n}\n\nbool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, const std::string& forAccount, int64_t nKeyChain)\n{\n    LOCK(cs_wallet);\n\n    if (mapAccounts.find(getUUIDFromString(forAccount)) == mapAccounts.end())\n        return false;\n \n    return mapAccounts[getUUIDFromString(forAccount)]->AddCryptedKeyWithChain(vchPubKey, vchCryptedSecret, nKeyChain);\n}\n\nvoid CWallet::UpdateTimeFirstKey(int64_t nCreateTime)\n{\n    AssertLockHeld(cs_wallet);\n    if (nCreateTime <= 1) {\n        // Cannot determine birthday information, so set the wallet birthday to\n        // the beginning of time.\n        nTimeFirstKey = 1;\n    } else if (!nTimeFirstKey || nCreateTime < int64_t(nTimeFirstKey)) {\n        nTimeFirstKey = nCreateTime;\n    }\n}\n\nbool CWallet::AddCScript(const CScript& redeemScript)\n{\n    LOCK(cs_wallet);\n\n    //fixme: (FUT) (WATCH_ONLY)\n    bool ret = false;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        if (forAccount->AddCScript(redeemScript))\n        {\n            ret = true;\n            break;\n        }\n    }\n\n    if (!ret)\n        return false;\n    return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript);\n}\n\nbool CWallet::LoadCScript(const CScript& redeemScript)\n{\n    LOCK(cs_wallet);\n\n    /* A sanity check was added in pull #3843 to avoid adding redeemScripts\n     * that never can be redeemed. However, old wallets may still contain\n     * these. Do not add them to the wallet and warn. */\n    if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)\n    {\n        std::string strAddr = CNativeAddress(CScriptID(redeemScript)).ToString();\n        LogPrintf(\"%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\\n\",\n            __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);\n        return true;\n    }\n\n    //fixme: (FUT) (WATCH_ONLY)\n    bool ret = false;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        ret = forAccount->AddCScript(redeemScript);\n        if (ret == true)\n            break;\n    }\n    return ret;\n}\n\nbool CWallet::AddWatchOnly(const CScript &dest, int64_t nCreateTime)\n{\n    AssertLockHeld(cs_wallet);\n\n    bool ret = false;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        //fixme: (FUT) (WATCH_ONLY) - nCreateTime should go here as well?\n        if (forAccount->AddWatchOnly(dest))\n            ret = true;\n    }\n    if (!ret)\n        return false;\n\n    const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];\n    UpdateTimeFirstKey(meta.nCreateTime);\n\n     NotifyWatchonlyChanged(true);\n    return CWalletDB(*dbw).WriteWatchOnly(dest, meta);\n}\n\nbool CWallet::RemoveWatchOnly(const CScript &dest)\n{\n    AssertLockHeld(cs_wallet);\n    //fixme: (FUT) (WATCH_ONLY)\n    bool ret = true;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        if (forAccount->RemoveWatchOnly(dest))\n        {\n            ret = true;\n            break;\n        }\n    }\n    if (!ret)\n        return false;\n    if (!HaveWatchOnly())\n        NotifyWatchonlyChanged(false);\n    if (!CWalletDB(*dbw).EraseWatchOnly(dest))\n        return false;\n\n    return true;\n}\n\nbool CWallet::LoadWatchOnly(const CScript &dest)\n{\n    AssertLockHeld(cs_wallet);\n\n    //fixme: (FUT) (WATCH_ONLY)\n    bool ret = false;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        ret = forAccount->AddWatchOnly(dest);\n        if (ret)\n            break;\n    }\n    return ret;\n}\n\nbool CWallet::Unlock(const SecureString& strWalletPassphrase)\n{\n    CCrypter crypter;\n    CKeyingMaterial _vMasterKey;\n\n    {\n        LOCK(cs_wallet);\n        for(const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)\n        {\n            if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))\n            {\n                LogPrintf(\"CWallet::Unlock - Failed to set key from phrase\");\n                return false;\n            }\n            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))\n                continue; // try another master key\n            if (IsLocked()) {\n                bool unlocked = UnlockWithMasterKey(_vMasterKey);\n                if (unlocked)\n                    fAutoLock = false;\n                return unlocked;\n            }\n            else\n                return true;\n        }\n    }\n    LogPrintf(\"CWallet::Unlock - Failed to unlock any keys\");\n    return false;\n}\n\nbool CWallet::UnlockWithTimeout(const SecureString& strWalletPassphrase, int64_t lockTimeoutSeconds)\n{\n    bool ret = Unlock(strWalletPassphrase);\n\n    // Schedule the lock `lockTimeoutSeconds` from now\n    if (ret && schedulerForLock)\n    {\n        nRelockTime = GetTime() + lockTimeoutSeconds;\n\n        // Keep the time we are requesting here as a value copy in the lambda in addition to being stored as a member variable...\n        // Why? So that we can check that it hasn't changed before calling the lock\n        // Otherwise this sequence of events is an issue:\n        // 1. Unlock with timeout of 300.\n        // 2. Call lock after 250 seconds.\n        // 3. Unlock again with a timeout of 300.\n        // 4. We are now expecting to be locked for 300 seconds but instead of 50 seconds the first lambda executes and kills our lock.\n        int64_t nOriginalRelockTime = nRelockTime;\n        schedulerForLock->schedule( [this, nOriginalRelockTime](){\n            if (this->nRelockTime == nOriginalRelockTime)\n            {\n                Lock();\n            }\n        },  std::chrono::system_clock::time_point(std::chrono::seconds(nRelockTime)));\n    }\n    return ret;\n}\n\nbool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)\n{\n    bool fWasLocked = IsLocked();\n\n    {\n        LOCK(cs_wallet);\n        Lock();\n\n        CCrypter crypter;\n        CKeyingMaterial _vMasterKey;\n        for(MasterKeyMap::value_type& pMasterKey : mapMasterKeys)\n        {\n            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))\n                return false;\n            std::vector<unsigned char> cryptedKeyCopy = pMasterKey.second.vchCryptedKey;\n            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))\n                return false;\n\n            //fixme: (PHASE5) Remove - Temporary fix for a very small limited subset of wallets that got exposed to a password change bug.\n            //We can just leave this fix in for a while and then remove it.\n            bool unlocked = false;\n            unlocked = UnlockWithMasterKey(_vMasterKey);\n            while (!unlocked)\n            {\n                if (unlocked)\n                    break;\n                if (cryptedKeyCopy.size() < 2)\n                    break;\n                cryptedKeyCopy = std::vector<unsigned char>(cryptedKeyCopy.begin()+1, cryptedKeyCopy.end());\n                _vMasterKey.clear();\n                if (crypter.Decrypt(cryptedKeyCopy, _vMasterKey))\n                {\n                    unlocked = UnlockWithMasterKey(_vMasterKey);\n                }\n            }\n            if (unlocked)\n            {\n                int64_t nStartTime = GetTimeMillis();\n                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);\n                pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));\n\n                nStartTime = GetTimeMillis();\n                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);\n                pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;\n\n                if (pMasterKey.second.nDeriveIterations < 25000)\n                    pMasterKey.second.nDeriveIterations = 25000;\n\n                LogPrintf(\"Wallet passphrase changed to an nDeriveIterations of %i\\n\", pMasterKey.second.nDeriveIterations);\n\n                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))\n                    return false;\n                if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))\n                    return false;\n                CWalletDB(*dbw).WriteMasterKey(pMasterKey.first, pMasterKey.second);\n                if (fWasLocked)\n                    Lock();\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid CWallet::SetBestChain(const CBlockLocator& loc)\n{\n    CWalletDB walletdb(*dbw);\n    walletdb.WriteBestBlock(loc);\n}\n\nbool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)\n{\n    LOCK(cs_wallet); // nWalletVersion\n    if (nWalletVersion >= nVersion)\n        return true;\n\n    // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way\n    if (fExplicit && nVersion > nWalletMaxVersion)\n            nVersion = FEATURE_LATEST;\n\n    nWalletVersion = nVersion;\n\n    if (nVersion > nWalletMaxVersion)\n        nWalletMaxVersion = nVersion;\n\n    {\n        CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(*dbw);\n        if (nWalletVersion > 40000)\n            pwalletdb->WriteMinVersion(nWalletVersion);\n        if (!pwalletdbIn)\n            delete pwalletdb;\n    }\n\n    return true;\n}\n\nbool CWallet::SetMaxVersion(int nVersion)\n{\n    LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion\n    // cannot downgrade below current version\n    if (nWalletVersion > nVersion)\n        return false;\n\n    nWalletMaxVersion = nVersion;\n\n    return true;\n}\n\nstd::set<uint256> CWallet::GetConflicts(const uint256& txid) const\n{\n    std::set<uint256> result;\n    AssertLockHeld(cs_wallet);\n\n    std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);\n    if (it == mapWallet.end())\n        return result;\n    const CWalletTx& wtx = it->second;\n\n    std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;\n\n    for(const CTxIn& txin : wtx.tx->vin)\n    {\n        if (mapTxSpends.count(txin.GetPrevOut()) <= 1)\n            continue;  // No conflict if zero or one spends\n        range = mapTxSpends.equal_range(txin.GetPrevOut());\n        for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)\n            result.insert(_it->second);\n    }\n    return result;\n}\n\nbool CWallet::HasWalletSpend(const uint256& txid) const\n{\n    AssertLockHeld(cs_wallet);\n    auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));\n    uint256 txHash;\n    return (iter != mapTxSpends.end() && CWallet::GetTxHash(iter->first, txHash) && txHash == txid);\n}\n\nvoid CWallet::Flush(bool shutdown)\n{\n    dbw->Flush(shutdown);\n}\n\nbool CWallet::Verify()\n{\n    if (GetBoolArg(\"-disablewallet\", DEFAULT_DISABLE_WALLET))\n        return true;\n\n    uiInterface.InitMessage(_(\"Verifying wallet(s)...\"));\n\n    for (const std::string& walletFile : gArgs.GetArgs(\"-wallet\"))\n    {\n        if (boost::filesystem::path(walletFile).filename() != walletFile)\n        {\n            return InitError(_(\"-wallet parameter must only specify a filename (not a path)\"));\n        }\n        else if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile)\n        {\n            return InitError(_(\"Invalid characters in -wallet filename\"));\n        }\n\n        // Check file permissions by opening or creating file.\n        {\n            bool alreadyExists = fs::exists(GetDataDir() / walletFile);\n            {\n                std::fstream testPerms((GetDataDir() / walletFile).string(), std::ios::in | std::ios::out | std::ios::app);\n                if (!testPerms.is_open())\n                    return InitError(strprintf(_(\"%s may be read only or have permissions that deny access to the current user, please correct this and try again.\"), walletFile));\n            }\n            if (!alreadyExists)\n            {\n                fs::remove(GetDataDir() / walletFile);\n            }\n        }\n\n        std::string strError;\n        if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError))\n        {\n            return InitError(strError);\n        }\n\n        if (GetBoolArg(\"-salvagewallet\", false))\n        {\n            // Recover readable keypairs:\n            CWallet dummyWallet;\n            std::string backup_filename;\n            if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {\n                return false;\n            }\n        }\n\n        std::string strWarning;\n        bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);\n        if (!strWarning.empty())\n        {\n            InitWarning(strWarning);\n        }\n        if (!dbV)\n        {\n            InitError(strError);\n            return false;\n        }\n    }\n\n    return true;\n}\n\nvoid CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)\n{\n    // We want all the wallet transactions in range to have the same metadata as\n    // the oldest (smallest nOrderPos).\n    // So: find smallest nOrderPos:\n\n    int nMinOrderPos = std::numeric_limits<int>::max();\n    const CWalletTx* copyFrom = NULL;\n    for (TxSpends::iterator it = range.first; it != range.second; ++it)\n    {\n        const uint256& hash = it->second;\n        int n = mapWallet[hash].nOrderPos;\n        if (n < nMinOrderPos)\n        {\n            nMinOrderPos = n;\n            copyFrom = &mapWallet[hash];\n        }\n    }\n    // Now copy data from copyFrom to rest:\n    for (TxSpends::iterator it = range.first; it != range.second; ++it)\n    {\n        const uint256& hash = it->second;\n        CWalletTx* copyTo = &mapWallet[hash];\n        if (copyFrom == copyTo) continue;\n        if (!copyFrom->IsEquivalentTo(*copyTo)) continue;\n        copyTo->mapValue = copyFrom->mapValue;\n        copyTo->vOrderForm = copyFrom->vOrderForm;\n        // fTimeReceivedIsTxTime not copied on purpose\n        // nTimeReceived not copied on purpose\n        copyTo->nTimeSmart = copyFrom->nTimeSmart;\n        copyTo->fFromMe = copyFrom->fFromMe;\n        copyTo->strFromAccount = copyFrom->strFromAccount;\n        // nOrderPos not copied on purpose\n        // cached members not copied on purpose\n    }\n}\n\n/**\n * Outpoint is spent if any non-conflicted transaction\n * spends it:\n */\nbool CWallet::IsSpent(const COutPoint& outpoint) const\n{\n    std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;\n    range = mapTxSpends.equal_range(outpoint);\n\n    for (TxSpends::const_iterator it = range.first; it != range.second; ++it)\n    {\n        const uint256& wtxid = it->second;\n        std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);\n        if (mit != mapWallet.end()) {\n            int depth = mit->second.GetDepthInMainChain();\n            if ( depth > 0 )\n            {\n                return true; // Spent\n            }\n            else if ( (depth == 0 && !mit->second.isAbandoned()) )\n            {\n                if (mit->second.tx->vin.size() > 0)\n                {\n                    // Unconfirmed witness transactions never spend, otherwise we get strange display/balance issues with orphaned witness transactions.\n                    const CWalletTx* prevtx = GetWalletTx(mit->second.tx->vin[0].GetPrevOut());\n                    if (prevtx)\n                    {\n                        if (prevtx->tx->vout.size() == 0)\n                            return true;\n\n                        const auto& prevOut = prevtx->tx->vout[mit->second.tx->vin[0].GetPrevOut().n].output;\n                        if ( prevOut.nType == ScriptLegacyOutput )\n                        {\n                            return true; // Spent\n                        }\n                        else if ( prevOut.nType != PoW2WitnessOutput )\n                        {\n                            return true; // Spent\n                        }\n                    }\n                }\n                else\n                {\n                    return true; // Spent\n                }\n            }\n        }\n    }\n    return false;\n}\n\nvoid CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)\n{\n    mapTxSpends.insert(std::pair(outpoint, wtxid));\n\n    std::pair<TxSpends::iterator, TxSpends::iterator> range;\n    range = mapTxSpends.equal_range(outpoint);\n    SyncMetaData(range);\n}\n\n\nvoid CWallet::AddToSpends(const uint256& wtxid)\n{\n    assert(mapWallet.count(wtxid));\n    CWalletTx& thisTx = mapWallet[wtxid];\n    if (thisTx.IsCoinBase() && !thisTx.IsPoW2WitnessCoinBase()) // Coinbases don't spend anything!\n        return;\n\n    for(const CTxIn& txin : thisTx.tx->vin)\n    {\n        if (!txin.GetPrevOut().IsNull() || !thisTx.IsPoW2WitnessCoinBase())\n        {\n            AddToSpends(txin.GetPrevOut(), wtxid);\n        }\n    }\n}\n\nbool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)\n{\n    if (IsCrypted())\n        return false;\n\n    CKeyingMaterial _vMasterKey;\n\n    _vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);\n    GetStrongRandBytes(&_vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);\n\n    CMasterKey kMasterKey;\n\n    kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);\n    GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);\n\n    CCrypter crypter;\n    int64_t nStartTime = GetTimeMillis();\n    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);\n    kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));\n\n    nStartTime = GetTimeMillis();\n    crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);\n    kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;\n\n    if (kMasterKey.nDeriveIterations < 25000)\n        kMasterKey.nDeriveIterations = 25000;\n\n    LogPrintf(\"Encrypting Wallet with an nDeriveIterations of %i\\n\", kMasterKey.nDeriveIterations);\n\n    if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))\n        return false;\n    if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey))\n        return false;\n\n    {\n        LOCK(cs_wallet);\n        mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;\n        assert(!pwalletdbEncryption);\n        pwalletdbEncryption = new CWalletDB(*dbw);\n        if (!pwalletdbEncryption->TxnBegin()) {\n            delete pwalletdbEncryption;\n            pwalletdbEncryption = NULL;\n            return false;\n        }\n        pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);\n\n        for (const auto& [seedUUID, forSeed] : mapSeeds)\n        {\n            (unused) seedUUID;\n            if (!forSeed->Encrypt(_vMasterKey))\n            {\n                pwalletdbEncryption->TxnAbort();\n                delete pwalletdbEncryption;\n                // We now probably have half of our keys encrypted in memory, and half not...\n                // die and let the user reload the unencrypted wallet.\n                assert(false);\n            }\n            pwalletdbEncryption->WriteHDSeed(*forSeed);\n        }\n\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            if (!forAccount->Encrypt(_vMasterKey))\n            {\n                pwalletdbEncryption->TxnAbort();\n                delete pwalletdbEncryption;\n\n                // We now probably have half of our keys encrypted in memory, and half not...\n                // die and let the user reload the unencrypted wallet.\n                assert(false);\n            }\n            pwalletdbEncryption->WriteAccount(getUUIDAsString(accountUUID), forAccount);\n        }\n\n        // Encryption was introduced in version 0.4.0\n        SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);\n\n        if (!pwalletdbEncryption->TxnCommit()) {\n            delete pwalletdbEncryption;\n            // We now have keys encrypted in memory, but not on disk...\n            // die to avoid confusion and let the user reload the unencrypted wallet.\n            assert(false);\n        }\n\n        delete pwalletdbEncryption;\n        pwalletdbEncryption = NULL;\n\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            forAccount->Lock();\n        }\n        for (const auto& [seedUUID, forSeed] : mapSeeds)\n        {\n            (unused) seedUUID;\n            forSeed->Lock();\n        }\n        Unlock(strWalletPassphrase);\n\n        //fixme: (FUT) (ACCOUNTS) (HD) Munt HD - What to do here? We can't really throw the entire seed away...\n        /*\n        // if we are using HD, replace the HD master key (seed) with a new one\n        if (IsHDEnabled()) {\n            if (!SetHDMasterKey(GenerateNewHDMasterKey())) {\n                return false;\n            }\n        }\n        */\n\n        NewKeyPool();\n        Lock();\n\n        // Need to completely rewrite the wallet file; if we don't, bdb might keep\n        // bits of the unencrypted private key in slack space in the database file.\n        dbw->Rewrite();\n\n    }\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        forAccount->internalKeyStore.NotifyStatusChanged(&forAccount->internalKeyStore);\n        forAccount->externalKeyStore.NotifyStatusChanged(&forAccount->externalKeyStore);\n    }\n\n    return true;\n}\n\nDBErrors CWallet::ReorderTransactions()\n{\n    LOCK(cs_wallet);\n    CWalletDB walletdb(*dbw);\n\n    // Old wallets didn't have any defined order for transactions\n    // Probably a bad idea to change the output of this\n\n    // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.\n    typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;\n    typedef std::multimap<int64_t, TxPair > TxItems;\n    TxItems txByTime;\n\n    for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n    {\n        CWalletTx* wtx = &((*it).second);\n        txByTime.insert(std::pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));\n    }\n    std::list<CAccountingEntry> acentries;\n    walletdb.ListAccountCreditDebit(\"\", acentries);\n    for(CAccountingEntry& entry : acentries)\n    {\n        txByTime.insert(std::pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));\n    }\n\n    nOrderPosNext = 0;\n    std::vector<int64_t> nOrderPosOffsets;\n    for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)\n    {\n        CWalletTx *const pwtx = (*it).second.first;\n        CAccountingEntry *const pacentry = (*it).second.second;\n        int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;\n\n        if (nOrderPos == -1)\n        {\n            nOrderPos = nOrderPosNext++;\n            nOrderPosOffsets.push_back(nOrderPos);\n\n            if (pwtx)\n            {\n                if (!walletdb.WriteTx(*pwtx))\n                    return DB_LOAD_FAIL;\n            }\n            else\n                if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))\n                    return DB_LOAD_FAIL;\n        }\n        else\n        {\n            int64_t nOrderPosOff = 0;\n            for(const int64_t& nOffsetStart : nOrderPosOffsets)\n            {\n                if (nOrderPos >= nOffsetStart)\n                    ++nOrderPosOff;\n            }\n            nOrderPos += nOrderPosOff;\n            nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);\n\n            if (!nOrderPosOff)\n                continue;\n\n            // Since we're changing the order, write it back\n            if (pwtx)\n            {\n                if (!walletdb.WriteTx(*pwtx))\n                    return DB_LOAD_FAIL;\n            }\n            else\n                if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry))\n                    return DB_LOAD_FAIL;\n        }\n    }\n    walletdb.WriteOrderPosNext(nOrderPosNext);\n\n    return DB_LOAD_OK;\n}\n\nint64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)\n{\n    AssertLockHeld(cs_wallet); // nOrderPosNext\n    int64_t nRet = nOrderPosNext++;\n    if (pwalletdb) {\n        pwalletdb->WriteOrderPosNext(nOrderPosNext);\n    } else {\n        CWalletDB(*dbw).WriteOrderPosNext(nOrderPosNext);\n    }\n    return nRet;\n}\n\nbool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment)\n{\n    //fixme: (FUT) (REFACTOR) (ACCOUNTS)\n    //This should never be called.\n    assert(0);\n    return true;\n}\n\nbool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew)\n{\n    //fixme: (FUT) (REFACTOR) (ACCOUNTS)\n    //This should never be called.\n    assert(0);\n    return true;\n}\n\nvoid CWallet::MarkDirty()\n{\n    {\n        LOCK(cs_wallet);\n        for(PAIRTYPE(const uint256, CWalletTx)& item : mapWallet)\n            item.second.MarkDirty();\n    }\n}\n\nbool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)\n{\n    LOCK(cs_wallet);\n\n    auto mi = mapWallet.find(originalHash);\n\n    // There is a bug if MarkReplaced is not called on an existing wallet transaction.\n    assert(mi != mapWallet.end());\n\n    CWalletTx& wtx = (*mi).second;\n\n    wtx.MarkDirty();\n\n    // Ensure for now that we're not overwriting data\n    if (wtx.mapValue.count(\"replaced_by_txid\") != 0)\n        return false;\n\n    wtx.mapValue[\"replaced_by_txid\"] = newHash.ToString();\n\n    CWalletDB walletdb(*dbw, \"r+\");\n\n    bool success = true;\n    if (!walletdb.WriteTx(wtx)) {\n        LogPrintf(\"%s: Updating walletdb tx %s failed\", __func__, wtx.GetHash().ToString());\n        success = false;\n    }\n\n    NotifyTransactionChanged(this, originalHash, CT_UPDATED, false);\n\n    return success;\n}\n\nbool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose, bool fSelfComitted)\n{\n    LOCK(cs_wallet);\n\n    CWalletDB walletdb(*dbw, \"r+\", fFlushOnClose);\n\n    uint256 hash = wtxIn.GetHash();\n    // Refuse to add a null hash to the wallet, as this flags the wallet as corrupted on restart\n    if (hash.IsNull())\n        return false;\n    maintainHashMap(wtxIn, hash);\n\n    // Inserts only if not already there, returns tx inserted or tx found\n    std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::pair(hash, wtxIn));\n    CWalletTx& wtx = (*ret.first).second;\n    if (wtx.strFromAccount.empty())\n    {\n        LOCK(cs_wallet);\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            if (forAccount->HaveWalletTx(wtx))\n            {\n                wtx.strFromAccount = getUUIDAsString(accountUUID);\n            }\n        }\n    }\n    wtx.BindWallet(this);\n    bool fInsertedNew = ret.second;\n    if (fInsertedNew)\n    {\n        wtx.nTimeReceived = GetAdjustedTime();\n        wtx.nOrderPos = IncOrderPosNext(&walletdb);\n        wtxOrdered.insert(std::pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));\n        wtx.nTimeSmart = ComputeTimeSmart(wtx);\n        AddToSpends(hash);\n    }\n\n    bool fUpdated = false;\n    if (!fInsertedNew)\n    {\n        // Merge\n        if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)\n        {\n            wtx.hashBlock = wtxIn.hashBlock;\n            wtx.nHeight = wtxIn.nHeight;\n            wtx.nBlockTime = wtxIn.nBlockTime;\n            fUpdated = true;\n        }\n        // If no longer abandoned, update\n        if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())\n        {\n            wtx.hashBlock = wtxIn.hashBlock;\n            wtx.nHeight = wtxIn.nHeight;\n            wtx.nBlockTime = wtxIn.nBlockTime;\n            fUpdated = true;\n        }\n        // If height changed, update\n        if (wtxIn.nHeight != -1 && (wtxIn.nHeight != wtx.nHeight))\n        {\n            wtx.nHeight = wtxIn.nHeight;\n            fUpdated = true;\n        }\n        // If block time changed, update\n        if (wtxIn.nBlockTime != 0 && (wtxIn.nBlockTime != wtx.nBlockTime))\n        {\n            wtx.nBlockTime = wtxIn.nBlockTime;\n            fUpdated = true;\n        }\n        // If index changed, update\n        if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex))\n        {\n            wtx.nIndex = wtxIn.nIndex;\n            fUpdated = true;\n        }\n        if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)\n        {\n            wtx.fFromMe = wtxIn.fFromMe;\n            fUpdated = true;\n        }\n    }\n\n    //// debug print\n    LogPrintf(\"AddToWallet %s  %s%s\\n\", wtxIn.GetHash().ToString(), (fInsertedNew ? \"new\" : \"\"), (fUpdated ? \"update\" : \"\"));\n\n    // Write to disk\n    if (fInsertedNew || fUpdated)\n        if (!walletdb.WriteTx(wtx))\n            return false;\n\n    // Break debit/credit balance caches:\n    wtx.MarkDirty();\n\n    // Notify UI of new or updated transaction\n    NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED, fSelfComitted);\n\n    // notify an external script when a wallet transaction comes in or is updated\n    std::string strCmd = GetArg(\"-walletnotify\", \"\");\n\n    if ( !strCmd.empty())\n    {\n        boost::replace_all(strCmd, \"%s\", wtxIn.GetHash().GetHex());\n        std::thread(runCommand, strCmd).detach();\n    }\n\n    return true;\n}\n\nvoid CWallet::maintainHashMap(const CWalletTx& wtxIn, uint256& hash)\n{\n    //if (mapWallet.size() > 0 && mapWalletHash.empty())\n    if (wtxIn.nHeight > 0)\n    {\n        for (unsigned int i = 0; i < wtxIn.tx->vout.size(); i++)\n        {\n            mapWalletHash[COutPoint(wtxIn.nHeight, wtxIn.nIndex, i).getBucketHash()] = hash;\n        }\n    }\n}\n\nbool CWallet::LoadToWallet(const CWalletTx& wtxIn)\n{\n    uint256 hash = wtxIn.GetHash();\n\n    maintainHashMap(wtxIn, hash);\n    mapWallet[hash] = wtxIn;\n    \n    CWalletTx& wtx = mapWallet[hash];\n    wtx.BindWallet(this);\n    wtxOrdered.insert(std::pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));\n    AddToSpends(hash);\n\n    return true;\n}\n\nvoid CWallet::HandleTransactionsLoaded()\n{\n    for  (const auto& [hash, wtx] : mapWallet)\n    {\n        (unused) hash;\n        for (const CTxIn& txin : wtx.tx->vin)\n        {\n            const CWalletTx* prevtx = GetWalletTx(txin.GetPrevOut());\n            if (prevtx)\n            {\n                if (prevtx->nIndex == -1 && !prevtx->hashUnset())\n                {\n                    MarkConflicted(prevtx->hashBlock, wtx.GetHash());\n                }\n            }\n        }\n    }\n}\n\nvoid CWallet::ClearCacheForTransaction(const uint256& hash)\n{\n    auto& wtx = mapWallet[hash];\n    // Invalidate all caches for transaction as they will need to be recalculated.\n    // Otherwise we get incorrect wallet balance displays.\n    wtx.MarkDirty();\n}\n\n/**\n * Add a transaction to the wallet, or update it.  pIndex and posInBlock should\n * be set when the transaction was known to be included in a block.  When\n * pIndex == NULL, then wallet state is not updated in AddToWallet, but\n * notifications happen and cached balances are marked dirty.\n *\n * If fUpdate is true, existing transactions will be updated.\n * TODO: One exception to this is that the abandoned state is cleared under the\n * assumption that any further notification of a transaction that was considered\n * abandoned is an indication that it is not safe to be considered abandoned.\n * Abandoned state should probably be more carefully tracked via different\n * posInBlock signals or by checking mempool presence when necessary.\n */\nbool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)\n{\n    const CTransaction& tx = *ptx;\n    {\n        AssertLockHeld(cs_wallet);\n\n        std::vector<std::pair<uint256, uint256>> markReplacements;\n        if (pIndex != NULL)\n        {\n            for(const CTxIn& txin : tx.vin)\n            {\n                std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.GetPrevOut());\n                while (range.first != range.second)\n                {\n                    if (range.first->second != tx.GetHash())\n                    {\n                        uint256 txHash;\n                        CWallet::GetTxHash(range.first->first, txHash);\n                        LogPrintf(\"Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\\n\", tx.GetHash().ToString(), pIndex->GetBlockHashPoW2().ToString(), range.first->second.ToString(), txHash.ToString(), range.first->first.n);\n                        MarkConflicted(pIndex->GetBlockHashPoW2(), range.first->second);\n                    }\n                    range.first++;\n                }\n            }\n        }\n\n        bool fExisted = mapWallet.count(tx.GetHash()) != 0;\n        // Wipe cache from all transactions that possibly involve this one.\n        if (fExisted)\n            ClearCacheForTransaction(tx.GetHash());\n        for(const auto& txin : tx.vin)\n        {\n            const CWalletTx* wtx = GetWalletTx(txin.GetPrevOut());\n            if (wtx)\n                ClearCacheForTransaction(wtx->GetHash());\n        }\n        if (fExisted && !fUpdate) return false;\n        if (fExisted || IsMine(tx) || IsFromMe(tx))\n        {\n            CWalletTx wtx(this, ptx);\n\n            // Get merkle branch if transaction was found in a block\n            if (pIndex != NULL)\n                wtx.SetMerkleBranch(pIndex, posInBlock);\n\n            RemoveAddressFromKeypoolIfIsMine(tx, pIndex ? pIndex->nTime : 0);\n            for(const auto& txin : wtx.tx->vin)\n            {\n                RemoveAddressFromKeypoolIfIsMine(txin, pIndex ? pIndex->nTime : 0);\n            }\n\n            bool ret = AddToWallet(wtx, false);\n            //NB! We delibritely do this from here and not inside AddToWallet, because we sometimes add transactions that are not ours via AddToWallet (e.g. see lower down in this function where we add the incoming transactions)\n            GetMainSignals().WalletTransactionAdded(this, wtx);\n\n            // Update account state\n            //fixme: (PHASE5) - More efficient way to do this?\n            // If this is the first unconfirmed witness transaction a witness account is receiving then update the state to \"pending\" in the UI.\n            // If it has a confirm then update to \"locked\"\n            if (pactiveWallet)\n            {\n                for (const auto& txOut : wtx.tx->vout)\n                {\n                    if (txOut.GetType() == CTxOutType::PoW2WitnessOutput)\n                    {\n                        CAccount* potentialWitnessAccount = pactiveWallet->FindBestWitnessAccountForTransaction(txOut);\n                        if (potentialWitnessAccount && potentialWitnessAccount->m_Type == AccountType::PoW2Witness)\n                        {\n                            if (potentialWitnessAccount->GetWarningState() == AccountStatus::WitnessEmpty || potentialWitnessAccount->GetWarningState() == AccountStatus::WitnessPending)\n                            {\n                                potentialWitnessAccount->SetWarningState(pIndex ? AccountStatus::Default : AccountStatus::WitnessPending);\n                                static_cast<const CExtWallet*>(pactiveWallet)->NotifyAccountWarningChanged(pactiveWallet, potentialWitnessAccount);\n                                // Set active so that witness account gains the focus immediately after funding.\n                                if (!pIndex) {\n                                    CWalletDB walletdb(*pactiveWallet->dbw);\n                                    pactiveWallet->setActiveAccount(walletdb, potentialWitnessAccount);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            for (const auto& [wtx, newTx] : markReplacements)\n            {\n                MarkReplaced(wtx, newTx);\n            }\n\n            //fixme: (Future) This is slow and should be made faster.\n            //Add all incoming transactions to the wallet as well (even though they aren't from us necessarily) - so that we can always get 'incoming' address details.\n            //Is there maybe a better way to do this?\n            //\n            //Note the below has large speed implications - if we do need this it would be better to maybe just serialise the \"from address\" as part of CWalletTx and not keep additional transactions (that aren't ours) around.\n            //GetTransaction() is expensive and locks on mutexes that intefere with other parts of the code.\n            for(const auto& txin : tx.vin)\n            {\n                uint256 txHash;\n                if (CWallet::GetTxHash(txin.GetPrevOut(), txHash))\n                {\n                    bool fExistedIncoming = mapWallet.count(txHash) != 0;\n                    if (!fExistedIncoming)\n                    {\n                        uint256 hashBlock = uint256();\n                        if (GetTransaction(txHash, wtx.tx, Params(), hashBlock, true))\n                        {\n                            AddToWallet(wtx, false);\n                        }\n                    }\n                }\n            }\n            return ret;\n        }\n    }\n    return false;\n}\n\nbool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const\n{\n    LOCK2(cs_main, cs_wallet);\n    const CWalletTx* wtx = GetWalletTx(hashTx);\n    return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() <= 0 && !wtx->InMempool();\n}\n\nbool CWallet::AbandonTransaction(const uint256& hashTx)\n{\n    LOCK2(cs_main, cs_wallet);\n\n    CWalletDB walletdb(*dbw, \"r+\");\n\n    std::set<uint256> todo;\n    std::set<uint256> done;\n\n    // Can't mark abandoned if confirmed or in mempool\n    assert(mapWallet.count(hashTx));\n    CWalletTx& origtx = mapWallet[hashTx];\n    if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {\n        return false;\n    }\n\n    todo.insert(hashTx);\n\n    while (!todo.empty()) {\n        uint256 now = *todo.begin();\n        todo.erase(now);\n        done.insert(now);\n        assert(mapWallet.count(now));\n        CWalletTx& wtx = mapWallet[now];\n        int currentconfirm = wtx.GetDepthInMainChain();\n        // If the orig tx was not in block, none of its spends can be\n        assert(currentconfirm <= 0);\n        // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}\n        if (currentconfirm == 0 && !wtx.isAbandoned()) {\n            // If the orig tx was not in block/mempool, none of its spends can be in mempool\n            assert(!wtx.InMempool());\n            wtx.nIndex = -1;\n            wtx.setAbandoned();\n            wtx.MarkDirty();\n            walletdb.WriteTx(wtx);\n            NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED, false);\n            // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too\n            TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));\n            while (iter != mapTxSpends.end()) {\n                uint256 txHash;\n                if (!CWallet::GetTxHash(iter->first, txHash) || txHash != now)\n                    break;\n                if (!done.count(iter->second)) {\n                    todo.insert(iter->second);\n                }\n                iter++;\n            }\n            // If a transaction changes 'conflicted' state, that changes the balance\n            // available of the outputs it spends. So force those to be recomputed\n            for(const CTxIn& txin : wtx.tx->vin)\n            {\n                CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n                if (prev)\n                    prev->MarkDirty();\n            }\n        }\n    }\n\n    return true;\n}\n\nstatic void forceRestart()\n{\n    LogPrintf(\"shutdown: 'forceRestart' function triggered\");\n\n    // Immediately disable what we can so this is cleaner.\n    if (g_connman)\n    {\n        g_connman->SetNetworkActive(false);\n    }\n    fullyEraseDatadirOnShutdown=true;\n    \n    // Event loop will exit after current HTTP requests have been handled, so\n    // this reply will get back to the client.\n    AppLifecycleManager::gApp->shutdown();\n}\n\nvoid CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)\n{\n    LOCK2(cs_main, cs_wallet);\n\n    int conflictconfirms = 0;\n    if (mapBlockIndex.count(hashBlock))\n    {\n        CBlockIndex* pindex = mapBlockIndex[hashBlock];\n        if (partialChain.Contains(pindex) || chainActive.Contains(pindex))\n        {\n            conflictconfirms = -(std::max(partialChain.Height(), chainActive.Height()) - pindex->nHeight + 1);\n        }\n    }\n    // If number of conflict confirms cannot be determined, this means\n    // that the block is still unknown or not yet part of the main chain,\n    // for example when loading the wallet during a reindex. Do nothing in that\n    // case.\n    if (conflictconfirms >= 0)\n        return;\n\n    // Do not flush the wallet here for performance reasons\n    CWalletDB walletdb(*dbw, \"r+\", false);\n\n    std::set<uint256> todo;\n    std::set<uint256> done;\n\n    todo.insert(hashTx);\n\n    while (!todo.empty())\n    {\n        uint256 now = *todo.begin();\n        todo.erase(now);\n        done.insert(now);\n        auto it = mapWallet.find(now);\n        if (fSPV)\n        {\n            if (it == mapWallet.end())\n            {\n                forceRestart();\n                return;\n            }\n        }\n        else\n        {\n            assert(it != mapWallet.end());\n        }\n        CWalletTx& wtx = it->second;\n        int currentconfirm = wtx.GetDepthInMainChain();\n        if (conflictconfirms < currentconfirm || (conflictconfirms == currentconfirm && wtx.nIndex >= 0))\n        {\n            // Block is 'more conflicted' than current confirm; update. Or tx not marked as conflicted yet.\n            // Mark transaction as conflicted with this block.\n            wtx.nIndex = -1;\n            wtx.hashBlock = hashBlock;\n            wtx.MarkDirty();\n            walletdb.WriteTx(wtx);\n            // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too\n            TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));\n            while (iter != mapTxSpends.end())\n            {\n                uint256 txHash;\n                if (!CWallet::GetTxHash(iter->first, txHash) || txHash != now)\n                    break;\n                 if (!done.count(iter->second))\n                 {\n                     todo.insert(iter->second);\n                 }\n                 iter++;\n            }\n            // If a transaction changes 'conflicted' state, that changes the balance\n            // available of the outputs it spends. So force those to be recomputed\n            for (const CTxIn& txin : wtx.tx->vin)\n            {\n                CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n                if (prev)\n                    prev->MarkDirty();\n            }\n        }\n    }\n}\n\nvoid CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock) {\n    const CTransaction& tx = *ptx;\n\n    if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, true))\n        return; // Not one of ours\n\n    // If a transaction changes 'conflicted' state, that changes the balance\n    // available of the outputs it spends. So force those to be\n    // recomputed, also:\n    for(const CTxIn& txin : tx.vin)\n    {\n        CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n        if (prev)\n            prev->MarkDirty();\n    }\n}\n\nvoid CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {\n    LOCK2(cs_main, cs_wallet);\n    SyncTransaction(ptx);\n}\n\nvoid CWallet::TransactionRemovedFromMempool(const uint256& hash, MemPoolRemovalReason reason)\n{\n    LOCK2(cs_main, cs_wallet);\n\n    if (!isFullSyncMode() && IsPartialSyncActive() && MemPoolRemovalReason::EXPIRY == reason) {\n        const auto& it = mapWallet.find(hash);\n        if (it != mapWallet.end()) {\n            if (TransactionCanBeAbandoned(hash))\n                AbandonTransaction(hash);\n        }\n    }\n}\n\nvoid CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {\n    LOCK2(cs_main, cs_wallet);\n    // TODO: Temporarily ensure that mempool removals are notified before\n    // connected transactions.  This shouldn't matter, but the abandoned\n    // state of transactions in our wallet is currently cleared when we\n    // receive another notification and there is a race condition where\n    // notification of a connected conflict might cause an outside process\n    // to abandon a transaction and then have it inadvertently cleared by\n    // the notification that the conflicted transaction was evicted.\n\n    for (const CTransactionRef& ptx : vtxConflicted) {\n        SyncTransaction(ptx);\n    }\n    for (size_t i = 0; i < pblock->vtx.size(); i++) {\n        SyncTransaction(pblock->vtx[i], pindex, i);\n    }\n\n    static int lastReportedDepthChangeHeight = 0;\n    CChain& chain = IsPartialSyncActive() && partialChain.Height() > chainActive.Height() ? partialChain : chainActive;\n    if (chain.Height() != lastReportedDepthChangeHeight) {\n        lastReportedDepthChangeHeight = chain.Height();\n        for(const auto& [hash, wtx] : mapWallet)\n        {\n            int nDepth = wtx.GetDepthInMainChain();\n            if (nDepth > 0 && nDepth < 10)\n            {\n                NotifyTransactionDepthChanged(this, hash);\n            }\n        }\n    }\n}\n\nvoid CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {\n    LOCK2(cs_main, cs_wallet);\n\n    for (const CTransactionRef& ptx : pblock->vtx) {\n        SyncTransaction(ptx);\n    }\n}\n\nvoid CWallet::PruningConflictingBlock(const uint256& orphanBlockHash)\n{\n    LOCK2(cs_main, cs_wallet);\n\n    if (!mapBlockIndex.count(orphanBlockHash))\n        return;\n\n    CBlockIndex* pIndex = mapBlockIndex[orphanBlockHash];\n\n    if (pIndex->nHeight < partialChain.HeightOffset() || pIndex->nHeight >partialChain.Height())\n        return;\n\n    CBlock block;\n    if (!ReadBlockFromDisk(block, pIndex, Params())) {\n        LogPrintf(\"%s: Error reading block height=%d hash=%s\\n\", __func__, pIndex->nHeight, pIndex->GetBlockHashPoW2().ToString().c_str());\n        return;\n    }\n\n    for (const CTransactionRef& ptx : block.vtx) {\n        MarkConflicted(partialChain[pIndex->nHeight]->GetBlockHashPoW2(), ptx->GetHash());\n    }\n}\n\nbool CWallet::IsChange(const CTxOut& txout) const\n{\n    LOCK(cs_wallet);\n\n    if (::IsMine(*this, txout))\n    {\n        CTxDestination address;\n        if (!ExtractDestination(txout, address))\n            return true;\n\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (::IsMine(forAccount->internalKeyStore, address) > ISMINE_NO)\n                return true;\n        }\n    }\n\n    return false;\n}\n\nvoid CWallet::ReacceptWalletTransactions()\n{\n    // If transactions aren't being broadcasted, don't let them into local mempool either\n    if (!fBroadcastTransactions)\n        return;\n    LOCK2(cs_main, cs_wallet);\n    std::map<int64_t, CWalletTx*> mapSorted;\n\n    // Sort pending wallet transactions based on their initial wallet insertion order\n    for(PAIRTYPE(const uint256, CWalletTx)& item : mapWallet)\n    {\n        const uint256& wtxid = item.first;\n        CWalletTx& wtx = item.second;\n        assert(wtx.GetHash() == wtxid);\n\n        int nDepth = wtx.GetDepthInMainChain();\n\n        if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {\n            mapSorted.insert(std::pair(wtx.nOrderPos, &wtx));\n        }\n    }\n\n    // Try to add wallet transactions to memory pool\n    for(PAIRTYPE(const int64_t, CWalletTx*)& item : mapSorted)\n    {\n        CWalletTx& wtx = *(item.second);\n\n        LOCK(mempool.cs);\n        CValidationState state;\n        wtx.AcceptToMemoryPool(maxTxFee, state);\n    }\n}\n\nbool CWalletTx::RelayWalletTransaction(CConnman* connman)\n{\n    assert(pwallet->GetBroadcastTransactions());\n    if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)\n    {\n        CValidationState state;\n        /* GetDepthInMainChain already catches known conflicts. */\n        if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) {\n            LogPrintf(\"Relaying wtx %s\\n\", GetHash().ToString());\n            if (connman) {\n                CInv inv(MSG_TX, GetHash());\n                connman->ForEachNode([&inv](CNode* pnode)\n                {\n                    pnode->PushInventory(inv);\n                });\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nstd::set<uint256> CWalletTx::GetConflicts() const\n{\n    std::set<uint256> result;\n    if (pwallet != NULL)\n    {\n        uint256 myHash = GetHash();\n        result = pwallet->GetConflicts(myHash);\n        result.erase(myHash);\n    }\n    return result;\n}\n\nbool CWalletTx::InMempool() const\n{\n    LOCK(mempool.cs);\n    return mempool.exists(GetHash());\n}\n\nbool CWalletTx::IsTrusted() const\n{\n    // Quick answer in most cases\n    if (!CheckFinalTx(*this, IsPartialSyncActive() ? partialChain : chainActive))\n        return false;\n    int nDepth = GetDepthInMainChain();\n    if (nDepth >= 1)\n        return true;\n    if (nDepth < 0)\n        return false;\n    if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit\n        return false;\n\n    // Don't trust unconfirmed transactions from us unless they are in the mempool.\n    if (!InMempool())\n        return false;\n\n    // Trusted if all inputs are from us and are in the mempool:\n    for(const CTxIn& txin : tx->vin)\n    {\n        // Transactions not sent by us: not trusted\n        const CWalletTx* parent = pwallet->GetWalletTx(txin.GetPrevOut());\n        if (parent == NULL || parent->tx->vout.size() == 0)\n            return false;\n        const CTxOut& parentOut = parent->tx->vout[txin.GetPrevOut().n];\n        if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)\n            return false;\n    }\n    return true;\n}\n\nbool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const\n{\n        CMutableTransaction tx1 = *this->tx;\n        CMutableTransaction tx2 = *_tx.tx;\n        for (auto& txin : tx1.vin) txin.scriptSig = CScript();\n        for (auto& txin : tx2.vin) txin.scriptSig = CScript();\n        return CTransaction(tx1) == CTransaction(tx2);\n}\n\nstd::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)\n{\n    std::vector<uint256> result;\n\n    LOCK(cs_wallet);\n    // Sort them in chronological order\n    std::multimap<unsigned int, CWalletTx*> mapSorted;\n    for(PAIRTYPE(const uint256, CWalletTx)& item : mapWallet)\n    {\n        CWalletTx& wtx = item.second;\n        // Don't rebroadcast if newer than nTime:\n        if (wtx.nTimeReceived > nTime)\n            continue;\n        mapSorted.insert(std::pair(wtx.nTimeReceived, &wtx));\n    }\n    for(PAIRTYPE(const unsigned int, CWalletTx*)& item : mapSorted)\n    {\n        CWalletTx& wtx = *item.second;\n        if (wtx.RelayWalletTransaction(connman))\n            result.push_back(wtx.GetHash());\n    }\n    return result;\n}\n\nvoid CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)\n{\n    // Do this infrequently and randomly to avoid giving away\n    // that these are our transactions.\n    if (GetTime() < nNextResend || !fBroadcastTransactions)\n        return;\n    bool fFirst = (nNextResend == 0);\n    nNextResend = GetTime() + GetRand(30 * 60);\n    if (fFirst)\n        return;\n\n    // Only do it if there's been a new block since last time\n    if (nBestBlockTime < nLastResend)\n        return;\n    nLastResend = GetTime();\n\n    // Rebroadcast unconfirmed txes older than 5 minutes before the last\n    // block was found:\n    std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);\n    if (!relayed.empty())\n        LogPrintf(\"%s: rebroadcast %u unconfirmed transactions\\n\", __func__, relayed.size());\n}\n\n/** @} */ // end of mapWallet\n\n\n\n\n/** @defgroup Actions\n *\n * @{\n */\n\nextern bool IsMine(const CKeyStore* forAccount, const CWalletTx& tx);\n\n\nvoid CWallet::AvailableCoins(CAccount* forAccount, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth) const\n{\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(forAccount);\n    return AvailableCoins(accountsToTry, vCoins, fOnlySafe, coinControl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);\n}\n\nvoid CWallet::AvailableCoins(std::vector<CKeyStore*>& accountsToTry, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth) const\n{\n    vCoins.clear();\n\n    {\n        LOCK2(cs_main, cs_wallet);\n\n        CAmount nTotal = 0;\n\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const uint256& wtxid = it->first;\n            const CWalletTx* pcoin = &(*it).second;\n\n            bool isMineAny=false;\n            for (const auto& forAccount : accountsToTry)\n            {\n                if (::IsMine(forAccount, *pcoin))\n                {\n                    isMineAny = true;\n                }\n            }\n            if (!isMineAny)\n                continue;\n\n            if (!CheckFinalTx(*pcoin, IsPartialSyncActive() ? partialChain : chainActive))\n                continue;\n\n            if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->nTimeSmart != Params().GenesisBlock().nTime)\n                continue;\n\n            int nDepth = pcoin->GetDepthInMainChain();\n            if (nDepth < 0)\n                continue;\n\n            // We should not consider coins which aren't at least in our mempool\n            // It's possible for these to be conflicted via ancestors which we may never be able to detect\n            if (nDepth == 0 && !pcoin->InMempool())\n                continue;\n\n            bool safeTx = pcoin->IsTrusted();\n\n            // We should not consider coins from transactions that are replacing\n            // other transactions.\n            //\n            // Example: There is a transaction A which is replaced by bumpfee\n            // transaction B. In this case, we want to prevent creation of\n            // a transaction B' which spends an output of B.\n            //\n            // Reason: If transaction A were initially confirmed, transactions B\n            // and B' would no longer be valid, so the user would have to create\n            // a new transaction C to replace B'. However, in the case of a\n            // one-block reorg, transactions B' and C might BOTH be accepted,\n            // when the user only wanted one of them. Specifically, there could\n            // be a 1-block reorg away from the chain where transactions A and C\n            // were accepted to another chain where B, B', and C were all\n            // accepted.\n            if (nDepth == 0 && pcoin->mapValue.count(\"replaces_txid\")) {\n                safeTx = false;\n            }\n\n            // Similarly, we should not consider coins from transactions that\n            // have been replaced. In the example above, we would want to prevent\n            // creation of a transaction A' spending an output of A, because if\n            // transaction B were initially confirmed, conflicting with A and\n            // A', we wouldn't want to the user to create a transaction D\n            // intending to replace A', but potentially resulting in a scenario\n            // where A, A', and D could all be accepted (instead of just B and\n            // D, or just A and A' like the user would want).\n            if (nDepth == 0 && pcoin->mapValue.count(\"replaced_by_txid\")) {\n                safeTx = false;\n            }\n\n            if (fOnlySafe && !safeTx) {\n                continue;\n            }\n\n            if (nDepth < nMinDepth || nDepth > nMaxDepth)\n                continue;\n\n            for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {\n                // If coin is a witness transaction output that is currently locked (current tip) then the coin is not available for spending.\n                if (IsPoW2WitnessLocked(pcoin->tx->vout[i], (uint64_t)chainActive.Tip()->nHeight))\n                    continue;\n\n                if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)\n                    continue;\n\n                if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint((*it).first, i)))\n                    continue;\n\n                if (IsLockedCoin((*it).first, i))\n                    continue;\n\n                if (IsSpent(COutPoint(wtxid, i)) || IsSpent(COutPoint(pcoin->nHeight, pcoin->nIndex, i)))\n                    continue;\n\n                isminetype mine = ISMINE_NO;\n                for (const auto& forAccount : accountsToTry)\n                {\n                    isminetype temp = ::IsMine(*forAccount, pcoin->tx->vout[i]);\n                    if (mine < temp)\n                        mine = temp;\n                }\n\n                if (mine == ISMINE_NO) {\n                    continue;\n                }\n\n                bool fSpendableIn = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO);\n                bool fSolvableIn = (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO;\n\n                vCoins.push_back(COutput(pcoin, i, nDepth, fSpendableIn, fSolvableIn, safeTx));\n\n                // Checks the sum amount of all UTXO's.\n                if (nMinimumSumAmount != MAX_MONEY) {\n                    nTotal += pcoin->tx->vout[i].nValue;\n\n                    if (nTotal >= nMinimumSumAmount) {\n                        return;\n                    }\n                }\n\n                // Checks the maximum number of UTXO's.\n                if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) {\n                    return;\n                }\n            }\n        }\n    }\n}\n\nstd::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(CAccount* forAccount) const\n{\n    // TODO: Add AssertLockHeld(cs_wallet) here.\n    //\n    // Because the return value from this function contains pointers to\n    // CWalletTx objects, callers to this function really should acquire the\n    // cs_wallet lock before calling it. However, the current caller doesn't\n    // acquire this lock yet. There was an attempt to add the missing lock in\n    // https://github.com/bitcoin/bitcoin/pull/10340, but that change has been\n    // postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to\n    // avoid adding some extra complexity to the Qt code.\n\n    std::map<CTxDestination, std::vector<COutput>> result;\n\n    std::vector<COutput> availableCoins;\n    AvailableCoins(forAccount, availableCoins);\n\n    LOCK2(cs_main, cs_wallet);\n    for (auto& coin : availableCoins)\n    {\n        CTxDestination address;\n        if (coin.fSpendable && ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i), address))\n        {\n            result[address].emplace_back(std::move(coin));\n        }\n    }\n\n    std::vector<COutPoint> lockedCoins;\n    ListLockedCoins(lockedCoins);\n    for (const auto& output : lockedCoins)\n    {\n        CWalletTx* wtx = GetWalletTx(output);\n        if (wtx)\n        {\n            int depth = wtx->GetDepthInMainChain();\n            if (depth >= 0 && output.n < wtx->tx->vout.size() && IsMine(wtx->tx->vout[output.n]) == ISMINE_SPENDABLE)\n            {\n                CTxDestination address;\n                if (ExtractDestination(FindNonChangeParentOutput(*wtx->tx, output.n), address))\n                {\n                    bool isSpendable = true;\n                    bool isSolvable = true;\n                    bool isSafe = false;\n                    result[address].emplace_back(wtx, output.n, depth, isSpendable, isSolvable, isSafe);\n                }\n            }\n        }\n    }\n\n    return result;\n}\n\nconst CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int output) const\n{\n    const CTransaction* ptx = &tx;\n    int n = output;\n    while (IsChange(ptx->vout[n]) && ptx->vin.size() > 0)\n    {\n        const COutPoint& prevout = ptx->vin[0].GetPrevOut();\n        CWalletTx* prev = GetWalletTx(prevout);\n        if (!prev || prev->tx->vout.size() <= prevout.n || !IsMine(prev->tx->vout[prevout.n]))\n        {\n            break;\n        }\n        ptx = prev->tx.get();\n        n = prevout.n;\n    }\n    return ptx->vout[n];\n}\n\nstatic void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,\n                                  std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)\n{\n    std::vector<char> vfIncluded;\n\n    vfBest.assign(vValue.size(), true);\n    nBest = nTotalLower;\n\n    FastRandomContext insecure_rand;\n\n    for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)\n    {\n        vfIncluded.assign(vValue.size(), false);\n        CAmount nTotal = 0;\n        bool fReachedTarget = false;\n        for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)\n        {\n            for (unsigned int i = 0; i < vValue.size(); i++)\n            {\n                //The solver here uses a randomized algorithm,\n                //the randomness serves no real security purpose but is just\n                //needed to prevent degenerate behavior and it is important\n                //that the rng is fast. We do not use a constant random sequence,\n                //because there may be some privacy improvement by making\n                //the selection random.\n                if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i])\n                {\n                    nTotal += vValue[i].txout.nValue;\n                    vfIncluded[i] = true;\n                    if (nTotal >= nTargetValue)\n                    {\n                        fReachedTarget = true;\n                        if (nTotal < nBest)\n                        {\n                            nBest = nTotal;\n                            vfBest = vfIncluded;\n                        }\n                        nTotal -= vValue[i].txout.nValue;\n                        vfIncluded[i] = false;\n                    }\n                }\n            }\n        }\n    }\n}\n\nbool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins,\n                                 std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, bool allowIndexBased) const\n{\n    setCoinsRet.clear();\n    nValueRet = 0;\n\n    // List of values less than target\n    boost::optional<CInputCoin> coinLowestLarger;\n    std::vector<CInputCoin> vValue;\n    CAmount nTotalLower = 0;\n\n    std::random_device rng;\n    std::mt19937 urng(rng());\n    std::shuffle(vCoins.begin(), vCoins.end(), urng);\n\n    for(const COutput &output : vCoins)\n    {\n        if (!output.fSpendable)\n            continue;\n\n        const CWalletTx *pcoin = output.tx;\n\n        if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))\n            continue;\n\n        if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors))\n            continue;\n\n        int i = output.i;\n\n        CInputCoin coin = CInputCoin(pcoin, i, allowIndexBased);\n\n        if (coin.txout.nValue == nTargetValue)\n        {\n            setCoinsRet.insert(coin);\n            nValueRet += coin.txout.nValue;\n            return true;\n        }\n        else if (coin.txout.nValue < nTargetValue + MIN_CHANGE)\n        {\n            vValue.push_back(coin);\n            nTotalLower += coin.txout.nValue;\n        }\n        else if (!coinLowestLarger || coin.txout.nValue < coinLowestLarger->txout.nValue)\n        {\n            coinLowestLarger = coin;\n        }\n    }\n\n    if (nTotalLower == nTargetValue)\n    {\n        for (const auto& input : vValue)\n        {\n            setCoinsRet.insert(input);\n            nValueRet += input.txout.nValue;\n        }\n        return true;\n    }\n\n    if (nTotalLower < nTargetValue)\n    {\n        if (!coinLowestLarger)\n            return false;\n        setCoinsRet.insert(coinLowestLarger.get());\n        nValueRet += coinLowestLarger->txout.nValue;\n        return true;\n    }\n\n    // Solve subset sum by stochastic approximation\n    std::sort(vValue.begin(), vValue.end(), CompareValueOnly());\n    std::reverse(vValue.begin(), vValue.end());\n    std::vector<char> vfBest;\n    CAmount nBest;\n\n    ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);\n    if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)\n    {\n        ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);\n    }\n\n    // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,\n    //                                   or the next bigger coin is closer), return the bigger coin\n    if (coinLowestLarger &&((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger->txout.nValue <= nBest))\n    {\n        setCoinsRet.insert(coinLowestLarger.get());\n        nValueRet += coinLowestLarger->txout.nValue;\n    }\n    else\n    {\n        for (unsigned int i = 0; i < vValue.size(); i++)\n        {\n            if (vfBest[i])\n            {\n                setCoinsRet.insert(vValue[i]);\n                nValueRet += vValue[i].txout.nValue;\n            }\n        }\n\n        if (LogAcceptCategory(BCLog::SELECTCOINS))\n        {\n            LogPrint(BCLog::SELECTCOINS, \"SelectCoins() best subset: \");\n            for (unsigned int i = 0; i < vValue.size(); i++)\n            {\n                if (vfBest[i])\n                {\n                    LogPrint(BCLog::SELECTCOINS, \"%s \", FormatMoney(vValue[i].txout.nValue));\n                }\n            }\n            LogPrint(BCLog::SELECTCOINS, \"total %s\\n\", FormatMoney(nBest));\n        }\n    }\n\n    return true;\n}\n\nbool CWallet::SelectCoins(bool allowIndexBased, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const\n{\n    std::vector<COutput> vCoins(vAvailableCoins);\n\n    // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)\n    if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)\n    {\n        for(const COutput& out : vCoins)\n        {\n            if (!out.fSpendable)\n                 continue;\n            nValueRet += out.tx->tx->vout[out.i].nValue;\n            setCoinsRet.insert(CInputCoin(out.tx, out.i, allowIndexBased));\n        }\n        return (nValueRet >= nTargetValue);\n    }\n\n    // calculate value from preset inputs and store them\n    std::set<CInputCoin> setPresetCoins;\n    CAmount nValueFromPresetInputs = 0;\n\n    std::vector<COutPoint> vPresetInputs;\n    if (coinControl)\n        coinControl->ListSelected(vPresetInputs);\n    for(const COutPoint& outpoint : vPresetInputs)\n    {\n        CWalletTx* pcoin = GetWalletTx(outpoint);\n        if (pcoin)\n        {\n            // Clearly invalid input, fail\n            if (pcoin->tx->vout.size() <= outpoint.n)\n                return false;\n            nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;\n            setPresetCoins.insert(CInputCoin(pcoin, outpoint.n, allowIndexBased));\n        } else\n            return false; // TODO: Allow non-wallet inputs\n    }\n\n    // remove preset inputs from vCoins\n    for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)\n    {\n        // Check in both forms (index based and not) to eliminate the same selection occuring twice\n        if (setPresetCoins.count(CInputCoin(it->tx, it->i, allowIndexBased)) \n            || (allowIndexBased && setPresetCoins.count(CInputCoin(it->tx, it->i, false))))\n        {\n            it = vCoins.erase(it);\n        }\n        else\n        {\n            ++it;\n        }\n    }\n\n    size_t nMaxChainLength = std::min(GetArg(\"-limitancestorcount\", DEFAULT_ANCESTOR_LIMIT), GetArg(\"-limitdescendantcount\", DEFAULT_DESCENDANT_LIMIT));\n    bool fRejectLongChains = GetBoolArg(\"-walletrejectlongchains\", DEFAULT_WALLET_REJECT_LONG_CHAINS);\n\n    bool res = nTargetValue <= nValueFromPresetInputs ||\n        SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet, allowIndexBased) ||\n        SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet, allowIndexBased) ||\n        (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet, allowIndexBased)) ||\n        (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet, allowIndexBased)) ||\n        (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet, allowIndexBased)) ||\n        (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet, allowIndexBased)) ||\n        (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet, allowIndexBased));\n\n    // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset\n    setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());\n\n    // add preset inputs to the total value selected\n    nValueRet += nValueFromPresetInputs;\n\n    return res;\n}\n\nvoid CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {\n    CWalletDB walletdb(*dbw);\n    return walletdb.ListAccountCreditDebit(strAccount, entries);\n}\n\nbool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)\n{\n    CWalletDB walletdb(*dbw);\n\n    return AddAccountingEntry(acentry, &walletdb);\n}\n\nbool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb)\n{\n    if (!pwalletdb->WriteAccountingEntry(++nAccountingEntryNumber, acentry)) {\n        return false;\n    }\n\n    laccentries.push_back(acentry);\n    CAccountingEntry & entry = laccentries.back();\n    wtxOrdered.insert(std::pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));\n\n    return true;\n}\n\nCAmount CWallet::GetRequiredFee(unsigned int nTxBytes)\n{\n    return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));\n}\n\nCAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreGlobalPayTxFee)\n{\n    // payTxFee is the user-set global for desired feerate\n    CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);\n    // User didn't set: use -txconfirmtarget to estimate...\n    if (nFeeNeeded == 0 || ignoreGlobalPayTxFee) {\n        int estimateFoundTarget = nConfirmTarget;\n        nFeeNeeded = estimator.estimateSmartFee(nConfirmTarget, &estimateFoundTarget, pool).GetFee(nTxBytes);\n        // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee\n        if (nFeeNeeded == 0)\n            nFeeNeeded = fallbackFee.GetFee(nTxBytes);\n    }\n    // prevent user from paying a fee below minRelayTxFee or minTxFee\n    nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));\n    // But always obey the maximum\n    if (nFeeNeeded > maxTxFee)\n        nFeeNeeded = maxTxFee;\n    return nFeeNeeded;\n}\n\nDBErrors CWallet::ZapSelectTx(CWalletDB& walletdb, std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)\n{\n    AssertLockHeld(cs_wallet); // mapWallet\n    //vchDefaultKey = CPubKey();//MUNT - no default key.\n    DBErrors nZapSelectTxRet = walletdb.ZapSelectTx(vHashIn, vHashOut);\n    for (uint256 hash : vHashOut)\n        mapWallet.erase(hash);\n\n    if (nZapSelectTxRet == DB_NEED_REWRITE)\n    {\n        if (dbw->Rewrite(\"\\x04pool\"))\n        {\n            //fixme: (FUT) (ACCOUNTS) (MED)\n            for (const auto& [accountUUID, forAccount] : mapAccounts)\n            {\n                (unused) accountUUID;\n                forAccount->setKeyPoolInternal.clear();\n                forAccount->setKeyPoolExternal.clear();\n            }\n            // Note: can't top-up keypool here, because wallet is locked.\n            // User will be prompted to unlock wallet the next operation\n            // that requires a new key.\n        }\n    }\n\n    if (nZapSelectTxRet != DB_LOAD_OK)\n        return nZapSelectTxRet;\n\n    MarkDirty();\n\n    return DB_LOAD_OK;\n\n}\n\nDBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)\n{\n    //vchDefaultKey = CPubKey();//MUNT - no default key.\n    DBErrors nZapWalletTxRet = CWalletDB(*dbw,\"cr+\").ZapWalletTx(vWtx);\n    if (nZapWalletTxRet == DB_NEED_REWRITE)\n    {\n        if (dbw->Rewrite(\"\\x04pool\"))\n        {\n            LOCK(cs_wallet);\n            //fixme: (FUT) (ACCOUNTS) (MED)\n            for (const auto& [accountUUID, forAccount] : mapAccounts)\n            {\n                (unused) accountUUID;\n                forAccount->setKeyPoolInternal.clear();\n                forAccount->setKeyPoolExternal.clear();\n            }\n            // Note: can't top-up keypool here, because wallet is locked.\n            // User will be prompted to unlock wallet the next operation\n            // that requires a new key.\n        }\n    }\n\n    if (nZapWalletTxRet != DB_LOAD_OK)\n        return nZapWalletTxRet;\n\n    return DB_LOAD_OK;\n}\n\n\nbool CWallet::SetAddressBook(const std::string& address, const std::string& strName, const std::string& strRecipientDescription, const std::string& strPurpose)\n{\n    bool fUpdated = false;\n    {\n        LOCK(cs_wallet); // mapAddressBook\n        std::map<std::string, CAddressBookData>::iterator mi = mapAddressBook.find(address);\n        fUpdated = mi != mapAddressBook.end();\n        auto& data = mapAddressBook[address];\n        data.name = strName;\n        // Only update if explicitely requested to do so\n        if (!strPurpose.empty())\n            data.purpose = strPurpose;\n        if (!strRecipientDescription.empty())\n            data.description = strName;\n    }\n    NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, CNativeAddress(address).Get()) != ISMINE_NO, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );\n    \n    if (!strPurpose.empty() && !CWalletDB(*dbw).WriteRecipientPurpose(address, strPurpose))\n        return false;\n    if (!strRecipientDescription.empty()  && !CWalletDB(*dbw).WriteRecipientDescription(address, strRecipientDescription)) \n        return false;\n    return CWalletDB(*dbw).WriteRecipientName(address, strName);\n}\n\nbool CWallet::DelAddressBook(const std::string& address)\n{\n    {\n        LOCK(cs_wallet); // mapAddressBook\n\n        // Delete destdata tuples associated with address\n        for(const PAIRTYPE(std::string, std::string) &item : mapAddressBook[address].destdata)\n        {\n            CWalletDB(*dbw).EraseDestData(address, item.first);\n        }\n        mapAddressBook.erase(address);\n    }\n\n    NotifyAddressBookChanged(this, address, \"\", ::IsMine(*this, CNativeAddress(address).Get()) != ISMINE_NO, \"\", CT_DELETED);\n\n    // if address is a valid string encoding of a Munt address use that for delete key,\n    // else it is most likely an IBAN address and then use that directly as key\n    CNativeAddress nativeAddress;\n    std::string deleteKey = nativeAddress.SetString(address) ? nativeAddress.ToString() : address;\n    CWalletDB(*dbw).EraseRecipientPurpose(deleteKey);\n    return CWalletDB(*dbw).EraseRecipientName(deleteKey);\n}\n\nstd::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()\n{\n    AssertLockHeld(cs_wallet); // mapWallet\n    std::set< std::set<CTxDestination> > groupings;\n    std::set<CTxDestination> grouping;\n\n    for (const auto& walletEntry : mapWallet)\n    {\n        const CWalletTx *pcoin = &walletEntry.second;\n\n        if (pcoin->tx->vin.size() > 0)\n        {\n            bool any_mine = false;\n            // group all input addresses with each other\n            for(CTxIn txin : pcoin->tx->vin)\n            {\n                CTxDestination address;\n                if(!IsMine(txin)) /* If this input isn't mine, ignore it */\n                    continue;\n                const CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n                if(!prev || !ExtractDestination(prev->tx->vout[txin.GetPrevOut().n], address))\n                    continue;\n                grouping.insert(address);\n                any_mine = true;\n            }\n\n            // group change with input addresses\n            if (any_mine)\n            {\n               for(CTxOut txout : pcoin->tx->vout)\n                   if (IsChange(txout))\n                   {\n                       CTxDestination txoutAddr;\n                       if(!ExtractDestination(txout, txoutAddr))\n                           continue;\n                       grouping.insert(txoutAddr);\n                   }\n            }\n            if (grouping.size() > 0)\n            {\n                groupings.insert(grouping);\n                grouping.clear();\n            }\n        }\n\n        // group lone addrs by themselves\n        for (const auto& txout : pcoin->tx->vout)\n            if (IsMine(txout))\n            {\n                CTxDestination address;\n                if(!ExtractDestination(txout, address))\n                    continue;\n                grouping.insert(address);\n                groupings.insert(grouping);\n                grouping.clear();\n            }\n    }\n\n    std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses\n    std::map< CTxDestination, std::set<CTxDestination>* > setmap;  // map addresses to the unique group containing it\n    for(std::set<CTxDestination> _grouping : groupings)\n    {\n        // make a set of all the groups hit by this new group\n        std::set< std::set<CTxDestination>* > hits;\n        std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;\n        for(CTxDestination address : _grouping)\n            if ((it = setmap.find(address)) != setmap.end())\n                hits.insert((*it).second);\n\n        // merge all hit groups into a new single group and delete old groups\n        std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);\n        for(std::set<CTxDestination>* hit : hits)\n        {\n            merged->insert(hit->begin(), hit->end());\n            uniqueGroupings.erase(hit);\n            delete hit;\n        }\n        uniqueGroupings.insert(merged);\n\n        // update setmap\n        for(CTxDestination element : *merged)\n            setmap[element] = merged;\n    }\n\n    std::set< std::set<CTxDestination> > ret;\n    for(std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)\n    {\n        ret.insert(*uniqueGrouping);\n        delete uniqueGrouping;\n    }\n\n    return ret;\n}\n\n\n\nstd::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const\n{\n    LOCK(cs_wallet);\n    std::set<CTxDestination> result;\n    for(const PAIRTYPE(std::string, CAddressBookData)& item : mapAddressBook)\n    {\n        const std::string& address = item.first;\n        const std::string& strName = item.second.name;\n        if (strName == strAccount)\n            result.insert(CNativeAddress(address).Get());\n    }\n    return result;\n}\n\nbool CReserveKeyOrScript::GetReservedKey(CPubKey& pubkey)\n{\n    if (scriptOnly())\n        return false;\n\n    if (pwallet && nIndex == -1)\n    {\n        CKeyPool keypool;\n        pwallet->ReserveKeyFromKeyPool(nIndex, keypool, account, nKeyChain);\n        if (nIndex != -1)\n        {\n            vchPubKey = keypool.vchPubKey;\n        }\n        else\n        {\n            return false;\n        }\n    }\n    assert(vchPubKey.IsValid());\n    pubkey = vchPubKey;\n    return true;\n}\n\nbool CReserveKeyOrScript::GetReservedKeyID(CKeyID &pubKeyID_)\n{\n    if (scriptOnly())\n        return false;\n    \n    if (pubKeyID.IsNull())\n        return false;\n    \n    pubKeyID_ = pubKeyID;\n    return true;\n}\n\nvoid CReserveKeyOrScript::KeepKey()\n{\n    if (scriptOnly())\n        return;\n    if (nIndex != -1)\n        pwallet->KeepKey(nIndex);\n    nIndex = -1;\n    vchPubKey = CPubKey();\n}\n\nvoid CReserveKeyOrScript::ReturnKey()\n{\n    if (scriptOnly())\n        return;\n    if (nIndex != -1)\n        pwallet->ReturnKey(nIndex, account, nKeyChain);\n    nIndex = -1;\n    vchPubKey = CPubKey();\n}\n\nvoid CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const\n{\n    setAddress.clear();\n\n    CWalletDB walletdb(*dbw);\n\n    LOCK2(cs_main, cs_wallet);\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            const auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? forAccount->setKeyPoolExternal : forAccount->setKeyPoolInternal );\n            for (const int64_t& id : keyPool)\n            {\n                CKeyPool keypoolentry;\n                if (!walletdb.ReadPool(id, keypoolentry))\n                throw std::runtime_error(std::string(__func__) + \": read failed\");\n                assert(keypoolentry.vchPubKey.IsValid());\n                CKeyID keyID = keypoolentry.vchPubKey.GetID();\n                if (!HaveKey(keyID))\n                    throw std::runtime_error(std::string(__func__) + \": unknown key in key pool\");\n                setAddress.insert(keyID);\n            }\n        }\n    }\n}\n\nvoid CWallet::ScriptForMining(std::shared_ptr<CReserveKeyOrScript> &script, CAccount* forAccount)\n{\n    //fixme: (PHASE5) - Clean this all up.\n    std::shared_ptr<CReserveKeyOrScript> rKey;\n    if (forAccount)\n    {\n        rKey = std::make_shared<CReserveKeyOrScript>(this, forAccount, KEYCHAIN_EXTERNAL);\n    }\n    else\n    {\n        rKey = std::make_shared<CReserveKeyOrScript>(this, activeAccount, KEYCHAIN_EXTERNAL);\n    }\n    CPubKey pubkey;\n    if (!rKey->GetReservedKey(pubkey))\n    {\n        CAlert::Notify(\"Failed to obtain reward key for mining account.\", true, true);\n        return;\n    }\n    \n    CKeyID pubKeyID;\n    if (IsPow2Phase4Active(chainActive.Tip()) && rKey->GetReservedKeyID(pubKeyID))\n    {\n        script = std::make_shared<CReserveKeyOrScript>();\n    }\n    else\n    {\n        script = rKey;\n        script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;\n    }\n}\n\nvoid CWallet::ScriptForWitnessing(std::shared_ptr<CReserveKeyOrScript> &script, CAccount* forAccount)\n{\n    std::shared_ptr<CReserveKeyOrScript> rKey;\n\n    // forAccount should never be null\n    if (!forAccount)\n    {\n        CAlert::Notify(\"Failed to obtain reward key for witness account, invalid account.\", true, true);\n        return;\n    }\n\n    // Always pay to KEYCHAIN_SPENDING instead of KEYCHAIN_WITNESS if possible - that way if witness key is stolen our funds are safe.\n    // If an explicit script has been set via RPC then use that, otherwise we just make a script from a key\n    if (forAccount->hasNonCompoundRewardScript())\n    {\n        rKey = std::make_shared<CReserveKeyOrScript>(nullptr, nullptr, KEYCHAIN_SPENDING);\n        rKey->reserveScript = forAccount->getNonCompoundRewardScript();\n    }\n    else\n    {\n        rKey = std::make_shared<CReserveKeyOrScript>(this, forAccount, KEYCHAIN_SPENDING);\n\n        CPubKey pubkey;\n        if (!rKey->GetReservedKey(pubkey))\n        {\n            CAlert::Notify(\"Failed to obtain reward key for witness account.\", true, true);\n            return;\n        }\n\n        rKey->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;\n    }\n    script = rKey;\n}\n\nvoid CWallet::LockCoin(const COutPoint& output)\n{\n    AssertLockHeld(cs_wallet); // setLockedCoins\n    setLockedCoins.insert(output);\n}\n\nvoid CWallet::UnlockCoin(const COutPoint& output)\n{\n    AssertLockHeld(cs_wallet); // setLockedCoins\n    setLockedCoins.erase(output);\n}\n\nvoid CWallet::UnlockAllCoins()\n{\n    AssertLockHeld(cs_wallet); // setLockedCoins\n    setLockedCoins.clear();\n}\n\nbool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const\n{\n    AssertLockHeld(cs_wallet); // setLockedCoins\n    COutPoint outpt(hash, n);\n\n    return (setLockedCoins.count(outpt) > 0);\n}\n\nvoid CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const\n{\n    AssertLockHeld(cs_wallet); // setLockedCoins\n    for (std::set<COutPoint>::iterator it = setLockedCoins.begin();\n         it != setLockedCoins.end(); it++) {\n        COutPoint outpt = (*it);\n        vOutpts.push_back(outpt);\n    }\n}\n\n\nvoid CWallet::CompareWalletAgainstUTXO(int& nMismatchFound, int& nOrphansFound, int64_t& nBalanceInQuestion, bool attemptRepair)\n{\n    nMismatchFound = 0;\n    nBalanceInQuestion = 0;\n    nOrphansFound = 0;\n\n    LOCK2(cs_main, cs_wallet);\n    std::vector<CWalletTx*> allWalletCoins;\n    allWalletCoins.reserve(mapWallet.size());\n    for(auto& it : mapWallet)\n    {\n        allWalletCoins.push_back(&it.second);\n    }\n\n    CCoinsViewCache viewNew(pcoinsTip);\n    std::map<COutPoint, Coin> allUTXOCoins;\n    viewNew.GetAllCoins(allUTXOCoins);\n    \n    //Iterate all UTXO entries and check if they are ours\n    //If they are check they are in the wallet\n    //If they aren't this is an issue\n    for(const auto& [utxoOutpoint, utxoCoin] : allUTXOCoins)\n    {\n        if (utxoOutpoint.isHash)\n        {\n            if(IsMine(utxoCoin.out) >= ISMINE_SPENDABLE)\n            {\n                if (mapWallet.find(utxoOutpoint.getTransactionHash()) == mapWallet.end())\n                {\n                    LogPrintf(\"CompareWalletAgainstUTXO: Found a utxo that is ours but that isn't in wallet %s %s[%d]\\n\", FormatMoney(utxoCoin.out.nValue).c_str(), utxoOutpoint.getTransactionHash().ToString().c_str(), utxoOutpoint.n);\n                    nMismatchFound++;\n                    nBalanceInQuestion += utxoCoin.out.nValue;\n                }\n            }\n        }\n    }\n    //Iterate all wallet entries\n    //Ensure that they are in the UTXO if they are unspent\n    //Ensure that they aren't in the UTXO if they are spent\n    //If either of the above is untrue this is an issue\n    for(CWalletTx* walletCoin : allWalletCoins)\n    {\n        uint256 hash = walletCoin->GetHash();\n        uint64_t n;\n\n        if(walletCoin->IsCoinBase() && (walletCoin->GetDepthInMainChain() < 0))\n        {\n           nOrphansFound++;\n           printf(\"CompareWalletAgainstUTXO: Found orphaned generation tx [%s]\\n\", hash.ToString().c_str());\n        }\n        else\n        {\n            for(n = 0; n < walletCoin->tx->vout.size(); n++)\n            {\n                if(IsMine(walletCoin->tx->vout[n]) >= ISMINE_SPENDABLE)\n                {\n                    COutPoint walletCoinOutpoint(walletCoin->tx->GetHash(), n);\n                    COutPoint walletCoinOutpointIndex(walletCoin->nHeight, walletCoin->nIndex, n);\n                    bool outputIsInUTXO = (allUTXOCoins.find(walletCoinOutpoint) != allUTXOCoins.end()) || (allUTXOCoins.find(walletCoinOutpointIndex) != allUTXOCoins.end());\n                    bool outputSpentInWallet = pactiveWallet->IsSpent(walletCoinOutpoint) || IsSpent(walletCoinOutpointIndex);\n                    if(outputSpentInWallet && outputIsInUTXO)\n                    {\n                        LogPrintf(\"CompareWalletAgainstUTXO: Found wallet-spent coins that are in the utxo and therefore shouldn't be spent %s %s[%d]\\n\", FormatMoney(walletCoin->tx->vout[n].nValue).c_str(), hash.ToString().c_str(), n);\n                        nMismatchFound++;\n                        nBalanceInQuestion += walletCoin->tx->vout[n].nValue;\n                    }\n                    else if(!outputSpentInWallet && !outputIsInUTXO)\n                    {\n                        if (attemptRepair)\n                        {\n                            std::vector<uint256> hashesToErase;\n                            std::vector<uint256> hashesErased;\n                            CWalletDB walletdb(*dbw);\n                            hashesToErase.push_back(walletCoinOutpoint.getTransactionHash());\n                            pactiveWallet->ZapSelectTx(walletdb, hashesToErase, hashesErased);\n                        }\n                        printf(\"CompareWalletAgainstUTXO: Found wallet-unspent coins that aren't in the chain utxo and therefore should be spent %s %s[%ld]\\n\", FormatMoney(walletCoin->tx->vout[n].nValue).c_str(), hash.ToString().c_str(), n);\n                        nMismatchFound++;\n                        nBalanceInQuestion += walletCoin->tx->vout[n].nValue;\n                    }\n                }\n            }  \n        }\n    }\n}\n\nbool CWallet::RemoveAllOrphans(uint64_t& numErased, uint64_t& numDetected, std::string& strError)\n{\n    std::vector<uint256> transactionsToZap;\n    std::vector<uint256> transactionsZapped;\n    numErased = 0;\n    for(auto& [hash, walletCoin] : mapWallet)\n    {\n        if(walletCoin.IsCoinBase() && (walletCoin.GetDepthInMainChain() < 0))\n        {\n           transactionsToZap.emplace_back(hash);\n        }\n    }\n    \n    numDetected = transactionsToZap.size();\n    if (numDetected > 0)\n    {\n        LogPrintf(\"Removing [%d] orphan transactions from wallet\\n\", numDetected);\n        \n        CWalletDB walletdb(*pactiveWallet->dbw);\n        bool ret = ZapSelectTx(walletdb, transactionsToZap, transactionsZapped) != DB_LOAD_OK;\n        numErased = transactionsZapped.size();\n        LogPrintf(\"Removed [%d] of [%d] orphan transactions from wallet\\n\", numErased, numDetected);\n        if (!ret)\n        {\n            strError = \"Failed to erase orphan transactions for account.\";\n            LogPrintf(\"%s\\n\", strError.c_str());\n            CAlert::Notify(strError, true, true);\n            return false;\n        }\n    }\n    return true;\n}\n\n/** @} */ // end of Actions\n\nclass CAffectedKeysVisitor : public boost::static_visitor<void> {\nprivate:\n    const CKeyStore &keystore;\n    std::vector<CKeyID> &vKeys;\n\npublic:\n    CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}\n\n    void Process(const CTxOut &out) {\n        txnouttype type;\n        std::vector<CTxDestination> vDest;\n        int nRequired;\n        if (ExtractDestinations(out, type, vDest, nRequired)) {\n            for(const CTxDestination &dest : vDest)\n                boost::apply_visitor(*this, dest);\n        }\n    }\n\n    void operator()(const CKeyID &keyId) {\n        if (keystore.HaveKey(keyId))\n            vKeys.push_back(keyId);\n    }\n\n    void operator()(const CScriptID &scriptId) {\n        CScript script;\n        if (keystore.GetCScript(scriptId, script))\n        {\n            txnouttype type;\n            std::vector<CTxDestination> vDest;\n            int nRequired;\n            if (ExtractDestinations(script, type, vDest, nRequired))\n            {\n                for (const CTxDestination &dest : vDest)\n                {\n                    boost::apply_visitor(*this, dest);\n                }\n            }\n        }\n    }\n\n    void operator()(const CPoW2WitnessDestination &dest) {\n        if (keystore.HaveKey(dest.witnessKey))\n            vKeys.push_back(dest.witnessKey);\n        if (keystore.HaveKey(dest.spendingKey))\n            vKeys.push_back(dest.spendingKey);\n    }\n\n    void operator()(const CNoDestination &none) {}\n};\n\nvoid CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const\n{\n    LOCK(cs_wallet);\n\n    AssertLockHeld(cs_wallet); // mapKeyMetadata\n    mapKeyBirth.clear();\n\n    // get birth times for keys with metadata\n    for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)\n    {\n        if (it->second.nCreateTime)\n        {\n            mapKeyBirth[it->first] = it->second.nCreateTime;\n        }\n    }\n\n    // map in which we'll infer heights of other keys\n    auto& chain = IsPartialSyncActive() ? partialChain : chainActive;\n    CBlockIndex *pindexMax = chain[std::max(0, chain.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin\n    std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;\n    std::set<CKeyID> setKeys;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        forAccount->GetKeys(setKeys);\n        for(const auto keyid : setKeys)\n        {\n            if (mapKeyBirth.count(keyid) == 0)\n            {\n                mapKeyFirstBlock[keyid] = pindexMax;\n            }\n        }\n        setKeys.clear();\n    }\n\n    // if there are no such keys, we're done\n    if (mapKeyFirstBlock.empty())\n        return;\n\n    // find first block that affects those keys, if there are any left\n    std::vector<CKeyID> vAffected;\n    for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++)\n    {\n        // iterate over all wallet transactions...\n        const CWalletTx &wtx = (*it).second;\n        BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);\n        if (blit != mapBlockIndex.end() && chain.Contains(blit->second))\n        {\n            // ... which are already in a block\n            int nHeight = blit->second->nHeight;\n            for(const CTxOut &txout : wtx.tx->vout)\n            {\n                // iterate over all their outputs\n                for (const auto& [accountUUID, forAccount] : mapAccounts)\n                {\n                    (unused) accountUUID;\n                    for (const auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n                    {\n                        const auto& keyStore = (keyChain == KEYCHAIN_EXTERNAL) ? forAccount->externalKeyStore : forAccount->internalKeyStore;\n                        CAffectedKeysVisitor(keyStore, vAffected).Process(txout);\n                        // ... and all their affected keys\n                        for(const CKeyID &keyid : vAffected)\n                        {\n                            std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);\n                            if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)\n                            {\n                                rit->second = blit->second;\n                            }\n                        }\n                        vAffected.clear();\n                    }\n                }\n            }\n        }\n    }\n\n    // Extract block timestamps for those keys\n    for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)\n    {\n        mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off\n    }\n}\n\n/**\n * Compute smart timestamp for a transaction being added to the wallet.\n *\n * Logic:\n * - If sending a transaction, assign its timestamp to the current time.\n * - If receiving a transaction outside a block, assign its timestamp to the\n *   current time.\n * - If receiving a block with a future timestamp, assign all its (not already\n *   known) transactions' timestamps to the current time.\n * - If receiving a block with a past timestamp, but after the most recent known\n *   transaction, assign all its (not already known) transactions' timestamps to\n *   the block time.\n *\n * For more information see CWalletTx::nTimeSmart,\n * https://bitcointalk.org/?topic=54527, or\n * https://github.com/bitcoin/bitcoin/pull/1393.\n */\nunsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const\n{\n    unsigned int nTimeSmart = wtx.nTimeReceived;\n    if (!wtx.hashUnset()) {\n        if (mapBlockIndex.count(wtx.hashBlock)) {\n            int64_t latestNow = wtx.nTimeReceived;\n\n            // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future\n            int64_t latestTolerated = latestNow + 300;\n            const TxItems& txOrdered = wtxOrdered;\n            for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {\n                CWalletTx* const pwtx = it->second.first;\n                if (pwtx == &wtx) {\n                    continue;\n                }\n                CAccountingEntry* const pacentry = it->second.second;\n                int64_t nSmartTime;\n                if (pwtx) {\n                    nSmartTime = pwtx->nTimeSmart;\n                    if (!nSmartTime) {\n                        nSmartTime = pwtx->nTimeReceived;\n                    }\n                } else {\n                    nSmartTime = pacentry->nTime;\n                }\n                if (nSmartTime <= latestTolerated) {\n                    if (nSmartTime > latestNow) {\n                        latestNow = nSmartTime;\n                    }\n                    break;\n                }\n            }\n\n            int64_t blocktime = mapBlockIndex[wtx.hashBlock]->GetBlockTime();\n            nTimeSmart = std::min(blocktime, latestNow);\n        } else {\n            LogPrintf(\"%s: found %s in block %s not in index\\n\", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());\n        }\n    }\n    return nTimeSmart;\n}\n\nbool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)\n{\n    if (boost::get<CNoDestination>(&dest))\n        return false;\n\n    mapAddressBook[CNativeAddress(dest).ToString()].destdata.insert(std::pair(key, value));\n    return CWalletDB(*dbw).WriteDestData(CNativeAddress(dest).ToString(), key, value);\n}\n\nbool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)\n{\n    if (!mapAddressBook[CNativeAddress(dest).ToString()].destdata.erase(key))\n        return false;\n    return CWalletDB(*dbw).EraseDestData(CNativeAddress(dest).ToString(), key);\n}\n\nbool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)\n{\n    mapAddressBook[CNativeAddress(dest).ToString()].destdata.insert(std::pair(key, value));\n    return true;\n}\n\nbool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const\n{\n    std::map<std::string, CAddressBookData>::const_iterator i = mapAddressBook.find(CNativeAddress(dest).ToString());\n    if(i != mapAddressBook.end())\n    {\n        CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);\n        if(j != i->second.destdata.end())\n        {\n            if(value)\n                *value = j->second;\n            return true;\n        }\n    }\n    return false;\n}\n\nstd::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const\n{\n    LOCK(cs_wallet);\n    std::vector<std::string> values;\n    for (const auto& address : mapAddressBook) {\n        for (const auto& data : address.second.destdata) {\n            if (!data.first.compare(0, prefix.size(), prefix)) {\n                values.emplace_back(data.second);\n            }\n        }\n    }\n    return values;\n}\n\nCKeyPool::CKeyPool()\n{\n    nTime = GetTime();\n}\n\nCKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, const std::string& accountNameIn, int64_t nChainIn)\n: nTime( GetTime() )\n, vchPubKey( vchPubKeyIn )\n, accountName( accountNameIn )\n, nChain ( nChainIn )\n{\n}\n\nCWalletKey::CWalletKey(int64_t nExpires)\n{\n    nTimeCreated = (nExpires ? GetTime() : 0);\n    nTimeExpires = nExpires;\n}\n\nnamespace\n{\n    class CRecipientVisitor : public boost::static_visitor<CRecipient>\n    {\n    private:\n        CTxDestination dest;\n        CAmount nValue;\n        bool fSubtractFeeFromAmount;\n    public:\n        CRecipientVisitor(const CTxDestination& dest_, CAmount nValue_, bool fSubtractFeeFromAmount_) : dest(dest_), nValue(nValue_), fSubtractFeeFromAmount(fSubtractFeeFromAmount_) {  }\n\n        CRecipient operator()(const CNoDestination &dest) const\n        {\n            return CRecipient(GetScriptForDestination(dest), nValue, fSubtractFeeFromAmount);\n        }\n\n        CRecipient operator()(const CKeyID &keyID) const\n        {\n            return CRecipient(CTxOutStandardKeyHash(keyID), nValue, fSubtractFeeFromAmount);\n        }\n\n        CRecipient operator()(const CScriptID &scriptID) const\n        {\n            return CRecipient(GetScriptForDestination(dest), nValue, fSubtractFeeFromAmount);\n        }\n\n        CRecipient operator()(const CPoW2WitnessDestination& destinationPoW2Witness) const\n        {\n            return CRecipient(GetPoW2WitnessOutputFromWitnessDestination(destinationPoW2Witness), nValue, fSubtractFeeFromAmount);\n        }\n    };\n}\nCRecipient GetRecipientForDestination(const CTxDestination& dest, CAmount nValue, bool fSubtractFeeFromAmount, int nPoW2Phase)\n{\n    if (nPoW2Phase < 4)\n    {\n        return CRecipient(GetScriptForDestination(dest), nValue, fSubtractFeeFromAmount);\n    }\n    else\n    {\n        return boost::apply_visitor(CRecipientVisitor(dest, nValue, fSubtractFeeFromAmount), dest);\n    }\n}\n\nCRecipient GetRecipientForTxOut(const CTxOut& out, CAmount nValue, bool fSubtractFeeFromAmount)\n{\n    switch(out.GetType())\n    {\n        case CTxOutType::ScriptLegacyOutput:\n            return CRecipient(out.output.scriptPubKey, nValue, fSubtractFeeFromAmount);\n        case CTxOutType::PoW2WitnessOutput:\n            return CRecipient(out.output.witnessDetails, nValue, fSubtractFeeFromAmount);\n        case CTxOutType::StandardKeyHashOutput:\n            return CRecipient(out.output.standardKeyHash, nValue, fSubtractFeeFromAmount);\n    }\n    return CRecipient();\n}\n\nconst CBlockIndex* CWallet::LastSPVBlockProcessed() const\n{\n    return pSPVScanner ? pSPVScanner->LastBlockProcessed() : nullptr;\n}\n\nint64_t CWallet::birthTime() const\n{\n    int64_t birthTime = 0;\n\n    // determine block time of earliest transaction (if any)\n    // if this cannot be determined for every transaction a phrase without birth time acceleration will be used\n    int64_t firstTransactionTime = std::numeric_limits<int64_t>::max();\n    for (CWallet::TxItems::const_iterator it = pactiveWallet->wtxOrdered.begin(); it != pactiveWallet->wtxOrdered.end(); ++it)\n    {\n        CWalletTx* wtx = it->second.first;\n        if (!wtx->hashUnset())\n        {\n            CBlockIndex* index = mapBlockIndex.count(wtx->hashBlock) ? mapBlockIndex[wtx->hashBlock] : nullptr;\n            // try to get time from block timestamp\n            if (index && index->IsValid(BLOCK_VALID_HEADER))\n                firstTransactionTime = std::min(firstTransactionTime, std::max(int64_t(0), index->GetBlockTime()));\n            else if (wtx->nBlockTime > 0)\n            {\n                firstTransactionTime = std::min(firstTransactionTime, int64_t(wtx->nBlockTime));\n            }\n            else\n            {\n                // can't determine transaction time, only safe option left\n                firstTransactionTime = 0;\n                break;\n            }\n        }\n    }\n\n    int64_t tipTime;\n    const CBlockIndex* lastSPVBlock = pactiveWallet->LastSPVBlockProcessed();\n    if (lastSPVBlock)\n        tipTime = lastSPVBlock->GetBlockTime();\n    else\n        tipTime = chainActive.Tip()->GetBlockTime();\n\n    // never use a time beyond our processed tip either spv or full sync\n    birthTime = std::min(tipTime, firstTransactionTime);\n\n    return birthTime;\n}\n\nvoid CWallet::BeginUnlocked(std::string reason, std::function<void (void)> callback)\n{\n    // scoped because of cs_wallet\n    {\n        LOCK(cs_wallet);\n\n        bool beganLocked = IsLocked();\n\n        // try to unlock\n        if (beganLocked) {\n            uiInterface.RequestUnlockWithCallback(this, reason, [=]() {\n                // async callback, so the scoped lock above is already destructed, need to lock here again\n                {\n                    LOCK(cs_wallet);\n\n                    // begin session\n                    nUnlockSessions++;\n\n                    // when locked before the session, enable auto lock when all sessions end\n                    if (beganLocked)\n                        fAutoLock = true;\n                }\n\n                // execute callback without cs_wallet\n                callback();\n            });\n            return;\n        }\n\n        // begin session\n        nUnlockSessions++;\n\n        // when locked before the session enable, auto lock when all sessions end\n        if (beganLocked)\n            fAutoLock = true;\n    }\n\n    // execute callback without cs_wallet\n    callback();\n}\n\nbool CWallet::BeginUnlocked(const SecureString& strWalletPassphrase)\n{\n    LOCK(cs_wallet);\n\n    bool beganLocked = IsLocked();\n\n    // try to unlock\n    if (beganLocked) {\n        if (!Unlock(strWalletPassphrase))\n            return false;\n    }\n\n    // begin session\n    nUnlockSessions++;\n\n    // when locked before the session enable auto lock when all sessions end\n    if (beganLocked)\n        fAutoLock = true;\n\n    return true;\n}\n\nvoid CWallet::EndUnlocked()\n{\n    LOCK(cs_wallet);\n\n    assert(nUnlockSessions > 0);\n\n    nUnlockSessions--;\n    if (nUnlockSessions == 0 && fAutoLock) {\n        LockHard();\n    }\n}\n"
  },
  {
    "path": "src/wallet/wallet.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_WALLET_H\n#define WALLET_WALLET_H\n\n#include \"wallettx.h\"\n\n#include \"amount.h\"\n#include \"policy/feerate.h\"\n#include \"streams.h\"\n#include \"tinyformat.h\"\n#include \"ui_interface.h\"\n#include \"util/strencodings.h\"\n#include \"validation/validationinterface.h\"\n#include \"script/ismine.h\"\n#include \"script/sign.h\"\n#include \"wallet/crypter.h\"\n#include \"wallet/walletdb.h\"\n#include \"wallet/rpcwallet.h\"\n\n#include <algorithm>\n#include <atomic>\n#include <map>\n#include <set>\n#include <stdexcept>\n#include <stdint.h>\n#include <string>\n#include <utility>\n#include <vector>\n\ntypedef CWallet* CWalletRef;\nextern std::vector<CWalletRef> vpwallets;\nextern CWalletRef pactiveWallet;\n\n//Munt specific includes\n#include \"wallet/walletdberrors.h\"\n#include \"wallet/extwallet.h\"\n#include \"wallet/account.h\"\n\n#include <boost/thread.hpp>\n#include <consensus/consensus.h>\n\n/**\n * Settings\n */\nextern CFeeRate payTxFee;\nextern unsigned int nTxConfirmTarget;\nextern bool bSpendZeroConfChange;\nextern bool fWalletRbf;\nextern bool fSPV;\n\nstatic const unsigned int DEFAULT_ACCOUNT_KEYPOOL_SIZE = 30;\n//! -paytxfee default\nstatic const CAmount DEFAULT_TRANSACTION_FEE = 0;\n//! -fallbackfee default\nstatic const CAmount DEFAULT_FALLBACK_FEE = 20000;\n//! -mintxfee default\nstatic const CAmount DEFAULT_TRANSACTION_MINFEE = 1000000;\n//! minimum recommended increment for BIP 125 replacement txs\nstatic const CAmount WALLET_INCREMENTAL_RELAY_FEE = 5000;\n//! target minimum change amount\nstatic const CAmount MIN_CHANGE = CENT;\n//! final minimum change amount after paying for fees\nstatic const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;\n//! Default for -spendzeroconfchange\nstatic const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;\n//! Default for -walletrejectlongchains\nstatic const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;\n//! -txconfirmtarget default\nstatic const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;\n//! -walletrbf default\nstatic const bool DEFAULT_WALLET_RBF = false;\nstatic const bool DEFAULT_WALLETBROADCAST = true;\nstatic const bool DEFAULT_DISABLE_WALLET = false;\n//! if set, all keys will be derived by using BIP32\nstatic const bool DEFAULT_USE_HD_WALLET = true;\n\nextern const char * DEFAULT_WALLET_DAT;\n\nclass CBlockIndex;\nclass CCoinControl;\nclass COutput;\nclass CReserveKeyOrScript;\nclass CScript;\nclass CScheduler;\nclass CTxMemPool;\nclass CBlockPolicyEstimator;\nclass CWalletTx;\nclass CWalletDB;\nclass CSPVScanner;\n\n/** (client) version numbers for particular wallet features */\nenum WalletFeature\n{\n    FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)\n\n    FEATURE_WALLETCRYPT = 40000, // wallet encryption\n    FEATURE_COMPRPUBKEY = 60000, // compressed public keys\n\n    FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet)\n    FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version\n};\n\n\n/** A key pool entry */\nclass CKeyPool\n{\npublic:\n    int64_t nTime;\n    CPubKey vchPubKey;\n    std::string accountName;\n    int64_t nChain;//internal or external keypool (HD wallets)\n\n\n    CKeyPool();\n    CKeyPool(const CPubKey& vchPubKeyIn, const std::string& accountNameIn, int64_t nChainIn);\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        int nVersion = s.GetVersion();\n        if (!(s.GetType() & SER_GETHASH))\n            READWRITE(nVersion);\n        READWRITE(nTime);\n        READWRITE(vchPubKey);\n\n        //Allow to fail for legacy accounts.\n        try\n        {\n            READWRITE(accountName);\n            READWRITE(nChain);\n        }\n        catch(...)\n        {\n        }\n    }\n};\n\n/** Address book data */\nclass CAddressBookData\n{\npublic:\n    std::string name;\n    std::string description;\n    std::string purpose;\n\n    CAddressBookData() : purpose(\"unknown\") {}\n\n    typedef std::map<std::string, std::string> StringMap;\n    StringMap destdata;\n};\n\nclass CRecipient\n{\npublic:\n    CRecipient() : nType(CTxOutType::ScriptLegacyOutput) {}\n    CRecipient(CScript scriptPubKey_, CAmount nAmount_, bool fSubtractFeeFromAmount_) : nType(CTxOutType::ScriptLegacyOutput), scriptPubKey(scriptPubKey_), nAmount(nAmount_), fSubtractFeeFromAmount(fSubtractFeeFromAmount_) {}\n    CRecipient(CTxOutPoW2Witness witnessDetails_, CAmount nAmount_, bool fSubtractFeeFromAmount_) : nType(CTxOutType::PoW2WitnessOutput), witnessDetails(witnessDetails_), nAmount(nAmount_), fSubtractFeeFromAmount(fSubtractFeeFromAmount_) {}\n    CRecipient(CTxOutStandardKeyHash standardKeyHash_, CAmount nAmount_, bool fSubtractFeeFromAmount_) : nType(CTxOutType::StandardKeyHashOutput), standardKeyHash(standardKeyHash_), nAmount(nAmount_), fSubtractFeeFromAmount(fSubtractFeeFromAmount_) {}\n\n    CRecipient(const CRecipient& copy)\n    {\n        nType = copy.nType;\n        scriptPubKey = copy.scriptPubKey;\n        witnessForAccount = copy.witnessForAccount;\n        witnessDetails = copy.witnessDetails;\n        standardKeyHash = copy.standardKeyHash;\n        nAmount = copy.nAmount;\n        fSubtractFeeFromAmount = copy.fSubtractFeeFromAmount;\n    }\n    CTxOutType nType;\n    CScript scriptPubKey;\n    CAccount* witnessForAccount = nullptr;\n    CTxOutPoW2Witness witnessDetails;\n    CTxOutStandardKeyHash standardKeyHash;\n    CAmount nAmount;\n    bool fSubtractFeeFromAmount;\n    CTxOut GetTxOut() const\n    {\n        if (nType <= ScriptLegacyOutput)\n        {\n            return CTxOut(nAmount, scriptPubKey);\n        }\n        else if (nType == PoW2WitnessOutput)\n        {\n            return CTxOut(nAmount, witnessDetails);\n        }\n        else if (nType == StandardKeyHashOutput)\n        {\n            return CTxOut(nAmount, standardKeyHash);\n        }\n        else\n        {\n            assert(0);\n        }\n        return CTxOut();\n    }\n};\n\nCRecipient GetRecipientForDestination(const CTxDestination& dest, CAmount nValue, bool fSubtractFeeFromAmount, int nPoW2Phase);\nCRecipient GetRecipientForTxOut(const CTxOut& out, CAmount nValue, bool fSubtractFeeFromAmount);\n\n\n\nclass CInputCoin {\npublic:\n    CInputCoin(const CWalletTx* walletTx, unsigned int i, bool allowIndexBased)\n    {\n        if (!walletTx)\n            throw std::invalid_argument(\"walletTx should not be null\");\n        if (i >= walletTx->tx->vout.size())\n            throw std::out_of_range(\"The output index is out of range\");\n        \n        isCoinBase = walletTx->tx->IsCoinBase();\n\n        if (allowIndexBased && walletTx->GetDepthInMainChain() > COINBASE_MATURITY && walletTx->nHeight > 1 && walletTx->nIndex >= 0)\n        {\n            // Convert to an index based outpoint, whenever possible\n            outpoint = COutPoint(walletTx->nHeight, walletTx->nIndex, i);\n        }\n        else\n        {\n            // Use a regular hash based outpoint\n            outpoint = COutPoint(walletTx->GetHash(), i);\n        }\n        \n        txout = walletTx->tx->vout[i];\n    }\n\n    CInputCoin(const COutPoint& outpoint_, const CTxOut& txout_, bool allowIndexBased, bool isCoinBase_, uint64_t nBlockHeight=0, uint64_t nTxIndex=0)\n    : isCoinBase(isCoinBase_)\n    {\n        if (allowIndexBased && nBlockHeight < (uint64_t)chainActive.Tip()->nHeight && ((uint64_t)chainActive.Tip()->nHeight - nBlockHeight > (uint64_t)COINBASE_MATURITY))\n        {\n            // Convert to an index based outpoint, whenever possible\n            outpoint = COutPoint(nBlockHeight, nTxIndex, outpoint_.n);\n        }\n        else\n        {\n            // Use a regular hash based outpoint\n            outpoint = outpoint_;\n        }\n        txout = txout_;\n    }\n\n    COutPoint outpoint;\n    CTxOut txout;\n    bool isCoinBase;\n\n    bool operator<(const CInputCoin& rhs) const {\n        return outpoint < rhs.outpoint;\n    }\n\n    bool operator!=(const CInputCoin& rhs) const {\n        return outpoint != rhs.outpoint;\n    }\n\n    bool operator==(const CInputCoin& rhs) const {\n        return outpoint == rhs.outpoint;\n    }\n};\n\nclass COutput\n{\npublic:\n    const CWalletTx *tx;\n    int i;\n    int nDepth;\n\n    /** Whether we have the private keys to spend this output */\n    bool fSpendable;\n\n    /** Whether we know how to spend this output, ignoring the lack of keys */\n    bool fSolvable;\n\n    /**\n     * Whether this output is considered safe to spend. Unconfirmed transactions\n     * from outside keys and unconfirmed replacement transactions are considered\n     * unsafe and will not be used to fund new spending transactions.\n     */\n    bool fSafe;\n\n    COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn)\n    {\n        tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn;\n    }\n\n    std::string ToString() const;\n};\n\n\n\n\n/** Private key that includes an expiration date in case it never gets used. */\nclass CWalletKey\n{\npublic:\n    CPrivKey vchPrivKey;\n    int64_t nTimeCreated;\n    int64_t nTimeExpires;\n    std::string strComment;\n    //! todo: add something to note what created it (user, getnewaddress, change)\n    //!   maybe should have a map<string, string> property map\n\n    CWalletKey(int64_t nExpires=0);\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        int nVersion = s.GetVersion();\n        if (!(s.GetType() & SER_GETHASH))\n            READWRITE(nVersion);\n        READWRITECOMPACTSIZEVECTOR(vchPrivKey);\n        READWRITE(nTimeCreated);\n        READWRITE(nTimeExpires);\n        READWRITE(LIMITED_STRING(strComment, 65536));\n    }\n};\n\n/**\n * Internal transfers.\n * Database key is acentry<account><counter>.\n */\nclass CAccountingEntry\n{\npublic:\n    std::string strAccount;\n    CAmount nCreditDebit;\n    int64_t nTime;\n    std::string strOtherAccount;\n    std::string strComment;\n    mapValue_t mapValue;\n    int64_t nOrderPos; //!< position in ordered transaction list\n    uint64_t nEntryNo;\n\n    CAccountingEntry()\n    {\n        SetNull();\n    }\n\n    void SetNull()\n    {\n        nCreditDebit = 0;\n        nTime = 0;\n        strAccount.clear();\n        strOtherAccount.clear();\n        strComment.clear();\n        nOrderPos = -1;\n        nEntryNo = 0;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        int nVersion = s.GetVersion();\n        if (!(s.GetType() & SER_GETHASH))\n            READWRITE(nVersion);\n        //! Note: strAccount is serialized as part of the key, not here.\n        READWRITE(nCreditDebit);\n        READWRITE(nTime);\n        READWRITE(LIMITED_STRING(strOtherAccount, 65536));\n\n        if (!ser_action.ForRead())\n        {\n            WriteOrderPos(nOrderPos, mapValue);\n\n            if (!(mapValue.empty() && _ssExtra.empty()))\n            {\n                CDataStream ss(s.GetType(), s.GetVersion());\n                ss.insert(ss.begin(), std::byte('\\0'));\n                ss << mapValue;\n                ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());\n                strComment.append(ss.str());\n            }\n        }\n\n        READWRITE(LIMITED_STRING(strComment, 65536));\n\n        size_t nSepPos = strComment.find(\"\\0\", 0, 1);\n        if (ser_action.ForRead())\n        {\n            mapValue.clear();\n            if (std::string::npos != nSepPos)\n            {\n                CDataStream ss(AsBytes(Span(&strComment[0] + nSepPos + 1, strComment.length() -  (nSepPos + 1))), s.GetType(), s.GetVersion());\n                ss >> mapValue;\n                _ssExtra = CSerializeData(ss.begin(), ss.end());\n            }\n            ReadOrderPos(nOrderPos, mapValue);\n        }\n        if (std::string::npos != nSepPos)\n            strComment.erase(nSepPos);\n\n        mapValue.erase(\"n\");\n    }\n\nprivate:\n    CSerializeData _ssExtra;\n};\n\nstruct WalletBalances\n{\n    CAmount availableIncludingLocked = -1;\n    CAmount availableExcludingLocked = -1;\n    CAmount availableLocked = -1;\n    CAmount unconfirmedIncludingLocked = -1;\n    CAmount unconfirmedExcludingLocked = -1;\n    CAmount unconfirmedLocked = -1;\n    CAmount immatureIncludingLocked = -1;\n    CAmount immatureExcludingLocked = -1;\n    CAmount immatureLocked = -1;\n    CAmount totalLocked = -1;\n\n    bool operator==(const WalletBalances& rhs) const\n    {\n        return availableIncludingLocked       == rhs.availableIncludingLocked\n                && availableExcludingLocked   == rhs.availableExcludingLocked\n                && availableLocked            == rhs.availableLocked\n                && unconfirmedIncludingLocked == rhs.unconfirmedIncludingLocked\n                && unconfirmedExcludingLocked == rhs.unconfirmedExcludingLocked\n                && unconfirmedLocked          == rhs.unconfirmedLocked\n                && immatureIncludingLocked    == rhs.immatureIncludingLocked\n                && immatureExcludingLocked    == rhs.immatureExcludingLocked\n                && immatureLocked             == rhs.immatureLocked\n                && totalLocked                == rhs.totalLocked;\n    }\n    bool operator!=(const WalletBalances& rhs) const\n    {\n        return availableIncludingLocked       != rhs.availableIncludingLocked\n                || availableExcludingLocked   != rhs.availableExcludingLocked\n                || availableLocked            != rhs.availableLocked\n                || unconfirmedIncludingLocked != rhs.unconfirmedIncludingLocked\n                || unconfirmedExcludingLocked != rhs.unconfirmedExcludingLocked\n                || unconfirmedLocked          != rhs.unconfirmedLocked\n                || immatureIncludingLocked    != rhs.immatureIncludingLocked\n                || immatureExcludingLocked    != rhs.immatureExcludingLocked\n                || immatureLocked             != rhs.immatureLocked\n                || totalLocked                != rhs.totalLocked;\n    }\n};\n\n//fixme: (HIGH) Merge Cwallet and CExtWallet back into a single class\n/*\nAll Novo specific functionality goes in base class CExtWallet\nA little bit clumsy \n*/\nclass CWallet : public CExtWallet\n{\nprivate:\n    static std::atomic<bool> fFlushScheduled;\n    std::atomic<bool> fAbortRescan;\n    std::atomic<bool> fScanningWallet;\n\n    /**\n     * Select a set of coins such that nValueRet >= nTargetValue and at least\n     * all coins from coinControl are selected; Never select unconfirmed coins\n     * if they are not ours\n     */\n    bool SelectCoins(bool allowIndexBased, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;\n\n    CWalletDB *pwalletdbEncryption;\n\n    //! the current wallet version: clients below this version are not able to load the wallet\n    int nWalletVersion;\n\n    //! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded\n    int nWalletMaxVersion;\n\n    std::unique_ptr<CSPVScanner> pSPVScanner;\n\n    int64_t nNextResend;\n    int64_t nLastResend;\n    bool fBroadcastTransactions;\n\n    /**\n     * Used to keep track of spent outpoints, and\n     * detect and report conflicts (double-spends or\n     * mutated transactions where the mutant gets mined).\n     */\n    typedef std::multimap<COutPoint, uint256> TxSpends;\n    TxSpends mapTxSpends;\n    void AddToSpends(const COutPoint& outpoint, const uint256& wtxid);\n    void AddToSpends(const uint256& wtxid);\n\n    /* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */\n    void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);\n\n    void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);\n\n    /* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected.\n     * Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */\n    void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = NULL, int posInBlock = 0);\n\n    //int64_t nTimeFirstKey;\n\n    /**\n     * Private version of AddWatchOnly method which does not accept a\n     * timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if\n     * the watch key did not previously have a timestamp associated with it.\n     * Because this is an inherited virtual method, it is accessible despite\n     * being marked private, but it is marked private anyway to encourage use\n     * of the other AddWatchOnly which accepts a timestamp and sets\n     * nTimeFirstKey more intelligently for more efficient rescans.\n     */\n#if 0\n    bool AddWatchOnly(const CScript& dest) override;\n#endif\n\n    //std::unique_ptr<CWalletDBWrapper> dbw;\n\npublic:\n    /*\n     * Main wallet lock.\n     * This lock protects all the fields added by CWallet.\n     */\n    //mutable CCriticalSection cs_wallet;//Moved to base\n\n    /** Get database handle used by this wallet. Ideally this function would\n     * not be necessary.\n     */\n    CWalletDBWrapper& GetDBHandle()\n    {\n        return *dbw;\n    }\n\n    /** Get a name for this wallet for logging/debugging purposes.\n     */\n    std::string GetName() const\n    {\n        if (dbw) {\n            return dbw->GetName();\n        } else {\n            return \"dummy\";\n        }\n    }\n\n    void LoadKeyPool(int nIndex, const CKeyPool &keypool)\n    {\n        // If no metadata exists yet, create a default with the pool key's\n        // creation time. Note that this may be overwritten by actually\n        // stored metadata for that key later, which is fine.\n        CKeyID keyid = keypool.vchPubKey.GetID();\n        if (mapKeyMetadata.count(keyid) == 0)\n            mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);\n    }\n\n    std::map<CKeyID, CKeyMetadata> mapKeyMetadata;\n\n    typedef std::map<unsigned int, CMasterKey> MasterKeyMap;\n    MasterKeyMap mapMasterKeys;\n    unsigned int nMasterKeyMaxID;\n\n    // Create wallet with dummy database handle\n    CWallet();\n\n    // Create wallet with passed-in database handle\n    CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in);\n\n    ~CWallet();\n\n    void SetNull()\n    {\n        nWalletVersion = FEATURE_BASE;\n        nWalletMaxVersion = FEATURE_BASE;\n        nMasterKeyMaxID = 0;\n        pwalletdbEncryption = NULL;\n        nOrderPosNext = 0;\n        nAccountingEntryNumber = 0;\n        nNextResend = 0;\n        nLastResend = 0;\n        nTimeFirstKey = 0;\n        fBroadcastTransactions = false;\n        nRelockTime = 0;\n        fAbortRescan = false;\n        fScanningWallet = false;\n        activeAccount = NULL;\n        activeSeed = NULL;\n        nUnlockSessions = 0;\n        nUnlockedSessionsOwnedByShadow = 0;\n    }\n\n    std::map<uint256, CWalletTx> mapWallet;\n    std::map<uint256, uint256> mapWalletHash;\n    void maintainHashMap(const CWalletTx& wtxIn, uint256& hash);\n    /** Transaction hash from outpoint. Even if it is index based. */\n    bool GetTxHash(const COutPoint& outpoint, uint256& txHash) const;\n    std::list<CAccountingEntry> laccentries;\n\n    int64_t nOrderPosNext;\n    uint64_t nAccountingEntryNumber;\n    std::map<uint256, int> mapRequestCount;\n\n    std::map<std::string, CAddressBookData> mapAddressBook;\n\n    std::set<COutPoint> setLockedCoins;\n\n    const CWalletTx* GetWalletTx(const uint256& hash) const;\n    CWalletTx* GetWalletTx(const COutPoint& outpoint) const;\n\n    //! check whether we are allowed to upgrade (or already support) to the named feature\n    bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }\n\n    /**\n     * populate vCoins with vector of available COutputs.\n     */\n    void AvailableCoins(CAccount* forAccount, std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999) const;\n    void AvailableCoins(std::vector<CKeyStore*>& accountsToTry, std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999) const;\n\n    /**\n     * Return list of available coins and locked coins grouped by non-change output address.\n     */\n    std::map<CTxDestination, std::vector<COutput>> ListCoins(CAccount* forAccount) const;\n\n    /**\n     * Find non-change parent output.\n     */\n    const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const;\n\n    /**\n     * Shuffle and select coins until nTargetValue is reached while avoiding\n     * small change; This method is stochastic for some inputs and upon\n     * completion the coin set and corresponding actual target value is\n     * assembled\n     */\n    bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, bool allowIndexBased) const;\n\n    bool IsSpent(const COutPoint& outpoint) const;\n\n    bool IsLockedCoin(uint256 hash, unsigned int n) const;\n    void LockCoin(const COutPoint& output);\n    void UnlockCoin(const COutPoint& output);\n    void UnlockAllCoins();\n    void ListLockedCoins(std::vector<COutPoint>& vOutpts) const;\n    \n    // Checks for wallet vs. UTXO inconsistency; reports any spent state inconsistency found\n    void CompareWalletAgainstUTXO(int& nMismatchFound, int& nOrphansFound, int64_t& nBalanceInQuestio, bool attemptRepair=false);\n\n    // Clear all orphan transactions from wallet\n    bool RemoveAllOrphans(uint64_t& numErased, uint64_t& numDetected, std::string& strError);\n\n    /*\n     * Rescan abort properties\n     */\n    void AbortRescan() { fAbortRescan = true; }\n    bool IsAbortingRescan() { return fAbortRescan; }\n    bool IsScanning() { return fScanningWallet; }\n\n    /**\n     * keystore implementation\n     * Generate a new key\n     */\n    CPubKey GenerateNewKey(CAccount& forAccount, int keyChain);\n    //! Adds a key to the store, and saves it to disk.\n    bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, CAccount& forAccount, int keyChain);\n    //! Adds a key to the store, without saving it to disk (used by LoadWallet)\n    bool LoadKey(const CKey& key, const CPubKey &pubkey, const std::string& forAccount, int64_t nKeyChain);\n    //! Load metadata (used by LoadWallet)\n    bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);\n\n    bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }\n    void UpdateTimeFirstKey(int64_t nCreateTime);\n\n/*\n    //! Adds an encrypted key to the store, and saves it to disk.\n    bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override;\n*/\n    //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)\n    bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, const std::string& forAccount, int64_t nKeyChain);\n    bool AddCScript(const CScript& redeemScript);\n    bool LoadCScript(const CScript& redeemScript);\n\n    //! Adds a destination data tuple to the store, and saves it to disk\n    bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value);\n    //! Erases a destination data tuple in the store and on disk\n    bool EraseDestData(const CTxDestination &dest, const std::string &key);\n    //! Adds a destination data tuple to the store, without saving it to disk\n    bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value);\n    //! Look up a destination data tuple in the store, return true if found false otherwise\n    bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;\n    //! Get all destination values matching a prefix.\n    std::vector<std::string> GetDestValues(const std::string& prefix) const;\n\n    //! Adds a watch-only address to the store, and saves it to disk.\n    bool AddWatchOnly(const CScript &dest, int64_t nCreateTime);\n    bool RemoveWatchOnly(const CScript &dest);\n    //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)\n    bool LoadWatchOnly(const CScript &dest);\n\n    //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().\n    int64_t nRelockTime;\n\n    bool Unlock(const SecureString& strWalletPassphrase);\n    bool UnlockWithTimeout(const SecureString& strWalletPassphrase, int64_t lockTimeoutSeconds);\n    //fixme: (FUT) Handle this better with global scheduler (after we merge latest munt changes\n    private:\n    CScheduler* schedulerForLock=nullptr;\n    public:\n    bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);\n    bool EncryptWallet(const SecureString& strWalletPassphrase);\n\n    /**\n     * Begin an unlocked session. While at least one unlocked session is in progress the wallet cannot be locked.\n     * If a lock attempt is done during an unlocked session the wallet will be kept unlocked untill all unlocked sessions are done.\n     * Every BeginUnlocked() session must be closed by a matching EndUnlocked().\n     *\n     * If not already unlocked a passphrase request for unlocking is done using the reason passed.\n     * When unlock is succesfull the callback will be executed.\n     * If locked before the session begins the wallet will be locked again automatically when all sessions are finished.\n     *\n     * Note: while the previous Lock/Unlock still work their usage is discouraged. All new wallet unlocking should use this new API\n     * and over time usage of the old Lock/Unlock API is to be removed.\n     */\n    void BeginUnlocked(std::string reason, std::function<void (void)> callback);\n\n    /**\n     * Synchronous version of BeginUnlocked.\n     * @return Succesfully unlocked\n     */\n    bool BeginUnlocked(const SecureString& strWalletPassphrase);\n\n    /**\n     * End an unlocked session. When all unlocked session are ended automatically lock the wallet if it was locked when\n     * the first active unlock session began or if a lock request was made during a session.\n     */\n    void EndUnlocked();\n\n    void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;\n    unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;\n\n    //! Import a witness-only account from a URL\n    void importWitnessOnlyAccountFromURL(const SecureString& sKey, std::string sAccountName);\n\n    void importPrivKey(const SecureString& sKey, std::string sAccountName);\n    void importPrivKey(const CKey& privKey, std::string sAccountName);\n    bool importPrivKeyIntoAccount(CAccount* targetAccount, const CKey& privKey, const CKeyID& importKeyID, uint64_t keyBirthDate, bool allowRescan=true);\n    bool forceKeyIntoKeypool(CAccount* forAccount, const CKey& privKey);\n\n    /** \n     * Increment the next transaction order id\n     * @return next transaction order id\n     */\n    int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);\n    DBErrors ReorderTransactions();\n    bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = \"\");\n    bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false);\n\n    void MarkDirty();\n    bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true, bool fSelfComitted=false);\n    //NB! After calling this function one or more times 'HandleTransactionsLoaded' must be called as well for final processing\n    bool LoadToWallet(const CWalletTx& wtxIn);\n    // This function allows us to move work out of LoadToWallet and into a place where mapWalletHash is already fully populated\n    // As a result it performs massively faster on some wallets\n    // NB! This must be called after 'LoadToWallet' is called one or more times\n    void HandleTransactionsLoaded();\n    \n    void TransactionAddedToMempool(const CTransactionRef& tx) override;\n    void TransactionRemovedFromMempool( const uint256 &hash, MemPoolRemovalReason reason) override;\n    void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;\n    void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;\n    void ClearCacheForTransaction(const uint256& hash);\n    bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);\n    int GetTransactionScanProgressPercent();\n    int64_t RescanFromTime(int64_t startTime, bool update);\n    CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);\n    void ReacceptWalletTransactions();\n    std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);\n    void GetBalances(WalletBalances& balances, const CAccount* forAccount = nullptr, bool includeChildren=false) const;\n    CAmount GetBalanceForDepth(int minDepth, const CAccount* forAccount = nullptr, bool includePoW2LockedWitnesses=false, bool includeChildren=false) const;\n    CAmount GetBalance(const CAccount* forAccount = nullptr, bool useCache=true, bool includePoW2LockedWitnesses=false, bool includeChildren=false) const;\n    CAmount GetLockedBalance(const CAccount* forAccount = nullptr, bool includeChildren=false);\n    CAmount GetUnconfirmedBalance(const CAccount* forAccount = nullptr, bool includePoW2LockedWitnesses=false, bool includeChildren=false) const;\n    CAmount GetImmatureBalance(const CAccount* forAccount = nullptr, bool includePoW2LockedWitnesses=false, bool includeChildren=false) const;\n    CAmount GetWatchOnlyBalance(int minDepth=0, const CAccount* forAccount = nullptr, bool includeChildren=false) const;\n    CAmount GetUnconfirmedWatchOnlyBalance() const;\n    CAmount GetImmatureWatchOnlyBalance() const;\n    #if 0\n    CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const boost::uuids::uuid* accountUUID, bool includeChildren=false) const;\n    #endif\n    CAmount GetAvailableBalance(CAccount* forAccount, const CCoinControl* coinControl = nullptr) const;\n\n    //! Fund a transaction that is otherwise already created\n    // Where possible it is best to ensuire that all inputs of the transaction to be funded are constructed as index based (if they fit the criteria) instead of hash based\n    // Otherwise this can result in some obscure issues, see comments in function body for more witnessDetails\n    // The function automatically tries to take care of these issues but its better to avoid it having to do so entirely\n    bool FundTransaction(CAccount* fundingAccount, CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl, CReserveKeyOrScript& reservekey);\n\n    //! Sign a transaction that is already fully populated/funded\n    //! The transaction inputs must be in the wallet as SignTransaction will look these up and fail if the are not\n    //! For special cases of signing when not in wallet we provide prevOutOverride - however this only caters for one input to not be in the wallet...\n    bool SignTransaction(CAccount* fromAccount, CMutableTransaction& tx, SignType type, CTxOut* prevOutOverride=nullptr);\n\n    //! Create a transaction that renews an expired witness account\n    bool PrepareRenewWitnessAccountTransaction(CAccount* funderAccount, CAccount* targetWitnessAccount, CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, CAmount& nFeeOut, std::string& strError, uint64_t* skipPastTransaction=nullptr, CCoinControl* coinControl=nullptr);\n\n    //! Create a transaction upgrades an old ScriptLegacyOutput witness to a new PoW2WitnessOutput\n    void PrepareUpgradeWitnessAccountTransaction(CAccount* funderAccount, CAccount* targetWitnessAccount, CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, CAmount& nFeeOut);\n\n    /**\n     * Insert additional inputs into the transaction by\n     * calling CreateTransaction();\n     */\n    void AddTxInput(CMutableTransaction& tx, const CInputCoin& inputCoin, bool rbf);\n    void AddTxInputs(CMutableTransaction& tx, std::set<CInputCoin>& setCoins, bool rbf);\n\n    /**\n     * Create a new transaction paying the recipients with a set of coins\n     * selected by SelectCoins(); Also create the change output, when needed\n     * @note passing nChangePosInOut as -1 will result in setting a random position\n     */\n    bool CreateTransaction(std::vector<CKeyStore*>& accountsToTry, const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CAmount& nFeeRet, int& nChangePosInOut,\n                           std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);\n    bool CreateTransaction(CAccount* forAccount, const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CAmount& nFeeRet, int& nChangePosInOut,\n                           std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);\n\n    //! Used currently by the witnessing code to add the fee for a witness renewal transaction, and various other special operation transactions\n    bool AddFeeForTransaction(CAccount* forAccount, CMutableTransaction& txNew, CReserveKeyOrScript& reservekey, CAmount& nFeeOut, bool sign, std::string& strFailReason, const CCoinControl* coinControl);\n\n    /**\n     * Sign and submit a transaction (that has not yet been signed) to the network, add to wallet as appropriate etc.\n     */\n    bool SignAndSubmitTransaction(CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, std::string& strError, uint256* pTransactionHashOut=nullptr, SignType type=SignType::Spend);\n\n    bool CommitTransaction(CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CConnman* connman, CValidationState& state);\n\n    void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);\n    bool AddAccountingEntry(const CAccountingEntry&);\n    bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb);\n    template <typename ContainerType>\n    bool DummySignTx(std::vector<CKeyStore*>& accountsToTry, CMutableTransaction &txNew, const ContainerType &coins, SignType type) const;\n\n    static CFeeRate minTxFee;\n    static CFeeRate fallbackFee;\n    /**\n     * Estimate the minimum fee considering user set parameters\n     * and the required fee\n     */\n    static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, bool ignoreGlobalPayTxFee = false);\n    /**\n     * Return the minimum required fee taking into account the\n     * floating relay fee and user set minimum transaction fee\n     */\n    static CAmount GetRequiredFee(unsigned int nTxBytes);\n\n    bool NewKeyPool();\n    /*\n    size_t KeypoolCountExternalKeys();\n    */\n    int TopUpKeyPool(unsigned int nTargetKeypoolSize = 0, unsigned int nMaxNewAllocations = 0, CAccount* forAccount = nullptr, unsigned int nMinimalKeypoolOverride = 1);\n    void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, CAccount* forAccount, int64_t keyChain);\n    void KeepKey(int64_t nIndex);\n    void ReturnKey(int64_t nIndex, CAccount* forAccount, int64_t keyChain);\n    bool GetKeyFromPool(CPubKey &key, CAccount* forAccount, int64_t keyChain);\n    int64_t GetOldestKeyPoolTime();\n    void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;\n\n    std::set< std::set<CTxDestination> > GetAddressGroupings();\n    std::map<CTxDestination, CAmount> GetAddressBalances();\n\n    std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;\n\n    isminetype IsMine(const CTxIn& txin) const;\n    isminetype IsMine(const CTxOut& txout) const;\n    isminetype IsMineWitness(const CTxOut& txout) const;\n    /**\n     * Returns amount of debit if the input matches the\n     * filter, otherwise returns 0\n     */\n    CAmount GetDebit(const CTxIn& txin, const isminefilter& filter, CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetCredit(const CTxOut& txout, const isminefilter& filter, CAccount* forAccount=NULL, bool includeChildren=false) const;\n    bool IsChange(const CTxOut& txout) const;\n    CAmount GetChange(const CTxOut& txout) const;\n    bool IsMine(const CTransaction& tx) const;\n    /** should probably be renamed to IsRelevantToMe */\n    bool IsFromMe(const CTransaction& tx) const;\n    CAmount GetDebit(const CTransaction& tx, const isminefilter& filter, CAccount* forAccount=NULL) const;\n    /** Returns whether all of the inputs match the filter */\n    bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;\n    CAmount GetCredit(const CTransaction& tx, const isminefilter& filter, CAccount* forAccount=NULL) const;\n    CAmount GetChange(const CTransaction& tx) const;\n\n    DBErrors LoadWallet(WalletLoadState& nExtraLoadState);\n    DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);\n    DBErrors ZapSelectTx(CWalletDB& walletdb, std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);\n\n    bool SetAddressBook(const std::string& address, const std::string& strName, const std::string& strRecipientDescription, const std::string& purpose);\n\n    bool DelAddressBook(const std::string& address);\n\n    std::vector<CAccount*> FindAccountsForTransaction(const CTxOut& out);\n    CAccount* FindBestWitnessAccountForTransaction(const CTxOut& out);\n\n    // CValidationInterface updates\n    void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;\n    void SetBestChain(const CBlockLocator& loc) override;\n\n    void ScriptForMining(std::shared_ptr<CReserveKeyOrScript> &script, CAccount* forAccount) override;\n    void ScriptForWitnessing(std::shared_ptr<CReserveKeyOrScript> &script, CAccount* forAccount) override;\n\n    unsigned int GetKeyPoolSize()\n    {\n        AssertLockHeld(cs_wallet); // setKeyPool\n        int nPoolSize=0;\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            LOCK(forAccount->cs_keypool);\n            nPoolSize += forAccount->GetKeyPoolSize();\n        }\n        return nPoolSize;\n    }\n\n    //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower\n    bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);\n\n    //! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)\n    bool SetMaxVersion(int nVersion);\n\n    //! get the current wallet format (the oldest client version guaranteed to understand this wallet)\n    int GetVersion() { LOCK(cs_wallet); return nWalletVersion; }\n\n    //! Get wallet transactions that conflict with given transaction (spend same outputs)\n    std::set<uint256> GetConflicts(const uint256& txid) const;\n\n    //! Check if a given transaction has any of its outputs spent by another transaction in the wallet\n    bool HasWalletSpend(const uint256& txid) const;\n\n    //! Flush wallet (bitdb flush)\n    void Flush(bool shutdown=false);\n\n    //! Verify the wallet database and perform salvage if required\n    static bool Verify();\n\n    /** \n     * Address book entry changed.\n     * @note called with lock cs_wallet held.\n     */\n    boost::signals2::signal<void (CWallet *wallet, const std::string\n            &address, const std::string &label, bool isMine,\n            const std::string &purpose,\n            ChangeType status)> NotifyAddressBookChanged;\n\n    /** \n     * Wallet transaction added, removed or updated.\n     * @note called with lock cs_wallet held.\n     */\n    boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status, bool fSelfComitted)> NotifyTransactionChanged;\n\n    /** \n     * Wallet transaction depth in chain changed (only called up until depth 10)\n     * @note called with lock cs_wallet held.\n     */\n    boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx)> NotifyTransactionDepthChanged;\n\n    /** Show progress e.g. for rescan */\n    boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;\n\n    /** Watch-only address added */\n    boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;\n\n    /** A key pool was topped up with one or more keys. */\n    boost::signals2::signal<void ()> NotifyKeyPoolToppedUp;\n\n    /** Inquire whether this wallet broadcasts transactions. */\n    bool GetBroadcastTransactions() const { return fBroadcastTransactions; }\n    /** Set whether this wallet broadcasts transactions. */\n    void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }\n\n    /** Return whether transaction can be abandoned */\n    bool TransactionCanBeAbandoned(const uint256& hashTx) const;\n\n    /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */\n    bool AbandonTransaction(const uint256& hashTx);\n\n    /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */\n    bool MarkReplaced(const uint256& originalHash, const uint256& newHash);\n\n    /* Returns the wallets help message */\n    static std::string GetWalletHelpString(bool showDebug);\n\n    /* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */\n    static CWallet* CreateWalletFromFile(const std::string walletFile);\n    static bool InitLoadWallet();\n    static void CreateSeedAndAccountFromPhrase(CWallet* walletInstance);\n    static void CreateSeedAndAccountFromLink(CWallet *walletInstance);\n\n    /**\n     * Wallet post-init setup\n     * Gives the wallet a chance to register repetitive tasks and complete post-init tasks\n     */\n    void postInitProcess(CScheduler& scheduler);\n\n    /* Wallets parameter interaction */\n    static bool ParameterInteraction();\n\n    bool BackupWallet(const std::string& strDest);\n\n    const CBlockIndex* LastSPVBlockProcessed() const;\n\n    static void ResetUnifiedSPVProgressNotification();\n\n    /**\n     * Birthtime computed from wallet transactions\n     * If there are no transactions the tip of the known chain is used\n     * If birthtime cannot be succesfully computed it will return 0\n     */\n    int64_t birthTime() const;\n\n    void StartSPV();\n    void ResetSPV();\n\n    void EraseWalletSeedsAndAccounts();\n\nprotected:\n    void PruningConflictingBlock(const uint256& orphanBlockHash) override;\n\nprivate:\n    int nTransactionScanProgressPercent;\n\n    friend class CAccount;\n};\n\n\n// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)\n// ContainerType is meant to hold pair<CWalletTx *, int>, and be iterable\n// so that each entry corresponds to each vIn, in order.\ntemplate <typename ContainerType>\nbool CWallet::DummySignTx(std::vector<CKeyStore*>& accountsToTry, CMutableTransaction &txNew, const ContainerType &coins, SignType type) const\n{\n    // Fill in dummy signatures for fee calculation.\n    int nIn = 0;\n    for (const auto& coin : coins)\n    {\n        SignatureData sigdata;\n\n        if (!ProduceSignature(DummySignatureCreator(accountsToTry), coin.txout, sigdata, type, txNew.nVersion))\n        {\n            return false;\n        }\n        else\n        {\n            UpdateTransaction(txNew, nIn, sigdata);\n        }\n\n        nIn++;\n    }\n    return true;\n}\n#endif\n"
  },
  {
    "path": "src/wallet/wallet_init.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"alert.h\"\n\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"scheduler.h\"\n#include \"timedata.h\"\n#include \"util/moneystr.h\"\n#include \"init.h\"\n#include \"net_processing.h\"\n#include \"spvscanner.h\"\n#include <unity/appmanager.h>\n#include <wallet/mnemonic.h>\n#include <future>\n\nCWallet::CWallet()\n    : CExtWallet()\n{\n    SetNull();\n}\n\nCWallet::CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in)\n    : CExtWallet(std::move(dbw_in))\n{\n    SetNull();\n}\n\nCWallet::~CWallet()\n{\n    delete pwalletdbEncryption;\n    pwalletdbEncryption = NULL;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        delete forAccount;\n    }\n    for (const auto& [seedUUID, forSeed] : mapSeeds)\n    {\n        (unused) seedUUID;\n        delete forSeed;\n    }\n}\n\nDBErrors CWallet::LoadWallet(WalletLoadState& nExtraLoadState)\n{\n    nExtraLoadState = NEW_WALLET;\n    DBErrors nLoadWalletRet = CWalletDB(*dbw,\"cr+\").LoadWallet(this, nExtraLoadState);\n    if (nLoadWalletRet == DB_NEED_REWRITE)\n    {\n        if (dbw->Rewrite(\"\\x04pool\"))\n        {\n            LOCK(cs_wallet);\n            //fixme: (FUT) (ACCOUNTS)\n            for (const auto& [accountUUID, forAccount] : mapAccounts)\n            {\n                (unused) accountUUID;\n                forAccount->setKeyPoolInternal.clear();\n                forAccount->setKeyPoolExternal.clear();\n            }\n            // Note: can't top-up keypool here, because wallet is locked.\n            // User will be prompted to unlock wallet the next operation\n            // that requires a new key.\n        }\n    }\n\n    if (nLoadWalletRet != DB_LOAD_OK)\n        return nLoadWalletRet;\n\n    uiInterface.LoadWallet(this);\n\n    return DB_LOAD_OK;\n}\n\n//If we want to translate help messages in future we can replace helptr with _ and everything will just work.\n#define helptr(x) std::string(x)\n//If we want to translate error messages in future we can replace helptr with _ and everything will just work.\n#define errortr(x) std::string(x)\n//If we want to translate warning messages in future we can replace helptr with _ and everything will just work.\n#define warningtr(x) std::string(x)\n\nstd::string CWallet::GetWalletHelpString(bool showDebug)\n{\n    std::string strUsage = HelpMessageGroup(helptr(\"Wallet options:\"));\n    strUsage += HelpMessageOpt(\"-disablewallet\", helptr(\"Do not load the wallet and disable wallet RPC calls\"));\n    strUsage += HelpMessageOpt(\"-disableui\", helptr(\"Load the wallet in a special console only mode\"));\n    strUsage += HelpMessageOpt(\"-keypool=<n>\", strprintf(helptr(\"Set key pool size to <n> (default: %u)\"), DEFAULT_ACCOUNT_KEYPOOL_SIZE));\n    strUsage += HelpMessageOpt(\"-accountpool=<n>\", strprintf(helptr(\"Set account pool size to <n> (default: %u)\"), 10));\n    strUsage += HelpMessageOpt(\"-fallbackfee=<amt>\", strprintf(helptr(\"A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)\"),\n                                                               CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));\n    strUsage += HelpMessageOpt(\"-mintxfee=<amt>\", strprintf(helptr(\"Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)\"),\n                                                            CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));\n    strUsage += HelpMessageOpt(\"-paytxfee=<amt>\", strprintf(helptr(\"Fee (in %s/kB) to add to transactions you send (default: %s)\"),\n                                                            CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));\n    strUsage += HelpMessageOpt(\"-rescan\", helptr(\"Rescan the block chain for missing wallet transactions on startup\"));\n    strUsage += HelpMessageOpt(\"-salvagewallet\", helptr(\"Attempt to recover private keys from a corrupt wallet on startup\"));\n    strUsage += HelpMessageOpt(\"-spendzeroconfchange\", strprintf(helptr(\"Spend unconfirmed change when sending transactions (default: %u)\"), DEFAULT_SPEND_ZEROCONF_CHANGE));\n    strUsage += HelpMessageOpt(\"-txconfirmtarget=<n>\", strprintf(helptr(\"If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)\"), DEFAULT_TX_CONFIRM_TARGET));\n    strUsage += HelpMessageOpt(\"-usehd\", helptr(\"Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start\") + \" \" + strprintf(helptr(\"(default: %u)\"), DEFAULT_USE_HD_WALLET));\n    strUsage += HelpMessageOpt(\"-walletrbf\", strprintf(helptr(\"Send transactions with full-RBF opt-in enabled (default: %u)\"), DEFAULT_WALLET_RBF));\n    strUsage += HelpMessageOpt(\"-upgradewallet\", helptr(\"Upgrade wallet to latest format on startup\"));\n    strUsage += HelpMessageOpt(\"-wallet=<file>\", helptr(\"Specify wallet file (within data directory)\") + \" \" + strprintf(helptr(\"(default: %s)\"), DEFAULT_WALLET_DAT));\n    strUsage += HelpMessageOpt(\"-walletbroadcast\", helptr(\"Make the wallet broadcast transactions\") + \" \" + strprintf(helptr(\"(default: %u)\"), DEFAULT_WALLETBROADCAST));\n    strUsage += HelpMessageOpt(\"-walletnotify=<cmd>\", helptr(\"Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)\"));\n    strUsage += HelpMessageOpt(\"-zapwallettxes=<mode>\", helptr(\"Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup\") +\n                               \" \" + helptr(\"(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)\"));\n\n    if (showDebug)\n    {\n        strUsage += HelpMessageGroup(helptr(\"Wallet debugging/testing options:\"));\n\n        strUsage += HelpMessageOpt(\"-dblogsize=<n>\", strprintf(\"Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)\", DEFAULT_WALLET_DBLOGSIZE));\n        strUsage += HelpMessageOpt(\"-flushwallet\", strprintf(\"Run a thread to flush wallet periodically (default: %u)\", DEFAULT_FLUSHWALLET));\n        strUsage += HelpMessageOpt(\"-privdb\", strprintf(\"Sets the DB_PRIVATE flag in the wallet db environment (default: %u)\", DEFAULT_WALLET_PRIVDB));\n        strUsage += HelpMessageOpt(\"-walletrejectlongchains\", strprintf(helptr(\"Wallet will not create transactions that violate mempool chain limits (default: %u)\"), DEFAULT_WALLET_REJECT_LONG_CHAINS));\n    }\n\n    return strUsage;\n}\n\n//Assign the bare minimum keys here, let the rest take place in the background thread\nvoid PerformInitialMinimalKeyAllocation(CWallet* walletInstance)\n{\n    walletInstance->TopUpKeyPool(1);\n}\n\nvoid CWallet::CreateSeedAndAccountFromLink(CWallet *walletInstance)\n{\n    walletInstance->nTimeFirstKey = AppLifecycleManager::gApp->getLinkedBirthTime();\n\n    LogPrintf(\"%s: Creating new linked primary account, birth time [%d]\\n\", __func__, walletInstance->nTimeFirstKey);\n\n    walletInstance->activeAccount = walletInstance->CreateSeedlessHDAccount(\"My account\", AppLifecycleManager::gApp->getLinkedKey(), AccountState::Normal, AccountType::Mobi, false);\n\n    SecureString encryptUsingPassword = AppLifecycleManager::gApp->getRecoveryPassword();\n    if (encryptUsingPassword.length() > 0)\n    {\n        LogPrintf(\"Encrypting wallet using passphrase\\n\");\n        if (!walletInstance->EncryptWallet(encryptUsingPassword))\n            throw std::runtime_error(\"Failed to encrypt wallet\");\n        if (!walletInstance->Unlock(encryptUsingPassword))\n            throw std::runtime_error(\"Failed to unlock freshly encrypted wallet\");\n    }\n    // Write the primary account into wallet file\n    {\n        CWalletDB walletdb(*walletInstance->dbw);\n        if (!walletdb.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n        {\n            throw std::runtime_error(\"Writing legacy account failed\");\n        }\n        walletdb.WritePrimaryAccount(walletInstance->activeAccount);\n    }\n\n    // Assign initial keys to the wallet\n    PerformInitialMinimalKeyAllocation(walletInstance);\n\n    //SPV special case - we need to allocate all the addresses now already for better filtering.\n    if (GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        walletInstance->TopUpKeyPool(10);\n    }\n\n    AppLifecycleManager::gApp->SecureWipeRecoveryDetails();\n}\n\nCWallet* CWallet::CreateWalletFromFile(const std::string walletFile)\n{\n    // needed to restore wallet transaction meta data after -zapwallettxes\n    std::vector<CWalletTx> vWtx;\n\n    if (GetBoolArg(\"-zapwallettxes\", false)) {\n        uiInterface.InitMessage(_(\"Zapping all transactions from wallet...\"));\n\n        std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));\n        CWallet *tempWallet = new CWallet(std::move(dbw));\n        DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);\n        if (nZapWalletRet != DB_LOAD_OK) {\n            InitError(strprintf(errortr(\"Error loading %s: Wallet corrupted\"), walletFile));\n            return NULL;\n        }\n\n        delete tempWallet;\n        tempWallet = NULL;\n    }\n\n    uiInterface.InitMessage(_(\"Loading wallet...\"));\n\n    int64_t nStart = GetTimeMillis();\n    WalletLoadState loadState = NEW_WALLET;\n    std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));\n    CWallet *walletInstance = new CWallet(std::move(dbw));\n    DBErrors nLoadWalletRet = walletInstance->LoadWallet(loadState);\n    if (nLoadWalletRet != DB_LOAD_OK)\n    {\n        if (nLoadWalletRet == DB_CORRUPT)\n        {\n            InitError(strprintf(errortr(\"Error loading %s: Wallet corrupted\"), walletFile));\n            return NULL;\n        }\n        else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)\n        {\n            InitWarning(strprintf(warningtr(\"Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.\"),\n                walletFile));\n        }\n        else if (nLoadWalletRet == DB_TOO_NEW)\n        {\n            InitError(strprintf(errortr(\"Error loading %s: Wallet requires newer version of %s\"), walletFile, _(PACKAGE_NAME)));\n            return NULL;\n        }\n        else if (nLoadWalletRet == DB_NEED_REWRITE)\n        {\n            InitError(strprintf(errortr(\"Wallet needed to be rewritten: restart %s to complete\"), _(PACKAGE_NAME)));\n            return NULL;\n        }\n        else {\n            InitError(strprintf(errortr(\"Error loading %s\"), walletFile));\n            return NULL;\n        }\n    }\n\n    if (GetBoolArg(\"-upgradewallet\", loadState == NEW_WALLET))\n    {\n        int nMaxVersion = GetArg(\"-upgradewallet\", 0);\n        if (nMaxVersion == 0) // the -upgradewallet without argument case\n        {\n            LogPrintf(\"Performing wallet upgrade to %i\\n\", FEATURE_LATEST);\n            nMaxVersion = CLIENT_VERSION;\n            walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately\n        }\n        else\n            LogPrintf(\"Allowing wallet upgrade up to %i\\n\", nMaxVersion);\n        if (nMaxVersion < walletInstance->GetVersion())\n        {\n            InitError(errortr(\"Cannot downgrade wallet\"));\n            return NULL;\n        }\n        walletInstance->SetMaxVersion(nMaxVersion);\n    }\n\n    if (loadState == NEW_WALLET)\n    {\n        // Create new keyUser and set as default key\n        if (GetBoolArg(\"-usehd\", DEFAULT_USE_HD_WALLET))\n        {\n            if (fNoUI)\n            {\n                //fixme: (UNITY) (SPV) decide if we want to keep this option\n                if (IsArgSet(\"-phrase\")) {\n                    SecureString phrase(GetArg(\"-phrase\", \"\"));\n                    AppLifecycleManager::gApp->setCombinedRecoveryPhrase(phrase);\n                    LogPrintf(\"Using phrase argument for new wallet seed\\n\");\n                }\n                else if (AppLifecycleManager::gApp->getRecoveryPhrase().size() == 0)\n                {\n                    std::vector<unsigned char> entropy(16);\n                    GetStrongRandBytes(&entropy[0], 16);\n                    AppLifecycleManager::gApp->setRecoveryPhrase(mnemonicFromEntropy(entropy, entropy.size()*8));\n                    AppLifecycleManager::gApp->setRecoveryBirthTime(GetAdjustedTime());\n                }\n            }\n\n            if (AppLifecycleManager::gApp->getRecoveryPhrase().size() == 0)\n            {\n                //Work around an issue with \"non HD\" wallets from older versions where active account may not be set in the wallet.\n                if (!walletInstance->mapAccounts.empty()) {\n                    CWalletDB walletdb(*walletInstance->dbw);\n                    walletInstance->setActiveAccount(walletdb, walletInstance->mapAccounts.begin()->second);\n                }\n                throw std::runtime_error(\"Invalid seed mnemonic\");\n            }\n\n            if (AppLifecycleManager::gApp->isLink)\n            {\n                CreateSeedAndAccountFromLink(walletInstance);\n            }\n            else\n            {\n                CreateSeedAndAccountFromPhrase(walletInstance);\n            }\n        }\n        else\n        {\n            //fixme: (FUT) (MED) - encrypt at creation option here.\n            walletInstance->activeAccount = new CAccount();\n            walletInstance->activeAccount->m_State = AccountState::Normal;\n            walletInstance->activeAccount->m_Type = AccountType::Desktop;\n\n            // Write the primary account into wallet file\n            {\n                CWalletDB walletdb(*walletInstance->dbw);\n                if (!walletdb.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n                {\n                    throw std::runtime_error(\"Writing legacy account failed\");\n                }\n                walletdb.WritePrimaryAccount(walletInstance->activeAccount);\n            }\n\n            // Assign initial keys to the wallet\n            PerformInitialMinimalKeyAllocation(walletInstance);\n        }\n\n        pactiveWallet = walletInstance;\n        walletInstance->SetBestChain(chainActive.GetLocatorPoW2());\n    }\n    else if (loadState == EXISTING_WALLET_OLDACCOUNTSYSTEM)\n    {\n        // HD upgrade.\n        // Only perform upgrade if usehd is present (default for UI)\n        // For daemon we force users to choose (for exchanges etc.)\n        if (fNoUI)\n        {\n            if (!walletInstance->activeAccount->IsHD() && !walletInstance->activeSeed)\n            {\n                if (IsArgSet(\"-usehd\"))\n                {\n                    throw std::runtime_error(\"Must specify -usehd=1 or -usehd=0, in order to allow or refuse HD upgrade.\");\n                }\n            }\n        }\n\n        if (GetBoolArg(\"-usehd\", DEFAULT_USE_HD_WALLET))\n        {\n            if (!walletInstance->activeAccount->IsHD() && !walletInstance->activeSeed)\n            {\n                std::promise<void> promiseToUnlock;\n                walletInstance->BeginUnlocked(_(\"Wallet unlock required for wallet upgrade\"), [&]() {\n                    promiseToUnlock.set_value();\n                });\n                promiseToUnlock.get_future().wait();\n\n                bool walletWasCrypted = walletInstance->activeAccount->externalKeyStore.IsCrypted();\n                {\n                    LOCK(walletInstance->cs_wallet);\n\n                    // transfer unlock session ownership\n                    walletInstance->nUnlockedSessionsOwnedByShadow++;\n\n                    //Force old legacy account to resave\n                    {\n                        CWalletDB walletdb(*walletInstance->dbw);\n                        walletInstance->changeAccountName(walletInstance->activeAccount, _(\"Legacy account\"), true);\n                        if (!walletdb.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n                        {\n                            throw std::runtime_error(\"Writing legacy account failed\");\n                        }\n                        if (walletWasCrypted && !walletInstance->activeAccount->internalKeyStore.IsCrypted())\n                        {\n                            walletInstance->activeAccount->internalKeyStore.SetCrypted();\n                            bool needsWriteToDisk = false;\n                            walletInstance->activeAccount->internalKeyStore.Unlock(walletInstance->activeAccount->vMasterKey, needsWriteToDisk);\n                            if (needsWriteToDisk)\n                            {\n                                CWalletDB db(*dbw);\n                                if (!db.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n                                {\n                                    throw std::runtime_error(\"Writing account failed\");\n                                }\n                            }\n                        }\n                        walletInstance->ForceRewriteKeys(*walletInstance->activeAccount);\n                    }\n\n                    // Generate a new primary seed and account (BIP44)\n                    std::vector<unsigned char> entropy(16);\n                    GetStrongRandBytes(&entropy[0], 16);\n                    walletInstance->activeSeed = new CHDSeed(mnemonicFromEntropy(entropy, entropy.size()*8).c_str(), CHDSeed::CHDSeed::BIP44);\n                    if (!CWalletDB(*walletInstance->dbw).WriteHDSeed(*walletInstance->activeSeed))\n                    {\n                        throw std::runtime_error(\"Writing seed failed\");\n                    }\n                    if (walletWasCrypted)\n                    {\n                        if (!walletInstance->activeSeed->Encrypt(walletInstance->activeAccount->vMasterKey))\n                        {\n                            throw std::runtime_error(\"Encrypting seed failed\");\n                        }\n                    }\n                    walletInstance->mapSeeds[walletInstance->activeSeed->getUUID()] = walletInstance->activeSeed;\n                    {\n                        CWalletDB walletdb(*walletInstance->dbw);\n                        walletdb.WritePrimarySeed(*walletInstance->activeSeed);\n                    }\n                    walletInstance->activeAccount = walletInstance->GenerateNewAccount(_(\"My account\"), AccountState::Normal, AccountType::Desktop);\n                    {\n                        CWalletDB walletdb(*walletInstance->dbw);\n                        walletdb.WritePrimaryAccount(walletInstance->activeAccount);\n                    }\n                }\n            }\n        }\n        else\n        {\n            std::promise<void> promiseToUnlock;\n            walletInstance->BeginUnlocked(_(\"Wallet unlock required for wallet upgrade\"), [&]() {\n                promiseToUnlock.set_value();\n            });\n            promiseToUnlock.get_future().wait();\n\n            bool walletWasCrypted = walletInstance->activeAccount->externalKeyStore.IsCrypted();\n            {\n                LOCK(walletInstance->cs_wallet);\n\n                // transfer unlock session ownership\n                walletInstance->nUnlockedSessionsOwnedByShadow++;\n\n                //Force old legacy account to resave\n                {\n                    CWalletDB walletdb(*walletInstance->dbw);\n                    walletInstance->changeAccountName(walletInstance->activeAccount, _(\"Legacy account\"), true);\n                    if (!walletdb.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n                    {\n                        throw std::runtime_error(\"Writing legacy account failed\");\n                    }\n                    if (walletWasCrypted && !walletInstance->activeAccount->internalKeyStore.IsCrypted())\n                    {\n                        walletInstance->activeAccount->internalKeyStore.SetCrypted();\n                        bool needsWriteToDisk = false;\n                        walletInstance->activeAccount->internalKeyStore.Unlock(walletInstance->activeAccount->vMasterKey, needsWriteToDisk);\n                        if (needsWriteToDisk)\n                        {\n                            CWalletDB db(*dbw);\n                            if (!db.WriteAccount(getUUIDAsString(walletInstance->activeAccount->getUUID()), walletInstance->activeAccount))\n                            {\n                                throw std::runtime_error(\"Writing account failed\");\n                            }\n                        }\n                    }\n                    walletInstance->ForceRewriteKeys(*walletInstance->activeAccount);\n                }\n            }\n        }\n    }\n    else if (loadState == EXISTING_WALLET)\n    {\n        CAccount* firstAccount = nullptr;\n\n        //Detect any HD account seed gaps.\n        bool indexError=false;\n        for (const auto& accountType : {AccountType::Desktop, AccountType::Mobi, AccountType::PoW2Witness})\n        {\n            for (const auto& [seedUUID, seed] : walletInstance->mapSeeds)\n            {\n                (unused)seed;\n                std::set<uint64_t> allIndexes;\n                for(const auto& [accountUUID, account] : walletInstance->mapAccounts)\n                {\n                    if (account->m_Type != accountType)\n                        continue;\n\n                    (unused)accountUUID;\n                    if (account->IsHD() && dynamic_cast<CAccountHD*>(account)->getSeedUUID() == seedUUID)\n                    {\n                        uint64_t nIndex = dynamic_cast<CAccountHD*>(account)->getIndex();\n                        if (nIndex >= BIP32_HARDENED_KEY_LIMIT)\n                        {\n                            nIndex = nIndex & ~BIP32_HARDENED_KEY_LIMIT;\n                        }\n                        if (!firstAccount && nIndex == 0)\n                            firstAccount = account;\n                        allIndexes.insert(nIndex);\n                    }\n                }\n                if (allIndexes.size() > 0)\n                {\n                    uint64_t nStart = *allIndexes.begin();\n                    uint64_t nStartComp = 0;\n                    switch (accountType)\n                    {\n                        case AccountType::Desktop: nStartComp=0; break;\n                        case AccountType::Mobi: nStartComp=HDMobileStartIndex; break;\n                        case AccountType::PoW2Witness: nStartComp=HDWitnessStartIndex; break;\n                        default:\n                            //Do nothing.\n                            break;\n                    }\n                    if (nStart != nStartComp && nStart != nStartComp+1)\n                        indexError = true;\n                    if (!indexError)\n                    {\n                        std::set<uint64_t>::iterator setIter = allIndexes.begin();\n                        ++setIter;\n                        uint64_t index=1;\n                        for (;setIter != allIndexes.end();)\n                        {\n                            if (*setIter != nStart + index)\n                            {\n                                indexError = true;\n                            }\n                            ++index;\n                            ++setIter;\n                        }\n                    }\n                }\n            }\n        }\n        if (indexError)\n        {\n            std::string strErrorMessage = strprintf(\"Wallet contains an HD index error, this is not immediately dangerous but should be rectified as soon as possible, please contact a developer for assistance\");\n            CAlert::Notify(strErrorMessage, true, true);\n            LogPrintf(\"%s\", strErrorMessage.c_str());\n            uiInterface.ThreadSafeMessageBox(strErrorMessage,\"\", CClientUIInterface::MSG_ERROR);\n        }\n\n        //Clean up a slight issue in 1.6.0 -> 1.6.3 wallets where a \"usehd=0\" account was created but no active account set.\n        if (!walletInstance->activeAccount)\n        {\n            if (!walletInstance->mapAccounts.empty())\n            {\n                CWalletDB walletdb(*walletInstance->dbw);\n                walletInstance->setActiveAccount(walletdb, firstAccount ? firstAccount : walletInstance->mapAccounts.begin()->second);\n            }\n            else\n                throw std::runtime_error(\"Wallet contains no accounts, but is marked as upgraded.\");\n        }\n        //fixme: (FUT) (SPV) (LOW) - Remove this eventually\n        //Work around issue in early android SPV wallets where if there are multiple accounts we end up with the wrong one active somehow.\n        //We should remove this in the future, but only once we are sure it is fully solved.\n        else if(firstAccount && (GetBoolArg(\"-spv\", DEFAULT_SPV)) && walletInstance->activeAccount != firstAccount)\n        {\n            CWalletDB walletdb(*walletInstance->dbw);\n            walletInstance->setActiveAccount(walletdb, firstAccount);\n        }\n\n        //fixme: (FUT) Remove this in future\n        //Clean up an issue with some wallets that accidentally changed mining address, in 2.2.0.0 release.\n        {\n            LOCK(walletInstance->cs_wallet);\n            for (const auto& [accountUUID, forAccount] : walletInstance->mapAccounts)\n            {\n                if (forAccount->IsMiningAccount())\n                {\n                    LOCK(walletInstance->cs_wallet);\n                    CExtPubKey pubkey;\n                    if (static_cast<CAccountHD*>(forAccount)->GetPubKeyManual(0, KEYCHAIN_EXTERNAL, pubkey))\n                    {\n                        CWalletDB walletdb(*walletInstance->dbw);\n                        if (!walletdb.HasPool(walletInstance, pubkey.GetKey().GetID()))\n                        {\n                            LogPrintf(\"Restoring mining address for account [%s] to first address\\n\", forAccount->getLabel());\n                            \n                            // Find a unique *gap* in the current pool indexes\n                            // Needs to be a gap because we need it to be the lowest id key in the mining account\n                            // Note this isn't as bad as it looks, because most wallets will have a gap at quite low numbers if they've ever transacted at all\n                            // And small keypools if they have not\n                            int64_t nIndex = 1;\n                            bool foundGap=false;\n                            while (!foundGap)\n                            {\n                                foundGap = true;\n                                for (const auto& [loopAccountUUID, loopForAccount] : walletInstance->mapAccounts)\n                                {\n                                    (unused) loopAccountUUID;\n                                    for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n                                    {\n                                        auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? loopForAccount->setKeyPoolExternal : loopForAccount->setKeyPoolInternal );\n                                        for (const auto& item : keyPool)\n                                        {\n                                            if (item == nIndex)\n                                            {\n                                                ++nIndex;\n                                                foundGap = false;\n                                                break;\n                                            }\n                                        }\n                                        if (!foundGap)\n                                            break;\n                                    }\n                                    if (!foundGap)\n                                            break;\n                                }\n                            }\n                            auto& keyPool = forAccount->setKeyPoolExternal;\n                            walletdb.WritePool(++nIndex, CKeyPool(pubkey.GetKey(), getUUIDAsString(accountUUID), KEYCHAIN_EXTERNAL ));\n                            keyPool.insert(nIndex);\n                        }\n                    }    \n                }\n            }\n        }\n        \n        //Clean up an issue with some wallets that didn't delete one of the seeds correctly\n        if (walletInstance->IsCrypted() && walletInstance->mapSeeds.size() > 1)\n        {\n            bool anyFixed = true;\n            while (anyFixed)\n            {\n                anyFixed = false;\n                for (const auto& [seedUUID, seed] : walletInstance->mapSeeds)\n                {\n                    if (!seed->IsCrypted())\n                    {\n                        if (seed->m_type == CHDSeed::CHDSeed::BIP32 || seed->m_type == CHDSeed::CHDSeed::BIP32Legacy)\n                        {\n                            // Erase\n                            walletInstance->mapSeeds.erase(walletInstance->mapSeeds.find(seedUUID));\n                            if (!CWalletDB(*walletInstance->dbw).DeleteHDSeed(*seed))\n                            {\n                                throw std::runtime_error(\"Deleting seed failed\");\n                            }\n                            anyFixed = true;\n                            break;\n                        }\n                        else\n                        {\n                            std::string strErrorMessage = strprintf(\"Wallet contains a seed encryption error, this is not immediately dangerous but should be rectified as soon as possible, please contact a developer for assistance\");\n                            CAlert::Notify(strErrorMessage, true, true);\n                            LogPrintf(\"%s\", strErrorMessage.c_str());\n                            uiInterface.ThreadSafeMessageBox(strErrorMessage,\"\", CClientUIInterface::MSG_ERROR);\n                            anyFixed = false;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n    }\n    else\n    {\n        throw std::runtime_error(\"Unknown wallet load state.\");\n    }\n\n    if (AppLifecycleManager::gApp->isRecovery && AppLifecycleManager::gApp->getRecoveryBirthTime() == 0)\n    {\n        walletInstance->nTimeFirstKey = Params().GenesisBlock().nTime;\n    }\n\n    LogPrintf(\" wallet      %15dms\\n\", GetTimeMillis() - nStart);\n\n    RegisterValidationInterface(walletInstance);\n\n    CBlockIndex *pindexRescan = chainActive.Tip();\n    if (GetBoolArg(\"-rescan\", false) || AppLifecycleManager::gApp->isRecovery || AppLifecycleManager::gApp->isLink)\n    {\n        //fixme: (FUT) (SPV) rescan from latest checkpoint before nTimeFirstKey\n        pindexRescan = chainActive.Genesis();\n    }\n    else\n    {\n        CWalletDB walletdb(*walletInstance->dbw);\n        CBlockLocator locator;\n        if (walletdb.ReadBestBlock(locator))\n            pindexRescan = FindForkInGlobalIndex(chainActive, locator);\n    }\n    if (chainActive.Tip() && chainActive.Tip() != pindexRescan)\n    {\n        //We can't rescan beyond non-pruned blocks, stop and throw an error\n        //this might happen if a user uses a old wallet within a pruned node\n        // or if he ran -disablewallet for a longer time, then decided to re-enable\n        if (fPruneMode)\n        {\n            CBlockIndex *block = chainActive.Tip();\n            while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)\n                block = block->pprev;\n\n            if (pindexRescan != block) {\n                InitError(errortr(\"Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)\"));\n                return NULL;\n            }\n        }\n\n        uiInterface.InitMessage(_(\"Rescanning...\"));\n        LogPrintf(\"Rescanning last %i blocks (from block %i)...\\n\", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);\n        nStart = GetTimeMillis();\n        //fixme: (FUT) We have to set the active wallet early here otherwise we get a crash inside AddToWalletIfInvolvingMe via ScanForWalletTransactions as pActiveWallet is NULL.\n        //Normally active wallet would only be set after this function returns.\n        //Look into a re-architecture here.\n        pactiveWallet = walletInstance;\n        walletInstance->ScanForWalletTransactions(pindexRescan, true);\n        LogPrintf(\" rescan      %15dms\\n\", GetTimeMillis() - nStart);\n        walletInstance->SetBestChain(chainActive.GetLocatorPoW2());\n        walletInstance->dbw->IncrementUpdateCounter();\n\n        // Restore wallet transaction metadata after -zapwallettxes=1\n        if (GetBoolArg(\"-zapwallettxes\", false) && GetArg(\"-zapwallettxes\", \"1\") != \"2\")\n        {\n            CWalletDB walletdb(*walletInstance->dbw);\n\n            for(const CWalletTx& wtxOld : vWtx)\n            {\n                uint256 hash = wtxOld.GetHash();\n                std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);\n                if (mi != walletInstance->mapWallet.end())\n                {\n                    const CWalletTx* copyFrom = &wtxOld;\n                    CWalletTx* copyTo = &mi->second;\n                    copyTo->mapValue = copyFrom->mapValue;\n                    copyTo->vOrderForm = copyFrom->vOrderForm;\n                    copyTo->nTimeReceived = copyFrom->nTimeReceived;\n                    copyTo->nTimeSmart = copyFrom->nTimeSmart;\n                    copyTo->fFromMe = copyFrom->fFromMe;\n                    copyTo->strFromAccount = copyFrom->strFromAccount;\n                    copyTo->nOrderPos = copyFrom->nOrderPos;\n                    walletdb.WriteTx(*copyTo);\n                }\n            }\n        }\n    }\n    walletInstance->SetBroadcastTransactions(GetBoolArg(\"-walletbroadcast\", DEFAULT_WALLETBROADCAST));\n\n    {\n        LOCK(walletInstance->cs_wallet);\n        //fixme: (FUT) (ACCOUNTS) - 'key pool size' concept for wallet doesn't really make sense anymore.\n        LogPrintf(\"setKeyPool.size() = %u\\n\",      walletInstance->GetKeyPoolSize());\n        LogPrintf(\"mapWallet.size() = %u\\n\",       walletInstance->mapWallet.size());\n        LogPrintf(\"mapAddressBook.size() = %u\\n\",  walletInstance->mapAddressBook.size());\n    }\n\n    // Ensure we leave the wallet in a locked state\n    if (!walletInstance->IsLocked())\n    {\n        // However don't lock immediately let the shadow pool thread generate accounts still if it needs too\n        walletInstance->fAutoLock = true;\n        walletInstance->nUnlockSessions++;\n        walletInstance->nUnlockedSessionsOwnedByShadow++;\n    }\n\n    return walletInstance;\n}\n\nvoid CWallet::CreateSeedAndAccountFromPhrase(CWallet* walletInstance)\n{\n    // Generate a new primary seed and account (BIP44)\n    walletInstance->activeSeed = new CHDSeed(AppLifecycleManager::gApp->getRecoveryPhrase().c_str(), CHDSeed::CHDSeed::BIP44);\n    walletInstance->nTimeFirstKey = AppLifecycleManager::gApp->getRecoveryBirthTime();\n\n    SecureString encryptUsingPassword = AppLifecycleManager::gApp->getRecoveryPassword();\n    walletInstance->mapSeeds[walletInstance->activeSeed->getUUID()] = walletInstance->activeSeed;\n    if (encryptUsingPassword.length() > 0)\n    {\n        LogPrintf(\"Encrypting wallet using passphrase\\n\");\n        if (!walletInstance->EncryptWallet(encryptUsingPassword))\n            throw std::runtime_error(\"Failed to encrypt wallet\");\n        if (!walletInstance->Unlock(encryptUsingPassword))\n            throw std::runtime_error(\"Failed to unlock freshly encrypted wallet\");\n    }\n    walletInstance->activeAccount = walletInstance->GenerateNewAccount(\"My account\", AccountState::Normal, AccountType::Desktop);\n\n    // Now generate children shadow accounts to handle legacy transactions\n    // Only for recovery wallets though, new ones don't need them\n    #ifdef DJINNI_NODEJS\n    //fixme: (UNITY) We seem to unwittingly create these unnecessarily when creating new wallets (because we treat them as a \"recovery\")\n    if (!fSPV && AppLifecycleManager::gApp->isRecovery)\n    #else\n    if (AppLifecycleManager::gApp->isRecovery)\n    #endif\n    {\n        //fixme: (UNITY) (SPV) extract firstkeytime from recovery\n        //Temporary seeds for shadow children\n        CHDSeed* seedBip32 = new CHDSeed(AppLifecycleManager::gApp->getRecoveryPhrase().c_str(), CHDSeed::CHDSeed::BIP32);\n        CHDSeed* seedBip32Legacy = new CHDSeed(AppLifecycleManager::gApp->getRecoveryPhrase().c_str(), CHDSeed::CHDSeed::BIP32Legacy);\n\n        // If wallet is encrypted we need to encrypt the seeds (even though they are temporary) to ensure that they produce properly encrypted accounts.\n        if (walletInstance->IsCrypted())\n        {\n            if (!seedBip32->Encrypt(walletInstance->activeAccount->vMasterKey)) { throw std::runtime_error(\"Encrypting bip32 seed failed\"); }\n            if (!seedBip32Legacy->Encrypt(walletInstance->activeAccount->vMasterKey)) { throw std::runtime_error(\"Encrypting bip32-legacy seed failed\"); }\n        }\n\n        // Write new accounts\n        CAccountHD* newAccountBip32 = seedBip32->GenerateAccount(AccountType::Desktop, NULL);\n        newAccountBip32->m_State = AccountState::ShadowChild;\n        walletInstance->activeAccount->AddChild(newAccountBip32);\n        walletInstance->addAccount(newAccountBip32, \"BIP32 child account\");\n\n        // Write new accounts\n        CAccountHD* newAccountBip32Legacy = seedBip32Legacy->GenerateAccount(AccountType::Desktop, NULL);\n        newAccountBip32Legacy->m_State = AccountState::ShadowChild;\n        walletInstance->activeAccount->AddChild(newAccountBip32Legacy);\n        walletInstance->addAccount(newAccountBip32Legacy, \"BIP32 legacy child account\");\n\n        //NB! We intentionally delete these seeds we only want the one account from them (for backwards compatibility with old phones).\n        delete seedBip32Legacy;\n        delete seedBip32;\n    }\n\n    // Write the seed last so that account index changes are reflected\n    {\n        CWalletDB walletdb(*walletInstance->dbw);\n        if (!walletdb.WriteHDSeed(*walletInstance->activeSeed)) { throw std::runtime_error(\"Writing seed failed\"); }\n        if (!walletdb.WritePrimarySeed(*walletInstance->activeSeed)) { throw std::runtime_error(\"Writing primary seed failed\"); }\n        if (!walletdb.WritePrimaryAccount(walletInstance->activeAccount)) { throw std::runtime_error(\"Writing active account failed\"); }\n    }\n\n    AppLifecycleManager::gApp->SecureWipeRecoveryDetails();\n\n    // Assign initial keys to the wallet\n    PerformInitialMinimalKeyAllocation(walletInstance);\n\n    //SPV special case - we need to allocate all the addresses now already for better filtering.\n    if (GetBoolArg(\"-spv\", DEFAULT_SPV))\n    {\n        walletInstance->TopUpKeyPool(10);\n    }\n}\n\nbool CWallet::InitLoadWallet()\n{\n    LOCK(cs_main);\n\n    if (GetBoolArg(\"-disablewallet\", DEFAULT_DISABLE_WALLET)) {\n        LogPrintf(\"Wallet disabled!\\n\");\n        return true;\n    }\n\n    for (const std::string& walletFile : gArgs.GetArgs(\"-wallet\")) {\n        CWallet * const pwallet = CreateWalletFromFile(walletFile);\n        if (!pwallet) {\n            return false;\n        }\n        vpwallets.push_back(pwallet);\n        pactiveWallet = pwallet;\n    }\n\n    if (fSPV) {\n        for (CWallet* pwallet : vpwallets)\n            pwallet->StartSPV();\n    }\n\n    return true;\n}\n\nvoid CWallet::StartSPV()\n{\n    LOCK(cs_wallet);\n    auto scanner = std::make_unique<CSPVScanner>(*this);\n    if (scanner->StartScan())\n        pSPVScanner.swap(scanner);\n}\n\nvoid CWallet::ResetSPV()\n{\n    LOCK(cs_wallet);\n    if (pSPVScanner) {\n        pSPVScanner->ResetScan();\n        pSPVScanner->StartScan();\n    }\n}\n\nvoid CWallet::EraseWalletSeedsAndAccounts()\n{\n    LOCK2(cs_main, cs_wallet);\n\n    if (pSPVScanner)\n        pSPVScanner->ResetScan();\n\n    CWalletDB walletdb(*dbw);\n\n    // Purge all current accounts/seeds from the system\n    LogPrintf(\"EraseWalletSeedsAndAccounts: Begin purge seeds [%d]\", mapSeeds.size());\n    while (!mapSeeds.empty())\n    {\n        LogPrintf(\"EraseWalletSeedsAndAccounts: purge seed\");\n        DeleteSeed(walletdb, pactiveWallet->mapSeeds.begin()->second, true);\n    }\n    LogPrintf(\"EraseWalletSeedsAndAccounts: End purge seeds\");\n\n    LogPrintf(\"EraseWalletSeedsAndAccounts: Begin purge standalone accounts [%d]\", mapAccounts.size());\n    while (!mapAccounts.empty())\n    {\n        LogPrintf(\"EraseWalletSeedsAndAccounts: purge account\");\n        deleteAccount(walletdb, pactiveWallet->mapAccounts.begin()->second, true);\n    }\n    LogPrintf(\"EraseWalletSeedsAndAccounts: End purge standalone accounts\");\n\n    LogPrintf(\"EraseWalletSeedsAndAccounts: Begin purge masterkeys [%d]\", mapMasterKeys.size());\n    while (!mapMasterKeys.empty())\n    {\n        LogPrintf(\"EraseWalletSeedsAndAccounts: purge masterkey\");\n        walletdb.EraseMasterKey(mapMasterKeys.begin()->first);\n        mapMasterKeys.erase(mapMasterKeys.begin());\n    }\n    nMasterKeyMaxID = 0;\n    LogPrintf(\"EraseWalletSeedsAndAccounts: End purge masterkeys\");\n\n    walletdb.ErasePrimaryAccount();\n    walletdb.EraseLastSPVBlockProcessed();\n}\n\nvoid CWallet::ResetUnifiedSPVProgressNotification()\n{\n    // TODO refactor spv scanning out of wallet and into validation/net at some point\n    // this simplifies architecture a bit and avoids the weird responsibility split\n    // which for example leads to this funny bit in here where we need to iterate the wallets\n    // to get to the spvscannerS!\n\n    LOCK(cs_main);\n\n    for (CWallet* pwallet : vpwallets)\n    {\n        LOCK(pwallet->cs_wallet);\n        if (pwallet->pSPVScanner)\n            pwallet->pSPVScanner->ResetUnifiedProgressNotification();\n    }\n}\n\nstd::atomic<bool> CWallet::fFlushScheduled(false);\n\nvoid CWallet::postInitProcess(CScheduler& scheduler)\n{\n    schedulerForLock = &scheduler;\n\n    // Add wallet transactions that aren't already in a block to mempool\n    // Do this here as mempool requires genesis block to be loaded\n    ReacceptWalletTransactions();\n\n    // Run a thread to flush wallet periodically\n    if (!CWallet::fFlushScheduled.exchange(true)) {\n        scheduler.scheduleEvery(MaybeCompactWalletDB, std::chrono::milliseconds(500));\n    }\n}\n\nbool CWallet::ParameterInteraction()\n{\n    SoftSetArg(\"-wallet\", DEFAULT_WALLET_DAT);\n    const bool is_multiwallet = gArgs.GetArgs(\"-wallet\").size() > 1;\n\n    if (GetBoolArg(\"-disablewallet\", DEFAULT_DISABLE_WALLET))\n        return true;\n\n    if (GetBoolArg(\"-blocksonly\", DEFAULT_BLOCKSONLY) && SoftSetBoolArg(\"-walletbroadcast\", false)) {\n        LogPrintf(\"%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\\n\", __func__);\n    }\n\n    if (GetBoolArg(\"-salvagewallet\", false) && SoftSetBoolArg(\"-rescan\", true)) {\n        if (is_multiwallet) {\n            return InitError(strprintf(\"%s is only allowed with a single wallet file\", \"-salvagewallet\"));\n        }\n        // Rewrite just private keys: rescan to find transactions\n        LogPrintf(\"%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\\n\", __func__);\n    }\n\n    // -zapwallettx implies a rescan\n    if (GetBoolArg(\"-zapwallettxes\", false) && SoftSetBoolArg(\"-rescan\", true)) {\n        if (is_multiwallet) {\n            return InitError(strprintf(\"%s is only allowed with a single wallet file\", \"-zapwallettxes\"));\n        }\n        LogPrintf(\"%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\\n\", __func__);\n    }\n\n    if (is_multiwallet) {\n        if (GetBoolArg(\"-upgradewallet\", false)) {\n            return InitError(strprintf(\"%s is only allowed with a single wallet file\", \"-upgradewallet\"));\n        }\n    }\n\n    if (GetBoolArg(\"-sysperms\", false))\n        return InitError(\"-sysperms is not allowed in combination with enabled wallet functionality\");\n    if (GetArg(\"-prune\", 0) && GetBoolArg(\"-rescan\", false))\n        return InitError(errortr(\"Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.\"));\n\n    if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)\n        InitWarning(AmountHighWarn(\"-minrelaytxfee\") + \" \" + warningtr(\"The wallet will avoid paying less than the minimum relay fee.\"));\n\n    if (IsArgSet(\"-mintxfee\"))\n    {\n        CAmount n = 0;\n        if (!ParseMoney(GetArg(\"-mintxfee\", \"\"), n) || 0 == n)\n            return InitError(AmountErrMsg(\"mintxfee\", GetArg(\"-mintxfee\", \"\")));\n        if (n > HIGH_TX_FEE_PER_KB)\n            InitWarning(AmountHighWarn(\"-mintxfee\") + \" \" + warningtr(\"This is the minimum transaction fee you pay on every transaction.\"));\n        CWallet::minTxFee = CFeeRate(n);\n    }\n    if (IsArgSet(\"-fallbackfee\"))\n    {\n        CAmount nFeePerK = 0;\n        if (!ParseMoney(GetArg(\"-fallbackfee\", \"\"), nFeePerK))\n            return InitError(strprintf(warningtr(\"Invalid amount for -fallbackfee=<amount>: '%s'\"), GetArg(\"-fallbackfee\", \"\")));\n        if (nFeePerK > HIGH_TX_FEE_PER_KB)\n            InitWarning(AmountHighWarn(\"-fallbackfee\") + \" \" + warningtr(\"This is the transaction fee you may pay when fee estimates are not available.\"));\n        CWallet::fallbackFee = CFeeRate(nFeePerK);\n    }\n    if (IsArgSet(\"-paytxfee\"))\n    {\n        CAmount nFeePerK = 0;\n        if (!ParseMoney(GetArg(\"-paytxfee\", \"\"), nFeePerK))\n            return InitError(AmountErrMsg(\"paytxfee\", GetArg(\"-paytxfee\", \"\")));\n        if (nFeePerK > HIGH_TX_FEE_PER_KB)\n            InitWarning(AmountHighWarn(\"-paytxfee\") + \" \" + warningtr(\"This is the transaction fee you will pay if you send a transaction.\"));\n\n        payTxFee = CFeeRate(nFeePerK, 1000);\n        if (payTxFee < ::minRelayTxFee)\n        {\n            return InitError(strprintf(errortr(\"Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)\"),\n                                       GetArg(\"-paytxfee\", \"\"), ::minRelayTxFee.ToString()));\n        }\n    }\n    if (IsArgSet(\"-maxtxfee\"))\n    {\n        CAmount nMaxFee = 0;\n        if (!ParseMoney(GetArg(\"-maxtxfee\", \"\"), nMaxFee))\n            return InitError(AmountErrMsg(\"maxtxfee\", GetArg(\"-maxtxfee\", \"\")));\n        if (nMaxFee > HIGH_MAX_TX_FEE)\n            InitWarning(warningtr(\"-maxtxfee is set very high! Fees this large could be paid on a single transaction.\"));\n        maxTxFee = nMaxFee;\n        if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)\n        {\n            return InitError(strprintf(errortr(\"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)\"),\n                                       GetArg(\"-maxtxfee\", \"\"), ::minRelayTxFee.ToString()));\n        }\n    }\n    nTxConfirmTarget = GetArg(\"-txconfirmtarget\", DEFAULT_TX_CONFIRM_TARGET);\n    bSpendZeroConfChange = GetBoolArg(\"-spendzeroconfchange\", DEFAULT_SPEND_ZEROCONF_CHANGE);\n    fWalletRbf = GetBoolArg(\"-walletrbf\", DEFAULT_WALLET_RBF);\n\n    if (GetBoolArg(\"-spv\", DEFAULT_SPV)) {\n        fSPV = true;\n        // When using SPV we don't want normal block download to happen when syncing headers, it could delay SPV scanning\n        PreventBlockDownloadDuringHeaderSync(true);\n    }\n\n    return true;\n}\n\nbool CWallet::BackupWallet(const std::string& strDest)\n{\n    return dbw->Backup(strDest);\n}\n"
  },
  {
    "path": "src/wallet/wallet_ismine.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"scheduler.h\"\n#include \"timedata.h\"\n#include \"util/moneystr.h\"\n#include \"init.h\"\n#include <unity/appmanager.h>\n#include <script/ismine.h>\n\nisminetype CWallet::IsMine(const CTxIn &txin) const\n{\n    {\n        LOCK(cs_wallet);\n        const CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n        if (prev)\n        {\n            if (txin.GetPrevOut().n < prev->tx->vout.size())\n                return IsMine(prev->tx->vout[txin.GetPrevOut().n]);\n        }\n    }\n    return ISMINE_NO;\n}\n\nisminetype CWallet::IsMine(const CTxOut& txout) const\n{\n    return ::IsMine(*this, txout);\n}\n\nisminetype CWallet::IsMineWitness(const CTxOut& txout) const\n{\n    return ::IsMineWitness(*this, txout);\n}\n\nbool CWallet::IsMine(const CTransaction& tx) const\n{\n    for(const CTxOut& txout : tx.vout)\n        if (IsMine(txout))\n            return true;\n    return false;\n}\n\nbool CWallet::IsFromMe(const CTransaction& tx) const\n{\n    return (GetDebit(tx, ISMINE_ALL) > 0);\n}\n\nbool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const\n{\n    LOCK(cs_wallet);\n\n    for(const CTxIn& txin : tx.vin)\n    {\n        const CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n        if (!prev)\n            return false; // any unknown inputs can't be from us\n\n        if (txin.GetPrevOut().n >= prev->tx->vout.size())\n            return false; // invalid input!\n\n        if (!(IsMine(prev->tx->vout[txin.GetPrevOut().n]) & filter))\n            return false;\n    }\n    return true;\n}\n\nint CWallet::GetTransactionScanProgressPercent()\n{\n    return nTransactionScanProgressPercent;\n}\n\n/**\n * Scan active chain for relevant transactions after importing keys. This should\n * be called whenever new keys are added to the wallet, with the oldest key\n * creation time.\n *\n * @return Earliest timestamp that could be successfully scanned from. Timestamp\n * returned will be higher than startTime if relevant blocks could not be read.\n */\nint64_t CWallet::RescanFromTime(int64_t startTime, bool update)\n{\n    // Find starting block. May be null if nCreateTime is greater than the\n    // highest blockchain timestamp, in which case there is nothing that needs\n    // to be scanned.\n    CBlockIndex* startBlock = nullptr;\n    {\n        LOCK(cs_main);\n        startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);\n        LogPrintf(\"%s: Rescanning last %i blocks\\n\", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);\n    }\n\n    if (startBlock)\n    {\n        const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);\n        if (failedBlock)\n        {\n            return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;\n        }\n    }\n    return startTime;\n}\n\n/**\n * Scan the block chain (starting in pindexStart) for transactions\n * from or to us. If fUpdate is true, found transactions that already\n * exist in the wallet will be updated.\n *\n * Returns null if scan was successful. Otherwise, if a complete rescan was not\n * possible (due to pruning or corruption), returns pointer to the most recent\n * block that could not be scanned.\n */\nCBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)\n{\n    int64_t nNow = GetTime();\n\n    CBlockIndex* pindex = pindexStart;\n    CBlockIndex* ret = nullptr;\n    {\n        LOCK2(cs_main, cs_wallet); // Required for ReadBlockFromDisk.\n        fAbortRescan = false;\n        fScanningWallet = true;\n\n        // no need to read and scan block, if block was created before\n        // our wallet birthday (as adjusted for block time variability)\n        // NB! nTimeFirstKey > TIMESTAMP_WINDOW check is important otherwise we overflow nTimeFirstKey\n        while (pindex && (nTimeFirstKey > TIMESTAMP_WINDOW) && (pindex->GetBlockTime() < (int64_t)(nTimeFirstKey - TIMESTAMP_WINDOW)))\n            pindex = chainActive.Next(pindex);\n\n        nTransactionScanProgressPercent = 0;\n        ShowProgress(_(\"Rescanning...\"), nTransactionScanProgressPercent); // show rescan progress in GUI, if -rescan on startup\n        if (!pindex)\n        {\n            LogPrintf(\"Nothing to do for rescan, chain empty.\\n\");\n            return ret;\n        }\n        LogPrintf(\"Rescanning...\\n\");\n        uint64_t nProgressStart = pindex->nHeight;\n        uint64_t nProgressTip = chainActive.Tip()->nHeight;\n        uint64_t nWorkQuantity = nProgressTip - nProgressStart;\n        while (pindex && !fAbortRescan && nWorkQuantity > 0)\n        {\n            // Temporarily release lock to allow shadow key allocation a chance to do it's thing\n            LEAVE_CRITICAL_SECTION(cs_wallet)\n            LEAVE_CRITICAL_SECTION(cs_main)\n            nTransactionScanProgressPercent = ((pindex->nHeight-nProgressStart) / (double)(nWorkQuantity)) * 100;\n            nTransactionScanProgressPercent = std::max(1, std::min(99, nTransactionScanProgressPercent));\n            if (pindex->nHeight % 100 == 0 && nProgressTip - nProgressStart > 0)\n            {\n                ShowProgress(_(\"Rescanning...\"), nTransactionScanProgressPercent);\n            }\n            if (GetTime() >= nNow + 60) {\n                nNow = GetTime();\n                LogPrintf(\"Still rescanning. At block %d. Progress=%d%%\\n\", pindex->nHeight, nTransactionScanProgressPercent);\n            }\n            ENTER_CRITICAL_SECTION(cs_main)\n            ENTER_CRITICAL_SECTION(cs_wallet)\n\n            if (ShutdownRequested())\n                return ret;\n\n            CBlock block;\n            if (ReadBlockFromDisk(block, pindex, Params())) {\n                for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {\n                    AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate);\n                }\n            } else {\n                ret = pindex;\n            }\n            pindex = chainActive.Next(pindex);\n        }\n        if (pindex && fAbortRescan) {\n            LogPrintf(\"Rescan aborted at block %d. Progress=%f\\n\", pindex->nHeight, GuessVerificationProgress(pindex));\n        }\n        nTransactionScanProgressPercent = 100;\n        ShowProgress(_(\"Rescanning...\"), nTransactionScanProgressPercent); // hide progress dialog in GUI\n\n        fScanningWallet = false;\n    }\n    LogPrintf(\"Rescan done.\\n\");\n    return ret;\n}\n"
  },
  {
    "path": "src/wallet/wallet_keypool.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n#include \"wallet/wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"alert.h\"\n\n#include \"validation/validation.h\"\n#include \"net.h\"\n#include \"scheduler.h\"\n#include \"timedata.h\"\n#include \"util/moneystr.h\"\n#include \"init.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"witnessutil.h\"\n\n/**\n * Mark old keypool keys as used,\n * and generate all new keys\n */\nbool CWallet::NewKeyPool()\n{\n    LogPrintf(\"keypool - newkeypool\\n\");\n    {\n        LOCK(cs_wallet);\n        CWalletDB walletdb(*dbw);\n\n        for (const auto& [accountUUID, forAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if(!forAccount->IsHD())\n            {\n                for(int64_t nIndex : forAccount->setKeyPoolInternal)\n                    walletdb.ErasePool(this, nIndex);\n                for(int64_t nIndex : forAccount->setKeyPoolExternal)\n                    walletdb.ErasePool(this, nIndex);\n\n                forAccount->setKeyPoolInternal.clear();\n                forAccount->setKeyPoolExternal.clear();\n            }\n        }\n\n        if (IsLocked())\n            return false;\n\n        //Nothing else to do - the shadow thread will take care of the rest.\n    }\n    return true;\n}\n\n//fixme: (FUT) (ACCOUNTS) MUNT Note for HD this should actually care more about maintaining a gap above the last used address than it should about the size of the pool.\nint CWallet::TopUpKeyPool(unsigned int nTargetKeypoolSize, unsigned int nMaxNewAllocations, CAccount* topupForAccount, unsigned int nMinimalKeypoolOverride)\n{\n    // Return -1 if we fail to allocate any -and- one of the accounts is not HD -and- it is locked.\n    uint32_t nNew = 0;\n    bool bAnyNonHDAccountsLockedAndRequireKeys = false;\n\n    // enclosed in block to ensure that NotifyKeyPoolToppedUp (at end) is called outside the locks\n    {\n        LOCK2(cs_main, cs_wallet);\n\n        CWalletDB walletdb(*dbw);\n\n        // Top up key pool\n        uint32_t nAccountTargetSize;\n        if (nTargetKeypoolSize > 0)\n            nAccountTargetSize = nTargetKeypoolSize;\n        else\n            nAccountTargetSize = GetArg(\"-keypool\", 5);\n\n        //Find current unique highest key index across *all* keypools.\n        int64_t nIndex = 1;\n        for (const auto& [accountUUID, loopForAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n            {\n                auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? loopForAccount->setKeyPoolExternal : loopForAccount->setKeyPoolInternal );\n                if (!keyPool.empty())\n                    nIndex = std::max( nIndex, *(--keyPool.end()) + 1 );\n            }\n        }\n\n        for (const auto& [accountUUID, loopForAccount] : mapAccounts)\n        {\n            if ( (topupForAccount == nullptr) || (topupForAccount->getUUID() == accountUUID) )\n            {\n                // If account uses a fixed keypool then never generate new keys to add to it.\n                // NB! This is one of the few places where IsMinimalKeyPool differed from IsFixedKeyPool - we do still generate new addresses for IsMinimalKeyPool (though we keep the size at 1)\n                if (loopForAccount->IsFixedKeyPool())\n                    continue;\n\n                uint32_t nFinalAccountTargetSize = nAccountTargetSize;\n                if (loopForAccount->IsMinimalKeyPool())\n                {\n                    nFinalAccountTargetSize = nMinimalKeypoolOverride;\n                }\n\n                for (auto& keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n                {\n                    auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? loopForAccount->setKeyPoolExternal : loopForAccount->setKeyPoolInternal );\n                    while (keyPool.size() < nFinalAccountTargetSize && (nMaxNewAllocations == 0 || nNew < nMaxNewAllocations))\n                    {\n                        // We can't allocate any keys here if we are a non HD account that is locked - so don't and instead just signal to caller that there is an issue.\n                        if (!loopForAccount->IsHD() && loopForAccount->IsLocked())\n                        {\n                            bAnyNonHDAccountsLockedAndRequireKeys = true;\n                            break;\n                        }\n                        else\n                        {\n                            if (!walletdb.WritePool( ++nIndex, CKeyPool(GenerateNewKey(*loopForAccount, keyChain), getUUIDAsString(accountUUID), keyChain ) ) )\n                                throw std::runtime_error(std::string(__func__) + \": writing generated key failed\");\n                            keyPool.insert(nIndex);\n                            LogPrintf(\"keypool [%s:%s] added key %d, size=%u\\n\", loopForAccount->getLabel(), (keyChain == KEYCHAIN_CHANGE ? \"change\" : \"external\"), nIndex, keyPool.size());\n\n                            // Limit generation for this loop, keeping count using nNew - rest will be generated later\n                            ++nNew;\n                        }\n                    }\n                }\n            }\n        }\n    }\n    if (bAnyNonHDAccountsLockedAndRequireKeys && (nNew == 0))\n        return -1;\n\n    if (nNew > 0)\n        NotifyKeyPoolToppedUp();\n\n    return nNew;\n}\n\nvoid CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypoolentry, CAccount* forAccount, int64_t keyChain)\n{\n    nIndex = -1;\n    keypoolentry.vchPubKey = CPubKey();\n    {\n        LOCK2(cs_main, cs_wallet);\n\n        if (!IsLocked())\n            TopUpKeyPool(1, 0, forAccount);//Only assign the bare minimum here, let the background thread do the rest.\n\n        auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? forAccount->setKeyPoolExternal : forAccount->setKeyPoolInternal );\n\n        // Get the oldest key\n        if(keyPool.empty())\n            return;\n\n        CWalletDB walletdb(*dbw);\n\n        nIndex = *(keyPool.begin());\n        // If account uses a fixed or minimal keypool then never remove keys from it.\n        if (!forAccount->IsFixedKeyPool() && !forAccount->IsMinimalKeyPool())\n        {\n            keyPool.erase(keyPool.begin());\n        }\n        if (!walletdb.ReadPool(nIndex, keypoolentry))\n            throw std::runtime_error(std::string(__func__) + \": read failed\");\n        if (!forAccount->HaveKey(keypoolentry.vchPubKey.GetID()))\n            throw std::runtime_error(std::string(__func__) + \": unknown key in key pool\");\n        assert(keypoolentry.vchPubKey.IsValid());\n        LogPrintf(\"keypool reserve %d\\n\", nIndex);\n    }\n}\n\nvoid CWallet::KeepKey(int64_t nIndex)\n{\n    // Remove from key pool\n    CWalletDB walletdb(*dbw);\n    walletdb.ErasePool(this, nIndex);\n    LogPrintf(\"keypool keep %d\\n\", nIndex);\n}\n\n//fixme: (FUT) (ACCOUNTS) - We should handle this MarkKeyUsed case better, have it broadcast an event to all reserve keys or something.\n//And then remove the disk check below\nvoid CWallet::ReturnKey(int64_t nIndex, CAccount* forAccount, int64_t keyChain)\n{\n    // Return to key pool - but only if it hasn't been used in the interim (If MarkKeyUsed has removed it from disk in the meantime then we don't return it)\n    CKeyPool keypoolentry;\n\n    CWalletDB walletdb(*dbw);\n    if (!walletdb.ReadPool(nIndex, keypoolentry))\n    {\n        LogPrintf(\"keypool return - aborted as key already used %d\\n\", nIndex);\n        return;\n    }\n\n    {\n        LOCK(cs_wallet);\n        auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? forAccount->setKeyPoolExternal : forAccount->setKeyPoolInternal );\n        keyPool.insert(nIndex);\n    }\n    LogPrintf(\"keypool return %d\\n\", nIndex);\n}\n\nbool CWallet::GetKeyFromPool(CPubKey& result, CAccount* forAccount, int64_t keyChain)\n{\n    CKeyPool keypool;\n    {\n        LOCK(cs_wallet);\n        int64_t nIndex = 0;\n        ReserveKeyFromKeyPool(nIndex, keypool, forAccount, keyChain);\n        if (nIndex == -1 )\n        {\n            // If account uses a fixed or minimal keypool then never generate new keys for it here\n            // In the case of minimal keypools we do allow generation, but only when explicitely requested by the user\n            if (!forAccount->IsFixedKeyPool() && !forAccount->IsMinimalKeyPool())\n            {\n                if (IsLocked()) return false;\n                result = GenerateNewKey(*forAccount, keyChain);\n                return true;\n            }\n        }\n        KeepKey(nIndex);\n        result = keypool.vchPubKey;\n    }\n    return true;\n}\n\nint64_t CWallet::GetOldestKeyPoolTime()\n{\n    LOCK(cs_wallet);\n\n\n    // load oldest key from keypool, get time and return\n    CKeyPool keypoolentry;\n    CWalletDB walletdb(*dbw);\n\n    // if the keypool is empty, return <NOW>\n    int64_t nTime = GetTime();\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            const auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? forAccount->setKeyPoolExternal : forAccount->setKeyPoolInternal );\n            if(!keyPool.empty())\n            {\n                int64_t nIndex = *(keyPool.begin());\n                if (!walletdb.ReadPool(nIndex, keypoolentry))\n                throw std::runtime_error(std::string(__func__) + \": read oldest key in keypool failed\");\n                assert(keypoolentry.vchPubKey.IsValid());\n                nTime = std::min(nTime, keypoolentry.nTime);\n            }\n        }\n    }\n    return nTime;\n}\n\nvoid CWallet::importWitnessOnlyAccountFromURL(const SecureString& sKey, const std::string sAccountName)\n{\n    //fixme: (PHASE5) Handle error here more appropriately etc.\n    std::vector<std::pair<CKey, uint64_t>> keysAndBirthDates;\n    bool urlError = false;\n    try\n    {\n        keysAndBirthDates = ParseWitnessKeyURL(sKey.c_str());\n        if (keysAndBirthDates.empty())\n        {\n            urlError = true;\n        }\n    }\n    catch(...)\n    {\n        urlError = true;\n    }\n    if (urlError)\n    {\n        std::string strErrorMessage = _(\"Invalid witness URL\");\n        LogPrintf(strErrorMessage.c_str());\n        CAlert::Notify(strErrorMessage, true, true);\n        return;\n    }\n\n    CreateWitnessOnlyWitnessAccount(sAccountName, keysAndBirthDates);\n}\n\nvoid CWallet::importPrivKey(const SecureString& sKey, std::string sAccountName)\n{\n    CEncodedSecretKey vchSecret;\n    bool fGood = vchSecret.SetString(sKey.c_str());\n\n    if (fGood)\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n\n        CKey privKey = vchSecret.GetKey();\n        if (!privKey.IsValid())\n        {\n            std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + _(\"Invalid private key.\");\n            LogPrintf(strErrorMessage.c_str());\n            CAlert::Notify(strErrorMessage, true, true);\n            return;\n        }\n\n        importPrivKey(privKey, sAccountName);\n    }\n}\n\nvoid CWallet::importPrivKey(const CKey& privKey, std::string sAccountName)\n{\n    CPubKey pubkey = privKey.GetPubKey();\n    assert(privKey.VerifyPubKey(pubkey));\n\n    CKeyID importKeyID = pubkey.GetID();\n\n    //Don't import an address that is already in wallet.\n    if (pactiveWallet->HaveKey(importKeyID))\n    {\n        std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + _(\"Wallet already contains key.\");\n        LogPrintf(strErrorMessage.c_str());\n        CAlert::Notify(strErrorMessage, true, true);\n        return;\n    }\n\n    CAccount* newAccount = new CAccount();\n    newAccount->m_Type = ImportedPrivateKeyAccount;\n\n    if (IsCrypted())\n    {\n        if (IsLocked())\n        {\n            std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + (\"Wallet locked.\");\n            LogPrintf(strErrorMessage.c_str());\n            CAlert::Notify(strErrorMessage, true, true);\n        }\n\n        if (!activeAccount)\n        {\n            std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + (\"Unable to obtain encyption key.\");\n            LogPrintf(strErrorMessage.c_str());\n            CAlert::Notify(strErrorMessage, true, true);\n        }\n\n        if (!newAccount->Encrypt(activeAccount->vMasterKey))\n        {\n            std::string strErrorMessage = _(\"Error importing private key\") + \"\\n\" + (\"Failed to encrypt new account.\");\n            LogPrintf(strErrorMessage.c_str());\n            CAlert::Notify(strErrorMessage, true, true);\n        }\n    }\n\n    pactiveWallet->addAccount(newAccount, sAccountName);\n\n    //fixme: (FUT) (ACCOUNTS) - Optionally take a key birth date here.\n    if (!importPrivKeyIntoAccount(newAccount, privKey, importKeyID, 1))\n    {\n        //Error messages aleady handled internally by importPrivKeyIntoAccount.\n        //fixme: (FUT) (ACCOUNTS) we should delete the account in this scenario.\n        return;\n    }\n\n    //fixme: (FUT) (ACCOUNTS) Delete account on failure.\n}\n\nbool CWallet::forceKeyIntoKeypool(CAccount* forAccount, const CKey& privKeyToInsert)\n{\n    if (forAccount->IsHD())\n    {\n        std::string strError = \"forceKeyIntoKeypool called on an HD account. Please contact a developer and let them know what you were doing at the time so that they can look into the issue.\";\n        LogPrintf(strError.c_str());\n        CAlert::Notify(strError, true, true);\n        return false;\n    }\n\n    LOCK(cs_wallet);\n    CWalletDB walletdb(*dbw);\n\n    //Find current unique highest key index across *all* keypools.\n    int64_t nIndex = 1;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        for (auto keyChain : { KEYCHAIN_EXTERNAL, KEYCHAIN_CHANGE })\n        {\n            auto& keyPool = ( keyChain == KEYCHAIN_EXTERNAL ? forAccount->setKeyPoolExternal : forAccount->setKeyPoolInternal );\n            if (!keyPool.empty())\n                nIndex = std::max( nIndex, *(--keyPool.end()) + 1 );\n        }\n    }\n\n    //fixme: (FUT) (ACCOUNTS) Add some key metadata here as well?\n\n    CPubKey pubKeyToInsert = privKeyToInsert.GetPubKey();\n    if (!AddKeyPubKey(privKeyToInsert, pubKeyToInsert, *forAccount, KEYCHAIN_EXTERNAL))\n    {\n        std::string strError = \"Failed to add public key, perhaps it already exists in another account.\";\n        LogPrintf(strError.c_str());\n        CAlert::Notify(strError, true, true);\n        return false;\n    }\n    if (!walletdb.WritePool( ++nIndex, CKeyPool(pubKeyToInsert, getUUIDAsString(forAccount->getUUID()), KEYCHAIN_EXTERNAL ) ) )\n    {\n        std::string strError = \"Failed to write key to pool. Please contact a developer and let them know what you were doing at the time so that they can look into the issue.\";\n        LogPrintf(strError.c_str());\n        CAlert::Notify(strError, true, true);\n        return false;\n    }\n    forAccount->setKeyPoolExternal.insert(nIndex);\n    LogPrintf(\"keypool [%s:external] added imported key %d, size=%u\\n\", forAccount->getLabel(), nIndex, forAccount->setKeyPoolExternal.size());\n    return true;\n}\n\nbool CWallet::importPrivKeyIntoAccount(CAccount* targetAccount, const CKey& privKey, const CKeyID& importKeyID, uint64_t keyBirthDate, bool allowRescan)\n{\n    assert(!targetAccount->IsHD());\n\n    pactiveWallet->MarkDirty();\n    pactiveWallet->mapKeyMetadata[importKeyID].nCreateTime = 1;\n\n    // Force key into the keypool\n    if (!forceKeyIntoKeypool(targetAccount, privKey))\n    {\n        return false;\n    }\n\n    // Whenever a key is imported, we need to scan the whole chain from birth date - do so now\n    pactiveWallet->nTimeFirstKey = std::min(pactiveWallet->nTimeFirstKey, keyBirthDate);\n    if (allowRescan)\n    {\n        ResetSPVStartRescanThread();\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "src/wallet/wallet_transaction.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"net.h\"\n#include \"scheduler.h\"\n#include \"timedata.h\"\n#include \"init.h\"\n#include \"key.h\"\n#include \"keystore.h\"\n#include \"wallet/coincontrol.h\"\n#include \"policy/policy.h\"\n#include \"policy/rbf.h\"\n#include \"witnessutil.h\"\n#include \"alert.h\"\n\nstd::vector<CAccount*> CWallet::FindAccountsForTransaction(const CTxOut& out)\n{\n    std::vector<CAccount*> ret;\n    for (const auto& [accountUUID, forAccount] : mapAccounts)\n    {\n        (unused) accountUUID;\n        if (::IsMine(*forAccount, out) == ISMINE_SPENDABLE)\n        {\n            ret.push_back(forAccount);\n        }\n    }\n    return ret;\n}\n\nCAccount* CWallet::FindBestWitnessAccountForTransaction(const CTxOut& out)\n{\n    // Find all accounts for this address\n    CAccount* witnessAccount = nullptr;\n    std::vector<CAccount*> potentialWitnessAccounts = FindAccountsForTransaction(out);\n    \n    // Filter for witness accounts\n    for (auto account : potentialWitnessAccounts)\n    {\n        if (account->IsPoW2Witness())\n        {\n            // Try to prefer full witness account to witness only\n            if (!witnessAccount || witnessAccount->IsWitnessOnly())\n            {\n                witnessAccount = account;\n            }\n        }\n    }\n    return witnessAccount;\n}\n\nbool CWallet::SignTransaction(CAccount* fromAccount, CMutableTransaction &tx, SignType type, CTxOut* prevOutOverride)\n{\n    AssertLockHeld(cs_wallet); // mapWallet\n\n    // sign the new tx\n    CTransaction txNewConst(tx);\n    int nIn = 0;\n    for (const auto& input : tx.vin)\n    {\n        if (input.GetPrevOut().IsNull() && txNewConst.IsPoW2WitnessCoinBase())\n        {\n            nIn++;\n            continue;\n        }\n\n        const CWalletTx* prev = GetWalletTx(input.GetPrevOut());\n        const CTxOut* prevout = nullptr;\n        if(!prev || input.GetPrevOut().n >= prev->tx->vout.size())\n        {\n            if (prevOutOverride)\n            {\n                prevout = prevOutOverride;\n            }\n            else\n            {\n                return false;\n            }\n        }\n        else\n        {\n            prevout = &prev->tx->vout[input.GetPrevOut().n];\n        }\n        \n        const CAmount& amount = prevout->nValue;\n        CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(*prevout, type);\n        SignatureData sigdata;\n        std::vector<CAccount*> accountsToTry;\n        if (!fromAccount)\n            accountsToTry = FindAccountsForTransaction(*prevout);\n        else\n            accountsToTry.push_back(fromAccount);    \n        if (accountsToTry.empty())\n            return false;\n        \n        std::string strAccountsToTry;\n        std::vector<CKeyStore*> keystores;\n        keystores.reserve(accountsToTry.size());\n        for (auto account : accountsToTry)\n        {\n            strAccountsToTry += account->getLabel() + \" \";\n            keystores.push_back(account);\n        }\n        \n        if (!ProduceSignature(TransactionSignatureCreator(signingKeyID, keystores, &txNewConst, nIn, amount, SIGHASH_ALL), *prevout, sigdata, type, txNewConst.nVersion))\n        {\n            LogPrintf(\"CWallet::SignTransaction failed to produce signature [signing accounts: %s] [transaction: %s]\\n\", strAccountsToTry.c_str(), txNewConst.ToString());\n            return false;\n        }\n        UpdateTransaction(tx, nIn, sigdata);\n        nIn++;\n    }\n    return true;\n}\n\n\n\nbool CWallet::FundTransaction(CAccount* fromAccount, CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl, CReserveKeyOrScript& reservekey)\n{\n    std::vector<CRecipient> vecSend;\n\n    // Turn the txout set into a CRecipient vector\n    for (size_t idx = 0; idx < tx.vout.size(); idx++)\n    {\n        const CTxOut& txOut = tx.vout[idx];\n        CRecipient recipient = GetRecipientForTxOut(txOut, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1);\n        vecSend.push_back(recipient);\n    }\n\n    coinControl.fAllowOtherInputs = true;\n\n    for(const CTxIn& txin : tx.vin)\n        coinControl.Select(txin.GetPrevOut());\n\n    CWalletTx wtx;\n    if (!CreateTransaction(fromAccount, vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false))\n        return false;\n\n    if (nChangePosInOut != -1)\n        tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);\n\n    // Copy output sizes from new transaction; they may have had the fee subtracted from them\n    for (unsigned int idx = 0; idx < tx.vout.size(); idx++)\n        tx.vout[idx].nValue = wtx.tx->vout[idx].nValue;\n\n    // Add new txins (keeping original txin scriptSig/order)\n    for(const CTxIn& txin : wtx.tx->vin)\n    {\n        //NB!!!\n        //If txin.prevout was hash based and not index based, and a valid index based outpoint representation also exists (mature enough) then we end up with a double output here.\n        //CreateTransaction ends up selecting the index based outpoint and the two txin no longer match\n        //We work around this by looking up the hash (if its in the wallet) and using that instead\n        //However callers to this function should also rather just pass in index based inputs where possible\n        if (!coinControl.IsSelected(txin.GetPrevOut()))\n        {\n            bool add = false;\n            if (txin.GetPrevOut().isHash)\n            {\n                add = true;\n            }\n            else\n            {\n                uint256 convertedHash;\n                if (CWallet::GetTxHash(txin.GetPrevOut(), convertedHash))\n                {\n                    if(!coinControl.IsSelected(COutPoint(convertedHash, txin.GetPrevOut().n)))\n                    {\n                        add = true;\n                    }\n                }\n            }\n            if (add)\n            {\n                tx.vin.push_back(txin);\n                if (lockUnspents)\n                {\n                    LOCK2(cs_main, cs_wallet);\n                    LockCoin(txin.GetPrevOut());\n                }\n            }\n        }\n    }\n\n    return true;\n}\n\n\nvoid CWallet::AddTxInput(CMutableTransaction& tx, const CInputCoin& inputCoin, bool rbf)\n{\n    std::set<CInputCoin> setCoins;\n    setCoins.insert(inputCoin);\n    AddTxInputs(tx, setCoins, rbf);\n}\n\nvoid CWallet::AddTxInputs(CMutableTransaction& tx, std::set<CInputCoin>& setCoins, bool rbf)\n{\n    uint8_t nFlags = 0;\n    uint32_t nSequence = 0;\n    if (IsOldTransactionVersion(tx.nVersion))\n    {\n        if (rbf)\n        {\n            // Use sequence number to signal RBF\n            nSequence = MAX_BIP125_RBF_SEQUENCE;\n        }\n        else if(tx.nLockTime == 0)\n        {\n            // Use sequence number to signal locktime\n            nSequence = std::numeric_limits<unsigned int>::max() - 1;\n        }\n        else\n        {\n            // Final sequence number\n            nSequence = std::numeric_limits<unsigned int>::max();\n        }\n    }\n    else\n    {\n        if (rbf)\n        {\n            nFlags |= CTxInFlags::OptInRBF;\n        }\n        else if(tx.nLockTime == 0)\n        {\n            //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n            //nFlags |= CTxInFlags::HasAbsoluteLock;\n        }\n        else\n        {\n            // Final sequence number\n            nSequence = std::numeric_limits<unsigned int>::max();\n        }\n    }\n    for (const auto& coin : setCoins)\n        tx.vin.push_back(CTxIn(coin.outpoint,CScript(), nSequence, nFlags));\n}\n\nbool CWallet::CreateTransaction(CAccount* forAccount, const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CAmount& nFeeRet,\n                                int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)\n{\n\n    if (forAccount->IsReadOnly())\n    {\n        strFailReason = _(\"Can't send from read only (watch) account.\");\n        return false;\n    }\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(forAccount);\n    return CreateTransaction(accountsToTry, vecSend, wtxNew, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, sign);\n}\n\nbool CWallet::CreateTransaction(std::vector<CKeyStore*>& accountsToTry, const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CAmount& nFeeRet,\n                                int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)\n{\n\n    //fixme: (HIGH) (UNITY)\n    //for (const auto& forAccount : accountsToTry)\n    //{\n        //if (forAccount->IsReadOnly())\n        //{\n            //strFailReason = _(\"Can't send from read only (watch) account.\");\n            //return false;\n        //}\n    //}\n\n    CAmount nValue = 0;\n    int nChangePosRequest = nChangePosInOut;\n    unsigned int nSubtractFeeFromAmount = 0;\n    for (const auto& recipient : vecSend)\n    {\n        if (nValue < 0 || recipient.nAmount < 0)\n        {\n            strFailReason = _(\"Transaction amounts must not be negative\");\n            return false;\n        }\n        nValue += recipient.nAmount;\n\n        if (recipient.fSubtractFeeFromAmount)\n            nSubtractFeeFromAmount++;\n    }\n    if (vecSend.empty())\n    {\n        strFailReason = _(\"Transaction must have at least one recipient\");\n        return false;\n    }\n\n    wtxNew.fTimeReceivedIsTxTime = true;\n    wtxNew.BindWallet(this);\n    CMutableTransaction txNew(CURRENT_TX_VERSION_POW2);\n\n    // Discourage fee sniping.\n    //\n    // For a large miner the value of the transactions in the best block and\n    // the mempool can exceed the cost of deliberately attempting to mine two\n    // blocks to orphan the current best block. By setting nLockTime such that\n    // only the next block can include the transaction, we discourage this\n    // practice as the height restricted and limited blocksize gives miners\n    // considering fee sniping fewer options for pulling off this attack.\n    //\n    // A simple way to think about this is from the wallet's point of view we\n    // always want the blockchain to move forward. By setting nLockTime this\n    // way we're basically making the statement that we only want this\n    // transaction to appear in the next block; we don't want to potentially\n    // encourage reorgs by allowing transactions to appear at lower heights\n    // than the next block in forks of the best chain.\n    //\n    // Of course, the subsidy is high enough, and transaction volume low\n    // enough, that fee sniping isn't a problem yet, but by implementing a fix\n    // now we ensure code won't be written that makes assumptions about\n    // nLockTime that preclude a fix later.\n    //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n    //if (GetRandInt(10) == 0)//Munt - we only set this on 10% of blocks to avoid unnecessary space wastage. //fixme: (PHASE5) (only set this for high fee [per byte] transactions?)\n        //txNew.nLockTime = chainActive.Height();\n\n    // Secondly occasionally randomly pick a nLockTime even further back, so\n    // that transactions that are delayed after signing for whatever reason,\n    // e.g. high-latency mix networks and some CoinJoin implementations, have\n    // better privacy.\n    //fixme: (PHASE4POSTREL) (SEGSIG) (LOCKTIME) (SEQUENCE) - Look closer into the various lock mechanisms again, temporarily set as non standard\n    //if (GetRandInt(100) == 0)\n        //txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100));\n\n    assert(txNew.nLockTime <= (unsigned int)chainActive.Height());\n    assert(txNew.nLockTime < LOCKTIME_THRESHOLD);\n\n    {\n        std::set<CInputCoin> setCoins;\n        LOCK2(cs_main, cs_wallet);\n        {\n            std::vector<COutput> vAvailableCoins;\n            AvailableCoins(accountsToTry, vAvailableCoins, true, coinControl);\n\n            nFeeRet = 0;\n            // Start with no fee and loop until there is enough fee\n            while (true)\n            {\n                nChangePosInOut = nChangePosRequest;\n                txNew.vin.clear();\n                txNew.vout.clear();\n                wtxNew.fFromMe = true;\n                bool fFirst = true;\n\n                CAmount nValueToSelect = nValue;\n                if (nSubtractFeeFromAmount == 0)\n                    nValueToSelect += nFeeRet;\n                // vouts to the payees\n                for (const auto& recipient : vecSend)\n                {\n                    CTxOut txout = recipient.GetTxOut();\n\n                    if (recipient.fSubtractFeeFromAmount)\n                    {\n                        txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient\n\n                        if (fFirst) // first receiver pays the remainder not divisible by output count\n                        {\n                            fFirst = false;\n                            txout.nValue -= nFeeRet % nSubtractFeeFromAmount;\n                        }\n                    }\n\n                    if (IsDust(txout, ::dustRelayFee))\n                    {\n                        if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)\n                        {\n                            if (txout.nValue < 0) { strFailReason = _(\"The transaction amount is too small to pay the fee\"); }\n                            else { strFailReason = _(\"The transaction amount is too small to send after the fee has been deducted\"); }\n                        }\n                        else { strFailReason = _(\"Transaction amount too small\"); }\n                        return false;\n                    }\n                    txNew.vout.push_back(txout);\n                }\n\n                // Choose coins to use\n                CAmount nValueIn = 0;\n                setCoins.clear();\n                if (!SelectCoins(!IsOldTransactionVersion(txNew.nVersion), vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))\n                {\n                    strFailReason = _(\"Insufficient funds\");\n                    return false;\n                }\n\n                const CAmount nChange = nValueIn - nValueToSelect;\n                if (nChange > 0)\n                {\n                    std::shared_ptr<CTxOut> newTxOut = nullptr;\n                    //fixme: (FUT) (COIN_CONTROL)\n                    //We might want to allow coincontrol to produce script transactions even though segsig is enabled.\n                    if (!IsOldTransactionVersion(txNew.nVersion))\n                    {\n                        // Reserve a new key pair from key pool\n                        CPubKey vchPubKey;\n                        bool ret;\n                        ret = reservekey.GetReservedKey(vchPubKey);\n                        if (!ret)\n                        {\n                            if (reservekey.account && (reservekey.account->IsFixedKeyPool() || reservekey.account->IsMinimalKeyPool()))\n                            {\n                                std::string strFailReason = _(\"This type of account only supports emptying the entire balance in one go, no partial transactions.\");\n                                CAlert::Notify(strFailReason, true, true);\n                                LogPrintf(\"%s\", strFailReason.c_str());\n                            }\n                            else\n                            {\n                                strFailReason = _(\"Keypool ran out, please call keypoolrefill first\");\n                            }\n                            return false;\n                        }\n\n                        CTxOutStandardKeyHash standardKeyHashKeyID(vchPubKey.GetID());\n                        newTxOut = std::make_shared<CTxOut>(CTxOut(nChange, standardKeyHashKeyID));\n                    }\n                    else\n                    {\n                        // Fill a vout to ourself\n                        // TODO: pass in scriptChange instead of reservekey so\n                        // change transaction isn't always pay-to-Munt-address\n                        CScript scriptChange;\n\n                        // coin control: send change to custom address\n                        if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))\n                            scriptChange = GetScriptForDestination(coinControl->destChange);\n\n                        // no coin control: send change to newly generated address\n                        else\n                        {\n                            // Note: We use a new key here to keep it from being obvious which side is the change.\n                            //  The drawback is that by not reusing a previous key, the change may be lost if a\n                            //  backup is restored, if the backup doesn't have the new private key for the change.\n                            //  If we reused the old key, it would be possible to add code to look for and\n                            //  rediscover unknown transactions that were written with keys of ours to recover\n                            //  post-backup change.\n\n                            // Reserve a new key pair from key pool\n                            CPubKey vchPubKey;\n                            bool ret = false;\n                            try\n                            {\n                                ret = reservekey.GetReservedKey(vchPubKey);\n                            }\n                            catch(...)\n                            {\n                                \n                            }\n                            if (!ret)\n                            {\n                                if (reservekey.account && (reservekey.account->IsFixedKeyPool() || reservekey.account->IsMinimalKeyPool()))\n                                {\n                                    std::string strFailReason = _(\"This type of account only supports emptying the entire balance in one go, no partial transactions.\");\n                                    CAlert::Notify(strFailReason, true, true);\n                                    LogPrintf(\"%s\", strFailReason.c_str());\n                                }\n                                else\n                                {\n                                    strFailReason = _(\"Keypool ran out, please call keypoolrefill first\");\n                                }\n                                return false;\n                            }\n\n                            scriptChange = GetScriptForDestination(vchPubKey.GetID());\n                        }\n                        newTxOut = std::make_shared<CTxOut>(CTxOut(nChange, scriptChange));\n                    }\n\n                    // We do not move dust-change to fees, because the sender would end up paying more than requested.\n                    // This would be against the purpose of the all-inclusive feature.\n                    // So instead we raise the change and deduct from the recipient.\n                    if (nSubtractFeeFromAmount > 0 && IsDust(*newTxOut, ::dustRelayFee))\n                    {\n                        CAmount nDust = GetDustThreshold(*newTxOut, ::dustRelayFee) - newTxOut->nValue;\n                        newTxOut->nValue += nDust; // raise change until no more dust\n                        for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient\n                        {\n                            if (vecSend[i].fSubtractFeeFromAmount)\n                            {\n                                txNew.vout[i].nValue -= nDust;\n                                if (IsDust(txNew.vout[i], ::dustRelayFee))\n                                {\n                                    strFailReason = _(\"The transaction amount is too small to send after the fee has been deducted\");\n                                    return false;\n                                }\n                                break;\n                            }\n                        }\n                    }\n\n                    // Never create dust outputs; if we would, just\n                    // add the dust to the fee.\n                    if (IsDust(*newTxOut, ::dustRelayFee))\n                    {\n                        nChangePosInOut = -1;\n                        nFeeRet += nChange;\n                        reservekey.ReturnKey();\n                    }\n                    else\n                    {\n                        if (nChangePosInOut == -1)\n                        {\n                            // Insert change txn at random position:\n                            nChangePosInOut = GetRandInt(txNew.vout.size()+1);\n                        }\n                        else if ((unsigned int)nChangePosInOut > txNew.vout.size())\n                        {\n                            strFailReason = _(\"Change index out of range\");\n                            return false;\n                        }\n\n                        std::vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;\n                        txNew.vout.insert(position, *newTxOut);\n                    }\n                }\n                else\n                {\n                    reservekey.ReturnKey();\n                    nChangePosInOut = -1;\n                }\n\n                // Fill vin\n                //\n                // Note how the sequence number is set to non-maxint so that\n                // the nLockTime set above actually works.\n                //\n                // BIP125 defines opt-in RBF as any nSequence < maxint-1, so\n                // we use the highest possible value in that range (maxint-2)\n                // to avoid conflicting with other possible uses of nSequence,\n                // and in the spirit of \"smallest possible change from prior\n                // behavior.\"\n                bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf;\n                AddTxInputs(txNew, setCoins , rbf);\n\n                // Fill in dummy signatures for fee calculation.\n                if (!DummySignTx(accountsToTry, txNew, setCoins, Spend)) {\n                    SignatureData sigdata;\n                    if (!ProduceSignature(DummySignatureCreator(accountsToTry), CTxOut(), sigdata, Spend, txNew.nVersion))\n                    {\n                        strFailReason = _(\"Signing transaction failed\");\n                        return false;\n                    }\n                }\n\n                unsigned int numCoinBase = 0;\n                for (const auto& coin : setCoins)\n                {\n                    if (coin.isCoinBase)\n                    {\n                        ++numCoinBase;\n                    }\n                }\n                unsigned int nBytesDiscounted = GetVirtualTransactionSizeDiscounted(txNew, numCoinBase);\n\n                CTransaction txNewConst(txNew);\n\n                // Remove scriptSigs to eliminate the fee calculation dummy signatures\n                for (auto& vin : txNew.vin) {\n                    vin.scriptSig = CScript();\n                    vin.segregatedSignatureData.SetNull();\n                }\n\n                // Allow to override the default confirmation target over the CoinControl instance\n                int currentConfirmationTarget = nTxConfirmTarget;\n                if (coinControl && coinControl->nConfirmTarget > 0)\n                    currentConfirmationTarget = coinControl->nConfirmTarget;\n\n                CAmount nFeeNeeded = GetMinimumFee(nBytesDiscounted, currentConfirmationTarget, ::mempool, ::feeEstimator);\n                if (coinControl && coinControl->fOverrideFeeRate)\n                    nFeeNeeded = coinControl->nFeeRate.GetFee(nBytesDiscounted);\n\n                // If we made it here and we aren't even able to meet the relay fee on the next pass, give up\n                // because we must be at the maximum allowed fee.\n                if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytesDiscounted))\n                {\n                    strFailReason = _(\"Transaction too large for fee policy\");\n                    return false;\n                }\n\n                if (nFeeRet >= nFeeNeeded) {\n                    // Reduce fee to only the needed amount if we have change\n                    // output to increase.  This prevents potential overpayment\n                    // in fees if the coins selected to meet nFeeNeeded result\n                    // in a transaction that requires less fee than the prior\n                    // iteration.\n                    // TODO: The case where nSubtractFeeFromAmount > 0 remains\n                    // to be addressed because it requires returning the fee to\n                    // the payees and not the change output.\n                    // TODO: The case where there is no change output remains\n                    // to be addressed so we avoid creating too small an output.\n                    if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {\n                        CAmount extraFeePaid = nFeeRet - nFeeNeeded;\n                        std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;\n                        change_position->nValue += extraFeePaid;\n                        nFeeRet -= extraFeePaid;\n                    }\n                    break; // Done, enough fee included.\n                }\n\n                // Try to reduce change to include necessary fee\n                if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {\n                    CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;\n                    std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;\n                    // Only reduce change if remaining amount is still a large enough output.\n                    if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {\n                        change_position->nValue -= additionalFeeNeeded;\n                        nFeeRet += additionalFeeNeeded;\n                        break; // Done, able to increase fee from change\n                    }\n                }\n\n                // Include more fee and try again.\n                nFeeRet = nFeeNeeded;\n                continue;\n            }\n        }\n\n        if (sign)\n        {\n            CTransaction txNewConst(txNew);\n            int nIn = 0;\n            for (const auto& coin : setCoins)\n            {\n                SignatureData sigdata;\n\n                CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(coin.txout, SignType::Spend);\n\n                if (!ProduceSignature(TransactionSignatureCreator(signingKeyID, accountsToTry, &txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL),  coin.txout, sigdata, Spend, txNewConst.nVersion))\n                {\n                    strFailReason = _(\"Signing transaction failed\");\n                    return false;\n                }\n                else\n                {\n                    UpdateTransaction(txNew, nIn, sigdata);\n                }\n\n                nIn++;\n            }\n        }\n\n        // Embed the constructed transaction data in wtxNew.\n        wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));\n\n        // Limit size\n        if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)\n        {\n            strFailReason = _(\"Transaction too large\");\n            return false;\n        }\n    }\n\n    if (GetBoolArg(\"-walletrejectlongchains\", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {\n        // Lastly, ensure this tx will pass the mempool's chain limits\n        LockPoints lp;\n        CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, lp);\n        CTxMemPool::setEntries setAncestors;\n        size_t nLimitAncestors = GetArg(\"-limitancestorcount\", DEFAULT_ANCESTOR_LIMIT);\n        size_t nLimitAncestorSize = GetArg(\"-limitancestorsize\", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;\n        size_t nLimitDescendants = GetArg(\"-limitdescendantcount\", DEFAULT_DESCENDANT_LIMIT);\n        size_t nLimitDescendantSize = GetArg(\"-limitdescendantsize\", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;\n        std::string errString;\n        if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {\n            strFailReason = _(\"Transaction has too long of a mempool chain\");\n            return false;\n        }\n    }\n\n    // NB! This part of the process is super important.\n    // We insert the private witnessing (**not** -spending- only -witnessing-) key into the unencrypted keychain for the HD account (even on encrypted wallet)\n    // This allows witnessing to work correctly on encrypted wallets.\n    for (const auto& recipient : vecSend)\n    {\n        if (recipient.witnessForAccount != nullptr)\n        {\n            CKey privWitnessKey;\n            if (!recipient.witnessForAccount->GetKey(recipient.witnessDetails.witnessKeyID, privWitnessKey))\n            {\n                //fixme: (FUT) Localise\n                strFailReason = strprintf(\"Wallet error, failed to retrieve private witness key.\");\n                return false;\n            }\n            if (!AddKeyPubKey(privWitnessKey, privWitnessKey.GetPubKey(), *recipient.witnessForAccount, KEYCHAIN_WITNESS))\n            {\n                //fixme: (FUT) Localise\n                strFailReason = strprintf(\"Wallet error, failed to store witness key.\");\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\n\nbool CWallet::AddFeeForTransaction(CAccount* forAccount, CMutableTransaction& txNew, CReserveKeyOrScript& reservekey, CAmount& nFeeOut, bool sign, std::string& strFailReason, const CCoinControl* coinControl)\n{\n    std::vector<CKeyStore*> accountsToTry;\n    accountsToTry.push_back(forAccount);\n                \n    CWalletTx wtxNew;\n    if (forAccount->IsReadOnly())\n    {\n        strFailReason = _(\"Can't send from read only (watch) account.\");\n        return false;\n    }\n\n    {\n        std::set<CInputCoin> setCoins;\n        int nChangePos = -1;\n        LOCK2(cs_main, cs_wallet);\n        {\n            std::vector<COutput> vAvailableCoins;\n            AvailableCoins(forAccount, vAvailableCoins, true, nullptr);\n\n            CAmount nMandatoryWitnessPenaltyFee = 0;\n            for(const auto& output : txNew.vout)\n            {\n                nMandatoryWitnessPenaltyFee += CalculateWitnessPenaltyFee(output);\n            }\n            nFeeOut = nMandatoryWitnessPenaltyFee;\n\n            // Start with no fee and loop until there is enough fee\n            while (true)\n            {\n                // Choose coins to use\n                CAmount nValueSelected = 0;\n                setCoins.clear();\n                if (!SelectCoins(IsOldTransactionVersion(txNew.nVersion), vAvailableCoins, nFeeOut, setCoins, nValueSelected, coinControl))\n                {\n                    strFailReason = _(\"Insufficient funds\");\n                    return false;\n                }\n\n                const CAmount nChange = nValueSelected - nFeeOut;\n                if (nChange > 0)\n                {\n                    //fixme: (FUT) (COIN_CONTROL)\n                    //We might want to allow coincontrol to produce script transactions even though segsig is enabled.\n                    std::shared_ptr<CTxOut> newTxOut = nullptr;\n                    if (!IsOldTransactionVersion(txNew.nVersion))\n                    {\n                        // Reserve a new key pair from key pool\n                        CPubKey vchPubKey;\n                        bool ret;\n                        ret = reservekey.GetReservedKey(vchPubKey);\n                        if (!ret)\n                        {\n                            strFailReason = _(\"Keypool ran out, please call keypoolrefill first\");\n                            return false;\n                        }\n\n                        CTxOutStandardKeyHash standardKeyHashKeyID(vchPubKey.GetID());\n                        newTxOut = std::make_shared<CTxOut>(CTxOut(nChange, standardKeyHashKeyID));\n                    }\n                    else\n                    {\n                        // Fill a vout to ourself\n                        // TODO: pass in scriptChange instead of reservekey so\n                        // change transaction isn't always pay-to-Munt-address\n                        CScript scriptChange;\n\n                        // coin control: send change to custom address\n                        if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))\n                        {\n                            scriptChange = GetScriptForDestination(coinControl->destChange);\n                        }\n                        else // no coin control: send change to newly generated address\n                        {\n                            // Note: We use a new key here to keep it from being obvious which side is the change.\n                            //  The drawback is that by not reusing a previous key, the change may be lost if a\n                            //  backup is restored, if the backup doesn't have the new private key for the change.\n                            //  If we reused the old key, it would be possible to add code to look for and\n                            //  rediscover unknown transactions that were written with keys of ours to recover\n                            //  post-backup change.\n\n                            // Reserve a new key pair from key pool\n                            CPubKey vchPubKey;\n                            bool ret;\n                            ret = reservekey.GetReservedKey(vchPubKey);\n                            if (!ret)\n                            {\n                                strFailReason = _(\"Keypool ran out, please call keypoolrefill first\");\n                                return false;\n                            }\n\n                            scriptChange = GetScriptForDestination(vchPubKey.GetID());\n                        }\n                        newTxOut = std::make_shared<CTxOut>(CTxOut(nChange, scriptChange));\n                    }\n\n                    // Never create dust outputs; if we would, just\n                    // add the dust to the fee.\n                    if (IsDust(*newTxOut, ::dustRelayFee))\n                    {\n                        nFeeOut += nChange;\n                        reservekey.ReturnKey();\n                    }\n                    else\n                    {\n                        txNew.vout.push_back(*newTxOut);\n                        nChangePos = txNew.vout.size()-1;\n                    }\n                }\n                else\n                {\n                    reservekey.ReturnKey();\n                }\n\n                // Add inputs\n                AddTxInputs(txNew, setCoins, false);\n\n                // Fill in dummy signatures for fee calculation.\n                if (!DummySignTx(accountsToTry, txNew, setCoins, Spend)) {\n                    SignatureData sigdata;\n                    if (!ProduceSignature(DummySignatureCreator(accountsToTry), CTxOut(), sigdata, Spend, txNew.nVersion))\n                    {\n                        strFailReason = _(\"Signing transaction failed\");\n                        return false;\n                    }\n                }\n\n                unsigned int nBytes = GetVirtualTransactionSize(txNew);\n\n                CTransaction txNewConst(txNew);\n\n                // Remove scriptSigs to eliminate the fee calculation dummy signatures\n                {\n                    LOCK2(cs_main, cs_wallet);\n                    for (auto& txin : txNew.vin)\n                    {\n                        txin.scriptSig = CScript();\n                        txin.segregatedSignatureData.SetNull();\n                        \n                        // Prevent input being spent twice\n                        LockCoin(txin.GetPrevOut());\n                    }\n                }\n\n                // Allow to override the default confirmation target over the CoinControl instance\n                int currentConfirmationTarget = nTxConfirmTarget;\n                if (coinControl && coinControl->nConfirmTarget > 0)\n                    currentConfirmationTarget = coinControl->nConfirmTarget;\n\n                CAmount nMinimumFee = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator);\n                CAmount nFeeNeeded = (nMinimumFee > nMandatoryWitnessPenaltyFee) ? nMinimumFee : nMandatoryWitnessPenaltyFee;\n                if (coinControl && coinControl->fOverrideFeeRate)\n                    nFeeNeeded = (coinControl->nFeeRate.GetFee(nBytes) > nMandatoryWitnessPenaltyFee) ? (coinControl->nFeeRate.GetFee(nBytes)) : nMandatoryWitnessPenaltyFee;\n\n                // If we made it here and we aren't even able to meet the relay fee on the next pass, give up\n                // because we must be at the maximum allowed fee.\n                if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))\n                {\n                    strFailReason = _(\"Transaction too large for fee policy\");\n                    return false;\n                }\n\n                if (nFeeOut >= nFeeNeeded) {\n                    // Reduce fee to only the needed amount if we have change\n                    // output to increase.  This prevents potential overpayment\n                    // in fees if the coins selected to meet nFeeNeeded result\n                    // in a transaction that requires less fee than the prior\n                    // iteration.\n                    // TODO: The case where there is no change output remains\n                    // to be addressed so we avoid creating too small an output.\n                    if (nFeeOut > nFeeNeeded && nChangePos != -1)\n                    {\n                        CAmount extraFeePaid = nFeeOut - nFeeNeeded;\n                        std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePos;\n                        change_position->nValue += extraFeePaid;\n                        nFeeOut -= extraFeePaid;\n                    }\n                    break; // Done, enough fee included.\n                }\n\n                // Try to reduce change to include necessary fee\n                if (nChangePos != -1)\n                {\n                    CAmount additionalFeeNeeded = nFeeNeeded - nFeeOut;\n                    std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePos;\n                    // Only reduce change if remaining amount is still a large enough output.\n                    if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {\n                        change_position->nValue -= additionalFeeNeeded;\n                        nFeeOut += additionalFeeNeeded;\n                        break; // Done, able to increase fee from change\n                    }\n                }\n\n                // Include more fee and try again.\n                nFeeOut = nFeeNeeded;\n                continue;\n            }\n        }\n\n        if (sign)\n        {\n            CTransaction txNewConst(txNew);\n            int nIn = 0;\n            for (const auto& coin : setCoins)\n            {\n                SignatureData sigdata;\n\n                CKeyID signingKeyID = ExtractSigningPubkeyFromTxOutput(coin.txout, SignType::Spend);\n\n                if (!ProduceSignature(TransactionSignatureCreator(signingKeyID, accountsToTry, &txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL),  coin.txout, sigdata, Spend, txNewConst.nVersion))\n                {\n                    LogPrintf(\"CWallet::AddFeeForTransaction ProduceSignature call failed\\n\");\n                    strFailReason = _(\"Signing transaction failed\");\n                    return false;\n                }\n                else\n                {\n                    UpdateTransaction(txNew, nIn, sigdata);\n                }\n\n                nIn++;\n            }\n        }\n\n        // Embed the constructed transaction data in wtxNew.\n        wtxNew.SetTx(MakeTransactionRef(txNew));\n\n        // Limit size\n        if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)\n        {\n            strFailReason = _(\"Transaction too large\");\n            return false;\n        }\n    }\n\n    if (GetBoolArg(\"-walletrejectlongchains\", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {\n        // Lastly, ensure this tx will pass the mempool's chain limits\n        LockPoints lp;\n        CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, lp);\n        CTxMemPool::setEntries setAncestors;\n        size_t nLimitAncestors = GetArg(\"-limitancestorcount\", DEFAULT_ANCESTOR_LIMIT);\n        size_t nLimitAncestorSize = GetArg(\"-limitancestorsize\", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;\n        size_t nLimitDescendants = GetArg(\"-limitdescendantcount\", DEFAULT_DESCENDANT_LIMIT);\n        size_t nLimitDescendantSize = GetArg(\"-limitdescendantsize\", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;\n        std::string errString;\n        if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {\n            strFailReason = _(\"Transaction has too long of a mempool chain\");\n            return false;\n        }\n    }\n    return true;\n}\n\n\nbool CWallet::PrepareRenewWitnessAccountTransaction(CAccount* funderAccount, CAccount* targetWitnessAccount, CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, CAmount& nFeeOut, std::string& strError, uint64_t* skipPastTransaction, CCoinControl* coinControl)\n{\n    LOCK2(cs_main, cs_wallet); // cs_main required for ReadBlockFromDisk.\n\n    //fixme: (FUT) (COIN_CONTROL)\n    CCoinControl tempCoinControl;\n    if (!coinControl)\n        coinControl = &tempCoinControl;\n    \n    bool allowIndexBased = !IsOldTransactionVersion(tx.nVersion);\n\n    CGetWitnessInfo witnessInfo;\n    CBlock block;\n    if (!ReadBlockFromDisk(block, chainActive.Tip(), Params()))\n    {\n        strError = \"Error reading block from disk.\";\n        return false;\n    }\n    GetWitnessInfo(chainActive, Params(), nullptr, chainActive.Tip()->pprev, block, witnessInfo, chainActive.Tip()->nHeight);\n    bool addedAny=false;\n    for (const auto& witCoin : witnessInfo.witnessSelectionPoolUnfiltered)\n    {\n        if (::IsMine(*targetWitnessAccount, witCoin.coin.out))\n        {\n            if (witnessHasExpired(witCoin.nAge, witCoin.nWeight, witnessInfo.nTotalWeightRaw))\n            {\n                addedAny = true;\n               \n                // Add witness input\n                AddTxInput(tx, CInputCoin(witCoin.outpoint, witCoin.coin.out, allowIndexBased, false, witCoin.coin.nHeight, witCoin.coin.nTxIndex), false);\n\n                // Add witness output\n                CTxOut renewedWitnessTxOutput;\n                CTxOutPoW2Witness witnessDestination;\n                if (!GetPow2WitnessOutput(witCoin.coin.out, witnessDestination))\n                {\n                    strError = \"Unable to correctly retrieve data\";\n                    return false;\n                }\n                \n                if (!HaveKey(witnessDestination.spendingKeyID))\n                {\n                    strError = strprintf(\"Spending key for [%s] not available in wallet\", CNativeAddress(CPoW2WitnessDestination(witnessDestination.spendingKeyID, witnessDestination.witnessKeyID)).ToString());\n                }\n                \n                if (!HaveKey(witnessDestination.witnessKeyID))\n                {\n                    strError = strprintf(\"Witness key for [%s] not available in wallet\", CNativeAddress(CPoW2WitnessDestination(witnessDestination.spendingKeyID, witnessDestination.witnessKeyID)).ToString());\n                }\n\n                // Increment fail count appropriately\n                IncrementWitnessFailCount(witnessDestination.failCount);\n\n                // Ensure consistent lock from\n                if (witnessDestination.lockFromBlock == 0)\n                {\n                    witnessDestination.lockFromBlock = witCoin.coin.nHeight;\n                }\n\n                if (GetPoW2Phase(chainActive.Tip()) >= 4)\n                {\n                    renewedWitnessTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n                    renewedWitnessTxOutput.output.witnessDetails.spendingKeyID = witnessDestination.spendingKeyID;\n                    renewedWitnessTxOutput.output.witnessDetails.witnessKeyID = witnessDestination.witnessKeyID;\n                    renewedWitnessTxOutput.output.witnessDetails.lockFromBlock = witnessDestination.lockFromBlock;\n                    renewedWitnessTxOutput.output.witnessDetails.lockUntilBlock = witnessDestination.lockUntilBlock;\n                    renewedWitnessTxOutput.output.witnessDetails.failCount = witnessDestination.failCount;\n                    renewedWitnessTxOutput.output.witnessDetails.actionNonce = witnessDestination.actionNonce+1;\n                }\n                else\n                {\n                    CPoW2WitnessDestination dest;\n                    dest.spendingKey = witnessDestination.spendingKeyID;\n                    dest.witnessKey = witnessDestination.witnessKeyID;\n                    dest.lockFromBlock = witnessDestination.lockFromBlock;\n                    dest.lockUntilBlock = witnessDestination.lockUntilBlock;\n                    dest.failCount = witnessDestination.failCount;\n                    dest.actionNonce = witnessDestination.actionNonce+1;\n                    renewedWitnessTxOutput.SetType(CTxOutType::ScriptLegacyOutput);\n                    renewedWitnessTxOutput.output.scriptPubKey = GetScriptForDestination(dest);\n                }\n                renewedWitnessTxOutput.nValue = witCoin.coin.out.nValue;\n                tx.vout.push_back(renewedWitnessTxOutput);\n                \n                // Re-add the witness key in case the wallet doesn't already have it for whatever reason\n                CKey privWitnessKey;\n                targetWitnessAccount->GetKey(witnessDestination.witnessKeyID, privWitnessKey);\n                targetWitnessAccount->AddKeyPubKey(privWitnessKey, privWitnessKey.GetPubKey(), KEYCHAIN_WITNESS);\n            }\n        }\n    }\n    if (addedAny)\n    {\n        // Add fee input and change output\n        std::string sFailReason;\n        if (!AddFeeForTransaction(funderAccount, tx, changeReserveKey, nFeeOut, true, sFailReason, coinControl))\n        {\n            strError = \"Unable to add fee: \" + sFailReason;\n            return false;\n        }\n        return true;\n    }\n    strError = \"Unable to locate any expired inputs for account\";\n    return false;\n}\n\nvoid CWallet::PrepareUpgradeWitnessAccountTransaction(CAccount* funderAccount, CAccount* targetWitnessAccount, CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, CAmount& nFeeOut)\n{\n    LOCK2(cs_main, cs_wallet); // cs_main required for ReadBlockFromDisk.\n\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    //fixme: (FUT) (COIN_CONTROL)\n    CCoinControl coinControl;\n\n    CGetWitnessInfo witnessInfo;\n    CBlock block;\n    if (!ReadBlockFromDisk(block, chainActive.Tip(), Params()))\n        throw std::runtime_error(\"Error reading block from disk.\");\n\n    GetWitnessInfo(chainActive, Params(), nullptr, chainActive.Tip()->pprev, block, witnessInfo, chainActive.Tip()->nHeight);\n    for (const auto& witCoin : witnessInfo.witnessSelectionPoolUnfiltered)\n    {\n        if (::IsMine(*targetWitnessAccount, witCoin.coin.out))\n        {\n            // Add witness input\n            AddTxInput(tx, CInputCoin(witCoin.outpoint, witCoin.coin.out, true, false,witCoin.coin.nHeight, witCoin.coin.nTxIndex), false);\n\n            // Add witness output\n            CTxOut renewedWitnessTxOutput;\n            CTxOutPoW2Witness witnessDestination;\n            if (!GetPow2WitnessOutput(witCoin.coin.out, witnessDestination))\n                throw std::runtime_error(\"Unable to correctly retrieve data\");\n\n            // Increment fail count appropriately\n            // Note that for upgrade there was no real failure, but the fail count needs to be incremented for the upgrade to pass\n            // validation as a renewal\n            IncrementWitnessFailCount(witnessDestination.failCount);\n\n            // Ensure consistent lock from\n            if (witnessDestination.lockFromBlock == 0)\n            {\n                witnessDestination.lockFromBlock = witCoin.coin.nHeight;\n            }\n\n            renewedWitnessTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n            renewedWitnessTxOutput.output.witnessDetails.spendingKeyID = witnessDestination.spendingKeyID;\n            renewedWitnessTxOutput.output.witnessDetails.witnessKeyID = witnessDestination.witnessKeyID;\n            renewedWitnessTxOutput.output.witnessDetails.lockFromBlock = witnessDestination.lockFromBlock;\n            renewedWitnessTxOutput.output.witnessDetails.lockUntilBlock = witnessDestination.lockUntilBlock;\n            renewedWitnessTxOutput.output.witnessDetails.failCount = witnessDestination.failCount;\n            renewedWitnessTxOutput.output.witnessDetails.actionNonce = witnessDestination.actionNonce+1;\n            renewedWitnessTxOutput.nValue = witCoin.coin.out.nValue;\n            tx.vout.push_back(renewedWitnessTxOutput);\n\n            // Add fee input and change output\n            std::string sFailReason;\n            if (!AddFeeForTransaction(funderAccount, tx, changeReserveKey, nFeeOut, true, sFailReason, &coinControl))\n                throw std::runtime_error(\"Unable to add fee\");\n\n            return;\n        }\n    }\n\n    throw std::runtime_error(\"Could not find suitable witness to upgrade\");\n}\n\nbool CWallet::SignAndSubmitTransaction(CReserveKeyOrScript& changeReserveKey, CMutableTransaction& tx, std::string& strError, uint256* pTransactionHashOut, SignType type)\n{\n    if (!SignTransaction(nullptr, tx, type))\n    {\n        strError = \"Unable to sign transaction\";\n        return false;\n    }\n\n    // Accept the transaction to wallet and broadcast.\n    CWalletTx wtxNew;\n    wtxNew.fTimeReceivedIsTxTime = true;\n    wtxNew.BindWallet(this);\n    wtxNew.SetTx(MakeTransactionRef(std::move(tx)));\n    CValidationState state;\n    if (!CommitTransaction(wtxNew, changeReserveKey, g_connman.get(), state))\n    {\n        strError = \"Unable to commit transaction\";\n        return false;\n    }\n    if (pTransactionHashOut)\n        *pTransactionHashOut = wtxNew.GetHash();\n\n    return true;\n}\n\n/**\n * Call after CreateTransaction unless you want to abort\n */\nbool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKeyOrScript& reservekey, CConnman* connman, CValidationState& state)\n{\n    // Refuse to add a null hash to the wallet, as this flags the wallet as corrupted on restart\n    if(wtxNew.GetHash().IsNull())\n        return false;\n    \n    {\n        LOCK2(cs_main, cs_wallet);\n        LogPrintf(\"CommitTransaction:\\n%s\", wtxNew.tx->ToString());\n        CDataStream ssTx(SER_NETWORK, 0);\n        ssTx << wtxNew.tx;\n        LogPrintf(\"TransactionHex[%s]\\n\", HexStr(ssTx.begin(), ssTx.end()));\n        {\n            // Take key pair from key pool so it won't be used again\n            reservekey.KeepKey();\n\n            // Add tx to wallet, because if it has change it's also ours,\n            // otherwise just for transaction history.\n            AddToWallet(wtxNew, true, true);\n\n            // Notify that old coins are spent\n            for(const CTxIn& txin : wtxNew.tx->vin)\n            {\n                CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n                if (prev)\n                {\n                    prev->BindWallet(this);\n                    NotifyTransactionChanged(this, prev->GetHash(), CT_UPDATED, false);\n                }\n            }\n        }\n\n        // Track how many getdata requests our transaction gets\n        mapRequestCount[wtxNew.GetHash()] = 0;\n\n        if (fBroadcastTransactions)\n        {\n            // Broadcast\n            if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {\n                LogPrintf(\"CommitTransaction(): Transaction cannot be broadcast immediately, %s\\n\", state.GetRejectReason());\n                // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.\n            } else {\n                wtxNew.RelayWalletTransaction(connman);\n            }\n        }\n    }\n    return true;\n}\n"
  },
  {
    "path": "src/wallet/walletbalance.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallet.h\"\n#include \"wallet/wallettx.h\"\n\n#include \"validation/validation.h\"\n#include \"policy/policy.h\"\n#include \"witnessutil.h\"\n\n// Note that this function doesn't distinguish between a 0-valued input,\n// and a not-\"is mine\" (according to the filter) input.\nCAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter, CAccount* forAccount, bool includeChildren) const\n{\n    CAmount ret = 0;\n    {\n        LOCK(cs_wallet);\n        const CWalletTx* prev = GetWalletTx(txin.GetPrevOut());\n        if (prev)\n        {\n            if (txin.GetPrevOut().n < prev->tx->vout.size())\n            {\n                if ( (forAccount && (::IsMine(*forAccount, prev->tx->vout[txin.GetPrevOut().n]) & filter)) || (!forAccount && (IsMine(prev->tx->vout[txin.GetPrevOut().n]) & filter)) )\n                {\n                    ret = prev->tx->vout[txin.GetPrevOut().n].nValue;\n                }\n            }\n        }\n        if (forAccount && includeChildren)\n        {\n            for (const auto& [accountUUID, childAccount] : mapAccounts)\n            {\n                (unused) accountUUID;\n                if (childAccount->getParentUUID() == forAccount->getUUID())\n                {\n                    ret += GetDebit(txin, filter, childAccount, false);\n                }\n            }\n        }\n    }\n    return ret;\n}\n\n\nCAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter, CAccount* forAccount, bool includeChildren) const\n{\n    CAmount ret = 0;\n    if (!MoneyRange(txout.nValue))\n        throw std::runtime_error(std::string(__func__) + \": value out of range\");\n    if ( (forAccount && ::IsMine(*forAccount, txout) & filter) || (!forAccount && IsMine(txout) & filter) )\n        ret = txout.nValue;\n\n    if (forAccount && includeChildren)\n    {\n        for (const auto& [accountUUID, childAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                ret += GetCredit(txout, filter, childAccount, false);\n            }\n        }\n    }\n    return ret;\n}\n\nCAmount CWallet::GetChange(const CTxOut& txout) const\n{\n    if (!MoneyRange(txout.nValue))\n        throw std::runtime_error(std::string(__func__) + \": value out of range\");\n    return (IsChange(txout) ? txout.nValue : 0);\n}\n\n// Note that this function doesn't distinguish between a 0-valued input,\n// and a not-\"is mine\" (according to the filter) input.\nCAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter, CAccount* forAccount) const\n{\n    CAmount nDebit = 0;\n    for(const CTxIn& txin : tx.vin)\n    {\n        nDebit += GetDebit(txin, filter, forAccount);\n        if (!MoneyRange(nDebit))\n            throw std::runtime_error(std::string(__func__) + \": value out of range\");\n    }\n    return nDebit;\n}\n\nCAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter, CAccount* forAccount) const\n{\n    CAmount nCredit = 0;\n    for(const CTxOut& txout : tx.vout)\n    {\n        nCredit += GetCredit(txout, filter, forAccount);\n        if (!MoneyRange(nCredit))\n            throw std::runtime_error(std::string(__func__) + \": value out of range\");\n    }\n    return nCredit;\n}\n\nCAmount CWallet::GetChange(const CTransaction& tx) const\n{\n    CAmount nChange = 0;\n    for(const CTxOut& txout : tx.vout)\n    {\n        nChange += GetChange(txout);\n        if (!MoneyRange(nChange))\n            throw std::runtime_error(std::string(__func__) + \": value out of range\");\n    }\n    return nChange;\n}\n\nCAmount CWalletTx::GetDebit(const isminefilter& filter, CAccount* forAccount, bool includeChildren) const\n{\n    if (tx->vin.empty())\n        return 0;\n\n    CAmount debit = 0;\n    if(filter & ISMINE_SPENDABLE)\n    {\n        if (debitCached.find(forAccount) != debitCached.end())\n            debit += debitCached[forAccount];\n        else\n        {\n            debitCached[forAccount] = pwallet->GetDebit(*this, ISMINE_SPENDABLE, forAccount);\n            debit += debitCached[forAccount];\n        }\n    }\n    if(filter & ISMINE_WATCH_ONLY)\n    {\n        if (watchDebitCached.find(forAccount) != watchDebitCached.end())\n            debit += watchDebitCached[forAccount];\n        else\n        {\n            watchDebitCached[forAccount] = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY, forAccount);\n            debit += watchDebitCached[forAccount];\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                debit += GetDebit(filter, childAccount, false);\n            }\n        }\n    }\n    return debit;\n}\n\nCAmount CWalletTx::GetCredit(const isminefilter& filter, CAccount* forAccount, bool includeChildren) const\n{\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if (IsCoinBase() && GetBlocksToMaturity() > 0)\n        return 0;\n\n    CAmount credit = 0;\n    if (filter & ISMINE_SPENDABLE)\n    {\n        // GetBalance can assume transactions in mapWallet won't change\n        if (creditCached.find(forAccount) != creditCached.end())\n            credit += creditCached[forAccount];\n        else\n        {\n            creditCached[forAccount] = pwallet->GetCredit(*this, ISMINE_SPENDABLE, forAccount);\n            credit += creditCached[forAccount];\n        }\n    }\n    if (filter & ISMINE_WATCH_ONLY)\n    {\n        if (watchCreditCached.find(forAccount) != watchCreditCached.end())\n            credit += watchCreditCached[forAccount];\n        else\n        {\n            watchCreditCached[forAccount] = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY, forAccount);\n            credit += watchCreditCached[forAccount];\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                credit += GetCredit(filter, childAccount, false);\n            }\n        }\n    }\n    return credit;\n}\n\n//fixme: (FUT) As the cache is -after- some of the checks and the calls after the checks are basically the same as for normal getcredit\n//Is there any point to immatureCreditCached, or can we just share the getcredit cache and always call the tests.\n//NB! We must always call the tests as obviously they change so can't be cached.\nCAmount CWalletTx::GetImmatureCredit(bool fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (pwallet == 0)\n        return 0;\n\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if (!IsCoinBase() || GetBlocksToMaturity() <= 0 || GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n    if (fUseCache && immatureCreditCached.find(forAccount) != immatureCreditCached.end())\n    {\n        nCredit = immatureCreditCached[forAccount];\n    }\n    else\n    {\n        for (unsigned int i = 0; i < tx->vout.size(); i++)\n        {\n            if (!pwallet->IsSpent(COutPoint(GetHash(), i)) && !pwallet->IsSpent(COutPoint(nHeight, nIndex, i)))\n            {\n                const CTxOut &txout = tx->vout[i];\n                if (!forAccount || IsMine(*forAccount, txout))\n                {\n                    if (!IsPoW2WitnessLocked(txout, chainActive.Tip()->nHeight))\n                    {\n                        // Work around an issue where (for another year at least) some witness accounts have a spending key that comes from a different account (and we don't want the balance to count toward both accounts)\n                        if (forAccount && txout.GetType() == CTxOutType::PoW2WitnessOutput && !forAccount->IsPoW2Witness())\n                            continue;\n\n                        nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);\n                        if (!MoneyRange(nCredit))\n                            throw std::runtime_error(\"CWalletTx::GetAvailableCredit() : value out of range\");\n                    }\n                }\n            }\n        }\n        immatureCreditCached[forAccount] = nCredit;\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nCredit += GetImmatureCredit(fUseCache, childAccount, false);\n            }\n        }\n    }\n\n    return nCredit;\n}\n\nCAmount CWalletTx::GetImmatureCreditIncludingLockedWitnesses(bool fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (pwallet == 0)\n        return 0;\n\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if (!IsCoinBase() || GetBlocksToMaturity() <= 0 || GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n\n    if (fUseCache && immatureCreditCachedIncludingLockedWitnesses.find(forAccount) != immatureCreditCachedIncludingLockedWitnesses.end())\n    {\n        nCredit = immatureCreditCachedIncludingLockedWitnesses[forAccount];\n    }\n    else\n    {\n        for (unsigned int i = 0; i < tx->vout.size(); i++)\n        {\n            if (!pwallet->IsSpent(COutPoint(GetHash(), i)) && !pwallet->IsSpent(COutPoint(nHeight, nIndex, i)))\n            {\n                const CTxOut &txout = tx->vout[i];\n                if (!forAccount || IsMine(*forAccount, txout))\n                {\n                    // Work around an issue where (for another year at least) some witness accounts have a spending key that comes from a different account (and we don't want the balance to count toward both accounts)\n                    if (forAccount && txout.GetType() == CTxOutType::PoW2WitnessOutput && !forAccount->IsPoW2Witness())\n                        continue;\n\n                    nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);\n                    if (!MoneyRange(nCredit))\n                        throw std::runtime_error(\"CWalletTx::GetAvailableCredit() : value out of range\");\n                }\n            }\n        }\n\n        immatureCreditCachedIncludingLockedWitnesses[forAccount] = nCredit;\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nCredit += GetImmatureCreditIncludingLockedWitnesses(fUseCache, childAccount, false);\n            }\n        }\n    }\n\n    return nCredit;\n}\n\nCAmount CWalletTx::GetAvailableCredit(bool fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (pwallet == 0)\n        return 0;\n\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if ((IsCoinBase() && GetBlocksToMaturity() > 0) || GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n    if (fUseCache && availableCreditCached.find(forAccount) != availableCreditCached.end())\n    {\n        nCredit = availableCreditCached[forAccount];\n    }\n    else\n    {\n        for (unsigned int i = 0; i < tx->vout.size(); i++)\n        {\n            if (!pwallet->IsSpent(COutPoint(GetHash(), i)) && !pwallet->IsSpent(COutPoint(nHeight, nIndex, i)))\n            {\n                const CTxOut &txout = tx->vout[i];\n                if (!forAccount || IsMine(*forAccount, txout))\n                {\n                    if (!IsPoW2WitnessLocked(txout, chainActive.Tip()->nHeight))\n                    {\n                        // Work around an issue where (for another year at least) some witness accounts have a spending key that comes from a different account (and we don't want the balance to count toward both accounts)\n                        if (forAccount && (txout.GetType() == CTxOutType::PoW2WitnessOutput && !forAccount->IsPoW2Witness()))\n                            continue;\n\n                        nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);\n                        if (!MoneyRange(nCredit))\n                            throw std::runtime_error(\"CWalletTx::GetAvailableCredit() : value out of range\");\n                    }\n                }\n            }\n        }\n        availableCreditCached[forAccount] = nCredit;\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nCredit += GetAvailableCredit(fUseCache, childAccount, false);\n            }\n        }\n    }\n\n    return nCredit;\n}\n\nCAmount CWalletTx::GetAvailableCreditIncludingLockedWitnesses(bool fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (pwallet == 0)\n        return 0;\n\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if ((IsCoinBase() && GetBlocksToMaturity() > 0) || GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n    if (fUseCache && availableCreditCachedIncludingLockedWitnesses.find(forAccount) != availableCreditCachedIncludingLockedWitnesses.end())\n    {\n        nCredit = availableCreditCachedIncludingLockedWitnesses[forAccount];\n    }\n    else\n    {\n        for (unsigned int i = 0; i < tx->vout.size(); i++)\n        {\n            if (!pwallet->IsSpent(COutPoint(GetHash(), i)) && !pwallet->IsSpent(COutPoint(nHeight, nIndex, i)))\n            {\n                const CTxOut &txout = tx->vout[i];\n\n                // Work around an issue where (for another year at least) some witness accounts have a spending key that comes from a different account (and we don't want the balance to count toward both accounts)\n                if (forAccount && txout.GetType() == CTxOutType::PoW2WitnessOutput && !forAccount->IsPoW2Witness())\n                    continue;\n                \n                if (!forAccount || IsMine(*forAccount, txout))\n                {\n                    nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);\n                    if (!MoneyRange(nCredit))\n                        throw std::runtime_error(\"CWalletTx::GetAvailableCredit() : value out of range\");\n                }\n            }\n        }\n        availableCreditCachedIncludingLockedWitnesses[forAccount] = nCredit;\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nCredit += GetAvailableCreditIncludingLockedWitnesses(fUseCache, childAccount, false);\n            }\n        }\n    }\n\n    return nCredit;\n}\n\nCAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n    if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())\n    {\n        if (fUseCache && immatureWatchCreditCached.find(forAccount) != immatureWatchCreditCached.end())\n        {\n            nCredit = immatureWatchCreditCached[forAccount];\n        }\n        else\n        {\n            immatureWatchCreditCached[forAccount] = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);\n            nCredit = immatureWatchCreditCached[forAccount];\n        }\n        if (forAccount && includeChildren)\n        {\n            for (const auto& accountItem : pwallet->mapAccounts)\n            {\n                const auto& childAccount = accountItem.second;\n                if (childAccount->getParentUUID() == forAccount->getUUID())\n                {\n                    nCredit += GetImmatureWatchOnlyCredit(fUseCache, childAccount, false);\n                }\n            }\n        }\n    }\n\n    return nCredit;\n}\n\nCAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache, const CAccount* forAccount, bool includeChildren) const\n{\n    if (pwallet == 0)\n        return 0;\n\n    // Must wait until coinbase is safely deep enough in the chain before valuing it\n    if ((IsCoinBase() && GetBlocksToMaturity() > 0) || GetDepthInMainChain() < 0)\n        return 0;\n\n    CAmount nCredit = 0;\n    if (fUseCache && availableWatchCreditCached.find(forAccount) != availableWatchCreditCached.end())\n    {\n        nCredit = availableWatchCreditCached[forAccount];\n    }\n    else\n    {\n        for (unsigned int i = 0; i < tx->vout.size(); i++)\n        {\n            if (!pwallet->IsSpent(COutPoint(GetHash(), i)) && !pwallet->IsSpent(COutPoint(nHeight, nIndex, i)))\n            {\n                const CTxOut &txout = tx->vout[i];\n                // Work around an issue where (for another year at least) some witness accounts have a spending key that comes from a different account (and we don't want the balance to count toward both accounts)\n                if (forAccount && txout.GetType() == CTxOutType::PoW2WitnessOutput && !forAccount->IsPoW2Witness())\n                    continue;\n                        \n                nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);\n                if (!MoneyRange(nCredit))\n                    throw std::runtime_error(\"CWalletTx::GetAvailableCredit() : value out of range\");\n            }\n        }\n\n        availableWatchCreditCached[forAccount] = nCredit;\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& accountItem : pwallet->mapAccounts)\n        {\n            const auto& childAccount = accountItem.second;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nCredit += GetAvailableWatchOnlyCredit(fUseCache, childAccount, false);\n            }\n        }\n    }\n    return nCredit;\n}\n\nCAmount CWalletTx::GetChange() const\n{\n    if (fChangeCached)\n        return nChangeCached;\n    nChangeCached = pwallet->GetChange(*this);\n    fChangeCached = true;\n    return nChangeCached;\n}\n\nextern bool IsMine(const CKeyStore* forAccount, const CWalletTx& tx);\n\n\nCAmount CWallet::GetBalanceForDepth(int minDepth, const CAccount* forAccount, bool includePoW2LockedWitnesses, bool includeChildren) const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n           \n            //fixme: (FUT) (ACCOUNT) - is this okay? Should it be cached or something? (CBSU?)\n            if (pcoin->GetDepthInMainChain() < minDepth)\n                continue;\n            if (pcoin->IsTrusted() && !pcoin->isAbandoned() && pcoin->mapValue.count(\"replaced_by_txid\") == 0)\n            {\n                if (!forAccount || ::IsMine(forAccount, *pcoin))\n                {\n                    CAmount nCredit = includePoW2LockedWitnesses ? pcoin->GetAvailableCreditIncludingLockedWitnesses(true, forAccount, false) : pcoin->GetAvailableCredit(true, forAccount, false);\n                    nTotal += nCredit;\n                }\n            }\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& [childAccountUUID, childAccount] : mapAccounts)\n        {\n            (unused) childAccountUUID;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nTotal += GetBalanceForDepth(minDepth, childAccount, includePoW2LockedWitnesses, false);\n            }\n        }\n    }\n\n    return nTotal;\n}\n\nCAmount CWallet::GetBalance(const CAccount* forAccount, bool useCache, bool includePoW2LockedWitnesses, bool includeChildren) const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n           \n            //fixme: (FUT) (ACCOUNT) - is this okay? Should it be cached or something? (CBSU?)\n            if (!forAccount || ::IsMine(forAccount, *pcoin))\n            {\n                if (pcoin->IsTrusted() && !pcoin->isAbandoned() && pcoin->mapValue.count(\"replaced_by_txid\") == 0)\n                {\n                    CAmount nCredit = includePoW2LockedWitnesses ? pcoin->GetAvailableCreditIncludingLockedWitnesses(useCache, forAccount, false) : pcoin->GetAvailableCredit(useCache, forAccount, false);\n                    nTotal += nCredit;\n                }\n            }\n\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& [childAccountUUID, childAccount] : mapAccounts)\n        {\n            (unused) childAccountUUID;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nTotal += GetBalance(childAccount, useCache, includePoW2LockedWitnesses, false);\n            }\n        }\n    }\n\n    return nTotal;\n}\n\nCAmount CWallet::GetLockedBalance(const CAccount* forAccount, bool includeChildren)\n{\n    //fixme: (FUT) (ACCOUNTS) This can probably be drastically improved.\n    WalletBalances balances;\n    GetBalances(balances, forAccount, includeChildren);\n    return balances.totalLocked;;\n}\n\nvoid CWallet::GetBalances(WalletBalances& balances, const CAccount* forAccount, bool includeChildren) const\n{\n    LOCK2(cs_main, cs_wallet);\n    balances.availableIncludingLocked = GetBalance(forAccount, true, true, includeChildren);\n    balances.availableExcludingLocked = GetBalance(forAccount, true, false, includeChildren);\n    balances.availableLocked = balances.availableIncludingLocked - balances.availableExcludingLocked;\n    balances.unconfirmedIncludingLocked = GetUnconfirmedBalance(forAccount, true, includeChildren);\n    balances.unconfirmedExcludingLocked = GetUnconfirmedBalance(forAccount, false, includeChildren);\n    balances.unconfirmedLocked = balances.unconfirmedIncludingLocked - balances.unconfirmedExcludingLocked;\n    balances.immatureIncludingLocked = GetImmatureBalance(forAccount, true, includeChildren);\n    balances.immatureExcludingLocked = GetImmatureBalance(forAccount, false, includeChildren);\n    balances.immatureLocked = balances.immatureIncludingLocked - balances.immatureExcludingLocked;\n    balances.totalLocked = balances.availableLocked + balances.unconfirmedLocked + balances.immatureLocked;\n}\n\nCAmount CWallet::GetUnconfirmedBalance(const CAccount* forAccount, bool includePoW2LockedWitnesses, bool includeChildren) const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n            //fixme: (FUT) (ACCOUNTS) - is this okay? Should it be cached or something? (CBSU?)\n            if (!forAccount || ::IsMine(forAccount, *pcoin))\n            {\n                if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool() && !pcoin->isAbandoned() && pcoin->mapValue.count(\"replaced_by_txid\") == 0)\n                {\n                    nTotal += includePoW2LockedWitnesses ? pcoin->GetAvailableCreditIncludingLockedWitnesses(true, forAccount, false) : pcoin->GetAvailableCredit(true, forAccount, false);\n                }\n            }\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& [accountUUID, childAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nTotal += GetUnconfirmedBalance(childAccount, includePoW2LockedWitnesses, false);\n            }\n        }\n    }\n    return nTotal;\n}\n\nCAmount CWallet::GetImmatureBalance(const CAccount* forAccount, bool includePoW2LockedWitnesses, bool includeChildren) const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n            if (!pcoin->isAbandoned() && pcoin->GetDepthInMainChain() > 0 && pcoin->mapValue.count(\"replaced_by_txid\") == 0)\n            {\n                if (!forAccount || ::IsMine(forAccount, *pcoin))\n                {\n                    nTotal += includePoW2LockedWitnesses ? pcoin->GetImmatureCreditIncludingLockedWitnesses(true, forAccount, false) : pcoin->GetImmatureCredit(true, forAccount, false);\n                }\n            }\n        }\n    }\n    if (forAccount && includeChildren)\n    {\n        for (const auto& [accountUUID, childAccount] : mapAccounts)\n        {\n            (unused) accountUUID;\n            if (childAccount->getParentUUID() == forAccount->getUUID())\n            {\n                nTotal += GetImmatureBalance(childAccount, includePoW2LockedWitnesses, false);\n            }\n        }\n    }\n    return nTotal;\n}\n\nCAmount CWallet::GetWatchOnlyBalance(int minDepth, const CAccount* forAccount, bool includeChildren) const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n           \n            if (pcoin->GetDepthInMainChain() < minDepth)\n                continue;\n            if (pcoin->IsTrusted())\n                nTotal += pcoin->GetAvailableWatchOnlyCredit(true, forAccount, includeChildren);\n        }\n    }\n\n    return nTotal;\n}\n\nCAmount CWallet::GetUnconfirmedWatchOnlyBalance() const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n            if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())\n                nTotal += pcoin->GetAvailableWatchOnlyCredit();\n        }\n    }\n    return nTotal;\n}\n\nCAmount CWallet::GetImmatureWatchOnlyBalance() const\n{\n    CAmount nTotal = 0;\n    {\n        LOCK2(cs_main, cs_wallet);\n        for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\n        {\n            const CWalletTx* pcoin = &(*it).second;\n            nTotal += pcoin->GetImmatureWatchOnlyCredit();\n        }\n    }\n    return nTotal;\n}\n\n//fixme: (Future). We temporarily keep this around for debugging purposes, in future we can remove it.\n#if 0\n// Calculate total balance in a different way from GetBalance. The biggest\n// difference is that GetBalance sums up all unspent TxOuts paying to the\n// wallet, while this sums up both spent and unspent TxOuts paying to the\n// wallet, and then subtracts the values of TxIns spending from the wallet. This\n// also has fewer restrictions on which unconfirmed transactions are considered\n// trusted.\nCAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const boost::uuids::uuid* accountUUID, bool includeChildren) const\n{\n    LOCK2(cs_main, cs_wallet);\n\n    LogPrintf(\"GetLegacyBalanceForAccount [%s]\\n\", getUUIDAsString(*accountUUID));\n    \n    CAccount* forAccount = NULL;\n    if (accountUUID && mapAccounts.find(*accountUUID) != mapAccounts.end())\n        forAccount = mapAccounts.find(*accountUUID)->second;\n\n    CAmount balance = 0;\n\n\n    //checkme: (MUNT) - Is fee handled right?\n    for (const auto& entry : mapWallet)\n    {\n        const CWalletTx& wtx = entry.second;\n        const int depth = wtx.GetDepthInMainChain();\n        \n        if (depth < 0 || !CheckFinalTx(*wtx.tx, chainActive) || wtx.GetBlocksToMaturity() > 0 || wtx.isAbandoned())\n        {\n            continue;\n        }\n\n        if (depth >= minDepth)\n        {\n            CAmount nCredit = wtx.GetCredit(filter, forAccount, includeChildren);\n            CAmount nDebit = wtx.GetDebit(filter, forAccount, includeChildren);\n            balance += nCredit;\n            balance -= nDebit;\n        }\n    }\n\n    return balance;\n}\n#endif\n\nCAmount CWallet::GetAvailableBalance(CAccount* forAccount, const CCoinControl* coinControl) const\n{\n    LOCK2(cs_main, cs_wallet);\n\n    CAmount balance = 0;\n    std::vector<COutput> vCoins;\n    AvailableCoins(forAccount, vCoins, true, coinControl);\n    for (const COutput& out : vCoins) {\n        if (out.fSpendable) {\n            balance += out.tx->tx->vout[out.i].nValue;\n        }\n    }\n    return balance;\n}\n\n\nstd::map<CTxDestination, CAmount> CWallet::GetAddressBalances()\n{\n    std::map<CTxDestination, CAmount> balances;\n\n    {\n        LOCK(cs_wallet);\n        for (const auto& walletEntry : mapWallet)\n        {\n            const CWalletTx *pcoin = &walletEntry.second;\n\n            if (!pcoin->IsTrusted())\n                continue;\n\n            if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)\n                continue;\n\n            int nDepth = pcoin->GetDepthInMainChain();\n            if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))\n                continue;\n\n            for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)\n            {\n                CTxDestination addr;\n                if (!IsMine(pcoin->tx->vout[i]))\n                    continue;\n                if(!ExtractDestination(pcoin->tx->vout[i], addr))\n                    continue;\n\n                CAmount n = (IsSpent(COutPoint(walletEntry.first, i))||IsSpent(COutPoint(walletEntry.second.nHeight, walletEntry.second.nIndex, i))) ? 0 : pcoin->tx->vout[i].nValue;\n\n                if (!balances.count(addr))\n                    balances[addr] = 0;\n                balances[addr] += n;\n            }\n        }\n    }\n\n    return balances;\n}\n"
  },
  {
    "path": "src/wallet/walletdb.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/walletdb.h\"\n\n#include \"base58.h\"\n#include \"consensus/tx_verify.h\"\n#include \"consensus/validation.h\"\n#include \"fs.h\"\n#include \"protocol.h\"\n#include \"serialize.h\"\n#include \"sync.h\"\n#include \"util.h\"\n#include \"util/time.h\"\n#include \"wallet/wallet.h\"\n\n#include <atomic>\n\n\n#include <boost/thread.hpp>\n\n#include <map>\n\nstatic std::map<CKeyID, int64_t> staticPoolCache;\n//\n// CWalletDB\n//\n\nbool CWalletDB::WriteRecipientName(const std::string& strAddress, const std::string& strName)\n{\n    return WriteIC(std::pair(std::string(\"name\"), strAddress), strName);\n}\n\nbool CWalletDB::EraseRecipientName(const std::string& strAddress)\n{\n    // This should only be used for sending addresses, never for receiving addresses,\n    // receiving addresses must always have an address book entry if they're not change return.\n    return EraseIC(std::pair(std::string(\"name\"), strAddress));\n}\n\nbool CWalletDB::WriteRecipientDescription(const std::string& strAddress, const std::string& strDescription)\n{\n    return WriteIC(std::pair(std::string(\"rcp_description\"), strAddress), strDescription);\n}\n\nbool CWalletDB::EraseRecipientDescription(const std::string& strDescription)\n{\n    return EraseIC(std::pair(std::string(\"rcp_description\"), strDescription));\n}\n\nbool CWalletDB::WriteRecipientPurpose(const std::string& strAddress, const std::string& strPurpose)\n{\n    return WriteIC(std::pair(std::string(\"purpose\"), strAddress), strPurpose);\n}\n\nbool CWalletDB::EraseRecipientPurpose(const std::string& strPurpose)\n{\n    return EraseIC(std::pair(std::string(\"purpose\"), strPurpose));\n}\n\nbool CWalletDB::WriteTx(const CWalletTx& wtx)\n{\n    auto hash = wtx.GetHash();\n\n    // Remove old format if present as we are trying to remove it\n    EraseIC(std::pair(std::string(\"tx\"), hash));\n\n    // Write only latest format\n    return WriteIC(std::pair(std::string(\"wtx\"), hash), wtx);\n}\n\nbool CWalletDB::EraseTx(uint256 hash)\n{\n    // Remove old format if present.\n    bool erasedOld = EraseIC(std::pair(std::string(\"tx\"), hash));\n    \n    // Remove new format if present.\n    bool erasedNew = EraseIC(std::pair(std::string(\"wtx\"), hash));\n    \n    // If either succeeded then we erased the transaction and can return true.\n    return (erasedOld || erasedNew);\n}\n\nbool CWalletDB::EraseKey(const CPubKey& vchPubKey)\n{\n    bool eraseKey = EraseIC(std::pair(std::string(\"keyHD\"), vchPubKey));\n    eraseKey = EraseIC(std::pair(std::string(\"key\"), vchPubKey)) || eraseKey;\n    return EraseIC(std::pair(std::string(\"keymeta\"), vchPubKey)) && eraseKey;\n}\n\nbool CWalletDB::EraseEncryptedKey(const CPubKey& vchPubKey)\n{\n    return EraseIC(std::pair(std::string(\"keymeta\"), vchPubKey)) && EraseIC(std::pair(std::string(\"ckey\"), vchPubKey));\n}\n\nbool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta, const std::string forAccount, int64_t nKeyChain)\n{\n    if (!WriteIC(std::pair(std::string(\"keymeta\"), vchPubKey), keyMeta, false)) {\n        return false;\n    }\n\n    // hash pubkey/privkey to accelerate wallet load\n    std::vector<unsigned char> vchKey;\n    vchKey.reserve(vchPubKey.size() + vchPrivKey.size());\n    vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());\n    vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());\n\n    return WriteIC(std::pair(std::string(\"key\"), vchPubKey), std::tuple(COMPACTSIZEVECTOR(vchPrivKey), Hash( vchKey.begin(), vchKey.end() ), forAccount, nKeyChain), false);\n}\n\nbool CWalletDB::WriteKeyOverride(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const std::string forAccount, int64_t nKeyChain)\n{\n    // hash pubkey/privkey to accelerate wallet load\n    std::vector<unsigned char> vchKey;\n    vchKey.reserve(vchPubKey.size() + vchPrivKey.size());\n    vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());\n    vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());\n\n    //Erase previous value if any.and new privkey is not null\n    CPrivKey nullKey;\n    if (vchPrivKey == nullKey)\n    {\n        WriteIC(std::pair(std::string(\"key\"), vchPubKey), std::tuple(COMPACTSIZEVECTOR(vchPrivKey), Hash( vchKey.begin(), vchKey.end() ), forAccount, nKeyChain), false);\n        return true;\n    }\n    EraseIC(std::pair(std::string(\"key\"), vchPubKey));\n    return WriteIC(std::pair(std::string(\"key\"), vchPubKey), std::tuple(COMPACTSIZEVECTOR(vchPrivKey), Hash( vchKey.begin(), vchKey.end() ), forAccount, nKeyChain), false);\n}\n\nbool CWalletDB::WriteKeyHD(const CPubKey& vchPubKey, const int64_t HDKeyIndex, int64_t keyChain, const CKeyMetadata &keyMeta, const std::string forAccount)\n{\n    if (!WriteIC(std::pair(std::string(\"keymeta\"), vchPubKey), keyMeta, false))\n        return false;\n\n    return WriteIC(std::pair(std::string(\"keyHD\"), vchPubKey), std::tuple(HDKeyIndex, keyChain, forAccount), false);\n}\n\nbool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta, const std::string forAccount, int64_t nKeyChain)\n{\n    const bool fEraseUnencryptedKey = true;\n\n    if (!WriteIC(std::pair(std::string(\"keymeta\"), vchPubKey), keyMeta)) {\n        return false;\n    }\n\n    if (!WriteIC(std::pair(std::string(\"ckey\"), vchPubKey), std::tuple(COMPACTSIZEVECTOR(vchCryptedSecret), forAccount, nKeyChain), false)) {\n        return false;\n    }\n    if (fEraseUnencryptedKey)\n    {\n        EraseIC(std::pair(std::string(\"key\"), vchPubKey));\n        EraseIC(std::pair(std::string(\"wkey\"), vchPubKey));\n    }\n\n    return true;\n}\n\nbool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)\n{\n    return WriteIC(std::pair(std::string(\"mkey\"), nID), kMasterKey, true);\n}\n\nbool CWalletDB::EraseMasterKey(unsigned int nID)\n{\n    return EraseIC(std::pair(std::string(\"mkey\"), nID));\n}\n\nbool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)\n{\n    return WriteIC(std::pair(std::string(\"cscript\"), hash), *(const CScriptBase*)(&redeemScript), false);\n}\n\nbool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)\n{\n    if (!WriteIC(std::pair(std::string(\"watchmeta\"), *(const CScriptBase*)(&dest)), keyMeta)) {\n        return false;\n    }\n    return WriteIC(std::pair(std::string(\"watchs\"), *(const CScriptBase*)(&dest)), '1');\n}\n\nbool CWalletDB::EraseWatchOnly(const CScript &dest)\n{\n    if (!EraseIC(std::pair(std::string(\"watchmeta\"), *(const CScriptBase*)(&dest)))) {\n        return false;\n    }\n    return EraseIC(std::pair(std::string(\"watchs\"), *(const CScriptBase*)(&dest)));\n}\n\nbool CWalletDB::WriteBestBlock(const CBlockLocator& locator)\n{\n    WriteIC(std::string(\"bestblock\"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan\n    return WriteIC(std::string(\"bestblock_nomerkle\"), locator);\n}\n\nbool CWalletDB::ReadBestBlock(CBlockLocator& locator)\n{\n    if (batch.Read(std::string(\"bestblock\"), locator) && !locator.vHave.empty()) return true;\n    return batch.Read(std::string(\"bestblock_nomerkle\"), locator);\n}\n\nbool CWalletDB::EraseLastSPVBlockProcessed()\n{\n    return EraseIC(std::string(\"lastspvblock\"));\n}\n\nbool CWalletDB::WriteLastSPVBlockProcessed(const CBlockLocator& locator, const int64_t time)\n{\n    return WriteIC(std::string(\"lastspvblock\"), std::pair(locator, time));\n}\n\nbool CWalletDB::ReadLastSPVBlockProcessed(CBlockLocator& locator, int64_t& time)\n{\n    std::pair<CBlockLocator, int64_t> value;\n    if (batch.Read(std::string(\"lastspvblock\"), value))\n    {\n        locator = value.first;\n        time = value.second;\n        return true;\n    }\n\n    return false;\n}\n\nbool CWalletDB::WriteMiningAddressString(const std::string& miningAddress)\n{\n    return WriteIC(std::string(\"mining_address_string\"), miningAddress);\n}\n\nbool CWalletDB::ReadMiningAddressString(std::string& miningAddress)\n{\n    return batch.Read(std::string(\"mining_address_string\"), miningAddress);\n}\n\nbool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)\n{\n    return WriteIC(std::string(\"orderposnext\"), nOrderPosNext);\n}\n/*MUNT - no default key (accounts)\nbool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)\n{\n    return WriteIC(std::string(\"defaultkey\"), vchPubKey);\n}\n*/\nbool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)\n{\n    return batch.Read(std::pair(std::string(\"pool\"), nPool), keypool);\n}\n\nbool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)\n{\n    staticPoolCache[keypool.vchPubKey.GetID()] = nPool;\n    return WriteIC(std::pair(std::string(\"pool\"), nPool), keypool);\n}\n\nbool CWalletDB::ErasePool(CWallet* pwallet, int64_t nPool, bool forceErase)\n{\n    // If account uses a fixed keypool then never remove keys from it.\n    if (!forceErase)\n    {\n        for (auto iter : pwallet->mapAccounts)\n        {\n            if (iter.second->IsFixedKeyPool() || iter.second->IsMinimalKeyPool())\n            {\n                if ((iter.second->setKeyPoolExternal.find(nPool) != iter.second->setKeyPoolExternal.end()) || (iter.second->setKeyPoolInternal.find(nPool) != iter.second->setKeyPoolInternal.end()))\n                {\n                    return true;\n                }\n            }\n        }\n    }\n\n    return EraseIC(std::pair(std::string(\"pool\"), nPool));\n}\n\nbool CWalletDB::ErasePool(CWallet* pwallet, const CKeyID& id, bool forceErase)\n{\n    int64_t keyIndex = staticPoolCache[id];\n    // If account uses a fixed keypool then never remove keys from it.\n    bool allowErase = true;\n    if (!forceErase)\n    {\n        for (auto iter : pwallet->mapAccounts)\n        {\n            if ((iter.second->IsFixedKeyPool() || iter.second->IsMinimalKeyPool()))\n            {\n                if ((iter.second->setKeyPoolExternal.find(keyIndex) != iter.second->setKeyPoolExternal.end()) || (iter.second->setKeyPoolInternal.find(keyIndex) != iter.second->setKeyPoolInternal.end()))\n                {\n                    return true;\n                }\n            }\n        }\n    }\n\n    //fixme: (Post-2.1) (CBSU)\n    //Remove from internal keypool, key has been used so shouldn't circulate anymore - address will now reside only in address book.\n    for (auto iter : pwallet->mapAccounts)\n    {\n        iter.second->setKeyPoolExternal.erase(keyIndex);\n        iter.second->setKeyPoolInternal.erase(keyIndex);\n    }\n\n    //Remove from disk\n    if (allowErase)\n        return EraseIC(std::pair(std::string(\"pool\"), staticPoolCache[id]));\n    else\n        return true;\n}\n\nbool CWalletDB::HasPool(CWallet* pwallet, const CKeyID& id)\n{\n    //Remove from disk\n    return batch.Exists(std::pair(std::string(\"pool\"), staticPoolCache[id]));\n}\n\nbool CWalletDB::WriteMinVersion(int nVersion)\n{\n    return WriteIC(std::string(\"minversion\"), nVersion);\n}\n\nbool CWalletDB::WriteAccountLabel(const std::string& strUUID, const std::string& strLabel)\n{\n    return WriteIC(std::pair(std::string(\"acclabel\"), strUUID), strLabel);\n}\n\nbool CWalletDB::EraseAccountLabel(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"acclabel\"), strUUID));\n}\n\nbool CWalletDB::WriteAccountLinks(const std::string& strUUID,  const std::map<std::string, std::string>& accountLinks)\n{\n    return WriteIC(std::pair(std::string(\"accextlinks\"), strUUID), accountLinks);\n}\n\nbool CWalletDB::EraseAccountLinks(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"accextlinks\"), strUUID));\n}\n\nbool CWalletDB::WriteAccountCompoundingSettings(const std::string& strUUID, const CAmount compoundAmount)\n{\n    return WriteIC(std::pair(std::string(\"acc_compound\"), strUUID), compoundAmount);\n}\n\nbool CWalletDB::EraseAccountCompoundingSettings(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"acc_compound\"), strUUID));\n}\n\nbool CWalletDB::WriteAccountCompoundingPercentSettings(const std::string& strUUID, const int32_t compoundPercent)\n{\n    return WriteIC(std::pair(std::string(\"acc_compound_percent\"), strUUID), compoundPercent);\n}\n\nbool CWalletDB::EraseAccountCompoundingPercentSettings(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"acc_compound_percent\"), strUUID));\n}\n\nbool CWalletDB::WriteAccountNonCompoundWitnessEarningsScript(const std::string& strUUID, const CScript& earningsScript)\n{\n    return WriteIC(std::pair(std::string(\"acc_non_compound_wit_earn_script\"), strUUID), *(const CScriptBase*)(&earningsScript));\n}\n\nbool CWalletDB::EraseAccountNonCompoundWitnessEarningsScript(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"acc_non_compound_wit_earn_script\"), strUUID));\n}\n\nbool CWalletDB::WriteAccountRewardTemplate(const std::string& strUUID, const CWitnessRewardTemplate& rewardTemplate)\n{\n    return WriteIC(std::pair(std::string(\"acc_reward_template\"), strUUID), rewardTemplate);\n}\n\nbool CWalletDB::EraseAccountRewardTemplate(const std::string& strUUID)\n{\n    return EraseIC(std::pair(std::string(\"acc_reward_template\"), strUUID));\n}\n\nbool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount* account)\n{\n    if (account->IsHD())\n      return WriteIC(std::pair(std::string(\"acchd\"), strAccount), *((CAccountHD*)account));\n    else\n      return WriteIC(std::pair(std::string(\"accleg\"), strAccount), *account);\n}\n\nbool CWalletDB::EraseAccount(const std::string& strAccount, const CAccount* account)\n{\n    if (account->IsHD())\n      return EraseIC(std::pair(std::string(\"acchd\"), strAccount));\n    else\n      return EraseIC(std::pair(std::string(\"accleg\"), strAccount));\n}\n\nbool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)\n{\n    return WriteIC(std::pair(std::string(\"acentry\"), std::pair(acentry.strAccount, nAccEntryNum)), acentry);\n}\n\nCAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)\n{\n    std::list<CAccountingEntry> entries;\n    ListAccountCreditDebit(strAccount, entries);\n\n    CAmount nCreditDebit = 0;\n    for (const CAccountingEntry& entry : entries)\n        nCreditDebit += entry.nCreditDebit;\n\n    return nCreditDebit;\n}\n\nvoid CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)\n{\n    bool fAllAccounts = (strAccount == \"*\");\n\n    Dbc* pcursor = batch.GetCursor();\n    if (!pcursor)\n        throw std::runtime_error(std::string(__func__) + \": cannot create DB cursor\");\n    bool setRange = true;\n    while (true)\n    {\n        // Read next record\n        CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n        if (setRange)\n            ssKey << std::pair(std::string(\"acentry\"), std::pair((fAllAccounts ? std::string(\"\") : strAccount), uint64_t(0)));\n        CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n        int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);\n        setRange = false;\n        if (ret == DB_NOTFOUND)\n            break;\n        else if (ret != 0)\n        {\n            pcursor->close();\n            throw std::runtime_error(std::string(__func__) + \": error scanning DB\");\n        }\n\n        // Unserialize\n        std::string strType;\n        ssKey >> strType;\n        if (strType != \"acentry\")\n            break;\n        CAccountingEntry acentry;\n        ssKey >> acentry.strAccount;\n        if (!fAllAccounts && acentry.strAccount != strAccount)\n            break;\n\n        ssValue >> acentry;\n        ssKey >> acentry.nEntryNo;\n        entries.push_back(acentry);\n    }\n\n    pcursor->close();\n}\n\nclass CWalletScanState {\npublic:\n    unsigned int nKeys;\n    unsigned int nCKeys;\n    unsigned int nKeyMeta;\n    bool fIsEncrypted;\n    bool fAnyUnordered;\n    int nFileVersion;\n    std::vector<uint256> vWalletUpgrade;\n\n    CWalletScanState() {\n        nKeys = nCKeys = nKeyMeta = 0;\n        fIsEncrypted = false;\n        fAnyUnordered = false;\n        nFileVersion = 0;\n    }\n};\n\nbool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletScanState &wss, std::string& strType, std::string& strErr)\n{\n    try\n    {\n        // Unserialize\n        // Taking advantage of the fact that pair serialization\n        // is just the two items serialized one after the other\n        ssKey >> strType;\n        if (strType == \"name\")\n        {\n            std::string strAddress;\n            ssKey >> strAddress;\n            ssValue >> pwallet->mapAddressBook[strAddress].name;\n        }\n        else if (strType == \"rcp_description\")\n        {\n            std::string strAddress;\n            ssKey >> strAddress;\n            ssValue >> pwallet->mapAddressBook[strAddress].description;\n        }\n        else if (strType == \"purpose\")\n        {\n            std::string strAddress;\n            ssKey >> strAddress;\n            ssValue >> pwallet->mapAddressBook[strAddress].purpose;\n        }\n        else if (strType == \"wtx\" || strType == \"tx\")\n        {\n            // Work around for a mistake in initial unity (for mobile) rollout\n            // Where format changed in a way that wasn't fully 'backwards' compatible with future desktop upgrades.\n            // For desktop we introduce 'wtx' to do the upgrade 'right', but on mobile 'tx' is already also upgraded so we need to treat it as such (only on mobile)\n            // wtx is treated the same on both and should be preffered in future - we should phase out and remove 'tx' in future.\n            //fixme: (FUTURE) - Remove 'tx' completely once wallets are upgraded; may have to write some code to forcefully upgrade all 'tx' to 'wtx'\n            #ifndef PLATFORM_MOBILE\n                // Force old serialization version\n                if (strType == \"tx\")\n                {\n                    ssValue.SetVersion(2010000);\n                }\n            #endif\n\n            uint256 hash;\n            ssKey >> hash;\n            CWalletTx wtx;\n            ssValue >> wtx;\n            CValidationState state;\n\n            if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))\n            {\n                return false;\n            }\n\n            // Undo serialize changes in 31600\n            if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)\n            {\n                if (!ssValue.empty())\n                {\n                    char fTmp;\n                    char fUnused;\n                    ssValue >> fTmp >> fUnused >> wtx.strFromAccount;\n                    strErr = strprintf(\"LoadWallet() upgrading tx ver=%d %d '%s' %s\", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());\n                    wtx.fTimeReceivedIsTxTime = fTmp;\n                }\n                else\n                {\n                    strErr = strprintf(\"LoadWallet() repairing tx ver=%d %s\", wtx.fTimeReceivedIsTxTime, hash.ToString());\n                    wtx.fTimeReceivedIsTxTime = 0;\n                }\n                wss.vWalletUpgrade.push_back(hash);\n            }\n\n            if (wtx.nOrderPos == -1)\n                wss.fAnyUnordered = true;\n\n            pwallet->LoadToWallet(wtx);\n        }\n        else if (strType == \"acentry\")\n        {\n            std::string strAccount;\n            ssKey >> strAccount;\n            uint64_t nNumber;\n            ssKey >> nNumber;\n            if (nNumber > pwallet->nAccountingEntryNumber) {\n                pwallet->nAccountingEntryNumber = nNumber;\n            }\n\n            if (!wss.fAnyUnordered)\n            {\n                CAccountingEntry acentry;\n                ssValue >> acentry;\n                if (acentry.nOrderPos == -1)\n                    wss.fAnyUnordered = true;\n            }\n        }\n        else if (strType == \"watchs\")\n        {\n            CScript script;\n            ssKey >> *(CScriptBase*)(&script);\n            char fYes;\n            ssValue >> fYes;\n            if (fYes == '1')\n                pwallet->LoadWatchOnly(script);\n\n            // Watch-only addresses have no birthday information for now,\n            // so set the wallet birthday to the beginning of time.\n            pwallet->nTimeFirstKey = 1;\n        }\n        else if (strType == \"keyHD\")\n        {\n            std::string forAccount = \"\";\n            CPubKey vchPubKey;\n            ssKey >> vchPubKey;\n            if (!vchPubKey.IsValid())\n            {\n                strErr = \"Error reading wallet database: CPubKey corrupt\";\n                return false;\n            }\n\n            int64_t HDKeyIndex;\n            int64_t keyChain;\n            ssValue >> HDKeyIndex;\n            ssValue >> keyChain;\n            ssValue >> forAccount;\n\n            if (pwallet->mapAccounts.count(getUUIDFromString(forAccount)) == 0)\n            {\n                strErr = \"Wallet contains key for non existent HD account\";\n                return false;\n            }\n\n            if (!pwallet->LoadHDKey(HDKeyIndex, keyChain, vchPubKey, forAccount))\n            {\n                strErr = \"Error reading wallet database: LoadKey (HD) failed\";\n                return false;\n            }\n        }\n        else if (strType == \"key\" || strType == \"wkey\")\n        {\n            std::string forAccount = \"\";\n            CPubKey vchPubKey;\n            ssKey >> vchPubKey;\n            if (!vchPubKey.IsValid())\n            {\n                strErr = \"Error reading wallet database: CPubKey corrupt\";\n                return false;\n            }\n            CKey key;\n            CPrivKey pkey;\n            uint256 hash;\n\n            if (strType == \"key\")\n            {\n                wss.nKeys++;\n                ssValue >> COMPACTSIZEVECTOR(pkey);\n            } else {\n                CWalletKey wkey;\n                ssValue >> wkey;\n                pkey = wkey.vchPrivKey;\n            }\n\n            // Old wallets store keys as \"key\" [pubkey] => [privkey]\n            // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key\n            // using EC operations as a checksum.\n            // Newer wallets store keys as \"key\"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while\n            // remaining backwards-compatible.\n            int64_t nKeyChain;\n            try\n            {\n                ssValue >> hash;\n                //1.6.0 wallets and upward store keys by account - older wallets will just lump all keys into a default account.\n                ssValue >> forAccount;\n                ssValue >> nKeyChain;\n            }\n            catch (...)\n            {\n                forAccount = getUUIDAsString(pwallet->activeAccount->getUUID());\n                nKeyChain = KEYCHAIN_EXTERNAL;\n            }\n\n            if (strType == \"key\" && GetBoolArg(\"-skipplainkeys\", false))\n            {\n                LogPrintf(\"Skipping unencrypted key [skipplainkeys] [%s]\\n\", CNativeAddress(vchPubKey.GetID()).ToString());\n            }\n            else\n            {\n                bool fSkipCheck = false;\n\n                if (!hash.IsNull())\n                {\n                    // hash pubkey/privkey to accelerate wallet load\n                    std::vector<unsigned char> vchKey;\n                    vchKey.reserve(vchPubKey.size() + pkey.size());\n                    vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());\n                    vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());\n\n                    if (Hash(vchKey.begin(), vchKey.end()) != hash)\n                    {\n                        strErr = \"Error reading wallet database: CPubKey/CPrivKey corrupt\";\n                        return false;\n                    }\n\n                    fSkipCheck = true;\n                }\n\n                if (!key.Load(pkey, vchPubKey, fSkipCheck))\n                {\n                    if ( pwallet->mapAccounts.count(getUUIDFromString(forAccount)) == 0 )\n                    {\n                        strErr = \"Wallet contains key for non existent account\";\n                        return false;\n                    }\n                    CAccount* targetAccount = pwallet->mapAccounts[getUUIDFromString(forAccount)];\n                    if (targetAccount->IsHD() && targetAccount->IsPoW2Witness())\n                    {\n                        //NULL key was expected in this case.\n                        key = CKey();\n                    }\n                    else\n                    {\n                        strErr = \"Error reading wallet database: CPrivKey corrupt\";\n                        return false;\n                    }\n                }\n                if (!pwallet->LoadKey(key, vchPubKey, forAccount, nKeyChain))\n                {\n                    strErr = \"Error reading wallet database: LoadKey failed\";\n                    return false;\n                }\n            }\n        }\n        else if (strType == \"mkey\")\n        {\n            unsigned int nID;\n            ssKey >> nID;\n            CMasterKey kMasterKey;\n            ssValue >> kMasterKey;\n            if(pwallet->mapMasterKeys.count(nID) != 0)\n            {\n                strErr = strprintf(\"Error reading wallet database: duplicate CMasterKey id %u\", nID);\n                return false;\n            }\n            pwallet->mapMasterKeys[nID] = kMasterKey;\n            if (pwallet->nMasterKeyMaxID < nID)\n                pwallet->nMasterKeyMaxID = nID;\n        }\n        else if (strType == \"ckey\")\n        {\n            std::string forAccount=\"\";\n            int64_t nKeyChain;\n            CPubKey vchPubKey;\n            ssKey >> vchPubKey;\n            if (!vchPubKey.IsValid())\n            {\n                strErr = \"Error reading wallet database: CPubKey corrupt\";\n                return false;\n            }\n            std::vector<unsigned char> vchPrivKey;\n            ssValue >> COMPACTSIZEVECTOR(vchPrivKey);\n            wss.nCKeys++;\n            try\n            {\n                //1.6.0 wallets and upward store keys by account - older wallets will just lump all keys into a default account.\n                ssValue >> forAccount;\n                ssValue >> nKeyChain;\n            }\n            catch (...)\n            {\n                forAccount = getUUIDAsString(pwallet->activeAccount->getUUID());\n                nKeyChain = KEYCHAIN_EXTERNAL;\n            }\n\n            if (GetBoolArg(\"-skipplainkeys\", false))\n            {\n                LogPrintf(\"Load crypted key [skipplainkeys] [%s]\\n\", CNativeAddress(vchPubKey.GetID()).ToString());\n            }\n\n            if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey, forAccount, nKeyChain))\n            {\n                strErr = \"Error reading wallet database: LoadCryptedKey failed\";\n                return false;\n            }\n            wss.fIsEncrypted = true;\n        }\n        else if (strType == \"keymeta\")\n        {\n            CPubKey vchPubKey;\n            ssKey >> vchPubKey;\n            CKeyMetadata keyMeta;\n            ssValue >> keyMeta;\n            wss.nKeyMeta++;\n\n            pwallet->LoadKeyMetadata(vchPubKey, keyMeta);\n\n            // find earliest key creation time, as wallet birthday\n            if (!pwallet->nTimeFirstKey ||\n                (keyMeta.nCreateTime < int64_t(pwallet->nTimeFirstKey)))\n                pwallet->nTimeFirstKey = keyMeta.nCreateTime;\n        }\n        else if (strType == \"pool\")\n        {\n            int64_t nIndex;\n            ssKey >> nIndex;\n            CKeyPool keypool;\n            ssValue >> keypool;\n\n            CAccount* forAccount = NULL;\n            std::string accountUUID = keypool.accountName;\n            // If we are importing an old legacy (pre HD) wallet - then this keypool becomes the keypool of our 'legacy' account\n            if (accountUUID.empty())\n            {\n                forAccount = pwallet->activeAccount;\n                keypool.nChain = KEYCHAIN_EXTERNAL;\n            }\n            else\n            {\n                if ( pwallet->mapAccounts.count(getUUIDFromString(accountUUID)) == 0 )\n                {\n                    strErr = \"Wallet contains key for non existent account\";\n                    return false;\n                }\n                forAccount = pwallet->mapAccounts[getUUIDFromString(accountUUID)];\n            }\n\n            if (keypool.nChain == KEYCHAIN_EXTERNAL)\n            {\n                forAccount->setKeyPoolExternal.insert(nIndex);\n            }\n            else\n            {\n                forAccount->setKeyPoolInternal.insert(nIndex);\n            }\n\n            pwallet->LoadKeyPool(nIndex, keypool);\n\n            staticPoolCache[keypool.vchPubKey.GetID()] = nIndex;\n        }\n        else if (strType == \"version\")\n        {\n            ssValue >> wss.nFileVersion;\n            if (wss.nFileVersion == 10300)\n                wss.nFileVersion = 300;\n        }\n        else if (strType == \"cscript\")\n        {\n            uint160 hash;\n            ssKey >> hash;\n            CScript script;\n            ssValue >> *(CScriptBase*)(&script);\n            if (!pwallet->LoadCScript(script))\n            {\n                strErr = \"Error reading wallet database: LoadCScript failed\";\n                return false;\n            }\n        }\n        else if (strType == \"orderposnext\")\n        {\n            ssValue >> pwallet->nOrderPosNext;\n        }\n        else if (strType == \"destdata\")\n        {\n            std::string strAddress, strKey, strValue;\n            ssKey >> strAddress;\n            ssKey >> strKey;\n            ssValue >> strValue;\n            if (!pwallet->LoadDestData(CNativeAddress(strAddress).Get(), strKey, strValue))\n            {\n                strErr = \"Error reading wallet database: LoadDestData failed\";\n                return false;\n            }\n        }\n        else if (strType == \"hdseed\")\n        {\n            CHDSeed* newSeed = new CHDSeed();\n            ssValue >> *newSeed;\n            if (!pwallet->activeSeed)\n                pwallet->activeSeed = newSeed;\n            pwallet->mapSeeds[newSeed->getUUID()] = newSeed;\n        }\n        else if (strType == \"primaryseed\")\n        {\n            //Do nothing - aleady handled in first pass through\n        }\n        else if (strType == \"primaryaccount\")\n        {\n            //Do nothing - aleady handled in first pass through\n        }\n        else if (strType == \"acc\")\n        {\n            //Throw old 'accounts' away.\n        }\n        else if (strType == \"accleg\")\n        {\n            std::string strAccountUUID;\n            ssKey >> strAccountUUID;\n            if (pwallet->mapAccounts.count(getUUIDFromString(strAccountUUID)) == 0)\n            {\n                CAccount* newAccount = new CAccount();\n                newAccount->setUUID(strAccountUUID);\n                ssValue >> *newAccount;\n                pwallet->mapAccounts[getUUIDFromString(strAccountUUID)] = newAccount;\n                //If no active account saved (for whatever reason) - make the first one we run into the active one.\n                if (!pwallet->activeAccount)\n                    pwallet->activeAccount = newAccount;\n            }\n        }\n        else if (strType == \"acchd\")\n        {\n            std::string strAccountUUID;\n            ssKey >> strAccountUUID;\n            if (pwallet->mapAccounts.count(getUUIDFromString(strAccountUUID)) == 0)\n            {\n                CAccountHD* newAccount = new CAccountHD();\n                newAccount->setUUID(strAccountUUID);\n                ssValue >> *newAccount;\n                pwallet->mapAccounts[getUUIDFromString(strAccountUUID)] = newAccount;\n                if (!pwallet->activeAccount)\n                    pwallet->activeAccount = newAccount;\n            }\n        }\n        else if (strType == \"acclabel\")\n        {\n            std::string strAccountUUID;\n            std::string strAccountLabel;\n            ssKey >> strAccountUUID;\n            ssValue >> strAccountLabel;\n\n            pwallet->mapAccountLabels[getUUIDFromString(strAccountUUID)] = strAccountLabel;\n        }\n        else if (strType == \"accextlinks\")\n        {\n            std::string strAccountUUID;\n            std::map<std::string, std::string> accountLinks;\n            ssKey >> strAccountUUID;\n            ssValue >> accountLinks;\n            \n            pwallet->mapAccounts[getUUIDFromString(strAccountUUID)]->loadLinks(accountLinks);\n        }\n        else if (strType == \"acc_compound\")\n        {\n            std::string accountUUID;\n            CAmount compoundAmount;\n\n            ssKey >> accountUUID;\n            ssValue >> compoundAmount;\n\n            auto findIter = pwallet->mapAccounts.find(getUUIDFromString(accountUUID));\n            if (findIter != pwallet->mapAccounts.end())\n            {\n                findIter->second->setCompounding(compoundAmount, nullptr);\n            }\n            else\n            {\n                strErr = \"Error reading compound status for account\";\n                return false;\n            }\n        }\n        else if (strType == \"acc_compound_percent\")\n        {\n            std::string accountUUID;\n            int32_t compoundPercent;\n\n            ssKey >> accountUUID;\n            ssValue >> compoundPercent;\n\n            auto findIter = pwallet->mapAccounts.find(getUUIDFromString(accountUUID));\n            if (findIter != pwallet->mapAccounts.end())\n            {\n                findIter->second->setCompoundingPercent(compoundPercent, nullptr);\n            }\n            else\n            {\n                strErr = \"Error reading compound status for account\";\n                return false;\n            }\n        }\n        else if (strType == \"acc_non_compound_wit_earn_script\")\n        {\n            std::string accountUUID;\n            CScript earningsScript;\n\n            ssKey >> accountUUID;\n            ssValue >> *(CScriptBase*)(&earningsScript);\n\n            auto findIter = pwallet->mapAccounts.find(getUUIDFromString(accountUUID));\n            if (findIter != pwallet->mapAccounts.end())\n            {\n                findIter->second->setNonCompoundRewardScript(earningsScript, nullptr);\n            }\n            else\n            {\n                strErr = strprintf(\"Error reading compound script for account [%s]\", accountUUID);\n                return false;\n            }\n        }\n        else if (strType == \"acc_reward_template\")\n        {\n            std::string accountUUID;\n            CWitnessRewardTemplate rewardTemplate;\n\n            ssKey >> accountUUID;\n            ssValue >> rewardTemplate;\n\n            auto findIter = pwallet->mapAccounts.find(getUUIDFromString(accountUUID));\n            if (findIter != pwallet->mapAccounts.end())\n            {\n                findIter->second->setRewardTemplate(rewardTemplate, nullptr);\n            }\n            else\n            {\n                strErr = strprintf(\"Error reading reward template for account [%s]\", accountUUID);\n                return false;\n            }\n        }\n    }\n    catch (...)\n    {\n        return false;\n    }\n    return true;\n}\n\nbool CWalletDB::IsKeyType(const std::string& strType)\n{\n    return (strType== \"key\" || strType == \"wkey\" ||\n            strType == \"mkey\" || strType == \"ckey\");\n}\n\nDBErrors CWalletDB::LoadWallet(CWallet* pwallet, WalletLoadState& nExtraLoadState)\n{\n    CWalletScanState wss;\n    bool fNoncriticalErrors = false;\n    DBErrors result = DB_LOAD_OK;\n\n    std::string primaryAccountString;\n    std::string primarySeedString;\n    try {\n        LOCK(pwallet->cs_wallet);\n        int nMinVersion = 0;\n        if (batch.Read((std::string)\"minversion\", nMinVersion))\n        {\n            if (nMinVersion > CLIENT_VERSION)\n                return DB_TOO_NEW;\n            pwallet->LoadMinVersion(nMinVersion);\n        }\n\n\n        bool isPreHDWallet=false;\n        bool haveAnyAccounts=false;\n        // Accounts first\n        {\n            // Get cursor\n            Dbc* pcursor = batch.GetCursor();\n            if (!pcursor)\n            {\n                LogPrintf(\"Error getting wallet database cursor\\n\");\n                return DB_CORRUPT;\n            }\n            while (true)\n            {\n                // Read next record\n                CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n                CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n                int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);\n                if (ret == DB_NOTFOUND)\n                    break;\n                else if (ret != 0)\n                {\n                    LogPrintf(\"Error reading next record from wallet database\\n\");\n                    return DB_CORRUPT;\n                }\n\n                std::string sKey;\n                ssKey >> sKey;\n                if (sKey == \"accleg\" || sKey == \"acchd\")\n                {\n                    haveAnyAccounts = true;\n                    CDataStream ssKey2(SER_DISK, CLIENT_VERSION);\n                    std::string accountUUID;\n                    ssKey >> accountUUID;\n                    ssKey2 << sKey << accountUUID;\n                    // Try to be tolerant of single corrupt records:\n                    std::string strType, strErr;\n                    if (!ReadKeyValue(pwallet, ssKey2, ssValue, wss, strType, strErr))\n                    {\n                        // losing keys is considered a catastrophic error, anything else\n                        // we assume the user can live with:\n                        if (IsKeyType(strType))\n                            result = DB_CORRUPT;\n                        else\n                        {\n                            // Leave other errors alone, if we try to fix them we might make things worse.\n                            fNoncriticalErrors = true; // ... but do warn the user there is something wrong.\n                            // Rescan if there is a bad transaction record:\n                            if (strType == \"tx\" || strType == \"wtx\")\n                            {\n                                SoftSetBoolArg(\"-rescan\", true);\n                            }\n                        }\n                    }\n                    if (!strErr.empty())\n                        LogPrintf(\"%s\\n\", strErr);\n                }\n                else if (sKey == \"primaryseed\")\n                {\n                    ssValue >> primarySeedString;\n                }\n                else if (sKey == \"primaryaccount\")\n                {\n                    ssValue >> primaryAccountString;\n                }\n                else if (sKey == \"defaultkey\")\n                {\n                    isPreHDWallet = true;\n                }\n            }\n            pcursor->close();\n        }\n\n\n        nExtraLoadState = NEW_WALLET;\n        if (!primaryAccountString.empty())\n        {\n            nExtraLoadState = EXISTING_WALLET;\n            if (pwallet->mapAccounts.count(getUUIDFromString(primaryAccountString)) == 0)\n            {\n                LogPrintf(\"Error - missing primary account for UUID [%s]\\n\", primaryAccountString);\n                fNoncriticalErrors = true;\n            }\n            else\n            {\n                pwallet->activeAccount = pwallet->mapAccounts[getUUIDFromString(primaryAccountString)];\n            }\n        }\n        else if (isPreHDWallet && !haveAnyAccounts)\n        {\n            nExtraLoadState = EXISTING_WALLET_OLDACCOUNTSYSTEM;\n\n            //Upgrade old legacy wallet - set active account - all the old keys will just land up in this.\n            if (pwallet->activeAccount == NULL && pwallet->activeSeed == NULL)\n            {\n                try\n                {\n                    fs::path oldPath = bitdb.strPath;\n                    oldPath = oldPath / pwallet->dbw->GetName();\n                    fs::path backupPath = oldPath;\n                    backupPath.replace_extension(\".old.preHD\");\n                    fs::copy_file(oldPath, backupPath);\n                }\n                catch(...)\n                {\n                    //We don't care enough about this to worry - if it fails we just carry on.\n                }\n\n                pwallet->activeAccount = new CAccount();\n                pwallet->activeAccount->setLabel(\"Legacy\", nullptr);\n                pwallet->mapAccounts[pwallet->activeAccount->getUUID()] = pwallet->activeAccount;\n                pwallet->mapAccountLabels[pwallet->activeAccount->getUUID()] = \"Legacy\";\n            }\n        }\n        else if (haveAnyAccounts)\n        {\n            nExtraLoadState = EXISTING_WALLET;\n        }\n\n        // Get cursor\n        Dbc* pcursor = batch.GetCursor();\n        if (!pcursor)\n        {\n            LogPrintf(\"Error getting wallet database cursor\\n\");\n            return DB_CORRUPT;\n        }\n\n        while (true)\n        {\n            // Read next record\n            CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n            CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n            int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);\n            if (ret == DB_NOTFOUND)\n                break;\n            else if (ret != 0)\n            {\n                LogPrintf(\"Error reading next record from wallet database\\n\");\n                return DB_CORRUPT;\n            }\n\n            // Try to be tolerant of single corrupt records:\n            std::string strType, strErr;\n            if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))\n            {\n                // losing keys is considered a catastrophic error, anything else\n                // we assume the user can live with:\n                if (IsKeyType(strType))\n                    result = DB_CORRUPT;\n                else\n                {\n                    // Leave other errors alone, if we try to fix them we might make things worse.\n                    fNoncriticalErrors = true; // ... but do warn the user there is something wrong.\n                    // Rescan if there is a bad transaction record:\n                    if (strType == \"tx\" || strType == \"wtx\")\n                    {\n                        SoftSetBoolArg(\"-rescan\", true);\n                    }\n                }\n            }\n            if (!strErr.empty())\n                LogPrintf(\"%s\\n\", strErr);\n        }\n        pcursor->close();\n    }\n    catch (const boost::thread_interrupted&) {\n        throw;\n    }\n    catch (...) {\n        result = DB_CORRUPT;\n    }\n    \n    // Batch process code that would otherwise be called for every LoadToWallet call\n    pwallet->HandleTransactionsLoaded();\n\n    for (const auto& labelPair : pwallet->mapAccountLabels)\n        {\n            if (pwallet->mapAccounts.count(labelPair.first) == 0)\n            {\n                //Definitely a non-crticial error, user will just see a very unfriendly account name that they can manually correct.\n                LogPrintf(\"Error - missing account label for account UUID [%s]\\n\", labelPair.first);\n                fNoncriticalErrors = true;\n            }\n            else\n            {\n                pwallet->mapAccounts[labelPair.first]->setLabel(labelPair.second, nullptr);\n            }\n        }\n    if (!primarySeedString.empty())\n    {\n        if (pwallet->mapSeeds.count(getUUIDFromString(primarySeedString)) == 0)\n        {\n            //fixme: (2.1) Treat this more severely?\n            LogPrintf(\"Error - missing primary seed for UUID [%s]\\n\", primarySeedString);\n            fNoncriticalErrors = true;\n        }\n        else\n        {\n            pwallet->activeSeed = pwallet->mapSeeds[getUUIDFromString(primarySeedString)];\n        }\n    }\n\n\n    if (fNoncriticalErrors && result == DB_LOAD_OK)\n        result = DB_NONCRITICAL_ERROR;\n\n    // Any wallet corruption at all: skip any rewriting or\n    // upgrading, we don't want to make it worse.\n    if (result != DB_LOAD_OK)\n        return result;\n\n    LogPrintf(\"nFileVersion = %d\\n\", wss.nFileVersion);\n\n    LogPrintf(\"Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\\n\",\n           wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);\n\n    // nTimeFirstKey is only reliable if all keys have metadata\n    if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)\n        pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'\n\n    for(uint256 hash : wss.vWalletUpgrade)\n        WriteTx(pwallet->mapWallet[hash]);\n\n    // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:\n    if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))\n        return DB_NEED_REWRITE;\n\n    if (wss.nFileVersion < CLIENT_VERSION) // Update\n        WriteVersion(CLIENT_VERSION);\n\n    if (wss.fAnyUnordered)\n        result = pwallet->ReorderTransactions();\n\n    pwallet->laccentries.clear();\n    ListAccountCreditDebit(\"*\", pwallet->laccentries);\n    for(CAccountingEntry& entry : pwallet->laccentries) {\n        pwallet->wtxOrdered.insert(std::pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));\n    }\n\n    return result;\n}\n\nDBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)\n{\n    bool fNoncriticalErrors = false;\n    DBErrors result = DB_LOAD_OK;\n\n    try {\n        int nMinVersion = 0;\n        if (batch.Read((std::string)\"minversion\", nMinVersion))\n        {\n            if (nMinVersion > CLIENT_VERSION)\n                return DB_TOO_NEW;\n        }\n\n        // Get cursor\n        Dbc* pcursor = batch.GetCursor();\n        if (!pcursor)\n        {\n            LogPrintf(\"Error getting wallet database cursor\\n\");\n            return DB_CORRUPT;\n        }\n\n        while (true)\n        {\n            // Read next record\n            CDataStream ssKey(SER_DISK, CLIENT_VERSION);\n            CDataStream ssValue(SER_DISK, CLIENT_VERSION);\n            int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);\n            if (ret == DB_NOTFOUND)\n                break;\n            else if (ret != 0)\n            {\n                LogPrintf(\"Error reading next record from wallet database\\n\");\n                return DB_CORRUPT;\n            }\n\n            std::string strType;\n            ssKey >> strType;\n            if (strType == \"tx\" || strType == \"wtx\")\n            {\n                // Work around for a mistake in initial unity (for mobile) rollout\n                // Where format changed in a way that wasn't fully 'backwards' compatible with future desktop upgrades.\n                // For desktop we introduce 'wtx' to do the upgrade 'right', but on mobile 'tx' is already also upgraded so we need to treat it as such (only on mobile)\n                // wtx is treated the same on both and should be preffered in future - we should phase out and remove 'tx' in future.\n                //fixme: (FUTURE) - Remove 'tx' completely once wallets are upgraded; may have to write some code to forcefully upgrade all 'tx' to 'wtx'\n                #ifndef PLATFORM_MOBILE\n                    // Force old serialization version\n                    if (strType == \"tx\")\n                    {\n                        ssValue.SetVersion(2010000);\n                    }\n                #endif\n            \n                uint256 hash;\n                ssKey >> hash;\n\n                CWalletTx wtx;\n                ssValue >> wtx;\n\n                vTxHash.push_back(hash);\n                vWtx.push_back(wtx);\n            }\n        }\n        pcursor->close();\n    }\n    catch (const boost::thread_interrupted&)\n    {\n        throw;\n    }\n    catch (...)\n    {\n        result = DB_CORRUPT;\n    }\n\n    if (fNoncriticalErrors && result == DB_LOAD_OK)\n    {\n        result = DB_NONCRITICAL_ERROR;\n    }\n\n    return result;\n}\n\nDBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)\n{\n    // build list of wallet TXs and hashes\n    std::vector<uint256> vTxHash;\n    std::vector<CWalletTx> vWtx;\n    DBErrors err = FindWalletTx(vTxHash, vWtx);\n    if (err != DB_LOAD_OK) {\n        return err;\n    }\n\n    std::sort(vTxHash.begin(), vTxHash.end());\n    std::sort(vTxHashIn.begin(), vTxHashIn.end());\n\n    // erase each matching wallet TX\n    bool delerror = false;\n    std::vector<uint256>::iterator it = vTxHashIn.begin();\n    for (uint256 hash : vTxHash) {\n        while (it < vTxHashIn.end() && (*it) < hash) {\n            it++;\n        }\n        if (it == vTxHashIn.end()) {\n            break;\n        }\n        else if ((*it) == hash) {\n            if(!EraseTx(hash)) {\n                LogPrint(BCLog::DB, \"Transaction was found for deletion but returned database error: %s\\n\", hash.GetHex());\n                delerror = true;\n            }\n            vTxHashOut.push_back(hash);\n        }\n    }\n\n    if (delerror) {\n        return DB_CORRUPT;\n    }\n    return DB_LOAD_OK;\n}\n\nDBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)\n{\n    // build list of wallet TXs\n    std::vector<uint256> vTxHash;\n    DBErrors err = FindWalletTx(vTxHash, vWtx);\n    if (err != DB_LOAD_OK)\n        return err;\n\n    // erase each wallet TX\n    for (uint256& hash : vTxHash) {\n        if (!EraseTx(hash))\n            return DB_CORRUPT;\n    }\n\n    return DB_LOAD_OK;\n}\n\nvoid MaybeCompactWalletDB()\n{\n    static std::atomic<bool> fOneThread;\n    if (fOneThread.exchange(true)) {\n        return;\n    }\n    if (!GetBoolArg(\"-flushwallet\", DEFAULT_FLUSHWALLET)) {\n        return;\n    }\n\n    for (CWalletRef pwallet : vpwallets) {\n        CWalletDBWrapper& dbh = pwallet->GetDBHandle();\n\n        unsigned int nUpdateCounter = dbh.nUpdateCounter;\n\n        if (dbh.nLastSeen != nUpdateCounter) {\n            dbh.nLastSeen = nUpdateCounter;\n            dbh.nLastWalletUpdate = GetTime();\n        }\n\n        if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {\n            if (CDB::PeriodicFlush(dbh)) {\n                dbh.nLastFlushed = nUpdateCounter;\n            }\n        }\n    }\n\n    fOneThread = false;\n}\n\n//\n// Try to (very carefully!) recover wallet file if there is a problem.\n//\nbool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)\n{\n    return CDB::Recover(filename, callbackDataIn, recoverKVcallback, out_backup_filename);\n}\n\nbool CWalletDB::Recover(const std::string& filename, std::string& out_backup_filename)\n{\n    // recover without a key filter callback\n    // results in recovering all record types\n    return CWalletDB::Recover(filename, NULL, NULL, out_backup_filename);\n}\n\nbool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)\n{\n    CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);\n    CWalletScanState dummyWss;\n    std::string strType, strErr;\n    bool fReadOK;\n    {\n        // Required in LoadKeyMetadata():\n        LOCK(dummyWallet->cs_wallet);\n        fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,\n                               dummyWss, strType, strErr);\n    }\n    if (!IsKeyType(strType) && strType != \"hdchain\")\n        return false;\n    if (!fReadOK)\n    {\n        LogPrintf(\"WARNING: CWalletDB::Recover skipping %s: %s\\n\", strType, strErr);\n        return false;\n    }\n\n    return true;\n}\n\nbool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)\n{\n    return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);\n}\n\nbool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)\n{\n    return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);\n}\n\nbool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)\n{\n    return WriteIC(std::pair(std::string(\"destdata\"), std::pair(address, key)), value);\n}\n\nbool CWalletDB::EraseDestData(const std::string &address, const std::string &key)\n{\n    return EraseIC(std::pair(std::string(\"destdata\"), std::pair(address, key)));\n}\n\n/*\nbool CWalletDB::WriteHDChain(const CHDChain& chain)\n{\n    return WriteIC(std::string(\"hdchain\"), chain);\n}\n*/\n\nbool CWalletDB::TxnBegin()\n{\n    return batch.TxnBegin();\n}\n\nbool CWalletDB::TxnCommit()\n{\n    return batch.TxnCommit();\n}\n\nbool CWalletDB::TxnAbort()\n{\n    return batch.TxnAbort();\n}\n\nbool CWalletDB::ReadVersion(int& nVersion)\n{\n    return batch.ReadVersion(nVersion);\n}\n\nbool CWalletDB::WriteVersion(int nVersion)\n{\n    return batch.WriteVersion(nVersion);\n}\n\nbool CWalletDB::WriteHDSeed(const CHDSeed& seed)\n{\n    return WriteIC(std::pair(std::string(\"hdseed\"), getUUIDAsString(seed.getUUID())), seed);\n}\n\nbool CWalletDB::DeleteHDSeed(const CHDSeed& seed)\n{\n    return EraseIC(std::pair(std::string(\"hdseed\"), getUUIDAsString(seed.getUUID())));\n}\n\nbool CWalletDB::WritePrimarySeed(const CHDSeed& seed)\n{\n    return WriteIC(std::string(\"primaryseed\"), getUUIDAsString(seed.getUUID()));\n}\n\nbool CWalletDB::ErasePrimarySeed()\n{\n    return EraseIC(std::string(\"primaryseed\"));\n}\n\nbool CWalletDB::WritePrimaryAccount(const CAccount* account)\n{\n    return WriteIC(std::string(\"primaryaccount\"), getUUIDAsString(account->getUUID()));\n}\n\nbool CWalletDB::ErasePrimaryAccount()\n{\n    return EraseIC(std::string(\"primaryaccount\"));\n}\n"
  },
  {
    "path": "src/wallet/walletdb.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_WALLETDB_H\n#define WALLET_WALLETDB_H\n\n#include \"amount.h\"\n#include \"primitives/transaction.h\"\n#include \"wallet/db.h\"\n#include \"wallet/walletdberrors.h\"\n#include \"key.h\"\n\n#include <list>\n#include <stdint.h>\n#include <string>\n#include <utility>\n#include <vector>\n\n/**\n * Overview of wallet database classes:\n *\n * - CDBEnv is an environment in which the database exists (has no analog in dbwrapper.h)\n * - CWalletDBWrapper represents a wallet database (similar to CDBWrapper in dbwrapper.h)\n * - CDB is a low-level database transaction (similar to CDBBatch in dbwrapper.h)\n * - CWalletDB is a modifier object for the wallet, and encapsulates a database\n *   transaction as well as methods to act on the database (no analog in\n *   dbwrapper.h)\n *\n * The latter two are named confusingly, in contrast to what the names CDB\n * and CWalletDB suggest they are transient transaction objects and don't\n * represent the database itself.\n */\n\nstatic const bool DEFAULT_FLUSHWALLET = true;\n\nclass CHDSeed;\nclass CAccount;\nclass CAccountHD;\nclass CAccountingEntry;\nstruct CBlockLocator;\nclass CKeyPool;\nclass CMasterKey;\nclass CScript;\nclass CWallet;\nclass CWalletTx;\nclass uint160;\nclass uint256;\nclass CWitnessRewardTemplate;\n\nenum WalletLoadState\n{\n    NEW_WALLET,\n    EXISTING_WALLET_OLDACCOUNTSYSTEM,\n    EXISTING_WALLET\n};\n\nclass CKeyMetadata\n{\npublic:\n    static const int VERSION_BASIC=1;\n    static const int VERSION_WITH_HDDATA=10;\n    static const int CURRENT_VERSION=VERSION_WITH_HDDATA;\n    int nVersion;\n    int64_t nCreateTime; // 0 means unknown\n    std::string hdKeypath; //optional HD/bip32 keypath\n    std::string hdAccountUUID; //uuid of the account used to derive this key\n\n    CKeyMetadata()\n    {\n        SetNull();\n    }\n    CKeyMetadata(int64_t nCreateTime_)\n    {\n        SetNull();\n        nCreateTime = nCreateTime_;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        READWRITE(this->nVersion);\n        nVersion = this->nVersion;\n        READWRITE(nCreateTime);\n        if (this->nVersion >= VERSION_WITH_HDDATA)\n        {\n            READWRITE(hdKeypath);\n            READWRITE(hdAccountUUID);\n        }\n\n    }\n\n    void SetNull()\n    {\n        nVersion = CKeyMetadata::CURRENT_VERSION;\n        nCreateTime = 0;\n        hdKeypath.clear();\n        hdAccountUUID = \"\";\n    }\n};\n\n/** Access to the wallet database.\n * This should really be named CWalletDBBatch, as it represents a single transaction at the\n * database. It will be committed when the object goes out of scope.\n * Optionally (on by default) it will flush to disk as well.\n */\nclass CWalletDB\n{\nprivate:\n    template <typename K, typename T>\n    bool WriteIC(const K& key, const T& value, bool fOverwrite = true)\n    {\n        if (!batch.Write(key, value, fOverwrite)) {\n            return false;\n        }\n        m_dbw.IncrementUpdateCounter();\n        return true;\n    }\n\n    template <typename K>\n    bool EraseIC(const K& key)\n    {\n        if (!batch.Erase(key)) {\n            return false;\n        }\n        m_dbw.IncrementUpdateCounter();\n        return true;\n    }\n\npublic:\n    CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = \"r+\", bool _fFlushOnClose = true) :\n        batch(dbw, pszMode, _fFlushOnClose),\n        m_dbw(dbw)\n    {\n    }\n\n    bool WriteRecipientName(const std::string& strAddress, const std::string& strName);\n    bool EraseRecipientName(const std::string& strAddress);\n\n    bool WriteRecipientDescription(const std::string& strAddress, const std::string& description);\n    bool EraseRecipientDescription(const std::string& strAddress);\n    \n    bool WriteRecipientPurpose(const std::string& strAddress, const std::string& purpose);\n    bool EraseRecipientPurpose(const std::string& strAddress);\n\n    bool WriteTx(const CWalletTx& wtx);\n    bool EraseTx(uint256 hash);\n\n    //! Write key and metadata to walletdb (unencrypted)\n    bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta, const std::string forAccount, int64_t nKeyChain);\n    //! Write key and metadata to walletdb (encrypted)\n    bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta, const std::string forAccount, int64_t nKeyChain);\n    //! Special writer only for witness accounts (where we store the witness key in both HD and non-HD mode)\n    bool WriteKeyOverride(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const std::string forAccount, int64_t nKeyChain);\n    bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey);\n    bool EraseMasterKey(unsigned int nID);\n\n    bool EraseKey(const CPubKey& vchPubKey);\n    bool EraseEncryptedKey(const CPubKey& vchPubKey);\n    bool WriteKeyHD(const CPubKey& vchPubKey, const int64_t HDKeyIndex, const int64_t keyChain, const CKeyMetadata &keyMeta, const std::string forAccount);\n\n    bool WriteCScript(const uint160& hash, const CScript& redeemScript);\n\n    bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);\n    bool EraseWatchOnly(const CScript &script);\n\n    bool WriteBestBlock(const CBlockLocator& locator);\n    bool ReadBestBlock(CBlockLocator& locator);\n    \n    bool WriteMiningAddressString(const std::string& miningAddress);\n    bool ReadMiningAddressString(std::string& miningAddress);\n\n    bool EraseLastSPVBlockProcessed();\n    bool WriteLastSPVBlockProcessed(const CBlockLocator& locator, const int64_t time);\n    bool ReadLastSPVBlockProcessed(CBlockLocator& locator, int64_t& time);\n\n    bool WriteOrderPosNext(int64_t nOrderPosNext);\n    bool ReadPool(int64_t nPool, CKeyPool& keypool);\n    bool WritePool(int64_t nPool, const CKeyPool& keypool);\n\n    //! Erase a keypool AddAccountingEntry\n    //! Pass forceErase=true to bypass keypool \"protection\" that is applied for IsFixedKeyPool() and IsMinimalKeyPool() accounts\n    bool ErasePool(CWallet* pwallet, int64_t nPool, bool forceErase=false);\n    bool ErasePool(CWallet* pwallet, const CKeyID& id, bool forceErase=false);\n    bool HasPool(CWallet* pwallet, const CKeyID& id);\n\n    bool WriteMinVersion(int nVersion);\n\n    /// This writes directly to the database, and will not update the CWallet's cached accounting entries!\n    /// Use wallet.AddAccountingEntry instead, to write *and* update its caches.\n    bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);\n\n    //! write the account to the database, this excludes information like the label and compounding status which are written seperately to allow them to be changeable without rewriting the entire account.\n    bool WriteAccount(const std::string& strAccount, const CAccount* account);\n    //! Wipe the acount from the database, note it's necessary to also erase the label and other info manually.\n    bool EraseAccount(const std::string& strAccount, const CAccount* account);\n\n    //! write the account label\n    bool WriteAccountLabel(const std::string& strUUID, const std::string& strLabel);\n    bool EraseAccountLabel(const std::string& strUUID);\n    \n    //! write the account links\n    bool WriteAccountLinks(const std::string& strUUID, const std::map<std::string, std::string>& accountLinks);\n    bool EraseAccountLinks(const std::string& strUUID);\n\n    //! Write the account compounding amount settings; used only by witness accounts, controls whether the account should compound earnings or pay them to an external address.\n    bool WriteAccountCompoundingSettings(const std::string& strUUID, const CAmount compoundAmount);\n    bool EraseAccountCompoundingSettings(const std::string& strUUID);\n    bool WriteAccountCompoundingPercentSettings(const std::string& strUUID, const int32_t compoundPercent);\n    bool EraseAccountCompoundingPercentSettings(const std::string& strUUID);\n\n    //! Write the account compounding script settings; used only by witness accounts, controls where the account should pay any non-compounding earnings it has to pay out.\n    bool WriteAccountNonCompoundWitnessEarningsScript(const std::string& strUUID, const CScript& earningsScript);\n    bool EraseAccountNonCompoundWitnessEarningsScript(const std::string& strUUID);\n\n    //! Write the account witness reward template; used only by witness accounts when witnessing, controls where witness earnings go to.\n    bool WriteAccountRewardTemplate(const std::string& strUUID, const CWitnessRewardTemplate& rewardTemplate);\n    bool EraseAccountRewardTemplate(const std::string& strUUID);\n\n    //! write the seed (mnemonic / account index counter)\n    bool WriteHDSeed(const CHDSeed& seed);\n    bool DeleteHDSeed(const CHDSeed& seed);\n    bool WritePrimarySeed(const CHDSeed& seed);\n    bool ErasePrimarySeed();\n    bool WritePrimaryAccount(const CAccount* account);\n    bool ErasePrimaryAccount();\n\n    /// Write destination data key,value tuple to database\n    bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);\n    /// Erase destination data tuple from wallet database\n    bool EraseDestData(const std::string &address, const std::string &key);\n\n    CAmount GetAccountCreditDebit(const std::string& strAccount);\n    void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);\n\n    DBErrors LoadWallet(CWallet* pwallet, WalletLoadState& nExtraLoadState);\n    DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);\n    DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);\n    DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);\n    /* Try to (very carefully!) recover wallet database (with a possible key type filter) */\n    static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);\n    /* Recover convenience-function to bypass the key filter callback, called when verify fails, recovers everything */\n    static bool Recover(const std::string& filename, std::string& out_backup_filename);\n    /* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */\n    static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);\n    /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */\n    static bool IsKeyType(const std::string& strType);\n    /* verifies the database environment */\n    static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);\n    /* verifies the database file */\n    static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr);\n\n    //! write the hdchain model (external chain child index counter)\n    /* MUNT - We don't use HD chain.\n    bool WriteHDChain(const CHDChain& chain);\n    */\n\n    //! Begin a new transaction\n    bool TxnBegin();\n    //! Commit current transaction\n    bool TxnCommit();\n    //! Abort current transaction\n    bool TxnAbort();\n    //! Read wallet version\n    bool ReadVersion(int& nVersion);\n    //! Write wallet version\n    bool WriteVersion(int nVersion);\nprivate:\n    CDB batch;\n    CWalletDBWrapper& m_dbw;\n\n    CWalletDB(const CWalletDB&);\n    void operator=(const CWalletDB&);\n};\n\n//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)\nvoid MaybeCompactWalletDB();\n\n#endif\n"
  },
  {
    "path": "src/wallet/walletdberrors.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_WALLETDBERRORS_H\n#define WALLET_WALLETDBERRORS_H\n\n/** Error statuses for the wallet database */\nenum DBErrors\n{\n    DB_LOAD_OK,\n    DB_CORRUPT,\n    DB_NONCRITICAL_ERROR,\n    DB_TOO_NEW,\n    DB_LOAD_FAIL,\n    DB_NEED_REWRITE\n};\n\n\n#endif\n"
  },
  {
    "path": "src/wallet/wallettx.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet.h\"\n#include \"wallettx.h\"\n\nint64_t CWalletTx::GetTxTime() const\n{\n    int64_t n = nTimeSmart;\n    return n ? n : nTimeReceived;\n}\n\nvoid CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,\n                           std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter, CKeyStore* from, bool includeChildren) const\n{\n    if (!from)\n        from = pwallet->activeAccount;\n\n    nFee = 0;\n    listReceived.clear();\n    listSent.clear();\n\n    // Compute fee:\n    CAmount nDebit = GetDebit(filter);\n    if (nDebit > 0) // debit>0 means we signed/sent this transaction\n    {\n        CAmount nValueOut = tx->GetValueOut();\n        nFee = nDebit - nValueOut;\n    }\n\n    // Sent.\n    for (unsigned int i = 0; i < tx->vin.size(); ++i)\n    {\n        const CTxIn& txin = tx->vin[i];\n\n        const CWalletTx* prev = pwallet->GetWalletTx(txin.GetPrevOut());\n        if (prev)\n        {\n            if (txin.GetPrevOut().n < prev->tx->vout.size())\n            {\n                const auto& prevOut =  prev->tx->vout[txin.GetPrevOut().n];\n\n                isminetype fIsMine = IsMine(*from, prevOut);\n                if (includeChildren && !(fIsMine & filter))\n                {\n                    for (const auto& accountItem : pwallet->mapAccounts)\n                    {\n                        const auto& childAccount = accountItem.second;\n                        if (childAccount->getParentUUID() == dynamic_cast<CAccount*>(from)->getUUID())\n                        {\n                            fIsMine = IsMine(*childAccount, prevOut);\n                            if (fIsMine & filter)\n                                break;\n                        }\n                    }\n                }\n\n                if (fIsMine & filter)\n                {\n                    CTxDestination address;\n                    if (!ExtractDestination(prevOut, address) && !prevOut.IsUnspendable())\n                    {\n                        LogPrintf(\"CWalletTx::GetAmounts: Unknown transaction type found, txid %s\\n\",\n                                this->GetHash().ToString());\n                        address = CNoDestination();\n                    }\n\n                    //fixme: (FUT) (ACCOUNTS) - There should be a seperate CInputEntry class/array here or something.\n                    COutputEntry output = {address, prevOut.nValue, (int)i};\n\n                    // We are debited by the transaction, add the output as a \"sent\" entry\n                    listSent.push_back(output);\n                }\n            }\n        }\n    }\n\n    // received.\n    for (unsigned int i = 0; i < tx->vout.size(); ++i)\n    {\n        const CTxOut& txout = tx->vout[i];\n        isminetype fIsMine = IsMine(*from, txout);\n        if (includeChildren && !(fIsMine & filter))\n        {\n            for (const auto& accountItem : pwallet->mapAccounts)\n            {\n                const auto& childAccount = accountItem.second;\n                if (childAccount->getParentUUID() == dynamic_cast<CAccount*>(from)->getUUID())\n                {\n                    fIsMine = IsMine(*childAccount, txout);\n                    if (fIsMine & filter)\n                        break;\n                }\n            }\n        }\n\n        if (fIsMine & filter)\n        {\n            // Get the destination address\n            CTxDestination address;\n            if (!ExtractDestination(txout, address) && !txout.IsUnspendable())\n            {\n                LogPrintf(\"CWalletTx::GetAmounts: Unknown transaction type found, txid %s\\n\",\n                        this->GetHash().ToString());\n                address = CNoDestination();\n            }\n\n            COutputEntry output = {address, txout.nValue, (int)i};\n\n            // We are receiving the output, add it as a \"received\" entry\n            listReceived.push_back(output);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/wallet/wallettx.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WALLET_WALLETTX_H\n#define WALLET_WALLETTX_H\n\n#include \"merkletx.h\"\n#include <uint256.h>\n#include \"amount.h\"\n#include <script/standard.h>\n#include <script/ismine.h>\n\nclass CAccount;\nclass CWallet;\nclass CKeyStore;\nclass CConnman;\n\n\n\ntypedef std::map<std::string, std::string> mapValue_t;\n\n\nstatic inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)\n{\n    if (!mapValue.count(\"n\"))\n    {\n        nOrderPos = -1; // TODO: calculate elsewhere\n        return;\n    }\n    nOrderPos = atoi64(mapValue[\"n\"].c_str());\n}\n\n\nstatic inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)\n{\n    if (nOrderPos == -1)\n        return;\n    mapValue[\"n\"] = i64tostr(nOrderPos);\n}\n\nstruct COutputEntry\n{\n    CTxDestination destination;\n    CAmount amount;\n    int vout;\n};\n\n/** \n * A transaction with a bunch of additional info that only the owner cares about.\n * It includes any unrecorded transactions needed to link it back to the block chain.\n */\nclass CWalletTx : public CMerkleTx\n{\nprivate:\n    const CWallet* pwallet;\n\npublic:\n    /**\n     * Key/value map with information about the transaction.\n     *\n     * The following keys can be read and written through the map and are\n     * serialized in the wallet database:\n     *\n     *     \"comment\", \"to\"   - comment strings provided to sendtoaddress,\n     *                         sendfrom, sendmany wallet RPCs\n     *     \"replaces_txid\"   - txid (as HexStr) of transaction replaced by\n     *                         bumpfee on transaction created by bumpfee\n     *     \"replaced_by_txid\" - txid (as HexStr) of transaction created by\n     *                         bumpfee on transaction replaced by bumpfee\n     *     \"from\", \"message\" - obsolete fields that could be set in UI prior to\n     *                         2011 (removed in commit 4d9b223)\n     *\n     * The following keys are serialized in the wallet database, but shouldn't\n     * be read or written through the map (they will be temporarily added and\n     * removed from the map during serialization):\n     *\n     *     \"fromaccount\"     - serialized strFromAccount value\n     *     \"n\"               - serialized nOrderPos value\n     *     \"timesmart\"       - serialized nTimeSmart value\n     *     \"spent\"           - serialized vfSpent value that existed prior to\n     *                         2014 (removed in commit 93a18a3)\n     */\n    mapValue_t mapValue;\n    std::vector<std::pair<std::string, std::string> > vOrderForm;\n    unsigned int fTimeReceivedIsTxTime;\n    unsigned int nTimeReceived; //!< time received by this node\n    /**\n     * Stable timestamp that never changes, and reflects the order a transaction\n     * was added to the wallet. Timestamp is based on the block time for a\n     * transaction added as part of a block, or else the time when the\n     * transaction was received if it wasn't part of a block, with the timestamp\n     * adjusted in both cases so timestamp order matches the order transactions\n     * were added to the wallet. More details can be found in\n     * CWallet::ComputeTimeSmart().\n     */\n    unsigned int nTimeSmart;\n    /**\n     * From me flag is set to 1 for transactions that were created by the wallet\n     * on this Munt node, and set to 0 for transactions that were created\n     * externally and came in through the network or sendrawtransaction RPC.\n     */\n    char fFromMe;\n    std::string strFromAccount;\n    int64_t nOrderPos; //!< position in ordered transaction list\n\n    // memory only\n    mutable bool fChangeCached;\n    mutable CAmount nChangeCached;\n    mutable std::map<const CAccount*, CAmount> debitCached;\n    mutable std::map<const CAccount*, CAmount> creditCached;\n    mutable std::map<const CAccount*, CAmount> immatureCreditCached;\n    mutable std::map<const CAccount*, CAmount> immatureCreditCachedIncludingLockedWitnesses;\n    mutable std::map<const CAccount*, CAmount> availableCreditCached;\n    mutable std::map<const CAccount*, CAmount> availableCreditCachedIncludingLockedWitnesses;\n    mutable std::map<const CAccount*, CAmount> watchDebitCached;\n    mutable std::map<const CAccount*, CAmount> watchCreditCached;\n    mutable std::map<const CAccount*, CAmount> immatureWatchCreditCached;\n    mutable std::map<const CAccount*, CAmount> availableWatchCreditCached;\n\n    /**\n     * Witness bundles (optional). These can be efficiently computed during sync/validation, optionally cached here to avoid re-doing this\n     * later. This can be either expensive because of required disk access, or even impossible because the required data\n     * is not available anymore.\n     */\n    CWitnessBundlesRef witnessBundles;\n\n    CWalletTx()\n    {\n        Init(NULL);\n    }\n\n    CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))\n    {\n        Init(pwalletIn);\n    }\n\n    void Init(const CWallet* pwalletIn)\n    {\n        pwallet = pwalletIn;\n        mapValue.clear();\n        vOrderForm.clear();\n        fTimeReceivedIsTxTime = false;\n        nTimeReceived = 0;\n        nTimeSmart = 0;\n        fFromMe = false;\n        strFromAccount.clear();\n        fChangeCached = false;\n        debitCached.clear();\n        creditCached.clear();\n        immatureCreditCached.clear();\n        immatureCreditCachedIncludingLockedWitnesses.clear();\n        availableCreditCached.clear();\n        availableCreditCachedIncludingLockedWitnesses.clear();\n        watchDebitCached.clear();\n        watchCreditCached.clear();\n        immatureWatchCreditCached.clear();\n        availableWatchCreditCached.clear();\n        nChangeCached = 0;\n        nOrderPos = -1;\n    }\n\n    ADD_SERIALIZE_METHODS;\n\n    template <typename Stream, typename Operation>\n    inline void SerializationOp(Stream& s, Operation ser_action) {\n        if (ser_action.ForRead())\n            Init(NULL);\n        char fSpent = false;\n\n        if (!ser_action.ForRead())\n        {\n            mapValue[\"fromaccount\"] = strFromAccount;\n\n            WriteOrderPos(nOrderPos, mapValue);\n\n            if (nTimeSmart)\n                mapValue[\"timesmart\"] = strprintf(\"%u\", nTimeSmart);\n        }\n\n        READWRITE(*(CMerkleTx*)this);\n        std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev\n        READWRITECOMPACTSIZEVECTOR(vUnused);\n        READWRITE(mapValue);\n        READWRITECOMPACTSIZEVECTOR(vOrderForm);\n        READWRITE(fTimeReceivedIsTxTime);\n        READWRITE(nTimeReceived);\n        READWRITE(fFromMe);\n        READWRITE(fSpent);\n\n        // Optional extras.\n        unsigned char fEXTRA_WITNESS_BUNDLE = 1 << 0;\n        if (ser_action.ForRead() && s.size() > 0)\n        {\n            unsigned char fExtras;\n            READWRITE(fExtras);\n            if (fExtras & fEXTRA_WITNESS_BUNDLE) {\n                READWRITE(witnessBundles);\n            }\n        }\n        if (!ser_action.ForRead() && witnessBundles)\n        {\n            READWRITE(fEXTRA_WITNESS_BUNDLE);\n            READWRITE(witnessBundles);\n        }\n\n        if (ser_action.ForRead())\n        {\n            strFromAccount = mapValue[\"fromaccount\"];\n\n            ReadOrderPos(nOrderPos, mapValue);\n\n            nTimeSmart = mapValue.count(\"timesmart\") ? (unsigned int)atoi64(mapValue[\"timesmart\"]) : 0;\n        }\n\n        mapValue.erase(\"fromaccount\");\n        mapValue.erase(\"spent\");\n        mapValue.erase(\"n\");\n        mapValue.erase(\"timesmart\");\n    }\n\n    //! make sure balances are recalculated\n    void MarkDirty()\n    {\n        fChangeCached = false;\n        nChangeCached = 0;\n        debitCached.clear();\n        creditCached.clear();\n        immatureCreditCached.clear();\n        availableCreditCached.clear();\n        availableCreditCachedIncludingLockedWitnesses.clear();\n        watchDebitCached.clear();\n        watchCreditCached.clear();\n        immatureWatchCreditCached.clear();\n        availableWatchCreditCached.clear();\n    }\n\n    void BindWallet(CWallet *pwalletIn)\n    {\n        pwallet = pwalletIn;\n        MarkDirty();\n    }\n\n    //! filter decides which addresses will count towards the debit\n    CAmount GetDebit(const isminefilter& filter, CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetCredit(const isminefilter& filter, CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetImmatureCredit(bool fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetImmatureCreditIncludingLockedWitnesses(bool fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetAvailableCredit(bool fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetAvailableCreditIncludingLockedWitnesses(bool fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true, const CAccount* forAccount=NULL, bool includeChildren=false) const;\n    CAmount GetChange() const;\n\n    void GetAmounts(std::list<COutputEntry>& listReceived,\n                    std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter, CKeyStore* from=NULL, bool includeChildren=false) const;\n\n    bool IsFromMe(const isminefilter& filter) const\n    {\n        return (GetDebit(filter) > 0);\n    }\n\n    // True if only scriptSigs are different\n    bool IsEquivalentTo(const CWalletTx& tx) const;\n\n    bool InMempool() const;\n    bool IsTrusted() const;\n\n    int64_t GetTxTime() const;\n\n    bool RelayWalletTransaction(CConnman* connman);\n\n    std::set<uint256> GetConflicts() const;\n};\n\n#endif\n"
  },
  {
    "path": "src/wallet/witness_operations.cpp",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Modifications by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"witness_operations.h\"\n\n#include <stdexcept>\n#include <numeric>\n#include <algorithm>\n#include <boost/uuid/uuid_io.hpp>\n#include <cmath>\n#include <inttypes.h>\n#include \"wallet.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"consensus/consensus.h\"\n#include \"consensus/validation.h\"\n#include \"witnessutil.h\"\n#include \"coincontrol.h\"\n#include \"net.h\"\n#include \"alert.h\"\n#include \"appname.h\"\n#include \"util/moneystr.h\"\n\nwitnessOutputsInfoVector getCurrentOutputsForWitnessAccount(CAccount* forAccount)\n{\n    std::map<COutPoint, Coin> allWitnessCoins;\n    if (!getAllUnspentWitnessCoins(chainActive, Params(), chainActive.Tip(), allWitnessCoins))\n        throw std::runtime_error(\"Failed to enumerate all witness coins.\");\n\n    witnessOutputsInfoVector matchedOutputs;\n    for (const auto& [outpoint, coin] : allWitnessCoins)\n    {\n        if (IsMine(*forAccount, coin.out))\n        {\n            matchedOutputs.push_back(std::tuple(coin.out, coin.nHeight, coin.nTxIndex, outpoint));\n        }\n    }\n    return matchedOutputs;\n}\n\nvoid extendwitnessaddresshelper(CAccount* fundingAccount, witnessOutputsInfoVector unspentWitnessOutputs, CWallet* pwallet, CAmount requestedAmount, uint64_t requestedLockPeriodInBlocks, std::string* pTxid, CAmount* pFee)\n{\n    AssertLockHeld(cs_main);\n    AssertLockHeld(pwallet->cs_wallet);\n\n    if (unspentWitnessOutputs.size() > 1)\n        throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Address has too many witness outputs cannot extend \"));\n\n    if (requestedAmount < (gMinimumWitnessAmount*COIN))\n        throw witness_error(witness::RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n\n    if (requestedLockPeriodInBlocks > MaximumWitnessLockLength())\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Maximum lock period of 3 years exceeded.\");\n\n    if (requestedLockPeriodInBlocks < MinimumWitnessLockLength())\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Minimum lock period of 1 month exceeded.\");\n\n    // Add a small buffer to give us time to enter the blockchain\n    if (requestedLockPeriodInBlocks == MinimumWitnessLockLength())\n        requestedLockPeriodInBlocks += 50;\n\n    // Check for immaturity\n    const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] = unspentWitnessOutputs[0];\n    //fixme: (PHASE5) - Minor code cleanup.\n    //This check should go through the actual chain maturity stuff (via wtx) and not calculate maturity directly.\n    if (chainActive.Tip()->nHeight - currentWitnessHeight < (uint64_t)(COINBASE_MATURITY))\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot perform operation on immature transaction, please wait for transaction to mature and try again\");\n\n    // Check type (can't extend script type, must witness once or renew after phase 4 activated)\n    if (currentWitnessTxOut.GetType() != CTxOutType::PoW2WitnessOutput)\n        throw witness_error(witness::RPC_TYPE_ERROR, \"Witness has to be type POW2WITNESS\");\n\n    // Calculate existing lock period\n    CTxOutPoW2Witness currentWitnessDetails;\n    GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails);\n    uint64_t remainingLockDurationInBlocks = GetPoW2RemainingLockLengthInBlocks(currentWitnessDetails.lockUntilBlock, chainActive.Tip()->nHeight);\n    if (remainingLockDurationInBlocks == 0)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"PoW² witness has already unlocked so cannot be extended.\");\n    }\n\n    if (requestedLockPeriodInBlocks < remainingLockDurationInBlocks)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, strprintf(\"New lock period [%d] does not exceed remaining lock period [%d]\", requestedLockPeriodInBlocks, remainingLockDurationInBlocks));\n    }\n\n    if (requestedAmount < currentWitnessTxOut.nValue)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, strprintf(\"New amount [%d] is smaller than current amount [%d]\", requestedAmount, currentWitnessTxOut.nValue));\n    }\n\n    // Enforce minimum weight\n    int64_t newWeight = GetPoW2RawWeightForAmount(requestedAmount, chainActive.Height(), requestedLockPeriodInBlocks);\n    if (newWeight < gMinimumWitnessWeight)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"PoW² witness has insufficient weight.\");\n    }\n\n    // Enforce new weight > old weight\n    uint64_t notUsed1, notUsed2;\n    int64_t oldWeight = GetPoW2RawWeightForAmount(currentWitnessTxOut.nValue, chainActive.Height(), GetPoW2LockLengthInBlocksFromOutput(currentWitnessTxOut, currentWitnessHeight, notUsed1, notUsed2));\n    if (newWeight <= oldWeight)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, strprintf(\"New weight [%d] does not exceed old weight [%d].\", newWeight, oldWeight));\n    }\n\n    // Find the account for this address\n    CAccount* witnessAccount = pwallet->FindBestWitnessAccountForTransaction(currentWitnessTxOut);\n    \n    if (!witnessAccount)\n        throw witness_error(witness::RPC_MISC_ERROR, \"Could not locate account for address\");\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot extend a witness-only account as spend key is required to do this.\");\n    }\n\n    // Finally attempt to create and send the witness transaction.\n    CReserveKeyOrScript reservekey(pwallet, fundingAccount, KEYCHAIN_CHANGE);\n    std::string reasonForFail;\n    CAmount transactionFee;\n    CMutableTransaction extendWitnessTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION);\n    {\n        // Add the existing witness output as an input\n        pwallet->AddTxInput(extendWitnessTransaction, CInputCoin(currentWitnessOutpoint, currentWitnessTxOut, true, false, currentWitnessHeight, currentWitnessTxIndex), false);\n\n        // Add new witness output\n        CTxOut extendedWitnessTxOutput;\n        extendedWitnessTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n        // As we are extending the address we reset the \"lock from\" and we set the \"lock until\" everything else except the value remains unchanged.\n        extendedWitnessTxOutput.output.witnessDetails.lockFromBlock = 0;\n        extendedWitnessTxOutput.output.witnessDetails.lockUntilBlock = chainActive.Tip()->nHeight + requestedLockPeriodInBlocks;\n        extendedWitnessTxOutput.output.witnessDetails.spendingKeyID = currentWitnessDetails.spendingKeyID;\n        extendedWitnessTxOutput.output.witnessDetails.witnessKeyID = currentWitnessDetails.witnessKeyID;\n        extendedWitnessTxOutput.output.witnessDetails.failCount = currentWitnessDetails.failCount;\n        extendedWitnessTxOutput.output.witnessDetails.actionNonce = currentWitnessDetails.actionNonce+1;\n        extendedWitnessTxOutput.nValue = requestedAmount;\n        extendWitnessTransaction.vout.push_back(extendedWitnessTxOutput);\n\n        // Fund the additional amount in the transaction (including fees)\n        int changeOutputPosition = 1;\n        std::set<int> subtractFeeFromOutputs; // Empty - we don't subtract fee from outputs\n        CCoinControl coincontrol;\n        if (!pwallet->FundTransaction(fundingAccount, extendWitnessTransaction, transactionFee, changeOutputPosition, reasonForFail, false, subtractFeeFromOutputs, coincontrol, reservekey))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to fund transaction [%s]\", reasonForFail.c_str()));\n        }\n    }\n\n    uint256 extendTransactionHash;\n    {\n        LOCK2(cs_main, pwallet->cs_wallet);\n        if (!pwallet->SignAndSubmitTransaction(reservekey, extendWitnessTransaction, reasonForFail, &extendTransactionHash))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to commit transaction [%s]\", reasonForFail.c_str()));\n        }\n    }\n\n    // Set result parameters\n    if (pTxid != nullptr)\n        *pTxid = extendTransactionHash.GetHex();\n    if (pFee != nullptr)\n        *pFee = transactionFee;\n}\n\nvoid fundwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, CAmount amount, uint64_t requestedPeriodInBlocks, bool fAllowMultiple, std::string* pTxid, CAmount* pFee)\n{\n    if (!IsPow2Phase2Active(chainActive.Tip()))\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Can't create witness accounts before phase 2 activates\"));\n    }\n    \n    std::vector<CAmount> amounts;\n    LOCK(cs_main);\n    \n    // For the sake of testnet we turn off 'splitting' for very short lock periods as it was triggering some testnet specific 'short period' bugs that aren't worth fixing for mainnet (where they can't occur)\n    if (IsSegSigEnabled(chainActive.TipPrev()) && requestedPeriodInBlocks > 1000)\n    {\n        CGetWitnessInfo witnessInfo = GetWitnessInfoWrapper();\n        amounts = optimalWitnessDistribution(amount, requestedPeriodInBlocks, witnessInfo.nTotalWeightEligibleRaw);\n    }\n    else\n        amounts = { amount };\n\n    fundwitnessaccount(pwallet, fundingAccount, witnessAccount, amounts, requestedPeriodInBlocks, fAllowMultiple, pTxid, pFee);\n}\n\nvoid fundwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, const std::vector<CAmount>& amounts, uint64_t requestedPeriodInBlocks, bool fAllowMultiple, std::string* pTxid, CAmount* pFee)\n{\n    if (!IsPow2Phase2Active(chainActive.Tip()))\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Can't create witness accounts before phase 2 activates\"));\n    }\n\n    if (pwallet == nullptr || witnessAccount == nullptr || fundingAccount == nullptr)\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Require non-null pwallet, fundingAccount, witnessAccount\");\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (!witnessAccount->IsPoW2Witness())\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Specified account is not a witness account [%s].\", boost::uuids::to_string(witnessAccount->getUUID())));\n    if (witnessAccount->m_Type == WitnessOnlyWitnessAccount || !witnessAccount->IsHD())\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Cannot fund a witness only witness account [%s].\", boost::uuids::to_string(witnessAccount->getUUID())));\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(witnessAccount);\n    if (unspentWitnessOutputs.size() > 0)\n    {\n        if (!fAllowMultiple)\n            throw std::runtime_error(\"Account already has an active funded witness address. Perhaps you intended to 'extend' it? See: 'help extendwitnessaccount'\");\n    }\n\n    if (std::any_of(amounts.begin(), amounts.end(), [](const auto& amount){ return amount < (gMinimumWitnessAmount*COIN); }))\n        throw witness_error(witness::RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n\n    if (requestedPeriodInBlocks == 0)\n        throw witness_error(witness::RPC_TYPE_ERROR, \"Invalid number passed for lock period.\");\n\n    if (requestedPeriodInBlocks > MaximumWitnessLockLength())\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Maximum lock period of 3 years exceeded.\");\n\n    if (requestedPeriodInBlocks < MinimumWitnessLockLength())\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Minimum lock period of 1 month exceeded.\");\n\n    // Add a small buffer to give us time to enter the blockchain\n    if (requestedPeriodInBlocks == MinimumWitnessLockLength())\n        requestedPeriodInBlocks += 50;\n\n    // Enforce minimum weight for each amount\n    if (std::any_of(amounts.begin(), amounts.end(), [&](const auto& amount){ return GetPoW2RawWeightForAmount(amount, chainActive.Height(), requestedPeriodInBlocks) < gMinimumWitnessWeight; }))\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"PoW² witness has insufficient weight.\");\n    }\n\n    // Finally attempt to create and send the witness transaction.\n    CPoW2WitnessDestination destinationPoW2Witness;\n    destinationPoW2Witness.lockFromBlock = 0;\n    destinationPoW2Witness.lockUntilBlock = chainActive.Tip()->nHeight + requestedPeriodInBlocks;\n    destinationPoW2Witness.failCount = 0;\n    destinationPoW2Witness.actionNonce = 0;\n    {\n        CReserveKeyOrScript keyWitness(pactiveWallet, witnessAccount, KEYCHAIN_WITNESS);\n        CPubKey pubWitnessKey;\n        if (!keyWitness.GetReservedKey(pubWitnessKey))\n            throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, \"Error allocating witness key for witness account.\");\n\n        //We delibritely return the key here, so that if we fail we won't leak the key.\n        //The key will be marked as used when the transaction is accepted anyway.\n        keyWitness.ReturnKey();\n        destinationPoW2Witness.witnessKey = pubWitnessKey.GetID();\n    }\n    {\n        //Code should be refactored to only call 'KeepKey' -after- success, a bit tricky to get there though.\n        CReserveKeyOrScript keySpending(pactiveWallet, witnessAccount, KEYCHAIN_SPENDING);\n        CPubKey pubSpendingKey;\n        if (!keySpending.GetReservedKey(pubSpendingKey))\n            throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, \"Error allocating spending key for witness account.\");\n\n        //We delibritely return the key here, so that if we fail we won't leak the key.\n        //The key will be marked as used when the transaction is accepted anyway.\n        keySpending.ReturnKey();\n        destinationPoW2Witness.spendingKey = pubSpendingKey.GetID();\n    }\n\n    CAmount transactionFee;\n    std::string strError;\n    std::vector<CRecipient> vecSend;\n    int nChangePosRet = -1;\n\n    std::for_each(amounts.begin(), amounts.end(), [&](const CAmount& amount){\n        CRecipient recipient = ( IsSegSigEnabled(chainActive.TipPrev()) ? ( CRecipient(GetPoW2WitnessOutputFromWitnessDestination(destinationPoW2Witness), amount, false) ) : ( CRecipient(GetScriptForDestination(destinationPoW2Witness), amount, false) ) ) ;\n        if (!IsSegSigEnabled(chainActive.TipPrev()))\n        {\n            // We have to copy this anyway even though we are using a CSCript as later code depends on it to grab the witness key id.\n            recipient.witnessDetails.witnessKeyID = destinationPoW2Witness.witnessKey;\n        }\n\n        //NB! Setting this is -super- important, if we don't then encrypted wallets may fail to witness.\n        recipient.witnessForAccount = witnessAccount;\n        vecSend.push_back(recipient);\n    });\n\n    CWalletTx wtx;\n    CReserveKeyOrScript reservekey(pwallet, fundingAccount, KEYCHAIN_CHANGE);\n    if (!pwallet->CreateTransaction(fundingAccount, vecSend, wtx, reservekey, transactionFee, nChangePosRet, strError))\n    {\n        throw witness_error(witness::RPC_WALLET_ERROR, strError);\n    }\n\n    CValidationState state;\n    if (!pwallet->CommitTransaction(wtx, reservekey, g_connman.get(), state))\n    {\n        strError = strprintf(\"Error: The transaction was rejected! Reason given: %s\", state.GetRejectReason());\n        throw witness_error(witness::RPC_WALLET_ERROR, strError);\n    }\n\n    // Set result parameters\n    if (pTxid != nullptr)\n        *pTxid = wtx.GetHash().GetHex();\n    if (pFee != nullptr)\n        *pFee = transactionFee;\n}\n\nvoid renewwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, std::string* pTxid, CAmount* pFee)\n{\n    if (pwallet == nullptr || witnessAccount == nullptr || fundingAccount == nullptr)\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Require non-null pwallet, fundingAccount, witnessAccount\");\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (pwallet->IsLocked()) {\n        throw std::runtime_error(\"Wallet locked\");\n    }\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot renew a witness-only account as spend key is required to do this.\");\n    }\n\n    std::string strError;\n    CMutableTransaction tx(CURRENT_TX_VERSION_POW2);\n    CReserveKeyOrScript changeReserveKey(pactiveWallet, fundingAccount, KEYCHAIN_EXTERNAL);\n    CAmount transactionFee;\n    if (!pwallet->PrepareRenewWitnessAccountTransaction(fundingAccount, witnessAccount, changeReserveKey, tx, transactionFee, strError))\n    {\n        throw std::runtime_error(strprintf(\"Failed to renew witness [%s]\", strError.c_str()));\n    }\n\n    uint256 upgradeTransactionHash;\n    if (!pwallet->SignAndSubmitTransaction(changeReserveKey, tx, strError, &upgradeTransactionHash))\n    {\n        LogPrintf(\"renewwitnessaccount Failed to sign transaction [%s]\", strError.c_str());\n        throw std::runtime_error(strprintf(\"Failed to sign transaction [%s]\", strError.c_str()));\n    }\n\n    // Set result parameters\n    if (pTxid != nullptr)\n        *pTxid = upgradeTransactionHash.GetHex();\n    if (pFee != nullptr)\n        *pFee = transactionFee;\n}\n\nvoid rotatewitnessaddresshelper(CAccount* fundingAccount, witnessOutputsInfoVector unspentWitnessOutputs, CWallet* pwallet, std::string* pTxid, CAmount* pFee)\n{\n    if (unspentWitnessOutputs.size() == 0)\n        throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Too few witness outputs cannot rotate.\"));\n\n    // Check for immaturity\n    for (const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint]: unspentWitnessOutputs)\n    {\n        (unused) currentWitnessTxOut;\n        (unused) currentWitnessOutpoint;\n        (unused) currentWitnessTxIndex;\n        //fixme: (PHASE5) - Minor code cleanup.\n        //This check should go through the actual chain maturity stuff (via wtx) and not calculate maturity directly.\n        if (chainActive.Tip()->nHeight - currentWitnessHeight < (uint64_t)(COINBASE_MATURITY))\n            throw witness_error(witness::RPC_MISC_ERROR, \"Cannot perform operation on immature transaction, please wait for transaction to mature and try again\");\n    }\n\n\n    // Find the account for this address\n    CAccount* witnessAccount = nullptr;\n    {\n        CTxOutPoW2Witness currentWitnessDetails;\n        const auto& currentWitnessTxOut = std::get<0>(unspentWitnessOutputs[0]);\n        GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails);\n        witnessAccount = pwallet->FindBestWitnessAccountForTransaction(currentWitnessTxOut);\n    }\n    if (!witnessAccount)\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Could not locate account\");\n    }\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot rotate a witness-only account as spend key is required to do this.\");\n    }\n\n    // Finally attempt to create and send the witness transaction.\n    CReserveKeyOrScript reservekey(pwallet, fundingAccount, KEYCHAIN_CHANGE);\n    std::string reasonForFail;\n    CAmount transactionFee;\n    CMutableTransaction rotateWitnessTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION);\n    CPubKey pubWitnessKey;\n    {\n        // Get new witness key\n        CReserveKeyOrScript keyWitness(pactiveWallet, witnessAccount, KEYCHAIN_WITNESS);\n        if (!keyWitness.GetReservedKey(pubWitnessKey))\n        {\n            throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, \"Error allocating witness key for witness account.\");\n        }\n\n        //We delibritely return the key here, so that if we fail we won't leak the key.\n        //The key will be marked as used when the transaction is accepted anyway.\n        keyWitness.ReturnKey();\n    }\n\n    // Add all existing outputs as inputs and new outputs\n    for (const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint]: unspentWitnessOutputs)\n    {\n        // Add input\n        pwallet->AddTxInput(rotateWitnessTransaction, CInputCoin(currentWitnessOutpoint, currentWitnessTxOut, true, false, currentWitnessHeight, currentWitnessTxIndex), false);\n\n        // Get witness details\n        CTxOutPoW2Witness currentWitnessDetails;\n        if (!GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails))\n            throw witness_error(witness::RPC_MISC_ERROR, \"Failure extracting witness details.\");\n\n        // Add rotated output\n        CTxOut rotatedWitnessTxOutput;\n        rotatedWitnessTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n        rotatedWitnessTxOutput.output.witnessDetails.lockFromBlock = currentWitnessDetails.lockFromBlock;\n        // Ensure consistent lock from\n        if (rotatedWitnessTxOutput.output.witnessDetails.lockFromBlock == 0)\n        {\n            rotatedWitnessTxOutput.output.witnessDetails.lockFromBlock = currentWitnessHeight;\n        }\n        rotatedWitnessTxOutput.output.witnessDetails.lockUntilBlock = currentWitnessDetails.lockUntilBlock;\n        rotatedWitnessTxOutput.output.witnessDetails.spendingKeyID = currentWitnessDetails.spendingKeyID;\n        rotatedWitnessTxOutput.output.witnessDetails.witnessKeyID = pubWitnessKey.GetID();\n        rotatedWitnessTxOutput.output.witnessDetails.failCount = currentWitnessDetails.failCount;\n        rotatedWitnessTxOutput.output.witnessDetails.actionNonce = currentWitnessDetails.actionNonce+1;\n        rotatedWitnessTxOutput.nValue = currentWitnessTxOut.nValue;\n        rotateWitnessTransaction.vout.push_back(rotatedWitnessTxOutput);\n    }\n\n    // Fund the additional amount in the transaction (including fees)\n    int changeOutputPosition = 1;\n    std::set<int> subtractFeeFromOutputs; // Empty - we don't subtract fee from outputs\n    CCoinControl coincontrol;\n    if (!pwallet->FundTransaction(fundingAccount, rotateWitnessTransaction, transactionFee, changeOutputPosition, reasonForFail, false, subtractFeeFromOutputs, coincontrol, reservekey))\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to fund transaction [%s]\", reasonForFail.c_str()));\n    }\n\n\n    //fixme: (PHASE5) - Minor code cleanup\n    //Improve this a bit, we should make this 'atomic'\n    //i.e. only perform the action that can't be rolled back (adding the key to the account) if the entire thing succeeds\n    //So only after the signing of the transaction is a success\n    //Also (low) this shares common code with CreateTransaction() - so it should be factored out into a common helper that both can use.\n    CKey privWitnessKey;\n    if (!witnessAccount->GetKey(pubWitnessKey.GetID(), privWitnessKey))\n    {\n        reasonForFail = strprintf(\"Wallet error, failed to retrieve private witness key.\");\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to fund transaction [%s]\", reasonForFail.c_str()));\n    }\n    if (!pwallet->AddKeyPubKey(privWitnessKey, privWitnessKey.GetPubKey(), *witnessAccount, KEYCHAIN_WITNESS))\n    {\n        reasonForFail = strprintf(\"Wallet error, failed to store witness key.\");\n        throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to fund transaction [%s]\", reasonForFail.c_str()));\n    }\n\n    uint256 rotateTransactionHash;\n    {\n        LOCK2(cs_main, pactiveWallet->cs_wallet);\n        if (!pwallet->SignAndSubmitTransaction(reservekey, rotateWitnessTransaction, reasonForFail, &rotateTransactionHash))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to commit transaction [%s]\", reasonForFail.c_str()));\n        }\n    }\n\n    // Set result parameters\n    if (pTxid != nullptr)\n        *pTxid = rotateTransactionHash.GetHex();\n    if (pFee != nullptr)\n        *pFee = transactionFee;\n}\n\nvoid rotatewitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, std::string* pTxid, CAmount* pFee)\n{\n    if (pwallet == nullptr || witnessAccount == nullptr || fundingAccount == nullptr)\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Require non-null pwallet, fundingAccount, witnessAccount\");\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n        throw std::runtime_error(\"Cannot use this command before segsig activates\");\n\n    if (pwallet->IsLocked()) {\n        throw std::runtime_error(\"Wallet locked\");\n    }\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot rotate a witness-only account as spend key is required to do this.\");\n    }\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(witnessAccount);\n    if (unspentWitnessOutputs.size() == 0)\n        throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Account does not contain any witness outputs [%s].\",\n                                                                           boost::uuids::to_string(witnessAccount->getUUID())));\n\n    rotatewitnessaddresshelper(fundingAccount, unspentWitnessOutputs, pwallet, pTxid, pFee);\n}\n\nCGetWitnessInfo GetWitnessInfoWrapper()\n{\n    CGetWitnessInfo witnessInfo;\n\n    CBlock block;\n    {\n        LOCK(cs_main); // Required for ReadBlockFromDisk as well as GetWitnessInfo.\n        if (!ReadBlockFromDisk(block, chainActive.Tip(), Params()))\n        {\n            std::string strErrorMessage = \"Error in GetWitnessInfoWrapper, failed to read block from disk\";\n            CAlert::Notify(strErrorMessage, true, true);\n            LogPrintf(\"%s\", strErrorMessage.c_str());\n            throw std::runtime_error(strErrorMessage);\n        }\n        if (!GetWitness(chainActive, Params(), nullptr, chainActive.Tip()->pprev, block, witnessInfo))\n        {\n            std::string strErrorMessage = \"Error in GetWitnessInfoWrapper, failed to retrieve witness info\";\n            CAlert::Notify(strErrorMessage, true, true);\n            LogPrintf(\"%s\", strErrorMessage.c_str());\n            throw std::runtime_error(strErrorMessage);\n        }\n    }\n\n    return witnessInfo;\n}\n\nvoid EnsureMatchingWitnessCharacteristics(const witnessOutputsInfoVector& unspentWitnessOutputs)\n{\n    // Properties should beidentical, except lockFromBlock is special.\n    // Extending (or initial funding) of a multiple-part witness can result in different lockFromBlock values, which are test as follows:\n    // A) All outputs that have a non-zero lockFromBlock should share the same non-zero value.\n    // B) All outputs with a zero lockFromBlock should share the same coin height.\n    // C) And finally the non-zero value from A and B should be the same.\n    // When a new witness is created it enters with a lockFromBlock == 0, which is replaced by the height the tx entered the chain\n    // in a later operation (ie. a witness operation, rearrange, renew etc.)\n    if (unspentWitnessOutputs.size() > 0)\n    {\n        CTxOutPoW2Witness witnessDetails0;\n        if (!GetPow2WitnessOutput(std::get<0>(unspentWitnessOutputs[0]), witnessDetails0))\n            throw std::runtime_error(\"Failure extracting witness details.\");\n\n        // collect values for A and B tests\n        uint64_t nonZeroFrom = 0;\n        uint64_t nonZeroCoin = 0;\n        for (unsigned int i = 0; i < unspentWitnessOutputs.size(); i++) {\n            CTxOutPoW2Witness witnessDetails;\n            if (!GetPow2WitnessOutput(std::get<0>(unspentWitnessOutputs[i]), witnessDetails))\n                throw std::runtime_error(\"Failure extracting witness details.\");\n            if (witnessDetails.lockFromBlock != 0)\n                nonZeroFrom = witnessDetails.lockFromBlock;\n            else\n                nonZeroCoin = std::get<1>(unspentWitnessOutputs[i]);\n\n            if (nonZeroFrom != 0 && nonZeroCoin != 0)\n                break;\n        }\n\n        // test C\n        if (nonZeroFrom != 0 && nonZeroCoin != 0 && nonZeroFrom != nonZeroCoin)\n            throw std::runtime_error(\"Multiple addresses with different witness characteristics in account. Use RPC to furter handle this account.\");\n\n        for (unsigned int i = 0; i < unspentWitnessOutputs.size(); i++) {\n            CTxOutPoW2Witness witnessCompare;\n            if (!GetPow2WitnessOutput(std::get<0>(unspentWitnessOutputs[i]), witnessCompare))\n                throw std::runtime_error(\"Failure extracting witness details.\");\n            if (witnessCompare.lockUntilBlock != witnessDetails0.lockUntilBlock ||\n                witnessCompare.spendingKeyID != witnessDetails0.spendingKeyID ||\n                witnessCompare.witnessKeyID != witnessDetails0.witnessKeyID ||\n                (witnessCompare.lockFromBlock != 0 && witnessCompare.lockFromBlock != nonZeroFrom) || // test A\n                (witnessCompare.lockFromBlock == 0 && std::get<1>(unspentWitnessOutputs[i]) != nonZeroCoin)) // test B\n            {\n                throw std::runtime_error(\"Multiple addresses with different witness characteristics in account. Use RPC to furter handle this account.\");\n            }\n        }\n\n    }\n}\n\n\nCWitnessBundlesRef GetWitnessBundles(const CWalletTx& wtx)\n{\n    CWitnessBundlesRef pWitnessBundles = std::make_shared<CWitnessBundles>();\n    if (wtx.witnessBundles)\n    {\n        pWitnessBundles = wtx.witnessBundles;\n        return pWitnessBundles;\n    }\n    else\n    {\n        bool haveBundles = false;\n        if (wtx.tx->witnessBundles)\n        {\n            pWitnessBundles = wtx.tx->witnessBundles;\n            haveBundles = true;\n        }\n        else\n        {\n            CValidationState state;\n            int nWalletTxBlockHeight = chainActive.Tip()?chainActive.Tip()->nHeight:0;\n            const auto& findIter = mapBlockIndex.find(wtx.hashBlock);\n            if (findIter != mapBlockIndex.end())\n                nWalletTxBlockHeight = findIter->second->nHeight;\n\n            CWitnessBundles bundles;\n            haveBundles = BuildWitnessBundles(*wtx.tx, state, nWalletTxBlockHeight, wtx.nIndex,\n            [&](const COutPoint& outpoint, CTxOut& txOut, uint64_t& txHeight, uint64_t& txIndex, uint64_t& txIndexOutput) {\n                CTransactionRef txRef;\n                int nInputHeight = -1;\n                LOCK(cs_main);\n                if (outpoint.isHash) {\n                    const CWalletTx* txPrev = pactiveWallet->GetWalletTx(outpoint.getTransactionHash());\n                    if (!txPrev || txPrev->tx->vout.size() == 0)\n                        return false;\n\n                    const auto& findIter = mapBlockIndex.find(txPrev->hashBlock);\n                    if (findIter != mapBlockIndex.end()) {\n                        nInputHeight = findIter->second->nHeight;\n                    }\n\n                    txRef = txPrev->tx;\n                }\n                else\n                {\n                    nInputHeight = outpoint.getTransactionBlockNumber();\n                    CBlock block;\n                    if (chainActive.Height() >= nInputHeight && ReadBlockFromDisk(block, chainActive[nInputHeight], Params())) {\n                        txRef = block.vtx[outpoint.getTransactionIndex()];\n                    }\n                    else\n                        return false;\n                }\n                txOut = txRef->vout[outpoint.n];\n                txHeight = nInputHeight;\n                return true;\n            },\n            bundles);\n            pWitnessBundles = std::make_shared<CWitnessBundles>(bundles);\n        }\n\n        if (haveBundles)\n        {\n            CWalletTx& w = REF(wtx);\n            w.witnessBundles = pWitnessBundles;\n            CWalletDB walletdb(*pactiveWallet->dbw);\n            walletdb.WriteTx(w);\n        }\n    }\n\n    return pWitnessBundles;\n}\n    \n    \nCWitnessAccountStatus GetWitnessAccountStatus(CWallet* pWallet, CAccount* account, CGetWitnessInfo* pWitnessInfo)\n{\n    WitnessStatus status;\n\n    LOCK2(cs_main, pWallet->cs_wallet);\n\n    CGetWitnessInfo witnessInfo;\n\n    if (chainActive.Height() > 0 && IsPow2Phase5Active(chainActive.Height())) {\n        witnessInfo = GetWitnessInfoWrapper();\n    }\n\n    // Collect uspent witnesses coins for the account\n    std::vector<RouletteItem> accountItems;\n    for (const auto& item : witnessInfo.witnessSelectionPoolUnfiltered)\n    {\n        if (IsMine(*account, item.coin.out))\n            accountItems.push_back(item);\n    }\n\n    bool haveUnspentWitnessUtxo = accountItems.size() > 0;\n\n    CTxOutPoW2Witness witnessDetails0;\n    if (haveUnspentWitnessUtxo && !GetPow2WitnessOutput(accountItems[0].coin.out, witnessDetails0))\n        throw std::runtime_error(\"Failure extracting witness details.\");\n\n    uint64_t nLockFromBlock = 0;\n    uint64_t nLockUntilBlock = 0;\n    uint64_t nLockPeriodInBlocks = accountItems.size() > 0 ? GetPoW2LockLengthInBlocksFromOutput(accountItems[0].coin.out, accountItems[0].coin.nHeight, nLockFromBlock, nLockUntilBlock) : 0;\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(account);\n    EnsureMatchingWitnessCharacteristics(unspentWitnessOutputs);\n\n    bool hasUnconfirmedBalance = pactiveWallet->GetUnconfirmedBalance(account, true, true) > 0;\n    bool hasImmatureBalance = pactiveWallet->GetImmatureBalance(account, true, true) > 0;\n    CAmount lockedBalance = pactiveWallet->GetLockedBalance(account, true);\n    bool hasLockedBalance = lockedBalance > 0;\n    bool hasMatureBalance = pactiveWallet->GetBalance(account, true, false, true) > 0;\n    \n    bool hasBalance = hasUnconfirmedBalance||hasImmatureBalance||hasMatureBalance||hasLockedBalance;\n\n    bool isLocked = haveUnspentWitnessUtxo && IsPoW2WitnessLocked(witnessDetails0, chainActive.Tip()->nHeight);\n\n    uint64_t networkWeight = witnessInfo.nTotalWeightRaw;\n    bool isExpired = haveUnspentWitnessUtxo && std::any_of(accountItems.begin(), accountItems.end(), [=](const RouletteItem& ri){\n                         return witnessHasExpired(ri.nAge, ri.nWeight, networkWeight);\n                     });\n\n    if (!haveUnspentWitnessUtxo && (hasImmatureBalance||hasUnconfirmedBalance||hasLockedBalance))\n    {\n        status = WitnessStatus::Pending;\n    }\n    else if (!haveUnspentWitnessUtxo && !hasBalance)\n    {\n        status = WitnessStatus::Empty;\n    }\n    else if (!haveUnspentWitnessUtxo && hasMatureBalance && !(hasImmatureBalance || hasUnconfirmedBalance))\n    {\n        status = WitnessStatus::EmptyWithRemainder;\n    }\n    else if (haveUnspentWitnessUtxo && hasBalance && isLocked && isExpired)\n    {\n        status = WitnessStatus::Expired;\n    }\n    else if (haveUnspentWitnessUtxo && hasBalance && isLocked && !isExpired)\n    {\n        status = WitnessStatus::Witnessing;\n    }\n    else if (haveUnspentWitnessUtxo && hasBalance && isLocked && isExpired)\n    {\n        status = WitnessStatus::Expired;\n    }\n    else if (haveUnspentWitnessUtxo && hasBalance && !isLocked)\n    {\n        status = WitnessStatus::Ended;\n    }\n    else if (haveUnspentWitnessUtxo && !hasBalance && !isLocked)\n    {\n        status = WitnessStatus::Emptying;\n    }\n    else\n    {\n        throw std::runtime_error(\"Unable to determine witness state.\");\n    }\n\n    CAmount originAmountLocked= 0;\n    uint64_t originWeight = 0;\n    bool hasUnconfirmedWittnessTx = false;\n    for (const auto& it: pWallet->mapWallet)\n    {\n        const auto& wtx = it.second;\n\n        // NOTE: assuming any unconfirmed tx here is a witness; avoid getting the witness bundles and testing those, this will almost always be correct. Any edge cases where this fails will automatically resolve once the tx confirms.\n        if (!hasUnconfirmedWittnessTx && account->HaveWalletTx(it.second) && it.second.InMempool())\n        {\n            hasUnconfirmedWittnessTx = true;\n        }\n        \n        // Coinbase can only be generation not lock\n        if (!wtx.IsPoW2WitnessCoinBase())\n        {\n            const auto& bundles = GetWitnessBundles(wtx);\n            if (bundles && bundles->size() > 0)\n            {\n                for (const CWitnessTxBundle& witnessBundle : *bundles)\n                {\n                    switch (witnessBundle.bundleType)\n                    {\n                        case CWitnessTxBundle::WitnessTxType::CreationType:\n                        {\n                            originAmountLocked += std::accumulate(witnessBundle.outputs.begin(), witnessBundle.outputs.end(), CAmount(0), \n                            [&account](const CAmount acc, const auto& txIter)\n                                {\n                                    const CTxOut& txOut = std::get<0>(txIter);\n                                    if (IsMine(*account, txOut))\n                                    {\n                                        return acc + txOut.nValue;\n                                    }\n                                    return acc;\n                                }\n                            );\n                        }\n                        break;\n                        case CWitnessTxBundle::WitnessTxType::IncreaseType:\n                        {\n                            //fixme: IMPLEMENT\n                        }\n                        break;\n                        case CWitnessTxBundle::WitnessTxType::RearrangeType:\n                        {\n                        //fixme: IMPLEMENT\n                        }\n                        break;\n                        default:\n                        break;\n                    } \n                }\n            }\n        }\n    }\n\n    // hasUnconfirmedWittnessTx -> renewed, extended ...\n    if (status == WitnessStatus::Expired && hasUnconfirmedWittnessTx)\n        status = WitnessStatus::Witnessing;\n\n    bool hasScriptLegacyOutput = std::any_of(accountItems.begin(), accountItems.end(), [](const RouletteItem& ri){ return ri.coin.out.GetType() == CTxOutType::ScriptLegacyOutput; });\n\n    std::vector<std::tuple<uint64_t, uint64_t>> parts;\n    std::transform(accountItems.begin(), accountItems.end(), std::back_inserter(parts), [](const auto& ri) { return std::tuple(ri.nWeight, ri.nAge); });\n\n    CWitnessAccountStatus result {\n        account,\n        status,\n        networkWeight,\n        //NB! We always want the account weight (even if expired) - otherwise how do we e.g. draw a historical graph of the expected earnings for the expired account?\n        std::accumulate(accountItems.begin(), accountItems.end(), uint64_t(0), [](const uint64_t acc, const RouletteItem& ri){ return acc + ri.nWeight; }),\n        originWeight,\n        lockedBalance,\n        originAmountLocked,\n        hasScriptLegacyOutput,\n        hasUnconfirmedWittnessTx,\n        nLockFromBlock,\n        nLockUntilBlock,\n        nLockPeriodInBlocks,\n        parts\n    };\n\n    if (pWitnessInfo && IsPow2Phase3Active(chainActive.Height()))\n        *pWitnessInfo = std::move(witnessInfo);\n\n    return result;\n}\n\nvoid redistributeandextendwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, const std::vector<CAmount>& redistributionAmounts, uint64_t requestedLockPeriodInBlocks, std::string* pTxid, CAmount* pFee)\n{\n    if (pwallet == nullptr || witnessAccount == nullptr || fundingAccount == nullptr)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"Require non-null pwallet, fundingAccount, witnessAccount\");\n    }\n\n    LOCK2(cs_main, pwallet->cs_wallet);\n\n    if (!IsSegSigEnabled(chainActive.TipPrev()))\n    {\n        throw std::runtime_error(\"Segsig not activated\");\n    }\n\n    if (pwallet->IsLocked())\n    {\n        throw std::runtime_error(\"Wallet locked\");\n    }\n\n    if ((!witnessAccount->IsPoW2Witness()) || witnessAccount->IsFixedKeyPool())\n    {\n        throw witness_error(witness::RPC_MISC_ERROR, \"Cannot operate on witness-only account as spend key is required to do this.\");\n    }\n\n    const auto& unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(witnessAccount);\n    if (unspentWitnessOutputs.size() == 0)\n    {\n        throw witness_error(witness::RPC_INVALID_ADDRESS_OR_KEY, strprintf(\"Account does not contain any witness outputs [%s].\", boost::uuids::to_string(witnessAccount->getUUID())));\n    }\n\n    EnsureMatchingWitnessCharacteristics(unspentWitnessOutputs);\n\n    const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] = unspentWitnessOutputs[0];\n    (unused)currentWitnessHeight;\n    (unused)currentWitnessTxIndex;\n    (unused)currentWitnessOutpoint;\n\n    // Get the current witness details\n    CTxOutPoW2Witness currentWitnessDetails;\n    GetPow2WitnessOutput(currentWitnessTxOut, currentWitnessDetails);\n\n    if (std::any_of(redistributionAmounts.begin(), redistributionAmounts.end(), [](const auto& amount){ return amount < (gMinimumWitnessAmount*COIN); }))\n        throw witness_error(witness::RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n\n    uint64_t remainingLockDurationInBlocks = GetPoW2RemainingLockLengthInBlocks(currentWitnessDetails.lockUntilBlock, chainActive.Tip()->nHeight);\n    if (remainingLockDurationInBlocks == 0)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, \"PoW² witness has already unlocked.\");\n    }\n\n    // extend specifics\n    if (requestedLockPeriodInBlocks != 0)\n    {\n        if (requestedLockPeriodInBlocks > MaximumWitnessLockLength())\n        {\n            throw witness_error(witness::RPC_INVALID_PARAMETER, \"Maximum lock period of 3 years exceeded.\");\n        }\n\n        if (requestedLockPeriodInBlocks < MinimumWitnessLockLength())\n        {\n            throw witness_error(witness::RPC_INVALID_PARAMETER, \"Minimum lock period of 1 month exceeded.\");\n        }\n\n        // Add a small buffer to give us time to enter the blockchain\n        if (requestedLockPeriodInBlocks == MinimumWitnessLockLength())\n        {\n            requestedLockPeriodInBlocks += 50;\n        }\n\n        if (requestedLockPeriodInBlocks < remainingLockDurationInBlocks)\n        {\n            throw witness_error(witness::RPC_INVALID_PARAMETER, strprintf(\"New lock period [%d] does not exceed remaining lock period [%d]\", requestedLockPeriodInBlocks, remainingLockDurationInBlocks));\n        }\n\n        // Enforce minimum weight for each amount\n        auto tooSmallTest = [&] (const auto& amount){ return GetPoW2RawWeightForAmount(amount, chainActive.Height(), requestedLockPeriodInBlocks) < gMinimumWitnessWeight; };\n        bool witnessAmountTooSmall = std::any_of(redistributionAmounts.begin(), redistributionAmounts.end(), tooSmallTest);\n        if (witnessAmountTooSmall)\n        {\n            throw witness_error(witness::RPC_TYPE_ERROR, strprintf(\"Witness amount must be %d or larger\", gMinimumWitnessAmount));\n        }\n\n        // Enforce new combined weight > old combined weight\n        const CGetWitnessInfo witnessInfo = GetWitnessInfoWrapper();\n        uint64_t dummyLockFrom, dummyLockUntil;\n        uint64_t oldLockPeriod = GetPoW2LockLengthInBlocksFromOutput(currentWitnessTxOut, currentWitnessHeight, dummyLockFrom, dummyLockUntil);\n        std::vector<CAmount> oldAmounts;\n        std::transform(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), std::back_inserter(oldAmounts), [](const auto& it) { return std::get<0>(it).nValue; });\n        uint64_t oldCombinedWeight = combinedWeight(oldAmounts, currentWitnessHeight, oldLockPeriod);\n        uint64_t newCombinedWeight = combinedWeight(redistributionAmounts, currentWitnessHeight, requestedLockPeriodInBlocks);\n        if (oldCombinedWeight >= newCombinedWeight)\n        {\n            throw witness_error(witness::RPC_TYPE_ERROR, strprintf(\"New combined witness weight (%\" PRIu64 \") must exceed old (%\" PRIu64 \")\", newCombinedWeight, oldCombinedWeight));\n        }\n    }\n\n    // Check for immaturity\n    for ( const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint] : unspentWitnessOutputs )\n    {\n        (unused) currentWitnessTxOut;\n        (unused) currentWitnessOutpoint;\n        (unused) currentWitnessTxIndex;\n        //fixme: (PHASE5) - Minor code cleanup.\n        //This check should go through the actual chain maturity stuff (via wtx) and not calculate maturity directly.\n        if (chainActive.Tip()->nHeight - currentWitnessHeight < (uint64_t)(COINBASE_MATURITY))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, \"Cannot perform operation on immature transaction, please wait for transaction to mature and try again\");\n        }\n    }\n\n    // Check type (can't extend script type, must witness once or renew/upgrade after phase 4 activated)\n    if (std::any_of(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), [](const auto& it){ return std::get<0>(it).GetType() !=  CTxOutType::PoW2WitnessOutput; }))\n    {\n        throw witness_error(witness::RPC_TYPE_ERROR, \"Witness has to be type POW2WITNESS, renew or upgrade account\");\n    }\n\n    // Check that total of new value is at least old total\n    CAmount redistributionTotal = std::accumulate(redistributionAmounts.begin(), redistributionAmounts.end(), CAmount(0), [](const CAmount acc, const CAmount amount){ return acc + amount; });\n    CAmount oldTotal = std::accumulate(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), CAmount(0), [](const CAmount acc, const auto& it){\n        const CTxOut& txOut = std::get<0>(it);\n        return acc + txOut.nValue;\n    });\n    if (redistributionTotal < oldTotal)\n    {\n        throw witness_error(witness::RPC_INVALID_PARAMETER, strprintf(\"New amount [%s] is smaller than current amount [%s]\", FormatMoney(redistributionTotal), FormatMoney(oldTotal)));\n    }\n\n\n    // Create the redistribution transaction\n    CReserveKeyOrScript reservekey(pwallet, fundingAccount, KEYCHAIN_CHANGE);\n    std::string reasonForFail;\n    CAmount transactionFee;\n    CMutableTransaction witnessTransaction(CTransaction::SEGSIG_ACTIVATION_VERSION);\n    {\n\n        uint64_t highestActionNonce = 0;\n        uint64_t highestFailCount = 0;\n\n        // Add all original outputs as inputs\n        for (const auto& [currentWitnessTxOut, currentWitnessHeight, currentWitnessTxIndex, currentWitnessOutpoint]: unspentWitnessOutputs)\n        {\n            pwallet->AddTxInput(witnessTransaction, CInputCoin(currentWitnessOutpoint, currentWitnessTxOut, true, false, currentWitnessHeight, currentWitnessTxIndex), false);\n\n            CTxOutPoW2Witness details;\n            if (!GetPow2WitnessOutput(currentWitnessTxOut, details))\n            {\n                throw witness_error(witness::RPC_MISC_ERROR, \"Failure extracting witness details.\");\n            }\n            if (details.actionNonce > highestActionNonce)\n                highestActionNonce = details.actionNonce;\n            if (details.failCount > highestFailCount)\n                highestFailCount = details.failCount;\n        }\n\n        // Add new witness outputs\n        for (const CAmount& distAmount : redistributionAmounts)\n        {\n            CTxOut distTxOutput;\n            distTxOutput.SetType(CTxOutType::PoW2WitnessOutput);\n             if (requestedLockPeriodInBlocks != 0)\n             {\n                 // extend\n                 distTxOutput.output.witnessDetails.lockFromBlock = 0;\n                 distTxOutput.output.witnessDetails.lockUntilBlock = chainActive.Tip()->nHeight + requestedLockPeriodInBlocks;\n             }\n             else\n             {\n                 // rearrange\n                 distTxOutput.output.witnessDetails.lockFromBlock = currentWitnessDetails.lockFromBlock;\n                 distTxOutput.output.witnessDetails.lockUntilBlock = currentWitnessDetails.lockUntilBlock;\n             }\n            distTxOutput.output.witnessDetails.spendingKeyID = currentWitnessDetails.spendingKeyID;\n            distTxOutput.output.witnessDetails.witnessKeyID = currentWitnessDetails.witnessKeyID;\n            distTxOutput.output.witnessDetails.failCount = highestFailCount;\n            distTxOutput.output.witnessDetails.actionNonce = highestActionNonce + 1;\n            distTxOutput.nValue = distAmount;\n            witnessTransaction.vout.push_back(distTxOutput);\n        }\n\n        // Fund the additional amount in the transaction (including fees)\n        int changeOutputPosition = 1;\n        std::set<int> subtractFeeFromOutputs; // Empty - we don't subtract fee from outputs\n        CCoinControl coincontrol;\n        if (!pwallet->FundTransaction(fundingAccount, witnessTransaction, transactionFee, changeOutputPosition, reasonForFail, false, subtractFeeFromOutputs, coincontrol, reservekey))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to fund transaction [%s]\", reasonForFail.c_str()));\n        }\n    }\n\n    uint256 finalTransactionHash;\n    {\n        LOCK2(cs_main, pwallet->cs_wallet);\n        if (!pwallet->SignAndSubmitTransaction(reservekey, witnessTransaction, reasonForFail, &finalTransactionHash))\n        {\n            throw witness_error(witness::RPC_MISC_ERROR, strprintf(\"Failed to commit transaction [%s]\", reasonForFail.c_str()));\n        }\n    }\n\n    // Set result parameters\n    if (pTxid != nullptr)\n        *pTxid = finalTransactionHash.GetHex();\n    if (pFee != nullptr)\n        *pFee = transactionFee;\n}\n\nvoid redistributewitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, const std::vector<CAmount>& redistributionAmounts, std::string* pTxid, CAmount* pFee)\n{\n    redistributeandextendwitnessaccount(pwallet, fundingAccount, witnessAccount, redistributionAmounts, 0, pTxid, pFee);\n}\n\nvoid extendwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, CAmount amount, uint64_t requestedLockPeriodInBlocks, std::string* pTxid, CAmount* pFee)\n{\n    CGetWitnessInfo witnessInfo = GetWitnessInfoWrapper();\n    auto distribution = optimalWitnessDistribution(amount, requestedLockPeriodInBlocks, witnessInfo.nTotalWeightEligibleRaw);\n    redistributeandextendwitnessaccount(pwallet, fundingAccount, witnessAccount, distribution, requestedLockPeriodInBlocks, pTxid, pFee);\n}\n\nuint64_t adjustedWeightForAmount(const CAmount amount, const uint64_t nHeight, const uint64_t duration, uint64_t networkWeight)\n{\n    uint64_t maxWeight = networkWeight / 100;\n    uint64_t rawWeight = GetPoW2RawWeightForAmount(amount, nHeight, duration);\n    uint64_t weight = std::min(rawWeight, maxWeight);\n    return weight;\n}\n\n/** Estimated witnessing count expressed as a fraction per block for a single amount */\ndouble witnessFraction(const CAmount amount, const uint64_t nHeight, const uint64_t duration, const uint64_t totalWeight)\n{\n    uint64_t weight = adjustedWeightForAmount(amount, nHeight, duration, totalWeight);\n\n    // election probability\n    const double p = double(weight) / totalWeight;\n\n    // adjust for cooldown\n    double fraction = 1.0 / (gMinimumParticipationAge + 1.0/p);\n\n    return fraction;\n}\n\n/** Estimated witnessing count expressed as a fraction per block for an amount distribution */\ndouble witnessFraction(const std::vector<CAmount>& amounts, const uint64_t nHeight, const uint64_t duration, const uint64_t totalWeight)\n{\n    double fraction = std::accumulate(amounts.begin(), amounts.end(), 0.0, [=](double acc, CAmount amount) {\n        return acc + witnessFraction(amount, nHeight, duration, totalWeight);\n    });\n    return fraction;\n}\n\nstd::tuple<std::vector<CAmount>, uint64_t, CAmount> witnessDistribution(CWallet* pWallet, CAccount* account)\n{\n    // assumes all account witness outputs have identical characteristics\n\n    LOCK2(cs_main, pWallet->cs_wallet);\n\n    const auto unspentWitnessOutputs = getCurrentOutputsForWitnessAccount(account);\n\n    std::vector<CAmount> distribution;\n    std::transform(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), std::back_inserter(distribution), [](const auto& it) {\n        const CTxOut& txOut = std::get<0>(it);\n        return txOut.nValue;\n    });\n\n    CAmount total = std::accumulate(unspentWitnessOutputs.begin(), unspentWitnessOutputs.end(), CAmount(0), [](const CAmount acc, const auto& it){\n        const CTxOut& txOut = std::get<0>(it);\n        return acc + txOut.nValue;\n    });\n\n    int64_t duration = 0;\n    if (unspentWitnessOutputs.size() > 0) {\n        const CTxOut& txOut = std::get<0>(unspentWitnessOutputs[0]);\n        uint64_t nUnused1, nUnused2;\n        duration = GetPoW2LockLengthInBlocksFromOutput(txOut, std::get<1>(unspentWitnessOutputs[0]), nUnused1, nUnused2);\n    }\n\n    return std::tuple(distribution, duration, total);\n}\n\nCAmount maxAmountForDurationAndWeight(uint64_t lockDuration, uint64_t nHeight, uint64_t targetWeight)\n{\n    (unused) nHeight;\n    // note that yearly_blocks is only correct for mainnet and should be parametrized for testnet, however it is consistent with\n    // with other parts of the code that also use mainnet characteristics for weight determination when on testnet\n    const double yearly_blocks = 365 * gRefactorDailyBlocksUsage;\n    const double K = 100000.0;\n    const double T = (1.0 + lockDuration / (yearly_blocks));\n\n    // solve quadratic to find amount that will match weight\n    const double A = T / K;\n    const double B = T;\n    const double C = - (double)(targetWeight);\n\n    double amount = (-B + sqrt(B*B - 4.0 * A * C)) / (2.0 * A);\n\n    return CAmount (amount * COIN);\n}\n\nstd::vector<CAmount> optimalWitnessDistribution(CAmount totalAmount, uint64_t duration, uint64_t totalWeight)\n{\n    std::vector<CAmount> distribution;\n\n    // Amount where maximum weight is reached and so any extra on top of that will not produce any gains\n    CAmount partMax = maxAmountForDurationAndWeight(duration, chainActive.Height(), totalWeight/100);\n    // Amount we have to be above to be a valid part of chain\n    CAmount partMin = maxAmountForDurationAndWeight(duration, chainActive.Height(), gMinimumWitnessWeight)+1;\n    if (partMin < gMinimumWitnessAmount*COIN)\n        partMin = gMinimumWitnessAmount*COIN+1;\n\n    // Divide int parts into 96% of maximum workable amount.\n    // Leaves some room for:\n    // a) leaves some room for entwork weight fluctuatiopns\n    // b) leaves some room when total network witness weight changes\n    CAmount partTarget = (96 * partMax) / 100;\n    \n    // Don't divide at all if parts are smaller than this\n    CAmount partTargetMin = (60 * partMax) / 100;\n\n    // ensure minimum criterium is met (on mainnet this is not expected to happen)\n    if (partTarget < partMin)\n        partTarget = partMin;\n\n    int wholeParts = totalAmount / partTarget;\n    \n    if (wholeParts > 1)\n    {\n        CAmount remainder = totalAmount - wholeParts * partTarget;\n        CAmount partRemainder = remainder/wholeParts;\n\n        for (int i=0; i< wholeParts; i++)\n        {\n            distribution.push_back(partTarget+partRemainder);\n            remainder -= partRemainder;\n        }\n\n        // add any final remainder to first part\n        distribution[0] += remainder;\n    }\n    else if (wholeParts == 1 && (totalAmount > partTarget) && (totalAmount / 2 > partTargetMin))\n    {\n        CAmount remainder = totalAmount - (totalAmount/2*2);\n        distribution.push_back((totalAmount/2)+remainder);\n        distribution.push_back(totalAmount/2);\n    }\n    else\n    {\n        distribution.push_back(totalAmount);\n    }\n    return distribution;\n}\n\nbool isWitnessDistributionNearOptimal(CWallet* pWallet, CAccount* account, const CGetWitnessInfo& witnessInfo)\n{\n    // NB! We prefer the raw weight to the eligible weight as the raw weight fluctuates less\n    // And over time the two should become close anyway\n    uint64_t totalWeight = witnessInfo.nTotalWeightEligibleRaw;\n\n    auto [currentDistribution, duration, totalAmount] = witnessDistribution(pWallet, account);\n    double currentFraction = witnessFraction(currentDistribution, chainActive.Height(), duration, totalWeight);\n\n    auto optimalDistribution = optimalWitnessDistribution(totalAmount, duration, totalWeight);\n    double optimalFraction = witnessFraction(optimalDistribution, chainActive.Height(), duration, totalWeight);\n\n    const double OPTIMAL_DISTRIBUTION_THRESHOLD = 0.95;\n    bool nearOptimal = currentFraction / optimalFraction >= OPTIMAL_DISTRIBUTION_THRESHOLD;\n    return nearOptimal;\n}\n\nuint64_t combinedWeight(const std::vector<CAmount> amounts, uint64_t height, uint64_t duration)\n{\n    return std::accumulate(amounts.begin(), amounts.end(), uint64_t(0), [=](uint64_t acc, CAmount amount)\n    {\n        return acc + GetPoW2RawWeightForAmount(amount, height, duration);\n    });\n}\n\nstd::string witnessAddressForAccount(CWallet* pWallet, CAccount* account)\n{\n    LOCK2(cs_main, pWallet->cs_wallet);\n\n    if (chainActive.Tip())\n    {\n        std::map<COutPoint, Coin> allWitnessCoins;\n        if (getAllUnspentWitnessCoins(chainActive, Params(), chainActive.Tip(), allWitnessCoins))\n        {\n            for (const auto& [witnessOutPoint, witnessCoin] : allWitnessCoins)\n            {\n                (unused)witnessOutPoint;\n                CTxOutPoW2Witness witnessDetails;\n                GetPow2WitnessOutput(witnessCoin.out, witnessDetails);\n                if (account->HaveKey(witnessDetails.witnessKeyID))\n                {\n                    return CNativeAddress(CPoW2WitnessDestination(witnessDetails.spendingKeyID, witnessDetails.witnessKeyID)).ToString();\n                }\n            }\n        }\n    }\n\n    return \"\";\n}\n\nstd::string witnessKeysLinkUrlForAccount(CWallet* pWallet, CAccount* account)\n{\n    std::set<CKeyID> keys;\n\n    LOCK2(cs_main, pWallet->cs_wallet);\n\n    if (chainActive.Tip())\n    {\n        std::map<COutPoint, Coin> allWitnessCoins;\n        if (getAllUnspentWitnessCoins(chainActive, Params(), chainActive.Tip(), allWitnessCoins))\n        {\n            for (const auto& [witnessOutPoint, witnessCoin] : allWitnessCoins)\n            {\n                (unused)witnessOutPoint;\n                CTxOutPoW2Witness witnessDetails;\n                GetPow2WitnessOutput(witnessCoin.out, witnessDetails);\n                if (account->HaveKey(witnessDetails.witnessKeyID))\n                {\n                    keys.insert(witnessDetails.witnessKeyID);\n                }\n            }\n        }\n    }\n\n    std::string witnessAccountKeys = \"\";\n    for (const CKeyID& key: keys) {\n        //fixme: (FUT) - to be 100% correct we should export the creation time of the actual key (where available) and not getEarliestPossibleCreationTime - however getEarliestPossibleCreationTime will do for now.\n        CKey witnessPrivKey;\n        if (account->GetKey(key, witnessPrivKey))\n        witnessAccountKeys += CEncodedSecretKey(witnessPrivKey).ToString() + strprintf(\"#%s\", account->getEarliestPossibleCreationTime());\n        witnessAccountKeys += \":\";\n    }\n\n    if (!witnessAccountKeys.empty())\n    {\n        witnessAccountKeys.pop_back();\n        witnessAccountKeys = GLOBAL_APP_URIPREFIX\"://witnesskeys?keys=\" + witnessAccountKeys;\n    }\n\n    return witnessAccountKeys;\n}\n"
  },
  {
    "path": "src/wallet/witness_operations.h",
    "content": "// Copyright (c) 2016-2022 The Centure developers\n// Authored by: Willem de Jonge (willem@isnapp.nl)\n// Modified by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WITNESS_OPERATIONS_H\n#define WITNESS_OPERATIONS_H\n\n#include \"amount.h\"\n#include <string>\n#include <cstdint>\n#include \"primitives/transaction.h\"\n\nclass CWallet;\nclass CAccount;\n\n// Error codes match exaclty with the codes used in rpc (plain copy)\n// This is now local to the witness operations but perhaps it could be promotoed to application wide\n// errors at some point. Scoped in namespace here to prevent collision and polution.\nnamespace witness {\n    enum ErrorCode {\n        //! General application defined errors\n        RPC_MISC_ERROR                  = -1,  //!< std::exception thrown in command handling\n        RPC_FORBIDDEN_BY_SAFE_MODE      = -2,  //!< Server is in safe mode, and command is not allowed in safe mode\n        RPC_TYPE_ERROR                  = -3,  //!< Unexpected type was passed as parameter\n        RPC_INVALID_ADDRESS_OR_KEY      = -5,  //!< Invalid address or key\n        RPC_OUT_OF_MEMORY               = -7,  //!< Ran out of memory during operation\n        RPC_INVALID_PARAMETER           = -8,  //!< Invalid, missing or duplicate parameter\n        RPC_DATABASE_ERROR              = -20, //!< Database error\n        RPC_DESERIALIZATION_ERROR       = -22, //!< Error parsing or validating structure in raw format\n        RPC_VERIFY_ERROR                = -25, //!< General error during transaction or block submission\n        RPC_VERIFY_REJECTED             = -26, //!< Transaction or block was rejected by network rules\n        RPC_VERIFY_ALREADY_IN_CHAIN     = -27, //!< Transaction already in chain\n        RPC_IN_WARMUP                   = -28, //!< Client still warming up\n\n        //! Wallet errors\n        RPC_WALLET_ERROR                = -4,  //!< Unspecified problem with wallet (key not found etc.)\n        RPC_WALLET_INSUFFICIENT_FUNDS   = -6,  //!< Not enough funds in wallet or account\n        RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name\n        RPC_WALLET_KEYPOOL_RAN_OUT      = -12, //!< Keypool ran out, call keypoolrefill first\n        RPC_WALLET_UNLOCK_NEEDED        = -13, //!< Enter the wallet passphrase with walletpassphrase first\n        RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect\n        RPC_WALLET_WRONG_ENC_STATE      = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)\n        RPC_WALLET_ENCRYPTION_FAILED    = -16, //!< Failed to encrypt the wallet\n        RPC_WALLET_ALREADY_UNLOCKED     = -17, //!< Wallet is already unlocked\n    };\n}\n\nclass witness_error: public std::runtime_error\n{\npublic:\n    explicit witness_error(int c, const std::string& what) : std::runtime_error(what), _code(c) {}\n\n    int code() const { return _code; }\n\nprivate:\n    int _code;\n};\n\ntypedef std::vector<std::tuple<CTxOut, uint64_t, uint64_t, COutPoint>> witnessOutputsInfoVector;\n\n// throw on failure\nvoid extendwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, CAmount amount, uint64_t requestedLockPeriodInBlocks, std::string* pTxid, CAmount* pFee);\nvoid extendwitnessaddresshelper(CAccount* fundingAccount, witnessOutputsInfoVector unspentWitnessOutputs, CWallet* pwallet, CAmount requestedAmount, uint64_t requestedLockPeriodInBlocks, std::string* pTxid, CAmount* pFee);\nvoid renewwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, std::string* pTxid, CAmount* pFee);\nvoid fundwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, CAmount amount, uint64_t requestedPeriodInBlocks, bool fAllowMultiple, std::string* pTxid, CAmount* pFee);\nvoid fundwitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, const std::vector<CAmount>& amounts, uint64_t requestedPeriodInBlocks, bool fAllowMultiple, std::string* pTxid, CAmount* pFee);\nvoid rotatewitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, std::string* pTxid, CAmount* pFee);\nvoid rotatewitnessaddresshelper(CAccount* fundingAccount, witnessOutputsInfoVector unspentWitnessOutputs, CWallet* pwallet, std::string* pTxid, CAmount* pFee);\nvoid redistributewitnessaccount(CWallet* pwallet, CAccount* fundingAccount, CAccount* witnessAccount, const std::vector<CAmount>& redistributionAmounts, std::string* pTxid, CAmount* pFee);\n\nstruct CGetWitnessInfo;\n\nenum class WitnessStatus {\n    Empty,\n    EmptyWithRemainder,\n    Pending,\n    Witnessing,\n    Ended,\n    Expired,\n    Emptying\n};\n\nCGetWitnessInfo GetWitnessInfoWrapper();\n\nstruct CWitnessAccountStatus\n{\n    CAccount* account;\n    WitnessStatus status;\n    uint64_t networkWeight;\n    uint64_t currentWeight;\n    uint64_t originWeight;\n    CAmount currentAmountLocked;\n    CAmount originAmountLocked;\n    bool hasScriptLegacyOutput;\n    bool hasUnconfirmedWittnessTx;\n    uint64_t nLockFromBlock;\n    uint64_t nLockUntilBlock;\n    uint64_t nLockPeriodInBlocks;\n    std::vector<std::tuple<uint64_t, uint64_t>> parts; // individual weight and age of all parts\n};\n\n/** Get account witness status and accompanying details\n * hasScriptLegacyOutput IFF any of the outputs is CTxOutType::ScriptLegacyOutput\n * hasUnconfirmedWittnessTx IFF unconfirmed witness tx for the account (not actually checked for witness type, see implementation note)\n * pWitnessInfo if != nullptr it will be filled with the witnessInfo if available\n*/\nCWitnessAccountStatus GetWitnessAccountStatus(CWallet* pWallet, CAccount* account, CGetWitnessInfo* pWitnessInfo = nullptr);\n\nwitnessOutputsInfoVector getCurrentOutputsForWitnessAccount(CAccount* forAccount);\n\nbool isWitnessDistributionNearOptimal(CWallet* pWallet, CAccount* account, const CGetWitnessInfo& witnessInfo);\nuint64_t adjustedWeightForAmount(const CAmount amount, const uint64_t nHeight, const uint64_t duration, uint64_t networkWeight);\nstd::tuple<std::vector<CAmount>, uint64_t, CAmount> witnessDistribution(CWallet* pWallet, CAccount* account);\nstd::vector<CAmount> optimalWitnessDistribution(CAmount totalAmount, uint64_t duration, uint64_t totalWeight);\nuint64_t combinedWeight(const std::vector<CAmount> amounts, uint64_t nHeight, uint64_t duration);\ndouble witnessFraction(const std::vector<CAmount>& amounts, uint64_t nHeight, const uint64_t duration, const uint64_t totalWeight);\nstd::string witnessAddressForAccount(CWallet* pWallet, CAccount* account);\nstd::string witnessKeysLinkUrlForAccount(CWallet* pWallet, CAccount* account);\n\n#endif // WITNESS_OPERATIONS_H\n"
  },
  {
    "path": "src/warnings.cpp",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n\n#include \"sync.h\"\n#include \"clientversion.h\"\n#include \"util.h\"\n#include \"warnings.h\"\n#include \"alert.h\"\n#include \"validation/validation.h\"\n\nRecursiveMutex cs_warnings;\nstd::string strMiscWarning;\nbool fLargeWorkForkFound = false;\nbool fLargeWorkInvalidChainFound = false;\n\nvoid SetMiscWarning(const std::string& strWarning)\n{\n    LOCK(cs_warnings);\n    strMiscWarning = strWarning;\n}\n\nvoid SetfLargeWorkForkFound(bool flag)\n{\n    LOCK(cs_warnings);\n    fLargeWorkForkFound = flag;\n}\n\nbool GetfLargeWorkForkFound()\n{\n    LOCK(cs_warnings);\n    return fLargeWorkForkFound;\n}\n\nvoid SetfLargeWorkInvalidChainFound(bool flag)\n{\n    LOCK(cs_warnings);\n    fLargeWorkInvalidChainFound = flag;\n}\n\nbool GetfLargeWorkInvalidChainFound()\n{\n    LOCK(cs_warnings);\n    return fLargeWorkInvalidChainFound;\n}\n\nstd::string GetWarnings(const std::string& strFor)\n{\n    std::string strStatusBar;\n    std::string strRPC;\n    std::string strGUI;\n    const std::string uiAlertSeperator = \"<hr />\";\n\n    LOCK(cs_warnings);\n\n    if (!CLIENT_VERSION_IS_RELEASE) {\n        strStatusBar = \"This is a pre-release test build - use at your own risk - do not use for mining or merchant applications\";\n        strGUI = _(\"This is a pre-release test build - use at your own risk - do not use for mining or merchant applications\");\n    }\n\n    if (GetBoolArg(\"-testsafemode\", DEFAULT_TESTSAFEMODE))\n        strStatusBar = strRPC = strGUI = \"testsafemode enabled\";\n\n    // Misc warnings like out of disk space and clock is wrong\n    if (strMiscWarning != \"\")\n    {\n        strStatusBar = strMiscWarning;\n        strGUI += (strGUI.empty() ? \"\" : uiAlertSeperator) + strMiscWarning;\n    }\n\n    if (fLargeWorkForkFound)\n    {\n        strStatusBar = strRPC = \"Warning: The network appears to be forked, please seek assistance.\";\n        strGUI += (strGUI.empty() ? \"\" : uiAlertSeperator) + _(\"Warning: The network appears to be forked, please seek assistance.\");\n    }\n    else if (fLargeWorkInvalidChainFound)\n    {\n        strStatusBar = strRPC = \"Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.\";\n        strGUI += (strGUI.empty() ? \"\" : uiAlertSeperator) + _(\"Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.\");\n    }\n\n\n    // Alerts\n    {\n        LOCK(cs_mapAlerts);\n        for (const auto& [alertHash, alert] : mapAlerts)\n        {\n            (unused) alertHash;\n            if (alert.AppliesToMe() )\n            {\n                strStatusBar = strGUI = strRPC = alert.strStatusBar;\n            }\n        }\n    }\n\n    if (strFor == \"gui\")\n        return strGUI;\n    else if (strFor == \"statusbar\")\n        return strStatusBar;\n    else if (strFor == \"rpc\")\n        return strRPC;\n    assert(!\"GetWarnings(): invalid parameter\");\n    return \"error\";\n}\n"
  },
  {
    "path": "src/warnings.h",
    "content": "// Copyright (c) 2009-2010 Satoshi Nakamoto\n// Copyright (c) 2009-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef WARNINGS_H\n#define WARNINGS_H\n\n#include <stdlib.h>\n#include <string>\n\nvoid SetMiscWarning(const std::string& strWarning);\nvoid SetfLargeWorkForkFound(bool flag);\nbool GetfLargeWorkForkFound();\nvoid SetfLargeWorkInvalidChainFound(bool flag);\nbool GetfLargeWorkInvalidChainFound();\n/** Format a string that describes several potential problems detected by the core.\n * strFor can have three values:\n * - \"rpc\": get critical warnings, which should put the client in safe mode if non-empty\n * - \"statusbar\": get all warnings\n * - \"gui\": get all warnings, translated (where possible) for GUI\n * This function only returns the highest priority warning of the set selected by strFor.\n */\nstd::string GetWarnings(const std::string& strFor);\n\nstatic const bool DEFAULT_TESTSAFEMODE = false;\n\n#endif\n"
  },
  {
    "path": "src/witnessutil.cpp",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"wallet/wallettx.h\"\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#endif\n#include \"timedata.h\"\n#include \"util.h\"\n#include \"consensus/validation.h\"\n#include \"validation/validation.h\"\n#include \"validation/versionbitsvalidation.h\"\n#include \"validation/witnessvalidation.h\"\n#include \"versionbits.h\"\n#include \"net_processing.h\"\n#include \"txdb.h\"\n\n#include \"primitives/transaction.h\"\n#include <LRUCache/LRUCache11.hpp>\n\n\n#ifdef ENABLE_WALLET\nstatic bool alreadyInRescan = false;\nvoid rescanThread()\n{\n    if (alreadyInRescan)\n        return;\n    alreadyInRescan = true;\n    pactiveWallet->ScanForWalletTransactions(chainActive.Genesis(), true);\n    alreadyInRescan = false;\n}\n\n//fixme: (2.2) (UNITY) (HIGH) - While this works as a temporary way of achieving things it is far from ideal\n//Rearchitecture this into something more appropriate.\n//When we perform a link we need to ensure that the wallet that empties our transaction broadcasts\n//As we reset all the networking as part of the rescan this doesn't always happen \"naturally\" like it should\n//And the 'trickle' transaction code further works against us etc.\n//So for now we use this heavy handed approach of forcefully rebroadcasting the transactions every five seconds for 30 seconds which is enough to ensure the transactions propagate\nvoid broadcastTransactionsThread()\n{\n    for (int i=0; i < 6; ++i)\n    {\n        MilliSleep(5000);\n        // Resend any inventory that might have been pending send before we cleared all the connections.\n        for (CWallet* pwallet : vpwallets) {\n            LOCK2(cs_main, pwallet->cs_wallet);\n            pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());\n        }\n    }\n}\n\nvoid ResetSPVStartRescanThread()\n{\n    // reset SPV first\n    {\n        LOCK(cs_main);\n\n        // disconnect all nodes to avoid problems with inconsistent block index state\n        g_connman->ForEachNode([](CNode* node)\n        {\n            g_connman->DisconnectNode(node->GetId());\n        });\n\n        // clear old spv requests (and also avoid invalid block index access)\n        CancelAllPriorityDownloads();\n\n        // reset wallet spv, note that this will also\n        // 1) restart spv and partial sync\n        // 2) clear the partial sync state underneath (in most cases, as likely\n        // too much of the index will have been pruned)\n        if (fSPV) {\n            for (CWallet* pwallet : vpwallets) {\n                LOCK(pwallet->cs_wallet);\n                pwallet->ResetSPV();\n            }\n        }\n\n        std::thread(broadcastTransactionsThread).detach();\n    }\n\n    // second do the standard rescan thread in fullsync\n    if (isFullSyncMode()) {\n        std::thread(rescanThread).detach();\n    }\n}\n\nstd::string StringFromSeedType(CHDSeed* seed)\n{\n    switch(seed->m_type)\n    {\n        case CHDSeed::CHDSeed::BIP32:\n            return \"BIP32\";\n        case CHDSeed::CHDSeed::BIP32Legacy:\n            return \"BIP32 Legacy\";\n        case CHDSeed::CHDSeed::BIP44:\n            return \"BIP44\";\n        case CHDSeed::CHDSeed::BIP44External:\n            return \"BIP44 External\";\n        case CHDSeed::CHDSeed::BIP44NoHardening:\n            return \"BIP44 No Hardening\";\n    }\n    return \"unknown\";\n}\n\nCHDSeed::SeedType SeedTypeFromString(std::string type)\n{\n    if (type == \"BIP32\")\n        return CHDSeed::CHDSeed::BIP32;\n    else if (type == \"BIP32 Legacy\" || type == \"Bip32L\")\n        return CHDSeed::CHDSeed::BIP32Legacy;\n    else if (type == \"BIP44\")\n        return CHDSeed::CHDSeed::BIP44;\n    else if (type == \"BIP44 External\" || type == \"BIP44E\")\n        return CHDSeed::CHDSeed::BIP44External;\n    else if (type == \"BIP44 No Hardening\" || type == \"BIP44NH\")\n        return CHDSeed::CHDSeed::BIP44NoHardening;\n\n    throw std::runtime_error(\"Invalid seed type\");\n\n    return CHDSeed::CHDSeed::BIP44;\n}\n#endif\n\nbool IsPow2Phase2Active(const CBlockIndex* pindexPrev)\n{\n    if (pindexPrev && ((uint64_t)pindexPrev->nHeight >= Params().GetConsensus().pow2Phase2FirstBlockHeight))\n            return true;\n    \n    return false;\n}\n\nbool IsPow2Phase3Active(uint64_t nHeight)\n{\n    if (nHeight >= Params().GetConsensus().pow2Phase3FirstBlockHeight)\n        return true;\n    return false;\n}\n\nbool IsPow2Phase4Active(const CBlockIndex* pindexPrev)\n{\n    if (pindexPrev && ((uint64_t)pindexPrev->nHeight >= Params().GetConsensus().pow2Phase4FirstBlockHeight))\n    {\n        return true;\n    }\n    return false;\n}\n\n\n// Phase 5 becomes active after all 'backwards compatible' witness addresses have been flushed from the system.\n// At this point 'backwards compatible' witness addresses in the chain are treated simply as anyone can spend transactions (as they have all been spent this is fine) and old witness data is discarded.\nbool IsPow2Phase5Active(uint64_t nHeight)\n{\n    if (nHeight >= Params().GetConsensus().pow2Phase5FirstBlockHeight)\n        return true;\n    return false;\n}\n\nbool IsPow2Phase5Active(const CBlockIndex* pIndex, const CChainParams& params, CChain& chain, CCoinsViewCache* viewOverride)\n{\n    if (pIndex)\n    {\n        return IsPow2Phase5Active((uint64_t)pIndex->nHeight);\n    }\n    return false;\n}\n\nbool IsPow2WitnessingActive(uint64_t nHeight)\n{\n    // If phase 3, 4 or 5 is active then witnessing is active - we only need to check phase 3 to be sure as if 4 or 5 is active for a block 3 will be as well.\n    return IsPow2Phase3Active(nHeight);\n}\n\nint GetPoW2Phase(const CBlockIndex* pindexPrev)\n{\n    int nRet = 1;\n    if (IsPow2Phase2Active(pindexPrev))\n    {\n        nRet = 2;\n        if (IsPow2Phase3Active(pindexPrev?pindexPrev->nHeight:0))\n        {\n            nRet = 3;\n            if (IsPow2Phase4Active(pindexPrev))\n                nRet = 4;\n            //NB! We don't call IsPow2Phase5Active here as it can lead to infinite recursion in some cases.\n        }\n    }\n    return nRet;\n}\n\n//NB! nAmount is already in internal monetary format (8 zeros) form when entering this function - i.e. the nAmount for 22 NLG is '2200000000' and not '22'\nint64_t GetPoW2RawWeightForAmount(int64_t nAmount, int64_t nHeight, int64_t nLockLengthInBlocks)\n{\n    (unused) nHeight;\n    // We rebase the entire formula to to match internal monetary format (8 zeros), so that we can work with fixed point precision.\n    // We rebase back to 10 at the end for the final weight.\n    static const arith_uint256 base = arith_uint256(COIN);\n    static const arith_uint256 base3 = base*base*base;\n    static const arith_uint256 BlocksPerYear = arith_uint256(365 * 576);\n    #define BASE(x) (arith_uint256(x)*base)\n    arith_uint256 Quantity = arith_uint256(nAmount);\n    arith_uint256 nWeight = ((BASE(Quantity)) + ((Quantity*Quantity) / arith_uint256(100000))) * (BASE(1) + (BASE(nLockLengthInBlocks) / BlocksPerYear));\n    #undef BASE\n    nWeight /= base3;\n    return nWeight.GetLow64();\n}\n\n\nuint64_t GetPoW2LockLengthInBlocksFromOutput(const CTxOut& out, uint64_t txBlockNumber, uint64_t& nFromBlockOut, uint64_t& nUntilBlockOut)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        nFromBlockOut = out.output.witnessDetails.lockFromBlock == 0 ? txBlockNumber : out.output.witnessDetails.lockFromBlock;\n        nUntilBlockOut = out.output.witnessDetails.lockUntilBlock;\n    }\n    else if (out.GetType() <= CTxOutType::ScriptLegacyOutput)\n    {\n        CTxOutPoW2Witness witnessDetails;\n        out.output.scriptPubKey.ExtractPoW2WitnessFromScript(witnessDetails);\n        nFromBlockOut =  witnessDetails.lockFromBlock == 0 ? txBlockNumber : witnessDetails.lockFromBlock;\n        nUntilBlockOut = witnessDetails.lockUntilBlock;\n    }\n    else\n    {\n        assert(0);\n    }\n    return (nUntilBlockOut - nFromBlockOut)+1;\n}\n\nuint64_t GetPoW2RemainingLockLengthInBlocks(uint64_t lockUntilBlock, uint64_t tipHeight)\n{\n    return (lockUntilBlock < tipHeight) ? 0 : (lockUntilBlock - tipHeight) + 1;\n}\n\ntypedef std::pair<int64_t, int64_t> NumAndWeight;\ntypedef lru11::Cache<uint256, NumAndWeight, lru11::NullLock, std::unordered_map<uint256, typename std::list<lru11::KeyValuePair<uint256, NumAndWeight>>::iterator, BlockHasher>> BlockWeightCache;\nBlockWeightCache networkWeightCache(800,100);\nbool GetPow2NetworkWeight(const CBlockIndex* pIndex, const CChainParams& chainparams, int64_t& nNumWitnessAddresses, int64_t& nTotalWeight, CChain& chain, CCoinsViewCache* viewOverride)\n{\n    DO_BENCHMARK(\"WIT: GetPow2NetworkWeight\", BCLog::BENCH|BCLog::WITNESS);\n\n    const auto& blockHash = pIndex->GetBlockHashPoW2();\n    if (networkWeightCache.contains(blockHash))\n    {\n        const auto& cachePair = networkWeightCache.get(blockHash);\n        nNumWitnessAddresses = cachePair.first;\n        nTotalWeight = cachePair.second;\n        return true;\n    }\n\n    {\n        #ifdef ENABLE_WALLET\n        LOCK2(cs_main, pactiveWallet?&pactiveWallet->cs_wallet:NULL);\n        #else\n        LOCK(cs_main);\n        #endif\n\n        std::map<COutPoint, Coin> allWitnessCoins;\n        if (!getAllUnspentWitnessCoins(chain, chainparams, pIndex, allWitnessCoins, nullptr, viewOverride))\n            return error(\"GetPow2NetworkWeight: Failed to enumerate all unspent witness coins\");\n\n        nNumWitnessAddresses = 0;\n        nTotalWeight = 0;\n\n        for (auto iter : allWitnessCoins)\n        {\n            if (pIndex == nullptr || iter.second.nHeight <= pIndex->nHeight)\n            {\n                CTxOut output = iter.second.out;\n\n                uint64_t nUnused1, nUnused2;\n                nTotalWeight += GetPoW2RawWeightForAmount(output.nValue, pIndex->nHeight, GetPoW2LockLengthInBlocksFromOutput(output, iter.second.nHeight, nUnused1, nUnused2));\n                ++nNumWitnessAddresses;\n            }\n        }\n    }\n    networkWeightCache.insert(blockHash, std::pair(nNumWitnessAddresses, nTotalWeight));\n    return true;\n}\n\n\n\nCBlockIndex* GetPoWBlockForPoSBlock(const CBlockIndex* pIndex)\n{\n    DO_BENCHMARK(\"WIT: GetPoWBlockForPoSBlock\", BCLog::BENCH|BCLog::WITNESS);\n\n    AssertLockHeld(cs_main); // Required for ReadBlockFromDisk.\n\n    uint256 powHash = pIndex->GetBlockHashLegacy();\n    if (!mapBlockIndex.count(powHash))\n    {\n        std::shared_ptr<CBlock> pBlockPoW(new CBlock);\n        if (!ReadBlockFromDisk(*pBlockPoW, pIndex, Params()))\n            return nullptr;\n\n        // Strip any witness information from the block we have been given to get back to the raw PoW block on which it was based.\n        for (unsigned int i = 1; i < pBlockPoW->vtx.size(); i++)\n        {\n            if (pBlockPoW->vtx[i]->IsCoinBase() && pBlockPoW->vtx[i]->IsPoW2WitnessCoinBase())\n            {\n                while (pBlockPoW->vtx.size() > i)\n                {\n                    pBlockPoW->vtx.pop_back();\n                }\n                break;\n            }\n        }\n        pBlockPoW->nVersionPoW2Witness = 0;\n        pBlockPoW->nTimePoW2Witness = 0;\n        pBlockPoW->hashMerkleRootPoW2Witness = uint256();\n        pBlockPoW->witnessHeaderPoW2Sig.clear();\n        pBlockPoW->witnessUTXODelta.clear();\n\n        if (!ProcessNewBlock(Params(), pBlockPoW, true, nullptr, false, true))\n            return nullptr;\n    }\n    return mapBlockIndex[powHash];\n}\n\nint GetPow2ValidationCloneHeight(CChain& chain, const CBlockIndex* pIndex, int nMargin)\n{\n    if (pIndex->nHeight <= 10)\n        return 0;\n\n    const CBlockIndex* pprevFork = chainActive.FindFork(pIndex);\n    return (pprevFork->nHeight > nMargin ? pprevFork->nHeight - nMargin : 0);\n}\n\nbool IsPartialSyncActive()\n{\n    return partialChain.Height() >= partialChain.HeightOffset();\n}\n\nbool IsPartialNearPresent(enum BlockStatus nUpTo)\n{\n    if (!IsPartialSyncActive())\n        return false;\n\n    CBlockIndex* index = partialChain.Tip();\n    int64_t farBack = GetAdjustedTime() - Params().GetConsensus().nPowTargetSpacing * 20;\n    while (   index\n           && index->nHeight >= partialChain.HeightOffset()\n           && (index->GetBlockTime() <= farBack || !index->IsPartialValid(nUpTo)))\n    {\n        index = index->pprev;\n    }\n\n    // index && index->nHeight >= partialChain.HeightOffset() => index->GetBlockTime() > farBack && index->IsPartialValid(nUpTo)\n    return index && index->nHeight >= partialChain.HeightOffset();\n}\n\nbool IsChainNearPresent()\n{\n    CBlockIndex* index = chainActive.Tip();\n    if (index == nullptr)\n        return false;\n\n    int64_t farBack = GetAdjustedTime() - Params().GetConsensus().nPowTargetSpacing * 20;\n\n    return index->GetBlockTime() > farBack;\n}\n\nint DailyBlocksTarget()\n{\n    return (24 * 60 * 60) / Params().GetConsensus().nPowTargetSpacing;\n}\n\nuint64_t MinimumWitnessLockLength()\n{\n    if (Params().IsOfficialTestnetV1())\n    {\n        return gMinimumWitnessLockDays * gRefactorDailyBlocksUsage;\n    }\n    else if (Params().IsTestnet())\n    {\n        return 50;\n    }\n    else\n    {\n        return gMinimumWitnessLockDays * DailyBlocksTarget();\n    }\n}\n\nuint64_t MaximumWitnessLockLength()\n{\n    if (Params().IsTestnet())\n    {\n        return gMaximumWitnessLockDays * gRefactorDailyBlocksUsage;\n    }\n    else\n    {\n        return gMaximumWitnessLockDays * DailyBlocksTarget();\n    }\n}\n\nstatic constexpr int recovery_birth_period = 7 * 24 * 3600; // one week\n\nint timeToBirthNumber(const int64_t time)\n{\n    // 0 for invalid time\n    if (time < Params().GenesisBlock().nTime)\n        return 0;\n\n    int periods = (time - Params().GenesisBlock().nTime) / recovery_birth_period;\n\n    return Base10ChecksumEncode(periods);\n}\n\nint64_t birthNumberToTime(int number)\n{\n    int periods;\n    if (!Base10ChecksumDecode(number, &periods))\n        return 0;\n\n    return Params().GenesisBlock().nTime + int64_t(periods) * recovery_birth_period;\n}\n"
  },
  {
    "path": "src/witnessutil.h",
    "content": "// Copyright (c) 2015-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#ifndef WITNESS_UTIL_H\n#define WITNESS_UTIL_H\n\n#include <string>\n#ifdef ENABLE_WALLET\n#include \"wallet/wallet.h\"\n#include \"wallet/account.h\"\n#endif\n#include \"script/standard.h\"\n#include \"chainparams.h\"\n#include \"chain.h\"\n#include \"coins.h\"\n\n#ifdef ENABLE_WALLET\nvoid ResetSPVStartRescanThread();\nstd::string StringFromSeedType(CHDSeed* seed);\nCHDSeed::SeedType SeedTypeFromString(std::string type);\n#endif\n\nclass CBlockIndex;\nbool IsPow2Phase2Active(const CBlockIndex* pindexPrev);\nbool IsPow2Phase3Active(uint64_t nHeight);\nbool IsPow2Phase4Active(const CBlockIndex* pindexPrev);\nbool IsPow2Phase5Active(const CBlockIndex* pindexPrev, const CChainParams& chainparams, CChain& chain, CCoinsViewCache* viewOverride=nullptr);\nbool IsPow2Phase5Active(uint64_t nHeight);\nbool IsPow2WitnessingActive(uint64_t nHeight);\nint GetPoW2Phase(const CBlockIndex* pindexPrev);\n\nbool GetPow2NetworkWeight(const CBlockIndex* pIndex, const CChainParams& chainparams, int64_t& nNumWitnessAddresses, int64_t& nTotalWeight, CChain& chain, CCoinsViewCache* viewOverride=nullptr);\n\nint64_t GetPoW2RawWeightForAmount(int64_t nAmount, int64_t nHeight, int64_t nLockLengthInBlocks);\n\n\n//! Calculate how many blocks a witness transaction is locked for from an output\n//! Always use this helper instead of attempting to calculate directly - to avoid off by 1 errors.\nuint64_t GetPoW2LockLengthInBlocksFromOutput(const CTxOut& out, uint64_t txBlockNumber, uint64_t& nFromBlockOut, uint64_t& nUntilBlockOut);\n\n//! Calculate how many blocks are left from `tipHeight` until a witness output unlocks, given inputs 'lockUntilBlock' and 'tipHeight'\n//! Though this is a relatively simple calculation, always use this helper instead of attempting to calculate directly - to avoid off by 1 errors.\nuint64_t GetPoW2RemainingLockLengthInBlocks(uint64_t lockUntilBlock, uint64_t tipHeight);\n\nCBlockIndex* GetPoWBlockForPoSBlock(const CBlockIndex* pIndex);\n\nint GetPow2ValidationCloneHeight(CChain& chain, const CBlockIndex* pIndex, int nMargin);\n\ninline bool IsPow2WitnessOutput(const CTxOut& out)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n        return true;\n    return false;\n}\n\ninline bool GetPow2WitnessOutput(const CTxOut& out, CTxOutPoW2Witness& witnessDetails)\n{\n    if (out.GetType() == CTxOutType::PoW2WitnessOutput)\n    {\n        witnessDetails = out.output.witnessDetails;\n        witnessDetails.nType = CTxOutType::PoW2WitnessOutput;\n        return true;\n    }\n    return false;\n}\n\ninline CTxOutPoW2Witness GetPoW2WitnessOutputFromWitnessDestination(const CPoW2WitnessDestination& fromDest)\n{\n    CTxOutPoW2Witness txout;\n    txout.spendingKeyID = fromDest.spendingKey;\n    txout.witnessKeyID = fromDest.witnessKey;\n    txout.lockFromBlock = fromDest.lockFromBlock;\n    txout.lockUntilBlock = fromDest.lockUntilBlock;\n    txout.failCount = fromDest.failCount;\n    txout.actionNonce = fromDest.actionNonce;\n    return txout;\n}\n\ninline bool IsPoW2WitnessLocked(const CTxOutPoW2Witness& witnessDetails, uint64_t nTipHeight)\n{\n    if (witnessDetails.lockUntilBlock >= nTipHeight)\n        return true;\n    return false;\n}\n\ninline bool IsPoW2WitnessLocked(const CTxOut& out, uint64_t nTipHeight)\n{\n    CTxOutPoW2Witness witnessDetails;\n    if (!GetPow2WitnessOutput(out, witnessDetails))\n        return false;\n    return IsPoW2WitnessLocked(witnessDetails, nTipHeight);\n}\n\n/**\n * Partial (header) sync is considered active if the partial chain has been populatd with at least one block.\n * Requires cs_main\n */\nbool IsPartialSyncActive();\n\n/**\n  * Check if the most recent block in the partial tree is near the present (if it exists)\n  * Requires cs_main\n  */\nbool IsPartialNearPresent(enum BlockStatus nUpTo = BLOCK_PARTIAL_TREE);\n\n/**\n  * Check if the most recent block in the full chainActive is near the present\n  * Requires cs_main\n  */\nbool IsChainNearPresent();\n\nint DailyBlocksTarget();\nuint64_t MinimumWitnessLockLength();\nuint64_t MaximumWitnessLockLength();\n\nint timeToBirthNumber(const int64_t time);\n\nint64_t birthNumberToTime(int number);\n\n#endif\n"
  },
  {
    "path": "src/zmq/zmqabstractnotifier.cpp",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"zmqabstractnotifier.h\"\n#include \"util.h\"\n\n\nCZMQAbstractNotifier::~CZMQAbstractNotifier()\n{\n    assert(!psocket);\n}\n\nbool CZMQAbstractNotifier::NotifyBlock(const CBlockIndex* /*CBlockIndex*/)\n{\n    return true;\n}\n\nbool CZMQAbstractNotifier::NotifyStalledWitness(const CBlockIndex* /*pDelayedIndex*/, uint64_t /*nSecondsDelayed*/)\n{\n    return true;\n}\n\nbool CZMQAbstractNotifier::NotifyTransaction(const CTransaction& /*transaction*/)\n{\n    return true;\n}\n\n#ifdef ENABLE_WALLET\nbool CZMQAbstractNotifier::NotifyWalletTransaction(CWallet* const pWallet, const CWalletTx& /*wtx*/)\n{\n    return true;\n}\n#endif\n"
  },
  {
    "path": "src/zmq/zmqabstractnotifier.h",
    "content": "// Copyright (c) 2015 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ZMQ_ZMQABSTRACTNOTIFIER_H\n#define ZMQ_ZMQABSTRACTNOTIFIER_H\n\n#include \"zmqconfig.h\"\n#ifdef ENABLE_WALLET\n#include <wallet/wallet.h>\n#endif\n\nclass CBlockIndex;\nclass CZMQAbstractNotifier;\n\ntypedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();\n\nclass CZMQAbstractNotifier\n{\npublic:\n    CZMQAbstractNotifier() : psocket(0) { }\n    virtual ~CZMQAbstractNotifier();\n\n    template <typename T>\n    static CZMQAbstractNotifier* Create()\n    {\n        return new T();\n    }\n\n    std::string GetType() const { return type; }\n    void SetType(const std::string &t) { type = t; }\n    std::string GetAddress() const { return address; }\n    void SetAddress(const std::string &a) { address = a; }\n\n    virtual bool Initialize(void *pcontext) = 0;\n    virtual void Shutdown() = 0;\n\n    virtual bool NotifyBlock(const CBlockIndex *pindex);\n    virtual bool NotifyStalledWitness(const CBlockIndex* pDelayedIndex, uint64_t nSecondsDelayed);\n    virtual bool NotifyTransaction(const CTransaction &transaction);\n    #ifdef ENABLE_WALLET\n    virtual bool NotifyWalletTransaction(CWallet* const pWallet, const CWalletTx &wtx);\n    #endif\n\nprotected:\n    void *psocket;\n    std::string type;\n    std::string address;\n};\n\n#endif // ZMQ_ZMQABSTRACTNOTIFIER_H\n"
  },
  {
    "path": "src/zmq/zmqconfig.h",
    "content": "// Copyright (c) 2014 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ZMQ_ZMQCONFIG_H\n#define ZMQ_ZMQCONFIG_H\n\n#if defined(HAVE_CONFIG_H)\n#include \"config/build-config.h\"\n#endif\n\n#include <stdarg.h>\n#include <string>\n\n#if ENABLE_ZMQ\n#include <zmq.h>\n#endif\n\n#include \"primitives/block.h\"\n#include \"primitives/transaction.h\"\n\nvoid zmqError(const char *str);\n\n#endif // ZMQ_ZMQCONFIG_H\n"
  },
  {
    "path": "src/zmq/zmqnotificationinterface.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#include \"zmqnotificationinterface.h\"\n#include \"zmqpublishnotifier.h\"\n\n#include <zmq.h>\n\n#include \"version.h\"\n#include \"validation/validation.h\"\n#include \"streams.h\"\n#include \"util.h\"\n\nvoid zmqError(const char *str)\n{\n    LogPrint(BCLog::ZMQ, \"zmq: Error: %s, errno=%s\\n\", str, zmq_strerror(errno));\n}\n\nCZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL)\n{\n}\n\nCZMQNotificationInterface::~CZMQNotificationInterface()\n{\n    Shutdown();\n\n    for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)\n    {\n        delete *i;\n    }\n}\n\nCZMQNotificationInterface* CZMQNotificationInterface::Create()\n{\n    CZMQNotificationInterface* notificationInterface = NULL;\n    std::map<std::string, CZMQNotifierFactory> factories;\n    std::list<CZMQAbstractNotifier*> notifiers;\n\n    factories[\"pubhashblock\"] = CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;\n    factories[\"pubhashtx\"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;\n    factories[\"pubrawblock\"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;\n    factories[\"pubrawtx\"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;\n    factories[\"pubwallettx\"] = CZMQAbstractNotifier::Create<CZMQPublishWalletTransactionNotifier>;\n    factories[\"pubstalledwitness\"] = CZMQAbstractNotifier::Create<CZMQPublishStalledWitnessNotifier>;\n\n    for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)\n    {\n        std::string arg(\"-zmq\" + i->first);\n        if (IsArgSet(arg))\n        {\n            CZMQNotifierFactory factory = i->second;\n            std::string address = GetArg(arg, \"\");\n            CZMQAbstractNotifier *notifier = factory();\n            notifier->SetType(i->first);\n            notifier->SetAddress(address);\n            notifiers.push_back(notifier);\n        }\n    }\n\n    if (!notifiers.empty())\n    {\n        notificationInterface = new CZMQNotificationInterface();\n        notificationInterface->notifiers = notifiers;\n\n        if (!notificationInterface->Initialize())\n        {\n            delete notificationInterface;\n            notificationInterface = NULL;\n        }\n    }\n\n    return notificationInterface;\n}\n\n// Called at startup to conditionally set up ZMQ socket(s)\nbool CZMQNotificationInterface::Initialize()\n{\n    LogPrint(BCLog::ZMQ, \"zmq: Initialize notification interface\\n\");\n    assert(!pcontext);\n\n    pcontext = zmq_init(1);\n\n    if (!pcontext)\n    {\n        zmqError(\"Unable to initialize context\");\n        return false;\n    }\n\n    std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin();\n    for (; i!=notifiers.end(); ++i)\n    {\n        CZMQAbstractNotifier *notifier = *i;\n        if (notifier->Initialize(pcontext))\n        {\n            LogPrint(BCLog::ZMQ, \"  Notifier %s ready (address = %s)\\n\", notifier->GetType(), notifier->GetAddress());\n        }\n        else\n        {\n            LogPrint(BCLog::ZMQ, \"  Notifier %s failed (address = %s)\\n\", notifier->GetType(), notifier->GetAddress());\n            break;\n        }\n    }\n\n    if (i!=notifiers.end())\n    {\n        return false;\n    }\n\n    return true;\n}\n\n// Called during shutdown sequence\nvoid CZMQNotificationInterface::Shutdown()\n{\n    LogPrint(BCLog::ZMQ, \"zmq: Shutdown notification interface\\n\");\n    if (pcontext)\n    {\n        for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)\n        {\n            CZMQAbstractNotifier *notifier = *i;\n            LogPrint(BCLog::ZMQ, \"   Shutdown notifier %s at %s\\n\", notifier->GetType(), notifier->GetAddress());\n            notifier->Shutdown();\n        }\n        zmq_ctx_destroy(pcontext);\n\n        pcontext = 0;\n    }\n}\n\nvoid CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)\n{\n    if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones\n        return;\n\n    for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )\n    {\n        CZMQAbstractNotifier *notifier = *i;\n        if (notifier->NotifyBlock(pindexNew))\n        {\n            i++;\n        }\n        else\n        {\n            notifier->Shutdown();\n            i = notifiers.erase(i);\n        }\n    }\n}\n\nvoid CZMQNotificationInterface::StalledWitness(const CBlockIndex* pBlock, uint64_t nSeconds)\n{\n    for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )\n    {\n        CZMQAbstractNotifier *notifier = *i;\n        if (notifier->NotifyStalledWitness(pBlock, nSeconds))\n        {\n            i++;\n        }\n        else\n        {\n            notifier->Shutdown();\n            i = notifiers.erase(i);\n        }\n    }\n}\n\nvoid CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx)\n{\n    // Used by BlockConnected and BlockDisconnected as well, because they're\n    // all the same external callback.\n    const CTransaction& tx = *ptx;\n\n    for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )\n    {\n        CZMQAbstractNotifier *notifier = *i;\n        if (notifier->NotifyTransaction(tx))\n        {\n            i++;\n        }\n        else\n        {\n            notifier->Shutdown();\n            i = notifiers.erase(i);\n        }\n    }\n}\n\n#ifdef ENABLE_WALLET\nvoid CZMQNotificationInterface::WalletTransactionAdded(CWallet* const pWallet, const CWalletTx& wtx)\n{\n    for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )\n    {\n        CZMQAbstractNotifier *notifier = *i;\n        if (notifier->NotifyWalletTransaction(pWallet, wtx))\n        {\n            i++;\n        }\n        else\n        {\n            notifier->Shutdown();\n            i = notifiers.erase(i);\n        }\n    }\n}\n#endif\n\nvoid CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted)\n{\n    for (const CTransactionRef& ptx : pblock->vtx) {\n        // Do a normal notify for each transaction added in the block\n        TransactionAddedToMempool(ptx);\n    }\n}\n\nvoid CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock)\n{\n    for (const CTransactionRef& ptx : pblock->vtx) {\n        // Do a normal notify for each transaction removed in block disconnection\n        TransactionAddedToMempool(ptx);\n    }\n}\n"
  },
  {
    "path": "src/zmq/zmqnotificationinterface.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ZMQ_ZMQNOTIFICATIONINTERFACE_H\n#define ZMQ_ZMQNOTIFICATIONINTERFACE_H\n\n#include \"validation/validationinterface.h\"\n#include <string>\n#include <map>\n#include <list>\n\nclass CBlockIndex;\nclass CZMQAbstractNotifier;\n\nclass CZMQNotificationInterface : public CValidationInterface\n{\npublic:\n    virtual ~CZMQNotificationInterface();\n\n    static CZMQNotificationInterface* Create();\n\nprotected:\n    bool Initialize();\n    void Shutdown();\n\n    // CValidationInterface\n    void StalledWitness(const CBlockIndex* pBlock, uint64_t nSeconds) override;\n    void TransactionAddedToMempool(const CTransactionRef& tx) override;\n    #ifdef ENABLE_WALLET\n    void WalletTransactionAdded(CWallet* const pWallet, const CWalletTx& wtx) override;\n    #endif\n    void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;\n    void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;\n    void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;\n\nprivate:\n    CZMQNotificationInterface();\n\n    void *pcontext;\n    std::list<CZMQAbstractNotifier*> notifiers;\n};\n\n#endif // ZMQ_ZMQNOTIFICATIONINTERFACE_H\n"
  },
  {
    "path": "src/zmq/zmqpublishnotifier.cpp",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n//\n// File contains modifications by: The Centure developers\n// All modifications:\n// Copyright (c) 2017-2022 The Centure developers\n// Authored by: Malcolm MacLeod (mmacleod@gmx.com)\n// Distributed under the GNU Lesser General Public License v3, see the accompanying\n// file COPYING\n\n#include \"chain.h\"\n#include \"chainparams.h\"\n#include \"streams.h\"\n#include \"zmqpublishnotifier.h\"\n#include \"validation/validation.h\"\n#include \"util.h\"\n#include \"rpc/server.h\"\n\n#include <zmq.h>\n\nstatic std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;\n\nstatic const char *MSG_HASHBLOCK = \"hashblock\";\nstatic const char *MSG_HASHTX    = \"hashtx\";\nstatic const char *MSG_RAWBLOCK  = \"rawblock\";\nstatic const char *MSG_RAWTX     = \"rawtx\";\nstatic const char *MSG_WALLETTX     = \"wallettx\";\nstatic const char *MSG_STALLEDWITNESS = \"stalledwitness\";\n\n// Internal function to send multipart message\nstatic int zmq_send_multipart(void *sock, const void* data, size_t size, ...)\n{\n    va_list args;\n    va_start(args, size);\n\n    while (1)\n    {\n        zmq_msg_t msg;\n\n        int rc = zmq_msg_init_size(&msg, size);\n        if (rc != 0)\n        {\n            zmqError(\"Unable to initialize ZMQ msg\");\n            va_end(args);\n            return -1;\n        }\n\n        void *buf = zmq_msg_data(&msg);\n        memcpy(buf, data, size);\n\n        data = va_arg(args, const void*);\n\n        rc = zmq_msg_send(&msg, sock, data ? ZMQ_SNDMORE : 0);\n        if (rc == -1)\n        {\n            zmqError(\"Unable to send ZMQ msg\");\n            zmq_msg_close(&msg);\n            va_end(args);\n            return -1;\n        }\n\n        zmq_msg_close(&msg);\n\n        if (!data)\n            break;\n\n        size = va_arg(args, size_t);\n    }\n    va_end(args);\n    return 0;\n}\n\nbool CZMQAbstractPublishNotifier::Initialize(void *pcontext)\n{\n    assert(!psocket);\n\n    // check if address is being used by other publish notifier\n    std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address);\n\n    if (i==mapPublishNotifiers.end())\n    {\n        psocket = zmq_socket(pcontext, ZMQ_PUB);\n        if (!psocket)\n        {\n            zmqError(\"Failed to create socket\");\n            return false;\n        }\n\n        int rc = zmq_bind(psocket, address.c_str());\n        if (rc!=0)\n        {\n            zmqError(\"Failed to bind address\");\n            zmq_close(psocket);\n            return false;\n        }\n\n        // register this notifier for the address, so it can be reused for other publish notifier\n        mapPublishNotifiers.insert(std::pair(address, this));\n        return true;\n    }\n    else\n    {\n        LogPrint(BCLog::ZMQ, \"zmq: Reusing socket for address %s\\n\", address);\n\n        psocket = i->second->psocket;\n        mapPublishNotifiers.insert(std::pair(address, this));\n\n        return true;\n    }\n}\n\nvoid CZMQAbstractPublishNotifier::Shutdown()\n{\n    assert(psocket);\n\n    int count = mapPublishNotifiers.count(address);\n\n    // remove this notifier from the list of publishers using this address\n    typedef std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator iterator;\n    std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address);\n\n    for (iterator it = iterpair.first; it != iterpair.second; ++it)\n    {\n        if (it->second==this)\n        {\n            mapPublishNotifiers.erase(it);\n            break;\n        }\n    }\n\n    if (count == 1)\n    {\n        LogPrint(BCLog::ZMQ, \"Close socket at address %s\\n\", address);\n        int linger = 0;\n        zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));\n        zmq_close(psocket);\n    }\n\n    psocket = 0;\n}\n\nbool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)\n{\n    assert(psocket);\n\n    /* send three parts, command & data & a LE 4byte sequence number */\n    unsigned char msgseq[sizeof(uint32_t)];\n    WriteLE32(&msgseq[0], nSequence);\n    int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), (void*)0);\n    if (rc == -1)\n        return false;\n\n    /* increment memory only sequence number after sending */\n    nSequence++;\n\n    return true;\n}\n\nbool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)\n{\n    uint256 hash = pindex->GetBlockHashPoW2();\n    LogPrint(BCLog::ZMQ, \"zmq: Publish hashblock %s\\n\", hash.GetHex());\n    unsigned char data[32];\n    for (unsigned int i = 0; i < 32; i++)\n        data[31 - i] = hash.begin()[i];\n    return SendMessage(MSG_HASHBLOCK, data, 32);\n}\n\nbool CZMQPublishStalledWitnessNotifier::NotifyStalledWitness(const CBlockIndex* pDelayedIndex, uint64_t nSecondsDelayed)\n{\n    uint256 hash = pDelayedIndex->GetBlockHashPoW2();\n    LogPrint(BCLog::ZMQ, \"zmq: Publish stalled witness hashblock %s %d\\n\", hash.GetHex(), nSecondsDelayed);\n    unsigned char data[40];\n    for (unsigned int i = 0; i < 32; i++)\n        data[31 - i] = hash.begin()[i];\n    WriteLE64(&data[32], nSecondsDelayed);\n    return SendMessage(MSG_STALLEDWITNESS, data, 40);\n}\n\nbool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)\n{\n    uint256 hash = transaction.GetHash();\n    LogPrint(BCLog::ZMQ, \"zmq: Publish hashtx %s\\n\", hash.GetHex());\n    char data[32];\n    for (unsigned int i = 0; i < 32; i++)\n        data[31 - i] = hash.begin()[i];\n    return SendMessage(MSG_HASHTX, data, 32);\n}\n\nbool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)\n{\n    LogPrint(BCLog::ZMQ, \"zmq: Publish rawblock %s\\n\", pindex->GetBlockHashPoW2().GetHex());\n\n    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());\n    {\n        LOCK(cs_main);// cs_main required for ReadBlockFromDisk.\n        CBlock block;\n        if(!ReadBlockFromDisk(block, pindex, Params()))\n        {\n            zmqError(\"Can't read block from disk\");\n            return false;\n        }\n\n        ss << block;\n    }\n\n    return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());\n}\n\nbool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)\n{\n    uint256 hash = transaction.GetHash();\n    LogPrint(BCLog::ZMQ, \"zmq: Publish rawtx %s\\n\", hash.GetHex());\n    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());\n    ss << transaction;\n    return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());\n}\n\n#ifdef ENABLE_WALLET\nextern void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry);\nextern void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter);\nbool CZMQPublishWalletTransactionNotifier::NotifyWalletTransaction(CWallet* const pWallet_, const CWalletTx& wtx)\n{\n    uint256 hash = wtx.GetHash();\n    LogPrint(BCLog::ZMQ, \"zmq: Publish wallettx %s\\n\", hash.GetHex());\n          \n    UniValue entry(UniValue::VOBJ);\n    WalletTxToJSON(wtx, entry);\n    UniValue details(UniValue::VARR);\n    ListTransactions(pWallet_, wtx, \"*\", 0, false, details, ISMINE_SPENDABLE);\n    entry.pushKV(\"details\", details);\n            \n    std::string transactionJSON = entry.write();\n    return SendMessage(MSG_WALLETTX, &(*transactionJSON.begin()), transactionJSON.size());\n}\n#endif\n"
  },
  {
    "path": "src/zmq/zmqpublishnotifier.h",
    "content": "// Copyright (c) 2015-2016 The Bitcoin Core developers\n// Distributed under the MIT software license, see the accompanying\n// file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#ifndef ZMQ_ZMQPUBLISHNOTIFIER_H\n#define ZMQ_ZMQPUBLISHNOTIFIER_H\n\n#include \"zmqabstractnotifier.h\"\n\nclass CBlockIndex;\n\nclass CZMQAbstractPublishNotifier : public CZMQAbstractNotifier\n{\nprivate:\n    uint32_t nSequence; //!< upcounting per message sequence number\n\npublic:\n\n    /* send zmq multipart message\n       parts:\n          * command\n          * data\n          * message sequence number\n    */\n    bool SendMessage(const char *command, const void* data, size_t size);\n\n    bool Initialize(void *pcontext);\n    void Shutdown();\n};\n\nclass CZMQPublishHashBlockNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyBlock(const CBlockIndex *pindex);\n};\n\nclass CZMQPublishStalledWitnessNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyStalledWitness(const CBlockIndex* pDelayedIndex, uint64_t nSecondsDelayed) override;\n};\n\nclass CZMQPublishHashTransactionNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyTransaction(const CTransaction &transaction);\n};\n\nclass CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyBlock(const CBlockIndex *pindex);\n};\n\nclass CZMQPublishRawTransactionNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyTransaction(const CTransaction &transaction);\n};\n\n#ifdef ENABLE_WALLET\nclass CZMQPublishWalletTransactionNotifier : public CZMQAbstractPublishNotifier\n{\npublic:\n    bool NotifyWalletTransaction(CWallet* const pWallet, const CWalletTx &wtx);\n};\n#endif\n\n#endif // ZMQ_ZMQPUBLISHNOTIFIER_H\n"
  },
  {
    "path": "technical_documentation/accelerated_testnet.md",
    "content": "# Accelerated testnet\n\nMunt implements a unique \"accelerated testnet\" system, that is used extensively by the developers for testing.\nThe system allows for the easy creation/management of multiple testnets, with different block target paramaters and different hash types; and even the ability to switch between them at will.\n\nThis allows for easy setup of a custom testnet to test specific scenarios.\nTestnet paramaters are controlled by a unique 'testnet specifier' for each testnet. The code ensures that clients with different testnet paramaters will not interact with one another.\n\nAn example of such a specifier `-testnet=**C**1529510550:*10*` which can be broken down as follows\n\n- _C_ Use city hash as the hash function\n- _1529510550_ Use unix timestamp 1529510550 as the start date\n- _10_ Attempt to mine blocks every 10 seconds Block interval target\n\nCurrent testnet paramaters that are supported (more may be added in future)\nHash Function:\n\n- C City hash; use this for CPU friendly testing.\n- S Scrypt hash; use this for testing mining pools or other funcitonality that requires the same properties as mainnet.\n  Block target:\n- 1 Use this to de-activate block targetting; the testnet will allow you to simply mine blocks as fast as your CPU allows. This is good for testing scenarios that might take months in real world time in a matter of minutes instead.\n- 2 or higher Testnet will attempt to mine blocks at a frequency that matches your settings\n  Timestamp:\n- There is no specific restriction on the timestamp other than that it should be reasonably recent, just grab the current timestamp with `date +%s` or similar and use this.\n\n# Official testnet\n\nOf course for those who just want to test something on an existing testnet with lots of other users we have that as well, complete with nocks testbed integation.\nJust start with `-testnet=S1596003003:60 -addnode=gulden.devbak.net` to connect then head to our Slack to interact with other testnet users!\n\n# Start your own testnet\n\nTo create a new testnet simply create a new testnet specifier from the options above picking the ones that suit your need.\nYou can then pass it to the program:\n\n- `./Munt -testnet=C1529510552:5`\n\nOnce in the program open the debug window and type the following (which will limit mining to 3000 hashes a second and start mining on a single core):\n\n- `sethashlimit 3000`\n- `setgenerate true 1`\n\nCongratulations you have a testnet and are good for solo testing.\nFor multiuser testing just launch a second instance with the same `testnet=xxx` arguments and `-addnode=<youriphere>` and you can start testing.\n"
  },
  {
    "path": "technical_documentation/account_system.md",
    "content": "Account system\n======\n\nThe Munt wallets implement a hierarchical deterministic account system in which the keys of each account are physically partitioned from those of other accounts within the wallet. This allows for the seperation of funds with the guarantee that funds from different accounts will not unintentionally get mixed to pay one anothers fees, via shared change \nor other wallet shortcomings or bugs that are prevalent in other cryptocurrencies that do not use such a system.\n\nIn addition to this basic account system the wallets also support various advanced capabilities, amongst which are:\n* The ability to import/control multiple `seeds` (trees of accounts created from a phrase) within a single wallet\n* The ability to share a single account as a read only account with another wallet; with the other wallet being able to generate future addresses that match ours\n* The ability to share an entire seed as a read only seed with another wallet; with the other wallet being able to generate the same future accounts and addresses as ours\n* The ability to link an account in a read/write way with our mobile wallets \n\nThese capabilities allow for proper secure implementation of various services for Munt - e.g. by setting up a merchant or website with a read only seed they can generate and receive payments without any risk of the funds being compromised if the server is compromised (as it contains a read only key)\nFor more on the account system please view the RPC help.\n\n\nTODO: add more text here\n"
  },
  {
    "path": "technical_documentation/gui_development.md",
    "content": "Amongst various other frontends, Munt has an electron based frontend that sits on top of our unified backend.\nThis makes contributing toward the user interface more accessible to a wider audience of developers.\n\nTo get started tinkering with the electron frontend and/or contributing changes, these are the required steps:\n1. Install prerequisites yarn/npm/node/git\n2. Check out a copy of the repository using `git`\n3. Select an appropriate branch. For development purposes you should use the latest development branch\n4. Change into `src/frontend/electron_vue` folder\n5. Type `yarn` to install the depedencies\n6. Type `yarn libunity:copy` to fetch the latest unified backend plugin\n7. Type `yarn electron:serve` to launch the program\n\nNotes:\n* Development version runs in a different data directory (munt_dev) than your regular wallet\n* You can't/shouldn't run both versions simultaneously unless you change the ports of one of them \n\nTroubleshooting:\n* `error An unexpected error occurred: \"https://npm.fontawesome.com/@fortawesome%2ffontawesome-pro: authentication required\".\n` Unfortunately currently it is not possible to run without a license for fontawesome pro, which the developers do have for releases but that we cannot share the key of with end users.\nTo add your own license if you have one\n```\nnpm config set \"@fortawesome:registry\" \"https://npm.fontawesome.com/\"\nnpm config set \"//npm.fontawesome.com/:_authToken=YOURAUTHTOKENGOESHERE\"\n```\nWe are still looking into ways to allow users to run without this dependency for development, pull requests welcome.\n"
  },
  {
    "path": "technical_documentation/transaction_format.md",
    "content": "Version 1 transaction format\n======\nThe original Munt transaction format is not overly interesting, it is based on [the Bitcoin transaction format](https://en.bitcoin.it/wiki/Transaction) (before the introduction of \"SegWit\") which is well documented elsewhere so there is no need to go into detail on it here.\nFor our version 2.0 release we have implemented a completely new transaction format which replaces the original transaction format as well as fixing transaction malleability in a different way to \"SegWit\".\n\n\nVersion 2 transaction format\n======\nThe heart of the V1 transaction format is a powerful script system that allows for all sorts of interesting uses of a blockchain other than just plain money transfers.\nThis script system makes transactions very versatile and almost anything can be done with them even regular plain `address1` -> `address2` payments are implemented using a script.\n\nOn very many levels this is nice however with scaling being one of the key obstacles we face the following has become obvious:\n* The majority of payments are just plain `address1` -> `address2` payments with no need for fancy scripting capability\n* The scripting capability is adding overhead to these transactions\n* The transaction format is otherwise not as optimal as it could be\n\nAn important concept is that of \"Users should only pay for the features they actually use\". And so with this in mind we set out to upgrade the transaction format with the following objectives:\n* Users should only pay for the features they need\n* Should be as compact as possible\n* Should be as fast to process as possible\n* Should maintain the advanced scripting capabilities that the V1 format has.\n* Should be easy to extend in future for even more advanced functionality\n\n\nCheck back for more technical information, this documentation will be updated over the coming weeks.\n"
  },
  {
    "path": "test/README.md",
    "content": "This directory contains integration tests that test Munt-daemon and its\nutilities in their entirety. It does not contain unit tests, which\ncan be found in [/src/test](/src/test), [/src/wallet/test](/src/wallet/test),\netc.\n\nThis directory contains the following sets of tests:\n\n- [functional](/test/functional) which test the functionality of\nMunt-daemon by interacting with it through the RPC and P2P\ninterfaces.\n- [util](/test/util) which tests the Munt utilities, currently only\nMunt-tx.\n- [lint](/test/lint/) which perform various static analysis checks.\n\nThe util tests are run as part of `make check` target. The functional\ntests and lint scripts are run by the travis continuous build process whenever a pull\nrequest is opened. All sets of tests can also be run locally.\n\n# Running tests locally\n\nBefore tests can be run locally, Bitcoin Core must be built.  See the [building instructions](/doc#building) for help.\n\n\n### Functional tests\n\n#### Dependencies\n\nThe ZMQ functional test requires a python ZMQ library. To install it:\n\n- on Unix, run `sudo apt-get install python3-zmq`\n- on mac OS, run `pip3 install pyzmq`\n\n#### Running the tests\n\nIndividual tests can be run by directly calling the test script, e.g.:\n\n```\ntest/functional/feature_rbf.py\n```\n\nor can be run through the test_runner harness, eg:\n\n```\ntest/functional/test_runner.py feature_rbf.py\n```\n\nYou can run any combination (incl. duplicates) of tests by calling:\n\n```\ntest/functional/test_runner.py <testname1> <testname2> <testname3> ...\n```\n\nRun the regression test suite with:\n\n```\ntest/functional/test_runner.py\n```\n\nRun all possible tests with\n\n```\ntest/functional/test_runner.py --extended\n```\n\nBy default, up to 4 tests will be run in parallel by test_runner. To specify\nhow many jobs to run, append `--jobs=n`\n\nThe individual tests and the test_runner harness have many command-line\noptions. Run `test_runner.py -h` to see them all.\n\n#### Troubleshooting and debugging test failures\n\n##### Resource contention\n\nThe P2P and RPC ports used by the Munt-daemon nodes-under-test are chosen to make\nconflicts with other processes unlikely. However, if there is another Munt-daemon\nprocess running on the system (perhaps from a previous test which hasn't successfully\nkilled all its Munt-daemon nodes), then there may be a port conflict which will\ncause the test to fail. It is recommended that you run the tests on a system\nwhere no other Munt-daemon processes are running.\n\nOn linux, the test_framework will warn if there is another\nMunt-daemon process running when the tests are started.\n\nIf there are zombie Munt-daemon processes after test failure, you can kill them\nby running the following commands. **Note that these commands will kill all\nMunt-daemon processes running on the system, so should not be used if any non-test\nMunt-daemon processes are being run.**\n\n```bash\nkillall Munt-daemon\n```\n\nor\n\n```bash\npkill -9 Munt-daemon\n```\n\n\n##### Data directory cache\n\nA pre-mined blockchain with 200 blocks is generated the first time a\nfunctional test is run and is stored in test/cache. This speeds up\ntest startup times since new blockchains don't need to be generated for\neach test. However, the cache may get into a bad state, in which case\ntests will fail. If this happens, remove the cache directory (and make\nsure Munt-daemon processes are stopped as above):\n\n```bash\nrm -rf cache\nkillall Munt-daemon\n```\n\n##### Test logging\n\nThe tests contain logging at different levels (debug, info, warning, etc). By\ndefault:\n\n- when run through the test_runner harness, *all* logs are written to\n  `test_framework.log` and no logs are output to the console.\n- when run directly, *all* logs are written to `test_framework.log` and INFO\n  level and above are output to the console.\n- when run on Travis, no logs are output to the console. However, if a test\n  fails, the `test_framework.log` and Munt-daemon `debug.log`s will all be dumped\n  to the console to help troubleshooting.\n\nTo change the level of logs output to the console, use the `-l` command line\nargument.\n\n`test_framework.log` and Munt-daemon `debug.log`s can be combined into a single\naggregate log by running the `combine_logs.py` script. The output can be plain\ntext, colorized text or html. For example:\n\n```\ncombine_logs.py -c <test data directory> | less -r\n```\n\nwill pipe the colorized logs from the test into less.\n\nUse `--tracerpc` to trace out all the RPC calls and responses to the console. For\nsome tests (eg any that use `submitblock` to submit a full block over RPC),\nthis can result in a lot of screen output.\n\nBy default, the test data directory will be deleted after a successful run.\nUse `--nocleanup` to leave the test data directory intact. The test data\ndirectory is never deleted after a failed test.\n\n##### Attaching a debugger\n\nA python debugger can be attached to tests at any point. Just add the line:\n\n```py\nimport pdb; pdb.set_trace()\n```\n\nanywhere in the test. You will then be able to inspect variables, as well as\ncall methods that interact with the Munt-daemon nodes-under-test.\n\nIf further introspection of the Munt-daemon instances themselves becomes\nnecessary, this can be accomplished by first setting a pdb breakpoint\nat an appropriate location, running the test to that point, then using\n`gdb` to attach to the process and debug.\n\nFor instance, to attach to `self.node[1]` during a run:\n\n```bash\n2017-06-27 14:13:56.686000 TestFramework (INFO): Initializing test directory /tmp/user/1000/testo9vsdjo3\n```\n\nuse the directory path to get the pid from the pid file:\n\n```bash\ncat /tmp/user/1000/testo9vsdjo3/node1/regtest/Munt-daemon.pid\ngdb /home/example/Munt-daemon <pid>\n```\n\nNote: gdb attach step may require ptrace_scope to be modified, or `sudo` preceding the `gdb`.\nSee this link for considerations: https://www.kernel.org/doc/Documentation/security/Yama.txt\n\n##### Profiling\n\nAn easy way to profile node performance during functional tests is provided\nfor Linux platforms using `perf`.\n\nPerf will sample the running node and will generate profile data in the node's\ndatadir. The profile data can then be presented using `perf report` or a graphical\ntool like [hotspot](https://github.com/KDAB/hotspot).\n\nTo generate a profile during test suite runs, use the `--perf` flag.\n\nTo see render the output to text, run\n\n```sh\nperf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less\n```\n\nFor ways to generate more granular profiles, see the README in\n[test/functional](/test/functional).\n\n### Util tests\n\nUtil tests can be run locally by running `test/util/util-test.py`.\nUse the `-v` option for verbose output.\n\n### Lint tests\n\n#### Dependencies\n\nThe lint tests require codespell and flake8. To install: `pip3 install codespell flake8`.\n\n#### Running the tests\n\nIndividual tests can be run by directly calling the test script, e.g.:\n\n```\ntest/lint/lint-filenames.sh\n```\n\nYou can run all the shell-based lint tests by running:\n\n```\ntest/lint/lint-all.sh\n```\n\n# Writing functional tests\n\nYou are encouraged to write functional tests for new or existing features.\nFurther information about the functional test framework and individual\ntests is found in [test/functional](/test/functional).\n"
  },
  {
    "path": "test/config.ini.in",
    "content": "# Copyright (c) 2013-2016 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n# These environment variables are set by the build process and read by\n# test/functional/test_runner.py and test/util/util-test.py\n\n[environment]\nSRCDIR=@abs_top_srcdir@\nBUILDDIR=@abs_top_builddir@\nEXEEXT=@EXEEXT@\nRPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py\n\n[components]\n# Which components are enabled. These are commented out by `configure` if they were disabled when running config.\n@ENABLE_WALLET_TRUE@ENABLE_WALLET=true\n@USE_BDB_TRUE@USE_BDB=true\n@BUILD_UTILS_TRUE@ENABLE_CLI=true\n@BUILD_DAEMON_TRUE@ENABLE_DAEMON=true\n@ENABLE_FUZZ_TRUE@ENABLE_FUZZ=true\n@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true\n"
  },
  {
    "path": "test/functional/.gitignore",
    "content": "*.pyc\ncache\n"
  },
  {
    "path": "test/functional/README.md",
    "content": "# Functional tests\n\n### Writing Functional Tests\n\n#### Example test\n\nThe [example_test.py](example_test.py) is a heavily commented example of a test case that uses both\nthe RPC and P2P interfaces. If you are writing your first test, copy that file\nand modify to fit your needs.\n\n#### Coverage\n\nRunning `test_runner.py` with the `--coverage` argument tracks which RPCs are\ncalled by the tests and prints a report of uncovered RPCs in the summary. This\ncan be used (along with the `--extended` argument) to find out which RPCs we\ndon't have test cases for.\n\n#### Style guidelines\n\n- Where possible, try to adhere to [PEP-8 guidelines](https://www.python.org/dev/peps/pep-0008/)\n- Use a python linter like flake8 before submitting PRs to catch common style\n  nits (eg trailing whitespace, unused imports, etc)\n- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md).\n  Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version),\n  to prevent accidentally introducing modern syntax from an unsupported Python version.\n  The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).\n- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that\n  could lead to bugs and issues in the test code.\n- Avoid wildcard imports\n- Use a module-level docstring to describe what the test is testing, and how it\n  is testing it.\n- When subclassing the MuntTestFramwork, place overrides for the\n  `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of\n  the subclass, then locally-defined helper methods, then the `run_test()` method.\n- Use `'{}'.format(x)` for string formatting, not `'%s' % x`.\n\n#### Naming guidelines\n\n- Name the test `<area>_test.py`, where area can be one of the following:\n    - `feature` for tests for full features that aren't wallet/mining/mempool, eg `feature_rbf.py`\n    - `interface` for tests for other interfaces (REST, ZMQ, etc), eg `interface_rest.py`\n    - `mempool` for tests for mempool behaviour, eg `mempool_reorg.py`\n    - `mining` for tests for mining features, eg `mining_prioritisetransaction.py`\n    - `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py`\n    - `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py`\n    - `tool` for tests for tools, eg `tool_wallet.py`\n    - `wallet` for tests for wallet features, eg `wallet_keypool.py`\n- use an underscore to separate words\n    - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py`\n- Don't use the redundant word `test` in the name, eg `interface_zmq.py`, not `interface_zmq_test.py`\n\n#### General test-writing advice\n\n- Set `self.num_nodes` to the minimum number of nodes necessary for the test.\n  Having additional unrequired nodes adds to the execution time of the test as\n  well as memory/CPU/disk requirements (which is important when running tests in\n  parallel or on Travis).\n- Avoid stop-starting the nodes multiple times during the test if possible. A\n  stop-start takes several seconds, so doing it several times blows up the\n  runtime of the test.\n- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether\n  or not to use the cached data directories. The cached data directories\n  contain a 200-block pre-mined blockchain and wallets for four nodes. Each node\n  has 25 mature blocks (25x50=1250 BTC) in its wallet.\n- When calling RPCs with lots of arguments, consider using named keyword\n  arguments instead of positional arguments to make the intent of the call\n  clear to readers.\n- Many of the core test framework classes such as `CBlock` and `CTransaction`\n  don't allow new attributes to be added to their objects at runtime like\n  typical Python objects allow. This helps prevent unpredictable side effects\n  from typographical errors or usage of the objects outside of their intended\n  purpose.\n\n#### RPC and P2P definitions\n\nTest writers may find it helpful to refer to the definitions for the RPC and\nP2P messages. These can be found in the following source files:\n\n- `/src/rpc/*` for RPCs\n- `/src/wallet/rpc*` for wallet RPCs\n- `ProcessMessage()` in `/src/net_processing.cpp` for parsing P2P messages\n\n#### Using the P2P interface\n\n- `messages.py` contains all the definitions for objects that pass\nover the network (`CBlock`, `CTransaction`, etc, along with the network-level\nwrappers for them, `msg_block`, `msg_tx`, etc).\n\n- P2P tests have two threads. One thread handles all network communication\nwith the Munt-daemon(s) being tested in a callback-based event loop; the other\nimplements the test logic.\n\n- `P2PConnection` is the class used to connect to a Munt-daemon.  `P2PInterface`\ncontains the higher level logic for processing P2P payloads and connecting to\nthe Bitcoin Core node application logic. For custom behaviour, subclass the\nP2PInterface object and override the callback methods.\n\n- Can be used to write tests where specific P2P protocol behavior is tested.\nExamples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`.\n\n### test-framework modules\n\n#### [test_framework/authproxy.py](test_framework/authproxy.py)\nTaken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc).\n\n#### [test_framework/test_framework.py](test_framework/test_framework.py)\nBase class for functional tests.\n\n#### [test_framework/util.py](test_framework/util.py)\nGenerally useful functions.\n\n#### [test_framework/mininode.py](test_framework/mininode.py)\nBasic code to support P2P connectivity to a Munt-daemon.\n\n#### [test_framework/script.py](test_framework/script.py)\nUtilities for manipulating transaction scripts (originally from python-bitcoinlib)\n\n#### [test_framework/key.py](test_framework/key.py)\nWrapper around OpenSSL EC_Key (originally from python-bitcoinlib)\n\n#### [test_framework/bignum.py](test_framework/bignum.py)\nHelpers for script.py\n\n#### [test_framework/blocktools.py](test_framework/blocktools.py)\nHelper functions for creating blocks and transactions.\n\n### Benchmarking with perf\n\nAn easy way to profile node performance during functional tests is provided\nfor Linux platforms using `perf`.\n\nPerf will sample the running node and will generate profile data in the node's\ndatadir. The profile data can then be presented using `perf report` or a graphical\ntool like [hotspot](https://github.com/KDAB/hotspot).\n\nThere are two ways of invoking perf: one is to use the `--perf` flag when\nrunning tests, which will profile each node during the entire test run: perf\nbegins to profile when the node starts and ends when it shuts down. The other\nway is the use the `profile_with_perf` context manager, e.g.\n\n```python\nwith node.profile_with_perf(\"send-big-msgs\"):\n    # Perform activity on the node you're interested in profiling, e.g.:\n    for _ in range(10000):\n        node.p2p.send_message(some_large_message)\n```\n\nTo see useful textual output, run\n\n```sh\nperf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less\n```\n\n#### See also:\n\n- [Installing perf](https://askubuntu.com/q/50145)\n- [Perf examples](http://www.brendangregg.com/perf.html)\n- [Hotspot](https://github.com/KDAB/hotspot): a GUI for perf output analysis\n"
  },
  {
    "path": "test/functional/combine_logs.py",
    "content": "#!/usr/bin/env python3\n\"\"\"Combine logs from multiple Munt nodes as well as the test_framework log.\n\nThis streams the combined log output to stdout. Use combine_logs.py > outputfile\nto write to an outputfile.\n\nIf no argument is provided, the most recent test directory will be used.\"\"\"\n\nimport argparse\nfrom collections import defaultdict, namedtuple\nimport heapq\nimport itertools\nimport os\nimport re\nimport sys\nimport tempfile\n\n# N.B.: don't import any local modules here - this script must remain executable\n# without the parent module installed.\n\n# Should match same symbol in `test_framework.test_framework`.\nTMPDIR_PREFIX = \"munt_func_test_\"\n\n# Matches on the date format at the start of the log event\nTIMESTAMP_PATTERN = re.compile(r\"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{6})?Z\")\n\nLogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])\n\ndef main():\n    \"\"\"Main function. Parses args, reads the log files and renders them as text or html.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=__doc__, formatter_class=argparse.RawTextHelpFormatter)\n    parser.add_argument(\n        'testdir', nargs='?', default='',\n        help=('temporary test directory to combine logs from. '\n              'Defaults to the most recent'))\n    parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)')\n    parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2')\n    args = parser.parse_args()\n\n    if args.html and args.color:\n        print(\"Only one out of --color or --html should be specified\")\n        sys.exit(1)\n\n    testdir = args.testdir or find_latest_test_dir()\n\n    if not testdir:\n        print(\"No test directories found\")\n        sys.exit(1)\n\n    if not args.testdir:\n        print(\"Opening latest test directory: {}\".format(testdir), file=sys.stderr)\n\n    log_events = read_logs(testdir)\n\n    print_logs(log_events, color=args.color, html=args.html)\n\ndef read_logs(tmp_dir):\n    \"\"\"Reads log files.\n\n    Delegates to generator function get_log_events() to provide individual log events\n    for each of the input log files.\"\"\"\n\n    files = [(\"test\", \"%s/test_framework.log\" % tmp_dir)]\n    for i in itertools.count():\n        logfile = \"{}/node{}/regtest/debug.log\".format(tmp_dir, i)\n        if not os.path.isfile(logfile):\n            break\n        files.append((\"node%d\" % i, logfile))\n\n    return heapq.merge(*[get_log_events(source, f) for source, f in files])\n\n\ndef find_latest_test_dir():\n    \"\"\"Returns the latest tmpfile test directory prefix.\"\"\"\n    tmpdir = tempfile.gettempdir()\n\n    def join_tmp(basename):\n        return os.path.join(tmpdir, basename)\n\n    def is_valid_test_tmpdir(basename):\n        fullpath = join_tmp(basename)\n        return (\n            os.path.isdir(fullpath)\n            and basename.startswith(TMPDIR_PREFIX)\n            and os.access(fullpath, os.R_OK)\n        )\n\n    testdir_paths = [\n        join_tmp(name) for name in os.listdir(tmpdir) if is_valid_test_tmpdir(name)\n    ]\n\n    return max(testdir_paths, key=os.path.getmtime) if testdir_paths else None\n\n\ndef get_log_events(source, logfile):\n    \"\"\"Generator function that returns individual log events.\n\n    Log events may be split over multiple lines. We use the timestamp\n    regex match as the marker for a new log event.\"\"\"\n    try:\n        with open(logfile, 'r', encoding='utf-8') as infile:\n            event = ''\n            timestamp = ''\n            for line in infile:\n                # skip blank lines\n                if line == '\\n':\n                    continue\n                # if this line has a timestamp, it's the start of a new log event.\n                time_match = TIMESTAMP_PATTERN.match(line)\n                if time_match:\n                    if event:\n                        yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())\n                    timestamp = time_match.group()\n                    if time_match.group(1) is None:\n                        # timestamp does not have microseconds. Add zeroes.\n                        timestamp_micro = timestamp.replace(\"Z\", \".000000Z\")\n                        line = line.replace(timestamp, timestamp_micro)\n                        timestamp = timestamp_micro\n                    event = line\n                # if it doesn't have a timestamp, it's a continuation line of the previous log.\n                else:\n                    # Add the line. Prefix with space equivalent to the source + timestamp so log lines are aligned\n                    event += \"                                   \" + line\n            # Flush the final event\n            yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())\n    except FileNotFoundError:\n        print(\"File %s could not be opened. Continuing without it.\" % logfile, file=sys.stderr)\n\ndef print_logs(log_events, color=False, html=False):\n    \"\"\"Renders the iterator of log events into text or html.\"\"\"\n    if not html:\n        colors = defaultdict(lambda: '')\n        if color:\n            colors[\"test\"] = \"\\033[0;36m\"   # CYAN\n            colors[\"node0\"] = \"\\033[0;34m\"  # BLUE\n            colors[\"node1\"] = \"\\033[0;32m\"  # GREEN\n            colors[\"node2\"] = \"\\033[0;31m\"  # RED\n            colors[\"node3\"] = \"\\033[0;33m\"  # YELLOW\n            colors[\"reset\"] = \"\\033[0m\"     # Reset font color\n\n        for event in log_events:\n            lines = event.event.splitlines()\n            print(\"{0} {1: <5} {2} {3}\".format(colors[event.source.rstrip()], event.source, lines[0], colors[\"reset\"]))\n            if len(lines) > 1:\n                for line in lines[1:]:\n                    print(\"{0}{1}{2}\".format(colors[event.source.rstrip()], line, colors[\"reset\"]))\n\n    else:\n        try:\n            import jinja2\n        except ImportError:\n            print(\"jinja2 not found. Try `pip install jinja2`\")\n            sys.exit(1)\n        print(jinja2.Environment(loader=jinja2.FileSystemLoader('./'))\n                    .get_template('combined_log_template.html')\n                    .render(title=\"Combined Logs from testcase\", log_events=[event._asdict() for event in log_events]))\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "test/functional/combined_log_template.html",
    "content": "<html lang=\"en\">\n<head>\n    <title> {{ title }} </title>\n    <style>\n        ul {\n            list-style-type: none;\n            font-family: monospace;\n        }\n        li {\n            border: 1px solid slategray;\n            margin-bottom: 1px;\n        }\n        li:hover {\n            filter: brightness(85%);\n        }\n        li.log-test {\n            background-color: cyan;\n        }\n        li.log-node0 {\n            background-color: lightblue;\n        }\n        li.log-node1 {\n            background-color: lightgreen;\n        }\n        li.log-node2 {\n            background-color: lightsalmon;\n        }\n        li.log-node3 {\n            background-color: lightyellow;\n        }\n    </style>\n</head>\n<body>\n<ul>\n{% for event in log_events %}\n<li class=\"log-{{ event.source }}\"> {{ event.source }} {{ event.timestamp }} {{event.event}}</li>\n{% endfor %}\n</ul>\n</body>\n</html>\n"
  },
  {
    "path": "test/functional/create_cache.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Create a blockchain cache.\n\nCreating a cache of the blockchain speeds up test execution when running\nmultiple functional tests. This helper script is executed by test_runner when multiple\ntests are being run in parallel.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\n\nclass CreateCache(MuntTestFramework):\n    # Test network and test nodes are not required:\n\n    def set_test_params(self):\n        self.num_nodes = 0\n        self.supports_cli = True\n\n    def setup_network(self):\n        pass\n\n    def run_test(self):\n        pass\n\nif __name__ == '__main__':\n    CreateCache().main()\n"
  },
  {
    "path": "test/functional/data/invalid_txs.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"\nTemplates for constructing various sorts of invalid transactions.\n\nThese templates (or an iterator over all of them) can be reused in different\ncontexts to test using a number of invalid transaction types.\n\nHopefully this makes it easier to get coverage of a full variety of tx\nvalidation checks through different interfaces (AcceptBlock, AcceptToMemPool,\netc.) without repeating ourselves.\n\nInvalid tx cases not covered here can be found by running:\n\n    $ diff \\\n      <(grep -IREho \"bad-txns[a-zA-Z-]+\" src | sort -u) \\\n      <(grep -IEho \"bad-txns[a-zA-Z-]+\" test/functional/data/invalid_txs.py | sort -u)\n\n\"\"\"\nimport abc\n\nfrom test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint\nfrom test_framework import script as sc\nfrom test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS\n\nbasic_p2sh = sc.CScript([sc.OP_HASH160, sc.hash160(sc.CScript([sc.OP_0])), sc.OP_EQUAL])\n\n\nclass BadTxTemplate:\n    \"\"\"Allows simple construction of a certain kind of invalid tx. Base class to be subclassed.\"\"\"\n    __metaclass__ = abc.ABCMeta\n\n    # The expected error code given by Munt-daemon upon submission of the tx.\n    reject_reason = \"\"\n\n    # Only specified if it differs from mempool acceptance error.\n    block_reject_reason = \"\"\n\n    # Do we expect to be disconnected after submitting this tx?\n    expect_disconnect = False\n\n    # Is this tx considered valid when included in a block, but not for acceptance into\n    # the mempool (i.e. does it violate policy but not consensus)?\n    valid_in_block = False\n\n    def __init__(self, *, spend_tx=None, spend_block=None):\n        self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx\n        self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)\n        self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b\"\", 0xffffffff)\n\n    @abc.abstractmethod\n    def get_tx(self, *args, **kwargs):\n        \"\"\"Return a CTransaction that is invalid per the subclass.\"\"\"\n        pass\n\n\nclass OutputMissing(BadTxTemplate):\n    reject_reason = \"bad-txns-vout-empty\"\n    expect_disconnect = False\n\n    def get_tx(self):\n        tx = CTransaction()\n        tx.vin.append(self.valid_txin)\n        tx.calc_sha256()\n        return tx\n\n\nclass InputMissing(BadTxTemplate):\n    reject_reason = \"bad-txns-vin-empty\"\n    expect_disconnect = False\n\n    def get_tx(self):\n        tx = CTransaction()\n        tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100)))\n        tx.calc_sha256()\n        return tx\n\n\nclass SizeTooSmall(BadTxTemplate):\n    reject_reason = \"tx-size-small\"\n    expect_disconnect = False\n    valid_in_block = True\n\n    def get_tx(self):\n        tx = CTransaction()\n        tx.vin.append(self.valid_txin)\n        tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE])))\n        tx.calc_sha256()\n        return tx\n\n\nclass BadInputOutpointIndex(BadTxTemplate):\n    # Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins\n    # database can't distinguish between spent outpoints and outpoints which never existed.\n    reject_reason = None\n    expect_disconnect = False\n\n    def get_tx(self):\n        num_indices = len(self.spend_tx.vin)\n        bad_idx = num_indices + 100\n\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b\"\", 0xffffffff))\n        tx.vout.append(CTxOut(0, basic_p2sh))\n        tx.calc_sha256()\n        return tx\n\n\nclass DuplicateInput(BadTxTemplate):\n    reject_reason = 'bad-txns-inputs-duplicate'\n    expect_disconnect = True\n\n    def get_tx(self):\n        tx = CTransaction()\n        tx.vin.append(self.valid_txin)\n        tx.vin.append(self.valid_txin)\n        tx.vout.append(CTxOut(1, basic_p2sh))\n        tx.calc_sha256()\n        return tx\n\n\nclass NonexistentInput(BadTxTemplate):\n    reject_reason = None  # Added as an orphan tx.\n    expect_disconnect = False\n\n    def get_tx(self):\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b\"\", 0xffffffff))\n        tx.vin.append(self.valid_txin)\n        tx.vout.append(CTxOut(1, basic_p2sh))\n        tx.calc_sha256()\n        return tx\n\n\nclass SpendTooMuch(BadTxTemplate):\n    reject_reason = 'bad-txns-in-belowout'\n    expect_disconnect = True\n\n    def get_tx(self):\n        return create_tx_with_script(\n            self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1))\n\n\nclass SpendNegative(BadTxTemplate):\n    reject_reason = 'bad-txns-vout-negative'\n    expect_disconnect = True\n\n    def get_tx(self):\n        return create_tx_with_script(self.spend_tx, 0, amount=-1)\n\n\nclass InvalidOPIFConstruction(BadTxTemplate):\n    reject_reason = \"mandatory-script-verify-flag-failed (Invalid OP_IF construction)\"\n    expect_disconnect = True\n    valid_in_block = True\n\n    def get_tx(self):\n        return create_tx_with_script(\n            self.spend_tx, 0, script_sig=b'\\x64' * 35,\n            amount=(self.spend_avail // 2))\n\n\nclass TooManySigops(BadTxTemplate):\n    reject_reason = \"bad-txns-too-many-sigops\"\n    block_reject_reason = \"bad-blk-sigops, out-of-bounds SigOpCount\"\n    expect_disconnect = False\n\n    def get_tx(self):\n        lotsa_checksigs = sc.CScript([sc.OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))\n        return create_tx_with_script(\n            self.spend_tx, 0,\n            script_pub_key=lotsa_checksigs,\n            amount=1)\n\n\ndef iter_all_templates():\n    \"\"\"Iterate through all bad transaction template types.\"\"\"\n    return BadTxTemplate.__subclasses__()\n"
  },
  {
    "path": "test/functional/data/rpc_getblockstats.json",
    "content": "{\n  \"blocks\": [\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000f8dcd6e372bf9002b89d6da07b0e6fb65b623751458de65a4497603ecb0bed4bdae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3a04ffff001d0104324f6e206a616e756172692031737420746865204475746368206c6f73742074686572652062656c6f7665642047756c64656effffffff0100000000000000000200ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020bce134d7a2f8c49a66a250237e7cf55ddf2fc2bc5eae6020b7f7750f0e834b3ed8c78af8f59c6b7564d5a164bae2017b2c706ce8572a7e4d46b528de462d87f7a248fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0451000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b1689ee1fc133fe937598d81854ac4b6331c6c78a014842f2b76e10ec008fe260299a594e0dd5a16516cdb12bf785a4fccfdfbcc2db94759ad79743d77409b86a248fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0452000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002094974665c4a03321111b47d456f97f0e5a64b7e61c9ae76767fd9c76a83d58222c501cab24b1899c3964c5b4a5671d863d9fa0ae6bc5ad84222e61a3e6eadbdda348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0453000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f1732559c50aa136275e318747ca5ced1665d0caed3b33cd6c60f0620fec692d5ea7359bc79e0cd06f4a41f7a80e4da698b71c0f043bcd3676556a30d7563faea348fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0454000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ddd6c9dc15c0f0bb5f0087eed4ca53b9aaf0288ccd5d3051d989f055c6f2632b1234338e252fb1495e2603201abb9d4175ba7e400f4356e2bf842ff7e286c055a348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0455000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f3c85347f1cab030905b5b65986d40146247b42636384fdba5ec2469c37e8506fac555ff2c5c23e5a136899caed189f5c1da04a913eea4f92097ca10cc697a77a348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0456000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000204494f7d0b3aabeb762c3cd2235288ad6d424513d636b103cd93c0787d985f01a15d3b7c06dedd69580510e058e83ce65df855063f7f56a064deb452ff3a536aaa348fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0457000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000206fe8db6b63118f1fba8a9314dcd1cd13eb6ee6b6efdf005c7fb4bbd86b10cc4a9ff14998e2ddee88a191ece6aaacb77e40556a5969163d8221a811044d4050eaa348fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0458000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000201b1111d78b61ff561a4a7de6c3835c609403653d2599b12e4939239318f9e821d9b5254b981179c17ffbba237d67c3c14acba9b1cddddfd97786c75a2c201022a448fc61ffff7f20060000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0459000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002081c18a380389f11d717f29b761671c5dff41d5c3ff8c775e4edd5e2deb45a679a99a86562412ab8ca703c18f3aefb8dfcd3c4af2a50f315f1848f4b0a3cb8ba8a448fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ec39851440dd55ff615d8a453bdbf46c5654267b906315db7eeec45555a9293283c52ffe4a5005eba09b750fe9ac35e5b28da9fe0d7fc711f01defb20170e1aba448fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002086002f8e9ddf97e14191c701d1c26a6aea3b846498a8c42f435afb10b57acc66af2feaa44edd398c425a926cf60ad212dcf2626ff37db902335e15889dc28a53a448fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002021d1031da3f11e63ee2feaf7fedac7d1a9f32e94d1ae4d257b1a9c9725b7034711c80e374557eb1a65b95326abe4ce8558bbd3acc9a11cfcf094a29661f9ac06a448fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c22ab5291b77d7e4c397a181aa51daa80fc59ed619cf84974a632e09d037c7127ae09bf3e19598c081408ffa0722777dfb03c9d587d307d10f04c9b196098b26a448fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000208ff65ac7f892ab123d832456344b5bf5d8fc01a9d9f840f8a5b515f71f1238057ec76fd32d7059bb31eb344f5103db3e919089d00d8bd9403c76fb9eff585d5da548fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff045f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020fe8ec6af8b6d3b9eccf1ad174e05e80839f01291ef154e5b5124e135cedcde331cc871ee7c125ab847ecba307b6bf9c07b6a2a1189e3a5a5cf0b8279d638816ca548fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0460000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002072eb12562d25a1de8ca5219322506bc02d85f09f6e0b67cff00efdb81bd03a3f2670bab0abe8fb7cfbc9e462b0278ea235ea2debce9259adcf8f156ee775bd24a548fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050111000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d69ba43ce70f08c8e1f4563ab0fbf2b2482c35eab3791f01b12b19113ff620614d8adda47d7044c3702d7472a511d0bcdef207d5e8b2b41086729cd0f02ba00fa548fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050112000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c86e79646bccddb76c9506f0ec4c848801ced9725d9ef0bdeabf6d2e50cb584b22f97e0e9892300cb5ca2061b90fbd9996879d80fac9bd190a406a5aa55cc6f3a548fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050113000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000205f3df34cc1709cc54bed6e2647b9f3b8affce10f1833438d57d0f0304cdc0714f595aacc19498a913ba2ed6a3b7dcc3564cff8d93b4eacf0d3816f9047394c37a548fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050114000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002033f7d64aa7194d77d873708bedfc69697fc8e4e0d7c53211e23a5acea360154310b1855618c40a16f7ed32e12cb081ee6059345dfc17018cf5f6a3c76cf185c6a648fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050115000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e672e38393fe6793733229bf27a1c56b6d2c16eaae834e82142022c356256538dc1ee09e82d585280a005e48fcd67fd58de55fe8a4a1dc65033140d54d7acab7a648fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050116000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020124bbf53b69998ede7e1c5094d3e37707dca3bc0a08ff303e018a307a369d34c53b4832ee2c2c572d32c183c213d29e5ccc7496a7d1a6ccba22556b52c9fc790a648fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050117000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002009517c7af73cc5cb52f5cfd22d2f50bc94230469a8a262c03f06073ab045294f172326479ab94909ef5e2c53f7e07da8ba9211e7dc3441b0bada18596ed8b27da648fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050118000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000203b75a2a03c60a49e8d532de58453f0338498cc2aed6754624d4e0ef3f9ba02593a16b8bf213ebbe835060cd7f9fd1fa3412beafed96853cb3426919eee37cdcda648fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050119000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020963cc96017c192840b2e1686a675d02f377b97e5d108170147dfd7a0d78548225e17cf2191fea2fe1b52b833c7874ca54bb92eb0dc2f6929f9c5ad09978084b8a648fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020cac2379197e1349887fd6e52212e7500104e822645979abbfdf484ebca2c16390cfebeb7c1a80f463272b103615305cc0b0fc71cf1eb87cc583a89a2d436ddf5a748fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000209a5d29283a538b0dacf1df412f121a48416a9c80dbd96d85e417f271dad4134c0a85dc26779e9c253884ed648597f912680bceed9488add9571efabf89856671a748fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020410f494685ecd6447b0fb995916f1be684f3bd1409e4e71841fbff5c0dca2b21d8e9e496ca43be2b739fe74f5e66813ab698c200bc6f970812cbd9a5434a90b6a748fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002026a294e0e982cc4b06aa4dbdbf5328aec304eb7ff82c01037df78ba168ad987da01524aef7e763d4a0439f1bf2d2c3775d1d0ada6acc2ce6ad3ba9021050c16ba748fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002005846c5a029f093fa12ecb2b9888ae7f15ae1f7e787f4a5ea5465424e3b63876596b9be6e5b6db8d7514bda97e334061c6adc1514a80a439349ab6991f2c693da748fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05011f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002061a653e968f39a79d0ee30f76388216c41b8e378a68a80099e17ac01c4ebb44cd1aee826b5147e201cf334124a5c24906d23726b08f23e909e71b2c29c88a8eda748fc61ffff7f20040000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050120000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d019ae4119b2ab1e8b3530afe62ce26a13e286091737bbcbec0041665e829f31c2fbee3057e6d483a3cc280f0d47c1f26e57d4864bbf25f5ec7ed40870cb3ed7a848fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050121000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000207357289c940bb196cf13a3387f9a5f3e138fd1bf1ea51b791d09af28d46fc030f4dc276960d8e0b8584117ee7ebb5986d618d481a80db27522449c0fb2d098d3a848fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050122000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002050c08b19433449fa4cefe2db57e3a9da9d96e5c339d16eb1e3e8ee35be2e226d0416d1ba543a7ed4eeddb62504315134ad6d6c29d5d162d73f0d8b03759e8f9aa848fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050123000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020975502d3eae971c97faa21c9c169ee3a60808760068fb7e67f4814e64ced856f8f423af5031732846a604f87f52dc8fefb51f75fc5b7d74c3e8f18b07d8cb2e2a848fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050124000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b67c2a3b9c8f5340f9f047d6e5971064ecc2e6913a38e9fe3a792ea281b5f33ca93f0813bda852a3face183e9b8e3a47fcd8108d09cb9b2d3896f40e7fdc39bfa848fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050125000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020722ec86c1a9fe97a5e97bb4947cb977138c5dc673326d76ee4912778cef639719d47f3daf1d7b22b87cb3dd40ec953c54c90dd7d4206c7a97d139ee961eb24bfa848fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050126000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020dcb59482b94b7798942ae0340b51108d8c1da1674a302e62eeb0d3897d65f24131969a96ce3a5f575e5d0b33aa05f5b3bfe693d4a3ad023b650c886c80c3cd5ba948fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050127000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020303e6a6abe86cbf6a94b5fe669ea4e4a245108ea2a10f9e068bab119e7a0b176c47fead5732c92dfa87763946b7605039862bb042147712d33e2a847e739569fa948fc61ffff7f20040000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050128000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020df31ec12842b04227ad6d977bf963b787a68f37bdeb70775cccb172c1f77573d8322b8311b13faa6a3d65be49e5828ce6ebe9ffd3eb96e6b51f52b921e2db0c6a948fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050129000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020976cff2a6eb69c9706e465702f60e1d3de788673abdc8c998bdf735d14c2d10847da0d8d7da13d4d9f4cbb1df27b890d6e2d645fd581aace7a319aadc374fcb9a948fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020123c6394fed7360c0fec8a46aac15b600f5882fa1730477703625a363d6f4650fadca354a540cb71cff138056ef41477f0749e4fd7a76ceafbf4cab27f012efaa948fc61ffff7f20060000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000208a367842ebf8df144bc6ebc05379bf1944da25482f53e646d749de918e94c11618c37239ac6ffc4efd492979b9f41f112670004f6e163c6d8b89bf8bbf764618a948fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b491aeb04eb4e6ed4294df04f241e36259433e42bf74f08573e86e8cb9b74d797adf30b186fdbe009257d4d4c44bae3f787c88bc812c052cdec09b2a33d8f67daa48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000200f7d99d7d29ca2e8ee865543b33fc8633ff5af0dcf0d7374f103b4a08895f274b9d272dfc77c43eeef1c3bfe18ed3adbc98198f18b95cc493cffa74c402a42a4aa48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d7448b68ecac75a907b2cea7c572c2529dd99c8a67a06ac90d85621fafb5fa38dd4bf53833dec61127e527a52f408df7d8a9a2f6548a138af0d69bf6d80d52b0aa48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05012f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000204e6d076dac5fd57f29a03f45d6e852e4e0e29b8bd05be2bd89a88f7f376a674d6b5ec8353f3d513a1c1efcabaab16bdc166fae4dfca664f0bea922b8ce939fd0aa48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050130000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000206c6eae32026d14038651abadc4b27ed748dfbf6bb6fc1d71c15bd5919a5c985a9bc834c1dfb48840fe50e54cc395b0ae2afc48f1bf5f68a98e9f06f6e8cd96fbaa48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050131000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000209b5a06f274f729b9c2fd2dc3604ea8b1889018f576ba447e2b1d65957bc5bd3fd9d650a968bba89da2ad5e7b4c4da86be38d9984ee1956ff93a7eeb75e83cf48aa48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050132000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020b0456a9abfb2e083727dfd129d04e26dd28f473354259c552bafdca54476d9710f3bbfaadaf585b44909e38fe160d4cae0239f9202c25eaa9a2deda6f5a5c3a4ab48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050133000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a6639e9d87210c52282a4e223c3c64af70a6fd804319213876440b0257f59a0b22d7284e72190a6258e365627a23d5f25088a7248565cc3b3c2778bb78cc5797ab48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050134000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000202bda141835c13331ecdf87df267ae86ae3c7a3e45bd17043afbd0701cb3ea24af255170f29030602ca6c1792aa676ad08e16b14c6cc8c3abe3fdd6804465acddab48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050135000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d8ea711e9011ede2e0737aacfb8e56f766e64321440cfbf214ca552a5b52db3f9046a245bc1bece9b2536ab1d918ae9eb73d9b675ada17390016267a081ffa2cab48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050136000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000208950917d1a5e15e866e7ba27e9ded6cc9370059b564b892ab575cb1d0b36777ea5fa1bb3e84ffd81f5bce41608ffc8685d4857f7118e6db21e0473d9e033a107ab48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050137000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000205e8596f4cb897c99461b44bb9817c5e55951de1bde88ebb5763cfcbb8f70eb7439a24e1e9b753e152de95f5f750fcc527b772270649838e84e5ac45253c74ceaab48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050138000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020e393d2471e726f2303fb011714bc34a491598388f3c3275b83132fb4c469116db3b8e2ec0368051ce806a9e737ec2629ec228f1afe79b73a66de506c8356673dac48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050139000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ea836544702b80477c74ff58037e4756a717f8b8408961376f62dd3f1cecac3e4d5613e490f0f90c2772a19a67840748613faf54378fd17397e379a61accf364ac48fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000206f587e0498c89dd563a5cd8693dd807c57a81e9746f0fb4f3a49d244534bb65c3c02176d7493579dfc5f1731600ed60647ab79ddb055e1d2d6faa12ee4d515f4ac48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ff361af4c337235cbc0b9afc81b03e41b936299d532c43cc251a56c80076c00e405185af442cc5d3e884b7309225da065fd310672f6af4d8b294352f9ba3a58dac48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d3f5734d65ea245c7732386468348f0719ce63e817ca4bc30018eb08feffb46e7cae4b6ccd059e9034e4179ad1c637433fe78f383593cdc0a3dc04d85f98c624ac48fc61ffff7f20040000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020bffd8739e754ae63a90ee298cc1f8184c5b187d98a339c130b5f455d3806c36e9189cd50c6cc5a85cb462bd3206013c4080418f27b84e0221ea011543970cae2ad48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ce7a99dc8bb92c02b103b77d2de7f9c0f865b2a8242cc08e5950a0cb4e2fd67322fa8a93972182f4f80ea904e6edebb54658b9aeff07fce052cba3c04722a2dfad48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05013f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020feba94ca44baf1060e5052ef7f73ac2fe7f30194726ff2cac508c9f3337fa825aeaa22c3610433445521ccf6b664c3f71b9e7645d2d1392469d8b1e8d9f51b63ad48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050140000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020eb28da1aa3a2967d6549b03a2f4ef72788731203c5aa7ed1a96194bfdc756070b3c4d1472642fe7ad92ba9b58a3519e1408a36ed07d92f8b1b731b6d4e9fe894ad48fc61ffff7f20030000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050141000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000203c012b046e0c6ec4040875022521eee2e037b4845278531070ff638716aa583881eaa3f7b7d33e1104eb5538c1e82779d1742e22d57e56f1d3cd48ebdd79a648ad48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050142000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020fde7653c17d1362639ebe300c156f3d5a881cedcb17f5ee508725566113b3a73145996313a6eec3cef2dc12f543157c5a267626cd14526e5832292d7db91ba80ad48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050143000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020db3dc377520201ed7b3c15611ed9879e9c5942421cfbee75cf73591953524922a7261c22273490bf1b231d3d48f70f0376c4579405c953c3f84624999953b9dbae48fc61ffff7f20030000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050144000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000205a1be1ace0c43ffbd4df221334672145506daf4f888620bfe3cdc151cabffd3c448bf20736ef22d142b8d6f9a3d11d7ca0d8a811743454016380ce35bc5b3f70ae48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050145000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000205f991c43fdb32f2f38af213a4dd573c93fefffe1dc7a93553a367a5ccc446f1e9e15f101c01e0953fc3887a71edce78ac0fe26530ae0ef8322ae931b251c9036ae48fc61ffff7f20040000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050146000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000202fe118d9b9b0e0ae5522439504c3369cca4981301e35f022fc10bcd31ac26022c9b67e892bd072835023e2d0379d7bb3d17a285e0442d5be1b5ddc117227e1fcae48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050147000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000206098ed8204b5fb8a1762a0109f7d916cb0e6368532c20846e659f96164e2464f89e6fb387b81ff9a16f10878708e814a244eacc6db288617f881f968e89e3e8fae48fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050148000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c773d605741615140a86ad45195db8776c2b9cc17a35247fa356bd5e77bae871779c16081cececb353b1ea823dfa330d09f87e8bf87aa6dba7565b54adf2d6e5ae48fc61ffff7f20030000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050149000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c3a8969ed0733239cb25b849630dff06549f611c6e9700412030cc0f43c232499b23a4fd567c43c6c1b2fd7c05d6afab5345cd3b133c3ed31df9c2e326c14c6baf48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020672494670cfaf597729c84d9bfbbea3ace1653ceb6f3b0145bce08d058e5c51a9ce6b57f5f1dc8da6e636b0b30c1453d27ab42322256a009ec3c3adae802fd33af48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ea5d4d54aac9d722a443ee49f49235eb442c294b095820569ac8d610ea1b315e12036a0b6b816663b47af9092aee09154a3fe2c38435b14e08d4c0810c124db4af48fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020af794b3d56c226514f2777a77fb8d1547be8be7fbcc5513fce4eeb25d7f26d4ac0f35e0817c12f9c3d590372e3df748e77c3103a6045b53713ebf0139485accfaf48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000201e284e075a5deeac35bdcca227ea55f90fc8f02ae34e8bdbc3307624f5374079f689223e0d5a59441608ce93009e716091492888b8fed9c165474d731723e56aaf48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000208faac5b3819228d45e06c68cd5e2bb44e9bfcd541e5699569050783ea938006bcbab28a8ad9a0e0c32eca648ecd16d2669aec7b4179084c84114fa052a67d75aaf48fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05014f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020702d470774a6a04392dc02f4361c8fd2b53e6a03a4ed26dd7d056a705db04f7c116c97702b79b79ac89b73b835ab842f8a5b7bfeb46dac88001e08b35a47f031b048fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050150000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000203d6f5414e6f688f327b7c884ffcd1cc6c05950c1beb415b382ceb7fbb4df3a79255be41591b3c9d0bc2d4abb6e5a2238a973ee37490b2678b293892ca65339d4b048fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050151000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002054ac0aac556365d30f09cada5e3fc9b9612173cff9d759e7b66116b30114603833ef62fe8593c00ba409eaae4cd8beea347239f916beb319aa8ed2e6d8aa822db048fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050152000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d2ed30ba0bafd44cbd7a5724da8a2008d8fe981b5b06aa2d9672fde87006d71f4144eb93ea30a45f6897ae0773cd0c021201e073a0e89facb7e4c80a07761797b048fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050153000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d86aa02574eb28c7c9570aac5d25aab056a3ce8b35a2482cb730c058338cd61cfc8597c96442c547deac6631d3ec8641e3753bb50e6ae788e6d5e28fc84b7ca2b048fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050154000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002094265e4478e0f006b6c86bc733da64a9fa16aa8f0ca2bd621dc025a50ecd2a7e247c2c9d229cbea8999b00a908246efc64f3dcd189e64d9292efa508f29fe26bb048fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050155000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a0df0bea40d0c6182ef02482608892ffcb68d854ed4f4c368fa2d82b8675221c80a04485693364e1a3353f3dd5a70bf3d90a1ad908daebf3d51152488b9a0e31b148fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050156000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002084dc127add3498c4b93a02eaf3f52d0c2c5b985f1df66c8b31a8033aa847481b681192cf71b40f7c1e7c7bd1e7b978566a1d8f426cf2c1e2e642f61453d4a3a4b148fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050157000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020bd2109a2f2cbd8c486e2016b4de5c2f584b1f1c186cf908994f3014ede02dd58fc4fb36c9b944fb165ef511de97f8abd65999883db4786bf352b0c25175791c2b148fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050158000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002069b72f15c66a0a26bb3394f2e1b7440a796949b9523874c3da98574f2c722041441816a14242a8395d251f36edd9286b817113d9a7e7dacae23c1241b0736c3db148fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050159000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000204af607c6fbc66ea6f2fd0a784e02fcc94818752c493838dded58795820b3951cd50ed0e923217b28e924ad9cbaf762b8534832091707618f99645b3c31195b16b148fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015a000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020ddc633f53078d0c94eb84574c3dc7aaef01326cf1e2e8386ba908eed9df4df183fbc12b26b02c63de363a5c2937db0a1ca526cdfd10103e214aa840c749ad00ab148fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015b000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a89ae6c53dcdfae7731fdf0228faade8b29f176ce82bb859f8ffb41008e87e367990497cabeba84fe982f0a90d043206f884ebeaabb23e4cbe3d48f4b976a04bb248fc61ffff7f20020000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015c000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002012461b665d1a1df49b5d1766cb6861b3c345640169a8c26b728e0049900a734a14e1aff025181775ab412dd065f38c7a2957edd5649dcfe923b1bf2ae9539f0fb248fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015d000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c9c0f5834d55d0eedd4b1727015a6d4edd9d3f965d54959a09dbcdda6b80ea7fd110cb94db4e45bafeed9847380220c1b3e213dc7fc5788494e870762c39e8b7b248fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015e000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002005eb4d16c50e97364797268bbd58c8c86c658ddd69d0135f2975c1baec754b3a5623a72a7e652734551898c0f4caaf3689bece7e57c7bea30435dbeac01fd90eb248fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff05015f000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002066fd64c4ef56283d9776a68a1939ca634c3b5daf0bb6b9a21928ef603ca871790aecbcaf0ea5b6c9b9a3c0ba934a50a82963ea5fb95ce9b165b3dd754d465e4fb248fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050160000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002003f15c027a54ad8889ba1bc9e033394680c03e093cde8df272fdcd9ee2c994235f2d4a8eaead96fcc199c0a1a8997a101a1eb1254d442b886c123226f60d95d8b248fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050161000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000202f766d2921c7d570eaf2f12aa505e1338257e13eb46ff6c0cf74b3295d4b3676e3238c027f06c1c9d59af95646e70308e1f6dc66dd3ffb6ed9d6c02374054111b348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050162000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020789d0d1f7b7761373d09952f73027371454cf13ad91d4de695f31640383a556fdbe5b4ce80d9023c5d48f36a5f92049750988dc5821b7c72d32862cdb12eb42db348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050163000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002043fa449db6dce27e83d80b9be6d65d871a0ebdaef84370f8bfba6096fa50544e9d9952a14303bcf7b1537dc26923cd64d1bf88281c72c87824788033dfaec253b348fc61ffff7f20010000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050164000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f39b12d8cbe250e7b416a950a7f5f805034eb8829f289e7a4755e0f6f3ab744a7754e0fcc02dcffc509fa36704aa053840929753c46d3d19efe4faaf362066ccb348fc61ffff7f20000000000104000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050165000000ffffffff0100f2052a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac00000000\",\n    \"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000020d3fc2a76357c3ee93edd90f62f9b9f1b3bac5c2f9efd630259ec92b596eac6020aea8ab84f6cdc6f28eae9f00b5c494d1fe511afee391c483a808a8388e25783b348fc61ffff7f20000000000204000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050166000000ffffffff01707a082a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac000000000100000001d8c78af8f59c6b7564d5a164bae2017b2c706ce8572a7e4d46b528de462d87f7000000006a4730440220023297ce9129e653471cd96e773e9c1da639a213de0280702ac3d473d589b9bb022052623118231494087f8e23039ba282d646c159443f02a72eb144d16aa32bdee2012102bd8bfe18681ccca07d3315449f0f018ef5251ccd48fe7e9eabae8bf48a5b2453feffffff029041983b000000001976a914132d0e627ab8b155b278f6913300752177dd189988ac00286bee000000001976a9144595bdd5695828d821ce871c75b41cc62662f24688ac00000000\",\n    \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000002009f0f275ece8e2fc331b61d3adfc7dbaf9ecb2d929e1abe9ccd135816bce5f66c3a5abe89368a0fa455e6f6830d0d14d9d895af7de6f1e6aecb3c18904c27414b648fc61ffff7f20000000000404000000010000000000000000000000000000000000000000000000000000000000000000ffffffff050167000000ffffffff0110600f2a010000001976a9140f3a5edc2f08a193fd04e4793d20296c207b8f9488ac000000000100000001a5285758e2bcaabd48381be45b455c5954b5503a447917a8a589d075185aacf1000000006a4730440220759e673b7512cc46f555770ccdcd6f759b4b703043cffd8b1cfb607a0a14776a022007a651d95300c5925e4843be00e95eb1ac3f485fd74f752ef02ef909c1d6bd6101210325963e89684f3d518b7266d0ad181eabf4bab62692c996157d35b3319ebc7106feffffff029060a235000000001976a91486c379aedd42b18fec9cf0032eefa4204fd3e95f88ac306ef205000000001976a9147bebbdbf8942ed0ad416f430fd051ffe9a9bb15888ac000000000100000001a5285758e2bcaabd48381be45b455c5954b5503a447917a8a589d075185aacf1010000006b483045022100d2ea2e78e5b17724aaf0de0bf8fb3c5d495342a9e5dd8d1142557b1a38d74d5b02200e8e5d4dea5631348f934a541e1e78cbbd9e27bb0c28403d880ff242ff98515a01210365aca3cfd0cc6aab546db828ec4694cb3614bc79b8761f006201d593b7fbe2b0feffffff023057973b000000001976a91411a8d5892918d427209c86d8f13c3388eb81c20288ac005ed0b2000000001976a914a62369992c4dcaa3da0e0957ca3931446c0b937b88ac0000000001000000010299a594e0dd5a16516cdb12bf785a4fccfdfbcc2db94759ad79743d77409b86000000006b4830450221009e89755d847026fabb59cdb13bb777c7e858447228492172f90755a8ca168af902200f2614dfdd17b7e3103f81c0bf7f44e9d9b4f366b2eecf70586137fa02aaf71f012102bd8bfe18681ccca07d3315449f0f018ef5251ccd48fe7e9eabae8bf48a5b2453feffffff0200ca9a3b000000001976a9145e9ebfab9ee823b3af490e2390fef60fa270599a88ac909f68ee000000001976a9140a19199b9c21981d4ab18ac72b42def5eddd706c88ac00000000\"\n  ],\n  \"mocktime\": 1643923559,\n  \"stats\": [\n    {\n      \"avgfee\": 0,\n      \"avgfeerate\": 0,\n      \"avgtxsize\": 0,\n      \"blockhash\": \"02c6ea96b592ec590263fd9e2f5cac3b1b9f9b2ff690dd3ee93e7c35762afcd3\",\n      \"feerate_percentiles\": [\n        0,\n        0,\n        0,\n        0,\n        0\n      ],\n      \"height\": 101,\n      \"ins\": 0,\n      \"maxfee\": 0,\n      \"maxfeerate\": 0,\n      \"maxtxsize\": 0,\n      \"medianfee\": 0,\n      \"mediantime\": 1643923633,\n      \"mediantxsize\": 0,\n      \"minfee\": 0,\n      \"minfeerate\": 0,\n      \"mintxsize\": 0,\n      \"outs\": 1,\n      \"subsidy\": 5000000000,\n      \"subsidy_dev\": 0,\n      \"subsidy_mining\": 5000000000,\n      \"subsidy_witness\": 0,\n      \"swtotal_size\": 0,\n      \"swtotal_weight\": 0,\n      \"swtxs\": 0,\n      \"time\": 1643923635,\n      \"total_out\": 0,\n      \"total_size\": 0,\n      \"total_weight\": 0,\n      \"totalfee\": 0,\n      \"txs\": 1,\n      \"utxo_increase\": 1,\n      \"utxo_size_inc\": 73\n    },\n    {\n      \"avgfee\": 166000,\n      \"avgfeerate\": 737,\n      \"avgtxsize\": 225,\n      \"blockhash\": \"665fce6b8135d1cce9abe129d9b2ecf9ba7dfcadd3611b33fce2e8ec75f2f009\",\n      \"feerate_percentiles\": [\n        737,\n        737,\n        737,\n        737,\n        737\n      ],\n      \"height\": 102,\n      \"ins\": 1,\n      \"maxfee\": 166000,\n      \"maxfeerate\": 737,\n      \"maxtxsize\": 225,\n      \"medianfee\": 166000,\n      \"mediantime\": 1643923634,\n      \"mediantxsize\": 225,\n      \"minfee\": 166000,\n      \"minfeerate\": 737,\n      \"mintxsize\": 225,\n      \"outs\": 3,\n      \"subsidy\": 5000000000,\n      \"subsidy_dev\": 0,\n      \"subsidy_mining\": 5000000000,\n      \"subsidy_witness\": 0,\n      \"swtotal_size\": 0,\n      \"swtotal_weight\": 0,\n      \"swtxs\": 0,\n      \"time\": 1643923635,\n      \"total_out\": 4999834000,\n      \"total_size\": 225,\n      \"total_weight\": 225,\n      \"totalfee\": 166000,\n      \"txs\": 2,\n      \"utxo_increase\": 2,\n      \"utxo_size_inc\": 152\n    },\n    {\n      \"avgfee\": 206000,\n      \"avgfeerate\": 912,\n      \"avgtxsize\": 225,\n      \"blockhash\": \"254ebf981df0f228cac443bf97113a8e8f5fe74c4b56e2dd1bade1a774b8a727\",\n      \"feerate_percentiles\": [\n        734,\n        734,\n        1000,\n        1004,\n        1004\n      ],\n      \"height\": 103,\n      \"ins\": 3,\n      \"maxfee\": 226000,\n      \"maxfeerate\": 1004,\n      \"maxtxsize\": 226,\n      \"medianfee\": 226000,\n      \"mediantime\": 1643923634,\n      \"mediantxsize\": 226,\n      \"minfee\": 166000,\n      \"minfeerate\": 734,\n      \"mintxsize\": 225,\n      \"outs\": 7,\n      \"subsidy\": 5000000000,\n      \"subsidy_dev\": 0,\n      \"subsidy_mining\": 5000000000,\n      \"subsidy_witness\": 0,\n      \"swtotal_size\": 0,\n      \"swtotal_weight\": 0,\n      \"swtxs\": 0,\n      \"time\": 1643923638,\n      \"total_out\": 9999216000,\n      \"total_size\": 677,\n      \"total_weight\": 677,\n      \"totalfee\": 618000,\n      \"txs\": 4,\n      \"utxo_increase\": 4,\n      \"utxo_size_inc\": 303\n    }\n  ]\n}"
  },
  {
    "path": "test/functional/data/rpc_psbt.json",
    "content": "{\n    \"invalid\" : [\n        \"AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA==\",\n        \"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==\",\n        \"cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA=\",\n        \"cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==\",\n        \"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA\",\n        \"cHNidP8CAAFVAgAAAAEnmiMjpd+1H8RfIg+liw/BPh4zQnkqhdfjbNYzO1y8OQAAAAAA/////wGgWuoLAAAAABl2qRT/6cAGEJfMO2NvLLBGD6T8Qn0rRYisAAAAAAABASCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAIBACCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIQIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYwQwIgBCS1jv+qppThVZ6lyTu/1KiQZCJAVc3wcLZ3FGlELQcCH1yOsP6mUW1guKyzOtZO3mDoeFv7OqlLmb34YVHbmpoBAQQiACB3H9GK1FlmbdSfPVZOPbxC9MhHdONgraFoFqjtSI1WgQEFR1IhA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GIQPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvVKuIgYDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYQtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA==\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQIEACIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoECBQBHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriEGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb0QtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA==\",\n        \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAIAALsCAAAAAarXOTEBi9JfhK5AC2iEi+CdtwbqwqwYKYur7nGrZW+LAAAAAEhHMEQCIFj2/HxqM+GzFUjUgcgmwBW9MBNarULNZ3kNq2bSrSQ7AiBKHO0mBMZzW2OT5bQWkd14sA8MWUL7n3UYVvqpOBV9ugH+////AoDw+gIAAAAAF6kUD7lGNCFpa4LIM68kHHjBfdveSTSH0PIKJwEAAAAXqRQpynT4oI+BmZQoGFyXtdhS5AY/YYdlAAAAAQfaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n        \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAACBwDaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n        \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAggA2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n        \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA\",\n        \"cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A\",\n        \"cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A\",\n        \"cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A\",\n        \"cHNidP8BAHMCAAAAAbiWoY6pOQepFsEGhUPXaulX9rvye2NH+NrdlAHg+WgpAQAAAAD/////AkBLTAAAAAAAF6kUqWwXCcLM5BN2zoNqMNT5qMlIi7+HQEtMAAAAAAAXqRSVF/in2XNxAlN1OSxkyp0z+Wtg2YcAAAAAAAEBIBNssgAAAAAAF6kUamsvautR8hRlMRY6OKNTx03DK96HAQcXFgAUo8u1LWpHprjt/uENAwBpGZD0UH0BCGsCRzBEAiAONfH3DYiw67ZbylrsxCF/XXpVwyWBRgofyRbPslzvwgIgIKCsWw5sHSIPh1icNvcVLZLHWj6NA7Dk+4Os2pOnMbQBIQPGStfYHPtyhpV7zIWtn0Q4GXv5gK1zy/tnJ+cBXu4iiwABABYAFMwmJQEz+HDpBEEabxJ5PogPsqZRAAEAFgAUyCrGc3h3FYCmiIspbv2pSTKZ5jU\"\n    ],\n    \"valid\" : [\n        \"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA\",\n        \"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA\",\n        \"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA==\",\n        \"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=\",\n        \"cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriIGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GELSmumcAAACAAAAAgAQAAIAiBgPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvRC0prpnAAAAgAAAAIAFAACAAAA=\",\n        \"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==\"\n    ],\n    \"creator\" : [\n        {\n            \"inputs\" : [\n                {\n                    \"txid\":\"75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858\",\n                    \"vout\":0\n                },\n                {\n                    \"txid\":\"1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83\",\n                    \"vout\":1\n                }\n            ],\n            \"outputs\" : [\n                {\n                    \"bcrt1qmpwzkuwsqc9snjvgdt4czhjsnywa5yjdqpxskv\":1.49990000\n                },\n                {\n                    \"bcrt1qqzh2ngh97ru8dfvgma25d6r595wcwqy0cee4cc\": 1\n                }\n            ],\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA=\"\n        }\n    ],\n    \"signer\" : [\n        {\n            \"privkeys\" : [\n                \"cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr\",\n                \"cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d\"\n            ],\n            \"psbt\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\"\n        },\n        {\n            \"privkeys\" : [\n                \"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au\",\n                \"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE\"\n            ],\n            \"psbt\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\"\n        },\n        {\n            \"privkeys\" : [\n                \"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE\"\n            ],\n            \"psbt\" : \"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=\",\n            \"result\" : \"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=\"\n        },\n        {\n            \"privkeys\" : [\n                \"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au\",\n                \"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE\"\n            ],\n            \"psbt\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\"\n        },\n        {\n            \"privkeys\" : [\n                \"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au\",\n                \"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE\"\n            ],\n            \"psbt\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\"\n        },\n        {\n            \"privkeys\" : [\n                \"cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au\",\n                \"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE\"\n            ],\n            \"psbt\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\"\n        }\n    ],\n    \"combiner\" : [\n        {\n            \"combine\" : [\n                \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\",\n                \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\"\n            ],\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXRzBEAiBjGpif5zipKtAZhgIzEsGSFP4oArOeXLwaw2eIBsaSwwIgOdtsOHvSZ3Ft/bPU2NpQuOhdITMmunx9qqTAzkHrkiMBAQMEAQAAAAEER1IhApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/IQLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU211KuIgYClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8Q2QxqTwAAAIAAAACAAAAAgCIGAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXENkMak8AAACAAAAAgAEAAIAAAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IciAgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3EcwRAIgYut6VWEHp8c/RaxKtaHd329wdfsSdZaafzg+//eEvLICIAwF27dHDb8vCFV901bHMlwe0wkT6ZbNOECUXbEiKNpfASICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=\"\n        },\n        {\n            \"combine\" : [\n                \"cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwA=\",\n                \"cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA=\"\n            ],\n            \"result\" : \"cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8KDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PCg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA=\"\n        }\n    ],\n    \"finalizer\" : [\n        {\n            \"finalize\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA\",\n            \"result\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\"\n        }\n    ],\n    \"extractor\" : [\n        {\n            \"extract\" : \"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==\",\n            \"result\" : \"0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000\"\n        }\n    ]\n}"
  },
  {
    "path": "test/functional/example_test.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"An example functional test\n\nThe module-level docstring should include a high-level description of\nwhat the test is doing. It's the first thing people see when they open\nthe file and should give the reader information about *what* the test\nis testing and *how* it's being tested\n\"\"\"\n# Imports should be in PEP8 ordering (std library first, then third party\n# libraries then local imports).\nfrom collections import defaultdict\n\n# Avoid wildcard * imports\nfrom test_framework.blocktools import (create_block, create_coinbase)\nfrom test_framework.messages import CInv\nfrom test_framework.mininode import (\n    P2PInterface,\n    mininode_lock,\n    msg_block,\n    msg_getdata,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes,\n    wait_until,\n)\n\n# P2PInterface is a class containing callbacks to be executed when a P2P\n# message is received from the node-under-test. Subclass P2PInterface and\n# override the on_*() methods if you need custom behaviour.\nclass BaseNode(P2PInterface):\n    def __init__(self):\n        \"\"\"Initialize the P2PInterface\n\n        Used to initialize custom properties for the Node that aren't\n        included by default in the base class. Be aware that the P2PInterface\n        base class already stores a counter for each P2P message type and the\n        last received message of each type, which should be sufficient for the\n        needs of most tests.\n\n        Call super().__init__() first for standard initialization and then\n        initialize custom properties.\"\"\"\n        super().__init__()\n        # Stores a dictionary of all blocks received\n        self.block_receive_map = defaultdict(int)\n\n    def on_block(self, message):\n        \"\"\"Override the standard on_block callback\n\n        Store the hash of a received block in the dictionary.\"\"\"\n        message.block.calc_sha256()\n        self.block_receive_map[message.block.sha256] += 1\n\n    def on_inv(self, message):\n        \"\"\"Override the standard on_inv callback\"\"\"\n        pass\n\ndef custom_function():\n    \"\"\"Do some custom behaviour\n\n    If this function is more generally useful for other tests, consider\n    moving it to a module in test_framework.\"\"\"\n    # self.log.info(\"running custom_function\")  # Oops! Can't run self.log outside the MuntTestFramework\n    pass\n\n\nclass ExampleTest(MuntTestFramework):\n    # Each functional test is a subclass of the MuntTestFramework class.\n\n    # Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()\n    # and setup_nodes() methods to customize the test setup as required.\n\n    def set_test_params(self):\n        \"\"\"Override test parameters for your individual test.\n\n        This method must be overridden and num_nodes must be explicitly set.\"\"\"\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        # Use self.extra_args to change command-line arguments for the nodes\n        self.extra_args = [[], [\"-logips\"], []]\n\n        # self.log.info(\"I've finished set_test_params\")  # Oops! Can't run self.log before run_test()\n\n    # Use skip_test_if_missing_module() to skip the test if your test requires certain modules to be present.\n    # This test uses generate which requires wallet to be compiled\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    # Use add_options() to add specific command-line options for your test.\n    # In practice this is not used very much, since the tests are mostly written\n    # to be run in automated environments without command-line options.\n    # def add_options()\n    #     pass\n\n    # Use setup_chain() to customize the node data directories. In practice\n    # this is not used very much since the default behaviour is almost always\n    # fine\n    # def setup_chain():\n    #     pass\n\n    def setup_network(self):\n        \"\"\"Setup the test network topology\n\n        Often you won't need to override this, since the standard network topology\n        (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests.\n\n        If you do override this method, remember to start the nodes, assign\n        them to self.nodes, connect them and then sync.\"\"\"\n\n        self.setup_nodes()\n\n        # In this test, we're not connecting node2 to node0 or node1. Calls to\n        # sync_all() should not include node2, since we're not expecting it to\n        # sync.\n        connect_nodes(self.nodes[0], 1)\n        self.sync_all([self.nodes[0:2]])\n\n    # Use setup_nodes() to customize the node start behaviour (for example if\n    # you don't want to start all nodes at the start of the test).\n    # def setup_nodes():\n    #     pass\n\n    def custom_method(self):\n        \"\"\"Do some custom behaviour for this test\n\n        Define it in a method here because you're going to use it repeatedly.\n        If you think it's useful in general, consider moving it to the base\n        MuntTestFramework class so other tests can use it.\"\"\"\n\n        self.log.info(\"Running custom_method\")\n\n    def run_test(self):\n        \"\"\"Main test logic\"\"\"\n\n        # Create P2P connections will wait for a verack to make sure the connection is fully up\n        self.nodes[0].add_p2p_connection(BaseNode())\n\n        # Generating a block on one of the nodes will get us out of IBD\n        blocks = [int(self.nodes[0].generate(num_blocks=1)[0], 16)]\n        self.sync_all([self.nodes[0:2]])\n\n        # Notice above how we called an RPC by calling a method with the same\n        # name on the node object. Notice also how we used a keyword argument\n        # to specify a named RPC argument. Neither of those are defined on the\n        # node object. Instead there's some __getattr__() magic going on under\n        # the covers to dispatch unrecognised attribute calls to the RPC\n        # interface.\n\n        # Logs are nice. Do plenty of them. They can be used in place of comments for\n        # breaking the test into sub-sections.\n        self.log.info(\"Starting test!\")\n\n        self.log.info(\"Calling a custom function\")\n        custom_function()\n\n        self.log.info(\"Calling a custom method\")\n        self.custom_method()\n\n        self.log.info(\"Create some blocks\")\n        self.tip = int(self.nodes[0].getbestblockhash(), 16)\n        self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1\n\n        height = self.nodes[0].getblockcount()\n\n        for i in range(10):\n            # Use the mininode and blocktools functionality to manually build a block\n            # Calling the generate() rpc is easier, but this allows us to exactly\n            # control the blocks and transactions.\n            block = create_block(self.tip, create_coinbase(height+1), self.block_time)\n            block.solve()\n            block_message = msg_block(block)\n            # Send message is used to send a P2P message to the node over our P2PInterface\n            self.nodes[0].p2p.send_message(block_message)\n            self.tip = block.sha256\n            blocks.append(self.tip)\n            self.block_time += 1\n            height += 1\n\n        self.log.info(\"Wait for node1 to reach current tip (height 11) using RPC\")\n        self.nodes[1].waitforblockheight(11)\n\n        self.log.info(\"Connect node2 and node1\")\n        connect_nodes(self.nodes[1], 2)\n\n        self.log.info(\"Add P2P connection to node2\")\n        self.nodes[0].disconnect_p2ps()\n\n        self.nodes[2].add_p2p_connection(BaseNode())\n\n        self.log.info(\"Wait for node2 reach current tip. Test that it has propagated all the blocks to us\")\n\n        getdata_request = msg_getdata()\n        for block in blocks:\n            getdata_request.inv.append(CInv(2, block))\n        self.nodes[2].p2p.send_message(getdata_request)\n\n        # wait_until() will loop until a predicate condition is met. Use it to test properties of the\n        # P2PInterface objects.\n        wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock)\n\n        self.log.info(\"Check that each block was received only once\")\n        # The network thread uses a global lock on data access to the P2PConnection objects when sending and receiving\n        # messages. The test thread should acquire the global lock before accessing any P2PConnection data to avoid locking\n        # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.\n        with mininode_lock:\n            for block in self.nodes[2].p2p.block_receive_map.values():\n                assert_equal(block, 1)\n\nif __name__ == '__main__':\n    ExampleTest().main()\n"
  },
  {
    "path": "test/functional/feature_assumevalid.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test logic for skipping signature validation on old blocks.\n\nTest logic for skipping signature validation on blocks which we've assumed\nvalid (https://github.com/bitcoin/bitcoin/pull/9484)\n\nWe build a chain that includes and invalid signature for one of the\ntransactions:\n\n    0:        genesis block\n    1:        block 1 with coinbase transaction output.\n    2-101:    bury that block with 100 blocks so the coinbase transaction\n              output can be spent\n    102:      a block containing a transaction spending the coinbase\n              transaction output. The transaction has an invalid signature.\n    103-2202: bury the bad block with just over two weeks' worth of blocks\n              (2100 blocks)\n\nStart three nodes:\n\n    - node0 has no -assumevalid parameter. Try to sync to block 2202. It will\n      reject block 102 and only sync as far as block 101\n    - node1 has -assumevalid set to the hash of block 102. Try to sync to\n      block 2202. node1 will sync all the way to block 2202.\n    - node2 has -assumevalid set to the hash of block 102. Try to sync to\n      block 200. node2 will reject block 102 since it's assumed valid, but it\n      isn't buried by at least two weeks' work.\n\"\"\"\nimport time\n\nfrom test_framework.blocktools import (create_block, create_coinbase)\nfrom test_framework.key import CECKey\nfrom test_framework.messages import (\n    CBlockHeader,\n    COutPoint,\n    CTransaction,\n    CTxIn,\n    CTxOut,\n    msg_block,\n    msg_headers\n)\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.script import (CScript, OP_TRUE)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass BaseNode(P2PInterface):\n    def send_header_for_blocks(self, new_blocks):\n        headers_message = msg_headers()\n        headers_message.headers = [CBlockHeader(b) for b in new_blocks]\n        self.send_message(headers_message)\n\nclass AssumeValidTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n\n    def setup_network(self):\n        self.add_nodes(3)\n        # Start node0. We don't start the other nodes yet since\n        # we need to pre-mine a block with an invalid transaction\n        # signature so we can pass in the block hash as assumevalid.\n        self.start_node(0)\n\n    def send_blocks_until_disconnected(self, p2p_conn):\n        \"\"\"Keep sending blocks to the node until we're disconnected.\"\"\"\n        for i in range(len(self.blocks)):\n            if not p2p_conn.is_connected:\n                break\n            try:\n                p2p_conn.send_message(msg_block(self.blocks[i]))\n            except IOError as e:\n                assert not p2p_conn.is_connected\n                break\n\n    def assert_blockchain_height(self, node, height):\n        \"\"\"Wait until the blockchain is no longer advancing and verify it's reached the expected height.\"\"\"\n        last_height = node.getblock(node.getbestblockhash())['height']\n        timeout = 10\n        while True:\n            time.sleep(0.25)\n            current_height = node.getblock(node.getbestblockhash())['height']\n            if current_height != last_height:\n                last_height = current_height\n                if timeout < 0:\n                    assert False, \"blockchain too short after timeout: %d\" % current_height\n                timeout - 0.25\n                continue\n            elif current_height > height:\n                assert False, \"blockchain too long: %d\" % current_height\n            elif current_height == height:\n                break\n\n    def run_test(self):\n        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())\n\n        # Build the blockchain\n        self.tip = int(self.nodes[0].getbestblockhash(), 16)\n        self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1\n\n        self.blocks = []\n\n        # Get a pubkey for the coinbase TXO\n        coinbase_key = CECKey()\n        coinbase_key.set_secretbytes(b\"horsebattery\")\n        coinbase_pubkey = coinbase_key.get_pubkey()\n\n        # Create the first block with a coinbase output to our key\n        height = 1\n        block = create_block(self.tip, create_coinbase(height, coinbase_pubkey), self.block_time)\n        self.blocks.append(block)\n        self.block_time += 1\n        block.solve()\n        # Save the coinbase for later\n        self.block1 = block\n        self.tip = block.sha256\n        height += 1\n\n        # Bury the block 100 deep so the coinbase output is spendable\n        for i in range(100):\n            block = create_block(self.tip, create_coinbase(height), self.block_time)\n            block.solve()\n            self.blocks.append(block)\n            self.tip = block.sha256\n            self.block_time += 1\n            height += 1\n\n        # Create a transaction spending the coinbase output with an invalid (null) signature\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b\"\"))\n        tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))\n        tx.calc_sha256()\n\n        block102 = create_block(self.tip, create_coinbase(height), self.block_time)\n        self.block_time += 1\n        block102.vtx.extend([tx])\n        block102.hashMerkleRoot = block102.calc_merkle_root()\n        block102.rehash()\n        block102.solve()\n        self.blocks.append(block102)\n        self.tip = block102.sha256\n        self.block_time += 1\n        height += 1\n\n        # Bury the assumed valid block 2100 deep\n        for i in range(2100):\n            block = create_block(self.tip, create_coinbase(height), self.block_time)\n            block.nVersion = 4\n            block.solve()\n            self.blocks.append(block)\n            self.tip = block.sha256\n            self.block_time += 1\n            height += 1\n\n        self.nodes[0].disconnect_p2ps()\n\n        # Start node1 and node2 with assumevalid so they accept a block with a bad signature.\n        self.start_node(1, extra_args=[\"-assumevalid=\" + hex(block102.sha256)])\n        self.start_node(2, extra_args=[\"-assumevalid=\" + hex(block102.sha256)])\n\n        p2p0 = self.nodes[0].add_p2p_connection(BaseNode())\n        p2p1 = self.nodes[1].add_p2p_connection(BaseNode())\n        p2p2 = self.nodes[2].add_p2p_connection(BaseNode())\n\n        # send header lists to all three nodes\n        p2p0.send_header_for_blocks(self.blocks[0:2000])\n        p2p0.send_header_for_blocks(self.blocks[2000:])\n        p2p1.send_header_for_blocks(self.blocks[0:2000])\n        p2p1.send_header_for_blocks(self.blocks[2000:])\n        p2p2.send_header_for_blocks(self.blocks[0:200])\n\n        # Send blocks to node0. Block 102 will be rejected.\n        self.send_blocks_until_disconnected(p2p0)\n        self.assert_blockchain_height(self.nodes[0], 101)\n\n        # Send all blocks to node1. All blocks will be accepted.\n        for i in range(2202):\n            p2p1.send_message(msg_block(self.blocks[i]))\n        # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.\n        p2p1.sync_with_ping(200)\n        assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)\n\n        # Send blocks to node2. Block 102 will be rejected.\n        self.send_blocks_until_disconnected(p2p2)\n        self.assert_blockchain_height(self.nodes[2], 101)\n\nif __name__ == '__main__':\n    AssumeValidTest().main()\n"
  },
  {
    "path": "test/functional/feature_bip68_sequence.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test BIP68 implementation.\"\"\"\n\nimport time\n\nfrom test_framework.blocktools import create_block, create_coinbase, add_witness_commitment\nfrom test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex\nfrom test_framework.script import CScript\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, get_bip9_status, satoshi_round, sync_blocks\n\nSEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)\nSEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)\nSEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift\nSEQUENCE_LOCKTIME_MASK = 0x0000ffff\n\n# RPC error for non-BIP68 final transactions\nNOT_FINAL_ERROR = \"non-BIP68-final (code 64)\"\n\nclass BIP68Test(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [[], [\"-acceptnonstdtxn=0\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.relayfee = self.nodes[0].getnetworkinfo()[\"relayfee\"]\n\n        # Generate some coins\n        self.nodes[0].generate(110)\n\n        self.log.info(\"Running test disable flag\")\n        self.test_disable_flag()\n\n        self.log.info(\"Running test sequence-lock-confirmed-inputs\")\n        self.test_sequence_lock_confirmed_inputs()\n\n        self.log.info(\"Running test sequence-lock-unconfirmed-inputs\")\n        self.test_sequence_lock_unconfirmed_inputs()\n\n        self.log.info(\"Running test BIP68 not consensus before versionbits activation\")\n        self.test_bip68_not_consensus()\n\n        self.log.info(\"Activating BIP68 (and 112/113)\")\n        self.activateCSV()\n\n        self.log.info(\"Verifying nVersion=2 transactions are standard.\")\n        self.log.info(\"Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).\")\n        self.test_version2_relay()\n\n        self.log.info(\"Passed\")\n\n    # Test that BIP68 is not in effect if tx version is 1, or if\n    # the first sequence bit is set.\n    def test_disable_flag(self):\n        # Create some unconfirmed inputs\n        new_addr = self.nodes[0].getnewaddress()\n        self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC\n\n        utxos = self.nodes[0].listunspent(0, 0)\n        assert len(utxos) > 0\n\n        utxo = utxos[0]\n\n        tx1 = CTransaction()\n        value = int(satoshi_round(utxo[\"amount\"] - self.relayfee)*COIN)\n\n        # Check that the disable flag disables relative locktime.\n        # If sequence locks were used, this would require 1 block for the\n        # input to mature.\n        sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1\n        tx1.vin = [CTxIn(COutPoint(int(utxo[\"txid\"], 16), utxo[\"vout\"]), nSequence=sequence_value)]\n        tx1.vout = [CTxOut(value, CScript([b'a']))]\n\n        tx1_signed = self.nodes[0].signrawtransaction(ToHex(tx1))[\"hex\"]\n        tx1_id = self.nodes[0].sendrawtransaction(tx1_signed)\n        tx1_id = int(tx1_id, 16)\n\n        # This transaction will enable sequence-locks, so this transaction should\n        # fail\n        tx2 = CTransaction()\n        tx2.nVersion = 2\n        sequence_value = sequence_value & 0x7fffffff\n        tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)]\n        tx2.vout = [CTxOut(int(value - self.relayfee * COIN), CScript([b'a' * 35]))]\n        tx2.rehash()\n\n        assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))\n\n        # Setting the version back down to 1 should disable the sequence lock,\n        # so this should be accepted.\n        tx2.nVersion = 1\n\n        self.nodes[0].sendrawtransaction(ToHex(tx2))\n\n    # Calculate the median time past of a prior block (\"confirmations\" before\n    # the current tip).\n    def get_median_time_past(self, confirmations):\n        block_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount()-confirmations)\n        return self.nodes[0].getblockheader(block_hash)[\"mediantime\"]\n\n    # Test that sequence locks are respected for transactions spending confirmed inputs.\n    def test_sequence_lock_confirmed_inputs(self):\n        # Create lots of confirmed utxos, and use them to generate lots of random\n        # transactions.\n        max_outputs = 50\n        addresses = []\n        while len(addresses) < max_outputs:\n            addresses.append(self.nodes[0].getnewaddress())\n        while len(self.nodes[0].listunspent()) < 200:\n            import random\n            random.shuffle(addresses)\n            num_outputs = random.randint(1, max_outputs)\n            outputs = {}\n            for i in range(num_outputs):\n                outputs[addresses[i]] = random.randint(1, 20)*0.01\n            self.nodes[0].sendmany(\"\", outputs)\n            self.nodes[0].generate(1)\n\n        utxos = self.nodes[0].listunspent()\n\n        # Try creating a lot of random transactions.\n        # Each time, choose a random number of inputs, and randomly set\n        # some of those inputs to be sequence locked (and randomly choose\n        # between height/time locking). Small random chance of making the locks\n        # all pass.\n        for i in range(400):\n            # Randomly choose up to 10 inputs\n            num_inputs = random.randint(1, 10)\n            random.shuffle(utxos)\n\n            # Track whether any sequence locks used should fail\n            should_pass = True\n\n            # Track whether this transaction was built with sequence locks\n            using_sequence_locks = False\n\n            tx = CTransaction()\n            tx.nVersion = 2\n            value = 0\n            for j in range(num_inputs):\n                sequence_value = 0xfffffffe # this disables sequence locks\n\n                # 50% chance we enable sequence locks\n                if random.randint(0,1):\n                    using_sequence_locks = True\n\n                    # 10% of the time, make the input sequence value pass\n                    input_will_pass = (random.randint(1,10) == 1)\n                    sequence_value = utxos[j][\"confirmations\"]\n                    if not input_will_pass:\n                        sequence_value += 1\n                        should_pass = False\n\n                    # Figure out what the median-time-past was for the confirmed input\n                    # Note that if an input has N confirmations, we're going back N blocks\n                    # from the tip so that we're looking up MTP of the block\n                    # PRIOR to the one the input appears in, as per the BIP68 spec.\n                    orig_time = self.get_median_time_past(utxos[j][\"confirmations\"])\n                    cur_time = self.get_median_time_past(0) # MTP of the tip\n\n                    # can only timelock this input if it's not too old -- otherwise use height\n                    can_time_lock = True\n                    if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) >= SEQUENCE_LOCKTIME_MASK:\n                        can_time_lock = False\n\n                    # if time-lockable, then 50% chance we make this a time lock\n                    if random.randint(0,1) and can_time_lock:\n                        # Find first time-lock value that fails, or latest one that succeeds\n                        time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY\n                        if input_will_pass and time_delta > cur_time - orig_time:\n                            sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)\n                        elif (not input_will_pass and time_delta <= cur_time - orig_time):\n                            sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1\n                        sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG\n                tx.vin.append(CTxIn(COutPoint(int(utxos[j][\"txid\"], 16), utxos[j][\"vout\"]), nSequence=sequence_value))\n                value += utxos[j][\"amount\"]*COIN\n            # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output\n            tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50\n            tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))\n            rawtx = self.nodes[0].signrawtransaction(ToHex(tx))[\"hex\"]\n\n            if (using_sequence_locks and not should_pass):\n                # This transaction should be rejected\n                assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)\n            else:\n                # This raw transaction should be accepted\n                self.nodes[0].sendrawtransaction(rawtx)\n                utxos = self.nodes[0].listunspent()\n\n    # Test that sequence locks on unconfirmed inputs must have nSequence\n    # height or time of 0 to be accepted.\n    # Then test that BIP68-invalid transactions are removed from the mempool\n    # after a reorg.\n    def test_sequence_lock_unconfirmed_inputs(self):\n        # Store height so we can easily reset the chain at the end of the test\n        cur_height = self.nodes[0].getblockcount()\n\n        # Create a mempool tx.\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)\n        tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))\n        tx1.rehash()\n\n        # Anyone-can-spend mempool tx.\n        # Sequence lock of 0 should pass.\n        tx2 = CTransaction()\n        tx2.nVersion = 2\n        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]\n        tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]\n        tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))[\"hex\"]\n        tx2 = FromHex(tx2, tx2_raw)\n        tx2.rehash()\n\n        self.nodes[0].sendrawtransaction(tx2_raw)\n\n        # Create a spend of the 0th output of orig_tx with a sequence lock\n        # of 1, and test what happens when submitting.\n        # orig_tx.vout[0] must be an anyone-can-spend output\n        def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):\n            sequence_value = 1\n            if not use_height_lock:\n                sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG\n\n            tx = CTransaction()\n            tx.nVersion = 2\n            tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]\n            tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), CScript([b'a' * 35]))]\n            tx.rehash()\n\n            if (orig_tx.hash in node.getrawmempool()):\n                # sendrawtransaction should fail if the tx is in the mempool\n                assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))\n            else:\n                # sendrawtransaction should succeed if the tx is not in the mempool\n                node.sendrawtransaction(ToHex(tx))\n\n            return tx\n\n        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)\n        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)\n\n        # Now mine some blocks, but make sure tx2 doesn't get mined.\n        # Use prioritisetransaction to lower the effective feerate to 0\n        self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(-self.relayfee*COIN))\n        cur_time = int(time.time())\n        for i in range(10):\n            self.nodes[0].setmocktime(cur_time + 600)\n            self.nodes[0].generate(1)\n            cur_time += 600\n\n        assert tx2.hash in self.nodes[0].getrawmempool()\n\n        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)\n        test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)\n\n        # Mine tx2, and then try again\n        self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(self.relayfee*COIN))\n\n        # Advance the time on the node so that we can test timelocks\n        self.nodes[0].setmocktime(cur_time+600)\n        self.nodes[0].generate(1)\n        assert tx2.hash not in self.nodes[0].getrawmempool()\n\n        # Now that tx2 is not in the mempool, a sequence locked spend should\n        # succeed\n        tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)\n        assert tx3.hash in self.nodes[0].getrawmempool()\n\n        self.nodes[0].generate(1)\n        assert tx3.hash not in self.nodes[0].getrawmempool()\n\n        # One more test, this time using height locks\n        tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True)\n        assert tx4.hash in self.nodes[0].getrawmempool()\n\n        # Now try combining confirmed and unconfirmed inputs\n        tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)\n        assert tx5.hash not in self.nodes[0].getrawmempool()\n\n        utxos = self.nodes[0].listunspent()\n        tx5.vin.append(CTxIn(COutPoint(int(utxos[0][\"txid\"], 16), utxos[0][\"vout\"]), nSequence=1))\n        tx5.vout[0].nValue += int(utxos[0][\"amount\"]*COIN)\n        raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))[\"hex\"]\n\n        assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)\n\n        # Test mempool-BIP68 consistency after reorg\n        #\n        # State of the transactions in the last blocks:\n        # ... -> [ tx2 ] ->  [ tx3 ]\n        #         tip-1        tip\n        # And currently tx4 is in the mempool.\n        #\n        # If we invalidate the tip, tx3 should get added to the mempool, causing\n        # tx4 to be removed (fails sequence-lock).\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n        assert tx4.hash not in self.nodes[0].getrawmempool()\n        assert tx3.hash in self.nodes[0].getrawmempool()\n\n        # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in\n        # diagram above).\n        # This would cause tx2 to be added back to the mempool, which in turn causes\n        # tx3 to be removed.\n        tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16)\n        height = self.nodes[0].getblockcount()\n        for i in range(2):\n            block = create_block(tip, create_coinbase(height), cur_time)\n            block.nVersion = 3\n            block.rehash()\n            block.solve()\n            tip = block.sha256\n            height += 1\n            self.nodes[0].submitblock(ToHex(block))\n            cur_time += 1\n\n        mempool = self.nodes[0].getrawmempool()\n        assert tx3.hash not in mempool\n        assert tx2.hash in mempool\n\n        # Reset the chain and get rid of the mocktimed-blocks\n        self.nodes[0].setmocktime(0)\n        self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))\n        self.nodes[0].generate(10)\n\n    # Make sure that BIP68 isn't being used to validate blocks, prior to\n    # versionbits activation.  If more blocks are mined prior to this test\n    # being run, then it's possible the test has activated the soft fork, and\n    # this test should be moved to run earlier, or deleted.\n    def test_bip68_not_consensus(self):\n        assert get_bip9_status(self.nodes[0], 'csv')['status'] != 'active'\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)\n\n        tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))\n        tx1.rehash()\n\n        # Make an anyone-can-spend transaction\n        tx2 = CTransaction()\n        tx2.nVersion = 1\n        tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]\n        tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]\n\n        # sign tx2\n        tx2_raw = self.nodes[0].signrawtransaction(ToHex(tx2))[\"hex\"]\n        tx2 = FromHex(tx2, tx2_raw)\n        tx2.rehash()\n\n        self.nodes[0].sendrawtransaction(ToHex(tx2))\n\n        # Now make an invalid spend of tx2 according to BIP68\n        sequence_value = 100 # 100 block relative locktime\n\n        tx3 = CTransaction()\n        tx3.nVersion = 2\n        tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)]\n        tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), CScript([b'a' * 35]))]\n        tx3.rehash()\n\n        assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))\n\n        # make a block that violates bip68; ensure that the tip updates\n        tip = int(self.nodes[0].getbestblockhash(), 16)\n        block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1))\n        block.nVersion = 3\n        block.vtx.extend([tx1, tx2, tx3])\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.rehash()\n        add_witness_commitment(block)\n        block.solve()\n\n        self.nodes[0].submitblock(block.serialize(True).hex())\n        assert_equal(self.nodes[0].getbestblockhash(), block.hash)\n\n    def activateCSV(self):\n        # activation should happen at block height 432 (3 periods)\n        # getblockchaininfo will show CSV as active at block 431 (144 * 3 -1) since it's returning whether CSV is active for the next block.\n        min_activation_height = 432\n        height = self.nodes[0].getblockcount()\n        assert_greater_than(min_activation_height - height, 2)\n        self.nodes[0].generate(min_activation_height - height - 2)\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], \"locked_in\")\n        self.nodes[0].generate(1)\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], \"active\")\n        sync_blocks(self.nodes)\n\n    # Use self.nodes[1] to test that version 2 transactions are standard.\n    def test_version2_relay(self):\n        inputs = [ ]\n        outputs = { self.nodes[1].getnewaddress() : 1.0 }\n        rawtx = self.nodes[1].createrawtransaction(inputs, outputs)\n        rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex']\n        tx = FromHex(CTransaction(), rawtxfund)\n        tx.nVersion = 2\n        tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))[\"hex\"]\n        self.nodes[1].sendrawtransaction(tx_signed)\n\nif __name__ == '__main__':\n    BIP68Test().main()\n"
  },
  {
    "path": "test/functional/feature_block.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test block processing.\"\"\"\nimport copy\nimport struct\nimport time\n\nfrom test_framework.blocktools import (\n    create_block,\n    create_coinbase,\n    create_tx_with_script,\n    get_legacy_sigopcount_block,\n    MAX_BLOCK_SIGOPS,\n)\nfrom test_framework.key import CECKey\nfrom test_framework.messages import (\n    CBlock,\n    COIN,\n    COutPoint,\n    CTransaction,\n    CTxIn,\n    CTxOut,\n    MAX_BLOCK_BASE_SIZE,\n    uint256_from_compact,\n    uint256_from_str,\n)\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.script import (\n    CScript,\n    MAX_SCRIPT_ELEMENT_SIZE,\n    OP_2DUP,\n    OP_CHECKMULTISIG,\n    OP_CHECKMULTISIGVERIFY,\n    OP_CHECKSIG,\n    OP_CHECKSIGVERIFY,\n    OP_ELSE,\n    OP_ENDIF,\n    OP_EQUAL,\n    OP_DROP,\n    OP_FALSE,\n    OP_HASH160,\n    OP_IF,\n    OP_INVALIDOPCODE,\n    OP_RETURN,\n    OP_TRUE,\n    SIGHASH_ALL,\n    SignatureHash,\n    hash160,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\nfrom data import invalid_txs\n\n#  Use this class for tests that require behavior other than normal \"mininode\" behavior.\n#  For now, it is used to serialize a bloated varint (b64).\nclass CBrokenBlock(CBlock):\n    def initialize(self, base_block):\n        self.vtx = copy.deepcopy(base_block.vtx)\n        self.hashMerkleRoot = self.calc_merkle_root()\n\n    def serialize(self, with_witness=False):\n        r = b\"\"\n        r += super(CBlock, self).serialize()\n        r += struct.pack(\"<BQ\", 255, len(self.vtx))\n        for tx in self.vtx:\n            if with_witness:\n                r += tx.serialize_with_witness()\n            else:\n                r += tx.serialize_without_witness()\n        return r\n\n    def normal_serialize(self):\n        return super().serialize()\n\nclass FullBlockTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n        self.extra_args = [[]]\n\n    def run_test(self):\n        node = self.nodes[0]  # convenience reference to the node\n\n        self.bootstrap_p2p()  # Add one p2p connection to the node\n\n        self.block_heights = {}\n        self.coinbase_key = CECKey()\n        self.coinbase_key.set_secretbytes(b\"horsebattery\")\n        self.coinbase_pubkey = self.coinbase_key.get_pubkey()\n        self.tip = None\n        self.blocks = {}\n        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)\n        self.block_heights[self.genesis_hash] = 0\n        self.spendable_outputs = []\n\n        # Create a new block\n        b0 = self.next_block(0)\n        self.save_spendable_output()\n        self.sync_blocks([b0])\n\n        # These constants chosen specifically to trigger an immature coinbase spend\n        # at a certain time below.\n        NUM_BUFFER_BLOCKS_TO_GENERATE = 99\n        NUM_OUTPUTS_TO_COLLECT = 33\n\n        # Allow the block to mature\n        blocks = []\n        for i in range(NUM_BUFFER_BLOCKS_TO_GENERATE):\n            blocks.append(self.next_block(\"maturitybuffer.{}\".format(i)))\n            self.save_spendable_output()\n        self.sync_blocks(blocks)\n\n        # collect spendable outputs now to avoid cluttering the code later on\n        out = []\n        for i in range(NUM_OUTPUTS_TO_COLLECT):\n            out.append(self.get_spendable_output())\n\n        # Start by building a couple of blocks on top (which output is spent is\n        # in parentheses):\n        #     genesis -> b1 (0) -> b2 (1)\n        b1 = self.next_block(1, spend=out[0])\n        self.save_spendable_output()\n\n        b2 = self.next_block(2, spend=out[1])\n        self.save_spendable_output()\n\n        self.sync_blocks([b1, b2], timeout=4)\n\n        # Select a txn with an output eligible for spending. This won't actually be spent,\n        # since we're testing submission of a series of blocks with invalid txns.\n        attempt_spend_tx = out[2]\n\n        # Submit blocks for rejection, each of which contains a single transaction\n        # (aside from coinbase) which should be considered invalid.\n        for TxTemplate in invalid_txs.iter_all_templates():\n            template = TxTemplate(spend_tx=attempt_spend_tx)\n\n            if template.valid_in_block:\n                continue\n\n            self.log.info(\"Reject block with invalid tx: %s\", TxTemplate.__name__)\n            blockname = \"for_invalid.%s\" % TxTemplate.__name__\n            badblock = self.next_block(blockname)\n            badtx = template.get_tx()\n            if TxTemplate != invalid_txs.InputMissing:\n                self.sign_tx(badtx, attempt_spend_tx)\n            else:\n                # Segwit is active in regtest at this point, so to deserialize a\n                # transaction without any inputs correctly, we set the outputs\n                # to an empty list. This is a hack, as the serialization of an\n                # empty list of outputs is deserialized as flags==0 and thus\n                # deserialization of the outputs is skipped.\n                # A policy check requires \"loose\" txs to be of a minimum size,\n                # so vtx is not set to be empty in the TxTemplate class and we\n                # only apply the workaround where txs are not \"loose\", i.e. in\n                # blocks.\n                #\n                # The workaround has the purpose that both sides calculate\n                # the same tx hash in the merkle tree\n                badtx.vout = []\n            badtx.rehash()\n            badblock = self.update_block(blockname, [badtx])\n            self.sync_blocks(\n                [badblock], success=False,\n                reject_reason=(template.block_reject_reason or template.reject_reason),\n                reconnect=True, timeout=2)\n\n            self.move_tip(2)\n\n        # Fork like this:\n        #\n        #     genesis -> b1 (0) -> b2 (1)\n        #                      \\-> b3 (1)\n        #\n        # Nothing should happen at this point. We saw b2 first so it takes priority.\n        self.log.info(\"Don't reorg to a chain of the same length\")\n        self.move_tip(1)\n        b3 = self.next_block(3, spend=out[1])\n        txout_b3 = b3.vtx[1]\n        self.sync_blocks([b3], False)\n\n        # Now we add another block to make the alternative chain longer.\n        #\n        #     genesis -> b1 (0) -> b2 (1)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reorg to a longer chain\")\n        b4 = self.next_block(4, spend=out[2])\n        self.sync_blocks([b4])\n\n        # ... and back to the first chain.\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.move_tip(2)\n        b5 = self.next_block(5, spend=out[2])\n        self.save_spendable_output()\n        self.sync_blocks([b5], False)\n\n        self.log.info(\"Reorg back to the original chain\")\n        b6 = self.next_block(6, spend=out[3])\n        self.sync_blocks([b6], True)\n\n        # Try to create a fork that double-spends\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)\n        #                                          \\-> b7 (2) -> b8 (4)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a chain with a double spend, even if it is longer\")\n        self.move_tip(5)\n        b7 = self.next_block(7, spend=out[2])\n        self.sync_blocks([b7], False)\n\n        b8 = self.next_block(8, spend=out[4])\n        self.sync_blocks([b8], False, reconnect=True)\n\n        # Try to create a block that has too much fee\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)\n        #                                                    \\-> b9 (4)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block where the miner creates too much coinbase reward\")\n        self.move_tip(6)\n        b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)\n        self.sync_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)\n\n        # Create a fork that ends in a block with too much fee (the one that causes the reorg)\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b10 (3) -> b11 (4)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a chain where the miner creates too much coinbase reward, even if the chain is longer\")\n        self.move_tip(5)\n        b10 = self.next_block(10, spend=out[3])\n        self.sync_blocks([b10], False)\n\n        b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)\n        self.sync_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)\n\n        # Try again, but with a valid fork first\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b14 (5)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)\")\n        self.move_tip(5)\n        b12 = self.next_block(12, spend=out[3])\n        self.save_spendable_output()\n        b13 = self.next_block(13, spend=out[4])\n        self.save_spendable_output()\n        b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)\n        self.sync_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)\n\n        # New tip should be b13.\n        assert_equal(node.getbestblockhash(), b13.hash)\n\n        # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Accept a block with lots of checksigs\")\n        lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1))\n        self.move_tip(13)\n        b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)\n        self.save_spendable_output()\n        self.sync_blocks([b15], True)\n\n        self.log.info(\"Reject a block with too many checksigs\")\n        too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))\n        b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)\n        self.sync_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # Attempt to spend a transaction created on a different fork\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block with a spend from a re-org'ed out tx\")\n        self.move_tip(15)\n        b17 = self.next_block(17, spend=txout_b3)\n        self.sync_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # Attempt to spend a transaction created on a different fork (on a fork this time)\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5)\n        #                                                                \\-> b18 (b3.vtx[1]) -> b19 (6)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block with a spend from a re-org'ed out tx (on a forked chain)\")\n        self.move_tip(13)\n        b18 = self.next_block(18, spend=txout_b3)\n        self.sync_blocks([b18], False)\n\n        b19 = self.next_block(19, spend=out[6])\n        self.sync_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # Attempt to spend a coinbase at depth too low\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block spending an immature coinbase.\")\n        self.move_tip(15)\n        b20 = self.next_block(20, spend=out[7])\n        self.sync_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')\n\n        # Attempt to spend a coinbase at depth too low (on a fork this time)\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5)\n        #                                                                \\-> b21 (6) -> b22 (5)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block spending an immature coinbase (on a forked chain)\")\n        self.move_tip(13)\n        b21 = self.next_block(21, spend=out[6])\n        self.sync_blocks([b21], False)\n\n        b22 = self.next_block(22, spend=out[5])\n        self.sync_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')\n\n        # Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)\n        #                                                                           \\-> b24 (6) -> b25 (7)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Accept a block of size MAX_BLOCK_BASE_SIZE\")\n        self.move_tip(15)\n        b23 = self.next_block(23, spend=out[6])\n        tx = CTransaction()\n        script_length = MAX_BLOCK_BASE_SIZE - len(b23.serialize()) - 69\n        script_output = CScript([b'\\x00' * script_length])\n        tx.vout.append(CTxOut(0, script_output))\n        tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0)))\n        b23 = self.update_block(23, [tx])\n        # Make sure the math above worked out to produce a max-sized block\n        assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE)\n        self.sync_blocks([b23], True)\n        self.save_spendable_output()\n\n        self.log.info(\"Reject a block of size MAX_BLOCK_BASE_SIZE + 1\")\n        self.move_tip(15)\n        b24 = self.next_block(24, spend=out[6])\n        script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69\n        script_output = CScript([b'\\x00' * (script_length + 1)])\n        tx.vout = [CTxOut(0, script_output)]\n        b24 = self.update_block(24, [tx])\n        assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)\n        self.sync_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)\n\n        b25 = self.next_block(25, spend=out[7])\n        self.sync_blocks([b25], False)\n\n        # Create blocks with a coinbase input script size out of range\n        #     genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6  (3)\n        #                                          \\-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)\n        #                                                                           \\-> ... (6) -> ... (7)\n        #                      \\-> b3 (1) -> b4 (2)\n        self.log.info(\"Reject a block with coinbase input script size out of range\")\n        self.move_tip(15)\n        b26 = self.next_block(26, spend=out[6])\n        b26.vtx[0].vin[0].scriptSig = b'\\x00'\n        b26.vtx[0].rehash()\n        # update_block causes the merkle root to get updated, even with no new\n        # transactions, and updates the required state.\n        b26 = self.update_block(26, [])\n        self.sync_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)\n\n        # Extend the b26 chain to make sure Munt-daemon isn't accepting b26\n        b27 = self.next_block(27, spend=out[7])\n        self.sync_blocks([b27], False)\n\n        # Now try a too-large-coinbase script\n        self.move_tip(15)\n        b28 = self.next_block(28, spend=out[6])\n        b28.vtx[0].vin[0].scriptSig = b'\\x00' * 101\n        b28.vtx[0].rehash()\n        b28 = self.update_block(28, [])\n        self.sync_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)\n\n        # Extend the b28 chain to make sure Munt-daemon isn't accepting b28\n        b29 = self.next_block(29, spend=out[7])\n        self.sync_blocks([b29], False)\n\n        # b30 has a max-sized coinbase scriptSig.\n        self.move_tip(23)\n        b30 = self.next_block(30)\n        b30.vtx[0].vin[0].scriptSig = b'\\x00' * 100\n        b30.vtx[0].rehash()\n        b30 = self.update_block(30, [])\n        self.sync_blocks([b30], True)\n        self.save_spendable_output()\n\n        # b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY\n        #\n        #     genesis -> ... -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)\n        #                                                                \\-> b36 (11)\n        #                                                    \\-> b34 (10)\n        #                                         \\-> b32 (9)\n        #\n\n        # MULTISIG: each op code counts as 20 sigops.  To create the edge case, pack another 19 sigops at the end.\n        self.log.info(\"Accept a block with the max number of OP_CHECKMULTISIG sigops\")\n        lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)\n        b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)\n        assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS)\n        self.sync_blocks([b31], True)\n        self.save_spendable_output()\n\n        # this goes over the limit because the coinbase has one sigop\n        self.log.info(\"Reject a block with too many OP_CHECKMULTISIG sigops\")\n        too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))\n        b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)\n        assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)\n        self.sync_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # CHECKMULTISIGVERIFY\n        self.log.info(\"Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops\")\n        self.move_tip(31)\n        lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)\n        b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)\n        self.sync_blocks([b33], True)\n        self.save_spendable_output()\n\n        self.log.info(\"Reject a block with too many OP_CHECKMULTISIGVERIFY sigops\")\n        too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))\n        b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)\n        self.sync_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # CHECKSIGVERIFY\n        self.log.info(\"Accept a block with the max number of OP_CHECKSIGVERIFY sigops\")\n        self.move_tip(33)\n        lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1))\n        b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)\n        self.sync_blocks([b35], True)\n        self.save_spendable_output()\n\n        self.log.info(\"Reject a block with too many OP_CHECKSIGVERIFY sigops\")\n        too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))\n        b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)\n        self.sync_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # Check spending of a transaction in a block which failed to connect\n        #\n        # b6  (3)\n        # b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)\n        #                                                                                     \\-> b37 (11)\n        #                                                                                     \\-> b38 (11/37)\n        #\n\n        # save 37's spendable output, but then double-spend out11 to invalidate the block\n        self.log.info(\"Reject a block spending transaction from a block which failed to connect\")\n        self.move_tip(35)\n        b37 = self.next_block(37, spend=out[11])\n        txout_b37 = b37.vtx[1]\n        tx = self.create_and_sign_transaction(out[11], 0)\n        b37 = self.update_block(37, [tx])\n        self.sync_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid\n        self.move_tip(35)\n        b38 = self.next_block(38, spend=txout_b37)\n        self.sync_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # Check P2SH SigOp counting\n        #\n        #\n        #   13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b41 (12)\n        #                                                                                        \\-> b40 (12)\n        #\n        # b39 - create some P2SH outputs that will require 6 sigops to spend:\n        #\n        #           redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG\n        #           p2sh_script = OP_HASH160, ripemd160(sha256(script)), OP_EQUAL\n        #\n        self.log.info(\"Check P2SH SIGOPS are correctly counted\")\n        self.move_tip(35)\n        b39 = self.next_block(39)\n        b39_outputs = 0\n        b39_sigops_per_output = 6\n\n        # Build the redeem script, hash it, use hash to create the p2sh script\n        redeem_script = CScript([self.coinbase_pubkey] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG])\n        redeem_script_hash = hash160(redeem_script)\n        p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL])\n\n        # Create a transaction that spends one satoshi to the p2sh_script, the rest to OP_TRUE\n        # This must be signed because it is spending a coinbase\n        spend = out[11]\n        tx = self.create_tx(spend, 0, 1, p2sh_script)\n        tx.vout.append(CTxOut(spend.vout[0].nValue - 1, CScript([OP_TRUE])))\n        self.sign_tx(tx, spend)\n        tx.rehash()\n        b39 = self.update_block(39, [tx])\n        b39_outputs += 1\n\n        # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE\n        tx_new = None\n        tx_last = tx\n        total_size = len(b39.serialize())\n        while(total_size < MAX_BLOCK_BASE_SIZE):\n            tx_new = self.create_tx(tx_last, 1, 1, p2sh_script)\n            tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE])))\n            tx_new.rehash()\n            total_size += len(tx_new.serialize())\n            if total_size >= MAX_BLOCK_BASE_SIZE:\n                break\n            b39.vtx.append(tx_new)  # add tx to block\n            tx_last = tx_new\n            b39_outputs += 1\n\n        b39 = self.update_block(39, [])\n        self.sync_blocks([b39], True)\n        self.save_spendable_output()\n\n        # Test sigops in P2SH redeem scripts\n        #\n        # b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops.\n        # The first tx has one sigop and then at the end we add 2 more to put us just over the max.\n        #\n        # b41 does the same, less one, so it has the maximum sigops permitted.\n        #\n        self.log.info(\"Reject a block with too many P2SH sigops\")\n        self.move_tip(39)\n        b40 = self.next_block(40, spend=out[12])\n        sigops = get_legacy_sigopcount_block(b40)\n        numTxes = (MAX_BLOCK_SIGOPS - sigops) // b39_sigops_per_output\n        assert_equal(numTxes <= b39_outputs, True)\n\n        lastOutpoint = COutPoint(b40.vtx[1].sha256, 0)\n        new_txs = []\n        for i in range(1, numTxes + 1):\n            tx = CTransaction()\n            tx.vout.append(CTxOut(1, CScript([OP_TRUE])))\n            tx.vin.append(CTxIn(lastOutpoint, b''))\n            # second input is corresponding P2SH output from b39\n            tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b''))\n            # Note: must pass the redeem_script (not p2sh_script) to the signature hash function\n            (sighash, err) = SignatureHash(redeem_script, tx, 1, SIGHASH_ALL)\n            sig = self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))\n            scriptSig = CScript([sig, redeem_script])\n\n            tx.vin[1].scriptSig = scriptSig\n            tx.rehash()\n            new_txs.append(tx)\n            lastOutpoint = COutPoint(tx.sha256, 0)\n\n        b40_sigops_to_fill = MAX_BLOCK_SIGOPS - (numTxes * b39_sigops_per_output + sigops) + 1\n        tx = CTransaction()\n        tx.vin.append(CTxIn(lastOutpoint, b''))\n        tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill)))\n        tx.rehash()\n        new_txs.append(tx)\n        self.update_block(40, new_txs)\n        self.sync_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # same as b40, but one less sigop\n        self.log.info(\"Accept a block with the max number of P2SH sigops\")\n        self.move_tip(39)\n        b41 = self.next_block(41, spend=None)\n        self.update_block(41, b40.vtx[1:-1])\n        b41_sigops_to_fill = b40_sigops_to_fill - 1\n        tx = CTransaction()\n        tx.vin.append(CTxIn(lastOutpoint, b''))\n        tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill)))\n        tx.rehash()\n        self.update_block(41, [tx])\n        self.sync_blocks([b41], True)\n\n        # Fork off of b39 to create a constant base again\n        #\n        # b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13)\n        #                                                                  \\-> b41 (12)\n        #\n        self.move_tip(39)\n        b42 = self.next_block(42, spend=out[12])\n        self.save_spendable_output()\n\n        b43 = self.next_block(43, spend=out[13])\n        self.save_spendable_output()\n        self.sync_blocks([b42, b43], True)\n\n        # Test a number of really invalid scenarios\n        #\n        #  -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b44 (14)\n        #                                                                                   \\-> ??? (15)\n\n        # The next few blocks are going to be created \"by hand\" since they'll do funky things, such as having\n        # the first transaction be non-coinbase, etc.  The purpose of b44 is to make sure this works.\n        self.log.info(\"Build block 44 manually\")\n        height = self.block_heights[self.tip.sha256] + 1\n        coinbase = create_coinbase(height, self.coinbase_pubkey)\n        b44 = CBlock()\n        b44.nTime = self.tip.nTime + 1\n        b44.hashPrevBlock = self.tip.sha256\n        b44.nBits = 0x207fffff\n        b44.vtx.append(coinbase)\n        b44.hashMerkleRoot = b44.calc_merkle_root()\n        b44.solve()\n        self.tip = b44\n        self.block_heights[b44.sha256] = height\n        self.blocks[44] = b44\n        self.sync_blocks([b44], True)\n\n        self.log.info(\"Reject a block with a non-coinbase as the first tx\")\n        non_coinbase = self.create_tx(out[15], 0, 1)\n        b45 = CBlock()\n        b45.nTime = self.tip.nTime + 1\n        b45.hashPrevBlock = self.tip.sha256\n        b45.nBits = 0x207fffff\n        b45.vtx.append(non_coinbase)\n        b45.hashMerkleRoot = b45.calc_merkle_root()\n        b45.calc_sha256()\n        b45.solve()\n        self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1\n        self.tip = b45\n        self.blocks[45] = b45\n        self.sync_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)\n\n        self.log.info(\"Reject a block with no transactions\")\n        self.move_tip(44)\n        b46 = CBlock()\n        b46.nTime = b44.nTime + 1\n        b46.hashPrevBlock = b44.sha256\n        b46.nBits = 0x207fffff\n        b46.vtx = []\n        b46.hashMerkleRoot = 0\n        b46.solve()\n        self.block_heights[b46.sha256] = self.block_heights[b44.sha256] + 1\n        self.tip = b46\n        assert 46 not in self.blocks\n        self.blocks[46] = b46\n        self.sync_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)\n\n        self.log.info(\"Reject a block with invalid work\")\n        self.move_tip(44)\n        b47 = self.next_block(47, solve=False)\n        target = uint256_from_compact(b47.nBits)\n        while b47.sha256 < target:\n            b47.nNonce += 1\n            b47.rehash()\n        self.sync_blocks([b47], False, force_send=True, reject_reason='high-hash')\n\n        self.log.info(\"Reject a block with a timestamp >2 hours in the future\")\n        self.move_tip(44)\n        b48 = self.next_block(48, solve=False)\n        b48.nTime = int(time.time()) + 60 * 60 * 3\n        b48.solve()\n        self.sync_blocks([b48], False, force_send=True, reject_reason='time-too-new')\n\n        self.log.info(\"Reject a block with invalid merkle hash\")\n        self.move_tip(44)\n        b49 = self.next_block(49)\n        b49.hashMerkleRoot += 1\n        b49.solve()\n        self.sync_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)\n\n        self.log.info(\"Reject a block with incorrect POW limit\")\n        self.move_tip(44)\n        b50 = self.next_block(50)\n        b50.nBits = b50.nBits - 1\n        b50.solve()\n        self.sync_blocks([b50], False, force_send=True, reject_reason='bad-diffbits', reconnect=True)\n\n        self.log.info(\"Reject a block with two coinbase transactions\")\n        self.move_tip(44)\n        b51 = self.next_block(51)\n        cb2 = create_coinbase(51, self.coinbase_pubkey)\n        b51 = self.update_block(51, [cb2])\n        self.sync_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)\n\n        self.log.info(\"Reject a block with duplicate transactions\")\n        # Note: txns have to be in the right position in the merkle tree to trigger this error\n        self.move_tip(44)\n        b52 = self.next_block(52, spend=out[15])\n        tx = self.create_tx(b52.vtx[1], 0, 1)\n        b52 = self.update_block(52, [tx, tx])\n        self.sync_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)\n\n        # Test block timestamps\n        #  -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)\n        #                                                                                   \\-> b54 (15)\n        #\n        self.move_tip(43)\n        b53 = self.next_block(53, spend=out[14])\n        self.sync_blocks([b53], False)\n        self.save_spendable_output()\n\n        self.log.info(\"Reject a block with timestamp before MedianTimePast\")\n        b54 = self.next_block(54, spend=out[15])\n        b54.nTime = b35.nTime - 1\n        b54.solve()\n        self.sync_blocks([b54], False, force_send=True, reject_reason='time-too-old')\n\n        # valid timestamp\n        self.move_tip(53)\n        b55 = self.next_block(55, spend=out[15])\n        b55.nTime = b35.nTime\n        self.update_block(55, [])\n        self.sync_blocks([b55], True)\n        self.save_spendable_output()\n\n        # Test Merkle tree malleability\n        #\n        # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57p2 (16)\n        #                                                \\-> b57   (16)\n        #                                                \\-> b56p2 (16)\n        #                                                \\-> b56   (16)\n        #\n        # Merkle tree malleability (CVE-2012-2459): repeating sequences of transactions in a block without\n        #                           affecting the merkle root of a block, while still invalidating it.\n        #                           See:  src/consensus/merkle.h\n        #\n        #  b57 has three txns:  coinbase, tx, tx1.  The merkle root computation will duplicate tx.\n        #  Result:  OK\n        #\n        #  b56 copies b57 but duplicates tx1 and does not recalculate the block hash.  So it has a valid merkle\n        #  root but duplicate transactions.\n        #  Result:  Fails\n        #\n        #  b57p2 has six transactions in its merkle tree:\n        #       - coinbase, tx, tx1, tx2, tx3, tx4\n        #  Merkle root calculation will duplicate as necessary.\n        #  Result:  OK.\n        #\n        #  b56p2 copies b57p2 but adds both tx3 and tx4.  The purpose of the test is to make sure the code catches\n        #  duplicate txns that are not next to one another with the \"bad-txns-duplicate\" error (which indicates\n        #  that the error was caught early, avoiding a DOS vulnerability.)\n\n        # b57 - a good block with 2 txs, don't submit until end\n        self.move_tip(55)\n        b57 = self.next_block(57)\n        tx = self.create_and_sign_transaction(out[16], 1)\n        tx1 = self.create_tx(tx, 0, 1)\n        b57 = self.update_block(57, [tx, tx1])\n\n        # b56 - copy b57, add a duplicate tx\n        self.log.info(\"Reject a block with a duplicate transaction in the Merkle Tree (but with a valid Merkle Root)\")\n        self.move_tip(55)\n        b56 = copy.deepcopy(b57)\n        self.blocks[56] = b56\n        assert_equal(len(b56.vtx), 3)\n        b56 = self.update_block(56, [tx1])\n        assert_equal(b56.hash, b57.hash)\n        self.sync_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)\n\n        # b57p2 - a good block with 6 tx'es, don't submit until end\n        self.move_tip(55)\n        b57p2 = self.next_block(\"57p2\")\n        tx = self.create_and_sign_transaction(out[16], 1)\n        tx1 = self.create_tx(tx, 0, 1)\n        tx2 = self.create_tx(tx1, 0, 1)\n        tx3 = self.create_tx(tx2, 0, 1)\n        tx4 = self.create_tx(tx3, 0, 1)\n        b57p2 = self.update_block(\"57p2\", [tx, tx1, tx2, tx3, tx4])\n\n        # b56p2 - copy b57p2, duplicate two non-consecutive tx's\n        self.log.info(\"Reject a block with two duplicate transactions in the Merkle Tree (but with a valid Merkle Root)\")\n        self.move_tip(55)\n        b56p2 = copy.deepcopy(b57p2)\n        self.blocks[\"b56p2\"] = b56p2\n        assert_equal(b56p2.hash, b57p2.hash)\n        assert_equal(len(b56p2.vtx), 6)\n        b56p2 = self.update_block(\"b56p2\", [tx3, tx4])\n        self.sync_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)\n\n        self.move_tip(\"57p2\")\n        self.sync_blocks([b57p2], True)\n\n        self.move_tip(57)\n        self.sync_blocks([b57], False)  # The tip is not updated because 57p2 seen first\n        self.save_spendable_output()\n\n        # Test a few invalid tx types\n        #\n        # -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)\n        #                                                                                    \\-> ??? (17)\n        #\n\n        # tx with prevout.n out of range\n        self.log.info(\"Reject a block with a transaction with prevout.n out of range\")\n        self.move_tip(57)\n        b58 = self.next_block(58, spend=out[17])\n        tx = CTransaction()\n        assert len(out[17].vout) < 42\n        tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))\n        tx.vout.append(CTxOut(0, b\"\"))\n        tx.calc_sha256()\n        b58 = self.update_block(58, [tx])\n        self.sync_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # tx with output value > input value\n        self.log.info(\"Reject a block with a transaction with outputs > inputs\")\n        self.move_tip(57)\n        b59 = self.next_block(59)\n        tx = self.create_and_sign_transaction(out[17], 51 * COIN)\n        b59 = self.update_block(59, [tx])\n        self.sync_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)\n\n        # reset to good chain\n        self.move_tip(57)\n        b60 = self.next_block(60, spend=out[17])\n        self.sync_blocks([b60], True)\n        self.save_spendable_output()\n\n        # Test BIP30\n        #\n        # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)\n        #                                                                                    \\-> b61 (18)\n        #\n        # Blocks are not allowed to contain a transaction whose id matches that of an earlier,\n        # not-fully-spent transaction in the same chain. To test, make identical coinbases;\n        # the second one should be rejected.\n        #\n        self.log.info(\"Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)\")\n        self.move_tip(60)\n        b61 = self.next_block(61, spend=out[18])\n        b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig  # Equalize the coinbases\n        b61.vtx[0].rehash()\n        b61 = self.update_block(61, [])\n        assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())\n        self.sync_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)\n\n        # Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)\n        #\n        #   -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)\n        #                                                                                     \\-> b62 (18)\n        #\n        self.log.info(\"Reject a block with a transaction with a nonfinal locktime\")\n        self.move_tip(60)\n        b62 = self.next_block(62)\n        tx = CTransaction()\n        tx.nLockTime = 0xffffffff  # this locktime is non-final\n        tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0)))  # don't set nSequence\n        tx.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        assert tx.vin[0].nSequence < 0xffffffff\n        tx.calc_sha256()\n        b62 = self.update_block(62, [tx])\n        self.sync_blocks([b62], success=False, reject_reason='bad-txns-nonfinal')\n\n        # Test a non-final coinbase is also rejected\n        #\n        #   -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)\n        #                                                                                     \\-> b63 (-)\n        #\n        self.log.info(\"Reject a block with a coinbase transaction with a nonfinal locktime\")\n        self.move_tip(60)\n        b63 = self.next_block(63)\n        b63.vtx[0].nLockTime = 0xffffffff\n        b63.vtx[0].vin[0].nSequence = 0xDEADBEEF\n        b63.vtx[0].rehash()\n        b63 = self.update_block(63, [])\n        self.sync_blocks([b63], success=False, reject_reason='bad-txns-nonfinal')\n\n        #  This checks that a block with a bloated VARINT between the block_header and the array of tx such that\n        #  the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,\n        #  does not cause a subsequent, identical block with canonical encoding to be rejected.  The test does not\n        #  care whether the bloated block is accepted or rejected; it only cares that the second block is accepted.\n        #\n        #  What matters is that the receiving node should not reject the bloated block, and then reject the canonical\n        #  block on the basis that it's the same as an already-rejected block (which would be a consensus failure.)\n        #\n        #  -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18)\n        #                                                                                        \\\n        #                                                                                         b64a (18)\n        #  b64a is a bloated block (non-canonical varint)\n        #  b64 is a good block (same as b64 but w/ canonical varint)\n        #\n        self.log.info(\"Accept a valid block even if a bloated version of the block has previously been sent\")\n        self.move_tip(60)\n        regular_block = self.next_block(\"64a\", spend=out[18])\n\n        # make it a \"broken_block,\" with non-canonical serialization\n        b64a = CBrokenBlock(regular_block)\n        b64a.initialize(regular_block)\n        self.blocks[\"64a\"] = b64a\n        self.tip = b64a\n        tx = CTransaction()\n\n        # use canonical serialization to calculate size\n        script_length = MAX_BLOCK_BASE_SIZE - len(b64a.normal_serialize()) - 69\n        script_output = CScript([b'\\x00' * script_length])\n        tx.vout.append(CTxOut(0, script_output))\n        tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))\n        b64a = self.update_block(\"64a\", [tx])\n        assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)\n        self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')\n\n        # Munt-daemon doesn't disconnect us for sending a bloated block, but if we subsequently\n        # resend the header message, it won't send us the getdata message again. Just\n        # disconnect and reconnect and then call sync_blocks.\n        # TODO: improve this test to be less dependent on P2P DOS behaviour.\n        node.disconnect_p2ps()\n        self.reconnect_p2p()\n\n        self.move_tip(60)\n        b64 = CBlock(b64a)\n        b64.vtx = copy.deepcopy(b64a.vtx)\n        assert_equal(b64.hash, b64a.hash)\n        assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE)\n        self.blocks[64] = b64\n        b64 = self.update_block(64, [])\n        self.sync_blocks([b64], True)\n        self.save_spendable_output()\n\n        # Spend an output created in the block itself\n        #\n        # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)\n        #\n        self.log.info(\"Accept a block with a transaction spending an output created in the same block\")\n        self.move_tip(64)\n        b65 = self.next_block(65)\n        tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)\n        tx2 = self.create_and_sign_transaction(tx1, 0)\n        b65 = self.update_block(65, [tx1, tx2])\n        self.sync_blocks([b65], True)\n        self.save_spendable_output()\n\n        # Attempt to spend an output created later in the same block\n        #\n        # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)\n        #                                                                                    \\-> b66 (20)\n        self.log.info(\"Reject a block with a transaction spending an output created later in the same block\")\n        self.move_tip(65)\n        b66 = self.next_block(66)\n        tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)\n        tx2 = self.create_and_sign_transaction(tx1, 1)\n        b66 = self.update_block(66, [tx2, tx1])\n        self.sync_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # Attempt to double-spend a transaction created in a block\n        #\n        # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)\n        #                                                                                    \\-> b67 (20)\n        #\n        #\n        self.log.info(\"Reject a block with a transaction double spending a transaction created in the same block\")\n        self.move_tip(65)\n        b67 = self.next_block(67)\n        tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)\n        tx2 = self.create_and_sign_transaction(tx1, 1)\n        tx3 = self.create_and_sign_transaction(tx1, 2)\n        b67 = self.update_block(67, [tx1, tx2, tx3])\n        self.sync_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # More tests of block subsidy\n        #\n        # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)\n        #                                                                                    \\-> b68 (20)\n        #\n        # b68 - coinbase with an extra 10 satoshis,\n        #       creates a tx that has 9 satoshis from out[20] go to fees\n        #       this fails because the coinbase is trying to claim 1 satoshi too much in fees\n        #\n        # b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee\n        #       this succeeds\n        #\n        self.log.info(\"Reject a block trying to claim too much subsidy in the coinbase transaction\")\n        self.move_tip(65)\n        b68 = self.next_block(68, additional_coinbase_value=10)\n        tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)\n        b68 = self.update_block(68, [tx])\n        self.sync_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)\n\n        self.log.info(\"Accept a block claiming the correct subsidy in the coinbase transaction\")\n        self.move_tip(65)\n        b69 = self.next_block(69, additional_coinbase_value=10)\n        tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 10)\n        self.update_block(69, [tx])\n        self.sync_blocks([b69], True)\n        self.save_spendable_output()\n\n        # Test spending the outpoint of a non-existent transaction\n        #\n        # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)\n        #                                                                                    \\-> b70 (21)\n        #\n        self.log.info(\"Reject a block containing a transaction spending from a non-existent input\")\n        self.move_tip(69)\n        b70 = self.next_block(70, spend=out[21])\n        bogus_tx = CTransaction()\n        bogus_tx.sha256 = uint256_from_str(b\"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c\")\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b\"\", 0xffffffff))\n        tx.vout.append(CTxOut(1, b\"\"))\n        b70 = self.update_block(70, [tx])\n        self.sync_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        # Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)\n        #\n        #  -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21)\n        #                                                                                      \\-> b71 (21)\n        #\n        # b72 is a good block.\n        # b71 is a copy of 72, but re-adds one of its transactions.  However, it has the same hash as b72.\n        self.log.info(\"Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability\")\n        self.move_tip(69)\n        b72 = self.next_block(72)\n        tx1 = self.create_and_sign_transaction(out[21], 2)\n        tx2 = self.create_and_sign_transaction(tx1, 1)\n        b72 = self.update_block(72, [tx1, tx2])  # now tip is 72\n        b71 = copy.deepcopy(b72)\n        b71.vtx.append(tx2)   # add duplicate tx2\n        self.block_heights[b71.sha256] = self.block_heights[b69.sha256] + 1  # b71 builds off b69\n        self.blocks[71] = b71\n\n        assert_equal(len(b71.vtx), 4)\n        assert_equal(len(b72.vtx), 3)\n        assert_equal(b72.sha256, b71.sha256)\n\n        self.move_tip(71)\n        self.sync_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)\n\n        self.move_tip(72)\n        self.sync_blocks([b72], True)\n        self.save_spendable_output()\n\n        # Test some invalid scripts and MAX_BLOCK_SIGOPS\n        #\n        # -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21)\n        #                                                                                    \\-> b** (22)\n        #\n\n        # b73 - tx with excessive sigops that are placed after an excessively large script element.\n        #       The purpose of the test is to make sure those sigops are counted.\n        #\n        #       script is a bytearray of size 20,526\n        #\n        #       bytearray[0-19,998]     : OP_CHECKSIG\n        #       bytearray[19,999]       : OP_PUSHDATA4\n        #       bytearray[20,000-20,003]: 521  (max_script_element_size+1, in little-endian format)\n        #       bytearray[20,004-20,525]: unread data (script_element)\n        #       bytearray[20,526]       : OP_CHECKSIG (this puts us over the limit)\n        self.log.info(\"Reject a block containing too many sigops after a large script element\")\n        self.move_tip(72)\n        b73 = self.next_block(73)\n        size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1\n        a = bytearray([OP_CHECKSIG] * size)\n        a[MAX_BLOCK_SIGOPS - 1] = int(\"4e\", 16)  # OP_PUSHDATA4\n\n        element_size = MAX_SCRIPT_ELEMENT_SIZE + 1\n        a[MAX_BLOCK_SIGOPS] = element_size % 256\n        a[MAX_BLOCK_SIGOPS + 1] = element_size // 256\n        a[MAX_BLOCK_SIGOPS + 2] = 0\n        a[MAX_BLOCK_SIGOPS + 3] = 0\n\n        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))\n        b73 = self.update_block(73, [tx])\n        assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)\n        self.sync_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        # b74/75 - if we push an invalid script element, all previous sigops are counted,\n        #          but sigops after the element are not counted.\n        #\n        #       The invalid script element is that the push_data indicates that\n        #       there will be a large amount of data (0xffffff bytes), but we only\n        #       provide a much smaller number.  These bytes are CHECKSIGS so they would\n        #       cause b75 to fail for excessive sigops, if those bytes were counted.\n        #\n        #       b74 fails because we put MAX_BLOCK_SIGOPS+1 before the element\n        #       b75 succeeds because we put MAX_BLOCK_SIGOPS before the element\n        self.log.info(\"Check sigops are counted correctly after an invalid script element\")\n        self.move_tip(72)\n        b74 = self.next_block(74)\n        size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42  # total = 20,561\n        a = bytearray([OP_CHECKSIG] * size)\n        a[MAX_BLOCK_SIGOPS] = 0x4e\n        a[MAX_BLOCK_SIGOPS + 1] = 0xfe\n        a[MAX_BLOCK_SIGOPS + 2] = 0xff\n        a[MAX_BLOCK_SIGOPS + 3] = 0xff\n        a[MAX_BLOCK_SIGOPS + 4] = 0xff\n        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))\n        b74 = self.update_block(74, [tx])\n        self.sync_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)\n\n        self.move_tip(72)\n        b75 = self.next_block(75)\n        size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42\n        a = bytearray([OP_CHECKSIG] * size)\n        a[MAX_BLOCK_SIGOPS - 1] = 0x4e\n        a[MAX_BLOCK_SIGOPS] = 0xff\n        a[MAX_BLOCK_SIGOPS + 1] = 0xff\n        a[MAX_BLOCK_SIGOPS + 2] = 0xff\n        a[MAX_BLOCK_SIGOPS + 3] = 0xff\n        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))\n        b75 = self.update_block(75, [tx])\n        self.sync_blocks([b75], True)\n        self.save_spendable_output()\n\n        # Check that if we push an element filled with CHECKSIGs, they are not counted\n        self.move_tip(75)\n        b76 = self.next_block(76)\n        size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5\n        a = bytearray([OP_CHECKSIG] * size)\n        a[MAX_BLOCK_SIGOPS - 1] = 0x4e  # PUSHDATA4, but leave the following bytes as just checksigs\n        tx = self.create_and_sign_transaction(out[23], 1, CScript(a))\n        b76 = self.update_block(76, [tx])\n        self.sync_blocks([b76], True)\n        self.save_spendable_output()\n\n        # Test transaction resurrection\n        #\n        # -> b77 (24) -> b78 (25) -> b79 (26)\n        #            \\-> b80 (25) -> b81 (26) -> b82 (27)\n        #\n        #    b78 creates a tx, which is spent in b79. After b82, both should be in mempool\n        #\n        #    The tx'es must be unsigned and pass the node's mempool policy.  It is unsigned for the\n        #    rather obscure reason that the Python signature code does not distinguish between\n        #    Low-S and High-S values (whereas the Munt code has custom code which does so);\n        #    as a result of which, the odds are 50% that the python code will use the right\n        #    value and the transaction will be accepted into the mempool. Until we modify the\n        #    test framework to support low-S signing, we are out of luck.\n        #\n        #    To get around this issue, we construct transactions which are not signed and which\n        #    spend to OP_TRUE.  If the standard-ness rules change, this test would need to be\n        #    updated.  (Perhaps to spend to a P2SH OP_TRUE script)\n        self.log.info(\"Test transaction resurrection during a re-org\")\n        self.move_tip(76)\n        b77 = self.next_block(77)\n        tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)\n        b77 = self.update_block(77, [tx77])\n        self.sync_blocks([b77], True)\n        self.save_spendable_output()\n\n        b78 = self.next_block(78)\n        tx78 = self.create_tx(tx77, 0, 9 * COIN)\n        b78 = self.update_block(78, [tx78])\n        self.sync_blocks([b78], True)\n\n        b79 = self.next_block(79)\n        tx79 = self.create_tx(tx78, 0, 8 * COIN)\n        b79 = self.update_block(79, [tx79])\n        self.sync_blocks([b79], True)\n\n        # mempool should be empty\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n\n        self.move_tip(77)\n        b80 = self.next_block(80, spend=out[25])\n        self.sync_blocks([b80], False, force_send=True)\n        self.save_spendable_output()\n\n        b81 = self.next_block(81, spend=out[26])\n        self.sync_blocks([b81], False, force_send=True)  # other chain is same length\n        self.save_spendable_output()\n\n        b82 = self.next_block(82, spend=out[27])\n        self.sync_blocks([b82], True)  # now this chain is longer, triggers re-org\n        self.save_spendable_output()\n\n        # now check that tx78 and tx79 have been put back into the peer's mempool\n        mempool = self.nodes[0].getrawmempool()\n        assert_equal(len(mempool), 2)\n        assert tx78.hash in mempool\n        assert tx79.hash in mempool\n\n        # Test invalid opcodes in dead execution paths.\n        #\n        #  -> b81 (26) -> b82 (27) -> b83 (28)\n        #\n        self.log.info(\"Accept a block with invalid opcodes in dead execution paths\")\n        b83 = self.next_block(83)\n        op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]\n        script = CScript(op_codes)\n        tx1 = self.create_and_sign_transaction(out[28], out[28].vout[0].nValue, script)\n\n        tx2 = self.create_and_sign_transaction(tx1, 0, CScript([OP_TRUE]))\n        tx2.vin[0].scriptSig = CScript([OP_FALSE])\n        tx2.rehash()\n\n        b83 = self.update_block(83, [tx1, tx2])\n        self.sync_blocks([b83], True)\n        self.save_spendable_output()\n\n        # Reorg on/off blocks that have OP_RETURN in them (and try to spend them)\n        #\n        #  -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31)\n        #                                    \\-> b85 (29) -> b86 (30)            \\-> b89a (32)\n        #\n        self.log.info(\"Test re-orging blocks with OP_RETURN in them\")\n        b84 = self.next_block(84)\n        tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))\n        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        tx1.calc_sha256()\n        self.sign_tx(tx1, out[29])\n        tx1.rehash()\n        tx2 = self.create_tx(tx1, 1, 0, CScript([OP_RETURN]))\n        tx2.vout.append(CTxOut(0, CScript([OP_RETURN])))\n        tx3 = self.create_tx(tx1, 2, 0, CScript([OP_RETURN]))\n        tx3.vout.append(CTxOut(0, CScript([OP_TRUE])))\n        tx4 = self.create_tx(tx1, 3, 0, CScript([OP_TRUE]))\n        tx4.vout.append(CTxOut(0, CScript([OP_RETURN])))\n        tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN]))\n\n        b84 = self.update_block(84, [tx1, tx2, tx3, tx4, tx5])\n        self.sync_blocks([b84], True)\n        self.save_spendable_output()\n\n        self.move_tip(83)\n        b85 = self.next_block(85, spend=out[29])\n        self.sync_blocks([b85], False)  # other chain is same length\n\n        b86 = self.next_block(86, spend=out[30])\n        self.sync_blocks([b86], True)\n\n        self.move_tip(84)\n        b87 = self.next_block(87, spend=out[30])\n        self.sync_blocks([b87], False)  # other chain is same length\n        self.save_spendable_output()\n\n        b88 = self.next_block(88, spend=out[31])\n        self.sync_blocks([b88], True)\n        self.save_spendable_output()\n\n        # trying to spend the OP_RETURN output is rejected\n        b89a = self.next_block(\"89a\", spend=out[32])\n        tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))\n        b89a = self.update_block(\"89a\", [tx])\n        self.sync_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)\n\n        self.log.info(\"Test a re-org of one week's worth of blocks (1088 blocks)\")\n\n        self.move_tip(88)\n        LARGE_REORG_SIZE = 1088\n        blocks = []\n        spend = out[32]\n        for i in range(89, LARGE_REORG_SIZE + 89):\n            b = self.next_block(i, spend, version=4)\n            tx = CTransaction()\n            script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69\n            script_output = CScript([b'\\x00' * script_length])\n            tx.vout.append(CTxOut(0, script_output))\n            tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))\n            b = self.update_block(i, [tx])\n            assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE)\n            blocks.append(b)\n            self.save_spendable_output()\n            spend = self.get_spendable_output()\n\n        self.sync_blocks(blocks, True, timeout=480)\n        chain1_tip = i\n\n        # now create alt chain of same length\n        self.move_tip(88)\n        blocks2 = []\n        for i in range(89, LARGE_REORG_SIZE + 89):\n            blocks2.append(self.next_block(\"alt\" + str(i), version=4))\n        self.sync_blocks(blocks2, False, force_send=True)\n\n        # extend alt chain to trigger re-org\n        block = self.next_block(\"alt\" + str(chain1_tip + 1), version=4)\n        self.sync_blocks([block], True, timeout=480)\n\n        # ... and re-org back to the first chain\n        self.move_tip(chain1_tip)\n        block = self.next_block(chain1_tip + 1, version=4)\n        self.sync_blocks([block], False, force_send=True)\n        block = self.next_block(chain1_tip + 2, version=4)\n        self.sync_blocks([block], True, timeout=480)\n\n        self.log.info(\"Reject a block with an invalid block header version\")\n        b_v1 = self.next_block('b_v1', version=1)\n        self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)')\n\n        self.move_tip(chain1_tip + 2)\n        b_cb34 = self.next_block('b_cb34', version=4)\n        b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1]\n        b_cb34.vtx[0].rehash()\n        b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()\n        b_cb34.solve()\n        self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True)\n\n    # Helper methods\n    ################\n\n    def add_transactions_to_block(self, block, tx_list):\n        [tx.rehash() for tx in tx_list]\n        block.vtx.extend(tx_list)\n\n    # this is a little handier to use than the version in blocktools.py\n    def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])):\n        return create_tx_with_script(spend_tx, n, amount=value, script_pub_key=script)\n\n    # sign a transaction, using the key we know about\n    # this signs input 0 in tx, which is assumed to be spending output n in spend_tx\n    def sign_tx(self, tx, spend_tx):\n        scriptPubKey = bytearray(spend_tx.vout[0].scriptPubKey)\n        if (scriptPubKey[0] == OP_TRUE):  # an anyone-can-spend\n            tx.vin[0].scriptSig = CScript()\n            return\n        (sighash, err) = SignatureHash(spend_tx.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL)\n        tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])\n\n    def create_and_sign_transaction(self, spend_tx, value, script=CScript([OP_TRUE])):\n        tx = self.create_tx(spend_tx, 0, value, script)\n        self.sign_tx(tx, spend_tx)\n        tx.rehash()\n        return tx\n\n    def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1):\n        if self.tip is None:\n            base_block_hash = self.genesis_hash\n            block_time = int(time.time()) + 1\n        else:\n            base_block_hash = self.tip.sha256\n            block_time = self.tip.nTime + 1\n        # First create the coinbase\n        height = self.block_heights[base_block_hash] + 1\n        coinbase = create_coinbase(height, self.coinbase_pubkey)\n        coinbase.vout[0].nValue += additional_coinbase_value\n        coinbase.rehash()\n        if spend is None:\n            block = create_block(base_block_hash, coinbase, block_time, version=version)\n        else:\n            coinbase.vout[0].nValue += spend.vout[0].nValue - 1  # all but one satoshi to fees\n            coinbase.rehash()\n            block = create_block(base_block_hash, coinbase, block_time, version=version)\n            tx = self.create_tx(spend, 0, 1, script)  # spend 1 satoshi\n            self.sign_tx(tx, spend)\n            self.add_transactions_to_block(block, [tx])\n            block.hashMerkleRoot = block.calc_merkle_root()\n        if solve:\n            block.solve()\n        self.tip = block\n        self.block_heights[block.sha256] = height\n        assert number not in self.blocks\n        self.blocks[number] = block\n        return block\n\n    # save the current tip so it can be spent by a later block\n    def save_spendable_output(self):\n        self.log.debug(\"saving spendable output %s\" % self.tip.vtx[0])\n        self.spendable_outputs.append(self.tip)\n\n    # get an output that we previously marked as spendable\n    def get_spendable_output(self):\n        self.log.debug(\"getting spendable output %s\" % self.spendable_outputs[0].vtx[0])\n        return self.spendable_outputs.pop(0).vtx[0]\n\n    # move the tip back to a previous block\n    def move_tip(self, number):\n        self.tip = self.blocks[number]\n\n    # adds transactions to the block and updates state\n    def update_block(self, block_number, new_transactions):\n        block = self.blocks[block_number]\n        self.add_transactions_to_block(block, new_transactions)\n        old_sha256 = block.sha256\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n        # Update the internal state just like in next_block\n        self.tip = block\n        if block.sha256 != old_sha256:\n            self.block_heights[block.sha256] = self.block_heights[old_sha256]\n            del self.block_heights[old_sha256]\n        self.blocks[block_number] = block\n        return block\n\n    def bootstrap_p2p(self, timeout=10):\n        \"\"\"Add a P2P connection to the node.\n\n        Helper to connect and wait for version handshake.\"\"\"\n        self.nodes[0].add_p2p_connection(P2PDataStore())\n        # We need to wait for the initial getheaders from the peer before we\n        # start populating our blockstore. If we don't, then we may run ahead\n        # to the next subtest before we receive the getheaders. We'd then send\n        # an INV for the next block and receive two getheaders - one for the\n        # IBD and one for the INV. We'd respond to both and could get\n        # unexpectedly disconnected if the DoS score for that error is 50.\n        self.nodes[0].p2p.wait_for_getheaders(timeout=timeout)\n\n    def reconnect_p2p(self, timeout=60):\n        \"\"\"Tear down and bootstrap the P2P connection to the node.\n\n        The node gets disconnected several times in this test. This helper\n        method reconnects the p2p and restarts the network thread.\"\"\"\n        self.nodes[0].disconnect_p2ps()\n        self.bootstrap_p2p(timeout=timeout)\n\n    def sync_blocks(self, blocks, success=True, reject_reason=None, force_send=False, reconnect=False, timeout=60):\n        \"\"\"Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.\n\n        Call with success = False if the tip shouldn't advance to the most recent block.\"\"\"\n        self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect)\n\n        if reconnect:\n            self.reconnect_p2p(timeout=timeout)\n\n\nif __name__ == '__main__':\n    FullBlockTest().main()\n"
  },
  {
    "path": "test/functional/feature_blocksdir.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the blocksdir option.\n\"\"\"\n\nimport os\nimport shutil\n\nfrom test_framework.test_framework import MuntTestFramework, initialize_datadir\n\n\nclass BlocksdirTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def run_test(self):\n        self.stop_node(0)\n        assert os.path.isdir(os.path.join(self.nodes[0].datadir, \"regtestlegacy\", \"blocks\"))\n        assert not os.path.isdir(os.path.join(self.nodes[0].datadir, \"blocks\"))\n        shutil.rmtree(self.nodes[0].datadir)\n        initialize_datadir(self.options.tmpdir, 0)\n        self.log.info(\"Starting with nonexistent blocksdir ...\")\n        blocksdir_path = os.path.join(self.options.tmpdir, 'blocksdir')\n        self.nodes[0].assert_start_raises_init_error([\"-blocksdir=\" + blocksdir_path], 'Error: Specified blocks directory \"{}\" does not exist.'.format(blocksdir_path))\n        os.mkdir(blocksdir_path)\n        self.log.info(\"Starting with existing blocksdir ...\")\n        self.start_node(0, [\"-blocksdir=\" + blocksdir_path])\n        self.log.info(\"mining blocks..\")\n        self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)\n        assert os.path.isfile(os.path.join(blocksdir_path, \"regtestlegacy\", \"blocks\", \"blk00000.dat\"))\n        assert os.path.isdir(os.path.join(self.nodes[0].datadir, \"regtestlegacy\", \"blocks\", \"index\"))\n\n\nif __name__ == '__main__':\n    BlocksdirTest().main()\n"
  },
  {
    "path": "test/functional/feature_cltv.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test BIP65 (CHECKLOCKTIMEVERIFY).\n\nTest that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height\n1351.\n\"\"\"\n\nfrom test_framework.blocktools import create_coinbase, create_block, create_transaction\nfrom test_framework.messages import CTransaction, msg_block, ToHex\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    hex_str_to_bytes,\n)\n\nfrom io import BytesIO\n\nCLTV_HEIGHT = 1351\n\n# Reject codes that we might receive in this test\nREJECT_INVALID = 16\nREJECT_NONSTANDARD = 64\n\ndef cltv_invalidate(tx):\n    '''Modify the signature in vin 0 of the tx to fail CLTV\n\n    Prepends -1 CLTV DROP in the scriptSig itself.\n\n    TODO: test more ways that transactions using CLTV could be invalid (eg\n    locktime requirements fail, sequence time requirements fail, etc).\n    '''\n    tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +\n                                  list(CScript(tx.vin[0].scriptSig)))\n\ndef cltv_validate(node, tx, height):\n    '''Modify the signature in vin 0 of the tx to pass CLTV\n    Prepends <height> CLTV DROP in the scriptSig, and sets\n    the locktime to height'''\n    tx.vin[0].nSequence = 0\n    tx.nLockTime = height\n\n    # Need to re-sign, since nSequence and nLockTime changed\n    signed_result = node.signrawtransaction(ToHex(tx))\n    new_tx = CTransaction()\n    new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex'])))\n\n    new_tx.vin[0].scriptSig = CScript([CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP] +\n                                  list(CScript(new_tx.vin[0].scriptSig)))\n    return new_tx\n\n\nclass BIP65Test(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.extra_args = [['-whitelist=127.0.0.1', '-par=1']]  # Use only one script thread to get the exact reject reason for testing\n        self.setup_clean_chain = True\n        self.rpc_timeout = 120\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[0].add_p2p_connection(P2PInterface())\n\n        self.log.info(\"Mining %d blocks\", CLTV_HEIGHT - 2)\n        self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)]\n        self.nodeaddress = self.nodes[0].getnewaddress()\n\n        self.log.info(\"Test that an invalid-according-to-CLTV transaction can still appear in a block\")\n\n        spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0],\n                self.nodeaddress, amount=1.0)\n        cltv_invalidate(spendtx)\n        spendtx.rehash()\n\n        tip = self.nodes[0].getbestblockhash()\n        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1\n        block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)\n        block.nVersion = 3\n        block.vtx.append(spendtx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n\n        self.nodes[0].p2p.send_and_ping(msg_block(block))\n        assert_equal(self.nodes[0].getbestblockhash(), block.hash)\n\n        self.log.info(\"Test that blocks must now be at least version 4\")\n        tip = block.sha256\n        block_time += 1\n        block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)\n        block.nVersion = 3\n        block.solve()\n\n        with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000003)'.format(block.hash)]):\n            self.nodes[0].p2p.send_and_ping(msg_block(block))\n            assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)\n            self.nodes[0].p2p.sync_with_ping()\n\n        self.log.info(\"Test that invalid-according-to-cltv transactions cannot appear in a block\")\n        block.nVersion = 4\n\n        spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],\n                self.nodeaddress, amount=1.0)\n        cltv_invalidate(spendtx)\n        spendtx.rehash()\n\n        # First we show that this tx is valid except for CLTV by getting it\n        # rejected from the mempool for exactly that reason.\n        assert_equal(\n            [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],\n            self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)\n        )\n\n        # Now we verify that a block with this transaction is also invalid.\n        block.vtx.append(spendtx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n\n        with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):\n            self.nodes[0].p2p.send_and_ping(msg_block(block))\n            assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)\n            self.nodes[0].p2p.sync_with_ping()\n\n        self.log.info(\"Test that a version 4 block with a valid-according-to-CLTV transaction is accepted\")\n        spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)\n        spendtx.rehash()\n\n        block.vtx.pop(1)\n        block.vtx.append(spendtx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n\n        self.nodes[0].p2p.send_and_ping(msg_block(block))\n        assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)\n\n\nif __name__ == '__main__':\n    BIP65Test().main()\n"
  },
  {
    "path": "test/functional/feature_config_args.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test various command line arguments and configuration file parameters.\"\"\"\n\nimport os\n\nfrom test_framework.test_framework import MuntTestFramework\n\n\nclass ConfArgsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def test_config_file_parser(self):\n        # Assume node is stopped\n\n        inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')\n        with open(os.path.join(self.nodes[0].datadir, 'munt.conf'), 'a', encoding='utf-8') as conf:\n            conf.write('includeconf={}\\n'.format(inc_conf_file_path))\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('-dash=1\\n')\n        self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('nono\\n')\n        self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('server=1\\nrpcuser=someuser\\nrpcpassword=some#pass')\n        self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('server=1\\nrpcuser=someuser\\nmain.rpcpassword=some#pass')\n        self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('server=1\\nrpcuser=someuser\\n[main]\\nrpcpassword=some#pass')\n        self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided')\n\n        inc_conf_file2_path = os.path.join(self.nodes[0].datadir, 'include2.conf')\n        with open(os.path.join(self.nodes[0].datadir, 'munt.conf'), 'a', encoding='utf-8') as conf:\n            conf.write('includeconf={}\\n'.format(inc_conf_file2_path))\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('testnot.datadir=1\\n')\n        with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf:\n            conf.write('[testnet]\\n')\n        self.restart_node(0)\n        self.nodes[0].stop_node(expected_stderr='Warning: ' + inc_conf_file_path + ':1 Section [testnot] is not recognized.' + os.linesep + 'Warning: ' + inc_conf_file2_path + ':1 Section [testnet] is not recognized.')\n\n        with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:\n            conf.write('')  # clear\n        with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf:\n            conf.write('')  # clear\n\n    def run_test(self):\n        self.stop_node(0)\n\n        self.test_config_file_parser()\n\n        # Remove the -datadir argument so it doesn't override the config file\n        self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith(\"-datadir\")]\n\n        default_data_dir = self.nodes[0].datadir\n        new_data_dir = os.path.join(default_data_dir, 'newdatadir')\n        new_data_dir_2 = os.path.join(default_data_dir, 'newdatadir2')\n\n        # Check that using -datadir argument on non-existent directory fails\n        self.nodes[0].datadir = new_data_dir\n        self.nodes[0].assert_start_raises_init_error(['-datadir=' + new_data_dir], 'Error: Specified data directory \"' + new_data_dir + '\" does not exist.')\n\n        # Check that using non-existent datadir in conf file fails\n        conf_file = os.path.join(default_data_dir, \"munt.conf\")\n\n        # datadir needs to be set before [regtest] section\n        conf_file_contents = open(conf_file, encoding='utf8').read()\n        with open(conf_file, 'w', encoding='utf8') as f:\n            f.write(\"datadir=\" + new_data_dir + \"\\n\")\n            f.write(conf_file_contents)\n\n        # Temporarily disabled, because this test would access the user's home dir (~/.munt)\n        #self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error reading configuration file: specified data directory \"' + new_data_dir + '\" does not exist.')\n\n        # Create the directory and ensure the config file now works\n        os.mkdir(new_data_dir)\n        # Temporarily disabled, because this test would access the user's home dir (~/.munt)\n        #self.start_node(0, ['-conf='+conf_file, '-wallet=w1'])\n        #self.stop_node(0)\n        #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks'))\n        #if self.is_wallet_compiled():\n        #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1'))\n\n        # Ensure command line argument overrides datadir in conf\n        os.mkdir(new_data_dir_2)\n        self.nodes[0].datadir = new_data_dir_2\n        self.start_node(0, ['-datadir='+new_data_dir_2, '-conf='+conf_file, '-wallet=w2'])\n        assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'blocks'))\n        if self.is_wallet_compiled():\n            assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'wallets', 'w2'))\n\n\nif __name__ == '__main__':\n    ConfArgsTest().main()\n"
  },
  {
    "path": "test/functional/feature_csv_activation.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test activation of the first version bits soft fork.\n\nThis soft fork will activate the following BIPS:\nBIP 68  - nSequence relative lock times\nBIP 112 - CHECKSEQUENCEVERIFY\nBIP 113 - MedianTimePast semantics for nLockTime\n\nregtest lock-in with 108/144 block signalling\nactivation after a further 144 blocks\n\nmine 82 blocks whose coinbases will be used to generate inputs for our tests\nmine 61 blocks to transition from DEFINED to STARTED\nmine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period\nmine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN\nmine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572\nmine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered\nmine 1 block and test that enforcement has triggered (which triggers ACTIVE)\nTest BIP 113 is enforced\nMine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height\nMine 1 block so next height is 581 and test BIP 68 now passes time but not height\nMine 1 block so next height is 582 and test BIP 68 now passes time and height\nTest that BIP 112 is enforced\n\nVarious transactions will be used to test that the BIPs rules are not enforced before the soft fork activates\nAnd that after the soft fork activates transactions pass and fail as they should according to the rules.\nFor each BIP, transactions of versions 1 and 2 will be tested.\n----------------\nBIP 113:\nbip113tx - modify the nLocktime variable\n\nBIP 68:\nbip68txs - 16 txs with nSequence relative locktime of 10 with various bits set as per the relative_locktimes below\n\nBIP 112:\nbip112txs_vary_nSequence - 16 txs with nSequence relative_locktimes of 10 evaluated against 10 OP_CSV OP_DROP\nbip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evaluated against 10 OP_CSV OP_DROP\nbip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP\nbip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP\nbip112tx_special - test negative argument to OP_CSV\n\"\"\"\nfrom decimal import Decimal\nfrom itertools import product\nfrom io import BytesIO\nimport time\n\nfrom test_framework.blocktools import create_coinbase, create_block, create_transaction\nfrom test_framework.messages import ToHex, CTransaction\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.script import (\n    CScript,\n    OP_CHECKSEQUENCEVERIFY,\n    OP_DROP,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    get_bip9_status,\n    hex_str_to_bytes,\n)\n\nBASE_RELATIVE_LOCKTIME = 10\nSEQ_DISABLE_FLAG = 1 << 31\nSEQ_RANDOM_HIGH_BIT = 1 << 25\nSEQ_TYPE_FLAG = 1 << 22\nSEQ_RANDOM_LOW_BIT = 1 << 18\n\ndef relative_locktime(sdf, srhb, stf, srlb):\n    \"\"\"Returns a locktime with certain bits set.\"\"\"\n\n    locktime = BASE_RELATIVE_LOCKTIME\n    if sdf:\n        locktime |= SEQ_DISABLE_FLAG\n    if srhb:\n        locktime |= SEQ_RANDOM_HIGH_BIT\n    if stf:\n        locktime |= SEQ_TYPE_FLAG\n    if srlb:\n        locktime |= SEQ_RANDOM_LOW_BIT\n    return locktime\n\ndef all_rlt_txs(txs):\n    return [tx['tx'] for tx in txs]\n\ndef sign_transaction(node, unsignedtx):\n    rawtx = ToHex(unsignedtx)\n    signresult = node.signrawtransaction(rawtx)\n    tx = CTransaction()\n    f = BytesIO(hex_str_to_bytes(signresult['hex']))\n    tx.deserialize(f)\n    return tx\n\ndef create_bip112special(node, input, txversion, address):\n    tx = create_transaction(node, input, address, amount=Decimal(\"49.98\"))\n    tx.nVersion = txversion\n    signtx = sign_transaction(node, tx)\n    signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))\n    return signtx\n\ndef send_generic_input_tx(node, coinbases, address):\n    return node.sendrawtransaction(ToHex(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount=Decimal(\"49.99\")))))\n\ndef create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0):\n    \"\"\"Returns a list of bip68 transactions with different bits set.\"\"\"\n    txs = []\n    assert len(bip68inputs) >= 16\n    for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):\n        locktime = relative_locktime(sdf, srhb, stf, srlb)\n        tx = create_transaction(node, bip68inputs[i], address, amount=Decimal(\"49.98\"))\n        tx.nVersion = txversion\n        tx.vin[0].nSequence = locktime + locktime_delta\n        tx = sign_transaction(node, tx)\n        tx.rehash()\n        txs.append({'tx': tx, 'sdf': sdf, 'stf': stf})\n\n    return txs\n\ndef create_bip112txs(node, bip112inputs, varyOP_CSV, txversion, address, locktime_delta=0):\n    \"\"\"Returns a list of bip68 transactions with different bits set.\"\"\"\n    txs = []\n    assert len(bip112inputs) >= 16\n    for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):\n        locktime = relative_locktime(sdf, srhb, stf, srlb)\n        tx = create_transaction(node, bip112inputs[i], address, amount=Decimal(\"49.98\"))\n        if (varyOP_CSV):  # if varying OP_CSV, nSequence is fixed\n            tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta\n        else:  # vary nSequence instead, OP_CSV is fixed\n            tx.vin[0].nSequence = locktime + locktime_delta\n        tx.nVersion = txversion\n        signtx = sign_transaction(node, tx)\n        if (varyOP_CSV):\n            signtx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))\n        else:\n            signtx.vin[0].scriptSig = CScript([BASE_RELATIVE_LOCKTIME, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))\n        tx.rehash()\n        txs.append({'tx': signtx, 'sdf': sdf, 'stf': stf})\n    return txs\n\nclass BIP68_112_113Test(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n        self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def generate_blocks(self, number, version, test_blocks=None):\n        if test_blocks is None:\n            test_blocks = []\n        for i in range(number):\n            block = self.create_test_block([], version)\n            test_blocks.append(block)\n            self.last_block_time += 600\n            self.tip = block.sha256\n            self.tipheight += 1\n        return test_blocks\n\n    def create_test_block(self, txs, version=536870912):\n        block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600)\n        block.nVersion = version\n        block.vtx.extend(txs)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.rehash()\n        block.solve()\n        return block\n\n    def sync_blocks(self, blocks, success=True):\n        \"\"\"Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.\n\n        Call with success = False if the tip shouldn't advance to the most recent block.\"\"\"\n        self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success)\n\n    def run_test(self):\n        self.nodes[0].add_p2p_connection(P2PDataStore())\n\n        self.log.info(\"Generate blocks in the past for coinbase outputs.\")\n        long_past_time = int(time.time()) - 600 * 1000  # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future\n        self.nodes[0].setmocktime(long_past_time - 100)  # enough so that the generated blocks will still all be before long_past_time\n        self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2 * 32 + 1)  # 82 blocks generated for inputs\n        self.nodes[0].setmocktime(0)  # set time back to present so yielded blocks aren't in the future as we advance last_block_time\n        self.tipheight = 82  # height of the next block to build\n        self.last_block_time = long_past_time\n        self.tip = int(self.nodes[0].getbestblockhash(), 16)\n        self.nodeaddress = self.nodes[0].getnewaddress()\n\n        self.log.info(\"Test that the csv softfork is DEFINED\")\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined')\n        test_blocks = self.generate_blocks(61, 4)\n        self.sync_blocks(test_blocks)\n\n        self.log.info(\"Advance from DEFINED to STARTED, height = 143\")\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')\n\n        self.log.info(\"Fail to achieve LOCKED_IN\")\n        # 100 out of 144 signal bit 0. Use a variety of bits to simulate multiple parallel softforks\n\n        test_blocks = self.generate_blocks(50, 536870913)  # 0x20000001 (signalling ready)\n        test_blocks = self.generate_blocks(20, 4, test_blocks)  # 0x00000004 (signalling not)\n        test_blocks = self.generate_blocks(50, 536871169, test_blocks)  # 0x20000101 (signalling ready)\n        test_blocks = self.generate_blocks(24, 536936448, test_blocks)  # 0x20010000 (signalling not)\n        self.sync_blocks(test_blocks)\n\n        self.log.info(\"Failed to advance past STARTED, height = 287\")\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')\n\n        self.log.info(\"Generate blocks to achieve LOCK-IN\")\n        # 108 out of 144 signal bit 0 to achieve lock-in\n        # using a variety of bits to simulate multiple parallel softforks\n        test_blocks = self.generate_blocks(58, 536870913)  # 0x20000001 (signalling ready)\n        test_blocks = self.generate_blocks(26, 4, test_blocks)  # 0x00000004 (signalling not)\n        test_blocks = self.generate_blocks(50, 536871169, test_blocks)  # 0x20000101 (signalling ready)\n        test_blocks = self.generate_blocks(10, 536936448, test_blocks)  # 0x20010000 (signalling not)\n        self.sync_blocks(test_blocks)\n\n        self.log.info(\"Advanced from STARTED to LOCKED_IN, height = 431\")\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')\n\n        # Generate 140 more version 4 blocks\n        test_blocks = self.generate_blocks(140, 4)\n        self.sync_blocks(test_blocks)\n\n        # Inputs at height = 572\n        #\n        # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block)\n        # Note we reuse inputs for v1 and v2 txs so must test these separately\n        # 16 normal inputs\n        bip68inputs = []\n        for i in range(16):\n            bip68inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress))\n\n        # 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)\n        bip112basicinputs = []\n        for j in range(2):\n            inputs = []\n            for i in range(16):\n                inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress))\n            bip112basicinputs.append(inputs)\n\n        # 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig)\n        bip112diverseinputs = []\n        for j in range(2):\n            inputs = []\n            for i in range(16):\n                inputs.append(send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress))\n            bip112diverseinputs.append(inputs)\n\n        # 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)\n        bip112specialinput = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)\n\n        # 1 normal input\n        bip113input = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)\n\n        self.nodes[0].setmocktime(self.last_block_time + 600)\n        inputblockhash = self.nodes[0].generate(1)[0]  # 1 block generated for inputs to be in chain at height 572\n        self.nodes[0].setmocktime(0)\n        self.tip = int(inputblockhash, 16)\n        self.tipheight += 1\n        self.last_block_time += 600\n        assert_equal(len(self.nodes[0].getblock(inputblockhash, True)[\"tx\"]), 82 + 1)\n\n        # 2 more version 4 blocks\n        test_blocks = self.generate_blocks(2, 4)\n        self.sync_blocks(test_blocks)\n\n        self.log.info(\"Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575)\")\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')\n\n        # Test both version 1 and version 2 transactions for all tests\n        # BIP113 test transaction will be modified before each use to put in appropriate block time\n        bip113tx_v1 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal(\"49.98\"))\n        bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE\n        bip113tx_v1.nVersion = 1\n        bip113tx_v2 = create_transaction(self.nodes[0], bip113input, self.nodeaddress, amount=Decimal(\"49.98\"))\n        bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE\n        bip113tx_v2.nVersion = 2\n\n        # For BIP68 test all 16 relative sequence locktimes\n        bip68txs_v1 = create_bip68txs(self.nodes[0], bip68inputs, 1, self.nodeaddress)\n        bip68txs_v2 = create_bip68txs(self.nodes[0], bip68inputs, 2, self.nodeaddress)\n\n        # For BIP112 test:\n        # 16 relative sequence locktimes of 10 against 10 OP_CSV OP_DROP inputs\n        bip112txs_vary_nSequence_v1 = create_bip112txs(self.nodes[0], bip112basicinputs[0], False, 1, self.nodeaddress)\n        bip112txs_vary_nSequence_v2 = create_bip112txs(self.nodes[0], bip112basicinputs[0], False, 2, self.nodeaddress)\n        # 16 relative sequence locktimes of 9 against 10 OP_CSV OP_DROP inputs\n        bip112txs_vary_nSequence_9_v1 = create_bip112txs(self.nodes[0], bip112basicinputs[1], False, 1, self.nodeaddress, -1)\n        bip112txs_vary_nSequence_9_v2 = create_bip112txs(self.nodes[0], bip112basicinputs[1], False, 2, self.nodeaddress, -1)\n        # sequence lock time of 10 against 16 (relative_lock_time) OP_CSV OP_DROP inputs\n        bip112txs_vary_OP_CSV_v1 = create_bip112txs(self.nodes[0], bip112diverseinputs[0], True, 1, self.nodeaddress)\n        bip112txs_vary_OP_CSV_v2 = create_bip112txs(self.nodes[0], bip112diverseinputs[0], True, 2, self.nodeaddress)\n        # sequence lock time of 9 against 16 (relative_lock_time) OP_CSV OP_DROP inputs\n        bip112txs_vary_OP_CSV_9_v1 = create_bip112txs(self.nodes[0], bip112diverseinputs[1], True, 1, self.nodeaddress, -1)\n        bip112txs_vary_OP_CSV_9_v2 = create_bip112txs(self.nodes[0], bip112diverseinputs[1], True, 2, self.nodeaddress, -1)\n        # -1 OP_CSV OP_DROP input\n        bip112tx_special_v1 = create_bip112special(self.nodes[0], bip112specialinput, 1, self.nodeaddress)\n        bip112tx_special_v2 = create_bip112special(self.nodes[0], bip112specialinput, 2, self.nodeaddress)\n\n        self.log.info(\"TESTING\")\n\n        self.log.info(\"Pre-Soft Fork Tests. All txs should pass.\")\n        self.log.info(\"Test version 1 txs\")\n\n        success_txs = []\n        # add BIP113 tx and -1 CSV tx\n        bip113tx_v1.nLockTime = self.last_block_time - 600 * 5  # = MTP of prior block (not <) but < time put on current block\n        bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)\n        success_txs.append(bip113signed1)\n        success_txs.append(bip112tx_special_v1)\n        # add BIP 68 txs\n        success_txs.extend(all_rlt_txs(bip68txs_v1))\n        # add BIP 112 with seq=10 txs\n        success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1))\n        success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v1))\n        # try BIP 112 with seq=9 txs\n        success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1))\n        success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v1))\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        self.log.info(\"Test version 2 txs\")\n\n        success_txs = []\n        # add BIP113 tx and -1 CSV tx\n        bip113tx_v2.nLockTime = self.last_block_time - 600 * 5  # = MTP of prior block (not <) but < time put on current block\n        bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)\n        success_txs.append(bip113signed2)\n        success_txs.append(bip112tx_special_v2)\n        # add BIP 68 txs\n        success_txs.extend(all_rlt_txs(bip68txs_v2))\n        # add BIP 112 with seq=10 txs\n        success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v2))\n        success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_v2))\n        # try BIP 112 with seq=9 txs\n        success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2))\n        success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2))\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block\n        test_blocks = self.generate_blocks(1, 4)\n        self.sync_blocks(test_blocks)\n        assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active')\n\n        self.log.info(\"Post-Soft Fork Tests.\")\n\n        self.log.info(\"BIP 113 tests\")\n        # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules\n        bip113tx_v1.nLockTime = self.last_block_time - 600 * 5  # = MTP of prior block (not <) but < time put on current block\n        bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)\n        bip113tx_v2.nLockTime = self.last_block_time - 600 * 5  # = MTP of prior block (not <) but < time put on current block\n        bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)\n        for bip113tx in [bip113signed1, bip113signed2]:\n            self.sync_blocks([self.create_test_block([bip113tx])], success=False)\n        # BIP 113 tests should now pass if the locktime is < MTP\n        bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1  # < MTP of prior block\n        bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)\n        bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1  # < MTP of prior block\n        bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)\n        for bip113tx in [bip113signed1, bip113signed2]:\n            self.sync_blocks([self.create_test_block([bip113tx])])\n            self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # Next block height = 580 after 4 blocks of random version\n        test_blocks = self.generate_blocks(4, 1234)\n        self.sync_blocks(test_blocks)\n\n        self.log.info(\"BIP 68 tests\")\n        self.log.info(\"Test version 1 txs - all should still pass\")\n\n        success_txs = []\n        success_txs.extend(all_rlt_txs(bip68txs_v1))\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        self.log.info(\"Test version 2 txs\")\n\n        # All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass\n        bip68success_txs = [tx['tx'] for tx in bip68txs_v2 if tx['sdf']]\n        self.sync_blocks([self.create_test_block(bip68success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512\n        bip68timetxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and tx['stf']]\n        for tx in bip68timetxs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        bip68heighttxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and not tx['stf']]\n        for tx in bip68heighttxs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        # Advance one block to 581\n        test_blocks = self.generate_blocks(1, 1234)\n        self.sync_blocks(test_blocks)\n\n        # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512\n        bip68success_txs.extend(bip68timetxs)\n        self.sync_blocks([self.create_test_block(bip68success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n        for tx in bip68heighttxs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        # Advance one block to 582\n        test_blocks = self.generate_blocks(1, 1234)\n        self.sync_blocks(test_blocks)\n\n        # All BIP 68 txs should pass\n        bip68success_txs.extend(bip68heighttxs)\n        self.sync_blocks([self.create_test_block(bip68success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        self.log.info(\"BIP 112 tests\")\n        self.log.info(\"Test version 1 txs\")\n\n        # -1 OP_CSV tx should fail\n        self.sync_blocks([self.create_test_block([bip112tx_special_v1])], success=False)\n        # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass\n\n        success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v1 if tx['sdf']]\n        success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if tx['sdf']]\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail\n        fail_txs = all_rlt_txs(bip112txs_vary_nSequence_v1)\n        fail_txs += all_rlt_txs(bip112txs_vary_nSequence_9_v1)\n        fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]\n        fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]\n        for tx in fail_txs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        self.log.info(\"Test version 2 txs\")\n\n        # -1 OP_CSV tx should fail\n        self.sync_blocks([self.create_test_block([bip112tx_special_v2])], success=False)\n\n        # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met)\n        success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if tx['sdf']]\n        success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if tx['sdf']]\n\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ##\n\n        # All txs with nSequence 9 should fail either due to earlier mismatch or failing the CSV check\n        fail_txs = all_rlt_txs(bip112txs_vary_nSequence_9_v2)\n        fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if not tx['sdf']]\n        for tx in fail_txs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail\n        fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if tx['sdf']]\n        for tx in fail_txs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        # If sequencelock types mismatch, tx should fail\n        fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and tx['stf']]\n        fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]\n        for tx in fail_txs:\n            self.sync_blocks([self.create_test_block([tx])], success=False)\n\n        # Remaining txs should pass, just test masking works properly\n        success_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and not tx['stf']]\n        success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and not tx['stf']]\n        self.sync_blocks([self.create_test_block(success_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # Additional test, of checking that comparison of two time types works properly\n        time_txs = []\n        for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]:\n            tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG\n            signtx = sign_transaction(self.nodes[0], tx)\n            time_txs.append(signtx)\n\n        self.sync_blocks([self.create_test_block(time_txs)])\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # TODO: Test empty stack fails\n\nif __name__ == '__main__':\n    BIP68_112_113Test().main()\n"
  },
  {
    "path": "test/functional/feature_dbcrash.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test recovery from a crash during chainstate writing.\n\n- 4 nodes\n  * node0, node1, and node2 will have different dbcrash ratios, and different\n    dbcache sizes\n  * node3 will be a regular node, with no crashing.\n  * The nodes will not connect to each other.\n\n- use default test framework starting chain. initialize starting_tip_height to\n  tip height.\n\n- Main loop:\n  * generate lots of transactions on node3, enough to fill up a block.\n  * uniformly randomly pick a tip height from starting_tip_height to\n    tip_height; with probability 1/(height_difference+4), invalidate this block.\n  * mine enough blocks to overtake tip_height at start of loop.\n  * for each node in [node0,node1,node2]:\n     - for each mined block:\n       * submit block to node\n       * if node crashed on/after submitting:\n         - restart until recovery succeeds\n         - check that utxo matches node3 using gettxoutsetinfo\"\"\"\n\nimport errno\nimport http.client\nimport random\nimport time\n\nfrom test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, ToHex\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, create_confirmed_utxos, hex_str_to_bytes\n\n\nclass ChainstateWriteCrashTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = False\n        # Need a bit of extra time for the nodes to start up for this test\n        self.rpc_timeout = 90\n\n        # Set -maxmempool=0 to turn off mempool memory sharing with dbcache\n        # Set -rpcservertimeout=900 to reduce socket disconnects in this\n        # long-running test\n        self.base_args = [\"-limitdescendantsize=0\", \"-maxmempool=0\", \"-rpcservertimeout=900\", \"-dbbatchsize=200000\"]\n\n        # Set different crash ratios and cache sizes.  Note that not all of\n        # -dbcache goes to pcoinsTip.\n        self.node0_args = [\"-dbcrashratio=8\", \"-dbcache=4\"] + self.base_args\n        self.node1_args = [\"-dbcrashratio=16\", \"-dbcache=8\"] + self.base_args\n        self.node2_args = [\"-dbcrashratio=24\", \"-dbcache=16\"] + self.base_args\n\n        # Node3 is a normal node with default args, except will mine full blocks\n        self.node3_args = [\"-blockmaxweight=4000000\"]\n        self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes, extra_args=self.extra_args)\n        self.start_nodes()\n        self.import_deterministic_coinbase_privkeys()\n        # Leave them unconnected, we'll use submitblock directly in this test\n\n    def restart_node(self, node_index, expected_tip):\n        \"\"\"Start up a given node id, wait for the tip to reach the given block hash, and calculate the utxo hash.\n\n        Exceptions on startup should indicate node crash (due to -dbcrashratio), in which case we try again. Give up\n        after 60 seconds. Returns the utxo hash of the given node.\"\"\"\n\n        time_start = time.time()\n        while time.time() - time_start < 120:\n            try:\n                # Any of these RPC calls could throw due to node crash\n                self.start_node(node_index)\n                self.nodes[node_index].waitforblock(expected_tip)\n                utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2']\n                return utxo_hash\n            except:\n                # An exception here should mean the node is about to crash.\n                # If Munt-daemon exits, then try again.  wait_for_node_exit()\n                # should raise an exception if Munt-daemon doesn't exit.\n                self.wait_for_node_exit(node_index, timeout=10)\n            self.crashed_on_restart += 1\n            time.sleep(1)\n\n        # If we got here, Munt-daemon isn't coming back up on restart.  Could be a\n        # bug in Munt-daemon, or we've gotten unlucky with our dbcrash ratio --\n        # perhaps we generated a test case that blew up our cache?\n        # TODO: If this happens a lot, we should try to restart without -dbcrashratio\n        # and make sure that recovery happens.\n        raise AssertionError(\"Unable to successfully restart node %d in allotted time\", node_index)\n\n    def submit_block_catch_error(self, node_index, block):\n        \"\"\"Try submitting a block to the given node.\n\n        Catch any exceptions that indicate the node has crashed.\n        Returns true if the block was submitted successfully; false otherwise.\"\"\"\n\n        try:\n            self.nodes[node_index].submitblock(block)\n            return True\n        except (http.client.CannotSendRequest, http.client.RemoteDisconnected) as e:\n            self.log.debug(\"node %d submitblock raised exception: %s\", node_index, e)\n            return False\n        except OSError as e:\n            self.log.debug(\"node %d submitblock raised OSError exception: errno=%s\", node_index, e.errno)\n            if e.errno in [errno.EPIPE, errno.ECONNREFUSED, errno.ECONNRESET]:\n                # The node has likely crashed\n                return False\n            else:\n                # Unexpected exception, raise\n                raise\n\n    def sync_node3blocks(self, block_hashes):\n        \"\"\"Use submitblock to sync node3's chain with the other nodes\n\n        If submitblock fails, restart the node and get the new utxo hash.\n        If any nodes crash while updating, we'll compare utxo hashes to\n        ensure recovery was successful.\"\"\"\n\n        node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']\n\n        # Retrieve all the blocks from node3\n        blocks = []\n        for block_hash in block_hashes:\n            blocks.append([block_hash, self.nodes[3].getblock(block_hash, 0)])\n\n        # Deliver each block to each other node\n        for i in range(3):\n            nodei_utxo_hash = None\n            self.log.debug(\"Syncing blocks to node %d\", i)\n            for (block_hash, block) in blocks:\n                # Get the block from node3, and submit to node_i\n                self.log.debug(\"submitting block %s\", block_hash)\n                if not self.submit_block_catch_error(i, block):\n                    # TODO: more carefully check that the crash is due to -dbcrashratio\n                    # (change the exit code perhaps, and check that here?)\n                    self.wait_for_node_exit(i, timeout=30)\n                    self.log.debug(\"Restarting node %d after block hash %s\", i, block_hash)\n                    nodei_utxo_hash = self.restart_node(i, block_hash)\n                    assert nodei_utxo_hash is not None\n                    self.restart_counts[i] += 1\n                else:\n                    # Clear it out after successful submitblock calls -- the cached\n                    # utxo hash will no longer be correct\n                    nodei_utxo_hash = None\n\n            # Check that the utxo hash matches node3's utxo set\n            # NOTE: we only check the utxo set if we had to restart the node\n            # after the last block submitted:\n            # - checking the utxo hash causes a cache flush, which we don't\n            # want to do every time; so\n            # - we only update the utxo cache after a node restart, since flushing\n            # the cache is a no-op at that point\n            if nodei_utxo_hash is not None:\n                self.log.debug(\"Checking txoutsetinfo matches for node %d\", i)\n                assert_equal(nodei_utxo_hash, node3_utxo_hash)\n\n    def verify_utxo_hash(self):\n        \"\"\"Verify that the utxo hash of each node matches node3.\n\n        Restart any nodes that crash while querying.\"\"\"\n        node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']\n        self.log.info(\"Verifying utxo hash matches for all nodes\")\n\n        for i in range(3):\n            try:\n                nodei_utxo_hash = self.nodes[i].gettxoutsetinfo()['hash_serialized_2']\n            except OSError:\n                # probably a crash on db flushing\n                nodei_utxo_hash = self.restart_node(i, self.nodes[3].getbestblockhash())\n            assert_equal(nodei_utxo_hash, node3_utxo_hash)\n\n    def generate_small_transactions(self, node, count, utxo_list):\n        FEE = 1000  # TODO: replace this with node relay fee based calculation\n        num_transactions = 0\n        random.shuffle(utxo_list)\n        while len(utxo_list) >= 2 and num_transactions < count:\n            tx = CTransaction()\n            input_amount = 0\n            for i in range(2):\n                utxo = utxo_list.pop()\n                tx.vin.append(CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout'])))\n                input_amount += int(utxo['amount'] * COIN)\n            output_amount = (input_amount - FEE) // 3\n\n            if output_amount <= 0:\n                # Sanity check -- if we chose inputs that are too small, skip\n                continue\n\n            for i in range(3):\n                tx.vout.append(CTxOut(output_amount, hex_str_to_bytes(utxo['scriptPubKey'])))\n\n            # Sign and send the transaction to get into the mempool\n            tx_signed_hex = node.signrawtransaction(ToHex(tx))['hex']\n            node.sendrawtransaction(tx_signed_hex)\n            num_transactions += 1\n\n    def run_test(self):\n        # Track test coverage statistics\n        self.restart_counts = [0, 0, 0]  # Track the restarts for nodes 0-2\n        self.crashed_on_restart = 0      # Track count of crashes during recovery\n\n        # Start by creating a lot of utxos on node3\n        initial_height = self.nodes[3].getblockcount()\n        utxo_list = create_confirmed_utxos(self.nodes[3].getnetworkinfo()['relayfee'], self.nodes[3], 5000)\n        self.log.info(\"Prepped %d utxo entries\", len(utxo_list))\n\n        # Sync these blocks with the other nodes\n        block_hashes_to_sync = []\n        for height in range(initial_height + 1, self.nodes[3].getblockcount() + 1):\n            block_hashes_to_sync.append(self.nodes[3].getblockhash(height))\n\n        self.log.debug(\"Syncing %d blocks with other nodes\", len(block_hashes_to_sync))\n        # Syncing the blocks could cause nodes to crash, so the test begins here.\n        self.sync_node3blocks(block_hashes_to_sync)\n\n        starting_tip_height = self.nodes[3].getblockcount()\n\n        # Main test loop:\n        # each time through the loop, generate a bunch of transactions,\n        # and then either mine a single new block on the tip, or some-sized reorg.\n        for i in range(40):\n            self.log.info(\"Iteration %d, generating 2500 transactions %s\", i, self.restart_counts)\n            # Generate a bunch of small-ish transactions\n            self.generate_small_transactions(self.nodes[3], 2500, utxo_list)\n            # Pick a random block between current tip, and starting tip\n            current_height = self.nodes[3].getblockcount()\n            random_height = random.randint(starting_tip_height, current_height)\n            self.log.debug(\"At height %d, considering height %d\", current_height, random_height)\n            if random_height > starting_tip_height:\n                # Randomly reorg from this point with some probability (1/4 for\n                # tip, 1/5 for tip-1, ...)\n                if random.random() < 1.0 / (current_height + 4 - random_height):\n                    self.log.debug(\"Invalidating block at height %d\", random_height)\n                    self.nodes[3].invalidateblock(self.nodes[3].getblockhash(random_height))\n\n            # Now generate new blocks until we pass the old tip height\n            self.log.debug(\"Mining longer tip\")\n            block_hashes = []\n            while current_height + 1 > self.nodes[3].getblockcount():\n                block_hashes.extend(self.nodes[3].generate(min(10, current_height + 1 - self.nodes[3].getblockcount())))\n            self.log.debug(\"Syncing %d new blocks...\", len(block_hashes))\n            self.sync_node3blocks(block_hashes)\n            utxo_list = self.nodes[3].listunspent()\n            self.log.debug(\"Node3 utxo count: %d\", len(utxo_list))\n\n        # Check that the utxo hashes agree with node3\n        # Useful side effect: each utxo cache gets flushed here, so that we\n        # won't get crashes on shutdown at the end of the test.\n        self.verify_utxo_hash()\n\n        # Check the test coverage\n        self.log.info(\"Restarted nodes: %s; crashes on restart: %d\", self.restart_counts, self.crashed_on_restart)\n\n        # If no nodes were restarted, we didn't test anything.\n        assert self.restart_counts != [0, 0, 0]\n\n        # Make sure we tested the case of crash-during-recovery.\n        assert self.crashed_on_restart > 0\n\n        # Warn if any of the nodes escaped restart.\n        for i in range(3):\n            if self.restart_counts[i] == 0:\n                self.log.warn(\"Node %d never crashed during utxo flush!\", i)\n\nif __name__ == \"__main__\":\n    ChainstateWriteCrashTest().main()\n"
  },
  {
    "path": "test/functional/feature_dersig.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test BIP66 (DER SIG).\n\nTest that the DERSIG soft-fork activates at (regtest) height 1251.\n\"\"\"\n\nfrom test_framework.blocktools import create_coinbase, create_block, create_transaction\nfrom test_framework.messages import msg_block\nfrom test_framework.mininode import mininode_lock, P2PInterface\nfrom test_framework.script import CScript\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    wait_until,\n)\n\nDERSIG_HEIGHT = 1251\n\n# Reject codes that we might receive in this test\nREJECT_INVALID = 16\nREJECT_NONSTANDARD = 64\n\n# A canonical signature consists of:\n# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>\ndef unDERify(tx):\n    \"\"\"\n    Make the signature in vin 0 of a tx non-DER-compliant,\n    by adding padding after the S-value.\n    \"\"\"\n    scriptSig = CScript(tx.vin[0].scriptSig)\n    newscript = []\n    for i in scriptSig:\n        if (len(newscript) == 0):\n            newscript.append(i[0:-1] + b'\\0' + i[-1:])\n        else:\n            newscript.append(i)\n    tx.vin[0].scriptSig = CScript(newscript)\n\n\n\nclass BIP66Test(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.extra_args = [['-whitelist=127.0.0.1', '-par=1', '-enablebip61']]  # Use only one script thread to get the exact reject reason for testing\n        self.setup_clean_chain = True\n        self.rpc_timeout = 120\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[0].add_p2p_connection(P2PInterface())\n\n        self.log.info(\"Mining %d blocks\", DERSIG_HEIGHT - 2)\n        self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(DERSIG_HEIGHT - 2)]\n        self.nodeaddress = self.nodes[0].getnewaddress()\n\n        self.log.info(\"Test that a transaction with non-DER signature can still appear in a block\")\n\n        spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0],\n                self.nodeaddress, amount=1.0)\n        unDERify(spendtx)\n        spendtx.rehash()\n\n        tip = self.nodes[0].getbestblockhash()\n        block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1\n        block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time)\n        block.nVersion = 2\n        block.vtx.append(spendtx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.rehash()\n        block.solve()\n\n        self.nodes[0].p2p.send_and_ping(msg_block(block))\n        assert_equal(self.nodes[0].getbestblockhash(), block.hash)\n\n        self.log.info(\"Test that blocks must now be at least version 3\")\n        tip = block.sha256\n        block_time += 1\n        block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time)\n        block.nVersion = 2\n        block.rehash()\n        block.solve()\n\n        with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000002)'.format(block.hash)]):\n            self.nodes[0].p2p.send_and_ping(msg_block(block))\n            assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)\n            self.nodes[0].p2p.sync_with_ping()\n\n        self.log.info(\"Test that transactions with non-DER signatures cannot appear in a block\")\n        block.nVersion = 3\n\n        spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],\n                self.nodeaddress, amount=1.0)\n        unDERify(spendtx)\n        spendtx.rehash()\n\n        # First we show that this tx is valid except for DERSIG by getting it\n        # rejected from the mempool for exactly that reason.\n        assert_equal(\n            [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],\n            self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)\n        )\n\n        # Now we verify that a block with this transaction is also invalid.\n        block.vtx.append(spendtx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.rehash()\n        block.solve()\n\n        with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]):\n            self.nodes[0].p2p.send_and_ping(msg_block(block))\n            assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)\n            self.nodes[0].p2p.sync_with_ping()\n\n        wait_until(lambda: \"reject\" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)\n        with mininode_lock:\n            assert self.nodes[0].p2p.last_message[\"reject\"].code in [REJECT_INVALID, REJECT_NONSTANDARD]\n            assert_equal(self.nodes[0].p2p.last_message[\"reject\"].data, block.sha256)\n            assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message[\"reject\"].reason\n\n        self.log.info(\"Test that a version 3 block with a DERSIG-compliant transaction is accepted\")\n        block.vtx[1] = create_transaction(self.nodes[0], self.coinbase_txids[1], self.nodeaddress, amount=1.0)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.rehash()\n        block.solve()\n\n        self.nodes[0].p2p.send_and_ping(msg_block(block))\n        assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)\n\nif __name__ == '__main__':\n    BIP66Test().main()\n"
  },
  {
    "path": "test/functional/feature_fee_estimation.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test fee estimation code.\"\"\"\nfrom decimal import Decimal\nimport random\n\nfrom test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN\nfrom test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n    connect_nodes,\n    satoshi_round,\n    sync_blocks,\n    sync_mempools,\n)\n\n# Construct 2 trivial P2SH's and the ScriptSigs that spend them\n# So we can create many transactions without needing to spend\n# time signing.\nREDEEM_SCRIPT_1 = CScript([OP_1, OP_DROP])\nREDEEM_SCRIPT_2 = CScript([OP_2, OP_DROP])\nP2SH_1 = CScript([OP_HASH160, hash160(REDEEM_SCRIPT_1), OP_EQUAL])\nP2SH_2 = CScript([OP_HASH160, hash160(REDEEM_SCRIPT_2), OP_EQUAL])\n\n# Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2\nSCRIPT_SIG = [CScript([OP_TRUE, REDEEM_SCRIPT_1]), CScript([OP_TRUE, REDEEM_SCRIPT_2])]\n\ndef small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):\n    \"\"\"Create and send a transaction with a random fee.\n\n    The transaction pays to a trivial P2SH script, and assumes that its inputs\n    are of the same form.\n    The function takes a list of confirmed outputs and unconfirmed outputs\n    and attempts to use the confirmed list first for its inputs.\n    It adds the newly created outputs to the unconfirmed list.\n    Returns (raw transaction, fee).\"\"\"\n\n    # It's best to exponentially distribute our random fees\n    # because the buckets are exponentially spaced.\n    # Exponentially distributed from 1-128 * fee_increment\n    rand_fee = float(fee_increment) * (1.1892 ** random.randint(0, 28))\n    # Total fee ranges from min_fee to min_fee + 127*fee_increment\n    fee = min_fee - fee_increment + satoshi_round(rand_fee)\n    tx = CTransaction()\n    total_in = Decimal(\"0.00000000\")\n    while total_in <= (amount + fee) and len(conflist) > 0:\n        t = conflist.pop(0)\n        total_in += t[\"amount\"]\n        tx.vin.append(CTxIn(COutPoint(int(t[\"txid\"], 16), t[\"vout\"]), b\"\"))\n    if total_in <= amount + fee:\n        while total_in <= (amount + fee) and len(unconflist) > 0:\n            t = unconflist.pop(0)\n            total_in += t[\"amount\"]\n            tx.vin.append(CTxIn(COutPoint(int(t[\"txid\"], 16), t[\"vout\"]), b\"\"))\n        if total_in <= amount + fee:\n            raise RuntimeError(\"Insufficient funds: need %d, have %d\" % (amount + fee, total_in))\n    tx.vout.append(CTxOut(int((total_in - amount - fee) * COIN), P2SH_1))\n    tx.vout.append(CTxOut(int(amount * COIN), P2SH_2))\n    # These transactions don't need to be signed, but we still have to insert\n    # the ScriptSig that will satisfy the ScriptPubKey.\n    for inp in tx.vin:\n        inp.scriptSig = SCRIPT_SIG[inp.prevout.n]\n    txid = from_node.sendrawtransaction(hexstring=ToHex(tx))\n    unconflist.append({\"txid\": txid, \"vout\": 0, \"amount\": total_in - amount - fee})\n    unconflist.append({\"txid\": txid, \"vout\": 1, \"amount\": amount})\n\n    return (ToHex(tx), fee)\n\ndef split_inputs(from_node, txins, txouts, initial_split=False):\n    \"\"\"Generate a lot of inputs so we can generate a ton of transactions.\n\n    This function takes an input from txins, and creates and sends a transaction\n    which splits the value into 2 outputs which are appended to txouts.\n    Previously this was designed to be small inputs so they wouldn't have\n    a high coin age when the notion of priority still existed.\"\"\"\n\n    prevtxout = txins.pop()\n    tx = CTransaction()\n    tx.vin.append(CTxIn(COutPoint(int(prevtxout[\"txid\"], 16), prevtxout[\"vout\"]), b\"\"))\n\n    half_change = satoshi_round(prevtxout[\"amount\"] / 2)\n    rem_change = prevtxout[\"amount\"] - half_change - Decimal(\"0.00001000\")\n    tx.vout.append(CTxOut(int(half_change * COIN), P2SH_1))\n    tx.vout.append(CTxOut(int(rem_change * COIN), P2SH_2))\n\n    # If this is the initial split we actually need to sign the transaction\n    # Otherwise we just need to insert the proper ScriptSig\n    if (initial_split):\n        completetx = from_node.signrawtransaction(ToHex(tx))[\"hex\"]\n    else:\n        tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout[\"vout\"]]\n        completetx = ToHex(tx)\n    txid = from_node.sendrawtransaction(hexstring=completetx)\n    txouts.append({\"txid\": txid, \"vout\": 0, \"amount\": half_change})\n    txouts.append({\"txid\": txid, \"vout\": 1, \"amount\": rem_change})\n\ndef check_estimates(node, fees_seen):\n    \"\"\"Call estimatesmartfee and verify that the estimates meet certain invariants.\"\"\"\n\n    delta = 1.0e-6  # account for rounding error\n    last_feerate = float(max(fees_seen))\n    all_smart_estimates = [node.estimatesmartfee(i) for i in range(1, 26)]\n    for i, e in enumerate(all_smart_estimates):  # estimate is for i+1\n        feerate = float(e[\"feerate\"])\n        assert_greater_than(feerate, 0)\n\n        if feerate + delta < min(fees_seen) or feerate - delta > max(fees_seen):\n            raise AssertionError(\"Estimated fee (%f) out of range (%f,%f)\"\n                                 % (feerate, min(fees_seen), max(fees_seen)))\n        if feerate - delta > last_feerate:\n            raise AssertionError(\"Estimated fee (%f) larger than last fee (%f) for lower number of confirms\"\n                                 % (feerate, last_feerate))\n        last_feerate = feerate\n\n        if i == 0:\n            assert_equal(e[\"blocks\"], 2)\n        else:\n            assert_greater_than_or_equal(i + 1, e[\"blocks\"])\n\nclass EstimateFeeTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 3\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        \"\"\"\n        We'll setup the network to have 3 nodes that all mine with different parameters.\n        But first we need to use one node to create a lot of outputs\n        which we will use to generate our transactions.\n        \"\"\"\n        self.add_nodes(3, extra_args=[[\"-maxorphantx=1000\", \"-whitelist=127.0.0.1\"],\n                                      [\"-blockmaxweight=68000\", \"-maxorphantx=1000\"],\n                                      [\"-blockmaxweight=32000\", \"-maxorphantx=1000\"]])\n        # Use node0 to mine blocks for input splitting\n        # Node1 mines small blocks but that are bigger than the expected transaction rate.\n        # NOTE: the CreateNewBlock code starts counting block weight at 4,000 weight,\n        # (68k weight is room enough for 120 or so transactions)\n        # Node2 is a stingy miner, that\n        # produces too small blocks (room for only 55 or so transactions)\n        self.start_nodes()\n        self.import_deterministic_coinbase_privkeys()\n        self.stop_nodes()\n\n    def transact_and_mine(self, numblocks, mining_node):\n        min_fee = Decimal(\"0.00001\")\n        # We will now mine numblocks blocks generating on average 100 transactions between each block\n        # We shuffle our confirmed txout set before each set of transactions\n        # small_txpuzzle_randfee will use the transactions that have inputs already in the chain when possible\n        # resorting to tx's that depend on the mempool when those run out\n        for i in range(numblocks):\n            random.shuffle(self.confutxo)\n            for j in range(random.randrange(100 - 50, 100 + 50)):\n                from_index = random.randint(1, 2)\n                (txhex, fee) = small_txpuzzle_randfee(self.nodes[from_index], self.confutxo,\n                                                      self.memutxo, Decimal(\"0.005\"), min_fee, min_fee)\n                tx_kbytes = (len(txhex) // 2) / 1000.0\n                self.fees_per_kb.append(float(fee) / tx_kbytes)\n            sync_mempools(self.nodes[0:3], wait=.1)\n            mined = mining_node.getblock(mining_node.generate(1)[0], True)[\"tx\"]\n            sync_blocks(self.nodes[0:3], wait=.1)\n            # update which txouts are confirmed\n            newmem = []\n            for utx in self.memutxo:\n                if utx[\"txid\"] in mined:\n                    self.confutxo.append(utx)\n                else:\n                    newmem.append(utx)\n            self.memutxo = newmem\n\n    def run_test(self):\n        self.log.info(\"This test is time consuming, please be patient\")\n        self.log.info(\"Splitting inputs so we can generate tx's\")\n\n        # Start node0\n        self.start_node(0)\n        self.txouts = []\n        self.txouts2 = []\n        # Split a coinbase into two transaction puzzle outputs\n        split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True)\n\n        # Mine\n        while (len(self.nodes[0].getrawmempool()) > 0):\n            self.nodes[0].generate(1)\n\n        # Repeatedly split those 2 outputs, doubling twice for each rep\n        # Use txouts to monitor the available utxo, since these won't be tracked in wallet\n        reps = 0\n        while (reps < 5):\n            # Double txouts to txouts2\n            while (len(self.txouts) > 0):\n                split_inputs(self.nodes[0], self.txouts, self.txouts2)\n            while (len(self.nodes[0].getrawmempool()) > 0):\n                self.nodes[0].generate(1)\n            # Double txouts2 to txouts\n            while (len(self.txouts2) > 0):\n                split_inputs(self.nodes[0], self.txouts2, self.txouts)\n            while (len(self.nodes[0].getrawmempool()) > 0):\n                self.nodes[0].generate(1)\n            reps += 1\n        self.log.info(\"Finished splitting\")\n\n        # Now we can connect the other nodes, didn't want to connect them earlier\n        # so the estimates would not be affected by the splitting transactions\n        self.start_node(1)\n        self.start_node(2)\n        connect_nodes(self.nodes[1], 0)\n        connect_nodes(self.nodes[0], 2)\n        connect_nodes(self.nodes[2], 1)\n\n        self.sync_all()\n\n        self.fees_per_kb = []\n        self.memutxo = []\n        self.confutxo = self.txouts  # Start with the set of confirmed txouts after splitting\n        self.log.info(\"Will output estimates for 1/2/3/6/15/25 blocks\")\n\n        for i in range(2):\n            ###self.log.info(\"Creating transactions and mining them with a block size that can't keep up\")\n            # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine\n            ###self.transact_and_mine(10, self.nodes[2])\n            ###check_estimates(self.nodes[1], self.fees_per_kb)\n\n            self.log.info(\"Creating transactions and mining them at a block size that is just big enough\")\n            # Generate transactions while mining 10 more blocks, this time with node1\n            # which mines blocks with capacity just above the rate that transactions are being created\n            self.transact_and_mine(10, self.nodes[1])\n            check_estimates(self.nodes[1], self.fees_per_kb)\n\n        # Finish by mining a normal-sized block:\n        while len(self.nodes[1].getrawmempool()) > 0:\n            self.nodes[1].generate(1)\n\n        sync_blocks(self.nodes[0:3], wait=.1)\n        self.log.info(\"Final estimates after emptying mempools\")\n        check_estimates(self.nodes[1], self.fees_per_kb)\n\nif __name__ == '__main__':\n    EstimateFeeTest().main()\n"
  },
  {
    "path": "test/functional/feature_filelock.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Check that it's not possible to start a second Munt-daemon instance using the same datadir or wallet.\"\"\"\nimport os\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.test_node import ErrorMatch\n\nclass FilelockTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes, extra_args=None)\n        self.nodes[0].start([])\n        self.nodes[0].wait_for_rpc_connection()\n\n    def run_test(self):\n        datadir = os.path.join(self.nodes[0].datadir, 'regtest')\n        self.log.info(\"Using datadir {}\".format(datadir))\n\n        self.log.info(\"Check that we can't start a second Munt-daemon instance using the same datadir\")\n        expected_msg = \"Error: Cannot obtain a lock on data directory {}. Munt is probably already running.\".format(datadir)\n        self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_TEXT)\n\n        ###if self.is_wallet_compiled():\n            ###wallet_dir = os.path.join(datadir, 'wallets')\n            ###self.log.info(\"Check that we can't start a second Munt-daemon instance using the same wallet\")\n            ###expected_msg = \"Error: Error initializing wallet database environment\"\n            ###self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX)\n\nif __name__ == '__main__':\n    FilelockTest().main()\n"
  },
  {
    "path": "test/functional/feature_help.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Verify that starting with -h works as expected.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass HelpTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes)\n        # Don't start the node\n\n    def get_node_output(self, *, ret_code_expected):\n        ret_code = self.nodes[0].process.wait(timeout=5)\n        assert_equal(ret_code, ret_code_expected)\n        self.nodes[0].stdout.seek(0)\n        self.nodes[0].stderr.seek(0)\n        out = self.nodes[0].stdout.read()\n        err = self.nodes[0].stderr.read()\n        self.nodes[0].stdout.close()\n        self.nodes[0].stderr.close()\n\n        # Clean up TestNode state\n        self.nodes[0].running = False\n        self.nodes[0].process = None\n        self.nodes[0].rpc_connected = False\n        self.nodes[0].rpc = None\n\n        return out, err\n\n    def run_test(self):\n        self.log.info(\"Start with -h for help text\")\n        self.nodes[0].start(extra_args=['-h'])\n        # Node should exit immediately and output help to stdout.\n        output, _ = self.get_node_output(ret_code_expected=0)\n        assert b'Options' in output\n        self.log.info(\"Help text received: {} (...)\".format(output[0:60]))\n\n        self.log.info(\"Start with -version for version information\")\n        self.nodes[0].start(extra_args=['-version'])\n        # Node should exit immediately and output version to stdout.\n        output, _ = self.get_node_output(ret_code_expected=0)\n        assert b'version' in output\n        self.log.info(\"Version text received: {} (...)\".format(output[0:60]))\n\n        # Test that arguments not in the help results in an error\n        ###self.log.info(\"Start with -fakearg to make sure it does not start\")\n        ###self.nodes[0].start(extra_args=['-fakearg'])\n        # Node should exit immediately and output an error to stderr\n        ###_, output = self.get_node_output(ret_code_expected=1)\n        ###assert b'Error parsing command line arguments' in output\n        ###self.log.info(\"Error message received: {} (...)\".format(output[0:60]))\n\n\nif __name__ == '__main__':\n    HelpTest().main()\n"
  },
  {
    "path": "test/functional/feature_includeconf.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Tests the includeconf argument\n\nVerify that:\n\n1. adding includeconf to the configuration file causes the includeconf\n   file to be loaded in the correct order.\n2. includeconf cannot be used as a command line argument.\n3. includeconf cannot be used recursively (ie includeconf can only\n   be used from the base config file).\n4. multiple includeconf arguments can be specified in the main config\n   file.\n\"\"\"\nimport os\n\nfrom test_framework.test_framework import MuntTestFramework\n\nclass IncludeConfTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = False\n        self.num_nodes = 1\n\n    def setup_chain(self):\n        super().setup_chain()\n        # Create additional config files\n        # - tmpdir/node0/relative.conf\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"relative.conf\"), \"w\", encoding=\"utf8\") as f:\n            f.write(\"uacomment=relative\\n\")\n        # - tmpdir/node0/relative2.conf\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"relative2.conf\"), \"w\", encoding=\"utf8\") as f:\n            f.write(\"uacomment=relative2\\n\")\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"munt.conf\"), \"a\", encoding='utf8') as f:\n            f.write(\"uacomment=main\\nincludeconf=relative.conf\\n\")\n\n    def run_test(self):\n        self.log.info(\"-includeconf works from config file. subversion should end with 'main; relative)/'\")\n\n        subversion = self.nodes[0].getnetworkinfo()[\"subversion\"]\n        assert subversion.endswith(\"main; relative)/\")\n\n        self.log.info(\"-includeconf cannot be used as command-line arg\")\n        self.stop_node(0)\n        self.nodes[0].assert_start_raises_init_error(extra_args=[\"-includeconf=relative2.conf\"], expected_msg=\"Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf\")\n\n        self.log.info(\"-includeconf cannot be used recursively. subversion should end with 'main; relative)/'\")\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"relative.conf\"), \"a\", encoding=\"utf8\") as f:\n            f.write(\"includeconf=relative2.conf\\n\")\n        self.start_node(0)\n\n        subversion = self.nodes[0].getnetworkinfo()[\"subversion\"]\n        assert subversion.endswith(\"main; relative)/\")\n        self.stop_node(0, expected_stderr=\"warning: -includeconf cannot be used from included files; ignoring -includeconf=relative2.conf\")\n\n        self.log.info(\"-includeconf cannot contain invalid arg\")\n\n        # Commented out as long as we ignore invalid arguments in configuration files\n        #with open(os.path.join(self.options.tmpdir, \"node0\", \"relative.conf\"), \"w\", encoding=\"utf8\") as f:\n        #    f.write(\"foo=bar\\n\")\n        #self.nodes[0].assert_start_raises_init_error(expected_msg=\"Error reading configuration file: Invalid configuration value foo\")\n\n        self.log.info(\"-includeconf cannot be invalid path\")\n        os.remove(os.path.join(self.options.tmpdir, \"node0\", \"relative.conf\"))\n        self.nodes[0].assert_start_raises_init_error(expected_msg=\"Error reading configuration file: Failed to include configuration file relative.conf\")\n\n        self.log.info(\"multiple -includeconf args can be used from the base config file. subversion should end with 'main; relative; relative2)/'\")\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"relative.conf\"), \"w\", encoding=\"utf8\") as f:\n            # Restore initial file contents\n            f.write(\"uacomment=relative\\n\")\n\n        with open(os.path.join(self.options.tmpdir, \"node0\", \"munt.conf\"), \"a\", encoding='utf8') as f:\n            f.write(\"includeconf=relative2.conf\\n\")\n\n        self.start_node(0)\n\n        subversion = self.nodes[0].getnetworkinfo()[\"subversion\"]\n        assert subversion.endswith(\"main; relative; relative2)/\")\n\nif __name__ == '__main__':\n    IncludeConfTest().main()\n"
  },
  {
    "path": "test/functional/feature_logging.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test debug logging.\"\"\"\n\nimport os\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.test_node import ErrorMatch\n\n\nclass LoggingTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def relative_log_path(self, name):\n        return os.path.join(self.nodes[0].datadir, \"regtestlegacy\", name)\n\n    def run_test(self):\n        # test default log file name\n        default_log_path = self.relative_log_path(\"debug.log\")\n        assert os.path.isfile(default_log_path)\n\n        # test alternative log file name in datadir\n        #self.restart_node(0, [\"-debuglogfile=foo.log\"])\n        #assert os.path.isfile(self.relative_log_path(\"foo.log\"))\n\n        # test alternative log file name outside datadir\n        #tempname = os.path.join(self.options.tmpdir, \"foo.log\")\n        #self.restart_node(0, [\"-debuglogfile=%s\" % tempname])\n        #assert os.path.isfile(tempname)\n\n        # check that invalid log (relative) will cause error\n        #invdir = self.relative_log_path(\"foo\")\n        #invalidname = os.path.join(\"foo\", \"foo.log\")\n        #self.stop_node(0)\n        #exp_stderr = \"Error: Could not open debug log file \\S+$\"\n        #self.nodes[0].assert_start_raises_init_error([\"-debuglogfile=%s\" % (invalidname)], exp_stderr, match=ErrorMatch.FULL_REGEX)\n        #assert not os.path.isfile(os.path.join(invdir, \"foo.log\"))\n\n        # check that invalid log (relative) works after path exists\n        #self.stop_node(0)\n        #os.mkdir(invdir)\n        #self.start_node(0, [\"-debuglogfile=%s\" % (invalidname)])\n        #assert os.path.isfile(os.path.join(invdir, \"foo.log\"))\n\n        # check that invalid log (absolute) will cause error\n        #self.stop_node(0)\n        #invdir = os.path.join(self.options.tmpdir, \"foo\")\n        #invalidname = os.path.join(invdir, \"foo.log\")\n        #self.nodes[0].assert_start_raises_init_error([\"-debuglogfile=%s\" % invalidname], exp_stderr, match=ErrorMatch.FULL_REGEX)\n        #assert not os.path.isfile(os.path.join(invdir, \"foo.log\"))\n\n        # check that invalid log (absolute) works after path exists\n        #self.stop_node(0)\n        #os.mkdir(invdir)\n        #self.start_node(0, [\"-debuglogfile=%s\" % (invalidname)])\n        #assert os.path.isfile(os.path.join(invdir, \"foo.log\"))\n\n        # check that -nodebuglogfile disables logging\n        #self.stop_node(0)\n        #os.unlink(default_log_path)\n        #assert not os.path.isfile(default_log_path)\n        #self.start_node(0, [\"-nodebuglogfile\"])\n        #assert not os.path.isfile(default_log_path)\n\n        # just sanity check no crash here\n        #self.stop_node(0)\n        #self.start_node(0, [\"-debuglogfile=%s\" % os.devnull])\n\n\nif __name__ == '__main__':\n    LoggingTest().main()\n"
  },
  {
    "path": "test/functional/feature_maxuploadtarget.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test behavior of -maxuploadtarget.\n\n* Verify that getdata requests for old blocks (>1week) are dropped\nif uploadtarget has been reached.\n* Verify that getdata requests for recent blocks are respected even\nif uploadtarget has been reached.\n* Verify that the upload counters are reset after 24 hours.\n\"\"\"\nfrom collections import defaultdict\nimport time\n\nfrom test_framework.messages import CInv, msg_getdata\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, mine_large_block\n\nclass TestP2PConn(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.block_receive_map = defaultdict(int)\n\n    def on_inv(self, message):\n        pass\n\n    def on_block(self, message):\n        message.block.calc_sha256()\n        self.block_receive_map[message.block.sha256] += 1\n\nclass MaxUploadTest(MuntTestFramework):\n\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        self.extra_args = [[\"-maxuploadtarget=800\"]]\n\n        # Cache for utxos, as the listunspent may take a long time later in the test\n        self.utxo_cache = []\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Before we connect anything, we first set the time on the node\n        # to be in the past, otherwise things break because the CNode\n        # time counters can't be reset backward after initialization\n        old_time = int(time.time() - 2*60*60*24*7)\n        self.nodes[0].setmocktime(old_time)\n\n        # Generate some old blocks\n        self.nodes[0].generate(130)\n\n        # p2p_conns[0] will only request old blocks\n        # p2p_conns[1] will only request new blocks\n        # p2p_conns[2] will test resetting the counters\n        p2p_conns = []\n\n        for _ in range(3):\n            p2p_conns.append(self.nodes[0].add_p2p_connection(TestP2PConn()))\n\n        # Now mine a big block\n        mine_large_block(self.nodes[0], self.utxo_cache)\n\n        # Store the hash; we'll request this later\n        big_old_block = self.nodes[0].getbestblockhash()\n        old_block_size = self.nodes[0].getblock(big_old_block, True)['size']\n        big_old_block = int(big_old_block, 16)\n\n        # Advance to two days ago\n        self.nodes[0].setmocktime(int(time.time()) - 2*60*60*24)\n\n        # Mine one more block, so that the prior block looks old\n        mine_large_block(self.nodes[0], self.utxo_cache)\n\n        # We'll be requesting this new block too\n        big_new_block = self.nodes[0].getbestblockhash()\n        big_new_block = int(big_new_block, 16)\n\n        # p2p_conns[0] will test what happens if we just keep requesting the\n        # the same big old block too many times (expect: disconnect)\n\n        getdata_request = msg_getdata()\n        getdata_request.inv.append(CInv(2, big_old_block))\n\n        max_bytes_per_day = 800*1024*1024\n        daily_buffer = 144 * 4000000\n        max_bytes_available = max_bytes_per_day - daily_buffer\n        success_count = max_bytes_available // old_block_size\n\n        # 576MB will be reserved for relaying new blocks, so expect this to\n        # succeed for ~235 tries.\n        for i in range(success_count):\n            p2p_conns[0].send_message(getdata_request)\n            p2p_conns[0].sync_with_ping()\n            assert_equal(p2p_conns[0].block_receive_map[big_old_block], i+1)\n\n        assert_equal(len(self.nodes[0].getpeerinfo()), 3)\n        # At most a couple more tries should succeed (depending on how long\n        # the test has been running so far).\n        for i in range(3):\n            p2p_conns[0].send_message(getdata_request)\n        p2p_conns[0].wait_for_disconnect()\n        assert_equal(len(self.nodes[0].getpeerinfo()), 2)\n        self.log.info(\"Peer 0 disconnected after downloading old block too many times\")\n\n        # Requesting the current block on p2p_conns[1] should succeed indefinitely,\n        # even when over the max upload target.\n        # We'll try 800 times\n        getdata_request.inv = [CInv(2, big_new_block)]\n        for i in range(800):\n            p2p_conns[1].send_message(getdata_request)\n            p2p_conns[1].sync_with_ping()\n            assert_equal(p2p_conns[1].block_receive_map[big_new_block], i+1)\n\n        self.log.info(\"Peer 1 able to repeatedly download new block\")\n\n        # But if p2p_conns[1] tries for an old block, it gets disconnected too.\n        getdata_request.inv = [CInv(2, big_old_block)]\n        p2p_conns[1].send_message(getdata_request)\n        p2p_conns[1].wait_for_disconnect()\n        assert_equal(len(self.nodes[0].getpeerinfo()), 1)\n\n        self.log.info(\"Peer 1 disconnected after trying to download old block\")\n\n        self.log.info(\"Advancing system time on node to clear counters...\")\n\n        # If we advance the time by 24 hours, then the counters should reset,\n        # and p2p_conns[2] should be able to retrieve the old block.\n        self.nodes[0].setmocktime(int(time.time()))\n        p2p_conns[2].sync_with_ping()\n        p2p_conns[2].send_message(getdata_request)\n        p2p_conns[2].sync_with_ping()\n        assert_equal(p2p_conns[2].block_receive_map[big_old_block], 1)\n\n        self.log.info(\"Peer 2 able to download old block\")\n\n        self.nodes[0].disconnect_p2ps()\n\n        #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1\n        self.log.info(\"Restarting nodes with -whitelist=127.0.0.1\")\n        self.stop_node(0)\n        self.start_node(0, [\"-whitelist=127.0.0.1\", \"-maxuploadtarget=1\"])\n\n        # Reconnect to self.nodes[0]\n        self.nodes[0].add_p2p_connection(TestP2PConn())\n\n        #retrieve 20 blocks which should be enough to break the 1MB limit\n        getdata_request.inv = [CInv(2, big_new_block)]\n        for i in range(20):\n            self.nodes[0].p2p.send_message(getdata_request)\n            self.nodes[0].p2p.sync_with_ping()\n            assert_equal(self.nodes[0].p2p.block_receive_map[big_new_block], i+1)\n\n        getdata_request.inv = [CInv(2, big_old_block)]\n        self.nodes[0].p2p.send_and_ping(getdata_request)\n        assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist\n\n        self.log.info(\"Peer still connected after trying to download old block (whitelisted)\")\n\nif __name__ == '__main__':\n    MaxUploadTest().main()\n"
  },
  {
    "path": "test/functional/feature_minchainwork.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test logic for setting nMinimumChainWork on command line.\n\nNodes don't consider themselves out of \"initial block download\" until\ntheir active chain has more work than nMinimumChainWork.\n\nNodes don't download blocks from a peer unless the peer's best known block\nhas more work than nMinimumChainWork.\n\nWhile in initial block download, nodes won't relay blocks to their peers, so\ntest that this parameter functions as intended by verifying that block relay\nonly succeeds past a given node once its nMinimumChainWork has been exceeded.\n\"\"\"\n\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import connect_nodes, assert_equal\n\n# 2 hashes required per regtest block (with no difficulty adjustment)\nREGTEST_WORK_PER_BLOCK = 2\n\nclass MinimumChainWorkTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n\n        self.extra_args = [[], [\"-minimumchainwork=0x65\"], [\"-minimumchainwork=0x65\"]]\n        self.node_min_work = [0, 101, 101]\n\n    def setup_network(self):\n        # This test relies on the chain setup being:\n        # node0 <- node1 <- node2\n        # Before leaving IBD, nodes prefer to download blocks from outbound\n        # peers, so ensure that we're mining on an outbound peer and testing\n        # block relay to inbound peers.\n        self.setup_nodes()\n        for i in range(self.num_nodes-1):\n            connect_nodes(self.nodes[i+1], i)\n\n    def run_test(self):\n        # Start building a chain on node0.  node2 shouldn't be able to sync until node1's\n        # minchainwork is exceeded\n        starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work\n        self.log.info(\"Testing relay across node %d (minChainWork = %d)\", 1, self.node_min_work[1])\n\n        starting_blockcount = self.nodes[2].getblockcount()\n\n        num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK)\n        self.log.info(\"Generating %d blocks on node0\", num_blocks_to_generate)\n        hashes = self.nodes[0].generatetoaddress(num_blocks_to_generate,\n                                                 self.nodes[0].get_deterministic_priv_key().address)\n\n        self.log.info(\"Node0 current chain work: %s\", self.nodes[0].getblockheader(hashes[-1])['chainwork'])\n\n        # Sleep a few seconds and verify that node2 didn't get any new blocks\n        # or headers.  We sleep, rather than sync_blocks(node0, node1) because\n        # it's reasonable either way for node1 to get the blocks, or not get\n        # them (since they're below node1's minchainwork).\n        time.sleep(3)\n\n        self.log.info(\"Verifying node 2 has no more blocks than before\")\n        self.log.info(\"Blockcounts: %s\", [n.getblockcount() for n in self.nodes])\n        # Node2 shouldn't have any new headers yet, because node1 should not\n        # have relayed anything.\n        assert_equal(len(self.nodes[2].getchaintips()), 1)\n        ###assert_equal(self.nodes[2].getchaintips()[0]['height'], 0)\n\n        ###assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash()\n        ###assert_equal(self.nodes[2].getblockcount(), starting_blockcount)\n\n        self.log.info(\"Generating one more block\")\n        self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)\n\n        self.log.info(\"Verifying nodes are all synced\")\n\n        # Because nodes in regtest are all manual connections (eg using\n        # addnode), node1 should not have disconnected node0. If not for that,\n        # we'd expect node1 to have disconnected node0 for serving an\n        # insufficient work chain, in which case we'd need to reconnect them to\n        # continue the test.\n\n        self.sync_all()\n        self.log.info(\"Blockcounts: %s\", [n.getblockcount() for n in self.nodes])\n\nif __name__ == '__main__':\n    MinimumChainWorkTest().main()\n"
  },
  {
    "path": "test/functional/feature_notifications.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the -alertnotify, -blocknotify and -walletnotify options.\"\"\"\nimport os\n\nfrom test_framework.address import ADDRESS_BCRT1_UNSPENDABLE\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, wait_until, connect_nodes_bi\n\n\nclass NotificationsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n\n    def setup_network(self):\n        self.alertnotify_dir = os.path.join(self.options.tmpdir, \"alertnotify\")\n        self.blocknotify_dir = os.path.join(self.options.tmpdir, \"blocknotify\")\n        self.walletnotify_dir = os.path.join(self.options.tmpdir, \"walletnotify\")\n        os.mkdir(self.alertnotify_dir)\n        os.mkdir(self.blocknotify_dir)\n        os.mkdir(self.walletnotify_dir)\n\n        # -alertnotify and -blocknotify on node0, walletnotify on node1\n        self.extra_args = [[\n                            \"-alertnotify=echo > {}\".format(os.path.join(self.alertnotify_dir, '%s')),\n                            \"-blocknotify=echo > {}\".format(os.path.join(self.blocknotify_dir, '%s'))],\n                           [\"-blockversion=211\",\n                            \"-rescan\",\n                            \"-walletnotify=echo > {}\".format(os.path.join(self.walletnotify_dir, '%s'))]]\n        super().setup_network()\n\n    def run_test(self):\n        self.log.info(\"test -blocknotify\")\n        block_count = 10\n        blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE)\n\n        # wait at most 10 seconds for expected number of files before reading the content\n        wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10)\n\n        # directory content should equal the generated blocks hashes\n        assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir)))\n\n        if self.is_wallet_compiled():\n            self.log.info(\"test -walletnotify\")\n            # wait at most 10 seconds for expected number of files before reading the content\n            wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)\n\n            # directory content should equal the generated transaction hashes\n            txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions(\"*\", block_count)))\n            assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))\n            self.stop_node(1)\n            for tx_file in os.listdir(self.walletnotify_dir):\n                os.remove(os.path.join(self.walletnotify_dir, tx_file))\n\n            self.log.info(\"test -walletnotify after rescan\")\n            # restart node to rescan to force wallet notifications\n            self.start_node(1)\n            connect_nodes_bi(self.nodes, 0, 1)\n\n            wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)\n\n            # directory content should equal the generated transaction hashes\n            txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions(\"*\", block_count)))\n            assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))\n\n        # TODO: add test for `-alertnotify` large fork notifications\n\nif __name__ == '__main__':\n    NotificationsTest().main()\n"
  },
  {
    "path": "test/functional/feature_nulldummy.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test NULLDUMMY softfork.\n\nConnect to a single node.\nGenerate 2 blocks (save the coinbases for later).\nGenerate 427 more blocks.\n[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.\n[Policy] Check that non-NULLDUMMY transactions are rejected before activation.\n[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block.\n[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.\n\"\"\"\nimport time\n\nfrom test_framework.blocktools import create_coinbase, create_block, create_transaction, add_witness_commitment\nfrom test_framework.messages import CTransaction\nfrom test_framework.script import CScript\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\nNULLDUMMY_ERROR = \"non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)\"\n\ndef trueDummy(tx):\n    scriptSig = CScript(tx.vin[0].scriptSig)\n    newscript = []\n    for i in scriptSig:\n        if (len(newscript) == 0):\n            assert len(i) == 0\n            newscript.append(b'\\x51')\n        else:\n            newscript.append(i)\n    tx.vin[0].scriptSig = CScript(newscript)\n    tx.rehash()\n\nclass NULLDUMMYTest(MuntTestFramework):\n\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n        # This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through\n        # normal segwit activation here (and don't use the default always-on behaviour).\n        self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy']]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.address = self.nodes[0].getnewaddress()\n        self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address']\n        self.wit_address = self.nodes[0].getnewaddress(address_type='p2sh-segwit')\n        self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address']\n\n        self.coinbase_blocks = self.nodes[0].generate(2)  # Block 2\n        coinbase_txid = []\n        for i in self.coinbase_blocks:\n            coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])\n        self.nodes[0].generate(427)  # Block 429\n        self.lastblockhash = self.nodes[0].getbestblockhash()\n        self.tip = int(\"0x\" + self.lastblockhash, 0)\n        self.lastblockheight = 429\n        self.lastblocktime = int(time.time()) + 429\n\n        self.log.info(\"Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]\")\n        test1txs = [create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, amount=49)]\n        txid1 = self.nodes[0].sendrawtransaction(test1txs[0].serialize_with_witness().hex(), 0)\n        test1txs.append(create_transaction(self.nodes[0], txid1, self.ms_address, amount=48))\n        txid2 = self.nodes[0].sendrawtransaction(test1txs[1].serialize_with_witness().hex(), 0)\n        test1txs.append(create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, amount=49))\n        txid3 = self.nodes[0].sendrawtransaction(test1txs[2].serialize_with_witness().hex(), 0)\n        self.block_submit(self.nodes[0], test1txs, False, True)\n\n        self.log.info(\"Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation\")\n        test2tx = create_transaction(self.nodes[0], txid2, self.ms_address, amount=47)\n        trueDummy(test2tx)\n        assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test2tx.serialize_with_witness().hex(), 0)\n\n        self.log.info(\"Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]\")\n        self.block_submit(self.nodes[0], [test2tx], False, True)\n\n        self.log.info(\"Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation\")\n        test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46)\n        test6txs = [CTransaction(test4tx)]\n        trueDummy(test4tx)\n        assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test4tx.serialize_with_witness().hex(), 0)\n        self.block_submit(self.nodes[0], [test4tx])\n\n        self.log.info(\"Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation\")\n        test5tx = create_transaction(self.nodes[0], txid3, self.wit_address, amount=48)\n        test6txs.append(CTransaction(test5tx))\n        test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\\x01'\n        assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test5tx.serialize_with_witness().hex(), 0)\n        self.block_submit(self.nodes[0], [test5tx], True)\n\n        self.log.info(\"Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]\")\n        for i in test6txs:\n            self.nodes[0].sendrawtransaction(i.serialize_with_witness().hex(), 0)\n        self.block_submit(self.nodes[0], test6txs, True, True)\n\n    def block_submit(self, node, txs, witness=False, accept=False):\n        block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)\n        block.nVersion = 4\n        for tx in txs:\n            tx.rehash()\n            block.vtx.append(tx)\n        block.hashMerkleRoot = block.calc_merkle_root()\n        witness and add_witness_commitment(block)\n        block.rehash()\n        block.solve()\n        node.submitblock(block.serialize(True).hex())\n        if (accept):\n            assert_equal(node.getbestblockhash(), block.hash)\n            self.tip = block.sha256\n            self.lastblockhash = block.hash\n            self.lastblocktime += 1\n            self.lastblockheight += 1\n        else:\n            assert_equal(node.getbestblockhash(), self.lastblockhash)\n\nif __name__ == '__main__':\n    NULLDUMMYTest().main()\n"
  },
  {
    "path": "test/functional/feature_proxy.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test Munt-daemon with different proxy configuration.\n\nTest plan:\n- Start Munt-daemon's with different proxy configurations\n- Use addnode to initiate connections\n- Verify that proxies are connected to, and the right connection command is given\n- Proxy configurations to test on Munt-daemon side:\n    - `-proxy` (proxy everything)\n    - `-onion` (proxy just onions)\n    - `-proxyrandomize` Circuit randomization\n- Proxy configurations to test on proxy side,\n    - support no authentication (other proxy)\n    - support no authentication + user/pass authentication (Tor)\n    - proxy on IPv6\n\n- Create various proxies (as threads)\n- Create Mint-daemons that connect to them\n- Manipulate the Munt-daemons using addnode (onetry) an observe effects\n\naddnode connect to IPv4\naddnode connect to IPv6\naddnode connect to onion\naddnode connect to generic DNS name\n\"\"\"\n\nimport socket\nimport os\n\nfrom test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    PORT_MIN,\n    PORT_RANGE,\n    assert_equal,\n)\nfrom test_framework.netutil import test_ipv6_local\n\nRANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE  # Start after p2p and rpc ports\n\nclass ProxyTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n\n    def setup_nodes(self):\n        self.have_ipv6 = test_ipv6_local()\n        # Create two proxies on different ports\n        # ... one unauthenticated\n        self.conf1 = Socks5Configuration()\n        self.conf1.addr = ('127.0.0.1', RANGE_BEGIN + (os.getpid() % 1000))\n        self.conf1.unauth = True\n        self.conf1.auth = False\n        # ... one supporting authenticated and unauthenticated (Tor)\n        self.conf2 = Socks5Configuration()\n        self.conf2.addr = ('127.0.0.1', RANGE_BEGIN + 1000 + (os.getpid() % 1000))\n        self.conf2.unauth = True\n        self.conf2.auth = True\n        if self.have_ipv6:\n            # ... one on IPv6 with similar configuration\n            self.conf3 = Socks5Configuration()\n            self.conf3.af = socket.AF_INET6\n            self.conf3.addr = ('::1', RANGE_BEGIN + 2000 + (os.getpid() % 1000))\n            self.conf3.unauth = True\n            self.conf3.auth = True\n        else:\n            self.log.warning(\"Testing without local IPv6 support\")\n\n        self.serv1 = Socks5Server(self.conf1)\n        self.serv1.start()\n        self.serv2 = Socks5Server(self.conf2)\n        self.serv2.start()\n        if self.have_ipv6:\n            self.serv3 = Socks5Server(self.conf3)\n            self.serv3.start()\n\n        # Note: proxies are not used to connect to local nodes\n        # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost\n        args = [\n            ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],\n            ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],\n            ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],\n            []\n            ]\n        if self.have_ipv6:\n            args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']\n        self.add_nodes(self.num_nodes, extra_args=args)\n        self.start_nodes()\n\n    def node_test(self, node, proxies, auth, test_onion=True):\n        rv = []\n        # Test: outgoing IPv4 connection through node\n        node.addnode(\"15.61.23.23:1234\", \"onetry\")\n        cmd = proxies[0].queue.get()\n        assert isinstance(cmd, Socks5Command)\n        # Note: Munt-daemon's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6\n        assert_equal(cmd.atyp, AddressType.DOMAINNAME)\n        assert_equal(cmd.addr, b\"15.61.23.23\")\n        assert_equal(cmd.port, 1234)\n        if not auth:\n            assert_equal(cmd.username, None)\n            assert_equal(cmd.password, None)\n        rv.append(cmd)\n\n        if self.have_ipv6:\n            # Test: outgoing IPv6 connection through node\n            node.addnode(\"[1233:3432:2434:2343:3234:2345:6546:4534]:5443\", \"onetry\")\n            cmd = proxies[1].queue.get()\n            assert isinstance(cmd, Socks5Command)\n            # Note: Munt-daemon's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6\n            assert_equal(cmd.atyp, AddressType.DOMAINNAME)\n            assert_equal(cmd.addr, b\"1233:3432:2434:2343:3234:2345:6546:4534\")\n            assert_equal(cmd.port, 5443)\n            if not auth:\n                assert_equal(cmd.username, None)\n                assert_equal(cmd.password, None)\n            rv.append(cmd)\n\n        if test_onion:\n            # Test: outgoing onion connection through node\n            node.addnode(\"bitcoinostk4e4re.onion:8333\", \"onetry\")\n            cmd = proxies[2].queue.get()\n            assert isinstance(cmd, Socks5Command)\n            assert_equal(cmd.atyp, AddressType.DOMAINNAME)\n            assert_equal(cmd.addr, b\"bitcoinostk4e4re.onion\")\n            assert_equal(cmd.port, 8333)\n            if not auth:\n                assert_equal(cmd.username, None)\n                assert_equal(cmd.password, None)\n            rv.append(cmd)\n\n        # Test: outgoing DNS name connection through node\n        node.addnode(\"node.noumenon:8333\", \"onetry\")\n        cmd = proxies[3].queue.get()\n        assert isinstance(cmd, Socks5Command)\n        assert_equal(cmd.atyp, AddressType.DOMAINNAME)\n        assert_equal(cmd.addr, b\"node.noumenon\")\n        assert_equal(cmd.port, 8333)\n        if not auth:\n            assert_equal(cmd.username, None)\n            assert_equal(cmd.password, None)\n        rv.append(cmd)\n\n        return rv\n\n    def run_test(self):\n        # basic -proxy\n        self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False)\n\n        # -proxy plus -onion\n        self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False)\n\n        # -proxy plus -onion, -proxyrandomize\n        rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True)\n        # Check that credentials as used for -proxyrandomize connections are unique\n        credentials = set((x.username,x.password) for x in rv)\n        assert_equal(len(credentials), len(rv))\n\n        if self.have_ipv6:\n            # proxy on IPv6 localhost\n            self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False)\n\n        def networks_dict(d):\n            r = {}\n            for x in d['networks']:\n                r[x['name']] = x\n            return r\n\n        # test RPC getnetworkinfo\n        n0 = networks_dict(self.nodes[0].getnetworkinfo())\n        for net in ['ipv4','ipv6','onion']:\n            assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr))\n            assert_equal(n0[net]['proxy_randomize_credentials'], True)\n        assert_equal(n0['onion']['reachable'], True)\n\n        n1 = networks_dict(self.nodes[1].getnetworkinfo())\n        for net in ['ipv4','ipv6']:\n            assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr))\n            assert_equal(n1[net]['proxy_randomize_credentials'], False)\n        assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr))\n        assert_equal(n1['onion']['proxy_randomize_credentials'], False)\n        assert_equal(n1['onion']['reachable'], True)\n\n        n2 = networks_dict(self.nodes[2].getnetworkinfo())\n        for net in ['ipv4','ipv6','onion']:\n            assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr))\n            assert_equal(n2[net]['proxy_randomize_credentials'], True)\n        assert_equal(n2['onion']['reachable'], True)\n\n        if self.have_ipv6:\n            n3 = networks_dict(self.nodes[3].getnetworkinfo())\n            for net in ['ipv4','ipv6']:\n                assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr))\n                assert_equal(n3[net]['proxy_randomize_credentials'], False)\n            assert_equal(n3['onion']['reachable'], False)\n\nif __name__ == '__main__':\n    ProxyTest().main()\n"
  },
  {
    "path": "test/functional/feature_pruning.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the pruning code.\n\nWARNING:\nThis test uses 4GB of disk space.\nThis test takes 30 mins or more (up to 2 hours)\n\"\"\"\nimport os\n\nfrom test_framework.blocktools import create_coinbase\nfrom test_framework.messages import CBlock, ToHex\nfrom test_framework.script import CScript, OP_RETURN, OP_NOP\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, connect_nodes, disconnect_nodes, sync_blocks, wait_until\n\nMIN_BLOCKS_TO_KEEP = 288\n\n# Rescans start at the earliest block up to 2 hours before a key timestamp, so\n# the manual prune RPC avoids pruning blocks in the same window to be\n# compatible with pruning based on key creation time.\nTIMESTAMP_WINDOW = 2 * 60 * 60\n\ndef mine_large_blocks(node, n):\n    # Make a large scriptPubKey for the coinbase transaction. This is OP_RETURN\n    # followed by 950k of OP_NOP. This would be non-standard in a non-coinbase\n    # transaction but is consensus valid.\n\n    # Get the block parameters for the first block\n    big_script = CScript([OP_RETURN] + [OP_NOP] * 950000)\n    best_block = node.getblock(node.getbestblockhash())\n    height = int(best_block[\"height\"]) + 1\n    try:\n        # Static variable ensures that time is monotonicly increasing and is therefore\n        # different for each block created => blockhash is unique.\n        mine_large_blocks.nTime = min(mine_large_blocks.nTime, int(best_block[\"time\"])) + 1\n    except AttributeError:\n        mine_large_blocks.nTime = int(best_block[\"time\"]) + 1\n    previousblockhash = int(best_block[\"hash\"], 16)\n\n    for _ in range(n):\n        # Build the coinbase transaction (with large scriptPubKey)\n        coinbase_tx = create_coinbase(height)\n        coinbase_tx.vin[0].nSequence = 2 ** 32 - 1\n        coinbase_tx.vout[0].scriptPubKey = big_script\n        coinbase_tx.rehash()\n\n        # Build the block\n        block = CBlock()\n        block.nVersion = best_block[\"version\"]\n        block.hashPrevBlock = previousblockhash\n        block.nTime = mine_large_blocks.nTime\n        block.nBits = int('207fffff', 16)\n        block.nNonce = 0\n        block.vtx = [coinbase_tx]\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n\n        # Submit to the node\n        node.submitblock(ToHex(block))\n\n        previousblockhash = block.sha256\n        height += 1\n        mine_large_blocks.nTime += 1\n\ndef calc_usage(blockdir):\n    return sum(os.path.getsize(blockdir + f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.)\n\nclass PruneTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 6\n\n        # Create nodes 0 and 1 to mine.\n        # Create node 2 to test pruning.\n        self.full_node_default_args = [\"-maxreceivebuffer=20000\", \"-checkblocks=5\"]\n        # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)\n        # Create nodes 5 to test wallet in prune mode, but do not connect\n        self.extra_args = [\n            self.full_node_default_args,\n            self.full_node_default_args,\n            [\"-maxreceivebuffer=20000\", \"-prune=550\"],\n            [\"-maxreceivebuffer=20000\"],\n            [\"-maxreceivebuffer=20000\"],\n            [\"-prune=550\"],\n        ]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n\n        self.prunedir = os.path.join(self.nodes[2].datadir, 'regtest', 'blocks', '')\n\n        connect_nodes(self.nodes[0], 1)\n        connect_nodes(self.nodes[1], 2)\n        connect_nodes(self.nodes[0], 2)\n        connect_nodes(self.nodes[0], 3)\n        connect_nodes(self.nodes[0], 4)\n        sync_blocks(self.nodes[0:5])\n\n    def setup_nodes(self):\n        self.add_nodes(self.num_nodes, self.extra_args)\n        self.start_nodes()\n        for n in self.nodes:\n            n.importprivkey(muntprivkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=False)\n\n    def create_big_chain(self):\n        # Start by creating some coinbases we can spend later\n        self.nodes[1].generate(200)\n        sync_blocks(self.nodes[0:2])\n        self.nodes[0].generate(150)\n\n        # Then mine enough full blocks to create more than 550MiB of data\n        mine_large_blocks(self.nodes[0], 645)\n\n        sync_blocks(self.nodes[0:5])\n\n    def test_height_min(self):\n        assert os.path.isfile(os.path.join(self.prunedir, \"blk00000.dat\")), \"blk00000.dat is missing, pruning too early\"\n        self.log.info(\"Success\")\n        self.log.info(\"Though we're already using more than 550MiB, current usage: %d\" % calc_usage(self.prunedir))\n        self.log.info(\"Mining 25 more blocks should cause the first block file to be pruned\")\n        # Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this\n        mine_large_blocks(self.nodes[0], 25)\n\n        # Wait for blk00000.dat to be pruned\n        wait_until(lambda: not os.path.isfile(os.path.join(self.prunedir, \"blk00000.dat\")), timeout=30)\n\n        self.log.info(\"Success\")\n        usage = calc_usage(self.prunedir)\n        self.log.info(\"Usage should be below target: %d\" % usage)\n        assert_greater_than(550, usage)\n\n    def create_chain_with_staleblocks(self):\n        # Create stale blocks in manageable sized chunks\n        self.log.info(\"Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds\")\n\n        for j in range(12):\n            # Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain\n            # Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects\n            disconnect_nodes(self.nodes[0], 1)\n            disconnect_nodes(self.nodes[0], 2)\n            # Mine 24 blocks in node 1\n            mine_large_blocks(self.nodes[1], 24)\n\n            # Reorg back with 25 block chain from node 0\n            mine_large_blocks(self.nodes[0], 25)\n\n            # Create connections in the order so both nodes can see the reorg at the same time\n            connect_nodes(self.nodes[0], 1)\n            connect_nodes(self.nodes[0], 2)\n            sync_blocks(self.nodes[0:3])\n\n        self.log.info(\"Usage can be over target because of high stale rate: %d\" % calc_usage(self.prunedir))\n\n    def reorg_test(self):\n        # Node 1 will mine a 300 block chain starting 287 blocks back from Node 0 and Node 2's tip\n        # This will cause Node 2 to do a reorg requiring 288 blocks of undo data to the reorg_test chain\n\n        height = self.nodes[1].getblockcount()\n        self.log.info(\"Current block height: %d\" % height)\n\n        self.forkheight = height - 287\n        self.forkhash = self.nodes[1].getblockhash(self.forkheight)\n        self.log.info(\"Invalidating block %s at height %d\" % (self.forkhash, self.forkheight))\n        self.nodes[1].invalidateblock(self.forkhash)\n\n        # We've now switched to our previously mined-24 block fork on node 1, but that's not what we want\n        # So invalidate that fork as well, until we're on the same chain as node 0/2 (but at an ancestor 288 blocks ago)\n        mainchainhash = self.nodes[0].getblockhash(self.forkheight - 1)\n        curhash = self.nodes[1].getblockhash(self.forkheight - 1)\n        while curhash != mainchainhash:\n            self.nodes[1].invalidateblock(curhash)\n            curhash = self.nodes[1].getblockhash(self.forkheight - 1)\n\n        assert self.nodes[1].getblockcount() == self.forkheight - 1\n        self.log.info(\"New best height: %d\" % self.nodes[1].getblockcount())\n\n        # Disconnect node1 and generate the new chain\n        disconnect_nodes(self.nodes[0], 1)\n        disconnect_nodes(self.nodes[1], 2)\n\n        self.log.info(\"Generating new longer chain of 300 more blocks\")\n        self.nodes[1].generate(300)\n\n        self.log.info(\"Reconnect nodes\")\n        connect_nodes(self.nodes[0], 1)\n        connect_nodes(self.nodes[1], 2)\n        sync_blocks(self.nodes[0:3], timeout=120)\n\n        self.log.info(\"Verify height on node 2: %d\" % self.nodes[2].getblockcount())\n        self.log.info(\"Usage possibly still high because of stale blocks in block files: %d\" % calc_usage(self.prunedir))\n\n        self.log.info(\"Mine 220 more large blocks so we have requisite history\")\n\n        mine_large_blocks(self.nodes[0], 220)\n\n        usage = calc_usage(self.prunedir)\n        self.log.info(\"Usage should be below target: %d\" % usage)\n        assert_greater_than(550, usage)\n\n    def reorg_back(self):\n        # Verify that a block on the old main chain fork has been pruned away\n        assert_raises_rpc_error(-1, \"Block not available (pruned data)\", self.nodes[2].getblock, self.forkhash)\n        with self.nodes[2].assert_debug_log(expected_msgs=['block verification stopping at height', '(pruning, no data)']):\n            self.nodes[2].verifychain(checklevel=4, num_blocks=0)\n        self.log.info(\"Will need to redownload block %d\" % self.forkheight)\n\n        # Verify that we have enough history to reorg back to the fork point\n        # Although this is more than 288 blocks, because this chain was written more recently\n        # and only its other 299 small and 220 large blocks are in the block files after it,\n        # it is expected to still be retained\n        self.nodes[2].getblock(self.nodes[2].getblockhash(self.forkheight))\n\n        first_reorg_height = self.nodes[2].getblockcount()\n        curchainhash = self.nodes[2].getblockhash(self.mainchainheight)\n        self.nodes[2].invalidateblock(curchainhash)\n        goalbestheight = self.mainchainheight\n        goalbesthash = self.mainchainhash2\n\n        # As of 0.10 the current block download logic is not able to reorg to the original chain created in\n        # create_chain_with_stale_blocks because it doesn't know of any peer that's on that chain from which to\n        # redownload its missing blocks.\n        # Invalidate the reorg_test chain in node 0 as well, it can successfully switch to the original chain\n        # because it has all the block data.\n        # However it must mine enough blocks to have a more work chain than the reorg_test chain in order\n        # to trigger node 2's block download logic.\n        # At this point node 2 is within 288 blocks of the fork point so it will preserve its ability to reorg\n        if self.nodes[2].getblockcount() < self.mainchainheight:\n            blocks_to_mine = first_reorg_height + 1 - self.mainchainheight\n            self.log.info(\"Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed: %d\" % blocks_to_mine)\n            self.nodes[0].invalidateblock(curchainhash)\n            assert_equal(self.nodes[0].getblockcount(), self.mainchainheight)\n            assert_equal(self.nodes[0].getbestblockhash(), self.mainchainhash2)\n            goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1]\n            goalbestheight = first_reorg_height + 1\n\n        self.log.info(\"Verify node 2 reorged back to the main chain, some blocks of which it had to redownload\")\n        # Wait for Node 2 to reorg to proper height\n        wait_until(lambda: self.nodes[2].getblockcount() >= goalbestheight, timeout=900)\n        assert_equal(self.nodes[2].getbestblockhash(), goalbesthash)\n        # Verify we can now have the data for a block previously pruned\n        assert_equal(self.nodes[2].getblock(self.forkhash)[\"height\"], self.forkheight)\n\n    def manual_test(self, node_number, use_timestamp):\n        # at this point, node has 995 blocks and has not yet run in prune mode\n        self.start_node(node_number)\n        node = self.nodes[node_number]\n        assert_equal(node.getblockcount(), 995)\n        assert_raises_rpc_error(-1, \"not in prune mode\", node.pruneblockchain, 500)\n\n        # now re-start in manual pruning mode\n        self.stop_node(node_number)\n        self.start_node(node_number, extra_args=[\"-prune=1\"])\n        node = self.nodes[node_number]\n        assert_equal(node.getblockcount(), 995)\n\n        def height(index):\n            if use_timestamp:\n                return node.getblockheader(node.getblockhash(index))[\"time\"] + TIMESTAMP_WINDOW\n            else:\n                return index\n\n        def prune(index, expected_ret=None):\n            ret = node.pruneblockchain(height=height(index))\n            # Check the return value. When use_timestamp is True, just check\n            # that the return value is less than or equal to the expected\n            # value, because when more than one block is generated per second,\n            # a timestamp will not be granular enough to uniquely identify an\n            # individual block.\n            if expected_ret is None:\n                expected_ret = index\n            if use_timestamp:\n                assert_greater_than(ret, 0)\n                assert_greater_than(expected_ret + 1, ret)\n            else:\n                assert_equal(ret, expected_ret)\n\n        def has_block(index):\n            return os.path.isfile(os.path.join(self.nodes[node_number].datadir, \"regtest\", \"blocks\", \"blk{:05}.dat\".format(index)))\n\n        # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)\n        assert_raises_rpc_error(-1, \"Blockchain is too short for pruning\", node.pruneblockchain, height(500))\n\n        # Save block transaction count before pruning, assert value\n        block1_details = node.getblock(node.getblockhash(1))\n        assert_equal(block1_details[\"nTx\"], len(block1_details[\"tx\"]))\n\n        # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)\n        node.generate(6)\n        assert_equal(node.getblockchaininfo()[\"blocks\"], 1001)\n\n        # Pruned block should still know the number of transactions\n        assert_equal(node.getblockheader(node.getblockhash(1))[\"nTx\"], block1_details[\"nTx\"])\n\n        # negative heights should raise an exception\n        assert_raises_rpc_error(-8, \"Negative\", node.pruneblockchain, -10)\n\n        # height=100 too low to prune first block file so this is a no-op\n        prune(100)\n        assert has_block(0), \"blk00000.dat is missing when should still be there\"\n\n        # Does nothing\n        node.pruneblockchain(height(0))\n        assert has_block(0), \"blk00000.dat is missing when should still be there\"\n\n        # height=500 should prune first file\n        prune(500)\n        assert not has_block(0), \"blk00000.dat is still there, should be pruned by now\"\n        assert has_block(1), \"blk00001.dat is missing when should still be there\"\n\n        # height=650 should prune second file\n        prune(650)\n        assert not has_block(1), \"blk00001.dat is still there, should be pruned by now\"\n\n        # height=1000 should not prune anything more, because tip-288 is in blk00002.dat.\n        prune(1000, 1001 - MIN_BLOCKS_TO_KEEP)\n        assert has_block(2), \"blk00002.dat is still there, should be pruned by now\"\n\n        # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)\n        node.generate(288)\n        prune(1000)\n        assert not has_block(2), \"blk00002.dat is still there, should be pruned by now\"\n        assert not has_block(3), \"blk00003.dat is still there, should be pruned by now\"\n\n        # stop node, start back up with auto-prune at 550 MiB, make sure still runs\n        self.stop_node(node_number)\n        self.start_node(node_number, extra_args=[\"-prune=550\"])\n\n        self.log.info(\"Success\")\n\n    def wallet_test(self):\n        # check that the pruning node's wallet is still in good shape\n        self.log.info(\"Stop and start pruning node to trigger wallet rescan\")\n        self.stop_node(2)\n        self.start_node(2, extra_args=[\"-prune=550\"])\n        self.log.info(\"Success\")\n\n        # check that wallet loads successfully when restarting a pruned node after IBD.\n        # this was reported to fail in #7494.\n        self.log.info(\"Syncing node 5 to test wallet\")\n        connect_nodes(self.nodes[0], 5)\n        nds = [self.nodes[0], self.nodes[5]]\n        sync_blocks(nds, wait=5, timeout=300)\n        self.stop_node(5)  # stop and start to trigger rescan\n        self.start_node(5, extra_args=[\"-prune=550\"])\n        self.log.info(\"Success\")\n\n    def run_test(self):\n        self.log.info(\"Warning! This test requires 4GB of disk space\")\n\n        self.log.info(\"Mining a big blockchain of 995 blocks\")\n        self.create_big_chain()\n        # Chain diagram key:\n        # *   blocks on main chain\n        # +,&,$,@ blocks on other forks\n        # X   invalidated block\n        # N1  Node 1\n        #\n        # Start by mining a simple chain that all nodes have\n        # N0=N1=N2 **...*(995)\n\n        # stop manual-pruning node with 995 blocks\n        self.stop_node(3)\n        self.stop_node(4)\n\n        self.log.info(\"Check that we haven't started pruning yet because we're below PruneAfterHeight\")\n        self.test_height_min()\n        # Extend this chain past the PruneAfterHeight\n        # N0=N1=N2 **...*(1020)\n\n        self.log.info(\"Check that we'll exceed disk space target if we have a very high stale block rate\")\n        self.create_chain_with_staleblocks()\n        # Disconnect N0\n        # And mine a 24 block chain on N1 and a separate 25 block chain on N0\n        # N1=N2 **...*+...+(1044)\n        # N0    **...**...**(1045)\n        #\n        # reconnect nodes causing reorg on N1 and N2\n        # N1=N2 **...*(1020) *...**(1045)\n        #                   \\\n        #                    +...+(1044)\n        #\n        # repeat this process until you have 12 stale forks hanging off the\n        # main chain on N1 and N2\n        # N0    *************************...***************************(1320)\n        #\n        # N1=N2 **...*(1020) *...**(1045) *..         ..**(1295) *...**(1320)\n        #                   \\            \\                      \\\n        #                    +...+(1044)  &..                    $...$(1319)\n\n        # Save some current chain state for later use\n        self.mainchainheight = self.nodes[2].getblockcount()  # 1320\n        self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight)\n\n        self.log.info(\"Check that we can survive a 288 block reorg still\")\n        self.reorg_test()  # (1033, )\n        # Now create a 288 block reorg by mining a longer chain on N1\n        # First disconnect N1\n        # Then invalidate 1033 on main chain and 1032 on fork so height is 1032 on main chain\n        # N1   **...*(1020) **...**(1032)X..\n        #                  \\\n        #                   ++...+(1031)X..\n        #\n        # Now mine 300 more blocks on N1\n        # N1    **...*(1020) **...**(1032) @@...@(1332)\n        #                 \\               \\\n        #                  \\               X...\n        #                   \\                 \\\n        #                    ++...+(1031)X..   ..\n        #\n        # Reconnect nodes and mine 220 more blocks on N1\n        # N1    **...*(1020) **...**(1032) @@...@@@(1552)\n        #                 \\               \\\n        #                  \\               X...\n        #                   \\                 \\\n        #                    ++...+(1031)X..   ..\n        #\n        # N2    **...*(1020) **...**(1032) @@...@@@(1552)\n        #                 \\               \\\n        #                  \\               *...**(1320)\n        #                   \\                 \\\n        #                    ++...++(1044)     ..\n        #\n        # N0    ********************(1032) @@...@@@(1552)\n        #                                 \\\n        #                                  *...**(1320)\n\n        self.log.info(\"Test that we can rerequest a block we previously pruned if needed for a reorg\")\n        self.reorg_back()\n        # Verify that N2 still has block 1033 on current chain (@), but not on main chain (*)\n        # Invalidate 1033 on current chain (@) on N2 and we should be able to reorg to\n        # original main chain (*), but will require redownload of some blocks\n        # In order to have a peer we think we can download from, must also perform this invalidation\n        # on N0 and mine a new longest chain to trigger.\n        # Final result:\n        # N0    ********************(1032) **...****(1553)\n        #                                 \\\n        #                                  X@...@@@(1552)\n        #\n        # N2    **...*(1020) **...**(1032) **...****(1553)\n        #                 \\               \\\n        #                  \\               X@...@@@(1552)\n        #                   \\\n        #                    +..\n        #\n        # N1 doesn't change because 1033 on main chain (*) is invalid\n\n        self.log.info(\"Test manual pruning with block indices\")\n        self.manual_test(3, use_timestamp=False)\n\n        self.log.info(\"Test manual pruning with timestamps\")\n        self.manual_test(4, use_timestamp=True)\n\n        self.log.info(\"Test wallet re-scan\")\n        self.wallet_test()\n\n        self.log.info(\"Done\")\n\nif __name__ == '__main__':\n    PruneTest().main()\n"
  },
  {
    "path": "test/functional/feature_rbf.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the RBF code.\"\"\"\n\nfrom decimal import Decimal\n\nfrom test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut\nfrom test_framework.script import CScript, OP_DROP\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round\n\nMAX_REPLACEMENT_LIMIT = 100\n\ndef txToHex(tx):\n    return tx.serialize().hex()\n\ndef make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):\n    \"\"\"Create a txout with a given amount and scriptPubKey\n\n    Mines coins as needed.\n\n    confirmed - txouts created will be confirmed in the blockchain;\n                unconfirmed otherwise.\n    \"\"\"\n    fee = 1*COIN\n    while node.getbalance() < satoshi_round((amount + fee)/COIN):\n        node.generate(100)\n\n    new_addr = node.getnewaddress()\n    txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))\n    tx1 = node.getrawtransaction(txid, 1)\n    txid = int(txid, 16)\n    i = None\n\n    for i, txout in enumerate(tx1['vout']):\n        if txout['scriptPubKey']['addresses'] == [new_addr]:\n            break\n    assert i is not None\n\n    tx2 = CTransaction()\n    tx2.vin = [CTxIn(COutPoint(txid, i))]\n    tx2.vout = [CTxOut(amount, scriptPubKey)]\n    tx2.rehash()\n\n    signed_tx = node.signrawtransaction(txToHex(tx2))\n\n    txid = node.sendrawtransaction(signed_tx['hex'], 0)\n\n    # If requested, ensure txouts are confirmed.\n    if confirmed:\n        mempool_size = len(node.getrawmempool())\n        while mempool_size > 0:\n            node.generate(1)\n            new_size = len(node.getrawmempool())\n            # Error out if we have something stuck in the mempool, as this\n            # would likely be a bug.\n            assert new_size < mempool_size\n            mempool_size = new_size\n\n    return COutPoint(int(txid, 16), 0)\n\n\nclass ReplaceByFeeTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [\n            [\n                \"-maxorphantx=1000\",\n                \"-whitelist=127.0.0.1\",\n                \"-limitancestorcount=50\",\n                \"-limitancestorsize=101\",\n                \"-limitdescendantcount=200\",\n                \"-limitdescendantsize=101\",\n            ],\n            [\n                \"-mempoolreplacement=0\",\n            ],\n        ]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Leave IBD\n        self.nodes[0].generate(1)\n\n        make_utxo(self.nodes[0], 1*COIN)\n\n        # Ensure nodes are synced\n        self.sync_all()\n\n        self.log.info(\"Running test simple doublespend...\")\n        self.test_simple_doublespend()\n\n        self.log.info(\"Running test doublespend chain...\")\n        self.test_doublespend_chain()\n\n        self.log.info(\"Running test doublespend tree...\")\n        self.test_doublespend_tree()\n\n        self.log.info(\"Running test replacement feeperkb...\")\n        self.test_replacement_feeperkb()\n\n        self.log.info(\"Running test spends of conflicting outputs...\")\n        self.test_spends_of_conflicting_outputs()\n\n        self.log.info(\"Running test new unconfirmed inputs...\")\n        self.test_new_unconfirmed_inputs()\n\n        self.log.info(\"Running test too many replacements...\")\n        self.test_too_many_replacements()\n\n        self.log.info(\"Running test opt-in...\")\n        self.test_opt_in()\n\n        self.log.info(\"Running test RPC...\")\n        self.test_rpc()\n\n        self.log.info(\"Running test prioritised transactions...\")\n        self.test_prioritised_transactions()\n\n        self.log.info(\"Passed\")\n\n    def test_simple_doublespend(self):\n        \"\"\"Simple doublespend\"\"\"\n        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        # make_utxo may have generated a bunch of blocks, so we need to sync\n        # before we can spend the coins generated, or else the resulting\n        # transactions might not be accepted by our peers.\n        self.sync_all()\n\n        tx1a = CTransaction()\n        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1a_hex = txToHex(tx1a)\n        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)\n\n        self.sync_all()\n\n        # Should fail because we haven't changed the fee\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1b.vout = [CTxOut(1 * COIN, CScript([b'b' * 35]))]\n        tx1b_hex = txToHex(tx1b)\n\n        # This will raise an exception due to insufficient fee\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, tx1b_hex, 0)\n        # This will raise an exception due to transaction replacement being disabled\n        assert_raises_rpc_error(-26, \"txn-mempool-conflict\", self.nodes[1].sendrawtransaction, tx1b_hex, 0)\n\n        # Extra 0.1 BTC fee\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]\n        tx1b_hex = txToHex(tx1b)\n        # Replacement still disabled even with \"enough fee\"\n        assert_raises_rpc_error(-26, \"txn-mempool-conflict\", self.nodes[1].sendrawtransaction, tx1b_hex, 0)\n        # Works when enabled\n        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)\n\n        mempool = self.nodes[0].getrawmempool()\n\n        assert tx1a_txid not in mempool\n        assert tx1b_txid in mempool\n\n        assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid))\n\n        # Second node is running mempoolreplacement=0, will not replace originally-seen txn\n        mempool = self.nodes[1].getrawmempool()\n        assert tx1a_txid in mempool\n        assert tx1b_txid not in mempool\n\n    def test_doublespend_chain(self):\n        \"\"\"Doublespend of a long chain\"\"\"\n\n        initial_nValue = 50*COIN\n        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)\n\n        prevout = tx0_outpoint\n        remaining_value = initial_nValue\n        chain_txids = []\n        while remaining_value > 10*COIN:\n            remaining_value -= 1*COIN\n            tx = CTransaction()\n            tx.vin = [CTxIn(prevout, nSequence=0)]\n            tx.vout = [CTxOut(remaining_value, CScript([1, OP_DROP] * 15 + [1]))]\n            tx_hex = txToHex(tx)\n            txid = self.nodes[0].sendrawtransaction(tx_hex, 0)\n            chain_txids.append(txid)\n            prevout = COutPoint(int(txid, 16), 0)\n\n        # Whether the double-spend is allowed is evaluated by including all\n        # child fees - 40 BTC - so this attempt is rejected.\n        dbl_tx = CTransaction()\n        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        dbl_tx.vout = [CTxOut(initial_nValue - 30 * COIN, CScript([1] * 35))]\n        dbl_tx_hex = txToHex(dbl_tx)\n\n        # This will raise an exception due to insufficient fee\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)\n\n        # Accepted with sufficient fee\n        dbl_tx = CTransaction()\n        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        dbl_tx.vout = [CTxOut(1 * COIN, CScript([1] * 35))]\n        dbl_tx_hex = txToHex(dbl_tx)\n        self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)\n\n        mempool = self.nodes[0].getrawmempool()\n        for doublespent_txid in chain_txids:\n            assert doublespent_txid not in mempool\n\n    def test_doublespend_tree(self):\n        \"\"\"Doublespend of a big tree of transactions\"\"\"\n\n        initial_nValue = 50*COIN\n        tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)\n\n        def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _total_txs=None):\n            if _total_txs is None:\n                _total_txs = [0]\n            if _total_txs[0] >= max_txs:\n                return\n\n            txout_value = (initial_value - fee) // tree_width\n            if txout_value < fee:\n                return\n\n            vout = [CTxOut(txout_value, CScript([i+1]))\n                    for i in range(tree_width)]\n            tx = CTransaction()\n            tx.vin = [CTxIn(prevout, nSequence=0)]\n            tx.vout = vout\n            tx_hex = txToHex(tx)\n\n            assert len(tx.serialize()) < 100000\n            txid = self.nodes[0].sendrawtransaction(tx_hex, 0)\n            yield tx\n            _total_txs[0] += 1\n\n            txid = int(txid, 16)\n\n            for i, txout in enumerate(tx.vout):\n                for x in branch(COutPoint(txid, i), txout_value,\n                                  max_txs,\n                                  tree_width=tree_width, fee=fee,\n                                  _total_txs=_total_txs):\n                    yield x\n\n        fee = int(0.0001*COIN)\n        n = MAX_REPLACEMENT_LIMIT\n        tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))\n        assert_equal(len(tree_txs), n)\n\n        # Attempt double-spend, will fail because too little fee paid\n        dbl_tx = CTransaction()\n        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        dbl_tx.vout = [CTxOut(initial_nValue - fee * n, CScript([1] * 35))]\n        dbl_tx_hex = txToHex(dbl_tx)\n        # This will raise an exception due to insufficient fee\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)\n\n        # 1 BTC fee is enough\n        dbl_tx = CTransaction()\n        dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, CScript([1] * 35))]\n        dbl_tx_hex = txToHex(dbl_tx)\n        self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)\n\n        mempool = self.nodes[0].getrawmempool()\n\n        for tx in tree_txs:\n            tx.rehash()\n            assert tx.hash not in mempool\n\n        # Try again, but with more total transactions than the \"max txs\n        # double-spent at once\" anti-DoS limit.\n        for n in (MAX_REPLACEMENT_LIMIT+1, MAX_REPLACEMENT_LIMIT*2):\n            fee = int(0.0001*COIN)\n            tx0_outpoint = make_utxo(self.nodes[0], initial_nValue)\n            tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))\n            assert_equal(len(tree_txs), n)\n\n            dbl_tx = CTransaction()\n            dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n            dbl_tx.vout = [CTxOut(initial_nValue - 2 * fee * n, CScript([1] * 35))]\n            dbl_tx_hex = txToHex(dbl_tx)\n            # This will raise an exception\n            assert_raises_rpc_error(-26, \"too many potential replacements\", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)\n\n            for tx in tree_txs:\n                tx.rehash()\n                self.nodes[0].getrawtransaction(tx.hash)\n\n    def test_replacement_feeperkb(self):\n        \"\"\"Replacement requires fee-per-KB to be higher\"\"\"\n        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        tx1a = CTransaction()\n        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1a_hex = txToHex(tx1a)\n        self.nodes[0].sendrawtransaction(tx1a_hex, 0)\n\n        # Higher fee, but the fee per KB is much lower, so the replacement is\n        # rejected.\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))]\n        tx1b_hex = txToHex(tx1b)\n\n        # This will raise an exception due to insufficient fee\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, tx1b_hex, 0)\n\n    def test_spends_of_conflicting_outputs(self):\n        \"\"\"Replacements that spend conflicting tx outputs are rejected\"\"\"\n        utxo1 = make_utxo(self.nodes[0], int(1.2*COIN))\n        utxo2 = make_utxo(self.nodes[0], 3*COIN)\n\n        tx1a = CTransaction()\n        tx1a.vin = [CTxIn(utxo1, nSequence=0)]\n        tx1a.vout = [CTxOut(int(1.1 * COIN), CScript([b'a' * 35]))]\n        tx1a_hex = txToHex(tx1a)\n        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)\n\n        tx1a_txid = int(tx1a_txid, 16)\n\n        # Direct spend an output of the transaction we're replacing.\n        tx2 = CTransaction()\n        tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0)]\n        tx2.vin.append(CTxIn(COutPoint(tx1a_txid, 0), nSequence=0))\n        tx2.vout = tx1a.vout\n        tx2_hex = txToHex(tx2)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"bad-txns-spends-conflicting-tx\", self.nodes[0].sendrawtransaction, tx2_hex, 0)\n\n        # Spend tx1a's output to test the indirect case.\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]\n        tx1b.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1b_hex = txToHex(tx1b)\n        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)\n        tx1b_txid = int(tx1b_txid, 16)\n\n        tx2 = CTransaction()\n        tx2.vin = [CTxIn(utxo1, nSequence=0), CTxIn(utxo2, nSequence=0),\n                   CTxIn(COutPoint(tx1b_txid, 0))]\n        tx2.vout = tx1a.vout\n        tx2_hex = txToHex(tx2)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"bad-txns-spends-conflicting-tx\", self.nodes[0].sendrawtransaction, tx2_hex, 0)\n\n    def test_new_unconfirmed_inputs(self):\n        \"\"\"Replacements that add new unconfirmed inputs are rejected\"\"\"\n        confirmed_utxo = make_utxo(self.nodes[0], int(1.1*COIN))\n        unconfirmed_utxo = make_utxo(self.nodes[0], int(0.1*COIN), False)\n\n        tx1 = CTransaction()\n        tx1.vin = [CTxIn(confirmed_utxo)]\n        tx1.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1_hex = txToHex(tx1)\n        self.nodes[0].sendrawtransaction(tx1_hex, 0)\n\n        tx2 = CTransaction()\n        tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)]\n        tx2.vout = tx1.vout\n        tx2_hex = txToHex(tx2)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"replacement-adds-unconfirmed\", self.nodes[0].sendrawtransaction, tx2_hex, 0)\n\n    def test_too_many_replacements(self):\n        \"\"\"Replacements that evict too many transactions are rejected\"\"\"\n        # Try directly replacing more than MAX_REPLACEMENT_LIMIT\n        # transactions\n\n        # Start by creating a single transaction with many outputs\n        initial_nValue = 10*COIN\n        utxo = make_utxo(self.nodes[0], initial_nValue)\n        fee = int(0.0001*COIN)\n        split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))\n\n        outputs = []\n        for i in range(MAX_REPLACEMENT_LIMIT+1):\n            outputs.append(CTxOut(split_value, CScript([1])))\n\n        splitting_tx = CTransaction()\n        splitting_tx.vin = [CTxIn(utxo, nSequence=0)]\n        splitting_tx.vout = outputs\n        splitting_tx_hex = txToHex(splitting_tx)\n\n        txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, 0)\n        txid = int(txid, 16)\n\n        # Now spend each of those outputs individually\n        for i in range(MAX_REPLACEMENT_LIMIT+1):\n            tx_i = CTransaction()\n            tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)]\n            tx_i.vout = [CTxOut(split_value - fee, CScript([b'a' * 35]))]\n            tx_i_hex = txToHex(tx_i)\n            self.nodes[0].sendrawtransaction(tx_i_hex, 0)\n\n        # Now create doublespend of the whole lot; should fail.\n        # Need a big enough fee to cover all spending transactions and have\n        # a higher fee rate\n        double_spend_value = (split_value-100*fee)*(MAX_REPLACEMENT_LIMIT+1)\n        inputs = []\n        for i in range(MAX_REPLACEMENT_LIMIT+1):\n            inputs.append(CTxIn(COutPoint(txid, i), nSequence=0))\n        double_tx = CTransaction()\n        double_tx.vin = inputs\n        double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]\n        double_tx_hex = txToHex(double_tx)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"too many potential replacements\", self.nodes[0].sendrawtransaction, double_tx_hex, 0)\n\n        # If we remove an input, it should pass\n        double_tx = CTransaction()\n        double_tx.vin = inputs[0:-1]\n        double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]\n        double_tx_hex = txToHex(double_tx)\n        self.nodes[0].sendrawtransaction(double_tx_hex, 0)\n\n    def test_opt_in(self):\n        \"\"\"Replacing should only work if orig tx opted in\"\"\"\n        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        # Create a non-opting in transaction\n        tx1a = CTransaction()\n        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]\n        tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1a_hex = txToHex(tx1a)\n        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)\n\n        # This transaction isn't shown as replaceable\n        assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False)\n\n        # Shouldn't be able to double-spend\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]\n        tx1b_hex = txToHex(tx1b)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"txn-mempool-conflict\", self.nodes[0].sendrawtransaction, tx1b_hex, 0)\n\n        tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        # Create a different non-opting in transaction\n        tx2a = CTransaction()\n        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]\n        tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx2a_hex = txToHex(tx2a)\n        tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, 0)\n\n        # Still shouldn't be able to double-spend\n        tx2b = CTransaction()\n        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]\n        tx2b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]\n        tx2b_hex = txToHex(tx2b)\n\n        # This will raise an exception\n        assert_raises_rpc_error(-26, \"txn-mempool-conflict\", self.nodes[0].sendrawtransaction, tx2b_hex, 0)\n\n        # Now create a new transaction that spends from tx1a and tx2a\n        # opt-in on one of the inputs\n        # Transaction should be replaceable on either input\n\n        tx1a_txid = int(tx1a_txid, 16)\n        tx2a_txid = int(tx2a_txid, 16)\n\n        tx3a = CTransaction()\n        tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),\n                    CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]\n        tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]\n        tx3a_hex = txToHex(tx3a)\n\n        tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, 0)\n\n        # This transaction is shown as replaceable\n        assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True)\n\n        tx3b = CTransaction()\n        tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]\n        tx3b.vout = [CTxOut(int(0.5 * COIN), CScript([b'e' * 35]))]\n        tx3b_hex = txToHex(tx3b)\n\n        tx3c = CTransaction()\n        tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]\n        tx3c.vout = [CTxOut(int(0.5 * COIN), CScript([b'f' * 35]))]\n        tx3c_hex = txToHex(tx3c)\n\n        self.nodes[0].sendrawtransaction(tx3b_hex, 0)\n        # If tx3b was accepted, tx3c won't look like a replacement,\n        # but make sure it is accepted anyway\n        self.nodes[0].sendrawtransaction(tx3c_hex, 0)\n\n    def test_prioritised_transactions(self):\n        # Ensure that fee deltas used via prioritisetransaction are\n        # correctly used by replacement logic\n\n        # 1. Check that feeperkb uses modified fees\n        tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        tx1a = CTransaction()\n        tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx1a_hex = txToHex(tx1a)\n        tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)\n\n        # Higher fee, but the actual fee per KB is much lower.\n        tx1b = CTransaction()\n        tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]\n        tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*740000]))]\n        tx1b_hex = txToHex(tx1b)\n\n        # Verify tx1b cannot replace tx1a.\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, tx1b_hex, 0)\n\n        # Use prioritisetransaction to set tx1a's fee to 0.\n        self.nodes[0].prioritisetransaction(txid=tx1a_txid, fee_delta=int(-0.1*COIN))\n\n        # Now tx1b should be able to replace tx1a\n        tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)\n\n        assert tx1b_txid in self.nodes[0].getrawmempool()\n\n        # 2. Check that absolute fee checks use modified fee.\n        tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))\n\n        tx2a = CTransaction()\n        tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]\n        tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]\n        tx2a_hex = txToHex(tx2a)\n        self.nodes[0].sendrawtransaction(tx2a_hex, 0)\n\n        # Lower fee, but we'll prioritise it\n        tx2b = CTransaction()\n        tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]\n        tx2b.vout = [CTxOut(int(1.01 * COIN), CScript([b'a' * 35]))]\n        tx2b.rehash()\n        tx2b_hex = txToHex(tx2b)\n\n        # Verify tx2b cannot replace tx2a.\n        assert_raises_rpc_error(-26, \"insufficient fee\", self.nodes[0].sendrawtransaction, tx2b_hex, 0)\n\n        # Now prioritise tx2b to have a higher modified fee\n        self.nodes[0].prioritisetransaction(txid=tx2b.hash, fee_delta=int(0.1*COIN))\n\n        # tx2b should now be accepted\n        tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, 0)\n\n        assert tx2b_txid in self.nodes[0].getrawmempool()\n\n    def test_rpc(self):\n        us0 = self.nodes[0].listunspent()[0]\n        ins = [us0]\n        outs = {self.nodes[0].getnewaddress() : Decimal(1.0000000)}\n        rawtx0 = self.nodes[0].createrawtransaction(ins, outs, 0, True)\n        rawtx1 = self.nodes[0].createrawtransaction(ins, outs, 0, False)\n        json0  = self.nodes[0].decoderawtransaction(rawtx0)\n        json1  = self.nodes[0].decoderawtransaction(rawtx1)\n        assert_equal(json0[\"vin\"][0][\"sequence\"], 4294967293)\n        assert_equal(json1[\"vin\"][0][\"sequence\"], 4294967295)\n\n        rawtx2 = self.nodes[0].createrawtransaction([], outs)\n        frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {\"replaceable\": True})\n        frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {\"replaceable\": False})\n\n        json0  = self.nodes[0].decoderawtransaction(frawtx2a['hex'])\n        json1  = self.nodes[0].decoderawtransaction(frawtx2b['hex'])\n        assert_equal(json0[\"vin\"][0][\"sequence\"], 4294967293)\n        assert_equal(json1[\"vin\"][0][\"sequence\"], 4294967294)\n\nif __name__ == '__main__':\n    ReplaceByFeeTest().main()\n"
  },
  {
    "path": "test/functional/feature_reindex.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test running Munt-daemon with -reindex and -reindex-chainstate options.\n\n- Start a single node and generate 3 blocks.\n- Stop the node and restart it with -reindex. Verify that the node has reindexed up to block 3.\n- Stop the node and restart it with -reindex-chainstate. Verify that the node has reindexed up to block 3.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import wait_until\n\nclass ReindexTest(MuntTestFramework):\n\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def reindex(self, justchainstate=False):\n        self.nodes[0].generatetoaddress(3, self.nodes[0].get_deterministic_priv_key().address)\n        blockcount = self.nodes[0].getblockcount()\n        self.stop_nodes()\n        extra_args = [[\"-reindex-chainstate\" if justchainstate else \"-reindex\"]]\n        self.start_nodes(extra_args)\n        wait_until(lambda: self.nodes[0].getblockcount() == blockcount)\n        self.log.info(\"Success\")\n\n    def run_test(self):\n        self.reindex(False)\n        self.reindex(True)\n        self.reindex(False)\n        self.reindex(True)\n\nif __name__ == '__main__':\n    ReindexTest().main()\n"
  },
  {
    "path": "test/functional/feature_segwit.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the SegWit changeover logic.\"\"\"\n\nfrom decimal import Decimal\nfrom io import BytesIO\n\nfrom test_framework.address import (\n    key_to_p2pkh,\n    program_to_witness,\n    script_to_p2sh,\n    script_to_p2sh_p2wsh,\n    script_to_p2wsh,\n)\nfrom test_framework.blocktools import witness_script, send_to_witness\nfrom test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, sha256, ToHex\nfrom test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE, OP_DROP\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, hex_str_to_bytes, sync_blocks, try_rpc\n\nNODE_0 = 0\nNODE_2 = 2\nWIT_V0 = 0\nWIT_V1 = 1\n\ndef getutxo(txid):\n    utxo = {}\n    utxo[\"vout\"] = 0\n    utxo[\"txid\"] = txid\n    return utxo\n\ndef find_spendable_utxo(node, min_value):\n    for utxo in node.listunspent(query_options={'minimumAmount': min_value}):\n        if utxo['spendable']:\n            return utxo\n\n    raise AssertionError(\"Unspent output equal or higher than %s not found\" % min_value)\n\ntxs_mined = {} # txindex from txid to blockhash\n\nclass SegWitTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.\n        self.extra_args = [\n            [\n                \"-rpcserialversion=0\",\n                \"-vbparams=segwit:0:999999999999\",\n                \"-addresstype=legacy\",\n            ],\n            [\n                \"-blockversion=4\",\n                \"-rpcserialversion=1\",\n                \"-vbparams=segwit:0:999999999999\",\n                \"-addresstype=legacy\",\n            ],\n            [\n                \"-blockversion=536870915\",\n                \"-vbparams=segwit:0:999999999999\",\n                \"-addresstype=legacy\",\n            ],\n        ]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        super().setup_network()\n        connect_nodes(self.nodes[0], 2)\n        self.sync_all()\n\n    def success_mine(self, node, txid, sign, redeem_script=\"\"):\n        send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal(\"49.998\"), sign, redeem_script)\n        block = node.generate(1)\n        assert_equal(len(node.getblock(block[0])[\"tx\"]), 2)\n        sync_blocks(self.nodes)\n\n    def skip_mine(self, node, txid, sign, redeem_script=\"\"):\n        send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal(\"49.998\"), sign, redeem_script)\n        block = node.generate(1)\n        assert_equal(len(node.getblock(block[0])[\"tx\"]), 1)\n        sync_blocks(self.nodes)\n\n    def fail_accept(self, node, error_msg, txid, sign, redeem_script=\"\"):\n        assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal(\"49.998\"), sign=sign, insert_redeem_script=redeem_script)\n\n    def run_test(self):\n        self.nodes[0].generate(161)  # block 161\n\n        self.log.info(\"Verify sigops are counted in GBT with pre-BIP141 rules before the fork\")\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        assert tmpl['sizelimit'] == 1000000\n        assert 'weightlimit' not in tmpl\n        assert tmpl['sigoplimit'] == 20000\n        assert tmpl['transactions'][0]['hash'] == txid\n        assert tmpl['transactions'][0]['sigops'] == 2\n        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        assert tmpl['sizelimit'] == 1000000\n        assert 'weightlimit' not in tmpl\n        assert tmpl['sigoplimit'] == 20000\n        assert tmpl['transactions'][0]['hash'] == txid\n        assert tmpl['transactions'][0]['sigops'] == 2\n        self.nodes[0].generate(1)  # block 162\n\n        balance_presetup = self.nodes[0].getbalance()\n        self.pubkey = []\n        p2sh_ids = []  # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh\n        wit_ids = []  # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness\n        for i in range(3):\n            newaddress = self.nodes[i].getnewaddress()\n            self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)[\"pubkey\"])\n            multiscript = CScript([OP_1, hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG])\n            p2sh_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']\n            bip173_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'bech32')['address']\n            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))\n            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))\n            p2sh_ids.append([])\n            wit_ids.append([])\n            for v in range(2):\n                p2sh_ids[i].append([])\n                wit_ids[i].append([])\n\n        for i in range(5):\n            for n in range(3):\n                for v in range(2):\n                    wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], False, Decimal(\"49.999\")))\n                    p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal(\"49.999\")))\n\n        self.nodes[0].generate(1)  # block 163\n        sync_blocks(self.nodes)\n\n        # Make sure all nodes recognize the transactions as theirs\n        assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal(\"49.999\") + 50)\n        assert_equal(self.nodes[1].getbalance(), 20 * Decimal(\"49.999\"))\n        assert_equal(self.nodes[2].getbalance(), 20 * Decimal(\"49.999\"))\n\n        self.nodes[0].generate(260)  # block 423\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Verify witness txs are skipped for mining before the fork\")\n        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True)  # block 424\n        self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True)  # block 425\n        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True)  # block 426\n        self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True)  # block 427\n\n        self.log.info(\"Verify unsigned p2sh witness txs without a redeem script are invalid\")\n        self.fail_accept(self.nodes[2], \"mandatory-script-verify-flag\", p2sh_ids[NODE_2][WIT_V0][1], False)\n        self.fail_accept(self.nodes[2], \"mandatory-script-verify-flag\", p2sh_ids[NODE_2][WIT_V1][1], False)\n\n        self.nodes[2].generate(4)  # blocks 428-431\n\n        self.log.info(\"Verify previous witness txs skipped for mining can now be mined\")\n        assert_equal(len(self.nodes[2].getrawmempool()), 4)\n        blockhash = self.nodes[2].generate(1)[0]  # block 432 (first block with new rules; 432 = 144 * 3)\n        sync_blocks(self.nodes)\n        assert_equal(len(self.nodes[2].getrawmempool()), 0)\n        segwit_tx_list = self.nodes[2].getblock(blockhash)[\"tx\"]\n        assert_equal(len(segwit_tx_list), 5)\n\n        self.log.info(\"Verify default node can't accept txs with missing witness\")\n        # unsigned, no scriptsig\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", wit_ids[NODE_0][WIT_V0][0], False)\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", wit_ids[NODE_0][WIT_V1][0], False)\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", p2sh_ids[NODE_0][WIT_V0][0], False)\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", p2sh_ids[NODE_0][WIT_V1][0], False)\n        # unsigned with redeem script\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))\n        self.fail_accept(self.nodes[0], \"mandatory-script-verify-flag\", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))\n\n        self.log.info(\"Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag\")\n        assert self.nodes[2].getblock(blockhash, False) != self.nodes[0].getblock(blockhash, False)\n        assert self.nodes[1].getblock(blockhash, False) == self.nodes[2].getblock(blockhash, False)\n\n        for tx_id in segwit_tx_list:\n            tx = FromHex(CTransaction(), self.nodes[2].gettransaction(tx_id)[\"hex\"])\n            assert self.nodes[2].getrawtransaction(tx_id, False, blockhash) != self.nodes[0].getrawtransaction(tx_id, False, blockhash)\n            assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].getrawtransaction(tx_id, False, blockhash)\n            assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) != self.nodes[2].gettransaction(tx_id)[\"hex\"]\n            assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].gettransaction(tx_id)[\"hex\"]\n            assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) == tx.serialize_without_witness().hex()\n\n        self.log.info(\"Verify witness txs without witness data are invalid after the fork\")\n        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', wit_ids[NODE_2][WIT_V0][2], sign=False)\n        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', wit_ids[NODE_2][WIT_V1][2], sign=False)\n        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', p2sh_ids[NODE_2][WIT_V0][2], sign=False, redeem_script=witness_script(False, self.pubkey[2]))\n        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', p2sh_ids[NODE_2][WIT_V1][2], sign=False, redeem_script=witness_script(True, self.pubkey[2]))\n\n        self.log.info(\"Verify default node can now use witness txs\")\n        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True)  # block 432\n        self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True)  # block 433\n        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True)  # block 434\n        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True)  # block 435\n\n        self.log.info(\"Verify sigops are counted in GBT with BIP141 rules after the fork\")\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        assert tmpl['sizelimit'] >= 3999577  # actual maximum size is lower due to minimum mandatory non-witness data\n        assert tmpl['weightlimit'] == 4000000\n        assert tmpl['sigoplimit'] == 80000\n        assert tmpl['transactions'][0]['txid'] == txid\n        assert tmpl['transactions'][0]['sigops'] == 8\n\n        self.nodes[0].generate(1)  # Mine a block to clear the gbt cache\n\n        self.log.info(\"Non-segwit miners are able to use GBT response after activation.\")\n        # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->\n        #                      tx2 (segwit input, paying to a non-segwit output) ->\n        #                      tx3 (non-segwit input, paying to a non-segwit output).\n        # tx1 is allowed to appear in the block, but no others.\n        txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal(\"49.996\"))\n        hex_tx = self.nodes[0].gettransaction(txid)['hex']\n        tx = FromHex(CTransaction(), hex_tx)\n        assert tx.wit.is_null()  # This should not be a segwit input\n        assert txid1 in self.nodes[0].getrawmempool()\n\n        # Now create tx2, which will spend from txid1.\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))\n        tx.vout.append(CTxOut(int(49.99 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n        tx2_hex = self.nodes[0].signrawtransaction(ToHex(tx))['hex']\n        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)\n        tx = FromHex(CTransaction(), tx2_hex)\n        assert not tx.wit.is_null()\n\n        # Now create tx3, which will spend from txid2\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b\"\"))\n        tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee\n        tx.calc_sha256()\n        txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))\n        assert tx.wit.is_null()\n        assert txid3 in self.nodes[0].getrawmempool()\n\n        # Check that getblocktemplate includes all transactions.\n        template = self.nodes[0].getblocktemplate({\"rules\": [\"segwit\"]})\n        template_txids = [t['txid'] for t in template['transactions']]\n        assert txid1 in template_txids\n        assert txid2 in template_txids\n        assert txid3 in template_txids\n\n        # Check that wtxid is properly reported in mempool entry\n        assert_equal(int(self.nodes[0].getmempoolentry(txid3)[\"wtxid\"], 16), tx.calc_sha256(True))\n\n        # Mine a block to clear the gbt cache again.\n        self.nodes[0].generate(1)\n\n        self.log.info(\"Verify behaviour of importaddress and listunspent\")\n\n        # Some public keys to be used later\n        pubkeys = [\n            \"0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242\",  # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb\n            \"02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF\",  # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97\n            \"04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E\",  # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV\n            \"02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538\",  # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd\n            \"036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228\",  # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66\n            \"0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC\",  # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K\n            \"0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84\",  # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ\n        ]\n\n        # Import a compressed key and an uncompressed key, generate some multisig addresses\n        self.nodes[0].importprivkey(\"92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn\")\n        uncompressed_spendable_address = [\"mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu\"]\n        self.nodes[0].importprivkey(\"cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR\")\n        compressed_spendable_address = [\"mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe\"]\n        assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed']\n        assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed']\n\n        self.nodes[0].importpubkey(pubkeys[0])\n        compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]\n        self.nodes[0].importpubkey(pubkeys[1])\n        compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))\n        self.nodes[0].importpubkey(pubkeys[2])\n        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]\n\n        spendable_anytime = []                      # These outputs should be seen anytime after importprivkey and addmultisigaddress\n        spendable_after_importaddress = []          # These outputs should be seen after importaddress\n        solvable_after_importaddress = []           # These outputs should be seen after importaddress but not spendable\n        unsolvable_after_importaddress = []         # These outputs should be unsolvable after importaddress\n        solvable_anytime = []                       # These outputs should be solvable after importpubkey\n        unseen_anytime = []                         # These outputs should never be seen\n\n        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])\n        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])\n        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])\n        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address'])\n        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])\n        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address'])\n\n        # Test multisig_without_privkey\n        # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.\n        # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.\n\n        multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])['address']\n        script = CScript([OP_2, hex_str_to_bytes(pubkeys[3]), hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG])\n        solvable_after_importaddress.append(CScript([OP_HASH160, hash160(script), OP_EQUAL]))\n\n        for i in compressed_spendable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                # p2sh multisig with compressed keys should always be spendable\n                spendable_anytime.extend([p2sh])\n                # bare multisig can be watched and signed, but is not treated as ours\n                solvable_after_importaddress.extend([bare])\n                # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress\n                spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # normal P2PKH and P2PK with compressed keys should always be spendable\n                spendable_anytime.extend([p2pkh, p2pk])\n                # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress\n                spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])\n                # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable\n                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])\n\n        for i in uncompressed_spendable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                # p2sh multisig with uncompressed keys should always be spendable\n                spendable_anytime.extend([p2sh])\n                # bare multisig can be watched and signed, but is not treated as ours\n                solvable_after_importaddress.extend([bare])\n                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen\n                unseen_anytime.extend([p2wsh, p2sh_p2wsh])\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # normal P2PKH and P2PK with uncompressed keys should always be spendable\n                spendable_anytime.extend([p2pkh, p2pk])\n                # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress\n                spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])\n                # Witness output types with uncompressed keys are never seen\n                unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])\n\n        for i in compressed_solvable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                # Multisig without private is not seen after addmultisigaddress, but seen after importaddress\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen\n                solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])\n                # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress\n                solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])\n\n        for i in uncompressed_solvable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress\n                solvable_after_importaddress.extend([bare, p2sh])\n                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen\n                unseen_anytime.extend([p2wsh, p2sh_p2wsh])\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # normal P2PKH and P2PK with uncompressed keys should always be seen\n                solvable_anytime.extend([p2pkh, p2pk])\n                # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress\n                solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])\n                # Witness output types with uncompressed keys are never seen\n                unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])\n\n        op1 = CScript([OP_1])\n        op0 = CScript([OP_0])\n        # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V\n        unsolvable_address_key = hex_str_to_bytes(\"02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D\")\n        unsolvablep2pkh = CScript([OP_DUP, OP_HASH160, hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG])\n        unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])\n        p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL])\n        p2wshop1 = CScript([OP_0, sha256(op1)])\n        unsolvable_after_importaddress.append(unsolvablep2pkh)\n        unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)\n        unsolvable_after_importaddress.append(op1)  # OP_1 will be imported as script\n        unsolvable_after_importaddress.append(p2wshop1)\n        unseen_anytime.append(op0)  # OP_0 will be imported as P2SH address with no script provided\n        unsolvable_after_importaddress.append(p2shop0)\n\n        spendable_txid = []\n        solvable_txid = []\n        spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2))\n        solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1))\n        self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0)\n\n        importlist = []\n        for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                bare = hex_str_to_bytes(v['hex'])\n                importlist.append(bare.hex())\n                importlist.append(CScript([OP_0, sha256(bare)]).hex())\n            else:\n                pubkey = hex_str_to_bytes(v['pubkey'])\n                p2pk = CScript([pubkey, OP_CHECKSIG])\n                p2pkh = CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG])\n                importlist.append(p2pk.hex())\n                importlist.append(p2pkh.hex())\n                importlist.append(CScript([OP_0, hash160(pubkey)]).hex())\n                importlist.append(CScript([OP_0, sha256(p2pk)]).hex())\n                importlist.append(CScript([OP_0, sha256(p2pkh)]).hex())\n\n        importlist.append(unsolvablep2pkh.hex())\n        importlist.append(unsolvablep2wshp2pkh.hex())\n        importlist.append(op1.hex())\n        importlist.append(p2wshop1.hex())\n\n        for i in importlist:\n            # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC\n            # exceptions and continue.\n            try_rpc(-4, \"The wallet already contains the private key for this address or script\", self.nodes[0].importaddress, i, \"\", False, True)\n\n        self.nodes[0].importaddress(script_to_p2sh(op0))  # import OP_0 as address only\n        self.nodes[0].importaddress(multisig_without_privkey_address)  # Test multisig_without_privkey\n\n        spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))\n        solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))\n        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)\n        self.mine_and_test_listunspent(unseen_anytime, 0)\n\n        spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))\n        solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))\n        self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)\n        self.mine_and_test_listunspent(unseen_anytime, 0)\n\n        # Repeat some tests. This time we don't add witness scripts with importaddress\n        # Import a compressed key and an uncompressed key, generate some multisig addresses\n        self.nodes[0].importprivkey(\"927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH\")\n        uncompressed_spendable_address = [\"mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi\"]\n        self.nodes[0].importprivkey(\"cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw\")\n        compressed_spendable_address = [\"n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL\"]\n\n        self.nodes[0].importpubkey(pubkeys[5])\n        compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]\n        self.nodes[0].importpubkey(pubkeys[6])\n        uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]\n\n        unseen_anytime = []                         # These outputs should never be seen\n        solvable_anytime = []                       # These outputs should be solvable after importpubkey\n        unseen_anytime = []                         # These outputs should never be seen\n\n        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])\n        uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])\n        compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])\n        uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]])['address'])\n        compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])\n\n        premature_witaddress = []\n\n        for i in compressed_spendable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                premature_witaddress.append(script_to_p2sh(p2wsh))\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # P2WPKH, P2SH_P2WPKH are always spendable\n                spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])\n\n        for i in uncompressed_spendable_address + uncompressed_solvable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen\n                unseen_anytime.extend([p2wsh, p2sh_p2wsh])\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen\n                unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])\n\n        for i in compressed_solvable_address:\n            v = self.nodes[0].getaddressinfo(i)\n            if (v['isscript']):\n                [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)\n                premature_witaddress.append(script_to_p2sh(p2wsh))\n            else:\n                [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)\n                # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable\n                solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])\n\n        self.mine_and_test_listunspent(spendable_anytime, 2)\n        self.mine_and_test_listunspent(solvable_anytime, 1)\n        self.mine_and_test_listunspent(unseen_anytime, 0)\n\n        # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works\n        v1_addr = program_to_witness(1, [3, 5])\n        v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})\n        v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)\n        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0], v1_addr)\n        assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], \"51020305\")\n\n        # Check that spendable outputs are really spendable\n        self.create_and_mine_tx_from_txids(spendable_txid)\n\n        # import all the private keys so solvable addresses become spendable\n        self.nodes[0].importprivkey(\"cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb\")\n        self.nodes[0].importprivkey(\"cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97\")\n        self.nodes[0].importprivkey(\"91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV\")\n        self.nodes[0].importprivkey(\"cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd\")\n        self.nodes[0].importprivkey(\"cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66\")\n        self.nodes[0].importprivkey(\"cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K\")\n        self.create_and_mine_tx_from_txids(solvable_txid)\n\n        # Test that importing native P2WPKH/P2WSH scripts works\n        for use_p2wsh in [False, True]:\n            if use_p2wsh:\n                scriptPubKey = \"00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a\"\n                transaction = \"01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000\"\n            else:\n                scriptPubKey = \"a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87\"\n                transaction = \"01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000\"\n\n            self.nodes[1].importaddress(scriptPubKey, \"\", False)\n            rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']\n            rawtxfund = self.nodes[1].signrawtransaction(rawtxfund)[\"hex\"]\n            txid = self.nodes[1].sendrawtransaction(rawtxfund)\n\n            assert_equal(self.nodes[1].gettransaction(txid, True)[\"txid\"], txid)\n            assert_equal(self.nodes[1].listtransactions(\"*\", 1, 0, True)[0][\"txid\"], txid)\n\n            # Assert it is properly saved\n            self.stop_node(1)\n            self.start_node(1)\n            assert_equal(self.nodes[1].gettransaction(txid, True)[\"txid\"], txid)\n            assert_equal(self.nodes[1].listtransactions(\"*\", 1, 0, True)[0][\"txid\"], txid)\n\n    def mine_and_test_listunspent(self, script_list, ismine):\n        utxo = find_spendable_utxo(self.nodes[0], 50)\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(int('0x' + utxo['txid'], 0), utxo['vout'])))\n        for i in script_list:\n            tx.vout.append(CTxOut(10000000, i))\n        tx.rehash()\n        signresults = self.nodes[0].signrawtransaction(tx.serialize_without_witness().hex())['hex']\n        txid = self.nodes[0].sendrawtransaction(signresults, 0)\n        txs_mined[txid] = self.nodes[0].generate(1)[0]\n        sync_blocks(self.nodes)\n        watchcount = 0\n        spendcount = 0\n        for i in self.nodes[0].listunspent():\n            if (i['txid'] == txid):\n                watchcount += 1\n                if i['spendable']:\n                    spendcount += 1\n        if (ismine == 2):\n            assert_equal(spendcount, len(script_list))\n        elif (ismine == 1):\n            assert_equal(watchcount, len(script_list))\n            assert_equal(spendcount, 0)\n        else:\n            assert_equal(watchcount, 0)\n        return txid\n\n    def p2sh_address_to_script(self, v):\n        bare = CScript(hex_str_to_bytes(v['hex']))\n        p2sh = CScript(hex_str_to_bytes(v['scriptPubKey']))\n        p2wsh = CScript([OP_0, sha256(bare)])\n        p2sh_p2wsh = CScript([OP_HASH160, hash160(p2wsh), OP_EQUAL])\n        return([bare, p2sh, p2wsh, p2sh_p2wsh])\n\n    def p2pkh_address_to_script(self, v):\n        pubkey = hex_str_to_bytes(v['pubkey'])\n        p2wpkh = CScript([OP_0, hash160(pubkey)])\n        p2sh_p2wpkh = CScript([OP_HASH160, hash160(p2wpkh), OP_EQUAL])\n        p2pk = CScript([pubkey, OP_CHECKSIG])\n        p2pkh = CScript(hex_str_to_bytes(v['scriptPubKey']))\n        p2sh_p2pk = CScript([OP_HASH160, hash160(p2pk), OP_EQUAL])\n        p2sh_p2pkh = CScript([OP_HASH160, hash160(p2pkh), OP_EQUAL])\n        p2wsh_p2pk = CScript([OP_0, sha256(p2pk)])\n        p2wsh_p2pkh = CScript([OP_0, sha256(p2pkh)])\n        p2sh_p2wsh_p2pk = CScript([OP_HASH160, hash160(p2wsh_p2pk), OP_EQUAL])\n        p2sh_p2wsh_p2pkh = CScript([OP_HASH160, hash160(p2wsh_p2pkh), OP_EQUAL])\n        return [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]\n\n    def create_and_mine_tx_from_txids(self, txids, success=True):\n        tx = CTransaction()\n        for i in txids:\n            txtmp = CTransaction()\n            txraw = self.nodes[0].getrawtransaction(i, 0, txs_mined[i])\n            f = BytesIO(hex_str_to_bytes(txraw))\n            txtmp.deserialize(f)\n            for j in range(len(txtmp.vout)):\n                tx.vin.append(CTxIn(COutPoint(int('0x' + i, 0), j)))\n        tx.vout.append(CTxOut(0, CScript()))\n        tx.rehash()\n        signresults = self.nodes[0].signrawtransaction(tx.serialize_without_witness().hex())['hex']\n        self.nodes[0].sendrawtransaction(signresults, 0)\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n\nif __name__ == '__main__':\n    SegWitTest().main()\n"
  },
  {
    "path": "test/functional/feature_shutdown.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test Munt-daemon shutdown.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, get_rpc_proxy, wait_until\nfrom threading import Thread\n\ndef test_long_call(node):\n    block = node.waitfornewblock()\n    assert_equal(block['height'], 0)\n\nclass ShutdownTest(MuntTestFramework):\n\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def run_test(self):\n        node = get_rpc_proxy(self.nodes[0].url, 1, timeout=600, coveragedir=self.nodes[0].coverage_dir)\n        # Force connection establishment by executing a dummy command.\n        node.getblockcount()\n        Thread(target=test_long_call, args=(node,)).start()\n        # Wait until the server is executing the above `waitfornewblock`.\n        wait_until(lambda: len(self.nodes[0].getrpcinfo()['active_commands']) == 2)\n        # Wait 1 second after requesting shutdown but not before the `stop` call\n        # finishes. This is to ensure event loop waits for current connections\n        # to close.\n        self.stop_node(0, wait=1000)\n\nif __name__ == '__main__':\n    ShutdownTest().main()\n"
  },
  {
    "path": "test/functional/feature_uacomment.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the -uacomment option.\"\"\"\n\nimport re\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.test_node import ErrorMatch\nfrom test_framework.util import assert_equal\n\n\nclass UacommentTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def run_test(self):\n        self.log.info(\"test multiple -uacomment\")\n        test_uacomment = self.nodes[0].getnetworkinfo()[\"subversion\"][-12:-1]\n        assert_equal(test_uacomment, \"(testnode0)\")\n\n        self.restart_node(0, [\"-uacomment=foo\"])\n        foo_uacomment = self.nodes[0].getnetworkinfo()[\"subversion\"][-17:-1]\n        assert_equal(foo_uacomment, \"(testnode0; foo)\")\n\n        self.log.info(\"test -uacomment max length\")\n        self.stop_node(0)\n        expected = \"Error: Total length of network version string \\([0-9]+\\) exceeds maximum length \\(256\\). Reduce the number or size of uacomments.\"\n        self.nodes[0].assert_start_raises_init_error([\"-uacomment=\" + 'a' * 256], expected, match=ErrorMatch.FULL_REGEX)\n\n        self.log.info(\"test -uacomment unsafe characters\")\n        for unsafe_char in ['/', ':', '(', ')', '🏃']:\n            expected = \"Error: User Agent comment \\(\" + re.escape(unsafe_char) + \"\\) contains unsafe characters.\"\n            self.nodes[0].assert_start_raises_init_error([\"-uacomment=\" + unsafe_char], expected, match=ErrorMatch.FULL_REGEX)\n\n\nif __name__ == '__main__':\n    UacommentTest().main()\n"
  },
  {
    "path": "test/functional/feature_versionbits_warning.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test version bits warning system.\n\nGenerate chains with block versions that appear to be signalling unknown\nsoft-forks, and test that warning alerts are generated.\n\"\"\"\nimport os\nimport re\n\nfrom test_framework.blocktools import create_block, create_coinbase\nfrom test_framework.messages import msg_block\nfrom test_framework.mininode import P2PInterface, mininode_lock\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import wait_until\n\nVB_PERIOD = 144           # versionbits period length for regtest\nVB_THRESHOLD = 108        # versionbits activation threshold for regtest\nVB_TOP_BITS = 0x20000000\nVB_UNKNOWN_BIT = 27       # Choose a bit unassigned to any deployment\nVB_UNKNOWN_VERSION = VB_TOP_BITS | (1 << VB_UNKNOWN_BIT)\n\nWARN_UNKNOWN_RULES_ACTIVE = \"unknown new rules activated (versionbit {})\".format(VB_UNKNOWN_BIT)\nVB_PATTERN = re.compile(\"Warning: unknown new rules activated.*versionbit\")\n\nclass VersionBitsWarningTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def setup_network(self):\n        self.alert_filename = os.path.join(self.options.tmpdir, \"alert.txt\")\n        # Open and close to create zero-length file\n        with open(self.alert_filename, 'w', encoding='utf8'):\n            pass\n        self.extra_args = [[\"-alertnotify=echo %s >> \\\"\" + self.alert_filename + \"\\\"\"]]\n        self.setup_nodes()\n\n    def send_blocks_with_version(self, peer, numblocks, version):\n        \"\"\"Send numblocks blocks to peer with version set\"\"\"\n        tip = self.nodes[0].getbestblockhash()\n        height = self.nodes[0].getblockcount()\n        block_time = self.nodes[0].getblockheader(tip)[\"time\"] + 1\n        tip = int(tip, 16)\n\n        for _ in range(numblocks):\n            block = create_block(tip, create_coinbase(height + 1), block_time)\n            block.nVersion = version\n            block.solve()\n            peer.send_message(msg_block(block))\n            block_time += 1\n            height += 1\n            tip = block.sha256\n        peer.sync_with_ping()\n\n    def versionbits_in_alert_file(self):\n        \"\"\"Test that the versionbits warning has been written to the alert file.\"\"\"\n        alert_text = open(self.alert_filename, 'r', encoding='utf8').read()\n        return VB_PATTERN.search(alert_text) is not None\n\n    def run_test(self):\n        node = self.nodes[0]\n        node.add_p2p_connection(P2PInterface())\n\n        node_deterministic_address = node.get_deterministic_priv_key().address\n        # Mine one period worth of blocks\n        node.generatetoaddress(VB_PERIOD, node_deterministic_address)\n\n        self.log.info(\"Check that there is no warning if previous VB_BLOCKS have <VB_THRESHOLD blocks with unknown versionbits version.\")\n        # Build one period of blocks with < VB_THRESHOLD blocks signaling some unknown bit\n        self.send_blocks_with_version(node.p2p, VB_THRESHOLD - 1, VB_UNKNOWN_VERSION)\n        node.generatetoaddress(VB_PERIOD - VB_THRESHOLD + 1, node_deterministic_address)\n\n        # Check that we're not getting any versionbit-related errors in get*info()\n        assert not VB_PATTERN.match(node.getmininginfo()[\"warnings\"])\n        assert not VB_PATTERN.match(node.getnetworkinfo()[\"warnings\"])\n\n        # Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit\n        self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION)\n        node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address)\n\n        self.log.info(\"Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.\")\n        # Mine a period worth of expected blocks so the generic block-version warning\n        # is cleared. This will move the versionbit state to ACTIVE.\n        node.generatetoaddress(VB_PERIOD, node_deterministic_address)\n\n        # Stop-start the node. This is required because Munt-daemon will only warn once about unknown versions or unknown rules activating.\n        self.restart_node(0)\n\n        # Generating one block guarantees that we'll get out of IBD\n        node.generatetoaddress(1, node_deterministic_address)\n        wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)\n        # Generating one more block will be enough to generate an error.\n        node.generatetoaddress(1, node_deterministic_address)\n        # Check that get*info() shows the versionbits unknown rules warning\n        assert WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()[\"warnings\"]\n        assert WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()[\"warnings\"]\n        # Check that the alert file shows the versionbits unknown rules warning\n        wait_until(lambda: self.versionbits_in_alert_file(), timeout=60)\n\nif __name__ == '__main__':\n    VersionBitsWarningTest().main()\n"
  },
  {
    "path": "test/functional/interface_cli.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test CLI\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_process_error, get_auth_cookie\n\nclass TestCli(MuntTestFramework):\n\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def run_test(self):\n        \"\"\"Main test logic\"\"\"\n\n        cli_response = self.nodes[0].cli(\"-version\").send_cli()\n        assert \"Munt RPC client version\" in cli_response\n\n        self.log.info(\"Compare responses from getwalletinfo RPC and `Munt-cli getwalletinfo`\")\n        if self.is_wallet_compiled():\n            cli_response = self.nodes[0].cli.getwalletinfo()\n            rpc_response = self.nodes[0].getwalletinfo()\n            assert_equal(cli_response, rpc_response)\n\n        self.log.info(\"Compare responses from getblockchaininfo RPC and `Munt-cli getblockchaininfo`\")\n        cli_response = self.nodes[0].cli.getblockchaininfo()\n        rpc_response = self.nodes[0].getblockchaininfo()\n        assert_equal(cli_response, rpc_response)\n\n        user, password = get_auth_cookie(self.nodes[0].datadir)\n\n        #self.log.info(\"Test -stdinrpcpass option\")\n        #assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())\n        #assert_raises_process_error(1, \"Incorrect rpcuser or rpcpassword\", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=\"foo\").echo)\n\n        #self.log.info(\"Test -stdin and -stdinrpcpass\")\n        #assert_equal([\"foo\", \"bar\"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + \"\\nfoo\\nbar\").echo())\n        #assert_raises_process_error(1, \"Incorrect rpcuser or rpcpassword\", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=\"foo\").echo)\n\n        self.log.info(\"Test connecting to a non-existing server\")\n        assert_raises_process_error(1, \"couldn't connect to server\", self.nodes[0].cli('-rpcport=1').echo)\n\n        self.log.info(\"Test connecting with non-existing RPC cookie file\")\n        assert_raises_process_error(1, \"Could not locate RPC credentials\", self.nodes[0].cli('-rpccookiefile=does-not-exist', '-rpcpassword=').echo)\n\n        #self.log.info(\"Make sure that -getinfo with arguments fails\")\n        #assert_raises_process_error(1, \"-getinfo takes no arguments\", self.nodes[0].cli('-getinfo').help)\n\n        self.log.info(\"Compare responses from `Munt-cli -getinfo` and the RPCs data is retrieved from.\")\n        cli_get_info = self.nodes[0].cli('getinfo').send_cli()\n        if self.is_wallet_compiled():\n            wallet_info = self.nodes[0].getwalletinfo()\n        network_info = self.nodes[0].getnetworkinfo()\n        blockchain_info = self.nodes[0].getblockchaininfo()\n\n        assert_equal(cli_get_info['version'], network_info['version'])\n        assert_equal(cli_get_info['protocolversion'], network_info['protocolversion'])\n        assert_equal(cli_get_info['blocks'], blockchain_info['blocks'])\n        assert_equal(cli_get_info['timeoffset'], network_info['timeoffset'])\n        assert_equal(cli_get_info['connections'], network_info['connections'])\n        assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy'])\n        assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])\n        #assert_equal(cli_get_info['chain'], blockchain_info['chain'])\n        if self.is_wallet_compiled():\n            assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])\n            assert_equal(cli_get_info['balance'], wallet_info['balance'])\n            assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest'])\n            #assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])\n            assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])\n            assert_equal(cli_get_info['relayfee'], network_info['relayfee'])\n            # unlocked_until is not tested because the wallet is not encrypted\n\n\nif __name__ == '__main__':\n    TestCli().main()\n"
  },
  {
    "path": "test/functional/interface_http.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the RPC HTTP basics.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, str_to_b64str\n\nimport http.client\nimport urllib.parse\n\nclass HTTPBasicsTest (MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 3\n\n    def setup_network(self):\n        self.setup_nodes()\n\n    def run_test(self):\n\n        #################################################\n        # lowlevel check for http persistent connection #\n        #################################################\n        url = urllib.parse.urlparse(self.nodes[0].url)\n        authpair = url.username + ':' + url.password\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1\n        assert conn.sock is not None  #according to http/1.1 connection must still be open!\n\n        #send 2nd request without closing connection\n        conn.request('POST', '/', '{\"method\": \"getchaintips\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1  #must also response with a correct json-rpc message\n        assert conn.sock is not None  #according to http/1.1 connection must still be open!\n        conn.close()\n\n        #same should be if we add keep-alive because this should be the std. behaviour\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair), \"Connection\": \"keep-alive\"}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1\n        assert conn.sock is not None  #according to http/1.1 connection must still be open!\n\n        #send 2nd request without closing connection\n        conn.request('POST', '/', '{\"method\": \"getchaintips\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1  #must also response with a correct json-rpc message\n        assert conn.sock is not None  #according to http/1.1 connection must still be open!\n        conn.close()\n\n        #now do the same with \"Connection: close\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair), \"Connection\":\"close\"}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1\n        assert conn.sock is None  #now the connection must be closed after the response\n\n        #node1 (2nd node) is running with disabled keep-alive option\n        urlNode1 = urllib.parse.urlparse(self.nodes[1].url)\n        authpair = urlNode1.username + ':' + urlNode1.password\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair)}\n\n        conn = http.client.HTTPConnection(urlNode1.hostname, urlNode1.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1\n\n        #node2 (third node) is running with standard keep-alive parameters which means keep-alive is on\n        urlNode2 = urllib.parse.urlparse(self.nodes[2].url)\n        authpair = urlNode2.username + ':' + urlNode2.password\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair)}\n\n        conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        out1 = conn.getresponse().read()\n        assert b'\"error\":null' in out1\n        assert conn.sock is not None  #connection must be closed because Munt-daemon should use keep-alive by default\n\n        # Check excessive request size\n        conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)\n        conn.connect()\n        conn.request('GET', '/' + ('x'*1000), '', headers)\n        out1 = conn.getresponse()\n        assert_equal(out1.status, http.client.NOT_FOUND)\n\n        conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)\n        conn.connect()\n        conn.request('GET', '/' + ('x'*10000), '', headers)\n        out1 = conn.getresponse()\n        assert_equal(out1.status, http.client.BAD_REQUEST)\n\n\nif __name__ == '__main__':\n    HTTPBasicsTest ().main ()\n"
  },
  {
    "path": "test/functional/interface_rest.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the REST API.\"\"\"\n\nimport binascii\nfrom decimal import Decimal\nfrom enum import Enum\nfrom io import BytesIO\nimport json\nfrom struct import pack, unpack\n\nimport http.client\nimport urllib.parse\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n    hex_str_to_bytes,\n)\n\nfrom test_framework.messages import BLOCK_HEADER_SIZE\n\nclass ReqType(Enum):\n    JSON = 1\n    BIN = 2\n    HEX = 3\n\nclass RetType(Enum):\n    OBJ = 1\n    BYTES = 2\n    JSON = 3\n\ndef filter_output_indices_by_value(vouts, value):\n    for vout in vouts:\n        if vout['value'] == value:\n            yield vout['n']\n\nclass RESTTest (MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.extra_args = [[\"-rest\"], []]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON):\n        rest_uri = '/rest' + uri\n        if req_type == ReqType.JSON:\n            rest_uri += '.json'\n        elif req_type == ReqType.BIN:\n            rest_uri += '.bin'\n        elif req_type == ReqType.HEX:\n            rest_uri += '.hex'\n\n        conn = http.client.HTTPConnection(self.url.hostname, self.url.port)\n        self.log.debug('%s %s %s', http_method, rest_uri, body)\n        if http_method == 'GET':\n            conn.request('GET', rest_uri)\n        elif http_method == 'POST':\n            conn.request('POST', rest_uri, body)\n        resp = conn.getresponse()\n\n        assert_equal(resp.status, status)\n\n        if ret_type == RetType.OBJ:\n            return resp\n        elif ret_type == RetType.BYTES:\n            return resp.read()\n        elif ret_type == RetType.JSON:\n            return json.loads(resp.read().decode('utf-8'), parse_float=Decimal)\n\n    def run_test(self):\n        self.url = urllib.parse.urlparse(self.nodes[0].url)\n        self.log.info(\"Mine blocks and send Munt to node 1\")\n\n        # Random address so node1's balance doesn't increase\n        not_related_address = \"RHTNonta4EXNSiT12wCrzjjrZqcGFFoVxa\"\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n        self.nodes[1].generatetoaddress(100, not_related_address)\n        self.sync_all()\n\n        assert_equal(self.nodes[0].getbalance(), 50)\n\n        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)\n        self.sync_all()\n\n        self.log.info(\"Test the /tx URI\")\n\n        json_obj = self.test_rest_request(\"/tx/{}\".format(txid))\n        assert_equal(json_obj['txid'], txid)\n\n        # Check hex format response\n        hex_response = self.test_rest_request(\"/tx/{}\".format(txid), req_type=ReqType.HEX, ret_type=RetType.OBJ)\n        assert_greater_than_or_equal(int(hex_response.getheader('content-length')),\n                                     json_obj['size']*2)\n\n        spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout'])  # get the vin to later check for utxo (should be spent by then)\n        # get n of 0.1 outpoint\n        n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1'))\n        spending = (txid, n)\n\n        self.log.info(\"Query an unspent TXO using the /getutxos URI\")\n\n        self.nodes[1].generatetoaddress(1, not_related_address)\n        self.sync_all()\n        bb_hash = self.nodes[0].getbestblockhash()\n\n        assert_equal(self.nodes[1].getbalance(), Decimal(\"0.1\"))\n\n        # Check chainTip response\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}\".format(*spending))\n        assert_equal(json_obj['chaintipHash'], bb_hash)\n\n        # Make sure there is one utxo\n        assert_equal(len(json_obj['utxos']), 1)\n        assert_equal(json_obj['utxos'][0]['value'], Decimal('0.1'))\n\n        self.log.info(\"Query a spent TXO using the /getutxos URI\")\n\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}\".format(*spent))\n\n        # Check chainTip response\n        assert_equal(json_obj['chaintipHash'], bb_hash)\n\n        # Make sure there is no utxo in the response because this outpoint has been spent\n        assert_equal(len(json_obj['utxos']), 0)\n\n        # Check bitmap\n        assert_equal(json_obj['bitmap'], \"0\")\n\n        self.log.info(\"Query two TXOs using the /getutxos URI\")\n\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}/{}-{}\".format(*(spending + spent)))\n\n        assert_equal(len(json_obj['utxos']), 1)\n        assert_equal(json_obj['bitmap'], \"10\")\n\n        self.log.info(\"Query the TXOs using the /getutxos URI with a binary response\")\n\n        bin_request = b'\\x01\\x02'\n        for txid, n in [spending, spent]:\n            bin_request += hex_str_to_bytes(txid)\n            bin_request += pack(\"i\", n)\n\n        bin_response = self.test_rest_request(\"/getutxos\", http_method='POST', req_type=ReqType.BIN, body=bin_request, ret_type=RetType.BYTES)\n        output = BytesIO(bin_response)\n        chain_height, = unpack(\"i\", output.read(4))\n        response_hash = output.read(32)[::-1].hex()\n\n        assert_equal(bb_hash, response_hash)  # check if getutxo's chaintip during calculation was fine\n        assert_equal(chain_height, 102)  # chain height must be 102\n\n        self.log.info(\"Test the /getutxos URI with and without /checkmempool\")\n        # Create a transaction, check that it's found with /checkmempool, but\n        # not found without. Then confirm the transaction and check that it's\n        # found with or without /checkmempool.\n\n        # do a tx and don't sync\n        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)\n        json_obj = self.test_rest_request(\"/tx/{}\".format(txid))\n        # get the spent output to later check for utxo (should be spent by then)\n        spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout'])\n        # get n of 0.1 outpoint\n        n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1'))\n        spending = (txid, n)\n\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}\".format(*spending))\n        assert_equal(len(json_obj['utxos']), 0)\n\n        json_obj = self.test_rest_request(\"/getutxos/checkmempool/{}-{}\".format(*spending))\n        assert_equal(len(json_obj['utxos']), 1)\n\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}\".format(*spent))\n        assert_equal(len(json_obj['utxos']), 1)\n\n        json_obj = self.test_rest_request(\"/getutxos/checkmempool/{}-{}\".format(*spent))\n        assert_equal(len(json_obj['utxos']), 0)\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        json_obj = self.test_rest_request(\"/getutxos/{}-{}\".format(*spending))\n        assert_equal(len(json_obj['utxos']), 1)\n\n        json_obj = self.test_rest_request(\"/getutxos/checkmempool/{}-{}\".format(*spending))\n        assert_equal(len(json_obj['utxos']), 1)\n\n        # Do some invalid requests\n        self.test_rest_request(\"/getutxos\", http_method='POST', req_type=ReqType.JSON, body='{\"checkmempool', status=400, ret_type=RetType.OBJ)\n        self.test_rest_request(\"/getutxos\", http_method='POST', req_type=ReqType.BIN, body='{\"checkmempool', status=400, ret_type=RetType.OBJ)\n        self.test_rest_request(\"/getutxos/checkmempool\", http_method='POST', req_type=ReqType.JSON, status=400, ret_type=RetType.OBJ)\n\n        # Test limits\n        long_uri = '/'.join([\"{}-{}\".format(txid, n_) for n_ in range(20)])\n        self.test_rest_request(\"/getutxos/checkmempool/{}\".format(long_uri), http_method='POST', status=400, ret_type=RetType.OBJ)\n\n        long_uri = '/'.join(['{}-{}'.format(txid, n_) for n_ in range(15)])\n        self.test_rest_request(\"/getutxos/checkmempool/{}\".format(long_uri), http_method='POST', status=200)\n\n        self.nodes[0].generate(1)  # generate block to not affect upcoming tests\n        self.sync_all()\n\n        self.log.info(\"Test the /block, /blockhashbyheight and /headers URIs\")\n        bb_hash = self.nodes[0].getbestblockhash()\n\n        # Check result if block does not exists\n        assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), [])\n        self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ)\n\n        # Check result if block is not in the active chain\n        self.nodes[0].invalidateblock(bb_hash)\n        assert_equal(self.test_rest_request('/headers/1/{}'.format(bb_hash)), [])\n        self.test_rest_request('/block/{}'.format(bb_hash))\n        self.nodes[0].reconsiderblock(bb_hash)\n\n        # Check binary format\n        response = self.test_rest_request(\"/block/{}\".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ)\n        assert_greater_than(int(response.getheader('content-length')), BLOCK_HEADER_SIZE)\n        response_bytes = response.read()\n\n        # Compare with block header\n        response_header = self.test_rest_request(\"/headers/1/{}\".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ)\n        assert_equal(int(response_header.getheader('content-length')), BLOCK_HEADER_SIZE)\n        response_header_bytes = response_header.read()\n        assert_equal(response_bytes[:BLOCK_HEADER_SIZE], response_header_bytes)\n\n        # Check block hex format\n        response_hex = self.test_rest_request(\"/block/{}\".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ)\n        assert_greater_than(int(response_hex.getheader('content-length')), BLOCK_HEADER_SIZE*2)\n        response_hex_bytes = response_hex.read().strip(b'\\n')\n        assert_equal(binascii.hexlify(response_bytes), response_hex_bytes)\n\n        # Compare with hex block header\n        response_header_hex = self.test_rest_request(\"/headers/1/{}\".format(bb_hash), req_type=ReqType.HEX, ret_type=RetType.OBJ)\n        assert_greater_than(int(response_header_hex.getheader('content-length')), BLOCK_HEADER_SIZE*2)\n        response_header_hex_bytes = response_header_hex.read(BLOCK_HEADER_SIZE*2)\n        assert_equal(binascii.hexlify(response_bytes[:BLOCK_HEADER_SIZE]), response_header_hex_bytes)\n\n        # Check json format\n        block_json_obj = self.test_rest_request(\"/block/{}\".format(bb_hash))\n        assert_equal(block_json_obj['hash'], bb_hash)\n        assert_equal(self.test_rest_request(\"/blockhashbyheight/{}\".format(block_json_obj['height']))['blockhash'], bb_hash)\n\n        # Check hex/bin format\n        resp_hex = self.test_rest_request(\"/blockhashbyheight/{}\".format(block_json_obj['height']), req_type=ReqType.HEX, ret_type=RetType.OBJ)\n        assert_equal(resp_hex.read().decode('utf-8').rstrip(), bb_hash)\n        resp_bytes = self.test_rest_request(\"/blockhashbyheight/{}\".format(block_json_obj['height']), req_type=ReqType.BIN, ret_type=RetType.BYTES)\n        blockhash = resp_bytes[::-1].hex()\n        assert_equal(blockhash, bb_hash)\n\n        # Check invalid blockhashbyheight requests\n        resp = self.test_rest_request(\"/blockhashbyheight/abc\", ret_type=RetType.OBJ, status=400)\n        assert_equal(resp.read().decode('utf-8').rstrip(), \"Invalid height: abc\")\n        resp = self.test_rest_request(\"/blockhashbyheight/1000000\", ret_type=RetType.OBJ, status=404)\n        assert_equal(resp.read().decode('utf-8').rstrip(), \"Block height out of range\")\n        resp = self.test_rest_request(\"/blockhashbyheight/-1\", ret_type=RetType.OBJ, status=400)\n        assert_equal(resp.read().decode('utf-8').rstrip(), \"Invalid height: -1\")\n        self.test_rest_request(\"/blockhashbyheight/\", ret_type=RetType.OBJ, status=400)\n\n        # Compare with json block header\n        json_obj = self.test_rest_request(\"/headers/1/{}\".format(bb_hash))\n        assert_equal(len(json_obj), 1)  # ensure that there is one header in the json response\n        assert_equal(json_obj[0]['hash'], bb_hash)  # request/response hash should be the same\n\n        # Compare with normal RPC block response\n        rpc_block_json = self.nodes[0].getblock(bb_hash)\n        for key in ['hash', 'confirmations', 'height', 'version', 'merkleroot', 'time', 'nonce', 'bits', 'difficulty', 'chainwork', 'previousblockhash']:\n            assert_equal(json_obj[0][key], rpc_block_json[key])\n\n        # See if we can get 5 headers in one response\n        self.nodes[1].generate(5)\n        self.sync_all()\n        json_obj = self.test_rest_request(\"/headers/5/{}\".format(bb_hash))\n        assert_equal(len(json_obj), 5)  # now we should have 5 header objects\n\n        self.log.info(\"Test tx inclusion in the /mempool and /block URIs\")\n\n        # Make 3 tx and mine them on node 1\n        txs = []\n        txs.append(self.nodes[0].sendtoaddress(not_related_address, 11))\n        txs.append(self.nodes[0].sendtoaddress(not_related_address, 11))\n        txs.append(self.nodes[0].sendtoaddress(not_related_address, 11))\n        self.sync_all()\n\n        # Check that there are exactly 3 transactions in the TX memory pool before generating the block\n        json_obj = self.test_rest_request(\"/mempool/info\")\n        assert_equal(json_obj['size'], 3)\n        # the size of the memory pool should be greater than 3x ~100 bytes\n        assert_greater_than(json_obj['bytes'], 300)\n\n        # Check that there are our submitted transactions in the TX memory pool\n        json_obj = self.test_rest_request(\"/mempool/contents\")\n        for i, tx in enumerate(txs):\n            assert tx in json_obj\n            assert_equal(json_obj[tx]['spentby'], txs[i + 1:i + 2])\n            assert_equal(json_obj[tx]['depends'], txs[i - 1:i])\n\n        # Now mine the transactions\n        newblockhash = self.nodes[1].generate(1)\n        self.sync_all()\n\n        # Check if the 3 tx show up in the new block\n        json_obj = self.test_rest_request(\"/block/{}\".format(newblockhash[0]))\n        non_coinbase_txs = {tx['txid'] for tx in json_obj['tx']\n                            if 'coinbase' not in tx['vin'][0]}\n        assert_equal(non_coinbase_txs, set(txs))\n\n        # Check the same but without tx details\n        json_obj = self.test_rest_request(\"/block/notxdetails/{}\".format(newblockhash[0]))\n        for tx in txs:\n            assert tx in json_obj['tx']\n\n        self.log.info(\"Test the /chaininfo URI\")\n\n        bb_hash = self.nodes[0].getbestblockhash()\n\n        json_obj = self.test_rest_request(\"/chaininfo\")\n        assert_equal(json_obj['bestblockhash'], bb_hash)\n\nif __name__ == '__main__':\n    RESTTest().main()\n"
  },
  {
    "path": "test/functional/interface_rpc.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Tests some generic aspects of the RPC interface.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_greater_than_or_equal\n\nclass RPCInterfaceTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def test_getrpcinfo(self):\n        self.log.info(\"Testing getrpcinfo...\")\n\n        info = self.nodes[0].getrpcinfo()\n        assert_equal(len(info['active_commands']), 1)\n\n        command = info['active_commands'][0]\n        assert_equal(command['method'], 'getrpcinfo')\n        assert_greater_than_or_equal(command['duration'], 0)\n\n    def test_batch_request(self):\n        self.log.info(\"Testing basic JSON-RPC batch request...\")\n\n        results = self.nodes[0].batch([\n            # A basic request that will work fine.\n            {\"method\": \"getblockcount\", \"id\": 1},\n            # Request that will fail.  The whole batch request should still\n            # work fine.\n            {\"method\": \"invalidmethod\", \"id\": 2},\n            # Another call that should succeed.\n            {\"method\": \"getbestblockhash\", \"id\": 3},\n        ])\n\n        result_by_id = {}\n        for res in results:\n            result_by_id[res[\"id\"]] = res\n\n        assert_equal(result_by_id[1]['error'], None)\n        assert_equal(result_by_id[1]['result'], 0)\n\n        assert_equal(result_by_id[2]['error']['code'], -32601)\n        assert_equal(result_by_id[2]['result'], None)\n\n        assert_equal(result_by_id[3]['error'], None)\n        assert result_by_id[3]['result'] is not None\n\n    def run_test(self):\n        self.test_getrpcinfo()\n        self.test_batch_request()\n\n\nif __name__ == '__main__':\n    RPCInterfaceTest().main()\n"
  },
  {
    "path": "test/functional/interface_zmq.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the ZMQ notification interface.\"\"\"\nimport struct\n\nfrom test_framework.address import ADDRESS_BCRT1_UNSPENDABLE\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.messages import CTransaction\nfrom test_framework.util import (\n    assert_equal,\n    hash256,\n)\nfrom io import BytesIO\n\nADDRESS = \"tcp://127.0.0.1:28332\"\n\nclass ZMQSubscriber:\n    def __init__(self, socket, topic):\n        self.sequence = 0\n        self.socket = socket\n        self.topic = topic\n\n        import zmq\n        self.socket.setsockopt(zmq.SUBSCRIBE, self.topic)\n\n    def receive(self):\n        topic, body, seq = self.socket.recv_multipart()\n        # Topic should match the subscriber topic.\n        assert_equal(topic, self.topic)\n        # Sequence should be incremental.\n        assert_equal(struct.unpack('<I', seq)[-1], self.sequence)\n        self.sequence += 1\n        return body\n\n\nclass ZMQTest (MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_py3_zmq()\n        self.skip_if_no_daemon_zmq()\n\n    def setup_nodes(self):\n        import zmq\n\n        # Initialize ZMQ context and socket.\n        # All messages are received in the same socket which means\n        # that this test fails if the publishing order changes.\n        # Note that the publishing order is not defined in the documentation and\n        # is subject to change.\n        self.zmq_context = zmq.Context()\n        socket = self.zmq_context.socket(zmq.SUB)\n        socket.set(zmq.RCVTIMEO, 60000)\n        socket.connect(ADDRESS)\n\n        # Subscribe to all available topics.\n        self.hashblock = ZMQSubscriber(socket, b\"hashblock\")\n        self.hashtx = ZMQSubscriber(socket, b\"hashtx\")\n        self.rawblock = ZMQSubscriber(socket, b\"rawblock\")\n        self.rawtx = ZMQSubscriber(socket, b\"rawtx\")\n\n        self.extra_args = [\n            [\"-zmqpub%s=%s\" % (sub.topic.decode(), ADDRESS) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]],\n            [],\n        ]\n        self.add_nodes(self.num_nodes, self.extra_args)\n        self.start_nodes()\n        self.import_deterministic_coinbase_privkeys()\n\n    def run_test(self):\n        try:\n            self._zmq_test()\n        finally:\n            # Destroy the ZMQ context.\n            self.log.debug(\"Destroying ZMQ context\")\n            self.zmq_context.destroy(linger=None)\n\n    def _zmq_test(self):\n        num_blocks = 5\n        self.log.info(\"Generate %(n)d blocks (and %(n)d coinbase txes)\" % {\"n\": num_blocks})\n        genhashes = self.nodes[0].generatetoaddress(num_blocks, ADDRESS_BCRT1_UNSPENDABLE)\n        self.sync_all()\n\n        for x in range(num_blocks):\n            # Should receive the coinbase txid.\n            txid = self.hashtx.receive()\n\n            # Should receive the coinbase raw transaction.\n            hex = self.rawtx.receive()\n            tx = CTransaction()\n            tx.deserialize(BytesIO(hex))\n            tx.calc_sha256()\n            assert_equal(tx.hash, txid.hex())\n\n            # Should receive the generated block hash.\n            hash = self.hashblock.receive().hex()\n            assert_equal(genhashes[x], hash)\n            # The block should only have the coinbase txid.\n            assert_equal([txid.hex()], self.nodes[1].getblock(hash)[\"tx\"])\n\n            # Should receive the generated raw block.\n            block = self.rawblock.receive()\n            assert_equal(genhashes[x], hash256(block[:80]).hex())\n\n        if self.is_wallet_compiled():\n            self.log.info(\"Wait for tx from second node\")\n            payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)\n            self.sync_all()\n\n            # Should receive the broadcasted txid.\n            txid = self.hashtx.receive()\n            assert_equal(payment_txid, txid.hex())\n\n            # Should receive the broadcasted raw transaction.\n            hex = self.rawtx.receive()\n            assert_equal(payment_txid, hash256(hex).hex())\n\n\n        self.log.info(\"Test the getzmqnotifications RPC\")\n        assert_equal(self.nodes[0].getzmqnotifications(), [\n            {\"type\": \"pubhashblock\", \"address\": ADDRESS, \"hwm\": 1000},\n            {\"type\": \"pubhashtx\", \"address\": ADDRESS, \"hwm\": 1000},\n            {\"type\": \"pubrawblock\", \"address\": ADDRESS, \"hwm\": 1000},\n            {\"type\": \"pubrawtx\", \"address\": ADDRESS, \"hwm\": 1000},\n        ])\n\n        assert_equal(self.nodes[1].getzmqnotifications(), [])\n\nif __name__ == '__main__':\n    ZMQTest().main()\n"
  },
  {
    "path": "test/functional/mempool_accept.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test mempool acceptance of raw transactions.\"\"\"\n\nfrom io import BytesIO\nimport math\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.messages import (\n    BIP125_SEQUENCE_NUMBER,\n    COIN,\n    COutPoint,\n    CTransaction,\n    CTxOut,\n    MAX_BLOCK_BASE_SIZE,\n)\nfrom test_framework.script import (\n    hash160,\n    CScript,\n    OP_0,\n    OP_EQUAL,\n    OP_HASH160,\n    OP_RETURN,\n)\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    hex_str_to_bytes,\n)\n\n\nclass MempoolAcceptanceTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.extra_args = [[\n            '-txindex',\n            '-acceptnonstdtxn=0',  # Try to mimic main-net\n        ]] * self.num_nodes\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def check_mempool_result(self, result_expected, *args, **kwargs):\n        \"\"\"Wrapper to check result of testmempoolaccept on node_0's mempool\"\"\"\n        result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)\n        assert_equal(result_expected, result_test)\n        assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size)  # Must not change mempool state\n\n    def run_test(self):\n        node = self.nodes[0]\n\n        self.log.info('Start with empty mempool, and 200 blocks')\n        self.mempool_size = 0\n        assert_equal(node.getblockcount(), 200)\n        assert_equal(node.getmempoolinfo()['size'], self.mempool_size)\n        coins = node.listunspent()\n\n        self.log.info('Should not accept garbage to testmempoolaccept')\n        assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))\n        assert_raises_rpc_error(-8, 'Array must contain exactly one raw transaction for now', lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))\n        assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))\n\n        self.log.info('A transaction already in the blockchain')\n        coin = coins.pop()  # Pick a random coin(base) to spend\n        raw_tx_in_block = node.signrawtransaction(node.createrawtransaction(\n            inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],\n            outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],\n        ))['hex']\n        txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block)\n        node.generate(1)\n        self.mempool_size = 0\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': '18: txn-already-known'}],\n            rawtxs=[raw_tx_in_block],\n        )\n\n        self.log.info('A transaction not in the mempool')\n        fee = 0.00000700\n        raw_tx_0 = node.signrawtransaction(node.createrawtransaction(\n            inputs=[{\"txid\": txid_in_block, \"vout\": 0, \"sequence\": BIP125_SEQUENCE_NUMBER}],  # RBF is used later\n            outputs=[{node.getnewaddress(): 0.3 - fee}],\n        ))['hex']\n        tx = CTransaction()\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        txid_0 = tx.rehash()\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_0, 'allowed': True}],\n            rawtxs=[raw_tx_0],\n        )\n\n        self.log.info('A final transaction not in the mempool')\n        coin = coins.pop()  # Pick a random coin(base) to spend\n        raw_tx_final = node.signrawtransaction(node.createrawtransaction(\n            inputs=[{'txid': coin['txid'], 'vout': coin['vout'], \"sequence\": 0xffffffff}],  # SEQUENCE_FINAL\n            outputs=[{node.getnewaddress(): 0.025}],\n            locktime=node.getblockcount() + 2000,  # Can be anything\n        ))['hex']\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final)))\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': True}],\n            rawtxs=[tx.serialize().hex()],\n            maxfeerate=0,\n        )\n        node.sendrawtransaction(hexstring=raw_tx_final)\n        self.mempool_size += 1\n\n        self.log.info('A transaction in the mempool')\n        node.sendrawtransaction(hexstring=raw_tx_0)\n        self.mempool_size += 1\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': '18: txn-already-in-mempool'}],\n            rawtxs=[raw_tx_0],\n        )\n\n        self.log.info('A transaction that replaces a mempool transaction')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        tx.vout[0].nValue -= int(fee * COIN)  # Double the fee\n        tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1  # Now, opt out of RBF\n        raw_tx_0 = node.signrawtransaction(tx.serialize().hex())['hex']\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        txid_0 = tx.rehash()\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_0, 'allowed': True}],\n            rawtxs=[raw_tx_0],\n        )\n\n        self.log.info('A transaction that conflicts with an unconfirmed tx')\n        # Send the transaction that replaces the mempool transaction and opts out of replaceability\n        node.sendrawtransaction(hexstring=tx.serialize().hex())\n        # take original raw_tx_0\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        tx.vout[0].nValue -= int(4 * fee * COIN)  # Set more fee\n        # skip re-signing the tx\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],\n            rawtxs=[tx.serialize().hex()],\n            maxfeerate=0,\n        )\n\n        self.log.info('A transaction with missing inputs, that never existed')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)\n        # skip re-signing the tx\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with missing inputs, that existed once in the past')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))\n        tx.vin[0].prevout.n = 1  # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend\n        raw_tx_1 = node.signrawtransaction(tx.serialize().hex())['hex']\n        txid_1 = node.sendrawtransaction(hexstring=raw_tx_1)\n        # Now spend both to \"clearly hide\" the outputs, ie. remove the coins from the utxo set by spending them\n        raw_tx_spend_both = node.signrawtransaction(node.createrawtransaction(\n            inputs=[\n                {'txid': txid_0, 'vout': 0},\n                {'txid': txid_1, 'vout': 0},\n            ],\n            outputs=[{node.getnewaddress(): 0.1}]\n        ))['hex']\n        txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both)\n        node.generate(1)\n        self.mempool_size = 0\n        # Now see if we can add the coins back to the utxo set by sending the exact txs again\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'missing-inputs'}],\n            rawtxs=[raw_tx_0],\n        )\n        self.check_mempool_result(\n            result_expected=[{'txid': txid_1, 'allowed': False, 'reject-reason': 'missing-inputs'}],\n            rawtxs=[raw_tx_1],\n        )\n\n        self.log.info('Create a signed \"reference\" tx for later use')\n        raw_tx_reference = node.signrawtransaction(node.createrawtransaction(\n            inputs=[{'txid': txid_spend_both, 'vout': 0}],\n            outputs=[{node.getnewaddress(): 0.05}],\n        ))['hex']\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        # Reference tx should be valid on itself\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': True}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with no outputs')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout = []\n        # Skip re-signing the transaction for context independent checks from now on\n        # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransaction(tx.serialize().hex())['hex'])))\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A really large transaction')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with negative output value')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout[0].nValue *= -1\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with too large output value')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout[0].nValue = 21000000 * COIN + 1\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with too large sum of output values')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout = [tx.vout[0]] * 2\n        tx.vout[0].nValue = 21000000 * COIN\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction with duplicate inputs')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vin = [tx.vin[0]] * 2\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A coinbase transaction')\n        # Pick the input of the first tx we signed, so it has to be a coinbase tx\n        raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('Some nonstandard transactions')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.nVersion = 3  # A version currently non-standard\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vin[0].scriptSig = CScript([OP_HASH160])  # Some not-pushonly scriptSig\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript([OP_HASH160, hash160(b'burn'), OP_EQUAL]))\n        num_scripts = 100000 // len(output_p2sh_burn.serialize())  # Use enough outputs to make the tx too large for our policy\n        tx.vout = [output_p2sh_burn] * num_scripts\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout[0] = output_p2sh_burn\n        tx.vout[0].nValue -= 1  # Make output smaller, such that it is dust for our policy\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\\xff'])\n        tx.vout = [tx.vout[0]] * 2\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A timelocked transaction')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vin[0].nSequence -= 1  # Should be non-max, so locktime is not ignored\n        tx.nLockTime = node.getblockcount() + 1\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}],\n            rawtxs=[tx.serialize().hex()],\n        )\n\n        self.log.info('A transaction that is locked by BIP68 sequence logic')\n        tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))\n        tx.vin[0].nSequence = 2  # We could include it in the second block mined from now, but not the very next one\n        # Can skip re-signing the tx because of early rejection\n        self.check_mempool_result(\n            result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],\n            rawtxs=[tx.serialize().hex()],\n            maxfeerate=0,\n        )\n\n\nif __name__ == '__main__':\n    MempoolAcceptanceTest().main()\n"
  },
  {
    "path": "test/functional/mempool_limit.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test mempool limiting together/eviction with the wallet.\"\"\"\n\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts\n\nclass MempoolLimitTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        self.extra_args = [[\"-maxmempool=5\", \"-spendzeroconfchange=0\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        txouts = gen_return_txouts()\n        relayfee = self.nodes[0].getnetworkinfo()['relayfee']\n\n        self.log.info('Check that mempoolminfee is minrelytxfee')\n        assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))\n        assert_equal(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))\n\n        txids = []\n        utxos = create_confirmed_utxos(relayfee, self.nodes[0], 91)\n\n        self.log.info('Create a mempool tx that will be evicted')\n        us0 = utxos.pop()\n        inputs = [{ \"txid\" : us0[\"txid\"], \"vout\" : us0[\"vout\"]}]\n        outputs = {self.nodes[0].getnewaddress() : 0.0001}\n        tx = self.nodes[0].createrawtransaction(inputs, outputs)\n        self.nodes[0].settxfee(relayfee) # specifically fund this tx with low fee\n        txF = self.nodes[0].fundrawtransaction(tx)\n        self.nodes[0].settxfee(0) # return to automatic fee selection\n        txFS = self.nodes[0].signrawtransaction(txF['hex'])\n        txid = self.nodes[0].sendrawtransaction(txFS['hex'])\n\n        relayfee = self.nodes[0].getnetworkinfo()['relayfee']\n        base_fee = relayfee*100\n        for i in range (3):\n            txids.append([])\n            txids[i] = create_lots_of_big_transactions(self.nodes[0], txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)\n\n        self.log.info('The tx should be evicted by now')\n        assert txid not in self.nodes[0].getrawmempool()\n        txdata = self.nodes[0].gettransaction(txid)\n        assert txdata['confirmations'] ==  0  #confirmation should still be 0\n\n        self.log.info('Check that mempoolminfee is larger than minrelytxfee')\n        assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))\n        assert_greater_than(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))\n\n        self.log.info('Create a mempool tx that will not pass mempoolminfee')\n        us0 = utxos.pop()\n        inputs = [{ \"txid\" : us0[\"txid\"], \"vout\" : us0[\"vout\"]}]\n        outputs = {self.nodes[0].getnewaddress() : 0.0001}\n        tx = self.nodes[0].createrawtransaction(inputs, outputs)\n        # specifically fund this tx with a fee < mempoolminfee, >= than minrelaytxfee\n        txF = self.nodes[0].fundrawtransaction(tx, {'feeRate': relayfee})\n        txFS = self.nodes[0].signrawtransaction(txF['hex'])\n        assert_raises_rpc_error(-26, \"mempool min fee not met\", self.nodes[0].sendrawtransaction, txFS['hex'])\n\nif __name__ == '__main__':\n    MempoolLimitTest().main()\n"
  },
  {
    "path": "test/functional/mempool_packages.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test descendant package tracking code.\"\"\"\n\nfrom decimal import Decimal\n\nfrom test_framework.messages import COIN\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round, sync_blocks, sync_mempools\n\nMAX_ANCESTORS = 25\nMAX_DESCENDANTS = 25\n\nclass MempoolPackagesTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [[\"-maxorphantx=1000\"], [\"-maxorphantx=1000\", \"-limitancestorcount=5\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    # Build a transaction that spends parent_txid:vout\n    # Return amount sent\n    def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs):\n        send_value = satoshi_round((value - fee)/num_outputs)\n        inputs = [ {'txid' : parent_txid, 'vout' : vout} ]\n        outputs = {}\n        for i in range(num_outputs):\n            outputs[node.getnewaddress()] = send_value\n        rawtx = node.createrawtransaction(inputs, outputs)\n        signedtx = node.signrawtransaction(rawtx)\n        txid = node.sendrawtransaction(signedtx['hex'])\n        fulltx = node.getrawtransaction(txid, 1)\n        assert len(fulltx['vout']) == num_outputs  # make sure we didn't generate a change output\n        return (txid, send_value)\n\n    def run_test(self):\n        # Mine some blocks and have them mature.\n        self.nodes[0].generate(101)\n        utxo = self.nodes[0].listunspent(10)\n        txid = utxo[0]['txid']\n        vout = utxo[0]['vout']\n        value = utxo[0]['amount']\n\n        fee = Decimal(\"0.0001\")\n        # MAX_ANCESTORS transactions off a confirmed tx should be fine\n        chain = []\n        for i in range(MAX_ANCESTORS):\n            (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, 0, value, fee, 1)\n            value = sent_value\n            chain.append(txid)\n\n        # Check mempool has MAX_ANCESTORS transactions in it, and descendant and ancestor\n        # count and fees should look correct\n        mempool = self.nodes[0].getrawmempool(True)\n        assert_equal(len(mempool), MAX_ANCESTORS)\n        descendant_count = 1\n        descendant_fees = 0\n        descendant_vsize = 0\n\n        ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])\n        ancestor_count = MAX_ANCESTORS\n        ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])\n\n        descendants = []\n        ancestors = list(chain)\n        for x in reversed(chain):\n            # Check that getmempoolentry is consistent with getrawmempool\n            entry = self.nodes[0].getmempoolentry(x)\n            assert_equal(entry, mempool[x])\n\n            # Check that the descendant calculations are correct\n            assert_equal(mempool[x]['descendantcount'], descendant_count)\n            descendant_fees += mempool[x]['fee']\n            assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee'])\n            assert_equal(mempool[x]['fees']['base'], mempool[x]['fee'])\n            assert_equal(mempool[x]['fees']['modified'], mempool[x]['modifiedfee'])\n            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN)\n            assert_equal(mempool[x]['fees']['descendant'], descendant_fees)\n            descendant_vsize += mempool[x]['vsize']\n            assert_equal(mempool[x]['descendantsize'], descendant_vsize)\n            descendant_count += 1\n\n            # Check that ancestor calculations are correct\n            assert_equal(mempool[x]['ancestorcount'], ancestor_count)\n            assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN)\n            assert_equal(mempool[x]['ancestorsize'], ancestor_vsize)\n            ancestor_vsize -= mempool[x]['vsize']\n            ancestor_fees -= mempool[x]['fee']\n            ancestor_count -= 1\n\n            # Check that parent/child list is correct\n            assert_equal(mempool[x]['spentby'], descendants[-1:])\n            assert_equal(mempool[x]['depends'], ancestors[-2:-1])\n\n            # Check that getmempooldescendants is correct\n            assert_equal(sorted(descendants), sorted(self.nodes[0].getmempooldescendants(x)))\n\n            # Check getmempooldescendants verbose output is correct\n            for descendant, dinfo in self.nodes[0].getmempooldescendants(x, True).items():\n                assert_equal(dinfo['depends'], [chain[chain.index(descendant)-1]])\n                if dinfo['descendantcount'] > 1:\n                    assert_equal(dinfo['spentby'], [chain[chain.index(descendant)+1]])\n                else:\n                    assert_equal(dinfo['spentby'], [])\n            descendants.append(x)\n\n            # Check that getmempoolancestors is correct\n            ancestors.remove(x)\n            assert_equal(sorted(ancestors), sorted(self.nodes[0].getmempoolancestors(x)))\n\n            # Check that getmempoolancestors verbose output is correct\n            for ancestor, ainfo in self.nodes[0].getmempoolancestors(x, True).items():\n                assert_equal(ainfo['spentby'], [chain[chain.index(ancestor)+1]])\n                if ainfo['ancestorcount'] > 1:\n                    assert_equal(ainfo['depends'], [chain[chain.index(ancestor)-1]])\n                else:\n                    assert_equal(ainfo['depends'], [])\n\n\n        # Check that getmempoolancestors/getmempooldescendants correctly handle verbose=true\n        v_ancestors = self.nodes[0].getmempoolancestors(chain[-1], True)\n        assert_equal(len(v_ancestors), len(chain)-1)\n        for x in v_ancestors.keys():\n            assert_equal(mempool[x], v_ancestors[x])\n        assert chain[-1] not in v_ancestors.keys()\n\n        v_descendants = self.nodes[0].getmempooldescendants(chain[0], True)\n        assert_equal(len(v_descendants), len(chain)-1)\n        for x in v_descendants.keys():\n            assert_equal(mempool[x], v_descendants[x])\n        assert chain[0] not in v_descendants.keys()\n\n        # Check that ancestor modified fees includes fee deltas from\n        # prioritisetransaction\n        self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=1000)\n        mempool = self.nodes[0].getrawmempool(True)\n        ancestor_fees = 0\n        for x in chain:\n            ancestor_fees += mempool[x]['fee']\n            assert_equal(mempool[x]['fees']['ancestor'], ancestor_fees + Decimal('0.00001'))\n            assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)\n\n        # Undo the prioritisetransaction for later tests\n        self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=-1000)\n\n        # Check that descendant modified fees includes fee deltas from\n        # prioritisetransaction\n        self.nodes[0].prioritisetransaction(txid=chain[-1], fee_delta=1000)\n        mempool = self.nodes[0].getrawmempool(True)\n\n        descendant_fees = 0\n        for x in reversed(chain):\n            descendant_fees += mempool[x]['fee']\n            assert_equal(mempool[x]['fees']['descendant'], descendant_fees + Decimal('0.00001'))\n            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000)\n\n        # Adding one more transaction on to the chain should fail.\n        assert_raises_rpc_error(-26, \"too-long-mempool-chain\", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1)\n\n        # Check that prioritising a tx before it's added to the mempool works\n        # First clear the mempool by mining a block.\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        # Prioritise a transaction that has been mined, then add it back to the\n        # mempool by using invalidateblock.\n        self.nodes[0].prioritisetransaction(txid=chain[-1], fee_delta=2000)\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n        # Keep node1's tip synced with node0\n        self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())\n\n        # Now check that the transaction is in the mempool, with the right modified fee\n        mempool = self.nodes[0].getrawmempool(True)\n\n        descendant_fees = 0\n        for x in reversed(chain):\n            descendant_fees += mempool[x]['fee']\n            if (x == chain[-1]):\n                assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002))\n                assert_equal(mempool[x]['fees']['modified'], mempool[x]['fee']+satoshi_round(0.00002))\n            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 2000)\n            assert_equal(mempool[x]['fees']['descendant'], descendant_fees+satoshi_round(0.00002))\n\n        # TODO: check that node1's mempool is as expected\n\n        # TODO: test ancestor size limits\n\n        # Now test descendant chain limits\n        txid = utxo[1]['txid']\n        value = utxo[1]['amount']\n        vout = utxo[1]['vout']\n\n        transaction_package = []\n        tx_children = []\n        # First create one parent tx with 10 children\n        (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 10)\n        parent_transaction = txid\n        for i in range(10):\n            transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})\n\n        # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx\n        for i in range(MAX_DESCENDANTS - 1):\n            utxo = transaction_package.pop(0)\n            (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)\n            if utxo['txid'] is parent_transaction:\n                tx_children.append(txid)\n            for j in range(10):\n                transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})\n\n        mempool = self.nodes[0].getrawmempool(True)\n        assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)\n        assert_equal(sorted(mempool[parent_transaction]['spentby']), sorted(tx_children))\n\n        for child in tx_children:\n            assert_equal(mempool[child]['depends'], [parent_transaction])\n\n        # Sending one more chained transaction will fail\n        utxo = transaction_package.pop(0)\n        assert_raises_rpc_error(-26, \"too-long-mempool-chain\", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)\n\n        # TODO: check that node1's mempool is as expected\n\n        # TODO: test descendant size limits\n\n        # Test reorg handling\n        # First, the basics:\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n        self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())\n        self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())\n\n        # Now test the case where node1 has a transaction T in its mempool that\n        # depends on transactions A and B which are in a mined block, and the\n        # block containing A and B is disconnected, AND B is not accepted back\n        # into node1's mempool because its ancestor count is too high.\n\n        # Create 8 transactions, like so:\n        # Tx0 -> Tx1 (vout0)\n        #   \\--> Tx2 (vout1) -> Tx3 -> Tx4 -> Tx5 -> Tx6 -> Tx7\n        #\n        # Mine them in the next block, then generate a new tx8 that spends\n        # Tx1 and Tx7, and add to node1's mempool, then disconnect the\n        # last block.\n\n        # Create tx0 with 2 outputs\n        utxo = self.nodes[0].listunspent()\n        txid = utxo[0]['txid']\n        value = utxo[0]['amount']\n        vout = utxo[0]['vout']\n\n        send_value = satoshi_round((value - fee)/2)\n        inputs = [ {'txid' : txid, 'vout' : vout} ]\n        outputs = {}\n        for i in range(2):\n            outputs[self.nodes[0].getnewaddress()] = send_value\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        signedtx = self.nodes[0].signrawtransaction(rawtx)\n        txid = self.nodes[0].sendrawtransaction(signedtx['hex'])\n        tx0_id = txid\n        value = send_value\n\n        # Create tx1\n        tx1_id, _ = self.chain_transaction(self.nodes[0], tx0_id, 0, value, fee, 1)\n\n        # Create tx2-7\n        vout = 1\n        txid = tx0_id\n        for i in range(6):\n            (txid, sent_value) = self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)\n            vout = 0\n            value = sent_value\n\n        # Mine these in a block\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        # Now generate tx8, with a big fee\n        inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ]\n        outputs = { self.nodes[0].getnewaddress() : send_value + value - 4*fee }\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        signedtx = self.nodes[0].signrawtransaction(rawtx)\n        txid = self.nodes[0].sendrawtransaction(signedtx['hex'])\n        sync_mempools(self.nodes)\n\n        # Now try to disconnect the tip on each node...\n        self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n        sync_blocks(self.nodes)\n\nif __name__ == '__main__':\n    MempoolPackagesTest().main()\n"
  },
  {
    "path": "test/functional/mempool_persist.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test mempool persistence.\n\nBy default, Munt-daemon will dump mempool on shutdown and\nthen reload it on startup. This can be overridden with\nthe -persistmempool=0 command line option.\n\nTest is as follows:\n\n  - start node0, node1 and node2. node1 has -persistmempool=0\n  - create 5 transactions on node2 to its own address. Note that these\n    are not sent to node0 or node1 addresses because we don't want\n    them to be saved in the wallet.\n  - check that node0 and node1 have 5 transactions in their mempools\n  - shutdown all nodes.\n  - startup node0. Verify that it still has 5 transactions\n    in its mempool. Shutdown node0. This tests that by default the\n    mempool is persistent.\n  - startup node1. Verify that its mempool is empty. Shutdown node1.\n    This tests that with -persistmempool=0, the mempool is not\n    dumped to disk when the node is shut down.\n  - Restart node0 with -persistmempool=0. Verify that its mempool is\n    empty. Shutdown node0. This tests that with -persistmempool=0,\n    the mempool is not loaded from disk on start up.\n  - Restart node0 with -persistmempool. Verify that it has 5\n    transactions in its mempool. This tests that -persistmempool=0\n    does not overwrite a previously valid mempool stored on disk.\n  - Remove node0 mempool.dat and verify savemempool RPC recreates it\n    and verify that node1 can load it and has 5 transactions in its\n    mempool.\n  - Verify that savemempool throws when the RPC is called if\n    node1 can't write to disk.\n\n\"\"\"\nfrom decimal import Decimal\nimport os\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, wait_until\n\n\nclass MempoolPersistTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 3\n        self.extra_args = [[], [\"-persistmempool=0\"], []]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        chain_height = self.nodes[0].getblockcount()\n        assert_equal(chain_height, 200)\n\n        self.log.debug(\"Mine a single block to get out of IBD\")\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        self.log.debug(\"Send 5 transactions from node2 (to its own address)\")\n        for i in range(5):\n            last_txid = self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), Decimal(\"10\"))\n        node2_balance = self.nodes[2].getbalance()\n        self.sync_all()\n\n        self.log.debug(\"Verify that node0 and node1 have 5 transactions in their mempools\")\n        assert_equal(len(self.nodes[0].getrawmempool()), 5)\n        assert_equal(len(self.nodes[1].getrawmempool()), 5)\n\n        self.log.debug(\"Prioritize a transaction on node0\")\n        fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees']\n        assert_equal(fees['base'], fees['modified'])\n        self.nodes[0].prioritisetransaction(txid=last_txid, fee_delta=1000)\n        fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees']\n        assert_equal(fees['base'] + Decimal('0.00001000'), fees['modified'])\n\n        self.log.debug(\"Stop-start the nodes. Verify that node0 has the transactions in its mempool and node1 does not. Verify that node2 calculates its balance correctly after loading wallet transactions.\")\n        self.stop_nodes()\n        # Give this node a head-start, so we can be \"extra-sure\" that it didn't load anything later\n        # Also don't store the mempool, to keep the datadir clean\n        self.start_node(1, extra_args=[\"-persistmempool=0\"])\n        self.start_node(0)\n        self.start_node(2)\n        # Give Munt-daemon a second to reload the mempool\n        wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5, timeout=1)\n        wait_until(lambda: len(self.nodes[2].getrawmempool()) == 5, timeout=1)\n        # The others have loaded their mempool. If node_1 loaded anything, we'd probably notice by now:\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n\n        self.log.debug('Verify prioritization is loaded correctly')\n        fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees']\n        assert_equal(fees['base'] + Decimal('0.00001000'), fees['modified'])\n\n        # Verify accounting of mempool transactions after restart is correct\n        self.nodes[2].syncwithvalidationinterfacequeue()  # Flush mempool to wallet\n        assert_equal(node2_balance, self.nodes[2].getbalance())\n\n        self.log.debug(\"Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.\")\n        self.stop_nodes()\n        self.start_node(0, extra_args=[\"-persistmempool=0\"])\n        # Give Munt-daemon a second to reload the mempool\n        time.sleep(1)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n\n        self.log.debug(\"Stop-start node0. Verify that it has the transactions in its mempool.\")\n        self.stop_nodes()\n        self.start_node(0)\n        wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)\n\n        mempooldat0 = os.path.join(self.nodes[0].datadir, 'regtest', 'mempool.dat')\n        mempooldat1 = os.path.join(self.nodes[1].datadir, 'regtest', 'mempool.dat')\n        self.log.debug(\"Remove the mempool.dat file. Verify that savemempool to disk via RPC re-creates it\")\n        os.remove(mempooldat0)\n        self.nodes[0].savemempool()\n        assert os.path.isfile(mempooldat0)\n\n        self.log.debug(\"Stop nodes, make node1 use mempool.dat from node0. Verify it has 5 transactions\")\n        os.rename(mempooldat0, mempooldat1)\n        self.stop_nodes()\n        self.start_node(1, extra_args=[])\n        wait_until(lambda: len(self.nodes[1].getrawmempool()) == 5)\n\n        self.log.debug(\"Prevent Munt-daemon from writing mempool.dat to disk. Verify that `savemempool` fails\")\n        # to test the exception we are creating a tmp folder called mempool.dat.new\n        # which is an implementation detail that could change and break this test\n        mempooldotnew1 = mempooldat1 + '.new'\n        os.mkdir(mempooldotnew1)\n        assert_raises_rpc_error(-1, \"Unable to dump mempool to disk\", self.nodes[1].savemempool)\n        os.rmdir(mempooldotnew1)\n\n\nif __name__ == '__main__':\n    MempoolPersistTest().main()\n"
  },
  {
    "path": "test/functional/mempool_reorg.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test mempool re-org scenarios.\n\nTest re-org scenarios with a mempool that contains transactions\nthat spend (directly or indirectly) coinbase transactions.\n\"\"\"\n\nfrom test_framework.blocktools import create_raw_transaction\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\n\nclass MempoolCoinbaseTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    alert_filename = None  # Set by setup_network\n\n    def run_test(self):\n        # Start with a 200 block chain\n        assert_equal(self.nodes[0].getblockcount(), 200)\n\n        # Mine four blocks. After this, nodes[0] blocks\n        # 101, 102, and 103 are spend-able.\n        new_blocks = self.nodes[1].generate(4)\n        self.sync_all()\n\n        node0_address = self.nodes[0].getnewaddress()\n        node1_address = self.nodes[1].getnewaddress()\n\n        # Three scenarios for re-orging coinbase spends in the memory pool:\n        # 1. Direct coinbase spend  :  spend_101\n        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1\n        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1\n        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),\n        # and make sure the mempool code behaves correctly.\n        b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ]\n        coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]\n        spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99)\n        spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99)\n        spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99)\n\n        # Create a transaction which is time-locked to two blocks in the future\n        timelock_tx = self.nodes[0].createrawtransaction([{\"txid\": coinbase_txids[0], \"vout\": 0}], {node0_address: 49.99})\n        # Set the time lock\n        timelock_tx = timelock_tx.replace(\"ffffffff\", \"11111191\", 1)\n        timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + \"000000\"\n        timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)[\"hex\"]\n        # This will raise an exception because the timelock transaction is too immature to spend\n        assert_raises_rpc_error(-26, \"non-final\", self.nodes[0].sendrawtransaction, timelock_tx)\n\n        # Broadcast and mine spend_102 and 103:\n        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)\n        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)\n        self.nodes[0].generate(1)\n        # Time-locked transaction is still too immature to spend\n        assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx)\n\n        # Create 102_1 and 103_1:\n        spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98)\n        spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98)\n\n        # Broadcast and mine 103_1:\n        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)\n        last_block = self.nodes[0].generate(1)\n        # Time-locked transaction can now be spent\n        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)\n\n        # ... now put spend_101 and spend_102_1 in memory pools:\n        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)\n        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)\n\n        self.sync_all()\n\n        assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id})\n\n        for node in self.nodes:\n            node.invalidateblock(last_block[0])\n        # Time-locked transaction is now too immature and has been removed from the mempool\n        # spend_103_1 has been re-orged out of the chain and is back in the mempool\n        assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})\n\n        # Use invalidateblock to re-org back and make all those coinbase spends\n        # immature/invalid:\n        for node in self.nodes:\n            node.invalidateblock(new_blocks[0])\n\n        self.sync_all()\n\n        # mempool should be empty.\n        assert_equal(set(self.nodes[0].getrawmempool()), set())\n\nif __name__ == '__main__':\n    MempoolCoinbaseTest().main()\n"
  },
  {
    "path": "test/functional/mempool_resurrect.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test resurrection of mined transactions when the blockchain is re-organized.\"\"\"\n\nfrom test_framework.blocktools import create_raw_transaction\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\n\nclass MempoolCoinbaseTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        node0_address = self.nodes[0].getnewaddress()\n        # Spend block 1/2/3's coinbase transactions\n        # Mine a block.\n        # Create three more transactions, spending the spends\n        # Mine another block.\n        # ... make sure all the transactions are confirmed\n        # Invalidate both blocks\n        # ... make sure all the transactions are put back in the mempool\n        # Mine a new block\n        # ... make sure all the transactions are confirmed again.\n\n        b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]\n        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]\n        spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]\n        spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]\n\n        blocks = []\n        blocks.extend(self.nodes[0].generate(1))\n\n        spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.98) for txid in spends1_id]\n        spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]\n\n        blocks.extend(self.nodes[0].generate(1))\n\n        # mempool should be empty, all txns confirmed\n        assert_equal(set(self.nodes[0].getrawmempool()), set())\n        for txid in spends1_id+spends2_id:\n            tx = self.nodes[0].gettransaction(txid)\n            assert tx[\"confirmations\"] > 0\n\n        # Use invalidateblock to re-org back\n        for node in self.nodes:\n            node.invalidateblock(blocks[0])\n\n        # All txns should be back in mempool with 0 confirmations\n        assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))\n        for txid in spends1_id+spends2_id:\n            tx = self.nodes[0].gettransaction(txid)\n            assert tx[\"confirmations\"] == 0\n\n        # Generate another block, they should all get mined\n        self.nodes[0].generate(1)\n        # mempool should be empty, all txns confirmed\n        assert_equal(set(self.nodes[0].getrawmempool()), set())\n        for txid in spends1_id+spends2_id:\n            tx = self.nodes[0].gettransaction(txid)\n            assert tx[\"confirmations\"] > 0\n\n\nif __name__ == '__main__':\n    MempoolCoinbaseTest().main()\n"
  },
  {
    "path": "test/functional/mempool_spend_coinbase.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test spending coinbase transactions.\n\nThe coinbase transaction in block N can appear in block\nN+100... so is valid in the mempool when the best block\nheight is N+99.\nThis test makes sure coinbase spends that will be mature\nin the next block are accepted into the memory pool,\nbut less mature coinbase spends are NOT.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.blocktools import create_raw_transaction\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\n\nclass MempoolSpendCoinbaseTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        chain_height = self.nodes[0].getblockcount()\n        assert_equal(chain_height, 200)\n        node0_address = self.nodes[0].getnewaddress()\n\n        # Coinbase at height chain_height-100+1 ok in mempool, should\n        # get mined. Coinbase at height chain_height-100+2 is\n        # is too immature to spend.\n        b = [self.nodes[0].getblockhash(n) for n in range(101, 103)]\n        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]\n        spends_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]\n\n        spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])\n\n        # coinbase at height 102 should be too immature to spend\n        assert_raises_rpc_error(-26,\"bad-txns-premature-spend-of-coinbase\", self.nodes[0].sendrawtransaction, spends_raw[1])\n\n        # mempool should have just spend_101:\n        assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])\n\n        # mine a block, spend_101 should get confirmed\n        self.nodes[0].generate(1)\n        assert_equal(set(self.nodes[0].getrawmempool()), set())\n\n        # ... and now height 102 can be spent:\n        spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])\n        assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])\n\nif __name__ == '__main__':\n    MempoolSpendCoinbaseTest().main()\n"
  },
  {
    "path": "test/functional/mining_basic.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test mining RPCs\n\n- getmininginfo\n- getblocktemplate proposal mode\n- submitblock\"\"\"\n\nimport copy\nfrom decimal import Decimal\n\nfrom test_framework.blocktools import (\n    create_coinbase,\n    TIME_GENESIS_BLOCK,\n)\nfrom test_framework.messages import (\n    CBlock,\n    CBlockHeader,\n    BLOCK_HEADER_SIZE\n)\nfrom test_framework.mininode import (\n    P2PDataStore,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n)\nfrom test_framework.script import CScriptNum\n\n\ndef assert_template(node, block, expect, rehash=True):\n    if rehash:\n        block.hashMerkleRoot = block.calc_merkle_root()\n    rsp = node.getblocktemplate(template_request={'data': block.serialize().hex(), 'mode': 'proposal', 'rules': ['segwit']})\n    assert_equal(rsp, expect)\n\n\nclass MiningTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n\n    def mine_chain(self):\n        self.log.info('Create some old blocks')\n        for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):\n            self.nodes[0].setmocktime(t)\n            self.nodes[0].generate(1)\n        mining_info = self.nodes[0].getmininginfo()\n        assert_equal(mining_info['blocks'], 200)\n        assert_equal(mining_info['currentblocktx'], 0)\n        assert_equal(mining_info['currentblockweight'], 4000)\n        self.restart_node(0)\n        connect_nodes_bi(self.nodes, 0, 1)\n\n    def run_test(self):\n        self.mine_chain()\n        node = self.nodes[0]\n\n        def assert_submitblock(block, result_str_1, result_str_2=None):\n            block.solve()\n            result_str_2 = result_str_2 or 'duplicate-invalid'\n            assert_equal(result_str_1, node.submitblock(hexdata=block.serialize().hex()))\n            assert_equal(result_str_2, node.submitblock(hexdata=block.serialize().hex()))\n\n        self.log.info('getmininginfo')\n        mining_info = node.getmininginfo()\n        assert_equal(mining_info['blocks'], 200)\n        assert_equal(mining_info['chain'], 'regtest')\n        assert 'currentblocktx' not in mining_info\n        assert 'currentblockweight' not in mining_info\n        assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10'))\n        assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334'))\n        assert_equal(mining_info['pooledtx'], 0)\n\n        # Mine a block to leave initial block download\n        node.generatetoaddress(1, node.get_deterministic_priv_key().address)\n        tmpl = node.getblocktemplate({'rules': ['segwit']})\n        self.log.info(\"getblocktemplate: Test capability advertised\")\n        assert 'proposal' in tmpl['capabilities']\n        assert 'coinbasetxn' not in tmpl\n\n        next_height = int(tmpl[\"height\"])\n        coinbase_tx = create_coinbase(height=next_height)\n        # sequence numbers must not be max for nLockTime to have effect\n        coinbase_tx.vin[0].nSequence = 2 ** 32 - 2\n        coinbase_tx.rehash()\n\n        # round-trip the encoded bip34 block height commitment\n        assert_equal(CScriptNum.decode(coinbase_tx.vin[0].scriptSig), next_height)\n        # round-trip negative and multi-byte CScriptNums to catch python regression\n        assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(1500))), 1500)\n        assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(-1500))), -1500)\n        assert_equal(CScriptNum.decode(CScriptNum.encode(CScriptNum(-1))), -1)\n\n        block = CBlock()\n        block.nVersion = tmpl[\"version\"]\n        block.hashPrevBlock = int(tmpl[\"previousblockhash\"], 16)\n        block.nTime = tmpl[\"curtime\"]\n        block.nBits = int(tmpl[\"bits\"], 16)\n        block.nNonce = 0\n        block.vtx = [coinbase_tx]\n\n        self.log.info(\"getblocktemplate: segwit rule must be set\")\n        assert_raises_rpc_error(-8, \"getblocktemplate must be called with the segwit rule set\", node.getblocktemplate)\n\n        self.log.info(\"getblocktemplate: Test valid block\")\n        assert_template(node, block, None)\n\n        self.log.info(\"submitblock: Test block decode failure\")\n        assert_raises_rpc_error(-22, \"Block decode failed\", node.submitblock, block.serialize()[:-15].hex())\n\n        self.log.info(\"getblocktemplate: Test bad input hash for coinbase transaction\")\n        bad_block = copy.deepcopy(block)\n        bad_block.vtx[0].vin[0].prevout.hash += 1\n        bad_block.vtx[0].rehash()\n        assert_template(node, bad_block, 'bad-cb-missing')\n\n        self.log.info(\"submitblock: Test invalid coinbase transaction\")\n        assert_raises_rpc_error(-22, \"Block does not start with a coinbase\", node.submitblock, bad_block.serialize().hex())\n\n        self.log.info(\"getblocktemplate: Test truncated final transaction\")\n        assert_raises_rpc_error(-22, \"Block decode failed\", node.getblocktemplate, {'data': block.serialize()[:-1].hex(), 'mode': 'proposal', 'rules': ['segwit']})\n\n        self.log.info(\"getblocktemplate: Test duplicate transaction\")\n        bad_block = copy.deepcopy(block)\n        bad_block.vtx.append(bad_block.vtx[0])\n        assert_template(node, bad_block, 'bad-txns-duplicate')\n        assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate')\n\n        self.log.info(\"getblocktemplate: Test invalid transaction\")\n        bad_block = copy.deepcopy(block)\n        bad_tx = copy.deepcopy(bad_block.vtx[0])\n        bad_tx.vin[0].prevout.hash = 255\n        bad_tx.rehash()\n        bad_block.vtx.append(bad_tx)\n        assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')\n        assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent')\n\n        self.log.info(\"getblocktemplate: Test nonfinal transaction\")\n        bad_block = copy.deepcopy(block)\n        bad_block.vtx[0].nLockTime = 2 ** 32 - 1\n        bad_block.vtx[0].rehash()\n        assert_template(node, bad_block, 'bad-txns-nonfinal')\n        assert_submitblock(bad_block, 'bad-txns-nonfinal')\n\n        self.log.info(\"getblocktemplate: Test bad tx count\")\n        # The tx count is immediately after the block header\n        bad_block_sn = bytearray(block.serialize())\n        assert_equal(bad_block_sn[BLOCK_HEADER_SIZE], 1)\n        bad_block_sn[BLOCK_HEADER_SIZE] += 1\n        assert_raises_rpc_error(-22, \"Block decode failed\", node.getblocktemplate, {'data': bad_block_sn.hex(), 'mode': 'proposal', 'rules': ['segwit']})\n\n        self.log.info(\"getblocktemplate: Test bad bits\")\n        bad_block = copy.deepcopy(block)\n        bad_block.nBits = 469762303  # impossible in the real world\n        assert_template(node, bad_block, 'bad-diffbits')\n\n        self.log.info(\"getblocktemplate: Test bad merkle root\")\n        bad_block = copy.deepcopy(block)\n        bad_block.hashMerkleRoot += 1\n        assert_template(node, bad_block, 'bad-txnmrklroot', False)\n        assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot')\n\n        self.log.info(\"getblocktemplate: Test bad timestamps\")\n        bad_block = copy.deepcopy(block)\n        bad_block.nTime = 2 ** 31 - 1\n        assert_template(node, bad_block, 'time-too-new')\n        assert_submitblock(bad_block, 'time-too-new', 'time-too-new')\n        bad_block.nTime = 0\n        assert_template(node, bad_block, 'time-too-old')\n        assert_submitblock(bad_block, 'time-too-old', 'time-too-old')\n\n        self.log.info(\"getblocktemplate: Test not best block\")\n        bad_block = copy.deepcopy(block)\n        bad_block.hashPrevBlock = 123\n        assert_template(node, bad_block, 'inconclusive-not-best-prevblk')\n        assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found')\n\n        self.log.info('submitheader tests')\n        assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * BLOCK_HEADER_SIZE))\n        assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (BLOCK_HEADER_SIZE-2)))\n        assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=super(CBlock, bad_block).serialize().hex()))\n\n        block.nTime += 1\n        block.solve()\n\n        def chain_tip(b_hash, *, status='headers-only', branchlen=1):\n            return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}\n\n        assert chain_tip(block.hash) not in node.getchaintips()\n        node.submitheader(hexdata=block.serialize().hex())\n        assert chain_tip(block.hash) in node.getchaintips()\n        node.submitheader(hexdata=CBlockHeader(block).serialize().hex())  # Noop\n        assert chain_tip(block.hash) in node.getchaintips()\n\n        bad_block_root = copy.deepcopy(block)\n        bad_block_root.hashMerkleRoot += 2\n        bad_block_root.solve()\n        assert chain_tip(bad_block_root.hash) not in node.getchaintips()\n        node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())\n        assert chain_tip(bad_block_root.hash) in node.getchaintips()\n        # Should still reject invalid blocks, even if we have the header:\n        assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')\n        assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')\n        assert chain_tip(bad_block_root.hash) in node.getchaintips()\n        # We know the header for this invalid block, so should just return early without error:\n        node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())\n        assert chain_tip(bad_block_root.hash) in node.getchaintips()\n\n        bad_block_lock = copy.deepcopy(block)\n        bad_block_lock.vtx[0].nLockTime = 2**32 - 1\n        bad_block_lock.vtx[0].rehash()\n        bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()\n        bad_block_lock.solve()\n        assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'bad-txns-nonfinal')\n        assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'duplicate-invalid')\n        # Build a \"good\" block on top of the submitted bad block\n        bad_block2 = copy.deepcopy(block)\n        bad_block2.hashPrevBlock = bad_block_lock.sha256\n        bad_block2.solve()\n        assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))\n\n        # Should reject invalid header right away\n        bad_block_time = copy.deepcopy(block)\n        bad_block_time.nTime = 1\n        bad_block_time.solve()\n        assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))\n\n        # Should ask for the block from a p2p node, if they announce the header as well:\n        node.add_p2p_connection(P2PDataStore())\n        node.p2p.wait_for_getheaders(timeout=5)  # Drop the first getheaders\n        node.p2p.send_blocks_and_test(blocks=[block], node=node)\n        # Must be active now:\n        assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips()\n\n        # Building a few blocks should give the same results\n        node.generatetoaddress(10, node.get_deterministic_priv_key().address)\n        assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))\n        assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))\n        node.submitheader(hexdata=CBlockHeader(block).serialize().hex())\n        node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())\n        assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate')  # valid\n\n\nif __name__ == '__main__':\n    MiningTest().main()\n"
  },
  {
    "path": "test/functional/mining_getblocktemplate_longpoll.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test longpolling with getblocktemplate.\"\"\"\n\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import get_rpc_proxy, random_transaction\n\nimport threading\n\nclass LongpollThread(threading.Thread):\n    def __init__(self, node):\n        threading.Thread.__init__(self)\n        # query current longpollid\n        template = node.getblocktemplate({'rules': ['segwit']})\n        self.longpollid = template['longpollid']\n        # create a new connection to the node, we can't use the same\n        # connection from two threads\n        self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir)\n\n    def run(self):\n        self.node.getblocktemplate({'longpollid': self.longpollid, 'rules': ['segwit']})\n\nclass GetBlockTemplateLPTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.log.info(\"Warning: this test will take about 70 seconds in the best case. Be patient.\")\n        self.nodes[0].generate(10)\n        template = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        longpollid = template['longpollid']\n        # longpollid should not change between successive invocations if nothing else happens\n        template2 = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        assert template2['longpollid'] == longpollid\n\n        # Test 1: test that the longpolling wait if we do nothing\n        thr = LongpollThread(self.nodes[0])\n        thr.start()\n        # check that thread still lives\n        thr.join(5)  # wait 5 seconds or until thread exits\n        assert thr.is_alive()\n\n        # Test 2: test that longpoll will terminate if another node generates a block\n        self.nodes[1].generate(1)  # generate a block on another node\n        # check that thread will exit now that new transaction entered mempool\n        thr.join(5)  # wait 5 seconds or until thread exits\n        assert not thr.is_alive()\n\n        # Test 3: test that longpoll will terminate if we generate a block ourselves\n        thr = LongpollThread(self.nodes[0])\n        thr.start()\n        self.nodes[0].generate(1)  # generate a block on another node\n        thr.join(5)  # wait 5 seconds or until thread exits\n        assert not thr.is_alive()\n\n        # Test 4: test that introducing a new transaction into the mempool will terminate the longpoll\n        thr = LongpollThread(self.nodes[0])\n        thr.start()\n        # generate a random transaction and submit it\n        min_relay_fee = self.nodes[0].getnetworkinfo()[\"relayfee\"]\n        # min_relay_fee is fee per 1000 bytes, which should be more than enough.\n        (txid, txhex, fee) = random_transaction(self.nodes, Decimal(\"1.1\"), min_relay_fee, Decimal(\"0.001\"), 20)\n        # after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned\n        thr.join(60 + 20)\n        assert not thr.is_alive()\n\nif __name__ == '__main__':\n    GetBlockTemplateLPTest().main()\n"
  },
  {
    "path": "test/functional/mining_prioritisetransaction.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the prioritisetransaction mining RPC.\"\"\"\n\nimport time\n\nfrom test_framework.messages import COIN, MAX_BLOCK_BASE_SIZE\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts\n\nclass PrioritiseTransactionTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.extra_args = [[\"-printpriority=1\"], [\"-printpriority=1\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Test `prioritisetransaction` required parameters\n        assert_raises_rpc_error(-1, \"prioritisetransaction\", self.nodes[0].prioritisetransaction)\n        assert_raises_rpc_error(-1, \"prioritisetransaction\", self.nodes[0].prioritisetransaction, '')\n        assert_raises_rpc_error(-1, \"prioritisetransaction\", self.nodes[0].prioritisetransaction, '', 0)\n\n        # Test `prioritisetransaction` invalid extra parameters\n        assert_raises_rpc_error(-1, \"prioritisetransaction\", self.nodes[0].prioritisetransaction, '', 0, 0, 0)\n\n        # Test `prioritisetransaction` invalid `txid`\n        assert_raises_rpc_error(-8, \"txid must be of length 64 (not 3, for 'foo')\", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)\n        assert_raises_rpc_error(-8, \"txid must be hexadecimal string (not 'Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000')\", self.nodes[0].prioritisetransaction, txid='Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000', fee_delta=0)\n\n        # Test `prioritisetransaction` invalid `dummy`\n        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'\n        assert_raises_rpc_error(-1, \"JSON value is not a number as expected\", self.nodes[0].prioritisetransaction, txid, 'foo', 0)\n        assert_raises_rpc_error(-8, \"Priority is no longer supported, dummy argument to prioritisetransaction must be 0.\", self.nodes[0].prioritisetransaction, txid, 1, 0)\n\n        # Test `prioritisetransaction` invalid `fee_delta`\n        assert_raises_rpc_error(-1, \"JSON value is not an integer as expected\", self.nodes[0].prioritisetransaction, txid=txid, fee_delta='foo')\n\n        self.txouts = gen_return_txouts()\n        self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']\n\n        utxo_count = 90\n        utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count)\n        base_fee = self.relayfee*100 # our transactions are smaller than 100kb\n        txids = []\n\n        # Create 3 batches of transactions at 3 different fee rate levels\n        range_size = utxo_count // 3\n        for i in range(3):\n            txids.append([])\n            start_range = i * range_size\n            end_range = start_range + range_size\n            txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee)\n\n        # Make sure that the size of each group of transactions exceeds\n        # MAX_BLOCK_BASE_SIZE -- otherwise the test needs to be revised to create\n        # more transactions.\n        mempool = self.nodes[0].getrawmempool(True)\n        sizes = [0, 0, 0]\n        for i in range(3):\n            for j in txids[i]:\n                assert j in mempool\n                sizes[i] += mempool[j]['vsize']\n            assert sizes[i] > MAX_BLOCK_BASE_SIZE  # Fail => raise utxo_count\n\n        # add a fee delta to something in the cheapest bucket and make sure it gets mined\n        # also check that a different entry in the cheapest bucket is NOT mined\n        self.nodes[0].prioritisetransaction(txid=txids[0][0], fee_delta=int(3*base_fee*COIN))\n\n        self.nodes[0].generate(1)\n\n        mempool = self.nodes[0].getrawmempool()\n        self.log.info(\"Assert that prioritised transaction was mined\")\n        assert txids[0][0] not in mempool\n        assert txids[0][1] in mempool\n\n        high_fee_tx = None\n        for x in txids[2]:\n            if x not in mempool:\n                high_fee_tx = x\n\n        # Something high-fee should have been mined!\n        assert high_fee_tx is not None\n\n        # Add a prioritisation before a tx is in the mempool (de-prioritising a\n        # high-fee transaction so that it's now low fee).\n        self.nodes[0].prioritisetransaction(txid=high_fee_tx, fee_delta=-int(2*base_fee*COIN))\n\n        # Add everything back to mempool\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n\n        # Check to make sure our high fee rate tx is back in the mempool\n        mempool = self.nodes[0].getrawmempool()\n        assert high_fee_tx in mempool\n\n        # Now verify the modified-high feerate transaction isn't mined before\n        # the other high fee transactions. Keep mining until our mempool has\n        # decreased by all the high fee size that we calculated above.\n        while (self.nodes[0].getmempoolinfo()['bytes'] > sizes[0] + sizes[1]):\n            self.nodes[0].generate(1)\n\n        # High fee transaction should not have been mined, but other high fee rate\n        # transactions should have been.\n        mempool = self.nodes[0].getrawmempool()\n        self.log.info(\"Assert that de-prioritised transaction is still in mempool\")\n        assert high_fee_tx in mempool\n        for x in txids[2]:\n            if (x != high_fee_tx):\n                assert x not in mempool\n\n        # Create a free transaction.  Should be rejected.\n        utxo_list = self.nodes[0].listunspent()\n        assert len(utxo_list) > 0\n        utxo = utxo_list[0]\n\n        inputs = []\n        outputs = {}\n        inputs.append({\"txid\" : utxo[\"txid\"], \"vout\" : utxo[\"vout\"]})\n        outputs[self.nodes[0].getnewaddress()] = utxo[\"amount\"]\n        raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)\n        tx_hex = self.nodes[0].signrawtransaction(raw_tx)[\"hex\"]\n        tx_id = self.nodes[0].decoderawtransaction(tx_hex)[\"txid\"]\n\n        # This will raise an exception due to min relay fee not being met\n        assert_raises_rpc_error(-26, \"min relay fee not met\", self.nodes[0].sendrawtransaction, tx_hex)\n        assert tx_id not in self.nodes[0].getrawmempool()\n\n        # This is a less than 1000-byte transaction, so just set the fee\n        # to be the minimum for a 1000-byte transaction and check that it is\n        # accepted.\n        self.nodes[0].prioritisetransaction(txid=tx_id, fee_delta=int(self.relayfee*COIN))\n\n        self.log.info(\"Assert that prioritised free transaction is accepted to mempool\")\n        assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)\n        assert tx_id in self.nodes[0].getrawmempool()\n\n        # Test that calling prioritisetransaction is sufficient to trigger\n        # getblocktemplate to (eventually) return a new block.\n        mock_time = int(time.time())\n        self.nodes[0].setmocktime(mock_time)\n        template = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n        self.nodes[0].prioritisetransaction(txid=tx_id, fee_delta=-int(self.relayfee*COIN))\n        self.nodes[0].setmocktime(mock_time+10)\n        new_template = self.nodes[0].getblocktemplate({'rules': ['segwit']})\n\n        assert template != new_template\n\nif __name__ == '__main__':\n    PrioritiseTransactionTest().main()\n"
  },
  {
    "path": "test/functional/p2p_compactblocks.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test compact blocks (BIP 152).\n\nVersion 1 compact blocks are pre-segwit (txids)\nVersion 2 compact blocks are post-segwit (wtxids)\n\"\"\"\nfrom decimal import Decimal\nimport random\n\nfrom test_framework.blocktools import create_block, create_coinbase, add_witness_commitment\nfrom test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_block, msg_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_witness_block, msg_witness_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, NODE_WITNESS, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex\nfrom test_framework.mininode import mininode_lock, P2PInterface\nfrom test_framework.script import CScript, OP_TRUE, OP_DROP\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, get_bip9_status, satoshi_round, sync_blocks, wait_until\n\n# TestP2PConn: A peer we use to send messages to Munt-daemon, and store responses.\nclass TestP2PConn(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.last_sendcmpct = []\n        self.block_announced = False\n        # Store the hashes of blocks we've seen announced.\n        # This is for synchronizing the p2p message traffic,\n        # so we can eg wait until a particular block is announced.\n        self.announced_blockhashes = set()\n\n    def on_sendcmpct(self, message):\n        self.last_sendcmpct.append(message)\n\n    def on_cmpctblock(self, message):\n        self.block_announced = True\n        self.last_message[\"cmpctblock\"].header_and_shortids.header.calc_sha256()\n        self.announced_blockhashes.add(self.last_message[\"cmpctblock\"].header_and_shortids.header.sha256)\n\n    def on_headers(self, message):\n        self.block_announced = True\n        for x in self.last_message[\"headers\"].headers:\n            x.calc_sha256()\n            self.announced_blockhashes.add(x.sha256)\n\n    def on_inv(self, message):\n        for x in self.last_message[\"inv\"].inv:\n            if x.type == 2:\n                self.block_announced = True\n                self.announced_blockhashes.add(x.hash)\n\n    # Requires caller to hold mininode_lock\n    def received_block_announcement(self):\n        return self.block_announced\n\n    def clear_block_announcement(self):\n        with mininode_lock:\n            self.block_announced = False\n            self.last_message.pop(\"inv\", None)\n            self.last_message.pop(\"headers\", None)\n            self.last_message.pop(\"cmpctblock\", None)\n\n    def get_headers(self, locator, hashstop):\n        msg = msg_getheaders()\n        msg.locator.vHave = locator\n        msg.hashstop = hashstop\n        self.send_message(msg)\n\n    def send_header_for_blocks(self, new_blocks):\n        headers_message = msg_headers()\n        headers_message.headers = [CBlockHeader(b) for b in new_blocks]\n        self.send_message(headers_message)\n\n    def request_headers_and_sync(self, locator, hashstop=0):\n        self.clear_block_announcement()\n        self.get_headers(locator, hashstop)\n        wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock)\n        self.clear_block_announcement()\n\n    # Block until a block announcement for a particular block hash is\n    # received.\n    def wait_for_block_announcement(self, block_hash, timeout=30):\n        def received_hash():\n            return (block_hash in self.announced_blockhashes)\n        wait_until(received_hash, timeout=timeout, lock=mininode_lock)\n\n    def send_await_disconnect(self, message, timeout=30):\n        \"\"\"Sends a message to the node and wait for disconnect.\n\n        This is used when we want to send a message into the node that we expect\n        will get us disconnected, eg an invalid block.\"\"\"\n        self.send_message(message)\n        wait_until(lambda: not self.is_connected, timeout=timeout, lock=mininode_lock)\n\nclass CompactBlocksTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        # Node0 = pre-segwit, node1 = segwit-aware\n        self.num_nodes = 2\n        # This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window).\n        # TODO: Rewrite this test to support SegWit being always active.\n        self.extra_args = [[\"-vbparams=segwit:0:0\"], [\"-vbparams=segwit:0:999999999999\", \"-txindex\"]]\n        self.utxos = []\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def build_block_on_tip(self, node, segwit=False):\n        height = node.getblockcount()\n        tip = node.getbestblockhash()\n        mtp = node.getblockheader(tip)['mediantime']\n        block = create_block(int(tip, 16), create_coinbase(height + 1), mtp + 1)\n        block.nVersion = 4\n        if segwit:\n            add_witness_commitment(block)\n        block.solve()\n        return block\n\n    # Create 10 more anyone-can-spend utxo's for testing.\n    def make_utxos(self):\n        # Doesn't matter which node we use, just use node0.\n        block = self.build_block_on_tip(self.nodes[0])\n        self.test_node.send_and_ping(msg_block(block))\n        assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256\n        self.nodes[0].generate(100)\n\n        total_value = block.vtx[0].vout[0].nValue\n        out_value = total_value // 10\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(block.vtx[0].sha256, 0), b''))\n        for i in range(10):\n            tx.vout.append(CTxOut(out_value, CScript([OP_TRUE])))\n        tx.rehash()\n\n        block2 = self.build_block_on_tip(self.nodes[0])\n        block2.vtx.append(tx)\n        block2.hashMerkleRoot = block2.calc_merkle_root()\n        block2.solve()\n        self.test_node.send_and_ping(msg_block(block2))\n        assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256)\n        self.utxos.extend([[tx.sha256, i, out_value] for i in range(10)])\n        return\n\n    # Test \"sendcmpct\" (between peers preferring the same version):\n    # - No compact block announcements unless sendcmpct is sent.\n    # - If sendcmpct is sent with version > preferred_version, the message is ignored.\n    # - If sendcmpct is sent with boolean 0, then block announcements are not\n    #   made with compact blocks.\n    # - If sendcmpct is then sent with boolean 1, then new block announcements\n    #   are made with compact blocks.\n    # If old_node is passed in, request compact blocks with version=preferred-1\n    # and verify that it receives block announcements via compact block.\n    def test_sendcmpct(self, node, test_node, preferred_version, old_node=None):\n        # Make sure we get a SENDCMPCT message from our peer\n        def received_sendcmpct():\n            return (len(test_node.last_sendcmpct) > 0)\n        wait_until(received_sendcmpct, timeout=30, lock=mininode_lock)\n        with mininode_lock:\n            # Check that the first version received is the preferred one\n            assert_equal(test_node.last_sendcmpct[0].version, preferred_version)\n            # And that we receive versions down to 1.\n            assert_equal(test_node.last_sendcmpct[-1].version, 1)\n            test_node.last_sendcmpct = []\n\n        tip = int(node.getbestblockhash(), 16)\n\n        def check_announcement_of_new_block(node, peer, predicate):\n            peer.clear_block_announcement()\n            block_hash = int(node.generate(1)[0], 16)\n            peer.wait_for_block_announcement(block_hash, timeout=30)\n            assert peer.block_announced\n\n            with mininode_lock:\n                assert predicate(peer), (\n                    \"block_hash={!r}, cmpctblock={!r}, inv={!r}\".format(\n                        block_hash, peer.last_message.get(\"cmpctblock\", None), peer.last_message.get(\"inv\", None)))\n\n        # We shouldn't get any block announcements via cmpctblock yet.\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" not in p.last_message)\n\n        # Try one more time, this time after requesting headers.\n        test_node.request_headers_and_sync(locator=[tip])\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" not in p.last_message and \"inv\" in p.last_message)\n\n        # Test a few ways of using sendcmpct that should NOT\n        # result in compact block announcements.\n        # Before each test, sync the headers chain.\n        test_node.request_headers_and_sync(locator=[tip])\n\n        # Now try a SENDCMPCT message with too-high version\n        sendcmpct = msg_sendcmpct()\n        sendcmpct.version = preferred_version + 1\n        sendcmpct.announce = True\n        test_node.send_and_ping(sendcmpct)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" not in p.last_message)\n\n        # Headers sync before next test.\n        test_node.request_headers_and_sync(locator=[tip])\n\n        # Now try a SENDCMPCT message with valid version, but announce=False\n        sendcmpct.version = preferred_version\n        sendcmpct.announce = False\n        test_node.send_and_ping(sendcmpct)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" not in p.last_message)\n\n        # Headers sync before next test.\n        test_node.request_headers_and_sync(locator=[tip])\n\n        # Finally, try a SENDCMPCT message with announce=True\n        sendcmpct.version = preferred_version\n        sendcmpct.announce = True\n        test_node.send_and_ping(sendcmpct)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" in p.last_message)\n\n        # Try one more time (no headers sync should be needed!)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" in p.last_message)\n\n        # Try one more time, after turning on sendheaders\n        test_node.send_and_ping(msg_sendheaders())\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" in p.last_message)\n\n        # Try one more time, after sending a version-1, announce=false message.\n        sendcmpct.version = preferred_version - 1\n        sendcmpct.announce = False\n        test_node.send_and_ping(sendcmpct)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" in p.last_message)\n\n        # Now turn off announcements\n        sendcmpct.version = preferred_version\n        sendcmpct.announce = False\n        test_node.send_and_ping(sendcmpct)\n        check_announcement_of_new_block(node, test_node, lambda p: \"cmpctblock\" not in p.last_message and \"headers\" in p.last_message)\n\n        if old_node is not None:\n            # Verify that a peer using an older protocol version can receive\n            # announcements from this node.\n            sendcmpct.version = preferred_version - 1\n            sendcmpct.announce = True\n            old_node.send_and_ping(sendcmpct)\n            # Header sync\n            old_node.request_headers_and_sync(locator=[tip])\n            check_announcement_of_new_block(node, old_node, lambda p: \"cmpctblock\" in p.last_message)\n\n    # This test actually causes Munt-daemon to (reasonably!) disconnect us, so do this last.\n    def test_invalid_cmpctblock_message(self):\n        self.nodes[0].generate(101)\n        block = self.build_block_on_tip(self.nodes[0])\n\n        cmpct_block = P2PHeaderAndShortIDs()\n        cmpct_block.header = CBlockHeader(block)\n        cmpct_block.prefilled_txn_length = 1\n        # This index will be too high\n        prefilled_txn = PrefilledTransaction(1, block.vtx[0])\n        cmpct_block.prefilled_txn = [prefilled_txn]\n        self.test_node.send_await_disconnect(msg_cmpctblock(cmpct_block))\n        assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)\n\n    # Compare the generated shortids to what we expect based on BIP 152, given\n    # Munt-daemon's choice of nonce.\n    def test_compactblock_construction(self, node, test_node, version, use_witness_address):\n        # Generate a bunch of transactions.\n        node.generate(101)\n        num_transactions = 25\n        address = node.getnewaddress()\n        if use_witness_address:\n            # Want at least one segwit spend, so move all funds to\n            # a witness address.\n            address = node.getnewaddress()\n            value_to_send = node.getbalance()\n            node.sendtoaddress(address, satoshi_round(value_to_send - Decimal(0.1)))\n            node.generate(1)\n\n        segwit_tx_generated = False\n        for i in range(num_transactions):\n            txid = node.sendtoaddress(address, 0.1)\n            hex_tx = node.gettransaction(txid)[\"hex\"]\n            tx = FromHex(CTransaction(), hex_tx)\n            if not tx.wit.is_null():\n                segwit_tx_generated = True\n\n        if use_witness_address:\n            assert segwit_tx_generated  # check that our test is not broken\n\n        # Wait until we've seen the block announcement for the resulting tip\n        tip = int(node.getbestblockhash(), 16)\n        test_node.wait_for_block_announcement(tip)\n\n        # Make sure we will receive a fast-announce compact block\n        self.request_cb_announcements(test_node, node, version)\n\n        # Now mine a block, and look at the resulting compact block.\n        test_node.clear_block_announcement()\n        block_hash = int(node.generate(1)[0], 16)\n\n        # Store the raw block in our internal format.\n        block = FromHex(CBlock(), node.getblock(\"%064x\" % block_hash, False))\n        for tx in block.vtx:\n            tx.calc_sha256()\n        block.rehash()\n\n        # Wait until the block was announced (via compact blocks)\n        wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)\n\n        # Now fetch and check the compact block\n        header_and_shortids = None\n        with mininode_lock:\n            assert \"cmpctblock\" in test_node.last_message\n            # Convert the on-the-wire representation to absolute indexes\n            header_and_shortids = HeaderAndShortIDs(test_node.last_message[\"cmpctblock\"].header_and_shortids)\n        self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)\n\n        # Now fetch the compact block using a normal non-announce getdata\n        with mininode_lock:\n            test_node.clear_block_announcement()\n            inv = CInv(4, block_hash)  # 4 == \"CompactBlock\"\n            test_node.send_message(msg_getdata([inv]))\n\n        wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)\n\n        # Now fetch and check the compact block\n        header_and_shortids = None\n        with mininode_lock:\n            assert \"cmpctblock\" in test_node.last_message\n            # Convert the on-the-wire representation to absolute indexes\n            header_and_shortids = HeaderAndShortIDs(test_node.last_message[\"cmpctblock\"].header_and_shortids)\n        self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)\n\n    def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):\n        # Check that we got the right block!\n        header_and_shortids.header.calc_sha256()\n        assert_equal(header_and_shortids.header.sha256, block_hash)\n\n        # Make sure the prefilled_txn appears to have included the coinbase\n        assert len(header_and_shortids.prefilled_txn) >= 1\n        assert_equal(header_and_shortids.prefilled_txn[0].index, 0)\n\n        # Check that all prefilled_txn entries match what's in the block.\n        for entry in header_and_shortids.prefilled_txn:\n            entry.tx.calc_sha256()\n            # This checks the non-witness parts of the tx agree\n            assert_equal(entry.tx.sha256, block.vtx[entry.index].sha256)\n\n            # And this checks the witness\n            wtxid = entry.tx.calc_sha256(True)\n            if version == 2:\n                assert_equal(wtxid, block.vtx[entry.index].calc_sha256(True))\n            else:\n                # Shouldn't have received a witness\n                assert entry.tx.wit.is_null()\n\n        # Check that the cmpctblock message announced all the transactions.\n        assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))\n\n        # And now check that all the shortids are as expected as well.\n        # Determine the siphash keys to use.\n        [k0, k1] = header_and_shortids.get_siphash_keys()\n\n        index = 0\n        while index < len(block.vtx):\n            if (len(header_and_shortids.prefilled_txn) > 0 and\n                    header_and_shortids.prefilled_txn[0].index == index):\n                # Already checked prefilled transactions above\n                header_and_shortids.prefilled_txn.pop(0)\n            else:\n                tx_hash = block.vtx[index].sha256\n                if version == 2:\n                    tx_hash = block.vtx[index].calc_sha256(True)\n                shortid = calculate_shortid(k0, k1, tx_hash)\n                assert_equal(shortid, header_and_shortids.shortids[0])\n                header_and_shortids.shortids.pop(0)\n            index += 1\n\n    # Test that Munt-daemon requests compact blocks when we announce new blocks\n    # via header or inv, and that responding to getblocktxn causes the block\n    # to be successfully reconstructed.\n    # Post-segwit: upgraded nodes would only make this request of cb-version-2,\n    # NODE_WITNESS peers.  Unupgraded nodes would still make this request of\n    # any cb-version-1-supporting peer.\n    def test_compactblock_requests(self, node, test_node, version, segwit):\n        # Try announcing a block with an inv or header, expect a compactblock\n        # request\n        for announce in [\"inv\", \"header\"]:\n            block = self.build_block_on_tip(node, segwit=segwit)\n            with mininode_lock:\n                test_node.last_message.pop(\"getdata\", None)\n\n            if announce == \"inv\":\n                test_node.send_message(msg_inv([CInv(2, block.sha256)]))\n                wait_until(lambda: \"getheaders\" in test_node.last_message, timeout=30, lock=mininode_lock)\n                test_node.send_header_for_blocks([block])\n            else:\n                test_node.send_header_for_blocks([block])\n            wait_until(lambda: \"getdata\" in test_node.last_message, timeout=30, lock=mininode_lock)\n            assert_equal(len(test_node.last_message[\"getdata\"].inv), 1)\n            assert_equal(test_node.last_message[\"getdata\"].inv[0].type, 4)\n            assert_equal(test_node.last_message[\"getdata\"].inv[0].hash, block.sha256)\n\n            # Send back a compactblock message that omits the coinbase\n            comp_block = HeaderAndShortIDs()\n            comp_block.header = CBlockHeader(block)\n            comp_block.nonce = 0\n            [k0, k1] = comp_block.get_siphash_keys()\n            coinbase_hash = block.vtx[0].sha256\n            if version == 2:\n                coinbase_hash = block.vtx[0].calc_sha256(True)\n            comp_block.shortids = [calculate_shortid(k0, k1, coinbase_hash)]\n            test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))\n            assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)\n            # Expect a getblocktxn message.\n            with mininode_lock:\n                assert \"getblocktxn\" in test_node.last_message\n                absolute_indexes = test_node.last_message[\"getblocktxn\"].block_txn_request.to_absolute()\n            assert_equal(absolute_indexes, [0])  # should be a coinbase request\n\n            # Send the coinbase, and verify that the tip advances.\n            if version == 2:\n                msg = msg_witness_blocktxn()\n            else:\n                msg = msg_blocktxn()\n            msg.block_transactions.blockhash = block.sha256\n            msg.block_transactions.transactions = [block.vtx[0]]\n            test_node.send_and_ping(msg)\n            assert_equal(int(node.getbestblockhash(), 16), block.sha256)\n\n    # Create a chain of transactions from given utxo, and add to a new block.\n    def build_block_with_transactions(self, node, utxo, num_transactions):\n        block = self.build_block_on_tip(node)\n\n        for i in range(num_transactions):\n            tx = CTransaction()\n            tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))\n            tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n            tx.rehash()\n            utxo = [tx.sha256, 0, tx.vout[0].nValue]\n            block.vtx.append(tx)\n\n        block.hashMerkleRoot = block.calc_merkle_root()\n        block.solve()\n        return block\n\n    # Test that we only receive getblocktxn requests for transactions that the\n    # node needs, and that responding to them causes the block to be\n    # reconstructed.\n    def test_getblocktxn_requests(self, node, test_node, version):\n        with_witness = (version == 2)\n\n        def test_getblocktxn_response(compact_block, peer, expected_result):\n            msg = msg_cmpctblock(compact_block.to_p2p())\n            peer.send_and_ping(msg)\n            with mininode_lock:\n                assert \"getblocktxn\" in peer.last_message\n                absolute_indexes = peer.last_message[\"getblocktxn\"].block_txn_request.to_absolute()\n            assert_equal(absolute_indexes, expected_result)\n\n        def test_tip_after_message(node, peer, msg, tip):\n            peer.send_and_ping(msg)\n            assert_equal(int(node.getbestblockhash(), 16), tip)\n\n        # First try announcing compactblocks that won't reconstruct, and verify\n        # that we receive getblocktxn messages back.\n        utxo = self.utxos.pop(0)\n\n        block = self.build_block_with_transactions(node, utxo, 5)\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n        comp_block = HeaderAndShortIDs()\n        comp_block.initialize_from_block(block, use_witness=with_witness)\n\n        test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5])\n\n        msg_bt = msg_blocktxn()\n        if with_witness:\n            msg_bt = msg_witness_blocktxn()  # serialize with witnesses\n        msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:])\n        test_tip_after_message(node, test_node, msg_bt, block.sha256)\n\n        utxo = self.utxos.pop(0)\n        block = self.build_block_with_transactions(node, utxo, 5)\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n\n        # Now try interspersing the prefilled transactions\n        comp_block.initialize_from_block(block, prefill_list=[0, 1, 5], use_witness=with_witness)\n        test_getblocktxn_response(comp_block, test_node, [2, 3, 4])\n        msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[2:5])\n        test_tip_after_message(node, test_node, msg_bt, block.sha256)\n\n        # Now try giving one transaction ahead of time.\n        utxo = self.utxos.pop(0)\n        block = self.build_block_with_transactions(node, utxo, 5)\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n        test_node.send_and_ping(msg_tx(block.vtx[1]))\n        assert block.vtx[1].hash in node.getrawmempool()\n\n        # Prefill 4 out of the 6 transactions, and verify that only the one\n        # that was not in the mempool is requested.\n        comp_block.initialize_from_block(block, prefill_list=[0, 2, 3, 4], use_witness=with_witness)\n        test_getblocktxn_response(comp_block, test_node, [5])\n\n        msg_bt.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]])\n        test_tip_after_message(node, test_node, msg_bt, block.sha256)\n\n        # Now provide all transactions to the node before the block is\n        # announced and verify reconstruction happens immediately.\n        utxo = self.utxos.pop(0)\n        block = self.build_block_with_transactions(node, utxo, 10)\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n        for tx in block.vtx[1:]:\n            test_node.send_message(msg_tx(tx))\n        test_node.sync_with_ping()\n        # Make sure all transactions were accepted.\n        mempool = node.getrawmempool()\n        for tx in block.vtx[1:]:\n            assert tx.hash in mempool\n\n        # Clear out last request.\n        with mininode_lock:\n            test_node.last_message.pop(\"getblocktxn\", None)\n\n        # Send compact block\n        comp_block.initialize_from_block(block, prefill_list=[0], use_witness=with_witness)\n        test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)\n        with mininode_lock:\n            # Shouldn't have gotten a request for any transaction\n            assert \"getblocktxn\" not in test_node.last_message\n\n    # Incorrectly responding to a getblocktxn shouldn't cause the block to be\n    # permanently failed.\n    def test_incorrect_blocktxn_response(self, node, test_node, version):\n        if (len(self.utxos) == 0):\n            self.make_utxos()\n        utxo = self.utxos.pop(0)\n\n        block = self.build_block_with_transactions(node, utxo, 10)\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n        # Relay the first 5 transactions from the block in advance\n        for tx in block.vtx[1:6]:\n            test_node.send_message(msg_tx(tx))\n        test_node.sync_with_ping()\n        # Make sure all transactions were accepted.\n        mempool = node.getrawmempool()\n        for tx in block.vtx[1:6]:\n            assert tx.hash in mempool\n\n        # Send compact block\n        comp_block = HeaderAndShortIDs()\n        comp_block.initialize_from_block(block, prefill_list=[0], use_witness=(version == 2))\n        test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))\n        absolute_indexes = []\n        with mininode_lock:\n            assert \"getblocktxn\" in test_node.last_message\n            absolute_indexes = test_node.last_message[\"getblocktxn\"].block_txn_request.to_absolute()\n        assert_equal(absolute_indexes, [6, 7, 8, 9, 10])\n\n        # Now give an incorrect response.\n        # Note that it's possible for Munt-daemon to be smart enough to know we're\n        # lying, since it could check to see if the shortid matches what we're\n        # sending, and eg disconnect us for misbehavior.  If that behavior\n        # change was made, we could just modify this test by having a\n        # different peer provide the block further down, so that we're still\n        # verifying that the block isn't marked bad permanently. This is good\n        # enough for now.\n        msg = msg_blocktxn()\n        if version == 2:\n            msg = msg_witness_blocktxn()\n        msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:])\n        test_node.send_and_ping(msg)\n\n        # Tip should not have updated\n        assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)\n\n        # We should receive a getdata request\n        wait_until(lambda: \"getdata\" in test_node.last_message, timeout=10, lock=mininode_lock)\n        assert_equal(len(test_node.last_message[\"getdata\"].inv), 1)\n        assert test_node.last_message[\"getdata\"].inv[0].type == 2 or test_node.last_message[\"getdata\"].inv[0].type == 2 | MSG_WITNESS_FLAG\n        assert_equal(test_node.last_message[\"getdata\"].inv[0].hash, block.sha256)\n\n        # Deliver the block\n        if version == 2:\n            test_node.send_and_ping(msg_witness_block(block))\n        else:\n            test_node.send_and_ping(msg_block(block))\n        assert_equal(int(node.getbestblockhash(), 16), block.sha256)\n\n    def test_getblocktxn_handler(self, node, test_node, version):\n        # Munt-daemon will not send blocktxn responses for blocks whose height is\n        # more than 10 blocks deep.\n        MAX_GETBLOCKTXN_DEPTH = 10\n        chain_height = node.getblockcount()\n        current_height = chain_height\n        while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH):\n            block_hash = node.getblockhash(current_height)\n            block = FromHex(CBlock(), node.getblock(block_hash, False))\n\n            msg = msg_getblocktxn()\n            msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [])\n            num_to_request = random.randint(1, len(block.vtx))\n            msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))\n            test_node.send_message(msg)\n            wait_until(lambda: \"blocktxn\" in test_node.last_message, timeout=10, lock=mininode_lock)\n\n            [tx.calc_sha256() for tx in block.vtx]\n            with mininode_lock:\n                assert_equal(test_node.last_message[\"blocktxn\"].block_transactions.blockhash, int(block_hash, 16))\n                all_indices = msg.block_txn_request.to_absolute()\n                for index in all_indices:\n                    tx = test_node.last_message[\"blocktxn\"].block_transactions.transactions.pop(0)\n                    tx.calc_sha256()\n                    assert_equal(tx.sha256, block.vtx[index].sha256)\n                    if version == 1:\n                        # Witnesses should have been stripped\n                        assert tx.wit.is_null()\n                    else:\n                        # Check that the witness matches\n                        assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True))\n                test_node.last_message.pop(\"blocktxn\", None)\n            current_height -= 1\n\n        # Next request should send a full block response, as we're past the\n        # allowed depth for a blocktxn response.\n        block_hash = node.getblockhash(current_height)\n        msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])\n        with mininode_lock:\n            test_node.last_message.pop(\"block\", None)\n            test_node.last_message.pop(\"blocktxn\", None)\n        test_node.send_and_ping(msg)\n        with mininode_lock:\n            test_node.last_message[\"block\"].block.calc_sha256()\n            assert_equal(test_node.last_message[\"block\"].block.sha256, int(block_hash, 16))\n            assert \"blocktxn\" not in test_node.last_message\n\n    def test_compactblocks_not_at_tip(self, node, test_node):\n        # Test that requesting old compactblocks doesn't work.\n        MAX_CMPCTBLOCK_DEPTH = 5\n        new_blocks = []\n        for i in range(MAX_CMPCTBLOCK_DEPTH + 1):\n            test_node.clear_block_announcement()\n            new_blocks.append(node.generate(1)[0])\n            wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)\n\n        test_node.clear_block_announcement()\n        test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))\n        wait_until(lambda: \"cmpctblock\" in test_node.last_message, timeout=30, lock=mininode_lock)\n\n        test_node.clear_block_announcement()\n        node.generate(1)\n        wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)\n        test_node.clear_block_announcement()\n        with mininode_lock:\n            test_node.last_message.pop(\"block\", None)\n        test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))\n        wait_until(lambda: \"block\" in test_node.last_message, timeout=30, lock=mininode_lock)\n        with mininode_lock:\n            test_node.last_message[\"block\"].block.calc_sha256()\n            assert_equal(test_node.last_message[\"block\"].block.sha256, int(new_blocks[0], 16))\n\n        # Generate an old compactblock, and verify that it's not accepted.\n        cur_height = node.getblockcount()\n        hashPrevBlock = int(node.getblockhash(cur_height - 5), 16)\n        block = self.build_block_on_tip(node)\n        block.hashPrevBlock = hashPrevBlock\n        block.solve()\n\n        comp_block = HeaderAndShortIDs()\n        comp_block.initialize_from_block(block)\n        test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))\n\n        tips = node.getchaintips()\n        found = False\n        for x in tips:\n            if x[\"hash\"] == block.hash:\n                assert_equal(x[\"status\"], \"headers-only\")\n                found = True\n                break\n        assert found\n\n        # Requesting this block via getblocktxn should silently fail\n        # (to avoid fingerprinting attacks).\n        msg = msg_getblocktxn()\n        msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0])\n        with mininode_lock:\n            test_node.last_message.pop(\"blocktxn\", None)\n        test_node.send_and_ping(msg)\n        with mininode_lock:\n            assert \"blocktxn\" not in test_node.last_message\n\n    def activate_segwit(self, node):\n        node.generate(144 * 3)\n        assert_equal(get_bip9_status(node, \"segwit\")[\"status\"], 'active')\n\n    def test_end_to_end_block_relay(self, node, listeners):\n        utxo = self.utxos.pop(0)\n\n        block = self.build_block_with_transactions(node, utxo, 10)\n\n        [l.clear_block_announcement() for l in listeners]\n\n        # ToHex() won't serialize with witness, but this block has no witnesses\n        # anyway. TODO: repeat this test with witness tx's to a segwit node.\n        node.submitblock(ToHex(block))\n\n        for l in listeners:\n            wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock)\n        with mininode_lock:\n            for l in listeners:\n                assert \"cmpctblock\" in l.last_message\n                l.last_message[\"cmpctblock\"].header_and_shortids.header.calc_sha256()\n                assert_equal(l.last_message[\"cmpctblock\"].header_and_shortids.header.sha256, block.sha256)\n\n    # Test that we don't get disconnected if we relay a compact block with valid header,\n    # but invalid transactions.\n    def test_invalid_tx_in_compactblock(self, node, test_node, use_segwit):\n        assert len(self.utxos)\n        utxo = self.utxos[0]\n\n        block = self.build_block_with_transactions(node, utxo, 5)\n        del block.vtx[3]\n        block.hashMerkleRoot = block.calc_merkle_root()\n        if use_segwit:\n            # If we're testing with segwit, also drop the coinbase witness,\n            # but include the witness commitment.\n            add_witness_commitment(block)\n            block.vtx[0].wit.vtxinwit = []\n        block.solve()\n\n        # Now send the compact block with all transactions prefilled, and\n        # verify that we don't get disconnected.\n        comp_block = HeaderAndShortIDs()\n        comp_block.initialize_from_block(block, prefill_list=[0, 1, 2, 3, 4], use_witness=use_segwit)\n        msg = msg_cmpctblock(comp_block.to_p2p())\n        test_node.send_and_ping(msg)\n\n        # Check that the tip didn't advance\n        assert int(node.getbestblockhash(), 16) is not block.sha256\n        test_node.sync_with_ping()\n\n    # Helper for enabling cb announcements\n    # Send the sendcmpct request and sync headers\n    def request_cb_announcements(self, peer, node, version):\n        tip = node.getbestblockhash()\n        peer.get_headers(locator=[int(tip, 16)], hashstop=0)\n\n        msg = msg_sendcmpct()\n        msg.version = version\n        msg.announce = True\n        peer.send_and_ping(msg)\n\n    def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer):\n        assert len(self.utxos)\n\n        def announce_cmpct_block(node, peer):\n            utxo = self.utxos.pop(0)\n            block = self.build_block_with_transactions(node, utxo, 5)\n\n            cmpct_block = HeaderAndShortIDs()\n            cmpct_block.initialize_from_block(block)\n            msg = msg_cmpctblock(cmpct_block.to_p2p())\n            peer.send_and_ping(msg)\n            with mininode_lock:\n                assert \"getblocktxn\" in peer.last_message\n            return block, cmpct_block\n\n        block, cmpct_block = announce_cmpct_block(node, stalling_peer)\n\n        for tx in block.vtx[1:]:\n            delivery_peer.send_message(msg_tx(tx))\n        delivery_peer.sync_with_ping()\n        mempool = node.getrawmempool()\n        for tx in block.vtx[1:]:\n            assert tx.hash in mempool\n\n        delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))\n        assert_equal(int(node.getbestblockhash(), 16), block.sha256)\n\n        self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])\n\n        # Now test that delivering an invalid compact block won't break relay\n\n        block, cmpct_block = announce_cmpct_block(node, stalling_peer)\n        for tx in block.vtx[1:]:\n            delivery_peer.send_message(msg_tx(tx))\n        delivery_peer.sync_with_ping()\n\n        cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()]\n        cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]\n\n        cmpct_block.use_witness = True\n        delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))\n        assert int(node.getbestblockhash(), 16) != block.sha256\n\n        msg = msg_blocktxn()\n        msg.block_transactions.blockhash = block.sha256\n        msg.block_transactions.transactions = block.vtx[1:]\n        stalling_peer.send_and_ping(msg)\n        assert_equal(int(node.getbestblockhash(), 16), block.sha256)\n\n    def run_test(self):\n        # Setup the p2p connections\n        self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())\n        self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)\n        self.old_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)\n\n        # We will need UTXOs to construct transactions in later tests.\n        self.make_utxos()\n\n        self.log.info(\"Running tests, pre-segwit activation:\")\n\n        self.log.info(\"Testing SENDCMPCT p2p message... \")\n        self.test_sendcmpct(self.nodes[0], self.test_node, 1)\n        sync_blocks(self.nodes)\n        self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing compactblock construction...\")\n        self.test_compactblock_construction(self.nodes[0], self.test_node, 1, False)\n        sync_blocks(self.nodes)\n        self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, False)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing compactblock requests... \")\n        self.test_compactblock_requests(self.nodes[0], self.test_node, 1, False)\n        sync_blocks(self.nodes)\n        self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, False)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing getblocktxn requests...\")\n        self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)\n        sync_blocks(self.nodes)\n        self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing getblocktxn handler...\")\n        self.test_getblocktxn_handler(self.nodes[0], self.test_node, 1)\n        sync_blocks(self.nodes)\n        self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)\n        self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing compactblock requests/announcements not at chain tip...\")\n        self.test_compactblocks_not_at_tip(self.nodes[0], self.test_node)\n        sync_blocks(self.nodes)\n        self.test_compactblocks_not_at_tip(self.nodes[1], self.segwit_node)\n        self.test_compactblocks_not_at_tip(self.nodes[1], self.old_node)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing handling of incorrect blocktxn responses...\")\n        self.test_incorrect_blocktxn_response(self.nodes[0], self.test_node, 1)\n        sync_blocks(self.nodes)\n        self.test_incorrect_blocktxn_response(self.nodes[1], self.segwit_node, 2)\n        sync_blocks(self.nodes)\n\n        # End-to-end block relay tests\n        self.log.info(\"Testing end-to-end block relay...\")\n        self.request_cb_announcements(self.test_node, self.nodes[0], 1)\n        self.request_cb_announcements(self.old_node, self.nodes[1], 1)\n        self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)\n        self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node])\n        self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])\n\n        self.log.info(\"Testing handling of invalid compact blocks...\")\n        self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)\n        self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)\n        self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)\n\n        self.log.info(\"Testing reconstructing compact blocks from all peers...\")\n        self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)\n        sync_blocks(self.nodes)\n\n        # Advance to segwit activation\n        self.log.info(\"Advancing to segwit activation\")\n        self.activate_segwit(self.nodes[1])\n        self.log.info(\"Running tests, post-segwit activation...\")\n\n        self.log.info(\"Testing compactblock construction...\")\n        self.test_compactblock_construction(self.nodes[1], self.old_node, 1, True)\n        self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, True)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing compactblock requests (unupgraded node)... \")\n        self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True)\n\n        self.log.info(\"Testing getblocktxn requests (unupgraded node)...\")\n        self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)\n\n        # Need to manually sync node0 and node1, because post-segwit activation,\n        # node1 will not download blocks from node0.\n        self.log.info(\"Syncing nodes...\")\n        assert self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()\n        while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):\n            block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount() + 1)\n            self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))\n        assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())\n\n        self.log.info(\"Testing compactblock requests (segwit node)... \")\n        self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True)\n\n        self.log.info(\"Testing getblocktxn requests (segwit node)...\")\n        self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)\n        sync_blocks(self.nodes)\n\n        self.log.info(\"Testing getblocktxn handler (segwit node should return witnesses)...\")\n        self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)\n        self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)\n\n        # Test that if we submitblock to node1, we'll get a compact block\n        # announcement to all peers.\n        # (Post-segwit activation, blocks won't propagate from node0 to node1\n        # automatically, so don't bother testing a block announced to node0.)\n        self.log.info(\"Testing end-to-end block relay...\")\n        self.request_cb_announcements(self.test_node, self.nodes[0], 1)\n        self.request_cb_announcements(self.old_node, self.nodes[1], 1)\n        self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)\n        self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])\n\n        self.log.info(\"Testing handling of invalid compact blocks...\")\n        self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)\n        self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True)\n        self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True)\n\n        self.log.info(\"Testing invalid index in cmpctblock message...\")\n        self.test_invalid_cmpctblock_message()\n\n\nif __name__ == '__main__':\n    CompactBlocksTest().main()\n"
  },
  {
    "path": "test/functional/p2p_disconnect_ban.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test node disconnect and ban behavior\"\"\"\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n    wait_until,\n)\n\nclass DisconnectBanTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def run_test(self):\n        self.log.info(\"Test setban and listbanned RPCs\")\n\n        self.log.info(\"setban: successfully ban single IP address\")\n        assert_equal(len(self.nodes[1].getpeerinfo()), 2)  # node1 should have 2 connections to node0 at this point\n        self.nodes[1].setban(subnet=\"127.0.0.1\", command=\"add\")\n        wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)\n        assert_equal(len(self.nodes[1].getpeerinfo()), 0)  # all nodes must be disconnected at this point\n        assert_equal(len(self.nodes[1].listbanned()), 1)\n\n        self.log.info(\"clearbanned: successfully clear ban list\")\n        self.nodes[1].clearbanned()\n        assert_equal(len(self.nodes[1].listbanned()), 0)\n        self.nodes[1].setban(\"127.0.0.0/24\", \"add\")\n\n        self.log.info(\"setban: fail to ban an already banned subnet\")\n        assert_equal(len(self.nodes[1].listbanned()), 1)\n        assert_raises_rpc_error(-23, \"IP/Subnet already banned\", self.nodes[1].setban, \"127.0.0.1\", \"add\")\n\n        self.log.info(\"setban: fail to ban an invalid subnet\")\n        assert_raises_rpc_error(-30, \"Error: Invalid IP/Subnet\", self.nodes[1].setban, \"127.0.0.1/42\", \"add\")\n        assert_equal(len(self.nodes[1].listbanned()), 1)  # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24\n\n        self.log.info(\"setban remove: fail to unban a non-banned subnet\")\n        assert_raises_rpc_error(-30, \"Error: Unban failed\", self.nodes[1].setban, \"127.0.0.1\", \"remove\")\n        assert_equal(len(self.nodes[1].listbanned()), 1)\n\n        self.log.info(\"setban remove: successfully unban subnet\")\n        self.nodes[1].setban(\"127.0.0.0/24\", \"remove\")\n        assert_equal(len(self.nodes[1].listbanned()), 0)\n        self.nodes[1].clearbanned()\n        assert_equal(len(self.nodes[1].listbanned()), 0)\n\n        self.log.info(\"setban: test persistence across node restart\")\n        self.nodes[1].setban(\"127.0.0.0/32\", \"add\")\n        self.nodes[1].setban(\"127.0.0.0/24\", \"add\")\n        # Set the mocktime so we can control when bans expire\n        old_time = int(time.time())\n        self.nodes[1].setmocktime(old_time)\n        self.nodes[1].setban(\"192.168.0.1\", \"add\", 1)  # ban for 1 seconds\n        self.nodes[1].setban(\"2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19\", \"add\", 1000)  # ban for 1000 seconds\n        listBeforeShutdown = self.nodes[1].listbanned()\n        assert_equal(\"192.168.0.1/32\", listBeforeShutdown[2]['address'])\n        # Move time forward by 3 seconds so the third ban has expired\n        self.nodes[1].setmocktime(old_time + 3)\n        assert_equal(len(self.nodes[1].listbanned()), 3)\n\n        self.stop_node(1)\n        self.start_node(1)\n\n        listAfterShutdown = self.nodes[1].listbanned()\n        assert_equal(\"127.0.0.0/24\", listAfterShutdown[0]['address'])\n        assert_equal(\"127.0.0.0/32\", listAfterShutdown[1]['address'])\n        assert_equal(\"/19\" in listAfterShutdown[2]['address'], True)\n\n        # Clear ban lists\n        self.nodes[1].clearbanned()\n        connect_nodes_bi(self.nodes, 0, 1)\n\n        self.log.info(\"Test disconnectnode RPCs\")\n\n        self.log.info(\"disconnectnode: fail to disconnect when calling with address and nodeid\")\n        address1 = self.nodes[0].getpeerinfo()[0]['addr']\n        node1 = self.nodes[0].getpeerinfo()[0]['addr']\n        assert_raises_rpc_error(-32602, \"Only one of address and nodeid should be provided.\", self.nodes[0].disconnectnode, address=address1, node_id=node1)\n\n        self.log.info(\"disconnectnode: fail to disconnect when calling with junk address\")\n        assert_raises_rpc_error(-29, \"Node not found in connected nodes\", self.nodes[0].disconnectnode, address=\"221B Baker Street\")\n\n        self.log.info(\"disconnectnode: successfully disconnect node by address\")\n        address1 = self.nodes[0].getpeerinfo()[0]['addr']\n        self.nodes[0].disconnectnode(address=address1)\n        wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)\n        assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]\n\n        self.log.info(\"disconnectnode: successfully reconnect node\")\n        connect_nodes_bi(self.nodes, 0, 1)  # reconnect the node\n        assert_equal(len(self.nodes[0].getpeerinfo()), 2)\n        assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]\n\n        self.log.info(\"disconnectnode: successfully disconnect node by node id\")\n        id1 = self.nodes[0].getpeerinfo()[0]['id']\n        self.nodes[0].disconnectnode(node_id=id1)\n        wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)\n        assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]\n\nif __name__ == '__main__':\n    DisconnectBanTest().main()\n"
  },
  {
    "path": "test/functional/p2p_feefilter.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test processing of feefilter messages.\"\"\"\n\nfrom decimal import Decimal\nimport time\n\nfrom test_framework.messages import msg_feefilter\nfrom test_framework.mininode import mininode_lock, P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import sync_blocks, sync_mempools\n\ndef hashToHex(hash):\n    return format(hash, '064x')\n\n# Wait up to 60 secs to see if the testnode has received all the expected invs\ndef allInvsMatch(invsExpected, testnode):\n    for x in range(60):\n        with mininode_lock:\n            if (sorted(invsExpected) == sorted(testnode.txinvs)):\n                return True\n        time.sleep(1)\n    return False\n\nclass TestP2PConn(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.txinvs = []\n\n    def on_inv(self, message):\n        for i in message.inv:\n            if (i.type == 1):\n                self.txinvs.append(hashToHex(i.hash))\n\n    def clear_invs(self):\n        with mininode_lock:\n            self.txinvs = []\n\nclass FeeFilterTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        node1 = self.nodes[1]\n        node0 = self.nodes[0]\n        # Get out of IBD\n        node1.generate(1)\n        sync_blocks(self.nodes)\n\n        self.nodes[0].add_p2p_connection(TestP2PConn())\n\n        # Test that invs are received for all txs at feerate of 20 sat/byte\n        node1.settxfee(Decimal(\"0.00020000\"))\n        txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]\n        assert allInvsMatch(txids, self.nodes[0].p2p)\n        self.nodes[0].p2p.clear_invs()\n\n        # Set a filter of 15 sat/byte\n        self.nodes[0].p2p.send_and_ping(msg_feefilter(15000))\n\n        # Test that txs are still being received (paying 20 sat/byte)\n        txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]\n        assert allInvsMatch(txids, self.nodes[0].p2p)\n        self.nodes[0].p2p.clear_invs()\n\n        # Change tx fee rate to 10 sat/byte and test they are no longer received\n        node1.settxfee(Decimal(\"0.00010000\"))\n        [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]\n        sync_mempools(self.nodes) # must be sure node 0 has received all txs\n\n        # Send one transaction from node0 that should be received, so that we\n        # we can sync the test on receipt (if node1's txs were relayed, they'd\n        # be received by the time this node0 tx is received). This is\n        # unfortunately reliant on the current relay behavior where we batch up\n        # to 35 entries in an inv, which means that when this next transaction\n        # is eligible for relay, the prior transactions from node1 are eligible\n        # as well.\n        node0.settxfee(Decimal(\"0.00020000\"))\n        txids = [node0.sendtoaddress(node0.getnewaddress(), 1)]\n        assert allInvsMatch(txids, self.nodes[0].p2p)\n        self.nodes[0].p2p.clear_invs()\n\n        # Remove fee filter and check that txs are received again\n        self.nodes[0].p2p.send_and_ping(msg_feefilter(0))\n        txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]\n        assert allInvsMatch(txids, self.nodes[0].p2p)\n        self.nodes[0].p2p.clear_invs()\n\nif __name__ == '__main__':\n    FeeFilterTest().main()\n"
  },
  {
    "path": "test/functional/p2p_fingerprint.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test various fingerprinting protections.\n\nIf a stale block more than a month old or its header are requested by a peer,\nthe node should pretend that it does not have it to avoid fingerprinting.\n\"\"\"\n\nimport time\n\nfrom test_framework.blocktools import (create_block, create_coinbase)\nfrom test_framework.messages import CInv\nfrom test_framework.mininode import (\n    P2PInterface,\n    msg_headers,\n    msg_block,\n    msg_getdata,\n    msg_getheaders,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    wait_until,\n)\n\nclass P2PFingerprintTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    # Build a chain of blocks on top of given one\n    def build_chain(self, num_blocks, prev_hash, prev_height, prev_median_time):\n        blocks = []\n        for _ in range(num_blocks):\n            coinbase = create_coinbase(prev_height + 1)\n            block_time = prev_median_time + 1\n            block = create_block(int(prev_hash, 16), coinbase, block_time)\n            block.solve()\n\n            blocks.append(block)\n            prev_hash = block.hash\n            prev_height += 1\n            prev_median_time = block_time\n        return blocks\n\n    # Send a getdata request for a given block hash\n    def send_block_request(self, block_hash, node):\n        msg = msg_getdata()\n        msg.inv.append(CInv(2, block_hash))  # 2 == \"Block\"\n        node.send_message(msg)\n\n    # Send a getheaders request for a given single block hash\n    def send_header_request(self, block_hash, node):\n        msg = msg_getheaders()\n        msg.hashstop = block_hash\n        node.send_message(msg)\n\n    # Check whether last block received from node has a given hash\n    def last_block_equals(self, expected_hash, node):\n        block_msg = node.last_message.get(\"block\")\n        return block_msg and block_msg.block.rehash() == expected_hash\n\n    # Check whether last block header received from node has a given hash\n    def last_header_equals(self, expected_hash, node):\n        headers_msg = node.last_message.get(\"headers\")\n        return (headers_msg and\n                headers_msg.headers and\n                headers_msg.headers[0].rehash() == expected_hash)\n\n    # Checks that stale blocks timestamped more than a month ago are not served\n    # by the node while recent stale blocks and old active chain blocks are.\n    # This does not currently test that stale blocks timestamped within the\n    # last month but that have over a month's worth of work are also withheld.\n    def run_test(self):\n        node0 = self.nodes[0].add_p2p_connection(P2PInterface())\n\n        # Set node time to 60 days ago\n        self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 60)\n\n        # Generating a chain of 10 blocks\n        block_hashes = self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)\n\n        # Create longer chain starting 2 blocks before current tip\n        height = len(block_hashes) - 2\n        block_hash = block_hashes[height - 1]\n        block_time = self.nodes[0].getblockheader(block_hash)[\"mediantime\"] + 1\n        new_blocks = self.build_chain(5, block_hash, height, block_time)\n\n        # Force reorg to a longer chain\n        node0.send_message(msg_headers(new_blocks))\n        node0.wait_for_getdata()\n        for block in new_blocks:\n            node0.send_and_ping(msg_block(block))\n\n        # Check that reorg succeeded\n        assert_equal(self.nodes[0].getblockcount(), 13)\n\n        stale_hash = int(block_hashes[-1], 16)\n\n        # Check that getdata request for stale block succeeds\n        self.send_block_request(stale_hash, node0)\n        test_function = lambda: self.last_block_equals(stale_hash, node0)\n        wait_until(test_function, timeout=3)\n\n        # Check that getheader request for stale block header succeeds\n        self.send_header_request(stale_hash, node0)\n        test_function = lambda: self.last_header_equals(stale_hash, node0)\n        wait_until(test_function, timeout=3)\n\n        # Longest chain is extended so stale is much older than chain tip\n        self.nodes[0].setmocktime(0)\n        tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]\n        assert_equal(self.nodes[0].getblockcount(), 14)\n\n        # Send getdata & getheaders to refresh last received getheader message\n        block_hash = int(tip, 16)\n        self.send_block_request(block_hash, node0)\n        self.send_header_request(block_hash, node0)\n        node0.sync_with_ping()\n\n        # Request for very old stale block should now fail\n        self.send_block_request(stale_hash, node0)\n        time.sleep(3)\n        assert not self.last_block_equals(stale_hash, node0)\n\n        # Request for very old stale block header should now fail\n        self.send_header_request(stale_hash, node0)\n        time.sleep(3)\n        assert not self.last_header_equals(stale_hash, node0)\n\n        # Verify we can fetch very old blocks and headers on the active chain\n        block_hash = int(block_hashes[2], 16)\n        self.send_block_request(block_hash, node0)\n        self.send_header_request(block_hash, node0)\n        node0.sync_with_ping()\n\n        self.send_block_request(block_hash, node0)\n        test_function = lambda: self.last_block_equals(block_hash, node0)\n        wait_until(test_function, timeout=3)\n\n        self.send_header_request(block_hash, node0)\n        test_function = lambda: self.last_header_equals(block_hash, node0)\n        wait_until(test_function, timeout=3)\n\nif __name__ == '__main__':\n    P2PFingerprintTest().main()\n"
  },
  {
    "path": "test/functional/p2p_invalid_block.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test node responses to invalid blocks.\n\nIn this test we connect to one node over p2p, and test block requests:\n1) Valid blocks should be requested and become chain tip.\n2) Invalid block with duplicated transaction should be re-requested.\n3) Invalid block with bad coinbase value should be rejected and not\nre-requested.\n\"\"\"\nimport copy\n\nfrom test_framework.blocktools import create_block, create_coinbase, create_tx_with_script\nfrom test_framework.messages import COIN\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass InvalidBlockRequestTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n        self.extra_args = [[\"-whitelist=127.0.0.1\"]]\n\n    def run_test(self):\n        # Add p2p connection to node0\n        node = self.nodes[0]  # convenience reference to the node\n        node.add_p2p_connection(P2PDataStore())\n\n        best_block = node.getblock(node.getbestblockhash())\n        tip = int(node.getbestblockhash(), 16)\n        height = best_block[\"height\"] + 1\n        block_time = best_block[\"time\"] + 1\n\n        self.log.info(\"Create a new block with an anyone-can-spend coinbase\")\n\n        height = 1\n        block = create_block(tip, create_coinbase(height), block_time)\n        block.solve()\n        # Save the coinbase for later\n        block1 = block\n        tip = block.sha256\n        node.p2p.send_blocks_and_test([block1], node, success=True)\n\n        self.log.info(\"Mature the block.\")\n        node.generatetoaddress(100, node.get_deterministic_priv_key().address)\n\n        best_block = node.getblock(node.getbestblockhash())\n        tip = int(node.getbestblockhash(), 16)\n        height = best_block[\"height\"] + 1\n        block_time = best_block[\"time\"] + 1\n\n        # Use merkle-root malleability to generate an invalid block with\n        # same blockheader.\n        # Manufacture a block with 3 transactions (coinbase, spend of prior\n        # coinbase, spend of that spend).  Duplicate the 3rd transaction to\n        # leave merkle root and blockheader unchanged but invalidate the block.\n        self.log.info(\"Test merkle root malleability.\")\n\n        block2 = create_block(tip, create_coinbase(height), block_time)\n        block_time += 1\n\n        # b'0x51' is OP_TRUE\n        tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\\x51', amount=50 * COIN)\n        tx2 = create_tx_with_script(tx1, 0, script_sig=b'\\x51', amount=50 * COIN)\n\n        block2.vtx.extend([tx1, tx2])\n        block2.hashMerkleRoot = block2.calc_merkle_root()\n        block2.rehash()\n        block2.solve()\n        orig_hash = block2.sha256\n        block2_orig = copy.deepcopy(block2)\n\n        # Mutate block 2\n        block2.vtx.append(tx2)\n        assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root())\n        assert_equal(orig_hash, block2.rehash())\n        assert block2_orig.vtx != block2.vtx\n\n        node.p2p.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate')\n\n        # Check transactions for duplicate inputs\n        self.log.info(\"Test duplicate input block.\")\n\n        block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0])\n        block2_orig.vtx[2].rehash()\n        block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root()\n        block2_orig.rehash()\n        block2_orig.solve()\n        node.p2p.send_blocks_and_test([block2_orig], node, success=False, reject_reason='bad-txns-inputs-duplicate')\n\n        self.log.info(\"Test very broken block.\")\n\n        block3 = create_block(tip, create_coinbase(height), block_time)\n        block_time += 1\n        block3.vtx[0].vout[0].nValue = 100 * COIN  # Too high!\n        block3.vtx[0].sha256 = None\n        block3.vtx[0].calc_sha256()\n        block3.hashMerkleRoot = block3.calc_merkle_root()\n        block3.rehash()\n        block3.solve()\n\n        node.p2p.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')\n\n\nif __name__ == '__main__':\n    InvalidBlockRequestTest().main()\n"
  },
  {
    "path": "test/functional/p2p_invalid_locator.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test node responses to invalid locators.\n\"\"\"\n\nfrom test_framework.messages import msg_getheaders, msg_getblocks, MAX_LOCATOR_SZ\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\n\n\nclass InvalidLocatorTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = False\n\n    def run_test(self):\n        node = self.nodes[0]  # convenience reference to the node\n        node.generatetoaddress(1, node.get_deterministic_priv_key().address)  # Get node out of IBD\n\n        self.log.info('Test max locator size')\n        block_count = node.getblockcount()\n        for msg in [msg_getheaders(), msg_getblocks()]:\n            self.log.info('Wait for disconnect when sending {} hashes in locator'.format(MAX_LOCATOR_SZ + 1))\n            node.add_p2p_connection(P2PInterface())\n            msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ + 1), -1)]\n            node.p2p.send_message(msg)\n            node.p2p.wait_for_disconnect()\n            node.disconnect_p2ps()\n\n            self.log.info('Wait for response when sending {} hashes in locator'.format(MAX_LOCATOR_SZ))\n            node.add_p2p_connection(P2PInterface())\n            msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ), -1)]\n            node.p2p.send_message(msg)\n            if type(msg) == msg_getheaders:\n                node.p2p.wait_for_header(int(node.getbestblockhash(), 16))\n            else:\n                node.p2p.wait_for_block(int(node.getbestblockhash(), 16))\n\n\nif __name__ == '__main__':\n    InvalidLocatorTest().main()\n"
  },
  {
    "path": "test/functional/p2p_invalid_messages.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test node responses to invalid network messages.\"\"\"\nimport os\nimport struct\n\nfrom test_framework import messages\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.test_framework import MuntTestFramework\n\n\nclass msg_unrecognized:\n    \"\"\"Nonsensical message. Modeled after similar types in test_framework.messages.\"\"\"\n\n    command = b'badmsg'\n\n    def __init__(self, *, str_data):\n        self.str_data = str_data.encode() if not isinstance(str_data, bytes) else str_data\n\n    def serialize(self):\n        return messages.ser_string(self.str_data)\n\n    def __repr__(self):\n        return \"{}(data={})\".format(self.command, self.str_data)\n\n\nclass InvalidMessagesTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def run_test(self):\n        \"\"\"\n         . Test msg header\n        0. Send a bunch of large (4MB) messages of an unrecognized type. Check to see\n           that it isn't an effective DoS against the node.\n\n        1. Send an oversized (4MB+) message and check that we're disconnected.\n\n        2. Send a few messages with an incorrect data size in the header, ensure the\n           messages are ignored.\n        \"\"\"\n        self.test_magic_bytes()\n        self.test_checksum()\n        self.test_size()\n        self.test_command()\n\n        node = self.nodes[0]\n        self.node = node\n        node.add_p2p_connection(P2PDataStore())\n        conn2 = node.add_p2p_connection(P2PDataStore())\n\n        msg_limit = 4 * 1000 * 1000  # 4MB, per MAX_PROTOCOL_MESSAGE_LENGTH\n        valid_data_limit = msg_limit - 5  # Account for the 4-byte length prefix\n\n        #\n        # 0.\n        #\n        # Send as large a message as is valid, ensure we aren't disconnected but\n        # also can't exhaust resources.\n        #\n        msg_at_size = msg_unrecognized(str_data=\"b\" * valid_data_limit)\n        assert len(msg_at_size.serialize()) == msg_limit\n\n        increase_allowed = 0.5\n        if [s for s in os.environ.get(\"MUNT_CONFIG\", \"\").split(\" \") if \"--with-sanitizers\" in s and \"address\" in s]:\n            increase_allowed = 3.5\n        with node.assert_memory_usage_stable(increase_allowed=increase_allowed):\n            self.log.info(\n                \"Sending a bunch of large, junk messages to test \"\n                \"memory exhaustion. May take a bit...\")\n\n            # Run a bunch of times to test for memory exhaustion.\n            for _ in range(80):\n                node.p2p.send_message(msg_at_size)\n\n            # Check that, even though the node is being hammered by nonsense from one\n            # connection, it can still service other peers in a timely way.\n            for _ in range(20):\n                conn2.sync_with_ping(timeout=2)\n\n            # Peer 1, despite serving up a bunch of nonsense, should still be connected.\n            self.log.info(\"Waiting for node to drop junk messages.\")\n            node.p2p.sync_with_ping(timeout=120)\n            assert node.p2p.is_connected\n\n        #\n        # 1.\n        #\n        # Send an oversized message, ensure we're disconnected.\n        #\n        msg_over_size = msg_unrecognized(str_data=\"b\" * (valid_data_limit + 1))\n        assert len(msg_over_size.serialize()) == (msg_limit + 1)\n\n        with node.assert_debug_log([\"Oversized message from peer=4, disconnecting\"]):\n            # An unknown message type (or *any* message type) over\n            # MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect.\n            node.p2p.send_message(msg_over_size)\n            node.p2p.wait_for_disconnect(timeout=4)\n\n        node.disconnect_p2ps()\n        conn = node.add_p2p_connection(P2PDataStore())\n        conn.wait_for_verack()\n\n        #\n        # 2.\n        #\n        # Send messages with an incorrect data size in the header.\n        #\n        actual_size = 100\n        msg = msg_unrecognized(str_data=\"b\" * actual_size)\n\n        # TODO: handle larger-than cases. I haven't been able to pin down what behavior to expect.\n        for wrong_size in (2, 77, 78, 79):\n            self.log.info(\"Sending a message with incorrect size of {}\".format(wrong_size))\n\n            # Unmodified message should submit okay.\n            node.p2p.send_and_ping(msg)\n\n            # A message lying about its data size results in a disconnect when the incorrect\n            # data size is less than the actual size.\n            #\n            # TODO: why does behavior change at 78 bytes?\n            #\n            node.p2p.send_raw_message(self._tweak_msg_data_size(msg, wrong_size))\n\n            # For some reason unknown to me, we sometimes have to push additional data to the\n            # peer in order for it to realize a disconnect.\n            try:\n                node.p2p.send_message(messages.msg_ping(nonce=123123))\n            except IOError:\n                pass\n\n            node.p2p.wait_for_disconnect(timeout=10)\n            node.disconnect_p2ps()\n            node.add_p2p_connection(P2PDataStore())\n\n        # Node is still up.\n        conn = node.add_p2p_connection(P2PDataStore())\n        conn.sync_with_ping()\n\n    def test_magic_bytes(self):\n        conn = self.nodes[0].add_p2p_connection(P2PDataStore())\n        conn._on_data = lambda: None  # Need to ignore all incoming messages from now, since they come with \"invalid\" magic bytes\n        conn.magic_bytes = b'\\x00\\x11\\x22\\x32'\n        with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART ping']):\n            conn.send_message(messages.msg_ping(nonce=0xff))\n            conn.wait_for_disconnect(timeout=1)\n            self.nodes[0].disconnect_p2ps()\n\n    def test_checksum(self):\n        conn = self.nodes[0].add_p2p_connection(P2PDataStore())\n        with self.nodes[0].assert_debug_log(['ProcessMessages(badmsg, 2 bytes): CHECKSUM ERROR expected 78df0a04 was ffffffff']):\n            msg = conn.build_message(msg_unrecognized(str_data=\"d\"))\n            cut_len = (\n                4 +  # magic\n                12 +  # command\n                4  #len\n            )\n            # modify checksum\n            msg = msg[:cut_len] + b'\\xff' * 4 + msg[cut_len + 4:]\n            self.nodes[0].p2p.send_raw_message(msg)\n            conn.sync_with_ping(timeout=1)\n            self.nodes[0].disconnect_p2ps()\n\n    def test_size(self):\n        conn = self.nodes[0].add_p2p_connection(P2PDataStore())\n        with self.nodes[0].assert_debug_log(['']):\n            msg = conn.build_message(msg_unrecognized(str_data=\"d\"))\n            cut_len = (\n                4 +  # magic\n                12  # command\n            )\n            # modify len to MAX_SIZE + 1\n            msg = msg[:cut_len] + struct.pack(\"<I\", 0x02000000 + 1) + msg[cut_len + 4:]\n            self.nodes[0].p2p.send_raw_message(msg)\n            conn.wait_for_disconnect(timeout=1)\n            self.nodes[0].disconnect_p2ps()\n\n    def test_command(self):\n        conn = self.nodes[0].add_p2p_connection(P2PDataStore())\n        with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: ERRORS IN HEADER']):\n            msg = msg_unrecognized(str_data=\"d\")\n            msg.command = b'\\xff' * 12\n            msg = conn.build_message(msg)\n            # Modify command\n            msg = msg[:7] + b'\\x00' + msg[7 + 1:]\n            self.nodes[0].p2p.send_raw_message(msg)\n            conn.sync_with_ping(timeout=1)\n            self.nodes[0].disconnect_p2ps()\n\n    def _tweak_msg_data_size(self, message, wrong_size):\n        \"\"\"\n        Return a raw message based on another message but with an incorrect data size in\n        the message header.\n        \"\"\"\n        raw_msg = self.node.p2p.build_message(message)\n\n        bad_size_bytes = struct.pack(\"<I\", wrong_size)\n        num_header_bytes_before_size = 4 + 12\n\n        # Replace the correct data size in the message with an incorrect one.\n        raw_msg_with_wrong_size = (\n            raw_msg[:num_header_bytes_before_size] +\n            bad_size_bytes +\n            raw_msg[(num_header_bytes_before_size + len(bad_size_bytes)):]\n        )\n        assert len(raw_msg) == len(raw_msg_with_wrong_size)\n\n        return raw_msg_with_wrong_size\n\n\nif __name__ == '__main__':\n    InvalidMessagesTest().main()\n"
  },
  {
    "path": "test/functional/p2p_invalid_tx.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test node responses to invalid transactions.\n\nIn this test we connect to one node over p2p, and test tx requests.\"\"\"\nfrom test_framework.blocktools import create_block, create_coinbase\nfrom test_framework.messages import (\n    COIN,\n    COutPoint,\n    CTransaction,\n    CTxIn,\n    CTxOut,\n)\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    wait_until,\n)\nfrom data import invalid_txs\n\n\nclass InvalidTxRequestTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def bootstrap_p2p(self, *, num_connections=1):\n        \"\"\"Add a P2P connection to the node.\n\n        Helper to connect and wait for version handshake.\"\"\"\n        for _ in range(num_connections):\n            self.nodes[0].add_p2p_connection(P2PDataStore())\n\n    def reconnect_p2p(self, **kwargs):\n        \"\"\"Tear down and bootstrap the P2P connection to the node.\n\n        The node gets disconnected several times in this test. This helper\n        method reconnects the p2p and restarts the network thread.\"\"\"\n        self.nodes[0].disconnect_p2ps()\n        self.bootstrap_p2p(**kwargs)\n\n    def run_test(self):\n        node = self.nodes[0]  # convenience reference to the node\n\n        self.bootstrap_p2p()  # Add one p2p connection to the node\n\n        best_block = self.nodes[0].getbestblockhash()\n        tip = int(best_block, 16)\n        best_block_time = self.nodes[0].getblock(best_block)['time']\n        block_time = best_block_time + 1\n\n        self.log.info(\"Create a new block with an anyone-can-spend coinbase.\")\n        height = 1\n        block = create_block(tip, create_coinbase(height), block_time)\n        block.solve()\n        # Save the coinbase for later\n        block1 = block\n        tip = block.sha256\n        node.p2p.send_blocks_and_test([block], node, success=True)\n\n        self.log.info(\"Mature the block.\")\n        self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address)\n\n        # Iterate through a list of known invalid transaction types, ensuring each is\n        # rejected. Some are consensus invalid and some just violate policy.\n        for BadTxTemplate in invalid_txs.iter_all_templates():\n            self.log.info(\"Testing invalid transaction: %s\", BadTxTemplate.__name__)\n            template = BadTxTemplate(spend_block=block1)\n            tx = template.get_tx()\n            node.p2p.send_txs_and_test(\n                [tx], node, success=False,\n                expect_disconnect=template.expect_disconnect,\n                reject_reason=template.reject_reason,\n            )\n\n            if template.expect_disconnect:\n                self.log.info(\"Reconnecting to peer\")\n                self.reconnect_p2p()\n\n        # Make two p2p connections to provide the node with orphans\n        # * p2ps[0] will send valid orphan txs (one with low fee)\n        # * p2ps[1] will send an invalid orphan tx (and is later disconnected for that)\n        self.reconnect_p2p(num_connections=2)\n\n        self.log.info('Test orphan transaction handling ... ')\n        # Create a root transaction that we withhold until all dependent transactions\n        # are sent out and in the orphan cache\n        SCRIPT_PUB_KEY_OP_TRUE = b'\\x51\\x75' * 15 + b'\\x51'\n        tx_withhold = CTransaction()\n        tx_withhold.vin.append(CTxIn(outpoint=COutPoint(block1.vtx[0].sha256, 0)))\n        tx_withhold.vout.append(CTxOut(nValue=50 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))\n        tx_withhold.calc_sha256()\n\n        # Our first orphan tx with some outputs to create further orphan txs\n        tx_orphan_1 = CTransaction()\n        tx_orphan_1.vin.append(CTxIn(outpoint=COutPoint(tx_withhold.sha256, 0)))\n        tx_orphan_1.vout = [CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 3\n        tx_orphan_1.calc_sha256()\n\n        # A valid transaction with low fee\n        tx_orphan_2_no_fee = CTransaction()\n        tx_orphan_2_no_fee.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 0)))\n        tx_orphan_2_no_fee.vout.append(CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))\n\n        # A valid transaction with sufficient fee\n        tx_orphan_2_valid = CTransaction()\n        tx_orphan_2_valid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 1)))\n        tx_orphan_2_valid.vout.append(CTxOut(nValue=10 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))\n        tx_orphan_2_valid.calc_sha256()\n\n        # An invalid transaction with negative fee\n        tx_orphan_2_invalid = CTransaction()\n        tx_orphan_2_invalid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.sha256, 2)))\n        tx_orphan_2_invalid.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE))\n\n        self.log.info('Send the orphans ... ')\n        # Send valid orphan txs from p2ps[0]\n        node.p2p.send_txs_and_test([tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid], node, success=False)\n        # Send invalid tx from p2ps[1]\n        node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid], node, success=False)\n\n        assert_equal(0, node.getmempoolinfo()['size'])  # Mempool should be empty\n        assert_equal(2, len(node.getpeerinfo()))  # p2ps[1] is still connected\n\n        self.log.info('Send the withhold tx ... ')\n        with node.assert_debug_log(expected_msgs=[\"bad-txns-in-belowout\"]):\n            node.p2p.send_txs_and_test([tx_withhold], node, success=True)\n\n        # Transactions that should end up in the mempool\n        expected_mempool = {\n            t.hash\n            for t in [\n                tx_withhold,  # The transaction that is the root for all orphans\n                tx_orphan_1,  # The orphan transaction that splits the coins\n                tx_orphan_2_valid,  # The valid transaction (with sufficient fee)\n            ]\n        }\n        # Transactions that do not end up in the mempool\n        # tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx)\n        # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)\n\n        wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12)  # p2ps[1] is no longer connected\n        assert_equal(expected_mempool, set(node.getrawmempool()))\n\n\nif __name__ == '__main__':\n    InvalidTxRequestTest().main()\n"
  },
  {
    "path": "test/functional/p2p_leak.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test message sending before handshake completion.\n\nA node should never send anything other than VERSION/VERACK/REJECT until it's\nreceived a VERACK.\n\nThis test connects to a node and sends it a few messages, trying to entice it\ninto sending us something it shouldn't.\"\"\"\n\nimport time\n\nfrom test_framework.messages import msg_getaddr, msg_ping, msg_verack\nfrom test_framework.mininode import mininode_lock, P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import wait_until\n\nbanscore = 10\n\nclass CLazyNode(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.unexpected_msg = False\n        self.ever_connected = False\n\n    def bad_message(self, message):\n        self.unexpected_msg = True\n        self.log.info(\"should not have received message: %s\" % message.command)\n\n    def on_open(self):\n        self.ever_connected = True\n\n    def on_version(self, message): self.bad_message(message)\n    def on_verack(self, message): self.bad_message(message)\n    def on_reject(self, message): self.bad_message(message)\n    def on_inv(self, message): self.bad_message(message)\n    def on_addr(self, message): self.bad_message(message)\n    def on_getdata(self, message): self.bad_message(message)\n    def on_getblocks(self, message): self.bad_message(message)\n    def on_tx(self, message): self.bad_message(message)\n    def on_block(self, message): self.bad_message(message)\n    def on_getaddr(self, message): self.bad_message(message)\n    def on_headers(self, message): self.bad_message(message)\n    def on_getheaders(self, message): self.bad_message(message)\n    def on_ping(self, message): self.bad_message(message)\n    def on_mempool(self, message): self.bad_message(message)\n    def on_pong(self, message): self.bad_message(message)\n    def on_feefilter(self, message): self.bad_message(message)\n    def on_sendheaders(self, message): self.bad_message(message)\n    def on_sendcmpct(self, message): self.bad_message(message)\n    def on_cmpctblock(self, message): self.bad_message(message)\n    def on_getblocktxn(self, message): self.bad_message(message)\n    def on_blocktxn(self, message): self.bad_message(message)\n\n# Node that never sends a version. We'll use this to send a bunch of messages\n# anyway, and eventually get disconnected.\nclass CNodeNoVersionBan(CLazyNode):\n    # send a bunch of veracks without sending a message. This should get us disconnected.\n    # NOTE: implementation-specific check here. Remove if Munt-daemon ban behavior changes\n    def on_open(self):\n        super().on_open()\n        for i in range(banscore):\n            self.send_message(msg_verack())\n\n    def on_reject(self, message): pass\n\n# Node that never sends a version. This one just sits idle and hopes to receive\n# any message (it shouldn't!)\nclass CNodeNoVersionIdle(CLazyNode):\n    def __init__(self):\n        super().__init__()\n\n# Node that sends a version but not a verack.\nclass CNodeNoVerackIdle(CLazyNode):\n    def __init__(self):\n        self.version_received = False\n        super().__init__()\n\n    def on_reject(self, message): pass\n    def on_verack(self, message): pass\n    # When version is received, don't reply with a verack. Instead, see if the\n    # node will give us a message that it shouldn't. This is not an exhaustive\n    # list!\n    def on_version(self, message):\n        self.version_received = True\n        self.send_message(msg_ping())\n        self.send_message(msg_getaddr())\n\nclass P2PLeakTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.extra_args = [['-banscore=' + str(banscore)]]\n\n    def run_test(self):\n        no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False)\n        no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False)\n        no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle())\n\n        wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)\n        wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)\n        wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)\n\n        # Mine a block and make sure that it's not sent to the connected nodes\n        self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)\n\n        #Give the node enough time to possibly leak out a message\n        time.sleep(5)\n\n        #This node should have been banned\n        assert not no_version_bannode.is_connected\n\n        self.nodes[0].disconnect_p2ps()\n\n        # Wait until all connections are closed\n        wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)\n\n        # Make sure no unexpected messages came in\n        assert no_version_bannode.unexpected_msg == False\n        assert no_version_idlenode.unexpected_msg == False\n        assert no_verack_idlenode.unexpected_msg == False\n\n\nif __name__ == '__main__':\n    P2PLeakTest().main()\n"
  },
  {
    "path": "test/functional/p2p_leak_tx.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test that we don't leak txs to inbound peers that we haven't yet announced to\"\"\"\n\nfrom test_framework.messages import msg_getdata, CInv\nfrom test_framework.mininode import P2PDataStore\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n)\n\n\nclass P2PNode(P2PDataStore):\n    def on_inv(self, msg):\n        pass\n\n\nclass P2PLeakTxTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        gen_node = self.nodes[0]  # The block and tx generating node\n        gen_node.generate(1)\n\n        inbound_peer = self.nodes[0].add_p2p_connection(P2PNode())  # An \"attacking\" inbound peer\n\n        MAX_REPEATS = 100\n        self.log.info(\"Running test up to {} times.\".format(MAX_REPEATS))\n        for i in range(MAX_REPEATS):\n            self.log.info('Run repeat {}'.format(i + 1))\n            txid = gen_node.sendtoaddress(gen_node.getnewaddress(), 0.01)\n\n            want_tx = msg_getdata()\n            want_tx.inv.append(CInv(t=1, h=int(txid, 16)))\n            inbound_peer.last_message.pop('notfound', None)\n            inbound_peer.send_message(want_tx)\n            inbound_peer.sync_with_ping()\n\n            if inbound_peer.last_message.get('notfound'):\n                self.log.debug('tx {} was not yet announced to us.'.format(txid))\n                self.log.debug(\"node has responded with a notfound message. End test.\")\n                assert_equal(inbound_peer.last_message['notfound'].vec[0].hash, int(txid, 16))\n                inbound_peer.last_message.pop('notfound')\n                break\n            else:\n                self.log.debug('tx {} was already announced to us. Try test again.'.format(txid))\n                assert int(txid, 16) in [inv.hash for inv in inbound_peer.last_message['inv'].inv]\n\n\nif __name__ == '__main__':\n    P2PLeakTxTest().main()\n"
  },
  {
    "path": "test/functional/p2p_mempool.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test p2p mempool message.\n\nTest that nodes are disconnected if they send mempool messages when bloom\nfilters are not enabled.\n\"\"\"\n\nfrom test_framework.messages import msg_mempool\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass P2PMempoolTests(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        self.extra_args = [[\"-peerbloomfilters=0\"]]\n\n    def run_test(self):\n        # Add a p2p connection\n        self.nodes[0].add_p2p_connection(P2PInterface())\n\n        #request mempool\n        self.nodes[0].p2p.send_message(msg_mempool())\n        self.nodes[0].p2p.wait_for_disconnect()\n\n        #mininode must be disconnected at this point\n        assert_equal(len(self.nodes[0].getpeerinfo()), 0)\n\nif __name__ == '__main__':\n    P2PMempoolTests().main()\n"
  },
  {
    "path": "test/functional/p2p_node_network_limited.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Tests NODE_NETWORK_LIMITED.\n\nTests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correctly\nand that it responds to getdata requests for blocks correctly:\n    - send a block within 288 + 2 of the tip\n    - disconnect peers who request blocks older than that.\"\"\"\nfrom test_framework.messages import CInv, msg_getdata, msg_verack, NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS\nfrom test_framework.mininode import P2PInterface, mininode_lock\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks, wait_until\n\nclass P2PIgnoreInv(P2PInterface):\n    firstAddrnServices = 0\n    def on_inv(self, message):\n        # The node will send us invs for other blocks. Ignore them.\n        pass\n    def on_addr(self, message):\n        self.firstAddrnServices = message.addrs[0].nServices\n    def wait_for_addr(self, timeout=5):\n        test_function = lambda: self.last_message.get(\"addr\")\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n    def send_getdata_for_block(self, blockhash):\n        getdata_request = msg_getdata()\n        getdata_request.inv.append(CInv(2, int(blockhash, 16)))\n        self.send_message(getdata_request)\n\nclass NodeNetworkLimitedTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        self.extra_args = [['-prune=550', '-addrmantest'], [], []]\n\n    ###def disconnect_all(self):\n        ###disconnect_nodes(self.nodes[0], 1)\n        ###disconnect_nodes(self.nodes[1], 0)\n        ###disconnect_nodes(self.nodes[2], 1)\n        ###disconnect_nodes(self.nodes[2], 0)\n        ###disconnect_nodes(self.nodes[0], 2)\n        ###disconnect_nodes(self.nodes[1], 2)\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes, self.extra_args)\n        self.start_nodes()\n\n    def run_test(self):\n        node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())\n\n        expected_services = NODE_BLOOM | NODE_WITNESS | NODE_NETWORK_LIMITED\n\n        self.log.info(\"Check that node has signalled expected services.\")\n        ###assert_equal(node.nServices, expected_services)\n\n        self.log.info(\"Check that the localservices is as expected.\")\n        ###assert_equal(int(self.nodes[0].getnetworkinfo()['localservices'], 16), expected_services)\n\n        self.log.info(\"Mine enough blocks to reach the NODE_NETWORK_LIMITED range.\")\n        connect_nodes_bi(self.nodes, 0, 1)\n        blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address)\n        sync_blocks([self.nodes[0], self.nodes[1]])\n\n        self.log.info(\"Make sure we can max retrieve block at tip-288.\")\n        node.send_getdata_for_block(blocks[1])  # last block in valid range\n        node.wait_for_block(int(blocks[1], 16), timeout=3)\n\n        self.log.info(\"Requesting block at height 2 (tip-289) must fail (ignored).\")\n        node.send_getdata_for_block(blocks[0])  # first block outside of the 288+2 limit\n        ###node.wait_for_disconnect(5)\n\n        self.log.info(\"Check local address relay, do a fresh connection.\")\n        self.nodes[0].disconnect_p2ps()\n        node1 = self.nodes[0].add_p2p_connection(P2PIgnoreInv())\n        node1.send_message(msg_verack())\n\n        ###node1.wait_for_addr()\n        ###must relay address with NODE_NETWORK_LIMITED\n        ###assert_equal(node1.firstAddrnServices, 1036)\n\n        self.nodes[0].disconnect_p2ps()\n        node1.wait_for_disconnect()\n\n        # connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer\n        # because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible\n        connect_nodes_bi(self.nodes, 0, 2)\n        try:\n            sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)\n        except:\n            pass\n        # node2 must remain at height 0\n        assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0)\n\n        # now connect also to node 1 (non pruned)\n        connect_nodes_bi(self.nodes, 1, 2)\n\n        # sync must be possible\n        sync_blocks(self.nodes)\n\n        # disconnect all peers\n        ###self.disconnect_all()\n\n        # mine 10 blocks on node 0 (pruned node)\n        self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)\n\n        # connect node1 (non pruned) with node0 (pruned) and check if the can sync\n        connect_nodes_bi(self.nodes, 0, 1)\n\n        # sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)\n        sync_blocks([self.nodes[0], self.nodes[1]])\n\nif __name__ == '__main__':\n    NodeNetworkLimitedTest().main()\n"
  },
  {
    "path": "test/functional/p2p_segwit.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test segwit transactions and blocks on P2P network.\"\"\"\nimport math\nimport random\nimport struct\nimport time\n\nfrom test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER\nfrom test_framework.key import CECKey, CPubKey\nfrom test_framework.messages import (\n    BIP125_SEQUENCE_NUMBER,\n    CBlock,\n    CBlockHeader,\n    CInv,\n    COutPoint,\n    CTransaction,\n    CTxIn,\n    CTxInWitness,\n    CTxOut,\n    CTxWitness,\n    MAX_BLOCK_BASE_SIZE,\n    MSG_WITNESS_FLAG,\n    NODE_NETWORK,\n    NODE_WITNESS,\n    msg_block,\n    msg_getdata,\n    msg_headers,\n    msg_inv,\n    msg_tx,\n    msg_witness_block,\n    msg_witness_tx,\n    ser_uint256,\n    ser_vector,\n    sha256,\n    uint256_from_str,\n)\nfrom test_framework.mininode import (\n    P2PInterface,\n    mininode_lock,\n)\nfrom test_framework.script import (\n    CScript,\n    CScriptNum,\n    CScriptOp,\n    MAX_SCRIPT_ELEMENT_SIZE,\n    OP_0,\n    OP_1,\n    OP_16,\n    OP_2DROP,\n    OP_CHECKMULTISIG,\n    OP_CHECKSIG,\n    OP_DROP,\n    OP_DUP,\n    OP_ELSE,\n    OP_ENDIF,\n    OP_EQUAL,\n    OP_EQUALVERIFY,\n    OP_HASH160,\n    OP_IF,\n    OP_RETURN,\n    OP_TRUE,\n    SIGHASH_ALL,\n    SIGHASH_ANYONECANPAY,\n    SIGHASH_NONE,\n    SIGHASH_SINGLE,\n    SegwitVersion1SignatureHash,\n    SignatureHash,\n    hash160,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes,\n    disconnect_nodes,\n    get_bip9_status,\n    hex_str_to_bytes,\n    sync_blocks,\n    sync_mempools,\n)\n\n# The versionbit bit used to signal activation of SegWit\nVB_WITNESS_BIT = 1\nVB_PERIOD = 144\nVB_TOP_BITS = 0x20000000\n\nMAX_SIGOP_COST = 80000\n\nclass UTXO():\n    \"\"\"Used to keep track of anyone-can-spend outputs that we can use in the tests.\"\"\"\n    def __init__(self, sha256, n, value):\n        self.sha256 = sha256\n        self.n = n\n        self.nValue = value\n\ndef get_p2pkh_script(pubkeyhash):\n    \"\"\"Get the script associated with a P2PKH.\"\"\"\n    return CScript([CScriptOp(OP_DUP), CScriptOp(OP_HASH160), pubkeyhash, CScriptOp(OP_EQUALVERIFY), CScriptOp(OP_CHECKSIG)])\n\ndef sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key):\n    \"\"\"Add signature for a P2PK witness program.\"\"\"\n    tx_hash = SegwitVersion1SignatureHash(script, tx_to, in_idx, hashtype, value)\n    signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')\n    tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script]\n    tx_to.rehash()\n\ndef get_virtual_size(witness_block):\n    \"\"\"Calculate the virtual size of a witness block.\n\n    Virtual size is base + witness/4.\"\"\"\n    base_size = len(witness_block.serialize(with_witness=False))\n    total_size = len(witness_block.serialize(with_witness=True))\n    # the \"+3\" is so we round up\n    vsize = int((3 * base_size + total_size + 3) / 4)\n    return vsize\n\ndef test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None):\n    \"\"\"Send a transaction to the node and check that it's accepted to the mempool\n\n    - Submit the transaction over the p2p interface\n    - use the getrawmempool rpc to check for acceptance.\"\"\"\n    reason = [reason] if reason else []\n    with node.assert_debug_log(expected_msgs=reason):\n        p2p.send_message(msg_witness_tx(tx) if with_witness else msg_tx(tx))\n        p2p.sync_with_ping()\n        assert_equal(tx.hash in node.getrawmempool(), accepted)\n\ndef test_witness_block(node, p2p, block, accepted, with_witness=True, reason=None):\n    \"\"\"Send a block to the node and check that it's accepted\n\n    - Submit the block over the p2p interface\n    - use the getbestblockhash rpc to check for acceptance.\"\"\"\n    reason = [reason] if reason else []\n    with node.assert_debug_log(expected_msgs=reason):\n        p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block))\n        p2p.sync_with_ping()\n        assert_equal(node.getbestblockhash() == block.hash, accepted)\n\n\nclass TestP2PConn(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.getdataset = set()\n\n    def on_getdata(self, message):\n        for inv in message.inv:\n            self.getdataset.add(inv.hash)\n\n    def announce_tx_and_wait_for_getdata(self, tx, timeout=60, success=True):\n        with mininode_lock:\n            self.last_message.pop(\"getdata\", None)\n        self.send_message(msg_inv(inv=[CInv(1, tx.sha256)]))\n        if success:\n            self.wait_for_getdata(timeout)\n        else:\n            time.sleep(timeout)\n            assert not self.last_message.get(\"getdata\")\n\n    def announce_block_and_wait_for_getdata(self, block, use_header, timeout=60):\n        with mininode_lock:\n            self.last_message.pop(\"getdata\", None)\n            self.last_message.pop(\"getheaders\", None)\n        msg = msg_headers()\n        msg.headers = [CBlockHeader(block)]\n        if use_header:\n            self.send_message(msg)\n        else:\n            self.send_message(msg_inv(inv=[CInv(2, block.sha256)]))\n            self.wait_for_getheaders()\n            self.send_message(msg)\n        self.wait_for_getdata()\n\n    def request_block(self, blockhash, inv_type, timeout=60):\n        with mininode_lock:\n            self.last_message.pop(\"block\", None)\n        self.send_message(msg_getdata(inv=[CInv(inv_type, blockhash)]))\n        self.wait_for_block(blockhash, timeout)\n        return self.last_message[\"block\"].block\n\nclass SegWitTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.\n        self.extra_args = [[\"-whitelist=127.0.0.1\", \"-vbparams=segwit:0:999999999999\"], [\"-whitelist=127.0.0.1\", \"-acceptnonstdtxn=0\", \"-vbparams=segwit:0:999999999999\"], [\"-whitelist=127.0.0.1\", \"-vbparams=segwit:0:0\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n        connect_nodes(self.nodes[0], 1)\n        connect_nodes(self.nodes[0], 2)\n        self.sync_all()\n\n    # Helper functions\n\n    def build_next_block(self, version=4):\n        \"\"\"Build a block on top of node0's tip.\"\"\"\n        tip = self.nodes[0].getbestblockhash()\n        height = self.nodes[0].getblockcount() + 1\n        block_time = self.nodes[0].getblockheader(tip)[\"mediantime\"] + 1\n        block = create_block(int(tip, 16), create_coinbase(height), block_time)\n        block.nVersion = version\n        block.rehash()\n        return block\n\n    def update_witness_block_with_transactions(self, block, tx_list, nonce=0):\n        \"\"\"Add list of transactions to block, adds witness commitment, then solves.\"\"\"\n        block.vtx.extend(tx_list)\n        add_witness_commitment(block, nonce)\n        block.solve()\n\n    def run_test(self):\n        # Setup the p2p connections\n        # self.test_node sets NODE_WITNESS|NODE_NETWORK\n        self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)\n        # self.old_node sets only NODE_NETWORK\n        self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)\n        # self.std_node is for testing node1 (fRequireStandard=true)\n        self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)\n\n        assert self.test_node.nServices & NODE_WITNESS != 0\n\n        # Keep a place to store utxo's that can be used in later tests\n        self.utxo = []\n\n        # Segwit status 'defined'\n        self.segwit_status = 'defined'\n\n        self.test_non_witness_transaction()\n        self.test_unnecessary_witness_before_segwit_activation()\n        self.test_v0_outputs_arent_spendable()\n        self.test_block_relay()\n        self.advance_to_segwit_started()\n\n        # Segwit status 'started'\n\n        self.test_getblocktemplate_before_lockin()\n        self.advance_to_segwit_lockin()\n\n        # Segwit status 'locked_in'\n\n        self.test_unnecessary_witness_before_segwit_activation()\n        self.test_witness_tx_relay_before_segwit_activation()\n        self.test_block_relay()\n        self.test_standardness_v0()\n        self.advance_to_segwit_active()\n\n        # Segwit status 'active'\n\n        self.test_p2sh_witness()\n        self.test_witness_commitments()\n        self.test_block_malleability()\n        self.test_witness_block_size()\n        self.test_submit_block()\n        self.test_extra_witness_data()\n        self.test_max_witness_push_length()\n        self.test_max_witness_program_length()\n        self.test_witness_input_length()\n        self.test_block_relay()\n        self.test_tx_relay_after_segwit_activation()\n        self.test_standardness_v0()\n        self.test_segwit_versions()\n        self.test_premature_coinbase_witness_spend()\n        self.test_uncompressed_pubkey()\n        self.test_signature_version_1()\n        self.test_non_standard_witness_blinding()\n        self.test_non_standard_witness()\n        self.test_upgrade_after_activation()\n        self.test_witness_sigops()\n\n    # Individual tests\n\n    def subtest(func):  # noqa: N805\n        \"\"\"Wraps the subtests for logging and state assertions.\"\"\"\n        def func_wrapper(self, *args, **kwargs):\n            self.log.info(\"Subtest: {} (Segwit status = {})\".format(func.__name__, self.segwit_status))\n            # Assert segwit status is as expected\n            assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)\n            func(self, *args, **kwargs)\n            # Each subtest should leave some utxos for the next subtest\n            assert self.utxo\n            sync_blocks(self.nodes)\n            # Assert segwit status is as expected at end of subtest\n            assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)\n\n        return func_wrapper\n\n    @subtest\n    def test_non_witness_transaction(self):\n        \"\"\"See if sending a regular transaction works, and create a utxo to use in later tests.\"\"\"\n        # Mine a block with an anyone-can-spend coinbase,\n        # let it mature, then try to spend it.\n\n        block = self.build_next_block(version=1)\n        block.solve()\n        self.test_node.send_message(msg_block(block))\n        self.test_node.sync_with_ping()  # make sure the block was processed\n        txid = block.vtx[0].sha256\n\n        self.nodes[0].generate(99)  # let the block mature\n\n        # Create a transaction that spends the coinbase\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(txid, 0), b\"\"))\n        tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n        tx.calc_sha256()\n\n        # Check that serializing it with or without witness is the same\n        # This is a sanity check of our testing framework.\n        assert_equal(msg_tx(tx).serialize(), msg_witness_tx(tx).serialize())\n\n        self.test_node.send_message(msg_witness_tx(tx))\n        self.test_node.sync_with_ping()  # make sure the tx was processed\n        assert tx.hash in self.nodes[0].getrawmempool()\n        # Save this transaction for later\n        self.utxo.append(UTXO(tx.sha256, 0, 49 * 100000000))\n        self.nodes[0].generate(1)\n\n    @subtest\n    def test_unnecessary_witness_before_segwit_activation(self):\n        \"\"\"Verify that blocks with witnesses are rejected before activation.\"\"\"\n\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE])))\n        tx.wit.vtxinwit.append(CTxInWitness())\n        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)])]\n\n        # Verify the hash with witness differs from the txid\n        # (otherwise our testing framework must be broken!)\n        tx.rehash()\n        assert tx.sha256 != tx.calc_sha256(with_witness=True)\n\n        # Construct a segwit-signaling block that includes the transaction.\n        block = self.build_next_block(version=(VB_TOP_BITS | (1 << VB_WITNESS_BIT)))\n        self.update_witness_block_with_transactions(block, [tx])\n        # Sending witness data before activation is not allowed (anti-spam\n        # rule).\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='unexpected-witness')\n\n        # But it should not be permanently marked bad...\n        # Resend without witness information.\n        self.test_node.send_message(msg_block(block))\n        self.test_node.sync_with_ping()\n        assert_equal(self.nodes[0].getbestblockhash(), block.hash)\n\n        # Update our utxo list; we spent the first entry.\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))\n\n    @subtest\n    def test_block_relay(self):\n        \"\"\"Test that block requests to NODE_WITNESS peer are with MSG_WITNESS_FLAG.\n\n        This is true regardless of segwit activation.\n        Also test that we don't ask for blocks from unupgraded peers.\"\"\"\n\n        blocktype = 2 | MSG_WITNESS_FLAG\n\n        # test_node has set NODE_WITNESS, so all getdata requests should be for\n        # witness blocks.\n        # Test announcing a block via inv results in a getdata, and that\n        # announcing a version 4 or random VB block with a header results in a getdata\n        block1 = self.build_next_block()\n        block1.solve()\n\n        self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)\n        assert self.test_node.last_message[\"getdata\"].inv[0].type == blocktype\n        test_witness_block(self.nodes[0], self.test_node, block1, True)\n\n        block2 = self.build_next_block(version=4)\n        block2.solve()\n\n        self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)\n        assert self.test_node.last_message[\"getdata\"].inv[0].type == blocktype\n        test_witness_block(self.nodes[0], self.test_node, block2, True)\n\n        block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))\n        block3.solve()\n        self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)\n        assert self.test_node.last_message[\"getdata\"].inv[0].type == blocktype\n        test_witness_block(self.nodes[0], self.test_node, block3, True)\n\n        # Check that we can getdata for witness blocks or regular blocks,\n        # and the right thing happens.\n        if self.segwit_status != 'active':\n            # Before activation, we should be able to request old blocks with\n            # or without witness, and they should be the same.\n            chain_height = self.nodes[0].getblockcount()\n            # Pick 10 random blocks on main chain, and verify that getdata's\n            # for MSG_BLOCK, MSG_WITNESS_BLOCK, and rpc getblock() are equal.\n            all_heights = list(range(chain_height + 1))\n            random.shuffle(all_heights)\n            all_heights = all_heights[0:10]\n            for height in all_heights:\n                block_hash = self.nodes[0].getblockhash(height)\n                rpc_block = self.nodes[0].getblock(block_hash, False)\n                block_hash = int(block_hash, 16)\n                block = self.test_node.request_block(block_hash, 2)\n                wit_block = self.test_node.request_block(block_hash, 2 | MSG_WITNESS_FLAG)\n                assert_equal(block.serialize(True), wit_block.serialize(True))\n                assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))\n        else:\n            # After activation, witness blocks and non-witness blocks should\n            # be different.  Verify rpc getblock() returns witness blocks, while\n            # getdata respects the requested type.\n            block = self.build_next_block()\n            self.update_witness_block_with_transactions(block, [])\n            # This gives us a witness commitment.\n            assert len(block.vtx[0].wit.vtxinwit) == 1\n            assert len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1\n            test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n            # Now try to retrieve it...\n            rpc_block = self.nodes[0].getblock(block.hash, False)\n            non_wit_block = self.test_node.request_block(block.sha256, 2)\n            wit_block = self.test_node.request_block(block.sha256, 2 | MSG_WITNESS_FLAG)\n            assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))\n            assert_equal(wit_block.serialize(False), non_wit_block.serialize())\n            assert_equal(wit_block.serialize(True), block.serialize(True))\n\n            # Test size, vsize, weight\n            rpc_details = self.nodes[0].getblock(block.hash, True)\n            assert_equal(rpc_details[\"size\"], len(block.serialize(True)))\n            assert_equal(rpc_details[\"strippedsize\"], len(block.serialize(False)))\n            weight = 3 * len(block.serialize(False)) + len(block.serialize(True))\n            assert_equal(rpc_details[\"weight\"], weight)\n\n            # Upgraded node should not ask for blocks from unupgraded\n            block4 = self.build_next_block(version=4)\n            block4.solve()\n            self.old_node.getdataset = set()\n\n            # Blocks can be requested via direct-fetch (immediately upon processing the announcement)\n            # or via parallel download (with an indeterminate delay from processing the announcement)\n            # so to test that a block is NOT requested, we could guess a time period to sleep for,\n            # and then check. We can avoid the sleep() by taking advantage of transaction getdata's\n            # being processed after block getdata's, and announce a transaction as well,\n            # and then check to see if that particular getdata has been received.\n            # Since 0.14, inv's will only be responded to with a getheaders, so send a header\n            # to announce this block.\n            msg = msg_headers()\n            msg.headers = [CBlockHeader(block4)]\n            self.old_node.send_message(msg)\n            self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])\n            assert block4.sha256 not in self.old_node.getdataset\n\n    @subtest\n    def test_v0_outputs_arent_spendable(self):\n        \"\"\"Test that v0 outputs aren't spendable before segwit activation.\n\n        ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was\n        backdated so that it applies to all blocks, going back to the genesis\n        block.\n\n        Consequently, version 0 witness outputs are never spendable without\n        witness, and so can't be spent before segwit activation (the point at which\n        blocks are permitted to contain witnesses).\"\"\"\n\n        # node2 doesn't need to be connected for this test.\n        # (If it's connected, node0 may propagate an invalid block to it over\n        # compact blocks and the nodes would have inconsistent tips.)\n        disconnect_nodes(self.nodes[0], 2)\n\n        # Create two outputs, a p2wsh and p2sh-p2wsh\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        p2sh_pubkey = hash160(script_pubkey)\n        p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])\n\n        value = self.utxo[0].nValue // 3\n\n        tx = CTransaction()\n        tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]\n        tx.vout = [CTxOut(value, script_pubkey), CTxOut(value, p2sh_script_pubkey)]\n        tx.vout.append(CTxOut(value, CScript([OP_TRUE])))\n        tx.rehash()\n        txid = tx.sha256\n\n        # Add it to a block\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        # Verify that segwit isn't activated. A block serialized with witness\n        # should be rejected prior to activation.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')\n        # Now send the block without witness. It should be accepted\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)\n\n        # Now try to spend the outputs. This should fail since SCRIPT_VERIFY_WITNESS is always enabled.\n        p2wsh_tx = CTransaction()\n        p2wsh_tx.vin = [CTxIn(COutPoint(txid, 0), b'')]\n        p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]\n        p2wsh_tx.wit.vtxinwit.append(CTxInWitness())\n        p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]\n        p2wsh_tx.rehash()\n\n        p2sh_p2wsh_tx = CTransaction()\n        p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([script_pubkey]))]\n        p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]\n        p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())\n        p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]\n        p2sh_p2wsh_tx.rehash()\n\n        for tx in [p2wsh_tx, p2sh_p2wsh_tx]:\n\n            block = self.build_next_block()\n            self.update_witness_block_with_transactions(block, [tx])\n\n            # When the block is serialized with a witness, the block will be rejected because witness\n            # data isn't allowed in blocks that don't commit to witness data.\n            test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')\n\n            # When the block is serialized without witness, validation fails because the transaction is\n            # invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction\n            # without a witness is invalid).\n            # Note: The reject reason for this failure could be\n            # 'block-validation-failed' (if script check threads > 1) or\n            # 'non-mandatory-script-verify-flag (Witness program was passed an\n            # empty witness)' (otherwise).\n            # TODO: support multiple acceptable reject reasons.\n            test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)\n\n        connect_nodes(self.nodes[0], 2)\n\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(txid, 2, value))\n\n    @subtest\n    def advance_to_segwit_started(self):\n        \"\"\"Mine enough blocks for segwit's vb state to be 'started'.\"\"\"\n        height = self.nodes[0].getblockcount()\n        # Will need to rewrite the tests here if we are past the first period\n        assert height < VB_PERIOD - 1\n        # Advance to end of period, status should now be 'started'\n        self.nodes[0].generate(VB_PERIOD - height - 1)\n        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')\n        self.segwit_status = 'started'\n\n    @subtest\n    def test_getblocktemplate_before_lockin(self):\n        txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)\n\n        for node in [self.nodes[0], self.nodes[2]]:\n            gbt_results = node.getblocktemplate({\"rules\": [\"segwit\"]})\n            block_version = gbt_results['version']\n            if node == self.nodes[2]:\n                # If this is a non-segwit node, we should not get a witness\n                # commitment, nor a version bit signalling segwit.\n                assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)\n                assert 'default_witness_commitment' not in gbt_results\n            else:\n                # For segwit-aware nodes, check the version bit and the witness\n                # commitment are correct.\n                assert block_version & (1 << VB_WITNESS_BIT) != 0\n                assert 'default_witness_commitment' in gbt_results\n                witness_commitment = gbt_results['default_witness_commitment']\n\n                # Check that default_witness_commitment is present.\n                witness_root = CBlock.get_merkle_root([ser_uint256(0),\n                                                       ser_uint256(txid)])\n                script = get_witness_script(witness_root, 0)\n                assert_equal(witness_commitment, script.hex())\n\n    @subtest\n    def advance_to_segwit_lockin(self):\n        \"\"\"Mine enough blocks to lock in segwit, but don't activate.\"\"\"\n        height = self.nodes[0].getblockcount()\n        # Advance to end of period, and verify lock-in happens at the end\n        self.nodes[0].generate(VB_PERIOD - 1)\n        height = self.nodes[0].getblockcount()\n        assert (height % VB_PERIOD) == VB_PERIOD - 2\n        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')\n        self.nodes[0].generate(1)\n        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')\n        self.segwit_status = 'locked_in'\n\n    @subtest\n    def test_witness_tx_relay_before_segwit_activation(self):\n\n        # Generate a transaction that doesn't require a witness, but send it\n        # with a witness.  Should be rejected for premature-witness, but should\n        # not be added to recently rejected list.\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n        tx.wit.vtxinwit.append(CTxInWitness())\n        tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']\n        tx.rehash()\n\n        tx_hash = tx.sha256\n        tx_value = tx.vout[0].nValue\n\n        # Verify that if a peer doesn't set nServices to include NODE_WITNESS,\n        # the getdata is just for the non-witness portion.\n        self.old_node.announce_tx_and_wait_for_getdata(tx)\n        assert self.old_node.last_message[\"getdata\"].inv[0].type == 1\n\n        # Since we haven't delivered the tx yet, inv'ing the same tx from\n        # a witness transaction ought not result in a getdata.\n        self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2, success=False)\n\n        # Delivering this transaction with witness should fail (no matter who\n        # its from)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n        test_transaction_acceptance(self.nodes[0], self.old_node, tx, with_witness=True, accepted=False)\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)\n\n        # But eliminating the witness should fix it\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)\n\n        # Cleanup: mine the first transaction and update utxo\n        self.nodes[0].generate(1)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx_hash, 0, tx_value))\n\n    @subtest\n    def test_standardness_v0(self):\n        \"\"\"Test V0 txout standardness.\n\n        V0 segwit outputs and inputs are always standard.\n        V0 segwit inputs may only be mined after activation, but not before.\"\"\"\n\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        p2sh_pubkey = hash160(witness_program)\n        p2sh_script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])\n\n        # First prepare a p2sh output (so that spending it will pass standardness)\n        p2sh_tx = CTransaction()\n        p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\")]\n        p2sh_tx.vout = [CTxOut(self.utxo[0].nValue - 1000, p2sh_script_pubkey)]\n        p2sh_tx.rehash()\n\n        # Mine it on test_node to create the confirmed output.\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_tx, with_witness=True, accepted=True)\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # Now test standardness of v0 P2WSH outputs.\n        # Start by creating a transaction with two outputs.\n        tx = CTransaction()\n        tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))]\n        tx.vout = [CTxOut(p2sh_tx.vout[0].nValue - 10000, script_pubkey)]\n        tx.vout.append(CTxOut(8000, script_pubkey))  # Might burn this later\n        tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER  # Just to have the option to bump this tx from the mempool\n        tx.rehash()\n\n        # This is always accepted, since the mempool policy is to consider segwit as always active\n        # and thus allow segwit outputs\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=True)\n\n        # Now create something that looks like a P2PKH output. This won't be spendable.\n        script_pubkey = CScript([OP_0, hash160(witness_hash)])\n        tx2 = CTransaction()\n        # tx was accepted, so we spend the second output.\n        tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b\"\")]\n        tx2.vout = [CTxOut(7000, script_pubkey)]\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        tx2.rehash()\n\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=True)\n\n        # Now update self.utxo for later tests.\n        tx3 = CTransaction()\n        # tx and tx2 were both accepted.  Don't bother trying to reclaim the\n        # P2PKH output; just send tx's first output back to an anyone-can-spend.\n        sync_mempools([self.nodes[0], self.nodes[1]])\n        tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b\"\")]\n        tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]\n        tx3.wit.vtxinwit.append(CTxInWitness())\n        tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        tx3.rehash()\n        if self.segwit_status != 'active':\n            # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed\n            # in blocks and the tx is impossible to mine right now.\n            assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}])\n            # Create the same output as tx3, but by replacing tx\n            tx3_out = tx3.vout[0]\n            tx3 = tx\n            tx3.vout = [tx3_out]\n            tx3.rehash()\n            assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}])\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)\n\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n\n    @subtest\n    def advance_to_segwit_active(self):\n        \"\"\"Mine enough blocks to activate segwit.\"\"\"\n        height = self.nodes[0].getblockcount()\n        self.nodes[0].generate(VB_PERIOD - (height % VB_PERIOD) - 2)\n        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')\n        self.nodes[0].generate(1)\n        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'active')\n        self.segwit_status = 'active'\n\n    @subtest\n    def test_p2sh_witness(self):\n        \"\"\"Test P2SH wrapped witness programs.\"\"\"\n\n        # Prepare the p2sh-wrapped witness output\n        witness_program = CScript([OP_DROP, OP_TRUE])\n        witness_hash = sha256(witness_program)\n        p2wsh_pubkey = CScript([OP_0, witness_hash])\n        p2sh_witness_hash = hash160(p2wsh_pubkey)\n        script_pubkey = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])\n        script_sig = CScript([p2wsh_pubkey])  # a push of the redeem script\n\n        # Fund the P2SH output\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))\n        tx.rehash()\n\n        # Verify mempool acceptance and block validity\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=True)\n        sync_blocks(self.nodes)\n\n        # Now test attempts to spend the output.\n        spend_tx = CTransaction()\n        spend_tx.vin.append(CTxIn(COutPoint(tx.sha256, 0), script_sig))\n        spend_tx.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))\n        spend_tx.rehash()\n\n        # This transaction should not be accepted into the mempool pre- or\n        # post-segwit.  Mempool acceptance will use SCRIPT_VERIFY_WITNESS which\n        # will require a witness to spend a witness program regardless of\n        # segwit activation.  Note that older Munt-daemon's that are not\n        # segwit-aware would also reject this for failing CLEANSTACK.\n        with self.nodes[0].assert_debug_log(\n                expected_msgs=(spend_tx.hash, 'was not accepted: non-mandatory-script-verify-flag (Witness program was passed an empty witness)')):\n            test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)\n\n        # Try to put the witness script in the scriptSig, should also fail.\n        spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a'])\n        spend_tx.rehash()\n        with self.nodes[0].assert_debug_log(\n                expected_msgs=(spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')):\n            test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)\n\n        # Now put the witness script in the witness, should succeed after\n        # segwit activates.\n        spend_tx.vin[0].scriptSig = script_sig\n        spend_tx.rehash()\n        spend_tx.wit.vtxinwit.append(CTxInWitness())\n        spend_tx.wit.vtxinwit[0].scriptWitness.stack = [b'a', witness_program]\n\n        # Verify mempool acceptance\n        test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=True, accepted=True)\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [spend_tx])\n\n        # If we're after activation, then sending this with witnesses should be valid.\n        # This no longer works before activation, because SCRIPT_VERIFY_WITNESS\n        # is always set.\n        # TODO: rewrite this test to make clear that it only works after activation.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Update self.utxo\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(spend_tx.sha256, 0, spend_tx.vout[0].nValue))\n\n    @subtest\n    def test_witness_commitments(self):\n        \"\"\"Test witness commitments.\n\n        This test can only be run after segwit has activated.\"\"\"\n\n        # First try a correct witness commitment.\n        block = self.build_next_block()\n        add_witness_commitment(block)\n        block.solve()\n\n        # Test the test -- witness serialization should be different\n        assert msg_witness_block(block).serialize() != msg_block(block).serialize()\n\n        # This empty block should be valid.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Try to tweak the nonce\n        block_2 = self.build_next_block()\n        add_witness_commitment(block_2, nonce=28)\n        block_2.solve()\n\n        # The commitment should have changed!\n        assert block_2.vtx[0].vout[-1] != block.vtx[0].vout[-1]\n\n        # This should also be valid.\n        test_witness_block(self.nodes[0], self.test_node, block_2, accepted=True)\n\n        # Now test commitments with actual transactions\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n\n        # Let's construct a witness program\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))\n        tx.rehash()\n\n        # tx2 will spend tx1, and send back to a regular anyone-can-spend address\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        tx2.rehash()\n\n        block_3 = self.build_next_block()\n        self.update_witness_block_with_transactions(block_3, [tx, tx2], nonce=1)\n        # Add an extra OP_RETURN output that matches the witness commitment template,\n        # even though it has extra data after the incorrect commitment.\n        # This block should fail.\n        block_3.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, WITNESS_COMMITMENT_HEADER + ser_uint256(2), 10])))\n        block_3.vtx[0].rehash()\n        block_3.hashMerkleRoot = block_3.calc_merkle_root()\n        block_3.rehash()\n        block_3.solve()\n\n        test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)\n\n        # Add a different commitment with different nonce, but in the\n        # right location, and with some funds burned(!).\n        # This should succeed (nValue shouldn't affect finding the\n        # witness commitment).\n        add_witness_commitment(block_3, nonce=0)\n        block_3.vtx[0].vout[0].nValue -= 1\n        block_3.vtx[0].vout[-1].nValue += 1\n        block_3.vtx[0].rehash()\n        block_3.hashMerkleRoot = block_3.calc_merkle_root()\n        block_3.rehash()\n        assert len(block_3.vtx[0].vout) == 4  # 3 OP_returns\n        block_3.solve()\n        test_witness_block(self.nodes[0], self.test_node, block_3, accepted=True)\n\n        # Finally test that a block with no witness transactions can\n        # omit the commitment.\n        block_4 = self.build_next_block()\n        tx3 = CTransaction()\n        tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b\"\"))\n        tx3.vout.append(CTxOut(tx.vout[0].nValue - 1000, witness_program))\n        tx3.rehash()\n        block_4.vtx.append(tx3)\n        block_4.hashMerkleRoot = block_4.calc_merkle_root()\n        block_4.solve()\n        test_witness_block(self.nodes[0], self.test_node, block_4, with_witness=False, accepted=True)\n\n        # Update available utxo's for use in later test.\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))\n\n    @subtest\n    def test_block_malleability(self):\n\n        # Make sure that a block that has too big a virtual size\n        # because of a too-large coinbase witness is not permanently\n        # marked bad.\n        block = self.build_next_block()\n        add_witness_commitment(block)\n        block.solve()\n\n        block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000)\n        assert get_virtual_size(block) > MAX_BLOCK_BASE_SIZE\n\n        # We can't send over the p2p network, because this is too big to relay\n        # TODO: repeat this test with a block that can be relayed\n        self.nodes[0].submitblock(block.serialize(True).hex())\n\n        assert self.nodes[0].getbestblockhash() != block.hash\n\n        block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop()\n        assert get_virtual_size(block) < MAX_BLOCK_BASE_SIZE\n        self.nodes[0].submitblock(block.serialize(True).hex())\n\n        assert self.nodes[0].getbestblockhash() == block.hash\n\n        # Now make sure that malleating the witness reserved value doesn't\n        # result in a block permanently marked bad.\n        block = self.build_next_block()\n        add_witness_commitment(block)\n        block.solve()\n\n        # Change the nonce -- should not cause the block to be permanently\n        # failed\n        block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Changing the witness reserved value doesn't change the block hash\n        block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n    @subtest\n    def test_witness_block_size(self):\n        # TODO: Test that non-witness carrying blocks can't exceed 1MB\n        # Skipping this test for now; this is covered in p2p-fullblocktest.py\n\n        # Test that witness-bearing blocks are limited at ceil(base + wit/4) <= 1MB.\n        block = self.build_next_block()\n\n        assert len(self.utxo) > 0\n\n        # Create a P2WSH transaction.\n        # The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.\n        # This should give us plenty of room to tweak the spending tx's\n        # virtual size.\n        NUM_DROPS = 200  # 201 max ops per script!\n        NUM_OUTPUTS = 50\n\n        witness_program = CScript([OP_2DROP] * NUM_DROPS + [OP_TRUE])\n        witness_hash = uint256_from_str(sha256(witness_program))\n        script_pubkey = CScript([OP_0, ser_uint256(witness_hash)])\n\n        prevout = COutPoint(self.utxo[0].sha256, self.utxo[0].n)\n        value = self.utxo[0].nValue\n\n        parent_tx = CTransaction()\n        parent_tx.vin.append(CTxIn(prevout, b\"\"))\n        child_value = int(value / NUM_OUTPUTS)\n        for i in range(NUM_OUTPUTS):\n            parent_tx.vout.append(CTxOut(child_value, script_pubkey))\n        parent_tx.vout[0].nValue -= 50000\n        assert parent_tx.vout[0].nValue > 0\n        parent_tx.rehash()\n\n        child_tx = CTransaction()\n        for i in range(NUM_OUTPUTS):\n            child_tx.vin.append(CTxIn(COutPoint(parent_tx.sha256, i), b\"\"))\n        child_tx.vout = [CTxOut(value - 100000, CScript([OP_TRUE]))]\n        for i in range(NUM_OUTPUTS):\n            child_tx.wit.vtxinwit.append(CTxInWitness())\n            child_tx.wit.vtxinwit[-1].scriptWitness.stack = [b'a' * 195] * (2 * NUM_DROPS) + [witness_program]\n        child_tx.rehash()\n        self.update_witness_block_with_transactions(block, [parent_tx, child_tx])\n\n        vsize = get_virtual_size(block)\n        additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize) * 4\n        i = 0\n        while additional_bytes > 0:\n            # Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1\n            extra_bytes = min(additional_bytes + 1, 55)\n            block.vtx[-1].wit.vtxinwit[int(i / (2 * NUM_DROPS))].scriptWitness.stack[i % (2 * NUM_DROPS)] = b'a' * (195 + extra_bytes)\n            additional_bytes -= extra_bytes\n            i += 1\n\n        block.vtx[0].vout.pop()  # Remove old commitment\n        add_witness_commitment(block)\n        block.solve()\n        vsize = get_virtual_size(block)\n        assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)\n        # Make sure that our test case would exceed the old max-network-message\n        # limit\n        assert len(block.serialize(True)) > 2 * 1024 * 1024\n\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now resize the second transaction to make the block fit.\n        cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])\n        block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (cur_length - 1)\n        block.vtx[0].vout.pop()\n        add_witness_commitment(block)\n        block.solve()\n        assert get_virtual_size(block) == MAX_BLOCK_BASE_SIZE\n\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Update available utxo's\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue))\n\n    @subtest\n    def test_submit_block(self):\n        \"\"\"Test that submitblock adds the nonce automatically when possible.\"\"\"\n        block = self.build_next_block()\n\n        # Try using a custom nonce and then don't supply it.\n        # This shouldn't possibly work.\n        add_witness_commitment(block, nonce=1)\n        block.vtx[0].wit = CTxWitness()  # drop the nonce\n        block.solve()\n        self.nodes[0].submitblock(block.serialize(True).hex())\n        assert self.nodes[0].getbestblockhash() != block.hash\n\n        # Now redo commitment with the standard nonce, but let Munt-daemon fill it in.\n        add_witness_commitment(block, nonce=0)\n        block.vtx[0].wit = CTxWitness()\n        block.solve()\n        self.nodes[0].submitblock(block.serialize(True).hex())\n        assert_equal(self.nodes[0].getbestblockhash(), block.hash)\n\n        # This time, add a tx with non-empty witness, but don't supply\n        # the commitment.\n        block_2 = self.build_next_block()\n\n        add_witness_commitment(block_2)\n\n        block_2.solve()\n\n        # Drop commitment and nonce -- submitblock should not fill in.\n        block_2.vtx[0].vout.pop()\n        block_2.vtx[0].wit = CTxWitness()\n\n        self.nodes[0].submitblock(block_2.serialize(True).hex())\n        # Tip should not advance!\n        assert self.nodes[0].getbestblockhash() != block_2.hash\n\n    @subtest\n    def test_extra_witness_data(self):\n        \"\"\"Test extra witness data in a transaction.\"\"\"\n\n        block = self.build_next_block()\n\n        witness_program = CScript([OP_DROP, OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        # First try extra witness data on a tx that doesn't require a witness\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 2000, script_pubkey))\n        tx.vout.append(CTxOut(1000, CScript([OP_TRUE])))  # non-witness output\n        tx.wit.vtxinwit.append(CTxInWitness())\n        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([])]\n        tx.rehash()\n        self.update_witness_block_with_transactions(block, [tx])\n\n        # Extra witness data should not be allowed.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Try extra signature data.  Ok if we're not spending a witness output.\n        block.vtx[1].wit.vtxinwit = []\n        block.vtx[1].vin[0].scriptSig = CScript([OP_0])\n        block.vtx[1].rehash()\n        add_witness_commitment(block)\n        block.solve()\n\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Now try extra witness/signature data on an input that DOES require a\n        # witness\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))  # witness output\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 1), b\"\"))  # non-witness\n        tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))\n        tx2.wit.vtxinwit.extend([CTxInWitness(), CTxInWitness()])\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), CScript([CScriptNum(1)]), witness_program]\n        tx2.wit.vtxinwit[1].scriptWitness.stack = [CScript([OP_TRUE])]\n\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx2])\n\n        # This has extra witness data, so it should fail.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now get rid of the extra witness, but add extra scriptSig data\n        tx2.vin[0].scriptSig = CScript([OP_TRUE])\n        tx2.vin[1].scriptSig = CScript([OP_TRUE])\n        tx2.wit.vtxinwit[0].scriptWitness.stack.pop(0)\n        tx2.wit.vtxinwit[1].scriptWitness.stack = []\n        tx2.rehash()\n        add_witness_commitment(block)\n        block.solve()\n\n        # This has extra signature data for a witness input, so it should fail.\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now get rid of the extra scriptsig on the witness input, and verify\n        # success (even with extra scriptsig data in the non-witness input)\n        tx2.vin[0].scriptSig = b\"\"\n        tx2.rehash()\n        add_witness_commitment(block)\n        block.solve()\n\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Update utxo for later tests\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))\n\n    @subtest\n    def test_max_witness_push_length(self):\n        \"\"\"Test that witness stack can only allow up to 520 byte pushes.\"\"\"\n\n        block = self.build_next_block()\n\n        witness_program = CScript([OP_DROP, OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))\n        tx.rehash()\n\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        # First try a 521-byte stack element\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * (MAX_SCRIPT_ELEMENT_SIZE + 1), witness_program]\n        tx2.rehash()\n\n        self.update_witness_block_with_transactions(block, [tx, tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now reduce the length of the stack element\n        tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)\n\n        add_witness_commitment(block)\n        block.solve()\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Update the utxo for later tests\n        self.utxo.pop()\n        self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))\n\n    @subtest\n    def test_max_witness_program_length(self):\n        \"\"\"Test that witness outputs greater than 10kB can't be spent.\"\"\"\n\n        MAX_PROGRAM_LENGTH = 10000\n\n        # This program is 19 max pushes (9937 bytes), then 64 more opcode-bytes.\n        long_witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 63 + [OP_TRUE])\n        assert len(long_witness_program) == MAX_PROGRAM_LENGTH + 1\n        long_witness_hash = sha256(long_witness_program)\n        long_script_pubkey = CScript([OP_0, long_witness_hash])\n\n        block = self.build_next_block()\n\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, long_script_pubkey))\n        tx.rehash()\n\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE])))\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 44 + [long_witness_program]\n        tx2.rehash()\n\n        self.update_witness_block_with_transactions(block, [tx, tx2])\n\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Try again with one less byte in the witness program\n        witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 62 + [OP_TRUE])\n        assert len(witness_program) == MAX_PROGRAM_LENGTH\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        tx.vout[0] = CTxOut(tx.vout[0].nValue, script_pubkey)\n        tx.rehash()\n        tx2.vin[0].prevout.hash = tx.sha256\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a'] * 43 + [witness_program]\n        tx2.rehash()\n        block.vtx = [block.vtx[0]]\n        self.update_witness_block_with_transactions(block, [tx, tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        self.utxo.pop()\n        self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))\n\n    @subtest\n    def test_witness_input_length(self):\n        \"\"\"Test that vin length must match vtxinwit length.\"\"\"\n\n        witness_program = CScript([OP_DROP, OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        # Create a transaction that splits our utxo into many outputs\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        value = self.utxo[0].nValue\n        for i in range(10):\n            tx.vout.append(CTxOut(int(value / 10), script_pubkey))\n        tx.vout[0].nValue -= 1000\n        assert tx.vout[0].nValue >= 0\n\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Try various ways to spend tx that should all break.\n        # This \"broken\" transaction serializer will not normalize\n        # the length of vtxinwit.\n        class BrokenCTransaction(CTransaction):\n            def serialize_with_witness(self):\n                flags = 0\n                if not self.wit.is_null():\n                    flags |= 1\n                r = b\"\"\n                r += struct.pack(\"<i\", self.nVersion)\n                if flags:\n                    dummy = []\n                    r += ser_vector(dummy)\n                    r += struct.pack(\"<B\", flags)\n                r += ser_vector(self.vin)\n                r += ser_vector(self.vout)\n                if flags & 1:\n                    r += self.wit.serialize()\n                r += struct.pack(\"<I\", self.nLockTime)\n                return r\n\n        tx2 = BrokenCTransaction()\n        for i in range(10):\n            tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b\"\"))\n        tx2.vout.append(CTxOut(value - 3000, CScript([OP_TRUE])))\n\n        # First try using a too long vtxinwit\n        for i in range(11):\n            tx2.wit.vtxinwit.append(CTxInWitness())\n            tx2.wit.vtxinwit[i].scriptWitness.stack = [b'a', witness_program]\n\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now try using a too short vtxinwit\n        tx2.wit.vtxinwit.pop()\n        tx2.wit.vtxinwit.pop()\n\n        block.vtx = [block.vtx[0]]\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Now make one of the intermediate witnesses be incorrect\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[-1].scriptWitness.stack = [b'a', witness_program]\n        tx2.wit.vtxinwit[5].scriptWitness.stack = [witness_program]\n\n        block.vtx = [block.vtx[0]]\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Fix the broken witness and the block should be accepted.\n        tx2.wit.vtxinwit[5].scriptWitness.stack = [b'a', witness_program]\n        block.vtx = [block.vtx[0]]\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        self.utxo.pop()\n        self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))\n\n    @subtest\n    def test_tx_relay_after_segwit_activation(self):\n        \"\"\"Test transaction relay after segwit activation.\n\n        After segwit activates, verify that mempool:\n        - rejects transactions with unnecessary/extra witnesses\n        - accepts transactions with valid witnesses\n        and that witness transactions are relayed to non-upgraded peers.\"\"\"\n\n        # Generate a transaction that doesn't require a witness, but send it\n        # with a witness.  Should be rejected because we can't use a witness\n        # when spending a non-witness output.\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n        tx.wit.vtxinwit.append(CTxInWitness())\n        tx.wit.vtxinwit[0].scriptWitness.stack = [b'a']\n        tx.rehash()\n\n        tx_hash = tx.sha256\n\n        # Verify that unnecessary witnesses are rejected.\n        self.test_node.announce_tx_and_wait_for_getdata(tx)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)\n\n        # Verify that removing the witness succeeds.\n        self.test_node.announce_tx_and_wait_for_getdata(tx)\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)\n\n        # Now try to add extra witness data to a valid witness tx.\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx_hash, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))\n        tx2.rehash()\n\n        tx3 = CTransaction()\n        tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b\"\"))\n        tx3.wit.vtxinwit.append(CTxInWitness())\n\n        # Add too-large for IsStandard witness and check that it does not enter reject filter\n        p2sh_program = CScript([OP_TRUE])\n        p2sh_pubkey = hash160(p2sh_program)\n        witness_program2 = CScript([b'a' * 400000])\n        tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))\n        tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2]\n        tx3.rehash()\n\n        # Node will not be blinded to the transaction\n        self.std_node.announce_tx_and_wait_for_getdata(tx3)\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')\n        self.std_node.announce_tx_and_wait_for_getdata(tx3)\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')\n\n        # Remove witness stuffing, instead add extra witness push on stack\n        tx3.vout[0] = CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))\n        tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program]\n        tx3.rehash()\n\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False)\n\n        # Get rid of the extra witness, and verify acceptance.\n        tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        # Also check that old_node gets a tx announcement, even though this is\n        # a witness transaction.\n        self.old_node.wait_for_inv([CInv(1, tx2.sha256)])  # wait until tx2 was inv'ed\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)\n        self.old_node.wait_for_inv([CInv(1, tx3.sha256)])\n\n        # Test that getrawtransaction returns correct witness information\n        # hash, size, vsize\n        raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1)\n        assert_equal(int(raw_tx[\"hash\"], 16), tx3.calc_sha256(True))\n        assert_equal(raw_tx[\"size\"], len(tx3.serialize_with_witness()))\n        weight = len(tx3.serialize_with_witness()) + 3 * len(tx3.serialize_without_witness())\n        vsize = math.ceil(weight / 4)\n        assert_equal(raw_tx[\"vsize\"], vsize)\n        assert_equal(raw_tx[\"weight\"], weight)\n        assert_equal(len(raw_tx[\"vin\"][0][\"txinwitness\"]), 1)\n        assert_equal(raw_tx[\"vin\"][0][\"txinwitness\"][0], witness_program.hex())\n        assert vsize != raw_tx[\"size\"]\n\n        # Cleanup: mine the transactions and update utxo for next test\n        self.nodes[0].generate(1)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))\n\n    @subtest\n    def test_segwit_versions(self):\n        \"\"\"Test validity of future segwit version transactions.\n\n        Future segwit version transactions are non-standard, but valid in blocks.\n        Can run this before and after segwit activation.\"\"\"\n\n        NUM_SEGWIT_VERSIONS = 17  # will test OP_0, OP1, ..., OP_16\n        if len(self.utxo) < NUM_SEGWIT_VERSIONS:\n            tx = CTransaction()\n            tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n            split_value = (self.utxo[0].nValue - 4000) // NUM_SEGWIT_VERSIONS\n            for i in range(NUM_SEGWIT_VERSIONS):\n                tx.vout.append(CTxOut(split_value, CScript([OP_TRUE])))\n            tx.rehash()\n            block = self.build_next_block()\n            self.update_witness_block_with_transactions(block, [tx])\n            test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n            self.utxo.pop(0)\n            for i in range(NUM_SEGWIT_VERSIONS):\n                self.utxo.append(UTXO(tx.sha256, i, split_value))\n\n        sync_blocks(self.nodes)\n        temp_utxo = []\n        tx = CTransaction()\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n        for version in list(range(OP_1, OP_16 + 1)) + [OP_0]:\n            # First try to spend to a future version segwit script_pubkey.\n            script_pubkey = CScript([CScriptOp(version), witness_hash])\n            tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\")]\n            tx.vout = [CTxOut(self.utxo[0].nValue - 1000, script_pubkey)]\n            tx.rehash()\n            test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=False)\n            test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)\n            self.utxo.pop(0)\n            temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))\n\n        self.nodes[0].generate(1)  # Mine all the transactions\n        sync_blocks(self.nodes)\n        assert len(self.nodes[0].getrawmempool()) == 0\n\n        # Finally, verify that version 0 -> version 1 transactions\n        # are non-standard\n        script_pubkey = CScript([CScriptOp(OP_1), witness_hash])\n        tx2 = CTransaction()\n        tx2.vin = [CTxIn(COutPoint(tx.sha256, 0), b\"\")]\n        tx2.vout = [CTxOut(tx.vout[0].nValue - 1000, script_pubkey)]\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        tx2.rehash()\n        # Gets accepted to test_node, because standardness of outputs isn't\n        # checked with fRequireStandard\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=False)\n        temp_utxo.pop()  # last entry in temp_utxo was the output we just spent\n        temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))\n\n        # Spend everything in temp_utxo back to an OP_TRUE output.\n        tx3 = CTransaction()\n        total_value = 0\n        for i in temp_utxo:\n            tx3.vin.append(CTxIn(COutPoint(i.sha256, i.n), b\"\"))\n            tx3.wit.vtxinwit.append(CTxInWitness())\n            total_value += i.nValue\n        tx3.wit.vtxinwit[-1].scriptWitness.stack = [witness_program]\n        tx3.vout.append(CTxOut(total_value - 1000, CScript([OP_TRUE])))\n        tx3.rehash()\n        # Spending a higher version witness output is not allowed by policy,\n        # even with fRequireStandard=false.\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason=\"reserved for soft-fork upgrades\")\n\n        # Building a block with the transaction must be valid, however.\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx2, tx3])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n        sync_blocks(self.nodes)\n\n        # Add utxo to our list\n        self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))\n\n    @subtest\n    def test_premature_coinbase_witness_spend(self):\n\n        block = self.build_next_block()\n        # Change the output of the block to be a witness output.\n        witness_program = CScript([OP_TRUE])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n        block.vtx[0].vout[0].scriptPubKey = script_pubkey\n        # This next line will rehash the coinbase and update the merkle\n        # root, and solve.\n        self.update_witness_block_with_transactions(block, [])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        spend_tx = CTransaction()\n        spend_tx.vin = [CTxIn(COutPoint(block.vtx[0].sha256, 0), b\"\")]\n        spend_tx.vout = [CTxOut(block.vtx[0].vout[0].nValue, witness_program)]\n        spend_tx.wit.vtxinwit.append(CTxInWitness())\n        spend_tx.wit.vtxinwit[0].scriptWitness.stack = [witness_program]\n        spend_tx.rehash()\n\n        # Now test a premature spend.\n        self.nodes[0].generate(98)\n        sync_blocks(self.nodes)\n        block2 = self.build_next_block()\n        self.update_witness_block_with_transactions(block2, [spend_tx])\n        test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)\n\n        # Advancing one more block should allow the spend.\n        self.nodes[0].generate(1)\n        block2 = self.build_next_block()\n        self.update_witness_block_with_transactions(block2, [spend_tx])\n        test_witness_block(self.nodes[0], self.test_node, block2, accepted=True)\n        sync_blocks(self.nodes)\n\n    @subtest\n    def test_uncompressed_pubkey(self):\n        \"\"\"Test uncompressed pubkey validity in segwit transactions.\n\n        Uncompressed pubkeys are no longer supported in default relay policy,\n        but (for now) are still valid in blocks.\"\"\"\n\n        # Segwit transactions using uncompressed pubkeys are not accepted\n        # under default policy, but should still pass consensus.\n        key = CECKey()\n        key.set_secretbytes(b\"9\")\n        key.set_compressed(False)\n        pubkey = CPubKey(key.get_pubkey())\n        assert_equal(len(pubkey), 65)  # This should be an uncompressed pubkey\n\n        utxo = self.utxo.pop(0)\n\n        # Test 1: P2WPKH\n        # First create a P2WPKH output that uses an uncompressed pubkey\n        pubkeyhash = hash160(pubkey)\n        script_pkh = CScript([OP_0, pubkeyhash])\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(utxo.sha256, utxo.n), b\"\"))\n        tx.vout.append(CTxOut(utxo.nValue - 1000, script_pkh))\n        tx.rehash()\n\n        # Confirm it in a block.\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Now try to spend it. Send it to a P2WSH output, which we'll\n        # use in the next test.\n        witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])\n        witness_hash = sha256(witness_program)\n        script_wsh = CScript([OP_0, witness_hash])\n\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_wsh))\n        script = get_p2pkh_script(pubkeyhash)\n        sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)\n        signature = key.sign(sig_hash) + b'\\x01'  # 0x1 is SIGHASH_ALL\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey]\n        tx2.rehash()\n\n        # Should fail policy test.\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx2, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')\n        # But passes consensus.\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Test 2: P2WSH\n        # Try to spend the P2WSH output created in last test.\n        # Send it to a P2SH(P2WSH) output, which we'll use in the next test.\n        p2sh_witness_hash = hash160(script_wsh)\n        script_p2sh = CScript([OP_HASH160, p2sh_witness_hash, OP_EQUAL])\n        script_sig = CScript([script_wsh])\n\n        tx3 = CTransaction()\n        tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b\"\"))\n        tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, script_p2sh))\n        tx3.wit.vtxinwit.append(CTxInWitness())\n        sign_p2pk_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)\n\n        # Should fail policy test.\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')\n        # But passes consensus.\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx3])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Test 3: P2SH(P2WSH)\n        # Try to spend the P2SH output created in the last test.\n        # Send it to a P2PKH output, which we'll use in the next test.\n        script_pubkey = get_p2pkh_script(pubkeyhash)\n        tx4 = CTransaction()\n        tx4.vin.append(CTxIn(COutPoint(tx3.sha256, 0), script_sig))\n        tx4.vout.append(CTxOut(tx3.vout[0].nValue - 1000, script_pubkey))\n        tx4.wit.vtxinwit.append(CTxInWitness())\n        sign_p2pk_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)\n\n        # Should fail policy test.\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx4, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx4])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Test 4: Uncompressed pubkeys should still be valid in non-segwit\n        # transactions.\n        tx5 = CTransaction()\n        tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b\"\"))\n        tx5.vout.append(CTxOut(tx4.vout[0].nValue - 1000, CScript([OP_TRUE])))\n        (sig_hash, err) = SignatureHash(script_pubkey, tx5, 0, SIGHASH_ALL)\n        signature = key.sign(sig_hash) + b'\\x01'  # 0x1 is SIGHASH_ALL\n        tx5.vin[0].scriptSig = CScript([signature, pubkey])\n        tx5.rehash()\n        # Should pass policy and consensus.\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx5, True, True)\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx5])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n        self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))\n\n    @subtest\n    def test_signature_version_1(self):\n\n        key = CECKey()\n        key.set_secretbytes(b\"9\")\n        pubkey = CPubKey(key.get_pubkey())\n\n        witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        # First create a witness output for use in the tests.\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))\n        tx.rehash()\n\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)\n        # Mine this transaction in preparation for following tests.\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n        sync_blocks(self.nodes)\n        self.utxo.pop(0)\n\n        # Test each hashtype\n        prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)\n        for sigflag in [0, SIGHASH_ANYONECANPAY]:\n            for hashtype in [SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE]:\n                hashtype |= sigflag\n                block = self.build_next_block()\n                tx = CTransaction()\n                tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b\"\"))\n                tx.vout.append(CTxOut(prev_utxo.nValue - 1000, script_pubkey))\n                tx.wit.vtxinwit.append(CTxInWitness())\n                # Too-large input value\n                sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue + 1, key)\n                self.update_witness_block_with_transactions(block, [tx])\n                test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n                # Too-small input value\n                sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue - 1, key)\n                block.vtx.pop()  # remove last tx\n                self.update_witness_block_with_transactions(block, [tx])\n                test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n                # Now try correct value\n                sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)\n                block.vtx.pop()\n                self.update_witness_block_with_transactions(block, [tx])\n                test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n                prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)\n\n        # Test combinations of signature hashes.\n        # Split the utxo into a lot of outputs.\n        # Randomly choose up to 10 to spend, sign with different hashtypes, and\n        # output to a random number of outputs.  Repeat NUM_SIGHASH_TESTS times.\n        # Ensure that we've tested a situation where we use SIGHASH_SINGLE with\n        # an input index > number of outputs.\n        NUM_SIGHASH_TESTS = 500\n        temp_utxos = []\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(prev_utxo.sha256, prev_utxo.n), b\"\"))\n        split_value = prev_utxo.nValue // NUM_SIGHASH_TESTS\n        for i in range(NUM_SIGHASH_TESTS):\n            tx.vout.append(CTxOut(split_value, script_pubkey))\n        tx.wit.vtxinwit.append(CTxInWitness())\n        sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, prev_utxo.nValue, key)\n        for i in range(NUM_SIGHASH_TESTS):\n            temp_utxos.append(UTXO(tx.sha256, i, split_value))\n\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        block = self.build_next_block()\n        used_sighash_single_out_of_bounds = False\n        for i in range(NUM_SIGHASH_TESTS):\n            # Ping regularly to keep the connection alive\n            if (not i % 100):\n                self.test_node.sync_with_ping()\n            # Choose random number of inputs to use.\n            num_inputs = random.randint(1, 10)\n            # Create a slight bias for producing more utxos\n            num_outputs = random.randint(1, 11)\n            random.shuffle(temp_utxos)\n            assert len(temp_utxos) > num_inputs\n            tx = CTransaction()\n            total_value = 0\n            for i in range(num_inputs):\n                tx.vin.append(CTxIn(COutPoint(temp_utxos[i].sha256, temp_utxos[i].n), b\"\"))\n                tx.wit.vtxinwit.append(CTxInWitness())\n                total_value += temp_utxos[i].nValue\n            split_value = total_value // num_outputs\n            for i in range(num_outputs):\n                tx.vout.append(CTxOut(split_value, script_pubkey))\n            for i in range(num_inputs):\n                # Now try to sign each input, using a random hashtype.\n                anyonecanpay = 0\n                if random.randint(0, 1):\n                    anyonecanpay = SIGHASH_ANYONECANPAY\n                hashtype = random.randint(1, 3) | anyonecanpay\n                sign_p2pk_witness_input(witness_program, tx, i, hashtype, temp_utxos[i].nValue, key)\n                if (hashtype == SIGHASH_SINGLE and i >= num_outputs):\n                    used_sighash_single_out_of_bounds = True\n            tx.rehash()\n            for i in range(num_outputs):\n                temp_utxos.append(UTXO(tx.sha256, i, split_value))\n            temp_utxos = temp_utxos[num_inputs:]\n\n            block.vtx.append(tx)\n\n            # Test the block periodically, if we're close to maxblocksize\n            if (get_virtual_size(block) > MAX_BLOCK_BASE_SIZE - 1000):\n                self.update_witness_block_with_transactions(block, [])\n                test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n                block = self.build_next_block()\n\n        if (not used_sighash_single_out_of_bounds):\n            self.log.info(\"WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value\")\n        # Test the transactions we've added to the block\n        if (len(block.vtx) > 1):\n            self.update_witness_block_with_transactions(block, [])\n            test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        # Now test witness version 0 P2PKH transactions\n        pubkeyhash = hash160(pubkey)\n        script_pkh = CScript([OP_0, pubkeyhash])\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(temp_utxos[0].sha256, temp_utxos[0].n), b\"\"))\n        tx.vout.append(CTxOut(temp_utxos[0].nValue, script_pkh))\n        tx.wit.vtxinwit.append(CTxInWitness())\n        sign_p2pk_witness_input(witness_program, tx, 0, SIGHASH_ALL, temp_utxos[0].nValue, key)\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b\"\"))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE])))\n\n        script = get_p2pkh_script(pubkeyhash)\n        sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)\n        signature = key.sign(sig_hash) + b'\\x01'  # 0x1 is SIGHASH_ALL\n\n        # Check that we can't have a scriptSig\n        tx2.vin[0].scriptSig = CScript([signature, pubkey])\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx, tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=False)\n\n        # Move the signature to the witness.\n        block.vtx.pop()\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey]\n        tx2.vin[0].scriptSig = b\"\"\n        tx2.rehash()\n\n        self.update_witness_block_with_transactions(block, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        temp_utxos.pop(0)\n\n        # Update self.utxos for later tests by creating two outputs\n        # that consolidate all the coins in temp_utxos.\n        output_value = sum(i.nValue for i in temp_utxos) // 2\n\n        tx = CTransaction()\n        index = 0\n        # Just spend to our usual anyone-can-spend output\n        tx.vout = [CTxOut(output_value, CScript([OP_TRUE]))] * 2\n        for i in temp_utxos:\n            # Use SIGHASH_ALL|SIGHASH_ANYONECANPAY so we can build up\n            # the signatures as we go.\n            tx.vin.append(CTxIn(COutPoint(i.sha256, i.n), b\"\"))\n            tx.wit.vtxinwit.append(CTxInWitness())\n            sign_p2pk_witness_input(witness_program, tx, index, SIGHASH_ALL | SIGHASH_ANYONECANPAY, i.nValue, key)\n            index += 1\n        block = self.build_next_block()\n        self.update_witness_block_with_transactions(block, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)\n\n        for i in range(len(tx.vout)):\n            self.utxo.append(UTXO(tx.sha256, i, tx.vout[i].nValue))\n\n    @subtest\n    def test_non_standard_witness_blinding(self):\n        \"\"\"Test behavior of unnecessary witnesses in transactions does not blind the node for the transaction\"\"\"\n\n        # Create a p2sh output -- this is so we can pass the standardness\n        # rules (an anyone-can-spend OP_TRUE would be rejected, if not wrapped\n        # in P2SH).\n        p2sh_program = CScript([OP_TRUE])\n        p2sh_pubkey = hash160(p2sh_program)\n        script_pubkey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])\n\n        # Now check that unnecessary witnesses can't be used to blind a node\n        # to a transaction, eg by violating standardness checks.\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))\n        tx.rehash()\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, False, True)\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # We'll add an unnecessary witness to this transaction that would cause\n        # it to be non-standard, to test that violating policy with a witness\n        # doesn't blind a node to a transaction.  Transactions\n        # rejected for having a witness shouldn't be added\n        # to the rejection cache.\n        tx2 = CTransaction()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), CScript([p2sh_program])))\n        tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[0].scriptWitness.stack = [b'a' * 400]\n        tx2.rehash()\n        # This will be rejected due to a policy check:\n        # No witness is allowed, since it is not a witness program but a p2sh program\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx2, True, False, 'bad-witness-nonstandard')\n\n        # If we send without witness, it should be accepted.\n        test_transaction_acceptance(self.nodes[1], self.std_node, tx2, False, True)\n\n        # Now create a new anyone-can-spend utxo for the next test.\n        tx3 = CTransaction()\n        tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))\n        tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))\n        tx3.rehash()\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx2, False, True)\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx3, False, True)\n\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # Update our utxo list; we spent the first entry.\n        self.utxo.pop(0)\n        self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))\n\n    @subtest\n    def test_non_standard_witness(self):\n        \"\"\"Test detection of non-standard P2WSH witness\"\"\"\n        pad = chr(1).encode('latin-1')\n\n        # Create scripts for tests\n        scripts = []\n        scripts.append(CScript([OP_DROP] * 100))\n        scripts.append(CScript([OP_DROP] * 99))\n        scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 60))\n        scripts.append(CScript([pad * 59] * 59 + [OP_DROP] * 61))\n\n        p2wsh_scripts = []\n\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n\n        # For each script, generate a pair of P2WSH and P2SH-P2WSH output.\n        outputvalue = (self.utxo[0].nValue - 1000) // (len(scripts) * 2)\n        for i in scripts:\n            p2wsh = CScript([OP_0, sha256(i)])\n            p2sh = hash160(p2wsh)\n            p2wsh_scripts.append(p2wsh)\n            tx.vout.append(CTxOut(outputvalue, p2wsh))\n            tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))\n        tx.rehash()\n        txid = tx.sha256\n        test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)\n\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # Creating transactions for tests\n        p2wsh_txs = []\n        p2sh_txs = []\n        for i in range(len(scripts)):\n            p2wsh_tx = CTransaction()\n            p2wsh_tx.vin.append(CTxIn(COutPoint(txid, i * 2)))\n            p2wsh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(\"\"))])))\n            p2wsh_tx.wit.vtxinwit.append(CTxInWitness())\n            p2wsh_tx.rehash()\n            p2wsh_txs.append(p2wsh_tx)\n            p2sh_tx = CTransaction()\n            p2sh_tx.vin.append(CTxIn(COutPoint(txid, i * 2 + 1), CScript([p2wsh_scripts[i]])))\n            p2sh_tx.vout.append(CTxOut(outputvalue - 5000, CScript([OP_0, hash160(hex_str_to_bytes(\"\"))])))\n            p2sh_tx.wit.vtxinwit.append(CTxInWitness())\n            p2sh_tx.rehash()\n            p2sh_txs.append(p2sh_tx)\n\n        # Testing native P2WSH\n        # Witness stack size, excluding witnessScript, over 100 is non-standard\n        p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[0], True, False, 'bad-witness-nonstandard')\n        # Non-standard nodes should accept\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[0], True, True)\n\n        # Stack element size over 80 bytes is non-standard\n        p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, False, 'bad-witness-nonstandard')\n        # Non-standard nodes should accept\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[1], True, True)\n        # Standard nodes should accept if element size is not over 80 bytes\n        p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, True)\n\n        # witnessScript size at 3600 bytes is standard\n        p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[2], True, True)\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[2], True, True)\n\n        # witnessScript size at 3601 bytes is non-standard\n        p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[3], True, False, 'bad-witness-nonstandard')\n        # Non-standard nodes should accept\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[3], True, True)\n\n        # Repeating the same tests with P2SH-P2WSH\n        p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[0], True, False, 'bad-witness-nonstandard')\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[0], True, True)\n        p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, False, 'bad-witness-nonstandard')\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[1], True, True)\n        p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, True)\n        p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[2], True, True)\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[2], True, True)\n        p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]\n        test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[3], True, False, 'bad-witness-nonstandard')\n        test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[3], True, True)\n\n        self.nodes[0].generate(1)  # Mine and clean up the mempool of non-standard node\n        # Valid but non-standard transactions in a block should be accepted by standard node\n        sync_blocks(self.nodes)\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n\n        self.utxo.pop(0)\n\n    @subtest\n    def test_upgrade_after_activation(self):\n        \"\"\"Test the behavior of starting up a segwit-aware node after the softfork has activated.\"\"\"\n\n        # Restart with the new binary\n        self.stop_node(2)\n        self.start_node(2, extra_args=[\"-vbparams=segwit:0:999999999999\"])\n        connect_nodes(self.nodes[0], 2)\n\n        sync_blocks(self.nodes)\n\n        # Make sure that this peer thinks segwit has activated.\n        assert get_bip9_status(self.nodes[2], 'segwit')['status'] == \"active\"\n\n        # Make sure this peer's blocks match those of node0.\n        height = self.nodes[2].getblockcount()\n        while height >= 0:\n            block_hash = self.nodes[2].getblockhash(height)\n            assert_equal(block_hash, self.nodes[0].getblockhash(height))\n            assert_equal(self.nodes[0].getblock(block_hash), self.nodes[2].getblock(block_hash))\n            height -= 1\n\n    @subtest\n    def test_witness_sigops(self):\n        \"\"\"Test sigop counting is correct inside witnesses.\"\"\"\n\n        # Keep this under MAX_OPS_PER_SCRIPT (201)\n        witness_program = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKMULTISIG] * 5 + [OP_CHECKSIG] * 193 + [OP_ENDIF])\n        witness_hash = sha256(witness_program)\n        script_pubkey = CScript([OP_0, witness_hash])\n\n        sigops_per_script = 20 * 5 + 193 * 1\n        # We'll produce 2 extra outputs, one with a program that would take us\n        # over max sig ops, and one with a program that would exactly reach max\n        # sig ops\n        outputs = (MAX_SIGOP_COST // sigops_per_script) + 2\n        extra_sigops_available = MAX_SIGOP_COST % sigops_per_script\n\n        # We chose the number of checkmultisigs/checksigs to make this work:\n        assert extra_sigops_available < 100  # steer clear of MAX_OPS_PER_SCRIPT\n\n        # This script, when spent with the first\n        # N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,\n        # would push us just over the block sigop limit.\n        witness_program_toomany = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available + 1) + [OP_ENDIF])\n        witness_hash_toomany = sha256(witness_program_toomany)\n        script_pubkey_toomany = CScript([OP_0, witness_hash_toomany])\n\n        # If we spend this script instead, we would exactly reach our sigop\n        # limit (for witness sigops).\n        witness_program_justright = CScript([OP_TRUE, OP_IF, OP_TRUE, OP_ELSE] + [OP_CHECKSIG] * (extra_sigops_available) + [OP_ENDIF])\n        witness_hash_justright = sha256(witness_program_justright)\n        script_pubkey_justright = CScript([OP_0, witness_hash_justright])\n\n        # First split our available utxo into a bunch of outputs\n        split_value = self.utxo[0].nValue // outputs\n        tx = CTransaction()\n        tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b\"\"))\n        for i in range(outputs):\n            tx.vout.append(CTxOut(split_value, script_pubkey))\n        tx.vout[-2].scriptPubKey = script_pubkey_toomany\n        tx.vout[-1].scriptPubKey = script_pubkey_justright\n        tx.rehash()\n\n        block_1 = self.build_next_block()\n        self.update_witness_block_with_transactions(block_1, [tx])\n        test_witness_block(self.nodes[0], self.test_node, block_1, accepted=True)\n\n        tx2 = CTransaction()\n        # If we try to spend the first n-1 outputs from tx, that should be\n        # too many sigops.\n        total_value = 0\n        for i in range(outputs - 1):\n            tx2.vin.append(CTxIn(COutPoint(tx.sha256, i), b\"\"))\n            tx2.wit.vtxinwit.append(CTxInWitness())\n            tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program]\n            total_value += tx.vout[i].nValue\n        tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_toomany]\n        tx2.vout.append(CTxOut(total_value, CScript([OP_TRUE])))\n        tx2.rehash()\n\n        block_2 = self.build_next_block()\n        self.update_witness_block_with_transactions(block_2, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False)\n\n        # Try dropping the last input in tx2, and add an output that has\n        # too many sigops (contributing to legacy sigop count).\n        checksig_count = (extra_sigops_available // 4) + 1\n        script_pubkey_checksigs = CScript([OP_CHECKSIG] * checksig_count)\n        tx2.vout.append(CTxOut(0, script_pubkey_checksigs))\n        tx2.vin.pop()\n        tx2.wit.vtxinwit.pop()\n        tx2.vout[0].nValue -= tx.vout[-2].nValue\n        tx2.rehash()\n        block_3 = self.build_next_block()\n        self.update_witness_block_with_transactions(block_3, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)\n\n        # If we drop the last checksig in this output, the tx should succeed.\n        block_4 = self.build_next_block()\n        tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG] * (checksig_count - 1))\n        tx2.rehash()\n        self.update_witness_block_with_transactions(block_4, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block_4, accepted=True)\n\n        # Reset the tip back down for the next test\n        sync_blocks(self.nodes)\n        for x in self.nodes:\n            x.invalidateblock(block_4.hash)\n\n        # Try replacing the last input of tx2 to be spending the last\n        # output of tx\n        block_5 = self.build_next_block()\n        tx2.vout.pop()\n        tx2.vin.append(CTxIn(COutPoint(tx.sha256, outputs - 1), b\"\"))\n        tx2.wit.vtxinwit.append(CTxInWitness())\n        tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_justright]\n        tx2.rehash()\n        self.update_witness_block_with_transactions(block_5, [tx2])\n        test_witness_block(self.nodes[0], self.test_node, block_5, accepted=True)\n\n        # TODO: test p2sh sigop counting\n\nif __name__ == '__main__':\n    SegWitTest().main()\n"
  },
  {
    "path": "test/functional/p2p_sendheaders.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test behavior of headers messages to announce blocks.\n\nSetup:\n\n- Two nodes:\n    - node0 is the node-under-test. We create two p2p connections to it. The\n      first p2p connection is a control and should only ever receive inv's. The\n      second p2p connection tests the headers sending logic.\n    - node1 is used to create reorgs.\n\ntest_null_locators\n==================\n\nSends two getheaders requests with null locator values. First request's hashstop\nvalue refers to validated block, while second request's hashstop value refers to\na block which hasn't been validated. Verifies only the first request returns\nheaders.\n\ntest_nonnull_locators\n=====================\n\nPart 1: No headers announcements before \"sendheaders\"\na. node mines a block [expect: inv]\n   send getdata for the block [expect: block]\nb. node mines another block [expect: inv]\n   send getheaders and getdata [expect: headers, then block]\nc. node mines another block [expect: inv]\n   peer mines a block, announces with header [expect: getdata]\nd. node mines another block [expect: inv]\n\nPart 2: After \"sendheaders\", headers announcements should generally work.\na. peer sends sendheaders [expect: no response]\n   peer sends getheaders with current tip [expect: no response]\nb. node mines a block [expect: tip header]\nc. for N in 1, ..., 10:\n   * for announce-type in {inv, header}\n     - peer mines N blocks, announces with announce-type\n       [ expect: getheaders/getdata or getdata, deliver block(s) ]\n     - node mines a block [ expect: 1 header ]\n\nPart 3: Headers announcements stop after large reorg and resume after getheaders or inv from peer.\n- For response-type in {inv, getheaders}\n  * node mines a 7 block reorg [ expect: headers announcement of 8 blocks ]\n  * node mines an 8-block reorg [ expect: inv at tip ]\n  * peer responds with getblocks/getdata [expect: inv, blocks ]\n  * node mines another block [ expect: inv at tip, peer sends getdata, expect: block ]\n  * node mines another block at tip [ expect: inv ]\n  * peer responds with getheaders with an old hashstop more than 8 blocks back [expect: headers]\n  * peer requests block [ expect: block ]\n  * node mines another block at tip [ expect: inv, peer sends getdata, expect: block ]\n  * peer sends response-type [expect headers if getheaders, getheaders/getdata if mining new block]\n  * node mines 1 block [expect: 1 header, peer responds with getdata]\n\nPart 4: Test direct fetch behavior\na. Announce 2 old block headers.\n   Expect: no getdata requests.\nb. Announce 3 new blocks via 1 headers message.\n   Expect: one getdata request for all 3 blocks.\n   (Send blocks.)\nc. Announce 1 header that forks off the last two blocks.\n   Expect: no response.\nd. Announce 1 more header that builds on that fork.\n   Expect: one getdata request for two blocks.\ne. Announce 16 more headers that build on that fork.\n   Expect: getdata request for 14 more blocks.\nf. Announce 1 more header that builds on that fork.\n   Expect: no response.\n\nPart 5: Test handling of headers that don't connect.\na. Repeat 10 times:\n   1. Announce a header that doesn't connect.\n      Expect: getheaders message\n   2. Send headers chain.\n      Expect: getdata for the missing blocks, tip update.\nb. Then send 9 more headers that don't connect.\n   Expect: getheaders message each time.\nc. Announce a header that does connect.\n   Expect: no response.\nd. Announce 49 headers that don't connect.\n   Expect: getheaders message each time.\ne. Announce one more that doesn't connect.\n   Expect: disconnect.\n\"\"\"\nfrom test_framework.blocktools import create_block, create_coinbase\nfrom test_framework.messages import CInv\nfrom test_framework.mininode import (\n    CBlockHeader,\n    NODE_WITNESS,\n    P2PInterface,\n    mininode_lock,\n    msg_block,\n    msg_getblocks,\n    msg_getdata,\n    msg_getheaders,\n    msg_headers,\n    msg_inv,\n    msg_sendheaders,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    sync_blocks,\n    wait_until,\n)\n\nDIRECT_FETCH_RESPONSE_TIME = 0.05\n\nclass BaseNode(P2PInterface):\n    def __init__(self):\n        super().__init__()\n\n        self.block_announced = False\n        self.last_blockhash_announced = None\n        self.recent_headers_announced = []\n\n    def send_get_data(self, block_hashes):\n        \"\"\"Request data for a list of block hashes.\"\"\"\n        msg = msg_getdata()\n        for x in block_hashes:\n            msg.inv.append(CInv(2, x))\n        self.send_message(msg)\n\n    def send_get_headers(self, locator, hashstop):\n        msg = msg_getheaders()\n        msg.locator.vHave = locator\n        msg.hashstop = hashstop\n        self.send_message(msg)\n\n    def send_block_inv(self, blockhash):\n        msg = msg_inv()\n        msg.inv = [CInv(2, blockhash)]\n        self.send_message(msg)\n\n    def send_header_for_blocks(self, new_blocks):\n        headers_message = msg_headers()\n        headers_message.headers = [CBlockHeader(b) for b in new_blocks]\n        self.send_message(headers_message)\n\n    def send_getblocks(self, locator):\n        getblocks_message = msg_getblocks()\n        getblocks_message.locator.vHave = locator\n        self.send_message(getblocks_message)\n\n    def wait_for_getdata(self, hash_list, timeout=60):\n        if hash_list == []:\n            return\n\n        test_function = lambda: \"getdata\" in self.last_message and [x.hash for x in self.last_message[\"getdata\"].inv] == hash_list\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_block_announcement(self, block_hash, timeout=60):\n        test_function = lambda: self.last_blockhash_announced == block_hash\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def on_inv(self, message):\n        self.block_announced = True\n        self.last_blockhash_announced = message.inv[-1].hash\n\n    def on_headers(self, message):\n        if len(message.headers):\n            self.block_announced = True\n            for x in message.headers:\n                x.calc_sha256()\n                # append because headers may be announced over multiple messages.\n                self.recent_headers_announced.append(x.sha256)\n            self.last_blockhash_announced = message.headers[-1].sha256\n\n    def clear_block_announcements(self):\n        with mininode_lock:\n            self.block_announced = False\n            self.last_message.pop(\"inv\", None)\n            self.last_message.pop(\"headers\", None)\n            self.recent_headers_announced = []\n\n\n    def check_last_headers_announcement(self, headers):\n        \"\"\"Test whether the last headers announcements received are right.\n           Headers may be announced across more than one message.\"\"\"\n        test_function = lambda: (len(self.recent_headers_announced) >= len(headers))\n        wait_until(test_function, timeout=60, lock=mininode_lock)\n        with mininode_lock:\n            assert_equal(self.recent_headers_announced, headers)\n            self.block_announced = False\n            self.last_message.pop(\"headers\", None)\n            self.recent_headers_announced = []\n\n    def check_last_inv_announcement(self, inv):\n        \"\"\"Test whether the last announcement received had the right inv.\n        inv should be a list of block hashes.\"\"\"\n\n        test_function = lambda: self.block_announced\n        wait_until(test_function, timeout=60, lock=mininode_lock)\n\n        with mininode_lock:\n            compare_inv = []\n            if \"inv\" in self.last_message:\n                compare_inv = [x.hash for x in self.last_message[\"inv\"].inv]\n            assert_equal(compare_inv, inv)\n            self.block_announced = False\n            self.last_message.pop(\"inv\", None)\n\nclass SendHeadersTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n\n    def mine_blocks(self, count):\n        \"\"\"Mine count blocks and return the new tip.\"\"\"\n\n        # Clear out block announcements from each p2p listener\n        [x.clear_block_announcements() for x in self.nodes[0].p2ps]\n        self.nodes[0].generatetoaddress(count, self.nodes[0].get_deterministic_priv_key().address)\n        return int(self.nodes[0].getbestblockhash(), 16)\n\n    def mine_reorg(self, length):\n        \"\"\"Mine a reorg that invalidates length blocks (replacing them with # length+1 blocks).\n\n        Note: we clear the state of our p2p connections after the\n        to-be-reorged-out blocks are mined, so that we don't break later tests.\n        return the list of block hashes newly mined.\"\"\"\n\n        # make sure all invalidated blocks are node0's\n        self.nodes[0].generatetoaddress(length, self.nodes[0].get_deterministic_priv_key().address)\n        sync_blocks(self.nodes, wait=0.1)\n        for x in self.nodes[0].p2ps:\n            x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))\n            x.clear_block_announcements()\n\n        tip_height = self.nodes[1].getblockcount()\n        hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))\n        self.nodes[1].invalidateblock(hash_to_invalidate)\n        all_hashes = self.nodes[1].generatetoaddress(length + 1, self.nodes[1].get_deterministic_priv_key().address)  # Must be longer than the orig chain\n        sync_blocks(self.nodes, wait=0.1)\n        return [int(x, 16) for x in all_hashes]\n\n    def run_test(self):\n        # Setup the p2p connections\n        inv_node = self.nodes[0].add_p2p_connection(BaseNode())\n        # Make sure NODE_NETWORK is not set for test_node, so no block download\n        # will occur outside of direct fetching\n        test_node = self.nodes[0].add_p2p_connection(BaseNode(), services=NODE_WITNESS)\n\n        # Ensure verack's have been processed by our peer\n        inv_node.sync_with_ping()\n        test_node.sync_with_ping()\n\n        self.test_null_locators(test_node, inv_node)\n        self.test_nonnull_locators(test_node, inv_node)\n\n    def test_null_locators(self, test_node, inv_node):\n        tip = self.nodes[0].getblockheader(self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0])\n        tip_hash = int(tip[\"hash\"], 16)\n\n        inv_node.check_last_inv_announcement(inv=[tip_hash])\n        test_node.check_last_inv_announcement(inv=[tip_hash])\n\n        self.log.info(\"Verify getheaders with null locator and valid hashstop returns headers.\")\n        test_node.clear_block_announcements()\n        test_node.send_get_headers(locator=[], hashstop=tip_hash)\n        test_node.check_last_headers_announcement(headers=[tip_hash])\n\n        self.log.info(\"Verify getheaders with null locator and invalid hashstop does not return headers.\")\n        block = create_block(int(tip[\"hash\"], 16), create_coinbase(tip[\"height\"] + 1), tip[\"mediantime\"] + 1)\n        block.solve()\n        test_node.send_header_for_blocks([block])\n        test_node.clear_block_announcements()\n        test_node.send_get_headers(locator=[], hashstop=int(block.hash, 16))\n        test_node.sync_with_ping()\n        assert_equal(test_node.block_announced, False)\n        inv_node.clear_block_announcements()\n        test_node.send_message(msg_block(block))\n        inv_node.check_last_inv_announcement(inv=[int(block.hash, 16)])\n\n    def test_nonnull_locators(self, test_node, inv_node):\n        tip = int(self.nodes[0].getbestblockhash(), 16)\n\n        # PART 1\n        # 1. Mine a block; expect inv announcements each time\n        self.log.info(\"Part 1: headers don't start before sendheaders message...\")\n        for i in range(4):\n            self.log.debug(\"Part 1.{}: starting...\".format(i))\n            old_tip = tip\n            tip = self.mine_blocks(1)\n            inv_node.check_last_inv_announcement(inv=[tip])\n            test_node.check_last_inv_announcement(inv=[tip])\n            # Try a few different responses; none should affect next announcement\n            if i == 0:\n                # first request the block\n                test_node.send_get_data([tip])\n                test_node.wait_for_block(tip)\n            elif i == 1:\n                # next try requesting header and block\n                test_node.send_get_headers(locator=[old_tip], hashstop=tip)\n                test_node.send_get_data([tip])\n                test_node.wait_for_block(tip)\n                test_node.clear_block_announcements()  # since we requested headers...\n            elif i == 2:\n                # this time announce own block via headers\n                inv_node.clear_block_announcements()\n                height = self.nodes[0].getblockcount()\n                last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time']\n                block_time = last_time + 1\n                new_block = create_block(tip, create_coinbase(height + 1), block_time)\n                new_block.solve()\n                test_node.send_header_for_blocks([new_block])\n                test_node.wait_for_getdata([new_block.sha256])\n                test_node.send_message(msg_block(new_block))\n                test_node.sync_with_ping()  # make sure this block is processed\n                wait_until(lambda: inv_node.block_announced, timeout=60, lock=mininode_lock)\n                inv_node.clear_block_announcements()\n                test_node.clear_block_announcements()\n\n        self.log.info(\"Part 1: success!\")\n        self.log.info(\"Part 2: announce blocks with headers after sendheaders message...\")\n        # PART 2\n        # 2. Send a sendheaders message and test that headers announcements\n        # commence and keep working.\n        test_node.send_message(msg_sendheaders())\n        prev_tip = int(self.nodes[0].getbestblockhash(), 16)\n        test_node.send_get_headers(locator=[prev_tip], hashstop=0)\n        test_node.sync_with_ping()\n\n        # Now that we've synced headers, headers announcements should work\n        tip = self.mine_blocks(1)\n        inv_node.check_last_inv_announcement(inv=[tip])\n        test_node.check_last_headers_announcement(headers=[tip])\n\n        height = self.nodes[0].getblockcount() + 1\n        block_time += 10  # Advance far enough ahead\n        for i in range(10):\n            self.log.debug(\"Part 2.{}: starting...\".format(i))\n            # Mine i blocks, and alternate announcing either via\n            # inv (of tip) or via headers. After each, new blocks\n            # mined by the node should successfully be announced\n            # with block header, even though the blocks are never requested\n            for j in range(2):\n                self.log.debug(\"Part 2.{}.{}: starting...\".format(i, j))\n                blocks = []\n                for b in range(i + 1):\n                    blocks.append(create_block(tip, create_coinbase(height), block_time))\n                    blocks[-1].solve()\n                    tip = blocks[-1].sha256\n                    block_time += 1\n                    height += 1\n                if j == 0:\n                    # Announce via inv\n                    test_node.send_block_inv(tip)\n                    test_node.wait_for_getheaders()\n                    # Should have received a getheaders now\n                    test_node.send_header_for_blocks(blocks)\n                    # Test that duplicate inv's won't result in duplicate\n                    # getdata requests, or duplicate headers announcements\n                    [inv_node.send_block_inv(x.sha256) for x in blocks]\n                    test_node.wait_for_getdata([x.sha256 for x in blocks])\n                    inv_node.sync_with_ping()\n                else:\n                    # Announce via headers\n                    test_node.send_header_for_blocks(blocks)\n                    test_node.wait_for_getdata([x.sha256 for x in blocks])\n                    # Test that duplicate headers won't result in duplicate\n                    # getdata requests (the check is further down)\n                    inv_node.send_header_for_blocks(blocks)\n                    inv_node.sync_with_ping()\n                [test_node.send_message(msg_block(x)) for x in blocks]\n                test_node.sync_with_ping()\n                inv_node.sync_with_ping()\n                # This block should not be announced to the inv node (since it also\n                # broadcast it)\n                assert \"inv\" not in inv_node.last_message\n                assert \"headers\" not in inv_node.last_message\n                tip = self.mine_blocks(1)\n                inv_node.check_last_inv_announcement(inv=[tip])\n                test_node.check_last_headers_announcement(headers=[tip])\n                height += 1\n                block_time += 1\n\n        self.log.info(\"Part 2: success!\")\n\n        self.log.info(\"Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...\")\n\n        # PART 3.  Headers announcements can stop after large reorg, and resume after\n        # getheaders or inv from peer.\n        for j in range(2):\n            self.log.debug(\"Part 3.{}: starting...\".format(j))\n            # First try mining a reorg that can propagate with header announcement\n            new_block_hashes = self.mine_reorg(length=7)\n            tip = new_block_hashes[-1]\n            inv_node.check_last_inv_announcement(inv=[tip])\n            test_node.check_last_headers_announcement(headers=new_block_hashes)\n\n            block_time += 8\n\n            # Mine a too-large reorg, which should be announced with a single inv\n            new_block_hashes = self.mine_reorg(length=8)\n            tip = new_block_hashes[-1]\n            inv_node.check_last_inv_announcement(inv=[tip])\n            test_node.check_last_inv_announcement(inv=[tip])\n\n            block_time += 9\n\n            fork_point = self.nodes[0].getblock(\"%064x\" % new_block_hashes[0])[\"previousblockhash\"]\n            fork_point = int(fork_point, 16)\n\n            # Use getblocks/getdata\n            test_node.send_getblocks(locator=[fork_point])\n            test_node.check_last_inv_announcement(inv=new_block_hashes)\n            test_node.send_get_data(new_block_hashes)\n            test_node.wait_for_block(new_block_hashes[-1])\n\n            for i in range(3):\n                self.log.debug(\"Part 3.{}.{}: starting...\".format(j, i))\n\n                # Mine another block, still should get only an inv\n                tip = self.mine_blocks(1)\n                inv_node.check_last_inv_announcement(inv=[tip])\n                test_node.check_last_inv_announcement(inv=[tip])\n                if i == 0:\n                    # Just get the data -- shouldn't cause headers announcements to resume\n                    test_node.send_get_data([tip])\n                    test_node.wait_for_block(tip)\n                elif i == 1:\n                    # Send a getheaders message that shouldn't trigger headers announcements\n                    # to resume (best header sent will be too old)\n                    test_node.send_get_headers(locator=[fork_point], hashstop=new_block_hashes[1])\n                    test_node.send_get_data([tip])\n                    test_node.wait_for_block(tip)\n                elif i == 2:\n                    # This time, try sending either a getheaders to trigger resumption\n                    # of headers announcements, or mine a new block and inv it, also\n                    # triggering resumption of headers announcements.\n                    test_node.send_get_data([tip])\n                    test_node.wait_for_block(tip)\n                    if j == 0:\n                        test_node.send_get_headers(locator=[tip], hashstop=0)\n                        test_node.sync_with_ping()\n                    else:\n                        test_node.send_block_inv(tip)\n                        test_node.sync_with_ping()\n            # New blocks should now be announced with header\n            tip = self.mine_blocks(1)\n            inv_node.check_last_inv_announcement(inv=[tip])\n            test_node.check_last_headers_announcement(headers=[tip])\n\n        self.log.info(\"Part 3: success!\")\n\n        self.log.info(\"Part 4: Testing direct fetch behavior...\")\n        tip = self.mine_blocks(1)\n        height = self.nodes[0].getblockcount() + 1\n        last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time']\n        block_time = last_time + 1\n\n        # Create 2 blocks.  Send the blocks, then send the headers.\n        blocks = []\n        for b in range(2):\n            blocks.append(create_block(tip, create_coinbase(height), block_time))\n            blocks[-1].solve()\n            tip = blocks[-1].sha256\n            block_time += 1\n            height += 1\n            inv_node.send_message(msg_block(blocks[-1]))\n\n        inv_node.sync_with_ping()  # Make sure blocks are processed\n        test_node.last_message.pop(\"getdata\", None)\n        test_node.send_header_for_blocks(blocks)\n        test_node.sync_with_ping()\n        # should not have received any getdata messages\n        with mininode_lock:\n            assert \"getdata\" not in test_node.last_message\n\n        # This time, direct fetch should work\n        blocks = []\n        for b in range(3):\n            blocks.append(create_block(tip, create_coinbase(height), block_time))\n            blocks[-1].solve()\n            tip = blocks[-1].sha256\n            block_time += 1\n            height += 1\n\n        test_node.send_header_for_blocks(blocks)\n        test_node.sync_with_ping()\n        test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=DIRECT_FETCH_RESPONSE_TIME)\n\n        [test_node.send_message(msg_block(x)) for x in blocks]\n\n        test_node.sync_with_ping()\n\n        # Now announce a header that forks the last two blocks\n        tip = blocks[0].sha256\n        height -= 2\n        blocks = []\n\n        # Create extra blocks for later\n        for b in range(20):\n            blocks.append(create_block(tip, create_coinbase(height), block_time))\n            blocks[-1].solve()\n            tip = blocks[-1].sha256\n            block_time += 1\n            height += 1\n\n        # Announcing one block on fork should not trigger direct fetch\n        # (less work than tip)\n        test_node.last_message.pop(\"getdata\", None)\n        test_node.send_header_for_blocks(blocks[0:1])\n        test_node.sync_with_ping()\n        with mininode_lock:\n            assert \"getdata\" not in test_node.last_message\n\n        # Announcing one more block on fork should trigger direct fetch for\n        # both blocks (same work as tip)\n        test_node.send_header_for_blocks(blocks[1:2])\n        test_node.sync_with_ping()\n        test_node.wait_for_getdata([x.sha256 for x in blocks[0:2]], timeout=DIRECT_FETCH_RESPONSE_TIME)\n\n        # Announcing 16 more headers should trigger direct fetch for 14 more\n        # blocks\n        test_node.send_header_for_blocks(blocks[2:18])\n        test_node.sync_with_ping()\n        test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=DIRECT_FETCH_RESPONSE_TIME)\n\n        # Announcing 1 more header should not trigger any response\n        test_node.last_message.pop(\"getdata\", None)\n        test_node.send_header_for_blocks(blocks[18:19])\n        test_node.sync_with_ping()\n        with mininode_lock:\n            assert \"getdata\" not in test_node.last_message\n\n        self.log.info(\"Part 4: success!\")\n\n        # Now deliver all those blocks we announced.\n        [test_node.send_message(msg_block(x)) for x in blocks]\n\n        self.log.info(\"Part 5: Testing handling of unconnecting headers\")\n        # First we test that receipt of an unconnecting header doesn't prevent\n        # chain sync.\n        for i in range(10):\n            self.log.debug(\"Part 5.{}: starting...\".format(i))\n            test_node.last_message.pop(\"getdata\", None)\n            blocks = []\n            # Create two more blocks.\n            for j in range(2):\n                blocks.append(create_block(tip, create_coinbase(height), block_time))\n                blocks[-1].solve()\n                tip = blocks[-1].sha256\n                block_time += 1\n                height += 1\n            # Send the header of the second block -> this won't connect.\n            with mininode_lock:\n                test_node.last_message.pop(\"getheaders\", None)\n            test_node.send_header_for_blocks([blocks[1]])\n            test_node.wait_for_getheaders()\n            test_node.send_header_for_blocks(blocks)\n            test_node.wait_for_getdata([x.sha256 for x in blocks])\n            [test_node.send_message(msg_block(x)) for x in blocks]\n            test_node.sync_with_ping()\n            assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256)\n\n        blocks = []\n        # Now we test that if we repeatedly don't send connecting headers, we\n        # don't go into an infinite loop trying to get them to connect.\n        MAX_UNCONNECTING_HEADERS = 10\n        for j in range(MAX_UNCONNECTING_HEADERS + 1):\n            blocks.append(create_block(tip, create_coinbase(height), block_time))\n            blocks[-1].solve()\n            tip = blocks[-1].sha256\n            block_time += 1\n            height += 1\n\n        for i in range(1, MAX_UNCONNECTING_HEADERS):\n            # Send a header that doesn't connect, check that we get a getheaders.\n            with mininode_lock:\n                test_node.last_message.pop(\"getheaders\", None)\n            test_node.send_header_for_blocks([blocks[i]])\n            test_node.wait_for_getheaders()\n\n        # Next header will connect, should re-set our count:\n        test_node.send_header_for_blocks([blocks[0]])\n\n        # Remove the first two entries (blocks[1] would connect):\n        blocks = blocks[2:]\n\n        # Now try to see how many unconnecting headers we can send\n        # before we get disconnected.  Should be 5*MAX_UNCONNECTING_HEADERS\n        for i in range(5 * MAX_UNCONNECTING_HEADERS - 1):\n            # Send a header that doesn't connect, check that we get a getheaders.\n            with mininode_lock:\n                test_node.last_message.pop(\"getheaders\", None)\n            test_node.send_header_for_blocks([blocks[i % len(blocks)]])\n            test_node.wait_for_getheaders()\n\n        # Eventually this stops working.\n        test_node.send_header_for_blocks([blocks[-1]])\n\n        # Should get disconnected\n        test_node.wait_for_disconnect()\n\n        self.log.info(\"Part 5: success!\")\n\n        # Finally, check that the inv node never received a getdata request,\n        # throughout the test\n        assert \"getdata\" not in inv_node.last_message\n\nif __name__ == '__main__':\n    SendHeadersTest().main()\n"
  },
  {
    "path": "test/functional/p2p_timeouts.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test various net timeouts.\n\n- Create three Munt-daemon nodes:\n\n    no_verack_node - we never send a verack in response to their version\n    no_version_node - we never send a version (only a ping)\n    no_send_node - we never send any P2P message.\n\n- Start all three nodes\n- Wait 1 second\n- Assert that we're connected\n- Send a ping to no_verack_node and no_version_node\n- Wait 1 second\n- Assert that we're still connected\n- Send a ping to no_verack_node and no_version_node\n- Wait 2 seconds\n- Assert that we're no longer connected (timeout to receive version/verack is 3 seconds)\n\"\"\"\n\nfrom time import sleep\n\nfrom test_framework.messages import msg_ping\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\n\nclass TestP2PConn(P2PInterface):\n    def on_version(self, message):\n        # Don't send a verack in response\n        pass\n\nclass TimeoutsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        # set timeout to receive version/verack to 3 seconds\n        self.extra_args = [[\"-peertimeout=3\"]]\n\n    def run_test(self):\n        # Setup the p2p connections\n        no_verack_node = self.nodes[0].add_p2p_connection(TestP2PConn())\n        no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)\n        no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)\n\n        sleep(1)\n\n        assert no_verack_node.is_connected\n        assert no_version_node.is_connected\n        assert no_send_node.is_connected\n\n        no_verack_node.send_message(msg_ping())\n        no_version_node.send_message(msg_ping())\n\n        sleep(1)\n\n        assert \"version\" in no_verack_node.last_message\n\n        assert no_verack_node.is_connected\n        assert no_version_node.is_connected\n        assert no_send_node.is_connected\n\n        no_verack_node.send_message(msg_ping())\n        no_version_node.send_message(msg_ping())\n\n        expected_timeout_logs = [\n            \"version handshake timeout from 0\",\n            \"socket no message in first 3 seconds, 1 0 from 1\",\n            \"socket no message in first 3 seconds, 0 0 from 2\",\n        ]\n\n        with self.nodes[0].assert_debug_log(expected_msgs=expected_timeout_logs):\n            sleep(3)\n            # By now, we waited a total of 5 seconds. Off-by-two for two\n            # reasons:\n            #  * The internal precision is one second\n            #  * Account for network delay\n            assert not no_verack_node.is_connected\n            assert not no_version_node.is_connected\n            assert not no_send_node.is_connected\n\nif __name__ == '__main__':\n    TimeoutsTest().main()\n"
  },
  {
    "path": "test/functional/p2p_unrequested_blocks.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test processing of unrequested blocks.\n\nSetup: two nodes, node0+node1, not connected to each other. Node1 will have\nnMinimumChainWork set to 0x10, so it won't process low-work unrequested blocks.\n\nWe have one P2PInterface connection to node0 called test_node, and one to node1\ncalled min_work_node.\n\nThe test:\n1. Generate one block on each node, to leave IBD.\n\n2. Mine a new block on each tip, and deliver to each node from node's peer.\n   The tip should advance for node0, but node1 should skip processing due to\n   nMinimumChainWork.\n\nNode1 is unused in tests 3-7:\n\n3. Mine a block that forks from the genesis block, and deliver to test_node.\n   Node0 should not process this block (just accept the header), because it\n   is unrequested and doesn't have more or equal work to the tip.\n\n4a,b. Send another two blocks that build on the forking block.\n   Node0 should process the second block but be stuck on the shorter chain,\n   because it's missing an intermediate block.\n\n4c.Send 288 more blocks on the longer chain (the number of blocks ahead\n   we currently store).\n   Node0 should process all but the last block (too far ahead in height).\n\n5. Send a duplicate of the block in #3 to Node0.\n   Node0 should not process the block because it is unrequested, and stay on\n   the shorter chain.\n\n6. Send Node0 an inv for the height 3 block produced in #4 above.\n   Node0 should figure out that Node0 has the missing height 2 block and send a\n   getdata.\n\n7. Send Node0 the missing block again.\n   Node0 should process and the tip should advance.\n\n8. Create a fork which is invalid at a height longer than the current chain\n   (ie to which the node will try to reorg) but which has headers built on top\n   of the invalid block. Check that we get disconnected if we send more headers\n   on the chain the node now knows to be invalid.\n\n9. Test Node1 is able to sync when connected to node0 (which should have sufficient\n   work on its chain).\n\"\"\"\n\nimport time\n\nfrom test_framework.blocktools import create_block, create_coinbase, create_tx_with_script\nfrom test_framework.messages import CBlockHeader, CInv, msg_block, msg_headers, msg_inv\nfrom test_framework.mininode import mininode_lock, P2PInterface\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks\n\n\nclass AcceptBlockTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.extra_args = [[], [\"-minimumchainwork=0x10\"]]\n\n    def setup_network(self):\n        # Node0 will be used to test behavior of processing unrequested blocks\n        # from peers which are not whitelisted, while Node1 will be used for\n        # the whitelisted case.\n        # Node2 will be used for non-whitelisted peers to test the interaction\n        # with nMinimumChainWork.\n        self.setup_nodes()\n\n    def run_test(self):\n        # Setup the p2p connections\n        # test_node connects to node0 (not whitelisted)\n        test_node = self.nodes[0].add_p2p_connection(P2PInterface())\n        # min_work_node connects to node1 (whitelisted)\n        min_work_node = self.nodes[1].add_p2p_connection(P2PInterface())\n\n        # 1. Have nodes mine a block (leave IBD)\n        [n.generatetoaddress(1, n.get_deterministic_priv_key().address) for n in self.nodes]\n        tips = [int(\"0x\" + n.getbestblockhash(), 0) for n in self.nodes]\n\n        # 2. Send one block that builds on each tip.\n        # This should be accepted by node0\n        blocks_h2 = []  # the height 2 blocks on each node's chain\n        block_time = int(time.time()) + 1\n        for i in range(2):\n            blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time))\n            blocks_h2[i].solve()\n            block_time += 1\n        test_node.send_message(msg_block(blocks_h2[0]))\n        min_work_node.send_message(msg_block(blocks_h2[1]))\n\n        for x in [test_node, min_work_node]:\n            x.sync_with_ping()\n        assert_equal(self.nodes[0].getblockcount(), 2)\n        assert_equal(self.nodes[1].getblockcount(), 1)\n        self.log.info(\"First height 2 block accepted by node0; correctly rejected by node1\")\n\n        # 3. Send another block that builds on genesis.\n        block_h1f = create_block(int(\"0x\" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time)\n        block_time += 1\n        block_h1f.solve()\n        test_node.send_message(msg_block(block_h1f))\n\n        test_node.sync_with_ping()\n        tip_entry_found = False\n        for x in self.nodes[0].getchaintips():\n            if x['hash'] == block_h1f.hash:\n                assert_equal(x['status'], \"headers-only\")\n                tip_entry_found = True\n        assert tip_entry_found\n        assert_raises_rpc_error(-1, \"Block not found on disk\", self.nodes[0].getblock, block_h1f.hash)\n\n        # 4. Send another two block that build on the fork.\n        block_h2f = create_block(block_h1f.sha256, create_coinbase(2), block_time)\n        block_time += 1\n        block_h2f.solve()\n        test_node.send_message(msg_block(block_h2f))\n\n        test_node.sync_with_ping()\n        # Since the earlier block was not processed by node, the new block\n        # can't be fully validated.\n        tip_entry_found = False\n        for x in self.nodes[0].getchaintips():\n            if x['hash'] == block_h2f.hash:\n                assert_equal(x['status'], \"headers-only\")\n                tip_entry_found = True\n        assert tip_entry_found\n\n        # But this block should be accepted by node since it has equal work.\n        self.nodes[0].getblock(block_h2f.hash)\n        self.log.info(\"Second height 2 block accepted, but not reorg'ed to\")\n\n        # 4b. Now send another block that builds on the forking chain.\n        block_h3 = create_block(block_h2f.sha256, create_coinbase(3), block_h2f.nTime+1)\n        block_h3.solve()\n        test_node.send_message(msg_block(block_h3))\n\n        test_node.sync_with_ping()\n        # Since the earlier block was not processed by node, the new block\n        # can't be fully validated.\n        tip_entry_found = False\n        for x in self.nodes[0].getchaintips():\n            if x['hash'] == block_h3.hash:\n                assert_equal(x['status'], \"headers-only\")\n                tip_entry_found = True\n        assert tip_entry_found\n        self.nodes[0].getblock(block_h3.hash)\n\n        # But this block should be accepted by node since it has more work.\n        self.nodes[0].getblock(block_h3.hash)\n        self.log.info(\"Unrequested more-work block accepted\")\n\n        # 4c. Now mine 288 more blocks and deliver; all should be processed but\n        # the last (height-too-high) on node (as long as it is not missing any headers)\n        tip = block_h3\n        all_blocks = []\n        for i in range(288):\n            next_block = create_block(tip.sha256, create_coinbase(i + 4), tip.nTime+1)\n            next_block.solve()\n            all_blocks.append(next_block)\n            tip = next_block\n\n        # Now send the block at height 5 and check that it wasn't accepted (missing header)\n        test_node.send_message(msg_block(all_blocks[1]))\n        test_node.sync_with_ping()\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[0].getblock, all_blocks[1].hash)\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[0].getblockheader, all_blocks[1].hash)\n\n        # The block at height 5 should be accepted if we provide the missing header, though\n        headers_message = msg_headers()\n        headers_message.headers.append(CBlockHeader(all_blocks[0]))\n        test_node.send_message(headers_message)\n        test_node.send_message(msg_block(all_blocks[1]))\n        test_node.sync_with_ping()\n        self.nodes[0].getblock(all_blocks[1].hash)\n\n        # Now send the blocks in all_blocks\n        for i in range(288):\n            test_node.send_message(msg_block(all_blocks[i]))\n        test_node.sync_with_ping()\n\n        # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead\n        for x in all_blocks[:-1]:\n            self.nodes[0].getblock(x.hash)\n        assert_raises_rpc_error(-1, \"Block not found on disk\", self.nodes[0].getblock, all_blocks[-1].hash)\n\n        # 5. Test handling of unrequested block on the node that didn't process\n        # Should still not be processed (even though it has a child that has more\n        # work).\n\n        # The node should have requested the blocks at some point, so\n        # disconnect/reconnect first\n\n        self.nodes[0].disconnect_p2ps()\n        self.nodes[1].disconnect_p2ps()\n\n        test_node = self.nodes[0].add_p2p_connection(P2PInterface())\n\n        test_node.send_message(msg_block(block_h1f))\n\n        test_node.sync_with_ping()\n        assert_equal(self.nodes[0].getblockcount(), 2)\n        self.log.info(\"Unrequested block that would complete more-work chain was ignored\")\n\n        # 6. Try to get node to request the missing block.\n        # Poke the node with an inv for block at height 3 and see if that\n        # triggers a getdata on block 2 (it should if block 2 is missing).\n        with mininode_lock:\n            # Clear state so we can check the getdata request\n            test_node.last_message.pop(\"getdata\", None)\n            test_node.send_message(msg_inv([CInv(2, block_h3.sha256)]))\n\n        test_node.sync_with_ping()\n        with mininode_lock:\n            getdata = test_node.last_message[\"getdata\"]\n\n        # Check that the getdata includes the right block\n        assert_equal(getdata.inv[0].hash, block_h1f.sha256)\n        self.log.info(\"Inv at tip triggered getdata for unprocessed block\")\n\n        # 7. Send the missing block for the third time (now it is requested)\n        test_node.send_message(msg_block(block_h1f))\n\n        test_node.sync_with_ping()\n        assert_equal(self.nodes[0].getblockcount(), 290)\n        self.nodes[0].getblock(all_blocks[286].hash)\n        assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)\n        assert_raises_rpc_error(-1, \"Block not found on disk\", self.nodes[0].getblock, all_blocks[287].hash)\n        self.log.info(\"Successfully reorged to longer chain from non-whitelisted peer\")\n\n        # 8. Create a chain which is invalid at a height longer than the\n        # current chain, but which has more blocks on top of that\n        block_289f = create_block(all_blocks[284].sha256, create_coinbase(289), all_blocks[284].nTime+1)\n        block_289f.solve()\n        block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1)\n        block_290f.solve()\n        block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)\n        # block_291 spends a coinbase below maturity!\n        block_291.vtx.append(create_tx_with_script(block_290f.vtx[0], 0, script_sig=b\"42\", amount=1))\n        block_291.hashMerkleRoot = block_291.calc_merkle_root()\n        block_291.solve()\n        block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)\n        block_292.solve()\n\n        # Now send all the headers on the chain and enough blocks to trigger reorg\n        headers_message = msg_headers()\n        headers_message.headers.append(CBlockHeader(block_289f))\n        headers_message.headers.append(CBlockHeader(block_290f))\n        headers_message.headers.append(CBlockHeader(block_291))\n        headers_message.headers.append(CBlockHeader(block_292))\n        test_node.send_message(headers_message)\n\n        test_node.sync_with_ping()\n        tip_entry_found = False\n        for x in self.nodes[0].getchaintips():\n            if x['hash'] == block_292.hash:\n                assert_equal(x['status'], \"headers-only\")\n                tip_entry_found = True\n        assert tip_entry_found\n        assert_raises_rpc_error(-1, \"Block not found on disk\", self.nodes[0].getblock, block_292.hash)\n\n        test_node.send_message(msg_block(block_289f))\n        test_node.send_message(msg_block(block_290f))\n\n        test_node.sync_with_ping()\n        self.nodes[0].getblock(block_289f.hash)\n        self.nodes[0].getblock(block_290f.hash)\n\n        test_node.send_message(msg_block(block_291))\n\n        # At this point we've sent an obviously-bogus block, wait for full processing\n        # without assuming whether we will be disconnected or not\n        try:\n            # Only wait a short while so the test doesn't take forever if we do get\n            # disconnected\n            test_node.sync_with_ping(timeout=1)\n        except AssertionError:\n            test_node.wait_for_disconnect()\n\n            self.nodes[0].disconnect_p2ps()\n            test_node = self.nodes[0].add_p2p_connection(P2PInterface())\n\n        # We should have failed reorg and switched back to 290 (but have block 291)\n        assert_equal(self.nodes[0].getblockcount(), 290)\n        assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)\n        assert_equal(self.nodes[0].getblock(block_291.hash)[\"confirmations\"], -1)\n\n        # Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected\n        block_293 = create_block(block_292.sha256, create_coinbase(293), block_292.nTime+1)\n        block_293.solve()\n        headers_message = msg_headers()\n        headers_message.headers.append(CBlockHeader(block_293))\n        test_node.send_message(headers_message)\n        test_node.wait_for_disconnect()\n\n        # 9. Connect node1 to node0 and ensure it is able to sync\n        connect_nodes(self.nodes[0], 1)\n        sync_blocks([self.nodes[0], self.nodes[1]])\n        self.log.info(\"Successfully synced nodes 1 and 0\")\n\nif __name__ == '__main__':\n    AcceptBlockTest().main()\n"
  },
  {
    "path": "test/functional/rpc_bind.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test running Munt-daemon with the -rpcbind and -rpcallowip options.\"\"\"\n\nimport sys\n\nfrom test_framework.netutil import all_interfaces, addr_to_hex, get_bind_addrs, test_ipv6_local\nfrom test_framework.test_framework import MuntTestFramework, SkipTest\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, get_rpc_proxy, rpc_port, rpc_url\n\nclass RPCBindTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.bind_to_localhost_only = False\n        self.num_nodes = 1\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes, None)\n\n    def add_options(self, parser):\n        parser.add_argument(\"--ipv4\", action='store_true', dest=\"run_ipv4\", help=\"Run ipv4 tests only\", default=False)\n        parser.add_argument(\"--ipv6\", action='store_true', dest=\"run_ipv6\", help=\"Run ipv6 tests only\", default=False)\n        parser.add_argument(\"--nonloopback\", action='store_true', dest=\"run_nonloopback\", help=\"Run non-loopback tests only\", default=False)\n\n    def run_bind_test(self, allow_ips, connect_to, addresses, expected):\n        '''\n        Start a node with requested rpcallowip and rpcbind parameters,\n        then try to connect, and check if the set of bound addresses\n        matches the expected set.\n        '''\n        self.log.info(\"Bind test for %s\" % str(addresses))\n        expected = [(addr_to_hex(addr), port) for (addr, port) in expected]\n        base_args = ['-disablewallet', '-nolisten']\n        if allow_ips:\n            base_args += ['-rpcallowip=' + x for x in allow_ips]\n        binds = ['-rpcbind='+addr for addr in addresses]\n        self.nodes[0].rpchost = connect_to\n        self.start_node(0, base_args + binds)\n        pid = self.nodes[0].process.pid\n        assert_equal(set(get_bind_addrs(pid)), set(expected))\n        self.stop_nodes()\n\n    def run_allowip_test(self, allow_ips, rpchost, rpcport):\n        '''\n        Start a node with rpcallow IP, and request getnetworkinfo\n        at a non-localhost IP.\n        '''\n        self.log.info(\"Allow IP test for %s:%d\" % (rpchost, rpcport))\n        node_args = \\\n            ['-disablewallet', '-nolisten'] + \\\n            ['-rpcallowip='+x for x in allow_ips] + \\\n            ['-rpcbind='+addr for addr in ['127.0.0.1', \"%s:%d\" % (rpchost, rpcport)]] # Bind to localhost as well so start_nodes doesn't hang\n        self.nodes[0].rpchost = None\n        self.start_nodes([node_args])\n        # connect to node through non-loopback interface\n        node = get_rpc_proxy(rpc_url(self.nodes[0].datadir, 0, \"%s:%d\" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir)\n        node.getnetworkinfo()\n        self.stop_nodes()\n\n    def run_test(self):\n        # due to OS-specific network stats queries, this test works only on Linux\n        if sum([self.options.run_ipv4, self.options.run_ipv6, self.options.run_nonloopback]) > 1:\n            raise AssertionError(\"Only one of --ipv4, --ipv6 and --nonloopback can be set\")\n\n        self.log.info(\"Check for linux\")\n        if not sys.platform.startswith('linux'):\n            raise SkipTest(\"This test can only be run on linux.\")\n\n        self.log.info(\"Check for ipv6\")\n        have_ipv6 = test_ipv6_local()\n        if not have_ipv6 and not (self.options.run_ipv4 or self.options.run_nonloopback):\n            raise SkipTest(\"This test requires ipv6 support.\")\n\n        self.log.info(\"Check for non-loopback interface\")\n        self.non_loopback_ip = None\n        for name,ip in all_interfaces():\n            if ip != '127.0.0.1':\n                self.non_loopback_ip = ip\n                break\n        if self.non_loopback_ip is None and self.options.run_nonloopback:\n            raise SkipTest(\"This test requires a non-loopback ip address.\")\n\n        self.defaultport = rpc_port(0)\n\n        if not self.options.run_nonloopback:\n            self._run_loopback_tests()\n        if not self.options.run_ipv4 and not self.options.run_ipv6:\n            self._run_nonloopback_tests()\n\n    def _run_loopback_tests(self):\n        if self.options.run_ipv4:\n            # check only IPv4 localhost (explicit)\n            self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],\n                [('127.0.0.1', self.defaultport)])\n            # check only IPv4 localhost (explicit) with alternative port\n            self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],\n                [('127.0.0.1', 32171)])\n            # check only IPv4 localhost (explicit) with multiple alternative ports on same host\n            self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],\n                [('127.0.0.1', 32171), ('127.0.0.1', 32172)])\n        else:\n            # check default without rpcallowip (IPv4 and IPv6 localhost)\n            self.run_bind_test(None, '127.0.0.1', [],\n                [('127.0.0.1', self.defaultport), ('::1', self.defaultport)])\n            # check default with rpcallowip (IPv4 and IPv6 localhost)\n            self.run_bind_test(['127.0.0.1'], '127.0.0.1', [],\n                [('127.0.0.1', self.defaultport), ('::1', self.defaultport)])\n            # check only IPv6 localhost (explicit)\n            self.run_bind_test(['[::1]'], '[::1]', ['[::1]'],\n                [('::1', self.defaultport)])\n            # check both IPv4 and IPv6 localhost (explicit)\n            self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],\n                [('127.0.0.1', self.defaultport), ('::1', self.defaultport)])\n\n    def _run_nonloopback_tests(self):\n        self.log.info(\"Using interface %s for testing\" % self.non_loopback_ip)\n\n        # check only non-loopback interface\n        self.run_bind_test([self.non_loopback_ip], self.non_loopback_ip, [self.non_loopback_ip],\n            [(self.non_loopback_ip, self.defaultport)])\n\n        # Check that with invalid rpcallowip, we are denied\n        self.run_allowip_test([self.non_loopback_ip], self.non_loopback_ip, self.defaultport)\n        assert_raises_rpc_error(-342, \"non-JSON HTTP response with '403 Forbidden' from server\", self.run_allowip_test, ['1.1.1.1'], self.non_loopback_ip, self.defaultport)\n\nif __name__ == '__main__':\n    RPCBindTest().main()\n"
  },
  {
    "path": "test/functional/rpc_blockchain.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test RPCs related to blockchainstate.\n\nTest the following RPCs:\n    - getblockchaininfo\n    - gettxoutsetinfo\n    - getdifficulty\n    - getbestblockhash\n    - getblockhash\n    - getblockheader\n    - getchaintxstats\n    - getnetworkhashps\n    - verifychain\n\nTests correspond to code in rpc/blockchain.cpp.\n\"\"\"\n\nfrom decimal import Decimal\nimport http.client\nimport subprocess\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n    assert_raises,\n    assert_raises_rpc_error,\n    assert_is_hex_string,\n    assert_is_hash_string,\n)\nfrom test_framework.blocktools import (\n    create_block,\n    create_coinbase,\n    TIME_GENESIS_BLOCK,\n)\nfrom test_framework.messages import (\n    msg_block,\n)\nfrom test_framework.mininode import (\n    P2PInterface,\n)\n\n\nclass BlockchainTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def run_test(self):\n        self.mine_chain()\n        self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1'])  # Set extra args with pruning after rescan is complete\n\n        self._test_getblockchaininfo()\n        self._test_getchaintxstats()\n        self._test_gettxoutsetinfo()\n        self._test_getblockheader()\n        self._test_getdifficulty()\n        self._test_getnetworkhashps()\n        self._test_stopatheight()\n        self._test_waitforblockheight()\n        assert self.nodes[0].verifychain(4, 0)\n\n    def mine_chain(self):\n        self.log.info('Create some old blocks')\n        address = self.nodes[0].get_deterministic_priv_key().address\n        for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):\n            # ten-minute steps from genesis block time\n            self.nodes[0].setmocktime(t)\n            self.nodes[0].generatetoaddress(1, address)\n        assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)\n\n    def _test_getblockchaininfo(self):\n        self.log.info(\"Test getblockchaininfo\")\n\n        keys = [\n            'bestblockhash',\n            'bip9_softforks',\n            'blocks',\n            'chain',\n            'chainwork',\n            'difficulty',\n            'headers',\n            'initialblockdownload',\n            'mediantime',\n            'pruned',\n            'size_on_disk',\n            'softforks',\n            'verificationprogress',\n            'warnings',\n        ]\n        res = self.nodes[0].getblockchaininfo()\n\n        # result should have these additional pruning keys if manual pruning is enabled\n        assert_equal(sorted(res.keys()), sorted(['pruneheight', 'automatic_pruning'] + keys))\n\n        # size_on_disk should be > 0\n        assert_greater_than(res['size_on_disk'], 0)\n\n        # pruneheight should be greater or equal to 0\n        assert_greater_than_or_equal(res['pruneheight'], 0)\n\n        # check other pruning fields given that prune=1\n        assert res['pruned']\n        assert not res['automatic_pruning']\n\n        self.restart_node(0, ['-stopatheight=207'])\n        res = self.nodes[0].getblockchaininfo()\n        # should have exact keys\n        assert_equal(sorted(res.keys()), keys)\n\n        self.restart_node(0, ['-stopatheight=207', '-prune=550'])\n        res = self.nodes[0].getblockchaininfo()\n        # result should have these additional pruning keys if prune=550\n        assert_equal(sorted(res.keys()), sorted(['pruneheight', 'automatic_pruning', 'prune_target_size'] + keys))\n\n        # check related fields\n        assert res['pruned']\n        assert_equal(res['pruneheight'], 0)\n        assert res['automatic_pruning']\n        assert_equal(res['prune_target_size'], 576716800)\n        assert_greater_than(res['size_on_disk'], 0)\n\n    def _test_getchaintxstats(self):\n        self.log.info(\"Test getchaintxstats\")\n\n        # Test `getchaintxstats` invalid extra parameters\n        assert_raises_rpc_error(-1, 'getchaintxstats', self.nodes[0].getchaintxstats, 0, '', 0)\n\n        # Test `getchaintxstats` invalid `num_blocks`\n        assert_raises_rpc_error(-1, \"JSON value is not an integer as expected\", self.nodes[0].getchaintxstats, '')\n        assert_raises_rpc_error(-8, \"Invalid block count: should be between 0 and the block's height - 1\", self.nodes[0].getchaintxstats, -1)\n        assert_raises_rpc_error(-8, \"Invalid block count: should be between 0 and the block's height - 1\", self.nodes[0].getchaintxstats, self.nodes[0].getblockcount())\n\n        # Test `getchaintxstats` invalid `blockhash`\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[0].getchaintxstats, blockhash=0)\n        assert_raises_rpc_error(-8, \"blockhash must be of length 64 (not 1, for '0')\", self.nodes[0].getchaintxstats, blockhash='0')\n        assert_raises_rpc_error(-8, \"blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')\", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000')\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000')\n        blockhash = self.nodes[0].getblockhash(200)\n        self.nodes[0].invalidateblock(blockhash)\n        assert_raises_rpc_error(-8, \"Block is not in main chain\", self.nodes[0].getchaintxstats, blockhash=blockhash)\n        self.nodes[0].reconsiderblock(blockhash)\n\n        chaintxstats = self.nodes[0].getchaintxstats(num_blocks=1)\n        # 200 txs plus genesis tx\n        assert_equal(chaintxstats['txcount'], 201)\n        # tx rate should be 1 per 10 minutes, or 1/600\n        # we have to round because of binary math\n        assert_equal(round(chaintxstats['txrate'] * 600, 10), Decimal(1))\n\n        b1_hash = self.nodes[0].getblockhash(1)\n        b1 = self.nodes[0].getblock(b1_hash)\n        b200_hash = self.nodes[0].getblockhash(200)\n        b200 = self.nodes[0].getblock(b200_hash)\n        time_diff = b200['mediantime'] - b1['mediantime']\n\n        chaintxstats = self.nodes[0].getchaintxstats()\n        assert_equal(chaintxstats['time'], b200['time'])\n        assert_equal(chaintxstats['txcount'], 201)\n        assert_equal(chaintxstats['window_final_block_hash'], b200_hash)\n        assert_equal(chaintxstats['window_block_count'], 199)\n        assert_equal(chaintxstats['window_tx_count'], 199)\n        assert_equal(chaintxstats['window_interval'], time_diff)\n        assert_equal(round(chaintxstats['txrate'] * time_diff, 10), Decimal(199))\n\n        chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1_hash)\n        assert_equal(chaintxstats['time'], b1['time'])\n        assert_equal(chaintxstats['txcount'], 2)\n        assert_equal(chaintxstats['window_final_block_hash'], b1_hash)\n        assert_equal(chaintxstats['window_block_count'], 0)\n        assert 'window_tx_count' not in chaintxstats\n        assert 'window_interval' not in chaintxstats\n        assert 'txrate' not in chaintxstats\n\n    def _test_gettxoutsetinfo(self):\n        node = self.nodes[0]\n        res = node.gettxoutsetinfo()\n\n        assert_equal(res['total_amount'], Decimal('8725.00000000'))\n        assert_equal(res['transactions'], 200)\n        assert_equal(res['height'], 200)\n        assert_equal(res['txouts'], 200)\n        assert_equal(res['bogosize'], 15000),\n        assert_equal(res['bestblock'], node.getblockhash(200))\n        size = res['disk_size']\n        assert size > 6400\n        assert size < 64000\n        assert_equal(len(res['bestblock']), 64)\n        assert_equal(len(res['hash_serialized_2']), 64)\n\n        self.log.info(\"Test that gettxoutsetinfo() works for blockchain with just the genesis block\")\n        b1hash = node.getblockhash(1)\n        node.invalidateblock(b1hash)\n\n        res2 = node.gettxoutsetinfo()\n        assert_equal(res2['transactions'], 0)\n        assert_equal(res2['total_amount'], Decimal('0'))\n        assert_equal(res2['height'], 0)\n        assert_equal(res2['txouts'], 0)\n        assert_equal(res2['bogosize'], 0),\n        assert_equal(res2['bestblock'], node.getblockhash(0))\n        assert_equal(len(res2['hash_serialized_2']), 64)\n\n        self.log.info(\"Test that gettxoutsetinfo() returns the same result after invalidate/reconsider block\")\n        node.reconsiderblock(b1hash)\n\n        res3 = node.gettxoutsetinfo()\n        # The field 'disk_size' is non-deterministic and can thus not be\n        # compared between res and res3.  Everything else should be the same.\n        del res['disk_size'], res3['disk_size']\n        assert_equal(res, res3)\n\n    def _test_getblockheader(self):\n        node = self.nodes[0]\n\n        assert_raises_rpc_error(-8, \"hash must be of length 64 (not 8, for 'nonsense')\", node.getblockheader, \"nonsense\")\n        assert_raises_rpc_error(-8, \"hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')\", node.getblockheader, \"ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844\")\n        assert_raises_rpc_error(-5, \"Block not found\", node.getblockheader, \"0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844\")\n\n        besthash = node.getbestblockhash()\n        secondbesthash = node.getblockhash(199)\n        header = node.getblockheader(blockhash=besthash)\n\n        assert_equal(header['hash'], besthash)\n        assert_equal(header['height'], 200)\n        assert_equal(header['confirmations'], 1)\n        assert_equal(header['previousblockhash'], secondbesthash)\n        assert_is_hex_string(header['chainwork'])\n        assert_equal(header['nTx'], 1)\n        assert_is_hash_string(header['hash'])\n        assert_is_hash_string(header['previousblockhash'])\n        assert_is_hash_string(header['merkleroot'])\n        assert_is_hash_string(header['bits'], length=None)\n        assert isinstance(header['time'], int)\n        assert isinstance(header['mediantime'], int)\n        assert isinstance(header['nonce'], int)\n        assert isinstance(header['version'], int)\n        assert isinstance(int(header['versionHex'], 16), int)\n        assert isinstance(header['difficulty'], Decimal)\n\n    def _test_getdifficulty(self):\n        difficulty = self.nodes[0].getdifficulty()\n        # 1 hash in 2 should be valid, so difficulty should be 1/2**31\n        # binary => decimal => binary math is why we do this check\n        assert abs(difficulty * 2**31 - 1) < 0.0001\n\n    def _test_getnetworkhashps(self):\n        hashes_per_second = self.nodes[0].getnetworkhashps()\n        # This should be 2 hashes every 10 minutes or 1/300\n        assert abs(hashes_per_second * 300 - 1) < 0.0001\n\n    def _test_stopatheight(self):\n        assert_equal(self.nodes[0].getblockcount(), 200)\n        self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address)\n        assert_equal(self.nodes[0].getblockcount(), 206)\n        self.log.debug('Node should not stop at this height')\n        assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))\n        try:\n            self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)\n        except (ConnectionError, http.client.BadStatusLine):\n            pass  # The node already shut down before response\n        self.log.debug('Node should stop at this height...')\n        self.nodes[0].wait_until_stopped()\n        self.start_node(0)\n        assert_equal(self.nodes[0].getblockcount(), 207)\n\n    def _test_waitforblockheight(self):\n        self.log.info(\"Test waitforblockheight\")\n        node = self.nodes[0]\n        node.add_p2p_connection(P2PInterface())\n\n        current_height = node.getblock(node.getbestblockhash())['height']\n\n        # Create a fork somewhere below our current height, invalidate the tip\n        # of that fork, and then ensure that waitforblockheight still\n        # works as expected.\n        #\n        # (Previously this was broken based on setting\n        # `rpc/blockchain.cpp:latestblock` incorrectly.)\n        #\n        b20hash = node.getblockhash(20)\n        b20 = node.getblock(b20hash)\n\n        def solve_and_send_block(prevhash, height, time):\n            b = create_block(prevhash, create_coinbase(height), time)\n            b.solve()\n            node.p2p.send_message(msg_block(b))\n            node.p2p.sync_with_ping()\n            return b\n\n        b21f = solve_and_send_block(int(b20hash, 16), 21, b20['time'] + 1)\n        b22f = solve_and_send_block(b21f.sha256, 22, b21f.nTime + 1)\n\n        node.invalidateblock(b22f.hash)\n\n        def assert_waitforheight(height, timeout=2):\n            assert_equal(\n                node.waitforblockheight(height=height, timeout=timeout)['height'],\n                current_height)\n\n        assert_waitforheight(0)\n        assert_waitforheight(current_height - 1)\n        assert_waitforheight(current_height)\n        assert_waitforheight(current_height + 1)\n\n\nif __name__ == '__main__':\n    BlockchainTest().main()\n"
  },
  {
    "path": "test/functional/rpc_createmultisig.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test transaction signing using the signrawtransaction* RPCs.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nimport decimal\n\nclass RpcCreateMultiSigTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def get_keys(self):\n        node0, node1, node2 = self.nodes\n        self.add = [node1.getnewaddress() for _ in range(self.nkeys)]\n        self.pub = [node1.getaddressinfo(a)[\"pubkey\"] for a in self.add]\n        self.priv = [node1.dumpprivkey(a) for a in self.add]\n        self.final = node2.getnewaddress()\n\n    def run_test(self):\n        node0,node1,node2 = self.nodes\n\n        # 50 BTC each, rest will be 25 BTC each\n        node0.generate(149)\n        self.sync_all()\n\n        self.moved = 0\n        for self.nkeys in [3,5]:\n            for self.nsigs in [2,3]:\n                for self.output_type in [\"bech32\", \"p2sh-segwit\", \"legacy\"]:\n                    self.get_keys()\n                    self.do_multisig()\n\n        self.checkbalances()\n\n    def checkbalances(self):\n        node0,node1,node2 = self.nodes\n        node0.generate(100)\n        self.sync_all()\n\n        bal0 = node0.getbalance()\n        bal1 = node1.getbalance()\n        bal2 = node2.getbalance()\n\n        height = node0.getblockchaininfo()[\"blocks\"]\n        assert 150 < height < 350\n        total = 149*50 + (height-149-100)*25\n        assert bal1 == 0\n        assert bal2 == self.moved\n        assert bal0+bal1+bal2 == total\n\n    def do_multisig(self):\n        node0,node1,node2 = self.nodes\n\n        msig = node2.createmultisig(self.nsigs, self.pub, self.output_type)\n        madd = msig[\"address\"]\n        mredeem = msig[\"redeemScript\"]\n        if self.output_type == 'bech32':\n            assert madd[0:4] == \"bcrt\"  # actually a bech32 address\n\n        # compare against addmultisigaddress\n        msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)\n        maddw = msigw[\"address\"]\n        mredeemw = msigw[\"redeemScript\"]\n        # addmultisigiaddress and createmultisig work the same\n        assert maddw == madd\n        assert mredeemw == mredeem\n\n        txid = node0.sendtoaddress(madd, 40)\n\n        tx = node0.getrawtransaction(txid, True)\n        vout = [v[\"n\"] for v in tx[\"vout\"] if madd in v[\"scriptPubKey\"].get(\"addresses\",[])]\n        assert len(vout) == 1\n        vout = vout[0]\n        scriptPubKey = tx[\"vout\"][vout][\"scriptPubKey\"][\"hex\"]\n        value = tx[\"vout\"][vout][\"value\"]\n        prevtxs = [{\"txid\": txid, \"vout\": vout, \"scriptPubKey\": scriptPubKey, \"redeemScript\": mredeem, \"amount\": value}]\n\n        node0.generate(1)\n\n        outval = value - decimal.Decimal(\"0.00001000\")\n        rawtx = node2.createrawtransaction([{\"txid\": txid, \"vout\": vout}], [{self.final: outval}])\n\n        rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], prevtxs)\n        rawtx3 = node2.signrawtransactionwithkey(rawtx2[\"hex\"], [self.priv[-1]], prevtxs)\n\n        self.moved += outval\n        tx = node0.sendrawtransaction(rawtx3[\"hex\"], 0)\n        blk = node0.generate(1)[0]\n        assert tx in node0.getblock(blk)[\"tx\"]\n\n        txinfo = node0.getrawtransaction(tx, True, blk)\n        self.log.info(\"n/m=%d/%d %s size=%d vsize=%d weight=%d\" % (self.nsigs, self.nkeys, self.output_type, txinfo[\"size\"], txinfo[\"vsize\"], txinfo[\"weight\"]))\n\nif __name__ == '__main__':\n    RpcCreateMultiSigTest().main()\n"
  },
  {
    "path": "test/functional/rpc_decodescript.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test decoding scripts via decodescript RPC command.\"\"\"\n\nfrom test_framework.messages import CTransaction, sha256\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, hex_str_to_bytes\n\nfrom io import BytesIO\n\nclass DecodeScriptTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def decodescript_script_sig(self):\n        signature = '304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001'\n        push_signature = '48' + signature\n        public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2'\n        push_public_key = '21' + public_key\n\n        # below are test cases for all of the standard transaction types\n\n        # 1) P2PK scriptSig\n        # the scriptSig of a public key scriptPubKey simply pushes a signature onto the stack\n        rpc_result = self.nodes[0].decodescript(push_signature)\n        assert_equal(signature, rpc_result['asm'])\n\n        # 2) P2PKH scriptSig\n        rpc_result = self.nodes[0].decodescript(push_signature + push_public_key)\n        assert_equal(signature + ' ' + public_key, rpc_result['asm'])\n\n        # 3) multisig scriptSig\n        # this also tests the leading portion of a P2SH multisig scriptSig\n        # OP_0 <A sig> <B sig>\n        rpc_result = self.nodes[0].decodescript('00' + push_signature + push_signature)\n        assert_equal('0 ' + signature + ' ' + signature, rpc_result['asm'])\n\n        # 4) P2SH scriptSig\n        # an empty P2SH redeemScript is valid and makes for a very simple test case.\n        # thus, such a spending scriptSig would just need to pass the outer redeemScript\n        # hash test and leave true on the top of the stack.\n        rpc_result = self.nodes[0].decodescript('5100')\n        assert_equal('1 0', rpc_result['asm'])\n\n        # 5) null data scriptSig - no such thing because null data scripts can not be spent.\n        # thus, no test case for that standard transaction type is here.\n\n    def decodescript_script_pub_key(self):\n        public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2'\n        push_public_key = '21' + public_key\n        public_key_hash = '5dd1d3a048119c27b28293056724d9522f26d945'\n        push_public_key_hash = '14' + public_key_hash\n        uncompressed_public_key = '04b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb25e01fc8fde47c96c98a4f3a8123e33a38a50cf9025cc8c4494a518f991792bb7'\n        push_uncompressed_public_key = '41' + uncompressed_public_key\n        p2wsh_p2pk_script_hash = 'd8590cf8ea0674cf3d49fd7ca249b85ef7485dea62c138468bddeb20cd6519f7'\n\n        # below are test cases for all of the standard transaction types\n\n        # 1) P2PK scriptPubKey\n        # <pubkey> OP_CHECKSIG\n        rpc_result = self.nodes[0].decodescript(push_public_key + 'ac')\n        assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm'])\n        # P2PK is translated to P2WPKH\n        assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])\n\n        # 2) P2PKH scriptPubKey\n        # OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG\n        rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac')\n        assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm'])\n        # P2PKH is translated to P2WPKH\n        assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])\n\n        # 3) multisig scriptPubKey\n        # <m> <A pubkey> <B pubkey> <C pubkey> <n> OP_CHECKMULTISIG\n        # just imagine that the pub keys used below are different.\n        # for our purposes here it does not matter that they are the same even though it is unrealistic.\n        multisig_script = '52' + push_public_key + push_public_key + push_public_key + '53ae'\n        rpc_result = self.nodes[0].decodescript(multisig_script)\n        assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key +  ' 3 OP_CHECKMULTISIG', rpc_result['asm'])\n        # multisig in P2WSH\n        multisig_script_hash = sha256(hex_str_to_bytes(multisig_script)).hex()\n        assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm'])\n\n        # 4) P2SH scriptPubKey\n        # OP_HASH160 <Hash160(redeemScript)> OP_EQUAL.\n        # push_public_key_hash here should actually be the hash of a redeem script.\n        # but this works the same for purposes of this test.\n        rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87')\n        assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm'])\n        # P2SH does not work in segwit secripts. decodescript should not return a result for it.\n        assert 'segwit' not in rpc_result\n\n        # 5) null data scriptPubKey\n        # use a signature look-alike here to make sure that we do not decode random data as a signature.\n        # this matters if/when signature sighash decoding comes along.\n        # would want to make sure that no such decoding takes place in this case.\n        signature_imposter = '48304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001'\n        # OP_RETURN <data>\n        rpc_result = self.nodes[0].decodescript('6a' + signature_imposter)\n        assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm'])\n\n        # 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here.\n        # OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY.\n        # just imagine that the pub keys used below are different.\n        # for our purposes here it does not matter that they are the same even though it is unrealistic.\n        #\n        # OP_IF\n        #   <receiver-pubkey> OP_CHECKSIGVERIFY\n        # OP_ELSE\n        #   <lock-until> OP_CHECKLOCKTIMEVERIFY OP_DROP\n        # OP_ENDIF\n        # <sender-pubkey> OP_CHECKSIG\n        #\n        # lock until block 500,000\n        cltv_script = '63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac'\n        rpc_result = self.nodes[0].decodescript(cltv_script)\n        assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])\n        # CLTV script in P2WSH\n        cltv_script_hash = sha256(hex_str_to_bytes(cltv_script)).hex()\n        assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm'])\n\n        # 7) P2PK scriptPubKey\n        # <pubkey> OP_CHECKSIG\n        rpc_result = self.nodes[0].decodescript(push_uncompressed_public_key + 'ac')\n        assert_equal(uncompressed_public_key + ' OP_CHECKSIG', rpc_result['asm'])\n        # uncompressed pubkeys are invalid for checksigs in segwit scripts.\n        # decodescript should not return a P2WPKH equivalent.\n        assert 'segwit' not in rpc_result\n\n        # 8) multisig scriptPubKey with an uncompressed pubkey\n        # <m> <A pubkey> <B pubkey> <n> OP_CHECKMULTISIG\n        # just imagine that the pub keys used below are different.\n        # the purpose of this test is to check that a segwit script is not returned for bare multisig scripts\n        # with an uncompressed pubkey in them.\n        rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_uncompressed_public_key +'52ae')\n        assert_equal('2 ' + public_key + ' ' + uncompressed_public_key + ' 2 OP_CHECKMULTISIG', rpc_result['asm'])\n        # uncompressed pubkeys are invalid for checksigs in segwit scripts.\n        # decodescript should not return a P2WPKH equivalent.\n        assert 'segwit' not in rpc_result\n\n        # 9) P2WPKH scriptpubkey\n        # 0 <PubKeyHash>\n        rpc_result = self.nodes[0].decodescript('00' + push_public_key_hash)\n        assert_equal('0 ' + public_key_hash, rpc_result['asm'])\n        # segwit scripts do not work nested into each other.\n        # a nested segwit script should not be returned in the results.\n        assert 'segwit' not in rpc_result\n\n        # 10) P2WSH scriptpubkey\n        # 0 <ScriptHash>\n        # even though this hash is of a P2PK script which is better used as bare P2WPKH, it should not matter\n        # for the purpose of this test.\n        rpc_result = self.nodes[0].decodescript('0020' + p2wsh_p2pk_script_hash)\n        assert_equal('0 ' + p2wsh_p2pk_script_hash, rpc_result['asm'])\n        # segwit scripts do not work nested into each other.\n        # a nested segwit script should not be returned in the results.\n        assert 'segwit' not in rpc_result\n\n    def decoderawtransaction_asm_sighashtype(self):\n        \"\"\"Test decoding scripts via RPC command \"decoderawtransaction\".\n\n        This test is in with the \"decodescript\" tests because they are testing the same \"asm\" script decodes.\n        \"\"\"\n\n        # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output\n        tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'\n        rpc_result = self.nodes[0].decoderawtransaction(tx)\n        assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])\n\n        # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.\n        # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc\n        # verify that we have not altered scriptPubKey decoding.\n        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'\n        rpc_result = self.nodes[0].decoderawtransaction(tx)\n        assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])\n        assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])\n        assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])\n        assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])\n        txSave = CTransaction()\n        txSave.deserialize(BytesIO(hex_str_to_bytes(tx)))\n\n        # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type\n        tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'\n        rpc_result = self.nodes[0].decoderawtransaction(tx)\n        assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])\n\n        # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks\n        tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'\n        rpc_result = self.nodes[0].decoderawtransaction(tx)\n        assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])\n        assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])\n\n        # some more full transaction tests of varying specific scriptSigs. used instead of\n        # tests in decodescript_script_sig because the decodescript RPC is specifically\n        # for working on scriptPubKeys (argh!).\n        push_signature = txSave.vin[0].scriptSig.hex()[2:(0x48*2+4)]\n        signature = push_signature[2:]\n        der_signature = signature[:-2]\n        signature_sighash_decoded = der_signature + '[ALL]'\n        signature_2 = der_signature + '82'\n        push_signature_2 = '48' + signature_2\n        signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'\n\n        # 1) P2PK scriptSig\n        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)\n        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())\n        assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])\n\n        # make sure that the sighash decodes come out correctly for a more complex / lesser used case.\n        txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)\n        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())\n        assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])\n\n        # 2) multisig scriptSig\n        txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2)\n        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())\n        assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])\n\n        # 3) test a scriptSig that contains more than push operations.\n        # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.\n        txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101')\n        rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())\n        assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])\n\n    def run_test(self):\n        self.decodescript_script_sig()\n        self.decodescript_script_pub_key()\n        self.decoderawtransaction_asm_sighashtype()\n\nif __name__ == '__main__':\n    DecodeScriptTest().main()\n"
  },
  {
    "path": "test/functional/rpc_deprecated.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test deprecation of RPC calls.\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\n# from test_framework.util import assert_raises_rpc_error\n\nclass DeprecatedRpcTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n        self.extra_args = [[], []]\n\n    def run_test(self):\n        # This test should be used to verify correct behaviour of deprecated\n        # RPC methods with and without the -deprecatedrpc flags. For example:\n        #\n        # In set_test_params:\n        # self.extra_args = [[], [\"-deprecatedrpc=generate\"]]\n        #\n        # In run_test:\n        # self.log.info(\"Test generate RPC\")\n        # assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1)\n        # self.nodes[1].generate(1)\n        self.log.info(\"No tested deprecated RPC methods\")\n\nif __name__ == '__main__':\n    DeprecatedRpcTest().main()\n"
  },
  {
    "path": "test/functional/rpc_deriveaddresses.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the deriveaddresses rpc call.\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.descriptors import descsum_create\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\nclass DeriveaddressesTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.supports_cli = 1\n\n    def run_test(self):\n        assert_raises_rpc_error(-5, \"Invalid descriptor\", self.nodes[0].deriveaddresses, \"a\")\n\n        descriptor = \"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64\"\n        address = \"bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5\"\n        assert_equal(self.nodes[0].deriveaddresses(descriptor), [address])\n\n        descriptor = descriptor[:-9]\n        assert_raises_rpc_error(-5, \"Invalid descriptor\", self.nodes[0].deriveaddresses, descriptor)\n\n        descriptor_pubkey = \"wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)#s9ga3alw\"\n        address = \"bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5\"\n        assert_equal(self.nodes[0].deriveaddresses(descriptor_pubkey), [address])\n\n        ranged_descriptor = \"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy\"\n        assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, [1, 2]), [\"bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy\", \"bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq\"])\n        assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 2), [address, \"bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy\", \"bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq\"])\n\n        assert_raises_rpc_error(-8, \"Range should not be specified for an un-ranged descriptor\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)\"), [0, 2])\n\n        assert_raises_rpc_error(-8, \"Range must be specified for a ranged descriptor\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\"))\n\n        assert_raises_rpc_error(-8, \"End of range is too high\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\"), 10000000000)\n\n        assert_raises_rpc_error(-8, \"Range is too large\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\"), [1000000000, 2000000000])\n\n        assert_raises_rpc_error(-8, \"Range specified as [begin,end] must not have begin after end\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\"), [2, 0])\n\n        assert_raises_rpc_error(-8, \"Range should be greater or equal than 0\", self.nodes[0].deriveaddresses, descsum_create(\"wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\"), [-1, 0])\n\n        combo_descriptor = descsum_create(\"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)\")\n        assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), [\"mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ\", \"mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ\", address, \"2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x\"])\n\n        hardened_without_privkey_descriptor = descsum_create(\"wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)\")\n        assert_raises_rpc_error(-5, \"Cannot derive script without private keys\", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor)\n\n        bare_multisig_descriptor = descsum_create(\"multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)\")\n        assert_raises_rpc_error(-5, \"Descriptor does not have a corresponding address\", self.nodes[0].deriveaddresses, bare_multisig_descriptor)\n\nif __name__ == '__main__':\n    DeriveaddressesTest().main()\n"
  },
  {
    "path": "test/functional/rpc_fundrawtransaction.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the fundrawtransaction RPC.\"\"\"\n\nfrom decimal import Decimal\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_fee_amount,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n    count_bytes,\n    find_vout_for_address,\n)\n\n\ndef get_unspent(listunspent, amount):\n    for utx in listunspent:\n        if utx['amount'] == amount:\n            return utx\n    raise AssertionError('Could not find unspent with amount={}'.format(amount))\n\nclass RawTransactionsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 1, 2)\n        connect_nodes_bi(self.nodes, 0, 2)\n        connect_nodes_bi(self.nodes, 0, 3)\n\n    def run_test(self):\n        min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']\n        # This test is not meant to test fee estimation and we'd like\n        # to be sure all txs are sent at a consistent desired feerate\n        for node in self.nodes:\n            node.settxfee(min_relay_tx_fee)\n\n        # if the fee's positive delta is higher than this value tests will fail,\n        # neg. delta always fail the tests.\n        # The size of the signature of every input may be at most 2 bytes larger\n        # than a minimum sized signature.\n\n        #            = 2 bytes * minRelayTxFeePerByte\n        feeTolerance = 2 * min_relay_tx_fee/1000\n\n        self.nodes[2].generate(1)\n        self.sync_all()\n        self.nodes[0].generate(121)\n        self.sync_all()\n\n        # ensure that setting changePosition in fundraw with an exact match is handled properly\n        rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50})\n        rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {\"changePosition\":1, \"subtractFeeFromOutputs\":[0]})\n        assert_equal(rawmatch[\"changepos\"], -1)\n\n        watchonly_address = self.nodes[0].getnewaddress()\n        watchonly_pubkey = self.nodes[0].getaddressinfo(watchonly_address)[\"pubkey\"]\n        watchonly_amount = Decimal(200)\n        self.nodes[3].importpubkey(watchonly_pubkey, \"\", True)\n        watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount)\n\n        # Lock UTXO so nodes[0] doesn't accidentally spend it\n        watchonly_vout = find_vout_for_address(self.nodes[0], watchonly_txid, watchonly_address)\n        self.nodes[0].lockunspent(False, [{\"txid\": watchonly_txid, \"vout\": watchonly_vout}])\n\n        self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10)\n\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        ###############\n        # simple test #\n        ###############\n        inputs  = [ ]\n        outputs = { self.nodes[0].getnewaddress() : 1.0 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        assert len(dec_tx['vin']) > 0  #test that we have enough inputs\n\n        ##############################\n        # simple test with two coins #\n        ##############################\n        inputs  = [ ]\n        outputs = { self.nodes[0].getnewaddress() : 2.2 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        assert len(dec_tx['vin']) > 0  #test if we have enough inputs\n\n        ##############################\n        # simple test with two coins #\n        ##############################\n        inputs  = [ ]\n        outputs = { self.nodes[0].getnewaddress() : 2.6 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        assert len(dec_tx['vin']) > 0\n        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')\n\n\n        ################################\n        # simple test with two outputs #\n        ################################\n        inputs  = [ ]\n        outputs = { self.nodes[0].getnewaddress() : 2.6, self.nodes[1].getnewaddress() : 2.5 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        for out in dec_tx['vout']:\n            totalOut += out['value']\n\n        assert len(dec_tx['vin']) > 0\n        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')\n\n\n        #########################################################################\n        # test a fundrawtransaction with a VIN greater than the required amount #\n        #########################################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]\n        outputs = { self.nodes[0].getnewaddress() : 1.0 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        for out in dec_tx['vout']:\n            totalOut += out['value']\n\n        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee\n\n\n        #####################################################################\n        # test a fundrawtransaction with which will not get a change output #\n        #####################################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        for out in dec_tx['vout']:\n            totalOut += out['value']\n\n        assert_equal(rawtxfund['changepos'], -1)\n        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee\n\n\n        ####################################################\n        # test a fundrawtransaction with an invalid option #\n        ####################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        assert_raises_rpc_error(-3, \"Unexpected key foo\", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'})\n\n        # reserveChangeKey was deprecated and is now removed\n        assert_raises_rpc_error(-3, \"Unexpected key reserveChangeKey\", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, options={'reserveChangeKey': True}))\n\n        ############################################################\n        # test a fundrawtransaction with an invalid change address #\n        ############################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        assert_raises_rpc_error(-5, \"changeAddress must be a valid Munt address\", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})\n\n        ############################################################\n        # test a fundrawtransaction with a provided change address #\n        ############################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        change = self.nodes[2].getnewaddress()\n        assert_raises_rpc_error(-8, \"changePosition out of bounds\", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2})\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        out = dec_tx['vout'][0]\n        assert_equal(change, out['scriptPubKey']['addresses'][0])\n\n        #########################################################\n        # test a fundrawtransaction with a provided change type #\n        #########################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[2].fundrawtransaction, rawtx, {'change_type': None})\n        assert_raises_rpc_error(-5, \"Unknown change type ''\", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''})\n        rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'})\n        dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex'])\n        assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type'])\n\n        #########################################################################\n        # test a fundrawtransaction with a VIN smaller than the required amount #\n        #########################################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 1)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]\n        outputs = { self.nodes[0].getnewaddress() : 1.0 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n\n        # 4-byte version + 1-byte vin count + 36-byte prevout then script_len\n        rawtx = rawtx[:82] + \"0100\" + rawtx[84:]\n\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n        assert_equal(\"00\", dec_tx['vin'][0]['scriptSig']['hex'])\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        matchingOuts = 0\n        for i, out in enumerate(dec_tx['vout']):\n            totalOut += out['value']\n            if out['scriptPubKey']['addresses'][0] in outputs:\n                matchingOuts+=1\n            else:\n                assert_equal(i, rawtxfund['changepos'])\n\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n        assert_equal(\"00\", dec_tx['vin'][0]['scriptSig']['hex'])\n\n        assert_equal(matchingOuts, 1)\n        assert_equal(len(dec_tx['vout']), 2)\n\n\n        ###########################################\n        # test a fundrawtransaction with two VINs #\n        ###########################################\n        utx = get_unspent(self.nodes[2].listunspent(), 1)\n        utx2 = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : 6.0 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        matchingOuts = 0\n        for out in dec_tx['vout']:\n            totalOut += out['value']\n            if out['scriptPubKey']['addresses'][0] in outputs:\n                matchingOuts+=1\n\n        assert_equal(matchingOuts, 1)\n        assert_equal(len(dec_tx['vout']), 2)\n\n        matchingIns = 0\n        for vinOut in dec_tx['vin']:\n            for vinIn in inputs:\n                if vinIn['txid'] == vinOut['txid']:\n                    matchingIns+=1\n\n        assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params\n\n        #########################################################\n        # test a fundrawtransaction with two VINs and two vOUTs #\n        #########################################################\n        utx = get_unspent(self.nodes[2].listunspent(), 1)\n        utx2 = get_unspent(self.nodes[2].listunspent(), 5)\n\n        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]\n        outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        fee = rawtxfund['fee']\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n        totalOut = 0\n        matchingOuts = 0\n        for out in dec_tx['vout']:\n            totalOut += out['value']\n            if out['scriptPubKey']['addresses'][0] in outputs:\n                matchingOuts+=1\n\n        assert_equal(matchingOuts, 2)\n        assert_equal(len(dec_tx['vout']), 3)\n\n        ##############################################\n        # test a fundrawtransaction with invalid vin #\n        ##############################################\n        inputs  = [ {'txid' : \"1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1\", 'vout' : 0} ] #invalid vin!\n        outputs = { self.nodes[0].getnewaddress() : 1.0}\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n\n        assert_raises_rpc_error(-4, \"Insufficient funds\", self.nodes[2].fundrawtransaction, rawtx)\n\n        ############################################################\n        #compare fee of a standard pubkeyhash transaction\n        inputs = []\n        outputs = {self.nodes[1].getnewaddress():1.1}\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[0].fundrawtransaction(rawtx)\n\n        #create same transaction over sendtoaddress\n        txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)\n        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']\n\n        #compare fee\n        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)\n        assert feeDelta >= 0 and feeDelta <= feeTolerance\n        ############################################################\n\n        ############################################################\n        #compare fee of a standard pubkeyhash transaction with multiple outputs\n        inputs = []\n        outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3}\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[0].fundrawtransaction(rawtx)\n        #create same transaction over sendtoaddress\n        txId = self.nodes[0].sendmany(\"\", outputs)\n        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']\n\n        #compare fee\n        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)\n        assert feeDelta >= 0 and feeDelta <= feeTolerance\n        ############################################################\n\n\n        ############################################################\n        #compare fee of a 2of2 multisig p2sh transaction\n\n        # create 2of2 addr\n        addr1 = self.nodes[1].getnewaddress()\n        addr2 = self.nodes[1].getnewaddress()\n\n        addr1Obj = self.nodes[1].getaddressinfo(addr1)\n        addr2Obj = self.nodes[1].getaddressinfo(addr2)\n\n        mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']\n\n        inputs = []\n        outputs = {mSigObj:1.1}\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[0].fundrawtransaction(rawtx)\n\n        #create same transaction over sendtoaddress\n        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)\n        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']\n\n        #compare fee\n        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)\n        assert feeDelta >= 0 and feeDelta <= feeTolerance\n        ############################################################\n\n\n        ############################################################\n        #compare fee of a standard pubkeyhash transaction\n\n        # create 4of5 addr\n        addr1 = self.nodes[1].getnewaddress()\n        addr2 = self.nodes[1].getnewaddress()\n        addr3 = self.nodes[1].getnewaddress()\n        addr4 = self.nodes[1].getnewaddress()\n        addr5 = self.nodes[1].getnewaddress()\n\n        addr1Obj = self.nodes[1].getaddressinfo(addr1)\n        addr2Obj = self.nodes[1].getaddressinfo(addr2)\n        addr3Obj = self.nodes[1].getaddressinfo(addr3)\n        addr4Obj = self.nodes[1].getaddressinfo(addr4)\n        addr5Obj = self.nodes[1].getaddressinfo(addr5)\n\n        mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']])['address']\n\n        inputs = []\n        outputs = {mSigObj:1.1}\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[0].fundrawtransaction(rawtx)\n\n        #create same transaction over sendtoaddress\n        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)\n        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']\n\n        #compare fee\n        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)\n        assert feeDelta >= 0 and feeDelta <= feeTolerance\n        ############################################################\n\n\n        ############################################################\n        # spend a 2of2 multisig transaction over fundraw\n\n        # create 2of2 addr\n        addr1 = self.nodes[2].getnewaddress()\n        addr2 = self.nodes[2].getnewaddress()\n\n        addr1Obj = self.nodes[2].getaddressinfo(addr1)\n        addr2Obj = self.nodes[2].getaddressinfo(addr2)\n\n        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']\n\n\n        # send 1.2 BTC to msig addr\n        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)\n        self.sync_all()\n        self.nodes[1].generate(1)\n        self.sync_all()\n\n        oldBalance = self.nodes[1].getbalance()\n        inputs = []\n        outputs = {self.nodes[1].getnewaddress():1.1}\n        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[2].fundrawtransaction(rawtx)\n\n        signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])\n        txId = self.nodes[2].sendrawtransaction(signedTx['hex'])\n        self.sync_all()\n        self.nodes[1].generate(1)\n        self.sync_all()\n\n        # make sure funds are received at node1\n        assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance())\n\n        ############################################################\n        # locked wallet test\n        self.nodes[1].encryptwallet(\"test\")\n        self.stop_nodes()\n\n        self.start_nodes()\n        # This test is not meant to test fee estimation and we'd like\n        # to be sure all txs are sent at a consistent desired feerate\n        for node in self.nodes:\n            node.settxfee(min_relay_tx_fee)\n\n        connect_nodes_bi(self.nodes,0,1)\n        connect_nodes_bi(self.nodes,1,2)\n        connect_nodes_bi(self.nodes,0,2)\n        connect_nodes_bi(self.nodes,0,3)\n        # Again lock the watchonly UTXO or nodes[0] may spend it, because\n        # lockunspent is memory-only and thus lost on restart\n        self.nodes[0].lockunspent(False, [{\"txid\": watchonly_txid, \"vout\": watchonly_vout}])\n        self.sync_all()\n\n        # drain the keypool\n        self.nodes[1].getnewaddress()\n        self.nodes[1].getrawchangeaddress()\n        inputs = []\n        outputs = {self.nodes[0].getnewaddress():1.1}\n        rawtx = self.nodes[1].createrawtransaction(inputs, outputs)\n        # fund a transaction that requires a new key for the change output\n        # creating the key must be impossible because the wallet is locked\n        assert_raises_rpc_error(-4, \"Keypool ran out, please call keypoolrefill first\", self.nodes[1].fundrawtransaction, rawtx)\n\n        #refill the keypool\n        self.nodes[1].walletpassphrase(\"test\", 100)\n        self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address\n        self.nodes[1].walletlock()\n\n        assert_raises_rpc_error(-13, \"walletpassphrase\", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2)\n\n        oldBalance = self.nodes[0].getbalance()\n\n        inputs = []\n        outputs = {self.nodes[0].getnewaddress():1.1}\n        rawtx = self.nodes[1].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[1].fundrawtransaction(rawtx)\n\n        #now we need to unlock\n        self.nodes[1].walletpassphrase(\"test\", 600)\n        signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])\n        txId = self.nodes[1].sendrawtransaction(signedTx['hex'])\n        self.nodes[1].generate(1)\n        self.sync_all()\n\n        # make sure funds are received at node1\n        assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance())\n\n\n        ###############################################\n        # multiple (~19) inputs tx test | Compare fee #\n        ###############################################\n\n        #empty node1, send some small coins from node0 to node1\n        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), \"\", \"\", True)\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        for i in range(0,20):\n            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        #fund a tx with ~20 small inputs\n        inputs = []\n        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}\n        rawtx = self.nodes[1].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[1].fundrawtransaction(rawtx)\n\n        #create same transaction over sendtoaddress\n        txId = self.nodes[1].sendmany(\"\", outputs)\n        signedFee = self.nodes[1].getrawmempool(True)[txId]['fee']\n\n        #compare fee\n        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)\n        assert feeDelta >= 0 and feeDelta <= feeTolerance*19  #~19 inputs\n\n\n        #############################################\n        # multiple (~19) inputs tx test | sign/send #\n        #############################################\n\n        #again, empty node1, send some small coins from node0 to node1\n        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), \"\", \"\", True)\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        for i in range(0,20):\n            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        #fund a tx with ~20 small inputs\n        oldBalance = self.nodes[0].getbalance()\n\n        inputs = []\n        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}\n        rawtx = self.nodes[1].createrawtransaction(inputs, outputs)\n        fundedTx = self.nodes[1].fundrawtransaction(rawtx)\n        fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])\n        txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n        assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward\n\n        #####################################################\n        # test fundrawtransaction with OP_RETURN and no vin #\n        #####################################################\n\n        rawtx   = \"0100000000010000000000000000066a047465737400000000\"\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)\n\n        assert_equal(len(dec_tx['vin']), 0)\n        assert_equal(len(dec_tx['vout']), 1)\n\n        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)\n        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])\n\n        assert_greater_than(len(dec_tx['vin']), 0) # at least one vin\n        assert_equal(len(dec_tx['vout']), 2) # one change output added\n\n\n        ##################################################\n        # test a fundrawtransaction using only watchonly #\n        ##################################################\n\n        inputs = []\n        outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2}\n        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)\n\n        result = self.nodes[3].fundrawtransaction(rawtx, {'includeWatching': True })\n        res_dec = self.nodes[0].decoderawtransaction(result[\"hex\"])\n        assert_equal(len(res_dec[\"vin\"]), 1)\n        assert_equal(res_dec[\"vin\"][0][\"txid\"], watchonly_txid)\n\n        assert \"fee\" in result.keys()\n        assert_greater_than(result[\"changepos\"], -1)\n\n        ###############################################################\n        # test fundrawtransaction using the entirety of watched funds #\n        ###############################################################\n\n        inputs = []\n        outputs = {self.nodes[2].getnewaddress() : watchonly_amount}\n        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)\n\n        # Backward compatibility test (2nd param is includeWatching)\n        result = self.nodes[3].fundrawtransaction(rawtx, True)\n        res_dec = self.nodes[0].decoderawtransaction(result[\"hex\"])\n        assert_equal(len(res_dec[\"vin\"]), 2)\n        assert res_dec[\"vin\"][0][\"txid\"] == watchonly_txid or res_dec[\"vin\"][1][\"txid\"] == watchonly_txid\n\n        assert_greater_than(result[\"fee\"], 0)\n        assert_greater_than(result[\"changepos\"], -1)\n        assert_equal(result[\"fee\"] + res_dec[\"vout\"][result[\"changepos\"]][\"value\"], watchonly_amount / 10)\n\n        signedtx = self.nodes[3].signrawtransaction(result[\"hex\"])\n        assert not signedtx[\"complete\"]\n        signedtx = self.nodes[0].signrawtransaction(signedtx[\"hex\"])\n        assert signedtx[\"complete\"]\n        self.nodes[0].sendrawtransaction(signedtx[\"hex\"])\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        #######################\n        # Test feeRate option #\n        #######################\n\n        # Make sure there is exactly one input so coin selection can't skew the result\n        assert_equal(len(self.nodes[3].listunspent(1)), 1)\n\n        inputs = []\n        outputs = {self.nodes[3].getnewaddress() : 1}\n        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)\n        result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)\n        result2 = self.nodes[3].fundrawtransaction(rawtx, {\"feeRate\": 2*min_relay_tx_fee})\n        result3 = self.nodes[3].fundrawtransaction(rawtx, {\"feeRate\": 10*min_relay_tx_fee})\n        result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])\n        assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)\n        assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)\n\n        ################################\n        # Test no address reuse occurs #\n        ################################\n\n        result3 = self.nodes[3].fundrawtransaction(rawtx)\n        res_dec = self.nodes[0].decoderawtransaction(result3[\"hex\"])\n        changeaddress = \"\"\n        for out in res_dec['vout']:\n            if out['value'] > 1.0:\n                changeaddress += out['scriptPubKey']['addresses'][0]\n        assert changeaddress != \"\"\n        nextaddr = self.nodes[3].getnewaddress()\n        # Now the change address key should be removed from the keypool\n        assert changeaddress != nextaddr\n\n        ######################################\n        # Test subtractFeeFromOutputs option #\n        ######################################\n\n        # Make sure there is exactly one input so coin selection can't skew the result\n        assert_equal(len(self.nodes[3].listunspent(1)), 1)\n\n        inputs = []\n        outputs = {self.nodes[2].getnewaddress(): 1}\n        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)\n\n        result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee)\n                  self.nodes[3].fundrawtransaction(rawtx, {\"subtractFeeFromOutputs\": []}), # empty subtraction list\n                  self.nodes[3].fundrawtransaction(rawtx, {\"subtractFeeFromOutputs\": [0]}), # uses min_relay_tx_fee (set by settxfee)\n                  self.nodes[3].fundrawtransaction(rawtx, {\"feeRate\": 2*min_relay_tx_fee}),\n                  self.nodes[3].fundrawtransaction(rawtx, {\"feeRate\": 2*min_relay_tx_fee, \"subtractFeeFromOutputs\": [0]})]\n\n        dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]\n        output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]\n        change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]\n\n        assert_equal(result[0]['fee'], result[1]['fee'], result[2]['fee'])\n        assert_equal(result[3]['fee'], result[4]['fee'])\n        assert_equal(change[0], change[1])\n        assert_equal(output[0], output[1])\n        assert_equal(output[0], output[2] + result[2]['fee'])\n        assert_equal(change[0] + result[0]['fee'], change[2])\n        assert_equal(output[3], output[4] + result[4]['fee'])\n        assert_equal(change[3] + result[3]['fee'], change[4])\n\n        inputs = []\n        outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)}\n        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)\n\n        result = [self.nodes[3].fundrawtransaction(rawtx),\n                  # split the fee between outputs 0, 2, and 3, but not output 1\n                  self.nodes[3].fundrawtransaction(rawtx, {\"subtractFeeFromOutputs\": [0, 2, 3]})]\n\n        dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),\n                  self.nodes[3].decoderawtransaction(result[1]['hex'])]\n\n        # Nested list of non-change output amounts for each transaction\n        output = [[out['value'] for i, out in enumerate(d['vout']) if i != r['changepos']]\n                  for d, r in zip(dec_tx, result)]\n\n        # List of differences in output amounts between normal and subtractFee transactions\n        share = [o0 - o1 for o0, o1 in zip(output[0], output[1])]\n\n        # output 1 is the same in both transactions\n        assert_equal(share[1], 0)\n\n        # the other 3 outputs are smaller as a result of subtractFeeFromOutputs\n        assert_greater_than(share[0], 0)\n        assert_greater_than(share[2], 0)\n        assert_greater_than(share[3], 0)\n\n        # outputs 2 and 3 take the same share of the fee\n        assert_equal(share[2], share[3])\n\n        # output 0 takes at least as much share of the fee, and no more than 2 satoshis more, than outputs 2 and 3\n        assert_greater_than_or_equal(share[0], share[2])\n        assert_greater_than_or_equal(share[2] + Decimal(2e-8), share[0])\n\n        # the fee is the same in both transactions\n        assert_equal(result[0]['fee'], result[1]['fee'])\n\n        # the total subtracted from the outputs is equal to the fee\n        assert_equal(share[0] + share[2] + share[3], result[0]['fee'])\n\nif __name__ == '__main__':\n    RawTransactionsTest().main()\n"
  },
  {
    "path": "test/functional/rpc_getblockstats.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n#\n# Test getblockstats rpc call\n#\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\nimport json\nimport os\nimport time\n\nTESTSDIR = os.path.dirname(os.path.realpath(__file__))\n\nclass GetblockstatsTest(MuntTestFramework):\n\n    start_height = 101\n    max_stat_pos = 2\n    STATS_NEED_TXINDEX = [\n        'avgfee',\n        'avgfeerate',\n        'maxfee',\n        'maxfeerate',\n        'medianfee',\n        'feerate_percentiles',\n        'minfee',\n        'minfeerate',\n        'totalfee',\n        'utxo_size_inc',\n    ]\n\n    def add_options(self, parser):\n        parser.add_argument('--gen-test-data', dest='gen_test_data',\n                            default=False, action='store_true',\n                            help='Generate test data')\n        parser.add_argument('--test-data', dest='test_data',\n                            default='data/rpc_getblockstats.json',\n                            action='store', metavar='FILE',\n                            help='Test data file')\n\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [['-txindex'], ['-paytxfee=0.003']]\n        self.setup_clean_chain = True\n\n    def get_stats(self):\n        return [self.nodes[0].getblockstats(hash_or_height=self.start_height + i) for i in range(self.max_stat_pos+1)]\n\n    def generate_test_data(self, filename):\n        mocktime = time.time()\n        self.nodes[0].generate(101)\n\n        self.nodes[0].sendtoaddress(address=self.nodes[1].getnewaddress(), amount=10, subtract_fee_from_amount=True)\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtract_fee_from_amount=True)\n        self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtract_fee_from_amount=False)\n        self.nodes[1].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1, subtract_fee_from_amount=True)\n        self.sync_all()\n        self.nodes[0].generate(1)\n\n        self.expected_stats = self.get_stats()\n\n        blocks = []\n        tip = self.nodes[0].getbestblockhash()\n        blockhash = None\n        height = 0\n        while tip != blockhash:\n            blockhash = self.nodes[0].getblockhash(height)\n            blocks.append(self.nodes[0].getblock(blockhash, 0))\n            height += 1\n\n        to_dump = {\n            'blocks': blocks,\n            'mocktime': int(mocktime),\n            'stats': self.expected_stats,\n        }\n        with open(filename, 'w', encoding=\"utf8\") as f:\n            json.dump(to_dump, f, sort_keys=True, indent=2)\n\n    def load_test_data(self, filename):\n        with open(filename, 'r', encoding=\"utf8\") as f:\n            d = json.load(f)\n            blocks = d['blocks']\n            mocktime = d['mocktime']\n            self.expected_stats = d['stats']\n\n        # Set the timestamps from the file so that the nodes can get out of Initial Block Download\n        self.nodes[0].setmocktime(mocktime)\n        self.nodes[1].setmocktime(mocktime)\n\n        for b in blocks:\n            self.nodes[0].submitblock(b)\n\n    def run_test(self):\n        test_data = os.path.join(TESTSDIR, self.options.test_data)\n        if self.options.gen_test_data:\n            self.generate_test_data(test_data)\n        else:\n            self.load_test_data(test_data)\n\n        self.sync_all()\n        stats = self.get_stats()\n        expected_stats_noindex = []\n        for stat_row in stats:\n            expected_stats_noindex.append({k: v for k, v in stat_row.items() if k not in self.STATS_NEED_TXINDEX})\n\n        # Make sure all valid statistics are included but nothing else is\n        expected_keys = self.expected_stats[0].keys()\n        assert_equal(set(stats[0].keys()), set(expected_keys))\n\n        assert_equal(stats[0]['height'], self.start_height)\n        assert_equal(stats[self.max_stat_pos]['height'], self.start_height + self.max_stat_pos)\n\n        for i in range(self.max_stat_pos+1):\n            self.log.info('Checking block %d\\n' % (i))\n            assert_equal(stats[i], self.expected_stats[i])\n\n            # Check selecting block by hash too\n            blockhash = self.expected_stats[i]['blockhash']\n            stats_by_hash = self.nodes[0].getblockstats(hash_or_height=blockhash)\n            assert_equal(stats_by_hash, self.expected_stats[i])\n\n            # Check with the node that has no txindex\n            stats_no_txindex = self.nodes[1].getblockstats(hash_or_height=blockhash, stats=list(expected_stats_noindex[i].keys()))\n            assert_equal(stats_no_txindex, expected_stats_noindex[i])\n\n        # Make sure each stat can be queried on its own\n        for stat in expected_keys:\n            for i in range(self.max_stat_pos+1):\n                result = self.nodes[0].getblockstats(hash_or_height=self.start_height + i, stats=[stat])\n                assert_equal(list(result.keys()), [stat])\n                if result[stat] != self.expected_stats[i][stat]:\n                    self.log.info('result[%s] (%d) failed, %r != %r' % (\n                        stat, i, result[stat], self.expected_stats[i][stat]))\n                assert_equal(result[stat], self.expected_stats[i][stat])\n\n        # Make sure only the selected statistics are included (more than one)\n        some_stats = {'minfee', 'maxfee'}\n        stats = self.nodes[0].getblockstats(hash_or_height=1, stats=list(some_stats))\n        assert_equal(set(stats.keys()), some_stats)\n\n        # Test invalid parameters raise the proper json exceptions\n        tip = self.start_height + self.max_stat_pos\n        assert_raises_rpc_error(-8, 'Target block height %d after current tip %d' % (tip+1, tip),\n                                self.nodes[0].getblockstats, hash_or_height=tip+1)\n        assert_raises_rpc_error(-8, 'Target block height %d is negative' % (-1),\n                                self.nodes[0].getblockstats, hash_or_height=-1)\n\n        # Make sure not valid stats aren't allowed\n        inv_sel_stat = 'asdfghjkl'\n        inv_stats = [\n            [inv_sel_stat],\n            ['minfee' , inv_sel_stat],\n            [inv_sel_stat, 'minfee'],\n            ['minfee', inv_sel_stat, 'maxfee'],\n        ]\n        for inv_stat in inv_stats:\n            assert_raises_rpc_error(-8, 'Invalid selected statistic %s' % inv_sel_stat,\n                                    self.nodes[0].getblockstats, hash_or_height=1, stats=inv_stat)\n\n        # Make sure we aren't always returning inv_sel_stat as the culprit stat\n        assert_raises_rpc_error(-8, 'Invalid selected statistic aaa%s' % inv_sel_stat,\n                                self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee' , 'aaa%s' % inv_sel_stat])\n\n        ###assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',\n        ###                       self.nodes[1].getblockstats, hash_or_height=1)\n        ###assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',\n        ###                        self.nodes[1].getblockstats, hash_or_height=self.start_height + self.max_stat_pos)\n\n        # Mainchain's genesis block shouldn't be found on regtest\n        assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats,\n                                hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')\n\n        # Invalid number of args\n        ###assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2)\n        ###assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats)\n\n\nif __name__ == '__main__':\n    GetblockstatsTest().main()\n"
  },
  {
    "path": "test/functional/rpc_getchaintips.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the getchaintips RPC.\n\n- introduce a network split\n- work on chains of different lengths\n- join the network together again\n- verify that getchaintips now returns two chain tips.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass GetChainTipsTest (MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n\n    def run_test(self):\n        tips = self.nodes[0].getchaintips()\n        assert_equal(len(tips), 1)\n        assert_equal(tips[0]['branchlen'], 0)\n        assert_equal(tips[0]['height'], 200)\n        assert_equal(tips[0]['status'], 'active')\n\n        # Split the network and build two chains of different lengths.\n        self.split_network()\n        self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)\n        self.nodes[2].generatetoaddress(20, self.nodes[2].get_deterministic_priv_key().address)\n        self.sync_all([self.nodes[:2], self.nodes[2:]])\n\n        tips = self.nodes[1].getchaintips ()\n        assert_equal (len (tips), 1)\n        shortTip = tips[0]\n        assert_equal (shortTip['branchlen'], 0)\n        assert_equal (shortTip['height'], 210)\n        assert_equal (tips[0]['status'], 'active')\n\n        tips = self.nodes[3].getchaintips ()\n        assert_equal (len (tips), 1)\n        longTip = tips[0]\n        assert_equal (longTip['branchlen'], 0)\n        assert_equal (longTip['height'], 220)\n        assert_equal (tips[0]['status'], 'active')\n\n        # Join the network halves and check that we now have two tips\n        # (at least at the nodes that previously had the short chain).\n        self.join_network ()\n\n        tips = self.nodes[0].getchaintips ()\n        assert_equal (len (tips), 2)\n        assert_equal (tips[0], longTip)\n\n        assert_equal (tips[1]['branchlen'], 10)\n        assert_equal (tips[1]['status'], 'valid-fork')\n        tips[1]['branchlen'] = 0\n        tips[1]['status'] = 'active'\n        assert_equal (tips[1], shortTip)\n\nif __name__ == '__main__':\n    GetChainTipsTest ().main ()\n"
  },
  {
    "path": "test/functional/rpc_help.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test RPC help output.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\nimport os\n\n\nclass HelpRpcTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def run_test(self):\n        self.test_categories()\n        self.dump_help()\n\n    def test_categories(self):\n        node = self.nodes[0]\n\n        # wrong argument count\n        assert_raises_rpc_error(-1, 'help', node.help, 'foo', 'bar')\n\n        # invalid argument\n        assert_raises_rpc_error(-1, 'JSON value is not a string as expected', node.help, 0)\n\n        # help of unknown command\n        assert_equal(node.help('foo'), 'help: unknown command: foo')\n\n        # command titles\n        titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]\n\n        components = ['Accounts', 'Block_generation', 'Blockchain', 'Control', 'Developer', 'Generating', 'Mnemonics', 'Network', 'Rawtransactions', 'Util']\n\n        if self.is_wallet_compiled():\n            components.append('Wallet')\n\n        components.append('Witness')\n\n        ###if self.is_zmq_compiled():\n            ###components.append('Zmq')\n\n        assert_equal(titles, components)\n\n    def dump_help(self):\n        dump_dir = os.path.join(self.options.tmpdir, 'rpc_help_dump')\n        os.mkdir(dump_dir)\n        calls = [line.split(' ', 1)[0] for line in self.nodes[0].help().splitlines() if line and not line.startswith('==')]\n        for call in calls:\n            with open(os.path.join(dump_dir, call), 'w', encoding='utf-8') as f:\n                # Make sure the node can generate the help at runtime without crashing\n                f.write(self.nodes[0].help(call))\n\n\nif __name__ == '__main__':\n    HelpRpcTest().main()\n"
  },
  {
    "path": "test/functional/rpc_invalidateblock.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the invalidateblock RPC.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.address import ADDRESS_BCRT1_UNSPENDABLE\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes_bi,\n    sync_blocks,\n    wait_until,\n)\n\n\nclass InvalidateTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n\n    def setup_network(self):\n        self.setup_nodes()\n\n    def run_test(self):\n        self.log.info(\"Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:\")\n        self.log.info(\"Mine 4 blocks on Node 0\")\n        self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address)\n        assert_equal(self.nodes[0].getblockcount(), 4)\n        besthash_n0 = self.nodes[0].getbestblockhash()\n\n        self.log.info(\"Mine competing 6 blocks on Node 1\")\n        self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address)\n        assert_equal(self.nodes[1].getblockcount(), 6)\n\n        self.log.info(\"Connect nodes to force a reorg\")\n        connect_nodes_bi(self.nodes, 0, 1)\n        sync_blocks(self.nodes[0:2])\n        assert_equal(self.nodes[0].getblockcount(), 6)\n        badhash = self.nodes[1].getblockhash(2)\n\n        self.log.info(\"Invalidate block 2 on node 0 and verify we reorg to node 0's original chain\")\n        self.nodes[0].invalidateblock(badhash)\n        assert_equal(self.nodes[0].getblockcount(), 4)\n        assert_equal(self.nodes[0].getbestblockhash(), besthash_n0)\n\n        self.log.info(\"Make sure we won't reorg to a lower work chain:\")\n        connect_nodes_bi(self.nodes, 1, 2)\n        self.log.info(\"Sync node 2 to node 1 so both have 6 blocks\")\n        sync_blocks(self.nodes[1:3])\n        assert_equal(self.nodes[2].getblockcount(), 6)\n        self.log.info(\"Invalidate block 5 on node 1 so its tip is now at 4\")\n        self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5))\n        assert_equal(self.nodes[1].getblockcount(), 4)\n        self.log.info(\"Invalidate block 3 on node 2, so its tip is now 2\")\n        self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))\n        assert_equal(self.nodes[2].getblockcount(), 2)\n        self.log.info(\"..and then mine a block\")\n        self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address)\n        self.log.info(\"Verify all nodes are at the right height\")\n        wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5)\n        wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5)\n        wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5)\n\n        self.log.info(\"Verify that we reconsider all ancestors as well\")\n        blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE)\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])\n        # Invalidate the two blocks at the tip\n        self.nodes[1].invalidateblock(blocks[-1])\n        self.nodes[1].invalidateblock(blocks[-2])\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-3])\n        # Reconsider only the previous tip\n        self.nodes[1].reconsiderblock(blocks[-1])\n        # Should be back at the tip by now\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])\n\n        self.log.info(\"Verify that we reconsider all descendants\")\n        blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE)\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])\n        # Invalidate the two blocks at the tip\n        self.nodes[1].invalidateblock(blocks[-2])\n        self.nodes[1].invalidateblock(blocks[-4])\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-5])\n        # Reconsider only the previous tip\n        self.nodes[1].reconsiderblock(blocks[-4])\n        # Should be back at the tip by now\n        assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])\n\n\nif __name__ == '__main__':\n    InvalidateTest().main()\n"
  },
  {
    "path": "test/functional/rpc_misc.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test RPC misc output.\"\"\"\nimport xml.etree.ElementTree as ET\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_raises_rpc_error,\n    assert_equal,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n)\n\nfrom test_framework.authproxy import JSONRPCException\n\n\nclass RpcMiscTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def run_test(self):\n        node = self.nodes[0]\n\n        self.log.info(\"test getmemoryinfo\")\n        memory = node.getmemoryinfo()['locked']\n        assert_greater_than(memory['used'], 0)\n        assert_greater_than(memory['free'], 0)\n        assert_greater_than(memory['total'], 0)\n        # assert_greater_than_or_equal() for locked in case locking pages failed at some point\n        assert_greater_than_or_equal(memory['locked'], 0)\n        assert_greater_than(memory['chunks_used'], 0)\n        assert_greater_than(memory['chunks_free'], 0)\n        assert_equal(memory['used'] + memory['free'], memory['total'])\n\n        self.log.info(\"test mallocinfo\")\n        try:\n            mallocinfo = node.getmemoryinfo(mode=\"mallocinfo\")\n            self.log.info('getmemoryinfo(mode=\"mallocinfo\") call succeeded')\n            tree = ET.fromstring(mallocinfo)\n            assert_equal(tree.tag, 'malloc')\n        except JSONRPCException:\n            self.log.info('getmemoryinfo(mode=\"mallocinfo\") not available')\n            assert_raises_rpc_error(-8, 'mallocinfo is only available when compiled with glibc 2.10+', node.getmemoryinfo, mode=\"mallocinfo\")\n\n        assert_raises_rpc_error(-8, \"unknown mode foobar\", node.getmemoryinfo, mode=\"foobar\")\n\nif __name__ == '__main__':\n    RpcMiscTest().main()\n"
  },
  {
    "path": "test/functional/rpc_named_arguments.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test using named arguments for RPCs.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\nclass NamedArgumentTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def run_test(self):\n        node = self.nodes[0]\n        h = node.help(command='getblockchaininfo')\n        assert h.startswith('getblockchaininfo\\n')\n\n        assert_raises_rpc_error(-8, 'Unknown named parameter', node.help, random='getblockchaininfo')\n\n        h = node.getblockhash(height=0)\n        node.getblock(blockhash=h)\n\n        assert_equal(node.echo(), [])\n        assert_equal(node.echo(arg0=0,arg9=9), [0] + [None]*8 + [9])\n        assert_equal(node.echo(arg1=1), [None, 1])\n        assert_equal(node.echo(arg9=None), [None]*10)\n        assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9])\n\nif __name__ == '__main__':\n    NamedArgumentTest().main()\n"
  },
  {
    "path": "test/functional/rpc_net.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test RPC calls related to net.\n\nTests correspond to code in rpc/net.cpp.\n\"\"\"\n\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than_or_equal,\n    assert_greater_than,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n    p2p_port,\n    wait_until,\n)\nfrom test_framework.mininode import P2PInterface\nfrom test_framework.messages import CAddress, msg_addr, NODE_NETWORK, NODE_WITNESS\n\nclass NetTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.extra_args = [[\"-minrelaytxfee=0.00001000\"],[\"-minrelaytxfee=0.00000500\"]]\n\n    def run_test(self):\n        self._test_connection_count()\n        self._test_getnettotals()\n        self._test_getnetworkinginfo()\n        self._test_getaddednodeinfo()\n        self._test_getpeerinfo()\n        #fixme: Munt doesn't have this RPC command yet\n        #self._test_getnodeaddresses()\n\n    def _test_connection_count(self):\n        # connect_nodes_bi connects each node to the other\n        assert_equal(self.nodes[0].getconnectioncount(), 2)\n\n    def _test_getnettotals(self):\n        # getnettotals totalbytesrecv and totalbytessent should be\n        # consistent with getpeerinfo. Since the RPC calls are not atomic,\n        # and messages might have been recvd or sent between RPC calls, call\n        # getnettotals before and after and verify that the returned values\n        # from getpeerinfo are bounded by those values.\n        net_totals_before = self.nodes[0].getnettotals()\n        peer_info = self.nodes[0].getpeerinfo()\n        net_totals_after = self.nodes[0].getnettotals()\n        assert_equal(len(peer_info), 2)\n        peers_recv = sum([peer['bytesrecv'] for peer in peer_info])\n        peers_sent = sum([peer['bytessent'] for peer in peer_info])\n\n        assert_greater_than_or_equal(peers_recv, net_totals_before['totalbytesrecv'])\n        assert_greater_than_or_equal(net_totals_after['totalbytesrecv'], peers_recv)\n        assert_greater_than_or_equal(peers_sent, net_totals_before['totalbytessent'])\n        assert_greater_than_or_equal(net_totals_after['totalbytessent'], peers_sent)\n\n        # test getnettotals and getpeerinfo by doing a ping\n        # the bytes sent/received should change\n        # note ping and pong are 32 bytes each\n        self.nodes[0].ping()\n        wait_until(lambda: (self.nodes[0].getnettotals()['totalbytessent'] >= net_totals_after['totalbytessent'] + 32 * 2), timeout=1)\n        wait_until(lambda: (self.nodes[0].getnettotals()['totalbytesrecv'] >= net_totals_after['totalbytesrecv'] + 32 * 2), timeout=1)\n\n        peer_info_after_ping = self.nodes[0].getpeerinfo()\n        for before, after in zip(peer_info, peer_info_after_ping):\n            assert_greater_than_or_equal(after['bytesrecv_per_msg'].get('pong', 0), before['bytesrecv_per_msg'].get('pong', 0) + 32)\n            assert_greater_than_or_equal(after['bytessent_per_msg'].get('ping', 0), before['bytessent_per_msg'].get('ping', 0) + 32)\n\n    def _test_getnetworkinginfo(self):\n        assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)\n        assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)\n\n        # fixme: this fails for some reason; temporarily disabled but must be fixed.\n        #self.nodes[0].setnetworkactive(state=False)\n        #assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)\n        # Wait a bit for all sockets to close\n        #wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3)\n\n        #self.nodes[0].setnetworkactive(state=True)\n        #connect_nodes_bi(self.nodes, 0, 1)\n        #assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)\n        #assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)\n\n    def _test_getaddednodeinfo(self):\n        assert_equal(self.nodes[0].getaddednodeinfo(), [])\n        # add a node (node2) to node0\n        ip_port = \"127.0.0.1:{}\".format(p2p_port(2))\n        self.nodes[0].addnode(node=ip_port, command='add')\n        # check that the node has indeed been added\n        added_nodes = self.nodes[0].getaddednodeinfo(ip_port)\n        assert_equal(len(added_nodes), 1)\n        assert_equal(added_nodes[0]['addednode'], ip_port)\n        # check that a non-existent node returns an error\n        assert_raises_rpc_error(-24, \"Node has not been added\", self.nodes[0].getaddednodeinfo, '1.1.1.1')\n\n    def _test_getpeerinfo(self):\n        peer_info = [x.getpeerinfo() for x in self.nodes]\n        # check both sides of bidirectional connection between nodes\n        # the address bound to on one side will be the source address for the other node\n        assert_equal(peer_info[0][0]['addrbind'], peer_info[1][0]['addr'])\n        assert_equal(peer_info[1][0]['addrbind'], peer_info[0][0]['addr'])\n        #fixme: get working and reenable\n        #assert_equal(peer_info[0][0]['minfeefilter'], Decimal(\"0.00000500\"))\n        #assert_equal(peer_info[1][0]['minfeefilter'], Decimal(\"0.00001000\"))\n\n    def _test_getnodeaddresses(self):\n        self.nodes[0].add_p2p_connection(P2PInterface())\n\n        # send some addresses to the node via the p2p message addr\n        msg = msg_addr()\n        imported_addrs = []\n        for i in range(256):\n            a = \"123.123.123.{}\".format(i)\n            imported_addrs.append(a)\n            addr = CAddress()\n            addr.time = 100000000\n            addr.nServices = NODE_NETWORK | NODE_WITNESS\n            addr.ip = a\n            addr.port = 8333\n            msg.addrs.append(addr)\n        self.nodes[0].p2p.send_and_ping(msg)\n\n        # obtain addresses via rpc call and check they were ones sent in before\n        REQUEST_COUNT = 10\n        node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT)\n        assert_equal(len(node_addresses), REQUEST_COUNT)\n        for a in node_addresses:\n            assert_greater_than(a[\"time\"], 1527811200) # 1st June 2018\n            assert_equal(a[\"services\"], NODE_NETWORK | NODE_WITNESS)\n            assert a[\"address\"] in imported_addrs\n            assert_equal(a[\"port\"], 8333)\n\n        assert_raises_rpc_error(-8, \"Address count out of range\", self.nodes[0].getnodeaddresses, -1)\n\n        # addrman's size cannot be known reliably after insertion, as hash collisions may occur\n        # so only test that requesting a large number of addresses returns less than that\n        LARGE_REQUEST_COUNT = 10000\n        node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT)\n        assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses))\n\nif __name__ == '__main__':\n    NetTest().main()\n"
  },
  {
    "path": "test/functional/rpc_preciousblock.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the preciousblock RPC.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes_bi,\n    sync_blocks,\n)\n\ndef unidirectional_node_sync_via_rpc(node_src, node_dest):\n    blocks_to_copy = []\n    blockhash = node_src.getbestblockhash()\n    while True:\n        try:\n            assert len(node_dest.getblock(blockhash, False)) > 0\n            break\n        except:\n            blocks_to_copy.append(blockhash)\n            blockhash = node_src.getblockheader(blockhash, True)['previousblockhash']\n    blocks_to_copy.reverse()\n    for blockhash in blocks_to_copy:\n        blockdata = node_src.getblock(blockhash, False)\n        assert node_dest.submitblock(blockdata) in (None, 'inconclusive')\n\ndef node_sync_via_rpc(nodes):\n    for node_src in nodes:\n        for node_dest in nodes:\n            if node_src is node_dest:\n                continue\n            unidirectional_node_sync_via_rpc(node_src, node_dest)\n\nclass PreciousTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n\n    def setup_network(self):\n        self.setup_nodes()\n\n    def run_test(self):\n        self.log.info(\"Ensure submitblock can in principle reorg to a competing chain\")\n        gen_address = lambda i: self.nodes[i].get_deterministic_priv_key().address  # A non-wallet address to mine to\n        self.nodes[0].generatetoaddress(1, gen_address(0))\n        assert_equal(self.nodes[0].getblockcount(), 1)\n        hashZ = self.nodes[1].generatetoaddress(2, gen_address(1))[-1]\n        assert_equal(self.nodes[1].getblockcount(), 2)\n        node_sync_via_rpc(self.nodes[0:3])\n        assert_equal(self.nodes[0].getbestblockhash(), hashZ)\n\n        self.log.info(\"Mine blocks A-B-C on Node 0\")\n        hashC = self.nodes[0].generatetoaddress(3, gen_address(0))[-1]\n        assert_equal(self.nodes[0].getblockcount(), 5)\n        self.log.info(\"Mine competing blocks E-F-G on Node 1\")\n        hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1]\n        assert_equal(self.nodes[1].getblockcount(), 5)\n        assert hashC != hashG\n        self.log.info(\"Connect nodes and check no reorg occurs\")\n        # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)\n        node_sync_via_rpc(self.nodes[0:2])\n        connect_nodes_bi(self.nodes,0,1)\n        assert_equal(self.nodes[0].getbestblockhash(), hashC)\n        assert_equal(self.nodes[1].getbestblockhash(), hashG)\n        self.log.info(\"Make Node0 prefer block G\")\n        self.nodes[0].preciousblock(hashG)\n        assert_equal(self.nodes[0].getbestblockhash(), hashG)\n        self.log.info(\"Make Node0 prefer block C again\")\n        self.nodes[0].preciousblock(hashC)\n        assert_equal(self.nodes[0].getbestblockhash(), hashC)\n        self.log.info(\"Make Node1 prefer block C\")\n        self.nodes[1].preciousblock(hashC)\n        sync_blocks(self.nodes[0:2])  # wait because node 1 may not have downloaded hashC\n        assert_equal(self.nodes[1].getbestblockhash(), hashC)\n        self.log.info(\"Make Node1 prefer block G again\")\n        self.nodes[1].preciousblock(hashG)\n        assert_equal(self.nodes[1].getbestblockhash(), hashG)\n        self.log.info(\"Make Node0 prefer block G again\")\n        self.nodes[0].preciousblock(hashG)\n        assert_equal(self.nodes[0].getbestblockhash(), hashG)\n        self.log.info(\"Make Node1 prefer block C again\")\n        self.nodes[1].preciousblock(hashC)\n        assert_equal(self.nodes[1].getbestblockhash(), hashC)\n        self.log.info(\"Mine another block (E-F-G-)H on Node 0 and reorg Node 1\")\n        self.nodes[0].generatetoaddress(1, gen_address(0))\n        assert_equal(self.nodes[0].getblockcount(), 6)\n        sync_blocks(self.nodes[0:2])\n        hashH = self.nodes[0].getbestblockhash()\n        assert_equal(self.nodes[1].getbestblockhash(), hashH)\n        self.log.info(\"Node1 should not be able to prefer block C anymore\")\n        self.nodes[1].preciousblock(hashC)\n        assert_equal(self.nodes[1].getbestblockhash(), hashH)\n        self.log.info(\"Mine competing blocks I-J-K-L on Node 2\")\n        self.nodes[2].generatetoaddress(4, gen_address(2))\n        assert_equal(self.nodes[2].getblockcount(), 6)\n        hashL = self.nodes[2].getbestblockhash()\n        self.log.info(\"Connect nodes and check no reorg occurs\")\n        node_sync_via_rpc(self.nodes[1:3])\n        connect_nodes_bi(self.nodes,1,2)\n        connect_nodes_bi(self.nodes,0,2)\n        assert_equal(self.nodes[0].getbestblockhash(), hashH)\n        assert_equal(self.nodes[1].getbestblockhash(), hashH)\n        assert_equal(self.nodes[2].getbestblockhash(), hashL)\n        self.log.info(\"Make Node1 prefer block L\")\n        self.nodes[1].preciousblock(hashL)\n        assert_equal(self.nodes[1].getbestblockhash(), hashL)\n        self.log.info(\"Make Node2 prefer block H\")\n        self.nodes[2].preciousblock(hashH)\n        assert_equal(self.nodes[2].getbestblockhash(), hashH)\n\nif __name__ == '__main__':\n    PreciousTest().main()\n"
  },
  {
    "path": "test/functional/rpc_psbt.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the Partially Signed Transaction RPCs.\n\"\"\"\n\nfrom decimal import Decimal\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, disconnect_nodes, find_output, sync_blocks\n\nimport json\nimport os\n\nMAX_BIP125_RBF_SEQUENCE = 0xfffffffd\n\n# Create one-input, one-output, no-fee transaction:\nclass PSBTTest(MuntTestFramework):\n\n    def set_test_params(self):\n        self.setup_clean_chain = False\n        self.num_nodes = 3\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def test_utxo_conversion(self):\n        mining_node = self.nodes[2]\n        offline_node = self.nodes[0]\n        online_node = self.nodes[1]\n\n        # Disconnect offline node from others\n        disconnect_nodes(offline_node, 1)\n        disconnect_nodes(online_node, 0)\n        disconnect_nodes(offline_node, 2)\n        disconnect_nodes(mining_node, 0)\n\n        # Mine a transaction that credits the offline address\n        offline_addr = offline_node.getnewaddress()\n        online_addr = online_node.getnewaddress()\n        online_node.importaddress(offline_addr, \"\", False)\n        mining_node.sendtoaddress(address=offline_addr, amount=1.0)\n        mining_node.generate(num_blocks=1)\n        sync_blocks([mining_node, online_node])\n\n        # Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)\n        utxos = online_node.listunspent(addresses=[offline_addr])\n        raw = online_node.createrawtransaction([{\"txid\":utxos[0][\"txid\"], \"vout\":utxos[0][\"vout\"]}],[{online_addr:0.9999}])\n        psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))[\"psbt\"]\n        assert \"non_witness_utxo\" in mining_node.decodepsbt(psbt)[\"inputs\"][0]\n\n        # Have the offline node sign the PSBT (which will update the UTXO to segwit)\n        signed_psbt = offline_node.walletprocesspsbt(psbt)[\"psbt\"]\n        assert \"witness_utxo\" in mining_node.decodepsbt(signed_psbt)[\"inputs\"][0]\n\n        # Make sure we can mine the resulting transaction\n        txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)[\"hex\"])\n        mining_node.generate(1)\n        sync_blocks([mining_node, online_node])\n        assert_equal(online_node.gettxout(txid,0)[\"confirmations\"], 1)\n\n        # Reconnect\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 0, 2)\n\n    def run_test(self):\n        # Create and fund a raw tx for sending 10 BTC\n        psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt']\n\n        # Node 1 should not be able to add anything to it but still return the psbtx same as before\n        psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']\n        assert_equal(psbtx1, psbtx)\n\n        # Sign the transaction and send\n        signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']\n        final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']\n        self.nodes[0].sendrawtransaction(final_tx)\n\n        # Create p2sh, p2wpkh, and p2wsh addresses\n        pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']\n        pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']\n        pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']\n        p2sh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], \"\", \"legacy\")['address']\n        p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], \"\", \"bech32\")['address']\n        p2sh_p2wsh = self.nodes[1].addmultisigaddress(2, [pubkey0, pubkey1, pubkey2], \"\", \"p2sh-segwit\")['address']\n        p2wpkh = self.nodes[1].getnewaddress(\"\", \"bech32\")\n        p2pkh = self.nodes[1].getnewaddress(\"\", \"legacy\")\n        p2sh_p2wpkh = self.nodes[1].getnewaddress(\"\", \"p2sh-segwit\")\n\n        # fund those addresses\n        rawtx = self.nodes[0].createrawtransaction([], {p2sh:10, p2wsh:10, p2wpkh:10, p2sh_p2wsh:10, p2sh_p2wpkh:10, p2pkh:10})\n        rawtx = self.nodes[0].fundrawtransaction(rawtx, {\"changePosition\":3})\n        signed_tx = self.nodes[0].signrawtransaction(rawtx['hex'])['hex']\n        txid = self.nodes[0].sendrawtransaction(signed_tx)\n        self.nodes[0].generate(6)\n        self.sync_all()\n\n        # Find the output pos\n        p2sh_pos = -1\n        p2wsh_pos = -1\n        p2wpkh_pos = -1\n        p2pkh_pos = -1\n        p2sh_p2wsh_pos = -1\n        p2sh_p2wpkh_pos = -1\n        decoded = self.nodes[0].decoderawtransaction(signed_tx)\n        for out in decoded['vout']:\n            if out['scriptPubKey']['addresses'][0] == p2sh:\n                p2sh_pos = out['n']\n            elif out['scriptPubKey']['addresses'][0] == p2wsh:\n                p2wsh_pos = out['n']\n            elif out['scriptPubKey']['addresses'][0] == p2wpkh:\n                p2wpkh_pos = out['n']\n            elif out['scriptPubKey']['addresses'][0] == p2sh_p2wsh:\n                p2sh_p2wsh_pos = out['n']\n            elif out['scriptPubKey']['addresses'][0] == p2sh_p2wpkh:\n                p2sh_p2wpkh_pos = out['n']\n            elif out['scriptPubKey']['addresses'][0] == p2pkh:\n                p2pkh_pos = out['n']\n\n        # spend single key from node 1\n        rawtx = self.nodes[1].walletcreatefundedpsbt([{\"txid\":txid,\"vout\":p2wpkh_pos},{\"txid\":txid,\"vout\":p2sh_p2wpkh_pos},{\"txid\":txid,\"vout\":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']\n        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(rawtx)\n        assert_equal(walletprocesspsbt_out['complete'], True)\n        self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])\n\n        # partially sign multisig things with node 1\n        psbtx = self.nodes[1].walletcreatefundedpsbt([{\"txid\":txid,\"vout\":p2wsh_pos},{\"txid\":txid,\"vout\":p2sh_pos},{\"txid\":txid,\"vout\":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']\n        walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)\n        psbtx = walletprocesspsbt_out['psbt']\n        assert_equal(walletprocesspsbt_out['complete'], False)\n\n        # partially sign with node 2. This should be complete and sendable\n        walletprocesspsbt_out = self.nodes[2].walletprocesspsbt(psbtx)\n        assert_equal(walletprocesspsbt_out['complete'], True)\n        self.nodes[2].sendrawtransaction(self.nodes[2].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])\n\n        # check that walletprocesspsbt fails to decode a non-psbt\n        rawtx = self.nodes[1].createrawtransaction([{\"txid\":txid,\"vout\":p2wpkh_pos}], {self.nodes[1].getnewaddress():9.99})\n        assert_raises_rpc_error(-22, \"TX decode failed\", self.nodes[1].walletprocesspsbt, rawtx)\n\n        # Convert a non-psbt to psbt and make sure we can decode it\n        rawtx = self.nodes[0].createrawtransaction([], {self.nodes[1].getnewaddress():10})\n        rawtx = self.nodes[0].fundrawtransaction(rawtx)\n        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])\n        self.nodes[0].decodepsbt(new_psbt)\n\n        # Make sure that a psbt with signatures cannot be converted\n        signedtx = self.nodes[0].signrawtransaction(rawtx['hex'])\n        assert_raises_rpc_error(-22, \"TX decode failed\", self.nodes[0].converttopsbt, signedtx['hex'])\n        assert_raises_rpc_error(-22, \"TX decode failed\", self.nodes[0].converttopsbt, signedtx['hex'], False)\n        # Unless we allow it to convert and strip signatures\n        self.nodes[0].converttopsbt(signedtx['hex'], True)\n\n        # Explicitly allow converting non-empty txs\n        new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])\n        self.nodes[0].decodepsbt(new_psbt)\n\n        # Create outputs to nodes 1 and 2\n        node1_addr = self.nodes[1].getnewaddress()\n        node2_addr = self.nodes[2].getnewaddress()\n        txid1 = self.nodes[0].sendtoaddress(node1_addr, 13)\n        txid2 = self.nodes[0].sendtoaddress(node2_addr, 13)\n        blockhash = self.nodes[0].generate(6)[0]\n        self.sync_all()\n        vout1 = find_output(self.nodes[1], txid1, 13, blockhash=blockhash)\n        vout2 = find_output(self.nodes[2], txid2, 13, blockhash=blockhash)\n\n        # Create a psbt spending outputs from nodes 1 and 2\n        psbt_orig = self.nodes[0].createpsbt([{\"txid\":txid1,  \"vout\":vout1}, {\"txid\":txid2, \"vout\":vout2}], {self.nodes[0].getnewaddress():25.999})\n\n        # Update psbts, should only have data for one input and not the other\n        psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']\n        psbt1_decoded = self.nodes[0].decodepsbt(psbt1)\n        assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]\n        psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']\n        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)\n        assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]\n\n        # Combine, finalize, and send the psbts\n        combined = self.nodes[0].combinepsbt([psbt1, psbt2])\n        finalized = self.nodes[0].finalizepsbt(combined)['hex']\n        self.nodes[0].sendrawtransaction(finalized)\n        self.nodes[0].generate(6)\n        self.sync_all()\n\n        # Test additional args in walletcreatepsbt\n        # Make sure both pre-included and funded inputs\n        # have the correct sequence numbers based on\n        # replaceable arg\n        block_height = self.nodes[0].getblockcount()\n        unspent = self.nodes[0].listunspent()[0]\n        psbtx_info = self.nodes[0].walletcreatefundedpsbt([{\"txid\":unspent[\"txid\"], \"vout\":unspent[\"vout\"]}], [{self.nodes[2].getnewaddress():unspent[\"amount\"]+1}], block_height+2, {\"replaceable\":True}, False)\n        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info[\"psbt\"])\n        for tx_in, psbt_in in zip(decoded_psbt[\"tx\"][\"vin\"], decoded_psbt[\"inputs\"]):\n           assert_equal(tx_in[\"sequence\"], MAX_BIP125_RBF_SEQUENCE)\n           assert \"bip32_derivs\" not in psbt_in\n        assert_equal(decoded_psbt[\"tx\"][\"locktime\"], block_height+2)\n\n        # Same construction with only locktime set\n        psbtx_info = self.nodes[0].walletcreatefundedpsbt([{\"txid\":unspent[\"txid\"], \"vout\":unspent[\"vout\"]}], [{self.nodes[2].getnewaddress():unspent[\"amount\"]+1}], block_height, {}, True)\n        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info[\"psbt\"])\n        for tx_in, psbt_in in zip(decoded_psbt[\"tx\"][\"vin\"], decoded_psbt[\"inputs\"]):\n            assert tx_in[\"sequence\"] > MAX_BIP125_RBF_SEQUENCE\n            assert \"bip32_derivs\" in psbt_in\n        assert_equal(decoded_psbt[\"tx\"][\"locktime\"], block_height)\n\n        # Same construction without optional arguments\n        psbtx_info = self.nodes[0].walletcreatefundedpsbt([{\"txid\":unspent[\"txid\"], \"vout\":unspent[\"vout\"]}], [{self.nodes[2].getnewaddress():unspent[\"amount\"]+1}])\n        decoded_psbt = self.nodes[0].decodepsbt(psbtx_info[\"psbt\"])\n        for tx_in in decoded_psbt[\"tx\"][\"vin\"]:\n            assert tx_in[\"sequence\"] > MAX_BIP125_RBF_SEQUENCE\n        assert_equal(decoded_psbt[\"tx\"][\"locktime\"], 0)\n\n        # Make sure change address wallet does not have P2SH innerscript access to results in success\n        # when attempting BnB coin selection\n        self.nodes[0].walletcreatefundedpsbt([], [{self.nodes[2].getnewaddress():unspent[\"amount\"]+1}], block_height+2, {\"changeAddress\":self.nodes[1].getnewaddress()}, False)\n\n        # Regression test for 14473 (mishandling of already-signed witness transaction):\n        psbtx_info = self.nodes[0].walletcreatefundedpsbt([{\"txid\":unspent[\"txid\"], \"vout\":unspent[\"vout\"]}], [{self.nodes[2].getnewaddress():unspent[\"amount\"]+1}])\n        complete_psbt = self.nodes[0].walletprocesspsbt(psbtx_info[\"psbt\"])\n        double_processed_psbt = self.nodes[0].walletprocesspsbt(complete_psbt[\"psbt\"])\n        assert_equal(complete_psbt, double_processed_psbt)\n        # We don't care about the decode result, but decoding must succeed.\n        self.nodes[0].decodepsbt(double_processed_psbt[\"psbt\"])\n\n        # BIP 174 Test Vectors\n\n        # Check that unknown values are just passed through\n        unknown_psbt = \"cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA=\"\n        unknown_out = self.nodes[0].walletprocesspsbt(unknown_psbt)['psbt']\n        assert_equal(unknown_psbt, unknown_out)\n\n        # Open the data file\n        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_psbt.json'), encoding='utf-8') as f:\n            d = json.load(f)\n            invalids = d['invalid']\n            valids = d['valid']\n            creators = d['creator']\n            signers = d['signer']\n            combiners = d['combiner']\n            finalizers = d['finalizer']\n            extractors = d['extractor']\n\n        # Invalid PSBTs\n        for invalid in invalids:\n            assert_raises_rpc_error(-22, \"TX decode failed\", self.nodes[0].decodepsbt, invalid)\n\n        # Valid PSBTs\n        for valid in valids:\n            self.nodes[0].decodepsbt(valid)\n\n        # Creator Tests\n        for creator in creators:\n            created_tx = self.nodes[0].createpsbt(creator['inputs'], creator['outputs'])\n            assert_equal(created_tx, creator['result'])\n\n        # Signer tests\n        for i, signer in enumerate(signers):\n            self.nodes[2].createwallet(\"wallet{}\".format(i))\n            wrpc = self.nodes[2].get_wallet_rpc(\"wallet{}\".format(i))\n            for key in signer['privkeys']:\n                wrpc.importprivkey(key)\n            signed_tx = wrpc.walletprocesspsbt(signer['psbt'])['psbt']\n            assert_equal(signed_tx, signer['result'])\n\n        # Combiner test\n        for combiner in combiners:\n            combined = self.nodes[2].combinepsbt(combiner['combine'])\n            assert_equal(combined, combiner['result'])\n\n        # Empty combiner test\n        assert_raises_rpc_error(-8, \"Parameter 'txs' cannot be empty\", self.nodes[0].combinepsbt, [])\n\n        # Finalizer test\n        for finalizer in finalizers:\n            finalized = self.nodes[2].finalizepsbt(finalizer['finalize'], False)['psbt']\n            assert_equal(finalized, finalizer['result'])\n\n        # Extractor test\n        for extractor in extractors:\n            extracted = self.nodes[2].finalizepsbt(extractor['extract'], True)['hex']\n            assert_equal(extracted, extractor['result'])\n\n        # Unload extra wallets\n        for i, signer in enumerate(signers):\n            self.nodes[2].unloadwallet(\"wallet{}\".format(i))\n\n        self.test_utxo_conversion()\n\n        # Test that psbts with p2pkh outputs are created properly\n        p2pkh = self.nodes[0].getnewaddress()\n        psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {\"includeWatching\" : True}, True)\n        self.nodes[0].decodepsbt(psbt['psbt'])\n\n        # Test decoding error: invalid base64\n        assert_raises_rpc_error(-22, \"TX decode failed invalid base64\", self.nodes[0].decodepsbt, \";definitely not base64;\")\n\n        # Send to all types of addresses\n        addr1 = self.nodes[1].getnewaddress(\"\", \"bech32\")\n        txid1 = self.nodes[0].sendtoaddress(addr1, 11)\n        vout1 = find_output(self.nodes[0], txid1, 11)\n        addr2 = self.nodes[1].getnewaddress(\"\", \"legacy\")\n        txid2 = self.nodes[0].sendtoaddress(addr2, 11)\n        vout2 = find_output(self.nodes[0], txid2, 11)\n        addr3 = self.nodes[1].getnewaddress(\"\", \"p2sh-segwit\")\n        txid3 = self.nodes[0].sendtoaddress(addr3, 11)\n        vout3 = find_output(self.nodes[0], txid3, 11)\n        self.sync_all()\n\n        # Update a PSBT with UTXOs from the node\n        # Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness\n        psbt = self.nodes[1].createpsbt([{\"txid\":txid1, \"vout\":vout1},{\"txid\":txid2, \"vout\":vout2},{\"txid\":txid3, \"vout\":vout3}], {self.nodes[0].getnewaddress():32.999})\n        decoded = self.nodes[1].decodepsbt(psbt)\n        assert \"witness_utxo\" not in decoded['inputs'][0] and \"non_witness_utxo\" not in decoded['inputs'][0]\n        assert \"witness_utxo\" not in decoded['inputs'][1] and \"non_witness_utxo\" not in decoded['inputs'][1]\n        assert \"witness_utxo\" not in decoded['inputs'][2] and \"non_witness_utxo\" not in decoded['inputs'][2]\n        updated = self.nodes[1].utxoupdatepsbt(psbt)\n        decoded = self.nodes[1].decodepsbt(updated)\n        assert \"witness_utxo\" in decoded['inputs'][0] and \"non_witness_utxo\" not in decoded['inputs'][0]\n        assert \"witness_utxo\" not in decoded['inputs'][1] and \"non_witness_utxo\" not in decoded['inputs'][1]\n        assert \"witness_utxo\" not in decoded['inputs'][2] and \"non_witness_utxo\" not in decoded['inputs'][2]\n\n        # Two PSBTs with a common input should not be joinable\n        psbt1 = self.nodes[1].createpsbt([{\"txid\":txid1, \"vout\":vout1}], {self.nodes[0].getnewaddress():Decimal('10.999')})\n        assert_raises_rpc_error(-8, \"exists in multiple PSBTs\", self.nodes[1].joinpsbts, [psbt1, updated])\n\n        # Join two distinct PSBTs\n        addr4 = self.nodes[1].getnewaddress(\"\", \"p2sh-segwit\")\n        txid4 = self.nodes[0].sendtoaddress(addr4, 5)\n        vout4 = find_output(self.nodes[0], txid4, 5)\n        self.nodes[0].generate(6)\n        self.sync_all()\n        psbt2 = self.nodes[1].createpsbt([{\"txid\":txid4, \"vout\":vout4}], {self.nodes[0].getnewaddress():Decimal('4.999')})\n        psbt2 = self.nodes[1].walletprocesspsbt(psbt2)['psbt']\n        psbt2_decoded = self.nodes[0].decodepsbt(psbt2)\n        assert \"final_scriptwitness\" in psbt2_decoded['inputs'][0] and \"final_scriptSig\" in psbt2_decoded['inputs'][0]\n        joined = self.nodes[0].joinpsbts([psbt, psbt2])\n        joined_decoded = self.nodes[0].decodepsbt(joined)\n        assert len(joined_decoded['inputs']) == 4 and len(joined_decoded['outputs']) == 2 and \"final_scriptwitness\" not in joined_decoded['inputs'][3] and \"final_scriptSig\" not in joined_decoded['inputs'][3]\n\n        # Newly created PSBT needs UTXOs and updating\n        addr = self.nodes[1].getnewaddress(\"\", \"p2sh-segwit\")\n        txid = self.nodes[0].sendtoaddress(addr, 7)\n        addrinfo = self.nodes[1].getaddressinfo(addr)\n        blockhash = self.nodes[0].generate(6)[0]\n        self.sync_all()\n        vout = find_output(self.nodes[0], txid, 7, blockhash=blockhash)\n        psbt = self.nodes[1].createpsbt([{\"txid\":txid, \"vout\":vout}], {self.nodes[0].getnewaddress(\"\", \"p2sh-segwit\"):Decimal('6.999')})\n        analyzed = self.nodes[0].analyzepsbt(psbt)\n        assert not analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed['inputs'][0]['next'] == 'updater' and analyzed['next'] == 'updater'\n\n        # After update with wallet, only needs signing\n        updated = self.nodes[1].walletprocesspsbt(psbt, False, 'ALL', True)['psbt']\n        analyzed = self.nodes[0].analyzepsbt(updated)\n        assert analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed['inputs'][0]['next'] == 'signer' and analyzed['next'] == 'signer' and analyzed['inputs'][0]['missing']['signatures'][0] == addrinfo['embedded']['witness_program']\n\n        # Check fee and size things\n        assert analyzed['fee'] == Decimal('0.001') and analyzed['estimated_vsize'] == 134 and analyzed['estimated_feerate'] == Decimal('0.00746268')\n\n        # After signing and finalizing, needs extracting\n        signed = self.nodes[1].walletprocesspsbt(updated)['psbt']\n        analyzed = self.nodes[0].analyzepsbt(signed)\n        assert analyzed['inputs'][0]['has_utxo'] and analyzed['inputs'][0]['is_final'] and analyzed['next'] == 'extractor'\n\nif __name__ == '__main__':\n    PSBTTest().main()\n"
  },
  {
    "path": "test/functional/rpc_rawtransaction.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the rawtransaction RPCs.\n\nTest the following RPCs:\n   - createrawtransaction\n   - signrawtransaction\n   - sendrawtransaction\n   - decoderawtransaction\n   - getrawtransaction\n\"\"\"\n\nfrom collections import OrderedDict\nfrom decimal import Decimal\nfrom io import BytesIO\nfrom test_framework.messages import CTransaction, ToHex\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, hex_str_to_bytes\n\nclass multidict(dict):\n    \"\"\"Dictionary that allows duplicate keys.\n\n    Constructed with a list of (key, value) tuples. When dumped by the json module,\n    will output invalid json with repeated keys, eg:\n    >>> json.dumps(multidict([(1,2),(1,2)])\n    '{\"1\": 2, \"1\": 2}'\n\n    Used to test calls to rpc methods with repeated keys in the json object.\"\"\"\n\n    def __init__(self, x):\n        dict.__init__(self, x)\n        self.x = x\n\n    def items(self):\n        return self.x\n\n\n# Create one-input, one-output, no-fee transaction:\nclass RawTransactionsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        self.extra_args = [[\"-addresstype=legacy\", \"-txindex\"], [\"-addresstype=legacy\", \"-txindex\"], [\"-addresstype=legacy\", \"-txindex\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        super().setup_network()\n        connect_nodes_bi(self.nodes, 0, 2)\n\n    def run_test(self):\n        self.log.info('prepare some coins for multiple *rawtransaction commands')\n        self.nodes[2].generate(1)\n        self.sync_all()\n        self.nodes[0].generate(101)\n        self.sync_all()\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5)\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0)\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0)\n        self.sync_all()\n        self.nodes[0].generate(5)\n        self.sync_all()\n\n        self.log.info('Test getrawtransaction on genesis block coinbase returns an error')\n        block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))\n        assert_raises_rpc_error(-5, \"The genesis block coinbase is not considered an ordinary transaction\", self.nodes[0].getrawtransaction, block['merkleroot'])\n\n        self.log.info('Check parameter types and required parameters of createrawtransaction')\n        # Test `createrawtransaction` required parameters\n        assert_raises_rpc_error(-1, \"createrawtransaction\", self.nodes[0].createrawtransaction)\n        assert_raises_rpc_error(-1, \"createrawtransaction\", self.nodes[0].createrawtransaction, [])\n\n        # Test `createrawtransaction` invalid extra parameters\n        assert_raises_rpc_error(-1, \"createrawtransaction\", self.nodes[0].createrawtransaction, [], {}, 0, False, 'foo')\n\n        # Test `createrawtransaction` invalid `inputs`\n        txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'\n        assert_raises_rpc_error(-3, \"Expected type array\", self.nodes[0].createrawtransaction, 'foo', {})\n        assert_raises_rpc_error(-1, \"JSON value is not an object as expected\", self.nodes[0].createrawtransaction, ['foo'], {})\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[0].createrawtransaction, [{}], {})\n        assert_raises_rpc_error(-8, \"txid must be of length 64 (not 3, for 'foo')\", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})\n        assert_raises_rpc_error(-8, \"txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')\", self.nodes[0].createrawtransaction, [{'txid': 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'}], {})\n        assert_raises_rpc_error(-8, \"Invalid parameter, missing vout key\", self.nodes[0].createrawtransaction, [{'txid': txid}], {})\n        assert_raises_rpc_error(-8, \"Invalid parameter, missing vout key\", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {})\n        assert_raises_rpc_error(-8, \"Invalid parameter, vout must be positive\", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {})\n        assert_raises_rpc_error(-8, \"Invalid parameter, sequence number is out of range\", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 0, 'sequence': -1}], {})\n\n        # Test `createrawtransaction` invalid `outputs`\n        address = self.nodes[0].getnewaddress()\n        address2 = self.nodes[0].getnewaddress()\n        assert_raises_rpc_error(-1, \"JSON value is not an array as expected\", self.nodes[0].createrawtransaction, [], 'foo')\n        self.nodes[0].createrawtransaction(inputs=[], outputs={})  # Should not throw for backwards compatibility\n        self.nodes[0].createrawtransaction(inputs=[], outputs=[])\n        assert_raises_rpc_error(-8, \"Data must be hexadecimal string\", self.nodes[0].createrawtransaction, [], {'data': 'foo'})\n        assert_raises_rpc_error(-5, \"Invalid Munt address\", self.nodes[0].createrawtransaction, [], {'foo': 0})\n        assert_raises_rpc_error(-3, \"Invalid amount\", self.nodes[0].createrawtransaction, [], {address: 'foo'})\n        assert_raises_rpc_error(-3, \"Amount out of range\", self.nodes[0].createrawtransaction, [], {address: -1})\n        assert_raises_rpc_error(-8, \"Invalid parameter, duplicated address: %s\" % address, self.nodes[0].createrawtransaction, [], multidict([(address, 1), (address, 1)]))\n        assert_raises_rpc_error(-8, \"Invalid parameter, duplicated address: %s\" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])\n        assert_raises_rpc_error(-8, \"Invalid parameter, duplicate key: data\", self.nodes[0].createrawtransaction, [], [{\"data\": 'aa'}, {\"data\": \"bb\"}])\n        assert_raises_rpc_error(-8, \"Invalid parameter, duplicate key: data\", self.nodes[0].createrawtransaction, [], multidict([(\"data\", 'aa'), (\"data\", \"bb\")]))\n        assert_raises_rpc_error(-8, \"Invalid parameter, key-value pair must contain exactly one key\", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])\n        assert_raises_rpc_error(-8, \"Invalid parameter, key-value pair not an object as expected\", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])\n\n        # Test `createrawtransaction` invalid `locktime`\n        assert_raises_rpc_error(-3, \"Expected type number\", self.nodes[0].createrawtransaction, [], {}, 'foo')\n        assert_raises_rpc_error(-8, \"Invalid parameter, locktime out of range\", self.nodes[0].createrawtransaction, [], {}, -1)\n        assert_raises_rpc_error(-8, \"Invalid parameter, locktime out of range\", self.nodes[0].createrawtransaction, [], {}, 4294967296)\n\n        # Test `createrawtransaction` invalid `replaceable`\n        assert_raises_rpc_error(-3, \"Expected type bool\", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')\n\n        self.log.info('Check that createrawtransaction accepts an array and object as outputs')\n        tx = CTransaction()\n        # One output\n        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs={address: 99}))))\n        assert_equal(len(tx.vout), 1)\n        assert_equal(\n            tx.serialize().hex(),\n            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}]),\n        )\n        # Two outputs\n        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))))\n        assert_equal(len(tx.vout), 2)\n        assert_equal(\n            tx.serialize().hex(),\n            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),\n        )\n        # Multiple mixed outputs\n        tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), (address2, 99), ('data', '99')])))))\n        assert_equal(len(tx.vout), 3)\n        assert_equal(\n            tx.serialize().hex(),\n            self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),\n        )\n\n        for type in [\"bech32\", \"p2sh-segwit\", \"legacy\"]:\n            addr = self.nodes[0].getnewaddress(\"\", type)\n            addrinfo = self.nodes[0].getaddressinfo(addr)\n            pubkey = addrinfo[\"scriptPubKey\"]\n\n            self.log.info('sendrawtransaction with missing prevtx info (%s)' %(type))\n\n            # Test `signrawtransaction` invalid `prevtxs`\n            inputs  = [ {'txid' : txid, 'vout' : 3, 'sequence' : 1000}]\n            outputs = { self.nodes[0].getnewaddress() : 1 }\n            rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)\n\n            prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)\n            succ = self.nodes[0].signrawtransaction(rawtx, [prevtx])\n            assert succ[\"complete\"]\n            if type == \"legacy\":\n                del prevtx[\"amount\"]\n                succ = self.nodes[0].signrawtransaction(rawtx, [prevtx])\n                assert succ[\"complete\"]\n\n            if type != \"legacy\":\n                assert_raises_rpc_error(-3, \"Missing amount\", self.nodes[0].signrawtransaction, rawtx, [\n                    {\n                        \"txid\": txid,\n                        \"scriptPubKey\": pubkey,\n                        \"vout\": 3,\n                    }\n                ])\n\n            assert_raises_rpc_error(-3, \"Missing vout\", self.nodes[0].signrawtransaction, rawtx, [\n                {\n                    \"txid\": txid,\n                    \"scriptPubKey\": pubkey,\n                    \"amount\": 1,\n                }\n            ])\n            assert_raises_rpc_error(-3, \"Missing txid\", self.nodes[0].signrawtransaction, rawtx, [\n                {\n                    \"scriptPubKey\": pubkey,\n                    \"vout\": 3,\n                    \"amount\": 1,\n                }\n            ])\n            assert_raises_rpc_error(-3, \"Missing scriptPubKey\", self.nodes[0].signrawtransaction, rawtx, [\n                {\n                    \"txid\": txid,\n                    \"vout\": 3,\n                    \"amount\": 1\n                }\n            ])\n\n        #########################################\n        # sendrawtransaction with missing input #\n        #########################################\n\n        self.log.info('sendrawtransaction with missing input')\n        inputs  = [ {'txid' : \"1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000\", 'vout' : 1}] #won't exists\n        outputs = { self.nodes[0].getnewaddress() : 4.998 }\n        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)\n        rawtx   = self.nodes[2].signrawtransaction(rawtx)\n\n        # This will raise an exception since there are missing inputs\n        assert_raises_rpc_error(-25, \"Missing inputs\", self.nodes[2].sendrawtransaction, rawtx['hex'])\n\n        #####################################\n        # getrawtransaction with block hash #\n        #####################################\n\n        # make a tx by sending then generate 2 blocks; block1 has the tx in it\n        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)\n        block1, block2 = self.nodes[2].generate(2)\n        self.sync_all()\n        # We should be able to get the raw transaction by providing the correct block\n        gottx = self.nodes[0].getrawtransaction(tx, True, block1)\n        assert_equal(gottx['txid'], tx)\n        assert_equal(gottx['in_active_chain'], True)\n        # We should not have the 'in_active_chain' flag when we don't provide a block\n        gottx = self.nodes[0].getrawtransaction(tx, True)\n        assert_equal(gottx['txid'], tx)\n        assert 'in_active_chain' not in gottx\n        # We should not get the tx if we provide an unrelated block\n        assert_raises_rpc_error(-5, \"No such transaction found\", self.nodes[0].getrawtransaction, tx, True, block2)\n        # An invalid block hash should raise the correct errors\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[0].getrawtransaction, tx, True, True)\n        assert_raises_rpc_error(-8, \"parameter 3 must be of length 64 (not 6, for 'foobar')\", self.nodes[0].getrawtransaction, tx, True, \"foobar\")\n        assert_raises_rpc_error(-8, \"parameter 3 must be of length 64 (not 8, for 'abcd1234')\", self.nodes[0].getrawtransaction, tx, True, \"abcd1234\")\n        assert_raises_rpc_error(-8, \"parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')\", self.nodes[0].getrawtransaction, tx, True, \"ZZZ0000000000000000000000000000000000000000000000000000000000000\")\n        assert_raises_rpc_error(-5, \"Block hash not found\", self.nodes[0].getrawtransaction, tx, True, \"0000000000000000000000000000000000000000000000000000000000000000\")\n        # Undo the blocks and check in_active_chain\n        self.nodes[0].invalidateblock(block1)\n        gottx = self.nodes[0].getrawtransaction(txid=tx, verbose=True, blockhash=block1)\n        assert_equal(gottx['in_active_chain'], False)\n        self.nodes[0].reconsiderblock(block1)\n        assert_equal(self.nodes[0].getbestblockhash(), block2)\n\n        #########################\n        # RAW TX MULTISIG TESTS #\n        #########################\n        # 2of2 test\n        addr1 = self.nodes[2].getnewaddress()\n        addr2 = self.nodes[2].getnewaddress()\n\n        addr1Obj = self.nodes[2].getaddressinfo(addr1)\n        addr2Obj = self.nodes[2].getaddressinfo(addr2)\n\n        # Tests for createmultisig and addmultisigaddress\n        assert_raises_rpc_error(-5, \"Invalid public key\", self.nodes[0].createmultisig, 1, [\"01020304\"])\n        self.nodes[0].createmultisig(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) # createmultisig can only take public keys\n        assert_raises_rpc_error(-5, \"Invalid public key\", self.nodes[0].createmultisig, 2, [addr1Obj['pubkey'], addr1]) # addmultisigaddress can take both pubkeys and addresses so long as they are in the wallet, which is tested here.\n\n        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr1])['address']\n\n        #use balance deltas instead of absolute values\n        bal = self.nodes[2].getbalance()\n\n        # send 1.2 BTC to msig adr\n        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n        assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #node2 has both keys of the 2of2 ms addr., tx should affect the balance\n\n\n        # 2of3 test from different nodes\n        bal = self.nodes[2].getbalance()\n        addr1 = self.nodes[1].getnewaddress()\n        addr2 = self.nodes[2].getnewaddress()\n        addr3 = self.nodes[2].getnewaddress()\n\n        addr1Obj = self.nodes[1].getaddressinfo(addr1)\n        addr2Obj = self.nodes[2].getaddressinfo(addr2)\n        addr3Obj = self.nodes[2].getaddressinfo(addr3)\n\n        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])['address']\n\n        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)\n        decTx = self.nodes[0].gettransaction(txId)\n        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        #THIS IS AN INCOMPLETE FEATURE\n        #NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION\n        assert_equal(self.nodes[2].getbalance(), bal) #for now, assume the funds of a 2of3 multisig tx are not marked as spendable\n\n        txDetails = self.nodes[0].gettransaction(txId, True)\n        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])\n        vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('2.20000000'))\n\n        bal = self.nodes[0].getbalance()\n        inputs = [{ \"txid\" : txId, \"vout\" : vout['n'], \"scriptPubKey\" : vout['scriptPubKey']['hex'], \"amount\" : vout['value']}]\n        outputs = { self.nodes[0].getnewaddress() : 2.19 }\n        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)\n        rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs)\n        assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx\n\n        rawTxSigned = self.nodes[2].signrawtransaction(rawTx, inputs)\n        assert_equal(rawTxSigned['complete'], True) #node2 can sign the tx compl., own two of three keys\n        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])\n        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx\n\n        # 2of2 test for combining transactions\n        bal = self.nodes[2].getbalance()\n        addr1 = self.nodes[1].getnewaddress()\n        addr2 = self.nodes[2].getnewaddress()\n\n        addr1Obj = self.nodes[1].getaddressinfo(addr1)\n        addr2Obj = self.nodes[2].getaddressinfo(addr2)\n\n        self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']\n        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']\n        mSigObjValid = self.nodes[2].getaddressinfo(mSigObj)\n\n        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)\n        decTx = self.nodes[0].gettransaction(txId)\n        rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable\n\n        txDetails = self.nodes[0].gettransaction(txId, True)\n        rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])\n        vout = next(o for o in rawTx2['vout'] if o['value'] == Decimal('2.20000000'))\n\n        bal = self.nodes[0].getbalance()\n        inputs = [{ \"txid\" : txId, \"vout\" : vout['n'], \"scriptPubKey\" : vout['scriptPubKey']['hex'], \"redeemScript\" : mSigObjValid['hex'], \"amount\" : vout['value']}]\n        outputs = { self.nodes[0].getnewaddress() : 2.19 }\n        rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs)\n        rawTxPartialSigned1 = self.nodes[1].signrawtransaction(rawTx2, inputs)\n        self.log.debug(rawTxPartialSigned1)\n        assert_equal(rawTxPartialSigned1['complete'], False) #node1 only has one key, can't comp. sign the tx\n\n        rawTxPartialSigned2 = self.nodes[2].signrawtransaction(rawTx2, inputs)\n        self.log.debug(rawTxPartialSigned2)\n        assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx\n        rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']])\n        self.log.debug(rawTxComb)\n        self.nodes[2].sendrawtransaction(rawTxComb)\n        rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)\n        self.sync_all()\n        self.nodes[0].generate(1)\n        self.sync_all()\n        assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx\n\n        # decoderawtransaction tests\n        # witness transaction\n        encrawtx = \"010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000\"\n        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction\n        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))\n        assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction\n        # non-witness transaction\n        encrawtx = \"01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000\"\n        decrawtx = self.nodes[0].decoderawtransaction(encrawtx, False) # decode as non-witness transaction\n        assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))\n\n        # getrawtransaction tests\n        # 1. valid parameters - only supply txid\n        txHash = rawTx[\"hash\"]\n        assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex'])\n\n        # 2. valid parameters - supply txid and 0 for non-verbose\n        assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex'])\n\n        # 3. valid parameters - supply txid and False for non-verbose\n        assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex'])\n\n        # 4. valid parameters - supply txid and 1 for verbose.\n        # We only check the \"hex\" field of the output so we don't need to update this test every time the output format changes.\n        assert_equal(self.nodes[0].getrawtransaction(txHash, 1)[\"hex\"], rawTxSigned['hex'])\n\n        # 5. valid parameters - supply txid and True for non-verbose\n        assert_equal(self.nodes[0].getrawtransaction(txHash, True)[\"hex\"], rawTxSigned['hex'])\n\n        # 6. invalid parameters - supply txid and string \"Flase\"\n        assert_raises_rpc_error(-1, \"not a boolean\", self.nodes[0].getrawtransaction, txHash, \"Flase\")\n\n        # 7. invalid parameters - supply txid and empty array\n        assert_raises_rpc_error(-1, \"not a boolean\", self.nodes[0].getrawtransaction, txHash, [])\n\n        # 8. invalid parameters - supply txid and empty dict\n        assert_raises_rpc_error(-1, \"not a boolean\", self.nodes[0].getrawtransaction, txHash, {})\n\n        inputs  = [ {'txid' : \"1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000\", 'vout' : 1, 'sequence' : 1000}]\n        outputs = { self.nodes[0].getnewaddress() : 1 }\n        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)\n        decrawtx= self.nodes[0].decoderawtransaction(rawtx)\n        assert_equal(decrawtx['vin'][0]['sequence'], 1000)\n\n        # 9. invalid parameters - sequence number out of range\n        inputs  = [ {'txid' : \"1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000\", 'vout' : 1, 'sequence' : -1}]\n        outputs = { self.nodes[0].getnewaddress() : 1 }\n        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)\n\n        # 10. invalid parameters - sequence number out of range\n        inputs  = [ {'txid' : \"1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000\", 'vout' : 1, 'sequence' : 4294967296}]\n        outputs = { self.nodes[0].getnewaddress() : 1 }\n        assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)\n\n        inputs  = [ {'txid' : \"1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000\", 'vout' : 1, 'sequence' : 4294967294}]\n        outputs = { self.nodes[0].getnewaddress() : 1 }\n        rawtx   = self.nodes[0].createrawtransaction(inputs, outputs)\n        decrawtx= self.nodes[0].decoderawtransaction(rawtx)\n        assert_equal(decrawtx['vin'][0]['sequence'], 4294967294)\n\n        ####################################\n        # TRANSACTION VERSION NUMBER TESTS #\n        ####################################\n\n        # Test the minimum transaction version number that fits in a signed 32-bit integer.\n        tx = CTransaction()\n        tx.nVersion = -0x80000000\n        rawtx = ToHex(tx)\n        decrawtx = self.nodes[0].decoderawtransaction(rawtx)\n        assert_equal(decrawtx['version'], -0x80000000)\n\n        # Test the maximum transaction version number that fits in a signed 32-bit integer.\n        tx = CTransaction()\n        tx.nVersion = 0x7fffffff\n        rawtx = ToHex(tx)\n        decrawtx = self.nodes[0].decoderawtransaction(rawtx)\n        assert_equal(decrawtx['version'], 0x7fffffff)\n\n        self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')\n\n        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)\n        rawTx = self.nodes[0].getrawtransaction(txId, True)\n        vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))\n\n        self.sync_all()\n        inputs = [{ \"txid\" : txId, \"vout\" : vout['n'] }]\n        outputs = { self.nodes[0].getnewaddress() : Decimal(\"0.99999000\") } # 1000 sat fee\n        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)\n        rawTxSigned = self.nodes[2].signrawtransaction(rawTx)\n        assert_equal(rawTxSigned['complete'], True)\n        # 1000 sat fee, ~200 b transaction, fee rate should land around 5 sat/b = 0.00005000 BTC/kB\n        # Thus, testmempoolaccept should reject\n        testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]\n        assert_equal(testres['allowed'], False)\n        assert_equal(testres['reject-reason'], '256: absurdly-high-fee')\n        # and sendrawtransaction should throw\n        assert_raises_rpc_error(-26, \"absurdly-high-fee\", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])\n        # And below calls should both succeed\n        testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate=0.00007000)[0]\n        assert_equal(testres['allowed'], True)\n        self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])\n\n\nif __name__ == '__main__':\n    RawTransactionsTest().main()\n"
  },
  {
    "path": "test/functional/rpc_scantxoutset.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the scantxoutset rpc call.\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nfrom decimal import Decimal\nimport shutil\nimport os\n\ndef descriptors(out):\n    return sorted(u['desc'] for u in out['unspents'])\n\nclass ScantxoutsetTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.log.info(\"Mining blocks...\")\n        self.nodes[0].generate(110)\n\n        addr_P2SH_SEGWIT = self.nodes[0].getnewaddress(\"\", \"p2sh-segwit\")\n        pubk1 = self.nodes[0].getaddressinfo(addr_P2SH_SEGWIT)['pubkey']\n        addr_LEGACY = self.nodes[0].getnewaddress(\"\", \"legacy\")\n        pubk2 = self.nodes[0].getaddressinfo(addr_LEGACY)['pubkey']\n        addr_BECH32 = self.nodes[0].getnewaddress(\"\", \"bech32\")\n        pubk3 = self.nodes[0].getaddressinfo(addr_BECH32)['pubkey']\n        self.nodes[0].sendtoaddress(addr_P2SH_SEGWIT, 0.001)\n        self.nodes[0].sendtoaddress(addr_LEGACY, 0.002)\n        self.nodes[0].sendtoaddress(addr_BECH32, 0.004)\n\n        #send to child keys of tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK\n        self.nodes[0].sendtoaddress(\"mkHV1C6JLheLoUSSZYk7x3FH5tnx9bu7yc\", 0.008) # (m/0'/0'/0')\n        self.nodes[0].sendtoaddress(\"mipUSRmJAj2KrjSvsPQtnP8ynUon7FhpCR\", 0.016) # (m/0'/0'/1')\n        self.nodes[0].sendtoaddress(\"n37dAGe6Mq1HGM9t4b6rFEEsDGq7Fcgfqg\", 0.032) # (m/0'/0'/1500')\n        self.nodes[0].sendtoaddress(\"mqS9Rpg8nNLAzxFExsgFLCnzHBsoQ3PRM6\", 0.064) # (m/0'/0'/0)\n        self.nodes[0].sendtoaddress(\"mnTg5gVWr3rbhHaKjJv7EEEc76ZqHgSj4S\", 0.128) # (m/0'/0'/1)\n        self.nodes[0].sendtoaddress(\"mketCd6B9U9Uee1iCsppDJJBHfvi6U6ukC\", 0.256) # (m/0'/0'/1500)\n        self.nodes[0].sendtoaddress(\"mj8zFzrbBcdaWXowCQ1oPZ4qioBVzLzAp7\", 0.512) # (m/1/1/0')\n        self.nodes[0].sendtoaddress(\"mfnKpKQEftniaoE1iXuMMePQU3PUpcNisA\", 1.024) # (m/1/1/1')\n        self.nodes[0].sendtoaddress(\"mou6cB1kaP1nNJM1sryW6YRwnd4shTbXYQ\", 2.048) # (m/1/1/1500')\n        self.nodes[0].sendtoaddress(\"mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ\", 4.096) # (m/1/1/0)\n        self.nodes[0].sendtoaddress(\"mxp7w7j8S1Aq6L8StS2PqVvtt4HGxXEvdy\", 8.192) # (m/1/1/1)\n        self.nodes[0].sendtoaddress(\"mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq\", 16.384) # (m/1/1/1500)\n\n\n        self.nodes[0].generate(1)\n\n        self.log.info(\"Stop node, remove wallet, mine again some blocks...\")\n        self.stop_node(0)\n        shutil.rmtree(os.path.join(self.nodes[0].datadir, \"regtest\", 'wallets'))\n        self.start_node(0)\n        self.nodes[0].generate(110)\n\n        self.restart_node(0, ['-nowallet'])\n        self.log.info(\"Test if we have found the non HD unspent outputs.\")\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"pkh(\" + pubk1 + \")\", \"pkh(\" + pubk2 + \")\", \"pkh(\" + pubk3 + \")\"])['total_amount'], Decimal(\"0.002\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"wpkh(\" + pubk1 + \")\", \"wpkh(\" + pubk2 + \")\", \"wpkh(\" + pubk3 + \")\"])['total_amount'], Decimal(\"0.004\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"sh(wpkh(\" + pubk1 + \"))\", \"sh(wpkh(\" + pubk2 + \"))\", \"sh(wpkh(\" + pubk3 + \"))\"])['total_amount'], Decimal(\"0.001\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(\" + pubk1 + \")\", \"combo(\" + pubk2 + \")\", \"combo(\" + pubk3 + \")\"])['total_amount'], Decimal(\"0.007\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"addr(\" + addr_P2SH_SEGWIT + \")\", \"addr(\" + addr_LEGACY + \")\", \"addr(\" + addr_BECH32 + \")\"])['total_amount'], Decimal(\"0.007\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"addr(\" + addr_P2SH_SEGWIT + \")\", \"addr(\" + addr_LEGACY + \")\", \"combo(\" + pubk3 + \")\"])['total_amount'], Decimal(\"0.007\"))\n\n        self.log.info(\"Test extended key derivation.\")\n        # Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.\n        # Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/0h)\"])['total_amount'], Decimal(\"0.008\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/1h)\"])['total_amount'], Decimal(\"0.016\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500')\"])['total_amount'], Decimal(\"0.032\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/0)\"])['total_amount'], Decimal(\"0.064\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/1)\"])['total_amount'], Decimal(\"0.128\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500)\"])['total_amount'], Decimal(\"0.256\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*h)\", \"range\": 1499}])['total_amount'], Decimal(\"0.024\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/*h)\", \"range\": 1500}])['total_amount'], Decimal(\"0.056\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)\", \"range\": 1499}])['total_amount'], Decimal(\"0.192\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*)\", \"range\": 1500}])['total_amount'], Decimal(\"0.448\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0')\"])['total_amount'], Decimal(\"0.512\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1')\"])['total_amount'], Decimal(\"1.024\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500h)\"])['total_amount'], Decimal(\"2.048\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)\"])['total_amount'], Decimal(\"4.096\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)\"])['total_amount'], Decimal(\"8.192\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)\"])['total_amount'], Decimal(\"16.384\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)\"])['total_amount'], Decimal(\"4.096\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo([abcdef88/1/2'/3/4h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)\"])['total_amount'], Decimal(\"8.192\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)\"])['total_amount'], Decimal(\"16.384\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')\", \"range\": 1499}])['total_amount'], Decimal(\"1.536\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')\", \"range\": 1500}])['total_amount'], Decimal(\"3.584\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\", \"range\": 1499}])['total_amount'], Decimal(\"12.288\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)\", \"range\": 1500}])['total_amount'], Decimal(\"28.672\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)\", \"range\": 1499}])['total_amount'], Decimal(\"12.288\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)\", \"range\": 1500}])['total_amount'], Decimal(\"28.672\"))\n        assert_equal(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)\", \"range\": [1500,1500]}])['total_amount'], Decimal(\"16.384\"))\n\n        # Test the reported descriptors for a few matches\n        assert_equal(descriptors(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)\", \"range\": 1499}])), [\"pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x\", \"pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed\"])\n        assert_equal(descriptors(self.nodes[0].scantxoutset(\"start\", [ \"combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)\"])), [\"pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8\"])\n        assert_equal(descriptors(self.nodes[0].scantxoutset(\"start\", [ {\"desc\": \"combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)\", \"range\": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa'])\n\nif __name__ == '__main__':\n    ScantxoutsetTest().main()\n"
  },
  {
    "path": "test/functional/rpc_signmessage.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test RPC commands for signing and verifying messages.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass SignMessagesTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        self.extra_args = [[\"-addresstype=legacy\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        message = 'This is just a test message'\n\n        self.log.info('test signing with priv_key')\n        priv_key = 'UtGZ5Y97YgZrkWVANrjX2QeuUzjW6bGYeE7SNx6tznm3362qL1bp'\n        address = 'RY5DVxjvNemCUAcdaXMgZ2cHgVBJp6tC6y'\n        expected_signature = 'ICSd+NQOQ/5EJr2kx2FNbZyFTeD5BJgHPlyVQ1imB9eJdwfTGgttLulBt0y3tNod0YGAPnOjKGveLj21wgmRplE='\n        signature = self.nodes[0].signmessagewithprivkey(priv_key, message)\n        assert_equal(expected_signature, signature)\n        assert self.nodes[0].verifymessage(address, signature, message)\n\n        self.log.info('test signing with an address with wallet')\n        address = self.nodes[0].getnewaddress()\n        signature = self.nodes[0].signmessage(address, message)\n        assert self.nodes[0].verifymessage(address, signature, message)\n\n        self.log.info('test verifying with another address should not work')\n        other_address = self.nodes[0].getnewaddress()\n        other_signature = self.nodes[0].signmessage(other_address, message)\n        assert not self.nodes[0].verifymessage(other_address, signature, message)\n        assert not self.nodes[0].verifymessage(address, other_signature, message)\n\nif __name__ == '__main__':\n    SignMessagesTest().main()\n"
  },
  {
    "path": "test/functional/rpc_signrawtransaction.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test transaction signing using the signrawtransaction* RPCs.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes\nfrom test_framework.messages import sha256\nfrom test_framework.script import CScript, OP_0\n\nfrom decimal import Decimal\n\nclass SignRawTransactionsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def successful_signing_test(self):\n        \"\"\"Create and sign a valid raw transaction with one input.\n\n        Expected results:\n\n        1) The transaction has a complete set of signatures\n        2) No script verification error occurred\"\"\"\n        privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N', 'cVKpPfVKSJxKqVpE9awvXNWuLHCa5j5tiE7K6zbUSptFpTEtiFrA']\n\n        inputs = [\n            # Valid pay-to-pubkey scripts\n            {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0,\n             'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'},\n            {'txid': '83a4f6a6b73660e13ee6cb3c6063fa3759c50c9b7521d0536022961898f4fb02', 'vout': 0,\n             'scriptPubKey': '76a914669b857c03a5ed269d5d85a1ffac9ed5d663072788ac'},\n        ]\n\n        outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}\n\n        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)\n        rawTxSigned = self.nodes[0].signrawtransactionwithkey(rawTx, privKeys, inputs)\n\n        # 1) The transaction has a complete set of signatures\n        assert rawTxSigned['complete']\n\n        # 2) No script verification error occurred\n        assert 'errors' not in rawTxSigned\n\n    def test_with_lock_outputs(self):\n        \"\"\"Test correct error reporting when trying to sign a locked output\"\"\"\n        self.nodes[0].encryptwallet(\"password\")\n\n        rawTx = '020000000156b958f78e3f24e0b2f4e4db1255426b0902027cb37e3ddadb52e37c3557dddb0000000000ffffffff01c0a6b929010000001600149a2ee8c77140a053f36018ac8124a6ececc1668a00000000'\n\n        assert_raises_rpc_error(-13, \"Please enter the wallet passphrase with walletpassphrase first\", self.nodes[0].signrawtransaction, rawTx)\n\n    def script_verification_error_test(self):\n        \"\"\"Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.\n\n        Expected results:\n\n        3) The transaction has no complete set of signatures\n        4) Two script verification errors occurred\n        5) Script verification errors have certain properties (\"txid\", \"vout\", \"scriptSig\", \"sequence\", \"error\")\n        6) The verification errors refer to the invalid (vin 1) and missing input (vin 2)\"\"\"\n        privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N']\n\n        inputs = [\n            # Valid pay-to-pubkey script\n            {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0},\n            # Invalid script\n            {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7},\n            # Missing scriptPubKey\n            {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 1},\n        ]\n\n        scripts = [\n            # Valid pay-to-pubkey script\n            {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0,\n             'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'},\n            # Invalid script\n            {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7,\n             'scriptPubKey': 'badbadbadbad'}\n        ]\n\n        outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}\n\n        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)\n\n        # Make sure decoderawtransaction is at least marginally sane\n        decodedRawTx = self.nodes[0].decoderawtransaction(rawTx)\n        for i, inp in enumerate(inputs):\n            assert_equal(decodedRawTx[\"vin\"][i][\"txid\"], inp[\"txid\"])\n            assert_equal(decodedRawTx[\"vin\"][i][\"vout\"], inp[\"vout\"])\n\n        # Make sure decoderawtransaction throws if there is extra data\n        assert_raises_rpc_error(-22, \"TX decode failed\", self.nodes[0].decoderawtransaction, rawTx + \"00\")\n\n        rawTxSigned = self.nodes[0].signrawtransactionwithkey(rawTx, privKeys, scripts)\n\n        # 3) The transaction has no complete set of signatures\n        assert not rawTxSigned['complete']\n\n        # 4) Two script verification errors occurred\n        assert 'errors' in rawTxSigned\n        assert_equal(len(rawTxSigned['errors']), 2)\n\n        # 5) Script verification errors have certain properties\n        assert 'txid' in rawTxSigned['errors'][0]\n        assert 'vout' in rawTxSigned['errors'][0]\n        assert 'witness' in rawTxSigned['errors'][0]\n        assert 'scriptSig' in rawTxSigned['errors'][0]\n        assert 'sequence' in rawTxSigned['errors'][0]\n        assert 'error' in rawTxSigned['errors'][0]\n\n        # 6) The verification errors refer to the invalid (vin 1) and missing input (vin 2)\n        assert_equal(rawTxSigned['errors'][0]['txid'], inputs[1]['txid'])\n        assert_equal(rawTxSigned['errors'][0]['vout'], inputs[1]['vout'])\n        assert_equal(rawTxSigned['errors'][1]['txid'], inputs[2]['txid'])\n        assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout'])\n        assert not rawTxSigned['errors'][0]['witness']\n\n        # Now test signing failure for transaction with input witnesses\n        p2wpkh_raw_tx = \"01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000\"\n\n        rawTxSigned = self.nodes[0].signrawtransaction(p2wpkh_raw_tx)\n\n        # 7) The transaction has no complete set of signatures\n        assert not rawTxSigned['complete']\n\n        # 8) Two script verification errors occurred\n        assert 'errors' in rawTxSigned\n        assert_equal(len(rawTxSigned['errors']), 2)\n\n        # 9) Script verification errors have certain properties\n        assert 'txid' in rawTxSigned['errors'][0]\n        assert 'vout' in rawTxSigned['errors'][0]\n        assert 'witness' in rawTxSigned['errors'][0]\n        assert 'scriptSig' in rawTxSigned['errors'][0]\n        assert 'sequence' in rawTxSigned['errors'][0]\n        assert 'error' in rawTxSigned['errors'][0]\n\n        # Non-empty witness checked here\n        assert_equal(rawTxSigned['errors'][1]['witness'], [\"304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01\", \"025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357\"])\n        assert not rawTxSigned['errors'][0]['witness']\n\n    def witness_script_test(self):\n        # Now test signing transaction to P2SH-P2WSH addresses without wallet\n        # Create a new P2SH-P2WSH 1-of-1 multisig address:\n        embedded_address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())\n        embedded_privkey = self.nodes[1].dumpprivkey(embedded_address[\"address\"])\n        p2sh_p2wsh_address = self.nodes[1].addmultisigaddress(1, [embedded_address[\"pubkey\"]], \"\", \"p2sh-segwit\")\n        # send transaction to P2SH-P2WSH 1-of-1 multisig address\n        self.nodes[0].generate(101)\n        self.nodes[0].sendtoaddress(p2sh_p2wsh_address[\"address\"], 49.999)\n        self.nodes[0].generate(1)\n        self.sync_all()\n        # Find the UTXO for the transaction node[1] should have received, check witnessScript matches\n        unspent_output = self.nodes[1].listunspent(0, 999999, [p2sh_p2wsh_address[\"address\"]])[0]\n        assert_equal(unspent_output[\"witnessScript\"], p2sh_p2wsh_address[\"redeemScript\"])\n        p2sh_redeemScript = CScript([OP_0, sha256(hex_str_to_bytes(p2sh_p2wsh_address[\"redeemScript\"]))])\n        assert_equal(unspent_output[\"redeemScript\"], p2sh_redeemScript.hex())\n        # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys\n        spending_tx = self.nodes[0].createrawtransaction([unspent_output], {self.nodes[1].getnewaddress(): Decimal(\"49.998\")})\n        spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [unspent_output])\n        # Check the signing completed successfully\n        assert 'complete' in spending_tx_signed\n        assert_equal(spending_tx_signed['complete'], True)\n\n    def run_test(self):\n        self.successful_signing_test()\n        self.script_verification_error_test()\n        self.witness_script_test()\n        self.test_with_lock_outputs()\n\n\nif __name__ == '__main__':\n    SignRawTransactionsTest().main()\n"
  },
  {
    "path": "test/functional/rpc_txoutproof.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test gettxoutproof and verifytxoutproof RPCs.\"\"\"\n\nfrom test_framework.messages import CMerkleBlock, FromHex, ToHex\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes\n\nclass MerkleBlockTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n        # Nodes 0/1 are \"wallet\" nodes, Nodes 2/3 are used for testing\n        self.extra_args = [[], [], [], [\"-txindex\"]]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n        connect_nodes(self.nodes[0], 1)\n        connect_nodes(self.nodes[0], 2)\n        connect_nodes(self.nodes[0], 3)\n\n        self.sync_all()\n\n    def run_test(self):\n        self.log.info(\"Mining blocks...\")\n        self.nodes[0].generate(105)\n        self.sync_all()\n\n        chain_height = self.nodes[1].getblockcount()\n        assert_equal(chain_height, 105)\n        assert_equal(self.nodes[1].getbalance(), 0)\n        assert_equal(self.nodes[2].getbalance(), 0)\n\n        node0utxos = self.nodes[0].listunspent(1)\n        tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 49.99})\n        txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)[\"hex\"])\n        tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 49.99})\n        txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)[\"hex\"])\n        # This will raise an exception because the transaction is not yet in a block\n        assert_raises_rpc_error(-5, \"Transaction not yet in block\", self.nodes[0].gettxoutproof, [txid1])\n\n        self.nodes[0].generate(1)\n        blockhash = self.nodes[0].getblockhash(chain_height + 1)\n        self.sync_all()\n\n        txlist = []\n        blocktxn = self.nodes[0].getblock(blockhash, True)[\"tx\"]\n        txlist.append(blocktxn[1])\n        txlist.append(blocktxn[2])\n\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1])), [txid1])\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist)\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), txlist)\n\n        txin_spent = self.nodes[1].listunspent(1).pop()\n        tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 49.98})\n        txid3 = self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)[\"hex\"])\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        txid_spent = txin_spent[\"txid\"]\n        txid_unspent = txid1 if txin_spent[\"txid\"] != txid1 else txid2\n\n        # Invalid txids\n        assert_raises_rpc_error(-8, \"txid must be of length 64 (not 32, for '00000000000000000000000000000000')\", self.nodes[2].gettxoutproof, [\"00000000000000000000000000000000\"], blockhash)\n        assert_raises_rpc_error(-8, \"txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')\", self.nodes[2].gettxoutproof, [\"ZZZ0000000000000000000000000000000000000000000000000000000000000\"], blockhash)\n        # Invalid blockhashes\n        assert_raises_rpc_error(-8, \"blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')\", self.nodes[2].gettxoutproof, [txid_spent], \"00000000000000000000000000000000\")\n        assert_raises_rpc_error(-8, \"blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')\", self.nodes[2].gettxoutproof, [txid_spent], \"ZZZ0000000000000000000000000000000000000000000000000000000000000\")\n        # We can't find the block from a fully-spent tx\n        assert_raises_rpc_error(-5, \"Transaction not yet in block\", self.nodes[2].gettxoutproof, [txid_spent])\n        # We can get the proof if we specify the block\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent])\n        # We can't get the proof if we specify a non-existent block\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[2].gettxoutproof, [txid_spent], \"0000000000000000000000000000000000000000000000000000000000000000\")\n        # We can get the proof if the transaction is unspent\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent])\n        # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter.\n        assert_equal(sorted(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2]))), sorted(txlist))\n        assert_equal(sorted(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid2, txid1]))), sorted(txlist))\n        # We can always get a proof if we have a -txindex\n        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent])\n        # We can't get a proof if we specify transactions from different blocks\n        assert_raises_rpc_error(-5, \"Not all transactions found in specified or retrieved block\", self.nodes[2].gettxoutproof, [txid1, txid3])\n\n        # Now we'll try tweaking a proof.\n        proof = self.nodes[3].gettxoutproof([txid1, txid2])\n        assert txid1 in self.nodes[0].verifytxoutproof(proof)\n        assert txid2 in self.nodes[1].verifytxoutproof(proof)\n\n        tweaked_proof = FromHex(CMerkleBlock(), proof)\n\n        # Make sure that our serialization/deserialization is working\n        assert txid1 in self.nodes[2].verifytxoutproof(ToHex(tweaked_proof))\n\n        # Check to see if we can go up the merkle tree and pass this off as a\n        # single-transaction block\n        tweaked_proof.txn.nTransactions = 1\n        tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot]\n        tweaked_proof.txn.vBits = [True] + [False]*7\n\n        for n in self.nodes:\n            assert not n.verifytxoutproof(ToHex(tweaked_proof))\n\n        # TODO: try more variants, eg transactions at different depths, and\n        # verify that the proofs are invalid\n\nif __name__ == '__main__':\n    MerkleBlockTest().main()\n"
  },
  {
    "path": "test/functional/rpc_uptime.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the RPC call related to the uptime command.\n\nTest corresponds to code in rpc/server.cpp.\n\"\"\"\n\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\n\n\nclass UptimeTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def run_test(self):\n        self._test_uptime()\n\n    def _test_uptime(self):\n        wait_time = 10\n        self.nodes[0].setmocktime(int(time.time() + wait_time))\n        assert self.nodes[0].uptime() >= wait_time\n\n\nif __name__ == '__main__':\n    UptimeTest().main()\n"
  },
  {
    "path": "test/functional/rpc_users.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test multiple RPC users.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    get_datadir_path,\n    str_to_b64str,\n)\n\nimport os\nimport http.client\nimport urllib.parse\nimport subprocess\nfrom random import SystemRandom\nimport string\nimport configparser\nimport sys\n\n\nclass HTTPBasicsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def setup_chain(self):\n        super().setup_chain()\n        #Append rpcauth to munt.conf before initialization\n        rpcauth = \"rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144\"\n        rpcauth2 = \"rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e\"\n        rpcuser = \"rpcuser=rpcuser💻\"\n        rpcpassword = \"rpcpassword=rpcpassword🔑\"\n\n        self.user = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10))\n        config = configparser.ConfigParser()\n        config.read_file(open(self.options.configfile))\n        gen_rpcauth = config['environment']['RPCAUTH']\n        p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True, text=True)\n        lines = p.stdout.read().splitlines()\n        rpcauth3 = lines[1]\n        self.password = lines[3]\n\n        with open(os.path.join(get_datadir_path(self.options.tmpdir, 0), \"munt.conf\"), 'a', encoding='utf8') as f:\n            f.write(rpcauth+\"\\n\")\n            f.write(rpcauth2+\"\\n\")\n            f.write(rpcauth3+\"\\n\")\n        with open(os.path.join(get_datadir_path(self.options.tmpdir, 1), \"munt.conf\"), 'a', encoding='utf8') as f:\n            f.write(rpcuser+\"\\n\")\n            f.write(rpcpassword+\"\\n\")\n\n    def run_test(self):\n\n        ##################################################\n        # Check correctness of the rpcauth config option #\n        ##################################################\n        url = urllib.parse.urlparse(self.nodes[0].url)\n\n        #Old authpair\n        authpair = url.username + ':' + url.password\n\n        #New authpair generated via share/rpcauth tool\n        password = \"cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=\"\n\n        #Second authpair with different username\n        password2 = \"8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=\"\n        authpairnew = \"rt:\"+password\n\n        self.log.info('Correct...')\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpair)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 200)\n        conn.close()\n\n        #Use new authpair to confirm both work\n        self.log.info('Correct...')\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 200)\n        conn.close()\n\n        #Wrong login name with rt's password\n        self.log.info('Wrong...')\n        authpairnew = \"rtwrong:\"+password\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n        #Wrong password for rt\n        self.log.info('Wrong...')\n        authpairnew = \"rt:\"+password+\"wrong\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n        #Correct for rt2\n        self.log.info('Correct...')\n        authpairnew = \"rt2:\"+password2\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 200)\n        conn.close()\n\n        #Wrong password for rt2\n        self.log.info('Wrong...')\n        authpairnew = \"rt2:\"+password2+\"wrong\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n        #Correct for randomly generated user\n        self.log.info('Correct...')\n        authpairnew = self.user+\":\"+self.password\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 200)\n        conn.close()\n\n        #Wrong password for randomly generated user\n        self.log.info('Wrong...')\n        authpairnew = self.user+\":\"+self.password+\"Wrong\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(authpairnew)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n        ###############################################################\n        # Check correctness of the rpcuser/rpcpassword config options #\n        ###############################################################\n        url = urllib.parse.urlparse(self.nodes[1].url)\n\n        # rpcuser and rpcpassword authpair\n        self.log.info('Correct...')\n        rpcuserauthpair = \"rpcuser💻:rpcpassword🔑\"\n\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(rpcuserauthpair)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 200)\n        conn.close()\n\n        #Wrong login name with rpcuser's password\n        rpcuserauthpair = \"rpcuserwrong:rpcpassword\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(rpcuserauthpair)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n        #Wrong password for rpcuser\n        self.log.info('Wrong...')\n        rpcuserauthpair = \"rpcuser:rpcpasswordwrong\"\n        headers = {\"Authorization\": \"Basic \" + str_to_b64str(rpcuserauthpair)}\n\n        conn = http.client.HTTPConnection(url.hostname, url.port)\n        conn.connect()\n        conn.request('POST', '/', '{\"method\": \"getbestblockhash\"}', headers)\n        resp = conn.getresponse()\n        assert_equal(resp.status, 401)\n        conn.close()\n\n\nif __name__ == '__main__':\n    HTTPBasicsTest ().main ()\n"
  },
  {
    "path": "test/functional/test_framework/__init__.py",
    "content": ""
  },
  {
    "path": "test/functional/test_framework/address.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Encode and decode BASE58, P2PKH and P2SH addresses.\"\"\"\n\nfrom .script import hash256, hash160, sha256, CScript, OP_0\nfrom .util import hex_str_to_bytes\n\nfrom . import segwit_addr\n\nADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj'\n\nchars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\n\n\ndef byte_to_base58(b, version):\n    result = ''\n    str = b.hex()\n    str = chr(version).encode('latin-1').hex() + str\n    checksum = hash256(hex_str_to_bytes(str)).hex()\n    str += checksum[:8]\n    value = int('0x'+str,0)\n    while value > 0:\n        result = chars[value % 58] + result\n        value //= 58\n    while (str[:2] == '00'):\n        result = chars[0] + result\n        str = str[2:]\n    return result\n\n# TODO: def base58_decode\n\ndef keyhash_to_p2pkh(hash, main = False):\n    assert len(hash) == 20\n    version = 0 if main else 111\n    return byte_to_base58(hash, version)\n\ndef scripthash_to_p2sh(hash, main = False):\n    assert len(hash) == 20\n    version = 5 if main else 196\n    return byte_to_base58(hash, version)\n\ndef key_to_p2pkh(key, main = False):\n    key = check_key(key)\n    return keyhash_to_p2pkh(hash160(key), main)\n\ndef script_to_p2sh(script, main = False):\n    script = check_script(script)\n    return scripthash_to_p2sh(hash160(script), main)\n\ndef key_to_p2sh_p2wpkh(key, main = False):\n    key = check_key(key)\n    p2shscript = CScript([OP_0, hash160(key)])\n    return script_to_p2sh(p2shscript, main)\n\ndef program_to_witness(version, program, main = False):\n    if (type(program) is str):\n        program = hex_str_to_bytes(program)\n    assert 0 <= version <= 16\n    assert 2 <= len(program) <= 40\n    assert version > 0 or len(program) in [20, 32]\n    return segwit_addr.encode(\"bc\" if main else \"bcrt\", version, program)\n\ndef script_to_p2wsh(script, main = False):\n    script = check_script(script)\n    return program_to_witness(0, sha256(script), main)\n\ndef key_to_p2wpkh(key, main = False):\n    key = check_key(key)\n    return program_to_witness(0, hash160(key), main)\n\ndef script_to_p2sh_p2wsh(script, main = False):\n    script = check_script(script)\n    p2shscript = CScript([OP_0, sha256(script)])\n    return script_to_p2sh(p2shscript, main)\n\ndef check_key(key):\n    if (type(key) is str):\n        key = hex_str_to_bytes(key) # Assuming this is hex string\n    if (type(key) is bytes and (len(key) == 33 or len(key) == 65)):\n        return key\n    assert False\n\ndef check_script(script):\n    if (type(script) is str):\n        script = hex_str_to_bytes(script) # Assuming this is hex string\n    if (type(script) is bytes or type(script) is CScript):\n        return script\n    assert False\n"
  },
  {
    "path": "test/functional/test_framework/authproxy.py",
    "content": "# Copyright (c) 2011 Jeff Garzik\n#\n# Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:\n#\n# Copyright (c) 2007 Jan-Klaas Kollhof\n#\n# This file is part of jsonrpc.\n#\n# jsonrpc is free software; you can redistribute it and/or modify\n# it under the terms of the GNU Lesser General Public License as published by\n# the Free Software Foundation; either version 2.1 of the License, or\n# (at your option) any later version.\n#\n# This software is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with this software; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\"\"\"HTTP proxy for opening RPC connection to Munt-daemon.\n\nAuthServiceProxy has the following improvements over python-jsonrpc's\nServiceProxy class:\n\n- HTTP connections persist for the life of the AuthServiceProxy object\n  (if server supports HTTP/1.1)\n- sends protocol 'version', per JSON-RPC 1.1\n- sends proper, incrementing 'id'\n- sends Basic HTTP authentication headers\n- parses all JSON numbers that look like floats as Decimal\n- uses standard Python json lib\n\"\"\"\n\nimport base64\nimport decimal\nimport http.client\nimport json\nimport logging\nimport os\nimport socket\nimport time\nimport urllib.parse\n\nHTTP_TIMEOUT = 30\nUSER_AGENT = \"AuthServiceProxy/0.1\"\n\nlog = logging.getLogger(\"MuntRPC\")\n\nclass JSONRPCException(Exception):\n    def __init__(self, rpc_error):\n        try:\n            errmsg = '%(message)s (%(code)i)' % rpc_error\n        except (KeyError, TypeError):\n            errmsg = ''\n        super().__init__(errmsg)\n        self.error = rpc_error\n\n\ndef EncodeDecimal(o):\n    if isinstance(o, decimal.Decimal):\n        return str(o)\n    raise TypeError(repr(o) + \" is not JSON serializable\")\n\nclass AuthServiceProxy():\n    __id_count = 0\n\n    # ensure_ascii: escape unicode as \\uXXXX, passed to json.dumps\n    def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True):\n        self.__service_url = service_url\n        self._service_name = service_name\n        self.ensure_ascii = ensure_ascii  # can be toggled on the fly by tests\n        self.__url = urllib.parse.urlparse(service_url)\n        user = None if self.__url.username is None else self.__url.username.encode('utf8')\n        passwd = None if self.__url.password is None else self.__url.password.encode('utf8')\n        authpair = user + b':' + passwd\n        self.__auth_header = b'Basic ' + base64.b64encode(authpair)\n        self.timeout = timeout\n        self._set_conn(connection)\n\n    def __getattr__(self, name):\n        if name.startswith('__') and name.endswith('__'):\n            # Python internal stuff\n            raise AttributeError\n        if self._service_name is not None:\n            name = \"%s.%s\" % (self._service_name, name)\n        return AuthServiceProxy(self.__service_url, name, connection=self.__conn)\n\n    def _request(self, method, path, postdata):\n        '''\n        Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout).\n        This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5.\n        '''\n        headers = {'Host': self.__url.hostname,\n                   'User-Agent': USER_AGENT,\n                   'Authorization': self.__auth_header,\n                   'Content-type': 'application/json'}\n        if os.name == 'nt':\n            # Windows somehow does not like to re-use connections\n            # TODO: Find out why the connection would disconnect occasionally and make it reusable on Windows\n            self._set_conn()\n        try:\n            self.__conn.request(method, path, postdata, headers)\n            return self._get_response()\n        except http.client.BadStatusLine as e:\n            if e.line == \"''\":  # if connection was closed, try again\n                self.__conn.close()\n                self.__conn.request(method, path, postdata, headers)\n                return self._get_response()\n            else:\n                raise\n        except (BrokenPipeError, ConnectionResetError):\n            # Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset\n            # ConnectionResetError happens on FreeBSD with Python 3.4\n            self.__conn.close()\n            self.__conn.request(method, path, postdata, headers)\n            return self._get_response()\n\n    def get_request(self, *args, **argsn):\n        AuthServiceProxy.__id_count += 1\n\n        log.debug(\"-%s-> %s %s\" % (AuthServiceProxy.__id_count, self._service_name,\n                                   json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))\n        if args and argsn:\n            raise ValueError('Cannot handle both named and positional arguments')\n        return {'version': '1.1',\n                'method': self._service_name,\n                'params': args or argsn,\n                'id': AuthServiceProxy.__id_count}\n\n    def __call__(self, *args, **argsn):\n        postdata = json.dumps(self.get_request(*args, **argsn), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)\n        response = self._request('POST', self.__url.path, postdata.encode('utf-8'))\n        if response['error'] is not None:\n            raise JSONRPCException(response['error'])\n        elif 'result' not in response:\n            raise JSONRPCException({\n                'code': -343, 'message': 'missing JSON-RPC result'})\n        else:\n            return response['result']\n\n    def batch(self, rpc_call_list):\n        postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)\n        log.debug(\"--> \" + postdata)\n        return self._request('POST', self.__url.path, postdata.encode('utf-8'))\n\n    def _get_response(self):\n        req_start_time = time.time()\n        try:\n            http_response = self.__conn.getresponse()\n        except socket.timeout:\n            raise JSONRPCException({\n                'code': -344,\n                'message': '%r RPC took longer than %f seconds. Consider '\n                           'using larger timeout for calls that take '\n                           'longer to return.' % (self._service_name,\n                                                  self.__conn.timeout)})\n        if http_response is None:\n            raise JSONRPCException({\n                'code': -342, 'message': 'missing HTTP response from server'})\n\n        content_type = http_response.getheader('Content-Type')\n        if content_type != 'application/json':\n            raise JSONRPCException({\n                'code': -342, 'message': 'non-JSON HTTP response with \\'%i %s\\' from server' % (http_response.status, http_response.reason)})\n\n        responsedata = http_response.read().decode('utf8')\n        response = json.loads(responsedata, parse_float=decimal.Decimal)\n        elapsed = time.time() - req_start_time\n        if \"error\" in response and response[\"error\"] is None:\n            log.debug(\"<-%s- [%.6f] %s\" % (response[\"id\"], elapsed, json.dumps(response[\"result\"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))\n        else:\n            log.debug(\"<-- [%.6f] %s\" % (elapsed, responsedata))\n        return response\n\n    def __truediv__(self, relative_uri):\n        return AuthServiceProxy(\"{}/{}\".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn)\n\n    def _set_conn(self, connection=None):\n        port = 80 if self.__url.port is None else self.__url.port\n        if connection:\n            self.__conn = connection\n            self.timeout = connection.timeout\n        elif self.__url.scheme == 'https':\n            self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=self.timeout)\n        else:\n            self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=self.timeout)\n"
  },
  {
    "path": "test/functional/test_framework/bignum.py",
    "content": "#!/usr/bin/env python3\n#\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Big number routines.\n\nThis file is copied from python-bitcoinlib.\n\"\"\"\n\nimport struct\n\n\n# generic big endian MPI format\n\ndef bn_bytes(v, have_ext=False):\n    ext = 0\n    if have_ext:\n        ext = 1\n    return ((v.bit_length()+7)//8) + ext\n\ndef bn2bin(v):\n    s = bytearray()\n    i = bn_bytes(v)\n    while i > 0:\n        s.append((v >> ((i-1) * 8)) & 0xff)\n        i -= 1\n    return s\n\ndef bn2mpi(v):\n    have_ext = False\n    if v.bit_length() > 0:\n        have_ext = (v.bit_length() & 0x07) == 0\n\n    neg = False\n    if v < 0:\n        neg = True\n        v = -v\n\n    s = struct.pack(b\">I\", bn_bytes(v, have_ext))\n    ext = bytearray()\n    if have_ext:\n        ext.append(0)\n    v_bin = bn2bin(v)\n    if neg:\n        if have_ext:\n            ext[0] |= 0x80\n        else:\n            v_bin[0] |= 0x80\n    return s + ext + v_bin\n\n# Munt-specific little endian format, with implicit size\ndef mpi2vch(s):\n    r = s[4:]           # strip size\n    r = r[::-1]         # reverse string, converting BE->LE\n    return r\n\ndef bn2vch(v):\n    return bytes(mpi2vch(bn2mpi(v)))\n"
  },
  {
    "path": "test/functional/test_framework/blocktools.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Utilities for manipulating blocks and transactions.\"\"\"\n\nfrom .address import (\n    key_to_p2sh_p2wpkh,\n    key_to_p2wpkh,\n    script_to_p2sh_p2wsh,\n    script_to_p2wsh,\n)\nfrom .messages import (\n    CBlock,\n    COIN,\n    COutPoint,\n    CTransaction,\n    CTxIn,\n    CTxInWitness,\n    CTxOut,\n    FromHex,\n    ToHex,\n    hash256,\n    hex_str_to_bytes,\n    ser_string,\n    ser_uint256,\n    sha256,\n    uint256_from_str,\n)\nfrom .script import (\n    CScript,\n    OP_0,\n    OP_1,\n    OP_CHECKMULTISIG,\n    OP_CHECKSIG,\n    OP_RETURN,\n    OP_TRUE,\n    hash160,\n)\nfrom .util import assert_equal\nfrom io import BytesIO\n\nMAX_BLOCK_SIGOPS = 20000\n\n# Genesis block time (regtestlegacy)\nTIME_GENESIS_BLOCK = 1296688602\n\n# From BIP141\nWITNESS_COMMITMENT_HEADER = b\"\\xaa\\x21\\xa9\\xed\"\n\n\ndef create_block(hashprev, coinbase, ntime=None, *, version=1):\n    \"\"\"Create a block (with regtestlegacy difficulty).\"\"\"\n    block = CBlock()\n    block.nVersion = version\n    if ntime is None:\n        import time\n        block.nTime = int(time.time() + 600)\n    else:\n        block.nTime = ntime\n    block.hashPrevBlock = hashprev\n    block.nBits = 0x207fffff  # difficulty retargeting is disabled in REGTEST chainparams\n    block.vtx.append(coinbase)\n    block.hashMerkleRoot = block.calc_merkle_root()\n    block.calc_sha256()\n    return block\n\ndef get_witness_script(witness_root, witness_nonce):\n    witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce)))\n    output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)\n    return CScript([OP_RETURN, output_data])\n\ndef add_witness_commitment(block, nonce=0):\n    \"\"\"Add a witness commitment to the block's coinbase transaction.\n\n    According to BIP141, blocks with witness rules active must commit to the\n    hash of all in-block transactions including witness.\"\"\"\n    # First calculate the merkle root of the block's\n    # transactions, with witnesses.\n    witness_nonce = nonce\n    witness_root = block.calc_witness_merkle_root()\n    # witness_nonce should go to coinbase witness.\n    block.vtx[0].wit.vtxinwit = [CTxInWitness()]\n    block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]\n\n    # witness commitment is the last OP_RETURN output in coinbase\n    block.vtx[0].vout.append(CTxOut(0, get_witness_script(witness_root, witness_nonce)))\n    block.vtx[0].rehash()\n    block.hashMerkleRoot = block.calc_merkle_root()\n    block.rehash()\n\ndef serialize_script_num(value):\n    r = bytearray(0)\n    if value == 0:\n        return r\n    neg = value < 0\n    absvalue = -value if neg else value\n    while (absvalue):\n        r.append(int(absvalue & 0xff))\n        absvalue >>= 8\n    if r[-1] & 0x80:\n        r.append(0x80 if neg else 0)\n    elif neg:\n        r[-1] |= 0x80\n    return r\n\ndef create_coinbase(height, pubkey=None):\n    \"\"\"Create a coinbase transaction, assuming no miner fees.\n\n    If pubkey is passed in, the coinbase output will be a P2PK output;\n    otherwise an anyone-can-spend output.\"\"\"\n    coinbase = CTransaction()\n    coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),\n                        ser_string(serialize_script_num(height)), 0xffffffff))\n    coinbaseoutput = CTxOut()\n    coinbaseoutput.nValue = 50 * COIN\n    halvings = int(height / 150)  # regtestlegacy\n    coinbaseoutput.nValue >>= halvings\n    if (pubkey is not None):\n        coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG])\n    else:\n        coinbaseoutput.scriptPubKey = CScript([OP_TRUE])\n    coinbase.vout = [coinbaseoutput]\n    coinbase.calc_sha256()\n    return coinbase\n\ndef create_tx_with_script(prevtx, n, script_sig=b\"\", *, amount, script_pub_key=CScript()):\n    \"\"\"Return one-input, one-output transaction object\n       spending the prevtx's n-th output with the given amount.\n\n       Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.\n    \"\"\"\n    tx = CTransaction()\n    assert n < len(prevtx.vout)\n    tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))\n    tx.vout.append(CTxOut(amount, script_pub_key))\n    tx.calc_sha256()\n    return tx\n\ndef create_transaction(node, txid, to_address, *, amount):\n    \"\"\" Return signed transaction spending the first output of the\n        input txid. Note that the node must be able to sign for the\n        output that is being spent, and the node must not be running\n        multiple wallets.\n    \"\"\"\n    raw_tx = create_raw_transaction(node, txid, to_address, amount=amount)\n    tx = CTransaction()\n    tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx)))\n    return tx\n\ndef create_raw_transaction(node, txid, to_address, *, amount):\n    \"\"\" Return raw signed transaction spending the first output of the\n        input txid. Note that the node must be able to sign for the\n        output that is being spent, and the node must not be running\n        multiple wallets.\n    \"\"\"\n    rawtx = node.createrawtransaction(inputs=[{\"txid\": txid, \"vout\": 0}], outputs={to_address: amount})\n    signresult = node.signrawtransaction(rawtx)\n    assert_equal(signresult[\"complete\"], True)\n    return signresult['hex']\n\ndef get_legacy_sigopcount_block(block, accurate=True):\n    count = 0\n    for tx in block.vtx:\n        count += get_legacy_sigopcount_tx(tx, accurate)\n    return count\n\ndef get_legacy_sigopcount_tx(tx, accurate=True):\n    count = 0\n    for i in tx.vout:\n        count += i.scriptPubKey.GetSigOpCount(accurate)\n    for j in tx.vin:\n        # scriptSig might be of type bytes, so convert to CScript for the moment\n        count += CScript(j.scriptSig).GetSigOpCount(accurate)\n    return count\n\ndef witness_script(use_p2wsh, pubkey):\n    \"\"\"Create a scriptPubKey for a pay-to-witness TxOut.\n\n    This is either a P2WPKH output for the given pubkey, or a P2WSH output of a\n    1-of-1 multisig for the given pubkey. Returns the hex encoding of the\n    scriptPubKey.\"\"\"\n    if not use_p2wsh:\n        # P2WPKH instead\n        pubkeyhash = hash160(hex_str_to_bytes(pubkey))\n        pkscript = CScript([OP_0, pubkeyhash])\n    else:\n        # 1-of-1 multisig\n        witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])\n        scripthash = sha256(witness_program)\n        pkscript = CScript([OP_0, scripthash])\n    return pkscript.hex()\n\ndef create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):\n    \"\"\"Return a transaction (in hex) that spends the given utxo to a segwit output.\n\n    Optionally wrap the segwit output using P2SH.\"\"\"\n    if use_p2wsh:\n        program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])\n        addr = script_to_p2sh_p2wsh(program) if encode_p2sh else script_to_p2wsh(program)\n    else:\n        addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)\n    if not encode_p2sh:\n        assert_equal(node.getaddressinfo(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))\n    return node.createrawtransaction([utxo], {addr: amount})\n\ndef send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=\"\"):\n    \"\"\"Create a transaction spending a given utxo to a segwit output.\n\n    The output corresponds to the given pubkey: use_p2wsh determines whether to\n    use P2WPKH or P2WSH; encode_p2sh determines whether to wrap in P2SH.\n    sign=True will have the given node sign the transaction.\n    insert_redeem_script will be added to the scriptSig, if given.\"\"\"\n    tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)\n    if (sign):\n        signed = node.signrawtransaction(tx_to_witness)\n        assert \"errors\" not in signed or len([\"errors\"]) == 0\n        return node.sendrawtransaction(signed[\"hex\"])\n    else:\n        if (insert_redeem_script):\n            tx = FromHex(CTransaction(), tx_to_witness)\n            tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)])\n            tx_to_witness = ToHex(tx)\n\n    return node.sendrawtransaction(tx_to_witness)\n"
  },
  {
    "path": "test/functional/test_framework/coverage.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Utilities for doing coverage analysis on the RPC interface.\n\nProvides a way to track which RPC commands are exercised during\ntesting.\n\"\"\"\n\nimport os\n\n\nREFERENCE_FILENAME = 'rpc_interface.txt'\n\n\nclass AuthServiceProxyWrapper():\n    \"\"\"\n    An object that wraps AuthServiceProxy to record specific RPC calls.\n\n    \"\"\"\n    def __init__(self, auth_service_proxy_instance, coverage_logfile=None):\n        \"\"\"\n        Kwargs:\n            auth_service_proxy_instance (AuthServiceProxy): the instance\n                being wrapped.\n            coverage_logfile (str): if specified, write each service_name\n                out to a file when called.\n\n        \"\"\"\n        self.auth_service_proxy_instance = auth_service_proxy_instance\n        self.coverage_logfile = coverage_logfile\n\n    def __getattr__(self, name):\n        return_val = getattr(self.auth_service_proxy_instance, name)\n        if not isinstance(return_val, type(self.auth_service_proxy_instance)):\n            # If proxy getattr returned an unwrapped value, do the same here.\n            return return_val\n        return AuthServiceProxyWrapper(return_val, self.coverage_logfile)\n\n    def __call__(self, *args, **kwargs):\n        \"\"\"\n        Delegates to AuthServiceProxy, then writes the particular RPC method\n        called to a file.\n\n        \"\"\"\n        return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)\n        self._log_call()\n        return return_val\n\n    def _log_call(self):\n        rpc_method = self.auth_service_proxy_instance._service_name\n\n        if self.coverage_logfile:\n            with open(self.coverage_logfile, 'a+', encoding='utf8') as f:\n                f.write(\"%s\\n\" % rpc_method)\n\n    def __truediv__(self, relative_uri):\n        return AuthServiceProxyWrapper(self.auth_service_proxy_instance / relative_uri,\n                                       self.coverage_logfile)\n\n    def get_request(self, *args, **kwargs):\n        self._log_call()\n        return self.auth_service_proxy_instance.get_request(*args, **kwargs)\n\ndef get_filename(dirname, n_node):\n    \"\"\"\n    Get a filename unique to the test process ID and node.\n\n    This file will contain a list of RPC commands covered.\n    \"\"\"\n    pid = str(os.getpid())\n    return os.path.join(\n        dirname, \"coverage.pid%s.node%s.txt\" % (pid, str(n_node)))\n\n\ndef write_all_rpc_commands(dirname, node):\n    \"\"\"\n    Write out a list of all RPC functions available in `Munt-cli` for\n    coverage comparison. This will only happen once per coverage\n    directory.\n\n    Args:\n        dirname (str): temporary test dir\n        node (AuthServiceProxy): client\n\n    Returns:\n        bool. if the RPC interface file was written.\n\n    \"\"\"\n    filename = os.path.join(dirname, REFERENCE_FILENAME)\n\n    if os.path.isfile(filename):\n        return False\n\n    help_output = node.help().split('\\n')\n    commands = set()\n\n    for line in help_output:\n        line = line.strip()\n\n        # Ignore blanks and headers\n        if line and not line.startswith('='):\n            commands.add(\"%s\\n\" % line.split()[0])\n\n    with open(filename, 'w', encoding='utf8') as f:\n        f.writelines(list(commands))\n\n    return True\n"
  },
  {
    "path": "test/functional/test_framework/descriptors.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2019 Pieter Wuille\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Utility functions related to output descriptors\"\"\"\n\nINPUT_CHARSET = \"0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\\\"\\\\ \"\nCHECKSUM_CHARSET = \"qpzry9x8gf2tvdw0s3jn54khce6mua7l\"\nGENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd]\n\ndef descsum_polymod(symbols):\n    \"\"\"Internal function that computes the descriptor checksum.\"\"\"\n    chk = 1\n    for value in symbols:\n        top = chk >> 35\n        chk = (chk & 0x7ffffffff) << 5 ^ value\n        for i in range(5):\n            chk ^= GENERATOR[i] if ((top >> i) & 1) else 0\n    return chk\n\ndef descsum_expand(s):\n    \"\"\"Internal function that does the character to symbol expansion\"\"\"\n    groups = []\n    symbols = []\n    for c in s:\n        if not c in INPUT_CHARSET:\n            return None\n        v = INPUT_CHARSET.find(c)\n        symbols.append(v & 31)\n        groups.append(v >> 5)\n        if len(groups) == 3:\n            symbols.append(groups[0] * 9 + groups[1] * 3 + groups[2])\n            groups = []\n    if len(groups) == 1:\n        symbols.append(groups[0])\n    elif len(groups) == 2:\n        symbols.append(groups[0] * 3 + groups[1])\n    return symbols\n\ndef descsum_create(s):\n    \"\"\"Add a checksum to a descriptor without\"\"\"\n    symbols = descsum_expand(s) + [0, 0, 0, 0, 0, 0, 0, 0]\n    checksum = descsum_polymod(symbols) ^ 1\n    return s + '#' + ''.join(CHECKSUM_CHARSET[(checksum >> (5 * (7 - i))) & 31] for i in range(8))\n\ndef descsum_check(s, require=True):\n    \"\"\"Verify that the checksum is correct in a descriptor\"\"\"\n    if not '#' in s:\n        return not require\n    if s[-9] != '#':\n        return False\n    if not all(x in CHECKSUM_CHARSET for x in s[-8:]):\n        return False\n    symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]]\n    return descsum_polymod(symbols) == 1\n"
  },
  {
    "path": "test/functional/test_framework/key.py",
    "content": "# Copyright (c) 2011 Sam Rushing\n\"\"\"ECC secp256k1 OpenSSL wrapper.\n\nWARNING: This module does not mlock() secrets; your private keys may end up on\ndisk in swap! Use with caution!\n\nThis file is modified from python-bitcoinlib.\n\"\"\"\n\nimport ctypes\nimport ctypes.util\nimport hashlib\n\nssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32')\n\nssl.BN_new.restype = ctypes.c_void_p\nssl.BN_new.argtypes = []\n\nssl.BN_bin2bn.restype = ctypes.c_void_p\nssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]\n\nssl.BN_CTX_free.restype = None\nssl.BN_CTX_free.argtypes = [ctypes.c_void_p]\n\nssl.BN_CTX_new.restype = ctypes.c_void_p\nssl.BN_CTX_new.argtypes = []\n\nssl.ECDH_compute_key.restype = ctypes.c_int\nssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]\n\nssl.ECDSA_sign.restype = ctypes.c_int\nssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]\n\nssl.ECDSA_verify.restype = ctypes.c_int\nssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]\n\nssl.EC_KEY_free.restype = None\nssl.EC_KEY_free.argtypes = [ctypes.c_void_p]\n\nssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p\nssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]\n\nssl.EC_KEY_get0_group.restype = ctypes.c_void_p\nssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]\n\nssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p\nssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]\n\nssl.EC_KEY_set_private_key.restype = ctypes.c_int\nssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]\n\nssl.EC_KEY_set_conv_form.restype = None\nssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int]\n\nssl.EC_KEY_set_public_key.restype = ctypes.c_int\nssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]\n\nssl.i2o_ECPublicKey.restype = ctypes.c_void_p\nssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]\n\nssl.EC_POINT_new.restype = ctypes.c_void_p\nssl.EC_POINT_new.argtypes = [ctypes.c_void_p]\n\nssl.EC_POINT_free.restype = None\nssl.EC_POINT_free.argtypes = [ctypes.c_void_p]\n\nssl.EC_POINT_mul.restype = ctypes.c_int\nssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]\n\n# this specifies the curve used with ECDSA.\nNID_secp256k1 = 714 # from openssl/obj_mac.h\n\nSECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\nSECP256K1_ORDER_HALF = SECP256K1_ORDER // 2\n\n# Thx to Sam Devlin for the ctypes magic 64-bit fix.\ndef _check_result(val, func, args):\n    if val == 0:\n        raise ValueError\n    else:\n        return ctypes.c_void_p (val)\n\nssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p\nssl.EC_KEY_new_by_curve_name.errcheck = _check_result\n\nclass CECKey():\n    \"\"\"Wrapper around OpenSSL's EC_KEY\"\"\"\n\n    POINT_CONVERSION_COMPRESSED = 2\n    POINT_CONVERSION_UNCOMPRESSED = 4\n\n    def __init__(self):\n        self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1)\n\n    def __del__(self):\n        if ssl:\n            ssl.EC_KEY_free(self.k)\n        self.k = None\n\n    def set_secretbytes(self, secret):\n        priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new())\n        group = ssl.EC_KEY_get0_group(self.k)\n        pub_key = ssl.EC_POINT_new(group)\n        ctx = ssl.BN_CTX_new()\n        if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):\n            raise ValueError(\"Could not derive public key from the supplied secret.\")\n        ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)\n        ssl.EC_KEY_set_private_key(self.k, priv_key)\n        ssl.EC_KEY_set_public_key(self.k, pub_key)\n        ssl.EC_POINT_free(pub_key)\n        ssl.BN_CTX_free(ctx)\n        return self.k\n\n    def set_privkey(self, key):\n        self.mb = ctypes.create_string_buffer(key)\n        return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))\n\n    def set_pubkey(self, key):\n        self.mb = ctypes.create_string_buffer(key)\n        return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))\n\n    def get_privkey(self):\n        size = ssl.i2d_ECPrivateKey(self.k, 0)\n        mb_pri = ctypes.create_string_buffer(size)\n        ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))\n        return mb_pri.raw\n\n    def get_pubkey(self):\n        size = ssl.i2o_ECPublicKey(self.k, 0)\n        mb = ctypes.create_string_buffer(size)\n        ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))\n        return mb.raw\n\n    def get_raw_ecdh_key(self, other_pubkey):\n        ecdh_keybuffer = ctypes.create_string_buffer(32)\n        r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,\n                                 ssl.EC_KEY_get0_public_key(other_pubkey.k),\n                                 self.k, 0)\n        if r != 32:\n            raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')\n        return ecdh_keybuffer.raw\n\n    def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):\n        # FIXME: be warned it's not clear what the kdf should be as a default\n        r = self.get_raw_ecdh_key(other_pubkey)\n        return kdf(r)\n\n    def sign(self, hash, low_s = True):\n        # FIXME: need unit tests for below cases\n        if not isinstance(hash, bytes):\n            raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)\n        if len(hash) != 32:\n            raise ValueError('Hash must be exactly 32 bytes long')\n\n        sig_size0 = ctypes.c_uint32()\n        sig_size0.value = ssl.ECDSA_size(self.k)\n        mb_sig = ctypes.create_string_buffer(sig_size0.value)\n        result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)\n        assert 1 == result\n        assert mb_sig.raw[0] == 0x30\n        assert mb_sig.raw[1] == sig_size0.value - 2\n        total_size = mb_sig.raw[1]\n        assert mb_sig.raw[2] == 2\n        r_size = mb_sig.raw[3]\n        assert mb_sig.raw[4 + r_size] == 2\n        s_size = mb_sig.raw[5 + r_size]\n        s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big')\n        if (not low_s) or s_value <= SECP256K1_ORDER_HALF:\n            return mb_sig.raw[:sig_size0.value]\n        else:\n            low_s_value = SECP256K1_ORDER - s_value\n            low_s_bytes = (low_s_value).to_bytes(33, byteorder='big')\n            while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80:\n                low_s_bytes = low_s_bytes[1:]\n            new_s_size = len(low_s_bytes)\n            new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big')\n            new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big')\n            return b'\\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes\n\n    def verify(self, hash, sig):\n        \"\"\"Verify a DER signature\"\"\"\n        return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1\n\n    def set_compressed(self, compressed):\n        if compressed:\n            form = self.POINT_CONVERSION_COMPRESSED\n        else:\n            form = self.POINT_CONVERSION_UNCOMPRESSED\n        ssl.EC_KEY_set_conv_form(self.k, form)\n\n\nclass CPubKey(bytes):\n    \"\"\"An encapsulated public key\n\n    Attributes:\n\n    is_valid      - Corresponds to CPubKey.IsValid()\n    is_fullyvalid - Corresponds to CPubKey.IsFullyValid()\n    is_compressed - Corresponds to CPubKey.IsCompressed()\n    \"\"\"\n\n    def __new__(cls, buf, _cec_key=None):\n        self = super(CPubKey, cls).__new__(cls, buf)\n        if _cec_key is None:\n            _cec_key = CECKey()\n        self._cec_key = _cec_key\n        self.is_fullyvalid = _cec_key.set_pubkey(self) != 0\n        return self\n\n    @property\n    def is_valid(self):\n        return len(self) > 0\n\n    @property\n    def is_compressed(self):\n        return len(self) == 33\n\n    def verify(self, hash, sig):\n        return self._cec_key.verify(hash, sig)\n\n    def __str__(self):\n        return repr(self)\n\n    def __repr__(self):\n        return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())\n\n"
  },
  {
    "path": "test/functional/test_framework/messages.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2010 ArtForz -- public domain half-a-node\n# Copyright (c) 2012 Jeff Garzik\n# Copyright (c) 2010-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Munt test framework primitive and message structures\n\nCBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:\n    data structures that should map to corresponding structures in\n    munt/primitives\n\nmsg_block, msg_tx, msg_headers, etc.:\n    data structures that represent network messages\n\nser_*, deser_*: functions that handle serialization/deserialization.\n\nClasses use __slots__ to ensure extraneous attributes aren't accidentally added\nby tests, compromising their intended effect.\n\"\"\"\nfrom codecs import encode\nimport copy\nimport hashlib\nfrom io import BytesIO\nimport random\nimport socket\nimport struct\nimport time\n\nfrom test_framework.siphash import siphash256\nfrom test_framework.util import hex_str_to_bytes, assert_equal\n\nMIN_VERSION_SUPPORTED = 60001\nMY_VERSION = 70020  # past bip-31 for ping/pong\nMY_SUBVERSION = b\"/python-mininode-tester:0.0.3/\"\nMY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)\n\nMAX_LOCATOR_SZ = 101\nMAX_BLOCK_BASE_SIZE = 1000000\n\nCOIN = 100000000  # 1 btc in satoshis\n\nBIP125_SEQUENCE_NUMBER = 0xfffffffd  # Sequence number that is BIP 125 opt-in and BIP 68-opt-out\n\nNODE_NETWORK = (1 << 0)\n# NODE_GETUTXO = (1 << 1)\nNODE_BLOOM = (1 << 2)\nNODE_WITNESS = (1 << 3)\nNODE_NETWORK_LIMITED = (1 << 10)\n\nMSG_TX = 1\nMSG_BLOCK = 2\nMSG_WITNESS_FLAG = 1 << 30\nMSG_TYPE_MASK = 0xffffffff >> 2\n\n# Serialization/deserialization tools\ndef sha256(s):\n    return hashlib.new('sha256', s).digest()\n\ndef hash256(s):\n    return sha256(sha256(s))\n\ndef ser_compact_size(l):\n    r = b\"\"\n    if l < 253:\n        r = struct.pack(\"B\", l)\n    elif l < 0x10000:\n        r = struct.pack(\"<BH\", 253, l)\n    elif l < 0x100000000:\n        r = struct.pack(\"<BI\", 254, l)\n    else:\n        r = struct.pack(\"<BQ\", 255, l)\n    return r\n\ndef deser_compact_size(f):\n    nit = struct.unpack(\"<B\", f.read(1))[0]\n    if nit == 253:\n        nit = struct.unpack(\"<H\", f.read(2))[0]\n    elif nit == 254:\n        nit = struct.unpack(\"<I\", f.read(4))[0]\n    elif nit == 255:\n        nit = struct.unpack(\"<Q\", f.read(8))[0]\n    return nit\n\ndef deser_string(f):\n    nit = deser_compact_size(f)\n    return f.read(nit)\n\ndef ser_string(s):\n    return ser_compact_size(len(s)) + s\n\ndef deser_uint256(f):\n    r = 0\n    for i in range(8):\n        t = struct.unpack(\"<I\", f.read(4))[0]\n        r += t << (i * 32)\n    return r\n\n\ndef ser_uint256(u):\n    rs = b\"\"\n    for i in range(8):\n        rs += struct.pack(\"<I\", u & 0xFFFFFFFF)\n        u >>= 32\n    return rs\n\n\ndef uint256_from_str(s):\n    r = 0\n    t = struct.unpack(\"<IIIIIIII\", s[:32])\n    for i in range(8):\n        r += t[i] << (i * 32)\n    return r\n\n\ndef uint256_from_compact(c):\n    nbytes = (c >> 24) & 0xFF\n    v = (c & 0xFFFFFF) << (8 * (nbytes - 3))\n    return v\n\n\ndef deser_vector(f, c):\n    nit = deser_compact_size(f)\n    r = []\n    for i in range(nit):\n        t = c()\n        t.deserialize(f)\n        r.append(t)\n    return r\n\n\n# ser_function_name: Allow for an alternate serialization function on the\n# entries in the vector (we use this for serializing the vector of transactions\n# for a witness block).\ndef ser_vector(l, ser_function_name=None):\n    r = ser_compact_size(len(l))\n    for i in l:\n        if ser_function_name:\n            r += getattr(i, ser_function_name)()\n        else:\n            r += i.serialize()\n    return r\n\n\ndef deser_uint256_vector(f):\n    nit = deser_compact_size(f)\n    r = []\n    for i in range(nit):\n        t = deser_uint256(f)\n        r.append(t)\n    return r\n\n\ndef ser_uint256_vector(l):\n    r = ser_compact_size(len(l))\n    for i in l:\n        r += ser_uint256(i)\n    return r\n\n\ndef deser_string_vector(f):\n    nit = deser_compact_size(f)\n    r = []\n    for i in range(nit):\n        t = deser_string(f)\n        r.append(t)\n    return r\n\n\ndef ser_string_vector(l):\n    r = ser_compact_size(len(l))\n    for sv in l:\n        r += ser_string(sv)\n    return r\n\n\n# Deserialize from a hex string representation (eg from RPC)\ndef FromHex(obj, hex_string):\n    obj.deserialize(BytesIO(hex_str_to_bytes(hex_string)))\n    return obj\n\n# Convert a binary-serializable object to hex (eg for submission via RPC)\ndef ToHex(obj):\n    return obj.serialize().hex()\n\n# Objects that map to Munt-daemon objects, which can be serialized/deserialized\n\n\nclass CAddress:\n    __slots__ = (\"ip\", \"nServices\", \"pchReserved\", \"port\", \"time\")\n\n    def __init__(self):\n        self.time = 0\n        self.nServices = 1\n        self.pchReserved = b\"\\x00\" * 10 + b\"\\xff\" * 2\n        self.ip = \"0.0.0.0\"\n        self.port = 0\n\n    def deserialize(self, f, with_time=True):\n        if with_time:\n            self.time = struct.unpack(\"<i\", f.read(4))[0]\n        self.nServices = struct.unpack(\"<Q\", f.read(8))[0]\n        self.pchReserved = f.read(12)\n        self.ip = socket.inet_ntoa(f.read(4))\n        self.port = struct.unpack(\">H\", f.read(2))[0]\n\n    def serialize(self, with_time=True):\n        r = b\"\"\n        if with_time:\n            r += struct.pack(\"<i\", self.time)\n        r += struct.pack(\"<Q\", self.nServices)\n        r += self.pchReserved\n        r += socket.inet_aton(self.ip)\n        r += struct.pack(\">H\", self.port)\n        return r\n\n    def __repr__(self):\n        return \"CAddress(nServices=%i ip=%s port=%i)\" % (self.nServices,\n                                                         self.ip, self.port)\n\n\nclass CInv:\n    __slots__ = (\"hash\", \"type\")\n\n    typemap = {\n        0: \"Error\",\n        1: \"TX\",\n        2: \"Block\",\n        1|MSG_WITNESS_FLAG: \"WitnessTx\",\n        2|MSG_WITNESS_FLAG : \"WitnessBlock\",\n        4: \"CompactBlock\"\n    }\n\n    def __init__(self, t=0, h=0):\n        self.type = t\n        self.hash = h\n\n    def deserialize(self, f):\n        self.type = struct.unpack(\"<i\", f.read(4))[0]\n        self.hash = deser_uint256(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.type)\n        r += ser_uint256(self.hash)\n        return r\n\n    def __repr__(self):\n        return \"CInv(type=%s hash=%064x)\" \\\n            % (self.typemap[self.type], self.hash)\n\n\nclass CBlockLocator:\n    __slots__ = (\"nVersion\", \"vHave\")\n\n    def __init__(self):\n        self.nVersion = MY_VERSION\n        self.vHave = []\n\n    def deserialize(self, f):\n        self.nVersion = struct.unpack(\"<i\", f.read(4))[0]\n        self.vHave = deser_uint256_vector(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nVersion)\n        r += ser_uint256_vector(self.vHave)\n        return r\n\n    def __repr__(self):\n        return \"CBlockLocator(nVersion=%i vHave=%s)\" \\\n            % (self.nVersion, repr(self.vHave))\n\n\nclass COutPoint:\n    __slots__ = (\"hash\", \"n\")\n\n    def __init__(self, hash=0, n=0):\n        self.hash = hash\n        self.n = n\n\n    def deserialize(self, f):\n        self.hash = deser_uint256(f)\n        self.n = struct.unpack(\"<I\", f.read(4))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += ser_uint256(self.hash)\n        r += struct.pack(\"<I\", self.n)\n        return r\n\n    def __repr__(self):\n        return \"COutPoint(hash=%064x n=%i)\" % (self.hash, self.n)\n\n\nclass CTxIn:\n    __slots__ = (\"nSequence\", \"prevout\", \"scriptSig\")\n\n    def __init__(self, outpoint=None, scriptSig=b\"\", nSequence=0):\n        if outpoint is None:\n            self.prevout = COutPoint()\n        else:\n            self.prevout = outpoint\n        self.scriptSig = scriptSig\n        self.nSequence = nSequence\n\n    def deserialize(self, f):\n        self.prevout = COutPoint()\n        self.prevout.deserialize(f)\n        self.scriptSig = deser_string(f)\n        self.nSequence = struct.unpack(\"<I\", f.read(4))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += self.prevout.serialize()\n        r += ser_string(self.scriptSig)\n        r += struct.pack(\"<I\", self.nSequence)\n        return r\n\n    def __repr__(self):\n        return \"CTxIn(prevout=%s scriptSig=%s nSequence=%i)\" \\\n            % (repr(self.prevout), self.scriptSig.hex(),\n               self.nSequence)\n\n\nclass CTxOut:\n    __slots__ = (\"nValue\", \"scriptPubKey\")\n\n    def __init__(self, nValue=0, scriptPubKey=b\"\"):\n        self.nValue = nValue\n        self.scriptPubKey = scriptPubKey\n\n    def deserialize(self, f):\n        self.nValue = struct.unpack(\"<q\", f.read(8))[0]\n        self.scriptPubKey = deser_string(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<q\", self.nValue)\n        r += ser_string(self.scriptPubKey)\n        return r\n\n    def __repr__(self):\n        return \"CTxOut(nValue=%i.%08i scriptPubKey=%s)\" \\\n            % (self.nValue // COIN, self.nValue % COIN,\n               self.scriptPubKey.hex())\n\n\nclass CScriptWitness:\n    __slots__ = (\"stack\",)\n\n    def __init__(self):\n        # stack is a vector of strings\n        self.stack = []\n\n    def __repr__(self):\n        return \"CScriptWitness(%s)\" % \\\n               (\",\".join([x.hex() for x in self.stack]))\n\n    def is_null(self):\n        if self.stack:\n            return False\n        return True\n\n\nclass CTxInWitness:\n    __slots__ = (\"scriptWitness\",)\n\n    def __init__(self):\n        self.scriptWitness = CScriptWitness()\n\n    def deserialize(self, f):\n        self.scriptWitness.stack = deser_string_vector(f)\n\n    def serialize(self):\n        return ser_string_vector(self.scriptWitness.stack)\n\n    def __repr__(self):\n        return repr(self.scriptWitness)\n\n    def is_null(self):\n        return self.scriptWitness.is_null()\n\n\nclass CTxWitness:\n    __slots__ = (\"vtxinwit\",)\n\n    def __init__(self):\n        self.vtxinwit = []\n\n    def deserialize(self, f):\n        for i in range(len(self.vtxinwit)):\n            self.vtxinwit[i].deserialize(f)\n\n    def serialize(self):\n        r = b\"\"\n        # This is different than the usual vector serialization --\n        # we omit the length of the vector, which is required to be\n        # the same length as the transaction's vin vector.\n        for x in self.vtxinwit:\n            r += x.serialize()\n        return r\n\n    def __repr__(self):\n        return \"CTxWitness(%s)\" % \\\n               (';'.join([repr(x) for x in self.vtxinwit]))\n\n    def is_null(self):\n        for x in self.vtxinwit:\n            if not x.is_null():\n                return False\n        return True\n\n\nclass CTransaction:\n    __slots__ = (\"hash\", \"nLockTime\", \"nVersion\", \"sha256\", \"vin\", \"vout\",\n                 \"wit\")\n\n    def __init__(self, tx=None):\n        if tx is None:\n            self.nVersion = 1\n            self.vin = []\n            self.vout = []\n            self.wit = CTxWitness()\n            self.nLockTime = 0\n            self.sha256 = None\n            self.hash = None\n        else:\n            self.nVersion = tx.nVersion\n            self.vin = copy.deepcopy(tx.vin)\n            self.vout = copy.deepcopy(tx.vout)\n            self.nLockTime = tx.nLockTime\n            self.sha256 = tx.sha256\n            self.hash = tx.hash\n            self.wit = copy.deepcopy(tx.wit)\n\n    def deserialize(self, f):\n        self.nVersion = struct.unpack(\"<i\", f.read(4))[0]\n        self.vin = deser_vector(f, CTxIn)\n        flags = 0\n        if len(self.vin) == 0:\n            flags = struct.unpack(\"<B\", f.read(1))[0]\n            # Not sure why flags can't be zero, but this\n            # matches the implementation in Munt-daemon\n            if (flags != 0):\n                self.vin = deser_vector(f, CTxIn)\n                self.vout = deser_vector(f, CTxOut)\n        else:\n            self.vout = deser_vector(f, CTxOut)\n        if flags != 0:\n            self.wit.vtxinwit = [CTxInWitness() for i in range(len(self.vin))]\n            self.wit.deserialize(f)\n        else:\n            self.wit = CTxWitness()\n        self.nLockTime = struct.unpack(\"<I\", f.read(4))[0]\n        self.sha256 = None\n        self.hash = None\n\n    def serialize_without_witness(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nVersion)\n        r += ser_vector(self.vin)\n        r += ser_vector(self.vout)\n        r += struct.pack(\"<I\", self.nLockTime)\n        return r\n\n    # Only serialize with witness when explicitly called for\n    def serialize_with_witness(self):\n        flags = 0\n        if not self.wit.is_null():\n            flags |= 1\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nVersion)\n        if flags:\n            dummy = []\n            r += ser_vector(dummy)\n            r += struct.pack(\"<B\", flags)\n        r += ser_vector(self.vin)\n        r += ser_vector(self.vout)\n        if flags & 1:\n            if (len(self.wit.vtxinwit) != len(self.vin)):\n                # vtxinwit must have the same length as vin\n                self.wit.vtxinwit = self.wit.vtxinwit[:len(self.vin)]\n                for i in range(len(self.wit.vtxinwit), len(self.vin)):\n                    self.wit.vtxinwit.append(CTxInWitness())\n            r += self.wit.serialize()\n        r += struct.pack(\"<I\", self.nLockTime)\n        return r\n\n    # Regular serialization is with witness -- must explicitly\n    # call serialize_without_witness to exclude witness data.\n    def serialize(self):\n        return self.serialize_with_witness()\n\n    # Recalculate the txid (transaction hash without witness)\n    def rehash(self):\n        self.sha256 = None\n        self.calc_sha256()\n        return self.hash\n\n    # We will only cache the serialization without witness in\n    # self.sha256 and self.hash -- those are expected to be the txid.\n    def calc_sha256(self, with_witness=False):\n        if with_witness:\n            # Don't cache the result, just return it\n            return uint256_from_str(hash256(self.serialize_with_witness()))\n\n        if self.sha256 is None:\n            self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))\n        self.hash = encode(hash256(self.serialize_without_witness())[::-1], 'hex_codec').decode('ascii')\n\n    def is_valid(self):\n        self.calc_sha256()\n        for tout in self.vout:\n            if tout.nValue < 0 or tout.nValue > 21000000 * COIN:\n                return False\n        return True\n\n    def __repr__(self):\n        return \"CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)\" \\\n            % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime)\n\ndef get_compact_size(inp):\n    if inp < 0xfd:\n        return inp.to_bytes(1, 'little')\n    elif inp < 0xffff:\n        return b'\\xfd' + inp.to_bytes(2, 'little')\n    elif inp < 0xffffffff:\n        return b'\\xfe' + inp.to_bytes(4, 'little')\n    else:\n        return b'\\xff' + inp.to_bytes(8, 'little')\n\ndef read_compact_size(f):\n    ni = struct.unpack(\"<c\", f.read(1))[0][0]\n    if ni < 253:\n        return ni\n    if ni == 253:  # integer of 2 bytes\n        size = 2\n    elif ni == 254:  # integer of 4 bytes\n        size = 4\n    else:  # integer of 8 bytes\n        size = 8\n    return int.from_bytes(byteint[1:1+size][::-1], 'big')\n\nclass CBlockHeader:\n    __slots__ = (\"hash\", \"hashMerkleRoot\", \"hashPrevBlock\", \"nBits\", \"nNonce\",\n                 \"nTime\", \"nVersion\", \"sha256\", \"nVersionPoW2Witness\", \"nTimePoW2Witness\", \"hashMerkleRootPoW2Witness\", \"witnessHeaderPoW2Sig\", \"witnessUTXODelta\")\n\n    def __init__(self, header=None):\n        if header is None:\n            self.set_null()\n        else:\n            self.nVersion = header.nVersion\n            self.hashPrevBlock = header.hashPrevBlock\n            self.hashMerkleRoot = header.hashMerkleRoot\n            self.nTime = header.nTime\n            self.nBits = header.nBits\n            self.nNonce = header.nNonce\n\n            self.nVersionPoW2Witness = header.nVersionPoW2Witness\n            self.nTimePoW2Witness = header.nTimePoW2Witness\n            self.hashMerkleRootPoW2Witness = header.hashMerkleRootPoW2Witness\n            self.witnessHeaderPoW2Sig = header.witnessHeaderPoW2Sig\n            self.witnessUTXODelta = header.witnessUTXODelta\n\n            self.sha256 = header.sha256\n            self.hash = header.hash\n            self.calc_sha256()\n\n    def set_null(self):\n        self.nVersionPoW2Witness = 0\n        self.nTimePoW2Witness = 0\n        self.hashMerkleRootPoW2Witness = 0\n        self.nVersion = 1\n        self.hashPrevBlock = 0\n        self.hashMerkleRoot = 0\n        self.nTime = 0\n        self.nBits = 0\n        self.nNonce = 0\n        self.witnessHeaderPoW2Sig = 0\n        self.witnessUTXODelta = 0\n        self.sha256 = None\n        self.hash = None\n\n    def deserialize(self, f):\n        self.nVersionPoW2Witness = struct.unpack(\"<i\", f.read(4))[0]\n        self.nTimePoW2Witness = struct.unpack(\"<I\", f.read(4))[0]\n        self.hashMerkleRootPoW2Witness = deser_uint256(f)\n\n        self.nVersion = struct.unpack(\"<i\", f.read(4))[0]\n        self.hashPrevBlock = deser_uint256(f)\n        self.hashMerkleRoot = deser_uint256(f)\n        self.nTime = struct.unpack(\"<I\", f.read(4))[0]\n        self.nBits = struct.unpack(\"<I\", f.read(4))[0]\n        self.nNonce = struct.unpack(\"<I\", f.read(4))[0]\n\n        if self.nVersionPoW2Witness != 0:\n            self.witnessHeaderPoW2Sig = f.read(65)\n            deltaSize = read_compact_size(f)\n            self.witnessUTXODelta = f.read(deltaSize)\n\n        self.sha256 = None\n        self.hash = None\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nVersionPoW2Witness)\n        r += struct.pack(\"<I\", self.nTimePoW2Witness)\n        r += ser_uint256(self.hashMerkleRootPoW2Witness)\n\n        r += struct.pack(\"<i\", self.nVersion)\n        r += ser_uint256(self.hashPrevBlock)\n        r += ser_uint256(self.hashMerkleRoot)\n        r += struct.pack(\"<I\", self.nTime)\n        r += struct.pack(\"<I\", self.nBits)\n        r += struct.pack(\"<I\", self.nNonce)\n\n        if self.nVersionPoW2Witness != 0:\n            r += self.witnessHeaderPoW2Sig\n            deltaSize = get_compact_size(len(self.witnessUTXODelta))\n            r += struct.pack(\"<c\", deltaSize)\n            r += self.witnessUTXODelta\n        return r\n\n    def calc_sha256(self):\n        if self.sha256 is None:\n            r = b\"\"\n            r += struct.pack(\"<i\", self.nVersion)\n            r += ser_uint256(self.hashPrevBlock)\n            r += ser_uint256(self.hashMerkleRoot)\n            r += struct.pack(\"<I\", self.nTime)\n            r += struct.pack(\"<I\", self.nBits)\n            r += struct.pack(\"<I\", self.nNonce)\n\n            if self.nVersionPoW2Witness != 0:\n                r += self.witnessHeaderPoW2Sig\n                deltaSize = get_compact_size(len(self.witnessUTXODelta))\n                r += struct.pack(\"<c\", deltaSize)\n                r += self.witnessUTXODelta\n\n            self.sha256 = uint256_from_str(hash256(r))\n            self.hash = encode(hash256(r)[::-1], 'hex_codec').decode('ascii')\n\n    def rehash(self):\n        self.sha256 = None\n        self.calc_sha256()\n        return self.sha256\n\n    def __repr__(self):\n        return \"CBlockHeader(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x)\" \\\n            % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,\n               time.ctime(self.nTime), self.nBits, self.nNonce)\n\nBLOCK_HEADER_SIZE = len(CBlockHeader().serialize())\nassert_equal(BLOCK_HEADER_SIZE, 120)\n\nclass CBlock(CBlockHeader):\n    __slots__ = (\"vtx\",)\n\n    def __init__(self, header=None):\n        super(CBlock, self).__init__(header)\n        self.vtx = []\n\n    def deserialize(self, f):\n        super(CBlock, self).deserialize(f)\n        self.vtx = deser_vector(f, CTransaction)\n\n    def serialize(self, with_witness=False):\n        r = b\"\"\n        r += super(CBlock, self).serialize()\n        if with_witness:\n            r += ser_vector(self.vtx, \"serialize_with_witness\")\n        else:\n            r += ser_vector(self.vtx, \"serialize_without_witness\")\n        return r\n\n    # Calculate the merkle root given a vector of transaction hashes\n    @classmethod\n    def get_merkle_root(cls, hashes):\n        while len(hashes) > 1:\n            newhashes = []\n            for i in range(0, len(hashes), 2):\n                i2 = min(i+1, len(hashes)-1)\n                newhashes.append(hash256(hashes[i] + hashes[i2]))\n            hashes = newhashes\n        return uint256_from_str(hashes[0])\n\n    def calc_merkle_root(self):\n        hashes = []\n        for tx in self.vtx:\n            tx.calc_sha256()\n            hashes.append(ser_uint256(tx.sha256))\n        return self.get_merkle_root(hashes)\n\n    def calc_witness_merkle_root(self):\n        # For witness root purposes, the hash of the\n        # coinbase, with witness, is defined to be 0...0\n        hashes = [ser_uint256(0)]\n\n        for tx in self.vtx[1:]:\n            # Calculate the hashes with witness data\n            hashes.append(ser_uint256(tx.calc_sha256(True)))\n\n        return self.get_merkle_root(hashes)\n\n    def is_valid(self):\n        self.calc_sha256()\n        target = uint256_from_compact(self.nBits)\n        if self.sha256 > target:\n            return False\n        for tx in self.vtx:\n            if not tx.is_valid():\n                return False\n        if self.calc_merkle_root() != self.hashMerkleRoot:\n            return False\n        return True\n\n    def solve(self):\n        self.rehash()\n        target = uint256_from_compact(self.nBits)\n        while self.sha256 > target:\n            self.nNonce += 1\n            self.rehash()\n\n    def __repr__(self):\n        return \"CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)\" \\\n            % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,\n               time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx))\n\n\nclass PrefilledTransaction:\n    __slots__ = (\"index\", \"tx\")\n\n    def __init__(self, index=0, tx = None):\n        self.index = index\n        self.tx = tx\n\n    def deserialize(self, f):\n        self.index = deser_compact_size(f)\n        self.tx = CTransaction()\n        self.tx.deserialize(f)\n\n    def serialize(self, with_witness=True):\n        r = b\"\"\n        r += ser_compact_size(self.index)\n        if with_witness:\n            r += self.tx.serialize_with_witness()\n        else:\n            r += self.tx.serialize_without_witness()\n        return r\n\n    def serialize_without_witness(self):\n        return self.serialize(with_witness=False)\n\n    def serialize_with_witness(self):\n        return self.serialize(with_witness=True)\n\n    def __repr__(self):\n        return \"PrefilledTransaction(index=%d, tx=%s)\" % (self.index, repr(self.tx))\n\n\n# This is what we send on the wire, in a cmpctblock message.\nclass P2PHeaderAndShortIDs:\n    __slots__ = (\"header\", \"nonce\", \"prefilled_txn\", \"prefilled_txn_length\",\n                 \"shortids\", \"shortids_length\")\n\n    def __init__(self):\n        self.header = CBlockHeader()\n        self.nonce = 0\n        self.shortids_length = 0\n        self.shortids = []\n        self.prefilled_txn_length = 0\n        self.prefilled_txn = []\n\n    def deserialize(self, f):\n        self.header.deserialize(f)\n        self.nonce = struct.unpack(\"<Q\", f.read(8))[0]\n        self.shortids_length = deser_compact_size(f)\n        for i in range(self.shortids_length):\n            # shortids are defined to be 6 bytes in the spec, so append\n            # two zero bytes and read it in as an 8-byte number\n            self.shortids.append(struct.unpack(\"<Q\", f.read(6) + b'\\x00\\x00')[0])\n        self.prefilled_txn = deser_vector(f, PrefilledTransaction)\n        self.prefilled_txn_length = len(self.prefilled_txn)\n\n    # When using version 2 compact blocks, we must serialize with_witness.\n    def serialize(self, with_witness=False):\n        r = b\"\"\n        r += self.header.serialize()\n        r += struct.pack(\"<Q\", self.nonce)\n        r += ser_compact_size(self.shortids_length)\n        for x in self.shortids:\n            # We only want the first 6 bytes\n            r += struct.pack(\"<Q\", x)[0:6]\n        if with_witness:\n            r += ser_vector(self.prefilled_txn, \"serialize_with_witness\")\n        else:\n            r += ser_vector(self.prefilled_txn, \"serialize_without_witness\")\n        return r\n\n    def __repr__(self):\n        return \"P2PHeaderAndShortIDs(header=%s, nonce=%d, shortids_length=%d, shortids=%s, prefilled_txn_length=%d, prefilledtxn=%s\" % (repr(self.header), self.nonce, self.shortids_length, repr(self.shortids), self.prefilled_txn_length, repr(self.prefilled_txn))\n\n\n# P2P version of the above that will use witness serialization (for compact\n# block version 2)\nclass P2PHeaderAndShortWitnessIDs(P2PHeaderAndShortIDs):\n    __slots__ = ()\n    def serialize(self):\n        return super(P2PHeaderAndShortWitnessIDs, self).serialize(with_witness=True)\n\n# Calculate the BIP 152-compact blocks shortid for a given transaction hash\ndef calculate_shortid(k0, k1, tx_hash):\n    expected_shortid = siphash256(k0, k1, tx_hash)\n    expected_shortid &= 0x0000ffffffffffff\n    return expected_shortid\n\n\n# This version gets rid of the array lengths, and reinterprets the differential\n# encoding into indices that can be used for lookup.\nclass HeaderAndShortIDs:\n    __slots__ = (\"header\", \"nonce\", \"prefilled_txn\", \"shortids\", \"use_witness\")\n\n    def __init__(self, p2pheaders_and_shortids = None):\n        self.header = CBlockHeader()\n        self.nonce = 0\n        self.shortids = []\n        self.prefilled_txn = []\n        self.use_witness = False\n\n        if p2pheaders_and_shortids is not None:\n            self.header = p2pheaders_and_shortids.header\n            self.nonce = p2pheaders_and_shortids.nonce\n            self.shortids = p2pheaders_and_shortids.shortids\n            last_index = -1\n            for x in p2pheaders_and_shortids.prefilled_txn:\n                self.prefilled_txn.append(PrefilledTransaction(x.index + last_index + 1, x.tx))\n                last_index = self.prefilled_txn[-1].index\n\n    def to_p2p(self):\n        if self.use_witness:\n            ret = P2PHeaderAndShortWitnessIDs()\n        else:\n            ret = P2PHeaderAndShortIDs()\n        ret.header = self.header\n        ret.nonce = self.nonce\n        ret.shortids_length = len(self.shortids)\n        ret.shortids = self.shortids\n        ret.prefilled_txn_length = len(self.prefilled_txn)\n        ret.prefilled_txn = []\n        last_index = -1\n        for x in self.prefilled_txn:\n            ret.prefilled_txn.append(PrefilledTransaction(x.index - last_index - 1, x.tx))\n            last_index = x.index\n        return ret\n\n    def get_siphash_keys(self):\n        header_nonce = self.header.serialize()\n        header_nonce += struct.pack(\"<Q\", self.nonce)\n        hash_header_nonce_as_str = sha256(header_nonce)\n        key0 = struct.unpack(\"<Q\", hash_header_nonce_as_str[0:8])[0]\n        key1 = struct.unpack(\"<Q\", hash_header_nonce_as_str[8:16])[0]\n        return [ key0, key1 ]\n\n    # Version 2 compact blocks use wtxid in shortids (rather than txid)\n    def initialize_from_block(self, block, nonce=0, prefill_list = [0], use_witness = False):\n        self.header = CBlockHeader(block)\n        self.nonce = nonce\n        self.prefilled_txn = [ PrefilledTransaction(i, block.vtx[i]) for i in prefill_list ]\n        self.shortids = []\n        self.use_witness = use_witness\n        [k0, k1] = self.get_siphash_keys()\n        for i in range(len(block.vtx)):\n            if i not in prefill_list:\n                tx_hash = block.vtx[i].sha256\n                if use_witness:\n                    tx_hash = block.vtx[i].calc_sha256(with_witness=True)\n                self.shortids.append(calculate_shortid(k0, k1, tx_hash))\n\n    def __repr__(self):\n        return \"HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s\" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn))\n\n\nclass BlockTransactionsRequest:\n    __slots__ = (\"blockhash\", \"indexes\")\n\n    def __init__(self, blockhash=0, indexes = None):\n        self.blockhash = blockhash\n        self.indexes = indexes if indexes is not None else []\n\n    def deserialize(self, f):\n        self.blockhash = deser_uint256(f)\n        indexes_length = deser_compact_size(f)\n        for i in range(indexes_length):\n            self.indexes.append(deser_compact_size(f))\n\n    def serialize(self):\n        r = b\"\"\n        r += ser_uint256(self.blockhash)\n        r += ser_compact_size(len(self.indexes))\n        for x in self.indexes:\n            r += ser_compact_size(x)\n        return r\n\n    # helper to set the differentially encoded indexes from absolute ones\n    def from_absolute(self, absolute_indexes):\n        self.indexes = []\n        last_index = -1\n        for x in absolute_indexes:\n            self.indexes.append(x-last_index-1)\n            last_index = x\n\n    def to_absolute(self):\n        absolute_indexes = []\n        last_index = -1\n        for x in self.indexes:\n            absolute_indexes.append(x+last_index+1)\n            last_index = absolute_indexes[-1]\n        return absolute_indexes\n\n    def __repr__(self):\n        return \"BlockTransactionsRequest(hash=%064x indexes=%s)\" % (self.blockhash, repr(self.indexes))\n\n\nclass BlockTransactions:\n    __slots__ = (\"blockhash\", \"transactions\")\n\n    def __init__(self, blockhash=0, transactions = None):\n        self.blockhash = blockhash\n        self.transactions = transactions if transactions is not None else []\n\n    def deserialize(self, f):\n        self.blockhash = deser_uint256(f)\n        self.transactions = deser_vector(f, CTransaction)\n\n    def serialize(self, with_witness=True):\n        r = b\"\"\n        r += ser_uint256(self.blockhash)\n        if with_witness:\n            r += ser_vector(self.transactions, \"serialize_with_witness\")\n        else:\n            r += ser_vector(self.transactions, \"serialize_without_witness\")\n        return r\n\n    def __repr__(self):\n        return \"BlockTransactions(hash=%064x transactions=%s)\" % (self.blockhash, repr(self.transactions))\n\n\nclass CPartialMerkleTree:\n    __slots__ = (\"nTransactions\", \"vBits\", \"vHash\")\n\n    def __init__(self):\n        self.nTransactions = 0\n        self.vHash = []\n        self.vBits = []\n\n    def deserialize(self, f):\n        self.nTransactions = struct.unpack(\"<i\", f.read(4))[0]\n        self.vHash = deser_uint256_vector(f)\n        vBytes = deser_string(f)\n        self.vBits = []\n        for i in range(len(vBytes) * 8):\n            self.vBits.append(vBytes[i//8] & (1 << (i % 8)) != 0)\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nTransactions)\n        r += ser_uint256_vector(self.vHash)\n        vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8))\n        for i in range(len(self.vBits)):\n            vBytesArray[i // 8] |= self.vBits[i] << (i % 8)\n        r += ser_string(bytes(vBytesArray))\n        return r\n\n    def __repr__(self):\n        return \"CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)\" % (self.nTransactions, repr(self.vHash), repr(self.vBits))\n\n\nclass CMerkleBlock:\n    __slots__ = (\"header\", \"txn\")\n\n    def __init__(self):\n        self.header = CBlockHeader()\n        self.txn = CPartialMerkleTree()\n\n    def deserialize(self, f):\n        self.header.deserialize(f)\n        self.txn.deserialize(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.header.serialize()\n        r += self.txn.serialize()\n        return r\n\n    def __repr__(self):\n        return \"CMerkleBlock(header=%s, txn=%s)\" % (repr(self.header), repr(self.txn))\n\n\n# Objects that correspond to messages on the wire\nclass msg_version:\n    __slots__ = (\"addrFrom\", \"addrTo\", \"nNonce\", \"nRelay\", \"nServices\",\n                 \"nStartingHeight\", \"nTime\", \"nVersion\", \"strSubVer\")\n    command = b\"version\"\n\n    def __init__(self):\n        self.nVersion = MY_VERSION\n        self.nServices = NODE_NETWORK | NODE_WITNESS\n        self.nTime = int(time.time())\n        self.addrTo = CAddress()\n        self.addrFrom = CAddress()\n        self.nNonce = random.getrandbits(64)\n        self.strSubVer = MY_SUBVERSION\n        self.nStartingHeight = -1\n        self.nRelay = MY_RELAY\n\n    def deserialize(self, f):\n        self.nVersion = struct.unpack(\"<i\", f.read(4))[0]\n        self.nServices = struct.unpack(\"<Q\", f.read(8))[0]\n        self.nTime = struct.unpack(\"<q\", f.read(8))[0]\n        self.addrTo = CAddress()\n        self.addrTo.deserialize(f, False)\n\n        self.addrFrom = CAddress()\n        self.addrFrom.deserialize(f, False)\n        self.nNonce = struct.unpack(\"<Q\", f.read(8))[0]\n        self.strSubVer = deser_string(f)\n\n        self.nStartingHeight = struct.unpack(\"<i\", f.read(4))[0]\n\n        if self.nVersion >= 70001:\n            # Relay field is optional for version 70001 onwards\n            try:\n                self.nRelay = struct.unpack(\"<b\", f.read(1))[0]\n            except:\n                self.nRelay = 0\n        else:\n            self.nRelay = 0\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<i\", self.nVersion)\n        r += struct.pack(\"<Q\", self.nServices)\n        r += struct.pack(\"<q\", self.nTime)\n        r += self.addrTo.serialize(False)\n        r += self.addrFrom.serialize(False)\n        r += struct.pack(\"<Q\", self.nNonce)\n        r += ser_string(self.strSubVer)\n        r += struct.pack(\"<i\", self.nStartingHeight)\n        r += struct.pack(\"<b\", self.nRelay)\n        return r\n\n    def __repr__(self):\n        return 'msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i nRelay=%i)' \\\n            % (self.nVersion, self.nServices, time.ctime(self.nTime),\n               repr(self.addrTo), repr(self.addrFrom), self.nNonce,\n               self.strSubVer, self.nStartingHeight, self.nRelay)\n\n\nclass msg_verack:\n    __slots__ = ()\n    command = b\"verack\"\n\n    def __init__(self):\n        pass\n\n    def deserialize(self, f):\n        pass\n\n    def serialize(self):\n        return b\"\"\n\n    def __repr__(self):\n        return \"msg_verack()\"\n\n\nclass msg_addr:\n    __slots__ = (\"addrs\",)\n    command = b\"addr\"\n\n    def __init__(self):\n        self.addrs = []\n\n    def deserialize(self, f):\n        self.addrs = deser_vector(f, CAddress)\n\n    def serialize(self):\n        return ser_vector(self.addrs)\n\n    def __repr__(self):\n        return \"msg_addr(addrs=%s)\" % (repr(self.addrs))\n\n\nclass msg_inv:\n    __slots__ = (\"inv\",)\n    command = b\"inv\"\n\n    def __init__(self, inv=None):\n        if inv is None:\n            self.inv = []\n        else:\n            self.inv = inv\n\n    def deserialize(self, f):\n        self.inv = deser_vector(f, CInv)\n\n    def serialize(self):\n        return ser_vector(self.inv)\n\n    def __repr__(self):\n        return \"msg_inv(inv=%s)\" % (repr(self.inv))\n\n\nclass msg_getdata:\n    __slots__ = (\"inv\",)\n    command = b\"getdata\"\n\n    def __init__(self, inv=None):\n        self.inv = inv if inv is not None else []\n\n    def deserialize(self, f):\n        self.inv = deser_vector(f, CInv)\n\n    def serialize(self):\n        return ser_vector(self.inv)\n\n    def __repr__(self):\n        return \"msg_getdata(inv=%s)\" % (repr(self.inv))\n\n\nclass msg_getblocks:\n    __slots__ = (\"locator\", \"hashstop\")\n    command = b\"getblocks\"\n\n    def __init__(self):\n        self.locator = CBlockLocator()\n        self.hashstop = 0\n\n    def deserialize(self, f):\n        self.locator = CBlockLocator()\n        self.locator.deserialize(f)\n        self.hashstop = deser_uint256(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.locator.serialize()\n        r += ser_uint256(self.hashstop)\n        return r\n\n    def __repr__(self):\n        return \"msg_getblocks(locator=%s hashstop=%064x)\" \\\n            % (repr(self.locator), self.hashstop)\n\n\nclass msg_tx:\n    __slots__ = (\"tx\",)\n    command = b\"tx\"\n\n    def __init__(self, tx=CTransaction()):\n        self.tx = tx\n\n    def deserialize(self, f):\n        self.tx.deserialize(f)\n\n    def serialize(self):\n        return self.tx.serialize_without_witness()\n\n    def __repr__(self):\n        return \"msg_tx(tx=%s)\" % (repr(self.tx))\n\n\nclass msg_witness_tx(msg_tx):\n    __slots__ = ()\n\n    def serialize(self):\n        return self.tx.serialize_with_witness()\n\n\nclass msg_block:\n    __slots__ = (\"block\",)\n    command = b\"block\"\n\n    def __init__(self, block=None):\n        if block is None:\n            self.block = CBlock()\n        else:\n            self.block = block\n\n    def deserialize(self, f):\n        self.block.deserialize(f)\n\n    def serialize(self):\n        return self.block.serialize(with_witness=False)\n\n    def __repr__(self):\n        return \"msg_block(block=%s)\" % (repr(self.block))\n\n\n# for cases where a user needs tighter control over what is sent over the wire\n# note that the user must supply the name of the command, and the data\nclass msg_generic:\n    __slots__ = (\"command\", \"data\")\n\n    def __init__(self, command, data=None):\n        self.command = command\n        self.data = data\n\n    def serialize(self):\n        return self.data\n\n    def __repr__(self):\n        return \"msg_generic()\"\n\n\nclass msg_witness_block(msg_block):\n    __slots__ = ()\n    def serialize(self):\n        r = self.block.serialize(with_witness=True)\n        return r\n\n\nclass msg_getaddr:\n    __slots__ = ()\n    command = b\"getaddr\"\n\n    def __init__(self):\n        pass\n\n    def deserialize(self, f):\n        pass\n\n    def serialize(self):\n        return b\"\"\n\n    def __repr__(self):\n        return \"msg_getaddr()\"\n\n\nclass msg_ping:\n    __slots__ = (\"nonce\",)\n    command = b\"ping\"\n\n    def __init__(self, nonce=0):\n        self.nonce = nonce\n\n    def deserialize(self, f):\n        self.nonce = struct.unpack(\"<Q\", f.read(8))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<Q\", self.nonce)\n        return r\n\n    def __repr__(self):\n        return \"msg_ping(nonce=%08x)\" % self.nonce\n\n\nclass msg_pong:\n    __slots__ = (\"nonce\",)\n    command = b\"pong\"\n\n    def __init__(self, nonce=0):\n        self.nonce = nonce\n\n    def deserialize(self, f):\n        self.nonce = struct.unpack(\"<Q\", f.read(8))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<Q\", self.nonce)\n        return r\n\n    def __repr__(self):\n        return \"msg_pong(nonce=%08x)\" % self.nonce\n\n\nclass msg_mempool:\n    __slots__ = ()\n    command = b\"mempool\"\n\n    def __init__(self):\n        pass\n\n    def deserialize(self, f):\n        pass\n\n    def serialize(self):\n        return b\"\"\n\n    def __repr__(self):\n        return \"msg_mempool()\"\n\n\nclass msg_notfound:\n    __slots__ = (\"vec\", )\n    command = b\"notfound\"\n\n    def __init__(self, vec=None):\n        self.vec = vec or []\n\n    def deserialize(self, f):\n        self.vec = deser_vector(f, CInv)\n\n    def serialize(self):\n        return ser_vector(self.vec)\n\n    def __repr__(self):\n        return \"msg_notfound(vec=%s)\" % (repr(self.vec))\n\n\nclass msg_sendheaders:\n    __slots__ = ()\n    command = b\"sendheaders\"\n\n    def __init__(self):\n        pass\n\n    def deserialize(self, f):\n        pass\n\n    def serialize(self):\n        return b\"\"\n\n    def __repr__(self):\n        return \"msg_sendheaders()\"\n\n\n# getheaders message has\n# number of entries\n# vector of hashes\n# hash_stop (hash of last desired block header, 0 to get as many as possible)\nclass msg_getheaders:\n    __slots__ = (\"hashstop\", \"locator\",)\n    command = b\"getheaders\"\n\n    def __init__(self):\n        self.locator = CBlockLocator()\n        self.hashstop = 0\n\n    def deserialize(self, f):\n        self.locator = CBlockLocator()\n        self.locator.deserialize(f)\n        self.hashstop = deser_uint256(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.locator.serialize()\n        r += ser_uint256(self.hashstop)\n        return r\n\n    def __repr__(self):\n        return \"msg_getheaders(locator=%s, stop=%064x)\" \\\n            % (repr(self.locator), self.hashstop)\n\n\n# headers message has\n# <count> <vector of block headers>\nclass msg_headers:\n    __slots__ = (\"headers\",)\n    command = b\"headers\"\n\n    def __init__(self, headers=None):\n        self.headers = headers if headers is not None else []\n\n    def deserialize(self, f):\n        # comment in Munt-daemon indicates these should be deserialized as blocks\n        blocks = deser_vector(f, CBlock)\n        for x in blocks:\n            self.headers.append(CBlockHeader(x))\n\n    def serialize(self):\n        blocks = [CBlock(x) for x in self.headers]\n        return ser_vector(blocks)\n\n    def __repr__(self):\n        return \"msg_headers(headers=%s)\" % repr(self.headers)\n\n\nclass msg_reject:\n    __slots__ = (\"code\", \"data\", \"message\", \"reason\")\n    command = b\"reject\"\n    REJECT_MALFORMED = 1\n\n    def __init__(self):\n        self.message = b\"\"\n        self.code = 0\n        self.reason = b\"\"\n        self.data = 0\n\n    def deserialize(self, f):\n        self.message = deser_string(f)\n        self.code = struct.unpack(\"<B\", f.read(1))[0]\n        self.reason = deser_string(f)\n        if (self.code != self.REJECT_MALFORMED and\n                (self.message == b\"block\" or self.message == b\"tx\")):\n            self.data = deser_uint256(f)\n\n    def serialize(self):\n        r = ser_string(self.message)\n        r += struct.pack(\"<B\", self.code)\n        r += ser_string(self.reason)\n        if (self.code != self.REJECT_MALFORMED and\n                (self.message == b\"block\" or self.message == b\"tx\")):\n            r += ser_uint256(self.data)\n        return r\n\n    def __repr__(self):\n        return \"msg_reject: %s %d %s [%064x]\" \\\n            % (self.message, self.code, self.reason, self.data)\n\n\nclass msg_feefilter:\n    __slots__ = (\"feerate\",)\n    command = b\"feefilter\"\n\n    def __init__(self, feerate=0):\n        self.feerate = feerate\n\n    def deserialize(self, f):\n        self.feerate = struct.unpack(\"<Q\", f.read(8))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<Q\", self.feerate)\n        return r\n\n    def __repr__(self):\n        return \"msg_feefilter(feerate=%08x)\" % self.feerate\n\n\nclass msg_sendcmpct:\n    __slots__ = (\"announce\", \"version\")\n    command = b\"sendcmpct\"\n\n    def __init__(self):\n        self.announce = False\n        self.version = 1\n\n    def deserialize(self, f):\n        self.announce = struct.unpack(\"<?\", f.read(1))[0]\n        self.version = struct.unpack(\"<Q\", f.read(8))[0]\n\n    def serialize(self):\n        r = b\"\"\n        r += struct.pack(\"<?\", self.announce)\n        r += struct.pack(\"<Q\", self.version)\n        return r\n\n    def __repr__(self):\n        return \"msg_sendcmpct(announce=%s, version=%lu)\" % (self.announce, self.version)\n\n\nclass msg_cmpctblock:\n    __slots__ = (\"header_and_shortids\",)\n    command = b\"cmpctblock\"\n\n    def __init__(self, header_and_shortids = None):\n        self.header_and_shortids = header_and_shortids\n\n    def deserialize(self, f):\n        self.header_and_shortids = P2PHeaderAndShortIDs()\n        self.header_and_shortids.deserialize(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.header_and_shortids.serialize()\n        return r\n\n    def __repr__(self):\n        return \"msg_cmpctblock(HeaderAndShortIDs=%s)\" % repr(self.header_and_shortids)\n\n\nclass msg_getblocktxn:\n    __slots__ = (\"block_txn_request\",)\n    command = b\"getblocktxn\"\n\n    def __init__(self):\n        self.block_txn_request = None\n\n    def deserialize(self, f):\n        self.block_txn_request = BlockTransactionsRequest()\n        self.block_txn_request.deserialize(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.block_txn_request.serialize()\n        return r\n\n    def __repr__(self):\n        return \"msg_getblocktxn(block_txn_request=%s)\" % (repr(self.block_txn_request))\n\n\nclass msg_blocktxn:\n    __slots__ = (\"block_transactions\",)\n    command = b\"blocktxn\"\n\n    def __init__(self):\n        self.block_transactions = BlockTransactions()\n\n    def deserialize(self, f):\n        self.block_transactions.deserialize(f)\n\n    def serialize(self):\n        r = b\"\"\n        r += self.block_transactions.serialize(with_witness=False)\n        return r\n\n    def __repr__(self):\n        return \"msg_blocktxn(block_transactions=%s)\" % (repr(self.block_transactions))\n\n\nclass msg_witness_blocktxn(msg_blocktxn):\n    __slots__ = ()\n\n    def serialize(self):\n        r = b\"\"\n        r += self.block_transactions.serialize(with_witness=True)\n        return r\n"
  },
  {
    "path": "test/functional/test_framework/mininode.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2010 ArtForz -- public domain half-a-node\n# Copyright (c) 2012 Jeff Garzik\n# Copyright (c) 2010-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Munt P2P network half-a-node.\n\nThis python code was modified from ArtForz' public domain half-a-node, as\nfound in the mini-node branch of http://github.com/jgarzik/pynode.\n\nP2PConnection: A low-level connection object to a node's P2P interface\nP2PInterface: A high-level interface object for communicating to a node over P2P\nP2PDataStore: A p2p interface class that keeps a store of transactions and blocks\n              and can respond correctly to getdata and getheaders messages\"\"\"\nimport asyncio\nfrom collections import defaultdict\nfrom io import BytesIO\nimport logging\nimport struct\nimport sys\nimport threading\n\nfrom test_framework.messages import (\n    CBlockHeader,\n    MIN_VERSION_SUPPORTED,\n    msg_addr,\n    msg_block,\n    MSG_BLOCK,\n    msg_blocktxn,\n    msg_cmpctblock,\n    msg_feefilter,\n    msg_getaddr,\n    msg_getblocks,\n    msg_getblocktxn,\n    msg_getdata,\n    msg_getheaders,\n    msg_headers,\n    msg_inv,\n    msg_mempool,\n    msg_notfound,\n    msg_ping,\n    msg_pong,\n    msg_reject,\n    msg_sendcmpct,\n    msg_sendheaders,\n    msg_tx,\n    MSG_TX,\n    MSG_TYPE_MASK,\n    msg_verack,\n    msg_version,\n    NODE_NETWORK,\n    NODE_WITNESS,\n    sha256,\n)\nfrom test_framework.util import wait_until\n\nlogger = logging.getLogger(\"TestFramework.mininode\")\n\nMESSAGEMAP = {\n    b\"addr\": msg_addr,\n    b\"block\": msg_block,\n    b\"blocktxn\": msg_blocktxn,\n    b\"cmpctblock\": msg_cmpctblock,\n    b\"feefilter\": msg_feefilter,\n    b\"getaddr\": msg_getaddr,\n    b\"getblocks\": msg_getblocks,\n    b\"getblocktxn\": msg_getblocktxn,\n    b\"getdata\": msg_getdata,\n    b\"getheaders\": msg_getheaders,\n    b\"headers\": msg_headers,\n    b\"inv\": msg_inv,\n    b\"mempool\": msg_mempool,\n    b\"notfound\": msg_notfound,\n    b\"ping\": msg_ping,\n    b\"pong\": msg_pong,\n    b\"reject\": msg_reject,\n    b\"sendcmpct\": msg_sendcmpct,\n    b\"sendheaders\": msg_sendheaders,\n    b\"tx\": msg_tx,\n    b\"verack\": msg_verack,\n    b\"version\": msg_version,\n}\n\nMAGIC_BYTES = {\n    \"mainnet\":  b\"\\xfc\\xfe\\xf7\\xe0\",  # mainnet\n    ###fixme:\n    \"testnet3\": b\"\\x3c\\x7a\\x79\\x43\",  # testnet3\n    \"regtestlegacy\":  b\"\\xfc\\xfe\\xf7\\xff\",  # regtestlegacy\n}\n\n\nclass P2PConnection(asyncio.Protocol):\n    \"\"\"A low-level connection object to a node's P2P interface.\n\n    This class is responsible for:\n\n    - opening and closing the TCP connection to the node\n    - reading bytes from and writing bytes to the socket\n    - deserializing and serializing the P2P message header\n    - logging messages as they are sent and received\n\n    This class contains no logic for handing the P2P message payloads. It must be\n    sub-classed and the on_message() callback overridden.\"\"\"\n\n    def __init__(self):\n        # The underlying transport of the connection.\n        # Should only call methods on this from the NetworkThread, c.f. call_soon_threadsafe\n        self._transport = None\n\n    @property\n    def is_connected(self):\n        return self._transport is not None\n\n    def peer_connect(self, dstaddr, dstport, net=\"regtestlegacy\"):\n        assert not self.is_connected\n        self.dstaddr = dstaddr\n        self.dstport = dstport\n        # The initial message to send after the connection was made:\n        self.on_connection_send_msg = None\n        self.recvbuf = b\"\"\n        self.magic_bytes = MAGIC_BYTES[net]\n        logger.debug('Connecting to Munt Node: %s:%d' % (self.dstaddr, self.dstport))\n\n        loop = NetworkThread.network_event_loop\n        conn_gen_unsafe = loop.create_connection(lambda: self, host=self.dstaddr, port=self.dstport)\n        conn_gen = lambda: loop.call_soon_threadsafe(loop.create_task, conn_gen_unsafe)\n        return conn_gen\n\n    def peer_disconnect(self):\n        # Connection could have already been closed by other end.\n        NetworkThread.network_event_loop.call_soon_threadsafe(lambda: self._transport and self._transport.abort())\n\n    # Connection and disconnection methods\n\n    def connection_made(self, transport):\n        \"\"\"asyncio callback when a connection is opened.\"\"\"\n        assert not self._transport\n        logger.debug(\"Connected & Listening: %s:%d\" % (self.dstaddr, self.dstport))\n        self._transport = transport\n        if self.on_connection_send_msg:\n            self.send_message(self.on_connection_send_msg)\n            self.on_connection_send_msg = None  # Never used again\n        self.on_open()\n\n    def connection_lost(self, exc):\n        \"\"\"asyncio callback when a connection is closed.\"\"\"\n        if exc:\n            logger.warning(\"Connection lost to {}:{} due to {}\".format(self.dstaddr, self.dstport, exc))\n        else:\n            logger.debug(\"Closed connection to: %s:%d\" % (self.dstaddr, self.dstport))\n        self._transport = None\n        self.recvbuf = b\"\"\n        self.on_close()\n\n    # Socket read methods\n\n    def data_received(self, t):\n        \"\"\"asyncio callback when data is read from the socket.\"\"\"\n        if len(t) > 0:\n            self.recvbuf += t\n            self._on_data()\n\n    def _on_data(self):\n        \"\"\"Try to read P2P messages from the recv buffer.\n\n        This method reads data from the buffer in a loop. It deserializes,\n        parses and verifies the P2P header, then passes the P2P payload to\n        the on_message callback for processing.\"\"\"\n        try:\n            while True:\n                if len(self.recvbuf) < 4:\n                    return\n                if self.recvbuf[:4] != self.magic_bytes:\n                    raise ValueError(\"magic bytes mismatch: {} != {}\".format(repr(self.magic_bytes), repr(self.recvbuf)))\n                if len(self.recvbuf) < 4 + 12 + 4 + 4:\n                    return\n                command = self.recvbuf[4:4+12].split(b\"\\x00\", 1)[0]\n                msglen = struct.unpack(\"<i\", self.recvbuf[4+12:4+12+4])[0]\n                checksum = self.recvbuf[4+12+4:4+12+4+4]\n                if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:\n                    return\n                msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]\n                th = sha256(msg)\n                h = sha256(th)\n                if checksum != h[:4]:\n                    raise ValueError(\"got bad checksum \" + repr(self.recvbuf))\n                self.recvbuf = self.recvbuf[4+12+4+4+msglen:]\n                if command not in MESSAGEMAP:\n                    raise ValueError(\"Received unknown command from %s:%d: '%s' %s\" % (self.dstaddr, self.dstport, command, repr(msg)))\n                f = BytesIO(msg)\n                t = MESSAGEMAP[command]()\n                t.deserialize(f)\n                self._log_message(\"receive\", t)\n                self.on_message(t)\n        except Exception as e:\n            logger.exception('Error reading message:', repr(e))\n            raise\n\n    def on_message(self, message):\n        \"\"\"Callback for processing a P2P payload. Must be overridden by derived class.\"\"\"\n        raise NotImplementedError\n\n    # Socket write methods\n\n    def send_message(self, message):\n        \"\"\"Send a P2P message over the socket.\n\n        This method takes a P2P payload, builds the P2P header and adds\n        the message to the send buffer to be sent over the socket.\"\"\"\n        tmsg = self.build_message(message)\n        self._log_message(\"send\", message)\n        return self.send_raw_message(tmsg)\n\n    def send_raw_message(self, raw_message_bytes):\n        if not self.is_connected:\n            raise IOError('Not connected')\n\n        def maybe_write():\n            if not self._transport:\n                return\n            if self._transport.is_closing():\n                return\n            self._transport.write(raw_message_bytes)\n        NetworkThread.network_event_loop.call_soon_threadsafe(maybe_write)\n\n    # Class utility methods\n\n    def build_message(self, message):\n        \"\"\"Build a serialized P2P message\"\"\"\n        command = message.command\n        data = message.serialize()\n        tmsg = self.magic_bytes\n        tmsg += command\n        tmsg += b\"\\x00\" * (12 - len(command))\n        tmsg += struct.pack(\"<I\", len(data))\n        th = sha256(data)\n        h = sha256(th)\n        tmsg += h[:4]\n        tmsg += data\n        return tmsg\n\n    def _log_message(self, direction, msg):\n        \"\"\"Logs a message being sent or received over the connection.\"\"\"\n        if direction == \"send\":\n            log_message = \"Send message to \"\n        elif direction == \"receive\":\n            log_message = \"Received message from \"\n        log_message += \"%s:%d: %s\" % (self.dstaddr, self.dstport, repr(msg)[:500])\n        if len(log_message) > 500:\n            log_message += \"... (msg truncated)\"\n        logger.debug(log_message)\n\n\nclass P2PInterface(P2PConnection):\n    \"\"\"A high-level P2P interface class for communicating with a Munt node.\n\n    This class provides high-level callbacks for processing P2P message\n    payloads, as well as convenience methods for interacting with the\n    node over P2P.\n\n    Individual testcases should subclass this and override the on_* methods\n    if they want to alter message handling behaviour.\"\"\"\n    def __init__(self):\n        super().__init__()\n\n        # Track number of messages of each type received and the most recent\n        # message of each type\n        self.message_count = defaultdict(int)\n        self.last_message = {}\n\n        # A count of the number of ping messages we've sent to the node\n        self.ping_counter = 1\n\n        # The network services received from the peer\n        self.nServices = 0\n\n    def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs):\n        create_conn = super().peer_connect(*args, **kwargs)\n\n        if send_version:\n            # Send a version msg\n            vt = msg_version()\n            vt.nServices = services\n            vt.addrTo.ip = self.dstaddr\n            vt.addrTo.port = self.dstport\n            vt.addrFrom.ip = \"0.0.0.0\"\n            vt.addrFrom.port = 0\n            self.on_connection_send_msg = vt  # Will be sent soon after connection_made\n\n        return create_conn\n\n    # Message receiving methods\n\n    def on_message(self, message):\n        \"\"\"Receive message and dispatch message to appropriate callback.\n\n        We keep a count of how many of each message type has been received\n        and the most recent message of each type.\"\"\"\n        with mininode_lock:\n            try:\n                command = message.command.decode('ascii')\n                self.message_count[command] += 1\n                self.last_message[command] = message\n                getattr(self, 'on_' + command)(message)\n            except:\n                print(\"ERROR delivering %s (%s)\" % (repr(message), sys.exc_info()[0]))\n                raise\n\n    # Callback methods. Can be overridden by subclasses in individual test\n    # cases to provide custom message handling behaviour.\n\n    def on_open(self):\n        pass\n\n    def on_close(self):\n        pass\n\n    def on_addr(self, message): pass\n    def on_block(self, message): pass\n    def on_blocktxn(self, message): pass\n    def on_cmpctblock(self, message): pass\n    def on_feefilter(self, message): pass\n    def on_getaddr(self, message): pass\n    def on_getblocks(self, message): pass\n    def on_getblocktxn(self, message): pass\n    def on_getdata(self, message): pass\n    def on_getheaders(self, message): pass\n    def on_headers(self, message): pass\n    def on_mempool(self, message): pass\n    def on_notfound(self, message): pass\n    def on_pong(self, message): pass\n    def on_reject(self, message): pass\n    def on_sendcmpct(self, message): pass\n    def on_sendheaders(self, message): pass\n    def on_tx(self, message): pass\n\n    def on_inv(self, message):\n        want = msg_getdata()\n        for i in message.inv:\n            if i.type != 0:\n                want.inv.append(i)\n        if len(want.inv):\n            self.send_message(want)\n\n    def on_ping(self, message):\n        self.send_message(msg_pong(message.nonce))\n\n    def on_verack(self, message):\n        pass\n\n    def on_version(self, message):\n        assert message.nVersion >= MIN_VERSION_SUPPORTED, \"Version {} received. Test framework only supports versions greater than {}\".format(message.nVersion, MIN_VERSION_SUPPORTED)\n        self.send_message(msg_verack())\n        self.nServices = message.nServices\n\n    # Connection helper methods\n\n    def wait_for_disconnect(self, timeout=60):\n        test_function = lambda: not self.is_connected\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    # Message receiving helper methods\n\n    def wait_for_block(self, blockhash, timeout=60):\n        test_function = lambda: self.last_message.get(\"block\") and self.last_message[\"block\"].block.rehash() == blockhash\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_header(self, blockhash, timeout=60):\n        def test_function():\n            last_headers = self.last_message.get('headers')\n            if not last_headers:\n                return False\n            return last_headers.headers[0].rehash() == blockhash\n\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_getdata(self, timeout=60):\n        \"\"\"Waits for a getdata message.\n\n        Receiving any getdata message will satisfy the predicate. the last_message[\"getdata\"]\n        value must be explicitly cleared before calling this method, or this will return\n        immediately with success. TODO: change this method to take a hash value and only\n        return true if the correct block/tx has been requested.\"\"\"\n        test_function = lambda: self.last_message.get(\"getdata\")\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_getheaders(self, timeout=60):\n        \"\"\"Waits for a getheaders message.\n\n        Receiving any getheaders message will satisfy the predicate. the last_message[\"getheaders\"]\n        value must be explicitly cleared before calling this method, or this will return\n        immediately with success. TODO: change this method to take a hash value and only\n        return true if the correct block header has been requested.\"\"\"\n        test_function = lambda: self.last_message.get(\"getheaders\")\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_inv(self, expected_inv, timeout=60):\n        \"\"\"Waits for an INV message and checks that the first inv object in the message was as expected.\"\"\"\n        if len(expected_inv) > 1:\n            raise NotImplementedError(\"wait_for_inv() will only verify the first inv object\")\n        test_function = lambda: self.last_message.get(\"inv\") and \\\n                                self.last_message[\"inv\"].inv[0].type == expected_inv[0].type and \\\n                                self.last_message[\"inv\"].inv[0].hash == expected_inv[0].hash\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    def wait_for_verack(self, timeout=60):\n        test_function = lambda: self.message_count[\"verack\"]\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n\n    # Message sending helper functions\n\n    def send_and_ping(self, message, timeout=60):\n        self.send_message(message)\n        self.sync_with_ping(timeout=timeout)\n\n    # Sync up with the node\n    def sync_with_ping(self, timeout=60):\n        self.send_message(msg_ping(nonce=self.ping_counter))\n        test_function = lambda: self.last_message.get(\"pong\") and self.last_message[\"pong\"].nonce == self.ping_counter\n        wait_until(test_function, timeout=timeout, lock=mininode_lock)\n        self.ping_counter += 1\n\n\n# One lock for synchronizing all data access between the network event loop (see\n# NetworkThread below) and the thread running the test logic.  For simplicity,\n# P2PConnection acquires this lock whenever delivering a message to a P2PInterface.\n# This lock should be acquired in the thread running the test logic to synchronize\n# access to any data shared with the P2PInterface or P2PConnection.\nmininode_lock = threading.RLock()\n\n\nclass NetworkThread(threading.Thread):\n    network_event_loop = None\n\n    def __init__(self):\n        super().__init__(name=\"NetworkThread\")\n        # There is only one event loop and no more than one thread must be created\n        assert not self.network_event_loop\n\n        NetworkThread.network_event_loop = asyncio.new_event_loop()\n\n    def run(self):\n        \"\"\"Start the network thread.\"\"\"\n        self.network_event_loop.run_forever()\n\n    def close(self, timeout=10):\n        \"\"\"Close the connections and network event loop.\"\"\"\n        self.network_event_loop.call_soon_threadsafe(self.network_event_loop.stop)\n        wait_until(lambda: not self.network_event_loop.is_running(), timeout=timeout)\n        self.network_event_loop.close()\n        self.join(timeout)\n\n\nclass P2PDataStore(P2PInterface):\n    \"\"\"A P2P data store class.\n\n    Keeps a block and transaction store and responds correctly to getdata and getheaders requests.\"\"\"\n\n    def __init__(self):\n        super().__init__()\n        # store of blocks. key is block hash, value is a CBlock object\n        self.block_store = {}\n        self.last_block_hash = ''\n        # store of txs. key is txid, value is a CTransaction object\n        self.tx_store = {}\n        self.getdata_requests = []\n\n    def on_getdata(self, message):\n        \"\"\"Check for the tx/block in our stores and if found, reply with an inv message.\"\"\"\n        for inv in message.inv:\n            self.getdata_requests.append(inv.hash)\n            if (inv.type & MSG_TYPE_MASK) == MSG_TX and inv.hash in self.tx_store.keys():\n                self.send_message(msg_tx(self.tx_store[inv.hash]))\n            elif (inv.type & MSG_TYPE_MASK) == MSG_BLOCK and inv.hash in self.block_store.keys():\n                self.send_message(msg_block(self.block_store[inv.hash]))\n            else:\n                logger.debug('getdata message type {} received.'.format(hex(inv.type)))\n\n    def on_getheaders(self, message):\n        \"\"\"Search back through our block store for the locator, and reply with a headers message if found.\"\"\"\n\n        locator, hash_stop = message.locator, message.hashstop\n\n        # Assume that the most recent block added is the tip\n        if not self.block_store:\n            return\n\n        headers_list = [self.block_store[self.last_block_hash]]\n        maxheaders = 2000\n        while headers_list[-1].sha256 not in locator.vHave:\n            # Walk back through the block store, adding headers to headers_list\n            # as we go.\n            prev_block_hash = headers_list[-1].hashPrevBlock\n            if prev_block_hash in self.block_store:\n                prev_block_header = CBlockHeader(self.block_store[prev_block_hash])\n                headers_list.append(prev_block_header)\n                if prev_block_header.sha256 == hash_stop:\n                    # if this is the hashstop header, stop here\n                    break\n            else:\n                logger.debug('block hash {} not found in block store'.format(hex(prev_block_hash)))\n                break\n\n        # Truncate the list if there are too many headers\n        headers_list = headers_list[:-maxheaders - 1:-1]\n        response = msg_headers(headers_list)\n\n        if response is not None:\n            self.send_message(response)\n\n    def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60):\n        \"\"\"Send blocks to test node and test whether the tip advances.\n\n         - add all blocks to our block_store\n         - send a headers message for the final block\n         - the on_getheaders handler will ensure that any getheaders are responded to\n         - if force_send is False: wait for getdata for each of the blocks. The on_getdata handler will\n           ensure that any getdata messages are responded to. Otherwise send the full block unsolicited.\n         - if success is True: assert that the node's tip advances to the most recent block\n         - if success is False: assert that the node's tip doesn't advance\n         - if reject_reason is set: assert that the correct reject message is logged\"\"\"\n\n        with mininode_lock:\n            for block in blocks:\n                self.block_store[block.sha256] = block\n                self.last_block_hash = block.sha256\n\n        reject_reason = [reject_reason] if reject_reason else []\n        with node.assert_debug_log(expected_msgs=reject_reason):\n            if force_send:\n                for b in blocks:\n                    self.send_message(msg_block(block=b))\n            else:\n                self.send_message(msg_headers([CBlockHeader(blocks[-1])]))\n                wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)\n\n            if expect_disconnect:\n                self.wait_for_disconnect(timeout=timeout)\n            else:\n                self.sync_with_ping(timeout=timeout)\n\n            if success:\n                wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)\n            else:\n                assert node.getbestblockhash() != blocks[-1].hash\n\n    def send_txs_and_test(self, txs, node, *, success=True, expect_disconnect=False, reject_reason=None):\n        \"\"\"Send txs to test node and test whether they're accepted to the mempool.\n\n         - add all txs to our tx_store\n         - send tx messages for all txs\n         - if success is True/False: assert that the txs are/are not accepted to the mempool\n         - if expect_disconnect is True: Skip the sync with ping\n         - if reject_reason is set: assert that the correct reject message is logged.\"\"\"\n\n        with mininode_lock:\n            for tx in txs:\n                self.tx_store[tx.sha256] = tx\n\n        reject_reason = [reject_reason] if reject_reason else []\n        with node.assert_debug_log(expected_msgs=reject_reason):\n            for tx in txs:\n                self.send_message(msg_tx(tx))\n\n            if expect_disconnect:\n                self.wait_for_disconnect()\n            else:\n                self.sync_with_ping()\n\n            raw_mempool = node.getrawmempool()\n            if success:\n                # Check that all txs are now in the mempool\n                for tx in txs:\n                    assert tx.hash in raw_mempool, \"{} not found in mempool\".format(tx.hash)\n            else:\n                # Check that none of the txs are now in the mempool\n                for tx in txs:\n                    assert tx.hash not in raw_mempool, \"{} tx found in mempool\".format(tx.hash)\n"
  },
  {
    "path": "test/functional/test_framework/netutil.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Linux network utilities.\n\nRoughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal\n\"\"\"\n\nimport sys\nimport socket\nimport struct\nimport array\nimport os\nfrom binascii import unhexlify\n\n# STATE_ESTABLISHED = '01'\n# STATE_SYN_SENT  = '02'\n# STATE_SYN_RECV = '03'\n# STATE_FIN_WAIT1 = '04'\n# STATE_FIN_WAIT2 = '05'\n# STATE_TIME_WAIT = '06'\n# STATE_CLOSE = '07'\n# STATE_CLOSE_WAIT = '08'\n# STATE_LAST_ACK = '09'\nSTATE_LISTEN = '0A'\n# STATE_CLOSING = '0B'\n\ndef get_socket_inodes(pid):\n    '''\n    Get list of socket inodes for process pid.\n    '''\n    base = '/proc/%i/fd' % pid\n    inodes = []\n    for item in os.listdir(base):\n        target = os.readlink(os.path.join(base, item))\n        if target.startswith('socket:'):\n            inodes.append(int(target[8:-1]))\n    return inodes\n\ndef _remove_empty(array):\n    return [x for x in array if x !='']\n\ndef _convert_ip_port(array):\n    host,port = array.split(':')\n    # convert host from mangled-per-four-bytes form as used by kernel\n    host = unhexlify(host)\n    host_out = ''\n    for x in range(0, len(host) // 4):\n        (val,) = struct.unpack('=I', host[x*4:(x+1)*4])\n        host_out += '%08x' % val\n\n    return host_out,int(port,16)\n\ndef netstat(typ='tcp'):\n    '''\n    Function to return a list with status of tcp connections at linux systems\n    To get pid of all network process running on system, you must run this script\n    as superuser\n    '''\n    with open('/proc/net/'+typ,'r',encoding='utf8') as f:\n        content = f.readlines()\n        content.pop(0)\n    result = []\n    for line in content:\n        line_array = _remove_empty(line.split(' '))     # Split lines and remove empty spaces.\n        tcp_id = line_array[0]\n        l_addr = _convert_ip_port(line_array[1])\n        r_addr = _convert_ip_port(line_array[2])\n        state = line_array[3]\n        inode = int(line_array[9])                      # Need the inode to match with process pid.\n        nline = [tcp_id, l_addr, r_addr, state, inode]\n        result.append(nline)\n    return result\n\ndef get_bind_addrs(pid):\n    '''\n    Get bind addresses as (host,port) tuples for process pid.\n    '''\n    inodes = get_socket_inodes(pid)\n    bind_addrs = []\n    for conn in netstat('tcp') + netstat('tcp6'):\n        if conn[3] == STATE_LISTEN and conn[4] in inodes:\n            bind_addrs.append(conn[1])\n    return bind_addrs\n\n# from: http://code.activestate.com/recipes/439093/\ndef all_interfaces():\n    '''\n    Return all interfaces that are up\n    '''\n    import fcntl  # Linux only, so only import when required\n\n    is_64bits = sys.maxsize > 2**32\n    struct_size = 40 if is_64bits else 32\n    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n    max_possible = 8 # initial value\n    while True:\n        bytes = max_possible * struct_size\n        names = array.array('B', b'\\0' * bytes)\n        outbytes = struct.unpack('iL', fcntl.ioctl(\n            s.fileno(),\n            0x8912,  # SIOCGIFCONF\n            struct.pack('iL', bytes, names.buffer_info()[0])\n        ))[0]\n        if outbytes == bytes:\n            max_possible *= 2\n        else:\n            break\n    namestr = names.tobytes()\n    return [(namestr[i:i+16].split(b'\\0', 1)[0],\n             socket.inet_ntoa(namestr[i+20:i+24]))\n            for i in range(0, outbytes, struct_size)]\n\ndef addr_to_hex(addr):\n    '''\n    Convert string IPv4 or IPv6 address to binary address as returned by\n    get_bind_addrs.\n    Very naive implementation that certainly doesn't work for all IPv6 variants.\n    '''\n    if '.' in addr: # IPv4\n        addr = [int(x) for x in addr.split('.')]\n    elif ':' in addr: # IPv6\n        sub = [[], []] # prefix, suffix\n        x = 0\n        addr = addr.split(':')\n        for i,comp in enumerate(addr):\n            if comp == '':\n                if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end\n                    continue\n                x += 1 # :: skips to suffix\n                assert x < 2\n            else: # two bytes per component\n                val = int(comp, 16)\n                sub[x].append(val >> 8)\n                sub[x].append(val & 0xff)\n        nullbytes = 16 - len(sub[0]) - len(sub[1])\n        assert (x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)\n        addr = sub[0] + ([0] * nullbytes) + sub[1]\n    else:\n        raise ValueError('Could not parse address %s' % addr)\n    return bytearray(addr).hex()\n\ndef test_ipv6_local():\n    '''\n    Check for (local) IPv6 support.\n    '''\n    import socket\n    # By using SOCK_DGRAM this will not actually make a connection, but it will\n    # fail if there is no route to IPv6 localhost.\n    have_ipv6 = True\n    try:\n        s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)\n        s.connect(('::1', 0))\n    except socket.error:\n        have_ipv6 = False\n    return have_ipv6\n"
  },
  {
    "path": "test/functional/test_framework/script.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Functionality to build scripts, as well as SignatureHash().\n\nThis file is modified from python-bitcoinlib.\n\"\"\"\n\nfrom .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string\n\nimport hashlib\nimport struct\n\nfrom .bignum import bn2vch\n\nMAX_SCRIPT_ELEMENT_SIZE = 520\n\nOPCODE_NAMES = {}\n\ndef hash160(s):\n    return hashlib.new('ripemd160', sha256(s)).digest()\n\n\n_opcode_instances = []\nclass CScriptOp(int):\n    \"\"\"A single script opcode\"\"\"\n    __slots__ = ()\n\n    @staticmethod\n    def encode_op_pushdata(d):\n        \"\"\"Encode a PUSHDATA op, returning bytes\"\"\"\n        if len(d) < 0x4c:\n            return b'' + bytes([len(d)]) + d # OP_PUSHDATA\n        elif len(d) <= 0xff:\n            return b'\\x4c' + bytes([len(d)]) + d # OP_PUSHDATA1\n        elif len(d) <= 0xffff:\n            return b'\\x4d' + struct.pack(b'<H', len(d)) + d # OP_PUSHDATA2\n        elif len(d) <= 0xffffffff:\n            return b'\\x4e' + struct.pack(b'<I', len(d)) + d # OP_PUSHDATA4\n        else:\n            raise ValueError(\"Data too long to encode in a PUSHDATA op\")\n\n    @staticmethod\n    def encode_op_n(n):\n        \"\"\"Encode a small integer op, returning an opcode\"\"\"\n        if not (0 <= n <= 16):\n            raise ValueError('Integer must be in range 0 <= n <= 16, got %d' % n)\n\n        if n == 0:\n            return OP_0\n        else:\n            return CScriptOp(OP_1 + n-1)\n\n    def decode_op_n(self):\n        \"\"\"Decode a small integer opcode, returning an integer\"\"\"\n        if self == OP_0:\n            return 0\n\n        if not (self == OP_0 or OP_1 <= self <= OP_16):\n            raise ValueError('op %r is not an OP_N' % self)\n\n        return int(self - OP_1+1)\n\n    def is_small_int(self):\n        \"\"\"Return true if the op pushes a small integer to the stack\"\"\"\n        if 0x51 <= self <= 0x60 or self == 0:\n            return True\n        else:\n            return False\n\n    def __str__(self):\n        return repr(self)\n\n    def __repr__(self):\n        if self in OPCODE_NAMES:\n            return OPCODE_NAMES[self]\n        else:\n            return 'CScriptOp(0x%x)' % self\n\n    def __new__(cls, n):\n        try:\n            return _opcode_instances[n]\n        except IndexError:\n            assert len(_opcode_instances) == n\n            _opcode_instances.append(super(CScriptOp, cls).__new__(cls, n))\n            return _opcode_instances[n]\n\n# Populate opcode instance table\nfor n in range(0xff+1):\n    CScriptOp(n)\n\n\n# push value\nOP_0 = CScriptOp(0x00)\nOP_FALSE = OP_0\nOP_PUSHDATA1 = CScriptOp(0x4c)\nOP_PUSHDATA2 = CScriptOp(0x4d)\nOP_PUSHDATA4 = CScriptOp(0x4e)\nOP_1NEGATE = CScriptOp(0x4f)\nOP_RESERVED = CScriptOp(0x50)\nOP_1 = CScriptOp(0x51)\nOP_TRUE=OP_1\nOP_2 = CScriptOp(0x52)\nOP_3 = CScriptOp(0x53)\nOP_4 = CScriptOp(0x54)\nOP_5 = CScriptOp(0x55)\nOP_6 = CScriptOp(0x56)\nOP_7 = CScriptOp(0x57)\nOP_8 = CScriptOp(0x58)\nOP_9 = CScriptOp(0x59)\nOP_10 = CScriptOp(0x5a)\nOP_11 = CScriptOp(0x5b)\nOP_12 = CScriptOp(0x5c)\nOP_13 = CScriptOp(0x5d)\nOP_14 = CScriptOp(0x5e)\nOP_15 = CScriptOp(0x5f)\nOP_16 = CScriptOp(0x60)\n\n# control\nOP_NOP = CScriptOp(0x61)\nOP_VER = CScriptOp(0x62)\nOP_IF = CScriptOp(0x63)\nOP_NOTIF = CScriptOp(0x64)\nOP_VERIF = CScriptOp(0x65)\nOP_VERNOTIF = CScriptOp(0x66)\nOP_ELSE = CScriptOp(0x67)\nOP_ENDIF = CScriptOp(0x68)\nOP_VERIFY = CScriptOp(0x69)\nOP_RETURN = CScriptOp(0x6a)\n\n# stack ops\nOP_TOALTSTACK = CScriptOp(0x6b)\nOP_FROMALTSTACK = CScriptOp(0x6c)\nOP_2DROP = CScriptOp(0x6d)\nOP_2DUP = CScriptOp(0x6e)\nOP_3DUP = CScriptOp(0x6f)\nOP_2OVER = CScriptOp(0x70)\nOP_2ROT = CScriptOp(0x71)\nOP_2SWAP = CScriptOp(0x72)\nOP_IFDUP = CScriptOp(0x73)\nOP_DEPTH = CScriptOp(0x74)\nOP_DROP = CScriptOp(0x75)\nOP_DUP = CScriptOp(0x76)\nOP_NIP = CScriptOp(0x77)\nOP_OVER = CScriptOp(0x78)\nOP_PICK = CScriptOp(0x79)\nOP_ROLL = CScriptOp(0x7a)\nOP_ROT = CScriptOp(0x7b)\nOP_SWAP = CScriptOp(0x7c)\nOP_TUCK = CScriptOp(0x7d)\n\n# splice ops\nOP_CAT = CScriptOp(0x7e)\nOP_SUBSTR = CScriptOp(0x7f)\nOP_LEFT = CScriptOp(0x80)\nOP_RIGHT = CScriptOp(0x81)\nOP_SIZE = CScriptOp(0x82)\n\n# bit logic\nOP_INVERT = CScriptOp(0x83)\nOP_AND = CScriptOp(0x84)\nOP_OR = CScriptOp(0x85)\nOP_XOR = CScriptOp(0x86)\nOP_EQUAL = CScriptOp(0x87)\nOP_EQUALVERIFY = CScriptOp(0x88)\nOP_RESERVED1 = CScriptOp(0x89)\nOP_RESERVED2 = CScriptOp(0x8a)\n\n# numeric\nOP_1ADD = CScriptOp(0x8b)\nOP_1SUB = CScriptOp(0x8c)\nOP_2MUL = CScriptOp(0x8d)\nOP_2DIV = CScriptOp(0x8e)\nOP_NEGATE = CScriptOp(0x8f)\nOP_ABS = CScriptOp(0x90)\nOP_NOT = CScriptOp(0x91)\nOP_0NOTEQUAL = CScriptOp(0x92)\n\nOP_ADD = CScriptOp(0x93)\nOP_SUB = CScriptOp(0x94)\nOP_MUL = CScriptOp(0x95)\nOP_DIV = CScriptOp(0x96)\nOP_MOD = CScriptOp(0x97)\nOP_LSHIFT = CScriptOp(0x98)\nOP_RSHIFT = CScriptOp(0x99)\n\nOP_BOOLAND = CScriptOp(0x9a)\nOP_BOOLOR = CScriptOp(0x9b)\nOP_NUMEQUAL = CScriptOp(0x9c)\nOP_NUMEQUALVERIFY = CScriptOp(0x9d)\nOP_NUMNOTEQUAL = CScriptOp(0x9e)\nOP_LESSTHAN = CScriptOp(0x9f)\nOP_GREATERTHAN = CScriptOp(0xa0)\nOP_LESSTHANOREQUAL = CScriptOp(0xa1)\nOP_GREATERTHANOREQUAL = CScriptOp(0xa2)\nOP_MIN = CScriptOp(0xa3)\nOP_MAX = CScriptOp(0xa4)\n\nOP_WITHIN = CScriptOp(0xa5)\n\n# crypto\nOP_RIPEMD160 = CScriptOp(0xa6)\nOP_SHA1 = CScriptOp(0xa7)\nOP_SHA256 = CScriptOp(0xa8)\nOP_HASH160 = CScriptOp(0xa9)\nOP_HASH256 = CScriptOp(0xaa)\nOP_CODESEPARATOR = CScriptOp(0xab)\nOP_CHECKSIG = CScriptOp(0xac)\nOP_CHECKSIGVERIFY = CScriptOp(0xad)\nOP_CHECKMULTISIG = CScriptOp(0xae)\nOP_CHECKMULTISIGVERIFY = CScriptOp(0xaf)\n\n# expansion\nOP_NOP1 = CScriptOp(0xb0)\nOP_CHECKLOCKTIMEVERIFY = CScriptOp(0xb1)\nOP_CHECKSEQUENCEVERIFY = CScriptOp(0xb2)\nOP_NOP4 = CScriptOp(0xb3)\nOP_NOP5 = CScriptOp(0xb4)\nOP_NOP6 = CScriptOp(0xb5)\nOP_NOP7 = CScriptOp(0xb6)\nOP_NOP8 = CScriptOp(0xb7)\nOP_NOP9 = CScriptOp(0xb8)\nOP_NOP10 = CScriptOp(0xb9)\n\n# template matching params\nOP_SMALLINTEGER = CScriptOp(0xfa)\nOP_PUBKEYS = CScriptOp(0xfb)\nOP_PUBKEYHASH = CScriptOp(0xfd)\nOP_PUBKEY = CScriptOp(0xfe)\n\nOP_INVALIDOPCODE = CScriptOp(0xff)\n\nOPCODE_NAMES.update({\n    OP_0 : 'OP_0',\n    OP_PUSHDATA1 : 'OP_PUSHDATA1',\n    OP_PUSHDATA2 : 'OP_PUSHDATA2',\n    OP_PUSHDATA4 : 'OP_PUSHDATA4',\n    OP_1NEGATE : 'OP_1NEGATE',\n    OP_RESERVED : 'OP_RESERVED',\n    OP_1 : 'OP_1',\n    OP_2 : 'OP_2',\n    OP_3 : 'OP_3',\n    OP_4 : 'OP_4',\n    OP_5 : 'OP_5',\n    OP_6 : 'OP_6',\n    OP_7 : 'OP_7',\n    OP_8 : 'OP_8',\n    OP_9 : 'OP_9',\n    OP_10 : 'OP_10',\n    OP_11 : 'OP_11',\n    OP_12 : 'OP_12',\n    OP_13 : 'OP_13',\n    OP_14 : 'OP_14',\n    OP_15 : 'OP_15',\n    OP_16 : 'OP_16',\n    OP_NOP : 'OP_NOP',\n    OP_VER : 'OP_VER',\n    OP_IF : 'OP_IF',\n    OP_NOTIF : 'OP_NOTIF',\n    OP_VERIF : 'OP_VERIF',\n    OP_VERNOTIF : 'OP_VERNOTIF',\n    OP_ELSE : 'OP_ELSE',\n    OP_ENDIF : 'OP_ENDIF',\n    OP_VERIFY : 'OP_VERIFY',\n    OP_RETURN : 'OP_RETURN',\n    OP_TOALTSTACK : 'OP_TOALTSTACK',\n    OP_FROMALTSTACK : 'OP_FROMALTSTACK',\n    OP_2DROP : 'OP_2DROP',\n    OP_2DUP : 'OP_2DUP',\n    OP_3DUP : 'OP_3DUP',\n    OP_2OVER : 'OP_2OVER',\n    OP_2ROT : 'OP_2ROT',\n    OP_2SWAP : 'OP_2SWAP',\n    OP_IFDUP : 'OP_IFDUP',\n    OP_DEPTH : 'OP_DEPTH',\n    OP_DROP : 'OP_DROP',\n    OP_DUP : 'OP_DUP',\n    OP_NIP : 'OP_NIP',\n    OP_OVER : 'OP_OVER',\n    OP_PICK : 'OP_PICK',\n    OP_ROLL : 'OP_ROLL',\n    OP_ROT : 'OP_ROT',\n    OP_SWAP : 'OP_SWAP',\n    OP_TUCK : 'OP_TUCK',\n    OP_CAT : 'OP_CAT',\n    OP_SUBSTR : 'OP_SUBSTR',\n    OP_LEFT : 'OP_LEFT',\n    OP_RIGHT : 'OP_RIGHT',\n    OP_SIZE : 'OP_SIZE',\n    OP_INVERT : 'OP_INVERT',\n    OP_AND : 'OP_AND',\n    OP_OR : 'OP_OR',\n    OP_XOR : 'OP_XOR',\n    OP_EQUAL : 'OP_EQUAL',\n    OP_EQUALVERIFY : 'OP_EQUALVERIFY',\n    OP_RESERVED1 : 'OP_RESERVED1',\n    OP_RESERVED2 : 'OP_RESERVED2',\n    OP_1ADD : 'OP_1ADD',\n    OP_1SUB : 'OP_1SUB',\n    OP_2MUL : 'OP_2MUL',\n    OP_2DIV : 'OP_2DIV',\n    OP_NEGATE : 'OP_NEGATE',\n    OP_ABS : 'OP_ABS',\n    OP_NOT : 'OP_NOT',\n    OP_0NOTEQUAL : 'OP_0NOTEQUAL',\n    OP_ADD : 'OP_ADD',\n    OP_SUB : 'OP_SUB',\n    OP_MUL : 'OP_MUL',\n    OP_DIV : 'OP_DIV',\n    OP_MOD : 'OP_MOD',\n    OP_LSHIFT : 'OP_LSHIFT',\n    OP_RSHIFT : 'OP_RSHIFT',\n    OP_BOOLAND : 'OP_BOOLAND',\n    OP_BOOLOR : 'OP_BOOLOR',\n    OP_NUMEQUAL : 'OP_NUMEQUAL',\n    OP_NUMEQUALVERIFY : 'OP_NUMEQUALVERIFY',\n    OP_NUMNOTEQUAL : 'OP_NUMNOTEQUAL',\n    OP_LESSTHAN : 'OP_LESSTHAN',\n    OP_GREATERTHAN : 'OP_GREATERTHAN',\n    OP_LESSTHANOREQUAL : 'OP_LESSTHANOREQUAL',\n    OP_GREATERTHANOREQUAL : 'OP_GREATERTHANOREQUAL',\n    OP_MIN : 'OP_MIN',\n    OP_MAX : 'OP_MAX',\n    OP_WITHIN : 'OP_WITHIN',\n    OP_RIPEMD160 : 'OP_RIPEMD160',\n    OP_SHA1 : 'OP_SHA1',\n    OP_SHA256 : 'OP_SHA256',\n    OP_HASH160 : 'OP_HASH160',\n    OP_HASH256 : 'OP_HASH256',\n    OP_CODESEPARATOR : 'OP_CODESEPARATOR',\n    OP_CHECKSIG : 'OP_CHECKSIG',\n    OP_CHECKSIGVERIFY : 'OP_CHECKSIGVERIFY',\n    OP_CHECKMULTISIG : 'OP_CHECKMULTISIG',\n    OP_CHECKMULTISIGVERIFY : 'OP_CHECKMULTISIGVERIFY',\n    OP_NOP1 : 'OP_NOP1',\n    OP_CHECKLOCKTIMEVERIFY : 'OP_CHECKLOCKTIMEVERIFY',\n    OP_CHECKSEQUENCEVERIFY : 'OP_CHECKSEQUENCEVERIFY',\n    OP_NOP4 : 'OP_NOP4',\n    OP_NOP5 : 'OP_NOP5',\n    OP_NOP6 : 'OP_NOP6',\n    OP_NOP7 : 'OP_NOP7',\n    OP_NOP8 : 'OP_NOP8',\n    OP_NOP9 : 'OP_NOP9',\n    OP_NOP10 : 'OP_NOP10',\n    OP_SMALLINTEGER : 'OP_SMALLINTEGER',\n    OP_PUBKEYS : 'OP_PUBKEYS',\n    OP_PUBKEYHASH : 'OP_PUBKEYHASH',\n    OP_PUBKEY : 'OP_PUBKEY',\n    OP_INVALIDOPCODE : 'OP_INVALIDOPCODE',\n})\n\nclass CScriptInvalidError(Exception):\n    \"\"\"Base class for CScript exceptions\"\"\"\n    pass\n\nclass CScriptTruncatedPushDataError(CScriptInvalidError):\n    \"\"\"Invalid pushdata due to truncation\"\"\"\n    def __init__(self, msg, data):\n        self.data = data\n        super(CScriptTruncatedPushDataError, self).__init__(msg)\n\n\n# This is used, eg, for blockchain heights in coinbase scripts (bip34)\nclass CScriptNum:\n    __slots__ = (\"value\",)\n\n    def __init__(self, d=0):\n        self.value = d\n\n    @staticmethod\n    def encode(obj):\n        r = bytearray(0)\n        if obj.value == 0:\n            return bytes(r)\n        neg = obj.value < 0\n        absvalue = -obj.value if neg else obj.value\n        while (absvalue):\n            r.append(absvalue & 0xff)\n            absvalue >>= 8\n        if r[-1] & 0x80:\n            r.append(0x80 if neg else 0)\n        elif neg:\n            r[-1] |= 0x80\n        return bytes([len(r)]) + r\n\n    @staticmethod\n    def decode(vch):\n        result = 0\n        # We assume valid push_size and minimal encoding\n        value = vch[1:]\n        if len(value) == 0:\n            return result\n        for i, byte in enumerate(value):\n            result |= int(byte) << 8*i\n        if value[-1] >= 0x80:\n            # Mask for all but the highest result bit\n            num_mask = (2**(len(value)*8) - 1) >> 1\n            result &= num_mask\n            result *= -1\n        return result\n\n\nclass CScript(bytes):\n    \"\"\"Serialized script\n\n    A bytes subclass, so you can use this directly whenever bytes are accepted.\n    Note that this means that indexing does *not* work - you'll get an index by\n    byte rather than opcode. This format was chosen for efficiency so that the\n    general case would not require creating a lot of little CScriptOP objects.\n\n    iter(script) however does iterate by opcode.\n    \"\"\"\n    __slots__ = ()\n\n    @classmethod\n    def __coerce_instance(cls, other):\n        # Coerce other into bytes\n        if isinstance(other, CScriptOp):\n            other = bytes([other])\n        elif isinstance(other, CScriptNum):\n            if (other.value == 0):\n                other = bytes([CScriptOp(OP_0)])\n            else:\n                other = CScriptNum.encode(other)\n        elif isinstance(other, int):\n            if 0 <= other <= 16:\n                other = bytes([CScriptOp.encode_op_n(other)])\n            elif other == -1:\n                other = bytes([OP_1NEGATE])\n            else:\n                other = CScriptOp.encode_op_pushdata(bn2vch(other))\n        elif isinstance(other, (bytes, bytearray)):\n            other = CScriptOp.encode_op_pushdata(other)\n        return other\n\n    def __add__(self, other):\n        # Do the coercion outside of the try block so that errors in it are\n        # noticed.\n        other = self.__coerce_instance(other)\n\n        try:\n            # bytes.__add__ always returns bytes instances unfortunately\n            return CScript(super(CScript, self).__add__(other))\n        except TypeError:\n            raise TypeError('Can not add a %r instance to a CScript' % other.__class__)\n\n    def join(self, iterable):\n        # join makes no sense for a CScript()\n        raise NotImplementedError\n\n    def __new__(cls, value=b''):\n        if isinstance(value, bytes) or isinstance(value, bytearray):\n            return super(CScript, cls).__new__(cls, value)\n        else:\n            def coerce_iterable(iterable):\n                for instance in iterable:\n                    yield cls.__coerce_instance(instance)\n            # Annoyingly on both python2 and python3 bytes.join() always\n            # returns a bytes instance even when subclassed.\n            return super(CScript, cls).__new__(cls, b''.join(coerce_iterable(value)))\n\n    def raw_iter(self):\n        \"\"\"Raw iteration\n\n        Yields tuples of (opcode, data, sop_idx) so that the different possible\n        PUSHDATA encodings can be accurately distinguished, as well as\n        determining the exact opcode byte indexes. (sop_idx)\n        \"\"\"\n        i = 0\n        while i < len(self):\n            sop_idx = i\n            opcode = self[i]\n            i += 1\n\n            if opcode > OP_PUSHDATA4:\n                yield (opcode, None, sop_idx)\n            else:\n                datasize = None\n                pushdata_type = None\n                if opcode < OP_PUSHDATA1:\n                    pushdata_type = 'PUSHDATA(%d)' % opcode\n                    datasize = opcode\n\n                elif opcode == OP_PUSHDATA1:\n                    pushdata_type = 'PUSHDATA1'\n                    if i >= len(self):\n                        raise CScriptInvalidError('PUSHDATA1: missing data length')\n                    datasize = self[i]\n                    i += 1\n\n                elif opcode == OP_PUSHDATA2:\n                    pushdata_type = 'PUSHDATA2'\n                    if i + 1 >= len(self):\n                        raise CScriptInvalidError('PUSHDATA2: missing data length')\n                    datasize = self[i] + (self[i+1] << 8)\n                    i += 2\n\n                elif opcode == OP_PUSHDATA4:\n                    pushdata_type = 'PUSHDATA4'\n                    if i + 3 >= len(self):\n                        raise CScriptInvalidError('PUSHDATA4: missing data length')\n                    datasize = self[i] + (self[i+1] << 8) + (self[i+2] << 16) + (self[i+3] << 24)\n                    i += 4\n\n                else:\n                    assert False # shouldn't happen\n\n\n                data = bytes(self[i:i+datasize])\n\n                # Check for truncation\n                if len(data) < datasize:\n                    raise CScriptTruncatedPushDataError('%s: truncated data' % pushdata_type, data)\n\n                i += datasize\n\n                yield (opcode, data, sop_idx)\n\n    def __iter__(self):\n        \"\"\"'Cooked' iteration\n\n        Returns either a CScriptOP instance, an integer, or bytes, as\n        appropriate.\n\n        See raw_iter() if you need to distinguish the different possible\n        PUSHDATA encodings.\n        \"\"\"\n        for (opcode, data, sop_idx) in self.raw_iter():\n            if data is not None:\n                yield data\n            else:\n                opcode = CScriptOp(opcode)\n\n                if opcode.is_small_int():\n                    yield opcode.decode_op_n()\n                else:\n                    yield CScriptOp(opcode)\n\n    def __repr__(self):\n        def _repr(o):\n            if isinstance(o, bytes):\n                return \"x('%s')\" % o.hex()\n            else:\n                return repr(o)\n\n        ops = []\n        i = iter(self)\n        while True:\n            op = None\n            try:\n                op = _repr(next(i))\n            except CScriptTruncatedPushDataError as err:\n                op = '%s...<ERROR: %s>' % (_repr(err.data), err)\n                break\n            except CScriptInvalidError as err:\n                op = '<ERROR: %s>' % err\n                break\n            except StopIteration:\n                break\n            finally:\n                if op is not None:\n                    ops.append(op)\n\n        return \"CScript([%s])\" % ', '.join(ops)\n\n    def GetSigOpCount(self, fAccurate):\n        \"\"\"Get the SigOp count.\n\n        fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details.\n\n        Note that this is consensus-critical.\n        \"\"\"\n        n = 0\n        lastOpcode = OP_INVALIDOPCODE\n        for (opcode, data, sop_idx) in self.raw_iter():\n            if opcode in (OP_CHECKSIG, OP_CHECKSIGVERIFY):\n                n += 1\n            elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY):\n                if fAccurate and (OP_1 <= lastOpcode <= OP_16):\n                    n += opcode.decode_op_n()\n                else:\n                    n += 20\n            lastOpcode = opcode\n        return n\n\n\nSIGHASH_ALL = 1\nSIGHASH_NONE = 2\nSIGHASH_SINGLE = 3\nSIGHASH_ANYONECANPAY = 0x80\n\ndef FindAndDelete(script, sig):\n    \"\"\"Consensus critical, see FindAndDelete() in Satoshi codebase\"\"\"\n    r = b''\n    last_sop_idx = sop_idx = 0\n    skip = True\n    for (opcode, data, sop_idx) in script.raw_iter():\n        if not skip:\n            r += script[last_sop_idx:sop_idx]\n        last_sop_idx = sop_idx\n        if script[sop_idx:sop_idx + len(sig)] == sig:\n            skip = True\n        else:\n            skip = False\n    if not skip:\n        r += script[last_sop_idx:]\n    return CScript(r)\n\n\ndef SignatureHash(script, txTo, inIdx, hashtype):\n    \"\"\"Consensus-correct SignatureHash\n\n    Returns (hash, err) to precisely match the consensus-critical behavior of\n    the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)\n    \"\"\"\n    HASH_ONE = b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n\n    if inIdx >= len(txTo.vin):\n        return (HASH_ONE, \"inIdx %d out of range (%d)\" % (inIdx, len(txTo.vin)))\n    txtmp = CTransaction(txTo)\n\n    for txin in txtmp.vin:\n        txin.scriptSig = b''\n    txtmp.vin[inIdx].scriptSig = FindAndDelete(script, CScript([OP_CODESEPARATOR]))\n\n    if (hashtype & 0x1f) == SIGHASH_NONE:\n        txtmp.vout = []\n\n        for i in range(len(txtmp.vin)):\n            if i != inIdx:\n                txtmp.vin[i].nSequence = 0\n\n    elif (hashtype & 0x1f) == SIGHASH_SINGLE:\n        outIdx = inIdx\n        if outIdx >= len(txtmp.vout):\n            return (HASH_ONE, \"outIdx %d out of range (%d)\" % (outIdx, len(txtmp.vout)))\n\n        tmp = txtmp.vout[outIdx]\n        txtmp.vout = []\n        for i in range(outIdx):\n            txtmp.vout.append(CTxOut(-1))\n        txtmp.vout.append(tmp)\n\n        for i in range(len(txtmp.vin)):\n            if i != inIdx:\n                txtmp.vin[i].nSequence = 0\n\n    if hashtype & SIGHASH_ANYONECANPAY:\n        tmp = txtmp.vin[inIdx]\n        txtmp.vin = []\n        txtmp.vin.append(tmp)\n\n    s = txtmp.serialize_without_witness()\n    s += struct.pack(b\"<I\", hashtype)\n\n    hash = hash256(s)\n\n    return (hash, None)\n\n# TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided.\n# Performance optimization probably not necessary for python tests, however.\n# Note that this corresponds to sigversion == 1 in EvalScript, which is used\n# for version 0 witnesses.\ndef SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, amount):\n\n    hashPrevouts = 0\n    hashSequence = 0\n    hashOutputs = 0\n\n    if not (hashtype & SIGHASH_ANYONECANPAY):\n        serialize_prevouts = bytes()\n        for i in txTo.vin:\n            serialize_prevouts += i.prevout.serialize()\n        hashPrevouts = uint256_from_str(hash256(serialize_prevouts))\n\n    if (not (hashtype & SIGHASH_ANYONECANPAY) and (hashtype & 0x1f) != SIGHASH_SINGLE and (hashtype & 0x1f) != SIGHASH_NONE):\n        serialize_sequence = bytes()\n        for i in txTo.vin:\n            serialize_sequence += struct.pack(\"<I\", i.nSequence)\n        hashSequence = uint256_from_str(hash256(serialize_sequence))\n\n    if ((hashtype & 0x1f) != SIGHASH_SINGLE and (hashtype & 0x1f) != SIGHASH_NONE):\n        serialize_outputs = bytes()\n        for o in txTo.vout:\n            serialize_outputs += o.serialize()\n        hashOutputs = uint256_from_str(hash256(serialize_outputs))\n    elif ((hashtype & 0x1f) == SIGHASH_SINGLE and inIdx < len(txTo.vout)):\n        serialize_outputs = txTo.vout[inIdx].serialize()\n        hashOutputs = uint256_from_str(hash256(serialize_outputs))\n\n    ss = bytes()\n    ss += struct.pack(\"<i\", txTo.nVersion)\n    ss += ser_uint256(hashPrevouts)\n    ss += ser_uint256(hashSequence)\n    ss += txTo.vin[inIdx].prevout.serialize()\n    ss += ser_string(script)\n    ss += struct.pack(\"<q\", amount)\n    ss += struct.pack(\"<I\", txTo.vin[inIdx].nSequence)\n    ss += ser_uint256(hashOutputs)\n    ss += struct.pack(\"<i\", txTo.nLockTime)\n    ss += struct.pack(\"<I\", hashtype)\n\n    return hash256(ss)\n"
  },
  {
    "path": "test/functional/test_framework/segwit_addr.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017 Pieter Wuille\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Reference implementation for Bech32 and segwit addresses.\"\"\"\n\n\nCHARSET = \"qpzry9x8gf2tvdw0s3jn54khce6mua7l\"\n\n\ndef bech32_polymod(values):\n    \"\"\"Internal function that computes the Bech32 checksum.\"\"\"\n    generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]\n    chk = 1\n    for value in values:\n        top = chk >> 25\n        chk = (chk & 0x1ffffff) << 5 ^ value\n        for i in range(5):\n            chk ^= generator[i] if ((top >> i) & 1) else 0\n    return chk\n\n\ndef bech32_hrp_expand(hrp):\n    \"\"\"Expand the HRP into values for checksum computation.\"\"\"\n    return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]\n\n\ndef bech32_verify_checksum(hrp, data):\n    \"\"\"Verify a checksum given HRP and converted data characters.\"\"\"\n    return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1\n\n\ndef bech32_create_checksum(hrp, data):\n    \"\"\"Compute the checksum values given HRP and data.\"\"\"\n    values = bech32_hrp_expand(hrp) + data\n    polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1\n    return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]\n\n\ndef bech32_encode(hrp, data):\n    \"\"\"Compute a Bech32 string given HRP and data values.\"\"\"\n    combined = data + bech32_create_checksum(hrp, data)\n    return hrp + '1' + ''.join([CHARSET[d] for d in combined])\n\n\ndef bech32_decode(bech):\n    \"\"\"Validate a Bech32 string, and determine HRP and data.\"\"\"\n    if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or\n            (bech.lower() != bech and bech.upper() != bech)):\n        return (None, None)\n    bech = bech.lower()\n    pos = bech.rfind('1')\n    if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:\n        return (None, None)\n    if not all(x in CHARSET for x in bech[pos+1:]):\n        return (None, None)\n    hrp = bech[:pos]\n    data = [CHARSET.find(x) for x in bech[pos+1:]]\n    if not bech32_verify_checksum(hrp, data):\n        return (None, None)\n    return (hrp, data[:-6])\n\n\ndef convertbits(data, frombits, tobits, pad=True):\n    \"\"\"General power-of-2 base conversion.\"\"\"\n    acc = 0\n    bits = 0\n    ret = []\n    maxv = (1 << tobits) - 1\n    max_acc = (1 << (frombits + tobits - 1)) - 1\n    for value in data:\n        if value < 0 or (value >> frombits):\n            return None\n        acc = ((acc << frombits) | value) & max_acc\n        bits += frombits\n        while bits >= tobits:\n            bits -= tobits\n            ret.append((acc >> bits) & maxv)\n    if pad:\n        if bits:\n            ret.append((acc << (tobits - bits)) & maxv)\n    elif bits >= frombits or ((acc << (tobits - bits)) & maxv):\n        return None\n    return ret\n\n\ndef decode(hrp, addr):\n    \"\"\"Decode a segwit address.\"\"\"\n    hrpgot, data = bech32_decode(addr)\n    if hrpgot != hrp:\n        return (None, None)\n    decoded = convertbits(data[1:], 5, 8, False)\n    if decoded is None or len(decoded) < 2 or len(decoded) > 40:\n        return (None, None)\n    if data[0] > 16:\n        return (None, None)\n    if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:\n        return (None, None)\n    return (data[0], decoded)\n\n\ndef encode(hrp, witver, witprog):\n    \"\"\"Encode a segwit address.\"\"\"\n    ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5))\n    if decode(hrp, ret) == (None, None):\n        return None\n    return ret\n"
  },
  {
    "path": "test/functional/test_framework/siphash.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Specialized SipHash-2-4 implementations.\n\nThis implements SipHash-2-4 for 256-bit integers.\n\"\"\"\n\ndef rotl64(n, b):\n    return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b\n\ndef siphash_round(v0, v1, v2, v3):\n    v0 = (v0 + v1) & ((1 << 64) - 1)\n    v1 = rotl64(v1, 13)\n    v1 ^= v0\n    v0 = rotl64(v0, 32)\n    v2 = (v2 + v3) & ((1 << 64) - 1)\n    v3 = rotl64(v3, 16)\n    v3 ^= v2\n    v0 = (v0 + v3) & ((1 << 64) - 1)\n    v3 = rotl64(v3, 21)\n    v3 ^= v0\n    v2 = (v2 + v1) & ((1 << 64) - 1)\n    v1 = rotl64(v1, 17)\n    v1 ^= v2\n    v2 = rotl64(v2, 32)\n    return (v0, v1, v2, v3)\n\ndef siphash256(k0, k1, h):\n    n0 = h & ((1 << 64) - 1)\n    n1 = (h >> 64) & ((1 << 64) - 1)\n    n2 = (h >> 128) & ((1 << 64) - 1)\n    n3 = (h >> 192) & ((1 << 64) - 1)\n    v0 = 0x736f6d6570736575 ^ k0\n    v1 = 0x646f72616e646f6d ^ k1\n    v2 = 0x6c7967656e657261 ^ k0\n    v3 = 0x7465646279746573 ^ k1 ^ n0\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0 ^= n0\n    v3 ^= n1\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0 ^= n1\n    v3 ^= n2\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0 ^= n2\n    v3 ^= n3\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0 ^= n3\n    v3 ^= 0x2000000000000000\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0 ^= 0x2000000000000000\n    v2 ^= 0xFF\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3)\n    return v0 ^ v1 ^ v2 ^ v3\n"
  },
  {
    "path": "test/functional/test_framework/socks5.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Dummy Socks5 server for testing.\"\"\"\n\nimport socket\nimport threading\nimport queue\nimport logging\n\nlogger = logging.getLogger(\"TestFramework.socks5\")\n\n# Protocol constants\nclass Command:\n    CONNECT = 0x01\n\nclass AddressType:\n    IPV4 = 0x01\n    DOMAINNAME = 0x03\n    IPV6 = 0x04\n\n# Utility functions\ndef recvall(s, n):\n    \"\"\"Receive n bytes from a socket, or fail.\"\"\"\n    rv = bytearray()\n    while n > 0:\n        d = s.recv(n)\n        if not d:\n            raise IOError('Unexpected end of stream')\n        rv.extend(d)\n        n -= len(d)\n    return rv\n\n# Implementation classes\nclass Socks5Configuration():\n    \"\"\"Proxy configuration.\"\"\"\n    def __init__(self):\n        self.addr = None # Bind address (must be set)\n        self.af = socket.AF_INET # Bind address family\n        self.unauth = False  # Support unauthenticated\n        self.auth = False  # Support authentication\n\nclass Socks5Command():\n    \"\"\"Information about an incoming socks5 command.\"\"\"\n    def __init__(self, cmd, atyp, addr, port, username, password):\n        self.cmd = cmd # Command (one of Command.*)\n        self.atyp = atyp # Address type (one of AddressType.*)\n        self.addr = addr # Address\n        self.port = port # Port to connect to\n        self.username = username\n        self.password = password\n    def __repr__(self):\n        return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password)\n\nclass Socks5Connection():\n    def __init__(self, serv, conn):\n        self.serv = serv\n        self.conn = conn\n\n    def handle(self):\n        \"\"\"Handle socks5 request according to RFC192.\"\"\"\n        try:\n            # Verify socks version\n            ver = recvall(self.conn, 1)[0]\n            if ver != 0x05:\n                raise IOError('Invalid socks version %i' % ver)\n            # Choose authentication method\n            nmethods = recvall(self.conn, 1)[0]\n            methods = bytearray(recvall(self.conn, nmethods))\n            method = None\n            if 0x02 in methods and self.serv.conf.auth:\n                method = 0x02 # username/password\n            elif 0x00 in methods and self.serv.conf.unauth:\n                method = 0x00 # unauthenticated\n            if method is None:\n                raise IOError('No supported authentication method was offered')\n            # Send response\n            self.conn.sendall(bytearray([0x05, method]))\n            # Read authentication (optional)\n            username = None\n            password = None\n            if method == 0x02:\n                ver = recvall(self.conn, 1)[0]\n                if ver != 0x01:\n                    raise IOError('Invalid auth packet version %i' % ver)\n                ulen = recvall(self.conn, 1)[0]\n                username = str(recvall(self.conn, ulen))\n                plen = recvall(self.conn, 1)[0]\n                password = str(recvall(self.conn, plen))\n                # Send authentication response\n                self.conn.sendall(bytearray([0x01, 0x00]))\n\n            # Read connect request\n            ver, cmd, _, atyp = recvall(self.conn, 4)\n            if ver != 0x05:\n                raise IOError('Invalid socks version %i in connect request' % ver)\n            if cmd != Command.CONNECT:\n                raise IOError('Unhandled command %i in connect request' % cmd)\n\n            if atyp == AddressType.IPV4:\n                addr = recvall(self.conn, 4)\n            elif atyp == AddressType.DOMAINNAME:\n                n = recvall(self.conn, 1)[0]\n                addr = recvall(self.conn, n)\n            elif atyp == AddressType.IPV6:\n                addr = recvall(self.conn, 16)\n            else:\n                raise IOError('Unknown address type %i' % atyp)\n            port_hi,port_lo = recvall(self.conn, 2)\n            port = (port_hi << 8) | port_lo\n\n            # Send dummy response\n            self.conn.sendall(bytearray([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))\n\n            cmdin = Socks5Command(cmd, atyp, addr, port, username, password)\n            self.serv.queue.put(cmdin)\n            logger.info('Proxy: %s', cmdin)\n            # Fall through to disconnect\n        except Exception as e:\n            logger.exception(\"socks5 request handling failed.\")\n            self.serv.queue.put(e)\n        finally:\n            self.conn.close()\n\nclass Socks5Server():\n    def __init__(self, conf):\n        self.conf = conf\n        self.s = socket.socket(conf.af)\n        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n        self.s.bind(conf.addr)\n        self.s.listen(5)\n        self.running = False\n        self.thread = None\n        self.queue = queue.Queue() # report connections and exceptions to client\n\n    def run(self):\n        while self.running:\n            (sockconn, _) = self.s.accept()\n            if self.running:\n                conn = Socks5Connection(self, sockconn)\n                thread = threading.Thread(None, conn.handle)\n                thread.daemon = True\n                thread.start()\n\n    def start(self):\n        assert not self.running\n        self.running = True\n        self.thread = threading.Thread(None, self.run)\n        self.thread.daemon = True\n        self.thread.start()\n\n    def stop(self):\n        self.running = False\n        # connect to self to end run loop\n        s = socket.socket(self.conf.af)\n        s.connect(self.conf.addr)\n        s.close()\n        self.thread.join()\n\n"
  },
  {
    "path": "test/functional/test_framework/test_framework.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Base class for RPC testing.\"\"\"\n\nimport configparser\nfrom enum import Enum\nimport logging\nimport argparse\nimport os\nimport pdb\nimport shutil\nimport sys\nimport tempfile\nimport time\n\nfrom .authproxy import JSONRPCException\nfrom . import coverage\nfrom .test_node import TestNode\nfrom .mininode import NetworkThread\nfrom .util import (\n    MAX_NODES,\n    PortSeed,\n    assert_equal,\n    check_json_precision,\n    connect_nodes_bi,\n    disconnect_nodes,\n    get_datadir_path,\n    initialize_datadir,\n    p2p_port,\n    sync_blocks,\n    sync_mempools,\n)\n\n\nclass TestStatus(Enum):\n    PASSED = 1\n    FAILED = 2\n    SKIPPED = 3\n\nTEST_EXIT_PASSED = 0\nTEST_EXIT_FAILED = 1\nTEST_EXIT_SKIPPED = 77\n\nTMPDIR_PREFIX = \"munt_func_test_\"\n\n\nclass SkipTest(Exception):\n    \"\"\"This exception is raised to skip a test\"\"\"\n\n    def __init__(self, message):\n        self.message = message\n\n\nclass MuntTestMetaClass(type):\n    \"\"\"Metaclass for MuntTestFramework.\n\n    Ensures that any attempt to register a subclass of `MuntTestFramework`\n    adheres to a standard whereby the subclass overrides `set_test_params` and\n    `run_test` but DOES NOT override either `__init__` or `main`. If any of\n    those standards are violated, a ``TypeError`` is raised.\"\"\"\n\n    def __new__(cls, clsname, bases, dct):\n        if not clsname == 'MuntTestFramework':\n            if not ('run_test' in dct and 'set_test_params' in dct):\n                raise TypeError(\"MuntTestFramework subclasses must override \"\n                                \"'run_test' and 'set_test_params'\")\n            if '__init__' in dct or 'main' in dct:\n                raise TypeError(\"MuntTestFramework subclasses may not override \"\n                                \"'__init__' or 'main'\")\n\n        return super().__new__(cls, clsname, bases, dct)\n\n\nclass MuntTestFramework(metaclass=MuntTestMetaClass):\n    \"\"\"Base class for a Munt test script.\n\n    Individual Munt test scripts should subclass this class and override the set_test_params() and run_test() methods.\n\n    Individual tests can also override the following methods to customize the test setup:\n\n    - add_options()\n    - setup_chain()\n    - setup_network()\n    - setup_nodes()\n\n    The __init__() and main() methods should not be overridden.\n\n    This class also contains various public and private helper methods.\"\"\"\n\n    def __init__(self):\n        \"\"\"Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method\"\"\"\n        self.setup_clean_chain = False\n        self.nodes = []\n        self.network_thread = None\n        self.rpc_timeout = 60  # Wait for up to 60 seconds for the RPC server to respond\n        self.supports_cli = False\n        self.bind_to_localhost_only = True\n        self.set_test_params()\n\n        assert hasattr(self, \"num_nodes\"), \"Test must set self.num_nodes in set_test_params()\"\n\n    def main(self):\n        \"\"\"Main function. This should not be overridden by the subclass test scripts.\"\"\"\n\n        parser = argparse.ArgumentParser(usage=\"%(prog)s [options]\")\n        parser.add_argument(\"--nocleanup\", dest=\"nocleanup\", default=False, action=\"store_true\",\n                            help=\"Leave Munt-daemons and test.* datadir on exit or error\")\n        parser.add_argument(\"--noshutdown\", dest=\"noshutdown\", default=False, action=\"store_true\",\n                            help=\"Don't stop Munt-daemons after the test execution\")\n        parser.add_argument(\"--cachedir\", dest=\"cachedir\", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + \"/../../cache\"),\n                            help=\"Directory for caching pregenerated datadirs (default: %(default)s)\")\n        parser.add_argument(\"--tmpdir\", dest=\"tmpdir\", help=\"Root directory for datadirs\")\n        parser.add_argument(\"-l\", \"--loglevel\", dest=\"loglevel\", default=\"INFO\",\n                            help=\"log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.\")\n        parser.add_argument(\"--tracerpc\", dest=\"trace_rpc\", default=False, action=\"store_true\",\n                            help=\"Print out all RPC calls as they are made\")\n        parser.add_argument(\"--portseed\", dest=\"port_seed\", default=os.getpid(), type=int,\n                            help=\"The seed to use for assigning port numbers (default: current process id)\")\n        parser.add_argument(\"--coveragedir\", dest=\"coveragedir\",\n                            help=\"Write tested RPC commands into this directory\")\n        parser.add_argument(\"--configfile\", dest=\"configfile\",\n                            default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + \"/../../config.ini\"),\n                            help=\"Location of the test framework config file (default: %(default)s)\")\n        parser.add_argument(\"--pdbonfailure\", dest=\"pdbonfailure\", default=False, action=\"store_true\",\n                            help=\"Attach a python debugger if test fails\")\n        parser.add_argument(\"--usecli\", dest=\"usecli\", default=False, action=\"store_true\",\n                            help=\"use Munt-cli instead of RPC for all commands\")\n        parser.add_argument(\"--perf\", dest=\"perf\", default=False, action=\"store_true\",\n                            help=\"profile running nodes with perf for the duration of the test\")\n        self.add_options(parser)\n        self.options = parser.parse_args()\n\n        PortSeed.n = self.options.port_seed\n\n        check_json_precision()\n\n        self.options.cachedir = os.path.abspath(self.options.cachedir)\n\n        config = configparser.ConfigParser()\n        config.read_file(open(self.options.configfile))\n        self.config = config\n        self.options.muntdaemon = os.getenv(\"MUNTDAEMON\", default=config[\"environment\"][\"BUILDDIR\"] + '/src/Munt-daemon' + config[\"environment\"][\"EXEEXT\"])\n        self.options.muntcli = os.getenv(\"MUNTCLI\", default=config[\"environment\"][\"BUILDDIR\"] + '/src/Munt-cli' + config[\"environment\"][\"EXEEXT\"])\n\n        os.environ['PATH'] = os.pathsep.join([\n            os.path.join(config['environment']['BUILDDIR'], 'src'),\n            os.path.join(config['environment']['BUILDDIR'], 'src', 'qt'),\n            os.environ['PATH']\n        ])\n\n        # Set up temp directory and start logging\n        if self.options.tmpdir:\n            self.options.tmpdir = os.path.abspath(self.options.tmpdir)\n            os.makedirs(self.options.tmpdir, exist_ok=False)\n        else:\n            self.options.tmpdir = tempfile.mkdtemp(prefix=TMPDIR_PREFIX)\n        self._start_logging()\n\n        self.log.debug('Setting up network thread')\n        self.network_thread = NetworkThread()\n        self.network_thread.start()\n\n        success = TestStatus.FAILED\n\n        try:\n            if self.options.usecli:\n                if not self.supports_cli:\n                    raise SkipTest(\"--usecli specified but test does not support using CLI\")\n                self.skip_if_no_cli()\n            self.skip_test_if_missing_module()\n            self.setup_chain()\n            self.setup_network()\n            self.run_test()\n            success = TestStatus.PASSED\n        except JSONRPCException as e:\n            self.log.exception(\"JSONRPC error\")\n        except SkipTest as e:\n            self.log.warning(\"Test Skipped: %s\" % e.message)\n            success = TestStatus.SKIPPED\n        except AssertionError as e:\n            self.log.exception(\"Assertion failed\")\n        except KeyError as e:\n            self.log.exception(\"Key error\")\n        except Exception as e:\n            self.log.exception(\"Unexpected exception caught during testing\")\n        except KeyboardInterrupt as e:\n            self.log.warning(\"Exiting after keyboard interrupt\")\n\n        if success == TestStatus.FAILED and self.options.pdbonfailure:\n            print(\"Testcase failed. Attaching python debugger. Enter ? for help\")\n            pdb.set_trace()\n\n        self.log.debug('Closing down network thread')\n        self.network_thread.close()\n        if not self.options.noshutdown:\n            self.log.info(\"Stopping nodes\")\n            if self.nodes:\n                self.stop_nodes()\n        else:\n            for node in self.nodes:\n                node.cleanup_on_exit = False\n            self.log.info(\"Note: Munt-daemons were not stopped and may still be running\")\n\n        should_clean_up = (\n            not self.options.nocleanup and\n            not self.options.noshutdown and\n            success != TestStatus.FAILED and\n            not self.options.perf\n        )\n        if should_clean_up:\n            self.log.info(\"Cleaning up {} on exit\".format(self.options.tmpdir))\n            cleanup_tree_on_exit = True\n        elif self.options.perf:\n            self.log.warning(\"Not cleaning up dir {} due to perf data\".format(self.options.tmpdir))\n            cleanup_tree_on_exit = False\n        else:\n            self.log.warning(\"Not cleaning up dir {}\".format(self.options.tmpdir))\n            cleanup_tree_on_exit = False\n\n        if success == TestStatus.PASSED:\n            self.log.info(\"Tests successful\")\n            exit_code = TEST_EXIT_PASSED\n        elif success == TestStatus.SKIPPED:\n            self.log.info(\"Test skipped\")\n            exit_code = TEST_EXIT_SKIPPED\n        else:\n            self.log.error(\"Test failed. Test logging available at %s/test_framework.log\", self.options.tmpdir)\n            self.log.error(\"Hint: Call {} '{}' to consolidate all logs\".format(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + \"/../combine_logs.py\"), self.options.tmpdir))\n            exit_code = TEST_EXIT_FAILED\n        logging.shutdown()\n        if cleanup_tree_on_exit:\n            shutil.rmtree(self.options.tmpdir)\n        sys.exit(exit_code)\n\n    # Methods to override in subclass test scripts.\n    def set_test_params(self):\n        \"\"\"Tests must this method to change default values for number of nodes, topology, etc\"\"\"\n        raise NotImplementedError\n\n    def add_options(self, parser):\n        \"\"\"Override this method to add command-line options to the test\"\"\"\n        pass\n\n    def skip_test_if_missing_module(self):\n        \"\"\"Override this method to skip a test if a module is not compiled\"\"\"\n        pass\n\n    def setup_chain(self):\n        \"\"\"Override this method to customize blockchain setup\"\"\"\n        self.log.info(\"Initializing test directory \" + self.options.tmpdir)\n        if self.setup_clean_chain:\n            self._initialize_chain_clean()\n        else:\n            self._initialize_chain()\n\n    def setup_network(self):\n        \"\"\"Override this method to customize test network topology\"\"\"\n        self.setup_nodes()\n\n        # Connect the nodes as a \"chain\".  This allows us\n        # to split the network between nodes 1 and 2 to get\n        # two halves that can work on competing chains.\n        for i in range(self.num_nodes - 1):\n            connect_nodes_bi(self.nodes, i, i + 1)\n        self.sync_all()\n\n    def setup_nodes(self):\n        \"\"\"Override this method to customize test node setup\"\"\"\n        extra_args = None\n        if hasattr(self, \"extra_args\"):\n            extra_args = self.extra_args\n        self.add_nodes(self.num_nodes, extra_args)\n        self.start_nodes()\n        self.import_deterministic_coinbase_privkeys()\n        if not self.setup_clean_chain:\n            for n in self.nodes:\n                assert_equal(n.getblockchaininfo()[\"blocks\"], 199)\n            # To ensure that all nodes are out of IBD, the most recent block\n            # must have a timestamp not too old (see IsInitialBlockDownload()).\n            self.log.debug('Generate a block with current time')\n            block_hash = self.nodes[0].generate(1)[0]\n            block = self.nodes[0].getblock(blockhash=block_hash, verbosity=0)\n            for n in self.nodes:\n                n.submitblock(block)\n                chain_info = n.getblockchaininfo()\n                assert_equal(chain_info[\"blocks\"], 200)\n                ###assert_equal(chain_info[\"initialblockdownload\"], False)\n\n    def import_deterministic_coinbase_privkeys(self):\n        for n in self.nodes:\n            try:\n                n.getwalletinfo()\n            except JSONRPCException as e:\n                assert str(e).startswith('Method not found')\n                continue\n\n            n.createaccount(name=\"Legacy\", type=\"Legacy\")\n            n.setactiveaccount(account=\"Legacy\")\n            n.importprivkey(muntprivkey=n.get_deterministic_priv_key().key, account=\"Legacy\", label='coinbase')\n\n    def run_test(self):\n        \"\"\"Tests must override this method to define test logic\"\"\"\n        raise NotImplementedError\n\n    # Public helper methods. These can be accessed by the subclass test scripts.\n\n    def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):\n        \"\"\"Instantiate TestNode objects.\n\n        Should only be called once after the nodes have been specified in\n        set_test_params().\"\"\"\n        if self.bind_to_localhost_only:\n            extra_confs = [[\"bind=127.0.0.1\"]] * num_nodes\n        else:\n            extra_confs = [[]] * num_nodes\n        if extra_args is None:\n            extra_args = [[]] * num_nodes\n        if binary is None:\n            binary = [self.options.Munt_daemon] * num_nodes\n        assert_equal(len(extra_confs), num_nodes)\n        assert_equal(len(extra_args), num_nodes)\n        assert_equal(len(binary), num_nodes)\n        for i in range(num_nodes):\n            self.nodes.append(TestNode(\n                i,\n                get_datadir_path(self.options.tmpdir, i),\n                rpchost=rpchost,\n                timewait=self.rpc_timeout,\n                Munt_daemon=binary[i],\n                Munt_cli=self.options.muntcli,\n                coverage_dir=self.options.coveragedir,\n                cwd=self.options.tmpdir,\n                extra_conf=extra_confs[i],\n                extra_args=extra_args[i],\n                use_cli=self.options.usecli,\n                start_perf=self.options.perf,\n            ))\n\n    def start_node(self, i, *args, **kwargs):\n        \"\"\"Start a Munt-daemon\"\"\"\n\n        node = self.nodes[i]\n\n        node.start(*args, **kwargs)\n        node.wait_for_rpc_connection()\n\n        if self.options.coveragedir is not None:\n            coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)\n\n    def start_nodes(self, extra_args=None, *args, **kwargs):\n        \"\"\"Start multiple Munt-daemons\"\"\"\n\n        if extra_args is None:\n            extra_args = [None] * self.num_nodes\n        assert_equal(len(extra_args), self.num_nodes)\n        try:\n            for i, node in enumerate(self.nodes):\n                node.start(extra_args[i], *args, **kwargs)\n            for node in self.nodes:\n                node.wait_for_rpc_connection()\n        except:\n            # If one node failed to start, stop the others\n            self.stop_nodes()\n            raise\n\n        if self.options.coveragedir is not None:\n            for node in self.nodes:\n                coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)\n\n    def stop_node(self, i, expected_stderr='', wait=0):\n        \"\"\"Stop a Munt-deamon test node\"\"\"\n        self.nodes[i].stop_node(expected_stderr, wait=wait)\n        self.nodes[i].wait_until_stopped()\n\n    def stop_nodes(self, wait=0):\n        \"\"\"Stop multiple Munt-daemon test nodes\"\"\"\n        for node in self.nodes:\n            # Issue RPC to stop nodes\n            node.stop_node(wait=wait)\n\n        for node in self.nodes:\n            # Wait for nodes to stop\n            node.wait_until_stopped()\n\n    def restart_node(self, i, extra_args=None):\n        \"\"\"Stop and start a test node\"\"\"\n        self.stop_node(i)\n        self.start_node(i, extra_args)\n\n    def wait_for_node_exit(self, i, timeout):\n        self.nodes[i].process.wait(timeout)\n\n    def split_network(self):\n        \"\"\"\n        Split the network of four nodes into nodes 0/1 and 2/3.\n        \"\"\"\n        disconnect_nodes(self.nodes[1], 2)\n        disconnect_nodes(self.nodes[2], 1)\n        self.sync_all([self.nodes[:2], self.nodes[2:]])\n\n    def join_network(self):\n        \"\"\"\n        Join the (previously split) network halves together.\n        \"\"\"\n        connect_nodes_bi(self.nodes, 1, 2)\n        self.sync_all()\n\n    def sync_all(self, node_groups=None):\n        if not node_groups:\n            node_groups = [self.nodes]\n\n        for group in node_groups:\n            sync_blocks(group)\n            sync_mempools(group)\n\n    # Private helper methods. These should not be accessed by the subclass test scripts.\n\n    def _start_logging(self):\n        # Add logger and logging handlers\n        self.log = logging.getLogger('TestFramework')\n        self.log.setLevel(logging.DEBUG)\n        # Create file handler to log all messages\n        fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log', encoding='utf-8')\n        fh.setLevel(logging.DEBUG)\n        # Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel.\n        ch = logging.StreamHandler(sys.stdout)\n        # User can provide log level as a number or string (eg DEBUG). loglevel was caught as a string, so try to convert it to an int\n        ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper()\n        ch.setLevel(ll)\n        # Format logs the same as Munt-daemon's debug.log with microprecision (so log files can be concatenated and sorted)\n        formatter = logging.Formatter(fmt='%(asctime)s.%(msecs)03d000Z %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')\n        formatter.converter = time.gmtime\n        fh.setFormatter(formatter)\n        ch.setFormatter(formatter)\n        # add the handlers to the logger\n        self.log.addHandler(fh)\n        self.log.addHandler(ch)\n\n        if self.options.trace_rpc:\n            rpc_logger = logging.getLogger(\"MuntRPC\")\n            rpc_logger.setLevel(logging.DEBUG)\n            rpc_handler = logging.StreamHandler(sys.stdout)\n            rpc_handler.setLevel(logging.DEBUG)\n            rpc_logger.addHandler(rpc_handler)\n\n    def _initialize_chain(self):\n        \"\"\"Initialize a pre-mined blockchain for use by the test.\n\n        Create a cache of a 199-block-long chain (with wallet) for MAX_NODES\n        Afterward, create num_nodes copies from the cache.\"\"\"\n\n        assert self.num_nodes <= MAX_NODES\n        create_cache = False\n        for i in range(MAX_NODES):\n            if not os.path.isdir(get_datadir_path(self.options.cachedir, i)):\n                create_cache = True\n                break\n\n        if create_cache:\n            self.log.debug(\"Creating data directories from cached datadir\")\n\n            # find and delete old cache directories if any exist\n            for i in range(MAX_NODES):\n                if os.path.isdir(get_datadir_path(self.options.cachedir, i)):\n                    shutil.rmtree(get_datadir_path(self.options.cachedir, i))\n\n            # Create cache directories, run Munt-daemons:\n            for i in range(MAX_NODES):\n                datadir = initialize_datadir(self.options.cachedir, i)\n                args = [self.options.Munt_daemon, \"-datadir=\" + datadir, '-disablewallet']\n                if i > 0:\n                    args.append(\"-connect=127.0.0.1:\" + str(p2p_port(0)))\n                self.nodes.append(TestNode(\n                    i,\n                    get_datadir_path(self.options.cachedir, i),\n                    extra_conf=[\"bind=127.0.0.1\"],\n                    extra_args=[],\n                    rpchost=None,\n                    timewait=self.rpc_timeout,\n                    Munt_daemon=self.options.muntdaemon,\n                    Munt_cli=self.options.muntcli,\n                    coverage_dir=None,\n                    cwd=self.options.tmpdir,\n                ))\n                self.nodes[i].args = args\n                self.start_node(i)\n\n            # Wait for RPC connections to be ready\n            for node in self.nodes:\n                node.wait_for_rpc_connection()\n\n            # Create a 199-block-long chain; each of the 4 first nodes\n            # gets 25 mature blocks and 25 immature.\n            # The 4th node gets only 24 immature blocks so that the very last\n            # block in the cache does not age too much (have an old tip age).\n            # This is needed so that we are out of IBD when the test starts,\n            # see the tip age check in IsInitialBlockDownload().\n            for i in range(8):\n                self.nodes[0].generatetoaddress(25 if i != 7 else 24, self.nodes[i % 4].get_deterministic_priv_key().address)\n            sync_blocks(self.nodes)\n\n            for n in self.nodes:\n                assert_equal(n.getblockchaininfo()[\"blocks\"], 199)\n\n            # Shut them down, and clean up cache directories:\n            self.stop_nodes()\n            self.nodes = []\n\n            def cache_path(n, *paths):\n                return os.path.join(get_datadir_path(self.options.cachedir, n), \"regtestlegacy\", *paths)\n\n            for i in range(MAX_NODES):\n                for entry in os.listdir(cache_path(i)):\n                    if entry not in ['chainstate', 'blocks', 'witstate', 'autocheckpoints']:\n                        os.remove(cache_path(i, entry))\n\n        for i in range(self.num_nodes):\n            from_dir = get_datadir_path(self.options.cachedir, i)\n            to_dir = get_datadir_path(self.options.tmpdir, i)\n            shutil.copytree(from_dir, to_dir)\n            initialize_datadir(self.options.tmpdir, i)  # Overwrite port/rpcport in munt.conf\n\n    def _initialize_chain_clean(self):\n        \"\"\"Initialize empty blockchain for use by the test.\n\n        Create an empty blockchain and num_nodes wallets.\n        Useful if a test case wants complete control over initialization.\"\"\"\n        for i in range(self.num_nodes):\n            initialize_datadir(self.options.tmpdir, i)\n\n    def skip_if_no_py3_zmq(self):\n        \"\"\"Attempt to import the zmq package and skip the test if the import fails.\"\"\"\n        try:\n            import zmq  # noqa\n        except ImportError:\n            raise SkipTest(\"python3-zmq module not available.\")\n\n    def skip_if_no_daemon_zmq(self):\n        \"\"\"Skip the running test if Munt-daemon has not been compiled with zmq support.\"\"\"\n        if not self.is_zmq_compiled():\n            raise SkipTest(\"daemon has not been built with zmq enabled.\")\n\n    def skip_if_no_wallet(self):\n        \"\"\"Skip the running test if wallet has not been compiled.\"\"\"\n        if not self.is_wallet_compiled():\n            raise SkipTest(\"wallet has not been compiled.\")\n\n    def skip_if_no_cli(self):\n        \"\"\"Skip the running test if Munt-cli has not been compiled.\"\"\"\n        if not self.is_cli_compiled():\n            raise SkipTest(\"Munt-cli has not been compiled.\")\n\n    def is_cli_compiled(self):\n        \"\"\"Checks whether Munt-cli was compiled.\"\"\"\n        config = configparser.ConfigParser()\n        config.read_file(open(self.options.configfile))\n\n        return config[\"components\"].getboolean(\"ENABLE_CLI\")\n\n    def is_wallet_compiled(self):\n        \"\"\"Checks whether the wallet module was compiled.\"\"\"\n        config = configparser.ConfigParser()\n        config.read_file(open(self.options.configfile))\n\n        return config[\"components\"].getboolean(\"ENABLE_WALLET\")\n\n    def is_zmq_compiled(self):\n        \"\"\"Checks whether the zmq module was compiled.\"\"\"\n        config = configparser.ConfigParser()\n        config.read_file(open(self.options.configfile))\n\n        return config[\"components\"].getboolean(\"ENABLE_ZMQ\")\n"
  },
  {
    "path": "test/functional/test_framework/test_node.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Class for Munt-daemon node under test\"\"\"\n\nimport contextlib\nimport decimal\nimport errno\nfrom enum import Enum\nimport http.client\nimport json\nimport logging\nimport os\nimport re\nimport subprocess\nimport tempfile\nimport time\nimport urllib.parse\nimport collections\nimport shlex\nimport sys\n\nfrom .authproxy import JSONRPCException\nfrom .util import (\n    append_config,\n    delete_cookie_file,\n    get_rpc_proxy,\n    rpc_url,\n    wait_until,\n    p2p_port,\n)\n\nDAEMON_PROC_WAIT_TIMEOUT = 60\n\n\nclass FailedToStartError(Exception):\n    \"\"\"Raised when a node fails to start correctly.\"\"\"\n\n\nclass ErrorMatch(Enum):\n    FULL_TEXT = 1\n    FULL_REGEX = 2\n    PARTIAL_REGEX = 3\n    PARTIAL_TEXT = 4\n\n\nclass TestNode():\n    \"\"\"A class for representing a Munt-daemon node under test.\n\n    This class contains:\n\n    - state about the node (whether it's running, etc)\n    - a Python subprocess.Popen object representing the running process\n    - an RPC connection to the node\n    - one or more P2P connections to the node\n\n\n    To make things easier for the test writer, any unrecognised messages will\n    be dispatched to the RPC connection.\"\"\"\n\n    def __init__(self, i, datadir, *, rpchost, timewait, Munt_daemon, Munt_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False):\n        \"\"\"\n        Kwargs:\n            start_perf (bool): If True, begin profiling the node with `perf` as soon as\n                the node starts.\n        \"\"\"\n\n        self.index = i\n        self.datadir = datadir\n        self.stdout_dir = os.path.join(self.datadir, \"stdout\")\n        self.stderr_dir = os.path.join(self.datadir, \"stderr\")\n        self.rpchost = rpchost\n        self.rpc_timeout = timewait\n        self.binary = Munt-daemon\n        self.coverage_dir = coverage_dir\n        self.cwd = cwd\n        if extra_conf is not None:\n            append_config(datadir, extra_conf)\n        # Most callers will just need to add extra args to the standard list below.\n        # For those callers that need more flexibility, they can just set the args property directly.\n        # Note that common args are set in the config file (see initialize_datadir)\n        self.extra_args = extra_args\n        self.args = [\n            self.binary,\n            \"-datadir=\" + self.datadir,\n            \"-logtimemicros\",\n            \"-debug\",\n            \"-debugexclude=libevent\",\n            \"-debugexclude=leveldb\",\n            \"-uacomment=testnode%d\" % i,\n        ]\n\n        self.cli = TestNodeCLI(Munt_cli, self.datadir)\n        self.use_cli = use_cli\n        self.start_perf = start_perf\n\n        self.running = False\n        self.process = None\n        self.rpc_connected = False\n        self.rpc = None\n        self.url = None\n        self.log = logging.getLogger('TestFramework.node%d' % i)\n        self.cleanup_on_exit = True # Whether to kill the node when this object goes away\n        # Cache perf subprocesses here by their data output filename.\n        self.perf_subprocesses = {}\n\n        self.p2ps = []\n\n    def get_deterministic_priv_key(self):\n        \"\"\"Return a deterministic priv key in base58, that only depends on the node's index\"\"\"\n        AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])\n        PRIV_KEYS = [\n            # address , privkey\n            AddressKeyPair('RAfi93sGHe4ZaN9gy7qGzQSoqiFRG6tKBL', 'Utt31s2vDFPPSDMXfdQGUn2sbH7Q7PNEEZVc2vFnQ8Qk5ExrMPNf'),\n            AddressKeyPair('RMqiJNr6JmX9thenyRDFmfpVyur9H9isqi', 'Uu7pw5cGXTt8XXP1JmkouaKUoL3gvPrdwE8gbjMiFwt7wPdAi5iu'),\n            AddressKeyPair('RCqMJRmK73i5Mrx6NYYD64xcWh3mG5We4v', 'Usye5nGW5ia6sWodnQ5GAkdFLFS5jyTQwopwRg3chaeBpTQCH1Zi'),\n            AddressKeyPair('RMmxSqGoQ98unSBQTxKK4ZJdK1nrL3a7Ft', 'UrXT9ZNzZM9fhXfFnU3dAdrEvmQ8x7t2BKfpBdHn5fqs8Bo7nApy'),\n            AddressKeyPair('RJmzb699dbYCw5h1FZtZy84Ro7uRPxn9mS', 'UvKnXStjJPYVBeUoC7kGgDhyqetQd6JUYjVhgxjKTa5omFARPPqM'),\n            AddressKeyPair('RSA8fgSRGNpxfE9oYwnUGArWUuj1JvbAFJ', 'UqAMhWCepuMPFGpJGk7ezcK3VVDXFVAwi8y2VakvEaNQaAe4Uydm'),\n            AddressKeyPair('RWCxDSBYgnvFQqmswHUEdvGA5BeAFgvJyd', 'UvstGi613t64Erp7ezTuqwLnnvdKie9XkpQgtsFekVogRwM93F6V'),\n            AddressKeyPair('R9Zwd7WietYMGVugrFNq7ZB3zJU2wDNnJM', 'Uui876wttEpme1vLArHt8NFgYGfnYTLiqLVpkX1TtJN3dx7iYQmS'),\n            AddressKeyPair('RLuyaiWv3ZVcxMmMb61NBtkb4xUoBmStwm', 'UqzqNnYDK1K8s454m9HQm78N5YZHmxvpBDHAyBddCs2dSjvfzY2x'),\n        ]\n        return PRIV_KEYS[self.index]\n\n    def get_mem_rss_kilobytes(self):\n        \"\"\"Get the memory usage (RSS) per `ps`.\n\n        Returns None if `ps` is unavailable.\n        \"\"\"\n        assert self.running\n\n        try:\n            return int(subprocess.check_output(\n                [\"ps\", \"h\", \"-o\", \"rss\", \"{}\".format(self.process.pid)],\n                stderr=subprocess.DEVNULL).split()[-1])\n\n        # Avoid failing on platforms where ps isn't installed.\n        #\n        # We could later use something like `psutils` to work across platforms.\n        except (FileNotFoundError, subprocess.SubprocessError):\n            self.log.exception(\"Unable to get memory usage\")\n            return None\n\n    def _node_msg(self, msg: str) -> str:\n        \"\"\"Return a modified msg that identifies this node by its index as a debugging aid.\"\"\"\n        return \"[node %d] %s\" % (self.index, msg)\n\n    def _raise_assertion_error(self, msg: str):\n        \"\"\"Raise an AssertionError with msg modified to identify this node.\"\"\"\n        raise AssertionError(self._node_msg(msg))\n\n    def __del__(self):\n        # Ensure that we don't leave any Munt-daemon processes lying around after\n        # the test ends\n        if self.process and self.cleanup_on_exit:\n            # Should only happen on test failure\n            # Avoid using logger, as that may have already been shutdown when\n            # this destructor is called.\n            print(self._node_msg(\"Cleaning up leftover process\"))\n            self.process.kill()\n\n    def __getattr__(self, name):\n        \"\"\"Dispatches any unrecognised messages to the RPC connection or a CLI instance.\"\"\"\n        if self.use_cli:\n            return getattr(self.cli, name)\n        else:\n            assert self.rpc_connected and self.rpc is not None, self._node_msg(\"Error: no RPC connection\")\n            return getattr(self.rpc, name)\n\n    def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs):\n        \"\"\"Start the node.\"\"\"\n        if extra_args is None:\n            extra_args = self.extra_args\n\n        # Add a new stdout and stderr file each time Munt-daemon is started\n        if stderr is None:\n            stderr = tempfile.NamedTemporaryFile(dir=self.stderr_dir, delete=False)\n        if stdout is None:\n            stdout = tempfile.NamedTemporaryFile(dir=self.stdout_dir, delete=False)\n        self.stderr = stderr\n        self.stdout = stdout\n\n        if cwd is None:\n            cwd = self.cwd\n\n        # Delete any existing cookie file -- if such a file exists (eg due to\n        # unclean shutdown), it will get overwritten anyway by Munt-daemon, and\n        # potentially interfere with our attempt to authenticate\n        delete_cookie_file(self.datadir)\n\n        # add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal\n        subp_env = dict(os.environ, LIBC_FATAL_STDERR_=\"1\")\n\n        self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, cwd=cwd, **kwargs)\n\n        self.running = True\n        self.log.debug(\"Munt-daemon started, waiting for RPC to come up\")\n\n        if self.start_perf:\n            self._start_perf()\n\n    def wait_for_rpc_connection(self):\n        \"\"\"Sets up an RPC connection to the Munt-daemon process. Returns False if unable to connect.\"\"\"\n        # Poll at a rate of four times per second\n        poll_per_s = 4\n        for _ in range(poll_per_s * self.rpc_timeout):\n            if self.process.poll() is not None:\n                raise FailedToStartError(self._node_msg(\n                    'Munt-daemon exited with status {} during initialization'.format(self.process.returncode)))\n            try:\n                rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)\n                rpc.getblockcount()\n                # If the call to getblockcount() succeeds then the RPC connection is up\n                self.log.debug(\"RPC successfully started\")\n                if self.use_cli:\n                    return\n                self.rpc = rpc\n                self.rpc_connected = True\n                self.url = self.rpc.url\n                return\n            except IOError as e:\n                if e.errno != errno.ECONNREFUSED:  # Port not yet open?\n                    raise  # unknown IO error\n            except JSONRPCException as e:  # Initialization phase\n                # -28 RPC in warmup\n                # -342 Service unavailable, RPC server started but is shutting down due to error\n                if e.error['code'] != -28 and e.error['code'] != -342:\n                    raise  # unknown JSON RPC exception\n            except ValueError as e:  # cookie file not found and no rpcuser or rpcassword. Munt-daemon still starting\n                if \"No RPC credentials\" not in str(e):\n                    raise\n            time.sleep(1.0 / poll_per_s)\n        self._raise_assertion_error(\"Unable to connect to Munt-daemon\")\n\n    def generate(self, num_blocks, max_tries=1000000):\n        self.log.debug(\"TestNode.generate() dispatches `generate` call to `generatetoaddress`\")\n        return self.generatetoaddress(num_blocks=num_blocks, address=self.get_deterministic_priv_key().address, max_tries=max_tries)\n\n    def get_wallet_rpc(self, wallet_name):\n        if self.use_cli:\n            return self.cli(\"-rpcwallet={}\".format(wallet_name))\n        else:\n            assert self.rpc_connected and self.rpc, self._node_msg(\"RPC not connected\")\n            wallet_path = \"wallet/{}\".format(urllib.parse.quote(wallet_name))\n            return self.rpc / wallet_path\n\n    def stop_node(self, expected_stderr='', wait=0):\n        \"\"\"Stop the node.\"\"\"\n        if not self.running:\n            return\n        self.log.debug(\"Stopping node\")\n        try:\n            self.stop(wait=wait)\n        except http.client.CannotSendRequest:\n            self.log.exception(\"Unable to stop node.\")\n\n        # If there are any running perf processes, stop them.\n        for profile_name in tuple(self.perf_subprocesses.keys()):\n            self._stop_perf(profile_name)\n\n        # Check that stderr is as expected\n        self.stderr.seek(0)\n        stderr = self.stderr.read().decode('utf-8').strip()\n        if stderr != expected_stderr:\n            raise AssertionError(\"Unexpected stderr {} != {}\".format(stderr, expected_stderr))\n\n        self.stdout.close()\n        self.stderr.close()\n\n        del self.p2ps[:]\n\n    def is_node_stopped(self):\n        \"\"\"Checks whether the node has stopped.\n\n        Returns True if the node has stopped. False otherwise.\n        This method is responsible for freeing resources (self.process).\"\"\"\n        if not self.running:\n            return True\n        return_code = self.process.poll()\n        if return_code is None:\n            return False\n\n        # process has stopped. Assert that it didn't return an error code.\n        assert return_code == 0, self._node_msg(\n            \"Node returned non-zero exit code (%d) when stopping\" % return_code)\n        self.running = False\n        self.process = None\n        self.rpc_connected = False\n        self.rpc = None\n        self.log.debug(\"Node stopped\")\n        return True\n\n    def wait_until_stopped(self, timeout=DAEMON_PROC_WAIT_TIMEOUT):\n        wait_until(self.is_node_stopped, timeout=timeout)\n\n    @contextlib.contextmanager\n    def assert_debug_log(self, expected_msgs):\n        debug_log = os.path.join(self.datadir, 'regtestlegacy', 'debug.log')\n        with open(debug_log, encoding='utf-8') as dl:\n            dl.seek(0, 2)\n            prev_size = dl.tell()\n        try:\n            yield\n        finally:\n            with open(debug_log, encoding='utf-8') as dl:\n                dl.seek(prev_size)\n                log = dl.read()\n            print_log = \" - \" + \"\\n - \".join(log.splitlines())\n            for expected_msg in expected_msgs:\n                if re.search(re.escape(expected_msg), log, flags=re.MULTILINE) is None:\n                    self._raise_assertion_error('Expected message \"{}\" does not partially match log:\\n\\n{}\\n\\n'.format(expected_msg, print_log))\n\n    @contextlib.contextmanager\n    def assert_memory_usage_stable(self, *, increase_allowed=0.03):\n        \"\"\"Context manager that allows the user to assert that a node's memory usage (RSS)\n        hasn't increased beyond some threshold percentage.\n\n        Args:\n            increase_allowed (float): the fractional increase in memory allowed until failure;\n                e.g. `0.12` for up to 12% increase allowed.\n        \"\"\"\n        before_memory_usage = self.get_mem_rss_kilobytes()\n\n        yield\n\n        after_memory_usage = self.get_mem_rss_kilobytes()\n\n        if not (before_memory_usage and after_memory_usage):\n            self.log.warning(\"Unable to detect memory usage (RSS) - skipping memory check.\")\n            return\n\n        perc_increase_memory_usage = (after_memory_usage / before_memory_usage) - 1\n\n        if perc_increase_memory_usage > increase_allowed:\n            self._raise_assertion_error(\n                \"Memory usage increased over threshold of {:.3f}% from {} to {} ({:.3f}%)\".format(\n                    increase_allowed * 100, before_memory_usage, after_memory_usage,\n                    perc_increase_memory_usage * 100))\n\n    @contextlib.contextmanager\n    def profile_with_perf(self, profile_name):\n        \"\"\"\n        Context manager that allows easy profiling of node activity using `perf`.\n\n        See `test/functional/README.md` for details on perf usage.\n\n        Args:\n            profile_name (str): This string will be appended to the\n                profile data filename generated by perf.\n        \"\"\"\n        subp = self._start_perf(profile_name)\n\n        yield\n\n        if subp:\n            self._stop_perf(profile_name)\n\n    def _start_perf(self, profile_name=None):\n        \"\"\"Start a perf process to profile this node.\n\n        Returns the subprocess running perf.\"\"\"\n        subp = None\n\n        def test_success(cmd):\n            return subprocess.call(\n                # shell=True required for pipe use below\n                cmd, shell=True,\n                stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0\n\n        if not sys.platform.startswith('linux'):\n            self.log.warning(\"Can't profile with perf; only availabe on Linux platforms\")\n            return None\n\n        if not test_success('which perf'):\n            self.log.warning(\"Can't profile with perf; must install perf-tools\")\n            return None\n\n        if not test_success('readelf -S {} | grep .debug_str'.format(shlex.quote(self.binary))):\n            self.log.warning(\n                \"perf output won't be very useful without debug symbols compiled into Munt-daemon\")\n\n        output_path = tempfile.NamedTemporaryFile(\n            dir=self.datadir,\n            prefix=\"{}.perf.data.\".format(profile_name or 'test'),\n            delete=False,\n        ).name\n\n        cmd = [\n            'perf', 'record',\n            '-g',                     # Record the callgraph.\n            '--call-graph', 'dwarf',  # Compatibility for gcc's --fomit-frame-pointer.\n            '-F', '101',              # Sampling frequency in Hz.\n            '-p', str(self.process.pid),\n            '-o', output_path,\n        ]\n        subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n        self.perf_subprocesses[profile_name] = subp\n\n        return subp\n\n    def _stop_perf(self, profile_name):\n        \"\"\"Stop (and pop) a perf subprocess.\"\"\"\n        subp = self.perf_subprocesses.pop(profile_name)\n        output_path = subp.args[subp.args.index('-o') + 1]\n\n        subp.terminate()\n        subp.wait(timeout=10)\n\n        stderr = subp.stderr.read().decode()\n        if 'Consider tweaking /proc/sys/kernel/perf_event_paranoid' in stderr:\n            self.log.warning(\n                \"perf couldn't collect data! Try \"\n                \"'sudo sysctl -w kernel.perf_event_paranoid=-1'\")\n        else:\n            report_cmd = \"perf report -i {}\".format(output_path)\n            self.log.info(\"See perf output by running '{}'\".format(report_cmd))\n\n    def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs):\n        \"\"\"Attempt to start the node and expect it to raise an error.\n\n        extra_args: extra arguments to pass through to Munt-daemon\n        expected_msg: regex that stderr should match when Munt-daemon fails\n\n        Will throw if Munt-daemon starts without an error.\n        Will throw if an expected_msg is provided and it does not match Munt-daemon's stdout.\"\"\"\n        with tempfile.NamedTemporaryFile(dir=self.stderr_dir, delete=False) as log_stderr, \\\n             tempfile.NamedTemporaryFile(dir=self.stdout_dir, delete=False) as log_stdout:\n            try:\n                self.start(extra_args, stdout=log_stdout, stderr=log_stderr, *args, **kwargs)\n                self.wait_for_rpc_connection()\n                self.stop_node()\n                self.wait_until_stopped()\n            except FailedToStartError as e:\n                self.log.debug('Munt-daemon failed to start: %s', e)\n                self.running = False\n                self.process = None\n                # Check stderr for expected message\n                if expected_msg is not None:\n                    log_stderr.seek(0)\n                    stderr = log_stderr.read().decode('utf-8').strip()\n                    if match == ErrorMatch.PARTIAL_REGEX:\n                        if re.search(expected_msg, stderr, flags=re.MULTILINE) is None:\n                            self._raise_assertion_error(\n                                'Expected message \"{}\" does not partially regex match stderr:\\n\"{}\"'.format(expected_msg, stderr))\n                    elif match == ErrorMatch.FULL_REGEX:\n                        if re.fullmatch(expected_msg, stderr) is None:\n                            self._raise_assertion_error(\n                                'Expected message \"{}\" does not fully regex match stderr:\\n\"{}\"'.format(expected_msg, stderr))\n                    elif match == ErrorMatch.FULL_TEXT:\n                        if expected_msg != stderr:\n                            self._raise_assertion_error(\n                                'Expected message \"{}\" does not fully text match stderr:\\n\"{}\"'.format(expected_msg, stderr))\n                    elif match == ErrorMatch.PARTIAL_TEXT:\n                        if stderr.find(expected_msg) != -1:\n                            self._raise_assertion_error(\n                                'Expected message \"{}\" does not partially text match stderr:\\n\"{}\"'.format(expected_msg, stderr))\n            else:\n                if expected_msg is None:\n                    assert_msg = \"Munt-daemon should have exited with an error\"\n                else:\n                    assert_msg = \"Munt-daemon should have exited with expected error \" + expected_msg\n                self._raise_assertion_error(assert_msg)\n\n    def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):\n        \"\"\"Add a p2p connection to the node.\n\n        This method adds the p2p connection to the self.p2ps list and also\n        returns the connection to the caller.\"\"\"\n        if 'dstport' not in kwargs:\n            kwargs['dstport'] = p2p_port(self.index)\n        if 'dstaddr' not in kwargs:\n            kwargs['dstaddr'] = '127.0.0.1'\n\n        p2p_conn.peer_connect(**kwargs)()\n        self.p2ps.append(p2p_conn)\n        if wait_for_verack:\n            p2p_conn.wait_for_verack()\n\n        return p2p_conn\n\n    @property\n    def p2p(self):\n        \"\"\"Return the first p2p connection\n\n        Convenience property - most tests only use a single p2p connection to each\n        node, so this saves having to write node.p2ps[0] many times.\"\"\"\n        assert self.p2ps, self._node_msg(\"No p2p connection\")\n        return self.p2ps[0]\n\n    def disconnect_p2ps(self):\n        \"\"\"Close all p2p connections to the node.\"\"\"\n        for p in self.p2ps:\n            p.peer_disconnect()\n        del self.p2ps[:]\n\nclass TestNodeCLIAttr:\n    def __init__(self, cli, command):\n        self.cli = cli\n        self.command = command\n\n    def __call__(self, *args, **kwargs):\n        return self.cli.send_cli(self.command, *args, **kwargs)\n\n    def get_request(self, *args, **kwargs):\n        return lambda: self(*args, **kwargs)\n\ndef arg_to_cli(arg):\n    if isinstance(arg, bool):\n        return str(arg).lower()\n    elif isinstance(arg, dict) or isinstance(arg, list):\n        return json.dumps(arg)\n    else:\n        return str(arg)\n\nclass TestNodeCLI():\n    \"\"\"Interface to Munt-cli for an individual node\"\"\"\n\n    def __init__(self, binary, datadir):\n        self.options = []\n        self.binary = binary\n        self.datadir = datadir\n        self.input = None\n        self.log = logging.getLogger('TestFramework.muntcli')\n\n    def __call__(self, *options, input=None):\n        # TestNodeCLI is callable with Munt-cli command-line options\n        cli = TestNodeCLI(self.binary, self.datadir)\n        cli.options = [str(o) for o in options]\n        cli.input = input\n        return cli\n\n    def __getattr__(self, command):\n        return TestNodeCLIAttr(self, command)\n\n    def batch(self, requests):\n        results = []\n        for request in requests:\n            try:\n                results.append(dict(result=request()))\n            except JSONRPCException as e:\n                results.append(dict(error=e))\n        return results\n\n    def send_cli(self, command=None, *args, **kwargs):\n        \"\"\"Run Munt-cli command. Deserializes returned string as python object.\"\"\"\n        pos_args = [arg_to_cli(arg) for arg in args]\n        named_args = [str(key) + \"=\" + arg_to_cli(value) for (key, value) in kwargs.items()]\n        assert not (pos_args and named_args), \"Cannot use positional arguments and named arguments in the same Munt-cli call\"\n        p_args = [self.binary, \"-datadir=\" + self.datadir] + self.options\n        if named_args:\n            p_args += [\"-named\"]\n        if command is not None:\n            p_args += [command]\n        p_args += pos_args + named_args\n        self.log.debug(\"Running Munt-cli command: %s\" % command)\n        process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)\n        cli_stdout, cli_stderr = process.communicate(input=self.input)\n        returncode = process.poll()\n        if returncode:\n            match = re.match(r'error code: ([-0-9]+)\\nerror message:\\n(.*)', cli_stderr)\n            if match:\n                code, message = match.groups()\n                raise JSONRPCException(dict(code=int(code), message=message))\n            # Ignore cli_stdout, raise with cli_stderr\n            raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)\n        try:\n            return json.loads(cli_stdout, parse_float=decimal.Decimal)\n        except json.JSONDecodeError:\n            return cli_stdout.rstrip(\"\\n\")\n"
  },
  {
    "path": "test/functional/test_framework/util.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Helpful routines for regression testing.\"\"\"\n\nfrom base64 import b64encode\nfrom binascii import unhexlify\nfrom decimal import Decimal, ROUND_DOWN\nimport hashlib\nimport inspect\nimport json\nimport logging\nimport os\nimport random\nimport re\nfrom subprocess import CalledProcessError\nimport time\n\nfrom . import coverage\nfrom .authproxy import AuthServiceProxy, JSONRPCException\n\nlogger = logging.getLogger(\"TestFramework.utils\")\n\n# Assert functions\n##################\n\ndef assert_fee_amount(fee, tx_size, fee_per_kB):\n    \"\"\"Assert the fee was in range\"\"\"\n    target_fee = round(tx_size * fee_per_kB / 1000, 8)\n    if fee < target_fee:\n        raise AssertionError(\"Fee of %s BTC too low! (Should be %s BTC)\" % (str(fee), str(target_fee)))\n    # allow the wallet's estimation to be at most 2 bytes off\n    if fee > (tx_size + 2) * fee_per_kB / 1000:\n        raise AssertionError(\"Fee of %s BTC too high! (Should be %s BTC)\" % (str(fee), str(target_fee)))\n\ndef assert_equal(thing1, thing2, *args):\n    if thing1 != thing2 or any(thing1 != arg for arg in args):\n        raise AssertionError(\"not(%s)\" % \" == \".join(str(arg) for arg in (thing1, thing2) + args))\n\ndef assert_greater_than(thing1, thing2):\n    if thing1 <= thing2:\n        raise AssertionError(\"%s <= %s\" % (str(thing1), str(thing2)))\n\ndef assert_greater_than_or_equal(thing1, thing2):\n    if thing1 < thing2:\n        raise AssertionError(\"%s < %s\" % (str(thing1), str(thing2)))\n\ndef assert_raises(exc, fun, *args, **kwds):\n    assert_raises_message(exc, None, fun, *args, **kwds)\n\ndef assert_raises_message(exc, message, fun, *args, **kwds):\n    try:\n        fun(*args, **kwds)\n    except JSONRPCException:\n        raise AssertionError(\"Use assert_raises_rpc_error() to test RPC failures\")\n    except exc as e:\n        if message is not None and message not in e.error['message']:\n            raise AssertionError(\"Expected substring not found:\" + e.error['message'])\n    except Exception as e:\n        raise AssertionError(\"Unexpected exception raised: \" + type(e).__name__)\n    else:\n        raise AssertionError(\"No exception raised\")\n\ndef assert_raises_process_error(returncode, output, fun, *args, **kwds):\n    \"\"\"Execute a process and asserts the process return code and output.\n\n    Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError\n    and verifies that the return code and output are as expected. Throws AssertionError if\n    no CalledProcessError was raised or if the return code and output are not as expected.\n\n    Args:\n        returncode (int): the process return code.\n        output (string): [a substring of] the process output.\n        fun (function): the function to call. This should execute a process.\n        args*: positional arguments for the function.\n        kwds**: named arguments for the function.\n    \"\"\"\n    try:\n        fun(*args, **kwds)\n    except CalledProcessError as e:\n        if returncode != e.returncode:\n            raise AssertionError(\"Unexpected returncode %i\" % e.returncode)\n        if output not in e.output:\n            raise AssertionError(\"Expected substring not found:\" + e.output)\n    else:\n        raise AssertionError(\"No exception raised\")\n\ndef assert_raises_rpc_error(code, message, fun, *args, **kwds):\n    \"\"\"Run an RPC and verify that a specific JSONRPC exception code and message is raised.\n\n    Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException\n    and verifies that the error code and message are as expected. Throws AssertionError if\n    no JSONRPCException was raised or if the error code/message are not as expected.\n\n    Args:\n        code (int), optional: the error code returned by the RPC call (defined\n            in src/rpc/protocol.h). Set to None if checking the error code is not required.\n        message (string), optional: [a substring of] the error string returned by the\n            RPC call. Set to None if checking the error string is not required.\n        fun (function): the function to call. This should be the name of an RPC.\n        args*: positional arguments for the function.\n        kwds**: named arguments for the function.\n    \"\"\"\n    assert try_rpc(code, message, fun, *args, **kwds), \"No exception raised\"\n\ndef try_rpc(code, message, fun, *args, **kwds):\n    \"\"\"Tries to run an rpc command.\n\n    Test against error code and message if the rpc fails.\n    Returns whether a JSONRPCException was raised.\"\"\"\n    try:\n        fun(*args, **kwds)\n    except JSONRPCException as e:\n        # JSONRPCException was thrown as expected. Check the code and message values are correct.\n        if (code is not None) and (code != e.error[\"code\"]):\n            raise AssertionError(\"Unexpected JSONRPC error code %i\" % e.error[\"code\"])\n        if (message is not None) and (message not in e.error['message']):\n            raise AssertionError(\"Expected substring not found:\" + e.error['message'])\n        return True\n    except Exception as e:\n        raise AssertionError(\"Unexpected exception raised: \" + type(e).__name__)\n    else:\n        return False\n\ndef assert_is_hex_string(string):\n    try:\n        int(string, 16)\n    except Exception as e:\n        raise AssertionError(\n            \"Couldn't interpret %r as hexadecimal; raised: %s\" % (string, e))\n\ndef assert_is_hash_string(string, length=64):\n    if not isinstance(string, str):\n        raise AssertionError(\"Expected a string, got type %r\" % type(string))\n    elif length and len(string) != length:\n        raise AssertionError(\n            \"String of length %d expected; got %d\" % (length, len(string)))\n    elif not re.match('[abcdef0-9]+$', string):\n        raise AssertionError(\n            \"String %r contains invalid characters for a hash.\" % string)\n\ndef assert_array_result(object_array, to_match, expected, should_not_find=False):\n    \"\"\"\n        Pass in array of JSON objects, a dictionary with key/value pairs\n        to match against, and another dictionary with expected key/value\n        pairs.\n        If the should_not_find flag is true, to_match should not be found\n        in object_array\n        \"\"\"\n    if should_not_find:\n        assert_equal(expected, {})\n    num_matched = 0\n    for item in object_array:\n        all_match = True\n        for key, value in to_match.items():\n            if item[key] != value:\n                all_match = False\n        if not all_match:\n            continue\n        elif should_not_find:\n            num_matched = num_matched + 1\n        for key, value in expected.items():\n            if item[key] != value:\n                raise AssertionError(\"%s : expected %s=%s\" % (str(item), str(key), str(value)))\n            num_matched = num_matched + 1\n    if num_matched == 0 and not should_not_find:\n        raise AssertionError(\"No objects matched %s\" % (str(to_match)))\n    if num_matched > 0 and should_not_find:\n        raise AssertionError(\"Objects were found %s\" % (str(to_match)))\n\n# Utility functions\n###################\n\ndef check_json_precision():\n    \"\"\"Make sure json library being used does not lose precision converting BTC values\"\"\"\n    n = Decimal(\"20000000.00000003\")\n    satoshis = int(json.loads(json.dumps(float(n))) * 1.0e8)\n    if satoshis != 2000000000000003:\n        raise RuntimeError(\"JSON encode/decode loses precision\")\n\ndef count_bytes(hex_string):\n    return len(bytearray.fromhex(hex_string))\n\ndef hash256(byte_str):\n    sha256 = hashlib.sha256()\n    sha256.update(byte_str)\n    sha256d = hashlib.sha256()\n    sha256d.update(sha256.digest())\n    return sha256d.digest()[::-1]\n\ndef hex_str_to_bytes(hex_str):\n    return unhexlify(hex_str.encode('ascii'))\n\ndef str_to_b64str(string):\n    return b64encode(string.encode('utf-8')).decode('ascii')\n\ndef satoshi_round(amount):\n    return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)\n\ndef wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None):\n    if attempts == float('inf') and timeout == float('inf'):\n        timeout = 60\n    attempt = 0\n    time_end = time.time() + timeout\n\n    while attempt < attempts and time.time() < time_end:\n        if lock:\n            with lock:\n                if predicate():\n                    return\n        else:\n            if predicate():\n                return\n        attempt += 1\n        time.sleep(0.05)\n\n    # Print the cause of the timeout\n    predicate_source = inspect.getsourcelines(predicate)\n    logger.error(\"wait_until() failed. Predicate: {}\".format(predicate_source))\n    if attempt >= attempts:\n        raise AssertionError(\"Predicate {} not true after {} attempts\".format(predicate_source, attempts))\n    elif time.time() >= time_end:\n        raise AssertionError(\"Predicate {} not true after {} seconds\".format(predicate_source, timeout))\n    raise RuntimeError('Unreachable')\n\n# RPC/P2P connection constants and functions\n############################################\n\n# The maximum number of nodes a single test can spawn\nMAX_NODES = 8\n# Don't assign rpc or p2p ports lower than this\nPORT_MIN = 11000\n# The number of ports to \"reserve\" for p2p and rpc, each\nPORT_RANGE = 5000\n\nclass PortSeed:\n    # Must be initialized with a unique integer for each process\n    n = None\n\ndef get_rpc_proxy(url, node_number, timeout=None, coveragedir=None):\n    \"\"\"\n    Args:\n        url (str): URL of the RPC server to call\n        node_number (int): the node number (or id) that this calls to\n\n    Kwargs:\n        timeout (int): HTTP timeout in seconds\n\n    Returns:\n        AuthServiceProxy. convenience object for making RPC calls.\n\n    \"\"\"\n    proxy_kwargs = {}\n    if timeout is not None:\n        proxy_kwargs['timeout'] = timeout\n\n    proxy = AuthServiceProxy(url, **proxy_kwargs)\n    proxy.url = url  # store URL on proxy for info\n\n    coverage_logfile = coverage.get_filename(\n        coveragedir, node_number) if coveragedir else None\n\n    return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile)\n\ndef p2p_port(n):\n    assert n <= MAX_NODES\n    return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)\n\ndef rpc_port(n):\n    return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)\n\ndef rpc_url(datadir, i, rpchost=None):\n    rpc_u, rpc_p = get_auth_cookie(datadir)\n    host = '127.0.0.1'\n    port = rpc_port(i)\n    if rpchost:\n        parts = rpchost.split(':')\n        if len(parts) == 2:\n            host, port = parts\n        else:\n            host = rpchost\n    return \"http://%s:%s@%s:%d\" % (rpc_u, rpc_p, host, int(port))\n\n# Node functions\n################\n\ndef initialize_datadir(dirname, n):\n    datadir = get_datadir_path(dirname, n)\n    if not os.path.isdir(datadir):\n        os.makedirs(datadir)\n    with open(os.path.join(datadir, \"munt.conf\"), 'w', encoding='utf8') as f:\n        f.write(\"regtestlegacy=1\\n\")\n        f.write(\"[regtestlegacy]\\n\")\n        f.write(\"port=\" + str(p2p_port(n)) + \"\\n\")\n        f.write(\"rpcport=\" + str(rpc_port(n)) + \"\\n\")\n        f.write(\"server=1\\n\")\n        f.write(\"debug=1\\n\")\n        f.write(\"keypool=1\\n\")\n        f.write(\"discover=0\\n\")\n        f.write(\"listenonion=0\\n\")\n        f.write(\"printtoconsole=0\\n\")\n        os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)\n        os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)\n    return datadir\n\ndef get_datadir_path(dirname, n):\n    return os.path.join(dirname, \"node\" + str(n))\n\ndef append_config(datadir, options):\n    with open(os.path.join(datadir, \"munt.conf\"), 'a', encoding='utf8') as f:\n        for option in options:\n            f.write(option + \"\\n\")\n\ndef get_auth_cookie(datadir):\n    user = None\n    password = None\n    if os.path.isfile(os.path.join(datadir, \"munt.conf\")):\n        with open(os.path.join(datadir, \"munt.conf\"), 'r', encoding='utf8') as f:\n            for line in f:\n                if line.startswith(\"rpcuser=\"):\n                    assert user is None  # Ensure that there is only one rpcuser line\n                    user = line.split(\"=\")[1].strip(\"\\n\")\n                if line.startswith(\"rpcpassword=\"):\n                    assert password is None  # Ensure that there is only one rpcpassword line\n                    password = line.split(\"=\")[1].strip(\"\\n\")\n    if os.path.isfile(os.path.join(datadir, \"regtestlegacy\", \".cookie\")) and os.access(os.path.join(datadir, \"regtestlegacy\", \".cookie\"), os.R_OK):\n        with open(os.path.join(datadir, \"regtestlegacy\", \".cookie\"), 'r', encoding=\"ascii\") as f:\n            userpass = f.read()\n            split_userpass = userpass.split(':')\n            user = split_userpass[0]\n            password = split_userpass[1]\n    if user is None or password is None:\n        raise ValueError(\"No RPC credentials\")\n    return user, password\n\n# If a cookie file exists in the given datadir, delete it.\ndef delete_cookie_file(datadir):\n    if os.path.isfile(os.path.join(datadir, \"regtestlegacy\", \".cookie\")):\n        logger.debug(\"Deleting leftover cookie file\")\n        os.remove(os.path.join(datadir, \"regtestlegacy\", \".cookie\"))\n\ndef get_bip9_status(node, key):\n    info = node.getblockchaininfo()\n    return info['bip9_softforks'][key]\n\ndef set_node_times(nodes, t):\n    for node in nodes:\n        node.setmocktime(t)\n\ndef disconnect_nodes(from_connection, node_num):\n    for peer_id in [peer['id'] for peer in from_connection.getpeerinfo() if \"testnode%d\" % node_num in peer['subver']]:\n        try:\n            from_connection.disconnectnode(node_id=peer_id)\n        except JSONRPCException as e:\n            # If this node is disconnected between calculating the peer id\n            # and issuing the disconnect, don't worry about it.\n            # This avoids a race condition if we're mass-disconnecting peers.\n            if e.error['code'] != -29: # RPC_CLIENT_NODE_NOT_CONNECTED\n                raise\n\n    # wait to disconnect\n    wait_until(lambda: [peer['id'] for peer in from_connection.getpeerinfo() if \"testnode%d\" % node_num in peer['subver']] == [], timeout=5)\n\ndef connect_nodes(from_connection, node_num):\n    ip_port = \"127.0.0.1:\" + str(p2p_port(node_num))\n    from_connection.addnode(ip_port, \"onetry\")\n    # poll until version handshake complete to avoid race conditions\n    # with transaction relaying\n    wait_until(lambda:  all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))\n\ndef connect_nodes_bi(nodes, a, b):\n    connect_nodes(nodes[a], b)\n    connect_nodes(nodes[b], a)\n\ndef sync_blocks(rpc_connections, *, wait=1, timeout=60):\n    \"\"\"\n    Wait until everybody has the same tip.\n\n    sync_blocks needs to be called with an rpc_connections set that has least\n    one node already synced to the latest, stable tip, otherwise there's a\n    chance it might return before all nodes are stably synced.\n    \"\"\"\n    stop_time = time.time() + timeout\n    while time.time() <= stop_time:\n        best_hash = [x.getbestblockhash() for x in rpc_connections]\n        if best_hash.count(best_hash[0]) == len(rpc_connections):\n            return\n        time.sleep(wait)\n    raise AssertionError(\"Block sync timed out:{}\".format(\"\".join(\"\\n  {!r}\".format(b) for b in best_hash)))\n\ndef sync_mempools(rpc_connections, *, wait=1, timeout=60, flush_scheduler=True):\n    \"\"\"\n    Wait until everybody has the same transactions in their memory\n    pools\n    \"\"\"\n    stop_time = time.time() + timeout\n    while time.time() <= stop_time:\n        pool = [set(r.getrawmempool()) for r in rpc_connections]\n        ###if pool.count(pool[0]) == len(rpc_connections):\n            ###if flush_scheduler:\n                ###for r in rpc_connections:\n                    ###r.syncwithvalidationinterfacequeue()\n            ###return\n        time.sleep(wait)\n        return\n    raise AssertionError(\"Mempool sync timed out:{}\".format(\"\".join(\"\\n  {!r}\".format(m) for m in pool)))\n\n# Transaction/Block functions\n#############################\n\ndef find_output(node, txid, amount, *, blockhash=None):\n    \"\"\"\n    Return index to output of txid with value amount\n    Raises exception if there is none.\n    \"\"\"\n    txdata = node.getrawtransaction(txid, 1, blockhash)\n    for i in range(len(txdata[\"vout\"])):\n        if txdata[\"vout\"][i][\"value\"] == amount:\n            return i\n    raise RuntimeError(\"find_output txid %s : %s not found\" % (txid, str(amount)))\n\ndef gather_inputs(from_node, amount_needed, confirmations_required=1):\n    \"\"\"\n    Return a random set of unspent txouts that are enough to pay amount_needed\n    \"\"\"\n    assert confirmations_required >= 0\n    utxo = from_node.listunspent(confirmations_required)\n    random.shuffle(utxo)\n    inputs = []\n    total_in = Decimal(\"0.00000000\")\n    while total_in < amount_needed and len(utxo) > 0:\n        t = utxo.pop()\n        total_in += t[\"amount\"]\n        inputs.append({\"txid\": t[\"txid\"], \"vout\": t[\"vout\"], \"address\": t[\"address\"]})\n    if total_in < amount_needed:\n        raise RuntimeError(\"Insufficient funds: need %d, have %d\" % (amount_needed, total_in))\n    return (total_in, inputs)\n\ndef make_change(from_node, amount_in, amount_out, fee):\n    \"\"\"\n    Create change output(s), return them\n    \"\"\"\n    outputs = {}\n    amount = amount_out + fee\n    change = amount_in - amount\n    if change > amount * 2:\n        # Create an extra change output to break up big inputs\n        change_address = from_node.getnewaddress()\n        # Split change in two, being careful of rounding:\n        outputs[change_address] = Decimal(change / 2).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)\n        change = amount_in - amount - outputs[change_address]\n    if change > 0:\n        outputs[from_node.getnewaddress()] = change\n    return outputs\n\ndef random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):\n    \"\"\"\n    Create a random transaction.\n    Returns (txid, hex-encoded-transaction-data, fee)\n    \"\"\"\n    from_node = random.choice(nodes)\n    to_node = random.choice(nodes)\n    fee = min_fee + fee_increment * random.randint(0, fee_variants)\n\n    (total_in, inputs) = gather_inputs(from_node, amount + fee)\n    outputs = make_change(from_node, total_in, amount, fee)\n    outputs[to_node.getnewaddress()] = float(amount)\n\n    rawtx = from_node.createrawtransaction(inputs, outputs)\n    signresult = from_node.signrawtransaction(rawtx)\n    txid = from_node.sendrawtransaction(signresult[\"hex\"], 0)\n\n    return (txid, signresult[\"hex\"], fee)\n\n# Helper to create at least \"count\" utxos\n# Pass in a fee that is sufficient for relay and mining new transactions.\ndef create_confirmed_utxos(fee, node, count):\n    to_generate = int(0.5 * count) + 101\n    while to_generate > 0:\n        node.generate(min(25, to_generate))\n        to_generate -= 25\n    utxos = node.listunspent()\n    iterations = count - len(utxos)\n    addr1 = node.getnewaddress()\n    addr2 = node.getnewaddress()\n    if iterations <= 0:\n        return utxos\n    for i in range(iterations):\n        t = utxos.pop()\n        inputs = []\n        inputs.append({\"txid\": t[\"txid\"], \"vout\": t[\"vout\"]})\n        outputs = {}\n        send_value = t['amount'] - fee\n        outputs[addr1] = satoshi_round(send_value / 2)\n        outputs[addr2] = satoshi_round(send_value / 2)\n        raw_tx = node.createrawtransaction(inputs, outputs)\n        signed_tx = node.signrawtransaction(raw_tx)[\"hex\"]\n        node.sendrawtransaction(signed_tx)\n\n    while (node.getmempoolinfo()['size'] > 0):\n        node.generate(1)\n\n    utxos = node.listunspent()\n    assert len(utxos) >= count\n    return utxos\n\n# Create large OP_RETURN txouts that can be appended to a transaction\n# to make it large (helper for constructing large transactions).\ndef gen_return_txouts():\n    # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create\n    # So we have big transactions (and therefore can't fit very many into each block)\n    # create one script_pubkey\n    script_pubkey = \"6a4d0200\"  # OP_RETURN OP_PUSH2 512 bytes\n    for i in range(512):\n        script_pubkey = script_pubkey + \"01\"\n    # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change\n    txouts = \"81\"\n    for k in range(128):\n        # add txout value\n        txouts = txouts + \"0000000000000000\"\n        # add length of script_pubkey\n        txouts = txouts + \"fd0402\"\n        # add script_pubkey\n        txouts = txouts + script_pubkey\n    return txouts\n\n# Create a spend of each passed-in utxo, splicing in \"txouts\" to each raw\n# transaction to make it large.  See gen_return_txouts() above.\ndef create_lots_of_big_transactions(node, txouts, utxos, num, fee):\n    addr = node.getnewaddress()\n    txids = []\n    for _ in range(num):\n        t = utxos.pop()\n        inputs = [{\"txid\": t[\"txid\"], \"vout\": t[\"vout\"]}]\n        outputs = {}\n        change = t['amount'] - fee\n        outputs[addr] = satoshi_round(change)\n        rawtx = node.createrawtransaction(inputs, outputs)\n        newtx = rawtx[0:92]\n        newtx = newtx + txouts\n        newtx = newtx + rawtx[94:]\n        signresult = node.signrawtransaction(newtx, None, \"NONE\")\n        txid = node.sendrawtransaction(signresult[\"hex\"], 0)\n        txids.append(txid)\n    return txids\n\ndef mine_large_block(node, utxos=None):\n    # generate a 66k transaction,\n    # and 14 of them is close to the 1MB block limit\n    num = 14\n    txouts = gen_return_txouts()\n    utxos = utxos if utxos is not None else []\n    if len(utxos) < num:\n        utxos.clear()\n        utxos.extend(node.listunspent())\n    fee = 100 * node.getnetworkinfo()[\"relayfee\"]\n    create_lots_of_big_transactions(node, txouts, utxos, num, fee=fee)\n    node.generate(1)\n\ndef find_vout_for_address(node, txid, addr):\n    \"\"\"\n    Locate the vout index of the given transaction sending to the\n    given address. Raises runtime error exception if not found.\n    \"\"\"\n    tx = node.getrawtransaction(txid, True)\n    for i in range(len(tx[\"vout\"])):\n        if any([addr == a for a in tx[\"vout\"][i][\"scriptPubKey\"][\"addresses\"]]):\n            return i\n    raise RuntimeError(\"Vout not found for address: txid=%s, addr=%s\" % (txid, addr))\n"
  },
  {
    "path": "test/functional/test_framework/wallet_util.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Useful util functions for testing the wallet\"\"\"\nfrom collections import namedtuple\n\nfrom test_framework.address import (\n    key_to_p2pkh,\n    key_to_p2sh_p2wpkh,\n    key_to_p2wpkh,\n    script_to_p2sh,\n    script_to_p2sh_p2wsh,\n    script_to_p2wsh,\n)\nfrom test_framework.script import (\n    CScript,\n    OP_0,\n    OP_2,\n    OP_3,\n    OP_CHECKMULTISIG,\n    OP_CHECKSIG,\n    OP_DUP,\n    OP_EQUAL,\n    OP_EQUALVERIFY,\n    OP_HASH160,\n    hash160,\n    sha256,\n)\nfrom test_framework.util import hex_str_to_bytes\n\nKey = namedtuple('Key', ['privkey',\n                         'pubkey',\n                         'p2pkh_script',\n                         'p2pkh_addr',\n                         'p2wpkh_script',\n                         'p2wpkh_addr',\n                         'p2sh_p2wpkh_script',\n                         'p2sh_p2wpkh_redeem_script',\n                         'p2sh_p2wpkh_addr'])\n\nMultisig = namedtuple('Multisig', ['privkeys',\n                                   'pubkeys',\n                                   'p2sh_script',\n                                   'p2sh_addr',\n                                   'redeem_script',\n                                   'p2wsh_script',\n                                   'p2wsh_addr',\n                                   'p2sh_p2wsh_script',\n                                   'p2sh_p2wsh_addr'])\n\ndef get_key(node):\n    \"\"\"Generate a fresh key on node\n\n    Returns a named tuple of privkey, pubkey and all address and scripts.\"\"\"\n    addr = node.getnewaddress()\n    pubkey = node.getaddressinfo(addr)['pubkey']\n    pkh = hash160(hex_str_to_bytes(pubkey))\n    return Key(privkey=node.dumpprivkey(addr),\n               pubkey=pubkey,\n               p2pkh_script=CScript([OP_DUP, OP_HASH160, pkh, OP_EQUALVERIFY, OP_CHECKSIG]).hex(),\n               p2pkh_addr=key_to_p2pkh(pubkey),\n               p2wpkh_script=CScript([OP_0, pkh]).hex(),\n               p2wpkh_addr=key_to_p2wpkh(pubkey),\n               p2sh_p2wpkh_script=CScript([OP_HASH160, hash160(CScript([OP_0, pkh])), OP_EQUAL]).hex(),\n               p2sh_p2wpkh_redeem_script=CScript([OP_0, pkh]).hex(),\n               p2sh_p2wpkh_addr=key_to_p2sh_p2wpkh(pubkey))\n\ndef get_multisig(node):\n    \"\"\"Generate a fresh 2-of-3 multisig on node\n\n    Returns a named tuple of privkeys, pubkeys and all address and scripts.\"\"\"\n    addrs = []\n    pubkeys = []\n    for _ in range(3):\n        addr = node.getaddressinfo(node.getnewaddress())\n        addrs.append(addr['address'])\n        pubkeys.append(addr['pubkey'])\n    script_code = CScript([OP_2] + [hex_str_to_bytes(pubkey) for pubkey in pubkeys] + [OP_3, OP_CHECKMULTISIG])\n    witness_script = CScript([OP_0, sha256(script_code)])\n    return Multisig(privkeys=[node.dumpprivkey(addr) for addr in addrs],\n                    pubkeys=pubkeys,\n                    p2sh_script=CScript([OP_HASH160, hash160(script_code), OP_EQUAL]).hex(),\n                    p2sh_addr=script_to_p2sh(script_code),\n                    redeem_script=script_code.hex(),\n                    p2wsh_script=witness_script.hex(),\n                    p2wsh_addr=script_to_p2wsh(script_code),\n                    p2sh_p2wsh_script=CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(),\n                    p2sh_p2wsh_addr=script_to_p2sh_p2wsh(script_code))\n\ndef test_address(node, address, **kwargs):\n    \"\"\"Get address info for `address` and test whether the returned values are as expected.\"\"\"\n    addr_info = node.getaddressinfo(address)\n    for key, value in kwargs.items():\n        if value is None:\n            if key in addr_info.keys():\n                raise AssertionError(\"key {} unexpectedly returned in getaddressinfo.\".format(key))\n        elif addr_info[key] != value:\n            raise AssertionError(\"key {} value {} did not match expected value {}\".format(key, addr_info[key], value))\n"
  },
  {
    "path": "test/functional/test_runner.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Run regression test suite.\n\nThis module calls down into individual test cases via subprocess. It will\nforward all unrecognized arguments onto the individual test scripts.\n\nFor a description of arguments recognized by test scripts, see\n`test/functional/test_framework/test_framework.py:MuntTestFramework.main`.\n\n\"\"\"\n\nimport argparse\nfrom collections import deque\nimport configparser\nimport datetime\nimport os\nimport time\nimport shutil\nimport signal\nimport sys\nimport subprocess\nimport tempfile\nimport re\nimport logging\n\n# Formatting. Default colors to empty strings.\nBOLD, GREEN, RED, GREY = (\"\", \"\"), (\"\", \"\"), (\"\", \"\"), (\"\", \"\")\ntry:\n    # Make sure python thinks it can write unicode to its stdout\n    \"\\u2713\".encode(\"utf_8\").decode(sys.stdout.encoding)\n    TICK = \"✓ \"\n    CROSS = \"✖ \"\n    CIRCLE = \"○ \"\nexcept UnicodeDecodeError:\n    TICK = \"P \"\n    CROSS = \"x \"\n    CIRCLE = \"o \"\n\nif os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393):\n    if os.name == 'nt':\n        import ctypes\n        kernel32 = ctypes.windll.kernel32\n        ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4\n        STD_OUTPUT_HANDLE = -11\n        STD_ERROR_HANDLE = -12\n        # Enable ascii color control to stdout\n        stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)\n        stdout_mode = ctypes.c_int32()\n        kernel32.GetConsoleMode(stdout, ctypes.byref(stdout_mode))\n        kernel32.SetConsoleMode(stdout, stdout_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)\n        # Enable ascii color control to stderr\n        stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE)\n        stderr_mode = ctypes.c_int32()\n        kernel32.GetConsoleMode(stderr, ctypes.byref(stderr_mode))\n        kernel32.SetConsoleMode(stderr, stderr_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)\n    # primitive formatting on supported\n    # terminal via ANSI escape sequences:\n    BOLD = ('\\033[0m', '\\033[1m')\n    GREEN = ('\\033[0m', '\\033[0;32m')\n    RED = ('\\033[0m', '\\033[0;31m')\n    GREY = ('\\033[0m', '\\033[1;30m')\n\nTEST_EXIT_PASSED = 0\nTEST_EXIT_SKIPPED = 77\n\nBASE_SCRIPTS = [\n    # Scripts that are run by the travis build process.\n    # Longest test should go first, to favor running tests in parallel\n    ###'feature_fee_estimation.py',\n    ###'wallet_hd.py',\n    'wallet_backup.py',\n    # vv Tests less than 5m vv\n    ###'mining_getblocktemplate_longpoll.py',\n    ###'feature_maxuploadtarget.py',\n    ###'feature_block.py',\n    ###'rpc_fundrawtransaction.py',\n    ###'p2p_compactblocks.py',\n    ###'feature_segwit.py',\n    # vv Tests less than 2m vv\n    'wallet_basic.py',\n    ###'p2p_segwit.py',\n    ###'p2p_timeouts.py',\n    ###'wallet_dump.py',\n    ###'wallet_listtransactions.py',\n    # vv Tests less than 60s vv\n    ###'p2p_sendheaders.py',\n    'wallet_zapwallettxes.py',\n    ###'wallet_importmulti.py',\n    ###'mempool_limit.py',\n    ###'rpc_txoutproof.py',\n    ###'wallet_listreceivedby.py',\n    ###'wallet_abandonconflict.py',\n    ###'feature_csv_activation.py',\n    ###'rpc_rawtransaction.py',\n    ###'wallet_address_types.py',\n    ###'feature_bip68_sequence.py',\n    ###'p2p_feefilter.py',\n    ###'feature_reindex.py',\n    # vv Tests less than 30s vv\n    ###'wallet_keypool_topup.py',\n    ###'interface_zmq.py',\n    'interface_cli.py',\n    ###'mempool_resurrect.py',\n    ###'wallet_txn_doublespend.py --mineblock',\n    ###'tool_wallet.py',\n    ###'wallet_txn_clone.py',\n    ###'wallet_txn_clone.py --segwit',\n    ###'rpc_getchaintips.py',\n    'rpc_misc.py',\n    ###'interface_rest.py',\n    ###'mempool_spend_coinbase.py',\n    'mempool_reorg.py',\n    ###'mempool_persist.py',\n    ###'wallet_multiwallet.py',\n    ###'wallet_multiwallet.py --usecli',\n    ###'wallet_createwallet.py',\n    ###'wallet_createwallet.py --usecli',\n    ###'interface_http.py',\n    ###'interface_rpc.py',\n    ###'rpc_psbt.py',\n    'rpc_users.py',\n    ###'feature_proxy.py',\n    ###'rpc_signrawtransaction.py',\n    ###'wallet_groups.py',\n    'p2p_disconnect_ban.py',\n    ###'rpc_decodescript.py',\n    ###'rpc_blockchain.py',\n    ###'rpc_deprecated.py',\n    ###'wallet_disable.py',\n    'rpc_net.py',\n    ###'wallet_keypool.py',\n    ###'p2p_mempool.py',\n    ###'mining_prioritisetransaction.py',\n    ###'p2p_invalid_locator.py',\n    ###'p2p_invalid_block.py',\n    'p2p_invalid_messages.py',\n    ###'p2p_invalid_tx.py',\n    ###'feature_assumevalid.py',\n    'example_test.py',\n    ###'wallet_txn_doublespend.py',\n    ###'wallet_txn_clone.py --mineblock',\n    ###'feature_notifications.py',\n    ###'rpc_invalidateblock.py',\n    ###'feature_rbf.py',\n    ###'mempool_packages.py',\n    ###'rpc_createmultisig.py',\n    ###'feature_versionbits_warning.py',\n    ###'rpc_preciousblock.py',\n    ###'wallet_importprunedfunds.py',\n    'p2p_leak_tx.py',\n    'rpc_signmessage.py',\n    'wallet_balance.py',\n    ###'feature_nulldummy.py',\n    ###'mempool_accept.py',\n    ###'wallet_import_rescan.py',\n    ###'wallet_import_with_label.py',\n    'rpc_bind.py --ipv4',\n    ###'rpc_bind.py --ipv6',\n    'rpc_bind.py --nonloopback',\n    ###'mining_basic.py',\n    ###'wallet_bumpfee.py',\n    'rpc_named_arguments.py',\n    ###'wallet_listsinceblock.py',\n    'p2p_leak.py',\n    'wallet_encryption.py',\n    ###'feature_dersig.py',\n    ###'feature_cltv.py',\n    'rpc_uptime.py',\n    ###'wallet_resendwallettransactions.py',\n    ###'wallet_fallbackfee.py',\n    'feature_minchainwork.py',\n    'rpc_getblockstats.py',\n    ###'wallet_create_tx.py',\n    ###'p2p_fingerprint.py',\n    'feature_uacomment.py',\n    ###'wallet_coinbase_category.py',\n    'feature_filelock.py',\n    ###'p2p_unrequested_blocks.py',\n    ###'feature_includeconf.py',\n    ###'rpc_deriveaddresses.py',\n    ###'rpc_deriveaddresses.py --usecli',\n    ###'rpc_scantxoutset.py',\n    'feature_logging.py',\n    'p2p_node_network_limited.py',\n    ###'feature_blocksdir.py',\n    ###'feature_config_args.py',\n    'rpc_help.py',\n    'feature_help.py',\n    ###'feature_shutdown.py',\n    # Don't append tests at the end to avoid merge conflicts\n    # Put them in a random line within the section that fits their approximate run-time\n]\n\nEXTENDED_SCRIPTS = [\n    # These tests are not run by the travis build process.\n    # Longest test should go first, to favor running tests in parallel\n    ###'feature_pruning.py',\n    ###'feature_dbcrash.py',\n]\n\n# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests\nALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS\n\nNON_SCRIPTS = [\n    # These are python files that live in the functional tests directory, but are not test scripts.\n    \"combine_logs.py\",\n    \"create_cache.py\",\n    \"test_runner.py\",\n]\n\ndef main():\n    # Parse arguments and pass through unrecognised args\n    parser = argparse.ArgumentParser(add_help=False,\n                                     usage='%(prog)s [test_runner.py options] [script options] [scripts]',\n                                     description=__doc__,\n                                     epilog='''\n    Help text and arguments for individual test script:''',\n                                     formatter_class=argparse.RawTextHelpFormatter)\n    parser.add_argument('--combinedlogslen', '-c', type=int, default=0, metavar='n', help='On failure, print a log (of length n lines) to the console, combined from the test framework and all test nodes.')\n    parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')\n    parser.add_argument('--ci', action='store_true', help='Run checks and code that are usually only enabled in a continuous integration environment')\n    parser.add_argument('--exclude', '-x', help='specify a comma-separated-list of scripts to exclude.')\n    parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')\n    parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')\n    parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')\n    parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.')\n    parser.add_argument('--quiet', '-q', action='store_true', help='only print dots, results summary and failure logs')\n    parser.add_argument('--tmpdirprefix', '-t', default=tempfile.gettempdir(), help=\"Root directory for datadirs\")\n    parser.add_argument('--failfast', action='store_true', help='stop execution after the first test failure')\n    args, unknown_args = parser.parse_known_args()\n\n    # args to be passed on always start with two dashes; tests are the remaining unknown args\n    tests = [arg for arg in unknown_args if arg[:2] != \"--\"]\n    passon_args = [arg for arg in unknown_args if arg[:2] == \"--\"]\n\n    # Read config generated by configure.\n    config = configparser.ConfigParser()\n    configfile = os.path.abspath(os.path.dirname(__file__)) + \"/../config.ini\"\n    config.read_file(open(configfile, encoding=\"utf8\"))\n\n    passon_args.append(\"--configfile=%s\" % configfile)\n\n    # Set up logging\n    logging_level = logging.INFO if args.quiet else logging.DEBUG\n    logging.basicConfig(format='%(message)s', level=logging_level)\n\n    # Create base test directory\n    tmpdir = \"%s/test_runner_G_🏃_%s\" % (args.tmpdirprefix, datetime.datetime.now().strftime(\"%Y%m%d_%H%M%S\"))\n\n    os.makedirs(tmpdir)\n\n    logging.debug(\"Temporary test directory at %s\" % tmpdir)\n\n    enable_daemon = config[\"components\"].getboolean(\"ENABLE_DAEMON\")\n\n    if not enable_daemon:\n        print(\"No functional tests to run.\")\n        print(\"Rerun ./configure with --with-daemon and then make\")\n        sys.exit(0)\n\n    # Build list of tests\n    test_list = []\n    if tests:\n        # Individual tests have been specified. Run specified tests that exist\n        # in the ALL_SCRIPTS list. Accept the name with or without .py extension.\n        tests = [test + \".py\" if \".py\" not in test else test for test in tests]\n        for test in tests:\n            if test in ALL_SCRIPTS:\n                test_list.append(test)\n            else:\n                print(\"{}WARNING!{} Test '{}' not found in full test list.\".format(BOLD[1], BOLD[0], test))\n    elif args.extended:\n        # Include extended tests\n        test_list += ALL_SCRIPTS\n    else:\n        # Run base tests only\n        test_list += BASE_SCRIPTS\n\n    # Remove the test cases that the user has explicitly asked to exclude.\n    if args.exclude:\n        exclude_tests = [test.split('.py')[0] for test in args.exclude.split(',')]\n        for exclude_test in exclude_tests:\n            # Remove <test_name>.py and <test_name>.py --arg from the test list\n            exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test]\n            for exclude_item in exclude_list:\n                test_list.remove(exclude_item)\n            if not exclude_list:\n                print(\"{}WARNING!{} Test '{}' not found in current test list.\".format(BOLD[1], BOLD[0], exclude_test))\n\n    if not test_list:\n        print(\"No valid test scripts specified. Check that your test is in one \"\n              \"of the test lists in test_runner.py, or run test_runner.py with no arguments to run all tests\")\n        sys.exit(0)\n\n    if args.help:\n        # Print help for test_runner.py, then print help of the first script (with args removed) and exit.\n        parser.print_help()\n        subprocess.check_call([sys.executable, os.path.join(config[\"environment\"][\"SRCDIR\"], 'test', 'functional', test_list[0].split()[0]), '-h'])\n        sys.exit(0)\n\n    check_script_list(src_dir=config[\"environment\"][\"SRCDIR\"], fail_on_warn=args.ci)\n    check_script_prefixes()\n\n    if not args.keepcache:\n        shutil.rmtree(\"%s/test/cache\" % config[\"environment\"][\"BUILDDIR\"], ignore_errors=True)\n\n    run_tests(\n        test_list=test_list,\n        src_dir=config[\"environment\"][\"SRCDIR\"],\n        build_dir=config[\"environment\"][\"BUILDDIR\"],\n        tmpdir=tmpdir,\n        jobs=args.jobs,\n        enable_coverage=args.coverage,\n        args=passon_args,\n        combined_logs_len=args.combinedlogslen,\n        failfast=args.failfast,\n        runs_ci=args.ci,\n    )\n\ndef run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, runs_ci):\n    args = args or []\n\n    # Warn if Munt-daemon is already running (unix only)\n    try:\n        if subprocess.check_output([\"pidof\", \"Munt-daemon\"]) is not None:\n            print(\"%sWARNING!%s There is already a Munt-daemon process running on this system. Tests may fail unexpectedly due to resource contention!\" % (BOLD[1], BOLD[0]))\n    except (OSError, subprocess.SubprocessError):\n        pass\n\n    # Warn if there is a cache directory\n    cache_dir = \"%s/test/cache\" % build_dir\n    if os.path.isdir(cache_dir):\n        print(\"%sWARNING!%s There is a cache directory here: %s. If tests fail unexpectedly, try deleting the cache directory.\" % (BOLD[1], BOLD[0], cache_dir))\n\n    tests_dir = src_dir + '/test/functional/'\n\n    flags = ['--cachedir={}'.format(cache_dir)] + args\n\n    if enable_coverage:\n        coverage = RPCCoverage()\n        flags.append(coverage.flag)\n        logging.debug(\"Initializing coverage directory at %s\" % coverage.dir)\n    else:\n        coverage = None\n\n    if len(test_list) > 1 and jobs > 1:\n        # Populate cache\n        try:\n            subprocess.check_output([sys.executable, tests_dir + 'create_cache.py'] + flags + [\"--tmpdir=%s/cache\" % tmpdir])\n        except subprocess.CalledProcessError as e:\n            sys.stdout.buffer.write(e.output)\n            raise\n\n    #Run Tests\n    job_queue = TestHandler(\n        num_tests_parallel=jobs,\n        tests_dir=tests_dir,\n        tmpdir=tmpdir,\n        test_list=test_list,\n        flags=flags,\n        timeout_duration=40 * 60 if runs_ci else float('inf'),  # in seconds\n    )\n    start_time = time.time()\n    test_results = []\n\n    max_len_name = len(max(test_list, key=len))\n    test_count = len(test_list)\n    for i in range(test_count):\n        test_result, testdir, stdout, stderr = job_queue.get_next()\n        test_results.append(test_result)\n        done_str = \"{}/{} - {}{}{}\".format(i + 1, test_count, BOLD[1], test_result.name, BOLD[0])\n        if test_result.status == \"Passed\":\n            logging.debug(\"%s passed, Duration: %s s\" % (done_str, test_result.time))\n        elif test_result.status == \"Skipped\":\n            logging.debug(\"%s skipped\" % (done_str))\n        else:\n            print(\"%s failed, Duration: %s s\\n\" % (done_str, test_result.time))\n            print(BOLD[1] + 'stdout:\\n' + BOLD[0] + stdout + '\\n')\n            print(BOLD[1] + 'stderr:\\n' + BOLD[0] + stderr + '\\n')\n            if combined_logs_len and os.path.isdir(testdir):\n                # Print the final `combinedlogslen` lines of the combined logs\n                print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0]))\n                print('\\n============')\n                print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))\n                print('============\\n')\n                combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]\n                if BOLD[0]:\n                    combined_logs_args += ['--color']\n                combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()\n                print(\"\\n\".join(deque(combined_logs.splitlines(), combined_logs_len)))\n\n            if failfast:\n                logging.debug(\"Early exiting after test failure\")\n                break\n\n    print_results(test_results, max_len_name, (int(time.time() - start_time)))\n\n    if coverage:\n        coverage.report_rpc_coverage()\n\n        logging.debug(\"Cleaning up coverage data\")\n        coverage.cleanup()\n\n    # Clear up the temp directory if all subdirectories are gone\n    if not os.listdir(tmpdir):\n        os.rmdir(tmpdir)\n\n    all_passed = all(map(lambda test_result: test_result.was_successful, test_results))\n\n    # This will be a no-op unless failfast is True in which case there may be dangling\n    # processes which need to be killed.\n    job_queue.kill_and_join()\n\n    sys.exit(not all_passed)\n\ndef print_results(test_results, max_len_name, runtime):\n    results = \"\\n\" + BOLD[1] + \"%s | %s | %s\\n\\n\" % (\"TEST\".ljust(max_len_name), \"STATUS   \", \"DURATION\") + BOLD[0]\n\n    test_results.sort(key=TestResult.sort_key)\n    all_passed = True\n    time_sum = 0\n\n    for test_result in test_results:\n        all_passed = all_passed and test_result.was_successful\n        time_sum += test_result.time\n        test_result.padding = max_len_name\n        results += str(test_result)\n\n    status = TICK + \"Passed\" if all_passed else CROSS + \"Failed\"\n    if not all_passed:\n        results += RED[1]\n    results += BOLD[1] + \"\\n%s | %s | %s s (accumulated) \\n\" % (\"ALL\".ljust(max_len_name), status.ljust(9), time_sum) + BOLD[0]\n    if not all_passed:\n        results += RED[0]\n    results += \"Runtime: %s s\\n\" % (runtime)\n    print(results)\n\nclass TestHandler:\n    \"\"\"\n    Trigger the test scripts passed in via the list.\n    \"\"\"\n\n    def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, timeout_duration):\n        assert num_tests_parallel >= 1\n        self.num_jobs = num_tests_parallel\n        self.tests_dir = tests_dir\n        self.tmpdir = tmpdir\n        self.timeout_duration = timeout_duration\n        self.test_list = test_list\n        self.flags = flags\n        self.num_running = 0\n        self.jobs = []\n\n    def get_next(self):\n        while self.num_running < self.num_jobs and self.test_list:\n            # Add tests\n            self.num_running += 1\n            test = self.test_list.pop(0)\n            portseed = len(self.test_list)\n            portseed_arg = [\"--portseed={}\".format(portseed)]\n            log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)\n            log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)\n            test_argv = test.split()\n            testdir = \"{}/{}_{}\".format(self.tmpdir, re.sub(\".py$\", \"\", test_argv[0]), portseed)\n            tmpdir_arg = [\"--tmpdir={}\".format(testdir)]\n            self.jobs.append((test,\n                              time.time(),\n                              subprocess.Popen([sys.executable, self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir_arg,\n                                               universal_newlines=True,\n                                               stdout=log_stdout,\n                                               stderr=log_stderr),\n                              testdir,\n                              log_stdout,\n                              log_stderr))\n        if not self.jobs:\n            raise IndexError('pop from empty list')\n\n        # Print remaining running jobs when all jobs have been started.\n        if not self.test_list:\n            print(\"Remaining jobs: [{}]\".format(\", \".join(j[0] for j in self.jobs)))\n\n        dot_count = 0\n        while True:\n            # Return first proc that finishes\n            time.sleep(.5)\n            for job in self.jobs:\n                (name, start_time, proc, testdir, log_out, log_err) = job\n                if int(time.time() - start_time) > self.timeout_duration:\n                    # In travis, timeout individual tests (to stop tests hanging and not providing useful output).\n                    proc.send_signal(signal.SIGINT)\n                if proc.poll() is not None:\n                    log_out.seek(0), log_err.seek(0)\n                    [stdout, stderr] = [log_file.read().decode('utf-8') for log_file in (log_out, log_err)]\n                    log_out.close(), log_err.close()\n                    if proc.returncode == TEST_EXIT_PASSED and stderr == \"\":\n                        status = \"Passed\"\n                    elif proc.returncode == TEST_EXIT_SKIPPED:\n                        status = \"Skipped\"\n                    else:\n                        status = \"Failed\"\n                    self.num_running -= 1\n                    self.jobs.remove(job)\n                    clearline = '\\r' + (' ' * dot_count) + '\\r'\n                    print(clearline, end='', flush=True)\n                    dot_count = 0\n                    return TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr\n            print('.', end='', flush=True)\n            dot_count += 1\n\n    def kill_and_join(self):\n        \"\"\"Send SIGKILL to all jobs and block until all have ended.\"\"\"\n        procs = [i[2] for i in self.jobs]\n\n        for proc in procs:\n            proc.kill()\n\n        for proc in procs:\n            proc.wait()\n\n\nclass TestResult():\n    def __init__(self, name, status, time):\n        self.name = name\n        self.status = status\n        self.time = time\n        self.padding = 0\n\n    def sort_key(self):\n        if self.status == \"Passed\":\n            return 0, self.name.lower()\n        elif self.status == \"Failed\":\n            return 2, self.name.lower()\n        elif self.status == \"Skipped\":\n            return 1, self.name.lower()\n\n    def __repr__(self):\n        if self.status == \"Passed\":\n            color = GREEN\n            glyph = TICK\n        elif self.status == \"Failed\":\n            color = RED\n            glyph = CROSS\n        elif self.status == \"Skipped\":\n            color = GREY\n            glyph = CIRCLE\n\n        return color[1] + \"%s | %s%s | %s s\\n\" % (self.name.ljust(self.padding), glyph, self.status.ljust(7), self.time) + color[0]\n\n    @property\n    def was_successful(self):\n        return self.status != \"Failed\"\n\n\ndef check_script_prefixes():\n    \"\"\"Check that test scripts start with one of the allowed name prefixes.\"\"\"\n\n    good_prefixes_re = re.compile(\"(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool)_\")\n    bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None]\n\n    if bad_script_names:\n        print(\"%sERROR:%s %d tests not meeting naming conventions:\" % (BOLD[1], BOLD[0], len(bad_script_names)))\n        print(\"  %s\" % (\"\\n  \".join(sorted(bad_script_names))))\n        raise AssertionError(\"Some tests are not following naming convention!\")\n\n\ndef check_script_list(*, src_dir, fail_on_warn):\n    \"\"\"Check scripts directory.\n\n    Check that there are no scripts in the functional tests directory which are\n    not being run by pull-tester.py.\"\"\"\n    script_dir = src_dir + '/test/functional/'\n    python_files = set([test_file for test_file in os.listdir(script_dir) if test_file.endswith(\".py\")])\n    missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))\n    if len(missed_tests) != 0:\n        print(\"%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py.\" % (BOLD[1], BOLD[0], str(missed_tests)))\n        if fail_on_warn:\n            # On travis this warning is an error to prevent merging incomplete commits into master\n            sys.exit(1)\n\n\nclass RPCCoverage():\n    \"\"\"\n    Coverage reporting utilities for test_runner.\n\n    Coverage calculation works by having each test script subprocess write\n    coverage files into a particular directory. These files contain the RPC\n    commands invoked during testing, as well as a complete listing of RPC\n    commands per `Munt-cli help` (`rpc_interface.txt`).\n\n    After all tests complete, the commands run are combined and diff'd against\n    the complete list to calculate uncovered RPC commands.\n\n    See also: test/functional/test_framework/coverage.py\n\n    \"\"\"\n    def __init__(self):\n        self.dir = tempfile.mkdtemp(prefix=\"coverage\")\n        self.flag = '--coveragedir=%s' % self.dir\n\n    def report_rpc_coverage(self):\n        \"\"\"\n        Print out RPC commands that were unexercised by tests.\n\n        \"\"\"\n        uncovered = self._get_uncovered_rpc_commands()\n\n        if uncovered:\n            print(\"Uncovered RPC commands:\")\n            print(\"\".join((\"  - %s\\n\" % command) for command in sorted(uncovered)))\n        else:\n            print(\"All RPC commands covered.\")\n\n    def cleanup(self):\n        return shutil.rmtree(self.dir)\n\n    def _get_uncovered_rpc_commands(self):\n        \"\"\"\n        Return a set of currently untested RPC commands.\n\n        \"\"\"\n        # This is shared from `test/functional/test-framework/coverage.py`\n        reference_filename = 'rpc_interface.txt'\n        coverage_file_prefix = 'coverage.'\n\n        coverage_ref_filename = os.path.join(self.dir, reference_filename)\n        coverage_filenames = set()\n        all_cmds = set()\n        covered_cmds = set()\n\n        if not os.path.isfile(coverage_ref_filename):\n            raise RuntimeError(\"No coverage reference found\")\n\n        with open(coverage_ref_filename, 'r', encoding=\"utf8\") as coverage_ref_file:\n            all_cmds.update([line.strip() for line in coverage_ref_file.readlines()])\n\n        for root, _, files in os.walk(self.dir):\n            for filename in files:\n                if filename.startswith(coverage_file_prefix):\n                    coverage_filenames.add(os.path.join(root, filename))\n\n        for filename in coverage_filenames:\n            with open(filename, 'r', encoding=\"utf8\") as coverage_file:\n                covered_cmds.update([line.strip() for line in coverage_file.readlines()])\n\n        return all_cmds - covered_cmds\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "test/functional/tool_wallet.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test Munt-wallet.\"\"\"\nimport subprocess\nimport textwrap\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal\n\nclass ToolWalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def munt_wallet_process(self, *args):\n        binary = self.config[\"environment\"][\"BUILDDIR\"] + '/src/Munt-wallet' + self.config[\"environment\"][\"EXEEXT\"]\n        args = ['-datadir={}'.format(self.nodes[0].datadir), '-regtestlegacy'] + list(args)\n        return subprocess.Popen([binary] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)\n\n    def assert_raises_tool_error(self, error, *args):\n        p = self.munt_wallet_process(*args)\n        stdout, stderr = p.communicate()\n        assert_equal(p.poll(), 1)\n        assert_equal(stdout, '')\n        assert_equal(stderr.strip(), error)\n\n    def assert_tool_output(self, output, *args):\n        p = self.munt_wallet_process(*args)\n        stdout, stderr = p.communicate()\n        assert_equal(p.poll(), 0)\n        assert_equal(stderr, '')\n        assert_equal(stdout, output)\n\n    def run_test(self):\n\n        self.assert_raises_tool_error('Invalid command: foo', 'foo')\n        # `Munt-wallet help` is an error. Use `Munt-wallet -help`\n        self.assert_raises_tool_error('Invalid command: help', 'help')\n        self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')\n        self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')\n        self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info')\n        self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')\n\n        # stop the node to close the wallet to call info command\n        self.stop_node(0)\n\n        out = textwrap.dedent('''\\\n            Wallet info\n            ===========\n            Encrypted: no\n            HD (hd seed available): yes\n            Keypool Size: 2\n            Transactions: 0\n            Address Book: 3\n        ''')\n        self.assert_tool_output(out, '-wallet=wallet.dat', 'info')\n\n        # mutate the wallet to check the info command output changes accordingly\n        self.start_node(0)\n        self.nodes[0].generate(1)\n        self.stop_node(0)\n\n        out = textwrap.dedent('''\\\n            Wallet info\n            ===========\n            Encrypted: no\n            HD (hd seed available): yes\n            Keypool Size: 2\n            Transactions: 1\n            Address Book: 3\n        ''')\n        self.assert_tool_output(out, '-wallet=wallet.dat', 'info')\n\n        out = textwrap.dedent('''\\\n            Topping up keypool...\n            Wallet info\n            ===========\n            Encrypted: no\n            HD (hd seed available): yes\n            Keypool Size: 2000\n            Transactions: 0\n            Address Book: 0\n        ''')\n        self.assert_tool_output(out, '-wallet=foo', 'create')\n\n        self.start_node(0, ['-wallet=foo'])\n        out = self.nodes[0].getwalletinfo()\n        self.stop_node(0)\n\n        assert_equal(0, out['txcount'])\n        assert_equal(1000, out['keypoolsize'])\n        assert_equal(1000, out['keypoolsize_hd_internal'])\n        assert_equal(True, 'hdseedid' in out)\n\nif __name__ == '__main__':\n    ToolWalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_abandonconflict.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the abandontransaction RPC.\n\n The abandontransaction RPC marks a transaction and all its in-wallet\n descendants as abandoned which allows their inputs to be respent. It can be\n used to replace \"stuck\" or evicted transactions. It only works on transactions\n which are not included in a block and are not currently in the mempool. It has\n no effect on transactions which are already abandoned.\n\"\"\"\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    connect_nodes,\n    disconnect_nodes,\n    sync_blocks,\n    sync_mempools,\n)\n\n\nclass AbandonConflictTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [[\"-minrelaytxfee=0.00001\"], []]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[1].generate(100)\n        sync_blocks(self.nodes)\n        balance = self.nodes[0].getbalance()\n        txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal(\"10\"))\n        txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal(\"10\"))\n        txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal(\"10\"))\n        sync_mempools(self.nodes)\n        self.nodes[1].generate(1)\n\n        # Can not abandon non-wallet transaction\n        assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', lambda: self.nodes[0].abandontransaction(txid='ff' * 32))\n        # Can not abandon confirmed transaction\n        assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: self.nodes[0].abandontransaction(txid=txA))\n\n        sync_blocks(self.nodes)\n        newbalance = self.nodes[0].getbalance()\n        assert balance - newbalance < Decimal(\"0.01\")  #no more than fees lost\n        balance = newbalance\n\n        # Disconnect nodes so node0's transactions don't get into node1's mempool\n        disconnect_nodes(self.nodes[0], 1)\n\n        # Identify the 10btc outputs\n        nA = next(tx_out[\"vout\"] for tx_out in self.nodes[0].gettransaction(txA)[\"details\"] if tx_out[\"amount\"] == Decimal(\"10\"))\n        nB = next(tx_out[\"vout\"] for tx_out in self.nodes[0].gettransaction(txB)[\"details\"] if tx_out[\"amount\"] == Decimal(\"10\"))\n        nC = next(tx_out[\"vout\"] for tx_out in self.nodes[0].gettransaction(txC)[\"details\"] if tx_out[\"amount\"] == Decimal(\"10\"))\n\n        inputs = []\n        # spend 10btc outputs from txA and txB\n        inputs.append({\"txid\": txA, \"vout\": nA})\n        inputs.append({\"txid\": txB, \"vout\": nB})\n        outputs = {}\n\n        outputs[self.nodes[0].getnewaddress()] = Decimal(\"14.99998\")\n        outputs[self.nodes[1].getnewaddress()] = Decimal(\"5\")\n        signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))\n        txAB1 = self.nodes[0].sendrawtransaction(signed[\"hex\"])\n\n        # Identify the 14.99998btc output\n        nAB = next(tx_out[\"vout\"] for tx_out in self.nodes[0].gettransaction(txAB1)[\"details\"] if tx_out[\"amount\"] == Decimal(\"14.99998\"))\n\n        #Create a child tx spending AB1 and C\n        inputs = []\n        inputs.append({\"txid\": txAB1, \"vout\": nAB})\n        inputs.append({\"txid\": txC, \"vout\": nC})\n        outputs = {}\n        outputs[self.nodes[0].getnewaddress()] = Decimal(\"24.9996\")\n        signed2 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))\n        txABC2 = self.nodes[0].sendrawtransaction(signed2[\"hex\"])\n\n        # Create a child tx spending ABC2\n        signed3_change = Decimal(\"24.999\")\n        inputs = [{\"txid\": txABC2, \"vout\": 0}]\n        outputs = {self.nodes[0].getnewaddress(): signed3_change}\n        signed3 = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs))\n        # note tx is never directly referenced, only abandoned as a child of the above\n        self.nodes[0].sendrawtransaction(signed3[\"hex\"])\n\n        # In mempool txs from self should increase balance from change\n        newbalance = self.nodes[0].getbalance()\n        #assert_equal(newbalance, balance - Decimal(\"30\") + signed3_change)\n        balance = newbalance\n\n        # Restart the node with a higher min relay fee so the parent tx is no longer in mempool\n        # TODO: redo with eviction\n        self.stop_node(0)\n        self.start_node(0, extra_args=[\"-minrelaytxfee=0.0001\"])\n\n        # Verify txs no longer in either node's mempool\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        assert_equal(len(self.nodes[1].getrawmempool()), 0)\n\n        # Not in mempool txs from self should only reduce balance\n        # inputs are still spent, but change not received\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance - signed3_change)\n        # Unconfirmed received funds that are not in mempool, also shouldn't show\n        # up in unconfirmed balance\n        unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()\n        assert_equal(unconfbalance, newbalance)\n        # Also shouldn't show up in listunspent\n        assert not txABC2 in [utxo[\"txid\"] for utxo in self.nodes[0].listunspent(0)]\n        balance = newbalance\n\n        # Abandon original transaction and verify inputs are available again\n        # including that the child tx was also abandoned\n        self.nodes[0].abandontransaction(txAB1)\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance + Decimal(\"30\"))\n        balance = newbalance\n\n        # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned\n        self.stop_node(0)\n        self.start_node(0, extra_args=[\"-minrelaytxfee=0.00001\"])\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        assert_equal(self.nodes[0].getbalance(), balance)\n\n        # But if it is received again then it is unabandoned\n        # And since now in mempool, the change is available\n        # But its child tx remains abandoned\n        self.nodes[0].sendrawtransaction(signed[\"hex\"])\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance - Decimal(\"20\") + Decimal(\"14.99998\"))\n        balance = newbalance\n\n        # Send child tx again so it is unabandoned\n        self.nodes[0].sendrawtransaction(signed2[\"hex\"])\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance - Decimal(\"10\") - Decimal(\"14.99998\") + Decimal(\"24.9996\"))\n        balance = newbalance\n\n        # Remove using high relay fee again\n        self.stop_node(0)\n        self.start_node(0, extra_args=[\"-minrelaytxfee=0.0001\"])\n        assert_equal(len(self.nodes[0].getrawmempool()), 0)\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance - Decimal(\"24.9996\"))\n        balance = newbalance\n\n        # Create a double spend of AB1 by spending again from only A's 10 output\n        # Mine double spend from node 1\n        inputs = []\n        inputs.append({\"txid\": txA, \"vout\": nA})\n        outputs = {}\n        outputs[self.nodes[1].getnewaddress()] = Decimal(\"9.9999\")\n        tx = self.nodes[0].createrawtransaction(inputs, outputs)\n        signed = self.nodes[0].signrawtransaction(tx)\n        self.nodes[1].sendrawtransaction(signed[\"hex\"])\n        self.nodes[1].generate(1)\n\n        connect_nodes(self.nodes[0], 1)\n        sync_blocks(self.nodes)\n\n        # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted\n        newbalance = self.nodes[0].getbalance()\n        assert_equal(newbalance, balance + Decimal(\"20\"))\n        balance = newbalance\n\n        # There is currently a minor bug around this and so this test doesn't work.  See Issue #7315\n        # Invalidate the block with the double spend and B's 10 BTC output should no longer be available\n        # Don't think C's should either\n        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())\n        newbalance = self.nodes[0].getbalance()\n        #assert_equal(newbalance, balance - Decimal(\"10\"))\n        self.log.info(\"If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer\")\n        self.log.info(\"conflicted has not resumed causing its inputs to be seen as spent.  See Issue #7315\")\n        self.log.info(str(balance) + \" -> \" + str(newbalance) + \" ?\")\n\n\nif __name__ == '__main__':\n    AbandonConflictTest().main()\n"
  },
  {
    "path": "test/functional/wallet_address_types.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test that the wallet can send and receive using all combinations of address types.\n\nThere are 5 nodes-under-test:\n    - node0 uses legacy addresses\n    - node1 uses p2sh/segwit addresses\n    - node2 uses p2sh/segwit addresses and bech32 addresses for change\n    - node3 uses bech32 addresses\n    - node4 uses a p2sh/segwit addresses for change\n\nnode5 exists to generate new blocks.\n\n## Multisig address test\n\nTest that adding a multisig address with:\n    - an uncompressed pubkey always gives a legacy address\n    - only compressed pubkeys gives the an `-addresstype` address\n\n## Sending to address types test\n\nA series of tests, iterating over node0-node4. In each iteration of the test, one node sends:\n    - 10/101th of its balance to itself (using getrawchangeaddress for single key addresses)\n    - 20/101th to the next node\n    - 30/101th to the node after that\n    - 40/101th to the remaining node\n    - 1/101th remains as fee+change\n\nIterate over each node for single key addresses, and then over each node for\nmultisig addresses.\n\nRepeat test, but with explicit address_type parameters passed to getnewaddress\nand getrawchangeaddress:\n    - node0 and node3 send to p2sh.\n    - node1 sends to bech32.\n    - node2 sends to legacy.\n\nAs every node sends coins after receiving, this also\nverifies that spending coins sent to all these address types works.\n\n## Change type test\n\nTest that the nodes generate the correct change address type:\n    - node0 always uses a legacy change address.\n    - node1 uses a bech32 addresses for change if any destination address is bech32.\n    - node2 always uses a bech32 address for change\n    - node3 always uses a bech32 address for change\n    - node4 always uses p2sh/segwit output for change.\n\"\"\"\n\nfrom decimal import Decimal\nimport itertools\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.descriptors import (\n    descsum_create,\n    descsum_check,\n)\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n    sync_blocks,\n    sync_mempools,\n)\n\n\nclass AddressTypeTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 6\n        self.extra_args = [\n            [\"-addresstype=legacy\"],\n            [\"-addresstype=p2sh-segwit\"],\n            [\"-addresstype=p2sh-segwit\", \"-changetype=bech32\"],\n            [\"-addresstype=bech32\"],\n            [\"-changetype=p2sh-segwit\"],\n            [],\n        ]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n\n        # Fully mesh-connect nodes for faster mempool sync\n        for i, j in itertools.product(range(self.num_nodes), repeat=2):\n            if i > j:\n                connect_nodes_bi(self.nodes, i, j)\n        self.sync_all()\n\n    def get_balances(self, confirmed=True):\n        \"\"\"Return a list of confirmed or unconfirmed balances.\"\"\"\n        if confirmed:\n            return [self.nodes[i].getbalance() for i in range(4)]\n        else:\n            return [self.nodes[i].getunconfirmedbalance() for i in range(4)]\n\n    def test_address(self, node, address, multisig, typ):\n        \"\"\"Run sanity checks on an address.\"\"\"\n        info = self.nodes[node].getaddressinfo(address)\n        assert self.nodes[node].validateaddress(address)['isvalid']\n        assert_equal(info.get('solvable'), True)\n\n        if not multisig and typ == 'legacy':\n            # P2PKH\n            assert not info['isscript']\n            assert not info['iswitness']\n            assert 'pubkey' in info\n        elif not multisig and typ == 'p2sh-segwit':\n            # P2SH-P2WPKH\n            assert info['isscript']\n            assert not info['iswitness']\n            assert_equal(info['script'], 'witness_v0_keyhash')\n            assert 'pubkey' in info\n        elif not multisig and typ == 'bech32':\n            # P2WPKH\n            assert not info['isscript']\n            assert info['iswitness']\n            assert_equal(info['witness_version'], 0)\n            assert_equal(len(info['witness_program']), 40)\n            assert 'pubkey' in info\n        elif typ == 'legacy':\n            # P2SH-multisig\n            assert info['isscript']\n            assert_equal(info['script'], 'multisig')\n            assert not info['iswitness']\n            assert 'pubkeys' in info\n        elif typ == 'p2sh-segwit':\n            # P2SH-P2WSH-multisig\n            assert info['isscript']\n            assert_equal(info['script'], 'witness_v0_scripthash')\n            assert not info['iswitness']\n            assert info['embedded']['isscript']\n            assert_equal(info['embedded']['script'], 'multisig')\n            assert info['embedded']['iswitness']\n            assert_equal(info['embedded']['witness_version'], 0)\n            assert_equal(len(info['embedded']['witness_program']), 64)\n            assert 'pubkeys' in info['embedded']\n        elif typ == 'bech32':\n            # P2WSH-multisig\n            assert info['isscript']\n            assert_equal(info['script'], 'multisig')\n            assert info['iswitness']\n            assert_equal(info['witness_version'], 0)\n            assert_equal(len(info['witness_program']), 64)\n            assert 'pubkeys' in info\n        else:\n            # Unknown type\n            assert False\n\n    def test_desc(self, node, address, multisig, typ, utxo):\n        \"\"\"Run sanity checks on a descriptor reported by getaddressinfo.\"\"\"\n        info = self.nodes[node].getaddressinfo(address)\n        assert 'desc' in info\n        assert_equal(info['desc'], utxo['desc'])\n        assert self.nodes[node].validateaddress(address)['isvalid']\n\n        # Use a ridiculously roundabout way to find the key origin info through\n        # the PSBT logic. However, this does test consistency between the PSBT reported\n        # fingerprints/paths and the descriptor logic.\n        psbt = self.nodes[node].createpsbt([{'txid':utxo['txid'], 'vout':utxo['vout']}],[{address:0.00010000}])\n        psbt = self.nodes[node].walletprocesspsbt(psbt, False, \"ALL\", True)\n        decode = self.nodes[node].decodepsbt(psbt['psbt'])\n        key_descs = {}\n        for deriv in decode['inputs'][0]['bip32_derivs']:\n            assert_equal(len(deriv['master_fingerprint']), 8)\n            assert_equal(deriv['path'][0], 'm')\n            key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:] + ']' + deriv['pubkey']\n\n        # Verify the descriptor checksum against the Python implementation\n        assert descsum_check(info['desc'])\n        # Verify that stripping the checksum and recreating it using Python roundtrips\n        assert info['desc'] == descsum_create(info['desc'][:-9])\n        # Verify that stripping the checksum and feeding it to getdescriptorinfo roundtrips\n        assert info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'][:-9])['descriptor']\n\n        if not multisig and typ == 'legacy':\n            # P2PKH\n            assert_equal(info['desc'], descsum_create(\"pkh(%s)\" % key_descs[info['pubkey']]))\n        elif not multisig and typ == 'p2sh-segwit':\n            # P2SH-P2WPKH\n            assert_equal(info['desc'], descsum_create(\"sh(wpkh(%s))\" % key_descs[info['pubkey']]))\n        elif not multisig and typ == 'bech32':\n            # P2WPKH\n            assert_equal(info['desc'], descsum_create(\"wpkh(%s)\" % key_descs[info['pubkey']]))\n        elif typ == 'legacy':\n            # P2SH-multisig\n            assert_equal(info['desc'], descsum_create(\"sh(multi(2,%s,%s))\" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])))\n        elif typ == 'p2sh-segwit':\n            # P2SH-P2WSH-multisig\n            assert_equal(info['desc'], descsum_create(\"sh(wsh(multi(2,%s,%s)))\" % (key_descs[info['embedded']['pubkeys'][0]], key_descs[info['embedded']['pubkeys'][1]])))\n        elif typ == 'bech32':\n            # P2WSH-multisig\n            assert_equal(info['desc'], descsum_create(\"wsh(multi(2,%s,%s))\" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])))\n        else:\n            # Unknown type\n            assert False\n\n    def test_change_output_type(self, node_sender, destinations, expected_type):\n        txid = self.nodes[node_sender].sendmany(dummy=\"\", amounts=dict.fromkeys(destinations, 0.001))\n        raw_tx = self.nodes[node_sender].getrawtransaction(txid)\n        tx = self.nodes[node_sender].decoderawtransaction(raw_tx)\n\n        # Make sure the transaction has change:\n        assert_equal(len(tx[\"vout\"]), len(destinations) + 1)\n\n        # Make sure the destinations are included, and remove them:\n        output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx[\"vout\"]]\n        change_addresses = [d for d in output_addresses if d not in destinations]\n        assert_equal(len(change_addresses), 1)\n\n        self.log.debug(\"Check if change address \" + change_addresses[0] + \" is \" + expected_type)\n        self.test_address(node_sender, change_addresses[0], multisig=False, typ=expected_type)\n\n    def run_test(self):\n        # Mine 101 blocks on node5 to bring nodes out of IBD and make sure that\n        # no coinbases are maturing for the nodes-under-test during the test\n        self.nodes[5].generate(101)\n        sync_blocks(self.nodes)\n\n        uncompressed_1 = \"0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee\"\n        uncompressed_2 = \"047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77\"\n        compressed_1 = \"0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52\"\n        compressed_2 = \"037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073\"\n\n        # addmultisigaddress with at least 1 uncompressed key should return a legacy address.\n        for node in range(4):\n            self.test_address(node, self.nodes[node].addmultisigaddress(2, [uncompressed_1, uncompressed_2])['address'], True, 'legacy')\n            self.test_address(node, self.nodes[node].addmultisigaddress(2, [compressed_1, uncompressed_2])['address'], True, 'legacy')\n            self.test_address(node, self.nodes[node].addmultisigaddress(2, [uncompressed_1, compressed_2])['address'], True, 'legacy')\n        # addmultisigaddress with all compressed keys should return the appropriate address type (even when the keys are not ours).\n        self.test_address(0, self.nodes[0].addmultisigaddress(2, [compressed_1, compressed_2])['address'], True, 'legacy')\n        self.test_address(1, self.nodes[1].addmultisigaddress(2, [compressed_1, compressed_2])['address'], True, 'p2sh-segwit')\n        self.test_address(2, self.nodes[2].addmultisigaddress(2, [compressed_1, compressed_2])['address'], True, 'p2sh-segwit')\n        self.test_address(3, self.nodes[3].addmultisigaddress(2, [compressed_1, compressed_2])['address'], True, 'bech32')\n\n        for explicit_type, multisig, from_node in itertools.product([False, True], [False, True], range(4)):\n            address_type = None\n            if explicit_type and not multisig:\n                if from_node == 1:\n                    address_type = 'bech32'\n                elif from_node == 0 or from_node == 3:\n                    address_type = 'p2sh-segwit'\n                else:\n                    address_type = 'legacy'\n            self.log.info(\"Sending from node {} ({}) with{} multisig using {}\".format(from_node, self.extra_args[from_node], \"\" if multisig else \"out\", \"default\" if address_type is None else address_type))\n            old_balances = self.get_balances()\n            self.log.debug(\"Old balances are {}\".format(old_balances))\n            to_send = (old_balances[from_node] / 101).quantize(Decimal(\"0.00000001\"))\n            sends = {}\n            addresses = {}\n\n            self.log.debug(\"Prepare sends\")\n            for n, to_node in enumerate(range(from_node, from_node + 4)):\n                to_node %= 4\n                change = False\n                if not multisig:\n                    if from_node == to_node:\n                        # When sending non-multisig to self, use getrawchangeaddress\n                        address = self.nodes[to_node].getrawchangeaddress(address_type=address_type)\n                        change = True\n                    else:\n                        address = self.nodes[to_node].getnewaddress(address_type=address_type)\n                else:\n                    addr1 = self.nodes[to_node].getnewaddress()\n                    addr2 = self.nodes[to_node].getnewaddress()\n                    address = self.nodes[to_node].addmultisigaddress(2, [addr1, addr2])['address']\n\n                # Do some sanity checking on the created address\n                if address_type is not None:\n                    typ = address_type\n                elif to_node == 0:\n                    typ = 'legacy'\n                elif to_node == 1 or (to_node == 2 and not change):\n                    typ = 'p2sh-segwit'\n                else:\n                    typ = 'bech32'\n                self.test_address(to_node, address, multisig, typ)\n\n                # Output entry\n                sends[address] = to_send * 10 * (1 + n)\n                addresses[to_node] = (address, typ)\n\n            self.log.debug(\"Sending: {}\".format(sends))\n            self.nodes[from_node].sendmany(\"\", sends)\n            sync_mempools(self.nodes)\n\n            unconf_balances = self.get_balances(False)\n            self.log.debug(\"Check unconfirmed balances: {}\".format(unconf_balances))\n            assert_equal(unconf_balances[from_node], 0)\n            for n, to_node in enumerate(range(from_node + 1, from_node + 4)):\n                to_node %= 4\n                assert_equal(unconf_balances[to_node], to_send * 10 * (2 + n))\n\n            # node5 collects fee and block subsidy to keep accounting simple\n            self.nodes[5].generate(1)\n            sync_blocks(self.nodes)\n\n            # Verify that the receiving wallet contains a UTXO with the expected address, and expected descriptor\n            for n, to_node in enumerate(range(from_node, from_node + 4)):\n                to_node %= 4\n                found = False\n                for utxo in self.nodes[to_node].listunspent():\n                    if utxo['address'] == addresses[to_node][0]:\n                        found = True\n                        self.test_desc(to_node, addresses[to_node][0], multisig, addresses[to_node][1], utxo)\n                        break\n                assert found\n\n            new_balances = self.get_balances()\n            self.log.debug(\"Check new balances: {}\".format(new_balances))\n            # We don't know what fee was set, so we can only check bounds on the balance of the sending node\n            assert_greater_than(new_balances[from_node], to_send * 10)\n            assert_greater_than(to_send * 11, new_balances[from_node])\n            for n, to_node in enumerate(range(from_node + 1, from_node + 4)):\n                to_node %= 4\n                assert_equal(new_balances[to_node], old_balances[to_node] + to_send * 10 * (2 + n))\n\n        # Get one p2sh/segwit address from node2 and two bech32 addresses from node3:\n        to_address_p2sh = self.nodes[2].getnewaddress()\n        to_address_bech32_1 = self.nodes[3].getnewaddress()\n        to_address_bech32_2 = self.nodes[3].getnewaddress()\n\n        # Fund node 4:\n        self.nodes[5].sendtoaddress(self.nodes[4].getnewaddress(), Decimal(\"1\"))\n        self.nodes[5].generate(1)\n        sync_blocks(self.nodes)\n        assert_equal(self.nodes[4].getbalance(), 1)\n\n        self.log.info(\"Nodes with addresstype=legacy never use a P2WPKH change output\")\n        self.test_change_output_type(0, [to_address_bech32_1], 'legacy')\n\n        self.log.info(\"Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:\")\n        self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')\n        self.test_change_output_type(1, [to_address_bech32_1], 'bech32')\n        self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')\n        self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')\n\n        self.log.info(\"Nodes with change_type=bech32 always use a P2WPKH change output:\")\n        self.test_change_output_type(2, [to_address_bech32_1], 'bech32')\n        self.test_change_output_type(2, [to_address_p2sh], 'bech32')\n\n        self.log.info(\"Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):\")\n        self.test_change_output_type(3, [to_address_bech32_1], 'bech32')\n        self.test_change_output_type(3, [to_address_p2sh], 'bech32')\n\n        self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')\n        self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')\n\n        self.log.info('test invalid address type arguments')\n        assert_raises_rpc_error(-5, \"Unknown address type ''\", self.nodes[3].addmultisigaddress, 2, [compressed_1, compressed_2], None, '')\n        assert_raises_rpc_error(-5, \"Unknown address type ''\", self.nodes[3].getnewaddress, None, '')\n        assert_raises_rpc_error(-5, \"Unknown address type ''\", self.nodes[3].getrawchangeaddress, '')\n        assert_raises_rpc_error(-5, \"Unknown address type 'bech23'\", self.nodes[3].getrawchangeaddress, 'bech23')\n\n        self.log.info(\"Nodes with changetype=p2sh-segwit never use a P2WPKH change output\")\n        self.test_change_output_type(4, [to_address_bech32_1], 'p2sh-segwit')\n        self.test_address(4, self.nodes[4].getrawchangeaddress(), multisig=False, typ='p2sh-segwit')\n        self.log.info(\"Except for getrawchangeaddress if specified:\")\n        self.test_address(4, self.nodes[4].getrawchangeaddress(), multisig=False, typ='p2sh-segwit')\n        self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')\n\nif __name__ == '__main__':\n    AddressTypeTest().main()\n"
  },
  {
    "path": "test/functional/wallet_backup.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet backup features.\n\nTest case is:\n4 nodes. 1 2 and 3 send transactions between each other,\nfourth node is a miner.\n1 2 3 each mine a block to start, then\nMiner creates 100 blocks so 1 2 3 each have 50 mature\ncoins to spend.\nThen 5 iterations of 1/2/3 sending coins amongst\nthemselves to get transactions in the wallets,\nand the miner mining one block.\n\nWallets are backed up using dumpwallet/backupwallet.\nThen 5 more iterations of transactions and mining a block.\n\nMiner then generates 101 more blocks, so any\ntransaction fees paid mature.\n\nSanity check:\n  Sum(1,2,3,4 balances) == 114*50\n\n1/2/3 are shutdown, and their wallets erased.\nThen restore using wallet.dat backup. And\nconfirm 1/2/3/4 balances are same as before.\n\nShutdown again, restore using importwallet,\nand confirm again balances are correct.\n\"\"\"\nfrom decimal import Decimal\nimport os\nfrom random import randint\nimport shutil\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks, sync_mempools\n\nclass WalletBackupTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n        # nodes 1, 2,3 are spenders, let's give them a keypool=100\n        self.extra_args = [[\"-keypool=100\"], [\"-keypool=100\"], [\"-keypool=100\"], []]\n        self.rpc_timeout = 180\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n        connect_nodes(self.nodes[0], 3)\n        connect_nodes(self.nodes[1], 3)\n        connect_nodes(self.nodes[2], 3)\n        connect_nodes(self.nodes[2], 0)\n        self.sync_all()\n\n    def one_send(self, from_node, to_address):\n        if (randint(1,2) == 1):\n            amount = Decimal(randint(1,10)) / Decimal(10)\n            self.nodes[from_node].sendtoaddress(to_address, amount)\n\n    def do_one_round(self):\n        a0 = self.nodes[0].getnewaddress()\n        a1 = self.nodes[1].getnewaddress()\n        a2 = self.nodes[2].getnewaddress()\n\n        self.one_send(0, a1)\n        self.one_send(0, a2)\n        self.one_send(1, a0)\n        self.one_send(1, a2)\n        self.one_send(2, a0)\n        self.one_send(2, a1)\n\n        # Have the miner (node3) mine a block.\n        # Must sync mempools before mining.\n        sync_mempools(self.nodes)\n        self.nodes[3].generate(1)\n        sync_blocks(self.nodes)\n\n    # As above, this mirrors the original bash test.\n    def start_three(self):\n        self.start_node(0)\n        self.start_node(1)\n        self.start_node(2)\n        connect_nodes(self.nodes[0], 3)\n        connect_nodes(self.nodes[1], 3)\n        connect_nodes(self.nodes[2], 3)\n        connect_nodes(self.nodes[2], 0)\n\n    def stop_three(self):\n        self.stop_node(0)\n        self.stop_node(1)\n        self.stop_node(2)\n\n    def erase_three(self):\n        os.remove(os.path.join(self.nodes[0].datadir, 'regtestlegacy', 'wallet.dat'))\n        os.remove(os.path.join(self.nodes[1].datadir, 'regtestlegacy', 'wallet.dat'))\n        os.remove(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'wallet.dat'))\n\n    def run_test(self):\n        self.log.info(\"Generating initial blockchain\")\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n        self.nodes[1].generate(1)\n        sync_blocks(self.nodes)\n        self.nodes[2].generate(1)\n        sync_blocks(self.nodes)\n        self.nodes[3].generate(100)\n        sync_blocks(self.nodes)\n\n        assert_equal(self.nodes[0].getbalance(), 50)\n        assert_equal(self.nodes[1].getbalance(), 50)\n        assert_equal(self.nodes[2].getbalance(), 50)\n        assert_equal(self.nodes[3].getbalance(), 0)\n\n        self.log.info(\"Creating transactions\")\n        # Five rounds of sending each other transactions.\n        for i in range(5):\n            self.do_one_round()\n\n        self.log.info(\"Backing up\")\n\n        self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, 'wallet.bak'))\n        self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, 'wallet.dump'), 'I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY')\n        self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, 'wallet.bak'))\n        self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump'), 'I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY')\n        self.nodes[2].backupwallet(os.path.join(self.nodes[2].datadir, 'wallet.bak'))\n        self.nodes[2].dumpwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump'), 'I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY')\n\n        self.log.info(\"More transactions\")\n        for i in range(5):\n            self.do_one_round()\n\n        #fixme: This was previously 101 blocks, bumped to 110 because for some reason there were balance (maturity?) issues with 101\n        #however 101 should work... so we should look closer at this and change back to 101 (or at least make it also work with 101)\n        # Generate 110 more blocks, so any fees paid mature\n        self.nodes[3].generate(110)\n        self.sync_all()\n\n        balance0 = self.nodes[0].getbalance()\n        balance1 = self.nodes[1].getbalance()\n        balance2 = self.nodes[2].getbalance()\n        balance3 = self.nodes[3].getbalance()\n        total = balance0 + balance1 + balance2 + balance3\n\n        # At this point, there are 223 blocks (103 for setup, then 10 rounds, then 110.)\n        # 123 are mature, so the sum of all wallets should be 123 * 50 = 6150.\n        assert_equal(total, 6150)\n\n        ##\n        # Test restoring spender wallets from backups\n        ##\n        self.log.info(\"Restoring using wallet.dat\")\n        self.stop_three()\n        self.erase_three()\n\n        # Start node2 with no chain\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'blocks'))\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'chainstate'))\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'witstate'))\n\n        # Restore wallets from backup\n        shutil.copyfile(os.path.join(self.nodes[0].datadir, 'wallet.bak'), os.path.join(self.nodes[0].datadir, 'regtestlegacy', 'wallet.dat'))\n        shutil.copyfile(os.path.join(self.nodes[1].datadir, 'wallet.bak'), os.path.join(self.nodes[1].datadir, 'regtestlegacy', 'wallet.dat'))\n        shutil.copyfile(os.path.join(self.nodes[2].datadir, 'wallet.bak'), os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'wallet.dat'))\n\n        self.log.info(\"Re-starting nodes\")\n        self.start_three()\n        sync_blocks(self.nodes)\n\n        assert_equal(self.nodes[0].getbalance(), balance0)\n        assert_equal(self.nodes[1].getbalance(), balance1)\n        assert_equal(self.nodes[2].getbalance(), balance2)\n\n        self.log.info(\"Restoring using dumped wallet\")\n        self.stop_three()\n        self.erase_three()\n\n        #start node2 with no chain\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'blocks'))\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'chainstate'))\n        shutil.rmtree(os.path.join(self.nodes[2].datadir, 'regtestlegacy', 'witstate'))\n\n        self.start_three()\n\n        assert_equal(self.nodes[0].getbalance(), 0)\n        assert_equal(self.nodes[1].getbalance(), 0)\n        assert_equal(self.nodes[2].getbalance(), 0)\n\n        self.nodes[0].createaccount(name=\"Legacy\", type=\"Legacy\")\n        self.nodes[0].setactiveaccount(account=\"Legacy\")\n        self.nodes[0].importwallet(os.path.join(self.nodes[0].datadir, 'wallet.dump'), 'Legacy')\n        self.nodes[1].createaccount(name=\"Legacy\", type=\"Legacy\")\n        self.nodes[1].setactiveaccount(account=\"Legacy\")\n        self.nodes[1].importwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump'), 'Legacy')\n        self.nodes[2].createaccount(name=\"Legacy\", type=\"Legacy\")\n        self.nodes[2].setactiveaccount(account=\"Legacy\")\n        self.nodes[2].importwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump'), 'Legacy')\n\n        sync_blocks(self.nodes)\n\n        assert_equal(self.nodes[0].getbalance(), balance0)\n        assert_equal(self.nodes[1].getbalance(), balance1)\n        assert_equal(self.nodes[2].getbalance(), balance2)\n\n        # Backup to source wallet file must fail\n        sourcePaths = [\n            os.path.join(self.nodes[0].datadir, 'regtestlegacy', 'wallet.dat')\n            ]\n\n        for sourcePath in sourcePaths:\n            assert_raises_rpc_error(-4, \"backup failed\", self.nodes[0].backupwallet, sourcePath)\n\n\nif __name__ == '__main__':\n    WalletBackupTest().main()\n"
  },
  {
    "path": "test/functional/wallet_balance.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet balance RPC methods.\"\"\"\nimport time\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\nRANDOM_COINBASE_ADDRESS = 'RCSTsbHpfVPR8FxHobrUwYsLyUFD4oU43Q'\n\ndef create_transactions(node, address, amt, fees):\n    # Create and sign raw transactions from node to address for amt.\n    # Creates a transaction for each fee and returns an array\n    # of the raw transactions.\n    utxos = node.listunspent(0)\n\n    # Create transactions\n    inputs = []\n    ins_total = 0\n    for utxo in utxos:\n        inputs.append({\"txid\": utxo[\"txid\"], \"vout\": utxo[\"vout\"]})\n        ins_total += utxo['amount']\n        if ins_total > amt:\n            break\n\n    txs = []\n    for fee in fees:\n        outputs = {address: amt, node.getrawchangeaddress(): ins_total - amt - fee}\n        raw_tx = node.createrawtransaction(inputs, outputs, 0, True)\n        raw_tx = node.signrawtransaction(raw_tx)\n        txs.append(raw_tx)\n\n    return txs\n\nclass WalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Check that nodes don't own any UTXOs\n        assert_equal(len(self.nodes[0].listunspent()), 0)\n        assert_equal(len(self.nodes[1].listunspent()), 0)\n\n        self.log.info(\"Mining one block for each node\")\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n        self.nodes[1].generate(1)\n        self.nodes[1].generatetoaddress(100, RANDOM_COINBASE_ADDRESS)\n        self.sync_all()\n\n        assert_equal(self.nodes[0].getbalance(), 50)\n        assert_equal(self.nodes[1].getbalance(), 50)\n\n        self.log.info(\"Test getbalance with different arguments\")\n        assert_equal(self.nodes[0].getbalance(\"*\"), 50)\n        assert_equal(self.nodes[0].getbalance(\"*\", 1), 50)\n        assert_equal(self.nodes[0].getbalance(\"*\", 1, True), 50)\n        assert_equal(self.nodes[0].getbalance(min_conf=1), 50)\n\n        # Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0.\n        txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')])\n        self.nodes[0].sendrawtransaction(txs[0]['hex'])\n        self.nodes[1].sendrawtransaction(txs[0]['hex'])  # sending on both nodes is faster than waiting for propagation\n\n        self.sync_all()\n        txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), 60, [Decimal('0.01'), Decimal('0.02')])\n        self.nodes[1].sendrawtransaction(txs[0]['hex'])\n        self.nodes[0].sendrawtransaction(txs[0]['hex'])  # sending on both nodes is faster than waiting for propagation\n        self.sync_all()\n\n        # First argument of getbalance must be set to \"*\"\n        #assert_raises_rpc_error(-32, \"dummy first argument must be excluded or set to \\\"*\\\"\", self.nodes[1].getbalance, \"\")\n\n        self.log.info(\"Test getbalance and getunconfirmedbalance with unconfirmed inputs\")\n\n        # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions\n        #assert_equal(self.nodes[0].getbalance(\"*\"), Decimal('9.99'))  # change from node 0's send\n        #assert_equal(self.nodes[1].getbalance(\"*\"), Decimal('29.99'))  # change from node 1's send\n        # Same with minconf=0\n        #assert_equal(self.nodes[0].getbalance(\"*\", min_conf=0), Decimal('9.99'))\n        #assert_equal(self.nodes[1].getbalance(\"*\", min_conf=0), Decimal('29.99'))\n        # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago\n        # TODO: fix getbalance tracking of coin spentness depth\n        assert_equal(self.nodes[0].getbalance(min_conf=1), Decimal('0'))\n        assert_equal(self.nodes[1].getbalance(min_conf=1), Decimal('0'))\n        # getunconfirmedbalance\n        assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60'))  # output of node 1's spend\n        assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0'))  # Doesn't include output of node 0's send since it was spent\n\n        # Node 1 bumps the transaction fee and resends\n        self.nodes[1].sendrawtransaction(txs[1]['hex'])\n        self.sync_all()\n\n        self.log.info(\"Test getbalance and getunconfirmedbalance with conflicted unconfirmed inputs\")\n\n        assert_equal(self.nodes[0].getwalletinfo()[\"unconfirmed_balance\"], Decimal('60'))  # output of node 1's send\n        assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60'))\n        assert_equal(self.nodes[1].getwalletinfo()[\"unconfirmed_balance\"], Decimal('0'))  # Doesn't include output of node 0's send since it was spent\n        assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0'))\n\n        self.nodes[1].generatetoaddress(1, RANDOM_COINBASE_ADDRESS)\n        self.sync_all()\n\n        # balances are correct after the transactions are confirmed\n        assert_equal(self.nodes[0].getbalance(), Decimal('69.99'))  # node 1's send plus change from node 0's send\n        assert_equal(self.nodes[1].getbalance(), Decimal('29.98'))  # change from node 0's send\n\n        # Send total balance away from node 1\n        txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.97'), [Decimal('0.01')])\n        self.nodes[1].sendrawtransaction(txs[0]['hex'])\n        self.nodes[1].generatetoaddress(2, RANDOM_COINBASE_ADDRESS)\n        self.sync_all()\n\n        # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago\n        # TODO: fix getbalance tracking of coin spentness depth\n        # getbalance with minconf=3 should still show the old balance\n        assert_equal(self.nodes[1].getbalance(min_conf=3), Decimal('0'))\n\n        # getbalance with minconf=2 will show the new balance.\n        assert_equal(self.nodes[1].getbalance(min_conf=2), Decimal('0'))\n\n        # check mempool transactions count for wallet unconfirmed balance after\n        # dynamically loading the wallet.\n        #before = self.nodes[1].getunconfirmedbalance()\n        #dst = self.nodes[1].getnewaddress()\n        #self.nodes[1].unloadwallet('')\n        #self.nodes[0].sendtoaddress(dst, 0.1)\n        #self.sync_all()\n        #self.nodes[1].loadwallet('')\n        #after = self.nodes[1].getunconfirmedbalance()\n        #assert_equal(before + Decimal('0.1'), after)\n\n\nif __name__ == '__main__':\n    WalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_basic.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet.\"\"\"\nfrom decimal import Decimal\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_array_result,\n    assert_equal,\n    assert_fee_amount,\n    assert_raises_rpc_error,\n    connect_nodes_bi,\n    sync_blocks,\n    wait_until,\n)\n\n\nclass WalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n        self.rpc_timeout = 180\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n        # Only need nodes 0-2 running at start of test\n        self.stop_node(3)\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 1, 2)\n        connect_nodes_bi(self.nodes, 0, 2)\n        self.sync_all([self.nodes[0:3]])\n\n    def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):\n        \"\"\"Return curr_balance after asserting the fee was in range\"\"\"\n        fee = balance_with_fee - curr_balance\n        assert_fee_amount(fee, tx_size, fee_per_byte * 1000)\n        return curr_balance\n\n    def get_vsize(self, txn):\n        return self.nodes[0].decoderawtransaction(txn)['vsize']\n\n    def run_test(self):\n        # Check that there's no UTXO on none of the nodes\n        assert_equal(len(self.nodes[0].listunspent()), 0)\n        assert_equal(len(self.nodes[1].listunspent()), 0)\n        assert_equal(len(self.nodes[2].listunspent()), 0)\n\n        self.log.info(\"Mining blocks...\")\n\n        self.nodes[0].generate(1)\n\n        walletinfo = self.nodes[0].getwalletinfo()\n        assert_equal(walletinfo['immature_balance'], 50)\n        assert_equal(walletinfo['balance'], 0)\n\n        self.sync_all([self.nodes[0:3]])\n        self.nodes[1].generate(101)\n        self.sync_all([self.nodes[0:3]])\n\n        assert_equal(self.nodes[0].getbalance(), 50)\n        assert_equal(self.nodes[1].getbalance(), 50)\n        assert_equal(self.nodes[2].getbalance(), 0)\n\n        # Check that only first and second nodes have UTXOs\n        utxos = self.nodes[0].listunspent()\n        assert_equal(len(utxos), 1)\n        assert_equal(len(self.nodes[1].listunspent()), 1)\n        assert_equal(len(self.nodes[2].listunspent()), 0)\n\n        self.log.info(\"test gettxout\")\n        confirmed_txid, confirmed_index = utxos[0][\"txid\"], utxos[0][\"vout\"]\n        # First, outputs that are unspent both in the chain and in the\n        # mempool should appear with or without include_mempool\n        txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False)\n        assert_equal(txout['value'], 50)\n        txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True)\n        assert_equal(txout['value'], 50)\n\n        # Send 21 MUNT from 0 to 2 using sendtoaddress call.\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)\n        mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)\n\n        self.log.info(\"test gettxout (second part)\")\n        # utxo spent in mempool should be visible if you exclude mempool\n        # but invisible if you include mempool\n        txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)\n        assert_equal(txout['value'], 50)\n        txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)\n        assert txout is None\n        # new utxo from mempool should be invisible if you exclude mempool\n        # but visible if you include mempool\n        txout = self.nodes[0].gettxout(mempool_txid, 0, False)\n        assert txout is None\n        txout1 = self.nodes[0].gettxout(mempool_txid, 0, True)\n        txout2 = self.nodes[0].gettxout(mempool_txid, 1, True)\n        # note the mempool tx will have randomly assigned indices\n        # but 10 will go to node2 and the rest will go to node0\n        balance = self.nodes[0].getbalance(\"\", 0)\n        assert_equal(set([txout1['value'], txout2['value']]), set([10, balance]))\n        walletinfo = self.nodes[0].getwalletinfo()\n        assert_equal(walletinfo['immature_balance'], 0)\n\n        # Have node0 mine a block, thus it will collect its own fee.\n        self.nodes[0].generate(1)\n        self.sync_all([self.nodes[0:3]])\n\n        # Exercise locking of unspent outputs\n        ###unspent_0 = self.nodes[2].listunspent()[0]\n        ###unspent_0 = {\"txid\": unspent_0[\"txid\"], \"vout\": unspent_0[\"vout\"]}\n        ###assert_raises_rpc_error(-8, \"Invalid parameter, expected locked output\", self.nodes[2].lockunspent, True, [unspent_0])\n        ###self.nodes[2].lockunspent(False, [unspent_0])\n        ###assert_raises_rpc_error(-8, \"Invalid parameter, output already locked\", self.nodes[2].lockunspent, False, [unspent_0])\n        ###assert_raises_rpc_error(-4, \"Insufficient funds\", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)\n        ###assert_equal([unspent_0], self.nodes[2].listlockunspent())\n        ###self.nodes[2].lockunspent(True, [unspent_0])\n        ###assert_equal(len(self.nodes[2].listlockunspent()), 0)\n        ###assert_raises_rpc_error(-8, \"txid must be of length 64 (not 34, for '0000000000000000000000000000000000')\",\n                                ###self.nodes[2].lockunspent, False,\n                                ###[{\"txid\": \"0000000000000000000000000000000000\", \"vout\": 0}])\n        ###assert_raises_rpc_error(-8, \"txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')\",\n                                ###self.nodes[2].lockunspent, False,\n                                ###[{\"txid\": \"ZZZ0000000000000000000000000000000000000000000000000000000000000\", \"vout\": 0}])\n        ###assert_raises_rpc_error(-8, \"Invalid parameter, unknown transaction\",\n                                ###self.nodes[2].lockunspent, False,\n                                ###[{\"txid\": \"0000000000000000000000000000000000000000000000000000000000000000\", \"vout\": 0}])\n        ###assert_raises_rpc_error(-8, \"Invalid parameter, vout index out of bounds\",\n                                ###self.nodes[2].lockunspent, False,\n                                ###[{\"txid\": unspent_0[\"txid\"], \"vout\": 999}])\n\n        # An output should be unlocked when spent\n        ###unspent_0 = self.nodes[1].listunspent()[0]\n        ###self.nodes[1].lockunspent(False, [unspent_0])\n        ###tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 })\n        ###tx = self.nodes[1].fundrawtransaction(tx)['hex']\n        ###tx = self.nodes[1].signrawtransaction(tx)[\"hex\"]\n        ###self.nodes[1].sendrawtransaction(tx)\n        ###assert_equal(len(self.nodes[1].listlockunspent()), 0)\n\n        # Have node1 generate 100 blocks (so node0 can recover the fee)\n        self.nodes[1].generate(100)\n        self.sync_all([self.nodes[0:3]])\n\n        # node0 should end up with 100 MUNT in block rewards plus fees, but\n        # minus the 21 plus fees sent to node2\n        assert_equal(self.nodes[0].getbalance(), 100 - 21)\n        assert_equal(self.nodes[2].getbalance(), 21)\n\n        # Node0 should have two unspent outputs.\n        # Create a couple of transactions to send them to node2, submit them through\n        # node1, and make sure both node0 and node2 pick them up properly:\n        node0utxos = self.nodes[0].listunspent(1)\n        assert_equal(len(node0utxos), 2)\n\n        # create both transactions\n        txns_to_send = []\n        for utxo in node0utxos:\n            inputs = []\n            outputs = {}\n            inputs.append({\"txid\": utxo[\"txid\"], \"vout\": utxo[\"vout\"]})\n            outputs[self.nodes[2].getnewaddress()] = utxo[\"amount\"] - 3\n            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)\n            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))\n\n        # Have node 1 (miner) send the transactions\n        self.nodes[1].sendrawtransaction(txns_to_send[0][\"hex\"], True)\n        self.nodes[1].sendrawtransaction(txns_to_send[1][\"hex\"], True)\n\n        # Have node1 mine a block to confirm transactions:\n        self.nodes[1].generate(1)\n        self.sync_all([self.nodes[0:3]])\n\n        assert_equal(self.nodes[0].getbalance(), 0)\n        assert_equal(self.nodes[2].getbalance(), 94)\n\n        # Verify that a spent output cannot be locked anymore\n        ###spent_0 = {\"txid\": node0utxos[0][\"txid\"], \"vout\": node0utxos[0][\"vout\"]}\n        ###assert_raises_rpc_error(-8, \"Invalid parameter, expected unspent output\", self.nodes[0].lockunspent, False, [spent_0])\n\n        # Send 10 MUNT normal\n        address = self.nodes[0].getnewaddress()\n        fee_per_byte = Decimal('0.001') / 1000\n        self.nodes[2].settxfee(fee_per_byte * 1000)\n        txid = self.nodes[2].sendtoaddress(address, 10, \"\", \"\", False)\n        self.nodes[2].generate(1)\n        self.sync_all([self.nodes[0:3]])\n        ###node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))\n        assert_equal(self.nodes[0].getbalance(), Decimal('10'))\n\n        # Send 10 MUNT with subtract fee from amount\n        txid = self.nodes[2].sendtoaddress(address, 10, \"\", \"\", True)\n        self.nodes[2].generate(1)\n        self.sync_all([self.nodes[0:3]])\n        ###node_2_bal -= Decimal('10')\n        ###assert_equal(self.nodes[2].getbalance(), node_2_bal)\n        ###node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))\n\n        # Sendmany 10 MUNT\n        txid = self.nodes[2].sendmany('', {address: 10}, 0, \"\", [])\n        self.nodes[2].generate(1)\n        self.sync_all([self.nodes[0:3]])\n        ###node_0_bal += Decimal('10')\n        ###node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))\n        ###assert_equal(self.nodes[0].getbalance(), node_0_bal)\n\n        # Sendmany 10 MUNT with subtract fee from amount\n        txid = self.nodes[2].sendmany('', {address: 10}, 0, \"\", [address])\n        self.nodes[2].generate(1)\n        self.sync_all([self.nodes[0:3]])\n        ###node_2_bal -= Decimal('10')\n        ###assert_equal(self.nodes[2].getbalance(), node_2_bal)\n        ###node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))\n\n        self.start_node(3)\n        connect_nodes_bi(self.nodes, 0, 3)\n        self.sync_all([self.nodes[0:3]])\n\n        # check if we can list zero value tx as available coins\n        # 1. create raw_tx\n        # 2. hex-changed one output to 0.0\n        # 3. sign and send\n        # 4. check if recipient (node0) can list the zero value tx\n        ###usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0]\n        ###inputs = [{\"txid\": usp['txid'], \"vout\": usp['vout']}]\n        ###outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11}\n\n        ###raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace(\"c0833842\", \"00000000\")  # replace 11.11 with 0.0 (int32)\n        ###signed_raw_tx = self.nodes[1].signrawtransaction(raw_tx)\n        ###decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex'])\n        ###zero_value_txid = decoded_raw_tx['txid']\n        ###self.nodes[1].sendrawtransaction(signed_raw_tx['hex'])\n\n        ###self.sync_all()\n        ###self.nodes[1].generate(1)  # mine a block\n        ###self.sync_all()\n\n        ###unspent_txs = self.nodes[0].listunspent()  # zero value tx must be in listunspents output\n        ###found = False\n        ##for uTx in unspent_txs:\n            ###if uTx['txid'] == zero_value_txid:\n               ### found = True\n                ###assert_equal(uTx['amount'], Decimal('0'))\n        ###assert found\n\n        # do some -walletbroadcast tests\n        self.stop_nodes()\n        self.start_node(0, [\"-walletbroadcast=0\"])\n        self.start_node(1, [\"-walletbroadcast=0\"])\n        self.start_node(2, [\"-walletbroadcast=0\"])\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 1, 2)\n        connect_nodes_bi(self.nodes, 0, 2)\n        self.sync_all([self.nodes[0:3]])\n\n        txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)\n        tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)\n        self.nodes[1].generate(1)  # mine a block, tx should not be in there\n        self.sync_all([self.nodes[0:3]])\n        ###assert_equal(self.nodes[2].getbalance(), node_2_bal)  # should not be changed because tx was not broadcasted\n\n        # now broadcast from another node, mine a block, sync, and check the balance\n        self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex'])\n        self.nodes[1].generate(1)\n        self.sync_all([self.nodes[0:3]])\n        ###node_2_bal += 2\n        tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)\n        ###assert_equal(self.nodes[2].getbalance(), node_2_bal)\n\n        # create another tx\n        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)\n\n        # restart the nodes with -walletbroadcast=1\n        self.stop_nodes()\n        self.start_node(0)\n        self.start_node(1)\n        self.start_node(2)\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 1, 2)\n        connect_nodes_bi(self.nodes, 0, 2)\n        sync_blocks(self.nodes[0:3])\n\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes[0:3])\n        ###node_2_bal += 2\n\n        # tx should be added to balance because after restarting the nodes tx should be broadcast\n        ###assert_equal(self.nodes[2].getbalance(), node_2_bal)\n\n        # send a tx with value in a string (PR#6380 +)\n        txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), \"2\")\n        tx_obj = self.nodes[0].gettransaction(txid)\n        assert_equal(tx_obj['amount'], Decimal('-2'))\n\n        txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), \"0.0001\")\n        tx_obj = self.nodes[0].gettransaction(txid)\n        assert_equal(tx_obj['amount'], Decimal('-0.0001'))\n\n        # check if JSON parser can handle scientific notation in strings\n        txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), \"1e-4\")\n        tx_obj = self.nodes[0].gettransaction(txid)\n        assert_equal(tx_obj['amount'], Decimal('-0.0001'))\n\n        # General checks for errors from incorrect inputs\n        # This will raise an exception because the amount type is wrong\n        assert_raises_rpc_error(-3, \"Invalid amount\", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), \"1f-4\")\n\n        # This will raise an exception since generate does not accept a string\n        assert_raises_rpc_error(-1, \"not an integer\", self.nodes[0].generate, \"2\")\n\n        # This will raise an exception for the invalid private key format\n        ###assert_raises_rpc_error(-5, \"Invalid private key encoding\", self.nodes[0].importprivkey, \"invalid\")\n\n        # This will raise an exception for importing an address with the PS2H flag\n        temp_address = self.nodes[1].getnewaddress()\n        ###assert_raises_rpc_error(-5, \"Cannot use the p2sh flag with an address - use a script instead\", self.nodes[0].importaddress, temp_address, \"label\", False, True)\n\n        # This will raise an exception for attempting to dump the private key of an address you do not own\n        ###assert_raises_rpc_error(-3, \"Address does not refer to a key\", self.nodes[0].dumpprivkey, temp_address)\n\n        # This will raise an exception for attempting to get the private key of an invalid Munt address\n        ###assert_raises_rpc_error(-5, \"Invalid Munt address\", self.nodes[0].dumpprivkey, \"invalid\")\n\n        # This will raise an exception for attempting to set a label for an invalid Munt address\n        ###assert_raises_rpc_error(-5, \"Invalid Munt address\", self.nodes[0].setlabel, \"invalid address\", \"label\")\n\n        # This will raise an exception for importing an invalid address\n        ###assert_raises_rpc_error(-5, \"Invalid Munt address or script\", self.nodes[0].importaddress, \"invalid\")\n\n        # This will raise an exception for attempting to import a pubkey that isn't in hex\n        ###assert_raises_rpc_error(-5, \"Pubkey must be a hex string\", self.nodes[0].importpubkey, \"not hex\")\n\n        # This will raise an exception for importing an invalid pubkey\n        ###assert_raises_rpc_error(-5, \"Pubkey is not a valid public key\", self.nodes[0].importpubkey, \"5361746f736869204e616b616d6f746f\")\n\n        # Import address and private key to check correct behavior of spendable unspents\n        # 1. Send some coins to generate new UTXO\n        address_to_import = self.nodes[2].getnewaddress()\n        txid = self.nodes[0].sendtoaddress(address_to_import, 1)\n        self.nodes[0].generate(1)\n        self.sync_all([self.nodes[0:3]])\n\n        # 2. Import address from node2 to node1\n        ###self.nodes[1].importaddress(address_to_import)\n\n        # 3. Validate that the imported address is watch-only on node1\n        ###assert self.nodes[1].getaddressinfo(address_to_import)[\"iswatchonly\"]\n\n        # 4. Check that the unspents after import are not spendable\n        ###assert_array_result(self.nodes[1].listunspent(),\n                            ###{\"address\": address_to_import},\n                            ###{\"spendable\": False})\n\n        # 5. Import private key of the previously imported address on node1\n        ###priv_key = self.nodes[2].dumpprivkey(address_to_import)\n        ###self.nodes[1].importprivkey(priv_key)\n\n        # 6. Check that the unspents are now spendable on node1\n        ###assert_array_result(self.nodes[1].listunspent(),\n                            ###{\"address\": address_to_import},\n                            ##{\"spendable\": True})\n\n        # Mine a block from node0 to an address from node1\n        ###coinbase_addr = self.nodes[1].getnewaddress()\n        ###block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0]\n        ###coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0]\n        ###self.sync_all([self.nodes[0:3]])\n\n        # Check that the txid and balance is found by node1\n        ###self.nodes[1].gettransaction(coinbase_txid)\n\n        # check if wallet or blockchain maintenance changes the balance\n        ###self.sync_all([self.nodes[0:3]])\n        ###blocks = self.nodes[0].generate(2)\n        ###self.sync_all([self.nodes[0:3]])\n        ###balance_nodes = [self.nodes[i].getbalance() for i in range(3)]\n        ###block_count = self.nodes[0].getblockcount()\n\n        # Check modes:\n        #   - True: unicode escaped as \\u....\n        #   - False: unicode directly as UTF-8\n        ###for mode in [True, False]:\n            ###self.nodes[0].rpc.ensure_ascii = mode\n            # unicode check: Basic Multilingual Plane, Supplementary Plane respectively\n            ###for label in [u'рыба', u'𝅘𝅥𝅯']:\n                ###addr = self.nodes[0].getnewaddress()\n                ###self.nodes[0].setlabel(addr, label)\n                ###assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label)\n                ###assert label in self.nodes[0].listlabels()\n        ###self.nodes[0].rpc.ensure_ascii = True  # restore to default\n\n        # maintenance tests\n        maintenance = [\n            '-rescan',\n            '-reindex',\n            '-zapwallettxes=1',\n            '-zapwallettxes=2',\n            # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463\n            # '-salvagewallet',\n        ]\n        chainlimit = 6\n        ###for m in maintenance:\n            ###self.log.info(\"check \" + m)\n            ###self.stop_nodes()\n            # set lower ancestor limit for later\n            ###self.start_node(0, [m, \"-limitancestorcount=\" + str(chainlimit)])\n            ###self.start_node(1, [m, \"-limitancestorcount=\" + str(chainlimit)])\n            ###self.start_node(2, [m, \"-limitancestorcount=\" + str(chainlimit)])\n            ###if m == '-reindex':\n                # reindex will leave rpc warm up \"early\"; Wait for it to finish\n                ###wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])\n            ###assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])\n\n        # Exercise listsinceblock with the last two blocks\n        ###coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])\n        ###assert_equal(coinbase_tx_1[\"lastblock\"], blocks[1])\n        ###assert_equal(len(coinbase_tx_1[\"transactions\"]), 1)\n        ###assert_equal(coinbase_tx_1[\"transactions\"][0][\"blockhash\"], blocks[1])\n        ###assert_equal(len(self.nodes[0].listsinceblock(blocks[1])[\"transactions\"]), 0)\n\n        # ==Check that wallet prefers to use coins that don't exceed mempool limits =====\n\n        # Get all non-zero utxos together\n        ###chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]\n        ###singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), \"\", \"\", True)\n        ###self.nodes[0].generate(1)\n        ###node0_balance = self.nodes[0].getbalance()\n        # Split into two chains\n        ###rawtx = self.nodes[0].createrawtransaction([{\"txid\": singletxid, \"vout\": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')})\n        ###signedtx = self.nodes[0].signrawtransaction(rawtx)\n        ###singletxid = self.nodes[0].sendrawtransaction(signedtx[\"hex\"])\n        ###self.nodes[0].generate(1)\n\n        # Make a long chain of unconfirmed payments without hitting mempool limit\n        # Each tx we make leaves only one output of change on a chain 1 longer\n        # Since the amount to send is always much less than the outputs, we only ever need one output\n        # So we should be able to generate exactly chainlimit txs for each original output\n        ###sending_addr = self.nodes[1].getnewaddress()\n        ###txid_list = []\n        ###for i in range(chainlimit * 2):\n            ###txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')))\n        ###assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2)\n        ###assert_equal(len(txid_list), chainlimit * 2)\n\n        # Without walletrejectlongchains, we will still generate a txid\n        # The tx will be stored in the wallet but not accepted to the mempool\n        ###extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))\n        ###assert extra_txid not in self.nodes[0].getrawmempool()\n        ###assert extra_txid in [tx[\"txid\"] for tx in self.nodes[0].listtransactions()]\n        ###self.nodes[0].abandontransaction(extra_txid)\n        ###total_txs = len(self.nodes[0].listtransactions(\"*\", 99999))\n\n        # Try with walletrejectlongchains\n        # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf\n        ###self.stop_node(0)\n        ###self.start_node(0, extra_args=[\"-walletrejectlongchains\", \"-limitancestorcount=\" + str(2 * chainlimit)])\n\n        # wait for loadmempool\n        ###timeout = 10\n        ###while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit * 2):\n            ###time.sleep(0.5)\n            ###timeout -= 0.5\n        ###assert_equal(len(self.nodes[0].getrawmempool()), chainlimit * 2)\n\n        ###node0_balance = self.nodes[0].getbalance()\n        # With walletrejectlongchains we will not create the tx and store it in our wallet.\n        ###assert_raises_rpc_error(-4, \"Transaction has too long of a mempool chain\", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))\n\n        # Verify nothing new in wallet\n        ###assert_equal(total_txs, len(self.nodes[0].listtransactions(\"*\", 99999)))\n\n        # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py\n        ###assert_raises_rpc_error(-5, \"Invalid address\", self.nodes[0].getaddressinfo, \"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy\")\n        ###address_info = self.nodes[0].getaddressinfo(\"mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ\")\n        ###assert_equal(address_info['address'], \"mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ\")\n        ###assert_equal(address_info[\"scriptPubKey\"], \"76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac\")\n        ###assert not address_info[\"ismine\"]\n        ###assert not address_info[\"iswatchonly\"]\n        ###assert not address_info[\"isscript\"]\n        ###assert not address_info[\"ischange\"]\n\n        # Test getaddressinfo 'ischange' field on change address.\n        ###self.nodes[0].generate(1)\n        ###destination = self.nodes[1].getnewaddress()\n        ###txid = self.nodes[0].sendtoaddress(destination, 0.123)\n        ###tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])\n        ###output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx[\"vout\"]]\n        ###assert len(output_addresses) > 1\n        ###for address in output_addresses:\n            ###ischange = self.nodes[0].getaddressinfo(address)['ischange']\n            ###assert_equal(ischange, address != destination)\n            ###if ischange:\n                ###change = address\n        ###self.nodes[0].setlabel(change, 'foobar')\n        ###assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)\n\n\nif __name__ == '__main__':\n    WalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_bumpfee.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the bumpfee RPC.\n\nVerifies that the bumpfee RPC creates replacement transactions successfully when\nits preconditions are met, and returns appropriate errors in other cases.\n\nThis module consists of around a dozen individual test cases implemented in the\ntop-level functions named as test_<test_case_description>. The test functions\ncan be disabled or reordered if needed for debugging. If new test cases are\nadded in the future, they should try to follow the same convention and not\nmake assumptions about execution order.\n\"\"\"\nfrom decimal import Decimal\nimport io\n\nfrom test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness\nfrom test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, connect_nodes_bi, hex_str_to_bytes, sync_mempools\n\nWALLET_PASSPHRASE = \"test\"\nWALLET_PASSPHRASE_TIMEOUT = 3600\n\nclass BumpFeeTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n        self.extra_args = [[\n            \"-walletrbf={}\".format(i),\n            \"-mintxfee=0.00002\",\n        ] for i in range(self.num_nodes)]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Encrypt wallet for test_locked_wallet_fails test\n        self.nodes[1].encryptwallet(WALLET_PASSPHRASE)\n        self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)\n\n        connect_nodes_bi(self.nodes, 0, 1)\n        self.sync_all()\n\n        peer_node, rbf_node = self.nodes\n        rbf_node_address = rbf_node.getnewaddress()\n\n        # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)\n        self.log.info(\"Mining blocks...\")\n        peer_node.generate(110)\n        self.sync_all()\n        for i in range(25):\n            peer_node.sendtoaddress(rbf_node_address, 0.001)\n        self.sync_all()\n        peer_node.generate(1)\n        self.sync_all()\n        assert_equal(rbf_node.getbalance(), Decimal(\"0.025\"))\n\n        self.log.info(\"Running tests\")\n        dest_address = peer_node.getnewaddress()\n        test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)\n        test_segwit_bumpfee_succeeds(rbf_node, dest_address)\n        test_nonrbf_bumpfee_fails(peer_node, dest_address)\n        test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)\n        test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)\n        test_small_output_fails(rbf_node, dest_address)\n        test_dust_to_fee(rbf_node, dest_address)\n        test_settxfee(rbf_node, dest_address)\n        test_rebumping(rbf_node, dest_address)\n        test_rebumping_not_replaceable(rbf_node, dest_address)\n        test_unconfirmed_not_spendable(rbf_node, rbf_node_address)\n        test_bumpfee_metadata(rbf_node, dest_address)\n        test_locked_wallet_fails(rbf_node, dest_address)\n        self.log.info(\"Success\")\n\n\ndef test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):\n    rbfid = spend_one_input(rbf_node, dest_address)\n    rbftx = rbf_node.gettransaction(rbfid)\n    sync_mempools((rbf_node, peer_node))\n    assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()\n    bumped_tx = rbf_node.bumpfee(rbfid)\n    assert_equal(bumped_tx[\"errors\"], [])\n    assert bumped_tx[\"fee\"] - abs(rbftx[\"fee\"]) > 0\n    # check that bumped_tx propagates, original tx was evicted and has a wallet conflict\n    sync_mempools((rbf_node, peer_node))\n    assert bumped_tx[\"txid\"] in rbf_node.getrawmempool()\n    assert bumped_tx[\"txid\"] in peer_node.getrawmempool()\n    assert rbfid not in rbf_node.getrawmempool()\n    assert rbfid not in peer_node.getrawmempool()\n    oldwtx = rbf_node.gettransaction(rbfid)\n    assert len(oldwtx[\"walletconflicts\"]) > 0\n    # check wallet transaction replaces and replaced_by values\n    bumpedwtx = rbf_node.gettransaction(bumped_tx[\"txid\"])\n    assert_equal(oldwtx[\"replaced_by_txid\"], bumped_tx[\"txid\"])\n    assert_equal(bumpedwtx[\"replaces_txid\"], rbfid)\n\n\ndef test_segwit_bumpfee_succeeds(rbf_node, dest_address):\n    # Create a transaction with segwit output, then create an RBF transaction\n    # which spends it, and make sure bumpfee can be called on it.\n\n    segwit_in = next(u for u in rbf_node.listunspent() if u[\"amount\"] == Decimal(\"0.001\"))\n    segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress()\n    segwitid = send_to_witness(\n        use_p2wsh=False,\n        node=rbf_node,\n        utxo=segwit_in,\n        pubkey=segwit_out[\"pubkey\"],\n        encode_p2sh=False,\n        amount=Decimal(\"0.0009\"),\n        sign=True)\n\n    rbfraw = rbf_node.createrawtransaction([{\n        'txid': segwitid,\n        'vout': 0,\n        \"sequence\": BIP125_SEQUENCE_NUMBER\n    }], {dest_address: Decimal(\"0.0005\"),\n         rbf_node.getrawchangeaddress(): Decimal(\"0.0003\")})\n    rbfsigned = rbf_node.signrawtransaction(rbfraw)\n    rbfid = rbf_node.sendrawtransaction(rbfsigned[\"hex\"])\n    assert rbfid in rbf_node.getrawmempool()\n\n    bumped_tx = rbf_node.bumpfee(rbfid)\n    assert bumped_tx[\"txid\"] in rbf_node.getrawmempool()\n    assert rbfid not in rbf_node.getrawmempool()\n\n\ndef test_nonrbf_bumpfee_fails(peer_node, dest_address):\n    # cannot replace a non RBF transaction (from node which did not enable RBF)\n    not_rbfid = peer_node.sendtoaddress(dest_address, Decimal(\"0.00090000\"))\n    assert_raises_rpc_error(-4, \"not BIP 125 replaceable\", peer_node.bumpfee, not_rbfid)\n\n\ndef test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):\n    # cannot bump fee unless the tx has only inputs that we own.\n    # here, the rbftx has a peer_node coin and then adds a rbf_node input\n    # Note that this test depends upon the RPC code checking input ownership prior to change outputs\n    # (since it can't use fundrawtransaction, it lacks a proper change output)\n    utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)]\n    inputs = [{\n        \"txid\": utxo[\"txid\"],\n        \"vout\": utxo[\"vout\"],\n        \"address\": utxo[\"address\"],\n        \"sequence\": BIP125_SEQUENCE_NUMBER\n    } for utxo in utxos]\n    output_val = sum(utxo[\"amount\"] for utxo in utxos) - Decimal(\"0.001\")\n    rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val})\n    signedtx = rbf_node.signrawtransaction(rawtx)\n    signedtx = peer_node.signrawtransaction(signedtx[\"hex\"])\n    rbfid = rbf_node.sendrawtransaction(signedtx[\"hex\"])\n    assert_raises_rpc_error(-4, \"Transaction contains inputs that don't belong to this wallet\",\n                            rbf_node.bumpfee, rbfid)\n\n\ndef test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):\n    # cannot bump fee if the transaction has a descendant\n    # parent is send-to-self, so we don't have to check which output is change when creating the child tx\n    parent_id = spend_one_input(rbf_node, rbf_node_address)\n    tx = rbf_node.createrawtransaction([{\"txid\": parent_id, \"vout\": 0}], {dest_address: 0.00020000})\n    tx = rbf_node.signrawtransaction(tx)\n    rbf_node.sendrawtransaction(tx[\"hex\"])\n    assert_raises_rpc_error(-8, \"Transaction has descendants in the wallet\", rbf_node.bumpfee, parent_id)\n\n\ndef test_small_output_fails(rbf_node, dest_address):\n    # cannot bump fee with a too-small output\n    rbfid = spend_one_input(rbf_node, dest_address)\n    rbf_node.bumpfee(rbfid, {\"totalFee\": 50000})\n\n    rbfid = spend_one_input(rbf_node, dest_address)\n    assert_raises_rpc_error(-4, \"Change output is too small\", rbf_node.bumpfee, rbfid, {\"totalFee\": 50001})\n\n\ndef test_dust_to_fee(rbf_node, dest_address):\n    # check that if output is reduced to dust, it will be converted to fee\n    # the bumped tx sets fee=49,900, but it converts to 50,000\n    rbfid = spend_one_input(rbf_node, dest_address)\n    fulltx = rbf_node.getrawtransaction(rbfid, 1)\n    # (32-byte p2sh-pwpkh output size + 148 p2pkh spend estimate) * 10k(discard_rate) / 1000 = 1800\n    # P2SH outputs are slightly \"over-discarding\" due to the IsDust calculation assuming it will\n    # be spent as a P2PKH.\n    bumped_tx = rbf_node.bumpfee(rbfid, {\"totalFee\": 50000 - 1800})\n    full_bumped_tx = rbf_node.getrawtransaction(bumped_tx[\"txid\"], 1)\n    assert_equal(bumped_tx[\"fee\"], Decimal(\"0.00050000\"))\n    assert_equal(len(fulltx[\"vout\"]), 2)\n    assert_equal(len(full_bumped_tx[\"vout\"]), 1)  # change output is eliminated\n\n\ndef test_settxfee(rbf_node, dest_address):\n    assert_raises_rpc_error(-8, \"txfee cannot be less than min relay tx fee\", rbf_node.settxfee, Decimal('0.000005'))\n    assert_raises_rpc_error(-8, \"txfee cannot be less than wallet min fee\", rbf_node.settxfee, Decimal('0.000015'))\n    # check that bumpfee reacts correctly to the use of settxfee (paytxfee)\n    rbfid = spend_one_input(rbf_node, dest_address)\n    requested_feerate = Decimal(\"0.00025000\")\n    rbf_node.settxfee(requested_feerate)\n    bumped_tx = rbf_node.bumpfee(rbfid)\n    actual_feerate = bumped_tx[\"fee\"] * 1000 / rbf_node.getrawtransaction(bumped_tx[\"txid\"], True)[\"vsize\"]\n    # Assert that the difference between the requested feerate and the actual\n    # feerate of the bumped transaction is small.\n    assert_greater_than(Decimal(\"0.00001000\"), abs(requested_feerate - actual_feerate))\n    rbf_node.settxfee(Decimal(\"0.00000000\"))  # unset paytxfee\n\n\ndef test_rebumping(rbf_node, dest_address):\n    # check that re-bumping the original tx fails, but bumping the bumper succeeds\n    rbfid = spend_one_input(rbf_node, dest_address)\n    bumped = rbf_node.bumpfee(rbfid, {\"totalFee\": 2000})\n    assert_raises_rpc_error(-4, \"already bumped\", rbf_node.bumpfee, rbfid, {\"totalFee\": 3000})\n    rbf_node.bumpfee(bumped[\"txid\"], {\"totalFee\": 3000})\n\n\ndef test_rebumping_not_replaceable(rbf_node, dest_address):\n    # check that re-bumping a non-replaceable bump tx fails\n    rbfid = spend_one_input(rbf_node, dest_address)\n    bumped = rbf_node.bumpfee(rbfid, {\"totalFee\": 10000, \"replaceable\": False})\n    assert_raises_rpc_error(-4, \"Transaction is not BIP 125 replaceable\", rbf_node.bumpfee, bumped[\"txid\"],\n                            {\"totalFee\": 20000})\n\n\ndef test_unconfirmed_not_spendable(rbf_node, rbf_node_address):\n    # check that unconfirmed outputs from bumped transactions are not spendable\n    rbfid = spend_one_input(rbf_node, rbf_node_address)\n    rbftx = rbf_node.gettransaction(rbfid)[\"hex\"]\n    assert rbfid in rbf_node.getrawmempool()\n    bumpid = rbf_node.bumpfee(rbfid)[\"txid\"]\n    assert bumpid in rbf_node.getrawmempool()\n    assert rbfid not in rbf_node.getrawmempool()\n\n    # check that outputs from the bump transaction are not spendable\n    # due to the replaces_txid check in CWallet::AvailableCoins\n    assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t[\"txid\"] == bumpid], [])\n\n    # submit a block with the rbf tx to clear the bump tx out of the mempool,\n    # then invalidate the block so the rbf tx will be put back in the mempool.\n    # This makes it possible to check whether the rbf tx outputs are\n    # spendable before the rbf tx is confirmed.\n    block = submit_block_with_tx(rbf_node, rbftx)\n    # Can not abandon conflicted tx\n    assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid))\n    rbf_node.invalidateblock(block.hash)\n    # Call abandon to make sure the wallet doesn't attempt to resubmit\n    # the bump tx and hope the wallet does not rebroadcast before we call.\n    rbf_node.abandontransaction(bumpid)\n    assert bumpid not in rbf_node.getrawmempool()\n    assert rbfid in rbf_node.getrawmempool()\n\n    # check that outputs from the rbf tx are not spendable before the\n    # transaction is confirmed, due to the replaced_by_txid check in\n    # CWallet::AvailableCoins\n    assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t[\"txid\"] == rbfid], [])\n\n    # check that the main output from the rbf tx is spendable after confirmed\n    rbf_node.generate(1)\n    assert_equal(\n        sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False)\n            if t[\"txid\"] == rbfid and t[\"address\"] == rbf_node_address and t[\"spendable\"]), 1)\n\n\ndef test_bumpfee_metadata(rbf_node, dest_address):\n    rbfid = rbf_node.sendtoaddress(dest_address, Decimal(\"0.00100000\"), \"comment value\", \"to value\")\n    bumped_tx = rbf_node.bumpfee(rbfid)\n    bumped_wtx = rbf_node.gettransaction(bumped_tx[\"txid\"])\n    assert_equal(bumped_wtx[\"comment\"], \"comment value\")\n    assert_equal(bumped_wtx[\"to\"], \"to value\")\n\n\ndef test_locked_wallet_fails(rbf_node, dest_address):\n    rbfid = spend_one_input(rbf_node, dest_address)\n    rbf_node.walletlock()\n    assert_raises_rpc_error(-13, \"Please enter the wallet passphrase with walletpassphrase first.\",\n                            rbf_node.bumpfee, rbfid)\n\n\ndef spend_one_input(node, dest_address):\n    tx_input = dict(\n        sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u[\"amount\"] == Decimal(\"0.00100000\")))\n    rawtx = node.createrawtransaction(\n        [tx_input], {dest_address: Decimal(\"0.00050000\"),\n                     node.getrawchangeaddress(): Decimal(\"0.00049000\")})\n    signedtx = node.signrawtransaction(rawtx)\n    txid = node.sendrawtransaction(signedtx[\"hex\"])\n    return txid\n\n\ndef submit_block_with_tx(node, tx):\n    ctx = CTransaction()\n    ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))\n\n    tip = node.getbestblockhash()\n    height = node.getblockcount() + 1\n    block_time = node.getblockheader(tip)[\"mediantime\"] + 1\n    block = create_block(int(tip, 16), create_coinbase(height), block_time)\n    block.vtx.append(ctx)\n    block.rehash()\n    block.hashMerkleRoot = block.calc_merkle_root()\n    add_witness_commitment(block)\n    block.solve()\n    node.submitblock(block.serialize(True).hex())\n    return block\n\n\nif __name__ == \"__main__\":\n    BumpFeeTest().main()\n"
  },
  {
    "path": "test/functional/wallet_coinbase_category.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test coinbase transactions return the correct categories.\n\nTests listtransactions, listsinceblock, and gettransaction.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_array_result\n)\n\nclass CoinbaseCategoryTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def assert_category(self, category, address, txid, skip):\n        assert_array_result(self.nodes[0].listtransactions(skip=skip),\n                            {\"address\": address},\n                            {\"category\": category})\n        assert_array_result(self.nodes[0].listsinceblock()[\"transactions\"],\n                            {\"address\": address},\n                            {\"category\": category})\n        assert_array_result(self.nodes[0].gettransaction(txid)[\"details\"],\n                            {\"address\": address},\n                            {\"category\": category})\n\n    def run_test(self):\n        # Generate one block to an address\n        address = self.nodes[0].getnewaddress()\n        self.nodes[0].generatetoaddress(1, address)\n        hash = self.nodes[0].getbestblockhash()\n        txid = self.nodes[0].getblock(hash)[\"tx\"][0]\n\n        # Coinbase transaction is immature after 1 confirmation\n        self.assert_category(\"immature\", address, txid, 0)\n\n        # Mine another 99 blocks on top\n        self.nodes[0].generate(99)\n        # Coinbase transaction is still immature after 100 confirmations\n        self.assert_category(\"immature\", address, txid, 99)\n\n        # Mine one more block\n        self.nodes[0].generate(1)\n        # Coinbase transaction is now matured, so category is \"generate\"\n        self.assert_category(\"generate\", address, txid, 100)\n\n        # Orphan block that paid to address\n        self.nodes[0].invalidateblock(hash)\n        # Coinbase transaction is now orphaned\n        self.assert_category(\"orphan\", address, txid, 100)\n\nif __name__ == '__main__':\n    CoinbaseCategoryTest().main()\n"
  },
  {
    "path": "test/functional/wallet_create_tx.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n)\nfrom test_framework.blocktools import (\n    TIME_GENESIS_BLOCK,\n)\n\n\nclass CreateTxWalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.log.info('Create some old blocks')\n        self.nodes[0].setmocktime(TIME_GENESIS_BLOCK)\n        self.nodes[0].generate(200)\n        self.nodes[0].setmocktime(0)\n\n        self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')\n        assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])\n        assert_equal(tx['locktime'], 0)\n\n        self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block')\n        self.nodes[0].generate(1)\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])\n        assert 0 < tx['locktime'] <= 201\n\n\nif __name__ == '__main__':\n    CreateTxWalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_createwallet.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test createwallet arguments.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\nclass CreateWalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = False\n        self.num_nodes = 1\n        self.supports_cli = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        node = self.nodes[0]\n        node.generate(1) # Leave IBD for sethdseed\n\n        self.nodes[0].createwallet(wallet_name='w0')\n        w0 = node.get_wallet_rpc('w0')\n        address1 = w0.getnewaddress()\n\n        self.log.info(\"Test disableprivatekeys creation.\")\n        self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True)\n        w1 = node.get_wallet_rpc('w1')\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w1.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w1.getrawchangeaddress)\n        w1.importpubkey(w0.getaddressinfo(address1)['pubkey'])\n\n        self.log.info('Test that private keys cannot be imported')\n        addr = w0.getnewaddress('', 'legacy')\n        privkey = w0.dumpprivkey(addr)\n        assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey)\n        result = w1.importmulti([{'scriptPubKey': {'address': addr}, 'timestamp': 'now', 'keys': [privkey]}])\n        assert not result[0]['success']\n        assert 'warning' not in result[0]\n        assert_equal(result[0]['error']['code'], -4)\n        assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled')\n\n        self.log.info(\"Test blank creation with private keys disabled.\")\n        self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True)\n        w2 = node.get_wallet_rpc('w2')\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w2.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w2.getrawchangeaddress)\n        w2.importpubkey(w0.getaddressinfo(address1)['pubkey'])\n\n        self.log.info(\"Test blank creation with private keys enabled.\")\n        self.nodes[0].createwallet(wallet_name='w3', disable_private_keys=False, blank=True)\n        w3 = node.get_wallet_rpc('w3')\n        assert_equal(w3.getwalletinfo()['keypoolsize'], 0)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w3.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w3.getrawchangeaddress)\n        # Import private key\n        w3.importprivkey(w0.dumpprivkey(address1))\n        # Imported private keys are currently ignored by the keypool\n        assert_equal(w3.getwalletinfo()['keypoolsize'], 0)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w3.getnewaddress)\n        # Set the seed\n        w3.sethdseed()\n        assert_equal(w3.getwalletinfo()['keypoolsize'], 1)\n        w3.getnewaddress()\n        w3.getrawchangeaddress()\n\n        self.log.info(\"Test blank creation with privkeys enabled and then encryption\")\n        self.nodes[0].createwallet(wallet_name='w4', disable_private_keys=False, blank=True)\n        w4 = node.get_wallet_rpc('w4')\n        assert_equal(w4.getwalletinfo()['keypoolsize'], 0)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w4.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w4.getrawchangeaddress)\n        # Encrypt the wallet. Nothing should change about the keypool\n        w4.encryptwallet('pass')\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w4.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w4.getrawchangeaddress)\n        # Now set a seed and it should work. Wallet should also be encrypted\n        w4.walletpassphrase('pass', 2)\n        w4.sethdseed()\n        w4.getnewaddress()\n        w4.getrawchangeaddress()\n\n        self.log.info(\"Test blank creation with privkeys disabled and then encryption\")\n        self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True)\n        w5 = node.get_wallet_rpc('w5')\n        assert_equal(w5.getwalletinfo()['keypoolsize'], 0)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w5.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w5.getrawchangeaddress)\n        # Encrypt the wallet\n        w5.encryptwallet('pass')\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w5.getnewaddress)\n        assert_raises_rpc_error(-4, \"Error: This wallet has no available keys\", w5.getrawchangeaddress)\n\nif __name__ == '__main__':\n    CreateWalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_disable.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test a node with the -disablewallet option.\n\n- Test that validateaddress RPC works when running with -disablewallet\n- Test that it is not possible to mine to an invalid address.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_raises_rpc_error\n\nclass DisableWalletTest (MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n        self.extra_args = [[\"-disablewallet\"]]\n\n    def run_test (self):\n        # Make sure wallet is really disabled\n        assert_raises_rpc_error(-32601, 'Method not found', self.nodes[0].getwalletinfo)\n        x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')\n        assert x['isvalid'] == False\n        x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')\n        assert x['isvalid'] == True\n\n        # Checking mining to an address without a wallet. Generating to a valid address should succeed\n        # but generating to an invalid address will fail.\n        self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')\n        assert_raises_rpc_error(-5, \"Invalid address\", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')\n\nif __name__ == '__main__':\n    DisableWalletTest ().main ()\n"
  },
  {
    "path": "test/functional/wallet_dump.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the dumpwallet RPC.\"\"\"\nimport os\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\n\ndef read_dump(file_name, addrs, script_addrs, hd_master_addr_old):\n    \"\"\"\n    Read the given dump, count the addrs that match, count change and reserve.\n    Also check that the old hd_master is inactive\n    \"\"\"\n    with open(file_name, encoding='utf8') as inputfile:\n        found_legacy_addr = 0\n        found_p2sh_segwit_addr = 0\n        found_bech32_addr = 0\n        found_script_addr = 0\n        found_addr_chg = 0\n        found_addr_rsv = 0\n        hd_master_addr_ret = None\n        for line in inputfile:\n            # only read non comment lines\n            if line[0] != \"#\" and len(line) > 10:\n                # split out some data\n                key_date_label, comment = line.split(\"#\")\n                key_date_label = key_date_label.split(\" \")\n                # key = key_date_label[0]\n                date = key_date_label[1]\n                keytype = key_date_label[2]\n\n                imported_key = date == '1970-01-01T00:00:01Z'\n                if imported_key:\n                    # Imported keys have multiple addresses, no label (keypath) and timestamp\n                    # Skip them\n                    continue\n\n                addr_keypath = comment.split(\" addr=\")[1]\n                addr = addr_keypath.split(\" \")[0]\n                keypath = None\n                if keytype == \"inactivehdseed=1\":\n                    # ensure the old master is still available\n                    assert hd_master_addr_old == addr\n                elif keytype == \"hdseed=1\":\n                    # ensure we have generated a new hd master key\n                    assert hd_master_addr_old != addr\n                    hd_master_addr_ret = addr\n                elif keytype == \"script=1\":\n                    # scripts don't have keypaths\n                    keypath = None\n                else:\n                    keypath = addr_keypath.rstrip().split(\"hdkeypath=\")[1]\n\n                # count key types\n                for addrObj in addrs:\n                    if addrObj['address'] == addr.split(\",\")[0] and addrObj['hdkeypath'] == keypath and keytype == \"label=\":\n                        if addr.startswith('m') or addr.startswith('n'):\n                            # P2PKH address\n                            found_legacy_addr += 1\n                        elif addr.startswith('2'):\n                            # P2SH-segwit address\n                            found_p2sh_segwit_addr += 1\n                        elif addr.startswith('bcrt1'):\n                            found_bech32_addr += 1\n                        break\n                    elif keytype == \"change=1\":\n                        found_addr_chg += 1\n                        break\n                    elif keytype == \"reserve=1\":\n                        found_addr_rsv += 1\n                        break\n\n                # count scripts\n                for script_addr in script_addrs:\n                    if script_addr == addr.rstrip() and keytype == \"script=1\":\n                        found_script_addr += 1\n                        break\n\n        return found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret\n\n\nclass WalletDumpTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.extra_args = [[\"-keypool=90\", \"-addresstype=legacy\"]]\n        self.rpc_timeout = 120\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.add_nodes(self.num_nodes, extra_args=self.extra_args)\n        self.start_nodes()\n\n    def run_test(self):\n        wallet_unenc_dump = os.path.join(self.nodes[0].datadir, \"wallet.unencrypted.dump\")\n        wallet_enc_dump = os.path.join(self.nodes[0].datadir, \"wallet.encrypted.dump\")\n\n        # generate 30 addresses to compare against the dump\n        # - 10 legacy P2PKH\n        # - 10 P2SH-segwit\n        # - 10 bech32\n        test_addr_count = 10\n        addrs = []\n        for address_type in ['legacy', 'p2sh-segwit', 'bech32']:\n            for i in range(0, test_addr_count):\n                addr = self.nodes[0].getnewaddress(address_type=address_type)\n                vaddr = self.nodes[0].getaddressinfo(addr)  # required to get hd keypath\n                addrs.append(vaddr)\n\n        # Test scripts dump by adding a 1-of-1 multisig address\n        multisig_addr = self.nodes[0].addmultisigaddress(1, [addrs[1][\"address\"]])[\"address\"]\n\n        # Refill the keypool. getnewaddress() refills the keypool *before* taking a key from\n        # the keypool, so the final call to getnewaddress leaves the keypool with one key below\n        # its capacity\n        self.nodes[0].keypoolrefill()\n\n        # dump unencrypted wallet\n        result = self.nodes[0].dumpwallet(wallet_unenc_dump)\n        assert_equal(result['filename'], wallet_unenc_dump)\n\n        found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \\\n            read_dump(wallet_unenc_dump, addrs, [multisig_addr], None)\n        assert_equal(found_legacy_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_p2sh_segwit_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_bech32_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_script_addr, 1)  # all scripts must be in the dump\n        assert_equal(found_addr_chg, 0)  # 0 blocks where mined\n        assert_equal(found_addr_rsv, 90 * 2)  # 90 keys plus 100% internal keys\n\n        # encrypt wallet, restart, unlock and dump\n        self.nodes[0].encryptwallet('test')\n        self.nodes[0].walletpassphrase('test', 10)\n        # Should be a no-op:\n        self.nodes[0].keypoolrefill()\n        self.nodes[0].dumpwallet(wallet_enc_dump)\n\n        found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \\\n            read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc)\n        assert_equal(found_legacy_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_p2sh_segwit_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_bech32_addr, test_addr_count)  # all keys must be in the dump\n        assert_equal(found_script_addr, 1)\n        assert_equal(found_addr_chg, 90 * 2)  # old reserve keys are marked as change now\n        assert_equal(found_addr_rsv, 90 * 2)\n\n        # Overwriting should fail\n        assert_raises_rpc_error(-8, \"already exists\", lambda: self.nodes[0].dumpwallet(wallet_enc_dump))\n\n        # Restart node with new wallet, and test importwallet\n        self.stop_node(0)\n        self.start_node(0, ['-wallet=w2'])\n\n        # Make sure the address is not IsMine before import\n        result = self.nodes[0].getaddressinfo(multisig_addr)\n        assert not result['ismine']\n\n        self.nodes[0].importwallet(wallet_unenc_dump)\n\n        # Now check IsMine is true\n        result = self.nodes[0].getaddressinfo(multisig_addr)\n        assert result['ismine']\n\nif __name__ == '__main__':\n    WalletDumpTest().main()\n"
  },
  {
    "path": "test/functional/wallet_encryption.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test Wallet encryption\"\"\"\n\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    assert_greater_than,\n    assert_greater_than_or_equal,\n)\n\nclass WalletEncryptionTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        passphrase = \"WalletPassphrase\"\n        passphrase2 = \"SecondWalletPassphrase\"\n\n        # Make sure the wallet isn't encrypted first\n        address = self.nodes[0].getnewaddress()\n        privkey = self.nodes[0].dumpprivkey(address)\n        assert_equal(privkey[:1], \"U\")\n        assert_equal(len(privkey), 52)\n        assert_raises_rpc_error(-15, \"Error: running with an unencrypted wallet, but walletpassphrase was called\", self.nodes[0].walletpassphrase, 'ff', 1)\n        assert_raises_rpc_error(-15, \"Error: running with an unencrypted wallet, but walletpassphrasechange was called.\", self.nodes[0].walletpassphrasechange, 'ff', 'ff')\n\n        # Encrypt the wallet\n        ###assert_raises_rpc_error(-8, \"passphrase can not be empty\", self.nodes[0].encryptwallet, '')\n        self.nodes[0].encryptwallet(passphrase)\n\n        #wallet will have stopped from the encryption so start it again\n        time.sleep(5)\n        self.start_node(0)\n\n        # wallet needs to be unlocked for a while to do some post encryption bookkeeping\n        self.nodes[0].walletpassphrase(passphrase, 2)\n        time.sleep(2)\n\n        # Test that the wallet is encrypted\n        assert_raises_rpc_error(-13, \"Please enter the wallet passphrase with walletpassphrase first\", self.nodes[0].dumpprivkey, address, \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\")\n        assert_raises_rpc_error(-15, \"Error: running with an encrypted wallet, but encryptwallet was called.\", self.nodes[0].encryptwallet, 'ff')\n        ###assert_raises_rpc_error(-8, \"passphrase can not be empty\", self.nodes[0].walletpassphrase, '', 1)\n        ###assert_raises_rpc_error(-8, \"passphrase can not be empty\", self.nodes[0].walletpassphrasechange, '', 'ff')\n\n        # Check that walletpassphrase works\n        self.nodes[0].walletpassphrase(passphrase, 2)\n        assert_equal(privkey, self.nodes[0].dumpprivkey(address))\n\n        # Check that the timeout is right\n        time.sleep(2)\n        assert_raises_rpc_error(-13, \"Please enter the wallet passphrase with walletpassphrase first\", self.nodes[0].dumpprivkey, address, \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\")\n\n        # Test wrong passphrase\n        assert_raises_rpc_error(-14, \"wallet passphrase entered was incorrect\", self.nodes[0].walletpassphrase, passphrase + \"wrong\", 10)\n\n        # Test walletlock\n        self.nodes[0].walletpassphrase(passphrase, 84600)\n        assert_equal(privkey, self.nodes[0].dumpprivkey(address, \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\"))\n        self.nodes[0].walletlock()\n        assert_raises_rpc_error(-13, \"Please enter the wallet passphrase with walletpassphrase first\", self.nodes[0].dumpprivkey, address, \"I_UNDERSTAND_AND_ACCEPT_THE_RISK_OF_DUMPING_AN_HD_PRIVKEY\")\n\n        # Test passphrase changes\n        self.nodes[0].walletpassphrasechange(passphrase, passphrase2)\n        assert_raises_rpc_error(-14, \"wallet passphrase entered was incorrect\", self.nodes[0].walletpassphrase, passphrase, 10)\n        self.nodes[0].walletpassphrase(passphrase2, 10)\n        assert_equal(privkey, self.nodes[0].dumpprivkey(address))\n        self.nodes[0].walletlock()\n\n        # Test timeout bounds\n        #assert_raises_rpc_error(-8, \"Timeout cannot be negative.\", self.nodes[0].walletpassphrase, passphrase2, -10)\n        # Check the timeout\n        # Check a time less than the limit\n        MAX_VALUE = 100000000\n        expected_time = int(time.time()) + MAX_VALUE - 600\n        self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)\n        actual_time = self.nodes[0].getwalletinfo()['unlocked_until']\n        assert_greater_than_or_equal(actual_time, expected_time)\n        assert_greater_than(expected_time + 5, actual_time) # 5 second buffer\n        # Check a time greater than the limit\n        ###expected_time = int(time.time()) + MAX_VALUE - 1\n        ###self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)\n        ###actual_time = self.nodes[0].getwalletinfo()['unlocked_until']\n        ###assert_greater_than_or_equal(actual_time, expected_time)\n        ###assert_greater_than(expected_time + 5, actual_time) # 5 second buffer\n\nif __name__ == '__main__':\n    WalletEncryptionTest().main()\n"
  },
  {
    "path": "test/functional/wallet_fallbackfee.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test wallet replace-by-fee capabilities in conjunction with the fallbackfee.\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_raises_rpc_error\n\nclass WalletRBFTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[0].generate(101)\n\n        # sending a transaction without fee estimations must be possible by default on regtest\n        self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n\n        # test sending a tx with disabled fallback fee (must fail)\n        self.restart_node(0, extra_args=[\"-fallbackfee=0\"])\n        assert_raises_rpc_error(-4, \"Fee estimation failed\", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))\n        assert_raises_rpc_error(-4, \"Fee estimation failed\", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))\n        assert_raises_rpc_error(-6, \"Fee estimation failed\", lambda: self.nodes[0].sendmany(\"\", {self.nodes[0].getnewaddress(): 1}))\n\nif __name__ == '__main__':\n    WalletRBFTest().main()\n"
  },
  {
    "path": "test/functional/wallet_groups.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test wallet group functionality.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.messages import CTransaction, FromHex, ToHex\nfrom test_framework.util import (\n    assert_equal,\n)\n\ndef assert_approx(v, vexp, vspan=0.00001):\n    if v < vexp - vspan:\n        raise AssertionError(\"%s < [%s..%s]\" % (str(v), str(vexp - vspan), str(vexp + vspan)))\n    if v > vexp + vspan:\n        raise AssertionError(\"%s > [%s..%s]\" % (str(v), str(vexp - vspan), str(vexp + vspan)))\n\nclass WalletGroupTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 3\n        self.extra_args = [[], [], ['-avoidpartialspends']]\n        self.rpc_timeout = 120\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Mine some coins\n        self.nodes[0].generate(110)\n\n        # Get some addresses from the two nodes\n        addr1 = [self.nodes[1].getnewaddress() for i in range(3)]\n        addr2 = [self.nodes[2].getnewaddress() for i in range(3)]\n        addrs = addr1 + addr2\n\n        # Send 1 + 0.5 coin to each address\n        [self.nodes[0].sendtoaddress(addr, 1.0) for addr in addrs]\n        [self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        # For each node, send 0.2 coins back to 0;\n        # - node[1] should pick one 0.5 UTXO and leave the rest\n        # - node[2] should pick one (1.0 + 0.5) UTXO group corresponding to a\n        #   given address, and leave the rest\n        txid1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)\n        tx1 = self.nodes[1].getrawtransaction(txid1, True)\n        # txid1 should have 1 input and 2 outputs\n        assert_equal(1, len(tx1[\"vin\"]))\n        assert_equal(2, len(tx1[\"vout\"]))\n        # one output should be 0.2, the other should be ~0.3\n        v = [vout[\"value\"] for vout in tx1[\"vout\"]]\n        v.sort()\n        assert_approx(v[0], 0.2)\n        assert_approx(v[1], 0.3, 0.0001)\n\n        txid2 = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)\n        tx2 = self.nodes[2].getrawtransaction(txid2, True)\n        # txid2 should have 2 inputs and 2 outputs\n        assert_equal(2, len(tx2[\"vin\"]))\n        assert_equal(2, len(tx2[\"vout\"]))\n        # one output should be 0.2, the other should be ~1.3\n        v = [vout[\"value\"] for vout in tx2[\"vout\"]]\n        v.sort()\n        assert_approx(v[0], 0.2)\n        assert_approx(v[1], 1.3, 0.0001)\n\n        # Empty out node2's wallet\n        self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)\n        self.sync_all()\n        self.nodes[0].generate(1)\n\n        # Fill node2's wallet with 10000 outputs corresponding to the same\n        # scriptPubKey\n        for i in range(5):\n            raw_tx = self.nodes[0].createrawtransaction([{\"txid\":\"0\"*64, \"vout\":0}], [{addr2[0]: 0.05}])\n            tx = FromHex(CTransaction(), raw_tx)\n            tx.vin = []\n            tx.vout = [tx.vout[0]] * 2000\n            funded_tx = self.nodes[0].fundrawtransaction(ToHex(tx))\n            signed_tx = self.nodes[0].signrawtransaction(funded_tx['hex'])\n            self.nodes[0].sendrawtransaction(signed_tx['hex'])\n            self.nodes[0].generate(1)\n\n        self.sync_all()\n\n        # Check that we can create a transaction that only requires ~100 of our\n        # utxos, without pulling in all outputs and creating a transaction that\n        # is way too big.\n        assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5)\n\nif __name__ == '__main__':\n    WalletGroupTest().main ()\n"
  },
  {
    "path": "test/functional/wallet_hd.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2016-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test Hierarchical Deterministic wallet function.\"\"\"\n\nimport os\nimport shutil\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes_bi,\n    assert_raises_rpc_error\n)\n\n\nclass WalletHDTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.extra_args = [[], ['-keypool=0']]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Make sure we use hd, keep masterkeyid\n        masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']\n        assert_equal(len(masterkeyid), 40)\n\n        # create an internal key\n        change_addr = self.nodes[1].getrawchangeaddress()\n        change_addrV= self.nodes[1].getaddressinfo(change_addr)\n        assert_equal(change_addrV[\"hdkeypath\"], \"m/0'/1'/0'\") #first internal child key\n\n        # Import a non-HD private key in the HD wallet\n        non_hd_add = self.nodes[0].getnewaddress()\n        self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))\n\n        # This should be enough to keep the master key and the non-HD key\n        self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, \"hd.bak\"))\n        #self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, \"hd.dump\"))\n\n        # Derive some HD addresses and remember the last\n        # Also send funds to each add\n        self.nodes[0].generate(101)\n        hd_add = None\n        NUM_HD_ADDS = 10\n        for i in range(NUM_HD_ADDS):\n            hd_add = self.nodes[1].getnewaddress()\n            hd_info = self.nodes[1].getaddressinfo(hd_add)\n            assert_equal(hd_info[\"hdkeypath\"], \"m/0'/0'/\"+str(i)+\"'\")\n            assert_equal(hd_info[\"hdseedid\"], masterkeyid)\n            self.nodes[0].sendtoaddress(hd_add, 1)\n            self.nodes[0].generate(1)\n        self.nodes[0].sendtoaddress(non_hd_add, 1)\n        self.nodes[0].generate(1)\n\n        # create an internal key (again)\n        change_addr = self.nodes[1].getrawchangeaddress()\n        change_addrV= self.nodes[1].getaddressinfo(change_addr)\n        assert_equal(change_addrV[\"hdkeypath\"], \"m/0'/1'/1'\") #second internal child key\n\n        self.sync_all()\n        assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)\n\n        self.log.info(\"Restore backup ...\")\n        self.stop_node(1)\n        # we need to delete the complete regtest directory\n        # otherwise node1 would auto-recover all funds in flag the keypool keys as used\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"blocks\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"chainstate\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"witstate\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"autocheckpoints\"))\n        shutil.copyfile(os.path.join(self.nodes[1].datadir, \"hd.bak\"), os.path.join(self.nodes[1].datadir, \"regtest\", \"wallets\", \"wallet.dat\"))\n        self.start_node(1)\n\n        # Assert that derivation is deterministic\n        hd_add_2 = None\n        for i in range(NUM_HD_ADDS):\n            hd_add_2 = self.nodes[1].getnewaddress()\n            hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2)\n            assert_equal(hd_info_2[\"hdkeypath\"], \"m/0'/0'/\"+str(i)+\"'\")\n            assert_equal(hd_info_2[\"hdseedid\"], masterkeyid)\n        assert_equal(hd_add, hd_add_2)\n        connect_nodes_bi(self.nodes, 0, 1)\n        self.sync_all()\n\n        # Needs rescan\n        self.stop_node(1)\n        self.start_node(1, extra_args=self.extra_args[1] + ['-rescan'])\n        assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)\n\n        # Try a RPC based rescan\n        self.stop_node(1)\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"blocks\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"chainstate\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"witstate\"))\n        shutil.rmtree(os.path.join(self.nodes[1].datadir, \"regtest\", \"autocheckpoints\"))\n        shutil.copyfile(os.path.join(self.nodes[1].datadir, \"hd.bak\"), os.path.join(self.nodes[1].datadir, \"regtest\", \"wallets\", \"wallet.dat\"))\n        self.start_node(1, extra_args=self.extra_args[1])\n        connect_nodes_bi(self.nodes, 0, 1)\n        self.sync_all()\n        # Wallet automatically scans blocks older than key on startup\n        assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)\n        out = self.nodes[1].rescanblockchain(0, 1)\n        assert_equal(out['start_height'], 0)\n        assert_equal(out['stop_height'], 1)\n        out = self.nodes[1].rescanblockchain()\n        assert_equal(out['start_height'], 0)\n        assert_equal(out['stop_height'], self.nodes[1].getblockcount())\n        assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)\n\n        # send a tx and make sure its using the internal chain for the changeoutput\n        txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']\n        keypath = \"\"\n        for out in outs:\n            if out['value'] != 1:\n                keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['addresses'][0])['hdkeypath']\n\n        assert_equal(keypath[0:7], \"m/0'/1'\")\n\n        # Generate a new HD seed on node 1 and make sure it is set\n        orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']\n        self.nodes[1].sethdseed()\n        new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']\n        assert orig_masterkeyid != new_masterkeyid\n        addr = self.nodes[1].getnewaddress()\n        assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\\'/0\\'/0\\'') # Make sure the new address is the first from the keypool\n        self.nodes[1].keypoolrefill(1) # Fill keypool with 1 key\n\n        # Set a new HD seed on node 1 without flushing the keypool\n        new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())\n        orig_masterkeyid = new_masterkeyid\n        self.nodes[1].sethdseed(False, new_seed)\n        new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']\n        assert orig_masterkeyid != new_masterkeyid\n        addr = self.nodes[1].getnewaddress()\n        assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo(addr)['hdseedid'])\n        assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/0\\'/0\\'/1\\'') # Make sure the new address continues previous keypool\n\n        # Check that the next address is from the new seed\n        self.nodes[1].keypoolrefill(1)\n        next_addr = self.nodes[1].getnewaddress()\n        assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo(next_addr)['hdseedid'])\n        assert_equal(self.nodes[1].getaddressinfo(next_addr)['hdkeypath'], 'm/0\\'/0\\'/0\\'') # Make sure the new address is not from previous keypool\n        assert next_addr != addr\n\n        # Sethdseed parameter validity\n        assert_raises_rpc_error(-1, 'sethdseed', self.nodes[0].sethdseed, False, new_seed, 0)\n        assert_raises_rpc_error(-5, \"Invalid private key\", self.nodes[1].sethdseed, False, \"not_wif\")\n        assert_raises_rpc_error(-1, \"JSON value is not a boolean as expected\", self.nodes[1].sethdseed, \"Not_bool\")\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[1].sethdseed, False, True)\n        assert_raises_rpc_error(-5, \"Already have this key\", self.nodes[1].sethdseed, False, new_seed)\n        assert_raises_rpc_error(-5, \"Already have this key\", self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()))\n\nif __name__ == '__main__':\n    WalletHDTest().main ()\n"
  },
  {
    "path": "test/functional/wallet_import_rescan.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test wallet import RPCs.\n\nTest rescan behavior of importaddress, importpubkey, importprivkey, and\nimportmulti RPCs with different types of keys and rescan options.\n\nIn the first part of the test, node 0 creates an address for each type of\nimport RPC call and sends BTC to it. Then other nodes import the addresses,\nand the test makes listtransactions and getbalance calls to confirm that the\nimporting node either did or did not execute rescans picking up the send\ntransactions.\n\nIn the second part of the test, node 0 sends more BTC to each address, and the\ntest makes more listtransactions and getbalance calls to confirm that the\nimporting nodes pick up the new transactions regardless of whether rescans\nhappened previously.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (assert_raises_rpc_error, connect_nodes, sync_blocks, assert_equal, set_node_times)\n\nimport collections\nimport enum\nimport itertools\n\nCall = enum.Enum(\"Call\", \"single multiaddress multiscript\")\nData = enum.Enum(\"Data\", \"address pub priv\")\nRescan = enum.Enum(\"Rescan\", \"no yes late_timestamp\")\n\n\nclass Variant(collections.namedtuple(\"Variant\", \"call data rescan prune\")):\n    \"\"\"Helper for importing one key and verifying scanned transactions.\"\"\"\n\n    def try_rpc(self, func, *args, **kwargs):\n        if self.expect_disabled:\n            assert_raises_rpc_error(-4, \"Rescan is disabled in pruned mode\", func, *args, **kwargs)\n        else:\n            return func(*args, **kwargs)\n\n    def do_import(self, timestamp):\n        \"\"\"Call one key import RPC.\"\"\"\n        rescan = self.rescan == Rescan.yes\n\n        if self.call == Call.single:\n            if self.data == Data.address:\n                response = self.try_rpc(self.node.importaddress, address=self.address[\"address\"], label=self.label, rescan=rescan)\n            elif self.data == Data.pub:\n                response = self.try_rpc(self.node.importpubkey, pubkey=self.address[\"pubkey\"], label=self.label, rescan=rescan)\n            elif self.data == Data.priv:\n                response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)\n            assert_equal(response, None)\n\n        elif self.call in (Call.multiaddress, Call.multiscript):\n            response = self.node.importmulti([{\n                \"scriptPubKey\": {\n                    \"address\": self.address[\"address\"]\n                } if self.call == Call.multiaddress else self.address[\"scriptPubKey\"],\n                \"timestamp\": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),\n                \"pubkeys\": [self.address[\"pubkey\"]] if self.data == Data.pub else [],\n                \"keys\": [self.key] if self.data == Data.priv else [],\n                \"label\": self.label,\n                \"watchonly\": self.data != Data.priv\n            }], {\"rescan\": self.rescan in (Rescan.yes, Rescan.late_timestamp)})\n            assert_equal(response, [{\"success\": True}])\n\n    def check(self, txid=None, amount=None, confirmations=None):\n        \"\"\"Verify that listtransactions/listreceivedbyaddress return expected values.\"\"\"\n\n        txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True)\n        assert_equal(len(txs), self.expected_txs)\n\n        addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])\n        if self.expected_txs:\n            assert_equal(len(addresses[0][\"txids\"]), self.expected_txs)\n\n        if txid is not None:\n            tx, = [tx for tx in txs if tx[\"txid\"] == txid]\n            assert_equal(tx[\"label\"], self.label)\n            assert_equal(tx[\"address\"], self.address[\"address\"])\n            assert_equal(tx[\"amount\"], amount)\n            assert_equal(tx[\"category\"], \"receive\")\n            assert_equal(tx[\"label\"], self.label)\n            assert_equal(tx[\"txid\"], txid)\n            assert_equal(tx[\"confirmations\"], confirmations)\n            assert_equal(\"trusted\" not in tx, True)\n\n            address, = [ad for ad in addresses if txid in ad[\"txids\"]]\n            assert_equal(address[\"address\"], self.address[\"address\"])\n            assert_equal(address[\"amount\"], self.expected_balance)\n            assert_equal(address[\"confirmations\"], confirmations)\n            # Verify the transaction is correctly marked watchonly depending on\n            # whether the transaction pays to an imported public key or\n            # imported private key. The test setup ensures that transaction\n            # inputs will not be from watchonly keys (important because\n            # involvesWatchonly will be true if either the transaction output\n            # or inputs are watchonly).\n            if self.data != Data.priv:\n                assert_equal(address[\"involvesWatchonly\"], True)\n            else:\n                assert_equal(\"involvesWatchonly\" not in address, True)\n\n\n# List of Variants for each way a key or address could be imported.\nIMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, Rescan, (False, True))]\n\n# List of nodes to import keys to. Half the nodes will have pruning disabled,\n# half will have it enabled. Different nodes will be used for imports that are\n# expected to cause rescans, and imports that are not expected to cause\n# rescans, in order to prevent rescans during later imports picking up\n# transactions associated with earlier imports. This makes it easier to keep\n# track of expected balances and transactions.\nImportNode = collections.namedtuple(\"ImportNode\", \"prune rescan\")\nIMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True), repeat=2)]\n\n# Rescans start at the earliest block up to 2 hours before the key timestamp.\nTIMESTAMP_WINDOW = 2 * 60 * 60\n\n\nclass ImportRescanTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2 + len(IMPORT_NODES)\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        extra_args = [[\"-addresstype=legacy\"] for _ in range(self.num_nodes)]\n        for i, import_node in enumerate(IMPORT_NODES, 2):\n            if import_node.prune:\n                extra_args[i] += [\"-prune=1\"]\n\n        self.add_nodes(self.num_nodes, extra_args=extra_args)\n\n        # Import keys with pruning disabled\n        self.start_nodes(extra_args=[[]] * self.num_nodes)\n        for n in self.nodes:\n            n.importprivkey(muntprivkey=n.get_deterministic_priv_key().key, label='coinbase')\n        self.stop_nodes()\n\n        self.start_nodes()\n        for i in range(1, self.num_nodes):\n            connect_nodes(self.nodes[i], 0)\n\n    def run_test(self):\n        # Create one transaction on node 0 with a unique amount for\n        # each possible type of wallet import RPC.\n        for i, variant in enumerate(IMPORT_VARIANTS):\n            variant.label = \"label {} {}\".format(i, variant)\n            variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))\n            variant.key = self.nodes[1].dumpprivkey(variant.address[\"address\"])\n            variant.initial_amount = 1 - (i + 1) / 64\n            variant.initial_txid = self.nodes[0].sendtoaddress(variant.address[\"address\"], variant.initial_amount)\n\n        # Generate a block containing the initial transactions, then another\n        # block further in the future (past the rescan window).\n        self.nodes[0].generate(1)\n        assert_equal(self.nodes[0].getrawmempool(), [])\n        timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())[\"time\"]\n        set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1)\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # For each variation of wallet key import, invoke the import RPC and\n        # check the results from getbalance and listtransactions.\n        for variant in IMPORT_VARIANTS:\n            variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single\n            expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled\n            variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]\n            variant.do_import(timestamp)\n            if expect_rescan:\n                variant.expected_balance = variant.initial_amount\n                variant.expected_txs = 1\n                variant.check(variant.initial_txid, variant.initial_amount, 2)\n            else:\n                variant.expected_balance = 0\n                variant.expected_txs = 0\n                variant.check()\n\n        # Create new transactions sending to each address.\n        for i, variant in enumerate(IMPORT_VARIANTS):\n            variant.sent_amount = 1 - (2 * i + 1) / 128\n            variant.sent_txid = self.nodes[0].sendtoaddress(variant.address[\"address\"], variant.sent_amount)\n\n        # Generate a block containing the new transactions.\n        self.nodes[0].generate(1)\n        assert_equal(self.nodes[0].getrawmempool(), [])\n        sync_blocks(self.nodes)\n\n        # Check the latest results from getbalance and listtransactions.\n        for variant in IMPORT_VARIANTS:\n            if not variant.expect_disabled:\n                variant.expected_balance += variant.sent_amount\n                variant.expected_txs += 1\n                variant.check(variant.sent_txid, variant.sent_amount, 1)\n            else:\n                variant.check()\n\nif __name__ == \"__main__\":\n    ImportRescanTest().main()\n"
  },
  {
    "path": "test/functional/wallet_import_with_label.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the behavior of RPC importprivkey on set and unset labels of\naddresses.\n\nIt tests different cases in which an address is imported with importaddress\nwith or without a label and then its private key is imported with importprivkey\nwith and without a label.\n\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.wallet_util import test_address\n\n\nclass ImportWithLabel(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        \"\"\"Main test logic\"\"\"\n\n        self.log.info(\n            \"Test importaddress with label and importprivkey without label.\"\n        )\n        self.log.info(\"Import a watch-only address with a label.\")\n        address = self.nodes[0].getnewaddress()\n        label = \"Test Label\"\n        self.nodes[1].importaddress(address, label)\n        test_address(self.nodes[1],\n                     address,\n                     iswatchonly=True,\n                     ismine=False,\n                     label=label)\n\n        self.log.info(\n            \"Import the watch-only address's private key without a \"\n            \"label and the address should keep its label.\"\n        )\n        priv_key = self.nodes[0].dumpprivkey(address)\n        self.nodes[1].importprivkey(priv_key)\n\n        test_address(self.nodes[1],\n                     address,\n                     label=label)\n\n        self.log.info(\n            \"Test importaddress without label and importprivkey with label.\"\n        )\n        self.log.info(\"Import a watch-only address without a label.\")\n        address2 = self.nodes[0].getnewaddress()\n        self.nodes[1].importaddress(address2)\n        test_address(self.nodes[1],\n                     address2,\n                     iswatchonly=True,\n                     ismine=False,\n                     label=\"\")\n\n        self.log.info(\n            \"Import the watch-only address's private key with a \"\n            \"label and the address should have its label updated.\"\n        )\n        priv_key2 = self.nodes[0].dumpprivkey(address2)\n        label2 = \"Test Label 2\"\n        self.nodes[1].importprivkey(priv_key2, label2)\n\n        test_address(self.nodes[1],\n                     address2,\n                     label=label2)\n\n        self.log.info(\"Test importaddress with label and importprivkey with label.\")\n        self.log.info(\"Import a watch-only address with a label.\")\n        address3 = self.nodes[0].getnewaddress()\n        label3_addr = \"Test Label 3 for importaddress\"\n        self.nodes[1].importaddress(address3, label3_addr)\n        test_address(self.nodes[1],\n                     address3,\n                     iswatchonly=True,\n                     ismine=False,\n                     label=label3_addr)\n\n        self.log.info(\n            \"Import the watch-only address's private key with a \"\n            \"label and the address should have its label updated.\"\n        )\n        priv_key3 = self.nodes[0].dumpprivkey(address3)\n        label3_priv = \"Test Label 3 for importprivkey\"\n        self.nodes[1].importprivkey(priv_key3, label3_priv)\n\n        test_address(self.nodes[1],\n                     address3,\n                     label=label3_priv)\n\n        self.log.info(\n            \"Test importprivkey won't label new dests with the same \"\n            \"label as others labeled dests for the same key.\"\n        )\n        self.log.info(\"Import a watch-only legacy address with a label.\")\n        address4 = self.nodes[0].getnewaddress()\n        label4_addr = \"Test Label 4 for importaddress\"\n        self.nodes[1].importaddress(address4, label4_addr)\n        test_address(self.nodes[1],\n                     address4,\n                     iswatchonly=True,\n                     ismine=False,\n                     label=label4_addr,\n                     embedded=None)\n\n        self.log.info(\n            \"Import the watch-only address's private key without a \"\n            \"label and new destinations for the key should have an \"\n            \"empty label while the 'old' destination should keep \"\n            \"its label.\"\n        )\n        priv_key4 = self.nodes[0].dumpprivkey(address4)\n        self.nodes[1].importprivkey(priv_key4)\n        embedded_addr = self.nodes[1].getaddressinfo(address4)['embedded']['address']\n\n        test_address(self.nodes[1],\n                     embedded_addr,\n                     label=\"\")\n        test_address(self.nodes[1],\n                     address4,\n                     label=label4_addr)\n\n        self.stop_nodes()\n\n\nif __name__ == \"__main__\":\n    ImportWithLabel().main()\n"
  },
  {
    "path": "test/functional/wallet_importmulti.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the importmulti RPC.\n\nTest importmulti by generating keys on node0, importing the scriptPubKeys and\naddresses on node1 and then testing the address info for the different address\nvariants.\n\n- `get_key()` and `get_multisig()` are called to generate keys on node0 and\n  return the privkeys, pubkeys and all variants of scriptPubKey and address.\n- `test_importmulti()` is called to send an importmulti call to node1, test\n  success, and (if unsuccessful) test the error code and error message returned.\n- `test_address()` is called to call getaddressinfo for an address on node1\n  and test the values returned.\"\"\"\n\nfrom test_framework.script import (\n    CScript,\n    OP_NOP,\n)\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.descriptors import descsum_create\nfrom test_framework.util import (\n    assert_equal,\n    assert_greater_than,\n    assert_raises_rpc_error,\n)\nfrom test_framework.wallet_util import (\n    get_key,\n    get_multisig,\n    test_address,\n)\n\nclass ImportMultiTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n        self.extra_args = [[\"-addresstype=legacy\"], [\"-addresstype=legacy\"]]\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def setup_network(self):\n        self.setup_nodes()\n\n    def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=[]):\n        \"\"\"Run importmulti and assert success\"\"\"\n        result = self.nodes[1].importmulti([req])\n        observed_warnings = []\n        if 'warnings' in result[0]:\n           observed_warnings = result[0]['warnings']\n        assert_equal(\"\\n\".join(sorted(warnings)), \"\\n\".join(sorted(observed_warnings)))\n        assert_equal(result[0]['success'], success)\n        if error_code is not None:\n            assert_equal(result[0]['error']['code'], error_code)\n            assert_equal(result[0]['error']['message'], error_message)\n\n    def run_test(self):\n        self.log.info(\"Mining blocks...\")\n        self.nodes[0].generate(1)\n        self.nodes[1].generate(1)\n        timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']\n\n        node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())\n\n        # Check only one address\n        assert_equal(node0_address1['ismine'], True)\n\n        # Node 1 sync test\n        assert_equal(self.nodes[1].getblockcount(), 1)\n\n        # Address Test - before import\n        address_info = self.nodes[1].getaddressinfo(node0_address1['address'])\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], False)\n\n        # RPC importmulti -----------------------------------------------\n\n        # Munt Address (implicit non-internal)\n        self.log.info(\"Should import an address\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=timestamp,\n                     ischange=False)\n        watchonly_address = key.p2pkh_addr\n        watchonly_timestamp = timestamp\n\n        self.log.info(\"Should not import an invalid address\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": \"not valid address\"},\n                               \"timestamp\": \"now\"},\n                              success=False,\n                              error_code=-5,\n                              error_message='Invalid address \\\"not valid address\\\"')\n\n        # ScriptPubKey + internal\n        self.log.info(\"Should import a scriptPubKey with internal flag\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"internal\": True},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=timestamp,\n                     ischange=True)\n\n        # ScriptPubKey + internal + label\n        self.log.info(\"Should not allow a label to be specified when internal is true\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"internal\": True,\n                               \"label\": \"Example label\"},\n                              success=False,\n                              error_code=-8,\n                              error_message='Internal addresses should not have a label')\n\n        # Nonstandard scriptPubKey + !internal\n        self.log.info(\"Should not import a nonstandard scriptPubKey without internal flag\")\n        nonstandardScriptPubKey = key.p2pkh_script + CScript([OP_NOP]).hex()\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": nonstandardScriptPubKey,\n                               \"timestamp\": \"now\"},\n                              success=False,\n                              error_code=-8,\n                              error_message='Internal must be set to true for nonstandard scriptPubKey imports.')\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=False,\n                     timestamp=None)\n\n        # Address + Public key + !Internal(explicit)\n        self.log.info(\"Should import an address with public key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [key.pubkey],\n                               \"internal\": False},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=timestamp)\n\n        # ScriptPubKey + Public key + internal\n        self.log.info(\"Should import a scriptPubKey with internal and with public key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [key.pubkey],\n                               \"internal\": True},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=timestamp)\n\n        # Nonstandard scriptPubKey + Public key + !internal\n        self.log.info(\"Should not import a nonstandard scriptPubKey without internal and with public key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": nonstandardScriptPubKey,\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [key.pubkey]},\n                              success=False,\n                              error_code=-8,\n                              error_message='Internal must be set to true for nonstandard scriptPubKey imports.')\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=False,\n                     timestamp=None)\n\n        # Address + Private key + !watchonly\n        self.log.info(\"Should import an address with private key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey]},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=True,\n                     timestamp=timestamp)\n\n        self.log.info(\"Should not import an address with private key if is already imported\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey]},\n                              success=False,\n                              error_code=-4,\n                              error_message='The wallet already contains the private key for this address or script (\"' + key.p2pkh_script + '\")')\n\n        # Address + Private key + watchonly\n        self.log.info(\"Should import an address with private key and with watchonly\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey],\n                               \"watchonly\": True},\n                              success=True,\n                              warnings=[\"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=True,\n                     timestamp=timestamp)\n\n        # ScriptPubKey + Private key + internal\n        self.log.info(\"Should import a scriptPubKey with internal and with private key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey],\n                               \"internal\": True},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=True,\n                     timestamp=timestamp)\n\n        # Nonstandard scriptPubKey + Private key + !internal\n        self.log.info(\"Should not import a nonstandard scriptPubKey without internal and with private key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": nonstandardScriptPubKey,\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey]},\n                              success=False,\n                              error_code=-8,\n                              error_message='Internal must be set to true for nonstandard scriptPubKey imports.')\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=False,\n                     ismine=False,\n                     timestamp=None)\n\n        # P2SH address\n        multisig = get_multisig(self.nodes[0])\n        self.nodes[1].generate(100)\n        self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)\n        self.nodes[1].generate(1)\n        timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']\n\n        self.log.info(\"Should import a p2sh\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2sh_addr},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr,\n                     isscript=True,\n                     iswatchonly=True,\n                     timestamp=timestamp)\n        p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]\n        assert_equal(p2shunspent['spendable'], False)\n        assert_equal(p2shunspent['solvable'], False)\n\n        # P2SH + Redeem script\n        multisig = get_multisig(self.nodes[0])\n        self.nodes[1].generate(100)\n        self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)\n        self.nodes[1].generate(1)\n        timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']\n\n        self.log.info(\"Should import a p2sh with respective redeem script\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2sh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": multisig.redeem_script},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, solvable=True)\n\n        p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]\n        assert_equal(p2shunspent['spendable'], False)\n        assert_equal(p2shunspent['solvable'], True)\n\n        # P2SH + Redeem script + Private Keys + !Watchonly\n        multisig = get_multisig(self.nodes[0])\n        self.nodes[1].generate(100)\n        self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)\n        self.nodes[1].generate(1)\n        timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']\n\n        self.log.info(\"Should import a p2sh with respective redeem script and private keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2sh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": multisig.redeem_script,\n                               \"keys\": multisig.privkeys[0:2]},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr,\n                     timestamp=timestamp,\n                     ismine=False,\n                     iswatchonly=True,\n                     solvable=True)\n\n        p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]\n        assert_equal(p2shunspent['spendable'], False)\n        assert_equal(p2shunspent['solvable'], True)\n\n        # P2SH + Redeem script + Private Keys + Watchonly\n        multisig = get_multisig(self.nodes[0])\n        self.nodes[1].generate(100)\n        self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)\n        self.nodes[1].generate(1)\n        timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']\n\n        self.log.info(\"Should import a p2sh with respective redeem script and private keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2sh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": multisig.redeem_script,\n                               \"keys\": multisig.privkeys[0:2],\n                               \"watchonly\": True},\n                              success=True)\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     solvable=True,\n                     timestamp=timestamp)\n\n        # Address + Public key + !Internal + Wrong pubkey\n        self.log.info(\"Should not import an address with the wrong public key as non-solvable\")\n        key = get_key(self.nodes[0])\n        wrong_key = get_key(self.nodes[0]).pubkey\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [wrong_key]},\n                              success=True,\n                              warnings=[\"Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.\", \"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     solvable=False,\n                     timestamp=timestamp)\n\n        # ScriptPubKey + Public key + internal + Wrong pubkey\n        self.log.info(\"Should import a scriptPubKey with internal and with a wrong public key as non-solvable\")\n        key = get_key(self.nodes[0])\n        wrong_key = get_key(self.nodes[0]).pubkey\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [wrong_key],\n                               \"internal\": True},\n                              success=True,\n                              warnings=[\"Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.\", \"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     solvable=False,\n                     timestamp=timestamp)\n\n        # Address + Private key + !watchonly + Wrong private key\n        self.log.info(\"Should import an address with a wrong private key as non-solvable\")\n        key = get_key(self.nodes[0])\n        wrong_privkey = get_key(self.nodes[0]).privkey\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\",\n                               \"keys\": [wrong_privkey]},\n                               success=True,\n                               warnings=[\"Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.\", \"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     solvable=False,\n                     timestamp=timestamp)\n\n        # ScriptPubKey + Private key + internal + Wrong private key\n        self.log.info(\"Should import a scriptPubKey with internal and with a wrong private key as non-solvable\")\n        key = get_key(self.nodes[0])\n        wrong_privkey = get_key(self.nodes[0]).privkey\n        self.test_importmulti({\"scriptPubKey\": key.p2pkh_script,\n                               \"timestamp\": \"now\",\n                               \"keys\": [wrong_privkey],\n                               \"internal\": True},\n                              success=True,\n                              warnings=[\"Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.\", \"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     iswatchonly=True,\n                     ismine=False,\n                     solvable=False,\n                     timestamp=timestamp)\n\n        # Importing existing watch only address with new timestamp should replace saved timestamp.\n        assert_greater_than(timestamp, watchonly_timestamp)\n        self.log.info(\"Should replace previously saved watch only timestamp.\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": watchonly_address},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     watchonly_address,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=timestamp)\n        watchonly_timestamp = timestamp\n\n        # restart nodes to check for proper serialization/deserialization of watch only address\n        self.stop_nodes()\n        self.start_nodes()\n        test_address(self.nodes[1],\n                     watchonly_address,\n                     iswatchonly=True,\n                     ismine=False,\n                     timestamp=watchonly_timestamp)\n\n        # Bad or missing timestamps\n        self.log.info(\"Should throw on invalid or missing timestamp values\")\n        assert_raises_rpc_error(-3, 'Missing required timestamp field for key',\n                                self.nodes[1].importmulti, [{\"scriptPubKey\": key.p2pkh_script}])\n        assert_raises_rpc_error(-3, 'Expected number or \"now\" timestamp value for key. got type string',\n                                self.nodes[1].importmulti, [{\n                                    \"scriptPubKey\": key.p2pkh_script,\n                                    \"timestamp\": \"\"\n                                }])\n\n        # Import P2WPKH address as watch only\n        self.log.info(\"Should import a P2WPKH address as watch only\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2wpkh_addr},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2wpkh_addr,\n                     iswatchonly=True,\n                     solvable=False)\n\n        # Import P2WPKH address with public key but no private key\n        self.log.info(\"Should import a P2WPKH address and public key as solvable but not spendable\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2wpkh_addr},\n                               \"timestamp\": \"now\",\n                               \"pubkeys\": [key.pubkey]},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2wpkh_addr,\n                     ismine=False,\n                     solvable=True)\n\n        # Import P2WPKH address with key and check it is spendable\n        self.log.info(\"Should import a P2WPKH address with key\")\n        key = get_key(self.nodes[0])\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2wpkh_addr},\n                               \"timestamp\": \"now\",\n                               \"keys\": [key.privkey]},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2wpkh_addr,\n                     iswatchonly=False,\n                     ismine=True)\n\n        # P2WSH multisig address without scripts or keys\n        multisig = get_multisig(self.nodes[0])\n        self.log.info(\"Should import a p2wsh multisig as watch only without respective redeem script and private keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2wsh_addr},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr,\n                     solvable=False)\n\n        # Same P2WSH multisig address as above, but now with witnessscript + private keys\n        self.log.info(\"Should import a p2wsh with respective witness script and private keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2wsh_addr},\n                               \"timestamp\": \"now\",\n                               \"witnessscript\": multisig.redeem_script,\n                               \"keys\": multisig.privkeys},\n                              success=True)\n        test_address(self.nodes[1],\n                     multisig.p2sh_addr,\n                     solvable=True,\n                     ismine=True,\n                     sigsrequired=2)\n\n        # P2SH-P2WPKH address with no redeemscript or public or private key\n        key = get_key(self.nodes[0])\n        self.log.info(\"Should import a p2sh-p2wpkh without redeem script or keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2sh_p2wpkh_addr},\n                               \"timestamp\": \"now\"},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2sh_p2wpkh_addr,\n                     solvable=False,\n                     ismine=False)\n\n        # P2SH-P2WPKH address + redeemscript + public key with no private key\n        self.log.info(\"Should import a p2sh-p2wpkh with respective redeem script and pubkey as solvable\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2sh_p2wpkh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": key.p2sh_p2wpkh_redeem_script,\n                               \"pubkeys\": [key.pubkey]},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2sh_p2wpkh_addr,\n                     solvable=True,\n                     ismine=False)\n\n        # P2SH-P2WPKH address + redeemscript + private key\n        key = get_key(self.nodes[0])\n        self.log.info(\"Should import a p2sh-p2wpkh with respective redeem script and private keys\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": key.p2sh_p2wpkh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": key.p2sh_p2wpkh_redeem_script,\n                               \"keys\": [key.privkey]},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2sh_p2wpkh_addr,\n                     solvable=True,\n                     ismine=True)\n\n        # P2SH-P2WSH multisig + redeemscript with no private key\n        multisig = get_multisig(self.nodes[0])\n        self.log.info(\"Should import a p2sh-p2wsh with respective redeem script but no private key\")\n        self.test_importmulti({\"scriptPubKey\": {\"address\": multisig.p2sh_p2wsh_addr},\n                               \"timestamp\": \"now\",\n                               \"redeemscript\": multisig.p2wsh_script,\n                               \"witnessscript\": multisig.redeem_script},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     multisig.p2sh_p2wsh_addr,\n                     solvable=True,\n                     ismine=False)\n\n        # Test importing of a P2SH-P2WPKH address via descriptor + private key\n        key = get_key(self.nodes[0])\n        self.log.info(\"Should not import a p2sh-p2wpkh address from descriptor without checksum and private key\")\n        self.test_importmulti({\"desc\": \"sh(wpkh(\" + key.pubkey + \"))\",\n                               \"timestamp\": \"now\",\n                               \"label\": \"Descriptor import test\",\n                               \"keys\": [key.privkey]},\n                              success=False,\n                              error_code=-5,\n                              error_message=\"Descriptor is invalid\")\n\n        # Test importing of a P2SH-P2WPKH address via descriptor + private key\n        key = get_key(self.nodes[0])\n        self.log.info(\"Should import a p2sh-p2wpkh address from descriptor and private key\")\n        self.test_importmulti({\"desc\": descsum_create(\"sh(wpkh(\" + key.pubkey + \"))\"),\n                               \"timestamp\": \"now\",\n                               \"label\": \"Descriptor import test\",\n                               \"keys\": [key.privkey]},\n                              success=True)\n        test_address(self.nodes[1],\n                     key.p2sh_p2wpkh_addr,\n                     solvable=True,\n                     ismine=True,\n                     label=\"Descriptor import test\")\n\n        # Test ranged descriptor fails if range is not specified\n        xpriv = \"tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg\"\n        addresses = [\"2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf\", \"2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA\"] # hdkeypath=m/0'/0'/0' and 1'\n        desc = \"sh(wpkh(\" + xpriv + \"/0'/0'/*'\" + \"))\"\n        self.log.info(\"Ranged descriptor import should fail without a specified range\")\n        self.test_importmulti({\"desc\": descsum_create(desc),\n                               \"timestamp\": \"now\"},\n                              success=False,\n                              error_code=-8,\n                              error_message='Descriptor is ranged, please specify the range')\n\n        # Test importing of a ranged descriptor without keys\n        self.log.info(\"Should import the ranged descriptor with specified range as solvable\")\n        self.test_importmulti({\"desc\": descsum_create(desc),\n                               \"timestamp\": \"now\",\n                               \"range\": 1},\n                              success=True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        for address in addresses:\n            test_address(self.nodes[1],\n                         key.p2sh_p2wpkh_addr,\n                         solvable=True)\n\n        # Test importing of a P2PKH address via descriptor\n        key = get_key(self.nodes[0])\n        self.log.info(\"Should import a p2pkh address from descriptor\")\n        self.test_importmulti({\"desc\": descsum_create(\"pkh(\" + key.pubkey + \")\"),\n                               \"timestamp\": \"now\",\n                               \"label\": \"Descriptor import test\"},\n                              True,\n                              warnings=[\"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.\"])\n        test_address(self.nodes[1],\n                     key.p2pkh_addr,\n                     solvable=True,\n                     ismine=False,\n                     label=\"Descriptor import test\")\n\n        # Test import fails if both desc and scriptPubKey are provided\n        key = get_key(self.nodes[0])\n        self.log.info(\"Import should fail if both scriptPubKey and desc are provided\")\n        self.test_importmulti({\"desc\": descsum_create(\"pkh(\" + key.pubkey + \")\"),\n                               \"scriptPubKey\": {\"address\": key.p2pkh_addr},\n                               \"timestamp\": \"now\"},\n                              success=False,\n                              error_code=-8,\n                              error_message='Both a descriptor and a scriptPubKey should not be provided.')\n\n        # Test import fails if neither desc nor scriptPubKey are present\n        key = get_key(self.nodes[0])\n        self.log.info(\"Import should fail if neither a descriptor nor a scriptPubKey are provided\")\n        self.test_importmulti({\"timestamp\": \"now\"},\n                              success=False,\n                              error_code=-8,\n                              error_message='Either a descriptor or scriptPubKey must be provided.')\n\n        # Test importing of a multisig via descriptor\n        key1 = get_key(self.nodes[0])\n        key2 = get_key(self.nodes[0])\n        self.log.info(\"Should import a 1-of-2 bare multisig from descriptor\")\n        self.test_importmulti({\"desc\": descsum_create(\"multi(1,\" + key1.pubkey + \",\" + key2.pubkey + \")\"),\n                               \"timestamp\": \"now\"},\n                              success=True)\n        self.log.info(\"Should not treat individual keys from the imported bare multisig as watchonly\")\n        test_address(self.nodes[1],\n                     key1.p2pkh_addr,\n                     ismine=False,\n                     iswatchonly=False)\n\n        # Import pubkeys with key origin info\n        self.log.info(\"Addresses should have hd keypath and master key id after import with key origin\")\n        pub_addr = self.nodes[1].getnewaddress()\n        pub_addr = self.nodes[1].getnewaddress()\n        info = self.nodes[1].getaddressinfo(pub_addr)\n        pub = info['pubkey']\n        pub_keypath = info['hdkeypath']\n        pub_fpr = info['hdmasterfingerprint']\n        result = self.nodes[0].importmulti(\n            [{\n                'desc' : descsum_create(\"wpkh([\" + pub_fpr + pub_keypath[1:] +\"]\" + pub + \")\"),\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        pub_import_info = self.nodes[0].getaddressinfo(pub_addr)\n        assert_equal(pub_import_info['hdmasterfingerprint'], pub_fpr)\n        assert_equal(pub_import_info['pubkey'], pub)\n        assert_equal(pub_import_info['hdkeypath'], pub_keypath)\n\n        # Import privkeys with key origin info\n        priv_addr = self.nodes[1].getnewaddress()\n        info = self.nodes[1].getaddressinfo(priv_addr)\n        priv = self.nodes[1].dumpprivkey(priv_addr)\n        priv_keypath = info['hdkeypath']\n        priv_fpr = info['hdmasterfingerprint']\n        result = self.nodes[0].importmulti(\n            [{\n                'desc' : descsum_create(\"wpkh([\" + priv_fpr + priv_keypath[1:] + \"]\" + priv + \")\"),\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        priv_import_info = self.nodes[0].getaddressinfo(priv_addr)\n        assert_equal(priv_import_info['hdmasterfingerprint'], priv_fpr)\n        assert_equal(priv_import_info['hdkeypath'], priv_keypath)\n\n        # Make sure the key origin info are still there after a restart\n        self.stop_nodes()\n        self.start_nodes()\n        import_info = self.nodes[0].getaddressinfo(pub_addr)\n        assert_equal(import_info['hdmasterfingerprint'], pub_fpr)\n        assert_equal(import_info['hdkeypath'], pub_keypath)\n        import_info = self.nodes[0].getaddressinfo(priv_addr)\n        assert_equal(import_info['hdmasterfingerprint'], priv_fpr)\n        assert_equal(import_info['hdkeypath'], priv_keypath)\n\n        # Check legacy import does not import key origin info\n        self.log.info(\"Legacy imports don't have key origin info\")\n        pub_addr = self.nodes[1].getnewaddress()\n        info = self.nodes[1].getaddressinfo(pub_addr)\n        pub = info['pubkey']\n        result = self.nodes[0].importmulti(\n            [{\n                'scriptPubKey': {'address': pub_addr},\n                'pubkeys': [pub],\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        pub_import_info = self.nodes[0].getaddressinfo(pub_addr)\n        assert_equal(pub_import_info['pubkey'], pub)\n        assert 'hdmasterfingerprint' not in pub_import_info\n        assert 'hdkeypath' not in pub_import_info\n\n        # Import some public keys to the keypool of a no privkey wallet\n        self.log.info(\"Adding pubkey to keypool of disableprivkey wallet\")\n        self.nodes[1].createwallet(wallet_name=\"noprivkeys\", disable_private_keys=True)\n        wrpc = self.nodes[1].get_wallet_rpc(\"noprivkeys\")\n\n        addr1 = self.nodes[0].getnewaddress()\n        addr2 = self.nodes[0].getnewaddress()\n        pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']\n        pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']\n        result = wrpc.importmulti(\n            [{\n                'desc': descsum_create('wpkh(' + pub1 + ')'),\n                'keypool': True,\n                \"timestamp\": \"now\",\n            },\n            {\n                'desc': descsum_create('wpkh(' + pub2 + ')'),\n                'keypool': True,\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        assert result[1]['success']\n        assert_equal(wrpc.getwalletinfo()[\"keypoolsize\"], 2)\n        newaddr1 = wrpc.getnewaddress()\n        assert_equal(addr1, newaddr1)\n        newaddr2 = wrpc.getnewaddress()\n        assert_equal(addr2, newaddr2)\n\n        # Import some public keys to the internal keypool of a no privkey wallet\n        self.log.info(\"Adding pubkey to internal keypool of disableprivkey wallet\")\n        addr1 = self.nodes[0].getnewaddress()\n        addr2 = self.nodes[0].getnewaddress()\n        pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']\n        pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']\n        result = wrpc.importmulti(\n            [{\n                'desc': descsum_create('wpkh(' + pub1 + ')'),\n                'keypool': True,\n                'internal': True,\n                \"timestamp\": \"now\",\n            },\n            {\n                'desc': descsum_create('wpkh(' + pub2 + ')'),\n                'keypool': True,\n                'internal': True,\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        assert result[1]['success']\n        assert_equal(wrpc.getwalletinfo()[\"keypoolsize_hd_internal\"], 2)\n        newaddr1 = wrpc.getrawchangeaddress()\n        assert_equal(addr1, newaddr1)\n        newaddr2 = wrpc.getrawchangeaddress()\n        assert_equal(addr2, newaddr2)\n\n        # Import a multisig and make sure the keys don't go into the keypool\n        self.log.info('Imported scripts with pubkeys shoud not have their pubkeys go into the keypool')\n        addr1 = self.nodes[0].getnewaddress()\n        addr2 = self.nodes[0].getnewaddress()\n        pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']\n        pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']\n        result = wrpc.importmulti(\n            [{\n                'desc': descsum_create('wsh(multi(2,' + pub1 + ',' + pub2 + '))'),\n                'keypool': True,\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert result[0]['success']\n        assert_equal(wrpc.getwalletinfo()[\"keypoolsize\"], 0)\n\n        # Cannot import those pubkeys to keypool of wallet with privkeys\n        self.log.info(\"Pubkeys cannot be added to the keypool of a wallet with private keys\")\n        wrpc = self.nodes[1].get_wallet_rpc(\"\")\n        assert wrpc.getwalletinfo()['private_keys_enabled']\n        result = wrpc.importmulti(\n            [{\n                'desc': descsum_create('wpkh(' + pub1 + ')'),\n                'keypool': True,\n                \"timestamp\": \"now\",\n            }]\n        )\n        assert_equal(result[0]['error']['code'], -8)\n        assert_equal(result[0]['error']['message'], \"Keys can only be imported to the keypool when private keys are disabled\")\n\n        # Make sure ranged imports import keys in order\n        self.log.info('Key ranges should be imported in order')\n        wrpc = self.nodes[1].get_wallet_rpc(\"noprivkeys\")\n        assert_equal(wrpc.getwalletinfo()[\"keypoolsize\"], 0)\n        assert_equal(wrpc.getwalletinfo()[\"private_keys_enabled\"], False)\n        xpub = \"tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY\"\n        addresses = [\n            'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv', # m/0'/0'/0\n            'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8', # m/0'/0'/1\n            'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu', # m/0'/0'/2\n            'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640', # m/0'/0'/3\n            'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0', # m/0'/0'/4\n        ]\n        result = wrpc.importmulti(\n            [{\n                'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'),\n                'keypool': True,\n                'timestamp': 'now',\n                'range' : [0, 4],\n            }]\n        )\n        for i in range(0, 5):\n            addr = wrpc.getnewaddress('', 'bech32')\n            assert_equal(addr, addresses[i])\n\nif __name__ == '__main__':\n    ImportMultiTest().main()\n"
  },
  {
    "path": "test/functional/wallet_importprunedfunds.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the importprunedfunds and removeprunedfunds RPCs.\"\"\"\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\nclass ImportPrunedFundsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.log.info(\"Mining blocks...\")\n        self.nodes[0].generate(101)\n\n        self.sync_all()\n\n        # address\n        address1 = self.nodes[0].getnewaddress()\n        # pubkey\n        address2 = self.nodes[0].getnewaddress()\n        # privkey\n        address3 = self.nodes[0].getnewaddress()\n        address3_privkey = self.nodes[0].dumpprivkey(address3)  # Using privkey\n\n        # Check only one address\n        address_info = self.nodes[0].getaddressinfo(address1)\n        assert_equal(address_info['ismine'], True)\n\n        self.sync_all()\n\n        # Node 1 sync test\n        assert_equal(self.nodes[1].getblockcount(), 101)\n\n        # Address Test - before import\n        address_info = self.nodes[1].getaddressinfo(address1)\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], False)\n\n        address_info = self.nodes[1].getaddressinfo(address2)\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], False)\n\n        address_info = self.nodes[1].getaddressinfo(address3)\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], False)\n\n        # Send funds to self\n        txnid1 = self.nodes[0].sendtoaddress(address1, 0.1)\n        self.nodes[0].generate(1)\n        rawtxn1 = self.nodes[0].gettransaction(txnid1)['hex']\n        proof1 = self.nodes[0].gettxoutproof([txnid1])\n\n        txnid2 = self.nodes[0].sendtoaddress(address2, 0.05)\n        self.nodes[0].generate(1)\n        rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']\n        proof2 = self.nodes[0].gettxoutproof([txnid2])\n\n        txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)\n        self.nodes[0].generate(1)\n        rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']\n        proof3 = self.nodes[0].gettxoutproof([txnid3])\n\n        self.sync_all()\n\n        # Import with no affiliated address\n        assert_raises_rpc_error(-5, \"No addresses\", self.nodes[1].importprunedfunds, rawtxn1, proof1)\n\n        balance1 = self.nodes[1].getbalance()\n        assert_equal(balance1, Decimal(0))\n\n        # Import with affiliated address with no rescan\n        self.nodes[1].importaddress(address=address2, rescan=False)\n        self.nodes[1].importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2)\n        assert [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid2]\n\n        # Import with private key with no rescan\n        self.nodes[1].importprivkey(muntprivkey=address3_privkey, rescan=False)\n        self.nodes[1].importprunedfunds(rawtxn3, proof3)\n        assert [tx for tx in self.nodes[1].listtransactions() if tx['txid'] == txnid3]\n        balance3 = self.nodes[1].getbalance()\n        assert_equal(balance3, Decimal('0.025'))\n\n        # Addresses Test - after import\n        address_info = self.nodes[1].getaddressinfo(address1)\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], False)\n        address_info = self.nodes[1].getaddressinfo(address2)\n        assert_equal(address_info['iswatchonly'], True)\n        assert_equal(address_info['ismine'], False)\n        address_info = self.nodes[1].getaddressinfo(address3)\n        assert_equal(address_info['iswatchonly'], False)\n        assert_equal(address_info['ismine'], True)\n\n        # Remove transactions\n        assert_raises_rpc_error(-8, \"Transaction does not exist in wallet.\", self.nodes[1].removeprunedfunds, txnid1)\n        assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid1]\n\n        self.nodes[1].removeprunedfunds(txnid2)\n        assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid2]\n\n        self.nodes[1].removeprunedfunds(txnid3)\n        assert not [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid3]\n\nif __name__ == '__main__':\n    ImportPrunedFundsTest().main()\n"
  },
  {
    "path": "test/functional/wallet_keypool.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet keypool and interaction with wallet encryption/locking.\"\"\"\n\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_raises_rpc_error\n\nclass KeyPoolTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        nodes = self.nodes\n        addr_before_encrypting = nodes[0].getnewaddress()\n        addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)\n        wallet_info_old = nodes[0].getwalletinfo()\n        assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']\n\n        # Encrypt wallet and wait to terminate\n        nodes[0].encryptwallet('test')\n        # Keep creating keys\n        addr = nodes[0].getnewaddress()\n        addr_data = nodes[0].getaddressinfo(addr)\n        wallet_info = nodes[0].getwalletinfo()\n        assert addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid']\n        assert addr_data['hdseedid'] == wallet_info['hdseedid']\n        assert_raises_rpc_error(-12, \"Error: Keypool ran out, please call keypoolrefill first\", nodes[0].getnewaddress)\n\n        # put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)\n        nodes[0].walletpassphrase('test', 12000)\n        nodes[0].keypoolrefill(6)\n        nodes[0].walletlock()\n        wi = nodes[0].getwalletinfo()\n        assert_equal(wi['keypoolsize_hd_internal'], 6)\n        assert_equal(wi['keypoolsize'], 6)\n\n        # drain the internal keys\n        nodes[0].getrawchangeaddress()\n        nodes[0].getrawchangeaddress()\n        nodes[0].getrawchangeaddress()\n        nodes[0].getrawchangeaddress()\n        nodes[0].getrawchangeaddress()\n        nodes[0].getrawchangeaddress()\n        addr = set()\n        # the next one should fail\n        assert_raises_rpc_error(-12, \"Keypool ran out\", nodes[0].getrawchangeaddress)\n\n        # drain the external keys\n        addr.add(nodes[0].getnewaddress())\n        addr.add(nodes[0].getnewaddress())\n        addr.add(nodes[0].getnewaddress())\n        addr.add(nodes[0].getnewaddress())\n        addr.add(nodes[0].getnewaddress())\n        addr.add(nodes[0].getnewaddress())\n        assert len(addr) == 6\n        # the next one should fail\n        assert_raises_rpc_error(-12, \"Error: Keypool ran out, please call keypoolrefill first\", nodes[0].getnewaddress)\n\n        # refill keypool with three new addresses\n        nodes[0].walletpassphrase('test', 1)\n        nodes[0].keypoolrefill(3)\n\n        # test walletpassphrase timeout\n        time.sleep(1.1)\n        assert_equal(nodes[0].getwalletinfo()[\"unlocked_until\"], 0)\n\n        # drain the keypool\n        for _ in range(3):\n            nodes[0].getnewaddress()\n        assert_raises_rpc_error(-12, \"Keypool ran out\", nodes[0].getnewaddress)\n\n        nodes[0].walletpassphrase('test', 100)\n        nodes[0].keypoolrefill(100)\n        wi = nodes[0].getwalletinfo()\n        assert_equal(wi['keypoolsize_hd_internal'], 100)\n        assert_equal(wi['keypoolsize'], 100)\n\nif __name__ == '__main__':\n    KeyPoolTest().main()\n"
  },
  {
    "path": "test/functional/wallet_keypool_topup.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test HD Wallet keypool restore function.\n\nTwo nodes. Node1 is under test. Node0 is providing transactions and generating blocks.\n\n- Start node1, shutdown and backup wallet.\n- Generate 110 keys (enough to drain the keypool). Store key 90 (in the initial keypool) and key 110 (beyond the initial keypool). Send funds to key 90 and key 110.\n- Stop node1, clear the datadir, move wallet file back into the datadir and restart node1.\n- connect node1 to node0. Verify that they sync and node1 receives its funds.\"\"\"\nimport os\nimport shutil\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes_bi,\n    sync_blocks,\n)\n\n\nclass KeypoolRestoreTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 4\n        self.extra_args = [[], ['-keypool=100'], ['-keypool=100'], ['-keypool=100']]\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        wallet_path = os.path.join(self.nodes[1].datadir, \"regtest\", \"wallets\", \"wallet.dat\")\n        wallet_backup_path = os.path.join(self.nodes[1].datadir, \"wallet.bak\")\n        self.nodes[0].generate(101)\n\n        self.log.info(\"Make backup of wallet\")\n        self.stop_node(1)\n        shutil.copyfile(wallet_path, wallet_backup_path)\n        self.start_node(1, self.extra_args[1])\n        connect_nodes_bi(self.nodes, 0, 1)\n        connect_nodes_bi(self.nodes, 0, 2)\n        connect_nodes_bi(self.nodes, 0, 3)\n\n        for i, output_type in enumerate([\"legacy\", \"p2sh-segwit\", \"bech32\"]):\n\n            self.log.info(\"Generate keys for wallet with address type: {}\".format(output_type))\n            idx = i+1\n            for _ in range(90):\n                addr_oldpool = self.nodes[idx].getnewaddress(address_type=output_type)\n            for _ in range(20):\n                addr_extpool = self.nodes[idx].getnewaddress(address_type=output_type)\n\n            # Make sure we're creating the outputs we expect\n            address_details = self.nodes[idx].validateaddress(addr_extpool)\n            if i == 0:\n                assert not address_details[\"isscript\"] and not address_details[\"iswitness\"]\n            elif i == 1:\n                assert address_details[\"isscript\"] and not address_details[\"iswitness\"]\n            else:\n                assert not address_details[\"isscript\"] and address_details[\"iswitness\"]\n\n\n            self.log.info(\"Send funds to wallet\")\n            self.nodes[0].sendtoaddress(addr_oldpool, 10)\n            self.nodes[0].generate(1)\n            self.nodes[0].sendtoaddress(addr_extpool, 5)\n            self.nodes[0].generate(1)\n            sync_blocks(self.nodes)\n\n            self.log.info(\"Restart node with wallet backup\")\n            self.stop_node(idx)\n            shutil.copyfile(wallet_backup_path, wallet_path)\n            self.start_node(idx, self.extra_args[idx])\n            connect_nodes_bi(self.nodes, 0, idx)\n            self.sync_all()\n\n            self.log.info(\"Verify keypool is restored and balance is correct\")\n            assert_equal(self.nodes[idx].getbalance(), 15)\n            assert_equal(self.nodes[idx].listtransactions()[0]['category'], \"receive\")\n            # Check that we have marked all keys up to the used keypool key as used\n            assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress())['hdkeypath'], \"m/0'/0'/110'\")\n\n\nif __name__ == '__main__':\n    KeypoolRestoreTest().main()\n"
  },
  {
    "path": "test/functional/wallet_listreceivedby.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the listreceivedbyaddress RPC.\"\"\"\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_array_result,\n    assert_equal,\n    assert_raises_rpc_error,\n    sync_blocks,\n)\n\n\nclass ReceivedByTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        # Generate block to get out of IBD\n        self.nodes[0].generate(1)\n        sync_blocks(self.nodes)\n\n        # save the number of coinbase reward addresses so far\n        num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))\n\n        self.log.info(\"listreceivedbyaddress Test\")\n\n        # Send from node 0 to 1\n        addr = self.nodes[1].getnewaddress()\n        txid = self.nodes[0].sendtoaddress(addr, 0.1)\n        self.sync_all()\n\n        # Check not listed in listreceivedbyaddress because has 0 confirmations\n        assert_array_result(self.nodes[1].listreceivedbyaddress(),\n                            {\"address\": addr},\n                            {},\n                            True)\n        # Bury Tx under 10 block so it will be returned by listreceivedbyaddress\n        self.nodes[1].generate(10)\n        self.sync_all()\n        assert_array_result(self.nodes[1].listreceivedbyaddress(),\n                            {\"address\": addr},\n                            {\"address\": addr, \"label\": \"\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 10, \"txids\": [txid, ]})\n        # With min confidence < 10\n        assert_array_result(self.nodes[1].listreceivedbyaddress(5),\n                            {\"address\": addr},\n                            {\"address\": addr, \"label\": \"\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 10, \"txids\": [txid, ]})\n        # With min confidence > 10, should not find Tx\n        assert_array_result(self.nodes[1].listreceivedbyaddress(11), {\"address\": addr}, {}, True)\n\n        # Empty Tx\n        empty_addr = self.nodes[1].getnewaddress()\n        assert_array_result(self.nodes[1].listreceivedbyaddress(0, True),\n                            {\"address\": empty_addr},\n                            {\"address\": empty_addr, \"label\": \"\", \"amount\": 0, \"confirmations\": 0, \"txids\": []})\n\n        # Test Address filtering\n        # Only on addr\n        expected = {\"address\": addr, \"label\": \"\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 10, \"txids\": [txid, ]}\n        res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr)\n        assert_array_result(res, {\"address\": addr}, expected)\n        assert_equal(len(res), 1)\n        # Test for regression on CLI calls with address string (#14173)\n        cli_res = self.nodes[1].cli.listreceivedbyaddress(0, True, True, addr)\n        assert_array_result(cli_res, {\"address\": addr}, expected)\n        assert_equal(len(cli_res), 1)\n        # Error on invalid address\n        assert_raises_rpc_error(-4, \"address_filter parameter was invalid\", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter=\"bamboozling\")\n        # Another address receive money\n        res = self.nodes[1].listreceivedbyaddress(0, True, True)\n        assert_equal(len(res), 2 + num_cb_reward_addresses)  # Right now 2 entries\n        other_addr = self.nodes[1].getnewaddress()\n        txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1)\n        self.nodes[0].generate(1)\n        self.sync_all()\n        # Same test as above should still pass\n        expected = {\"address\": addr, \"label\": \"\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 11, \"txids\": [txid, ]}\n        res = self.nodes[1].listreceivedbyaddress(0, True, True, addr)\n        assert_array_result(res, {\"address\": addr}, expected)\n        assert_equal(len(res), 1)\n        # Same test as above but with other_addr should still pass\n        expected = {\"address\": other_addr, \"label\": \"\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 1, \"txids\": [txid2, ]}\n        res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr)\n        assert_array_result(res, {\"address\": other_addr}, expected)\n        assert_equal(len(res), 1)\n        # Should be two entries though without filter\n        res = self.nodes[1].listreceivedbyaddress(0, True, True)\n        assert_equal(len(res), 3 + num_cb_reward_addresses)  # Became 3 entries\n\n        # Not on random addr\n        other_addr = self.nodes[0].getnewaddress()  # note on node[0]! just a random addr\n        res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr)\n        assert_equal(len(res), 0)\n\n        self.log.info(\"getreceivedbyaddress Test\")\n\n        # Send from node 0 to 1\n        addr = self.nodes[1].getnewaddress()\n        txid = self.nodes[0].sendtoaddress(addr, 0.1)\n        self.sync_all()\n\n        # Check balance is 0 because of 0 confirmations\n        balance = self.nodes[1].getreceivedbyaddress(addr)\n        assert_equal(balance, Decimal(\"0.0\"))\n\n        # Check balance is 0.1\n        balance = self.nodes[1].getreceivedbyaddress(addr, 0)\n        assert_equal(balance, Decimal(\"0.1\"))\n\n        # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress\n        self.nodes[1].generate(10)\n        self.sync_all()\n        balance = self.nodes[1].getreceivedbyaddress(addr)\n        assert_equal(balance, Decimal(\"0.1\"))\n\n        # Trying to getreceivedby for an address the wallet doesn't own should return an error\n        assert_raises_rpc_error(-4, \"Address not found in wallet\", self.nodes[0].getreceivedbyaddress, addr)\n\n        self.log.info(\"listreceivedbylabel + getreceivedbylabel Test\")\n\n        # set pre-state\n        label = ''\n        address = self.nodes[1].getnewaddress()\n        assert_equal(self.nodes[1].getaddressinfo(address)['label'], label)\n        received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel() if r[\"label\"] == label][0]\n        balance_by_label = self.nodes[1].getreceivedbylabel(label)\n\n        txid = self.nodes[0].sendtoaddress(addr, 0.1)\n        self.sync_all()\n\n        # listreceivedbylabel should return received_by_label_json because of 0 confirmations\n        assert_array_result(self.nodes[1].listreceivedbylabel(),\n                            {\"label\": label},\n                            received_by_label_json)\n\n        # getreceivedbyaddress should return same balance because of 0 confirmations\n        balance = self.nodes[1].getreceivedbylabel(label)\n        assert_equal(balance, balance_by_label)\n\n        self.nodes[1].generate(10)\n        self.sync_all()\n        # listreceivedbylabel should return updated received list\n        assert_array_result(self.nodes[1].listreceivedbylabel(),\n                            {\"label\": label},\n                            {\"label\": received_by_label_json[\"label\"], \"amount\": (received_by_label_json[\"amount\"] + Decimal(\"0.1\"))})\n\n        # getreceivedbylabel should return updated receive total\n        balance = self.nodes[1].getreceivedbylabel(label)\n        assert_equal(balance, balance_by_label + Decimal(\"0.1\"))\n\n        # Create a new label named \"mynewlabel\" that has a 0 balance\n        address = self.nodes[1].getnewaddress()\n        self.nodes[1].setlabel(address, \"mynewlabel\")\n        received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel(0, True) if r[\"label\"] == \"mynewlabel\"][0]\n\n        # Test includeempty of listreceivedbylabel\n        assert_equal(received_by_label_json[\"amount\"], Decimal(\"0.0\"))\n\n        # Test getreceivedbylabel for 0 amount labels\n        balance = self.nodes[1].getreceivedbylabel(\"mynewlabel\")\n        assert_equal(balance, Decimal(\"0.0\"))\n\nif __name__ == '__main__':\n    ReceivedByTest().main()\n"
  },
  {
    "path": "test/functional/wallet_listsinceblock.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the listsincelast RPC.\"\"\"\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, assert_array_result, assert_raises_rpc_error\n\nclass ListSinceBlockTest (MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n        self.setup_clean_chain = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[2].generate(101)\n        self.sync_all()\n\n        self.test_no_blockhash()\n        self.test_invalid_blockhash()\n        self.test_reorg()\n        self.test_double_spend()\n        self.test_double_send()\n\n    def test_no_blockhash(self):\n        txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n        blockhash, = self.nodes[2].generate(1)\n        self.sync_all()\n\n        txs = self.nodes[0].listtransactions()\n        assert_array_result(txs, {\"txid\": txid}, {\n            \"category\": \"receive\",\n            \"amount\": 1,\n            \"blockhash\": blockhash,\n            \"confirmations\": 1,\n        })\n        assert_equal(\n            self.nodes[0].listsinceblock(),\n            {\"lastblock\": blockhash,\n             \"removed\": [],\n             \"transactions\": txs})\n        assert_equal(\n            self.nodes[0].listsinceblock(\"\"),\n            {\"lastblock\": blockhash,\n             \"removed\": [],\n             \"transactions\": txs})\n\n    def test_invalid_blockhash(self):\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[0].listsinceblock,\n                                \"42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4\")\n        assert_raises_rpc_error(-5, \"Block not found\", self.nodes[0].listsinceblock,\n                                \"0000000000000000000000000000000000000000000000000000000000000000\")\n        assert_raises_rpc_error(-8, \"blockhash must be of length 64 (not 11, for 'invalid-hex')\", self.nodes[0].listsinceblock,\n                                \"invalid-hex\")\n        assert_raises_rpc_error(-8, \"blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')\", self.nodes[0].listsinceblock,\n                                \"Z000000000000000000000000000000000000000000000000000000000000000\")\n\n    def test_reorg(self):\n        '''\n        `listsinceblock` did not behave correctly when handed a block that was\n        no longer in the main chain:\n\n             ab0\n          /       \\\n        aa1 [tx0]   bb1\n         |           |\n        aa2         bb2\n         |           |\n        aa3         bb3\n                     |\n                    bb4\n\n        Consider a client that has only seen block `aa3` above. It asks the node\n        to `listsinceblock aa3`. But at some point prior the main chain switched\n        to the bb chain.\n\n        Previously: listsinceblock would find height=4 for block aa3 and compare\n        this to height=5 for the tip of the chain (bb4). It would then return\n        results restricted to bb3-bb4.\n\n        Now: listsinceblock finds the fork at ab0 and returns results in the\n        range bb1-bb4.\n\n        This test only checks that [tx0] is present.\n        '''\n\n        # Split network into two\n        self.split_network()\n\n        # send to nodes[0] from nodes[2]\n        senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)\n\n        # generate on both sides\n        lastblockhash = self.nodes[1].generate(6)[5]\n        self.nodes[2].generate(7)\n        self.log.info('lastblockhash=%s' % (lastblockhash))\n\n        self.sync_all([self.nodes[:2], self.nodes[2:]])\n\n        self.join_network()\n\n        # listsinceblock(lastblockhash) should now include tx, as seen from nodes[0]\n        lsbres = self.nodes[0].listsinceblock(lastblockhash)\n        found = False\n        for tx in lsbres['transactions']:\n            if tx['txid'] == senttx:\n                found = True\n                break\n        assert found\n\n    def test_double_spend(self):\n        '''\n        This tests the case where the same UTXO is spent twice on two separate\n        blocks as part of a reorg.\n\n             ab0\n          /       \\\n        aa1 [tx1]   bb1 [tx2]\n         |           |\n        aa2         bb2\n         |           |\n        aa3         bb3\n                     |\n                    bb4\n\n        Problematic case:\n\n        1. User 1 receives BTC in tx1 from utxo1 in block aa1.\n        2. User 2 receives BTC in tx2 from utxo1 (same) in block bb1\n        3. User 1 sees 2 confirmations at block aa3.\n        4. Reorg into bb chain.\n        5. User 1 asks `listsinceblock aa3` and does not see that tx1 is now\n           invalidated.\n\n        Currently the solution to this is to detect that a reorg'd block is\n        asked for in listsinceblock, and to iterate back over existing blocks up\n        until the fork point, and to include all transactions that relate to the\n        node wallet.\n        '''\n\n        self.sync_all()\n\n        # Split network into two\n        self.split_network()\n\n        # share utxo between nodes[1] and nodes[2]\n        utxos = self.nodes[2].listunspent()\n        utxo = utxos[0]\n        privkey = self.nodes[2].dumpprivkey(utxo['address'])\n        self.nodes[1].importprivkey(privkey)\n\n        # send from nodes[1] using utxo to nodes[0]\n        change = '%.8f' % (float(utxo['amount']) - 1.0003)\n        recipient_dict = {\n            self.nodes[0].getnewaddress(): 1,\n            self.nodes[1].getnewaddress(): change,\n        }\n        utxo_dicts = [{\n            'txid': utxo['txid'],\n            'vout': utxo['vout'],\n        }]\n        txid1 = self.nodes[1].sendrawtransaction(\n            self.nodes[1].signrawtransaction(\n                self.nodes[1].createrawtransaction(utxo_dicts, recipient_dict))['hex'])\n\n        # send from nodes[2] using utxo to nodes[3]\n        recipient_dict2 = {\n            self.nodes[3].getnewaddress(): 1,\n            self.nodes[2].getnewaddress(): change,\n        }\n        self.nodes[2].sendrawtransaction(\n            self.nodes[2].signrawtransaction(\n                self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict2))['hex'])\n\n        # generate on both sides\n        lastblockhash = self.nodes[1].generate(3)[2]\n        self.nodes[2].generate(4)\n\n        self.join_network()\n\n        self.sync_all()\n\n        # gettransaction should work for txid1\n        assert self.nodes[0].gettransaction(txid1)['txid'] == txid1, \"gettransaction failed to find txid1\"\n\n        # listsinceblock(lastblockhash) should now include txid1, as seen from nodes[0]\n        lsbres = self.nodes[0].listsinceblock(lastblockhash)\n        assert any(tx['txid'] == txid1 for tx in lsbres['removed'])\n\n        # but it should not include 'removed' if include_removed=false\n        lsbres2 = self.nodes[0].listsinceblock(blockhash=lastblockhash, include_removed=False)\n        assert 'removed' not in lsbres2\n\n    def test_double_send(self):\n        '''\n        This tests the case where the same transaction is submitted twice on two\n        separate blocks as part of a reorg. The former will vanish and the\n        latter will appear as the true transaction (with confirmations dropping\n        as a result).\n\n             ab0\n          /       \\\n        aa1 [tx1]   bb1\n         |           |\n        aa2         bb2\n         |           |\n        aa3         bb3 [tx1]\n                     |\n                    bb4\n\n        Asserted:\n\n        1. tx1 is listed in listsinceblock.\n        2. It is included in 'removed' as it was removed, even though it is now\n           present in a different block.\n        3. It is listed with a confirmation count of 2 (bb3, bb4), not\n           3 (aa1, aa2, aa3).\n        '''\n\n        self.sync_all()\n\n        # Split network into two\n        self.split_network()\n\n        # create and sign a transaction\n        utxos = self.nodes[2].listunspent()\n        utxo = utxos[0]\n        change = '%.8f' % (float(utxo['amount']) - 1.0003)\n        recipient_dict = {\n            self.nodes[0].getnewaddress(): 1,\n            self.nodes[2].getnewaddress(): change,\n        }\n        utxo_dicts = [{\n            'txid': utxo['txid'],\n            'vout': utxo['vout'],\n        }]\n        signedtxres = self.nodes[2].signrawtransaction(\n            self.nodes[2].createrawtransaction(utxo_dicts, recipient_dict))\n        assert signedtxres['complete']\n\n        signedtx = signedtxres['hex']\n\n        # send from nodes[1]; this will end up in aa1\n        txid1 = self.nodes[1].sendrawtransaction(signedtx)\n\n        # generate bb1-bb2 on right side\n        self.nodes[2].generate(2)\n\n        # send from nodes[2]; this will end up in bb3\n        txid2 = self.nodes[2].sendrawtransaction(signedtx)\n\n        assert_equal(txid1, txid2)\n\n        # generate on both sides\n        lastblockhash = self.nodes[1].generate(3)[2]\n        self.nodes[2].generate(2)\n\n        self.join_network()\n\n        self.sync_all()\n\n        # gettransaction should work for txid1\n        self.nodes[0].gettransaction(txid1)\n\n        # listsinceblock(lastblockhash) should now include txid1 in transactions\n        # as well as in removed\n        lsbres = self.nodes[0].listsinceblock(lastblockhash)\n        assert any(tx['txid'] == txid1 for tx in lsbres['transactions'])\n        assert any(tx['txid'] == txid1 for tx in lsbres['removed'])\n\n        # find transaction and ensure confirmations is valid\n        for tx in lsbres['transactions']:\n            if tx['txid'] == txid1:\n                assert_equal(tx['confirmations'], 2)\n\n        # the same check for the removed array; confirmations should STILL be 2\n        for tx in lsbres['removed']:\n            if tx['txid'] == txid1:\n                assert_equal(tx['confirmations'], 2)\n\nif __name__ == '__main__':\n    ListSinceBlockTest().main()\n"
  },
  {
    "path": "test/functional/wallet_listtransactions.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the listtransactions API.\"\"\"\nfrom decimal import Decimal\nfrom io import BytesIO\n\nfrom test_framework.messages import COIN, CTransaction\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_array_result,\n    assert_equal,\n    hex_str_to_bytes,\n    sync_mempools,\n)\n\ndef tx_from_hex(hexstring):\n    tx = CTransaction()\n    f = BytesIO(hex_str_to_bytes(hexstring))\n    tx.deserialize(f)\n    return tx\n\nclass ListTransactionsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 2\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.nodes[0].generate(1)  # Get out of IBD\n        self.sync_all()\n        # Simple send, 0 to 1:\n        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)\n        self.sync_all()\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"txid\": txid},\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.1\"), \"confirmations\": 0})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"txid\": txid},\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 0})\n        # mine a block, confirmations should change:\n        self.nodes[0].generate(1)\n        self.sync_all()\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"txid\": txid},\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.1\"), \"confirmations\": 1})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"txid\": txid},\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.1\"), \"confirmations\": 1})\n\n        # send-to-self:\n        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"txid\": txid, \"category\": \"send\"},\n                            {\"amount\": Decimal(\"-0.2\")})\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"txid\": txid, \"category\": \"receive\"},\n                            {\"amount\": Decimal(\"0.2\")})\n\n        # sendmany from node1: twice to self, twice to node2:\n        send_to = {self.nodes[0].getnewaddress(): 0.11,\n                   self.nodes[1].getnewaddress(): 0.22,\n                   self.nodes[0].getnewaddress(): 0.33,\n                   self.nodes[1].getnewaddress(): 0.44}\n        txid = self.nodes[1].sendmany(\"\", send_to)\n        self.sync_all()\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.11\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.11\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.22\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.22\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.33\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[0].listtransactions(),\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.33\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"send\", \"amount\": Decimal(\"-0.44\")},\n                            {\"txid\": txid})\n        assert_array_result(self.nodes[1].listtransactions(),\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.44\")},\n                            {\"txid\": txid})\n\n        pubkey = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']\n        multisig = self.nodes[1].createmultisig(1, [pubkey])\n        self.nodes[0].importaddress(multisig[\"redeemScript\"], \"watchonly\", False, True)\n        txid = self.nodes[1].sendtoaddress(multisig[\"address\"], 0.1)\n        self.nodes[1].generate(1)\n        self.sync_all()\n        assert len(self.nodes[0].listtransactions(label=\"watchonly\", count=100, include_watchonly=False)) == 0\n        assert_array_result(self.nodes[0].listtransactions(label=\"watchonly\", count=100, include_watchonly=True),\n                            {\"category\": \"receive\", \"amount\": Decimal(\"0.1\")},\n                            {\"txid\": txid, \"label\": \"watchonly\"})\n\n        self.run_rbf_opt_in_test()\n\n    # Check that the opt-in-rbf flag works properly, for sent and received\n    # transactions.\n    def run_rbf_opt_in_test(self):\n        # Check whether a transaction signals opt-in RBF itself\n        def is_opt_in(node, txid):\n            rawtx = node.getrawtransaction(txid, 1)\n            for x in rawtx[\"vin\"]:\n                if x[\"sequence\"] < 0xfffffffe:\n                    return True\n            return False\n\n        # Find an unconfirmed output matching a certain txid\n        def get_unconfirmed_utxo_entry(node, txid_to_match):\n            utxo = node.listunspent(0, 0)\n            for i in utxo:\n                if i[\"txid\"] == txid_to_match:\n                    return i\n            return None\n\n        # 1. Chain a few transactions that don't opt-in.\n        txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)\n        assert not is_opt_in(self.nodes[0], txid_1)\n        assert_array_result(self.nodes[0].listtransactions(), {\"txid\": txid_1}, {\"bip125-replaceable\": \"no\"})\n        sync_mempools(self.nodes)\n        assert_array_result(self.nodes[1].listtransactions(), {\"txid\": txid_1}, {\"bip125-replaceable\": \"no\"})\n\n        # Tx2 will build off txid_1, still not opting in to RBF.\n        utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1)\n        assert_equal(utxo_to_use[\"safe\"], True)\n        utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)\n        utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)\n        assert_equal(utxo_to_use[\"safe\"], False)\n\n        # Create tx2 using createrawtransaction\n        inputs = [{\"txid\": utxo_to_use[\"txid\"], \"vout\": utxo_to_use[\"vout\"]}]\n        outputs = {self.nodes[0].getnewaddress(): 0.999}\n        tx2 = self.nodes[1].createrawtransaction(inputs, outputs)\n        tx2_signed = self.nodes[1].signrawtransaction(tx2)[\"hex\"]\n        txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)\n\n        # ...and check the result\n        assert not is_opt_in(self.nodes[1], txid_2)\n        assert_array_result(self.nodes[1].listtransactions(), {\"txid\": txid_2}, {\"bip125-replaceable\": \"no\"})\n        sync_mempools(self.nodes)\n        assert_array_result(self.nodes[0].listtransactions(), {\"txid\": txid_2}, {\"bip125-replaceable\": \"no\"})\n\n        # Tx3 will opt-in to RBF\n        utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_2)\n        inputs = [{\"txid\": txid_2, \"vout\": utxo_to_use[\"vout\"]}]\n        outputs = {self.nodes[1].getnewaddress(): 0.998}\n        tx3 = self.nodes[0].createrawtransaction(inputs, outputs)\n        tx3_modified = tx_from_hex(tx3)\n        tx3_modified.vin[0].nSequence = 0\n        tx3 = tx3_modified.serialize().hex()\n        tx3_signed = self.nodes[0].signrawtransaction(tx3)['hex']\n        txid_3 = self.nodes[0].sendrawtransaction(tx3_signed)\n\n        assert is_opt_in(self.nodes[0], txid_3)\n        assert_array_result(self.nodes[0].listtransactions(), {\"txid\": txid_3}, {\"bip125-replaceable\": \"yes\"})\n        sync_mempools(self.nodes)\n        assert_array_result(self.nodes[1].listtransactions(), {\"txid\": txid_3}, {\"bip125-replaceable\": \"yes\"})\n\n        # Tx4 will chain off tx3.  Doesn't signal itself, but depends on one\n        # that does.\n        utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3)\n        inputs = [{\"txid\": txid_3, \"vout\": utxo_to_use[\"vout\"]}]\n        outputs = {self.nodes[0].getnewaddress(): 0.997}\n        tx4 = self.nodes[1].createrawtransaction(inputs, outputs)\n        tx4_signed = self.nodes[1].signrawtransaction(tx4)[\"hex\"]\n        txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)\n\n        assert not is_opt_in(self.nodes[1], txid_4)\n        assert_array_result(self.nodes[1].listtransactions(), {\"txid\": txid_4}, {\"bip125-replaceable\": \"yes\"})\n        sync_mempools(self.nodes)\n        assert_array_result(self.nodes[0].listtransactions(), {\"txid\": txid_4}, {\"bip125-replaceable\": \"yes\"})\n\n        # Replace tx3, and check that tx4 becomes unknown\n        tx3_b = tx3_modified\n        tx3_b.vout[0].nValue -= int(Decimal(\"0.004\") * COIN)  # bump the fee\n        tx3_b = tx3_b.serialize().hex()\n        tx3_b_signed = self.nodes[0].signrawtransaction(tx3_b)['hex']\n        txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, 0)\n        assert is_opt_in(self.nodes[0], txid_3b)\n\n        assert_array_result(self.nodes[0].listtransactions(), {\"txid\": txid_4}, {\"bip125-replaceable\": \"unknown\"})\n        sync_mempools(self.nodes)\n        assert_array_result(self.nodes[1].listtransactions(), {\"txid\": txid_4}, {\"bip125-replaceable\": \"unknown\"})\n\n        # Check gettransaction as well:\n        for n in self.nodes[0:2]:\n            assert_equal(n.gettransaction(txid_1)[\"bip125-replaceable\"], \"no\")\n            assert_equal(n.gettransaction(txid_2)[\"bip125-replaceable\"], \"no\")\n            assert_equal(n.gettransaction(txid_3)[\"bip125-replaceable\"], \"yes\")\n            assert_equal(n.gettransaction(txid_3b)[\"bip125-replaceable\"], \"yes\")\n            assert_equal(n.gettransaction(txid_4)[\"bip125-replaceable\"], \"unknown\")\n\n        # After mining a transaction, it's no longer BIP125-replaceable\n        self.nodes[0].generate(1)\n        assert txid_3b not in self.nodes[0].getrawmempool()\n        assert_equal(self.nodes[0].gettransaction(txid_3b)[\"bip125-replaceable\"], \"no\")\n        assert_equal(self.nodes[0].gettransaction(txid_4)[\"bip125-replaceable\"], \"unknown\")\n\nif __name__ == '__main__':\n    ListTransactionsTest().main()\n"
  },
  {
    "path": "test/functional/wallet_multiwallet.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test multiwallet.\n\nVerify that a Munt-daemon node can load multiple wallet files\n\"\"\"\nimport os\nimport shutil\nimport time\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.test_node import ErrorMatch\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n)\n\n\nclass MultiWalletTest(MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.supports_cli = True\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        node = self.nodes[0]\n\n        data_dir = lambda *p: os.path.join(node.datadir, 'regtest', *p)\n        wallet_dir = lambda *p: data_dir('wallets', *p)\n        wallet = lambda name: node.get_wallet_rpc(name)\n\n        def wallet_file(name):\n            if os.path.isdir(wallet_dir(name)):\n                return wallet_dir(name, \"wallet.dat\")\n            return wallet_dir(name)\n\n        assert_equal(self.nodes[0].listwalletdir(), { 'wallets': [{ 'name': '' }] })\n\n        # check wallet.dat is created\n        self.stop_nodes()\n        assert_equal(os.path.isfile(wallet_dir('wallet.dat')), True)\n\n        # create symlink to verify wallet directory path can be referenced\n        # through symlink\n        os.mkdir(wallet_dir('w7'))\n        os.symlink('w7', wallet_dir('w7_symlink'))\n\n        # rename wallet.dat to make sure plain wallet file paths (as opposed to\n        # directory paths) can be loaded\n        os.rename(wallet_dir(\"wallet.dat\"), wallet_dir(\"w8\"))\n\n        # create another dummy wallet for use in testing backups later\n        self.start_node(0, [])\n        self.stop_nodes()\n        empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat')\n        os.rename(wallet_dir(\"wallet.dat\"), empty_wallet)\n\n        # restart node with a mix of wallet names:\n        #   w1, w2, w3 - to verify new wallets created when non-existing paths specified\n        #   w          - to verify wallet name matching works when one wallet path is prefix of another\n        #   sub/w5     - to verify relative wallet path is created correctly\n        #   extern/w6  - to verify absolute wallet path is created correctly\n        #   w7_symlink - to verify symlinked wallet path is initialized correctly\n        #   w8         - to verify existing wallet file is loaded correctly\n        #   ''         - to verify default wallet file is created correctly\n        wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', os.path.join(self.options.tmpdir, 'extern/w6'), 'w7_symlink', 'w8', '']\n        extra_args = ['-wallet={}'.format(n) for n in wallet_names]\n        self.start_node(0, extra_args)\n        assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8'])\n\n        assert_equal(set(node.listwallets()), set(wallet_names))\n\n        # check that all requested wallets were created\n        self.stop_node(0)\n        for wallet_name in wallet_names:\n            assert_equal(os.path.isfile(wallet_file(wallet_name)), True)\n\n        # should not initialize if wallet path can't be created\n        exp_stderr = \"boost::filesystem::create_directory:\"\n        self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)\n\n        self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir \"wallets\" does not exist')\n        self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir \"wallets\" is a relative path', cwd=data_dir())\n        self.nodes[0].assert_start_raises_init_error(['-walletdir=debug.log'], 'Error: Specified -walletdir \"debug.log\" is not a directory', cwd=data_dir())\n\n        # should not initialize if there are duplicate wallets\n        self.nodes[0].assert_start_raises_init_error(['-wallet=w1', '-wallet=w1'], 'Error: Error loading wallet w1. Duplicate -wallet filename specified.')\n\n        # should not initialize if one wallet is a copy of another\n        shutil.copyfile(wallet_dir('w8'), wallet_dir('w8_copy'))\n        exp_stderr = \"BerkeleyBatch: Can't open database w8_copy \\(duplicates fileid \\w+ from w8\\)\"\n        self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)\n\n        # should not initialize if wallet file is a symlink\n        os.symlink('w8', wallet_dir('w8_symlink'))\n        self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \\'w8_symlink\\'\\. .*', match=ErrorMatch.FULL_REGEX)\n\n        # should not initialize if the specified walletdir does not exist\n        self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir \"bad\" does not exist')\n        # should not initialize if the specified walletdir is not a directory\n        not_a_dir = wallet_dir('notadir')\n        open(not_a_dir, 'a', encoding=\"utf8\").close()\n        self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir \"' + not_a_dir + '\" is not a directory')\n\n        self.log.info(\"Do not allow -zapwallettxes with multiwallet\")\n        self.nodes[0].assert_start_raises_init_error(['-zapwallettxes', '-wallet=w1', '-wallet=w2'], \"Error: -zapwallettxes is only allowed with a single wallet file\")\n        self.nodes[0].assert_start_raises_init_error(['-zapwallettxes=1', '-wallet=w1', '-wallet=w2'], \"Error: -zapwallettxes is only allowed with a single wallet file\")\n        self.nodes[0].assert_start_raises_init_error(['-zapwallettxes=2', '-wallet=w1', '-wallet=w2'], \"Error: -zapwallettxes is only allowed with a single wallet file\")\n\n        self.log.info(\"Do not allow -salvagewallet with multiwallet\")\n        self.nodes[0].assert_start_raises_init_error(['-salvagewallet', '-wallet=w1', '-wallet=w2'], \"Error: -salvagewallet is only allowed with a single wallet file\")\n        self.nodes[0].assert_start_raises_init_error(['-salvagewallet=1', '-wallet=w1', '-wallet=w2'], \"Error: -salvagewallet is only allowed with a single wallet file\")\n\n        self.log.info(\"Do not allow -upgradewallet with multiwallet\")\n        self.nodes[0].assert_start_raises_init_error(['-upgradewallet', '-wallet=w1', '-wallet=w2'], \"Error: -upgradewallet is only allowed with a single wallet file\")\n        self.nodes[0].assert_start_raises_init_error(['-upgradewallet=1', '-wallet=w1', '-wallet=w2'], \"Error: -upgradewallet is only allowed with a single wallet file\")\n\n        # if wallets/ doesn't exist, datadir should be the default wallet dir\n        wallet_dir2 = data_dir('walletdir')\n        os.rename(wallet_dir(), wallet_dir2)\n        self.start_node(0, ['-wallet=w4', '-wallet=w5'])\n        assert_equal(set(node.listwallets()), {\"w4\", \"w5\"})\n        w5 = wallet(\"w5\")\n        node.generatetoaddress(num_blocks=1, address=w5.getnewaddress())\n\n        # now if wallets/ exists again, but the rootdir is specified as the walletdir, w4 and w5 should still be loaded\n        os.rename(wallet_dir2, wallet_dir())\n        self.restart_node(0, ['-wallet=w4', '-wallet=w5', '-walletdir=' + data_dir()])\n        assert_equal(set(node.listwallets()), {\"w4\", \"w5\"})\n        w5 = wallet(\"w5\")\n        w5_info = w5.getwalletinfo()\n        assert_equal(w5_info['immature_balance'], 50)\n\n        competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir')\n        os.mkdir(competing_wallet_dir)\n        self.restart_node(0, ['-walletdir=' + competing_wallet_dir])\n        exp_stderr = \"Error: Error initializing wallet database environment \\\"\\S+competing_walletdir\\\"!\"\n        self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)\n\n        self.restart_node(0, extra_args)\n\n        assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy'])\n\n        wallets = [wallet(w) for w in wallet_names]\n        wallet_bad = wallet(\"bad\")\n\n        # check wallet names and balances\n        node.generatetoaddress(num_blocks=1, address=wallets[0].getnewaddress())\n        for wallet_name, wallet in zip(wallet_names, wallets):\n            info = wallet.getwalletinfo()\n            assert_equal(info['immature_balance'], 50 if wallet is wallets[0] else 0)\n            assert_equal(info['walletname'], wallet_name)\n\n        # accessing invalid wallet fails\n        assert_raises_rpc_error(-18, \"Requested wallet does not exist or is not loaded\", wallet_bad.getwalletinfo)\n\n        # accessing wallet RPC without using wallet endpoint fails\n        assert_raises_rpc_error(-19, \"Wallet file not specified\", node.getwalletinfo)\n\n        w1, w2, w3, w4, *_ = wallets\n        node.generatetoaddress(num_blocks=101, address=w1.getnewaddress())\n        assert_equal(w1.getbalance(), 100)\n        assert_equal(w2.getbalance(), 0)\n        assert_equal(w3.getbalance(), 0)\n        assert_equal(w4.getbalance(), 0)\n\n        w1.sendtoaddress(w2.getnewaddress(), 1)\n        w1.sendtoaddress(w3.getnewaddress(), 2)\n        w1.sendtoaddress(w4.getnewaddress(), 3)\n        node.generatetoaddress(num_blocks=1, address=w1.getnewaddress())\n        assert_equal(w2.getbalance(), 1)\n        assert_equal(w3.getbalance(), 2)\n        assert_equal(w4.getbalance(), 3)\n\n        batch = w1.batch([w1.getblockchaininfo.get_request(), w1.getwalletinfo.get_request()])\n        assert_equal(batch[0][\"result\"][\"chain\"], \"regtest\")\n        assert_equal(batch[1][\"result\"][\"walletname\"], \"w1\")\n\n        self.log.info('Check for per-wallet settxfee call')\n        assert_equal(w1.getwalletinfo()['paytxfee'], 0)\n        assert_equal(w2.getwalletinfo()['paytxfee'], 0)\n        w2.settxfee(4.0)\n        assert_equal(w1.getwalletinfo()['paytxfee'], 0)\n        assert_equal(w2.getwalletinfo()['paytxfee'], 4.0)\n\n        self.log.info(\"Test dynamic wallet loading\")\n\n        self.restart_node(0, ['-nowallet'])\n        assert_equal(node.listwallets(), [])\n        assert_raises_rpc_error(-32601, \"Method not found\", node.getwalletinfo)\n\n        self.log.info(\"Load first wallet\")\n        loadwallet_name = node.loadwallet(wallet_names[0])\n        assert_equal(loadwallet_name['name'], wallet_names[0])\n        assert_equal(node.listwallets(), wallet_names[0:1])\n        node.getwalletinfo()\n        w1 = node.get_wallet_rpc(wallet_names[0])\n        w1.getwalletinfo()\n\n        self.log.info(\"Load second wallet\")\n        loadwallet_name = node.loadwallet(wallet_names[1])\n        assert_equal(loadwallet_name['name'], wallet_names[1])\n        assert_equal(node.listwallets(), wallet_names[0:2])\n        assert_raises_rpc_error(-19, \"Wallet file not specified\", node.getwalletinfo)\n        w2 = node.get_wallet_rpc(wallet_names[1])\n        w2.getwalletinfo()\n\n        self.log.info(\"Load remaining wallets\")\n        for wallet_name in wallet_names[2:]:\n            loadwallet_name = self.nodes[0].loadwallet(wallet_name)\n            assert_equal(loadwallet_name['name'], wallet_name)\n\n        assert_equal(set(self.nodes[0].listwallets()), set(wallet_names))\n\n        # Fail to load if wallet doesn't exist\n        assert_raises_rpc_error(-18, 'Wallet wallets not found.', self.nodes[0].loadwallet, 'wallets')\n\n        # Fail to load duplicate wallets\n        assert_raises_rpc_error(-4, 'Wallet file verification failed: Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, wallet_names[0])\n\n        # Fail to load duplicate wallets by different ways (directory and filepath)\n        assert_raises_rpc_error(-4, \"Wallet file verification failed: Error loading wallet wallet.dat. Duplicate -wallet filename specified.\", self.nodes[0].loadwallet, 'wallet.dat')\n\n        # Fail to load if one wallet is a copy of another\n        assert_raises_rpc_error(-1, \"BerkeleyBatch: Can't open database w8_copy (duplicates fileid\", self.nodes[0].loadwallet, 'w8_copy')\n\n        # Fail to load if one wallet is a copy of another, test this twice to make sure that we don't re-introduce #14304\n        assert_raises_rpc_error(-1, \"BerkeleyBatch: Can't open database w8_copy (duplicates fileid\", self.nodes[0].loadwallet, 'w8_copy')\n\n\n        # Fail to load if wallet file is a symlink\n        assert_raises_rpc_error(-4, \"Wallet file verification failed: Invalid -wallet path 'w8_symlink'\", self.nodes[0].loadwallet, 'w8_symlink')\n\n        # Fail to load if a directory is specified that doesn't contain a wallet\n        os.mkdir(wallet_dir('empty_wallet_dir'))\n        assert_raises_rpc_error(-18, \"Directory empty_wallet_dir does not contain a wallet.dat file\", self.nodes[0].loadwallet, 'empty_wallet_dir')\n\n        self.log.info(\"Test dynamic wallet creation.\")\n\n        # Fail to create a wallet if it already exists.\n        assert_raises_rpc_error(-4, \"Wallet w2 already exists.\", self.nodes[0].createwallet, 'w2')\n\n        # Successfully create a wallet with a new name\n        loadwallet_name = self.nodes[0].createwallet('w9')\n        assert_equal(loadwallet_name['name'], 'w9')\n        w9 = node.get_wallet_rpc('w9')\n        assert_equal(w9.getwalletinfo()['walletname'], 'w9')\n\n        assert 'w9' in self.nodes[0].listwallets()\n\n        # Successfully create a wallet using a full path\n        new_wallet_dir = os.path.join(self.options.tmpdir, 'new_walletdir')\n        new_wallet_name = os.path.join(new_wallet_dir, 'w10')\n        loadwallet_name = self.nodes[0].createwallet(new_wallet_name)\n        assert_equal(loadwallet_name['name'], new_wallet_name)\n        w10 = node.get_wallet_rpc(new_wallet_name)\n        assert_equal(w10.getwalletinfo()['walletname'], new_wallet_name)\n\n        assert new_wallet_name in self.nodes[0].listwallets()\n\n        self.log.info(\"Test dynamic wallet unloading\")\n\n        # Test `unloadwallet` errors\n        assert_raises_rpc_error(-1, \"JSON value is not a string as expected\", self.nodes[0].unloadwallet)\n        assert_raises_rpc_error(-18, \"Requested wallet does not exist or is not loaded\", self.nodes[0].unloadwallet, \"dummy\")\n        assert_raises_rpc_error(-18, \"Requested wallet does not exist or is not loaded\", node.get_wallet_rpc(\"dummy\").unloadwallet)\n        assert_raises_rpc_error(-8, \"Cannot unload the requested wallet\", w1.unloadwallet, \"w2\"),\n\n        # Successfully unload the specified wallet name\n        self.nodes[0].unloadwallet(\"w1\")\n        assert 'w1' not in self.nodes[0].listwallets()\n\n        # Successfully unload the wallet referenced by the request endpoint\n        # Also ensure unload works during walletpassphrase timeout\n        w2.encryptwallet('test')\n        w2.walletpassphrase('test', 1)\n        w2.unloadwallet()\n        time.sleep(1.1)\n        assert 'w2' not in self.nodes[0].listwallets()\n\n        # Successfully unload all wallets\n        for wallet_name in self.nodes[0].listwallets():\n            self.nodes[0].unloadwallet(wallet_name)\n        assert_equal(self.nodes[0].listwallets(), [])\n        assert_raises_rpc_error(-32601, \"Method not found (wallet method is disabled because no wallet is loaded)\", self.nodes[0].getwalletinfo)\n\n        # Successfully load a previously unloaded wallet\n        self.nodes[0].loadwallet('w1')\n        assert_equal(self.nodes[0].listwallets(), ['w1'])\n        assert_equal(w1.getwalletinfo()['walletname'], 'w1')\n\n        assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy', 'w9'])\n\n        # Test backing up and restoring wallets\n        self.log.info(\"Test wallet backup\")\n        self.restart_node(0, ['-nowallet'])\n        for wallet_name in wallet_names:\n            self.nodes[0].loadwallet(wallet_name)\n        for wallet_name in wallet_names:\n            rpc = self.nodes[0].get_wallet_rpc(wallet_name)\n            addr = rpc.getnewaddress()\n            backup = os.path.join(self.options.tmpdir, 'backup.dat')\n            rpc.backupwallet(backup)\n            self.nodes[0].unloadwallet(wallet_name)\n            shutil.copyfile(empty_wallet, wallet_file(wallet_name))\n            self.nodes[0].loadwallet(wallet_name)\n            assert_equal(rpc.getaddressinfo(addr)['ismine'], False)\n            self.nodes[0].unloadwallet(wallet_name)\n            shutil.copyfile(backup, wallet_file(wallet_name))\n            self.nodes[0].loadwallet(wallet_name)\n            assert_equal(rpc.getaddressinfo(addr)['ismine'], True)\n\n        # Test .walletlock file is closed\n        self.start_node(1)\n        wallet = os.path.join(self.options.tmpdir, 'my_wallet')\n        self.nodes[0].createwallet(wallet)\n        assert_raises_rpc_error(-4, \"Error initializing wallet database environment\", self.nodes[1].loadwallet, wallet)\n        self.nodes[0].unloadwallet(wallet)\n        self.nodes[1].loadwallet(wallet)\n\n\nif __name__ == '__main__':\n    MultiWalletTest().main()\n"
  },
  {
    "path": "test/functional/wallet_resendwallettransactions.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test that the wallet resends transactions periodically.\"\"\"\nfrom collections import defaultdict\nimport time\n\nfrom test_framework.blocktools import create_block, create_coinbase\nfrom test_framework.messages import ToHex\nfrom test_framework.mininode import P2PInterface, mininode_lock\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import assert_equal, wait_until\n\nclass P2PStoreTxInvs(P2PInterface):\n    def __init__(self):\n        super().__init__()\n        self.tx_invs_received = defaultdict(int)\n\n    def on_inv(self, message):\n        # Store how many times invs have been received for each tx.\n        for i in message.inv:\n            if i.type == 1:\n                # save txid\n                self.tx_invs_received[i.hash] += 1\n\nclass ResendWalletTransactionsTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 1\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        node = self.nodes[0]  # alias\n\n        node.add_p2p_connection(P2PStoreTxInvs())\n\n        self.log.info(\"Create a new transaction and wait until it's broadcast\")\n        txid = int(node.sendtoaddress(node.getnewaddress(), 1), 16)\n\n        # Can take a few seconds due to transaction trickling\n        wait_until(lambda: node.p2p.tx_invs_received[txid] >= 1, lock=mininode_lock)\n\n        # Add a second peer since txs aren't rebroadcast to the same peer (see filterInventoryKnown)\n        node.add_p2p_connection(P2PStoreTxInvs())\n\n        self.log.info(\"Create a block\")\n        # Create and submit a block without the transaction.\n        # Transactions are only rebroadcast if there has been a block at least five minutes\n        # after the last time we tried to broadcast. Use mocktime and give an extra minute to be sure.\n        block_time = int(time.time()) + 6 * 60\n        node.setmocktime(block_time)\n        block = create_block(int(node.getbestblockhash(), 16), create_coinbase(node.getblockchaininfo()['blocks']), block_time)\n        block.nVersion = 3\n        block.rehash()\n        block.solve()\n        node.submitblock(ToHex(block))\n\n        # Transaction should not be rebroadcast\n        node.p2ps[1].sync_with_ping()\n        assert_equal(node.p2ps[1].tx_invs_received[txid], 0)\n\n        self.log.info(\"Transaction should be rebroadcast after 30 minutes\")\n        # Use mocktime and give an extra 5 minutes to be sure.\n        rebroadcast_time = int(time.time()) + 41 * 60\n        node.setmocktime(rebroadcast_time)\n        wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock)\n\nif __name__ == '__main__':\n    ResendWalletTransactionsTest().main()\n"
  },
  {
    "path": "test/functional/wallet_txn_clone.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs.\"\"\"\n\nimport io\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes,\n    disconnect_nodes,\n    sync_blocks,\n)\nfrom test_framework.messages import CTransaction, COIN\n\nclass TxnMallTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def add_options(self, parser):\n        parser.add_argument(\"--mineblock\", dest=\"mine_block\", default=False, action=\"store_true\",\n                            help=\"Test double-spend of 1-confirmed transaction\")\n        parser.add_argument(\"--segwit\", dest=\"segwit\", default=False, action=\"store_true\",\n                            help=\"Test behaviour with SegWit txn (which should fail\")\n\n    def setup_network(self):\n        # Start with split network:\n        super(TxnMallTest, self).setup_network()\n        disconnect_nodes(self.nodes[1], 2)\n        disconnect_nodes(self.nodes[2], 1)\n\n    def run_test(self):\n        # All nodes should start with 1,250 BTC:\n        starting_balance = 1250\n        for i in range(4):\n            assert_equal(self.nodes[i].getbalance(), starting_balance)\n            self.nodes[i].getnewaddress()  # bug workaround, coins generated assigned to first getnewaddress!\n\n        self.nodes[0].settxfee(.001)\n\n        node0_address1 = self.nodes[0].getnewaddress()\n        node0_txid1 = self.nodes[0].sendtoaddress(node0_address1, 1219)\n        node0_tx1 = self.nodes[0].gettransaction(node0_txid1)\n\n        node0_address2 = self.nodes[0].getnewaddress()\n        node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, 29)\n        node0_tx2 = self.nodes[0].gettransaction(node0_txid2)\n\n        assert_equal(self.nodes[0].getbalance(),\n                     starting_balance + node0_tx1[\"fee\"] + node0_tx2[\"fee\"])\n\n        # Coins are sent to node1_address\n        node1_address = self.nodes[1].getnewaddress()\n\n        # Send tx1, and another transaction tx2 that won't be cloned\n        txid1 = self.nodes[0].sendtoaddress(node1_address, 40)\n        txid2 = self.nodes[0].sendtoaddress(node1_address, 20)\n\n        # Construct a clone of tx1, to be malleated\n        rawtx1 = self.nodes[0].getrawtransaction(txid1, 1)\n        clone_inputs = [{\"txid\": rawtx1[\"vin\"][0][\"txid\"], \"vout\": rawtx1[\"vin\"][0][\"vout\"], \"sequence\": rawtx1[\"vin\"][0][\"sequence\"]}]\n        clone_outputs = {rawtx1[\"vout\"][0][\"scriptPubKey\"][\"addresses\"][0]: rawtx1[\"vout\"][0][\"value\"],\n                         rawtx1[\"vout\"][1][\"scriptPubKey\"][\"addresses\"][0]: rawtx1[\"vout\"][1][\"value\"]}\n        clone_locktime = rawtx1[\"locktime\"]\n        clone_raw = self.nodes[0].createrawtransaction(clone_inputs, clone_outputs, clone_locktime)\n\n        # createrawtransaction randomizes the order of its outputs, so swap them if necessary.\n        clone_tx = CTransaction()\n        clone_tx.deserialize(io.BytesIO(bytes.fromhex(clone_raw)))\n        if (rawtx1[\"vout\"][0][\"value\"] == 40 and clone_tx.vout[0].nValue != 40*COIN or rawtx1[\"vout\"][0][\"value\"] != 40 and clone_tx.vout[0].nValue == 40*COIN):\n            (clone_tx.vout[0], clone_tx.vout[1]) = (clone_tx.vout[1], clone_tx.vout[0])\n\n        # Use a different signature hash type to sign.  This creates an equivalent but malleated clone.\n        # Don't send the clone anywhere yet\n        tx1_clone = self.nodes[0].signrawtransaction(clone_tx.serialize().hex(), None, \"ALL|ANYONECANPAY\")\n        assert_equal(tx1_clone[\"complete\"], True)\n\n        # Have node0 mine a block, if requested:\n        if (self.options.mine_block):\n            self.nodes[0].generate(1)\n            sync_blocks(self.nodes[0:2])\n\n        tx1 = self.nodes[0].gettransaction(txid1)\n        tx2 = self.nodes[0].gettransaction(txid2)\n\n        # Node0's balance should be starting balance, plus 50BTC for another\n        # matured block, minus tx1 and tx2 amounts, and minus transaction fees:\n        expected = starting_balance + node0_tx1[\"fee\"] + node0_tx2[\"fee\"]\n        if self.options.mine_block:\n            expected += 50\n        expected += tx1[\"amount\"] + tx1[\"fee\"]\n        expected += tx2[\"amount\"] + tx2[\"fee\"]\n        assert_equal(self.nodes[0].getbalance(), expected)\n\n        if self.options.mine_block:\n            assert_equal(tx1[\"confirmations\"], 1)\n            assert_equal(tx2[\"confirmations\"], 1)\n        else:\n            assert_equal(tx1[\"confirmations\"], 0)\n            assert_equal(tx2[\"confirmations\"], 0)\n\n        # Send clone and its parent to miner\n        self.nodes[2].sendrawtransaction(node0_tx1[\"hex\"])\n        txid1_clone = self.nodes[2].sendrawtransaction(tx1_clone[\"hex\"])\n        if self.options.segwit:\n            assert_equal(txid1, txid1_clone)\n            return\n\n        # ... mine a block...\n        self.nodes[2].generate(1)\n\n        # Reconnect the split network, and sync chain:\n        connect_nodes(self.nodes[1], 2)\n        self.nodes[2].sendrawtransaction(node0_tx2[\"hex\"])\n        self.nodes[2].sendrawtransaction(tx2[\"hex\"])\n        self.nodes[2].generate(1)  # Mine another block to make sure we sync\n        sync_blocks(self.nodes)\n\n        # Re-fetch transaction info:\n        tx1 = self.nodes[0].gettransaction(txid1)\n        tx1_clone = self.nodes[0].gettransaction(txid1_clone)\n        tx2 = self.nodes[0].gettransaction(txid2)\n\n        # Verify expected confirmations\n        assert_equal(tx1[\"confirmations\"], -2)\n        assert_equal(tx1_clone[\"confirmations\"], 2)\n        assert_equal(tx2[\"confirmations\"], 1)\n\n        # Check node0's total balance; should be same as before the clone, + 100 BTC for 2 matured,\n        # less possible orphaned matured subsidy\n        expected += 100\n        if (self.options.mine_block):\n            expected -= 50\n        assert_equal(self.nodes[0].getbalance(), expected)\n\nif __name__ == '__main__':\n    TxnMallTest().main()\n"
  },
  {
    "path": "test/functional/wallet_txn_doublespend.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the wallet accounts properly when there is a double-spend conflict.\"\"\"\nfrom decimal import Decimal\n\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    connect_nodes,\n    disconnect_nodes,\n    find_output,\n    sync_blocks,\n)\n\nclass TxnMallTest(MuntTestFramework):\n    def set_test_params(self):\n        self.num_nodes = 4\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def add_options(self, parser):\n        parser.add_argument(\"--mineblock\", dest=\"mine_block\", default=False, action=\"store_true\",\n                            help=\"Test double-spend of 1-confirmed transaction\")\n\n    def setup_network(self):\n        # Start with split network:\n        super().setup_network()\n        disconnect_nodes(self.nodes[1], 2)\n        disconnect_nodes(self.nodes[2], 1)\n\n    def run_test(self):\n        # All nodes should start with 1,250 BTC:\n        starting_balance = 1250\n\n        # All nodes should be out of IBD.\n        # If the nodes are not all out of IBD, that can interfere with\n        # blockchain sync later in the test when nodes are connected, due to\n        # timing issues.\n        for n in self.nodes:\n            assert n.getblockchaininfo()[\"initialblockdownload\"] == False\n\n        for i in range(4):\n            assert_equal(self.nodes[i].getbalance(), starting_balance)\n            self.nodes[i].getnewaddress(\"\")  # bug workaround, coins generated assigned to first getnewaddress!\n\n        # Assign coins to foo and bar addresses:\n        node0_address_foo = self.nodes[0].getnewaddress()\n        fund_foo_txid = self.nodes[0].sendtoaddress(node0_address_foo, 1219)\n        fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid)\n\n        node0_address_bar = self.nodes[0].getnewaddress()\n        fund_bar_txid = self.nodes[0].sendtoaddress(node0_address_bar, 29)\n        fund_bar_tx = self.nodes[0].gettransaction(fund_bar_txid)\n\n        assert_equal(self.nodes[0].getbalance(),\n                     starting_balance + fund_foo_tx[\"fee\"] + fund_bar_tx[\"fee\"])\n\n        # Coins are sent to node1_address\n        node1_address = self.nodes[1].getnewaddress()\n\n        # First: use raw transaction API to send 1240 BTC to node1_address,\n        # but don't broadcast:\n        doublespend_fee = Decimal('-.02')\n        rawtx_input_0 = {}\n        rawtx_input_0[\"txid\"] = fund_foo_txid\n        rawtx_input_0[\"vout\"] = find_output(self.nodes[0], fund_foo_txid, 1219)\n        rawtx_input_1 = {}\n        rawtx_input_1[\"txid\"] = fund_bar_txid\n        rawtx_input_1[\"vout\"] = find_output(self.nodes[0], fund_bar_txid, 29)\n        inputs = [rawtx_input_0, rawtx_input_1]\n        change_address = self.nodes[0].getnewaddress()\n        outputs = {}\n        outputs[node1_address] = 1240\n        outputs[change_address] = 1248 - 1240 + doublespend_fee\n        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)\n        doublespend = self.nodes[0].signrawtransaction(rawtx)\n        assert_equal(doublespend[\"complete\"], True)\n\n        # Create two spends using 1 50 BTC coin each\n        txid1 = self.nodes[0].sendtoaddress(node1_address, 40)\n        txid2 = self.nodes[0].sendtoaddress(node1_address, 20)\n\n        # Have node0 mine a block:\n        if (self.options.mine_block):\n            self.nodes[0].generate(1)\n            sync_blocks(self.nodes[0:2])\n\n        tx1 = self.nodes[0].gettransaction(txid1)\n        tx2 = self.nodes[0].gettransaction(txid2)\n\n        # Node0's balance should be starting balance, plus 50BTC for another\n        # matured block, minus 40, minus 20, and minus transaction fees:\n        expected = starting_balance + fund_foo_tx[\"fee\"] + fund_bar_tx[\"fee\"]\n        if self.options.mine_block:\n            expected += 50\n        expected += tx1[\"amount\"] + tx1[\"fee\"]\n        expected += tx2[\"amount\"] + tx2[\"fee\"]\n        assert_equal(self.nodes[0].getbalance(), expected)\n\n        if self.options.mine_block:\n            assert_equal(tx1[\"confirmations\"], 1)\n            assert_equal(tx2[\"confirmations\"], 1)\n            # Node1's balance should be both transaction amounts:\n            assert_equal(self.nodes[1].getbalance(), starting_balance - tx1[\"amount\"] - tx2[\"amount\"])\n        else:\n            assert_equal(tx1[\"confirmations\"], 0)\n            assert_equal(tx2[\"confirmations\"], 0)\n\n        # Now give doublespend and its parents to miner:\n        self.nodes[2].sendrawtransaction(fund_foo_tx[\"hex\"])\n        self.nodes[2].sendrawtransaction(fund_bar_tx[\"hex\"])\n        doublespend_txid = self.nodes[2].sendrawtransaction(doublespend[\"hex\"])\n        # ... mine a block...\n        self.nodes[2].generate(1)\n\n        # Reconnect the split network, and sync chain:\n        connect_nodes(self.nodes[1], 2)\n        self.nodes[2].generate(1)  # Mine another block to make sure we sync\n        sync_blocks(self.nodes)\n        assert_equal(self.nodes[0].gettransaction(doublespend_txid)[\"confirmations\"], 2)\n\n        # Re-fetch transaction info:\n        tx1 = self.nodes[0].gettransaction(txid1)\n        tx2 = self.nodes[0].gettransaction(txid2)\n\n        # Both transactions should be conflicted\n        assert_equal(tx1[\"confirmations\"], -2)\n        assert_equal(tx2[\"confirmations\"], -2)\n\n        # Node0's total balance should be starting balance, plus 100BTC for\n        # two more matured blocks, minus 1240 for the double-spend, plus fees (which are\n        # negative):\n        expected = starting_balance + 100 - 1240 + fund_foo_tx[\"fee\"] + fund_bar_tx[\"fee\"] + doublespend_fee\n        assert_equal(self.nodes[0].getbalance(), expected)\n\n        # Node1's balance should be its initial balance (1250 for 25 block rewards) plus the doublespend:\n        assert_equal(self.nodes[1].getbalance(), 1250 + 1240)\n\nif __name__ == '__main__':\n    TxnMallTest().main()\n"
  },
  {
    "path": "test/functional/wallet_zapwallettxes.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2014-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test the zapwallettxes functionality.\n\n- start two Munt-daemon nodes\n- create two transactions on node 0 - one is confirmed and one is unconfirmed.\n- restart node 0 and verify that both the confirmed and the unconfirmed\n  transactions are still available.\n- restart node 0 with zapwallettxes and persistmempool, and verify that both\n  the confirmed and the unconfirmed transactions are still available.\n- restart node 0 with just zapwallettxes and verify that the confirmed\n  transactions are still available, but that the unconfirmed transaction has\n  been zapped.\n\"\"\"\nfrom test_framework.test_framework import MuntTestFramework\nfrom test_framework.util import (\n    assert_equal,\n    assert_raises_rpc_error,\n    wait_until,\n)\n\nclass ZapWalletTXesTest (MuntTestFramework):\n    def set_test_params(self):\n        self.setup_clean_chain = True\n        self.num_nodes = 2\n        self.rpc_timeout = 180\n\n    def skip_test_if_missing_module(self):\n        self.skip_if_no_wallet()\n\n    def run_test(self):\n        self.log.info(\"Mining blocks...\")\n        self.nodes[0].generate(1)\n        self.sync_all()\n        self.nodes[1].generate(100)\n        self.sync_all()\n\n        # This transaction will be confirmed\n        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10)\n\n        self.nodes[0].generate(1)\n        self.sync_all()\n\n        # This transaction will not be confirmed\n        txid2 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 20)\n\n        # Confirmed and unconfirmed transactions are now in the wallet.\n        assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)\n        assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)\n\n        # Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet.\n        self.stop_node(0)\n        self.start_node(0)\n\n        assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)\n        assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)\n\n        # Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed\n        # transaction is zapped from the wallet, but is re-added when the mempool is reloaded.\n        self.stop_node(0)\n        self.start_node(0, [\"-persistmempool=1\", \"-zapwallettxes=2\"])\n\n        wait_until(lambda: self.nodes[0].getmempoolinfo()['size'] == 1, timeout=3)\n        ###self.nodes[0].syncwithvalidationinterfacequeue()  # Flush mempool to wallet\n\n        assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)\n        assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)\n\n        # Stop node0 and restart with zapwallettxes, but not persistmempool.\n        # The unconfirmed transaction is zapped and is no longer in the wallet.\n        self.stop_node(0)\n        self.start_node(0, [\"-persistmempool=0\", \"-zapwallettxes=2\"])\n\n        # tx1 is still be available because it was confirmed\n        assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)\n\n        # This will raise an exception because the unconfirmed transaction has been zapped\n        assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2)\n\nif __name__ == '__main__':\n    ZapWalletTXesTest().main()\n"
  },
  {
    "path": "test/fuzz/test_runner.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Run fuzz test targets.\n\"\"\"\n\nimport argparse\nimport configparser\nimport os\nimport sys\nimport subprocess\nimport logging\n\n\ndef main():\n    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)\n    parser.add_argument(\n        \"-l\",\n        \"--loglevel\",\n        dest=\"loglevel\",\n        default=\"INFO\",\n        help=\"log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console.\",\n    )\n    parser.add_argument(\n        '--export_coverage',\n        action='store_true',\n        help='If true, export coverage information to files in the seed corpus',\n    )\n    parser.add_argument(\n        'seed_dir',\n        help='The seed corpus to run on (must contain subfolders for each fuzz target).',\n    )\n    parser.add_argument(\n        'target',\n        nargs='*',\n        help='The target(s) to run. Default is to run all targets.',\n    )\n\n    args = parser.parse_args()\n\n    # Set up logging\n    logging.basicConfig(\n        format='%(message)s',\n        level=int(args.loglevel) if args.loglevel.isdigit() else args.loglevel.upper(),\n    )\n\n    # Read config generated by configure.\n    config = configparser.ConfigParser()\n    configfile = os.path.abspath(os.path.dirname(__file__)) + \"/../config.ini\"\n    config.read_file(open(configfile, encoding=\"utf8\"))\n\n    if not config[\"components\"].getboolean(\"ENABLE_FUZZ\"):\n        logging.error(\"Must have fuzz targets built\")\n        sys.exit(1)\n\n    # Build list of tests\n    test_list_all = parse_test_list(makefile=os.path.join(config[\"environment\"][\"SRCDIR\"], 'src', 'Makefile.test.include'))\n\n    if not test_list_all:\n        logging.error(\"No fuzz targets found\")\n        sys.exit(1)\n\n    logging.info(\"Fuzz targets found: {}\".format(test_list_all))\n\n    args.target = args.target or test_list_all  # By default run all\n    test_list_error = list(set(args.target).difference(set(test_list_all)))\n    if test_list_error:\n        logging.error(\"Unknown fuzz targets selected: {}\".format(test_list_error))\n    test_list_selection = list(set(test_list_all).intersection(set(args.target)))\n    if not test_list_selection:\n        logging.error(\"No fuzz targets selected\")\n    logging.info(\"Fuzz targets selected: {}\".format(test_list_selection))\n\n    try:\n        help_output = subprocess.run(\n            args=[\n                os.path.join(config[\"environment\"][\"BUILDDIR\"], 'src', 'test', 'fuzz', test_list_selection[0]),\n                '-help=1',\n            ],\n            timeout=1,\n            check=True,\n            stderr=subprocess.PIPE,\n            universal_newlines=True,\n        ).stderr\n        if \"libFuzzer\" not in help_output:\n            logging.error(\"Must be built with libFuzzer\")\n            sys.exit(1)\n    except subprocess.TimeoutExpired:\n        logging.error(\"subprocess timed out: Currently only libFuzzer is supported\")\n        sys.exit(1)\n\n    run_once(\n        corpus=args.seed_dir,\n        test_list=test_list_selection,\n        build_dir=config[\"environment\"][\"BUILDDIR\"],\n        export_coverage=args.export_coverage,\n    )\n\n\ndef run_once(*, corpus, test_list, build_dir, export_coverage):\n    for t in test_list:\n        args = [\n            os.path.join(build_dir, 'src', 'test', 'fuzz', t),\n            '-runs=1',\n            os.path.join(corpus, t),\n        ]\n        logging.debug('Run {} with args {}'.format(t, args))\n        output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr\n        logging.debug('Output: {}'.format(output))\n        if not export_coverage:\n            continue\n        for l in output.splitlines():\n            if 'INITED' in l:\n                with open(os.path.join(corpus, t + '_coverage'), 'w', encoding='utf-8') as cov_file:\n                    cov_file.write(l)\n                    break\n\n\ndef parse_test_list(makefile):\n    with open(makefile, encoding='utf-8') as makefile_test:\n        test_list_all = []\n        read_targets = False\n        for line in makefile_test.readlines():\n            line = line.strip().replace('test/fuzz/', '').replace(' \\\\', '')\n            if read_targets:\n                if not line:\n                    break\n                test_list_all.append(line)\n                continue\n\n            if line == 'FUZZ_TARGETS =':\n                read_targets = True\n    return test_list_all\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "test/lint/README.md",
    "content": "This folder contains lint scripts.\n\ncheck-doc.py\n============\nCheck for missing documentation of command line options.\n\ncommit-script-check.sh\n======================\nVerification of [scripted diffs](/doc/developer-notes.md#scripted-diffs).\nScripted diffs are only assumed to run on the latest LTS release of Ubuntu. Running them on other operating systems\nmight require installing GNU tools, such as GNU sed.\n\ngit-subtree-check.sh\n====================\nRun this script from the root of the repository to verify that a subtree matches the contents of\nthe commit it claims to have been updated to.\n\n```\nUsage: test/lint/git-subtree-check.sh [-r] DIR [COMMIT]\n       test/lint/git-subtree-check.sh -?\n```\n\n- `DIR` is the prefix within the repository to check.\n- `COMMIT` is the commit to check, if it is not provided, HEAD will be used.\n- `-r` checks that subtree commit is present in repository.\n\nTo do a full check with `-r`, make sure that you have fetched the upstream repository branch in which the subtree is\nmaintained:\n* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)\n* for `src/leveldb`: https://github.com/bitcoin-core/leveldb-subtree.git (branch bitcoin-fork)\n* for `src/univalue`: https://github.com/bitcoin-core/univalue-subtree.git (branch master)\n* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)\n* for `src/crc32c`: https://github.com/bitcoin-core/crc32c-subtree.git (branch bitcoin-fork)\n* for `src/minisketch`: https://github.com/sipa/minisketch.git (branch master)\n\nTo do so, add the upstream repository as remote:\n\n```\ngit remote add --fetch secp256k1 https://github.com/bitcoin-core/secp256k1.git\n```\n\nlint-all.sh\n===========\nCalls other scripts with the `lint-` prefix.\n"
  },
  {
    "path": "test/lint/check-doc.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2020 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n'''\nThis checks if all command line args are documented.\nReturn value is 0 to indicate no error.\n\nAuthor: @MarcoFalke\n'''\n\nfrom subprocess import check_output\nimport re\n\nFOLDER_GREP = 'src'\nFOLDER_TEST = 'src/test/'\nREGEX_ARG = r'(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\\(\"(-[^\"]+)\"'\nREGEX_DOC = r'AddArg\\(\"(-[^\"=]+?)(?:=|\")'\nCMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP)\nCMD_GREP_ARGS = r\"git grep --perl-regexp '{}' -- {} ':(exclude){}'\".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)\nCMD_GREP_WALLET_ARGS = r\"git grep --function-context 'void WalletInit::AddWalletOptions' -- {} | grep AddArg\".format(CMD_ROOT_DIR)\nCMD_GREP_WALLET_HIDDEN_ARGS = r\"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}\".format(CMD_ROOT_DIR)\nCMD_GREP_DOCS = r\"git grep --perl-regexp '{}' {}\".format(REGEX_DOC, CMD_ROOT_DIR)\n# list unsupported, deprecated and duplicate args as they need no documentation\nSET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb', '-zapwallettxes'])\n\n\ndef lint_missing_argument_documentation():\n    used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip()\n    docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip()\n\n    args_used = set(re.findall(re.compile(REGEX_ARG), used))\n    args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)\n    args_need_doc = args_used.difference(args_docd)\n    args_unknown = args_docd.difference(args_used)\n\n    print(\"Args used        : {}\".format(len(args_used)))\n    print(\"Args documented  : {}\".format(len(args_docd)))\n    print(\"Args undocumented: {}\".format(len(args_need_doc)))\n    print(args_need_doc)\n    print(\"Args unknown     : {}\".format(len(args_unknown)))\n    print(args_unknown)\n\n    assert 0 == len(args_need_doc), \"Please document the following arguments: {}\".format(args_need_doc)\n\n\ndef lint_missing_hidden_wallet_args():\n    wallet_args = check_output(CMD_GREP_WALLET_ARGS, shell=True).decode('utf8').strip()\n    wallet_hidden_args = check_output(CMD_GREP_WALLET_HIDDEN_ARGS, shell=True).decode('utf8').strip()\n\n    wallet_args = set(re.findall(re.compile(REGEX_DOC), wallet_args))\n    wallet_hidden_args = set(re.findall(re.compile(r'    \"([^\"=]+)'), wallet_hidden_args))\n\n    hidden_missing = wallet_args.difference(wallet_hidden_args)\n    if hidden_missing:\n        assert 0, \"Please add {} to the hidden args in DummyWalletInit::AddWalletOptions\".format(hidden_missing)\n\n\ndef main():\n    lint_missing_argument_documentation()\n    lint_missing_hidden_wallet_args()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/lint/check-rpc-mappings.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2017-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Check RPC argument consistency.\"\"\"\n\nfrom collections import defaultdict\nimport os\nimport re\nimport sys\n\n# Source files (relative to root) to scan for dispatch tables\nSOURCES = [\n    \"src/rpc/server.cpp\",\n    \"src/rpc/blockchain.cpp\",\n    \"src/rpc/mining.cpp\",\n    \"src/rpc/misc.cpp\",\n    \"src/rpc/net.cpp\",\n    \"src/rpc/rawtransaction.cpp\",\n    \"src/wallet/rpcwallet.cpp\",\n]\n# Source file (relative to root) containing conversion mapping\nSOURCE_CLIENT = 'src/rpc/client.cpp'\n# Argument names that should be ignored in consistency checks\nIGNORE_DUMMY_ARGS = {'dummy', 'arg0', 'arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6', 'arg7', 'arg8', 'arg9'}\n\nclass RPCCommand:\n    def __init__(self, name, args):\n        self.name = name\n        self.args = args\n\nclass RPCArgument:\n    def __init__(self, names, idx):\n        self.names = names\n        self.idx = idx\n        self.convert = False\n\ndef parse_string(s):\n    assert s[0] == '\"'\n    assert s[-1] == '\"'\n    return s[1:-1]\n\ndef process_commands(fname):\n    \"\"\"Find and parse dispatch table in implementation file `fname`.\"\"\"\n    cmds = []\n    in_rpcs = False\n    with open(fname, \"r\", encoding=\"utf8\") as f:\n        for line in f:\n            line = line.rstrip()\n            if not in_rpcs:\n                if re.match(\"static const CRPCCommand .*\\[\\] =\", line):\n                    in_rpcs = True\n            else:\n                if line.startswith('};'):\n                    in_rpcs = False\n                elif '{' in line and '\"' in line:\n                    m = re.search('{ *(\"[^\"]*\"), *(\"[^\"]*\"), *&([^,]*), *{([^}]*)} *},', line)\n                    assert m, 'No match to table expression: %s' % line\n                    name = parse_string(m.group(2))\n                    args_str = m.group(4).strip()\n                    if args_str:\n                        args = [RPCArgument(parse_string(x.strip()).split('|'), idx) for idx, x in enumerate(args_str.split(','))]\n                    else:\n                        args = []\n                    cmds.append(RPCCommand(name, args))\n    assert not in_rpcs and cmds, \"Something went wrong with parsing the C++ file: update the regexps\"\n    return cmds\n\ndef process_mapping(fname):\n    \"\"\"Find and parse conversion table in implementation file `fname`.\"\"\"\n    cmds = []\n    in_rpcs = False\n    with open(fname, \"r\", encoding=\"utf8\") as f:\n        for line in f:\n            line = line.rstrip()\n            if not in_rpcs:\n                if line == 'static const CRPCConvertParam vRPCConvertParams[] =':\n                    in_rpcs = True\n            else:\n                if line.startswith('};'):\n                    in_rpcs = False\n                elif '{' in line and '\"' in line:\n                    m = re.search('{ *(\"[^\"]*\"), *([0-9]+) *, *(\"[^\"]*\") *},', line)\n                    assert m, 'No match to table expression: %s' % line\n                    name = parse_string(m.group(1))\n                    idx = int(m.group(2))\n                    argname = parse_string(m.group(3))\n                    cmds.append((name, idx, argname))\n    assert not in_rpcs and cmds\n    return cmds\n\ndef main():\n    if len(sys.argv) != 2:\n        print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr)\n        sys.exit(1)\n\n    root = sys.argv[1]\n\n    # Get all commands from dispatch tables\n    cmds = []\n    for fname in SOURCES:\n        cmds += process_commands(os.path.join(root, fname))\n\n    cmds_by_name = {}\n    for cmd in cmds:\n        cmds_by_name[cmd.name] = cmd\n\n    # Get current convert mapping for client\n    client = SOURCE_CLIENT\n    mapping = set(process_mapping(os.path.join(root, client)))\n\n    print('* Checking consistency between dispatch tables and vRPCConvertParams')\n\n    # Check mapping consistency\n    errors = 0\n    for (cmdname, argidx, argname) in mapping:\n        try:\n            rargnames = cmds_by_name[cmdname].args[argidx].names\n        except IndexError:\n            print('ERROR: %s argument %i (named %s in vRPCConvertParams) is not defined in dispatch table' % (cmdname, argidx, argname))\n            errors += 1\n            continue\n        if argname not in rargnames:\n            print('ERROR: %s argument %i is named %s in vRPCConvertParams but %s in dispatch table' % (cmdname, argidx, argname, rargnames), file=sys.stderr)\n            errors += 1\n\n    # Check for conflicts in vRPCConvertParams conversion\n    # All aliases for an argument must either be present in the\n    # conversion table, or not. Anything in between means an oversight\n    # and some aliases won't work.\n    for cmd in cmds:\n        for arg in cmd.args:\n            convert = [((cmd.name, arg.idx, argname) in mapping) for argname in arg.names]\n            if any(convert) != all(convert):\n                print('ERROR: %s argument %s has conflicts in vRPCConvertParams conversion specifier %s' % (cmd.name, arg.names, convert))\n                errors += 1\n            arg.convert = all(convert)\n\n    # Check for conversion difference by argument name.\n    # It is preferable for API consistency that arguments with the same name\n    # have the same conversion, so bin by argument name.\n    all_methods_by_argname = defaultdict(list)\n    converts_by_argname = defaultdict(list)\n    for cmd in cmds:\n        for arg in cmd.args:\n            for argname in arg.names:\n                all_methods_by_argname[argname].append(cmd.name)\n                converts_by_argname[argname].append(arg.convert)\n\n    for argname, convert in converts_by_argname.items():\n        if all(convert) != any(convert):\n            if argname in IGNORE_DUMMY_ARGS:\n                # these are testing or dummy, don't warn for them\n                continue\n            print('WARNING: conversion mismatch for argument named %s (%s)' %\n                  (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))\n\n    sys.exit(errors > 0)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "test/lint/commit-script-check.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2017-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\n# This simple script checks for commits beginning with: scripted-diff:\n# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and\n# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the\n# commit message.\n\n# The resulting script should exactly transform the previous commit into the current\n# one. Any remaining diff signals an error.\n\nexport LC_ALL=C\nif test -z \"$1\"; then\n    echo \"Usage: $0 <commit>...\"\n    exit 1\nfi\n\nif ! sed --help 2>&1 | grep -q 'GNU'; then\n    echo \"Error: the installed sed package is not compatible. Please make sure you have GNU sed installed in your system.\";\n    exit 1;\nfi\n\nRET=0\nPREV_BRANCH=$(git name-rev --name-only HEAD)\nPREV_HEAD=$(git rev-parse HEAD)\nfor commit in $(git rev-list --reverse \"$1\"); do\n    if git rev-list -n 1 --pretty=\"%s\" \"$commit\" | grep -q \"^scripted-diff:\"; then\n        git checkout --quiet \"$commit\"^ || exit\n        SCRIPT=\"$(git rev-list --format=%b -n1 \"$commit\" | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d')\"\n        if test -z \"$SCRIPT\"; then\n            echo \"Error: missing script for: $commit\"\n            echo \"Failed\"\n            RET=1\n        else\n            echo \"Running script for: $commit\"\n            echo \"$SCRIPT\"\n            (eval \"$SCRIPT\")\n            git --no-pager diff --exit-code \"$commit\" && echo \"OK\" || (echo \"Failed\"; false) || RET=1\n        fi\n        git reset --quiet --hard HEAD\n     else\n        if git rev-list \"--format=%b\" -n1 \"$commit\" | grep -q '^-\\(BEGIN\\|END\\)[ a-zA-Z]*-$'; then\n            echo \"Error: script block marker but no scripted-diff in title of commit $commit\"\n            echo \"Failed\"\n            RET=1\n        fi\n    fi\ndone\ngit checkout --quiet \"$PREV_BRANCH\" 2>/dev/null || git checkout --quiet \"$PREV_HEAD\"\nexit $RET\n"
  },
  {
    "path": "test/lint/git-subtree-check.sh",
    "content": "#!/bin/sh\n# Copyright (c) 2015-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nexport LC_ALL=C\n\ncheck_remote=0\nwhile getopts \"?hr\" opt; do\n  case $opt in\n    '?' | h)\n      echo \"Usage: $0 [-r] DIR [COMMIT]\"\n      echo \"       $0 -?\"\n      echo \"\"\n      echo \"Checks that a certain prefix is pure subtree, and optionally whether the\"\n      echo \"referenced commit is present in any fetched remote.\"\n      echo \"\"\n      echo \"DIR is the prefix within the repository to check.\"\n      echo \"COMMIT is the commit to check, if it is not provided, HEAD will be used.\"\n      echo \"\"\n      echo \"-r      Check that subtree commit is present in repository.\"\n      echo \"        To do this check, fetch the subtreed remote first. Example:\"\n      echo \"\"\n      echo \"            git fetch https://github.com/bitcoin-core/secp256k1.git\"\n      echo \"            test/lint/git-subtree-check.sh -r src/secp256k1\"\n      exit 1\n    ;;\n    r)\n      check_remote=1\n    ;;\n  esac\ndone\nshift $((OPTIND-1))\n\nif [ -z \"$1\" ]; then\n    echo \"Need to provide a DIR, see $0 -?\"\n    exit 1\nfi\n\n# Strip trailing / from directory path (in case it was added by autocomplete)\nDIR=\"${1%/}\"\nCOMMIT=\"$2\"\nif [ -z \"$COMMIT\" ]; then\n    COMMIT=HEAD\nfi\n\n# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>)\nfind_latest_squash()\n{\n\tdir=\"$1\"\n\tsq=\n\tmain=\n\tsub=\n\tgit log --grep=\"^git-subtree-dir: $dir/*\\$\" \\\n\t\t--pretty=format:'START %H%n%s%n%n%b%nEND%n' \"$COMMIT\" |\n\twhile read a b _; do\n\t\tcase \"$a\" in\n\t\t\tSTART) sq=\"$b\" ;;\n\t\t\tgit-subtree-mainline:) main=\"$b\" ;;\n\t\t\tgit-subtree-split:) sub=\"$b\" ;;\n\t\t\tEND)\n\t\t\t\tif [ -n \"$sub\" ]; then\n\t\t\t\t\tif [ -n \"$main\" ]; then\n\t\t\t\t\t\t# a rejoin commit?\n\t\t\t\t\t\t# Pretend its sub was a squash.\n\t\t\t\t\t\tsq=\"$sub\"\n\t\t\t\t\tfi\n\t\t\t\t\techo \"$sq\" \"$sub\"\n\t\t\t\t\tbreak\n\t\t\t\tfi\n\t\t\t\tsq=\n\t\t\t\tmain=\n\t\t\t\tsub=\n\t\t\t\t;;\n\t\tesac\n\tdone\n}\n\n# find latest subtree update\nlatest_squash=\"$(find_latest_squash \"$DIR\")\"\nif [ -z \"$latest_squash\" ]; then\n    echo \"ERROR: $DIR is not a subtree\" >&2\n    exit 2\nfi\n# shellcheck disable=SC2086\nset $latest_squash\nold=$1\nrev=$2\n\n# get the tree in the current commit\ntree_actual=$(git ls-tree -d \"$COMMIT\" \"$DIR\" | head -n 1)\nif [ -z \"$tree_actual\" ]; then\n    echo \"FAIL: subtree directory $DIR not found in $COMMIT\" >&2\n    exit 1\nfi\n# shellcheck disable=SC2086\nset $tree_actual\ntree_actual_type=$2\ntree_actual_tree=$3\necho \"$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree\"\nif [ \"d$tree_actual_type\" != \"dtree\" ]; then\n    echo \"FAIL: subtree directory $DIR is not a tree in $COMMIT\" >&2\n    exit 1\nfi\n\n# get the tree at the time of the last subtree update\ntree_commit=$(git show -s --format=\"%T\" \"$old\")\necho \"$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)\"\n\n# ... and compare the actual tree with it\nif [ \"$tree_actual_tree\" != \"$tree_commit\" ]; then\n    git diff \"$tree_commit\" \"$tree_actual_tree\" >&2\n    echo \"FAIL: subtree directory was touched without subtree merge\" >&2\n    exit 1\nfi\n\nif [ \"$check_remote\" != \"0\" ]; then\n    # get the tree in the subtree commit referred to\n    if [ \"d$(git cat-file -t \"$rev\" 2>/dev/null)\" != dcommit ]; then\n        echo \"subtree commit $rev unavailable: cannot compare. Did you add and fetch the remote?\" >&2\n        exit 1\n    fi\n    tree_subtree=$(git show -s --format=\"%T\" \"$rev\")\n    echo \"$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)\"\n\n    # ... and compare the actual tree with it\n    if [ \"$tree_actual_tree\" != \"$tree_subtree\" ]; then\n        echo \"FAIL: subtree update commit differs from upstream tree!\" >&2\n        exit 1\n    fi\nfi\n\necho \"GOOD\"\n"
  },
  {
    "path": "test/lint/lint-all.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2017-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# This script runs all contrib/devtools/lint-*.sh files, and fails if any exit\n# with a non-zero status code.\n\n# This script is intentionally locale dependent by not setting \"export LC_ALL=C\"\n# in order to allow for the executed lint scripts to opt in or opt out of locale\n# dependence themselves.\n\nset -u\n\nSCRIPTDIR=$(dirname \"${BASH_SOURCE[0]}\")\nLINTALL=$(basename \"${BASH_SOURCE[0]}\")\n\nEXIT_CODE=0\n\nfor f in \"${SCRIPTDIR}\"/lint-*.sh; do\n  if [ \"$(basename \"$f\")\" != \"$LINTALL\" ]; then\n    if ! \"$f\"; then\n      echo \"^---- failure generated from $f\"\n      EXIT_CODE=1\n    fi\n  fi\ndone\n\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-assertions.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2020 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for assertions with obvious side effects.\n\nexport LC_ALL=C\n\nEXIT_CODE=0\n\n# PRE31-C (SEI CERT C Coding Standard):\n# \"Assertions should not contain assignments, increment, or decrement operators.\"\nOUTPUT=$(git grep -E '[^_]assert\\(.*(\\+\\+|\\-\\-|[^=!<>]=[^=!<>]).*\\);' -- \"*.cpp\" \"*.h\")\nif [[ ${OUTPUT} != \"\" ]]; then\n    echo \"Assertions should not have side effects:\"\n    echo\n    echo \"${OUTPUT}\"\n    EXIT_CODE=1\nfi\n\n# Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it\n# is undesirable to crash the whole program. See: src/util/check.h\n# src/rpc/server.cpp is excluded from this check since it's mostly meta-code.\nOUTPUT=$(git grep -nE '\\<(A|a)ssert *\\(.*\\);' -- \"src/rpc/\" \"src/wallet/rpc*\" \":(exclude)src/rpc/server.cpp\")\nif [[ ${OUTPUT} != \"\" ]]; then\n    echo \"CHECK_NONFATAL(condition) should be used instead of assert for RPC code.\"\n    echo\n    echo \"${OUTPUT}\"\n    EXIT_CODE=1\nfi\n\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-circular-dependencies.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for circular dependencies\n\nexport LC_ALL=C\n\nEXPECTED_CIRCULAR_DEPENDENCIES=(\n    \"chainparamsbase -> util/system -> chainparamsbase\"\n    \"node/blockstorage -> validation -> node/blockstorage\"\n    \"index/blockfilterindex -> node/blockstorage -> validation -> index/blockfilterindex\"\n    \"index/base -> validation -> index/blockfilterindex -> index/base\"\n    \"index/coinstatsindex -> node/coinstats -> index/coinstatsindex\"\n    \"policy/fees -> txmempool -> policy/fees\"\n    \"wallet/fees -> wallet/wallet -> wallet/fees\"\n    \"wallet/wallet -> wallet/walletdb -> wallet/wallet\"\n    \"node/coinstats -> validation -> node/coinstats\"\n)\n\nEXIT_CODE=0\n\nCIRCULAR_DEPENDENCIES=()\n\nIFS=$'\\n'\nfor CIRC in $(cd src && ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp} | sed -e 's/^Circular dependency: //'); do\n    CIRCULAR_DEPENDENCIES+=( \"$CIRC\" )\n    IS_EXPECTED_CIRC=0\n    for EXPECTED_CIRC in \"${EXPECTED_CIRCULAR_DEPENDENCIES[@]}\"; do\n        if [[ \"${CIRC}\" == \"${EXPECTED_CIRC}\" ]]; then\n            IS_EXPECTED_CIRC=1\n            break\n        fi\n    done\n    if [[ ${IS_EXPECTED_CIRC} == 0 ]]; then\n        echo \"A new circular dependency in the form of \\\"${CIRC}\\\" appears to have been introduced.\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\n\nfor EXPECTED_CIRC in \"${EXPECTED_CIRCULAR_DEPENDENCIES[@]}\"; do\n    IS_PRESENT_EXPECTED_CIRC=0\n    for CIRC in \"${CIRCULAR_DEPENDENCIES[@]}\"; do\n        if [[ \"${CIRC}\" == \"${EXPECTED_CIRC}\" ]]; then\n            IS_PRESENT_EXPECTED_CIRC=1\n            break\n        fi\n    done\n    if [[ ${IS_PRESENT_EXPECTED_CIRC} == 0 ]]; then\n        echo \"Good job! The circular dependency \\\"${EXPECTED_CIRC}\\\" is no longer present.\"\n        echo \"Please remove it from EXPECTED_CIRCULAR_DEPENDENCIES in $0\"\n        echo \"to make sure this circular dependency is not accidentally reintroduced.\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\n\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-filenames.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Make sure only lowercase alphanumerics (a-z0-9), underscores (_),\n# hyphens (-) and dots (.) are used in source code filenames.\n\nexport LC_ALL=C\n\nEXIT_CODE=0\nOUTPUT=$(git ls-files --full-name -- \"*.[cC][pP][pP]\" \"*.[hH]\" \"*.[pP][yY]\" \"*.[sS][hH]\" | \\\n    grep -vE '^[a-z0-9_./-]+$' | \\\n    grep -vE '^src/(secp256k1|univalue)/')\n\nif [[ ${OUTPUT} != \"\" ]]; then\n    echo \"Use only lowercase alphanumerics (a-z0-9), underscores (_), hyphens (-) and dots (.)\"\n    echo \"in source code filenames:\"\n    echo\n    echo \"${OUTPUT}\"\n    EXIT_CODE=1\nfi\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-format-strings.py",
    "content": "#!/usr/bin/env python3\n#\n# Copyright (c) 2018-2019 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Lint format strings: This program checks that the number of arguments passed\n# to a variadic format string function matches the number of format specifiers\n# in the format string.\n\nimport argparse\nimport re\nimport sys\n\nFALSE_POSITIVES = [\n    (\"src/dbwrapper.cpp\", \"vsnprintf(p, limit - p, format, backup_ap)\"),\n    (\"src/index/base.cpp\", \"FatalError(const char* fmt, const Args&... args)\"),\n    (\"src/netbase.cpp\", \"LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)\"),\n    (\"src/util/system.cpp\", \"strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION)\"),\n    (\"src/validationinterface.cpp\", \"LogPrint(BCLog::VALIDATION, fmt \\\"\\\\n\\\", __VA_ARGS__)\"),\n    (\"src/wallet/wallet.h\",  \"WalletLogPrintf(std::string fmt, Params... parameters)\"),\n    (\"src/wallet/wallet.h\", \"LogPrintf((\\\"%s \\\" + fmt).c_str(), GetDisplayName(), parameters...)\"),\n    (\"src/wallet/scriptpubkeyman.h\",  \"WalletLogPrintf(std::string fmt, Params... parameters)\"),\n    (\"src/wallet/scriptpubkeyman.h\", \"LogPrintf((\\\"%s \\\" + fmt).c_str(), m_storage.GetDisplayName(), parameters...)\"),\n    (\"src/logging.h\", \"LogPrintf(const char* fmt, const Args&... args)\"),\n    (\"src/wallet/scriptpubkeyman.h\", \"WalletLogPrintf(const std::string& fmt, const Params&... parameters)\"),\n]\n\n\ndef parse_function_calls(function_name, source_code):\n    \"\"\"Return an array with all calls to function function_name in string source_code.\n    Preprocessor directives and C++ style comments (\"//\") in source_code are removed.\n\n    >>> len(parse_function_calls(\"foo\", \"foo();bar();foo();bar();\"))\n    2\n    >>> parse_function_calls(\"foo\", \"foo(1);bar(1);foo(2);bar(2);\")[0].startswith(\"foo(1);\")\n    True\n    >>> parse_function_calls(\"foo\", \"foo(1);bar(1);foo(2);bar(2);\")[1].startswith(\"foo(2);\")\n    True\n    >>> len(parse_function_calls(\"foo\", \"foo();bar();// foo();bar();\"))\n    1\n    >>> len(parse_function_calls(\"foo\", \"#define FOO foo();\"))\n    0\n    \"\"\"\n    assert type(function_name) is str and type(source_code) is str and function_name\n    lines = [re.sub(\"// .*\", \" \", line).strip()\n             for line in source_code.split(\"\\n\")\n             if not line.strip().startswith(\"#\")]\n    return re.findall(r\"[^a-zA-Z_](?=({}\\(.*).*)\".format(function_name), \" \" + \" \".join(lines))\n\n\ndef normalize(s):\n    \"\"\"Return a normalized version of string s with newlines, tabs and C style comments (\"/* ... */\")\n    replaced with spaces. Multiple spaces are replaced with a single space.\n\n    >>> normalize(\"  /* nothing */   foo\\tfoo  /* bar */  foo     \")\n    'foo foo foo'\n    \"\"\"\n    assert type(s) is str\n    s = s.replace(\"\\n\", \" \")\n    s = s.replace(\"\\t\", \" \")\n    s = re.sub(r\"/\\*.*?\\*/\", \" \", s)\n    s = re.sub(\" {2,}\", \" \", s)\n    return s.strip()\n\n\nESCAPE_MAP = {\n    r\"\\n\": \"[escaped-newline]\",\n    r\"\\t\": \"[escaped-tab]\",\n    r'\\\"': \"[escaped-quote]\",\n}\n\n\ndef escape(s):\n    \"\"\"Return the escaped version of string s with \"\\\\\\\"\", \"\\\\n\" and \"\\\\t\" escaped as\n    \"[escaped-backslash]\", \"[escaped-newline]\" and \"[escaped-tab]\".\n\n    >>> unescape(escape(\"foo\")) == \"foo\"\n    True\n    >>> escape(r'foo \\\\t foo \\\\n foo \\\\\\\\ foo \\\\ foo \\\\\"bar\\\\\"')\n    'foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\\\\\\\\\ foo \\\\\\\\ foo [escaped-quote]bar[escaped-quote]'\n    \"\"\"\n    assert type(s) is str\n    for raw_value, escaped_value in ESCAPE_MAP.items():\n        s = s.replace(raw_value, escaped_value)\n    return s\n\n\ndef unescape(s):\n    \"\"\"Return the unescaped version of escaped string s.\n    Reverses the replacements made in function escape(s).\n\n    >>> unescape(escape(\"bar\"))\n    'bar'\n    >>> unescape(\"foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\\\\\\\\\ foo \\\\\\\\ foo [escaped-quote]bar[escaped-quote]\")\n    'foo \\\\\\\\t foo \\\\\\\\n foo \\\\\\\\\\\\\\\\ foo \\\\\\\\ foo \\\\\\\\\"bar\\\\\\\\\"'\n    \"\"\"\n    assert type(s) is str\n    for raw_value, escaped_value in ESCAPE_MAP.items():\n        s = s.replace(escaped_value, raw_value)\n    return s\n\n\ndef parse_function_call_and_arguments(function_name, function_call):\n    \"\"\"Split string function_call into an array of strings consisting of:\n    * the string function_call followed by \"(\"\n    * the function call argument #1\n    * ...\n    * the function call argument #n\n    * a trailing \");\"\n\n    The strings returned are in escaped form. See escape(...).\n\n    >>> parse_function_call_and_arguments(\"foo\", 'foo(\"%s\", \"foo\");')\n    ['foo(', '\"%s\",', ' \"foo\"', ')']\n    >>> parse_function_call_and_arguments(\"foo\", 'foo(\"%s\", \"foo\");')\n    ['foo(', '\"%s\",', ' \"foo\"', ')']\n    >>> parse_function_call_and_arguments(\"foo\", 'foo(\"%s %s\", \"foo\", \"bar\");')\n    ['foo(', '\"%s %s\",', ' \"foo\",', ' \"bar\"', ')']\n    >>> parse_function_call_and_arguments(\"fooprintf\", 'fooprintf(\"%050d\", i);')\n    ['fooprintf(', '\"%050d\",', ' i', ')']\n    >>> parse_function_call_and_arguments(\"foo\", 'foo(bar(foobar(barfoo(\"foo\"))), foobar); barfoo')\n    ['foo(', 'bar(foobar(barfoo(\"foo\"))),', ' foobar', ')']\n    >>> parse_function_call_and_arguments(\"foo\", \"foo()\")\n    ['foo(', '', ')']\n    >>> parse_function_call_and_arguments(\"foo\", \"foo(123)\")\n    ['foo(', '123', ')']\n    >>> parse_function_call_and_arguments(\"foo\", 'foo(\"foo\")')\n    ['foo(', '\"foo\"', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);')\n    ['strprintf(', '\"%s (%d)\",', ' std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf),', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo<wchar_t>().to_bytes(buf), err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo<wchar_t>().to_bytes(buf),', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo().to_bytes(buf), err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo().to_bytes(buf),', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo << 1, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo << 1,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo<bar>() >> 1, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo<bar>() >> 1,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo < 1 ? bar : foobar, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo < 1 ? bar : foobar,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo < 1, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo < 1,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo > 1 ? bar : foobar, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo > 1 ? bar : foobar,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo > 1, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo > 1,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo <= 1, err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo <= 1,', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo <= bar<1, 2>(1, 2), err);')\n    ['strprintf(', '\"%s (%d)\",', ' foo <= bar<1, 2>(1, 2),', ' err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo>foo<1,2>(1,2)?bar:foobar,err)');\n    ['strprintf(', '\"%s (%d)\",', ' foo>foo<1,2>(1,2)?bar:foobar,', 'err', ')']\n    >>> parse_function_call_and_arguments(\"strprintf\", 'strprintf(\"%s (%d)\", foo>foo<1,2>(1,2),err)');\n    ['strprintf(', '\"%s (%d)\",', ' foo>foo<1,2>(1,2),', 'err', ')']\n    \"\"\"\n    assert type(function_name) is str and type(function_call) is str and function_name\n    remaining = normalize(escape(function_call))\n    expected_function_call = \"{}(\".format(function_name)\n    assert remaining.startswith(expected_function_call)\n    parts = [expected_function_call]\n    remaining = remaining[len(expected_function_call):]\n    open_parentheses = 1\n    open_template_arguments = 0\n    in_string = False\n    parts.append(\"\")\n    for i, char in enumerate(remaining):\n        parts.append(parts.pop() + char)\n        if char == \"\\\"\":\n            in_string = not in_string\n            continue\n        if in_string:\n            continue\n        if char == \"(\":\n            open_parentheses += 1\n            continue\n        if char == \")\":\n            open_parentheses -= 1\n        if open_parentheses > 1:\n            continue\n        if open_parentheses == 0:\n            parts.append(parts.pop()[:-1])\n            parts.append(char)\n            break\n        prev_char = remaining[i - 1] if i - 1 >= 0 else None\n        next_char = remaining[i + 1] if i + 1 <= len(remaining) - 1 else None\n        if char == \"<\" and next_char not in [\" \", \"<\", \"=\"] and prev_char not in [\" \", \"<\"]:\n            open_template_arguments += 1\n            continue\n        if char == \">\" and next_char not in [\" \", \">\", \"=\"] and prev_char not in [\" \", \">\"] and open_template_arguments > 0:\n            open_template_arguments -= 1\n        if open_template_arguments > 0:\n            continue\n        if char == \",\":\n            parts.append(\"\")\n    return parts\n\n\ndef parse_string_content(argument):\n    \"\"\"Return the text within quotes in string argument.\n\n    >>> parse_string_content('1 \"foo %d bar\" 2')\n    'foo %d bar'\n    >>> parse_string_content('1 foobar 2')\n    ''\n    >>> parse_string_content('1 \"bar\" 2')\n    'bar'\n    >>> parse_string_content('1 \"foo\" 2 \"bar\" 3')\n    'foobar'\n    >>> parse_string_content('1 \"foo\" 2 \" \" \"bar\" 3')\n    'foo bar'\n    >>> parse_string_content('\"\"')\n    ''\n    >>> parse_string_content('')\n    ''\n    >>> parse_string_content('1 2 3')\n    ''\n    \"\"\"\n    assert type(argument) is str\n    string_content = \"\"\n    in_string = False\n    for char in normalize(escape(argument)):\n        if char == \"\\\"\":\n            in_string = not in_string\n        elif in_string:\n            string_content += char\n    return string_content\n\n\ndef count_format_specifiers(format_string):\n    \"\"\"Return the number of format specifiers in string format_string.\n\n    >>> count_format_specifiers(\"foo bar foo\")\n    0\n    >>> count_format_specifiers(\"foo %d bar foo\")\n    1\n    >>> count_format_specifiers(\"foo %d bar %i foo\")\n    2\n    >>> count_format_specifiers(\"foo %d bar %i foo %% foo\")\n    2\n    >>> count_format_specifiers(\"foo %d bar %i foo %% foo %d foo\")\n    3\n    >>> count_format_specifiers(\"foo %d bar %i foo %% foo %*d foo\")\n    4\n    \"\"\"\n    assert type(format_string) is str\n    format_string = format_string.replace('%%', 'X')\n    n = 0\n    in_specifier = False\n    for i, char in enumerate(format_string):\n        if char == \"%\":\n            in_specifier = True\n            n += 1\n        elif char in \"aAcdeEfFgGinopsuxX\":\n            in_specifier = False\n        elif in_specifier and char == \"*\":\n            n += 1\n    return n\n\n\ndef main():\n    parser = argparse.ArgumentParser(description=\"This program checks that the number of arguments passed \"\n                                     \"to a variadic format string function matches the number of format \"\n                                     \"specifiers in the format string.\")\n    parser.add_argument(\"--skip-arguments\", type=int, help=\"number of arguments before the format string \"\n                        \"argument (e.g. 1 in the case of fprintf)\", default=0)\n    parser.add_argument(\"function_name\", help=\"function name (e.g. fprintf)\", default=None)\n    parser.add_argument(\"file\", nargs=\"*\", help=\"C++ source code file (e.g. foo.cpp)\")\n    args = parser.parse_args()\n    exit_code = 0\n    for filename in args.file:\n        with open(filename, \"r\", encoding=\"utf-8\") as f:\n            for function_call_str in parse_function_calls(args.function_name, f.read()):\n                parts = parse_function_call_and_arguments(args.function_name, function_call_str)\n                relevant_function_call_str = unescape(\"\".join(parts))[:512]\n                if (f.name, relevant_function_call_str) in FALSE_POSITIVES:\n                    continue\n                if len(parts) < 3 + args.skip_arguments:\n                    exit_code = 1\n                    print(\"{}: Could not parse function call string \\\"{}(...)\\\": {}\".format(f.name, args.function_name, relevant_function_call_str))\n                    continue\n                argument_count = len(parts) - 3 - args.skip_arguments\n                format_str = parse_string_content(parts[1 + args.skip_arguments])\n                format_specifier_count = count_format_specifiers(format_str)\n                if format_specifier_count != argument_count:\n                    exit_code = 1\n                    print(\"{}: Expected {} argument(s) after format string but found {} argument(s): {}\".format(f.name, format_specifier_count, argument_count, relevant_function_call_str))\n                    continue\n    sys.exit(exit_code)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/lint/lint-format-strings.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2020 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Lint format strings: This program checks that the number of arguments passed\n# to a variadic format string function matches the number of format specifiers\n# in the format string.\n\nexport LC_ALL=C\n\nFUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=(\n    \"FatalError,0\"\n    \"fprintf,1\"\n    \"tfm::format,1\" # Assuming tfm::::format(std::ostream&, ...\n    \"LogConnectFailure,1\"\n    \"LogPrint,1\"\n    \"LogPrintf,0\"\n    \"printf,0\"\n    \"snprintf,2\"\n    \"sprintf,1\"\n    \"strprintf,0\"\n    \"vfprintf,1\"\n    \"vprintf,1\"\n    \"vsnprintf,1\"\n    \"vsprintf,1\"\n    \"WalletLogPrintf,0\"\n)\n\nEXIT_CODE=0\nif ! python3 -m doctest test/lint/lint-format-strings.py; then\n    EXIT_CODE=1\nfi\nfor S in \"${FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS[@]}\"; do\n    IFS=\",\" read -r FUNCTION_NAME SKIP_ARGUMENTS <<< \"${S}\"\n    for MATCHING_FILE in $(git grep --full-name -l \"${FUNCTION_NAME}\" -- \"*.c\" \"*.cpp\" \"*.h\" | sort | grep -vE \"^src/(leveldb|secp256k1|minisketch|tinyformat|univalue|test/fuzz/strprintf.cpp)\"); do\n        MATCHING_FILES+=(\"${MATCHING_FILE}\")\n    done\n    if ! test/lint/lint-format-strings.py --skip-arguments \"${SKIP_ARGUMENTS}\" \"${FUNCTION_NAME}\" \"${MATCHING_FILES[@]}\"; then\n        EXIT_CODE=1\n    fi\ndone\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-include-guards.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check include guards.\n\nexport LC_ALL=C\nHEADER_ID_PREFIX=\"\"\nHEADER_ID_SUFFIX=\"_H\"\n\nREGEXP_EXCLUDE_FILES_WITH_PREFIX=\"src/(crypto/ctaes/|leveldb/|crc32c/|secp256k1/|minisketch/|test/fuzz/FuzzedDataProvider.h|tinyformat.h|bench/nanobench.h|univalue/)\"\n\nEXIT_CODE=0\nfor HEADER_FILE in $(git ls-files -- \"*.h\" | grep -vE \"^${REGEXP_EXCLUDE_FILES_WITH_PREFIX}\")\ndo\n    HEADER_ID_BASE=$(cut -f2- -d/ <<< \"${HEADER_FILE}\" | sed \"s/\\.h$//g\" | tr / _ | tr - _ | tr \"[:lower:]\" \"[:upper:]\")\n    HEADER_ID=\"${HEADER_ID_PREFIX}${HEADER_ID_BASE}${HEADER_ID_SUFFIX}\"\n    if [[ $(grep --count --extended-regexp \"^#(ifndef|define|endif //) ${HEADER_ID}\" \"${HEADER_FILE}\") != 3 ]]; then\n        echo \"${HEADER_FILE} seems to be missing the expected include guard:\"\n        echo \"  #ifndef ${HEADER_ID}\"\n        echo \"  #define ${HEADER_ID}\"\n        echo \"  ...\"\n        echo \"  #endif // ${HEADER_ID}\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-includes.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for duplicate includes.\n# Guard against accidental introduction of new Boost dependencies.\n# Check includes: Check for duplicate includes. Enforce bracket syntax includes.\n\nexport LC_ALL=C\nIGNORE_REGEXP=\"/(leveldb|secp256k1|minisketch|univalue|crc32c)/\"\n\n# cd to root folder of git repo for git ls-files to work properly\ncd \"$(dirname \"$0\")/../..\" || exit 1\n\nfilter_suffix() {\n    git ls-files | grep -E \"^src/.*\\.${1}\"'$' | grep -Ev \"${IGNORE_REGEXP}\"\n}\n\nEXIT_CODE=0\n\nfor HEADER_FILE in $(filter_suffix h); do\n    DUPLICATE_INCLUDES_IN_HEADER_FILE=$(grep -E \"^#include \" < \"${HEADER_FILE}\" | sort | uniq -d)\n    if [[ ${DUPLICATE_INCLUDES_IN_HEADER_FILE} != \"\" ]]; then\n        echo \"Duplicate include(s) in ${HEADER_FILE}:\"\n        echo \"${DUPLICATE_INCLUDES_IN_HEADER_FILE}\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\n\nfor CPP_FILE in $(filter_suffix cpp); do\n    DUPLICATE_INCLUDES_IN_CPP_FILE=$(grep -E \"^#include \" < \"${CPP_FILE}\" | sort | uniq -d)\n    if [[ ${DUPLICATE_INCLUDES_IN_CPP_FILE} != \"\" ]]; then\n        echo \"Duplicate include(s) in ${CPP_FILE}:\"\n        echo \"${DUPLICATE_INCLUDES_IN_CPP_FILE}\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\n\nINCLUDED_CPP_FILES=$(git grep -E \"^#include [<\\\"][^>\\\"]+\\.cpp[>\\\"]\" -- \"*.cpp\" \"*.h\")\nif [[ ${INCLUDED_CPP_FILES} != \"\" ]]; then\n    echo \"The following files #include .cpp files:\"\n    echo \"${INCLUDED_CPP_FILES}\"\n    echo\n    EXIT_CODE=1\nfi\n\nEXPECTED_BOOST_INCLUDES=(\n    boost/algorithm/string.hpp\n    boost/algorithm/string/classification.hpp\n    boost/algorithm/string/replace.hpp\n    boost/algorithm/string/split.hpp\n    boost/date_time/posix_time/posix_time.hpp\n    boost/filesystem.hpp\n    boost/filesystem/fstream.hpp\n    boost/multi_index/sequenced_index.hpp\n    boost/signals2/signal.hpp\n    boost/test/unit_test.hpp\n    boost/accumulators/accumulators.hpp\n    boost/accumulators/statistics/max.hpp\n    boost/accumulators/statistics/mean.hpp\n    boost/accumulators/statistics/median.hpp\n    boost/accumulators/statistics/min.hpp\n    boost/accumulators/statistics/stats.hpp\n    boost/algorithm/string/case_conv.hpp\n    boost/algorithm/string/join.hpp\n    boost/algorithm/string/predicate.hpp\n    boost/asio.hpp\n    boost/asio/thread_pool.hpp\n    boost/assign/list_of.hpp\n    boost/assign/std/vector.hpp\n    boost/bind.hpp\n    boost/bind/bind.hpp\n    boost/chrono/chrono.hpp\n    boost/chrono/thread_clock.hpp\n    boost/container/flat_set.hpp\n    boost/filesystem/detail/utf8_codecvt_facet.hpp\n    boost/foreach.hpp\n    boost/format.hpp\n    boost/interprocess/sync/file_lock.hpp\n    boost/preprocessor/cat.hpp\n    boost/preprocessor/stringize.hpp\n    boost/program_options.hpp\n    boost/program_options/detail/config_file.hpp\n    boost/program_options/parsers.hpp\n    boost/range/adaptor/reversed.hpp\n    boost/range/rbegin.hpp\n    boost/scope_exit.hpp\n    boost/scoped_array.hpp\n    boost/signals2.hpp\n    boost/signals2/last_value.hpp\n    boost/thread.hpp\n    boost/thread/condition_variable.hpp\n    boost/thread/mutex.hpp\n    boost/thread/recursive_mutex.hpp\n    boost/thread/thread.hpp\n    boost/uuid/nil_generator.hpp\n    boost/uuid/random_generator.hpp\n    boost/uuid/string_generator.hpp\n    boost/uuid/uuid.hpp\n    boost/uuid/uuid_io.hpp\n    boost/variant.hpp\n    boost/variant/apply_visitor.hpp\n    boost/variant/static_visitor.hpp\n)\n\nfor BOOST_INCLUDE in $(git grep '^#include <boost/' -- \"*.cpp\" \"*.h\" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do\n    IS_EXPECTED_INCLUDE=0\n    for EXPECTED_BOOST_INCLUDE in \"${EXPECTED_BOOST_INCLUDES[@]}\"; do\n        if [[ \"${BOOST_INCLUDE}\" == \"${EXPECTED_BOOST_INCLUDE}\" ]]; then\n            IS_EXPECTED_INCLUDE=1\n            break\n        fi\n    done\n    if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then\n        EXIT_CODE=1\n        echo \"A new Boost dependency in the form of \\\"${BOOST_INCLUDE}\\\" appears to have been introduced:\"\n        git grep \"${BOOST_INCLUDE}\" -- \"*.cpp\" \"*.h\"\n        echo\n    fi\ndone\n\nfor EXPECTED_BOOST_INCLUDE in \"${EXPECTED_BOOST_INCLUDES[@]}\"; do\n    if ! git grep -q \"^#include <${EXPECTED_BOOST_INCLUDE}>\" -- \"*.cpp\" \"*.h\"; then\n        echo \"Good job! The Boost dependency \\\"${EXPECTED_BOOST_INCLUDE}\\\" is no longer used.\"\n        echo \"Please remove it from EXPECTED_BOOST_INCLUDES in $0\"\n        echo \"to make sure this dependency is not accidentally reintroduced.\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\n\nQUOTE_SYNTAX_INCLUDES=$(git grep '^#include \"' -- \"*.cpp\" \"*.h\" | grep -Ev \"${IGNORE_REGEXP}\")\nif [[ ${QUOTE_SYNTAX_INCLUDES} != \"\" ]]; then\n    echo \"Please use bracket syntax includes (\\\"#include <foo.h>\\\") instead of quote syntax includes:\"\n    echo \"${QUOTE_SYNTAX_INCLUDES}\"\n    echo\n    EXIT_CODE=1\nfi\n\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-locale-dependence.sh",
    "content": "#!/usr/bin/env bash\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\nexport LC_ALL=C\n\n# Be aware that bitcoind and bitcoin-qt differ in terms of localization: Qt\n# opts in to POSIX localization by running setlocale(LC_ALL, \"\") on startup,\n# whereas no such call is made in bitcoind.\n#\n# Qt runs setlocale(LC_ALL, \"\") on initialization. This installs the locale\n# specified by the user's LC_ALL (or LC_*) environment variable as the new\n# C locale.\n#\n# In contrast, bitcoind does not opt in to localization -- no call to\n# setlocale(LC_ALL, \"\") is made and the environment variables LC_* are\n# thus ignored.\n#\n# This results in situations where bitcoind is guaranteed to be running\n# with the classic locale (\"C\") whereas the locale of bitcoin-qt will vary\n# depending on the user's environment variables.\n#\n# An example: Assuming the environment variable LC_ALL=de_DE then the\n# call std::to_string(1.23) will return \"1.230000\" in bitcoind but\n# \"1,230000\" in bitcoin-qt.\n#\n# From the Qt documentation:\n# \"On Unix/Linux Qt is configured to use the system locale settings by default.\n#  This can cause a conflict when using POSIX functions, for instance, when\n#  converting between data types such as floats and strings, since the notation\n#  may differ between locales. To get around this problem, call the POSIX function\n#  setlocale(LC_NUMERIC,\"C\") right after initializing QApplication, QGuiApplication\n#  or QCoreApplication to reset the locale that is used for number formatting to\n#  \"C\"-locale.\"\n#\n# See https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings and\n# https://stackoverflow.com/a/34878283 for more details.\n\n# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf.\nKNOWN_VIOLATIONS=(\n    \"src/dbwrapper.cpp:.*vsnprintf\"\n    \"src/test/dbwrapper_tests.cpp:.*snprintf\"\n    \"src/test/fuzz/locale.cpp\"\n    \"src/test/fuzz/string.cpp\"\n    \"src/test/util_tests.cpp\"\n)\n\nREGEXP_IGNORE_EXTERNAL_DEPENDENCIES=\"^src/(crypto/ctaes/|leveldb/|secp256k1/|minisketch/|tinyformat.h|univalue/)\"\n\nLOCALE_DEPENDENT_FUNCTIONS=(\n    alphasort    # LC_COLLATE (via strcoll)\n    asctime      # LC_TIME (directly)\n    asprintf     # (via vasprintf)\n    atof         # LC_NUMERIC (via strtod)\n    atoi         # LC_NUMERIC (via strtol)\n    atol         # LC_NUMERIC (via strtol)\n    atoll        # (via strtoll)\n    atoq\n    btowc        # LC_CTYPE (directly)\n    ctime        # (via asctime or localtime)\n    dprintf      # (via vdprintf)\n    fgetwc\n    fgetws\n    fold_case    # boost::locale::fold_case\n    fprintf      # (via vfprintf)\n    fputwc\n    fputws\n    fscanf       # (via __vfscanf)\n    fwprintf     # (via __vfwprintf)\n    getdate      # via __getdate_r => isspace // __localtime_r\n    getwc\n    getwchar\n    is_digit     # boost::algorithm::is_digit\n    is_space     # boost::algorithm::is_space\n    isalnum      # LC_CTYPE\n    isalpha      # LC_CTYPE\n    isblank      # LC_CTYPE\n    iscntrl      # LC_CTYPE\n    isctype      # LC_CTYPE\n    isdigit      # LC_CTYPE\n    isgraph      # LC_CTYPE\n    islower      # LC_CTYPE\n    isprint      # LC_CTYPE\n    ispunct      # LC_CTYPE\n    isspace      # LC_CTYPE\n    isupper      # LC_CTYPE\n    iswalnum     # LC_CTYPE\n    iswalpha     # LC_CTYPE\n    iswblank     # LC_CTYPE\n    iswcntrl     # LC_CTYPE\n    iswctype     # LC_CTYPE\n    iswdigit     # LC_CTYPE\n    iswgraph     # LC_CTYPE\n    iswlower     # LC_CTYPE\n    iswprint     # LC_CTYPE\n    iswpunct     # LC_CTYPE\n    iswspace     # LC_CTYPE\n    iswupper     # LC_CTYPE\n    iswxdigit    # LC_CTYPE\n    isxdigit     # LC_CTYPE\n    localeconv   # LC_NUMERIC + LC_MONETARY\n    mblen        # LC_CTYPE\n    mbrlen\n    mbrtowc\n    mbsinit\n    mbsnrtowcs\n    mbsrtowcs\n    mbstowcs     # LC_CTYPE\n    mbtowc       # LC_CTYPE\n    mktime\n    normalize    # boost::locale::normalize\n    printf       # LC_NUMERIC\n    putwc\n    putwchar\n    scanf        # LC_NUMERIC\n    setlocale\n    snprintf\n    sprintf\n    sscanf\n    std::locale::global\n    std::to_string\n    stod\n    stof\n    stoi\n    stol\n    stold\n    stoll\n    stoul\n    stoull\n    strcasecmp\n    strcasestr\n    strcoll      # LC_COLLATE\n#   strerror\n    strfmon\n    strftime     # LC_TIME\n    strncasecmp\n    strptime\n    strtod       # LC_NUMERIC\n    strtof\n    strtoimax\n    strtol       # LC_NUMERIC\n    strtold\n    strtoll\n    strtoq\n    strtoul      # LC_NUMERIC\n    strtoull\n    strtoumax\n    strtouq\n    strxfrm      # LC_COLLATE\n    swprintf\n    to_lower     # boost::locale::to_lower\n    to_title     # boost::locale::to_title\n    to_upper     # boost::locale::to_upper\n    tolower      # LC_CTYPE\n    toupper      # LC_CTYPE\n    towctrans\n    towlower     # LC_CTYPE\n    towupper     # LC_CTYPE\n    trim         # boost::algorithm::trim\n    trim_left    # boost::algorithm::trim_left\n    trim_right   # boost::algorithm::trim_right\n    ungetwc\n    vasprintf\n    vdprintf\n    versionsort\n    vfprintf\n    vfscanf\n    vfwprintf\n    vprintf\n    vscanf\n    vsnprintf\n    vsprintf\n    vsscanf\n    vswprintf\n    vwprintf\n    wcrtomb\n    wcscasecmp\n    wcscoll      # LC_COLLATE\n    wcsftime     # LC_TIME\n    wcsncasecmp\n    wcsnrtombs\n    wcsrtombs\n    wcstod       # LC_NUMERIC\n    wcstof\n    wcstoimax\n    wcstol       # LC_NUMERIC\n    wcstold\n    wcstoll\n    wcstombs     # LC_CTYPE\n    wcstoul      # LC_NUMERIC\n    wcstoull\n    wcstoumax\n    wcswidth\n    wcsxfrm      # LC_COLLATE\n    wctob\n    wctomb       # LC_CTYPE\n    wctrans\n    wctype\n    wcwidth\n    wprintf\n)\n\nfunction join_array {\n    local IFS=\"$1\"\n    shift\n    echo \"$*\"\n}\n\nREGEXP_IGNORE_KNOWN_VIOLATIONS=$(join_array \"|\" \"${KNOWN_VIOLATIONS[@]}\")\n\n# Invoke \"git grep\" only once in order to minimize run-time\nREGEXP_LOCALE_DEPENDENT_FUNCTIONS=$(join_array \"|\" \"${LOCALE_DEPENDENT_FUNCTIONS[@]}\")\nGIT_GREP_OUTPUT=$(git grep -E \"[^a-zA-Z0-9_\\`'\\\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(_r|_s)?)[^a-zA-Z0-9_\\`'\\\"<>]\" -- \"*.cpp\" \"*.h\")\n\nEXIT_CODE=0\nfor LOCALE_DEPENDENT_FUNCTION in \"${LOCALE_DEPENDENT_FUNCTIONS[@]}\"; do\n    MATCHES=$(grep -E \"[^a-zA-Z0-9_\\`'\\\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\\`'\\\"<>]\" <<< \"${GIT_GREP_OUTPUT}\" | \\\n        grep -vE \"\\.(c|cpp|h):\\s*(//|\\*|/\\*|\\\").*${LOCALE_DEPENDENT_FUNCTION}\")\n    if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != \"\" ]]; then\n        MATCHES=$(grep -vE \"${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}\" <<< \"${MATCHES}\")\n    fi\n    if [[ ${REGEXP_IGNORE_KNOWN_VIOLATIONS} != \"\" ]]; then\n        MATCHES=$(grep -vE \"${REGEXP_IGNORE_KNOWN_VIOLATIONS}\" <<< \"${MATCHES}\")\n    fi\n    if [[ ${MATCHES} != \"\" ]]; then\n        echo \"The locale dependent function ${LOCALE_DEPENDENT_FUNCTION}(...) appears to be used:\"\n        echo \"${MATCHES}\"\n        echo\n        EXIT_CODE=1\n    fi\ndone\nif [[ ${EXIT_CODE} != 0 ]]; then\n    echo \"Unnecessary locale dependence can cause bugs that are very\"\n    echo \"tricky to isolate and fix. Please avoid using locale dependent\"\n    echo \"functions if possible.\"\n    echo\n    echo \"Advice not applicable in this specific case? Add an exception\"\n    echo \"by updating the ignore list in $0\"\nfi\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-logs.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check that all logs are terminated with '\\n'\n#\n# Some logs are continued over multiple lines. They should be explicitly\n# commented with /* Continued */\n#\n# There are some instances of LogPrintf() in comments. Those can be\n# ignored\n\nexport LC_ALL=C\nUNTERMINATED_LOGS=$(git grep --extended-regexp \"LogPrintf?\\(\" -- \"*.cpp\" | \\\n    grep -v '\\\\n\"' | \\\n    grep -v '\\.\\.\\.' | \\\n    grep -v \"/\\* Continued \\*/\" | \\\n    grep -v \"LogPrint()\" | \\\n    grep -v \"LogPrintf()\")\nif [[ ${UNTERMINATED_LOGS} != \"\" ]]; then\n    # shellcheck disable=SC2028\n    echo \"All calls to LogPrintf() and LogPrint() should be terminated with \\\\n\"\n    echo\n    echo \"${UNTERMINATED_LOGS}\"\n    exit 1\nfi\n"
  },
  {
    "path": "test/lint/lint-python-dead-code.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Find dead Python code.\n\nexport LC_ALL=C\n\nif ! command -v vulture > /dev/null; then\n    echo \"Skipping Python dead code linting since vulture is not installed. Install by running \\\"pip3 install vulture\\\"\"\n    exit 0\nfi\n\n# --min-confidence 100 will only report code that is guaranteed to be unused within the analyzed files.\n# Any value below 100 introduces the risk of false positives, which would create an unacceptable maintenance burden.\nmapfile -t FILES < <(git ls-files -- \"*.py\")\nif ! vulture --min-confidence 100 \"${FILES[@]}\"; then\n    echo \"Python dead code detection found some issues\"\n    exit 1\nfi\n"
  },
  {
    "path": "test/lint/lint-python-utf8-encoding.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2020 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Make sure we explicitly open all text files using UTF-8 (or ASCII) encoding to\n# avoid potential issues on the BSDs where the locale is not always set.\n\nexport LC_ALL=C\nEXIT_CODE=0\nOUTPUT=$(git grep \" open(\" -- \"*.py\" \":(exclude)src/crc32c/\" | grep -vE \"encoding=.(ascii|utf8|utf-8).\" | grep -vE \"open\\([^,]*, ['\\\"][^'\\\"]*b[^'\\\"]*['\\\"]\")\nif [[ ${OUTPUT} != \"\" ]]; then\n    echo \"Python's open(...) seems to be used to open text files without explicitly\"\n    echo \"specifying encoding=\\\"utf8\\\":\"\n    echo\n    echo \"${OUTPUT}\"\n    EXIT_CODE=1\nfi\nOUTPUT=$(git grep \"check_output(\" -- \"*.py\" \":(exclude)src/crc32c/\"| grep \"universal_newlines=True\" | grep -vE \"encoding=.(ascii|utf8|utf-8).\")\nif [[ ${OUTPUT} != \"\" ]]; then\n    echo \"Python's check_output(...) seems to be used to get program outputs without explicitly\"\n    echo \"specifying encoding=\\\"utf8\\\":\"\n    echo\n    echo \"${OUTPUT}\"\n    EXIT_CODE=1\nfi\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-python.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2017-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for specified flake8 warnings in python files.\n\nexport LC_ALL=C\nexport MYPY_CACHE_DIR=\"${BASE_ROOT_DIR}/test/.mypy_cache\"\n\nenabled=(\n    E101 # indentation contains mixed spaces and tabs\n    E112 # expected an indented block\n    E113 # unexpected indentation\n    E115 # expected an indented block (comment)\n    E116 # unexpected indentation (comment)\n    E125 # continuation line with same indent as next logical line\n    E129 # visually indented line with same indent as next logical line\n    E131 # continuation line unaligned for hanging indent\n    E133 # closing bracket is missing indentation\n    E223 # tab before operator\n    E224 # tab after operator\n    E242 # tab after ','\n    E266 # too many leading '#' for block comment\n    E271 # multiple spaces after keyword\n    E272 # multiple spaces before keyword\n    E273 # tab after keyword\n    E274 # tab before keyword\n    E275 # missing whitespace after keyword\n    E304 # blank lines found after function decorator\n    E306 # expected 1 blank line before a nested definition\n    E401 # multiple imports on one line\n    E402 # module level import not at top of file\n    E502 # the backslash is redundant between brackets\n    E701 # multiple statements on one line (colon)\n    E702 # multiple statements on one line (semicolon)\n    E703 # statement ends with a semicolon\n    E711 # comparison to None should be 'if cond is None:'\n    E714 # test for object identity should be \"is not\"\n    E721 # do not compare types, use \"isinstance()\"\n    E742 # do not define classes named \"l\", \"O\", or \"I\"\n    E743 # do not define functions named \"l\", \"O\", or \"I\"\n    E901 # SyntaxError: invalid syntax\n    E902 # TokenError: EOF in multi-line string\n    F401 # module imported but unused\n    F402 # import module from line N shadowed by loop variable\n    F403 # 'from foo_module import *' used; unable to detect undefined names\n    F404 # future import(s) name after other statements\n    F405 # foo_function may be undefined, or defined from star imports: bar_module\n    F406 # \"from module import *\" only allowed at module level\n    F407 # an undefined __future__ feature name was imported\n    F601 # dictionary key name repeated with different values\n    F602 # dictionary key variable name repeated with different values\n    F621 # too many expressions in an assignment with star-unpacking\n    F622 # two or more starred expressions in an assignment (a, *b, *c = d)\n    F631 # assertion test is a tuple, which are always True\n    F632 # use ==/!= to compare str, bytes, and int literals\n    F701 # a break statement outside of a while or for loop\n    F702 # a continue statement outside of a while or for loop\n    F703 # a continue statement in a finally block in a loop\n    F704 # a yield or yield from statement outside of a function\n    F705 # a return statement with arguments inside a generator\n    F706 # a return statement outside of a function/method\n    F707 # an except: block as not the last exception handler\n    F811 # redefinition of unused name from line N\n    F812 # list comprehension redefines 'foo' from line N\n    F821 # undefined name 'Foo'\n    F822 # undefined name name in __all__\n    F823 # local variable name … referenced before assignment\n    F831 # duplicate argument name in function definition\n    F841 # local variable 'foo' is assigned to but never used\n    W191 # indentation contains tabs\n    W291 # trailing whitespace\n    W292 # no newline at end of file\n    W293 # blank line contains whitespace\n    W601 # .has_key() is deprecated, use \"in\"\n    W602 # deprecated form of raising exception\n    W603 # \"<>\" is deprecated, use \"!=\"\n    W604 # backticks are deprecated, use \"repr()\"\n    W605 # invalid escape sequence \"x\"\n    W606 # 'async' and 'await' are reserved keywords starting with Python 3.7\n)\n\nif ! command -v flake8 > /dev/null; then\n    echo \"Skipping Python linting since flake8 is not installed.\"\n    exit 0\nelif PYTHONWARNINGS=\"ignore\" flake8 --version | grep -q \"Python 2\"; then\n    echo \"Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8.\"\n    exit 0\nfi\n\nEXIT_CODE=0\n\n# shellcheck disable=SC2046\nif ! PYTHONWARNINGS=\"ignore\" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=\",\"; echo \"${enabled[*]}\") $(\n    if [[ $# == 0 ]]; then\n        git ls-files \"*.py\"\n    else\n        echo \"$@\"\n    fi\n); then\n    EXIT_CODE=1\nfi\n\nmapfile -t FILES < <(git ls-files \"test/functional/*.py\" \"contrib/devtools/*.py\")\nif ! mypy --show-error-codes \"${FILES[@]}\"; then\n    EXIT_CODE=1\nfi\n\nexit $EXIT_CODE\n"
  },
  {
    "path": "test/lint/lint-rpc-help.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check that all RPC help texts are generated by RPCHelpMan.\n\nexport LC_ALL=C\n\nEXIT_CODE=0\n\n# Assume that all multiline strings passed into a runtime_error are help texts.\n# This is potentially fragile, but the linter is only temporary and can safely\n# be removed early 2019.\n\nnon_autogenerated_help=$(grep --perl-regexp --null-data --only-matching 'runtime_error\\(\\n\\s*\".*\\\\n\"\\n' $(git ls-files -- \"*.cpp\"))\nif [[ ${non_autogenerated_help} != \"\" ]]; then\n    echo \"Must use RPCHelpMan to generate the help for the following RPC methods:\"\n    echo \"${non_autogenerated_help}\"\n    echo\n    EXIT_CODE=1\nfi\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-shebang.sh",
    "content": "#!/usr/bin/env bash\n# Assert expected shebang lines\n\nexport LC_ALL=C\nEXIT_CODE=0\nfor PYTHON_FILE in $(git ls-files -- \"*.py\"); do\n    if [[ $(head -c 2 \"${PYTHON_FILE}\") == \"#!\" &&\n          $(head -n 1 \"${PYTHON_FILE}\") != \"#!/usr/bin/env python3\" ]]; then\n        echo \"Missing shebang \\\"#!/usr/bin/env python3\\\" in ${PYTHON_FILE} (do not use python or python2)\"\n        EXIT_CODE=1\n    fi\ndone\nfor SHELL_FILE in $(git ls-files -- \"*.sh\"); do\n    if [[ $(head -n 1 \"${SHELL_FILE}\") != \"#!/usr/bin/env bash\" &&\n          $(head -n 1 \"${SHELL_FILE}\") != \"#!/bin/sh\" ]]; then\n        echo \"Missing expected shebang \\\"#!/usr/bin/env bash\\\" or \\\"#!/bin/sh\\\" in ${SHELL_FILE}\"\n        EXIT_CODE=1\n    fi\ndone\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-shell-locale.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2020 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Make sure all shell scripts:\n# a.) explicitly opt out of locale dependence using\n#     \"export LC_ALL=C\" or \"export LC_ALL=C.UTF-8\", or\n# b.) explicitly opt in to locale dependence using the annotation below.\n\nexport LC_ALL=C\n\nEXIT_CODE=0\nfor SHELL_SCRIPT in $(git ls-files -- \"*.sh\" | grep -vE \"src/(secp256k1|minisketch|univalue)/\"); do\n    if grep -q \"# This script is intentionally locale dependent by not setting \\\"export LC_ALL=C\\\"\" \"${SHELL_SCRIPT}\"; then\n        continue\n    fi\n    FIRST_NON_COMMENT_LINE=$(grep -vE '^(#.*)?$' \"${SHELL_SCRIPT}\" | head -1)\n    if [[ ${FIRST_NON_COMMENT_LINE} != \"export LC_ALL=C\" && ${FIRST_NON_COMMENT_LINE} != \"export LC_ALL=C.UTF-8\" ]]; then\n        echo \"Missing \\\"export LC_ALL=C\\\" (to avoid locale dependence) as first non-comment non-empty line in ${SHELL_SCRIPT}\"\n        EXIT_CODE=1\n    fi\ndone\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-shell.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for shellcheck warnings in shell scripts.\n\nexport LC_ALL=C\n\n# Disabled warnings:\ndisabled=(\n    SC2162 # read without -r will mangle backslashes.\n)\n\nEXIT_CODE=0\n\nif ! command -v shellcheck > /dev/null; then\n    echo \"Skipping shell linting since shellcheck is not installed.\"\n    exit $EXIT_CODE\nfi\n\nSHELLCHECK_CMD=(shellcheck --external-sources --check-sourced --source-path=SCRIPTDIR)\nEXCLUDE=\"--exclude=$(IFS=','; echo \"${disabled[*]}\")\"\n# Check shellcheck directive used for sourced files\nmapfile -t SOURCED_FILES < <(git ls-files | xargs gawk '/^# shellcheck shell=/ {print FILENAME} {nextfile}')\nmapfile -t GUIX_FILES < <(git ls-files contrib/guix contrib/shell | xargs gawk '/^#!\\/usr\\/bin\\/env bash/ {print FILENAME} {nextfile}')\nmapfile -t FILES < <(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|minisketch|univalue)/')\nif ! \"${SHELLCHECK_CMD[@]}\" \"$EXCLUDE\" \"${SOURCED_FILES[@]}\" \"${GUIX_FILES[@]}\" \"${FILES[@]}\"; then\n    EXIT_CODE=1\nfi\n\nexit $EXIT_CODE\n"
  },
  {
    "path": "test/lint/lint-spelling.ignore-words.txt",
    "content": "asend\nba\nblockin\ncachable\ncreat\nfo\nfpr\nhights\nhist\ninout\ninvokable\nkeypair\nmor\nnin\nser\nunparseable\nunser\nuseable\nwit\n"
  },
  {
    "path": "test/lint/lint-spelling.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Warn in case of spelling errors.\n# Note: Will exit successfully regardless of spelling errors.\n\nexport LC_ALL=C\n\nif ! command -v codespell > /dev/null; then\n    echo \"Skipping spell check linting since codespell is not installed.\"\n    exit 0\nfi\n\nIGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt\nmapfile -t FILES < <(git ls-files -- \":(exclude)build-aux/m4/\" \":(exclude)contrib/seeds/*.txt\" \":(exclude)depends/\" \":(exclude)doc/release-notes/\" \":(exclude)src/leveldb/\" \":(exclude)src/crc32c/\" \":(exclude)src/secp256k1/\" \":(exclude)src/minisketch/\" \":(exclude)src/univalue/\" \":(exclude)contrib/builder-keys/keys.txt\" \":(exclude)contrib/guix/patches\")\nif ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} \"${FILES[@]}\"; then\n    echo \"^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}\"\nfi\n"
  },
  {
    "path": "test/lint/lint-tests.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check the test suite naming conventions\n\nexport LC_ALL=C\nEXIT_CODE=0\n\nNAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\\(' -- \\\n    \"src/test/**.cpp\" \"src/wallet/test/**.cpp\" | \\\n    grep -vE '/(.*?)\\.cpp:BOOST_FIXTURE_TEST_SUITE\\(\\1, .*\\)$')\nif [[ ${NAMING_INCONSISTENCIES} != \"\" ]]; then\n    echo \"The test suite in file src/test/foo_tests.cpp should be named\"\n    echo \"\\\"foo_tests\\\". Please make sure the following test suites follow\"\n    echo \"that convention:\"\n    echo\n    echo \"${NAMING_INCONSISTENCIES}\"\n    EXIT_CODE=1\nfi\n\nTEST_SUITE_NAME_COLLISSIONS=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\\(' -- \\\n    \"src/test/**.cpp\" \"src/wallet/test/**.cpp\" | cut -f2 -d'(' | cut -f1 -d, | \\\n    sort | uniq -d)\nif [[ ${TEST_SUITE_NAME_COLLISSIONS} != \"\" ]]; then\n    echo \"Test suite names must be unique. The following test suite names\"\n    echo \"appear to be used more than once:\"\n    echo\n    echo \"${TEST_SUITE_NAME_COLLISSIONS}\"\n    EXIT_CODE=1\nfi\n\nexit ${EXIT_CODE}\n"
  },
  {
    "path": "test/lint/lint-whitespace.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright (c) 2017-2021 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n#\n# Check for new lines in diff that introduce trailing whitespace.\n\n# We can't run this check unless we know the commit range for the PR.\n\nexport LC_ALL=C\nwhile getopts \"?\" opt; do\n  case $opt in\n    ?)\n      echo \"Usage: $0 [N]\"\n      echo \"       COMMIT_RANGE='<commit range>' $0\"\n      echo \"       $0 -?\"\n      echo \"Checks unstaged changes, the previous N commits, or a commit range.\"\n      echo \"COMMIT_RANGE='47ba2c3...ee50c9e' $0\"\n      exit 0\n    ;;\n  esac\ndone\n\nif [ -z \"${COMMIT_RANGE}\" ]; then\n  if [ -n \"$1\" ]; then\n    COMMIT_RANGE=\"HEAD~$1...HEAD\"\n  else\n    # This assumes that the target branch of the pull request will be master.\n    MERGE_BASE=$(git merge-base HEAD master)\n    COMMIT_RANGE=\"$MERGE_BASE..HEAD\"\n  fi\nfi\n\nshowdiff() {\n  if ! git diff -U0 \"${COMMIT_RANGE}\" -- \".\" \":(exclude)depends/patches/\" \":(exclude)contrib/guix/patches/\" \":(exclude)src/leveldb/\" \":(exclude)src/crc32c/\" \":(exclude)src/secp256k1/\" \":(exclude)src/minisketch/\" \":(exclude)src/univalue/\" \":(exclude)doc/release-notes/\" \":(exclude)src/qt/locale/\"; then\n    echo \"Failed to get a diff\"\n    exit 1\n  fi\n}\n\nshowcodediff() {\n  if ! git diff -U0 \"${COMMIT_RANGE}\" -- *.cpp *.h *.md *.py *.sh \":(exclude)src/leveldb/\" \":(exclude)src/crc32c/\" \":(exclude)src/secp256k1/\" \":(exclude)src/minisketch/\" \":(exclude)src/univalue/\" \":(exclude)doc/release-notes/\" \":(exclude)src/qt/locale/\"; then\n    echo \"Failed to get a diff\"\n    exit 1\n  fi\n}\n\nRET=0\n\n# Check if trailing whitespace was found in the diff.\nif showdiff | grep -E -q '^\\+.*\\s+$'; then\n  echo \"This diff appears to have added new lines with trailing whitespace.\"\n  echo \"The following changes were suspected:\"\n  FILENAME=\"\"\n  SEEN=0\n  SEENLN=0\n  while read -r line; do\n    if [[ \"$line\" =~ ^diff ]]; then\n      FILENAME=\"$line\"\n      SEEN=0\n    elif [[ \"$line\" =~ ^@@ ]]; then\n      LINENUMBER=\"$line\"\n      SEENLN=0\n    else\n      if [ \"$SEEN\" -eq 0 ]; then\n        # The first time a file is seen with trailing whitespace, we print the\n        # filename (preceded by a newline).\n        echo\n        echo \"$FILENAME\"\n        SEEN=1\n      fi\n      if [ \"$SEENLN\" -eq 0 ]; then\n        echo \"$LINENUMBER\"\n        SEENLN=1\n      fi\n      echo \"$line\"\n    fi\n  done < <(showdiff | grep -E '^(diff --git |@@|\\+.*\\s+$)')\n  RET=1\nfi\n\n# Check if tab characters were found in the diff.\nif showcodediff | perl -nle '$MATCH++ if m{^\\+.*\\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then\n  echo \"This diff appears to have added new lines with tab characters instead of spaces.\"\n  echo \"The following changes were suspected:\"\n  FILENAME=\"\"\n  SEEN=0\n  SEENLN=0\n  while read -r line; do\n    if [[ \"$line\" =~ ^diff ]]; then\n      FILENAME=\"$line\"\n      SEEN=0\n    elif [[ \"$line\" =~ ^@@ ]]; then\n      LINENUMBER=\"$line\"\n      SEENLN=0\n    else\n      if [ \"$SEEN\" -eq 0 ]; then\n        # The first time a file is seen with a tab character, we print the\n        # filename (preceded by a newline).\n        echo\n        echo \"$FILENAME\"\n        SEEN=1\n      fi\n      if [ \"$SEENLN\" -eq 0 ]; then\n        echo \"$LINENUMBER\"\n        SEENLN=1\n      fi\n      echo \"$line\"\n    fi\n  done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\\+.*\\t)}')\n  RET=1\nfi\n\nexit $RET\n"
  },
  {
    "path": "test/sanitizer_suppressions/lsan",
    "content": "# Suppress warnings triggered in dependencies\nleak:libcrypto\nleak:libqminimal\nleak:libQt5Core\nleak:libQt5Gui\nleak:libQt5Widgets\n"
  },
  {
    "path": "test/sanitizer_suppressions/tsan",
    "content": "# ThreadSanitizer suppressions\n# ============================\n\n# WalletBatch (unidentified deadlock)\ndeadlock:WalletBatch\n\n# Intentional deadlock in tests\ndeadlock:TestPotentialDeadLockDetected\n\n# External libraries\ndeadlock:libdb\nrace:libzmq\n"
  },
  {
    "path": "test/sanitizer_suppressions/ubsan",
    "content": "alignment:move.h\nalignment:prevector.h\nbool:wallet/wallet.cpp\nfloat-divide-by-zero:policy/fees.cpp\nfloat-divide-by-zero:validation.cpp\nfloat-divide-by-zero:wallet/wallet.cpp\nunsigned-integer-overflow:arith_uint256.h\nunsigned-integer-overflow:basic_string.h\nunsigned-integer-overflow:bench/bench.h\nunsigned-integer-overflow:Munt-tx.cpp\nunsigned-integer-overflow:bloom.cpp\nunsigned-integer-overflow:chain.cpp\nunsigned-integer-overflow:chain.h\nunsigned-integer-overflow:coded_stream.h\nunsigned-integer-overflow:core_write.cpp\nunsigned-integer-overflow:crypto/chacha20.cpp\nunsigned-integer-overflow:crypto/ctaes/ctaes.c\nunsigned-integer-overflow:crypto/poly1305.cpp\nunsigned-integer-overflow:crypto/ripemd160.cpp\nunsigned-integer-overflow:crypto/sha1.cpp\nunsigned-integer-overflow:crypto/sha256.cpp\nunsigned-integer-overflow:crypto/sha512.cpp\nunsigned-integer-overflow:hash.cpp\nunsigned-integer-overflow:leveldb/db/log_reader.cc\nunsigned-integer-overflow:leveldb/util/bloom.cc\nunsigned-integer-overflow:leveldb/util/crc32c.h\nunsigned-integer-overflow:leveldb/util/hash.cc\nunsigned-integer-overflow:policy/fees.cpp\nunsigned-integer-overflow:prevector.h\nunsigned-integer-overflow:script/interpreter.cpp\nunsigned-integer-overflow:stl_bvector.h\nunsigned-integer-overflow:txmempool.cpp\nunsigned-integer-overflow:util/strencodings.cpp\nunsigned-integer-overflow:validation.cpp\nvptr:fs.cpp\n"
  },
  {
    "path": "test/util/data/blanktxv1.hex",
    "content": "01000000000000000000\n"
  },
  {
    "path": "test/util/data/blanktxv1.json",
    "content": "{\n    \"txid\": \"d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43\",\n    \"hash\": \"d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43\",\n    \"version\": 1,\n    \"size\": 10,\n    \"vsize\": 10,\n    \"weight\": 40,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n    ],\n    \"hex\": \"01000000000000000000\"\n}\n"
  },
  {
    "path": "test/util/data/blanktxv2.hex",
    "content": "02000000000000000000\n"
  },
  {
    "path": "test/util/data/blanktxv2.json",
    "content": "{\n    \"txid\": \"4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a\",\n    \"hash\": \"4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a\",\n    \"version\": 2,\n    \"size\": 10,\n    \"vsize\": 10,\n    \"weight\": 40,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n    ],\n    \"hex\": \"02000000000000000000\"\n}\n"
  },
  {
    "path": "test/util/data/tt-delin1-out.hex",
    "content": "0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000\n"
  },
  {
    "path": "test/util/data/tt-delin1-out.json",
    "content": "{\n    \"txid\": \"81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd\",\n    \"hash\": \"81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd\",\n    \"version\": 1,\n    \"size\": 3040,\n    \"vsize\": 3040,\n    \"weight\": 12160,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd\",\n            \"vout\": 332,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed\",\n            \"vout\": 209,\n            \"scriptSig\": {\n                \"asm\": \"304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485\",\n            \"vout\": 21,\n            \"scriptSig\": {\n                \"asm\": \"3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282\",\n            \"vout\": 9,\n            \"scriptSig\": {\n                \"asm\": \"304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88\",\n            \"vout\": 30,\n            \"scriptSig\": {\n                \"asm\": \"30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766\",\n            \"vout\": 114,\n            \"scriptSig\": {\n                \"asm\": \"304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02\",\n            \"vout\": 103,\n            \"scriptSig\": {\n                \"asm\": \"3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920\",\n            \"vout\": 221,\n            \"scriptSig\": {\n                \"asm\": \"3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55\",\n            \"vout\": 27,\n            \"scriptSig\": {\n                \"asm\": \"304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057\",\n            \"vout\": 1095,\n            \"scriptSig\": {\n                \"asm\": \"304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f\",\n            \"vout\": 37,\n            \"scriptSig\": {\n                \"asm\": \"3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241\",\n            \"vout\": 20,\n            \"scriptSig\": {\n                \"asm\": \"304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236\",\n            \"vout\": 242,\n            \"scriptSig\": {\n                \"asm\": \"3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.37820000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o\"\n                ]\n            }\n        },\n        {\n            \"value\": 0.01000001,\n            \"n\": 1,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/tt-delout1-out.hex",
    "content": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000\n"
  },
  {
    "path": "test/util/data/tt-delout1-out.json",
    "content": "{\n    \"txid\": \"c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493\",\n    \"hash\": \"c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493\",\n    \"version\": 1,\n    \"size\": 3155,\n    \"vsize\": 3155,\n    \"weight\": 12620,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd\",\n            \"vout\": 332,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba[ALL] 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505\",\n                \"hex\": \"493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed\",\n            \"vout\": 209,\n            \"scriptSig\": {\n                \"asm\": \"304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485\",\n            \"vout\": 21,\n            \"scriptSig\": {\n                \"asm\": \"3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282\",\n            \"vout\": 9,\n            \"scriptSig\": {\n                \"asm\": \"304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88\",\n            \"vout\": 30,\n            \"scriptSig\": {\n                \"asm\": \"30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766\",\n            \"vout\": 114,\n            \"scriptSig\": {\n                \"asm\": \"304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02\",\n            \"vout\": 103,\n            \"scriptSig\": {\n                \"asm\": \"3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920\",\n            \"vout\": 221,\n            \"scriptSig\": {\n                \"asm\": \"3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55\",\n            \"vout\": 27,\n            \"scriptSig\": {\n                \"asm\": \"304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057\",\n            \"vout\": 1095,\n            \"scriptSig\": {\n                \"asm\": \"304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f\",\n            \"vout\": 37,\n            \"scriptSig\": {\n                \"asm\": \"3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241\",\n            \"vout\": 20,\n            \"scriptSig\": {\n                \"asm\": \"304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236\",\n            \"vout\": 242,\n            \"scriptSig\": {\n                \"asm\": \"3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.37820000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/tt-locktime317000-out.hex",
    "content": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400\n"
  },
  {
    "path": "test/util/data/tt-locktime317000-out.json",
    "content": "{\n    \"txid\": \"aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5\",\n    \"hash\": \"aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5\",\n    \"version\": 1,\n    \"size\": 3189,\n    \"vsize\": 3189,\n    \"weight\": 12756,\n    \"locktime\": 317000,\n    \"vin\": [\n        {\n            \"txid\": \"27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd\",\n            \"vout\": 332,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba[ALL] 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505\",\n                \"hex\": \"493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed\",\n            \"vout\": 209,\n            \"scriptSig\": {\n                \"asm\": \"304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\",\n                \"hex\": \"483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485\",\n            \"vout\": 21,\n            \"scriptSig\": {\n                \"asm\": \"3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282\",\n            \"vout\": 9,\n            \"scriptSig\": {\n                \"asm\": \"304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88\",\n            \"vout\": 30,\n            \"scriptSig\": {\n                \"asm\": \"30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766\",\n            \"vout\": 114,\n            \"scriptSig\": {\n                \"asm\": \"304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02\",\n            \"vout\": 103,\n            \"scriptSig\": {\n                \"asm\": \"3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\",\n                \"hex\": \"49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920\",\n            \"vout\": 221,\n            \"scriptSig\": {\n                \"asm\": \"3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\",\n                \"hex\": \"483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55\",\n            \"vout\": 27,\n            \"scriptSig\": {\n                \"asm\": \"304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057\",\n            \"vout\": 1095,\n            \"scriptSig\": {\n                \"asm\": \"304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f\",\n            \"vout\": 37,\n            \"scriptSig\": {\n                \"asm\": \"3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241\",\n            \"vout\": 20,\n            \"scriptSig\": {\n                \"asm\": \"304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\",\n                \"hex\": \"48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236\",\n            \"vout\": 242,\n            \"scriptSig\": {\n                \"asm\": \"3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\",\n                \"hex\": \"493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.37820000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o\"\n                ]\n            }\n        },\n        {\n            \"value\": 0.01000001,\n            \"n\": 1,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400\"\n}\n"
  },
  {
    "path": "test/util/data/tx394b54bb.hex",
    "content": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000\n"
  },
  {
    "path": "test/util/data/txcreate1.hex",
    "content": "02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000\n"
  },
  {
    "path": "test/util/data/txcreate1.json",
    "content": "{\n    \"txid\": \"fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f\",\n    \"hash\": \"fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f\",\n    \"version\": 2,\n    \"size\": 201,\n    \"vsize\": 201,\n    \"weight\": 804,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c\",\n            \"vout\": 18,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967295\n        },\n        {\n            \"txid\": \"22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc\",\n            \"vout\": 1,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.18000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"\n                ]\n            }\n        },\n        {\n            \"value\": 4.00000000,\n            \"n\": 1,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 f2d4db28cad6502226ee484ae24505c2885cb12d OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreate2.hex",
    "content": "02000000000100000000000000000000000000\n"
  },
  {
    "path": "test/util/data/txcreate2.json",
    "content": "{\n    \"txid\": \"0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715\",\n    \"hash\": \"0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715\",\n    \"version\": 2,\n    \"size\": 19,\n    \"vsize\": 19,\n    \"weight\": 76,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"\",\n                \"hex\": \"\",\n                \"type\": \"nonstandard\"\n            }\n        }\n    ],\n    \"hex\": \"02000000000100000000000000000000000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatedata1.hex",
    "content": "02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000\n"
  },
  {
    "path": "test/util/data/txcreatedata1.json",
    "content": "{\n    \"txid\": \"07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e\",\n    \"hash\": \"07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e\",\n    \"version\": 1,\n    \"size\": 176,\n    \"vsize\": 176,\n    \"weight\": 704,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.18000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"\n                ]\n            }\n        },\n        {\n            \"value\": 4.00000000,\n            \"n\": 1,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\",\n                \"hex\": \"6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\",\n                \"type\": \"nulldata\"\n            }\n        }\n    ],\n    \"hex\": \"01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatedata2.hex",
    "content": "02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000\n"
  },
  {
    "path": "test/util/data/txcreatedata2.json",
    "content": "{\n    \"txid\": \"c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0\",\n    \"hash\": \"c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0\",\n    \"version\": 2,\n    \"size\": 176,\n    \"vsize\": 176,\n    \"weight\": 704,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.18000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"\n                ]\n            }\n        },\n        {\n            \"value\": 0.00000000,\n            \"n\": 1,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\",\n                \"hex\": \"6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\",\n                \"type\": \"nulldata\"\n            }\n        }\n    ],\n    \"hex\": \"02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatedata_seq0.hex",
    "content": "02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\n"
  },
  {
    "path": "test/util/data/txcreatedata_seq0.json",
    "content": "{\n    \"txid\": \"8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0\",\n    \"hash\": \"8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0\",\n    \"version\": 2,\n    \"size\": 85,\n    \"vsize\": 85,\n    \"weight\": 340,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967293\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.18000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatedata_seq1.hex",
    "content": "01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\n"
  },
  {
    "path": "test/util/data/txcreatedata_seq1.json",
    "content": "{\n    \"txid\": \"c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b\",\n    \"hash\": \"c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b\",\n    \"version\": 1,\n    \"size\": 126,\n    \"vsize\": 126,\n    \"weight\": 504,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 4294967293\n        },\n        {\n            \"txid\": \"5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"\",\n                \"hex\": \"\"\n            },\n            \"sequence\": 1\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.18000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatemultisig1.hex",
    "content": "01000000000100e1f5050000000069522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae00000000\n"
  },
  {
    "path": "test/util/data/txcreatemultisig1.json",
    "content": "{\n    \"txid\": \"0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894\",\n    \"hash\": \"0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894\",\n    \"version\": 1,\n    \"size\": 124,\n    \"vsize\": 124,\n    \"weight\": 496,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"2 02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d 02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485 3 OP_CHECKMULTISIG\",\n                \"hex\": \"522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae\",\n                \"reqSigs\": 2,\n                \"type\": \"multisig\",\n                \"addresses\": [\n                    \"1FoG2386FG2tAJS9acMuiDsKy67aGg9MKz\",\n                    \"1FXtz9KU8JNmQDyHdiEm5HDiALuP3zdHvV\",\n                    \"14LuavcBbXZYJ6Tsz3cAUQj9SuQoL2xCQX\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000000100e1f5050000000069522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatemultisig2.hex",
    "content": "01000000000100e1f5050000000017a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac8700000000\n"
  },
  {
    "path": "test/util/data/txcreatemultisig2.json",
    "content": "{\n    \"txid\": \"0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3\",\n    \"hash\": \"0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3\",\n    \"version\": 1,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 1c6fbaf46d64221e80cbae182c33ddf81b9294ac OP_EQUAL\",\n                \"hex\": \"a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac87\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000000100e1f5050000000017a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac8700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatemultisig3.hex",
    "content": "01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000\n"
  },
  {
    "path": "test/util/data/txcreatemultisig3.json",
    "content": "{\n    \"txid\": \"ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f\",\n    \"hash\": \"ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f\",\n    \"version\": 1,\n    \"size\": 53,\n    \"vsize\": 53,\n    \"weight\": 212,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"0 e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05\",\n                \"hex\": \"0020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05\",\n                \"reqSigs\": 1,\n                \"type\": \"witness_v0_scripthash\",\n                \"addresses\": [\n                    \"bc1qu9dgdg330r6r84g5mw7wqshg04exv2uttmw2elfwx74h5tgntuzs44gyfg\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatemultisig4.hex",
    "content": "01000000000100e1f5050000000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000\n"
  },
  {
    "path": "test/util/data/txcreatemultisig4.json",
    "content": "{\n    \"txid\": \"5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567\",\n    \"hash\": \"5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567\",\n    \"version\": 1,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 6edf12858999f0dae74f9c692e6694ee3621b2ac OP_EQUAL\",\n                \"hex\": \"a9146edf12858999f0dae74f9c692e6694ee3621b2ac87\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000000100e1f5050000000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatemultisig5.json",
    "content": "{\n    \"txid\": \"813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f\",\n    \"hash\": \"813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f\",\n    \"version\": 2,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 1.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 a4051c02398868af83f28f083208fae99a769263 OP_EQUAL\",\n                \"hex\": \"a914a4051c02398868af83f28f083208fae99a76926387\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"02000000000100e1f5050000000017a914a4051c02398868af83f28f083208fae99a7692638700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey1.hex",
    "content": "0100000000010000000000000000232102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac00000000\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey1.json",
    "content": "{\n    \"txid\": \"f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f\",\n    \"hash\": \"f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f\",\n    \"version\": 1,\n    \"size\": 54,\n    \"vsize\": 54,\n    \"weight\": 216,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 OP_CHECKSIG\",\n                \"hex\": \"2102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkey\",\n                \"addresses\": [\n                    \"1FoG2386FG2tAJS9acMuiDsKy67aGg9MKz\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"0100000000010000000000000000232102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey2.hex",
    "content": "0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey2.json",
    "content": "{\n    \"txid\": \"70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73\",\n    \"hash\": \"70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73\",\n    \"version\": 1,\n    \"size\": 41,\n    \"vsize\": 41,\n    \"weight\": 164,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"0 a2516e770582864a6a56ed21a102044e388c62e3\",\n                \"hex\": \"0014a2516e770582864a6a56ed21a102044e388c62e3\",\n                \"reqSigs\": 1,\n                \"type\": \"witness_v0_keyhash\",\n                \"addresses\": [\n                    \"bc1q5fgkuac9s2ry56jka5s6zqsyfcugcchry5cwu0\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey3.hex",
    "content": "010000000001000000000000000017a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a838700000000\n"
  },
  {
    "path": "test/util/data/txcreateoutpubkey3.json",
    "content": "{\n    \"txid\": \"bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c\",\n    \"hash\": \"bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c\",\n    \"version\": 1,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 a5ab14c9804d0d8bf02f1aea4e82780733ad0a83 OP_EQUAL\",\n                \"hex\": \"a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a8387\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"010000000001000000000000000017a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a838700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatescript1.hex",
    "content": "0100000000010000000000000000017500000000\n"
  },
  {
    "path": "test/util/data/txcreatescript1.json",
    "content": "{\n    \"txid\": \"f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9\",\n    \"hash\": \"f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9\",\n    \"version\": 1,\n    \"size\": 20,\n    \"vsize\": 20,\n    \"weight\": 80,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DROP\",\n                \"hex\": \"75\",\n                \"type\": \"nonstandard\"\n            }\n        }\n    ],\n    \"hex\": \"0100000000010000000000000000017500000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatescript2.hex",
    "content": "010000000001000000000000000017a91471ed53322d470bb96657deb786b94f97dd46fb158700000000\n"
  },
  {
    "path": "test/util/data/txcreatescript2.json",
    "content": "{\n    \"txid\": \"6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0\",\n    \"hash\": \"6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0\",\n    \"version\": 1,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 71ed53322d470bb96657deb786b94f97dd46fb15 OP_EQUAL\",\n                \"hex\": \"a91471ed53322d470bb96657deb786b94f97dd46fb1587\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"010000000001000000000000000017a91471ed53322d470bb96657deb786b94f97dd46fb158700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatescript3.hex",
    "content": "01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000\n"
  },
  {
    "path": "test/util/data/txcreatescript3.json",
    "content": "{\n    \"txid\": \"8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8\",\n    \"hash\": \"8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8\",\n    \"version\": 1,\n    \"size\": 53,\n    \"vsize\": 53,\n    \"weight\": 212,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"0 0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6\",\n                \"hex\": \"00200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6\",\n                \"reqSigs\": 1,\n                \"type\": \"witness_v0_scripthash\",\n                \"addresses\": [\n                    \"bc1qp0lfxhnscvsu0j36l36uurgv5tuck4pzuqytkvwqp3kh78cupttqyf705v\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatescript4.hex",
    "content": "010000000001000000000000000017a9146a2c482f4985f57e702f325816c90e3723ca81ae8700000000\n"
  },
  {
    "path": "test/util/data/txcreatescript4.json",
    "content": "{\n    \"txid\": \"24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc\",\n    \"hash\": \"24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc\",\n    \"version\": 1,\n    \"size\": 42,\n    \"vsize\": 42,\n    \"weight\": 168,\n    \"locktime\": 0,\n    \"vin\": [\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00000000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_HASH160 6a2c482f4985f57e702f325816c90e3723ca81ae OP_EQUAL\",\n                \"hex\": \"a9146a2c482f4985f57e702f325816c90e3723ca81ae87\",\n                \"reqSigs\": 1,\n                \"type\": \"scripthash\",\n                \"addresses\": [\n                    \"3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"010000000001000000000000000017a9146a2c482f4985f57e702f325816c90e3723ca81ae8700000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatesignv1.hex",
    "content": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000\n"
  },
  {
    "path": "test/util/data/txcreatesignv1.json",
    "content": "{\n    \"txid\": \"ffc7e509ec3fd60a182eb712621d41a47dc7d4ff310a70826c2fb0e9afb3fa02\",\n    \"hash\": \"ffc7e509ec3fd60a182eb712621d41a47dc7d4ff310a70826c2fb0e9afb3fa02\",\n    \"version\": 1,\n    \"size\": 223,\n    \"vsize\": 223,\n    \"weight\": 892,\n    \"locktime\": 0,\n    \"vin\": [\n        {\n            \"txid\": \"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\n            \"vout\": 0,\n            \"scriptSig\": {\n                \"asm\": \"30440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8\",\n                \"hex\": \"4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8\"\n            },\n            \"sequence\": 4294967295\n        }\n    ],\n    \"vout\": [\n        {\n            \"value\": 0.00100000,\n            \"n\": 0,\n            \"scriptPubKey\": {\n                \"asm\": \"OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG\",\n                \"hex\": \"76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac\",\n                \"reqSigs\": 1,\n                \"type\": \"pubkeyhash\",\n                \"addresses\": [\n                    \"193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"\n                ]\n            }\n        }\n    ],\n    \"hex\": \"01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a4730440220131432090a6af42da3e8335ff110831b41a44f4e9d18d88f5d50278380696c7202200fc2e48938f323ad13625890c0ea926c8a189c08b8efc38376b20c8a2188e96e01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000\"\n}\n"
  },
  {
    "path": "test/util/data/txcreatesignv2.hex",
    "content": "02000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a473044022079c7aa014177a2e973caf6df7c7b8f15399083b91eba370ea1e19c4caed9181e02205f8f8763505ce8e6cbdd2cd28fab3fd407a75003e7d0dc04e6bebb0a3c89e7cb01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000\n"
  },
  {
    "path": "test/util/data/util-test.json",
    "content": "[\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"nversion=1\"],\n    \"output_cmp\": \"blanktxv1.hex\",\n    \"description\": \"Creates a blank v1 transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\",\"-create\", \"nversion=1\"],\n    \"output_cmp\": \"blanktxv1.json\",\n    \"description\": \"Creates a blank v1 transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\"],\n    \"input\": \"blanktxv2.hex\",\n    \"output_cmp\": \"blanktxv2.hex\",\n    \"description\": \"Creates a blank transaction when nothing is piped into Munt-tx\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\",\"-create\"],\n    \"output_cmp\": \"blanktxv2.json\",\n    \"description\": \"Creates a blank transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\",\"-\"],\n    \"input\": \"blanktxv2.hex\",\n    \"output_cmp\": \"blanktxv2.json\",\n    \"description\": \"Creates a blank transaction when nothing is piped into Munt-tx (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"nversion=1foo\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX version requested\",\n    \"description\": \"Tests the check for invalid nversion value\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delin=1\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-delin1-out.hex\",\n    \"description\": \"Deletes a single input from a transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-\", \"delin=1\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-delin1-out.json\",\n    \"description\": \"Deletes a single input from a transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delin=31\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX input index '31'\",\n    \"description\": \"Attempts to delete an input with a bad index from a transaction. Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delin=1foo\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX input index\",\n    \"description\": \"Tests the check for an invalid input index with delin\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delout=1\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-delout1-out.hex\",\n    \"description\": \"Deletes a single output from a transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-\", \"delout=1\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-delout1-out.json\",\n    \"description\": \"Deletes a single output from a transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delout=2\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX output index '2'\",\n    \"description\": \"Attempts to delete an output with a bad index from a transaction. Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"delout=1foo\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX output index\",\n    \"description\": \"Tests the check for an invalid output index with delout\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-\", \"locktime=317000\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-locktime317000-out.hex\",\n    \"description\": \"Adds an nlocktime to a transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-\", \"locktime=317000\"],\n    \"input\": \"tx394b54bb.hex\",\n    \"output_cmp\": \"tt-locktime317000-out.json\",\n    \"description\": \"Adds an nlocktime to a transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"locktime=317000foo\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX locktime requested\",\n    \"description\": \"Tests the check for invalid locktime value\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=Z897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX input txid\",\n    \"description\": \"Tests the check for an invalid txid invalid hex\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6:0\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX input txid\",\n    \"description\": \"Tests the check for an invalid txid valid hex but too short\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f12:0\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX input txid\",\n    \"description\": \"Tests the check for an invalid txid valid hex but too long\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"replaceable=0foo\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: Invalid TX input index\",\n    \"description\": \"Tests the check for an invalid input index with replaceable\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0x\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX input vout\",\n    \"description\": \"Tests the check for an invalid vout value when adding an input\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"outaddr=1\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: TX output missing or too many separators\",\n    \"description\": \"Malformed outaddr argument (no address specified). Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"outaddr=1:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o:garbage\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: TX output missing or too many separators\",\n    \"description\": \"Malformed outaddr argument (too many separators). Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"outpubkey=0\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: TX output missing or too many separators\",\n    \"description\": \"Malformed outpubkey argument (no pubkey specified). Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W:non53nse\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: TX output missing or too many separators\",\n    \"description\": \"Malformed outpubkey argument (too many separators). Expected to fail.\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18\",\n     \"in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46\"],\n    \"output_cmp\": \"txcreate1.hex\",\n    \"description\": \"Creates a new transaction with three inputs and two outputs\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18\",\n     \"in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46\"],\n    \"output_cmp\": \"txcreate1.json\",\n    \"description\": \"Creates a new transaction with three inputs and two outputs (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outscript=0:\"],\n    \"output_cmp\": \"txcreate2.hex\",\n    \"description\": \"Creates a new transaction with a single empty output script\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outscript=0:\"],\n    \"output_cmp\": \"txcreate2.json\",\n    \"description\": \"Creates a new transaction with a single empty output script (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"02000000000100000000000000000000000000\"],\n    \"output_cmp\": \"txcreate2.hex\",\n    \"description\": \"Parses a transaction with no inputs and a single output script\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"02000000000100000000000000000000000000\"],\n    \"output_cmp\": \"txcreate2.json\",\n    \"description\": \"Parses a transaction with no inputs and a single output script (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outscript=0:OP_DROP\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript1.hex\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outscript=0:OP_DROP\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript1.json\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outscript=0:OP_DROP:S\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript2.hex\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2SH\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outscript=0:OP_DROP:S\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript2.json\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2SH (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outscript=0:OP_DROP:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript3.hex\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2WSH\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outscript=0:OP_DROP:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript3.json\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2WSH (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outscript=0:OP_DROP:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript4.hex\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2WSH, wrapped in a P2SH\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outscript=0:OP_DROP:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatescript4.json\",\n    \"description\": \"Create a new transaction with a single output script (OP_DROP) in a P2SH, wrapped in a P2SH (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\", \"nversion=1\",\n     \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n     \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n     \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n     \"sign=ALL\",\n     \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"output_cmp\": \"txcreatesignv1.hex\",\n    \"description\": \"Creates a new v1 transaction with a single input and a single output, and then signs the transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"-create\", \"nversion=1\",\n     \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n     \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n     \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n     \"sign=ALL\",\n     \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"output_cmp\": \"txcreatesignv1.json\",\n    \"description\": \"Creates a new v1 transaction with a single input and a single output, and then signs the transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n      \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n      \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n      \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n      \"sign=ALL\",\n      \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"output_cmp\": \"txcreatesignv2.hex\",\n    \"description\": \"Creates a new transaction with a single input and a single output, and then signs the transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n      \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n      \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n      \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\\\",\\\"vout\\\":\\\"0foo\\\",\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n      \"sign=ALL\",\n      \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: prevtxs internal object typecheck fail\",\n    \"description\": \"Tests the check for invalid vout index in prevtxs for sign\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n      \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n      \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n      \"set=prevtxs:[{\\\"txid\\\":\\\"Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n      \"sign=ALL\",\n      \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: txid must be hexadecimal string (not 'Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412')\",\n    \"description\": \"Tests the check for invalid txid due to invalid hex\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n      \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n      \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n      \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n      \"sign=ALL\",\n      \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594')\",\n    \"description\": \"Tests the check for invalid txid valid hex, but too short\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n      \"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0\",\n      \"set=privatekeys:[\\\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\\\"]\",\n      \"set=prevtxs:[{\\\"txid\\\":\\\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512\\\",\\\"vout\\\":0,\\\"scriptPubKey\\\":\\\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\\\"}]\",\n      \"sign=ALL\",\n      \"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512')\",\n    \"description\": \"Tests the check for invalid txid valid hex, but too long\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey1.hex\",\n    \"description\": \"Creates a new transaction with a single pay-to-pubkey output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\", \"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey1.json\",\n    \"description\": \"Creates a new transaction with a single pay-to-pubkey output (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey2.hex\",\n    \"description\": \"Creates a new transaction with a single pay-to-witness-pubkey output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\", \"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey2.json\",\n    \"description\": \"Creates a new transaction with a single pay-to-witness-pubkey output (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey3.hex\",\n    \"description\": \"Creates a new transaction with a single pay-to-witness-pubkey, wrapped in P2SH output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\", \"-create\", \"outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreateoutpubkey3.json\",\n    \"description\": \"Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\", \"-create\", \"outpubkey=0:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS\", \"nversion=1\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: Uncompressed pubkeys are not useable for SegWit outputs\",\n    \"description\": \"Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outdata=4:badhexdata\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX output data\",\n    \"description\": \"Attempts to create a new transaction with one input and an output with malformed hex data. Expected to fail\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outdata=badhexdata\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: invalid TX output data\",\n    \"description\": \"Attempts to create a new transaction with one input and an output with no value and malformed hex data. Expected to fail\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\"],\n    \"output_cmp\": \"txcreatedata1.hex\",\n    \"description\": \"Creates a new transaction with one input, one address output and one data output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"-create\", \"nversion=1\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\"],\n    \"output_cmp\": \"txcreatedata1.json\",\n    \"description\": \"Creates a new v1 transaction with one input, one address output and one data output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\"],\n    \"output_cmp\": \"txcreatedata2.hex\",\n    \"description\": \"Creates a new transaction with one input, one address output and one data (zero value) output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\",\n     \"outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e\"],\n    \"output_cmp\": \"txcreatedata2.json\",\n    \"description\": \"Creates a new transaction with one input, one address output and one data (zero value) output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"],\n    \"output_cmp\": \"txcreatedata_seq0.hex\",\n    \"description\": \"Creates a new transaction with one input with sequence number and one address output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"-create\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293\",\n     \"outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o\"],\n    \"output_cmp\": \"txcreatedata_seq0.json\",\n    \"description\": \"Creates a new transaction with one input with sequence number and one address output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1\"],\n    \"output_cmp\": \"txcreatedata_seq1.hex\",\n    \"description\": \"Adds a new input with sequence number to a transaction\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\":\n    [\"-json\",\n     \"01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000\",\n     \"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1\"],\n    \"output_cmp\": \"txcreatedata_seq1.json\",\n    \"description\": \"Adds a new input with sequence number to a transaction (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig1.hex\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig1.json\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:S\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig2.hex\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2SH output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:S\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig2.json\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2SH output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig3.hex\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2WSH output\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:W\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig3.json\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2WSH output (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig4.hex\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS\", \"nversion=1\"],\n    \"output_cmp\": \"txcreatemultisig4.json\",\n    \"description\": \"Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH (output in json)\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:S\"],\n    \"output_cmp\": \"txcreatemultisig5.json\",\n    \"description\": \"Uncompressed pubkeys should work just fine for non-witness outputs\"\n  },\n  { \"exec\": \"./Munt-tx\",\n    \"args\": [\"-json\", \"-create\", \"outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS\"],\n    \"return_code\": 1,\n    \"error_txt\": \"error: Uncompressed pubkeys are not useable for SegWit outputs\",\n    \"description\": \"Ensure adding witness outputs with uncompressed pubkeys fails\"\n  }\n]\n"
  },
  {
    "path": "test/util/rpcauth-test.py",
    "content": "#!/usr/bin/env python3\n# Copyright (c) 2015-2018 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test share/rpcauth/rpcauth.py\n\"\"\"\nimport base64\nimport configparser\nimport hmac\nimport importlib\nimport os\nimport sys\nimport unittest\n\nclass TestRPCAuth(unittest.TestCase):\n    def setUp(self):\n        config = configparser.ConfigParser()\n        config_path = os.path.abspath(\n            os.path.join(os.sep, os.path.abspath(os.path.dirname(__file__)),\n            \"../config.ini\"))\n        with open(config_path, encoding=\"utf8\") as config_file:\n            config.read_file(config_file)\n        sys.path.insert(0, os.path.dirname(config['environment']['RPCAUTH']))\n        self.rpcauth = importlib.import_module('rpcauth')\n\n    def test_generate_salt(self):\n        for i in range(16, 32 + 1):\n            self.assertEqual(len(self.rpcauth.generate_salt(i)), i * 2)\n\n    def test_generate_password(self):\n        password = self.rpcauth.generate_password()\n        expected_password = base64.urlsafe_b64encode(\n            base64.urlsafe_b64decode(password)).decode('utf-8')\n        self.assertEqual(expected_password, password)\n\n    def test_check_password_hmac(self):\n        salt = self.rpcauth.generate_salt(16)\n        password = self.rpcauth.generate_password()\n        password_hmac = self.rpcauth.password_to_hmac(salt, password)\n\n        m = hmac.new(bytearray(salt, 'utf-8'),\n            bytearray(password, 'utf-8'), 'SHA256')\n        expected_password_hmac = m.hexdigest()\n\n        self.assertEqual(expected_password_hmac, password_hmac)\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "test/util/util-test.py",
    "content": "#!/usr/bin/env python3\n# Copyright 2014 BitPay Inc.\n# Copyright 2016-2017 The Bitcoin Core developers\n# Distributed under the MIT software license, see the accompanying\n# file COPYING or http://www.opensource.org/licenses/mit-license.php.\n\"\"\"Test framework for Munt utils.\n\nRuns automatically during `make check`.\n\nCan also be run manually.\"\"\"\n\nimport argparse\nimport binascii\nimport configparser\nimport difflib\nimport json\nimport logging\nimport os\nimport pprint\nimport subprocess\nimport sys\n\ndef main():\n    config = configparser.ConfigParser()\n    config.optionxform = str\n    config.read_file(open(os.path.join(os.path.dirname(__file__), \"../config.ini\"), encoding=\"utf8\"))\n    env_conf = dict(config.items('environment'))\n\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument('-v', '--verbose', action='store_true')\n    args = parser.parse_args()\n    verbose = args.verbose\n\n    if verbose:\n        level = logging.DEBUG\n    else:\n        level = logging.ERROR\n    formatter = '%(asctime)s - %(levelname)s - %(message)s'\n    # Add the format/level to the logger\n    logging.basicConfig(format=formatter, level=level)\n\n    bctester(os.path.join(env_conf[\"SRCDIR\"], \"test\", \"util\", \"data\"), \"util-test.json\", env_conf)\n\ndef bctester(testDir, input_basename, buildenv):\n    \"\"\" Loads and parses the input file, runs all tests and reports results\"\"\"\n    input_filename = os.path.join(testDir, input_basename)\n    raw_data = open(input_filename, encoding=\"utf8\").read()\n    input_data = json.loads(raw_data)\n\n    failed_testcases = []\n\n    for testObj in input_data:\n        try:\n            bctest(testDir, testObj, buildenv)\n            logging.info(\"PASSED: \" + testObj[\"description\"])\n        except:\n            logging.info(\"FAILED: \" + testObj[\"description\"])\n            failed_testcases.append(testObj[\"description\"])\n\n    if failed_testcases:\n        error_message = \"FAILED_TESTCASES:\\n\"\n        error_message += pprint.pformat(failed_testcases, width=400)\n        logging.error(error_message)\n        sys.exit(1)\n    else:\n        sys.exit(0)\n\ndef bctest(testDir, testObj, buildenv):\n    \"\"\"Runs a single test, comparing output and RC to expected output and RC.\n\n    Raises an error if input can't be read, executable fails, or output/RC\n    are not as expected. Error is caught by bctester() and reported.\n    \"\"\"\n    # Get the exec names and arguments\n    execprog = os.path.join(buildenv[\"BUILDDIR\"], \"src\", testObj[\"exec\"] + buildenv[\"EXEEXT\"])\n    execargs = testObj['args']\n    execrun = [execprog] + execargs\n\n    # Read the input data (if there is any)\n    stdinCfg = None\n    inputData = None\n    if \"input\" in testObj:\n        filename = os.path.join(testDir, testObj[\"input\"])\n        inputData = open(filename, encoding=\"utf8\").read()\n        stdinCfg = subprocess.PIPE\n\n    # Read the expected output data (if there is any)\n    outputFn = None\n    outputData = None\n    outputType = None\n    if \"output_cmp\" in testObj:\n        outputFn = testObj['output_cmp']\n        outputType = os.path.splitext(outputFn)[1][1:]  # output type from file extension (determines how to compare)\n        try:\n            outputData = open(os.path.join(testDir, outputFn), encoding=\"utf8\").read()\n        except:\n            logging.error(\"Output file \" + outputFn + \" can not be opened\")\n            raise\n        if not outputData:\n            logging.error(\"Output data missing for \" + outputFn)\n            raise Exception\n        if not outputType:\n            logging.error(\"Output file %s does not have a file extension\" % outputFn)\n            raise Exception\n\n    # Run the test\n    proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)\n    try:\n        outs = proc.communicate(input=inputData)\n    except OSError:\n        logging.error(\"OSError, Failed to execute \" + execprog)\n        raise\n\n    if outputData:\n        data_mismatch, formatting_mismatch = False, False\n        # Parse command output and expected output\n        try:\n            a_parsed = parse_output(outs[0], outputType)\n        except Exception as e:\n            logging.error('Error parsing command output as %s: %s' % (outputType, e))\n            raise\n        try:\n            b_parsed = parse_output(outputData, outputType)\n        except Exception as e:\n            logging.error('Error parsing expected output %s as %s: %s' % (outputFn, outputType, e))\n            raise\n        # Compare data\n        if a_parsed != b_parsed:\n            logging.error(\"Output data mismatch for \" + outputFn + \" (format \" + outputType + \")\")\n            data_mismatch = True\n        # Compare formatting\n        if outs[0] != outputData:\n            error_message = \"Output formatting mismatch for \" + outputFn + \":\\n\"\n            error_message += \"\".join(difflib.context_diff(outputData.splitlines(True),\n                                                          outs[0].splitlines(True),\n                                                          fromfile=outputFn,\n                                                          tofile=\"returned\"))\n            logging.error(error_message)\n            formatting_mismatch = True\n\n        assert not data_mismatch and not formatting_mismatch\n\n    # Compare the return code to the expected return code\n    wantRC = 0\n    if \"return_code\" in testObj:\n        wantRC = testObj['return_code']\n    if proc.returncode != wantRC:\n        logging.error(\"Return code mismatch for \" + outputFn)\n        raise Exception\n\n    if \"error_txt\" in testObj:\n        want_error = testObj[\"error_txt\"]\n        # Compare error text\n        # TODO: ideally, we'd compare the strings exactly and also assert\n        # That stderr is empty if no errors are expected. However, Munt-tx\n        # emits DISPLAY errors when running as a windows application on\n        # linux through wine. Just assert that the expected error text appears\n        # somewhere in stderr.\n        if want_error not in outs[1]:\n            logging.error(\"Error mismatch:\\n\" + \"Expected: \" + want_error + \"\\nReceived: \" + outs[1].rstrip())\n            raise Exception\n\ndef parse_output(a, fmt):\n    \"\"\"Parse the output according to specified format.\n\n    Raise an error if the output can't be parsed.\"\"\"\n    if fmt == 'json':  # json: compare parsed data\n        return json.loads(a)\n    elif fmt == 'hex':  # hex: parse and compare binary data\n        return binascii.a2b_hex(a.strip())\n    else:\n        raise NotImplementedError(\"Don't know how to compare %s\" % fmt)\n\nif __name__ == '__main__':\n    main()\n"
  }
]